summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore40
-rw-r--r--CREDITS59
-rw-r--r--Changelog688
-rw-r--r--INSTALL18
-rw-r--r--INSTALL.md17
-rw-r--r--LICENSE66
-rw-r--r--LICENSE.md112
-rw-r--r--MAINTAINERS592
-rw-r--r--Makefile135
l---------README1
-rw-r--r--README.md24
-rw-r--r--RELEASE2
-rw-r--r--arch.mak6
-rw-r--r--avconv.c2695
-rw-r--r--avconv.h434
-rw-r--r--avconv_dxva2.c627
-rw-r--r--avconv_filter.c701
-rw-r--r--avconv_opt.c2437
-rw-r--r--avconv_vda.c134
-rw-r--r--avconv_vdpau.c299
-rw-r--r--avplay.c3063
-rw-r--r--avprobe.c1031
-rw-r--r--cmdutils.c1014
-rw-r--r--cmdutils.h144
-rw-r--r--cmdutils_common_opts.h23
-rw-r--r--cmdutils_opencl.c276
-rw-r--r--common.mak103
-rw-r--r--compat/aix/math.h14
-rw-r--r--compat/avisynth/avisynth_c.h882
-rw-r--r--compat/avisynth/avs/capi.h62
-rw-r--r--compat/avisynth/avs/config.h55
-rw-r--r--compat/avisynth/avs/types.h51
-rw-r--r--compat/avisynth/avxsynth_c.h728
-rw-r--r--compat/avisynth/windowsPorts/basicDataTypeConversions.h85
-rw-r--r--compat/avisynth/windowsPorts/windows2linux.h77
-rw-r--r--compat/float/float.h8
-rw-r--r--compat/float/limits.h8
-rw-r--r--compat/getopt.c11
-rw-r--r--compat/msvcrt/snprintf.c13
-rw-r--r--compat/msvcrt/snprintf.h38
-rw-r--r--compat/os2threads.h164
-rw-r--r--compat/plan9/main.c8
-rw-r--r--compat/strtod.c8
-rw-r--r--compat/tms470/math.h14
-rw-r--r--compat/va_copy.h29
-rw-r--r--compat/w32pthreads.h29
-rwxr-xr-xconfigure1667
-rw-r--r--doc/APIchanges1417
-rw-r--r--doc/Doxyfile18
-rw-r--r--doc/Makefile166
-rw-r--r--doc/RELEASE_NOTES75
-rw-r--r--doc/authors.texi11
-rw-r--r--doc/avconv.texi1184
-rw-r--r--doc/avplay.texi186
-rw-r--r--doc/avprobe.texi141
-rw-r--r--doc/avtools-common-opts.texi197
-rw-r--r--doc/avutil.txt36
-rw-r--r--doc/bitstream_filters.texi125
-rw-r--r--doc/bootstrap.min.css5
-rw-r--r--doc/build_system.txt36
-rw-r--r--doc/codecs.texi1151
-rw-r--r--doc/decoders.texi212
-rw-r--r--doc/default.css165
-rw-r--r--doc/demuxers.texi461
-rw-r--r--doc/developer.texi427
-rw-r--r--doc/devices.texi25
-rwxr-xr-xdoc/doxy-wrapper.sh16
-rw-r--r--doc/doxy/doxy_stylesheet.css2021
-rw-r--r--doc/doxy/footer.html9
-rw-r--r--doc/doxy/header.html16
-rw-r--r--doc/encoders.texi1871
-rw-r--r--doc/errno.txt174
-rw-r--r--doc/eval.texi156
-rw-r--r--doc/examples/Makefile45
-rw-r--r--doc/examples/README23
-rw-r--r--doc/examples/avcodec.c595
-rw-r--r--doc/examples/avio_list_dir.c120
-rw-r--r--doc/examples/avio_reading.c134
-rw-r--r--doc/examples/decoding_encoding.c665
-rw-r--r--doc/examples/demuxing_decoding.c405
-rw-r--r--doc/examples/extract_mvs.c185
-rw-r--r--doc/examples/filter_audio.c8
-rw-r--r--doc/examples/filtering_audio.c296
-rw-r--r--doc/examples/filtering_video.c278
-rw-r--r--doc/examples/metadata.c4
-rw-r--r--doc/examples/muxing.c670
-rw-r--r--doc/examples/output.c663
-rw-r--r--doc/examples/remuxing.c165
-rw-r--r--doc/examples/resampling_audio.c214
-rw-r--r--doc/examples/scaling_video.c140
-rw-r--r--doc/examples/transcode_aac.c103
-rw-r--r--doc/examples/transcoding.c583
-rw-r--r--doc/faq.texi399
-rw-r--r--doc/fate.texi258
-rw-r--r--doc/fate_config.sh.template30
-rw-r--r--doc/ffmpeg-bitstream-filters.texi46
-rw-r--r--doc/ffmpeg-codecs.texi43
-rw-r--r--doc/ffmpeg-devices.texi43
-rw-r--r--doc/ffmpeg-filters.texi43
-rw-r--r--doc/ffmpeg-formats.texi43
-rw-r--r--doc/ffmpeg-protocols.texi43
-rw-r--r--doc/ffmpeg-resampler.texi45
-rw-r--r--doc/ffmpeg-scaler.texi44
-rw-r--r--doc/ffmpeg-utils.texi43
-rw-r--r--doc/ffmpeg.texi1604
-rw-r--r--doc/ffmpeg.txt47
-rw-r--r--doc/ffplay.texi302
-rw-r--r--doc/ffprobe.texi683
-rw-r--r--doc/ffprobe.xsd355
-rw-r--r--doc/ffserver.conf371
-rw-r--r--doc/ffserver.texi923
-rw-r--r--doc/fftools-common-opts.texi387
-rw-r--r--doc/filter_design.txt270
-rw-r--r--doc/filters.texi10902
-rw-r--r--doc/formats.texi230
-rw-r--r--doc/general.texi323
-rw-r--r--doc/git-howto.texi97
-rw-r--r--doc/git-howto.txt272
-rw-r--r--doc/indevs.texi1072
-rw-r--r--doc/issue_tracker.txt194
-rw-r--r--doc/libavcodec.texi49
-rw-r--r--doc/libavdevice.texi46
-rw-r--r--doc/libavfilter.texi93
-rw-r--r--doc/libavformat.texi49
-rw-r--r--doc/libavutil.texi63
-rw-r--r--doc/libswresample.texi71
-rw-r--r--doc/libswscale.texi64
-rw-r--r--doc/metadata.texi46
-rw-r--r--doc/mips.txt75
-rw-r--r--doc/multithreading.txt4
-rw-r--r--doc/muxers.texi958
-rw-r--r--doc/nut.texi6
-rw-r--r--doc/optimization.txt13
-rw-r--r--doc/outdevs.texi425
-rw-r--r--doc/platform.texi73
-rw-r--r--doc/print_options.c14
-rw-r--r--doc/protocols.texi688
-rw-r--r--doc/resampler.texi232
-rw-r--r--doc/scaler.texi127
-rw-r--r--doc/snow.txt637
-rw-r--r--doc/soc.txt24
-rw-r--r--doc/style.min.css23
-rw-r--r--doc/swresample.txt46
-rw-r--r--doc/t2h.init200
-rw-r--r--doc/t2h.pm339
-rw-r--r--[-rwxr-xr-x]doc/texi2pod.pl79
-rw-r--r--doc/texidep.pl32
-rw-r--r--doc/utils.texi1067
-rw-r--r--doc/viterbi.txt109
-rw-r--r--doc/writing_filters.txt423
-rw-r--r--ffmpeg.c4095
-rw-r--r--ffmpeg.h546
-rw-r--r--ffmpeg_dxva2.c628
-rw-r--r--ffmpeg_filter.c1010
-rw-r--r--ffmpeg_opt.c3213
-rw-r--r--ffmpeg_vda.c134
-rw-r--r--ffmpeg_vdpau.c369
-rw-r--r--ffplay.c3873
-rw-r--r--ffprobe.c3262
-rw-r--r--ffserver.c3824
-rw-r--r--ffserver_config.c1313
-rw-r--r--ffserver_config.h133
-rw-r--r--libavcodec/012v.c155
-rw-r--r--libavcodec/4xm.c165
-rw-r--r--libavcodec/8bps.c31
-rw-r--r--libavcodec/8svx.c119
-rw-r--r--libavcodec/Makefile230
-rw-r--r--libavcodec/a64colors.h8
-rw-r--r--libavcodec/a64enc.h55
-rw-r--r--libavcodec/a64multienc.c97
-rw-r--r--libavcodec/a64tables.h8
-rw-r--r--libavcodec/aac.h48
-rw-r--r--libavcodec/aac_ac3_parser.c8
-rw-r--r--libavcodec/aac_ac3_parser.h8
-rw-r--r--libavcodec/aac_adtstoasc_bsf.c19
-rw-r--r--libavcodec/aac_parser.c10
-rw-r--r--libavcodec/aac_tablegen.c8
-rw-r--r--libavcodec/aac_tablegen.h10
-rw-r--r--libavcodec/aac_tablegen_decl.h8
-rw-r--r--libavcodec/aacadtsdec.c8
-rw-r--r--libavcodec/aacadtsdec.h8
-rw-r--r--libavcodec/aaccoder.c170
-rw-r--r--libavcodec/aacdec.c420
-rw-r--r--libavcodec/aacdectab.h8
-rw-r--r--libavcodec/aacenc.c142
-rw-r--r--libavcodec/aacenc.h23
-rw-r--r--libavcodec/aacps.c34
-rw-r--r--libavcodec/aacps.h10
-rw-r--r--libavcodec/aacps_tablegen.c10
-rw-r--r--libavcodec/aacps_tablegen.h12
-rw-r--r--libavcodec/aacpsdata.c8
-rw-r--r--libavcodec/aacpsdsp.c10
-rw-r--r--libavcodec/aacpsdsp.h9
-rw-r--r--libavcodec/aacpsy.c122
-rw-r--r--libavcodec/aacsbr.c126
-rw-r--r--libavcodec/aacsbr.h10
-rw-r--r--libavcodec/aacsbr_tablegen.c39
-rw-r--r--libavcodec/aacsbr_tablegen.h129
-rw-r--r--libavcodec/aacsbrdata.h100
-rw-r--r--libavcodec/aactab.c8
-rw-r--r--libavcodec/aactab.h8
-rw-r--r--libavcodec/aandcttab.c10
-rw-r--r--libavcodec/aandcttab.h10
-rw-r--r--libavcodec/aarch64/asm-offsets.h8
-rw-r--r--libavcodec/aarch64/cabac.h8
-rw-r--r--libavcodec/aarch64/fft_init_aarch64.c8
-rw-r--r--libavcodec/aarch64/fft_neon.S8
-rw-r--r--libavcodec/aarch64/h264chroma_init_aarch64.c8
-rw-r--r--libavcodec/aarch64/h264cmc_neon.S8
-rw-r--r--libavcodec/aarch64/h264dsp_init_aarch64.c9
-rw-r--r--libavcodec/aarch64/h264dsp_neon.S8
-rw-r--r--libavcodec/aarch64/h264idct_neon.S8
-rw-r--r--libavcodec/aarch64/h264qpel_init_aarch64.c136
-rw-r--r--libavcodec/aarch64/h264qpel_neon.S8
-rw-r--r--libavcodec/aarch64/hpeldsp_init_aarch64.c8
-rw-r--r--libavcodec/aarch64/hpeldsp_neon.S8
-rw-r--r--libavcodec/aarch64/imdct15_init.c8
-rw-r--r--libavcodec/aarch64/imdct15_neon.S8
-rw-r--r--libavcodec/aarch64/mdct_neon.S8
-rw-r--r--libavcodec/aarch64/mpegaudiodsp_init.c8
-rw-r--r--libavcodec/aarch64/mpegaudiodsp_neon.S8
-rw-r--r--libavcodec/aarch64/neon.S8
-rw-r--r--libavcodec/aarch64/neontest.c8
-rw-r--r--libavcodec/aarch64/rv40dsp_init_aarch64.c8
-rw-r--r--libavcodec/aarch64/vc1dsp_init_aarch64.c8
-rw-r--r--libavcodec/aarch64/videodsp.S8
-rw-r--r--libavcodec/aarch64/videodsp_init.c8
-rw-r--r--libavcodec/aarch64/vorbisdsp_init.c8
-rw-r--r--libavcodec/aarch64/vorbisdsp_neon.S8
-rw-r--r--libavcodec/aasc.c68
-rw-r--r--libavcodec/ac3.c15
-rw-r--r--libavcodec/ac3.h63
-rw-r--r--libavcodec/ac3_parser.c32
-rw-r--r--libavcodec/ac3_parser.h13
-rw-r--r--libavcodec/ac3dec.c293
-rw-r--r--libavcodec/ac3dec.h62
-rw-r--r--libavcodec/ac3dec_data.c8
-rw-r--r--libavcodec/ac3dec_data.h8
-rw-r--r--libavcodec/ac3dec_fixed.c196
-rw-r--r--libavcodec/ac3dec_float.c92
-rw-r--r--libavcodec/ac3dsp.c80
-rw-r--r--libavcodec/ac3dsp.h18
-rw-r--r--libavcodec/ac3enc.c74
-rw-r--r--libavcodec/ac3enc.h10
-rw-r--r--libavcodec/ac3enc_fixed.c23
-rw-r--r--libavcodec/ac3enc_float.c28
-rw-r--r--libavcodec/ac3enc_opts_template.c8
-rw-r--r--libavcodec/ac3enc_template.c47
-rw-r--r--libavcodec/ac3tab.c10
-rw-r--r--libavcodec/ac3tab.h8
-rw-r--r--libavcodec/acelp_filters.c20
-rw-r--r--libavcodec/acelp_filters.h43
-rw-r--r--libavcodec/acelp_pitch_delay.c20
-rw-r--r--libavcodec/acelp_pitch_delay.h8
-rw-r--r--libavcodec/acelp_vectors.c58
-rw-r--r--libavcodec/acelp_vectors.h63
-rw-r--r--libavcodec/adpcm.c381
-rw-r--r--libavcodec/adpcm.h14
-rw-r--r--libavcodec/adpcm_data.c46
-rw-r--r--libavcodec/adpcm_data.h16
-rw-r--r--libavcodec/adpcmenc.c74
-rw-r--r--libavcodec/adx.c8
-rw-r--r--libavcodec/adx.h8
-rw-r--r--libavcodec/adx_parser.c8
-rw-r--r--libavcodec/adxdec.c19
-rw-r--r--libavcodec/adxenc.c37
-rw-r--r--libavcodec/aic.c32
-rw-r--r--libavcodec/alac.c134
-rw-r--r--libavcodec/alac_data.c8
-rw-r--r--libavcodec/alac_data.h8
-rw-r--r--libavcodec/alacenc.c57
-rw-r--r--libavcodec/aliaspixdec.c8
-rw-r--r--libavcodec/aliaspixenc.c8
-rw-r--r--libavcodec/allcodecs.c139
-rw-r--r--libavcodec/alpha/Makefile10
-rw-r--r--libavcodec/alpha/asm.h186
-rw-r--r--libavcodec/alpha/blockdsp_alpha.c51
-rw-r--r--libavcodec/alpha/hpeldsp_alpha.c213
-rw-r--r--libavcodec/alpha/hpeldsp_alpha.h28
-rw-r--r--libavcodec/alpha/hpeldsp_alpha_asm.S125
-rw-r--r--libavcodec/alpha/idctdsp_alpha.c127
-rw-r--r--libavcodec/alpha/idctdsp_alpha.h34
-rw-r--r--libavcodec/alpha/idctdsp_alpha_asm.S167
-rw-r--r--libavcodec/alpha/me_cmp_alpha.c317
-rw-r--r--libavcodec/alpha/me_cmp_mvi_asm.S179
-rw-r--r--libavcodec/alpha/mpegvideo_alpha.c110
-rw-r--r--libavcodec/alpha/pixblockdsp_alpha.c78
-rw-r--r--libavcodec/alpha/regdef.h77
-rw-r--r--libavcodec/alpha/simple_idct_alpha.c303
-rw-r--r--libavcodec/alsdec.c190
-rw-r--r--libavcodec/amr.h8
-rw-r--r--libavcodec/amrnbdata.h12
-rw-r--r--libavcodec/amrnbdec.c84
-rw-r--r--libavcodec/amrwbdata.h10
-rw-r--r--libavcodec/amrwbdec.c73
-rw-r--r--libavcodec/anm.c20
-rw-r--r--libavcodec/ansi.c92
-rw-r--r--libavcodec/apedec.c114
-rw-r--r--libavcodec/apedsp.h44
-rw-r--r--libavcodec/api-flac-test.c266
-rw-r--r--libavcodec/apng.h41
-rw-r--r--libavcodec/arm/Makefile18
-rw-r--r--libavcodec/arm/aac.h8
-rw-r--r--libavcodec/arm/aacpsdsp_init_arm.c8
-rw-r--r--libavcodec/arm/aacpsdsp_neon.S8
-rw-r--r--libavcodec/arm/ac3dsp_arm.S8
-rw-r--r--libavcodec/arm/ac3dsp_armv6.S8
-rw-r--r--libavcodec/arm/ac3dsp_init_arm.c18
-rw-r--r--libavcodec/arm/ac3dsp_neon.S52
-rw-r--r--libavcodec/arm/apedsp_init_arm.c38
-rw-r--r--libavcodec/arm/apedsp_neon.S62
-rw-r--r--libavcodec/arm/asm-offsets.h8
-rw-r--r--libavcodec/arm/audiodsp_arm.h8
-rw-r--r--libavcodec/arm/audiodsp_init_arm.c8
-rw-r--r--libavcodec/arm/audiodsp_init_neon.c8
-rw-r--r--libavcodec/arm/audiodsp_neon.S8
-rw-r--r--libavcodec/arm/blockdsp_arm.h8
-rw-r--r--libavcodec/arm/blockdsp_init_arm.c8
-rw-r--r--libavcodec/arm/blockdsp_init_neon.c8
-rw-r--r--libavcodec/arm/blockdsp_neon.S8
-rw-r--r--libavcodec/arm/cabac.h14
-rw-r--r--libavcodec/arm/dca.h84
-rw-r--r--libavcodec/arm/dcadsp_init_arm.c8
-rw-r--r--libavcodec/arm/dcadsp_neon.S8
-rw-r--r--libavcodec/arm/dcadsp_vfp.S8
-rw-r--r--libavcodec/arm/dct-test.c8
-rw-r--r--libavcodec/arm/fft_fixed_init_arm.c10
-rw-r--r--libavcodec/arm/fft_fixed_neon.S8
-rw-r--r--libavcodec/arm/fft_init_arm.c10
-rw-r--r--libavcodec/arm/fft_neon.S8
-rw-r--r--libavcodec/arm/fft_vfp.S8
-rw-r--r--libavcodec/arm/flacdsp_arm.S8
-rw-r--r--libavcodec/arm/flacdsp_init_arm.c14
-rw-r--r--libavcodec/arm/fmtconvert_init_arm.c8
-rw-r--r--libavcodec/arm/fmtconvert_neon.S8
-rw-r--r--libavcodec/arm/fmtconvert_vfp.S8
-rw-r--r--libavcodec/arm/g722dsp_init_arm.c8
-rw-r--r--libavcodec/arm/g722dsp_neon.S8
-rw-r--r--libavcodec/arm/h264chroma_init_arm.c8
-rw-r--r--libavcodec/arm/h264cmc_neon.S8
-rw-r--r--libavcodec/arm/h264dsp_init_arm.c14
-rw-r--r--libavcodec/arm/h264dsp_neon.S8
-rw-r--r--libavcodec/arm/h264idct_neon.S8
-rw-r--r--libavcodec/arm/h264pred_init_arm.c13
-rw-r--r--libavcodec/arm/h264pred_neon.S8
-rw-r--r--libavcodec/arm/h264qpel_init_arm.c8
-rw-r--r--libavcodec/arm/h264qpel_neon.S8
-rw-r--r--libavcodec/arm/hevcdsp_arm.h26
-rw-r--r--libavcodec/arm/hevcdsp_deblock_neon.S385
-rw-r--r--libavcodec/arm/hevcdsp_idct_neon.S465
-rw-r--r--libavcodec/arm/hevcdsp_init_arm.c32
-rw-r--r--libavcodec/arm/hevcdsp_init_neon.c224
-rw-r--r--libavcodec/arm/hevcdsp_qpel_neon.S999
-rw-r--r--libavcodec/arm/hpeldsp_arm.S8
-rw-r--r--libavcodec/arm/hpeldsp_arm.h10
-rw-r--r--libavcodec/arm/hpeldsp_armv6.S8
-rw-r--r--libavcodec/arm/hpeldsp_init_arm.c8
-rw-r--r--libavcodec/arm/hpeldsp_init_armv6.c8
-rw-r--r--libavcodec/arm/hpeldsp_init_neon.c8
-rw-r--r--libavcodec/arm/hpeldsp_neon.S8
-rw-r--r--libavcodec/arm/idct.h8
-rw-r--r--libavcodec/arm/idctdsp_arm.S10
-rw-r--r--libavcodec/arm/idctdsp_arm.h8
-rw-r--r--libavcodec/arm/idctdsp_armv6.S8
-rw-r--r--libavcodec/arm/idctdsp_init_arm.c14
-rw-r--r--libavcodec/arm/idctdsp_init_armv5te.c11
-rw-r--r--libavcodec/arm/idctdsp_init_armv6.c14
-rw-r--r--libavcodec/arm/idctdsp_init_neon.c17
-rw-r--r--libavcodec/arm/idctdsp_neon.S8
-rw-r--r--libavcodec/arm/int_neon.S13
-rw-r--r--libavcodec/arm/lossless_audiodsp_init_arm.c38
-rw-r--r--libavcodec/arm/lossless_audiodsp_neon.S62
-rw-r--r--libavcodec/arm/mathops.h8
-rw-r--r--libavcodec/arm/mdct_fixed_neon.S8
-rw-r--r--libavcodec/arm/mdct_neon.S8
-rw-r--r--libavcodec/arm/mdct_vfp.S8
-rw-r--r--libavcodec/arm/me_cmp_armv6.S8
-rw-r--r--libavcodec/arm/me_cmp_init_arm.c8
-rw-r--r--libavcodec/arm/mlpdsp_armv5te.S8
-rw-r--r--libavcodec/arm/mlpdsp_armv6.S8
-rw-r--r--libavcodec/arm/mlpdsp_init_arm.c8
-rw-r--r--libavcodec/arm/mpegaudiodsp_fixed_armv6.S8
-rw-r--r--libavcodec/arm/mpegaudiodsp_init_arm.c8
-rw-r--r--libavcodec/arm/mpegvideo_arm.c8
-rw-r--r--libavcodec/arm/mpegvideo_arm.h8
-rw-r--r--libavcodec/arm/mpegvideo_armv5te.c13
-rw-r--r--libavcodec/arm/mpegvideo_armv5te_s.S8
-rw-r--r--libavcodec/arm/mpegvideo_neon.S8
-rw-r--r--libavcodec/arm/mpegvideoencdsp_armv6.S8
-rw-r--r--libavcodec/arm/mpegvideoencdsp_init_arm.c8
-rw-r--r--libavcodec/arm/neon.S8
-rw-r--r--libavcodec/arm/neontest.c8
-rw-r--r--libavcodec/arm/pixblockdsp_armv6.S8
-rw-r--r--libavcodec/arm/pixblockdsp_init_arm.c10
-rw-r--r--libavcodec/arm/rdft_neon.S8
-rw-r--r--libavcodec/arm/rv34dsp_init_arm.c8
-rw-r--r--libavcodec/arm/rv34dsp_neon.S8
-rw-r--r--libavcodec/arm/rv40dsp_init_arm.c8
-rw-r--r--libavcodec/arm/rv40dsp_neon.S8
-rw-r--r--libavcodec/arm/sbrdsp_init_arm.c8
-rw-r--r--libavcodec/arm/sbrdsp_neon.S8
-rw-r--r--libavcodec/arm/simple_idct_arm.S10
-rw-r--r--libavcodec/arm/simple_idct_armv5te.S8
-rw-r--r--libavcodec/arm/simple_idct_armv6.S8
-rw-r--r--libavcodec/arm/simple_idct_neon.S8
-rw-r--r--libavcodec/arm/startcode.h8
-rw-r--r--libavcodec/arm/startcode_armv6.S8
-rw-r--r--libavcodec/arm/synth_filter_neon.S8
-rw-r--r--libavcodec/arm/synth_filter_vfp.S8
-rw-r--r--libavcodec/arm/vc1dsp.h8
-rw-r--r--libavcodec/arm/vc1dsp_init_arm.c10
-rw-r--r--libavcodec/arm/vc1dsp_init_neon.c113
-rw-r--r--libavcodec/arm/vc1dsp_neon.S8
-rw-r--r--libavcodec/arm/videodsp_arm.h8
-rw-r--r--libavcodec/arm/videodsp_armv5te.S11
-rw-r--r--libavcodec/arm/videodsp_init_arm.c8
-rw-r--r--libavcodec/arm/videodsp_init_armv5te.c10
-rw-r--r--libavcodec/arm/vorbisdsp_init_arm.c8
-rw-r--r--libavcodec/arm/vorbisdsp_neon.S8
-rw-r--r--libavcodec/arm/vp3dsp_init_arm.c8
-rw-r--r--libavcodec/arm/vp3dsp_neon.S8
-rw-r--r--libavcodec/arm/vp56_arith.h8
-rw-r--r--libavcodec/arm/vp6dsp_init_arm.c8
-rw-r--r--libavcodec/arm/vp6dsp_neon.S8
-rw-r--r--libavcodec/arm/vp8.h8
-rw-r--r--libavcodec/arm/vp8_armv6.S8
-rw-r--r--libavcodec/arm/vp8dsp.h8
-rw-r--r--libavcodec/arm/vp8dsp_armv6.S8
-rw-r--r--libavcodec/arm/vp8dsp_init_arm.c8
-rw-r--r--libavcodec/arm/vp8dsp_init_armv6.c8
-rw-r--r--libavcodec/arm/vp8dsp_init_neon.c8
-rw-r--r--libavcodec/arm/vp8dsp_neon.S8
-rw-r--r--libavcodec/ass.c214
-rw-r--r--libavcodec/ass.h88
-rw-r--r--libavcodec/ass_split.c529
-rw-r--r--libavcodec/ass_split.h192
-rw-r--r--libavcodec/assdec.c76
-rw-r--r--libavcodec/assenc.c77
-rw-r--r--libavcodec/asv.c8
-rw-r--r--libavcodec/asv.h8
-rw-r--r--libavcodec/asvdec.c23
-rw-r--r--libavcodec/asvenc.c110
-rw-r--r--libavcodec/atrac.c11
-rw-r--r--libavcodec/atrac.h11
-rw-r--r--libavcodec/atrac1.c27
-rw-r--r--libavcodec/atrac1data.h10
-rw-r--r--libavcodec/atrac3.c66
-rw-r--r--libavcodec/atrac3data.h8
-rw-r--r--libavcodec/atrac3plus.c52
-rw-r--r--libavcodec/atrac3plus.h16
-rw-r--r--libavcodec/atrac3plus_data.h8
-rw-r--r--libavcodec/atrac3plusdec.c52
-rw-r--r--libavcodec/atrac3plusdsp.c12
-rw-r--r--libavcodec/audio_frame_queue.c151
-rw-r--r--libavcodec/audio_frame_queue.h14
-rw-r--r--libavcodec/audioconvert.c120
-rw-r--r--libavcodec/audioconvert.h86
-rw-r--r--libavcodec/audiodsp.c8
-rw-r--r--libavcodec/audiodsp.h8
-rw-r--r--libavcodec/aura.c12
-rw-r--r--libavcodec/avcodec.h1057
-rw-r--r--libavcodec/avcodecres.rc55
-rw-r--r--libavcodec/avdct.c137
-rw-r--r--libavcodec/avdct.h84
-rw-r--r--libavcodec/avfft.c44
-rw-r--r--libavcodec/avfft.h8
-rw-r--r--libavcodec/avpacket.c276
-rw-r--r--libavcodec/avpicture.c19
-rw-r--r--libavcodec/avr32/mathops.h8
-rw-r--r--libavcodec/avrndec.c131
-rw-r--r--libavcodec/avs.c18
-rw-r--r--libavcodec/avuidec.c130
-rw-r--r--libavcodec/avuienc.c117
-rw-r--r--libavcodec/bethsoftvideo.c15
-rw-r--r--libavcodec/bethsoftvideo.h8
-rw-r--r--libavcodec/bfi.c22
-rw-r--r--libavcodec/bfin/README6
-rw-r--r--libavcodec/bgmc.c12
-rw-r--r--libavcodec/bgmc.h12
-rw-r--r--libavcodec/bink.c103
-rw-r--r--libavcodec/binkaudio.c24
-rw-r--r--libavcodec/binkdata.h8
-rw-r--r--libavcodec/binkdsp.c10
-rw-r--r--libavcodec/binkdsp.h8
-rw-r--r--libavcodec/bintext.c258
-rw-r--r--libavcodec/bintext.h37
-rw-r--r--libavcodec/bit_depth_template.c13
-rw-r--r--libavcodec/bitstream.c109
-rw-r--r--libavcodec/bitstream_filter.c21
-rw-r--r--libavcodec/blockdsp.c10
-rw-r--r--libavcodec/blockdsp.h9
-rw-r--r--libavcodec/bmp.c90
-rw-r--r--libavcodec/bmp.h8
-rw-r--r--libavcodec/bmp_parser.c47
-rw-r--r--libavcodec/bmpenc.c28
-rw-r--r--libavcodec/bmvaudio.c12
-rw-r--r--libavcodec/bmvvideo.c27
-rw-r--r--libavcodec/brenderpix.c42
-rw-r--r--libavcodec/bswapdsp.c8
-rw-r--r--libavcodec/bswapdsp.h8
-rw-r--r--libavcodec/bytestream.h11
-rw-r--r--libavcodec/c93.c26
-rw-r--r--libavcodec/cabac.c251
-rw-r--r--libavcodec/cabac.h18
-rw-r--r--libavcodec/cabac_functions.h24
-rw-r--r--libavcodec/cabac_tablegen.c41
-rw-r--r--libavcodec/cabac_tablegen.h108
-rw-r--r--libavcodec/canopus.c8
-rw-r--r--libavcodec/canopus.h8
-rw-r--r--libavcodec/cavs.c97
-rw-r--r--libavcodec/cavs.h14
-rw-r--r--libavcodec/cavs_parser.c8
-rw-r--r--libavcodec/cavsdata.c15
-rw-r--r--libavcodec/cavsdec.c148
-rw-r--r--libavcodec/cavsdsp.c8
-rw-r--r--libavcodec/cavsdsp.h8
-rw-r--r--libavcodec/cbrt_tablegen.c8
-rw-r--r--libavcodec/cbrt_tablegen.h13
-rw-r--r--libavcodec/ccaption_dec.c591
-rw-r--r--libavcodec/cdgraphics.c36
-rw-r--r--libavcodec/cdxl.c35
-rw-r--r--libavcodec/celp_filters.c20
-rw-r--r--libavcodec/celp_filters.h57
-rw-r--r--libavcodec/celp_math.c50
-rw-r--r--libavcodec/celp_math.h47
-rw-r--r--libavcodec/cga_data.c419
-rw-r--r--libavcodec/cga_data.h11
-rw-r--r--libavcodec/chomp_bsf.c13
-rw-r--r--libavcodec/cinepak.c257
-rw-r--r--libavcodec/cinepakenc.c1335
-rw-r--r--libavcodec/cljrdec.c23
-rw-r--r--libavcodec/cljrenc.c87
-rw-r--r--libavcodec/cllc.c26
-rw-r--r--libavcodec/cngdec.c32
-rw-r--r--libavcodec/cngenc.c14
-rw-r--r--libavcodec/codec_desc.c538
-rw-r--r--libavcodec/cook.c89
-rw-r--r--libavcodec/cook_parser.c15
-rw-r--r--libavcodec/cookdata.h8
-rw-r--r--libavcodec/copy_block.h19
-rw-r--r--libavcodec/cos_tablegen.c10
-rw-r--r--libavcodec/cpia.c233
-rw-r--r--libavcodec/crystalhd.c1226
-rw-r--r--libavcodec/cscd.c142
-rw-r--r--libavcodec/cyuv.c32
-rw-r--r--libavcodec/d3d11va.h12
-rw-r--r--libavcodec/dca.c14
-rw-r--r--libavcodec/dca.h33
-rw-r--r--libavcodec/dca_exss.c25
-rw-r--r--libavcodec/dca_parser.c10
-rw-r--r--libavcodec/dca_syncwords.h8
-rw-r--r--libavcodec/dca_xll.c12
-rw-r--r--libavcodec/dcadata.c99
-rw-r--r--libavcodec/dcadata.h13
-rw-r--r--libavcodec/dcadec.c815
-rw-r--r--libavcodec/dcadsp.c8
-rw-r--r--libavcodec/dcadsp.h10
-rw-r--r--libavcodec/dcaenc.c974
-rw-r--r--libavcodec/dcaenc.h113
-rw-r--r--libavcodec/dcahuff.h8
-rw-r--r--libavcodec/dct-test.c89
-rw-r--r--libavcodec/dct.c14
-rw-r--r--libavcodec/dct.h13
-rw-r--r--libavcodec/dct32.h8
-rw-r--r--libavcodec/dct32_fixed.c8
-rw-r--r--libavcodec/dct32_float.c8
-rw-r--r--libavcodec/dct32_template.c8
-rw-r--r--libavcodec/dctref.c8
-rw-r--r--libavcodec/dctref.h8
-rw-r--r--libavcodec/dfa.c42
-rw-r--r--libavcodec/dirac.c44
-rw-r--r--libavcodec/dirac.h11
-rw-r--r--libavcodec/dirac_arith.c116
-rw-r--r--libavcodec/dirac_arith.h195
-rw-r--r--libavcodec/dirac_dwt.c561
-rw-r--r--libavcodec/dirac_dwt.h123
-rw-r--r--libavcodec/dirac_parser.c18
-rw-r--r--libavcodec/diracdec.c2037
-rw-r--r--libavcodec/diracdsp.c201
-rw-r--r--libavcodec/diracdsp.h67
-rw-r--r--libavcodec/dnxhd_parser.c50
-rw-r--r--libavcodec/dnxhddata.c727
-rw-r--r--libavcodec/dnxhddata.h19
-rw-r--r--libavcodec/dnxhddec.c99
-rw-r--r--libavcodec/dnxhdenc.c147
-rw-r--r--libavcodec/dnxhdenc.h10
-rw-r--r--libavcodec/dpcm.c21
-rw-r--r--libavcodec/dpx.c363
-rw-r--r--libavcodec/dpx_parser.c8
-rw-r--r--libavcodec/dpxenc.c206
-rw-r--r--libavcodec/dsd_tablegen.c38
-rw-r--r--libavcodec/dsd_tablegen.h95
-rw-r--r--libavcodec/dsddec.c167
-rw-r--r--libavcodec/dsicinaudio.c12
-rw-r--r--libavcodec/dsicinvideo.c68
-rw-r--r--libavcodec/dss_sp.c21
-rw-r--r--libavcodec/dump_extradata_bsf.c13
-rw-r--r--libavcodec/dv.c56
-rw-r--r--libavcodec/dv.h19
-rw-r--r--libavcodec/dv_profile.c66
-rw-r--r--libavcodec/dv_profile.h28
-rw-r--r--libavcodec/dv_profile_internal.h16
-rw-r--r--libavcodec/dv_tablegen.c8
-rw-r--r--libavcodec/dv_tablegen.h11
-rw-r--r--libavcodec/dvbsub.c118
-rw-r--r--libavcodec/dvbsub_parser.c16
-rw-r--r--libavcodec/dvbsubdec.c528
-rw-r--r--libavcodec/dvd_nav_parser.c115
-rw-r--r--libavcodec/dvdata.c73
-rw-r--r--libavcodec/dvdata.h15
-rw-r--r--libavcodec/dvdec.c157
-rw-r--r--libavcodec/dvdsub_parser.c15
-rw-r--r--libavcodec/dvdsubdec.c341
-rw-r--r--libavcodec/dvdsubenc.c429
-rw-r--r--libavcodec/dvenc.c60
-rw-r--r--libavcodec/dxa.c100
-rw-r--r--libavcodec/dxtory.c61
-rw-r--r--libavcodec/dxva2.c8
-rw-r--r--libavcodec/dxva2.h12
-rw-r--r--libavcodec/dxva2_h264.c16
-rw-r--r--libavcodec/dxva2_hevc.c8
-rw-r--r--libavcodec/dxva2_internal.h8
-rw-r--r--libavcodec/dxva2_mpeg2.c19
-rw-r--r--libavcodec/dxva2_vc1.c52
-rw-r--r--libavcodec/eac3_data.c8
-rw-r--r--libavcodec/eac3_data.h8
-rw-r--r--libavcodec/eac3dec.c23
-rw-r--r--libavcodec/eac3enc.c16
-rw-r--r--libavcodec/eac3enc.h8
-rw-r--r--libavcodec/eacmv.c20
-rw-r--r--libavcodec/eaidct.c8
-rw-r--r--libavcodec/eaidct.h8
-rw-r--r--libavcodec/eamad.c55
-rw-r--r--libavcodec/eatgq.c24
-rw-r--r--libavcodec/eatgv.c38
-rw-r--r--libavcodec/eatqi.c17
-rw-r--r--libavcodec/elbg.c59
-rw-r--r--libavcodec/elbg.h16
-rw-r--r--libavcodec/error_resilience.c342
-rw-r--r--libavcodec/error_resilience.h16
-rw-r--r--libavcodec/escape124.c43
-rw-r--r--libavcodec/escape130.c18
-rw-r--r--libavcodec/evrcdata.h1499
-rw-r--r--libavcodec/evrcdec.c918
-rw-r--r--libavcodec/exif.c142
-rw-r--r--libavcodec/exif.h170
-rw-r--r--libavcodec/exr.c12
-rw-r--r--libavcodec/faandct.h8
-rw-r--r--libavcodec/faanidct.c8
-rw-r--r--libavcodec/faanidct.h8
-rw-r--r--libavcodec/faxcompr.c39
-rw-r--r--libavcodec/faxcompr.h8
-rw-r--r--libavcodec/fdctdsp.c10
-rw-r--r--libavcodec/fdctdsp.h8
-rw-r--r--libavcodec/fft-fixed-test.c8
-rw-r--r--libavcodec/fft-fixed32-test.c21
-rw-r--r--libavcodec/fft-internal.h29
-rw-r--r--libavcodec/fft-test.c56
-rw-r--r--libavcodec/fft.h28
-rw-r--r--libavcodec/fft_fixed.c9
-rw-r--r--libavcodec/fft_fixed_32.c52
-rw-r--r--libavcodec/fft_float.c9
-rw-r--r--libavcodec/fft_init_table.c200
-rw-r--r--libavcodec/fft_table.h66
-rw-r--r--libavcodec/fft_template.c189
-rw-r--r--libavcodec/ffv1.c171
-rw-r--r--libavcodec/ffv1.h67
-rw-r--r--libavcodec/ffv1dec.c671
-rw-r--r--libavcodec/ffv1enc.c768
-rw-r--r--libavcodec/ffwavesynth.c481
-rw-r--r--libavcodec/fic.c41
-rw-r--r--libavcodec/flac.c11
-rw-r--r--libavcodec/flac.h8
-rw-r--r--libavcodec/flac_parser.c126
-rw-r--r--libavcodec/flacdata.c10
-rw-r--r--libavcodec/flacdata.h10
-rw-r--r--libavcodec/flacdec.c210
-rw-r--r--libavcodec/flacdsp.c25
-rw-r--r--libavcodec/flacdsp.h25
-rw-r--r--libavcodec/flacdsp_lpc_template.c26
-rw-r--r--libavcodec/flacdsp_template.c8
-rw-r--r--libavcodec/flacenc.c274
-rw-r--r--libavcodec/flashsv.c50
-rw-r--r--libavcodec/flashsv2enc.c920
-rw-r--r--libavcodec/flashsvenc.c22
-rw-r--r--libavcodec/flicvideo.c142
-rw-r--r--libavcodec/flv.h9
-rw-r--r--libavcodec/flvdec.c34
-rw-r--r--libavcodec/flvenc.c8
-rw-r--r--libavcodec/fmtconvert.c40
-rw-r--r--libavcodec/fmtconvert.h13
-rw-r--r--libavcodec/frame_thread_encoder.c295
-rw-r--r--libavcodec/frame_thread_encoder.h26
-rw-r--r--libavcodec/fraps.c224
-rw-r--r--libavcodec/frwu.c43
-rw-r--r--libavcodec/g2meet.c65
-rw-r--r--libavcodec/g722.c8
-rw-r--r--libavcodec/g722.h8
-rw-r--r--libavcodec/g722dec.c14
-rw-r--r--libavcodec/g722dsp.c10
-rw-r--r--libavcodec/g722dsp.h9
-rw-r--r--libavcodec/g722enc.c21
-rw-r--r--libavcodec/g723_1.c1304
-rw-r--r--libavcodec/g723_1_data.h171
-rw-r--r--libavcodec/g726.c51
-rw-r--r--libavcodec/g729.h29
-rw-r--r--libavcodec/g729data.h382
-rw-r--r--libavcodec/g729dec.c726
-rw-r--r--libavcodec/g729postfilter.c610
-rw-r--r--libavcodec/g729postfilter.h116
-rw-r--r--libavcodec/get_bits.h143
-rw-r--r--libavcodec/gif.c307
-rw-r--r--libavcodec/gif.h49
-rw-r--r--libavcodec/gifdec.c457
-rw-r--r--libavcodec/golomb-test.c12
-rw-r--r--libavcodec/golomb.c8
-rw-r--r--libavcodec/golomb.h108
-rw-r--r--libavcodec/gsm.h8
-rw-r--r--libavcodec/gsm_parser.c13
-rw-r--r--libavcodec/gsmdec.c17
-rw-r--r--libavcodec/gsmdec_data.c8
-rw-r--r--libavcodec/gsmdec_data.h8
-rw-r--r--libavcodec/gsmdec_template.c8
-rw-r--r--libavcodec/h261.c8
-rw-r--r--libavcodec/h261.h9
-rw-r--r--libavcodec/h261_parser.c22
-rw-r--r--libavcodec/h261data.c8
-rw-r--r--libavcodec/h261dec.c90
-rw-r--r--libavcodec/h261enc.c126
-rw-r--r--libavcodec/h263.c8
-rw-r--r--libavcodec/h263.h25
-rw-r--r--libavcodec/h263_parser.c22
-rw-r--r--libavcodec/h263_parser.h8
-rw-r--r--libavcodec/h263data.h12
-rw-r--r--libavcodec/h263dec.c198
-rw-r--r--libavcodec/h263dsp.c8
-rw-r--r--libavcodec/h263dsp.h8
-rw-r--r--libavcodec/h264.c682
-rw-r--r--libavcodec/h264.h163
-rw-r--r--libavcodec/h264_cabac.c56
-rw-r--r--libavcodec/h264_cavlc.c103
-rw-r--r--libavcodec/h264_direct.c31
-rw-r--r--libavcodec/h264_loopfilter.c30
-rw-r--r--libavcodec/h264_mb.c114
-rw-r--r--libavcodec/h264_mb_template.c25
-rw-r--r--libavcodec/h264_mc_template.c14
-rw-r--r--libavcodec/h264_mp4toannexb_bsf.c129
-rw-r--r--libavcodec/h264_mvpred.h18
-rw-r--r--libavcodec/h264_parser.c170
-rw-r--r--libavcodec/h264_picture.c65
-rw-r--r--libavcodec/h264_ps.c193
-rw-r--r--libavcodec/h264_refs.c118
-rw-r--r--libavcodec/h264_sei.c185
-rw-r--r--libavcodec/h264_slice.c547
-rw-r--r--libavcodec/h264addpx_template.c8
-rw-r--r--libavcodec/h264chroma.c10
-rw-r--r--libavcodec/h264chroma.h12
-rw-r--r--libavcodec/h264chroma_template.c56
-rw-r--r--libavcodec/h264data.h29
-rw-r--r--libavcodec/h264dsp.c26
-rw-r--r--libavcodec/h264dsp.h10
-rw-r--r--libavcodec/h264dsp_template.c56
-rw-r--r--libavcodec/h264idct.c16
-rw-r--r--libavcodec/h264idct.h10
-rw-r--r--libavcodec/h264idct_template.c12
-rw-r--r--libavcodec/h264pred.c28
-rw-r--r--libavcodec/h264pred.h10
-rw-r--r--libavcodec/h264pred_template.c170
-rw-r--r--libavcodec/h264qpel.c26
-rw-r--r--libavcodec/h264qpel.h8
-rw-r--r--libavcodec/h264qpel_template.c74
-rw-r--r--libavcodec/hevc.c2091
-rw-r--r--libavcodec/hevc.h194
-rw-r--r--libavcodec/hevc_cabac.c1077
-rw-r--r--libavcodec/hevc_filter.c913
-rw-r--r--libavcodec/hevc_mvs.c510
-rw-r--r--libavcodec/hevc_parser.c272
-rw-r--r--libavcodec/hevc_ps.c419
-rw-r--r--libavcodec/hevc_refs.c99
-rw-r--r--libavcodec/hevc_sei.c110
-rw-r--r--libavcodec/hevcdsp.c191
-rw-r--r--libavcodec/hevcdsp.h132
-rw-r--r--libavcodec/hevcdsp_template.c1846
-rw-r--r--libavcodec/hevcpred.c19
-rw-r--r--libavcodec/hevcpred.h45
-rw-r--r--libavcodec/hevcpred_template.c291
-rw-r--r--libavcodec/hnm4video.c93
-rw-r--r--libavcodec/hpel_template.c8
-rw-r--r--libavcodec/hpeldsp.c10
-rw-r--r--libavcodec/hpeldsp.h9
-rw-r--r--libavcodec/hq_hqa.c16
-rw-r--r--libavcodec/hq_hqa.h8
-rw-r--r--libavcodec/hq_hqadata.c8
-rw-r--r--libavcodec/hq_hqadsp.c8
-rw-r--r--libavcodec/hq_hqadsp.h8
-rw-r--r--libavcodec/hqx.c14
-rw-r--r--libavcodec/hqx.h8
-rw-r--r--libavcodec/hqxdsp.c10
-rw-r--r--libavcodec/hqxdsp.h8
-rw-r--r--libavcodec/hqxvlc.c8
-rw-r--r--libavcodec/huffman.c72
-rw-r--r--libavcodec/huffman.h13
-rw-r--r--libavcodec/huffyuv.c34
-rw-r--r--libavcodec/huffyuv.h49
-rw-r--r--libavcodec/huffyuvdec.c758
-rw-r--r--libavcodec/huffyuvdsp.c43
-rw-r--r--libavcodec/huffyuvdsp.h30
-rw-r--r--libavcodec/huffyuvenc.c556
-rw-r--r--libavcodec/huffyuvencdsp.c12
-rw-r--r--libavcodec/huffyuvencdsp.h12
-rw-r--r--libavcodec/idcinvideo.c25
-rw-r--r--libavcodec/idctdsp.c189
-rw-r--r--libavcodec/idctdsp.h20
-rw-r--r--libavcodec/iff.c693
-rw-r--r--libavcodec/iirfilter.c34
-rw-r--r--libavcodec/iirfilter.h39
-rw-r--r--libavcodec/imc.c90
-rw-r--r--libavcodec/imcdata.h8
-rw-r--r--libavcodec/imdct15.c12
-rw-r--r--libavcodec/imdct15.h8
-rw-r--r--libavcodec/imgconvert.c193
-rw-r--r--libavcodec/imgconvert.h8
-rw-r--r--libavcodec/imx_dump_header_bsf.c13
-rw-r--r--libavcodec/indeo2.c20
-rw-r--r--libavcodec/indeo2data.h8
-rw-r--r--libavcodec/indeo3.c108
-rw-r--r--libavcodec/indeo3data.h8
-rw-r--r--libavcodec/indeo4.c89
-rw-r--r--libavcodec/indeo4data.h10
-rw-r--r--libavcodec/indeo5.c59
-rw-r--r--libavcodec/indeo5data.h8
-rw-r--r--libavcodec/intelh263dec.c24
-rw-r--r--libavcodec/internal.h82
-rw-r--r--libavcodec/interplayvideo.c66
-rw-r--r--libavcodec/intrax8.c45
-rw-r--r--libavcodec/intrax8.h11
-rw-r--r--libavcodec/intrax8dsp.c8
-rw-r--r--libavcodec/intrax8dsp.h8
-rw-r--r--libavcodec/intrax8huf.h8
-rw-r--r--libavcodec/ituh263dec.c154
-rw-r--r--libavcodec/ituh263enc.c63
-rw-r--r--libavcodec/ivi.c90
-rw-r--r--libavcodec/ivi.h10
-rw-r--r--libavcodec/ivi_dsp.c68
-rw-r--r--libavcodec/ivi_dsp.h12
-rw-r--r--libavcodec/j2kenc.c1055
-rw-r--r--libavcodec/jacosub.h45
-rw-r--r--libavcodec/jacosubdec.c202
-rw-r--r--libavcodec/jfdctint.c8
-rw-r--r--libavcodec/jfdctint_template.c4
-rw-r--r--libavcodec/jpeg2000.c121
-rw-r--r--libavcodec/jpeg2000.h22
-rw-r--r--libavcodec/jpeg2000dec.c471
-rw-r--r--libavcodec/jpeg2000dsp.c8
-rw-r--r--libavcodec/jpeg2000dsp.h8
-rw-r--r--libavcodec/jpeg2000dwt.c237
-rw-r--r--libavcodec/jpeg2000dwt.h9
-rw-r--r--libavcodec/jpegls.c14
-rw-r--r--libavcodec/jpegls.h15
-rw-r--r--libavcodec/jpeglsdec.c163
-rw-r--r--libavcodec/jpeglsdec.h8
-rw-r--r--libavcodec/jpeglsenc.c20
-rw-r--r--libavcodec/jpegtables.c12
-rw-r--r--libavcodec/jpegtables.h8
-rw-r--r--libavcodec/jrevdct.c249
-rw-r--r--libavcodec/jvdec.c43
-rw-r--r--libavcodec/kbdwin.c22
-rw-r--r--libavcodec/kbdwin.h11
-rw-r--r--libavcodec/kgv1dec.c43
-rw-r--r--libavcodec/kmvc.c37
-rw-r--r--libavcodec/lagarith.c163
-rw-r--r--libavcodec/lagarithrac.c17
-rw-r--r--libavcodec/lagarithrac.h28
-rw-r--r--libavcodec/latm_parser.c9
-rw-r--r--libavcodec/lcl.h8
-rw-r--r--libavcodec/lcldec.c49
-rw-r--r--libavcodec/lclenc.c31
-rw-r--r--libavcodec/libaacplus.c145
-rw-r--r--libavcodec/libavcodec.v3
-rw-r--r--libavcodec/libcelt_dec.c140
-rw-r--r--libavcodec/libdcadec.c26
-rw-r--r--libavcodec/libfaac.c30
-rw-r--r--libavcodec/libfdk-aacdec.c16
-rw-r--r--libavcodec/libfdk-aacenc.c6
-rw-r--r--libavcodec/libgsmdec.c20
-rw-r--r--libavcodec/libgsmenc.c34
-rw-r--r--libavcodec/libilbc.c31
-rw-r--r--libavcodec/libmp3lame.c41
-rw-r--r--libavcodec/libopencore-amr.c42
-rw-r--r--libavcodec/libopenh264enc.c8
-rw-r--r--libavcodec/libopenjpegdec.c151
-rw-r--r--libavcodec/libopenjpegenc.c481
-rw-r--r--libavcodec/libopus.c8
-rw-r--r--libavcodec/libopus.h8
-rw-r--r--libavcodec/libopusdec.c51
-rw-r--r--libavcodec/libopusenc.c51
-rw-r--r--libavcodec/libschroedinger.c13
-rw-r--r--libavcodec/libschroedinger.h8
-rw-r--r--libavcodec/libschroedingerdec.c24
-rw-r--r--libavcodec/libschroedingerenc.c13
-rw-r--r--libavcodec/libshine.c149
-rw-r--r--libavcodec/libspeexdec.c43
-rw-r--r--libavcodec/libspeexenc.c17
-rw-r--r--libavcodec/libstagefright.cpp590
-rw-r--r--libavcodec/libtheoraenc.c85
-rw-r--r--libavcodec/libtwolame.c16
-rw-r--r--libavcodec/libutvideo.h70
-rw-r--r--libavcodec/libutvideodec.cpp272
-rw-r--r--libavcodec/libutvideoenc.cpp253
-rw-r--r--libavcodec/libvo-aacenc.c22
-rw-r--r--libavcodec/libvo-amrwbenc.c20
-rw-r--r--libavcodec/libvorbis.c354
-rw-r--r--libavcodec/libvorbisdec.c207
-rw-r--r--libavcodec/libvorbisenc.c380
-rw-r--r--libavcodec/libvpx.c70
-rw-r--r--libavcodec/libvpx.h10
-rw-r--r--libavcodec/libvpxdec.c101
-rw-r--r--libavcodec/libvpxenc.c541
-rw-r--r--libavcodec/libwavpackenc.c8
-rw-r--r--libavcodec/libwebpenc.c221
-rw-r--r--libavcodec/libwebpenc_animencoder.c150
-rw-r--r--libavcodec/libwebpenc_common.c254
-rw-r--r--libavcodec/libwebpenc_common.h84
-rw-r--r--libavcodec/libx264.c254
-rw-r--r--libavcodec/libx265.c16
-rw-r--r--libavcodec/libxavs.c35
-rw-r--r--libavcodec/libxvid.c148
-rw-r--r--libavcodec/libxvid.h8
-rw-r--r--libavcodec/libxvid_rc.c65
-rw-r--r--libavcodec/libzvbi-teletextdec.c571
-rw-r--r--libavcodec/ljpegenc.c76
-rw-r--r--libavcodec/loco.c117
-rw-r--r--libavcodec/lossless_audiodsp.c49
-rw-r--r--libavcodec/lossless_audiodsp.h46
-rw-r--r--libavcodec/lossless_videodsp.c128
-rw-r--r--libavcodec/lossless_videodsp.h40
-rw-r--r--libavcodec/lpc.c20
-rw-r--r--libavcodec/lpc.h17
-rw-r--r--libavcodec/lsp.c20
-rw-r--r--libavcodec/lsp.h8
-rw-r--r--libavcodec/lzw.c14
-rw-r--r--libavcodec/lzw.h9
-rw-r--r--libavcodec/lzwenc.c17
-rw-r--r--libavcodec/mace.c19
-rw-r--r--libavcodec/mathops.c26
-rw-r--r--libavcodec/mathops.h27
-rw-r--r--libavcodec/mathtables.c10
-rw-r--r--libavcodec/mdct_fixed.c9
-rw-r--r--libavcodec/mdct_fixed_32.c52
-rw-r--r--libavcodec/mdct_float.c9
-rw-r--r--libavcodec/mdct_template.c14
-rw-r--r--libavcodec/mdec.c29
-rw-r--r--libavcodec/me_cmp.c132
-rw-r--r--libavcodec/me_cmp.h29
-rw-r--r--libavcodec/metasound.c10
-rw-r--r--libavcodec/metasound_data.c195
-rw-r--r--libavcodec/metasound_data.h8
-rw-r--r--libavcodec/microdvddec.c381
-rw-r--r--libavcodec/mimic.c23
-rw-r--r--libavcodec/mips/Makefile24
-rw-r--r--libavcodec/mips/aaccoder_mips.c2523
-rw-r--r--libavcodec/mips/aacdec_mips.c442
-rw-r--r--libavcodec/mips/aacdec_mips.h251
-rw-r--r--libavcodec/mips/aacpsdsp_mips.c460
-rw-r--r--libavcodec/mips/aacpsy_mips.h232
-rw-r--r--libavcodec/mips/aacsbr_mips.c619
-rw-r--r--libavcodec/mips/aacsbr_mips.h494
-rw-r--r--libavcodec/mips/ac3dsp_mips.c413
-rw-r--r--libavcodec/mips/acelp_filters_mips.c217
-rw-r--r--libavcodec/mips/acelp_vectors_mips.c102
-rw-r--r--libavcodec/mips/amrwbdec_mips.c187
-rw-r--r--libavcodec/mips/amrwbdec_mips.h62
-rw-r--r--libavcodec/mips/celp_filters_mips.c289
-rw-r--r--libavcodec/mips/celp_math_mips.c90
-rw-r--r--libavcodec/mips/compute_antialias_fixed.h250
-rw-r--r--libavcodec/mips/compute_antialias_float.h184
-rw-r--r--libavcodec/mips/fft_mips.c513
-rw-r--r--libavcodec/mips/fmtconvert_mips.c141
-rw-r--r--libavcodec/mips/h264dsp_init_mips.c74
-rw-r--r--libavcodec/mips/h264dsp_mips.h71
-rw-r--r--libavcodec/mips/h264dsp_msa.c3034
-rw-r--r--libavcodec/mips/hevcdsp_init_mips.c108
-rw-r--r--libavcodec/mips/hevcdsp_mips.h118
-rw-r--r--libavcodec/mips/hevcdsp_msa.c4691
-rw-r--r--libavcodec/mips/iirfilter_mips.c208
-rw-r--r--libavcodec/mips/lsp_mips.h111
-rw-r--r--libavcodec/mips/mathops.h75
-rw-r--r--libavcodec/mips/mpegaudiodsp_mips_fixed.c908
-rw-r--r--libavcodec/mips/mpegaudiodsp_mips_float.c1257
-rw-r--r--libavcodec/mips/sbrdsp_mips.c911
-rw-r--r--libavcodec/mjpeg.h9
-rw-r--r--libavcodec/mjpeg2jpeg_bsf.c8
-rw-r--r--libavcodec/mjpeg_parser.c68
-rw-r--r--libavcodec/mjpega_dump_header_bsf.c13
-rw-r--r--libavcodec/mjpegbdec.c18
-rw-r--r--libavcodec/mjpegdec.c1234
-rw-r--r--libavcodec/mjpegdec.h24
-rw-r--r--libavcodec/mjpegenc.c157
-rw-r--r--libavcodec/mjpegenc.h10
-rw-r--r--libavcodec/mjpegenc_common.c144
-rw-r--r--libavcodec/mjpegenc_common.h17
-rw-r--r--libavcodec/mlp.c8
-rw-r--r--libavcodec/mlp.h8
-rw-r--r--libavcodec/mlp_parser.c61
-rw-r--r--libavcodec/mlp_parser.h13
-rw-r--r--libavcodec/mlpdec.c121
-rw-r--r--libavcodec/mlpdsp.c8
-rw-r--r--libavcodec/mlpdsp.h8
-rw-r--r--libavcodec/mmaldec.c8
-rw-r--r--libavcodec/mmvideo.c31
-rw-r--r--libavcodec/motion-test.c152
-rw-r--r--libavcodec/motion_est.c112
-rw-r--r--libavcodec/motion_est_template.c58
-rw-r--r--libavcodec/motionpixels.c60
-rw-r--r--libavcodec/motionpixels_tablegen.c8
-rw-r--r--libavcodec/motionpixels_tablegen.h17
-rw-r--r--libavcodec/movsub_bsf.c18
-rw-r--r--libavcodec/movtextdec.c223
-rw-r--r--libavcodec/movtextenc.c165
-rw-r--r--libavcodec/mp3_header_decompress_bsf.c97
-rw-r--r--libavcodec/mpc.c14
-rw-r--r--libavcodec/mpc.h8
-rw-r--r--libavcodec/mpc7.c28
-rw-r--r--libavcodec/mpc7data.h8
-rw-r--r--libavcodec/mpc8.c24
-rw-r--r--libavcodec/mpc8data.h8
-rw-r--r--libavcodec/mpc8huff.h8
-rw-r--r--libavcodec/mpcdata.h46
-rw-r--r--libavcodec/mpeg12.c39
-rw-r--r--libavcodec/mpeg12.h8
-rw-r--r--libavcodec/mpeg12data.c76
-rw-r--r--libavcodec/mpeg12data.h11
-rw-r--r--libavcodec/mpeg12dec.c670
-rw-r--r--libavcodec/mpeg12enc.c192
-rw-r--r--libavcodec/mpeg4_unpack_bframes_bsf.c194
-rw-r--r--libavcodec/mpeg4audio.c19
-rw-r--r--libavcodec/mpeg4audio.h10
-rw-r--r--libavcodec/mpeg4data.h8
-rw-r--r--libavcodec/mpeg4video.c8
-rw-r--r--libavcodec/mpeg4video.h25
-rw-r--r--libavcodec/mpeg4video_parser.c23
-rw-r--r--libavcodec/mpeg4video_parser.h8
-rw-r--r--libavcodec/mpeg4videodec.c558
-rw-r--r--libavcodec/mpeg4videoenc.c87
-rw-r--r--libavcodec/mpeg_er.c9
-rw-r--r--libavcodec/mpeg_er.h8
-rw-r--r--libavcodec/mpegaudio.c8
-rw-r--r--libavcodec/mpegaudio.h16
-rw-r--r--libavcodec/mpegaudio_parser.c17
-rw-r--r--libavcodec/mpegaudio_tablegen.c8
-rw-r--r--libavcodec/mpegaudio_tablegen.h18
-rw-r--r--libavcodec/mpegaudiodata.c18
-rw-r--r--libavcodec/mpegaudiodata.h8
-rw-r--r--libavcodec/mpegaudiodec_fixed.c10
-rw-r--r--libavcodec/mpegaudiodec_float.c14
-rw-r--r--libavcodec/mpegaudiodec_template.c138
-rw-r--r--libavcodec/mpegaudiodecheader.c24
-rw-r--r--libavcodec/mpegaudiodecheader.h10
-rw-r--r--libavcodec/mpegaudiodectab.h8
-rw-r--r--libavcodec/mpegaudiodsp.c10
-rw-r--r--libavcodec/mpegaudiodsp.h11
-rw-r--r--libavcodec/mpegaudiodsp_data.c8
-rw-r--r--libavcodec/mpegaudiodsp_fixed.c10
-rw-r--r--libavcodec/mpegaudiodsp_float.c10
-rw-r--r--libavcodec/mpegaudiodsp_template.c17
-rw-r--r--libavcodec/mpegaudioenc.c767
-rw-r--r--libavcodec/mpegaudioenc_fixed.c41
-rw-r--r--libavcodec/mpegaudioenc_float.c42
-rw-r--r--libavcodec/mpegaudioenc_template.c785
-rw-r--r--libavcodec/mpegaudiotab.h8
-rw-r--r--libavcodec/mpegutils.c8
-rw-r--r--libavcodec/mpegutils.h8
-rw-r--r--libavcodec/mpegvideo.c1405
-rw-r--r--libavcodec/mpegvideo.h77
-rw-r--r--libavcodec/mpegvideo_enc.c643
-rw-r--r--libavcodec/mpegvideo_motion.c88
-rw-r--r--libavcodec/mpegvideo_parser.c55
-rw-r--r--libavcodec/mpegvideo_xvmc.c61
-rw-r--r--libavcodec/mpegvideodsp.c8
-rw-r--r--libavcodec/mpegvideodsp.h8
-rw-r--r--libavcodec/mpegvideoencdsp.c11
-rw-r--r--libavcodec/mpegvideoencdsp.h8
-rw-r--r--libavcodec/mpl2dec.c93
-rw-r--r--libavcodec/mqc.c8
-rw-r--r--libavcodec/mqc.h22
-rw-r--r--libavcodec/mqcdec.c8
-rw-r--r--libavcodec/mqcenc.c119
-rw-r--r--libavcodec/msgsmdec.c8
-rw-r--r--libavcodec/msgsmdec.h8
-rw-r--r--libavcodec/msmpeg4.c41
-rw-r--r--libavcodec/msmpeg4.h10
-rw-r--r--libavcodec/msmpeg4data.c8
-rw-r--r--libavcodec/msmpeg4data.h8
-rw-r--r--libavcodec/msmpeg4dec.c39
-rw-r--r--libavcodec/msmpeg4enc.c20
-rw-r--r--libavcodec/msrle.c31
-rw-r--r--libavcodec/msrledec.c111
-rw-r--r--libavcodec/msrledec.h8
-rw-r--r--libavcodec/mss1.c28
-rw-r--r--libavcodec/mss12.c19
-rw-r--r--libavcodec/mss12.h22
-rw-r--r--libavcodec/mss2.c43
-rw-r--r--libavcodec/mss2dsp.c11
-rw-r--r--libavcodec/mss2dsp.h8
-rw-r--r--libavcodec/mss3.c15
-rw-r--r--libavcodec/mss34dsp.c12
-rw-r--r--libavcodec/mss34dsp.h8
-rw-r--r--libavcodec/mss4.c21
-rw-r--r--libavcodec/msvideo1.c16
-rw-r--r--libavcodec/msvideo1enc.c305
-rw-r--r--libavcodec/mvcdec.c8
-rw-r--r--libavcodec/mxpegdec.c31
-rw-r--r--libavcodec/nellymoserdec.c18
-rw-r--r--libavcodec/nellymoserenc.c47
-rw-r--r--libavcodec/neon/mpegvideo.c8
-rw-r--r--libavcodec/noise_bsf.c18
-rw-r--r--libavcodec/nuv.c67
-rw-r--r--libavcodec/nvenc.c1452
-rw-r--r--libavcodec/old_codec_ids.h397
-rw-r--r--libavcodec/on2avc.c88
-rw-r--r--libavcodec/on2avcdata.c28
-rw-r--r--libavcodec/on2avcdata.h28
-rw-r--r--libavcodec/options.c298
-rw-r--r--libavcodec/options_table.h136
-rw-r--r--libavcodec/opus.c8
-rw-r--r--libavcodec/opus.h42
-rw-r--r--libavcodec/opus_celt.c29
-rw-r--r--libavcodec/opus_parser.c8
-rw-r--r--libavcodec/opus_silk.c8
-rw-r--r--libavcodec/opusdec.c91
-rw-r--r--libavcodec/paf.h28
-rw-r--r--libavcodec/pafaudio.c12
-rw-r--r--libavcodec/pafvideo.c41
-rw-r--r--libavcodec/pamenc.c85
-rw-r--r--libavcodec/parser.c100
-rw-r--r--libavcodec/parser.h11
-rw-r--r--libavcodec/pcm-bluray.c19
-rw-r--r--libavcodec/pcm-dvd.c46
-rw-r--r--libavcodec/pcm.c182
-rw-r--r--libavcodec/pcm_tablegen.c8
-rw-r--r--libavcodec/pcm_tablegen.h8
-rw-r--r--libavcodec/pcx.c129
-rw-r--r--libavcodec/pcxenc.c30
-rw-r--r--libavcodec/pel_template.c8
-rw-r--r--libavcodec/pgssubdec.c54
-rw-r--r--libavcodec/pictordec.c50
-rw-r--r--libavcodec/pixblockdsp.c18
-rw-r--r--libavcodec/pixblockdsp.h12
-rw-r--r--libavcodec/pixblockdsp_template.c12
-rw-r--r--libavcodec/pixels.h8
-rw-r--r--libavcodec/png.c17
-rw-r--r--libavcodec/png.h15
-rw-r--r--libavcodec/png_parser.c29
-rw-r--r--libavcodec/pngdec.c1238
-rw-r--r--libavcodec/pngdsp.c8
-rw-r--r--libavcodec/pngdsp.h12
-rw-r--r--libavcodec/pngenc.c635
-rw-r--r--libavcodec/pnm.c71
-rw-r--r--libavcodec/pnm.h8
-rw-r--r--libavcodec/pnm_parser.c8
-rw-r--r--libavcodec/pnmdec.c120
-rw-r--r--libavcodec/pnmenc.c22
-rw-r--r--libavcodec/ppc/Makefile7
-rw-r--r--libavcodec/ppc/apedsp_altivec.c82
-rw-r--r--libavcodec/ppc/asm.S8
-rw-r--r--libavcodec/ppc/audiodsp.c8
-rw-r--r--libavcodec/ppc/blockdsp.c8
-rw-r--r--libavcodec/ppc/dct-test.c8
-rw-r--r--libavcodec/ppc/fdct.h8
-rw-r--r--libavcodec/ppc/fdctdsp.c12
-rw-r--r--libavcodec/ppc/fft_altivec.S8
-rw-r--r--libavcodec/ppc/fft_init.c20
-rw-r--r--libavcodec/ppc/fft_vsx.c227
-rw-r--r--libavcodec/ppc/fft_vsx.h830
-rw-r--r--libavcodec/ppc/fmtconvert_altivec.c8
-rw-r--r--libavcodec/ppc/h264chroma_init.c8
-rw-r--r--libavcodec/ppc/h264chroma_template.c231
-rw-r--r--libavcodec/ppc/h264dsp.c117
-rw-r--r--libavcodec/ppc/h264qpel.c117
-rw-r--r--libavcodec/ppc/h264qpel_template.c383
-rw-r--r--libavcodec/ppc/hpeldsp_altivec.c229
-rw-r--r--libavcodec/ppc/hpeldsp_altivec.h8
-rw-r--r--libavcodec/ppc/huffyuvdsp_altivec.c10
-rw-r--r--libavcodec/ppc/idctdsp.c49
-rw-r--r--libavcodec/ppc/lossless_audiodsp_altivec.c93
-rw-r--r--libavcodec/ppc/mathops.h8
-rw-r--r--libavcodec/ppc/me_cmp.c184
-rw-r--r--libavcodec/ppc/mpegaudiodsp_altivec.c8
-rw-r--r--libavcodec/ppc/mpegvideo_altivec.c11
-rw-r--r--libavcodec/ppc/mpegvideodsp.c12
-rw-r--r--libavcodec/ppc/mpegvideoencdsp.c68
-rw-r--r--libavcodec/ppc/pixblockdsp.c105
-rw-r--r--libavcodec/ppc/svq1enc_altivec.c8
-rw-r--r--libavcodec/ppc/vc1dsp_altivec.c21
-rw-r--r--libavcodec/ppc/videodsp_ppc.c8
-rw-r--r--libavcodec/ppc/vorbisdsp_altivec.c8
-rw-r--r--libavcodec/ppc/vp3dsp_altivec.c26
-rw-r--r--libavcodec/ppc/vp8dsp_altivec.c94
-rw-r--r--libavcodec/proresdata.c8
-rw-r--r--libavcodec/proresdata.h8
-rw-r--r--libavcodec/proresdec.c782
-rw-r--r--libavcodec/proresdec.h55
-rw-r--r--libavcodec/proresdec2.c690
-rw-r--r--libavcodec/proresdec_lgpl.c784
-rw-r--r--libavcodec/proresdsp.c16
-rw-r--r--libavcodec/proresdsp.h13
-rw-r--r--libavcodec/proresenc.c1341
-rw-r--r--libavcodec/proresenc_anatoliy.c635
-rw-r--r--libavcodec/proresenc_kostya.c1355
-rw-r--r--libavcodec/psymodel.c38
-rw-r--r--libavcodec/psymodel.h10
-rw-r--r--libavcodec/pthread.c8
-rw-r--r--libavcodec/pthread_frame.c177
-rw-r--r--libavcodec/pthread_internal.h8
-rw-r--r--libavcodec/pthread_slice.c97
-rw-r--r--libavcodec/ptx.c20
-rw-r--r--libavcodec/put_bits.h45
-rw-r--r--libavcodec/qcelpdata.h40
-rw-r--r--libavcodec/qcelpdec.c49
-rw-r--r--libavcodec/qdm2.c304
-rw-r--r--libavcodec/qdm2_tablegen.c27
-rw-r--r--libavcodec/qdm2_tablegen.h193
-rw-r--r--libavcodec/qdm2data.h8
-rw-r--r--libavcodec/qdrw.c55
-rw-r--r--libavcodec/qpeg.c66
-rw-r--r--libavcodec/qpel_template.c10
-rw-r--r--libavcodec/qpeldsp.c56
-rw-r--r--libavcodec/qpeldsp.h8
-rw-r--r--libavcodec/qsv.c8
-rw-r--r--libavcodec/qsv.h8
-rw-r--r--libavcodec/qsv_api.c8
-rw-r--r--libavcodec/qsv_internal.h10
-rw-r--r--libavcodec/qsvdec.c8
-rw-r--r--libavcodec/qsvdec.h8
-rw-r--r--libavcodec/qsvdec_h264.c8
-rw-r--r--libavcodec/qsvenc.c8
-rw-r--r--libavcodec/qsvenc.h8
-rw-r--r--libavcodec/qsvenc_h264.c8
-rw-r--r--libavcodec/qtrle.c78
-rw-r--r--libavcodec/qtrleenc.c160
-rw-r--r--libavcodec/r210dec.c43
-rw-r--r--libavcodec/r210enc.c123
-rw-r--r--libavcodec/ra144.c39
-rw-r--r--libavcodec/ra144.h22
-rw-r--r--libavcodec/ra144dec.c23
-rw-r--r--libavcodec/ra144enc.c30
-rw-r--r--libavcodec/ra288.c49
-rw-r--r--libavcodec/ra288.h10
-rw-r--r--libavcodec/ralf.c12
-rw-r--r--libavcodec/ralfdata.h8
-rw-r--r--libavcodec/rangecoder.c20
-rw-r--r--libavcodec/rangecoder.h16
-rw-r--r--libavcodec/ratecontrol.c104
-rw-r--r--libavcodec/ratecontrol.h16
-rw-r--r--libavcodec/raw.c94
-rw-r--r--libavcodec/raw.h18
-rw-r--r--libavcodec/rawdec.c231
-rw-r--r--libavcodec/rawenc.c11
-rw-r--r--libavcodec/rdft.c8
-rw-r--r--libavcodec/rdft.h10
-rw-r--r--libavcodec/realtextdec.c85
-rw-r--r--libavcodec/rectangle.h21
-rw-r--r--libavcodec/remove_extradata_bsf.c13
-rw-r--r--libavcodec/resample.c443
-rw-r--r--libavcodec/resample2.c319
-rw-r--r--libavcodec/rl.h16
-rw-r--r--libavcodec/rl2.c18
-rw-r--r--libavcodec/rle.c8
-rw-r--r--libavcodec/rle.h8
-rw-r--r--libavcodec/rnd_avg.h11
-rw-r--r--libavcodec/roqaudioenc.c12
-rw-r--r--libavcodec/roqvideo.c8
-rw-r--r--libavcodec/roqvideo.h12
-rw-r--r--libavcodec/roqvideodec.c38
-rw-r--r--libavcodec/roqvideoenc.c119
-rw-r--r--libavcodec/rpza.c30
-rw-r--r--libavcodec/rtjpeg.c8
-rw-r--r--libavcodec/rtjpeg.h8
-rw-r--r--libavcodec/rv10.c80
-rw-r--r--libavcodec/rv10enc.c8
-rw-r--r--libavcodec/rv20enc.c20
-rw-r--r--libavcodec/rv30.c31
-rw-r--r--libavcodec/rv30data.h10
-rw-r--r--libavcodec/rv30dsp.c8
-rw-r--r--libavcodec/rv34.c93
-rw-r--r--libavcodec/rv34.h10
-rw-r--r--libavcodec/rv34_parser.c8
-rw-r--r--libavcodec/rv34data.h8
-rw-r--r--libavcodec/rv34dsp.c8
-rw-r--r--libavcodec/rv34dsp.h8
-rw-r--r--libavcodec/rv34vlc.h8
-rw-r--r--libavcodec/rv40.c15
-rw-r--r--libavcodec/rv40data.h8
-rw-r--r--libavcodec/rv40dsp.c13
-rw-r--r--libavcodec/rv40vlc2.h8
-rw-r--r--libavcodec/s302m.c37
-rw-r--r--libavcodec/s302menc.c178
-rw-r--r--libavcodec/s3tc.c33
-rw-r--r--libavcodec/s3tc.h8
-rw-r--r--libavcodec/samidec.c161
-rw-r--r--libavcodec/sanm.c267
-rw-r--r--libavcodec/sbr.h38
-rw-r--r--libavcodec/sbrdsp.c11
-rw-r--r--libavcodec/sbrdsp.h9
-rw-r--r--libavcodec/sgi.h8
-rw-r--r--libavcodec/sgidec.c57
-rw-r--r--libavcodec/sgienc.c25
-rw-r--r--libavcodec/sgirledec.c18
-rw-r--r--libavcodec/sh4/README6
-rw-r--r--libavcodec/shorten.c108
-rw-r--r--libavcodec/simple_idct.c16
-rw-r--r--libavcodec/simple_idct.h13
-rw-r--r--libavcodec/simple_idct_template.c58
-rw-r--r--libavcodec/sinewin.c8
-rw-r--r--libavcodec/sinewin.h8
-rw-r--r--libavcodec/sinewin_tablegen.c8
-rw-r--r--libavcodec/sinewin_tablegen.h8
-rw-r--r--libavcodec/sipr.c14
-rw-r--r--libavcodec/sipr.h8
-rw-r--r--libavcodec/sipr16k.c11
-rw-r--r--libavcodec/sipr16kdata.h10
-rw-r--r--libavcodec/siprdata.h10
-rw-r--r--libavcodec/smacker.c172
-rw-r--r--libavcodec/smc.c16
-rw-r--r--libavcodec/smvjpegdec.c218
-rw-r--r--libavcodec/snow.c733
-rw-r--r--libavcodec/snow.h725
-rw-r--r--libavcodec/snow_dwt.c860
-rw-r--r--libavcodec/snow_dwt.h128
-rw-r--r--libavcodec/snowdata.h132
-rw-r--r--libavcodec/snowdec.c648
-rw-r--r--libavcodec/snowenc.c2038
-rw-r--r--libavcodec/sonic.c1115
-rw-r--r--libavcodec/sp5x.h10
-rw-r--r--libavcodec/sp5xdec.c19
-rw-r--r--libavcodec/sparc/README6
-rw-r--r--libavcodec/srtdec.c161
-rw-r--r--libavcodec/srtenc.c295
-rw-r--r--libavcodec/startcode.c8
-rw-r--r--libavcodec/startcode.h14
-rw-r--r--libavcodec/subviewerdec.c76
-rw-r--r--libavcodec/sunrast.c63
-rw-r--r--libavcodec/sunrast.h8
-rw-r--r--libavcodec/sunrastenc.c35
-rw-r--r--libavcodec/svq1.c12
-rw-r--r--libavcodec/svq1.h12
-rw-r--r--libavcodec/svq13.c8
-rw-r--r--libavcodec/svq1_cb.h12
-rw-r--r--libavcodec/svq1_vlc.h10
-rw-r--r--libavcodec/svq1dec.c86
-rw-r--r--libavcodec/svq1enc.c92
-rw-r--r--libavcodec/svq1enc.h12
-rw-r--r--libavcodec/svq1enc_cb.h8
-rw-r--r--libavcodec/svq3.c162
-rw-r--r--libavcodec/svq3.h8
-rw-r--r--libavcodec/synth_filter.c8
-rw-r--r--libavcodec/synth_filter.h8
-rw-r--r--libavcodec/tableprint.h19
-rw-r--r--libavcodec/tableprint_vlc.h81
-rw-r--r--libavcodec/tak.c58
-rw-r--r--libavcodec/tak.h13
-rw-r--r--libavcodec/tak_parser.c41
-rw-r--r--libavcodec/takdec.c348
-rw-r--r--libavcodec/targa.c161
-rw-r--r--libavcodec/targa.h15
-rw-r--r--libavcodec/targa_y216dec.c83
-rw-r--r--libavcodec/targaenc.c48
-rw-r--r--libavcodec/tdsc.c12
-rw-r--r--libavcodec/textdec.c164
-rw-r--r--libavcodec/thread.h23
-rw-r--r--libavcodec/tiertexseqv.c14
-rw-r--r--libavcodec/tiff.c877
-rw-r--r--libavcodec/tiff.h111
-rw-r--r--libavcodec/tiff_common.c313
-rw-r--r--libavcodec/tiff_common.h152
-rw-r--r--libavcodec/tiff_data.c1870
-rw-r--r--libavcodec/tiff_data.h92
-rw-r--r--libavcodec/tiffenc.c237
-rw-r--r--libavcodec/tmv.c16
-rw-r--r--libavcodec/tpeldsp.c8
-rw-r--r--libavcodec/tpeldsp.h8
-rw-r--r--libavcodec/truemotion1.c18
-rw-r--r--libavcodec/truemotion1data.h8
-rw-r--r--libavcodec/truemotion2.c122
-rw-r--r--libavcodec/truespeech.c12
-rw-r--r--libavcodec/truespeech_data.h8
-rw-r--r--libavcodec/tscc.c24
-rw-r--r--libavcodec/tscc2.c16
-rw-r--r--libavcodec/tscc2data.h8
-rw-r--r--libavcodec/tta.c365
-rw-r--r--libavcodec/ttadata.c52
-rw-r--r--libavcodec/ttadata.h50
-rw-r--r--libavcodec/ttadsp.c57
-rw-r--r--libavcodec/ttadsp.h34
-rw-r--r--libavcodec/ttaenc.c232
-rw-r--r--libavcodec/twinvq.c57
-rw-r--r--libavcodec/twinvq.h10
-rw-r--r--libavcodec/twinvq_data.h8
-rw-r--r--libavcodec/twinvqdec.c15
-rw-r--r--libavcodec/txd.c22
-rw-r--r--libavcodec/ulti.c12
-rw-r--r--libavcodec/ulti_cb.h8
-rw-r--r--libavcodec/unary.h8
-rw-r--r--libavcodec/utils.c1954
-rw-r--r--libavcodec/utvideo.c8
-rw-r--r--libavcodec/utvideo.h8
-rw-r--r--libavcodec/utvideodec.c29
-rw-r--r--libavcodec/utvideoenc.c49
-rw-r--r--libavcodec/v210dec.c128
-rw-r--r--libavcodec/v210dec.h36
-rw-r--r--libavcodec/v210enc.c10
-rw-r--r--libavcodec/v210enc.h8
-rw-r--r--libavcodec/v210x.c8
-rw-r--r--libavcodec/v308dec.c83
-rw-r--r--libavcodec/v308enc.c94
-rw-r--r--libavcodec/v408dec.c103
-rw-r--r--libavcodec/v408enc.c113
-rw-r--r--libavcodec/v410dec.c16
-rw-r--r--libavcodec/v410enc.c16
-rw-r--r--libavcodec/vaapi.c11
-rw-r--r--libavcodec/vaapi.h12
-rw-r--r--libavcodec/vaapi_h264.c20
-rw-r--r--libavcodec/vaapi_internal.h8
-rw-r--r--libavcodec/vaapi_mpeg2.c12
-rw-r--r--libavcodec/vaapi_mpeg4.c21
-rw-r--r--libavcodec/vaapi_vc1.c12
-rw-r--r--libavcodec/vb.c24
-rw-r--r--libavcodec/vble.c106
-rw-r--r--libavcodec/vc1.c338
-rw-r--r--libavcodec/vc1.h28
-rw-r--r--libavcodec/vc1_block.c541
-rw-r--r--libavcodec/vc1_common.h18
-rw-r--r--libavcodec/vc1_loopfilter.c32
-rw-r--r--libavcodec/vc1_mc.c569
-rw-r--r--libavcodec/vc1_parser.c44
-rw-r--r--libavcodec/vc1_pred.c133
-rw-r--r--libavcodec/vc1_pred.h8
-rw-r--r--libavcodec/vc1acdata.h8
-rw-r--r--libavcodec/vc1data.c22
-rw-r--r--libavcodec/vc1data.h26
-rw-r--r--libavcodec/vc1dec.c260
-rw-r--r--libavcodec/vc1dsp.c196
-rw-r--r--libavcodec/vc1dsp.h14
-rw-r--r--libavcodec/vcr1.c45
-rw-r--r--libavcodec/vda.c8
-rw-r--r--libavcodec/vda.h30
-rw-r--r--libavcodec/vda_h264.c96
-rw-r--r--libavcodec/vda_h264_dec.c273
-rw-r--r--libavcodec/vda_internal.h8
-rw-r--r--libavcodec/vdpau.c384
-rw-r--r--libavcodec/vdpau.h46
-rw-r--r--libavcodec/vdpau_h264.c8
-rw-r--r--libavcodec/vdpau_internal.h37
-rw-r--r--libavcodec/vdpau_mpeg12.c8
-rw-r--r--libavcodec/vdpau_mpeg4.c11
-rw-r--r--libavcodec/vdpau_vc1.c12
-rw-r--r--libavcodec/version.h43
-rw-r--r--libavcodec/videodsp.c9
-rw-r--r--libavcodec/videodsp.h27
-rw-r--r--libavcodec/videodsp_template.c36
-rw-r--r--libavcodec/vima.c20
-rw-r--r--libavcodec/vmdaudio.c26
-rw-r--r--libavcodec/vmdvideo.c94
-rw-r--r--libavcodec/vmnc.c56
-rw-r--r--libavcodec/vorbis.c27
-rw-r--r--libavcodec/vorbis.h8
-rw-r--r--libavcodec/vorbis_data.c8
-rw-r--r--libavcodec/vorbis_enc_data.h20
-rw-r--r--libavcodec/vorbis_parser.c53
-rw-r--r--libavcodec/vorbis_parser.h26
-rw-r--r--libavcodec/vorbis_parser_internal.h23
-rw-r--r--libavcodec/vorbisdec.c220
-rw-r--r--libavcodec/vorbisdsp.c8
-rw-r--r--libavcodec/vorbisdsp.h8
-rw-r--r--libavcodec/vorbisenc.c62
-rw-r--r--libavcodec/vp3.c159
-rw-r--r--libavcodec/vp3_parser.c8
-rw-r--r--libavcodec/vp3data.h30
-rw-r--r--libavcodec/vp3dsp.c11
-rw-r--r--libavcodec/vp3dsp.h8
-rw-r--r--libavcodec/vp5.c37
-rw-r--r--libavcodec/vp56.c321
-rw-r--r--libavcodec/vp56.h44
-rw-r--r--libavcodec/vp56data.c8
-rw-r--r--libavcodec/vp56data.h8
-rw-r--r--libavcodec/vp56dsp.c8
-rw-r--r--libavcodec/vp56dsp.h8
-rw-r--r--libavcodec/vp56rac.c8
-rw-r--r--libavcodec/vp5data.h8
-rw-r--r--libavcodec/vp6.c90
-rw-r--r--libavcodec/vp6data.h8
-rw-r--r--libavcodec/vp6dsp.c8
-rw-r--r--libavcodec/vp8.c161
-rw-r--r--libavcodec/vp8.h15
-rw-r--r--libavcodec/vp8_parser.c8
-rw-r--r--libavcodec/vp8data.h8
-rw-r--r--libavcodec/vp8dsp.c26
-rw-r--r--libavcodec/vp8dsp.h8
-rw-r--r--libavcodec/vp9.c4416
-rw-r--r--libavcodec/vp9.h356
-rw-r--r--libavcodec/vp9_mc_template.c435
-rw-r--r--libavcodec/vp9_parser.c136
-rw-r--r--libavcodec/vp9block.c1685
-rw-r--r--libavcodec/vp9data.c2133
-rw-r--r--libavcodec/vp9data.h2309
-rw-r--r--libavcodec/vp9dsp.c2162
-rw-r--r--libavcodec/vp9dsp.h131
-rw-r--r--libavcodec/vp9dsp_10bpp.c26
-rw-r--r--libavcodec/vp9dsp_12bpp.c26
-rw-r--r--libavcodec/vp9dsp_8bpp.c26
-rw-r--r--libavcodec/vp9dsp_template.c2601
-rw-r--r--libavcodec/vp9mvs.c352
-rw-r--r--libavcodec/vp9prob.c274
-rw-r--r--libavcodec/vqavideo.c110
-rw-r--r--libavcodec/wavpack.c235
-rw-r--r--libavcodec/wavpack.h194
-rw-r--r--libavcodec/wavpackenc.c2991
-rw-r--r--libavcodec/wavpackenc.h664
-rw-r--r--libavcodec/webp.c97
-rw-r--r--libavcodec/webvttdec.c102
-rw-r--r--libavcodec/webvttenc.c219
-rw-r--r--libavcodec/wma.c45
-rw-r--r--libavcodec/wma.h16
-rw-r--r--libavcodec/wma_common.c8
-rw-r--r--libavcodec/wma_common.h8
-rw-r--r--libavcodec/wma_freqs.c8
-rw-r--r--libavcodec/wma_freqs.h8
-rw-r--r--libavcodec/wmadata.h10
-rw-r--r--libavcodec/wmadec.c85
-rw-r--r--libavcodec/wmaenc.c95
-rw-r--r--libavcodec/wmalosslessdec.c205
-rw-r--r--libavcodec/wmaprodata.h8
-rw-r--r--libavcodec/wmaprodec.c77
-rw-r--r--libavcodec/wmavoice.c32
-rw-r--r--libavcodec/wmavoice_data.h8
-rw-r--r--libavcodec/wmv2.c36
-rw-r--r--libavcodec/wmv2.h21
-rw-r--r--libavcodec/wmv2dec.c23
-rw-r--r--libavcodec/wmv2dsp.c8
-rw-r--r--libavcodec/wmv2dsp.h8
-rw-r--r--libavcodec/wmv2enc.c39
-rw-r--r--libavcodec/wnv1.c22
-rw-r--r--libavcodec/ws-snd1.c14
-rw-r--r--libavcodec/x86/Makefile67
-rw-r--r--libavcodec/x86/ac3dsp.asm10
-rw-r--r--libavcodec/x86/ac3dsp_init.c15
-rw-r--r--libavcodec/x86/apedsp.asm167
-rw-r--r--libavcodec/x86/apedsp_init.c47
-rw-r--r--libavcodec/x86/audiodsp.asm100
-rw-r--r--libavcodec/x86/audiodsp.h25
-rw-r--r--libavcodec/x86/audiodsp_init.c13
-rw-r--r--libavcodec/x86/audiodsp_mmx.c58
-rw-r--r--libavcodec/x86/blockdsp.asm86
-rw-r--r--libavcodec/x86/blockdsp.c120
-rw-r--r--libavcodec/x86/blockdsp_init.c60
-rw-r--r--libavcodec/x86/bswapdsp.asm13
-rw-r--r--libavcodec/x86/bswapdsp_init.c8
-rw-r--r--libavcodec/x86/cabac.h58
-rw-r--r--libavcodec/x86/cavsdsp.c169
-rw-r--r--libavcodec/x86/constants.c58
-rw-r--r--libavcodec/x86/constants.h37
-rw-r--r--libavcodec/x86/dca.h60
-rw-r--r--libavcodec/x86/dcadsp.asm19
-rw-r--r--libavcodec/x86/dcadsp_init.c13
-rw-r--r--libavcodec/x86/dct-test.c57
-rw-r--r--libavcodec/x86/dct32.asm12
-rw-r--r--libavcodec/x86/dct_init.c10
-rw-r--r--libavcodec/x86/deinterlace.asm14
-rw-r--r--libavcodec/x86/dirac_dwt.c202
-rw-r--r--libavcodec/x86/dirac_dwt.h30
-rw-r--r--libavcodec/x86/diracdsp_mmx.c156
-rw-r--r--libavcodec/x86/diracdsp_mmx.h47
-rw-r--r--libavcodec/x86/diracdsp_yasm.asm265
-rw-r--r--libavcodec/x86/dnxhdenc.asm8
-rw-r--r--libavcodec/x86/dnxhdenc_init.c8
-rw-r--r--libavcodec/x86/dwt_yasm.asm307
-rw-r--r--libavcodec/x86/fdct.c12
-rw-r--r--libavcodec/x86/fdct.h8
-rw-r--r--libavcodec/x86/fdctdsp_init.c8
-rw-r--r--libavcodec/x86/fft.asm30
-rw-r--r--libavcodec/x86/fft.h8
-rw-r--r--libavcodec/x86/fft_init.c8
-rw-r--r--libavcodec/x86/flac_dsp_gpl.asm101
-rw-r--r--libavcodec/x86/flacdsp.asm304
-rw-r--r--libavcodec/x86/flacdsp_init.c115
-rw-r--r--libavcodec/x86/fmtconvert.asm48
-rw-r--r--libavcodec/x86/fmtconvert_init.c14
-rw-r--r--libavcodec/x86/fpel.asm134
-rw-r--r--libavcodec/x86/fpel.h10
-rw-r--r--libavcodec/x86/fpel_mmx.c140
-rw-r--r--libavcodec/x86/g722dsp.asm54
-rw-r--r--libavcodec/x86/g722dsp_init.c35
-rw-r--r--libavcodec/x86/h263_loopfilter.asm10
-rw-r--r--libavcodec/x86/h263dsp_init.c8
-rw-r--r--libavcodec/x86/h264_chromamc.asm8
-rw-r--r--libavcodec/x86/h264_chromamc_10bit.asm12
-rw-r--r--libavcodec/x86/h264_deblock.asm20
-rw-r--r--libavcodec/x86/h264_deblock_10bit.asm22
-rw-r--r--libavcodec/x86/h264_i386.h44
-rw-r--r--libavcodec/x86/h264_idct.asm8
-rw-r--r--libavcodec/x86/h264_idct_10bit.asm28
-rw-r--r--libavcodec/x86/h264_intrapred.asm13
-rw-r--r--libavcodec/x86/h264_intrapred_10bit.asm55
-rw-r--r--libavcodec/x86/h264_intrapred_init.c8
-rw-r--r--libavcodec/x86/h264_qpel.c48
-rw-r--r--libavcodec/x86/h264_qpel_10bit.asm12
-rw-r--r--libavcodec/x86/h264_qpel_8bit.asm8
-rw-r--r--libavcodec/x86/h264_weight.asm15
-rw-r--r--libavcodec/x86/h264_weight_10bit.asm11
-rw-r--r--libavcodec/x86/h264chroma_init.c8
-rw-r--r--libavcodec/x86/h264dsp_init.c10
-rw-r--r--libavcodec/x86/hevc_deblock.asm453
-rw-r--r--libavcodec/x86/hevc_idct.asm122
-rw-r--r--libavcodec/x86/hevc_mc.asm1671
-rw-r--r--libavcodec/x86/hevc_res_add.asm388
-rw-r--r--libavcodec/x86/hevc_sao.asm624
-rw-r--r--libavcodec/x86/hevcdsp.h261
-rw-r--r--libavcodec/x86/hevcdsp_init.c1081
-rw-r--r--libavcodec/x86/hpeldsp.asm318
-rw-r--r--libavcodec/x86/hpeldsp.h23
-rw-r--r--libavcodec/x86/hpeldsp_init.c84
-rw-r--r--libavcodec/x86/hpeldsp_mmx.c53
-rw-r--r--libavcodec/x86/hpeldsp_rnd_template.c39
-rw-r--r--libavcodec/x86/huffyuvdsp.asm176
-rw-r--r--libavcodec/x86/huffyuvdsp_init.c79
-rw-r--r--libavcodec/x86/huffyuvencdsp_mmx.c11
-rw-r--r--libavcodec/x86/idctdsp.asm183
-rw-r--r--libavcodec/x86/idctdsp.h21
-rw-r--r--libavcodec/x86/idctdsp_init.c24
-rw-r--r--libavcodec/x86/idctdsp_mmx.c168
-rw-r--r--libavcodec/x86/imdct36.asm35
-rw-r--r--libavcodec/x86/inline_asm.h10
-rw-r--r--libavcodec/x86/lossless_audiodsp.asm157
-rw-r--r--libavcodec/x86/lossless_audiodsp_init.c49
-rw-r--r--libavcodec/x86/lossless_videodsp.asm294
-rw-r--r--libavcodec/x86/lossless_videodsp_init.c62
-rw-r--r--libavcodec/x86/lpc.c14
-rw-r--r--libavcodec/x86/mathops.h10
-rw-r--r--libavcodec/x86/me_cmp.asm646
-rw-r--r--libavcodec/x86/me_cmp_init.c938
-rw-r--r--libavcodec/x86/mlpdsp.asm196
-rw-r--r--libavcodec/x86/mlpdsp.c187
-rw-r--r--libavcodec/x86/mlpdsp_init.c204
-rw-r--r--libavcodec/x86/mpegaudiodsp.c47
-rw-r--r--libavcodec/x86/mpegvideo.c28
-rw-r--r--libavcodec/x86/mpegvideodsp.c22
-rw-r--r--libavcodec/x86/mpegvideoenc.c22
-rw-r--r--libavcodec/x86/mpegvideoenc_qns_template.c12
-rw-r--r--libavcodec/x86/mpegvideoenc_template.c71
-rw-r--r--libavcodec/x86/mpegvideoencdsp.asm151
-rw-r--r--libavcodec/x86/mpegvideoencdsp_init.c49
-rw-r--r--libavcodec/x86/pixblockdsp.asm39
-rw-r--r--libavcodec/x86/pixblockdsp_init.c15
-rw-r--r--libavcodec/x86/pngdsp.asm22
-rw-r--r--libavcodec/x86/pngdsp_init.c8
-rw-r--r--libavcodec/x86/proresdsp.asm148
-rw-r--r--libavcodec/x86/proresdsp_init.c17
-rw-r--r--libavcodec/x86/qpel.asm8
-rw-r--r--libavcodec/x86/qpeldsp.asm13
-rw-r--r--libavcodec/x86/qpeldsp_init.c18
-rw-r--r--libavcodec/x86/rnd_template.c8
-rw-r--r--libavcodec/x86/rv34dsp.asm8
-rw-r--r--libavcodec/x86/rv34dsp_init.c8
-rw-r--r--libavcodec/x86/rv40dsp.asm8
-rw-r--r--libavcodec/x86/rv40dsp_init.c72
-rw-r--r--libavcodec/x86/sbrdsp.asm332
-rw-r--r--libavcodec/x86/sbrdsp_init.c38
-rw-r--r--libavcodec/x86/simple_idct.c12
-rw-r--r--libavcodec/x86/simple_idct.h8
-rw-r--r--libavcodec/x86/snowdsp.c908
-rw-r--r--libavcodec/x86/svq1enc.asm61
-rw-r--r--libavcodec/x86/svq1enc.c73
-rw-r--r--libavcodec/x86/svq1enc_init.c42
-rw-r--r--libavcodec/x86/ttadsp.asm119
-rw-r--r--libavcodec/x86/ttadsp_init.c42
-rw-r--r--libavcodec/x86/v210-init.c48
-rw-r--r--libavcodec/x86/v210.asm90
-rw-r--r--libavcodec/x86/v210enc.asm17
-rw-r--r--libavcodec/x86/v210enc_init.c8
-rw-r--r--libavcodec/x86/vc1dsp.asm8
-rw-r--r--libavcodec/x86/vc1dsp.h8
-rw-r--r--libavcodec/x86/vc1dsp_init.c15
-rw-r--r--libavcodec/x86/vc1dsp_mmx.c128
-rw-r--r--libavcodec/x86/videodsp.asm84
-rw-r--r--libavcodec/x86/videodsp_init.c93
-rw-r--r--libavcodec/x86/vorbisdsp.asm8
-rw-r--r--libavcodec/x86/vorbisdsp_init.c8
-rw-r--r--libavcodec/x86/vp3dsp.asm52
-rw-r--r--libavcodec/x86/vp3dsp_init.c20
-rw-r--r--libavcodec/x86/vp56_arith.h23
-rw-r--r--libavcodec/x86/vp6dsp.asm8
-rw-r--r--libavcodec/x86/vp6dsp_init.c8
-rw-r--r--libavcodec/x86/vp8dsp.asm10
-rw-r--r--libavcodec/x86/vp8dsp_init.c20
-rw-r--r--libavcodec/x86/vp8dsp_loopfilter.asm8
-rw-r--r--libavcodec/x86/vp9dsp.asm277
-rw-r--r--libavcodec/x86/vp9dsp_init.c565
-rw-r--r--libavcodec/x86/vp9intrapred.asm2044
-rw-r--r--libavcodec/x86/vp9itxfm.asm2723
-rw-r--r--libavcodec/x86/vp9lpf.asm1139
-rw-r--r--libavcodec/x86/vp9mc.asm623
-rw-r--r--libavcodec/x86/w64xmmtest.c15
-rw-r--r--libavcodec/x86/xvididct.asm983
-rw-r--r--libavcodec/x86/xvididct.h12
-rw-r--r--libavcodec/x86/xvididct_init.c56
-rw-r--r--libavcodec/x86/xvididct_mmx.c548
-rw-r--r--libavcodec/x86/xvididct_sse2.c405
-rw-r--r--libavcodec/xan.c108
-rw-r--r--libavcodec/xbmdec.c125
-rw-r--r--libavcodec/xbmenc.c33
-rw-r--r--libavcodec/xface.c386
-rw-r--r--libavcodec/xface.h96
-rw-r--r--libavcodec/xfacedec.c188
-rw-r--r--libavcodec/xfaceenc.c241
-rw-r--r--libavcodec/xiph.c14
-rw-r--r--libavcodec/xiph.h14
-rw-r--r--libavcodec/xl.c15
-rw-r--r--libavcodec/xsubdec.c27
-rw-r--r--libavcodec/xsubenc.c20
-rw-r--r--libavcodec/xvididct.c17
-rw-r--r--libavcodec/xvididct.h8
-rw-r--r--libavcodec/xvmc.h12
-rw-r--r--libavcodec/xvmc_internal.h15
-rw-r--r--libavcodec/xwd.h8
-rw-r--r--libavcodec/xwddec.c21
-rw-r--r--libavcodec/xwdenc.c45
-rw-r--r--libavcodec/xxan.c33
-rw-r--r--libavcodec/y41pdec.c92
-rw-r--r--libavcodec/y41penc.c102
-rw-r--r--libavcodec/yop.c48
-rw-r--r--libavcodec/yuv4dec.c84
-rw-r--r--libavcodec/yuv4enc.c91
-rw-r--r--libavcodec/zerocodec.c6
-rw-r--r--libavcodec/zmbv.c128
-rw-r--r--libavcodec/zmbvenc.c12
-rw-r--r--libavdevice/Makefile45
-rw-r--r--libavdevice/alldevices.c28
-rw-r--r--libavdevice/alsa.c143
-rw-r--r--libavdevice/alsa.h24
-rw-r--r--libavdevice/alsa_dec.c70
-rw-r--r--libavdevice/alsa_enc.c69
-rw-r--r--libavdevice/avdevice.c247
-rw-r--r--libavdevice/avdevice.h450
-rw-r--r--libavdevice/avdeviceres.rc55
-rw-r--r--libavdevice/avfoundation.m1049
-rw-r--r--libavdevice/bktr.c34
-rw-r--r--libavdevice/caca.c241
-rw-r--r--libavdevice/decklink_common.cpp241
-rw-r--r--libavdevice/decklink_common.h97
-rw-r--r--libavdevice/decklink_common_c.h33
-rw-r--r--libavdevice/decklink_dec.cpp541
-rw-r--r--libavdevice/decklink_dec.h32
-rw-r--r--libavdevice/decklink_dec_c.c55
-rw-r--r--libavdevice/decklink_enc.cpp426
-rw-r--r--libavdevice/decklink_enc.h32
-rw-r--r--libavdevice/decklink_enc_c.c57
-rw-r--r--libavdevice/dshow.c1325
-rw-r--r--libavdevice/dshow_capture.h352
-rw-r--r--libavdevice/dshow_common.c190
-rw-r--r--libavdevice/dshow_crossbar.c208
-rw-r--r--libavdevice/dshow_enummediatypes.c103
-rw-r--r--libavdevice/dshow_enumpins.c105
-rw-r--r--libavdevice/dshow_filter.c202
-rw-r--r--libavdevice/dshow_pin.c376
-rw-r--r--libavdevice/dv1394.c15
-rw-r--r--libavdevice/dv1394.h8
-rw-r--r--libavdevice/fbdev.c276
-rw-r--r--libavdevice/fbdev_common.c134
-rw-r--r--libavdevice/fbdev_common.h38
-rw-r--r--libavdevice/fbdev_dec.c245
-rw-r--r--libavdevice/fbdev_enc.c220
-rw-r--r--libavdevice/gdigrab.c636
-rw-r--r--libavdevice/iec61883.c498
-rw-r--r--libavdevice/internal.h27
-rw-r--r--libavdevice/jack.c33
-rw-r--r--libavdevice/lavfi.c514
-rw-r--r--libavdevice/libavdevice.v2
-rw-r--r--libavdevice/libcdio.c23
-rw-r--r--libavdevice/libdc1394.c9
-rw-r--r--libavdevice/openal-dec.c254
-rw-r--r--libavdevice/opengl_enc.c1307
-rw-r--r--libavdevice/opengl_enc_shaders.h188
-rw-r--r--libavdevice/oss.c31
-rw-r--r--libavdevice/oss.h8
-rw-r--r--libavdevice/oss_dec.c13
-rw-r--r--libavdevice/oss_enc.c20
-rw-r--r--libavdevice/pulse.c197
-rw-r--r--libavdevice/pulse_audio_common.c249
-rw-r--r--libavdevice/pulse_audio_common.h38
-rw-r--r--libavdevice/pulse_audio_dec.c376
-rw-r--r--libavdevice/pulse_audio_enc.c796
-rw-r--r--libavdevice/qtkit.m362
-rw-r--r--libavdevice/sdl.c375
-rw-r--r--libavdevice/sndio.c10
-rw-r--r--libavdevice/sndio.h10
-rw-r--r--libavdevice/sndio_dec.c9
-rw-r--r--libavdevice/sndio_enc.c18
-rw-r--r--libavdevice/timefilter.c52
-rw-r--r--libavdevice/timefilter.h27
-rw-r--r--libavdevice/utils.c59
-rw-r--r--libavdevice/v4l.c363
-rw-r--r--libavdevice/v4l2-common.c105
-rw-r--r--libavdevice/v4l2-common.h62
-rw-r--r--libavdevice/v4l2.c1039
-rw-r--r--libavdevice/v4l2enc.c119
-rw-r--r--libavdevice/version.h16
-rw-r--r--libavdevice/vfwcap.c53
-rw-r--r--libavdevice/x11grab.c146
-rw-r--r--libavdevice/xcbgrab.c46
-rw-r--r--libavdevice/xv.c383
-rw-r--r--libavfilter/Makefile180
-rw-r--r--libavfilter/aeval.c483
-rw-r--r--libavfilter/af_adelay.c285
-rw-r--r--libavfilter/af_aecho.c362
-rw-r--r--libavfilter/af_afade.c303
-rw-r--r--libavfilter/af_aformat.c42
-rw-r--r--libavfilter/af_amerge.c351
-rw-r--r--libavfilter/af_amix.c88
-rw-r--r--libavfilter/af_anull.c27
-rw-r--r--libavfilter/af_apad.c161
-rw-r--r--libavfilter/af_aphaser.c301
-rw-r--r--libavfilter/af_aresample.c351
-rw-r--r--libavfilter/af_asetnsamples.c196
-rw-r--r--libavfilter/af_asetrate.c118
-rw-r--r--libavfilter/af_ashowinfo.c55
-rw-r--r--libavfilter/af_astats.c278
-rw-r--r--libavfilter/af_astreamsync.c240
-rw-r--r--libavfilter/af_asyncts.c39
-rw-r--r--libavfilter/af_atempo.c1205
-rw-r--r--libavfilter/af_biquads.c623
-rw-r--r--libavfilter/af_bs2b.c29
-rw-r--r--libavfilter/af_channelmap.c44
-rw-r--r--libavfilter/af_channelsplit.c40
-rw-r--r--libavfilter/af_chorus.c379
-rw-r--r--libavfilter/af_compand.c160
-rw-r--r--libavfilter/af_dcshift.c167
-rw-r--r--libavfilter/af_earwax.c172
-rw-r--r--libavfilter/af_flanger.c244
-rw-r--r--libavfilter/af_join.c77
-rw-r--r--libavfilter/af_ladspa.c705
-rw-r--r--libavfilter/af_pan.c431
-rw-r--r--libavfilter/af_replaygain.c613
-rw-r--r--libavfilter/af_resample.c27
-rw-r--r--libavfilter/af_silencedetect.c215
-rw-r--r--libavfilter/af_silenceremove.c482
-rw-r--r--libavfilter/af_volume.c234
-rw-r--r--libavfilter/af_volume.h42
-rw-r--r--libavfilter/af_volumedetect.c157
-rw-r--r--libavfilter/all_channel_layouts.inc68
-rw-r--r--libavfilter/allfilters.c160
-rw-r--r--libavfilter/asink_anullsink.c10
-rw-r--r--libavfilter/asrc_abuffer.h91
-rw-r--r--libavfilter/asrc_anullsrc.c117
-rw-r--r--libavfilter/asrc_flite.c283
-rw-r--r--libavfilter/asrc_sine.c240
-rw-r--r--libavfilter/audio.c58
-rw-r--r--libavfilter/audio.h50
-rw-r--r--libavfilter/avcodec.c137
-rw-r--r--libavfilter/avcodec.h69
-rw-r--r--libavfilter/avf_avectorscope.c274
-rw-r--r--libavfilter/avf_concat.c426
-rw-r--r--libavfilter/avf_showcqt.c840
-rw-r--r--libavfilter/avf_showspectrum.c532
-rw-r--r--libavfilter/avf_showwaves.c535
-rw-r--r--libavfilter/avfilter.c625
-rw-r--r--libavfilter/avfilter.h465
-rw-r--r--libavfilter/avfiltergraph.c624
-rw-r--r--libavfilter/avfiltergraph.h9
-rw-r--r--libavfilter/avfilterres.rc55
-rw-r--r--libavfilter/bbox.c75
-rw-r--r--libavfilter/bbox.h44
-rw-r--r--libavfilter/buffer.c114
-rw-r--r--libavfilter/bufferqueue.h121
-rw-r--r--libavfilter/buffersink.c428
-rw-r--r--libavfilter/buffersink.h102
-rw-r--r--libavfilter/buffersrc.c206
-rw-r--r--libavfilter/buffersrc.h83
-rw-r--r--libavfilter/deshake.h107
-rw-r--r--libavfilter/deshake_opencl.c200
-rw-r--r--libavfilter/deshake_opencl.h45
-rw-r--r--libavfilter/deshake_opencl_kernel.h225
-rw-r--r--libavfilter/drawutils.c497
-rw-r--r--libavfilter/drawutils.h120
-rw-r--r--libavfilter/dualinput.c83
-rw-r--r--libavfilter/dualinput.h46
-rw-r--r--libavfilter/f_ebur128.c933
-rw-r--r--libavfilter/f_interleave.c259
-rw-r--r--libavfilter/f_perms.c178
-rw-r--r--libavfilter/f_select.c514
-rw-r--r--libavfilter/f_sendcmd.c584
-rw-r--r--libavfilter/f_zmq.c275
-rw-r--r--libavfilter/fifo.c12
-rw-r--r--libavfilter/filtfmts.c78
-rw-r--r--libavfilter/formats.c407
-rw-r--r--libavfilter/formats.h81
-rw-r--r--libavfilter/framesync.c329
-rw-r--r--libavfilter/framesync.h296
-rw-r--r--libavfilter/generate_wave_table.c84
-rw-r--r--libavfilter/generate_wave_table.h35
-rw-r--r--libavfilter/gradfun.h16
-rw-r--r--libavfilter/graphdump.c165
-rw-r--r--libavfilter/graphparser.c145
-rw-r--r--libavfilter/interlace.h9
-rw-r--r--libavfilter/internal.h180
-rw-r--r--libavfilter/lavfutils.c107
-rw-r--r--libavfilter/lavfutils.h43
-rw-r--r--libavfilter/log2_tab.c1
-rw-r--r--libavfilter/lswsutils.c50
-rw-r--r--libavfilter/lswsutils.h38
-rw-r--r--libavfilter/opencl_allkernels.c41
-rw-r--r--libavfilter/opencl_allkernels.h29
-rw-r--r--libavfilter/pthread.c13
-rw-r--r--libavfilter/setpts.c160
-rw-r--r--libavfilter/settb.c73
-rw-r--r--libavfilter/split.c90
-rw-r--r--libavfilter/src_movie.c611
-rw-r--r--libavfilter/thread.h8
-rw-r--r--libavfilter/tinterlace.h61
-rw-r--r--libavfilter/transform.c191
-rw-r--r--libavfilter/transform.h127
-rw-r--r--libavfilter/trim.c123
-rw-r--r--libavfilter/unsharp.h85
-rw-r--r--libavfilter/unsharp_opencl.c422
-rw-r--r--libavfilter/unsharp_opencl.h34
-rw-r--r--libavfilter/unsharp_opencl_kernel.h342
-rw-r--r--libavfilter/version.h17
-rw-r--r--libavfilter/vf_alphamerge.c207
-rw-r--r--libavfilter/vf_aspect.c184
-rw-r--r--libavfilter/vf_bbox.c134
-rw-r--r--libavfilter/vf_blackdetect.c211
-rw-r--r--libavfilter/vf_blackframe.c78
-rw-r--r--libavfilter/vf_blend.c557
-rw-r--r--libavfilter/vf_boxblur.c217
-rw-r--r--libavfilter/vf_codecview.c246
-rw-r--r--libavfilter/vf_colorbalance.c214
-rw-r--r--libavfilter/vf_colorchannelmixer.c362
-rw-r--r--libavfilter/vf_colorlevels.c256
-rw-r--r--libavfilter/vf_colormatrix.c456
-rw-r--r--libavfilter/vf_copy.c22
-rw-r--r--libavfilter/vf_cover_rect.c266
-rw-r--r--libavfilter/vf_crop.c161
-rw-r--r--libavfilter/vf_cropdetect.c167
-rw-r--r--libavfilter/vf_curves.c572
-rw-r--r--libavfilter/vf_dctdnoiz.c778
-rw-r--r--libavfilter/vf_decimate.c405
-rw-r--r--libavfilter/vf_dejudder.c187
-rw-r--r--libavfilter/vf_delogo.c132
-rw-r--r--libavfilter/vf_deshake.c575
-rw-r--r--libavfilter/vf_detelecine.c349
-rw-r--r--libavfilter/vf_drawbox.c347
-rw-r--r--libavfilter/vf_drawtext.c1433
-rw-r--r--libavfilter/vf_edgedetect.c399
-rw-r--r--libavfilter/vf_elbg.c212
-rw-r--r--libavfilter/vf_eq.c388
-rw-r--r--libavfilter/vf_eq.h105
-rw-r--r--libavfilter/vf_extractplanes.c335
-rw-r--r--libavfilter/vf_fade.c312
-rw-r--r--libavfilter/vf_fftfilt.c346
-rw-r--r--libavfilter/vf_field.c111
-rw-r--r--libavfilter/vf_fieldmatch.c986
-rw-r--r--libavfilter/vf_fieldorder.c97
-rw-r--r--libavfilter/vf_find_rect.c311
-rw-r--r--libavfilter/vf_format.c73
-rw-r--r--libavfilter/vf_fps.c92
-rw-r--r--libavfilter/vf_framepack.c31
-rw-r--r--libavfilter/vf_framestep.c101
-rw-r--r--libavfilter/vf_frei0r.c182
-rw-r--r--libavfilter/vf_fspp.c693
-rw-r--r--libavfilter/vf_fspp.h97
-rw-r--r--libavfilter/vf_geq.c284
-rw-r--r--libavfilter/vf_gradfun.c62
-rw-r--r--libavfilter/vf_hflip.c142
-rw-r--r--libavfilter/vf_histeq.c282
-rw-r--r--libavfilter/vf_histogram.c378
-rw-r--r--libavfilter/vf_hqdn3d.c84
-rw-r--r--libavfilter/vf_hqdn3d.h12
-rw-r--r--libavfilter/vf_hqx.c564
-rw-r--r--libavfilter/vf_hue.c453
-rw-r--r--libavfilter/vf_idet.c464
-rw-r--r--libavfilter/vf_idet.h80
-rw-r--r--libavfilter/vf_il.c211
-rw-r--r--libavfilter/vf_interlace.c62
-rw-r--r--libavfilter/vf_kerndeint.c319
-rw-r--r--libavfilter/vf_lenscorrection.c231
-rw-r--r--libavfilter/vf_libopencv.c70
-rw-r--r--libavfilter/vf_lut.c265
-rw-r--r--libavfilter/vf_lut3d.c817
-rw-r--r--libavfilter/vf_mcdeint.c314
-rw-r--r--libavfilter/vf_mergeplanes.c313
-rw-r--r--libavfilter/vf_mpdecimate.c249
-rw-r--r--libavfilter/vf_noise.c350
-rw-r--r--libavfilter/vf_noise.h64
-rw-r--r--libavfilter/vf_null.c23
-rw-r--r--libavfilter/vf_overlay.c690
-rw-r--r--libavfilter/vf_owdenoise.c335
-rw-r--r--libavfilter/vf_pad.c210
-rw-r--r--libavfilter/vf_palettegen.c565
-rw-r--r--libavfilter/vf_paletteuse.c1071
-rw-r--r--libavfilter/vf_perspective.c488
-rw-r--r--libavfilter/vf_phase.c331
-rw-r--r--libavfilter/vf_pixdesctest.c38
-rw-r--r--libavfilter/vf_pp.c196
-rw-r--r--libavfilter/vf_pp7.c406
-rw-r--r--libavfilter/vf_pp7.h46
-rw-r--r--libavfilter/vf_psnr.c388
-rw-r--r--libavfilter/vf_pullup.c783
-rw-r--r--libavfilter/vf_pullup.h71
-rw-r--r--libavfilter/vf_qp.c183
-rw-r--r--libavfilter/vf_removelogo.c587
-rw-r--r--libavfilter/vf_repeatfields.c192
-rw-r--r--libavfilter/vf_rotate.c569
-rw-r--r--libavfilter/vf_sab.c337
-rw-r--r--libavfilter/vf_scale.c415
-rw-r--r--libavfilter/vf_select.c350
-rw-r--r--libavfilter/vf_separatefields.c146
-rw-r--r--libavfilter/vf_setfield.c94
-rw-r--r--libavfilter/vf_showinfo.c99
-rw-r--r--libavfilter/vf_showpalette.c130
-rw-r--r--libavfilter/vf_shuffleplanes.c10
-rw-r--r--libavfilter/vf_signalstats.c595
-rw-r--r--libavfilter/vf_smartblur.c305
-rw-r--r--libavfilter/vf_spp.c529
-rw-r--r--libavfilter/vf_spp.h59
-rw-r--r--libavfilter/vf_stereo3d.c666
-rw-r--r--libavfilter/vf_subtitles.c467
-rw-r--r--libavfilter/vf_super2xsai.c354
-rw-r--r--libavfilter/vf_swapuv.c109
-rw-r--r--libavfilter/vf_telecine.c293
-rw-r--r--libavfilter/vf_thumbnail.c241
-rw-r--r--libavfilter/vf_tile.c244
-rw-r--r--libavfilter/vf_tinterlace.c415
-rw-r--r--libavfilter/vf_transpose.c222
-rw-r--r--libavfilter/vf_unsharp.c234
-rw-r--r--libavfilter/vf_uspp.c503
-rw-r--r--libavfilter/vf_vflip.c24
-rw-r--r--libavfilter/vf_vidstabdetect.c221
-rw-r--r--libavfilter/vf_vidstabtransform.c322
-rw-r--r--libavfilter/vf_vignette.c359
-rw-r--r--libavfilter/vf_w3fdif.c395
-rw-r--r--libavfilter/vf_xbr.c433
-rw-r--r--libavfilter/vf_yadif.c269
-rw-r--r--libavfilter/vf_zoompan.c312
-rw-r--r--libavfilter/video.c17
-rw-r--r--libavfilter/video.h10
-rw-r--r--libavfilter/vidstabutils.c85
-rw-r--r--libavfilter/vidstabutils.h47
-rw-r--r--libavfilter/vsink_nullsink.c8
-rw-r--r--libavfilter/vsrc_cellauto.c339
-rw-r--r--libavfilter/vsrc_color.c202
-rw-r--r--libavfilter/vsrc_life.c456
-rw-r--r--libavfilter/vsrc_mandelbrot.c432
-rw-r--r--libavfilter/vsrc_movie.c286
-rw-r--r--libavfilter/vsrc_mptestsrc.c363
-rw-r--r--libavfilter/vsrc_nullsrc.c136
-rw-r--r--libavfilter/vsrc_testsrc.c785
-rw-r--r--libavfilter/x86/Makefile15
-rw-r--r--libavfilter/x86/af_volume.asm10
-rw-r--r--libavfilter/x86/af_volume_init.c8
-rw-r--r--libavfilter/x86/vf_eq.c96
-rw-r--r--libavfilter/x86/vf_fspp.asm727
-rw-r--r--libavfilter/x86/vf_fspp_init.c49
-rw-r--r--libavfilter/x86/vf_gradfun.asm8
-rw-r--r--libavfilter/x86/vf_gradfun_init.c61
-rw-r--r--libavfilter/x86/vf_hqdn3d.asm8
-rw-r--r--libavfilter/x86/vf_hqdn3d_init.c10
-rw-r--r--libavfilter/x86/vf_idet.asm170
-rw-r--r--libavfilter/x86/vf_idet_init.c87
-rw-r--r--libavfilter/x86/vf_interlace.asm8
-rw-r--r--libavfilter/x86/vf_interlace_init.c8
-rw-r--r--libavfilter/x86/vf_noise.c144
-rw-r--r--libavfilter/x86/vf_pp7.asm57
-rw-r--r--libavfilter/x86/vf_pp7_init.c34
-rw-r--r--libavfilter/x86/vf_pullup.asm178
-rw-r--r--libavfilter/x86/vf_pullup_init.c41
-rw-r--r--libavfilter/x86/vf_spp.c235
-rw-r--r--libavfilter/x86/vf_tinterlace_init.c47
-rw-r--r--libavfilter/x86/vf_yadif.asm53
-rw-r--r--libavfilter/x86/vf_yadif_init.c68
-rw-r--r--libavfilter/x86/yadif-10.asm255
-rw-r--r--libavfilter/x86/yadif-16.asm317
-rw-r--r--libavfilter/yadif.h50
-rw-r--r--libavformat/4xm.c39
-rw-r--r--libavformat/Makefile171
-rw-r--r--libavformat/a64.c11
-rw-r--r--libavformat/aacdec.c26
-rw-r--r--libavformat/ac3dec.c77
-rw-r--r--libavformat/act.c207
-rw-r--r--libavformat/adp.c98
-rw-r--r--libavformat/adtsenc.c45
-rw-r--r--libavformat/adxdec.c21
-rw-r--r--libavformat/aea.c29
-rw-r--r--libavformat/afc.c79
-rw-r--r--libavformat/aiff.h14
-rw-r--r--libavformat/aiffdec.c117
-rw-r--r--libavformat/aiffenc.c198
-rw-r--r--libavformat/allformats.c113
-rw-r--r--libavformat/amr.c28
-rw-r--r--libavformat/anm.c10
-rw-r--r--libavformat/apc.c19
-rw-r--r--libavformat/ape.c54
-rw-r--r--libavformat/apetag.c100
-rw-r--r--libavformat/apetag.h12
-rw-r--r--libavformat/apngdec.c447
-rw-r--r--libavformat/apngenc.c271
-rw-r--r--libavformat/aqtitledec.c148
-rw-r--r--libavformat/asf.c9
-rw-r--r--libavformat/asf.h19
-rw-r--r--libavformat/asfcrypt.c8
-rw-r--r--libavformat/asfcrypt.h8
-rw-r--r--libavformat/asfdec.c329
-rw-r--r--libavformat/asfenc.c248
-rw-r--r--libavformat/assdec.c261
-rw-r--r--libavformat/assenc.c217
-rw-r--r--libavformat/ast.c29
-rw-r--r--libavformat/ast.h30
-rw-r--r--libavformat/astdec.c122
-rw-r--r--libavformat/astenc.c214
-rw-r--r--libavformat/au.c103
-rw-r--r--libavformat/audiointerleave.c28
-rw-r--r--libavformat/audiointerleave.h8
-rw-r--r--libavformat/avc.c10
-rw-r--r--libavformat/avc.h8
-rw-r--r--libavformat/avformat.h867
-rw-r--r--libavformat/avformatres.rc55
-rw-r--r--libavformat/avi.h8
-rw-r--r--libavformat/avidec.c526
-rw-r--r--libavformat/avienc.c291
-rw-r--r--libavformat/avio.c194
-rw-r--r--libavformat/avio.h213
-rw-r--r--libavformat/avio_internal.h25
-rw-r--r--libavformat/aviobuf.c259
-rw-r--r--libavformat/avisynth.c15
-rw-r--r--libavformat/avlanguage.c8
-rw-r--r--libavformat/avlanguage.h8
-rw-r--r--libavformat/avr.c99
-rw-r--r--libavformat/avs.c13
-rw-r--r--libavformat/bethsoftvid.c17
-rw-r--r--libavformat/bfi.c18
-rw-r--r--libavformat/bink.c43
-rw-r--r--libavformat/bintext.c388
-rw-r--r--libavformat/bit.c163
-rw-r--r--libavformat/bluray.c235
-rw-r--r--libavformat/bmv.c8
-rw-r--r--libavformat/boadec.c79
-rw-r--r--libavformat/brstm.c297
-rw-r--r--libavformat/c93.c10
-rw-r--r--libavformat/cache.c322
-rw-r--r--libavformat/caf.c56
-rw-r--r--libavformat/caf.h8
-rw-r--r--libavformat/cafdec.c74
-rw-r--r--libavformat/cafenc.c286
-rw-r--r--libavformat/cavsvideodec.c19
-rw-r--r--libavformat/cdg.c22
-rw-r--r--libavformat/cdxl.c69
-rw-r--r--libavformat/cinedec.c325
-rw-r--r--libavformat/concat.c13
-rw-r--r--libavformat/concatdec.c652
-rw-r--r--libavformat/crcenc.c9
-rw-r--r--libavformat/crypto.c179
-rw-r--r--libavformat/cutils.c29
-rw-r--r--libavformat/dashenc.c22
-rw-r--r--libavformat/data_uri.c118
-rw-r--r--libavformat/dauddec.c12
-rw-r--r--libavformat/daudenc.c8
-rw-r--r--libavformat/dfa.c25
-rw-r--r--libavformat/diracdec.c23
-rw-r--r--libavformat/dnxhddec.c10
-rw-r--r--libavformat/dsfdec.c159
-rw-r--r--libavformat/dsicin.c13
-rw-r--r--libavformat/dss.c77
-rw-r--r--libavformat/dtsdec.c94
-rw-r--r--libavformat/dtshddec.c139
-rw-r--r--libavformat/dump.c66
-rw-r--r--libavformat/dv.c185
-rw-r--r--libavformat/dv.h10
-rw-r--r--libavformat/dvbsub.c70
-rw-r--r--libavformat/dvenc.c121
-rw-r--r--libavformat/dxa.c38
-rw-r--r--libavformat/eacdata.c17
-rw-r--r--libavformat/electronicarts.c115
-rw-r--r--libavformat/epafdec.c104
-rw-r--r--libavformat/ffm.h60
-rw-r--r--libavformat/ffmdec.c740
-rw-r--r--libavformat/ffmenc.c374
-rw-r--r--libavformat/ffmeta.h8
-rw-r--r--libavformat/ffmetadec.c26
-rw-r--r--libavformat/ffmetaenc.c8
-rw-r--r--libavformat/file.c70
-rw-r--r--libavformat/filmstripdec.c20
-rw-r--r--libavformat/filmstripenc.c10
-rw-r--r--libavformat/flac_picture.c33
-rw-r--r--libavformat/flac_picture.h11
-rw-r--r--libavformat/flacdec.c104
-rw-r--r--libavformat/flacenc.c43
-rw-r--r--libavformat/flacenc.h8
-rw-r--r--libavformat/flacenc_header.c8
-rw-r--r--libavformat/flic.c27
-rw-r--r--libavformat/flv.h32
-rw-r--r--libavformat/flvdec.c382
-rw-r--r--libavformat/flvenc.c171
-rw-r--r--libavformat/format.c204
-rw-r--r--libavformat/framecrcenc.c53
-rw-r--r--libavformat/framehash.c11
-rw-r--r--libavformat/frmdec.c110
-rw-r--r--libavformat/ftp.c819
-rw-r--r--libavformat/g722.c11
-rw-r--r--libavformat/g723_1.c10
-rw-r--r--libavformat/g729dec.c103
-rw-r--r--libavformat/gif.c418
-rw-r--r--libavformat/gifdec.c337
-rw-r--r--libavformat/golomb_tab.c1
-rw-r--r--libavformat/gopher.c8
-rw-r--r--libavformat/gsmdec.c13
-rw-r--r--libavformat/gxf.c87
-rw-r--r--libavformat/gxf.h8
-rw-r--r--libavformat/gxfenc.c184
-rw-r--r--libavformat/h261dec.c45
-rw-r--r--libavformat/h263dec.c31
-rw-r--r--libavformat/h264dec.c8
-rw-r--r--libavformat/hdsenc.c42
-rw-r--r--libavformat/hevc.c22
-rw-r--r--libavformat/hevc.h10
-rw-r--r--libavformat/hevcdec.c8
-rw-r--r--libavformat/hls.c1559
-rw-r--r--libavformat/hlsenc.c372
-rw-r--r--libavformat/hlsproto.c14
-rw-r--r--libavformat/hnm.c12
-rw-r--r--libavformat/http.c374
-rw-r--r--libavformat/http.h14
-rw-r--r--libavformat/httpauth.c13
-rw-r--r--libavformat/httpauth.h10
-rw-r--r--libavformat/icecast.c53
-rw-r--r--libavformat/icodec.c182
-rw-r--r--libavformat/icoenc.c203
-rw-r--r--libavformat/id3v1.c26
-rw-r--r--libavformat/id3v1.h8
-rw-r--r--libavformat/id3v2.c463
-rw-r--r--libavformat/id3v2.h36
-rw-r--r--libavformat/id3v2enc.c157
-rw-r--r--libavformat/idcin.c56
-rw-r--r--libavformat/idroqdec.c15
-rw-r--r--libavformat/idroqenc.c38
-rw-r--r--libavformat/iff.c597
-rw-r--r--libavformat/ilbc.c8
-rw-r--r--libavformat/img2.c15
-rw-r--r--libavformat/img2.h70
-rw-r--r--libavformat/img2_alias_pix.c73
-rw-r--r--libavformat/img2_brender_pix.c57
-rw-r--r--libavformat/img2dec.c615
-rw-r--r--libavformat/img2enc.c139
-rw-r--r--libavformat/ingenientdec.c21
-rw-r--r--libavformat/internal.h109
-rw-r--r--libavformat/ipmovie.c52
-rw-r--r--libavformat/ircam.c47
-rw-r--r--libavformat/ircam.h30
-rw-r--r--libavformat/ircamdec.c115
-rw-r--r--libavformat/ircamenc.c62
-rw-r--r--libavformat/isom.c142
-rw-r--r--libavformat/isom.h57
-rw-r--r--libavformat/iss.c28
-rw-r--r--libavformat/iv8.c8
-rw-r--r--libavformat/ivfdec.c8
-rw-r--r--libavformat/ivfenc.c15
-rw-r--r--libavformat/jacosubdec.c274
-rw-r--r--libavformat/jacosubenc.c42
-rw-r--r--libavformat/jvdec.c22
-rw-r--r--libavformat/latmenc.c91
-rw-r--r--libavformat/libavformat.v16
-rw-r--r--libavformat/libgme.c201
-rw-r--r--libavformat/libmodplug.c382
-rw-r--r--libavformat/libnut.c324
-rw-r--r--libavformat/libquvi.c153
-rw-r--r--libavformat/librtmp.c25
-rw-r--r--libavformat/libsmbclient.c320
-rw-r--r--libavformat/libssh.c323
-rw-r--r--libavformat/lmlm4.c14
-rw-r--r--libavformat/loasdec.c94
-rw-r--r--libavformat/lrc.c34
-rw-r--r--libavformat/lrc.h29
-rw-r--r--libavformat/lrcdec.c248
-rw-r--r--libavformat/lrcenc.c152
-rw-r--r--libavformat/lvfdec.c152
-rw-r--r--libavformat/lxfdec.c20
-rw-r--r--libavformat/m4vdec.c22
-rw-r--r--libavformat/matroska.c56
-rw-r--r--libavformat/matroska.h56
-rw-r--r--libavformat/matroskadec.c1429
-rw-r--r--libavformat/matroskaenc.c879
-rw-r--r--libavformat/md5enc.c87
-rw-r--r--libavformat/md5proto.c8
-rw-r--r--libavformat/metadata.c10
-rw-r--r--libavformat/metadata.h8
-rw-r--r--libavformat/mgsts.c106
-rw-r--r--libavformat/microdvddec.c204
-rw-r--r--libavformat/microdvdenc.c67
-rw-r--r--libavformat/mkvtimestamp_v2.c50
-rw-r--r--libavformat/mlvdec.c465
-rw-r--r--libavformat/mm.c9
-rw-r--r--libavformat/mmf.c92
-rw-r--r--libavformat/mms.c8
-rw-r--r--libavformat/mms.h8
-rw-r--r--libavformat/mmsh.c77
-rw-r--r--libavformat/mmst.c33
-rw-r--r--libavformat/mov.c1474
-rw-r--r--libavformat/mov_chan.c18
-rw-r--r--libavformat/mov_chan.h8
-rw-r--r--libavformat/movenc.c1673
-rw-r--r--libavformat/movenc.h32
-rw-r--r--libavformat/movenchint.c23
-rw-r--r--libavformat/mp3dec.c274
-rw-r--r--libavformat/mp3enc.c148
-rw-r--r--libavformat/mpc.c19
-rw-r--r--libavformat/mpc8.c50
-rw-r--r--libavformat/mpeg.c652
-rw-r--r--libavformat/mpeg.h11
-rw-r--r--libavformat/mpegenc.c146
-rw-r--r--libavformat/mpegts.c904
-rw-r--r--libavformat/mpegts.h25
-rw-r--r--libavformat/mpegtsenc.c475
-rw-r--r--libavformat/mpegvideodec.c61
-rw-r--r--libavformat/mpjpeg.c41
-rw-r--r--libavformat/mpl2dec.c146
-rw-r--r--libavformat/mpsubdec.c144
-rw-r--r--libavformat/msnwc_tcp.c14
-rw-r--r--libavformat/mtv.c58
-rw-r--r--libavformat/mux.c619
-rw-r--r--libavformat/mvdec.c36
-rw-r--r--libavformat/mvi.c12
-rw-r--r--libavformat/mxf.c15
-rw-r--r--libavformat/mxf.h45
-rw-r--r--libavformat/mxfdec.c1253
-rw-r--r--libavformat/mxfenc.c1044
-rw-r--r--libavformat/mxg.c24
-rw-r--r--libavformat/ncdec.c10
-rw-r--r--libavformat/network.c64
-rw-r--r--libavformat/network.h33
-rw-r--r--libavformat/nistspheredec.c131
-rw-r--r--libavformat/noproxy-test.c8
-rw-r--r--libavformat/nsvdec.c72
-rw-r--r--libavformat/nullenc.c10
-rw-r--r--libavformat/nut.c196
-rw-r--r--libavformat/nut.h17
-rw-r--r--libavformat/nutdec.c411
-rw-r--r--libavformat/nutenc.c495
-rw-r--r--libavformat/nuv.c101
-rw-r--r--libavformat/oggdec.c401
-rw-r--r--libavformat/oggdec.h8
-rw-r--r--libavformat/oggenc.c83
-rw-r--r--libavformat/oggparsecelt.c27
-rw-r--r--libavformat/oggparsedirac.c10
-rw-r--r--libavformat/oggparseflac.c38
-rw-r--r--libavformat/oggparseogm.c28
-rw-r--r--libavformat/oggparseopus.c100
-rw-r--r--libavformat/oggparseskeleton.c25
-rw-r--r--libavformat/oggparsespeex.c10
-rw-r--r--libavformat/oggparsetheora.c40
-rw-r--r--libavformat/oggparsevorbis.c113
-rw-r--r--libavformat/oggparsevp8.c8
-rw-r--r--libavformat/oma.c8
-rw-r--r--libavformat/oma.h8
-rw-r--r--libavformat/omadec.c34
-rw-r--r--libavformat/omaenc.c13
-rw-r--r--libavformat/options.c23
-rw-r--r--libavformat/options_table.h44
-rw-r--r--libavformat/os_support.c15
-rw-r--r--libavformat/os_support.h31
-rw-r--r--libavformat/paf.c21
-rw-r--r--libavformat/pcm.c26
-rw-r--r--libavformat/pcm.h9
-rw-r--r--libavformat/pcmdec.c68
-rw-r--r--libavformat/pcmenc.c8
-rw-r--r--libavformat/pjsdec.c138
-rw-r--r--libavformat/pmpdec.c92
-rw-r--r--libavformat/psxstr.c71
-rw-r--r--libavformat/pva.c44
-rw-r--r--libavformat/pvfdec.c75
-rw-r--r--libavformat/qcp.c20
-rw-r--r--libavformat/qtpalette.h8
-rw-r--r--libavformat/r3d.c19
-rw-r--r--libavformat/rawdec.c183
-rw-r--r--libavformat/rawdec.h42
-rw-r--r--libavformat/rawenc.c85
-rw-r--r--libavformat/rawenc.h8
-rw-r--r--libavformat/rawvideodec.c40
-rw-r--r--libavformat/rdt.c25
-rw-r--r--libavformat/rdt.h8
-rw-r--r--libavformat/realtextdec.c156
-rw-r--r--libavformat/redspark.c170
-rw-r--r--libavformat/replaygain.c8
-rw-r--r--libavformat/replaygain.h8
-rw-r--r--libavformat/riff.c49
-rw-r--r--libavformat/riff.h44
-rw-r--r--libavformat/riffdec.c104
-rw-r--r--libavformat/riffenc.c101
-rw-r--r--libavformat/rl2.c27
-rw-r--r--libavformat/rm.c8
-rw-r--r--libavformat/rm.h10
-rw-r--r--libavformat/rmdec.c282
-rw-r--r--libavformat/rmenc.c23
-rw-r--r--libavformat/rmsipr.c8
-rw-r--r--libavformat/rmsipr.h8
-rw-r--r--libavformat/rpl.c39
-rw-r--r--libavformat/rsd.c168
-rw-r--r--libavformat/rso.c8
-rw-r--r--libavformat/rso.h8
-rw-r--r--libavformat/rsodec.c29
-rw-r--r--libavformat/rsoenc.c8
-rw-r--r--libavformat/rtmp.h8
-rw-r--r--libavformat/rtmpcrypt.c8
-rw-r--r--libavformat/rtmpcrypt.h8
-rw-r--r--libavformat/rtmpdh.c8
-rw-r--r--libavformat/rtmpdh.h8
-rw-r--r--libavformat/rtmphttp.c8
-rw-r--r--libavformat/rtmppkt.c9
-rw-r--r--libavformat/rtmppkt.h8
-rw-r--r--libavformat/rtmpproto.c93
-rw-r--r--libavformat/rtp.c11
-rw-r--r--libavformat/rtp.h8
-rw-r--r--libavformat/rtpdec.c27
-rw-r--r--libavformat/rtpdec.h12
-rw-r--r--libavformat/rtpdec_ac3.c8
-rw-r--r--libavformat/rtpdec_amr.c8
-rw-r--r--libavformat/rtpdec_asf.c30
-rw-r--r--libavformat/rtpdec_dv.c8
-rw-r--r--libavformat/rtpdec_formats.h10
-rw-r--r--libavformat/rtpdec_g726.c8
-rw-r--r--libavformat/rtpdec_h261.c8
-rw-r--r--libavformat/rtpdec_h263.c8
-rw-r--r--libavformat/rtpdec_h263_rfc2190.c8
-rw-r--r--libavformat/rtpdec_h264.c16
-rw-r--r--libavformat/rtpdec_hevc.c40
-rw-r--r--libavformat/rtpdec_ilbc.c8
-rw-r--r--libavformat/rtpdec_jpeg.c31
-rw-r--r--libavformat/rtpdec_latm.c17
-rw-r--r--libavformat/rtpdec_mpa_robust.c8
-rw-r--r--libavformat/rtpdec_mpeg12.c8
-rw-r--r--libavformat/rtpdec_mpeg4.c21
-rw-r--r--libavformat/rtpdec_mpegts.c20
-rw-r--r--libavformat/rtpdec_qcelp.c8
-rw-r--r--libavformat/rtpdec_qdm2.c18
-rw-r--r--libavformat/rtpdec_qt.c10
-rw-r--r--libavformat/rtpdec_svq3.c13
-rw-r--r--libavformat/rtpdec_vp8.c8
-rw-r--r--libavformat/rtpdec_vp9.c8
-rw-r--r--libavformat/rtpdec_xiph.c28
-rw-r--r--libavformat/rtpenc.c25
-rw-r--r--libavformat/rtpenc.h12
-rw-r--r--libavformat/rtpenc_aac.c8
-rw-r--r--libavformat/rtpenc_amr.c8
-rw-r--r--libavformat/rtpenc_chain.c14
-rw-r--r--libavformat/rtpenc_chain.h8
-rw-r--r--libavformat/rtpenc_h261.c12
-rw-r--r--libavformat/rtpenc_h263.c12
-rw-r--r--libavformat/rtpenc_h263_rfc2190.c23
-rw-r--r--libavformat/rtpenc_h264_hevc.c8
-rw-r--r--libavformat/rtpenc_jpeg.c17
-rw-r--r--libavformat/rtpenc_latm.c8
-rw-r--r--libavformat/rtpenc_mpegts.c8
-rw-r--r--libavformat/rtpenc_mpv.c8
-rw-r--r--libavformat/rtpenc_vp8.c8
-rw-r--r--libavformat/rtpenc_xiph.c11
-rw-r--r--libavformat/rtpproto.c62
-rw-r--r--libavformat/rtpproto.h8
-rw-r--r--libavformat/rtsp.c131
-rw-r--r--libavformat/rtsp.h21
-rw-r--r--libavformat/rtspcodes.h125
-rw-r--r--libavformat/rtspdec.c44
-rw-r--r--libavformat/rtspenc.c17
-rw-r--r--libavformat/samidec.c140
-rw-r--r--libavformat/sapdec.c13
-rw-r--r--libavformat/sapenc.c17
-rw-r--r--libavformat/sauce.c10
-rw-r--r--libavformat/sauce.h8
-rw-r--r--libavformat/sbgdec.c1512
-rw-r--r--libavformat/sctp.c16
-rw-r--r--libavformat/sdp.c28
-rw-r--r--libavformat/sdr2.c121
-rw-r--r--libavformat/seek-test.c45
-rw-r--r--libavformat/segafilm.c89
-rw-r--r--libavformat/segment.c892
-rw-r--r--libavformat/sierravmd.c93
-rw-r--r--libavformat/siff.c30
-rw-r--r--libavformat/smacker.c67
-rw-r--r--libavformat/smjpeg.c8
-rw-r--r--libavformat/smjpeg.h8
-rw-r--r--libavformat/smjpegdec.c14
-rw-r--r--libavformat/smjpegenc.c10
-rw-r--r--libavformat/smoothstreamingenc.c34
-rw-r--r--libavformat/smush.c18
-rw-r--r--libavformat/sol.c15
-rw-r--r--libavformat/sox.h8
-rw-r--r--libavformat/soxdec.c38
-rw-r--r--libavformat/soxenc.c25
-rw-r--r--libavformat/spdif.c8
-rw-r--r--libavformat/spdif.h11
-rw-r--r--libavformat/spdifdec.c35
-rw-r--r--libavformat/spdifenc.c30
-rw-r--r--libavformat/srtdec.c168
-rw-r--r--libavformat/srtenc.c112
-rw-r--r--libavformat/srtp.c8
-rw-r--r--libavformat/srtp.h8
-rw-r--r--libavformat/srtpproto.c8
-rw-r--r--libavformat/stldec.c141
-rw-r--r--libavformat/subfile.c147
-rw-r--r--libavformat/subtitles.c398
-rw-r--r--libavformat/subtitles.h210
-rw-r--r--libavformat/subviewer1dec.c124
-rw-r--r--libavformat/subviewerdec.c194
-rw-r--r--libavformat/supdec.c109
-rw-r--r--libavformat/swf.c8
-rw-r--r--libavformat/swf.h105
-rw-r--r--libavformat/swfdec.c361
-rw-r--r--libavformat/swfenc.c33
-rw-r--r--libavformat/takdec.c50
-rw-r--r--libavformat/tcp.c42
-rw-r--r--libavformat/tedcaptionsdec.c366
-rw-r--r--libavformat/tee.c495
-rw-r--r--libavformat/thp.c55
-rw-r--r--libavformat/tiertexseq.c10
-rw-r--r--libavformat/tls.c91
-rw-r--r--libavformat/tmv.c10
-rw-r--r--libavformat/tta.c102
-rw-r--r--libavformat/tty.c43
-rw-r--r--libavformat/txd.c33
-rw-r--r--libavformat/udp.c367
-rw-r--r--libavformat/uncodedframecrcenc.c172
-rw-r--r--libavformat/unix.c11
-rw-r--r--libavformat/url-test.c8
-rw-r--r--libavformat/url.c26
-rw-r--r--libavformat/url.h28
-rw-r--r--libavformat/urldecode.c8
-rw-r--r--libavformat/urldecode.h8
-rw-r--r--libavformat/utils.c2343
-rw-r--r--libavformat/vc1test.c15
-rw-r--r--libavformat/vc1testenc.c11
-rw-r--r--libavformat/version.h18
-rw-r--r--libavformat/vivo.c313
-rw-r--r--libavformat/voc.c8
-rw-r--r--libavformat/voc.h9
-rw-r--r--libavformat/vocdec.c56
-rw-r--r--libavformat/vocenc.c22
-rw-r--r--libavformat/vorbiscomment.c19
-rw-r--r--libavformat/vorbiscomment.h10
-rw-r--r--libavformat/vplayerdec.c128
-rw-r--r--libavformat/vqf.c31
-rw-r--r--libavformat/w64.c50
-rw-r--r--libavformat/w64.h31
-rw-r--r--libavformat/wavdec.c422
-rw-r--r--libavformat/wavenc.c488
-rw-r--r--libavformat/wc3movie.c21
-rw-r--r--libavformat/webm_chunk.c266
-rw-r--r--libavformat/webmdashenc.c550
-rw-r--r--libavformat/webpenc.c218
-rw-r--r--libavformat/webvttdec.c223
-rw-r--r--libavformat/webvttenc.c100
-rw-r--r--libavformat/westwood_aud.c14
-rw-r--r--libavformat/westwood_vqa.c53
-rw-r--r--libavformat/wtv.c1128
-rw-r--r--libavformat/wtv.h60
-rw-r--r--libavformat/wtv_common.c84
-rw-r--r--libavformat/wtvdec.c1132
-rw-r--r--libavformat/wtvenc.c845
-rw-r--r--libavformat/wv.c8
-rw-r--r--libavformat/wv.h8
-rw-r--r--libavformat/wvdec.c60
-rw-r--r--libavformat/wvenc.c12
-rw-r--r--libavformat/xa.c11
-rw-r--r--libavformat/xmv.c198
-rw-r--r--libavformat/xwma.c23
-rw-r--r--libavformat/yop.c25
-rw-r--r--libavformat/yuv4mpeg.h8
-rw-r--r--libavformat/yuv4mpegdec.c83
-rw-r--r--libavformat/yuv4mpegenc.c156
-rw-r--r--libavresample/Makefile3
-rw-r--r--libavresample/aarch64/asm-offsets.h8
-rw-r--r--libavresample/aarch64/audio_convert_init.c8
-rw-r--r--libavresample/aarch64/audio_convert_neon.S8
-rw-r--r--libavresample/aarch64/neontest.c8
-rw-r--r--libavresample/aarch64/resample_init.c8
-rw-r--r--libavresample/aarch64/resample_neon.S8
-rw-r--r--libavresample/arm/asm-offsets.h8
-rw-r--r--libavresample/arm/audio_convert_init.c8
-rw-r--r--libavresample/arm/audio_convert_neon.S8
-rw-r--r--libavresample/arm/neontest.c8
-rw-r--r--libavresample/arm/resample_init.c8
-rw-r--r--libavresample/arm/resample_neon.S8
-rw-r--r--libavresample/audio_convert.c8
-rw-r--r--libavresample/audio_convert.h8
-rw-r--r--libavresample/audio_data.c8
-rw-r--r--libavresample/audio_data.h8
-rw-r--r--libavresample/audio_mix.c10
-rw-r--r--libavresample/audio_mix.h8
-rw-r--r--libavresample/audio_mix_matrix.c8
-rw-r--r--libavresample/avresample-test.c8
-rw-r--r--libavresample/avresample.h10
-rw-r--r--libavresample/avresampleres.rc55
-rw-r--r--libavresample/dither.c8
-rw-r--r--libavresample/dither.h8
-rw-r--r--libavresample/internal.h8
-rw-r--r--libavresample/options.c8
-rw-r--r--libavresample/resample.c8
-rw-r--r--libavresample/resample.h8
-rw-r--r--libavresample/resample_template.c8
-rw-r--r--libavresample/utils.c14
-rw-r--r--libavresample/version.h8
-rw-r--r--libavresample/x86/audio_convert.asm42
-rw-r--r--libavresample/x86/audio_convert_init.c8
-rw-r--r--libavresample/x86/audio_mix.asm16
-rw-r--r--libavresample/x86/audio_mix_init.c8
-rw-r--r--libavresample/x86/dither.asm8
-rw-r--r--libavresample/x86/dither_init.c8
-rw-r--r--libavresample/x86/util.asm8
-rw-r--r--libavresample/x86/w64xmmtest.c8
-rw-r--r--libavutil/Makefile66
-rw-r--r--libavutil/aarch64/asm.S8
-rw-r--r--libavutil/aarch64/bswap.h8
-rw-r--r--libavutil/aarch64/cpu.c8
-rw-r--r--libavutil/aarch64/cpu.h8
-rw-r--r--libavutil/aarch64/float_dsp_init.c8
-rw-r--r--libavutil/aarch64/float_dsp_neon.S8
-rw-r--r--libavutil/aarch64/neontest.h8
-rw-r--r--libavutil/adler32.c46
-rw-r--r--libavutil/adler32.h8
-rw-r--r--libavutil/aes.c22
-rw-r--r--libavutil/aes.h12
-rw-r--r--libavutil/arm/asm.S8
-rw-r--r--libavutil/arm/bswap.h8
-rw-r--r--libavutil/arm/cpu.c17
-rw-r--r--libavutil/arm/cpu.h15
-rw-r--r--libavutil/arm/float_dsp_arm.h8
-rw-r--r--libavutil/arm/float_dsp_init_arm.c8
-rw-r--r--libavutil/arm/float_dsp_init_neon.c8
-rw-r--r--libavutil/arm/float_dsp_init_vfp.c10
-rw-r--r--libavutil/arm/float_dsp_neon.S8
-rw-r--r--libavutil/arm/float_dsp_vfp.S8
-rw-r--r--libavutil/arm/intmath.h8
-rw-r--r--libavutil/arm/intreadwrite.h8
-rw-r--r--libavutil/arm/neontest.h8
-rw-r--r--libavutil/arm/timer.h8
-rw-r--r--libavutil/atomic.c16
-rw-r--r--libavutil/atomic.h8
-rw-r--r--libavutil/atomic_gcc.h25
-rw-r--r--libavutil/atomic_suncc.h8
-rw-r--r--libavutil/atomic_win32.h9
-rw-r--r--libavutil/attributes.h46
-rw-r--r--libavutil/audio_fifo.c12
-rw-r--r--libavutil/audio_fifo.h15
-rw-r--r--libavutil/avassert.h10
-rw-r--r--libavutil/avr32/bswap.h8
-rw-r--r--libavutil/avr32/intreadwrite.h8
-rw-r--r--libavutil/avstring.c233
-rw-r--r--libavutil/avstring.h158
-rw-r--r--libavutil/avutil.h90
-rw-r--r--libavutil/avutilres.rc55
-rw-r--r--libavutil/base64.c172
-rw-r--r--libavutil/base64.h20
-rw-r--r--libavutil/bfin/bswap.h8
-rw-r--r--libavutil/bfin/timer.h8
-rw-r--r--libavutil/blowfish.c52
-rw-r--r--libavutil/blowfish.h9
-rw-r--r--libavutil/bprint.c381
-rw-r--r--libavutil/bprint.h219
-rw-r--r--libavutil/bswap.h10
-rw-r--r--libavutil/buffer.c122
-rw-r--r--libavutil/buffer.h19
-rw-r--r--libavutil/buffer_internal.h10
-rw-r--r--libavutil/camellia.c470
-rw-r--r--libavutil/camellia.h70
-rw-r--r--libavutil/cast5.c593
-rw-r--r--libavutil/cast5.h79
-rw-r--r--libavutil/channel_layout.c198
-rw-r--r--libavutil/channel_layout.h58
-rw-r--r--libavutil/color_utils.c52
-rw-r--r--libavutil/color_utils.h39
-rw-r--r--libavutil/colorspace.h8
-rw-r--r--libavutil/common.h99
-rw-r--r--libavutil/cpu.c163
-rw-r--r--libavutil/cpu.h43
-rw-r--r--libavutil/cpu_internal.h8
-rw-r--r--libavutil/crc.c60
-rw-r--r--libavutil/crc.h19
-rw-r--r--libavutil/des.c18
-rw-r--r--libavutil/des.h8
-rw-r--r--libavutil/dict.c240
-rw-r--r--libavutil/dict.h72
-rw-r--r--libavutil/display.c14
-rw-r--r--libavutil/display.h8
-rw-r--r--libavutil/downmix_info.c8
-rw-r--r--libavutil/downmix_info.h15
-rw-r--r--libavutil/dynarray.h70
-rw-r--r--libavutil/error.c110
-rw-r--r--libavutil/error.h80
-rw-r--r--libavutil/eval.c247
-rw-r--r--libavutil/eval.h12
-rw-r--r--libavutil/fifo.c86
-rw-r--r--libavutil/fifo.h39
-rw-r--r--libavutil/file.c75
-rw-r--r--libavutil/file.h21
-rw-r--r--libavutil/file_open.c50
-rw-r--r--libavutil/fixed_dsp.c102
-rw-r--r--libavutil/fixed_dsp.h144
-rw-r--r--libavutil/float_dsp.c61
-rw-r--r--libavutil/float_dsp.h18
-rw-r--r--libavutil/frame.c307
-rw-r--r--libavutil/frame.h188
-rw-r--r--libavutil/hash.c239
-rw-r--r--libavutil/hash.h112
-rw-r--r--libavutil/hmac.c132
-rw-r--r--libavutil/hmac.h12
-rw-r--r--libavutil/imgutils.c90
-rw-r--r--libavutil/imgutils.h11
-rw-r--r--libavutil/integer.c196
-rw-r--r--libavutil/integer.h86
-rw-r--r--libavutil/internal.h75
-rw-r--r--libavutil/intfloat.h8
-rw-r--r--libavutil/intmath.c8
-rw-r--r--libavutil/intmath.h51
-rw-r--r--libavutil/intreadwrite.h102
-rw-r--r--libavutil/lfg.c12
-rw-r--r--libavutil/lfg.h8
-rw-r--r--libavutil/libm.h19
-rw-r--r--libavutil/lls.c31
-rw-r--r--libavutil/lls.h19
-rw-r--r--libavutil/log.c323
-rw-r--r--libavutil/log.h94
-rw-r--r--libavutil/log2_tab.c10
-rw-r--r--libavutil/lzo.c89
-rw-r--r--libavutil/lzo.h8
-rw-r--r--libavutil/macros.h8
-rw-r--r--libavutil/mathematics.c70
-rw-r--r--libavutil/mathematics.h63
-rw-r--r--libavutil/md5.c106
-rw-r--r--libavutil/md5.h46
-rw-r--r--libavutil/mem.c188
-rw-r--r--libavutil/mem.h126
-rw-r--r--libavutil/mips/Makefile1
-rw-r--r--libavutil/mips/asmdefs.h46
-rw-r--r--libavutil/mips/float_dsp_mips.c352
-rw-r--r--libavutil/mips/generic_macros_msa.h1426
-rw-r--r--libavutil/mips/intreadwrite.h12
-rw-r--r--libavutil/mips/libm_mips.h73
-rw-r--r--libavutil/motion_vector.h50
-rw-r--r--libavutil/murmur3.c192
-rw-r--r--libavutil/murmur3.h32
-rw-r--r--libavutil/old_pix_fmts.h55
-rw-r--r--libavutil/opencl.c853
-rw-r--r--libavutil/opencl.h291
-rw-r--r--libavutil/opencl_internal.c59
-rw-r--r--libavutil/opencl_internal.h33
-rw-r--r--libavutil/opt.c1515
-rw-r--r--libavutil/opt.h387
-rw-r--r--libavutil/parseutils.c283
-rw-r--r--libavutil/parseutils.h58
-rw-r--r--libavutil/pca.c256
-rw-r--r--libavutil/pca.h35
-rw-r--r--libavutil/pixdesc.c865
-rw-r--r--libavutil/pixdesc.h109
-rw-r--r--libavutil/pixelutils.c222
-rw-r--r--libavutil/pixelutils.h52
-rw-r--r--libavutil/pixfmt.h214
-rw-r--r--libavutil/ppc/cpu.c10
-rw-r--r--libavutil/ppc/cpu.h8
-rw-r--r--libavutil/ppc/float_dsp_altivec.c26
-rw-r--r--libavutil/ppc/float_dsp_altivec.h8
-rw-r--r--libavutil/ppc/float_dsp_init.c8
-rw-r--r--libavutil/ppc/intreadwrite.h22
-rw-r--r--libavutil/ppc/timer.h15
-rw-r--r--libavutil/ppc/types_altivec.h8
-rw-r--r--libavutil/ppc/util_altivec.h79
-rw-r--r--libavutil/qsort.h117
-rw-r--r--libavutil/random_seed.c76
-rw-r--r--libavutil/random_seed.h19
-rw-r--r--libavutil/rational.c74
-rw-r--r--libavutil/rational.h21
-rw-r--r--libavutil/rc4.c8
-rw-r--r--libavutil/rc4.h8
-rw-r--r--libavutil/replaygain.h8
-rw-r--r--libavutil/ripemd.c605
-rw-r--r--libavutil/ripemd.h75
-rw-r--r--libavutil/samplefmt.c49
-rw-r--r--libavutil/samplefmt.h70
-rw-r--r--libavutil/sh4/bswap.h8
-rw-r--r--libavutil/sha.c141
-rw-r--r--libavutil/sha.h12
-rw-r--r--libavutil/sha512.c345
-rw-r--r--libavutil/sha512.h75
-rw-r--r--libavutil/softfloat.c98
-rw-r--r--libavutil/softfloat.h227
-rw-r--r--libavutil/softfloat_tables.h262
-rw-r--r--libavutil/stereo3d.c8
-rw-r--r--libavutil/stereo3d.h8
-rw-r--r--libavutil/thread.h16
-rw-r--r--libavutil/threadmessage.c184
-rw-r--r--libavutil/threadmessage.h91
-rw-r--r--libavutil/time.c24
-rw-r--r--libavutil/time.h16
-rw-r--r--libavutil/time_internal.h12
-rw-r--r--libavutil/timecode.c218
-rw-r--r--libavutil/timecode.h140
-rw-r--r--libavutil/timer.h22
-rw-r--r--libavutil/timestamp.h78
-rw-r--r--libavutil/tomi/intreadwrite.h8
-rw-r--r--libavutil/tree.c46
-rw-r--r--libavutil/tree.h20
-rw-r--r--libavutil/twofish.c405
-rw-r--r--libavutil/twofish.h70
-rw-r--r--libavutil/utf8.c73
-rw-r--r--libavutil/utils.c72
-rw-r--r--libavutil/version.h34
-rw-r--r--libavutil/wchar_filename.h10
-rw-r--r--libavutil/x86/Makefile8
-rw-r--r--libavutil/x86/asm.h51
-rw-r--r--libavutil/x86/bswap.h8
-rw-r--r--libavutil/x86/cpu.c12
-rw-r--r--libavutil/x86/cpu.h8
-rw-r--r--libavutil/x86/cpuid.asm8
-rw-r--r--libavutil/x86/emms.asm8
-rw-r--r--libavutil/x86/emms.h12
-rw-r--r--libavutil/x86/float_dsp.asm153
-rw-r--r--libavutil/x86/float_dsp_init.c97
-rw-r--r--libavutil/x86/intmath.h58
-rw-r--r--libavutil/x86/intreadwrite.h8
-rw-r--r--libavutil/x86/lls.asm11
-rw-r--r--libavutil/x86/lls_init.c14
-rw-r--r--libavutil/x86/pixelutils.asm165
-rw-r--r--libavutil/x86/pixelutils.h26
-rw-r--r--libavutil/x86/pixelutils_init.c64
-rw-r--r--libavutil/x86/timer.h9
-rw-r--r--libavutil/x86/w64xmmtest.h8
-rw-r--r--libavutil/x86/x86inc.asm604
-rw-r--r--libavutil/x86/x86util.asm141
-rw-r--r--libavutil/x86_cpu.h1
-rw-r--r--libavutil/xga_font_data.c417
-rw-r--r--libavutil/xga_font_data.h35
-rw-r--r--libavutil/xtea.c101
-rw-r--r--libavutil/xtea.h9
-rw-r--r--libpostproc/Makefile12
-rw-r--r--libpostproc/libpostproc.v4
-rw-r--r--libpostproc/postprocess.c1043
-rw-r--r--libpostproc/postprocess.h107
-rw-r--r--libpostproc/postprocess_altivec_template.c1210
-rw-r--r--libpostproc/postprocess_internal.h184
-rw-r--r--libpostproc/postprocess_template.c3746
-rw-r--r--libpostproc/postprocres.rc55
-rw-r--r--libpostproc/version.h45
-rw-r--r--library.mak27
-rw-r--r--libswresample/Makefile24
-rw-r--r--libswresample/aarch64/Makefile5
-rw-r--r--libswresample/aarch64/audio_convert_init.c67
-rw-r--r--libswresample/aarch64/audio_convert_neon.S363
-rw-r--r--libswresample/aarch64/neontest.c29
-rw-r--r--libswresample/arm/Makefile5
-rw-r--r--libswresample/arm/audio_convert_init.c67
-rw-r--r--libswresample/arm/audio_convert_neon.S363
-rw-r--r--libswresample/arm/neontest.c29
-rw-r--r--libswresample/audioconvert.c225
-rw-r--r--libswresample/audioconvert.h78
-rw-r--r--libswresample/dither.c148
-rw-r--r--libswresample/dither_template.c67
-rw-r--r--libswresample/libswresample.v4
-rw-r--r--libswresample/log2_tab.c1
-rw-r--r--libswresample/noise_shaping_data.c224
-rw-r--r--libswresample/options.c155
-rw-r--r--libswresample/rematrix.c510
-rw-r--r--libswresample/rematrix_template.c106
-rw-r--r--libswresample/resample.c417
-rw-r--r--libswresample/resample.h64
-rw-r--r--libswresample/resample_dsp.c68
-rw-r--r--libswresample/resample_template.c187
-rw-r--r--libswresample/soxr_resample.c104
-rw-r--r--libswresample/swresample-test.c421
-rw-r--r--libswresample/swresample.c872
-rw-r--r--libswresample/swresample.h534
-rw-r--r--libswresample/swresample_frame.c158
-rw-r--r--libswresample/swresample_internal.h211
-rw-r--r--libswresample/swresampleres.rc55
-rw-r--r--libswresample/version.h45
-rw-r--r--libswresample/x86/Makefile9
-rw-r--r--libswresample/x86/audio_convert.asm739
-rw-r--r--libswresample/x86/audio_convert_init.c179
-rw-r--r--libswresample/x86/rematrix.asm250
-rw-r--r--libswresample/x86/rematrix_init.c90
-rw-r--r--libswresample/x86/resample.asm600
-rw-r--r--libswresample/x86/resample_init.c90
-rw-r--r--libswresample/x86/w64xmmtest.c29
-rw-r--r--libswscale/Makefile10
-rw-r--r--libswscale/arm/Makefile4
-rw-r--r--libswscale/arm/rgb2yuv_neon_16.S80
-rw-r--r--libswscale/arm/rgb2yuv_neon_32.S119
-rw-r--r--libswscale/arm/rgb2yuv_neon_common.S291
-rw-r--r--libswscale/arm/swscale_unscaled.c79
-rw-r--r--libswscale/bayer_template.c236
-rw-r--r--libswscale/colorspace-test.c18
-rw-r--r--libswscale/hscale_fast_bilinear.c55
-rw-r--r--libswscale/input.c682
-rw-r--r--libswscale/log2_tab.c1
-rw-r--r--libswscale/options.c34
-rw-r--r--libswscale/output.c1018
-rw-r--r--libswscale/ppc/swscale_altivec.c241
-rw-r--r--libswscale/ppc/yuv2rgb_altivec.c26
-rw-r--r--libswscale/ppc/yuv2rgb_altivec.h8
-rw-r--r--libswscale/ppc/yuv2yuv_altivec.c8
-rw-r--r--libswscale/rgb2rgb.c120
-rw-r--r--libswscale/rgb2rgb.h28
-rw-r--r--libswscale/rgb2rgb_template.c97
-rw-r--r--libswscale/swscale-test.c70
-rw-r--r--libswscale/swscale.c716
-rw-r--r--libswscale/swscale.h22
-rw-r--r--libswscale/swscale_internal.h279
-rw-r--r--libswscale/swscale_unscaled.c1359
-rw-r--r--libswscale/swscaleres.rc55
-rw-r--r--libswscale/utils.c1115
-rw-r--r--libswscale/version.h12
-rw-r--r--libswscale/x86/Makefile4
-rw-r--r--libswscale/x86/hscale_fast_bilinear_simd.c359
-rw-r--r--libswscale/x86/input.asm252
-rw-r--r--libswscale/x86/output.asm12
-rw-r--r--libswscale/x86/rgb2rgb.c17
-rw-r--r--libswscale/x86/rgb2rgb_template.c226
-rw-r--r--libswscale/x86/scale.asm14
-rw-r--r--libswscale/x86/swscale.c148
-rw-r--r--libswscale/x86/swscale_template.c420
-rw-r--r--libswscale/x86/w64xmmtest.c8
-rw-r--r--libswscale/x86/yuv2rgb.c25
-rw-r--r--libswscale/x86/yuv2rgb_template.c46
-rw-r--r--libswscale/yuv2rgb.c187
-rw-r--r--presets/libvpx-1080p.avpreset17
-rw-r--r--presets/libvpx-1080p.ffpreset19
-rw-r--r--presets/libvpx-1080p50_60.avpreset17
-rw-r--r--presets/libvpx-1080p50_60.ffpreset19
-rw-r--r--presets/libvpx-360p.avpreset16
-rw-r--r--presets/libvpx-360p.ffpreset18
-rw-r--r--presets/libvpx-720p.avpreset17
-rw-r--r--presets/libvpx-720p.ffpreset19
-rw-r--r--presets/libvpx-720p50_60.avpreset17
-rw-r--r--presets/libvpx-720p50_60.ffpreset19
-rw-r--r--presets/libx264-baseline.avpreset1
-rw-r--r--presets/libx264-fast.avpreset1
-rw-r--r--presets/libx264-fast_firstpass.avpreset2
-rw-r--r--presets/libx264-faster.avpreset1
-rw-r--r--presets/libx264-faster_firstpass.avpreset2
-rw-r--r--presets/libx264-ipod320.avpreset4
-rw-r--r--presets/libx264-ipod640.avpreset4
-rw-r--r--presets/libx264-lossless_fast.avpreset2
-rw-r--r--presets/libx264-lossless_max.avpreset2
-rw-r--r--presets/libx264-lossless_medium.avpreset2
-rw-r--r--presets/libx264-lossless_slow.avpreset2
-rw-r--r--presets/libx264-lossless_slower.avpreset2
-rw-r--r--presets/libx264-lossless_ultrafast.avpreset2
-rw-r--r--presets/libx264-main.avpreset1
-rw-r--r--presets/libx264-medium.avpreset1
-rw-r--r--presets/libx264-medium_firstpass.avpreset2
-rw-r--r--presets/libx264-placebo.avpreset1
-rw-r--r--presets/libx264-placebo_firstpass.avpreset2
-rw-r--r--presets/libx264-slow.avpreset1
-rw-r--r--presets/libx264-slow_firstpass.avpreset2
-rw-r--r--presets/libx264-slower.avpreset1
-rw-r--r--presets/libx264-slower_firstpass.avpreset2
-rw-r--r--presets/libx264-superfast.avpreset1
-rw-r--r--presets/libx264-superfast_firstpass.avpreset2
-rw-r--r--presets/libx264-ultrafast.avpreset1
-rw-r--r--presets/libx264-ultrafast_firstpass.avpreset2
-rw-r--r--presets/libx264-veryfast.avpreset1
-rw-r--r--presets/libx264-veryfast_firstpass.avpreset2
-rw-r--r--presets/libx264-veryslow.avpreset1
-rw-r--r--presets/libx264-veryslow_firstpass.avpreset2
-rw-r--r--tests/Makefile85
-rw-r--r--tests/audiogen.c8
-rw-r--r--tests/base64.c8
-rwxr-xr-xtests/copycooker.sh30
-rwxr-xr-xtests/fate-run.sh123
-rw-r--r--tests/fate-valgrind.supp31
-rwxr-xr-xtests/fate.sh15
-rw-r--r--tests/fate/aac.mak24
-rw-r--r--tests/fate/ac3.mak11
-rw-r--r--tests/fate/acodec.mak98
-rw-r--r--tests/fate/adpcm.mak15
-rw-r--r--tests/fate/atrac.mak17
-rw-r--r--tests/fate/audio.mak43
-rw-r--r--tests/fate/avformat.mak28
-rw-r--r--tests/fate/cover-art.mak23
-rw-r--r--tests/fate/demux.mak96
-rw-r--r--tests/fate/ea.mak15
-rw-r--r--tests/fate/exif.mak18
-rw-r--r--tests/fate/ffmpeg.mak48
-rw-r--r--tests/fate/ffprobe.mak33
-rw-r--r--tests/fate/fft.mak21
-rw-r--r--tests/fate/filter-audio.mak29
-rw-r--r--tests/fate/filter-video.mak305
-rw-r--r--tests/fate/flac.mak4
-rw-r--r--tests/fate/gapless.mak7
-rw-r--r--tests/fate/gif.mak27
-rw-r--r--tests/fate/h264.mak366
-rw-r--r--tests/fate/hevc.mak101
-rw-r--r--tests/fate/image.mak58
-rw-r--r--tests/fate/libavcodec.mak21
-rw-r--r--tests/fate/libavresample.mak14
-rw-r--r--tests/fate/libavutil.mak52
-rw-r--r--tests/fate/libswresample.mak401
-rw-r--r--tests/fate/lossless-audio.mak29
-rw-r--r--tests/fate/lossless-video.mak24
-rw-r--r--tests/fate/microsoft.mak17
-rw-r--r--tests/fate/mp3.mak4
-rw-r--r--tests/fate/mpeg4.mak5
-rw-r--r--tests/fate/mxf.mak11
-rw-r--r--tests/fate/opus.mak14
-rw-r--r--tests/fate/pcm.mak24
-rw-r--r--tests/fate/probe.mak14
-rw-r--r--tests/fate/prores.mak16
-rw-r--r--tests/fate/qt.mak39
-rw-r--r--tests/fate/real.mak9
-rw-r--r--tests/fate/screen.mak17
-rw-r--r--tests/fate/seek.mak215
-rw-r--r--tests/fate/subtitles.mak70
-rw-r--r--tests/fate/utvideo.mak2
-rw-r--r--tests/fate/vcodec.mak149
-rw-r--r--tests/fate/video.mak183
-rw-r--r--tests/fate/voice.mak24
-rw-r--r--tests/fate/vpx.mak69
-rw-r--r--tests/fate/vqf.mak11
-rw-r--r--tests/fate/wavpack.mak58
-rwxr-xr-xtests/ffserver-regression.sh39
-rw-r--r--tests/ffserver.conf311
-rw-r--r--tests/ffserver.regression.ref10
-rw-r--r--tests/filtergraphs/alphamerge_alphaextract_rgb4
-rw-r--r--tests/filtergraphs/alphamerge_alphaextract_yuv4
-rw-r--r--tests/filtergraphs/concat8
-rw-r--r--tests/filtergraphs/gradfun2
-rw-r--r--tests/filtergraphs/hqdn3d1
-rw-r--r--tests/filtergraphs/overlay1
-rw-r--r--tests/filtergraphs/overlay_rgb4
-rw-r--r--tests/filtergraphs/overlay_yuv4204
-rw-r--r--tests/filtergraphs/overlay_yuv4224
-rw-r--r--tests/filtergraphs/overlay_yuv4444
-rw-r--r--tests/filtergraphs/scalenorm4
-rwxr-xr-xtests/lavf-regression.sh154
-rw-r--r--tests/md5.sh2
-rw-r--r--tests/ref/acodec/adpcm-adx6
-rw-r--r--tests/ref/acodec/adpcm-adx-trellis4
-rw-r--r--tests/ref/acodec/adpcm-ima_qt4
-rw-r--r--tests/ref/acodec/adpcm-ima_qt-trellis4
-rw-r--r--tests/ref/acodec/adpcm-ima_wav2
-rw-r--r--tests/ref/acodec/adpcm-ima_wav-trellis4
-rw-r--r--tests/ref/acodec/adpcm-ms2
-rw-r--r--tests/ref/acodec/adpcm-ms-trellis4
-rw-r--r--tests/ref/acodec/adpcm-swf2
-rw-r--r--tests/ref/acodec/adpcm-swf-trellis4
-rw-r--r--tests/ref/acodec/adpcm-yamaha2
-rw-r--r--tests/ref/acodec/adpcm-yamaha-trellis4
-rw-r--r--tests/ref/acodec/adpcm_ima_qt4
-rw-r--r--tests/ref/acodec/alac6
-rw-r--r--tests/ref/acodec/flac6
-rw-r--r--tests/ref/acodec/flac-exact-rice4
-rw-r--r--tests/ref/acodec/g723_14
-rw-r--r--tests/ref/acodec/mp22
-rw-r--r--tests/ref/acodec/mp2fixed4
-rw-r--r--tests/ref/acodec/pcm-alaw2
-rw-r--r--tests/ref/acodec/pcm-f32be6
-rw-r--r--tests/ref/acodec/pcm-f32le2
-rw-r--r--tests/ref/acodec/pcm-f64be6
-rw-r--r--tests/ref/acodec/pcm-f64le2
-rw-r--r--tests/ref/acodec/pcm-mulaw2
-rw-r--r--tests/ref/acodec/pcm-s16be6
-rw-r--r--tests/ref/acodec/pcm-s16be_planar4
-rw-r--r--tests/ref/acodec/pcm-s16le6
-rw-r--r--tests/ref/acodec/pcm-s16le_planar4
-rw-r--r--tests/ref/acodec/pcm-s24be6
-rw-r--r--tests/ref/acodec/pcm-s24le2
-rw-r--r--tests/ref/acodec/pcm-s24le_planar4
-rw-r--r--tests/ref/acodec/pcm-s32be6
-rw-r--r--tests/ref/acodec/pcm-s32le2
-rw-r--r--tests/ref/acodec/pcm-s32le_planar4
-rw-r--r--tests/ref/acodec/pcm-s86
-rw-r--r--tests/ref/acodec/pcm-s8_planar4
-rw-r--r--tests/ref/acodec/pcm-u16be4
-rw-r--r--tests/ref/acodec/pcm-u16le4
-rw-r--r--tests/ref/acodec/pcm-u24be4
-rw-r--r--tests/ref/acodec/pcm-u24le4
-rw-r--r--tests/ref/acodec/pcm-u32be4
-rw-r--r--tests/ref/acodec/pcm-u32le4
-rw-r--r--tests/ref/acodec/pcm-u86
-rw-r--r--tests/ref/acodec/roqaudio4
-rw-r--r--tests/ref/acodec/s302m4
-rw-r--r--tests/ref/acodec/tta4
-rw-r--r--tests/ref/acodec/wavpack4
-rw-r--r--tests/ref/fate/4xm-130
-rw-r--r--tests/ref/fate/4xm-2322
-rw-r--r--tests/ref/fate/8bps24
-rw-r--r--tests/ref/fate/acodec-aref4
-rw-r--r--tests/ref/fate/adpcm-4xm27
-rw-r--r--tests/ref/fate/adpcm-afc13
-rw-r--r--tests/ref/fate/adpcm-dtk33
-rw-r--r--tests/ref/fate/adpcm-ima-amv310
-rw-r--r--tests/ref/fate/adpcm-ima-oki1
-rw-r--r--tests/ref/fate/adpcm-ima-rad1
-rw-r--r--tests/ref/fate/adpcm-ima-smjpeg698
-rw-r--r--tests/ref/fate/aic16
-rw-r--r--tests/ref/fate/aic-oddsize116
-rw-r--r--tests/ref/fate/aliaspix-bgr2
-rw-r--r--tests/ref/fate/aliaspix-gray2
-rw-r--r--tests/ref/fate/ansi2569
-rw-r--r--tests/ref/fate/armovie-escape124200
-rw-r--r--tests/ref/fate/ast1
-rw-r--r--tests/ref/fate/avio-direct59
-rw-r--r--tests/ref/fate/avstring9
-rw-r--r--tests/ref/fate/bethsoft-vid140
-rw-r--r--tests/ref/fate/binsub-movtextenc1
-rw-r--r--tests/ref/fate/bmpparser8
-rw-r--r--tests/ref/fate/bprint16
-rw-r--r--tests/ref/fate/brstm1
-rw-r--r--tests/ref/fate/cavs343
-rw-r--r--tests/ref/fate/cdgraphics440
-rw-r--r--tests/ref/fate/cdxl-bitline-ham622
-rw-r--r--tests/ref/fate/cdxl-ham634
-rw-r--r--tests/ref/fate/cdxl-ham84
-rw-r--r--tests/ref/fate/cdxl-pal824
-rw-r--r--tests/ref/fate/cdxl-pal8-small94
-rw-r--r--tests/ref/fate/cine-demux1
-rw-r--r--tests/ref/fate/cljr72
-rw-r--r--tests/ref/fate/crc1
-rw-r--r--tests/ref/fate/creatureshock-avs114
-rw-r--r--tests/ref/fate/cvid-grayscale304
-rw-r--r--tests/ref/fate/cvid-palette114
-rw-r--r--tests/ref/fate/cvid-partial158
-rw-r--r--tests/ref/fate/d-cinema-demux2
-rw-r--r--tests/ref/fate/dfa150
-rw-r--r--tests/ref/fate/dfa1016
-rw-r--r--tests/ref/fate/dfa1118
-rw-r--r--tests/ref/fate/dfa234
-rw-r--r--tests/ref/fate/dfa320
-rw-r--r--tests/ref/fate/dfa427
-rw-r--r--tests/ref/fate/dfa530
-rw-r--r--tests/ref/fate/dfa624
-rw-r--r--tests/ref/fate/dfa724
-rw-r--r--tests/ref/fate/dfa872
-rw-r--r--tests/ref/fate/dfa912
-rw-r--r--tests/ref/fate/dict43
-rw-r--r--tests/ref/fate/dirac3
-rw-r--r--tests/ref/fate/dpxparser8
-rw-r--r--tests/ref/fate/ea-cmv388
-rw-r--r--tests/ref/fate/eval87
-rw-r--r--tests/ref/fate/exif-image-embedded404
-rw-r--r--tests/ref/fate/exif-image-jpg226
-rw-r--r--tests/ref/fate/exif-image-tiff27
-rw-r--r--tests/ref/fate/exif-image-webp226
-rw-r--r--tests/ref/fate/ffmpeg-filter_complex6
-rw-r--r--tests/ref/fate/ffmpeg-lavfi6
-rw-r--r--tests/ref/fate/ffprobe_compact32
-rw-r--r--tests/ref/fate/ffprobe_csv32
-rw-r--r--tests/ref/fate/ffprobe_default669
-rw-r--r--tests/ref/fate/ffprobe_flat605
-rw-r--r--tests/ref/fate/ffprobe_ini684
-rw-r--r--tests/ref/fate/ffprobe_json647
-rw-r--r--tests/ref/fate/ffprobe_xml57
-rw-r--r--tests/ref/fate/film-cvid220
-rw-r--r--tests/ref/fate/filter-2xbr3
-rw-r--r--tests/ref/fate/filter-3xbr3
-rw-r--r--tests/ref/fate/filter-4xbr3
-rw-r--r--tests/ref/fate/filter-adelay261
-rw-r--r--tests/ref/fate/filter-alphaextract_alphamerge_rgb51
-rw-r--r--tests/ref/fate/filter-alphaextract_alphamerge_yuv51
-rw-r--r--tests/ref/fate/filter-codecview-mvs61
-rw-r--r--tests/ref/fate/filter-colorchannelmixer51
-rw-r--r--tests/ref/fate/filter-colormatrix11
-rw-r--r--tests/ref/fate/filter-colormatrix21
-rw-r--r--tests/ref/fate/filter-concat202
-rw-r--r--tests/ref/fate/filter-crop2
-rw-r--r--tests/ref/fate/filter-crop_scale2
-rw-r--r--tests/ref/fate/filter-crop_scale_vflip2
-rw-r--r--tests/ref/fate/filter-crop_vflip2
-rw-r--r--tests/ref/fate/filter-curves6
-rw-r--r--tests/ref/fate/filter-delogo220
-rw-r--r--tests/ref/fate/filter-drawbox100
-rw-r--r--tests/ref/fate/filter-edgedetect1
-rw-r--r--tests/ref/fate/filter-edgedetect-colormix1
-rw-r--r--tests/ref/fate/filter-fade98
-rw-r--r--tests/ref/fate/filter-gradfun-sample21
-rw-r--r--tests/ref/fate/filter-histogram-levels51
-rw-r--r--tests/ref/fate/filter-histogram-waveform51
-rw-r--r--tests/ref/fate/filter-hq2x3
-rw-r--r--tests/ref/fate/filter-hq3x3
-rw-r--r--tests/ref/fate/filter-hq4x3
-rw-r--r--tests/ref/fate/filter-hqdn3d-sample74
-rw-r--r--tests/ref/fate/filter-hue1
-rw-r--r--tests/ref/fate/filter-idet26
-rw-r--r--tests/ref/fate/filter-lavd-life11
-rw-r--r--tests/ref/fate/filter-lavd-scalenorm11
-rw-r--r--tests/ref/fate/filter-lavd-testsrc71
-rw-r--r--tests/ref/fate/filter-mcdeint-fast31
-rw-r--r--tests/ref/fate/filter-mcdeint-medium31
-rw-r--r--tests/ref/fate/filter-metadata-ebur128280
-rw-r--r--tests/ref/fate/filter-metadata-scenedetect10
-rw-r--r--tests/ref/fate/filter-metadata-silencedetect512
-rw-r--r--tests/ref/fate/filter-null2
-rw-r--r--tests/ref/fate/filter-overlay100
-rw-r--r--tests/ref/fate/filter-overlay_rgb51
-rw-r--r--tests/ref/fate/filter-overlay_yuv42051
-rw-r--r--tests/ref/fate/filter-overlay_yuv42251
-rw-r--r--tests/ref/fate/filter-overlay_yuv44451
-rw-r--r--tests/ref/fate/filter-pad1
-rw-r--r--tests/ref/fate/filter-palettegen-12
-rw-r--r--tests/ref/fate/filter-palettegen-22
-rw-r--r--tests/ref/fate/filter-paletteuse-bayer72
-rw-r--r--tests/ref/fate/filter-paletteuse-nodither72
-rw-r--r--tests/ref/fate/filter-paletteuse-sierra2_4a72
-rw-r--r--tests/ref/fate/filter-phase51
-rw-r--r--tests/ref/fate/filter-pixdesc-0bgr1
-rw-r--r--tests/ref/fate/filter-pixdesc-0rgb1
-rw-r--r--tests/ref/fate/filter-pixdesc-abgr2
-rw-r--r--tests/ref/fate/filter-pixdesc-argb2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr01
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr242
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr444be2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr444le2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr48be2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr48le2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr4_byte2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr555be2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr555le2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr565be2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr565le2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgr82
-rw-r--r--tests/ref/fate/filter-pixdesc-bgra2
-rw-r--r--tests/ref/fate/filter-pixdesc-bgra64be1
-rw-r--r--tests/ref/fate/filter-pixdesc-bgra64le1
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrap2
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp2
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp12be1
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp12le1
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp14be1
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp14le1
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-gbrp9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-gray2
-rw-r--r--tests/ref/fate/filter-pixdesc-gray16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-gray16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-monob2
-rw-r--r--tests/ref/fate/filter-pixdesc-monow2
-rw-r--r--tests/ref/fate/filter-pixdesc-nv122
-rw-r--r--tests/ref/fate/filter-pixdesc-nv212
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb01
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb242
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb444be2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb444le2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb48be2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb48le2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb4_byte2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb555be2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb555le2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb565be2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb565le2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgb82
-rw-r--r--tests/ref/fate/filter-pixdesc-rgba2
-rw-r--r--tests/ref/fate/filter-pixdesc-rgba64be1
-rw-r--r--tests/ref/fate/filter-pixdesc-rgba64le1
-rw-r--r--tests/ref/fate/filter-pixdesc-uyvy4222
-rw-r--r--tests/ref/fate/filter-pixdesc-xyz12be1
-rw-r--r--tests/ref/fate/filter-pixdesc-xyz12le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv410p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv411p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p12be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p12le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p14be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p14le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv420p9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p12be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p12le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p14be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p14le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv422p9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv440p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv440p10be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv440p10le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv440p12be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv440p12le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p12be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p12le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p14be1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p14le1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuv444p9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva420p9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva422p9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p10be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p10le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p16be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p16le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p9be2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuva444p9le2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuvj411p1
-rw-r--r--tests/ref/fate/filter-pixdesc-yuvj420p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuvj422p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuvj440p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuvj444p2
-rw-r--r--tests/ref/fate/filter-pixdesc-yuyv4222
-rw-r--r--tests/ref/fate/filter-pixdesc-yvyu4222
-rw-r--r--tests/ref/fate/filter-pixfmts-copy214
-rw-r--r--tests/ref/fate/filter-pixfmts-crop160
-rw-r--r--tests/ref/fate/filter-pixfmts-field123
-rw-r--r--tests/ref/fate/filter-pixfmts-fieldmatch5
-rw-r--r--tests/ref/fate/filter-pixfmts-fieldorder92
-rw-r--r--tests/ref/fate/filter-pixfmts-hflip160
-rw-r--r--tests/ref/fate/filter-pixfmts-histeq6
-rw-r--r--tests/ref/fate/filter-pixfmts-il122
-rw-r--r--tests/ref/fate/filter-pixfmts-kerndeint10
-rw-r--r--tests/ref/fate/filter-pixfmts-lut19
-rw-r--r--tests/ref/fate/filter-pixfmts-null214
-rw-r--r--tests/ref/fate/filter-pixfmts-pad44
-rw-r--r--tests/ref/fate/filter-pixfmts-pullup12
-rw-r--r--tests/ref/fate/filter-pixfmts-rotate20
-rw-r--r--tests/ref/fate/filter-pixfmts-scale214
-rw-r--r--tests/ref/fate/filter-pixfmts-super2xsai14
-rw-r--r--tests/ref/fate/filter-pixfmts-swapuv66
-rw-r--r--tests/ref/fate/filter-pixfmts-tinterlace_merge14
-rw-r--r--tests/ref/fate/filter-pixfmts-tinterlace_pad14
-rw-r--r--tests/ref/fate/filter-pixfmts-vflip214
-rw-r--r--tests/ref/fate/filter-pp6
-rw-r--r--tests/ref/fate/filter-pp11
-rw-r--r--tests/ref/fate/filter-pp21
-rw-r--r--tests/ref/fate/filter-pp31
-rw-r--r--tests/ref/fate/filter-pp41
-rw-r--r--tests/ref/fate/filter-pp51
-rw-r--r--tests/ref/fate/filter-pp61
-rw-r--r--tests/ref/fate/filter-qp1
-rw-r--r--tests/ref/fate/filter-scale2002
-rw-r--r--tests/ref/fate/filter-scale5002
-rw-r--r--tests/ref/fate/filter-select18
-rw-r--r--tests/ref/fate/filter-separatefields101
-rw-r--r--tests/ref/fate/filter-setdar1
-rw-r--r--tests/ref/fate/filter-setpts89
-rw-r--r--tests/ref/fate/filter-setsar1
-rw-r--r--tests/ref/fate/filter-showpalette316
-rw-r--r--tests/ref/fate/filter-stereo3d-abr-ml6
-rw-r--r--tests/ref/fate/filter-stereo3d-abr-mr6
-rw-r--r--tests/ref/fate/filter-stereo3d-al-sbsl6
-rw-r--r--tests/ref/fate/filter-stereo3d-ar-abl6
-rw-r--r--tests/ref/fate/filter-stereo3d-sbsl-abl6
-rw-r--r--tests/ref/fate/filter-stereo3d-sbsl-abr6
-rw-r--r--tests/ref/fate/filter-stereo3d-sbsl-al6
-rw-r--r--tests/ref/fate/filter-stereo3d-sbsl-sbsr6
-rw-r--r--tests/ref/fate/filter-telecine63
-rw-r--r--tests/ref/fate/filter-thumbnail1
-rw-r--r--tests/ref/fate/filter-tile1
-rw-r--r--tests/ref/fate/filter-unsharp100
-rw-r--r--tests/ref/fate/filter-vflip2
-rw-r--r--tests/ref/fate/filter-vflip_crop2
-rw-r--r--tests/ref/fate/filter-vflip_vflip2
-rw-r--r--tests/ref/fate/filter-yadif-mode063
-rw-r--r--tests/ref/fate/filter-yadif-mode1123
-rw-r--r--tests/ref/fate/filter-yadif1031
-rw-r--r--tests/ref/fate/filter-yadif1631
-rw-r--r--tests/ref/fate/flic-af11-palette-change232
-rw-r--r--tests/ref/fate/flic-magiccarpet80
-rw-r--r--tests/ref/fate/force_key_frames4
-rw-r--r--tests/ref/fate/fraps-v28
-rw-r--r--tests/ref/fate/fraps-v32
-rw-r--r--tests/ref/fate/g729-01000
-rw-r--r--tests/ref/fate/g729-11000
-rw-r--r--tests/ref/fate/gapless-mp35
-rw-r--r--tests/ref/fate/gif-color174
-rw-r--r--tests/ref/fate/gif-demux37
-rw-r--r--tests/ref/fate/gif-disposal-background6
-rw-r--r--tests/ref/fate/gif-disposal-restore4
-rw-r--r--tests/ref/fate/gif-gray37
-rw-r--r--tests/ref/fate/gifenc-bgr4_byte174
-rw-r--r--tests/ref/fate/gifenc-bgr8174
-rw-r--r--tests/ref/fate/gifenc-gray174
-rw-r--r--tests/ref/fate/gifenc-pal8174
-rw-r--r--tests/ref/fate/gifenc-rgb4_byte174
-rw-r--r--tests/ref/fate/gifenc-rgb8174
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr10_sony_b6
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b6
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a6
-rw-r--r--tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a6
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a11
-rw-r--r--tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a11
-rw-r--r--tests/ref/fate/h264-crop-to-container8
-rw-r--r--tests/ref/fate/h264-direct-bff24
-rw-r--r--tests/ref/fate/h264-extreme-plane-pred4
-rw-r--r--tests/ref/fate/h264-lossless20
-rw-r--r--tests/ref/fate/hevc-conformance-ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_14
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_A_Samsung_661
-rw-r--r--tests/ref/fate/hevc-conformance-AMP_B_Samsung_661
-rw-r--r--tests/ref/fate/hevc-conformance-AMVP_C_Samsung_661
-rw-r--r--tests/ref/fate/hevc-conformance-BUMPING_A_ericsson_150
-rw-r--r--tests/ref/fate/hevc-conformance-CONFWIN_A_Sony_161
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_3 (renamed from tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_2)0
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_A_SONY_358
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_B_SONY_358
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_C_SONY_358
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_D_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_E_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_F_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DBLK_G_VIXS_19
-rw-r--r--tests/ref/fate/hevc-conformance-DELTAQP_A_BRCM_497
-rw-r--r--tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_358
-rw-r--r--tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_358
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_A_LG_251
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_A_Qualcomm_125
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_B_LG_251
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_B_Qualcomm_125
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_C_LG_351
-rw-r--r--tests/ref/fate/hevc-conformance-ENTP_C_Qualcomm_125
-rw-r--r--tests/ref/fate/hevc-conformance-FILLER_A_Sony_161
-rw-r--r--tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_297
-rw-r--r--tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_397
-rw-r--r--tests/ref/fate/hevc-conformance-INITQP_A_Sony_161
-rw-r--r--tests/ref/fate/hevc-conformance-INITQP_B_Sony_191
-rw-r--r--tests/ref/fate/hevc-conformance-IPCM_A_RExt_NEC2
-rw-r--r--tests/ref/fate/hevc-conformance-IPCM_B_RExt_NEC2
-rw-r--r--tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_25
-rw-r--r--tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_35
-rw-r--r--tests/ref/fate/hevc-conformance-Main_422_10_A_RExt_Sony_125
-rw-r--r--tests/ref/fate/hevc-conformance-Main_422_10_B_RExt_Sony_118
-rw-r--r--tests/ref/fate/hevc-conformance-NoOutPrior_A_Qualcomm_141
-rw-r--r--tests/ref/fate/hevc-conformance-NoOutPrior_B_Qualcomm_148
-rw-r--r--tests/ref/fate/hevc-conformance-OPFLAG_A_Qualcomm_1501
-rw-r--r--tests/ref/fate/hevc-conformance-OPFLAG_B_Qualcomm_199
-rw-r--r--tests/ref/fate/hevc-conformance-OPFLAG_C_Qualcomm_197
-rw-r--r--tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_13
-rw-r--r--tests/ref/fate/hevc-conformance-POC_A_Bossen_38
-rw-r--r--tests/ref/fate/hevc-conformance-QMATRIX_A_RExt_Sony_121
-rw-r--r--tests/ref/fate/hevc-conformance-RAP_B_Bossen_129
-rw-r--r--tests/ref/fate/hevc-conformance-RPS_D_ericsson_6134
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_A_RExt_MediaTek_19
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_C_Samsung_56
-rw-r--r--tests/ref/fate/hevc-conformance-SAO_D_Samsung_56
-rw-r--r--tests/ref/fate/hevc-conformance-SLPPLP_A_VIDYO_234
-rw-r--r--tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_661
-rw-r--r--tests/ref/fate/hevc-conformance-VPSID_A_VIDYO_234
-rw-r--r--tests/ref/fate/hevc-conformance-WP_B_Toshiba_3510
-rw-r--r--tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3510
-rw-r--r--tests/ref/fate/hevc-paramchange-yuv420p-yuv420p10512
-rw-r--r--tests/ref/fate/hmac30
-rw-r--r--tests/ref/fate/idroq-video-encode2
-rw-r--r--tests/ref/fate/indeo380
-rw-r--r--tests/ref/fate/indeo51
-rw-r--r--tests/ref/fate/interplay-mve-16bit102
-rw-r--r--tests/ref/fate/interplay-mve-8bit222
-rw-r--r--tests/ref/fate/iv8-demux11
-rw-r--r--tests/ref/fate/jv13
-rw-r--r--tests/ref/fate/jv-demux20
-rw-r--r--tests/ref/fate/kgv18
-rw-r--r--tests/ref/fate/lagarith-red26
-rw-r--r--tests/ref/fate/libavcodec-options161
-rw-r--r--tests/ref/fate/lmlm4-demux169
-rw-r--r--tests/ref/fate/lossless-tak1
-rw-r--r--tests/ref/fate/lossless-tta-encrypted1
-rw-r--r--tests/ref/fate/mapchan-6ch-extract-22
-rw-r--r--tests/ref/fate/mapchan-6ch-extract-2-downmix-mono1
-rw-r--r--tests/ref/fate/mapchan-silent-mono1
-rw-r--r--tests/ref/fate/mjpegb22
-rw-r--r--tests/ref/fate/mkv219
-rw-r--r--tests/ref/fate/mlv-demux1
-rw-r--r--tests/ref/fate/motionpixels220
-rw-r--r--tests/ref/fate/mpeg2-field-enc62
-rw-r--r--tests/ref/fate/mpeg4-bsf-unpack-bframes1
-rw-r--r--tests/ref/fate/mpeg4-resolution-change-down-down4
-rw-r--r--tests/ref/fate/mpeg4-resolution-change-down-up4
-rw-r--r--tests/ref/fate/mpeg4-resolution-change-up-down4
-rw-r--r--tests/ref/fate/mpeg4-resolution-change-up-up4
-rw-r--r--tests/ref/fate/mss2-wmv202
-rw-r--r--tests/ref/fate/msvideo1-16bit60
-rw-r--r--tests/ref/fate/mtv3
-rw-r--r--tests/ref/fate/murmur31
-rw-r--r--tests/ref/fate/mxf-demux171
-rw-r--r--tests/ref/fate/mxf-essencegroup-demux2
-rw-r--r--tests/ref/fate/mxf-missing-index-demux1
-rw-r--r--tests/ref/fate/mxpeg31
-rw-r--r--tests/ref/fate/nc-demux177
-rw-r--r--tests/ref/fate/nistsphere-demux1
-rw-r--r--tests/ref/fate/nsv-demux108
-rw-r--r--tests/ref/fate/nuv-rtjpeg18
-rw-r--r--tests/ref/fate/nuv-rtjpeg-fh102
-rw-r--r--tests/ref/fate/oggvp8-demux71
-rw-r--r--tests/ref/fate/opt364
-rw-r--r--tests/ref/fate/paf-demux160
-rw-r--r--tests/ref/fate/parseutils43
-rw-r--r--tests/ref/fate/pictor2
-rw-r--r--tests/ref/fate/pixelutils48
-rw-r--r--tests/ref/fate/pmp-demux106
-rw-r--r--tests/ref/fate/png-gray162
-rw-r--r--tests/ref/fate/png-gray82
-rw-r--r--tests/ref/fate/png-rgb242
-rw-r--r--tests/ref/fate/png-rgb482
-rw-r--r--tests/ref/fate/png-rgba2
-rw-r--r--tests/ref/fate/png-ya162
-rw-r--r--tests/ref/fate/png-ya82
-rw-r--r--tests/ref/fate/pngparser8
-rw-r--r--tests/ref/fate/prores-4226
-rw-r--r--tests/ref/fate/prores-422_hq6
-rw-r--r--tests/ref/fate/prores-422_lt6
-rw-r--r--tests/ref/fate/prores-422_proxy6
-rw-r--r--tests/ref/fate/prores-alpha6
-rw-r--r--tests/ref/fate/prores-alpha_skip3
-rw-r--r--tests/ref/fate/prores-transparency5
-rw-r--r--tests/ref/fate/prores-transparency_skip5
-rw-r--r--tests/ref/fate/ptx2
-rw-r--r--tests/ref/fate/pva-demux53
-rw-r--r--tests/ref/fate/qtrle-16bit168
-rw-r--r--tests/ref/fate/qtrle-1bit78
-rw-r--r--tests/ref/fate/qtrle-24bit68
-rw-r--r--tests/ref/fate/qtrle-2bit78
-rw-r--r--tests/ref/fate/qtrle-32bit54
-rw-r--r--tests/ref/fate/qtrle-4bit78
-rw-r--r--tests/ref/fate/qtrle-8bit334
-rw-r--r--tests/ref/fate/quickdraw4
-rw-r--r--tests/ref/fate/random_seed1
-rw-r--r--tests/ref/fate/redcode-demux2
-rw-r--r--tests/ref/fate/redspark-demux1
-rw-r--r--tests/ref/fate/ripemd28
-rw-r--r--tests/ref/fate/rpza62
-rw-r--r--tests/ref/fate/rsd-demux1
-rw-r--r--tests/ref/fate/rv30220
-rw-r--r--tests/ref/fate/rv40481
-rw-r--r--tests/ref/fate/sanm10
-rw-r--r--tests/ref/fate/sgi-gray2
-rw-r--r--tests/ref/fate/sgi-gray162
-rw-r--r--tests/ref/fate/sgi-rgb242
-rw-r--r--tests/ref/fate/sgi-rgb482
-rw-r--r--tests/ref/fate/sgi-rgba2
-rw-r--r--tests/ref/fate/sgi-rgba642
-rw-r--r--tests/ref/fate/sha51228
-rw-r--r--tests/ref/fate/sierra-vmd-video234
-rw-r--r--tests/ref/fate/smc240
-rw-r--r--tests/ref/fate/smjpeg425
-rw-r--r--tests/ref/fate/smjpeg-demux2
-rw-r--r--tests/ref/fate/smvjpeg13
-rw-r--r--tests/ref/fate/sub-aqtitle45
-rw-r--r--tests/ref/fate/sub-charenc62
-rw-r--r--tests/ref/fate/sub-jacosub23
-rw-r--r--tests/ref/fate/sub-microdvd22
-rw-r--r--tests/ref/fate/sub-microdvd-remuxbin0 -> 416 bytes
-rw-r--r--tests/ref/fate/sub-movtext15
-rw-r--r--tests/ref/fate/sub-mpl216
-rw-r--r--tests/ref/fate/sub-mpsub33
-rw-r--r--tests/ref/fate/sub-mpsub-frames14
-rw-r--r--tests/ref/fate/sub-pjs15
-rw-r--r--tests/ref/fate/sub-realtext17
-rw-r--r--tests/ref/fate/sub-sami21
-rw-r--r--tests/ref/fate/sub-srt50
-rw-r--r--tests/ref/fate/sub-stl29
-rw-r--r--tests/ref/fate/sub-subripenc14
-rw-r--r--tests/ref/fate/sub-subviewer15
-rw-r--r--tests/ref/fate/sub-subviewer122
-rw-r--r--tests/ref/fate/sub-vplayer15
-rw-r--r--tests/ref/fate/sub-webvtt27
-rw-r--r--tests/ref/fate/sub-webvttenc177
-rw-r--r--tests/ref/fate/sub2video97
-rw-r--r--tests/ref/fate/svq1300
-rw-r--r--tests/ref/fate/svq1-headerswap8
-rw-r--r--tests/ref/fate/svq3360
-rw-r--r--tests/ref/fate/tdsc84
-rw-r--r--tests/ref/fate/theora-coeff-level6418
-rw-r--r--tests/ref/fate/timefilter12
-rw-r--r--tests/ref/fate/truemotion1-15210
-rw-r--r--tests/ref/fate/tscc-15bit450
-rw-r--r--tests/ref/fate/unknown_layout-ac31
-rw-r--r--tests/ref/fate/unknown_layout-pcm1
-rw-r--r--tests/ref/fate/utvideoenc_rgb_left6
-rw-r--r--tests/ref/fate/utvideoenc_rgb_median4
-rw-r--r--tests/ref/fate/utvideoenc_rgb_none104
-rw-r--r--tests/ref/fate/utvideoenc_rgba_left104
-rw-r--r--tests/ref/fate/utvideoenc_rgba_median104
-rw-r--r--tests/ref/fate/utvideoenc_rgba_none104
-rw-r--r--tests/ref/fate/utvideoenc_yuv420_left104
-rw-r--r--tests/ref/fate/utvideoenc_yuv420_median104
-rw-r--r--tests/ref/fate/utvideoenc_yuv420_none104
-rw-r--r--tests/ref/fate/utvideoenc_yuv422_left104
-rw-r--r--tests/ref/fate/utvideoenc_yuv422_median104
-rw-r--r--tests/ref/fate/utvideoenc_yuv422_none104
-rw-r--r--tests/ref/fate/v410enc2
-rw-r--r--tests/ref/fate/vc1-ism184
-rw-r--r--tests/ref/fate/vc1_ilaced_twomv20
-rw-r--r--tests/ref/fate/vcr2158
-rw-r--r--tests/ref/fate/vmnc-16bit384
-rw-r--r--tests/ref/fate/vp60192
-rw-r--r--tests/ref/fate/vp6a188
-rw-r--r--tests/ref/fate/vp6a-skip_alpha94
-rw-r--r--tests/ref/fate/vp6f350
-rw-r--r--tests/ref/fate/vp8-alpha121
-rw-r--r--tests/ref/fate/vp8-sign-bias7
-rw-r--r--tests/ref/fate/vp8-size-change66
-rw-r--r--tests/ref/fate/vp8-test-vector-0014
-rw-r--r--tests/ref/fate/vp8-test-vector-0024
-rw-r--r--tests/ref/fate/vp8-test-vector-0034
-rw-r--r--tests/ref/fate/vp8-test-vector-0044
-rw-r--r--tests/ref/fate/vp8-test-vector-0054
-rw-r--r--tests/ref/fate/vp8-test-vector-0064
-rw-r--r--tests/ref/fate/vp8-test-vector-0074
-rw-r--r--tests/ref/fate/vp8-test-vector-0084
-rw-r--r--tests/ref/fate/vp8-test-vector-0094
-rw-r--r--tests/ref/fate/vp8-test-vector-0104
-rw-r--r--tests/ref/fate/vp8-test-vector-0114
-rw-r--r--tests/ref/fate/vp8-test-vector-0124
-rw-r--r--tests/ref/fate/vp8-test-vector-0134
-rw-r--r--tests/ref/fate/vp8-test-vector-0144
-rw-r--r--tests/ref/fate/vp8-test-vector-0154
-rw-r--r--tests/ref/fate/vp8-test-vector-0164
-rw-r--r--tests/ref/fate/vp8-test-vector-0174
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0310
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0410
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0510
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0610
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0710
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0810
-rw-r--r--tests/ref/fate/vp9-00-quantizer-0910
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1310
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1410
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1510
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1610
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1710
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1810
-rw-r--r--tests/ref/fate/vp9-00-quantizer-1910
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2310
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2410
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2510
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2610
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2710
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2810
-rw-r--r--tests/ref/fate/vp9-00-quantizer-2910
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3310
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3410
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3510
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3610
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3710
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3810
-rw-r--r--tests/ref/fate/vp9-00-quantizer-3910
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4310
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4410
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4510
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4610
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4710
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4810
-rw-r--r--tests/ref/fate/vp9-00-quantizer-4910
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5310
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5410
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5510
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5610
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5710
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5810
-rw-r--r--tests/ref/fate/vp9-00-quantizer-5910
-rw-r--r--tests/ref/fate/vp9-00-quantizer-6010
-rw-r--r--tests/ref/fate/vp9-00-quantizer-6110
-rw-r--r--tests/ref/fate/vp9-00-quantizer-6210
-rw-r--r--tests/ref/fate/vp9-00-quantizer-6310
-rw-r--r--tests/ref/fate/vp9-01-sharpness-126
-rw-r--r--tests/ref/fate/vp9-01-sharpness-226
-rw-r--r--tests/ref/fate/vp9-01-sharpness-326
-rw-r--r--tests/ref/fate/vp9-01-sharpness-426
-rw-r--r--tests/ref/fate/vp9-01-sharpness-526
-rw-r--r--tests/ref/fate/vp9-01-sharpness-626
-rw-r--r--tests/ref/fate/vp9-01-sharpness-726
-rw-r--r--tests/ref/fate/vp9-02-size-08x0826
-rw-r--r--tests/ref/fate/vp9-02-size-08x1026
-rw-r--r--tests/ref/fate/vp9-02-size-08x1626
-rw-r--r--tests/ref/fate/vp9-02-size-08x1826
-rw-r--r--tests/ref/fate/vp9-02-size-08x3226
-rw-r--r--tests/ref/fate/vp9-02-size-08x3426
-rw-r--r--tests/ref/fate/vp9-02-size-08x6426
-rw-r--r--tests/ref/fate/vp9-02-size-08x6626
-rw-r--r--tests/ref/fate/vp9-02-size-10x0826
-rw-r--r--tests/ref/fate/vp9-02-size-10x1026
-rw-r--r--tests/ref/fate/vp9-02-size-10x1626
-rw-r--r--tests/ref/fate/vp9-02-size-10x1826
-rw-r--r--tests/ref/fate/vp9-02-size-10x3226
-rw-r--r--tests/ref/fate/vp9-02-size-10x3426
-rw-r--r--tests/ref/fate/vp9-02-size-10x6426
-rw-r--r--tests/ref/fate/vp9-02-size-10x6626
-rw-r--r--tests/ref/fate/vp9-02-size-16x0826
-rw-r--r--tests/ref/fate/vp9-02-size-16x1026
-rw-r--r--tests/ref/fate/vp9-02-size-16x1626
-rw-r--r--tests/ref/fate/vp9-02-size-16x1826
-rw-r--r--tests/ref/fate/vp9-02-size-16x3226
-rw-r--r--tests/ref/fate/vp9-02-size-16x3426
-rw-r--r--tests/ref/fate/vp9-02-size-16x6426
-rw-r--r--tests/ref/fate/vp9-02-size-16x6626
-rw-r--r--tests/ref/fate/vp9-02-size-18x0826
-rw-r--r--tests/ref/fate/vp9-02-size-18x1026
-rw-r--r--tests/ref/fate/vp9-02-size-18x1626
-rw-r--r--tests/ref/fate/vp9-02-size-18x1826
-rw-r--r--tests/ref/fate/vp9-02-size-18x3226
-rw-r--r--tests/ref/fate/vp9-02-size-18x3426
-rw-r--r--tests/ref/fate/vp9-02-size-18x6426
-rw-r--r--tests/ref/fate/vp9-02-size-18x6626
-rw-r--r--tests/ref/fate/vp9-02-size-32x0826
-rw-r--r--tests/ref/fate/vp9-02-size-32x1026
-rw-r--r--tests/ref/fate/vp9-02-size-32x1626
-rw-r--r--tests/ref/fate/vp9-02-size-32x1826
-rw-r--r--tests/ref/fate/vp9-02-size-32x3226
-rw-r--r--tests/ref/fate/vp9-02-size-32x3426
-rw-r--r--tests/ref/fate/vp9-02-size-32x6426
-rw-r--r--tests/ref/fate/vp9-02-size-32x6626
-rw-r--r--tests/ref/fate/vp9-02-size-34x0826
-rw-r--r--tests/ref/fate/vp9-02-size-34x1026
-rw-r--r--tests/ref/fate/vp9-02-size-34x1626
-rw-r--r--tests/ref/fate/vp9-02-size-34x1826
-rw-r--r--tests/ref/fate/vp9-02-size-34x3226
-rw-r--r--tests/ref/fate/vp9-02-size-34x3426
-rw-r--r--tests/ref/fate/vp9-02-size-34x6426
-rw-r--r--tests/ref/fate/vp9-02-size-34x6626
-rw-r--r--tests/ref/fate/vp9-02-size-64x0826
-rw-r--r--tests/ref/fate/vp9-02-size-64x1026
-rw-r--r--tests/ref/fate/vp9-02-size-64x1626
-rw-r--r--tests/ref/fate/vp9-02-size-64x1826
-rw-r--r--tests/ref/fate/vp9-02-size-64x3226
-rw-r--r--tests/ref/fate/vp9-02-size-64x3426
-rw-r--r--tests/ref/fate/vp9-02-size-64x6426
-rw-r--r--tests/ref/fate/vp9-02-size-64x6626
-rw-r--r--tests/ref/fate/vp9-02-size-66x0826
-rw-r--r--tests/ref/fate/vp9-02-size-66x1026
-rw-r--r--tests/ref/fate/vp9-02-size-66x1626
-rw-r--r--tests/ref/fate/vp9-02-size-66x1826
-rw-r--r--tests/ref/fate/vp9-02-size-66x3226
-rw-r--r--tests/ref/fate/vp9-02-size-66x3426
-rw-r--r--tests/ref/fate/vp9-02-size-66x6426
-rw-r--r--tests/ref/fate/vp9-02-size-66x6626
-rw-r--r--tests/ref/fate/vp9-03-deltaq10
-rw-r--r--tests/ref/fate/vp9-03-size-196x19626
-rw-r--r--tests/ref/fate/vp9-03-size-196x19826
-rw-r--r--tests/ref/fate/vp9-03-size-196x20026
-rw-r--r--tests/ref/fate/vp9-03-size-196x20226
-rw-r--r--tests/ref/fate/vp9-03-size-196x20826
-rw-r--r--tests/ref/fate/vp9-03-size-196x21026
-rw-r--r--tests/ref/fate/vp9-03-size-196x22426
-rw-r--r--tests/ref/fate/vp9-03-size-196x22626
-rw-r--r--tests/ref/fate/vp9-03-size-198x19626
-rw-r--r--tests/ref/fate/vp9-03-size-198x19826
-rw-r--r--tests/ref/fate/vp9-03-size-198x20026
-rw-r--r--tests/ref/fate/vp9-03-size-198x20226
-rw-r--r--tests/ref/fate/vp9-03-size-198x20826
-rw-r--r--tests/ref/fate/vp9-03-size-198x21026
-rw-r--r--tests/ref/fate/vp9-03-size-198x22426
-rw-r--r--tests/ref/fate/vp9-03-size-198x22626
-rw-r--r--tests/ref/fate/vp9-03-size-200x19626
-rw-r--r--tests/ref/fate/vp9-03-size-200x19826
-rw-r--r--tests/ref/fate/vp9-03-size-200x20026
-rw-r--r--tests/ref/fate/vp9-03-size-200x20226
-rw-r--r--tests/ref/fate/vp9-03-size-200x20826
-rw-r--r--tests/ref/fate/vp9-03-size-200x21026
-rw-r--r--tests/ref/fate/vp9-03-size-200x22426
-rw-r--r--tests/ref/fate/vp9-03-size-200x22626
-rw-r--r--tests/ref/fate/vp9-03-size-202x19626
-rw-r--r--tests/ref/fate/vp9-03-size-202x19826
-rw-r--r--tests/ref/fate/vp9-03-size-202x20026
-rw-r--r--tests/ref/fate/vp9-03-size-202x20226
-rw-r--r--tests/ref/fate/vp9-03-size-202x20826
-rw-r--r--tests/ref/fate/vp9-03-size-202x21026
-rw-r--r--tests/ref/fate/vp9-03-size-202x22426
-rw-r--r--tests/ref/fate/vp9-03-size-202x22626
-rw-r--r--tests/ref/fate/vp9-03-size-208x19626
-rw-r--r--tests/ref/fate/vp9-03-size-208x19826
-rw-r--r--tests/ref/fate/vp9-03-size-208x20026
-rw-r--r--tests/ref/fate/vp9-03-size-208x20226
-rw-r--r--tests/ref/fate/vp9-03-size-208x20826
-rw-r--r--tests/ref/fate/vp9-03-size-208x21026
-rw-r--r--tests/ref/fate/vp9-03-size-208x22426
-rw-r--r--tests/ref/fate/vp9-03-size-208x22626
-rw-r--r--tests/ref/fate/vp9-03-size-210x19626
-rw-r--r--tests/ref/fate/vp9-03-size-210x19826
-rw-r--r--tests/ref/fate/vp9-03-size-210x20026
-rw-r--r--tests/ref/fate/vp9-03-size-210x20226
-rw-r--r--tests/ref/fate/vp9-03-size-210x20826
-rw-r--r--tests/ref/fate/vp9-03-size-210x21026
-rw-r--r--tests/ref/fate/vp9-03-size-210x22426
-rw-r--r--tests/ref/fate/vp9-03-size-210x22626
-rw-r--r--tests/ref/fate/vp9-03-size-224x19626
-rw-r--r--tests/ref/fate/vp9-03-size-224x19826
-rw-r--r--tests/ref/fate/vp9-03-size-224x20026
-rw-r--r--tests/ref/fate/vp9-03-size-224x20226
-rw-r--r--tests/ref/fate/vp9-03-size-224x20826
-rw-r--r--tests/ref/fate/vp9-03-size-224x21026
-rw-r--r--tests/ref/fate/vp9-03-size-224x22426
-rw-r--r--tests/ref/fate/vp9-03-size-224x22626
-rw-r--r--tests/ref/fate/vp9-03-size-226x19626
-rw-r--r--tests/ref/fate/vp9-03-size-226x19826
-rw-r--r--tests/ref/fate/vp9-03-size-226x20026
-rw-r--r--tests/ref/fate/vp9-03-size-226x20226
-rw-r--r--tests/ref/fate/vp9-03-size-226x20826
-rw-r--r--tests/ref/fate/vp9-03-size-226x21026
-rw-r--r--tests/ref/fate/vp9-03-size-226x22426
-rw-r--r--tests/ref/fate/vp9-03-size-226x22626
-rw-r--r--tests/ref/fate/vp9-05-resize15
-rw-r--r--tests/ref/fate/vp9-06-bilinear15
-rw-r--r--tests/ref/fate/vp9-09-lf_deltas35
-rw-r--r--tests/ref/fate/vp9-10-show-existing-frame14
-rw-r--r--tests/ref/fate/vp9-10-show-existing-frame220
-rw-r--r--tests/ref/fate/vp9-15-segkey_adpq155
-rw-r--r--tests/ref/fate/vp9-16-intra-only10
-rw-r--r--tests/ref/fate/vp9-2pass-akiyo106
-rw-r--r--tests/ref/fate/vp9-parallelmode-akiyo56
-rw-r--r--tests/ref/fate/vp9-segmentation-aq-akiyo56
-rw-r--r--tests/ref/fate/vp9-segmentation-sf-akiyo56
-rw-r--r--tests/ref/fate/vp9-tiling-pedestrian4
-rw-r--r--tests/ref/fate/vp9-trac384915
-rw-r--r--tests/ref/fate/vp9-trac43599
-rw-r--r--tests/ref/fate/vp9p1-04-yuv42215
-rw-r--r--tests/ref/fate/vp9p1-04-yuv44015
-rw-r--r--tests/ref/fate/vp9p1-04-yuv44415
-rw-r--r--tests/ref/fate/vp9p2-20-10bit-yuv42015
-rw-r--r--tests/ref/fate/vp9p2-20-12bit-yuv42015
-rw-r--r--tests/ref/fate/vp9p3-20-10bit-yuv42215
-rw-r--r--tests/ref/fate/vp9p3-20-10bit-yuv44025
-rw-r--r--tests/ref/fate/vp9p3-20-10bit-yuv44415
-rw-r--r--tests/ref/fate/vp9p3-20-12bit-yuv42215
-rw-r--r--tests/ref/fate/vp9p3-20-12bit-yuv44025
-rw-r--r--tests/ref/fate/vp9p3-20-12bit-yuv44415
-rw-r--r--tests/ref/fate/vqa-cc68
-rw-r--r--tests/ref/fate/vqf-demux2
-rw-r--r--tests/ref/fate/webm-dash-manifest48
-rw-r--r--tests/ref/fate/webm-dash-manifest-live24
-rw-r--r--tests/ref/fate/webm-dash-manifest-representations30
-rw-r--r--tests/ref/fate/webm-dash-manifest-unaligned-audio-streams30
-rw-r--r--tests/ref/fate/webm-dash-manifest-unaligned-video-streams30
-rw-r--r--tests/ref/fate/wmv8-drm260
-rw-r--r--tests/ref/fate/wmv8-drm-nodec258
-rw-r--r--tests/ref/fate/wmv8-x8intra474
-rw-r--r--tests/ref/fate/wtv-demux88
-rw-r--r--tests/ref/fate/xbm112
-rw-r--r--tests/ref/fate/xface2
-rw-r--r--tests/ref/fate/xmv-demux177
-rw-r--r--tests/ref/fate/xvid-custom-matrix44
-rw-r--r--tests/ref/fate/xvid-idct44
-rw-r--r--tests/ref/fate/yop12
-rw-r--r--tests/ref/fate/zmbv-15bit318
-rw-r--r--tests/ref/fate/zmbv-16bit238
-rw-r--r--tests/ref/lavf-fate/latm3
-rw-r--r--tests/ref/lavf-fate/mp33
-rw-r--r--tests/ref/lavf-fate/ogg_vp33
-rw-r--r--tests/ref/lavf/aiff4
-rw-r--r--tests/ref/lavf/asf4
-rw-r--r--tests/ref/lavf/ast3
-rw-r--r--tests/ref/lavf/au4
-rw-r--r--tests/ref/lavf/avi6
-rw-r--r--tests/ref/lavf/bmp2
-rw-r--r--tests/ref/lavf/caf3
-rw-r--r--tests/ref/lavf/dpx19
-rw-r--r--tests/ref/lavf/dv_fmt10
-rw-r--r--tests/ref/lavf/ffm3
-rw-r--r--tests/ref/lavf/flm3
-rw-r--r--tests/ref/lavf/flv_fmt6
-rw-r--r--tests/ref/lavf/gif6
-rw-r--r--tests/ref/lavf/gxf12
-rw-r--r--tests/ref/lavf/ircam3
-rw-r--r--tests/ref/lavf/ismv9
-rw-r--r--tests/ref/lavf/jpg2
-rw-r--r--tests/ref/lavf/mkv9
-rw-r--r--tests/ref/lavf/mmf4
-rw-r--r--tests/ref/lavf/mov15
-rw-r--r--tests/ref/lavf/mpg10
-rw-r--r--tests/ref/lavf/mxf10
-rw-r--r--tests/ref/lavf/mxf_d104
-rw-r--r--tests/ref/lavf/mxf_opatom3
-rw-r--r--tests/ref/lavf/mxf_opatom_audio3
-rw-r--r--tests/ref/lavf/nut6
-rw-r--r--tests/ref/lavf/ogg4
-rw-r--r--tests/ref/lavf/pam17
-rw-r--r--tests/ref/lavf/pcx4
-rw-r--r--tests/ref/lavf/pgm4
-rw-r--r--tests/ref/lavf/pgmpipe4
-rw-r--r--tests/ref/lavf/pixfmt16
-rw-r--r--tests/ref/lavf/png12
-rw-r--r--tests/ref/lavf/ppm2
-rw-r--r--tests/ref/lavf/rm4
-rw-r--r--tests/ref/lavf/sgi2
-rw-r--r--tests/ref/lavf/smjpeg3
-rw-r--r--tests/ref/lavf/sunrast2
-rw-r--r--tests/ref/lavf/swf6
-rw-r--r--tests/ref/lavf/tga2
-rw-r--r--tests/ref/lavf/tiff2
-rw-r--r--tests/ref/lavf/ts6
-rw-r--r--tests/ref/lavf/voc2
-rw-r--r--tests/ref/lavf/voc_s164
-rw-r--r--tests/ref/lavf/w643
-rw-r--r--tests/ref/lavf/wav4
-rw-r--r--tests/ref/lavf/wav_peak3
-rw-r--r--tests/ref/lavf/wav_peak_only2
-rw-r--r--tests/ref/lavf/wtv3
-rw-r--r--tests/ref/lavf/xbm3
-rw-r--r--tests/ref/lavf/xwd23
-rw-r--r--tests/ref/seek/acodec-adpcm-ima_qt-trellis53
-rw-r--r--tests/ref/seek/acodec-adpcm-ima_wav-trellis53
-rw-r--r--tests/ref/seek/acodec-adpcm-ms-trellis53
-rw-r--r--tests/ref/seek/acodec-adpcm-swf-trellis49
-rw-r--r--tests/ref/seek/acodec-adpcm-yamaha-trellis53
-rw-r--r--tests/ref/seek/acodec-flac58
-rw-r--r--tests/ref/seek/acodec-pcm-f32be54
-rw-r--r--tests/ref/seek/acodec-pcm-f64be54
-rw-r--r--tests/ref/seek/acodec-pcm-s16le54
-rw-r--r--tests/ref/seek/acodec-pcm-u854
-rw-r--r--tests/ref/seek/extra-mp353
-rw-r--r--tests/ref/seek/lavf-aiff30
-rw-r--r--tests/ref/seek/lavf-asf54
-rw-r--r--tests/ref/seek/lavf-au30
-rw-r--r--tests/ref/seek/lavf-avi36
-rw-r--r--tests/ref/seek/lavf-bmp9
-rw-r--r--tests/ref/seek/lavf-dv_fmt54
-rw-r--r--tests/ref/seek/lavf-ffm53
-rw-r--r--tests/ref/seek/lavf-flv_fmt36
-rw-r--r--tests/ref/seek/lavf-gif67
-rw-r--r--tests/ref/seek/lavf-gxf36
-rw-r--r--tests/ref/seek/lavf-jpg9
-rw-r--r--tests/ref/seek/lavf-mkv59
-rw-r--r--tests/ref/seek/lavf-mmf53
-rw-r--r--tests/ref/seek/lavf-mov60
-rw-r--r--tests/ref/seek/lavf-mpg54
-rw-r--r--tests/ref/seek/lavf-mxf44
-rw-r--r--tests/ref/seek/lavf-mxf_opatom53
-rw-r--r--tests/ref/seek/lavf-mxf_opatom_audio53
-rw-r--r--tests/ref/seek/lavf-nut86
-rw-r--r--tests/ref/seek/lavf-ogg63
-rw-r--r--tests/ref/seek/lavf-pbmpipe52
-rw-r--r--tests/ref/seek/lavf-pcx9
-rw-r--r--tests/ref/seek/lavf-pgm9
-rw-r--r--tests/ref/seek/lavf-pgmpipe52
-rw-r--r--tests/ref/seek/lavf-ppm9
-rw-r--r--tests/ref/seek/lavf-ppmpipe52
-rw-r--r--tests/ref/seek/lavf-rm54
-rw-r--r--tests/ref/seek/lavf-sgi9
-rw-r--r--tests/ref/seek/lavf-tga9
-rw-r--r--tests/ref/seek/lavf-tiff9
-rw-r--r--tests/ref/seek/lavf-ts54
-rw-r--r--tests/ref/seek/lavf-voc57
-rw-r--r--tests/ref/seek/lavf-wav30
-rw-r--r--tests/ref/seek/lavf-wtv48
-rw-r--r--tests/ref/seek/vsynth2-asv146
-rw-r--r--tests/ref/seek/vsynth2-asv246
-rw-r--r--tests/ref/seek/vsynth2-dnxhd-1080i44
-rw-r--r--tests/ref/seek/vsynth2-dnxhd-720p40
-rw-r--r--tests/ref/seek/vsynth2-dnxhd-720p-rd40
-rw-r--r--tests/ref/seek/vsynth2-dv53
-rw-r--r--tests/ref/seek/vsynth2-dv-41153
-rw-r--r--tests/ref/seek/vsynth2-dv-5053
-rw-r--r--tests/ref/seek/vsynth2-ffv146
-rw-r--r--tests/ref/seek/vsynth2-flashsv46
-rw-r--r--tests/ref/seek/vsynth2-flv46
-rw-r--r--tests/ref/seek/vsynth2-h26146
-rw-r--r--tests/ref/seek/vsynth2-h26346
-rw-r--r--tests/ref/seek/vsynth2-h263p46
-rw-r--r--tests/ref/seek/vsynth2-huffyuv46
-rw-r--r--tests/ref/seek/vsynth2-jpegls46
-rw-r--r--tests/ref/seek/vsynth2-ljpeg46
-rw-r--r--tests/ref/seek/vsynth2-mjpeg46
-rw-r--r--tests/ref/seek/vsynth2-mpeg146
-rw-r--r--tests/ref/seek/vsynth2-mpeg1b46
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-42246
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-idct-int46
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-ilace46
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-ivlc-qprd46
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-thread46
-rw-r--r--tests/ref/seek/vsynth2-mpeg2-thread-ivlc46
-rw-r--r--tests/ref/seek/vsynth2-mpeg450
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-adap46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-adv46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-error46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-nr46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-qpel46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-qprd46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-rc46
-rw-r--r--tests/ref/seek/vsynth2-mpeg4-thread46
-rw-r--r--tests/ref/seek/vsynth2-msmpeg446
-rw-r--r--tests/ref/seek/vsynth2-msmpeg4v246
-rw-r--r--tests/ref/seek/vsynth2-rgb46
-rw-r--r--tests/ref/seek/vsynth2-roqvideo27
-rw-r--r--tests/ref/seek/vsynth2-rv1052
-rw-r--r--tests/ref/seek/vsynth2-rv2053
-rw-r--r--tests/ref/seek/vsynth2-svq150
-rw-r--r--tests/ref/seek/vsynth2-wmv146
-rw-r--r--tests/ref/seek/vsynth2-wmv246
-rw-r--r--tests/ref/seek/vsynth2-yuv46
-rw-r--r--tests/ref/seek/vsynth_lena-asv146
-rw-r--r--tests/ref/seek/vsynth_lena-asv246
-rw-r--r--tests/ref/seek/vsynth_lena-dnxhd-1080i44
-rw-r--r--tests/ref/seek/vsynth_lena-dnxhd-720p40
-rw-r--r--tests/ref/seek/vsynth_lena-dnxhd-720p-rd40
-rw-r--r--tests/ref/seek/vsynth_lena-dv53
-rw-r--r--tests/ref/seek/vsynth_lena-dv-41153
-rw-r--r--tests/ref/seek/vsynth_lena-dv-5053
-rw-r--r--tests/ref/seek/vsynth_lena-ffv146
-rw-r--r--tests/ref/seek/vsynth_lena-flashsv46
-rw-r--r--tests/ref/seek/vsynth_lena-flv46
-rw-r--r--tests/ref/seek/vsynth_lena-h26146
-rw-r--r--tests/ref/seek/vsynth_lena-h26346
-rw-r--r--tests/ref/seek/vsynth_lena-h263p46
-rw-r--r--tests/ref/seek/vsynth_lena-huffyuv46
-rw-r--r--tests/ref/seek/vsynth_lena-jpegls46
-rw-r--r--tests/ref/seek/vsynth_lena-ljpeg46
-rw-r--r--tests/ref/seek/vsynth_lena-mjpeg46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg146
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg1b46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg2-42246
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg2-idct-int46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg2-ilace46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg2-ivlc-qprd46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg2-thread46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg2-thread-ivlc46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg450
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-adap46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-adv46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-error46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-nr46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-nsse46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-qpel46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-qprd46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-rc46
-rw-r--r--tests/ref/seek/vsynth_lena-mpeg4-thread46
-rw-r--r--tests/ref/seek/vsynth_lena-msmpeg446
-rw-r--r--tests/ref/seek/vsynth_lena-msmpeg4v246
-rw-r--r--tests/ref/seek/vsynth_lena-rgb46
-rw-r--r--tests/ref/seek/vsynth_lena-roqvideo27
-rw-r--r--tests/ref/seek/vsynth_lena-rv1052
-rw-r--r--tests/ref/seek/vsynth_lena-rv2053
-rw-r--r--tests/ref/seek/vsynth_lena-snow46
-rw-r--r--tests/ref/seek/vsynth_lena-snow-ll46
-rw-r--r--tests/ref/seek/vsynth_lena-svq150
-rw-r--r--tests/ref/seek/vsynth_lena-wmv146
-rw-r--r--tests/ref/seek/vsynth_lena-wmv246
-rw-r--r--tests/ref/seek/vsynth_lena-yuv46
-rw-r--r--tests/ref/vsynth/vsynth1-amv4
-rw-r--r--tests/ref/vsynth/vsynth1-asv18
-rw-r--r--tests/ref/vsynth/vsynth1-asv28
-rw-r--r--tests/ref/vsynth/vsynth1-avui4
-rw-r--r--tests/ref/vsynth/vsynth1-cinepak4
-rw-r--r--tests/ref/vsynth/vsynth1-cljr8
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd-1080i6
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd-1080i-colr4
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd-720p6
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd-720p-10bit4
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd-720p-rd4
-rw-r--r--tests/ref/vsynth/vsynth1-dnxhd_1080i4
-rw-r--r--tests/ref/vsynth/vsynth1-dv4
-rw-r--r--tests/ref/vsynth/vsynth1-dv-4116
-rw-r--r--tests/ref/vsynth/vsynth1-dv-504
-rw-r--r--tests/ref/vsynth/vsynth1-dv_4114
-rw-r--r--tests/ref/vsynth/vsynth1-ffv14
-rw-r--r--tests/ref/vsynth/vsynth1-ffv1.04
-rw-r--r--tests/ref/vsynth/vsynth1-ffvhuff4
-rw-r--r--tests/ref/vsynth/vsynth1-ffvhuff420p124
-rw-r--r--tests/ref/vsynth/vsynth1-ffvhuff422p10left4
-rw-r--r--tests/ref/vsynth/vsynth1-ffvhuff4444
-rw-r--r--tests/ref/vsynth/vsynth1-ffvhuff444p164
-rw-r--r--tests/ref/vsynth/vsynth1-flashsv8
-rw-r--r--tests/ref/vsynth/vsynth1-flashsv24
-rw-r--r--tests/ref/vsynth/vsynth1-flv6
-rw-r--r--tests/ref/vsynth/vsynth1-h2616
-rw-r--r--tests/ref/vsynth/vsynth1-h261-trellis4
-rw-r--r--tests/ref/vsynth/vsynth1-h2636
-rw-r--r--tests/ref/vsynth/vsynth1-h263-obmc6
-rw-r--r--tests/ref/vsynth/vsynth1-h263p6
-rw-r--r--tests/ref/vsynth/vsynth1-huffyuv4
-rw-r--r--tests/ref/vsynth/vsynth1-huffyuvbgr244
-rw-r--r--tests/ref/vsynth/vsynth1-huffyuvbgra4
-rw-r--r--tests/ref/vsynth/vsynth1-jpeg20004
-rw-r--r--tests/ref/vsynth/vsynth1-jpeg2000-974
-rw-r--r--tests/ref/vsynth/vsynth1-jpegls8
-rw-r--r--tests/ref/vsynth/vsynth1-ljpeg4
-rw-r--r--tests/ref/vsynth/vsynth1-mjpeg6
-rw-r--r--tests/ref/vsynth/vsynth1-mjpeg-4224
-rw-r--r--tests/ref/vsynth/vsynth1-mjpeg-4444
-rw-r--r--tests/ref/vsynth/vsynth1-mjpeg-trell4
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg18
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg1b6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg26
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg2-4228
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg2-idct-int4
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg2-ilace6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd8
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg2-thread6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg46
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-adap6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-adv6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-error8
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-nr8
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-nsse4
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-qpel8
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-qprd6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-rc6
-rw-r--r--tests/ref/vsynth/vsynth1-mpeg4-thread6
-rw-r--r--tests/ref/vsynth/vsynth1-mpng4
-rw-r--r--tests/ref/vsynth/vsynth1-msmpeg44
-rw-r--r--tests/ref/vsynth/vsynth1-msmpeg4v26
-rw-r--r--tests/ref/vsynth/vsynth1-msvideo14
-rw-r--r--tests/ref/vsynth/vsynth1-prores8
-rw-r--r--tests/ref/vsynth/vsynth1-prores_ks4
-rw-r--r--tests/ref/vsynth/vsynth1-qtrle8
-rw-r--r--tests/ref/vsynth/vsynth1-qtrlegray4
-rw-r--r--tests/ref/vsynth/vsynth1-r2104
-rw-r--r--tests/ref/vsynth/vsynth1-rgb8
-rw-r--r--tests/ref/vsynth/vsynth1-roqvideo8
-rw-r--r--tests/ref/vsynth/vsynth1-rv106
-rw-r--r--tests/ref/vsynth/vsynth1-rv206
-rw-r--r--tests/ref/vsynth/vsynth1-snow4
-rw-r--r--tests/ref/vsynth/vsynth1-snow-hpel4
-rw-r--r--tests/ref/vsynth/vsynth1-snow-ll4
-rw-r--r--tests/ref/vsynth/vsynth1-svq14
-rw-r--r--tests/ref/vsynth/vsynth1-v2104
-rw-r--r--tests/ref/vsynth/vsynth1-v3084
-rw-r--r--tests/ref/vsynth/vsynth1-v4084
-rw-r--r--tests/ref/vsynth/vsynth1-wmv16
-rw-r--r--tests/ref/vsynth/vsynth1-wmv26
-rw-r--r--tests/ref/vsynth/vsynth1-xface4
-rw-r--r--tests/ref/vsynth/vsynth1-y41p4
-rw-r--r--tests/ref/vsynth/vsynth1-yuv4
-rw-r--r--tests/ref/vsynth/vsynth1-yuv44
-rw-r--r--tests/ref/vsynth/vsynth1-zlib4
-rw-r--r--tests/ref/vsynth/vsynth1-zmbv4
-rw-r--r--tests/ref/vsynth/vsynth2-amv4
-rw-r--r--tests/ref/vsynth/vsynth2-asv18
-rw-r--r--tests/ref/vsynth/vsynth2-asv28
-rw-r--r--tests/ref/vsynth/vsynth2-avui4
-rw-r--r--tests/ref/vsynth/vsynth2-cinepak4
-rw-r--r--tests/ref/vsynth/vsynth2-cljr8
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd-1080i6
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd-1080i-colr4
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd-720p6
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd-720p-10bit6
-rw-r--r--tests/ref/vsynth/vsynth2-dnxhd-720p-rd6
-rw-r--r--tests/ref/vsynth/vsynth2-dv6
-rw-r--r--tests/ref/vsynth/vsynth2-dv-4114
-rw-r--r--tests/ref/vsynth/vsynth2-dv-506
-rw-r--r--tests/ref/vsynth/vsynth2-ffv14
-rw-r--r--tests/ref/vsynth/vsynth2-ffv1.04
-rw-r--r--tests/ref/vsynth/vsynth2-ffvhuff4
-rw-r--r--tests/ref/vsynth/vsynth2-ffvhuff420p124
-rw-r--r--tests/ref/vsynth/vsynth2-ffvhuff422p10left4
-rw-r--r--tests/ref/vsynth/vsynth2-ffvhuff4444
-rw-r--r--tests/ref/vsynth/vsynth2-ffvhuff444p164
-rw-r--r--tests/ref/vsynth/vsynth2-flashsv8
-rw-r--r--tests/ref/vsynth/vsynth2-flashsv24
-rw-r--r--tests/ref/vsynth/vsynth2-flv6
-rw-r--r--tests/ref/vsynth/vsynth2-h2616
-rw-r--r--tests/ref/vsynth/vsynth2-h261-trellis4
-rw-r--r--tests/ref/vsynth/vsynth2-h2636
-rw-r--r--tests/ref/vsynth/vsynth2-h263-obmc6
-rw-r--r--tests/ref/vsynth/vsynth2-h263p4
-rw-r--r--tests/ref/vsynth/vsynth2-huffyuv4
-rw-r--r--tests/ref/vsynth/vsynth2-huffyuvbgr244
-rw-r--r--tests/ref/vsynth/vsynth2-huffyuvbgra4
-rw-r--r--tests/ref/vsynth/vsynth2-jpeg20004
-rw-r--r--tests/ref/vsynth/vsynth2-jpeg2000-974
-rw-r--r--tests/ref/vsynth/vsynth2-jpegls8
-rw-r--r--tests/ref/vsynth/vsynth2-ljpeg4
-rw-r--r--tests/ref/vsynth/vsynth2-mjpeg6
-rw-r--r--tests/ref/vsynth/vsynth2-mjpeg-4224
-rw-r--r--tests/ref/vsynth/vsynth2-mjpeg-4444
-rw-r--r--tests/ref/vsynth/vsynth2-mjpeg-trell4
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg16
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg1b6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg26
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg2-4228
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg2-idct-int4
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg2-ilace6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg2-thread6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg46
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-adap8
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-adv4
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-error8
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-nr6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-nsse4
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-qpel6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-qprd4
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-rc6
-rw-r--r--tests/ref/vsynth/vsynth2-mpeg4-thread6
-rw-r--r--tests/ref/vsynth/vsynth2-mpng4
-rw-r--r--tests/ref/vsynth/vsynth2-msmpeg46
-rw-r--r--tests/ref/vsynth/vsynth2-msmpeg4v24
-rw-r--r--tests/ref/vsynth/vsynth2-msvideo14
-rw-r--r--tests/ref/vsynth/vsynth2-prores8
-rw-r--r--tests/ref/vsynth/vsynth2-prores_ks4
-rw-r--r--tests/ref/vsynth/vsynth2-qtrle8
-rw-r--r--tests/ref/vsynth/vsynth2-qtrlegray4
-rw-r--r--tests/ref/vsynth/vsynth2-r2104
-rw-r--r--tests/ref/vsynth/vsynth2-rgb8
-rw-r--r--tests/ref/vsynth/vsynth2-roqvideo8
-rw-r--r--tests/ref/vsynth/vsynth2-rv106
-rw-r--r--tests/ref/vsynth/vsynth2-rv206
-rw-r--r--tests/ref/vsynth/vsynth2-snow4
-rw-r--r--tests/ref/vsynth/vsynth2-snow-hpel4
-rw-r--r--tests/ref/vsynth/vsynth2-snow-ll4
-rw-r--r--tests/ref/vsynth/vsynth2-svq14
-rw-r--r--tests/ref/vsynth/vsynth2-v2104
-rw-r--r--tests/ref/vsynth/vsynth2-v3084
-rw-r--r--tests/ref/vsynth/vsynth2-v4084
-rw-r--r--tests/ref/vsynth/vsynth2-wmv16
-rw-r--r--tests/ref/vsynth/vsynth2-wmv26
-rw-r--r--tests/ref/vsynth/vsynth2-xface4
-rw-r--r--tests/ref/vsynth/vsynth2-y41p4
-rw-r--r--tests/ref/vsynth/vsynth2-yuv4
-rw-r--r--tests/ref/vsynth/vsynth2-yuv44
-rw-r--r--tests/ref/vsynth/vsynth2-zlib4
-rw-r--r--tests/ref/vsynth/vsynth3-amv4
-rw-r--r--tests/ref/vsynth/vsynth3-asv14
-rw-r--r--tests/ref/vsynth/vsynth3-asv24
-rw-r--r--tests/ref/vsynth/vsynth3-cljr4
-rw-r--r--tests/ref/vsynth/vsynth3-dnxhd-1080i-colr4
-rw-r--r--tests/ref/vsynth/vsynth3-ffv14
-rw-r--r--tests/ref/vsynth/vsynth3-ffv1.04
-rw-r--r--tests/ref/vsynth/vsynth3-ffvhuff4
-rw-r--r--tests/ref/vsynth/vsynth3-ffvhuff420p124
-rw-r--r--tests/ref/vsynth/vsynth3-ffvhuff422p10left4
-rw-r--r--tests/ref/vsynth/vsynth3-ffvhuff4444
-rw-r--r--tests/ref/vsynth/vsynth3-ffvhuff444p164
-rw-r--r--tests/ref/vsynth/vsynth3-flashsv4
-rw-r--r--tests/ref/vsynth/vsynth3-flashsv24
-rw-r--r--tests/ref/vsynth/vsynth3-flv4
-rw-r--r--tests/ref/vsynth/vsynth3-huffyuv4
-rw-r--r--tests/ref/vsynth/vsynth3-huffyuvbgr244
-rw-r--r--tests/ref/vsynth/vsynth3-huffyuvbgra4
-rw-r--r--tests/ref/vsynth/vsynth3-jpeg20004
-rw-r--r--tests/ref/vsynth/vsynth3-jpeg2000-974
-rw-r--r--tests/ref/vsynth/vsynth3-jpegls4
-rw-r--r--tests/ref/vsynth/vsynth3-ljpeg4
-rw-r--r--tests/ref/vsynth/vsynth3-mjpeg4
-rw-r--r--tests/ref/vsynth/vsynth3-mjpeg-4224
-rw-r--r--tests/ref/vsynth/vsynth3-mjpeg-4444
-rw-r--r--tests/ref/vsynth/vsynth3-mjpeg-trell4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg14
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg1b4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg24
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg2-4224
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg2-idct-int4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg2-ilace4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg2-ivlc-qprd4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg2-thread4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg2-thread-ivlc4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg44
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-adap4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-adv4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-error4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-nr4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-nsse4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-qpel4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-qprd4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-rc4
-rw-r--r--tests/ref/vsynth/vsynth3-mpeg4-thread4
-rw-r--r--tests/ref/vsynth/vsynth3-mpng4
-rw-r--r--tests/ref/vsynth/vsynth3-msmpeg44
-rw-r--r--tests/ref/vsynth/vsynth3-msmpeg4v24
-rw-r--r--tests/ref/vsynth/vsynth3-prores4
-rw-r--r--tests/ref/vsynth/vsynth3-prores_ks4
-rw-r--r--tests/ref/vsynth/vsynth3-qtrle4
-rw-r--r--tests/ref/vsynth/vsynth3-r2104
-rw-r--r--tests/ref/vsynth/vsynth3-rgb4
-rw-r--r--tests/ref/vsynth/vsynth3-svq14
-rw-r--r--tests/ref/vsynth/vsynth3-v2104
-rw-r--r--tests/ref/vsynth/vsynth3-v3084
-rw-r--r--tests/ref/vsynth/vsynth3-v4084
-rw-r--r--tests/ref/vsynth/vsynth3-wmv14
-rw-r--r--tests/ref/vsynth/vsynth3-wmv24
-rw-r--r--tests/ref/vsynth/vsynth3-xface4
-rw-r--r--tests/ref/vsynth/vsynth3-yuv4
-rw-r--r--tests/ref/vsynth/vsynth3-yuv44
-rw-r--r--tests/ref/vsynth/vsynth3-zlib4
-rw-r--r--tests/ref/vsynth/vsynth_lena-amv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-asv14
-rw-r--r--tests/ref/vsynth/vsynth_lena-asv24
-rw-r--r--tests/ref/vsynth/vsynth_lena-avui4
-rw-r--r--tests/ref/vsynth/vsynth_lena-cinepak4
-rw-r--r--tests/ref/vsynth/vsynth_lena-cljr4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dnxhd-1080i4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dnxhd-720p4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dnxhd-720p-10bit4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dnxhd-720p-rd4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dnxhd_1080i4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-dv-4114
-rw-r--r--tests/ref/vsynth/vsynth_lena-dv-504
-rw-r--r--tests/ref/vsynth/vsynth_lena-dv_4114
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffv14
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffv1.04
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffvhuff4
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffvhuff420p124
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffvhuff422p10left4
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffvhuff4444
-rw-r--r--tests/ref/vsynth/vsynth_lena-ffvhuff444p164
-rw-r--r--tests/ref/vsynth/vsynth_lena-flashsv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-flashsv24
-rw-r--r--tests/ref/vsynth/vsynth_lena-flv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-h2614
-rw-r--r--tests/ref/vsynth/vsynth_lena-h261-trellis4
-rw-r--r--tests/ref/vsynth/vsynth_lena-h2634
-rw-r--r--tests/ref/vsynth/vsynth_lena-h263-obmc4
-rw-r--r--tests/ref/vsynth/vsynth_lena-h263p4
-rw-r--r--tests/ref/vsynth/vsynth_lena-huffyuv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-huffyuvbgr244
-rw-r--r--tests/ref/vsynth/vsynth_lena-huffyuvbgra4
-rw-r--r--tests/ref/vsynth/vsynth_lena-jpeg20004
-rw-r--r--tests/ref/vsynth/vsynth_lena-jpeg2000-974
-rw-r--r--tests/ref/vsynth/vsynth_lena-jpegls4
-rw-r--r--tests/ref/vsynth/vsynth_lena-ljpeg4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mjpeg4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mjpeg-4224
-rw-r--r--tests/ref/vsynth/vsynth_lena-mjpeg-4444
-rw-r--r--tests/ref/vsynth/vsynth_lena-mjpeg-trell4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg14
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg1b4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg24
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg2-4224
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg2-idct-int4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg2-ilace4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg2-ivlc-qprd4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg2-thread4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg2-thread-ivlc4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg44
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-adap4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-adv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-error4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-nr4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-nsse4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-qpel4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-qprd4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-rc4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpeg4-thread4
-rw-r--r--tests/ref/vsynth/vsynth_lena-mpng4
-rw-r--r--tests/ref/vsynth/vsynth_lena-msmpeg44
-rw-r--r--tests/ref/vsynth/vsynth_lena-msmpeg4v24
-rw-r--r--tests/ref/vsynth/vsynth_lena-msvideo14
-rw-r--r--tests/ref/vsynth/vsynth_lena-prores4
-rw-r--r--tests/ref/vsynth/vsynth_lena-prores_ks4
-rw-r--r--tests/ref/vsynth/vsynth_lena-qtrle4
-rw-r--r--tests/ref/vsynth/vsynth_lena-qtrlegray4
-rw-r--r--tests/ref/vsynth/vsynth_lena-r2104
-rw-r--r--tests/ref/vsynth/vsynth_lena-rgb4
-rw-r--r--tests/ref/vsynth/vsynth_lena-roqvideo4
-rw-r--r--tests/ref/vsynth/vsynth_lena-rv104
-rw-r--r--tests/ref/vsynth/vsynth_lena-rv204
-rw-r--r--tests/ref/vsynth/vsynth_lena-snow4
-rw-r--r--tests/ref/vsynth/vsynth_lena-snow-hpel4
-rw-r--r--tests/ref/vsynth/vsynth_lena-snow-ll4
-rw-r--r--tests/ref/vsynth/vsynth_lena-svq14
-rw-r--r--tests/ref/vsynth/vsynth_lena-v2104
-rw-r--r--tests/ref/vsynth/vsynth_lena-v3084
-rw-r--r--tests/ref/vsynth/vsynth_lena-v4084
-rw-r--r--tests/ref/vsynth/vsynth_lena-wmv14
-rw-r--r--tests/ref/vsynth/vsynth_lena-wmv24
-rw-r--r--tests/ref/vsynth/vsynth_lena-xface4
-rw-r--r--tests/ref/vsynth/vsynth_lena-y41p4
-rw-r--r--tests/ref/vsynth/vsynth_lena-yuv4
-rw-r--r--tests/ref/vsynth/vsynth_lena-yuv44
-rw-r--r--tests/ref/vsynth/vsynth_lena-zlib4
-rw-r--r--tests/ref/vsynth/vsynth_lena-zmbv4
-rw-r--r--tests/ref/vsynth1/cljr4
-rw-r--r--tests/ref/vsynth1/yuv4
-rw-r--r--tests/ref/vsynth_lena/cljr4
-rw-r--r--tests/ref/vsynth_lena/huffyuv4
-rw-r--r--tests/ref/vsynth_lena/yuv4
-rwxr-xr-xtests/regression-funcs.sh28
-rw-r--r--tests/rotozoom.c8
-rw-r--r--tests/test.ffmeta9
-rw-r--r--tests/tiny_psnr.c178
-rw-r--r--tests/tiny_ssim.c246
-rw-r--r--tests/utils.c18
-rw-r--r--tests/videogen.c30
-rw-r--r--tools/aviocat.c8
-rwxr-xr-xtools/bisect-create46
-rw-r--r--tools/bookmarklets.html55
-rw-r--r--tools/build_libstagefright58
-rwxr-xr-xtools/clean-diff11
-rw-r--r--tools/coverity.c42
-rw-r--r--tools/crypto_bench.c490
-rw-r--r--tools/cws2fws.c16
-rwxr-xr-xtools/dvd2concat127
-rw-r--r--tools/enum_options.c143
-rw-r--r--tools/ffescape.c180
-rw-r--r--tools/ffeval.c139
-rw-r--r--tools/ffhash.c152
-rw-r--r--tools/fourcc2pixfmt.c124
-rwxr-xr-xtools/gen-rc121
-rw-r--r--tools/graph2dot.c49
-rw-r--r--tools/ismindex.c23
-rwxr-xr-xtools/make_chlayout_test114
-rwxr-xr-xtools/missing_codec_desc36
-rwxr-xr-xtools/normalize.py33
-rwxr-xr-xtools/patcheck13
-rw-r--r--tools/pktdumper.c8
-rwxr-xr-xtools/plotframes164
-rw-r--r--tools/probetest.c99
-rw-r--r--tools/qt-faststart.c18
-rw-r--r--tools/seek_print.c105
-rw-r--r--tools/sidxindex.c14
-rw-r--r--tools/trasher.c23
-rw-r--r--tools/uncoded_frame.c279
-rwxr-xr-xtools/unwrap-diff2
-rw-r--r--tools/yuvcmp.c184
-rw-r--r--tools/zmqsend.c167
-rwxr-xr-xtools/zmqshell.py26
-rwxr-xr-xversion.sh46
4446 files changed, 420686 insertions, 99766 deletions
diff --git a/.gitignore b/.gitignore
index e225866ec6..71d4d647e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,41 +19,66 @@
*.ver
*-example
*-test
+*_g
/.config
/.version
-/avconv
-/avplay
-/avprobe
+/ffmpeg
+/ffplay
+/ffprobe
+/ffserver
/config.*
/coverage.info
-/version.h
/doc/*.1
+/doc/*.3
/doc/*.html
/doc/*.pod
+/doc/config.texi
/doc/avoptions_codec.texi
/doc/avoptions_format.texi
/doc/doxy/html/
-/doc/examples/avcodec
+/doc/examples/avio_list_dir
+/doc/examples/avio_reading
+/doc/examples/decoding_encoding
+/doc/examples/demuxing_decoding
+/doc/examples/extract_mvs
/doc/examples/filter_audio
+/doc/examples/filtering_audio
+/doc/examples/filtering_video
/doc/examples/metadata
-/doc/examples/output
+/doc/examples/muxing
+/doc/examples/pc-uninstalled
+/doc/examples/remuxing
+/doc/examples/resampling_audio
+/doc/examples/scaling_video
/doc/examples/transcode_aac
+/doc/examples/transcoding
+/doc/fate.txt
/doc/print_options
/lcov/
/libavcodec/*_tablegen
/libavcodec/*_tables.c
/libavcodec/*_tables.h
/libavutil/avconfig.h
+/libavutil/ffversion.h
/tests/audiogen
/tests/base64
/tests/data/
/tests/pixfmts.mak
/tests/rotozoom
+/tests/test_copy.ffmeta
/tests/tiny_psnr
+/tests/tiny_ssim
/tests/videogen
/tests/vsynth1/
/tools/aviocat
+/tools/ffbisect
+/tools/bisect.need
+/tools/crypto_bench
/tools/cws2fws
+/tools/fourcc2pixfmt
+/tools/ffescape
+/tools/ffeval
+/tools/ffhash
/tools/graph2dot
/tools/ismindex
/tools/pktdumper
@@ -61,3 +86,6 @@
/tools/qt-faststart
/tools/sidxindex
/tools/trasher
+/tools/seek_print
+/tools/uncoded_frame
+/tools/zmqsend
diff --git a/CREDITS b/CREDITS
index 4a537786f0..e29f0b853c 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1,55 +1,6 @@
-This file contains the names of some of the people who have contributed to
-Libav/FFmpeg. The names are sorted alphabetically by last name. As this file is
-currently quite outdated and git serves as a much better tool for determining
-authorship, it remains here for historical reasons only.
+See the Git history of the project (git://source.ffmpeg.org/ffmpeg) to
+get the names of people who have contributed to FFmpeg.
-DĂ©nes Balatoni
-Michel Bardiaux
-Fabrice Bellard
-Patrice Bensoussan
-Alex Beregszaszi
-BERO
-Thilo Borgmann
-Mario Brito
-Ronald Bultje
-Alex Converse
-Maarten Daniels
-Reimar Doeffinger
-Tim Ferguson
-Brian Foley
-Arpad Gereoffy
-Philip Gladstone
-Vladimir Gneushev
-Roine Gustafsson
-David Hammerton
-Wolfgang Hesseler
-Marc Hoffman
-Falk Hueffner
-Aurélien Jacobs
-Steven Johnson
-Zdenek Kabelac
-Robin Kay
-Todd Kirby
-Nick Kurshev
-Benjamin Larsson
-LoĂ¯c Le Loarer
-Daniel Maas
-Mike Melanson
-Loren Merritt
-Jeff Muizelaar
-Michael Niedermayer
-François Revol
-Peter Ross
-MĂ¥ns RullgĂ¥rd
-Stefano Sabatini
-Roman Shaposhnik
-Oded Shimon
-Dieter Shirley
-Konstantin Shishkov
-Juan J. Sierralta
-Ewald Snel
-Sascha Sommer
-Leon van Stuivenberg
-Roberto Togni
-Lionel Ulmer
-Reynaldo Verdejo
+To check the log, you can type the command "git log" in the FFmpeg
+source directory, or browse the online repository at
+http://source.ffmpeg.org.
diff --git a/Changelog b/Changelog
index 41fe7c8319..3f47490627 100644
--- a/Changelog
+++ b/Changelog
@@ -2,178 +2,382 @@ Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
version <next>:
-- aliases and defaults for Ogg subtypes (opus, spx)
-- HEVC/H.265 RTP payload format (draft v6) packetizer and depacketizer
-- avplay now exits by default at the end of playback
-- XCB-based screen-grabber
-- creating DASH compatible fragmented MP4, MPEG-DASH segmenting muxer
-- H.261 RTP payload format (RFC 4587) depacketizer and experimental packetizer
+- FFT video filter
+- TDSC decoder
+- DTS lossless extension (XLL) decoding (not lossless, disabled by default)
+- showwavespic filter
+- DTS decoding through libdcadec
+- Drop support for nvenc API before 5.0
+- nvenc H265 encoder
+- Detelecine filter
+- Intel QSV-accelerated H.264 encoding
+- MMAL-accelerated H.264 decoding
+- basic APNG encoder and muxer with default extension "apng"
+- unpack DivX-style packed B-frames in MPEG-4 bitstream filter
+- WebM Live Chunk Muxer
+- nvenc level and tier options
+- chorus filter
+- Canopus HQ/HQA decoder
+- Automatically rotate videos based on metadata in ffmpeg
+- improved Quickdraw compatibility
+- VP9 high bit-depth and extended colorspaces decoding support
+- WebPAnimEncoder API when available for encoding and muxing WebP
+- Direct3D11-accelerated decoding
+
+
+version 2.6:
+- nvenc encoder
+- 10bit spp filter
+- colorlevels filter
+- RIFX format for *.wav files
- RTP/mpegts muxer
-- VP8 in Ogg demuxing
+- non continuous cache protocol support
+- tblend filter
+- cropdetect support for non 8bpp, absolute (if limit >= 1) and relative (if limit < 1.0) threshold
+- Camellia symmetric block cipher
- OpenH264 encoder wrapper
+- VOC seeking support
+- Closed caption Decoder
+- fspp, uspp, pp7 MPlayer postprocessing filters ported to native filters
+- showpalette filter
+- Twofish symmetric block cipher
- Support DNx100 (960x720@8)
-- Direct3D11-accelerated decoding
+- eq2 filter ported from libmpcodecs as eq filter
+- removed libmpcodecs
+- Changed default DNxHD colour range in QuickTime .mov derivatives to mpeg range
+- ported softpulldown filter from libmpcodecs as repeatfields filter
+- dcshift filter
+- RTP depacketizer for loss tolerant payload format for MP3 audio (RFC 5219)
+- RTP depacketizer for AC3 payload format (RFC 4184)
+- palettegen and paletteuse filters
+- VP9 RTP payload format (draft 0) experimental depacketizer
+- RTP depacketizer for DV (RFC 6469)
- DXVA2-accelerated HEVC decoding
- AAC ELD 480 decoding
- Intel QSV-accelerated H.264 decoding
- DSS SP decoder and DSS demuxer
-- RTP depacketizer for AC3 payload format (RFC 4184)
-- RTP depacketizer for loss tolerant payload format for MP3 audio (RFC 5219)
-- RTP depacketizer for DV (RFC 6469)
+- Fix stsd atom corruption in DNxHD QuickTimes
- Canopus HQX decoder
- RTP depacketization of T.140 text (RFC 4103)
-- VP9 RTP payload format (draft 0) experimental depacketizer
-- TDSC decoder
-- DTS lossless extension (XLL) decoding (not lossless, disabled by default)
-- Intel QSV-accelerated H.264 encoding
-- MMAL-accelerated H.264 decoding
-- DTS decoding through libdcadec
-- Canopus HQ/HQA decoder
-- Automatically rotate videos based on metadata in avconv
-- improved Quickdraw compatibility
+- Port MIPS optimizations to 64-bit
-version 11:
-- libx265 encoder
+version 2.5:
+- HEVC/H.265 RTP payload format (draft v6) packetizer
+- SUP/PGS subtitle demuxer
+- ffprobe -show_pixel_formats option
+- CAST128 symmetric block cipher, ECB mode
+- STL subtitle demuxer and decoder
+- libutvideo YUV 4:2:2 10bit support
+- XCB-based screen-grabber
+- UDP-Lite support (RFC 3828)
+- xBR scaling filter
+- AVFoundation screen capturing support
+- ffserver supports codec private options
+- creating DASH compatible fragmented MP4, MPEG-DASH segmenting muxer
+- WebP muxer with animated WebP support
+- zygoaudio decoding support
+- APNG demuxer
+- postproc visualization support
+
+
+version 2.4:
+- Icecast protocol
+- ported lenscorrection filter from frei0r filter
+- large optimizations in dctdnoiz to make it usable
+- ICY metadata are now requested by default with the HTTP protocol
+- support for using metadata in stream specifiers in fftools
+- LZMA compression support in TIFF decoder
+- H.261 RTP payload format (RFC 4587) depacketizer and experimental packetizer
+- HEVC/H.265 RTP payload format (draft v6) depacketizer
+- added codecview filter to visualize information exported by some codecs
+- Matroska 3D support thorugh side data
+- HTML generation using texi2html is deprecated in favor of makeinfo/texi2any
+- silenceremove filter
+
+
+version 2.3:
+- AC3 fixed-point decoding
- shuffleplanes filter
+- subfile protocol
+- Phantom Cine demuxer
- replaygain data export
+- VP7 video decoder
- Alias PIX image encoder and decoder
-- BRender PIX image decoder
-- Amazing Studio PAF playback support
-- XBM decoder
-- BMP standalone parser
-- OpenEXR image decoder
-- support encoding and decoding 4-channel SGI images
+- Improvements to the BRender PIX image decoder
+- Improvements to the XBM decoder
+- QTKit input device
+- improvements to OpenEXR image decoder
- support decoding 16-bit RLE SGI images
-- VP7 video decoder
-- LucasArts SMUSH SANM video decoder
-- LucasArts SMUSH VIMA audio decoder (ADPCM)
-- LucasArts SMUSH demuxer
-- MP2 encoding via TwoLAME
-- asettb filter
-- Silicon Graphics RLE 8-bit video decoder
-- Silicon Graphics Motion Video Compressor 1 & 2 decoder
-- Silicon Graphics Movie demuxer
+- GDI screen grabbing for Windows
+- alternative rendition support for HTTP Live Streaming
+- AVFoundation input device
+- Direct Stream Digital (DSD) decoder
+- Magic Lantern Video (MLV) demuxer
- On2 AVC (Audio for Video) decoder
-- support for decoding through DXVA2 in avconv
+- support for decoding through DXVA2 in ffmpeg
- libbs2b-based stereo-to-binaural audio filter
+- libx264 reference frames count limiting depending on level
- native Opus decoder
- display matrix export and rotation API
-- drop avserver, it was unmaintained for years and largely broken
-- Icecast protocol
-- request Icecast metadata by default
-- support for using metadata in stream specifiers in avtools
-- Matroska 3D support
+- WebVTT encoder
+- showcqt multimedia filter
+- zoompan filter
+- signalstats filter
+- hqx filter (hq2x, hq3x, hq4x)
+- flanger filter
+- Image format auto-detection
+- LRC demuxer and muxer
+- Samba protocol (via libsmbclient)
+- WebM DASH Manifest muxer
+- libfribidi support in drawtext
-version 10:
-- av_strnstr
-- support ID3v2 tags in ASF files
+version 2.2:
+
+- HNM version 4 demuxer and video decoder
+- Live HDS muxer
+- setsar/setdar filters now support variables in ratio expressions
+- elbg filter
+- string validation in ffprobe
+- support for decoding through VDPAU in ffmpeg (the -hwaccel option)
+- complete Voxware MetaSound decoder
+- remove mp3_header_compress bitstream filter
+- Windows resource files for shared libraries
+- aeval filter
+- stereoscopic 3d metadata handling
+- WebP encoding via libwebp
+- ATRAC3+ decoder
+- VP8 in Ogg demuxing
+- side & metadata support in NUT
+- framepack filter
+- XYZ12 rawvideo support in NUT
+- Exif metadata support in WebP decoder
+- OpenGL device
+- Use metadata_header_padding to control padding in ID3 tags (currently used in
+ MP3, AIFF, and OMA files), FLAC header, and the AVI "junk" block.
+- Mirillis FIC video decoder
+- Support DNx444
+- libx265 encoder
+- dejudder filter
+- Autodetect VDA like all other hardware accelerations
+- aliases and defaults for Ogg subtypes (opus, spx)
+
+
+version 2.1:
+
+- aecho filter
+- perspective filter ported from libmpcodecs
+- ffprobe -show_programs option
+- compand filter
+- RTMP seek support
+- when transcoding with ffmpeg (i.e. not streamcopying), -ss is now accurate
+ even when used as an input option. Previous behavior can be restored with
+ the -noaccurate_seek option.
+- ffmpeg -t option can now be used for inputs, to limit the duration of
+ data read from an input file
+- incomplete Voxware MetaSound decoder
+- read EXIF metadata from JPEG
+- DVB teletext decoder
+- phase filter ported from libmpcodecs
+- w3fdif filter
+- Opus support in Matroska
+- FFV1 version 1.3 is stable and no longer experimental
+- FFV1: YUVA(444,422,420) 9, 10 and 16 bit support
+- changed DTS stream id in lavf mpeg ps muxer from 0x8a to 0x88, to be
+ more consistent with other muxers.
+- adelay filter
+- pullup filter ported from libmpcodecs
+- ffprobe -read_intervals option
+- Lossless and alpha support for WebP decoder
+- Error Resilient AAC syntax (ER AAC LC) decoding
+- Low Delay AAC (ER AAC LD) decoding
+- mux chapters in ASF files
+- SFTP protocol (via libssh)
+- libx264: add ability to encode in YUVJ422P and YUVJ444P
+- Fraps: use BT.709 colorspace by default for yuv, as reference fraps decoder does
+- make decoding alpha optional for prores, ffv1 and vp6 by setting
+ the skip_alpha flag.
+- ladspa wrapper filter
+- native VP9 decoder
+- dpx parser
+- max_error_rate parameter in ffmpeg
+- PulseAudio output device
+- ReplayGain scanner
+- Enhanced Low Delay AAC (ER AAC ELD) decoding (no LD SBR support)
+- Linux framebuffer output device
+- HEVC decoder
+- raw HEVC, HEVC in MOV/MP4, HEVC in Matroska, HEVC in MPEG-TS demuxing
+- mergeplanes filter
+
+
+version 2.0:
+
+- curves filter
- reference-counting for AVFrame and AVPacket data
-- avconv now fails when input options are used for output file
+- ffmpeg now fails when input options are used for output file
or vice versa
-- avconv options -filter_script and -filter_complex_script, which allow a
+- support for Monkey's Audio versions from 3.93
+- perms and aperms filters
+- audio filtering support in ffplay
+- 10% faster aac encoding on x86 and MIPS
+- sine audio filter source
+- WebP demuxing and decoding support
+- ffmpeg options -filter_script and -filter_complex_script, which allow a
filtergraph description to be read from a file
+- OpenCL support
+- audio phaser filter
+- separatefields filter
+- libquvi demuxer
- uniform options syntax across all filters
+- telecine filter
- interlace filter
-- JPEG 2000 decoder
-- asetpts filter (same as setpts, but for audio)
+- smptehdbars source
+- inverse telecine filters (fieldmatch and decimate)
+- colorbalance filter
+- colorchannelmixer filter
+- The matroska demuxer can now output proper verbatim ASS packets. It will
+ become the default at the next libavformat major bump.
+- decent native animated GIF encoding
+- asetrate filter
+- interleave filter
+- timeline editing with filters
+- vidstabdetect and vidstabtransform filters for video stabilization using
+ the vid.stab library
+- astats filter
- trim and atrim filters
-- avconv -t and -ss (output-only) options are now sample-accurate when
+- ffmpeg -t and -ss (output-only) options are now sample-accurate when
transcoding audio
- Matroska muxer can now put the index at the beginning of the file.
-- avconv -deinterlace option removed, the yadif filter should be used instead
+- extractplanes filter
+- avectorscope filter
+- ADPCM DTK decoder
+- ADP demuxer
+- RSD demuxer
+- RedSpark demuxer
+- ADPCM IMA Radical decoder
+- zmq filters
+- DCT denoiser filter (dctdnoiz)
+- Wavelet denoiser filter ported from libmpcodecs as owdenoise (formerly "ow")
- Apple Intermediate Codec decoder
- Escape 130 video decoder
+- FTP protocol support
+- V4L2 output device
+- 3D LUT filter (lut3d)
+- SMPTE 302M audio encoder
- support for slice multithreading in libavfilter
+- Hald CLUT support (generation and filtering)
- VC-1 interlaced B-frame support
- support for WavPack muxing (raw and in Matroska)
+- XVideo output device
+- vignette filter
+- True Audio (TTA) encoder
- Go2Webinar decoder
+- mcdeint filter ported from libmpcodecs
+- sab filter ported from libmpcodecs
+- ffprobe -show_chapters option
- WavPack encoding through libwavpack
-- Added the -n parameter to avconv
-- RTMP seek support
-- when transcoding with avconv (i.e. not streamcopying), -ss is now accurate
- even when used as an input option. Previous behavior can be restored with
- the -noaccurate_seek option.
-- avconv -t option can now be used for inputs, to limit the duration of
- data read from an input file
-- Voxware MetaSound decoder
-- WebP decoder
-- Error Resilient AAC syntax (ER AAC LC) decoding
-- Low Delay AAC (ER AAC LD) decoding
-- mux chapters in ASF files
-- Opus in Ogg demuxing
-- Enhanced Low Delay AAC (ER AAC ELD) decoding (no LD SBR support)
-- F4V muxer
-- HNM version 4 demuxer and video decoder
-- HEVC decoder
-- raw HEVC, HEVC in MOV/MP4, HEVC in Matroska, HEVC in MPEG-TS demuxing
-- remove avplay -vismv option, which has not worked for a long time
-- Live HDS muxer
-- setsar/setdar filters now support variables in ratio expressions
-- dar variable in the scale filter now returns the actual DAR (i.e. a * sar)
-- VP9 decoder
-- support for decoding through VDPAU in avconv (the -hwaccel option)
-- remove mp3_header_(de)compress bitstream filters
-- stereoscopic 3d metadata handling
-- png standalone parser
-- WebP encoding via libwebp
-- ATRAC3+ decoder
-- framepack filter
-- Mirillis FIC video decoder
-- Support DNx444
-- compand audio filter
+- rotate filter
+- spp filter ported from libmpcodecs
+- libgme support
+- psnr filter
-version 9:
-- av_basename and av_dirname
-- adobe and limelight publisher authentication in RTMP
+version 1.2:
+
- VDPAU hardware acceleration through normal hwaccel
- SRTP support
-
-
-version 9_beta3:
-- ashowinfo audio filter
+- Error diffusion dither in Swscale
+- Chained Ogg support
+- Theora Midstream reconfiguration support
+- EVRC decoder
+- audio fade filter
+- filtering audio with unknown channel layout
+- allpass, bass, bandpass, bandreject, biquad, equalizer, highpass, lowpass
+ and treble audio filter
+- improved showspectrum filter, with multichannel support and sox-like colors
+- histogram filter
+- tee muxer
+- il filter ported from libmpcodecs
+- support ID3v2 tags in ASF files
+- encrypted TTA stream decoding support
+- RF64 support in WAV muxer
+- noise filter ported from libmpcodecs
+- Subtitles character encoding conversion
+- blend filter
+- stereo3d filter ported from libmpcodecs
+
+
+version 1.1:
+
+- stream disposition information printing in ffprobe
+- filter for loudness analysis following EBU R128
+- Opus encoder using libopus
+- ffprobe -select_streams option
+- Pinnacle TARGA CineWave YUV16 decoder
+- TAK demuxer, decoder and parser
+- DTS-HD demuxer
+- remove -same_quant, it hasn't worked for years
+- FFM2 support
+- X-Face image encoder and decoder
- 24-bit FLAC encoding
-- audio volume filter
-- deprecated the avconv -vol option. the volume filter is to be used instead.
- multi-channel ALAC encoding up to 7.1
-- TAK demuxer, parser, and decoder
-- adaptive frame-level multithreading for H.264
-
-
-version 9_beta2:
- metadata (INFO tag) support in WAV muxer
+- subtitles raw text decoder
- support for building DLLs using MSVC
-- remove avserver daemon mode
+- LVF demuxer
+- ffescape tool
+- metadata (info chunk) support in CAF muxer
+- field filter ported from libmpcodecs
+- AVR demuxer
+- geq filter ported from libmpcodecs
+- remove ffserver daemon mode
+- AST muxer/demuxer
+- new expansion syntax for drawtext
+- BRender PIX image decoder
+- ffprobe -show_entries option
+- ffprobe -sections option
+- ADPCM IMA Dialogic decoder
+- BRSTM demuxer
+- animated GIF decoder and demuxer
+- PVF demuxer
+- subtitles filter
+- IRCAM muxer/demuxer
+- Paris Audio File demuxer
+- Virtual concatenation demuxer
+- VobSub demuxer
+- JSON captions for TED talks decoding support
+- SOX Resampler support in libswresample
+- aselect filter
+- SGI RLE 8-bit / Silicon Graphics RLE 8-bit video decoder
+- Silicon Graphics Motion Video Compressor 1 & 2 decoder
+- Silicon Graphics Movie demuxer
+- apad filter
+- Resolution & pixel format change support with multithreading for H.264
+- documentation split into per-component manuals
+- pp (postproc) filter ported from MPlayer
+- NIST Sphere demuxer
+- MPL2, VPlayer, MPlayer, AQTitle, PJS and SubViewer v1 subtitles demuxers and decoders
+- Sony Wave64 muxer
+- adobe and limelight publisher authentication in RTMP
+- data: URI scheme
- support building on the Plan 9 operating system
-- ffv1: support version 1.3
+- kerndeint filter ported from MPlayer
+- histeq filter ported from VirtualDub
+- Megalux Frame demuxer
+- 012v decoder
+- Improved AVC Intra decoding support
-version 9_beta1:
+version 1.0:
-- XWD encoder and decoder
-- Support for fragmentation in the mov/mp4 muxer
-- ISMV (Smooth Streaming) muxer
-- CDXL demuxer and decoder
-- Apple ProRes encoder
-- Sun Rasterfile Encoder
-- remove libpostproc
-- ID3v2 attached pictures reading and writing
-- WMA Lossless decoder
-- XBM encoder
-- RealAudio Lossless decoder
-- ZeroCodec decoder
-- drop support for avconv without libavfilter
-- add libavresample audio conversion library
-- audio filters support in libavfilter and avconv
-- add fps filter
-- audio split filter
-- audio mix filter
-- avprobe output is now standard INI or JSON. The old format can still
- be used with -of old.
+- INI and flat output in ffprobe
+- Scene detection in libavfilter
- Indeo Audio decoder
- channelsplit audio filter
+- setnsamples audio filter
+- atempo filter
+- ffprobe -show_data option
- RTMPT protocol support
- iLBC encoding/decoding via libilbc
- Microsoft Screen 1 decoder
@@ -186,44 +390,146 @@ version 9_beta1:
- Microsoft Expression Encoder Screen decoder
- RTMPS protocol support
- RTMPTS protocol support
-- JPEG 2000 encoding support through OpenJPEG
-- G.723.1 demuxer and decoder
- RTMPE protocol support
- RTMPTE protocol support
+- showwaves and showspectrum filter
+- LucasArts SMUSH SANM playback support
+- LucasArts SMUSH VIMA audio decoder (ADPCM)
+- LucasArts SMUSH demuxer
+- SAMI, RealText and SubViewer demuxers and decoders
+- Heart Of Darkness PAF playback support
+- iec61883 device
+- asettb filter
+- new option: -progress
+- 3GPP Timed Text encoder/decoder
+- GeoTIFF decoder support
+- ffmpeg -(no)stdin option
+- Opus decoder using libopus
+- caca output device using libcaca
+- alphaextract and alphamerge filters
+- concat filter
+- flite filter
- Canopus Lossless Codec decoder
-- avconv -shortest option is now per-output file,
+- bitmap subtitles in filters (experimental and temporary)
+- MP2 encoding via TwoLAME
+- bmp parser
+- smptebars source
+- asetpts filter
+- hue filter
+- ICO muxer
+- SubRip encoder and decoder without embedded timing
+- edge detection filter
+- framestep filter
+- ffmpeg -shortest option is now per-output file
-pass and -passlogfile are now per-output stream
+- volume measurement filter
- Ut Video encoder
- Microsoft Screen 2 decoder
+- smartblur filter ported from MPlayer
+- CPiA decoder
+- decimate filter ported from MPlayer
- RTP depacketization of JPEG
- Smooth Streaming live segmenter muxer
+- F4V muxer
+- sendcmd and asendcmd filters
+- WebVTT demuxer and decoder (simple tags supported)
- RTP packetization of JPEG
-- Opus decoder and encoder using libopus
-- remove -same_quant, it hasn't worked for years
+- faststart option in the MOV/MP4 muxer
- support for building with MSVC
-version 0.8:
+version 0.11:
-- GSM audio parser
-- SMJPEG muxer
+- Fixes: CVE-2012-2772, CVE-2012-2774, CVE-2012-2775, CVE-2012-2776, CVE-2012-2777,
+ CVE-2012-2779, CVE-2012-2782, CVE-2012-2783, CVE-2012-2784, CVE-2012-2785,
+ CVE-2012-2786, CVE-2012-2787, CVE-2012-2788, CVE-2012-2789, CVE-2012-2790,
+ CVE-2012-2791, CVE-2012-2792, CVE-2012-2793, CVE-2012-2794, CVE-2012-2795,
+ CVE-2012-2796, CVE-2012-2797, CVE-2012-2798, CVE-2012-2799, CVE-2012-2800,
+ CVE-2012-2801, CVE-2012-2802, CVE-2012-2803, CVE-2012-2804,
+- v408 Quicktime and Microsoft AYUV Uncompressed 4:4:4:4 encoder and decoder
+- setfield filter
+- CDXL demuxer and decoder
+- Apple ProRes encoder
+- ffprobe -count_packets and -count_frames options
+- Sun Rasterfile Encoder
+- ID3v2 attached pictures reading and writing
+- WMA Lossless decoder
+- bluray protocol
+- blackdetect filter
+- libutvideo encoder wrapper (--enable-libutvideo)
+- swapuv filter
+- bbox filter
+- XBM encoder and decoder
+- RealAudio Lossless decoder
+- ZeroCodec decoder
+- tile video filter
+- Metal Gear Solid: The Twin Snakes demuxer
+- OpenEXR image decoder
+- removelogo filter
+- drop support for ffmpeg without libavfilter
+- drawtext video filter: fontconfig support
+- ffmpeg -benchmark_all option
+- super2xsai filter ported from libmpcodecs
+- add libavresample audio conversion library for compatibility
+- MicroDVD decoder
+- Avid Meridien (AVUI) encoder and decoder
+- accept + prefix to -pix_fmt option to disable automatic conversions.
+- complete audio filtering in libavfilter and ffmpeg
+- add fps filter
+- vorbis parser
+- png parser
+- audio mix filter
+- ffv1: support (draft) version 1.3
-version 0.8_beta2:
+version 0.10:
+- Fixes: CVE-2011-3929, CVE-2011-3934, CVE-2011-3935, CVE-2011-3936,
+ CVE-2011-3937, CVE-2011-3940, CVE-2011-3941, CVE-2011-3944,
+ CVE-2011-3945, CVE-2011-3946, CVE-2011-3947, CVE-2011-3949,
+ CVE-2011-3950, CVE-2011-3951, CVE-2011-3952
+- v410 Quicktime Uncompressed 4:4:4 10-bit encoder and decoder
+- SBaGen (SBG) binaural beats script demuxer
+- OpenMG Audio muxer
+- Timecode extraction in DV and MOV
+- thumbnail video filter
+- XML output in ffprobe
+- asplit audio filter
+- tinterlace video filter
+- astreamsync audio filter
+- amerge audio filter
+- ISMV (Smooth Streaming) muxer
+- GSM audio parser
+- SMJPEG muxer
+- XWD encoder and decoder
- Automatic thread count based on detection number of (available) CPU cores
-- Deprecate libpostproc. If desired, the switch --enable-postproc will
- enable it but it may be removed in a later Libav release.
+- y41p Brooktree Uncompressed 4:1:1 12-bit encoder and decoder
+- ffprobe -show_error option
+- Avid 1:1 10-bit RGB Packer codec
+- v308 Quicktime Uncompressed 4:4:4 encoder and decoder
+- yuv4 libquicktime packed 4:2:0 encoder and decoder
+- ffprobe -show_frames option
+- silencedetect audio filter
+- ffprobe -show_program_version, -show_library_versions, -show_versions options
- rv34: frame-level multi-threading
- optimized iMDCT transform on x86 using SSE for for mpegaudiodec
+- Improved PGS subtitle decoder
+- dumpgraph option to lavfi device
+- r210 and r10k encoders
+- ffwavesynth decoder
+- aviocat tool
+- ffeval tool
+- support encoding and decoding 4-channel SGI images
-version 0.8_beta1:
+version 0.9:
+- openal input device added
+- boxblur filter added
- BWF muxer
- Flash Screen Video 2 decoder
-- ffplay/ffprobe/ffserver renamed to avplay/avprobe/avserver
-- ffmpeg deprecated, added avconv, which is almost the same for now, except
+- lavfi input device added
+- added avconv, which is almost the same for now, except
for a few incompatible changes in the options, which will hopefully make them
easier to use. The changes are:
* The options placement is now strictly enforced! While in theory the
@@ -293,23 +599,40 @@ easier to use. The changes are:
* -vframes/-aframes/-dframes options are now aliases to the new -frames option.
* -vtag/-atag/-stag options are now aliases to the new -tag option.
- XMV demuxer
+- LOAS demuxer
+- ashowinfo filter added
- Windows Media Image decoder
+- amovie source added
- LATM muxer/demuxer
-- showinfo filter
-- split filter
+- Speex encoder via libspeex
+- JSON output in ffprobe
+- WTV muxer
+- Optional C++ Support (needed for libstagefright)
+- H.264 Decoding on Android via Stagefright
+- Prores decoder
+- BIN/XBIN/ADF/IDF text file decoder
+- aconvert audio filter added
+- audio support to lavfi input device added
- libcdio-paranoia input device for audio CD grabbing
-- select filter
- Apple ProRes decoder
- CELT in Ogg demuxing
+- G.723.1 demuxer and decoder
+- libmodplug support (--enable-libmodplug)
- VC-1 interlaced decoding
-- lut, lutrgb, and lutyuv filters
-- boxblur filter
+- libutvideo wrapper (--enable-libutvideo)
+- aevalsrc audio source added
- Ut Video decoder
- Speex encoding via libspeex
- 4:2:2 H.264 decoding support
- 4:2:2 and 4:4:4 H.264 encoding with libx264
- Pulseaudio input device
+- Prores encoder
+- Video Decoder Acceleration (VDA) HWAccel module.
- replacement Indeo 3 decoder
+- new ffmpeg option: -map_channel
+- volume audio filter added
+- earwax audio filter added
+- libv4l2 support (--enable-libv4l2)
- TLS/SSL and HTTPS protocol support
- AVOptions API rewritten and documented
- most of CODEC_FLAG2_*, some CODEC_FLAG_* and many codec-specific fields in
@@ -319,44 +642,27 @@ easier to use. The changes are:
- Discworld II BMV decoding support
- VBLE Decoder
- OS X Video Decoder Acceleration (VDA) support
+- compact and csv output in ffprobe
+- pan audio filter
+- IFF Amiga Continuous Bitmap (ACBM) decoder
+- ass filter
- CRI ADX audio format muxer and demuxer
- Playstation Portable PMP format demuxer
+- Microsoft Windows ICO demuxer
+- life source
- PCM format support in OMA demuxer
- CLJR encoder
+- new option: -report
- Dxtory capture format decoder
-- v410 QuickTime uncompressed 4:4:4 10-bit encoder and decoder
-- OpenMG Audio muxer
+- cellauto source
- Simple segmenting muxer
- Indeo 4 decoder
- SMJPEG demuxer
-version 0.7:
-
-- E-AC-3 audio encoder
-- ac3enc: add channel coupling support
-- floating-point sample format support for (E-)AC-3, DCA, AAC, Vorbis decoders
-- H.264/MPEG frame-level multithreading
-- av_metadata_* functions renamed to av_dict_* and moved to libavutil
-- 4:4:4 H.264 decoding support
-- 10-bit H.264 optimizations for x86
-- bump libswscale for recently reported ABI break
-
-
-version 0.7_beta2:
-
-- VP8 frame-level multithreading
-- NEON optimizations for VP8
-- removed a lot of deprecated API cruft
-- FFT and IMDCT optimizations for AVX (Sandy Bridge) processors
-- DPX image encoder
-- SMPTE 302M AES3 audio decoder
-- ffmpeg no longer quits after the 'q' key is pressed; use 'ctrl+c' instead
-- 9bit and 10bit per sample support in the H.264 decoder
-
-
-version 0.7_beta1:
+version 0.8:
+- many many things we forgot because we rather write code than changelogs
- WebM support in Matroska de/muxer
- low overhead Ogg muxing
- MMS-TCP support
@@ -364,6 +670,7 @@ version 0.7_beta1:
- Demuxer for On2's IVF format
- Pictor/PC Paint decoder
- HE-AAC v2 decoder
+- HE-AAC v2 encoding with libaacplus
- libfaad2 wrapper removed
- DTS-ES extension (XCh) decoding support
- native VP8 decoder
@@ -375,6 +682,7 @@ version 0.7_beta1:
- RTP depacketization of QDM2
- ANSI/ASCII art playback system
- Lego Mindstorms RSO de/muxer
+- libavcore added (and subsequently removed)
- SubRip subtitle file muxer and demuxer
- Chinese AVS encoding via libxavs
- ffprobe -show_packets option added
@@ -421,7 +729,7 @@ version 0.7_beta1:
- replace the ocv_smooth filter with a more generic ocv filter
- Windows Televison (WTV) demuxer
- FFmpeg metadata format muxer and demuxer
-- SubRip (srt) subtitle decoder
+- SubRip (srt) subtitle encoder and decoder
- floating-point AC-3 encoder added
- Lagarith decoder
- ffmpeg -copytb option added
@@ -434,11 +742,46 @@ version 0.7_beta1:
- sndio support for playback and record
- Linux framebuffer input device added
- Chronomaster DFA decoder
-- Mobotix MxPEG decoder
+- DPX image encoder
+- MicroDVD subtitle file muxer and demuxer
+- Playstation Portable PMP format demuxer
+- fieldorder video filter added
- AAC encoding via libvo-aacenc
- AMR-WB encoding via libvo-amrwbenc
- xWMA demuxer
-- fieldorder video filter added
+- Mobotix MxPEG decoder
+- VP8 frame-multithreading
+- NEON optimizations for VP8
+- Lots of deprecated API cruft removed
+- fft and imdct optimizations for AVX (Sandy Bridge) processors
+- showinfo filter added
+- SMPTE 302M AES3 audio decoder
+- Apple Core Audio Format muxer
+- 9bit and 10bit per sample support in the H.264 decoder
+- 9bit and 10bit FFV1 encoding / decoding
+- split filter added
+- select filter added
+- sdl output device added
+- libmpcodecs video filter support (3 times as many filters than before)
+- mpeg2 aspect ratio dection fixed
+- libxvid aspect pickiness fixed
+- Frame multithreaded decoding
+- E-AC-3 audio encoder
+- ac3enc: add channel coupling support
+- floating-point sample format support to the ac3, eac3, dca, aac, and vorbis decoders.
+- H264/MPEG frame-level multi-threading
+- All av_metadata_* functions renamed to av_dict_* and moved to libavutil
+- 4:4:4 H.264 decoding support
+- 10-bit H.264 optimizations for x86
+- lut, lutrgb, and lutyuv filters added
+- buffersink libavfilter sink added
+- Bump libswscale for recently reported ABI break
+- New J2K encoder (via OpenJPEG)
+
+
+version 0.7:
+
+- all the changes for 0.8, but keeping API/ABI compatibility with the 0.6 release
version 0.6:
@@ -679,6 +1022,7 @@ version 0.5:
- Gopher client support
- MXF D-10 muxer
- generic metadata API
+- flash ScreenVideo2 encoder
version 0.4.9-pre1:
@@ -881,7 +1225,7 @@ version 0.4.5:
- MPEG-4 vol header fixes (Jonathan Marsden <snmjbm at pacbell.net>)
- ARM optimizations (Lionel Ulmer <lionel.ulmer at free.fr>).
- Windows porting of file converter
-- added MJPEG raw format (input/ouput)
+- added MJPEG raw format (input/output)
- added JPEG image format support (input/output)
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index ac5dc5dbb6..0000000000
--- a/INSTALL
+++ /dev/null
@@ -1,18 +0,0 @@
-
-1) Type './configure' to create the configuration. A list of configure
-options is printed by running 'configure --help'.
-
-'configure' can be launched from a directory different from the Libav
-sources to build the objects out of tree. To do this, use an absolute
-path when launching 'configure', e.g. '/libavdir/libav/configure'.
-
-2) Then type 'make' to build Libav. GNU Make 3.81 or later is required.
-
-3) Type 'make install' to install all binaries and libraries you built.
-
-NOTICE
-
- - Non system dependencies (e.g. libx264, libvpx) are disabled by default.
-
- - The default cflags include -g, if you want lean libraries you can either
- pass --disable-debug or strip the debug symbols at a later time.
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000000..5db912231c
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,17 @@
+#Installing FFmpeg:
+
+1. Type `./configure` to create the configuration. A list of configure
+options is printed by running `configure --help`.
+
+ `configure` can be launched from a directory different from the FFmpeg
+sources to build the objects out of tree. To do this, use an absolute
+path when launching `configure`, e.g. `/ffmpegdir/ffmpeg/configure`.
+
+2. Then type `make` to build FFmpeg. GNU Make 3.81 or later is required.
+
+3. Type `make install` to install all binaries and libraries you built.
+
+NOTICE
+------
+
+ - Non system dependencies (e.g. libx264, libvpx) are disabled by default.
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 701e6e1d6c..0000000000
--- a/LICENSE
+++ /dev/null
@@ -1,66 +0,0 @@
-Libav:
-======
-
-Most files in Libav are under the GNU Lesser General Public License version 2.1
-or later (LGPL v2.1+). Read the file COPYING.LGPLv2.1 for details. Some other
-files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to
-Libav.
-
-Some optional parts of Libav are licensed under the GNU General Public License
-version 2 or later (GPL v2+). See the file COPYING.GPLv2 for details. None of
-these parts are used by default, you have to explicitly pass --enable-gpl to
-configure to activate them. In this case, Libav's license changes to GPL v2+.
-
-Specifically, the GPL parts of Libav are
-
-- the X11 grabber in libavdevice/x11grab.c
-- the texi2pod.pl tool
-- the following filters in libavfilter:
- - vf_blackframe.c
- - vf_boxblur.c
- - vf_cropdetect.c
- - vf_delogo.c
- - vf_hqdn3d.c
- - vf_interlace.c
-
-Should you, for whatever reason, prefer to use version 3 of the (L)GPL, then
-the configure parameter --enable-version3 will activate this licensing option
-for you. Read the file COPYING.LGPLv3 or, if you have enabled GPL parts,
-COPYING.GPLv3 to learn the exact legal terms that apply in this case.
-
-There are a handful of files under other licensing terms, namely:
-
-* The files libavcodec/jfdctfst.c, libavcodec/jfdctint_template.c and
- libavcodec/jrevdct.c are taken from libjpeg, see the top of the files for
- licensing details. Specifically note that you must credit the IJG in the
- documentation accompanying your program if you only distribute executables.
- You must also indicate any changes including additions and deletions to
- those three files in the documentation.
-
-
-external libraries
-==================
-
-Libav can be combined with a number of external libraries, which sometimes
-affect the licensing of binaries resulting from the combination.
-
-compatible libraries
---------------------
-
-The libcdio, libx264, libx265, libxavs and libxvid libraries are under GPL. When
-combining them with Libav, Libav needs to be licensed as GPL as well by
-passing --enable-gpl to configure.
-
-The OpenCORE and VisualOn libraries are under the Apache License 2.0. That
-license is incompatible with the LGPL v2.1 and the GPL v2, but not with
-version 3 of those licenses. So to combine these libraries with Libav, the
-license version needs to be upgraded by passing --enable-version3 to configure.
-
-incompatible libraries
-----------------------
-
-The Fraunhofer AAC library, FAAC and OpenSSL are under licenses incompatible
-with all (L)GPL versions. Thus, unfortunately, since both licenses cannot be
-satisfied simultaneously, binaries resulting from the combination of Libav
-with these libraries are nonfree und unredistributable. If you wish to enable
-any of these libraries nonetheless, pass --enable-nonfree to configure.
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000000..545d3668af
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,112 @@
+#FFmpeg:
+
+Most files in FFmpeg are under the GNU Lesser General Public License version 2.1
+or later (LGPL v2.1+). Read the file `COPYING.LGPLv2.1` for details. Some other
+files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to
+FFmpeg.
+
+Some optional parts of FFmpeg are licensed under the GNU General Public License
+version 2 or later (GPL v2+). See the file `COPYING.GPLv2` for details. None of
+these parts are used by default, you have to explicitly pass `--enable-gpl` to
+configure to activate them. In this case, FFmpeg's license changes to GPL v2+.
+
+Specifically, the GPL parts of FFmpeg are:
+
+- libpostproc
+- optional x86 optimizations in the files
+ - `libavcodec/x86/flac_dsp_gpl.asm`
+ - `libavcodec/x86/idct_mmx.c`
+- libutvideo encoding/decoding wrappers in
+ `libavcodec/libutvideo*.cpp`
+- the X11 grabber in `libavdevice/x11grab.c`
+- the swresample test app in
+ `libswresample/swresample-test.c`
+- the `texi2pod.pl` tool
+- the following filters in libavfilter:
+ - `f_ebur128.c`
+ - `vf_blackframe.c`
+ - `vf_boxblur.c`
+ - `vf_colormatrix.c`
+ - `vf_cover_rect.c`
+ - `vf_cropdetect.c`
+ - `vf_delogo.c`
+ - `vf_eq.c`
+ - `vf_find_rect.c`
+ - `vf_fspp.c`
+ - `vf_geq.c`
+ - `vf_histeq.c`
+ - `vf_hqdn3d.c`
+ - `vf_interlace.c`
+ - `vf_kerndeint.c`
+ - `vf_mcdeint.c`
+ - `vf_mpdecimate.c`
+ - `vf_owdenoise.c`
+ - `vf_perspective.c`
+ - `vf_phase.c`
+ - `vf_pp.c`
+ - `vf_pp7.c`
+ - `vf_pullup.c`
+ - `vf_sab.c`
+ - `vf_smartblur.c`
+ - `vf_repeatfields.c`
+ - `vf_spp.c`
+ - `vf_stereo3d.c`
+ - `vf_super2xsai.c`
+ - `vf_tinterlace.c`
+ - `vf_uspp.c`
+ - `vsrc_mptestsrc.c`
+
+Should you, for whatever reason, prefer to use version 3 of the (L)GPL, then
+the configure parameter `--enable-version3` will activate this licensing option
+for you. Read the file `COPYING.LGPLv3` or, if you have enabled GPL parts,
+`COPYING.GPLv3` to learn the exact legal terms that apply in this case.
+
+There are a handful of files under other licensing terms, namely:
+
+* The files `libavcodec/jfdctfst.c`, `libavcodec/jfdctint_template.c` and
+ `libavcodec/jrevdct.c` are taken from libjpeg, see the top of the files for
+ licensing details. Specifically note that you must credit the IJG in the
+ documentation accompanying your program if you only distribute executables.
+ You must also indicate any changes including additions and deletions to
+ those three files in the documentation.
+* `tests/reference.pnm` is under the expat license.
+
+
+external libraries
+==================
+
+FFmpeg can be combined with a number of external libraries, which sometimes
+affect the licensing of binaries resulting from the combination.
+
+compatible libraries
+--------------------
+
+The following libraries are under GPL:
+- frei0r
+- libcdio
+- libutvideo
+- libvidstab
+- libx264
+- libx265
+- libxavs
+- libxvid
+
+When combining them with FFmpeg, FFmpeg needs to be licensed as GPL as well by
+passing `--enable-gpl` to configure.
+
+The OpenCORE and VisualOn libraries are under the Apache License 2.0. That
+license is incompatible with the LGPL v2.1 and the GPL v2, but not with
+version 3 of those licenses. So to combine these libraries with FFmpeg, the
+license version needs to be upgraded by passing `--enable-version3` to configure.
+
+incompatible libraries
+----------------------
+
+The Fraunhofer AAC library, FAAC and aacplus are under licenses which
+are incompatible with the GPLv2 and v3. We do not know for certain if their
+licenses are compatible with the LGPL.
+If you wish to enable these libraries, pass `--enable-nonfree` to configure.
+But note that if you enable any of these libraries the resulting binary will
+be under a complex license mix that is more restrictive than the LGPL and that
+may result in additional obligations. It is possible that these
+restrictions cause the resulting binary to be unredistributeable.
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644
index 0000000000..598c0b30a6
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,592 @@
+FFmpeg maintainers
+==================
+
+Below is a list of the people maintaining different parts of the
+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.
+A (CC <address>) after the name means that the maintainer prefers to be CC-ed on
+patches and related discussions.
+
+
+Project Leader
+==============
+
+Michael Niedermayer
+ final design decisions
+
+
+Applications
+============
+
+ffmpeg:
+ ffmpeg.c Michael Niedermayer
+
+ffplay:
+ ffplay.c Marton Balint
+
+ffprobe:
+ ffprobe.c Stefano Sabatini
+
+ffserver:
+ ffserver.c Reynaldo H. Verdejo Pinochet
+
+Commandline utility code:
+ cmdutils.c, cmdutils.h Michael Niedermayer
+
+QuickTime faststart:
+ tools/qt-faststart.c Baptiste Coudurier
+
+
+Miscellaneous Areas
+===================
+
+documentation Stefano Sabatini, Mike Melanson, Timothy Gu
+build system (configure, makefiles) Diego Biurrun, Mans Rullgard
+project server ĂrpĂ¡d Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Lou Logan
+presets Robert Swain
+metadata subsystem Aurelien Jacobs
+release management Michael Niedermayer
+
+
+Communication
+=============
+
+website Deby Barbara Lepage
+fate.ffmpeg.org Timothy Gu
+Trac bug tracker Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos, Lou Logan
+mailing lists Michael Niedermayer, Baptiste Coudurier, Lou Logan
+Google+ Paul B Mahol, Michael Niedermayer, Alexander Strasser
+Twitter Lou Logan, Reynaldo H. Verdejo Pinochet
+Launchpad Timothy Gu
+
+
+libavutil
+=========
+
+External Interfaces:
+ libavutil/avutil.h Michael Niedermayer
+Internal Interfaces:
+ libavutil/common.h Michael Niedermayer
+
+Other:
+ bprint Nicolas George
+ bswap.h
+ des Reimar Doeffinger
+ dynarray.h Nicolas George
+ eval.c, eval.h Michael Niedermayer
+ float_dsp Loren Merritt
+ hash Reimar Doeffinger
+ intfloat* Michael Niedermayer
+ integer.c, integer.h Michael Niedermayer
+ lzo Reimar Doeffinger
+ mathematics.c, mathematics.h Michael Niedermayer
+ mem.c, mem.h Michael Niedermayer
+ opencl.c, opencl.h Wei Gao
+ opt.c, opt.h Michael Niedermayer
+ rational.c, rational.h Michael Niedermayer
+ rc4 Reimar Doeffinger
+ ripemd.c, ripemd.h James Almer
+ timecode ClĂ©ment BÅ“sch
+
+
+libavcodec
+==========
+
+Generic Parts:
+ External Interfaces:
+ avcodec.h Michael Niedermayer
+ utility code:
+ utils.c Michael Niedermayer
+ audio and video frame extraction:
+ parser.c Michael Niedermayer
+ bitstream reading:
+ bitstream.c, bitstream.h Michael Niedermayer
+ CABAC:
+ cabac.h, cabac.c Michael Niedermayer
+ codec names:
+ codec_names.sh Nicolas George
+ DSP utilities:
+ dsputils.c, dsputils.h Michael Niedermayer
+ entropy coding:
+ rangecoder.c, rangecoder.h Michael Niedermayer
+ lzw.* Michael Niedermayer
+ floating point AAN DCT:
+ faandct.c, faandct.h Michael Niedermayer
+ Golomb coding:
+ golomb.c, golomb.h Michael Niedermayer
+ LPC:
+ lpc.c, lpc.h Justin Ruggles
+ motion estimation:
+ motion* Michael Niedermayer
+ rate control:
+ ratecontrol.c Michael Niedermayer
+ libxvid_rc.c Michael Niedermayer
+ simple IDCT:
+ simple_idct.c, simple_idct.h Michael Niedermayer
+ postprocessing:
+ libpostproc/* Michael Niedermayer
+ table generation:
+ tableprint.c, tableprint.h Reimar Doeffinger
+ fixed point FFT:
+ fft* Zeljko Lukac
+ Text Subtitles ClĂ©ment BÅ“sch
+
+Codecs:
+ 4xm.c Michael Niedermayer
+ 8bps.c Roberto Togni
+ 8svx.c Jaikrishnan Menon
+ aasc.c Kostya Shishkov
+ ac3* Justin Ruggles
+ alacenc.c Jaikrishnan Menon
+ alsdec.c Thilo Borgmann
+ apedec.c Kostya Shishkov
+ ass* Aurelien Jacobs
+ asv* Michael Niedermayer
+ atrac3* Benjamin Larsson
+ atrac3plus* Maxim Poliakovski
+ bgmc.c, bgmc.h Thilo Borgmann
+ bink.c Kostya Shishkov
+ binkaudio.c Peter Ross
+ bmp.c Mans Rullgard, Kostya Shishkov
+ cavs* Stefan Gehrer
+ cdxl.c Paul B Mahol
+ celp_filters.* Vitor Sessak
+ cinepak.c Roberto Togni
+ cinepakenc.c Rl / Aetey G.T. AB
+ ccaption_dec.c Anshul Maheshwari
+ cljr Alex Beregszaszi
+ cllc.c Derek Buitenhuis
+ cook.c, cookdata.h Benjamin Larsson
+ cpia.c Stephan Hilb
+ crystalhd.c Philip Langdale
+ cscd.c Reimar Doeffinger
+ dca.c Kostya Shishkov, Benjamin Larsson
+ dnxhd* Baptiste Coudurier
+ dpcm.c Mike Melanson
+ dss_sp.c Oleksij Rempel, Michael Niedermayer
+ dv.c Roman Shaposhnik
+ dvbsubdec.c Anshul Maheshwari
+ dxa.c Kostya Shishkov
+ eacmv*, eaidct*, eat* Peter Ross
+ exif.c, exif.h Thilo Borgmann
+ ffv1* Michael Niedermayer
+ ffwavesynth.c Nicolas George
+ fic.c Derek Buitenhuis
+ flac* Justin Ruggles
+ flashsv* Benjamin Larsson
+ flicvideo.c Mike Melanson
+ g722.c Martin Storsjo
+ g726.c Roman Shaposhnik
+ gifdec.c Baptiste Coudurier
+ h261* Michael Niedermayer
+ h263* Michael Niedermayer
+ h264* Loren Merritt, Michael Niedermayer
+ huffyuv* Michael Niedermayer, Christophe Gisquet
+ idcinvideo.c Mike Melanson
+ imc* Benjamin Larsson
+ indeo2* Kostya Shishkov
+ indeo5* Kostya Shishkov
+ interplayvideo.c Mike Melanson
+ ivi* Kostya Shishkov
+ jacosub* ClĂ©ment BÅ“sch
+ jpeg2000* Nicolas Bertrand
+ jpeg_ls.c Kostya Shishkov
+ jvdec.c Peter Ross
+ kmvc.c Kostya Shishkov
+ lcl*.c Roberto Togni, Reimar Doeffinger
+ libcelt_dec.c Nicolas George
+ libdirac* David Conrad
+ libgsm.c Michel Bardiaux
+ libopenjpeg.c Jaikrishnan Menon
+ libopenjpegenc.c Michael Bradshaw
+ libschroedinger* David Conrad
+ libspeexdec.c Justin Ruggles
+ libtheoraenc.c David Conrad
+ libutvideo* Derek Buitenhuis
+ libvorbis.c David Conrad
+ libvpx* James Zern
+ libx264.c Mans Rullgard, Jason Garrett-Glaser
+ libx265.c Derek Buitenhuis
+ libxavs.c Stefan Gehrer
+ libzvbi-teletextdec.c Marton Balint
+ loco.c Kostya Shishkov
+ lzo.h, lzo.c Reimar Doeffinger
+ mdec.c Michael Niedermayer
+ mimic.c Ramiro Polla
+ mjpeg*.c Michael Niedermayer
+ mlp* Ramiro Polla
+ mmvideo.c Peter Ross
+ mpc* Kostya Shishkov
+ mpeg12.c, mpeg12data.h Michael Niedermayer
+ mpegvideo.c, mpegvideo.h Michael Niedermayer
+ mqc* Nicolas Bertrand
+ msmpeg4.c, msmpeg4data.h Michael Niedermayer
+ msrle.c Mike Melanson
+ msvideo1.c Mike Melanson
+ nellymoserdec.c Benjamin Larsson
+ nuv.c Reimar Doeffinger
+ nvenc.c Timo Rothenpieler
+ paf.* Paul B Mahol
+ pcx.c Ivo van Poorten
+ pgssubdec.c Reimar Doeffinger
+ ptx.c Ivo van Poorten
+ qcelp* Reynaldo H. Verdejo Pinochet
+ qdm2.c, qdm2data.h Roberto Togni, Benjamin Larsson
+ qdrw.c Kostya Shishkov
+ qpeg.c Kostya Shishkov
+ qtrle.c Mike Melanson
+ ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni
+ resample2.c Michael Niedermayer
+ rl2.c Sascha Sommer
+ rpza.c Roberto Togni
+ rtjpeg.c, rtjpeg.h Reimar Doeffinger
+ rv10.c Michael Niedermayer
+ rv3* Kostya Shishkov
+ rv4* Kostya Shishkov, Christophe Gisquet
+ s3tc* Ivo van Poorten
+ smacker.c Kostya Shishkov
+ smc.c Mike Melanson
+ smvjpegdec.c Ash Hughes
+ snow* Michael Niedermayer, Loren Merritt
+ sonic.c Alex Beregszaszi
+ srt* Aurelien Jacobs
+ sunrast.c Ivo van Poorten
+ svq3.c Michael Niedermayer
+ tak* Paul B Mahol
+ targa.c Kostya Shishkov
+ tiff.c Kostya Shishkov
+ truemotion1* Mike Melanson
+ truemotion2* Kostya Shishkov
+ truespeech.c Kostya Shishkov
+ tscc.c Kostya Shishkov
+ tta.c Alex Beregszaszi, Jaikrishnan Menon
+ ttaenc.c Paul B Mahol
+ txd.c Ivo van Poorten
+ ulti* Kostya Shishkov
+ v410*.c Derek Buitenhuis
+ vb.c Kostya Shishkov
+ vble.c Derek Buitenhuis
+ vc1* Kostya Shishkov, Christophe Gisquet
+ vcr1.c Michael Niedermayer
+ vda_h264_dec.c Xidorn Quan
+ vima.c Paul B Mahol
+ vmnc.c Kostya Shishkov
+ vorbisdec.c Denes Balatoni, David Conrad
+ vorbisenc.c Oded Shimon
+ vp3* Mike Melanson
+ vp5 Aurelien Jacobs
+ vp6 Aurelien Jacobs
+ vp8 David Conrad, Jason Garrett-Glaser, Ronald Bultje
+ vp9 Ronald Bultje, ClĂ©ment BÅ“sch
+ vqavideo.c Mike Melanson
+ wavpack.c Kostya Shishkov
+ wmaprodec.c Sascha Sommer
+ wmavoice.c Ronald S. Bultje
+ wmv2.c Michael Niedermayer
+ wnv1.c Kostya Shishkov
+ xan.c Mike Melanson
+ xbm* Paul B Mahol
+ xface Stefano Sabatini
+ xl.c Kostya Shishkov
+ xvmc.c Ivan Kalvachev
+ xwd* Paul B Mahol
+ zerocodec.c Derek Buitenhuis
+ zmbv* Kostya Shishkov
+
+Hardware acceleration:
+ crystalhd.c Philip Langdale
+ dxva2* Laurent Aimar
+ libstagefright.cpp Mohamed Naufal
+ vaapi* Gwenole Beauchesne
+ vda* Sebastien Zwickert
+ vdpau* Carl Eugen Hoyos
+
+
+libavdevice
+===========
+ External Interface:
+ libavdevice/avdevice.h
+
+
+ avfoundation.m Thilo Borgmann
+ decklink* Deti Fliegl
+ dshow.c Roger Pack (CC rogerdpack@gmail.com)
+ fbdev_enc.c Lukasz Marek
+ gdigrab.c Roger Pack (CC rogerdpack@gmail.com)
+ iec61883.c Georg Lippitsch
+ lavfi Stefano Sabatini
+ libdc1394.c Roman Shaposhnik
+ opengl_enc.c Lukasz Marek
+ pulse_audio_enc.c Lukasz Marek
+ qtkit.m Thilo Borgmann
+ sdl Stefano Sabatini
+ v4l2.c Giorgio Vazzana
+ vfwcap.c Ramiro Polla
+ xv.c Lukasz Marek
+
+libavfilter
+===========
+
+Generic parts:
+ graphdump.c Nicolas George
+
+Filters:
+ af_adelay.c Paul B Mahol
+ af_aecho.c Paul B Mahol
+ af_afade.c Paul B Mahol
+ af_amerge.c Nicolas George
+ af_aphaser.c Paul B Mahol
+ af_aresample.c Michael Niedermayer
+ af_astats.c Paul B Mahol
+ af_astreamsync.c Nicolas George
+ af_atempo.c Pavel Koshevoy
+ af_biquads.c Paul B Mahol
+ af_compand.c Paul B Mahol
+ af_ladspa.c Paul B Mahol
+ af_pan.c Nicolas George
+ af_silenceremove.c Paul B Mahol
+ avf_avectorscope.c Paul B Mahol
+ avf_showcqt.c Muhammad Faiz
+ vf_blend.c Paul B Mahol
+ vf_colorbalance.c Paul B Mahol
+ vf_dejudder.c Nicholas Robbins
+ vf_delogo.c Jean Delvare (CC <khali@linux-fr.org>)
+ vf_drawbox.c/drawgrid Andrey Utkin
+ vf_extractplanes.c Paul B Mahol
+ vf_histogram.c Paul B Mahol
+ vf_hqx.c ClĂ©ment BÅ“sch
+ vf_idet.c Pascal Massimino
+ vf_il.c Paul B Mahol
+ vf_lenscorrection.c Daniel Oberhoff
+ vf_mergeplanes.c Paul B Mahol
+ vf_psnr.c Paul B Mahol
+ vf_scale.c Michael Niedermayer
+ vf_separatefields.c Paul B Mahol
+ vf_stereo3d.c Paul B Mahol
+ vf_telecine.c Paul B Mahol
+ vf_yadif.c Michael Niedermayer
+
+Sources:
+ vsrc_mandelbrot.c Michael Niedermayer
+
+libavformat
+===========
+
+Generic parts:
+ External Interface:
+ libavformat/avformat.h Michael Niedermayer
+ Utility Code:
+ libavformat/utils.c Michael Niedermayer
+
+
+Muxers/Demuxers:
+ 4xm.c Mike Melanson
+ adtsenc.c Robert Swain
+ afc.c Paul B Mahol
+ aiffdec.c Baptiste Coudurier, Matthieu Bouron
+ aiffenc.c Baptiste Coudurier, Matthieu Bouron
+ ape.c Kostya Shishkov
+ apngdec.c Benoit Fouet
+ ass* Aurelien Jacobs
+ astdec.c Paul B Mahol
+ astenc.c James Almer
+ avi* Michael Niedermayer
+ avisynth.c AvxSynth Team (avxsynth.testing at gmail dot com)
+ avr.c Paul B Mahol
+ bink.c Peter Ross
+ brstm.c Paul B Mahol
+ caf* Peter Ross
+ cdxl.c Paul B Mahol
+ crc.c Michael Niedermayer
+ daud.c Reimar Doeffinger
+ dss.c Oleksij Rempel, Michael Niedermayer
+ dtshddec.c Paul B Mahol
+ dv.c Roman Shaposhnik
+ dxa.c Kostya Shishkov
+ electronicarts.c Peter Ross
+ epafdec.c Paul B Mahol
+ ffm* Baptiste Coudurier
+ flac* Justin Ruggles
+ flic.c Mike Melanson
+ flvdec.c, flvenc.c Michael Niedermayer
+ gxf.c Reimar Doeffinger
+ gxfenc.c Baptiste Coudurier
+ hls.c Anssi Hannula
+ idcin.c Mike Melanson
+ idroqdec.c Mike Melanson
+ iff.c Jaikrishnan Menon
+ img2*.c Michael Niedermayer
+ ipmovie.c Mike Melanson
+ ircam* Paul B Mahol
+ iss.c Stefan Gehrer
+ jacosub* ClĂ©ment BÅ“sch
+ jvdec.c Peter Ross
+ libmodplug.c ClĂ©ment BÅ“sch
+ libnut.c Oded Shimon
+ lmlm4.c Ivo van Poorten
+ lvfdec.c Paul B Mahol
+ lxfdec.c Tomas Härdin
+ matroska.c Aurelien Jacobs
+ matroskadec.c Aurelien Jacobs
+ matroskaenc.c David Conrad
+ matroska subtitles (matroskaenc.c) John Peebles
+ metadata* Aurelien Jacobs
+ mgsts.c Paul B Mahol
+ microdvd* Aurelien Jacobs
+ mm.c Peter Ross
+ mov.c Michael Niedermayer, Baptiste Coudurier
+ movenc.c Baptiste Coudurier, Matthieu Bouron
+ mpc.c Kostya Shishkov
+ mpeg.c Michael Niedermayer
+ mpegenc.c Michael Niedermayer
+ mpegts.c Marton Balint
+ mpegtsenc.c Baptiste Coudurier
+ msnwc_tcp.c Ramiro Polla
+ mtv.c Reynaldo H. Verdejo Pinochet
+ mxf* Baptiste Coudurier
+ mxfdec.c Tomas Härdin
+ nistspheredec.c Paul B Mahol
+ nsvdec.c Francois Revol
+ nut* Michael Niedermayer
+ nuv.c Reimar Doeffinger
+ oggdec.c, oggdec.h David Conrad
+ oggenc.c Baptiste Coudurier
+ oggparse*.c David Conrad
+ oma.c Maxim Poliakovski
+ paf.c Paul B Mahol
+ psxstr.c Mike Melanson
+ pva.c Ivo van Poorten
+ pvfdec.c Paul B Mahol
+ r3d.c Baptiste Coudurier
+ raw.c Michael Niedermayer
+ rdt.c Ronald S. Bultje
+ rl2.c Sascha Sommer
+ rmdec.c, rmenc.c Ronald S. Bultje, Kostya Shishkov
+ rtmp* Kostya Shishkov
+ rtp.c, rtpenc.c Martin Storsjo
+ rtpdec_ac3.* Gilles Chanteperdrix
+ rtpdec_dv.* Thomas Volkert
+ rtpdec_h261.*, rtpenc_h261.* Thomas Volkert
+ rtpdec_hevc.*, rtpenc_hevc.* Thomas Volkert
+ rtpdec_mpa_robust.* Gilles Chanteperdrix
+ rtpdec_asf.* Ronald S. Bultje
+ rtpdec_vp9.c Thomas Volkert
+ rtpenc_mpv.*, rtpenc_aac.* Martin Storsjo
+ rtsp.c Luca Barbato
+ sbgdec.c Nicolas George
+ sdp.c Martin Storsjo
+ segafilm.c Mike Melanson
+ segment.c Stefano Sabatini
+ siff.c Kostya Shishkov
+ smacker.c Kostya Shishkov
+ smjpeg* Paul B Mahol
+ spdif* Anssi Hannula
+ srtdec.c Aurelien Jacobs
+ swf.c Baptiste Coudurier
+ takdec.c Paul B Mahol
+ tta.c Alex Beregszaszi
+ txd.c Ivo van Poorten
+ voc.c Aurelien Jacobs
+ wav.c Michael Niedermayer
+ wc3movie.c Mike Melanson
+ webm dash (matroskaenc.c) Vignesh Venkatasubramanian
+ webvtt* Matthew J Heaney
+ westwood.c Mike Melanson
+ wtv.c Peter Ross
+ wv.c Kostya Shishkov
+ wvenc.c Paul B Mahol
+
+Protocols:
+ bluray.c Petri Hintukainen
+ ftp.c Lukasz Marek
+ http.c Ronald S. Bultje
+ libssh.c Lukasz Marek
+ mms*.c Ronald S. Bultje
+ udp.c Luca Abeni
+ icecast.c Marvin Scholz
+
+
+libswresample
+=============
+
+Generic parts:
+ audioconvert.c Michael Niedermayer
+ dither.c Michael Niedermayer
+ rematrix*.c Michael Niedermayer
+ swresample*.c Michael Niedermayer
+
+Resamplers:
+ resample*.c Michael Niedermayer
+ soxr_resample.c Rob Sykes
+
+
+Operating systems / CPU architectures
+=====================================
+
+Alpha Mans Rullgard, Falk Hueffner
+ARM Mans Rullgard
+AVR32 Mans Rullgard
+MIPS Mans Rullgard, Nedeljko Babic
+Mac OS X / PowerPC Romain Dolbeau, Guillaume Poirier
+Amiga / PowerPC Colin Ward
+Linux / PowerPC Luca Barbato
+Windows MinGW Alex Beregszaszi, Ramiro Polla
+Windows Cygwin Victor Paesa
+Windows MSVC Matthew Oliver
+Windows ICL Matthew Oliver
+ADI/Blackfin DSP Marc Hoffman
+Sparc Roman Shaposhnik
+x86 Michael Niedermayer
+
+
+Releases
+========
+
+2.6 Michael Niedermayer
+2.5 Michael Niedermayer
+2.4 Michael Niedermayer
+2.2 Michael Niedermayer
+
+If you want to maintain an older release, please contact us
+
+
+GnuPG Fingerprints of maintainers and contributors
+==================================================
+
+Alexander Strasser 1C96 78B7 83CB 8AA7 9AF5 D1EB A7D8 A57B A876 E58F
+Anssi Hannula 1A92 FF42 2DD9 8D2E 8AF7 65A9 4278 C520 513D F3CB
+Anton Khirnov 6D0C 6625 56F8 65D1 E5F5 814B B50A 1241 C067 07AB
+Ash Hughes 694D 43D2 D180 C7C7 6421 ABD3 A641 D0B7 623D 6029
+Attila Kinali 11F0 F9A6 A1D2 11F6 C745 D10C 6520 BCDD F2DF E765
+Baptiste Coudurier 8D77 134D 20CC 9220 201F C5DB 0AC9 325C 5C1A BAAA
+Ben Littler 3EE3 3723 E560 3214 A8CD 4DEB 2CDB FCE7 768C 8D2C
+Benoit Fouet B22A 4F4F 43EF 636B BB66 FCDC 0023 AE1E 2985 49C8
+ClĂ©ment BÅ“sch 52D0 3A82 D445 F194 DB8B 2B16 87EE 2CB8 F4B8 FCF9
+Daniel Verkamp 78A6 07ED 782C 653E C628 B8B9 F0EB 8DD8 2F0E 21C7
+Diego Biurrun 8227 1E31 B6D9 4994 7427 E220 9CAE D6CC 4757 FCC5
+FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8
+Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4
+Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368
+Jean Delvare 7CA6 9F44 60F1 BDC4 1FD2 C858 A552 6B9B B3CD 4E6A
+Justin Ruggles 3136 ECC0 C10D 6C04 5F43 CA29 FCBE CD2A 3787 1EBF
+Loren Merritt ABD9 08F4 C920 3F65 D8BE 35D7 1540 DAA7 060F 56DE
+Lou Logan 7D68 DC73 CBEF EABB 671A B6CF 621C 2E28 82F8 DC3A
+Luca Barbato 6677 4209 213C 8843 5B67 29E7 E84C 78C2 84E9 0E34
+Michael Niedermayer 9FF2 128B 147E F673 0BAD F133 611E C787 040B 0FAB
+Nicolas George 24CE 01CE 9ACC 5CEB 74D8 8D9D B063 D997 36E5 4C93
+Panagiotis Issaris 6571 13A3 33D9 3726 F728 AA98 F643 B12E ECF3 E029
+Peter Ross A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B
+Reimar Doeffinger C61D 16E5 9E2C D10C 8958 38A4 0899 A2B9 06D4 D9C7
+Reinhard Tartler 9300 5DC2 7E87 6C37 ED7B CA9A 9808 3544 9453 48A4
+Reynaldo H. Verdejo Pinochet 6E27 CD34 170C C78E 4D4F 5F40 C18E 077F 3114 452A
+Robert Swain EE7A 56EA 4A81 A7B5 2001 A521 67FA 362D A2FC 3E71
+Sascha Sommer 38A0 F88B 868E 9D3A 97D4 D6A0 E823 706F 1E07 0D3C
+Stefano Sabatini 0D0B AD6B 5330 BBAD D3D6 6A0C 719C 2839 FC43 2D5F
+Stephan Hilb 4F38 0B3A 5F39 B99B F505 E562 8D5C 5554 4E17 8863
+Tiancheng "Timothy" Gu 9456 AFC0 814A 8139 E994 8351 7FE6 B095 B582 B0D4
+Tim Nicholson 38CF DB09 3ED0 F607 8B67 6CED 0C0B FC44 8B0B FC83
+Tomas Härdin A79D 4E3D F38F 763F 91F5 8B33 A01E 8AE0 41BB 2551
+Wei Gao 4269 7741 857A 0E60 9EC5 08D2 4744 4EFA 62C1 87B9
diff --git a/Makefile b/Makefile
index cc016b3cd1..fd59628a42 100644
--- a/Makefile
+++ b/Makefile
@@ -1,85 +1,42 @@
+MAIN_MAKEFILE=1
include config.mak
vpath %.c $(SRC_PATH)
+vpath %.cpp $(SRC_PATH)
vpath %.h $(SRC_PATH)
+vpath %.m $(SRC_PATH)
vpath %.S $(SRC_PATH)
vpath %.asm $(SRC_PATH)
+vpath %.rc $(SRC_PATH)
vpath %.v $(SRC_PATH)
vpath %.texi $(SRC_PATH)
+vpath %/fate_config.sh.template $(SRC_PATH)
-ifndef V
-Q = @
-ECHO = printf "$(1)\t%s\n" $(2)
-BRIEF = CC HOSTCC HOSTLD AS YASM AR LD
-SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM STRIP
-MSG = $@
-M = @$(call ECHO,$(TAG),$@);
-$(foreach VAR,$(BRIEF), \
- $(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
-$(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
-$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_PATH)/%=%)); $(INSTALL))
-endif
-
-ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil swscale
-
-IFLAGS := -I. -I$(SRC_PATH)
-CPPFLAGS := $(IFLAGS) $(CPPFLAGS)
-CFLAGS += $(ECFLAGS)
-CCFLAGS = $(CPPFLAGS) $(CFLAGS)
-ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
-YASMFLAGS += $(IFLAGS:%=%/) -Pconfig.asm
-HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
-LDFLAGS := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)
-
-define COMPILE
- $(call $(1)DEP,$(1))
- $($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
-endef
-
-COMPILE_C = $(call COMPILE,CC)
-COMPILE_S = $(call COMPILE,AS)
-COMPILE_HOSTC = $(call COMPILE,HOSTCC)
-
-%.o: %.c
- $(COMPILE_C)
-
-%.o: %.S
- $(COMPILE_S)
+AVPROGS-$(CONFIG_FFMPEG) += ffmpeg
+AVPROGS-$(CONFIG_FFPLAY) += ffplay
+AVPROGS-$(CONFIG_FFPROBE) += ffprobe
+AVPROGS-$(CONFIG_FFSERVER) += ffserver
-%_host.o: %.c
- $(COMPILE_HOSTC)
-
-%.i: %.c
- $(CC) $(CCFLAGS) $(CC_E) $<
-
-%.h.c:
- $(Q)echo '#include "$*.h"' >$@
-
-%.ver: %.v
- $(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ > $@
-
-%.c %.h: TAG = GEN
-
-AVPROGS-$(CONFIG_AVCONV) += avconv
-AVPROGS-$(CONFIG_AVPLAY) += avplay
-AVPROGS-$(CONFIG_AVPROBE) += avprobe
-
-AVPROGS := $(AVPROGS-yes:%=%$(EXESUF))
+AVPROGS := $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF))
+INSTPROGS = $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF))
PROGS += $(AVPROGS)
-AVBASENAMES = avconv avplay avprobe
-ALLAVPROGS = $(AVBASENAMES:%=%$(EXESUF))
+AVBASENAMES = ffmpeg ffplay ffprobe ffserver
+ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
+ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
$(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog) += cmdutils.o))
+$(foreach prog,$(AVBASENAMES),$(eval OBJS-$(prog)-$(CONFIG_OPENCL) += cmdutils_opencl.o))
-OBJS-avconv += avconv_opt.o avconv_filter.o
-OBJS-avconv-$(HAVE_VDPAU_X11) += avconv_vdpau.o
-OBJS-avconv-$(HAVE_DXVA2_LIB) += avconv_dxva2.o
-OBJS-avconv-$(CONFIG_VDA) += avconv_vda.o
+OBJS-ffmpeg += ffmpeg_opt.o ffmpeg_filter.o
+OBJS-ffmpeg-$(HAVE_VDPAU_X11) += ffmpeg_vdpau.o
+OBJS-ffmpeg-$(HAVE_DXVA2_LIB) += ffmpeg_dxva2.o
+OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_vda.o
+OBJS-ffserver += ffserver_config.o
-TESTTOOLS = audiogen videogen rotozoom tiny_psnr base64
+TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options
-TOOLS = qt-faststart trasher
+TOOLS = qt-faststart trasher uncoded_frame
TOOLS-$(CONFIG_ZLIB) += cws2fws
# $(FFLIBS-yes) needs to be in linking order
@@ -88,11 +45,14 @@ FFLIBS-$(CONFIG_AVFILTER) += avfilter
FFLIBS-$(CONFIG_AVFORMAT) += avformat
FFLIBS-$(CONFIG_AVCODEC) += avcodec
FFLIBS-$(CONFIG_AVRESAMPLE) += avresample
+FFLIBS-$(CONFIG_POSTPROC) += postproc
+FFLIBS-$(CONFIG_SWRESAMPLE) += swresample
FFLIBS-$(CONFIG_SWSCALE) += swscale
FFLIBS := avutil
-DATA_FILES := $(wildcard $(SRC_PATH)/presets/*.avpreset)
+DATA_FILES := $(wildcard $(SRC_PATH)/presets/*.ffpreset) $(SRC_PATH)/doc/ffprobe.xsd
+EXAMPLES_FILES := $(wildcard $(SRC_PATH)/doc/examples/*.c) $(SRC_PATH)/doc/examples/Makefile $(SRC_PATH)/doc/examples/README
SKIPHEADERS = cmdutils_common_opts.h compat/w32pthreads.h
@@ -107,6 +67,8 @@ $(TOOLS): %$(EXESUF): %.o $(EXEOBJS)
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS)
tools/cws2fws$(EXESUF): ELIBS = $(ZLIB)
+tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS)
+tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS)
config.h: .config
.config: $(wildcard $(FFLIBS:%=$(SRC_PATH)/lib%/all*.c))
@@ -118,7 +80,8 @@ SUBDIR_VARS := CLEANFILES EXAMPLES FFLIBS HOSTPROGS TESTPROGS TOOLS \
HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \
ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \
ALTIVEC-OBJS MMX-OBJS YASM-OBJS \
- OBJS HOSTOBJS TESTOBJS
+ MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSPR1-OBJS MSA-OBJS \
+ LOONGSON3-OBJS OBJS SLIBOBJS HOSTOBJS TESTOBJS
define RESET
$(1) :=
@@ -140,16 +103,22 @@ include $(SRC_PATH)/doc/Makefile
define DOPROG
OBJS-$(1) += $(1).o $(EXEOBJS) $(OBJS-$(1)-yes)
-$(1)$(EXESUF): $$(OBJS-$(1))
+$(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1))
$$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1))
-$(1)$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
-$(1)$(EXESUF): FF_EXTRALIBS += $(LIBS-$(1))
+$(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
+$(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(LIBS-$(1))
-include $$(OBJS-$(1):.o=.d)
endef
-$(foreach P,$(PROGS),$(eval $(call DOPROG,$(P:$(EXESUF)=))))
+$(foreach P,$(PROGS),$(eval $(call DOPROG,$(P:$(PROGSSUF)$(EXESUF)=))))
+
+ffprobe.o cmdutils.o libavcodec/utils.o libavformat/utils.o libavdevice/avdevice.o libavfilter/avfilter.o libavutil/utils.o libpostproc/postprocess.o libswresample/swresample.o libswscale/utils.o : libavutil/ffversion.h
+
+$(PROGS): %$(PROGSSUF)$(EXESUF): %$(PROGSSUF)_g$(EXESUF)
+ $(CP) $< $@
+ $(STRIP) $@
-$(PROGS): %$(EXESUF): %.o $(FF_DEP_LIBS)
+%$(PROGSSUF)_g$(EXESUF): %.o $(FF_DEP_LIBS)
$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS)
OBJDIRS += tools
@@ -162,8 +131,8 @@ GIT_LOG = $(SRC_PATH)/.git/logs/HEAD
.version: $(wildcard $(GIT_LOG)) $(VERSION_SH) config.mak
.version: M=@
-version.h .version:
- $(M)$(VERSION_SH) $(SRC_PATH) version.h $(EXTRA_VERSION)
+libavutil/ffversion.h .version:
+ $(M)$(VERSION_SH) $(SRC_PATH) libavutil/ffversion.h $(EXTRA_VERSION)
$(Q)touch .version
# force version.sh to run whenever version might have changed
@@ -182,11 +151,12 @@ install-progs-$(CONFIG_SHARED): install-libs
install-progs: install-progs-yes $(AVPROGS)
$(Q)mkdir -p "$(BINDIR)"
- $(INSTALL) -c -m 755 $(AVPROGS) "$(BINDIR)"
+ $(INSTALL) -c -m 755 $(INSTPROGS) "$(BINDIR)"
-install-data: $(DATA_FILES)
- $(Q)mkdir -p "$(DATADIR)"
+install-data: $(DATA_FILES) $(EXAMPLES_FILES)
+ $(Q)mkdir -p "$(DATADIR)/examples"
$(INSTALL) -m 644 $(DATA_FILES) "$(DATADIR)"
+ $(INSTALL) -m 644 $(EXAMPLES_FILES) "$(DATADIR)/examples"
uninstall: uninstall-libs uninstall-headers uninstall-progs uninstall-data
@@ -197,19 +167,20 @@ uninstall-data:
$(RM) -r "$(DATADIR)"
clean::
- $(RM) $(ALLAVPROGS)
+ $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G)
$(RM) $(CLEANSUFFIXES)
$(RM) $(CLEANSUFFIXES:%=tools/%)
+ $(RM) -r coverage-html
$(RM) -rf coverage.info lcov
distclean::
$(RM) $(DISTCLEANSUFFIXES)
- $(RM) config.* .config libavutil/avconfig.h .version version.h
+ $(RM) config.* .config libavutil/avconfig.h .version version.h libavutil/ffversion.h libavcodec/codec_names.h
config:
- $(SRC_PATH)/configure $(value LIBAV_CONFIGURATION)
+ $(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION)
-check: all alltools checkheaders examples testprogs fate
+check: all alltools examples testprogs fate
include $(SRC_PATH)/tests/Makefile
@@ -224,5 +195,5 @@ $(sort $(OBJDIRS)):
# so this saves some time on slow systems.
.SUFFIXES:
-.PHONY: all all-yes alltools check *clean config examples install*
+.PHONY: all all-yes alltools check *clean config install*
.PHONY: testprogs uninstall*
diff --git a/README b/README
deleted file mode 120000
index 42061c01a1..0000000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-README.md \ No newline at end of file
diff --git a/README.md b/README.md
index 2dc668a24d..58e1eff03c 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-Libav
-=====
+FFmpeg README
+=============
-Libav is a collection of libraries and tools to process multimedia content
+FFmpeg is a collection of libraries and tools to process multimedia content
such as audio, video, subtitles and related metadata.
## Libraries
@@ -11,30 +11,32 @@ such as audio, video, subtitles and related metadata.
* `libavutil` includes hashers, decompressors and miscellaneous utility functions.
* `libavfilter` provides a mean to alter decoded Audio and Video through chain of filters.
* `libavdevice` provides an abstraction to access capture and playback devices.
-* `libavresample` implements audio mixing and resampling routines.
+* `libswresample` implements audio mixing and resampling routines.
* `libswscale` implements color conversion and scaling routines.
## Tools
-* [avconv](http://libav.org/avconv.html) is a command line toolbox to
+* [ffmpeg](http://ffmpeg.org/ffmpeg.html) is a command line toolbox to
manipulate, convert and stream multimedia content.
-* [avplay](http://libav.org/avplay.html) is a minimalistic multimedia player.
-* [avprobe](http://libav.org/avprobe.html) is a simple analisys tool to inspect
+* [ffplay](http://ffmpeg.org/ffplay.html) is a minimalistic multimedia player.
+* [ffprobe](http://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect
multimedia content.
+* [ffserver](http://ffmpeg.org/ffserver.html) is a multimedia streaming server
+ for live broadcasts.
* Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`.
## Documentation
The offline documentation is available in the **doc/** directory.
-The online documentation is available in the main [website](http://libav.org)
-and in the [wiki](http://wiki.libav.org).
+The online documentation is available in the main [website](http://ffmpeg.org)
+and in the [wiki](http://trac.ffmpeg.org).
### Examples
-Conding examples are available in the **doc/example** directory.
+Coding examples are available in the **doc/examples** directory.
## License
-Libav codebase is mainly LGPL-licensed with optional components licensed under
+FFmpeg codebase is mainly LGPL-licensed with optional components licensed under
GPL. Please refer to the LICENSE file for detailed information.
diff --git a/RELEASE b/RELEASE
index e41f5e748e..3359b98d07 100644
--- a/RELEASE
+++ b/RELEASE
@@ -1 +1 @@
-12_dev0
+2.6.git
diff --git a/arch.mak b/arch.mak
index 4bfc883ffa..bda3ae10ac 100644
--- a/arch.mak
+++ b/arch.mak
@@ -4,6 +4,12 @@ OBJS-$(HAVE_ARMV8) += $(ARMV8-OBJS) $(ARMV8-OBJS-yes)
OBJS-$(HAVE_VFP) += $(VFP-OBJS) $(VFP-OBJS-yes)
OBJS-$(HAVE_NEON) += $(NEON-OBJS) $(NEON-OBJS-yes)
+OBJS-$(HAVE_MIPSFPU) += $(MIPSFPU-OBJS) $(MIPSFPU-OBJS-yes)
+OBJS-$(HAVE_MIPSDSPR1) += $(MIPSDSPR1-OBJS) $(MIPSDSPR1-OBJS-yes)
+OBJS-$(HAVE_MIPSDSPR2) += $(MIPSDSPR2-OBJS) $(MIPSDSPR2-OBJS-yes)
+OBJS-$(HAVE_MSA) += $(MSA-OBJS) $(MSA-OBJS-yes)
+OBJS-$(HAVE_LOONGSON3) += $(LOONGSON3-OBJS) $(LOONGSON3-OBJS-yes)
+
OBJS-$(HAVE_ALTIVEC) += $(ALTIVEC-OBJS) $(ALTIVEC-OBJS-yes)
OBJS-$(HAVE_MMX) += $(MMX-OBJS) $(MMX-OBJS-yes)
diff --git a/avconv.c b/avconv.c
deleted file mode 100644
index 275c3eb268..0000000000
--- a/avconv.c
+++ /dev/null
@@ -1,2695 +0,0 @@
-/*
- * avconv main
- * Copyright (c) 2000-2011 The libav developers.
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#include <ctype.h>
-#include <string.h>
-#include <math.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <signal.h>
-#include <limits.h>
-#include <stdint.h>
-
-#include "libavformat/avformat.h"
-#include "libavdevice/avdevice.h"
-#include "libswscale/swscale.h"
-#include "libavresample/avresample.h"
-#include "libavutil/opt.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/samplefmt.h"
-#include "libavutil/fifo.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/dict.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/avstring.h"
-#include "libavutil/libm.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/time.h"
-#include "libavformat/os_support.h"
-
-# include "libavfilter/avfilter.h"
-# include "libavfilter/buffersrc.h"
-# include "libavfilter/buffersink.h"
-
-#if HAVE_SYS_RESOURCE_H
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-#elif HAVE_GETPROCESSTIMES
-#include <windows.h>
-#endif
-#if HAVE_GETPROCESSMEMORYINFO
-#include <windows.h>
-#include <psapi.h>
-#endif
-
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#if HAVE_PTHREADS
-#include <pthread.h>
-#endif
-
-#include <time.h>
-
-#include "avconv.h"
-#include "cmdutils.h"
-
-#include "libavutil/avassert.h"
-
-const char program_name[] = "avconv";
-const int program_birth_year = 2000;
-
-static FILE *vstats_file;
-
-static int nb_frames_drop = 0;
-
-
-
-#if HAVE_PTHREADS
-/* signal to input threads that they should exit; set by the main thread */
-static int transcoding_finished;
-#endif
-
-#define DEFAULT_PASS_LOGFILENAME_PREFIX "av2pass"
-
-InputStream **input_streams = NULL;
-int nb_input_streams = 0;
-InputFile **input_files = NULL;
-int nb_input_files = 0;
-
-OutputStream **output_streams = NULL;
-int nb_output_streams = 0;
-OutputFile **output_files = NULL;
-int nb_output_files = 0;
-
-FilterGraph **filtergraphs;
-int nb_filtergraphs;
-
-static void term_exit(void)
-{
- av_log(NULL, AV_LOG_QUIET, "");
-}
-
-static volatile int received_sigterm = 0;
-static volatile int received_nb_signals = 0;
-
-static void
-sigterm_handler(int sig)
-{
- received_sigterm = sig;
- received_nb_signals++;
- term_exit();
-}
-
-static void term_init(void)
-{
- signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
- signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
-#ifdef SIGXCPU
- signal(SIGXCPU, sigterm_handler);
-#endif
-}
-
-static int decode_interrupt_cb(void *ctx)
-{
- return received_nb_signals > 1;
-}
-
-const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
-
-static void avconv_cleanup(int ret)
-{
- int i, j;
-
- for (i = 0; i < nb_filtergraphs; i++) {
- FilterGraph *fg = filtergraphs[i];
- avfilter_graph_free(&fg->graph);
- for (j = 0; j < fg->nb_inputs; j++) {
- av_freep(&fg->inputs[j]->name);
- av_freep(&fg->inputs[j]);
- }
- av_freep(&fg->inputs);
- for (j = 0; j < fg->nb_outputs; j++) {
- av_freep(&fg->outputs[j]->name);
- av_freep(&fg->outputs[j]);
- }
- av_freep(&fg->outputs);
- av_freep(&fg->graph_desc);
-
- av_freep(&filtergraphs[i]);
- }
- av_freep(&filtergraphs);
-
- /* close files */
- for (i = 0; i < nb_output_files; i++) {
- OutputFile *of = output_files[i];
- AVFormatContext *s = of->ctx;
- if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE) && s->pb)
- avio_close(s->pb);
- avformat_free_context(s);
- av_dict_free(&of->opts);
-
- av_freep(&output_files[i]);
- }
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
- while (bsfc) {
- AVBitStreamFilterContext *next = bsfc->next;
- av_bitstream_filter_close(bsfc);
- bsfc = next;
- }
- ost->bitstream_filters = NULL;
- av_frame_free(&ost->filtered_frame);
-
- av_parser_close(ost->parser);
-
- av_freep(&ost->forced_keyframes);
- av_freep(&ost->avfilter);
- av_freep(&ost->logfile_prefix);
-
- avcodec_free_context(&ost->enc_ctx);
-
- av_freep(&output_streams[i]);
- }
- for (i = 0; i < nb_input_files; i++) {
- avformat_close_input(&input_files[i]->ctx);
- av_freep(&input_files[i]);
- }
- for (i = 0; i < nb_input_streams; i++) {
- InputStream *ist = input_streams[i];
-
- av_frame_free(&ist->decoded_frame);
- av_frame_free(&ist->filter_frame);
- av_dict_free(&ist->decoder_opts);
- av_freep(&ist->filters);
- av_freep(&ist->hwaccel_device);
-
- avcodec_free_context(&ist->dec_ctx);
-
- av_freep(&input_streams[i]);
- }
-
- if (vstats_file)
- fclose(vstats_file);
- av_free(vstats_filename);
-
- av_freep(&input_streams);
- av_freep(&input_files);
- av_freep(&output_streams);
- av_freep(&output_files);
-
- uninit_opts();
-
- avformat_network_deinit();
-
- if (received_sigterm) {
- av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
- (int) received_sigterm);
- exit (255);
- }
-}
-
-void assert_avoptions(AVDictionary *m)
-{
- 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);
- exit_program(1);
- }
-}
-
-static void abort_codec_experimental(AVCodec *c, int encoder)
-{
- const char *codec_string = encoder ? "encoder" : "decoder";
- AVCodec *codec;
- av_log(NULL, AV_LOG_FATAL, "%s '%s' is experimental and might produce bad "
- "results.\nAdd '-strict experimental' if you want to use it.\n",
- codec_string, c->name);
- codec = encoder ? avcodec_find_encoder(c->id) : avcodec_find_decoder(c->id);
- if (!(codec->capabilities & CODEC_CAP_EXPERIMENTAL))
- av_log(NULL, AV_LOG_FATAL, "Or use the non experimental %s '%s'.\n",
- codec_string, codec->name);
- exit_program(1);
-}
-
-/*
- * Update the requested input sample format based on the output sample format.
- * This is currently only used to request float output from decoders which
- * support multiple sample formats, one of which is AV_SAMPLE_FMT_FLT.
- * Ideally this will be removed in the future when decoders do not do format
- * conversion and only output in their native format.
- */
-static void update_sample_fmt(AVCodecContext *dec, AVCodec *dec_codec,
- AVCodecContext *enc)
-{
- /* if sample formats match or a decoder sample format has already been
- requested, just return */
- if (enc->sample_fmt == dec->sample_fmt ||
- dec->request_sample_fmt > AV_SAMPLE_FMT_NONE)
- return;
-
- /* if decoder supports more than one output format */
- if (dec_codec && dec_codec->sample_fmts &&
- dec_codec->sample_fmts[0] != AV_SAMPLE_FMT_NONE &&
- dec_codec->sample_fmts[1] != AV_SAMPLE_FMT_NONE) {
- const enum AVSampleFormat *p;
- int min_dec = INT_MAX, min_inc = INT_MAX;
- enum AVSampleFormat dec_fmt = AV_SAMPLE_FMT_NONE;
- enum AVSampleFormat inc_fmt = AV_SAMPLE_FMT_NONE;
-
- /* find a matching sample format in the encoder */
- for (p = dec_codec->sample_fmts; *p != AV_SAMPLE_FMT_NONE; p++) {
- if (*p == enc->sample_fmt) {
- dec->request_sample_fmt = *p;
- return;
- } else {
- enum AVSampleFormat dfmt = av_get_packed_sample_fmt(*p);
- enum AVSampleFormat efmt = av_get_packed_sample_fmt(enc->sample_fmt);
- int fmt_diff = 32 * abs(dfmt - efmt);
- if (av_sample_fmt_is_planar(*p) !=
- av_sample_fmt_is_planar(enc->sample_fmt))
- fmt_diff++;
- if (dfmt == efmt) {
- min_inc = fmt_diff;
- inc_fmt = *p;
- } else if (dfmt > efmt) {
- if (fmt_diff < min_inc) {
- min_inc = fmt_diff;
- inc_fmt = *p;
- }
- } else {
- if (fmt_diff < min_dec) {
- min_dec = fmt_diff;
- dec_fmt = *p;
- }
- }
- }
- }
-
- /* if none match, provide the one that matches quality closest */
- dec->request_sample_fmt = min_inc != INT_MAX ? inc_fmt : dec_fmt;
- }
-}
-
-static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
-{
- AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
- AVCodecContext *avctx = ost->encoding_needed ? ost->enc_ctx : ost->st->codec;
- int ret;
-
- /*
- * Audio encoders may split the packets -- #frames in != #packets out.
- * But there is no reordering, so we can limit the number of output packets
- * by simply dropping them here.
- * Counting encoded video frames needs to be done separately because of
- * reordering, see do_video_out()
- */
- if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
- if (ost->frame_number >= ost->max_frames) {
- av_free_packet(pkt);
- return;
- }
- ost->frame_number++;
- }
-
- while (bsfc) {
- AVPacket new_pkt = *pkt;
- int a = av_bitstream_filter_filter(bsfc, avctx, NULL,
- &new_pkt.data, &new_pkt.size,
- pkt->data, pkt->size,
- pkt->flags & AV_PKT_FLAG_KEY);
- if (a > 0) {
- av_free_packet(pkt);
- new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
- av_buffer_default_free, NULL, 0);
- if (!new_pkt.buf)
- exit_program(1);
- } else if (a < 0) {
- av_log(NULL, AV_LOG_ERROR, "%s failed for stream %d, codec %s",
- bsfc->filter->name, pkt->stream_index,
- avctx->codec ? avctx->codec->name : "copy");
- print_error("", a);
- if (exit_on_error)
- exit_program(1);
- }
- *pkt = new_pkt;
-
- bsfc = bsfc->next;
- }
-
- if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS) &&
- ost->last_mux_dts != AV_NOPTS_VALUE &&
- pkt->dts < ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT)) {
- av_log(NULL, AV_LOG_WARNING, "Non-monotonous DTS in output stream "
- "%d:%d; previous: %"PRId64", current: %"PRId64"; ",
- ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);
- if (exit_on_error) {
- av_log(NULL, AV_LOG_FATAL, "aborting.\n");
- exit_program(1);
- }
- av_log(NULL, AV_LOG_WARNING, "changing to %"PRId64". This may result "
- "in incorrect timestamps in the output file.\n",
- ost->last_mux_dts + 1);
- pkt->dts = ost->last_mux_dts + 1;
- if (pkt->pts != AV_NOPTS_VALUE)
- pkt->pts = FFMAX(pkt->pts, pkt->dts);
- }
- ost->last_mux_dts = pkt->dts;
-
- ost->data_size += pkt->size;
- ost->packets_written++;
-
- pkt->stream_index = ost->index;
- ret = av_interleaved_write_frame(s, pkt);
- if (ret < 0) {
- print_error("av_interleaved_write_frame()", ret);
- exit_program(1);
- }
-}
-
-static int check_recording_time(OutputStream *ost)
-{
- OutputFile *of = output_files[ost->file_index];
-
- if (of->recording_time != INT64_MAX &&
- av_compare_ts(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, of->recording_time,
- AV_TIME_BASE_Q) >= 0) {
- ost->finished = 1;
- return 0;
- }
- return 1;
-}
-
-static void do_audio_out(AVFormatContext *s, OutputStream *ost,
- AVFrame *frame)
-{
- AVCodecContext *enc = ost->enc_ctx;
- AVPacket pkt;
- int got_packet = 0;
-
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
-
- if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0)
- frame->pts = ost->sync_opts;
- ost->sync_opts = frame->pts + frame->nb_samples;
-
- ost->samples_encoded += frame->nb_samples;
- ost->frames_encoded++;
-
- if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Audio encoding failed\n");
- exit_program(1);
- }
-
- if (got_packet) {
- av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- write_frame(s, &pkt, ost);
- }
-}
-
-static void do_subtitle_out(AVFormatContext *s,
- OutputStream *ost,
- InputStream *ist,
- AVSubtitle *sub,
- int64_t pts)
-{
- static uint8_t *subtitle_out = NULL;
- int subtitle_out_max_size = 1024 * 1024;
- int subtitle_out_size, nb, i;
- AVCodecContext *enc;
- AVPacket pkt;
-
- if (pts == AV_NOPTS_VALUE) {
- av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
- if (exit_on_error)
- exit_program(1);
- return;
- }
-
- enc = ost->enc_ctx;
-
- if (!subtitle_out) {
- subtitle_out = av_malloc(subtitle_out_max_size);
- }
-
- /* Note: DVB subtitle need one packet to draw them and one other
- packet to clear them */
- /* XXX: signal it in the codec context ? */
- if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
- nb = 2;
- else
- nb = 1;
-
- for (i = 0; i < nb; i++) {
- ost->sync_opts = av_rescale_q(pts, ist->st->time_base, enc->time_base);
- if (!check_recording_time(ost))
- return;
-
- sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
- // start_display_time is required to be 0
- sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);
- sub->end_display_time -= sub->start_display_time;
- sub->start_display_time = 0;
-
- ost->frames_encoded++;
-
- subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
- subtitle_out_max_size, sub);
- if (subtitle_out_size < 0) {
- av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
- exit_program(1);
- }
-
- av_init_packet(&pkt);
- pkt.data = subtitle_out;
- pkt.size = subtitle_out_size;
- pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
- if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
- /* XXX: the pts correction is handled here. Maybe handling
- it in the codec would be better */
- if (i == 0)
- pkt.pts += 90 * sub->start_display_time;
- else
- pkt.pts += 90 * sub->end_display_time;
- }
- write_frame(s, &pkt, ost);
- }
-}
-
-static void do_video_out(AVFormatContext *s,
- OutputStream *ost,
- AVFrame *in_picture,
- int *frame_size)
-{
- int ret, format_video_sync;
- AVPacket pkt;
- AVCodecContext *enc = ost->enc_ctx;
-
- *frame_size = 0;
-
- format_video_sync = video_sync_method;
- if (format_video_sync == VSYNC_AUTO)
- format_video_sync = (s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH :
- (s->oformat->flags & AVFMT_VARIABLE_FPS) ? VSYNC_VFR : VSYNC_CFR;
- if (format_video_sync != VSYNC_PASSTHROUGH &&
- ost->frame_number &&
- in_picture->pts != AV_NOPTS_VALUE &&
- in_picture->pts < ost->sync_opts) {
- nb_frames_drop++;
- av_log(NULL, AV_LOG_WARNING,
- "*** dropping frame %d from stream %d at ts %"PRId64"\n",
- ost->frame_number, ost->st->index, in_picture->pts);
- return;
- }
-
- if (in_picture->pts == AV_NOPTS_VALUE)
- in_picture->pts = ost->sync_opts;
- ost->sync_opts = in_picture->pts;
-
-
- if (!ost->frame_number)
- ost->first_pts = in_picture->pts;
-
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
-
- if (ost->frame_number >= ost->max_frames)
- return;
-
- if (s->oformat->flags & AVFMT_RAWPICTURE &&
- enc->codec->id == AV_CODEC_ID_RAWVIDEO) {
- /* raw pictures are written as AVPicture structure to
- avoid any copies. We support temporarily the older
- method. */
- enc->coded_frame->interlaced_frame = in_picture->interlaced_frame;
- enc->coded_frame->top_field_first = in_picture->top_field_first;
- pkt.data = (uint8_t *)in_picture;
- pkt.size = sizeof(AVPicture);
- pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base);
- pkt.flags |= AV_PKT_FLAG_KEY;
-
- write_frame(s, &pkt, ost);
- } else {
- int got_packet;
-
- if (enc->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME) &&
- ost->top_field_first >= 0)
- in_picture->top_field_first = !!ost->top_field_first;
-
- in_picture->quality = enc->global_quality;
- in_picture->pict_type = 0;
- if (ost->forced_kf_index < ost->forced_kf_count &&
- in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
- in_picture->pict_type = AV_PICTURE_TYPE_I;
- ost->forced_kf_index++;
- }
-
- ost->frames_encoded++;
-
- ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
- exit_program(1);
- }
-
- if (got_packet) {
- av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- write_frame(s, &pkt, ost);
- *frame_size = pkt.size;
-
- /* if two pass, output log */
- if (ost->logfile && enc->stats_out) {
- fprintf(ost->logfile, "%s", enc->stats_out);
- }
- }
- }
- ost->sync_opts++;
- /*
- * For video, number of frames in == number of packets out.
- * But there may be reordering, so we can't throw away frames on encoder
- * flush, we need to limit them here, before they go into encoder.
- */
- ost->frame_number++;
-}
-
-static double psnr(double d)
-{
- return -10.0 * log(d) / log(10.0);
-}
-
-static void do_video_stats(OutputStream *ost, int frame_size)
-{
- AVCodecContext *enc;
- int frame_number;
- double ti1, bitrate, avg_bitrate;
-
- /* this is executed just the first time do_video_stats is called */
- if (!vstats_file) {
- vstats_file = fopen(vstats_filename, "w");
- if (!vstats_file) {
- perror("fopen");
- exit_program(1);
- }
- }
-
- enc = ost->enc_ctx;
- if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
- frame_number = ost->frame_number;
- fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality / (float)FF_QP2LAMBDA);
- if (enc->flags&CODEC_FLAG_PSNR)
- fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
-
- fprintf(vstats_file,"f_size= %6d ", frame_size);
- /* compute pts value */
- ti1 = ost->sync_opts * av_q2d(enc->time_base);
- if (ti1 < 0.01)
- ti1 = 0.01;
-
- bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
- avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0;
- fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
- (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate);
- fprintf(vstats_file, "type= %c\n", av_get_picture_type_char(enc->coded_frame->pict_type));
- }
-}
-
-/*
- * Read one frame for lavfi output for ost and encode it.
- */
-static int poll_filter(OutputStream *ost)
-{
- OutputFile *of = output_files[ost->file_index];
- AVFrame *filtered_frame = NULL;
- int frame_size, ret;
-
- if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
- return AVERROR(ENOMEM);
- }
- filtered_frame = ost->filtered_frame;
-
- if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
- !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE))
- ret = av_buffersink_get_samples(ost->filter->filter, filtered_frame,
- ost->enc_ctx->frame_size);
- else
- ret = av_buffersink_get_frame(ost->filter->filter, filtered_frame);
-
- if (ret < 0)
- return ret;
-
- if (filtered_frame->pts != AV_NOPTS_VALUE) {
- int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
- filtered_frame->pts = av_rescale_q(filtered_frame->pts,
- ost->filter->filter->inputs[0]->time_base,
- ost->enc_ctx->time_base) -
- av_rescale_q(start_time,
- AV_TIME_BASE_Q,
- ost->enc_ctx->time_base);
- }
-
- switch (ost->filter->filter->inputs[0]->type) {
- case AVMEDIA_TYPE_VIDEO:
- if (!ost->frame_aspect_ratio)
- ost->enc_ctx->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;
-
- do_video_out(of->ctx, ost, filtered_frame, &frame_size);
- if (vstats_filename && frame_size)
- do_video_stats(ost, frame_size);
- break;
- case AVMEDIA_TYPE_AUDIO:
- do_audio_out(of->ctx, ost, filtered_frame);
- break;
- default:
- // TODO support subtitle filters
- av_assert0(0);
- }
-
- av_frame_unref(filtered_frame);
-
- return 0;
-}
-
-static void finish_output_stream(OutputStream *ost)
-{
- OutputFile *of = output_files[ost->file_index];
- int i;
-
- ost->finished = 1;
-
- if (of->shortest) {
- for (i = 0; i < of->ctx->nb_streams; i++)
- output_streams[of->ost_index + i]->finished = 1;
- }
-}
-
-/*
- * Read as many frames from possible from lavfi and encode them.
- *
- * Always read from the active stream with the lowest timestamp. If no frames
- * are available for it then return EAGAIN and wait for more input. This way we
- * can use lavfi sources that generate unlimited amount of frames without memory
- * usage exploding.
- */
-static int poll_filters(void)
-{
- int i, ret = 0;
-
- while (ret >= 0 && !received_sigterm) {
- OutputStream *ost = NULL;
- int64_t min_pts = INT64_MAX;
-
- /* choose output stream with the lowest timestamp */
- for (i = 0; i < nb_output_streams; i++) {
- int64_t pts = output_streams[i]->sync_opts;
-
- if (!output_streams[i]->filter || output_streams[i]->finished)
- continue;
-
- pts = av_rescale_q(pts, output_streams[i]->enc_ctx->time_base,
- AV_TIME_BASE_Q);
- if (pts < min_pts) {
- min_pts = pts;
- ost = output_streams[i];
- }
- }
-
- if (!ost)
- break;
-
- ret = poll_filter(ost);
-
- if (ret == AVERROR_EOF) {
- finish_output_stream(ost);
- ret = 0;
- } else if (ret == AVERROR(EAGAIN))
- return 0;
- }
-
- return ret;
-}
-
-static void print_final_stats(int64_t total_size)
-{
- uint64_t video_size = 0, audio_size = 0, extra_size = 0, other_size = 0;
- uint64_t data_size = 0;
- float percent = -1.0;
- int i, j;
-
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- switch (ost->enc_ctx->codec_type) {
- case AVMEDIA_TYPE_VIDEO: video_size += ost->data_size; break;
- case AVMEDIA_TYPE_AUDIO: audio_size += ost->data_size; break;
- default: other_size += ost->data_size; break;
- }
- extra_size += ost->enc_ctx->extradata_size;
- data_size += ost->data_size;
- }
-
- if (data_size && total_size >= data_size)
- percent = 100.0 * (total_size - data_size) / data_size;
-
- av_log(NULL, AV_LOG_INFO, "\n");
- av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB other streams:%1.0fkB global headers:%1.0fkB muxing overhead: ",
- video_size / 1024.0,
- audio_size / 1024.0,
- other_size / 1024.0,
- extra_size / 1024.0);
- if (percent >= 0.0)
- av_log(NULL, AV_LOG_INFO, "%f%%", percent);
- else
- av_log(NULL, AV_LOG_INFO, "unknown");
- av_log(NULL, AV_LOG_INFO, "\n");
-
- /* print verbose per-stream stats */
- for (i = 0; i < nb_input_files; i++) {
- InputFile *f = input_files[i];
- uint64_t total_packets = 0, total_size = 0;
-
- av_log(NULL, AV_LOG_VERBOSE, "Input file #%d (%s):\n",
- i, f->ctx->filename);
-
- for (j = 0; j < f->nb_streams; j++) {
- InputStream *ist = input_streams[f->ist_index + j];
- enum AVMediaType type = ist->dec_ctx->codec_type;
-
- total_size += ist->data_size;
- total_packets += ist->nb_packets;
-
- av_log(NULL, AV_LOG_VERBOSE, " Input stream #%d:%d (%s): ",
- i, j, media_type_string(type));
- av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets read (%"PRIu64" bytes); ",
- ist->nb_packets, ist->data_size);
-
- if (ist->decoding_needed) {
- av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames decoded",
- ist->frames_decoded);
- if (type == AVMEDIA_TYPE_AUDIO)
- av_log(NULL, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ist->samples_decoded);
- av_log(NULL, AV_LOG_VERBOSE, "; ");
- }
-
- av_log(NULL, AV_LOG_VERBOSE, "\n");
- }
-
- av_log(NULL, AV_LOG_VERBOSE, " Total: %"PRIu64" packets (%"PRIu64" bytes) demuxed\n",
- total_packets, total_size);
- }
-
- for (i = 0; i < nb_output_files; i++) {
- OutputFile *of = output_files[i];
- uint64_t total_packets = 0, total_size = 0;
-
- av_log(NULL, AV_LOG_VERBOSE, "Output file #%d (%s):\n",
- i, of->ctx->filename);
-
- for (j = 0; j < of->ctx->nb_streams; j++) {
- OutputStream *ost = output_streams[of->ost_index + j];
- enum AVMediaType type = ost->enc_ctx->codec_type;
-
- total_size += ost->data_size;
- total_packets += ost->packets_written;
-
- av_log(NULL, AV_LOG_VERBOSE, " Output stream #%d:%d (%s): ",
- i, j, media_type_string(type));
- if (ost->encoding_needed) {
- av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames encoded",
- ost->frames_encoded);
- if (type == AVMEDIA_TYPE_AUDIO)
- av_log(NULL, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->samples_encoded);
- av_log(NULL, AV_LOG_VERBOSE, "; ");
- }
-
- av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets muxed (%"PRIu64" bytes); ",
- ost->packets_written, ost->data_size);
-
- av_log(NULL, AV_LOG_VERBOSE, "\n");
- }
-
- av_log(NULL, AV_LOG_VERBOSE, " Total: %"PRIu64" packets (%"PRIu64" bytes) muxed\n",
- total_packets, total_size);
- }
-}
-
-static void print_report(int is_last_report, int64_t timer_start)
-{
- char buf[1024];
- OutputStream *ost;
- AVFormatContext *oc;
- int64_t total_size;
- AVCodecContext *enc;
- int frame_number, vid, i;
- double bitrate, ti1, pts;
- static int64_t last_time = -1;
- static int qp_histogram[52];
-
- if (!print_stats && !is_last_report)
- return;
-
- if (!is_last_report) {
- int64_t cur_time;
- /* display the report every 0.5 seconds */
- cur_time = av_gettime_relative();
- if (last_time == -1) {
- last_time = cur_time;
- return;
- }
- if ((cur_time - last_time) < 500000)
- return;
- last_time = cur_time;
- }
-
-
- oc = output_files[0]->ctx;
-
- total_size = avio_size(oc->pb);
- if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too
- total_size = avio_tell(oc->pb);
- if (total_size < 0) {
- char errbuf[128];
- av_strerror(total_size, errbuf, sizeof(errbuf));
- av_log(NULL, AV_LOG_VERBOSE, "Bitrate not available, "
- "avio_tell() failed: %s\n", errbuf);
- total_size = 0;
- }
-
- buf[0] = '\0';
- ti1 = 1e10;
- vid = 0;
- for (i = 0; i < nb_output_streams; i++) {
- float q = -1;
- ost = output_streams[i];
- enc = ost->enc_ctx;
- if (!ost->stream_copy && enc->coded_frame)
- q = enc->coded_frame->quality / (float)FF_QP2LAMBDA;
- if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q);
- }
- if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
- float t = (av_gettime_relative() - timer_start) / 1000000.0;
-
- frame_number = ost->frame_number;
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3d q=%3.1f ",
- frame_number, (t > 1) ? (int)(frame_number / t + 0.5) : 0, q);
- if (is_last_report)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
- if (qp_hist) {
- int j;
- int qp = lrintf(q);
- if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram))
- qp_histogram[qp]++;
- for (j = 0; j < 32; j++)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log2(qp_histogram[j] + 1)));
- }
- if (enc->flags&CODEC_FLAG_PSNR) {
- int j;
- double error, error_sum = 0;
- double scale, scale_sum = 0;
- char type[3] = { 'Y','U','V' };
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR=");
- for (j = 0; j < 3; j++) {
- if (is_last_report) {
- error = enc->error[j];
- scale = enc->width * enc->height * 255.0 * 255.0 * frame_number;
- } else {
- error = enc->coded_frame->error[j];
- scale = enc->width * enc->height * 255.0 * 255.0;
- }
- if (j)
- scale /= 4;
- error_sum += error;
- scale_sum += scale;
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error / scale));
- }
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum));
- }
- vid = 1;
- }
- /* compute min output value */
- pts = (double)ost->last_mux_dts * av_q2d(ost->st->time_base);
- if ((pts < ti1) && (pts > 0))
- ti1 = pts;
- }
- if (ti1 < 0.01)
- ti1 = 0.01;
-
- bitrate = (double)(total_size * 8) / ti1 / 1000.0;
-
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- "size=%8.0fkB time=%0.2f bitrate=%6.1fkbits/s",
- (double)total_size / 1024, ti1, bitrate);
-
- if (nb_frames_drop)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " drop=%d",
- nb_frames_drop);
-
- av_log(NULL, AV_LOG_INFO, "%s \r", buf);
-
- fflush(stderr);
-
- if (is_last_report)
- print_final_stats(total_size);
-
-}
-
-static void flush_encoders(void)
-{
- int i, ret;
-
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- AVCodecContext *enc = ost->enc_ctx;
- AVFormatContext *os = output_files[ost->file_index]->ctx;
- int stop_encoding = 0;
-
- if (!ost->encoding_needed)
- continue;
-
- if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
- continue;
- if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO)
- continue;
-
- for (;;) {
- int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
- const char *desc;
-
- switch (enc->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- encode = avcodec_encode_audio2;
- desc = "Audio";
- break;
- case AVMEDIA_TYPE_VIDEO:
- encode = avcodec_encode_video2;
- desc = "Video";
- break;
- default:
- stop_encoding = 1;
- }
-
- if (encode) {
- AVPacket pkt;
- int got_packet;
- av_init_packet(&pkt);
- pkt.data = NULL;
- pkt.size = 0;
-
- ret = encode(enc, &pkt, NULL, &got_packet);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
- exit_program(1);
- }
- if (ost->logfile && enc->stats_out) {
- fprintf(ost->logfile, "%s", enc->stats_out);
- }
- if (!got_packet) {
- stop_encoding = 1;
- break;
- }
- av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
- write_frame(os, &pkt, ost);
- }
-
- if (stop_encoding)
- break;
- }
- }
-}
-
-/*
- * Check whether a packet from ist should be written into ost at this time
- */
-static int check_output_constraints(InputStream *ist, OutputStream *ost)
-{
- OutputFile *of = output_files[ost->file_index];
- int ist_index = input_files[ist->file_index]->ist_index + ist->st->index;
-
- if (ost->source_index != ist_index)
- return 0;
-
- if (of->start_time != AV_NOPTS_VALUE && ist->last_dts < of->start_time)
- return 0;
-
- return 1;
-}
-
-static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *pkt)
-{
- OutputFile *of = output_files[ost->file_index];
- InputFile *f = input_files [ist->file_index];
- int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
- int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
- AVPacket opkt;
-
- av_init_packet(&opkt);
-
- if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) &&
- !ost->copy_initial_nonkeyframes)
- return;
-
- if (of->recording_time != INT64_MAX &&
- ist->last_dts >= of->recording_time + start_time) {
- ost->finished = 1;
- return;
- }
-
- if (f->recording_time != INT64_MAX) {
- start_time = f->ctx->start_time;
- if (f->start_time != AV_NOPTS_VALUE)
- start_time += f->start_time;
- if (ist->last_dts >= f->recording_time + start_time) {
- ost->finished = 1;
- return;
- }
- }
-
- /* force the input stream PTS */
- if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
- ost->sync_opts++;
-
- if (pkt->pts != AV_NOPTS_VALUE)
- opkt.pts = av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
- else
- opkt.pts = AV_NOPTS_VALUE;
-
- if (pkt->dts == AV_NOPTS_VALUE)
- opkt.dts = av_rescale_q(ist->last_dts, AV_TIME_BASE_Q, ost->st->time_base);
- else
- opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
- opkt.dts -= ost_tb_start_time;
-
- opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
- opkt.flags = pkt->flags;
-
- // FIXME remove the following 2 lines they shall be replaced by the bitstream filters
- if ( ost->enc_ctx->codec_id != AV_CODEC_ID_H264
- && ost->enc_ctx->codec_id != AV_CODEC_ID_MPEG1VIDEO
- && ost->enc_ctx->codec_id != AV_CODEC_ID_MPEG2VIDEO
- && ost->enc_ctx->codec_id != AV_CODEC_ID_VC1
- ) {
- if (av_parser_change(ost->parser, ost->st->codec,
- &opkt.data, &opkt.size,
- pkt->data, pkt->size,
- pkt->flags & AV_PKT_FLAG_KEY)) {
- opkt.buf = av_buffer_create(opkt.data, opkt.size, av_buffer_default_free, NULL, 0);
- if (!opkt.buf)
- exit_program(1);
- }
- } else {
- opkt.data = pkt->data;
- opkt.size = pkt->size;
- }
-
- write_frame(of->ctx, &opkt, ost);
-}
-
-int guess_input_channel_layout(InputStream *ist)
-{
- AVCodecContext *dec = ist->dec_ctx;
-
- if (!dec->channel_layout) {
- char layout_name[256];
-
- dec->channel_layout = av_get_default_channel_layout(dec->channels);
- if (!dec->channel_layout)
- return 0;
- av_get_channel_layout_string(layout_name, sizeof(layout_name),
- dec->channels, dec->channel_layout);
- av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
- "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
- }
- return 1;
-}
-
-static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
-{
- AVFrame *decoded_frame, *f;
- AVCodecContext *avctx = ist->dec_ctx;
- int i, ret, err = 0, resample_changed;
-
- if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- decoded_frame = ist->decoded_frame;
-
- ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
- if (!*got_output || ret < 0) {
- if (!pkt->size) {
- for (i = 0; i < ist->nb_filters; i++)
- av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
- }
- return ret;
- }
-
- ist->samples_decoded += decoded_frame->nb_samples;
- ist->frames_decoded++;
-
- /* if the decoder provides a pts, use it instead of the last packet pts.
- the decoder could be delaying output by a packet or more. */
- if (decoded_frame->pts != AV_NOPTS_VALUE)
- ist->next_dts = decoded_frame->pts;
- else if (pkt->pts != AV_NOPTS_VALUE)
- decoded_frame->pts = pkt->pts;
- pkt->pts = AV_NOPTS_VALUE;
-
- resample_changed = ist->resample_sample_fmt != decoded_frame->format ||
- ist->resample_channels != avctx->channels ||
- ist->resample_channel_layout != decoded_frame->channel_layout ||
- ist->resample_sample_rate != decoded_frame->sample_rate;
- if (resample_changed) {
- char layout1[64], layout2[64];
-
- if (!guess_input_channel_layout(ist)) {
- av_log(NULL, AV_LOG_FATAL, "Unable to find default channel "
- "layout for Input Stream #%d.%d\n", ist->file_index,
- ist->st->index);
- exit_program(1);
- }
- decoded_frame->channel_layout = avctx->channel_layout;
-
- av_get_channel_layout_string(layout1, sizeof(layout1), ist->resample_channels,
- ist->resample_channel_layout);
- av_get_channel_layout_string(layout2, sizeof(layout2), avctx->channels,
- decoded_frame->channel_layout);
-
- av_log(NULL, AV_LOG_INFO,
- "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s\n",
- ist->file_index, ist->st->index,
- ist->resample_sample_rate, av_get_sample_fmt_name(ist->resample_sample_fmt),
- ist->resample_channels, layout1,
- decoded_frame->sample_rate, av_get_sample_fmt_name(decoded_frame->format),
- avctx->channels, layout2);
-
- ist->resample_sample_fmt = decoded_frame->format;
- ist->resample_sample_rate = decoded_frame->sample_rate;
- ist->resample_channel_layout = decoded_frame->channel_layout;
- ist->resample_channels = avctx->channels;
-
- for (i = 0; i < nb_filtergraphs; i++)
- if (ist_in_filtergraph(filtergraphs[i], ist) &&
- configure_filtergraph(filtergraphs[i]) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
- }
- }
-
- if (decoded_frame->pts != AV_NOPTS_VALUE)
- decoded_frame->pts = av_rescale_q(decoded_frame->pts,
- ist->st->time_base,
- (AVRational){1, avctx->sample_rate});
- for (i = 0; i < ist->nb_filters; i++) {
- if (i < ist->nb_filters - 1) {
- f = ist->filter_frame;
- err = av_frame_ref(f, decoded_frame);
- if (err < 0)
- break;
- } else
- f = decoded_frame;
-
- err = av_buffersrc_add_frame(ist->filters[i]->filter, f);
- if (err < 0)
- break;
- }
-
- av_frame_unref(ist->filter_frame);
- av_frame_unref(decoded_frame);
- return err < 0 ? err : ret;
-}
-
-static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
-{
- AVFrame *decoded_frame, *f;
- int i, ret = 0, err = 0, resample_changed;
-
- if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- decoded_frame = ist->decoded_frame;
-
- ret = avcodec_decode_video2(ist->dec_ctx,
- decoded_frame, got_output, pkt);
- if (!*got_output || ret < 0) {
- if (!pkt->size) {
- for (i = 0; i < ist->nb_filters; i++)
- av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
- }
- return ret;
- }
-
- ist->frames_decoded++;
-
- if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {
- err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame);
- if (err < 0)
- goto fail;
- }
- ist->hwaccel_retrieved_pix_fmt = decoded_frame->format;
-
- decoded_frame->pts = guess_correct_pts(&ist->pts_ctx, decoded_frame->pkt_pts,
- decoded_frame->pkt_dts);
- pkt->size = 0;
-
- if (ist->st->sample_aspect_ratio.num)
- decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
-
- resample_changed = ist->resample_width != decoded_frame->width ||
- ist->resample_height != decoded_frame->height ||
- ist->resample_pix_fmt != decoded_frame->format;
- if (resample_changed) {
- av_log(NULL, AV_LOG_INFO,
- "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
- ist->file_index, ist->st->index,
- ist->resample_width, ist->resample_height, av_get_pix_fmt_name(ist->resample_pix_fmt),
- decoded_frame->width, decoded_frame->height, av_get_pix_fmt_name(decoded_frame->format));
-
- ret = poll_filters();
- if (ret < 0 && (ret != AVERROR_EOF && ret != AVERROR(EAGAIN))) {
- char errbuf[128];
- av_strerror(ret, errbuf, sizeof(errbuf));
-
- av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf);
- }
-
- ist->resample_width = decoded_frame->width;
- ist->resample_height = decoded_frame->height;
- ist->resample_pix_fmt = decoded_frame->format;
-
- for (i = 0; i < nb_filtergraphs; i++)
- if (ist_in_filtergraph(filtergraphs[i], ist) &&
- configure_filtergraph(filtergraphs[i]) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
- exit_program(1);
- }
- }
-
- for (i = 0; i < ist->nb_filters; i++) {
- if (i < ist->nb_filters - 1) {
- f = ist->filter_frame;
- err = av_frame_ref(f, decoded_frame);
- if (err < 0)
- break;
- } else
- f = decoded_frame;
-
- err = av_buffersrc_add_frame(ist->filters[i]->filter, f);
- if (err < 0)
- break;
- }
-
-fail:
- av_frame_unref(ist->filter_frame);
- av_frame_unref(decoded_frame);
- return err < 0 ? err : ret;
-}
-
-static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
-{
- AVSubtitle subtitle;
- int i, ret = avcodec_decode_subtitle2(ist->dec_ctx,
- &subtitle, got_output, pkt);
- if (ret < 0)
- return ret;
- if (!*got_output)
- return ret;
-
- ist->frames_decoded++;
-
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
-
- if (!check_output_constraints(ist, ost) || !ost->encoding_needed)
- continue;
-
- do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle, pkt->pts);
- }
-
- avsubtitle_free(&subtitle);
- return ret;
-}
-
-/* pkt = NULL means EOF (needed to flush decoder buffers) */
-static int process_input_packet(InputStream *ist, const AVPacket *pkt)
-{
- int i;
- int got_output;
- AVPacket avpkt;
-
- if (ist->next_dts == AV_NOPTS_VALUE)
- ist->next_dts = ist->last_dts;
-
- if (!pkt) {
- /* EOF handling */
- av_init_packet(&avpkt);
- avpkt.data = NULL;
- avpkt.size = 0;
- goto handle_eof;
- } else {
- avpkt = *pkt;
- }
-
- if (pkt->dts != AV_NOPTS_VALUE)
- ist->next_dts = ist->last_dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
-
- // while we have more to decode or while the decoder did output something on EOF
- while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
- int ret = 0;
- handle_eof:
-
- ist->last_dts = ist->next_dts;
-
- if (avpkt.size && avpkt.size != pkt->size &&
- !(ist->dec->capabilities & CODEC_CAP_SUBFRAMES)) {
- av_log(NULL, ist->showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING,
- "Multiple frames in a packet from stream %d\n", pkt->stream_index);
- ist->showed_multi_packet_warning = 1;
- }
-
- switch (ist->dec_ctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- ret = decode_audio (ist, &avpkt, &got_output);
- break;
- case AVMEDIA_TYPE_VIDEO:
- ret = decode_video (ist, &avpkt, &got_output);
- if (avpkt.duration)
- ist->next_dts += av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
- else if (ist->st->avg_frame_rate.num)
- ist->next_dts += av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate),
- AV_TIME_BASE_Q);
- else if (ist->dec_ctx->framerate.num != 0) {
- int ticks = ist->st->parser ? ist->st->parser->repeat_pict + 1 :
- ist->dec_ctx->ticks_per_frame;
- ist->next_dts += av_rescale_q(ticks, ist->dec_ctx->framerate, AV_TIME_BASE_Q);
- }
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- ret = transcode_subtitles(ist, &avpkt, &got_output);
- break;
- default:
- return -1;
- }
-
- if (ret < 0)
- return ret;
- // touch data and size only if not EOF
- if (pkt) {
- avpkt.data += ret;
- avpkt.size -= ret;
- }
- if (!got_output) {
- continue;
- }
- }
-
- /* handle stream copy */
- if (!ist->decoding_needed) {
- ist->last_dts = ist->next_dts;
- switch (ist->dec_ctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) /
- ist->dec_ctx->sample_rate;
- break;
- case AVMEDIA_TYPE_VIDEO:
- if (ist->dec_ctx->framerate.num != 0) {
- int ticks = ist->st->parser ? ist->st->parser->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame;
- ist->next_dts += ((int64_t)AV_TIME_BASE *
- ist->dec_ctx->framerate.den * ticks) /
- ist->dec_ctx->framerate.num;
- }
- break;
- }
- }
- for (i = 0; pkt && i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
-
- if (!check_output_constraints(ist, ost) || ost->encoding_needed)
- continue;
-
- do_streamcopy(ist, ost, pkt);
- }
-
- return 0;
-}
-
-static void print_sdp(void)
-{
- char sdp[16384];
- int i;
- AVFormatContext **avc = av_malloc(sizeof(*avc) * nb_output_files);
-
- if (!avc)
- exit_program(1);
- for (i = 0; i < nb_output_files; i++)
- avc[i] = output_files[i]->ctx;
-
- av_sdp_create(avc, nb_output_files, sdp, sizeof(sdp));
- printf("SDP:\n%s\n", sdp);
- fflush(stdout);
- av_freep(&avc);
-}
-
-static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt)
-{
- int i;
- for (i = 0; hwaccels[i].name; i++)
- if (hwaccels[i].pix_fmt == pix_fmt)
- return &hwaccels[i];
- return NULL;
-}
-
-static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
-{
- InputStream *ist = s->opaque;
- const enum AVPixelFormat *p;
- int ret;
-
- for (p = pix_fmts; *p != -1; p++) {
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
- const HWAccel *hwaccel;
-
- if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
- break;
-
- hwaccel = get_hwaccel(*p);
- if (!hwaccel ||
- (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) ||
- (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != hwaccel->id))
- continue;
-
- ret = hwaccel->init(s);
- if (ret < 0) {
- if (ist->hwaccel_id == hwaccel->id) {
- av_log(NULL, AV_LOG_FATAL,
- "%s hwaccel requested for input stream #%d:%d, "
- "but cannot be initialized.\n", hwaccel->name,
- ist->file_index, ist->st->index);
- return AV_PIX_FMT_NONE;
- }
- continue;
- }
- ist->active_hwaccel_id = hwaccel->id;
- ist->hwaccel_pix_fmt = *p;
- break;
- }
-
- return *p;
-}
-
-static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
-{
- InputStream *ist = s->opaque;
-
- if (ist->hwaccel_get_buffer && frame->format == ist->hwaccel_pix_fmt)
- return ist->hwaccel_get_buffer(s, frame, flags);
-
- return avcodec_default_get_buffer2(s, frame, flags);
-}
-
-static int init_input_stream(int ist_index, char *error, int error_len)
-{
- int i, ret;
- InputStream *ist = input_streams[ist_index];
- if (ist->decoding_needed) {
- AVCodec *codec = ist->dec;
- if (!codec) {
- snprintf(error, error_len, "Decoder (codec id %d) not found for input stream #%d:%d",
- ist->dec_ctx->codec_id, ist->file_index, ist->st->index);
- return AVERROR(EINVAL);
- }
-
- /* update requested sample format for the decoder based on the
- corresponding encoder sample format */
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- if (ost->source_index == ist_index) {
- update_sample_fmt(ist->dec_ctx, codec, ost->enc_ctx);
- break;
- }
- }
-
- ist->dec_ctx->opaque = ist;
- ist->dec_ctx->get_format = get_format;
- ist->dec_ctx->get_buffer2 = get_buffer;
- ist->dec_ctx->thread_safe_callbacks = 1;
-
- av_opt_set_int(ist->dec_ctx, "refcounted_frames", 1, 0);
-
- if (!av_dict_get(ist->decoder_opts, "threads", NULL, 0))
- av_dict_set(&ist->decoder_opts, "threads", "auto", 0);
- if ((ret = avcodec_open2(ist->dec_ctx, codec, &ist->decoder_opts)) < 0) {
- char errbuf[128];
- if (ret == AVERROR_EXPERIMENTAL)
- abort_codec_experimental(codec, 0);
-
- av_strerror(ret, errbuf, sizeof(errbuf));
-
- snprintf(error, error_len,
- "Error while opening decoder for input stream "
- "#%d:%d : %s",
- ist->file_index, ist->st->index, errbuf);
- return ret;
- }
- assert_avoptions(ist->decoder_opts);
- }
-
- ist->last_dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
- ist->next_dts = AV_NOPTS_VALUE;
- init_pts_correction(&ist->pts_ctx);
-
- return 0;
-}
-
-static InputStream *get_input_stream(OutputStream *ost)
-{
- if (ost->source_index >= 0)
- return input_streams[ost->source_index];
-
- if (ost->filter) {
- FilterGraph *fg = ost->filter->graph;
- int i;
-
- for (i = 0; i < fg->nb_inputs; i++)
- if (fg->inputs[i]->ist->dec_ctx->codec_type == ost->enc_ctx->codec_type)
- return fg->inputs[i]->ist;
- }
-
- return NULL;
-}
-
-static void parse_forced_key_frames(char *kf, OutputStream *ost,
- AVCodecContext *avctx)
-{
- char *p;
- int n = 1, i;
- int64_t t;
-
- for (p = kf; *p; p++)
- if (*p == ',')
- n++;
- ost->forced_kf_count = n;
- ost->forced_kf_pts = av_malloc(sizeof(*ost->forced_kf_pts) * n);
- if (!ost->forced_kf_pts) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
- exit_program(1);
- }
-
- p = kf;
- for (i = 0; i < n; i++) {
- char *next = strchr(p, ',');
-
- if (next)
- *next++ = 0;
-
- t = parse_time_or_die("force_key_frames", p, 1);
- ost->forced_kf_pts[i] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
-
- p = next;
- }
-}
-
-static void set_encoder_id(OutputFile *of, OutputStream *ost)
-{
- AVDictionaryEntry *e;
-
- uint8_t *encoder_string;
- int encoder_string_len;
- int format_flags = 0;
-
- e = av_dict_get(of->opts, "fflags", NULL, 0);
- if (e) {
- const AVOption *o = av_opt_find(of->ctx, "fflags", NULL, 0, 0);
- if (!o)
- return;
- av_opt_eval_flags(of->ctx, o, e->value, &format_flags);
- }
-
- encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2;
- encoder_string = av_mallocz(encoder_string_len);
- if (!encoder_string)
- exit_program(1);
-
- if (!(format_flags & AVFMT_FLAG_BITEXACT))
- av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
- av_strlcat(encoder_string, ost->enc->name, encoder_string_len);
- av_dict_set(&ost->st->metadata, "encoder", encoder_string,
- AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
-}
-
-static int transcode_init(void)
-{
- int ret = 0, i, j, k;
- AVFormatContext *oc;
- OutputStream *ost;
- InputStream *ist;
- char error[1024];
- int want_sdp = 1;
-
- /* init framerate emulation */
- for (i = 0; i < nb_input_files; i++) {
- InputFile *ifile = input_files[i];
- if (ifile->rate_emu)
- for (j = 0; j < ifile->nb_streams; j++)
- input_streams[j + ifile->ist_index]->start = av_gettime_relative();
- }
-
- /* output stream init */
- for (i = 0; i < nb_output_files; i++) {
- oc = output_files[i]->ctx;
- if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
- av_dump_format(oc, i, oc->filename, 1);
- av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", i);
- return AVERROR(EINVAL);
- }
- }
-
- /* init complex filtergraphs */
- for (i = 0; i < nb_filtergraphs; i++)
- if ((ret = avfilter_graph_config(filtergraphs[i]->graph, NULL)) < 0)
- return ret;
-
- /* for each output stream, we compute the right encoding parameters */
- for (i = 0; i < nb_output_streams; i++) {
- AVCodecContext *enc_ctx;
- AVCodecContext *dec_ctx = NULL;
- ost = output_streams[i];
- oc = output_files[ost->file_index]->ctx;
- ist = get_input_stream(ost);
-
- if (ost->attachment_filename)
- continue;
-
- enc_ctx = ost->stream_copy ? ost->st->codec : ost->enc_ctx;
-
- if (ist) {
- dec_ctx = ist->dec_ctx;
-
- ost->st->disposition = ist->st->disposition;
- enc_ctx->bits_per_raw_sample = dec_ctx->bits_per_raw_sample;
- enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location;
- }
-
- if (ost->stream_copy) {
- AVRational sar;
- uint64_t extra_size;
-
- av_assert0(ist && !ost->filter);
-
- extra_size = (uint64_t)dec_ctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
-
- if (extra_size > INT_MAX) {
- return AVERROR(EINVAL);
- }
-
- /* if stream_copy is selected, no need to decode or encode */
- enc_ctx->codec_id = dec_ctx->codec_id;
- enc_ctx->codec_type = dec_ctx->codec_type;
-
- if (!enc_ctx->codec_tag) {
- if (!oc->oformat->codec_tag ||
- av_codec_get_id (oc->oformat->codec_tag, dec_ctx->codec_tag) == enc_ctx->codec_id ||
- av_codec_get_tag(oc->oformat->codec_tag, dec_ctx->codec_id) <= 0)
- enc_ctx->codec_tag = dec_ctx->codec_tag;
- }
-
- enc_ctx->bit_rate = dec_ctx->bit_rate;
- enc_ctx->rc_max_rate = dec_ctx->rc_max_rate;
- enc_ctx->rc_buffer_size = dec_ctx->rc_buffer_size;
- enc_ctx->field_order = dec_ctx->field_order;
- enc_ctx->extradata = av_mallocz(extra_size);
- if (!enc_ctx->extradata) {
- return AVERROR(ENOMEM);
- }
- memcpy(enc_ctx->extradata, dec_ctx->extradata, dec_ctx->extradata_size);
- enc_ctx->extradata_size = dec_ctx->extradata_size;
- if (!copy_tb) {
- enc_ctx->time_base = dec_ctx->time_base;
- enc_ctx->time_base.num *= dec_ctx->ticks_per_frame;
- av_reduce(&enc_ctx->time_base.num, &enc_ctx->time_base.den,
- enc_ctx->time_base.num, enc_ctx->time_base.den, INT_MAX);
- } else
- enc_ctx->time_base = ist->st->time_base;
-
- if (ist->st->nb_side_data) {
- ost->st->side_data = av_realloc_array(NULL, ist->st->nb_side_data,
- sizeof(*ist->st->side_data));
- if (!ost->st->side_data)
- return AVERROR(ENOMEM);
-
- for (j = 0; j < ist->st->nb_side_data; j++) {
- const AVPacketSideData *sd_src = &ist->st->side_data[j];
- AVPacketSideData *sd_dst = &ost->st->side_data[j];
-
- sd_dst->data = av_malloc(sd_src->size);
- if (!sd_dst->data)
- return AVERROR(ENOMEM);
- memcpy(sd_dst->data, sd_src->data, sd_src->size);
- sd_dst->size = sd_src->size;
- sd_dst->type = sd_src->type;
- ost->st->nb_side_data++;
- }
- }
-
- ost->parser = av_parser_init(enc_ctx->codec_id);
-
- switch (enc_ctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- if (audio_volume != 256) {
- av_log(NULL, AV_LOG_FATAL, "-acodec copy and -vol are incompatible (frames are not decoded)\n");
- exit_program(1);
- }
- enc_ctx->channel_layout = dec_ctx->channel_layout;
- enc_ctx->sample_rate = dec_ctx->sample_rate;
- enc_ctx->channels = dec_ctx->channels;
- enc_ctx->frame_size = dec_ctx->frame_size;
- enc_ctx->audio_service_type = dec_ctx->audio_service_type;
- enc_ctx->block_align = dec_ctx->block_align;
- break;
- case AVMEDIA_TYPE_VIDEO:
- enc_ctx->pix_fmt = dec_ctx->pix_fmt;
- enc_ctx->width = dec_ctx->width;
- enc_ctx->height = dec_ctx->height;
- enc_ctx->has_b_frames = dec_ctx->has_b_frames;
- if (ost->frame_aspect_ratio)
- sar = av_d2q(ost->frame_aspect_ratio * enc_ctx->height / enc_ctx->width, 255);
- else if (ist->st->sample_aspect_ratio.num)
- sar = ist->st->sample_aspect_ratio;
- else
- sar = dec_ctx->sample_aspect_ratio;
- ost->st->sample_aspect_ratio = enc_ctx->sample_aspect_ratio = sar;
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- enc_ctx->width = dec_ctx->width;
- enc_ctx->height = dec_ctx->height;
- break;
- case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_ATTACHMENT:
- break;
- default:
- abort();
- }
- } else {
- if (!ost->enc) {
- /* should only happen when a default codec is not present. */
- snprintf(error, sizeof(error), "Automatic encoder selection "
- "failed for output stream #%d:%d. Default encoder for "
- "format %s is probably disabled. Please choose an "
- "encoder manually.\n", ost->file_index, ost->index,
- oc->oformat->name);
- ret = AVERROR(EINVAL);
- goto dump_format;
- }
-
- if (ist)
- ist->decoding_needed = 1;
- ost->encoding_needed = 1;
-
- set_encoder_id(output_files[ost->file_index], ost);
-
- /*
- * We want CFR output if and only if one of those is true:
- * 1) user specified output framerate with -r
- * 2) user specified -vsync cfr
- * 3) output format is CFR and the user didn't force vsync to
- * something else than CFR
- *
- * in such a case, set ost->frame_rate
- */
- if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO &&
- !ost->frame_rate.num && ist &&
- (video_sync_method == VSYNC_CFR ||
- (video_sync_method == VSYNC_AUTO &&
- !(oc->oformat->flags & (AVFMT_NOTIMESTAMPS | AVFMT_VARIABLE_FPS))))) {
- if (ist->framerate.num)
- ost->frame_rate = ist->framerate;
- else if (ist->st->avg_frame_rate.num)
- ost->frame_rate = ist->st->avg_frame_rate;
- else {
- av_log(NULL, AV_LOG_WARNING, "Constant framerate requested "
- "for the output stream #%d:%d, but no information "
- "about the input framerate is available. Falling "
- "back to a default value of 25fps. Use the -r option "
- "if you want a different framerate.\n",
- ost->file_index, ost->index);
- ost->frame_rate = (AVRational){ 25, 1 };
- }
-
- if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
- int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
- ost->frame_rate = ost->enc->supported_framerates[idx];
- }
- }
-
- if (!ost->filter &&
- (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO)) {
- FilterGraph *fg;
- fg = init_simple_filtergraph(ist, ost);
- if (configure_filtergraph(fg)) {
- av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
- exit_program(1);
- }
- }
-
- switch (enc_ctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- enc_ctx->sample_fmt = ost->filter->filter->inputs[0]->format;
- enc_ctx->sample_rate = ost->filter->filter->inputs[0]->sample_rate;
- enc_ctx->channel_layout = ost->filter->filter->inputs[0]->channel_layout;
- enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
- enc_ctx->time_base = (AVRational){ 1, enc_ctx->sample_rate };
- break;
- case AVMEDIA_TYPE_VIDEO:
- enc_ctx->time_base = ost->filter->filter->inputs[0]->time_base;
-
- enc_ctx->width = ost->filter->filter->inputs[0]->w;
- enc_ctx->height = ost->filter->filter->inputs[0]->h;
- enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =
- ost->frame_aspect_ratio ? // overridden by the -aspect cli option
- av_d2q(ost->frame_aspect_ratio * enc_ctx->height/enc_ctx->width, 255) :
- ost->filter->filter->inputs[0]->sample_aspect_ratio;
- enc_ctx->pix_fmt = ost->filter->filter->inputs[0]->format;
-
- ost->st->avg_frame_rate = ost->frame_rate;
-
- if (dec_ctx &&
- (enc_ctx->width != dec_ctx->width ||
- enc_ctx->height != dec_ctx->height ||
- enc_ctx->pix_fmt != dec_ctx->pix_fmt)) {
- enc_ctx->bits_per_raw_sample = 0;
- }
-
- if (ost->forced_keyframes)
- parse_forced_key_frames(ost->forced_keyframes, ost,
- ost->enc_ctx);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- enc_ctx->time_base = (AVRational){1, 1000};
- break;
- default:
- abort();
- break;
- }
- /* two pass mode */
- if ((enc_ctx->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2))) {
- char logfilename[1024];
- FILE *f;
-
- snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
- ost->logfile_prefix ? ost->logfile_prefix :
- DEFAULT_PASS_LOGFILENAME_PREFIX,
- i);
- if (!strcmp(ost->enc->name, "libx264")) {
- av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
- } else {
- if (enc_ctx->flags & CODEC_FLAG_PASS1) {
- f = fopen(logfilename, "wb");
- if (!f) {
- av_log(NULL, AV_LOG_FATAL, "Cannot write log file '%s' for pass-1 encoding: %s\n",
- logfilename, strerror(errno));
- exit_program(1);
- }
- ost->logfile = f;
- } else {
- char *logbuffer;
- size_t logbuffer_size;
- if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
- logfilename);
- exit_program(1);
- }
- enc_ctx->stats_in = logbuffer;
- }
- }
- }
- }
- }
-
- /* open each encoder */
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
- if (ost->encoding_needed) {
- AVCodec *codec = ost->enc;
- AVCodecContext *dec = NULL;
-
- if ((ist = get_input_stream(ost)))
- dec = ist->dec_ctx;
- if (dec && dec->subtitle_header) {
- ost->enc_ctx->subtitle_header = av_malloc(dec->subtitle_header_size);
- if (!ost->enc_ctx->subtitle_header) {
- ret = AVERROR(ENOMEM);
- goto dump_format;
- }
- memcpy(ost->enc_ctx->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
- ost->enc_ctx->subtitle_header_size = dec->subtitle_header_size;
- }
- if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
- av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
- av_dict_set(&ost->encoder_opts, "side_data_only_packets", "1", 0);
-
- if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {
- if (ret == AVERROR_EXPERIMENTAL)
- abort_codec_experimental(codec, 1);
- snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d:%d - maybe incorrect parameters such as bit_rate, rate, width or height",
- ost->file_index, ost->index);
- goto dump_format;
- }
- assert_avoptions(ost->encoder_opts);
- if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000)
- av_log(NULL, AV_LOG_WARNING, "The bitrate parameter is set too low."
- "It takes bits/s as argument, not kbits/s\n");
-
- ret = avcodec_copy_context(ost->st->codec, ost->enc_ctx);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL,
- "Error initializing the output stream codec context.\n");
- exit_program(1);
- }
-
- ost->st->time_base = ost->enc_ctx->time_base;
- } else {
- ret = av_opt_set_dict(ost->enc_ctx, &ost->encoder_opts);
- if (ret < 0)
- return ret;
- ost->st->time_base = ost->st->codec->time_base;
- }
- }
-
- /* init input streams */
- for (i = 0; i < nb_input_streams; i++)
- if ((ret = init_input_stream(i, error, sizeof(error))) < 0)
- goto dump_format;
-
- /* discard unused programs */
- for (i = 0; i < nb_input_files; i++) {
- InputFile *ifile = input_files[i];
- for (j = 0; j < ifile->ctx->nb_programs; j++) {
- AVProgram *p = ifile->ctx->programs[j];
- int discard = AVDISCARD_ALL;
-
- for (k = 0; k < p->nb_stream_indexes; k++)
- if (!input_streams[ifile->ist_index + p->stream_index[k]]->discard) {
- discard = AVDISCARD_DEFAULT;
- break;
- }
- p->discard = discard;
- }
- }
-
- /* open files and write file headers */
- for (i = 0; i < nb_output_files; i++) {
- oc = output_files[i]->ctx;
- oc->interrupt_callback = int_cb;
- if ((ret = avformat_write_header(oc, &output_files[i]->opts)) < 0) {
- char errbuf[128];
- av_strerror(ret, errbuf, sizeof(errbuf));
- snprintf(error, sizeof(error),
- "Could not write header for output file #%d "
- "(incorrect codec parameters ?): %s",
- i, errbuf);
- ret = AVERROR(EINVAL);
- goto dump_format;
- }
- assert_avoptions(output_files[i]->opts);
- if (strcmp(oc->oformat->name, "rtp")) {
- want_sdp = 0;
- }
- }
-
- dump_format:
- /* dump the file output parameters - cannot be done before in case
- of stream copy */
- for (i = 0; i < nb_output_files; i++) {
- av_dump_format(output_files[i]->ctx, i, output_files[i]->ctx->filename, 1);
- }
-
- /* dump the stream mapping */
- av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
-
- for (j = 0; j < ist->nb_filters; j++) {
- if (ist->filters[j]->graph->graph_desc) {
- av_log(NULL, AV_LOG_INFO, " Stream #%d:%d (%s) -> %s",
- ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?",
- ist->filters[j]->name);
- if (nb_filtergraphs > 1)
- av_log(NULL, AV_LOG_INFO, " (graph %d)", ist->filters[j]->graph->index);
- av_log(NULL, AV_LOG_INFO, "\n");
- }
- }
- }
-
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
-
- if (ost->attachment_filename) {
- /* an attached file */
- av_log(NULL, AV_LOG_INFO, " File %s -> Stream #%d:%d\n",
- ost->attachment_filename, ost->file_index, ost->index);
- continue;
- }
-
- if (ost->filter && ost->filter->graph->graph_desc) {
- /* output from a complex graph */
- av_log(NULL, AV_LOG_INFO, " %s", ost->filter->name);
- if (nb_filtergraphs > 1)
- av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index);
-
- av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file_index,
- ost->index, ost->enc ? ost->enc->name : "?");
- continue;
- }
-
- av_log(NULL, AV_LOG_INFO, " Stream #%d:%d -> #%d:%d",
- input_streams[ost->source_index]->file_index,
- input_streams[ost->source_index]->st->index,
- ost->file_index,
- ost->index);
- if (ost->sync_ist != input_streams[ost->source_index])
- av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]",
- ost->sync_ist->file_index,
- ost->sync_ist->st->index);
- if (ost->stream_copy)
- av_log(NULL, AV_LOG_INFO, " (copy)");
- else {
- const AVCodec *in_codec = input_streams[ost->source_index]->dec;
- const AVCodec *out_codec = ost->enc;
- const char *decoder_name = "?";
- const char *in_codec_name = "?";
- const char *encoder_name = "?";
- const char *out_codec_name = "?";
- const AVCodecDescriptor *desc;
-
- if (in_codec) {
- decoder_name = in_codec->name;
- desc = avcodec_descriptor_get(in_codec->id);
- if (desc)
- in_codec_name = desc->name;
- if (!strcmp(decoder_name, in_codec_name))
- decoder_name = "native";
- }
-
- if (out_codec) {
- encoder_name = out_codec->name;
- desc = avcodec_descriptor_get(out_codec->id);
- if (desc)
- out_codec_name = desc->name;
- if (!strcmp(encoder_name, out_codec_name))
- encoder_name = "native";
- }
-
- av_log(NULL, AV_LOG_INFO, " (%s (%s) -> %s (%s))",
- in_codec_name, decoder_name,
- out_codec_name, encoder_name);
- }
- av_log(NULL, AV_LOG_INFO, "\n");
- }
-
- if (ret) {
- av_log(NULL, AV_LOG_ERROR, "%s\n", error);
- return ret;
- }
-
- if (want_sdp) {
- print_sdp();
- }
-
- return 0;
-}
-
-/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
-static int need_output(void)
-{
- int i;
-
- for (i = 0; i < nb_output_streams; i++) {
- OutputStream *ost = output_streams[i];
- OutputFile *of = output_files[ost->file_index];
- AVFormatContext *os = output_files[ost->file_index]->ctx;
-
- if (ost->finished ||
- (os->pb && avio_tell(os->pb) >= of->limit_filesize))
- continue;
- if (ost->frame_number >= ost->max_frames) {
- int j;
- for (j = 0; j < of->ctx->nb_streams; j++)
- output_streams[of->ost_index + j]->finished = 1;
- continue;
- }
-
- return 1;
- }
-
- return 0;
-}
-
-static InputFile *select_input_file(void)
-{
- InputFile *ifile = NULL;
- int64_t ipts_min = INT64_MAX;
- int i;
-
- for (i = 0; i < nb_input_streams; i++) {
- InputStream *ist = input_streams[i];
- int64_t ipts = ist->last_dts;
-
- if (ist->discard || input_files[ist->file_index]->eagain)
- continue;
- if (!input_files[ist->file_index]->eof_reached) {
- if (ipts < ipts_min) {
- ipts_min = ipts;
- ifile = input_files[ist->file_index];
- }
- }
- }
-
- return ifile;
-}
-
-#if HAVE_PTHREADS
-static void *input_thread(void *arg)
-{
- InputFile *f = arg;
- int ret = 0;
-
- while (!transcoding_finished && ret >= 0) {
- AVPacket pkt;
- ret = av_read_frame(f->ctx, &pkt);
-
- if (ret == AVERROR(EAGAIN)) {
- av_usleep(10000);
- ret = 0;
- continue;
- } else if (ret < 0)
- break;
-
- pthread_mutex_lock(&f->fifo_lock);
- while (!av_fifo_space(f->fifo))
- pthread_cond_wait(&f->fifo_cond, &f->fifo_lock);
-
- av_dup_packet(&pkt);
- av_fifo_generic_write(f->fifo, &pkt, sizeof(pkt), NULL);
-
- pthread_mutex_unlock(&f->fifo_lock);
- }
-
- f->finished = 1;
- return NULL;
-}
-
-static void free_input_threads(void)
-{
- int i;
-
- if (nb_input_files == 1)
- return;
-
- transcoding_finished = 1;
-
- for (i = 0; i < nb_input_files; i++) {
- InputFile *f = input_files[i];
- AVPacket pkt;
-
- if (!f->fifo || f->joined)
- continue;
-
- pthread_mutex_lock(&f->fifo_lock);
- while (av_fifo_size(f->fifo)) {
- av_fifo_generic_read(f->fifo, &pkt, sizeof(pkt), NULL);
- av_free_packet(&pkt);
- }
- pthread_cond_signal(&f->fifo_cond);
- pthread_mutex_unlock(&f->fifo_lock);
-
- pthread_join(f->thread, NULL);
- f->joined = 1;
-
- while (av_fifo_size(f->fifo)) {
- av_fifo_generic_read(f->fifo, &pkt, sizeof(pkt), NULL);
- av_free_packet(&pkt);
- }
- av_fifo_free(f->fifo);
- }
-}
-
-static int init_input_threads(void)
-{
- int i, ret;
-
- if (nb_input_files == 1)
- return 0;
-
- for (i = 0; i < nb_input_files; i++) {
- InputFile *f = input_files[i];
-
- if (!(f->fifo = av_fifo_alloc(8*sizeof(AVPacket))))
- return AVERROR(ENOMEM);
-
- pthread_mutex_init(&f->fifo_lock, NULL);
- pthread_cond_init (&f->fifo_cond, NULL);
-
- if ((ret = pthread_create(&f->thread, NULL, input_thread, f)))
- return AVERROR(ret);
- }
- return 0;
-}
-
-static int get_input_packet_mt(InputFile *f, AVPacket *pkt)
-{
- int ret = 0;
-
- pthread_mutex_lock(&f->fifo_lock);
-
- if (av_fifo_size(f->fifo)) {
- av_fifo_generic_read(f->fifo, pkt, sizeof(*pkt), NULL);
- pthread_cond_signal(&f->fifo_cond);
- } else {
- if (f->finished)
- ret = AVERROR_EOF;
- else
- ret = AVERROR(EAGAIN);
- }
-
- pthread_mutex_unlock(&f->fifo_lock);
-
- return ret;
-}
-#endif
-
-static int get_input_packet(InputFile *f, AVPacket *pkt)
-{
- if (f->rate_emu) {
- int i;
- for (i = 0; i < f->nb_streams; i++) {
- InputStream *ist = input_streams[f->ist_index + i];
- int64_t pts = av_rescale(ist->last_dts, 1000000, AV_TIME_BASE);
- int64_t now = av_gettime_relative() - ist->start;
- if (pts > now)
- return AVERROR(EAGAIN);
- }
- }
-
-#if HAVE_PTHREADS
- if (nb_input_files > 1)
- return get_input_packet_mt(f, pkt);
-#endif
- return av_read_frame(f->ctx, pkt);
-}
-
-static int got_eagain(void)
-{
- int i;
- for (i = 0; i < nb_input_files; i++)
- if (input_files[i]->eagain)
- return 1;
- return 0;
-}
-
-static void reset_eagain(void)
-{
- int i;
- for (i = 0; i < nb_input_files; i++)
- input_files[i]->eagain = 0;
-}
-
-/*
- * Read one packet from an input file and send it for
- * - decoding -> lavfi (audio/video)
- * - decoding -> encoding -> muxing (subtitles)
- * - muxing (streamcopy)
- *
- * Return
- * - 0 -- one packet was read and processed
- * - AVERROR(EAGAIN) -- no packets were available for selected file,
- * this function should be called again
- * - AVERROR_EOF -- this function should not be called again
- */
-static int process_input(void)
-{
- InputFile *ifile;
- AVFormatContext *is;
- InputStream *ist;
- AVPacket pkt;
- int ret, i, j;
-
- /* select the stream that we must read now */
- ifile = select_input_file();
- /* if none, if is finished */
- if (!ifile) {
- if (got_eagain()) {
- reset_eagain();
- av_usleep(10000);
- return AVERROR(EAGAIN);
- }
- av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from.\n");
- return AVERROR_EOF;
- }
-
- is = ifile->ctx;
- ret = get_input_packet(ifile, &pkt);
-
- if (ret == AVERROR(EAGAIN)) {
- ifile->eagain = 1;
- return ret;
- }
- if (ret < 0) {
- if (ret != AVERROR_EOF) {
- print_error(is->filename, ret);
- if (exit_on_error)
- exit_program(1);
- }
- ifile->eof_reached = 1;
-
- for (i = 0; i < ifile->nb_streams; i++) {
- ist = input_streams[ifile->ist_index + i];
- if (ist->decoding_needed)
- process_input_packet(ist, NULL);
-
- /* mark all outputs that don't go through lavfi as finished */
- for (j = 0; j < nb_output_streams; j++) {
- OutputStream *ost = output_streams[j];
-
- if (ost->source_index == ifile->ist_index + i &&
- (ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE))
- finish_output_stream(ost);
- }
- }
-
- return AVERROR(EAGAIN);
- }
-
- reset_eagain();
-
- if (do_pkt_dump) {
- av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
- is->streams[pkt.stream_index]);
- }
- /* the following test is needed in case new streams appear
- dynamically in stream : we ignore them */
- if (pkt.stream_index >= ifile->nb_streams)
- goto discard_packet;
-
- ist = input_streams[ifile->ist_index + pkt.stream_index];
-
- ist->data_size += pkt.size;
- ist->nb_packets++;
-
- if (ist->discard)
- goto discard_packet;
-
- /* add the stream-global side data to the first packet */
- if (ist->nb_packets == 1)
- for (i = 0; i < ist->st->nb_side_data; i++) {
- AVPacketSideData *src_sd = &ist->st->side_data[i];
- uint8_t *dst_data;
-
- if (av_packet_get_side_data(&pkt, src_sd->type, NULL))
- continue;
- if (ist->autorotate && src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)
- continue;
-
- dst_data = av_packet_new_side_data(&pkt, src_sd->type, src_sd->size);
- if (!dst_data)
- exit_program(1);
-
- memcpy(dst_data, src_sd->data, src_sd->size);
- }
-
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
-
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts *= ist->ts_scale;
- if (pkt.dts != AV_NOPTS_VALUE)
- pkt.dts *= ist->ts_scale;
-
- if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
- pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
- (is->iformat->flags & AVFMT_TS_DISCONT)) {
- int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
- int64_t delta = pkt_dts - ist->next_dts;
-
- if ((FFABS(delta) > 1LL * dts_delta_threshold * AV_TIME_BASE || pkt_dts + 1 < ist->last_dts) && !copy_ts) {
- ifile->ts_offset -= delta;
- av_log(NULL, AV_LOG_DEBUG,
- "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
- delta, ifile->ts_offset);
- pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
- if (pkt.pts != AV_NOPTS_VALUE)
- pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
- }
- }
-
- ret = process_input_packet(ist, &pkt);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d\n",
- ist->file_index, ist->st->index);
- if (exit_on_error)
- exit_program(1);
- }
-
-discard_packet:
- av_free_packet(&pkt);
-
- return 0;
-}
-
-/*
- * The following code is the main loop of the file converter
- */
-static int transcode(void)
-{
- int ret, i, need_input = 1;
- AVFormatContext *os;
- OutputStream *ost;
- InputStream *ist;
- int64_t timer_start;
-
- ret = transcode_init();
- if (ret < 0)
- goto fail;
-
- av_log(NULL, AV_LOG_INFO, "Press ctrl-c to stop encoding\n");
- term_init();
-
- timer_start = av_gettime_relative();
-
-#if HAVE_PTHREADS
- if ((ret = init_input_threads()) < 0)
- goto fail;
-#endif
-
- while (!received_sigterm) {
- /* check if there's any stream where output is still needed */
- if (!need_output()) {
- av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
- break;
- }
-
- /* read and process one input packet if needed */
- if (need_input) {
- ret = process_input();
- if (ret == AVERROR_EOF)
- need_input = 0;
- }
-
- ret = poll_filters();
- if (ret < 0) {
- if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
- continue;
- } else {
- char errbuf[128];
- av_strerror(ret, errbuf, sizeof(errbuf));
-
- av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf);
- break;
- }
- }
-
- /* dump report by using the output first video and audio streams */
- print_report(0, timer_start);
- }
-#if HAVE_PTHREADS
- free_input_threads();
-#endif
-
- /* at the end of stream, we must flush the decoder buffers */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
- process_input_packet(ist, NULL);
- }
- }
- poll_filters();
- flush_encoders();
-
- term_exit();
-
- /* write the trailer if needed and close file */
- for (i = 0; i < nb_output_files; i++) {
- os = output_files[i]->ctx;
- av_write_trailer(os);
- }
-
- /* dump report by using the first video and audio streams */
- print_report(1, timer_start);
-
- /* close each encoder */
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
- if (ost->encoding_needed) {
- av_freep(&ost->enc_ctx->stats_in);
- }
- }
-
- /* close each decoder */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->decoding_needed) {
- avcodec_close(ist->dec_ctx);
- if (ist->hwaccel_uninit)
- ist->hwaccel_uninit(ist->dec_ctx);
- }
- }
-
- /* finished ! */
- ret = 0;
-
- fail:
-#if HAVE_PTHREADS
- free_input_threads();
-#endif
-
- if (output_streams) {
- for (i = 0; i < nb_output_streams; i++) {
- ost = output_streams[i];
- if (ost) {
- if (ost->logfile) {
- fclose(ost->logfile);
- ost->logfile = NULL;
- }
- av_free(ost->forced_kf_pts);
- av_dict_free(&ost->encoder_opts);
- av_dict_free(&ost->resample_opts);
- }
- }
- }
- return ret;
-}
-
-static int64_t getutime(void)
-{
-#if HAVE_GETRUSAGE
- struct rusage rusage;
-
- getrusage(RUSAGE_SELF, &rusage);
- return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
-#elif HAVE_GETPROCESSTIMES
- HANDLE proc;
- FILETIME c, e, k, u;
- proc = GetCurrentProcess();
- GetProcessTimes(proc, &c, &e, &k, &u);
- return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
-#else
- return av_gettime_relative();
-#endif
-}
-
-static int64_t getmaxrss(void)
-{
-#if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
- struct rusage rusage;
- getrusage(RUSAGE_SELF, &rusage);
- return (int64_t)rusage.ru_maxrss * 1024;
-#elif HAVE_GETPROCESSMEMORYINFO
- HANDLE proc;
- PROCESS_MEMORY_COUNTERS memcounters;
- proc = GetCurrentProcess();
- memcounters.cb = sizeof(memcounters);
- GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));
- return memcounters.PeakPagefileUsage;
-#else
- return 0;
-#endif
-}
-
-int main(int argc, char **argv)
-{
- int ret;
- int64_t ti;
-
- register_exit(avconv_cleanup);
-
- av_log_set_flags(AV_LOG_SKIP_REPEATED);
- parse_loglevel(argc, argv, options);
-
- avcodec_register_all();
-#if CONFIG_AVDEVICE
- avdevice_register_all();
-#endif
- avfilter_register_all();
- av_register_all();
- avformat_network_init();
-
- show_banner();
-
- /* parse options and open all input/output files */
- ret = avconv_parse_options(argc, argv);
- if (ret < 0)
- exit_program(1);
-
- if (nb_output_files <= 0 && nb_input_files == 0) {
- show_usage();
- av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
- exit_program(1);
- }
-
- /* file converter / grab */
- if (nb_output_files <= 0) {
- fprintf(stderr, "At least one output file must be specified\n");
- exit_program(1);
- }
-
- ti = getutime();
- if (transcode() < 0)
- exit_program(1);
- ti = getutime() - ti;
- if (do_benchmark) {
- int maxrss = getmaxrss() / 1024;
- printf("bench: utime=%0.3fs maxrss=%ikB\n", ti / 1000000.0, maxrss);
- }
-
- exit_program(0);
- return 0;
-}
diff --git a/avconv.h b/avconv.h
deleted file mode 100644
index 5fddf98127..0000000000
--- a/avconv.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCONV_H
-#define AVCONV_H
-
-#include "config.h"
-
-#include <stdint.h>
-#include <stdio.h>
-
-#if HAVE_PTHREADS
-#include <pthread.h>
-#endif
-
-#include "cmdutils.h"
-
-#include "libavformat/avformat.h"
-#include "libavformat/avio.h"
-
-#include "libavcodec/avcodec.h"
-
-#include "libavfilter/avfilter.h"
-
-#include "libavutil/avutil.h"
-#include "libavutil/dict.h"
-#include "libavutil/fifo.h"
-#include "libavutil/pixfmt.h"
-#include "libavutil/rational.h"
-
-#define VSYNC_AUTO -1
-#define VSYNC_PASSTHROUGH 0
-#define VSYNC_CFR 1
-#define VSYNC_VFR 2
-
-enum HWAccelID {
- HWACCEL_NONE = 0,
- HWACCEL_AUTO,
- HWACCEL_VDPAU,
- HWACCEL_DXVA2,
- HWACCEL_VDA,
-};
-
-typedef struct HWAccel {
- const char *name;
- int (*init)(AVCodecContext *s);
- enum HWAccelID id;
- enum AVPixelFormat pix_fmt;
-} HWAccel;
-
-/* 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;
- int sync_file_index;
- int sync_stream_index;
- char *linklabel; /* name of an output link, for mapping lavfi outputs */
-} StreamMap;
-
-/* select an input file for an output file */
-typedef struct MetadataMap {
- int file; // file index
- char type; // type of metadata to copy -- (g)lobal, (s)tream, (c)hapter or (p)rogram
- int index; // stream/chapter/program number
-} MetadataMap;
-
-typedef struct OptionsContext {
- OptionGroup *g;
-
- /* input/output options */
- int64_t start_time;
- const char *format;
-
- SpecifierOpt *codec_names;
- int nb_codec_names;
- SpecifierOpt *audio_channels;
- int nb_audio_channels;
- SpecifierOpt *audio_sample_rate;
- int nb_audio_sample_rate;
- SpecifierOpt *frame_rates;
- int nb_frame_rates;
- SpecifierOpt *frame_sizes;
- int nb_frame_sizes;
- SpecifierOpt *frame_pix_fmts;
- int nb_frame_pix_fmts;
-
- /* input options */
- int64_t input_ts_offset;
- int rate_emu;
- int accurate_seek;
-
- SpecifierOpt *ts_scale;
- int nb_ts_scale;
- SpecifierOpt *dump_attachment;
- int nb_dump_attachment;
- SpecifierOpt *hwaccels;
- int nb_hwaccels;
- SpecifierOpt *hwaccel_devices;
- int nb_hwaccel_devices;
- SpecifierOpt *autorotate;
- int nb_autorotate;
-
- /* output options */
- StreamMap *stream_maps;
- int nb_stream_maps;
- /* first item specifies output metadata, second is input */
- MetadataMap (*meta_data_maps)[2];
- int nb_meta_data_maps;
- int metadata_global_manual;
- int metadata_streams_manual;
- int metadata_chapters_manual;
- const char **attachments;
- int nb_attachments;
-
- int chapters_input_file;
-
- int64_t recording_time;
- uint64_t limit_filesize;
- float mux_preload;
- float mux_max_delay;
- int shortest;
-
- int video_disable;
- int audio_disable;
- int subtitle_disable;
- int data_disable;
-
- /* indexed by output file stream index */
- int *streamid_map;
- int nb_streamid_map;
-
- SpecifierOpt *metadata;
- int nb_metadata;
- SpecifierOpt *max_frames;
- int nb_max_frames;
- SpecifierOpt *bitstream_filters;
- int nb_bitstream_filters;
- SpecifierOpt *codec_tags;
- int nb_codec_tags;
- SpecifierOpt *sample_fmts;
- int nb_sample_fmts;
- SpecifierOpt *qscale;
- int nb_qscale;
- SpecifierOpt *forced_key_frames;
- int nb_forced_key_frames;
- SpecifierOpt *force_fps;
- int nb_force_fps;
- SpecifierOpt *frame_aspect_ratios;
- int nb_frame_aspect_ratios;
- SpecifierOpt *rc_overrides;
- int nb_rc_overrides;
- SpecifierOpt *intra_matrices;
- int nb_intra_matrices;
- SpecifierOpt *inter_matrices;
- int nb_inter_matrices;
- SpecifierOpt *top_field_first;
- int nb_top_field_first;
- SpecifierOpt *metadata_map;
- int nb_metadata_map;
- SpecifierOpt *presets;
- int nb_presets;
- SpecifierOpt *copy_initial_nonkeyframes;
- int nb_copy_initial_nonkeyframes;
- SpecifierOpt *filters;
- int nb_filters;
- SpecifierOpt *filter_scripts;
- int nb_filter_scripts;
- SpecifierOpt *pass;
- int nb_pass;
- SpecifierOpt *passlogfiles;
- int nb_passlogfiles;
-} OptionsContext;
-
-typedef struct InputFilter {
- AVFilterContext *filter;
- struct InputStream *ist;
- struct FilterGraph *graph;
- uint8_t *name;
-} InputFilter;
-
-typedef struct OutputFilter {
- AVFilterContext *filter;
- struct OutputStream *ost;
- struct FilterGraph *graph;
- uint8_t *name;
-
- /* temporary storage until stream maps are processed */
- AVFilterInOut *out_tmp;
-} OutputFilter;
-
-typedef struct FilterGraph {
- int index;
- const char *graph_desc;
-
- AVFilterGraph *graph;
-
- InputFilter **inputs;
- int nb_inputs;
- OutputFilter **outputs;
- int nb_outputs;
-} FilterGraph;
-
-typedef struct InputStream {
- int file_index;
- AVStream *st;
- int discard; /* true if stream data should be discarded */
- int decoding_needed; /* true if the packets must be decoded in 'raw_fifo' */
- AVCodecContext *dec_ctx;
- AVCodec *dec;
- AVFrame *decoded_frame;
- AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
-
- int64_t start; /* time when read started */
- /* predicted dts of the next packet read for this stream or (when there are
- * several frames in a packet) of the next frame in current packet */
- int64_t next_dts;
- /* dts of the last packet read for this stream */
- int64_t last_dts;
- PtsCorrectionContext pts_ctx;
- double ts_scale;
- int showed_multi_packet_warning;
- AVDictionary *decoder_opts;
- AVRational framerate; /* framerate forced with -r */
-
- int autorotate;
- int resample_height;
- int resample_width;
- int resample_pix_fmt;
-
- int resample_sample_fmt;
- int resample_sample_rate;
- int resample_channels;
- uint64_t resample_channel_layout;
-
- /* decoded data from this stream goes into all those filters
- * currently video and audio only */
- InputFilter **filters;
- int nb_filters;
-
- /* hwaccel options */
- enum HWAccelID hwaccel_id;
- char *hwaccel_device;
-
- /* hwaccel context */
- enum HWAccelID active_hwaccel_id;
- void *hwaccel_ctx;
- void (*hwaccel_uninit)(AVCodecContext *s);
- int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
- int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
- enum AVPixelFormat hwaccel_pix_fmt;
- enum AVPixelFormat hwaccel_retrieved_pix_fmt;
-
- /* stats */
- // combined size of all the packets read
- uint64_t data_size;
- /* number of packets successfully read for this stream */
- uint64_t nb_packets;
- // number of frames/samples retrieved from the decoder
- uint64_t frames_decoded;
- uint64_t samples_decoded;
-} InputStream;
-
-typedef struct InputFile {
- AVFormatContext *ctx;
- int eof_reached; /* true if eof reached */
- int eagain; /* true if last read attempt returned EAGAIN */
- int ist_index; /* index of first stream in ist_table */
- int64_t ts_offset;
- int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
- int64_t recording_time;
- int nb_streams; /* number of stream that avconv is aware of; may be different
- from ctx.nb_streams if new streams appear during av_read_frame() */
- int rate_emu;
- int accurate_seek;
-
-#if HAVE_PTHREADS
- pthread_t thread; /* thread reading from this file */
- int finished; /* the thread has exited */
- int joined; /* the thread has been joined */
- pthread_mutex_t fifo_lock; /* lock for access to fifo */
- pthread_cond_t fifo_cond; /* the main thread will signal on this cond after reading from fifo */
- AVFifoBuffer *fifo; /* demuxed packets are stored here; freed by the main thread */
-#endif
-} InputFile;
-
-typedef struct OutputStream {
- int file_index; /* file index */
- int index; /* stream index in the output file */
- int source_index; /* InputStream index */
- AVStream *st; /* stream in the output file */
- int encoding_needed; /* true if encoding needed for this stream */
- int frame_number;
- /* input pts and corresponding output pts
- for A/V sync */
- // double sync_ipts; /* dts from the AVPacket of the demuxer in second units */
- struct InputStream *sync_ist; /* input stream to sync against */
- int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
- /* pts of the first frame encoded for this stream, used for limiting
- * recording time */
- int64_t first_pts;
- /* dts of the last packet sent to the muxer */
- int64_t last_mux_dts;
- AVBitStreamFilterContext *bitstream_filters;
- AVCodecContext *enc_ctx;
- AVCodec *enc;
- int64_t max_frames;
- AVFrame *filtered_frame;
-
- /* video only */
- AVRational frame_rate;
- int force_fps;
- int top_field_first;
-
- float frame_aspect_ratio;
-
- /* forced key frames */
- int64_t *forced_kf_pts;
- int forced_kf_count;
- int forced_kf_index;
- char *forced_keyframes;
-
- char *logfile_prefix;
- FILE *logfile;
-
- OutputFilter *filter;
- char *avfilter;
-
- int64_t sws_flags;
- AVDictionary *encoder_opts;
- AVDictionary *resample_opts;
- int finished; /* no more packets should be written for this stream */
- int stream_copy;
- const char *attachment_filename;
- int copy_initial_nonkeyframes;
-
- enum AVPixelFormat pix_fmts[2];
-
- AVCodecParserContext *parser;
-
- /* stats */
- // combined size of all the packets written
- uint64_t data_size;
- // number of packets send to the muxer
- uint64_t packets_written;
- // number of frames/samples sent to the encoder
- uint64_t frames_encoded;
- uint64_t samples_encoded;
-} OutputStream;
-
-typedef struct OutputFile {
- AVFormatContext *ctx;
- AVDictionary *opts;
- int ost_index; /* index of the first stream in output_streams */
- int64_t recording_time; /* desired length of the resulting file in microseconds */
- int64_t start_time; /* start time in microseconds */
- uint64_t limit_filesize;
-
- int shortest;
-} OutputFile;
-
-extern InputStream **input_streams;
-extern int nb_input_streams;
-extern InputFile **input_files;
-extern int nb_input_files;
-
-extern OutputStream **output_streams;
-extern int nb_output_streams;
-extern OutputFile **output_files;
-extern int nb_output_files;
-
-extern FilterGraph **filtergraphs;
-extern int nb_filtergraphs;
-
-extern char *vstats_filename;
-
-extern float audio_drift_threshold;
-extern float dts_delta_threshold;
-
-extern int audio_volume;
-extern int audio_sync_method;
-extern int video_sync_method;
-extern int do_benchmark;
-extern int do_deinterlace;
-extern int do_hex_dump;
-extern int do_pkt_dump;
-extern int copy_ts;
-extern int copy_tb;
-extern int exit_on_error;
-extern int print_stats;
-extern int qp_hist;
-
-extern const AVIOInterruptCB int_cb;
-
-extern const OptionDef options[];
-
-extern const HWAccel hwaccels[];
-
-void reset_options(OptionsContext *o);
-void show_usage(void);
-
-void opt_output_file(void *optctx, const char *filename);
-
-void assert_avoptions(AVDictionary *m);
-
-int guess_input_channel_layout(InputStream *ist);
-
-int configure_filtergraph(FilterGraph *fg);
-int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
-int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
-FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost);
-
-int avconv_parse_options(int argc, char **argv);
-
-int vdpau_init(AVCodecContext *s);
-int dxva2_init(AVCodecContext *s);
-int vda_init(AVCodecContext *s);
-
-#endif /* AVCONV_H */
diff --git a/avconv_dxva2.c b/avconv_dxva2.c
deleted file mode 100644
index 8ca08c3ce2..0000000000
--- a/avconv_dxva2.c
+++ /dev/null
@@ -1,627 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <windows.h>
-
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0600
-#define DXVA2API_USE_BITFIELDS
-#define COBJMACROS
-
-#include <stdint.h>
-
-#include <d3d9.h>
-#include <dxva2api.h>
-
-#include "avconv.h"
-
-#include "libavcodec/dxva2.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/buffer.h"
-#include "libavutil/frame.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/pixfmt.h"
-
-/* define all the GUIDs used directly here,
- to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */
-#include <initguid.h>
-DEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
-
-DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
-DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60);
-DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
-DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
-DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
-DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
-DEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
-DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0);
-DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
-DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
-
-typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
-typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **);
-
-typedef struct dxva2_mode {
- const GUID *guid;
- enum AVCodecID codec;
-} dxva2_mode;
-
-static const dxva2_mode dxva2_modes[] = {
- /* MPEG-2 */
- { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO },
- { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO },
-
- /* H.264 */
- { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 },
- { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 },
- /* Intel specific H.264 mode */
- { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 },
-
- /* VC-1 / WMV3 */
- { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 },
- { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 },
- { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 },
- { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 },
-
- /* HEVC/H.265 */
- { &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC },
-
- { NULL, 0 },
-};
-
-typedef struct surface_info {
- int used;
- uint64_t age;
-} surface_info;
-
-typedef struct DXVA2Context {
- HMODULE d3dlib;
- HMODULE dxva2lib;
-
- HANDLE deviceHandle;
-
- IDirect3D9 *d3d9;
- IDirect3DDevice9 *d3d9device;
- IDirect3DDeviceManager9 *d3d9devmgr;
- IDirectXVideoDecoderService *decoder_service;
- IDirectXVideoDecoder *decoder;
-
- GUID decoder_guid;
- DXVA2_ConfigPictureDecode decoder_config;
-
- LPDIRECT3DSURFACE9 *surfaces;
- surface_info *surface_infos;
- uint32_t num_surfaces;
- uint64_t surface_age;
-
- AVFrame *tmp_frame;
-} DXVA2Context;
-
-typedef struct DXVA2SurfaceWrapper {
- DXVA2Context *ctx;
- LPDIRECT3DSURFACE9 surface;
- IDirectXVideoDecoder *decoder;
-} DXVA2SurfaceWrapper;
-
-static void dxva2_destroy_decoder(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- DXVA2Context *ctx = ist->hwaccel_ctx;
-
- if (ctx->surfaces) {
- for (int i = 0; i < ctx->num_surfaces; i++) {
- if (ctx->surfaces[i])
- IDirect3DSurface9_Release(ctx->surfaces[i]);
- }
- }
- av_freep(&ctx->surfaces);
- av_freep(&ctx->surface_infos);
- ctx->num_surfaces = 0;
- ctx->surface_age = 0;
-
- if (ctx->decoder) {
- IDirectXVideoDecoder_Release(ctx->decoder);
- ctx->decoder = NULL;
- }
-}
-
-static void dxva2_uninit(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- DXVA2Context *ctx = ist->hwaccel_ctx;
-
- ist->hwaccel_uninit = NULL;
- ist->hwaccel_get_buffer = NULL;
- ist->hwaccel_retrieve_data = NULL;
-
- if (ctx->decoder)
- dxva2_destroy_decoder(s);
-
- if (ctx->decoder_service)
- IDirectXVideoDecoderService_Release(ctx->decoder_service);
-
- if (ctx->d3d9devmgr && ctx->deviceHandle != INVALID_HANDLE_VALUE)
- IDirect3DDeviceManager9_CloseDeviceHandle(ctx->d3d9devmgr, ctx->deviceHandle);
-
- if (ctx->d3d9devmgr)
- IDirect3DDeviceManager9_Release(ctx->d3d9devmgr);
-
- if (ctx->d3d9device)
- IDirect3DDevice9_Release(ctx->d3d9device);
-
- if (ctx->d3d9)
- IDirect3D9_Release(ctx->d3d9);
-
- if (ctx->d3dlib)
- FreeLibrary(ctx->d3dlib);
-
- if (ctx->dxva2lib)
- FreeLibrary(ctx->dxva2lib);
-
- av_frame_free(&ctx->tmp_frame);
-
- av_freep(&ist->hwaccel_ctx);
- av_freep(&s->hwaccel_context);
-}
-
-static void dxva2_release_buffer(void *opaque, uint8_t *data)
-{
- DXVA2SurfaceWrapper *w = opaque;
- DXVA2Context *ctx = w->ctx;
- int i;
-
- for (i = 0; i < ctx->num_surfaces; i++) {
- if (ctx->surfaces[i] == w->surface) {
- ctx->surface_infos[i].used = 0;
- break;
- }
- }
- IDirect3DSurface9_Release(w->surface);
- IDirectXVideoDecoder_Release(w->decoder);
- av_free(w);
-}
-
-static int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
-{
- InputStream *ist = s->opaque;
- DXVA2Context *ctx = ist->hwaccel_ctx;
- int i, old_unused = -1;
- LPDIRECT3DSURFACE9 surface;
- DXVA2SurfaceWrapper *w = NULL;
-
- av_assert0(frame->format == AV_PIX_FMT_DXVA2_VLD);
-
- for (i = 0; i < ctx->num_surfaces; i++) {
- surface_info *info = &ctx->surface_infos[i];
- if (!info->used && (old_unused == -1 || info->age < ctx->surface_infos[old_unused].age))
- old_unused = i;
- }
- if (old_unused == -1) {
- av_log(NULL, AV_LOG_ERROR, "No free DXVA2 surface!\n");
- return AVERROR(ENOMEM);
- }
- i = old_unused;
-
- surface = ctx->surfaces[i];
-
- w = av_mallocz(sizeof(*w));
- if (!w)
- return AVERROR(ENOMEM);
-
- frame->buf[0] = av_buffer_create((uint8_t*)surface, 0,
- dxva2_release_buffer, w,
- AV_BUFFER_FLAG_READONLY);
- if (!frame->buf[0]) {
- av_free(w);
- return AVERROR(ENOMEM);
- }
-
- w->ctx = ctx;
- w->surface = surface;
- IDirect3DSurface9_AddRef(w->surface);
- w->decoder = ctx->decoder;
- IDirectXVideoDecoder_AddRef(w->decoder);
-
- ctx->surface_infos[i].used = 1;
- ctx->surface_infos[i].age = ctx->surface_age++;
-
- frame->data[3] = (uint8_t *)surface;
-
- return 0;
-}
-
-static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame)
-{
- LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)frame->data[3];
- InputStream *ist = s->opaque;
- DXVA2Context *ctx = ist->hwaccel_ctx;
- D3DSURFACE_DESC surfaceDesc;
- D3DLOCKED_RECT LockedRect;
- HRESULT hr;
- int ret;
-
- IDirect3DSurface9_GetDesc(surface, &surfaceDesc);
-
- ctx->tmp_frame->width = frame->width;
- ctx->tmp_frame->height = frame->height;
- ctx->tmp_frame->format = AV_PIX_FMT_NV12;
-
- ret = av_frame_get_buffer(ctx->tmp_frame, 32);
- if (ret < 0)
- return ret;
-
- hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, D3DLOCK_READONLY);
- if (FAILED(hr)) {
- av_log(NULL, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n");
- return AVERROR_UNKNOWN;
- }
-
- av_image_copy_plane(ctx->tmp_frame->data[0], ctx->tmp_frame->linesize[0],
- (uint8_t*)LockedRect.pBits,
- LockedRect.Pitch, frame->width, frame->height);
-
- av_image_copy_plane(ctx->tmp_frame->data[1], ctx->tmp_frame->linesize[1],
- (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height,
- LockedRect.Pitch, frame->width, frame->height / 2);
-
- IDirect3DSurface9_UnlockRect(surface);
-
- ret = av_frame_copy_props(ctx->tmp_frame, frame);
- if (ret < 0)
- goto fail;
-
- av_frame_unref(frame);
- av_frame_move_ref(frame, ctx->tmp_frame);
-
- return 0;
-fail:
- av_frame_unref(ctx->tmp_frame);
- return ret;
-}
-
-static int dxva2_alloc(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
- DXVA2Context *ctx;
- pDirect3DCreate9 *createD3D = NULL;
- pCreateDeviceManager9 *createDeviceManager = NULL;
- HRESULT hr;
- D3DPRESENT_PARAMETERS d3dpp = {0};
- D3DDISPLAYMODE d3ddm;
- unsigned resetToken = 0;
- UINT adapter = D3DADAPTER_DEFAULT;
-
- ctx = av_mallocz(sizeof(*ctx));
- if (!ctx)
- return AVERROR(ENOMEM);
-
- ctx->deviceHandle = INVALID_HANDLE_VALUE;
-
- ist->hwaccel_ctx = ctx;
- ist->hwaccel_uninit = dxva2_uninit;
- ist->hwaccel_get_buffer = dxva2_get_buffer;
- ist->hwaccel_retrieve_data = dxva2_retrieve_data;
-
- ctx->d3dlib = LoadLibrary("d3d9.dll");
- if (!ctx->d3dlib) {
- av_log(NULL, loglevel, "Failed to load D3D9 library\n");
- goto fail;
- }
- ctx->dxva2lib = LoadLibrary("dxva2.dll");
- if (!ctx->dxva2lib) {
- av_log(NULL, loglevel, "Failed to load DXVA2 library\n");
- goto fail;
- }
-
- createD3D = (pDirect3DCreate9 *)GetProcAddress(ctx->d3dlib, "Direct3DCreate9");
- if (!createD3D) {
- av_log(NULL, loglevel, "Failed to locate Direct3DCreate9\n");
- goto fail;
- }
- createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(ctx->dxva2lib, "DXVA2CreateDirect3DDeviceManager9");
- if (!createDeviceManager) {
- av_log(NULL, loglevel, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n");
- goto fail;
- }
-
- ctx->d3d9 = createD3D(D3D_SDK_VERSION);
- if (!ctx->d3d9) {
- av_log(NULL, loglevel, "Failed to create IDirect3D object\n");
- goto fail;
- }
-
- if (ist->hwaccel_device) {
- adapter = atoi(ist->hwaccel_device);
- av_log(NULL, AV_LOG_INFO, "Using HWAccel device %d\n", adapter);
- }
-
- IDirect3D9_GetAdapterDisplayMode(ctx->d3d9, adapter, &d3ddm);
- d3dpp.Windowed = TRUE;
- d3dpp.BackBufferWidth = 640;
- d3dpp.BackBufferHeight = 480;
- d3dpp.BackBufferCount = 0;
- d3dpp.BackBufferFormat = d3ddm.Format;
- d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
-
- hr = IDirect3D9_CreateDevice(ctx->d3d9, adapter, D3DDEVTYPE_HAL, GetShellWindow(),
- D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
- &d3dpp, &ctx->d3d9device);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to create Direct3D device\n");
- goto fail;
- }
-
- hr = createDeviceManager(&resetToken, &ctx->d3d9devmgr);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to create Direct3D device manager\n");
- goto fail;
- }
-
- hr = IDirect3DDeviceManager9_ResetDevice(ctx->d3d9devmgr, ctx->d3d9device, resetToken);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to bind Direct3D device to device manager\n");
- goto fail;
- }
-
- hr = IDirect3DDeviceManager9_OpenDeviceHandle(ctx->d3d9devmgr, &ctx->deviceHandle);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to open device handle\n");
- goto fail;
- }
-
- hr = IDirect3DDeviceManager9_GetVideoService(ctx->d3d9devmgr, ctx->deviceHandle, &IID_IDirectXVideoDecoderService, (void **)&ctx->decoder_service);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to create IDirectXVideoDecoderService\n");
- goto fail;
- }
-
- ctx->tmp_frame = av_frame_alloc();
- if (!ctx->tmp_frame)
- goto fail;
-
- s->hwaccel_context = av_mallocz(sizeof(struct dxva_context));
- if (!s->hwaccel_context)
- goto fail;
-
- return 0;
-fail:
- dxva2_uninit(s);
- return AVERROR(EINVAL);
-}
-
-static int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid,
- const DXVA2_VideoDesc *desc,
- DXVA2_ConfigPictureDecode *config)
-{
- InputStream *ist = s->opaque;
- int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
- DXVA2Context *ctx = ist->hwaccel_ctx;
- unsigned cfg_count = 0, best_score = 0;
- DXVA2_ConfigPictureDecode *cfg_list = NULL;
- DXVA2_ConfigPictureDecode best_cfg = {{0}};
- HRESULT hr;
- int i;
-
- hr = IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, device_guid, desc, NULL, &cfg_count, &cfg_list);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Unable to retrieve decoder configurations\n");
- return AVERROR(EINVAL);
- }
-
- for (i = 0; i < cfg_count; i++) {
- DXVA2_ConfigPictureDecode *cfg = &cfg_list[i];
-
- unsigned score;
- if (cfg->ConfigBitstreamRaw == 1)
- score = 1;
- else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
- score = 2;
- else
- continue;
- if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt))
- score += 16;
- if (score > best_score) {
- best_score = score;
- best_cfg = *cfg;
- }
- }
- CoTaskMemFree(cfg_list);
-
- if (!best_score) {
- av_log(NULL, loglevel, "No valid decoder configuration available\n");
- return AVERROR(EINVAL);
- }
-
- *config = best_cfg;
- return 0;
-}
-
-static int dxva2_create_decoder(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
- DXVA2Context *ctx = ist->hwaccel_ctx;
- struct dxva_context *dxva_ctx = s->hwaccel_context;
- GUID *guid_list = NULL;
- unsigned guid_count = 0, i, j;
- GUID device_guid = GUID_NULL;
- D3DFORMAT target_format = 0;
- DXVA2_VideoDesc desc = { 0 };
- DXVA2_ConfigPictureDecode config;
- HRESULT hr;
- int surface_alignment;
- int ret;
-
- hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n");
- goto fail;
- }
-
- for (i = 0; dxva2_modes[i].guid; i++) {
- D3DFORMAT *target_list = NULL;
- unsigned target_count = 0;
- const dxva2_mode *mode = &dxva2_modes[i];
- if (mode->codec != s->codec_id)
- continue;
-
- for (j = 0; j < guid_count; j++) {
- if (IsEqualGUID(mode->guid, &guid_list[j]))
- break;
- }
- if (j == guid_count)
- continue;
-
- hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list);
- if (FAILED(hr)) {
- continue;
- }
- for (j = 0; j < target_count; j++) {
- const D3DFORMAT format = target_list[j];
- if (format == MKTAG('N','V','1','2')) {
- target_format = format;
- break;
- }
- }
- CoTaskMemFree(target_list);
- if (target_format) {
- device_guid = *mode->guid;
- break;
- }
- }
- CoTaskMemFree(guid_list);
-
- if (IsEqualGUID(&device_guid, &GUID_NULL)) {
- av_log(NULL, loglevel, "No decoder device for codec found\n");
- goto fail;
- }
-
- desc.SampleWidth = s->coded_width;
- desc.SampleHeight = s->coded_height;
- desc.Format = target_format;
-
- ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config);
- if (ret < 0) {
- goto fail;
- }
-
- /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
- but it causes issues for H.264 on certain AMD GPUs..... */
- if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO)
- surface_alignment = 32;
- /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
- all coding features have enough room to work with */
- else if (s->codec_id == AV_CODEC_ID_HEVC)
- surface_alignment = 128;
- else
- surface_alignment = 16;
-
- /* 4 base work surfaces */
- ctx->num_surfaces = 4;
-
- /* add surfaces based on number of possible refs */
- if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)
- ctx->num_surfaces += 16;
- else
- ctx->num_surfaces += 2;
-
- /* add extra surfaces for frame threading */
- if (s->active_thread_type & FF_THREAD_FRAME)
- ctx->num_surfaces += s->thread_count;
-
- ctx->surfaces = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));
- ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos));
-
- if (!ctx->surfaces || !ctx->surface_infos) {
- av_log(NULL, loglevel, "Unable to allocate surface arrays\n");
- goto fail;
- }
-
- hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service,
- FFALIGN(s->coded_width, surface_alignment),
- FFALIGN(s->coded_height, surface_alignment),
- ctx->num_surfaces - 1,
- target_format, D3DPOOL_DEFAULT, 0,
- DXVA2_VideoDecoderRenderTarget,
- ctx->surfaces, NULL);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to create %d video surfaces\n", ctx->num_surfaces);
- goto fail;
- }
-
- hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
- &desc, &config, ctx->surfaces,
- ctx->num_surfaces, &ctx->decoder);
- if (FAILED(hr)) {
- av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n");
- goto fail;
- }
-
- ctx->decoder_guid = device_guid;
- ctx->decoder_config = config;
-
- dxva_ctx->cfg = &ctx->decoder_config;
- dxva_ctx->decoder = ctx->decoder;
- dxva_ctx->surface = ctx->surfaces;
- dxva_ctx->surface_count = ctx->num_surfaces;
-
- if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E))
- dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
-
- return 0;
-fail:
- dxva2_destroy_decoder(s);
- return AVERROR(EINVAL);
-}
-
-int dxva2_init(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
- DXVA2Context *ctx;
- int ret;
-
- if (!ist->hwaccel_ctx) {
- ret = dxva2_alloc(s);
- if (ret < 0)
- return ret;
- }
- ctx = ist->hwaccel_ctx;
-
- if (s->codec_id == AV_CODEC_ID_H264 &&
- (s->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) {
- av_log(NULL, loglevel, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s->profile);
- return AVERROR(EINVAL);
- }
-
- if (ctx->decoder)
- dxva2_destroy_decoder(s);
-
- ret = dxva2_create_decoder(s);
- if (ret < 0) {
- av_log(NULL, loglevel, "Error creating the DXVA2 decoder\n");
- return ret;
- }
-
- return 0;
-}
diff --git a/avconv_filter.c b/avconv_filter.c
deleted file mode 100644
index c3360f1741..0000000000
--- a/avconv_filter.c
+++ /dev/null
@@ -1,701 +0,0 @@
-/*
- * avconv filter configuration
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-#include "avconv.h"
-
-#include "libavfilter/avfilter.h"
-
-#include "libavresample/avresample.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/avstring.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/display.h"
-#include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/pixfmt.h"
-#include "libavutil/samplefmt.h"
-
-/* Define a function for building a string containing a list of
- * allowed formats. */
-#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \
-static char *choose_ ## var ## s(OutputStream *ost) \
-{ \
- if (ost->enc_ctx->var != none) { \
- get_name(ost->enc_ctx->var); \
- return av_strdup(name); \
- } else if (ost->enc && ost->enc->supported_list) { \
- const type *p; \
- AVIOContext *s = NULL; \
- uint8_t *ret; \
- int len; \
- \
- if (avio_open_dyn_buf(&s) < 0) \
- exit(1); \
- \
- for (p = ost->enc->supported_list; *p != none; p++) { \
- get_name(*p); \
- avio_printf(s, "%s|", name); \
- } \
- len = avio_close_dyn_buf(s, &ret); \
- ret[len - 1] = 0; \
- return ret; \
- } else \
- return NULL; \
-}
-
-DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
- GET_PIX_FMT_NAME)
-
-DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
- AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
-
-DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
- GET_SAMPLE_RATE_NAME)
-
-DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
- GET_CH_LAYOUT_NAME)
-
-FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
-{
- FilterGraph *fg = av_mallocz(sizeof(*fg));
-
- if (!fg)
- exit(1);
- fg->index = nb_filtergraphs;
-
- GROW_ARRAY(fg->outputs, fg->nb_outputs);
- if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
- exit(1);
- fg->outputs[0]->ost = ost;
- fg->outputs[0]->graph = fg;
-
- ost->filter = fg->outputs[0];
-
- GROW_ARRAY(fg->inputs, fg->nb_inputs);
- if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit(1);
- fg->inputs[0]->ist = ist;
- fg->inputs[0]->graph = fg;
-
- GROW_ARRAY(ist->filters, ist->nb_filters);
- ist->filters[ist->nb_filters - 1] = fg->inputs[0];
-
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- filtergraphs[nb_filtergraphs - 1] = fg;
-
- return fg;
-}
-
-static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
-{
- InputStream *ist = NULL;
- enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
- int i;
-
- // TODO: support other filter types
- if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
- av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
- "currently.\n");
- exit(1);
- }
-
- if (in->name) {
- AVFormatContext *s;
- AVStream *st = NULL;
- char *p;
- int file_idx = strtol(in->name, &p, 0);
-
- if (file_idx < 0 || file_idx >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtegraph description %s.\n",
- file_idx, fg->graph_desc);
- exit(1);
- }
- s = input_files[file_idx]->ctx;
-
- for (i = 0; i < s->nb_streams; i++) {
- if (s->streams[i]->codec->codec_type != type)
- continue;
- if (check_stream_specifier(s, s->streams[i], *p == ':' ? p + 1 : p) == 1) {
- st = s->streams[i];
- break;
- }
- }
- if (!st) {
- av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
- "matches no streams.\n", p, fg->graph_desc);
- exit(1);
- }
- ist = input_streams[input_files[file_idx]->ist_index + st->index];
- } else {
- /* find the first unused stream of corresponding type */
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->dec_ctx->codec_type == type && ist->discard)
- break;
- }
- if (i == nb_input_streams) {
- av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
- "unlabeled input pad %d on filter %s\n", in->pad_idx,
- in->filter_ctx->name);
- exit(1);
- }
- }
- av_assert0(ist);
-
- ist->discard = 0;
- ist->decoding_needed = 1;
- ist->st->discard = AVDISCARD_NONE;
-
- GROW_ARRAY(fg->inputs, fg->nb_inputs);
- if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
- exit(1);
- fg->inputs[fg->nb_inputs - 1]->ist = ist;
- fg->inputs[fg->nb_inputs - 1]->graph = fg;
-
- GROW_ARRAY(ist->filters, ist->nb_filters);
- ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
-}
-
-static int insert_trim(int64_t start_time, int64_t duration,
- AVFilterContext **last_filter, int *pad_idx,
- const char *filter_name)
-{
- AVFilterGraph *graph = (*last_filter)->graph;
- AVFilterContext *ctx;
- const AVFilter *trim;
- enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
- const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
- int ret = 0;
-
- if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
- return 0;
-
- trim = avfilter_get_by_name(name);
- if (!trim) {
- av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit "
- "recording time.\n", name);
- return AVERROR_FILTER_NOT_FOUND;
- }
-
- ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
- if (!ctx)
- return AVERROR(ENOMEM);
-
- if (duration != INT64_MAX) {
- ret = av_opt_set_double(ctx, "duration", (double)duration / 1e6,
- AV_OPT_SEARCH_CHILDREN);
- }
- if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
- ret = av_opt_set_double(ctx, "start", (double)start_time / 1e6,
- AV_OPT_SEARCH_CHILDREN);
- }
- if (ret < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name);
- return ret;
- }
-
- ret = avfilter_init_str(ctx, NULL);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
- if (ret < 0)
- return ret;
-
- *last_filter = ctx;
- *pad_idx = 0;
- return 0;
-}
-
-static int insert_filter(AVFilterContext **last_filter, int *pad_idx,
- const char *filter_name, const char *args)
-{
- AVFilterGraph *graph = (*last_filter)->graph;
- AVFilterContext *ctx;
- int ret;
-
- ret = avfilter_graph_create_filter(&ctx,
- avfilter_get_by_name(filter_name),
- filter_name, args, NULL, graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
- if (ret < 0)
- return ret;
-
- *last_filter = ctx;
- *pad_idx = 0;
- return 0;
-}
-
-static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
-{
- char *pix_fmts;
- OutputStream *ost = ofilter->ost;
- OutputFile *of = output_files[ost->file_index];
- AVCodecContext *codec = ost->enc_ctx;
- AVFilterContext *last_filter = out->filter_ctx;
- int pad_idx = out->pad_idx;
- int ret;
- char name[255];
-
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&ofilter->filter,
- avfilter_get_by_name("buffersink"),
- name, NULL, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- if (codec->width || codec->height) {
- char args[255];
- AVFilterContext *filter;
-
- snprintf(args, sizeof(args), "%d:%d:0x%X",
- codec->width,
- codec->height,
- (unsigned)ost->sws_flags);
- snprintf(name, sizeof(name), "scaler for output stream %d:%d",
- ost->file_index, ost->index);
- if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
- name, args, NULL, fg->graph)) < 0)
- return ret;
- if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
- return ret;
-
- last_filter = filter;
- pad_idx = 0;
- }
-
- if ((pix_fmts = choose_pix_fmts(ost))) {
- AVFilterContext *filter;
- snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
- ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&filter,
- avfilter_get_by_name("format"),
- "format", pix_fmts, NULL, fg->graph);
- av_freep(&pix_fmts);
- if (ret < 0)
- return ret;
- if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
- return ret;
-
- last_filter = filter;
- pad_idx = 0;
- }
-
- if (ost->frame_rate.num) {
- AVFilterContext *fps;
- char args[255];
-
- snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
- ost->frame_rate.den);
- snprintf(name, sizeof(name), "fps for output stream %d:%d",
- ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, pad_idx, fps, 0);
- if (ret < 0)
- return ret;
- last_filter = fps;
- pad_idx = 0;
- }
-
- snprintf(name, sizeof(name), "trim for output stream %d:%d",
- ost->file_index, ost->index);
- ret = insert_trim(of->start_time, of->recording_time,
- &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
-
- if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
- return ret;
-
- return 0;
-}
-
-static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
-{
- OutputStream *ost = ofilter->ost;
- OutputFile *of = output_files[ost->file_index];
- AVCodecContext *codec = ost->enc_ctx;
- AVFilterContext *last_filter = out->filter_ctx;
- int pad_idx = out->pad_idx;
- char *sample_fmts, *sample_rates, *channel_layouts;
- char name[255];
- int ret;
-
-
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&ofilter->filter,
- avfilter_get_by_name("abuffersink"),
- name, NULL, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- if (codec->channels && !codec->channel_layout)
- codec->channel_layout = av_get_default_channel_layout(codec->channels);
-
- sample_fmts = choose_sample_fmts(ost);
- sample_rates = choose_sample_rates(ost);
- channel_layouts = choose_channel_layouts(ost);
- if (sample_fmts || sample_rates || channel_layouts) {
- AVFilterContext *format;
- char args[256];
- int len = 0;
-
- if (sample_fmts)
- len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:",
- sample_fmts);
- if (sample_rates)
- len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:",
- sample_rates);
- if (channel_layouts)
- len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:",
- channel_layouts);
- args[len - 1] = 0;
-
- av_freep(&sample_fmts);
- av_freep(&sample_rates);
- av_freep(&channel_layouts);
-
- snprintf(name, sizeof(name), "audio format for output stream %d:%d",
- ost->file_index, ost->index);
- ret = avfilter_graph_create_filter(&format,
- avfilter_get_by_name("aformat"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, pad_idx, format, 0);
- if (ret < 0)
- return ret;
-
- last_filter = format;
- pad_idx = 0;
- }
-
- snprintf(name, sizeof(name), "trim for output stream %d:%d",
- ost->file_index, ost->index);
- ret = insert_trim(of->start_time, of->recording_time,
- &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
- return ret;
-
- return 0;
-}
-
-#define DESCRIBE_FILTER_LINK(f, inout, in) \
-{ \
- AVFilterContext *ctx = inout->filter_ctx; \
- AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
- int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
- AVIOContext *pb; \
- \
- if (avio_open_dyn_buf(&pb) < 0) \
- exit(1); \
- \
- avio_printf(pb, "%s", ctx->filter->name); \
- if (nb_pads > 1) \
- avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
- avio_w8(pb, 0); \
- avio_close_dyn_buf(pb, &f->name); \
-}
-
-int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
-{
- av_freep(&ofilter->name);
- DESCRIBE_FILTER_LINK(ofilter, out, 0);
-
- switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
- case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
- default: av_assert0(0);
- }
-}
-
-static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
- AVFilterInOut *in)
-{
- AVFilterContext *last_filter;
- const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
- InputStream *ist = ifilter->ist;
- InputFile *f = input_files[ist->file_index];
- AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
- ist->st->time_base;
- AVRational sar;
- char args[255], name[255];
- int ret, pad_idx = 0;
-
- sar = ist->st->sample_aspect_ratio.num ?
- ist->st->sample_aspect_ratio :
- ist->dec_ctx->sample_aspect_ratio;
- snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->dec_ctx->width,
- ist->dec_ctx->height,
- ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->dec_ctx->pix_fmt,
- tb.num, tb.den, sar.num, sar.den);
- snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
- ist->file_index, ist->st->index);
-
- if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
- args, NULL, fg->graph)) < 0)
- return ret;
- last_filter = ifilter->filter;
-
- if (ist->autorotate) {
- uint8_t* displaymatrix = av_stream_get_side_data(ist->st,
- AV_PKT_DATA_DISPLAYMATRIX, NULL);
- if (displaymatrix) {
- double rot = av_display_rotation_get((int32_t*) displaymatrix);
- if (rot < -135 || rot > 135) {
- ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
- if (ret < 0)
- return ret;
- ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
- } else if (rot < -45) {
- ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=clock");
- } else if (rot > 45) {
- ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=cclock");
- }
- if (ret < 0)
- return ret;
- }
- }
-
- if (ist->framerate.num) {
- AVFilterContext *setpts;
-
- snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
- ist->file_index, ist->st->index);
- if ((ret = avfilter_graph_create_filter(&setpts,
- avfilter_get_by_name("setpts"),
- name, "N", NULL,
- fg->graph)) < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
- return ret;
-
- last_filter = setpts;
- }
-
- snprintf(name, sizeof(name), "trim for input stream %d:%d",
- ist->file_index, ist->st->index);
- ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
- AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
- return ret;
- return 0;
-}
-
-static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
- AVFilterInOut *in)
-{
- AVFilterContext *last_filter;
- const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
- InputStream *ist = ifilter->ist;
- InputFile *f = input_files[ist->file_index];
- char args[255], name[255];
- int ret, pad_idx = 0;
-
- snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s"
- ":channel_layout=0x%"PRIx64,
- 1, ist->dec_ctx->sample_rate,
- ist->dec_ctx->sample_rate,
- av_get_sample_fmt_name(ist->dec_ctx->sample_fmt),
- ist->dec_ctx->channel_layout);
- snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
- ist->file_index, ist->st->index);
-
- if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
- name, args, NULL,
- fg->graph)) < 0)
- return ret;
- last_filter = ifilter->filter;
-
- if (audio_sync_method > 0) {
- AVFilterContext *async;
- int len = 0;
-
- av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the "
- "asyncts audio filter instead.\n");
-
- if (audio_sync_method > 1)
- len += snprintf(args + len, sizeof(args) - len, "compensate=1:"
- "max_comp=%d:", audio_sync_method);
- snprintf(args + len, sizeof(args) - len, "min_delta=%f",
- audio_drift_threshold);
-
- snprintf(name, sizeof(name), "graph %d audio sync for input stream %d:%d",
- fg->index, ist->file_index, ist->st->index);
- ret = avfilter_graph_create_filter(&async,
- avfilter_get_by_name("asyncts"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, 0, async, 0);
- if (ret < 0)
- return ret;
-
- last_filter = async;
- }
- if (audio_volume != 256) {
- AVFilterContext *volume;
-
- av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
- "audio filter instead.\n");
-
- snprintf(args, sizeof(args), "volume=%f", audio_volume / 256.0);
-
- snprintf(name, sizeof(name), "graph %d volume for input stream %d:%d",
- fg->index, ist->file_index, ist->st->index);
- ret = avfilter_graph_create_filter(&volume,
- avfilter_get_by_name("volume"),
- name, args, NULL, fg->graph);
- if (ret < 0)
- return ret;
-
- ret = avfilter_link(last_filter, 0, volume, 0);
- if (ret < 0)
- return ret;
-
- last_filter = volume;
- }
-
- snprintf(name, sizeof(name), "trim for input stream %d:%d",
- ist->file_index, ist->st->index);
- ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
- AV_NOPTS_VALUE : 0, f->recording_time, &last_filter, &pad_idx, name);
- if (ret < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
- return ret;
-
- return 0;
-}
-
-static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
- AVFilterInOut *in)
-{
- av_freep(&ifilter->name);
- DESCRIBE_FILTER_LINK(ifilter, in, 1);
-
- switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
- case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
- default: av_assert0(0);
- }
-}
-
-int configure_filtergraph(FilterGraph *fg)
-{
- AVFilterInOut *inputs, *outputs, *cur;
- int ret, i, init = !fg->graph, simple = !fg->graph_desc;
- const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
- fg->graph_desc;
-
- avfilter_graph_free(&fg->graph);
- if (!(fg->graph = avfilter_graph_alloc()))
- return AVERROR(ENOMEM);
-
- if (simple) {
- OutputStream *ost = fg->outputs[0]->ost;
- char args[512];
- AVDictionaryEntry *e = NULL;
-
- snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
- fg->graph->scale_sws_opts = av_strdup(args);
-
- args[0] = '\0';
- while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
- AV_DICT_IGNORE_SUFFIX))) {
- av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
- }
- if (strlen(args))
- args[strlen(args) - 1] = '\0';
- fg->graph->resample_lavr_opts = av_strdup(args);
- }
-
- if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
- return ret;
-
- if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
- av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
- "exactly one input and output.\n", graph_desc);
- return AVERROR(EINVAL);
- }
-
- for (cur = inputs; !simple && init && cur; cur = cur->next)
- init_input_filter(fg, cur);
-
- for (cur = inputs, i = 0; cur; cur = cur->next, i++)
- if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0)
- return ret;
- avfilter_inout_free(&inputs);
-
- if (!init || simple) {
- /* we already know the mappings between lavfi outputs and output streams,
- * so we can finish the setup */
- for (cur = outputs, i = 0; cur; cur = cur->next, i++)
- configure_output_filter(fg, fg->outputs[i], cur);
- avfilter_inout_free(&outputs);
-
- if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
- return ret;
- } else {
- /* wait until output mappings are processed */
- for (cur = outputs; cur;) {
- GROW_ARRAY(fg->outputs, fg->nb_outputs);
- if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]))))
- exit(1);
- fg->outputs[fg->nb_outputs - 1]->graph = fg;
- fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
- cur = cur->next;
- fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
- }
- }
-
- return 0;
-}
-
-int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
-{
- int i;
- for (i = 0; i < fg->nb_inputs; i++)
- if (fg->inputs[i]->ist == ist)
- return 1;
- return 0;
-}
-
diff --git a/avconv_opt.c b/avconv_opt.c
deleted file mode 100644
index 29fc2be6dd..0000000000
--- a/avconv_opt.c
+++ /dev/null
@@ -1,2437 +0,0 @@
-/*
- * avconv option parsing
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-#include "avconv.h"
-#include "cmdutils.h"
-
-#include "libavformat/avformat.h"
-
-#include "libavcodec/avcodec.h"
-
-#include "libavfilter/avfilter.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/avstring.h"
-#include "libavutil/avutil.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/fifo.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/pixfmt.h"
-
-#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
-{\
- int i, ret;\
- for (i = 0; i < o->nb_ ## name; i++) {\
- char *spec = o->name[i].specifier;\
- if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
- outvar = o->name[i].u.type;\
- else if (ret < 0)\
- exit_program(1);\
- }\
-}
-
-const HWAccel hwaccels[] = {
-#if HAVE_VDPAU_X11
- { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
-#endif
-#if HAVE_DXVA2_LIB
- { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD },
-#endif
-#if CONFIG_VDA
- { "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
-#endif
- { 0 },
-};
-
-char *vstats_filename;
-
-float audio_drift_threshold = 0.1;
-float dts_delta_threshold = 10;
-
-int audio_volume = 256;
-int audio_sync_method = 0;
-int video_sync_method = VSYNC_AUTO;
-int do_benchmark = 0;
-int do_hex_dump = 0;
-int do_pkt_dump = 0;
-int copy_ts = 0;
-int copy_tb = 1;
-int exit_on_error = 0;
-int print_stats = 1;
-int qp_hist = 0;
-
-static int file_overwrite = 0;
-static int file_skip = 0;
-static int video_discard = 0;
-static int intra_dc_precision = 8;
-static int using_stdin = 0;
-static int input_sync;
-
-static void uninit_options(OptionsContext *o)
-{
- const OptionDef *po = options;
- int i;
-
- /* all OPT_SPEC and OPT_STRING can be freed in generic way */
- while (po->name) {
- void *dst = (uint8_t*)o + po->u.off;
-
- if (po->flags & OPT_SPEC) {
- SpecifierOpt **so = dst;
- int i, *count = (int*)(so + 1);
- for (i = 0; i < *count; i++) {
- av_freep(&(*so)[i].specifier);
- if (po->flags & OPT_STRING)
- av_freep(&(*so)[i].u.str);
- }
- av_freep(so);
- *count = 0;
- } else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
- av_freep(dst);
- po++;
- }
-
- for (i = 0; i < o->nb_stream_maps; i++)
- av_freep(&o->stream_maps[i].linklabel);
- av_freep(&o->stream_maps);
- av_freep(&o->meta_data_maps);
- av_freep(&o->streamid_map);
-}
-
-static void init_options(OptionsContext *o)
-{
- memset(o, 0, sizeof(*o));
-
- o->mux_max_delay = 0.7;
- o->start_time = AV_NOPTS_VALUE;
- o->recording_time = INT64_MAX;
- o->limit_filesize = UINT64_MAX;
- o->chapters_input_file = INT_MAX;
- o->accurate_seek = 1;
-}
-
-/* return a copy of the input with the stream specifiers removed from the keys */
-static AVDictionary *strip_specifiers(AVDictionary *dict)
-{
- AVDictionaryEntry *e = NULL;
- AVDictionary *ret = NULL;
-
- while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
- char *p = strchr(e->key, ':');
-
- if (p)
- *p = 0;
- av_dict_set(&ret, e->key, e->value, 0);
- if (p)
- *p = ':';
- }
- return ret;
-}
-
-static double parse_frame_aspect_ratio(const char *arg)
-{
- int x = 0, y = 0;
- double ar = 0;
- const char *p;
- char *end;
-
- p = strchr(arg, ':');
- if (p) {
- x = strtol(arg, &end, 10);
- if (end == p)
- y = strtol(end + 1, &end, 10);
- if (x > 0 && y > 0)
- ar = (double)x / (double)y;
- } else
- ar = strtod(arg, NULL);
-
- if (!ar) {
- av_log(NULL, AV_LOG_FATAL, "Incorrect aspect ratio specification.\n");
- exit_program(1);
- }
- return ar;
-}
-
-static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:a", arg, options);
-}
-
-static int opt_video_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:v", arg, options);
-}
-
-static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:s", arg, options);
-}
-
-static int opt_data_codec(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "codec:d", arg, options);
-}
-
-static int opt_map(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- StreamMap *m = NULL;
- int i, negative = 0, file_idx;
- int sync_file_idx = -1, sync_stream_idx;
- char *p, *sync;
- char *map;
-
- if (*arg == '-') {
- negative = 1;
- arg++;
- }
- map = av_strdup(arg);
- if (!map)
- return AVERROR(ENOMEM);
-
- /* parse sync stream first, just pick first matching stream */
- if (sync = strchr(map, ',')) {
- *sync = 0;
- sync_file_idx = strtol(sync + 1, &sync, 0);
- if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
- exit_program(1);
- }
- if (*sync)
- sync++;
- for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
- if (check_stream_specifier(input_files[sync_file_idx]->ctx,
- input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
- sync_stream_idx = i;
- break;
- }
- if (i == input_files[sync_file_idx]->nb_streams) {
- av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
- "match any streams.\n", arg);
- exit_program(1);
- }
- }
-
-
- if (map[0] == '[') {
- /* this mapping refers to lavfi output */
- const char *c = map + 1;
- GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
- 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);
- exit_program(1);
- }
- } else {
- file_idx = strtol(map, &p, 0);
- if (file_idx >= nb_input_files || file_idx < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
- exit_program(1);
- }
- 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,
- input_files[m->file_index]->ctx->streams[m->stream_index],
- *p == ':' ? p + 1 : p) > 0)
- 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)
- continue;
- GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
- m = &o->stream_maps[o->nb_stream_maps - 1];
-
- m->file_index = file_idx;
- m->stream_index = i;
-
- if (sync_file_idx >= 0) {
- m->sync_file_index = sync_file_idx;
- m->sync_stream_index = sync_stream_idx;
- } else {
- m->sync_file_index = file_idx;
- m->sync_stream_index = i;
- }
- }
- }
-
- if (!m) {
- av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
- exit_program(1);
- }
-
- av_freep(&map);
- return 0;
-}
-
-static int opt_attach(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- GROW_ARRAY(o->attachments, o->nb_attachments);
- o->attachments[o->nb_attachments - 1] = arg;
- return 0;
-}
-
-/**
- * Parse a metadata specifier passed as 'arg' parameter.
- * @param arg metadata string to parse
- * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
- * @param index for type c/p, chapter/program index is written here
- * @param stream_spec for type s, the stream specifier is written here
- */
-static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
-{
- if (*arg) {
- *type = *arg;
- switch (*arg) {
- case 'g':
- break;
- case 's':
- if (*(++arg) && *arg != ':') {
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
- exit_program(1);
- }
- *stream_spec = *arg == ':' ? arg + 1 : "";
- break;
- case 'c':
- case 'p':
- if (*(++arg) == ':')
- *index = strtol(++arg, NULL, 0);
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
- exit_program(1);
- }
- } else
- *type = 'g';
-}
-
-static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
-{
- AVDictionary **meta_in = NULL;
- AVDictionary **meta_out;
- int i, ret = 0;
- char type_in, type_out;
- const char *istream_spec = NULL, *ostream_spec = NULL;
- int idx_in = 0, idx_out = 0;
-
- parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
- parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
-
- if (type_in == 'g' || type_out == 'g')
- o->metadata_global_manual = 1;
- if (type_in == 's' || type_out == 's')
- o->metadata_streams_manual = 1;
- if (type_in == 'c' || type_out == 'c')
- o->metadata_chapters_manual = 1;
-
- /* ic is NULL when just disabling automatic mappings */
- if (!ic)
- return 0;
-
-#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
- if ((index) < 0 || (index) >= (nb_elems)) {\
- av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
- (desc), (index));\
- exit_program(1);\
- }
-
-#define SET_DICT(type, meta, context, index)\
- switch (type) {\
- case 'g':\
- meta = &context->metadata;\
- break;\
- case 'c':\
- METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
- meta = &context->chapters[index]->metadata;\
- break;\
- case 'p':\
- METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
- meta = &context->programs[index]->metadata;\
- break;\
- case 's':\
- break; /* handled separately below */ \
- default: av_assert0(0);\
- }\
-
- SET_DICT(type_in, meta_in, ic, idx_in);
- SET_DICT(type_out, meta_out, oc, idx_out);
-
- /* for input streams choose first matching stream */
- if (type_in == 's') {
- for (i = 0; i < ic->nb_streams; i++) {
- if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
- meta_in = &ic->streams[i]->metadata;
- break;
- } else if (ret < 0)
- exit_program(1);
- }
- if (!meta_in) {
- av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
- exit_program(1);
- }
- }
-
- if (type_out == 's') {
- for (i = 0; i < oc->nb_streams; i++) {
- if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
- meta_out = &oc->streams[i]->metadata;
- av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
- } else if (ret < 0)
- exit_program(1);
- }
- } else
- av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
-
- return 0;
-}
-
-static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
-{
- const AVCodecDescriptor *desc;
- const char *codec_string = encoder ? "encoder" : "decoder";
- AVCodec *codec;
-
- codec = encoder ?
- avcodec_find_encoder_by_name(name) :
- avcodec_find_decoder_by_name(name);
-
- if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
- codec = encoder ? avcodec_find_encoder(desc->id) :
- avcodec_find_decoder(desc->id);
- if (codec)
- av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
- codec_string, codec->name, desc->name);
- }
-
- if (!codec) {
- av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
- exit_program(1);
- }
- if (codec->type != type) {
- av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
- exit_program(1);
- }
- return codec;
-}
-
-static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
-{
- char *codec_name = NULL;
-
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
- if (codec_name) {
- AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
- st->codec->codec_id = codec->id;
- return codec;
- } else
- return avcodec_find_decoder(st->codec->codec_id);
-}
-
-/* Add all the streams from the given input file to the global
- * list of input streams. */
-static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
-{
- int i, ret;
-
- for (i = 0; i < ic->nb_streams; i++) {
- AVStream *st = ic->streams[i];
- AVCodecContext *dec = st->codec;
- InputStream *ist = av_mallocz(sizeof(*ist));
- char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
- char *codec_tag = NULL;
- char *next;
-
- if (!ist)
- exit_program(1);
-
- GROW_ARRAY(input_streams, nb_input_streams);
- input_streams[nb_input_streams - 1] = ist;
-
- ist->st = st;
- ist->file_index = nb_input_files;
- ist->discard = 1;
- st->discard = AVDISCARD_ALL;
-
- ist->ts_scale = 1.0;
- MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
-
- ist->autorotate = 1;
- MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
-
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
- if (codec_tag) {
- uint32_t tag = strtol(codec_tag, &next, 0);
- if (*next)
- tag = AV_RL32(codec_tag);
- st->codec->codec_tag = tag;
- }
-
- ist->dec = choose_decoder(o, ic, st);
- ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec);
-
- ist->dec_ctx = avcodec_alloc_context3(ist->dec);
- if (!ist->dec_ctx) {
- av_log(NULL, AV_LOG_ERROR, "Error allocating the decoder context.\n");
- exit_program(1);
- }
-
- ret = avcodec_copy_context(ist->dec_ctx, dec);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
- exit_program(1);
- }
-
- switch (dec->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- ist->resample_height = ist->dec_ctx->height;
- ist->resample_width = ist->dec_ctx->width;
- ist->resample_pix_fmt = ist->dec_ctx->pix_fmt;
-
- MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
- if (framerate && av_parse_video_rate(&ist->framerate,
- framerate) < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
- framerate);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
- if (hwaccel) {
- if (!strcmp(hwaccel, "none"))
- ist->hwaccel_id = HWACCEL_NONE;
- else if (!strcmp(hwaccel, "auto"))
- ist->hwaccel_id = HWACCEL_AUTO;
- else {
- int i;
- for (i = 0; hwaccels[i].name; i++) {
- if (!strcmp(hwaccels[i].name, hwaccel)) {
- ist->hwaccel_id = hwaccels[i].id;
- break;
- }
- }
-
- if (!ist->hwaccel_id) {
- av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
- hwaccel);
- av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
- for (i = 0; hwaccels[i].name; i++)
- av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name);
- av_log(NULL, AV_LOG_FATAL, "\n");
- exit_program(1);
- }
- }
- }
-
- MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
- if (hwaccel_device) {
- ist->hwaccel_device = av_strdup(hwaccel_device);
- if (!ist->hwaccel_device)
- exit_program(1);
- }
- ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;
-
- break;
- case AVMEDIA_TYPE_AUDIO:
- guess_input_channel_layout(ist);
-
- ist->resample_sample_fmt = ist->dec_ctx->sample_fmt;
- ist->resample_sample_rate = ist->dec_ctx->sample_rate;
- ist->resample_channels = ist->dec_ctx->channels;
- ist->resample_channel_layout = ist->dec_ctx->channel_layout;
-
- break;
- case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_SUBTITLE:
- case AVMEDIA_TYPE_ATTACHMENT:
- case AVMEDIA_TYPE_UNKNOWN:
- break;
- default:
- abort();
- }
- }
-}
-
-static void assert_file_overwrite(const char *filename)
-{
- if (file_overwrite && file_skip) {
- fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
- exit_program(1);
- }
-
- if (!file_overwrite &&
- (!strchr(filename, ':') || filename[1] == ':' ||
- av_strstart(filename, "file:", NULL))) {
- if (avio_check(filename, 0) == 0) {
- if (!using_stdin && !file_skip) {
- fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
- fflush(stderr);
- if (!read_yesno()) {
- fprintf(stderr, "Not overwriting - exiting\n");
- exit_program(1);
- }
- }
- else {
- fprintf(stderr,"File '%s' already exists. Exiting.\n", filename);
- exit_program(1);
- }
- }
- }
-}
-
-static void dump_attachment(AVStream *st, const char *filename)
-{
- int ret;
- AVIOContext *out = NULL;
- AVDictionaryEntry *e;
-
- if (!st->codec->extradata_size) {
- av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
- nb_input_files - 1, st->index);
- return;
- }
- if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
- filename = e->value;
- if (!*filename) {
- av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
- "in stream #%d:%d.\n", nb_input_files - 1, st->index);
- exit_program(1);
- }
-
- assert_file_overwrite(filename);
-
- if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
- filename);
- exit_program(1);
- }
-
- avio_write(out, st->codec->extradata, st->codec->extradata_size);
- avio_flush(out);
- avio_close(out);
-}
-
-static int open_input_file(OptionsContext *o, const char *filename)
-{
- InputFile *f;
- AVFormatContext *ic;
- AVInputFormat *file_iformat = NULL;
- int err, i, ret;
- int64_t timestamp;
- uint8_t buf[128];
- AVDictionary **opts;
- AVDictionary *unused_opts = NULL;
- AVDictionaryEntry *e = NULL;
- int orig_nb_streams; // number of streams before avformat_find_stream_info
-
- if (o->format) {
- if (!(file_iformat = av_find_input_format(o->format))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
- exit_program(1);
- }
- }
-
- if (!strcmp(filename, "-"))
- filename = "pipe:";
-
- using_stdin |= !strncmp(filename, "pipe:", 5) ||
- !strcmp(filename, "/dev/stdin");
-
- /* get default parameters from command line */
- ic = avformat_alloc_context();
- if (!ic) {
- print_error(filename, AVERROR(ENOMEM));
- exit_program(1);
- }
- if (o->nb_audio_sample_rate) {
- snprintf(buf, sizeof(buf), "%d", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i);
- av_dict_set(&o->g->format_opts, "sample_rate", buf, 0);
- }
- if (o->nb_audio_channels) {
- /* because we set audio_channels based on both the "ac" and
- * "channel_layout" options, we need to check that the specified
- * demuxer actually has the "channels" option before setting it */
- if (file_iformat && file_iformat->priv_class &&
- av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ)) {
- snprintf(buf, sizeof(buf), "%d",
- o->audio_channels[o->nb_audio_channels - 1].u.i);
- av_dict_set(&o->g->format_opts, "channels", buf, 0);
- }
- }
- if (o->nb_frame_rates) {
- /* set the format-level framerate option;
- * this is important for video grabbers, e.g. x11 */
- if (file_iformat && file_iformat->priv_class &&
- av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ)) {
- av_dict_set(&o->g->format_opts, "framerate",
- o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
- }
- }
- if (o->nb_frame_sizes) {
- av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
- }
- if (o->nb_frame_pix_fmts)
- av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
-
- ic->flags |= AVFMT_FLAG_NONBLOCK;
- ic->interrupt_callback = int_cb;
-
- /* open the input file with generic libav function */
- err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
- if (err < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- assert_avoptions(o->g->format_opts);
-
- /* apply forced codec ids */
- for (i = 0; i < ic->nb_streams; i++)
- choose_decoder(o, ic, ic->streams[i]);
-
- /* Set AVCodecContext options for avformat_find_stream_info */
- opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
- orig_nb_streams = ic->nb_streams;
-
- /* If not enough info to get the stream parameters, we decode the
- first frames to get it. (used in mpeg case for example) */
- ret = avformat_find_stream_info(ic, opts);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
- avformat_close_input(&ic);
- exit_program(1);
- }
-
- timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
- /* add the stream start time */
- if (ic->start_time != AV_NOPTS_VALUE)
- timestamp += ic->start_time;
-
- /* if seeking requested, we execute it */
- if (o->start_time != AV_NOPTS_VALUE) {
- ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
- if (ret < 0) {
- av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
- filename, (double)timestamp / AV_TIME_BASE);
- }
- }
-
- /* update the current parameters so that they match the one of the input stream */
- add_input_streams(o, ic);
-
- /* dump the file content */
- av_dump_format(ic, nb_input_files, filename, 0);
-
- GROW_ARRAY(input_files, nb_input_files);
- f = av_mallocz(sizeof(*f));
- if (!f)
- exit_program(1);
- input_files[nb_input_files - 1] = f;
-
- f->ctx = ic;
- f->ist_index = nb_input_streams - ic->nb_streams;
- f->start_time = o->start_time;
- f->recording_time = o->recording_time;
- f->ts_offset = o->input_ts_offset - (copy_ts ? 0 : timestamp);
- f->nb_streams = ic->nb_streams;
- f->rate_emu = o->rate_emu;
- f->accurate_seek = o->accurate_seek;
-
- /* check if all codec options have been used */
- unused_opts = strip_specifiers(o->g->codec_opts);
- for (i = f->ist_index; i < nb_input_streams; i++) {
- e = NULL;
- while ((e = av_dict_get(input_streams[i]->decoder_opts, "", e,
- AV_DICT_IGNORE_SUFFIX)))
- av_dict_set(&unused_opts, e->key, NULL, 0);
- }
-
- e = NULL;
- while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
- 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);
- if (!option)
- continue;
- if (!(option->flags & AV_OPT_FLAG_DECODING_PARAM)) {
- av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
- "input file #%d (%s) is not a decoding option.\n", e->key,
- option->help ? option->help : "", nb_input_files - 1,
- filename);
- exit_program(1);
- }
-
- av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
- "input file #%d (%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 : "", nb_input_files - 1, filename);
- }
- av_dict_free(&unused_opts);
-
- for (i = 0; i < o->nb_dump_attachment; i++) {
- int j;
-
- for (j = 0; j < ic->nb_streams; j++) {
- AVStream *st = ic->streams[j];
-
- if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
- dump_attachment(st, o->dump_attachment[i].u.str);
- }
- }
-
- for (i = 0; i < orig_nb_streams; i++)
- av_dict_free(&opts[i]);
- av_freep(&opts);
-
- return 0;
-}
-
-static uint8_t *get_line(AVIOContext *s)
-{
- AVIOContext *line;
- uint8_t *buf;
- char c;
-
- if (avio_open_dyn_buf(&line) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
- exit_program(1);
- }
-
- while ((c = avio_r8(s)) && c != '\n')
- avio_w8(line, c);
- avio_w8(line, 0);
- avio_close_dyn_buf(line, &buf);
-
- return buf;
-}
-
-static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
-{
- int i, ret = -1;
- char filename[1000];
- const char *base[3] = { getenv("AVCONV_DATADIR"),
- getenv("HOME"),
- AVCONV_DATADIR,
- };
-
- for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) {
- if (!base[i])
- continue;
- if (codec_name) {
- snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", codec_name, preset_name);
- ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
- }
- if (ret < 0) {
- snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", preset_name);
- ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
- }
- }
- return ret;
-}
-
-static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
-{
- char *codec_name = NULL;
-
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
- if (!codec_name) {
- ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
- NULL, ost->st->codec->codec_type);
- ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
- } else if (!strcmp(codec_name, "copy"))
- ost->stream_copy = 1;
- else {
- ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
- ost->st->codec->codec_id = ost->enc->id;
- }
-}
-
-static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type)
-{
- OutputStream *ost;
- AVStream *st = avformat_new_stream(oc, NULL);
- int idx = oc->nb_streams - 1, ret = 0;
- char *bsf = NULL, *next, *codec_tag = NULL;
- AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
- double qscale = -1;
-
- if (!st) {
- av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
- exit_program(1);
- }
-
- if (oc->nb_streams - 1 < o->nb_streamid_map)
- st->id = o->streamid_map[oc->nb_streams - 1];
-
- GROW_ARRAY(output_streams, nb_output_streams);
- if (!(ost = av_mallocz(sizeof(*ost))))
- exit_program(1);
- output_streams[nb_output_streams - 1] = ost;
-
- ost->file_index = nb_output_files - 1;
- ost->index = idx;
- ost->st = st;
- st->codec->codec_type = type;
- choose_encoder(o, oc, ost);
-
- ost->enc_ctx = avcodec_alloc_context3(ost->enc);
- if (!ost->enc_ctx) {
- av_log(NULL, AV_LOG_ERROR, "Error allocating the encoding context.\n");
- exit_program(1);
- }
- ost->enc_ctx->codec_type = type;
-
- if (ost->enc) {
- AVIOContext *s = NULL;
- char *buf = NULL, *arg = NULL, *preset = NULL;
-
- ost->encoder_opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
-
- MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
- if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
- do {
- buf = get_line(s);
- if (!buf[0] || buf[0] == '#') {
- av_free(buf);
- continue;
- }
- if (!(arg = strchr(buf, '='))) {
- av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
- exit_program(1);
- }
- *arg++ = 0;
- av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);
- av_free(buf);
- } while (!s->eof_reached);
- avio_close(s);
- }
- if (ret) {
- av_log(NULL, AV_LOG_FATAL,
- "Preset %s specified for stream %d:%d, but could not be opened.\n",
- preset, ost->file_index, ost->index);
- exit_program(1);
- }
- } else {
- ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
- }
-
- ost->max_frames = INT64_MAX;
- MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
-
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
- while (bsf) {
- if (next = strchr(bsf, ','))
- *next++ = 0;
- if (!(bsfc = av_bitstream_filter_init(bsf))) {
- av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
- exit_program(1);
- }
- if (bsfc_prev)
- bsfc_prev->next = bsfc;
- else
- ost->bitstream_filters = bsfc;
-
- bsfc_prev = bsfc;
- bsf = next;
- }
-
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
- if (codec_tag) {
- uint32_t tag = strtol(codec_tag, &next, 0);
- if (*next)
- tag = AV_RL32(codec_tag);
- ost->enc_ctx->codec_tag = tag;
- }
-
- MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
- if (qscale >= 0) {
- ost->enc_ctx->flags |= CODEC_FLAG_QSCALE;
- ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
- }
-
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- ost->enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
-
- av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
-
- ost->pix_fmts[0] = ost->pix_fmts[1] = AV_PIX_FMT_NONE;
- ost->last_mux_dts = AV_NOPTS_VALUE;
-
- return ost;
-}
-
-static void parse_matrix_coeffs(uint16_t *dest, const char *str)
-{
- int i;
- const char *p = str;
- for (i = 0;; i++) {
- dest[i] = atoi(p);
- if (i == 63)
- break;
- p = strchr(p, ',');
- if (!p) {
- av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
- exit_program(1);
- }
- p++;
- }
-}
-
-/* read file contents into a string */
-static uint8_t *read_file(const char *filename)
-{
- AVIOContext *pb = NULL;
- AVIOContext *dyn_buf = NULL;
- int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
- uint8_t buf[1024], *str;
-
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
- return NULL;
- }
-
- ret = avio_open_dyn_buf(&dyn_buf);
- if (ret < 0) {
- avio_closep(&pb);
- return NULL;
- }
- while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
- avio_write(dyn_buf, buf, ret);
- avio_w8(dyn_buf, 0);
- avio_closep(&pb);
-
- ret = avio_close_dyn_buf(dyn_buf, &str);
- if (ret < 0)
- return NULL;
- return str;
-}
-
-static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
- OutputStream *ost)
-{
- AVStream *st = ost->st;
- char *filter = NULL, *filter_script = NULL;
-
- MATCH_PER_STREAM_OPT(filter_scripts, str, filter_script, oc, st);
- MATCH_PER_STREAM_OPT(filters, str, filter, oc, st);
-
- if (filter_script && filter) {
- av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
- "output stream #%d:%d.\n", nb_output_files, st->index);
- exit_program(1);
- }
-
- if (filter_script)
- return read_file(filter_script);
- else if (filter)
- return av_strdup(filter);
-
- return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ?
- "null" : "anull");
-}
-
-static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *video_enc;
- char *frame_aspect_ratio = NULL;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO);
- st = ost->st;
- video_enc = ost->enc_ctx;
-
- MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
- if (frame_aspect_ratio)
- ost->frame_aspect_ratio = parse_frame_aspect_ratio(frame_aspect_ratio);
-
- if (!ost->stream_copy) {
- const char *p = NULL;
- char *frame_rate = NULL, *frame_size = NULL;
- char *frame_pix_fmt = NULL;
- char *intra_matrix = NULL, *inter_matrix = NULL;
- int do_pass = 0;
- int i;
-
- MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
- if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
- if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
- if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
- av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
- exit_program(1);
- }
- st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
-
- MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
- if (intra_matrix) {
- if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
- exit_program(1);
- }
- parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
- }
- MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
- if (inter_matrix) {
- if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
- exit_program(1);
- }
- parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
- }
-
- MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
- for (i = 0; p; i++) {
- int start, end, q;
- int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
- if (e != 3) {
- av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
- exit_program(1);
- }
- video_enc->rc_override =
- av_realloc(video_enc->rc_override,
- sizeof(RcOverride) * (i + 1));
- if (!video_enc->rc_override) {
- av_log(NULL, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n");
- exit_program(1);
- }
- video_enc->rc_override[i].start_frame = start;
- video_enc->rc_override[i].end_frame = end;
- if (q > 0) {
- video_enc->rc_override[i].qscale = q;
- video_enc->rc_override[i].quality_factor = 1.0;
- }
- else {
- video_enc->rc_override[i].qscale = 0;
- video_enc->rc_override[i].quality_factor = -q/100.0;
- }
- p = strchr(p, '/');
- if (p) p++;
- }
- video_enc->rc_override_count = i;
- video_enc->intra_dc_precision = intra_dc_precision - 8;
-
- /* two pass mode */
- MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
- if (do_pass) {
- if (do_pass == 1) {
- video_enc->flags |= CODEC_FLAG_PASS1;
- } else {
- video_enc->flags |= CODEC_FLAG_PASS2;
- }
- }
-
- MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
- if (ost->logfile_prefix &&
- !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
- exit_program(1);
-
- MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
- if (ost->forced_keyframes)
- ost->forced_keyframes = av_strdup(ost->forced_keyframes);
-
- MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
-
- ost->top_field_first = -1;
- MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
-
-
- ost->avfilter = get_ost_filters(o, oc, ost);
- if (!ost->avfilter)
- exit_program(1);
- } else {
- MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
- }
-
- return ost;
-}
-
-static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc)
-{
- AVStream *st;
- OutputStream *ost;
- AVCodecContext *audio_enc;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO);
- st = ost->st;
-
- audio_enc = ost->enc_ctx;
- audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
-
- if (!ost->stream_copy) {
- char *sample_fmt = NULL;
-
- MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
-
- MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
- if (sample_fmt &&
- (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
- av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
- exit_program(1);
- }
-
- MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
-
- ost->avfilter = get_ost_filters(o, oc, ost);
- if (!ost->avfilter)
- exit_program(1);
- }
-
- return ost;
-}
-
-static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc)
-{
- OutputStream *ost;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA);
- if (!ost->stream_copy) {
- av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
- exit_program(1);
- }
-
- return ost;
-}
-
-static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc)
-{
- OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT);
- ost->stream_copy = 1;
- ost->finished = 1;
- return ost;
-}
-
-static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc)
-{
- OutputStream *ost;
- AVCodecContext *subtitle_enc;
-
- ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE);
- subtitle_enc = ost->enc_ctx;
-
- subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
-
- return ost;
-}
-
-/* arg format is "output-stream-index:streamid-value". */
-static int opt_streamid(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- int idx;
- char *p;
- char idx_str[16];
-
- av_strlcpy(idx_str, arg, sizeof(idx_str));
- p = strchr(idx_str, ':');
- if (!p) {
- av_log(NULL, AV_LOG_FATAL,
- "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
- arg, opt);
- exit_program(1);
- }
- *p++ = '\0';
- idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX);
- o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
- o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
- return 0;
-}
-
-static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
-{
- AVFormatContext *is = ifile->ctx;
- AVFormatContext *os = ofile->ctx;
- AVChapter **tmp;
- int i;
-
- tmp = av_realloc(os->chapters, sizeof(*os->chapters) * (is->nb_chapters + os->nb_chapters));
- if (!tmp)
- return AVERROR(ENOMEM);
- os->chapters = tmp;
-
- for (i = 0; i < is->nb_chapters; i++) {
- AVChapter *in_ch = is->chapters[i], *out_ch;
- int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
- int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
- AV_TIME_BASE_Q, in_ch->time_base);
- int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
- av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
-
-
- if (in_ch->end < ts_off)
- continue;
- if (rt != INT64_MAX && in_ch->start > rt + ts_off)
- break;
-
- out_ch = av_mallocz(sizeof(AVChapter));
- if (!out_ch)
- return AVERROR(ENOMEM);
-
- out_ch->id = in_ch->id;
- out_ch->time_base = in_ch->time_base;
- out_ch->start = FFMAX(0, in_ch->start - ts_off);
- out_ch->end = FFMIN(rt, in_ch->end - ts_off);
-
- if (copy_metadata)
- av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
-
- os->chapters[os->nb_chapters++] = out_ch;
- }
- return 0;
-}
-
-static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
- AVFormatContext *oc)
-{
- OutputStream *ost;
-
- switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
- ofilter->out_tmp->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
- "currently.\n");
- exit_program(1);
- }
-
- ost->source_index = -1;
- ost->filter = ofilter;
-
- ofilter->ost = ost;
-
- if (ost->stream_copy) {
- av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
- "which is fed from a complex filtergraph. Filtering and streamcopy "
- "cannot be used together.\n", ost->file_index, ost->index);
- exit_program(1);
- }
-
- if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
- exit_program(1);
- }
- avfilter_inout_free(&ofilter->out_tmp);
-}
-
-static int configure_complex_filters(void)
-{
- int i, ret = 0;
-
- for (i = 0; i < nb_filtergraphs; i++)
- if (!filtergraphs[i]->graph &&
- (ret = configure_filtergraph(filtergraphs[i])) < 0)
- return ret;
- return 0;
-}
-
-static int open_output_file(OptionsContext *o, const char *filename)
-{
- AVFormatContext *oc;
- int i, j, err;
- AVOutputFormat *file_oformat;
- OutputFile *of;
- OutputStream *ost;
- InputStream *ist;
- AVDictionary *unused_opts = NULL;
- AVDictionaryEntry *e = NULL;
-
- if (configure_complex_filters() < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
- exit_program(1);
- }
-
- GROW_ARRAY(output_files, nb_output_files);
- of = av_mallocz(sizeof(*of));
- if (!of)
- exit_program(1);
- output_files[nb_output_files - 1] = of;
-
- of->ost_index = nb_output_streams;
- of->recording_time = o->recording_time;
- of->start_time = o->start_time;
- of->limit_filesize = o->limit_filesize;
- of->shortest = o->shortest;
- av_dict_copy(&of->opts, o->g->format_opts, 0);
-
- if (!strcmp(filename, "-"))
- filename = "pipe:";
-
- oc = avformat_alloc_context();
- if (!oc) {
- print_error(filename, AVERROR(ENOMEM));
- exit_program(1);
- }
- of->ctx = oc;
- if (o->recording_time != INT64_MAX)
- oc->duration = o->recording_time;
-
- if (o->format) {
- file_oformat = av_guess_format(o->format, NULL, NULL);
- if (!file_oformat) {
- av_log(NULL, AV_LOG_FATAL, "Requested output format '%s' is not a suitable output format\n", o->format);
- exit_program(1);
- }
- } else {
- file_oformat = av_guess_format(NULL, filename, NULL);
- if (!file_oformat) {
- av_log(NULL, AV_LOG_FATAL, "Unable to find a suitable output format for '%s'\n",
- filename);
- exit_program(1);
- }
- }
-
- oc->oformat = file_oformat;
- oc->interrupt_callback = int_cb;
- av_strlcpy(oc->filename, filename, sizeof(oc->filename));
-
- /* create streams for all unlabeled output pads */
- for (i = 0; i < nb_filtergraphs; i++) {
- FilterGraph *fg = filtergraphs[i];
- for (j = 0; j < fg->nb_outputs; j++) {
- OutputFilter *ofilter = fg->outputs[j];
-
- if (!ofilter->out_tmp || ofilter->out_tmp->name)
- continue;
-
- switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
- ofilter->out_tmp->pad_idx)) {
- case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
- case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
- case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
- }
- init_output_filter(ofilter, o, oc);
- }
- }
-
- if (!o->nb_stream_maps) {
- /* pick the "best" stream of each type */
-#define NEW_STREAM(type, index)\
- if (index >= 0) {\
- ost = new_ ## type ## _stream(o, oc);\
- ost->source_index = index;\
- ost->sync_ist = input_streams[index];\
- input_streams[index]->discard = 0;\
- input_streams[index]->st->discard = AVDISCARD_NONE;\
- }
-
- /* video: highest resolution */
- if (!o->video_disable && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
- int area = 0, idx = -1;
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- ist->st->codec->width * ist->st->codec->height > area) {
- area = ist->st->codec->width * ist->st->codec->height;
- idx = i;
- }
- }
- NEW_STREAM(video, idx);
- }
-
- /* audio: most channels */
- if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
- int channels = 0, idx = -1;
- for (i = 0; i < nb_input_streams; i++) {
- ist = input_streams[i];
- if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- ist->st->codec->channels > channels) {
- channels = ist->st->codec->channels;
- idx = i;
- }
- }
- NEW_STREAM(audio, idx);
- }
-
- /* subtitles: pick first */
- if (!o->subtitle_disable && oc->oformat->subtitle_codec != AV_CODEC_ID_NONE) {
- for (i = 0; i < nb_input_streams; i++)
- if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- NEW_STREAM(subtitle, i);
- break;
- }
- }
- /* do something with data? */
- } else {
- for (i = 0; i < o->nb_stream_maps; i++) {
- StreamMap *map = &o->stream_maps[i];
-
- if (map->disabled)
- continue;
-
- if (map->linklabel) {
- FilterGraph *fg;
- OutputFilter *ofilter = NULL;
- int j, k;
-
- for (j = 0; j < nb_filtergraphs; j++) {
- fg = filtergraphs[j];
- for (k = 0; k < fg->nb_outputs; k++) {
- AVFilterInOut *out = fg->outputs[k]->out_tmp;
- if (out && !strcmp(out->name, map->linklabel)) {
- ofilter = fg->outputs[k];
- goto loop_end;
- }
- }
- }
-loop_end:
- if (!ofilter) {
- av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
- "in any defined filter graph.\n", map->linklabel);
- exit_program(1);
- }
- init_output_filter(ofilter, o, oc);
- } else {
- ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
- switch (ist->st->codec->codec_type) {
- case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc); break;
- case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc); break;
- case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream(o, oc); break;
- case AVMEDIA_TYPE_DATA: ost = new_data_stream(o, oc); break;
- case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc); break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
- map->file_index, map->stream_index);
- exit_program(1);
- }
-
- ost->source_index = input_files[map->file_index]->ist_index + map->stream_index;
- ost->sync_ist = input_streams[input_files[map->sync_file_index]->ist_index +
- map->sync_stream_index];
- ist->discard = 0;
- ist->st->discard = AVDISCARD_NONE;
- }
- }
- }
-
- /* handle attached files */
- for (i = 0; i < o->nb_attachments; i++) {
- AVIOContext *pb;
- uint8_t *attachment;
- const char *p;
- int64_t len;
-
- if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
- o->attachments[i]);
- exit_program(1);
- }
- if ((len = avio_size(pb)) <= 0) {
- av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
- o->attachments[i]);
- exit_program(1);
- }
- if (!(attachment = av_malloc(len))) {
- av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
- o->attachments[i]);
- exit_program(1);
- }
- avio_read(pb, attachment, len);
-
- ost = new_attachment_stream(o, oc);
- ost->stream_copy = 0;
- ost->source_index = -1;
- ost->attachment_filename = o->attachments[i];
- ost->st->codec->extradata = attachment;
- ost->st->codec->extradata_size = len;
-
- p = strrchr(o->attachments[i], '/');
- av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
- avio_close(pb);
- }
-
- /* check if all codec options have been used */
- unused_opts = strip_specifiers(o->g->codec_opts);
- for (i = of->ost_index; i < nb_output_streams; i++) {
- e = NULL;
- while ((e = av_dict_get(output_streams[i]->encoder_opts, "", e,
- AV_DICT_IGNORE_SUFFIX)))
- av_dict_set(&unused_opts, e->key, NULL, 0);
- }
-
- e = NULL;
- while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
- 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);
- if (!option)
- continue;
- if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
- av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
- "output file #%d (%s) is not an encoding option.\n", e->key,
- option->help ? option->help : "", nb_output_files - 1,
- filename);
- exit_program(1);
- }
-
- av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
- "output file #%d (%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 : "", nb_output_files - 1, filename);
- }
- av_dict_free(&unused_opts);
-
- /* check filename in case of an image number is expected */
- if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
- if (!av_filename_number_test(oc->filename)) {
- print_error(oc->filename, AVERROR(EINVAL));
- exit_program(1);
- }
- }
-
- if (!(oc->oformat->flags & AVFMT_NOFILE)) {
- /* test if it already exists to avoid losing precious files */
- assert_file_overwrite(filename);
-
- /* open the file */
- if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
- &oc->interrupt_callback,
- &of->opts)) < 0) {
- print_error(filename, err);
- exit_program(1);
- }
- }
-
- if (o->mux_preload) {
- uint8_t buf[64];
- snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
- av_dict_set(&of->opts, "preload", buf, 0);
- }
- oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
- oc->flags |= AVFMT_FLAG_NONBLOCK;
-
- /* copy metadata */
- for (i = 0; i < o->nb_metadata_map; i++) {
- char *p;
- int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
-
- if (in_file_index >= nb_input_files) {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
- exit_program(1);
- }
- copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
- in_file_index >= 0 ?
- input_files[in_file_index]->ctx : NULL, o);
- }
-
- /* copy chapters */
- if (o->chapters_input_file >= nb_input_files) {
- if (o->chapters_input_file == INT_MAX) {
- /* copy chapters from the first input file that has them*/
- o->chapters_input_file = -1;
- for (i = 0; i < nb_input_files; i++)
- if (input_files[i]->ctx->nb_chapters) {
- o->chapters_input_file = i;
- break;
- }
- } else {
- av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
- o->chapters_input_file);
- exit_program(1);
- }
- }
- if (o->chapters_input_file >= 0)
- copy_chapters(input_files[o->chapters_input_file], of,
- !o->metadata_chapters_manual);
-
- /* copy global metadata by default */
- if (!o->metadata_global_manual && nb_input_files)
- av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
- AV_DICT_DONT_OVERWRITE);
- if (!o->metadata_streams_manual)
- for (i = of->ost_index; i < nb_output_streams; i++) {
- InputStream *ist;
- if (output_streams[i]->source_index < 0) /* this is true e.g. for attached files */
- continue;
- ist = input_streams[output_streams[i]->source_index];
- av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
- }
-
- /* process manually set metadata */
- for (i = 0; i < o->nb_metadata; i++) {
- AVDictionary **m;
- char type, *val;
- const char *stream_spec;
- int index = 0, j, ret;
-
- val = strchr(o->metadata[i].u.str, '=');
- if (!val) {
- av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
- o->metadata[i].u.str);
- exit_program(1);
- }
- *val++ = 0;
-
- parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
- if (type == 's') {
- for (j = 0; j < oc->nb_streams; j++) {
- if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
- av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
- } else if (ret < 0)
- exit_program(1);
- }
- }
- else {
- switch (type) {
- case 'g':
- m = &oc->metadata;
- break;
- case 'c':
- if (index < 0 || index >= oc->nb_chapters) {
- av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
- exit_program(1);
- }
- m = &oc->chapters[index]->metadata;
- break;
- default:
- av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
- exit_program(1);
- }
- av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
- }
- }
-
- return 0;
-}
-
-static int opt_target(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
- static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
-
- if (!strncmp(arg, "pal-", 4)) {
- norm = PAL;
- arg += 4;
- } else if (!strncmp(arg, "ntsc-", 5)) {
- norm = NTSC;
- arg += 5;
- } else if (!strncmp(arg, "film-", 5)) {
- norm = FILM;
- arg += 5;
- } else {
- /* Try to determine PAL/NTSC by peeking in the input files */
- if (nb_input_files) {
- int i, j, fr;
- for (j = 0; j < nb_input_files; j++) {
- for (i = 0; i < input_files[j]->nb_streams; i++) {
- AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
- if (c->codec_type != AVMEDIA_TYPE_VIDEO ||
- !c->time_base.num)
- continue;
- fr = c->time_base.den * 1000 / c->time_base.num;
- if (fr == 25000) {
- norm = PAL;
- break;
- } else if ((fr == 29970) || (fr == 23976)) {
- norm = NTSC;
- break;
- }
- }
- if (norm != UNKNOWN)
- break;
- }
- }
- if (norm != UNKNOWN)
- av_log(NULL, AV_LOG_INFO, "Assuming %s for target.\n", norm == PAL ? "PAL" : "NTSC");
- }
-
- if (norm == UNKNOWN) {
- av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
- av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
- av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
- exit_program(1);
- }
-
- if (!strcmp(arg, "vcd")) {
- opt_video_codec(o, "c:v", "mpeg1video");
- opt_audio_codec(o, "c:a", "mp2");
- parse_option(o, "f", "vcd", options);
-
- parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
- parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
-
- opt_default(NULL, "b", "1150000");
- opt_default(NULL, "maxrate", "1150000");
- opt_default(NULL, "minrate", "1150000");
- opt_default(NULL, "bufsize", "327680"); // 40*1024*8;
-
- opt_default(NULL, "b:a", "224000");
- parse_option(o, "ar", "44100", options);
- parse_option(o, "ac", "2", options);
-
- opt_default(NULL, "packetsize", "2324");
- opt_default(NULL, "muxrate", "3528"); // 2352 * 75 / 50;
-
- /* We have to offset the PTS, so that it is consistent with the SCR.
- SCR starts at 36000, but the first two packs contain only padding
- and the first pack from the other stream, respectively, may also have
- been written before.
- So the real data starts at SCR 36000+3*1200. */
- o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44
- } else if (!strcmp(arg, "svcd")) {
-
- opt_video_codec(o, "c:v", "mpeg2video");
- opt_audio_codec(o, "c:a", "mp2");
- parse_option(o, "f", "svcd", options);
-
- parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
- parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
-
- opt_default(NULL, "b", "2040000");
- opt_default(NULL, "maxrate", "2516000");
- opt_default(NULL, "minrate", "0"); // 1145000;
- opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
- opt_default(NULL, "scan_offset", "1");
-
-
- opt_default(NULL, "b:a", "224000");
- parse_option(o, "ar", "44100", options);
-
- opt_default(NULL, "packetsize", "2324");
-
- } else if (!strcmp(arg, "dvd")) {
-
- opt_video_codec(o, "c:v", "mpeg2video");
- opt_audio_codec(o, "c:a", "ac3");
- parse_option(o, "f", "dvd", options);
-
- parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
- parse_option(o, "r", frame_rates[norm], options);
- opt_default(NULL, "g", norm == PAL ? "15" : "18");
-
- opt_default(NULL, "b", "6000000");
- opt_default(NULL, "maxrate", "9000000");
- opt_default(NULL, "minrate", "0"); // 1500000;
- opt_default(NULL, "bufsize", "1835008"); // 224*1024*8;
-
- opt_default(NULL, "packetsize", "2048"); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
- opt_default(NULL, "muxrate", "25200"); // from mplex project: data_rate = 1260000. mux_rate = data_rate / 50
-
- opt_default(NULL, "b:a", "448000");
- parse_option(o, "ar", "48000", options);
-
- } else if (!strncmp(arg, "dv", 2)) {
-
- parse_option(o, "f", "dv", options);
-
- parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
- parse_option(o, "pix_fmt", !strncmp(arg, "dv50", 4) ? "yuv422p" :
- norm == PAL ? "yuv420p" : "yuv411p", options);
- parse_option(o, "r", frame_rates[norm], options);
-
- parse_option(o, "ar", "48000", options);
- parse_option(o, "ac", "2", options);
-
- } else {
- av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
- return AVERROR(EINVAL);
- }
-
- av_dict_copy(&o->g->codec_opts, codec_opts, 0);
- av_dict_copy(&o->g->format_opts, format_opts, 0);
-
- return 0;
-}
-
-static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
-{
- av_free (vstats_filename);
- vstats_filename = av_strdup (arg);
- return 0;
-}
-
-static int opt_vstats(void *optctx, const char *opt, const char *arg)
-{
- char filename[40];
- time_t today2 = time(NULL);
- struct tm *today = localtime(&today2);
-
- snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
- today->tm_sec);
- return opt_vstats_file(NULL, opt, filename);
-}
-
-static int opt_video_frames(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "frames:v", arg, options);
-}
-
-static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "frames:a", arg, options);
-}
-
-static int opt_data_frames(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "frames:d", arg, options);
-}
-
-static int opt_video_tag(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "tag:v", arg, options);
-}
-
-static int opt_audio_tag(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "tag:a", arg, options);
-}
-
-static int opt_subtitle_tag(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "tag:s", arg, options);
-}
-
-static int opt_video_filters(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "filter:v", arg, options);
-}
-
-static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "filter:a", arg, options);
-}
-
-static int opt_vsync(void *optctx, const char *opt, const char *arg)
-{
- if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR;
- else if (!av_strcasecmp(arg, "vfr")) video_sync_method = VSYNC_VFR;
- else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
-
- if (video_sync_method == VSYNC_AUTO)
- video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
- return 0;
-}
-
-static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- char layout_str[32];
- char *stream_str;
- char *ac_str;
- int ret, channels, ac_str_size;
- uint64_t layout;
-
- layout = av_get_channel_layout(arg);
- if (!layout) {
- av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg);
- return AVERROR(EINVAL);
- }
- snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
- ret = opt_default(NULL, opt, layout_str);
- if (ret < 0)
- return ret;
-
- /* set 'ac' option based on channel layout */
- channels = av_get_channel_layout_nb_channels(layout);
- snprintf(layout_str, sizeof(layout_str), "%d", channels);
- stream_str = strchr(opt, ':');
- ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0);
- ac_str = av_mallocz(ac_str_size);
- if (!ac_str)
- return AVERROR(ENOMEM);
- av_strlcpy(ac_str, "ac", 3);
- if (stream_str)
- av_strlcat(ac_str, stream_str, ac_str_size);
- ret = parse_option(o, ac_str, layout_str, options);
- av_free(ac_str);
-
- return ret;
-}
-
-static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
-{
- OptionsContext *o = optctx;
- return parse_option(o, "q:a", arg, options);
-}
-
-static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
-{
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
- return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
- if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
- return AVERROR(ENOMEM);
- return 0;
-}
-
-static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
-{
- uint8_t *graph_desc = read_file(arg);
- if (!graph_desc)
- return AVERROR(EINVAL);
-
- GROW_ARRAY(filtergraphs, nb_filtergraphs);
- if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
- return AVERROR(ENOMEM);
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
- filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
- return 0;
-}
-
-void show_help_default(const char *opt, const char *arg)
-{
- /* per-file options have at least one of those set */
- const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
- int show_advanced = 0, show_avoptions = 0;
-
- if (opt && *opt) {
- if (!strcmp(opt, "long"))
- show_advanced = 1;
- else if (!strcmp(opt, "full"))
- show_advanced = show_avoptions = 1;
- else
- av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
- }
-
- show_usage();
-
- printf("Getting help:\n"
- " -h -- print basic options\n"
- " -h long -- print more options\n"
- " -h full -- print all options (including all format and codec specific options, very long)\n"
- " See man %s for detailed description of the options.\n"
- "\n", program_name);
-
- show_help_options(options, "Print help / information / capabilities:",
- OPT_EXIT, 0, 0);
-
- show_help_options(options, "Global options (affect whole program "
- "instead of just one file:",
- 0, per_file | OPT_EXIT | OPT_EXPERT, 0);
- if (show_advanced)
- show_help_options(options, "Advanced global options:", OPT_EXPERT,
- per_file | OPT_EXIT, 0);
-
- show_help_options(options, "Per-file main options:", 0,
- OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |
- OPT_EXIT, per_file);
- if (show_advanced)
- show_help_options(options, "Advanced per-file options:",
- OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);
-
- show_help_options(options, "Video options:",
- OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
- if (show_advanced)
- show_help_options(options, "Advanced Video options:",
- OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);
-
- show_help_options(options, "Audio options:",
- OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);
- if (show_advanced)
- show_help_options(options, "Advanced Audio options:",
- OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);
- show_help_options(options, "Subtitle options:",
- OPT_SUBTITLE, 0, 0);
- printf("\n");
-
- if (show_avoptions) {
- int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
- show_help_children(avcodec_get_class(), flags);
- show_help_children(avformat_get_class(), flags);
- show_help_children(sws_get_class(), flags);
- show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM);
- }
-}
-
-void show_usage(void)
-{
- printf("Hyper fast Audio and Video encoder\n");
- printf("usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
- printf("\n");
-}
-
-enum OptGroup {
- GROUP_OUTFILE,
- GROUP_INFILE,
-};
-
-static const OptionGroupDef groups[] = {
- [GROUP_OUTFILE] = { "output file", NULL, OPT_OUTPUT },
- [GROUP_INFILE] = { "input file", "i", OPT_INPUT },
-};
-
-static int open_files(OptionGroupList *l, const char *inout,
- int (*open_file)(OptionsContext*, const char*))
-{
- int i, ret;
-
- for (i = 0; i < l->nb_groups; i++) {
- OptionGroup *g = &l->groups[i];
- OptionsContext o;
-
- init_options(&o);
- o.g = g;
-
- ret = parse_optgroup(&o, g);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file "
- "%s.\n", inout, g->arg);
- return ret;
- }
-
- av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg);
- ret = open_file(&o, g->arg);
- uninit_options(&o);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n",
- inout, g->arg);
- return ret;
- }
- av_log(NULL, AV_LOG_DEBUG, "Successfully opened the file.\n");
- }
-
- return 0;
-}
-
-int avconv_parse_options(int argc, char **argv)
-{
- OptionParseContext octx;
- uint8_t error[128];
- int ret;
-
- memset(&octx, 0, sizeof(octx));
-
- /* split the commandline into an internal representation */
- ret = split_commandline(&octx, argc, argv, options, groups,
- FF_ARRAY_ELEMS(groups));
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");
- goto fail;
- }
-
- /* apply global options */
- ret = parse_optgroup(NULL, &octx.global_opts);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");
- goto fail;
- }
-
- /* open input files */
- ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
- goto fail;
- }
-
- /* open output files */
- ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
- if (ret < 0) {
- av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
- goto fail;
- }
-
-fail:
- uninit_parse_context(&octx);
- if (ret < 0) {
- av_strerror(ret, error, sizeof(error));
- av_log(NULL, AV_LOG_FATAL, "%s\n", error);
- }
- return ret;
-}
-
-#define OFFSET(x) offsetof(OptionsContext, x)
-const OptionDef options[] = {
- /* main options */
-#include "cmdutils_common_opts.h"
- { "f", HAS_ARG | OPT_STRING | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(format) },
- "force format", "fmt" },
- { "y", OPT_BOOL, { &file_overwrite },
- "overwrite output files" },
- { "n", OPT_BOOL, { &file_skip },
- "never overwrite output files" },
- { "c", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
- "codec name", "codec" },
- { "codec", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
- "codec name", "codec" },
- { "pre", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(presets) },
- "preset name", "preset" },
- { "map", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_map },
- "set input stream mapping",
- "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
- { "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(metadata_map) },
- "set metadata information of outfile from infile",
- "outfile[,metadata]:infile[,metadata]" },
- { "map_chapters", HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET |
- OPT_OUTPUT, { .off = OFFSET(chapters_input_file) },
- "set chapters mapping", "input_file_index" },
- { "t", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) },
- "record or transcode \"duration\" seconds of audio/video",
- "duration" },
- { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },
- "set the limit file size in bytes", "limit_size" },
- { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
- "set the start time offset", "time_off" },
- { "accurate_seek", OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
- OPT_INPUT, { .off = OFFSET(accurate_seek) },
- "enable/disable accurate seeking with -ss" },
- { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
- "set the input ts offset", "time_off" },
- { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(ts_scale) },
- "set the input ts scale", "scale" },
- { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(metadata) },
- "add metadata", "string=string" },
- { "dframes", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
- OPT_OUTPUT, { .func_arg = opt_data_frames },
- "set the number of data frames to record", "number" },
- { "benchmark", OPT_BOOL | OPT_EXPERT, { &do_benchmark },
- "add timings for benchmarking" },
- { "timelimit", HAS_ARG | OPT_EXPERT, { .func_arg = opt_timelimit },
- "set max runtime in seconds", "limit" },
- { "dump", OPT_BOOL | OPT_EXPERT, { &do_pkt_dump },
- "dump each input packet" },
- { "hex", OPT_BOOL | OPT_EXPERT, { &do_hex_dump },
- "when dumping packets, also dump the payload" },
- { "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
- OPT_INPUT, { .off = OFFSET(rate_emu) },
- "read input at native frame rate", "" },
- { "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
- "specify target file type (\"vcd\", \"svcd\", \"dvd\","
- " \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
- { "vsync", HAS_ARG | OPT_EXPERT, { opt_vsync },
- "video sync method", "" },
- { "async", HAS_ARG | OPT_INT | OPT_EXPERT, { &audio_sync_method },
- "audio sync method", "" },
- { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &audio_drift_threshold },
- "audio drift threshold", "threshold" },
- { "copyts", OPT_BOOL | OPT_EXPERT, { &copy_ts },
- "copy timestamps" },
- { "copytb", OPT_BOOL | OPT_EXPERT, { &copy_tb },
- "copy input stream time base when stream copying" },
- { "shortest", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
- OPT_OUTPUT, { .off = OFFSET(shortest) },
- "finish encoding within shortest input" },
- { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_delta_threshold },
- "timestamp discontinuity delta threshold", "threshold" },
- { "xerror", OPT_BOOL | OPT_EXPERT, { &exit_on_error },
- "exit on error", "error" },
- { "copyinkf", OPT_BOOL | OPT_EXPERT | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(copy_initial_nonkeyframes) },
- "copy initial non-keyframes" },
- { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frames) },
- "set the number of frames to record", "number" },
- { "tag", OPT_STRING | HAS_ARG | OPT_SPEC |
- OPT_EXPERT | OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(codec_tags) },
- "force codec tag/fourcc", "fourcc/tag" },
- { "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
- "use fixed quality scale (VBR)", "q" },
- { "qscale", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
- "use fixed quality scale (VBR)", "q" },
- { "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
- "set stream filterchain", "filter_list" },
- { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
- "read stream filtergraph description from a file", "filename" },
- { "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
- "create a complex filtergraph", "graph_description" },
- { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
- "read complex filtergraph description from a file", "filename" },
- { "stats", OPT_BOOL, { &print_stats },
- "print progress report during encoding", },
- { "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
- OPT_OUTPUT, { .func_arg = opt_attach },
- "add an attachment to the output file", "filename" },
- { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
- "extract an attachment into a file", "filename" },
-
- /* video options */
- { "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
- "set the number of video frames to record", "number" },
- { "r", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_rates) },
- "set frame rate (Hz value, fraction or abbreviation)", "rate" },
- { "s", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) },
- "set frame size (WxH or abbreviation)", "size" },
- { "aspect", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(frame_aspect_ratios) },
- "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
- { "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
- "set pixel format", "format" },
- { "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(video_disable) },
- "disable video" },
- { "vdt", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &video_discard },
- "discard threshold", "n" },
- { "rc_override", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(rc_overrides) },
- "rate control override for specific intervals", "override" },
- { "vcodec", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_INPUT |
- OPT_OUTPUT, { .func_arg = opt_video_codec },
- "force video codec ('copy' to copy stream)", "codec" },
- { "pass", OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT | OPT_OUTPUT, { .off = OFFSET(pass) },
- "select the pass number (1 or 2)", "n" },
- { "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
- "select two pass log file name prefix", "prefix" },
- { "vstats", OPT_VIDEO | OPT_EXPERT , { &opt_vstats },
- "dump video coding statistics to file" },
- { "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
- "dump video coding statistics to file", "file" },
- { "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
- "video filters", "filter list" },
- { "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(intra_matrices) },
- "specify intra matrix coeffs", "matrix" },
- { "inter_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(inter_matrices) },
- "specify inter matrix coeffs", "matrix" },
- { "top", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_INT| OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(top_field_first) },
- "top=1/bottom=0/auto=-1 field first", "" },
- { "dc", OPT_VIDEO | OPT_INT | HAS_ARG | OPT_EXPERT , { &intra_dc_precision },
- "intra_dc_precision", "precision" },
- { "vtag", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_video_tag },
- "force video tag/fourcc", "fourcc/tag" },
- { "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
- "show QP histogram" },
- { "force_fps", OPT_VIDEO | OPT_BOOL | OPT_EXPERT | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(force_fps) },
- "force the selected framerate, disable the best supported framerate selection" },
- { "streamid", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_streamid },
- "set the value of an outfile streamid", "streamIndex:value" },
- { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
- OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
- "force key frames at specified timestamps", "timestamps" },
- { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
- OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccels) },
- "use HW accelerated decoding", "hwaccel name" },
- { "hwaccel_device", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
- OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_devices) },
- "select a device for HW acceleration" "devicename" },
- { "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC |
- OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) },
- "automatically insert correct rotate filters" },
-
- /* audio options */
- { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
- "set the number of audio frames to record", "number" },
- { "aq", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_qscale },
- "set audio quality (codec-specific)", "quality", },
- { "ar", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_sample_rate) },
- "set audio sampling rate (in Hz)", "rate" },
- { "ac", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
- OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_channels) },
- "set number of audio channels", "channels" },
- { "an", OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(audio_disable) },
- "disable audio" },
- { "acodec", OPT_AUDIO | HAS_ARG | OPT_PERFILE |
- OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_audio_codec },
- "force audio codec ('copy' to copy stream)", "codec" },
- { "atag", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_OUTPUT, { .func_arg = opt_audio_tag },
- "force audio tag/fourcc", "fourcc/tag" },
- { "vol", OPT_AUDIO | HAS_ARG | OPT_INT, { &audio_volume },
- "change audio volume (256=normal)" , "volume" },
- { "sample_fmt", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
- OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(sample_fmts) },
- "set sample format", "format" },
- { "channel_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
- OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_channel_layout },
- "set channel layout", "layout" },
- { "af", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_filters },
- "audio filters", "filter list" },
-
- /* subtitle options */
- { "sn", OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },
- "disable subtitle" },
- { "scodec", OPT_SUBTITLE | HAS_ARG | OPT_PERFILE | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_subtitle_codec },
- "force subtitle codec ('copy' to copy stream)", "codec" },
- { "stag", OPT_SUBTITLE | HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_subtitle_tag }
- , "force subtitle tag/fourcc", "fourcc/tag" },
-
- /* grab options */
- { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
-
- /* muxer options */
- { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_max_delay) },
- "set the maximum demux-decode delay", "seconds" },
- { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) },
- "set the initial demux-decode delay", "seconds" },
-
- { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },
- "A comma-separated list of bitstream filters", "bitstream_filters" },
-
- /* data codec support */
- { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },
- "force data codec ('copy' to copy stream)", "codec" },
-
- { NULL, },
-};
diff --git a/avconv_vda.c b/avconv_vda.c
deleted file mode 100644
index 40f87c4f76..0000000000
--- a/avconv_vda.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavcodec/avcodec.h"
-#include "libavcodec/vda.h"
-#include "libavutil/imgutils.h"
-
-#include "avconv.h"
-
-typedef struct VDAContext {
- AVFrame *tmp_frame;
-} VDAContext;
-
-static int vda_retrieve_data(AVCodecContext *s, AVFrame *frame)
-{
- InputStream *ist = s->opaque;
- VDAContext *vda = ist->hwaccel_ctx;
- CVPixelBufferRef pixbuf = (CVPixelBufferRef)frame->data[3];
- OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
- CVReturn err;
- uint8_t *data[4] = { 0 };
- int linesize[4] = { 0 };
- int planes, ret, i;
-
- av_frame_unref(vda->tmp_frame);
-
- switch (pixel_format) {
- case kCVPixelFormatType_420YpCbCr8Planar: vda->tmp_frame->format = AV_PIX_FMT_YUV420P; break;
- case kCVPixelFormatType_422YpCbCr8: vda->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
- default:
- av_log(NULL, AV_LOG_ERROR,
- "Unsupported pixel format: %u\n", pixel_format);
- return AVERROR(ENOSYS);
- }
-
- vda->tmp_frame->width = frame->width;
- vda->tmp_frame->height = frame->height;
- ret = av_frame_get_buffer(vda->tmp_frame, 32);
- if (ret < 0)
- return ret;
-
- err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
- if (err != kCVReturnSuccess) {
- av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
- return AVERROR_UNKNOWN;
- }
-
- if (CVPixelBufferIsPlanar(pixbuf)) {
-
- planes = CVPixelBufferGetPlaneCount(pixbuf);
- for (i = 0; i < planes; i++) {
- data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
- linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
- }
- } else {
- data[0] = CVPixelBufferGetBaseAddress(pixbuf);
- linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
- }
-
- av_image_copy(vda->tmp_frame->data, vda->tmp_frame->linesize,
- data, linesize, vda->tmp_frame->format,
- frame->width, frame->height);
-
- ret = av_frame_copy_props(vda->tmp_frame, frame);
- if (ret < 0)
- return ret;
-
- av_frame_unref(frame);
- av_frame_move_ref(frame, vda->tmp_frame);
-
- return 0;
-}
-
-static void vda_uninit(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- VDAContext *vda = ist->hwaccel_ctx;
-
- ist->hwaccel_uninit = NULL;
- ist->hwaccel_retrieve_data = NULL;
-
- av_frame_free(&vda->tmp_frame);
-
- av_vda_default_free(s);
- av_freep(&ist->hwaccel_ctx);
-}
-
-int vda_init(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
- VDAContext *vda;
- int ret;
-
- vda = av_mallocz(sizeof(*vda));
- if (!vda)
- return AVERROR(ENOMEM);
-
- ist->hwaccel_ctx = vda;
- ist->hwaccel_uninit = vda_uninit;
- ist->hwaccel_retrieve_data = vda_retrieve_data;
-
- vda->tmp_frame = av_frame_alloc();
- if (!vda->tmp_frame) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
-
- ret = av_vda_default_init(s);
- if (ret < 0) {
- av_log(NULL, loglevel, "Error creating VDA decoder.\n");
- goto fail;
- }
-
- return 0;
-fail:
- vda_uninit(s);
- return ret;
-}
diff --git a/avconv_vdpau.c b/avconv_vdpau.c
deleted file mode 100644
index 1bd1f48190..0000000000
--- a/avconv_vdpau.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-#include <vdpau/vdpau.h>
-#include <vdpau/vdpau_x11.h>
-
-#include <X11/Xlib.h>
-
-#include "avconv.h"
-
-#include "libavcodec/vdpau.h"
-
-#include "libavutil/avassert.h"
-#include "libavutil/buffer.h"
-#include "libavutil/frame.h"
-#include "libavutil/pixfmt.h"
-
-typedef struct VDPAUContext {
- Display *dpy;
-
- VdpDevice device;
- VdpDecoder decoder;
- VdpGetProcAddress *get_proc_address;
-
- VdpGetErrorString *get_error_string;
- VdpGetInformationString *get_information_string;
- VdpDeviceDestroy *device_destroy;
- VdpVideoSurfaceCreate *video_surface_create;
- VdpVideoSurfaceDestroy *video_surface_destroy;
- VdpVideoSurfaceGetBitsYCbCr *video_surface_get_bits;
- VdpVideoSurfaceGetParameters *video_surface_get_parameters;
- VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *video_surface_query;
-
- AVFrame *tmp_frame;
-
- enum AVPixelFormat pix_fmt;
- VdpYCbCrFormat vdpau_format;
-} VDPAUContext;
-
-static void vdpau_uninit(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- VDPAUContext *ctx = ist->hwaccel_ctx;
-
- ist->hwaccel_uninit = NULL;
- ist->hwaccel_get_buffer = NULL;
- ist->hwaccel_retrieve_data = NULL;
-
- if (ctx->device_destroy)
- ctx->device_destroy(ctx->device);
-
- if (ctx->dpy)
- XCloseDisplay(ctx->dpy);
-
- av_frame_free(&ctx->tmp_frame);
-
- av_freep(&ist->hwaccel_ctx);
- av_freep(&s->hwaccel_context);
-}
-
-static void vdpau_release_buffer(void *opaque, uint8_t *data)
-{
- VdpVideoSurface surface = *(VdpVideoSurface*)data;
- VDPAUContext *ctx = opaque;
-
- ctx->video_surface_destroy(surface);
- av_freep(&data);
-}
-
-static int vdpau_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
-{
- InputStream *ist = s->opaque;
- VDPAUContext *ctx = ist->hwaccel_ctx;
- VdpVideoSurface *surface;
- VdpStatus err;
- VdpChromaType chroma;
- uint32_t width, height;
-
- av_assert0(frame->format == AV_PIX_FMT_VDPAU);
-
- if (av_vdpau_get_surface_parameters(s, &chroma, &width, &height))
- return AVERROR(ENOSYS);
-
- surface = av_malloc(sizeof(*surface));
- if (!surface)
- return AVERROR(ENOMEM);
-
- frame->buf[0] = av_buffer_create((uint8_t*)surface, sizeof(*surface),
- vdpau_release_buffer, ctx,
- AV_BUFFER_FLAG_READONLY);
- if (!frame->buf[0]) {
- av_freep(&surface);
- return AVERROR(ENOMEM);
- }
-
- // properly we should keep a pool of surfaces instead of creating
- // them anew for each frame, but since we don't care about speed
- // much in this code, we don't bother
- err = ctx->video_surface_create(ctx->device, chroma, width, height,
- surface);
- if (err != VDP_STATUS_OK) {
- av_log(NULL, AV_LOG_ERROR, "Error allocating a VDPAU video surface: %s\n",
- ctx->get_error_string(err));
- av_buffer_unref(&frame->buf[0]);
- return AVERROR_UNKNOWN;
- }
-
- frame->data[3] = (uint8_t*)(uintptr_t)*surface;
-
- return 0;
-}
-
-static int vdpau_retrieve_data(AVCodecContext *s, AVFrame *frame)
-{
- VdpVideoSurface surface = (VdpVideoSurface)(uintptr_t)frame->data[3];
- InputStream *ist = s->opaque;
- VDPAUContext *ctx = ist->hwaccel_ctx;
- VdpStatus err;
- int ret, chroma_type;
-
- err = ctx->video_surface_get_parameters(surface, &chroma_type,
- &ctx->tmp_frame->width,
- &ctx->tmp_frame->height);
- if (err != VDP_STATUS_OK) {
- av_log(NULL, AV_LOG_ERROR, "Error getting surface parameters: %s\n",
- ctx->get_error_string(err));
- return AVERROR_UNKNOWN;
- }
- ctx->tmp_frame->format = ctx->pix_fmt;
-
- ret = av_frame_get_buffer(ctx->tmp_frame, 32);
- if (ret < 0)
- return ret;
-
- ctx->tmp_frame->width = frame->width;
- ctx->tmp_frame->height = frame->height;
-
- err = ctx->video_surface_get_bits(surface, ctx->vdpau_format,
- (void * const *)ctx->tmp_frame->data,
- ctx->tmp_frame->linesize);
- if (err != VDP_STATUS_OK) {
- av_log(NULL, AV_LOG_ERROR, "Error retrieving frame data from VDPAU: %s\n",
- ctx->get_error_string(err));
- ret = AVERROR_UNKNOWN;
- goto fail;
- }
-
- if (ctx->vdpau_format == VDP_YCBCR_FORMAT_YV12)
- FFSWAP(uint8_t*, ctx->tmp_frame->data[1], ctx->tmp_frame->data[2]);
-
- ret = av_frame_copy_props(ctx->tmp_frame, frame);
- if (ret < 0)
- goto fail;
-
- av_frame_unref(frame);
- av_frame_move_ref(frame, ctx->tmp_frame);
- return 0;
-
-fail:
- av_frame_unref(ctx->tmp_frame);
- return ret;
-}
-
-static const int vdpau_formats[][2] = {
- { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV420P },
- { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV12 },
- { VDP_YCBCR_FORMAT_YUYV, AV_PIX_FMT_YUYV422 },
- { VDP_YCBCR_FORMAT_UYVY, AV_PIX_FMT_UYVY422 },
-};
-
-static int vdpau_alloc(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
- int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
- VDPAUContext *ctx;
- const char *display, *vendor;
- VdpStatus err;
- int i;
-
- ctx = av_mallocz(sizeof(*ctx));
- if (!ctx)
- return AVERROR(ENOMEM);
-
- ist->hwaccel_ctx = ctx;
- ist->hwaccel_uninit = vdpau_uninit;
- ist->hwaccel_get_buffer = vdpau_get_buffer;
- ist->hwaccel_retrieve_data = vdpau_retrieve_data;
-
- ctx->tmp_frame = av_frame_alloc();
- if (!ctx->tmp_frame)
- goto fail;
-
- ctx->dpy = XOpenDisplay(ist->hwaccel_device);
- if (!ctx->dpy) {
- av_log(NULL, loglevel, "Cannot open the X11 display %s.\n",
- XDisplayName(ist->hwaccel_device));
- goto fail;
- }
- display = XDisplayString(ctx->dpy);
-
- err = vdp_device_create_x11(ctx->dpy, XDefaultScreen(ctx->dpy), &ctx->device,
- &ctx->get_proc_address);
- if (err != VDP_STATUS_OK) {
- av_log(NULL, loglevel, "VDPAU device creation on X11 display %s failed.\n",
- display);
- goto fail;
- }
-
-#define GET_CALLBACK(id, result) \
-do { \
- void *tmp; \
- err = ctx->get_proc_address(ctx->device, id, &tmp); \
- if (err != VDP_STATUS_OK) { \
- av_log(NULL, loglevel, "Error getting the " #id " callback.\n"); \
- goto fail; \
- } \
- ctx->result = tmp; \
-} while (0)
-
- GET_CALLBACK(VDP_FUNC_ID_GET_ERROR_STRING, get_error_string);
- GET_CALLBACK(VDP_FUNC_ID_GET_INFORMATION_STRING, get_information_string);
- GET_CALLBACK(VDP_FUNC_ID_DEVICE_DESTROY, device_destroy);
- GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_CREATE, video_surface_create);
- GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, video_surface_destroy);
- GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, video_surface_get_bits);
- GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, video_surface_get_parameters);
- GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES,
- video_surface_query);
-
- for (i = 0; i < FF_ARRAY_ELEMS(vdpau_formats); i++) {
- VdpBool supported;
- err = ctx->video_surface_query(ctx->device, VDP_CHROMA_TYPE_420,
- vdpau_formats[i][0], &supported);
- if (err != VDP_STATUS_OK) {
- av_log(NULL, loglevel,
- "Error querying VDPAU surface capabilities: %s\n",
- ctx->get_error_string(err));
- goto fail;
- }
- if (supported)
- break;
- }
- if (i == FF_ARRAY_ELEMS(vdpau_formats)) {
- av_log(NULL, loglevel,
- "No supported VDPAU format for retrieving the data.\n");
- return AVERROR(EINVAL);
- }
- ctx->vdpau_format = vdpau_formats[i][0];
- ctx->pix_fmt = vdpau_formats[i][1];
-
- if (av_vdpau_bind_context(s, ctx->device, ctx->get_proc_address, 0))
- goto fail;
-
- ctx->get_information_string(&vendor);
- av_log(NULL, AV_LOG_VERBOSE, "Using VDPAU -- %s -- on X11 display %s, "
- "to decode input stream #%d:%d.\n", vendor,
- display, ist->file_index, ist->st->index);
-
- return 0;
-
-fail:
- av_log(NULL, loglevel, "VDPAU init failed for stream #%d:%d.\n",
- ist->file_index, ist->st->index);
- vdpau_uninit(s);
- return AVERROR(EINVAL);
-}
-
-int vdpau_init(AVCodecContext *s)
-{
- InputStream *ist = s->opaque;
-
- if (!ist->hwaccel_ctx) {
- int ret = vdpau_alloc(s);
- if (ret < 0)
- return ret;
- }
-
- ist->hwaccel_get_buffer = vdpau_get_buffer;
- ist->hwaccel_retrieve_data = vdpau_retrieve_data;
-
- return 0;
-}
diff --git a/avplay.c b/avplay.c
deleted file mode 100644
index 7437bd615c..0000000000
--- a/avplay.c
+++ /dev/null
@@ -1,3063 +0,0 @@
-/*
- * avplay : Simple Media Player based on the Libav libraries
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#include <inttypes.h>
-#include <math.h>
-#include <limits.h>
-#include <stdint.h>
-
-#include "libavutil/avstring.h"
-#include "libavutil/colorspace.h"
-#include "libavutil/display.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/dict.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/samplefmt.h"
-#include "libavutil/time.h"
-#include "libavformat/avformat.h"
-#include "libavdevice/avdevice.h"
-#include "libswscale/swscale.h"
-#include "libavresample/avresample.h"
-#include "libavutil/opt.h"
-#include "libavcodec/avfft.h"
-
-#if CONFIG_AVFILTER
-# include "libavfilter/avfilter.h"
-# include "libavfilter/buffersink.h"
-# include "libavfilter/buffersrc.h"
-#endif
-
-#include "cmdutils.h"
-
-#include <SDL.h>
-#include <SDL_thread.h>
-
-#ifdef __MINGW32__
-#undef main /* We don't want SDL to override our main() */
-#endif
-
-#include <assert.h>
-
-const char program_name[] = "avplay";
-const int program_birth_year = 2003;
-
-#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
-#define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
-#define MIN_FRAMES 5
-
-/* SDL audio buffer size, in samples. Should be small to have precise
- A/V sync as SDL does not have hardware buffer fullness info. */
-#define SDL_AUDIO_BUFFER_SIZE 1024
-
-/* no AV sync correction is done if below the AV sync threshold */
-#define AV_SYNC_THRESHOLD 0.01
-/* no AV correction is done if too big error */
-#define AV_NOSYNC_THRESHOLD 10.0
-
-#define FRAME_SKIP_FACTOR 0.05
-
-/* maximum audio speed change to get correct sync */
-#define SAMPLE_CORRECTION_PERCENT_MAX 10
-
-/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
-#define AUDIO_DIFF_AVG_NB 20
-
-/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
-#define SAMPLE_ARRAY_SIZE (2 * 65536)
-
-static int64_t sws_flags = SWS_BICUBIC;
-
-typedef struct PacketQueue {
- AVPacketList *first_pkt, *last_pkt;
- int nb_packets;
- int size;
- int abort_request;
- SDL_mutex *mutex;
- SDL_cond *cond;
-} PacketQueue;
-
-#define VIDEO_PICTURE_QUEUE_SIZE 2
-#define SUBPICTURE_QUEUE_SIZE 4
-
-typedef struct VideoPicture {
- double pts; // presentation timestamp for this picture
- double target_clock; // av_gettime_relative() time at which this should be displayed ideally
- int64_t pos; // byte position in file
- SDL_Overlay *bmp;
- int width, height; /* source height & width */
- int allocated;
- int reallocate;
- enum AVPixelFormat pix_fmt;
-
- AVRational sar;
-} VideoPicture;
-
-typedef struct SubPicture {
- double pts; /* presentation time stamp for this picture */
- AVSubtitle sub;
-} SubPicture;
-
-enum {
- AV_SYNC_AUDIO_MASTER, /* default choice */
- AV_SYNC_VIDEO_MASTER,
- AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
-};
-
-typedef struct VideoState {
- SDL_Thread *parse_tid;
- SDL_Thread *video_tid;
- SDL_Thread *refresh_tid;
- AVInputFormat *iformat;
- int no_background;
- int abort_request;
- int paused;
- int last_paused;
- int seek_req;
- int seek_flags;
- int64_t seek_pos;
- int64_t seek_rel;
- int read_pause_return;
- AVFormatContext *ic;
-
- int audio_stream;
-
- int av_sync_type;
- double external_clock; /* external clock base */
- int64_t external_clock_time;
-
- double audio_clock;
- double audio_diff_cum; /* used for AV difference average computation */
- double audio_diff_avg_coef;
- double audio_diff_threshold;
- int audio_diff_avg_count;
- AVStream *audio_st;
- PacketQueue audioq;
- int audio_hw_buf_size;
- uint8_t silence_buf[SDL_AUDIO_BUFFER_SIZE];
- uint8_t *audio_buf;
- uint8_t *audio_buf1;
- unsigned int audio_buf_size; /* in bytes */
- int audio_buf_index; /* in bytes */
- AVPacket audio_pkt_temp;
- AVPacket audio_pkt;
- enum AVSampleFormat sdl_sample_fmt;
- uint64_t sdl_channel_layout;
- int sdl_channels;
- int sdl_sample_rate;
- enum AVSampleFormat resample_sample_fmt;
- uint64_t resample_channel_layout;
- int resample_sample_rate;
- AVAudioResampleContext *avr;
- AVFrame *frame;
-
- int show_audio; /* if true, display audio samples */
- int16_t sample_array[SAMPLE_ARRAY_SIZE];
- int sample_array_index;
- int last_i_start;
- RDFTContext *rdft;
- int rdft_bits;
- FFTSample *rdft_data;
- int xpos;
-
- SDL_Thread *subtitle_tid;
- int subtitle_stream;
- int subtitle_stream_changed;
- AVStream *subtitle_st;
- PacketQueue subtitleq;
- SubPicture subpq[SUBPICTURE_QUEUE_SIZE];
- int subpq_size, subpq_rindex, subpq_windex;
- SDL_mutex *subpq_mutex;
- SDL_cond *subpq_cond;
-
- double frame_timer;
- double frame_last_pts;
- double frame_last_delay;
- double video_clock; // pts of last decoded frame / predicted pts of next decoded frame
- int video_stream;
- AVStream *video_st;
- PacketQueue videoq;
- double video_current_pts; // current displayed pts (different from video_clock if frame fifos are used)
- double video_current_pts_drift; // video_current_pts - time (av_gettime_relative) at which we updated video_current_pts - used to have running video pts
- int64_t video_current_pos; // current displayed file pos
- VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
- int pictq_size, pictq_rindex, pictq_windex;
- SDL_mutex *pictq_mutex;
- SDL_cond *pictq_cond;
-#if !CONFIG_AVFILTER
- struct SwsContext *img_convert_ctx;
-#endif
-
- // QETimer *video_timer;
- char filename[1024];
- int width, height, xleft, ytop;
-
- PtsCorrectionContext pts_ctx;
-
-#if CONFIG_AVFILTER
- AVFilterContext *in_video_filter; // the first filter in the video chain
- AVFilterContext *out_video_filter; // the last filter in the video chain
-#endif
-
- float skip_frames;
- float skip_frames_index;
- int refresh;
-} VideoState;
-
-/* options specified by the user */
-static AVInputFormat *file_iformat;
-static const char *input_filename;
-static const char *window_title;
-static int fs_screen_width;
-static int fs_screen_height;
-static int screen_width = 0;
-static int screen_height = 0;
-static int audio_disable;
-static int video_disable;
-static int wanted_stream[AVMEDIA_TYPE_NB] = {
- [AVMEDIA_TYPE_AUDIO] = -1,
- [AVMEDIA_TYPE_VIDEO] = -1,
- [AVMEDIA_TYPE_SUBTITLE] = -1,
-};
-static int seek_by_bytes = -1;
-static int display_disable;
-static int show_status = 1;
-static int av_sync_type = AV_SYNC_AUDIO_MASTER;
-static int64_t start_time = AV_NOPTS_VALUE;
-static int64_t duration = AV_NOPTS_VALUE;
-static int step = 0;
-static int workaround_bugs = 1;
-static int fast = 0;
-static int genpts = 0;
-static int idct = FF_IDCT_AUTO;
-static enum AVDiscard skip_frame = AVDISCARD_DEFAULT;
-static enum AVDiscard skip_idct = AVDISCARD_DEFAULT;
-static enum AVDiscard skip_loop_filter = AVDISCARD_DEFAULT;
-static int error_concealment = 3;
-static int decoder_reorder_pts = -1;
-static int noautoexit;
-static int exit_on_keydown;
-static int exit_on_mousedown;
-static int loop = 1;
-static int framedrop = 1;
-static int infinite_buffer = 0;
-
-static int rdftspeed = 20;
-#if CONFIG_AVFILTER
-static char *vfilters = NULL;
-#endif
-static int autorotate = 1;
-
-/* current context */
-static int is_full_screen;
-static VideoState *cur_stream;
-static int64_t audio_callback_time;
-
-static AVPacket flush_pkt;
-
-#define FF_ALLOC_EVENT (SDL_USEREVENT)
-#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
-#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
-
-static SDL_Surface *screen;
-
-static int packet_queue_put(PacketQueue *q, AVPacket *pkt);
-
-/* packet queue handling */
-static void packet_queue_init(PacketQueue *q)
-{
- memset(q, 0, sizeof(PacketQueue));
- q->mutex = SDL_CreateMutex();
- q->cond = SDL_CreateCond();
- packet_queue_put(q, &flush_pkt);
-}
-
-static void packet_queue_flush(PacketQueue *q)
-{
- AVPacketList *pkt, *pkt1;
-
- SDL_LockMutex(q->mutex);
- for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
- pkt1 = pkt->next;
- av_free_packet(&pkt->pkt);
- av_freep(&pkt);
- }
- q->last_pkt = NULL;
- q->first_pkt = NULL;
- q->nb_packets = 0;
- q->size = 0;
- SDL_UnlockMutex(q->mutex);
-}
-
-static void packet_queue_end(PacketQueue *q)
-{
- packet_queue_flush(q);
- SDL_DestroyMutex(q->mutex);
- SDL_DestroyCond(q->cond);
-}
-
-static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
-{
- AVPacketList *pkt1;
-
- /* duplicate the packet */
- if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
- return -1;
-
- pkt1 = av_malloc(sizeof(AVPacketList));
- if (!pkt1)
- return -1;
- pkt1->pkt = *pkt;
- pkt1->next = NULL;
-
-
- SDL_LockMutex(q->mutex);
-
- if (!q->last_pkt)
-
- q->first_pkt = pkt1;
- else
- q->last_pkt->next = pkt1;
- q->last_pkt = pkt1;
- q->nb_packets++;
- q->size += pkt1->pkt.size + sizeof(*pkt1);
- /* XXX: should duplicate packet data in DV case */
- SDL_CondSignal(q->cond);
-
- SDL_UnlockMutex(q->mutex);
- return 0;
-}
-
-static void packet_queue_abort(PacketQueue *q)
-{
- SDL_LockMutex(q->mutex);
-
- q->abort_request = 1;
-
- SDL_CondSignal(q->cond);
-
- SDL_UnlockMutex(q->mutex);
-}
-
-/* return < 0 if aborted, 0 if no packet and > 0 if packet. */
-static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
-{
- AVPacketList *pkt1;
- int ret;
-
- SDL_LockMutex(q->mutex);
-
- for (;;) {
- if (q->abort_request) {
- ret = -1;
- break;
- }
-
- pkt1 = q->first_pkt;
- if (pkt1) {
- q->first_pkt = pkt1->next;
- if (!q->first_pkt)
- q->last_pkt = NULL;
- q->nb_packets--;
- q->size -= pkt1->pkt.size + sizeof(*pkt1);
- *pkt = pkt1->pkt;
- av_free(pkt1);
- ret = 1;
- break;
- } else if (!block) {
- ret = 0;
- break;
- } else {
- SDL_CondWait(q->cond, q->mutex);
- }
- }
- SDL_UnlockMutex(q->mutex);
- return ret;
-}
-
-static inline void fill_rectangle(SDL_Surface *screen,
- int x, int y, int w, int h, int color)
-{
- SDL_Rect rect;
- rect.x = x;
- rect.y = y;
- rect.w = w;
- rect.h = h;
- SDL_FillRect(screen, &rect, color);
-}
-
-#define ALPHA_BLEND(a, oldp, newp, s)\
-((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s))
-
-#define RGBA_IN(r, g, b, a, s)\
-{\
- unsigned int v = ((const uint32_t *)(s))[0];\
- a = (v >> 24) & 0xff;\
- r = (v >> 16) & 0xff;\
- g = (v >> 8) & 0xff;\
- b = v & 0xff;\
-}
-
-#define YUVA_IN(y, u, v, a, s, pal)\
-{\
- unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
- a = (val >> 24) & 0xff;\
- y = (val >> 16) & 0xff;\
- u = (val >> 8) & 0xff;\
- v = val & 0xff;\
-}
-
-#define YUVA_OUT(d, y, u, v, a)\
-{\
- ((uint32_t *)(d))[0] = (a << 24) | (y << 16) | (u << 8) | v;\
-}
-
-
-#define BPP 1
-
-static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
-{
- int wrap, wrap3, width2, skip2;
- int y, u, v, a, u1, v1, a1, w, h;
- uint8_t *lum, *cb, *cr;
- const uint8_t *p;
- const uint32_t *pal;
- int dstx, dsty, dstw, dsth;
-
- dstw = av_clip(rect->w, 0, imgw);
- dsth = av_clip(rect->h, 0, imgh);
- dstx = av_clip(rect->x, 0, imgw - dstw);
- dsty = av_clip(rect->y, 0, imgh - dsth);
- lum = dst->data[0] + dsty * dst->linesize[0];
- cb = dst->data[1] + (dsty >> 1) * dst->linesize[1];
- cr = dst->data[2] + (dsty >> 1) * dst->linesize[2];
-
- width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
- skip2 = dstx >> 1;
- wrap = dst->linesize[0];
- wrap3 = rect->pict.linesize[0];
- p = rect->pict.data[0];
- pal = (const uint32_t *)rect->pict.data[1]; /* Now in YCrCb! */
-
- if (dsty & 1) {
- lum += dstx;
- cb += skip2;
- cr += skip2;
-
- if (dstx & 1) {
- YUVA_IN(y, u, v, a, p, pal);
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
- cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
- cb++;
- cr++;
- lum++;
- p += BPP;
- }
- for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
- YUVA_IN(y, u, v, a, p, pal);
- u1 = u;
- v1 = v;
- a1 = a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
-
- YUVA_IN(y, u, v, a, p + BPP, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
- cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
- cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
- cb++;
- cr++;
- p += 2 * BPP;
- lum += 2;
- }
- if (w) {
- YUVA_IN(y, u, v, a, p, pal);
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
- cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
- p++;
- lum++;
- }
- p += wrap3 - dstw * BPP;
- lum += wrap - dstw - dstx;
- cb += dst->linesize[1] - width2 - skip2;
- cr += dst->linesize[2] - width2 - skip2;
- }
- for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
- lum += dstx;
- cb += skip2;
- cr += skip2;
-
- if (dstx & 1) {
- YUVA_IN(y, u, v, a, p, pal);
- u1 = u;
- v1 = v;
- a1 = a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- p += wrap3;
- lum += wrap;
- YUVA_IN(y, u, v, a, p, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
- cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
- cb++;
- cr++;
- p += -wrap3 + BPP;
- lum += -wrap + 1;
- }
- for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
- YUVA_IN(y, u, v, a, p, pal);
- u1 = u;
- v1 = v;
- a1 = a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
-
- YUVA_IN(y, u, v, a, p + BPP, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
- p += wrap3;
- lum += wrap;
-
- YUVA_IN(y, u, v, a, p, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
-
- YUVA_IN(y, u, v, a, p + BPP, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
-
- cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2);
- cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2);
-
- cb++;
- cr++;
- p += -wrap3 + 2 * BPP;
- lum += -wrap + 2;
- }
- if (w) {
- YUVA_IN(y, u, v, a, p, pal);
- u1 = u;
- v1 = v;
- a1 = a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- p += wrap3;
- lum += wrap;
- YUVA_IN(y, u, v, a, p, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
- cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
- cb++;
- cr++;
- p += -wrap3 + BPP;
- lum += -wrap + 1;
- }
- p += wrap3 + (wrap3 - dstw * BPP);
- lum += wrap + (wrap - dstw - dstx);
- cb += dst->linesize[1] - width2 - skip2;
- cr += dst->linesize[2] - width2 - skip2;
- }
- /* handle odd height */
- if (h) {
- lum += dstx;
- cb += skip2;
- cr += skip2;
-
- if (dstx & 1) {
- YUVA_IN(y, u, v, a, p, pal);
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
- cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
- cb++;
- cr++;
- lum++;
- p += BPP;
- }
- for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
- YUVA_IN(y, u, v, a, p, pal);
- u1 = u;
- v1 = v;
- a1 = a;
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
-
- YUVA_IN(y, u, v, a, p + BPP, pal);
- u1 += u;
- v1 += v;
- a1 += a;
- lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
- cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1);
- cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1);
- cb++;
- cr++;
- p += 2 * BPP;
- lum += 2;
- }
- if (w) {
- YUVA_IN(y, u, v, a, p, pal);
- lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
- cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
- cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
- }
- }
-}
-
-static void free_subpicture(SubPicture *sp)
-{
- avsubtitle_free(&sp->sub);
-}
-
-static void video_image_display(VideoState *is)
-{
- VideoPicture *vp;
- SubPicture *sp;
- AVPicture pict;
- float aspect_ratio;
- int width, height, x, y;
- SDL_Rect rect;
- int i;
-
- vp = &is->pictq[is->pictq_rindex];
- if (vp->bmp) {
-#if CONFIG_AVFILTER
- if (!vp->sar.num)
- aspect_ratio = 0;
- else
- aspect_ratio = av_q2d(vp->sar);
-#else
-
- /* XXX: use variable in the frame */
- if (is->video_st->sample_aspect_ratio.num)
- aspect_ratio = av_q2d(is->video_st->sample_aspect_ratio);
- else if (is->video_st->codec->sample_aspect_ratio.num)
- aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio);
- else
- aspect_ratio = 0;
-#endif
- if (aspect_ratio <= 0.0)
- aspect_ratio = 1.0;
- aspect_ratio *= (float)vp->width / (float)vp->height;
-
- if (is->subtitle_st)
- {
- if (is->subpq_size > 0)
- {
- sp = &is->subpq[is->subpq_rindex];
-
- if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000))
- {
- SDL_LockYUVOverlay (vp->bmp);
-
- pict.data[0] = vp->bmp->pixels[0];
- pict.data[1] = vp->bmp->pixels[2];
- pict.data[2] = vp->bmp->pixels[1];
-
- pict.linesize[0] = vp->bmp->pitches[0];
- pict.linesize[1] = vp->bmp->pitches[2];
- pict.linesize[2] = vp->bmp->pitches[1];
-
- for (i = 0; i < sp->sub.num_rects; i++)
- blend_subrect(&pict, sp->sub.rects[i],
- vp->bmp->w, vp->bmp->h);
-
- SDL_UnlockYUVOverlay (vp->bmp);
- }
- }
- }
-
-
- /* XXX: we suppose the screen has a 1.0 pixel ratio */
- height = is->height;
- width = ((int)rint(height * aspect_ratio)) & ~1;
- if (width > is->width) {
- width = is->width;
- height = ((int)rint(width / aspect_ratio)) & ~1;
- }
- x = (is->width - width) / 2;
- y = (is->height - height) / 2;
- is->no_background = 0;
- rect.x = is->xleft + x;
- rect.y = is->ytop + y;
- rect.w = width;
- rect.h = height;
- SDL_DisplayYUVOverlay(vp->bmp, &rect);
- }
-}
-
-/* get the current audio output buffer size, in samples. With SDL, we
- cannot have a precise information */
-static int audio_write_get_buf_size(VideoState *is)
-{
- return is->audio_buf_size - is->audio_buf_index;
-}
-
-static inline int compute_mod(int a, int b)
-{
- a = a % b;
- if (a >= 0)
- return a;
- else
- return a + b;
-}
-
-static void video_audio_display(VideoState *s)
-{
- int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
- int ch, channels, h, h2, bgcolor, fgcolor;
- int16_t time_diff;
- int rdft_bits, nb_freq;
-
- for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
- ;
- nb_freq = 1 << (rdft_bits - 1);
-
- /* compute display index : center on currently output samples */
- channels = s->sdl_channels;
- nb_display_channels = channels;
- if (!s->paused) {
- int data_used = s->show_audio == 1 ? s->width : (2 * nb_freq);
- n = 2 * channels;
- delay = audio_write_get_buf_size(s);
- delay /= n;
-
- /* to be more precise, we take into account the time spent since
- the last buffer computation */
- if (audio_callback_time) {
- time_diff = av_gettime_relative() - audio_callback_time;
- delay -= (time_diff * s->sdl_sample_rate) / 1000000;
- }
-
- delay += 2 * data_used;
- if (delay < data_used)
- delay = data_used;
-
- i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
- if (s->show_audio == 1) {
- h = INT_MIN;
- for (i = 0; i < 1000; i += channels) {
- int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
- int a = s->sample_array[idx];
- int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE];
- int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE];
- int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE];
- int score = a - d;
- if (h < score && (b ^ c) < 0) {
- h = score;
- i_start = idx;
- }
- }
- }
-
- s->last_i_start = i_start;
- } else {
- i_start = s->last_i_start;
- }
-
- bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- if (s->show_audio == 1) {
- fill_rectangle(screen,
- s->xleft, s->ytop, s->width, s->height,
- bgcolor);
-
- fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
-
- /* total height for one channel */
- h = s->height / nb_display_channels;
- /* graph height / 2 */
- h2 = (h * 9) / 20;
- for (ch = 0; ch < nb_display_channels; ch++) {
- i = i_start + ch;
- y1 = s->ytop + ch * h + (h / 2); /* position of center line */
- for (x = 0; x < s->width; x++) {
- y = (s->sample_array[i] * h2) >> 15;
- if (y < 0) {
- y = -y;
- ys = y1 - y;
- } else {
- ys = y1;
- }
- fill_rectangle(screen,
- s->xleft + x, ys, 1, y,
- fgcolor);
- i += channels;
- if (i >= SAMPLE_ARRAY_SIZE)
- i -= SAMPLE_ARRAY_SIZE;
- }
- }
-
- fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
-
- for (ch = 1; ch < nb_display_channels; ch++) {
- y = s->ytop + ch * h;
- fill_rectangle(screen,
- s->xleft, y, s->width, 1,
- fgcolor);
- }
- SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
- } else {
- nb_display_channels= FFMIN(nb_display_channels, 2);
- if (rdft_bits != s->rdft_bits) {
- av_rdft_end(s->rdft);
- av_free(s->rdft_data);
- s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
- s->rdft_bits = rdft_bits;
- s->rdft_data = av_malloc(4 * nb_freq * sizeof(*s->rdft_data));
- }
- {
- FFTSample *data[2];
- for (ch = 0; ch < nb_display_channels; ch++) {
- data[ch] = s->rdft_data + 2 * nb_freq * ch;
- i = i_start + ch;
- for (x = 0; x < 2 * nb_freq; x++) {
- double w = (x-nb_freq) * (1.0 / nb_freq);
- data[ch][x] = s->sample_array[i] * (1.0 - w * w);
- i += channels;
- if (i >= SAMPLE_ARRAY_SIZE)
- i -= SAMPLE_ARRAY_SIZE;
- }
- av_rdft_calc(s->rdft, data[ch]);
- }
- /* Least efficient way to do this, we should of course
- * directly access it but it is more than fast enough. */
- for (y = 0; y < s->height; y++) {
- double w = 1 / sqrt(nb_freq);
- int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1]));
- int b = (nb_display_channels == 2 ) ? sqrt(w * sqrt(data[1][2 * y + 0] * data[1][2 * y + 0]
- + data[1][2 * y + 1] * data[1][2 * y + 1])) : a;
- a = FFMIN(a, 255);
- b = FFMIN(b, 255);
- fgcolor = SDL_MapRGB(screen->format, a, b, (a + b) / 2);
-
- fill_rectangle(screen,
- s->xpos, s->height-y, 1, 1,
- fgcolor);
- }
- }
- SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
- s->xpos++;
- if (s->xpos >= s->width)
- s->xpos= s->xleft;
- }
-}
-
-static int video_open(VideoState *is)
-{
- int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
- int w,h;
-
- if (is_full_screen) flags |= SDL_FULLSCREEN;
- else flags |= SDL_RESIZABLE;
-
- if (is_full_screen && fs_screen_width) {
- w = fs_screen_width;
- h = fs_screen_height;
- } else if (!is_full_screen && screen_width) {
- w = screen_width;
- h = screen_height;
-#if CONFIG_AVFILTER
- } else if (is->out_video_filter && is->out_video_filter->inputs[0]) {
- w = is->out_video_filter->inputs[0]->w;
- h = is->out_video_filter->inputs[0]->h;
-#else
- } else if (is->video_st && is->video_st->codec->width) {
- w = is->video_st->codec->width;
- h = is->video_st->codec->height;
-#endif
- } else {
- w = 640;
- h = 480;
- }
- if (screen && is->width == screen->w && screen->w == w
- && is->height== screen->h && screen->h == h)
- return 0;
-
-#if defined(__APPLE__) && !SDL_VERSION_ATLEAST(1, 2, 14)
- /* setting bits_per_pixel = 0 or 32 causes blank video on OS X and older SDL */
- screen = SDL_SetVideoMode(w, h, 24, flags);
-#else
- screen = SDL_SetVideoMode(w, h, 0, flags);
-#endif
- if (!screen) {
- fprintf(stderr, "SDL: could not set video mode - exiting\n");
- return -1;
- }
- if (!window_title)
- window_title = input_filename;
- SDL_WM_SetCaption(window_title, window_title);
-
- is->width = screen->w;
- is->height = screen->h;
-
- return 0;
-}
-
-/* display the current picture, if any */
-static void video_display(VideoState *is)
-{
- if (!screen)
- video_open(cur_stream);
- if (is->audio_st && is->show_audio)
- video_audio_display(is);
- else if (is->video_st)
- video_image_display(is);
-}
-
-static int refresh_thread(void *opaque)
-{
- VideoState *is= opaque;
- while (!is->abort_request) {
- SDL_Event event;
- event.type = FF_REFRESH_EVENT;
- event.user.data1 = opaque;
- if (!is->refresh) {
- is->refresh = 1;
- SDL_PushEvent(&event);
- }
- av_usleep(is->audio_st && is->show_audio ? rdftspeed * 1000 : 5000); // FIXME ideally we should wait the correct time but SDLs event passing is so slow it would be silly
- }
- return 0;
-}
-
-/* get the current audio clock value */
-static double get_audio_clock(VideoState *is)
-{
- double pts;
- int hw_buf_size, bytes_per_sec;
- pts = is->audio_clock;
- hw_buf_size = audio_write_get_buf_size(is);
- bytes_per_sec = 0;
- if (is->audio_st) {
- bytes_per_sec = is->sdl_sample_rate * is->sdl_channels *
- av_get_bytes_per_sample(is->sdl_sample_fmt);
- }
- if (bytes_per_sec)
- pts -= (double)hw_buf_size / bytes_per_sec;
- return pts;
-}
-
-/* get the current video clock value */
-static double get_video_clock(VideoState *is)
-{
- if (is->paused) {
- return is->video_current_pts;
- } else {
- return is->video_current_pts_drift + av_gettime_relative() / 1000000.0;
- }
-}
-
-/* get the current external clock value */
-static double get_external_clock(VideoState *is)
-{
- int64_t ti;
- ti = av_gettime_relative();
- return is->external_clock + ((ti - is->external_clock_time) * 1e-6);
-}
-
-/* get the current master clock value */
-static double get_master_clock(VideoState *is)
-{
- double val;
-
- if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
- if (is->video_st)
- val = get_video_clock(is);
- else
- val = get_audio_clock(is);
- } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
- if (is->audio_st)
- val = get_audio_clock(is);
- else
- val = get_video_clock(is);
- } else {
- val = get_external_clock(is);
- }
- return val;
-}
-
-/* seek in the stream */
-static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
-{
- if (!is->seek_req) {
- is->seek_pos = pos;
- is->seek_rel = rel;
- is->seek_flags &= ~AVSEEK_FLAG_BYTE;
- if (seek_by_bytes)
- is->seek_flags |= AVSEEK_FLAG_BYTE;
- is->seek_req = 1;
- }
-}
-
-/* pause or resume the video */
-static void stream_pause(VideoState *is)
-{
- if (is->paused) {
- is->frame_timer += av_gettime_relative() / 1000000.0 + is->video_current_pts_drift - is->video_current_pts;
- if (is->read_pause_return != AVERROR(ENOSYS)) {
- is->video_current_pts = is->video_current_pts_drift + av_gettime_relative() / 1000000.0;
- }
- is->video_current_pts_drift = is->video_current_pts - av_gettime_relative() / 1000000.0;
- }
- is->paused = !is->paused;
-}
-
-static double compute_target_time(double frame_current_pts, VideoState *is)
-{
- double delay, sync_threshold, diff = 0;
-
- /* compute nominal delay */
- delay = frame_current_pts - is->frame_last_pts;
- if (delay <= 0 || delay >= 10.0) {
- /* if incorrect delay, use previous one */
- delay = is->frame_last_delay;
- } else {
- is->frame_last_delay = delay;
- }
- is->frame_last_pts = frame_current_pts;
-
- /* update delay to follow master synchronisation source */
- if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
- is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
- /* if video is slave, we try to correct big delays by
- duplicating or deleting a frame */
- diff = get_video_clock(is) - get_master_clock(is);
-
- /* skip or repeat frame. We take into account the
- delay to compute the threshold. I still don't know
- if it is the best guess */
- sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
- if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
- if (diff <= -sync_threshold)
- delay = 0;
- else if (diff >= sync_threshold)
- delay = 2 * delay;
- }
- }
- is->frame_timer += delay;
-
- av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f pts=%0.3f A-V=%f\n",
- delay, frame_current_pts, -diff);
-
- return is->frame_timer;
-}
-
-/* called to display each frame */
-static void video_refresh_timer(void *opaque)
-{
- VideoState *is = opaque;
- VideoPicture *vp;
-
- SubPicture *sp, *sp2;
-
- if (is->video_st) {
-retry:
- if (is->pictq_size == 0) {
- // nothing to do, no picture to display in the que
- } else {
- double time = av_gettime_relative() / 1000000.0;
- double next_target;
- /* dequeue the picture */
- vp = &is->pictq[is->pictq_rindex];
-
- if (time < vp->target_clock)
- return;
- /* update current video pts */
- is->video_current_pts = vp->pts;
- is->video_current_pts_drift = is->video_current_pts - time;
- is->video_current_pos = vp->pos;
- if (is->pictq_size > 1) {
- VideoPicture *nextvp = &is->pictq[(is->pictq_rindex + 1) % VIDEO_PICTURE_QUEUE_SIZE];
- assert(nextvp->target_clock >= vp->target_clock);
- next_target= nextvp->target_clock;
- } else {
- next_target = vp->target_clock + is->video_clock - vp->pts; // FIXME pass durations cleanly
- }
- if (framedrop && time > next_target) {
- is->skip_frames *= 1.0 + FRAME_SKIP_FACTOR;
- if (is->pictq_size > 1 || time > next_target + 0.5) {
- /* update queue size and signal for next picture */
- if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
- is->pictq_rindex = 0;
-
- SDL_LockMutex(is->pictq_mutex);
- is->pictq_size--;
- SDL_CondSignal(is->pictq_cond);
- SDL_UnlockMutex(is->pictq_mutex);
- goto retry;
- }
- }
-
- if (is->subtitle_st) {
- if (is->subtitle_stream_changed) {
- SDL_LockMutex(is->subpq_mutex);
-
- while (is->subpq_size) {
- free_subpicture(&is->subpq[is->subpq_rindex]);
-
- /* update queue size and signal for next picture */
- if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
- is->subpq_rindex = 0;
-
- is->subpq_size--;
- }
- is->subtitle_stream_changed = 0;
-
- SDL_CondSignal(is->subpq_cond);
- SDL_UnlockMutex(is->subpq_mutex);
- } else {
- if (is->subpq_size > 0) {
- sp = &is->subpq[is->subpq_rindex];
-
- if (is->subpq_size > 1)
- sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE];
- else
- sp2 = NULL;
-
- if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
- || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
- {
- free_subpicture(sp);
-
- /* update queue size and signal for next picture */
- if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
- is->subpq_rindex = 0;
-
- SDL_LockMutex(is->subpq_mutex);
- is->subpq_size--;
- SDL_CondSignal(is->subpq_cond);
- SDL_UnlockMutex(is->subpq_mutex);
- }
- }
- }
- }
-
- /* display picture */
- if (!display_disable)
- video_display(is);
-
- /* update queue size and signal for next picture */
- if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
- is->pictq_rindex = 0;
-
- SDL_LockMutex(is->pictq_mutex);
- is->pictq_size--;
- SDL_CondSignal(is->pictq_cond);
- SDL_UnlockMutex(is->pictq_mutex);
- }
- } else if (is->audio_st) {
- /* draw the next audio frame */
-
- /* if only audio stream, then display the audio bars (better
- than nothing, just to test the implementation */
-
- /* display picture */
- if (!display_disable)
- video_display(is);
- }
- if (show_status) {
- static int64_t last_time;
- int64_t cur_time;
- int aqsize, vqsize, sqsize;
- double av_diff;
-
- cur_time = av_gettime_relative();
- if (!last_time || (cur_time - last_time) >= 30000) {
- aqsize = 0;
- vqsize = 0;
- sqsize = 0;
- if (is->audio_st)
- aqsize = is->audioq.size;
- if (is->video_st)
- vqsize = is->videoq.size;
- if (is->subtitle_st)
- sqsize = is->subtitleq.size;
- av_diff = 0;
- if (is->audio_st && is->video_st)
- av_diff = get_audio_clock(is) - get_video_clock(is);
- printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r",
- get_master_clock(is), av_diff, FFMAX(is->skip_frames - 1, 0), aqsize / 1024,
- vqsize / 1024, sqsize, is->pts_ctx.num_faulty_dts, is->pts_ctx.num_faulty_pts);
- fflush(stdout);
- last_time = cur_time;
- }
- }
-}
-
-static void stream_close(VideoState *is)
-{
- VideoPicture *vp;
- int i;
- /* XXX: use a special url_shutdown call to abort parse cleanly */
- is->abort_request = 1;
- SDL_WaitThread(is->parse_tid, NULL);
- SDL_WaitThread(is->refresh_tid, NULL);
-
- /* free all pictures */
- for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
- vp = &is->pictq[i];
- if (vp->bmp) {
- SDL_FreeYUVOverlay(vp->bmp);
- vp->bmp = NULL;
- }
- }
- SDL_DestroyMutex(is->pictq_mutex);
- SDL_DestroyCond(is->pictq_cond);
- SDL_DestroyMutex(is->subpq_mutex);
- SDL_DestroyCond(is->subpq_cond);
-#if !CONFIG_AVFILTER
- if (is->img_convert_ctx)
- sws_freeContext(is->img_convert_ctx);
-#endif
- av_free(is);
-}
-
-static void do_exit(void)
-{
- if (cur_stream) {
- stream_close(cur_stream);
- cur_stream = NULL;
- }
- uninit_opts();
- avformat_network_deinit();
- if (show_status)
- printf("\n");
- SDL_Quit();
- av_log(NULL, AV_LOG_QUIET, "");
- exit(0);
-}
-
-/* allocate a picture (needs to do that in main thread to avoid
- potential locking problems */
-static void alloc_picture(void *opaque)
-{
- VideoState *is = opaque;
- VideoPicture *vp;
-
- vp = &is->pictq[is->pictq_windex];
-
- if (vp->bmp)
- SDL_FreeYUVOverlay(vp->bmp);
-
-#if CONFIG_AVFILTER
- vp->width = is->out_video_filter->inputs[0]->w;
- vp->height = is->out_video_filter->inputs[0]->h;
- vp->pix_fmt = is->out_video_filter->inputs[0]->format;
-#else
- vp->width = is->video_st->codec->width;
- vp->height = is->video_st->codec->height;
- vp->pix_fmt = is->video_st->codec->pix_fmt;
-#endif
-
- vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
- SDL_YV12_OVERLAY,
- screen);
- if (!vp->bmp || vp->bmp->pitches[0] < vp->width) {
- /* SDL allocates a buffer smaller than requested if the video
- * overlay hardware is unable to support the requested size. */
- fprintf(stderr, "Error: the video system does not support an image\n"
- "size of %dx%d pixels. Try using -vf \"scale=w:h\"\n"
- "to reduce the image size.\n", vp->width, vp->height );
- do_exit();
- }
-
- SDL_LockMutex(is->pictq_mutex);
- vp->allocated = 1;
- SDL_CondSignal(is->pictq_cond);
- SDL_UnlockMutex(is->pictq_mutex);
-}
-
-/* The 'pts' parameter is the dts of the packet / pts of the frame and
- * guessed if not known. */
-static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos)
-{
- VideoPicture *vp;
-#if CONFIG_AVFILTER
- AVPicture pict_src;
-#else
- int dst_pix_fmt = AV_PIX_FMT_YUV420P;
-#endif
- /* wait until we have space to put a new picture */
- SDL_LockMutex(is->pictq_mutex);
-
- if (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->refresh)
- is->skip_frames = FFMAX(1.0 - FRAME_SKIP_FACTOR, is->skip_frames * (1.0 - FRAME_SKIP_FACTOR));
-
- while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
- !is->videoq.abort_request) {
- SDL_CondWait(is->pictq_cond, is->pictq_mutex);
- }
- SDL_UnlockMutex(is->pictq_mutex);
-
- if (is->videoq.abort_request)
- return -1;
-
- vp = &is->pictq[is->pictq_windex];
-
- vp->sar = src_frame->sample_aspect_ratio;
-
- /* alloc or resize hardware picture buffer */
- if (!vp->bmp || vp->reallocate ||
-#if CONFIG_AVFILTER
- vp->width != is->out_video_filter->inputs[0]->w ||
- vp->height != is->out_video_filter->inputs[0]->h) {
-#else
- vp->width != is->video_st->codec->width ||
- vp->height != is->video_st->codec->height) {
-#endif
- SDL_Event event;
-
- vp->allocated = 0;
- vp->reallocate = 0;
-
- /* the allocation must be done in the main thread to avoid
- locking problems */
- event.type = FF_ALLOC_EVENT;
- event.user.data1 = is;
- SDL_PushEvent(&event);
-
- /* wait until the picture is allocated */
- SDL_LockMutex(is->pictq_mutex);
- while (!vp->allocated && !is->videoq.abort_request) {
- SDL_CondWait(is->pictq_cond, is->pictq_mutex);
- }
- SDL_UnlockMutex(is->pictq_mutex);
-
- if (is->videoq.abort_request)
- return -1;
- }
-
- /* if the frame is not skipped, then display it */
- if (vp->bmp) {
- AVPicture pict = { { 0 } };
-
- /* get a pointer on the bitmap */
- SDL_LockYUVOverlay (vp->bmp);
-
- pict.data[0] = vp->bmp->pixels[0];
- pict.data[1] = vp->bmp->pixels[2];
- pict.data[2] = vp->bmp->pixels[1];
-
- pict.linesize[0] = vp->bmp->pitches[0];
- pict.linesize[1] = vp->bmp->pitches[2];
- pict.linesize[2] = vp->bmp->pitches[1];
-
-#if CONFIG_AVFILTER
- pict_src.data[0] = src_frame->data[0];
- pict_src.data[1] = src_frame->data[1];
- pict_src.data[2] = src_frame->data[2];
-
- pict_src.linesize[0] = src_frame->linesize[0];
- pict_src.linesize[1] = src_frame->linesize[1];
- pict_src.linesize[2] = src_frame->linesize[2];
-
- // FIXME use direct rendering
- av_picture_copy(&pict, &pict_src,
- vp->pix_fmt, vp->width, vp->height);
-#else
- av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags);
- is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
- vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,
- dst_pix_fmt, sws_flags, NULL, NULL, NULL);
- if (!is->img_convert_ctx) {
- fprintf(stderr, "Cannot initialize the conversion context\n");
- exit(1);
- }
- sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
- 0, vp->height, pict.data, pict.linesize);
-#endif
- /* update the bitmap content */
- SDL_UnlockYUVOverlay(vp->bmp);
-
- vp->pts = pts;
- vp->pos = pos;
-
- /* now we can update the picture count */
- if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
- is->pictq_windex = 0;
- SDL_LockMutex(is->pictq_mutex);
- vp->target_clock = compute_target_time(vp->pts, is);
-
- is->pictq_size++;
- SDL_UnlockMutex(is->pictq_mutex);
- }
- return 0;
-}
-
-/* Compute the exact PTS for the picture if it is omitted in the stream.
- * The 'pts1' parameter is the dts of the packet / pts of the frame. */
-static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1, int64_t pos)
-{
- double frame_delay, pts;
- int ret;
-
- pts = pts1;
-
- if (pts != 0) {
- /* update video clock with pts, if present */
- is->video_clock = pts;
- } else {
- pts = is->video_clock;
- }
- /* update video clock for next frame */
- frame_delay = av_q2d(is->video_st->codec->time_base);
- /* for MPEG2, the frame can be repeated, so we update the
- clock accordingly */
- frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
- is->video_clock += frame_delay;
-
- ret = queue_picture(is, src_frame, pts, pos);
- av_frame_unref(src_frame);
- return ret;
-}
-
-static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacket *pkt)
-{
- int got_picture, i;
-
- if (packet_queue_get(&is->videoq, pkt, 1) < 0)
- return -1;
-
- if (pkt->data == flush_pkt.data) {
- avcodec_flush_buffers(is->video_st->codec);
-
- SDL_LockMutex(is->pictq_mutex);
- // Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
- for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++) {
- is->pictq[i].target_clock= 0;
- }
- while (is->pictq_size && !is->videoq.abort_request) {
- SDL_CondWait(is->pictq_cond, is->pictq_mutex);
- }
- is->video_current_pos = -1;
- SDL_UnlockMutex(is->pictq_mutex);
-
- init_pts_correction(&is->pts_ctx);
- is->frame_last_pts = AV_NOPTS_VALUE;
- is->frame_last_delay = 0;
- is->frame_timer = (double)av_gettime_relative() / 1000000.0;
- is->skip_frames = 1;
- is->skip_frames_index = 0;
- return 0;
- }
-
- avcodec_decode_video2(is->video_st->codec, frame, &got_picture, pkt);
-
- if (got_picture) {
- if (decoder_reorder_pts == -1) {
- *pts = guess_correct_pts(&is->pts_ctx, frame->pkt_pts, frame->pkt_dts);
- } else if (decoder_reorder_pts) {
- *pts = frame->pkt_pts;
- } else {
- *pts = frame->pkt_dts;
- }
-
- if (*pts == AV_NOPTS_VALUE) {
- *pts = 0;
- }
- if (is->video_st->sample_aspect_ratio.num) {
- frame->sample_aspect_ratio = is->video_st->sample_aspect_ratio;
- }
-
- is->skip_frames_index += 1;
- if (is->skip_frames_index >= is->skip_frames) {
- is->skip_frames_index -= FFMAX(is->skip_frames, 1.0);
- return 1;
- }
- av_frame_unref(frame);
- }
- return 0;
-}
-
-#if CONFIG_AVFILTER
-static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters)
-{
- char sws_flags_str[128];
- char buffersrc_args[256];
- int ret;
- AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter;
- AVCodecContext *codec = is->video_st->codec;
-
- snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags);
- graph->scale_sws_opts = av_strdup(sws_flags_str);
-
- snprintf(buffersrc_args, sizeof(buffersrc_args), "%d:%d:%d:%d:%d:%d:%d",
- codec->width, codec->height, codec->pix_fmt,
- is->video_st->time_base.num, is->video_st->time_base.den,
- codec->sample_aspect_ratio.num, codec->sample_aspect_ratio.den);
-
-
- if ((ret = avfilter_graph_create_filter(&filt_src,
- avfilter_get_by_name("buffer"),
- "src", buffersrc_args, NULL,
- graph)) < 0)
- return ret;
- if ((ret = avfilter_graph_create_filter(&filt_out,
- avfilter_get_by_name("buffersink"),
- "out", NULL, NULL, graph)) < 0)
- return ret;
-
- last_filter = filt_out;
-
-/* Note: this macro adds a filter before the lastly added filter, so the
- * processing order of the filters is in reverse */
-#define INSERT_FILT(name, arg) do { \
- AVFilterContext *filt_ctx; \
- \
- ret = avfilter_graph_create_filter(&filt_ctx, \
- avfilter_get_by_name(name), \
- "avplay_" name, arg, NULL, graph); \
- if (ret < 0) \
- return ret; \
- \
- ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
- if (ret < 0) \
- return ret; \
- \
- last_filter = filt_ctx; \
-} while (0)
-
- INSERT_FILT("format", "yuv420p");
-
- if (autorotate) {
- uint8_t* displaymatrix = av_stream_get_side_data(is->video_st,
- AV_PKT_DATA_DISPLAYMATRIX, NULL);
- if (displaymatrix) {
- double rot = av_display_rotation_get((int32_t*) displaymatrix);
- if (rot < -135 || rot > 135) {
- INSERT_FILT("vflip", NULL);
- INSERT_FILT("hflip", NULL);
- } else if (rot < -45) {
- INSERT_FILT("transpose", "dir=clock");
- } else if (rot > 45) {
- INSERT_FILT("transpose", "dir=cclock");
- }
- }
- }
-
- if (vfilters) {
- AVFilterInOut *outputs = avfilter_inout_alloc();
- AVFilterInOut *inputs = avfilter_inout_alloc();
-
- outputs->name = av_strdup("in");
- outputs->filter_ctx = filt_src;
- outputs->pad_idx = 0;
- outputs->next = NULL;
-
- inputs->name = av_strdup("out");
- inputs->filter_ctx = last_filter;
- inputs->pad_idx = 0;
- inputs->next = NULL;
-
- if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0)
- return ret;
- } else {
- if ((ret = avfilter_link(filt_src, 0, last_filter, 0)) < 0)
- return ret;
- }
-
- if ((ret = avfilter_graph_config(graph, NULL)) < 0)
- return ret;
-
- is->in_video_filter = filt_src;
- is->out_video_filter = filt_out;
-
- return ret;
-}
-
-#endif /* CONFIG_AVFILTER */
-
-static int video_thread(void *arg)
-{
- AVPacket pkt = { 0 };
- VideoState *is = arg;
- AVFrame *frame = av_frame_alloc();
- int64_t pts_int;
- double pts;
- int ret;
-
-#if CONFIG_AVFILTER
- AVFilterGraph *graph = avfilter_graph_alloc();
- AVFilterContext *filt_out = NULL, *filt_in = NULL;
- int last_w = is->video_st->codec->width;
- int last_h = is->video_st->codec->height;
- if (!graph) {
- av_frame_free(&frame);
- return AVERROR(ENOMEM);
- }
-
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
- goto the_end;
- filt_in = is->in_video_filter;
- filt_out = is->out_video_filter;
-#endif
-
- if (!frame) {
-#if CONFIG_AVFILTER
- avfilter_graph_free(&graph);
-#endif
- return AVERROR(ENOMEM);
- }
-
- for (;;) {
-#if CONFIG_AVFILTER
- AVRational tb;
-#endif
- while (is->paused && !is->videoq.abort_request)
- SDL_Delay(10);
-
- av_free_packet(&pkt);
-
- ret = get_video_frame(is, frame, &pts_int, &pkt);
- if (ret < 0)
- goto the_end;
-
- if (!ret)
- continue;
-
-#if CONFIG_AVFILTER
- if ( last_w != is->video_st->codec->width
- || last_h != is->video_st->codec->height) {
- av_log(NULL, AV_LOG_TRACE, "Changing size %dx%d -> %dx%d\n", last_w, last_h,
- is->video_st->codec->width, is->video_st->codec->height);
- avfilter_graph_free(&graph);
- graph = avfilter_graph_alloc();
- if ((ret = configure_video_filters(graph, is, vfilters)) < 0)
- goto the_end;
- filt_in = is->in_video_filter;
- filt_out = is->out_video_filter;
- last_w = is->video_st->codec->width;
- last_h = is->video_st->codec->height;
- }
-
- frame->pts = pts_int;
- ret = av_buffersrc_add_frame(filt_in, frame);
- if (ret < 0)
- goto the_end;
-
- while (ret >= 0) {
- ret = av_buffersink_get_frame(filt_out, frame);
- if (ret < 0) {
- ret = 0;
- break;
- }
-
- pts_int = frame->pts;
- tb = filt_out->inputs[0]->time_base;
- if (av_cmp_q(tb, is->video_st->time_base)) {
- av_unused int64_t pts1 = pts_int;
- pts_int = av_rescale_q(pts_int, tb, is->video_st->time_base);
- av_log(NULL, AV_LOG_TRACE, "video_thread(): "
- "tb:%d/%d pts:%"PRId64" -> tb:%d/%d pts:%"PRId64"\n",
- tb.num, tb.den, pts1,
- is->video_st->time_base.num, is->video_st->time_base.den, pts_int);
- }
- pts = pts_int * av_q2d(is->video_st->time_base);
- ret = output_picture2(is, frame, pts, 0);
- }
-#else
- pts = pts_int * av_q2d(is->video_st->time_base);
- ret = output_picture2(is, frame, pts, pkt.pos);
-#endif
-
- if (ret < 0)
- goto the_end;
-
-
- if (step)
- if (cur_stream)
- stream_pause(cur_stream);
- }
- the_end:
-#if CONFIG_AVFILTER
- av_freep(&vfilters);
- avfilter_graph_free(&graph);
-#endif
- av_free_packet(&pkt);
- av_frame_free(&frame);
- return 0;
-}
-
-static int subtitle_thread(void *arg)
-{
- VideoState *is = arg;
- SubPicture *sp;
- AVPacket pkt1, *pkt = &pkt1;
- int got_subtitle;
- double pts;
- int i, j;
- int r, g, b, y, u, v, a;
-
- for (;;) {
- while (is->paused && !is->subtitleq.abort_request) {
- SDL_Delay(10);
- }
- if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
- break;
-
- if (pkt->data == flush_pkt.data) {
- avcodec_flush_buffers(is->subtitle_st->codec);
- continue;
- }
- SDL_LockMutex(is->subpq_mutex);
- while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE &&
- !is->subtitleq.abort_request) {
- SDL_CondWait(is->subpq_cond, is->subpq_mutex);
- }
- SDL_UnlockMutex(is->subpq_mutex);
-
- if (is->subtitleq.abort_request)
- return 0;
-
- sp = &is->subpq[is->subpq_windex];
-
- /* NOTE: ipts is the PTS of the _first_ picture beginning in
- this packet, if any */
- pts = 0;
- if (pkt->pts != AV_NOPTS_VALUE)
- pts = av_q2d(is->subtitle_st->time_base) * pkt->pts;
-
- avcodec_decode_subtitle2(is->subtitle_st->codec, &sp->sub,
- &got_subtitle, pkt);
-
- if (got_subtitle && sp->sub.format == 0) {
- sp->pts = pts;
-
- for (i = 0; i < sp->sub.num_rects; i++)
- {
- for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
- {
- RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
- y = RGB_TO_Y_CCIR(r, g, b);
- u = RGB_TO_U_CCIR(r, g, b, 0);
- v = RGB_TO_V_CCIR(r, g, b, 0);
- YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
- }
- }
-
- /* now we can update the picture count */
- if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE)
- is->subpq_windex = 0;
- SDL_LockMutex(is->subpq_mutex);
- is->subpq_size++;
- SDL_UnlockMutex(is->subpq_mutex);
- }
- av_free_packet(pkt);
- }
- return 0;
-}
-
-/* copy samples for viewing in editor window */
-static void update_sample_display(VideoState *is, short *samples, int samples_size)
-{
- int size, len;
-
- size = samples_size / sizeof(short);
- while (size > 0) {
- len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
- if (len > size)
- len = size;
- memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
- samples += len;
- is->sample_array_index += len;
- if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
- is->sample_array_index = 0;
- size -= len;
- }
-}
-
-/* return the new audio buffer size (samples can be added or deleted
- to get better sync if video or external master clock) */
-static int synchronize_audio(VideoState *is, short *samples,
- int samples_size1, double pts)
-{
- int n, samples_size;
- double ref_clock;
-
- n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
- samples_size = samples_size1;
-
- /* if not master, then we try to remove or add samples to correct the clock */
- if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
- is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
- double diff, avg_diff;
- int wanted_size, min_size, max_size, nb_samples;
-
- ref_clock = get_master_clock(is);
- diff = get_audio_clock(is) - ref_clock;
-
- if (diff < AV_NOSYNC_THRESHOLD) {
- is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
- if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
- /* not enough measures to have a correct estimate */
- is->audio_diff_avg_count++;
- } else {
- /* estimate the A-V difference */
- avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
-
- if (fabs(avg_diff) >= is->audio_diff_threshold) {
- wanted_size = samples_size + ((int)(diff * is->sdl_sample_rate) * n);
- nb_samples = samples_size / n;
-
- min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
- max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
- if (wanted_size < min_size)
- wanted_size = min_size;
- else if (wanted_size > max_size)
- wanted_size = max_size;
-
- /* add or remove samples to correction the synchro */
- if (wanted_size < samples_size) {
- /* remove samples */
- samples_size = wanted_size;
- } else if (wanted_size > samples_size) {
- uint8_t *samples_end, *q;
- int nb;
-
- /* add samples */
- nb = (samples_size - wanted_size);
- samples_end = (uint8_t *)samples + samples_size - n;
- q = samples_end + n;
- while (nb > 0) {
- memcpy(q, samples_end, n);
- q += n;
- nb -= n;
- }
- samples_size = wanted_size;
- }
- }
- av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
- diff, avg_diff, samples_size - samples_size1,
- is->audio_clock, is->video_clock, is->audio_diff_threshold);
- }
- } else {
- /* too big difference : may be initial PTS errors, so
- reset A-V filter */
- is->audio_diff_avg_count = 0;
- is->audio_diff_cum = 0;
- }
- }
-
- return samples_size;
-}
-
-/* decode one audio frame and returns its uncompressed size */
-static int audio_decode_frame(VideoState *is, double *pts_ptr)
-{
- AVPacket *pkt_temp = &is->audio_pkt_temp;
- AVPacket *pkt = &is->audio_pkt;
- AVCodecContext *dec = is->audio_st->codec;
- int n, len1, data_size, got_frame;
- double pts;
- int new_packet = 0;
- int flush_complete = 0;
-
- for (;;) {
- /* NOTE: the audio packet can contain several frames */
- while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) {
- int resample_changed, audio_resample;
-
- if (!is->frame) {
- if (!(is->frame = av_frame_alloc()))
- return AVERROR(ENOMEM);
- }
-
- if (flush_complete)
- break;
- new_packet = 0;
- len1 = avcodec_decode_audio4(dec, is->frame, &got_frame, pkt_temp);
- if (len1 < 0) {
- /* if error, we skip the frame */
- pkt_temp->size = 0;
- break;
- }
-
- pkt_temp->data += len1;
- pkt_temp->size -= len1;
-
- if (!got_frame) {
- /* stop sending empty packets if the decoder is finished */
- if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY)
- flush_complete = 1;
- continue;
- }
- data_size = av_samples_get_buffer_size(NULL, dec->channels,
- is->frame->nb_samples,
- is->frame->format, 1);
-
- audio_resample = is->frame->format != is->sdl_sample_fmt ||
- is->frame->channel_layout != is->sdl_channel_layout ||
- is->frame->sample_rate != is->sdl_sample_rate;
-
- resample_changed = is->frame->format != is->resample_sample_fmt ||
- is->frame->channel_layout != is->resample_channel_layout ||
- is->frame->sample_rate != is->resample_sample_rate;
-
- if ((!is->avr && audio_resample) || resample_changed) {
- int ret;
- if (is->avr)
- avresample_close(is->avr);
- else if (audio_resample) {
- is->avr = avresample_alloc_context();
- if (!is->avr) {
- fprintf(stderr, "error allocating AVAudioResampleContext\n");
- break;
- }
- }
- if (audio_resample) {
- av_opt_set_int(is->avr, "in_channel_layout", is->frame->channel_layout, 0);
- av_opt_set_int(is->avr, "in_sample_fmt", is->frame->format, 0);
- av_opt_set_int(is->avr, "in_sample_rate", is->frame->sample_rate, 0);
- av_opt_set_int(is->avr, "out_channel_layout", is->sdl_channel_layout, 0);
- av_opt_set_int(is->avr, "out_sample_fmt", is->sdl_sample_fmt, 0);
- av_opt_set_int(is->avr, "out_sample_rate", is->sdl_sample_rate, 0);
-
- if ((ret = avresample_open(is->avr)) < 0) {
- fprintf(stderr, "error initializing libavresample\n");
- break;
- }
- }
- is->resample_sample_fmt = is->frame->format;
- is->resample_channel_layout = is->frame->channel_layout;
- is->resample_sample_rate = is->frame->sample_rate;
- }
-
- if (audio_resample) {
- void *tmp_out;
- int out_samples, out_size, out_linesize;
- int osize = av_get_bytes_per_sample(is->sdl_sample_fmt);
- int nb_samples = is->frame->nb_samples;
-
- out_size = av_samples_get_buffer_size(&out_linesize,
- is->sdl_channels,
- nb_samples,
- is->sdl_sample_fmt, 0);
- tmp_out = av_realloc(is->audio_buf1, out_size);
- if (!tmp_out)
- return AVERROR(ENOMEM);
- is->audio_buf1 = tmp_out;
-
- out_samples = avresample_convert(is->avr,
- &is->audio_buf1,
- out_linesize, nb_samples,
- is->frame->data,
- is->frame->linesize[0],
- is->frame->nb_samples);
- if (out_samples < 0) {
- fprintf(stderr, "avresample_convert() failed\n");
- break;
- }
- is->audio_buf = is->audio_buf1;
- data_size = out_samples * osize * is->sdl_channels;
- } else {
- is->audio_buf = is->frame->data[0];
- }
-
- /* if no pts, then compute it */
- pts = is->audio_clock;
- *pts_ptr = pts;
- n = is->sdl_channels * av_get_bytes_per_sample(is->sdl_sample_fmt);
- is->audio_clock += (double)data_size /
- (double)(n * is->sdl_sample_rate);
-#ifdef DEBUG
- {
- static double last_clock;
- printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
- is->audio_clock - last_clock,
- is->audio_clock, pts);
- last_clock = is->audio_clock;
- }
-#endif
- return data_size;
- }
-
- /* free the current packet */
- if (pkt->data)
- av_free_packet(pkt);
- memset(pkt_temp, 0, sizeof(*pkt_temp));
-
- if (is->paused || is->audioq.abort_request) {
- return -1;
- }
-
- /* read next packet */
- if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
- return -1;
-
- if (pkt->data == flush_pkt.data) {
- avcodec_flush_buffers(dec);
- flush_complete = 0;
- }
-
- *pkt_temp = *pkt;
-
- /* if update the audio clock with the pts */
- if (pkt->pts != AV_NOPTS_VALUE) {
- is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
- }
- }
-}
-
-/* prepare a new audio buffer */
-static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
-{
- VideoState *is = opaque;
- int audio_size, len1;
- double pts;
-
- audio_callback_time = av_gettime_relative();
-
- while (len > 0) {
- if (is->audio_buf_index >= is->audio_buf_size) {
- audio_size = audio_decode_frame(is, &pts);
- if (audio_size < 0) {
- /* if error, just output silence */
- is->audio_buf = is->silence_buf;
- is->audio_buf_size = sizeof(is->silence_buf);
- } else {
- if (is->show_audio)
- update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
- audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
- pts);
- is->audio_buf_size = audio_size;
- }
- is->audio_buf_index = 0;
- }
- len1 = is->audio_buf_size - is->audio_buf_index;
- if (len1 > len)
- len1 = len;
- memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
- len -= len1;
- stream += len1;
- is->audio_buf_index += len1;
- }
-}
-
-/* open a given stream. Return 0 if OK */
-static int stream_component_open(VideoState *is, int stream_index)
-{
- AVFormatContext *ic = is->ic;
- AVCodecContext *avctx;
- AVCodec *codec;
- SDL_AudioSpec wanted_spec, spec;
- AVDictionary *opts;
- AVDictionaryEntry *t = NULL;
- int ret = 0;
-
- if (stream_index < 0 || stream_index >= ic->nb_streams)
- return -1;
- avctx = ic->streams[stream_index]->codec;
-
- opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], NULL);
-
- codec = avcodec_find_decoder(avctx->codec_id);
- avctx->workaround_bugs = workaround_bugs;
- avctx->idct_algo = idct;
- avctx->skip_frame = skip_frame;
- avctx->skip_idct = skip_idct;
- avctx->skip_loop_filter = skip_loop_filter;
- avctx->error_concealment = error_concealment;
-
- if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
-
- if (!av_dict_get(opts, "threads", NULL, 0))
- av_dict_set(&opts, "threads", "auto", 0);
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
- av_dict_set(&opts, "refcounted_frames", "1", 0);
- if (!codec ||
- (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;
- goto fail;
- }
-
- /* prepare audio output */
- if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
- is->sdl_sample_rate = avctx->sample_rate;
-
- if (!avctx->channel_layout)
- avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
- if (!avctx->channel_layout) {
- fprintf(stderr, "unable to guess channel layout\n");
- ret = AVERROR_INVALIDDATA;
- goto fail;
- }
- if (avctx->channels == 1)
- is->sdl_channel_layout = AV_CH_LAYOUT_MONO;
- else
- is->sdl_channel_layout = AV_CH_LAYOUT_STEREO;
- is->sdl_channels = av_get_channel_layout_nb_channels(is->sdl_channel_layout);
-
- wanted_spec.format = AUDIO_S16SYS;
- wanted_spec.freq = is->sdl_sample_rate;
- wanted_spec.channels = is->sdl_channels;
- wanted_spec.silence = 0;
- wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
- wanted_spec.callback = sdl_audio_callback;
- wanted_spec.userdata = is;
- if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
- fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
- ret = AVERROR_UNKNOWN;
- goto fail;
- }
- is->audio_hw_buf_size = spec.size;
- is->sdl_sample_fmt = AV_SAMPLE_FMT_S16;
- is->resample_sample_fmt = is->sdl_sample_fmt;
- is->resample_channel_layout = avctx->channel_layout;
- is->resample_sample_rate = avctx->sample_rate;
- }
-
- ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- is->audio_stream = stream_index;
- is->audio_st = ic->streams[stream_index];
- is->audio_buf_size = 0;
- is->audio_buf_index = 0;
-
- /* init averaging filter */
- is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
- is->audio_diff_avg_count = 0;
- /* since we do not have a precise anough audio fifo fullness,
- we correct audio sync only if larger than this threshold */
- is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / avctx->sample_rate;
-
- memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
- packet_queue_init(&is->audioq);
- SDL_PauseAudio(0);
- break;
- case AVMEDIA_TYPE_VIDEO:
- is->video_stream = stream_index;
- is->video_st = ic->streams[stream_index];
-
- packet_queue_init(&is->videoq);
- is->video_tid = SDL_CreateThread(video_thread, is);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- is->subtitle_stream = stream_index;
- is->subtitle_st = ic->streams[stream_index];
- packet_queue_init(&is->subtitleq);
-
- is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
- break;
- default:
- break;
- }
-
-fail:
- av_dict_free(&opts);
-
- return ret;
-}
-
-static void stream_component_close(VideoState *is, int stream_index)
-{
- AVFormatContext *ic = is->ic;
- AVCodecContext *avctx;
-
- if (stream_index < 0 || stream_index >= ic->nb_streams)
- return;
- avctx = ic->streams[stream_index]->codec;
-
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- packet_queue_abort(&is->audioq);
-
- SDL_CloseAudio();
-
- packet_queue_end(&is->audioq);
- av_free_packet(&is->audio_pkt);
- if (is->avr)
- avresample_free(&is->avr);
- av_freep(&is->audio_buf1);
- is->audio_buf = NULL;
- av_frame_free(&is->frame);
-
- if (is->rdft) {
- av_rdft_end(is->rdft);
- av_freep(&is->rdft_data);
- is->rdft = NULL;
- is->rdft_bits = 0;
- }
- break;
- case AVMEDIA_TYPE_VIDEO:
- packet_queue_abort(&is->videoq);
-
- /* note: we also signal this mutex to make sure we deblock the
- video thread in all cases */
- SDL_LockMutex(is->pictq_mutex);
- SDL_CondSignal(is->pictq_cond);
- SDL_UnlockMutex(is->pictq_mutex);
-
- SDL_WaitThread(is->video_tid, NULL);
-
- packet_queue_end(&is->videoq);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- packet_queue_abort(&is->subtitleq);
-
- /* note: we also signal this mutex to make sure we deblock the
- video thread in all cases */
- SDL_LockMutex(is->subpq_mutex);
- is->subtitle_stream_changed = 1;
-
- SDL_CondSignal(is->subpq_cond);
- SDL_UnlockMutex(is->subpq_mutex);
-
- SDL_WaitThread(is->subtitle_tid, NULL);
-
- packet_queue_end(&is->subtitleq);
- break;
- default:
- break;
- }
-
- ic->streams[stream_index]->discard = AVDISCARD_ALL;
- avcodec_close(avctx);
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- is->audio_st = NULL;
- is->audio_stream = -1;
- break;
- case AVMEDIA_TYPE_VIDEO:
- is->video_st = NULL;
- is->video_stream = -1;
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- is->subtitle_st = NULL;
- is->subtitle_stream = -1;
- break;
- default:
- break;
- }
-}
-
-/* since we have only one decoding thread, we can use a global
- variable instead of a thread local variable */
-static VideoState *global_video_state;
-
-static int decode_interrupt_cb(void *ctx)
-{
- return global_video_state && global_video_state->abort_request;
-}
-
-/* this thread gets the stream from the disk or the network */
-static int decode_thread(void *arg)
-{
- VideoState *is = arg;
- AVFormatContext *ic = NULL;
- int err, i, ret;
- int st_index[AVMEDIA_TYPE_NB];
- AVPacket pkt1, *pkt = &pkt1;
- int eof = 0;
- int pkt_in_play_range = 0;
- AVDictionaryEntry *t;
- AVDictionary **opts;
- int orig_nb_streams;
-
- memset(st_index, -1, sizeof(st_index));
- is->video_stream = -1;
- is->audio_stream = -1;
- is->subtitle_stream = -1;
-
- global_video_state = is;
-
- ic = avformat_alloc_context();
- if (!ic) {
- av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- ic->interrupt_callback.callback = decode_interrupt_cb;
- err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
- if (err < 0) {
- print_error(is->filename, err);
- ret = -1;
- goto fail;
- }
- 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;
- goto fail;
- }
- is->ic = ic;
-
- if (genpts)
- ic->flags |= AVFMT_FLAG_GENPTS;
-
- opts = setup_find_stream_info_opts(ic, codec_opts);
- orig_nb_streams = ic->nb_streams;
-
- err = avformat_find_stream_info(ic, opts);
-
- for (i = 0; i < orig_nb_streams; i++)
- av_dict_free(&opts[i]);
- av_freep(&opts);
-
- if (err < 0) {
- fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
- ret = -1;
- goto fail;
- }
-
- if (ic->pb)
- ic->pb->eof_reached = 0; // FIXME hack, avplay maybe should not use url_feof() to test for the end
-
- if (seek_by_bytes < 0)
- seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT);
-
- /* if seeking requested, we execute it */
- if (start_time != AV_NOPTS_VALUE) {
- int64_t timestamp;
-
- timestamp = start_time;
- /* add the stream start time */
- if (ic->start_time != AV_NOPTS_VALUE)
- timestamp += ic->start_time;
- ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
- if (ret < 0) {
- fprintf(stderr, "%s: could not seek to position %0.3f\n",
- is->filename, (double)timestamp / AV_TIME_BASE);
- }
- }
-
- for (i = 0; i < ic->nb_streams; i++)
- ic->streams[i]->discard = AVDISCARD_ALL;
- if (!video_disable)
- st_index[AVMEDIA_TYPE_VIDEO] =
- av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
- wanted_stream[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
- if (!audio_disable)
- st_index[AVMEDIA_TYPE_AUDIO] =
- av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
- wanted_stream[AVMEDIA_TYPE_AUDIO],
- st_index[AVMEDIA_TYPE_VIDEO],
- NULL, 0);
- if (!video_disable)
- st_index[AVMEDIA_TYPE_SUBTITLE] =
- av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
- wanted_stream[AVMEDIA_TYPE_SUBTITLE],
- (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
- st_index[AVMEDIA_TYPE_AUDIO] :
- st_index[AVMEDIA_TYPE_VIDEO]),
- NULL, 0);
- if (show_status) {
- av_dump_format(ic, 0, is->filename, 0);
- }
-
- /* open the streams */
- if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
- stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
- }
-
- ret = -1;
- if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
- ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
- }
- is->refresh_tid = SDL_CreateThread(refresh_thread, is);
- if (ret < 0) {
- if (!display_disable)
- is->show_audio = 2;
- }
-
- if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
- stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
- }
-
- if (is->video_stream < 0 && is->audio_stream < 0) {
- fprintf(stderr, "%s: could not open codecs\n", is->filename);
- ret = -1;
- goto fail;
- }
-
- for (;;) {
- if (is->abort_request)
- break;
- if (is->paused != is->last_paused) {
- is->last_paused = is->paused;
- if (is->paused)
- is->read_pause_return = av_read_pause(ic);
- else
- av_read_play(ic);
- }
-#if CONFIG_RTSP_DEMUXER
- if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
- /* wait 10 ms to avoid trying to get another packet */
- /* XXX: horrible */
- SDL_Delay(10);
- continue;
- }
-#endif
- if (is->seek_req) {
- int64_t seek_target = is->seek_pos;
- int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
- int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
-// FIXME the +-2 is due to rounding being not done in the correct direction in generation
-// of the seek_pos/seek_rel variables
-
- ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
- if (ret < 0) {
- fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
- } else {
- if (is->audio_stream >= 0) {
- packet_queue_flush(&is->audioq);
- packet_queue_put(&is->audioq, &flush_pkt);
- }
- if (is->subtitle_stream >= 0) {
- packet_queue_flush(&is->subtitleq);
- packet_queue_put(&is->subtitleq, &flush_pkt);
- }
- if (is->video_stream >= 0) {
- packet_queue_flush(&is->videoq);
- packet_queue_put(&is->videoq, &flush_pkt);
- }
- }
- is->seek_req = 0;
- eof = 0;
- }
-
- /* if the queue are full, no need to read more */
- if (!infinite_buffer &&
- (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
- || ( (is->audioq .size > MIN_AUDIOQ_SIZE || is->audio_stream < 0)
- && (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0)
- && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0)))) {
- /* wait 10 ms */
- SDL_Delay(10);
- continue;
- }
- if (eof) {
- if (is->video_stream >= 0) {
- av_init_packet(pkt);
- pkt->data = NULL;
- pkt->size = 0;
- pkt->stream_index = is->video_stream;
- packet_queue_put(&is->videoq, pkt);
- }
- if (is->audio_stream >= 0 &&
- is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) {
- av_init_packet(pkt);
- pkt->data = NULL;
- pkt->size = 0;
- pkt->stream_index = is->audio_stream;
- packet_queue_put(&is->audioq, pkt);
- }
- SDL_Delay(10);
- if (is->audioq.size + is->videoq.size + is->subtitleq.size == 0) {
- if (loop != 1 && (!loop || --loop)) {
- stream_seek(cur_stream, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
- } else if (!noautoexit) {
- ret = AVERROR_EOF;
- goto fail;
- }
- }
- continue;
- }
- ret = av_read_frame(ic, pkt);
- if (ret < 0) {
- if (ret == AVERROR_EOF || (ic->pb && ic->pb->eof_reached))
- eof = 1;
- if (ic->pb && ic->pb->error)
- break;
- SDL_Delay(100); /* wait for user event */
- continue;
- }
- /* check if packet is in play range specified by user, then queue, otherwise discard */
- pkt_in_play_range = duration == AV_NOPTS_VALUE ||
- (pkt->pts - ic->streams[pkt->stream_index]->start_time) *
- av_q2d(ic->streams[pkt->stream_index]->time_base) -
- (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
- <= ((double)duration / 1000000);
- if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
- packet_queue_put(&is->audioq, pkt);
- } else if (pkt->stream_index == is->video_stream && pkt_in_play_range) {
- packet_queue_put(&is->videoq, pkt);
- } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
- packet_queue_put(&is->subtitleq, pkt);
- } else {
- av_free_packet(pkt);
- }
- }
- /* wait until the end */
- while (!is->abort_request) {
- SDL_Delay(100);
- }
-
- ret = 0;
- fail:
- /* disable interrupting */
- global_video_state = NULL;
-
- /* close each stream */
- if (is->audio_stream >= 0)
- stream_component_close(is, is->audio_stream);
- if (is->video_stream >= 0)
- stream_component_close(is, is->video_stream);
- if (is->subtitle_stream >= 0)
- stream_component_close(is, is->subtitle_stream);
- if (is->ic) {
- avformat_close_input(&is->ic);
- }
-
- if (ret != 0) {
- SDL_Event event;
-
- event.type = FF_QUIT_EVENT;
- event.user.data1 = is;
- SDL_PushEvent(&event);
- }
- return 0;
-}
-
-static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
-{
- VideoState *is;
-
- is = av_mallocz(sizeof(VideoState));
- if (!is)
- return NULL;
- av_strlcpy(is->filename, filename, sizeof(is->filename));
- is->iformat = iformat;
- is->ytop = 0;
- is->xleft = 0;
-
- /* start video display */
- is->pictq_mutex = SDL_CreateMutex();
- is->pictq_cond = SDL_CreateCond();
-
- is->subpq_mutex = SDL_CreateMutex();
- is->subpq_cond = SDL_CreateCond();
-
- is->av_sync_type = av_sync_type;
- is->parse_tid = SDL_CreateThread(decode_thread, is);
- if (!is->parse_tid) {
- av_free(is);
- return NULL;
- }
- return is;
-}
-
-static void stream_cycle_channel(VideoState *is, int codec_type)
-{
- AVFormatContext *ic = is->ic;
- int start_index, stream_index;
- AVStream *st;
-
- if (codec_type == AVMEDIA_TYPE_VIDEO)
- start_index = is->video_stream;
- else if (codec_type == AVMEDIA_TYPE_AUDIO)
- start_index = is->audio_stream;
- else
- start_index = is->subtitle_stream;
- if (start_index < (codec_type == AVMEDIA_TYPE_SUBTITLE ? -1 : 0))
- return;
- stream_index = start_index;
- for (;;) {
- if (++stream_index >= is->ic->nb_streams)
- {
- if (codec_type == AVMEDIA_TYPE_SUBTITLE)
- {
- stream_index = -1;
- goto the_end;
- } else
- stream_index = 0;
- }
- if (stream_index == start_index)
- return;
- st = ic->streams[stream_index];
- if (st->codec->codec_type == codec_type) {
- /* check that parameters are OK */
- switch (codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- if (st->codec->sample_rate != 0 &&
- st->codec->channels != 0)
- goto the_end;
- break;
- case AVMEDIA_TYPE_VIDEO:
- case AVMEDIA_TYPE_SUBTITLE:
- goto the_end;
- default:
- break;
- }
- }
- }
- the_end:
- stream_component_close(is, start_index);
- stream_component_open(is, stream_index);
-}
-
-
-static void toggle_full_screen(void)
-{
-#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
- /* OS X needs to empty the picture_queue */
- int i;
- for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
- cur_stream->pictq[i].reallocate = 1;
-#endif
- is_full_screen = !is_full_screen;
- video_open(cur_stream);
-}
-
-static void toggle_pause(void)
-{
- if (cur_stream)
- stream_pause(cur_stream);
- step = 0;
-}
-
-static void step_to_next_frame(void)
-{
- if (cur_stream) {
- /* if the stream is paused unpause it, then step */
- if (cur_stream->paused)
- stream_pause(cur_stream);
- }
- step = 1;
-}
-
-static void toggle_audio_display(void)
-{
- if (cur_stream) {
- int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
- cur_stream->show_audio = (cur_stream->show_audio + 1) % 3;
- fill_rectangle(screen,
- cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height,
- bgcolor);
- SDL_UpdateRect(screen, cur_stream->xleft, cur_stream->ytop, cur_stream->width, cur_stream->height);
- }
-}
-
-static void seek_chapter(VideoState *is, int incr)
-{
- int64_t pos = get_master_clock(is) * AV_TIME_BASE;
- int i;
-
- if (!is->ic->nb_chapters)
- return;
-
- /* find the current chapter */
- for (i = 0; i < is->ic->nb_chapters; i++) {
- AVChapter *ch = is->ic->chapters[i];
- if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0) {
- i--;
- break;
- }
- }
-
- i += incr;
- i = FFMAX(i, 0);
- if (i >= is->ic->nb_chapters)
- return;
-
- av_log(NULL, AV_LOG_VERBOSE, "Seeking to chapter %d.\n", i);
- stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,
- AV_TIME_BASE_Q), 0, 0);
-}
-
-/* handle an event sent by the GUI */
-static void event_loop(void)
-{
- SDL_Event event;
- double incr, pos, frac;
-
- for (;;) {
- double x;
- SDL_WaitEvent(&event);
- switch (event.type) {
- case SDL_KEYDOWN:
- if (exit_on_keydown) {
- do_exit();
- break;
- }
- switch (event.key.keysym.sym) {
- case SDLK_ESCAPE:
- case SDLK_q:
- do_exit();
- break;
- case SDLK_f:
- toggle_full_screen();
- break;
- case SDLK_p:
- case SDLK_SPACE:
- toggle_pause();
- break;
- case SDLK_s: // S: Step to next frame
- step_to_next_frame();
- break;
- case SDLK_a:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
- break;
- case SDLK_v:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
- break;
- case SDLK_t:
- if (cur_stream)
- stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
- break;
- case SDLK_w:
- toggle_audio_display();
- break;
- case SDLK_PAGEUP:
- seek_chapter(cur_stream, 1);
- break;
- case SDLK_PAGEDOWN:
- seek_chapter(cur_stream, -1);
- break;
- case SDLK_LEFT:
- incr = -10.0;
- goto do_seek;
- case SDLK_RIGHT:
- incr = 10.0;
- goto do_seek;
- case SDLK_UP:
- incr = 60.0;
- goto do_seek;
- case SDLK_DOWN:
- incr = -60.0;
- do_seek:
- if (cur_stream) {
- if (seek_by_bytes) {
- if (cur_stream->video_stream >= 0 && cur_stream->video_current_pos >= 0) {
- pos = cur_stream->video_current_pos;
- } else if (cur_stream->audio_stream >= 0 && cur_stream->audio_pkt.pos >= 0) {
- pos = cur_stream->audio_pkt.pos;
- } else
- pos = avio_tell(cur_stream->ic->pb);
- if (cur_stream->ic->bit_rate)
- incr *= cur_stream->ic->bit_rate / 8.0;
- else
- incr *= 180000.0;
- pos += incr;
- stream_seek(cur_stream, pos, incr, 1);
- } else {
- pos = get_master_clock(cur_stream);
- pos += incr;
- stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
- }
- }
- break;
- default:
- break;
- }
- break;
- case SDL_MOUSEBUTTONDOWN:
- if (exit_on_mousedown) {
- do_exit();
- break;
- }
- case SDL_MOUSEMOTION:
- if (event.type == SDL_MOUSEBUTTONDOWN) {
- x = event.button.x;
- } else {
- if (event.motion.state != SDL_PRESSED)
- break;
- x = event.motion.x;
- }
- if (cur_stream) {
- if (seek_by_bytes || cur_stream->ic->duration <= 0) {
- uint64_t size = avio_size(cur_stream->ic->pb);
- stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
- } else {
- int64_t ts;
- int ns, hh, mm, ss;
- int tns, thh, tmm, tss;
- tns = cur_stream->ic->duration / 1000000LL;
- thh = tns / 3600;
- tmm = (tns % 3600) / 60;
- tss = (tns % 60);
- frac = x / cur_stream->width;
- ns = frac * tns;
- hh = ns / 3600;
- mm = (ns % 3600) / 60;
- ss = (ns % 60);
- fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
- hh, mm, ss, thh, tmm, tss);
- ts = frac * cur_stream->ic->duration;
- if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
- ts += cur_stream->ic->start_time;
- stream_seek(cur_stream, ts, 0, 0);
- }
- }
- break;
- case SDL_VIDEORESIZE:
- if (cur_stream) {
- screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
- SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
- screen_width = cur_stream->width = event.resize.w;
- screen_height = cur_stream->height = event.resize.h;
- }
- break;
- case SDL_QUIT:
- case FF_QUIT_EVENT:
- do_exit();
- break;
- case FF_ALLOC_EVENT:
- video_open(event.user.data1);
- alloc_picture(event.user.data1);
- break;
- case FF_REFRESH_EVENT:
- video_refresh_timer(event.user.data1);
- cur_stream->refresh = 0;
- break;
- default:
- break;
- }
- }
-}
-
-static int opt_frame_size(void *optctx, const char *opt, const char *arg)
-{
- av_log(NULL, AV_LOG_ERROR,
- "Option '%s' has been removed, use private format options instead\n", opt);
- return AVERROR(EINVAL);
-}
-
-static int opt_width(void *optctx, const char *opt, const char *arg)
-{
- screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
- return 0;
-}
-
-static int opt_height(void *optctx, const char *opt, const char *arg)
-{
- screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
- return 0;
-}
-
-static int opt_format(void *optctx, const char *opt, const char *arg)
-{
- file_iformat = av_find_input_format(arg);
- if (!file_iformat) {
- fprintf(stderr, "Unknown input format: %s\n", arg);
- return AVERROR(EINVAL);
- }
- return 0;
-}
-
-static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
-{
- av_log(NULL, AV_LOG_ERROR,
- "Option '%s' has been removed, use private format options instead\n", opt);
- return AVERROR(EINVAL);
-}
-
-static int opt_sync(void *optctx, const char *opt, const char *arg)
-{
- if (!strcmp(arg, "audio"))
- av_sync_type = AV_SYNC_AUDIO_MASTER;
- else if (!strcmp(arg, "video"))
- av_sync_type = AV_SYNC_VIDEO_MASTER;
- else if (!strcmp(arg, "ext"))
- av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
- else {
- fprintf(stderr, "Unknown value for %s: %s\n", opt, arg);
- exit(1);
- }
- return 0;
-}
-
-static int opt_seek(void *optctx, const char *opt, const char *arg)
-{
- start_time = parse_time_or_die(opt, arg, 1);
- return 0;
-}
-
-static int opt_duration(void *optctx, const char *opt, const char *arg)
-{
- duration = parse_time_or_die(opt, arg, 1);
- return 0;
-}
-
-static const OptionDef options[] = {
-#include "cmdutils_common_opts.h"
- { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
- { "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
- { "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
- { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
- { "an", OPT_BOOL, { &audio_disable }, "disable audio" },
- { "vn", OPT_BOOL, { &video_disable }, "disable video" },
- { "ast", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_number" },
- { "vst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_number" },
- { "sst", OPT_INT | HAS_ARG | OPT_EXPERT, { &wanted_stream[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_number" },
- { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
- { "t", HAS_ARG, { .func_arg = opt_duration }, "play \"duration\" seconds of audio/video", "duration" },
- { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
- { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
- { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" },
- { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" },
- { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
- { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, { &workaround_bugs }, "workaround bugs", "" },
- { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
- { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
- { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
- { "skiploop", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_loop_filter }, "", "" },
- { "skipframe", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_frame }, "", "" },
- { "skipidct", OPT_INT | HAS_ARG | OPT_EXPERT, { &skip_idct }, "", "" },
- { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, { &idct }, "set idct algo", "algo" },
- { "ec", OPT_INT | HAS_ARG | OPT_EXPERT, { &error_concealment }, "set error concealment options", "bit_mask" },
- { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
- { "noautoexit", OPT_BOOL | OPT_EXPERT, { &noautoexit }, "Do not exit at the end of playback", "" },
- { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
- { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
- { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
- { "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
- { "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
- { "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" },
-#if CONFIG_AVFILTER
- { "vf", OPT_STRING | HAS_ARG, { &vfilters }, "video filters", "filter list" },
-#endif
- { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
- { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { opt_default }, "generic catch all option", "" },
- { "i", 0, { NULL }, "avconv compatibility dummy option", ""},
- { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
- { NULL, },
-};
-
-static void show_usage(void)
-{
- printf("Simple media player\n");
- printf("usage: %s [options] input_file\n", program_name);
- printf("\n");
-}
-
-void show_help_default(const char *opt, const char *arg)
-{
- av_log_set_callback(log_callback_help);
- show_usage();
- show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
- show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
- printf("\n");
- show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
- show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
-#if !CONFIG_AVFILTER
- show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
-#endif
- printf("\nWhile playing:\n"
- "q, ESC quit\n"
- "f toggle full screen\n"
- "p, SPC pause\n"
- "a cycle audio channel\n"
- "v cycle video channel\n"
- "t cycle subtitle channel\n"
- "w show audio waves\n"
- "s activate frame-step mode\n"
- "left/right seek backward/forward 10 seconds\n"
- "down/up seek backward/forward 1 minute\n"
- "mouse click seek to percentage in file corresponding to fraction of width\n"
- );
-}
-
-static void opt_input_file(void *optctx, const char *filename)
-{
- if (input_filename) {
- fprintf(stderr, "Argument '%s' provided as input filename, but '%s' was already specified.\n",
- filename, input_filename);
- exit(1);
- }
- if (!strcmp(filename, "-"))
- filename = "pipe:";
- input_filename = filename;
-}
-
-/* Called from the main */
-int main(int argc, char **argv)
-{
- int flags;
-
- av_log_set_flags(AV_LOG_SKIP_REPEATED);
- parse_loglevel(argc, argv, options);
-
- /* register all codecs, demux and protocols */
- avcodec_register_all();
-#if CONFIG_AVDEVICE
- avdevice_register_all();
-#endif
-#if CONFIG_AVFILTER
- avfilter_register_all();
-#endif
- av_register_all();
- avformat_network_init();
-
- init_opts();
-
- show_banner();
-
- parse_options(NULL, argc, argv, options, opt_input_file);
-
- if (!input_filename) {
- show_usage();
- fprintf(stderr, "An input file must be specified\n");
- fprintf(stderr, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
- exit(1);
- }
-
- if (display_disable) {
- video_disable = 1;
- }
- flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
-#if !defined(__MINGW32__) && !defined(__APPLE__)
- flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
-#endif
- if (SDL_Init (flags)) {
- fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
- exit(1);
- }
-
- if (!display_disable) {
- const SDL_VideoInfo *vi = SDL_GetVideoInfo();
- fs_screen_width = vi->current_w;
- fs_screen_height = vi->current_h;
- }
-
- SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
- SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
- SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
-
- av_init_packet(&flush_pkt);
- flush_pkt.data = (uint8_t *)&flush_pkt;
-
- cur_stream = stream_open(input_filename, file_iformat);
-
- event_loop();
-
- /* never returns */
-
- return 0;
-}
diff --git a/avprobe.c b/avprobe.c
deleted file mode 100644
index a83fa6815d..0000000000
--- a/avprobe.c
+++ /dev/null
@@ -1,1031 +0,0 @@
-/*
- * avprobe : Simple Media Prober based on the Libav libraries
- * Copyright (c) 2007-2010 Stefano Sabatini
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-
-#include "libavformat/avformat.h"
-#include "libavcodec/avcodec.h"
-#include "libavutil/avstring.h"
-#include "libavutil/display.h"
-#include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/dict.h"
-#include "libavutil/libm.h"
-#include "libavdevice/avdevice.h"
-#include "cmdutils.h"
-
-const char program_name[] = "avprobe";
-const int program_birth_year = 2007;
-
-static int do_show_format = 0;
-static AVDictionary *fmt_entries_to_show = NULL;
-static int nb_fmt_entries_to_show;
-static int do_show_packets = 0;
-static int do_show_streams = 0;
-
-static int show_value_unit = 0;
-static int use_value_prefix = 0;
-static int use_byte_value_binary_prefix = 0;
-static int use_value_sexagesimal_format = 0;
-
-/* globals */
-static const OptionDef *options;
-
-/* AVprobe context */
-static const char *input_filename;
-static AVInputFormat *iformat = NULL;
-
-static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
-static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P" };
-
-static const char unit_second_str[] = "s" ;
-static const char unit_hertz_str[] = "Hz" ;
-static const char unit_byte_str[] = "byte" ;
-static const char unit_bit_per_second_str[] = "bit/s";
-
-static void avprobe_cleanup(int ret)
-{
- av_dict_free(&fmt_entries_to_show);
-}
-
-/*
- * The output is structured in array and objects that might contain items
- * Array could require the objects within to not be named.
- * Object could require the items within to be named.
- *
- * For flat representation the name of each section is saved on prefix so it
- * can be rendered in order to represent nested structures (e.g. array of
- * objects for the packets list).
- *
- * Within an array each element can need an unique identifier or an index.
- *
- * Nesting level is accounted separately.
- */
-
-typedef enum {
- ARRAY,
- OBJECT
-} PrintElementType;
-
-typedef struct PrintElement {
- const char *name;
- PrintElementType type;
- int64_t index;
- int64_t nb_elems;
-} PrintElement;
-
-typedef struct PrintContext {
- PrintElement *prefix;
- int level;
- void (*print_header)(void);
- void (*print_footer)(void);
-
- void (*print_array_header) (const char *name, int plain_values);
- void (*print_array_footer) (const char *name, int plain_values);
- void (*print_object_header)(const char *name);
- void (*print_object_footer)(const char *name);
-
- void (*print_integer) (const char *key, int64_t value);
- void (*print_string) (const char *key, const char *value);
-} PrintContext;
-
-static AVIOContext *probe_out = NULL;
-static PrintContext octx;
-#define AVP_INDENT() avio_printf(probe_out, "%*c", octx.level * 2, ' ')
-
-/*
- * Default format, INI
- *
- * - all key and values are utf8
- * - '.' is the subgroup separator
- * - newlines and the following characters are escaped
- * - '\' is the escape character
- * - '#' is the comment
- * - '=' is the key/value separators
- * - ':' is not used but usually parsed as key/value separator
- */
-
-static void ini_print_header(void)
-{
- avio_printf(probe_out, "# avprobe output\n\n");
-}
-static void ini_print_footer(void)
-{
- avio_w8(probe_out, '\n');
-}
-
-static void ini_escape_print(const char *s)
-{
- int i = 0;
- char c = 0;
-
- while (c = s[i++]) {
- switch (c) {
- case '\r': avio_printf(probe_out, "%s", "\\r"); break;
- case '\n': avio_printf(probe_out, "%s", "\\n"); break;
- case '\f': avio_printf(probe_out, "%s", "\\f"); break;
- case '\b': avio_printf(probe_out, "%s", "\\b"); break;
- case '\t': avio_printf(probe_out, "%s", "\\t"); break;
- case '\\':
- case '#' :
- case '=' :
- case ':' : avio_w8(probe_out, '\\');
- default:
- if ((unsigned char)c < 32)
- avio_printf(probe_out, "\\x00%02x", c & 0xff);
- else
- avio_w8(probe_out, c);
- break;
- }
- }
-}
-
-static void ini_print_array_header(const char *name, int plain_values)
-{
- if (!plain_values) {
- /* Add a new line if we create a new full group */
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, "\n");
- } else {
- ini_escape_print(name);
- avio_w8(probe_out, '=');
- }
-}
-
-static void ini_print_array_footer(const char *name, int plain_values)
-{
- if (plain_values)
- avio_printf(probe_out, "\n");
-}
-
-static void ini_print_object_header(const char *name)
-{
- int i;
- PrintElement *el = octx.prefix + octx.level -1;
-
- if (el->nb_elems)
- avio_printf(probe_out, "\n");
-
- avio_printf(probe_out, "[");
-
- for (i = 1; i < octx.level; i++) {
- el = octx.prefix + i;
- avio_printf(probe_out, "%s.", el->name);
- if (el->index >= 0)
- avio_printf(probe_out, "%"PRId64".", el->index);
- }
-
- avio_printf(probe_out, "%s", name);
- if (el->type == ARRAY)
- avio_printf(probe_out, ".%"PRId64"", el->nb_elems);
- avio_printf(probe_out, "]\n");
-}
-
-static void ini_print_integer(const char *key, int64_t value)
-{
- if (key) {
- ini_escape_print(key);
- avio_printf(probe_out, "=%"PRId64"\n", value);
- } else {
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ",");
- avio_printf(probe_out, "%"PRId64, value);
- }
-}
-
-
-static void ini_print_string(const char *key, const char *value)
-{
- ini_escape_print(key);
- avio_printf(probe_out, "=");
- ini_escape_print(value);
- avio_w8(probe_out, '\n');
-}
-
-/*
- * Alternate format, JSON
- */
-
-static void json_print_header(void)
-{
- avio_printf(probe_out, "{");
-}
-static void json_print_footer(void)
-{
- avio_printf(probe_out, "}\n");
-}
-
-static void json_print_array_header(const char *name, int plain_values)
-{
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ",\n");
- AVP_INDENT();
- avio_printf(probe_out, "\"%s\" : ", name);
- avio_printf(probe_out, "[\n");
-}
-
-static void json_print_array_footer(const char *name, int plain_values)
-{
- avio_printf(probe_out, "\n");
- AVP_INDENT();
- avio_printf(probe_out, "]");
-}
-
-static void json_print_object_header(const char *name)
-{
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ",\n");
- AVP_INDENT();
- if (octx.prefix[octx.level -1].type == OBJECT)
- avio_printf(probe_out, "\"%s\" : ", name);
- avio_printf(probe_out, "{\n");
-}
-
-static void json_print_object_footer(const char *name)
-{
- avio_printf(probe_out, "\n");
- AVP_INDENT();
- avio_printf(probe_out, "}");
-}
-
-static void json_print_integer(const char *key, int64_t value)
-{
- if (key) {
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ",\n");
- AVP_INDENT();
- avio_printf(probe_out, "\"%s\" : ", key);
- } else {
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ", ");
- else
- AVP_INDENT();
- }
- avio_printf(probe_out, "%"PRId64, value);
-}
-
-static void json_escape_print(const char *s)
-{
- int i = 0;
- char c = 0;
-
- while (c = s[i++]) {
- switch (c) {
- case '\r': avio_printf(probe_out, "%s", "\\r"); break;
- case '\n': avio_printf(probe_out, "%s", "\\n"); break;
- case '\f': avio_printf(probe_out, "%s", "\\f"); break;
- case '\b': avio_printf(probe_out, "%s", "\\b"); break;
- case '\t': avio_printf(probe_out, "%s", "\\t"); break;
- case '\\':
- case '"' : avio_w8(probe_out, '\\');
- default:
- if ((unsigned char)c < 32)
- avio_printf(probe_out, "\\u00%02x", c & 0xff);
- else
- avio_w8(probe_out, c);
- break;
- }
- }
-}
-
-static void json_print_string(const char *key, const char *value)
-{
- if (octx.prefix[octx.level -1].nb_elems)
- avio_printf(probe_out, ",\n");
- AVP_INDENT();
- avio_w8(probe_out, '\"');
- json_escape_print(key);
- avio_printf(probe_out, "\" : \"");
- json_escape_print(value);
- avio_w8(probe_out, '\"');
-}
-
-/*
- * old-style pseudo-INI
- */
-static void old_print_object_header(const char *name)
-{
- char *str, *p;
-
- if (!strcmp(name, "tags"))
- return;
-
- str = p = av_strdup(name);
- if (!str)
- return;
- while (*p) {
- *p = av_toupper(*p);
- p++;
- }
-
- avio_printf(probe_out, "[%s]\n", str);
- av_freep(&str);
-}
-
-static void old_print_object_footer(const char *name)
-{
- char *str, *p;
-
- if (!strcmp(name, "tags"))
- return;
-
- str = p = av_strdup(name);
- if (!str)
- return;
- while (*p) {
- *p = av_toupper(*p);
- p++;
- }
-
- avio_printf(probe_out, "[/%s]\n", str);
- av_freep(&str);
-}
-
-static void old_print_string(const char *key, const char *value)
-{
- if (!strcmp(octx.prefix[octx.level - 1].name, "tags"))
- avio_printf(probe_out, "TAG:");
- ini_print_string(key, value);
-}
-
-/*
- * Simple Formatter for single entries.
- */
-
-static void show_format_entry_integer(const char *key, int64_t value)
-{
- if (key && av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
- if (nb_fmt_entries_to_show > 1)
- avio_printf(probe_out, "%s=", key);
- avio_printf(probe_out, "%"PRId64"\n", value);
- }
-}
-
-static void show_format_entry_string(const char *key, const char *value)
-{
- if (key && av_dict_get(fmt_entries_to_show, key, NULL, 0)) {
- if (nb_fmt_entries_to_show > 1)
- avio_printf(probe_out, "%s=", key);
- avio_printf(probe_out, "%s\n", value);
- }
-}
-
-static void probe_group_enter(const char *name, int type)
-{
- int64_t count = -1;
-
- octx.prefix =
- av_realloc(octx.prefix, sizeof(PrintElement) * (octx.level + 1));
-
- if (!octx.prefix || !name) {
- fprintf(stderr, "Out of memory\n");
- exit_program(1);
- }
-
- if (octx.level) {
- PrintElement *parent = octx.prefix + octx.level -1;
- if (parent->type == ARRAY)
- count = parent->nb_elems;
- parent->nb_elems++;
- }
-
- octx.prefix[octx.level++] = (PrintElement){name, type, count, 0};
-}
-
-static void probe_group_leave(void)
-{
- --octx.level;
-}
-
-static void probe_header(void)
-{
- if (octx.print_header)
- octx.print_header();
- probe_group_enter("root", OBJECT);
-}
-
-static void probe_footer(void)
-{
- if (octx.print_footer)
- octx.print_footer();
- probe_group_leave();
-}
-
-
-static void probe_array_header(const char *name, int plain_values)
-{
- if (octx.print_array_header)
- octx.print_array_header(name, plain_values);
-
- probe_group_enter(name, ARRAY);
-}
-
-static void probe_array_footer(const char *name, int plain_values)
-{
- probe_group_leave();
- if (octx.print_array_footer)
- octx.print_array_footer(name, plain_values);
-}
-
-static void probe_object_header(const char *name)
-{
- if (octx.print_object_header)
- octx.print_object_header(name);
-
- probe_group_enter(name, OBJECT);
-}
-
-static void probe_object_footer(const char *name)
-{
- probe_group_leave();
- if (octx.print_object_footer)
- octx.print_object_footer(name);
-}
-
-static void probe_int(const char *key, int64_t value)
-{
- octx.print_integer(key, value);
- octx.prefix[octx.level -1].nb_elems++;
-}
-
-static void probe_str(const char *key, const char *value)
-{
- octx.print_string(key, value);
- octx.prefix[octx.level -1].nb_elems++;
-}
-
-static void probe_dict(AVDictionary *dict, const char *name)
-{
- AVDictionaryEntry *entry = NULL;
- if (!dict)
- return;
- probe_object_header(name);
- while ((entry = av_dict_get(dict, "", entry, AV_DICT_IGNORE_SUFFIX))) {
- probe_str(entry->key, entry->value);
- }
- probe_object_footer(name);
-}
-
-static char *value_string(char *buf, int buf_size, double val, const char *unit)
-{
- if (unit == unit_second_str && use_value_sexagesimal_format) {
- double secs;
- int hours, mins;
- secs = val;
- mins = (int)secs / 60;
- secs = secs - mins * 60;
- hours = mins / 60;
- mins %= 60;
- snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
- } else if (use_value_prefix) {
- const char *prefix_string;
- int index;
-
- if (unit == unit_byte_str && use_byte_value_binary_prefix) {
- index = (int) log2(val) / 10;
- index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) - 1);
- val /= pow(2, index * 10);
- prefix_string = binary_unit_prefixes[index];
- } else {
- index = (int) (log10(val)) / 3;
- index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) - 1);
- val /= pow(10, index * 3);
- prefix_string = decimal_unit_prefixes[index];
- }
- snprintf(buf, buf_size, "%.*f%s%s",
- index ? 3 : 0, val,
- prefix_string,
- show_value_unit ? unit : "");
- } else {
- snprintf(buf, buf_size, "%f%s", val, show_value_unit ? unit : "");
- }
-
- return buf;
-}
-
-static char *time_value_string(char *buf, int buf_size, int64_t val,
- const AVRational *time_base)
-{
- if (val == AV_NOPTS_VALUE) {
- snprintf(buf, buf_size, "N/A");
- } else {
- value_string(buf, buf_size, val * av_q2d(*time_base), unit_second_str);
- }
-
- return buf;
-}
-
-static char *ts_value_string(char *buf, int buf_size, int64_t ts)
-{
- if (ts == AV_NOPTS_VALUE) {
- snprintf(buf, buf_size, "N/A");
- } else {
- snprintf(buf, buf_size, "%"PRId64, ts);
- }
-
- return buf;
-}
-
-static char *rational_string(char *buf, int buf_size, const char *sep,
- const AVRational *rat)
-{
- snprintf(buf, buf_size, "%d%s%d", rat->num, sep, rat->den);
- return buf;
-}
-
-static char *tag_string(char *buf, int buf_size, int tag)
-{
- snprintf(buf, buf_size, "0x%04x", tag);
- return buf;
-}
-
-static void show_packet(AVFormatContext *fmt_ctx, AVPacket *pkt)
-{
- char val_str[128];
- AVStream *st = fmt_ctx->streams[pkt->stream_index];
-
- probe_object_header("packet");
- probe_str("codec_type", media_type_string(st->codec->codec_type));
- probe_int("stream_index", pkt->stream_index);
- probe_str("pts", ts_value_string(val_str, sizeof(val_str), pkt->pts));
- probe_str("pts_time", time_value_string(val_str, sizeof(val_str),
- pkt->pts, &st->time_base));
- probe_str("dts", ts_value_string(val_str, sizeof(val_str), pkt->dts));
- probe_str("dts_time", time_value_string(val_str, sizeof(val_str),
- pkt->dts, &st->time_base));
- probe_str("duration", ts_value_string(val_str, sizeof(val_str),
- pkt->duration));
- probe_str("duration_time", time_value_string(val_str, sizeof(val_str),
- pkt->duration,
- &st->time_base));
- probe_str("size", value_string(val_str, sizeof(val_str),
- pkt->size, unit_byte_str));
- probe_int("pos", pkt->pos);
- probe_str("flags", pkt->flags & AV_PKT_FLAG_KEY ? "K" : "_");
- probe_object_footer("packet");
-}
-
-static void show_packets(AVFormatContext *fmt_ctx)
-{
- AVPacket pkt;
-
- av_init_packet(&pkt);
- probe_array_header("packets", 0);
- while (!av_read_frame(fmt_ctx, &pkt))
- show_packet(fmt_ctx, &pkt);
- probe_array_footer("packets", 0);
-}
-
-static void show_stream(AVFormatContext *fmt_ctx, int stream_idx)
-{
- AVStream *stream = fmt_ctx->streams[stream_idx];
- AVCodecContext *dec_ctx;
- const AVCodec *dec;
- const char *profile;
- char val_str[128];
- AVRational display_aspect_ratio, *sar = NULL;
- const AVPixFmtDescriptor *desc;
-
- probe_object_header("stream");
-
- probe_int("index", stream->index);
-
- if ((dec_ctx = stream->codec)) {
- if ((dec = dec_ctx->codec)) {
- probe_str("codec_name", dec->name);
- probe_str("codec_long_name", dec->long_name);
- } else {
- probe_str("codec_name", "unknown");
- }
-
- probe_str("codec_type", media_type_string(dec_ctx->codec_type));
- probe_str("codec_time_base",
- rational_string(val_str, sizeof(val_str),
- "/", &dec_ctx->time_base));
-
- /* print AVI/FourCC tag */
- av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
- probe_str("codec_tag_string", val_str);
- probe_str("codec_tag", tag_string(val_str, sizeof(val_str),
- dec_ctx->codec_tag));
-
- /* print profile, if there is one */
- if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
- probe_str("profile", profile);
-
- switch (dec_ctx->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- probe_int("width", dec_ctx->width);
- probe_int("height", dec_ctx->height);
- probe_int("coded_width", dec_ctx->coded_width);
- probe_int("coded_height", dec_ctx->coded_height);
- probe_int("has_b_frames", dec_ctx->has_b_frames);
- if (dec_ctx->sample_aspect_ratio.num)
- sar = &dec_ctx->sample_aspect_ratio;
- else if (stream->sample_aspect_ratio.num)
- sar = &stream->sample_aspect_ratio;
-
- if (sar) {
- probe_str("sample_aspect_ratio",
- rational_string(val_str, sizeof(val_str), ":", sar));
- av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
- dec_ctx->width * sar->num, dec_ctx->height * sar->den,
- 1024*1024);
- probe_str("display_aspect_ratio",
- rational_string(val_str, sizeof(val_str), ":",
- &display_aspect_ratio));
- }
- desc = av_pix_fmt_desc_get(dec_ctx->pix_fmt);
- probe_str("pix_fmt", desc ? desc->name : "unknown");
- probe_int("level", dec_ctx->level);
-
- probe_str("color_range", av_color_range_name(dec_ctx->color_range));
- probe_str("color_space", av_color_space_name(dec_ctx->colorspace));
- probe_str("color_trc", av_color_transfer_name(dec_ctx->color_trc));
- probe_str("color_pri", av_color_primaries_name(dec_ctx->color_primaries));
- probe_str("chroma_loc", av_chroma_location_name(dec_ctx->chroma_sample_location));
- break;
-
- case AVMEDIA_TYPE_AUDIO:
- probe_str("sample_rate",
- value_string(val_str, sizeof(val_str),
- dec_ctx->sample_rate,
- unit_hertz_str));
- probe_int("channels", dec_ctx->channels);
- probe_int("bits_per_sample",
- av_get_bits_per_sample(dec_ctx->codec_id));
- break;
- }
- } else {
- probe_str("codec_type", "unknown");
- }
-
- if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS)
- probe_int("id", stream->id);
- probe_str("avg_frame_rate",
- rational_string(val_str, sizeof(val_str), "/",
- &stream->avg_frame_rate));
- if (dec_ctx->bit_rate)
- probe_str("bit_rate",
- value_string(val_str, sizeof(val_str),
- dec_ctx->bit_rate, unit_bit_per_second_str));
- probe_str("time_base",
- rational_string(val_str, sizeof(val_str), "/",
- &stream->time_base));
- probe_str("start_time",
- time_value_string(val_str, sizeof(val_str),
- stream->start_time, &stream->time_base));
- probe_str("duration",
- time_value_string(val_str, sizeof(val_str),
- stream->duration, &stream->time_base));
- if (stream->nb_frames)
- probe_int("nb_frames", stream->nb_frames);
-
- probe_dict(stream->metadata, "tags");
-
- if (stream->nb_side_data) {
- int i, j;
- probe_object_header("sidedata");
- for (i = 0; i < stream->nb_side_data; i++) {
- const AVPacketSideData* sd = &stream->side_data[i];
- switch (sd->type) {
- case AV_PKT_DATA_DISPLAYMATRIX:
- probe_object_header("displaymatrix");
- probe_array_header("matrix", 1);
- for (j = 0; j < 9; j++)
- probe_int(NULL, ((int32_t *)sd->data)[j]);
- probe_array_footer("matrix", 1);
- probe_int("rotation",
- av_display_rotation_get((int32_t *)sd->data));
- probe_object_footer("displaymatrix");
- break;
- }
- }
- probe_object_footer("sidedata");
- }
-
- probe_object_footer("stream");
-}
-
-static void show_format(AVFormatContext *fmt_ctx)
-{
- char val_str[128];
- int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
-
- probe_object_header("format");
- probe_str("filename", fmt_ctx->filename);
- probe_int("nb_streams", fmt_ctx->nb_streams);
- probe_str("format_name", fmt_ctx->iformat->name);
- probe_str("format_long_name", fmt_ctx->iformat->long_name);
- probe_str("start_time",
- time_value_string(val_str, sizeof(val_str),
- fmt_ctx->start_time, &AV_TIME_BASE_Q));
- probe_str("duration",
- time_value_string(val_str, sizeof(val_str),
- fmt_ctx->duration, &AV_TIME_BASE_Q));
- probe_str("size",
- size >= 0 ? value_string(val_str, sizeof(val_str),
- size, unit_byte_str)
- : "unknown");
- probe_str("bit_rate",
- value_string(val_str, sizeof(val_str),
- fmt_ctx->bit_rate, unit_bit_per_second_str));
-
- probe_dict(fmt_ctx->metadata, "tags");
-
- probe_object_footer("format");
-}
-
-static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
-{
- int err, i;
- AVFormatContext *fmt_ctx = NULL;
- AVDictionaryEntry *t;
-
- if ((err = avformat_open_input(&fmt_ctx, filename,
- iformat, &format_opts)) < 0) {
- print_error(filename, err);
- return err;
- }
- 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);
- return AVERROR_OPTION_NOT_FOUND;
- }
-
-
- /* fill the streams in the format context */
- if ((err = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
- print_error(filename, err);
- return err;
- }
-
- av_dump_format(fmt_ctx, 0, filename, 0);
-
- /* bind a decoder to each input stream */
- for (i = 0; i < fmt_ctx->nb_streams; i++) {
- AVStream *stream = fmt_ctx->streams[i];
- AVCodec *codec;
-
- if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
- fprintf(stderr, "Failed to probe codec for input stream %d\n",
- stream->index);
- } else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
- fprintf(stderr,
- "Unsupported codec with id %d for input stream %d\n",
- stream->codec->codec_id, stream->index);
- } else if (avcodec_open2(stream->codec, codec, NULL) < 0) {
- fprintf(stderr, "Error while opening codec for input stream %d\n",
- stream->index);
- }
- }
-
- *fmt_ctx_ptr = fmt_ctx;
- return 0;
-}
-
-static void close_input_file(AVFormatContext **ctx_ptr)
-{
- int i;
- AVFormatContext *fmt_ctx = *ctx_ptr;
-
- /* close decoder for each stream */
- for (i = 0; i < fmt_ctx->nb_streams; i++) {
- AVStream *stream = fmt_ctx->streams[i];
-
- avcodec_close(stream->codec);
- }
- avformat_close_input(ctx_ptr);
-}
-
-static int probe_file(const char *filename)
-{
- AVFormatContext *fmt_ctx;
- int ret, i;
-
- if ((ret = open_input_file(&fmt_ctx, filename)))
- return ret;
-
- if (do_show_format)
- show_format(fmt_ctx);
-
- if (do_show_streams) {
- probe_array_header("streams", 0);
- for (i = 0; i < fmt_ctx->nb_streams; i++)
- show_stream(fmt_ctx, i);
- probe_array_footer("streams", 0);
- }
-
- if (do_show_packets)
- show_packets(fmt_ctx);
-
- close_input_file(&fmt_ctx);
- return 0;
-}
-
-static void show_usage(void)
-{
- printf("Simple multimedia streams analyzer\n");
- printf("usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
- printf("\n");
-}
-
-static int opt_format(void *optctx, const char *opt, const char *arg)
-{
- iformat = av_find_input_format(arg);
- if (!iformat) {
- fprintf(stderr, "Unknown input format: %s\n", arg);
- return AVERROR(EINVAL);
- }
- return 0;
-}
-
-static int opt_output_format(void *optctx, const char *opt, const char *arg)
-{
-
- if (!strcmp(arg, "json")) {
- octx.print_header = json_print_header;
- octx.print_footer = json_print_footer;
- octx.print_array_header = json_print_array_header;
- octx.print_array_footer = json_print_array_footer;
- octx.print_object_header = json_print_object_header;
- octx.print_object_footer = json_print_object_footer;
-
- octx.print_integer = json_print_integer;
- octx.print_string = json_print_string;
- } else if (!strcmp(arg, "ini")) {
- octx.print_header = ini_print_header;
- octx.print_footer = ini_print_footer;
- octx.print_array_header = ini_print_array_header;
- octx.print_array_footer = ini_print_array_footer;
- octx.print_object_header = ini_print_object_header;
-
- octx.print_integer = ini_print_integer;
- octx.print_string = ini_print_string;
- } else if (!strcmp(arg, "old")) {
- octx.print_header = NULL;
- octx.print_object_header = old_print_object_header;
- octx.print_object_footer = old_print_object_footer;
-
- octx.print_string = old_print_string;
- } else {
- av_log(NULL, AV_LOG_ERROR, "Unsupported formatter %s\n", arg);
- return AVERROR(EINVAL);
- }
- return 0;
-}
-
-static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
-{
- do_show_format = 1;
- nb_fmt_entries_to_show++;
- octx.print_header = NULL;
- octx.print_footer = NULL;
- octx.print_array_header = NULL;
- octx.print_array_footer = NULL;
- octx.print_object_header = NULL;
- octx.print_object_footer = NULL;
-
- octx.print_integer = show_format_entry_integer;
- octx.print_string = show_format_entry_string;
- av_dict_set(&fmt_entries_to_show, arg, "", 0);
- return 0;
-}
-
-static void opt_input_file(void *optctx, const char *arg)
-{
- if (input_filename) {
- fprintf(stderr,
- "Argument '%s' provided as input filename, but '%s' was already specified.\n",
- arg, input_filename);
- exit_program(1);
- }
- if (!strcmp(arg, "-"))
- arg = "pipe:";
- input_filename = arg;
-}
-
-void show_help_default(const char *opt, const char *arg)
-{
- av_log_set_callback(log_callback_help);
- show_usage();
- show_help_options(options, "Main options:", 0, 0, 0);
- printf("\n");
- show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
-}
-
-static int opt_pretty(void *optctx, const char *opt, const char *arg)
-{
- show_value_unit = 1;
- use_value_prefix = 1;
- use_byte_value_binary_prefix = 1;
- use_value_sexagesimal_format = 1;
- return 0;
-}
-
-static const OptionDef real_options[] = {
-#include "cmdutils_common_opts.h"
- { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
- { "of", HAS_ARG, {.func_arg = opt_output_format}, "output the document either as ini or json", "output_format" },
- { "unit", OPT_BOOL, {&show_value_unit},
- "show unit of the displayed values" },
- { "prefix", OPT_BOOL, {&use_value_prefix},
- "use SI prefixes for the displayed values" },
- { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
- "use binary prefixes for byte units" },
- { "sexagesimal", OPT_BOOL, {&use_value_sexagesimal_format},
- "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
- { "pretty", 0, {.func_arg = opt_pretty},
- "prettify the format of displayed values, make it more human readable" },
- { "show_format", OPT_BOOL, {&do_show_format} , "show format/container info" },
- { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
- "show a particular entry from the format/container info", "entry" },
- { "show_packets", OPT_BOOL, {&do_show_packets}, "show packets info" },
- { "show_streams", OPT_BOOL, {&do_show_streams}, "show streams info" },
- { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default},
- "generic catch all option", "" },
- { NULL, },
-};
-
-static int probe_buf_write(void *opaque, uint8_t *buf, int buf_size)
-{
- printf("%.*s", buf_size, buf);
- return 0;
-}
-
-#define AVP_BUFFSIZE 4096
-
-int main(int argc, char **argv)
-{
- int ret;
- uint8_t *buffer = av_malloc(AVP_BUFFSIZE);
-
- if (!buffer)
- exit(1);
-
- register_exit(avprobe_cleanup);
-
- options = real_options;
- parse_loglevel(argc, argv, options);
- av_register_all();
- avformat_network_init();
- init_opts();
-#if CONFIG_AVDEVICE
- avdevice_register_all();
-#endif
-
- show_banner();
-
- octx.print_header = ini_print_header;
- octx.print_footer = ini_print_footer;
-
- octx.print_array_header = ini_print_array_header;
- octx.print_array_footer = ini_print_array_footer;
- octx.print_object_header = ini_print_object_header;
-
- octx.print_integer = ini_print_integer;
- octx.print_string = ini_print_string;
-
- parse_options(NULL, argc, argv, options, opt_input_file);
-
- if (!input_filename) {
- show_usage();
- fprintf(stderr, "You have to specify one input file.\n");
- fprintf(stderr,
- "Use -h to get full help or, even better, run 'man %s'.\n",
- program_name);
- exit_program(1);
- }
-
- probe_out = avio_alloc_context(buffer, AVP_BUFFSIZE, 1, NULL, NULL,
- probe_buf_write, NULL);
- if (!probe_out)
- exit_program(1);
-
- probe_header();
- ret = probe_file(input_filename);
- probe_footer();
- avio_flush(probe_out);
- avio_close(probe_out);
-
- avformat_network_deinit();
-
- return ret;
-}
diff --git a/cmdutils.c b/cmdutils.c
index c4a78199f3..6e7a0bb09b 100644
--- a/cmdutils.c
+++ b/cmdutils.c
@@ -2,20 +2,20 @@
* Various utilities for command line tools
* Copyright (c) 2000-2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,23 +30,29 @@
references to libraries that are not being built. */
#include "config.h"
+#include "compat/va_copy.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavdevice/avdevice.h"
#include "libavresample/avresample.h"
#include "libswscale/swscale.h"
+#include "libswresample/swresample.h"
+#include "libpostproc/postprocess.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/display.h"
#include "libavutil/mathematics.h"
#include "libavutil/imgutils.h"
+#include "libavutil/libm.h"
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/eval.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/cpu.h"
+#include "libavutil/ffversion.h"
#include "cmdutils.h"
-#include "version.h"
#if CONFIG_NETWORK
#include "libavformat/network.h"
#endif
@@ -55,17 +61,22 @@
#include <sys/resource.h>
#endif
+static int init_report(const char *env);
+
struct SwsContext *sws_opts;
+AVDictionary *swr_opts;
AVDictionary *format_opts, *codec_opts, *resample_opts;
-static const int this_year = 2015;
+static FILE *report_file;
+static int report_file_level = AV_LOG_DEBUG;
+int hide_banner = 0;
void init_opts(void)
{
-#if CONFIG_SWSCALE
- sws_opts = sws_getContext(16, 16, 0, 16, 16, 0, SWS_BICUBIC,
+
+ if(CONFIG_SWSCALE)
+ sws_opts = sws_getContext(16, 16, 0, 16, 16, 0, SWS_BICUBIC,
NULL, NULL, NULL);
-#endif
}
void uninit_opts(void)
@@ -74,6 +85,8 @@ void uninit_opts(void)
sws_freeContext(sws_opts);
sws_opts = NULL;
#endif
+
+ av_dict_free(&swr_opts);
av_dict_free(&format_opts);
av_dict_free(&codec_opts);
av_dict_free(&resample_opts);
@@ -84,6 +97,22 @@ void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
vfprintf(stdout, fmt, vl);
}
+static void log_callback_report(void *ptr, int level, const char *fmt, va_list vl)
+{
+ va_list vl2;
+ char line[1024];
+ static int print_prefix = 1;
+
+ va_copy(vl2, vl);
+ av_log_default_callback(ptr, level, fmt, vl);
+ av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix);
+ va_end(vl2);
+ if (report_file_level >= level) {
+ fputs(line, report_file);
+ fflush(report_file);
+ }
+}
+
static void (*program_exit)(int ret);
void register_exit(void (*cb)(int ret))
@@ -139,7 +168,7 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
int first;
first = 1;
- for (po = options; po->name != NULL; po++) {
+ for (po = options; po->name; po++) {
char buf[64];
if (((po->flags & req_flags) != req_flags) ||
@@ -164,8 +193,10 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
void show_help_children(const AVClass *class, int flags)
{
const AVClass *child = NULL;
- av_opt_show2(&class, NULL, flags, 0);
- printf("\n");
+ if (class->option) {
+ av_opt_show2(&class, NULL, flags, 0);
+ printf("\n");
+ }
while (child = av_opt_child_class_next(class, child))
show_help_children(child, flags);
@@ -293,7 +324,8 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
int ret = po->u.func_arg(optctx, opt, arg);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR,
- "Failed to set value '%s' for option '%s'\n", arg, opt);
+ "Failed to set value '%s' for option '%s': %s\n",
+ arg, opt, av_err2str(ret));
return ret;
}
}
@@ -426,59 +458,153 @@ int locate_option(int argc, char **argv, const OptionDef *options,
return 0;
}
+static void dump_argument(const char *a)
+{
+ const unsigned char *p;
+
+ for (p = a; *p; p++)
+ if (!((*p >= '+' && *p <= ':') || (*p >= '@' && *p <= 'Z') ||
+ *p == '_' || (*p >= 'a' && *p <= 'z')))
+ break;
+ if (!*p) {
+ fputs(a, report_file);
+ return;
+ }
+ fputc('"', report_file);
+ for (p = a; *p; p++) {
+ if (*p == '\\' || *p == '"' || *p == '$' || *p == '`')
+ fprintf(report_file, "\\%c", *p);
+ else if (*p < ' ' || *p > '~')
+ fprintf(report_file, "\\x%02x", *p);
+ else
+ fputc(*p, report_file);
+ }
+ fputc('"', report_file);
+}
+
+static void check_options(const OptionDef *po)
+{
+ while (po->name) {
+ if (po->flags & OPT_PERFILE)
+ av_assert0(po->flags & (OPT_INPUT | OPT_OUTPUT));
+ po++;
+ }
+}
+
void parse_loglevel(int argc, char **argv, const OptionDef *options)
{
int idx = locate_option(argc, argv, options, "loglevel");
+ const char *env;
+
+ check_options(options);
+
if (!idx)
idx = locate_option(argc, argv, options, "v");
if (idx && argv[idx + 1])
opt_loglevel(NULL, "loglevel", argv[idx + 1]);
+ idx = locate_option(argc, argv, options, "report");
+ if ((env = getenv("FFREPORT")) || idx) {
+ init_report(env);
+ if (report_file) {
+ int i;
+ fprintf(report_file, "Command line:\n");
+ for (i = 0; i < argc; i++) {
+ dump_argument(argv[i]);
+ fputc(i < argc - 1 ? ' ' : '\n', report_file);
+ }
+ fflush(report_file);
+ }
+ }
+ idx = locate_option(argc, argv, options, "hide_banner");
+ if (idx)
+ hide_banner = 1;
+}
+
+static const AVOption *opt_find(void *obj, const char *name, const char *unit,
+ int opt_flags, int search_flags)
+{
+ const AVOption *o = av_opt_find(obj, name, unit, opt_flags, search_flags);
+ if(o && !o->flags)
+ return NULL;
+ return o;
}
#define FLAGS (o->type == AV_OPT_TYPE_FLAGS) ? AV_DICT_APPEND : 0
int opt_default(void *optctx, const char *opt, const char *arg)
{
const AVOption *o;
+ int consumed = 0;
char opt_stripped[128];
const char *p;
const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class();
#if CONFIG_AVRESAMPLE
const AVClass *rc = avresample_get_class();
#endif
-#if CONFIG_SWSCALE
- const AVClass *sc = sws_get_class();
-#endif
+ const AVClass *sc, *swr_class;
+
+ if (!strcmp(opt, "debug") || !strcmp(opt, "fdebug"))
+ av_log_set_level(AV_LOG_DEBUG);
if (!(p = strchr(opt, ':')))
p = opt + strlen(opt);
av_strlcpy(opt_stripped, opt, FFMIN(sizeof(opt_stripped), p - opt + 1));
- if ((o = av_opt_find(&cc, opt_stripped, NULL, 0,
+ if ((o = opt_find(&cc, opt_stripped, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) ||
((opt[0] == 'v' || opt[0] == 'a' || opt[0] == 's') &&
- (o = av_opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ))))
+ (o = opt_find(&cc, opt + 1, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)))) {
av_dict_set(&codec_opts, opt, arg, FLAGS);
- else if ((o = av_opt_find(&fc, opt, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)))
+ consumed = 1;
+ }
+ if ((o = opt_find(&fc, opt, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
av_dict_set(&format_opts, opt, arg, FLAGS);
-#if CONFIG_AVRESAMPLE
- else if ((o = av_opt_find(&rc, opt, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)))
- av_dict_set(&resample_opts, opt, arg, FLAGS);
-#endif
+ if (consumed)
+ av_log(NULL, AV_LOG_VERBOSE, "Routing option %s to both codec and muxer layer\n", opt);
+ consumed = 1;
+ }
#if CONFIG_SWSCALE
- else if ((o = av_opt_find(&sc, opt, NULL, 0,
- AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
+ sc = sws_get_class();
+ if (!consumed && opt_find(&sc, opt, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) {
// XXX we only support sws_flags, not arbitrary sws options
int ret = av_opt_set(sws_opts, opt, arg, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt);
return ret;
}
+ consumed = 1;
+ }
+#else
+ if (!consumed && !strcmp(opt, "sws_flags")) {
+ av_log(NULL, AV_LOG_WARNING, "Ignoring %s %s, due to disabled swscale\n", opt, arg);
+ consumed = 1;
+ }
+#endif
+#if CONFIG_SWRESAMPLE
+ swr_class = swr_get_class();
+ if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
+ struct SwrContext *swr = swr_alloc();
+ int ret = av_opt_set(swr, opt, arg, 0);
+ swr_free(&swr);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error setting option %s.\n", opt);
+ return ret;
+ }
+ av_dict_set(&swr_opts, opt, arg, FLAGS);
+ consumed = 1;
+ }
+#endif
+#if CONFIG_AVRESAMPLE
+ if ((o=opt_find(&rc, opt, NULL, 0,
+ AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
+ av_dict_set(&resample_opts, opt, arg, FLAGS);
+ consumed = 1;
}
#endif
- if (o)
+ if (consumed)
return 0;
return AVERROR_OPTION_NOT_FOUND;
}
@@ -523,6 +649,7 @@ static void finish_group(OptionParseContext *octx, int group_idx,
#if CONFIG_SWSCALE
g->sws_opts = sws_opts;
#endif
+ g->swr_opts = swr_opts;
g->codec_opts = codec_opts;
g->format_opts = format_opts;
g->resample_opts = resample_opts;
@@ -533,6 +660,7 @@ static void finish_group(OptionParseContext *octx, int group_idx,
#if CONFIG_SWSCALE
sws_opts = NULL;
#endif
+ swr_opts = NULL;
init_opts();
memset(&octx->cur_group, 0, sizeof(octx->cur_group));
@@ -562,7 +690,7 @@ static void init_parse_context(OptionParseContext *octx,
memset(octx, 0, sizeof(*octx));
octx->nb_groups = nb_groups;
- octx->groups = av_mallocz(sizeof(*octx->groups) * octx->nb_groups);
+ octx->groups = av_mallocz_array(octx->nb_groups, sizeof(*octx->groups));
if (!octx->groups)
exit_program(1);
@@ -590,6 +718,7 @@ void uninit_parse_context(OptionParseContext *octx)
#if CONFIG_SWSCALE
sws_freeContext(l->groups[j].sws_opts);
#endif
+ av_dict_free(&l->groups[j].swr_opts);
}
av_freep(&l->groups);
}
@@ -606,6 +735,7 @@ int split_commandline(OptionParseContext *octx, int argc, char *argv[],
const OptionGroupDef *groups, int nb_groups)
{
int optindex = 1;
+ int dashdash = -2;
/* perform system-dependent conversions for arguments list */
prepare_app_arguments(&argc, &argv);
@@ -620,8 +750,12 @@ int split_commandline(OptionParseContext *octx, int argc, char *argv[],
av_log(NULL, AV_LOG_DEBUG, "Reading option '%s' ...", opt);
+ if (opt[0] == '-' && opt[1] == '-' && !opt[2]) {
+ dashdash = optindex;
+ continue;
+ }
/* unnamed group separators, e.g. output filename */
- if (opt[0] != '-' || !opt[1]) {
+ if (opt[0] != '-' || !opt[1] || dashdash+1 == optindex) {
finish_group(octx, 0, opt);
av_log(NULL, AV_LOG_DEBUG, " matched as %s.\n", groups[0].name);
continue;
@@ -704,12 +838,13 @@ do { \
int opt_cpuflags(void *optctx, const char *opt, const char *arg)
{
- int flags = av_parse_cpu_flags(arg);
+ int ret;
+ unsigned flags = av_get_cpu_flags();
- if (flags < 0)
- return flags;
+ if ((ret = av_parse_cpu_caps(&flags, arg)) < 0)
+ return ret;
- av_set_cpu_flags_mask(flags);
+ av_force_cpu_flags(flags);
return 0;
}
@@ -728,8 +863,22 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
};
char *tail;
int level;
+ int flags;
int i;
+ flags = av_log_get_flags();
+ tail = strstr(arg, "repeat");
+ if (tail)
+ flags &= ~AV_LOG_SKIP_REPEATED;
+ else
+ flags |= AV_LOG_SKIP_REPEATED;
+
+ av_log_set_flags(flags);
+ if (tail == arg)
+ arg += 6 + (arg[6]=='+');
+ if(tail && !*arg)
+ return 0;
+
for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) {
if (!strcmp(log_levels[i].name, arg)) {
av_log_set_level(log_levels[i].level);
@@ -749,6 +898,124 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg)
return 0;
}
+static void expand_filename_template(AVBPrint *bp, const char *template,
+ struct tm *tm)
+{
+ int c;
+
+ while ((c = *(template++))) {
+ if (c == '%') {
+ if (!(c = *(template++)))
+ break;
+ switch (c) {
+ case 'p':
+ av_bprintf(bp, "%s", program_name);
+ break;
+ case 't':
+ av_bprintf(bp, "%04d%02d%02d-%02d%02d%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ break;
+ case '%':
+ av_bprint_chars(bp, c, 1);
+ break;
+ }
+ } else {
+ av_bprint_chars(bp, c, 1);
+ }
+ }
+}
+
+static int init_report(const char *env)
+{
+ char *filename_template = NULL;
+ char *key, *val;
+ int ret, count = 0;
+ time_t now;
+ struct tm *tm;
+ AVBPrint filename;
+
+ if (report_file) /* already opened */
+ return 0;
+ time(&now);
+ tm = localtime(&now);
+
+ while (env && *env) {
+ if ((ret = av_opt_get_key_value(&env, "=", ":", 0, &key, &val)) < 0) {
+ if (count)
+ av_log(NULL, AV_LOG_ERROR,
+ "Failed to parse FFREPORT environment variable: %s\n",
+ av_err2str(ret));
+ break;
+ }
+ if (*env)
+ env++;
+ count++;
+ if (!strcmp(key, "file")) {
+ av_free(filename_template);
+ filename_template = val;
+ val = NULL;
+ } else if (!strcmp(key, "level")) {
+ char *tail;
+ report_file_level = strtol(val, &tail, 10);
+ if (*tail) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid report file level\n");
+ exit_program(1);
+ }
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unknown key '%s' in FFREPORT\n", key);
+ }
+ av_free(val);
+ av_free(key);
+ }
+
+ av_bprint_init(&filename, 0, 1);
+ expand_filename_template(&filename,
+ av_x_if_null(filename_template, "%p-%t.log"), tm);
+ av_free(filename_template);
+ if (!av_bprint_is_complete(&filename)) {
+ av_log(NULL, AV_LOG_ERROR, "Out of memory building report file name\n");
+ return AVERROR(ENOMEM);
+ }
+
+ report_file = fopen(filename.str, "w");
+ if (!report_file) {
+ int ret = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR, "Failed to open report \"%s\": %s\n",
+ filename.str, strerror(errno));
+ return ret;
+ }
+ av_log_set_callback(log_callback_report);
+ av_log(NULL, AV_LOG_INFO,
+ "%s started on %04d-%02d-%02d at %02d:%02d:%02d\n"
+ "Report written to \"%s\"\n",
+ program_name,
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ filename.str);
+ av_bprint_finalize(&filename, NULL);
+ return 0;
+}
+
+int opt_report(const char *opt)
+{
+ return init_report(NULL);
+}
+
+int opt_max_alloc(void *optctx, const char *opt, const char *arg)
+{
+ char *tail;
+ size_t max;
+
+ max = strtol(arg, &tail, 10);
+ if (*tail) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid max_alloc \"%s\".\n", arg);
+ exit_program(1);
+ }
+ av_max_alloc(max);
+ return 0;
+}
+
int opt_timelimit(void *optctx, const char *opt, const char *arg)
{
#if HAVE_SETRLIMIT
@@ -777,6 +1044,7 @@ static int warned_cfg = 0;
#define INDENT 1
#define SHOW_VERSION 2
#define SHOW_CONFIG 4
+#define SHOW_COPYRIGHT 8
#define PRINT_LIB_INFO(libname, LIBNAME, flags, level) \
if (CONFIG_##LIBNAME) { \
@@ -784,7 +1052,7 @@ static int warned_cfg = 0;
if (flags & SHOW_VERSION) { \
unsigned int version = libname##_version(); \
av_log(NULL, level, \
- "%slib%-10s %2d.%3d.%2d / %2d.%3d.%2d\n", \
+ "%slib%-11s %2d.%3d.%3d / %2d.%3d.%3d\n", \
indent, #libname, \
LIB##LIBNAME##_VERSION_MAJOR, \
LIB##LIBNAME##_VERSION_MINOR, \
@@ -793,7 +1061,7 @@ static int warned_cfg = 0;
} \
if (flags & SHOW_CONFIG) { \
const char *cfg = libname##_configuration(); \
- if (strcmp(LIBAV_CONFIGURATION, cfg)) { \
+ if (strcmp(FFMPEG_CONFIGURATION, cfg)) { \
if (!warned_cfg) { \
av_log(NULL, level, \
"%sWARNING: library configuration mismatch\n", \
@@ -815,37 +1083,87 @@ static void print_all_libs_info(int flags, int level)
PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level);
PRINT_LIB_INFO(swscale, SWSCALE, flags, level);
+ PRINT_LIB_INFO(swresample,SWRESAMPLE, flags, level);
+ PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
}
-void show_banner(void)
+static void print_program_info(int flags, int level)
{
- av_log(NULL, AV_LOG_INFO,
- "%s version " LIBAV_VERSION ", Copyright (c) %d-%d the Libav developers\n",
- program_name, program_birth_year, this_year);
- av_log(NULL, AV_LOG_INFO, " built on %s %s with %s\n",
- __DATE__, __TIME__, CC_IDENT);
- av_log(NULL, AV_LOG_VERBOSE, " configuration: " LIBAV_CONFIGURATION "\n");
- print_all_libs_info(INDENT|SHOW_CONFIG, AV_LOG_VERBOSE);
- print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_VERBOSE);
+ const char *indent = flags & INDENT? " " : "";
+
+ av_log(NULL, level, "%s version " FFMPEG_VERSION, program_name);
+ if (flags & SHOW_COPYRIGHT)
+ av_log(NULL, level, " Copyright (c) %d-%d the FFmpeg developers",
+ program_birth_year, CONFIG_THIS_YEAR);
+ av_log(NULL, level, "\n");
+ av_log(NULL, level, "%sbuilt with %s\n", indent, CC_IDENT);
+
+ av_log(NULL, level, "%sconfiguration: " FFMPEG_CONFIGURATION "\n", indent);
+}
+
+static void print_buildconf(int flags, int level)
+{
+ const char *indent = flags & INDENT ? " " : "";
+ char str[] = { FFMPEG_CONFIGURATION };
+ char *conflist, *remove_tilde, *splitconf;
+
+ // Change all the ' --' strings to '~--' so that
+ // they can be identified as tokens.
+ while ((conflist = strstr(str, " --")) != NULL) {
+ strncpy(conflist, "~--", 3);
+ }
+
+ // Compensate for the weirdness this would cause
+ // when passing 'pkg-config --static'.
+ while ((remove_tilde = strstr(str, "pkg-config~")) != NULL) {
+ strncpy(remove_tilde, "pkg-config ", 11);
+ }
+
+ splitconf = strtok(str, "~");
+ av_log(NULL, level, "\n%sconfiguration:\n", indent);
+ while (splitconf != NULL) {
+ av_log(NULL, level, "%s%s%s\n", indent, indent, splitconf);
+ splitconf = strtok(NULL, "~");
+ }
+}
+
+void show_banner(int argc, char **argv, const OptionDef *options)
+{
+ int idx = locate_option(argc, argv, options, "version");
+ if (hide_banner || idx)
+ return;
+
+ print_program_info (INDENT|SHOW_COPYRIGHT, AV_LOG_INFO);
+ print_all_libs_info(INDENT|SHOW_CONFIG, AV_LOG_INFO);
+ print_all_libs_info(INDENT|SHOW_VERSION, AV_LOG_INFO);
}
int show_version(void *optctx, const char *opt, const char *arg)
{
av_log_set_callback(log_callback_help);
- printf("%s " LIBAV_VERSION "\n", program_name);
+ print_program_info (SHOW_COPYRIGHT, AV_LOG_INFO);
print_all_libs_info(SHOW_VERSION, AV_LOG_INFO);
return 0;
}
+int show_buildconf(void *optctx, const char *opt, const char *arg)
+{
+ av_log_set_callback(log_callback_help);
+ print_buildconf (INDENT|0, AV_LOG_INFO);
+
+ return 0;
+}
+
int show_license(void *optctx, const char *opt, const char *arg)
{
- printf(
#if CONFIG_NONFREE
+ printf(
"This version of %s has nonfree parts compiled in.\n"
"Therefore it is not legally redistributable.\n",
- program_name
+ program_name );
#elif CONFIG_GPLV3
+ printf(
"%s is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 3 of the License, or\n"
@@ -858,8 +1176,9 @@ int show_license(void *optctx, const char *opt, const char *arg)
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with %s. If not, see <http://www.gnu.org/licenses/>.\n",
- program_name, program_name, program_name
+ program_name, program_name, program_name );
#elif CONFIG_GPL
+ printf(
"%s is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
@@ -873,8 +1192,9 @@ int show_license(void *optctx, const char *opt, const char *arg)
"You should have received a copy of the GNU General Public License\n"
"along with %s; if not, write to the Free Software\n"
"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
- program_name, program_name, program_name
+ program_name, program_name, program_name );
#elif CONFIG_LGPLV3
+ printf(
"%s is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU Lesser General Public License as published by\n"
"the Free Software Foundation; either version 3 of the License, or\n"
@@ -887,8 +1207,9 @@ int show_license(void *optctx, const char *opt, const char *arg)
"\n"
"You should have received a copy of the GNU Lesser General Public License\n"
"along with %s. If not, see <http://www.gnu.org/licenses/>.\n",
- program_name, program_name, program_name
+ program_name, program_name, program_name );
#else
+ printf(
"%s is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU Lesser General Public\n"
"License as published by the Free Software Foundation; either\n"
@@ -902,23 +1223,30 @@ int show_license(void *optctx, const char *opt, const char *arg)
"You should have received a copy of the GNU Lesser General Public\n"
"License along with %s; if not, write to the Free Software\n"
"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n",
- program_name, program_name, program_name
+ program_name, program_name, program_name );
#endif
- );
return 0;
}
-int show_formats(void *optctx, const char *opt, const char *arg)
+static int is_device(const AVClass *avclass)
+{
+ if (!avclass)
+ return 0;
+ return AV_IS_INPUT_DEVICE(avclass->category) || AV_IS_OUTPUT_DEVICE(avclass->category);
+}
+
+static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only)
{
AVInputFormat *ifmt = NULL;
AVOutputFormat *ofmt = NULL;
const char *last_name;
+ int is_dev;
- printf("File formats:\n"
+ printf("%s\n"
" D. = Demuxing supported\n"
" .E = Muxing supported\n"
- " --\n");
+ " --\n", device_only ? "Devices:" : "File formats:");
last_name = "000";
for (;;) {
int decode = 0;
@@ -927,6 +1255,9 @@ int show_formats(void *optctx, const char *opt, const char *arg)
const char *long_name = NULL;
while ((ofmt = av_oformat_next(ofmt))) {
+ is_dev = is_device(ofmt->priv_class);
+ if (!is_dev && device_only)
+ continue;
if ((!name || strcmp(ofmt->name, name) < 0) &&
strcmp(ofmt->name, last_name) > 0) {
name = ofmt->name;
@@ -935,6 +1266,9 @@ int show_formats(void *optctx, const char *opt, const char *arg)
}
}
while ((ifmt = av_iformat_next(ifmt))) {
+ is_dev = is_device(ifmt->priv_class);
+ if (!is_dev && device_only)
+ continue;
if ((!name || strcmp(ifmt->name, name) < 0) &&
strcmp(ifmt->name, last_name) > 0) {
name = ifmt->name;
@@ -957,9 +1291,19 @@ int show_formats(void *optctx, const char *opt, const char *arg)
return 0;
}
+int show_formats(void *optctx, const char *opt, const char *arg)
+{
+ return show_formats_devices(optctx, opt, arg, 0);
+}
+
+int show_devices(void *optctx, const char *opt, const char *arg)
+{
+ return show_formats_devices(optctx, opt, arg, 1);
+}
+
#define PRINT_CODEC_SUPPORTED(codec, field, type, list_name, term, get_name) \
if (codec->field) { \
- const type *p = c->field; \
+ const type *p = codec->field; \
\
printf(" Supported " list_name ":"); \
while (*p != term) { \
@@ -977,7 +1321,8 @@ static void print_codec(const AVCodec *c)
printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name,
c->long_name ? c->long_name : "");
- if (c->type == AVMEDIA_TYPE_VIDEO) {
+ if (c->type == AVMEDIA_TYPE_VIDEO ||
+ c->type == AVMEDIA_TYPE_AUDIO) {
printf(" Threading capabilities: ");
switch (c->capabilities & (CODEC_CAP_FRAME_THREADS |
CODEC_CAP_SLICE_THREADS)) {
@@ -1021,7 +1366,9 @@ static char get_media_type_char(enum AVMediaType type)
switch (type) {
case AVMEDIA_TYPE_VIDEO: return 'V';
case AVMEDIA_TYPE_AUDIO: return 'A';
+ case AVMEDIA_TYPE_DATA: return 'D';
case AVMEDIA_TYPE_SUBTITLE: return 'S';
+ case AVMEDIA_TYPE_ATTACHMENT:return 'T';
default: return '?';
}
}
@@ -1037,6 +1384,36 @@ static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev,
return NULL;
}
+static int compare_codec_desc(const void *a, const void *b)
+{
+ const AVCodecDescriptor * const *da = a;
+ const AVCodecDescriptor * const *db = b;
+
+ return (*da)->type != (*db)->type ? (*da)->type - (*db)->type :
+ strcmp((*da)->name, (*db)->name);
+}
+
+static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
+{
+ const AVCodecDescriptor *desc = NULL;
+ const AVCodecDescriptor **codecs;
+ unsigned nb_codecs = 0, i = 0;
+
+ while ((desc = avcodec_descriptor_next(desc)))
+ nb_codecs++;
+ if (!(codecs = av_calloc(nb_codecs, sizeof(*codecs)))) {
+ av_log(NULL, AV_LOG_ERROR, "Out of memory\n");
+ exit_program(1);
+ }
+ desc = NULL;
+ while ((desc = avcodec_descriptor_next(desc)))
+ codecs[i++] = desc;
+ av_assert0(i == nb_codecs);
+ qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
+ *rcodecs = codecs;
+ return nb_codecs;
+}
+
static void print_codecs_for_id(enum AVCodecID id, int encoder)
{
const AVCodec *codec = NULL;
@@ -1051,7 +1428,8 @@ static void print_codecs_for_id(enum AVCodecID id, int encoder)
int show_codecs(void *optctx, const char *opt, const char *arg)
{
- const AVCodecDescriptor *desc = NULL;
+ const AVCodecDescriptor **codecs;
+ unsigned i, nb_codecs = get_codecs_sorted(&codecs);
printf("Codecs:\n"
" D..... = Decoding supported\n"
@@ -1063,9 +1441,14 @@ int show_codecs(void *optctx, const char *opt, const char *arg)
" ....L. = Lossy compression\n"
" .....S = Lossless compression\n"
" -------\n");
- while ((desc = avcodec_descriptor_next(desc))) {
+ for (i = 0; i < nb_codecs; i++) {
+ const AVCodecDescriptor *desc = codecs[i];
const AVCodec *codec = NULL;
+ if (strstr(desc->name, "_deprecated"))
+ continue;
+
+ printf(" ");
printf(avcodec_find_decoder(desc->id) ? "D" : ".");
printf(avcodec_find_encoder(desc->id) ? "E" : ".");
@@ -1094,30 +1477,37 @@ int show_codecs(void *optctx, const char *opt, const char *arg)
printf("\n");
}
+ av_free(codecs);
return 0;
}
static void print_codecs(int encoder)
{
- const AVCodecDescriptor *desc = NULL;
+ const AVCodecDescriptor **codecs;
+ unsigned i, nb_codecs = get_codecs_sorted(&codecs);
printf("%s:\n"
- " V... = Video\n"
- " A... = Audio\n"
- " S... = Subtitle\n"
- " .F.. = Frame-level multithreading\n"
- " ..S. = Slice-level multithreading\n"
- " ...X = Codec is experimental\n"
- " ---\n",
+ " V..... = Video\n"
+ " A..... = Audio\n"
+ " S..... = Subtitle\n"
+ " .F.... = Frame-level multithreading\n"
+ " ..S... = Slice-level multithreading\n"
+ " ...X.. = Codec is experimental\n"
+ " ....B. = Supports draw_horiz_band\n"
+ " .....D = Supports direct rendering method 1\n"
+ " ------\n",
encoder ? "Encoders" : "Decoders");
- while ((desc = avcodec_descriptor_next(desc))) {
+ for (i = 0; i < nb_codecs; i++) {
+ const AVCodecDescriptor *desc = codecs[i];
const AVCodec *codec = NULL;
while ((codec = next_codec_for_id(desc->id, codec, encoder))) {
- printf("%c", get_media_type_char(desc->type));
+ printf(" %c", get_media_type_char(desc->type));
printf((codec->capabilities & CODEC_CAP_FRAME_THREADS) ? "F" : ".");
printf((codec->capabilities & CODEC_CAP_SLICE_THREADS) ? "S" : ".");
printf((codec->capabilities & CODEC_CAP_EXPERIMENTAL) ? "X" : ".");
+ printf((codec->capabilities & CODEC_CAP_DRAW_HORIZ_BAND)?"B" : ".");
+ printf((codec->capabilities & CODEC_CAP_DR1) ? "D" : ".");
printf(" %-20s %s", codec->name, codec->long_name ? codec->long_name : "");
if (strcmp(codec->name, desc->name))
@@ -1126,6 +1516,7 @@ static void print_codecs(int encoder)
printf("\n");
}
}
+ av_free(codecs);
}
int show_decoders(void *optctx, const char *opt, const char *arg)
@@ -1159,10 +1550,10 @@ int show_protocols(void *optctx, const char *opt, const char *arg)
printf("Supported file protocols:\n"
"Input:\n");
while ((name = avio_enum_protocols(&opaque, 0)))
- printf("%s\n", name);
+ printf(" %s\n", name);
printf("Output:\n");
while ((name = avio_enum_protocols(&opaque, 1)))
- printf("%s\n", name);
+ printf(" %s\n", name);
return 0;
}
@@ -1170,16 +1561,62 @@ int show_filters(void *optctx, const char *opt, const char *arg)
{
#if CONFIG_AVFILTER
const AVFilter *filter = NULL;
-
- printf("Filters:\n");
- while ((filter = avfilter_next(filter)))
- printf("%-16s %s\n", filter->name, filter->description);
+ char descr[64], *descr_cur;
+ int i, j;
+ const AVFilterPad *pad;
+
+ printf("Filters:\n"
+ " T.. = Timeline support\n"
+ " .S. = Slice threading\n"
+ " ..C = Command support\n"
+ " A = Audio input/output\n"
+ " V = Video input/output\n"
+ " N = Dynamic number and/or type of input/output\n"
+ " | = Source or sink filter\n");
+ while ((filter = avfilter_next(filter))) {
+ descr_cur = descr;
+ for (i = 0; i < 2; i++) {
+ if (i) {
+ *(descr_cur++) = '-';
+ *(descr_cur++) = '>';
+ }
+ pad = i ? filter->outputs : filter->inputs;
+ for (j = 0; pad && pad[j].name; j++) {
+ if (descr_cur >= descr + sizeof(descr) - 4)
+ break;
+ *(descr_cur++) = get_media_type_char(pad[j].type);
+ }
+ if (!j)
+ *(descr_cur++) = ((!i && (filter->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) ||
+ ( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|';
+ }
+ *descr_cur = 0;
+ printf(" %c%c%c %-16s %-10s %s\n",
+ filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.',
+ filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.',
+ filter->process_command ? 'C' : '.',
+ filter->name, descr, filter->description);
+ }
#else
printf("No filters available: libavfilter disabled\n");
#endif
return 0;
}
+int show_colors(void *optctx, const char *opt, const char *arg)
+{
+ const char *name;
+ const uint8_t *rgb;
+ int i;
+
+ printf("%-32s #RRGGBB\n", "name");
+
+ for (i = 0; name = av_get_known_color_name(i, &rgb); i++)
+ printf("%-32s #%02x%02x%02x\n", name, rgb[0], rgb[1], rgb[2]);
+
+ return 0;
+}
+
int show_pix_fmts(void *optctx, const char *opt, const char *arg)
{
const AVPixFmtDescriptor *pix_desc = NULL;
@@ -1213,6 +1650,35 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg)
return 0;
}
+int show_layouts(void *optctx, const char *opt, const char *arg)
+{
+ int i = 0;
+ uint64_t layout, j;
+ const char *name, *descr;
+
+ printf("Individual channels:\n"
+ "NAME DESCRIPTION\n");
+ for (i = 0; i < 63; i++) {
+ name = av_get_channel_name((uint64_t)1 << i);
+ if (!name)
+ continue;
+ descr = av_get_channel_description((uint64_t)1 << i);
+ printf("%-14s %s\n", name, descr);
+ }
+ printf("\nStandard channel layouts:\n"
+ "NAME DECOMPOSITION\n");
+ for (i = 0; !av_get_standard_channel_layout(i, &layout, &name); i++) {
+ if (name) {
+ printf("%-14s ", name);
+ for (j = 1; j; j <<= 1)
+ if ((layout & j))
+ printf("%s%s", (layout & (j - 1)) ? "+" : "", av_get_channel_name(j));
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
int show_sample_fmts(void *optctx, const char *opt, const char *arg)
{
int i;
@@ -1246,13 +1712,13 @@ static void show_help_codec(const char *name, int encoder)
}
if (!printed) {
- av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to Libav, "
- "but no %s for it are available. Libav might need to be "
+ av_log(NULL, AV_LOG_ERROR, "Codec '%s' is known to FFmpeg, "
+ "but no %s for it are available. FFmpeg might need to be "
"recompiled with additional external libraries.\n",
name, encoder ? "encoders" : "decoders");
}
} else {
- av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by Libav.\n",
+ av_log(NULL, AV_LOG_ERROR, "Codec '%s' is not recognized by FFmpeg.\n",
name);
}
}
@@ -1311,6 +1777,7 @@ static void show_help_muxer(const char *name)
#if CONFIG_AVFILTER
static void show_help_filter(const char *name)
{
+#if CONFIG_AVFILTER
const AVFilter *f = avfilter_get_by_name(name);
int i, count;
@@ -1322,7 +1789,9 @@ static void show_help_filter(const char *name)
return;
}
- printf("Filter %s [%s]:\n", f->name, f->description);
+ printf("Filter %s\n", f->name);
+ if (f->description)
+ printf(" %s\n", f->description);
if (f->flags & AVFILTER_FLAG_SLICE_THREADS)
printf(" slice threading supported\n");
@@ -1330,24 +1799,34 @@ static void show_help_filter(const char *name)
printf(" Inputs:\n");
count = avfilter_pad_count(f->inputs);
for (i = 0; i < count; i++) {
- printf(" %d %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i),
+ printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->inputs, i),
media_type_string(avfilter_pad_get_type(f->inputs, i)));
}
if (f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)
printf(" dynamic (depending on the options)\n");
+ else if (!count)
+ printf(" none (source filter)\n");
printf(" Outputs:\n");
count = avfilter_pad_count(f->outputs);
for (i = 0; i < count; i++) {
- printf(" %d %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i),
+ printf(" #%d: %s (%s)\n", i, avfilter_pad_get_name(f->outputs, i),
media_type_string(avfilter_pad_get_type(f->outputs, i)));
}
if (f->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS)
printf(" dynamic (depending on the options)\n");
+ else if (!count)
+ printf(" none (sink filter)\n");
if (f->priv_class)
- show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM |
+ show_help_children(f->priv_class, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM |
AV_OPT_FLAG_AUDIO_PARAM);
+ if (f->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)
+ printf("This filter has support for timeline through the 'enable' option.\n");
+#else
+ av_log(NULL, AV_LOG_ERROR, "Build without libavfilter; "
+ "can not to satisfy request\n");
+#endif
}
#endif
@@ -1398,13 +1877,14 @@ int read_yesno(void)
int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
{
- int ret;
- FILE *f = fopen(filename, "rb");
+ int64_t ret;
+ FILE *f = av_fopen_utf8(filename, "rb");
if (!f) {
+ ret = AVERROR(errno);
av_log(NULL, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename,
strerror(errno));
- return AVERROR(errno);
+ return ret;
}
ret = fseek(f, 0, SEEK_END);
@@ -1436,9 +1916,9 @@ int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
if (ret < *size) {
av_free(*bufptr);
if (ferror(f)) {
+ ret = AVERROR(errno);
av_log(NULL, AV_LOG_ERROR, "Error while reading file '%s': %s\n",
filename, strerror(errno));
- ret = AVERROR(errno);
} else
ret = AVERROR_EOF;
} else {
@@ -1447,62 +1927,53 @@ int cmdutils_read_file(const char *filename, char **bufptr, size_t *size)
}
out:
+ if (ret < 0)
+ av_log(NULL, AV_LOG_ERROR, "IO error: %s\n", av_err2str(ret));
fclose(f);
return ret;
}
-void init_pts_correction(PtsCorrectionContext *ctx)
-{
- ctx->num_faulty_pts = ctx->num_faulty_dts = 0;
- ctx->last_pts = ctx->last_dts = INT64_MIN;
-}
-
-int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t reordered_pts,
- int64_t dts)
-{
- int64_t pts = AV_NOPTS_VALUE;
-
- if (dts != AV_NOPTS_VALUE) {
- ctx->num_faulty_dts += dts <= ctx->last_dts;
- ctx->last_dts = dts;
- }
- if (reordered_pts != AV_NOPTS_VALUE) {
- ctx->num_faulty_pts += reordered_pts <= ctx->last_pts;
- ctx->last_pts = reordered_pts;
- }
- if ((ctx->num_faulty_pts<=ctx->num_faulty_dts || dts == AV_NOPTS_VALUE)
- && reordered_pts != AV_NOPTS_VALUE)
- pts = reordered_pts;
- else
- pts = dts;
-
- return pts;
-}
-
FILE *get_preset_file(char *filename, size_t filename_size,
const char *preset_name, int is_path,
const char *codec_name)
{
FILE *f = NULL;
int i;
- const char *base[3] = { getenv("AVCONV_DATADIR"),
+ const char *base[3] = { getenv("FFMPEG_DATADIR"),
getenv("HOME"),
- AVCONV_DATADIR, };
+ FFMPEG_DATADIR, };
if (is_path) {
av_strlcpy(filename, preset_name, filename_size);
f = fopen(filename, "r");
} else {
+#ifdef _WIN32
+ char datadir[MAX_PATH], *ls;
+ base[2] = NULL;
+
+ if (GetModuleFileNameA(GetModuleHandleA(NULL), datadir, sizeof(datadir) - 1))
+ {
+ for (ls = datadir; ls < datadir + strlen(datadir); ls++)
+ if (*ls == '\\') *ls = '/';
+
+ if (ls = strrchr(datadir, '/'))
+ {
+ *ls = 0;
+ strncat(datadir, "/ffpresets", sizeof(datadir) - 1 - strlen(datadir));
+ base[2] = datadir;
+ }
+ }
+#endif
for (i = 0; i < 3 && !f; i++) {
if (!base[i])
continue;
- snprintf(filename, filename_size, "%s%s/%s.avpreset", base[i],
- i != 1 ? "" : "/.avconv", preset_name);
+ snprintf(filename, filename_size, "%s%s/%s.ffpreset", base[i],
+ i != 1 ? "" : "/.ffmpeg", preset_name);
f = fopen(filename, "r");
if (!f && codec_name) {
snprintf(filename, filename_size,
- "%s%s/%s-%s.avpreset",
- base[i], i != 1 ? "" : "/.avconv", codec_name,
+ "%s%s/%s-%s.ffpreset",
+ base[i], i != 1 ? "" : "/.ffmpeg", codec_name,
preset_name);
f = fopen(filename, "r");
}
@@ -1514,107 +1985,10 @@ FILE *get_preset_file(char *filename, size_t filename_size,
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
{
- if (*spec <= '9' && *spec >= '0') /* opt:index */
- return strtol(spec, NULL, 0) == st->index;
- else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
- *spec == 't') { /* opt:[vasdt] */
- enum AVMediaType type;
-
- switch (*spec++) {
- case 'v': type = AVMEDIA_TYPE_VIDEO; break;
- case 'a': type = AVMEDIA_TYPE_AUDIO; break;
- case 's': type = AVMEDIA_TYPE_SUBTITLE; break;
- case 'd': type = AVMEDIA_TYPE_DATA; break;
- case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
- default: av_assert0(0);
- }
- if (type != st->codec->codec_type)
- return 0;
- if (*spec++ == ':') { /* possibly followed by :index */
- int i, index = strtol(spec, NULL, 0);
- for (i = 0; i < s->nb_streams; i++)
- if (s->streams[i]->codec->codec_type == type && index-- == 0)
- return i == st->index;
- return 0;
- }
- return 1;
- } else if (*spec == 'p' && *(spec + 1) == ':') {
- int prog_id, i, j;
- char *endptr;
- spec += 2;
- prog_id = strtol(spec, &endptr, 0);
- for (i = 0; i < s->nb_programs; i++) {
- if (s->programs[i]->id != prog_id)
- continue;
-
- if (*endptr++ == ':') {
- int stream_idx = strtol(endptr, NULL, 0);
- return stream_idx >= 0 &&
- stream_idx < s->programs[i]->nb_stream_indexes &&
- st->index == s->programs[i]->stream_index[stream_idx];
- }
-
- for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
- if (st->index == s->programs[i]->stream_index[j])
- return 1;
- }
- return 0;
- } else if (*spec == 'i' && *(spec + 1) == ':') {
- int stream_id;
- char *endptr;
- spec += 2;
- stream_id = strtol(spec, &endptr, 0);
- return stream_id == st->id;
- } else if (*spec == 'm' && *(spec + 1) == ':') {
- AVDictionaryEntry *tag;
- char *key, *val;
- int ret;
-
- spec += 2;
- val = strchr(spec, ':');
-
- key = val ? av_strndup(spec, val - spec) : av_strdup(spec);
- if (!key)
- return AVERROR(ENOMEM);
-
- tag = av_dict_get(st->metadata, key, NULL, 0);
- if (tag) {
- if (!val || !strcmp(tag->value, val + 1))
- ret = 1;
- else
- ret = 0;
- } else
- ret = 0;
-
- av_freep(&key);
- return ret;
- } else if (*spec == 'u') {
- AVCodecContext *avctx = st->codec;
- int val;
- switch (avctx->codec_type) {
- case AVMEDIA_TYPE_AUDIO:
- val = avctx->sample_rate && avctx->channels;
- if (avctx->sample_fmt == AV_SAMPLE_FMT_NONE)
- return 0;
- break;
- case AVMEDIA_TYPE_VIDEO:
- val = avctx->width && avctx->height;
- if (avctx->pix_fmt == AV_PIX_FMT_NONE)
- return 0;
- break;
- case AVMEDIA_TYPE_UNKNOWN:
- val = 0;
- break;
- default:
- val = 1;
- break;
- }
- return avctx->codec_id != AV_CODEC_ID_NONE && val != 0;
- } else if (!*spec) /* empty specifier, matches everything */
- return 1;
-
- av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
- return AVERROR(EINVAL);
+ int ret = avformat_match_stream_specifier(s, st, spec);
+ if (ret < 0)
+ av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
+ return ret;
}
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
@@ -1654,11 +2028,12 @@ AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
switch (check_stream_specifier(s, st, p + 1)) {
case 1: *p = 0; break;
case 0: continue;
- default: return NULL;
+ default: exit_program(1);
}
if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||
- (codec && codec->priv_class &&
+ !codec ||
+ (codec->priv_class &&
av_opt_find(&codec->priv_class, t->key, NULL, flags,
AV_OPT_SEARCH_FAKE_OBJ)))
av_dict_set(&ret, t->key, t->value, 0);
@@ -1681,7 +2056,7 @@ AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
if (!s->nb_streams)
return NULL;
- opts = av_mallocz(s->nb_streams * sizeof(*opts));
+ opts = av_mallocz_array(s->nb_streams, sizeof(*opts));
if (!opts) {
av_log(NULL, AV_LOG_ERROR,
"Could not alloc memory for stream options.\n");
@@ -1700,7 +2075,7 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
exit_program(1);
}
if (*size < new_size) {
- uint8_t *tmp = av_realloc(array, new_size*elem_size);
+ uint8_t *tmp = av_realloc_array(array, new_size, elem_size);
if (!tmp) {
av_log(NULL, AV_LOG_ERROR, "Could not alloc buffer.\n");
exit_program(1);
@@ -1712,14 +2087,185 @@ void *grow_array(void *array, int elem_size, int *size, int new_size)
return array;
}
-const char *media_type_string(enum AVMediaType media_type)
+double get_rotation(AVStream *st)
{
- switch (media_type) {
- case AVMEDIA_TYPE_VIDEO: return "video";
- case AVMEDIA_TYPE_AUDIO: return "audio";
- case AVMEDIA_TYPE_DATA: return "data";
- case AVMEDIA_TYPE_SUBTITLE: return "subtitle";
- case AVMEDIA_TYPE_ATTACHMENT: return "attachment";
- default: return "unknown";
+ AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, "rotate", NULL, 0);
+ uint8_t* displaymatrix = av_stream_get_side_data(st,
+ AV_PKT_DATA_DISPLAYMATRIX, NULL);
+ double theta = 0;
+
+ if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
+ char *tail;
+ theta = av_strtod(rotate_tag->value, &tail);
+ if (*tail)
+ theta = 0;
+ }
+ if (displaymatrix && !theta)
+ theta = -av_display_rotation_get((int32_t*) displaymatrix);
+
+ theta -= 360*floor(theta/360 + 0.9/360);
+
+ if (fabs(theta - 90*round(theta/90)) > 2)
+ av_log_ask_for_sample(NULL, "Odd rotation angle\n");
+
+ return theta;
+}
+
+#if CONFIG_AVDEVICE
+static int print_device_sources(AVInputFormat *fmt, AVDictionary *opts)
+{
+ int ret, i;
+ AVDeviceInfoList *device_list = NULL;
+
+ if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
+ return AVERROR(EINVAL);
+
+ printf("Audo-detected sources for %s:\n", fmt->name);
+ if (!fmt->get_device_list) {
+ ret = AVERROR(ENOSYS);
+ printf("Cannot list sources. Not implemented.\n");
+ goto fail;
+ }
+
+ if ((ret = avdevice_list_input_sources(fmt, NULL, opts, &device_list)) < 0) {
+ printf("Cannot list sources.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < device_list->nb_devices; i++) {
+ printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ",
+ device_list->devices[i]->device_name, device_list->devices[i]->device_description);
+ }
+
+ fail:
+ avdevice_free_list_devices(&device_list);
+ return ret;
+}
+
+static int print_device_sinks(AVOutputFormat *fmt, AVDictionary *opts)
+{
+ int ret, i;
+ AVDeviceInfoList *device_list = NULL;
+
+ if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
+ return AVERROR(EINVAL);
+
+ printf("Audo-detected sinks for %s:\n", fmt->name);
+ if (!fmt->get_device_list) {
+ ret = AVERROR(ENOSYS);
+ printf("Cannot list sinks. Not implemented.\n");
+ goto fail;
+ }
+
+ if ((ret = avdevice_list_output_sinks(fmt, NULL, opts, &device_list)) < 0) {
+ printf("Cannot list sinks.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < device_list->nb_devices; i++) {
+ printf("%s %s [%s]\n", device_list->default_device == i ? "*" : " ",
+ device_list->devices[i]->device_name, device_list->devices[i]->device_description);
}
+
+ fail:
+ avdevice_free_list_devices(&device_list);
+ return ret;
}
+
+static int show_sinks_sources_parse_arg(const char *arg, char **dev, AVDictionary **opts)
+{
+ int ret;
+ if (arg) {
+ char *opts_str = NULL;
+ av_assert0(dev && opts);
+ *dev = av_strdup(arg);
+ if (!*dev)
+ return AVERROR(ENOMEM);
+ if ((opts_str = strchr(*dev, ','))) {
+ *(opts_str++) = '\0';
+ if (opts_str[0] && ((ret = av_dict_parse_string(opts, opts_str, "=", ":", 0)) < 0)) {
+ av_freep(dev);
+ return ret;
+ }
+ }
+ } else
+ printf("\nDevice name is not provided.\n"
+ "You can pass devicename[,opt1=val1[,opt2=val2...]] as an argument.\n\n");
+ return 0;
+}
+
+int show_sources(void *optctx, const char *opt, const char *arg)
+{
+ AVInputFormat *fmt = NULL;
+ char *dev = NULL;
+ AVDictionary *opts = NULL;
+ int ret = 0;
+ int error_level = av_log_get_level();
+
+ av_log_set_level(AV_LOG_ERROR);
+
+ if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
+ goto fail;
+
+ do {
+ fmt = av_input_audio_device_next(fmt);
+ if (fmt) {
+ if (!strcmp(fmt->name, "lavfi"))
+ continue; //it's pointless to probe lavfi
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sources(fmt, opts);
+ }
+ } while (fmt);
+ do {
+ fmt = av_input_video_device_next(fmt);
+ if (fmt) {
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sources(fmt, opts);
+ }
+ } while (fmt);
+ fail:
+ av_dict_free(&opts);
+ av_free(dev);
+ av_log_set_level(error_level);
+ return ret;
+}
+
+int show_sinks(void *optctx, const char *opt, const char *arg)
+{
+ AVOutputFormat *fmt = NULL;
+ char *dev = NULL;
+ AVDictionary *opts = NULL;
+ int ret = 0;
+ int error_level = av_log_get_level();
+
+ av_log_set_level(AV_LOG_ERROR);
+
+ if ((ret = show_sinks_sources_parse_arg(arg, &dev, &opts)) < 0)
+ goto fail;
+
+ do {
+ fmt = av_output_audio_device_next(fmt);
+ if (fmt) {
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sinks(fmt, opts);
+ }
+ } while (fmt);
+ do {
+ fmt = av_output_video_device_next(fmt);
+ if (fmt) {
+ if (dev && !av_match_name(dev, fmt->name))
+ continue;
+ print_device_sinks(fmt, opts);
+ }
+ } while (fmt);
+ fail:
+ av_dict_free(&opts);
+ av_free(dev);
+ av_log_set_level(error_level);
+ return ret;
+}
+
+#endif
diff --git a/cmdutils.h b/cmdutils.h
index d90ad4549d..a21ce35fa8 100644
--- a/cmdutils.h
+++ b/cmdutils.h
@@ -2,33 +2,38 @@
* Various utilities for command line tools
* copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef LIBAV_CMDUTILS_H
-#define LIBAV_CMDUTILS_H
+#ifndef FFMPEG_CMDUTILS_H
+#define FFMPEG_CMDUTILS_H
#include <stdint.h>
+#include "config.h"
#include "libavcodec/avcodec.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
+#ifdef _WIN32
+#undef main /* We don't want SDL to override our main() */
+#endif
+
/**
* program name, defined by the program for show_version().
*/
@@ -42,7 +47,9 @@ extern const int program_birth_year;
extern AVCodecContext *avcodec_opts[AVMEDIA_TYPE_NB];
extern AVFormatContext *avformat_opts;
extern struct SwsContext *sws_opts;
+extern AVDictionary *swr_opts;
extern AVDictionary *format_opts, *codec_opts, *resample_opts;
+extern int hide_banner;
/**
* Register a program-specific cleanup routine.
@@ -67,12 +74,12 @@ void uninit_opts(void);
/**
* Trivial log callback.
- * Only suitable for show_help and similar since it lacks prefix handling.
+ * Only suitable for opt_help and similar since it lacks prefix handling.
*/
void log_callback_help(void* ptr, int level, const char* fmt, va_list vl);
/**
- * Override the cpuflags mask.
+ * Override the cpuflags.
*/
int opt_cpuflags(void *optctx, const char *opt, const char *arg);
@@ -87,6 +94,18 @@ int opt_default(void *optctx, const char *opt, const char *arg);
*/
int opt_loglevel(void *optctx, const char *opt, const char *arg);
+int opt_report(const char *opt);
+
+int opt_max_alloc(void *optctx, const char *opt, const char *arg);
+
+int opt_codec_debug(void *optctx, const char *opt, const char *arg);
+
+#if CONFIG_OPENCL
+int opt_opencl(void *optctx, const char *opt, const char *arg);
+
+int opt_opencl_bench(void *optctx, const char *opt, const char *arg);
+#endif
+
/**
* Limit the execution time.
*/
@@ -120,7 +139,7 @@ double parse_number_or_die(const char *context, const char *numstr, int type,
* not zero timestr is interpreted as a duration, otherwise as a
* date
*
- * @see parse_date()
+ * @see av_parse_time()
*/
int64_t parse_time_or_die(const char *context, const char *timestr,
int is_duration);
@@ -151,7 +170,7 @@ typedef struct OptionDef {
#define OPT_INT64 0x0400
#define OPT_EXIT 0x0800
#define OPT_DATA 0x1000
-#define OPT_PERFILE 0x2000 /* the option is per-file (currently avconv-only).
+#define OPT_PERFILE 0x2000 /* the option is per-file (currently ffmpeg-only).
implied by OPT_OFFSET or OPT_SPEC */
#define OPT_OFFSET 0x4000 /* option is specified as an offset in a passed optctx */
#define OPT_SPEC 0x8000 /* option is to be stored in an array of SpecifierOpt.
@@ -189,13 +208,13 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags,
void show_help_children(const AVClass *class, int flags);
/**
- * Per-avtool specific help handler. Implemented in each
- * avtool, called by show_help().
+ * Per-fftool specific help handler. Implemented in each
+ * fftool, called by show_help().
*/
void show_help_default(const char *opt, const char *arg);
/**
- * Generic -h handler common to all avtools.
+ * Generic -h handler common to all fftools.
*/
int show_help(void *optctx, const char *opt, const char *arg);
@@ -238,7 +257,7 @@ typedef struct OptionGroupDef {
const char *name;
/**
* Option to be used as group separator. Can be NULL for groups which
- * are terminated by a non-option argument (e.g. avconv output files)
+ * are terminated by a non-option argument (e.g. ffmpeg output files)
*/
const char *sep;
/**
@@ -259,6 +278,7 @@ typedef struct OptionGroup {
AVDictionary *format_opts;
AVDictionary *resample_opts;
struct SwsContext *sws_opts;
+ AVDictionary *swr_opts;
} OptionGroup;
/**
@@ -385,30 +405,62 @@ void print_error(const char *filename, int err);
* current version of the repository and of the libav* libraries used by
* the program.
*/
-void show_banner(void);
+void show_banner(int argc, char **argv, const OptionDef *options);
/**
* Print the version of the program to stdout. The version message
* depends on the current versions of the repository and of the libav*
* libraries.
+ * This option processing function does not utilize the arguments.
*/
int show_version(void *optctx, const char *opt, const char *arg);
/**
+ * Print the build configuration of the program to stdout. The contents
+ * depend on the definition of FFMPEG_CONFIGURATION.
+ * This option processing function does not utilize the arguments.
+ */
+int show_buildconf(void *optctx, const char *opt, const char *arg);
+
+/**
* Print the license of the program to stdout. The license depends on
* the license of the libraries compiled into the program.
+ * This option processing function does not utilize the arguments.
*/
int show_license(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the formats supported by the
- * program.
+ * program (including devices).
+ * This option processing function does not utilize the arguments.
*/
int show_formats(void *optctx, const char *opt, const char *arg);
/**
+ * Print a listing containing all the devices supported by the
+ * program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_devices(void *optctx, const char *opt, const char *arg);
+
+#if CONFIG_AVDEVICE
+/**
+ * Print a listing containing audodetected sinks of the output device.
+ * Device name with options may be passed as an argument to limit results.
+ */
+int show_sinks(void *optctx, const char *opt, const char *arg);
+
+/**
+ * Print a listing containing audodetected sources of the input device.
+ * Device name with options may be passed as an argument to limit results.
+ */
+int show_sources(void *optctx, const char *opt, const char *arg);
+#endif
+
+/**
* Print a listing containing all the codecs supported by the
* program.
+ * This option processing function does not utilize the arguments.
*/
int show_codecs(void *optctx, const char *opt, const char *arg);
@@ -427,34 +479,51 @@ int show_encoders(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the filters supported by the
* program.
+ * This option processing function does not utilize the arguments.
*/
int show_filters(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the bit stream filters supported by the
* program.
+ * This option processing function does not utilize the arguments.
*/
int show_bsfs(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the protocols supported by the
* program.
+ * This option processing function does not utilize the arguments.
*/
int show_protocols(void *optctx, const char *opt, const char *arg);
/**
* Print a listing containing all the pixel formats supported by the
* program.
+ * This option processing function does not utilize the arguments.
*/
int show_pix_fmts(void *optctx, const char *opt, const char *arg);
/**
+ * Print a listing containing all the standard channel layouts supported by
+ * the program.
+ * This option processing function does not utilize the arguments.
+ */
+int show_layouts(void *optctx, const char *opt, const char *arg);
+
+/**
* Print a listing containing all the sample formats supported by the
* program.
*/
int show_sample_fmts(void *optctx, const char *opt, const char *arg);
/**
+ * Print a listing containing all the color names and values recognized
+ * by the program.
+ */
+int show_colors(void *optctx, const char *opt, const char *arg);
+
+/**
* Return a positive value if a line read from standard input
* starts with [yY], otherwise return 0.
*/
@@ -467,43 +536,19 @@ int read_yesno(void);
* @param filename file to read from
* @param bufptr location where pointer to buffer is returned
* @param size location where size of buffer is returned
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR error code in case of failure.
*/
int cmdutils_read_file(const char *filename, char **bufptr, size_t *size);
-typedef struct PtsCorrectionContext {
- int64_t num_faulty_pts; /// Number of incorrect PTS values so far
- int64_t num_faulty_dts; /// Number of incorrect DTS values so far
- int64_t last_pts; /// PTS of the last frame
- int64_t last_dts; /// DTS of the last frame
-} PtsCorrectionContext;
-
-/**
- * Reset the state of the PtsCorrectionContext.
- */
-void init_pts_correction(PtsCorrectionContext *ctx);
-
-/**
- * Attempt to guess proper monotonic timestamps for decoded video frames
- * which might have incorrect times. Input timestamps may wrap around, in
- * which case the output will as well.
- *
- * @param ctx the PtsCorrectionContext carrying stream pts information
- * @param pts the pts field of the decoded AVPacket, as passed through
- * AVCodecContext.reordered_opaque
- * @param dts the dts field of the decoded AVPacket
- * @return one of the input values, may be AV_NOPTS_VALUE
- */
-int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t pts, int64_t dts);
-
/**
* Get a file corresponding to a preset file.
*
* If is_path is non-zero, look for the file in the path preset_name.
- * Otherwise search for a file named arg.avpreset in the directories
- * $AVCONV_DATADIR (if set), $HOME/.avconv, and in the datadir defined
- * at configuration time, in that order. If no such file is found and
+ * Otherwise search for a file named arg.ffpreset in the directories
+ * $FFMPEG_DATADIR (if set), $HOME/.ffmpeg, and in the datadir defined
+ * at configuration time or in a "ffpresets" folder along the executable
+ * on win32, in that order. If no such file is found and
* codec_name is defined, then search for a file named
* codec_name-preset_name.avpreset in the above-mentioned directories.
*
@@ -529,10 +574,7 @@ FILE *get_preset_file(char *filename, size_t filename_size,
*/
void *grow_array(void *array, int elem_size, int *size, int new_size);
-/**
- * Get a string describing a media type.
- */
-const char *media_type_string(enum AVMediaType media_type);
+#define media_type_string av_get_media_type_string
#define GROW_ARRAY(array, nb_elems)\
array = grow_array(array, sizeof(*array), &nb_elems, nb_elems + 1)
@@ -555,4 +597,6 @@ const char *media_type_string(enum AVMediaType media_type);
char name[128];\
av_get_channel_layout_string(name, sizeof(name), 0, ch_layout);
-#endif /* LIBAV_CMDUTILS_H */
+double get_rotation(AVStream *st);
+
+#endif /* CMDUTILS_H */
diff --git a/cmdutils_common_opts.h b/cmdutils_common_opts.h
index 8693f59c56..758dac194c 100644
--- a/cmdutils_common_opts.h
+++ b/cmdutils_common_opts.h
@@ -4,7 +4,9 @@
{ "help" , OPT_EXIT, {.func_arg = show_help}, "show help", "topic" },
{ "-help" , OPT_EXIT, {.func_arg = show_help}, "show help", "topic" },
{ "version" , OPT_EXIT, {.func_arg = show_version}, "show version" },
+ { "buildconf" , OPT_EXIT, {.func_arg = show_buildconf}, "show build configuration" },
{ "formats" , OPT_EXIT, {.func_arg = show_formats }, "show available formats" },
+ { "devices" , OPT_EXIT, {.func_arg = show_devices }, "show available devices" },
{ "codecs" , OPT_EXIT, {.func_arg = show_codecs }, "show available codecs" },
{ "decoders" , OPT_EXIT, {.func_arg = show_decoders }, "show available decoders" },
{ "encoders" , OPT_EXIT, {.func_arg = show_encoders }, "show available encoders" },
@@ -12,7 +14,22 @@
{ "protocols" , OPT_EXIT, {.func_arg = show_protocols}, "show available protocols" },
{ "filters" , OPT_EXIT, {.func_arg = show_filters }, "show available filters" },
{ "pix_fmts" , OPT_EXIT, {.func_arg = show_pix_fmts }, "show available pixel formats" },
+ { "layouts" , OPT_EXIT, {.func_arg = show_layouts }, "show standard channel layouts" },
{ "sample_fmts", OPT_EXIT, {.func_arg = show_sample_fmts }, "show available audio sample formats" },
- { "loglevel" , HAS_ARG, {.func_arg = opt_loglevel}, "set libav* logging level", "loglevel" },
- { "v", HAS_ARG, {.func_arg = opt_loglevel}, "set libav* logging level", "loglevel" },
- { "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "set CPU flags mask", "mask" },
+ { "colors" , OPT_EXIT, {.func_arg = show_colors }, "show available color names" },
+ { "loglevel" , HAS_ARG, {.func_arg = opt_loglevel}, "set logging level", "loglevel" },
+ { "v", HAS_ARG, {.func_arg = opt_loglevel}, "set logging level", "loglevel" },
+ { "report" , 0, {(void*)opt_report}, "generate a report" },
+ { "max_alloc" , HAS_ARG, {.func_arg = opt_max_alloc}, "set maximum size of a single allocated block", "bytes" },
+ { "cpuflags" , HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" },
+ { "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" },
+#if CONFIG_OPENCL
+ { "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, "run benchmark on all OpenCL devices and show results" },
+ { "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, "set OpenCL environment options" },
+#endif
+#if CONFIG_AVDEVICE
+ { "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources },
+ "list sources of the input device", "device" },
+ { "sinks" , OPT_EXIT | HAS_ARG, { .func_arg = show_sinks },
+ "list sinks of the output device", "device" },
+#endif
diff --git a/cmdutils_opencl.c b/cmdutils_opencl.c
new file mode 100644
index 0000000000..61478e27af
--- /dev/null
+++ b/cmdutils_opencl.c
@@ -0,0 +1,276 @@
+/*
+ * 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
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/log.h"
+#include "libavutil/opencl.h"
+#include "libavutil/avstring.h"
+#include "cmdutils.h"
+
+typedef struct {
+ int platform_idx;
+ int device_idx;
+ char device_name[64];
+ int64_t runtime;
+} OpenCLDeviceBenchmark;
+
+const char *ocl_bench_source = AV_OPENCL_KERNEL(
+inline unsigned char clip_uint8(int a)
+{
+ if (a & (~0xFF))
+ return (-a)>>31;
+ else
+ return a;
+}
+
+kernel void unsharp_bench(
+ global unsigned char *src,
+ global unsigned char *dst,
+ global int *mask,
+ int width,
+ int height)
+{
+ int i, j, local_idx, lc_idx, sum = 0;
+ int2 thread_idx, block_idx, global_idx, lm_idx;
+ thread_idx.x = get_local_id(0);
+ thread_idx.y = get_local_id(1);
+ block_idx.x = get_group_id(0);
+ block_idx.y = get_group_id(1);
+ global_idx.x = get_global_id(0);
+ global_idx.y = get_global_id(1);
+ local uchar data[32][32];
+ local int lc[128];
+
+ for (i = 0; i <= 1; i++) {
+ lm_idx.y = -8 + (block_idx.y + i) * 16 + thread_idx.y;
+ lm_idx.y = lm_idx.y < 0 ? 0 : lm_idx.y;
+ lm_idx.y = lm_idx.y >= height ? height - 1: lm_idx.y;
+ for (j = 0; j <= 1; j++) {
+ lm_idx.x = -8 + (block_idx.x + j) * 16 + thread_idx.x;
+ lm_idx.x = lm_idx.x < 0 ? 0 : lm_idx.x;
+ lm_idx.x = lm_idx.x >= width ? width - 1: lm_idx.x;
+ data[i*16 + thread_idx.y][j*16 + thread_idx.x] = src[lm_idx.y*width + lm_idx.x];
+ }
+ }
+ local_idx = thread_idx.y*16 + thread_idx.x;
+ if (local_idx < 128)
+ lc[local_idx] = mask[local_idx];
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ \n#pragma unroll\n
+ for (i = -4; i <= 4; i++) {
+ lm_idx.y = 8 + i + thread_idx.y;
+ \n#pragma unroll\n
+ for (j = -4; j <= 4; j++) {
+ lm_idx.x = 8 + j + thread_idx.x;
+ lc_idx = (i + 4)*8 + j + 4;
+ sum += (int)data[lm_idx.y][lm_idx.x] * lc[lc_idx];
+ }
+ }
+ int temp = (int)data[thread_idx.y + 8][thread_idx.x + 8];
+ int res = temp + (((temp - (int)((sum + 1<<15) >> 16))) >> 16);
+ if (global_idx.x < width && global_idx.y < height)
+ dst[global_idx.x + global_idx.y*width] = clip_uint8(res);
+}
+);
+
+#define OCLCHECK(method, ... ) \
+do { \
+ status = method(__VA_ARGS__); \
+ if (status != CL_SUCCESS) { \
+ av_log(NULL, AV_LOG_ERROR, # method " error '%s'\n", \
+ av_opencl_errstr(status)); \
+ ret = AVERROR_EXTERNAL; \
+ goto end; \
+ } \
+} while (0)
+
+#define CREATEBUF(out, flags, size) \
+do { \
+ out = clCreateBuffer(ext_opencl_env->context, flags, size, NULL, &status); \
+ if (status != CL_SUCCESS) { \
+ av_log(NULL, AV_LOG_ERROR, "Could not create OpenCL buffer\n"); \
+ ret = AVERROR_EXTERNAL; \
+ goto end; \
+ } \
+} while (0)
+
+static void fill_rand_int(int *data, int n)
+{
+ int i;
+ srand(av_gettime());
+ for (i = 0; i < n; i++)
+ data[i] = rand();
+}
+
+#define OPENCL_NB_ITER 5
+static int64_t run_opencl_bench(AVOpenCLExternalEnv *ext_opencl_env)
+{
+ int i, arg = 0, width = 1920, height = 1088;
+ int64_t start, ret = 0;
+ cl_int status;
+ size_t kernel_len;
+ char *inbuf;
+ int *mask;
+ int buf_size = width * height * sizeof(char);
+ int mask_size = sizeof(uint32_t) * 128;
+
+ cl_mem cl_mask, cl_inbuf, cl_outbuf;
+ cl_kernel kernel = NULL;
+ cl_program program = NULL;
+ size_t local_work_size_2d[2] = {16, 16};
+ size_t global_work_size_2d[2] = {(size_t)width, (size_t)height};
+
+ if (!(inbuf = av_malloc(buf_size)) || !(mask = av_malloc(mask_size))) {
+ av_log(NULL, AV_LOG_ERROR, "Out of memory\n");
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ fill_rand_int((int*)inbuf, buf_size/4);
+ fill_rand_int(mask, mask_size/4);
+
+ CREATEBUF(cl_mask, CL_MEM_READ_ONLY, mask_size);
+ CREATEBUF(cl_inbuf, CL_MEM_READ_ONLY, buf_size);
+ CREATEBUF(cl_outbuf, CL_MEM_READ_WRITE, buf_size);
+
+ kernel_len = strlen(ocl_bench_source);
+ program = clCreateProgramWithSource(ext_opencl_env->context, 1, &ocl_bench_source,
+ &kernel_len, &status);
+ if (status != CL_SUCCESS || !program) {
+ av_log(NULL, AV_LOG_ERROR, "OpenCL unable to create benchmark program\n");
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ status = clBuildProgram(program, 1, &(ext_opencl_env->device_id), NULL, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(NULL, AV_LOG_ERROR, "OpenCL unable to build benchmark program\n");
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ kernel = clCreateKernel(program, "unsharp_bench", &status);
+ if (status != CL_SUCCESS) {
+ av_log(NULL, AV_LOG_ERROR, "OpenCL unable to create benchmark kernel\n");
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+
+ OCLCHECK(clEnqueueWriteBuffer, ext_opencl_env->command_queue, cl_inbuf, CL_TRUE, 0,
+ buf_size, inbuf, 0, NULL, NULL);
+ OCLCHECK(clEnqueueWriteBuffer, ext_opencl_env->command_queue, cl_mask, CL_TRUE, 0,
+ mask_size, mask, 0, NULL, NULL);
+ OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_inbuf);
+ OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_outbuf);
+ OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_mask);
+ OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &width);
+ OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &height);
+
+ start = av_gettime_relative();
+ for (i = 0; i < OPENCL_NB_ITER; i++)
+ OCLCHECK(clEnqueueNDRangeKernel, ext_opencl_env->command_queue, kernel, 2, NULL,
+ global_work_size_2d, local_work_size_2d, 0, NULL, NULL);
+ clFinish(ext_opencl_env->command_queue);
+ ret = (av_gettime_relative() - start)/OPENCL_NB_ITER;
+end:
+ if (kernel)
+ clReleaseKernel(kernel);
+ if (program)
+ clReleaseProgram(program);
+ if (cl_inbuf)
+ clReleaseMemObject(cl_inbuf);
+ if (cl_outbuf)
+ clReleaseMemObject(cl_outbuf);
+ if (cl_mask)
+ clReleaseMemObject(cl_mask);
+ av_free(inbuf);
+ av_free(mask);
+ return ret;
+}
+
+static int compare_ocl_device_desc(const void *a, const void *b)
+{
+ return ((OpenCLDeviceBenchmark*)a)->runtime - ((OpenCLDeviceBenchmark*)b)->runtime;
+}
+
+int opt_opencl_bench(void *optctx, const char *opt, const char *arg)
+{
+ int i, j, nb_devices = 0, count = 0;
+ int64_t score = 0;
+ AVOpenCLDeviceList *device_list;
+ AVOpenCLDeviceNode *device_node = NULL;
+ OpenCLDeviceBenchmark *devices = NULL;
+ cl_platform_id platform;
+
+ av_opencl_get_device_list(&device_list);
+ for (i = 0; i < device_list->platform_num; i++)
+ nb_devices += device_list->platform_node[i]->device_num;
+ if (!nb_devices) {
+ av_log(NULL, AV_LOG_ERROR, "No OpenCL device detected!\n");
+ return AVERROR(EINVAL);
+ }
+ if (!(devices = av_malloc_array(nb_devices, sizeof(OpenCLDeviceBenchmark)))) {
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate buffer\n");
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < device_list->platform_num; i++) {
+ for (j = 0; j < device_list->platform_node[i]->device_num; j++) {
+ device_node = device_list->platform_node[i]->device_node[j];
+ platform = device_list->platform_node[i]->platform_id;
+ score = av_opencl_benchmark(device_node, platform, run_opencl_bench);
+ if (score > 0) {
+ devices[count].platform_idx = i;
+ devices[count].device_idx = j;
+ devices[count].runtime = score;
+ av_strlcpy(devices[count].device_name, device_node->device_name,
+ sizeof(devices[count].device_name));
+ count++;
+ }
+ }
+ }
+ qsort(devices, count, sizeof(OpenCLDeviceBenchmark), compare_ocl_device_desc);
+ fprintf(stderr, "platform_idx\tdevice_idx\tdevice_name\truntime\n");
+ for (i = 0; i < count; i++)
+ fprintf(stdout, "%d\t%d\t%s\t%"PRId64"\n",
+ devices[i].platform_idx, devices[i].device_idx,
+ devices[i].device_name, devices[i].runtime);
+
+ av_opencl_free_device_list(&device_list);
+ av_free(devices);
+ return 0;
+}
+
+int opt_opencl(void *optctx, const char *opt, const char *arg)
+{
+ char *key, *value;
+ const char *opts = arg;
+ int ret = 0;
+ while (*opts) {
+ ret = av_opt_get_key_value(&opts, "=", ":", 0, &key, &value);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_set_option(key, value);
+ if (ret < 0)
+ return ret;
+ if (*opts)
+ opts++;
+ }
+ return ret;
+}
diff --git a/common.mak b/common.mak
index 9244fd366d..eac8bd9937 100644
--- a/common.mak
+++ b/common.mak
@@ -5,9 +5,102 @@
# first so "all" becomes default target
all: all-yes
+DEFAULT_YASMD=.dbg
+
+ifeq ($(DBG),1)
+YASMD=$(DEFAULT_YASMD)
+else
+YASMD=
+endif
+
+ifndef SUBDIR
+
+ifndef V
+Q = @
+ECHO = printf "$(1)\t%s\n" $(2)
+BRIEF = CC CXX HOSTCC HOSTLD AS YASM AR LD STRIP CP WINDRES
+SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM
+
+MSG = $@
+M = @$(call ECHO,$(TAG),$@);
+$(foreach VAR,$(BRIEF), \
+ $(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
+$(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
+$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
+endif
+
+ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample
+
+# NASM requires -I path terminated with /
+IFLAGS := -I. -I$(SRC_PATH)/
+CPPFLAGS := $(IFLAGS) $(CPPFLAGS)
+CFLAGS += $(ECFLAGS)
+CCFLAGS = $(CPPFLAGS) $(CFLAGS)
+ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
+CXXFLAGS += $(CPPFLAGS) $(CFLAGS)
+YASMFLAGS += $(IFLAGS:%=%/) -Pconfig.asm
+
+HOSTCCFLAGS = $(IFLAGS) $(HOSTCPPFLAGS) $(HOSTCFLAGS)
+LDFLAGS := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)
+
+define COMPILE
+ $(call $(1)DEP,$(1))
+ $($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
+endef
+
+COMPILE_C = $(call COMPILE,CC)
+COMPILE_CXX = $(call COMPILE,CXX)
+COMPILE_S = $(call COMPILE,AS)
+COMPILE_HOSTC = $(call COMPILE,HOSTCC)
+
+%.o: %.c
+ $(COMPILE_C)
+
+%.o: %.cpp
+ $(COMPILE_CXX)
+
+%.o: %.m
+ $(COMPILE_C)
+
+%.s: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -S -o $@ $<
+
+%.o: %.S
+ $(COMPILE_S)
+
+%_host.o: %.c
+ $(COMPILE_HOSTC)
+
+%.o: %.rc
+ $(WINDRES) $(IFLAGS) --preprocessor "$(DEPWINDRES) -E -xc-header -DRC_INVOKED $(CC_DEPFLAGS)" -o $@ $<
+
+%.i: %.c
+ $(CC) $(CCFLAGS) $(CC_E) $<
+
+%.h.c:
+ $(Q)echo '#include "$*.h"' >$@
+
+%.ver: %.v
+ $(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ > $@
+
+%.c %.h: TAG = GEN
+
+# Dummy rule to stop make trying to rebuild removed or renamed headers
+%.h:
+ @:
+
+# Disable suffix rules. Most of the builtin rules are suffix rules,
+# so this saves some time on slow systems.
+.SUFFIXES:
+
+# Do not delete intermediate files from chains of implicit rules
+$(OBJS):
+endif
+
include $(SRC_PATH)/arch.mak
OBJS += $(OBJS-yes)
+SLIBOBJS += $(SLIBOBJS-yes)
FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS)
TESTPROGS += $(TESTPROGS-yes)
@@ -15,6 +108,7 @@ LDLIBS = $(FFLIBS:%=%$(BUILDSUF))
FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS)
OBJS := $(sort $(OBJS:%=$(SUBDIR)%))
+SLIBOBJS := $(sort $(SLIBOBJS:%=$(SUBDIR)%))
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)%) $(TESTPROGS:%=$(SUBDIR)%-test.o)
TESTPROGS := $(TESTPROGS:%=$(SUBDIR)%-test$(EXESUF))
HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o)
@@ -46,22 +140,23 @@ $(HOSTPROGS): %$(HOSTEXESUF): %.o
$(OBJS): | $(sort $(dir $(OBJS)))
$(HOBJS): | $(sort $(dir $(HOBJS)))
$(HOSTOBJS): | $(sort $(dir $(HOSTOBJS)))
+$(SLIBOBJS): | $(sort $(dir $(SLIBOBJS)))
$(TESTOBJS): | $(sort $(dir $(TESTOBJS)))
$(TOOLOBJS): | tools
-OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(TESTOBJS))
+OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS))
-CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.gcno *.gcda
+CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ho *.gcno *.gcda *$(DEFAULT_YASMD).asm
DISTCLEANSUFFIXES = *.pc
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
define RULES
clean::
- $(RM) $(OBJS) $(OBJS:.o=.d)
+ $(RM) $(OBJS) $(OBJS:.o=.d) $(OBJS:.o=$(DEFAULT_YASMD).d)
$(RM) $(HOSTPROGS)
$(RM) $(TOOLS)
endef
$(eval $(RULES))
--include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d))
+-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SLIBOBJS:.o=.d)) $(OBJS:.o=$(DEFAULT_YASMD).d)
diff --git a/compat/aix/math.h b/compat/aix/math.h
index 380f87804d..65a89c4565 100644
--- a/compat/aix/math.h
+++ b/compat/aix/math.h
@@ -2,25 +2,25 @@
* Work around the class() function in AIX math.h clashing with
* identifiers named "class".
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef LIBAV_COMPAT_AIX_MATH_H
-#define LIBAV_COMPAT_AIX_MATH_H
+#ifndef FFMPEG_COMPAT_AIX_MATH_H
+#define FFMPEG_COMPAT_AIX_MATH_H
#define class class_in_math_h_causes_problems
@@ -28,4 +28,4 @@
#undef class
-#endif /* LIBAV_COMPAT_AIX_MATH_H */
+#endif /* FFMPEG_COMPAT_AIX_MATH_H */
diff --git a/compat/avisynth/avisynth_c.h b/compat/avisynth/avisynth_c.h
new file mode 100644
index 0000000000..0189dad72a
--- /dev/null
+++ b/compat/avisynth/avisynth_c.h
@@ -0,0 +1,882 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program 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.
+//
+// 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 General Public License for more details.
+//
+// You should have received a copy of the GNU 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, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+// NOTE: this is a partial update of the Avisynth C interface to recognize
+// new color spaces added in Avisynth 2.60. By no means is this document
+// completely Avisynth 2.60 compliant.
+
+#ifndef __AVISYNTH_C__
+#define __AVISYNTH_C__
+
+#include "avs/config.h"
+#include "avs/capi.h"
+#include "avs/types.h"
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Constants
+//
+
+#ifndef __AVISYNTH_6_H__
+enum { AVISYNTH_INTERFACE_VERSION = 6 };
+#endif
+
+enum {AVS_SAMPLE_INT8 = 1<<0,
+ AVS_SAMPLE_INT16 = 1<<1,
+ AVS_SAMPLE_INT24 = 1<<2,
+ AVS_SAMPLE_INT32 = 1<<3,
+ AVS_SAMPLE_FLOAT = 1<<4};
+
+enum {AVS_PLANAR_Y=1<<0,
+ AVS_PLANAR_U=1<<1,
+ AVS_PLANAR_V=1<<2,
+ AVS_PLANAR_ALIGNED=1<<3,
+ AVS_PLANAR_Y_ALIGNED=AVS_PLANAR_Y|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_U_ALIGNED=AVS_PLANAR_U|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_V_ALIGNED=AVS_PLANAR_V|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_A=1<<4,
+ AVS_PLANAR_R=1<<5,
+ AVS_PLANAR_G=1<<6,
+ AVS_PLANAR_B=1<<7,
+ AVS_PLANAR_A_ALIGNED=AVS_PLANAR_A|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_R_ALIGNED=AVS_PLANAR_R|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_G_ALIGNED=AVS_PLANAR_G|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_B_ALIGNED=AVS_PLANAR_B|AVS_PLANAR_ALIGNED};
+
+ // Colorspace properties.
+enum {AVS_CS_BGR = 1<<28,
+ AVS_CS_YUV = 1<<29,
+ AVS_CS_INTERLEAVED = 1<<30,
+ AVS_CS_PLANAR = 1<<31,
+
+ AVS_CS_SHIFT_SUB_WIDTH = 0,
+ AVS_CS_SHIFT_SUB_HEIGHT = 8,
+ AVS_CS_SHIFT_SAMPLE_BITS = 16,
+
+ AVS_CS_SUB_WIDTH_MASK = 7 << AVS_CS_SHIFT_SUB_WIDTH,
+ AVS_CS_SUB_WIDTH_1 = 3 << AVS_CS_SHIFT_SUB_WIDTH, // YV24
+ AVS_CS_SUB_WIDTH_2 = 0 << AVS_CS_SHIFT_SUB_WIDTH, // YV12, I420, YV16
+ AVS_CS_SUB_WIDTH_4 = 1 << AVS_CS_SHIFT_SUB_WIDTH, // YUV9, YV411
+
+ AVS_CS_VPLANEFIRST = 1 << 3, // YV12, YV16, YV24, YV411, YUV9
+ AVS_CS_UPLANEFIRST = 1 << 4, // I420
+
+ AVS_CS_SUB_HEIGHT_MASK = 7 << AVS_CS_SHIFT_SUB_HEIGHT,
+ AVS_CS_SUB_HEIGHT_1 = 3 << AVS_CS_SHIFT_SUB_HEIGHT, // YV16, YV24, YV411
+ AVS_CS_SUB_HEIGHT_2 = 0 << AVS_CS_SHIFT_SUB_HEIGHT, // YV12, I420
+ AVS_CS_SUB_HEIGHT_4 = 1 << AVS_CS_SHIFT_SUB_HEIGHT, // YUV9
+
+ AVS_CS_SAMPLE_BITS_MASK = 7 << AVS_CS_SHIFT_SAMPLE_BITS,
+ AVS_CS_SAMPLE_BITS_8 = 0 << AVS_CS_SHIFT_SAMPLE_BITS,
+ AVS_CS_SAMPLE_BITS_16 = 1 << AVS_CS_SHIFT_SAMPLE_BITS,
+ AVS_CS_SAMPLE_BITS_32 = 2 << AVS_CS_SHIFT_SAMPLE_BITS,
+
+ AVS_CS_PLANAR_MASK = AVS_CS_PLANAR | AVS_CS_INTERLEAVED | AVS_CS_YUV | AVS_CS_BGR | AVS_CS_SAMPLE_BITS_MASK | AVS_CS_SUB_HEIGHT_MASK | AVS_CS_SUB_WIDTH_MASK,
+ AVS_CS_PLANAR_FILTER = ~( AVS_CS_VPLANEFIRST | AVS_CS_UPLANEFIRST )};
+
+ // Specific colorformats
+enum {
+ AVS_CS_UNKNOWN = 0,
+ AVS_CS_BGR24 = 1<<0 | AVS_CS_BGR | AVS_CS_INTERLEAVED,
+ AVS_CS_BGR32 = 1<<1 | AVS_CS_BGR | AVS_CS_INTERLEAVED,
+ AVS_CS_YUY2 = 1<<2 | AVS_CS_YUV | AVS_CS_INTERLEAVED,
+ // AVS_CS_YV12 = 1<<3 Reserved
+ // AVS_CS_I420 = 1<<4 Reserved
+ AVS_CS_RAW32 = 1<<5 | AVS_CS_INTERLEAVED,
+
+ AVS_CS_YV24 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_1, // YVU 4:4:4 planar
+ AVS_CS_YV16 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_2, // YVU 4:2:2 planar
+ AVS_CS_YV12 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_2 | AVS_CS_SUB_WIDTH_2, // YVU 4:2:0 planar
+ AVS_CS_I420 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_UPLANEFIRST | AVS_CS_SUB_HEIGHT_2 | AVS_CS_SUB_WIDTH_2, // YUV 4:2:0 planar
+ AVS_CS_IYUV = AVS_CS_I420,
+ AVS_CS_YV411 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_4, // YVU 4:1:1 planar
+ AVS_CS_YUV9 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_4 | AVS_CS_SUB_WIDTH_4, // YVU 4:1:0 planar
+ AVS_CS_Y8 = AVS_CS_PLANAR | AVS_CS_INTERLEAVED | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 // Y 4:0:0 planar
+};
+
+enum {
+ AVS_IT_BFF = 1<<0,
+ AVS_IT_TFF = 1<<1,
+ AVS_IT_FIELDBASED = 1<<2};
+
+enum {
+ AVS_FILTER_TYPE=1,
+ AVS_FILTER_INPUT_COLORSPACE=2,
+ AVS_FILTER_OUTPUT_TYPE=9,
+ AVS_FILTER_NAME=4,
+ AVS_FILTER_AUTHOR=5,
+ AVS_FILTER_VERSION=6,
+ AVS_FILTER_ARGS=7,
+ AVS_FILTER_ARGS_INFO=8,
+ AVS_FILTER_ARGS_DESCRIPTION=10,
+ AVS_FILTER_DESCRIPTION=11};
+
+enum { //SUBTYPES
+ AVS_FILTER_TYPE_AUDIO=1,
+ AVS_FILTER_TYPE_VIDEO=2,
+ AVS_FILTER_OUTPUT_TYPE_SAME=3,
+ AVS_FILTER_OUTPUT_TYPE_DIFFERENT=4};
+
+enum {
+ // New 2.6 explicitly defined cache hints.
+ AVS_CACHE_NOTHING=10, // Do not cache video.
+ AVS_CACHE_WINDOW=11, // Hard protect upto X frames within a range of X from the current frame N.
+ AVS_CACHE_GENERIC=12, // LRU cache upto X frames.
+ AVS_CACHE_FORCE_GENERIC=13, // LRU cache upto X frames, override any previous CACHE_WINDOW.
+
+ AVS_CACHE_GET_POLICY=30, // Get the current policy.
+ AVS_CACHE_GET_WINDOW=31, // Get the current window h_span.
+ AVS_CACHE_GET_RANGE=32, // Get the current generic frame range.
+
+ AVS_CACHE_AUDIO=50, // Explicitly do cache audio, X byte cache.
+ AVS_CACHE_AUDIO_NOTHING=51, // Explicitly do not cache audio.
+ AVS_CACHE_AUDIO_NONE=52, // Audio cache off (auto mode), X byte intial cache.
+ AVS_CACHE_AUDIO_AUTO=53, // Audio cache on (auto mode), X byte intial cache.
+
+ AVS_CACHE_GET_AUDIO_POLICY=70, // Get the current audio policy.
+ AVS_CACHE_GET_AUDIO_SIZE=71, // Get the current audio cache size.
+
+ AVS_CACHE_PREFETCH_FRAME=100, // Queue request to prefetch frame N.
+ AVS_CACHE_PREFETCH_GO=101, // Action video prefetches.
+
+ AVS_CACHE_PREFETCH_AUDIO_BEGIN=120, // Begin queue request transaction to prefetch audio (take critical section).
+ AVS_CACHE_PREFETCH_AUDIO_STARTLO=121, // Set low 32 bits of start.
+ AVS_CACHE_PREFETCH_AUDIO_STARTHI=122, // Set high 32 bits of start.
+ AVS_CACHE_PREFETCH_AUDIO_COUNT=123, // Set low 32 bits of length.
+ AVS_CACHE_PREFETCH_AUDIO_COMMIT=124, // Enqueue request transaction to prefetch audio (release critical section).
+ AVS_CACHE_PREFETCH_AUDIO_GO=125, // Action audio prefetches.
+
+ AVS_CACHE_GETCHILD_CACHE_MODE=200, // Cache ask Child for desired video cache mode.
+ AVS_CACHE_GETCHILD_CACHE_SIZE=201, // Cache ask Child for desired video cache size.
+ AVS_CACHE_GETCHILD_AUDIO_MODE=202, // Cache ask Child for desired audio cache mode.
+ AVS_CACHE_GETCHILD_AUDIO_SIZE=203, // Cache ask Child for desired audio cache size.
+
+ AVS_CACHE_GETCHILD_COST=220, // Cache ask Child for estimated processing cost.
+ AVS_CACHE_COST_ZERO=221, // Child response of zero cost (ptr arithmetic only).
+ AVS_CACHE_COST_UNIT=222, // Child response of unit cost (less than or equal 1 full frame blit).
+ AVS_CACHE_COST_LOW=223, // Child response of light cost. (Fast)
+ AVS_CACHE_COST_MED=224, // Child response of medium cost. (Real time)
+ AVS_CACHE_COST_HI=225, // Child response of heavy cost. (Slow)
+
+ AVS_CACHE_GETCHILD_THREAD_MODE=240, // Cache ask Child for thread safetyness.
+ AVS_CACHE_THREAD_UNSAFE=241, // Only 1 thread allowed for all instances. 2.5 filters default!
+ AVS_CACHE_THREAD_CLASS=242, // Only 1 thread allowed for each instance. 2.6 filters default!
+ AVS_CACHE_THREAD_SAFE=243, // Allow all threads in any instance.
+ AVS_CACHE_THREAD_OWN=244, // Safe but limit to 1 thread, internally threaded.
+
+ AVS_CACHE_GETCHILD_ACCESS_COST=260, // Cache ask Child for preferred access pattern.
+ AVS_CACHE_ACCESS_RAND=261, // Filter is access order agnostic.
+ AVS_CACHE_ACCESS_SEQ0=262, // Filter prefers sequential access (low cost)
+ AVS_CACHE_ACCESS_SEQ1=263, // Filter needs sequential access (high cost)
+ };
+
+#ifdef BUILDING_AVSCORE
+struct AVS_ScriptEnvironment {
+ IScriptEnvironment * env;
+ const char * error;
+ AVS_ScriptEnvironment(IScriptEnvironment * e = 0)
+ : env(e), error(0) {}
+};
+#endif
+
+typedef struct AVS_Clip AVS_Clip;
+typedef struct AVS_ScriptEnvironment AVS_ScriptEnvironment;
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_VideoInfo
+//
+
+// AVS_VideoInfo is layed out identicly to VideoInfo
+typedef struct AVS_VideoInfo {
+ int width, height; // width=0 means no video
+ unsigned fps_numerator, fps_denominator;
+ int num_frames;
+
+ int pixel_type;
+
+ int audio_samples_per_second; // 0 means no audio
+ int sample_type;
+ INT64 num_audio_samples;
+ int nchannels;
+
+ // Imagetype properties
+
+ int image_type;
+} AVS_VideoInfo;
+
+// useful functions of the above
+AVSC_INLINE int avs_has_video(const AVS_VideoInfo * p)
+ { return (p->width!=0); }
+
+AVSC_INLINE int avs_has_audio(const AVS_VideoInfo * p)
+ { return (p->audio_samples_per_second!=0); }
+
+AVSC_INLINE int avs_is_rgb(const AVS_VideoInfo * p)
+ { return !!(p->pixel_type&AVS_CS_BGR); }
+
+AVSC_INLINE int avs_is_rgb24(const AVS_VideoInfo * p)
+ { return (p->pixel_type&AVS_CS_BGR24)==AVS_CS_BGR24; } // Clear out additional properties
+
+AVSC_INLINE int avs_is_rgb32(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_BGR32) == AVS_CS_BGR32 ; }
+
+AVSC_INLINE int avs_is_yuv(const AVS_VideoInfo * p)
+ { return !!(p->pixel_type&AVS_CS_YUV ); }
+
+AVSC_INLINE int avs_is_yuy2(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_YUY2) == AVS_CS_YUY2; }
+
+AVSC_API(int, avs_is_yv24)(const AVS_VideoInfo * p);
+
+AVSC_API(int, avs_is_yv16)(const AVS_VideoInfo * p);
+
+AVSC_API(int, avs_is_yv12)(const AVS_VideoInfo * p) ;
+
+AVSC_API(int, avs_is_yv411)(const AVS_VideoInfo * p);
+
+AVSC_API(int, avs_is_y8)(const AVS_VideoInfo * p);
+
+AVSC_INLINE int avs_is_property(const AVS_VideoInfo * p, int property)
+ { return ((p->image_type & property)==property ); }
+
+AVSC_INLINE int avs_is_planar(const AVS_VideoInfo * p)
+ { return !!(p->pixel_type & AVS_CS_PLANAR); }
+
+AVSC_API(int, avs_is_color_space)(const AVS_VideoInfo * p, int c_space);
+
+AVSC_INLINE int avs_is_field_based(const AVS_VideoInfo * p)
+ { return !!(p->image_type & AVS_IT_FIELDBASED); }
+
+AVSC_INLINE int avs_is_parity_known(const AVS_VideoInfo * p)
+ { return ((p->image_type & AVS_IT_FIELDBASED)&&(p->image_type & (AVS_IT_BFF | AVS_IT_TFF))); }
+
+AVSC_INLINE int avs_is_bff(const AVS_VideoInfo * p)
+ { return !!(p->image_type & AVS_IT_BFF); }
+
+AVSC_INLINE int avs_is_tff(const AVS_VideoInfo * p)
+ { return !!(p->image_type & AVS_IT_TFF); }
+
+AVSC_API(int, avs_get_plane_width_subsampling)(const AVS_VideoInfo * p, int plane);
+
+AVSC_API(int, avs_get_plane_height_subsampling)(const AVS_VideoInfo * p, int plane);
+
+
+AVSC_API(int, avs_bits_per_pixel)(const AVS_VideoInfo * p);
+
+AVSC_API(int, avs_bytes_from_pixels)(const AVS_VideoInfo * p, int pixels);
+
+AVSC_API(int, avs_row_size)(const AVS_VideoInfo * p, int plane);
+
+AVSC_API(int, avs_bmp_size)(const AVS_VideoInfo * vi);
+
+AVSC_INLINE int avs_samples_per_second(const AVS_VideoInfo * p)
+ { return p->audio_samples_per_second; }
+
+
+AVSC_INLINE int avs_bytes_per_channel_sample(const AVS_VideoInfo * p)
+{
+ switch (p->sample_type) {
+ case AVS_SAMPLE_INT8: return sizeof(signed char);
+ case AVS_SAMPLE_INT16: return sizeof(signed short);
+ case AVS_SAMPLE_INT24: return 3;
+ case AVS_SAMPLE_INT32: return sizeof(signed int);
+ case AVS_SAMPLE_FLOAT: return sizeof(float);
+ default: return 0;
+ }
+}
+AVSC_INLINE int avs_bytes_per_audio_sample(const AVS_VideoInfo * p)
+ { return p->nchannels*avs_bytes_per_channel_sample(p);}
+
+AVSC_INLINE INT64 avs_audio_samples_from_frames(const AVS_VideoInfo * p, INT64 frames)
+ { return ((INT64)(frames) * p->audio_samples_per_second * p->fps_denominator / p->fps_numerator); }
+
+AVSC_INLINE int avs_frames_from_audio_samples(const AVS_VideoInfo * p, INT64 samples)
+ { return (int)(samples * (INT64)p->fps_numerator / (INT64)p->fps_denominator / (INT64)p->audio_samples_per_second); }
+
+AVSC_INLINE INT64 avs_audio_samples_from_bytes(const AVS_VideoInfo * p, INT64 bytes)
+ { return bytes / avs_bytes_per_audio_sample(p); }
+
+AVSC_INLINE INT64 avs_bytes_from_audio_samples(const AVS_VideoInfo * p, INT64 samples)
+ { return samples * avs_bytes_per_audio_sample(p); }
+
+AVSC_INLINE int avs_audio_channels(const AVS_VideoInfo * p)
+ { return p->nchannels; }
+
+AVSC_INLINE int avs_sample_type(const AVS_VideoInfo * p)
+ { return p->sample_type;}
+
+// useful mutator
+AVSC_INLINE void avs_set_property(AVS_VideoInfo * p, int property)
+ { p->image_type|=property; }
+
+AVSC_INLINE void avs_clear_property(AVS_VideoInfo * p, int property)
+ { p->image_type&=~property; }
+
+AVSC_INLINE void avs_set_field_based(AVS_VideoInfo * p, int isfieldbased)
+ { if (isfieldbased) p->image_type|=AVS_IT_FIELDBASED; else p->image_type&=~AVS_IT_FIELDBASED; }
+
+AVSC_INLINE void avs_set_fps(AVS_VideoInfo * p, unsigned numerator, unsigned denominator)
+{
+ unsigned x=numerator, y=denominator;
+ while (y) { // find gcd
+ unsigned t = x%y; x = y; y = t;
+ }
+ p->fps_numerator = numerator/x;
+ p->fps_denominator = denominator/x;
+}
+
+#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR
+AVSC_INLINE int avs_is_same_colorspace(AVS_VideoInfo * x, AVS_VideoInfo * y)
+{
+ return (x->pixel_type == y->pixel_type)
+ || (avs_is_yv12(x) && avs_is_yv12(y));
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_VideoFrame
+//
+
+// VideoFrameBuffer holds information about a memory block which is used
+// for video data. For efficiency, instances of this class are not deleted
+// when the refcount reaches zero; instead they're stored in a linked list
+// to be reused. The instances are deleted when the corresponding AVS
+// file is closed.
+
+// AVS_VideoFrameBuffer is layed out identicly to VideoFrameBuffer
+// DO NOT USE THIS STRUCTURE DIRECTLY
+typedef struct AVS_VideoFrameBuffer {
+ BYTE * data;
+ int data_size;
+ // sequence_number is incremented every time the buffer is changed, so
+ // that stale views can tell they're no longer valid.
+ volatile long sequence_number;
+
+ volatile long refcount;
+} AVS_VideoFrameBuffer;
+
+// VideoFrame holds a "window" into a VideoFrameBuffer.
+
+// AVS_VideoFrame is layed out identicly to IVideoFrame
+// DO NOT USE THIS STRUCTURE DIRECTLY
+typedef struct AVS_VideoFrame {
+ volatile long refcount;
+ AVS_VideoFrameBuffer * vfb;
+ int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture.
+ int row_sizeUV, heightUV;
+} AVS_VideoFrame;
+
+// Access functions for AVS_VideoFrame
+AVSC_API(int, avs_get_pitch_p)(const AVS_VideoFrame * p, int plane);
+
+#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR
+AVSC_INLINE int avs_get_pitch(const AVS_VideoFrame * p) {
+ return avs_get_pitch_p(p, 0);}
+#endif
+
+AVSC_API(int, avs_get_row_size_p)(const AVS_VideoFrame * p, int plane);
+
+AVSC_INLINE int avs_get_row_size(const AVS_VideoFrame * p) {
+ return p->row_size; }
+
+AVSC_API(int, avs_get_height_p)(const AVS_VideoFrame * p, int plane);
+
+AVSC_INLINE int avs_get_height(const AVS_VideoFrame * p) {
+ return p->height;}
+
+AVSC_API(const BYTE *, avs_get_read_ptr_p)(const AVS_VideoFrame * p, int plane);
+
+#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR
+AVSC_INLINE const BYTE* avs_get_read_ptr(const AVS_VideoFrame * p) {
+ return avs_get_read_ptr_p(p, 0);}
+#endif
+
+AVSC_API(int, avs_is_writable)(const AVS_VideoFrame * p);
+
+AVSC_API(BYTE *, avs_get_write_ptr_p)(const AVS_VideoFrame * p, int plane);
+
+#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR
+AVSC_INLINE BYTE* avs_get_write_ptr(const AVS_VideoFrame * p) {
+ return avs_get_write_ptr_p(p, 0);}
+#endif
+
+AVSC_API(void, avs_release_video_frame)(AVS_VideoFrame *);
+// makes a shallow copy of a video frame
+AVSC_API(AVS_VideoFrame *, avs_copy_video_frame)(AVS_VideoFrame *);
+
+#ifndef AVSC_NO_DECLSPEC
+AVSC_INLINE void avs_release_frame(AVS_VideoFrame * f)
+ {avs_release_video_frame(f);}
+AVSC_INLINE AVS_VideoFrame * avs_copy_frame(AVS_VideoFrame * f)
+ {return avs_copy_video_frame(f);}
+#endif
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_Value
+//
+
+// Treat AVS_Value as a fat pointer. That is use avs_copy_value
+// and avs_release_value appropiaty as you would if AVS_Value was
+// a pointer.
+
+// To maintain source code compatibility with future versions of the
+// avisynth_c API don't use the AVS_Value directly. Use the helper
+// functions below.
+
+// AVS_Value is layed out identicly to AVSValue
+typedef struct AVS_Value AVS_Value;
+struct AVS_Value {
+ short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong
+ // for some function e'rror
+ short array_size;
+ union {
+ void * clip; // do not use directly, use avs_take_clip
+ char boolean;
+ int integer;
+ float floating_pt;
+ const char * string;
+ const AVS_Value * array;
+ } d;
+};
+
+// AVS_Value should be initilized with avs_void.
+// Should also set to avs_void after the value is released
+// with avs_copy_value. Consider it the equalvent of setting
+// a pointer to NULL
+static const AVS_Value avs_void = {'v'};
+
+AVSC_API(void, avs_copy_value)(AVS_Value * dest, AVS_Value src);
+AVSC_API(void, avs_release_value)(AVS_Value);
+
+AVSC_INLINE int avs_defined(AVS_Value v) { return v.type != 'v'; }
+AVSC_INLINE int avs_is_clip(AVS_Value v) { return v.type == 'c'; }
+AVSC_INLINE int avs_is_bool(AVS_Value v) { return v.type == 'b'; }
+AVSC_INLINE int avs_is_int(AVS_Value v) { return v.type == 'i'; }
+AVSC_INLINE int avs_is_float(AVS_Value v) { return v.type == 'f' || v.type == 'i'; }
+AVSC_INLINE int avs_is_string(AVS_Value v) { return v.type == 's'; }
+AVSC_INLINE int avs_is_array(AVS_Value v) { return v.type == 'a'; }
+AVSC_INLINE int avs_is_error(AVS_Value v) { return v.type == 'e'; }
+
+AVSC_API(AVS_Clip *, avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *);
+AVSC_API(void, avs_set_to_clip)(AVS_Value *, AVS_Clip *);
+
+AVSC_INLINE int avs_as_bool(AVS_Value v)
+ { return v.d.boolean; }
+AVSC_INLINE int avs_as_int(AVS_Value v)
+ { return v.d.integer; }
+AVSC_INLINE const char * avs_as_string(AVS_Value v)
+ { return avs_is_error(v) || avs_is_string(v) ? v.d.string : 0; }
+AVSC_INLINE double avs_as_float(AVS_Value v)
+ { return avs_is_int(v) ? v.d.integer : v.d.floating_pt; }
+AVSC_INLINE const char * avs_as_error(AVS_Value v)
+ { return avs_is_error(v) ? v.d.string : 0; }
+AVSC_INLINE const AVS_Value * avs_as_array(AVS_Value v)
+ { return v.d.array; }
+AVSC_INLINE int avs_array_size(AVS_Value v)
+ { return avs_is_array(v) ? v.array_size : 1; }
+AVSC_INLINE AVS_Value avs_array_elt(AVS_Value v, int index)
+ { return avs_is_array(v) ? v.d.array[index] : v; }
+
+// only use these functions on an AVS_Value that does not already have
+// an active value. Remember, treat AVS_Value as a fat pointer.
+AVSC_INLINE AVS_Value avs_new_value_bool(int v0)
+ { AVS_Value v; v.type = 'b'; v.d.boolean = v0 == 0 ? 0 : 1; return v; }
+AVSC_INLINE AVS_Value avs_new_value_int(int v0)
+ { AVS_Value v; v.type = 'i'; v.d.integer = v0; return v; }
+AVSC_INLINE AVS_Value avs_new_value_string(const char * v0)
+ { AVS_Value v; v.type = 's'; v.d.string = v0; return v; }
+AVSC_INLINE AVS_Value avs_new_value_float(float v0)
+ { AVS_Value v; v.type = 'f'; v.d.floating_pt = v0; return v;}
+AVSC_INLINE AVS_Value avs_new_value_error(const char * v0)
+ { AVS_Value v; v.type = 'e'; v.d.string = v0; return v; }
+#ifndef AVSC_NO_DECLSPEC
+AVSC_INLINE AVS_Value avs_new_value_clip(AVS_Clip * v0)
+ { AVS_Value v; avs_set_to_clip(&v, v0); return v; }
+#endif
+AVSC_INLINE AVS_Value avs_new_value_array(AVS_Value * v0, int size)
+ { AVS_Value v; v.type = 'a'; v.d.array = v0; v.array_size = size; return v; }
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_Clip
+//
+
+AVSC_API(void, avs_release_clip)(AVS_Clip *);
+AVSC_API(AVS_Clip *, avs_copy_clip)(AVS_Clip *);
+
+AVSC_API(const char *, avs_clip_get_error)(AVS_Clip *); // return 0 if no error
+
+AVSC_API(const AVS_VideoInfo *, avs_get_video_info)(AVS_Clip *);
+
+AVSC_API(int, avs_get_version)(AVS_Clip *);
+
+AVSC_API(AVS_VideoFrame *, avs_get_frame)(AVS_Clip *, int n);
+// The returned video frame must be released with avs_release_video_frame
+
+AVSC_API(int, avs_get_parity)(AVS_Clip *, int n);
+// return field parity if field_based, else parity of first field in frame
+
+AVSC_API(int, avs_get_audio)(AVS_Clip *, void * buf,
+ INT64 start, INT64 count);
+// start and count are in samples
+
+AVSC_API(int, avs_set_cache_hints)(AVS_Clip *,
+ int cachehints, int frame_range);
+
+// This is the callback type used by avs_add_function
+typedef AVS_Value (AVSC_CC * AVS_ApplyFunc)
+ (AVS_ScriptEnvironment *, AVS_Value args, void * user_data);
+
+typedef struct AVS_FilterInfo AVS_FilterInfo;
+struct AVS_FilterInfo
+{
+ // these members should not be modified outside of the AVS_ApplyFunc callback
+ AVS_Clip * child;
+ AVS_VideoInfo vi;
+ AVS_ScriptEnvironment * env;
+ AVS_VideoFrame * (AVSC_CC * get_frame)(AVS_FilterInfo *, int n);
+ int (AVSC_CC * get_parity)(AVS_FilterInfo *, int n);
+ int (AVSC_CC * get_audio)(AVS_FilterInfo *, void * buf,
+ INT64 start, INT64 count);
+ int (AVSC_CC * set_cache_hints)(AVS_FilterInfo *, int cachehints,
+ int frame_range);
+ void (AVSC_CC * free_filter)(AVS_FilterInfo *);
+
+ // Should be set when ever there is an error to report.
+ // It is cleared before any of the above methods are called
+ const char * error;
+ // this is to store whatever and may be modified at will
+ void * user_data;
+};
+
+// Create a new filter
+// fi is set to point to the AVS_FilterInfo so that you can
+// modify it once it is initilized.
+// store_child should generally be set to true. If it is not
+// set than ALL methods (the function pointers) must be defined
+// If it is set than you do not need to worry about freeing the child
+// clip.
+AVSC_API(AVS_Clip *, avs_new_c_filter)(AVS_ScriptEnvironment * e,
+ AVS_FilterInfo * * fi,
+ AVS_Value child, int store_child);
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_ScriptEnvironment
+//
+
+// For GetCPUFlags. These are backwards-compatible with those in VirtualDub.
+enum {
+ /* slowest CPU to support extension */
+ AVS_CPU_FORCE = 0x01, // N/A
+ AVS_CPU_FPU = 0x02, // 386/486DX
+ AVS_CPU_MMX = 0x04, // P55C, K6, PII
+ AVS_CPU_INTEGER_SSE = 0x08, // PIII, Athlon
+ AVS_CPU_SSE = 0x10, // PIII, Athlon XP/MP
+ AVS_CPU_SSE2 = 0x20, // PIV, Hammer
+ AVS_CPU_3DNOW = 0x40, // K6-2
+ AVS_CPU_3DNOW_EXT = 0x80, // Athlon
+ AVS_CPU_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2,
+ // which only Hammer will have anyway)
+ AVS_CPUF_SSE3 = 0x100, // PIV+, K8 Venice
+ AVS_CPUF_SSSE3 = 0x200, // Core 2
+ AVS_CPUF_SSE4 = 0x400, // Penryn, Wolfdale, Yorkfield
+ AVS_CPUF_SSE4_1 = 0x400,
+//AVS_CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer
+ AVS_CPUF_SSE4_2 = 0x1000, // Nehalem
+//AVS_CPUF_AVX2 = 0x2000, // Haswell
+//AVS_CPUF_AVX512 = 0x4000, // Knights Landing
+};
+
+
+AVSC_API(const char *, avs_get_error)(AVS_ScriptEnvironment *); // return 0 if no error
+
+AVSC_API(int, avs_get_cpu_flags)(AVS_ScriptEnvironment *);
+AVSC_API(int, avs_check_version)(AVS_ScriptEnvironment *, int version);
+
+AVSC_API(char *, avs_save_string)(AVS_ScriptEnvironment *, const char* s, int length);
+AVSC_API(char *, avs_sprintf)(AVS_ScriptEnvironment *, const char * fmt, ...);
+
+AVSC_API(char *, avs_vsprintf)(AVS_ScriptEnvironment *, const char * fmt, void* val);
+ // note: val is really a va_list; I hope everyone typedefs va_list to a pointer
+
+AVSC_API(int, avs_add_function)(AVS_ScriptEnvironment *,
+ const char * name, const char * params,
+ AVS_ApplyFunc apply, void * user_data);
+
+AVSC_API(int, avs_function_exists)(AVS_ScriptEnvironment *, const char * name);
+
+AVSC_API(AVS_Value, avs_invoke)(AVS_ScriptEnvironment *, const char * name,
+ AVS_Value args, const char** arg_names);
+// The returned value must be be released with avs_release_value
+
+AVSC_API(AVS_Value, avs_get_var)(AVS_ScriptEnvironment *, const char* name);
+// The returned value must be be released with avs_release_value
+
+AVSC_API(int, avs_set_var)(AVS_ScriptEnvironment *, const char* name, AVS_Value val);
+
+AVSC_API(int, avs_set_global_var)(AVS_ScriptEnvironment *, const char* name, const AVS_Value val);
+
+//void avs_push_context(AVS_ScriptEnvironment *, int level=0);
+//void avs_pop_context(AVS_ScriptEnvironment *);
+
+AVSC_API(AVS_VideoFrame *, avs_new_video_frame_a)(AVS_ScriptEnvironment *,
+ const AVS_VideoInfo * vi, int align);
+// align should be at least 16
+
+#ifndef AVSC_NO_DECLSPEC
+AVSC_INLINE
+AVS_VideoFrame * avs_new_video_frame(AVS_ScriptEnvironment * env,
+ const AVS_VideoInfo * vi)
+ {return avs_new_video_frame_a(env,vi,FRAME_ALIGN);}
+
+AVSC_INLINE
+AVS_VideoFrame * avs_new_frame(AVS_ScriptEnvironment * env,
+ const AVS_VideoInfo * vi)
+ {return avs_new_video_frame_a(env,vi,FRAME_ALIGN);}
+#endif
+
+
+AVSC_API(int, avs_make_writable)(AVS_ScriptEnvironment *, AVS_VideoFrame * * pvf);
+
+AVSC_API(void, avs_bit_blt)(AVS_ScriptEnvironment *, BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height);
+
+typedef void (AVSC_CC *AVS_ShutdownFunc)(void* user_data, AVS_ScriptEnvironment * env);
+AVSC_API(void, avs_at_exit)(AVS_ScriptEnvironment *, AVS_ShutdownFunc function, void * user_data);
+
+AVSC_API(AVS_VideoFrame *, avs_subframe)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height);
+// The returned video frame must be be released
+
+AVSC_API(int, avs_set_memory_max)(AVS_ScriptEnvironment *, int mem);
+
+AVSC_API(int, avs_set_working_dir)(AVS_ScriptEnvironment *, const char * newdir);
+
+// avisynth.dll exports this; it's a way to use it as a library, without
+// writing an AVS script or without going through AVIFile.
+AVSC_API(AVS_ScriptEnvironment *, avs_create_script_environment)(int version);
+
+// this symbol is the entry point for the plugin and must
+// be defined
+AVSC_EXPORT
+const char * AVSC_CC avisynth_c_plugin_init(AVS_ScriptEnvironment* env);
+
+
+AVSC_API(void, avs_delete_script_environment)(AVS_ScriptEnvironment *);
+
+
+AVSC_API(AVS_VideoFrame *, avs_subframe_planar)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV);
+// The returned video frame must be be released
+
+#ifdef AVSC_NO_DECLSPEC
+// use LoadLibrary and related functions to dynamically load Avisynth instead of declspec(dllimport)
+/*
+ The following functions needs to have been declared, probably from windows.h
+
+ void* malloc(size_t)
+ void free(void*);
+
+ HMODULE LoadLibrary(const char*);
+ void* GetProcAddress(HMODULE, const char*);
+ FreeLibrary(HMODULE);
+*/
+
+
+typedef struct AVS_Library AVS_Library;
+
+#define AVSC_DECLARE_FUNC(name) name##_func name
+
+struct AVS_Library {
+ HMODULE handle;
+
+ AVSC_DECLARE_FUNC(avs_add_function);
+ AVSC_DECLARE_FUNC(avs_at_exit);
+ AVSC_DECLARE_FUNC(avs_bit_blt);
+ AVSC_DECLARE_FUNC(avs_check_version);
+ AVSC_DECLARE_FUNC(avs_clip_get_error);
+ AVSC_DECLARE_FUNC(avs_copy_clip);
+ AVSC_DECLARE_FUNC(avs_copy_value);
+ AVSC_DECLARE_FUNC(avs_copy_video_frame);
+ AVSC_DECLARE_FUNC(avs_create_script_environment);
+ AVSC_DECLARE_FUNC(avs_delete_script_environment);
+ AVSC_DECLARE_FUNC(avs_function_exists);
+ AVSC_DECLARE_FUNC(avs_get_audio);
+ AVSC_DECLARE_FUNC(avs_get_cpu_flags);
+ AVSC_DECLARE_FUNC(avs_get_frame);
+ AVSC_DECLARE_FUNC(avs_get_parity);
+ AVSC_DECLARE_FUNC(avs_get_var);
+ AVSC_DECLARE_FUNC(avs_get_version);
+ AVSC_DECLARE_FUNC(avs_get_video_info);
+ AVSC_DECLARE_FUNC(avs_invoke);
+ AVSC_DECLARE_FUNC(avs_make_writable);
+ AVSC_DECLARE_FUNC(avs_new_c_filter);
+ AVSC_DECLARE_FUNC(avs_new_video_frame_a);
+ AVSC_DECLARE_FUNC(avs_release_clip);
+ AVSC_DECLARE_FUNC(avs_release_value);
+ AVSC_DECLARE_FUNC(avs_release_video_frame);
+ AVSC_DECLARE_FUNC(avs_save_string);
+ AVSC_DECLARE_FUNC(avs_set_cache_hints);
+ AVSC_DECLARE_FUNC(avs_set_global_var);
+ AVSC_DECLARE_FUNC(avs_set_memory_max);
+ AVSC_DECLARE_FUNC(avs_set_to_clip);
+ AVSC_DECLARE_FUNC(avs_set_var);
+ AVSC_DECLARE_FUNC(avs_set_working_dir);
+ AVSC_DECLARE_FUNC(avs_sprintf);
+ AVSC_DECLARE_FUNC(avs_subframe);
+ AVSC_DECLARE_FUNC(avs_subframe_planar);
+ AVSC_DECLARE_FUNC(avs_take_clip);
+ AVSC_DECLARE_FUNC(avs_vsprintf);
+
+ AVSC_DECLARE_FUNC(avs_get_error);
+ AVSC_DECLARE_FUNC(avs_is_yv24);
+ AVSC_DECLARE_FUNC(avs_is_yv16);
+ AVSC_DECLARE_FUNC(avs_is_yv12);
+ AVSC_DECLARE_FUNC(avs_is_yv411);
+ AVSC_DECLARE_FUNC(avs_is_y8);
+ AVSC_DECLARE_FUNC(avs_is_color_space);
+
+ AVSC_DECLARE_FUNC(avs_get_plane_width_subsampling);
+ AVSC_DECLARE_FUNC(avs_get_plane_height_subsampling);
+ AVSC_DECLARE_FUNC(avs_bits_per_pixel);
+ AVSC_DECLARE_FUNC(avs_bytes_from_pixels);
+ AVSC_DECLARE_FUNC(avs_row_size);
+ AVSC_DECLARE_FUNC(avs_bmp_size);
+ AVSC_DECLARE_FUNC(avs_get_pitch_p);
+ AVSC_DECLARE_FUNC(avs_get_row_size_p);
+ AVSC_DECLARE_FUNC(avs_get_height_p);
+ AVSC_DECLARE_FUNC(avs_get_read_ptr_p);
+ AVSC_DECLARE_FUNC(avs_is_writable);
+ AVSC_DECLARE_FUNC(avs_get_write_ptr_p);
+};
+
+#undef AVSC_DECLARE_FUNC
+
+
+AVSC_INLINE AVS_Library * avs_load_library() {
+ AVS_Library *library = (AVS_Library *)malloc(sizeof(AVS_Library));
+ if (library == NULL)
+ return NULL;
+ library->handle = LoadLibrary("avisynth");
+ if (library->handle == NULL)
+ goto fail;
+
+#define __AVSC_STRINGIFY(x) #x
+#define AVSC_STRINGIFY(x) __AVSC_STRINGIFY(x)
+#define AVSC_LOAD_FUNC(name) {\
+ library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\
+ if (library->name == NULL)\
+ goto fail;\
+}
+
+ AVSC_LOAD_FUNC(avs_add_function);
+ AVSC_LOAD_FUNC(avs_at_exit);
+ AVSC_LOAD_FUNC(avs_bit_blt);
+ AVSC_LOAD_FUNC(avs_check_version);
+ AVSC_LOAD_FUNC(avs_clip_get_error);
+ AVSC_LOAD_FUNC(avs_copy_clip);
+ AVSC_LOAD_FUNC(avs_copy_value);
+ AVSC_LOAD_FUNC(avs_copy_video_frame);
+ AVSC_LOAD_FUNC(avs_create_script_environment);
+ AVSC_LOAD_FUNC(avs_delete_script_environment);
+ AVSC_LOAD_FUNC(avs_function_exists);
+ AVSC_LOAD_FUNC(avs_get_audio);
+ AVSC_LOAD_FUNC(avs_get_cpu_flags);
+ AVSC_LOAD_FUNC(avs_get_frame);
+ AVSC_LOAD_FUNC(avs_get_parity);
+ AVSC_LOAD_FUNC(avs_get_var);
+ AVSC_LOAD_FUNC(avs_get_version);
+ AVSC_LOAD_FUNC(avs_get_video_info);
+ AVSC_LOAD_FUNC(avs_invoke);
+ AVSC_LOAD_FUNC(avs_make_writable);
+ AVSC_LOAD_FUNC(avs_new_c_filter);
+ AVSC_LOAD_FUNC(avs_new_video_frame_a);
+ AVSC_LOAD_FUNC(avs_release_clip);
+ AVSC_LOAD_FUNC(avs_release_value);
+ AVSC_LOAD_FUNC(avs_release_video_frame);
+ AVSC_LOAD_FUNC(avs_save_string);
+ AVSC_LOAD_FUNC(avs_set_cache_hints);
+ AVSC_LOAD_FUNC(avs_set_global_var);
+ AVSC_LOAD_FUNC(avs_set_memory_max);
+ AVSC_LOAD_FUNC(avs_set_to_clip);
+ AVSC_LOAD_FUNC(avs_set_var);
+ AVSC_LOAD_FUNC(avs_set_working_dir);
+ AVSC_LOAD_FUNC(avs_sprintf);
+ AVSC_LOAD_FUNC(avs_subframe);
+ AVSC_LOAD_FUNC(avs_subframe_planar);
+ AVSC_LOAD_FUNC(avs_take_clip);
+ AVSC_LOAD_FUNC(avs_vsprintf);
+
+ AVSC_LOAD_FUNC(avs_get_error);
+ AVSC_LOAD_FUNC(avs_is_yv24);
+ AVSC_LOAD_FUNC(avs_is_yv16);
+ AVSC_LOAD_FUNC(avs_is_yv12);
+ AVSC_LOAD_FUNC(avs_is_yv411);
+ AVSC_LOAD_FUNC(avs_is_y8);
+ AVSC_LOAD_FUNC(avs_is_color_space);
+
+ AVSC_LOAD_FUNC(avs_get_plane_width_subsampling);
+ AVSC_LOAD_FUNC(avs_get_plane_height_subsampling);
+ AVSC_LOAD_FUNC(avs_bits_per_pixel);
+ AVSC_LOAD_FUNC(avs_bytes_from_pixels);
+ AVSC_LOAD_FUNC(avs_row_size);
+ AVSC_LOAD_FUNC(avs_bmp_size);
+ AVSC_LOAD_FUNC(avs_get_pitch_p);
+ AVSC_LOAD_FUNC(avs_get_row_size_p);
+ AVSC_LOAD_FUNC(avs_get_height_p);
+ AVSC_LOAD_FUNC(avs_get_read_ptr_p);
+ AVSC_LOAD_FUNC(avs_is_writable);
+ AVSC_LOAD_FUNC(avs_get_write_ptr_p);
+
+#undef __AVSC_STRINGIFY
+#undef AVSC_STRINGIFY
+#undef AVSC_LOAD_FUNC
+
+ return library;
+
+fail:
+ free(library);
+ return NULL;
+}
+
+AVSC_INLINE void avs_free_library(AVS_Library *library) {
+ if (library == NULL)
+ return;
+ FreeLibrary(library->handle);
+ free(library);
+}
+#endif
+
+#endif
diff --git a/compat/avisynth/avs/capi.h b/compat/avisynth/avs/capi.h
new file mode 100644
index 0000000000..6ed6770c66
--- /dev/null
+++ b/compat/avisynth/avs/capi.h
@@ -0,0 +1,62 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program 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.
+//
+// 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+#ifndef AVS_CAPI_H
+#define AVS_CAPI_H
+
+#ifdef __cplusplus
+# define EXTERN_C extern "C"
+#else
+# define EXTERN_C
+#endif
+
+#ifndef AVSC_USE_STDCALL
+# define AVSC_CC __cdecl
+#else
+# define AVSC_CC __stdcall
+#endif
+
+#define AVSC_INLINE static __inline
+
+#ifdef BUILDING_AVSCORE
+# define AVSC_EXPORT EXTERN_C
+# define AVSC_API(ret, name) EXTERN_C __declspec(dllexport) ret AVSC_CC name
+#else
+# define AVSC_EXPORT EXTERN_C __declspec(dllexport)
+# ifndef AVSC_NO_DECLSPEC
+# define AVSC_API(ret, name) EXTERN_C __declspec(dllimport) ret AVSC_CC name
+# else
+# define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func)
+# endif
+#endif
+
+#endif //AVS_CAPI_H
diff --git a/compat/avisynth/avs/config.h b/compat/avisynth/avs/config.h
new file mode 100644
index 0000000000..7acd95b57e
--- /dev/null
+++ b/compat/avisynth/avs/config.h
@@ -0,0 +1,55 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program 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.
+//
+// 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+#ifndef AVS_CONFIG_H
+#define AVS_CONFIG_H
+
+// Undefine this to get cdecl calling convention
+#define AVSC_USE_STDCALL 1
+
+// NOTE TO PLUGIN AUTHORS:
+// Because FRAME_ALIGN can be substantially higher than the alignment
+// a plugin actually needs, plugins should not use FRAME_ALIGN to check for
+// alignment. They should always request the exact alignment value they need.
+// This is to make sure that plugins work over the widest range of AviSynth
+// builds possible.
+#define FRAME_ALIGN 32
+
+#if defined(_M_AMD64) || defined(__x86_64)
+# define X86_64
+#elif defined(_M_IX86) || defined(__i386__)
+# define X86_32
+#else
+# error Unsupported CPU architecture.
+#endif
+
+#endif //AVS_CONFIG_H
diff --git a/compat/avisynth/avs/types.h b/compat/avisynth/avs/types.h
new file mode 100644
index 0000000000..e5f084cd33
--- /dev/null
+++ b/compat/avisynth/avs/types.h
@@ -0,0 +1,51 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program 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.
+//
+// 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+#ifndef AVS_TYPES_H
+#define AVS_TYPES_H
+
+// Define all types necessary for interfacing with avisynth.dll
+
+// Raster types used by VirtualDub & Avisynth
+typedef unsigned int Pixel32;
+typedef unsigned char BYTE;
+
+// Audio Sample information
+typedef float SFLOAT;
+
+#ifdef __GNUC__
+typedef long long int INT64;
+#else
+typedef __int64 INT64;
+#endif
+
+#endif //AVS_TYPES_H
diff --git a/compat/avisynth/avxsynth_c.h b/compat/avisynth/avxsynth_c.h
new file mode 100644
index 0000000000..991f4be1ab
--- /dev/null
+++ b/compat/avisynth/avxsynth_c.h
@@ -0,0 +1,728 @@
+// Avisynth C Interface Version 0.20
+// Copyright 2003 Kevin Atkinson
+
+// This program 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.
+//
+// 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 General Public License for more details.
+//
+// You should have received a copy of the GNU 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, or visit
+// http://www.gnu.org/copyleft/gpl.html .
+//
+// As a special exception, I give you permission to link to the
+// Avisynth C interface with independent modules that communicate with
+// the Avisynth C interface solely through the interfaces defined in
+// avisynth_c.h, regardless of the license terms of these independent
+// modules, and to copy and distribute the resulting combined work
+// under terms of your choice, provided that every copy of the
+// combined work is accompanied by a complete copy of the source code
+// of the Avisynth C interface and Avisynth itself (with the version
+// used to produce the combined work), being distributed under the
+// terms of the GNU General Public License plus this exception. An
+// independent module is a module which is not derived from or based
+// on Avisynth C Interface, such as 3rd-party filters, import and
+// export plugins, or graphical user interfaces.
+
+#ifndef __AVXSYNTH_C__
+#define __AVXSYNTH_C__
+
+#include "windowsPorts/windows2linux.h"
+#include <stdarg.h>
+
+#ifdef __cplusplus
+# define EXTERN_C extern "C"
+#else
+# define EXTERN_C
+#endif
+
+#define AVSC_USE_STDCALL 1
+
+#ifndef AVSC_USE_STDCALL
+# define AVSC_CC __cdecl
+#else
+# define AVSC_CC __stdcall
+#endif
+
+#define AVSC_INLINE static __inline
+
+#ifdef AVISYNTH_C_EXPORTS
+# define AVSC_EXPORT EXTERN_C
+# define AVSC_API(ret, name) EXTERN_C __declspec(dllexport) ret AVSC_CC name
+#else
+# define AVSC_EXPORT EXTERN_C __declspec(dllexport)
+# ifndef AVSC_NO_DECLSPEC
+# define AVSC_API(ret, name) EXTERN_C __declspec(dllimport) ret AVSC_CC name
+# else
+# define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func)
+# endif
+#endif
+
+#ifdef __GNUC__
+typedef long long int INT64;
+#else
+typedef __int64 INT64;
+#endif
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Constants
+//
+
+#ifndef __AVXSYNTH_H__
+enum { AVISYNTH_INTERFACE_VERSION = 3 };
+#endif
+
+enum {AVS_SAMPLE_INT8 = 1<<0,
+ AVS_SAMPLE_INT16 = 1<<1,
+ AVS_SAMPLE_INT24 = 1<<2,
+ AVS_SAMPLE_INT32 = 1<<3,
+ AVS_SAMPLE_FLOAT = 1<<4};
+
+enum {AVS_PLANAR_Y=1<<0,
+ AVS_PLANAR_U=1<<1,
+ AVS_PLANAR_V=1<<2,
+ AVS_PLANAR_ALIGNED=1<<3,
+ AVS_PLANAR_Y_ALIGNED=AVS_PLANAR_Y|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_U_ALIGNED=AVS_PLANAR_U|AVS_PLANAR_ALIGNED,
+ AVS_PLANAR_V_ALIGNED=AVS_PLANAR_V|AVS_PLANAR_ALIGNED};
+
+ // Colorspace properties.
+enum {AVS_CS_BGR = 1<<28,
+ AVS_CS_YUV = 1<<29,
+ AVS_CS_INTERLEAVED = 1<<30,
+ AVS_CS_PLANAR = 1<<31};
+
+ // Specific colorformats
+enum {
+ AVS_CS_UNKNOWN = 0,
+ AVS_CS_BGR24 = 1<<0 | AVS_CS_BGR | AVS_CS_INTERLEAVED,
+ AVS_CS_BGR32 = 1<<1 | AVS_CS_BGR | AVS_CS_INTERLEAVED,
+ AVS_CS_YUY2 = 1<<2 | AVS_CS_YUV | AVS_CS_INTERLEAVED,
+ AVS_CS_YV12 = 1<<3 | AVS_CS_YUV | AVS_CS_PLANAR, // y-v-u, planar
+ AVS_CS_I420 = 1<<4 | AVS_CS_YUV | AVS_CS_PLANAR, // y-u-v, planar
+ AVS_CS_IYUV = 1<<4 | AVS_CS_YUV | AVS_CS_PLANAR // same as above
+};
+
+enum {
+ AVS_IT_BFF = 1<<0,
+ AVS_IT_TFF = 1<<1,
+ AVS_IT_FIELDBASED = 1<<2};
+
+enum {
+ AVS_FILTER_TYPE=1,
+ AVS_FILTER_INPUT_COLORSPACE=2,
+ AVS_FILTER_OUTPUT_TYPE=9,
+ AVS_FILTER_NAME=4,
+ AVS_FILTER_AUTHOR=5,
+ AVS_FILTER_VERSION=6,
+ AVS_FILTER_ARGS=7,
+ AVS_FILTER_ARGS_INFO=8,
+ AVS_FILTER_ARGS_DESCRIPTION=10,
+ AVS_FILTER_DESCRIPTION=11};
+
+enum { //SUBTYPES
+ AVS_FILTER_TYPE_AUDIO=1,
+ AVS_FILTER_TYPE_VIDEO=2,
+ AVS_FILTER_OUTPUT_TYPE_SAME=3,
+ AVS_FILTER_OUTPUT_TYPE_DIFFERENT=4};
+
+enum {
+ AVS_CACHE_NOTHING=0,
+ AVS_CACHE_RANGE=1,
+ AVS_CACHE_ALL=2,
+ AVS_CACHE_AUDIO=3,
+ AVS_CACHE_AUDIO_NONE=4,
+ AVS_CACHE_AUDIO_AUTO=5
+};
+
+#define AVS_FRAME_ALIGN 16
+
+typedef struct AVS_Clip AVS_Clip;
+typedef struct AVS_ScriptEnvironment AVS_ScriptEnvironment;
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_VideoInfo
+//
+
+// AVS_VideoInfo is layed out identicly to VideoInfo
+typedef struct AVS_VideoInfo {
+ int width, height; // width=0 means no video
+ unsigned fps_numerator, fps_denominator;
+ int num_frames;
+
+ int pixel_type;
+
+ int audio_samples_per_second; // 0 means no audio
+ int sample_type;
+ INT64 num_audio_samples;
+ int nchannels;
+
+ // Imagetype properties
+
+ int image_type;
+} AVS_VideoInfo;
+
+// useful functions of the above
+AVSC_INLINE int avs_has_video(const AVS_VideoInfo * p)
+ { return (p->width!=0); }
+
+AVSC_INLINE int avs_has_audio(const AVS_VideoInfo * p)
+ { return (p->audio_samples_per_second!=0); }
+
+AVSC_INLINE int avs_is_rgb(const AVS_VideoInfo * p)
+ { return !!(p->pixel_type&AVS_CS_BGR); }
+
+AVSC_INLINE int avs_is_rgb24(const AVS_VideoInfo * p)
+ { return (p->pixel_type&AVS_CS_BGR24)==AVS_CS_BGR24; } // Clear out additional properties
+
+AVSC_INLINE int avs_is_rgb32(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_BGR32) == AVS_CS_BGR32 ; }
+
+AVSC_INLINE int avs_is_yuv(const AVS_VideoInfo * p)
+ { return !!(p->pixel_type&AVS_CS_YUV ); }
+
+AVSC_INLINE int avs_is_yuy2(const AVS_VideoInfo * p)
+ { return (p->pixel_type & AVS_CS_YUY2) == AVS_CS_YUY2; }
+
+AVSC_INLINE int avs_is_yv12(const AVS_VideoInfo * p)
+ { return ((p->pixel_type & AVS_CS_YV12) == AVS_CS_YV12)||((p->pixel_type & AVS_CS_I420) == AVS_CS_I420); }
+
+AVSC_INLINE int avs_is_color_space(const AVS_VideoInfo * p, int c_space)
+ { return ((p->pixel_type & c_space) == c_space); }
+
+AVSC_INLINE int avs_is_property(const AVS_VideoInfo * p, int property)
+ { return ((p->pixel_type & property)==property ); }
+
+AVSC_INLINE int avs_is_planar(const AVS_VideoInfo * p)
+ { return !!(p->pixel_type & AVS_CS_PLANAR); }
+
+AVSC_INLINE int avs_is_field_based(const AVS_VideoInfo * p)
+ { return !!(p->image_type & AVS_IT_FIELDBASED); }
+
+AVSC_INLINE int avs_is_parity_known(const AVS_VideoInfo * p)
+ { return ((p->image_type & AVS_IT_FIELDBASED)&&(p->image_type & (AVS_IT_BFF | AVS_IT_TFF))); }
+
+AVSC_INLINE int avs_is_bff(const AVS_VideoInfo * p)
+ { return !!(p->image_type & AVS_IT_BFF); }
+
+AVSC_INLINE int avs_is_tff(const AVS_VideoInfo * p)
+ { return !!(p->image_type & AVS_IT_TFF); }
+
+AVSC_INLINE int avs_bits_per_pixel(const AVS_VideoInfo * p)
+{
+ switch (p->pixel_type) {
+ case AVS_CS_BGR24: return 24;
+ case AVS_CS_BGR32: return 32;
+ case AVS_CS_YUY2: return 16;
+ case AVS_CS_YV12:
+ case AVS_CS_I420: return 12;
+ default: return 0;
+ }
+}
+AVSC_INLINE int avs_bytes_from_pixels(const AVS_VideoInfo * p, int pixels)
+ { return pixels * (avs_bits_per_pixel(p)>>3); } // Will work on planar images, but will return only luma planes
+
+AVSC_INLINE int avs_row_size(const AVS_VideoInfo * p)
+ { return avs_bytes_from_pixels(p,p->width); } // Also only returns first plane on planar images
+
+AVSC_INLINE int avs_bmp_size(const AVS_VideoInfo * vi)
+ { if (avs_is_planar(vi)) {int p = vi->height * ((avs_row_size(vi)+3) & ~3); p+=p>>1; return p; } return vi->height * ((avs_row_size(vi)+3) & ~3); }
+
+AVSC_INLINE int avs_samples_per_second(const AVS_VideoInfo * p)
+ { return p->audio_samples_per_second; }
+
+
+AVSC_INLINE int avs_bytes_per_channel_sample(const AVS_VideoInfo * p)
+{
+ switch (p->sample_type) {
+ case AVS_SAMPLE_INT8: return sizeof(signed char);
+ case AVS_SAMPLE_INT16: return sizeof(signed short);
+ case AVS_SAMPLE_INT24: return 3;
+ case AVS_SAMPLE_INT32: return sizeof(signed int);
+ case AVS_SAMPLE_FLOAT: return sizeof(float);
+ default: return 0;
+ }
+}
+AVSC_INLINE int avs_bytes_per_audio_sample(const AVS_VideoInfo * p)
+ { return p->nchannels*avs_bytes_per_channel_sample(p);}
+
+AVSC_INLINE INT64 avs_audio_samples_from_frames(const AVS_VideoInfo * p, INT64 frames)
+ { return ((INT64)(frames) * p->audio_samples_per_second * p->fps_denominator / p->fps_numerator); }
+
+AVSC_INLINE int avs_frames_from_audio_samples(const AVS_VideoInfo * p, INT64 samples)
+ { return (int)(samples * (INT64)p->fps_numerator / (INT64)p->fps_denominator / (INT64)p->audio_samples_per_second); }
+
+AVSC_INLINE INT64 avs_audio_samples_from_bytes(const AVS_VideoInfo * p, INT64 bytes)
+ { return bytes / avs_bytes_per_audio_sample(p); }
+
+AVSC_INLINE INT64 avs_bytes_from_audio_samples(const AVS_VideoInfo * p, INT64 samples)
+ { return samples * avs_bytes_per_audio_sample(p); }
+
+AVSC_INLINE int avs_audio_channels(const AVS_VideoInfo * p)
+ { return p->nchannels; }
+
+AVSC_INLINE int avs_sample_type(const AVS_VideoInfo * p)
+ { return p->sample_type;}
+
+// useful mutator
+AVSC_INLINE void avs_set_property(AVS_VideoInfo * p, int property)
+ { p->image_type|=property; }
+
+AVSC_INLINE void avs_clear_property(AVS_VideoInfo * p, int property)
+ { p->image_type&=~property; }
+
+AVSC_INLINE void avs_set_field_based(AVS_VideoInfo * p, int isfieldbased)
+ { if (isfieldbased) p->image_type|=AVS_IT_FIELDBASED; else p->image_type&=~AVS_IT_FIELDBASED; }
+
+AVSC_INLINE void avs_set_fps(AVS_VideoInfo * p, unsigned numerator, unsigned denominator)
+{
+ unsigned x=numerator, y=denominator;
+ while (y) { // find gcd
+ unsigned t = x%y; x = y; y = t;
+ }
+ p->fps_numerator = numerator/x;
+ p->fps_denominator = denominator/x;
+}
+
+AVSC_INLINE int avs_is_same_colorspace(AVS_VideoInfo * x, AVS_VideoInfo * y)
+{
+ return (x->pixel_type == y->pixel_type)
+ || (avs_is_yv12(x) && avs_is_yv12(y));
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_VideoFrame
+//
+
+// VideoFrameBuffer holds information about a memory block which is used
+// for video data. For efficiency, instances of this class are not deleted
+// when the refcount reaches zero; instead they're stored in a linked list
+// to be reused. The instances are deleted when the corresponding AVS
+// file is closed.
+
+// AVS_VideoFrameBuffer is layed out identicly to VideoFrameBuffer
+// DO NOT USE THIS STRUCTURE DIRECTLY
+typedef struct AVS_VideoFrameBuffer {
+ unsigned char * data;
+ int data_size;
+ // sequence_number is incremented every time the buffer is changed, so
+ // that stale views can tell they're no longer valid.
+ long sequence_number;
+
+ long refcount;
+} AVS_VideoFrameBuffer;
+
+// VideoFrame holds a "window" into a VideoFrameBuffer.
+
+// AVS_VideoFrame is layed out identicly to IVideoFrame
+// DO NOT USE THIS STRUCTURE DIRECTLY
+typedef struct AVS_VideoFrame {
+ int refcount;
+ AVS_VideoFrameBuffer * vfb;
+ int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture.
+} AVS_VideoFrame;
+
+// Access functions for AVS_VideoFrame
+AVSC_INLINE int avs_get_pitch(const AVS_VideoFrame * p) {
+ return p->pitch;}
+
+AVSC_INLINE int avs_get_pitch_p(const AVS_VideoFrame * p, int plane) {
+ switch (plane) {
+ case AVS_PLANAR_U: case AVS_PLANAR_V: return p->pitchUV;}
+ return p->pitch;}
+
+AVSC_INLINE int avs_get_row_size(const AVS_VideoFrame * p) {
+ return p->row_size; }
+
+AVSC_INLINE int avs_get_row_size_p(const AVS_VideoFrame * p, int plane) {
+ int r;
+ switch (plane) {
+ case AVS_PLANAR_U: case AVS_PLANAR_V:
+ if (p->pitchUV) return p->row_size>>1;
+ else return 0;
+ case AVS_PLANAR_U_ALIGNED: case AVS_PLANAR_V_ALIGNED:
+ if (p->pitchUV) {
+ r = ((p->row_size+AVS_FRAME_ALIGN-1)&(~(AVS_FRAME_ALIGN-1)) )>>1; // Aligned rowsize
+ if (r < p->pitchUV)
+ return r;
+ return p->row_size>>1;
+ } else return 0;
+ case AVS_PLANAR_Y_ALIGNED:
+ r = (p->row_size+AVS_FRAME_ALIGN-1)&(~(AVS_FRAME_ALIGN-1)); // Aligned rowsize
+ if (r <= p->pitch)
+ return r;
+ return p->row_size;
+ }
+ return p->row_size;
+}
+
+AVSC_INLINE int avs_get_height(const AVS_VideoFrame * p) {
+ return p->height;}
+
+AVSC_INLINE int avs_get_height_p(const AVS_VideoFrame * p, int plane) {
+ switch (plane) {
+ case AVS_PLANAR_U: case AVS_PLANAR_V:
+ if (p->pitchUV) return p->height>>1;
+ return 0;
+ }
+ return p->height;}
+
+AVSC_INLINE const unsigned char* avs_get_read_ptr(const AVS_VideoFrame * p) {
+ return p->vfb->data + p->offset;}
+
+AVSC_INLINE const unsigned char* avs_get_read_ptr_p(const AVS_VideoFrame * p, int plane)
+{
+ switch (plane) {
+ case AVS_PLANAR_U: return p->vfb->data + p->offsetU;
+ case AVS_PLANAR_V: return p->vfb->data + p->offsetV;
+ default: return p->vfb->data + p->offset;}
+}
+
+AVSC_INLINE int avs_is_writable(const AVS_VideoFrame * p) {
+ return (p->refcount == 1 && p->vfb->refcount == 1);}
+
+AVSC_INLINE unsigned char* avs_get_write_ptr(const AVS_VideoFrame * p)
+{
+ if (avs_is_writable(p)) {
+ ++p->vfb->sequence_number;
+ return p->vfb->data + p->offset;
+ } else
+ return 0;
+}
+
+AVSC_INLINE unsigned char* avs_get_write_ptr_p(const AVS_VideoFrame * p, int plane)
+{
+ if (plane==AVS_PLANAR_Y && avs_is_writable(p)) {
+ ++p->vfb->sequence_number;
+ return p->vfb->data + p->offset;
+ } else if (plane==AVS_PLANAR_Y) {
+ return 0;
+ } else {
+ switch (plane) {
+ case AVS_PLANAR_U: return p->vfb->data + p->offsetU;
+ case AVS_PLANAR_V: return p->vfb->data + p->offsetV;
+ default: return p->vfb->data + p->offset;
+ }
+ }
+}
+
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(void, avs_release_video_frame)(AVS_VideoFrame *);
+// makes a shallow copy of a video frame
+AVSC_API(AVS_VideoFrame *, avs_copy_video_frame)(AVS_VideoFrame *);
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+#ifndef AVSC_NO_DECLSPEC
+AVSC_INLINE void avs_release_frame(AVS_VideoFrame * f)
+ {avs_release_video_frame(f);}
+AVSC_INLINE AVS_VideoFrame * avs_copy_frame(AVS_VideoFrame * f)
+ {return avs_copy_video_frame(f);}
+#endif
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_Value
+//
+
+// Treat AVS_Value as a fat pointer. That is use avs_copy_value
+// and avs_release_value appropiaty as you would if AVS_Value was
+// a pointer.
+
+// To maintain source code compatibility with future versions of the
+// avisynth_c API don't use the AVS_Value directly. Use the helper
+// functions below.
+
+// AVS_Value is layed out identicly to AVSValue
+typedef struct AVS_Value AVS_Value;
+struct AVS_Value {
+ short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong
+ // for some function e'rror
+ short array_size;
+ union {
+ void * clip; // do not use directly, use avs_take_clip
+ char boolean;
+ int integer;
+ INT64 integer64; // match addition of __int64 to avxplugin.h
+ float floating_pt;
+ const char * string;
+ const AVS_Value * array;
+ } d;
+};
+
+// AVS_Value should be initilized with avs_void.
+// Should also set to avs_void after the value is released
+// with avs_copy_value. Consider it the equalvent of setting
+// a pointer to NULL
+static const AVS_Value avs_void = {'v'};
+
+AVSC_API(void, avs_copy_value)(AVS_Value * dest, AVS_Value src);
+AVSC_API(void, avs_release_value)(AVS_Value);
+
+AVSC_INLINE int avs_defined(AVS_Value v) { return v.type != 'v'; }
+AVSC_INLINE int avs_is_clip(AVS_Value v) { return v.type == 'c'; }
+AVSC_INLINE int avs_is_bool(AVS_Value v) { return v.type == 'b'; }
+AVSC_INLINE int avs_is_int(AVS_Value v) { return v.type == 'i'; }
+AVSC_INLINE int avs_is_float(AVS_Value v) { return v.type == 'f' || v.type == 'i'; }
+AVSC_INLINE int avs_is_string(AVS_Value v) { return v.type == 's'; }
+AVSC_INLINE int avs_is_array(AVS_Value v) { return v.type == 'a'; }
+AVSC_INLINE int avs_is_error(AVS_Value v) { return v.type == 'e'; }
+
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(AVS_Clip *, avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *);
+AVSC_API(void, avs_set_to_clip)(AVS_Value *, AVS_Clip *);
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+AVSC_INLINE int avs_as_bool(AVS_Value v)
+ { return v.d.boolean; }
+AVSC_INLINE int avs_as_int(AVS_Value v)
+ { return v.d.integer; }
+AVSC_INLINE const char * avs_as_string(AVS_Value v)
+ { return avs_is_error(v) || avs_is_string(v) ? v.d.string : 0; }
+AVSC_INLINE double avs_as_float(AVS_Value v)
+ { return avs_is_int(v) ? v.d.integer : v.d.floating_pt; }
+AVSC_INLINE const char * avs_as_error(AVS_Value v)
+ { return avs_is_error(v) ? v.d.string : 0; }
+AVSC_INLINE const AVS_Value * avs_as_array(AVS_Value v)
+ { return v.d.array; }
+AVSC_INLINE int avs_array_size(AVS_Value v)
+ { return avs_is_array(v) ? v.array_size : 1; }
+AVSC_INLINE AVS_Value avs_array_elt(AVS_Value v, int index)
+ { return avs_is_array(v) ? v.d.array[index] : v; }
+
+// only use these functions on am AVS_Value that does not already have
+// an active value. Remember, treat AVS_Value as a fat pointer.
+AVSC_INLINE AVS_Value avs_new_value_bool(int v0)
+ { AVS_Value v = {0}; v.type = 'b'; v.d.boolean = v0 == 0 ? 0 : 1; return v; }
+AVSC_INLINE AVS_Value avs_new_value_int(int v0)
+ { AVS_Value v = {0}; v.type = 'i'; v.d.integer = v0; return v; }
+AVSC_INLINE AVS_Value avs_new_value_string(const char * v0)
+ { AVS_Value v = {0}; v.type = 's'; v.d.string = v0; return v; }
+AVSC_INLINE AVS_Value avs_new_value_float(float v0)
+ { AVS_Value v = {0}; v.type = 'f'; v.d.floating_pt = v0; return v;}
+AVSC_INLINE AVS_Value avs_new_value_error(const char * v0)
+ { AVS_Value v = {0}; v.type = 'e'; v.d.string = v0; return v; }
+#ifndef AVSC_NO_DECLSPEC
+AVSC_INLINE AVS_Value avs_new_value_clip(AVS_Clip * v0)
+ { AVS_Value v = {0}; avs_set_to_clip(&v, v0); return v; }
+#endif
+AVSC_INLINE AVS_Value avs_new_value_array(AVS_Value * v0, int size)
+ { AVS_Value v = {0}; v.type = 'a'; v.d.array = v0; v.array_size = size; return v; }
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_Clip
+//
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(void, avs_release_clip)(AVS_Clip *);
+AVSC_API(AVS_Clip *, avs_copy_clip)(AVS_Clip *);
+
+AVSC_API(const char *, avs_clip_get_error)(AVS_Clip *); // return 0 if no error
+
+AVSC_API(const AVS_VideoInfo *, avs_get_video_info)(AVS_Clip *);
+
+AVSC_API(int, avs_get_version)(AVS_Clip *);
+
+AVSC_API(AVS_VideoFrame *, avs_get_frame)(AVS_Clip *, int n);
+// The returned video frame must be released with avs_release_video_frame
+
+AVSC_API(int, avs_get_parity)(AVS_Clip *, int n);
+// return field parity if field_based, else parity of first field in frame
+
+AVSC_API(int, avs_get_audio)(AVS_Clip *, void * buf,
+ INT64 start, INT64 count);
+// start and count are in samples
+
+AVSC_API(int, avs_set_cache_hints)(AVS_Clip *,
+ int cachehints, size_t frame_range);
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+// This is the callback type used by avs_add_function
+typedef AVS_Value (AVSC_CC * AVS_ApplyFunc)
+ (AVS_ScriptEnvironment *, AVS_Value args, void * user_data);
+
+typedef struct AVS_FilterInfo AVS_FilterInfo;
+struct AVS_FilterInfo
+{
+ // these members should not be modified outside of the AVS_ApplyFunc callback
+ AVS_Clip * child;
+ AVS_VideoInfo vi;
+ AVS_ScriptEnvironment * env;
+ AVS_VideoFrame * (AVSC_CC * get_frame)(AVS_FilterInfo *, int n);
+ int (AVSC_CC * get_parity)(AVS_FilterInfo *, int n);
+ int (AVSC_CC * get_audio)(AVS_FilterInfo *, void * buf,
+ INT64 start, INT64 count);
+ int (AVSC_CC * set_cache_hints)(AVS_FilterInfo *, int cachehints,
+ int frame_range);
+ void (AVSC_CC * free_filter)(AVS_FilterInfo *);
+
+ // Should be set when ever there is an error to report.
+ // It is cleared before any of the above methods are called
+ const char * error;
+ // this is to store whatever and may be modified at will
+ void * user_data;
+};
+
+// Create a new filter
+// fi is set to point to the AVS_FilterInfo so that you can
+// modify it once it is initilized.
+// store_child should generally be set to true. If it is not
+// set than ALL methods (the function pointers) must be defined
+// If it is set than you do not need to worry about freeing the child
+// clip.
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(AVS_Clip *, avs_new_c_filter)(AVS_ScriptEnvironment * e,
+ AVS_FilterInfo * * fi,
+ AVS_Value child, int store_child);
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// AVS_ScriptEnvironment
+//
+
+// For GetCPUFlags. These are backwards-compatible with those in VirtualDub.
+enum {
+ /* slowest CPU to support extension */
+ AVS_CPU_FORCE = 0x01, // N/A
+ AVS_CPU_FPU = 0x02, // 386/486DX
+ AVS_CPU_MMX = 0x04, // P55C, K6, PII
+ AVS_CPU_INTEGER_SSE = 0x08, // PIII, Athlon
+ AVS_CPU_SSE = 0x10, // PIII, Athlon XP/MP
+ AVS_CPU_SSE2 = 0x20, // PIV, Hammer
+ AVS_CPU_3DNOW = 0x40, // K6-2
+ AVS_CPU_3DNOW_EXT = 0x80, // Athlon
+ AVS_CPU_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2,
+ // which only Hammer will have anyway)
+};
+
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(const char *, avs_get_error)(AVS_ScriptEnvironment *); // return 0 if no error
+
+AVSC_API(long, avs_get_cpu_flags)(AVS_ScriptEnvironment *);
+AVSC_API(int, avs_check_version)(AVS_ScriptEnvironment *, int version);
+
+AVSC_API(char *, avs_save_string)(AVS_ScriptEnvironment *, const char* s, int length);
+AVSC_API(char *, avs_sprintf)(AVS_ScriptEnvironment *, const char * fmt, ...);
+
+AVSC_API(char *, avs_vsprintf)(AVS_ScriptEnvironment *, const char * fmt, va_list val);
+ // note: val is really a va_list; I hope everyone typedefs va_list to a pointer
+
+AVSC_API(int, avs_add_function)(AVS_ScriptEnvironment *,
+ const char * name, const char * params,
+ AVS_ApplyFunc apply, void * user_data);
+
+AVSC_API(int, avs_function_exists)(AVS_ScriptEnvironment *, const char * name);
+
+AVSC_API(AVS_Value, avs_invoke)(AVS_ScriptEnvironment *, const char * name,
+ AVS_Value args, const char** arg_names);
+// The returned value must be be released with avs_release_value
+
+AVSC_API(AVS_Value, avs_get_var)(AVS_ScriptEnvironment *, const char* name);
+// The returned value must be be released with avs_release_value
+
+AVSC_API(int, avs_set_var)(AVS_ScriptEnvironment *, const char* name, AVS_Value val);
+
+AVSC_API(int, avs_set_global_var)(AVS_ScriptEnvironment *, const char* name, const AVS_Value val);
+
+//void avs_push_context(AVS_ScriptEnvironment *, int level=0);
+//void avs_pop_context(AVS_ScriptEnvironment *);
+
+AVSC_API(AVS_VideoFrame *, avs_new_video_frame_a)(AVS_ScriptEnvironment *,
+ const AVS_VideoInfo * vi, int align);
+// align should be at least 16
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+#ifndef AVSC_NO_DECLSPEC
+AVSC_INLINE
+AVS_VideoFrame * avs_new_video_frame(AVS_ScriptEnvironment * env,
+ const AVS_VideoInfo * vi)
+ {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);}
+
+AVSC_INLINE
+AVS_VideoFrame * avs_new_frame(AVS_ScriptEnvironment * env,
+ const AVS_VideoInfo * vi)
+ {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);}
+#endif
+
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(int, avs_make_writable)(AVS_ScriptEnvironment *, AVS_VideoFrame * * pvf);
+
+AVSC_API(void, avs_bit_blt)(AVS_ScriptEnvironment *, unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height);
+
+typedef void (AVSC_CC *AVS_ShutdownFunc)(void* user_data, AVS_ScriptEnvironment * env);
+AVSC_API(void, avs_at_exit)(AVS_ScriptEnvironment *, AVS_ShutdownFunc function, void * user_data);
+
+AVSC_API(AVS_VideoFrame *, avs_subframe)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height);
+// The returned video frame must be be released
+
+AVSC_API(int, avs_set_memory_max)(AVS_ScriptEnvironment *, int mem);
+
+AVSC_API(int, avs_set_working_dir)(AVS_ScriptEnvironment *, const char * newdir);
+
+// avisynth.dll exports this; it's a way to use it as a library, without
+// writing an AVS script or without going through AVIFile.
+AVSC_API(AVS_ScriptEnvironment *, avs_create_script_environment)(int version);
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+// this symbol is the entry point for the plugin and must
+// be defined
+AVSC_EXPORT
+const char * AVSC_CC avisynth_c_plugin_init(AVS_ScriptEnvironment* env);
+
+
+#if defined __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+AVSC_API(void, avs_delete_script_environment)(AVS_ScriptEnvironment *);
+
+
+AVSC_API(AVS_VideoFrame *, avs_subframe_planar)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV);
+// The returned video frame must be be released
+#if defined __cplusplus
+}
+#endif // __cplusplus
+
+#endif //__AVXSYNTH_C__
diff --git a/compat/avisynth/windowsPorts/basicDataTypeConversions.h b/compat/avisynth/windowsPorts/basicDataTypeConversions.h
new file mode 100644
index 0000000000..ff367d5a2a
--- /dev/null
+++ b/compat/avisynth/windowsPorts/basicDataTypeConversions.h
@@ -0,0 +1,85 @@
+#ifndef __DATA_TYPE_CONVERSIONS_H__
+#define __DATA_TYPE_CONVERSIONS_H__
+
+#include <stdint.h>
+#include <wchar.h>
+
+#ifdef __cplusplus
+namespace avxsynth {
+#endif // __cplusplus
+
+typedef int64_t __int64;
+typedef int32_t __int32;
+#ifdef __cplusplus
+typedef bool BOOL;
+#else
+typedef uint32_t BOOL;
+#endif // __cplusplus
+typedef void* HMODULE;
+typedef void* LPVOID;
+typedef void* PVOID;
+typedef PVOID HANDLE;
+typedef HANDLE HWND;
+typedef HANDLE HINSTANCE;
+typedef void* HDC;
+typedef void* HBITMAP;
+typedef void* HICON;
+typedef void* HFONT;
+typedef void* HGDIOBJ;
+typedef void* HBRUSH;
+typedef void* HMMIO;
+typedef void* HACMSTREAM;
+typedef void* HACMDRIVER;
+typedef void* HIC;
+typedef void* HACMOBJ;
+typedef HACMSTREAM* LPHACMSTREAM;
+typedef void* HACMDRIVERID;
+typedef void* LPHACMDRIVER;
+typedef unsigned char BYTE;
+typedef BYTE* LPBYTE;
+typedef char TCHAR;
+typedef TCHAR* LPTSTR;
+typedef const TCHAR* LPCTSTR;
+typedef char* LPSTR;
+typedef LPSTR LPOLESTR;
+typedef const char* LPCSTR;
+typedef LPCSTR LPCOLESTR;
+typedef wchar_t WCHAR;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef UINT MMRESULT;
+typedef uint32_t DWORD;
+typedef DWORD COLORREF;
+typedef DWORD FOURCC;
+typedef DWORD HRESULT;
+typedef DWORD* LPDWORD;
+typedef DWORD* DWORD_PTR;
+typedef int32_t LONG;
+typedef int32_t* LONG_PTR;
+typedef LONG_PTR LRESULT;
+typedef uint32_t ULONG;
+typedef uint32_t* ULONG_PTR;
+//typedef __int64_t intptr_t;
+typedef uint64_t _fsize_t;
+
+
+//
+// Structures
+//
+
+typedef struct _GUID {
+ DWORD Data1;
+ WORD Data2;
+ WORD Data3;
+ BYTE Data4[8];
+} GUID;
+
+typedef GUID REFIID;
+typedef GUID CLSID;
+typedef CLSID* LPCLSID;
+typedef GUID IID;
+
+#ifdef __cplusplus
+}; // namespace avxsynth
+#endif // __cplusplus
+#endif // __DATA_TYPE_CONVERSIONS_H__
diff --git a/compat/avisynth/windowsPorts/windows2linux.h b/compat/avisynth/windowsPorts/windows2linux.h
new file mode 100644
index 0000000000..7cf4600266
--- /dev/null
+++ b/compat/avisynth/windowsPorts/windows2linux.h
@@ -0,0 +1,77 @@
+#ifndef __WINDOWS2LINUX_H__
+#define __WINDOWS2LINUX_H__
+
+/*
+ * LINUX SPECIFIC DEFINITIONS
+*/
+//
+// Data types conversions
+//
+#include <stdlib.h>
+#include <string.h>
+#include "basicDataTypeConversions.h"
+
+#ifdef __cplusplus
+namespace avxsynth {
+#endif // __cplusplus
+//
+// purposefully define the following MSFT definitions
+// to mean nothing (as they do not mean anything on Linux)
+//
+#define __stdcall
+#define __cdecl
+#define noreturn
+#define __declspec(x)
+#define STDAPI extern "C" HRESULT
+#define STDMETHODIMP HRESULT __stdcall
+#define STDMETHODIMP_(x) x __stdcall
+
+#define STDMETHOD(x) virtual HRESULT x
+#define STDMETHOD_(a, x) virtual a x
+
+#ifndef TRUE
+#define TRUE true
+#endif
+
+#ifndef FALSE
+#define FALSE false
+#endif
+
+#define S_OK (0x00000000)
+#define S_FALSE (0x00000001)
+#define E_NOINTERFACE (0X80004002)
+#define E_POINTER (0x80004003)
+#define E_FAIL (0x80004005)
+#define E_OUTOFMEMORY (0x8007000E)
+
+#define INVALID_HANDLE_VALUE ((HANDLE)((LONG_PTR)-1))
+#define FAILED(hr) ((hr) & 0x80000000)
+#define SUCCEEDED(hr) (!FAILED(hr))
+
+
+//
+// Functions
+//
+#define MAKEDWORD(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+#define MAKEWORD(a,b) (((a) << 8) | (b))
+
+#define lstrlen strlen
+#define lstrcpy strcpy
+#define lstrcmpi strcasecmp
+#define _stricmp strcasecmp
+#define InterlockedIncrement(x) __sync_fetch_and_add((x), 1)
+#define InterlockedDecrement(x) __sync_fetch_and_sub((x), 1)
+// Windows uses (new, old) ordering but GCC has (old, new)
+#define InterlockedCompareExchange(x,y,z) __sync_val_compare_and_swap(x,z,y)
+
+#define UInt32x32To64(a, b) ( (uint64_t) ( ((uint64_t)((uint32_t)(a))) * ((uint32_t)(b)) ) )
+#define Int64ShrlMod32(a, b) ( (uint64_t) ( (uint64_t)(a) >> (b) ) )
+#define Int32x32To64(a, b) ((__int64)(((__int64)((long)(a))) * ((long)(b))))
+
+#define MulDiv(nNumber, nNumerator, nDenominator) (int32_t) (((int64_t) (nNumber) * (int64_t) (nNumerator) + (int64_t) ((nDenominator)/2)) / (int64_t) (nDenominator))
+
+#ifdef __cplusplus
+}; // namespace avxsynth
+#endif // __cplusplus
+
+#endif // __WINDOWS2LINUX_H__
diff --git a/compat/float/float.h b/compat/float/float.h
index c69f728e32..1f0d3ab4b5 100644
--- a/compat/float/float.h
+++ b/compat/float/float.h
@@ -1,20 +1,20 @@
/*
* Work around broken floating point limits on some systems.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/compat/float/limits.h b/compat/float/limits.h
index 9150bc8134..7ea374a8bc 100644
--- a/compat/float/limits.h
+++ b/compat/float/limits.h
@@ -1,20 +1,20 @@
/*
* Work around broken floating point limits on some systems.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/compat/getopt.c b/compat/getopt.c
index b7adf60e2f..41a641f7c8 100644
--- a/compat/getopt.c
+++ b/compat/getopt.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,7 +44,7 @@ static int getopt(int argc, char *argv[], char *opts)
int c;
char *cp;
- if (sp == 1)
+ if (sp == 1) {
if (optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return EOF;
@@ -52,6 +52,7 @@ static int getopt(int argc, char *argv[], char *opts)
optind++;
return EOF;
}
+ }
optopt = c = argv[optind][sp];
if (c == ':' || !(cp = strchr(opts, c))) {
fprintf(stderr, ": illegal option -- %c\n", c);
diff --git a/compat/msvcrt/snprintf.c b/compat/msvcrt/snprintf.c
index 0af7b54353..c64653fe82 100644
--- a/compat/msvcrt/snprintf.c
+++ b/compat/msvcrt/snprintf.c
@@ -2,20 +2,20 @@
* C99-compatible snprintf() and vsnprintf() implementations
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,10 +24,11 @@
#include <limits.h>
#include <string.h>
+#include "compat/va_copy.h"
#include "libavutil/error.h"
-#if !defined(va_copy) && defined(_MSC_VER)
-#define va_copy(dst, src) ((dst) = (src))
+#if defined(__MINGW32__)
+#define EOVERFLOW EFBIG
#endif
int avpriv_snprintf(char *s, size_t n, const char *fmt, ...)
diff --git a/compat/msvcrt/snprintf.h b/compat/msvcrt/snprintf.h
new file mode 100644
index 0000000000..f02113c5a2
--- /dev/null
+++ b/compat/msvcrt/snprintf.h
@@ -0,0 +1,38 @@
+/*
+ * C99-compatible snprintf() and vsnprintf() implementations
+ * Copyright (c) 2012 Ronald S. Bultje <rsbultje@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
+ */
+
+#ifndef COMPAT_SNPRINTF_H
+#define COMPAT_SNPRINTF_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+int avpriv_snprintf(char *s, size_t n, const char *fmt, ...);
+int avpriv_vsnprintf(char *s, size_t n, const char *fmt, va_list ap);
+
+#undef snprintf
+#undef _snprintf
+#undef vsnprintf
+#define snprintf avpriv_snprintf
+#define _snprintf avpriv_snprintf
+#define vsnprintf avpriv_vsnprintf
+
+#endif /* COMPAT_SNPRINTF_H */
diff --git a/compat/os2threads.h b/compat/os2threads.h
new file mode 100644
index 0000000000..441ac43710
--- /dev/null
+++ b/compat/os2threads.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2011 KO Myung-Hun <komh@chollian.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * os2threads to pthreads wrapper
+ */
+
+#ifndef AVCODEC_OS2PTHREADS_H
+#define AVCODEC_OS2PTHREADS_H
+
+#define INCL_DOS
+#include <os2.h>
+
+#undef __STRICT_ANSI__ /* for _beginthread() */
+#include <stdlib.h>
+
+#include "libavutil/mem.h"
+
+typedef TID pthread_t;
+typedef void pthread_attr_t;
+
+typedef HMTX pthread_mutex_t;
+typedef void pthread_mutexattr_t;
+
+typedef struct {
+ HEV event_sem;
+ int wait_count;
+} pthread_cond_t;
+
+typedef void pthread_condattr_t;
+
+struct thread_arg {
+ void *(*start_routine)(void *);
+ void *arg;
+};
+
+static void thread_entry(void *arg)
+{
+ struct thread_arg *thread_arg = arg;
+
+ thread_arg->start_routine(thread_arg->arg);
+
+ av_free(thread_arg);
+}
+
+static av_always_inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
+{
+ struct thread_arg *thread_arg;
+
+ thread_arg = av_mallocz(sizeof(struct thread_arg));
+
+ thread_arg->start_routine = start_routine;
+ thread_arg->arg = arg;
+
+ *thread = _beginthread(thread_entry, NULL, 256 * 1024, thread_arg);
+
+ return 0;
+}
+
+static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
+{
+ DosWaitThread((PTID)&thread, DCWW_WAIT);
+
+ return 0;
+}
+
+static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
+{
+ DosCreateMutexSem(NULL, (PHMTX)mutex, 0, FALSE);
+
+ return 0;
+}
+
+static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ DosCloseMutexSem(*(PHMTX)mutex);
+
+ return 0;
+}
+
+static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ DosRequestMutexSem(*(PHMTX)mutex, SEM_INDEFINITE_WAIT);
+
+ return 0;
+}
+
+static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ DosReleaseMutexSem(*(PHMTX)mutex);
+
+ return 0;
+}
+
+static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+ DosCreateEventSem(NULL, &cond->event_sem, DCE_POSTONE, FALSE);
+
+ cond->wait_count = 0;
+
+ return 0;
+}
+
+static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ DosCloseEventSem(cond->event_sem);
+
+ return 0;
+}
+
+static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
+{
+ if (cond->wait_count > 0) {
+ DosPostEventSem(cond->event_sem);
+
+ cond->wait_count--;
+ }
+
+ return 0;
+}
+
+static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ while (cond->wait_count > 0) {
+ DosPostEventSem(cond->event_sem);
+
+ cond->wait_count--;
+ }
+
+ return 0;
+}
+
+static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ cond->wait_count++;
+
+ pthread_mutex_unlock(mutex);
+
+ DosWaitEventSem(cond->event_sem, SEM_INDEFINITE_WAIT);
+
+ pthread_mutex_lock(mutex);
+
+ return 0;
+}
+
+#endif /* AVCODEC_OS2PTHREADS_H */
diff --git a/compat/plan9/main.c b/compat/plan9/main.c
index 97d70678a6..d46f96d170 100644
--- a/compat/plan9/main.c
+++ b/compat/plan9/main.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/compat/strtod.c b/compat/strtod.c
index 258909f409..3a9452eac2 100644
--- a/compat/strtod.c
+++ b/compat/strtod.c
@@ -2,20 +2,20 @@
* C99-compatible strtod() implementation
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/compat/tms470/math.h b/compat/tms470/math.h
index b686d4d8a9..6234cc597b 100644
--- a/compat/tms470/math.h
+++ b/compat/tms470/math.h
@@ -1,23 +1,23 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef LIBAV_COMPAT_TMS470_MATH_H
-#define LIBAV_COMPAT_TMS470_MATH_H
+#ifndef FFMPEG_COMPAT_TMS470_MATH_H
+#define FFMPEG_COMPAT_TMS470_MATH_H
#include_next <math.h>
@@ -27,4 +27,4 @@
#define INFINITY (*(const float*)((const unsigned []){ 0x7f800000 }))
#define NAN (*(const float*)((const unsigned []){ 0x7fc00000 }))
-#endif /* LIBAV_COMPAT_TMS470_MATH_H */
+#endif /* FFMPEG_COMPAT_TMS470_MATH_H */
diff --git a/compat/va_copy.h b/compat/va_copy.h
new file mode 100644
index 0000000000..3cb5ebee33
--- /dev/null
+++ b/compat/va_copy.h
@@ -0,0 +1,29 @@
+/*
+ * MSVC Compatible va_copy macro
+ * Copyright (c) 2012 Derek Buitenhuis
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdarg.h>
+
+#if !defined(va_copy) && defined(_MSC_VER)
+#define va_copy(dst, src) ((dst) = (src))
+#endif
+#if !defined(va_copy) && defined(__GNUC__) && __GNUC__ < 3
+#define va_copy(dst, src) __va_copy(dst, src)
+#endif
diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h
index 3748289809..87e816ff6e 100644
--- a/compat/w32pthreads.h
+++ b/compat/w32pthreads.h
@@ -4,20 +4,20 @@
* Authors: Steven Walters <kemuri9@gmail.com>
* Pegasys Inc. <http://www.pegasys-inc.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,8 @@
* w32threads to pthreads wrapper
*/
-#ifndef LIBAV_COMPAT_W32PTHREADS_H
-#define LIBAV_COMPAT_W32PTHREADS_H
+#ifndef FFMPEG_COMPAT_W32PTHREADS_H
+#define FFMPEG_COMPAT_W32PTHREADS_H
/* Build up a pthread-like API using underlying Windows API. Have only static
* methods so as to not conflict with a potentially linked in pthread-win32
@@ -40,6 +40,7 @@
#include <process.h>
#include "libavutil/attributes.h"
+#include "libavutil/common.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
@@ -118,9 +119,10 @@ static inline int pthread_mutex_unlock(pthread_mutex_t *m)
}
#if _WIN32_WINNT >= 0x0600
-static inline void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
+static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
{
InitializeConditionVariable(cond);
+ return 0;
}
/* native condition variables do not destroy */
@@ -164,28 +166,29 @@ static void (WINAPI *cond_signal)(pthread_cond_t *cond);
static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex,
DWORD milliseconds);
-static av_unused void pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
+static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
{
win32_cond_t *win32_cond = NULL;
if (cond_init) {
cond_init(cond);
- return;
+ return 0;
}
/* non native condition variables */
win32_cond = av_mallocz(sizeof(win32_cond_t));
if (!win32_cond)
- return;
+ return ENOMEM;
cond->Ptr = win32_cond;
win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
if (!win32_cond->semaphore)
- return;
+ return ENOMEM;
win32_cond->waiters_done = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!win32_cond->waiters_done)
- return;
+ return ENOMEM;
pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL);
pthread_mutex_init(&win32_cond->mtx_broadcast, NULL);
+ return 0;
}
static av_unused void pthread_cond_destroy(pthread_cond_t *cond)
@@ -310,4 +313,4 @@ static av_unused void w32thread_init(void)
}
-#endif /* LIBAV_COMPAT_W32PTHREADS_H */
+#endif /* FFMPEG_COMPAT_W32PTHREADS_H */
diff --git a/configure b/configure
index 18280b90a1..f6c8e691c2 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Libav configure script
+# FFmpeg configure script
#
# Copyright (c) 2000-2002 Fabrice Bellard
# Copyright (c) 2005-2008 Diego Biurrun
@@ -44,9 +44,9 @@ if test "$E1" != 0 || test "$E2" = 0; then
echo "No compatible shell script interpreter found."
echo "This configure script requires a POSIX-compatible shell"
echo "such as bash or ksh."
- echo "THIS IS NOT A BUG IN LIBAV, DO NOT REPORT IT AS SUCH."
+ echo "THIS IS NOT A BUG IN FFMPEG, DO NOT REPORT IT AS SUCH."
echo "Instead, install a working POSIX-compatible shell."
- echo "Disabling this configure test will create a broken Libav."
+ echo "Disabling this configure test will create a broken FFmpeg."
if test "$BASH_VERSION" = '2.04.0(1)-release'; then
echo "This bash version ($BASH_VERSION) is broken on your platform."
echo "Upgrade to a later version if available."
@@ -78,15 +78,18 @@ Help options:
Standard options:
--logfile=FILE log tests and output to FILE [config.log]
--disable-logging do not log configure debug information
+ --fatal-warnings fail if any configure warning is generated
--prefix=PREFIX install in PREFIX [$prefix]
--bindir=DIR install binaries in DIR [PREFIX/bin]
- --datadir=DIR install data files in DIR [PREFIX/share/avconv]
- --docdir=DIR install documentation in DIR [PREFIX/share/doc/libav]
+ --datadir=DIR install data files in DIR [PREFIX/share/ffmpeg]
+ --docdir=DIR install documentation in DIR [PREFIX/share/doc/ffmpeg]
--libdir=DIR install libs in DIR [PREFIX/lib]
- --shlibdir=DIR install shared libs in DIR [PREFIX/lib]
+ --shlibdir=DIR install shared libs in DIR [LIBDIR]
--incdir=DIR install includes in DIR [PREFIX/include]
--mandir=DIR install man page in DIR [PREFIX/share/man]
- --enable-rpath use rpath when linking programs [USE WITH CARE]
+ --enable-rpath use rpath to allow installing libraries in paths
+ not part of the dynamic linker search path
+ use rpath when linking programs [USE WITH CARE]
Licensing options:
--enable-gpl allow use of GPL code, the resulting libs
@@ -99,31 +102,43 @@ Configuration options:
--disable-static do not build static libraries [no]
--enable-shared build shared libraries [no]
--enable-small optimize for size instead of speed
- --enable-runtime-cpudetect detect cpu capabilities at runtime (bigger binary)
+ --disable-runtime-cpudetect disable detecting cpu capabilities at runtime (smaller binary)
--enable-gray enable full grayscale support (slower color)
--disable-swscale-alpha disable alpha channel support in swscale
--disable-all disable building components, libraries and programs
+ --enable-incompatible-libav-abi enable incompatible Libav fork ABI [no]
+ --enable-raise-major increase major version numbers in sonames [no]
Program options:
--disable-programs do not build command line programs
- --disable-avconv disable avconv build
- --disable-avplay disable avplay build
- --disable-avprobe disable avprobe build
- --disable-avserver deprecated, does nothing
+ --disable-ffmpeg disable ffmpeg build
+ --disable-ffplay disable ffplay build
+ --disable-ffprobe disable ffprobe build
+ --disable-ffserver disable ffserver build
-Component options:
+Documentation options:
--disable-doc do not build documentation
+ --disable-htmlpages do not build HTML documentation pages
+ --disable-manpages do not build man documentation pages
+ --disable-podpages do not build POD documentation pages
+ --disable-txtpages do not build text documentation pages
+
+Component options:
--disable-avdevice disable libavdevice build
--disable-avcodec disable libavcodec build
--disable-avformat disable libavformat build
--disable-avutil disable libavutil build
+ --disable-swresample disable libswresample build
--disable-swscale disable libswscale build
- --disable-avfilter disable video filter support [no]
- --disable-avresample disable libavresample build [no]
- --disable-pthreads disable pthreads [auto]
- --disable-w32threads disable Win32 threads [auto]
+ --disable-postproc disable libpostproc build
+ --disable-avfilter disable libavfilter build
+ --enable-avresample enable libavresample build [no]
+ --disable-pthreads disable pthreads [autodetect]
+ --disable-w32threads disable Win32 threads [autodetect]
+ --disable-os2threads disable OS/2 threads [autodetect]
--disable-network disable network support [no]
--disable-dct disable DCT code
+ --disable-dwt disable DWT code
--disable-error-resilience disable error resilience code
--disable-lsp disable LSP code
--disable-lzo disable LZO decoder code
@@ -131,13 +146,14 @@ Component options:
--disable-rdft disable RDFT code
--disable-fft disable FFT code
--disable-faan disable floating point AAN (I)DCT code
+ --disable-pixelutils disable pixel utils in libavutil
Hardware accelerators:
--enable-d3d11va enable D3D11VA code
- --enable-dxva2 enable DXVA2 code
- --enable-vaapi enable VAAPI code
- --enable-vda enable VDA code
- --enable-vdpau enable VDPAU code
+ --disable-dxva2 disable DXVA2 code [autodetect]
+ --disable-vaapi disable VAAPI code [autodetect]
+ --disable-vda disable VDA code [autodetect]
+ --disable-vdpau disable VDPAU code [autodetect]
Individual component options:
--disable-everything disable all components listed below
@@ -178,21 +194,38 @@ Individual component options:
External library support:
--enable-avisynth enable reading of AviSynth script files [no]
- --enable-bzlib enable bzlib [autodetect]
- --enable-frei0r enable frei0r video filtering
- --enable-gnutls enable gnutls [no]
+ --disable-bzlib disable bzlib [autodetect]
+ --enable-fontconfig enable fontconfig, useful for drawtext filter [no]
+ --enable-frei0r enable frei0r video filtering [no]
+ --enable-gnutls enable gnutls, needed for https support
+ if openssl is not used [no]
+ --disable-iconv disable iconv [autodetect]
+ --enable-ladspa enable LADSPA audio filtering [no]
+ --enable-libaacplus enable AAC+ encoding via libaacplus [no]
+ --enable-libass enable libass subtitles rendering,
+ needed for subtitles and ass filter [no]
+ --enable-libbluray enable BluRay reading using libbluray [no]
--enable-libbs2b enable bs2b DSP library [no]
- --enable-libcdio enable audio CD grabbing with libcdio
+ --enable-libcaca enable textual display using libcaca [no]
+ --enable-libcelt enable CELT decoding via libcelt [no]
+ --enable-libcdio enable audio CD grabbing with libcdio [no]
--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394
and libraw1394 [no]
--enable-libdcadec enable DCA decoding via libdcadec [no]
--enable-libfaac enable AAC encoding via libfaac [no]
--enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no]
- --enable-libfreetype enable libfreetype [no]
+ --enable-libflite enable flite (voice synthesis) support via libflite [no]
+ --enable-libfreetype enable libfreetype, needed for drawtext filter [no]
+ --enable-libfribidi enable libfribidi, improves drawtext filter [no]
+ --enable-libgme enable Game Music Emu via libgme [no]
--enable-libgsm enable GSM de/encoding via libgsm [no]
+ --enable-libiec61883 enable iec61883 via libiec61883 [no]
--enable-libilbc enable iLBC de/encoding via libilbc [no]
--enable-libmfx enable HW acceleration through libmfx
+ --enable-libmodplug enable ModPlug via libmodplug [no]
--enable-libmp3lame enable MP3 encoding via libmp3lame [no]
+ --enable-libnut enable NUT (de)muxing via libnut,
+ native (de)muxer exists [no]
--enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
--enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
--enable-libopencv enable video filtering via libopencv [no]
@@ -200,35 +233,58 @@ External library support:
--enable-libopenjpeg enable JPEG 2000 de/encoding via OpenJPEG [no]
--enable-libopus enable Opus de/encoding via libopus [no]
--enable-libpulse enable Pulseaudio input via libpulse [no]
+ --enable-libquvi enable quvi input via libquvi [no]
--enable-librtmp enable RTMP[E] support via librtmp [no]
--enable-libschroedinger enable Dirac de/encoding via libschroedinger [no]
+ --enable-libshine enable fixed-point MP3 encoding via libshine [no]
+ --enable-libsmbclient enable Samba protocol via libsmbclient [no]
+ --enable-libsoxr enable Include libsoxr resampling [no]
--enable-libspeex enable Speex de/encoding via libspeex [no]
+ --enable-libssh enable SFTP protocol via libssh [no]
+ --enable-libstagefright-h264 enable H.264 decoding via libstagefright [no]
--enable-libtheora enable Theora encoding via libtheora [no]
--enable-libtwolame enable MP2 encoding via libtwolame [no]
+ --enable-libutvideo enable Ut Video encoding and decoding via libutvideo [no]
+ --enable-libv4l2 enable libv4l2/v4l-utils [no]
+ --enable-libvidstab enable video stabilization using vid.stab [no]
--enable-libvo-aacenc enable AAC encoding via libvo-aacenc [no]
--enable-libvo-amrwbenc enable AMR-WB encoding via libvo-amrwbenc [no]
- --enable-libvorbis enable Vorbis encoding via libvorbis [no]
+ --enable-libvorbis enable Vorbis en/decoding via libvorbis,
+ native implementation exists [no]
--enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no]
--enable-libwavpack enable wavpack encoding via libwavpack [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]
--enable-libxavs enable AVS encoding via xavs [no]
- --enable-libxcb enable X11 grabbing using XCB [no]
- --enable-libxcb-shm enable X11 grabbing shm communication [auto]
- --enable-libxcb-xfixes enable X11 grabbing mouse rendering [auto]
+ --enable-libxcb enable X11 grabbing using XCB [autodetect]
+ --enable-libxcb-shm enable X11 grabbing shm communication [autodetect]
+ --enable-libxcb-xfixes enable X11 grabbing mouse rendering [autodetect]
+ --enable-libxcb-shape enable X11 grabbing shape rendering [autodetect]
--enable-libxvid enable Xvid encoding via xvidcore,
native MPEG-4/Xvid encoder exists [no]
+ --enable-libzmq enable message passing via libzmq [no]
+ --enable-libzvbi enable teletext support via libzvbi [no]
+ --disable-lzma disable lzma [autodetect]
+ --enable-decklink enable Blackmagick DeckLink I/O support [no]
--enable-mmal enable decoding via MMAL [no]
- --enable-openssl enable openssl [no]
+ --enable-nvenc enable NVIDIA NVENC support [no]
+ --enable-openal enable OpenAL 1.1 capture support [no]
+ --enable-opencl enable OpenCL code
+ --enable-opengl enable OpenGL rendering [no]
+ --enable-openssl enable openssl, needed for https support
+ if gnutls is not used [no]
+ --disable-sdl disable sdl [autodetect]
--enable-x11grab enable X11 grabbing (legacy) [no]
- --enable-zlib enable zlib [autodetect]
+ --disable-xlib disable xlib [autodetect]
+ --disable-zlib disable zlib [autodetect]
Toolchain options:
--arch=ARCH select architecture [$arch]
--cpu=CPU select the minimum required CPU (affects
instruction selection, may crash on older CPUs)
--cross-prefix=PREFIX use PREFIX for compilation tools [$cross_prefix]
+ --progs-suffix=SUFFIX program name suffix []
--enable-cross-compile assume a cross-compiler is used
--sysroot=PATH root of cross-build tree
--sysinclude=PATH location of cross-build system headers
@@ -236,15 +292,21 @@ Toolchain options:
--target-exec=CMD command to run executables on target
--target-path=DIR path to view of build directory on target
--target-samples=DIR path to samples directory on target
+ --tempprefix=PATH force fixed dir/prefix instead of mktemp for checks
--toolchain=NAME set tool defaults according to NAME
- --nm=NM use nm tool
+ --nm=NM use nm tool NM [$nm_default]
--ar=AR use archive tool AR [$ar_default]
--as=AS use assembler AS [$as_default]
+ --windres=WINDRES use windows resource compiler WINDRES [$windres_default]
+ --yasmexe=EXE use yasm-compatible assembler EXE [$yasmexe_default]
--cc=CC use C compiler CC [$cc_default]
+ --cxx=CXX use C compiler CXX [$cxx_default]
--dep-cc=DEPCC use dependency generator DEPCC [$cc_default]
- --ld=LD use linker LD
+ --ld=LD use linker LD [$ld_default]
--pkg-config=PKGCONFIG use pkg-config tool PKGCONFIG [$pkg_config_default]
--pkg-config-flags=FLAGS pass additional flags to pkgconf []
+ --ranlib=RANLIB use ranlib RANLIB [$ranlib_default]
+ --doxygen=DOXYGEN use DOXYGEN to generate API doc [$doxygen_default]
--host-cc=HOSTCC use host C compiler HOSTCC
--host-cflags=HCFLAGS use HCFLAGS when compiling for host
--host-cppflags=HCPPFLAGS use HCPPFLAGS when compiling for host
@@ -253,6 +315,7 @@ Toolchain options:
--host-libs=HLIBS use libs HLIBS when linking for host
--host-os=OS compiler host OS [$target_os]
--extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS]
+ --extra-cxxflags=ECFLAGS add ECFLAGS to CXXFLAGS [$CXXFLAGS]
--extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS]
--extra-ldexeflags=ELDFLAGS add ELDFLAGS to LDEXEFLAGS [$LDEXEFLAGS]
--extra-libs=ELIBS add ELIBS [$ELIBS]
@@ -271,7 +334,7 @@ Advanced options (experts only):
disable buffer boundary checking in bitreaders
(faster, but may crash)
--enable-memalign-hack emulate memalign, interferes with memory debuggers
- --enable-sram allow use of on-chip SRAM
+ --sws-max-filter-size=N the max filter size swscale uses [$sws_max_filter_size_default]
Optimization options (experts only):
--disable-asm disable all assembly optimizations
@@ -298,14 +361,30 @@ Optimization options (experts only):
--disable-neon disable NEON optimizations
--disable-inline-asm disable use of inline assembly
--disable-yasm disable use of nasm/yasm assembly
-
-Developer options (useful when working on Libav itself):
+ --disable-mips32r5 disable MIPS32R5 optimizations
+ --disable-mips64r6 disable MIPS64R6 optimizations
+ --disable-mipsdspr1 disable MIPS DSP ASE R1 optimizations
+ --disable-mipsdspr2 disable MIPS DSP ASE R2 optimizations
+ --disable-msa disable MSA optimizations
+ --disable-mipsfpu disable floating point MIPS optimizations
+ --disable-loongson3 disable Loongson-3 SIMD optimizations
+ --disable-fast-unaligned consider unaligned accesses slow
+
+Developer options (useful when working on FFmpeg itself):
--disable-debug disable debugging symbols
--enable-debug=LEVEL set the debug level [$debuglevel]
--disable-optimizations disable compiler optimizations
--enable-extra-warnings enable more compiler warnings
+ --disable-stripping disable stripping of executables and shared libraries
+ --assert-level=level 0(default), 1 or 2, amount of assertion testing,
+ 2 causes a slowdown at runtime.
+ --enable-memory-poisoning fill heap uninitialized allocated space with arbitrary data
+ --valgrind=VALGRIND run "make fate" tests through valgrind to detect memory
+ leaks and errors, using the specified valgrind binary.
+ Cannot be combined with --target-exec
+ --enable-ftrapv Trap arithmetic overflows
--samples=PATH location of test samples for FATE, if not set use
- \$LIBAV_SAMPLES at make invocation time.
+ \$FATE_SAMPLES at make invocation time.
--enable-neon-clobber-test check NEON registers for clobbering (should be
used only for debugging purposes)
--enable-xmm-clobber-test check XMM registers for clobbering (Win64-only;
@@ -354,7 +433,7 @@ die(){
If you think configure made a mistake, make sure you are using the latest
version from Git. If the latest version fails, report the problem to the
-libav-tools@libav.org mailing list or IRC #libav on irc.freenode.net.
+ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.freenode.net.
EOF
if disabled logging; then
cat <<EOF
@@ -364,7 +443,7 @@ EOF
else
cat <<EOF
Include the log file "$logfile" produced by configure as this will help
-solving the problem.
+solve the problem.
EOF
fi
exit 1
@@ -390,7 +469,7 @@ sh_quote(){
}
cleanws(){
- echo "$@" | sed 's/^ *//;s/ */ /g;s/ *$//'
+ echo "$@" | sed 's/^ *//;s/ */ /g;s/ *$//;s/\\r//g'
}
filter(){
@@ -642,6 +721,12 @@ print_config(){
} else if (file ~ /\\.mak\$/) {
n = -v ? \"\" : \"!\";
printf(\"%s%s=yes\\n\", n, c) >>file;
+ } else if (file ~ /\\.texi\$/) {
+ pre = -v ? \"\" : \"@c \";
+ yesno = \$2;
+ c2 = tolower(c);
+ gsub(/_/, \"-\", c2);
+ printf(\"%s@set %s %s\\n\", pre, c2, yesno) >>file;
}
}
}"
@@ -684,6 +769,10 @@ add_cflags(){
append CFLAGS $($cflags_filter "$@")
}
+add_cxxflags(){
+ append CXXFLAGS $($cflags_filter "$@")
+}
+
add_asflags(){
append ASFLAGS $($asflags_filter "$@")
}
@@ -697,7 +786,7 @@ add_ldexeflags(){
}
add_stripflags(){
- append STRIPFLAGS "$@"
+ append ASMSTRIPFLAGS "$@"
}
add_extralibs(){
@@ -727,6 +816,11 @@ check_cmd(){
"$@" >> $logfile 2>&1
}
+check_stat(){
+ log check_stat "$@"
+ stat "$1" >> $logfile 2>&1
+}
+
cc_o(){
eval printf '%s\\n' $CC_O
}
@@ -742,6 +836,20 @@ check_cc(){
check_cmd $cc $CPPFLAGS $CFLAGS "$@" $CC_C $(cc_o $TMPO) $TMPC
}
+check_cxx(){
+ log check_cxx "$@"
+ cat > $TMPCPP
+ log_file $TMPCPP
+ check_cmd $cxx $CPPFLAGS $CFLAGS $CXXFLAGS "$@" $CXX_C -o $TMPO $TMPCPP
+}
+
+check_oc(){
+ log check_oc "$@"
+ cat > $TMPM
+ log_file $TMPM
+ check_cmd $cc -Werror=missing-prototypes $CPPFLAGS $CFLAGS "$@" $CC_C $(cc_o $TMPO) $TMPM
+}
+
check_cpp(){
log check_cpp "$@"
cat > $TMPC
@@ -782,7 +890,7 @@ check_yasm(){
echo "$1" > $TMPS
log_file $TMPS
shift 1
- check_cmd $yasmexe $YASMFLAGS "$@" -o $TMPO $TMPS
+ check_cmd $yasmexe $YASMFLAGS -Werror "$@" -o $TMPO $TMPS
}
ld_o(){
@@ -791,9 +899,11 @@ ld_o(){
check_ld(){
log check_ld "$@"
- flags=$(filter_out '-l*' "$@")
- libs=$(filter '-l*' "$@")
- check_cc $($cflags_filter $flags) || return
+ type=$1
+ shift 1
+ flags=$(filter_out '-l*|*.so' $@)
+ libs=$(filter '-l*|*.so' $@)
+ check_$type $($cflags_filter $flags) || return
flags=$($ldflags_filter $flags)
libs=$($ldflags_filter $libs)
check_cmd $ld $LDFLAGS $flags $(ld_o $TMPE) $TMPO $libs $extralibs
@@ -840,9 +950,17 @@ check_cflags(){
test_cflags "$@" && add_cflags "$@"
}
+check_cxxflags(){
+ log check_cxxflags "$@"
+ set -- $($cflags_filter "$@")
+ check_cxx "$@" <<EOF && append CXXFLAGS "$@"
+int x;
+EOF
+}
+
test_ldflags(){
log test_ldflags "$@"
- check_ld "$@" <<EOF
+ check_ld "cc" "$@" <<EOF
int main(void){ return 0; }
EOF
}
@@ -858,7 +976,7 @@ test_stripflags(){
check_cc <<EOF
int main(void) { return 0; }
EOF
- check_cmd $strip $STRIPFLAGS "$@" $TMPO
+ check_cmd $strip $ASMSTRIPFLAGS "$@" $TMPO
}
check_stripflags(){
@@ -877,12 +995,24 @@ int x;
EOF
}
+check_header_oc(){
+ log check_header_oc "$@"
+ rm -f -- "$TMPO"
+ header=$1
+ shift
+ disable_safe $header
+ {
+ echo "#include <$header>"
+ echo "int main(void) { return 0; }"
+ } | check_oc && check_stat "$TMPO" && enable_safe $headers
+}
+
check_func(){
log check_func "$@"
func=$1
shift
disable $func
- check_ld "$@" <<EOF && enable $func
+ check_ld "cc" "$@" <<EOF && enable $func
extern int $func();
int main(void){ $func(); }
EOF
@@ -895,10 +1025,10 @@ check_mathfunc(){
shift 2
test $narg = 2 && args="f, g" || args="f"
disable $func
- check_ld "$@" <<EOF && enable $func
+ check_ld "cc" "$@" <<EOF && enable $func
#include <math.h>
float foo(float f, float g) { return $func($args); }
-int main(void){ return 0; }
+int main(void){ return (int) foo; }
EOF
}
@@ -915,7 +1045,26 @@ check_func_headers(){
echo "long check_$func(void) { return (long) $func; }"
done
echo "int main(void) { return 0; }"
- } | check_ld "$@" && enable $funcs && enable_safe $headers
+ } | check_ld "cc" "$@" && enable $funcs && enable_safe $headers
+}
+
+check_class_headers_cpp(){
+ log check_class_headers_cpp "$@"
+ headers=$1
+ classes=$2
+ shift 2
+ {
+ for hdr in $headers; do
+ echo "#include <$hdr>"
+ done
+ echo "int main(void) { "
+ i=1
+ for class in $classes; do
+ echo "$class obj$i;"
+ i=$(expr $i + 1)
+ done
+ echo "return 0; }"
+ } | check_ld "cxx" "$@" && enable $funcs && enable_safe $headers
}
check_cpp_condition(){
@@ -947,13 +1096,22 @@ check_lib2(){
check_func_headers "$headers" "$funcs" "$@" && add_extralibs "$@"
}
+check_lib_cpp(){
+ log check_lib_cpp "$@"
+ headers="$1"
+ classes="$2"
+ shift 2
+ check_class_headers_cpp "$headers" "$classes" "$@" && add_extralibs "$@"
+}
+
check_pkg_config(){
log check_pkg_config "$@"
- pkg="$1"
+ pkgandversion="$1"
+ pkg="${1%% *}"
headers="$2"
funcs="$3"
shift 3
- check_cmd $pkg_config --exists --print-errors $pkg || return
+ check_cmd $pkg_config --exists --print-errors $pkgandversion || return
pkg_cflags=$($pkg_config --cflags $pkg_config_flags $pkg)
pkg_libs=$($pkg_config --libs $pkg_config_flags $pkg)
check_func_headers "$headers" "$funcs" $pkg_cflags $pkg_libs "$@" &&
@@ -962,7 +1120,7 @@ check_pkg_config(){
}
check_exec(){
- check_ld "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; }
+ check_ld "cc" "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; }
}
check_exec_crash(){
@@ -1022,7 +1180,7 @@ check_builtin(){
builtin=$3
shift 3
disable "$name"
- check_code ld "$headers" "$builtin" "$@" && enable "$name"
+ check_code ld "$headers" "$builtin" "cc" "$@" && enable "$name"
}
check_compile_assert(){
@@ -1051,9 +1209,41 @@ require2(){
check_lib2 "$headers" $func "$@" || die "ERROR: $name not found"
}
-require_pkg_config(){
+require_cpp(){
+ name="$1"
+ headers="$2"
+ classes="$3"
+ shift 3
+ check_lib_cpp "$headers" "$classes" "$@" || die "ERROR: $name not found"
+}
+
+use_pkg_config(){
pkg="$1"
- check_pkg_config "$@" || die "ERROR: $pkg not found"
+ check_pkg_config "$@" || return 1
+ add_cflags $(get_safe ${pkg}_cflags)
+ add_extralibs $(get_safe ${pkg}_libs)
+}
+
+require_pkg_config(){
+ use_pkg_config "$@" || die "ERROR: $pkg not found using pkg-config$pkg_config_fail_message"
+}
+
+require_libfreetype(){
+ log require_libfreetype "$@"
+ pkg="freetype2"
+ check_cmd $pkg_config --exists --print-errors $pkg \
+ || die "ERROR: $pkg not found"
+ pkg_cflags=$($pkg_config --cflags $pkg_config_flags $pkg)
+ pkg_libs=$($pkg_config --libs $pkg_config_flags $pkg)
+ {
+ echo "#include <ft2build.h>"
+ echo "#include FT_FREETYPE_H"
+ echo "long check_func(void) { return (long) FT_Init_FreeType; }"
+ echo "int main(void) { return 0; }"
+ } | check_ld "cc" $pkg_cflags $pkg_libs \
+ && set_safe ${pkg}_cflags $pkg_cflags \
+ && set_safe ${pkg}_libs $pkg_libs \
+ || die "ERROR: $pkg not found"
add_cflags $(get_safe ${pkg}_cflags)
add_extralibs $(get_safe ${pkg}_libs)
}
@@ -1138,31 +1328,56 @@ COMPONENT_LIST="
"
EXAMPLE_LIST="
- avcodec_example
+ avio_reading_example
+ avio_list_dir_example
+ decoding_encoding_example
+ demuxing_decoding_example
+ extract_mvs_example
filter_audio_example
+ filtering_audio_example
+ filtering_video_example
metadata_example
- output_example
+ muxing_example
qsvdec_example
+ remuxing_example
+ resampling_audio_example
+ scaling_video_example
transcode_aac_example
+ transcoding_example
"
EXTERNAL_LIBRARY_LIST="
avisynth
bzlib
+ crystalhd
+ decklink
frei0r
gnutls
+ iconv
+ ladspa
+ libaacplus
+ libass
+ libbluray
libbs2b
+ libcaca
libcdio
+ libcelt
libdc1394
libdcadec
libfaac
libfdk_aac
+ libflite
libfontconfig
libfreetype
+ libfribidi
+ libgme
libgsm
+ libiec61883
libilbc
libmfx
+ libmodplug
libmp3lame
+ libnut
libopencore_amrnb
libopencore_amrwb
libopencv
@@ -1170,11 +1385,20 @@ EXTERNAL_LIBRARY_LIST="
libopenjpeg
libopus
libpulse
+ libquvi
librtmp
libschroedinger
+ libshine
+ libsmbclient
+ libsoxr
libspeex
+ libssh
+ libstagefright_h264
libtheora
libtwolame
+ libutvideo
+ libv4l2
+ libvidstab
libvo_aacenc
libvo_amrwbenc
libvorbis
@@ -1186,22 +1410,40 @@ EXTERNAL_LIBRARY_LIST="
libxavs
libxcb
libxcb_shm
+ libxcb_shape
libxcb_xfixes
libxvid
+ libzmq
+ libzvbi
+ lzma
mmal
+ nvenc
+ openal
+ opencl
+ opengl
openssl
+ sdl
x11grab
+ xlib
zlib
"
+DOCUMENT_LIST="
+ doc
+ htmlpages
+ manpages
+ podpages
+ txtpages
+"
+
FEATURE_LIST="
+ ftrapv
gray
hardcoded_tables
runtime_cpudetect
safe_bitstream_reader
shared
small
- sram
static
swscale_alpha
"
@@ -1212,6 +1454,7 @@ HWACCEL_LIST="
vaapi
vda
vdpau
+ xvmc
"
LIBRARY_LIST="
@@ -1221,6 +1464,8 @@ LIBRARY_LIST="
avformat
avresample
avutil
+ postproc
+ swresample
swscale
"
@@ -1231,26 +1476,30 @@ LICENSE_LIST="
"
PROGRAM_LIST="
- avconv
- avplay
- avprobe
+ ffplay
+ ffprobe
+ ffserver
+ ffmpeg
"
SUBSYSTEM_LIST="
dct
- doc
+ dwt
error_resilience
faan
+ fast_unaligned
fft
lsp
lzo
mdct
+ pixelutils
network
rdft
"
CONFIG_LIST="
$COMPONENT_LIST
+ $DOCUMENT_LIST
$EXAMPLE_LIST
$EXTERNAL_LIBRARY_LIST
$FEATURE_LIST
@@ -1259,11 +1508,14 @@ CONFIG_LIST="
$LIBRARY_LIST
$PROGRAM_LIST
$SUBSYSTEM_LIST
+ fontconfig
+ incompatible_libav_abi
memalign_hack
+ memory_poisoning
neon_clobber_test
pic
pod2man
- texi2html
+ raise_major
thumb
valgrind_backtrace
xmm_clobber_test
@@ -1271,6 +1523,7 @@ CONFIG_LIST="
THREADS_LIST="
pthreads
+ os2threads
w32threads
"
@@ -1315,6 +1568,21 @@ ARCH_EXT_LIST_ARM="
neon
vfp
vfpv3
+ setend
+"
+
+ARCH_EXT_LIST_MIPS="
+ mipsfpu
+ mips32r2
+ mips32r5
+ mips64r6
+ mipsdspr1
+ mipsdspr2
+ msa
+"
+
+ARCH_EXT_LIST_LOONGSON="
+ loongson3
"
ARCH_EXT_LIST_X86_SIMD="
@@ -1340,6 +1608,7 @@ ARCH_EXT_LIST_PPC="
dcbzl
ldbrx
ppc4xx
+ vsx
"
ARCH_EXT_LIST_X86="
@@ -1352,8 +1621,8 @@ ARCH_EXT_LIST="
$ARCH_EXT_LIST_ARM
$ARCH_EXT_LIST_PPC
$ARCH_EXT_LIST_X86
- loongson
- vis
+ $ARCH_EXT_LIST_MIPS
+ $ARCH_EXT_LIST_LOONGSON
"
ARCH_FEATURES="
@@ -1363,15 +1632,18 @@ ARCH_FEATURES="
fast_cmov
local_aligned_8
local_aligned_16
+ local_aligned_32
simd_align_16
"
BUILTIN_LIST="
atomic_cas_ptr
+ atomic_compare_exchange
machine_rw_barrier
MemoryBarrier
mm_empty
rdtsc
+ sarestart
sync_val_compare_and_swap
"
HAVE_LIST_CMDLINE="
@@ -1383,12 +1655,14 @@ HAVE_LIST_CMDLINE="
HAVE_LIST_PUB="
bigendian
fast_unaligned
+ incompatible_libav_abi
"
HEADERS_LIST="
alsa_asoundlib_h
altivec_h
arpa_inet_h
+ asm_types_h
cdio_paranoia_h
cdio_paranoia_paranoia_h
dev_bktr_ioctl_bt848_h
@@ -1400,12 +1674,15 @@ HEADERS_LIST="
dlfcn_h
d3d11_h
dxva_h
+ ES2_gl_h
gsm_h
io_h
mach_mach_time_h
machine_ioctl_bt848_h
machine_ioctl_meteor_h
malloc_h
+ openjpeg_1_5_openjpeg_h
+ OpenGL_gl3_h
poll_h
sndio_h
soundcard_h
@@ -1417,6 +1694,8 @@ HEADERS_LIST="
sys_time_h
sys_un_h
sys_videoio_h
+ termios_h
+ udplite_h
unistd_h
valgrind_valgrind_h
windows_h
@@ -1430,6 +1709,7 @@ INTRINSICS_LIST="
MATH_FUNCS="
atanf
atan2f
+ cbrt
cbrtf
cosf
exp2
@@ -1455,6 +1735,7 @@ MATH_FUNCS="
"
SYSTEM_FUNCS="
+ access
aligned_malloc
clock_gettime
closesocket
@@ -1475,11 +1756,15 @@ SYSTEM_FUNCS="
getservbyport
GetSystemTimeAsFileTime
gettimeofday
+ glob
+ glXGetProcAddress
gmtime_r
inet_aton
isatty
jack_port_get_latency_range
+ kbhit
localtime_r
+ lzo1x_999_compress
mach_absolute_time
MapViewOfFile
memalign
@@ -1487,7 +1772,9 @@ SYSTEM_FUNCS="
mmap
mprotect
nanosleep
+ PeekNamedPipe
posix_memalign
+ pthread_cancel
sched_getaffinity
SetConsoleTextAttribute
setmode
@@ -1498,6 +1785,7 @@ SYSTEM_FUNCS="
sysctl
usleep
VirtualAlloc
+ wglGetProcAddress
"
TOOLCHAIN_FEATURES="
@@ -1510,9 +1798,13 @@ TOOLCHAIN_FEATURES="
ebp_available
ebx_available
gnu_as
+ gnu_windres
ibm_asm
inline_asm_labels
+ inline_asm_nonlocal_labels
+ inline_asm_direct_symbol_refs
pragma_deprecated
+ rsync_contimeout
symver_asm_label
symver_gnu_asm
vfp_args
@@ -1530,9 +1822,11 @@ TYPES_LIST="
struct_ipv6_mreq
struct_pollfd
struct_rusage_ru_maxrss
+ struct_sctp_event_subscribe
struct_sockaddr_in6
struct_sockaddr_sa_len
struct_sockaddr_storage
+ struct_stat_st_mtim_tv_nsec
struct_v4l2_frmivalenum_discrete
"
@@ -1556,12 +1850,18 @@ HAVE_LIST="
dos_paths
d3d11_cobj
d3d11va_lib
+ dxva2api_cobj
dxva2_lib
libc_msvcrt
libdc1394_1
libdc1394_2
+ makeinfo
+ makeinfo_html
+ perl
+ pod2man
sdl
section_data_rel_ro
+ texi2html
threads
vaapi_x11
vdpau_x11
@@ -1578,10 +1878,12 @@ CONFIG_EXTRA="
bswapdsp
cabac
dvprofile
+ exif
faandct
faanidct
fdctdsp
fmtconvert
+ frame_thread_encoder
gcrypt
golomb
gplv3
@@ -1600,6 +1902,8 @@ CONFIG_EXTRA="
intrax8
jpegtables
lgplv3
+ llauddsp
+ llviddsp
lpc
me_cmp
mpeg_er
@@ -1639,6 +1943,7 @@ CMDLINE_SELECT="
lto
optimizations
rpath
+ stripping
"
PATHS_LIST="
@@ -1657,18 +1962,23 @@ CMDLINE_SET="
ar
arch
as
+ assert_level
build_suffix
cc
cpu
cross_prefix
+ cxx
dep_cc
+ doxygen
extra_version
+ gas
host_cc
host_cflags
host_ld
host_ldflags
host_libs
host_os
+ install
ld
logfile
malloc_prefix
@@ -1676,19 +1986,27 @@ CMDLINE_SET="
optflags
pkg_config
pkg_config_flags
+ progs_suffix
random_seed
+ ranlib
samples
+ strip
+ sws_max_filter_size
sysinclude
sysroot
target_exec
target_os
target_path
target_samples
+ tempprefix
toolchain
+ valgrind
+ yasmexe
"
CMDLINE_APPEND="
extra_cflags
+ extra_cxxflags
host_cppflags
"
@@ -1704,11 +2022,24 @@ neon_deps_any="aarch64 arm"
intrinsics_neon_deps="neon"
vfp_deps_any="aarch64 arm"
vfpv3_deps="vfp"
+setend_deps="arm"
map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM
+mipsfpu_deps="mips"
+mipsdspr1_deps="mips"
+mipsdspr2_deps="mips"
+mips32r2_deps="mips"
+mips32r5_deps="mips"
+mips64r6_deps="mips"
+msa_deps="mips"
+loongson3_deps="mips"
+
altivec_deps="ppc"
+dcbzl_deps="ppc"
+ldbrx_deps="ppc"
ppc4xx_deps="ppc"
+vsx_deps="ppc"
cpunop_deps="i686"
x86_64_select="i686"
@@ -1753,7 +2084,7 @@ symver_if_any="symver_asm_label symver_gnu_asm"
valgrind_backtrace_deps="!optimizations valgrind_valgrind_h"
# threading support
-atomics_gcc_if="sync_val_compare_and_swap"
+atomics_gcc_if_any="sync_val_compare_and_swap atomic_compare_exchange"
atomics_suncc_if="atomic_cas_ptr machine_rw_barrier"
atomics_win32_if="MemoryBarrier"
atomics_native_if_any="$ATOMICS_LIST"
@@ -1765,6 +2096,7 @@ dct_select="rdft"
error_resilience_select="me_cmp"
faandct_deps="faan fdctdsp"
faanidct_deps="faan idctdsp"
+frame_thread_encoder_deps="encoders threads"
intrax8_select="error_resilience"
mdct_select="fft"
rdft_select="fft"
@@ -1772,7 +2104,7 @@ me_cmp_select="fdctdsp idctdsp pixblockdsp"
mpeg_er_select="error_resilience"
mpegaudio_select="mpegaudiodsp"
mpegaudiodsp_select="dct"
-mpegvideo_select="blockdsp hpeldsp idctdsp me_cmp videodsp"
+mpegvideo_select="blockdsp h264chroma hpeldsp idctdsp me_cmp videodsp"
mpegvideoenc_select="me_cmp mpegvideo pixblockdsp qpeldsp"
qsvdec_select="qsv"
qsvenc_select="qsv"
@@ -1782,6 +2114,7 @@ aac_decoder_select="imdct15 mdct sinewin"
aac_encoder_select="audio_frame_queue iirfilter mdct sinewin"
aac_latm_decoder_select="aac_decoder aac_latm_parser"
ac3_decoder_select="ac3_parser ac3dsp bswapdsp fmtconvert mdct"
+ac3_fixed_decoder_select="ac3_parser ac3dsp bswapdsp mdct"
ac3_encoder_select="ac3dsp audiodsp mdct me_cmp"
ac3_fixed_encoder_select="ac3dsp audiodsp mdct me_cmp"
aic_decoder_select="golomb idctdsp"
@@ -1789,8 +2122,11 @@ alac_encoder_select="lpc"
als_decoder_select="bswapdsp"
amrnb_decoder_select="lsp"
amrwb_decoder_select="lsp"
-amv_decoder_select="sp5x_decoder"
-ape_decoder_select="bswapdsp"
+amv_decoder_select="sp5x_decoder exif"
+amv_encoder_select="aandcttables jpegtables mpegvideoenc"
+ape_decoder_select="bswapdsp llauddsp"
+apng_decoder_select="zlib"
+apng_encoder_select="huffyuvencdsp zlib"
asv1_decoder_select="blockdsp bswapdsp idctdsp"
asv1_encoder_select="bswapdsp fdctdsp pixblockdsp"
asv2_decoder_select="blockdsp bswapdsp idctdsp"
@@ -1798,6 +2134,7 @@ asv2_encoder_select="bswapdsp fdctdsp pixblockdsp"
atrac1_decoder_select="mdct sinewin"
atrac3_decoder_select="mdct"
atrac3p_decoder_select="mdct sinewin"
+avrn_decoder_select="exif jpegtables"
bink_decoder_select="blockdsp hpeldsp"
binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
@@ -1808,17 +2145,18 @@ cook_decoder_select="audiodsp mdct sinewin"
cscd_decoder_select="lzo"
cscd_decoder_suggest="zlib"
dca_decoder_select="fmtconvert mdct"
+dirac_decoder_select="dwt golomb videodsp mpegvideoenc"
dnxhd_decoder_select="blockdsp idctdsp"
dnxhd_encoder_select="aandcttables blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp"
dvvideo_decoder_select="dvprofile idctdsp"
dvvideo_encoder_select="dvprofile fdctdsp me_cmp pixblockdsp"
-dxa_decoder_deps="zlib"
+dxa_decoder_select="zlib"
eac3_decoder_select="ac3_decoder"
eac3_encoder_select="ac3_encoder"
eamad_decoder_select="aandcttables blockdsp bswapdsp idctdsp mpegvideo"
-eatgq_decoder_select="aandcttables idctdsp"
+eatgq_decoder_select="aandcttables"
eatqi_decoder_select="aandcttables blockdsp bswapdsp idctdsp mpeg1video_decoder"
-exr_decoder_deps="zlib"
+exr_decoder_select="zlib"
ffv1_decoder_select="golomb rangecoder"
ffv1_encoder_select="rangecoder"
ffvhuff_decoder_select="huffyuv_decoder"
@@ -1826,20 +2164,22 @@ ffvhuff_encoder_select="huffyuv_encoder"
fic_decoder_select="golomb"
flac_decoder_select="golomb"
flac_encoder_select="bswapdsp golomb lpc"
-flashsv_decoder_deps="zlib"
-flashsv_encoder_deps="zlib"
-flashsv2_decoder_deps="zlib"
+flashsv_decoder_select="zlib"
+flashsv_encoder_select="zlib"
+flashsv2_encoder_select="zlib"
+flashsv2_decoder_select="zlib"
flv_decoder_select="h263_decoder"
flv_encoder_select="h263_encoder"
fourxm_decoder_select="blockdsp bswapdsp"
fraps_decoder_select="bswapdsp huffman"
-g2m_decoder_deps="zlib"
-g2m_decoder_select="blockdsp idctdsp jpegtables"
+g2m_decoder_select="blockdsp idctdsp jpegtables zlib"
+g729_decoder_select="audiodsp"
h261_decoder_select="mpeg_er mpegvideo"
h261_encoder_select="aandcttables mpegvideoenc"
h263_decoder_select="error_resilience h263_parser h263dsp mpeg_er mpegvideo qpeldsp"
h263_encoder_select="aandcttables h263dsp mpegvideoenc"
h263i_decoder_select="h263_decoder"
+h263p_decoder_select="h263_decoder"
h263p_encoder_select="h263_encoder"
h264_decoder_select="cabac golomb h264chroma h264dsp h264pred h264qpel startcode videodsp"
h264_decoder_suggest="error_resilience"
@@ -1848,8 +2188,8 @@ h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec h264_qsv_hwacce
h264_qsv_encoder_deps="libmfx"
h264_qsv_encoder_select="qsvenc"
hevc_decoder_select="bswapdsp cabac golomb videodsp"
-huffyuv_decoder_select="bswapdsp huffyuvdsp"
-huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp"
+huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp"
+huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llviddsp"
iac_decoder_select="imc_decoder"
imc_decoder_select="bswapdsp fft mdct sinewin"
indeo3_decoder_select="hpeldsp"
@@ -1863,7 +2203,7 @@ loco_decoder_select="golomb"
mdec_decoder_select="blockdsp idctdsp mpegvideo"
metasound_decoder_select="lsp mdct sinewin"
mimic_decoder_select="blockdsp bswapdsp hpeldsp idctdsp"
-mjpeg_decoder_select="blockdsp hpeldsp idctdsp jpegtables"
+mjpeg_decoder_select="blockdsp hpeldsp exif idctdsp jpegtables"
mjpeg_encoder_select="aandcttables jpegtables mpegvideoenc"
mjpegb_decoder_select="mjpeg_decoder"
mlp_decoder_select="mlp_parser"
@@ -1882,10 +2222,11 @@ mpc7_decoder_select="bswapdsp mpegaudiodsp"
mpc8_decoder_select="mpegaudiodsp"
mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h"
mpeg_xvmc_decoder_select="mpeg2video_decoder"
+mpegvideo_decoder_select="error_resilience mpeg_er mpegvideo"
mpeg1video_decoder_select="error_resilience mpeg_er mpegvideo"
-mpeg1video_encoder_select="aandcttables mpegvideoenc"
+mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp"
mpeg2video_decoder_select="error_resilience mpeg_er mpegvideo"
-mpeg2video_encoder_select="aandcttables mpegvideoenc"
+mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp"
mpeg4_decoder_select="h263_decoder mpeg4video_parser"
mpeg4_encoder_select="h263_encoder"
msmpeg4v1_decoder_select="h263_decoder"
@@ -1899,17 +2240,19 @@ nellymoser_decoder_select="mdct sinewin"
nellymoser_encoder_select="audio_frame_queue mdct sinewin"
nuv_decoder_select="idctdsp lzo"
on2avc_decoder_select="mdct"
-opus_decoder_deps="avresample"
+opus_decoder_deps="swresample"
opus_decoder_select="imdct15"
-png_decoder_deps="zlib"
-png_encoder_deps="zlib"
-png_encoder_select="huffyuvencdsp"
-prores_decoder_select="idctdsp"
+png_decoder_select="zlib"
+png_encoder_select="huffyuvencdsp zlib"
+prores_decoder_select="blockdsp idctdsp"
prores_encoder_select="fdctdsp"
qcelp_decoder_select="lsp"
qdm2_decoder_select="mdct rdft mpegaudiodsp"
-ra_144_encoder_select="audio_frame_queue lpc"
+ra_144_encoder_select="audio_frame_queue lpc audiodsp"
+ra_144_decoder_select="audiodsp"
ralf_decoder_select="golomb"
+rawvideo_decoder_select="bswapdsp"
+rtjpeg_decoder_select="me_cmp"
rv10_decoder_select="error_resilience h263_decoder h263dsp mpeg_er"
rv10_encoder_select="h263_encoder"
rv20_decoder_select="error_resilience h263_decoder h263dsp mpeg_er"
@@ -1918,22 +2261,26 @@ rv30_decoder_select="error_resilience golomb h264chroma h264pred h264qpel mpeg_e
rv40_decoder_select="error_resilience golomb h264chroma h264pred h264qpel mpeg_er mpegvideo videodsp"
shorten_decoder_select="golomb"
sipr_decoder_select="lsp"
+snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp"
+snow_encoder_select="aandcttables dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder"
+sonic_decoder_select="golomb rangecoder"
+sonic_encoder_select="golomb rangecoder"
+sonic_ls_encoder_select="golomb rangecoder"
sp5x_decoder_select="mjpeg_decoder"
svq1_decoder_select="hpeldsp"
svq1_encoder_select="aandcttables hpeldsp me_cmp mpegvideoenc"
svq3_decoder_select="h264_decoder hpeldsp tpeldsp"
svq3_decoder_suggest="zlib"
tak_decoder_select="audiodsp"
-tdsc_decoder_deps="zlib"
-tdsc_decoder_select="mjpeg_decoder"
+tdsc_decoder_select="zlib mjpeg_decoder"
theora_decoder_select="vp3_decoder"
thp_decoder_select="mjpeg_decoder"
-tiff_decoder_suggest="zlib"
+tiff_decoder_suggest="zlib lzma"
tiff_encoder_suggest="zlib"
-truehd_decoder_select="mlp_decoder"
+truehd_decoder_select="mlp_parser"
truemotion2_decoder_select="bswapdsp"
truespeech_decoder_select="bswapdsp"
-tscc_decoder_deps="zlib"
+tscc_decoder_select="zlib"
twinvq_decoder_select="mdct lsp sinewin"
utvideo_decoder_select="bswapdsp"
utvideo_encoder_select="bswapdsp huffman huffyuvencdsp"
@@ -1949,8 +2296,9 @@ vp6a_decoder_select="vp6_decoder"
vp6f_decoder_select="vp6_decoder"
vp7_decoder_select="h264pred videodsp"
vp8_decoder_select="h264pred videodsp"
-vp9_decoder_select="videodsp"
+vp9_decoder_select="videodsp vp9_parser"
webp_decoder_select="vp8_decoder"
+wmalossless_decoder_select="llauddsp"
wmapro_decoder_select="mdct sinewin wma_freqs"
wmav1_decoder_select="mdct sinewin wma_freqs"
wmav1_encoder_select="mdct sinewin wma_freqs"
@@ -1963,24 +2311,27 @@ wmv2_decoder_select="blockdsp h263_decoder idctdsp intrax8 videodsp"
wmv2_encoder_select="h263_encoder"
wmv3_decoder_select="vc1_decoder"
wmv3image_decoder_select="wmv3_decoder"
-zerocodec_decoder_deps="zlib"
-zlib_decoder_deps="zlib"
-zlib_encoder_deps="zlib"
-zmbv_decoder_deps="zlib"
-zmbv_encoder_deps="zlib"
+zerocodec_decoder_select="zlib"
+zlib_decoder_select="zlib"
+zlib_encoder_select="zlib"
+zmbv_decoder_select="zlib"
+zmbv_encoder_select="zlib"
# hardware accelerators
+crystalhd_deps="libcrystalhd_libcrystalhd_if_h"
d3d11va_deps="d3d11_h dxva_h"
dxva2_deps="dxva2api_h"
vaapi_deps="va_va_h"
vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads"
vda_extralibs="-framework CoreFoundation -framework VideoDecodeAcceleration -framework QuartzCore"
vdpau_deps="vdpau_vdpau_h vdpau_vdpau_x11_h"
+xvmc_deps="X11_extensions_XvMClib_h"
h263_vaapi_hwaccel_deps="vaapi"
h263_vaapi_hwaccel_select="h263_decoder"
h263_vdpau_hwaccel_deps="vdpau"
h263_vdpau_hwaccel_select="h263_decoder"
+h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser"
h264_d3d11va_hwaccel_deps="d3d11va"
h264_d3d11va_hwaccel_select="h264_decoder"
h264_dxva2_hwaccel_deps="dxva2"
@@ -1992,18 +2343,31 @@ h264_mmal_encoder_deps="mmal"
h264_qsv_hwaccel_deps="libmfx"
h264_vaapi_hwaccel_deps="vaapi"
h264_vaapi_hwaccel_select="h264_decoder"
+h264_vda_decoder_deps="vda"
+h264_vda_decoder_select="h264_decoder"
h264_vda_hwaccel_deps="vda"
h264_vda_hwaccel_select="h264_decoder"
h264_vda_old_hwaccel_deps="vda"
h264_vda_old_hwaccel_select="h264_decoder"
+h264_vdpau_decoder_deps="vdpau"
+h264_vdpau_decoder_select="h264_decoder"
h264_vdpau_hwaccel_deps="vdpau"
h264_vdpau_hwaccel_select="h264_decoder"
hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC"
hevc_d3d11va_hwaccel_select="hevc_decoder"
hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC"
hevc_dxva2_hwaccel_select="hevc_decoder"
+mpeg_vdpau_decoder_deps="vdpau"
+mpeg_vdpau_decoder_select="mpeg2video_decoder"
+mpeg_xvmc_hwaccel_deps="xvmc"
+mpeg_xvmc_hwaccel_select="mpeg2video_decoder"
+mpeg1_vdpau_decoder_deps="vdpau"
+mpeg1_vdpau_decoder_select="mpeg1video_decoder"
mpeg1_vdpau_hwaccel_deps="vdpau"
mpeg1_vdpau_hwaccel_select="mpeg1video_decoder"
+mpeg1_xvmc_hwaccel_deps="xvmc"
+mpeg1_xvmc_hwaccel_select="mpeg1video_decoder"
+mpeg2_crystalhd_decoder_select="crystalhd"
mpeg2_d3d11va_hwaccel_deps="d3d11va"
mpeg2_d3d11va_hwaccel_select="mpeg2video_decoder"
mpeg2_dxva2_hwaccel_deps="dxva2"
@@ -2012,25 +2376,37 @@ mpeg2_vaapi_hwaccel_deps="vaapi"
mpeg2_vaapi_hwaccel_select="mpeg2video_decoder"
mpeg2_vdpau_hwaccel_deps="vdpau"
mpeg2_vdpau_hwaccel_select="mpeg2video_decoder"
+mpeg2_xvmc_hwaccel_deps="xvmc"
+mpeg2_xvmc_hwaccel_select="mpeg2video_decoder"
+mpeg4_crystalhd_decoder_select="crystalhd"
mpeg4_vaapi_hwaccel_deps="vaapi"
mpeg4_vaapi_hwaccel_select="mpeg4_decoder"
+mpeg4_vdpau_decoder_deps="vdpau"
+mpeg4_vdpau_decoder_select="mpeg4_decoder"
mpeg4_vdpau_hwaccel_deps="vdpau"
mpeg4_vdpau_hwaccel_select="mpeg4_decoder"
+msmpeg4_crystalhd_decoder_select="crystalhd"
+vc1_crystalhd_decoder_select="crystalhd"
vc1_d3d11va_hwaccel_deps="d3d11va"
vc1_d3d11va_hwaccel_select="vc1_decoder"
vc1_dxva2_hwaccel_deps="dxva2"
vc1_dxva2_hwaccel_select="vc1_decoder"
vc1_vaapi_hwaccel_deps="vaapi"
vc1_vaapi_hwaccel_select="vc1_decoder"
+vc1_vdpau_decoder_deps="vdpau"
+vc1_vdpau_decoder_select="vc1_decoder"
vc1_vdpau_hwaccel_deps="vdpau"
vc1_vdpau_hwaccel_select="vc1_decoder"
+wmv3_crystalhd_decoder_select="crystalhd"
wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel"
wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel"
wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel"
+wmv3_vdpau_decoder_select="vc1_vdpau_decoder"
wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel"
# parsers
h264_parser_select="h264_decoder"
+hevc_parser_select="hevc_decoder"
mpegvideo_parser_select="mpegvideo"
mpeg4video_parser_select="error_resilience h263dsp mpeg_er mpegvideo qpeldsp"
vc1_parser_select="mpegvideo startcode vc1_decoder"
@@ -2039,18 +2415,22 @@ vc1_parser_select="mpegvideo startcode vc1_decoder"
mjpeg2jpeg_bsf_select="jpegtables"
# external libraries
+libaacplus_encoder_deps="libaacplus"
+libcelt_decoder_deps="libcelt"
libdcadec_decoder_deps="libdcadec"
libfaac_encoder_deps="libfaac"
libfaac_encoder_select="audio_frame_queue"
libfdk_aac_decoder_deps="libfdk_aac"
libfdk_aac_encoder_deps="libfdk_aac"
libfdk_aac_encoder_select="audio_frame_queue"
+libgme_demuxer_deps="libgme"
libgsm_decoder_deps="libgsm"
libgsm_encoder_deps="libgsm"
libgsm_ms_decoder_deps="libgsm"
libgsm_ms_encoder_deps="libgsm"
libilbc_decoder_deps="libilbc"
libilbc_encoder_deps="libilbc"
+libmodplug_demuxer_deps="libmodplug"
libmp3lame_encoder_deps="libmp3lame"
libmp3lame_encoder_select="audio_frame_queue"
libopencore_amrnb_decoder_deps="libopencore_amrnb"
@@ -2063,16 +2443,21 @@ libopenjpeg_encoder_deps="libopenjpeg"
libopus_decoder_deps="libopus"
libopus_encoder_deps="libopus"
libopus_encoder_select="audio_frame_queue"
+libquvi_demuxer_deps="libquvi"
libschroedinger_decoder_deps="libschroedinger"
libschroedinger_encoder_deps="libschroedinger"
+libshine_encoder_deps="libshine"
+libshine_encoder_select="audio_frame_queue"
libspeex_decoder_deps="libspeex"
libspeex_encoder_deps="libspeex"
libspeex_encoder_select="audio_frame_queue"
+libstagefright_h264_decoder_deps="libstagefright_h264"
libtheora_encoder_deps="libtheora"
libtwolame_encoder_deps="libtwolame"
libvo_aacenc_encoder_deps="libvo_aacenc"
libvo_aacenc_encoder_select="audio_frame_queue"
libvo_amrwbenc_encoder_deps="libvo_amrwbenc"
+libvorbis_decoder_deps="libvorbis"
libvorbis_encoder_deps="libvorbis"
libvorbis_encoder_select="audio_frame_queue"
libvpx_vp8_decoder_deps="libvpx"
@@ -2081,23 +2466,33 @@ libvpx_vp9_decoder_deps="libvpx"
libvpx_vp9_encoder_deps="libvpx"
libwavpack_encoder_deps="libwavpack"
libwebp_encoder_deps="libwebp"
+libwebp_anim_encoder_deps="libwebp"
libx264_encoder_deps="libx264"
+libx264rgb_encoder_deps="libx264"
+libx264rgb_encoder_select="libx264_encoder"
libx265_encoder_deps="libx265"
libxavs_encoder_deps="libxavs"
libxvid_encoder_deps="libxvid"
+libutvideo_decoder_deps="libutvideo"
+libutvideo_encoder_deps="libutvideo"
+libzvbi_teletext_decoder_deps="libzvbi"
+nvenc_encoder_deps="nvenc"
+nvenc_h265_encoder_deps="nvenc"
# demuxers / muxers
ac3_demuxer_select="ac3_parser"
asf_demuxer_select="riffdec"
asf_muxer_select="riffenc"
asf_stream_muxer_select="asf_muxer"
-avi_demuxer_select="riffdec"
+avi_demuxer_select="riffdec exif"
avi_muxer_select="riffenc"
avisynth_demuxer_deps="avisynth"
avisynth_demuxer_select="riffdec"
caf_demuxer_select="riffdec"
dash_muxer_select="mp4_muxer"
dirac_demuxer_select="dirac_parser"
+dts_demuxer_select="dca_parser"
+dtshd_demuxer_select="dca_parser"
dv_demuxer_select="dvprofile"
dv_muxer_select="dvprofile"
dxa_demuxer_select="riffdec"
@@ -2106,8 +2501,12 @@ f4v_muxer_select="mov_muxer"
flac_demuxer_select="flac_parser"
hds_muxer_select="flv_muxer"
hls_muxer_select="mpegts_muxer"
+image2_alias_pix_demuxer_select="image2_demuxer"
+image2_brender_pix_demuxer_select="image2_demuxer"
ipod_muxer_select="mov_muxer"
ismv_muxer_select="mov_muxer"
+libnut_demuxer_deps="libnut"
+libnut_muxer_deps="libnut"
matroska_audio_muxer_select="matroska_muxer"
matroska_demuxer_select="riffdec"
matroska_demuxer_suggest="bzlib lzo zlib"
@@ -2121,6 +2520,7 @@ mp4_muxer_select="mov_muxer"
mpegts_muxer_select="adts_muxer latm_muxer"
mpegtsraw_demuxer_select="mpegts_demuxer"
mxf_d10_muxer_select="mxf_muxer"
+mxf_opatom_muxer_select="mxf_muxer"
nut_muxer_select="riffenc"
nuv_demuxer_select="riffdec"
oga_muxer_select="ogg_muxer"
@@ -2140,41 +2540,72 @@ spx_muxer_select="ogg_muxer"
tak_demuxer_select="tak_parser"
tg2_muxer_select="mov_muxer"
tgp_muxer_select="mov_muxer"
+vobsub_demuxer_select="mpegps_demuxer"
w64_demuxer_select="wav_demuxer"
+w64_muxer_select="wav_muxer"
wav_demuxer_select="riffdec"
wav_muxer_select="riffenc"
webm_muxer_select="riffenc"
wtv_demuxer_select="riffdec"
+wtv_muxer_select="riffenc"
xmv_demuxer_select="riffdec"
xwma_demuxer_select="riffdec"
# indevs / outdevs
alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
alsa_outdev_deps="alsa_asoundlib_h"
+avfoundation_indev_extralibs="-framework CoreVideo -framework Foundation -framework AVFoundation -framework CoreMedia"
+avfoundation_indev_select="avfoundation"
bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h"
+caca_outdev_deps="libcaca"
+decklink_outdev_deps="decklink pthreads"
+decklink_outdev_extralibs="-lstdc++"
+decklink_indev_deps="decklink pthreads"
+decklink_indev_extralibs="-lstdc++"
+dshow_indev_deps="IBaseFilter"
+dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi"
dv1394_indev_deps="dv1394"
dv1394_indev_select="dv_demuxer"
fbdev_indev_deps="linux_fb_h"
-jack_indev_deps="jack_jack_h pthreads"
+fbdev_outdev_deps="linux_fb_h"
+gdigrab_indev_deps="CreateDIBSection"
+gdigrab_indev_extralibs="-lgdi32"
+gdigrab_indev_select="bmp_decoder"
+iec61883_indev_deps="libiec61883"
+jack_indev_deps="jack_jack_h sem_timedwait"
+lavfi_indev_deps="avfilter"
libcdio_indev_deps="libcdio"
libdc1394_indev_deps="libdc1394"
+libv4l2_indev_deps="libv4l2"
+openal_indev_deps="openal"
+opengl_outdev_deps="opengl"
oss_indev_deps_any="soundcard_h sys_soundcard_h"
oss_outdev_deps_any="soundcard_h sys_soundcard_h"
pulse_indev_deps="libpulse"
+pulse_outdev_deps="libpulse"
+qtkit_indev_extralibs="-framework QTKit -framework Foundation -framework QuartzCore"
+qtkit_indev_select="qtkit"
+sdl_outdev_deps="sdl"
sndio_indev_deps="sndio_h"
sndio_outdev_deps="sndio_h"
+v4l_indev_deps="linux_videodev_h"
v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h"
+v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h"
vfwcap_indev_deps="capCreateCaptureWindow vfwcap_defines"
vfwcap_indev_extralibs="-lavicap32"
+xv_outdev_deps="X11_extensions_Xvlib_h XvGetPortAttribute"
+xv_outdev_extralibs="-lXv -lX11 -lXext"
x11grab_indev_deps="x11grab"
x11grab_xcb_indev_deps="libxcb"
# protocols
+bluray_protocol_deps="libbluray"
ffrtmpcrypt_protocol_deps="!librtmp_protocol"
ffrtmpcrypt_protocol_deps_any="gcrypt nettle openssl"
ffrtmpcrypt_protocol_select="tcp_protocol"
ffrtmphttp_protocol_deps="!librtmp_protocol"
ffrtmphttp_protocol_select="http_protocol"
+ftp_protocol_select="tcp_protocol"
gopher_protocol_select="network"
http_protocol_select="tcp_protocol"
httpproxy_protocol_select="tcp_protocol"
@@ -2185,6 +2616,8 @@ librtmpe_protocol_deps="librtmp"
librtmps_protocol_deps="librtmp"
librtmpt_protocol_deps="librtmp"
librtmpte_protocol_deps="librtmp"
+libsmbclient_protocol_deps="libsmbclient gplv3"
+libssh_protocol_deps="libssh"
mmsh_protocol_select="http_protocol"
mmst_protocol_select="network"
rtmp_protocol_deps="!librtmp_protocol"
@@ -2203,33 +2636,98 @@ tcp_protocol_select="network"
tls_protocol_deps_any="openssl gnutls"
tls_protocol_select="tcp_protocol"
udp_protocol_select="network"
+udplite_protocol_select="network"
unix_protocol_deps="sys_un_h"
unix_protocol_select="network"
# filters
+amovie_filter_deps="avcodec avformat"
+aresample_filter_deps="swresample"
+ass_filter_deps="libass"
+asyncts_filter_deps="avresample"
+atempo_filter_deps="avcodec"
+atempo_filter_select="rdft"
+azmq_filter_deps="libzmq"
blackframe_filter_deps="gpl"
boxblur_filter_deps="gpl"
bs2b_filter_deps="libbs2b"
+colormatrix_filter_deps="gpl"
+cover_rect_filter_deps="avcodec avformat gpl"
cropdetect_filter_deps="gpl"
delogo_filter_deps="gpl"
+deshake_filter_select="pixelutils"
drawtext_filter_deps="libfreetype"
+ebur128_filter_deps="gpl"
+eq_filter_deps="gpl"
+fftfilt_filter_deps="avcodec"
+fftfilt_filter_select="rdft"
+flite_filter_deps="libflite"
+find_rect_filter_deps="avcodec avformat gpl"
frei0r_filter_deps="frei0r dlopen"
-frei0r_filter_extralibs='$ldl'
frei0r_src_filter_deps="frei0r dlopen"
-frei0r_src_filter_extralibs='$ldl'
+fspp_filter_deps="gpl"
+geq_filter_deps="gpl"
+histeq_filter_deps="gpl"
hqdn3d_filter_deps="gpl"
interlace_filter_deps="gpl"
+kerndeint_filter_deps="gpl"
+ladspa_filter_deps="ladspa dlopen"
+mcdeint_filter_deps="avcodec gpl"
+movie_filter_deps="avcodec avformat"
+mpdecimate_filter_deps="gpl"
+mpdecimate_filter_select="pixelutils"
+mptestsrc_filter_deps="gpl"
+negate_filter_deps="lut_filter"
+perspective_filter_deps="gpl"
+pp7_filter_deps="gpl"
ocv_filter_deps="libopencv"
+owdenoise_filter_deps="gpl"
+pan_filter_deps="swresample"
+phase_filter_deps="gpl"
+pp_filter_deps="gpl postproc"
+pullup_filter_deps="gpl"
+removelogo_filter_deps="avcodec avformat swscale"
+repeatfields_filter_deps="gpl"
resample_filter_deps="avresample"
+sab_filter_deps="gpl swscale"
scale_filter_deps="swscale"
+select_filter_select="pixelutils"
+smartblur_filter_deps="gpl swscale"
+showspectrum_filter_deps="avcodec"
+showspectrum_filter_select="rdft"
+spp_filter_deps="gpl avcodec"
+spp_filter_select="fft idctdsp fdctdsp me_cmp pixblockdsp"
+stereo3d_filter_deps="gpl"
+subtitles_filter_deps="avformat avcodec libass"
+super2xsai_filter_deps="gpl"
+tinterlace_filter_deps="gpl"
+vidstabdetect_filter_deps="libvidstab"
+vidstabtransform_filter_deps="libvidstab"
+pixfmts_super2xsai_test_deps="super2xsai_filter"
+tinterlace_merge_test_deps="tinterlace_filter"
+tinterlace_pad_test_deps="tinterlace_filter"
+uspp_filter_deps="gpl avcodec"
+zmq_filter_deps="libzmq"
+zoompan_filter_deps="swscale"
# examples
+avio_reading="avformat avcodec avutil"
+avio_list_dir="avformat avutil"
avcodec_example_deps="avcodec avutil"
+decoding_encoding_example_deps="avcodec avformat avutil"
+demuxing_decoding_example_deps="avcodec avformat avutil"
+extract_mvs_example_deps="avcodec avformat avutil"
filter_audio_example_deps="avfilter avutil"
+filtering_audio_example_deps="avfilter avcodec avformat avutil"
+filtering_video_example_deps="avfilter avcodec avformat avutil"
metadata_example_deps="avformat avutil"
-output_example_deps="avcodec avformat avutil swscale"
+muxing_example_deps="avcodec avformat avutil swscale"
qsvdec_example_deps="avcodec avutil libmfx h264_qsv_decoder vaapi_x11"
-transcode_aac_example_deps="avcodec avformat avresample"
+remuxing_example_deps="avcodec avformat avutil"
+resampling_audio_example_deps="avutil swresample"
+scaling_video_example_deps="avutil swscale"
+transcode_aac_example_deps="avcodec avformat swresample"
+transcoding_example_deps="avfilter avcodec avformat avutil"
# libraries, in linking order
avcodec_deps="avutil"
@@ -2237,21 +2735,29 @@ avdevice_deps="avformat avcodec avutil"
avfilter_deps="avutil"
avformat_deps="avcodec avutil"
avresample_deps="avutil"
+postproc_deps="avutil gpl"
+swresample_deps="avutil"
swscale_deps="avutil"
# programs
-avconv_deps="avcodec avfilter avformat avresample swscale"
-avconv_select="aformat_filter anull_filter asyncts_filter atrim_filter format_filter
- fps_filter null_filter resample_filter scale_filter
+ffmpeg_deps="avcodec avfilter avformat swresample"
+ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter
+ null_filter
setpts_filter trim_filter"
-avplay_deps="avcodec avformat avresample swscale sdl"
-avplay_libs='$sdl_libs'
-avplay_select="rdft transpose_filter hflip_filter vflip_filter"
-avprobe_deps="avcodec avformat"
+ffplay_deps="avcodec avformat swscale swresample sdl"
+ffplay_libs='$sdl_libs'
+ffplay_select="rdft crop_filter transpose_filter hflip_filter vflip_filter rotate_filter"
+ffprobe_deps="avcodec avformat"
+ffserver_deps="avformat fork sarestart"
+ffserver_select="ffm_muxer rtp_protocol rtsp_demuxer"
# documentation
-pod2man_deps="doc"
-texi2html_deps="doc"
+podpages_deps="perl"
+manpages_deps="perl pod2man"
+htmlpages_deps="perl"
+htmlpages_deps_any="makeinfo_html texi2html"
+txtpages_deps="perl makeinfo"
+doc_deps_any="manpages htmlpages podpages txtpages"
# default parameters
@@ -2260,50 +2766,71 @@ logfile="config.log"
# installation paths
prefix_default="/usr/local"
bindir_default='${prefix}/bin'
-datadir_default='${prefix}/share/avconv'
-docdir_default='${prefix}/share/doc/libav'
+datadir_default='${prefix}/share/ffmpeg'
+docdir_default='${prefix}/share/doc/ffmpeg'
incdir_default='${prefix}/include'
libdir_default='${prefix}/lib'
mandir_default='${prefix}/share/man'
-shlibdir_default="$libdir_default"
# toolchain
ar_default="ar"
cc_default="gcc"
+cxx_default="g++"
host_cc_default="gcc"
cp_f="cp -f"
+doxygen_default="doxygen"
+install="install"
ln_s="ln -s -f"
nm_default="nm -g"
objformat="elf"
pkg_config_default=pkg-config
-ranlib="ranlib"
-strip="strip"
-yasmexe="yasm"
-
-# machine
-arch_default=$(uname -m)
-cpu="generic"
-intrinsics="none"
+if ranlib 2>&1 | grep -q "\-D "; then
+ ranlib_default="ranlib -D"
+else
+ ranlib_default="ranlib"
+fi
+strip_default="strip"
+yasmexe_default="yasm"
+windres_default="windres"
# OS
target_os_default=$(tolower $(uname -s))
host_os=$target_os_default
+# machine
+if test "$target_os_default" = aix; then
+ arch_default=$(uname -p)
+ strip_default="strip -X32_64"
+else
+ arch_default=$(uname -m)
+fi
+cpu="generic"
+intrinsics="none"
+
# configurable options
-enable $EXAMPLE_LIST $LIBRARY_LIST $PROGRAM_LIST
+enable $PROGRAM_LIST
+enable $DOCUMENT_LIST
+enable $EXAMPLE_LIST
+enable $(filter_out avresample $LIBRARY_LIST)
+enable stripping
enable asm
enable debug
enable doc
enable faan faandct faanidct
enable optimizations
+enable runtime_cpudetect
enable safe_bitstream_reader
enable static
enable swscale_alpha
enable valgrind_backtrace
-# By default, enable only those hwaccels that have no external dependencies.
-enable d3d11va dxva2 vda vdpau
+sws_max_filter_size_default=256
+set_default sws_max_filter_size
+
+# Enable hwaccels by default.
+enable d3d11va dxva2 vaapi vda vdpau xvmc
+enable xlib
# build settings
SHFLAGS='-shared -Wl,-soname,$$(@F)'
@@ -2329,6 +2856,8 @@ AS_O='-o $@'
CC_C='-c'
CC_E='-E -o $@'
CC_O='-o $@'
+CXX_C='-c'
+CXX_O='-o $@'
LD_O='-o $@'
LD_LIB='-l%'
LD_PATH='-L'
@@ -2363,7 +2892,7 @@ for v in "$@"; do
r=${v#*=}
l=${v%"$r"}
r=$(sh_quote "$r")
- LIBAV_CONFIGURATION="${LIBAV_CONFIGURATION# } ${l}${r}"
+ FFMPEG_CONFIGURATION="${FFMPEG_CONFIGURATION# } ${l}${r}"
done
find_things(){
@@ -2486,11 +3015,9 @@ for opt do
is_in "${thing}s" $COMPONENT_LIST || die_unknown "$opt"
eval list=\$$(toupper $thing)_LIST
name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing}
- $action $(filter "$name" $list)
- ;;
- --enable-avserver|--disable-avserver*)
- warn "avserver has been removed, the ${opt} option is only"\
- "provided for compatibility and will be removed in the future"
+ list=$(filter "$name" $list)
+ [ "$list" = "" ] && warn "Option $opt did not match anything"
+ $action $list
;;
--enable-?*|--disable-?*)
eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g')
@@ -2511,6 +3038,8 @@ for opt do
;;
--help|-h) show_help
;;
+ --fatal-warnings) enable fatal_warnings
+ ;;
*)
optname="${opt%%=*}"
optname="${optname#--}"
@@ -2528,9 +3057,11 @@ done
disabled logging && logfile=/dev/null
-echo "# $0 $LIBAV_CONFIGURATION" > $logfile
+echo "# $0 $FFMPEG_CONFIGURATION" > $logfile
set >> $logfile
+test -n "$valgrind" && toolchain="valgrind-memcheck"
+
case "$toolchain" in
clang-asan)
cc_default="clang"
@@ -2544,7 +3075,7 @@ case "$toolchain" in
;;
clang-usan)
cc_default="clang"
- add_cflags -fsanitize=undefined -O1
+ add_cflags -fsanitize=undefined
add_ldflags -fsanitize=undefined
;;
gcc-asan)
@@ -2563,17 +3094,17 @@ case "$toolchain" in
add_ldflags -fsanitize=undefined
;;
valgrind-massif)
- target_exec_default="valgrind"
- target_exec_args="--alloc-fn=av_malloc --alloc-fn=av_mallocz"
+ target_exec_default=${valgrind:-"valgrind"}
+ target_exec_args="--tool=massif --alloc-fn=av_malloc --alloc-fn=av_mallocz --alloc-fn=av_calloc --alloc-fn=av_fast_padded_malloc --alloc-fn=av_fast_malloc --alloc-fn=av_realloc_f --alloc-fn=av_fast_realloc --alloc-fn=av_realloc"
;;
valgrind-memcheck)
- target_exec_default="valgrind"
- target_exec_args="--track-origins=yes --leak-check=full"
+ target_exec_default=${valgrind:-"valgrind"}
+ target_exec_args="--error-exitcode=1 --malloc-fill=0x2a --track-origins=yes --leak-check=full --gen-suppressions=all --suppressions=$source_path/tests/fate-valgrind.supp"
;;
msvc)
# Check whether the current MSVC version needs the C99 converter.
# From MSVC 2013 (compiler major version 18) onwards, it does actually
- # support enough of C99 to build libav. Default to the new
+ # support enough of C99 to build ffmpeg. Default to the new
# behaviour if the regexp was unable to match anything, since this
# successfully parses the version number of existing supported
# versions that require the converter (MSVC 2010 and 2012).
@@ -2624,20 +3155,32 @@ fi
ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
+cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"
-ranlib="${cross_prefix}${ranlib}"
-strip="${cross_prefix}${strip}"
+ranlib_default="${cross_prefix}${ranlib_default}"
+strip_default="${cross_prefix}${strip_default}"
+windres_default="${cross_prefix}${windres_default}"
sysinclude_default="${sysroot}/usr/include"
-set_default arch cc pkg_config sysinclude target_exec target_os
+set_default arch cc cxx doxygen pkg_config ranlib strip sysinclude \
+ target_exec target_os yasmexe
enabled cross_compile || host_cc_default=$cc
set_default host_cc
+pkg_config_fail_message=""
if ! $pkg_config --version >/dev/null 2>&1; then
warn "$pkg_config not found, library detection may fail."
pkg_config=false
+elif is_in -static $cc $LDFLAGS && ! is_in --static $pkg_config $pkg_config_flags; then
+ pkg_config_fail_message="
+Note: When building a static binary, add --pkg-config-flags=\"--static\"."
+fi
+
+if test $doxygen != $doxygen_default && \
+ ! $doxygen --version >/dev/null 2>&1; then
+ warn "Specified doxygen \"$doxygen\" not found, API documentation will fail to build."
fi
exesuf() {
@@ -2654,7 +3197,11 @@ HOSTEXESUF=$(exesuf $host_os)
: ${TMPDIR:=$TMP}
: ${TMPDIR:=/tmp}
-if ! check_cmd mktemp -u XXXXXX; then
+if [ -n "$tempprefix" ] ; then
+ mktemp(){
+ echo $tempprefix.${HOSTNAME}.${UID}
+ }
+elif ! check_cmd mktemp -u XXXXXX; then
# simple replacement for missing mktemp
# NOT SAFE FOR GENERAL USE
mktemp(){
@@ -2674,8 +3221,10 @@ trap 'rm -f -- $TMPFILES' EXIT
tmpfile TMPASM .asm
tmpfile TMPC .c
+tmpfile TMPCPP .cpp
tmpfile TMPE $EXESUF
tmpfile TMPH .h
+tmpfile TMPM .m
tmpfile TMPO .o
tmpfile TMPS .S
tmpfile TMPSH .sh
@@ -2773,6 +3322,7 @@ msvc_flags(){
-Wall) echo -W4 -wd4244 -wd4127 -wd4018 -wd4389 \
-wd4146 -wd4057 -wd4204 -wd4706 -wd4305 \
-wd4152 -wd4324 -we4013 -wd4100 -wd4214 \
+ -wd4307 \
-wd4273 -wd4554 -wd4701 ;;
esac
done
@@ -2786,6 +3336,16 @@ icl_flags(){
# on Windows, does enable remarks so disable them here.
-Wall) echo $flag -Qdiag-disable:remark ;;
-std=c99) echo -Qstd=c99 ;;
+ -flto) echo -ipo ;;
+ esac
+ done
+}
+
+icc_flags(){
+ for flag; do
+ case $flag in
+ -flto) echo -ipo ;;
+ *) echo $flag ;;
esac
done
}
@@ -2818,9 +3378,16 @@ suncc_flags(){
prescott|nocona) echo -xarch=sse3 -xchip=pentium4 ;;
*-sse3) echo -xarch=sse3 ;;
core2) echo -xarch=ssse3 -xchip=core2 ;;
- corei7) echo -xarch=sse4_2 -xchip=nehalem ;;
- corei7-avx) echo -xarch=avx -xchip=sandybridge ;;
- amdfam10|barcelona|bdver*) echo -xarch=sse4_1 ;;
+ bonnell) echo -xarch=ssse3 ;;
+ corei7|nehalem) echo -xtarget=nehalem ;;
+ westmere) echo -xtarget=westmere ;;
+ silvermont) echo -xarch=sse4_2 ;;
+ corei7-avx|sandybridge) echo -xtarget=sandybridge ;;
+ core-avx*|ivybridge|haswell|broadwell)
+ echo -xarch=avx ;;
+ amdfam10|barcelona) echo -xtarget=barcelona ;;
+ btver1) echo -xarch=amdsse4a ;;
+ btver2|bdver*) echo -xarch=avx ;;
athlon-4|athlon-[mx]p) echo -xarch=ssea ;;
k8|opteron|athlon64|athlon-fx)
echo -xarch=sse2a ;;
@@ -2876,7 +3443,9 @@ probe_cc(){
unset _depflags _DEPCMD _DEPFLAGS
_flags_filter=echo
- if $_cc -v 2>&1 | grep -q '^gcc.*LLVM'; then
+ if $_cc --version 2>&1 | grep -q '^GNU assembler'; then
+ true # no-op to avoid reading stdin in following checks
+ elif $_cc -v 2>&1 | grep -q '^gcc.*LLVM'; then
_type=llvm_gcc
gcc_extra_ver=$(expr "$($_cc --version | head -n1)" : '.*\((.*)\)')
_ident="llvm-gcc $($_cc -dumpversion) $gcc_extra_ver"
@@ -2902,6 +3471,7 @@ probe_cc(){
_cflags_speed='-O3'
_cflags_size='-Os'
_cflags_noopt='-O1'
+ _flags_filter=icc_flags
elif $_cc -v 2>&1 | grep -q xlc; then
_type=xlc
_ident=$($_cc -qversion 2>/dev/null | head -n1)
@@ -2975,7 +3545,7 @@ probe_cc(){
opt_common='-alias=ansi -Mdse -Mlre -Mpre'
_cflags_speed="-O3 -Mautoinline -Munroll=c:4 $opt_common"
_cflags_size="-O2 -Munroll=c:1 $opt_common"
- _cflags_noopt="-O1"
+ _cflags_noopt="-O"
_flags_filter=pgi_flags
elif $_cc 2>&1 | grep -q 'Microsoft.*ARM.*Assembler'; then
_type=armasm
@@ -2983,54 +3553,58 @@ probe_cc(){
# 4509: "This form of conditional instruction is deprecated"
_flags="-nologo -ignore 4509"
_flags_filter=armasm_flags
- elif $_cc 2>&1 | grep -q Microsoft; then
- _type=msvc
+ elif $_cc 2>&1 | grep -q Intel; then
+ _type=icl
_ident=$($_cc 2>&1 | head -n1)
- _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)'
- _DEPFLAGS='$(CPPFLAGS) $(CFLAGS) -showIncludes -Zs'
+ _depflags='-QMMD -QMF$(@:.o=.d) -QMT$@'
+ # Not only is O3 broken on 13.x+ but it is slower on all previous
+ # versions (tested) as well.
_cflags_speed="-O2"
- _cflags_size="-O1"
+ _cflags_size="-O1 -Oi" # -O1 without -Oi miscompiles stuff
if $_cc 2>&1 | grep -q Linker; then
_ld_o='-out:$@'
else
_ld_o='-Fe$@'
fi
_cc_o='-Fo$@'
- _cc_e='-P -Fi$@'
- _flags_filter=msvc_flags
+ _cc_e='-P'
+ _flags_filter=icl_flags
_ld_lib='lib%.a'
_ld_path='-libpath:'
- _flags='-nologo'
- _cflags='-D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -Dinline=__inline -FIstdlib.h -Dstrtoll=_strtoi64'
+ # -Qdiag-error to make icl error when seeing certain unknown arguments
+ _flags='-nologo -Qdiag-error:4044,10157'
+ # -Qvec- -Qsimd- to prevent miscompilation, -GS, fp:precise for consistency
+ # with MSVC which enables it by default.
+ _cflags='-D_USE_MATH_DEFINES -FIstdlib.h -Dstrtoll=_strtoi64 -Qms0 -Qvec- -Qsimd- -GS -fp:precise'
if [ $pfx = hostcc ]; then
append _cflags -Dsnprintf=_snprintf
fi
- elif $_cc 2>&1 | grep -q Intel; then
- _type=icl
+ disable stripping
+ elif $_cc 2>&1 | grep -q Microsoft; then
+ _type=msvc
_ident=$($_cc 2>&1 | head -n1)
- _depflags='-QMMD -QMF$(@:.o=.d) -QMT$@'
- # Not only is O3 broken on 13.x+ but it is slower on all previous
- # versions (tested) as well.
+ _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)'
+ _DEPFLAGS='$(CPPFLAGS) $(CFLAGS) -showIncludes -Zs'
_cflags_speed="-O2"
- _cflags_size="-O1 -Oi" # -O1 without -Oi miscompiles stuff
+ _cflags_size="-O1"
if $_cc 2>&1 | grep -q Linker; then
_ld_o='-out:$@'
else
_ld_o='-Fe$@'
fi
_cc_o='-Fo$@'
- _cc_e='-P'
- _flags_filter=icl_flags
+ _cc_e='-P -Fi$@'
+ _flags_filter=msvc_flags
_ld_lib='lib%.a'
_ld_path='-libpath:'
- # -Qdiag-error to make icl error when seeing certain unknown arguments
- _flags='-nologo -Qdiag-error:4044,10157'
- # -Qvec- -Qsimd- to prevent miscompilation, -GS for consistency
- # with MSVC which enables it by default.
- _cflags='-D_USE_MATH_DEFINES -FIstdlib.h -Dstrtoll=_strtoi64 -Qms0 -Qvec- -Qsimd- -GS'
+ _flags='-nologo'
+ _cflags='-D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -Dinline=__inline -FIstdlib.h -Dstrtoll=_strtoi64'
if [ $pfx = hostcc ]; then
- append _cflags -Dsnprintf=_snprintf
+ if [ -z "$cl_major_ver" ] || [ $cl_major_ver -le 18 ]; then
+ append _cflags -Dsnprintf=_snprintf
+ fi
fi
+ disable stripping
elif $_cc --version 2>/dev/null | grep -q ^cparser; then
_type=cparser
_ident=$($_cc --version | head -n1)
@@ -3079,7 +3653,7 @@ test -n "$cc_type" && enable $cc_type ||
: ${dep_cc_default:=$cc}
: ${ld_default:=$cc}
: ${host_ld_default:=$host_cc}
-set_default ar as dep_cc ld host_ld
+set_default ar as dep_cc ld host_ld windres
probe_cc as "$as"
asflags_filter=$_flags_filter
@@ -3115,12 +3689,16 @@ elif $ar 2>&1 | grep -q 'Texas Instruments'; then
elif $ar 2>&1 | grep -q 'Usage: ar.*-X.*any'; then
arflags='-Xany -r -c'
ar_o='$@'
+elif $ar 2>&1 | grep -q "\[D\] "; then
+ arflags="rcD"
+ ar_o='$@'
else
arflags="rc"
ar_o='$@'
fi
add_cflags $extra_cflags
+add_cxxflags $extra_cxxflags
add_asflags $extra_cflags
if test -n "$sysroot"; then
@@ -3128,6 +3706,9 @@ if test -n "$sysroot"; then
gcc|llvm_gcc|clang)
add_cppflags --sysroot="$sysroot"
add_ldflags --sysroot="$sysroot"
+# On Darwin --sysroot may be ignored, -isysroot always affects headers and linking
+ add_cppflags -isysroot "$sysroot"
+ add_ldflags -isysroot "$sysroot"
;;
tms470)
add_cppflags -I"$sysinclude"
@@ -3163,7 +3744,7 @@ case "$arch" in
aarch64|arm64)
arch="aarch64"
;;
- arm*)
+ arm*|iPad*|iPhone*)
arch="arm"
;;
mips*|IP*)
@@ -3187,7 +3768,7 @@ case "$arch" in
tilegx|tile-gx)
arch="tilegx"
;;
- i[3-6]86|i86pc|BePC|x86pc|x86_64|amd64)
+ i[3-6]86*|i86pc|BePC|x86pc|x86_64|x86_32|amd64)
arch="x86"
;;
esac
@@ -3266,7 +3847,10 @@ elif enabled arm; then
case "$subarch" in
armv5t*) enable fast_clz ;;
- armv[6-8]*) enable fast_clz fast_unaligned ;;
+ armv[6-8]*)
+ enable fast_clz
+ disabled fast_unaligned || enable fast_unaligned
+ ;;
esac
elif enabled avr32; then
@@ -3298,9 +3882,90 @@ elif enabled mips; then
cpuflags="-march=$cpu"
+ case $cpu in
+ 24kc)
+ disable mips32r5
+ disable mips64r6
+ disable mipsfpu
+ disable mipsdspr1
+ disable mipsdspr2
+ disable msa
+ ;;
+ 24kf*)
+ disable mips32r5
+ disable mips64r6
+ disable mipsdspr1
+ disable mipsdspr2
+ disable msa
+ ;;
+ 24kec|34kc|1004kc)
+ disable mips32r5
+ disable mips64r6
+ disable mipsfpu
+ disable mipsdspr2
+ disable msa
+ ;;
+ 24kef*|34kf*|1004kf*)
+ disable mips32r5
+ disable mips64r6
+ disable mipsdspr2
+ disable msa
+ ;;
+ 74kc)
+ disable mips32r5
+ disable mips64r6
+ disable mipsfpu
+ disable msa
+ ;;
+ 74kf)
+ disable mips32r5
+ disable mips64r6
+ disable msa
+ ;;
+ p5600)
+ disable mips64r6
+ disable mipsdspr1
+ disable mipsdspr2
+
+ check_cflags "-mtune=p5600"
+ ;;
+ i6400)
+ disable mips32r5
+ disable mipsdspr1
+ disable mipsdspr2
+ disable mipsfpu
+
+ check_cflags "-mtune=i6400 -mabi=64"
+ check_ldflags "-mabi=64"
+ ;;
+ loongson3*)
+ disable mipsfpu
+ disable mips32r2
+ disable mips32r5
+ disable mips64r6
+ disable mipsdspr1
+ disable mipsdspr2
+ disable msa
+ enable local_aligned_8 local_aligned_16
+ enable simd_align_16
+ enable fast_64bit
+ enable fast_clz
+ enable fast_cmov
+ enable fast_unaligned
+ disable aligned_stack
+ cpuflags="-march=loongson3a -mhard-float"
+ ;;
+ generic)
+ disable mips32r5
+ disable mips64r6
+ disable msa
+ ;;
+ esac
+
elif enabled ppc; then
disable ldbrx
+ disable vsx
case $(tolower $cpu) in
601|ppc601|powerpc601)
@@ -3328,7 +3993,7 @@ elif enabled ppc; then
g5|970|ppc970|powerpc970)
cpuflags="-mcpu=970"
;;
- power[3-7]*)
+ power[3-8]*)
cpuflags="-mcpu=$cpu"
;;
cell)
@@ -3376,7 +4041,8 @@ elif enabled x86; then
disable i686
;;
# targets that do support nopl and conditional mov (cmov)
- i686|pentiumpro|pentium[23]|pentium-m|athlon|athlon-tbird|athlon-4|athlon-[mx]p|athlon64*|k8*|opteron*|athlon-fx|core2|corei7*|amdfam10|barcelona|atom|bdver*)
+ i686|pentiumpro|pentium[23]|pentium-m|athlon|athlon-tbird|athlon-4|athlon-[mx]p|athlon64*|k8*|opteron*|athlon-fx\
+ |core*|atom|bonnell|nehalem|westmere|silvermont|sandybridge|ivybridge|haswell|broadwell|amdfam10|barcelona|b[dt]ver*)
cpuflags="-march=$cpu"
enable i686
enable fast_cmov
@@ -3410,6 +4076,7 @@ if test "$?" != 0; then
fi
add_cppflags -D_ISOC99_SOURCE
+add_cxxflags -D__STDC_CONSTANT_MACROS
check_cflags -std=c99
check_cc -D_FILE_OFFSET_BITS=64 <<EOF && add_cppflags -D_FILE_OFFSET_BITS=64
#include <stdlib.h>
@@ -3457,10 +4124,18 @@ case "$arch" in
;;
x86)
check_64bit x86_32 x86_64 'sizeof(void *) > 4'
+ # Treat x32 as x64 for now. Note it also needs spic=$shared
+ test "$subarch" = "x86_32" && check_cpp_condition stddef.h 'defined(__x86_64__)' &&
+ subarch=x86_64
if test "$subarch" = "x86_64"; then
spic=$shared
fi
;;
+ ppc)
+ check_cc <<EOF && subarch="ppc64"
+ int test[(int)sizeof(char*) - 7];
+EOF
+ ;;
esac
enable $subarch
@@ -3490,6 +4165,7 @@ case $target_os in
SHFLAGS='-shared -Wl,-h,$$(@F)'
enabled x86 && SHFLAGS="-mimpure-text $SHFLAGS"
network_extralibs="-lsocket -lnsl"
+ add_cppflags -D__EXTENSIONS__
# When using suncc to build, the Solaris linker will mark
# an executable with each instruction set encountered by
# the Solaris assembler. As our libraries contain their own
@@ -3504,6 +4180,7 @@ case $target_os in
disable symver
oss_indev_extralibs="-lossaudio"
oss_outdev_extralibs="-lossaudio"
+ enabled gcc || check_ldflags -Wl,-zmuldefs
;;
openbsd|bitrig)
disable symver
@@ -3520,18 +4197,20 @@ case $target_os in
;;
bsd/os)
add_extralibs -lpoll -lgnugetopt
+ strip="strip -d"
;;
darwin)
enabled ppc && add_asflags -force_cpusubtype_ALL
SHFLAGS='-dynamiclib -Wl,-single_module -Wl,-install_name,$(SHLIBDIR)/$(SLIBNAME_WITH_MAJOR),-current_version,$(LIBVERSION),-compatibility_version,$(LIBMAJOR)'
enabled x86_32 && append SHFLAGS -Wl,-read_only_relocs,suppress
+ strip="${strip} -x"
add_ldflags -Wl,-dynamic,-search_paths_first
SLIBSUF=".dylib"
SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME).$(LIBVERSION)$(SLIBSUF)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME).$(LIBMAJOR)$(SLIBSUF)'
objformat="macho"
enabled x86_64 && objformat="macho64"
- enabled_any pic shared ||
+ enabled_any pic shared x86_64 ||
{ check_cflags -mdynamic-no-pic && add_asflags -mdynamic-no-pic; }
;;
mingw32*)
@@ -3546,21 +4225,30 @@ case $target_os in
elif enabled arm; then
LIBTARGET=arm-wince
fi
+ enabled shared && ! enabled small && check_cmd $windres --version && enable gnu_windres
check_ldflags -Wl,--nxcompat
check_ldflags -Wl,--dynamicbase
+ enabled x86_32 && check_ldflags -Wl,--large-address-aware
shlibdir_default="$bindir_default"
SLIBPREF=""
SLIBSUF=".dll"
SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
- SLIB_EXTRA_CMD=-'sed -e "s/ @[^ ]*//" $$(@:$(SLIBSUF)=.orig.def) > $$(@:$(SLIBSUF)=.def); $(DLLTOOL) -m $(LIBTARGET) -d $$(@:$(SLIBSUF)=.def) -l $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib) -D $(SLIBNAME_WITH_MAJOR)'
+ dlltool="${cross_prefix}dlltool"
+ if check_cmd lib.exe -list; then
+ SLIB_EXTRA_CMD=-'sed -e "s/ @[^ ]*//" $$(@:$(SLIBSUF)=.orig.def) > $$(@:$(SLIBSUF)=.def); lib.exe /machine:$(LIBTARGET) /def:$$(@:$(SLIBSUF)=.def) /out:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)'
+ if enabled x86_64; then
+ LIBTARGET=x64
+ fi
+ elif check_cmd $dlltool --version; then
+ SLIB_EXTRA_CMD=-'sed -e "s/ @[^ ]*//" $$(@:$(SLIBSUF)=.orig.def) > $$(@:$(SLIBSUF)=.def); $(DLLTOOL) -m $(LIBTARGET) -d $$(@:$(SLIBSUF)=.def) -l $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib) -D $(SLIBNAME_WITH_MAJOR)'
+ fi
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS=
SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)'
SLIB_INSTALL_EXTRA_LIB='lib$(SLIBNAME:$(SLIBSUF)=.dll.a) $(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=.def)'
SHFLAGS='-shared -Wl,--output-def,$$(@:$(SLIBSUF)=.orig.def) -Wl,--out-implib,$(SUBDIR)lib$(SLIBNAME:$(SLIBSUF)=.dll.a) -Wl,--enable-runtime-pseudo-reloc -Wl,--enable-auto-image-base'
objformat="win32"
- dlltool="${cross_prefix}dlltool"
ranlib=:
enable dos_paths
;;
@@ -3573,6 +4261,7 @@ case $target_os in
# Cannot build both shared and static libs with MSVC or icl.
disable static
fi
+ enabled x86_32 && check_ldflags -LARGEADDRESSAWARE
shlibdir_default="$bindir_default"
SLIBPREF=""
SLIBSUF=".dll"
@@ -3601,6 +4290,7 @@ case $target_os in
SHFLAGS='-shared -Wl,--out-implib,$(SUBDIR)lib$(FULLNAME).dll.a'
objformat="win32"
enable dos_paths
+ enabled shared && ! enabled small && check_cmd $windres --version && enable gnu_windres
;;
*-dos|freedos|opendos)
network_extralibs="-lsocket"
@@ -3617,6 +4307,7 @@ case $target_os in
ranlib="echo ignoring ranlib"
;;
os/2*)
+ strip="lxlite -CS"
ln_s="cp -f"
objformat="aout"
add_cppflags -D_GNU_SOURCE
@@ -3628,15 +4319,15 @@ case $target_os in
SLIBNAME_WITH_VERSION='$(SLIBPREF)$(NAME)-$(LIBVERSION)$(SLIBSUF)'
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(shell echo $(NAME) | cut -c1-6)$(LIBMAJOR)$(SLIBSUF)'
SLIB_CREATE_DEF_CMD='echo LIBRARY $(SLIBNAME_WITH_MAJOR) INITINSTANCE TERMINSTANCE > $(SUBDIR)$(NAME).def; \
- echo PROTMODE >> $(SUBDIR)$(NAME).def; \
echo CODE PRELOAD MOVEABLE DISCARDABLE >> $(SUBDIR)$(NAME).def; \
echo DATA PRELOAD MOVEABLE MULTIPLE NONSHARED >> $(SUBDIR)$(NAME).def; \
echo EXPORTS >> $(SUBDIR)$(NAME).def; \
- emxexp -o $(OBJS) >> $(SUBDIR)$(NAME).def'
+ emxexp $(OBJS) >> $(SUBDIR)$(NAME).def'
SLIB_EXTRA_CMD='emximp -o $(SUBDIR)$(LIBPREF)$(NAME)_dll.a $(SUBDIR)$(NAME).def; \
emximp -o $(SUBDIR)$(LIBPREF)$(NAME)_dll.lib $(SUBDIR)$(NAME).def;'
SLIB_INSTALL_EXTRA_LIB='$(LIBPREF)$(NAME)_dll.a $(LIBPREF)$(NAME)_dll.lib'
enable dos_paths
+ enable_weak os2threads
;;
gnu/kfreebsd)
add_cppflags -D_BSD_SOURCE
@@ -3673,6 +4364,7 @@ case $target_os in
add_compat strtod.o strtod=avpriv_strtod
network_extralibs='-lbsd'
exeobjs=compat/plan9/main.o
+ disable ffserver
cp_f='cp'
;;
none)
@@ -3701,6 +4393,10 @@ probe_libc(){
# MinGW64 is backwards compatible with MinGW32, so check for it first.
elif check_${pfx}cpp_condition _mingw.h "defined __MINGW64_VERSION_MAJOR"; then
eval ${pfx}libc_type=mingw64
+ if check_${pfx}cpp_condition _mingw.h "__MINGW64_VERSION_MAJOR < 3"; then
+ add_compat msvcrt/snprintf.o
+ add_cflags "-include $source_path/compat/msvcrt/snprintf.h"
+ fi
add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1
eval test \$${pfx_no_}cc_type = "gcc" &&
add_${pfx}cppflags -D__printf__=__gnu_printf__
@@ -3730,10 +4426,16 @@ probe_libc(){
elif check_${pfx}cpp_condition sys/brand.h "defined LABELED_BRAND_NAME"; then
eval ${pfx}libc_type=solaris
add_${pfx}cppflags -D__EXTENSIONS__ -D_XOPEN_SOURCE=600
- else
- eval ${pfx}libc_type=default
- add_${pfx}cppflags -D_DEFAULT_SOURCE
fi
+ check_${pfx}cc <<EOF
+#include <time.h>
+void *v = localtime_r;
+EOF
+test "$?" != 0 && check_${pfx}cc -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 <<EOF && add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600
+#include <time.h>
+void *v = localtime_r;
+EOF
+
}
probe_libc
@@ -3746,10 +4448,12 @@ case $libc_type in
add_compat strtod.o strtod=avpriv_strtod
;;
msvcrt)
- add_compat strtod.o strtod=avpriv_strtod
- add_compat msvcrt/snprintf.o snprintf=avpriv_snprintf \
- _snprintf=avpriv_snprintf \
- vsnprintf=avpriv_vsnprintf
+ if [ -z "$cl_major_ver" ] || [ $cl_major_ver -le 18 ]; then
+ add_compat strtod.o strtod=avpriv_strtod
+ add_compat msvcrt/snprintf.o snprintf=avpriv_snprintf \
+ _snprintf=avpriv_snprintf \
+ vsnprintf=avpriv_vsnprintf
+ fi
;;
esac
@@ -3774,10 +4478,13 @@ esc(){
echo "$*" | sed 's/%/%25/g;s/:/%3a/g'
}
-echo "config:$arch:$subarch:$cpu:$target_os:$(esc $cc_ident):$(esc $LIBAV_CONFIGURATION)" >config.fate
+echo "config:$arch:$subarch:$cpu:$target_os:$(esc $cc_ident):$(esc $FFMPEG_CONFIGURATION)" >config.fate
check_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable_weak pic
+set_default libdir
+: ${shlibdir_default:="$libdir"}
+
set_default $PATHS_LIST
set_default nm
@@ -3796,19 +4503,31 @@ die_license_disabled() {
enabled $1 || { enabled $2 && die "$2 is $1 and --enable-$1 is not specified."; }
}
+die_license_disabled_gpl() {
+ enabled $1 || { enabled $2 && die "$2 is incompatible with the gpl and --enable-$1 is not specified."; }
+}
+
+die_license_disabled gpl frei0r
die_license_disabled gpl libcdio
+die_license_disabled gpl libsmbclient
+die_license_disabled gpl libutvideo
+die_license_disabled gpl libvidstab
die_license_disabled gpl libx264
die_license_disabled gpl libx265
die_license_disabled gpl libxavs
die_license_disabled gpl libxvid
+die_license_disabled gpl libzvbi
die_license_disabled gpl x11grab
+die_license_disabled nonfree libaacplus
die_license_disabled nonfree libfaac
-die_license_disabled nonfree libfdk_aac
-die_license_disabled nonfree openssl
+die_license_disabled nonfree nvenc
+enabled gpl && die_license_disabled_gpl nonfree libfdk_aac
+enabled gpl && die_license_disabled_gpl nonfree openssl
die_license_disabled version3 libopencore_amrnb
die_license_disabled version3 libopencore_amrwb
+die_license_disabled version3 libsmbclient
die_license_disabled version3 libvo_aacenc
die_license_disabled version3 libvo_amrwbenc
@@ -3866,6 +4585,12 @@ unsigned int endian = 'B' << 24 | 'I' << 16 | 'G' << 8 | 'E';
EOF
od -t x1 $TMPO | grep -q '42 *49 *47 *45' && enable bigendian
+if [ "$cpu" = "power7" ] || [ "$cpu" = "power8" ] || enabled ppc64; then
+ if ! enabled bigendian && enabled altivec ;then
+ enable vsx
+ fi
+fi
+
check_gas() {
log "check_gas using '$as' as AS"
# :vararg is used on aarch64, arm and ppc altivec
@@ -3886,7 +4611,7 @@ EOF
if enabled_any arm aarch64 || enabled_all ppc altivec && enabled asm; then
nogas=:
enabled_any arm aarch64 && nogas=die
- enabled_all ppc altivec && nogas=warn
+ enabled_all ppc altivec && [ $target_os_default != aix ] && nogas=warn
as_noop=-v
case $as_type in
@@ -3897,8 +4622,9 @@ if enabled_any arm aarch64 || enabled_all ppc altivec && enabled asm; then
[ $target_os = "darwin" ] && gaspp_as_type="apple-$gaspp_as_type"
- check_cmd gas-preprocessor.pl -arch $arch -as-type $gaspp_as_type -- $as $as_noop &&
- gas="gas-preprocessor.pl -arch $arch -as-type $gaspp_as_type -- $as"
+ test "${as#*gas-preprocessor.pl}" != "$as" ||
+ check_cmd gas-preprocessor.pl -arch $arch -as-type $gaspp_as_type -- ${as:=$cc} $as_noop &&
+ gas="${gas:=gas-preprocessor.pl} -arch $arch -as-type $gaspp_as_type -- ${as:=$cc}"
if ! check_gas ; then
as=${gas:=$as}
@@ -3914,6 +4640,8 @@ fi
check_inline_asm inline_asm_labels '"1:\n"'
+check_inline_asm inline_asm_nonlocal_labels '"Label:\n"'
+
if enabled aarch64; then
enabled armv8 && check_insn armv8 'prfm pldl1strm, [x0]'
# internal assembler in clang 3.3 does not support this instruction
@@ -3928,7 +4656,10 @@ elif enabled alpha; then
elif enabled arm; then
- check_cpp_condition stddef.h "defined __thumb__" && enable_weak thumb
+ check_cpp_condition stddef.h "defined __thumb__" && check_cc <<EOF && enable_weak thumb
+float func(float a, float b){ return a+b; }
+EOF
+
enabled thumb && check_cflags -mthumb || check_cflags -marm
if check_cpp_condition stddef.h "defined __ARM_PCS_VFP"; then
@@ -3936,7 +4667,7 @@ elif enabled arm; then
elif ! check_cpp_condition stddef.h "defined __ARM_PCS || defined __SOFTFP__"; then
case "${cross_prefix:-$cc}" in
*hardfloat*) enable vfp_args; fpabi=vfp ;;
- *) check_ld <<EOF && enable vfp_args && fpabi=vfp || fpabi=soft ;;
+ *) check_ld "cc" <<EOF && enable vfp_args && fpabi=vfp || fpabi=soft ;;
__asm__ (".eabi_attribute 28, 1");
int main(void) { return 0; }
EOF
@@ -3950,6 +4681,7 @@ EOF
enabled neon && check_insn neon 'vadd.i16 q0, q0, q0'
enabled vfp && check_insn vfp 'fadds s0, s0, s0'
enabled vfpv3 && check_insn vfpv3 'vmov.f32 s0, #1.0'
+ enabled setend && check_insn setend 'setend be'
[ $target_os = linux ] || [ $target_os = android ] ||
map 'enabled_any ${v}_external ${v}_inline || disable $v' \
@@ -3971,19 +4703,52 @@ EOF
elif enabled mips; then
- check_inline_asm loongson '"dmult.g $1, $2, $3"'
+ # Enable minimum ISA based on selected options
+ if enabled mips64 && (enabled mipsdspr1 || enabled mipsdspr2); then
+ add_cflags "-mips64r2"
+ add_asflags "-mips64r2"
+ elif enabled mips64 && enabled mipsfpu && disabled loongson3; then
+ add_cflags "-mips64"
+ add_asflags "-mips64"
+ elif enabled mipsdspr1 || enabled mipsdspr2; then
+ add_cflags "-mips32r2 -mfp32"
+ add_asflags "-mips32r2 -mfp32"
+ elif enabled mips32r5 || enabled mips64r6; then
+ check_cflags "-mfp64"
+ check_ldflags "-mfp64"
+ fi
+
+ enabled mips32r5 && check_cflags "-mips32r5 -msched-weight -mload-store-pairs -funroll-loops" &&
+ check_ldflags "-mips32r5" &&
+ check_inline_asm mips32r5 '"ulw $t0, ($t1)"'
+ enabled mips64r6 && check_cflags "-mips64r6 -msched-weight -mload-store-pairs -funroll-loops" &&
+ check_ldflags "-mips64r6" &&
+ check_inline_asm mips64r6 '"aui $t0, $t1, 1"'
+ enabled mipsdspr1 && add_cflags "-mdsp" && add_asflags "-mdsp" &&
+ check_inline_asm mipsdspr1 '"addu.qb $t0, $t1, $t2"'
+ enabled mipsdspr2 && add_cflags "-mdspr2" && add_asflags "-mdspr2" &&
+ check_inline_asm mipsdspr2 '"absq_s.qb $t0, $t1"'
+ enabled mipsfpu && add_cflags "-mhard-float" && add_asflags "-mhard-float" &&
+ check_inline_asm mipsfpu '"madd.d $f0, $f2, $f4, $f6"'
+ enabled msa && check_cflags "-mmsa" && check_ldflags "-mmsa" &&
+ check_inline_asm msa '"addvi.b $w0, $w1, 1"'
+ enabled loongson3 && check_inline_asm loongson3 '"gsldxc1 $f0, 0($2, $3)"'
+
+ enabled mips32r5 && add_asflags "-mips32r5 -mfp64"
+ enabled mips64r6 && add_asflags "-mips64r6 -mfp64"
+ enabled msa && add_asflags "-mmsa"
elif enabled parisc; then
if enabled gcc; then
case $($cc -dumpversion) in
- 4.[3-8].*) check_cflags -fno-optimize-sibling-calls ;;
+ 4.[3-9].*) check_cflags -fno-optimize-sibling-calls ;;
esac
fi
elif enabled ppc; then
- enable local_aligned_8 local_aligned_16
+ enable local_aligned_8 local_aligned_16 local_aligned_32
check_inline_asm dcbzl '"dcbzl 0, %0" :: "r"(0)'
check_inline_asm ibm_asm '"add 0, 0, 0"'
@@ -4010,12 +4775,15 @@ EOF
enabled altivec || warn "Altivec disabled, possibly missing --cpu flag"
fi
+ if enabled vsx; then
+ check_cflags -mvsx
+ fi
elif enabled x86; then
check_builtin rdtsc intrin.h "__rdtsc()"
check_builtin mm_empty mmintrin.h "_mm_empty()"
- enable local_aligned_8 local_aligned_16
+ enable local_aligned_8 local_aligned_16 local_aligned_32
# check whether EBP is available on x86
# As 'i' is stored on the stack, this program will crash
@@ -4034,6 +4802,9 @@ EOF
# check whether xmm clobbers are supported
check_inline_asm xmm_clobbers '"":::"%xmm0"'
+ check_inline_asm inline_asm_direct_symbol_refs '"movl '$extern_prefix'test, %eax"' ||
+ check_inline_asm inline_asm_direct_symbol_refs '"movl '$extern_prefix'test(%rip), %eax"'
+
# check whether binutils is new enough to compile SSSE3/MMXEXT
enabled ssse3 && check_inline_asm ssse3_inline '"pabsw %xmm0, %xmm0"'
enabled mmxext && check_inline_asm mmxext_inline '"pmaxub %mm0, %mm1"'
@@ -4045,7 +4816,12 @@ EOF
elif check_cmd nasm -v; then
yasmexe=nasm
yasm_debug="-g -F dwarf"
- enabled x86_64 && test "$objformat" = elf && objformat=elf64
+ if enabled x86_64; then
+ case "$objformat" in
+ elf) objformat=elf64 ;;
+ win32) objformat=win64 ;;
+ esac
+ fi
fi
YASMFLAGS="-f $objformat $yasm_extra"
@@ -4057,8 +4833,8 @@ EOF
check_yasm "movbe ecx, [5]" && enable yasm ||
die "yasm/nasm not found or too old. Use --disable-yasm for a crippled build."
+ check_yasm "vextracti128 xmm0, ymm0, 0" || disable avx2_external
check_yasm "vpmacsdd xmm0, xmm1, xmm2, xmm3" || disable xop_external
- check_yasm "vfmadd132ps ymm0, ymm1, ymm2" || disable fma3_external
check_yasm "vfmaddps ymm0, ymm1, ymm2, ymm3" || disable fma4_external
check_yasm "CPU amdnop" || disable cpunop
fi
@@ -4074,6 +4850,7 @@ fi
check_code cc arm_neon.h "int16x8_t test = vdupq_n_s16(0)" && enable intrinsics_neon
check_ldflags -Wl,--as-needed
+check_ldflags -Wl,-z,noexecstack
if check_func dlopen; then
ldl=
@@ -4081,6 +4858,11 @@ elif check_func dlopen -ldl; then
ldl=-ldl
fi
+frei0r_filter_extralibs='$ldl'
+frei0r_src_filter_extralibs='$ldl'
+ladspa_filter_extralibs='$ldl'
+nvenc_encoder_extralibs='$ldl'
+
if ! disabled network; then
check_func getaddrinfo $network_extralibs
check_func getservbyport $network_extralibs
@@ -4122,17 +4904,18 @@ if ! disabled network; then
fi
check_builtin atomic_cas_ptr atomic.h "void **ptr; void *oldval, *newval; atomic_cas_ptr(ptr, oldval, newval)"
+check_builtin atomic_compare_exchange "" "int *ptr, *oldval; int newval; __atomic_compare_exchange_n(ptr, oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)"
check_builtin machine_rw_barrier mbarrier.h "__machine_rw_barrier()"
check_builtin MemoryBarrier windows.h "MemoryBarrier()"
+check_builtin sarestart signal.h "SA_RESTART"
check_builtin sync_val_compare_and_swap "" "int *ptr; int oldval, newval; __sync_val_compare_and_swap(ptr, oldval, newval)"
check_func_headers malloc.h _aligned_malloc && enable aligned_malloc
check_func ${malloc_prefix}memalign && enable memalign
check_func ${malloc_prefix}posix_memalign && enable posix_memalign
-check_cpp_condition unistd.h "defined(_POSIX_MONOTONIC_CLOCK)" &&
- check_func_headers time.h clock_gettime || { check_func_headers time.h clock_gettime -lrt && add_extralibs -lrt && LIBRT="-lrt"; }
-
+check_func access
+check_func_headers time.h clock_gettime || { check_func_headers time.h clock_gettime -lrt && add_extralibs -lrt && LIBRT="-lrt"; }
check_func fcntl
check_func fork
check_func gethrtime
@@ -4147,15 +4930,18 @@ check_func mkstemp
check_func mmap
check_func mprotect
# Solaris has nanosleep in -lrt, OpenSolaris no longer needs that
-check_func_headers time.h nanosleep || { check_func_headers time.h nanosleep -lrt && add_extralibs -lrt; }
+check_func_headers time.h nanosleep || { check_func_headers time.h nanosleep -lrt && add_extralibs -lrt && LIBRT="-lrt"; }
check_func sched_getaffinity
check_func setrlimit
+check_struct "sys/stat.h" "struct stat" st_mtim.tv_nsec -D_BSD_SOURCE
check_func strerror_r
check_func sysconf
check_func sysctl
check_func usleep
+check_func_headers conio.h kbhit
check_func_headers io.h setmode
+check_func_headers lzo/lzo1x.h lzo1x_999_compress
check_func_headers stdlib.h getenv
check_func_headers windows.h CoTaskMemFree -lole32
@@ -4163,19 +4949,25 @@ check_func_headers windows.h GetProcessAffinityMask
check_func_headers windows.h GetProcessTimes
check_func_headers windows.h GetSystemTimeAsFileTime
check_func_headers windows.h MapViewOfFile
+check_func_headers windows.h PeekNamedPipe
check_func_headers windows.h SetConsoleTextAttribute
check_func_headers windows.h Sleep
check_func_headers windows.h VirtualAlloc
check_struct windows.h "CONDITION_VARIABLE" Ptr
+check_func_headers glob.h glob
+enabled xlib &&
+ check_func_headers "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv -lX11 -lXext
check_header direct.h
check_header dlfcn.h
check_header d3d11.h
check_header dxva.h
-check_header dxva2api.h
+check_header dxva2api.h -D_WIN32_WINNT=0x0600
check_header io.h
+check_header libcrystalhd/libcrystalhd_if.h
check_header mach/mach_time.h
check_header malloc.h
+check_header net/udplite.h
check_header poll.h
check_header sys/mman.h
check_header sys/param.h
@@ -4183,6 +4975,7 @@ check_header sys/resource.h
check_header sys/select.h
check_header sys/time.h
check_header sys/un.h
+check_header termios.h
check_header unistd.h
check_header valgrind/valgrind.h
check_header vdpau/vdpau.h
@@ -4190,6 +4983,7 @@ check_header vdpau/vdpau_x11.h
check_header VideoDecodeAcceleration/VDADecoder.h
check_header windows.h
check_header X11/extensions/XvMClib.h
+check_header asm/types.h
check_lib2 "windows.h shellapi.h" CommandLineToArgvW -lshell32
check_lib2 "windows.h wincrypt.h" CryptGenRandom -ladvapi32
@@ -4206,28 +5000,38 @@ fi
# check for some common methods of building with pthread support
# do this before the optional library checks as some of them require pthreads
-if ! disabled pthreads && ! enabled w32threads; then
+if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then
enable pthreads
- if check_func pthread_join -pthread; then
+ if check_func pthread_join -pthread && check_func pthread_create -pthread; then
add_cflags -pthread
add_extralibs -pthread
- elif check_func pthread_join -pthreads; then
+ elif check_func pthread_join -pthreads && check_func pthread_create -pthreads; then
add_cflags -pthreads
add_extralibs -pthreads
- elif check_func pthread_join -lpthreadGC2; then
+ elif check_func pthread_join -ldl -pthread && check_func pthread_create -ldl -pthread; then
+ add_cflags -ldl -pthread
+ add_extralibs -ldl -pthread
+ elif check_func pthread_join -lpthreadGC2 && check_func pthread_create -lpthreadGC2; then
add_extralibs -lpthreadGC2
- elif check_lib pthread.h pthread_join -lpthread; then
+ elif check_lib pthread.h pthread_join -lpthread && check_lib pthread.h pthread_create -lpthread; then
:
- elif ! check_func pthread_join; then
+ elif ! check_func pthread_join && ! check_func pthread_create; then
disable pthreads
fi
+ check_code cc "pthread.h" "static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER" || disable pthreads
+fi
+
+
+if enabled pthreads; then
+ check_func pthread_cancel
fi
disabled zlib || check_lib zlib.h zlibVersion -lz || disable zlib
disabled bzlib || check_lib2 bzlib.h BZ2_bzlibVersion -lbz2 || disable bzlib
+disabled lzma || check_lib2 lzma.h lzma_version_number -llzma || disable lzma
check_lib math.h sin -lm && LIBM="-lm"
-enabled vaapi && require vaapi va/va.h vaInitialize -lva
+disabled crystalhd || check_lib libcrystalhd/libcrystalhd_if.h DtsCrystalHDVersion -lcrystalhd || disable crystalhd
atan2f_args=2
ldexpf_args=2
@@ -4238,56 +5042,98 @@ for func in $MATH_FUNCS; do
done
# these are off by default, so fail if requested and not available
-enabled avisynth && { check_lib2 "avisynth/avisynth_c.h windows.h" LoadLibrary ||
- check_lib2 "avxsynth/avxsynth_c.h dlfcn.h" dlopen -ldl ||
- die "ERROR: LoadLibrary/dlopen not found, or avisynth header not found"; }
+enabled avfoundation_indev && { check_header_oc AVFoundation/AVFoundation.h || disable avfoundation_indev; }
+enabled avfoundation_indev && { check_lib2 CoreGraphics/CoreGraphics.h CGGetActiveDisplayList -framework CoreGraphics ||
+ check_lib2 ApplicationServices/ApplicationServices.h CGGetActiveDisplayList -framework ApplicationServices; }
+enabled avisynth && { { check_lib2 "windows.h" LoadLibrary; } ||
+ { check_lib2 "dlfcn.h" dlopen -ldl; } ||
+ die "ERROR: LoadLibrary/dlopen not found for avisynth"; }
+enabled decklink && { check_header DeckLinkAPI.h || die "ERROR: DeckLinkAPI.h header not found"; }
enabled frei0r && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; }
enabled gnutls && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
+enabled ladspa && { check_header ladspa.h || die "ERROR: ladspa.h header not found"; }
+enabled libiec61883 && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883
+enabled libaacplus && require "libaacplus >= 2.0.0" aacplus.h aacplusEncOpen -laacplus
+enabled libass && require_pkg_config libass ass/ass.h ass_library_init
+enabled libbluray && require_pkg_config libbluray libbluray/bluray.h bd_open
enabled libbs2b && require_pkg_config libbs2b bs2b.h bs2b_open
-enabled libdcadec && require libdcadec libdcadec/dca_context.h dcadec_context_create -ldcadec
+enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 &&
+ { check_lib celt/celt.h celt_decoder_create_custom -lcelt0 ||
+ die "ERROR: libcelt must be installed and version must be >= 0.11.0."; }
+enabled libcaca && require_pkg_config caca caca.h caca_create_canvas
+enabled libdcadec && require_pkg_config dcadec libdcadec/dca_context.h dcadec_context_create
enabled libfaac && require2 libfaac "stdint.h faac.h" faacEncGetVersion -lfaac
enabled libfdk_aac && require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac
+flite_libs="-lflite_cmu_time_awb -lflite_cmu_us_awb -lflite_cmu_us_kal -lflite_cmu_us_kal16 -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish -lflite_cmulex -lflite"
+enabled libflite && require2 libflite "flite/flite.h" flite_init $flite_libs
+enabled fontconfig && enable libfontconfig
enabled libfontconfig && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit
-enabled libfreetype && require_pkg_config freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType
+enabled libfreetype && require_libfreetype
+enabled libfribidi && require_pkg_config fribidi fribidi.h fribidi_version_info
+enabled libgme && require libgme gme/gme.h gme_new_emu -lgme -lstdc++
enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do
check_lib "${gsm_hdr}" gsm_create -lgsm && break;
done || die "ERROR: libgsm not found"; }
enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc
enabled libmfx && require_pkg_config libmfx "mfx/mfxvideo.h" MFXInit
+enabled libmodplug && require_pkg_config libmodplug libmodplug/modplug.h ModPlug_Load
enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame
+enabled libnut && require libnut libnut.h nut_demuxer_init -lnut
enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb
enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb
-enabled libopencv && require_pkg_config opencv opencv/cv.h cvCreateImageHeader
+enabled libopencv && require_pkg_config opencv opencv/cxcore.h cvCreateImageHeader
enabled libopenh264 && require_pkg_config openh264 wels/codec_api.h WelsGetCodecVersion
-enabled libopenjpeg && { { check_header openjpeg.h && check_lib2 openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC; } ||
- { require_pkg_config libopenjpeg1 openjpeg.h opj_version -DOPJ_STATIC; } }
+enabled libopenjpeg && { check_lib openjpeg.h opj_version -lopenmj2 -DOPJ_STATIC ||
+ check_lib openjpeg-1.5/openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC ||
+ check_lib openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC ||
+ die "ERROR: libopenjpeg not found"; }
enabled libopus && require_pkg_config opus opus_multistream.h opus_multistream_decoder_create
-enabled libpulse && require_pkg_config libpulse-simple pulse/simple.h pa_simple_new
+enabled libpulse && require_pkg_config libpulse pulse/pulseaudio.h pa_context_new
+enabled libquvi && require_pkg_config libquvi quvi/quvi.h quvi_init
enabled librtmp && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket
enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init
+enabled libshine && require_pkg_config shine shine/layer3.h shine_encode_buffer
+enabled libsmbclient && { use_pkg_config smbclient libsmbclient.h smbc_init ||
+ require smbclient libsmbclient.h smbc_init -lsmbclient; }
+enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr
+enabled libssh && require_pkg_config libssh libssh/sftp.h sftp_init
enabled libspeex && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex
+enabled libstagefright_h264 && require_cpp libstagefright_h264 "binder/ProcessState.h media/stagefright/MetaData.h
+ media/stagefright/MediaBufferGroup.h media/stagefright/MediaDebug.h media/stagefright/MediaDefs.h
+ media/stagefright/OMXClient.h media/stagefright/OMXCodec.h" android::OMXClient -lstagefright -lmedia -lutils -lbinder -lgnustl_static
enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
-enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame
+enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame &&
+ { check_lib twolame.h twolame_encode_buffer_float32_interleaved -ltwolame ||
+ die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; }
+enabled libutvideo && require_cpp utvideo "stdint.h stdlib.h utvideo/utvideo.h utvideo/Codec.h" 'CCodec*' -lutvideo -lstdc++
+enabled libv4l2 && require_pkg_config libv4l2 libv4l2.h v4l2_ioctl
+enabled libvidstab && require_pkg_config "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit
enabled libvo_aacenc && require libvo_aacenc vo-aacenc/voAAC.h voGetAACEncAPI -lvo-aacenc
enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc
enabled libvorbis && require libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg
enabled libvpx && {
enabled libvpx_vp8_decoder && { check_lib2 "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_dec_init_ver -lvpx ||
die "ERROR: libvpx decoder version must be >=0.9.1"; }
- enabled libvpx_vp8_encoder && { check_lib2 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_enc_init_ver VPX_CQ" -lvpx ||
- die "ERROR: libvpx encoder version must be >=0.9.6"; }
+ enabled libvpx_vp8_encoder && { check_lib2 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_enc_init_ver VP8E_SET_MAX_INTRA_BITRATE_PCT" -lvpx ||
+ die "ERROR: libvpx encoder version must be >=0.9.7"; }
enabled libvpx_vp9_decoder && { check_lib2 "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx" -lvpx || disable libvpx_vp9_decoder; }
- enabled libvpx_vp9_encoder && { check_lib2 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx" -lvpx || disable libvpx_vp9_encoder; } }
+ enabled libvpx_vp9_encoder && { check_lib2 "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx VP9E_SET_AQ_MODE" -lvpx || disable libvpx_vp9_encoder; } }
enabled libwavpack && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput -lwavpack
-enabled libwebp && require_pkg_config libwebp webp/encode.h WebPGetEncoderVersion
-enabled libx264 && require_pkg_config x264 "stdint.h x264.h" x264_encoder_encode &&
+enabled libwebp && {
+ enabled libwebp_encoder && require_pkg_config "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion
+ enabled libwebp_anim_encoder && { use_pkg_config "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit || disable libwebp_anim_encoder; } }
+enabled libx264 && { use_pkg_config x264 "stdint.h x264.h" x264_encoder_encode ||
+ { require libx264 x264.h x264_encoder_encode -lx264 &&
+ warn "using libx264 without pkg-config"; } } &&
{ check_cpp_condition x264.h "X264_BUILD >= 118" ||
- die "ERROR: libx264 version must be >= 0.118."; }
+ die "ERROR: libx264 must be installed and version must be >= 0.118."; }
enabled libx265 && require_pkg_config x265 x265.h x265_encoder_encode &&
{ check_cpp_condition x265.h "X265_BUILD >= 57" ||
die "ERROR: libx265 version must be >= 57."; }
enabled libxavs && require libxavs xavs.h xavs_encoder_encode -lxavs
enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore
+enabled libzmq && require_pkg_config libzmq zmq.h zmq_ctx_new
+enabled libzvbi && require libzvbi libzvbi.h vbi_decoder_new -lzvbi
enabled mmal && { check_lib interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host ||
{ ! enabled cross_compile && {
add_cflags -isystem/opt/vc/include/ -isystem/opt/vc/include/interface/vmcs_host/linux -isystem/opt/vc/include/interface/vcos/pthreads -fgnu89-inline ;
@@ -4295,10 +5141,32 @@ enabled mmal && { check_lib interface/mmal/mmal.h mmal_port_connect
check_lib interface/mmal/mmal.h mmal_port_connect ; }
check_lib interface/mmal/mmal.h mmal_port_connect ; } ||
die "ERROR: mmal not found"; }
+enabled nvenc && { check_header nvEncodeAPI.h || die "ERROR: nvEncodeAPI.h not found."; } &&
+ { check_cpp_condition nvEncodeAPI.h "NVENCAPI_MAJOR_VERSION >= 5" ||
+ die "ERROR: NVENC API version 4 or older is not supported"; } &&
+ { [ $target_os != cygwin ] || die "ERROR: NVENC is not supported on Cygwin currently."; }
+enabled openal && { { for al_libs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
+ check_lib 'AL/al.h' alGetError "${al_libs}" && break; done } ||
+ die "ERROR: openal not found"; } &&
+ { check_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_lib2 OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL ||
+ check_lib2 CL/cl.h clEnqueueNDRangeKernel -lOpenCL ||
+ die "ERROR: opencl not found"; } &&
+ { check_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" ||
+ check_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" ||
+ die "ERROR: opencl must be installed and version must be 1.2 or compatible"; }
+enabled opengl && { check_lib GL/glx.h glXGetProcAddress "-lGL" ||
+ check_lib2 windows.h wglGetProcAddress "-lopengl32 -lgdi32" ||
+ check_lib2 OpenGL/gl3.h glGetError "-Wl,-framework,OpenGL" ||
+ check_lib2 ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" ||
+ die "ERROR: opengl not found."
+ }
enabled openssl && { check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto ||
check_lib openssl/ssl.h SSL_library_init -lssl32 -leay32 ||
check_lib openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 ||
die "ERROR: openssl not found"; }
+enabled qtkit_indev && { check_header_oc QTKit/QTKit.h || disable qtkit_indev; }
if enabled gnutls; then
{ check_lib nettle/bignum.h nettle_mpz_get_str_256 -lnettle -lhogweed -lgmp && enable nettle; } ||
@@ -4313,27 +5181,53 @@ if enabled libdc1394; then
enable libdc1394_1; } ||
die "ERROR: No version of libdc1394 found "
fi
-
-if check_pkg_config sdl SDL_events.h SDL_PollEvent; then
- check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x010201" $sdl_cflags &&
- check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x010300" $sdl_cflags &&
- enable sdl
+if ! disabled sdl; then
+ SDL_CONFIG="${cross_prefix}sdl-config"
+ if check_pkg_config sdl SDL_events.h SDL_PollEvent; then
+ check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x010201" $sdl_cflags &&
+ check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x010300" $sdl_cflags &&
+ enable sdl
+ else
+ if "${SDL_CONFIG}" --version > /dev/null 2>&1; then
+ sdl_cflags=$("${SDL_CONFIG}" --cflags)
+ sdl_libs=$("${SDL_CONFIG}" --libs)
+ check_func_headers SDL_version.h SDL_Linked_Version $sdl_cflags $sdl_libs &&
+ check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x010201" $sdl_cflags &&
+ check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x010300" $sdl_cflags &&
+ enable sdl
+ elif enabled sdl ; then
+ die "ERROR: SDL not found"
+ else
+ disable sdl
+ fi
+ fi
fi
-
+enabled sdl && add_cflags $sdl_cflags && add_extralibs $sdl_libs
+
+makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo
+enabled makeinfo && (makeinfo --version | \
+ grep -q 'makeinfo (GNU texinfo) 5' > /dev/null 2>&1) \
+ && enable makeinfo_html || disable makeinfo_html
+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
-texi2html -version > /dev/null 2>&1 && enable texi2html || disable texi2html
+rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
check_header linux/fb.h
+check_header linux/videodev.h
check_header linux/videodev2.h
-check_struct linux/videodev2.h "struct v4l2_frmivalenum" discrete
+check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
check_header sys/videoio.h
+check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extralibs"
# check that WM_CAP_DRIVER_CONNECT is defined to the proper value
# w32api 3.12 had it defined wrong
check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_defines
+check_type "dshow.h" IBaseFilter
+
# check for ioctl_meteor.h, ioctl_bt848.h and alternatives
{ check_header dev/bktr/ioctl_meteor.h &&
check_header dev/bktr/ioctl_bt848.h; } ||
@@ -4344,13 +5238,20 @@ check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_def
check_header dev/ic/bt8xx.h
check_header sndio.h
-check_header sys/soundcard.h
+if check_struct sys/soundcard.h audio_buf_info bytes; then
+ enable_safe sys/soundcard.h
+else
+ check_cc -D__BSD_VISIBLE -D__XSI_VISIBLE <<EOF && add_cppflags -D__BSD_VISIBLE -D__XSI_VISIBLE && enable_safe sys/soundcard.h
+ #include <sys/soundcard.h>
+ audio_buf_info abc;
+EOF
+fi
check_header soundcard.h
enabled_any alsa_indev alsa_outdev &&
check_lib2 alsa/asoundlib.h snd_pcm_htimestamp -lasound
-enabled jack_indev && check_lib2 jack/jack.h jack_client_open -ljack &&
+enabled jack_indev && check_lib2 jack/jack.h jack_client_open -ljack && check_func sem_timedwait &&
check_func jack_port_get_latency_range -ljack
enabled_any sndio_indev sndio_outdev && check_lib2 sndio.h sio_open -lsndio
@@ -4361,25 +5262,33 @@ if enabled libcdio; then
die "ERROR: No usable libcdio/cdparanoia found"
fi
-check_lib X11/Xlib.h XOpenDisplay -lX11 && enable xlib
+enabled xlib &&
+ check_lib X11/Xlib.h XOpenDisplay -lX11 || disable xlib
-if enabled libxcb || enabled x11grab && ! disabled libxcb; then
- check_pkg_config xcb-shape xcb/shape.h xcb_shape_rectangles || {
- enabled libxcb && die "ERROR: libxcb not found";
+if ! disabled libxcb; then
+ check_pkg_config "xcb >= 1.4" xcb/xcb.h xcb_connect || {
+ enabled libxcb && die "ERROR: libxcb >= 1.4 not found";
} && disable x11grab && enable libxcb
- disabled libxcb_shm ||
+if enabled libxcb; then
+ disabled libxcb_shm || {
check_pkg_config xcb-shm xcb/shm.h xcb_shm_attach || {
enabled libxcb_shm && die "ERROR: libxcb_shm not found";
- } && check_header sys/shm.h && enable libxcb_shm
+ } && check_header sys/shm.h && enable libxcb_shm; }
- disabled libxcb_xfixes ||
+ disabled libxcb_xfixes || {
check_pkg_config xcb-xfixes xcb/xfixes.h xcb_xfixes_get_cursor_image || {
enabled libxcb_xfixes && die "ERROR: libxcb_xfixes not found";
- } && enable libxcb_xfixes
+ } && enable libxcb_xfixes; }
- add_cflags "$xcb_event_cflags $xcb_shm_cflags $xcb_xfixes_cflags"
- add_extralibs "$xcb_event_libs $xcb_shm_libs $xcb_xfixes_libs"
+ disabled libxcb_shape || {
+ check_pkg_config xcb-shape xcb/shape.h xcb_shape_get_rectangles || {
+ enabled libxcb_shape && die "ERROR: libxcb_shape not found";
+ } && enable libxcb_shape; }
+
+ add_cflags $xcb_cflags $xcb_shm_cflags $xcb_xfixes_cflags $xcb_shape_cflags
+ add_extralibs $xcb_libs $xcb_shm_libs $xcb_xfixes_libs $xcb_shape_libs
+fi
fi
if enabled x11grab; then
@@ -4388,6 +5297,18 @@ if enabled x11grab; then
require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes
fi
+check_func_headers "windows.h" CreateDIBSection "$gdigrab_indev_extralibs"
+
+enabled dxva2api_h &&
+ check_cc <<EOF && enable dxva2api_cobj
+#define _WIN32_WINNT 0x0600
+#define COBJMACROS
+#include <windows.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+int main(void) { IDirectXVideoDecoder *o = NULL; IDirectXVideoDecoder_Release(o); return 0; }
+EOF
+
enabled d3d11_h &&
check_cc <<EOF && enable d3d11_cobj
#define _WIN32_WINNT 0x0600
@@ -4397,6 +5318,10 @@ enabled d3d11_h &&
int main(void) { ID3D11VideoDecoder *o = NULL; ID3D11VideoDecoder_Release(o); return 0; }
EOF
+enabled vaapi &&
+ check_lib va/va.h vaInitialize -lva ||
+ disable vaapi
+
enabled vaapi && enabled xlib &&
check_lib2 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 &&
enable vaapi_x11
@@ -4407,9 +5332,12 @@ enabled vdpau &&
enabled vdpau && enabled xlib &&
check_func_headers "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau &&
- prepend avconv_libs $($ldflags_filter "-lvdpau") &&
+ prepend ffmpeg_libs $($ldflags_filter "-lvdpau") &&
enable vdpau_x11
+# Funny iconv installations are not unusual, so check it after all flags have been set
+disabled iconv || check_func_headers iconv.h iconv || check_lib2 iconv.h iconv -liconv || disable iconv
+
enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel"
# add some useful compiler flags if supported
@@ -4418,12 +5346,13 @@ check_cflags -Wall
check_cflags -Wdisabled-optimization
check_cflags -Wpointer-arith
check_cflags -Wredundant-decls
-check_cflags -Wcast-qual
check_cflags -Wwrite-strings
check_cflags -Wtype-limits
check_cflags -Wundef
check_cflags -Wmissing-prototypes
+check_cflags -Wno-pointer-to-int-cast
check_cflags -Wstrict-prototypes
+check_cflags -Wempty-body
enabled extra_warnings && check_cflags -Winline
check_disable_warning(){
@@ -4438,13 +5367,13 @@ check_disable_warning -Wno-pointer-sign
# add some linker flags
check_ldflags -Wl,--warn-common
-check_ldflags -Wl,-rpath-link=libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample
+check_ldflags -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample
enabled rpath && add_ldexeflags -Wl,-rpath,$libdir
test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic
# add some strip flags
# -wN '..@*' is more selective than -x, but not available everywhere.
-check_stripflags -wN \'..@*\' || check_stripflags -x || strip='true'
+check_stripflags -wN \'..@*\' || check_stripflags -x
enabled neon_clobber_test &&
check_ldflags -Wl,--wrap,avcodec_open2 \
@@ -4454,6 +5383,7 @@ enabled neon_clobber_test &&
-Wl,--wrap,avcodec_encode_audio2 \
-Wl,--wrap,avcodec_encode_video2 \
-Wl,--wrap,avcodec_encode_subtitle \
+ -Wl,--wrap,swr_convert \
-Wl,--wrap,avresample_convert ||
disable neon_clobber_test
@@ -4463,8 +5393,10 @@ enabled xmm_clobber_test &&
-Wl,--wrap,avcodec_decode_video2 \
-Wl,--wrap,avcodec_decode_subtitle2 \
-Wl,--wrap,avcodec_encode_audio2 \
+ -Wl,--wrap,avcodec_encode_video \
-Wl,--wrap,avcodec_encode_video2 \
-Wl,--wrap,avcodec_encode_subtitle \
+ -Wl,--wrap,swr_convert \
-Wl,--wrap,avresample_convert \
-Wl,--wrap,sws_scale ||
disable xmm_clobber_test
@@ -4502,28 +5434,41 @@ if enabled lto; then
test "$cc_type" != "$ld_type" && die "LTO requires same compiler and linker"
check_cflags -flto
check_ldflags -flto $cpuflags
+ disable inline_asm_direct_symbol_refs
fi
check_optflags $optflags
check_optflags -fno-math-errno
check_optflags -fno-signed-zeros
+enabled ftrapv && check_cflags -ftrapv
+
+check_cc -mno-red-zone <<EOF && noredzone_flags="-mno-red-zone"
+int x;
+EOF
+
+
if enabled icc; then
# Just warnings, no remarks
check_cflags -w1
# -wd: Disable following warnings
# 144, 167, 556: -Wno-pointer-sign
+ # 188: enumerated type mixed with another type
# 1292: attribute "foo" ignored
# 1419: external declaration in primary source file
# 10006: ignoring unknown option -fno-signed-zeros
# 10148: ignoring unknown option -Wno-parentheses
# 10156: ignoring option '-W'; no argument required
- check_cflags -wd144,167,556,1292,1419,10006,10148,10156
+ # 13200: No EMMS instruction before call to function
+ # 13203: No EMMS instruction before return from function
+ check_cflags -wd144,167,188,556,1292,1419,10006,10148,10156,13200,13203
# 11030: Warning unknown option --as-needed
# 10156: ignoring option '-export'; no argument required
check_ldflags -wd10156,11030
# icc 11.0 and 11.1 work with ebp_available, but don't pass the test
enable ebp_available
+ # The test above does not test linking
+ enabled lto && disable symver_asm_label
if enabled x86_32; then
icc_version=$($cc -dumpversion)
test ${icc_version%%.*} -ge 11 &&
@@ -4538,12 +5483,12 @@ elif enabled ccc; then
add_cflags -msg_disable unsupieee
elif enabled gcc; then
check_optflags -fno-tree-vectorize
+ check_cflags -Werror=format-security
check_cflags -Werror=implicit-function-declaration
check_cflags -Werror=missing-prototypes
check_cflags -Werror=return-type
- check_cflags -Werror=declaration-after-statement
check_cflags -Werror=vla
- check_cflags -Werror=format-security
+ check_cflags -Wformat
check_cflags -fdiagnostics-color=auto
enabled extra_warnings || check_disable_warning -Wno-maybe-uninitialized
elif enabled llvm_gcc; then
@@ -4582,9 +5527,11 @@ elif enabled_any msvc icl; then
# (correctly) on icl 13.x.
check_cpp_condition "windows.h" "__ICL < 1300 || __ICL >= 1400" &&
add_cflags -Qansi-alias
- # icl will pass the inline asm tests but inline asm is currently
- # not supported (build will fail)
- disable inline_asm
+ # Some inline asm is not compilable in debug
+ if enabled debug; then
+ disable ebp_available
+ disable ebx_available
+ fi
fi
# msvcrt10 x64 incorrectly enables log2, only msvcrt12 (MSVC 2013) onwards actually has log2.
check_cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" || disable log2
@@ -4611,6 +5558,8 @@ case $target_os in
;;
esac
+enable frame_thread_encoder
+
enabled asm || { arch=c; disable $ARCH_LIST $ARCH_EXT_LIST; }
check_deps $CONFIG_LIST \
@@ -4618,17 +5567,52 @@ check_deps $CONFIG_LIST \
$HAVE_LIST \
$ALL_COMPONENTS \
+enabled threads && ! enabled pthreads && ! enabled atomics_native && die "non pthread threading without atomics not supported, try adding --enable-pthreads or --cpu=i486 or higher if you are on x86"
+
+
+if test $target_os = "haiku"; then
+ disable memalign
+ disable posix_memalign
+fi
+
enabled_all d3d11va d3d11_cobj CoTaskMemFree &&
- prepend avconv_libs $($ldflags_filter "-lole32") &&
+ prepend ffmpeg_libs $($ldflags_filter "-lole32") &&
enable d3d11va_lib
-enabled_all dxva2 CoTaskMemFree &&
- prepend avconv_libs $($ldflags_filter "-lole32") &&
+enabled_all dxva2 dxva2api_cobj CoTaskMemFree &&
+ prepend ffmpeg_libs $($ldflags_filter "-lole32" "-luser32") &&
enable dxva2_lib
! enabled_any memalign posix_memalign aligned_malloc &&
enabled simd_align_16 && enable memalign_hack
+# add_dep lib dep
+# -> enable ${lib}_deps_${dep}
+# -> add $dep to ${lib}_deps only once
+add_dep() {
+ lib=$1
+ dep=$2
+ enabled "${lib}_deps_${dep}" && return 0
+ enable "${lib}_deps_${dep}"
+ prepend "${lib}_deps" $dep
+}
+
+# merge deps lib components
+# merge all ${component}_deps into ${lib}_deps and ${lib}_deps_*
+merge_deps() {
+ lib=$1
+ shift
+ for comp in $*; do
+ enabled $comp || continue
+ eval "dep=\"\$${comp}_deps\""
+ for d in $dep; do
+ add_dep $lib $d
+ done
+ done
+}
+
+merge_deps libavfilter $FILTER_LIST
+
map 'enabled $v && intrinsics=${v#intrinsics_}' $INTRINSICS_LIST
for thread in $THREADS_LIST; do
@@ -4642,11 +5626,31 @@ done
enabled zlib && add_cppflags -DZLIB_CONST
# conditional library dependencies, in linking order
+enabled amovie_filter && prepend avfilter_deps "avformat avcodec"
+enabled aresample_filter && prepend avfilter_deps "swresample"
+enabled asyncts_filter && prepend avfilter_deps "avresample"
+enabled atempo_filter && prepend avfilter_deps "avcodec"
+enabled cover_rect_filter && prepend avfilter_deps "avformat avcodec"
+enabled ebur128_filter && enabled swresample && prepend avfilter_deps "swresample"
+enabled elbg_filter && prepend avfilter_deps "avcodec"
+enabled fftfilt_filter && prepend avfilter_deps "avcodec"
+enabled find_rect_filter && prepend avfilter_deps "avformat avcodec"
+enabled mcdeint_filter && prepend avfilter_deps "avcodec"
enabled movie_filter && prepend avfilter_deps "avformat avcodec"
+enabled pan_filter && prepend avfilter_deps "swresample"
+enabled pp_filter && prepend avfilter_deps "postproc"
+enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale"
enabled resample_filter && prepend avfilter_deps "avresample"
+enabled sab_filter && prepend avfilter_deps "swscale"
enabled scale_filter && prepend avfilter_deps "swscale"
+enabled showspectrum_filter && prepend avfilter_deps "avcodec"
+enabled smartblur_filter && prepend avfilter_deps "swscale"
+enabled subtitles_filter && prepend avfilter_deps "avformat avcodec"
+enabled uspp_filter && prepend avfilter_deps "avcodec"
+
+enabled lavfi_indev && prepend avdevice_deps "avfilter"
-enabled opus_decoder && prepend avcodec_deps "avresample"
+enabled opus_decoder && prepend avcodec_deps "swresample"
expand_deps(){
lib_deps=${1}_deps
@@ -4655,6 +5659,9 @@ expand_deps(){
unique $lib_deps
}
+#we have to remove gpl from the deps here as some code assumes all lib deps are libs
+postproc_deps="$(filter_out 'gpl' $postproc_deps)"
+
map 'expand_deps $v' $LIBRARY_LIST
echo "install prefix $prefix"
@@ -4669,6 +5676,9 @@ echo "ARCH $arch ($cpu)"
if test "$build_suffix" != ""; then
echo "build suffix $build_suffix"
fi
+if test "$progs_suffix" != ""; then
+ echo "progs suffix $progs_suffix"
+fi
if test "$extra_version" != ""; then
echo "version string suffix $extra_version"
fi
@@ -4701,22 +5711,41 @@ if enabled arm; then
echo "ARMv6T2 enabled ${armv6t2-no}"
echo "VFP enabled ${vfp-no}"
echo "NEON enabled ${neon-no}"
+ echo "THUMB enabled ${thumb-no}"
+fi
+if enabled mips; then
+ echo "MIPS FPU enabled ${mipsfpu-no}"
+ echo "MIPS32R5 enabled ${mips32r5-no}"
+ echo "MIPS64R6 enabled ${mips64r6-no}"
+ echo "MIPS DSP R1 enabled ${mipsdspr1-no}"
+ echo "MIPS DSP R2 enabled ${mipsdspr2-no}"
+ echo "MIPS MSA enabled ${msa-no}"
+ echo "LOONGSON3 enabled ${loongson3-no}"
fi
if enabled ppc; then
echo "AltiVec enabled ${altivec-no}"
echo "PPC 4xx optimizations ${ppc4xx-no}"
+ echo "PPC VSX optimizations ${vsx-no}"
echo "dcbzl available ${dcbzl-no}"
fi
echo "debug symbols ${debug-no}"
+echo "strip symbols ${stripping-no}"
echo "optimize for size ${small-no}"
echo "optimizations ${optimizations-no}"
echo "static ${static-no}"
echo "shared ${shared-no}"
+echo "postprocessing support ${postproc-no}"
echo "new filter support ${avfilter-no}"
echo "network support ${network-no}"
echo "threading support ${thread_type-no}"
echo "safe bitstream reader ${safe_bitstream_reader-no}"
echo "SDL support ${sdl-no}"
+echo "opencl enabled ${opencl-no}"
+echo "texi2html enabled ${texi2html-no}"
+echo "perl enabled ${perl-no}"
+echo "pod2man enabled ${pod2man-no}"
+echo "makeinfo enabled ${makeinfo-no}"
+echo "makeinfo supports HTML ${makeinfo_html-no}"
test -n "$random_seed" &&
echo "random seed ${random_seed}"
echo
@@ -4745,15 +5774,19 @@ fi
echo "License: $license"
-echo "Creating config.mak and config.h..."
+echo "Creating config.mak, config.h, and doc/config.texi..."
test -e Makefile || echo "include $source_path/Makefile" > Makefile
-config_files="$TMPH config.mak"
+enabled stripping || strip="echo skipping strip"
+
+config_files="$TMPH config.mak doc/config.texi"
cat > config.mak <<EOF
# Automatically generated by configure - do not modify!
-LIBAV_CONFIGURATION=$LIBAV_CONFIGURATION
+ifndef FFMPEG_CONFIG_MAK
+FFMPEG_CONFIG_MAK=1
+FFMPEG_CONFIGURATION=$FFMPEG_CONFIGURATION
prefix=$prefix
LIBDIR=\$(DESTDIR)$libdir
SHLIBDIR=\$(DESTDIR)$shlibdir
@@ -4763,10 +5796,14 @@ DATADIR=\$(DESTDIR)$datadir
DOCDIR=\$(DESTDIR)$docdir
MANDIR=\$(DESTDIR)$mandir
SRC_PATH=$source_path
+ifndef MAIN_MAKEFILE
+SRC_PATH:=\$(SRC_PATH:.%=..%)
+endif
CC_IDENT=$cc_ident
ARCH=$arch
INTRINSICS=$intrinsics
CC=$cc
+CXX=$cxx
AS=$as
LD=$ld
DEPCC=$dep_cc
@@ -4780,25 +5817,33 @@ ARFLAGS=$arflags
AR_O=$ar_o
RANLIB=$ranlib
STRIP=$strip
+CP=cp -p
LN_S=$ln_s
CPPFLAGS=$CPPFLAGS
CFLAGS=$CFLAGS
+CXXFLAGS=$CXXFLAGS
ASFLAGS=$ASFLAGS
AS_C=$AS_C
AS_O=$AS_O
CC_C=$CC_C
CC_E=$CC_E
CC_O=$CC_O
+CXX_C=$CXX_C
+CXX_O=$CXX_O
LD_O=$LD_O
LD_LIB=$LD_LIB
LD_PATH=$LD_PATH
DLLTOOL=$dlltool
+WINDRES=$windres
+DEPWINDRES=$dep_cc
+DOXYGEN=$doxygen
LDFLAGS=$LDFLAGS
LDEXEFLAGS=$LDEXEFLAGS
SHFLAGS=$(echo $($ldflags_filter $SHFLAGS))
-STRIPFLAGS=$STRIPFLAGS
+ASMSTRIPFLAGS=$ASMSTRIPFLAGS
YASMFLAGS=$YASMFLAGS
BUILDSUF=$build_suffix
+PROGSSUF=$progs_suffix
FULLNAME=$FULLNAME
LIBPREF=$LIBPREF
LIBSUF=$LIBSUF
@@ -4808,6 +5853,7 @@ SLIBSUF=$SLIBSUF
EXESUF=$EXESUF
EXTRA_VERSION=$extra_version
CCDEP=$CCDEP
+CXXDEP=$CXXDEP
CCDEP_FLAGS=$CCDEP_FLAGS
ASDEP=$ASDEP
ASDEP_FLAGS=$ASDEP_FLAGS
@@ -4831,13 +5877,13 @@ HOSTLD_O=$HOSTLD_O
TARGET_EXEC=$target_exec $target_exec_args
TARGET_PATH=$target_path
TARGET_SAMPLES=${target_samples:-\$(SAMPLES)}
-CFLAGS-avplay=$sdl_cflags
+CFLAGS-ffplay=$sdl_cflags
ZLIB=$($ldflags_filter -lz)
LIB_INSTALL_EXTRA_CMD=$LIB_INSTALL_EXTRA_CMD
EXTRALIBS=$extralibs
COMPAT_OBJS=$compat_objs
EXEOBJS=$exeobjs
-INSTALL=install
+INSTALL=$install
LIBTARGET=${LIBTARGET}
SLIBNAME=${SLIBNAME}
SLIBNAME_WITH_VERSION=${SLIBNAME_WITH_VERSION}
@@ -4848,7 +5894,8 @@ SLIB_INSTALL_NAME=${SLIB_INSTALL_NAME}
SLIB_INSTALL_LINKS=${SLIB_INSTALL_LINKS}
SLIB_INSTALL_EXTRA_LIB=${SLIB_INSTALL_EXTRA_LIB}
SLIB_INSTALL_EXTRA_SHLIB=${SLIB_INSTALL_EXTRA_SHLIB}
-SAMPLES:=${samples:-\$(LIBAV_SAMPLES)}
+SAMPLES:=${samples:-\$(FATE_SAMPLES)}
+NOREDZONE_FLAGS=$noredzone_flags
EOF
get_version(){
@@ -4856,6 +5903,7 @@ get_version(){
name=$(toupper $lcname)
file=$source_path/$lcname/version.h
eval $(awk "/#define ${name}_VERSION_M/ { print \$2 \"=\" \$3 }" "$file")
+ enabled raise_major && eval ${name}_VERSION_MAJOR=$((${name}_VERSION_MAJOR+100))
eval ${name}_VERSION=\$${name}_VERSION_MAJOR.\$${name}_VERSION_MINOR.\$${name}_VERSION_MICRO
eval echo "${lcname}_VERSION=\$${name}_VERSION" >> config.mak
eval echo "${lcname}_VERSION_MAJOR=\$${name}_VERSION_MAJOR" >> config.mak
@@ -4875,18 +5923,26 @@ map 'print_program_libs $v' $PROGRAM_LIST
cat > $TMPH <<EOF
/* Automatically generated by configure - do not modify! */
-#ifndef LIBAV_CONFIG_H
-#define LIBAV_CONFIG_H
-#define LIBAV_CONFIGURATION "$(c_escape $LIBAV_CONFIGURATION)"
-#define LIBAV_LICENSE "$(c_escape $license)"
+#ifndef FFMPEG_CONFIG_H
+#define FFMPEG_CONFIG_H
+#define FFMPEG_CONFIGURATION "$(c_escape $FFMPEG_CONFIGURATION)"
+#define FFMPEG_LICENSE "$(c_escape $license)"
+#define CONFIG_THIS_YEAR 2015
+#define FFMPEG_DATADIR "$(eval c_escape $datadir)"
#define AVCONV_DATADIR "$(eval c_escape $datadir)"
#define CC_IDENT "$(c_escape ${cc_ident:-Unknown compiler})"
-#define restrict $_restrict
+#define av_restrict $_restrict
#define EXTERN_PREFIX "${extern_prefix}"
#define EXTERN_ASM ${extern_prefix}
+#define BUILDSUF "$build_suffix"
#define SLIBSUF "$SLIBSUF"
+#define HAVE_MMX2 HAVE_MMXEXT
+#define SWS_MAX_FILTER_SIZE $sws_max_filter_size
EOF
+test -n "$assert_level" &&
+ echo "#define ASSERT_LEVEL $assert_level" >>$TMPH
+
test -n "$malloc_prefix" &&
echo "#define MALLOC_PREFIX $malloc_prefix" >>$TMPH
@@ -4897,13 +5953,19 @@ fi
enabled getenv || echo "#define getenv(x) NULL" >> $TMPH
+
+mkdir -p doc
+mkdir -p tests
+echo "@c auto-generated by configure" > doc/config.texi
+
print_config ARCH_ "$config_files" $ARCH_LIST
print_config HAVE_ "$config_files" $HAVE_LIST
print_config CONFIG_ "$config_files" $CONFIG_LIST \
$CONFIG_EXTRA \
$ALL_COMPONENTS \
-echo "#endif /* LIBAV_CONFIG_H */" >> $TMPH
+echo "#endif /* FFMPEG_CONFIG_H */" >> $TMPH
+echo "endif # FFMPEG_CONFIG_MAK" >> config.mak
# Do not overwrite an unchanged config.h to avoid superfluous rebuilds.
cp_if_changed $TMPH config.h
@@ -4923,12 +5985,15 @@ echo "#endif /* AVUTIL_AVCONFIG_H */" >> $TMPH
cp_if_changed $TMPH libavutil/avconfig.h
-test -n "$WARNINGS" && printf "\n$WARNINGS"
+if test -n "$WARNINGS"; then
+ printf "\n$WARNINGS"
+ enabled fatal_warnings && exit 1
+fi
# build pkg-config files
lib_version(){
- eval printf "\"lib${1} >= \$LIB$(toupper ${1})_VERSION, \""
+ eval printf "\"lib${1}${build_suffix} >= \$LIB$(toupper ${1})_VERSION, \""
}
pkgconfig_generate(){
@@ -4941,7 +6006,7 @@ pkgconfig_generate(){
requires=${requires%, }
enabled ${name#lib} || return 0
mkdir -p $name
- cat <<EOF > $name/$name.pc
+ cat <<EOF > $name/$name${build_suffix}.pc
prefix=$prefix
exec_prefix=\${prefix}
libdir=$libdir
@@ -4953,30 +6018,36 @@ Version: $version
Requires: $(enabled shared || echo $requires)
Requires.private: $(enabled shared && echo $requires)
Conflicts:
-Libs: -L\${libdir} -l${shortname} $(enabled shared || echo $libs)
+Libs: -L\${libdir} $(enabled rpath && echo "-Wl,-rpath,\${libdir}") -l${shortname} $(enabled shared || echo $libs)
Libs.private: $(enabled shared && echo $libs)
Cflags: -I\${includedir}
EOF
- cat <<EOF > $name/$name-uninstalled.pc
+
+mkdir -p doc/examples/pc-uninstalled
+includedir=${source_path}
+[ "$includedir" = . ] && includedir="\${pcfiledir}/../../.."
+ cat <<EOF > doc/examples/pc-uninstalled/$name.pc
prefix=
exec_prefix=
-libdir=\${pcfiledir}
-includedir=${source_path}
+libdir=\${pcfiledir}/../../../$name
+includedir=${includedir}
Name: $name
Description: $comment
Version: $version
Requires: $requires
Conflicts:
-Libs: \${libdir}/${LIBPREF}${shortname}${LIBSUF} $libs
+Libs: -L\${libdir} -Wl,-rpath,\${libdir} -l${shortname} $(enabled shared || echo $libs)
Cflags: -I\${includedir}
EOF
}
-pkgconfig_generate libavutil "Libav utility library" "$LIBAVUTIL_VERSION" "$LIBRT $LIBM"
-pkgconfig_generate libavcodec "Libav codec library" "$LIBAVCODEC_VERSION" "$extralibs"
-pkgconfig_generate libavformat "Libav container format library" "$LIBAVFORMAT_VERSION" "$extralibs"
-pkgconfig_generate libavdevice "Libav device handling library" "$LIBAVDEVICE_VERSION" "$extralibs"
-pkgconfig_generate libavfilter "Libav video filtering library" "$LIBAVFILTER_VERSION" "$extralibs"
-pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$LIBM"
-pkgconfig_generate libswscale "Libav image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM"
+pkgconfig_generate libavutil "FFmpeg utility library" "$LIBAVUTIL_VERSION" "$LIBRT $LIBM"
+pkgconfig_generate libavcodec "FFmpeg codec library" "$LIBAVCODEC_VERSION" "$extralibs"
+pkgconfig_generate libavformat "FFmpeg container format library" "$LIBAVFORMAT_VERSION" "$extralibs"
+pkgconfig_generate libavdevice "FFmpeg device handling library" "$LIBAVDEVICE_VERSION" "$extralibs"
+pkgconfig_generate libavfilter "FFmpeg audio/video filtering library" "$LIBAVFILTER_VERSION" "$extralibs"
+pkgconfig_generate libpostproc "FFmpeg postprocessing library" "$LIBPOSTPROC_VERSION" ""
+pkgconfig_generate libavresample "Libav audio resampling library" "$LIBAVRESAMPLE_VERSION" "$LIBM"
+pkgconfig_generate libswscale "FFmpeg image rescaling library" "$LIBSWSCALE_VERSION" "$LIBM"
+pkgconfig_generate libswresample "FFmpeg audio resampling library" "$LIBSWRESAMPLE_VERSION" "$LIBM"
diff --git a/doc/APIchanges b/doc/APIchanges
index 5d39ec64c2..3cca3890cb 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -1,5 +1,5 @@
Never assume the API of libav* to be stable unless at least 1 month has passed
-since the last major version increase.
+since the last major version increase or the API was added.
The last version increases were:
libavcodec: 2014-08-09
@@ -7,92 +7,181 @@ libavdevice: 2014-08-09
libavfilter: 2014-08-09
libavformat: 2014-08-09
libavresample: 2014-08-09
+libpostproc: 2014-08-09
+libswresample: 2014-08-09
libswscale: 2014-08-09
libavutil: 2014-08-09
API changes, most recent first:
-2015-xx-xx - xxxxxxx - lavc 56.23.0
+2015-05-13 - xxxxxxx - lavc 56.39.100 / 56.23.0
Add av_vda_default_init2.
-2015-xx-xx - xxxxxxx - lavu 54.12.0
+2015-05-11 - XXXXXXX - lavf 56.33.100 - avformat.h
+ Add AVOpenCallback AVFormatContext.open_cb
+
+2015-05-07 - a7dd933 - 56.38.100 - avcodec.h
+ Add av_packet_side_data_name().
+
+2015-05-07 - 01e59d4 - 56.37.102 - avcodec.h
+ Add FF_PROFILE_VP9_2 and FF_PROFILE_VP9_3.
+
+2015-05-04 - 079b7f6 - 56.37.100 - avcodec.h
+ Add FF_PROFILE_VP9_0 and FF_PROFILE_VP9_1.
+
+2015-04-22 - 748d481 - lavf 56.31.100 - avformat.h
+ Add AVFMT_FLAG_FAST_SEEK flag. Some formats (initially mp3) use it to enable
+ fast, but inaccurate seeking.
+
+2015-04-20 - 8e8219e / c253340 - lavu 54.23.100 / 54.12.0 - log.h
Add AV_LOG_TRACE for extremely verbose debugging.
-2015-xx-xx - xxxxxxx - lavu 54.11.0
- Add av_small_strptime().
+2015-04-02 - 26e0e393 - lavf 56.29.100 - avio.h
+ Add AVIODirEntryType.AVIO_ENTRY_SERVER.
+ Add AVIODirEntryType.AVIO_ENTRY_SHARE.
+ Add AVIODirEntryType.AVIO_ENTRY_WORKGROUP.
-2015-xx-xx - xxxxxxx - lavc 56.22.0
- Add FF_PROFILE_DTS_EXPRESS.
+2015-03-31 - 3188696 - lavu 54.22.100 - avstring.h
+ Add av_append_path_component()
+
+2015-03-27 - 184084c - lavf 56.27.100 - avio.h url.h
+ New directory listing API.
+
+ Add AVIODirEntryType enum.
+ Add AVIODirEntry, AVIODirContext structures.
+ Add avio_open_dir(), avio_read_dir(), avio_close_dir(), avio_free_directory_entry().
+ Add ff_alloc_dir_entry().
+ Extend URLProtocol with url_open_dir(), url_read_dir(), url_close_dir().
-2015-xx-xx - xxxxxxx - lavu 54.10.0
+2015-03-29 - 268ff17 / c484561 - lavu 54.21.100 / 54.10.0 - pixfmt.h
Add AV_PIX_FMT_MMAL for MMAL hardware acceleration.
-2015-xx-xx - xxxxxxx - lavc 56.13
+2015-03-19 - 11fe56c - 56.29.100 / lavc 56.22.0
+ Add FF_PROFILE_DTS_EXPRESS.
+
+-------- 8< --------- FFmpeg 2.6 was cut here -------- 8< ---------
+
+2015-03-04 - cca4476 - lavf 56.25.100
+ Add avformat_flush()
+
+2015-03-03 - 81a9126 - lavf 56.24.100
+ Add avio_put_str16be()
+
+2015-02-19 - 560eb71 / 31d2039 - lavc 56.23.100 / 56.13.0
Add width, height, coded_width, coded_height and format to
AVCodecParserContext.
-2015-xx-xx - xxxxxxx - lavu 54.9.0
+2015-02-19 - e375511 / 5b1d9ce - lavu 54.19.100 / 54.9.0
Add AV_PIX_FMT_QSV for QSV hardware acceleration.
-2015-01-27 - 728685f - lavc 56.12.0, lavu 54.8.0 - avcodec.h, frame.h
+2015-02-14 - ba22295 - lavc 56.21.102
+ Deprecate VIMA decoder.
+
+2015-01-27 - 62a82c6 / 728685f - lavc 56.21.100 / 56.12.0, lavu 54.18.100 / 54.8.0 - avcodec.h, frame.h
Add AV_PKT_DATA_AUDIO_SERVICE_TYPE and AV_FRAME_DATA_AUDIO_SERVICE_TYPE for
storing the audio service type as side data.
-2015-01-14 - e2ad0b6 - lavu 54.6.0 - imgutils.h
- Add utility functions for image manipulation: av_image_get_buffer_size()
- av_image_fill_arrays() and av_image_copy_to_buffer().
+2015-01-16 - a47c933 - lavf 56.19.100 - avformat.h
+ Add data_codec and data_codec_id for storing codec of data stream
-2014-12-25 - c220a60 - lavc 56.10.0 - vdpau.h
+2015-01-11 - 007c33d - lavd 56.4.100 - avdevice.h
+ Add avdevice_list_input_sources().
+ Add avdevice_list_output_sinks().
+
+2014-12-25 - d7aaeea / c220a60 - lavc 56.19.100 / 56.10.0 - vdpau.h
Add av_vdpau_get_surface_parameters().
-2014-12-25 - 6c99c92 - lavc 56.9.0 - avcodec.h
+2014-12-25 - ddb9a24 / 6c99c92 - lavc 56.18.100 / 56.9.0 - avcodec.h
Add AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH flag to av_vdpau_bind_context().
-2014-12-25 - 57b6704 - lavc 56.8.0 - avcodec.h
+2014-12-25 - d16079a / 57b6704 - lavc 56.17.100 / 56.8.0 - avcodec.h
Add AVCodecContext.sw_pix_fmt.
-2014-11-07 - 1384df6 - lavf 56.06.3 - avformat.h
- Add AVFormatContext.avoid_negative_ts.
+2014-12-04 - 6e9ac02 - lavc 56.14.100 - dv_profile.h
+ Add av_dv_codec_profile2().
-2014-11-06 - 5e80fb7 - lavc 56.6.0 - vorbis_parser.h
- Add a public API for parsing vorbis packets.
+-------- 8< --------- FFmpeg 2.5 was cut here -------- 8< ---------
+
+2014-11-21 - ab922f9 - lavu 54.15.100 - dict.h
+ Add av_dict_get_string().
+
+2014-11-18 - a54a51c - lavu 54.14.100 - float_dsp.h
+ Add avpriv_float_dsp_alloc().
+
+2014-11-16 - 6690d4c3 - lavf 56.13.100 - avformat.h
+ Add AVStream.recommended_encoder_configuration with accessors.
-2014-10-24 - 1bd0bdc - lavu 54.5.0 - time.h
- Add av_gettime_relative().
+2014-11-16 - bee5844d - lavu 54.13.100 - opt.h
+ Add av_opt_serialize().
-2014-10-15 - 7ea1b34 - lavc 56.5.0 - avcodec.h
+2014-11-16 - eec69332 - lavu 54.12.100 - opt.h
+ Add av_opt_is_set_to_default().
+
+2014-11-06 - 44fa267 / 5e80fb7 - lavc 56.11.100 / 56.6.0 - vorbis_parser.h
+ Add a public API for parsing vorbis packets.
+
+2014-10-15 - 17085a0 / 7ea1b34 - lavc 56.7.100 / 56.5.0 - avcodec.h
Replace AVCodecContext.time_base used for decoding
with AVCodecContext.framerate.
-2014-10-15 - d565fef1- lavc 56.4.0 - avcodec.h
+2014-10-15 - 51c810e / d565fef1 - lavc 56.6.100 / 56.4.0 - avcodec.h
Add AV_HWACCEL_FLAG_IGNORE_LEVEL flag to av_vdpau_bind_context().
-2014-10-13 - 2df0c32 - lavc 56.03.0 - avcodec.h
+2014-10-13 - da21895 / 2df0c32e - lavc 56.5.100 / 56.3.0 - avcodec.h
Add AVCodecContext.initial_padding. Deprecate the use of AVCodecContext.delay
for audio encoding.
-2014-10-08 - 5a419b2 - lavu 54.04.0 - pixdesc.h
+2014-10-08 - bb44f7d / 5a419b2 - lavu 54.10.100 / 54.4.0 - pixdesc.h
Add API to return the name of frame and context color properties.
-2014-10-06 - e3e158e - lavc 56.2.0 - vdpau.h
+2014-10-06 - a61899a / e3e158e - lavc 56.3.100 / 56.2.0 - vdpau.h
Add av_vdpau_bind_context(). This function should now be used for creating
(or resetting) a AVVDPAUContext instead of av_vdpau_alloc_context().
-2014-08-25 - b263f8f - lavf 56.03.0 - avformat.h
- Add AVFormatContext.max_ts_probe.
+2014-10-02 - cdd6f05 - lavc 56.2.100 - avcodec.h
+2014-10-02 - cdd6f05 - lavu 54.9.100 - frame.h
+ Add AV_FRAME_DATA_SKIP_SAMPLES. Add lavc CODEC_FLAG2_SKIP_MANUAL and
+ AVOption "skip_manual", which makes lavc export skip information via
+ AV_FRAME_DATA_SKIP_SAMPLES AVFrame side data, instead of skipping and
+ discarding samples automatically.
-------------------------------8<-------------------------------------
- 11 branch was cut here
------------------------------>8--------------------------------------
+2014-10-02 - 0d92b0d - lavu 54.8.100 - avstring.h
+ Add av_match_list()
-2014-08-28 - 9301486 - lavc 56.1.0 - avcodec.h
+2014-09-24 - ac68295 - libpostproc 53.1.100
+ Add visualization support
+
+2014-09-19 - 6edd6a4 - lavc 56.1.101 - dv_profile.h
+ deprecate avpriv_dv_frame_profile2(), which was made public by accident.
+
+
+-------- 8< --------- FFmpeg 2.4 was cut here -------- 8< ---------
+
+2014-08-25 - 215db29 / b263f8f - lavf 56.3.100 / 56.3.0 - avformat.h
+ Add AVFormatContext.max_ts_probe.
+
+2014-08-28 - f30a815 / 9301486 - lavc 56.1.100 / 56.1.0 - avcodec.h
Add AV_PKT_DATA_STEREO3D to export container-level stereo3d information.
-2014-08-13 - 8ddc326 - lavu 54.03.0 - mem.h
+2014-08-23 - 8fc9bd0 - lavu 54.7.100 - dict.h
+ AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL arguments are now
+ freed even on error. This is consistent with the behaviour all users
+ of it we could find expect.
+
+2014-08-21 - 980a5b0 - lavu 54.6.100 - frame.h motion_vector.h
+ Add AV_FRAME_DATA_MOTION_VECTORS side data and AVMotionVector structure
+
+2014-08-16 - b7d5e01 - lswr 1.1.100 - swresample.h
+ Add AVFrame based API
+
+2014-08-16 - c2829dc - lavu 54.4.100 - dict.h
+ Add av_dict_set_int helper function.
+
+2014-08-13 - c8571c6 / 8ddc326 - lavu 54.3.100 / 54.3.0 - mem.h
Add av_strndup().
-2014-08-13 - a8c104a - lavu 54.02.0 - opt.h
+2014-08-13 - 2ba4577 / a8c104a - lavu 54.2.100 / 54.2.0 - opt.h
Add av_opt_get_dict_val/set_dict_val with AV_OPT_TYPE_DICT to support
dictionary types being set as options.
@@ -100,334 +189,737 @@ API changes, most recent first:
Add AVFormatContext.event_flags and AVStream.event_flags for signaling to
the user when events happen in the file/stream.
-2014-08-10 - fb1ddcd - lavr 2.1.0 - avresample.h
+2014-08-10 - 78eaaa8 / fb1ddcd - lavr 2.1.0 - avresample.h
Add avresample_convert_frame() and avresample_config().
-2014-08-10 - fb1ddcd - lavu 54.1.0 - error.h
+2014-08-10 - 78eaaa8 / fb1ddcd - lavu 54.1.100 / 54.1.0 - error.h
Add AVERROR_INPUT_CHANGED and AVERROR_OUTPUT_CHANGED.
-2014-08-08 - d35b94f - lavc 55.57.4 - avcodec.h
+2014-08-08 - 3841f2a / d35b94f - lavc 55.73.102 / 55.57.4 - avcodec.h
Deprecate FF_IDCT_XVIDMMX define and xvidmmx idct option.
Replaced by FF_IDCT_XVID and xvid respectively.
+2014-08-08 - 5c3c671 - lavf 55.53.100 - avio.h
+ Add avio_feof() and deprecate url_feof().
+
2014-08-07 - bb78903 - lsws 2.1.3 - swscale.h
- sws_getCachedContext is not going to be removed in the future.
+ sws_getContext is not going to be removed in the future.
-2014-08-07 - ad1ee5f - lavc 55.57.3 - avcodec.h
+2014-08-07 - a561662 / ad1ee5f - lavc 55.73.101 / 55.57.3 - avcodec.h
reordered_opaque is not going to be removed in the future.
-2014-08-04 - e9abafc - lavu 53.22.0 - pixfmt.h
+2014-08-02 - 28a2107 - lavu 52.98.100 - pixelutils.h
+ Add pixelutils API with SAD functions
+
+2014-08-04 - 6017c98 / e9abafc - lavu 52.97.100 / 53.22.0 - pixfmt.h
Add AV_PIX_FMT_YA16 pixel format for 16 bit packed gray with alpha.
-2014-08-04 - e96c3b8 - lavu 53.21.1 - avstring.h
+2014-08-04 - 4c8bc6f / e96c3b8 - lavu 52.96.101 / 53.21.1 - avstring.h
Rename AV_PIX_FMT_Y400A to AV_PIX_FMT_YA8 to better identify the format.
An alias pixel format and color space name are provided for compatibility.
-2014-08-04 - d2962e9 - lavu 53.21.0 - pixdesc.h
+2014-08-04 - 073c074 / d2962e9 - lavu 52.96.100 / 53.21.0 - pixdesc.h
Support name aliases for pixel formats.
-2014-08-03 - 1ef9e83 - lavc 55.57.2 - avcodec.h
-2014-08-03 - 1ef9e83 - lavu 53.20.0 - frame.h
+2014-08-03 - 71d008e / 1ef9e83 - lavc 55.72.101 / 55.57.2 - avcodec.h
+2014-08-03 - 71d008e / 1ef9e83 - lavu 52.95.100 / 53.20.0 - frame.h
Deprecate AVCodecContext.dtg_active_format and use side-data instead.
-2014-08-03 - 9f17685 - lavc 55.57.1 - avcodec.h
+2014-08-03 - e680c73 - lavc 55.72.100 - avcodec.h
+ Add get_pixels() to AVDCT
+
+2014-08-03 - 9400603 / 9f17685 - lavc 55.71.101 / 55.57.1 - avcodec.h
Deprecate unused FF_IDCT_IPP define and ipp avcodec option.
Deprecate unused FF_DEBUG_PTS define and pts avcodec option.
Deprecate unused FF_CODER_TYPE_DEFLATE define and deflate avcodec option.
Deprecate unused FF_DCT_INT define and int avcodec option.
Deprecate unused avcodec option scenechange_factor.
-2014-07-29 - 69e7336 - lavu 53.19.0 - avstring.h
+2014-07-30 - ba3e331 - lavu 52.94.100 - frame.h
+ Add av_frame_side_data_name()
+
+2014-07-29 - 80a3a66 / 3a19405 - lavf 56.01.100 / 56.01.0 - avformat.h
+ Add mime_type field to AVProbeData, which now MUST be initialized in
+ order to avoid uninitialized reads of the mime_type pointer, likely
+ leading to crashes.
+ Typically, this means you will do 'AVProbeData pd = { 0 };' instead of
+ 'AVProbeData pd;'.
+
+2014-07-29 - 31e0b5d / 69e7336 - lavu 52.92.100 / 53.19.0 - avstring.h
Make name matching function from lavf public as av_match_name().
-2014-07-28 - c5fca01 - lavc 55.57.0 - avcodec.h
+2014-07-28 - 2e5c8b0 / c5fca01 - lavc 55.71.100 / 55.57.0 - avcodec.h
Add AV_CODEC_PROP_REORDER to mark codecs supporting frame reordering.
-2014-07-09 - a54f03b - lavu 53.18.0 - display.h
+2014-07-27 - ff9a154 - lavf 55.50.100 - avformat.h
+ New field int64_t probesize2 instead of deprecated
+ field int probesize.
+
+2014-07-27 - 932ff70 - lavc 55.70.100 - avdct.h
+ Add AVDCT / avcodec_dct_alloc() / avcodec_dct_init().
+
+2014-07-23 - 8a4c086 - lavf 55.49.100 - avio.h
+ Add avio_read_to_bprint()
+
+
+-------- 8< --------- FFmpeg 2.3 was cut here -------- 8< ---------
+
+2014-07-14 - 62227a7 - lavf 55.47.100 - avformat.h
+ Add av_stream_get_parser()
+
+2014-07-09 - c67690f / a54f03b - lavu 52.92.100 / 53.18.0 - display.h
Add av_display_matrix_flip() to flip the transformation matrix.
-2014-07-09 - f6ee61f - lavc 55.56.0 - dv_profile.h
+2014-07-09 - 1b58f13 / f6ee61f - lavc 55.69.100 / 55.56.0 - dv_profile.h
Add a public API for DV profile handling.
-2014-06-20 - 9e500ef - lavu 53.17.0 - imgutils.h
+2014-06-20 - 0dceefc / 9e500ef - lavu 52.90.100 / 53.17.0 - imgutils.h
Add av_image_check_sar().
-2014-06-20 - 874390e - lavc 55.55.0 - avcodec.h
+2014-06-20 - 4a99333 / 874390e - lavc 55.68.100 / 55.55.0 - avcodec.h
Add av_packet_rescale_ts() to simplify timestamp conversion.
-2014-06-18 - 194be1f - lavf 55.20.0 - avformat.h
+2014-06-18 - ac293b6 / 194be1f - lavf 55.44.100 / 55.20.0 - avformat.h
The proper way for providing a hint about the desired timebase to the muxers
is now setting AVStream.time_base, instead of AVStream.codec.time_base as was
done previously. The old method is now deprecated.
-2014-06-01 - 0957b27 - lavc 55.54.0 - avcodec.h
+2014-06-11 - 67d29da - lavc 55.66.101 - avcodec.h
+ Increase FF_INPUT_BUFFER_PADDING_SIZE to 32 due to some corner cases needing
+ it
+
+2014-06-10 - 5482780 - lavf 55.43.100 - avformat.h
+ New field int64_t max_analyze_duration2 instead of deprecated
+ int max_analyze_duration.
+
+2014-05-30 - 00759d7 - lavu 52.89.100 - opt.h
+ Add av_opt_copy()
+
+2014-06-01 - 03bb99a / 0957b27 - lavc 55.66.100 / 55.54.0 - avcodec.h
Add AVCodecContext.side_data_only_packets to allow encoders to output packets
with only side data. This option may become mandatory in the future, so all
users are recommended to update their code and enable this option.
-2014-06-01 - 8c02adc - lavu 53.16.0 - frame.h, pixfmt.h
+2014-06-01 - 6e8e9f1 / 8c02adc - lavu 52.88.100 / 53.16.0 - frame.h, pixfmt.h
Move all color-related enums (AVColorPrimaries, AVColorSpace, AVColorRange,
AVColorTransferCharacteristic, and AVChromaLocation) inside lavu.
- Add AVFrame fields for them on the next lavu major bump.
+ And add AVFrame fields for them.
-2014-05-28 - b2d4565 - lavr 1.3.0 - avresample.h
+2014-05-29 - bdb2e80 / b2d4565 - lavr 1.3.0 - avresample.h
Add avresample_max_output_samples
-2014-05-28 - 6d21259 - lavf 55.19.0 - avformat.h
+2014-05-28 - d858ee7 / 6d21259 - lavf 55.42.100 / 55.19.0 - avformat.h
Add strict_std_compliance and related AVOptions to support experimental
muxing.
-2014-05-20 - c23c96b - lavf 55.18.0 - avformat.h
+2014-05-26 - 55cc60c - lavu 52.87.100 - threadmessage.h
+ Add thread message queue API.
+
+2014-05-26 - c37d179 - lavf 55.41.100 - avformat.h
+ Add format_probesize to AVFormatContext.
+
+2014-05-20 - 7d25af1 / c23c96b - lavf 55.39.100 / 55.18.0 - avformat.h
Add av_stream_get_side_data() to access stream-level side data
in the same way as av_packet_get_side_data().
-2014-05-19 - bddd8cb - lavu 53.15.0 - frame.h, display.h
+2014-05-20 - 7336e39 - lavu 52.86.100 - fifo.h
+ Add av_fifo_alloc_array() function.
+
+2014-05-19 - ef1d4ee / bddd8cb - lavu 52.85.100 / 53.15.0 - frame.h, display.h
Add AV_FRAME_DATA_DISPLAYMATRIX for exporting frame-level
spatial rendering on video frames for proper display.
-2014-05-19 - bddd8cb - lavc 55.53.0 - avcodec.h
+2014-05-19 - ef1d4ee / bddd8cb - lavc 55.64.100 / 55.53.0 - avcodec.h
Add AV_PKT_DATA_DISPLAYMATRIX for exporting packet-level
spatial rendering on video frames for proper display.
-2014-05-19 - a312f71 - lavf 55.17.1 - avformat.h
+2014-05-19 - 999a99c / a312f71 - lavf 55.38.101 / 55.17.1 - avformat.h
Deprecate AVStream.pts and the AVFrac struct, which was its only use case.
- Those fields were poorly defined and not meant to be public, so there is
- no replacement for them.
+ See use av_stream_get_end_pts()
-2014-05-18 - fd05602 - lavc 55.52.0 - avcodec.h
+2014-05-18 - 68c0518 / fd05602 - lavc 55.63.100 / 55.52.0 - avcodec.h
Add avcodec_free_context(). From now on it should be used for freeing
AVCodecContext.
-2014-05-15 - 0c1959b - lavf 55.17.0 - avformat.h
+2014-05-17 - 0eec06e / 1bd0bdc - lavu 52.84.100 / 54.5.0 - time.h
+ Add av_gettime_relative() av_gettime_relative_is_monotonic()
+
+2014-05-15 - eacf7d6 / 0c1959b - lavf 55.38.100 / 55.17.0 - avformat.h
Add AVFMT_FLAG_BITEXACT flag. Muxers now use it instead of checking
CODEC_FLAG_BITEXACT on the first stream.
-2014-05-11 - 66e6c8a - lavu 53.14.0 - pixfmt.h
+2014-05-15 - 96cb4c8 - lswr 0.19.100 - swresample.h
+ Add swr_close()
+
+2014-05-11 - 14aef38 / 66e6c8a - lavu 52.83.100 / 53.14.0 - pixfmt.h
Add AV_PIX_FMT_VDA for new-style VDA acceleration.
-2014-05-01 - a2941c8 - lavc 55.50.3 - avcodec.h
+2014-05-07 - 351f611 - lavu 52.82.100 - fifo.h
+ Add av_fifo_freep() function.
+
+2014-05-02 - ba52fb11 - lavu 52.81.100 - opt.h
+ Add av_opt_set_dict2() function.
+
+2014-05-01 - e77b985 / a2941c8 - lavc 55.60.103 / 55.50.3 - avcodec.h
Deprecate CODEC_FLAG_MV0. It is replaced by the flag "mv0" in the
"mpv_flags" private option of the mpegvideo encoders.
-2014-05-01 - 6484149 - lavc 55.50.2 - avcodec.h
+2014-05-01 - e40ae8c / 6484149 - lavc 55.60.102 / 55.50.2 - avcodec.h
Deprecate CODEC_FLAG_GMC. It is replaced by the "gmc" private option of the
libxvid encoder.
-2014-05-01 - b2c3171 - lavc 55.50.1 - avcodec.h
+2014-05-01 - 1851643 / b2c3171 - lavc 55.60.101 / 55.50.1 - avcodec.h
Deprecate CODEC_FLAG_NORMALIZE_AQP. It is replaced by the flag "naq" in the
"mpv_flags" private option of the mpegvideo encoders.
-2014-05-01 - 5fcceda - avcodec.h
+2014-05-01 - cac07d0 / 5fcceda - avcodec.h
Deprecate CODEC_FLAG_INPUT_PRESERVED. Its functionality is replaced by passing
reference-counted frames to encoders.
-2014-04-28 - ed4b757 - lavc 55.50.0 - dxva2.h
+2014-04-30 - 617e866 - lavu 52.81.100 - pixdesc.h
+ Add av_find_best_pix_fmt_of_2(), av_get_pix_fmt_loss()
+ Deprecate avcodec_get_pix_fmt_loss(), avcodec_find_best_pix_fmt_of_2()
+
+2014-04-29 - 1bf6396 - lavc 55.60.100 - avcodec.h
+ Add AVCodecDescriptor.mime_types field.
+
+2014-04-29 - b804eb4 - lavu 52.80.100 - hash.h
+ Add av_hash_final_bin(), av_hash_final_hex() and av_hash_final_b64().
+
+2014-03-07 - 8b2a130 - lavc 55.50.0 / 55.53.100 - dxva2.h
Add FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO for old Intel GPUs.
-2014-04-22 - 502512e - lavu 53.13.0 - avutil.h
+2014-04-22 - 502512e /dac7e8a - lavu 53.13.0 / 52.78.100 - avutil.h
Add av_get_time_base_q().
-2014-04-17 - 0983d48 - lavu 53.12.0 - crc.h
+2014-04-17 - a8d01a7 / 0983d48 - lavu 53.12.0 / 52.77.100 - crc.h
Add AV_CRC_16_ANSI_LE crc variant.
-2014-04-07 - 8b17243 - lavu 53.11.0 - pixfmt.h
+2014-04-15 - ef818d8 - lavf 55.37.101 - avformat.h
+ Add av_format_inject_global_side_data()
+
+2014-04-12 - 4f698be - lavu 52.76.100 - log.h
+ Add av_log_get_flags()
+
+2014-04-11 - 6db42a2b - lavd 55.12.100 - avdevice.h
+ Add avdevice_capabilities_create() function.
+ Add avdevice_capabilities_free() function.
+
+2014-04-07 - 0a1cc04 / 8b17243 - lavu 52.75.100 / 53.11.0 - pixfmt.h
Add AV_PIX_FMT_YVYU422 pixel format.
-2014-04-04 - 8542f9c - lavu 53.10.0 - replaygain.h
+2014-04-04 - c1d0536 / 8542f9c - lavu 52.74.100 / 53.10.0 - replaygain.h
Full scale for peak values is now 100000 (instead of UINT32_MAX) and values
may overflow.
-2014-04-03 - 7763118 - lavu 53.09.0 - log.h
+2014-04-03 - c16e006 / 7763118 - lavu 52.73.100 / 53.9.0 - log.h
Add AV_LOG(c) macro to have 256 color debug messages.
-2014-03-24 - d161ae0 - lavu 53.08.0 - frame.h
+2014-04-03 - eaed4da9 - lavu 52.72.100 - opt.h
+ Add AV_OPT_MULTI_COMPONENT_RANGE define to allow return
+ multi-component option ranges.
+
+2014-03-29 - cd50a44b - lavu 52.70.100 - mem.h
+ Add av_dynarray_add_nofree() function.
+
+2014-02-24 - 3e1f241 / d161ae0 - lavu 52.69.100 / 53.8.0 - frame.h
Add av_frame_remove_side_data() for removing a single side data
instance from a frame.
-2014-03-24 - 5a7e35d - lavu 53.07.0 - frame.h, replaygain.h
+2014-03-24 - 83e8978 / 5a7e35d - lavu 52.68.100 / 53.7.0 - frame.h, replaygain.h
Add AV_FRAME_DATA_REPLAYGAIN for exporting replaygain tags.
Add a new header replaygain.h with the AVReplayGain struct.
-2014-03-24 - 5a7e35d - lavc 55.36.0 - avcodec.h
+2014-03-24 - 83e8978 / 5a7e35d - lavc 55.54.100 / 55.36.0 - avcodec.h
Add AV_PKT_DATA_REPLAYGAIN for exporting replaygain tags.
-2014-03-24 - 25b3258 - lavf 55.13.0 - avformat.h
+2014-03-24 - 595ba3b / 25b3258 - lavf 55.35.100 / 55.13.0 - avformat.h
Add AVStream.side_data and AVStream.nb_side_data for exporting stream-global
side data (e.g. replaygain tags, video rotation)
-2014-03-24 - 0e2c3ee - lavc 55.35.0 - avcodec.h
+2014-03-24 - bd34e26 / 0e2c3ee - lavc 55.53.100 / 55.35.0 - avcodec.h
Give the name AVPacketSideData to the previously anonymous struct used for
AVPacket.side_data.
-2014-03-16 - 1481d24 - lavu 53.06.0 - pixfmt.h
- Add RGBA64 pixel format and variants.
-2014-02-24 - 1155fd0 - lavu 53.05.0 - frame.h
+-------- 8< --------- FFmpeg 2.2 was cut here -------- 8< ---------
+
+2014-03-18 - 37c07d4 - lsws 2.5.102
+ Make gray16 full-scale.
+
+2014-03-16 - 6b1ca17 / 1481d24 - lavu 52.67.100 / 53.6.0 - pixfmt.h
+ Add RGBA64_LIBAV pixel format and variants for compatibility
+
+2014-03-11 - 3f3229c - lavf 55.34.101 - avformat.h
+ Set AVFormatContext.start_time_realtime when demuxing.
+
+2014-03-03 - 06fed440 - lavd 55.11.100 - avdevice.h
+ Add av_input_audio_device_next().
+ Add av_input_video_device_next().
+ Add av_output_audio_device_next().
+ Add av_output_video_device_next().
+
+2014-02-24 - fff5262 / 1155fd0 - lavu 52.66.100 / 53.5.0 - frame.h
Add av_frame_copy() for copying the frame data.
-2014-02-22 - 7e86c27 - lavr 1.2.0 - avresample.h
+2014-02-24 - a66be60 - lswr 0.18.100 - swresample.h
+ Add swr_is_initialized() for checking whether a resample context is initialized.
+
+2014-02-22 - 5367c0b / 7e86c27 - lavr 1.2.0 - avresample.h
Add avresample_is_open() for checking whether a resample context is open.
-2014-02-19 - c3ecd96 - lavu 53.04.0 - opt.h
+2014-02-19 - 6a24d77 / c3ecd96 - lavu 52.65.100 / 53.4.0 - opt.h
Add AV_OPT_FLAG_EXPORT and AV_OPT_FLAG_READONLY to mark options meant (only)
for reading.
-2014-02-19 - 6bb8720 - lavu 53.03.01 - opt.h
+2014-02-19 - f4c8d00 / 6bb8720 - lavu 52.64.101 / 53.3.1 - opt.h
Deprecate unused AV_OPT_FLAG_METADATA.
-------------------------------8<-------------------------------------
- 10 branch was cut here
------------------------------>8--------------------------------------
+2014-02-16 - 81c3f81 - lavd 55.10.100 - avdevice.h
+ Add avdevice_list_devices() and avdevice_free_list_devices()
-2014-02-15 - c98f316 - lavu 53.3.0 - frame.h
+2014-02-16 - db3c970 - lavf 55.33.100 - avio.h
+ Add avio_find_protocol_name() to find out the name of the protocol that would
+ be selected for a given URL.
+
+2014-02-15 - a2bc6c1 / c98f316 - lavu 52.64.100 / 53.3.0 - frame.h
Add AV_FRAME_DATA_DOWNMIX_INFO value to the AVFrameSideDataType enum and
downmix_info.h API, which identify downmix-related metadata.
-2014-02-04 - d9ae103 - lavf 55.11.0 - avformat.h
+2014-02-11 - 1b05ac2 - lavf 55.32.100 - avformat.h
+ Add av_write_uncoded_frame() and av_interleaved_write_uncoded_frame().
+
+2014-02-04 - 3adb5f8 / d9ae103 - lavf 55.30.100 / 55.11.0 - avformat.h
Add AVFormatContext.max_interleave_delta for controlling amount of buffering
when interleaving.
-2014-01-20 - 93c553c - lavc 55.32.1 - avcodec.h
+2014-02-02 - 5871ee5 - lavf 55.29.100 - avformat.h
+ Add output_ts_offset muxing option to AVFormatContext.
+
+2014-01-27 - 102bd64 - lavd 55.7.100 - avdevice.h
+ lavf 55.28.100 - avformat.h
+ Add avdevice_dev_to_app_control_message() function.
+
+2014-01-27 - 7151411 - lavd 55.6.100 - avdevice.h
+ lavf 55.27.100 - avformat.h
+ Add avdevice_app_to_dev_control_message() function.
+
+2014-01-24 - 86bee79 - lavf 55.26.100 - avformat.h
+ Add AVFormatContext option metadata_header_padding to allow control over the
+ amount of padding added.
+
+2014-01-20 - eef74b2 / 93c553c - lavc 55.48.102 / 55.32.1 - avcodec.h
Edges are not required anymore on video buffers allocated by get_buffer2()
(i.e. as if the CODEC_FLAG_EMU_EDGE flag was always on). Deprecate
CODEC_FLAG_EMU_EDGE and avcodec_get_edge_width().
-2014-01-05 - 5b4797a - lavu 53.2.0 - frame.h
+2014-01-19 - 1a193c4 - lavf 55.25.100 - avformat.h
+ Add avformat_get_mov_video_tags() and avformat_get_mov_audio_tags().
+
+2014-01-19 - 3532dd5 - lavu 52.63.100 - rational.h
+ Add av_make_q() function.
+
+2014-01-05 - 4cf4da9 / 5b4797a - lavu 52.62.100 / 53.2.0 - frame.h
Add AV_FRAME_DATA_MATRIXENCODING value to the AVFrameSideDataType enum, which
identifies AVMatrixEncoding data.
-2014-01-05 - 5c437fb - lavu 53.1.0 - channel_layout.h
+2014-01-05 - 751385f / 5c437fb - lavu 52.61.100 / 53.1.0 - channel_layout.h
Add values for various Dolby flags to the AVMatrixEncoding enum.
-2013-12-20 - 2a41826 - lavc 55.30.0 - avcodec.h
- Add HEVC profiles
+2014-01-04 - b317f94 - lavu 52.60.100 - mathematics.h
+ Add av_add_stable() function.
+
+2013-12-22 - 911676c - lavu 52.59.100 - avstring.h
+ Add av_strnlen() function.
+
+2013-12-09 - 64f73ac - lavu 52.57.100 - opencl.h
+ Add av_opencl_benchmark() function.
+
+2013-11-30 - 82b2e9c - lavu 52.56.100 - ffversion.h
+ Moves version.h to libavutil/ffversion.h.
+ Install ffversion.h and make it public.
-2013-12-11 - b9fb59d,9431356,d7b3ee9 - lavc 55.28.1 - avcodec.h
+2013-12-11 - 29c83d2 / b9fb59d,409a143 / 9431356,44967ab / d7b3ee9 - lavc 55.45.101 / 55.28.1 - avcodec.h
av_frame_alloc(), av_frame_unref() and av_frame_free() now can and should be
used instead of avcodec_alloc_frame(), avcodec_get_frame_defaults() and
avcodec_free_frame() respectively. The latter three functions are deprecated.
-2013-12-09 - 7e244c6- - lavu 52.20.0 - frame.h
+2013-12-09 - 7a60348 / 7e244c6- - lavu 52.58.100 / 52.20.0 - frame.h
Add AV_FRAME_DATA_STEREO3D value to the AVFrameSideDataType enum and
stereo3d.h API, that identify codec-independent stereo3d information.
-2013-11-26 - 1eaac1d- - lavu 52.19.0 - frame.h
+2013-11-26 - 625b290 / 1eaac1d- - lavu 52.55.100 / 52.19.0 - frame.h
Add AV_FRAME_DATA_A53_CC value to the AVFrameSideDataType enum, which
identifies ATSC A53 Part 4 Closed Captions data.
-2013-11-14 - cce3e0a - lavu 52.18.0 - mem.h
+2013-11-22 - 6859065 - lavu 52.54.100 - avstring.h
+ Add av_utf8_decode() function.
+
+2013-11-22 - fb7d70c - lavc 55.44.100 - avcodec.h
+ Add HEVC profiles
+
+2013-11-20 - c28b61c - lavc 55.44.100 - avcodec.h
+ Add av_packet_{un,}pack_dictionary()
+ Add AV_PKT_METADATA_UPDATE side data type, used to transmit key/value
+ strings between a stream and the application.
+
+2013-11-14 - 7c888ae / cce3e0a - lavu 52.53.100 / 52.18.0 - mem.h
Move av_fast_malloc() and av_fast_realloc() for libavcodec to libavutil.
-2013-11-14 - 8941971 - lavc 55.27.0 - avcodec.h
+2013-11-14 - b71e4d8 / 8941971 - lavc 55.43.100 / 55.27.0 - avcodec.h
Deprecate AVCodecContext.error_rate, it is replaced by the 'error_rate'
private option of the mpegvideo encoder family.
-2013-11-14 - 728c465 - lavc 55.26.0 - vdpau.h
+2013-11-14 - 31c09b7 / 728c465 - lavc 55.42.100 / 55.26.0 - vdpau.h
Add av_vdpau_get_profile().
Add av_vdpau_alloc_context(). This function must from now on be
used for allocating AVVDPAUContext.
-2013-11-04 - cd8f772 - lavc 55.25.0 - avcodec.h
+2013-11-04 - be41f21 / cd8f772 - lavc 55.41.100 / 55.25.0 - avcodec.h
+ lavu 52.51.100 - frame.h
Add ITU-R BT.2020 and other not yet included values to color primaries,
transfer characteristics and colorspaces.
-2013-10-31 - 28096e0 - lavu 52.17.0 - frame.h
+2013-11-04 - 85cabf1 - lavu 52.50.100 - avutil.h
+ Add av_fopen_utf8()
+
+2013-10-31 - 78265fc / 28096e0 - lavu 52.49.100 / 52.17.0 - frame.h
Add AVFrame.flags and AV_FRAME_FLAG_CORRUPT.
-2013-09-28 - 0767bfd - lavfi 3.11.0 - avfilter.h
+
+-------- 8< --------- FFmpeg 2.1 was cut here -------- 8< ---------
+
+2013-10-27 - dbe6f9f - lavc 55.39.100 - avcodec.h
+ Add CODEC_CAP_DELAY support to avcodec_decode_subtitle2.
+
+2013-10-27 - d61617a - lavu 52.48.100 - parseutils.h
+ Add av_get_known_color_name().
+
+2013-10-17 - 8696e51 - lavu 52.47.100 - opt.h
+ Add AV_OPT_TYPE_CHANNEL_LAYOUT and channel layout option handlers
+ av_opt_get_channel_layout() and av_opt_set_channel_layout().
+
+2013-10-06 - ccf96f8 -libswscale 2.5.101 - options.c
+ Change default scaler to bicubic
+
+2013-10-03 - e57dba0 - lavc 55.34.100 - avcodec.h
+ Add av_codec_get_max_lowres()
+
+2013-10-02 - 5082fcc - lavf 55.19.100 - avformat.h
+ Add audio/video/subtitle AVCodec fields to AVFormatContext to force specific
+ decoders
+
+2013-09-28 - 7381d31 / 0767bfd - lavfi 3.88.100 / 3.11.0 - avfilter.h
Add AVFilterGraph.execute and AVFilterGraph.opaque for custom slice threading
implementations.
-2013-09-21 - e208e6d - lavu 52.16.0 - pixfmt.h
+2013-09-21 - 85f8a3c / e208e6d - lavu 52.46.100 / 52.16.0 - pixfmt.h
Add interleaved 4:2:2 8/10-bit formats AV_PIX_FMT_NV16 and
AV_PIX_FMT_NV20.
-2013-09-16 - 3feb3d6 - lavu 52.15.0 - mem.h
+2013-09-16 - c74c3fb / 3feb3d6 - lavu 52.44.100 / 52.15.0 - mem.h
Add av_reallocp.
-2013-08-10 - 5a9a9d4 - lavc 55.16.0 - avcodec.h
+2013-09-04 - 3e1f507 - lavc 55.31.101 - avcodec.h
+ avcodec_close() argument can be NULL.
+
+2013-09-04 - 36cd017a - lavf 55.16.101 - avformat.h
+ avformat_close_input() argument can be NULL and point on NULL.
+
+2013-08-29 - e31db62 - lavf 55.15.100 - avformat.h
+ Add av_format_get_probe_score().
+
+2013-08-15 - 1e0e193 - lsws 2.5.100 -
+ Add a sws_dither AVOption, allowing to set the dither algorithm used
+
+2013-08-11 - d404fe35 - lavc 55.27.100 - vdpau.h
+ Add a render2 alternative to the render callback function.
+
+2013-08-11 - af05edc - lavc 55.26.100 - vdpau.h
+ Add allocation function for AVVDPAUContext, allowing
+ to extend it in the future without breaking ABI/API.
+
+2013-08-10 - 67a580f / 5a9a9d4 - lavc 55.25.100 / 55.16.0 - avcodec.h
Extend AVPacket API with av_packet_unref, av_packet_ref,
av_packet_move_ref, av_packet_copy_props, av_packet_free_side_data.
-2013-08-05 - f824535 - lavc 55.13.0 - avcodec.h
+2013-08-05 - 9547e3e / f824535 - lavc 55.22.100 / 55.13.0 - avcodec.h
Deprecate the bitstream-related members from struct AVVDPAUContext.
- The bistream buffers no longer need to be explicitly freed.
+ The bitstream buffers no longer need to be explicitly freed.
-2013-08-05 - 549294f - lavc 55.12.0 - avcodec.h
+2013-08-05 - 3b805dc / 549294f - lavc 55.21.100 / 55.12.0 - avcodec.h
Deprecate the CODEC_CAP_HWACCEL_VDPAU codec capability. Use CODEC_CAP_HWACCEL
and select the AV_PIX_FMT_VDPAU format with get_format() instead.
-2013-08-05 - a0ad5d0 - lavu 52.14.0 - pixfmt.h
+2013-08-05 - 4ee0984 / a0ad5d0 - lavu 52.41.100 / 52.14.0 - pixfmt.h
Deprecate AV_PIX_FMT_VDPAU_*. Use AV_PIX_FMT_VDPAU instead.
-2013-08-02 - a8b1927 - lavc 55.11.0 - avcodec.h
+2013-08-02 - 82fdfe8 / a8b1927 - lavc 55.20.100 / 55.11.0 - avcodec.h
Add output_picture_number to AVCodecParserContext.
-2013-06-24 - 95d5246 - lavc 55.10.0 - avcodec.h
+2013-07-23 - abc8110 - lavc 55.19.100 - avcodec.h
+ Add avcodec_chroma_pos_to_enum()
+ Add avcodec_enum_to_chroma_pos()
+
+
+-------- 8< --------- FFmpeg 2.0 was cut here -------- 8< ---------
+
+2013-07-03 - 838bd73 - lavfi 3.78.100 - avfilter.h
+ Deprecate avfilter_graph_parse() in favor of the equivalent
+ avfilter_graph_parse_ptr().
+
+2013-06-24 - af5f9c0 / 95d5246 - lavc 55.17.100 / 55.10.0 - avcodec.h
Add MPEG-2 AAC profiles
-2013-06-04 - fc962d4 - lavu 52.13.0 - mem.h
+2013-06-25 - af5f9c0 / 95d5246 - lavf 55.10.100 - avformat.h
+ Add AV_DISPOSITION_* flags to indicate text track kind.
+
+2013-06-15 - 99b8cd0 - lavu 52.36.100
+ Add AVRIPEMD:
+ av_ripemd_alloc()
+ av_ripemd_init()
+ av_ripemd_update()
+ av_ripemd_final()
+
+2013-06-04 - 30b491f / fc962d4 - lavu 52.35.100 / 52.13.0 - mem.h
Add av_realloc_array and av_reallocp_array
-2013-05-24 - 129bb23 - lavfi 3.10.0 - avfilter.h
+2013-05-30 - 682b227 - lavu 52.35.100
+ Add AVSHA512:
+ av_sha512_alloc()
+ av_sha512_init()
+ av_sha512_update()
+ av_sha512_final()
+
+2013-05-24 - 8d4e969 / 129bb23 - lavfi 3.10.0 / 3.70.100 - avfilter.h
Add support for slice multithreading to lavfi. Filters supporting threading
are marked with AVFILTER_FLAG_SLICE_THREADS.
New fields AVFilterContext.thread_type, AVFilterGraph.thread_type and
AVFilterGraph.nb_threads (accessible directly or through AVOptions) may be
used to configure multithreading.
-2013-05-24 - 2a6eaea - lavu 52.12.0 - cpu.h
+2013-05-24 - fe40a9f / 2a6eaea - lavu 52.12.0 / 52.34.100 - cpu.h
Add av_cpu_count() function for getting the number of logical CPUs.
-2013-05-24 - b493847 - lavc 55.7.0 - avcodec.h
+2013-05-24 - 0c25c39 / b493847 - lavc 55.7.0 / 55.12.100 - avcodec.h
Add picture_structure to AVCodecParserContext.
-2013-05-15 - e6c4ac7 - lavu 52.11.0 - pixdesc.h
+2013-05-17 - 3a751ea - lavu 52.33.100 - opt.h
+ Add AV_OPT_TYPE_COLOR value to AVOptionType enum.
+
+2013-05-13 - e398416 - lavu 52.31.100 - mem.h
+ Add av_dynarray2_add().
+
+2013-05-12 - 1776177 - lavfi 3.65.100
+ Add AVFILTER_FLAG_SUPPORT_TIMELINE* filter flags.
+
+2013-04-19 - 380cfce - lavc 55.4.100
+ Add AV_CODEC_PROP_TEXT_SUB property for text based subtitles codec.
+
+2013-04-18 - 7c1a002 - lavf 55.3.100
+ The matroska demuxer can now output proper verbatim ASS packets. It will
+ become the default starting lavf 56.0.100.
+
+2013-04-10 - af0d270 - lavu 25.26.100 - avutil.h,opt.h
+ Add av_int_list_length()
+ and av_opt_set_int_list().
+
+2013-03-30 - 5c73645 - lavu 52.24.100 - samplefmt.h
+ Add av_samples_alloc_array_and_samples().
+
+2013-03-29 - ef7b6b4 - lavf 55.1.100 - avformat.h
+ Add av_guess_frame_rate()
+
+2013-03-20 - 8d928a9 - lavu 52.22.100 - opt.h
+ Add AV_OPT_TYPE_DURATION value to AVOptionType enum.
+
+2013-03-17 - 7aa9af5 - lavu 52.20.100 - opt.h
+ Add AV_OPT_TYPE_VIDEO_RATE value to AVOptionType enum.
+
+
+-------- 8< --------- FFmpeg 1.2 was cut here -------- 8< ---------
+
+2013-03-07 - 9767ec6 - lavu 52.18.100 - avstring.h,bprint.h
+ Add av_escape() and av_bprint_escape() API.
+
+2013-02-24 - b59cd08 - lavfi 3.41.100 - buffersink.h
+ Add sample_rates field to AVABufferSinkParams.
+
+2013-01-17 - a1a707f - lavf 54.61.100
+ Add av_codec_get_tag2().
+
+2013-01-01 - 2eb2e17 - lavfi 3.34.100
+ Add avfilter_get_audio_buffer_ref_from_arrays_channels.
+
+
+-------- 8< --------- FFmpeg 1.1 was cut here -------- 8< ---------
+
+2012-12-20 - 34de47aa - lavfi 3.29.100 - avfilter.h
+ Add AVFilterLink.channels, avfilter_link_get_channels()
+ and avfilter_ref_get_channels().
+
+2012-12-15 - 96d815fc - lavc 54.80.100 - avcodec.h
+ Add pkt_size field to AVFrame.
+
+2012-11-25 - c70ec631 - lavu 52.9.100 - opt.h
+ Add the following convenience functions to opt.h:
+ av_opt_get_image_size
+ av_opt_get_pixel_fmt
+ av_opt_get_sample_fmt
+ av_opt_set_image_size
+ av_opt_set_pixel_fmt
+ av_opt_set_sample_fmt
+
+2012-11-17 - 4cd74c81 - lavu 52.8.100 - bprint.h
+ Add av_bprint_strftime().
+
+2012-11-15 - 92648107 - lavu 52.7.100 - opt.h
+ Add av_opt_get_key_value().
+
+2012-11-13 - 79456652 - lavfi 3.23.100 - avfilter.h
+ Add channels field to AVFilterBufferRefAudioProps.
+
+2012-11-03 - 481fdeee - lavu 52.3.100 - opt.h
+ Add AV_OPT_TYPE_SAMPLE_FMT value to AVOptionType enum.
+
+2012-10-21 - 6fb2fd8 - lavc 54.68.100 - avcodec.h
+ lavfi 3.20.100 - avfilter.h
+ Add AV_PKT_DATA_STRINGS_METADATA side data type, used to transmit key/value
+ strings between AVPacket and AVFrame, and add metadata field to
+ AVCodecContext (which shall not be accessed by users; see AVFrame metadata
+ instead).
+
+2012-09-27 - a70b493 - lavd 54.3.100 - version.h
+ Add LIBAVDEVICE_IDENT symbol.
+
+2012-09-27 - a70b493 - lavfi 3.18.100 - version.h
+ Add LIBAVFILTER_IDENT symbol.
+
+2012-09-27 - a70b493 - libswr 0.16.100 - version.h
+ Add LIBSWRESAMPLE_VERSION, LIBSWRESAMPLE_BUILD
+ and LIBSWRESAMPLE_IDENT symbols.
+
+
+-------- 8< --------- FFmpeg 1.0 was cut here -------- 8< ---------
+
+2012-09-06 - 29e972f - lavu 51.72.100 - parseutils.h
+ Add av_small_strptime() time parsing function.
+
+ Can be used as a stripped-down replacement for strptime(), on
+ systems which do not support it.
+
+2012-08-25 - 2626cc4 - lavf 54.28.100
+ Matroska demuxer now identifies SRT subtitles as AV_CODEC_ID_SUBRIP instead
+ of AV_CODEC_ID_TEXT.
+
+2012-08-13 - 5c0d8bc - lavfi 3.8.100 - avfilter.h
+ Add avfilter_get_class() function, and priv_class field to AVFilter
+ struct.
+
+2012-08-12 - a25346e - lavu 51.69.100 - opt.h
+ Add AV_OPT_FLAG_FILTERING_PARAM symbol in opt.h.
+
+2012-07-31 - 23fc4dd - lavc 54.46.100
+ Add channels field to AVFrame.
+
+2012-07-30 - f893904 - lavu 51.66.100
+ Add av_get_channel_description()
+ and av_get_standard_channel_layout() functions.
+
+2012-07-21 - 016a472 - lavc 54.43.100
+ Add decode_error_flags field to AVFrame.
+
+2012-07-20 - b062936 - lavf 54.18.100
+ Add avformat_match_stream_specifier() function.
+
+2012-07-14 - f49ec1b - lavc 54.38.100 - avcodec.h
+ Add metadata to AVFrame, and the accessor functions
+ av_frame_get_metadata() and av_frame_set_metadata().
+
+2012-07-10 - 0e003d8 - lavc 54.33.100
+ Add av_fast_padded_mallocz().
+
+2012-07-10 - 21d5609 - lavfi 3.2.0 - avfilter.h
+ Add init_opaque() callback to AVFilter struct.
+
+2012-06-26 - e6674e4 - lavu 51.63.100 - imgutils.h
+ Add functions to libavutil/imgutils.h:
+ av_image_get_buffer_size()
+ av_image_fill_arrays()
+ av_image_copy_to_buffer()
+
+2012-06-24 - c41899a - lavu 51.62.100 - version.h
+ version moved from avutil.h to version.h
+
+2012-04-11 - 359abb1 - lavu 51.58.100 - error.h
+ Add av_make_error_string() and av_err2str() utilities to
+ libavutil/error.h.
+
+2012-06-05 - 62b39d4 - lavc 54.24.100
+ Add pkt_duration field to AVFrame.
+
+2012-05-24 - f2ee065 - lavu 51.54.100
+ Move AVPALETTE_SIZE and AVPALETTE_COUNT macros from
+ libavcodec/avcodec.h to libavutil/pixfmt.h.
+
+2012-05-14 - 94a9ac1 - lavf 54.5.100
+ Add av_guess_sample_aspect_ratio() function.
+
+2012-04-20 - 65fa7bc - lavfi 2.70.100
+ Add avfilter_unref_bufferp() to avfilter.h.
+
+2012-04-13 - 162e400 - lavfi 2.68.100
+ Install libavfilter/asrc_abuffer.h public header.
+
+2012-03-26 - a67d9cf - lavfi 2.66.100
+ Add avfilter_fill_frame_from_{audio_,}buffer_ref() functions.
+
+2013-05-15 - ff46809 / e6c4ac7 - lavu 52.32.100 / 52.11.0 - pixdesc.h
Replace PIX_FMT_* flags with AV_PIX_FMT_FLAG_*.
-2013-04-03 - 507b1e4 - lavc 55.4.0 - avcodec.h
+2013-04-03 - 6fc58a8 / 507b1e4 - lavc 55.7.100 / 55.4.0 - avcodec.h
Add field_order to AVCodecParserContext.
-2013-04-19 - 5e83d9a - lavc 55.2.0 - avcodec.h
+2013-04-19 - f4b05cd / 5e83d9a - lavc 55.5.100 / 55.2.0 - avcodec.h
Add CODEC_FLAG_UNALIGNED to allow decoders to produce unaligned output.
-2013-04-11 - lavfi 3.8.0
- 38f0c07 - Move all content from avfiltergraph.h to avfilter.h. Deprecate
+2013-04-11 - lavfi 3.53.100 / 3.8.0
+ 231fd44 / 38f0c07 - Move all content from avfiltergraph.h to avfilter.h. Deprecate
avfilterhraph.h, user applications should include just avfilter.h
- bc1a985 - Add avfilter_graph_alloc_filter(), deprecate avfilter_open() and
+ 86070b8 / bc1a985 - Add avfilter_graph_alloc_filter(), deprecate avfilter_open() and
avfilter_graph_add_filter().
- 1113672 - Add AVFilterContext.graph pointing to the AVFilterGraph that contains the
+ 4fde705 / 1113672 - Add AVFilterContext.graph pointing to the AVFilterGraph that contains the
filter.
- 48a5ada - Add avfilter_init_str(), deprecate avfilter_init_filter().
- 1ba95a9 - Add avfilter_init_dict().
- 7cdd737 - Add AVFilter.flags field and AVFILTER_FLAG_DYNAMIC_{INPUTS,OUTPUTS} flags.
- 7e8fe4b - Add avfilter_pad_count() for counting filter inputs/outputs.
- fa2a34c - Add avfilter_next(), deprecate av_filter_next().
+ 710b0aa / 48a5ada - Add avfilter_init_str(), deprecate avfilter_init_filter().
+ 46de9ba / 1ba95a9 - Add avfilter_init_dict().
+ 16fc24b / 7cdd737 - Add AVFilter.flags field and AVFILTER_FLAG_DYNAMIC_{INPUTS,OUTPUTS} flags.
+ f4db6bf / 7e8fe4b - Add avfilter_pad_count() for counting filter inputs/outputs.
+ 835cc0f / fa2a34c - Add avfilter_next(), deprecate av_filter_next().
Deprecate avfilter_uninit().
-2013-04-09 - lavfi 3.7.0 - avfilter.h
- b439c99 - Add AVFilter.priv_class for exporting filter options through the
+2013-04-09 - lavfi 3.51.100 / 3.7.0 - avfilter.h
+ 0594ef0 / b439c99 - Add AVFilter.priv_class for exporting filter options through the
AVOptions API in the similar way private options work in lavc and lavf.
- 8114c10 - Add avfilter_get_class().
+ 44d4488 / 8114c10 - Add avfilter_get_class().
Switch all filters to use AVOptions.
-2013-03-19 - 2c328a9 - lavu 52.9.0 - pixdesc.h
+2013-03-19 - 17ebef2 / 2c328a9 - lavu 52.20.100 / 52.9.0 - pixdesc.h
Add av_pix_fmt_count_planes() function for counting planes in a pixel format.
-2013-03-16 - 42c7c61 - lavfi 3.6.0
+2013-03-16 - ecade98 / 42c7c61 - lavfi 3.47.100 / 3.6.0
Add AVFilterGraph.nb_filters, deprecate AVFilterGraph.filter_count.
-2013-03-08 - Reference counted buffers - lavu 52.8.0, lavc 55.0.0, lavf 55.0.0,
-lavd 54.0.0, lavfi 3.5.0
- 8e401db, 1cec062 - add a new API for reference counted buffers and buffer
+2013-03-08 - Reference counted buffers - lavu 52.8.0, lavc 55.0.100 / 55.0.0, lavf 55.0.100 / 55.0.0,
+lavd 54.4.100 / 54.0.0, lavfi 3.5.0
+ 36099df / 8e401db, 532f31a / 1cec062 - add a new API for reference counted buffers and buffer
pools (new header libavutil/buffer.h).
- 1afddbe - add AVPacket.buf to allow reference counting for the AVPacket data.
+ 2653e12 / 1afddbe - add AVPacket.buf to allow reference counting for the AVPacket data.
Add av_packet_from_data() function for constructing packets from
av_malloc()ed data.
- 7ecc2d4 - move AVFrame from lavc to lavu (new header libavutil/frame.h), add
+ c4e8821 / 7ecc2d4 - move AVFrame from lavc to lavu (new header libavutil/frame.h), add
AVFrame.buf/extended_buf to allow reference counting for the AVFrame
data. Add new API for working with reference-counted AVFrames.
- 759001c - add the refcounted_frames field to AVCodecContext to make audio and
+ 80e9e63 / 759001c - add the refcounted_frames field to AVCodecContext to make audio and
video decoders return reference-counted frames. Add get_buffer2()
callback to AVCodecContext which allocates reference-counted frames.
Add avcodec_default_get_buffer2() as the default get_buffer2()
@@ -445,68 +937,63 @@ lavd 54.0.0, lavfi 3.5.0
* qscale_table, qstride, qscale_type, mbskip_table, motion_val,
mb_type, dct_coeff, ref_index -- mpegvideo-specific tables,
which are not exported anymore.
- 7e35037 - switch libavfilter to use AVFrame instead of AVFilterBufferRef. Add
+ a05a44e / 7e35037 - switch libavfilter to use AVFrame instead of AVFilterBufferRef. Add
av_buffersrc_add_frame(), deprecate av_buffersrc_buffer().
Add av_buffersink_get_frame() and av_buffersink_get_samples(),
deprecate av_buffersink_read() and av_buffersink_read_samples().
Deprecate AVFilterBufferRef and all functions for working with it.
-2013-03-17 - 12c5c1d - lavu 52.8.0 - avstring.h
+2013-03-17 - 6c17ff8 / 12c5c1d - lavu 52.19.100 / 52.8.0 - avstring.h
Add av_isdigit, av_isgraph, av_isspace, av_isxdigit.
-2013-02-23 - 9f12235 - lavfi 3.4.0 - avfiltergraph.h
+2013-02-23 - 71cf094 / 9f12235 - lavfi 3.40.100 / 3.4.0 - avfiltergraph.h
Add resample_lavr_opts to AVFilterGraph for setting libavresample options
for auto-inserted resample filters.
-2013-01-25 - 38c1466 - lavu 52.7.0 - dict.h
+2013-01-25 - e7e14bc / 38c1466 - lavu 52.17.100 / 52.7.0 - dict.h
Add av_dict_parse_string() to set multiple key/value pairs at once from a
string.
-2013-01-25 - b85a5e8 - lavu 52.6.0 - avstring.h
+2013-01-25 - 25be630 / b85a5e8 - lavu 52.16.100 / 52.6.0 - avstring.h
Add av_strnstr()
-2013-01-15 - 8ee288d - lavu 52.5.0 - hmac.h
+2013-01-15 - e7e0186 / 8ee288d - lavu 52.15.100 / 52.5.0 - hmac.h
Add AVHMAC.
-2013-01-13 - 44e065d - lavc 54.36.0 - vdpau.h
+2013-01-13 - 8ee7b38 / 44e065d - lavc 54.87.100 / 54.36.0 - vdpau.h
Add AVVDPAUContext struct for VDPAU hardware-accelerated decoding.
-2013-01-12 - 169fb94 - lavu 52.4.0 - pixdesc.h
+2013-01-12 - dae382b / 169fb94 - lavu 52.14.100 / 52.4.0 - pixdesc.h
Add AV_PIX_FMT_VDPAU flag.
-2013-01-07 - 074a00d - lavr 1.1.0
+2013-01-07 - 249fca3 / 074a00d - lavr 1.1.0
Add avresample_set_channel_mapping() for input channel reordering,
duplication, and silencing.
-------------------------------8<-------------------------------------
- 9 branch was cut here
------------------------------>8--------------------------------------
-
-2012-12-29 - d8fd06c - lavu 52.3.0 - avstring.h
+2012-12-29 - 2ce43b3 / d8fd06c - lavu 52.13.100 / 52.3.0 - avstring.h
Add av_basename() and av_dirname().
-2012-11-11 - 5980f5d - lavu 52.2.0 - audioconvert.h
+2012-11-11 - 03b0787 / 5980f5d - lavu 52.6.100 / 52.2.0 - audioconvert.h
Rename audioconvert.h to channel_layout.h. audioconvert.h is now deprecated.
-2012-11-05 - dfde8a3 - lavu 52.1.0 - intmath.h
+2012-11-05 - 7d26be6 / dfde8a3 - lavu 52.5.100 / 52.1.0 - intmath.h
Add av_ctz() for trailing zero bit count
-2012-10-21 - a893655 - lavu 51.45.0 - error.h
+2012-10-21 - e3a91c5 / a893655 - lavu 51.77.100 / 51.45.0 - error.h
Add AVERROR_EXPERIMENTAL
-2012-10-12 - d2fcb35 - lavu 51.44.0 - pixdesc.h
+2012-10-12 - a33ed6b / d2fcb35 - lavu 51.76.100 / 51.44.0 - pixdesc.h
Add functions for accessing pixel format descriptors.
Accessing the av_pix_fmt_descriptors array directly is now
deprecated.
-2012-10-11 - 9a92aea - lavu 51.43.0 - aes.h, md5.h, sha.h, tree.h
+2012-10-11 - f391e40 / 9a92aea - lavu 51.75.100 / 51.43.0 - aes.h, md5.h, sha.h, tree.h
Add functions for allocating the opaque contexts for the algorithms,
- deprecate the context size variables.
-2012-10-10 - b522000 - lavf 54.18.0 - avio.h
+2012-10-10 - de31814 / b522000 - lavf 54.32.100 / 54.18.0 - avio.h
Add avio_closep to complement avio_close.
-2012-10-08 - 78071a1 - lavu 51.42.0 - pixfmt.h
+2012-10-08 - ae77266 / 78071a1 - lavu 51.74.100 / 51.42.0 - pixfmt.h
Rename PixelFormat to AVPixelFormat and all PIX_FMT_* to AV_PIX_FMT_*.
To provide backwards compatibility, PixelFormat is now #defined as
AVPixelFormat.
@@ -514,23 +1001,26 @@ lavd 54.0.0, lavfi 3.5.0
'PixelFormat' identifier. Such code should either #undef PixelFormat
or stop using the PixelFormat name.
-2012-10-05 - e7ba5b1 - lavr 1.0.0 - avresample.h
+2012-10-05 - 55c49af / e7ba5b1 - lavr 1.0.0 - avresample.h
Data planes parameters to avresample_convert() and
avresample_read() are now uint8_t** instead of void**.
Libavresample is now stable.
-2012-09-24 - a42aada - lavc 54.28.0 - avcodec.h
+2012-09-26 - 3ba0dab7 / 1384df64 - lavf 54.29.101 / 56.06.3 - avformat.h
+ Add AVFormatContext.avoid_negative_ts.
+
+2012-09-24 - 46a3595 / a42aada - lavc 54.59.100 / 54.28.0 - avcodec.h
Add avcodec_free_frame(). This function must now
be used for freeing an AVFrame.
-2012-09-12 - 8919fee - lavu 51.41.0 - audioconvert.h
+2012-09-12 - e3e09f2 / 8919fee - lavu 51.73.100 / 51.41.0 - audioconvert.h
Added AV_CH_LOW_FREQUENCY_2 channel mask value.
-2012-09-04 - 686a329 - lavu 51.40.0 - opt.h
+2012-09-04 - b21b5b0 / 686a329 - lavu 51.71.100 / 51.40.0 - opt.h
Reordered the fields in default_val in AVOption, changed which
default_val field is used for which AVOptionType.
-2012-08-30 - a231832 - lavc 54.26.1 - avcodec.h
+2012-08-30 - 98298eb / a231832 - lavc 54.54.101 / 54.26.1 - avcodec.h
Add codec descriptor properties AV_CODEC_PROP_LOSSY and
AV_CODEC_PROP_LOSSLESS.
@@ -538,101 +1028,90 @@ lavd 54.0.0, lavfi 3.5.0
Add codec descriptors for accessing codec properties without having
to refer to a specific decoder or encoder.
- c223d79 - Add an AVCodecDescriptor struct and functions
+ f5f3684 / c223d79 - Add an AVCodecDescriptor struct and functions
avcodec_descriptor_get() and avcodec_descriptor_next().
- 51efed1 - Add AVCodecDescriptor.props and AV_CODEC_PROP_INTRA_ONLY.
- 91e59fe - Add avcodec_descriptor_get_by_name().
-
+ f5f3684 / 51efed1 - Add AVCodecDescriptor.props and AV_CODEC_PROP_INTRA_ONLY.
+ 6c180b3 / 91e59fe - Add avcodec_descriptor_get_by_name().
-2012-08-08 - 1d9c2dc - lavu 51.39 - avutil.h
- Don't implicitly include libavutil/common.h in avutil.h
-
-2012-08-08 - 987170c - lavu 51.38 - dict.h
+2012-08-08 - f5f3684 / 987170c - lavu 51.68.100 / 51.38.0 - dict.h
Add av_dict_count().
-2012-08-07 - 104e10f - lavc 54.25 - avcodec.h
+2012-08-07 - 7a72695 / 104e10f - lavc 54.51.100 / 54.25.0 - avcodec.h
Rename CodecID to AVCodecID and all CODEC_ID_* to AV_CODEC_ID_*.
To provide backwards compatibility, CodecID is now #defined as AVCodecID.
Note that this can break user code that includes avcodec.h and uses the
'CodecID' identifier. Such code should either #undef CodecID or stop using the
CodecID name.
-2012-08-03 - 239fdf1 - lavu 51.37.1 - cpu.h
+2012-08-03 - e776ee8 / 239fdf1 - lavu 51.66.101 / 51.37.1 - cpu.h
lsws 2.1.1 - swscale.h
Rename AV_CPU_FLAG_MMX2 ---> AV_CPU_FLAG_MMXEXT.
Rename SWS_CPU_CAPS_MMX2 ---> SWS_CPU_CAPS_MMXEXT.
-2012-07-29 - 681ed00 - lavf 54.13.0 - avformat.h
+2012-07-29 - 7c26761 / 681ed00 - lavf 54.22.100 / 54.13.0 - avformat.h
Add AVFMT_FLAG_NOBUFFER for low latency use cases.
-2012-07-20 - b70d89a - lavfi 3.0.0 - avfilter.h
- Add avfilter_unref_bufferp().
-
-2012-07-10 - 5fade8a - lavu 51.37.0
+2012-07-10 - fbe0245 / f3e5e6f - lavu 51.65.100 / 51.37.0
Add av_malloc_array() and av_mallocz_array()
-2012-06-22 - d3d3a32 - lavu 51.34.0
+2012-06-22 - e847f41 / d3d3a32 - lavu 51.61.100 / 51.34.0
Add av_usleep()
-2012-06-20 - ae0a301 - lavu 51.33.0
+2012-06-20 - 4da42eb / ae0a301 - lavu 51.60.100 / 51.33.0
Move av_gettime() to libavutil, add libavutil/time.h
-2012-06-09 - 3971be0 - lavr 0.0.3
+2012-06-09 - 82edf67 / 3971be0 - lavr 0.0.3
Add a parameter to avresample_build_matrix() for Dolby/DPLII downmixing.
-2012-06-12 - 9baeff9 - lavfi 2.23.0 - avfilter.h
+2012-06-12 - c7b9eab / 9baeff9 - lavfi 2.79.100 / 2.23.0 - avfilter.h
Add AVFilterContext.nb_inputs/outputs. Deprecate
AVFilterContext.input/output_count.
-2012-06-12 - 84b9fbe - lavfi 2.22.0 - avfilter.h
+2012-06-12 - c7b9eab / 84b9fbe - lavfi 2.79.100 / 2.22.0 - avfilter.h
Add avfilter_pad_get_type() and avfilter_pad_get_name(). Those
should now be used instead of accessing AVFilterPad members
directly.
-2012-06-12 - b0f0dfc - lavu 51.32.0 - audioconvert.h
+2012-06-12 - 3630a07 / b0f0dfc - lavu 51.57.100 / 51.32.0 - audioconvert.h
Add av_get_channel_layout_channel_index(), av_get_channel_name()
and av_channel_layout_extract_channel().
-2012-05-25 - 154486f - lavu 51.31.0 - opt.h
+2012-05-25 - 53ce990 / 154486f - lavu 51.55.100 / 51.31.0 - opt.h
Add av_opt_set_bin()
-2012-05-26 - e9cef89 - lavf 54.3.0
- Add AVFMT_TS_NONSTRICT format flag to indicate that a muxer supports
- non-increasing monotone timestamps.
-
-2012-05-15 - lavfi 2.17.0
+2012-05-15 - lavfi 2.74.100 / 2.17.0
Add support for audio filters
- ac71230/a2cd9be - add video/audio buffer sink in a new installed
+ 61930bd / ac71230, 1cbf7fb / a2cd9be - add video/audio buffer sink in a new installed
header buffersink.h
- 720c6b7 - add av_buffersrc_write_frame(), deprecate
+ 1cbf7fb / 720c6b7 - add av_buffersrc_write_frame(), deprecate
av_vsrc_buffer_add_frame()
- ab16504 - add avfilter_copy_buf_props()
- 9453c9e - add extended_data to AVFilterBuffer
- 1b8c927 - add avfilter_get_audio_buffer_ref_from_arrays()
+ 61930bd / ab16504 - add avfilter_copy_buf_props()
+ 61930bd / 9453c9e - add extended_data to AVFilterBuffer
+ 61930bd / 1b8c927 - add avfilter_get_audio_buffer_ref_from_arrays()
-2012-05-09 - lavu 51.30.0 - samplefmt.h
- 142e740 - add av_samples_copy()
- 6d7f617 - add av_samples_set_silence()
+2012-05-09 - lavu 51.53.100 / 51.30.0 - samplefmt.h
+ 61930bd / 142e740 - add av_samples_copy()
+ 61930bd / 6d7f617 - add av_samples_set_silence()
-2012-05-09 - a5117a2 - lavc 54.13.1
+2012-05-09 - 61930bd / a5117a2 - lavc 54.21.101 / 54.13.1
For audio formats with fixed frame size, the last frame
no longer needs to be padded with silence, libavcodec
will handle this internally (effectively all encoders
behave as if they had CODEC_CAP_SMALL_LAST_FRAME set).
-2012-05-07 - 828bd08 - lavc 54.13.0 - avcodec.h
+2012-05-07 - 653d117 / 828bd08 - lavc 54.20.100 / 54.13.0 - avcodec.h
Add sample_rate and channel_layout fields to AVFrame.
-2012-05-01 - 4010d72 - lavr 0.0.1
+2012-05-01 - 2330eb1 / 4010d72 - lavr 0.0.1
Change AV_MIX_COEFF_TYPE_Q6 to AV_MIX_COEFF_TYPE_Q8.
-2012-04-25 - 3527a73 - lavu 51.29.0 - cpu.h
+2012-04-25 - e890b68 / 3527a73 - lavu 51.48.100 / 51.29.0 - cpu.h
Add av_parse_cpu_flags()
-2012-04-24 - c8af852 - lavr 0.0.0
+2012-04-24 - 3ead79e / c8af852 - lavr 0.0.0
Add libavresample audio conversion library
-2012-04-20 - 0c0d1bc - lavu 51.28.0 - audio_fifo.h
+2012-04-20 - 3194ab7 / 0c0d1bc - lavu 51.47.100 / 51.28.0 - audio_fifo.h
Add audio FIFO functions:
av_audio_fifo_free()
av_audio_fifo_alloc()
@@ -644,144 +1123,165 @@ lavd 54.0.0, lavfi 3.5.0
av_audio_fifo_size()
av_audio_fifo_space()
-2012-04-14 - lavfi 2.16.0 - avfiltergraph.h
- d7bcc71 Add avfilter_graph_parse2().
- 91d3cbe Add avfilter_inout_alloc() and avfilter_inout_free().
+2012-04-14 - lavfi 2.70.100 / 2.16.0 - avfiltergraph.h
+ 7432bcf / d7bcc71 Add avfilter_graph_parse2().
-2012-04-08 - 4d693b0 - lavu 51.27.0 - samplefmt.h
+2012-04-08 - 6bfb304 / 4d693b0 - lavu 51.46.100 / 51.27.0 - samplefmt.h
Add av_get_packed_sample_fmt() and av_get_planar_sample_fmt()
-2012-04-05 - 5cc51a5 - lavu 51.26.0 - audioconvert.h
- Add av_get_default_channel_layout()
+2012-03-21 - b75c67d - lavu 51.43.100
+ Add bprint.h for bprint API.
+
+2012-02-21 - 9cbf17e - lavc 54.4.100
+ Add av_get_pcm_codec() function.
+
+2012-02-16 - 560b224 - libswr 0.7.100
+ Add swr_set_matrix() function.
-2012-03-20 - 3c90cc2 - lavfo 54.2.0
+2012-02-09 - c28e7af - lavu 51.39.100
+ Add a new installed header libavutil/timestamp.h with timestamp
+ utilities.
+
+2012-02-06 - 70ffda3 - lavu 51.38.100
+ Add av_parse_ratio() function to parseutils.h.
+
+2012-02-06 - 70ffda3 - lavu 51.38.100
+ Add AV_LOG_MAX_OFFSET macro to log.h.
+
+2012-02-02 - 0eaa123 - lavu 51.37.100
+ Add public timecode helpers.
+
+2012-01-24 - 0c3577b - lavfi 2.60.100
+ Add avfilter_graph_dump.
+
+2012-03-20 - 0ebd836 / 3c90cc2 - lavfo 54.2.0
Deprecate av_read_packet(), use av_read_frame() with
AVFMT_FLAG_NOPARSE | AVFMT_FLAG_NOFILLIN in AVFormatContext.flags
-2012-03-06 - 4d851f8 - lavu 51.25.0 - cpu.h
- Add av_set_cpu_flags_mask().
-
-2012-03-05 - lavc 54.8.0
- 6699d07 Add av_get_exact_bits_per_sample()
- 9524cf7 Add av_get_audio_frame_duration()
+2012-03-05 - lavc 54.10.100 / 54.8.0
+ f095391 / 6699d07 Add av_get_exact_bits_per_sample()
+ f095391 / 9524cf7 Add av_get_audio_frame_duration()
-2012-03-04 - 44fe77b - lavc 54.7.0 - avcodec.h
+2012-03-04 - 2af8f2c / 44fe77b - lavc 54.8.100 / 54.7.0 - avcodec.h
Add av_codec_is_encoder/decoder().
-2012-03-01 - 442c132 - lavc 54.3.0 - avcodec.h
+2012-03-01 - 1eb7f39 / 442c132 - lavc 54.5.100 / 54.3.0 - avcodec.h
Add av_packet_shrink_side_data.
-2012-02-29 - dd2a4bc - lavf 54.2.0 - avformat.h
+2012-02-29 - 79ae084 / dd2a4bc - lavf 54.2.100 / 54.2.0 - avformat.h
Add AVStream.attached_pic and AV_DISPOSITION_ATTACHED_PIC,
used for dealing with attached pictures/cover art.
-2012-02-25 - c9bca80 - lavu 51.24.0 - error.h
+2012-02-25 - 305e4b3 / c9bca80 - lavu 51.41.100 / 51.24.0 - error.h
Add AVERROR_UNKNOWN
NOTE: this was backported to 0.8
-2012-02-20 - e9cda85 - lavc 54.2.0
+2012-02-20 - eadd426 / e9cda85 - lavc 54.2.100 / 54.2.0
Add duration field to AVCodecParserContext
-2012-02-20 - 0b42a93 - lavu 51.23.1 - mathematics.h
+2012-02-20 - eadd426 / 0b42a93 - lavu 51.40.100 / 51.23.1 - mathematics.h
Add av_rescale_q_rnd()
-2012-02-08 - 38d5533 - lavu 51.22.1 - pixdesc.h
+2012-02-08 - f2b20b7 / 38d5533 - lavu 51.38.101 / 51.22.1 - pixdesc.h
Add PIX_FMT_PSEUDOPAL flag.
-2012-02-08 - 52f82a1 - lavc 54.01.0
+2012-02-08 - f2b20b7 / 52f82a1 - lavc 54.2.100 / 54.1.0
Add avcodec_encode_video2() and deprecate avcodec_encode_video().
-2012-02-01 - 316fc74 - lavc 54.01.0
+2012-02-01 - 4c677df / 316fc74 - lavc 54.1.0
Add av_fast_padded_malloc() as alternative for av_realloc() when aligned
memory is required. The buffer will always have FF_INPUT_BUFFER_PADDING_SIZE
zero-padded bytes at the end.
-2012-01-31 - dd6d3b0 - lavf 54.01.0
+2012-01-31 - a369a6b / dd6d3b0 - lavf 54.1.0
Add avformat_get_riff_video_tags() and avformat_get_riff_audio_tags().
NOTE: this was backported to 0.8
-2012-01-31 - af08d9a - lavc 54.01.0
+2012-01-31 - a369a6b / af08d9a - lavc 54.1.0
Add avcodec_is_open() function.
NOTE: this was backported to 0.8
-2012-01-30 - 8b93312 - lavu 51.22.0 - intfloat.h
+2012-01-30 - 151ecc2 / 8b93312 - lavu 51.36.100 / 51.22.0 - intfloat.h
Add a new installed header libavutil/intfloat.h with int/float punning
functions.
NOTE: this was backported to 0.8
-2012-01-25 - lavf 53.22.0
- f1caf01 Allow doing av_write_frame(ctx, NULL) for flushing possible
+2012-01-25 - lavf 53.31.100 / 53.22.0
+ 3c5fe5b / f1caf01 Allow doing av_write_frame(ctx, NULL) for flushing possible
buffered data within a muxer. Added AVFMT_ALLOW_FLUSH for
muxers supporting it (av_write_frame makes sure it is called
only for muxers with this flag).
-------------------------------8<-------------------------------------
- 0.8 branch was cut here
------------------------------>8--------------------------------------
-
-2012-01-15 - lavc 53.34.0
+2012-01-15 - lavc 53.56.105 / 53.34.0
New audio encoding API:
- b2c75b6 Add CODEC_CAP_VARIABLE_FRAME_SIZE capability for use by audio
+ 67f5650 / b2c75b6 Add CODEC_CAP_VARIABLE_FRAME_SIZE capability for use by audio
encoders.
- 5ee5fa0 Add avcodec_fill_audio_frame() as a convenience function.
- b2c75b6 Add avcodec_encode_audio2() and deprecate avcodec_encode_audio().
+ 67f5650 / 5ee5fa0 Add avcodec_fill_audio_frame() as a convenience function.
+ 67f5650 / b2c75b6 Add avcodec_encode_audio2() and deprecate avcodec_encode_audio().
Add AVCodec.encode2().
-2012-01-12 - 3167dc9 - lavfi 2.15.0
+2012-01-12 - b18e17e / 3167dc9 - lavfi 2.59.100 / 2.15.0
Add a new installed header -- libavfilter/version.h -- with version macros.
-2011-01-03 - b73ec05 - lavu 51.21.0
+
+-------- 8< --------- FFmpeg 0.9 was cut here -------- 8< ---------
+
+2011-12-08 - a502939 - lavfi 2.52.0
+ Add av_buffersink_poll_frame() to buffersink.h.
+
+2011-12-08 - 26c6fec - lavu 51.31.0
+ Add av_log_format_line.
+
+2011-12-03 - 976b095 - lavu 51.30.0
+ Add AVERROR_BUG.
+
+2011-11-24 - 573ffbb - lavu 51.28.1
+ Add av_get_alt_sample_fmt() to samplefmt.h.
+
+2011-11-03 - 96949da - lavu 51.23.0
+ Add av_strcasecmp() and av_strncasecmp() to avstring.h.
+
+2011-10-20 - b35e9e1 - lavu 51.22.0
+ Add av_strtok() to avstring.h.
+
+2012-01-03 - ad1c8dd / b73ec05 - lavu 51.34.100 / 51.21.0
Add av_popcount64
-2011-12-25 - lavfi 2.14.0
- e1d9dbf Add a new installed header - buffersrc.h
- It contains a new function av_buffersrc_buffer() that allows passing
- frames to the 'buffer' filter, but unlike av_vsrc_buffer_add_frame()
- it allows for direct rendering.
- 1c9e340 Add avfilter_copy_frame_props() for copying properties from
- AVFrame to AVFilterBufferRef.
-
-2011-12-25 - lavc 53.31.0
- Add the following new fields to AVFrame:
- b58dbb5 sample_aspect_ratio
- 3a2ddf7 width, height
- 8a4a5f6 format
-
-2011-12-18 - 8400b12 - lavc 53.28.1
+2011-12-18 - 7c29313 / 8400b12 - lavc 53.46.1 / 53.28.1
Deprecate AVFrame.age. The field is unused.
-2011-12-12 - 5266045 - lavf 53.17.0
+2011-12-12 - 8bc7fe4 / 5266045 - lavf 53.25.0 / 53.17.0
Add avformat_close_input().
Deprecate av_close_input_file() and av_close_input_stream().
-2011-12-09 - b2890f5 - lavu 51.20.0 - audioconvert.h
+2011-12-09 - c59b80c / b2890f5 - lavu 51.32.0 / 51.20.0 - audioconvert.h
Expand the channel layout list.
-2011-12-02 - 0eea212 - lavc 53.25.0
+2011-12-02 - e4de716 / 0eea212 - lavc 53.40.0 / 53.25.0
Add nb_samples and extended_data fields to AVFrame.
Deprecate AVCODEC_MAX_AUDIO_FRAME_SIZE.
Deprecate avcodec_decode_audio3() in favor of avcodec_decode_audio4().
avcodec_decode_audio4() writes output samples to an AVFrame, which allows
audio decoders to use get_buffer().
-2011-12-04 - 560f773 - lavc 53.24.0
+2011-12-04 - e4de716 / 560f773 - lavc 53.40.0 / 53.24.0
Change AVFrame.data[4]/base[4]/linesize[4]/error[4] to [8] at next major bump.
Change AVPicture.data[4]/linesize[4] to [8] at next major bump.
Change AVCodecContext.error[4] to [8] at next major bump.
Add AV_NUM_DATA_POINTERS to simplify the bump transition.
-2011-11-24 - lavu 51.19.0
- bd97b2e - add planar RGB pixel formats
- 6b0768e - add PIX_FMT_PLANAR and PIX_FMT_RGB pixel descriptions
+2011-11-24 - lavu 51.29.0 / 51.19.0
+ 92afb43 / bd97b2e - add planar RGB pixel formats
+ 92afb43 / 6b0768e - add PIX_FMT_PLANAR and PIX_FMT_RGB pixel descriptions
-2011-11-23 - bbb46f3 - lavu 51.18.0
+2011-11-23 - 8e576d5 / bbb46f3 - lavu 51.27.0 / 51.18.0
Add av_samples_get_buffer_size(), av_samples_fill_arrays(), and
av_samples_alloc(), to samplefmt.h.
-2011-11-23 - 8889cc4 - lavu 51.17.0
+2011-11-23 - 8e576d5 / 8889cc4 - lavu 51.27.0 / 51.17.0
Add planar sample formats and av_sample_fmt_is_planar() to samplefmt.h.
-2011-11-19 - f3a29b7 - lavc 53.21.0
+2011-11-19 - dbb38bc / f3a29b7 - lavc 53.36.0 / 53.21.0
Move some AVCodecContext fields to a new private struct, AVCodecInternal,
which is accessed from a new field, AVCodecContext.internal.
- fields moved:
@@ -789,220 +1289,371 @@ lavd 54.0.0, lavfi 3.5.0
AVCodecContext.internal_buffer_count --> AVCodecInternal.buffer_count
AVCodecContext.is_copy --> AVCodecInternal.is_copy
-2011-11-16 - 6270671 - lavu 51.16.0
+2011-11-16 - 8709ba9 / 6270671 - lavu 51.26.0 / 51.16.0
Add av_timegm()
-2011-11-13 - lavf 53.15.0
+2011-11-13 - lavf 53.21.0 / 53.15.0
New interrupt callback API, allowing per-AVFormatContext/AVIOContext
interrupt callbacks.
- 6aa0b98 Add AVIOInterruptCB struct and the interrupt_callback field to
+ 5f268ca / 6aa0b98 Add AVIOInterruptCB struct and the interrupt_callback field to
AVFormatContext.
- 1dee0ac Add avio_open2() with additional parameters. Those are
+ 5f268ca / 1dee0ac Add avio_open2() with additional parameters. Those are
an interrupt callback and an options AVDictionary.
This will allow passing AVOptions to protocols after lavf
54.0.
-2011-11-06 - ba04ecf - lavu 51.14.0
+2011-11-06 - 13b7781 / ba04ecf - lavu 51.24.0 / 51.14.0
Add av_strcasecmp() and av_strncasecmp() to avstring.h.
-2011-11-06 - 07b172f - lavu 51.13.0
+2011-11-06 - 13b7781 / 07b172f - lavu 51.24.0 / 51.13.0
Add av_toupper()/av_tolower()
-2011-11-05 - b6d08f4 - lavf 53.13.0
+2011-11-05 - d8cab5c / b6d08f4 - lavf 53.19.0 / 53.13.0
Add avformat_network_init()/avformat_network_deinit()
-2011-10-27 - 512557b - lavc 53.15.0
+2011-10-27 - 6faf0a2 / 512557b - lavc 53.24.0 / 53.15.0
Remove avcodec_parse_frame.
Deprecate AVCodecContext.parse_only and CODEC_CAP_PARSE_ONLY.
-2011-10-19 - 569129a - lavf 53.10.0
+2011-10-19 - d049257 / 569129a - lavf 53.17.0 / 53.10.0
Add avformat_new_stream(). Deprecate av_new_stream().
-2011-10-13 - b631fba - lavf 53.9.0
+2011-10-13 - 91eb1b1 / b631fba - lavf 53.16.0 / 53.9.0
Add AVFMT_NO_BYTE_SEEK AVInputFormat flag.
-2011-10-12 - lavu 51.12.0
+2011-10-12 - lavu 51.21.0 / 51.12.0
AVOptions API rewrite.
- - 145f741 FF_OPT_TYPE* renamed to AV_OPT_TYPE_*
+ - f884ef0 / 145f741 FF_OPT_TYPE* renamed to AV_OPT_TYPE_*
- new setting/getting functions with slightly different semantics:
- dac66da av_set_string3 -> av_opt_set
+ f884ef0 / dac66da av_set_string3 -> av_opt_set
av_set_double -> av_opt_set_double
av_set_q -> av_opt_set_q
av_set_int -> av_opt_set_int
- 41d9d51 av_get_string -> av_opt_get
+ f884ef0 / 41d9d51 av_get_string -> av_opt_get
av_get_double -> av_opt_get_double
av_get_q -> av_opt_get_q
av_get_int -> av_opt_get_int
- - 8c5dcaa trivial rename av_next_option -> av_opt_next
- - 641c7af new functions - av_opt_child_next, av_opt_child_class_next
+ - f884ef0 / 8c5dcaa trivial rename av_next_option -> av_opt_next
+ - f884ef0 / 641c7af new functions - av_opt_child_next, av_opt_child_class_next
and av_opt_find2()
-2011-09-03 - fb4ca26 - lavc 53.10.0
- lavf 53.6.0
+2011-09-22 - a70e787 - lavu 51.17.0
+ Add av_x_if_null().
+
+2011-09-18 - 645cebb - lavc 53.16.0
+ Add showall flag2
+
+2011-09-16 - ea8de10 - lavfi 2.42.0
+ Add avfilter_all_channel_layouts.
+
+2011-09-16 - 9899037 - lavfi 2.41.0
+ Rename avfilter_all_* function names to avfilter_make_all_*.
+
+ In particular, apply the renames:
+ avfilter_all_formats -> avfilter_make_all_formats
+ avfilter_all_channel_layouts -> avfilter_make_all_channel_layouts
+ avfilter_all_packing_formats -> avfilter_make_all_packing_formats
+
+2011-09-12 - 4381bdd - lavfi 2.40.0
+ Change AVFilterBufferRefAudioProps.sample_rate type from uint32_t to int.
+
+2011-09-12 - 2c03174 - lavfi 2.40.0
+ Simplify signature for avfilter_get_audio_buffer(), make it
+ consistent with avfilter_get_video_buffer().
+
+2011-09-06 - 4f7dfe1 - lavfi 2.39.0
+ Rename libavfilter/vsink_buffer.h to libavfilter/buffersink.h.
+
+2011-09-06 - c4415f6 - lavfi 2.38.0
+ Unify video and audio sink API.
+
+ In particular, add av_buffersink_get_buffer_ref(), deprecate
+ av_vsink_buffer_get_video_buffer_ref() and change the value for the
+ opaque field passed to the abuffersink init function.
+
+2011-09-04 - 61e2e29 - lavu 51.16.0
+ Add av_asprintf().
+
+2011-08-22 - dacd827 - lavf 53.10.0
+ Add av_find_program_from_stream().
+
+2011-08-20 - 69e2c1a - lavu 51.13.0
+ Add av_get_media_type_string().
+
+2011-09-03 - 1889c67 / fb4ca26 - lavc 53.13.0
+ lavf 53.11.0
lsws 2.1.0
Add {avcodec,avformat,sws}_get_class().
-2011-09-03 - c11fb82 - lavu 51.10.0
+2011-08-03 - 1889c67 / c11fb82 - lavu 51.15.0
Add AV_OPT_SEARCH_FAKE_OBJ flag for av_opt_find() function.
-2011-08-26 - lavu 51.9.0
- - f2011ed Add av_fifo_peek2(), deprecate av_fifo_peek().
- - add41de..abc78a5 Do not include intfloat_readwrite.h,
+2011-08-14 - 323b930 - lavu 51.12.0
+ Add av_fifo_peek2(), deprecate av_fifo_peek().
+
+2011-08-26 - lavu 51.14.0 / 51.9.0
+ - 976a8b2 / add41de..976a8b2 / abc78a5 Do not include intfloat_readwrite.h,
mathematics.h, rational.h, pixfmt.h, or log.h from avutil.h.
-2011-08-16 - 48f9e45 - lavf 53.4.0
+2011-08-16 - 27fbe31 / 48f9e45 - lavf 53.11.0 / 53.8.0
Add avformat_query_codec().
-2011-08-16 - bca06e7 - lavc 53.8.0
+2011-08-16 - 27fbe31 / bca06e7 - lavc 53.11.0
Add avcodec_get_type().
-2011-08-06 - 2f63440 - lavf 53.4.0
+2011-08-06 - 0cb233c / 2f63440 - lavf 53.7.0
Add error_recognition to AVFormatContext.
-2011-08-02 - 9d39cbf - lavc 53.7.1
+2011-08-02 - 1d186e9 / 9d39cbf - lavc 53.9.1
Add AV_PKT_FLAG_CORRUPT AVPacket flag.
-2011-07-10 - a67c061 - lavf 53.3.0
+2011-07-16 - b57df29 - lavfi 2.27.0
+ Add audio packing negotiation fields and helper functions.
+
+ In particular, add AVFilterPacking enum, planar, in_packings and
+ out_packings fields to AVFilterLink, and the functions:
+ avfilter_set_common_packing_formats()
+ avfilter_all_packing_formats()
+
+2011-07-10 - 3602ad7 / a67c061 - lavf 53.6.0
Add avformat_find_stream_info(), deprecate av_find_stream_info().
NOTE: this was backported to 0.7
-2011-07-10 - 0b950fe - lavc 53.6.0
+2011-07-10 - 3602ad7 / 0b950fe - lavc 53.8.0
Add avcodec_open2(), deprecate avcodec_open().
NOTE: this was backported to 0.7
Add avcodec_alloc_context3. Deprecate avcodec_alloc_context() and
avcodec_alloc_context2().
-2011-06-23 - 67e9ae1 - lavu 51.8.0 - attributes.h
- Add av_printf_format().
+2011-07-01 - b442ca6 - lavf 53.5.0 - avformat.h
+ Add function av_get_output_timestamp().
+
+2011-06-28 - 5129336 - lavu 51.11.0 - avutil.h
+ Define the AV_PICTURE_TYPE_NONE value in AVPictureType enum.
+
+
+-------- 8< --------- FFmpeg 0.7 was cut here -------- 8< ---------
+
+
+
+-------- 8< --------- FFmpeg 0.8 was cut here -------- 8< ---------
+
+2011-06-19 - fd2c0a5 - lavfi 2.23.0 - avfilter.h
+ Add layout negotiation fields and helper functions.
+
+ In particular, add in_chlayouts and out_chlayouts to AVFilterLink,
+ and the functions:
+ avfilter_set_common_sample_formats()
+ avfilter_set_common_channel_layouts()
+ avfilter_all_channel_layouts()
+
+2011-06-19 - 527ca39 - lavfi 2.22.0 - AVFilterFormats
+ Change type of AVFilterFormats.formats from int * to int64_t *,
+ and update formats handling API accordingly.
+
+ avfilter_make_format_list() still takes a int32_t array and converts
+ it to int64_t. A new function, avfilter_make_format64_list(), that
+ takes int64_t arrays has been added.
+
+2011-06-19 - 44f669e - lavfi 2.21.0 - vsink_buffer.h
+ Add video sink buffer and vsink_buffer.h public header.
+
+2011-06-12 - 9fdf772 - lavfi 2.18.0 - avcodec.h
+ Add avfilter_get_video_buffer_ref_from_frame() function in
+ libavfilter/avcodec.h.
+
+2011-06-12 - c535494 - lavfi 2.17.0 - avfiltergraph.h
+ Add avfilter_inout_alloc() and avfilter_inout_free() functions.
-------------------------------8<-------------------------------------
- 0.7 branch was cut here
------------------------------>8--------------------------------------
+2011-06-12 - 6119b23 - lavfi 2.16.0 - avfilter_graph_parse()
+ Change avfilter_graph_parse() signature.
-2011-06-16 - 05e84c9, 25de595 - lavf 53.2.0 - avformat.h
+2011-06-23 - 686959e / 67e9ae1 - lavu 51.10.0 / 51.8.0 - attributes.h
+ Add av_printf_format().
+
+2011-06-16 - 2905e3f / 05e84c9, 2905e3f / 25de595 - lavf 53.4.0 / 53.2.0 - avformat.h
Add avformat_open_input and avformat_write_header().
Deprecate av_open_input_stream, av_open_input_file,
AVFormatParameters and av_write_header.
-2011-06-16 - 7e83e1c, dc59ec5 - lavu 51.7.0 - opt.h
+2011-06-16 - 2905e3f / 7e83e1c, 2905e3f / dc59ec5 - lavu 51.9.0 / 51.7.0 - opt.h
Add av_opt_set_dict() and av_opt_find().
Deprecate av_find_opt().
Add AV_DICT_APPEND flag.
-2011-06-10 - cb7c11c - lavu 51.6.0 - opt.h
+2011-06-10 - 45fb647 / cb7c11c - lavu 51.6.0 - opt.h
Add av_opt_flag_is_set().
-2011-06-08 - d9f80ea - lavu 51.5.0 - AVMetadata
+2011-06-10 - c381960 - lavfi 2.15.0 - avfilter_get_audio_buffer_ref_from_arrays
+ Add avfilter_get_audio_buffer_ref_from_arrays() to avfilter.h.
+
+2011-06-09 - f9ecb84 / d9f80ea - lavu 51.8.0 - AVMetadata
Move AVMetadata from lavf to lavu and rename it to
AVDictionary -- new installed header dict.h.
All av_metadata_* functions renamed to av_dict_*.
-2011-06-07 - a6703fa - lavu 51.4.0 - av_get_bytes_per_sample()
+2011-06-07 - d552f61 / a6703fa - lavu 51.8.0 - av_get_bytes_per_sample()
Add av_get_bytes_per_sample() in libavutil/samplefmt.h.
Deprecate av_get_bits_per_sample_fmt().
-2011-06-05 - b39b062 - lavu 51.3.0 - opt.h
+2011-06-05 - f956924 / b39b062 - lavu 51.8.0 - opt.h
Add av_opt_free convenience function.
-2011-05-28 - 0420bd7 - lavu 51.2.0 - pixdesc.h
+2011-06-06 - 95a0242 - lavfi 2.14.0 - AVFilterBufferRefAudioProps
+ Remove AVFilterBufferRefAudioProps.size, and use nb_samples in
+ avfilter_get_audio_buffer() and avfilter_default_get_audio_buffer() in
+ place of size.
+
+2011-06-06 - 0bc2cca - lavu 51.6.0 - av_samples_alloc()
+ Switch nb_channels and nb_samples parameters order in
+ av_samples_alloc().
+
+2011-06-06 - e1c7414 - lavu 51.5.0 - av_samples_*
+ Change the data layout created by av_samples_fill_arrays() and
+ av_samples_alloc().
+
+2011-06-06 - 27bcf55 - lavfi 2.13.0 - vsrc_buffer.h
+ Make av_vsrc_buffer_add_video_buffer_ref() accepts an additional
+ flags parameter in input.
+
+2011-06-03 - e977ca2 - lavfi 2.12.0 - avfilter_link_free()
+ Add avfilter_link_free() function.
+
+2011-06-02 - 5ad38d9 - lavu 51.4.0 - av_force_cpu_flags()
+ Add av_cpu_flags() in libavutil/cpu.h.
+
+2011-05-28 - e71f260 - lavu 51.3.0 - pixdesc.h
Add av_get_pix_fmt_name() in libavutil/pixdesc.h, and deprecate
avcodec_get_pix_fmt_name() in libavcodec/avcodec.h in its favor.
-2011-05-25 - 30315a8 - lavf 53.1.0 - avformat.h
+2011-05-25 - 39e4206 / 30315a8 - lavf 53.3.0 - avformat.h
Add fps_probe_size to AVFormatContext.
-2011-05-18 - 64150ff - lavc 53.4.0 - AVCodecContext.request_sample_fmt
+2011-05-22 - 5ecdfd0 - lavf 53.2.0 - avformat.h
+ Introduce avformat_alloc_output_context2() and deprecate
+ avformat_alloc_output_context().
+
+2011-05-22 - 83db719 - lavfi 2.10.0 - vsrc_buffer.h
+ Make libavfilter/vsrc_buffer.h public.
+
+2011-05-19 - c000a9f - lavfi 2.8.0 - avcodec.h
+ Add av_vsrc_buffer_add_frame() to libavfilter/avcodec.h.
+
+2011-05-14 - 9fdf772 - lavfi 2.6.0 - avcodec.h
+ Add avfilter_get_video_buffer_ref_from_frame() to libavfilter/avcodec.h.
+
+2011-05-18 - 75a37b5 / 64150ff - lavc 53.7.0 - AVCodecContext.request_sample_fmt
Add request_sample_fmt field to AVCodecContext.
-2011-05-10 - 188dea1 - lavc 53.3.0 - avcodec.h
+2011-05-10 - 59eb12f / 188dea1 - lavc 53.6.0 - avcodec.h
Deprecate AVLPCType and the following fields in
AVCodecContext: lpc_coeff_precision, prediction_order_method,
min_partition_order, max_partition_order, lpc_type, lpc_passes.
Corresponding FLAC encoder options should be used instead.
-2011-04-26 - bebe72f - lavu 51.1.0 - avutil.h
+2011-05-07 - 9fdf772 - lavfi 2.5.0 - avcodec.h
+ Add libavfilter/avcodec.h header and avfilter_copy_frame_props()
+ function.
+
+2011-05-07 - 18ded93 - lavc 53.5.0 - AVFrame
+ Add format field to AVFrame.
+
+2011-05-07 - 22333a6 - lavc 53.4.0 - AVFrame
+ Add width and height fields to AVFrame.
+
+2011-05-01 - 35fe66a - lavfi 2.4.0 - avfilter.h
+ Rename AVFilterBufferRefVideoProps.pixel_aspect to
+ sample_aspect_ratio.
+
+2011-05-01 - 77e9dee - lavc 53.3.0 - AVFrame
+ Add a sample_aspect_ratio field to AVFrame.
+
+2011-05-01 - 1ba5727 - lavc 53.2.0 - AVFrame
+ Add a pkt_pos field to AVFrame.
+
+2011-04-29 - 35ceaa7 - lavu 51.2.0 - mem.h
+ Add av_dynarray_add function for adding
+ an element to a dynamic array.
+
+2011-04-26 - d7e5aeb / bebe72f - lavu 51.1.0 - avutil.h
Add AVPictureType enum and av_get_picture_type_char(), deprecate
FF_*_TYPE defines and av_get_pict_type_char() defined in
libavcodec/avcodec.h.
-2011-04-26 - 10d3940 - lavfi 2.3.0 - avfilter.h
+2011-04-26 - d7e5aeb / 10d3940 - lavfi 2.3.0 - avfilter.h
Add pict_type and key_frame fields to AVFilterBufferRefVideo.
-2011-04-26 - 7a11c82 - lavfi 2.2.0 - vsrc_buffer
+2011-04-26 - d7e5aeb / 7a11c82 - lavfi 2.2.0 - vsrc_buffer
Add sample_aspect_ratio fields to vsrc_buffer arguments
-2011-04-21 - 94f7451 - lavc 53.1.0 - avcodec.h
+2011-04-21 - 8772156 / 94f7451 - lavc 53.1.0 - avcodec.h
Add CODEC_CAP_SLICE_THREADS for codecs supporting sliced threading.
2011-04-15 - lavc 52.120.0 - avcodec.h
AVPacket structure got additional members for passing side information:
- 4de339e introduce side information for AVPacket
- 2d8591c make containers pass palette change in AVPacket
+ c407984 / 4de339e introduce side information for AVPacket
+ c407984 / 2d8591c make containers pass palette change in AVPacket
2011-04-12 - lavf 52.107.0 - avio.h
Avio cleanup, part II - deprecate the entire URLContext API:
- 175389c add avio_check as a replacement for url_exist
- ff1ec0c add avio_pause and avio_seek_time as replacements
+ c55780d / 175389c add avio_check as a replacement for url_exist
+ 9891004 / ff1ec0c add avio_pause and avio_seek_time as replacements
for _av_url_read_fseek/fpause
- cdc6a87 deprecate av_protocol_next(), avio_enum_protocols
+ d4d0932 / cdc6a87 deprecate av_protocol_next(), avio_enum_protocols
should be used instead.
- 80c6e23 rename url_set_interrupt_cb->avio_set_interrupt_cb.
- f87b1b3 rename open flags: URL_* -> AVIO_*
- f8270bb add avio_enum_protocols.
- 5593f03 deprecate URLProtocol.
- c486dad deprecate URLContext.
- 026e175 deprecate the typedef for URLInterruptCB
- 8e76a19 deprecate av_register_protocol2.
- b840484 deprecate URL_PROTOCOL_FLAG_NESTED_SCHEME
- 1305d93 deprecate av_url_read_seek
- fa104e1 deprecate av_url_read_pause
- 727c7aa deprecate url_get_filename().
- 5958df3 deprecate url_max_packet_size().
- 1869ea0 deprecate url_get_file_handle().
- 32a97d4 deprecate url_filesize().
- e52a914 deprecate url_close().
- 58a48c6 deprecate url_seek().
- 925e908 deprecate url_write().
- dce3756 deprecate url_read_complete().
- bc371ac deprecate url_read().
- 0589da0 deprecate url_open().
- 62eaaea deprecate url_connect.
- 5652bb9 deprecate url_alloc.
- 333e894 deprecate url_open_protocol
- e230705 deprecate url_poll and URLPollEntry
-
-2011-04-10 - lavu 50.40.0 - pixfmt.h
- Add PIX_FMT_BGR48LE and PIX_FMT_BGR48BE pixel formats
+ c88caa5 / 80c6e23 rename url_set_interrupt_cb->avio_set_interrupt_cb.
+ c88caa5 / f87b1b3 rename open flags: URL_* -> AVIO_*
+ d4d0932 / f8270bb add avio_enum_protocols.
+ d4d0932 / 5593f03 deprecate URLProtocol.
+ d4d0932 / c486dad deprecate URLContext.
+ d4d0932 / 026e175 deprecate the typedef for URLInterruptCB
+ c88caa5 / 8e76a19 deprecate av_register_protocol2.
+ 11d7841 / b840484 deprecate URL_PROTOCOL_FLAG_NESTED_SCHEME
+ 11d7841 / 1305d93 deprecate av_url_read_seek
+ 11d7841 / fa104e1 deprecate av_url_read_pause
+ 434f248 / 727c7aa deprecate url_get_filename().
+ 434f248 / 5958df3 deprecate url_max_packet_size().
+ 434f248 / 1869ea0 deprecate url_get_file_handle().
+ 434f248 / 32a97d4 deprecate url_filesize().
+ 434f248 / e52a914 deprecate url_close().
+ 434f248 / 58a48c6 deprecate url_seek().
+ 434f248 / 925e908 deprecate url_write().
+ 434f248 / dce3756 deprecate url_read_complete().
+ 434f248 / bc371ac deprecate url_read().
+ 434f248 / 0589da0 deprecate url_open().
+ 434f248 / 62eaaea deprecate url_connect.
+ 434f248 / 5652bb9 deprecate url_alloc.
+ 434f248 / 333e894 deprecate url_open_protocol
+ 434f248 / e230705 deprecate url_poll and URLPollEntry
2011-04-08 - lavf 52.106.0 - avformat.h
Minor avformat.h cleanup:
- a9bf9d8 deprecate av_guess_image2_codec
- c3675df rename avf_sdp_create->av_sdp_create
+ d4d0932 / a9bf9d8 deprecate av_guess_image2_codec
+ d4d0932 / c3675df rename avf_sdp_create->av_sdp_create
2011-04-03 - lavf 52.105.0 - avio.h
Large-scale renaming/deprecating of AVIOContext-related functions:
- 724f6a0 deprecate url_fdopen
- 403ee83 deprecate url_open_dyn_packet_buf
- 6dc7d80 rename url_close_dyn_buf -> avio_close_dyn_buf
- b92c545 rename url_open_dyn_buf -> avio_open_dyn_buf
- 8978fed introduce an AVIOContext.seekable field as a replacement for
+ 2cae980 / 724f6a0 deprecate url_fdopen
+ 2cae980 / 403ee83 deprecate url_open_dyn_packet_buf
+ 2cae980 / 6dc7d80 rename url_close_dyn_buf -> avio_close_dyn_buf
+ 2cae980 / b92c545 rename url_open_dyn_buf -> avio_open_dyn_buf
+ 2cae980 / 8978fed introduce an AVIOContext.seekable field as a replacement for
AVIOContext.is_streamed and url_is_streamed()
- b64030f deprecate get_checksum()
- 4c4427a deprecate init_checksum()
- 4ec153b deprecate udp_set_remote_url/get_local_port
- 933e90a deprecate av_url_read_fseek/fpause
- 8d9769a deprecate url_fileno
- b7f2fdd rename put_flush_packet -> avio_flush
- 35f1023 deprecate url_close_buf
- 83fddae deprecate url_open_buf
- d9d86e0 rename url_fprintf -> avio_printf
- 59f65d9 deprecate url_setbufsize
- 3e68b3b deprecate url_ferror
- 66e5b1d deprecate url_feof
+ 1caa412 / b64030f deprecate get_checksum()
+ 1caa412 / 4c4427a deprecate init_checksum()
+ 2fd41c9 / 4ec153b deprecate udp_set_remote_url/get_local_port
+ 4fa0e24 / 933e90a deprecate av_url_read_fseek/fpause
+ 4fa0e24 / 8d9769a deprecate url_fileno
+ 0fecf26 / b7f2fdd rename put_flush_packet -> avio_flush
+ 0fecf26 / 35f1023 deprecate url_close_buf
+ 0fecf26 / 83fddae deprecate url_open_buf
+ 0fecf26 / d9d86e0 rename url_fprintf -> avio_printf
+ 0fecf26 / 59f65d9 deprecate url_setbufsize
+ 6947b0c / 3e68b3b deprecate url_ferror
e8bb2e2 deprecate url_fget_max_packet_size
76aa876 rename url_fsize -> avio_size
e519753 deprecate url_fgetc
@@ -1023,9 +1674,12 @@ lavd 54.0.0, lavfi 3.5.0
b3db9ce deprecate get_partial_buffer
8d9ac96 rename av_alloc_put_byte -> avio_alloc_context
-2011-03-25 - 34b47d7 - lavc 52.115.0 - AVCodecContext.audio_service_type
+2011-03-25 - 27ef7b1 / 34b47d7 - lavc 52.115.0 - AVCodecContext.audio_service_type
Add audio_service_type field to AVCodecContext.
+2011-03-17 - e309fdc - lavu 50.40.0 - pixfmt.h
+ Add PIX_FMT_BGR48LE and PIX_FMT_BGR48BE pixel formats
+
2011-03-02 - 863c471 - lavf 52.103.0 - av_pkt_dump2, av_pkt_dump_log2
Add new functions av_pkt_dump2, av_pkt_dump_log2 that uses the
source stream timebase for outputting timestamps. Deprecate
@@ -1058,11 +1712,11 @@ lavd 54.0.0, lavfi 3.5.0
2011-02-10 - 12c14cd - lavf 52.99.0 - AVStream.disposition
Add AV_DISPOSITION_HEARING_IMPAIRED and AV_DISPOSITION_VISUAL_IMPAIRED.
-2011-02-09 - 5592734 - lavc 52.112.0 - avcodec_thread_init()
+2011-02-09 - c0b102c - lavc 52.112.0 - avcodec_thread_init()
Deprecate avcodec_thread_init()/avcodec_thread_free() use; instead
set thread_count before calling avcodec_open.
-2011-02-09 - 778b08a - lavc 52.111.0 - threading API
+2011-02-09 - 37b00b4 - lavc 52.111.0 - threading API
Add CODEC_CAP_FRAME_THREADS with new restrictions on get_buffer()/
release_buffer()/draw_horiz_band() callbacks for appropriate codecs.
Add thread_type and active_thread_type fields to AVCodecContext.
@@ -1092,6 +1746,12 @@ lavd 54.0.0, lavfi 3.5.0
2011-02-02 - dfd2a00 - lavu 50.37.0 - log.h
Make av_dlog public.
+2011-01-31 - 7b3ea55 - lavfi 1.76.0 - vsrc_buffer
+ Add sample_aspect_ratio fields to vsrc_buffer arguments
+
+2011-01-31 - 910b5b8 - lavfi 1.75.0 - AVFilterLink sample_aspect_ratio
+ Add sample_aspect_ratio field to AVFilterLink.
+
2011-01-15 - a242ac3 - lavfi 1.74.0 - AVFilterBufferRefAudioProps
Rename AVFilterBufferRefAudioProps.samples_nb to nb_samples.
@@ -1459,6 +2119,9 @@ lavd 54.0.0, lavfi 3.5.0
2010-06-02 - 7e566bb - lavc 52.73.0 - av_get_codec_tag_string()
Add av_get_codec_tag_string().
+
+-------- 8< --------- FFmpeg 0.6 was cut here -------- 8< ---------
+
2010-06-01 - 2b99142 - lsws 0.11.0 - convertPalette API
Add sws_convertPalette8ToPacked32() and sws_convertPalette8ToPacked24().
@@ -1476,10 +2139,6 @@ lavd 54.0.0, lavfi 3.5.0
2010-05-09 - b6bc205 - lavfi 1.20.0 - AVFilterPicRef
Add interlaced and top_field_first fields to AVFilterPicRef.
-------------------------------8<-------------------------------------
- 0.6 branch was cut here
------------------------------>8--------------------------------------
-
2010-05-01 - 8e2ee18 - lavf 52.62.0 - probe function
Add av_probe_input_format2 to API, it allows ignoring probe
results below given score and returns the actual probe score.
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 58f7dfbece..8697e6c551 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -25,7 +25,7 @@ DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
-PROJECT_NAME = Libav
+PROJECT_NAME = FFmpeg
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
@@ -33,7 +33,7 @@ PROJECT_NAME = Libav
PROJECT_NUMBER =
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included
+# With the PROJECT_LOGO tag one can specify a logo or icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
# pixels and the maximum width should not exceed 200 pixels. Doxygen will
# copy the logo to the output directory.
@@ -639,14 +639,14 @@ EXCLUDE_SYMBOLS =
# directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH =
+EXAMPLE_PATH = doc/examples/
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank all files are included.
-EXAMPLE_PATTERNS = *-example.c
+EXAMPLE_PATTERNS = *.c
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude
@@ -709,7 +709,7 @@ INLINE_SOURCES = NO
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible.
-STRIP_CODE_COMMENTS = YES
+STRIP_CODE_COMMENTS = NO
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
@@ -759,7 +759,7 @@ ALPHABETICAL_INDEX = YES
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
# in which this list will be split (can be a number in the range [1..20])
-COLS_IN_ALPHA_INDEX = 2
+COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
@@ -818,7 +818,7 @@ HTML_STYLESHEET =
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
# The allowed range is 0 to 359.
-HTML_COLORSTYLE_HUE = 120
+#HTML_COLORSTYLE_HUE = 120
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
# the colors in the HTML output. For a value of 0 the output will use
@@ -1056,7 +1056,7 @@ FORMULA_TRANSPARENT = YES
# typically be disabled. For large projects the javascript based search engine
# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
-SEARCHENGINE = NO
+SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a PHP enabled web server instead of at the web client
@@ -1359,6 +1359,8 @@ PREDEFINED = "__attribute__(x)=" \
"DECLARE_ALIGNED(a,t,n)=t n" \
"offsetof(x,y)=0x42" \
av_alloc_size \
+ AV_GCC_VERSION_AT_LEAST(x,y)=1 \
+ __GNUC__=1 \
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
diff --git a/doc/Makefile b/doc/Makefile
index 2f6a5fb0c1..4573531184 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,40 +1,80 @@
-ALLMANPAGES = $(AVBASENAMES:%=%.1)
-MANPAGES = $(AVPROGS-yes:%=doc/%.1)
-PODPAGES = $(AVPROGS-yes:%=doc/%.pod)
-HTMLPAGES = $(AVPROGS-yes:%=doc/%.html) \
+LIBRARIES-$(CONFIG_AVUTIL) += libavutil
+LIBRARIES-$(CONFIG_SWSCALE) += libswscale
+LIBRARIES-$(CONFIG_SWRESAMPLE) += libswresample
+LIBRARIES-$(CONFIG_AVCODEC) += libavcodec
+LIBRARIES-$(CONFIG_AVFORMAT) += libavformat
+LIBRARIES-$(CONFIG_AVDEVICE) += libavdevice
+LIBRARIES-$(CONFIG_AVFILTER) += libavfilter
+
+COMPONENTS-$(CONFIG_AVUTIL) += ffmpeg-utils
+COMPONENTS-$(CONFIG_SWSCALE) += ffmpeg-scaler
+COMPONENTS-$(CONFIG_SWRESAMPLE) += ffmpeg-resampler
+COMPONENTS-$(CONFIG_AVCODEC) += ffmpeg-codecs ffmpeg-bitstream-filters
+COMPONENTS-$(CONFIG_AVFORMAT) += ffmpeg-formats ffmpeg-protocols
+COMPONENTS-$(CONFIG_AVDEVICE) += ffmpeg-devices
+COMPONENTS-$(CONFIG_AVFILTER) += ffmpeg-filters
+
+MANPAGES1 = $(AVPROGS-yes:%=doc/%.1) $(AVPROGS-yes:%=doc/%-all.1) $(COMPONENTS-yes:%=doc/%.1)
+MANPAGES3 = $(LIBRARIES-yes:%=doc/%.3)
+MANPAGES = $(MANPAGES1) $(MANPAGES3)
+PODPAGES = $(AVPROGS-yes:%=doc/%.pod) $(AVPROGS-yes:%=doc/%-all.pod) $(COMPONENTS-yes:%=doc/%.pod) $(LIBRARIES-yes:%=doc/%.pod)
+HTMLPAGES = $(AVPROGS-yes:%=doc/%.html) $(AVPROGS-yes:%=doc/%-all.html) $(COMPONENTS-yes:%=doc/%.html) $(LIBRARIES-yes:%=doc/%.html) \
doc/developer.html \
doc/faq.html \
doc/fate.html \
doc/general.html \
doc/git-howto.html \
- doc/libavfilter.html \
doc/nut.html \
doc/platform.html \
-DOCS-$(CONFIG_POD2MAN) += $(MANPAGES) $(PODPAGES)
-DOCS-$(CONFIG_TEXI2HTML) += $(HTMLPAGES)
-DOCS = $(DOCS-yes)
+TXTPAGES = doc/fate.txt \
-DOC_EXAMPLES-$(CONFIG_AVCODEC_EXAMPLE) += avcodec
-DOC_EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio
-DOC_EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata
-DOC_EXAMPLES-$(CONFIG_OUTPUT_EXAMPLE) += output
-DOC_EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec
-DOC_EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac
-ALL_DOC_EXAMPLES = avcodec filter_audio metadata output transcode_aac
-DOC_EXAMPLES := $(DOC_EXAMPLES-yes:%=doc/examples/%$(EXESUF))
-ALL_DOC_EXAMPLES := $(ALL_DOC_EXAMPLES:%=doc/examples/%$(EXESUF))
-PROGS += $(DOC_EXAMPLES)
+DOCS-$(CONFIG_HTMLPAGES) += $(HTMLPAGES)
+DOCS-$(CONFIG_PODPAGES) += $(PODPAGES)
+DOCS-$(CONFIG_MANPAGES) += $(MANPAGES)
+DOCS-$(CONFIG_TXTPAGES) += $(TXTPAGES)
+DOCS = $(DOCS-yes)
-all: $(DOCS)
+DOC_EXAMPLES-$(CONFIG_AVIO_LIST_DIR_EXAMPLE) += avio_list_dir
+DOC_EXAMPLES-$(CONFIG_AVIO_READING_EXAMPLE) += avio_reading
+DOC_EXAMPLES-$(CONFIG_AVCODEC_EXAMPLE) += avcodec
+DOC_EXAMPLES-$(CONFIG_DECODING_ENCODING_EXAMPLE) += decoding_encoding
+DOC_EXAMPLES-$(CONFIG_DEMUXING_DECODING_EXAMPLE) += demuxing_decoding
+DOC_EXAMPLES-$(CONFIG_EXTRACT_MVS_EXAMPLE) += extract_mvs
+DOC_EXAMPLES-$(CONFIG_FILTER_AUDIO_EXAMPLE) += filter_audio
+DOC_EXAMPLES-$(CONFIG_FILTERING_AUDIO_EXAMPLE) += filtering_audio
+DOC_EXAMPLES-$(CONFIG_FILTERING_VIDEO_EXAMPLE) += filtering_video
+DOC_EXAMPLES-$(CONFIG_METADATA_EXAMPLE) += metadata
+DOC_EXAMPLES-$(CONFIG_MUXING_EXAMPLE) += muxing
+DOC_EXAMPLES-$(CONFIG_QSVDEC_EXAMPLE) += qsvdec
+DOC_EXAMPLES-$(CONFIG_REMUXING_EXAMPLE) += remuxing
+DOC_EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio
+DOC_EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video
+DOC_EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac
+DOC_EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding
+ALL_DOC_EXAMPLES_LIST = $(DOC_EXAMPLES-) $(DOC_EXAMPLES-yes)
+
+DOC_EXAMPLES := $(DOC_EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)$(EXESUF))
+ALL_DOC_EXAMPLES := $(ALL_DOC_EXAMPLES_LIST:%=doc/examples/%$(PROGSSUF)$(EXESUF))
+ALL_DOC_EXAMPLES_G := $(ALL_DOC_EXAMPLES_LIST:%=doc/examples/%$(PROGSSUF)_g$(EXESUF))
+PROGS += $(DOC_EXAMPLES)
+
+all-$(CONFIG_DOC): doc
+
+doc: documentation
apidoc: doc/doxy/html
documentation: $(DOCS)
examples: $(DOC_EXAMPLES)
-TEXIDEP = awk '/^@include/ { printf "$@: $(@D)/%s\n", $$2 }' <$< >$(@:%=%.d)
+TEXIDEP = perl $(SRC_PATH)/doc/texidep.pl $(SRC_PATH) $< $@ >$(@:%=%.d)
+
+doc/%.txt: TAG = TXT
+doc/%.txt: doc/%.texi
+ $(Q)$(TEXIDEP)
+ $(M)makeinfo --force --no-headers -o $@ $< 2>/dev/null
GENTEXI = format codec
GENTEXI := $(GENTEXI:%=doc/avoptions_%.texi)
@@ -44,55 +84,101 @@ $(GENTEXI): doc/avoptions_%.texi: doc/print_options$(HOSTEXESUF)
$(M)doc/print_options $* > $@
doc/%.html: TAG = HTML
+doc/%-all.html: TAG = HTML
+
+ifdef HAVE_MAKEINFO_HTML
+doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
+ $(Q)$(TEXIDEP)
+ $(M)makeinfo --html -I doc --no-split -D config-not-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
+
+doc/%-all.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
+ $(Q)$(TEXIDEP)
+ $(M)makeinfo --html -I doc --no-split -D config-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
+else
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.init $(GENTEXI)
$(Q)$(TEXIDEP)
- $(M)texi2html -I doc -monolithic --init-file $(SRC_PATH)/doc/t2h.init --output $@ $<
+ $(M)texi2html -I doc -monolithic --D=config-not-all --init-file $(SRC_PATH)/doc/t2h.init --output $@ $<
+
+doc/%-all.html: doc/%.texi $(SRC_PATH)/doc/t2h.init $(GENTEXI)
+ $(Q)$(TEXIDEP)
+ $(M)texi2html -I doc -monolithic --D=config-all --init-file $(SRC_PATH)/doc/t2h.init --output $@ $<
+endif
doc/%.pod: TAG = POD
doc/%.pod: doc/%.texi $(SRC_PATH)/doc/texi2pod.pl $(GENTEXI)
$(Q)$(TEXIDEP)
- $(M)$(SRC_PATH)/doc/texi2pod.pl -Idoc $< $@
+ $(M)perl $(SRC_PATH)/doc/texi2pod.pl -Dconfig-not-all=yes -Idoc $< $@
-doc/%.1: TAG = MAN
+doc/%-all.pod: TAG = POD
+doc/%-all.pod: doc/%.texi $(SRC_PATH)/doc/texi2pod.pl $(GENTEXI)
+ $(Q)$(TEXIDEP)
+ $(M)perl $(SRC_PATH)/doc/texi2pod.pl -Dconfig-all=yes -Idoc $< $@
+
+doc/%.1 doc/%.3: TAG = MAN
doc/%.1: doc/%.pod $(GENTEXI)
- $(M)pod2man --section=1 --center=" " --release=" " $< > $@
+ $(M)pod2man --section=1 --center=" " --release=" " --date=" " $< > $@
+doc/%.3: doc/%.pod $(GENTEXI)
+ $(M)pod2man --section=3 --center=" " --release=" " --date=" " $< > $@
$(DOCS) doc/doxy/html: | doc/
$(DOC_EXAMPLES:%$(EXESUF)=%.o): | doc/examples
OBJDIRS += doc/examples
DOXY_INPUT = $(addprefix $(SRC_PATH)/, $(INSTHEADERS) $(DOC_EXAMPLES:%$(EXESUF)=%.c) $(LIB_EXAMPLES:%$(EXESUF)=%.c))
-DOXY_TEMPLATES = doxy_stylesheet.css footer.html header.html
-DOXY_TEMPLATES := $(addprefix $(SRC_PATH)/doc/doxy/, $(DOXY_TEMPLATES))
-doc/doxy/html: $(SRC_PATH)/doc/Doxyfile $(DOXY_INPUT) $(DOXY_TEMPLATES)
- $(M)$(SRC_PATH)/doc/doxy-wrapper.sh $(SRC_PATH) $< $(DOXY_INPUT)
+doc/doxy/html: TAG = DOXY
+doc/doxy/html: $(SRC_PATH)/doc/Doxyfile $(SRC_PATH)/doc/doxy-wrapper.sh $(DOXY_INPUT)
+ $(M)$(SRC_PATH)/doc/doxy-wrapper.sh $(SRC_PATH) $< $(DOXYGEN) $(DOXY_INPUT)
+
+install-doc: install-html install-man
+
+install-html:
+
+install-man:
-install-progs-$(CONFIG_POD2MAN): install-man
-install-progs-$(CONFIG_TEXI2HTML): install-doc
+ifdef CONFIG_HTMLPAGES
+install-progs-$(CONFIG_DOC): install-html
-install-doc: $(HTMLPAGES)
+install-html: $(HTMLPAGES)
$(Q)mkdir -p "$(DOCDIR)"
$(INSTALL) -m 644 $(HTMLPAGES) "$(DOCDIR)"
+endif
+
+ifdef CONFIG_MANPAGES
+install-progs-$(CONFIG_DOC): install-man
install-man: $(MANPAGES)
$(Q)mkdir -p "$(MANDIR)/man1"
- $(INSTALL) -m 644 $(MANPAGES) "$(MANDIR)/man1"
+ $(INSTALL) -m 644 $(MANPAGES1) "$(MANDIR)/man1"
+ $(Q)mkdir -p "$(MANDIR)/man3"
+ $(INSTALL) -m 644 $(MANPAGES3) "$(MANDIR)/man3"
+endif
+
+uninstall: uninstall-doc
-uninstall: uninstall-doc uninstall-man
+uninstall-doc: uninstall-html uninstall-man
-uninstall-doc:
+uninstall-html:
$(RM) -r "$(DOCDIR)"
uninstall-man:
- $(RM) $(addprefix "$(MANDIR)/man1/",$(ALLMANPAGES))
+ $(RM) $(addprefix "$(MANDIR)/man1/",$(AVPROGS-yes:%=%.1) $(AVPROGS-yes:%=%-all.1) $(COMPONENTS-yes:%=%.1))
+ $(RM) $(addprefix "$(MANDIR)/man3/",$(LIBRARIES-yes:%=%.3))
+
+clean:: docclean
+
+distclean:: docclean
+ $(RM) doc/config.texi
+
+examplesclean:
+ $(RM) $(ALL_DOC_EXAMPLES) $(ALL_DOC_EXAMPLES_G)
+ $(RM) $(CLEANSUFFIXES:%=doc/examples/%)
-clean::
- $(RM) $(ALL_DOC_EXAMPLES)
- $(RM) $(CLEANSUFFIXES:%=doc/%) $(CLEANSUFFIXES:%=doc/examples/%)
- $(RM) doc/*.html doc/*.pod doc/*.1 doc/avoptions_*.texi
+docclean: examplesclean
+ $(RM) $(CLEANSUFFIXES:%=doc/%)
+ $(RM) $(TXTPAGES) doc/*.html doc/*.pod doc/*.1 doc/*.3 doc/avoptions_*.texi
$(RM) -r doc/doxy/html
-include $(wildcard $(DOCS:%=%.d))
-.PHONY: apidoc documentation
+.PHONY: apidoc doc documentation
diff --git a/doc/RELEASE_NOTES b/doc/RELEASE_NOTES
deleted file mode 100644
index bda4789aff..0000000000
--- a/doc/RELEASE_NOTES
+++ /dev/null
@@ -1,75 +0,0 @@
-Release Notes
-=============
-
-* 11 "One Louder"
-
-General notes
--------------
-
-With this release we are trying to answer the numerous calls from our users for
-shorter development cycles. From now on we will aim for approximately two major
-releases per year.
-
-Libav 11 is API-, but not ABI-compatible with the previous major release. This
-means that the code using our libraries needs to be rebuilt, but no source
-changes should be required. Note however, that a number of old APIs remain
-deprecated and will be dropped in the near future. All users are strongly
-encouraged to update their code as soon as possible. The doc/APIchanges file in
-the Libav source tree and the migration guide on the wiki should help with
-migration to the new APIs. If those are not sufficient, do not hesitate to
-contact us on IRC or through the user mailing list.
-
-One specific API issue in libavformat deserves mentioning here. When using
-libavcodec for decoding or encoding and libavformat for demuxing or muxing,
-the standard practice was to use the stream codec context (AVStream.codec) for
-actual decoding or encoding. There are multiple problems with this pattern
-(the main one is that the decoder/demuxer or encoder/muxer are not necessarily
-synchronized and may overwrite each other's state), so it is now strongly
-discouraged and will likely be deprecated in the future. Users should instead
-allocate a separate decoding or encoding context and populate it from the
-demuxing codec context (or the reverse for encoding) with the
-avcodec_copy_context() function.
-
-The main highlights of this release include native Opus, VP7, OpenEXR, and On2
-AVC decoders, HEVC encoding through libx265, new APIs for exporting ReplayGain
-and display transformation metadata and countless bug fixes. A large effort was
-also expended on internal cleanups which are not very visible to our users,
-but should make the codebase cleaner, safer and easier to maintain and extend.
-One point worth mentioning is refactoring the large monolithic framework for
-architecture-specific codec optimizations into small blocks, which reduces the
-size of configurations that selectively enable or disable certain codecs.
-
-The avserver streaming tool, which has not been maintained for many years and
-was mostly broken, was removed from the tree. It was decided that it is a
-significant maintenance burden and that we do our users no service by pretending
-to support it, while we in fact do not.
-
-See the Changelog file for a more extensive list of significant changes.
-
-API changes
------------
-
-A number of additional APIs have been introduced and some existing functions
-have been deprecated and are scheduled for removal in the next release.
-Significant API changes include:
-
-[libavcodec]
-+ Added the avcodec_copy_context() function that must from now on be used for
- freeing codec contexts.
-+- Added a new VDA hardware acceleration API, since the old one was broken and
- not fixable in a compatible way. Deprecated the old VDA API.
-
-[libavformat]
-+ Added support for exporting stream-global (as opposed to per-packet) side
- data. This feature is now used by some demuxers to export ReplayGain or
- display transformation matrix (aka rotation) or stereoscopic 3D mode.
-+ Added an API for live metadata updates through event flags.
-+- Changed the way to provide a hint about the desired timebase to muxers.
- Previously it was done by setting AVStream.codec.time_base. Now callers
- should set AVStream.time_base.
-
-[libavresample]
-+ Added an API for working with AVFrames.
-
-Please see the file doc/APIchanges for details along with similar
-programmer-centric information.
diff --git a/doc/authors.texi b/doc/authors.texi
new file mode 100644
index 0000000000..6c8c1d7efa
--- /dev/null
+++ b/doc/authors.texi
@@ -0,0 +1,11 @@
+@chapter Authors
+
+The FFmpeg developers.
+
+For details about the authorship, see the Git history of the project
+(git://source.ffmpeg.org/ffmpeg), e.g. by typing the command
+@command{git log} in the FFmpeg source directory, or browsing the
+online repository at @url{http://source.ffmpeg.org}.
+
+Maintainers for the specific components are listed in the file
+@file{MAINTAINERS} in the source code tree.
diff --git a/doc/avconv.texi b/doc/avconv.texi
deleted file mode 100644
index aea41d9eec..0000000000
--- a/doc/avconv.texi
+++ /dev/null
@@ -1,1184 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-
-@settitle avconv Documentation
-@titlepage
-@center @titlefont{avconv Documentation}
-@end titlepage
-
-@top
-
-@contents
-
-@chapter Synopsis
-
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avconv [global options] [[infile options][@option{-i} @var{infile}]]... @{[outfile options] @var{outfile}@}...
-@c man end
-@end example
-
-@chapter Description
-@c man begin DESCRIPTION
-
-avconv is a very fast video and audio converter that can also grab from
-a live audio/video source. It can also convert between arbitrary sample
-rates and resize video on the fly with a high quality polyphase filter.
-
-avconv reads from an arbitrary number of input "files" (which can be regular
-files, pipes, network streams, grabbing devices, etc.), specified by the
-@code{-i} option, and writes to an arbitrary number of output "files", which are
-specified by a plain output filename. Anything found on the command line which
-cannot be interpreted as an option is considered to be an output filename.
-
-Each input or output file can in principle contain any number of streams of
-different types (video/audio/subtitle/attachment/data). Allowed number and/or
-types of streams can be limited by the container format. Selecting, which
-streams from which inputs go into output, is done either automatically or with
-the @code{-map} option (see the Stream selection chapter).
-
-To refer to input files in options, you must use their indices (0-based). E.g.
-the first input file is @code{0}, the second is @code{1} etc. Similarly, streams
-within a file are referred to by their indices. E.g. @code{2:3} refers to the
-fourth stream in the third input file. See also the Stream specifiers chapter.
-
-As a general rule, options are applied to the next specified
-file. Therefore, order is important, and you can have the same
-option on the command line multiple times. Each occurrence is
-then applied to the next input or output file.
-Exceptions from this rule are the global options (e.g. verbosity level),
-which should be specified first.
-
-Do not mix input and output files -- first specify all input files, then all
-output files. Also do not mix options which belong to different files. All
-options apply ONLY to the next input or output file and are reset between files.
-
-@itemize
-@item
-To set the video bitrate of the output file to 64kbit/s:
-@example
-avconv -i input.avi -b 64k output.avi
-@end example
-
-@item
-To force the frame rate of the output file to 24 fps:
-@example
-avconv -i input.avi -r 24 output.avi
-@end example
-
-@item
-To force the frame rate of the input file (valid for raw formats only)
-to 1 fps and the frame rate of the output file to 24 fps:
-@example
-avconv -r 1 -i input.m2v -r 24 output.avi
-@end example
-@end itemize
-
-The format option may be needed for raw input files.
-
-@c man end DESCRIPTION
-
-@chapter Detailed description
-@c man begin DETAILED DESCRIPTION
-
-The transcoding process in @command{avconv} for each output can be described by
-the following diagram:
-
-@example
- _______ ______________
-| | | |
-| input | demuxer | encoded data | decoder
-| file | ---------> | packets | -----+
-|_______| |______________| |
- v
- _________
- | |
- | decoded |
- | frames |
- |_________|
- ________ ______________ |
-| | | | |
-| output | <-------- | encoded data | <----+
-| file | muxer | packets | encoder
-|________| |______________|
-
-
-@end example
-
-@command{avconv} calls the libavformat library (containing demuxers) to read
-input files and get packets containing encoded data from them. When there are
-multiple input files, @command{avconv} tries to keep them synchronized by
-tracking lowest timestamp on any active input stream.
-
-Encoded packets are then passed to the decoder (unless streamcopy is selected
-for the stream, see further for a description). The decoder produces
-uncompressed frames (raw video/PCM audio/...) which can be processed further by
-filtering (see next section). After filtering the frames are passed to the
-encoder, which encodes them and outputs encoded packets again. Finally those are
-passed to the muxer, which writes the encoded packets to the output file.
-
-@section Filtering
-Before encoding, @command{avconv} can process raw audio and video frames using
-filters from the libavfilter library. Several chained filters form a filter
-graph. @command{avconv} distinguishes between two types of filtergraphs -
-simple and complex.
-
-@subsection Simple filtergraphs
-Simple filtergraphs are those that have exactly one input and output, both of
-the same type. In the above diagram they can be represented by simply inserting
-an additional step between decoding and encoding:
-
-@example
- _________ ______________
-| | | |
-| decoded | | encoded data |
-| frames |\ /| packets |
-|_________| \ / |______________|
- \ __________ /
- simple \ | | / encoder
- filtergraph \| filtered |/
- | frames |
- |__________|
-
-@end example
-
-Simple filtergraphs are configured with the per-stream @option{-filter} option
-(with @option{-vf} and @option{-af} aliases for video and audio respectively).
-A simple filtergraph for video can look for example like this:
-
-@example
- _______ _____________ _______ ________
-| | | | | | | |
-| input | ---> | deinterlace | ---> | scale | ---> | output |
-|_______| |_____________| |_______| |________|
-
-@end example
-
-Note that some filters change frame properties but not frame contents. E.g. the
-@code{fps} filter in the example above changes number of frames, but does not
-touch the frame contents. Another example is the @code{setpts} filter, which
-only sets timestamps and otherwise passes the frames unchanged.
-
-@subsection Complex filtergraphs
-Complex filtergraphs are those which cannot be described as simply a linear
-processing chain applied to one stream. This is the case e.g. when the graph has
-more than one input and/or output, or when output stream type is different from
-input. They can be represented with the following diagram:
-
-@example
- _________
-| |
-| input 0 |\ __________
-|_________| \ | |
- \ _________ /| output 0 |
- \ | | / |__________|
- _________ \| complex | /
-| | | |/
-| input 1 |---->| filter |\
-|_________| | | \ __________
- /| graph | \ | |
- / | | \| output 1 |
- _________ / |_________| |__________|
-| | /
-| input 2 |/
-|_________|
-
-@end example
-
-Complex filtergraphs are configured with the @option{-filter_complex} option.
-Note that this option is global, since a complex filtergraph by its nature
-cannot be unambiguously associated with a single stream or file.
-
-A trivial example of a complex filtergraph is the @code{overlay} filter, which
-has two video inputs and one video output, containing one video overlaid on top
-of the other. Its audio counterpart is the @code{amix} filter.
-
-@section Stream copy
-Stream copy is a mode selected by supplying the @code{copy} parameter to the
-@option{-codec} option. It makes @command{avconv} omit the decoding and encoding
-step for the specified stream, so it does only demuxing and muxing. It is useful
-for changing the container format or modifying container-level metadata. The
-diagram above will in this case simplify to this:
-
-@example
- _______ ______________ ________
-| | | | | |
-| input | demuxer | encoded data | muxer | output |
-| file | ---------> | packets | -------> | file |
-|_______| |______________| |________|
-
-@end example
-
-Since there is no decoding or encoding, it is very fast and there is no quality
-loss. However it might not work in some cases because of many factors. Applying
-filters is obviously also impossible, since filters work on uncompressed data.
-
-@c man end DETAILED DESCRIPTION
-
-@chapter Stream selection
-@c man begin STREAM SELECTION
-
-By default avconv tries to pick the "best" stream of each type present in input
-files and add them to each output file. For video, this means the highest
-resolution, for audio the highest channel count. For subtitle it's simply the
-first subtitle stream.
-
-You can disable some of those defaults by using @code{-vn/-an/-sn} options. For
-full manual control, use the @code{-map} option, which disables the defaults just
-described.
-
-@c man end STREAM SELECTION
-
-@chapter Options
-@c man begin OPTIONS
-
-@include avtools-common-opts.texi
-
-@section Main options
-
-@table @option
-
-@item -f @var{fmt} (@emph{input/output})
-Force input or output file format. The format is normally autodetected for input
-files and guessed from file extension for output files, so this option is not
-needed in most cases.
-
-@item -i @var{filename} (@emph{input})
-input file name
-
-@item -y (@emph{global})
-Overwrite output files without asking.
-
-@item -n (@emph{global})
-Immediately exit when output files already exist.
-
-@item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
-@itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
-Select an encoder (when used before an output file) or a decoder (when used
-before an input file) for one or more streams. @var{codec} is the name of a
-decoder/encoder or a special value @code{copy} (output only) to indicate that
-the stream is not to be reencoded.
-
-For example
-@example
-avconv -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
-@end example
-encodes all video streams with libx264 and copies all audio streams.
-
-For each stream, the last matching @code{c} option is applied, so
-@example
-avconv -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
-@end example
-will copy all the streams except the second video, which will be encoded with
-libx264, and the 138th audio, which will be encoded with libvorbis.
-
-@item -t @var{duration} (@emph{output})
-Stop writing the output after its duration reaches @var{duration}.
-@var{duration} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
-
-@item -fs @var{limit_size} (@emph{output})
-Set the file size limit.
-
-@item -ss @var{position} (@emph{input/output})
-When used as an input option (before @code{-i}), seeks in this input file to
-@var{position}. Note the in most formats it is not possible to seek exactly, so
-@command{avconv} will seek to the closest seek point before @var{position}.
-When transcoding and @option{-accurate_seek} is enabled (the default), this
-extra segment between the seek point and @var{position} will be decoded and
-discarded. When doing stream copy or when @option{-noaccurate_seek} is used, it
-will be preserved.
-
-When used as an output option (before an output filename), decodes but discards
-input until the timestamps reach @var{position}.
-
-@var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form.
-
-@item -itsoffset @var{offset} (@emph{input})
-Set the input time offset in seconds.
-@code{[-]hh:mm:ss[.xxx]} syntax is also supported.
-The offset is added to the timestamps of the input files.
-Specifying a positive offset means that the corresponding
-streams are delayed by @var{offset} seconds.
-
-@item -metadata[:metadata_specifier] @var{key}=@var{value} (@emph{output,per-metadata})
-Set a metadata key/value pair.
-
-An optional @var{metadata_specifier} may be given to set metadata
-on streams or chapters. See @code{-map_metadata} documentation for
-details.
-
-This option overrides metadata set with @code{-map_metadata}. It is
-also possible to delete metadata by using an empty value.
-
-For example, for setting the title in the output file:
-@example
-avconv -i in.avi -metadata title="my title" out.flv
-@end example
-
-To set the language of the first audio stream:
-@example
-avconv -i INPUT -metadata:s:a:0 language=eng OUTPUT
-@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
-@code{film-} to use the corresponding standard. All the format options
-(bitrate, codecs, buffer sizes) are then set automatically. You can just type:
-
-@example
-avconv -i myfile.avi -target vcd /tmp/vcd.mpg
-@end example
-
-Nevertheless you can specify additional options as long as you know
-they do not conflict with the standard, as in:
-
-@example
-avconv -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
-@end example
-
-@item -dframes @var{number} (@emph{output})
-Set the number of data frames to record. This is an alias for @code{-frames:d}.
-
-@item -frames[:@var{stream_specifier}] @var{framecount} (@emph{output,per-stream})
-Stop writing to the stream after @var{framecount} frames.
-
-@item -q[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
-@itemx -qscale[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
-Use fixed quality scale (VBR). The meaning of @var{q} is
-codec-dependent.
-
-@item -filter[:@var{stream_specifier}] @var{filter_graph} (@emph{output,per-stream})
-@var{filter_graph} is a description of the filter graph to apply to
-the stream. Use @code{-filters} to show all the available filters
-(including also sources and sinks).
-
-See also the @option{-filter_complex} option if you want to create filter graphs
-with multiple inputs and/or outputs.
-
-@item -filter_script[:@var{stream_specifier}] @var{filename} (@emph{output,per-stream})
-This option is similar to @option{-filter}, the only difference is that its
-argument is the name of the file from which a filtergraph description is to be
-read.
-
-@item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream})
-Specify the preset for matching stream(s).
-
-@item -stats (@emph{global})
-Print encoding progress/statistics. On by default.
-
-@item -attach @var{filename} (@emph{output})
-Add an attachment to the output file. This is supported by a few formats
-like Matroska for e.g. fonts used in rendering subtitles. Attachments
-are implemented as a specific type of stream, so this option will add
-a new stream to the file. It is then possible to use per-stream options
-on this stream in the usual way. Attachment streams created with this
-option will be created after all the other streams (i.e. those created
-with @code{-map} or automatic mappings).
-
-Note that for Matroska you also have to set the mimetype metadata tag:
-@example
-avconv -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
-@end example
-(assuming that the attachment stream will be third in the output file).
-
-@item -dump_attachment[:@var{stream_specifier}] @var{filename} (@emph{input,per-stream})
-Extract the matching attachment stream into a file named @var{filename}. If
-@var{filename} is empty, then the value of the @code{filename} metadata tag
-will be used.
-
-E.g. to extract the first attachment to a file named 'out.ttf':
-@example
-avconv -dump_attachment:t:0 out.ttf INPUT
-@end example
-To extract all attachments to files determined by the @code{filename} tag:
-@example
-avconv -dump_attachment:t "" INPUT
-@end example
-
-Technical note -- attachments are implemented as codec extradata, so this
-option can actually be used to extract extradata from any stream, not just
-attachments.
-
-@item -noautorotate
-Disable automatically rotating video based on file metadata.
-
-@end table
-
-@section Video Options
-
-@table @option
-@item -vframes @var{number} (@emph{output})
-Set the number of video frames to record. This is an alias for @code{-frames:v}.
-@item -r[:@var{stream_specifier}] @var{fps} (@emph{input/output,per-stream})
-Set frame rate (Hz value, fraction or abbreviation).
-
-As an input option, ignore any timestamps stored in the file and instead
-generate timestamps assuming constant frame rate @var{fps}.
-
-As an output option, duplicate or drop input frames to achieve constant output
-frame rate @var{fps} (note that this actually causes the @code{fps} filter to be
-inserted to the end of the corresponding filtergraph).
-
-@item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream})
-Set frame size.
-
-As an input option, this is a shortcut for the @option{video_size} private
-option, recognized by some demuxers for which the frame size is either not
-stored in the file or is configurable -- e.g. raw video or video grabbers.
-
-As an output option, this inserts the @code{scale} video filter to the
-@emph{end} of the corresponding filtergraph. Please use the @code{scale} filter
-directly to insert it at the beginning or some other place.
-
-The format is @samp{wxh} (default - same as source). The following
-abbreviations are recognized:
-@table @samp
-@item sqcif
-128x96
-@item qcif
-176x144
-@item cif
-352x288
-@item 4cif
-704x576
-@item 16cif
-1408x1152
-@item qqvga
-160x120
-@item qvga
-320x240
-@item vga
-640x480
-@item svga
-800x600
-@item xga
-1024x768
-@item uxga
-1600x1200
-@item qxga
-2048x1536
-@item sxga
-1280x1024
-@item qsxga
-2560x2048
-@item hsxga
-5120x4096
-@item wvga
-852x480
-@item wxga
-1366x768
-@item wsxga
-1600x1024
-@item wuxga
-1920x1200
-@item woxga
-2560x1600
-@item wqsxga
-3200x2048
-@item wquxga
-3840x2400
-@item whsxga
-6400x4096
-@item whuxga
-7680x4800
-@item cga
-320x200
-@item ega
-640x350
-@item hd480
-852x480
-@item hd720
-1280x720
-@item hd1080
-1920x1080
-@end table
-
-@item -aspect[:@var{stream_specifier}] @var{aspect} (@emph{output,per-stream})
-Set the video display aspect ratio specified by @var{aspect}.
-
-@var{aspect} can be a floating point number string, or a string of the
-form @var{num}:@var{den}, where @var{num} and @var{den} are the
-numerator and denominator of the aspect ratio. For example "4:3",
-"16:9", "1.3333", and "1.7777" are valid argument values.
-
-@item -vn (@emph{output})
-Disable video recording.
-
-@item -vcodec @var{codec} (@emph{output})
-Set the video codec. This is an alias for @code{-codec:v}.
-
-@item -pass[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
-Select the pass number (1 or 2). It is used to do two-pass
-video encoding. The statistics of the video are recorded in the first
-pass into a log file (see also the option -passlogfile),
-and in the second pass that log file is used to generate the video
-at the exact requested bitrate.
-On pass 1, you may just deactivate audio and set output to null,
-examples for Windows and Unix:
-@example
-avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
-avconv -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
-@end example
-
-@item -passlogfile[:@var{stream_specifier}] @var{prefix} (@emph{output,per-stream})
-Set two-pass log file name prefix to @var{prefix}, the default file name
-prefix is ``av2pass''. The complete file name will be
-@file{PREFIX-N.log}, where N is a number specific to the output
-stream.
-
-@item -vf @var{filter_graph} (@emph{output})
-@var{filter_graph} is a description of the filter graph to apply to
-the input video.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks). This is an alias for @code{-filter:v}.
-
-@end table
-
-@section Advanced Video Options
-
-@table @option
-@item -pix_fmt[:@var{stream_specifier}] @var{format} (@emph{input/output,per-stream})
-Set pixel format. Use @code{-pix_fmts} to show all the supported
-pixel formats.
-@item -sws_flags @var{flags} (@emph{input/output})
-Set SwScaler flags.
-@item -vdt @var{n}
-Discard threshold.
-
-@item -rc_override[:@var{stream_specifier}] @var{override} (@emph{output,per-stream})
-rate control override for specific intervals
-
-@item -vstats
-Dump video coding statistics to @file{vstats_HHMMSS.log}.
-@item -vstats_file @var{file}
-Dump video coding statistics to @var{file}.
-@item -top[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
-top=1/bottom=0/auto=-1 field first
-@item -dc @var{precision}
-Intra_dc_precision.
-@item -vtag @var{fourcc/tag} (@emph{output})
-Force video tag/fourcc. This is an alias for @code{-tag:v}.
-@item -qphist (@emph{global})
-Show QP histogram.
-@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
-Force key frames at the specified timestamps, more precisely at the first
-frames after each specified time.
-This option can be useful to ensure that a seek point is present at a
-chapter mark or any other designated place in the output file.
-The timestamps must be specified in ascending order.
-
-@item -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
-When doing stream copy, copy also non-key frames found at the
-beginning.
-
-@item -hwaccel[:@var{stream_specifier}] @var{hwaccel} (@emph{input,per-stream})
-Use hardware acceleration to decode the matching stream(s). The allowed values
-of @var{hwaccel} are:
-@table @option
-@item none
-Do not use any hardware acceleration (the default).
-
-@item auto
-Automatically select the hardware acceleration method.
-
-@item vda
-Use Apple VDA hardware acceleration.
-
-@item vdpau
-Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration.
-
-@item dxva2
-Use DXVA2 (DirectX Video Acceleration) hardware acceleration.
-@end table
-
-This option has no effect if the selected hwaccel is not available or not
-supported by the chosen decoder.
-
-Note that most acceleration methods are intended for playback and will not be
-faster than software decoding on modern CPUs. Additionally, @command{avconv}
-will usually need to copy the decoded frames from the GPU memory into the system
-memory, resulting in further performance loss. This option is thus mainly
-useful for testing.
-
-@item -hwaccel_device[:@var{stream_specifier}] @var{hwaccel_device} (@emph{input,per-stream})
-Select a device to use for hardware acceleration.
-
-This option only makes sense when the @option{-hwaccel} option is also
-specified. Its exact meaning depends on the specific hardware acceleration
-method chosen.
-
-@table @option
-@item vdpau
-For VDPAU, this option specifies the X11 display/screen to use. If this option
-is not specified, the value of the @var{DISPLAY} environment variable is used
-
-@item dxva2
-For DXVA2, this option should contain the number of the display adapter to use.
-If this option is not specified, the default adapter is used.
-@end table
-@end table
-
-@section Audio Options
-
-@table @option
-@item -aframes @var{number} (@emph{output})
-Set the number of audio frames to record. This is an alias for @code{-frames:a}.
-@item -ar[:@var{stream_specifier}] @var{freq} (@emph{input/output,per-stream})
-Set the audio sampling frequency. For output streams it is set by
-default to the frequency of the corresponding input stream. For input
-streams this option only makes sense for audio grabbing devices and raw
-demuxers and is mapped to the corresponding demuxer options.
-@item -aq @var{q} (@emph{output})
-Set the audio quality (codec-specific, VBR). This is an alias for -q:a.
-@item -ac[:@var{stream_specifier}] @var{channels} (@emph{input/output,per-stream})
-Set the number of audio channels. For output streams it is set by
-default to the number of input audio channels. For input streams
-this option only makes sense for audio grabbing devices and raw demuxers
-and is mapped to the corresponding demuxer options.
-@item -an (@emph{output})
-Disable audio recording.
-@item -acodec @var{codec} (@emph{input/output})
-Set the audio codec. This is an alias for @code{-codec:a}.
-@item -sample_fmt[:@var{stream_specifier}] @var{sample_fmt} (@emph{output,per-stream})
-Set the audio sample format. Use @code{-sample_fmts} to get a list
-of supported sample formats.
-@item -af @var{filter_graph} (@emph{output})
-@var{filter_graph} is a description of the filter graph to apply to
-the input audio.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks). This is an alias for @code{-filter:a}.
-@end table
-
-@section Advanced Audio options:
-
-@table @option
-@item -atag @var{fourcc/tag} (@emph{output})
-Force audio tag/fourcc. This is an alias for @code{-tag:a}.
-@end table
-
-@section Subtitle options:
-
-@table @option
-@item -scodec @var{codec} (@emph{input/output})
-Set the subtitle codec. This is an alias for @code{-codec:s}.
-@item -sn (@emph{output})
-Disable subtitle recording.
-@end table
-
-@section Advanced options
-
-@table @option
-@item -map [-]@var{input_file_id}[:@var{stream_specifier}][,@var{sync_file_id}[:@var{stream_specifier}]] | @var{[linklabel]} (@emph{output})
-
-Designate one or more input streams as a source for the output file. Each input
-stream is identified by the input file index @var{input_file_id} and
-the input stream index @var{input_stream_id} within the input
-file. Both indices start at 0. If specified,
-@var{sync_file_id}:@var{stream_specifier} sets which input stream
-is used as a presentation sync reference.
-
-The first @code{-map} option on the command line specifies the
-source for output stream 0, the second @code{-map} option specifies
-the source for output stream 1, etc.
-
-A @code{-} character before the stream identifier creates a "negative" mapping.
-It disables matching streams from already created mappings.
-
-An alternative @var{[linklabel]} form will map outputs from complex filter
-graphs (see the @option{-filter_complex} option) to the output file.
-@var{linklabel} must correspond to a defined output link label in the graph.
-
-For example, to map ALL streams from the first input file to output
-@example
-avconv -i INPUT -map 0 output
-@end example
-
-For example, if you have two audio streams in the first input file,
-these streams are identified by "0:0" and "0:1". You can use
-@code{-map} to select which streams to place in an output file. For
-example:
-@example
-avconv -i INPUT -map 0:1 out.wav
-@end example
-will map the input stream in @file{INPUT} identified by "0:1" to
-the (single) output stream in @file{out.wav}.
-
-For example, to select the stream with index 2 from input file
-@file{a.mov} (specified by the identifier "0:2"), and stream with
-index 6 from input @file{b.mov} (specified by the identifier "1:6"),
-and copy them to the output file @file{out.mov}:
-@example
-avconv -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
-@end example
-
-To select all video and the third audio stream from an input file:
-@example
-avconv -i INPUT -map 0:v -map 0:a:2 OUTPUT
-@end example
-
-To map all the streams except the second audio, use negative mappings
-@example
-avconv -i INPUT -map 0 -map -0:a:1 OUTPUT
-@end example
-
-To pick the English audio stream:
-@example
-avconv -i INPUT -map 0:m:language:eng OUTPUT
-@end example
-
-Note that using this option disables the default mappings for this output file.
-
-@item -map_metadata[:@var{metadata_spec_out}] @var{infile}[:@var{metadata_spec_in}] (@emph{output,per-metadata})
-Set metadata information of the next output file from @var{infile}. Note that
-those are file indices (zero-based), not filenames.
-Optional @var{metadata_spec_in/out} parameters specify, which metadata to copy.
-A metadata specifier can have the following forms:
-@table @option
-@item @var{g}
-global metadata, i.e. metadata that applies to the whole file
-
-@item @var{s}[:@var{stream_spec}]
-per-stream metadata. @var{stream_spec} is a stream specifier as described
-in the @ref{Stream specifiers} chapter. In an input metadata specifier, the first
-matching stream is copied from. In an output metadata specifier, all matching
-streams are copied to.
-
-@item @var{c}:@var{chapter_index}
-per-chapter metadata. @var{chapter_index} is the zero-based chapter index.
-
-@item @var{p}:@var{program_index}
-per-program metadata. @var{program_index} is the zero-based program index.
-@end table
-If metadata specifier is omitted, it defaults to global.
-
-By default, global metadata is copied from the first input file,
-per-stream and per-chapter metadata is copied along with streams/chapters. These
-default mappings are disabled by creating any mapping of the relevant type. A negative
-file index can be used to create a dummy mapping that just disables automatic copying.
-
-For example to copy metadata from the first stream of the input file to global metadata
-of the output file:
-@example
-avconv -i in.ogg -map_metadata 0:s:0 out.mp3
-@end example
-
-To do the reverse, i.e. copy global metadata to all audio streams:
-@example
-avconv -i in.mkv -map_metadata:s:a 0:g out.mkv
-@end example
-Note that simple @code{0} would work as well in this example, since global
-metadata is assumed by default.
-
-@item -map_chapters @var{input_file_index} (@emph{output})
-Copy chapters from input file with index @var{input_file_index} to the next
-output file. If no chapter mapping is specified, then chapters are copied from
-the first input file with at least one chapter. Use a negative file index to
-disable any chapter copying.
-@item -debug
-Print specific debug info.
-@item -benchmark (@emph{global})
-Show benchmarking information at the end of an encode.
-Shows CPU time used and maximum memory consumption.
-Maximum memory consumption is not supported on all systems,
-it will usually display as 0 if not supported.
-@item -timelimit @var{duration} (@emph{global})
-Exit after avconv has been running for @var{duration} seconds.
-@item -dump (@emph{global})
-Dump each input packet to stderr.
-@item -hex (@emph{global})
-When dumping packets, also dump the payload.
-@item -re (@emph{input})
-Read input at native frame rate. Mainly used to simulate a grab device
-or live input stream (e.g. when reading from a file). Should not be used
-with actual grab devices or live input streams (where it can cause packet
-loss).
-@item -vsync @var{parameter}
-Video sync method.
-
-@table @option
-@item passthrough
-Each frame is passed with its timestamp from the demuxer to the muxer.
-@item cfr
-Frames will be duplicated and dropped to achieve exactly the requested
-constant framerate.
-@item vfr
-Frames are passed through with their timestamp or dropped so as to
-prevent 2 frames from having the same timestamp.
-@item auto
-Chooses between 1 and 2 depending on muxer capabilities. This is the
-default method.
-@end table
-
-With -map you can select from which stream the timestamps should be
-taken. You can leave either video or audio unchanged and sync the
-remaining stream(s) to the unchanged one.
-
-@item -async @var{samples_per_second}
-Audio sync method. "Stretches/squeezes" the audio stream to match the timestamps,
-the parameter is the maximum samples per second by which the audio is changed.
--async 1 is a special case where only the start of the audio stream is corrected
-without any later correction.
-This option has been deprecated. Use the @code{asyncts} audio filter instead.
-@item -copyts
-Copy timestamps from input to output.
-@item -copytb
-Copy input stream time base from input to output when stream copying.
-@item -shortest (@emph{output})
-Finish encoding when the shortest input stream ends.
-@item -dts_delta_threshold
-Timestamp discontinuity delta threshold.
-@item -muxdelay @var{seconds} (@emph{input})
-Set the maximum demux-decode delay.
-@item -muxpreload @var{seconds} (@emph{input})
-Set the initial demux-decode delay.
-@item -streamid @var{output-stream-index}:@var{new-value} (@emph{output})
-Assign a new stream-id value to an output stream. This option should be
-specified prior to the output filename to which it applies.
-For the situation where multiple output files exist, a streamid
-may be reassigned to a different value.
-
-For example, to set the stream 0 PID to 33 and the stream 1 PID to 36 for
-an output mpegts file:
-@example
-avconv -i infile -streamid 0:33 -streamid 1:36 out.ts
-@end example
-
-@item -bsf[:@var{stream_specifier}] @var{bitstream_filters} (@emph{output,per-stream})
-Set bitstream filters for matching streams. @var{bistream_filters} is
-a comma-separated list of bitstream filters. Use the @code{-bsfs} option
-to get the list of bitstream filters.
-@example
-avconv -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
-@end example
-@example
-avconv -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
-@end example
-
-@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{input/output,per-stream})
-Force a tag/fourcc for matching streams.
-
-@item -filter_complex @var{filtergraph} (@emph{global})
-Define a complex filter graph, 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 filter graph, as described in @ref{Filtergraph syntax}.
-
-Input link labels must refer to input streams using 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. An unlabeled input will be connected to the first unused input stream of
-the matching type.
-
-Output link labels are referred to with @option{-map}. Unlabeled outputs are
-added to the first output file.
-
-Note that with this option it is possible to use only lavfi sources without
-normal input files.
-
-For example, to overlay an image over video
-@example
-avconv -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
-'[out]' out.mkv
-@end example
-Here @code{[0:v]} refers to the first video stream in the first input file,
-which is linked to the first (main) input of the overlay filter. Similarly the
-first video stream in the second input is linked to the second (overlay) input
-of overlay.
-
-Assuming there is only one video stream in each input file, we can omit input
-labels, so the above is equivalent to
-@example
-avconv -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
-'[out]' out.mkv
-@end example
-
-Furthermore we can omit the output label and the single output from the filter
-graph will be added to the output file automatically, so we can simply write
-@example
-avconv -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
-@end example
-
-To generate 5 seconds of pure red video using lavfi @code{color} source:
-@example
-avconv -filter_complex 'color=red' -t 5 out.mkv
-@end example
-
-@item -filter_complex_script @var{filename} (@emph{global})
-This option is similar to @option{-filter_complex}, the only difference is that
-its argument is the name of the file from which a complex filtergraph
-description is to be read.
-
-@item -accurate_seek (@emph{input})
-This option enables or disables accurate seeking in input files with the
-@option{-ss} option. It is enabled by default, so seeking is accurate when
-transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
-e.g. when copying some streams and transcoding the others.
-
-@end table
-@c man end OPTIONS
-
-@chapter Tips
-@c man begin TIPS
-
-@itemize
-@item
-For streaming at very low bitrate application, use a low frame rate
-and a small GOP size. This is especially true for RealVideo where
-the Linux player does not seem to be very fast, so it can miss
-frames. An example is:
-
-@example
-avconv -g 3 -r 3 -t 10 -b 50k -s qcif -f rv10 /tmp/b.rm
-@end example
-
-@item
-The parameter 'q' which is displayed while encoding is the current
-quantizer. The value 1 indicates that a very good quality could
-be achieved. The value 31 indicates the worst quality. If q=31 appears
-too often, it means that the encoder cannot compress enough to meet
-your bitrate. You must either increase the bitrate, decrease the
-frame rate or decrease the frame size.
-
-@item
-If your computer is not fast enough, you can speed up the
-compression at the expense of the compression ratio. You can use
-'-me zero' to speed up motion estimation, and '-g 0' to disable
-motion estimation completely (you have only I-frames, which means it
-is about as good as JPEG compression).
-
-@item
-To have very low audio bitrates, reduce the sampling frequency
-(down to 22050 Hz for MPEG audio, 22050 or 11025 for AC-3).
-
-@item
-To have a constant quality (but a variable bitrate), use the option
-'-qscale n' when 'n' is between 1 (excellent quality) and 31 (worst
-quality).
-
-@end itemize
-@c man end TIPS
-
-@chapter Examples
-@c man begin EXAMPLES
-
-@section Preset files
-
-A preset file contains a sequence of @var{option=value} pairs, one for
-each line, specifying a sequence of options which can be specified also on
-the command line. Lines starting with the hash ('#') character are ignored and
-are used to provide comments. Empty lines are also ignored. Check the
-@file{presets} directory in the Libav source tree for examples.
-
-Preset files are specified with the @code{pre} option, this option takes a
-preset name as input. Avconv searches for a file named @var{preset_name}.avpreset in
-the directories @file{$AVCONV_DATADIR} (if set), and @file{$HOME/.avconv}, and in
-the data directory defined at configuration time (usually @file{$PREFIX/share/avconv})
-in that order. For example, if the argument is @code{libx264-max}, it will
-search for the file @file{libx264-max.avpreset}.
-
-@section Video and Audio grabbing
-
-If you specify the input format and device then avconv can grab video
-and audio directly.
-
-@example
-avconv -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
-@end example
-
-Note that you must activate the right video source and channel before
-launching avconv with any TV viewer such as
-@uref{http://linux.bytesex.org/xawtv/, xawtv} by Gerd Knorr. You also
-have to set the audio recording levels correctly with a
-standard mixer.
-
-@section X11 grabbing
-
-Grab the X11 display with avconv via
-
-@example
-avconv -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
-@end example
-
-0.0 is display.screen number of your X11 server, same as
-the DISPLAY environment variable.
-
-@example
-avconv -f x11grab -s cif -r 25 -i :0.0+10,20 /tmp/out.mpg
-@end example
-
-0.0 is display.screen number of your X11 server, same as the DISPLAY environment
-variable. 10 is the x-offset and 20 the y-offset for the grabbing.
-
-@section Video and Audio file format conversion
-
-Any supported file format and protocol can serve as input to avconv:
-
-Examples:
-@itemize
-@item
-You can use YUV files as input:
-
-@example
-avconv -i /tmp/test%d.Y /tmp/out.mpg
-@end example
-
-It will use the files:
-@example
-/tmp/test0.Y, /tmp/test0.U, /tmp/test0.V,
-/tmp/test1.Y, /tmp/test1.U, /tmp/test1.V, etc...
-@end example
-
-The Y files use twice the resolution of the U and V files. They are
-raw files, without header. They can be generated by all decent video
-decoders. You must specify the size of the image with the @option{-s} option
-if avconv cannot guess it.
-
-@item
-You can input from a raw YUV420P file:
-
-@example
-avconv -i /tmp/test.yuv /tmp/out.avi
-@end example
-
-test.yuv is a file containing raw YUV planar data. Each frame is composed
-of the Y plane followed by the U and V planes at half vertical and
-horizontal resolution.
-
-@item
-You can output to a raw YUV420P file:
-
-@example
-avconv -i mydivx.avi hugefile.yuv
-@end example
-
-@item
-You can set several input files and output files:
-
-@example
-avconv -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
-@end example
-
-Converts the audio file a.wav and the raw YUV video file a.yuv
-to MPEG file a.mpg.
-
-@item
-You can also do audio and video conversions at the same time:
-
-@example
-avconv -i /tmp/a.wav -ar 22050 /tmp/a.mp2
-@end example
-
-Converts a.wav to MPEG audio at 22050 Hz sample rate.
-
-@item
-You can encode to several formats at the same time and define a
-mapping from input stream to output streams:
-
-@example
-avconv -i /tmp/a.wav -map 0:a -b 64k /tmp/a.mp2 -map 0:a -b 128k /tmp/b.mp2
-@end example
-
-Converts a.wav to a.mp2 at 64 kbits and to b.mp2 at 128 kbits. '-map
-file:index' specifies which input stream is used for each output
-stream, in the order of the definition of output streams.
-
-@item
-You can transcode decrypted VOBs:
-
-@example
-avconv -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
-@end example
-
-This is a typical DVD ripping example; the input is a VOB file, the
-output an AVI file with MPEG-4 video and MP3 audio. Note that in this
-command we use B-frames so the MPEG-4 stream is DivX5 compatible, and
-GOP size is 300 which means one intra frame every 10 seconds for 29.97fps
-input video. Furthermore, the audio stream is MP3-encoded so you need
-to enable LAME support by passing @code{--enable-libmp3lame} to configure.
-The mapping is particularly useful for DVD transcoding
-to get the desired audio language.
-
-NOTE: To see the supported input formats, use @code{avconv -formats}.
-
-@item
-You can extract images from a video, or create a video from many images:
-
-For extracting images from a video:
-@example
-avconv -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
-@end example
-
-This will extract one video frame per second from the video and will
-output them in files named @file{foo-001.jpeg}, @file{foo-002.jpeg},
-etc. Images will be rescaled to fit the new WxH values.
-
-If you want to extract just a limited number of frames, you can use the
-above command in combination with the -vframes or -t option, or in
-combination with -ss to start extracting from a certain point in time.
-
-For creating a video from many images:
-@example
-avconv -f image2 -i foo-%03d.jpeg -r 12 -s WxH foo.avi
-@end example
-
-The syntax @code{foo-%03d.jpeg} specifies to use a decimal number
-composed of three digits padded with zeroes to express the sequence
-number. It is the same syntax supported by the C printf function, but
-only formats accepting a normal integer are suitable.
-
-@item
-You can put many streams of the same type in the output:
-
-@example
-avconv -i test1.avi -i test2.avi -map 1:1 -map 1:0 -map 0:1 -map 0:0 -c copy -y test12.nut
-@end example
-
-The resulting output file @file{test12.nut} will contain the first four streams
-from the input files in reverse order.
-
-@item
-To force CBR video output:
-@example
-avconv -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
-@end example
-
-@item
-The four options lmin, lmax, mblmin and mblmax use 'lambda' units,
-but you may use the QP2LAMBDA constant to easily convert from 'q' units:
-@example
-avconv -i src.ext -lmax 21*QP2LAMBDA dst.ext
-@end example
-
-@end itemize
-@c man end EXAMPLES
-
-@include eval.texi
-@include decoders.texi
-@include encoders.texi
-@include demuxers.texi
-@include muxers.texi
-@include indevs.texi
-@include outdevs.texi
-@include protocols.texi
-@include bitstream_filters.texi
-@include filters.texi
-@include metadata.texi
-
-@ignore
-
-@setfilename avconv
-@settitle avconv video converter
-
-@c man begin SEEALSO
-avplay(1), avprobe(1) and the Libav HTML documentation
-@c man end
-
-@c man begin AUTHORS
-The Libav developers
-@c man end
-
-@end ignore
-
-@bye
diff --git a/doc/avplay.texi b/doc/avplay.texi
deleted file mode 100644
index d143f75201..0000000000
--- a/doc/avplay.texi
+++ /dev/null
@@ -1,186 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-
-@settitle avplay Documentation
-@titlepage
-@center @titlefont{avplay Documentation}
-@end titlepage
-
-@top
-
-@contents
-
-@chapter Synopsis
-
-@example
-@c man begin SYNOPSIS
-avplay [options] @file{input_file}
-@c man end
-@end example
-
-@chapter Description
-@c man begin DESCRIPTION
-
-AVplay is a very simple and portable media player using the Libav
-libraries and the SDL library. It is mostly used as a testbed for the
-various Libav APIs.
-@c man end
-
-@chapter Options
-@c man begin OPTIONS
-
-@include avtools-common-opts.texi
-
-@section Main options
-
-@table @option
-@item -x @var{width}
-Force displayed width.
-@item -y @var{height}
-Force displayed height.
-@item -s @var{size}
-This option has been removed. Use private format options for specifying the
-input video size. For example with the rawvideo demuxer you need to specify the
-option @var{video_size}.
-@item -an
-Disable audio.
-@item -vn
-Disable video.
-@item -ss @var{pos}
-Seek to a given position in seconds.
-@item -t @var{duration}
-play <duration> seconds of audio/video
-@item -bytes
-Seek by bytes.
-@item -nodisp
-Disable graphical display.
-@item -f @var{fmt}
-Force format.
-@item -window_title @var{title}
-Set window title (default is the input filename).
-@item -loop @var{number}
-Loops movie playback <number> times. 0 means forever.
-@item -vf @var{filter_graph}
-@var{filter_graph} is a description of the filter graph to apply to
-the input video.
-Use the option "-filters" to show all the available filters (including
-also sources and sinks).
-
-@end table
-
-@section Advanced options
-@table @option
-@item -pix_fmt @var{format}
-This option has been removed. Use private options for specifying the
-input pixel format. For example with the rawvideo demuxer you need to specify
-the option @var{pixel_format}.
-@item -stats
-Show the stream duration, the codec parameters, the current position in
-the stream and the audio/video synchronisation drift.
-@item -bug
-Work around bugs.
-@item -fast
-Non-spec-compliant optimizations.
-@item -genpts
-Generate pts.
-@item -rtp_tcp
-Force RTP/TCP protocol usage instead of RTP/UDP. It is only meaningful
-if you are streaming with the RTSP protocol.
-@item -sync @var{type}
-Set the master clock to audio (@code{type=audio}), video
-(@code{type=video}) or external (@code{type=ext}). Default is audio. The
-master clock is used to control audio-video synchronization. Most media
-players use audio as master clock, but in some cases (streaming or high
-quality broadcast) it is necessary to change that. This option is mainly
-used for debugging purposes.
-@item -threads @var{count}
-Set the thread count.
-@item -ast @var{audio_stream_number}
-Select the desired audio stream number, counting from 0. The number
-refers to the list of all the input audio streams. If it is greater
-than the number of audio streams minus one, then the last one is
-selected, if it is negative the audio playback is disabled.
-@item -vst @var{video_stream_number}
-Select the desired video stream number, counting from 0. The number
-refers to the list of all the input video streams. If it is greater
-than the number of video streams minus one, then the last one is
-selected, if it is negative the video playback is disabled.
-@item -sst @var{subtitle_stream_number}
-Select the desired subtitle stream number, counting from 0. The number
-refers to the list of all the input subtitle streams. If it is greater
-than the number of subtitle streams minus one, then the last one is
-selected, if it is negative the subtitle rendering is disabled.
-@item -noautoexit
-Do not exit after playback is finished.
-@item -exitonkeydown
-Exit if any key is pressed.
-@item -exitonmousedown
-Exit if any mouse button is pressed.
-@item -noautorotate
-Disable automatically rotating video based on file metadata.
-@end table
-
-@section While playing
-
-@table @key
-@item q, ESC
-Quit.
-
-@item f
-Toggle full screen.
-
-@item p, SPC
-Pause.
-
-@item a
-Cycle audio channel.
-
-@item v
-Cycle video channel.
-
-@item t
-Cycle subtitle channel.
-
-@item w
-Show audio waves.
-
-@item left/right
-Seek backward/forward 10 seconds.
-
-@item down/up
-Seek backward/forward 1 minute.
-
-@item PGDOWN/PGUP
-Seek to the previous/next chapter.
-
-@item mouse click
-Seek to percentage in file corresponding to fraction of width.
-
-@end table
-
-@c man end
-
-@include eval.texi
-@include decoders.texi
-@include demuxers.texi
-@include muxers.texi
-@include indevs.texi
-@include outdevs.texi
-@include protocols.texi
-@include filters.texi
-
-@ignore
-
-@setfilename avplay
-@settitle AVplay media player
-
-@c man begin SEEALSO
-avconv(1), avprobe(1) and the Libav HTML documentation
-@c man end
-
-@c man begin AUTHORS
-The Libav developers
-@c man end
-
-@end ignore
-
-@bye
diff --git a/doc/avprobe.texi b/doc/avprobe.texi
deleted file mode 100644
index 7e6fedf5c4..0000000000
--- a/doc/avprobe.texi
+++ /dev/null
@@ -1,141 +0,0 @@
-\input texinfo @c -*- texinfo -*-
-
-@settitle avprobe Documentation
-@titlepage
-@center @titlefont{avprobe Documentation}
-@end titlepage
-
-@top
-
-@contents
-
-@chapter Synopsis
-
-The generic syntax is:
-
-@example
-@c man begin SYNOPSIS
-avprobe [options] [@file{input_file}]
-@c man end
-@end example
-
-@chapter Description
-@c man begin DESCRIPTION
-
-avprobe gathers information from multimedia streams and prints it in
-human- and machine-readable fashion.
-
-For example it can be used to check the format of the container used
-by a multimedia stream and the format and type of each media stream
-contained in it.
-
-If a filename is specified in input, avprobe will try to open and
-probe the file content. If the file cannot be opened or recognized as
-a multimedia file, a positive exit code is returned.
-
-avprobe may be employed both as a standalone application or in
-combination with a textual filter, which may perform more
-sophisticated processing, e.g. statistical processing or plotting.
-
-Options are used to list some of the formats supported by avprobe or
-for specifying which information to display, and for setting how
-avprobe will show it.
-
-avprobe output is designed to be easily parsable by any INI or JSON
-parsers.
-
-@c man end
-
-@chapter Options
-@c man begin OPTIONS
-
-@include avtools-common-opts.texi
-
-@section Main options
-
-@table @option
-
-@item -f @var{format}
-Force format to use.
-
-@item -of @var{formatter}
-Use a specific formatter to output the document. The following
-formatters are available
-@table @option
-@item ini
-
-@item json
-
-@item old
-Pseudo-INI format that used to be the only one available in old
-avprobe versions.
-@end table
-
-@item -unit
-Show the unit of the displayed values.
-
-@item -prefix
-Use SI prefixes for the displayed values.
-Unless the "-byte_binary_prefix" option is used all the prefixes
-are decimal.
-
-@item -byte_binary_prefix
-Force the use of binary prefixes for byte values.
-
-@item -sexagesimal
-Use sexagesimal format HH:MM:SS.MICROSECONDS for time values.
-
-@item -pretty
-Prettify the format of the displayed values, it corresponds to the
-options "-unit -prefix -byte_binary_prefix -sexagesimal".
-
-@item -show_format
-Show information about the container format of the input multimedia
-stream.
-
-All the container format information is printed within a section with
-name "FORMAT".
-
-@item -show_format_entry @var{name}
-Like @option{-show_format}, but only prints the specified entry of the
-container format information, rather than all. This option may be given more
-than once, then all specified entries will be shown.
-
-@item -show_packets
-Show information about each packet contained in the input multimedia
-stream.
-
-The information for each single packet is printed within a dedicated
-section with name "PACKET".
-
-@item -show_streams
-Show information about each media stream contained in the input
-multimedia stream.
-
-Each media stream information is printed within a dedicated section
-with name "STREAM".
-
-@end table
-@c man end
-
-@include demuxers.texi
-@include muxers.texi
-@include protocols.texi
-@include indevs.texi
-
-@ignore
-
-@setfilename avprobe
-@settitle avprobe media prober
-
-@c man begin SEEALSO
-avconv(1), avplay(1) and the Libav HTML documentation
-@c man end
-
-@c man begin AUTHORS
-The Libav developers
-@c man end
-
-@end ignore
-
-@bye
diff --git a/doc/avtools-common-opts.texi b/doc/avtools-common-opts.texi
deleted file mode 100644
index 79f764b58c..0000000000
--- a/doc/avtools-common-opts.texi
+++ /dev/null
@@ -1,197 +0,0 @@
-All the numerical options, if not specified otherwise, accept in input
-a string representing a number, which may contain one of the
-SI unit prefixes, for example 'K', 'M', 'G'.
-If 'i' is appended after the prefix, binary prefixes are used,
-which are based on powers of 1024 instead of powers of 1000.
-The 'B' postfix multiplies the value by 8, and can be
-appended after a unit prefix or used alone. This allows using for
-example 'KB', 'MiB', 'G' and 'B' as number postfix.
-
-Options which do not take arguments are boolean options, and set the
-corresponding value to true. They can be set to false by prefixing
-with "no" the option name, for example using "-nofoo" in the
-command line will set to false the boolean option with name "foo".
-
-@anchor{Stream specifiers}
-@section Stream specifiers
-Some options are applied per-stream, e.g. bitrate or codec. Stream specifiers
-are used to precisely specify which stream(s) does a given option belong to.
-
-A stream specifier is a string generally appended to the option name and
-separated from it by a colon. E.g. @code{-codec:a:1 ac3} option contains
-@code{a:1} stream specifer, which matches the second audio stream. Therefore it
-would select the ac3 codec for the second audio stream.
-
-A stream specifier can match several stream, the option is then applied to all
-of them. E.g. the stream specifier in @code{-b:a 128k} matches all audio
-streams.
-
-An empty stream specifier matches all streams, for example @code{-codec copy}
-or @code{-codec: copy} would copy all the streams without reencoding.
-
-Possible forms of stream specifiers are:
-@table @option
-@item @var{stream_index}
-Matches the stream with this index. E.g. @code{-threads:1 4} would set the
-thread count for the second stream to 4.
-@item @var{stream_type}[:@var{stream_index}]
-@var{stream_type} is one of: 'v' for video, 'a' for audio, 's' for subtitle,
-'d' for data and 't' for attachments. If @var{stream_index} is given, then
-matches stream number @var{stream_index} of this type. Otherwise matches all
-streams of this type.
-@item p:@var{program_id}[:@var{stream_index}]
-If @var{stream_index} is given, then matches stream number @var{stream_index} in
-program with id @var{program_id}. Otherwise matches all streams in this program.
-@item i:@var{stream_id}
-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.
-@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.
-
-Note that in @command{avconv}, matching by metadata will only work properly for
-input files.
-@end table
-@section Generic options
-
-These options are shared amongst the av* tools.
-
-@table @option
-
-@item -L
-Show license.
-
-@item -h, -?, -help, --help [@var{arg}]
-Show help. An optional parameter may be specified to print help about a specific
-item.
-
-Possible values of @var{arg} are:
-@table @option
-@item decoder=@var{decoder_name}
-Print detailed information about the decoder named @var{decoder_name}. Use the
-@option{-decoders} option to get a list of all decoders.
-
-@item encoder=@var{encoder_name}
-Print detailed information about the encoder named @var{encoder_name}. Use the
-@option{-encoders} option to get a list of all encoders.
-
-@item demuxer=@var{demuxer_name}
-Print detailed information about the demuxer named @var{demuxer_name}. Use the
-@option{-formats} option to get a list of all demuxers and muxers.
-
-@item muxer=@var{muxer_name}
-Print detailed information about the muxer named @var{muxer_name}. Use the
-@option{-formats} option to get a list of all muxers and demuxers.
-
-@item filter=@var{filter_name}
-Print detailed information about the filter name @var{filter_name}. Use the
-@option{-filters} option to get a list of all filters.
-
-@end table
-
-@item -version
-Show version.
-
-@item -formats
-Show available formats.
-
-The fields preceding the format names have the following meanings:
-@table @samp
-@item D
-Decoding available
-@item E
-Encoding available
-@end table
-
-@item -codecs
-Show all codecs known to libavcodec.
-
-Note that the term 'codec' is used throughout this documentation as a shortcut
-for what is more correctly called a media bitstream format.
-
-@item -decoders
-Show available decoders.
-
-@item -encoders
-Show all available encoders.
-
-@item -bsfs
-Show available bitstream filters.
-
-@item -protocols
-Show available protocols.
-
-@item -filters
-Show available libavfilter filters.
-
-@item -pix_fmts
-Show available pixel formats.
-
-@item -sample_fmts
-Show available sample formats.
-
-@item -loglevel @var{loglevel} | -v @var{loglevel}
-Set the logging level used by the library.
-@var{loglevel} is a number or a string containing one of the following values:
-@table @samp
-@item quiet
-@item panic
-@item fatal
-@item error
-@item warning
-@item info
-@item verbose
-@item debug
-@item trace
-@end table
-
-By default the program logs to stderr, if coloring is supported by the
-terminal, colors are used to mark errors and warnings. Log coloring
-can be disabled setting the environment variable
-@env{AV_LOG_FORCE_NOCOLOR} or @env{NO_COLOR}, or can be forced setting
-the environment variable @env{AV_LOG_FORCE_COLOR}.
-The use of the environment variable @env{NO_COLOR} is deprecated and
-will be dropped in a following Libav version.
-
-@item -cpuflags mask (@emph{global})
-Set a mask that's applied to autodetected CPU flags. This option is intended
-for testing. Do not use it unless you know what you're doing.
-
-@end table
-
-@section AVOptions
-
-These options are provided directly by the libavformat, libavdevice and
-libavcodec libraries. To see the list of available AVOptions, use the
-@option{-help} option. They are separated into two categories:
-@table @option
-@item generic
-These options can be set for any container, codec or device. Generic options
-are listed under AVFormatContext options for containers/devices and under
-AVCodecContext options for codecs.
-@item private
-These options are specific to the given container, device or codec. Private
-options are listed under their corresponding containers/devices/codecs.
-@end table
-
-For example to write an ID3v2.3 header instead of a default ID3v2.4 to
-an MP3 file, use the @option{id3v2_version} private option of the MP3
-muxer:
-@example
-avconv -i input.flac -id3v2_version 3 out.mp3
-@end example
-
-All codec AVOptions are obviously per-stream, so the chapter on stream
-specifiers applies to them
-
-Note @option{-nooption} syntax cannot be used for boolean AVOptions,
-use @option{-option 0}/@option{-option 1}.
-
-Note2 old undocumented way of specifying per-stream AVOptions by prepending
-v/a/s to the options name is now obsolete and will be removed soon.
-
-@include avoptions_codec.texi
-@include avoptions_format.texi
diff --git a/doc/avutil.txt b/doc/avutil.txt
deleted file mode 100644
index 0847683d1d..0000000000
--- a/doc/avutil.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-AVUtil
-======
-libavutil is a small lightweight library of generally useful functions.
-It is not a library for code needed by both libavcodec and libavformat.
-
-
-Overview:
-=========
-adler32.c adler32 checksum
-aes.c AES encryption and decryption
-fifo.c resizeable first in first out buffer
-intfloat_readwrite.c portable reading and writing of floating point values
-log.c "printf" with context and level
-md5.c MD5 Message-Digest Algorithm
-rational.c code to perform exact calculations with rational numbers
-tree.c generic AVL tree
-crc.c generic CRC checksumming code
-integer.c 128bit integer math
-lls.c
-mathematics.c greatest common divisor, integer sqrt, integer log2, ...
-mem.c memory allocation routines with guaranteed alignment
-
-Headers:
-bswap.h big/little/native-endian conversion code
-x86_cpu.h a few useful macros for unifying x86-64 and x86-32 code
-avutil.h
-common.h
-intreadwrite.h reading and writing of unaligned big/little/native-endian integers
-
-
-Goals:
-======
-* Modular (few interdependencies and the possibility of disabling individual parts during ./configure)
-* Small (source and object)
-* Efficient (low CPU and memory usage)
-* Useful (avoid useless features almost no one needs)
diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi
index 6e7f8781ee..563049e281 100644
--- a/doc/bitstream_filters.texi
+++ b/doc/bitstream_filters.texi
@@ -1,7 +1,7 @@
@chapter Bitstream Filters
@c man begin BITSTREAM FILTERS
-When you configure your Libav build, all the supported bitstream
+When you configure your FFmpeg build, all the supported bitstream
filters are enabled by default. You can list all available ones using
the configure option @code{--list-bsfs}.
@@ -10,20 +10,91 @@ You can disable all the bitstream filters using the configure option
the option @code{--enable-bsf=BSF}, or you can disable a particular
bitstream filter using the option @code{--disable-bsf=BSF}.
-The option @code{-bsfs} of the av* tools will display the list of
+The option @code{-bsfs} of the ff* tools will display the list of
all the supported bitstream filters included in your build.
-Below is a description of the currently available bitstream filters.
+The ff* tools have a -bsf option applied per stream, taking a
+comma-separated list of filters, whose parameters follow the filter
+name after a '='.
+
+@example
+ffmpeg -i INPUT -c:v copy -bsf:v filter1[=opt1=str1/opt2=str2][,filter2] OUTPUT
+@end example
+
+Below is a description of the currently available bitstream filters,
+with their parameters, if any.
@section aac_adtstoasc
+Convert MPEG-2/4 AAC ADTS to MPEG-4 Audio Specific Configuration
+bitstream filter.
+
+This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4
+ADTS header and removes the ADTS header.
+
+This is required for example when copying an AAC stream from a raw
+ADTS AAC container to a FLV or a MOV/MP4 file.
+
@section chomp
-@section dump_extradata
+Remove zero padding at the end of a packet.
+
+@section dump_extra
+
+Add extradata to the beginning of the filtered packets.
+
+The additional argument specifies which packets should be filtered.
+It accepts the values:
+@table @samp
+@item a
+add extradata to all key packets, but only if @var{local_header} is
+set in the @option{flags2} codec context field
+
+@item k
+add extradata to all key packets
+
+@item e
+add extradata to all packets
+@end table
+
+If not specified it is assumed @samp{k}.
+
+For example the following @command{ffmpeg} command forces a global
+header (thus disabling individual packet headers) in the H.264 packets
+generated by the @code{libx264} encoder, but corrects them by adding
+the header stored in extradata to the key packets:
+@example
+ffmpeg -i INPUT -map 0 -flags:v +global_header -c:v libx264 -bsf:v dump_extra out.ts
+@end example
@section h264_mp4toannexb
-@section imx_dump_header
+Convert an H.264 bitstream from length prefixed mode to start code
+prefixed mode (as defined in the Annex B of the ITU-T H.264
+specification).
+
+This is required by some streaming formats, typically the MPEG-2
+transport stream format ("mpegts").
+
+For example to remux an MP4 file containing an H.264 stream to mpegts
+format with @command{ffmpeg}, you can use the command:
+
+@example
+ffmpeg -i INPUT.mp4 -codec copy -bsf:v h264_mp4toannexb OUTPUT.ts
+@end example
+
+@section imxdump
+
+Modifies the bitstream to fit in MOV and to be usable by the Final Cut
+Pro decoder. This filter only applies to the mpeg2video codec, and is
+likely not needed for Final Cut Pro 7 and newer with the appropriate
+@option{-tag:v}.
+
+For example, to remux 30 MB/sec NTSC IMX to MOV:
+
+@example
+ffmpeg -i input.mxf -c copy -bsf:v imxdump -tag:v mx3n output.mov
+@end example
@section mjpeg2jpeg
@@ -34,7 +105,7 @@ JPEG image. The individual frames can be extracted without loss,
e.g. by
@example
-avconv -i ../some_mjpeg.avi -c:v copy frames_%d.jpg
+ffmpeg -i ../some_mjpeg.avi -c:v copy frames_%d.jpg
@end example
Unfortunately, these chunks are incomplete JPEG images, because
@@ -57,21 +128,53 @@ stream (carrying the AVI1 header ID and lacking a DHT segment) to
produce fully qualified JPEG images.
@example
-avconv -i mjpeg-movie.avi -c:v copy -bsf:v mjpeg2jpeg frame_%d.jpg
+ffmpeg -i mjpeg-movie.avi -c:v copy -bsf:v mjpeg2jpeg frame_%d.jpg
exiftran -i -9 frame*.jpg
-avconv -i frame_%d.jpg -c:v copy rotated.avi
+ffmpeg -i frame_%d.jpg -c:v copy rotated.avi
@end example
@section mjpega_dump_header
@section movsub
-@section mp3_header_compress
-
@section mp3_header_decompress
+@section mpeg4_unpack_bframes
+
+Unpack DivX-style packed B-frames.
+
+DivX-style packed B-frames are not valid MPEG-4 and were only a
+workaround for the broken Video for Windows subsystem.
+They use more space, can cause minor AV sync issues, require more
+CPU power to decode (unless the player has some decoded picture queue
+to compensate the 2,0,2,0 frame per packet style) and cause
+trouble if copied into a standard container like mp4 or mpeg-ps/ts,
+because MPEG-4 decoders may not be able to decode them, since they are
+not valid MPEG-4.
+
+For example to fix an AVI file containing an MPEG-4 stream with
+DivX-style packed B-frames using @command{ffmpeg}, you can use the command:
+
+@example
+ffmpeg -i INPUT.avi -codec copy -bsf:v mpeg4_unpack_bframes OUTPUT.avi
+@end example
+
@section noise
-@section remove_extradata
+Damages the contents of packets without damaging the container. Can be
+used for fuzzing or testing error resilience/concealment.
+
+Parameters:
+A numeral string, whose value is related to how often output bytes will
+be modified. Therefore, values below or equal to 0 are forbidden, and
+the lower the more frequent bytes will be modified, with 1 meaning
+every byte is modified.
+
+@example
+ffmpeg -i INPUT -c copy -bsf noise[=1] output.mkv
+@end example
+applies the modification to every byte.
+
+@section remove_extra
@c man end BITSTREAM FILTERS
diff --git a/doc/bootstrap.min.css b/doc/bootstrap.min.css
new file mode 100644
index 0000000000..6f68017d58
--- /dev/null
+++ b/doc/bootstrap.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.2.0 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;width:100% \9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;width:100% \9;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143 \0}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-horizontal .form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg,.form-horizontal .form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{position:absolute;z-index:-1;filter:alpha(opacity=0);opacity:0}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#777}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#777}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#777}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{min-width:30px;color:#777;background-color:transparent;background-image:none;-webkit-box-shadow:none;box-shadow:none}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate3d(0,-25%,0);-o-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0)}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
diff --git a/doc/build_system.txt b/doc/build_system.txt
index c3dede7cde..20242b1353 100644
--- a/doc/build_system.txt
+++ b/doc/build_system.txt
@@ -1,4 +1,4 @@
-Libav currently uses a custom build system, this text attempts to document
+FFmpeg currently uses a custom build system, this text attempts to document
some of its obscure features and options.
Makefile variables:
@@ -7,18 +7,32 @@ V
Disable the default terse mode, the full command issued by make and its
output will be shown on the screen.
+DBG
+ Preprocess x86 external assembler files to a .dbg.asm file in the object
+ directory, which then gets compiled. Helps developping those assembler
+ files.
+
DESTDIR
Destination directory for the install targets, useful to prepare packages
- or install Libav in cross-environments.
+ or install FFmpeg in cross-environments.
Makefile targets:
all
Default target, builds all the libraries and the executables.
+fate
+ Run the fate test suite, note you must have installed it
+
+fate-list
+ Will list all fate/regression test targets
+
install
Install headers, libraries and programs.
+examples
+ Build all examples located in doc/examples.
+
libavformat/output-example
Build the libavformat basic example.
@@ -27,3 +41,21 @@ libavcodec/api-example
libswscale/swscale-test
Build the swscale self-test (useful also as example).
+
+config
+ Reconfigure the project with current configuration.
+
+
+Useful standard make commands:
+make -t <target>
+ Touch all files that otherwise would be build, this is useful to reduce
+ unneeded rebuilding when changing headers, but note you must force rebuilds
+ of files that actually need it by hand then.
+
+make -j<num>
+ rebuild with multiple jobs at the same time. Faster on multi processor systems
+
+make -k
+ continue build in case of errors, this is useful for the regression tests
+ sometimes but note it will still not run all reg tests.
+
diff --git a/doc/codecs.texi b/doc/codecs.texi
new file mode 100644
index 0000000000..3c035a5ecb
--- /dev/null
+++ b/doc/codecs.texi
@@ -0,0 +1,1151 @@
+@anchor{codec-options}
+@chapter Codec Options
+@c man begin CODEC OPTIONS
+
+libavcodec provides some generic global options, which can be set on
+all the encoders and decoders. In addition each codec may support
+so-called private options, which are specific for a given codec.
+
+Sometimes, a global option may only affect a specific kind of codec,
+and may be nonsensical or ignored by another, so you need to be aware
+of the meaning of the specified options. Also some options are
+meant only for decoding or encoding.
+
+Options may be set by specifying -@var{option} @var{value} in the
+FFmpeg tools, or by setting the value explicitly in the
+@code{AVCodecContext} options or using the @file{libavutil/opt.h} API
+for programmatic use.
+
+The list of supported options follow:
+
+@table @option
+@item b @var{integer} (@emph{encoding,audio,video})
+Set bitrate in bits/s. Default value is 200K.
+
+@item ab @var{integer} (@emph{encoding,audio})
+Set audio bitrate (in bits/s). Default value is 128K.
+
+@item bt @var{integer} (@emph{encoding,video})
+Set video bitrate tolerance (in bits/s). In 1-pass mode, bitrate
+tolerance specifies how far ratecontrol is willing to deviate from the
+target average bitrate value. This is not related to min/max
+bitrate. Lowering tolerance too much has an adverse effect on quality.
+
+@item flags @var{flags} (@emph{decoding/encoding,audio,video,subtitles})
+Set generic flags.
+
+Possible values:
+@table @samp
+@item mv4
+Use four motion vector by macroblock (mpeg4).
+@item qpel
+Use 1/4 pel motion compensation.
+@item loop
+Use loop filter.
+@item qscale
+Use fixed qscale.
+@item gmc
+Use gmc.
+@item mv0
+Always try a mb with mv=<0,0>.
+@item input_preserved
+
+@item pass1
+Use internal 2pass ratecontrol in first pass mode.
+@item pass2
+Use internal 2pass ratecontrol in second pass mode.
+@item gray
+Only decode/encode grayscale.
+@item emu_edge
+Do not draw edges.
+@item psnr
+Set error[?] variables during encoding.
+@item truncated
+
+@item naq
+Normalize adaptive quantization.
+@item ildct
+Use interlaced DCT.
+@item low_delay
+Force low delay.
+@item global_header
+Place global headers in extradata instead of every keyframe.
+@item bitexact
+Only write platform-, build- and time-independent data. (except (I)DCT).
+This ensures that file and data checksums are reproducible and match between
+platforms. Its primary use is for regression testing.
+@item aic
+Apply H263 advanced intra coding / mpeg4 ac prediction.
+@item cbp
+Deprecated, use mpegvideo private options instead.
+@item qprd
+Deprecated, use mpegvideo private options instead.
+@item ilme
+Apply interlaced motion estimation.
+@item cgop
+Use closed gop.
+@end table
+
+@item me_method @var{integer} (@emph{encoding,video})
+Set motion estimation method.
+
+Possible values:
+@table @samp
+@item zero
+zero motion estimation (fastest)
+@item full
+full motion estimation (slowest)
+@item epzs
+EPZS motion estimation (default)
+@item esa
+esa motion estimation (alias for full)
+@item tesa
+tesa motion estimation
+@item dia
+dia motion estimation (alias for epzs)
+@item log
+log motion estimation
+@item phods
+phods motion estimation
+@item x1
+X1 motion estimation
+@item hex
+hex motion estimation
+@item umh
+umh motion estimation
+@item iter
+iter motion estimation
+@end table
+
+@item extradata_size @var{integer}
+Set extradata size.
+
+@item time_base @var{rational number}
+Set codec time base.
+
+It is the fundamental unit of time (in seconds) in terms of which
+frame timestamps are represented. For fixed-fps content, timebase
+should be @code{1 / frame_rate} and timestamp increments should be
+identically 1.
+
+@item g @var{integer} (@emph{encoding,video})
+Set the group of picture size. Default value is 12.
+
+@item ar @var{integer} (@emph{decoding/encoding,audio})
+Set audio sampling rate (in Hz).
+
+@item ac @var{integer} (@emph{decoding/encoding,audio})
+Set number of audio channels.
+
+@item cutoff @var{integer} (@emph{encoding,audio})
+Set cutoff bandwidth.
+
+@item frame_size @var{integer} (@emph{encoding,audio})
+Set audio frame size.
+
+Each submitted frame except the last must contain exactly frame_size
+samples per channel. May be 0 when the codec has
+CODEC_CAP_VARIABLE_FRAME_SIZE set, in that case the frame size is not
+restricted. It is set by some decoders to indicate constant frame
+size.
+
+@item frame_number @var{integer}
+Set the frame number.
+
+@item delay @var{integer}
+
+@item qcomp @var{float} (@emph{encoding,video})
+Set video quantizer scale compression (VBR). It is used as a constant
+in the ratecontrol equation. Recommended range for default rc_eq:
+0.0-1.0.
+
+@item qblur @var{float} (@emph{encoding,video})
+Set video quantizer scale blur (VBR).
+
+@item qmin @var{integer} (@emph{encoding,video})
+Set min video quantizer scale (VBR). Must be included between -1 and
+69, default value is 2.
+
+@item qmax @var{integer} (@emph{encoding,video})
+Set max video quantizer scale (VBR). Must be included between -1 and
+1024, default value is 31.
+
+@item qdiff @var{integer} (@emph{encoding,video})
+Set max difference between the quantizer scale (VBR).
+
+@item bf @var{integer} (@emph{encoding,video})
+Set max number of B frames between non-B-frames.
+
+Must be an integer between -1 and 16. 0 means that B-frames are
+disabled. If a value of -1 is used, it will choose an automatic value
+depending on the encoder.
+
+Default value is 0.
+
+@item b_qfactor @var{float} (@emph{encoding,video})
+Set qp factor between P and B frames.
+
+@item rc_strategy @var{integer} (@emph{encoding,video})
+Set ratecontrol method.
+
+@item b_strategy @var{integer} (@emph{encoding,video})
+Set strategy to choose between I/P/B-frames.
+
+@item ps @var{integer} (@emph{encoding,video})
+Set RTP payload size in bytes.
+
+@item mv_bits @var{integer}
+@item header_bits @var{integer}
+@item i_tex_bits @var{integer}
+@item p_tex_bits @var{integer}
+@item i_count @var{integer}
+@item p_count @var{integer}
+@item skip_count @var{integer}
+@item misc_bits @var{integer}
+@item frame_bits @var{integer}
+@item codec_tag @var{integer}
+@item bug @var{flags} (@emph{decoding,video})
+Workaround not auto detected encoder bugs.
+
+Possible values:
+@table @samp
+@item autodetect
+
+@item old_msmpeg4
+some old lavc generated msmpeg4v3 files (no autodetection)
+@item xvid_ilace
+Xvid interlacing bug (autodetected if fourcc==XVIX)
+@item ump4
+(autodetected if fourcc==UMP4)
+@item no_padding
+padding bug (autodetected)
+@item amv
+
+@item ac_vlc
+illegal vlc bug (autodetected per fourcc)
+@item qpel_chroma
+
+@item std_qpel
+old standard qpel (autodetected per fourcc/version)
+@item qpel_chroma2
+
+@item direct_blocksize
+direct-qpel-blocksize bug (autodetected per fourcc/version)
+@item edge
+edge padding bug (autodetected per fourcc/version)
+@item hpel_chroma
+
+@item dc_clip
+
+@item ms
+Workaround various bugs in microsoft broken decoders.
+@item trunc
+trancated frames
+@end table
+
+@item lelim @var{integer} (@emph{encoding,video})
+Set single coefficient elimination threshold for luminance (negative
+values also consider DC coefficient).
+
+@item celim @var{integer} (@emph{encoding,video})
+Set single coefficient elimination threshold for chrominance (negative
+values also consider dc coefficient)
+
+@item strict @var{integer} (@emph{decoding/encoding,audio,video})
+Specify how strictly to follow the standards.
+
+Possible values:
+@table @samp
+@item very
+strictly conform to a older more strict version of the spec or reference software
+@item strict
+strictly conform to all the things in the spec no matter what consequences
+@item normal
+
+@item unofficial
+allow unofficial extensions
+@item experimental
+allow non standardized experimental things, experimental
+(unfinished/work in progress/not well tested) decoders and encoders.
+Note: experimental decoders can pose a security risk, do not use this for
+decoding untrusted input.
+@end table
+
+@item b_qoffset @var{float} (@emph{encoding,video})
+Set QP offset between P and B frames.
+
+@item err_detect @var{flags} (@emph{decoding,audio,video})
+Set error detection flags.
+
+Possible values:
+@table @samp
+@item crccheck
+verify embedded CRCs
+@item bitstream
+detect bitstream specification deviations
+@item buffer
+detect improper bitstream length
+@item explode
+abort decoding on minor error detection
+@item ignore_err
+ignore decoding errors, and continue decoding.
+This is useful if you want to analyze the content of a video and thus want
+everything to be decoded no matter what. This option will not result in a video
+that is pleasing to watch in case of errors.
+@item careful
+consider things that violate the spec and have not been seen in the wild as errors
+@item compliant
+consider all spec non compliancies as errors
+@item aggressive
+consider things that a sane encoder should not do as an error
+@end table
+
+@item has_b_frames @var{integer}
+
+@item block_align @var{integer}
+
+@item mpeg_quant @var{integer} (@emph{encoding,video})
+Use MPEG quantizers instead of H.263.
+
+@item qsquish @var{float} (@emph{encoding,video})
+How to keep quantizer between qmin and qmax (0 = clip, 1 = use
+differentiable function).
+
+@item rc_qmod_amp @var{float} (@emph{encoding,video})
+Set experimental quantizer modulation.
+
+@item rc_qmod_freq @var{integer} (@emph{encoding,video})
+Set experimental quantizer modulation.
+
+@item rc_override_count @var{integer}
+
+@item rc_eq @var{string} (@emph{encoding,video})
+Set rate control equation. When computing the expression, besides the
+standard functions defined in the section 'Expression Evaluation', the
+following functions are available: bits2qp(bits), qp2bits(qp). Also
+the following constants are available: iTex pTex tex mv fCode iCount
+mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex
+avgTex.
+
+@item maxrate @var{integer} (@emph{encoding,audio,video})
+Set max bitrate tolerance (in bits/s). Requires bufsize to be set.
+
+@item minrate @var{integer} (@emph{encoding,audio,video})
+Set min bitrate tolerance (in bits/s). Most useful in setting up a CBR
+encode. It is of little use elsewise.
+
+@item bufsize @var{integer} (@emph{encoding,audio,video})
+Set ratecontrol buffer size (in bits).
+
+@item rc_buf_aggressivity @var{float} (@emph{encoding,video})
+Currently useless.
+
+@item i_qfactor @var{float} (@emph{encoding,video})
+Set QP factor between P and I frames.
+
+@item i_qoffset @var{float} (@emph{encoding,video})
+Set QP offset between P and I frames.
+
+@item rc_init_cplx @var{float} (@emph{encoding,video})
+Set initial complexity for 1-pass encoding.
+
+@item dct @var{integer} (@emph{encoding,video})
+Set DCT algorithm.
+
+Possible values:
+@table @samp
+@item auto
+autoselect a good one (default)
+@item fastint
+fast integer
+@item int
+accurate integer
+@item mmx
+
+@item altivec
+
+@item faan
+floating point AAN DCT
+@end table
+
+@item lumi_mask @var{float} (@emph{encoding,video})
+Compress bright areas stronger than medium ones.
+
+@item tcplx_mask @var{float} (@emph{encoding,video})
+Set temporal complexity masking.
+
+@item scplx_mask @var{float} (@emph{encoding,video})
+Set spatial complexity masking.
+
+@item p_mask @var{float} (@emph{encoding,video})
+Set inter masking.
+
+@item dark_mask @var{float} (@emph{encoding,video})
+Compress dark areas stronger than medium ones.
+
+@item idct @var{integer} (@emph{decoding/encoding,video})
+Select IDCT implementation.
+
+Possible values:
+@table @samp
+@item auto
+
+@item int
+
+@item simple
+
+@item simplemmx
+
+@item simpleauto
+Automatically pick a IDCT compatible with the simple one
+
+@item arm
+
+@item altivec
+
+@item sh4
+
+@item simplearm
+
+@item simplearmv5te
+
+@item simplearmv6
+
+@item simpleneon
+
+@item simplealpha
+
+@item ipp
+
+@item xvidmmx
+
+@item faani
+floating point AAN IDCT
+@end table
+
+@item slice_count @var{integer}
+
+@item ec @var{flags} (@emph{decoding,video})
+Set error concealment strategy.
+
+Possible values:
+@table @samp
+@item guess_mvs
+iterative motion vector (MV) search (slow)
+@item deblock
+use strong deblock filter for damaged MBs
+@item favor_inter
+favor predicting from the previous frame instead of the current
+@end table
+
+@item bits_per_coded_sample @var{integer}
+
+@item pred @var{integer} (@emph{encoding,video})
+Set prediction method.
+
+Possible values:
+@table @samp
+@item left
+
+@item plane
+
+@item median
+
+@end table
+
+@item aspect @var{rational number} (@emph{encoding,video})
+Set sample aspect ratio.
+
+@item debug @var{flags} (@emph{decoding/encoding,audio,video,subtitles})
+Print specific debug info.
+
+Possible values:
+@table @samp
+@item pict
+picture info
+@item rc
+rate control
+@item bitstream
+
+@item mb_type
+macroblock (MB) type
+@item qp
+per-block quantization parameter (QP)
+@item mv
+motion vector
+@item dct_coeff
+
+@item skip
+
+@item startcode
+
+@item pts
+
+@item er
+error recognition
+@item mmco
+memory management control operations (H.264)
+@item bugs
+
+@item vis_qp
+visualize quantization parameter (QP), lower QP are tinted greener
+@item vis_mb_type
+visualize block types
+@item buffers
+picture buffer allocations
+@item thread_ops
+threading operations
+@item nomc
+skip motion compensation
+@end table
+
+@item vismv @var{integer} (@emph{decoding,video})
+Visualize motion vectors (MVs).
+
+This option is deprecated, see the codecview filter instead.
+
+Possible values:
+@table @samp
+@item pf
+forward predicted MVs of P-frames
+@item bf
+forward predicted MVs of B-frames
+@item bb
+backward predicted MVs of B-frames
+@end table
+
+@item cmp @var{integer} (@emph{encoding,video})
+Set full pel me compare function.
+
+Possible values:
+@table @samp
+@item sad
+sum of absolute differences, fast (default)
+@item sse
+sum of squared errors
+@item satd
+sum of absolute Hadamard transformed differences
+@item dct
+sum of absolute DCT transformed differences
+@item psnr
+sum of squared quantization errors (avoid, low quality)
+@item bit
+number of bits needed for the block
+@item rd
+rate distortion optimal, slow
+@item zero
+0
+@item vsad
+sum of absolute vertical differences
+@item vsse
+sum of squared vertical differences
+@item nsse
+noise preserving sum of squared differences
+@item w53
+5/3 wavelet, only used in snow
+@item w97
+9/7 wavelet, only used in snow
+@item dctmax
+
+@item chroma
+
+@end table
+
+@item subcmp @var{integer} (@emph{encoding,video})
+Set sub pel me compare function.
+
+Possible values:
+@table @samp
+@item sad
+sum of absolute differences, fast (default)
+@item sse
+sum of squared errors
+@item satd
+sum of absolute Hadamard transformed differences
+@item dct
+sum of absolute DCT transformed differences
+@item psnr
+sum of squared quantization errors (avoid, low quality)
+@item bit
+number of bits needed for the block
+@item rd
+rate distortion optimal, slow
+@item zero
+0
+@item vsad
+sum of absolute vertical differences
+@item vsse
+sum of squared vertical differences
+@item nsse
+noise preserving sum of squared differences
+@item w53
+5/3 wavelet, only used in snow
+@item w97
+9/7 wavelet, only used in snow
+@item dctmax
+
+@item chroma
+
+@end table
+
+@item mbcmp @var{integer} (@emph{encoding,video})
+Set macroblock compare function.
+
+Possible values:
+@table @samp
+@item sad
+sum of absolute differences, fast (default)
+@item sse
+sum of squared errors
+@item satd
+sum of absolute Hadamard transformed differences
+@item dct
+sum of absolute DCT transformed differences
+@item psnr
+sum of squared quantization errors (avoid, low quality)
+@item bit
+number of bits needed for the block
+@item rd
+rate distortion optimal, slow
+@item zero
+0
+@item vsad
+sum of absolute vertical differences
+@item vsse
+sum of squared vertical differences
+@item nsse
+noise preserving sum of squared differences
+@item w53
+5/3 wavelet, only used in snow
+@item w97
+9/7 wavelet, only used in snow
+@item dctmax
+
+@item chroma
+
+@end table
+
+@item ildctcmp @var{integer} (@emph{encoding,video})
+Set interlaced dct compare function.
+
+Possible values:
+@table @samp
+@item sad
+sum of absolute differences, fast (default)
+@item sse
+sum of squared errors
+@item satd
+sum of absolute Hadamard transformed differences
+@item dct
+sum of absolute DCT transformed differences
+@item psnr
+sum of squared quantization errors (avoid, low quality)
+@item bit
+number of bits needed for the block
+@item rd
+rate distortion optimal, slow
+@item zero
+0
+@item vsad
+sum of absolute vertical differences
+@item vsse
+sum of squared vertical differences
+@item nsse
+noise preserving sum of squared differences
+@item w53
+5/3 wavelet, only used in snow
+@item w97
+9/7 wavelet, only used in snow
+@item dctmax
+
+@item chroma
+
+@end table
+
+@item dia_size @var{integer} (@emph{encoding,video})
+Set diamond type & size for motion estimation.
+
+@item last_pred @var{integer} (@emph{encoding,video})
+Set amount of motion predictors from the previous frame.
+
+@item preme @var{integer} (@emph{encoding,video})
+Set pre motion estimation.
+
+@item precmp @var{integer} (@emph{encoding,video})
+Set pre motion estimation compare function.
+
+Possible values:
+@table @samp
+@item sad
+sum of absolute differences, fast (default)
+@item sse
+sum of squared errors
+@item satd
+sum of absolute Hadamard transformed differences
+@item dct
+sum of absolute DCT transformed differences
+@item psnr
+sum of squared quantization errors (avoid, low quality)
+@item bit
+number of bits needed for the block
+@item rd
+rate distortion optimal, slow
+@item zero
+0
+@item vsad
+sum of absolute vertical differences
+@item vsse
+sum of squared vertical differences
+@item nsse
+noise preserving sum of squared differences
+@item w53
+5/3 wavelet, only used in snow
+@item w97
+9/7 wavelet, only used in snow
+@item dctmax
+
+@item chroma
+
+@end table
+
+@item pre_dia_size @var{integer} (@emph{encoding,video})
+Set diamond type & size for motion estimation pre-pass.
+
+@item subq @var{integer} (@emph{encoding,video})
+Set sub pel motion estimation quality.
+
+@item dtg_active_format @var{integer}
+
+@item me_range @var{integer} (@emph{encoding,video})
+Set limit motion vectors range (1023 for DivX player).
+
+@item ibias @var{integer} (@emph{encoding,video})
+Set intra quant bias.
+
+@item pbias @var{integer} (@emph{encoding,video})
+Set inter quant bias.
+
+@item color_table_id @var{integer}
+
+@item global_quality @var{integer} (@emph{encoding,audio,video})
+
+@item coder @var{integer} (@emph{encoding,video})
+
+Possible values:
+@table @samp
+@item vlc
+variable length coder / huffman coder
+@item ac
+arithmetic coder
+@item raw
+raw (no encoding)
+@item rle
+run-length coder
+@item deflate
+deflate-based coder
+@end table
+
+@item context @var{integer} (@emph{encoding,video})
+Set context model.
+
+@item slice_flags @var{integer}
+
+@item xvmc_acceleration @var{integer}
+
+@item mbd @var{integer} (@emph{encoding,video})
+Set macroblock decision algorithm (high quality mode).
+
+Possible values:
+@table @samp
+@item simple
+use mbcmp (default)
+@item bits
+use fewest bits
+@item rd
+use best rate distortion
+@end table
+
+@item stream_codec_tag @var{integer}
+
+@item sc_threshold @var{integer} (@emph{encoding,video})
+Set scene change threshold.
+
+@item lmin @var{integer} (@emph{encoding,video})
+Set min lagrange factor (VBR).
+
+@item lmax @var{integer} (@emph{encoding,video})
+Set max lagrange factor (VBR).
+
+@item nr @var{integer} (@emph{encoding,video})
+Set noise reduction.
+
+@item rc_init_occupancy @var{integer} (@emph{encoding,video})
+Set number of bits which should be loaded into the rc buffer before
+decoding starts.
+
+@item flags2 @var{flags} (@emph{decoding/encoding,audio,video})
+
+Possible values:
+@table @samp
+@item fast
+Allow non spec compliant speedup tricks.
+@item sgop
+Deprecated, use mpegvideo private options instead.
+@item noout
+Skip bitstream encoding.
+@item ignorecrop
+Ignore cropping information from sps.
+@item local_header
+Place global headers at every keyframe instead of in extradata.
+@item chunks
+Frame data might be split into multiple chunks.
+@item showall
+Show all frames before the first keyframe.
+@item skiprd
+Deprecated, use mpegvideo private options instead.
+@item export_mvs
+Export motion vectors into frame side-data (see @code{AV_FRAME_DATA_MOTION_VECTORS})
+for codecs that support it. See also @file{doc/examples/export_mvs.c}.
+@end table
+
+@item error @var{integer} (@emph{encoding,video})
+
+@item qns @var{integer} (@emph{encoding,video})
+Deprecated, use mpegvideo private options instead.
+
+@item threads @var{integer} (@emph{decoding/encoding,video})
+
+Possible values:
+@table @samp
+@item auto
+detect a good number of threads
+@end table
+
+@item me_threshold @var{integer} (@emph{encoding,video})
+Set motion estimation threshold.
+
+@item mb_threshold @var{integer} (@emph{encoding,video})
+Set macroblock threshold.
+
+@item dc @var{integer} (@emph{encoding,video})
+Set intra_dc_precision.
+
+@item nssew @var{integer} (@emph{encoding,video})
+Set nsse weight.
+
+@item skip_top @var{integer} (@emph{decoding,video})
+Set number of macroblock rows at the top which are skipped.
+
+@item skip_bottom @var{integer} (@emph{decoding,video})
+Set number of macroblock rows at the bottom which are skipped.
+
+@item profile @var{integer} (@emph{encoding,audio,video})
+
+Possible values:
+@table @samp
+@item unknown
+
+@item aac_main
+
+@item aac_low
+
+@item aac_ssr
+
+@item aac_ltp
+
+@item aac_he
+
+@item aac_he_v2
+
+@item aac_ld
+
+@item aac_eld
+
+@item mpeg2_aac_low
+
+@item mpeg2_aac_he
+
+@item mpeg4_sp
+
+@item mpeg4_core
+
+@item mpeg4_main
+
+@item mpeg4_asp
+
+@item dts
+
+@item dts_es
+
+@item dts_96_24
+
+@item dts_hd_hra
+
+@item dts_hd_ma
+
+@end table
+
+@item level @var{integer} (@emph{encoding,audio,video})
+
+Possible values:
+@table @samp
+@item unknown
+
+@end table
+
+@item lowres @var{integer} (@emph{decoding,audio,video})
+Decode at 1= 1/2, 2=1/4, 3=1/8 resolutions.
+
+@item skip_threshold @var{integer} (@emph{encoding,video})
+Set frame skip threshold.
+
+@item skip_factor @var{integer} (@emph{encoding,video})
+Set frame skip factor.
+
+@item skip_exp @var{integer} (@emph{encoding,video})
+Set frame skip exponent.
+Negative values behave identical to the corresponding positive ones, except
+that the score is normalized.
+Positive values exist primarily for compatibility reasons and are not so useful.
+
+@item skipcmp @var{integer} (@emph{encoding,video})
+Set frame skip compare function.
+
+Possible values:
+@table @samp
+@item sad
+sum of absolute differences, fast (default)
+@item sse
+sum of squared errors
+@item satd
+sum of absolute Hadamard transformed differences
+@item dct
+sum of absolute DCT transformed differences
+@item psnr
+sum of squared quantization errors (avoid, low quality)
+@item bit
+number of bits needed for the block
+@item rd
+rate distortion optimal, slow
+@item zero
+0
+@item vsad
+sum of absolute vertical differences
+@item vsse
+sum of squared vertical differences
+@item nsse
+noise preserving sum of squared differences
+@item w53
+5/3 wavelet, only used in snow
+@item w97
+9/7 wavelet, only used in snow
+@item dctmax
+
+@item chroma
+
+@end table
+
+@item border_mask @var{float} (@emph{encoding,video})
+Increase the quantizer for macroblocks close to borders.
+
+@item mblmin @var{integer} (@emph{encoding,video})
+Set min macroblock lagrange factor (VBR).
+
+@item mblmax @var{integer} (@emph{encoding,video})
+Set max macroblock lagrange factor (VBR).
+
+@item mepc @var{integer} (@emph{encoding,video})
+Set motion estimation bitrate penalty compensation (1.0 = 256).
+
+@item skip_loop_filter @var{integer} (@emph{decoding,video})
+@item skip_idct @var{integer} (@emph{decoding,video})
+@item skip_frame @var{integer} (@emph{decoding,video})
+
+Make decoder discard processing depending on the frame type selected
+by the option value.
+
+@option{skip_loop_filter} skips frame loop filtering, @option{skip_idct}
+skips frame IDCT/dequantization, @option{skip_frame} skips decoding.
+
+Possible values:
+@table @samp
+@item none
+Discard no frame.
+
+@item default
+Discard useless frames like 0-sized frames.
+
+@item noref
+Discard all non-reference frames.
+
+@item bidir
+Discard all bidirectional frames.
+
+@item nokey
+Discard all frames excepts keyframes.
+
+@item all
+Discard all frames.
+@end table
+
+Default value is @samp{default}.
+
+@item bidir_refine @var{integer} (@emph{encoding,video})
+Refine the two motion vectors used in bidirectional macroblocks.
+
+@item brd_scale @var{integer} (@emph{encoding,video})
+Downscale frames for dynamic B-frame decision.
+
+@item keyint_min @var{integer} (@emph{encoding,video})
+Set minimum interval between IDR-frames.
+
+@item refs @var{integer} (@emph{encoding,video})
+Set reference frames to consider for motion compensation.
+
+@item chromaoffset @var{integer} (@emph{encoding,video})
+Set chroma qp offset from luma.
+
+@item trellis @var{integer} (@emph{encoding,audio,video})
+Set rate-distortion optimal quantization.
+
+@item sc_factor @var{integer} (@emph{encoding,video})
+Set value multiplied by qscale for each frame and added to
+scene_change_score.
+
+@item mv0_threshold @var{integer} (@emph{encoding,video})
+@item b_sensitivity @var{integer} (@emph{encoding,video})
+Adjust sensitivity of b_frame_strategy 1.
+
+@item compression_level @var{integer} (@emph{encoding,audio,video})
+@item min_prediction_order @var{integer} (@emph{encoding,audio})
+@item max_prediction_order @var{integer} (@emph{encoding,audio})
+@item timecode_frame_start @var{integer} (@emph{encoding,video})
+Set GOP timecode frame start number, in non drop frame format.
+
+@item request_channels @var{integer} (@emph{decoding,audio})
+Set desired number of audio channels.
+
+@item bits_per_raw_sample @var{integer}
+@item channel_layout @var{integer} (@emph{decoding/encoding,audio})
+
+Possible values:
+@table @samp
+@end table
+@item request_channel_layout @var{integer} (@emph{decoding,audio})
+
+Possible values:
+@table @samp
+@end table
+@item rc_max_vbv_use @var{float} (@emph{encoding,video})
+@item rc_min_vbv_use @var{float} (@emph{encoding,video})
+@item ticks_per_frame @var{integer} (@emph{decoding/encoding,audio,video})
+@item color_primaries @var{integer} (@emph{decoding/encoding,video})
+@item color_trc @var{integer} (@emph{decoding/encoding,video})
+@item colorspace @var{integer} (@emph{decoding/encoding,video})
+@item color_range @var{integer} (@emph{decoding/encoding,video})
+@item chroma_sample_location @var{integer} (@emph{decoding/encoding,video})
+
+@item log_level_offset @var{integer}
+Set the log level offset.
+
+@item slices @var{integer} (@emph{encoding,video})
+Number of slices, used in parallelized encoding.
+
+@item thread_type @var{flags} (@emph{decoding/encoding,video})
+Select which multithreading methods to use.
+
+Use of @samp{frame} will increase decoding delay by one frame per
+thread, so clients which cannot provide future frames should not use
+it.
+
+Possible values:
+@table @samp
+@item slice
+Decode more than one part of a single frame at once.
+
+Multithreading using slices works only when the video was encoded with
+slices.
+
+@item frame
+Decode more than one frame at once.
+@end table
+
+Default value is @samp{slice+frame}.
+
+@item audio_service_type @var{integer} (@emph{encoding,audio})
+Set audio service type.
+
+Possible values:
+@table @samp
+@item ma
+Main Audio Service
+@item ef
+Effects
+@item vi
+Visually Impaired
+@item hi
+Hearing Impaired
+@item di
+Dialogue
+@item co
+Commentary
+@item em
+Emergency
+@item vo
+Voice Over
+@item ka
+Karaoke
+@end table
+
+@item request_sample_fmt @var{sample_fmt} (@emph{decoding,audio})
+Set sample format audio decoders should prefer. Default value is
+@code{none}.
+
+@item pkt_timebase @var{rational number}
+
+@item sub_charenc @var{encoding} (@emph{decoding,subtitles})
+Set the input subtitles character encoding.
+
+@item field_order @var{field_order} (@emph{video})
+Set/override the field order of the video.
+Possible values:
+@table @samp
+@item progressive
+Progressive video
+@item tt
+Interlaced video, top field coded and displayed first
+@item bb
+Interlaced video, bottom field coded and displayed first
+@item tb
+Interlaced video, top coded first, bottom displayed first
+@item bt
+Interlaced video, bottom coded first, top displayed first
+@end table
+
+@item skip_alpha @var{integer} (@emph{decoding,video})
+Set to 1 to disable processing alpha (transparency). This works like the
+@samp{gray} flag in the @option{flags} option which skips chroma information
+instead of alpha. Default is 0.
+
+@item codec_whitelist @var{list} (@emph{input})
+"," separated List of allowed decoders. By default all are allowed.
+
+@item dump_separator @var{string} (@emph{input})
+Separator used to separate the fields printed on the command line about the
+Stream parameters.
+For example to separate the fields with newlines and indention:
+@example
+ffprobe -dump_separator "
+ " -i ~/videos/matrixbench_mpeg2.mpg
+@end example
+
+@end table
+
+@c man end CODEC OPTIONS
+
+@ifclear config-writeonly
+@include decoders.texi
+@end ifclear
+@ifclear config-readonly
+@include encoders.texi
+@end ifclear
diff --git a/doc/decoders.texi b/doc/decoders.texi
index 99d2008101..68196cf111 100644
--- a/doc/decoders.texi
+++ b/doc/decoders.texi
@@ -1,10 +1,10 @@
@chapter Decoders
@c man begin DECODERS
-Decoders are configured elements in Libav which allow the decoding of
+Decoders are configured elements in FFmpeg which allow the decoding of
multimedia streams.
-When you configure your Libav build, all the supported native decoders
+When you configure your FFmpeg build, all the supported native decoders
are enabled by default. Decoders requiring an external library must be enabled
manually via the corresponding @code{--enable-lib} option. You can list all
available decoders using the configure option @code{--list-decoders}.
@@ -14,11 +14,41 @@ You can disable all the decoders with the configure option
with the options @code{--enable-decoder=@var{DECODER}} /
@code{--disable-decoder=@var{DECODER}}.
-The option @code{-decoders} of the av* tools will display the list of
+The option @code{-decoders} of the ff* tools will display the list of
enabled decoders.
@c man end DECODERS
+@chapter Video Decoders
+@c man begin VIDEO DECODERS
+
+A description of some of the currently available video decoders
+follows.
+
+@section rawvideo
+
+Raw video decoder.
+
+This decoder decodes rawvideo streams.
+
+@subsection Options
+
+@table @option
+@item top @var{top_field_first}
+Specify the assumed field type of the input video.
+@table @option
+@item -1
+the video is assumed to be progressive (default)
+@item 0
+bottom-field-first is assumed
+@item 1
+top-field-first is assumed
+@end table
+
+@end table
+
+@c man end VIDEO DECODERS
+
@chapter Audio Decoders
@c man begin AUDIO DECODERS
@@ -53,4 +83,180 @@ Loud sounds are fully compressed. Soft sounds are enhanced.
@end table
+@section flac
+
+FLAC audio decoder.
+
+This decoder aims to implement the complete FLAC specification from Xiph.
+
+@subsection FLAC Decoder options
+
+@table @option
+
+@item -use_buggy_lpc
+The lavc FLAC encoder used to produce buggy streams with high lpc values
+(like the default value). This option allows to decode such streams
+correctly by using lavc's old buggy lpc logic for decoding.
+
+@end table
+
+@section ffwavesynth
+
+Internal wave synthetizer.
+
+This decoder generates wave patterns according to predefined sequences. Its
+use is purely internal and the format of the data it accepts is not publicly
+documented.
+
+@section libcelt
+
+libcelt decoder wrapper.
+
+libcelt allows libavcodec to decode the Xiph CELT ultra-low delay audio codec.
+Requires the presence of the libcelt headers and library during configuration.
+You need to explicitly configure the build with @code{--enable-libcelt}.
+
+@section libgsm
+
+libgsm decoder wrapper.
+
+libgsm allows libavcodec to decode the GSM full rate audio codec. Requires
+the presence of the libgsm headers and library during configuration. You need
+to explicitly configure the build with @code{--enable-libgsm}.
+
+This decoder supports both the ordinary GSM and the Microsoft variant.
+
+@section libilbc
+
+libilbc decoder wrapper.
+
+libilbc allows libavcodec to decode the Internet Low Bitrate Codec (iLBC)
+audio codec. Requires the presence of the libilbc headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libilbc}.
+
+@subsection Options
+
+The following option is supported by the libilbc wrapper.
+
+@table @option
+@item enhance
+
+Enable the enhancement of the decoded audio when set to 1. The default
+value is 0 (disabled).
+
+@end table
+
+@section libopencore-amrnb
+
+libopencore-amrnb decoder wrapper.
+
+libopencore-amrnb allows libavcodec to decode the Adaptive Multi-Rate
+Narrowband audio codec. Using it requires the presence of the
+libopencore-amrnb headers and library during configuration. You need to
+explicitly configure the build with @code{--enable-libopencore-amrnb}.
+
+An FFmpeg native decoder for AMR-NB exists, so users can decode AMR-NB
+without this library.
+
+@section libopencore-amrwb
+
+libopencore-amrwb decoder wrapper.
+
+libopencore-amrwb allows libavcodec to decode the Adaptive Multi-Rate
+Wideband audio codec. Using it requires the presence of the
+libopencore-amrwb headers and library during configuration. You need to
+explicitly configure the build with @code{--enable-libopencore-amrwb}.
+
+An FFmpeg native decoder for AMR-WB exists, so users can decode AMR-WB
+without this library.
+
+@section libopus
+
+libopus decoder wrapper.
+
+libopus allows libavcodec to decode the Opus Interactive Audio Codec.
+Requires the presence of the libopus headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libopus}.
+
+An FFmpeg native decoder for Opus exists, so users can decode Opus
+without this library.
+
@c man end AUDIO DECODERS
+
+@chapter Subtitles Decoders
+@c man begin SUBTILES DECODERS
+
+@section dvdsub
+
+This codec decodes the bitmap subtitles used in DVDs; the same subtitles can
+also be found in VobSub file pairs and in some Matroska files.
+
+@subsection Options
+
+@table @option
+@item palette
+Specify the global palette used by the bitmaps. When stored in VobSub, the
+palette is normally specified in the index file; in Matroska, the palette is
+stored in the codec extra-data in the same format as in VobSub. In DVDs, the
+palette is stored in the IFO file, and therefore not available when reading
+from dumped VOB files.
+
+The format for this option is a string containing 16 24-bits hexadecimal
+numbers (without 0x prefix) separated by comas, for example @code{0d00ee,
+ee450d, 101010, eaeaea, 0ce60b, ec14ed, ebff0b, 0d617a, 7b7b7b, d1d1d1,
+7b2a0e, 0d950c, 0f007b, cf0dec, cfa80c, 7c127b}.
+
+@item ifo_palette
+Specify the IFO file from which the global palette is obtained.
+(experimental)
+
+@item forced_subs_only
+Only decode subtitle entries marked as forced. Some titles have forced
+and non-forced subtitles in the same track. Setting this flag to @code{1}
+will only keep the forced subtitles. Default value is @code{0}.
+@end table
+
+@section libzvbi-teletext
+
+Libzvbi allows libavcodec to decode DVB teletext pages and DVB teletext
+subtitles. Requires the presence of the libzvbi headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libzvbi}.
+
+@subsection Options
+
+@table @option
+@item txt_page
+List of teletext page numbers to decode. You may use the special * string to
+match all pages. Pages that do not match the specified list are dropped.
+Default value is *.
+@item txt_chop_top
+Discards the top teletext line. Default value is 1.
+@item txt_format
+Specifies the format of the decoded subtitles. The teletext decoder is capable
+of decoding the teletext pages to bitmaps or to simple text, you should use
+"bitmap" for teletext pages, because certain graphics and colors cannot be
+expressed in simple text. You might use "text" for teletext based subtitles if
+your application can handle simple text based subtitles. Default value is
+bitmap.
+@item txt_left
+X offset of generated bitmaps, default is 0.
+@item txt_top
+Y offset of generated bitmaps, default is 0.
+@item txt_chop_spaces
+Chops leading and trailing spaces and removes empty lines from the generated
+text. This option is useful for teletext based subtitles where empty spaces may
+be present at the start or at the end of the lines or empty lines may be
+present between the subtitle lines because of double-sized teletext charactes.
+Default value is 1.
+@item txt_duration
+Sets the display duration of the decoded teletext pages or subtitles in
+miliseconds. Default value is 30000 which is 30 seconds.
+@item txt_transparent
+Force transparent background of the generated teletext bitmaps. Default value
+is 0 which means an opaque (black) background.
+@end table
+
+@c man end SUBTILES DECODERS
diff --git a/doc/default.css b/doc/default.css
new file mode 100644
index 0000000000..bf50200c28
--- /dev/null
+++ b/doc/default.css
@@ -0,0 +1,165 @@
+a.summary-letter {
+ text-decoration: none;
+}
+
+a {
+ color: #2D6198;
+}
+
+a:visited {
+ color: #884488;
+}
+
+#banner {
+ background-color: white;
+ position: relative;
+ text-align: center;
+}
+
+#banner img {
+ margin-bottom: 1px;
+ margin-top: 5px;
+}
+
+#body {
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+body {
+ background-color: #313131;
+ margin: 0;
+ text-align: justify;
+}
+
+.center {
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+}
+
+#container {
+ background-color: white;
+ color: #202020;
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+#footer {
+ text-align: center;
+}
+
+h1 a, h2 a, h3 a, h4 a {
+ text-decoration: inherit;
+ color: inherit;
+}
+
+h1, h2, h3, h4 {
+ padding-left: 0.4em;
+ border-radius: 4px;
+ padding-bottom: 0.25em;
+ padding-top: 0.25em;
+ border: 1px solid #6A996A;
+}
+
+h1 {
+ background-color: #7BB37B;
+ color: #151515;
+ font-size: 1.2em;
+ padding-bottom: 0.3em;
+ padding-top: 0.3em;
+}
+
+h2 {
+ color: #313131;
+ font-size: 1.0em;
+ background-color: #ABE3AB;
+}
+
+h3 {
+ color: #313131;
+ font-size: 0.9em;
+ margin-bottom: -6px;
+ background-color: #BBF3BB;
+}
+
+h4 {
+ color: #313131;
+ font-size: 0.8em;
+ margin-bottom: -8px;
+ background-color: #D1FDD1;
+}
+
+img {
+ border: 0;
+}
+
+#navbar {
+ background-color: #738073;
+ border-bottom: 1px solid #5C665C;
+ border-top: 1px solid #5C665C;
+ margin-top: 12px;
+ padding: 0.3em;
+ position: relative;
+ text-align: center;
+}
+
+#navbar a, #navbar_secondary a {
+ color: white;
+ padding: 0.3em;
+ text-decoration: none;
+}
+
+#navbar a:hover, #navbar_secondary a:hover {
+ background-color: #313131;
+ color: white;
+ text-decoration: none;
+}
+
+#navbar_secondary {
+ background-color: #738073;
+ border-bottom: 1px solid #5C665C;
+ border-left: 1px solid #5C665C;
+ border-right: 1px solid #5C665C;
+ padding: 0.3em;
+ position: relative;
+ text-align: center;
+}
+
+p {
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+pre {
+ margin-left: 3em;
+ margin-right: 3em;
+ padding: 0.3em;
+ border: 1px solid #bbb;
+ background-color: #f7f7f7;
+}
+
+dl dt {
+ font-weight: bold;
+}
+
+#proj_desc {
+ font-size: 1.2em;
+}
+
+#repos {
+ margin-left: 1em;
+ margin-right: 1em;
+ border-collapse: collapse;
+ border: solid 1px #6A996A;
+}
+
+#repos th {
+ background-color: #7BB37B;
+ border: solid 1px #6A996A;
+}
+
+#repos td {
+ padding: 0.2em;
+ border: solid 1px #6A996A;
+}
diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index 2f2f464404..b7ddebb9a9 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -1,30 +1,272 @@
@chapter Demuxers
@c man begin DEMUXERS
-Demuxers are configured elements in Libav which allow to read the
+Demuxers are configured elements in FFmpeg that can read the
multimedia streams from a particular type of file.
-When you configure your Libav build, all the supported demuxers
+When you configure your FFmpeg build, all the supported demuxers
are enabled by default. You can list all available ones using the
-configure option "--list-demuxers".
+configure option @code{--list-demuxers}.
You can disable all the demuxers using the configure option
-"--disable-demuxers", and selectively enable a single demuxer with
-the option "--enable-demuxer=@var{DEMUXER}", or disable it
-with the option "--disable-demuxer=@var{DEMUXER}".
+@code{--disable-demuxers}, and selectively enable a single demuxer with
+the option @code{--enable-demuxer=@var{DEMUXER}}, or disable it
+with the option @code{--disable-demuxer=@var{DEMUXER}}.
-The option "-formats" of the av* tools will display the list of
+The option @code{-formats} of the ff* tools will display the list of
enabled demuxers.
The description of some of the currently available demuxers follows.
+@section applehttp
+
+Apple HTTP Live Streaming demuxer.
+
+This demuxer presents all AVStreams from all variant streams.
+The id field is set to the bitrate variant index number. By setting
+the discard flags on AVStreams (by pressing 'a' or 'v' in ffplay),
+the caller can decide which variant streams to actually receive.
+The total bitrate of the variant that the stream belongs to is
+available in a metadata key named "variant_bitrate".
+
+@section apng
+
+Animated Portable Network Graphics demuxer.
+
+This demuxer is used to demux APNG files.
+All headers, but the PNG signature, up to (but not including) the first
+fcTL chunk are transmitted as extradata.
+Frames are then split as being all the chunks between two fcTL ones, or
+between the last fcTL and IEND chunks.
+
+@table @option
+@item -ignore_loop @var{bool}
+Ignore the loop variable in the file if set.
+@item -max_fps @var{int}
+Maximum framerate in frames per second (0 for no limit).
+@item -default_fps @var{int}
+Default framerate in frames per second when none is specified in the file
+(0 meaning as fast as possible).
+@end table
+
+@section asf
+
+Advanced Systems Format demuxer.
+
+This demuxer is used to demux ASF files and MMS network streams.
+
+@table @option
+@item -no_resync_search @var{bool}
+Do not try to resynchronize by looking for a certain optional start code.
+@end table
+
+@anchor{concat}
+@section concat
+
+Virtual concatenation script demuxer.
+
+This demuxer reads a list of files and other directives from a text file and
+demuxes them one after the other, as if all their packet had been muxed
+together.
+
+The timestamps in the files are adjusted so that the first file starts at 0
+and each next file starts where the previous one finishes. Note that it is
+done globally and may cause gaps if all streams do not have exactly the same
+length.
+
+All files must have the same streams (same codecs, same time base, etc.).
+
+The duration of each file is used to adjust the timestamps of the next file:
+if the duration is incorrect (because it was computed using the bit-rate or
+because the file is truncated, for example), it can cause artifacts. The
+@code{duration} directive can be used to override the duration stored in
+each file.
+
+@subsection Syntax
+
+The script is a text file in extended-ASCII, with one directive per line.
+Empty lines, leading spaces and lines starting with '#' are ignored. The
+following directive is recognized:
+
+@table @option
+
+@item @code{file @var{path}}
+Path to a file to read; special characters and spaces must be escaped with
+backslash or single quotes.
+
+All subsequent file-related directives apply to that file.
+
+@item @code{ffconcat version 1.0}
+Identify the script type and version. It also sets the @option{safe} option
+to 1 if it was to its default -1.
+
+To make FFmpeg recognize the format automatically, this directive must
+appears exactly as is (no extra space or byte-order-mark) on the very first
+line of the script.
+
+@item @code{duration @var{dur}}
+Duration of the file. This information can be specified from the file;
+specifying it here may be more efficient or help if the information from the
+file is not available or accurate.
+
+If the duration is set for all files, then it is possible to seek in the
+whole concatenated video.
+
+@item @code{stream}
+Introduce a stream in the virtual file.
+All subsequent stream-related directives apply to the last introduced
+stream.
+Some streams properties must be set in order to allow identifying the
+matching streams in the subfiles.
+If no streams are defined in the script, the streams from the first file are
+copied.
+
+@item @code{exact_stream_id @var{id}}
+Set the id of the stream.
+If this directive is given, the string with the corresponding id in the
+subfiles will be used.
+This is especially useful for MPEG-PS (VOB) files, where the order of the
+streams is not reliable.
+
+@end table
+
+@subsection Options
+
+This demuxer accepts the following option:
+
+@table @option
+
+@item safe
+If set to 1, reject unsafe file paths. A file path is considered safe if it
+does not contain a protocol specification and is relative and all components
+only contain characters from the portable character set (letters, digits,
+period, underscore and hyphen) and have no period at the beginning of a
+component.
+
+If set to 0, any file name is accepted.
+
+The default is -1, it is equivalent to 1 if the format was automatically
+probed and 0 otherwise.
+
+@item auto_convert
+If set to 1, try to perform automatic conversions on packet data to make the
+streams concatenable.
+
+Currently, the only conversion is adding the h264_mp4toannexb bitstream
+filter to H.264 streams in MP4 format. This is necessary in particular if
+there are resolution changes.
+
+@end table
+
+@section flv
+
+Adobe Flash Video Format demuxer.
+
+This demuxer is used to demux FLV files and RTMP network streams.
+
+@table @option
+@item -flv_metadata @var{bool}
+Allocate the streams according to the onMetaData array content.
+@end table
+
+@section libgme
+
+The Game Music Emu library is a collection of video game music file emulators.
+
+See @url{http://code.google.com/p/game-music-emu/} for more information.
+
+Some files have multiple tracks. The demuxer will pick the first track by
+default. The @option{track_index} option can be used to select a different
+track. Track indexes start at 0. The demuxer exports the number of tracks as
+@var{tracks} meta data entry.
+
+For very large files, the @option{max_size} option may have to be adjusted.
+
+@section libquvi
+
+Play media from Internet services using the quvi project.
+
+The demuxer accepts a @option{format} option to request a specific quality. It
+is by default set to @var{best}.
+
+See @url{http://quvi.sourceforge.net/} for more information.
+
+FFmpeg needs to be built with @code{--enable-libquvi} for this demuxer to be
+enabled.
+
+@section gif
+
+Animated GIF demuxer.
+
+It accepts the following options:
+
+@table @option
+@item min_delay
+Set the minimum valid delay between frames in hundredths of seconds.
+Range is 0 to 6000. Default value is 2.
+
+@item max_gif_delay
+Set the maximum valid delay between frames in hundredth of seconds.
+Range is 0 to 65535. Default value is 65535 (nearly eleven minutes),
+the maximum value allowed by the specification.
+
+@item default_delay
+Set the default delay between frames in hundredths of seconds.
+Range is 0 to 6000. Default value is 10.
+
+@item ignore_loop
+GIF files can contain information to loop a certain number of times (or
+infinitely). If @option{ignore_loop} is set to 1, then the loop setting
+from the input will be ignored and looping will not occur. If set to 0,
+then looping will occur and will cycle the number of times according to
+the GIF. Default value is 1.
+@end table
+
+For example, with the overlay filter, place an infinitely looping GIF
+over another video:
+@example
+ffmpeg -i input.mp4 -ignore_loop 0 -i input.gif -filter_complex overlay=shortest=1 out.mkv
+@end example
+
+Note that in the above example the shortest option for overlay filter is
+used to end the output video at the length of the shortest input file,
+which in this case is @file{input.mp4} as the GIF in this example loops
+infinitely.
+
@section image2
Image file demuxer.
This demuxer reads from a list of image files specified by a pattern.
+The syntax and meaning of the pattern is specified by the
+option @var{pattern_type}.
-The pattern may contain the string "%d" or "%0@var{N}d", which
+The pattern may contain a suffix which is used to automatically
+determine the format of the images contained in the files.
+
+The size, the pixel format, and the format of each image must be the
+same for all the files in the sequence.
+
+This demuxer accepts the following options:
+@table @option
+@item framerate
+Set the frame rate for the video stream. It defaults to 25.
+@item loop
+If set to 1, loop over the input. Default value is 0.
+@item pattern_type
+Select the pattern type used to interpret the provided filename.
+
+@var{pattern_type} accepts one of the following values.
+@table @option
+@item none
+Disable pattern matching, therefore the video will only contain the specified
+image. You should use this option if you do not want to create sequences from
+multiple images and your filenames may contain special pattern characters.
+@item sequence
+Select a sequence pattern type, used to specify a sequence of files
+indexed by sequential numbers.
+
+A sequence pattern may contain the string "%d" or "%0@var{N}d", which
specifies the position of the characters representing a sequential
number in each filename matched by the pattern. If the form
"%d0@var{N}d" is used, the string representing the number in each
@@ -32,13 +274,11 @@ filename is 0-padded and @var{N} is the total number of 0-padded
digits representing the number. The literal character '%' can be
specified in the pattern with the string "%%".
-If the pattern contains "%d" or "%0@var{N}d", the first filename of
+If the sequence pattern contains "%d" or "%0@var{N}d", the first filename of
the file list specified by the pattern must contain a number
-inclusively contained between 0 and 4, all the following numbers must
-be sequential. This limitation may be hopefully fixed.
-
-The pattern may contain a suffix which is used to automatically
-determine the format of the images contained in the files.
+inclusively contained between @var{start_number} and
+@var{start_number}+@var{start_number_range}-1, and all the following
+numbers must be sequential.
For example the pattern "img-%03d.bmp" will match a sequence of
filenames of the form @file{img-001.bmp}, @file{img-002.bmp}, ...,
@@ -46,68 +286,179 @@ filenames of the form @file{img-001.bmp}, @file{img-002.bmp}, ...,
sequence of filenames of the form @file{i%m%g-1.jpg},
@file{i%m%g-2.jpg}, ..., @file{i%m%g-10.jpg}, etc.
-The size, the pixel format, and the format of each image must be the
-same for all the files in the sequence.
+Note that the pattern must not necessarily contain "%d" or
+"%0@var{N}d", for example to convert a single image file
+@file{img.jpeg} you can employ the command:
+@example
+ffmpeg -i img.jpeg img.png
+@end example
+
+@item glob
+Select a glob wildcard pattern type.
+
+The pattern is interpreted like a @code{glob()} pattern. This is only
+selectable if libavformat was compiled with globbing support.
+
+@item glob_sequence @emph{(deprecated, will be removed)}
+Select a mixed glob wildcard/sequence pattern.
+
+If your version of libavformat was compiled with globbing support, and
+the provided pattern contains at least one glob meta character among
+@code{%*?[]@{@}} that is preceded by an unescaped "%", the pattern is
+interpreted like a @code{glob()} pattern, otherwise it is interpreted
+like a sequence pattern.
+
+All glob special characters @code{%*?[]@{@}} must be prefixed
+with "%". To escape a literal "%" you shall use "%%".
+
+For example the pattern @code{foo-%*.jpeg} will match all the
+filenames prefixed by "foo-" and terminating with ".jpeg", and
+@code{foo-%?%?%?.jpeg} will match all the filenames prefixed with
+"foo-", followed by a sequence of three characters, and terminating
+with ".jpeg".
+
+This pattern type is deprecated in favor of @var{glob} and
+@var{sequence}.
+@end table
+
+Default value is @var{glob_sequence}.
+@item pixel_format
+Set the pixel format of the images to read. If not specified the pixel
+format is guessed from the first image file in the sequence.
+@item start_number
+Set the index of the file matched by the image file pattern to start
+to read from. Default value is 0.
+@item start_number_range
+Set the index interval range to check when looking for the first image
+file in the sequence, starting from @var{start_number}. Default value
+is 5.
+@item ts_from_file
+If set to 1, will set frame timestamp to modification time of image file. Note
+that monotonity of timestamps is not provided: images go in the same order as
+without this option. Default value is 0.
+If set to 2, will set frame timestamp to the modification time of the image file in
+nanosecond precision.
+@item video_size
+Set the video size of the images to read. If not specified the video
+size is guessed from the first image file in the sequence.
+@end table
+
+@subsection Examples
-The following example shows how to use @command{avconv} for creating a
-video from the images in the file sequence @file{img-001.jpeg},
-@file{img-002.jpeg}, ..., assuming an input framerate of 10 frames per
-second:
+@itemize
+@item
+Use @command{ffmpeg} for creating a video from the images in the file
+sequence @file{img-001.jpeg}, @file{img-002.jpeg}, ..., assuming an
+input frame rate of 10 frames per second:
@example
-avconv -i 'img-%03d.jpeg' -r 10 out.mkv
+ffmpeg -framerate 10 -i 'img-%03d.jpeg' out.mkv
@end example
-Note that the pattern must not necessarily contain "%d" or
-"%0@var{N}d", for example to convert a single image file
-@file{img.jpeg} you can employ the command:
+@item
+As above, but start by reading from a file with index 100 in the sequence:
+@example
+ffmpeg -framerate 10 -start_number 100 -i 'img-%03d.jpeg' out.mkv
+@end example
+
+@item
+Read images matching the "*.png" glob pattern , that is all the files
+terminating with the ".png" suffix:
@example
-avconv -i img.jpeg img.png
+ffmpeg -framerate 10 -pattern_type glob -i "*.png" out.mkv
@end example
+@end itemize
+
+@section mpegts
+
+MPEG-2 transport stream demuxer.
@table @option
-@item -pixel_format @var{format}
-Set the pixel format (for raw image)
-@item -video_size @var{size}
-Set the frame size (for raw image)
-@item -framerate @var{rate}
-Set the frame rate
-@item -loop @var{bool}
-Loop over the images
-@item -start_number @var{start}
-Specify the first number in the sequence
+
+@item fix_teletext_pts
+Overrides teletext packet PTS and DTS values with the timestamps calculated
+from the PCR of the first program which the teletext stream is part of and is
+not discarded. Default value is 1, set this option to 0 if you want your
+teletext packet PTS and DTS values untouched.
@end table
-@section applehttp
+@section rawvideo
-Apple HTTP Live Streaming demuxer.
+Raw video demuxer.
-This demuxer presents all AVStreams from all variant streams.
-The id field is set to the bitrate variant index number. By setting
-the discard flags on AVStreams (by pressing 'a' or 'v' in avplay),
-the caller can decide which variant streams to actually receive.
-The total bitrate of the variant that the stream belongs to is
-available in a metadata key named "variant_bitrate".
+This demuxer allows one to read raw video data. Since there is no header
+specifying the assumed video parameters, the user must specify them
+in order to be able to decode the data correctly.
-@section flv
+This demuxer accepts the following options:
+@table @option
-Adobe Flash Video Format demuxer.
+@item framerate
+Set input video frame rate. Default value is 25.
-This demuxer is used to demux FLV files and RTMP network streams.
+@item pixel_format
+Set the input video pixel format. Default value is @code{yuv420p}.
-@table @option
-@item -flv_metadata @var{bool}
-Allocate the streams according to the onMetaData array content.
+@item video_size
+Set the input video size. This value must be specified explicitly.
@end table
-@section asf
+For example to read a rawvideo file @file{input.raw} with
+@command{ffplay}, assuming a pixel format of @code{rgb24}, a video
+size of @code{320x240}, and a frame rate of 10 images per second, use
+the command:
+@example
+ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 input.raw
+@end example
-Advanced Systems Format demuxer.
+@section sbg
-This demuxer is used to demux ASF files and MMS network streams.
+SBaGen script demuxer.
+
+This demuxer reads the script language used by SBaGen
+@url{http://uazu.net/sbagen/} to generate binaural beats sessions. A SBG
+script looks like that:
+@example
+-SE
+a: 300-2.5/3 440+4.5/0
+b: 300-2.5/0 440+4.5/3
+off: -
+NOW == a
++0:07:00 == b
++0:14:00 == a
++0:21:00 == b
++0:30:00 off
+@end example
+
+A SBG script can mix absolute and relative timestamps. If the script uses
+either only absolute timestamps (including the script start time) or only
+relative ones, then its layout is fixed, and the conversion is
+straightforward. On the other hand, if the script mixes both kind of
+timestamps, then the @var{NOW} reference for relative timestamps will be
+taken from the current time of day at the time the script is read, and the
+script layout will be frozen according to that reference. That means that if
+the script is directly played, the actual times will match the absolute
+timestamps up to the sound controller's clock accuracy, but if the user
+somehow pauses the playback or seeks, all times will be shifted accordingly.
+
+@section tedcaptions
+
+JSON captions used for @url{http://www.ted.com/, TED Talks}.
+
+TED does not provide links to the captions, but they can be guessed from the
+page. The file @file{tools/bookmarklets.html} from the FFmpeg source tree
+contains a bookmarklet to expose them.
+This demuxer accepts the following option:
@table @option
-@item -no_resync_search @var{bool}
-Do not try to resynchronize by looking for a certain optional start code.
+@item start_time
+Set the start time of the TED talk, in milliseconds. The default is 15000
+(15s). It is used to sync the captions with the downloadable videos, because
+they include a 15s intro.
@end table
-@c man end INPUT DEVICES
+Example: convert the captions to a format most players understand:
+@example
+ffmpeg -i http://www.ted.com/talks/subtitles/id/1/lang/en talk1-en.srt
+@end example
+
+@c man end DEMUXERS
diff --git a/doc/developer.texi b/doc/developer.texi
index 00e2b6028f..d9ccf7b938 100644
--- a/doc/developer.texi
+++ b/doc/developer.texi
@@ -1,4 +1,5 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
@settitle Developer Documentation
@titlepage
@@ -11,87 +12,44 @@
@chapter Developers Guide
-@section API
+@section Notes for external developers
-@itemize @bullet
-@item libavcodec is the library containing the codecs (both encoding and
-decoding). Look at @file{libavcodec/apiexample.c} to see how to use it.
-
-@item libavformat is the library containing the file format handling (mux and
-demux code for several formats). Look at @file{avplay.c} to use it in a
-player. See @file{libavformat/output-example.c} to use it to generate
-audio or video streams.
-@end itemize
+This document is mostly useful for internal FFmpeg developers.
+External developers who need to use the API in their application should
+refer to the API doxygen documentation in the public headers, and
+check the examples in @file{doc/examples} and in the source code to
+see how the public API is employed.
-@section Integrating libav in your program
-
-Shared libraries should be used whenever is possible in order to reduce
-the effort distributors have to pour to support programs and to ensure
-only the public API is used.
-
-You can use Libav in your commercial program, but you must abide to the
-license, LGPL or GPL depending on the specific features used, please refer
-to @uref{http://libav.org/legal.html, our legal page} for a quick checklist and to
-the following links for the exact text of each license:
-@uref{http://git.libav.org/?p=libav.git;a=blob;f=COPYING.GPLv2, GPL version 2},
-@uref{http://git.libav.org/?p=libav.git;a=blob;f=COPYING.GPLv3, GPL version 3},
-@uref{http://git.libav.org/?p=libav.git;a=blob;f=COPYING.LGPLv2.1, LGPL version 2.1},
-@uref{http://git.libav.org/?p=libav.git;a=blob;f=COPYING.LGPLv3, LGPL version 3}.
-Any modification to the source code can be suggested for inclusion.
-The best way to proceed is to send your patches to the
-@uref{https://lists.libav.org/mailman/listinfo/libav-devel, libav-devel}
-mailing list.
+You can use the FFmpeg libraries in your commercial program, but you
+are encouraged to @emph{publish any patch you make}. In this case the
+best way to proceed is to send your patches to the ffmpeg-devel
+mailing list following the guidelines illustrated in the remainder of
+this document.
-@anchor{Coding Rules}
-@section Coding Rules
+For more detailed legal information about the use of FFmpeg in
+external programs read the @file{LICENSE} file in the source tree and
+consult @url{http://ffmpeg.org/legal.html}.
-@subsection Code formatting conventions
-The code is written in K&R C style. That means the following:
+@section Contributing
+There are 3 ways by which code gets into ffmpeg.
@itemize @bullet
-@item
-The control statements are formatted by putting space between the statement
-and parenthesis in the following way:
-@example
-for (i = 0; i < filter->input_count; i++) @{
-@end example
-
-@item
-The case statement is always located at the same level as the switch itself:
-@example
-switch (link->init_state) @{
-case AVLINK_INIT:
- continue;
-case AVLINK_STARTINIT:
- av_log(filter, AV_LOG_INFO, "circular filter chain detected");
- return 0;
-@end example
-
-@item
-Braces in function definitions are written on the new line:
-@example
-const char *avfilter_configuration(void)
-@{
- return LIBAV_CONFIGURATION;
-@}
-@end example
+@item Submitting Patches to the main developer mailing list
+ see @ref{Submitting patches} for details.
+@item Directly committing changes to the main tree.
+@item Committing changes to a git clone, for example on github.com or
+ gitorious.org. And asking us to merge these changes.
+@end itemize
-@item
-Do not check for NULL values by comparison, @samp{if (p)} and
-@samp{if (!p)} are correct; @samp{if (p == NULL)} and @samp{if (p != NULL)}
-are not.
+Whichever way, changes should be reviewed by the maintainer of the code
+before they are committed. And they should follow the @ref{Coding Rules}.
+The developer making the commit and the author are responsible for their changes
+and should try to fix issues their commit causes.
-@item
-In case of a single-statement if, no curly braces are required:
-@example
-if (!pic || !picref)
- goto fail;
-@end example
+@anchor{Coding Rules}
+@section Coding Rules
-@item
-Do not put spaces immediately inside parentheses. @samp{if (ret)} is
-a valid style; @samp{if ( ret )} is not.
-@end itemize
+@subsection Code formatting conventions
There are the following guidelines regarding the indentation in files:
@@ -110,7 +68,7 @@ and only if this improves readability.
@end itemize
The presentation is one inspired by 'indent -i4 -kr -nut'.
-The main priority in Libav is simplicity and small code size in order to
+The main priority in FFmpeg is simplicity and small code size in order to
minimize the bug count.
@subsection Comments
@@ -155,7 +113,7 @@ int myfunc(int my_parameter)
@subsection C language features
-Libav is programmed in the ISO C90 language with a few additional
+FFmpeg is programmed in the ISO C90 language with a few additional
features from ISO C99, namely:
@itemize @bullet
@@ -197,8 +155,8 @@ GCC statement expressions (@samp{(x = (@{ int y = 4; y; @})}).
@subsection Naming conventions
All names should be composed with underscores (_), not CamelCase. For example,
@samp{avfilter_get_video_buffer} is an acceptable function name and
-@samp{AVFilterGetVideo} is not. The only exception are structure
-names; they should always be CamelCase.
+@samp{AVFilterGetVideo} is not. The exception from this are type names, like
+for example structs and enums; they should always be in the CamelCase
There are the following conventions for naming variables and functions:
@@ -221,8 +179,13 @@ across multiple libraries, use @code{avpriv_} as prefix, for example,
@samp{avpriv_aac_parse_header}.
@item
-For externally visible symbols, each library has its own prefix. Check
-the existing code and choose names accordingly.
+Each library has its own prefix for public symbols, in addition to the
+commonly used @code{av_} (@code{avformat_} for libavformat,
+@code{avcodec_} for libavcodec, @code{swr_} for libswresample, etc).
+Check the existing code and choose names accordingly.
+Note that some symbols without these prefixes are also exported for
+retro-compatibility reasons. These exceptions are declared in the
+@code{lib<name>/lib<name>.v} files.
@end itemize
Furthermore, name space reserved for the system should not be invaded.
@@ -246,10 +209,10 @@ should also be avoided if they don't make the code easier to understand.
@end itemize
@subsection Editor configuration
-In order to configure Vim to follow Libav formatting conventions, paste
+In order to configure Vim to follow FFmpeg formatting conventions, paste
the following snippet into your @file{.vimrc}:
@example
-" Indentation rules for Libav: 4 spaces, no tabs.
+" indentation rules for FFmpeg: 4 spaces, no tabs
set expandtab
set shiftwidth=4
set softtabstop=4
@@ -265,8 +228,8 @@ autocmd InsertEnter * match ForbiddenWhitespace /\t\|\s\+\%#\@@<!$/
@end example
For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
-@example
-(c-add-style "libav"
+@lisp
+(c-add-style "ffmpeg"
'("k&r"
(c-basic-offset . 4)
(indent-tabs-mode . nil)
@@ -275,8 +238,8 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}:
(statement-cont . (c-lineup-assignments +)))
)
)
-(setq c-default-style "libav")
-@end example
+(setq c-default-style "ffmpeg")
+@end lisp
@section Development Policy
@@ -291,20 +254,16 @@ a gift-style license, the
@uref{http://www.gnu.org/licenses/gpl-2.0.html, GPL 2} including
an "or any later version" clause is also acceptable, but LGPL is
preferred.
+If you add a new file, give it a proper license header. Do not copy and
+paste it from a random place, use an existing file as template.
@item
-All the patches MUST be reviewed in the mailing list before they are
-committed.
-
-@item
-The Libav coding style should remain consistent. Changes to
-conform will be suggested during the review or implemented on commit.
-
-@item
-Patches should be generated using @code{git format-patch} or directly sent
-using @code{git send-email}.
-Please make sure you give the proper credit by setting the correct author
-in the commit.
+You must not commit code which breaks FFmpeg! (Meaning unfinished but
+enabled code which breaks compilation or compiles but does not work or
+breaks the regression tests)
+You can commit unfinished stuff (for testing etc), but it must be disabled
+(#ifdef etc) by default so it does not interfere with other developers'
+work.
@item
The commit message should have a short first line in the form of
@@ -313,24 +272,12 @@ from the body consisting of an explanation of why the change is necessary.
If the commit fixes a known bug on the bug tracker, the commit message
should include its bug ID. Referring to the issue on the bug tracker does
not exempt you from writing an excerpt of the bug in the commit message.
-If the patch is a bug fix which should be backported to stable releases,
-i.e. a non-API/ABI-breaking bug fix, add @code{CC: libav-stable@@libav.org}
-to the bottom of your commit message, and make sure to CC your patch to
-this address, too. Some git setups will do this automatically.
-
-@item
-Work in progress patches should be sent to the mailing list with the [WIP]
-or the [RFC] tag.
-
-@item
-Branches in public personal repos are advised as way to
-work on issues collaboratively.
@item
-You do not have to over-test things. If it works for you and you think it
-should work for others, send it to the mailing list for review.
-If you have doubt about portability please state it in the submission so
-people with specific hardware could test it.
+You do not have to over-test things. If it works for you, and you think it
+should work for others, then commit. If your code has problems
+(portability, triggers compiler bugs, unusual environment etc) they will be
+reported and eventually fixed.
@item
Do not commit unrelated changes together, split them into self-contained
@@ -339,44 +286,90 @@ depend on B, then A can and should be committed first and separate from B.
Keeping changes well split into self-contained parts makes reviewing and
understanding them on the commit log mailing list easier. This also helps
in case of debugging later on.
+Also if you have doubts about splitting or not splitting, do not hesitate to
+ask/discuss it on the developer mailing list.
@item
-Patches that change behavior of the programs (renaming options etc) or
-public API or ABI should be discussed in depth and possible few days should
-pass between discussion and commit.
-Changes to the build system (Makefiles, configure script) which alter
-the expected behavior should be considered in the same regard.
+Do not change behavior of the programs (renaming options etc) or public
+API or ABI without first discussing it on the ffmpeg-devel mailing list.
+Do not remove functionality from the code. Just improve!
+
+Note: Redundant code can be removed.
+
+@item
+Do not commit changes to the build system (Makefiles, configure script)
+which change behavior, defaults etc, without asking first. The same
+applies to compiler warning fixes, trivial looking fixes and to code
+maintained by other developers. We usually have a reason for doing things
+the way we do. Send your changes as patches to the ffmpeg-devel mailing
+list, and if the code maintainers say OK, you may commit. This does not
+apply to files you wrote and/or maintain.
+
+@item
+We refuse source indentation and other cosmetic changes if they are mixed
+with functional changes, such commits will be rejected and removed. Every
+developer has his own indentation style, you should not change it. Of course
+if you (re)write something, you can use your own style, even though we would
+prefer if the indentation throughout FFmpeg was consistent (Many projects
+force a given indentation style - we do not.). If you really need to make
+indentation changes (try to avoid this), separate them strictly from real
+changes.
+
+NOTE: If you had to put if()@{ .. @} over a large (> 5 lines) chunk of code,
+then either do NOT change the indentation of the inner part within (do not
+move it to the right)! or do so in a separate commit
+
+@item
+Always fill out the commit log message. Describe in a few lines what you
+changed and why. You can refer to mailing list postings if you fix a
+particular bug. Comments such as "fixed!" or "Changed it." are unacceptable.
+Recommended format:
+
+@example
+area changed: Short 1 line description
+
+details describing what and why and giving references.
+@end example
+
+@item
+Make sure the author of the commit is set correctly. (see git commit --author)
+If you apply a patch, send an
+answer to ffmpeg-devel (or wherever you got the patch from) saying that
+you applied the patch.
@item
When applying patches that have been discussed (at length) on the mailing
list, reference the thread in the log message.
@item
-Subscribe to the
-@uref{https://lists.libav.org/mailman/listinfo/libav-devel, libav-devel} and
-@uref{https://lists.libav.org/mailman/listinfo/libav-commits, libav-commits}
-mailing lists.
-Bugs and possible improvements or general questions regarding commits
-are discussed on libav-devel. We expect you to react if problems with
-your code are uncovered.
+Do NOT commit to code actively maintained by others without permission.
+Send a patch to ffmpeg-devel instead. If no one answers within a reasonable
+timeframe (12h for build failures and security fixes, 3 days small changes,
+1 week for big patches) then commit your patch if you think it is OK.
+Also note, the maintainer can simply ask for more time to review!
+
+@item
+Subscribe to the ffmpeg-cvslog mailing list. The diffs of all commits
+are sent there and reviewed by all the other developers. Bugs and possible
+improvements or general questions regarding commits are discussed there. We
+expect you to react if problems with your code are uncovered.
@item
Update the documentation if you change behavior or add features. If you are
-unsure how best to do this, send an [RFC] patch to libav-devel.
+unsure how best to do this, send a patch to ffmpeg-devel, the documentation
+maintainer(s) will review and commit your stuff.
@item
-All discussions and decisions should be reported on the public developer
-mailing list, so that there is a reference to them.
-Other media (e.g. IRC) should be used for coordination and immediate
-collaboration.
+Try to keep important discussions and requests (also) on the public
+developer mailing list, so that all developers can benefit from them.
@item
Never write to unallocated memory, never write over the end of arrays,
always check values read from some untrusted source before using them
-as array index or other risky things. Always use valgrind to double-check.
+as array index or other risky things.
@item
-Remember to check if you need to bump versions for the specific libav
+Remember to check if you need to bump versions for the specific libav*
parts (libavutil, libavcodec, libavformat) you are changing. You need
to change the version integer.
Incrementing the first component means no backward compatibility to
@@ -385,52 +378,59 @@ Incrementing the second component means backward compatible change
(e.g. addition of a function to the public API or extension of an
existing data structure).
Incrementing the third component means a noteworthy binary compatible
-change (e.g. encoder bug fix that matters for the decoder).
+change (e.g. encoder bug fix that matters for the decoder). The third
+component always starts at 100 to distinguish FFmpeg from Libav.
@item
-Compiler warnings indicate potential bugs or code with bad style.
+Compiler warnings indicate potential bugs or code with bad style. If a type of
+warning always points to correct and clean code, that warning should
+be disabled, not the code changed.
+Thus the remaining warnings can either be bugs or correct code.
If it is a bug, the bug has to be fixed. If it is not, the code should
be changed to not generate a warning unless that causes a slowdown
or obfuscates the code.
-If a type of warning leads to too many false positives, that warning
-should be disabled, not the code changed.
@item
-If you add a new file, give it a proper license header. Do not copy and
-paste it from a random place, use an existing file as template.
+Make sure that no parts of the codebase that you maintain are missing from the
+@file{MAINTAINERS} file. If something that you want to maintain is missing add it with
+your name after it.
+If at some point you no longer want to maintain some code, then please help
+finding a new maintainer and also don't forget updating the @file{MAINTAINERS} file.
@end enumerate
We think our rules are not too hard. If you have comments, contact us.
+@anchor{Submitting patches}
@section Submitting patches
First, read the @ref{Coding Rules} above if you did not yet, in particular
the rules regarding patch submission.
-As stated already, please do not submit a patch which contains several
-unrelated changes.
+When you submit your patch, please use @code{git format-patch} or
+@code{git send-email}. We cannot read other diffs :-)
+
+Also please do not submit a patch which contains several unrelated changes.
Split it into separate, self-contained pieces. This does not mean splitting
file by file. Instead, make the patch as small as possible while still
keeping it as a logical unit that contains an individual change, even
if it spans multiple files. This makes reviewing your patches much easier
for us and greatly increases your chances of getting your patch applied.
-Use the patcheck tool of Libav to check your patch.
+Use the patcheck tool of FFmpeg to check your patch.
The tool is located in the tools directory.
-Run the @ref{Regression Tests} before submitting a patch in order to verify
+Run the @ref{Regression tests} before submitting a patch in order to verify
it does not cause unexpected problems.
It also helps quite a bit if you tell us what the patch does (for example
'replaces lrint by lrintf'), and why (for example '*BSD isn't C99 compliant
-and has no lrint()'). This kind of explanation should be the body of the
-commit message.
+and has no lrint()')
Also please if you send several patches, send each patch as a separate mail,
do not attach several unrelated patches to the same mail.
Patches should be posted to the
-@uref{https://lists.libav.org/mailman/listinfo/libav-devel, libav-devel}
+@uref{http://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel}
mailing list. Use @code{git send-email} when possible since it will properly
send patches without requiring extra care. If you cannot, then send patches
as base64-encoded attachments, so your patch is not trashed during
@@ -439,8 +439,8 @@ transmission.
Your patch will be reviewed on the mailing list. You will likely be asked
to make some changes and are expected to send in an improved version that
incorporates the requests from the review. This process may go through
-several iterations. Once your patch is deemed good enough, it will be
-committed to the official Libav tree.
+several iterations. Once your patch is deemed good enough, some developer
+will pick it up and commit it to the official FFmpeg tree.
Give us a few days to react. But if some time passes without reaction,
send a reminder by email. Your patch should eventually be dealt with.
@@ -474,8 +474,8 @@ even if it is only a decoder?
@item
Did you add a rule to compile the appropriate files in the Makefile?
-Remember to do this even if you are just adding a format to a file that
-is already being compiled by some other rule, like a raw demuxer.
+Remember to do this even if you're just adding a format to a file that is
+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
@@ -502,15 +502,25 @@ Did you make sure it compiles standalone, i.e. with
@enumerate
@item
-Does @code{make check} pass with the patch applied?
+Does @code{make fate} pass with the patch applied?
@item
-Is the patch against latest Libav git master branch?
+Was the patch generated with git format-patch or send-email?
@item
-Are you subscribed to the
-@uref{https://lists.libav.org/mailman/listinfo/libav-devel, libav-devel}
-mailing list? (Only list subscribers are allowed to post.)
+Did you sign off your patch? (git commit -s)
+See @url{http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/SubmittingPatches} for the meaning
+of sign off.
+
+@item
+Did you provide a clear git commit log message?
+
+@item
+Is the patch against latest FFmpeg git master branch?
+
+@item
+Are you subscribed to ffmpeg-devel?
+(the list is subscribers only due to spam)
@item
Have you checked that the changes are minimal, so that the same cannot be
@@ -553,7 +563,7 @@ If the patch fixes a bug, did you provide a verbose analysis of the bug?
If the patch fixes a bug, did you provide enough information, including
a sample, so the bug can be reproduced and the fix can be verified?
Note please do not attach samples >100k to mails but rather provide a
-URL, you can upload to ftp://upload.libav.org
+URL, you can upload to ftp://upload.ffmpeg.org
@item
Did you provide a verbose summary about what the patch does change?
@@ -571,7 +581,7 @@ patch easily?
@item
If you added a new file, did you insert a license header? It should be
-taken from Libav, not randomly copied and pasted from somewhere else.
+taken from FFmpeg, not randomly copied and pasted from somewhere else.
@item
You should maintain alphabetical order in alphabetically ordered lists as
@@ -582,16 +592,24 @@ Lines with similar content should be aligned vertically when doing so
improves readability.
@item
+Consider to add a regression test for your code.
+
+@item
+If you added YASM code please check that things still work with --disable-yasm
+
+@item
Make sure you check the return values of function and return appropriate
-error codes. Especially memory allocation functions like @code{malloc()}
+error codes. Especially memory allocation functions like @code{av_malloc()}
are notoriously left unchecked, which is a serious problem.
+
+@item
+Test your code with valgrind and or Address Sanitizer to ensure it's free
+of leaks, out of array accesses, etc.
@end enumerate
@section Patch review process
-All patches posted to the
-@uref{https://lists.libav.org/mailman/listinfo/libav-devel, libav-devel}
-mailing list will be reviewed, unless they contain a
+All patches posted to ffmpeg-devel will be reviewed, unless they contain a
clear note that the patch is not for the git master branch.
Reviews and comments will be posted as replies to the patch on the
mailing list. The patch submitter then has to take care of every comment,
@@ -605,27 +623,43 @@ After a patch is approved it will be committed to the repository.
We will review all submitted patches, but sometimes we are quite busy so
especially for large patches this can take several weeks.
-When resubmitting patches, if their size grew or during the review different
-issues arisen please split the patch so each issue has a specific patch.
+If you feel that the review process is too slow and you are willing to try to
+take over maintainership of the area of code you change then just clone
+git master and maintain the area of code there. We will merge each area from
+where its best maintained.
+
+When resubmitting patches, please do not make any significant changes
+not related to the comments received during review. Such patches will
+be rejected. Instead, submit significant changes or new features as
+separate patches.
+
+@anchor{Regression tests}
+@section Regression tests
-@anchor{Regression Tests}
-@section Regression Tests
+Before submitting a patch (or committing to the repository), you should at least
+test that you did not break anything.
-Before submitting a patch (or committing to the repository), you should at
-least make sure that it does not break anything.
+Running 'make fate' accomplishes this, please see @url{fate.html} for details.
-If the code changed has already a test present in FATE you should run it,
-otherwise it is advised to add it.
+[Of course, some patches may change the results of the regression tests. In
+this case, the reference results of the regression tests shall be modified
+accordingly].
-Improvements to codec or demuxer might change the FATE results. Make sure
-to commit the update reference with the change and to explain in the comment
-why the expected result changed.
+@subsection Adding files to the fate-suite dataset
+
+When there is no muxer or encoder available to generate test media for a
+specific test then the media has to be included in the fate-suite.
+First please make sure that the sample file is as small as possible to test the
+respective decoder or demuxer sufficiently. Large files increase network
+bandwidth and disk space requirements.
+Once you have a working fate test and fate sample, provide in the commit
+message or introductory message for the patch series that you post to
+the ffmpeg-devel mailing list, a direct link to download the sample media.
-Please refer to @url{fate.html}.
@subsection Visualizing Test Coverage
-The Libav build system allows visualizing the test coverage in an easy
+The FFmpeg build system allows visualizing the test coverage in an easy
manner with the coverage tools @code{gcov}/@code{lcov}. This involves
the following steps:
@@ -637,7 +671,7 @@ the following steps:
@item
Run your test case, either manually or via FATE. This can be either
the full FATE regression suite, or any arbitrary invocation of any
- front-end tool provided by Libav, in any combination.
+ front-end tool provided by FFmpeg, in any combination.
@item
Run @code{make lcov} to generate coverage data in HTML format.
@@ -666,11 +700,11 @@ your configure line instead.
@anchor{Release process}
@section Release process
-Libav maintains a set of @strong{release branches}, which are the
+FFmpeg maintains a set of @strong{release branches}, which are the
recommended deliverable for system integrators and distributors (such as
-Linux distributions, etc.). At irregular times, a @strong{release
+Linux distributions, etc.). At regular times, a @strong{release
manager} prepares, tests and publishes tarballs on the
-@url{http://libav.org} website.
+@url{http://ffmpeg.org} website.
There are two kinds of releases:
@@ -685,7 +719,7 @@ which are named @code{release/X}, with @code{X} being the release
version number.
@end enumerate
-Note that we promise to our users that shared libraries from any Libav
+Note that we promise to our users that shared libraries from any FFmpeg
release never break programs that have been @strong{compiled} against
previous versions of @strong{the same release series} in any case!
@@ -693,7 +727,7 @@ However, from time to time, we do make API changes that require adaptations
in applications. Such changes are only allowed in (new) major releases and
require further steps such as bumping library version numbers and/or
adjustments to the symbol versioning file. Please discuss such changes
-on the @strong{libav-devel} mailing list in time to allow forward planning.
+on the @strong{ffmpeg-devel} mailing list in time to allow forward planning.
@anchor{Criteria for Point Releases}
@subsection Criteria for Point Releases
@@ -707,7 +741,7 @@ Fixes a security issue, preferably identified by a @strong{CVE
number} issued by @url{http://cve.mitre.org/}.
@item
-Fixes a documented bug in @url{http://bugzilla.libav.org}.
+Fixes a documented bug in @url{https://trac.ffmpeg.org}.
@item
Improves the included documentation.
@@ -719,11 +753,6 @@ point releases of the same release branch.
The order for checking the rules is (1 OR 2 OR 3) AND 4.
-All Libav developers are welcome to nominate commits that they push to
-@code{master} by mailing the @strong{libav-stable} mailing list. The
-easiest way to do so is to include @code{CC: libav-stable@@libav.org} in
-the commit message.
-
@subsection Release Checklist
@@ -735,43 +764,31 @@ Ensure that the @file{RELEASE} file contains the version number for
the upcoming release.
@item
-File a release tracking bug in @url{http://bugzilla.libav.org}. Make
-sure that the bug has an alias named @code{ReleaseX.Y} for the
-@code{X.Y} release.
+Add the release at @url{https://trac.ffmpeg.org/admin/ticket/versions}.
@item
Announce the intent to do a release to the mailing list.
@item
-Reassign unresolved blocking bugs from previous release
-tracking bugs to the new bug.
-
-@item
-Review patch nominations that reach the @strong{libav-stable}
-mailing list, and push patches that fulfill the stable release
-criteria to the release branch.
+Make sure all relevant security fixes have been backported. See
+@url{https://ffmpeg.org/security.html}.
@item
Ensure that the FATE regression suite still passes in the release
branch on at least @strong{i386} and @strong{amd64}
-(cf. @ref{Regression Tests}).
+(cf. @ref{Regression tests}).
@item
-Prepare the release tarballs in @code{xz} and @code{gz} formats, and
-supplementing files that contain @code{md5} and @code{sha1}
-checksums.
+Prepare the release tarballs in @code{bz2} and @code{gz} formats, and
+supplementing files that contain @code{gpg} signatures
@item
-Publish the tarballs at @url{http://libav.org/releases}. Create and
-push an annotated tag in the form @code{vX}, with @code{X}
+Publish the tarballs at @url{http://ffmpeg.org/releases}. Create and
+push an annotated tag in the form @code{nX}, with @code{X}
containing the version number.
@item
-Build the tarballs with the Windows binaries, and publish them at
-@url{http://win32.libav.org/releases}.
-
-@item
-Propose and send a patch to the @strong{libav-devel} mailing list
+Propose and send a patch to the @strong{ffmpeg-devel} mailing list
with a news entry for the website.
@item
diff --git a/doc/devices.texi b/doc/devices.texi
new file mode 100644
index 0000000000..5e74a962d7
--- /dev/null
+++ b/doc/devices.texi
@@ -0,0 +1,25 @@
+@chapter Device Options
+@c man begin DEVICE OPTIONS
+
+The libavdevice library provides the same interface as
+libavformat. Namely, an input device is considered like a demuxer, and
+an output device like a muxer, and the interface and generic device
+options are the same provided by libavformat (see the ffmpeg-formats
+manual).
+
+In addition each input or output device may support so-called private
+options, which are specific for that component.
+
+Options may be set by specifying -@var{option} @var{value} in the
+FFmpeg tools, or by setting the value explicitly in the device
+@code{AVFormatContext} options or using the @file{libavutil/opt.h} API
+for programmatic use.
+
+@c man end DEVICE OPTIONS
+
+@ifclear config-writeonly
+@include indevs.texi
+@end ifclear
+@ifclear config-readonly
+@include outdevs.texi
+@end ifclear
diff --git a/doc/doxy-wrapper.sh b/doc/doxy-wrapper.sh
index d38dd0bcdd..9720e54030 100755
--- a/doc/doxy-wrapper.sh
+++ b/doc/doxy-wrapper.sh
@@ -2,14 +2,20 @@
SRC_PATH="${1}"
DOXYFILE="${2}"
+DOXYGEN="${3}"
-shift 2
+shift 3
-doxygen - <<EOF
+if [ -e "$SRC_PATH/VERSION" ]; then
+ VERSION=`cat "$SRC_PATH/VERSION"`
+else
+ VERSION=`cd "$SRC_PATH"; git describe`
+fi
+
+$DOXYGEN - <<EOF
@INCLUDE = ${DOXYFILE}
INPUT = $@
EXAMPLE_PATH = ${SRC_PATH}/doc/examples
-HTML_HEADER = ${SRC_PATH}/doc/doxy/header.html
-HTML_FOOTER = ${SRC_PATH}/doc/doxy/footer.html
-HTML_STYLESHEET = ${SRC_PATH}/doc/doxy/doxy_stylesheet.css
+HTML_TIMESTAMP = NO
+PROJECT_NUMBER = $VERSION
EOF
diff --git a/doc/doxy/doxy_stylesheet.css b/doc/doxy/doxy_stylesheet.css
deleted file mode 100644
index d6dadded57..0000000000
--- a/doc/doxy/doxy_stylesheet.css
+++ /dev/null
@@ -1,2021 +0,0 @@
-/*!
- * Bootstrap v2.1.1
- *
- * Copyright 2012 Twitter, Inc
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Designed and built with all the love in the world @twitter by @mdo and @fat.
- */
-
-html {
- font-size: 100%;
- -webkit-text-size-adjust: 100%;
- -ms-text-size-adjust: 100%;
-}
-a:focus {
- outline: thin dotted #333;
- outline: 5px auto -webkit-focus-ring-color;
- outline-offset: -2px;
-}
-a:hover,
-a:current {
- outline: 0;
-}
-img {
- /* Responsive images (ensure images don't scale beyond their parents) */
-
- max-width: 100%;
- /* Part 1: Set a maxium relative to the parent */
-
- width: auto\9;
- /* IE7-8 need help adjusting responsive images */
-
- height: auto;
- /* Part 2: Scale the height according to the width, otherwise you get stretching */
-
- vertical-align: middle;
- border: 0;
- -ms-interpolation-mode: bicubic;
-}
-body {
- margin: 0;
- font-family: sans-serif;
- font-size: 14px;
- line-height: 20px;
- color: #333333;
- background-color: #ffffff;
-}
-a {
- color: #0088cc;
- text-decoration: none;
-}
-a:hover {
- color: #005580;
- text-decoration: underline;
-}
-.container {
- width: 940px;
-}
-
-.container {
- margin-right: auto;
- margin-left: auto;
- *zoom: 1;
-}
-
-.container:before,
-.container:after {
- display: table;
- content: "";
- line-height: 0;
-}
-.container:after {
- clear: both;
-}
-.container-fluid {
- padding-right: 20px;
- padding-left: 20px;
- *zoom: 1;
-}
-small {
- font-size: 85%;
-}
-strong {
- font-weight: bold;
-}
-em {
- font-style: italic;
-}
-cite {
- font-style: normal;
-}
-.text-warning {
- color: #c09853;
-}
-.text-error {
- color: #b94a48;
-}
-.text-info {
- color: #3a87ad;
-}
-.text-success {
- color: #468847;
-}
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin: 10px 0;
- font-family: inherit;
- font-weight: bold;
- line-height: 1;
- color: inherit;
- text-rendering: optimizelegibility;
-}
-h1 small,
-h2 small,
-h3 small,
-h4 small,
-h5 small,
-h6 small {
- font-weight: normal;
- line-height: 1;
- color: #999999;
-}
-h1 {
- font-size: 30px;
- line-height: 40px;
-}
-h2 {
- font-size: 20px;
- line-height: 40px;
-}
-h3 {
- font-size: 18px;
- line-height: 40px;
-}
-h4 {
- font-size: 18px;
- line-height: 20px;
-}
-h5 {
- font-size: 14px;
- line-height: 20px;
-}
-h6 {
- font-size: 12px;
- line-height: 20px;
-}
-ul,
-ol {
- padding: 0;
- margin: 0 0 10px 25px;
-}
-ul ul,
-ul ol,
-ol ol,
-ol ul {
- margin-bottom: 0;
-}
-li {
- line-height: 20px;
-}
-ul.unstyled,
-ol.unstyled {
- margin-left: 0;
- list-style: none;
-}
-dl {
- margin-bottom: 20px;
-}
-dt,
-dd {
- line-height: 20px;
-}
-dt {
- font-weight: bold;
-}
-dd {
- margin-left: 10px;
-}
-blockquote {
- padding: 0 0 0 15px;
- margin: 0 0 20px;
- border-left: 5px solid #eeeeee;
-}
-blockquote p {
- margin-bottom: 0;
- font-size: 16px;
- font-weight: 300;
- line-height: 25px;
-}
-blockquote:before,
-blockquote:after {
- content: "";
-}
-.fragment,
-code,
-pre {
- padding: 0 3px 2px;
- font-family: monospace;
- font-size: 12px;
- color: #333333;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
-}
-.fragment,
-code {
- padding: 2px 4px;
- color: #d14;
- background-color: #f7f7f9;
- border: 1px solid #e1e1e8;
-}
-.fragment .line {
- padding-left: 2em;
- white-space: pre;
-}
-pre {
- display: block;
- padding: 9.5px;
- margin: 0 0 10px;
- font-size: 13px;
- line-height: 20px;
- word-break: break-all;
- word-wrap: break-word;
- white-space: pre-wrap;
- background-color: #f5f5f5;
- border: 1px solid #ccc;
- border: 1px solid rgba(0, 0, 0, 0.15);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-pre code {
- padding: 0;
- color: inherit;
- background-color: transparent;
- border: 0;
-}
-.label,
-.badge {
- font-size: 11.844px;
- font-weight: bold;
- line-height: 14px;
- color: #ffffff;
- vertical-align: baseline;
- white-space: nowrap;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- background-color: #999999;
-}
-.label {
- padding: 1px 4px 2px;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
-}
-.badge {
- padding: 1px 9px 2px;
- -webkit-border-radius: 9px;
- -moz-border-radius: 9px;
- border-radius: 9px;
-}
-
-.label a {
- color:#ffffff;
-}
-a.label:hover,
-a.badge:hover {
- color: #ffffff;
- text-decoration: none;
- cursor: pointer;
-}
-.label-important,
-.badge-important {
- background-color: #b94a48;
-}
-.label-important[href],
-.badge-important[href] {
- background-color: #953b39;
-}
-.label-warning,
-.badge-warning {
- background-color: #f89406;
-}
-.label-warning[href],
-.badge-warning[href] {
- background-color: #c67605;
-}
-.label-success,
-.badge-success {
- background-color: #468847;
-}
-.label-success[href],
-.badge-success[href] {
- background-color: #356635;
-}
-.label-info,
-.badge-info {
- background-color: #3a87ad;
-}
-.label-info[href],
-.badge-info[href] {
- background-color: #2d6987;
-}
-.label-inverse,
-.badge-inverse {
- background-color: #333333;
-}
-.label-inverse[href],
-.badge-inverse[href] {
- background-color: #1a1a1a;
-}
-table {
- max-width: 100%;
- background-color: transparent;
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-table [class*=span],
-.row-fluid table [class*=span] {
- display: table-cell;
- float: none;
- margin-left: 0;
-}
-fieldset {
- padding: 0;
- margin: 0;
- border: 0;
-}
-legend {
- display: block;
- width: 100%;
- padding: 0;
- margin-bottom: 20px;
- font-size: 21px;
- line-height: 40px;
- color: #333333;
- border: 0;
- border-bottom: 1px solid #e5e5e5;
-}
-legend small {
- font-size: 15px;
- color: #999999;
-}
-label,
-input,
-button,
-select,
-textarea {
- font-size: 14px;
- font-weight: normal;
- line-height: 20px;
-}
-input,
-button,
-select,
-textarea {
- font-family: sans-serif;
-}
-label {
- display: block;
- margin-bottom: 5px;
-}
-
-.tablist {
- margin-left: 0;
- margin-bottom: 20px;
- list-style: none;
-}
-.tablist > li > a {
- display: block;
-}
-.tablist > li > a:hover {
- text-decoration: none;
- background-color: #eeeeee;
-}
-.tablist > .pull-right {
- float: right;
-}
-.tablist-header {
- display: block;
- padding: 3px 15px;
- font-size: 11px;
- font-weight: bold;
- line-height: 20px;
- color: #999999;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- text-transform: uppercase;
-}
-.tablist li + .tablist-header {
- margin-top: 9px;
-}
-.tablist-list {
- padding-left: 15px;
- padding-right: 15px;
- margin-bottom: 0;
-}
-.tablist-list > li > a,
-.tablist-list .tablist-header {
- margin-left: -15px;
- margin-right: -15px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-}
-.tablist-list > li > a {
- padding: 3px 15px;
-}
-.tablist-list > .current > a,
-.tablist-list > .current > a:hover {
- color: #ffffff;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
- background-color: #0088cc;
-}
-.tablist-list [class^="icon-"] {
- margin-right: 2px;
-}
-.tablist-list .divider {
- *width: 100%;
- height: 1px;
- margin: 9px 1px;
- *margin: -5px 0 5px;
- overflow: hidden;
- background-color: #e5e5e5;
- border-bottom: 1px solid #ffffff;
-}
-.tablist-tabs,
-.tablist {
- *zoom: 1;
-}
-.tablist-tabs:before,
-.tablist:before,
-.tablist-tabs:after,
-.tablist:after {
- display: table;
- content: "";
- line-height: 0;
-}
-.tablist-tabs:after,
-.tablist:after {
- clear: both;
-}
-.tablist-tabs > li,
-.tablist > li {
- float: left;
-}
-.tablist-tabs > li > a,
-.tablist > li > a {
- padding-right: 12px;
- padding-left: 12px;
- margin-right: 2px;
- line-height: 14px;
-}
-.tablist-tabs {
- border-bottom: 1px solid #ddd;
-}
-.tablist-tabs > li {
- margin-bottom: -1px;
-}
-.tablist-tabs > li > a {
- padding-top: 8px;
- padding-bottom: 8px;
- line-height: 20px;
- border: 1px solid transparent;
- -webkit-border-radius: 4px 4px 0 0;
- -moz-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
-}
-.tablist-tabs > li > a:hover {
- border-color: #eeeeee #eeeeee #dddddd;
-}
-.tablist-tabs > .current > a,
-.tablist-tabs > .current > a:hover {
- color: #555555;
- background-color: #ffffff;
- border: 1px solid #ddd;
- border-bottom-color: transparent;
- cursor: default;
-}
-.tablist > li > a {
- padding-top: 8px;
- padding-bottom: 8px;
- margin-top: 2px;
- margin-bottom: 2px;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
-}
-.tablist > .current > a,
-.tablist > .current > a:hover {
- color: #ffffff;
- background-color: #0088cc;
-}
-.tablist-stacked > li {
- float: none;
-}
-.tablist-stacked > li > a {
- margin-right: 0;
-}
-.tablist-tabs.tablist-stacked {
- border-bottom: 0;
-}
-.tablist-tabs.tablist-stacked > li > a {
- border: 1px solid #ddd;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
-}
-.tablist-tabs.tablist-stacked > li:first-child > a {
- -webkit-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- border-top-right-radius: 4px;
- -webkit-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- border-top-left-radius: 4px;
-}
-.tablist-tabs.tablist-stacked > li:last-child > a {
- -webkit-border-bottom-right-radius: 4px;
- -moz-border-radius-bottomright: 4px;
- border-bottom-right-radius: 4px;
- -webkit-border-bottom-left-radius: 4px;
- -moz-border-radius-bottomleft: 4px;
- border-bottom-left-radius: 4px;
-}
-.tablist-tabs.tablist-stacked > li > a:hover {
- border-color: #ddd;
- z-index: 2;
-}
-.tablist.tablist-stacked > li > a {
- margin-bottom: 3px;
-}
-.tablist.tablist-stacked > li:last-child > a {
- margin-bottom: 1px;
-}
-.tablist-tabs .dropdown-menu {
- -webkit-border-radius: 0 0 6px 6px;
- -moz-border-radius: 0 0 6px 6px;
- border-radius: 0 0 6px 6px;
-}
-.tablist .dropdown-menu {
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
-}
-.tablist .dropdown-toggle .caret {
- border-top-color: #0088cc;
- border-bottom-color: #0088cc;
- margin-top: 6px;
-}
-.tablist .dropdown-toggle:hover .caret {
- border-top-color: #005580;
- border-bottom-color: #005580;
-}
-/* move down carets for tabs */
-.tablist-tabs .dropdown-toggle .caret {
- margin-top: 8px;
-}
-.tablist .current .dropdown-toggle .caret {
- border-top-color: #fff;
- border-bottom-color: #fff;
-}
-.tablist-tabs .current .dropdown-toggle .caret {
- border-top-color: #555555;
- border-bottom-color: #555555;
-}
-.tablist > .dropdown.current > a:hover {
- cursor: pointer;
-}
-.tablist-tabs .open .dropdown-toggle,
-.tablist .open .dropdown-toggle,
-.tablist > li.dropdown.open.current > a:hover {
- color: #ffffff;
- background-color: #999999;
- border-color: #999999;
-}
-.tablist li.dropdown.open .caret,
-.tablist li.dropdown.open.current .caret,
-.tablist li.dropdown.open a:hover .caret {
- border-top-color: #ffffff;
- border-bottom-color: #ffffff;
- opacity: 1;
- filter: alpha(opacity=100);
-}
-.tabs-stacked .open > a:hover {
- border-color: #999999;
-}
-.tab-content > .tab-pane,
-.pill-content > .pill-pane {
- display: none;
-}
-.tab-content > .current,
-.pill-content > .current {
- display: block;
-}
-.tabs-below > .tablist-tabs {
- border-top: 1px solid #ddd;
-}
-.tabs-below > .tablist-tabs > li {
- margin-top: -1px;
- margin-bottom: 0;
-}
-.tabs-below > .tablist-tabs > li > a {
- -webkit-border-radius: 0 0 4px 4px;
- -moz-border-radius: 0 0 4px 4px;
- border-radius: 0 0 4px 4px;
-}
-.tabs-below > .tablist-tabs > li > a:hover {
- border-bottom-color: transparent;
- border-top-color: #ddd;
-}
-.tabs-below > .tablist-tabs > .current > a,
-.tabs-below > .tablist-tabs > .current > a:hover {
- border-color: transparent #ddd #ddd #ddd;
-}
-.tabs-left > .tablist-tabs > li,
-.tabs-right > .tablist-tabs > li {
- float: none;
-}
-.tabs-left > .tablist-tabs > li > a,
-.tabs-right > .tablist-tabs > li > a {
- min-width: 74px;
- margin-right: 0;
- margin-bottom: 3px;
-}
-.tabs-left > .tablist-tabs {
- float: left;
- margin-right: 19px;
- border-right: 1px solid #ddd;
-}
-.tabs-left > .tablist-tabs > li > a {
- margin-right: -1px;
- -webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
-}
-.tabs-left > .tablist-tabs > li > a:hover {
- border-color: #eeeeee #dddddd #eeeeee #eeeeee;
-}
-.tabs-left > .tablist-tabs .current > a,
-.tabs-left > .tablist-tabs .current > a:hover {
- border-color: #ddd transparent #ddd #ddd;
- *border-right-color: #ffffff;
-}
-.tabs-right > .tablist-tabs {
- float: right;
- margin-left: 19px;
- border-left: 1px solid #ddd;
-}
-.tabs-right > .tablist-tabs > li > a {
- margin-left: -1px;
- -webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
-}
-.tabs-right > .tablist-tabs > li > a:hover {
- border-color: #eeeeee #eeeeee #eeeeee #dddddd;
-}
-.tabs-right > .tablist-tabs .current > a,
-.tabs-right > .tablist-tabs .current > a:hover {
- border-color: #ddd #ddd #ddd transparent;
- *border-left-color: #ffffff;
-}
-.tablist > .disabled > a {
- color: #999999;
-}
-.tablist > .disabled > a:hover {
- text-decoration: none;
- background-color: transparent;
- cursor: default;
-}
-.tablistbar {
- overflow: visible;
- margin-bottom: 20px;
- color: #ffffff;
- *position: relative;
- *z-index: 2;
-}
-.tablistbar-inner {
- min-height: 40px;
- padding-left: 20px;
- padding-right: 20px;
- background-color: #034c03;
- background-image: -moz-linear-gradient(top, #024002, #045f04);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#024002), to(#045f04));
- background-image: -webkit-linear-gradient(top, #024002, #045f04);
- background-image: -o-linear-gradient(top, #024002, #045f04);
- background-image: linear-gradient(to bottom, #024002, #045f04);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff024002', endColorstr='#ff045f04', GradientType=0);
- border: 1px solid #022402;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
- -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065);
- *zoom: 1;
-}
-.tablistbar-inner:before,
-.tablistbar-inner:after {
- display: table;
- content: "";
- line-height: 0;
-}
-.tablistbar-inner:after {
- clear: both;
-}
-.tablistbar .container {
- width: auto;
-}
-.tablist-collapse.collapse {
- height: auto;
-}
-.tablistbar .brand {
- float: left;
- display: block;
- padding: 10px 20px 10px;
- margin-left: -20px;
- font-size: 20px;
- font-weight: 200;
- color: #ffffff;
- text-shadow: 0 1px 0 #024002;
-}
-.tablistbar .brand:hover {
- text-decoration: none;
-}
-.tablistbar-text {
- margin-bottom: 0;
- line-height: 40px;
-}
-.tablistbar-link {
- color: #ffffff;
-}
-.tablistbar-link:hover {
- color: #333333;
-}
-.tablistbar .tablist {
- position: relative;
- left: 0;
- display: block;
- float: left;
- margin: 0 10px 0 0;
-}
-.tablistbar .tablist.pull-right {
- float: right;
- margin-right: 0;
-}
-.tablistbar .tablist > li {
- float: left;
-}
-.tablistbar .tablist > li > a {
- float: none;
- padding: 10px 15px 10px;
- color: #ffffff;
- text-decoration: none;
- text-shadow: 0 1px 0 #024002;
-}
-.tablistbar .tablist .dropdown-toggle .caret {
- margin-top: 8px;
-}
-.tablistbar .tablist > li > a:focus,
-.tablistbar .tablist > li > a:hover {
- background-color: transparent;
- color: white;
- text-decoration: none;
-}
-.tablistbar .tablist > .current > a,
-.tablistbar .tablist > .current > a:hover,
-.tablistbar .tablist > .current > a:focus {
- color: #555555;
- text-decoration: none;
- background-color: #034703;
- -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
- -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
- box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
-}
-.tablistbar .btn-navbar {
- display: none;
- float: right;
- padding: 7px 10px;
- margin-left: 5px;
- margin-right: 5px;
- color: #ffffff;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- background-color: #023402;
- background-image: -moz-linear-gradient(top, #012701, #034703);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#012701), to(#034703));
- background-image: -webkit-linear-gradient(top, #012701, #034703);
- background-image: -o-linear-gradient(top, #012701, #034703);
- background-image: linear-gradient(to bottom, #012701, #034703);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff012701', endColorstr='#ff034703', GradientType=0);
- border-color: #034703 #034703 #000000;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- *background-color: #034703;
- /* Darken IE7 buttons by default so they stand out more given they won't have borders */
-
- filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-}
-.tablistbar .tablist > li > .dropdown-menu:before {
- content: '';
- display: inline-block;
- border-left: 7px solid transparent;
- border-right: 7px solid transparent;
- border-bottom: 7px solid #ccc;
- border-bottom-color: rgba(0, 0, 0, 0.2);
- position: absolute;
- top: -7px;
- left: 9px;
-}
-.tablistbar .tablist > li > .dropdown-menu:after {
- content: '';
- display: inline-block;
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
- border-bottom: 6px solid #ffffff;
- position: absolute;
- top: -6px;
- left: 10px;
-}
-.tablistbar .tablist li.dropdown.open > .dropdown-toggle,
-.tablistbar .tablist li.dropdown.current > .dropdown-toggle,
-.tablistbar .tablist li.dropdown.open.current > .dropdown-toggle {
- background-color: #034703;
- color: #555555;
-}
-.tablistbar .tablist li.dropdown > .dropdown-toggle .caret {
- border-top-color: #ffffff;
- border-bottom-color: #ffffff;
-}
-.tablistbar .tablist li.dropdown.open > .dropdown-toggle .caret,
-.tablistbar .tablist li.dropdown.current > .dropdown-toggle .caret,
-.tablistbar .tablist li.dropdown.open.current > .dropdown-toggle .caret {
- border-top-color: #555555;
- border-bottom-color: #555555;
-}
-.tablistbar .pull-right > li > .dropdown-menu,
-.tablistbar .tablist > li > .dropdown-menu.pull-right {
- left: auto;
- right: 0;
-}
-.tablistbar .pull-right > li > .dropdown-menu:before,
-.tablistbar .tablist > li > .dropdown-menu.pull-right:before {
- left: auto;
- right: 12px;
-}
-.tablistbar .pull-right > li > .dropdown-menu:after,
-.tablistbar .tablist > li > .dropdown-menu.pull-right:after {
- left: auto;
- right: 13px;
-}
-.tablistbar .pull-right > li > .dropdown-menu .dropdown-menu,
-.tablistbar .tablist > li > .dropdown-menu.pull-right .dropdown-menu {
- left: auto;
- right: 100%;
- margin-left: 0;
- margin-right: -1px;
- -webkit-border-radius: 6px 0 6px 6px;
- -moz-border-radius: 6px 0 6px 6px;
- border-radius: 6px 0 6px 6px;
-}
-.breadcrumb {
- padding: 8px 15px;
- margin: 0 0 20px;
- list-style: none;
- background-color: #f5f5f5;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.breadcrumb li {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
-
- *zoom: 1;
- text-shadow: 0 1px 0 #ffffff;
-}
-.breadcrumb .divider {
- padding: 0 5px;
- color: #ccc;
-}
-.breadcrumb .current {
- color: #999999;
-}
-.pagination-right {
- text-align: right;
-}
-.fade {
- opacity: 0;
- -webkit-transition: opacity 0.15s linear;
- -moz-transition: opacity 0.15s linear;
- -o-transition: opacity 0.15s linear;
- transition: opacity 0.15s linear;
-}
-.fade.in {
- opacity: 1;
-}
-.collapse {
- position: relative;
- height: 0;
- overflow: hidden;
- -webkit-transition: height 0.35s ease;
- -moz-transition: height 0.35s ease;
- -o-transition: height 0.35s ease;
- transition: height 0.35s ease;
-}
-.collapse.in {
- height: auto;
-}
-.hidden {
- display: none;
- visibility: hidden;
-}
-.visible-phone {
- display: none !important;
-}
-.visible-tablet {
- display: none !important;
-}
-.hidden-desktop {
- display: none !important;
-}
-.visible-desktop {
- display: inherit !important;
-}
-@media (min-width: 768px) and (max-width: 979px) {
- .hidden-desktop {
- display: inherit !important;
- }
- .visible-desktop {
- display: none !important ;
- }
- .visible-tablet {
- display: inherit !important;
- }
- .hidden-tablet {
- display: none !important;
- }
-}
-@media (max-width: 767px) {
- .hidden-desktop {
- display: inherit !important;
- }
- .visible-desktop {
- display: none !important;
- }
- .visible-phone {
- display: inherit !important;
- }
- .hidden-phone {
- display: none !important;
- }
-}
-@media (max-width: 767px) {
- body {
- padding-left: 20px;
- padding-right: 20px;
- }
- .container {
- width: auto;
- }
- .row,
- .thumbnails {
- margin-left: 0;
- }
-}
-@media (max-width: 480px) {
- .tablist-collapse {
- -webkit-transform: translate3d(0, 0, 0);
- }
- .page-header h1 small {
- display: block;
- line-height: 20px;
- }
-}
-@media (min-width: 768px) and (max-width: 979px) {
- .row {
- margin-left: -20px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- content: "";
- line-height: 0;
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- min-height: 1px;
- margin-left: 20px;
- }
- .container {
- width: 724px;
- }
-}
-@media (min-width: 1200px) {
- .row {
- margin-left: -30px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- content: "";
- line-height: 0;
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- min-height: 1px;
- margin-left: 30px;
- }
- .container {
- width: 1070px;
- }
-}
-@media (max-width: 979px) {
- body {
- padding-top: 0;
- }
-}
-@media (min-width: 980px) {
- .tablist-collapse.collapse {
- height: auto !important;
- overflow: visible !important;
- }
-}
-.tablistbar .brand {
- padding: 5px;
- margin-left: 0;
-}
-.tablistbar .brand img {
- width: 30px;
- vertical-align: middle;
-}
-
-h1 small {
- font-size: 18px;
-}
-
-h1 small,
-h2 small,
-h3 small,
-h4 small,
-h5 small,
-h6 small,
-.page-header small {
- line-height: 0.8;
- font-weight: normal;
- color: #999999;
- display:block;
- vertical-align: middle;
-}
-
-.page-header h1, h1:first-child {
- font-size: 40px;
- padding-bottom: 5px;
-}
-
-.page-header h1 {
- border-bottom: 1px solid #999999;
- padding-bottom: 9px;
-}
-
-.page-header img {
- height: 80px;
- padding-bottom: 5px;
-}
-
-.page-header small {
- line-height: 1.1;
- font-size: 18px;
-}
-
-h2,
-h3,
-h4,
-div.ah,
-.title {
- border-color: #D6E9C6;
- color: #468847;
- border-style: solid;
- border-width: 0 0 1px;
- padding-left: 0.5em;
-}
-
-
-.google {
- color: white;
-}
-
-.breadcrumb {
- font-size: 11px;
- padding-top: 2px;
- padding-bottom: 2px;
-}
-
-h1 a,
-h2 a,
-h3 a,
-h4 a {
- color: inherit;
-}
-
-.tablistbar-inner a {
- font-weight: bold;
-}
-
-.list-2panes:before,
-.list-2panes:after {
- display: table;
- content: "";
- line-height: 0;
-}
-
-.list-2panes:after {
- clear:both;
-}
-
-.list-2panes li {
- width: 470px;
- width: 470px;
- float: left;
- margin-left: 30px;
- min-height: 1px;
-}
-/* The standard CSS for doxygen */
-
-/* @group Heading Levels */
-
-
-dt {
- font-weight: bold;
-}
-
-div.multicol {
- -moz-column-gap: 1em;
- -webkit-column-gap: 1em;
- -moz-column-count: 3;
- -webkit-column-count: 3;
-}
-
-p.startli, p.startdd, p.starttd {
- margin-top: 2px;
-}
-
-p.endli {
- margin-bottom: 0px;
-}
-
-p.enddd {
- margin-bottom: 4px;
-}
-
-p.endtd {
- margin-bottom: 2px;
-}
-
-/* @end */
-
-caption {
- font-weight: bold;
-}
-
-span.legend {
- font-size: 70%;
- text-align: center;
-}
-
-h3.version {
- font-size: 90%;
- text-align: center;
-}
-
-div.qindex, div.tablisttab{
- background-color: #EBF6EB;
- border: 1px solid #A3D7A3;
- text-align: center;
-}
-
-div.qindex, div.tablistpath {
- width: 100%;
- line-height: 140%;
-}
-
-div.tablisttab {
- margin-right: 15px;
-}
-
-/* @group Link Styling */
-
-a {
- color: #3D8C3D;
- font-weight: normal;
- text-decoration: none;
-}
-
-.contents a:visited {
- color: #46A246;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-a.qindex {
- font-weight: bold;
-}
-
-a.qindexHL {
- font-weight: bold;
- background-color: #9CD49C;
- color: #ffffff;
- border: 1px double #86CA86;
-}
-
-.contents a.qindexHL:visited {
- color: #ffffff;
-}
-
-a.el {
- font-weight: bold;
-}
-
-a.elRef {
-}
-
-a.code {
- color: #4665A2;
-}
-
-a.codeRef {
- color: #4665A2;
-}
-
-/* @end */
-
-dl.el {
- margin-left: -1cm;
-}
-
-.fragment {
- font-family: monospace, fixed;
- font-size: 105%;
-}
-
-pre.fragment {
- border: 1px solid #C4E5C4;
- background-color: #FBFDFB;
- padding: 4px 6px;
- margin: 4px 8px 4px 2px;
- overflow: auto;
- word-wrap: break-word;
- font-size: 9pt;
- line-height: 125%;
-}
-
-div.groupHeader {
- margin-left: 16px;
- margin-top: 12px;
- font-weight: bold;
-}
-
-div.groupText {
- margin-left: 16px;
- font-style: italic;
-}
-
-div.contents {
- margin-top: 10px;
- margin-left: 8px;
- margin-right: 8px;
-}
-
-td.indexkey {
- white-space: nowrap;
- vertical-align: top;
-}
-
-
-tr.memlist {
- background-color: #EEF7EE;
-}
-
-p.formulaDsp {
- text-align: center;
-}
-
-img.formulaDsp {
-
-}
-
-img.formulaInl {
- vertical-align: middle;
-}
-
-div.center {
- text-align: center;
- margin-top: 0px;
- margin-bottom: 0px;
- padding: 0px;
-}
-
-div.center img {
- border: 0px;
-}
-
-#footer {
- margin: -10px 1em 0;
- padding-top: 20px;
- text-align: center;
- font-size: small;
-}
-
-address.footer {
- background-color: #ffffff;
- text-align: center;
-}
-
-img.footer {
- border: 0px;
- vertical-align: middle;
-}
-
-/* @group Code Colorization */
-
-span.keyword {
- color: #008000
-}
-
-span.keywordtype {
- color: #604020
-}
-
-span.keywordflow {
- color: #e08000
-}
-
-span.comment {
- color: #800000
-}
-
-span.preprocessor {
- color: #806020
-}
-
-span.stringliteral {
- color: #002080
-}
-
-span.charliteral {
- color: #008080
-}
-
-span.vhdldigit {
- color: #ff00ff
-}
-
-span.vhdlchar {
- color: #000000
-}
-
-span.vhdlkeyword {
- color: #700070
-}
-
-span.vhdllogic {
- color: #ff0000
-}
-
-/* @end */
-
-/*
-.search {
- color: #003399;
- font-weight: bold;
-}
-
-form.search {
- margin-bottom: 0px;
- margin-top: 0px;
-}
-
-input.search {
- font-size: 75%;
- color: #000080;
- font-weight: normal;
- background-color: #e8eef2;
-}
-*/
-
-td.tiny {
- font-size: 75%;
-}
-
-.dirtab {
- padding: 4px;
- border-collapse: collapse;
- border: 1px solid #A3D7A3;
-}
-
-th.dirtab {
- background: #EBF6EB;
- font-weight: bold;
-}
-
-hr {
- height: 0px;
- border: none;
- border-top: 1px solid #4AAA4A;
-}
-
-hr.footer {
- height: 1px;
-}
-
-/* @group Member Descriptions */
-
-table.memberdecls {
- border-spacing: 0px;
- padding: 0px;
-}
-
-.mdescLeft, .mdescRight,
-.memItemLeft, .memItemRight,
-.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
- background-color: #F9FCF9;
- border: none;
- margin: 4px;
- padding: 1px 0 0 8px;
-}
-
-.mdescLeft, .mdescRight {
- padding: 0px 8px 4px 8px;
- color: #555;
-}
-
-.memItemLeft, .memItemRight, .memTemplParams {
- border-top: 1px solid #C4E5C4;
-}
-
-.memItemLeft, .memTemplItemLeft {
- white-space: nowrap;
-}
-
-.memItemRight {
- width: 100%;
-}
-
-.memTemplParams {
- color: #46A246;
- white-space: nowrap;
-}
-
-/* @end */
-
-/* @group Member Details */
-
-/* Styles for detailed member documentation */
-
-.memtemplate {
- font-size: 80%;
- color: #46A246;
- font-weight: normal;
- margin-left: 9px;
-}
-
-.memnav {
- background-color: #EBF6EB;
- border: 1px solid #A3D7A3;
- text-align: center;
- margin: 2px;
- margin-right: 15px;
- padding: 2px;
-}
-
-.mempage {
- width: 100%;
-}
-
-.memitem {
- padding: 0;
- margin-bottom: 10px;
- margin-right: 5px;
-}
-
-.memname {
- white-space: nowrap;
- font-weight: bold;
- margin-left: 6px;
-}
-
-.memproto, dl.reflist dt {
- border-top: 1px solid #A8D9A8;
- border-left: 1px solid #A8D9A8;
- border-right: 1px solid #A8D9A8;
- padding: 6px 0px 6px 0px;
- color: #255525;
- font-weight: bold;
- text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
- /* opera specific markup */
- box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
- border-top-right-radius: 8px;
- border-top-left-radius: 8px;
- /* firefox specific markup */
- -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
- -moz-border-radius-topright: 8px;
- -moz-border-radius-topleft: 8px;
- /* webkit specific markup */
- -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
- -webkit-border-top-right-radius: 8px;
- -webkit-border-top-left-radius: 8px;
- background-repeat:repeat-x;
- background-color: #E2F2E2;
-
-}
-
-.memdoc, dl.reflist dd {
- border-bottom: 1px solid #A8D9A8;
- border-left: 1px solid #A8D9A8;
- border-right: 1px solid #A8D9A8;
- padding: 2px 5px;
- background-color: #FBFDFB;
- border-top-width: 0;
- /* opera specific markup */
- border-bottom-left-radius: 8px;
- border-bottom-right-radius: 8px;
- box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
- /* firefox specific markup */
- -moz-border-radius-bottomleft: 8px;
- -moz-border-radius-bottomright: 8px;
- -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
- background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7FBF7 95%, #EEF7EE);
- /* webkit specific markup */
- -webkit-border-bottom-left-radius: 8px;
- -webkit-border-bottom-right-radius: 8px;
- -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
- background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7FBF7), to(#EEF7EE));
-}
-
-dl.reflist dt {
- padding: 5px;
-}
-
-dl.reflist dd {
- margin: 0px 0px 10px 0px;
- padding: 5px;
-}
-
-.paramkey {
- text-align: right;
-}
-
-.paramtype {
- white-space: nowrap;
-}
-
-.paramname {
- color: #602020;
- white-space: nowrap;
-}
-.paramname em {
- font-style: normal;
-}
-
-.params, .retval, .exception, .tparams {
- border-spacing: 6px 2px;
-}
-
-.params .paramname, .retval .paramname {
- font-weight: bold;
- vertical-align: top;
-}
-
-.params .paramtype {
- font-style: italic;
- vertical-align: top;
-}
-
-.params .paramdir {
- font-family: "courier new",courier,monospace;
- vertical-align: top;
-}
-
-
-
-
-/* @end */
-
-/* @group Directory (tree) */
-
-/* for the tree view */
-
-.ftvtree {
- font-family: sans-serif;
- margin: 0px;
-}
-
-/* these are for tree view when used as main index */
-
-.directory {
- font-size: 9pt;
- font-weight: bold;
- margin: 5px;
-}
-
-.directory h3 {
- margin: 0px;
- margin-top: 1em;
- font-size: 11pt;
-}
-
-/*
-The following two styles can be used to replace the root node title
-with an image of your choice. Simply uncomment the next two styles,
-specify the name of your image and be sure to set 'height' to the
-proper pixel height of your image.
-*/
-
-/*
-.directory h3.swap {
- height: 61px;
- background-repeat: no-repeat;
- background-image: url("yourimage.gif");
-}
-.directory h3.swap span {
- display: none;
-}
-*/
-
-.directory > h3 {
- margin-top: 0;
-}
-
-.directory p {
- margin: 0px;
- white-space: nowrap;
-}
-
-.directory div {
- display: none;
- margin: 0px;
-}
-
-.directory img {
- vertical-align: -30%;
-}
-
-/* these are for tree view when not used as main index */
-
-.directory-alt {
- font-size: 100%;
- font-weight: bold;
-}
-
-.directory-alt h3 {
- margin: 0px;
- margin-top: 1em;
- font-size: 11pt;
-}
-
-.directory-alt > h3 {
- margin-top: 0;
-}
-
-.directory-alt p {
- margin: 0px;
- white-space: nowrap;
-}
-
-.directory-alt div {
- display: none;
- margin: 0px;
-}
-
-.directory-alt img {
- vertical-align: -30%;
-}
-
-/* @end */
-
-div.dynheader {
- margin-top: 8px;
-}
-
-address {
- font-style: normal;
- color: #2A612A;
-}
-
-table.doxtable {
- border-collapse:collapse;
-}
-
-table.doxtable td, table.doxtable th {
- border: 1px solid #2D682D;
- padding: 3px 7px 2px;
-}
-
-table.doxtable th {
- background-color: #377F37;
- color: #FFFFFF;
- font-size: 110%;
- padding-bottom: 4px;
- padding-top: 5px;
- text-align:left;
-}
-
-table.fieldtable {
- width: 100%;
- margin-bottom: 10px;
- border: 1px solid #A8D9A8;
- border-spacing: 0px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
- -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
- box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
-}
-
-.fieldtable td, .fieldtable th {
- padding: 3px 7px 2px;
-}
-
-.fieldtable td.fieldtype, .fieldtable td.fieldname {
- white-space: nowrap;
- border-right: 1px solid #A8D9A8;
- border-bottom: 1px solid #A8D9A8;
- vertical-align: top;
-}
-
-.fieldtable td.fielddoc {
- border-bottom: 1px solid #A8D9A8;
- width: 100%;
-}
-
-.fieldtable tr:last-child td {
- border-bottom: none;
-}
-
-.fieldtable th {
- background-repeat:repeat-x;
- background-color: #E2F2E2;
- font-size: 90%;
- color: #255525;
- padding-bottom: 4px;
- padding-top: 5px;
- text-align:left;
- -moz-border-radius-topleft: 4px;
- -moz-border-radius-topright: 4px;
- -webkit-border-top-left-radius: 4px;
- -webkit-border-top-right-radius: 4px;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- border-bottom: 1px solid #A8D9A8;
-}
-
-
-.tabsearch {
- top: 0px;
- left: 10px;
- height: 36px;
- z-index: 101;
- overflow: hidden;
- font-size: 13px;
-}
-
-.tablistpath ul
-{
- font-size: 11px;
- background-repeat:repeat-x;
- height:30px;
- line-height:30px;
- color:#8ACC8A;
- border:solid 1px #C2E4C2;
- overflow:hidden;
- margin:0px;
- padding:0px;
-}
-
-.tablistpath li
-{
- list-style-type:none;
- float:left;
- padding-left:10px;
- padding-right:15px;
- background-repeat:no-repeat;
- background-position:right;
- color:#367C36;
-}
-
-.tablistpath li.tablistelem a
-{
- height:32px;
- display:block;
- text-decoration: none;
- outline: none;
-}
-
-.tablistpath li.tablistelem a:hover
-{
- color:#68BD68;
-}
-
-.tablistpath li.footer
-{
- list-style-type:none;
- float:right;
- padding-left:10px;
- padding-right:15px;
- background-image:none;
- background-repeat:no-repeat;
- background-position:right;
- color:#367C36;
- font-size: 8pt;
-}
-
-
-div.summary
-{
- margin-top: 12px;
- text-align: center;
-}
-
-div.summary a
-{
- white-space: nowrap;
-}
-
-div.ingroups
-{
- margin-left: 5px;
- font-size: 8pt;
- padding-left: 5px;
- width: 50%;
- text-align: left;
-}
-
-div.ingroups a
-{
- white-space: nowrap;
-}
-
-div.headertitle
-{
- padding: 5px 5px 5px 7px;
-}
-
-dl
-{
- padding: 0 0 0 10px;
-}
-
-dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug
-{
- border-left:4px solid;
- padding: 0 0 0 6px;
-}
-
-dl.note
-{
- border-color: #D0C000;
-}
-
-dl.warning, dl.attention
-{
- border-color: #FF0000;
-}
-
-dl.pre, dl.post, dl.invariant
-{
- border-color: #00D000;
-}
-
-dl.deprecated
-{
- border-color: #505050;
-}
-
-dl.todo
-{
- border-color: #00C0E0;
-}
-
-dl.test
-{
- border-color: #3030E0;
-}
-
-dl.bug
-{
- border-color: #C08050;
-}
-
-#projectlogo
-{
- text-align: center;
- vertical-align: bottom;
- border-collapse: separate;
-}
-
-#projectlogo img
-{
- border: 0px none;
-}
-
-#projectname
-{
- font: 300% Tahoma, Arial,sans-serif;
- margin: 0px;
- padding: 2px 0px;
-}
-
-#projectbrief
-{
- font: 120% Tahoma, Arial,sans-serif;
- margin: 0px;
- padding: 0px;
-}
-
-#projectnumber
-{
- font: 50% Tahoma, Arial,sans-serif;
- margin: 0px;
- padding: 0px;
-}
-
-#titlearea
-{
- padding: 0px;
- margin: 0px;
- width: 100%;
- border-bottom: 1px solid #53B453;
-}
-
-.image
-{
- text-align: center;
-}
-
-.dotgraph
-{
- text-align: center;
-}
-
-.mscgraph
-{
- text-align: center;
-}
-
-.caption
-{
- font-weight: bold;
-}
-
-div.zoom
-{
- border: 1px solid #90CE90;
-}
-
-dl.citelist {
- margin-bottom:50px;
-}
-
-dl.citelist dt {
- color:#337533;
- float:left;
- font-weight:bold;
- margin-right:10px;
- padding:5px;
-}
-
-dl.citelist dd {
- margin:2px 0;
- padding:5px 0;
-}
-
-@media print
-{
- #top { display: none; }
- #side-nav { display: none; }
- #nav-path { display: none; }
- body { overflow:visible; }
- h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
- .summary { display: none; }
- .memitem { page-break-inside: avoid; }
- #doc-content
- {
- margin-left:0 !important;
- height:auto !important;
- width:auto !important;
- overflow:inherit;
- display:inline;
- }
- pre.fragment
- {
- overflow: visible;
- text-wrap: unrestricted;
- white-space: -moz-pre-wrap; /* Moz */
- white-space: -pre-wrap; /* Opera 4-6 */
- white-space: -o-pre-wrap; /* Opera 7 */
- white-space: pre-wrap; /* CSS3 */
- word-wrap: break-word; /* IE 5.5+ */
- }
-}
-
-#proj_desc {
- font-size: 1.2em;
-}
diff --git a/doc/doxy/footer.html b/doc/doxy/footer.html
deleted file mode 100644
index 101e6fe70b..0000000000
--- a/doc/doxy/footer.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
- <footer class="footer pagination-right">
- <span class="label label-info">
- Generated on $datetime for $projectname by&#160;<a href="http://www.doxygen.org/index.html">doxygen</a> $doxygenversion
- </span>
- </footer>
-</div>
-</body>
-</html>
diff --git a/doc/doxy/header.html b/doc/doxy/header.html
deleted file mode 100644
index 312990cdbc..0000000000
--- a/doc/doxy/header.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
-<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
-<link href="$relpath$doxy_stylesheet.css" rel="stylesheet" type="text/css" />
-<!--Header replace -->
-
-</head>
-
-<div class="container">
-
-<!--Header replace -->
-<div class="menu">
diff --git a/doc/encoders.texi b/doc/encoders.texi
index 94d834077a..753e683332 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -1,10 +1,10 @@
@chapter Encoders
@c man begin ENCODERS
-Encoders are configured elements in Libav which allow the encoding of
+Encoders are configured elements in FFmpeg which allow the encoding of
multimedia streams.
-When you configure your Libav build, all the supported native encoders
+When you configure your FFmpeg build, all the supported native encoders
are enabled by default. Encoders requiring an external library must be enabled
manually via the corresponding @code{--enable-lib} option. You can list all
available encoders using the configure option @code{--list-encoders}.
@@ -14,7 +14,7 @@ You can disable all the encoders with the configure option
with the options @code{--enable-encoder=@var{ENCODER}} /
@code{--disable-encoder=@var{ENCODER}}.
-The option @code{-encoders} of the av* tools will display the list of
+The option @code{-encoders} of the ff* tools will display the list of
enabled encoders.
@c man end ENCODERS
@@ -25,6 +25,88 @@ enabled encoders.
A description of some of the currently available audio encoders
follows.
+@anchor{aacenc}
+@section aac
+
+Advanced Audio Coding (AAC) encoder.
+
+This encoder is an experimental FFmpeg-native AAC encoder. Currently only the
+low complexity (AAC-LC) profile is supported. To use this encoder, you must set
+@option{strict} option to @samp{experimental} or lower.
+
+As this encoder is experimental, unexpected behavior may exist from time to
+time. For a more stable AAC encoder, see @ref{libvo-aacenc}. However, be warned
+that it has a worse quality reported by some users.
+
+@c todo @ref{libaacplus}
+See also @ref{libfdk-aac-enc,,libfdk_aac} and @ref{libfaac}.
+
+@subsection Options
+
+@table @option
+@item b
+Set bit rate in bits/s. Setting this automatically activates constant bit rate
+(CBR) mode.
+
+@item q
+Set quality for variable bit rate (VBR) mode. This option is valid only using
+the @command{ffmpeg} command-line tool. For library interface users, use
+@option{global_quality}.
+
+@item stereo_mode
+Set stereo encoding mode. Possible values:
+
+@table @samp
+@item auto
+Automatically selected by the encoder.
+
+@item ms_off
+Disable middle/side encoding. This is the default.
+
+@item ms_force
+Force middle/side encoding.
+@end table
+
+@item aac_coder
+Set AAC encoder coding method. Possible values:
+
+@table @samp
+@item faac
+FAAC-inspired method.
+
+This method is a simplified reimplementation of the method used in FAAC, which
+sets thresholds proportional to the band energies, and then decreases all the
+thresholds with quantizer steps to find the appropriate quantization with
+distortion below threshold band by band.
+
+The quality of this method is comparable to the two loop searching method
+described below, but somewhat a little better and slower.
+
+@item anmr
+Average noise to mask ratio (ANMR) trellis-based solution.
+
+This has a theoretic best quality out of all the coding methods, but at the
+cost of the slowest speed.
+
+@item twoloop
+Two loop searching (TLS) method.
+
+This method first sets quantizers depending on band thresholds and then tries
+to find an optimal combination by adding or subtracting a specific value from
+all quantizers and adjusting some individual quantizer a little.
+
+This method produces similar quality with the FAAC method and is the default.
+
+@item fast
+Constant quantizer method.
+
+This method sets a constant quantizer for all bands. This is the fastest of all
+the methods, yet produces the worst quality.
+
+@end table
+
+@end table
+
@section ac3 and ac3_fixed
AC-3 audio encoders.
@@ -369,7 +451,7 @@ is highly recommended that it be left as enabled except for testing purposes.
@end table
-@subheading Floating-Point-Only AC-3 Encoding Options
+@subsection Floating-Point-Only AC-3 Encoding Options
These options are only valid for the floating-point encoder and do not exist
for the fixed-point encoder due to the corresponding features not being
@@ -412,32 +494,843 @@ Selected by Encoder (default)
@end table
+@anchor{flac}
+@section flac
+
+FLAC (Free Lossless Audio Codec) Encoder
+
+@subsection Options
+
+The following options are supported by FFmpeg's flac encoder.
+
+@table @option
+@item compression_level
+Sets the compression level, which chooses defaults for many other options
+if they are not set explicitly.
+
+@item frame_size
+Sets the size of the frames in samples per channel.
+
+@item lpc_coeff_precision
+Sets the LPC coefficient precision, valid values are from 1 to 15, 15 is the
+default.
+
+@item lpc_type
+Sets the first stage LPC algorithm
+@table @samp
+@item none
+LPC is not used
+
+@item fixed
+fixed LPC coefficients
+
+@item levinson
+
+@item cholesky
+@end table
+
+@item lpc_passes
+Number of passes to use for Cholesky factorization during LPC analysis
+
+@item min_partition_order
+The minimum partition order
+
+@item max_partition_order
+The maximum partition order
+
+@item prediction_order_method
+@table @samp
+@item estimation
+@item 2level
+@item 4level
+@item 8level
+@item search
+Bruteforce search
+@item log
+@end table
+
+@item ch_mode
+Channel mode
+@table @samp
+@item auto
+The mode is chosen automatically for each frame
+@item indep
+Chanels are independently coded
+@item left_side
+@item right_side
+@item mid_side
+@end table
+
+@item exact_rice_parameters
+Chooses if rice parameters are calculated exactly or approximately.
+if set to 1 then they are chosen exactly, which slows the code down slightly and
+improves compression slightly.
+
+@item multi_dim_quant
+Multi Dimensional Quantization. If set to 1 then a 2nd stage LPC algorithm is
+applied after the first stage to finetune the coefficients. This is quite slow
+and slightly improves compression.
+
+@end table
+
+@anchor{libfaac}
+@section libfaac
+
+libfaac AAC (Advanced Audio Coding) encoder wrapper.
+
+Requires the presence of the libfaac headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libfaac --enable-nonfree}.
+
+This encoder is considered to be of higher quality with respect to the
+@ref{aacenc,,the native experimental FFmpeg AAC encoder}.
+
+For more information see the libfaac project at
+@url{http://www.audiocoding.com/faac.html/}.
+
+@subsection Options
+
+The following shared FFmpeg codec options are recognized.
+
+The following options are supported by the libfaac wrapper. The
+@command{faac}-equivalent of the options are listed in parentheses.
+
+@table @option
+@item b (@emph{-b})
+Set bit rate in bits/s for ABR (Average Bit Rate) mode. If the bit rate
+is not explicitly specified, it is automatically set to a suitable
+value depending on the selected profile. @command{faac} bitrate is
+expressed in kilobits/s.
+
+Note that libfaac does not support CBR (Constant Bit Rate) but only
+ABR (Average Bit Rate).
+
+If VBR mode is enabled this option is ignored.
+
+@item ar (@emph{-R})
+Set audio sampling rate (in Hz).
+
+@item ac (@emph{-c})
+Set the number of audio channels.
+
+@item cutoff (@emph{-C})
+Set cutoff frequency. If not specified (or explicitly set to 0) it
+will use a value automatically computed by the library. Default value
+is 0.
+
+@item profile
+Set audio profile.
+
+The following profiles are recognized:
+@table @samp
+@item aac_main
+Main AAC (Main)
+
+@item aac_low
+Low Complexity AAC (LC)
+
+@item aac_ssr
+Scalable Sample Rate (SSR)
+
+@item aac_ltp
+Long Term Prediction (LTP)
+@end table
+
+If not specified it is set to @samp{aac_low}.
+
+@item flags +qscale
+Set constant quality VBR (Variable Bit Rate) mode.
+
+@item global_quality
+Set quality in VBR mode as an integer number of lambda units.
+
+Only relevant when VBR mode is enabled with @code{flags +qscale}. The
+value is converted to QP units by dividing it by @code{FF_QP2LAMBDA},
+and used to set the quality value used by libfaac. A reasonable range
+for the option value in QP units is [10-500], the higher the value the
+higher the quality.
+
+@item q (@emph{-q})
+Enable VBR mode when set to a non-negative value, and set constant
+quality value as a double floating point value in QP units.
+
+The value sets the quality value used by libfaac. A reasonable range
+for the option value is [10-500], the higher the value the higher the
+quality.
+
+This option is valid only using the @command{ffmpeg} command-line
+tool. For library interface users, use @option{global_quality}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Use @command{ffmpeg} to convert an audio file to ABR 128 kbps AAC in an M4A (MP4)
+container:
+@example
+ffmpeg -i input.wav -codec:a libfaac -b:a 128k -output.m4a
+@end example
+
+@item
+Use @command{ffmpeg} to convert an audio file to VBR AAC, using the
+LTP AAC profile:
+@example
+ffmpeg -i input.wav -c:a libfaac -profile:a aac_ltp -q:a 100 output.m4a
+@end example
+@end itemize
+
+@anchor{libfdk-aac-enc}
+@section libfdk_aac
+
+libfdk-aac AAC (Advanced Audio Coding) encoder wrapper.
+
+The libfdk-aac library is based on the Fraunhofer FDK AAC code from
+the Android project.
+
+Requires the presence of the libfdk-aac headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libfdk-aac}. The library is also incompatible with GPL,
+so if you allow the use of GPL, you should configure with
+@code{--enable-gpl --enable-nonfree --enable-libfdk-aac}.
+
+This encoder is considered to be of higher quality with respect to
+both @ref{aacenc,,the native experimental FFmpeg AAC encoder} and
+@ref{libfaac}.
+
+VBR encoding, enabled through the @option{vbr} or @option{flags
++qscale} options, is experimental and only works with some
+combinations of parameters.
+
+Support for encoding 7.1 audio is only available with libfdk-aac 0.1.3 or
+higher.
+
+For more information see the fdk-aac project at
+@url{http://sourceforge.net/p/opencore-amr/fdk-aac/}.
+
+@subsection Options
+
+The following options are mapped on the shared FFmpeg codec options.
+
+@table @option
+@item b
+Set bit rate in bits/s. If the bitrate is not explicitly specified, it
+is automatically set to a suitable value depending on the selected
+profile.
+
+In case VBR mode is enabled the option is ignored.
+
+@item ar
+Set audio sampling rate (in Hz).
+
+@item channels
+Set the number of audio channels.
+
+@item flags +qscale
+Enable fixed quality, VBR (Variable Bit Rate) mode.
+Note that VBR is implicitly enabled when the @option{vbr} value is
+positive.
+
+@item cutoff
+Set cutoff frequency. If not specified (or explicitly set to 0) it
+will use a value automatically computed by the library. Default value
+is 0.
+
+@item profile
+Set audio profile.
+
+The following profiles are recognized:
+@table @samp
+@item aac_low
+Low Complexity AAC (LC)
+
+@item aac_he
+High Efficiency AAC (HE-AAC)
+
+@item aac_he_v2
+High Efficiency AAC version 2 (HE-AACv2)
+
+@item aac_ld
+Low Delay AAC (LD)
+
+@item aac_eld
+Enhanced Low Delay AAC (ELD)
+@end table
+
+If not specified it is set to @samp{aac_low}.
+@end table
+
+The following are private options of the libfdk_aac encoder.
+
+@table @option
+@item afterburner
+Enable afterburner feature if set to 1, disabled if set to 0. This
+improves the quality but also the required processing power.
+
+Default value is 1.
+
+@item eld_sbr
+Enable SBR (Spectral Band Replication) for ELD if set to 1, disabled
+if set to 0.
+
+Default value is 0.
+
+@item signaling
+Set SBR/PS signaling style.
+
+It can assume one of the following values:
+@table @samp
+@item default
+choose signaling implicitly (explicit hierarchical by default,
+implicit if global header is disabled)
+
+@item implicit
+implicit backwards compatible signaling
+
+@item explicit_sbr
+explicit SBR, implicit PS signaling
+
+@item explicit_hierarchical
+explicit hierarchical signaling
+@end table
+
+Default value is @samp{default}.
+
+@item latm
+Output LATM/LOAS encapsulated data if set to 1, disabled if set to 0.
+
+Default value is 0.
+
+@item header_period
+Set StreamMuxConfig and PCE repetition period (in frames) for sending
+in-band configuration buffers within LATM/LOAS transport layer.
+
+Must be a 16-bits non-negative integer.
+
+Default value is 0.
+
+@item vbr
+Set VBR mode, from 1 to 5. 1 is lowest quality (though still pretty
+good) and 5 is highest quality. A value of 0 will disable VBR, and CBR
+(Constant Bit Rate) is enabled.
+
+Currently only the @samp{aac_low} profile supports VBR encoding.
+
+VBR modes 1-5 correspond to roughly the following average bit rates:
+
+@table @samp
+@item 1
+32 kbps/channel
+@item 2
+40 kbps/channel
+@item 3
+48-56 kbps/channel
+@item 4
+64 kbps/channel
+@item 5
+about 80-96 kbps/channel
+@end table
+
+Default value is 0.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Use @command{ffmpeg} to convert an audio file to VBR AAC in an M4A (MP4)
+container:
+@example
+ffmpeg -i input.wav -codec:a libfdk_aac -vbr 3 output.m4a
+@end example
+
+@item
+Use @command{ffmpeg} to convert an audio file to CBR 64k kbps AAC, using the
+High-Efficiency AAC profile:
+@example
+ffmpeg -i input.wav -c:a libfdk_aac -profile:a aac_he -b:a 64k output.m4a
+@end example
+@end itemize
+
+@anchor{libmp3lame}
+@section libmp3lame
+
+LAME (Lame Ain't an MP3 Encoder) MP3 encoder wrapper.
+
+Requires the presence of the libmp3lame headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libmp3lame}.
+
+See @ref{libshine} for a fixed-point MP3 encoder, although with a
+lower quality.
+
+@subsection Options
+
+The following options are supported by the libmp3lame wrapper. The
+@command{lame}-equivalent of the options are listed in parentheses.
+
+@table @option
+@item b (@emph{-b})
+Set bitrate expressed in bits/s for CBR or ABR. LAME @code{bitrate} is
+expressed in kilobits/s.
+
+@item q (@emph{-V})
+Set constant quality setting for VBR. This option is valid only
+using the @command{ffmpeg} command-line tool. For library interface
+users, use @option{global_quality}.
+
+@item compression_level (@emph{-q})
+Set algorithm quality. Valid arguments are integers in the 0-9 range,
+with 0 meaning highest quality but slowest, and 9 meaning fastest
+while producing the worst quality.
+
+@item reservoir
+Enable use of bit reservoir when set to 1. Default value is 1. LAME
+has this enabled by default, but can be overridden by use
+@option{--nores} option.
+
+@item joint_stereo (@emph{-m j})
+Enable the encoder to use (on a frame by frame basis) either L/R
+stereo or mid/side stereo. Default value is 1.
+
+@item abr (@emph{--abr})
+Enable the encoder to use ABR when set to 1. The @command{lame}
+@option{--abr} sets the target bitrate, while this options only
+tells FFmpeg to use ABR still relies on @option{b} to set bitrate.
+
+@end table
+
+@section libopencore-amrnb
+
+OpenCORE Adaptive Multi-Rate Narrowband encoder.
+
+Requires the presence of the libopencore-amrnb headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libopencore-amrnb --enable-version3}.
+
+This is a mono-only encoder. Officially it only supports 8000Hz sample rate,
+but you can override it by setting @option{strict} to @samp{unofficial} or
+lower.
+
+@subsection Options
+
+@table @option
+
+@item b
+Set bitrate in bits per second. Only the following bitrates are supported,
+otherwise libavcodec will round to the nearest valid bitrate.
+
+@table @option
+@item 4750
+@item 5150
+@item 5900
+@item 6700
+@item 7400
+@item 7950
+@item 10200
+@item 12200
+@end table
+
+@item dtx
+Allow discontinuous transmission (generate comfort noise) when set to 1. The
+default value is 0 (disabled).
+
+@end table
+
+@anchor{libshine}
+@section libshine
+
+Shine Fixed-Point MP3 encoder wrapper.
+
+Shine is a fixed-point MP3 encoder. It has a far better performance on
+platforms without an FPU, e.g. armel CPUs, and some phones and tablets.
+However, as it is more targeted on performance than quality, it is not on par
+with LAME and other production-grade encoders quality-wise. Also, according to
+the project's homepage, this encoder may not be free of bugs as the code was
+written a long time ago and the project was dead for at least 5 years.
+
+This encoder only supports stereo and mono input. This is also CBR-only.
+
+The original project (last updated in early 2007) is at
+@url{http://sourceforge.net/projects/libshine-fxp/}. We only support the
+updated fork by the Savonet/Liquidsoap project at @url{https://github.com/savonet/shine}.
+
+Requires the presence of the libshine headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libshine}.
+
+See also @ref{libmp3lame}.
+
+@subsection Options
+
+The following options are supported by the libshine wrapper. The
+@command{shineenc}-equivalent of the options are listed in parentheses.
+
+@table @option
+@item b (@emph{-b})
+Set bitrate expressed in bits/s for CBR. @command{shineenc} @option{-b} option
+is expressed in kilobits/s.
+
+@end table
+
+@section libtwolame
+
+TwoLAME MP2 encoder wrapper.
+
+Requires the presence of the libtwolame headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libtwolame}.
+
+@subsection Options
+
+The following options are supported by the libtwolame wrapper. The
+@command{twolame}-equivalent options follow the FFmpeg ones and are in
+parentheses.
+
+@table @option
+@item b (@emph{-b})
+Set bitrate expressed in bits/s for CBR. @command{twolame} @option{b}
+option is expressed in kilobits/s. Default value is 128k.
+
+@item q (@emph{-V})
+Set quality for experimental VBR support. Maximum value range is
+from -50 to 50, useful range is from -10 to 10. The higher the
+value, the better the quality. This option is valid only using the
+@command{ffmpeg} command-line tool. For library interface users,
+use @option{global_quality}.
+
+@item mode (@emph{--mode})
+Set the mode of the resulting audio. Possible values:
+
+@table @samp
+@item auto
+Choose mode automatically based on the input. This is the default.
+@item stereo
+Stereo
+@item joint_stereo
+Joint stereo
+@item dual_channel
+Dual channel
+@item mono
+Mono
+@end table
+
+@item psymodel (@emph{--psyc-mode})
+Set psychoacoustic model to use in encoding. The argument must be
+an integer between -1 and 4, inclusive. The higher the value, the
+better the quality. The default value is 3.
+
+@item energy_levels (@emph{--energy})
+Enable energy levels extensions when set to 1. The default value is
+0 (disabled).
+
+@item error_protection (@emph{--protect})
+Enable CRC error protection when set to 1. The default value is 0
+(disabled).
+
+@item copyright (@emph{--copyright})
+Set MPEG audio copyright flag when set to 1. The default value is 0
+(disabled).
+
+@item original (@emph{--original})
+Set MPEG audio original flag when set to 1. The default value is 0
+(disabled).
+
+@end table
+
+@anchor{libvo-aacenc}
+@section libvo-aacenc
+
+VisualOn AAC encoder.
+
+Requires the presence of the libvo-aacenc headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libvo-aacenc --enable-version3}.
+
+This encoder is considered to be worse than the
+@ref{aacenc,,native experimental FFmpeg AAC encoder}, according to
+multiple sources.
+
+@subsection Options
+
+The VisualOn AAC encoder only support encoding AAC-LC and up to 2
+channels. It is also CBR-only.
+
+@table @option
+
+@item b
+Set bit rate in bits/s.
+
+@end table
+
+@section libvo-amrwbenc
+
+VisualOn Adaptive Multi-Rate Wideband encoder.
+
+Requires the presence of the libvo-amrwbenc headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libvo-amrwbenc --enable-version3}.
+
+This is a mono-only encoder. Officially it only supports 16000Hz sample
+rate, but you can override it by setting @option{strict} to
+@samp{unofficial} or lower.
+
+@subsection Options
+
+@table @option
+
+@item b
+Set bitrate in bits/s. Only the following bitrates are supported, otherwise
+libavcodec will round to the nearest valid bitrate.
+
+@table @samp
+@item 6600
+@item 8850
+@item 12650
+@item 14250
+@item 15850
+@item 18250
+@item 19850
+@item 23050
+@item 23850
+@end table
+
+@item dtx
+Allow discontinuous transmission (generate comfort noise) when set to 1. The
+default value is 0 (disabled).
+
+@end table
+
+@section libopus
+
+libopus Opus Interactive Audio Codec encoder wrapper.
+
+Requires the presence of the libopus headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libopus}.
+
+@subsection Option Mapping
+
+Most libopus options are modelled after the @command{opusenc} utility from
+opus-tools. The following is an option mapping chart describing options
+supported by the libopus wrapper, and their @command{opusenc}-equivalent
+in parentheses.
+
+@table @option
+
+@item b (@emph{bitrate})
+Set the bit rate in bits/s. FFmpeg's @option{b} option is
+expressed in bits/s, while @command{opusenc}'s @option{bitrate} in
+kilobits/s.
+
+@item vbr (@emph{vbr}, @emph{hard-cbr}, and @emph{cvbr})
+Set VBR mode. The FFmpeg @option{vbr} option has the following
+valid arguments, with the their @command{opusenc} equivalent options
+in parentheses:
+
+@table @samp
+@item off (@emph{hard-cbr})
+Use constant bit rate encoding.
+
+@item on (@emph{vbr})
+Use variable bit rate encoding (the default).
+
+@item constrained (@emph{cvbr})
+Use constrained variable bit rate encoding.
+@end table
+
+@item compression_level (@emph{comp})
+Set encoding algorithm complexity. Valid options are integers in
+the 0-10 range. 0 gives the fastest encodes but lower quality, while 10
+gives the highest quality but slowest encoding. The default is 10.
+
+@item frame_duration (@emph{framesize})
+Set maximum frame size, or duration of a frame in milliseconds. The
+argument must be exactly the following: 2.5, 5, 10, 20, 40, 60. Smaller
+frame sizes achieve lower latency but less quality at a given bitrate.
+Sizes greater than 20ms are only interesting at fairly low bitrates.
+The default is 20ms.
+
+@item packet_loss (@emph{expect-loss})
+Set expected packet loss percentage. The default is 0.
+
+@item application (N.A.)
+Set intended application type. Valid options are listed below:
+
+@table @samp
+@item voip
+Favor improved speech intelligibility.
+@item audio
+Favor faithfulness to the input (the default).
+@item lowdelay
+Restrict to only the lowest delay modes.
+@end table
+
+@item cutoff (N.A.)
+Set cutoff bandwidth in Hz. The argument must be exactly one of the
+following: 4000, 6000, 8000, 12000, or 20000, corresponding to
+narrowband, mediumband, wideband, super wideband, and fullband
+respectively. The default is 0 (cutoff disabled).
+
+@end table
+
+@section libvorbis
+
+libvorbis encoder wrapper.
+
+Requires the presence of the libvorbisenc headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libvorbis}.
+
+@subsection Options
+
+The following options are supported by the libvorbis wrapper. The
+@command{oggenc}-equivalent of the options are listed in parentheses.
+
+To get a more accurate and extensive documentation of the libvorbis
+options, consult the libvorbisenc's and @command{oggenc}'s documentations.
+See @url{http://xiph.org/vorbis/},
+@url{http://wiki.xiph.org/Vorbis-tools}, and oggenc(1).
+
+@table @option
+@item b (@emph{-b})
+Set bitrate expressed in bits/s for ABR. @command{oggenc} @option{-b} is
+expressed in kilobits/s.
+
+@item q (@emph{-q})
+Set constant quality setting for VBR. The value should be a float
+number in the range of -1.0 to 10.0. The higher the value, the better
+the quality. The default value is @samp{3.0}.
+
+This option is valid only using the @command{ffmpeg} command-line tool.
+For library interface users, use @option{global_quality}.
+
+@item cutoff (@emph{--advanced-encode-option lowpass_frequency=N})
+Set cutoff bandwidth in Hz, a value of 0 disables cutoff. @command{oggenc}'s
+related option is expressed in kHz. The default value is @samp{0} (cutoff
+disabled).
+
+@item minrate (@emph{-m})
+Set minimum bitrate expressed in bits/s. @command{oggenc} @option{-m} is
+expressed in kilobits/s.
+
+@item maxrate (@emph{-M})
+Set maximum bitrate expressed in bits/s. @command{oggenc} @option{-M} is
+expressed in kilobits/s. This only has effect on ABR mode.
+
+@item iblock (@emph{--advanced-encode-option impulse_noisetune=N})
+Set noise floor bias for impulse blocks. The value is a float number from
+-15.0 to 0.0. A negative bias instructs the encoder to pay special attention
+to the crispness of transients in the encoded audio. The tradeoff for better
+transient response is a higher bitrate.
+
+@end table
+
+@anchor{libwavpack}
@section libwavpack
A wrapper providing WavPack encoding through libwavpack.
Only lossless mode using 32-bit integer samples is supported currently.
-The @option{compression_level} option can be used to control speed vs.
-compression tradeoff, with the values mapped to libwavpack as follows:
+
+Requires the presence of the libwavpack headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libwavpack}.
+
+Note that a libavcodec-native encoder for the WavPack codec exists so users can
+encode audios with this codec without using this encoder. See @ref{wavpackenc}.
+
+@subsection Options
+
+@command{wavpack} command line utility's corresponding options are listed in
+parentheses, if any.
@table @option
+@item frame_size (@emph{--blocksize})
+Default is 32768.
-@item 0
-Fast mode - corresponding to the wavpack @option{-f} option.
+@item compression_level
+Set speed vs. compression tradeoff. Acceptable arguments are listed below:
+
+@table @samp
+@item 0 (@emph{-f})
+Fast mode.
@item 1
Normal (default) settings.
-@item 2
-High quality - corresponding to the wavpack @option{-h} option.
+@item 2 (@emph{-h})
+High quality.
-@item 3
-Very high quality - corresponding to the wavpack @option{-hh} option.
+@item 3 (@emph{-hh})
+Very high quality.
+
+@item 4-8 (@emph{-hh -x}@var{EXTRAPROC})
+Same as @samp{3}, but with extra processing enabled.
+
+@samp{4} is the same as @option{-x2} and @samp{8} is the same as @option{-x6}.
+
+@end table
+@end table
+
+@anchor{wavpackenc}
+@section wavpack
+
+WavPack lossless audio encoder.
-@item 4-8
-Same as 3, but with extra processing enabled - corresponding to the wavpack
-@option{-x} option. I.e. 4 is the same as @option{-x2} and 8 is the same as
-@option{-x6}.
+This is a libavcodec-native WavPack encoder. There is also an encoder based on
+libwavpack, but there is virtually no reason to use that encoder.
+
+See also @ref{libwavpack}.
+
+@subsection Options
+
+The equivalent options for @command{wavpack} command line utility are listed in
+parentheses.
+
+@subsubsection Shared options
+
+The following shared options are effective for this encoder. Only special notes
+about this particular encoder will be documented here. For the general meaning
+of the options, see @ref{codec-options,,the Codec Options chapter}.
+
+@table @option
+@item frame_size (@emph{--blocksize})
+For this encoder, the range for this option is between 128 and 131072. Default
+is automatically decided based on sample rate and number of channel.
+
+For the complete formula of calculating default, see
+@file{libavcodec/wavpackenc.c}.
+
+@item compression_level (@emph{-f}, @emph{-h}, @emph{-hh}, and @emph{-x})
+This option's syntax is consistent with @ref{libwavpack}'s.
+@end table
+
+@subsubsection Private options
+
+@table @option
+@item joint_stereo (@emph{-j})
+Set whether to enable joint stereo. Valid values are:
+
+@table @samp
+@item on (@emph{1})
+Force mid/side audio encoding.
+@item off (@emph{0})
+Force left/right audio encoding.
+@item auto
+Let the encoder decide automatically.
+@end table
+
+@item optimize_mono
+Set whether to enable optimization for mono. This option is only effective for
+non-mono streams. Available values:
+
+@table @samp
+@item on
+enabled
+@item off
+disabled
+@end table
@end table
@@ -446,6 +1339,197 @@ Same as 3, but with extra processing enabled - corresponding to the wavpack
@chapter Video Encoders
@c man begin VIDEO ENCODERS
+A description of some of the currently available video encoders
+follows.
+
+@section libtheora
+
+libtheora Theora encoder wrapper.
+
+Requires the presence of the libtheora headers and library during
+configuration. You need to explicitly configure the build with
+@code{--enable-libtheora}.
+
+For more information about the libtheora project see
+@url{http://www.theora.org/}.
+
+@subsection Options
+
+The following global options are mapped to internal libtheora options
+which affect the quality and the bitrate of the encoded stream.
+
+@table @option
+@item b
+Set the video bitrate in bit/s for CBR (Constant Bit Rate) mode. In
+case VBR (Variable Bit Rate) mode is enabled this option is ignored.
+
+@item flags
+Used to enable constant quality mode (VBR) encoding through the
+@option{qscale} flag, and to enable the @code{pass1} and @code{pass2}
+modes.
+
+@item g
+Set the GOP size.
+
+@item global_quality
+Set the global quality as an integer in lambda units.
+
+Only relevant when VBR mode is enabled with @code{flags +qscale}. The
+value is converted to QP units by dividing it by @code{FF_QP2LAMBDA},
+clipped in the [0 - 10] range, and then multiplied by 6.3 to get a
+value in the native libtheora range [0-63]. A higher value corresponds
+to a higher quality.
+
+@item q
+Enable VBR mode when set to a non-negative value, and set constant
+quality value as a double floating point value in QP units.
+
+The value is clipped in the [0-10] range, and then multiplied by 6.3
+to get a value in the native libtheora range [0-63].
+
+This option is valid only using the @command{ffmpeg} command-line
+tool. For library interface users, use @option{global_quality}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Set maximum constant quality (VBR) encoding with @command{ffmpeg}:
+@example
+ffmpeg -i INPUT -codec:v libtheora -q:v 10 OUTPUT.ogg
+@end example
+
+@item
+Use @command{ffmpeg} to convert a CBR 1000 kbps Theora video stream:
+@example
+ffmpeg -i INPUT -codec:v libtheora -b:v 1000k OUTPUT.ogg
+@end example
+@end itemize
+
+@section libvpx
+
+VP8/VP9 format supported through libvpx.
+
+Requires the presence of the libvpx headers and library during configuration.
+You need to explicitly configure the build with @code{--enable-libvpx}.
+
+@subsection Options
+
+Mapping from FFmpeg to libvpx options with conversion notes in parentheses.
+
+@table @option
+
+@item threads
+g_threads
+
+@item profile
+g_profile
+
+@item vb
+rc_target_bitrate
+
+@item g
+kf_max_dist
+
+@item keyint_min
+kf_min_dist
+
+@item qmin
+rc_min_quantizer
+
+@item qmax
+rc_max_quantizer
+
+@item bufsize, vb
+rc_buf_sz
+@code{(bufsize * 1000 / vb)}
+
+rc_buf_optimal_sz
+@code{(bufsize * 1000 / vb * 5 / 6)}
+
+@item rc_init_occupancy, vb
+rc_buf_initial_sz
+@code{(rc_init_occupancy * 1000 / vb)}
+
+@item rc_buffer_aggressivity
+rc_undershoot_pct
+
+@item skip_threshold
+rc_dropframe_thresh
+
+@item qcomp
+rc_2pass_vbr_bias_pct
+
+@item maxrate, vb
+rc_2pass_vbr_maxsection_pct
+@code{(maxrate * 100 / vb)}
+
+@item minrate, vb
+rc_2pass_vbr_minsection_pct
+@code{(minrate * 100 / vb)}
+
+@item minrate, maxrate, vb
+@code{VPX_CBR}
+@code{(minrate == maxrate == vb)}
+
+@item crf
+@code{VPX_CQ}, @code{VP8E_SET_CQ_LEVEL}
+
+@item quality
+@table @option
+@item @var{best}
+@code{VPX_DL_BEST_QUALITY}
+@item @var{good}
+@code{VPX_DL_GOOD_QUALITY}
+@item @var{realtime}
+@code{VPX_DL_REALTIME}
+@end table
+
+@item speed
+@code{VP8E_SET_CPUUSED}
+
+@item nr
+@code{VP8E_SET_NOISE_SENSITIVITY}
+
+@item mb_threshold
+@code{VP8E_SET_STATIC_THRESHOLD}
+
+@item slices
+@code{VP8E_SET_TOKEN_PARTITIONS}
+
+@item max-intra-rate
+@code{VP8E_SET_MAX_INTRA_BITRATE_PCT}
+
+@item force_key_frames
+@code{VPX_EFLAG_FORCE_KF}
+
+@item Alternate reference frame related
+@table @option
+@item vp8flags altref
+@code{VP8E_SET_ENABLEAUTOALTREF}
+@item @var{arnr_max_frames}
+@code{VP8E_SET_ARNR_MAXFRAMES}
+@item @var{arnr_type}
+@code{VP8E_SET_ARNR_TYPE}
+@item @var{arnr_strength}
+@code{VP8E_SET_ARNR_STRENGTH}
+@item @var{rc_lookahead}
+g_lag_in_frames
+@end table
+
+@item vp8flags error_resilient
+g_error_resilient
+
+@item aq_mode
+@code{VP9E_SET_AQ_MODE}
+
+@end table
+
+For more information about libvpx see:
+@url{http://www.webmproject.org/}
+
+
@section libwebp
libwebp WebP Image encoder wrapper
@@ -505,6 +1589,521 @@ Small-sized colorful images
Text-like
@end table
+@end table
+
+@section libx264, libx264rgb
+
+x264 H.264/MPEG-4 AVC encoder wrapper.
+
+This encoder requires the presence of the libx264 headers and library
+during configuration. You need to explicitly configure the build with
+@code{--enable-libx264}.
+
+libx264 supports an impressive number of features, including 8x8 and
+4x4 adaptive spatial transform, adaptive B-frame placement, CAVLC/CABAC
+entropy coding, interlacing (MBAFF), lossless mode, psy optimizations
+for detail retention (adaptive quantization, psy-RD, psy-trellis).
+
+Many libx264 encoder options are mapped to FFmpeg global codec
+options, while unique encoder options are provided through private
+options. Additionally the @option{x264opts} and @option{x264-params}
+private options allows one to pass a list of key=value tuples as accepted
+by the libx264 @code{x264_param_parse} function.
+
+The x264 project website is at
+@url{http://www.videolan.org/developers/x264.html}.
+
+The libx264rgb encoder is the same as libx264, except it accepts packed RGB
+pixel formats as input instead of YUV.
+
+@subsection Supported Pixel Formats
+
+x264 supports 8- to 10-bit color spaces. The exact bit depth is controlled at
+x264's configure time. FFmpeg only supports one bit depth in one particular
+build. In other words, it is not possible to build one FFmpeg with multiple
+versions of x264 with different bit depths.
+
+@subsection Options
+
+The following options are supported by the libx264 wrapper. The
+@command{x264}-equivalent options or values are listed in parentheses
+for easy migration.
+
+To reduce the duplication of documentation, only the private options
+and some others requiring special attention are documented here. For
+the documentation of the undocumented generic options, see
+@ref{codec-options,,the Codec Options chapter}.
+
+To get a more accurate and extensive documentation of the libx264
+options, invoke the command @command{x264 --full-help} or consult
+the libx264 documentation.
+
+@table @option
+@item b (@emph{bitrate})
+Set bitrate in bits/s. Note that FFmpeg's @option{b} option is
+expressed in bits/s, while @command{x264}'s @option{bitrate} is in
+kilobits/s.
+
+@item bf (@emph{bframes})
+
+@item g (@emph{keyint})
+
+@item qmin (@emph{qpmin})
+Minimum quantizer scale.
+
+@item qmax (@emph{qpmax})
+Maximum quantizer scale.
+
+@item qdiff (@emph{qpstep})
+Maximum difference between quantizer scales.
+
+@item qblur (@emph{qblur})
+Quantizer curve blur
+
+@item qcomp (@emph{qcomp})
+Quantizer curve compression factor
+
+@item refs (@emph{ref})
+Number of reference frames each P-frame can use. The range is from @var{0-16}.
+
+@item sc_threshold (@emph{scenecut})
+Sets the threshold for the scene change detection.
+
+@item trellis (@emph{trellis})
+Performs Trellis quantization to increase efficiency. Enabled by default.
+
+@item nr (@emph{nr})
+
+@item me_range (@emph{merange})
+Maximum range of the motion search in pixels.
+
+@item me_method (@emph{me})
+Set motion estimation method. Possible values in the decreasing order
+of speed:
+
+@table @samp
+@item dia (@emph{dia})
+@item epzs (@emph{dia})
+Diamond search with radius 1 (fastest). @samp{epzs} is an alias for
+@samp{dia}.
+@item hex (@emph{hex})
+Hexagonal search with radius 2.
+@item umh (@emph{umh})
+Uneven multi-hexagon search.
+@item esa (@emph{esa})
+Exhaustive search.
+@item tesa (@emph{tesa})
+Hadamard exhaustive search (slowest).
+@end table
+
+@item subq (@emph{subme})
+Sub-pixel motion estimation method.
+
+@item b_strategy (@emph{b-adapt})
+Adaptive B-frame placement decision algorithm. Use only on first-pass.
+
+@item keyint_min (@emph{min-keyint})
+Minimum GOP size.
+
+@item coder
+Set entropy encoder. Possible values:
+
+@table @samp
+@item ac
+Enable CABAC.
+
+@item vlc
+Enable CAVLC and disable CABAC. It generates the same effect as
+@command{x264}'s @option{--no-cabac} option.
+@end table
+
+@item cmp
+Set full pixel motion estimation comparation algorithm. Possible values:
+
+@table @samp
+@item chroma
+Enable chroma in motion estimation.
+
+@item sad
+Ignore chroma in motion estimation. It generates the same effect as
+@command{x264}'s @option{--no-chroma-me} option.
+@end table
+
+@item threads (@emph{threads})
+Number of encoding threads.
+
+@item thread_type
+Set multithreading technique. Possible values:
+
+@table @samp
+@item slice
+Slice-based multithreading. It generates the same effect as
+@command{x264}'s @option{--sliced-threads} option.
+@item frame
+Frame-based multithreading.
+@end table
+
+@item flags
+Set encoding flags. It can be used to disable closed GOP and enable
+open GOP by setting it to @code{-cgop}. The result is similar to
+the behavior of @command{x264}'s @option{--open-gop} option.
+
+@item rc_init_occupancy (@emph{vbv-init})
+
+@item preset (@emph{preset})
+Set the encoding preset.
+
+@item tune (@emph{tune})
+Set tuning of the encoding params.
+
+@item profile (@emph{profile})
+Set profile restrictions.
+
+@item fastfirstpass
+Enable fast settings when encoding first pass, when set to 1. When set
+to 0, it has the same effect of @command{x264}'s
+@option{--slow-firstpass} option.
+
+@item crf (@emph{crf})
+Set the quality for constant quality mode.
+
+@item crf_max (@emph{crf-max})
+In CRF mode, prevents VBV from lowering quality beyond this point.
+
+@item qp (@emph{qp})
+Set constant quantization rate control method parameter.
+
+@item aq-mode (@emph{aq-mode})
+Set AQ method. Possible values:
+
+@table @samp
+@item none (@emph{0})
+Disabled.
+
+@item variance (@emph{1})
+Variance AQ (complexity mask).
+
+@item autovariance (@emph{2})
+Auto-variance AQ (experimental).
+@end table
+
+@item aq-strength (@emph{aq-strength})
+Set AQ strength, reduce blocking and blurring in flat and textured areas.
+
+@item psy
+Use psychovisual optimizations when set to 1. When set to 0, it has the
+same effect as @command{x264}'s @option{--no-psy} option.
+
+@item psy-rd (@emph{psy-rd})
+Set strength of psychovisual optimization, in
+@var{psy-rd}:@var{psy-trellis} format.
+
+@item rc-lookahead (@emph{rc-lookahead})
+Set number of frames to look ahead for frametype and ratecontrol.
+
+@item weightb
+Enable weighted prediction for B-frames when set to 1. When set to 0,
+it has the same effect as @command{x264}'s @option{--no-weightb} option.
+
+@item weightp (@emph{weightp})
+Set weighted prediction method for P-frames. Possible values:
+
+@table @samp
+@item none (@emph{0})
+Disabled
+@item simple (@emph{1})
+Enable only weighted refs
+@item smart (@emph{2})
+Enable both weighted refs and duplicates
+@end table
+
+@item ssim (@emph{ssim})
+Enable calculation and printing SSIM stats after the encoding.
+
+@item intra-refresh (@emph{intra-refresh})
+Enable the use of Periodic Intra Refresh instead of IDR frames when set
+to 1.
+
+@item avcintra-class (@emph{class})
+Configure the encoder to generate AVC-Intra.
+Valid values are 50,100 and 200
+
+@item bluray-compat (@emph{bluray-compat})
+Configure the encoder to be compatible with the bluray standard.
+It is a shorthand for setting "bluray-compat=1 force-cfr=1".
+
+@item b-bias (@emph{b-bias})
+Set the influence on how often B-frames are used.
+
+@item b-pyramid (@emph{b-pyramid})
+Set method for keeping of some B-frames as references. Possible values:
+
+@table @samp
+@item none (@emph{none})
+Disabled.
+@item strict (@emph{strict})
+Strictly hierarchical pyramid.
+@item normal (@emph{normal})
+Non-strict (not Blu-ray compatible).
+@end table
+
+@item mixed-refs
+Enable the use of one reference per partition, as opposed to one
+reference per macroblock when set to 1. When set to 0, it has the
+same effect as @command{x264}'s @option{--no-mixed-refs} option.
+
+@item 8x8dct
+Enable adaptive spatial transform (high profile 8x8 transform)
+when set to 1. When set to 0, it has the same effect as
+@command{x264}'s @option{--no-8x8dct} option.
+
+@item fast-pskip
+Enable early SKIP detection on P-frames when set to 1. When set
+to 0, it has the same effect as @command{x264}'s
+@option{--no-fast-pskip} option.
+
+@item aud (@emph{aud})
+Enable use of access unit delimiters when set to 1.
+
+@item mbtree
+Enable use macroblock tree ratecontrol when set to 1. When set
+to 0, it has the same effect as @command{x264}'s
+@option{--no-mbtree} option.
+
+@item deblock (@emph{deblock})
+Set loop filter parameters, in @var{alpha}:@var{beta} form.
+
+@item cplxblur (@emph{cplxblur})
+Set fluctuations reduction in QP (before curve compression).
+
+@item partitions (@emph{partitions})
+Set partitions to consider as a comma-separated list of. Possible
+values in the list:
+
+@table @samp
+@item p8x8
+8x8 P-frame partition.
+@item p4x4
+4x4 P-frame partition.
+@item b8x8
+4x4 B-frame partition.
+@item i8x8
+8x8 I-frame partition.
+@item i4x4
+4x4 I-frame partition.
+(Enabling @samp{p4x4} requires @samp{p8x8} to be enabled. Enabling
+@samp{i8x8} requires adaptive spatial transform (@option{8x8dct}
+option) to be enabled.)
+@item none (@emph{none})
+Do not consider any partitions.
+@item all (@emph{all})
+Consider every partition.
+@end table
+
+@item direct-pred (@emph{direct})
+Set direct MV prediction mode. Possible values:
+
+@table @samp
+@item none (@emph{none})
+Disable MV prediction.
+@item spatial (@emph{spatial})
+Enable spatial predicting.
+@item temporal (@emph{temporal})
+Enable temporal predicting.
+@item auto (@emph{auto})
+Automatically decided.
+@end table
+
+@item slice-max-size (@emph{slice-max-size})
+Set the limit of the size of each slice in bytes. If not specified
+but RTP payload size (@option{ps}) is specified, that is used.
+
+@item stats (@emph{stats})
+Set the file name for multi-pass stats.
+
+@item nal-hrd (@emph{nal-hrd})
+Set signal HRD information (requires @option{vbv-bufsize} to be set).
+Possible values:
+
+@table @samp
+@item none (@emph{none})
+Disable HRD information signaling.
+@item vbr (@emph{vbr})
+Variable bit rate.
+@item cbr (@emph{cbr})
+Constant bit rate (not allowed in MP4 container).
+@end table
+
+@item x264opts (N.A.)
+Set any x264 option, see @command{x264 --fullhelp} for a list.
+
+Argument is a list of @var{key}=@var{value} couples separated by
+":". In @var{filter} and @var{psy-rd} options that use ":" as a separator
+themselves, use "," instead. They accept it as well since long ago but this
+is kept undocumented for some reason.
+
+For example to specify libx264 encoding options with @command{ffmpeg}:
+@example
+ffmpeg -i foo.mpg -vcodec libx264 -x264opts keyint=123:min-keyint=20 -an out.mkv
+@end example
+
+@item x264-params (N.A.)
+Override the x264 configuration using a :-separated list of key=value
+parameters.
+
+This option is functionally the same as the @option{x264opts}, but is
+duplicated for compatibility with the Libav fork.
+
+For example to specify libx264 encoding options with @command{ffmpeg}:
+@example
+ffmpeg -i INPUT -c:v libx264 -x264-params level=30:bframes=0:weightp=0:\
+cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:\
+no-fast-pskip=1:subq=6:8x8dct=0:trellis=0 OUTPUT
+@end example
+@end table
+
+Encoding ffpresets for common usages are provided so they can be used with the
+general presets system (e.g. passing the @option{pre} option).
+
+@section libx265
+
+x265 H.265/HEVC encoder wrapper.
+
+This encoder requires the presence of the libx265 headers and library
+during configuration. You need to explicitly configure the build with
+@option{--enable-libx265}.
+
+@subsection Options
+
+@table @option
+@item preset
+Set the x265 preset.
+
+@item tune
+Set the x265 tune parameter.
+
+@item x265-params
+Set x265 options using a list of @var{key}=@var{value} couples separated
+by ":". See @command{x265 --help} for a list of options.
+
+For example to specify libx265 encoding options with @option{-x265-params}:
+
+@example
+ffmpeg -i input -c:v libx265 -x265-params crf=26:psy-rd=1 output.mp4
+@end example
+@end table
+
+@section libxvid
+
+Xvid MPEG-4 Part 2 encoder wrapper.
+
+This encoder requires the presence of the libxvidcore headers and library
+during configuration. You need to explicitly configure the build with
+@code{--enable-libxvid --enable-gpl}.
+
+The native @code{mpeg4} encoder supports the MPEG-4 Part 2 format, so
+users can encode to this format without this library.
+
+@subsection Options
+
+The following options are supported by the libxvid wrapper. Some of
+the following options are listed but are not documented, and
+correspond to shared codec options. See @ref{codec-options,,the Codec
+Options chapter} for their documentation. The other shared options
+which are not listed have no effect for the libxvid encoder.
+
+@table @option
+@item b
+
+@item g
+
+@item qmin
+
+@item qmax
+
+@item mpeg_quant
+
+@item threads
+
+@item bf
+
+@item b_qfactor
+
+@item b_qoffset
+
+@item flags
+Set specific encoding flags. Possible values:
+
+@table @samp
+
+@item mv4
+Use four motion vector by macroblock.
+
+@item aic
+Enable high quality AC prediction.
+
+@item gray
+Only encode grayscale.
+
+@item gmc
+Enable the use of global motion compensation (GMC).
+
+@item qpel
+Enable quarter-pixel motion compensation.
+
+@item cgop
+Enable closed GOP.
+
+@item global_header
+Place global headers in extradata instead of every keyframe.
+
+@end table
+
+@item trellis
+
+@item me_method
+Set motion estimation method. Possible values in decreasing order of
+speed and increasing order of quality:
+
+@table @samp
+@item zero
+Use no motion estimation (default).
+
+@item phods
+@item x1
+@item log
+Enable advanced diamond zonal search for 16x16 blocks and half-pixel
+refinement for 16x16 blocks. @samp{x1} and @samp{log} are aliases for
+@samp{phods}.
+
+@item epzs
+Enable all of the things described above, plus advanced diamond zonal
+search for 8x8 blocks, half-pixel refinement for 8x8 blocks, and motion
+estimation on chroma planes.
+
+@item full
+Enable all of the things described above, plus extended 16x16 and 8x8
+blocks search.
+@end table
+
+@item mbd
+Set macroblock decision algorithm. Possible values in the increasing
+order of quality:
+
+@table @samp
+@item simple
+Use macroblock comparing function algorithm (default).
+
+@item bits
+Enable rate distortion-based half pixel and quarter pixel refinement for
+16x16 blocks.
+
+@item rd
+Enable all of the things described above, plus rate distortion-based
+half pixel and quarter pixel refinement for 8x8 blocks, and rate
+distortion-based search using square pattern.
+@end table
+
@item lumi_aq
Enable lumi masking adaptive quantization when set to 1. Default is 0
(disabled).
@@ -557,205 +2156,51 @@ fastest.
@end table
-@section libx264
-
-x264 H.264/MPEG-4 AVC encoder wrapper
-
-x264 supports an impressive number of features, including 8x8 and 4x4 adaptive
-spatial transform, adaptive B-frame placement, CAVLC/CABAC entropy coding,
-interlacing (MBAFF), lossless mode, psy optimizations for detail retention
-(adaptive quantization, psy-RD, psy-trellis).
+@section mpeg2
-The Libav wrapper provides a mapping for most of them using global options
-that match those of the encoders and provides private options for the unique
-encoder options. Additionally an expert override is provided to directly pass
-a list of key=value tuples as accepted by x264_param_parse.
-
-@subsection Option Mapping
-
-The following options are supported by the x264 wrapper, the x264-equivalent
-options follow the Libav ones.
-
-@multitable { } { } { }
-@item b @tab bitrate
-@tab Libav @code{b} option is expressed in bits/s, x264 @code{bitrate} in kilobits/s.
-@item bf @tab bframes
-@tab Maximum number of B-frames.
-@item g @tab keyint
-@tab Maximum GOP size.
-@item qmin @tab qpmin
-@tab Minimum quantizer scale.
-@item qmax @tab qpmax
-@tab Maximum quantizer scale.
-@item qdiff @tab qpstep
-@tab Maximum difference between quantizer scales.
-@item qblur @tab qblur
-@tab Quantizer curve blur
-@item qcomp @tab qcomp
-@tab Quantizer curve compression factor
-@item refs @tab ref
-@tab Number of reference frames each P-frame can use. The range is from @var{0-16}.
-@item sc_threshold @tab scenecut
-@tab Sets the threshold for the scene change detection.
-@item trellis @tab trellis
-@tab Performs Trellis quantization to increase efficiency. Enabled by default.
-@item nr @tab nr
-@tab Noise reduction.
-@item me_range @tab merange
-@tab Maximum range of the motion search in pixels.
-@item me_method @tab me
-@tab Full-pixel motion estimation method.
-@item subq @tab subme
-@tab Sub-pixel motion estimation method.
-@item b_strategy @tab b-adapt
-@tab Adaptive B-frame placement decision algorithm. Use only on first-pass.
-@item keyint_min @tab min-keyint
-@tab Minimum GOP size.
-@item coder @tab cabac
-@tab Set coder to @code{ac} to use CABAC.
-@item cmp @tab chroma-me
-@tab Set to @code{chroma} to use chroma motion estimation.
-@item threads @tab threads
-@tab Number of encoding threads.
-@item thread_type @tab sliced_threads
-@tab Set to @code{slice} to use sliced threading instead of frame threading.
-@item flags -cgop @tab open-gop
-@tab Set @code{-cgop} to use recovery points to close GOPs.
-@item rc_init_occupancy @tab vbv-init
-@tab Initial buffer occupancy.
-@end multitable
-
-@subsection Private Options
-@table @option
-@item -preset @var{string}
-Set the encoding preset (cf. x264 --fullhelp).
-@item -tune @var{string}
-Tune the encoding params (cf. x264 --fullhelp).
-@item -profile @var{string}
-Set profile restrictions (cf. x264 --fullhelp).
-@item -fastfirstpass @var{integer}
-Use fast settings when encoding first pass.
-@item -crf @var{float}
-Select the quality for constant quality mode.
-@item -crf_max @var{float}
-In CRF mode, prevents VBV from lowering quality beyond this point.
-@item -qp @var{integer}
-Constant quantization parameter rate control method.
-@item -aq-mode @var{integer}
-AQ method
-
-Possible values:
-@table @samp
-@item none
-
-@item variance
-Variance AQ (complexity mask).
-@item autovariance
-Auto-variance AQ (experimental).
-@end table
-@item -aq-strength @var{float}
-AQ strength, reduces blocking and blurring in flat and textured areas.
-@item -psy @var{integer}
-Use psychovisual optimizations.
-@item -psy-rd @var{string}
-Strength of psychovisual optimization, in <psy-rd>:<psy-trellis> format.
-@item -rc-lookahead @var{integer}
-Number of frames to look ahead for frametype and ratecontrol.
-@item -weightb @var{integer}
-Weighted prediction for B-frames.
-@item -weightp @var{integer}
-Weighted prediction analysis method.
-
-Possible values:
-@table @samp
-@item none
-
-@item simple
-
-@item smart
-
-@end table
-@item -ssim @var{integer}
-Calculate and print SSIM stats.
-@item -intra-refresh @var{integer}
-Use Periodic Intra Refresh instead of IDR frames.
-@item -bluray-compat @var{integer}
-Configure the encoder to be compatible with the bluray standard.
-It is a shorthand for setting "bluray-compat=1 force-cfr=1".
-@item -b-bias @var{integer}
-Influences how often B-frames are used.
-@item -b-pyramid @var{integer}
-Keep some B-frames as references.
+MPEG-2 video encoder.
-Possible values:
-@table @samp
-@item none
+@subsection Options
-@item strict
-Strictly hierarchical pyramid.
-@item normal
-Non-strict (not Blu-ray compatible).
+@table @option
+@item seq_disp_ext @var{integer}
+Specifies if the encoder should write a sequence_display_extension to the
+output.
+@table @option
+@item -1
+@itemx auto
+Decide automatically to write it or not (this is the default) by checking if
+the data to be written is different from the default or unspecified values.
+@item 0
+@itemx never
+Never write it.
+@item 1
+@itemx always
+Always write it.
@end table
-@item -mixed-refs @var{integer}
-One reference per partition, as opposed to one reference per macroblock.
-@item -8x8dct @var{integer}
-High profile 8x8 transform.
-@item -fast-pskip @var{integer}
-@item -aud @var{integer}
-Use access unit delimiters.
-@item -mbtree @var{integer}
-Use macroblock tree ratecontrol.
-@item -deblock @var{string}
-Loop filter parameters, in <alpha:beta> form.
-@item -cplxblur @var{float}
-Reduce fluctuations in QP (before curve compression).
-@item -partitions @var{string}
-A comma-separated list of partitions to consider, possible values: p8x8, p4x4, b8x8, i8x8, i4x4, none, all.
-@item -direct-pred @var{integer}
-Direct MV prediction mode
-
-Possible values:
-@table @samp
-@item none
-
-@item spatial
-
-@item temporal
-
-@item auto
-
@end table
-@item -slice-max-size @var{integer}
-Limit the size of each slice in bytes.
-@item -stats @var{string}
-Filename for 2 pass stats.
-@item -nal-hrd @var{integer}
-Signal HRD information (requires vbv-bufsize; cbr not allowed in .mp4).
-Possible values:
-@table @samp
-@item none
+@section png
-@item vbr
+PNG image encoder.
-@item cbr
+@subsection Private options
+@table @option
+@item dpi @var{integer}
+Set physical density of pixels, in dots per inch, unset by default
+@item dpm @var{integer}
+Set physical density of pixels, in dots per meter, unset by default
@end table
-@item -x264-params @var{string}
-Override the x264 configuration using a :-separated list of key=value parameters.
-@example
--x264-params level=30:bframes=0:weightp=0:cabac=0:ref=1:vbv-maxrate=768:vbv-bufsize=2000:analyse=all:me=umh:no-fast-pskip=1:subq=6:8x8dct=0:trellis=0
-@end example
-@end table
-
-Encoding avpresets for common usages are provided so they can be used with the
-general presets system (e.g. passing the @code{-pre} option).
@section ProRes
Apple ProRes encoder.
-@subsection Private Options
+FFmpeg contains 2 ProRes encoders, the prores-aw and prores-ks encoder.
+The used encoder can be chosen with the @code{-vcodec} option.
+
+@subsection Private Options for prores-ks
@table @option
@item profile @var{integer}
@@ -805,7 +2250,7 @@ Use @var{0} to disable alpha plane coding.
@subsection Speed considerations
In the default mode of operation the encoder has to honor frame constraints
-(i.e. not produc frames with size bigger than requested) while still making
+(i.e. not produce frames with size bigger than requested) while still making
output picture as good as possible.
A frame containing a lot of small details is harder to compress and the encoder
would spend more time searching for appropriate quantizers for each slice.
@@ -816,3 +2261,27 @@ For the fastest encoding speed set the @option{qscale} parameter (4 is the
recommended value) and do not set a size constraint.
@c man end VIDEO ENCODERS
+
+@chapter Subtitles Encoders
+@c man begin SUBTITLES ENCODERS
+
+@section dvdsub
+
+This codec encodes the bitmap subtitle format that is used in DVDs.
+Typically they are stored in VOBSUB file pairs (*.idx + *.sub),
+and they can also be used in Matroska files.
+
+@subsection Options
+
+@table @option
+@item even_rows_fix
+When set to 1, enable a work-around that makes the number of pixel rows
+even in all subtitles. This fixes a problem with some players that
+cut off the bottom row if the number is odd. The work-around just adds
+a fully transparent row if needed. The overhead is low, typically
+one byte per subtitle on average.
+
+By default, this work-around is disabled.
+@end table
+
+@c man end SUBTITLES ENCODERS
diff --git a/doc/errno.txt b/doc/errno.txt
new file mode 100644
index 0000000000..31cab26fc2
--- /dev/null
+++ b/doc/errno.txt
@@ -0,0 +1,174 @@
+The following table lists most error codes found in various operating
+systems supported by FFmpeg.
+
+ OS
+Code Std F LBMWwb Text (YMMV)
+
+E2BIG POSIX ++++++ Argument list too long
+EACCES POSIX ++++++ Permission denied
+EADDRINUSE POSIX +++..+ Address in use
+EADDRNOTAVAIL POSIX +++..+ Cannot assign requested address
+EADV +..... Advertise error
+EAFNOSUPPORT POSIX +++..+ Address family not supported
+EAGAIN POSIX + ++++++ Resource temporarily unavailable
+EALREADY POSIX +++..+ Operation already in progress
+EAUTH .++... Authentication error
+EBADARCH ..+... Bad CPU type in executable
+EBADE +..... Invalid exchange
+EBADEXEC ..+... Bad executable
+EBADF POSIX ++++++ Bad file descriptor
+EBADFD +..... File descriptor in bad state
+EBADMACHO ..+... Malformed Macho file
+EBADMSG POSIX ++4... Bad message
+EBADR +..... Invalid request descriptor
+EBADRPC .++... RPC struct is bad
+EBADRQC +..... Invalid request code
+EBADSLT +..... Invalid slot
+EBFONT +..... Bad font file format
+EBUSY POSIX - ++++++ Device or resource busy
+ECANCELED POSIX +++... Operation canceled
+ECHILD POSIX ++++++ No child processes
+ECHRNG +..... Channel number out of range
+ECOMM +..... Communication error on send
+ECONNABORTED POSIX +++..+ Software caused connection abort
+ECONNREFUSED POSIX - +++ss+ Connection refused
+ECONNRESET POSIX +++..+ Connection reset
+EDEADLK POSIX ++++++ Resource deadlock avoided
+EDEADLOCK +..++. File locking deadlock error
+EDESTADDRREQ POSIX +++... Destination address required
+EDEVERR ..+... Device error
+EDOM C89 - ++++++ Numerical argument out of domain
+EDOOFUS .F.... Programming error
+EDOTDOT +..... RFS specific error
+EDQUOT POSIX +++... Disc quota exceeded
+EEXIST POSIX ++++++ File exists
+EFAULT POSIX - ++++++ Bad address
+EFBIG POSIX - ++++++ File too large
+EFTYPE .++... Inappropriate file type or format
+EHOSTDOWN +++... Host is down
+EHOSTUNREACH POSIX +++..+ No route to host
+EHWPOISON +..... Memory page has hardware error
+EIDRM POSIX +++... Identifier removed
+EILSEQ C99 ++++++ Illegal byte sequence
+EINPROGRESS POSIX - +++ss+ Operation in progress
+EINTR POSIX - ++++++ Interrupted system call
+EINVAL POSIX + ++++++ Invalid argument
+EIO POSIX + ++++++ I/O error
+EISCONN POSIX +++..+ Socket is already connected
+EISDIR POSIX ++++++ Is a directory
+EISNAM +..... Is a named type file
+EKEYEXPIRED +..... Key has expired
+EKEYREJECTED +..... Key was rejected by service
+EKEYREVOKED +..... Key has been revoked
+EL2HLT +..... Level 2 halted
+EL2NSYNC +..... Level 2 not synchronized
+EL3HLT +..... Level 3 halted
+EL3RST +..... Level 3 reset
+ELIBACC +..... Can not access a needed shared library
+ELIBBAD +..... Accessing a corrupted shared library
+ELIBEXEC +..... Cannot exec a shared library directly
+ELIBMAX +..... Too many shared libraries
+ELIBSCN +..... .lib section in a.out corrupted
+ELNRNG +..... Link number out of range
+ELOOP POSIX +++..+ Too many levels of symbolic links
+EMEDIUMTYPE +..... Wrong medium type
+EMFILE POSIX ++++++ Too many open files
+EMLINK POSIX ++++++ Too many links
+EMSGSIZE POSIX +++..+ Message too long
+EMULTIHOP POSIX ++4... Multihop attempted
+ENAMETOOLONG POSIX - ++++++ Filen ame too long
+ENAVAIL +..... No XENIX semaphores available
+ENEEDAUTH .++... Need authenticator
+ENETDOWN POSIX +++..+ Network is down
+ENETRESET SUSv3 +++..+ Network dropped connection on reset
+ENETUNREACH POSIX +++..+ Network unreachable
+ENFILE POSIX ++++++ Too many open files in system
+ENOANO +..... No anode
+ENOATTR .++... Attribute not found
+ENOBUFS POSIX - +++..+ No buffer space available
+ENOCSI +..... No CSI structure available
+ENODATA XSR +N4... No message available
+ENODEV POSIX - ++++++ No such device
+ENOENT POSIX - ++++++ No such file or directory
+ENOEXEC POSIX ++++++ Exec format error
+ENOFILE ...++. No such file or directory
+ENOKEY +..... Required key not available
+ENOLCK POSIX ++++++ No locks available
+ENOLINK POSIX ++4... Link has been severed
+ENOMEDIUM +..... No medium found
+ENOMEM POSIX ++++++ Not enough space
+ENOMSG POSIX +++..+ No message of desired type
+ENONET +..... Machine is not on the network
+ENOPKG +..... Package not installed
+ENOPROTOOPT POSIX +++..+ Protocol not available
+ENOSPC POSIX ++++++ No space left on device
+ENOSR XSR +N4... No STREAM resources
+ENOSTR XSR +N4... Not a STREAM
+ENOSYS POSIX + ++++++ Function not implemented
+ENOTBLK +++... Block device required
+ENOTCONN POSIX +++..+ Socket is not connected
+ENOTDIR POSIX ++++++ Not a directory
+ENOTEMPTY POSIX ++++++ Directory not empty
+ENOTNAM +..... Not a XENIX named type file
+ENOTRECOVERABLE SUSv4 - +..... State not recoverable
+ENOTSOCK POSIX +++..+ Socket operation on non-socket
+ENOTSUP POSIX +++... Operation not supported
+ENOTTY POSIX ++++++ Inappropriate I/O control operation
+ENOTUNIQ +..... Name not unique on network
+ENXIO POSIX ++++++ No such device or address
+EOPNOTSUPP POSIX +++..+ Operation not supported (on socket)
+EOVERFLOW POSIX +++..+ Value too large to be stored in data type
+EOWNERDEAD SUSv4 +..... Owner died
+EPERM POSIX - ++++++ Operation not permitted
+EPFNOSUPPORT +++..+ Protocol family not supported
+EPIPE POSIX - ++++++ Broken pipe
+EPROCLIM .++... Too many processes
+EPROCUNAVAIL .++... Bad procedure for program
+EPROGMISMATCH .++... Program version wrong
+EPROGUNAVAIL .++... RPC prog. not avail
+EPROTO POSIX ++4... Protocol error
+EPROTONOSUPPORT POSIX - +++ss+ Protocol not supported
+EPROTOTYPE POSIX +++..+ Protocol wrong type for socket
+EPWROFF ..+... Device power is off
+ERANGE C89 - ++++++ Result too large
+EREMCHG +..... Remote address changed
+EREMOTE +++... Object is remote
+EREMOTEIO +..... Remote I/O error
+ERESTART +..... Interrupted system call should be restarted
+ERFKILL +..... Operation not possible due to RF-kill
+EROFS POSIX ++++++ Read-only file system
+ERPCMISMATCH .++... RPC version wrong
+ESHLIBVERS ..+... Shared library version mismatch
+ESHUTDOWN +++..+ Cannot send after socket shutdown
+ESOCKTNOSUPPORT +++... Socket type not supported
+ESPIPE POSIX ++++++ Illegal seek
+ESRCH POSIX ++++++ No such process
+ESRMNT +..... Srmount error
+ESTALE POSIX +++..+ Stale NFS file handle
+ESTRPIPE +..... Streams pipe error
+ETIME XSR +N4... Stream ioctl timeout
+ETIMEDOUT POSIX - +++ss+ Connection timed out
+ETOOMANYREFS +++... Too many references: cannot splice
+ETXTBSY POSIX +++... Text file busy
+EUCLEAN +..... Structure needs cleaning
+EUNATCH +..... Protocol driver not attached
+EUSERS +++... Too many users
+EWOULDBLOCK POSIX +++..+ Operation would block
+EXDEV POSIX ++++++ Cross-device link
+EXFULL +..... Exchange full
+
+Notations:
+
+F: used in FFmpeg (-: a few times, +: a lot)
+
+SUSv3: Single Unix Specification, version 3
+SUSv4: Single Unix Specification, version 4
+XSR: XSI STREAMS (obsolete)
+
+OS: availability on some supported operating systems
+L: GNU/Linux
+B: BSD (F: FreeBSD, N: NetBSD)
+M: MacOS X
+W: Microsoft Windows (s: emulated with winsock, see libavformat/network.h)
+w: Mingw32 (3.17) and Mingw64 (2.0.1)
+b: BeOS
diff --git a/doc/eval.texi b/doc/eval.texi
deleted file mode 100644
index e1fd7ee484..0000000000
--- a/doc/eval.texi
+++ /dev/null
@@ -1,156 +0,0 @@
-@chapter Expression Evaluation
-@c man begin EXPRESSION EVALUATION
-
-When evaluating an arithmetic expression, Libav uses an internal
-formula evaluator, implemented through the @file{libavutil/eval.h}
-interface.
-
-An expression may contain unary, binary operators, constants, and
-functions.
-
-Two expressions @var{expr1} and @var{expr2} can be combined to form
-another expression "@var{expr1};@var{expr2}".
-@var{expr1} and @var{expr2} are evaluated in turn, and the new
-expression evaluates to the value of @var{expr2}.
-
-The following binary operators are available: @code{+}, @code{-},
-@code{*}, @code{/}, @code{^}.
-
-The following unary operators are available: @code{+}, @code{-}.
-
-The following functions are available:
-@table @option
-@item sinh(x)
-@item cosh(x)
-@item tanh(x)
-@item sin(x)
-@item cos(x)
-@item tan(x)
-@item atan(x)
-@item asin(x)
-@item acos(x)
-@item exp(x)
-@item log(x)
-@item abs(x)
-@item squish(x)
-@item gauss(x)
-@item isinf(x)
-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 mod(x, y)
-@item max(x, y)
-@item min(x, y)
-@item eq(x, y)
-@item gte(x, y)
-@item gt(x, y)
-@item lte(x, y)
-@item lt(x, y)
-@item st(var, expr)
-Allow to 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.
-
-@item ld(var)
-Allow to load the value of the internal variable with number
-@var{var}, which was previously stored with st(@var{var}, @var{expr}).
-The function returns the loaded value.
-
-@item while(cond, expr)
-Evaluate expression @var{expr} while the expression @var{cond} is
-non-zero, and returns the value of the last @var{expr} evaluation, or
-NAN if @var{cond} was always false.
-
-@item ceil(expr)
-Round the value of expression @var{expr} upwards to the nearest
-integer. For example, "ceil(1.5)" is "2.0".
-
-@item floor(expr)
-Round the value of expression @var{expr} downwards to the nearest
-integer. For example, "floor(-1.5)" is "-2.0".
-
-@item trunc(expr)
-Round the value of expression @var{expr} towards zero to the nearest
-integer. For example, "trunc(-1.5)" is "-1.0".
-
-@item sqrt(expr)
-Compute the square root of @var{expr}. This is equivalent to
-"(@var{expr})^.5".
-
-@item not(expr)
-Return 1.0 if @var{expr} is zero, 0.0 otherwise.
-@end table
-
-Note that:
-
-@code{*} works like AND
-
-@code{+} works like OR
-
-thus
-@example
-if A then B else C
-@end example
-is equivalent to
-@example
-A*B + not(A)*C
-@end example
-
-In your C code, you can extend the list of unary and binary functions,
-and define recognized constants, so that they are available for your
-expressions.
-
-The evaluator also recognizes the International System number
-postfixes. If 'i' is appended after the postfix, powers of 2 are used
-instead of powers of 10. The 'B' postfix multiplies the value for 8,
-and can be appended after another postfix or used alone. This allows
-using for example 'KB', 'MiB', 'G' and 'B' as postfix.
-
-Follows the list of available International System postfixes, with
-indication of the corresponding powers of 10 and of 2.
-@table @option
-@item y
--24 / -80
-@item z
--21 / -70
-@item a
--18 / -60
-@item f
--15 / -50
-@item p
--12 / -40
-@item n
--9 / -30
-@item u
--6 / -20
-@item m
--3 / -10
-@item c
--2
-@item d
--1
-@item h
-2
-@item k
-3 / 10
-@item K
-3 / 10
-@item M
-6 / 20
-@item G
-9 / 30
-@item T
-12 / 40
-@item P
-15 / 40
-@item E
-18 / 50
-@item Z
-21 / 60
-@item Y
-24 / 70
-@end table
-
-@c man end
diff --git a/doc/examples/Makefile b/doc/examples/Makefile
new file mode 100644
index 0000000000..9699f11d43
--- /dev/null
+++ b/doc/examples/Makefile
@@ -0,0 +1,45 @@
+# use pkg-config for getting CFLAGS and LDLIBS
+FFMPEG_LIBS= libavdevice \
+ libavformat \
+ libavfilter \
+ libavcodec \
+ libswresample \
+ libswscale \
+ libavutil \
+
+CFLAGS += -Wall -g
+CFLAGS := $(shell pkg-config --cflags $(FFMPEG_LIBS)) $(CFLAGS)
+LDLIBS := $(shell pkg-config --libs $(FFMPEG_LIBS)) $(LDLIBS)
+
+EXAMPLES= avio_list_dir \
+ avio_reading \
+ decoding_encoding \
+ demuxing_decoding \
+ extract_mvs \
+ filtering_video \
+ filtering_audio \
+ metadata \
+ muxing \
+ remuxing \
+ resampling_audio \
+ scaling_video \
+ transcode_aac \
+ transcoding \
+
+OBJS=$(addsuffix .o,$(EXAMPLES))
+
+# the following examples make explicit use of the math library
+avcodec: LDLIBS += -lm
+decoding_encoding: LDLIBS += -lm
+muxing: LDLIBS += -lm
+resampling_audio: LDLIBS += -lm
+
+.phony: all clean-test clean
+
+all: $(OBJS) $(EXAMPLES)
+
+clean-test:
+ $(RM) test*.pgm test.h264 test.mp2 test.sw test.mpg
+
+clean: clean-test
+ $(RM) $(EXAMPLES) $(OBJS)
diff --git a/doc/examples/README b/doc/examples/README
new file mode 100644
index 0000000000..c1ce619d35
--- /dev/null
+++ b/doc/examples/README
@@ -0,0 +1,23 @@
+FFmpeg examples README
+----------------------
+
+Both following use cases rely on pkg-config and make, thus make sure
+that you have them installed and working on your system.
+
+
+Method 1: build the installed examples in a generic read/write user directory
+
+Copy to a read/write user directory and just use "make", it will link
+to the libraries on your system, assuming the PKG_CONFIG_PATH is
+correctly configured.
+
+Method 2: build the examples in-tree
+
+Assuming you are in the source FFmpeg checkout directory, you need to build
+FFmpeg (no need to make install in any prefix). Then just run "make examples".
+This will build the examples using the FFmpeg build system. You can clean those
+examples using "make examplesclean"
+
+If you want to try the dedicated Makefile examples (to emulate the first
+method), go into doc/examples and run a command such as
+PKG_CONFIG_PATH=pc-uninstalled make.
diff --git a/doc/examples/avcodec.c b/doc/examples/avcodec.c
deleted file mode 100644
index 1478881c25..0000000000
--- a/doc/examples/avcodec.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * copyright (c) 2001 Fabrice Bellard
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * libavcodec API use example.
- *
- * @example avcodec.c
- * Note that this library only handles codecs (mpeg, mpeg4, etc...),
- * not file formats (avi, vob, etc...). See library 'libavformat' for the
- * format handling
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#ifdef HAVE_AV_CONFIG_H
-#undef HAVE_AV_CONFIG_H
-#endif
-
-#include "libavcodec/avcodec.h"
-#include "libavutil/channel_layout.h"
-#include "libavutil/common.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/samplefmt.h"
-
-#define INBUF_SIZE 4096
-#define AUDIO_INBUF_SIZE 20480
-#define AUDIO_REFILL_THRESH 4096
-
-/* check that a given sample format is supported by the encoder */
-static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)
-{
- const enum AVSampleFormat *p = codec->sample_fmts;
-
- while (*p != AV_SAMPLE_FMT_NONE) {
- if (*p == sample_fmt)
- return 1;
- p++;
- }
- return 0;
-}
-
-/* just pick the highest supported samplerate */
-static int select_sample_rate(AVCodec *codec)
-{
- const int *p;
- int best_samplerate = 0;
-
- if (!codec->supported_samplerates)
- return 44100;
-
- p = codec->supported_samplerates;
- while (*p) {
- best_samplerate = FFMAX(*p, best_samplerate);
- p++;
- }
- return best_samplerate;
-}
-
-/* select layout with the highest channel count */
-static int select_channel_layout(AVCodec *codec)
-{
- const uint64_t *p;
- uint64_t best_ch_layout = 0;
- int best_nb_channels = 0;
-
- if (!codec->channel_layouts)
- return AV_CH_LAYOUT_STEREO;
-
- p = codec->channel_layouts;
- while (*p) {
- int nb_channels = av_get_channel_layout_nb_channels(*p);
-
- if (nb_channels > best_nb_channels) {
- best_ch_layout = *p;
- best_nb_channels = nb_channels;
- }
- p++;
- }
- return best_ch_layout;
-}
-
-/*
- * Audio encoding example
- */
-static void audio_encode_example(const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- AVFrame *frame;
- AVPacket pkt;
- int i, j, k, ret, got_output;
- int buffer_size;
- FILE *f;
- uint16_t *samples;
- float t, tincr;
-
- printf("Audio encoding\n");
-
- /* find the MP2 encoder */
- codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
-
- /* put sample parameters */
- c->bit_rate = 64000;
-
- /* check that the encoder supports s16 pcm input */
- c->sample_fmt = AV_SAMPLE_FMT_S16;
- if (!check_sample_fmt(codec, c->sample_fmt)) {
- fprintf(stderr, "encoder does not support %s",
- av_get_sample_fmt_name(c->sample_fmt));
- exit(1);
- }
-
- /* select other audio parameters supported by the encoder */
- c->sample_rate = select_sample_rate(codec);
- c->channel_layout = select_channel_layout(codec);
- c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- f = fopen(filename, "wb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
-
- /* frame containing input raw audio */
- frame = av_frame_alloc();
- if (!frame) {
- fprintf(stderr, "could not allocate audio frame\n");
- exit(1);
- }
-
- frame->nb_samples = c->frame_size;
- frame->format = c->sample_fmt;
- frame->channel_layout = c->channel_layout;
-
- /* the codec gives us the frame size, in samples,
- * we calculate the size of the samples buffer in bytes */
- buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size,
- c->sample_fmt, 0);
- samples = av_malloc(buffer_size);
- if (!samples) {
- fprintf(stderr, "could not allocate %d bytes for samples buffer\n",
- buffer_size);
- exit(1);
- }
- /* setup the data pointers in the AVFrame */
- ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
- (const uint8_t*)samples, buffer_size, 0);
- if (ret < 0) {
- fprintf(stderr, "could not setup audio frame\n");
- exit(1);
- }
-
- /* encode a single tone sound */
- t = 0;
- tincr = 2 * M_PI * 440.0 / c->sample_rate;
- for(i=0;i<200;i++) {
- av_init_packet(&pkt);
- pkt.data = NULL; // packet data will be allocated by the encoder
- pkt.size = 0;
-
- for (j = 0; j < c->frame_size; j++) {
- samples[2*j] = (int)(sin(t) * 10000);
-
- for (k = 1; k < c->channels; k++)
- samples[2*j + k] = samples[2*j];
- t += tincr;
- }
- /* encode the samples */
- ret = avcodec_encode_audio2(c, &pkt, frame, &got_output);
- if (ret < 0) {
- fprintf(stderr, "error encoding audio frame\n");
- exit(1);
- }
- if (got_output) {
- fwrite(pkt.data, 1, pkt.size, f);
- av_free_packet(&pkt);
- }
- }
- fclose(f);
-
- av_freep(&samples);
- av_frame_free(&frame);
- avcodec_close(c);
- av_free(c);
-}
-
-/*
- * Audio decoding.
- */
-static void audio_decode_example(const char *outfilename, const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- int len;
- FILE *f, *outfile;
- uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
- AVPacket avpkt;
- AVFrame *decoded_frame = NULL;
-
- av_init_packet(&avpkt);
-
- printf("Audio decoding\n");
-
- /* find the mpeg audio decoder */
- codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
- outfile = fopen(outfilename, "wb");
- if (!outfile) {
- av_free(c);
- exit(1);
- }
-
- /* decode until eof */
- avpkt.data = inbuf;
- avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
-
- while (avpkt.size > 0) {
- int got_frame = 0;
-
- if (!decoded_frame) {
- if (!(decoded_frame = av_frame_alloc())) {
- fprintf(stderr, "out of memory\n");
- exit(1);
- }
- }
-
- len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
- if (len < 0) {
- fprintf(stderr, "Error while decoding\n");
- exit(1);
- }
- if (got_frame) {
- /* if a frame has been decoded, output it */
- int data_size = av_samples_get_buffer_size(NULL, c->channels,
- decoded_frame->nb_samples,
- c->sample_fmt, 1);
- fwrite(decoded_frame->data[0], 1, data_size, outfile);
- }
- avpkt.size -= len;
- avpkt.data += len;
- if (avpkt.size < AUDIO_REFILL_THRESH) {
- /* Refill the input buffer, to avoid trying to decode
- * incomplete frames. Instead of this, one could also use
- * a parser, or use a proper container format through
- * libavformat. */
- memmove(inbuf, avpkt.data, avpkt.size);
- avpkt.data = inbuf;
- len = fread(avpkt.data + avpkt.size, 1,
- AUDIO_INBUF_SIZE - avpkt.size, f);
- if (len > 0)
- avpkt.size += len;
- }
- }
-
- fclose(outfile);
- fclose(f);
-
- avcodec_close(c);
- av_free(c);
- av_frame_free(&decoded_frame);
-}
-
-/*
- * Video encoding example
- */
-static void video_encode_example(const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- int i, ret, x, y, got_output;
- FILE *f;
- AVFrame *picture;
- AVPacket pkt;
- uint8_t endcode[] = { 0, 0, 1, 0xb7 };
-
- printf("Video encoding\n");
-
- /* find the mpeg1 video encoder */
- codec = avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
- picture = av_frame_alloc();
-
- /* put sample parameters */
- c->bit_rate = 400000;
- /* resolution must be a multiple of two */
- c->width = 352;
- c->height = 288;
- /* frames per second */
- c->time_base= (AVRational){1,25};
- c->gop_size = 10; /* emit one intra frame every ten frames */
- c->max_b_frames=1;
- c->pix_fmt = AV_PIX_FMT_YUV420P;
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- f = fopen(filename, "wb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
-
- ret = av_image_alloc(picture->data, picture->linesize, c->width, c->height,
- c->pix_fmt, 32);
- if (ret < 0) {
- fprintf(stderr, "could not alloc raw picture buffer\n");
- exit(1);
- }
- picture->format = c->pix_fmt;
- picture->width = c->width;
- picture->height = c->height;
-
- /* encode 1 second of video */
- for(i=0;i<25;i++) {
- av_init_packet(&pkt);
- pkt.data = NULL; // packet data will be allocated by the encoder
- pkt.size = 0;
-
- fflush(stdout);
- /* prepare a dummy image */
- /* Y */
- for(y=0;y<c->height;y++) {
- for(x=0;x<c->width;x++) {
- picture->data[0][y * picture->linesize[0] + x] = x + y + i * 3;
- }
- }
-
- /* Cb and Cr */
- for(y=0;y<c->height/2;y++) {
- for(x=0;x<c->width/2;x++) {
- picture->data[1][y * picture->linesize[1] + x] = 128 + y + i * 2;
- picture->data[2][y * picture->linesize[2] + x] = 64 + x + i * 5;
- }
- }
-
- picture->pts = i;
-
- /* encode the image */
- ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
- if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
- exit(1);
- }
-
- if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
- fwrite(pkt.data, 1, pkt.size, f);
- av_free_packet(&pkt);
- }
- }
-
- /* get the delayed frames */
- for (got_output = 1; got_output; i++) {
- fflush(stdout);
-
- ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
- if (ret < 0) {
- fprintf(stderr, "error encoding frame\n");
- exit(1);
- }
-
- if (got_output) {
- printf("encoding frame %3d (size=%5d)\n", i, pkt.size);
- fwrite(pkt.data, 1, pkt.size, f);
- av_free_packet(&pkt);
- }
- }
-
- /* add sequence end code to have a real mpeg file */
- fwrite(endcode, 1, sizeof(endcode), f);
- fclose(f);
-
- avcodec_close(c);
- av_free(c);
- av_freep(&picture->data[0]);
- av_frame_free(&picture);
- printf("\n");
-}
-
-/*
- * Video decoding example
- */
-
-static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
- char *filename)
-{
- FILE *f;
- int i;
-
- f=fopen(filename,"w");
- fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
- for(i=0;i<ysize;i++)
- fwrite(buf + i * wrap,1,xsize,f);
- fclose(f);
-}
-
-static void video_decode_example(const char *outfilename, const char *filename)
-{
- AVCodec *codec;
- AVCodecContext *c= NULL;
- int frame, got_picture, len;
- FILE *f;
- AVFrame *picture;
- uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
- char buf[1024];
- AVPacket avpkt;
-
- av_init_packet(&avpkt);
-
- /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
- memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
-
- printf("Video decoding\n");
-
- /* find the mpeg1 video decoder */
- codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- c = avcodec_alloc_context3(codec);
- picture = av_frame_alloc();
-
- if(codec->capabilities&CODEC_CAP_TRUNCATED)
- c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
-
- /* For some codecs, such as msmpeg4 and mpeg4, width and height
- MUST be initialized there because this information is not
- available in the bitstream. */
-
- /* open it */
- if (avcodec_open2(c, codec, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- /* the codec gives us the frame size, in samples */
-
- f = fopen(filename, "rb");
- if (!f) {
- fprintf(stderr, "could not open %s\n", filename);
- exit(1);
- }
-
- frame = 0;
- for(;;) {
- avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
- if (avpkt.size == 0)
- break;
-
- /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
- and this is the only method to use them because you cannot
- know the compressed data size before analysing it.
-
- BUT some other codecs (msmpeg4, mpeg4) are inherently frame
- based, so you must call them with all the data for one
- frame exactly. You must also initialize 'width' and
- 'height' before initializing them. */
-
- /* NOTE2: some codecs allow the raw parameters (frame size,
- sample rate) to be changed at any frame. We handle this, so
- you should also take care of it */
-
- /* here, we use a stream based decoder (mpeg1video), so we
- feed decoder and see if it could decode a frame */
- avpkt.data = inbuf;
- while (avpkt.size > 0) {
- len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
- if (len < 0) {
- fprintf(stderr, "Error while decoding frame %d\n", frame);
- exit(1);
- }
- if (got_picture) {
- printf("saving frame %3d\n", frame);
- fflush(stdout);
-
- /* the picture is allocated by the decoder. no need to
- free it */
- snprintf(buf, sizeof(buf), outfilename, frame);
- pgm_save(picture->data[0], picture->linesize[0],
- c->width, c->height, buf);
- frame++;
- }
- avpkt.size -= len;
- avpkt.data += len;
- }
- }
-
- /* some codecs, such as MPEG, transmit the I and P frame with a
- latency of one frame. You must do the following to have a
- chance to get the last frame of the video */
- avpkt.data = NULL;
- avpkt.size = 0;
- len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
- if (got_picture) {
- printf("saving last frame %3d\n", frame);
- fflush(stdout);
-
- /* the picture is allocated by the decoder. no need to
- free it */
- snprintf(buf, sizeof(buf), outfilename, frame);
- pgm_save(picture->data[0], picture->linesize[0],
- c->width, c->height, buf);
- frame++;
- }
-
- fclose(f);
-
- avcodec_close(c);
- av_free(c);
- av_frame_free(&picture);
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- const char *filename;
-
- /* register all the codecs */
- avcodec_register_all();
-
- if (argc <= 1) {
- audio_encode_example("/tmp/test.mp2");
- audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
-
- video_encode_example("/tmp/test.mpg");
- filename = "/tmp/test.mpg";
- } else {
- filename = argv[1];
- }
-
- // audio_decode_example("/tmp/test.sw", filename);
- video_decode_example("/tmp/test%d.pgm", filename);
-
- return 0;
-}
diff --git a/doc/examples/avio_list_dir.c b/doc/examples/avio_list_dir.c
new file mode 100644
index 0000000000..4060ba6213
--- /dev/null
+++ b/doc/examples/avio_list_dir.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014 Lukasz Marek
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+
+static const char *type_string(int type)
+{
+ switch (type) {
+ case AVIO_ENTRY_DIRECTORY:
+ return "<DIR>";
+ case AVIO_ENTRY_FILE:
+ return "<FILE>";
+ case AVIO_ENTRY_BLOCK_DEVICE:
+ return "<BLOCK DEVICE>";
+ case AVIO_ENTRY_CHARACTER_DEVICE:
+ return "<CHARACTER DEVICE>";
+ case AVIO_ENTRY_NAMED_PIPE:
+ return "<PIPE>";
+ case AVIO_ENTRY_SYMBOLIC_LINK:
+ return "<LINK>";
+ case AVIO_ENTRY_SOCKET:
+ return "<SOCKET>";
+ case AVIO_ENTRY_SERVER:
+ return "<SERVER>";
+ case AVIO_ENTRY_SHARE:
+ return "<SHARE>";
+ case AVIO_ENTRY_WORKGROUP:
+ return "<WORKGROUP>";
+ case AVIO_ENTRY_UNKNOWN:
+ default:
+ break;
+ }
+ return "<UNKNOWN>";
+}
+
+int main(int argc, char *argv[])
+{
+ const char *input_dir = NULL;
+ AVIODirEntry *entry = NULL;
+ AVIODirContext *ctx = NULL;
+ int cnt, ret;
+ char filemode[4], uid_and_gid[20];
+
+ av_log_set_level(AV_LOG_DEBUG);
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s input_dir\n"
+ "API example program to show how to list files in directory "
+ "accessed through AVIOContext.\n", argv[0]);
+ return 1;
+ }
+ input_dir = argv[1];
+
+ /* register codecs and formats and other lavf/lavc components*/
+ av_register_all();
+ avformat_network_init();
+
+ if ((ret = avio_open_dir(&ctx, input_dir, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open directory: %s.\n", av_err2str(ret));
+ goto fail;
+ }
+
+ cnt = 0;
+ for (;;) {
+ if ((ret = avio_read_dir(ctx, &entry)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot list directory: %s.\n", av_err2str(ret));
+ goto fail;
+ }
+ if (!entry)
+ break;
+ if (entry->filemode == -1) {
+ snprintf(filemode, 4, "???");
+ } else {
+ snprintf(filemode, 4, "%3"PRIo64, entry->filemode);
+ }
+ snprintf(uid_and_gid, 20, "%"PRId64"(%"PRId64")", entry->user_id, entry->group_id);
+ if (cnt == 0)
+ av_log(NULL, AV_LOG_INFO, "%-9s %12s %30s %10s %s %16s %16s %16s\n",
+ "TYPE", "SIZE", "NAME", "UID(GID)", "UGO", "MODIFIED",
+ "ACCESSED", "STATUS_CHANGED");
+ av_log(NULL, AV_LOG_INFO, "%-9s %12"PRId64" %30s %10s %s %16"PRId64" %16"PRId64" %16"PRId64"\n",
+ type_string(entry->type),
+ entry->size,
+ entry->name,
+ uid_and_gid,
+ filemode,
+ entry->modification_timestamp,
+ entry->access_timestamp,
+ entry->status_change_timestamp);
+ avio_free_directory_entry(&entry);
+ cnt++;
+ };
+
+ fail:
+ avio_close_dir(&ctx);
+ avformat_network_deinit();
+
+ return ret < 0 ? 1 : 0;
+}
diff --git a/doc/examples/avio_reading.c b/doc/examples/avio_reading.c
new file mode 100644
index 0000000000..02474e907a
--- /dev/null
+++ b/doc/examples/avio_reading.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libavformat AVIOContext API example.
+ *
+ * Make libavformat demuxer access media content through a custom
+ * AVIOContext read callback.
+ * @example avio_reading.c
+ */
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+#include <libavutil/file.h>
+
+struct buffer_data {
+ uint8_t *ptr;
+ size_t size; ///< size left in the buffer
+};
+
+static int read_packet(void *opaque, uint8_t *buf, int buf_size)
+{
+ struct buffer_data *bd = (struct buffer_data *)opaque;
+ buf_size = FFMIN(buf_size, bd->size);
+
+ printf("ptr:%p size:%zu\n", bd->ptr, bd->size);
+
+ /* copy internal buffer data to buf */
+ memcpy(buf, bd->ptr, buf_size);
+ bd->ptr += buf_size;
+ bd->size -= buf_size;
+
+ return buf_size;
+}
+
+int main(int argc, char *argv[])
+{
+ AVFormatContext *fmt_ctx = NULL;
+ AVIOContext *avio_ctx = NULL;
+ uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
+ size_t buffer_size, avio_ctx_buffer_size = 4096;
+ char *input_filename = NULL;
+ int ret = 0;
+ struct buffer_data bd = { 0 };
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s input_file\n"
+ "API example program to show how to read from a custom buffer "
+ "accessed through AVIOContext.\n", argv[0]);
+ return 1;
+ }
+ input_filename = argv[1];
+
+ /* register codecs and formats and other lavf/lavc components*/
+ av_register_all();
+
+ /* slurp file content into buffer */
+ ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
+ if (ret < 0)
+ goto end;
+
+ /* fill opaque structure used by the AVIOContext read callback */
+ bd.ptr = buffer;
+ bd.size = buffer_size;
+
+ if (!(fmt_ctx = avformat_alloc_context())) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
+ if (!avio_ctx_buffer) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
+ 0, &bd, &read_packet, NULL, NULL);
+ if (!avio_ctx) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ fmt_ctx->pb = avio_ctx;
+
+ ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open input\n");
+ goto end;
+ }
+
+ ret = avformat_find_stream_info(fmt_ctx, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not find stream information\n");
+ goto end;
+ }
+
+ av_dump_format(fmt_ctx, 0, input_filename, 0);
+
+end:
+ avformat_close_input(&fmt_ctx);
+ /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
+ if (avio_ctx) {
+ av_freep(&avio_ctx->buffer);
+ av_freep(&avio_ctx);
+ }
+ av_file_unmap(buffer, buffer_size);
+
+ if (ret < 0) {
+ fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/doc/examples/decoding_encoding.c b/doc/examples/decoding_encoding.c
new file mode 100644
index 0000000000..80da66431b
--- /dev/null
+++ b/doc/examples/decoding_encoding.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libavcodec API use example.
+ *
+ * @example decoding_encoding.c
+ * Note that libavcodec only handles codecs (mpeg, mpeg4, etc...),
+ * not file formats (avi, vob, mp4, mov, mkv, mxf, flv, mpegts, mpegps, etc...). See library 'libavformat' for the
+ * format handling
+ */
+
+#include <math.h>
+
+#include <libavutil/opt.h>
+#include <libavcodec/avcodec.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/common.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/samplefmt.h>
+
+#define INBUF_SIZE 4096
+#define AUDIO_INBUF_SIZE 20480
+#define AUDIO_REFILL_THRESH 4096
+
+/* check that a given sample format is supported by the encoder */
+static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)
+{
+ const enum AVSampleFormat *p = codec->sample_fmts;
+
+ while (*p != AV_SAMPLE_FMT_NONE) {
+ if (*p == sample_fmt)
+ return 1;
+ p++;
+ }
+ return 0;
+}
+
+/* just pick the highest supported samplerate */
+static int select_sample_rate(AVCodec *codec)
+{
+ const int *p;
+ int best_samplerate = 0;
+
+ if (!codec->supported_samplerates)
+ return 44100;
+
+ p = codec->supported_samplerates;
+ while (*p) {
+ best_samplerate = FFMAX(*p, best_samplerate);
+ p++;
+ }
+ return best_samplerate;
+}
+
+/* select layout with the highest channel count */
+static int select_channel_layout(AVCodec *codec)
+{
+ const uint64_t *p;
+ uint64_t best_ch_layout = 0;
+ int best_nb_channels = 0;
+
+ if (!codec->channel_layouts)
+ return AV_CH_LAYOUT_STEREO;
+
+ p = codec->channel_layouts;
+ while (*p) {
+ int nb_channels = av_get_channel_layout_nb_channels(*p);
+
+ if (nb_channels > best_nb_channels) {
+ best_ch_layout = *p;
+ best_nb_channels = nb_channels;
+ }
+ p++;
+ }
+ return best_ch_layout;
+}
+
+/*
+ * Audio encoding example
+ */
+static void audio_encode_example(const char *filename)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ AVFrame *frame;
+ AVPacket pkt;
+ int i, j, k, ret, got_output;
+ int buffer_size;
+ FILE *f;
+ uint16_t *samples;
+ float t, tincr;
+
+ printf("Encode audio file %s\n", filename);
+
+ /* find the MP2 encoder */
+ codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate audio codec context\n");
+ exit(1);
+ }
+
+ /* put sample parameters */
+ c->bit_rate = 64000;
+
+ /* check that the encoder supports s16 pcm input */
+ c->sample_fmt = AV_SAMPLE_FMT_S16;
+ if (!check_sample_fmt(codec, c->sample_fmt)) {
+ fprintf(stderr, "Encoder does not support sample format %s",
+ av_get_sample_fmt_name(c->sample_fmt));
+ exit(1);
+ }
+
+ /* select other audio parameters supported by the encoder */
+ c->sample_rate = select_sample_rate(codec);
+ c->channel_layout = select_channel_layout(codec);
+ c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+
+ /* frame containing input raw audio */
+ frame = av_frame_alloc();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate audio frame\n");
+ exit(1);
+ }
+
+ frame->nb_samples = c->frame_size;
+ frame->format = c->sample_fmt;
+ frame->channel_layout = c->channel_layout;
+
+ /* the codec gives us the frame size, in samples,
+ * we calculate the size of the samples buffer in bytes */
+ buffer_size = av_samples_get_buffer_size(NULL, c->channels, c->frame_size,
+ c->sample_fmt, 0);
+ if (buffer_size < 0) {
+ fprintf(stderr, "Could not get sample buffer size\n");
+ exit(1);
+ }
+ samples = av_malloc(buffer_size);
+ if (!samples) {
+ fprintf(stderr, "Could not allocate %d bytes for samples buffer\n",
+ buffer_size);
+ exit(1);
+ }
+ /* setup the data pointers in the AVFrame */
+ ret = avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,
+ (const uint8_t*)samples, buffer_size, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not setup audio frame\n");
+ exit(1);
+ }
+
+ /* encode a single tone sound */
+ t = 0;
+ tincr = 2 * M_PI * 440.0 / c->sample_rate;
+ for (i = 0; i < 200; i++) {
+ av_init_packet(&pkt);
+ pkt.data = NULL; // packet data will be allocated by the encoder
+ pkt.size = 0;
+
+ for (j = 0; j < c->frame_size; j++) {
+ samples[2*j] = (int)(sin(t) * 10000);
+
+ for (k = 1; k < c->channels; k++)
+ samples[2*j + k] = samples[2*j];
+ t += tincr;
+ }
+ /* encode the samples */
+ ret = avcodec_encode_audio2(c, &pkt, frame, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding audio frame\n");
+ exit(1);
+ }
+ if (got_output) {
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* get the delayed frames */
+ for (got_output = 1; got_output; i++) {
+ ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
+ exit(1);
+ }
+
+ if (got_output) {
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+ fclose(f);
+
+ av_freep(&samples);
+ av_frame_free(&frame);
+ avcodec_close(c);
+ av_free(c);
+}
+
+/*
+ * Audio decoding.
+ */
+static void audio_decode_example(const char *outfilename, const char *filename)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ int len;
+ FILE *f, *outfile;
+ uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ AVPacket avpkt;
+ AVFrame *decoded_frame = NULL;
+
+ av_init_packet(&avpkt);
+
+ printf("Decode audio file %s to %s\n", filename, outfilename);
+
+ /* find the mpeg audio decoder */
+ codec = avcodec_find_decoder(AV_CODEC_ID_MP2);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate audio codec context\n");
+ exit(1);
+ }
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+ outfile = fopen(outfilename, "wb");
+ if (!outfile) {
+ av_free(c);
+ exit(1);
+ }
+
+ /* decode until eof */
+ avpkt.data = inbuf;
+ avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
+
+ while (avpkt.size > 0) {
+ int i, ch;
+ int got_frame = 0;
+
+ if (!decoded_frame) {
+ if (!(decoded_frame = av_frame_alloc())) {
+ fprintf(stderr, "Could not allocate audio frame\n");
+ exit(1);
+ }
+ }
+
+ len = avcodec_decode_audio4(c, decoded_frame, &got_frame, &avpkt);
+ if (len < 0) {
+ fprintf(stderr, "Error while decoding\n");
+ exit(1);
+ }
+ if (got_frame) {
+ /* if a frame has been decoded, output it */
+ int data_size = av_get_bytes_per_sample(c->sample_fmt);
+ if (data_size < 0) {
+ /* This should not occur, checking just for paranoia */
+ fprintf(stderr, "Failed to calculate data size\n");
+ exit(1);
+ }
+ for (i=0; i<decoded_frame->nb_samples; i++)
+ for (ch=0; ch<c->channels; ch++)
+ fwrite(decoded_frame->data[ch] + data_size*i, 1, data_size, outfile);
+ }
+ avpkt.size -= len;
+ avpkt.data += len;
+ avpkt.dts =
+ avpkt.pts = AV_NOPTS_VALUE;
+ if (avpkt.size < AUDIO_REFILL_THRESH) {
+ /* Refill the input buffer, to avoid trying to decode
+ * incomplete frames. Instead of this, one could also use
+ * a parser, or use a proper container format through
+ * libavformat. */
+ memmove(inbuf, avpkt.data, avpkt.size);
+ avpkt.data = inbuf;
+ len = fread(avpkt.data + avpkt.size, 1,
+ AUDIO_INBUF_SIZE - avpkt.size, f);
+ if (len > 0)
+ avpkt.size += len;
+ }
+ }
+
+ fclose(outfile);
+ fclose(f);
+
+ avcodec_close(c);
+ av_free(c);
+ av_frame_free(&decoded_frame);
+}
+
+/*
+ * Video encoding example
+ */
+static void video_encode_example(const char *filename, int codec_id)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ int i, ret, x, y, got_output;
+ FILE *f;
+ AVFrame *frame;
+ AVPacket pkt;
+ uint8_t endcode[] = { 0, 0, 1, 0xb7 };
+
+ printf("Encode video file %s\n", filename);
+
+ /* find the mpeg1 video encoder */
+ codec = avcodec_find_encoder(codec_id);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate video codec context\n");
+ exit(1);
+ }
+
+ /* put sample parameters */
+ c->bit_rate = 400000;
+ /* resolution must be a multiple of two */
+ c->width = 352;
+ c->height = 288;
+ /* frames per second */
+ c->time_base = (AVRational){1,25};
+ /* emit one intra frame every ten frames
+ * check frame pict_type before passing frame
+ * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
+ * then gop_size is ignored and the output of encoder
+ * will always be I frame irrespective to gop_size
+ */
+ c->gop_size = 10;
+ c->max_b_frames = 1;
+ c->pix_fmt = AV_PIX_FMT_YUV420P;
+
+ if (codec_id == AV_CODEC_ID_H264)
+ av_opt_set(c->priv_data, "preset", "slow", 0);
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+
+ frame = av_frame_alloc();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ exit(1);
+ }
+ frame->format = c->pix_fmt;
+ frame->width = c->width;
+ frame->height = c->height;
+
+ /* the image can be allocated by any means and av_image_alloc() is
+ * just the most convenient way if av_malloc() is to be used */
+ ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
+ c->pix_fmt, 32);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate raw picture buffer\n");
+ exit(1);
+ }
+
+ /* encode 1 second of video */
+ for (i = 0; i < 25; i++) {
+ av_init_packet(&pkt);
+ pkt.data = NULL; // packet data will be allocated by the encoder
+ pkt.size = 0;
+
+ fflush(stdout);
+ /* prepare a dummy image */
+ /* Y */
+ for (y = 0; y < c->height; y++) {
+ for (x = 0; x < c->width; x++) {
+ frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
+ }
+ }
+
+ /* Cb and Cr */
+ for (y = 0; y < c->height/2; y++) {
+ for (x = 0; x < c->width/2; x++) {
+ frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
+ frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
+ }
+ }
+
+ frame->pts = i;
+
+ /* encode the image */
+ ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
+ exit(1);
+ }
+
+ if (got_output) {
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* get the delayed frames */
+ for (got_output = 1; got_output; i++) {
+ fflush(stdout);
+
+ ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding frame\n");
+ exit(1);
+ }
+
+ if (got_output) {
+ printf("Write frame %3d (size=%5d)\n", i, pkt.size);
+ fwrite(pkt.data, 1, pkt.size, f);
+ av_free_packet(&pkt);
+ }
+ }
+
+ /* add sequence end code to have a real mpeg file */
+ fwrite(endcode, 1, sizeof(endcode), f);
+ fclose(f);
+
+ avcodec_close(c);
+ av_free(c);
+ av_freep(&frame->data[0]);
+ av_frame_free(&frame);
+ printf("\n");
+}
+
+/*
+ * Video decoding example
+ */
+
+static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize,
+ char *filename)
+{
+ FILE *f;
+ int i;
+
+ f = fopen(filename,"w");
+ fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
+ for (i = 0; i < ysize; i++)
+ fwrite(buf + i * wrap, 1, xsize, f);
+ fclose(f);
+}
+
+static int decode_write_frame(const char *outfilename, AVCodecContext *avctx,
+ AVFrame *frame, int *frame_count, AVPacket *pkt, int last)
+{
+ int len, got_frame;
+ char buf[1024];
+
+ len = avcodec_decode_video2(avctx, frame, &got_frame, pkt);
+ if (len < 0) {
+ fprintf(stderr, "Error while decoding frame %d\n", *frame_count);
+ return len;
+ }
+ if (got_frame) {
+ printf("Saving %sframe %3d\n", last ? "last " : "", *frame_count);
+ fflush(stdout);
+
+ /* the picture is allocated by the decoder, no need to free it */
+ snprintf(buf, sizeof(buf), outfilename, *frame_count);
+ pgm_save(frame->data[0], frame->linesize[0],
+ avctx->width, avctx->height, buf);
+ (*frame_count)++;
+ }
+ if (pkt->data) {
+ pkt->size -= len;
+ pkt->data += len;
+ }
+ return 0;
+}
+
+static void video_decode_example(const char *outfilename, const char *filename)
+{
+ AVCodec *codec;
+ AVCodecContext *c= NULL;
+ int frame_count;
+ FILE *f;
+ AVFrame *frame;
+ uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
+ AVPacket avpkt;
+
+ av_init_packet(&avpkt);
+
+ /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
+ memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
+ printf("Decode video file %s to %s\n", filename, outfilename);
+
+ /* find the mpeg1 video decoder */
+ codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
+ if (!codec) {
+ fprintf(stderr, "Codec not found\n");
+ exit(1);
+ }
+
+ c = avcodec_alloc_context3(codec);
+ if (!c) {
+ fprintf(stderr, "Could not allocate video codec context\n");
+ exit(1);
+ }
+
+ if(codec->capabilities&CODEC_CAP_TRUNCATED)
+ c->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
+
+ /* For some codecs, such as msmpeg4 and mpeg4, width and height
+ MUST be initialized there because this information is not
+ available in the bitstream. */
+
+ /* open it */
+ if (avcodec_open2(c, codec, NULL) < 0) {
+ fprintf(stderr, "Could not open codec\n");
+ exit(1);
+ }
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ fprintf(stderr, "Could not open %s\n", filename);
+ exit(1);
+ }
+
+ frame = av_frame_alloc();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ exit(1);
+ }
+
+ frame_count = 0;
+ for (;;) {
+ avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
+ if (avpkt.size == 0)
+ break;
+
+ /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
+ and this is the only method to use them because you cannot
+ know the compressed data size before analysing it.
+
+ BUT some other codecs (msmpeg4, mpeg4) are inherently frame
+ based, so you must call them with all the data for one
+ frame exactly. You must also initialize 'width' and
+ 'height' before initializing them. */
+
+ /* NOTE2: some codecs allow the raw parameters (frame size,
+ sample rate) to be changed at any frame. We handle this, so
+ you should also take care of it */
+
+ /* here, we use a stream based decoder (mpeg1video), so we
+ feed decoder and see if it could decode a frame */
+ avpkt.data = inbuf;
+ while (avpkt.size > 0)
+ if (decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 0) < 0)
+ exit(1);
+ }
+
+ /* some codecs, such as MPEG, transmit the I and P frame with a
+ latency of one frame. You must do the following to have a
+ chance to get the last frame of the video */
+ avpkt.data = NULL;
+ avpkt.size = 0;
+ decode_write_frame(outfilename, c, frame, &frame_count, &avpkt, 1);
+
+ fclose(f);
+
+ avcodec_close(c);
+ av_free(c);
+ av_frame_free(&frame);
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ const char *output_type;
+
+ /* register all the codecs */
+ avcodec_register_all();
+
+ if (argc < 2) {
+ printf("usage: %s output_type\n"
+ "API example program to decode/encode a media stream with libavcodec.\n"
+ "This program generates a synthetic stream and encodes it to a file\n"
+ "named test.h264, test.mp2 or test.mpg depending on output_type.\n"
+ "The encoded stream is then decoded and written to a raw data output.\n"
+ "output_type must be chosen between 'h264', 'mp2', 'mpg'.\n",
+ argv[0]);
+ return 1;
+ }
+ output_type = argv[1];
+
+ if (!strcmp(output_type, "h264")) {
+ video_encode_example("test.h264", AV_CODEC_ID_H264);
+ } else if (!strcmp(output_type, "mp2")) {
+ audio_encode_example("test.mp2");
+ audio_decode_example("test.pcm", "test.mp2");
+ } else if (!strcmp(output_type, "mpg")) {
+ video_encode_example("test.mpg", AV_CODEC_ID_MPEG1VIDEO);
+ video_decode_example("test%02d.pgm", "test.mpg");
+ } else {
+ fprintf(stderr, "Invalid output type '%s', choose between 'h264', 'mp2', or 'mpg'\n",
+ output_type);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/doc/examples/demuxing_decoding.c b/doc/examples/demuxing_decoding.c
new file mode 100644
index 0000000000..feeeb967f8
--- /dev/null
+++ b/doc/examples/demuxing_decoding.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * Demuxing and decoding example.
+ *
+ * Show how to use the libavformat and libavcodec API to demux and
+ * decode audio and video data.
+ * @example demuxing_decoding.c
+ */
+
+#include <libavutil/imgutils.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/timestamp.h>
+#include <libavformat/avformat.h>
+
+static AVFormatContext *fmt_ctx = NULL;
+static AVCodecContext *video_dec_ctx = NULL, *audio_dec_ctx;
+static int width, height;
+static enum AVPixelFormat pix_fmt;
+static AVStream *video_stream = NULL, *audio_stream = NULL;
+static const char *src_filename = NULL;
+static const char *video_dst_filename = NULL;
+static const char *audio_dst_filename = NULL;
+static FILE *video_dst_file = NULL;
+static FILE *audio_dst_file = NULL;
+
+static uint8_t *video_dst_data[4] = {NULL};
+static int video_dst_linesize[4];
+static int video_dst_bufsize;
+
+static int video_stream_idx = -1, audio_stream_idx = -1;
+static AVFrame *frame = NULL;
+static AVPacket pkt;
+static int video_frame_count = 0;
+static int audio_frame_count = 0;
+
+/* The different ways of decoding and managing data memory. You are not
+ * supposed to support all the modes in your application but pick the one most
+ * appropriate to your needs. Look for the use of api_mode in this example to
+ * see what are the differences of API usage between them */
+enum {
+ API_MODE_OLD = 0, /* old method, deprecated */
+ API_MODE_NEW_API_REF_COUNT = 1, /* new method, using the frame reference counting */
+ API_MODE_NEW_API_NO_REF_COUNT = 2, /* new method, without reference counting */
+};
+
+static int api_mode = API_MODE_OLD;
+
+static int decode_packet(int *got_frame, int cached)
+{
+ int ret = 0;
+ int decoded = pkt.size;
+
+ *got_frame = 0;
+
+ if (pkt.stream_index == video_stream_idx) {
+ /* decode video frame */
+ ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding video frame (%s)\n", av_err2str(ret));
+ return ret;
+ }
+ if (video_dec_ctx->width != width || video_dec_ctx->height != height ||
+ video_dec_ctx->pix_fmt != pix_fmt) {
+ /* To handle this change, one could call av_image_alloc again and
+ * decode the following frames into another rawvideo file. */
+ fprintf(stderr, "Error: Width, height and pixel format have to be "
+ "constant in a rawvideo file, but the width, height or "
+ "pixel format of the input video changed:\n"
+ "old: width = %d, height = %d, format = %s\n"
+ "new: width = %d, height = %d, format = %s\n",
+ width, height, av_get_pix_fmt_name(pix_fmt),
+ video_dec_ctx->width, video_dec_ctx->height,
+ av_get_pix_fmt_name(video_dec_ctx->pix_fmt));
+ return -1;
+ }
+
+ if (*got_frame) {
+ printf("video_frame%s n:%d coded_n:%d pts:%s\n",
+ cached ? "(cached)" : "",
+ video_frame_count++, frame->coded_picture_number,
+ av_ts2timestr(frame->pts, &video_dec_ctx->time_base));
+
+ /* copy decoded frame to destination buffer:
+ * this is required since rawvideo expects non aligned data */
+ av_image_copy(video_dst_data, video_dst_linesize,
+ (const uint8_t **)(frame->data), frame->linesize,
+ pix_fmt, width, height);
+
+ /* write to rawvideo file */
+ fwrite(video_dst_data[0], 1, video_dst_bufsize, video_dst_file);
+ }
+ } else if (pkt.stream_index == audio_stream_idx) {
+ /* decode audio frame */
+ ret = avcodec_decode_audio4(audio_dec_ctx, frame, got_frame, &pkt);
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding audio frame (%s)\n", av_err2str(ret));
+ return ret;
+ }
+ /* Some audio decoders decode only part of the packet, and have to be
+ * called again with the remainder of the packet data.
+ * Sample: fate-suite/lossless-audio/luckynight-partial.shn
+ * Also, some decoders might over-read the packet. */
+ decoded = FFMIN(ret, pkt.size);
+
+ if (*got_frame) {
+ size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format);
+ printf("audio_frame%s n:%d nb_samples:%d pts:%s\n",
+ cached ? "(cached)" : "",
+ audio_frame_count++, frame->nb_samples,
+ av_ts2timestr(frame->pts, &audio_dec_ctx->time_base));
+
+ /* Write the raw audio data samples of the first plane. This works
+ * fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,
+ * most audio decoders output planar audio, which uses a separate
+ * plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).
+ * In other words, this code will write only the first audio channel
+ * in these cases.
+ * You should use libswresample or libavfilter to convert the frame
+ * to packed data. */
+ fwrite(frame->extended_data[0], 1, unpadded_linesize, audio_dst_file);
+ }
+ }
+
+ /* If we use the new API with reference counting, we own the data and need
+ * to de-reference it when we don't use it anymore */
+ if (*got_frame && api_mode == API_MODE_NEW_API_REF_COUNT)
+ av_frame_unref(frame);
+
+ return decoded;
+}
+
+static int open_codec_context(int *stream_idx,
+ AVFormatContext *fmt_ctx, enum AVMediaType type)
+{
+ int ret, stream_index;
+ AVStream *st;
+ AVCodecContext *dec_ctx = NULL;
+ AVCodec *dec = NULL;
+ AVDictionary *opts = NULL;
+
+ ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not find %s stream in input file '%s'\n",
+ av_get_media_type_string(type), src_filename);
+ return ret;
+ } else {
+ stream_index = ret;
+ st = fmt_ctx->streams[stream_index];
+
+ /* find decoder for the stream */
+ dec_ctx = st->codec;
+ dec = avcodec_find_decoder(dec_ctx->codec_id);
+ if (!dec) {
+ fprintf(stderr, "Failed to find %s codec\n",
+ av_get_media_type_string(type));
+ return AVERROR(EINVAL);
+ }
+
+ /* Init the decoders, with or without reference counting */
+ if (api_mode == API_MODE_NEW_API_REF_COUNT)
+ av_dict_set(&opts, "refcounted_frames", "1", 0);
+ if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
+ fprintf(stderr, "Failed to open %s codec\n",
+ av_get_media_type_string(type));
+ return ret;
+ }
+ *stream_idx = stream_index;
+ }
+
+ return 0;
+}
+
+static int get_format_from_sample_fmt(const char **fmt,
+ enum AVSampleFormat sample_fmt)
+{
+ int i;
+ struct sample_fmt_entry {
+ enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
+ } sample_fmt_entries[] = {
+ { AV_SAMPLE_FMT_U8, "u8", "u8" },
+ { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
+ { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
+ { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
+ { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
+ };
+ *fmt = NULL;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
+ struct sample_fmt_entry *entry = &sample_fmt_entries[i];
+ if (sample_fmt == entry->sample_fmt) {
+ *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
+ return 0;
+ }
+ }
+
+ fprintf(stderr,
+ "sample format %s is not supported as output format\n",
+ av_get_sample_fmt_name(sample_fmt));
+ return -1;
+}
+
+int main (int argc, char **argv)
+{
+ int ret = 0, got_frame;
+
+ if (argc != 4 && argc != 5) {
+ fprintf(stderr, "usage: %s [-refcount=<old|new_norefcount|new_refcount>] "
+ "input_file video_output_file audio_output_file\n"
+ "API example program to show how to read frames from an input file.\n"
+ "This program reads frames from a file, decodes them, and writes decoded\n"
+ "video frames to a rawvideo file named video_output_file, and decoded\n"
+ "audio frames to a rawaudio file named audio_output_file.\n\n"
+ "If the -refcount option is specified, the program use the\n"
+ "reference counting frame system which allows keeping a copy of\n"
+ "the data for longer than one decode call. If unset, it's using\n"
+ "the classic old method.\n"
+ "\n", argv[0]);
+ exit(1);
+ }
+ if (argc == 5) {
+ const char *mode = argv[1] + strlen("-refcount=");
+ if (!strcmp(mode, "old")) api_mode = API_MODE_OLD;
+ else if (!strcmp(mode, "new_norefcount")) api_mode = API_MODE_NEW_API_NO_REF_COUNT;
+ else if (!strcmp(mode, "new_refcount")) api_mode = API_MODE_NEW_API_REF_COUNT;
+ else {
+ fprintf(stderr, "unknow mode '%s'\n", mode);
+ exit(1);
+ }
+ argv++;
+ }
+ src_filename = argv[1];
+ video_dst_filename = argv[2];
+ audio_dst_filename = argv[3];
+
+ /* register all formats and codecs */
+ av_register_all();
+
+ /* open input file, and allocate format context */
+ if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
+ fprintf(stderr, "Could not open source file %s\n", src_filename);
+ exit(1);
+ }
+
+ /* retrieve stream information */
+ if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
+ fprintf(stderr, "Could not find stream information\n");
+ exit(1);
+ }
+
+ if (open_codec_context(&video_stream_idx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
+ video_stream = fmt_ctx->streams[video_stream_idx];
+ video_dec_ctx = video_stream->codec;
+
+ video_dst_file = fopen(video_dst_filename, "wb");
+ if (!video_dst_file) {
+ fprintf(stderr, "Could not open destination file %s\n", video_dst_filename);
+ ret = 1;
+ goto end;
+ }
+
+ /* allocate image where the decoded image will be put */
+ width = video_dec_ctx->width;
+ height = video_dec_ctx->height;
+ pix_fmt = video_dec_ctx->pix_fmt;
+ ret = av_image_alloc(video_dst_data, video_dst_linesize,
+ width, height, pix_fmt, 1);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate raw video buffer\n");
+ goto end;
+ }
+ video_dst_bufsize = ret;
+ }
+
+ if (open_codec_context(&audio_stream_idx, fmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0) {
+ audio_stream = fmt_ctx->streams[audio_stream_idx];
+ audio_dec_ctx = audio_stream->codec;
+ audio_dst_file = fopen(audio_dst_filename, "wb");
+ if (!audio_dst_file) {
+ fprintf(stderr, "Could not open destination file %s\n", audio_dst_filename);
+ ret = 1;
+ goto end;
+ }
+ }
+
+ /* dump input information to stderr */
+ av_dump_format(fmt_ctx, 0, src_filename, 0);
+
+ if (!audio_stream && !video_stream) {
+ fprintf(stderr, "Could not find audio or video stream in the input, aborting\n");
+ ret = 1;
+ goto end;
+ }
+
+ /* When using the new API, you need to use the libavutil/frame.h API, while
+ * the classic frame management is available in libavcodec */
+ if (api_mode == API_MODE_OLD)
+ frame = avcodec_alloc_frame();
+ else
+ frame = av_frame_alloc();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate frame\n");
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* initialize packet, set data to NULL, let the demuxer fill it */
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ if (video_stream)
+ printf("Demuxing video from file '%s' into '%s'\n", src_filename, video_dst_filename);
+ if (audio_stream)
+ printf("Demuxing audio from file '%s' into '%s'\n", src_filename, audio_dst_filename);
+
+ /* read frames from the file */
+ while (av_read_frame(fmt_ctx, &pkt) >= 0) {
+ AVPacket orig_pkt = pkt;
+ do {
+ ret = decode_packet(&got_frame, 0);
+ if (ret < 0)
+ break;
+ pkt.data += ret;
+ pkt.size -= ret;
+ } while (pkt.size > 0);
+ av_free_packet(&orig_pkt);
+ }
+
+ /* flush cached frames */
+ pkt.data = NULL;
+ pkt.size = 0;
+ do {
+ decode_packet(&got_frame, 1);
+ } while (got_frame);
+
+ printf("Demuxing succeeded.\n");
+
+ if (video_stream) {
+ printf("Play the output video file with the command:\n"
+ "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
+ av_get_pix_fmt_name(pix_fmt), width, height,
+ video_dst_filename);
+ }
+
+ if (audio_stream) {
+ enum AVSampleFormat sfmt = audio_dec_ctx->sample_fmt;
+ int n_channels = audio_dec_ctx->channels;
+ const char *fmt;
+
+ if (av_sample_fmt_is_planar(sfmt)) {
+ const char *packed = av_get_sample_fmt_name(sfmt);
+ printf("Warning: the sample format the decoder produced is planar "
+ "(%s). This example will output the first channel only.\n",
+ packed ? packed : "?");
+ sfmt = av_get_packed_sample_fmt(sfmt);
+ n_channels = 1;
+ }
+
+ if ((ret = get_format_from_sample_fmt(&fmt, sfmt)) < 0)
+ goto end;
+
+ printf("Play the output audio file with the command:\n"
+ "ffplay -f %s -ac %d -ar %d %s\n",
+ fmt, n_channels, audio_dec_ctx->sample_rate,
+ audio_dst_filename);
+ }
+
+end:
+ avcodec_close(video_dec_ctx);
+ avcodec_close(audio_dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ if (video_dst_file)
+ fclose(video_dst_file);
+ if (audio_dst_file)
+ fclose(audio_dst_file);
+ if (api_mode == API_MODE_OLD)
+ avcodec_free_frame(&frame);
+ else
+ av_frame_free(&frame);
+ av_free(video_dst_data[0]);
+
+ return ret < 0;
+}
diff --git a/doc/examples/extract_mvs.c b/doc/examples/extract_mvs.c
new file mode 100644
index 0000000000..d6fd61335e
--- /dev/null
+++ b/doc/examples/extract_mvs.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ * Copyright (c) 2014 ClĂ©ment BÅ“sch
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <libavutil/motion_vector.h>
+#include <libavformat/avformat.h>
+
+static AVFormatContext *fmt_ctx = NULL;
+static AVCodecContext *video_dec_ctx = NULL;
+static AVStream *video_stream = NULL;
+static const char *src_filename = NULL;
+
+static int video_stream_idx = -1;
+static AVFrame *frame = NULL;
+static AVPacket pkt;
+static int video_frame_count = 0;
+
+static int decode_packet(int *got_frame, int cached)
+{
+ int decoded = pkt.size;
+
+ *got_frame = 0;
+
+ if (pkt.stream_index == video_stream_idx) {
+ int ret = avcodec_decode_video2(video_dec_ctx, frame, got_frame, &pkt);
+ if (ret < 0) {
+ fprintf(stderr, "Error decoding video frame (%s)\n", av_err2str(ret));
+ return ret;
+ }
+
+ if (*got_frame) {
+ int i;
+ AVFrameSideData *sd;
+
+ video_frame_count++;
+ sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
+ if (sd) {
+ const AVMotionVector *mvs = (const AVMotionVector *)sd->data;
+ for (i = 0; i < sd->size / sizeof(*mvs); i++) {
+ const AVMotionVector *mv = &mvs[i];
+ printf("%d,%2d,%2d,%2d,%4d,%4d,%4d,%4d,0x%"PRIx64"\n",
+ video_frame_count, mv->source,
+ mv->w, mv->h, mv->src_x, mv->src_y,
+ mv->dst_x, mv->dst_y, mv->flags);
+ }
+ }
+ }
+ }
+
+ return decoded;
+}
+
+static int open_codec_context(int *stream_idx,
+ AVFormatContext *fmt_ctx, enum AVMediaType type)
+{
+ int ret;
+ AVStream *st;
+ AVCodecContext *dec_ctx = NULL;
+ AVCodec *dec = NULL;
+ AVDictionary *opts = NULL;
+
+ ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not find %s stream in input file '%s'\n",
+ av_get_media_type_string(type), src_filename);
+ return ret;
+ } else {
+ *stream_idx = ret;
+ st = fmt_ctx->streams[*stream_idx];
+
+ /* find decoder for the stream */
+ dec_ctx = st->codec;
+ dec = avcodec_find_decoder(dec_ctx->codec_id);
+ if (!dec) {
+ fprintf(stderr, "Failed to find %s codec\n",
+ av_get_media_type_string(type));
+ return AVERROR(EINVAL);
+ }
+
+ /* Init the video decoder */
+ av_dict_set(&opts, "flags2", "+export_mvs", 0);
+ if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
+ fprintf(stderr, "Failed to open %s codec\n",
+ av_get_media_type_string(type));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int ret = 0, got_frame;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <video>\n", argv[0]);
+ exit(1);
+ }
+ src_filename = argv[1];
+
+ av_register_all();
+
+ if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) {
+ fprintf(stderr, "Could not open source file %s\n", src_filename);
+ exit(1);
+ }
+
+ if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
+ fprintf(stderr, "Could not find stream information\n");
+ exit(1);
+ }
+
+ if (open_codec_context(&video_stream_idx, fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) {
+ video_stream = fmt_ctx->streams[video_stream_idx];
+ video_dec_ctx = video_stream->codec;
+ }
+
+ av_dump_format(fmt_ctx, 0, src_filename, 0);
+
+ if (!video_stream) {
+ fprintf(stderr, "Could not find video stream in the input, aborting\n");
+ ret = 1;
+ goto end;
+ }
+
+ frame = av_frame_alloc();
+ if (!frame) {
+ fprintf(stderr, "Could not allocate frame\n");
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ printf("framenum,source,blockw,blockh,srcx,srcy,dstx,dsty,flags\n");
+
+ /* initialize packet, set data to NULL, let the demuxer fill it */
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ /* read frames from the file */
+ while (av_read_frame(fmt_ctx, &pkt) >= 0) {
+ AVPacket orig_pkt = pkt;
+ do {
+ ret = decode_packet(&got_frame, 0);
+ if (ret < 0)
+ break;
+ pkt.data += ret;
+ pkt.size -= ret;
+ } while (pkt.size > 0);
+ av_free_packet(&orig_pkt);
+ }
+
+ /* flush cached frames */
+ pkt.data = NULL;
+ pkt.size = 0;
+ do {
+ decode_packet(&got_frame, 1);
+ } while (got_frame);
+
+end:
+ avcodec_close(video_dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ av_frame_free(&frame);
+ return ret < 0;
+}
diff --git a/doc/examples/filter_audio.c b/doc/examples/filter_audio.c
index 60fe107dda..01761dcee4 100644
--- a/doc/examples/filter_audio.c
+++ b/doc/examples/filter_audio.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2013 Andrew Kelley
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/doc/examples/filtering_audio.c b/doc/examples/filtering_audio.c
new file mode 100644
index 0000000000..f5cb8eb8a1
--- /dev/null
+++ b/doc/examples/filtering_audio.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2010 Nicolas George
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * API example for audio decoding and filtering
+ * @example filtering_audio.c
+ */
+
+#include <unistd.h>
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavfilter/avfiltergraph.h>
+#include <libavfilter/avcodec.h>
+#include <libavfilter/buffersink.h>
+#include <libavfilter/buffersrc.h>
+#include <libavutil/opt.h>
+
+static const char *filter_descr = "aresample=8000,aformat=sample_fmts=s16:channel_layouts=mono";
+static const char *player = "ffplay -f s16le -ar 8000 -ac 1 -";
+
+static AVFormatContext *fmt_ctx;
+static AVCodecContext *dec_ctx;
+AVFilterContext *buffersink_ctx;
+AVFilterContext *buffersrc_ctx;
+AVFilterGraph *filter_graph;
+static int audio_stream_index = -1;
+
+static int open_input_file(const char *filename)
+{
+ int ret;
+ AVCodec *dec;
+
+ if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
+ return ret;
+ }
+
+ if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
+ return ret;
+ }
+
+ /* select the audio stream */
+ ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot find a audio stream in the input file\n");
+ return ret;
+ }
+ audio_stream_index = ret;
+ dec_ctx = fmt_ctx->streams[audio_stream_index]->codec;
+ av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);
+
+ /* init the audio decoder */
+ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open audio decoder\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int init_filters(const char *filters_descr)
+{
+ char args[512];
+ int ret = 0;
+ AVFilter *abuffersrc = avfilter_get_by_name("abuffer");
+ AVFilter *abuffersink = avfilter_get_by_name("abuffersink");
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
+ static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
+ static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_MONO, -1 };
+ static const int out_sample_rates[] = { 8000, -1 };
+ const AVFilterLink *outlink;
+ AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base;
+
+ filter_graph = avfilter_graph_alloc();
+ if (!outputs || !inputs || !filter_graph) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* buffer audio source: the decoded frames from the decoder will be inserted here. */
+ if (!dec_ctx->channel_layout)
+ dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels);
+ snprintf(args, sizeof(args),
+ "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
+ time_base.num, time_base.den, dec_ctx->sample_rate,
+ av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout);
+ ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in",
+ args, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
+ goto end;
+ }
+
+ /* buffer audio sink: to terminate the filter chain. */
+ ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out",
+ NULL, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
+ goto end;
+ }
+
+ ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1,
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
+ goto end;
+ }
+
+ ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1,
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
+ goto end;
+ }
+
+ ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1,
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
+ goto end;
+ }
+
+ /*
+ * Set the endpoints for the filter graph. The filter_graph will
+ * be linked to the graph described by filters_descr.
+ */
+
+ /*
+ * The buffer source output must be connected to the input pad of
+ * the first filter described by filters_descr; since the first
+ * filter input label is not specified, it is set to "in" by
+ * default.
+ */
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = buffersrc_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ /*
+ * The buffer sink input must be connected to the output pad of
+ * the last filter described by filters_descr; since the last
+ * filter output label is not specified, it is set to "out" by
+ * default.
+ */
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = buffersink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
+ &inputs, &outputs, NULL)) < 0)
+ goto end;
+
+ if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
+ goto end;
+
+ /* Print summary of the sink buffer
+ * Note: args buffer is reused to store channel layout string */
+ outlink = buffersink_ctx->inputs[0];
+ av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout);
+ av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n",
+ (int)outlink->sample_rate,
+ (char *)av_x_if_null(av_get_sample_fmt_name(outlink->format), "?"),
+ args);
+
+end:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+
+ return ret;
+}
+
+static void print_frame(const AVFrame *frame)
+{
+ const int n = frame->nb_samples * av_get_channel_layout_nb_channels(av_frame_get_channel_layout(frame));
+ const uint16_t *p = (uint16_t*)frame->data[0];
+ const uint16_t *p_end = p + n;
+
+ while (p < p_end) {
+ fputc(*p & 0xff, stdout);
+ fputc(*p>>8 & 0xff, stdout);
+ p++;
+ }
+ fflush(stdout);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ AVPacket packet0, packet;
+ AVFrame *frame = av_frame_alloc();
+ AVFrame *filt_frame = av_frame_alloc();
+ int got_frame;
+
+ if (!frame || !filt_frame) {
+ perror("Could not allocate frame");
+ exit(1);
+ }
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s file | %s\n", argv[0], player);
+ exit(1);
+ }
+
+ av_register_all();
+ avfilter_register_all();
+
+ if ((ret = open_input_file(argv[1])) < 0)
+ goto end;
+ if ((ret = init_filters(filter_descr)) < 0)
+ goto end;
+
+ /* read all packets */
+ packet0.data = NULL;
+ packet.data = NULL;
+ while (1) {
+ if (!packet0.data) {
+ if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
+ break;
+ packet0 = packet;
+ }
+
+ if (packet.stream_index == audio_stream_index) {
+ got_frame = 0;
+ ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, &packet);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error decoding audio\n");
+ continue;
+ }
+ packet.size -= ret;
+ packet.data += ret;
+
+ if (got_frame) {
+ /* push the audio data from decoded frame into the filtergraph */
+ if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, 0) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error while feeding the audio filtergraph\n");
+ break;
+ }
+
+ /* pull filtered audio 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);
+ }
+ }
+
+ if (packet.size <= 0)
+ av_free_packet(&packet0);
+ } else {
+ /* discard non-wanted packets */
+ av_free_packet(&packet0);
+ }
+ }
+end:
+ avfilter_graph_free(&filter_graph);
+ avcodec_close(dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ av_frame_free(&frame);
+ av_frame_free(&filt_frame);
+
+ if (ret < 0 && ret != AVERROR_EOF) {
+ fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/doc/examples/filtering_video.c b/doc/examples/filtering_video.c
new file mode 100644
index 0000000000..c02040ae35
--- /dev/null
+++ b/doc/examples/filtering_video.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2010 Nicolas George
+ * Copyright (c) 2011 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * API example for decoding and filtering
+ * @example filtering_video.c
+ */
+
+#define _XOPEN_SOURCE 600 /* for usleep */
+#include <unistd.h>
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavfilter/avfiltergraph.h>
+#include <libavfilter/avcodec.h>
+#include <libavfilter/buffersink.h>
+#include <libavfilter/buffersrc.h>
+#include <libavutil/opt.h>
+
+const char *filter_descr = "scale=78:24";
+
+static AVFormatContext *fmt_ctx;
+static AVCodecContext *dec_ctx;
+AVFilterContext *buffersink_ctx;
+AVFilterContext *buffersrc_ctx;
+AVFilterGraph *filter_graph;
+static int video_stream_index = -1;
+static int64_t last_pts = AV_NOPTS_VALUE;
+
+static int open_input_file(const char *filename)
+{
+ int ret;
+ AVCodec *dec;
+
+ if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
+ return ret;
+ }
+
+ if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
+ return ret;
+ }
+
+ /* select the video stream */
+ ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
+ return ret;
+ }
+ video_stream_index = ret;
+ dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
+ av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);
+
+ /* init the video decoder */
+ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int init_filters(const char *filters_descr)
+{
+ char args[512];
+ int ret = 0;
+ AVFilter *buffersrc = avfilter_get_by_name("buffer");
+ AVFilter *buffersink = avfilter_get_by_name("buffersink");
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
+ AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;
+ enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
+
+ filter_graph = avfilter_graph_alloc();
+ if (!outputs || !inputs || !filter_graph) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* buffer video source: the decoded frames from the decoder will be inserted here. */
+ snprintf(args, sizeof(args),
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+ dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
+ time_base.num, time_base.den,
+ dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);
+
+ ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
+ args, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
+ goto end;
+ }
+
+ /* buffer video sink: to terminate the filter chain. */
+ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
+ NULL, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
+ goto end;
+ }
+
+ ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
+ AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
+ goto end;
+ }
+
+ /*
+ * Set the endpoints for the filter graph. The filter_graph will
+ * be linked to the graph described by filters_descr.
+ */
+
+ /*
+ * The buffer source output must be connected to the input pad of
+ * the first filter described by filters_descr; since the first
+ * filter input label is not specified, it is set to "in" by
+ * default.
+ */
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = buffersrc_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ /*
+ * The buffer sink input must be connected to the output pad of
+ * the last filter described by filters_descr; since the last
+ * filter output label is not specified, it is set to "out" by
+ * default.
+ */
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = buffersink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr,
+ &inputs, &outputs, NULL)) < 0)
+ goto end;
+
+ if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
+ goto end;
+
+end:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+
+ return ret;
+}
+
+static void display_frame(const AVFrame *frame, AVRational time_base)
+{
+ int x, y;
+ uint8_t *p0, *p;
+ int64_t delay;
+
+ if (frame->pts != AV_NOPTS_VALUE) {
+ if (last_pts != AV_NOPTS_VALUE) {
+ /* sleep roughly the right amount of time;
+ * usleep is in microseconds, just like AV_TIME_BASE. */
+ delay = av_rescale_q(frame->pts - last_pts,
+ time_base, AV_TIME_BASE_Q);
+ if (delay > 0 && delay < 1000000)
+ usleep(delay);
+ }
+ last_pts = frame->pts;
+ }
+
+ /* Trivial ASCII grayscale display. */
+ p0 = frame->data[0];
+ puts("\033c");
+ for (y = 0; y < frame->height; y++) {
+ p = p0;
+ for (x = 0; x < frame->width; x++)
+ putchar(" .-+#"[*(p++) / 52]);
+ putchar('\n');
+ p0 += frame->linesize[0];
+ }
+ fflush(stdout);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ AVPacket packet;
+ AVFrame *frame = av_frame_alloc();
+ AVFrame *filt_frame = av_frame_alloc();
+ int got_frame;
+
+ if (!frame || !filt_frame) {
+ perror("Could not allocate frame");
+ exit(1);
+ }
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s file\n", argv[0]);
+ exit(1);
+ }
+
+ av_register_all();
+ avfilter_register_all();
+
+ if ((ret = open_input_file(argv[1])) < 0)
+ goto end;
+ if ((ret = init_filters(filter_descr)) < 0)
+ goto end;
+
+ /* read all packets */
+ while (1) {
+ if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
+ break;
+
+ if (packet.stream_index == video_stream_index) {
+ got_frame = 0;
+ ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, &packet);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error decoding video\n");
+ break;
+ }
+
+ if (got_frame) {
+ frame->pts = av_frame_get_best_effort_timestamp(frame);
+
+ /* push the decoded frame into the filtergraph */
+ if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
+ break;
+ }
+
+ /* pull filtered 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);
+ }
+ av_frame_unref(frame);
+ }
+ }
+ av_free_packet(&packet);
+ }
+end:
+ avfilter_graph_free(&filter_graph);
+ avcodec_close(dec_ctx);
+ avformat_close_input(&fmt_ctx);
+ av_frame_free(&frame);
+ av_frame_free(&filt_frame);
+
+ if (ret < 0 && ret != AVERROR_EOF) {
+ fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ exit(0);
+}
diff --git a/doc/examples/metadata.c b/doc/examples/metadata.c
index f4c6eee9c3..f73c267369 100644
--- a/doc/examples/metadata.c
+++ b/doc/examples/metadata.c
@@ -22,8 +22,8 @@
/**
* @file
- * @example metadata.c
* Shows how the metadata API can be used in application programs.
+ * @example metadata.c
*/
#include <stdio.h>
@@ -51,6 +51,6 @@ int main (int argc, char **argv)
while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
printf("%s=%s\n", tag->key, tag->value);
- avformat_free_context(fmt_ctx);
+ avformat_close_input(&fmt_ctx);
return 0;
}
diff --git a/doc/examples/muxing.c b/doc/examples/muxing.c
new file mode 100644
index 0000000000..8b0ea60bb3
--- /dev/null
+++ b/doc/examples/muxing.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libavformat API example.
+ *
+ * Output a media file in any supported libavformat format. The default
+ * codecs are used.
+ * @example muxing.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <libavutil/avassert.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/opt.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/timestamp.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+#include <libswresample/swresample.h>
+
+#define STREAM_DURATION 10.0
+#define STREAM_FRAME_RATE 25 /* 25 images/s */
+#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
+
+#define SCALE_FLAGS SWS_BICUBIC
+
+// a wrapper around a single output AVStream
+typedef struct OutputStream {
+ AVStream *st;
+
+ /* pts of the next frame that will be generated */
+ int64_t next_pts;
+ int samples_count;
+
+ AVFrame *frame;
+ AVFrame *tmp_frame;
+
+ float t, tincr, tincr2;
+
+ struct SwsContext *sws_ctx;
+ struct SwrContext *swr_ctx;
+} OutputStream;
+
+static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt)
+{
+ AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
+
+ printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
+ pkt->stream_index);
+}
+
+static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
+{
+ /* rescale output packet timestamp values from codec to stream timebase */
+ av_packet_rescale_ts(pkt, *time_base, st->time_base);
+ pkt->stream_index = st->index;
+
+ /* Write the compressed frame to the media file. */
+ log_packet(fmt_ctx, pkt);
+ return av_interleaved_write_frame(fmt_ctx, pkt);
+}
+
+/* Add an output stream. */
+static void add_stream(OutputStream *ost, AVFormatContext *oc,
+ AVCodec **codec,
+ enum AVCodecID codec_id)
+{
+ AVCodecContext *c;
+ int i;
+
+ /* find the encoder */
+ *codec = avcodec_find_encoder(codec_id);
+ if (!(*codec)) {
+ fprintf(stderr, "Could not find encoder for '%s'\n",
+ avcodec_get_name(codec_id));
+ exit(1);
+ }
+
+ ost->st = avformat_new_stream(oc, *codec);
+ if (!ost->st) {
+ fprintf(stderr, "Could not allocate stream\n");
+ exit(1);
+ }
+ ost->st->id = oc->nb_streams-1;
+ c = ost->st->codec;
+
+ switch ((*codec)->type) {
+ case AVMEDIA_TYPE_AUDIO:
+ c->sample_fmt = (*codec)->sample_fmts ?
+ (*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
+ c->bit_rate = 64000;
+ c->sample_rate = 44100;
+ if ((*codec)->supported_samplerates) {
+ c->sample_rate = (*codec)->supported_samplerates[0];
+ for (i = 0; (*codec)->supported_samplerates[i]; i++) {
+ if ((*codec)->supported_samplerates[i] == 44100)
+ c->sample_rate = 44100;
+ }
+ }
+ c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
+ c->channel_layout = AV_CH_LAYOUT_STEREO;
+ if ((*codec)->channel_layouts) {
+ c->channel_layout = (*codec)->channel_layouts[0];
+ for (i = 0; (*codec)->channel_layouts[i]; i++) {
+ if ((*codec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
+ c->channel_layout = AV_CH_LAYOUT_STEREO;
+ }
+ }
+ c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
+ ost->st->time_base = (AVRational){ 1, c->sample_rate };
+ break;
+
+ case AVMEDIA_TYPE_VIDEO:
+ c->codec_id = codec_id;
+
+ c->bit_rate = 400000;
+ /* Resolution must be a multiple of two. */
+ c->width = 352;
+ c->height = 288;
+ /* timebase: This is the fundamental unit of time (in seconds) in terms
+ * of which frame timestamps are represented. For fixed-fps content,
+ * timebase should be 1/framerate and timestamp increments should be
+ * identical to 1. */
+ ost->st->time_base = (AVRational){ 1, STREAM_FRAME_RATE };
+ c->time_base = ost->st->time_base;
+
+ c->gop_size = 12; /* emit one intra frame every twelve frames at most */
+ c->pix_fmt = STREAM_PIX_FMT;
+ if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+ /* just for testing, we also add B frames */
+ c->max_b_frames = 2;
+ }
+ if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
+ /* Needed to avoid using macroblocks in which some coeffs overflow.
+ * This does not happen with normal video, it just happens here as
+ * the motion of the chroma plane does not match the luma plane. */
+ c->mb_decision = 2;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Some formats want stream headers to be separate. */
+ if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+ c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+}
+
+/**************************************************************/
+/* audio output */
+
+static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
+ uint64_t channel_layout,
+ int sample_rate, int nb_samples)
+{
+ AVFrame *frame = av_frame_alloc();
+ int ret;
+
+ if (!frame) {
+ fprintf(stderr, "Error allocating an audio frame\n");
+ exit(1);
+ }
+
+ frame->format = sample_fmt;
+ frame->channel_layout = channel_layout;
+ frame->sample_rate = sample_rate;
+ frame->nb_samples = nb_samples;
+
+ if (nb_samples) {
+ ret = av_frame_get_buffer(frame, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Error allocating an audio buffer\n");
+ exit(1);
+ }
+ }
+
+ return frame;
+}
+
+static void open_audio(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
+{
+ AVCodecContext *c;
+ int nb_samples;
+ int ret;
+ AVDictionary *opt = NULL;
+
+ c = ost->st->codec;
+
+ /* open it */
+ av_dict_copy(&opt, opt_arg, 0);
+ ret = avcodec_open2(c, codec, &opt);
+ av_dict_free(&opt);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open audio codec: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ /* init signal generator */
+ ost->t = 0;
+ ost->tincr = 2 * M_PI * 110.0 / c->sample_rate;
+ /* increment frequency by 110 Hz per second */
+ ost->tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
+
+ if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
+ nb_samples = 10000;
+ else
+ nb_samples = c->frame_size;
+
+ ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout,
+ c->sample_rate, nb_samples);
+ ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, c->channel_layout,
+ c->sample_rate, nb_samples);
+
+ /* create resampler context */
+ ost->swr_ctx = swr_alloc();
+ if (!ost->swr_ctx) {
+ fprintf(stderr, "Could not allocate resampler context\n");
+ exit(1);
+ }
+
+ /* set options */
+ av_opt_set_int (ost->swr_ctx, "in_channel_count", c->channels, 0);
+ av_opt_set_int (ost->swr_ctx, "in_sample_rate", c->sample_rate, 0);
+ av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ av_opt_set_int (ost->swr_ctx, "out_channel_count", c->channels, 0);
+ av_opt_set_int (ost->swr_ctx, "out_sample_rate", c->sample_rate, 0);
+ av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0);
+
+ /* initialize the resampling context */
+ if ((ret = swr_init(ost->swr_ctx)) < 0) {
+ fprintf(stderr, "Failed to initialize the resampling context\n");
+ exit(1);
+ }
+}
+
+/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
+ * 'nb_channels' channels. */
+static AVFrame *get_audio_frame(OutputStream *ost)
+{
+ AVFrame *frame = ost->tmp_frame;
+ int j, i, v;
+ int16_t *q = (int16_t*)frame->data[0];
+
+ /* check if we want to generate more frames */
+ if (av_compare_ts(ost->next_pts, ost->st->codec->time_base,
+ STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
+ return NULL;
+
+ for (j = 0; j <frame->nb_samples; j++) {
+ v = (int)(sin(ost->t) * 10000);
+ for (i = 0; i < ost->st->codec->channels; i++)
+ *q++ = v;
+ ost->t += ost->tincr;
+ ost->tincr += ost->tincr2;
+ }
+
+ frame->pts = ost->next_pts;
+ ost->next_pts += frame->nb_samples;
+
+ return frame;
+}
+
+/*
+ * encode one audio frame and send it to the muxer
+ * return 1 when encoding is finished, 0 otherwise
+ */
+static int write_audio_frame(AVFormatContext *oc, OutputStream *ost)
+{
+ AVCodecContext *c;
+ AVPacket pkt = { 0 }; // data and size must be 0;
+ AVFrame *frame;
+ int ret;
+ int got_packet;
+ int dst_nb_samples;
+
+ av_init_packet(&pkt);
+ c = ost->st->codec;
+
+ frame = get_audio_frame(ost);
+
+ if (frame) {
+ /* convert samples from native format to destination codec format, using the resampler */
+ /* compute destination number of samples */
+ dst_nb_samples = av_rescale_rnd(swr_get_delay(ost->swr_ctx, c->sample_rate) + frame->nb_samples,
+ c->sample_rate, c->sample_rate, AV_ROUND_UP);
+ av_assert0(dst_nb_samples == frame->nb_samples);
+
+ /* when we pass a frame to the encoder, it may keep a reference to it
+ * internally;
+ * make sure we do not overwrite it here
+ */
+ ret = av_frame_make_writable(ost->frame);
+ if (ret < 0)
+ exit(1);
+
+ /* convert to destination format */
+ ret = swr_convert(ost->swr_ctx,
+ ost->frame->data, dst_nb_samples,
+ (const uint8_t **)frame->data, frame->nb_samples);
+ if (ret < 0) {
+ fprintf(stderr, "Error while converting\n");
+ exit(1);
+ }
+ frame = ost->frame;
+
+ frame->pts = av_rescale_q(ost->samples_count, (AVRational){1, c->sample_rate}, c->time_base);
+ ost->samples_count += dst_nb_samples;
+ }
+
+ ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ if (got_packet) {
+ ret = write_frame(oc, &c->time_base, ost->st, &pkt);
+ if (ret < 0) {
+ fprintf(stderr, "Error while writing audio frame: %s\n",
+ av_err2str(ret));
+ exit(1);
+ }
+ }
+
+ return (frame || got_packet) ? 0 : 1;
+}
+
+/**************************************************************/
+/* video output */
+
+static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
+{
+ AVFrame *picture;
+ int ret;
+
+ picture = av_frame_alloc();
+ if (!picture)
+ return NULL;
+
+ picture->format = pix_fmt;
+ picture->width = width;
+ picture->height = height;
+
+ /* allocate the buffers for the frame data */
+ ret = av_frame_get_buffer(picture, 32);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+ exit(1);
+ }
+
+ return picture;
+}
+
+static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
+{
+ int ret;
+ AVCodecContext *c = ost->st->codec;
+ AVDictionary *opt = NULL;
+
+ av_dict_copy(&opt, opt_arg, 0);
+
+ /* open the codec */
+ ret = avcodec_open2(c, codec, &opt);
+ av_dict_free(&opt);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ /* allocate and init a re-usable frame */
+ ost->frame = alloc_picture(c->pix_fmt, c->width, c->height);
+ if (!ost->frame) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ exit(1);
+ }
+
+ /* If the output format is not YUV420P, then a temporary YUV420P
+ * picture is needed too. It is then converted to the required
+ * output format. */
+ ost->tmp_frame = NULL;
+ if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
+ ost->tmp_frame = alloc_picture(AV_PIX_FMT_YUV420P, c->width, c->height);
+ if (!ost->tmp_frame) {
+ fprintf(stderr, "Could not allocate temporary picture\n");
+ exit(1);
+ }
+ }
+}
+
+/* Prepare a dummy image. */
+static void fill_yuv_image(AVFrame *pict, int frame_index,
+ int width, int height)
+{
+ int x, y, i, ret;
+
+ /* when we pass a frame to the encoder, it may keep a reference to it
+ * internally;
+ * make sure we do not overwrite it here
+ */
+ ret = av_frame_make_writable(pict);
+ if (ret < 0)
+ exit(1);
+
+ i = frame_index;
+
+ /* Y */
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
+
+ /* Cb and Cr */
+ for (y = 0; y < height / 2; y++) {
+ for (x = 0; x < width / 2; x++) {
+ pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
+ pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
+ }
+ }
+}
+
+static AVFrame *get_video_frame(OutputStream *ost)
+{
+ AVCodecContext *c = ost->st->codec;
+
+ /* check if we want to generate more frames */
+ if (av_compare_ts(ost->next_pts, ost->st->codec->time_base,
+ STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
+ return NULL;
+
+ if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
+ /* as we only generate a YUV420P picture, we must convert it
+ * to the codec pixel format if needed */
+ if (!ost->sws_ctx) {
+ ost->sws_ctx = sws_getContext(c->width, c->height,
+ AV_PIX_FMT_YUV420P,
+ c->width, c->height,
+ c->pix_fmt,
+ SCALE_FLAGS, NULL, NULL, NULL);
+ if (!ost->sws_ctx) {
+ fprintf(stderr,
+ "Could not initialize the conversion context\n");
+ exit(1);
+ }
+ }
+ fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
+ sws_scale(ost->sws_ctx,
+ (const uint8_t * const *)ost->tmp_frame->data, ost->tmp_frame->linesize,
+ 0, c->height, ost->frame->data, ost->frame->linesize);
+ } else {
+ fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height);
+ }
+
+ ost->frame->pts = ost->next_pts++;
+
+ return ost->frame;
+}
+
+/*
+ * encode one video frame and send it to the muxer
+ * return 1 when encoding is finished, 0 otherwise
+ */
+static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
+{
+ int ret;
+ AVCodecContext *c;
+ AVFrame *frame;
+ int got_packet = 0;
+
+ c = ost->st->codec;
+
+ frame = get_video_frame(ost);
+
+ if (oc->oformat->flags & AVFMT_RAWPICTURE) {
+ /* a hack to avoid data copy with some raw video muxers */
+ AVPacket pkt;
+ av_init_packet(&pkt);
+
+ if (!frame)
+ return 1;
+
+ pkt.flags |= AV_PKT_FLAG_KEY;
+ pkt.stream_index = ost->st->index;
+ pkt.data = (uint8_t *)frame;
+ pkt.size = sizeof(AVPicture);
+
+ pkt.pts = pkt.dts = frame->pts;
+ av_packet_rescale_ts(&pkt, c->time_base, ost->st->time_base);
+
+ ret = av_interleaved_write_frame(oc, &pkt);
+ } else {
+ AVPacket pkt = { 0 };
+ av_init_packet(&pkt);
+
+ /* encode the image */
+ ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
+ if (ret < 0) {
+ fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ if (got_packet) {
+ ret = write_frame(oc, &c->time_base, ost->st, &pkt);
+ } else {
+ ret = 0;
+ }
+ }
+
+ if (ret < 0) {
+ fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret));
+ exit(1);
+ }
+
+ return (frame || got_packet) ? 0 : 1;
+}
+
+static void close_stream(AVFormatContext *oc, OutputStream *ost)
+{
+ avcodec_close(ost->st->codec);
+ av_frame_free(&ost->frame);
+ av_frame_free(&ost->tmp_frame);
+ sws_freeContext(ost->sws_ctx);
+ swr_free(&ost->swr_ctx);
+}
+
+/**************************************************************/
+/* media file output */
+
+int main(int argc, char **argv)
+{
+ OutputStream video_st = { 0 }, audio_st = { 0 };
+ const char *filename;
+ AVOutputFormat *fmt;
+ AVFormatContext *oc;
+ AVCodec *audio_codec, *video_codec;
+ int ret;
+ int have_video = 0, have_audio = 0;
+ int encode_video = 0, encode_audio = 0;
+ AVDictionary *opt = NULL;
+
+ /* Initialize libavcodec, and register all codecs and formats. */
+ av_register_all();
+
+ if (argc < 2) {
+ printf("usage: %s output_file\n"
+ "API example program to output a media file with libavformat.\n"
+ "This program generates a synthetic audio and video stream, encodes and\n"
+ "muxes them into a file named output_file.\n"
+ "The output format is automatically guessed according to the file extension.\n"
+ "Raw images can also be output by using '%%d' in the filename.\n"
+ "\n", argv[0]);
+ return 1;
+ }
+
+ filename = argv[1];
+ if (argc > 3 && !strcmp(argv[2], "-flags")) {
+ av_dict_set(&opt, argv[2]+1, argv[3], 0);
+ }
+
+ /* allocate the output media context */
+ avformat_alloc_output_context2(&oc, NULL, NULL, filename);
+ if (!oc) {
+ printf("Could not deduce output format from file extension: using MPEG.\n");
+ avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);
+ }
+ if (!oc)
+ return 1;
+
+ fmt = oc->oformat;
+
+ /* Add the audio and video streams using the default format codecs
+ * and initialize the codecs. */
+ if (fmt->video_codec != AV_CODEC_ID_NONE) {
+ add_stream(&video_st, oc, &video_codec, fmt->video_codec);
+ have_video = 1;
+ encode_video = 1;
+ }
+ if (fmt->audio_codec != AV_CODEC_ID_NONE) {
+ add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);
+ have_audio = 1;
+ encode_audio = 1;
+ }
+
+ /* Now that all the parameters are set, we can open the audio and
+ * video codecs and allocate the necessary encode buffers. */
+ if (have_video)
+ open_video(oc, video_codec, &video_st, opt);
+
+ if (have_audio)
+ open_audio(oc, audio_codec, &audio_st, opt);
+
+ av_dump_format(oc, 0, filename, 1);
+
+ /* open the output file, if needed */
+ if (!(fmt->flags & AVFMT_NOFILE)) {
+ ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open '%s': %s\n", filename,
+ av_err2str(ret));
+ return 1;
+ }
+ }
+
+ /* Write the stream header, if any. */
+ ret = avformat_write_header(oc, &opt);
+ if (ret < 0) {
+ fprintf(stderr, "Error occurred when opening output file: %s\n",
+ av_err2str(ret));
+ return 1;
+ }
+
+ while (encode_video || encode_audio) {
+ /* select the stream to encode */
+ if (encode_video &&
+ (!encode_audio || av_compare_ts(video_st.next_pts, video_st.st->codec->time_base,
+ audio_st.next_pts, audio_st.st->codec->time_base) <= 0)) {
+ encode_video = !write_video_frame(oc, &video_st);
+ } else {
+ encode_audio = !write_audio_frame(oc, &audio_st);
+ }
+ }
+
+ /* Write the trailer, if any. The trailer must be written before you
+ * close the CodecContexts open when you wrote the header; otherwise
+ * av_write_trailer() may try to use memory that was freed on
+ * av_codec_close(). */
+ av_write_trailer(oc);
+
+ /* Close each codec. */
+ if (have_video)
+ close_stream(oc, &video_st);
+ if (have_audio)
+ close_stream(oc, &audio_st);
+
+ if (!(fmt->flags & AVFMT_NOFILE))
+ /* Close the output file. */
+ avio_closep(&oc->pb);
+
+ /* free the stream */
+ avformat_free_context(oc);
+
+ return 0;
+}
diff --git a/doc/examples/output.c b/doc/examples/output.c
deleted file mode 100644
index 0534554360..0000000000
--- a/doc/examples/output.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * Copyright (c) 2003 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/**
- * @file
- * libavformat API example.
- *
- * @example output.c
- * Output a media file in any supported libavformat format. The default
- * codecs are used.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "libavutil/channel_layout.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-#include "libavformat/avformat.h"
-#include "libavresample/avresample.h"
-#include "libswscale/swscale.h"
-
-/* 5 seconds stream duration */
-#define STREAM_DURATION 5.0
-#define STREAM_FRAME_RATE 25 /* 25 images/s */
-#define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE))
-#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
-
-#define SCALE_FLAGS SWS_BICUBIC
-
-// a wrapper around a single output AVStream
-typedef struct OutputStream {
- AVStream *st;
-
- /* pts of the next frame that will be generated */
- int64_t next_pts;
-
- AVFrame *frame;
- AVFrame *tmp_frame;
-
- float t, tincr, tincr2;
-
- struct SwsContext *sws_ctx;
- AVAudioResampleContext *avr;
-} OutputStream;
-
-/**************************************************************/
-/* audio output */
-
-/*
- * add an audio output stream
- */
-static void add_audio_stream(OutputStream *ost, AVFormatContext *oc,
- enum AVCodecID codec_id)
-{
- AVCodecContext *c;
- AVCodec *codec;
- int ret;
-
- /* find the audio encoder */
- codec = avcodec_find_encoder(codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- ost->st = avformat_new_stream(oc, codec);
- if (!ost->st) {
- fprintf(stderr, "Could not alloc stream\n");
- exit(1);
- }
-
- c = ost->st->codec;
-
- /* put sample parameters */
- c->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_S16;
- c->sample_rate = codec->supported_samplerates ? codec->supported_samplerates[0] : 44100;
- c->channel_layout = codec->channel_layouts ? codec->channel_layouts[0] : AV_CH_LAYOUT_STEREO;
- c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
- c->bit_rate = 64000;
-
- ost->st->time_base = (AVRational){ 1, c->sample_rate };
-
- // some formats want stream headers to be separate
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- /* initialize sample format conversion;
- * to simplify the code, we always pass the data through lavr, even
- * if the encoder supports the generated format directly -- the price is
- * some extra data copying;
- */
- ost->avr = avresample_alloc_context();
- if (!ost->avr) {
- fprintf(stderr, "Error allocating the resampling context\n");
- exit(1);
- }
-
- av_opt_set_int(ost->avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
- av_opt_set_int(ost->avr, "in_sample_rate", 44100, 0);
- av_opt_set_int(ost->avr, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
- av_opt_set_int(ost->avr, "out_sample_fmt", c->sample_fmt, 0);
- av_opt_set_int(ost->avr, "out_sample_rate", c->sample_rate, 0);
- av_opt_set_int(ost->avr, "out_channel_layout", c->channel_layout, 0);
-
- ret = avresample_open(ost->avr);
- if (ret < 0) {
- fprintf(stderr, "Error opening the resampling context\n");
- exit(1);
- }
-}
-
-static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
- uint64_t channel_layout,
- int sample_rate, int nb_samples)
-{
- AVFrame *frame = av_frame_alloc();
- int ret;
-
- if (!frame) {
- fprintf(stderr, "Error allocating an audio frame\n");
- exit(1);
- }
-
- frame->format = sample_fmt;
- frame->channel_layout = channel_layout;
- frame->sample_rate = sample_rate;
- frame->nb_samples = nb_samples;
-
- if (nb_samples) {
- ret = av_frame_get_buffer(frame, 0);
- if (ret < 0) {
- fprintf(stderr, "Error allocating an audio buffer\n");
- exit(1);
- }
- }
-
- return frame;
-}
-
-static void open_audio(AVFormatContext *oc, OutputStream *ost)
-{
- AVCodecContext *c;
- int nb_samples;
-
- c = ost->st->codec;
-
- /* open it */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- /* init signal generator */
- ost->t = 0;
- ost->tincr = 2 * M_PI * 110.0 / c->sample_rate;
- /* increment frequency by 110 Hz per second */
- ost->tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;
-
- if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
- nb_samples = 10000;
- else
- nb_samples = c->frame_size;
-
- ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout,
- c->sample_rate, nb_samples);
- ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, AV_CH_LAYOUT_STEREO,
- 44100, nb_samples);
-}
-
-/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and
- * 'nb_channels' channels. */
-static AVFrame *get_audio_frame(OutputStream *ost)
-{
- AVFrame *frame = ost->tmp_frame;
- int j, i, v;
- int16_t *q = (int16_t*)frame->data[0];
-
- /* check if we want to generate more frames */
- if (av_compare_ts(ost->next_pts, ost->st->codec->time_base,
- STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
- return NULL;
-
-
- for (j = 0; j < frame->nb_samples; j++) {
- v = (int)(sin(ost->t) * 10000);
- for (i = 0; i < ost->st->codec->channels; i++)
- *q++ = v;
- ost->t += ost->tincr;
- ost->tincr += ost->tincr2;
- }
-
- return frame;
-}
-
-/* if a frame is provided, send it to the encoder, otherwise flush the encoder;
- * return 1 when encoding is finished, 0 otherwise
- */
-static int encode_audio_frame(AVFormatContext *oc, OutputStream *ost,
- AVFrame *frame)
-{
- AVPacket pkt = { 0 }; // data and size must be 0;
- int got_packet;
-
- av_init_packet(&pkt);
- avcodec_encode_audio2(ost->st->codec, &pkt, frame, &got_packet);
-
- if (got_packet) {
- pkt.stream_index = ost->st->index;
-
- av_packet_rescale_ts(&pkt, ost->st->codec->time_base, ost->st->time_base);
-
- /* Write the compressed frame to the media file. */
- if (av_interleaved_write_frame(oc, &pkt) != 0) {
- fprintf(stderr, "Error while writing audio frame\n");
- exit(1);
- }
- }
-
- return (frame || got_packet) ? 0 : 1;
-}
-
-/*
- * encode one audio frame and send it to the muxer
- * return 1 when encoding is finished, 0 otherwise
- */
-static int process_audio_stream(AVFormatContext *oc, OutputStream *ost)
-{
- AVFrame *frame;
- int got_output = 0;
- int ret;
-
- frame = get_audio_frame(ost);
- got_output |= !!frame;
-
- /* feed the data to lavr */
- if (frame) {
- ret = avresample_convert(ost->avr, NULL, 0, 0,
- frame->extended_data, frame->linesize[0],
- frame->nb_samples);
- if (ret < 0) {
- fprintf(stderr, "Error feeding audio data to the resampler\n");
- exit(1);
- }
- }
-
- while ((frame && avresample_available(ost->avr) >= ost->frame->nb_samples) ||
- (!frame && avresample_get_out_samples(ost->avr, 0))) {
- /* when we pass a frame to the encoder, it may keep a reference to it
- * internally;
- * make sure we do not overwrite it here
- */
- ret = av_frame_make_writable(ost->frame);
- if (ret < 0)
- exit(1);
-
- /* the difference between the two avresample calls here is that the
- * first one just reads the already converted data that is buffered in
- * the lavr output buffer, while the second one also flushes the
- * resampler */
- if (frame) {
- ret = avresample_read(ost->avr, ost->frame->extended_data,
- ost->frame->nb_samples);
- } else {
- ret = avresample_convert(ost->avr, ost->frame->extended_data,
- ost->frame->linesize[0], ost->frame->nb_samples,
- NULL, 0, 0);
- }
-
- if (ret < 0) {
- fprintf(stderr, "Error while resampling\n");
- exit(1);
- } else if (frame && ret != ost->frame->nb_samples) {
- fprintf(stderr, "Too few samples returned from lavr\n");
- exit(1);
- }
-
- ost->frame->nb_samples = ret;
-
- ost->frame->pts = ost->next_pts;
- ost->next_pts += ost->frame->nb_samples;
-
- got_output |= encode_audio_frame(oc, ost, ret ? ost->frame : NULL);
- }
-
- return !got_output;
-}
-
-/**************************************************************/
-/* video output */
-
-/* Add a video output stream. */
-static void add_video_stream(OutputStream *ost, AVFormatContext *oc,
- enum AVCodecID codec_id)
-{
- AVCodecContext *c;
- AVCodec *codec;
-
- /* find the video encoder */
- codec = avcodec_find_encoder(codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
-
- ost->st = avformat_new_stream(oc, codec);
- if (!ost->st) {
- fprintf(stderr, "Could not alloc stream\n");
- exit(1);
- }
-
- c = ost->st->codec;
-
- /* Put sample parameters. */
- c->bit_rate = 400000;
- /* Resolution must be a multiple of two. */
- c->width = 352;
- c->height = 288;
- /* timebase: This is the fundamental unit of time (in seconds) in terms
- * of which frame timestamps are represented. For fixed-fps content,
- * timebase should be 1/framerate and timestamp increments should be
- * identical to 1. */
- ost->st->time_base = (AVRational){ 1, STREAM_FRAME_RATE };
- c->time_base = ost->st->time_base;
-
- c->gop_size = 12; /* emit one intra frame every twelve frames at most */
- c->pix_fmt = STREAM_PIX_FMT;
- if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
- /* just for testing, we also add B frames */
- c->max_b_frames = 2;
- }
- if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
- /* Needed to avoid using macroblocks in which some coeffs overflow.
- * This does not happen with normal video, it just happens here as
- * the motion of the chroma plane does not match the luma plane. */
- c->mb_decision = 2;
- }
- /* Some formats want stream headers to be separate. */
- if (oc->oformat->flags & AVFMT_GLOBALHEADER)
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-}
-
-static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
-{
- AVFrame *picture;
- int ret;
-
- picture = av_frame_alloc();
- if (!picture)
- return NULL;
-
- picture->format = pix_fmt;
- picture->width = width;
- picture->height = height;
-
- /* allocate the buffers for the frame data */
- ret = av_frame_get_buffer(picture, 32);
- if (ret < 0) {
- fprintf(stderr, "Could not allocate frame data.\n");
- exit(1);
- }
-
- return picture;
-}
-
-static void open_video(AVFormatContext *oc, OutputStream *ost)
-{
- AVCodecContext *c;
-
- c = ost->st->codec;
-
- /* open the codec */
- if (avcodec_open2(c, NULL, NULL) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
- }
-
- /* Allocate the encoded raw picture. */
- ost->frame = alloc_picture(c->pix_fmt, c->width, c->height);
- if (!ost->frame) {
- fprintf(stderr, "Could not allocate picture\n");
- exit(1);
- }
-
- /* If the output format is not YUV420P, then a temporary YUV420P
- * picture is needed too. It is then converted to the required
- * output format. */
- ost->tmp_frame = NULL;
- if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
- ost->tmp_frame = alloc_picture(AV_PIX_FMT_YUV420P, c->width, c->height);
- if (!ost->tmp_frame) {
- fprintf(stderr, "Could not allocate temporary picture\n");
- exit(1);
- }
- }
-}
-
-/* Prepare a dummy image. */
-static void fill_yuv_image(AVFrame *pict, int frame_index,
- int width, int height)
-{
- int x, y, i, ret;
-
- /* when we pass a frame to the encoder, it may keep a reference to it
- * internally;
- * make sure we do not overwrite it here
- */
- ret = av_frame_make_writable(pict);
- if (ret < 0)
- exit(1);
-
- i = frame_index;
-
- /* Y */
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
-
- /* Cb and Cr */
- for (y = 0; y < height / 2; y++) {
- for (x = 0; x < width / 2; x++) {
- pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
- pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
- }
- }
-}
-
-static AVFrame *get_video_frame(OutputStream *ost)
-{
- AVCodecContext *c = ost->st->codec;
-
- /* check if we want to generate more frames */
- if (av_compare_ts(ost->next_pts, ost->st->codec->time_base,
- STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
- return NULL;
-
- if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
- /* as we only generate a YUV420P picture, we must convert it
- * to the codec pixel format if needed */
- if (!ost->sws_ctx) {
- ost->sws_ctx = sws_getContext(c->width, c->height,
- AV_PIX_FMT_YUV420P,
- c->width, c->height,
- c->pix_fmt,
- SCALE_FLAGS, NULL, NULL, NULL);
- if (!ost->sws_ctx) {
- fprintf(stderr,
- "Cannot initialize the conversion context\n");
- exit(1);
- }
- }
- fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
- sws_scale(ost->sws_ctx, ost->tmp_frame->data, ost->tmp_frame->linesize,
- 0, c->height, ost->frame->data, ost->frame->linesize);
- } else {
- fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height);
- }
-
- ost->frame->pts = ost->next_pts++;
-
- return ost->frame;
-}
-
-/*
- * encode one video frame and send it to the muxer
- * return 1 when encoding is finished, 0 otherwise
- */
-static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
-{
- int ret;
- AVCodecContext *c;
- AVFrame *frame;
- int got_packet = 0;
-
- c = ost->st->codec;
-
- frame = get_video_frame(ost);
-
- if (oc->oformat->flags & AVFMT_RAWPICTURE) {
- /* a hack to avoid data copy with some raw video muxers */
- AVPacket pkt;
- av_init_packet(&pkt);
-
- if (!frame)
- return 1;
-
- pkt.flags |= AV_PKT_FLAG_KEY;
- pkt.stream_index = ost->st->index;
- pkt.data = (uint8_t *)frame;
- pkt.size = sizeof(AVPicture);
-
- pkt.pts = pkt.dts = frame->pts;
- av_packet_rescale_ts(&pkt, c->time_base, ost->st->time_base);
-
- ret = av_interleaved_write_frame(oc, &pkt);
- } else {
- AVPacket pkt = { 0 };
- av_init_packet(&pkt);
-
- /* encode the image */
- ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
- if (ret < 0) {
- fprintf(stderr, "Error encoding a video frame\n");
- exit(1);
- }
-
- if (got_packet) {
- av_packet_rescale_ts(&pkt, c->time_base, ost->st->time_base);
- pkt.stream_index = ost->st->index;
-
- /* Write the compressed frame to the media file. */
- ret = av_interleaved_write_frame(oc, &pkt);
- }
- }
- if (ret != 0) {
- fprintf(stderr, "Error while writing video frame\n");
- exit(1);
- }
-
- return (frame || got_packet) ? 0 : 1;
-}
-
-static void close_stream(AVFormatContext *oc, OutputStream *ost)
-{
- avcodec_close(ost->st->codec);
- av_frame_free(&ost->frame);
- av_frame_free(&ost->tmp_frame);
- sws_freeContext(ost->sws_ctx);
- avresample_free(&ost->avr);
-}
-
-/**************************************************************/
-/* media file output */
-
-int main(int argc, char **argv)
-{
- OutputStream video_st = { 0 }, audio_st = { 0 };
- const char *filename;
- AVOutputFormat *fmt;
- AVFormatContext *oc;
- int have_video = 0, have_audio = 0;
- int encode_video = 0, encode_audio = 0;
-
- /* Initialize libavcodec, and register all codecs and formats. */
- av_register_all();
-
- if (argc != 2) {
- printf("usage: %s output_file\n"
- "API example program to output a media file with libavformat.\n"
- "The output format is automatically guessed according to the file extension.\n"
- "Raw images can also be output by using '%%d' in the filename\n"
- "\n", argv[0]);
- return 1;
- }
-
- filename = argv[1];
-
- /* Autodetect the output format from the name. default is MPEG. */
- fmt = av_guess_format(NULL, filename, NULL);
- if (!fmt) {
- printf("Could not deduce output format from file extension: using MPEG.\n");
- fmt = av_guess_format("mpeg", NULL, NULL);
- }
- if (!fmt) {
- fprintf(stderr, "Could not find suitable output format\n");
- return 1;
- }
-
- /* Allocate the output media context. */
- oc = avformat_alloc_context();
- if (!oc) {
- fprintf(stderr, "Memory error\n");
- return 1;
- }
- oc->oformat = fmt;
- snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
-
- /* Add the audio and video streams using the default format codecs
- * and initialize the codecs. */
- if (fmt->video_codec != AV_CODEC_ID_NONE) {
- add_video_stream(&video_st, oc, fmt->video_codec);
- have_video = 1;
- encode_video = 1;
- }
- if (fmt->audio_codec != AV_CODEC_ID_NONE) {
- add_audio_stream(&audio_st, oc, fmt->audio_codec);
- have_audio = 1;
- encode_audio = 1;
- }
-
- /* Now that all the parameters are set, we can open the audio and
- * video codecs and allocate the necessary encode buffers. */
- if (have_video)
- open_video(oc, &video_st);
- if (have_audio)
- open_audio(oc, &audio_st);
-
- av_dump_format(oc, 0, filename, 1);
-
- /* open the output file, if needed */
- if (!(fmt->flags & AVFMT_NOFILE)) {
- if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {
- fprintf(stderr, "Could not open '%s'\n", filename);
- return 1;
- }
- }
-
- /* Write the stream header, if any. */
- avformat_write_header(oc, NULL);
-
- while (encode_video || encode_audio) {
- /* select the stream to encode */
- if (encode_video &&
- (!encode_audio || av_compare_ts(video_st.next_pts, video_st.st->codec->time_base,
- audio_st.next_pts, audio_st.st->codec->time_base) <= 0)) {
- encode_video = !write_video_frame(oc, &video_st);
- } else {
- encode_audio = !process_audio_stream(oc, &audio_st);
- }
- }
-
- /* Write the trailer, if any. The trailer must be written before you
- * close the CodecContexts open when you wrote the header; otherwise
- * av_write_trailer() may try to use memory that was freed on
- * av_codec_close(). */
- av_write_trailer(oc);
-
- /* Close each codec. */
- if (have_video)
- close_stream(oc, &video_st);
- if (have_audio)
- close_stream(oc, &audio_st);
-
- if (!(fmt->flags & AVFMT_NOFILE))
- /* Close the output file. */
- avio_close(oc->pb);
-
- /* free the stream */
- avformat_free_context(oc);
-
- return 0;
-}
diff --git a/doc/examples/remuxing.c b/doc/examples/remuxing.c
new file mode 100644
index 0000000000..e9758a8dcb
--- /dev/null
+++ b/doc/examples/remuxing.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libavformat/libavcodec demuxing and muxing API example.
+ *
+ * Remux streams from one container format to another.
+ * @example remuxing.c
+ */
+
+#include <libavutil/timestamp.h>
+#include <libavformat/avformat.h>
+
+static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
+{
+ AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
+
+ printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
+ tag,
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
+ av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
+ pkt->stream_index);
+}
+
+int main(int argc, char **argv)
+{
+ AVOutputFormat *ofmt = NULL;
+ AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
+ AVPacket pkt;
+ const char *in_filename, *out_filename;
+ int ret, i;
+
+ if (argc < 3) {
+ printf("usage: %s input output\n"
+ "API example program to remux a media file with libavformat and libavcodec.\n"
+ "The output format is guessed according to the file extension.\n"
+ "\n", argv[0]);
+ return 1;
+ }
+
+ in_filename = argv[1];
+ out_filename = argv[2];
+
+ av_register_all();
+
+ if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
+ fprintf(stderr, "Could not open input file '%s'", in_filename);
+ goto end;
+ }
+
+ if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
+ fprintf(stderr, "Failed to retrieve input stream information");
+ goto end;
+ }
+
+ av_dump_format(ifmt_ctx, 0, in_filename, 0);
+
+ avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
+ if (!ofmt_ctx) {
+ fprintf(stderr, "Could not create output context\n");
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ ofmt = ofmt_ctx->oformat;
+
+ for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+ AVStream *in_stream = ifmt_ctx->streams[i];
+ AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
+ if (!out_stream) {
+ fprintf(stderr, "Failed allocating output stream\n");
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
+ goto end;
+ }
+ out_stream->codec->codec_tag = 0;
+ if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+ out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ }
+ av_dump_format(ofmt_ctx, 0, out_filename, 1);
+
+ if (!(ofmt->flags & AVFMT_NOFILE)) {
+ ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open output file '%s'", out_filename);
+ goto end;
+ }
+ }
+
+ ret = avformat_write_header(ofmt_ctx, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Error occurred when opening output file\n");
+ goto end;
+ }
+
+ while (1) {
+ AVStream *in_stream, *out_stream;
+
+ ret = av_read_frame(ifmt_ctx, &pkt);
+ if (ret < 0)
+ break;
+
+ in_stream = ifmt_ctx->streams[pkt.stream_index];
+ out_stream = ofmt_ctx->streams[pkt.stream_index];
+
+ log_packet(ifmt_ctx, &pkt, "in");
+
+ /* copy packet */
+ pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
+ pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
+ pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
+ pkt.pos = -1;
+ log_packet(ofmt_ctx, &pkt, "out");
+
+ ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
+ if (ret < 0) {
+ fprintf(stderr, "Error muxing packet\n");
+ break;
+ }
+ av_free_packet(&pkt);
+ }
+
+ av_write_trailer(ofmt_ctx);
+end:
+
+ avformat_close_input(&ifmt_ctx);
+
+ /* close output */
+ if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
+ avio_closep(&ofmt_ctx->pb);
+ avformat_free_context(ofmt_ctx);
+
+ if (ret < 0 && ret != AVERROR_EOF) {
+ fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/doc/examples/resampling_audio.c b/doc/examples/resampling_audio.c
new file mode 100644
index 0000000000..f35e7e1779
--- /dev/null
+++ b/doc/examples/resampling_audio.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @example resampling_audio.c
+ * libswresample API use example.
+ */
+
+#include <libavutil/opt.h>
+#include <libavutil/channel_layout.h>
+#include <libavutil/samplefmt.h>
+#include <libswresample/swresample.h>
+
+static int get_format_from_sample_fmt(const char **fmt,
+ enum AVSampleFormat sample_fmt)
+{
+ int i;
+ struct sample_fmt_entry {
+ enum AVSampleFormat sample_fmt; const char *fmt_be, *fmt_le;
+ } sample_fmt_entries[] = {
+ { AV_SAMPLE_FMT_U8, "u8", "u8" },
+ { AV_SAMPLE_FMT_S16, "s16be", "s16le" },
+ { AV_SAMPLE_FMT_S32, "s32be", "s32le" },
+ { AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
+ { AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
+ };
+ *fmt = NULL;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
+ struct sample_fmt_entry *entry = &sample_fmt_entries[i];
+ if (sample_fmt == entry->sample_fmt) {
+ *fmt = AV_NE(entry->fmt_be, entry->fmt_le);
+ return 0;
+ }
+ }
+
+ fprintf(stderr,
+ "Sample format %s not supported as output format\n",
+ av_get_sample_fmt_name(sample_fmt));
+ return AVERROR(EINVAL);
+}
+
+/**
+ * Fill dst buffer with nb_samples, generated starting from t.
+ */
+static void fill_samples(double *dst, int nb_samples, int nb_channels, int sample_rate, double *t)
+{
+ int i, j;
+ double tincr = 1.0 / sample_rate, *dstp = dst;
+ const double c = 2 * M_PI * 440.0;
+
+ /* generate sin tone with 440Hz frequency and duplicated channels */
+ for (i = 0; i < nb_samples; i++) {
+ *dstp = sin(c * *t);
+ for (j = 1; j < nb_channels; j++)
+ dstp[j] = dstp[0];
+ dstp += nb_channels;
+ *t += tincr;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int64_t src_ch_layout = AV_CH_LAYOUT_STEREO, dst_ch_layout = AV_CH_LAYOUT_SURROUND;
+ int src_rate = 48000, dst_rate = 44100;
+ uint8_t **src_data = NULL, **dst_data = NULL;
+ int src_nb_channels = 0, dst_nb_channels = 0;
+ int src_linesize, dst_linesize;
+ int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples;
+ enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL, dst_sample_fmt = AV_SAMPLE_FMT_S16;
+ const char *dst_filename = NULL;
+ FILE *dst_file;
+ int dst_bufsize;
+ const char *fmt;
+ struct SwrContext *swr_ctx;
+ double t;
+ int ret;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s output_file\n"
+ "API example program to show how to resample an audio stream with libswresample.\n"
+ "This program generates a series of audio frames, resamples them to a specified "
+ "output format and rate and saves them to an output file named output_file.\n",
+ argv[0]);
+ exit(1);
+ }
+ dst_filename = argv[1];
+
+ dst_file = fopen(dst_filename, "wb");
+ if (!dst_file) {
+ fprintf(stderr, "Could not open destination file %s\n", dst_filename);
+ exit(1);
+ }
+
+ /* create resampler context */
+ swr_ctx = swr_alloc();
+ if (!swr_ctx) {
+ fprintf(stderr, "Could not allocate resampler context\n");
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* set options */
+ av_opt_set_int(swr_ctx, "in_channel_layout", src_ch_layout, 0);
+ av_opt_set_int(swr_ctx, "in_sample_rate", src_rate, 0);
+ av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", src_sample_fmt, 0);
+
+ av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0);
+ av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0);
+ av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0);
+
+ /* initialize the resampling context */
+ if ((ret = swr_init(swr_ctx)) < 0) {
+ fprintf(stderr, "Failed to initialize the resampling context\n");
+ goto end;
+ }
+
+ /* allocate source and destination samples buffers */
+
+ src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);
+ ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels,
+ src_nb_samples, src_sample_fmt, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate source samples\n");
+ goto end;
+ }
+
+ /* compute the number of converted samples: buffering is avoided
+ * ensuring that the output buffer will contain at least all the
+ * converted input samples */
+ max_dst_nb_samples = dst_nb_samples =
+ av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
+
+ /* buffer is going to be directly written to a rawaudio file, no alignment */
+ dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
+ ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
+ dst_nb_samples, dst_sample_fmt, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate destination samples\n");
+ goto end;
+ }
+
+ t = 0;
+ do {
+ /* generate synthetic audio */
+ fill_samples((double *)src_data[0], src_nb_samples, src_nb_channels, src_rate, &t);
+
+ /* compute destination number of samples */
+ dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) +
+ src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);
+ if (dst_nb_samples > max_dst_nb_samples) {
+ av_freep(&dst_data[0]);
+ ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
+ dst_nb_samples, dst_sample_fmt, 1);
+ if (ret < 0)
+ break;
+ max_dst_nb_samples = dst_nb_samples;
+ }
+
+ /* convert to destination format */
+ ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)src_data, src_nb_samples);
+ if (ret < 0) {
+ fprintf(stderr, "Error while converting\n");
+ goto end;
+ }
+ dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
+ ret, dst_sample_fmt, 1);
+ if (dst_bufsize < 0) {
+ fprintf(stderr, "Could not get sample buffer size\n");
+ goto end;
+ }
+ printf("t:%f in:%d out:%d\n", t, src_nb_samples, ret);
+ fwrite(dst_data[0], 1, dst_bufsize, dst_file);
+ } while (t < 10);
+
+ if ((ret = get_format_from_sample_fmt(&fmt, dst_sample_fmt)) < 0)
+ goto end;
+ fprintf(stderr, "Resampling succeeded. Play the output file with the command:\n"
+ "ffplay -f %s -channel_layout %"PRId64" -channels %d -ar %d %s\n",
+ fmt, dst_ch_layout, dst_nb_channels, dst_rate, dst_filename);
+
+end:
+ fclose(dst_file);
+
+ if (src_data)
+ av_freep(&src_data[0]);
+ av_freep(&src_data);
+
+ if (dst_data)
+ av_freep(&dst_data[0]);
+ av_freep(&dst_data);
+
+ swr_free(&swr_ctx);
+ return ret < 0;
+}
diff --git a/doc/examples/scaling_video.c b/doc/examples/scaling_video.c
new file mode 100644
index 0000000000..587f3abe4f
--- /dev/null
+++ b/doc/examples/scaling_video.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * libswscale API use example.
+ * @example scaling_video.c
+ */
+
+#include <libavutil/imgutils.h>
+#include <libavutil/parseutils.h>
+#include <libswscale/swscale.h>
+
+static void fill_yuv_image(uint8_t *data[4], int linesize[4],
+ int width, int height, int frame_index)
+{
+ int x, y;
+
+ /* Y */
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ data[0][y * linesize[0] + x] = x + y + frame_index * 3;
+
+ /* Cb and Cr */
+ for (y = 0; y < height / 2; y++) {
+ for (x = 0; x < width / 2; x++) {
+ data[1][y * linesize[1] + x] = 128 + y + frame_index * 2;
+ data[2][y * linesize[2] + x] = 64 + x + frame_index * 5;
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ uint8_t *src_data[4], *dst_data[4];
+ int src_linesize[4], dst_linesize[4];
+ int src_w = 320, src_h = 240, dst_w, dst_h;
+ enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P, dst_pix_fmt = AV_PIX_FMT_RGB24;
+ const char *dst_size = NULL;
+ const char *dst_filename = NULL;
+ FILE *dst_file;
+ int dst_bufsize;
+ struct SwsContext *sws_ctx;
+ int i, ret;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s output_file output_size\n"
+ "API example program to show how to scale an image with libswscale.\n"
+ "This program generates a series of pictures, rescales them to the given "
+ "output_size and saves them to an output file named output_file\n."
+ "\n", argv[0]);
+ exit(1);
+ }
+ dst_filename = argv[1];
+ dst_size = argv[2];
+
+ if (av_parse_video_size(&dst_w, &dst_h, dst_size) < 0) {
+ fprintf(stderr,
+ "Invalid size '%s', must be in the form WxH or a valid size abbreviation\n",
+ dst_size);
+ exit(1);
+ }
+
+ dst_file = fopen(dst_filename, "wb");
+ if (!dst_file) {
+ fprintf(stderr, "Could not open destination file %s\n", dst_filename);
+ exit(1);
+ }
+
+ /* create scaling context */
+ sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt,
+ dst_w, dst_h, dst_pix_fmt,
+ SWS_BILINEAR, NULL, NULL, NULL);
+ if (!sws_ctx) {
+ fprintf(stderr,
+ "Impossible to create scale context for the conversion "
+ "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
+ av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
+ av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ /* allocate source and destination image buffers */
+ if ((ret = av_image_alloc(src_data, src_linesize,
+ src_w, src_h, src_pix_fmt, 16)) < 0) {
+ fprintf(stderr, "Could not allocate source image\n");
+ goto end;
+ }
+
+ /* buffer is going to be written to rawvideo file, no alignment */
+ if ((ret = av_image_alloc(dst_data, dst_linesize,
+ dst_w, dst_h, dst_pix_fmt, 1)) < 0) {
+ fprintf(stderr, "Could not allocate destination image\n");
+ goto end;
+ }
+ dst_bufsize = ret;
+
+ for (i = 0; i < 100; i++) {
+ /* generate synthetic video */
+ fill_yuv_image(src_data, src_linesize, src_w, src_h, i);
+
+ /* convert to destination format */
+ sws_scale(sws_ctx, (const uint8_t * const*)src_data,
+ src_linesize, 0, src_h, dst_data, dst_linesize);
+
+ /* write scaled image to file */
+ fwrite(dst_data[0], 1, dst_bufsize, dst_file);
+ }
+
+ fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n"
+ "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n",
+ av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);
+
+end:
+ fclose(dst_file);
+ av_freep(&src_data[0]);
+ av_freep(&dst_data[0]);
+ sws_freeContext(sws_ctx);
+ return ret < 0;
+}
diff --git a/doc/examples/transcode_aac.c b/doc/examples/transcode_aac.c
index 60698f719f..339d65c71c 100644
--- a/doc/examples/transcode_aac.c
+++ b/doc/examples/transcode_aac.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,7 +21,7 @@
* simple audio converter
*
* @example transcode_aac.c
- * Convert an input audio file to AAC in an MP4 container using Libav.
+ * Convert an input audio file to AAC in an MP4 container using FFmpeg.
* @author Andreas Unterweger (dustsigns@gmail.com)
*/
@@ -33,11 +33,12 @@
#include "libavcodec/avcodec.h"
#include "libavutil/audio_fifo.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/frame.h"
#include "libavutil/opt.h"
-#include "libavresample/avresample.h"
+#include "libswresample/swresample.h"
/** The output bit rate in kbit/s */
#define OUTPUT_BIT_RATE 96000
@@ -49,7 +50,7 @@
* @param error Error code to be converted
* @return Corresponding error text (not thread-safe)
*/
-static char *const get_error_text(const int error)
+static const char *get_error_text(const int error)
{
static char error_buffer[255];
av_strerror(error, error_buffer, sizeof(error_buffer));
@@ -203,7 +204,7 @@ static int open_output_file(const char *filename,
return 0;
cleanup:
- avio_close((*output_format_context)->pb);
+ avio_closep(&(*output_format_context)->pb);
avformat_free_context(*output_format_context);
*output_format_context = NULL;
return error < 0 ? error : AVERROR_EXIT;
@@ -231,52 +232,46 @@ static int init_input_frame(AVFrame **frame)
/**
* Initialize the audio resampler based on the input and output codec settings.
* If the input and output sample formats differ, a conversion is required
- * libavresample takes care of this, but requires initialization.
+ * libswresample takes care of this, but requires initialization.
*/
static int init_resampler(AVCodecContext *input_codec_context,
AVCodecContext *output_codec_context,
- AVAudioResampleContext **resample_context)
+ SwrContext **resample_context)
{
- /**
- * Only initialize the resampler if it is necessary, i.e.,
- * if and only if the sample formats differ.
- */
- if (input_codec_context->sample_fmt != output_codec_context->sample_fmt ||
- input_codec_context->channels != output_codec_context->channels) {
int error;
- /** Create a resampler context for the conversion. */
- if (!(*resample_context = avresample_alloc_context())) {
- fprintf(stderr, "Could not allocate resample context\n");
- return AVERROR(ENOMEM);
- }
-
/**
+ * Create a resampler context for the conversion.
* Set the conversion parameters.
* Default channel layouts based on the number of channels
* are assumed for simplicity (they are sometimes not detected
* properly by the demuxer and/or decoder).
*/
- av_opt_set_int(*resample_context, "in_channel_layout",
- av_get_default_channel_layout(input_codec_context->channels), 0);
- av_opt_set_int(*resample_context, "out_channel_layout",
- av_get_default_channel_layout(output_codec_context->channels), 0);
- av_opt_set_int(*resample_context, "in_sample_rate",
- input_codec_context->sample_rate, 0);
- av_opt_set_int(*resample_context, "out_sample_rate",
- output_codec_context->sample_rate, 0);
- av_opt_set_int(*resample_context, "in_sample_fmt",
- input_codec_context->sample_fmt, 0);
- av_opt_set_int(*resample_context, "out_sample_fmt",
- output_codec_context->sample_fmt, 0);
+ *resample_context = swr_alloc_set_opts(NULL,
+ av_get_default_channel_layout(output_codec_context->channels),
+ output_codec_context->sample_fmt,
+ output_codec_context->sample_rate,
+ av_get_default_channel_layout(input_codec_context->channels),
+ input_codec_context->sample_fmt,
+ input_codec_context->sample_rate,
+ 0, NULL);
+ if (!*resample_context) {
+ fprintf(stderr, "Could not allocate resample context\n");
+ return AVERROR(ENOMEM);
+ }
+ /**
+ * Perform a sanity check so that the number of converted samples is
+ * not greater than the number of samples to be converted.
+ * If the sample rates differ, this case has to be handled differently
+ */
+ av_assert0(output_codec_context->sample_rate == input_codec_context->sample_rate);
/** Open the resampler with the specified parameters. */
- if ((error = avresample_open(*resample_context)) < 0) {
+ if ((error = swr_init(*resample_context)) < 0) {
fprintf(stderr, "Could not open resample context\n");
- avresample_free(resample_context);
+ swr_free(resample_context);
return error;
}
- }
return 0;
}
@@ -317,7 +312,7 @@ static int decode_audio_frame(AVFrame *frame,
/** Read one audio frame from the input file into a temporary packet. */
if ((error = av_read_frame(input_format_context, &input_packet)) < 0) {
- /** If we are the the end of the file, flush the decoder below. */
+ /** If we are at the end of the file, flush the decoder below. */
if (error == AVERROR_EOF)
*finished = 1;
else {
@@ -396,30 +391,21 @@ static int init_converted_samples(uint8_t ***converted_input_samples,
* The conversion happens on a per-frame basis, the size of which is specified
* by frame_size.
*/
-static int convert_samples(uint8_t **input_data,
+static int convert_samples(const uint8_t **input_data,
uint8_t **converted_data, const int frame_size,
- AVAudioResampleContext *resample_context)
+ SwrContext *resample_context)
{
int error;
/** Convert the samples using the resampler. */
- if ((error = avresample_convert(resample_context, converted_data, 0,
- frame_size, input_data, 0, frame_size)) < 0) {
+ if ((error = swr_convert(resample_context,
+ converted_data, frame_size,
+ input_data , frame_size)) < 0) {
fprintf(stderr, "Could not convert input samples (error '%s')\n",
get_error_text(error));
return error;
}
- /**
- * Perform a sanity check so that the number of converted samples is
- * not greater than the number of samples to be converted.
- * If the sample rates differ, this case has to be handled differently
- */
- if (avresample_available(resample_context)) {
- fprintf(stderr, "Converted samples left over\n");
- return AVERROR_EXIT;
- }
-
return 0;
}
@@ -456,7 +442,7 @@ static int read_decode_convert_and_store(AVAudioFifo *fifo,
AVFormatContext *input_format_context,
AVCodecContext *input_codec_context,
AVCodecContext *output_codec_context,
- AVAudioResampleContext *resampler_context,
+ SwrContext *resampler_context,
int *finished)
{
/** Temporary storage of the input samples of the frame read from the file. */
@@ -493,7 +479,7 @@ static int read_decode_convert_and_store(AVAudioFifo *fifo,
* Convert the input samples to the desired output sample format.
* This requires a temporary storage provided by converted_input_samples.
*/
- if (convert_samples(input_frame->extended_data, converted_input_samples,
+ if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples,
input_frame->nb_samples, resampler_context))
goto cleanup;
@@ -664,7 +650,7 @@ int main(int argc, char **argv)
{
AVFormatContext *input_format_context = NULL, *output_format_context = NULL;
AVCodecContext *input_codec_context = NULL, *output_codec_context = NULL;
- AVAudioResampleContext *resample_context = NULL;
+ SwrContext *resample_context = NULL;
AVAudioFifo *fifo = NULL;
int ret = AVERROR_EXIT;
@@ -768,14 +754,11 @@ int main(int argc, char **argv)
cleanup:
if (fifo)
av_audio_fifo_free(fifo);
- if (resample_context) {
- avresample_close(resample_context);
- avresample_free(&resample_context);
- }
+ swr_free(&resample_context);
if (output_codec_context)
avcodec_close(output_codec_context);
if (output_format_context) {
- avio_close(output_format_context->pb);
+ avio_closep(&output_format_context->pb);
avformat_free_context(output_format_context);
}
if (input_codec_context)
diff --git a/doc/examples/transcoding.c b/doc/examples/transcoding.c
new file mode 100644
index 0000000000..2a8220eefa
--- /dev/null
+++ b/doc/examples/transcoding.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2010 Nicolas George
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2014 Andrey Utkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * API example for demuxing, decoding, filtering, encoding and muxing
+ * @example transcoding.c
+ */
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavfilter/avfiltergraph.h>
+#include <libavfilter/avcodec.h>
+#include <libavfilter/buffersink.h>
+#include <libavfilter/buffersrc.h>
+#include <libavutil/opt.h>
+#include <libavutil/pixdesc.h>
+
+static AVFormatContext *ifmt_ctx;
+static AVFormatContext *ofmt_ctx;
+typedef struct FilteringContext {
+ AVFilterContext *buffersink_ctx;
+ AVFilterContext *buffersrc_ctx;
+ AVFilterGraph *filter_graph;
+} FilteringContext;
+static FilteringContext *filter_ctx;
+
+static int open_input_file(const char *filename)
+{
+ int ret;
+ unsigned int i;
+
+ ifmt_ctx = NULL;
+ if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
+ return ret;
+ }
+
+ if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
+ return ret;
+ }
+
+ for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+ AVStream *stream;
+ AVCodecContext *codec_ctx;
+ stream = ifmt_ctx->streams[i];
+ codec_ctx = stream->codec;
+ /* Reencode video & audio and remux subtitles etc. */
+ if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
+ || codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ /* Open decoder */
+ ret = avcodec_open2(codec_ctx,
+ avcodec_find_decoder(codec_ctx->codec_id), NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i);
+ return ret;
+ }
+ }
+ }
+
+ av_dump_format(ifmt_ctx, 0, filename, 0);
+ return 0;
+}
+
+static int open_output_file(const char *filename)
+{
+ AVStream *out_stream;
+ AVStream *in_stream;
+ AVCodecContext *dec_ctx, *enc_ctx;
+ AVCodec *encoder;
+ int ret;
+ unsigned int i;
+
+ ofmt_ctx = NULL;
+ avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
+ if (!ofmt_ctx) {
+ av_log(NULL, AV_LOG_ERROR, "Could not create output context\n");
+ return AVERROR_UNKNOWN;
+ }
+
+
+ for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+ out_stream = avformat_new_stream(ofmt_ctx, NULL);
+ if (!out_stream) {
+ av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ in_stream = ifmt_ctx->streams[i];
+ dec_ctx = in_stream->codec;
+ enc_ctx = out_stream->codec;
+
+ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO
+ || dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ /* in this example, we choose transcoding to same codec */
+ encoder = avcodec_find_encoder(dec_ctx->codec_id);
+ if (!encoder) {
+ av_log(NULL, AV_LOG_FATAL, "Neccessary encoder not found\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* In this example, we transcode to same properties (picture size,
+ * sample rate etc.). These properties can be changed for output
+ * streams easily using filters */
+ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ enc_ctx->height = dec_ctx->height;
+ enc_ctx->width = dec_ctx->width;
+ enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio;
+ /* take first format from list of supported formats */
+ enc_ctx->pix_fmt = encoder->pix_fmts[0];
+ /* video time_base can be set to whatever is handy and supported by encoder */
+ enc_ctx->time_base = dec_ctx->time_base;
+ } else {
+ enc_ctx->sample_rate = dec_ctx->sample_rate;
+ enc_ctx->channel_layout = dec_ctx->channel_layout;
+ enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout);
+ /* take first format from list of supported formats */
+ enc_ctx->sample_fmt = encoder->sample_fmts[0];
+ enc_ctx->time_base = (AVRational){1, enc_ctx->sample_rate};
+ }
+
+ /* Third parameter can be used to pass settings to encoder */
+ ret = avcodec_open2(enc_ctx, encoder, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i);
+ return ret;
+ }
+ } else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) {
+ av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i);
+ return AVERROR_INVALIDDATA;
+ } else {
+ /* if this stream must be remuxed */
+ ret = avcodec_copy_context(ofmt_ctx->streams[i]->codec,
+ ifmt_ctx->streams[i]->codec);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Copying stream context failed\n");
+ return ret;
+ }
+ }
+
+ if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
+ enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ }
+ av_dump_format(ofmt_ctx, 0, filename, 1);
+
+ if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
+ ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename);
+ return ret;
+ }
+ }
+
+ /* init muxer, write output file header */
+ ret = avformat_write_header(ofmt_ctx, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx,
+ AVCodecContext *enc_ctx, const char *filter_spec)
+{
+ char args[512];
+ int ret = 0;
+ AVFilter *buffersrc = NULL;
+ AVFilter *buffersink = NULL;
+ AVFilterContext *buffersrc_ctx = NULL;
+ AVFilterContext *buffersink_ctx = NULL;
+ AVFilterInOut *outputs = avfilter_inout_alloc();
+ AVFilterInOut *inputs = avfilter_inout_alloc();
+ AVFilterGraph *filter_graph = avfilter_graph_alloc();
+
+ if (!outputs || !inputs || !filter_graph) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ buffersrc = avfilter_get_by_name("buffer");
+ buffersink = avfilter_get_by_name("buffersink");
+ if (!buffersrc || !buffersink) {
+ av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ snprintf(args, sizeof(args),
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+ dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
+ dec_ctx->time_base.num, dec_ctx->time_base.den,
+ dec_ctx->sample_aspect_ratio.num,
+ dec_ctx->sample_aspect_ratio.den);
+
+ ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
+ args, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
+ goto end;
+ }
+
+ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
+ NULL, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
+ goto end;
+ }
+
+ ret = av_opt_set_bin(buffersink_ctx, "pix_fmts",
+ (uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt),
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
+ goto end;
+ }
+ } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ buffersrc = avfilter_get_by_name("abuffer");
+ buffersink = avfilter_get_by_name("abuffersink");
+ if (!buffersrc || !buffersink) {
+ av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n");
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ if (!dec_ctx->channel_layout)
+ dec_ctx->channel_layout =
+ av_get_default_channel_layout(dec_ctx->channels);
+ snprintf(args, sizeof(args),
+ "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,
+ dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate,
+ av_get_sample_fmt_name(dec_ctx->sample_fmt),
+ dec_ctx->channel_layout);
+ ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
+ args, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n");
+ goto end;
+ }
+
+ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
+ NULL, NULL, filter_graph);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n");
+ goto end;
+ }
+
+ ret = av_opt_set_bin(buffersink_ctx, "sample_fmts",
+ (uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt),
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n");
+ goto end;
+ }
+
+ ret = av_opt_set_bin(buffersink_ctx, "channel_layouts",
+ (uint8_t*)&enc_ctx->channel_layout,
+ sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n");
+ goto end;
+ }
+
+ ret = av_opt_set_bin(buffersink_ctx, "sample_rates",
+ (uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate),
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n");
+ goto end;
+ }
+ } else {
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ /* Endpoints for the filter graph. */
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = buffersrc_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = buffersink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if (!outputs->name || !inputs->name) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec,
+ &inputs, &outputs, NULL)) < 0)
+ goto end;
+
+ if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0)
+ goto end;
+
+ /* Fill FilteringContext */
+ fctx->buffersrc_ctx = buffersrc_ctx;
+ fctx->buffersink_ctx = buffersink_ctx;
+ fctx->filter_graph = filter_graph;
+
+end:
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+
+ return ret;
+}
+
+static int init_filters(void)
+{
+ const char *filter_spec;
+ unsigned int i;
+ int ret;
+ filter_ctx = av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx));
+ if (!filter_ctx)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+ filter_ctx[i].buffersrc_ctx = NULL;
+ filter_ctx[i].buffersink_ctx = NULL;
+ filter_ctx[i].filter_graph = NULL;
+ if (!(ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO
+ || ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))
+ continue;
+
+
+ if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ filter_spec = "null"; /* passthrough (dummy) filter for video */
+ else
+ filter_spec = "anull"; /* passthrough (dummy) filter for audio */
+ ret = init_filter(&filter_ctx[i], ifmt_ctx->streams[i]->codec,
+ ofmt_ctx->streams[i]->codec, filter_spec);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) {
+ int ret;
+ int got_frame_local;
+ AVPacket enc_pkt;
+ int (*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) =
+ (ifmt_ctx->streams[stream_index]->codec->codec_type ==
+ AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;
+
+ if (!got_frame)
+ got_frame = &got_frame_local;
+
+ av_log(NULL, AV_LOG_INFO, "Encoding frame\n");
+ /* encode filtered frame */
+ enc_pkt.data = NULL;
+ enc_pkt.size = 0;
+ av_init_packet(&enc_pkt);
+ ret = enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt,
+ filt_frame, got_frame);
+ av_frame_free(&filt_frame);
+ if (ret < 0)
+ return ret;
+ if (!(*got_frame))
+ return 0;
+
+ /* prepare packet for muxing */
+ enc_pkt.stream_index = stream_index;
+ av_packet_rescale_ts(&enc_pkt,
+ ofmt_ctx->streams[stream_index]->codec->time_base,
+ ofmt_ctx->streams[stream_index]->time_base);
+
+ av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n");
+ /* mux encoded frame */
+ ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
+ return ret;
+}
+
+static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index)
+{
+ int ret;
+ AVFrame *filt_frame;
+
+ av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filters\n");
+ /* push the decoded frame into the filtergraph */
+ ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx,
+ frame, 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n");
+ return ret;
+ }
+
+ /* pull filtered frames from the filtergraph */
+ while (1) {
+ filt_frame = av_frame_alloc();
+ if (!filt_frame) {
+ ret = AVERROR(ENOMEM);
+ break;
+ }
+ av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filters\n");
+ ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx,
+ filt_frame);
+ if (ret < 0) {
+ /* if no more frames for output - returns AVERROR(EAGAIN)
+ * if flushed and no more frames for output - returns AVERROR_EOF
+ * rewrite retcode to 0 to show it as normal procedure completion
+ */
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ ret = 0;
+ av_frame_free(&filt_frame);
+ break;
+ }
+
+ filt_frame->pict_type = AV_PICTURE_TYPE_NONE;
+ ret = encode_write_frame(filt_frame, stream_index, NULL);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int flush_encoder(unsigned int stream_index)
+{
+ int ret;
+ int got_frame;
+
+ if (!(ofmt_ctx->streams[stream_index]->codec->codec->capabilities &
+ CODEC_CAP_DELAY))
+ return 0;
+
+ while (1) {
+ av_log(NULL, AV_LOG_INFO, "Flushing stream #%u encoder\n", stream_index);
+ ret = encode_write_frame(NULL, stream_index, &got_frame);
+ if (ret < 0)
+ break;
+ if (!got_frame)
+ return 0;
+ }
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ AVPacket packet = { .data = NULL, .size = 0 };
+ AVFrame *frame = NULL;
+ enum AVMediaType type;
+ unsigned int stream_index;
+ unsigned int i;
+ int got_frame;
+ int (*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *);
+
+ if (argc != 3) {
+ av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
+ return 1;
+ }
+
+ av_register_all();
+ avfilter_register_all();
+
+ if ((ret = open_input_file(argv[1])) < 0)
+ goto end;
+ if ((ret = open_output_file(argv[2])) < 0)
+ goto end;
+ if ((ret = init_filters()) < 0)
+ goto end;
+
+ /* read all packets */
+ while (1) {
+ if ((ret = av_read_frame(ifmt_ctx, &packet)) < 0)
+ break;
+ stream_index = packet.stream_index;
+ type = ifmt_ctx->streams[packet.stream_index]->codec->codec_type;
+ av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n",
+ stream_index);
+
+ if (filter_ctx[stream_index].filter_graph) {
+ av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame\n");
+ frame = av_frame_alloc();
+ if (!frame) {
+ ret = AVERROR(ENOMEM);
+ break;
+ }
+ av_packet_rescale_ts(&packet,
+ ifmt_ctx->streams[stream_index]->time_base,
+ ifmt_ctx->streams[stream_index]->codec->time_base);
+ dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 :
+ avcodec_decode_audio4;
+ ret = dec_func(ifmt_ctx->streams[stream_index]->codec, frame,
+ &got_frame, &packet);
+ if (ret < 0) {
+ av_frame_free(&frame);
+ av_log(NULL, AV_LOG_ERROR, "Decoding failed\n");
+ break;
+ }
+
+ if (got_frame) {
+ frame->pts = av_frame_get_best_effort_timestamp(frame);
+ ret = filter_encode_write_frame(frame, stream_index);
+ av_frame_free(&frame);
+ if (ret < 0)
+ goto end;
+ } else {
+ av_frame_free(&frame);
+ }
+ } else {
+ /* remux this frame without reencoding */
+ av_packet_rescale_ts(&packet,
+ ifmt_ctx->streams[stream_index]->time_base,
+ ofmt_ctx->streams[stream_index]->time_base);
+
+ ret = av_interleaved_write_frame(ofmt_ctx, &packet);
+ if (ret < 0)
+ goto end;
+ }
+ av_free_packet(&packet);
+ }
+
+ /* flush filters and encoders */
+ for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+ /* flush filter */
+ if (!filter_ctx[i].filter_graph)
+ continue;
+ ret = filter_encode_write_frame(NULL, i);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Flushing filter failed\n");
+ goto end;
+ }
+
+ /* flush encoder */
+ ret = flush_encoder(i);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Flushing encoder failed\n");
+ goto end;
+ }
+ }
+
+ av_write_trailer(ofmt_ctx);
+end:
+ av_free_packet(&packet);
+ av_frame_free(&frame);
+ for (i = 0; i < ifmt_ctx->nb_streams; i++) {
+ avcodec_close(ifmt_ctx->streams[i]->codec);
+ if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && ofmt_ctx->streams[i]->codec)
+ avcodec_close(ofmt_ctx->streams[i]->codec);
+ if (filter_ctx && filter_ctx[i].filter_graph)
+ avfilter_graph_free(&filter_ctx[i].filter_graph);
+ }
+ av_free(filter_ctx);
+ avformat_close_input(&ifmt_ctx);
+ if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
+ avio_closep(&ofmt_ctx->pb);
+ avformat_free_context(ofmt_ctx);
+
+ if (ret < 0)
+ av_log(NULL, AV_LOG_ERROR, "Error occurred: %s\n", av_err2str(ret));
+
+ return ret ? 1 : 0;
+}
diff --git a/doc/faq.texi b/doc/faq.texi
index b400124f69..5fe716b8a1 100644
--- a/doc/faq.texi
+++ b/doc/faq.texi
@@ -1,8 +1,9 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
-@settitle Libav FAQ
+@settitle FFmpeg FAQ
@titlepage
-@center @titlefont{Libav FAQ}
+@center @titlefont{FFmpeg FAQ}
@end titlepage
@top
@@ -11,23 +12,23 @@
@chapter General Questions
-@section Why doesn't Libav support feature [xyz]?
+@section Why doesn't FFmpeg support feature [xyz]?
-Because no one has taken on that task yet. Libav development is
+Because no one has taken on that task yet. FFmpeg development is
driven by the tasks that are important to the individual developers.
If there is a feature that is important to you, the best way to get
it implemented is to undertake the task yourself or sponsor a developer.
-@section Libav does not support codec XXX. Can you include a Windows DLL loader to support it?
+@section FFmpeg does not support codec XXX. Can you include a Windows DLL loader to support it?
No. Windows DLLs are not portable, bloated and often slow.
-Moreover Libav strives to support all codecs natively.
+Moreover FFmpeg strives to support all codecs natively.
A DLL loader is not conducive to that goal.
-@section I cannot read this file although this format seems to be supported by avconv.
+@section I cannot read this file although this format seems to be supported by ffmpeg.
-Even if avconv can read the container format, it may not support all its
-codecs. Please consult the supported codec list in the avconv
+Even if ffmpeg can read the container format, it may not support all its
+codecs. Please consult the supported codec list in the ffmpeg
documentation.
@section Which codecs are supported by Windows?
@@ -79,8 +80,75 @@ not a bug they should fix:
Then again, some of them do not know the difference between an undecidable
problem and an NP-hard problem...
+@section I have installed this library with my distro's package manager. Why does @command{configure} not see it?
+
+Distributions usually split libraries in several packages. The main package
+contains the files necessary to run programs using the library. The
+development package contains the files necessary to build programs using the
+library. Sometimes, docs and/or data are in a separate package too.
+
+To build FFmpeg, you need to install the development package. It is usually
+called @file{libfoo-dev} or @file{libfoo-devel}. You can remove it after the
+build is finished, but be sure to keep the main package.
+
+@section How do I make @command{pkg-config} find my libraries?
+
+Somewhere along with your libraries, there is a @file{.pc} file (or several)
+in a @file{pkgconfig} directory. You need to set environment variables to
+point @command{pkg-config} to these files.
+
+If you need to @emph{add} directories to @command{pkg-config}'s search list
+(typical use case: library installed separately), add it to
+@code{$PKG_CONFIG_PATH}:
+
+@example
+export PKG_CONFIG_PATH=/opt/x264/lib/pkgconfig:/opt/opus/lib/pkgconfig
+@end example
+
+If you need to @emph{replace} @command{pkg-config}'s search list
+(typical use case: cross-compiling), set it in
+@code{$PKG_CONFIG_LIBDIR}:
+
+@example
+export PKG_CONFIG_LIBDIR=/home/me/cross/usr/lib/pkgconfig:/home/me/cross/usr/local/lib/pkgconfig
+@end example
+
+If you need to know the library's internal dependencies (typical use: static
+linking), add the @code{--static} option to @command{pkg-config}:
+
+@example
+./configure --pkg-config-flags=--static
+@end example
+
+@section How do I use @command{pkg-config} when cross-compiling?
+
+The best way is to install @command{pkg-config} in your cross-compilation
+environment. It will automatically use the cross-compilation libraries.
+
+You can also use @command{pkg-config} from the host environment by
+specifying explicitly @code{--pkg-config=pkg-config} to @command{configure}.
+In that case, you must point @command{pkg-config} to the correct directories
+using the @code{PKG_CONFIG_LIBDIR}, as explained in the previous entry.
+
+As an intermediate solution, you can place in your cross-compilation
+environment a script that calls the host @command{pkg-config} with
+@code{PKG_CONFIG_LIBDIR} set. That script can look like that:
+
+@example
+#!/bin/sh
+PKG_CONFIG_LIBDIR=/path/to/cross/lib/pkgconfig
+export PKG_CONFIG_LIBDIR
+exec /usr/bin/pkg-config "$@@"
+@end example
+
@chapter Usage
+@section ffmpeg does not work; what is wrong?
+
+Try a @code{make distclean} in the ffmpeg source directory before the build.
+If this does not help see
+(@url{http://ffmpeg.org/bugreports.html}).
+
@section How do I encode single pictures into movies?
First, rename your pictures to follow a numerical sequence.
@@ -88,12 +156,21 @@ For example, img1.jpg, img2.jpg, img3.jpg,...
Then you may run:
@example
- avconv -f image2 -i img%d.jpg /tmp/a.mpg
+ffmpeg -f image2 -i img%d.jpg /tmp/a.mpg
@end example
Notice that @samp{%d} is replaced by the image number.
-@file{img%03d.jpg} means the sequence @file{img001.jpg}, @file{img002.jpg}, etc...
+@file{img%03d.jpg} means the sequence @file{img001.jpg}, @file{img002.jpg}, etc.
+
+Use the @option{-start_number} option to declare a starting number for
+the sequence. This is useful if your sequence does not start with
+@file{img001.jpg} but is still in a numerical order. The following
+example will start with @file{img100.jpg}:
+
+@example
+ffmpeg -f image2 -start_number 100 -i img%d.jpg /tmp/a.mpg
+@end example
If you have large number of pictures to rename, you can use the
following command to ease the burden. The command, using the bourne
@@ -102,7 +179,7 @@ that match @code{*jpg} to the @file{/tmp} directory in the sequence of
@file{img001.jpg}, @file{img002.jpg} and so on.
@example
- x=1; for i in *jpg; do counter=$(printf %03d $x); ln -s "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done
+x=1; for i in *jpg; do counter=$(printf %03d $x); ln -s "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done
@end example
If you want to sequence them by oldest modified first, substitute
@@ -111,17 +188,23 @@ If you want to sequence them by oldest modified first, substitute
Then run:
@example
- avconv -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg
+ffmpeg -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg
@end example
-The same logic is used for any image format that avconv reads.
+The same logic is used for any image format that ffmpeg reads.
+
+You can also use @command{cat} to pipe images to ffmpeg:
+
+@example
+cat *.jpg | ffmpeg -f image2pipe -c:v mjpeg -i - output.mpg
+@end example
@section How do I encode movie to single pictures?
Use:
@example
- avconv -i movie.mpg movie%d.jpg
+ffmpeg -i movie.mpg movie%d.jpg
@end example
The @file{movie.mpg} used as input will be converted to
@@ -137,7 +220,7 @@ to force the encoding.
Applying that to the previous example:
@example
- avconv -i movie.mpg -f image2 -c:v mjpeg menu%d.jpg
+ffmpeg -i movie.mpg -f image2 -c:v mjpeg menu%d.jpg
@end example
Beware that there is no "jpeg" codec. Use "mjpeg" instead.
@@ -156,12 +239,12 @@ Use @file{-} as file name.
Try '-f image2 test%d.jpg'.
-@section Why can I not change the framerate?
+@section Why can I not change the frame rate?
-Some codecs, like MPEG-1/2, only allow a small number of fixed framerates.
+Some codecs, like MPEG-1/2, only allow a small number of fixed frame rates.
Choose a different codec with the -c:v command line option.
-@section How do I encode Xvid or DivX video with avconv?
+@section How do I encode Xvid or DivX video with ffmpeg?
Both Xvid and DivX (version 4+) are implementations of the ISO MPEG-4
standard (note that there are many other coding formats that use this
@@ -182,24 +265,24 @@ things to try: '-bf 2', '-flags qprd', '-flags mv0', '-flags skiprd'.
but beware the '-g 100' might cause problems with some decoders.
Things to try: '-bf 2', '-flags qprd', '-flags mv0', '-flags skiprd.
-@section Interlaced video looks very bad when encoded with avconv, what is wrong?
+@section Interlaced video looks very bad when encoded with ffmpeg, what is wrong?
You should use '-flags +ilme+ildct' and maybe '-flags +alt' for interlaced
material, and try '-top 0/1' if the result looks really messed-up.
@section How can I read DirectShow files?
-If you have built Libav with @code{./configure --enable-avisynth}
+If you have built FFmpeg with @code{./configure --enable-avisynth}
(only possible on MinGW/Cygwin platforms),
then you may use any file that DirectShow can read as input.
Just create an "input.avs" text file with this single line ...
@example
- DirectShowSource("C:\path to your file\yourfile.asf")
+DirectShowSource("C:\path to your file\yourfile.asf")
@end example
-... and then feed that text file to avconv:
+... and then feed that text file to ffmpeg:
@example
- avconv -i input.avs
+ffmpeg -i input.avs
@end example
For ANY other help on AviSynth, please visit the
@@ -207,8 +290,67 @@ For ANY other help on AviSynth, please visit the
@section How can I join video files?
-A few multimedia containers (MPEG-1, MPEG-2 PS, DV) allow to join video files by
-merely concatenating them.
+To "join" video files is quite ambiguous. The following list explains the
+different kinds of "joining" and points out how those are addressed in
+FFmpeg. To join video files may mean:
+
+@itemize
+
+@item
+To put them one after the other: this is called to @emph{concatenate} them
+(in short: concat) and is addressed
+@ref{How can I concatenate video files, in this very faq}.
+
+@item
+To put them together in the same file, to let the user choose between the
+different versions (example: different audio languages): this is called to
+@emph{multiplex} them together (in short: mux), and is done by simply
+invoking ffmpeg with several @option{-i} options.
+
+@item
+For audio, to put all channels together in a single stream (example: two
+mono streams into one stereo stream): this is sometimes called to
+@emph{merge} them, and can be done using the
+@url{http://ffmpeg.org/ffmpeg-filters.html#amerge, @code{amerge}} filter.
+
+@item
+For audio, to play one on top of the other: this is called to @emph{mix}
+them, and can be done by first merging them into a single stream and then
+using the @url{http://ffmpeg.org/ffmpeg-filters.html#pan, @code{pan}} filter to mix
+the channels at will.
+
+@item
+For video, to display both together, side by side or one on top of a part of
+the other; it can be done using the
+@url{http://ffmpeg.org/ffmpeg-filters.html#overlay, @code{overlay}} video filter.
+
+@end itemize
+
+@anchor{How can I concatenate video files}
+@section How can I concatenate video files?
+
+There are several solutions, depending on the exact circumstances.
+
+@subsection Concatenating using the concat @emph{filter}
+
+FFmpeg has a @url{http://ffmpeg.org/ffmpeg-filters.html#concat,
+@code{concat}} filter designed specifically for that, with examples in the
+documentation. This operation is recommended if you need to re-encode.
+
+@subsection Concatenating using the concat @emph{demuxer}
+
+FFmpeg has a @url{http://www.ffmpeg.org/ffmpeg-formats.html#concat,
+@code{concat}} demuxer which you can use when you want to avoid a re-encode and
+your format doesn't support file level concatenation.
+
+@subsection Concatenating using the concat @emph{protocol} (file level)
+
+FFmpeg has a @url{http://ffmpeg.org/ffmpeg-protocols.html#concat,
+@code{concat}} protocol designed specifically for that, with examples in the
+documentation.
+
+A few multimedia containers (MPEG-1, MPEG-2 PS, DV) allow one to concatenate
+video by merely concatenating the files containing them.
Hence you may concatenate your multimedia files by first transcoding them to
these privileged formats, then using the humble @code{cat} command (or the
@@ -216,27 +358,38 @@ equally humble @code{copy} under Windows), and finally transcoding back to your
format of choice.
@example
-avconv -i input1.avi intermediate1.mpg
-avconv -i input2.avi intermediate2.mpg
+ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
+ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
cat intermediate1.mpg intermediate2.mpg > intermediate_all.mpg
-avconv -i intermediate_all.mpg output.avi
+ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
@end example
-Notice that you should set a reasonably high bitrate for your intermediate and
-output files, if you want to preserve video quality.
+Additionally, you can use the @code{concat} protocol instead of @code{cat} or
+@code{copy} which will avoid creation of a potentially huge intermediate file.
-Also notice that you may avoid the huge intermediate files by taking advantage
-of named pipes, should your platform support it:
+@example
+ffmpeg -i input1.avi -qscale:v 1 intermediate1.mpg
+ffmpeg -i input2.avi -qscale:v 1 intermediate2.mpg
+ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg" -c copy intermediate_all.mpg
+ffmpeg -i intermediate_all.mpg -qscale:v 2 output.avi
+@end example
+
+Note that you may need to escape the character "|" which is special for many
+shells.
+
+Another option is usage of named pipes, should your platform support it:
@example
mkfifo intermediate1.mpg
mkfifo intermediate2.mpg
-avconv -i input1.avi -y intermediate1.mpg < /dev/null &
-avconv -i input2.avi -y intermediate2.mpg < /dev/null &
+ffmpeg -i input1.avi -qscale:v 1 -y intermediate1.mpg < /dev/null &
+ffmpeg -i input2.avi -qscale:v 1 -y intermediate2.mpg < /dev/null &
cat intermediate1.mpg intermediate2.mpg |\
-avconv -f mpeg -i - -c:v mpeg4 -acodec libmp3lame output.avi
+ffmpeg -f mpeg -i - -c:v mpeg4 -acodec libmp3lame output.avi
@end example
+@subsection Concatenating using raw audio and video
+
Similarly, the yuv4mpegpipe format, and the raw video, raw audio codecs also
allow concatenation, and the transcoding step is almost lossless.
When using multiple yuv4mpegpipe(s), the first line needs to be discarded
@@ -244,7 +397,8 @@ from all but the first stream. This can be accomplished by piping through
@code{tail} as seen below. Note that when piping through @code{tail} you
must use command grouping, @code{@{ ;@}}, to background properly.
-For example, let's say we want to join two FLV files into an output.flv file:
+For example, let's say we want to concatenate two FLV files into an
+output.flv file:
@example
mkfifo temp1.a
@@ -253,45 +407,114 @@ mkfifo temp2.a
mkfifo temp2.v
mkfifo all.a
mkfifo all.v
-avconv -i input1.flv -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 - > temp1.a < /dev/null &
-avconv -i input2.flv -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 - > temp2.a < /dev/null &
-avconv -i input1.flv -an -f yuv4mpegpipe - > temp1.v < /dev/null &
-@{ avconv -i input2.flv -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v ; @} &
+ffmpeg -i input1.flv -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 - > temp1.a < /dev/null &
+ffmpeg -i input2.flv -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 - > temp2.a < /dev/null &
+ffmpeg -i input1.flv -an -f yuv4mpegpipe - > temp1.v < /dev/null &
+@{ ffmpeg -i input2.flv -an -f yuv4mpegpipe - < /dev/null | tail -n +2 > temp2.v ; @} &
cat temp1.a temp2.a > all.a &
cat temp1.v temp2.v > all.v &
-avconv -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i all.a \
+ffmpeg -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i all.a \
-f yuv4mpegpipe -i all.v \
-y output.flv
rm temp[12].[av] all.[av]
@end example
-@section -profile option fails when encoding H.264 video with AAC audio
+@section Using @option{-f lavfi}, audio becomes mono for no apparent reason.
+
+Use @option{-dumpgraph -} to find out exactly where the channel layout is
+lost.
-@command{avconv} prints an error like
+Most likely, it is through @code{auto-inserted aresample}. Try to understand
+why the converting filter was needed at that place.
+
+Just before the output is a likely place, as @option{-f lavfi} currently
+only support packed S16.
+
+Then insert the correct @code{aformat} explicitly in the filtergraph,
+specifying the exact format.
@example
-Undefined constant or missing '(' in 'baseline'
-Unable to parse option value "baseline"
-Error setting option profile to value baseline.
+aformat=sample_fmts=s16:channel_layouts=stereo
@end example
-Short answer: write @option{-profile:v} instead of @option{-profile}.
+@section Why does FFmpeg not see the subtitles in my VOB file?
+
+VOB and a few other formats do not have a global header that describes
+everything present in the file. Instead, applications are supposed to scan
+the file to see what it contains. Since VOB files are frequently large, only
+the beginning is scanned. If the subtitles happen only later in the file,
+they will not be initially detected.
+
+Some applications, including the @code{ffmpeg} command-line tool, can only
+work with streams that were detected during the initial scan; streams that
+are detected later are ignored.
+
+The size of the initial scan is controlled by two options: @code{probesize}
+(default ~5 Mo) and @code{analyzeduration} (default 5,000,000 µs = 5 s). For
+the subtitle stream to be detected, both values must be large enough.
+
+@section Why was the @command{ffmpeg} @option{-sameq} option removed? What to use instead?
+
+The @option{-sameq} option meant "same quantizer", and made sense only in a
+very limited set of cases. Unfortunately, a lot of people mistook it for
+"same quality" and used it in places where it did not make sense: it had
+roughly the expected visible effect, but achieved it in a very inefficient
+way.
+
+Each encoder has its own set of options to set the quality-vs-size balance,
+use the options for the encoder you are using to set the quality level to a
+point acceptable for your tastes. The most common options to do that are
+@option{-qscale} and @option{-qmax}, but you should peruse the documentation
+of the encoder you chose.
+
+@section I have a stretched video, why does scaling does not fix it?
+
+A lot of video codecs and formats can store the @emph{aspect ratio} of the
+video: this is the ratio between the width and the height of either the full
+image (DAR, display aspect ratio) or individual pixels (SAR, sample aspect
+ratio). For example, EGA screens at resolution 640Ă—350 had 4:3 DAR and 35:48
+SAR.
+
+Most still image processing work with square pixels, i.e. 1:1 SAR, but a lot
+of video standards, especially from the analogic-numeric transition era, use
+non-square pixels.
-Long answer: this happens because the @option{-profile} option can apply to both
-video and audio. Specifically the AAC encoder also defines some profiles, none
-of which are named @var{baseline}.
+Most processing filters in FFmpeg handle the aspect ratio to avoid
+stretching the image: cropping adjusts the DAR to keep the SAR constant,
+scaling adjusts the SAR to keep the DAR constant.
-The solution is to apply the @option{-profile} option to the video stream only
-by using @url{http://libav.org/avconv.html#Stream-specifiers-1, Stream specifiers}.
-Appending @code{:v} to it will do exactly that.
+If you want to stretch, or “unstretchâ€, the image, you need to override the
+information with the
+@url{http://ffmpeg.org/ffmpeg-filters.html#setdar_002c-setsar, @code{setdar or setsar filters}}.
+
+Do not forget to examine carefully the original video to check whether the
+stretching comes from the image or from the aspect ratio information.
+
+For example, to fix a badly encoded EGA capture, use the following commands,
+either the first one to upscale to square pixels or the second one to set
+the correct aspect ratio or the third one to avoid transcoding (may not work
+depending on the format / codec / player / phase of the moon):
+
+@example
+ffmpeg -i ega_screen.nut -vf scale=640:480,setsar=1 ega_screen_scaled.nut
+ffmpeg -i ega_screen.nut -vf setdar=4/3 ega_screen_anamorphic.nut
+ffmpeg -i ega_screen.nut -aspect 4/3 -c copy ega_screen_overridden.nut
+@end example
@chapter Development
-@section Are there examples illustrating how to use the Libav libraries, particularly libavcodec and libavformat?
+@section Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat?
+
+Yes. Check the @file{doc/examples} directory in the source
+repository, also available online at:
+@url{https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples}.
-Yes. Read the Developers Guide of the Libav documentation. Alternatively,
+Examples are also installed by default, usually in
+@code{$PREFIX/share/ffmpeg/examples}.
+
+Also you may read the Developers Guide of the FFmpeg documentation. Alternatively,
examine the source code for one of the many open source projects that
-already incorporate Libav at (@url{projects.html}).
+already incorporate FFmpeg at (@url{projects.html}).
@section Can you support my C compiler XXX?
@@ -302,42 +525,86 @@ with @code{#ifdef}s related to the compiler.
@section Is Microsoft Visual C++ supported?
Yes. Please see the @uref{platform.html, Microsoft Visual C++}
-section in the Libav documentation.
+section in the FFmpeg documentation.
@section Can you add automake, libtool or autoconf support?
No. These tools are too bloated and they complicate the build.
-@section Why not rewrite Libav in object-oriented C++?
+@section Why not rewrite FFmpeg in object-oriented C++?
-Libav is already organized in a highly modular manner and does not need to
+FFmpeg is already organized in a highly modular manner and does not need to
be rewritten in a formal object language. Further, many of the developers
favor straight C; it works for them. For more arguments on this matter,
read @uref{http://www.tux.org/lkml/#s15, "Programming Religion"}.
+@section Why are the ffmpeg programs devoid of debugging symbols?
+
+The build process creates @command{ffmpeg_g}, @command{ffplay_g}, etc. which
+contain full debug information. Those binaries are stripped to create
+@command{ffmpeg}, @command{ffplay}, etc. If you need the debug information, use
+the *_g versions.
+
@section I do not like the LGPL, can I contribute code under the GPL instead?
Yes, as long as the code is optional and can easily and cleanly be placed
-under #if CONFIG_GPL without breaking anything. So for example a new codec
+under #if CONFIG_GPL without breaking anything. So, for example, a new codec
or filter would be OK under GPL while a bug fix to LGPL code would not.
-@section I'm using Libav from within my C++ application but the linker complains about missing symbols which seem to be available.
+@section I'm using FFmpeg from within my C application but the linker complains about missing symbols from the libraries themselves.
+
+FFmpeg builds static libraries by default. In static libraries, dependencies
+are not handled. That has two consequences. First, you must specify the
+libraries in dependency order: @code{-lavdevice} must come before
+@code{-lavformat}, @code{-lavutil} must come after everything else, etc.
+Second, external libraries that are used in FFmpeg have to be specified too.
+
+An easy way to get the full list of required libraries in dependency order
+is to use @code{pkg-config}.
-Libav is a pure C project, so to use the libraries within your C++ application
+@example
+c99 -o program program.c $(pkg-config --cflags --libs libavformat libavcodec)
+@end example
+
+See @file{doc/example/Makefile} and @file{doc/example/pc-uninstalled} for
+more details.
+
+@section I'm using FFmpeg from within my C++ application but the linker complains about missing symbols which seem to be available.
+
+FFmpeg is a pure C project, so to use the libraries within your C++ application
you need to explicitly state that you are using a C library. You can do this by
-encompassing your Libav includes using @code{extern "C"}.
+encompassing your FFmpeg includes using @code{extern "C"}.
See @url{http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.3}
@section I'm using libavutil from within my C++ application but the compiler complains about 'UINT64_C' was not declared in this scope
-Libav is a pure C project using C99 math features, in order to enable C++
+FFmpeg is a pure C project using C99 math features, in order to enable C++
to use them you have to append -D__STDC_CONSTANT_MACROS to your CXXFLAGS
@section I have a file in memory / a API different from *open/*read/ libc how do I use it with libavformat?
You have to create a custom AVIOContext using @code{avio_alloc_context},
-see @file{libavformat/aviobuf.c} in Libav and @file{libmpdemux/demux_lavf.c} in MPlayer2 sources.
+see @file{libavformat/aviobuf.c} in FFmpeg and @file{libmpdemux/demux_lavf.c} in MPlayer or MPlayer2 sources.
+
+@section Where is the documentation about ffv1, msmpeg4, asv1, 4xm?
+
+see @url{http://www.ffmpeg.org/~michael/}
+
+@section How do I feed H.263-RTP (and other codecs in RTP) to libavcodec?
+
+Even if peculiar since it is network oriented, RTP is a container like any
+other. You have to @emph{demux} RTP before feeding the payload to libavcodec.
+In this specific case please look at RFC 4629 to see how it should be done.
+
+@section AVStream.r_frame_rate is wrong, it is much larger than the frame rate.
+
+@code{r_frame_rate} is NOT the average frame rate, it is the smallest frame rate
+that can accurately represent all timestamps. So no, it is not
+wrong if it is larger than the average!
+For example, if you have mixed 25 and 30 fps content, then @code{r_frame_rate}
+will be 150 (it is the least common multiple).
+If you are looking for the average frame rate, see @code{AVStream.avg_frame_rate}.
@section Why is @code{make fate} not running all tests?
diff --git a/doc/fate.texi b/doc/fate.texi
index d6beaa5c24..353443a17b 100644
--- a/doc/fate.texi
+++ b/doc/fate.texi
@@ -1,84 +1,179 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
-@settitle FATE Automated Testing Environment
+@settitle FFmpeg Automated Testing Environment
@titlepage
-@center @titlefont{FATE Automated Testing Environment}
+@center @titlefont{FFmpeg Automated Testing Environment}
@end titlepage
+@node Top
@top
@contents
@chapter Introduction
-FATE provides a regression testsuite embedded within the Libav build system.
-It can be run locally and optionally configured to send reports to a web
-aggregator and viewer @url{http://fate.libav.org}.
+FATE is an extended regression suite on the client-side and a means
+for results aggregation and presentation on the server-side.
-It is advised to run FATE before submitting patches to the current codebase
-and provide new tests when submitting patches to add additional features.
+The first part of this document explains how you can use FATE from
+your FFmpeg source directory to test your ffmpeg binary. The second
+part describes how you can run FATE to submit the results to FFmpeg's
+FATE server.
-@chapter Running FATE
+In any way you can have a look at the publicly viewable FATE results
+by visiting this website:
-@section Samples and References
-In order to run, FATE needs a large amount of data (samples and references)
-that is provided separately from the actual source distribution.
+@url{http://fate.ffmpeg.org/}
-To inform the build system about the testsuite location, pass
-@option{--samples=<path to the samples>} to @command{configure} or set the
-@var{SAMPLES} Make variable or the @var{LIBAV_SAMPLES} environment variable
-to a suitable value.
+This is especially recommended for all people contributing source
+code to FFmpeg, as it can be seen if some test on some platform broke
+with their recent contribution. This usually happens on the platforms
+the developers could not test on.
-To use a custom wrapper to run the test, pass @option{--target-exec} to
-@command{configure} or set the @var{TARGET_EXEC} Make variable.
+The second part of this document describes how you can run FATE to
+submit your results to FFmpeg's FATE server. If you want to submit your
+results be sure to check that your combination of CPU, OS and compiler
+is not already listed on the above mentioned website.
+
+In the third part you can find a comprehensive listing of FATE makefile
+targets and variables.
-The dataset is available through @command{rsync}, is possible to fetch
-the current sample using the straight rsync command or through a specific
-@ref{Makefile target}.
+
+@chapter Using FATE from your FFmpeg source directory
+
+If you want to run FATE on your machine you need to have the samples
+in place. You can get the samples via the build target fate-rsync.
+Use this command from the top-level source directory:
@example
-# rsync -aL rsync://fate-suite.libav.org/fate-suite/ fate-suite
+make fate-rsync SAMPLES=fate-suite/
+make fate SAMPLES=fate-suite/
@end example
+The above commands set the samples location by passing a makefile
+variable via command line. It is also possible to set the samples
+location at source configuration time by invoking configure with
+@option{--samples=<path to the samples directory>}. Afterwards you can
+invoke the makefile targets without setting the @var{SAMPLES} makefile
+variable. This is illustrated by the following commands:
+
@example
-# make fate-rsync SAMPLES=fate-suite
+./configure --samples=fate-suite/
+make fate-rsync
+make fate
@end example
+Yet another way to tell FATE about the location of the sample
+directory is by making sure the environment variable FATE_SAMPLES
+contains the path to your samples directory. This can be achieved
+by e.g. putting that variable in your shell profile or by setting
+it in your interactive session.
-@chapter Manual Run
-FATE regression test can be run through @command{make}.
-Specific Makefile targets and Makefile variables are available:
+@example
+FATE_SAMPLES=fate-suite/ make fate
+@end example
-@anchor{Makefile target}
-@section FATE Makefile targets
+@float NOTE
+Do not put a '~' character in the samples path to indicate a home
+directory. Because of shell nuances, this will cause FATE to fail.
+@end float
-@table @option
-@item fate-list
-List all fate/regression test targets.
+To use a custom wrapper to run the test, pass @option{--target-exec} to
+@command{configure} or set the @var{TARGET_EXEC} Make variable.
-@item fate-rsync
-Shortcut to download the fate test samples to the specified testsuite location.
-@item fate
-Run the FATE test suite (requires the fate-suite dataset).
+@chapter Submitting the results to the FFmpeg result aggregation server
+
+To submit your results to the server you should run fate through the
+shell script @file{tests/fate.sh} from the FFmpeg sources. This script needs
+to be invoked with a configuration file as its first argument.
+
+@example
+tests/fate.sh /path/to/fate_config
+@end example
+
+A configuration file template with comments describing the individual
+configuration variables can be found at @file{doc/fate_config.sh.template}.
+
+@ifhtml
+The mentioned configuration template is also available here:
+@verbatiminclude fate_config.sh.template
+@end ifhtml
+
+Create a configuration that suits your needs, based on the configuration
+template. The @env{slot} configuration variable can be any string that is not
+yet used, but it is suggested that you name it adhering to the following
+pattern @samp{@var{arch}-@var{os}-@var{compiler}-@var{compiler version}}. The
+configuration file itself will be sourced in a shell script, therefore all
+shell features may be used. This enables you to setup the environment as you
+need it for your build.
+
+For your first test runs the @env{fate_recv} variable should be empty or
+commented out. This will run everything as normal except that it will omit
+the submission of the results to the server. The following files should be
+present in $workdir as specified in the configuration file:
+
+@itemize
+ @item configure.log
+ @item compile.log
+ @item test.log
+ @item report
+ @item version
+@end itemize
+
+When you have everything working properly you can create an SSH key pair
+and send the public key to the FATE server administrator who can be contacted
+at the email address @email{fate-admin@@ffmpeg.org}.
+
+Configure your SSH client to use public key authentication with that key
+when connecting to the FATE server. Also do not forget to check the identity
+of the server and to accept its host key. This can usually be achieved by
+running your SSH client manually and killing it after you accepted the key.
+The FATE server's fingerprint is:
+
+@table @samp
+@item RSA
+ d3:f1:83:97:a4:75:2b:a6:fb:d6:e8:aa:81:93:97:51
+@item ECDSA
+ 76:9f:68:32:04:1e:d5:d4:ec:47:3f:dc:fc:18:17:86
@end table
-@section FATE Makefile variables
-@table @option
-@item V
-Verbosity level, can be set to 0, 1 or 2.
+If you have problems connecting to the FATE server, it may help to try out
+the @command{ssh} command with one or more @option{-v} options. You should
+get detailed output concerning your SSH configuration and the authentication
+process.
+
+The only thing left is to automate the execution of the fate.sh script and
+the synchronisation of the samples directory.
+
+
+@chapter FATE makefile targets and variables
+
+@section Makefile targets
@table @option
-@item 0
-show just the test arguments
+@item fate-rsync
+Download/synchronize sample files to the configured samples directory.
-@item 1
-show just the command used in the test
+@item fate-list
+Will list all fate/regression test targets.
-@item 2
-show everything
+@item fate
+Run the FATE test suite (requires the fate-suite dataset).
@end table
+@section Makefile variables
+
+@table @env
+@item V
+Verbosity level, can be set to 0, 1 or 2.
+ @itemize
+ @item 0: show just the test arguments
+ @item 1: show just the command used in the test
+ @item 2: show everything
+ @end itemize
+
@item SAMPLES
Specify or override the path to the FATE samples at make time, it has a
meaning only while running the regression tests.
@@ -88,81 +183,24 @@ Specify how many threads to use while running regression tests, it is
quite useful to detect thread-related regressions.
@item THREAD_TYPE
-Specify which threading strategy test, either @var{slice} or @var{frame},
-by default @var{slice+frame}
+Specify which threading strategy test, either @samp{slice} or @samp{frame},
+by default @samp{slice+frame}
@item CPUFLAGS
-Specify a mask to be applied to autodetected CPU flags.
+Specify CPU flags.
@item TARGET_EXEC
Specify or override the wrapper used to run the tests.
+The @env{TARGET_EXEC} option provides a way to run FATE wrapped in
+@command{valgrind}, @command{qemu-user} or @command{wine} or on remote targets
+through @command{ssh}.
@item GEN
-Set to @var{1} to generate the missing or mismatched references.
+Set to @samp{1} to generate the missing or mismatched references.
@end table
-@example
- make V=1 SAMPLES=/var/fate/samples THREADS=2 CPUFLAGS=mmx fate
-@end example
-
-@chapter Automated Tests
-In order to automatically testing specific configurations, e.g. multiple
-compilers, @command{tests/fate.sh} is provided.
-
-This shell script builds Libav, runs the regression tests and prepares
-a report that can be sent to @url{http://fate.libav.org/} or directly
-examined locally.
-
-@section Testing Profiles
-The configuration file passed to @command{fate.sh} is shell scripts as well.
-
-It must provide at least a @var{slot} identifier, the @var{repo} from
-which fetch the sources, the @var{samples} directory, a @var{workdir} with
-enough space to build and run all the tests.
-Optional submit command @var{fate_recv} and a @var{comment} to describe
-the testing profile are available.
-
-Additional optional parameter to tune the Libav building and reporting process
-can be passed.
+@section Examples
@example
-slot= # some unique identifier
-repo=git://git.libav.org/libav.git # the source repository
-#branch=release/10 # the branch to test
-samples=/path/to/fate/samples
-workdir= # directory in which to do all the work
-fate_recv="ssh -T fate@@fate.libav.org" # command to submit report
-comment= # optional description
-build_only= # set to "yes" for a compile-only instance that skips tests
-
-# the following are optional and map to configure options
-arch=
-cpu=
-cross_prefix=
-as=
-cc=
-ld=
-target_os=
-sysroot=
-target_exec=
-target_path=
-target_samples=
-extra_cflags=
-extra_ldflags=
-extra_libs=
-extra_conf= # extra configure options not covered above
-
-#make= # name of GNU make if not 'make'
-makeopts= # extra options passed to 'make'
-#tar= # command to create a tar archive from its arguments on
- # stdout, defaults to 'tar c'
+make V=1 SAMPLES=/var/fate/samples THREADS=2 CPUFLAGS=mmx fate
@end example
-
-@section Special Instances
-The @var{TARGET_EXEC} option provides a way to run FATE wrapped in
-@command{valgrind}, @command{qemu-user} or @command{wine} or on remote targets
-through @command{ssh}.
-
-@section Submitting Reports
-In order to send reports you need to create an @command{ssh} key and send it
-to @email{root@@libav.org}.
diff --git a/doc/fate_config.sh.template b/doc/fate_config.sh.template
new file mode 100644
index 0000000000..059a1f862f
--- /dev/null
+++ b/doc/fate_config.sh.template
@@ -0,0 +1,30 @@
+slot= # some unique identifier
+repo=git://source.ffmpeg.org/ffmpeg.git # the source repository
+#branch=release/2.6 # the branch to test
+samples= # path to samples directory
+workdir= # directory in which to do all the work
+#fate_recv="ssh -T fate@fate.ffmpeg.org" # command to submit report
+comment= # optional description
+build_only= # set to "yes" for a compile-only instance that skips tests
+
+# the following are optional and map to configure options
+arch=
+cpu=
+cross_prefix=
+as=
+cc=
+ld=
+target_os=
+sysroot=
+target_exec=
+target_path=
+target_samples=
+extra_cflags=
+extra_ldflags=
+extra_libs=
+extra_conf= # extra configure options not covered above
+
+#make= # name of GNU make if not 'make'
+makeopts= # extra options passed to 'make'
+#tar= # command to create a tar archive from its arguments on stdout,
+ # defaults to 'tar c'
diff --git a/doc/ffmpeg-bitstream-filters.texi b/doc/ffmpeg-bitstream-filters.texi
new file mode 100644
index 0000000000..bbde25708f
--- /dev/null
+++ b/doc/ffmpeg-bitstream-filters.texi
@@ -0,0 +1,46 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Bitstream Filters Documentation
+@titlepage
+@center @titlefont{FFmpeg Bitstream Filters Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the bitstream filters provided by the
+libavcodec library.
+
+A bitstream filter operates on the encoded stream data, and performs
+bitstream level modifications without performing decoding.
+
+@c man end DESCRIPTION
+
+@include bitstream_filters.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavcodec.html,libavcodec}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-bitstream-filters
+@settitle FFmpeg bitstream filters
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-codecs.texi b/doc/ffmpeg-codecs.texi
new file mode 100644
index 0000000000..7df4391ae7
--- /dev/null
+++ b/doc/ffmpeg-codecs.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Codecs Documentation
+@titlepage
+@center @titlefont{FFmpeg Codecs Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the codecs (decoders and encoders) provided by
+the libavcodec library.
+
+@c man end DESCRIPTION
+
+@include codecs.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavcodec.html,libavcodec}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-codecs
+@settitle FFmpeg codecs
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-devices.texi b/doc/ffmpeg-devices.texi
new file mode 100644
index 0000000000..721c0df800
--- /dev/null
+++ b/doc/ffmpeg-devices.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Devices Documentation
+@titlepage
+@center @titlefont{FFmpeg Devices Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the input and output devices provided by the
+libavdevice library.
+
+@c man end DESCRIPTION
+
+@include devices.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavdevice.html,libavdevice}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavdevice(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-devices
+@settitle FFmpeg devices
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-filters.texi b/doc/ffmpeg-filters.texi
new file mode 100644
index 0000000000..b643f2c027
--- /dev/null
+++ b/doc/ffmpeg-filters.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Filters Documentation
+@titlepage
+@center @titlefont{FFmpeg Filters Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes filters, sources, and sinks provided by the
+libavfilter library.
+
+@c man end DESCRIPTION
+
+@include filters.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavfilter.html,libavfilter}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavfilter(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-filters
+@settitle FFmpeg filters
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-formats.texi b/doc/ffmpeg-formats.texi
new file mode 100644
index 0000000000..d916ee84b7
--- /dev/null
+++ b/doc/ffmpeg-formats.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Formats Documentation
+@titlepage
+@center @titlefont{FFmpeg Formats Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the supported formats (muxers and demuxers)
+provided by the libavformat library.
+
+@c man end DESCRIPTION
+
+@include formats.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavformat.html,libavformat}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-formats
+@settitle FFmpeg formats
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-protocols.texi b/doc/ffmpeg-protocols.texi
new file mode 100644
index 0000000000..f3a09f6a69
--- /dev/null
+++ b/doc/ffmpeg-protocols.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Protocols Documentation
+@titlepage
+@center @titlefont{FFmpeg Protocols Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes the input and output protocols provided by the
+libavformat library.
+
+@c man end DESCRIPTION
+
+@include protocols.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavformat.html,libavformat}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-protocols
+@settitle FFmpeg protocols
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-resampler.texi b/doc/ffmpeg-resampler.texi
new file mode 100644
index 0000000000..be3784f3ed
--- /dev/null
+++ b/doc/ffmpeg-resampler.texi
@@ -0,0 +1,45 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Resampler Documentation
+@titlepage
+@center @titlefont{FFmpeg Resampler Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The FFmpeg resampler provides a high-level interface to the
+libswresample library audio resampling utilities. In particular it
+allows one to perform audio resampling, audio channel layout rematrixing,
+and convert audio format and packing layout.
+
+@c man end DESCRIPTION
+
+@include resampler.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libswresample.html,libswresample}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libswresample(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-resampler
+@settitle FFmpeg Resampler
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-scaler.texi b/doc/ffmpeg-scaler.texi
new file mode 100644
index 0000000000..9ab12a1f95
--- /dev/null
+++ b/doc/ffmpeg-scaler.texi
@@ -0,0 +1,44 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Scaler Documentation
+@titlepage
+@center @titlefont{FFmpeg Scaler Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The FFmpeg rescaler provides a high-level interface to the libswscale
+library image conversion utilities. In particular it allows one to perform
+image rescaling and pixel format conversion.
+
+@c man end DESCRIPTION
+
+@include scaler.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libswscale.html,libswscale}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libswscale(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-scaler
+@settitle FFmpeg video scaling and pixel format converter
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg-utils.texi b/doc/ffmpeg-utils.texi
new file mode 100644
index 0000000000..e39cfa85ec
--- /dev/null
+++ b/doc/ffmpeg-utils.texi
@@ -0,0 +1,43 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle FFmpeg Utilities Documentation
+@titlepage
+@center @titlefont{FFmpeg Utilities Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+This document describes some generic features and utilities provided
+by the libavutil library.
+
+@c man end DESCRIPTION
+
+@include utils.texi
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg-utils
+@settitle FFmpeg utilities
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
new file mode 100644
index 0000000000..16cee4708f
--- /dev/null
+++ b/doc/ffmpeg.texi
@@ -0,0 +1,1604 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle ffmpeg Documentation
+@titlepage
+@center @titlefont{ffmpeg Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Synopsis
+
+ffmpeg [@var{global_options}] @{[@var{input_file_options}] -i @file{input_file}@} ... @{[@var{output_file_options}] @file{output_file}@} ...
+
+@chapter Description
+@c man begin DESCRIPTION
+
+@command{ffmpeg} is a very fast video and audio converter that can also grab from
+a live audio/video source. It can also convert between arbitrary sample
+rates and resize video on the fly with a high quality polyphase filter.
+
+@command{ffmpeg} reads from an arbitrary number of input "files" (which can be regular
+files, pipes, network streams, grabbing devices, etc.), specified by the
+@code{-i} option, and writes to an arbitrary number of output "files", which are
+specified by a plain output filename. Anything found on the command line which
+cannot be interpreted as an option is considered to be an output filename.
+
+Each input or output file can, in principle, contain any number of streams of
+different types (video/audio/subtitle/attachment/data). The allowed number and/or
+types of streams may be limited by the container format. Selecting which
+streams from which inputs will go into which output is either done automatically
+or with the @code{-map} option (see the Stream selection chapter).
+
+To refer to input files in options, you must use their indices (0-based). E.g.
+the first input file is @code{0}, the second is @code{1}, etc. Similarly, streams
+within a file are referred to by their indices. E.g. @code{2:3} refers to the
+fourth stream in the third input file. Also see the Stream specifiers chapter.
+
+As a general rule, options are applied to the next specified
+file. Therefore, order is important, and you can have the same
+option on the command line multiple times. Each occurrence is
+then applied to the next input or output file.
+Exceptions from this rule are the global options (e.g. verbosity level),
+which should be specified first.
+
+Do not mix input and output files -- first specify all input files, then all
+output files. Also do not mix options which belong to different files. All
+options apply ONLY to the next input or output file and are reset between files.
+
+@itemize
+@item
+To set the video bitrate of the output file to 64 kbit/s:
+@example
+ffmpeg -i input.avi -b:v 64k -bufsize 64k output.avi
+@end example
+
+@item
+To force the frame rate of the output file to 24 fps:
+@example
+ffmpeg -i input.avi -r 24 output.avi
+@end example
+
+@item
+To force the frame rate of the input file (valid for raw formats only)
+to 1 fps and the frame rate of the output file to 24 fps:
+@example
+ffmpeg -r 1 -i input.m2v -r 24 output.avi
+@end example
+@end itemize
+
+The format option may be needed for raw input files.
+
+@c man end DESCRIPTION
+
+@chapter Detailed description
+@c man begin DETAILED DESCRIPTION
+
+The transcoding process in @command{ffmpeg} for each output can be described by
+the following diagram:
+
+@verbatim
+ _______ ______________
+| | | |
+| input | demuxer | encoded data | decoder
+| file | ---------> | packets | -----+
+|_______| |______________| |
+ v
+ _________
+ | |
+ | decoded |
+ | frames |
+ |_________|
+ ________ ______________ |
+| | | | |
+| output | <-------- | encoded data | <----+
+| file | muxer | packets | encoder
+|________| |______________|
+
+
+@end verbatim
+
+@command{ffmpeg} calls the libavformat library (containing demuxers) to read
+input files and get packets containing encoded data from them. When there are
+multiple input files, @command{ffmpeg} tries to keep them synchronized by
+tracking lowest timestamp on any active input stream.
+
+Encoded packets are then passed to the decoder (unless streamcopy is selected
+for the stream, see further for a description). The decoder produces
+uncompressed frames (raw video/PCM audio/...) which can be processed further by
+filtering (see next section). After filtering, the frames are passed to the
+encoder, which encodes them and outputs encoded packets. Finally those are
+passed to the muxer, which writes the encoded packets to the output file.
+
+@section Filtering
+Before encoding, @command{ffmpeg} can process raw audio and video frames using
+filters from the libavfilter library. Several chained filters form a filter
+graph. @command{ffmpeg} distinguishes between two types of filtergraphs:
+simple and complex.
+
+@subsection Simple filtergraphs
+Simple filtergraphs are those that have exactly one input and output, both of
+the same type. In the above diagram they can be represented by simply inserting
+an additional step between decoding and encoding:
+
+@verbatim
+ _________ ______________
+| | | |
+| decoded | | encoded data |
+| frames |\ _ | packets |
+|_________| \ /||______________|
+ \ __________ /
+ simple _\|| | / encoder
+ filtergraph | filtered |/
+ | frames |
+ |__________|
+
+@end verbatim
+
+Simple filtergraphs are configured with the per-stream @option{-filter} option
+(with @option{-vf} and @option{-af} aliases for video and audio respectively).
+A simple filtergraph for video can look for example like this:
+
+@verbatim
+ _______ _____________ _______ ________
+| | | | | | | |
+| input | ---> | deinterlace | ---> | scale | ---> | output |
+|_______| |_____________| |_______| |________|
+
+@end verbatim
+
+Note that some filters change frame properties but not frame contents. E.g. the
+@code{fps} filter in the example above changes number of frames, but does not
+touch the frame contents. Another example is the @code{setpts} filter, which
+only sets timestamps and otherwise passes the frames unchanged.
+
+@subsection Complex filtergraphs
+Complex filtergraphs are those which cannot be described as simply a linear
+processing chain applied to one stream. This is the case, for example, when the graph has
+more than one input and/or output, or when output stream type is different from
+input. They can be represented with the following diagram:
+
+@verbatim
+ _________
+| |
+| input 0 |\ __________
+|_________| \ | |
+ \ _________ /| output 0 |
+ \ | | / |__________|
+ _________ \| complex | /
+| | | |/
+| input 1 |---->| filter |\
+|_________| | | \ __________
+ /| graph | \ | |
+ / | | \| output 1 |
+ _________ / |_________| |__________|
+| | /
+| input 2 |/
+|_________|
+
+@end verbatim
+
+Complex filtergraphs are configured with the @option{-filter_complex} option.
+Note that this option is global, since a complex filtergraph, by its nature,
+cannot be unambiguously associated with a single stream or file.
+
+The @option{-lavfi} option is equivalent to @option{-filter_complex}.
+
+A trivial example of a complex filtergraph is the @code{overlay} filter, which
+has two video inputs and one video output, containing one video overlaid on top
+of the other. Its audio counterpart is the @code{amix} filter.
+
+@section Stream copy
+Stream copy is a mode selected by supplying the @code{copy} parameter to the
+@option{-codec} option. It makes @command{ffmpeg} omit the decoding and encoding
+step for the specified stream, so it does only demuxing and muxing. It is useful
+for changing the container format or modifying container-level metadata. The
+diagram above will, in this case, simplify to this:
+
+@verbatim
+ _______ ______________ ________
+| | | | | |
+| input | demuxer | encoded data | muxer | output |
+| file | ---------> | packets | -------> | file |
+|_______| |______________| |________|
+
+@end verbatim
+
+Since there is no decoding or encoding, it is very fast and there is no quality
+loss. However, it might not work in some cases because of many factors. Applying
+filters is obviously also impossible, since filters work on uncompressed data.
+
+@c man end DETAILED DESCRIPTION
+
+@chapter Stream selection
+@c man begin STREAM SELECTION
+
+By default, @command{ffmpeg} includes only one stream of each type (video, audio, subtitle)
+present in the input files and adds them to each output file. It picks the
+"best" of each based upon the following criteria: for video, it is the stream
+with the highest resolution, for audio, it is the stream with the most channels, for
+subtitles, it is the first subtitle stream. In the case where several streams of
+the same type rate equally, the stream with the lowest index is chosen.
+
+You can disable some of those defaults by using the @code{-vn/-an/-sn} options. For
+full manual control, use the @code{-map} option, which disables the defaults just
+described.
+
+@c man end STREAM SELECTION
+
+@chapter Options
+@c man begin OPTIONS
+
+@include fftools-common-opts.texi
+
+@section Main options
+
+@table @option
+
+@item -f @var{fmt} (@emph{input/output})
+Force input or output file format. The format is normally auto detected for input
+files and guessed from the file extension for output files, so this option is not
+needed in most cases.
+
+@item -i @var{filename} (@emph{input})
+input file name
+
+@item -y (@emph{global})
+Overwrite output files without asking.
+
+@item -n (@emph{global})
+Do not overwrite output files, and exit immediately if a specified
+output file already exists.
+
+@item -c[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
+@itemx -codec[:@var{stream_specifier}] @var{codec} (@emph{input/output,per-stream})
+Select an encoder (when used before an output file) or a decoder (when used
+before an input file) for one or more streams. @var{codec} is the name of a
+decoder/encoder or a special value @code{copy} (output only) to indicate that
+the stream is not to be re-encoded.
+
+For example
+@example
+ffmpeg -i INPUT -map 0 -c:v libx264 -c:a copy OUTPUT
+@end example
+encodes all video streams with libx264 and copies all audio streams.
+
+For each stream, the last matching @code{c} option is applied, so
+@example
+ffmpeg -i INPUT -map 0 -c copy -c:v:1 libx264 -c:a:137 libvorbis OUTPUT
+@end example
+will copy all the streams except the second video, which will be encoded with
+libx264, and the 138th audio, which will be encoded with libvorbis.
+
+@item -t @var{duration} (@emph{input/output})
+When used as an input option (before @code{-i}), limit the @var{duration} of
+data read from the input file.
+
+When used as an output option (before an output filename), stop writing the
+output after its duration reaches @var{duration}.
+
+@var{duration} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
+
+-to and -t are mutually exclusive and -t has priority.
+
+@item -to @var{position} (@emph{output})
+Stop writing the output at @var{position}.
+@var{position} may be a number in seconds, or in @code{hh:mm:ss[.xxx]} form.
+
+-to and -t are mutually exclusive and -t has priority.
+
+@item -fs @var{limit_size} (@emph{output})
+Set the file size limit, expressed in bytes.
+
+@item -ss @var{position} (@emph{input/output})
+When used as an input option (before @code{-i}), seeks in this input file to
+@var{position}. Note the in most formats it is not possible to seek exactly, so
+@command{ffmpeg} will seek to the closest seek point before @var{position}.
+When transcoding and @option{-accurate_seek} is enabled (the default), this
+extra segment between the seek point and @var{position} will be decoded and
+discarded. When doing stream copy or when @option{-noaccurate_seek} is used, it
+will be preserved.
+
+When used as an output option (before an output filename), decodes but discards
+input until the timestamps reach @var{position}.
+
+@var{position} may be either in seconds or in @code{hh:mm:ss[.xxx]} form.
+
+@item -itsoffset @var{offset} (@emph{input})
+Set the input time offset.
+
+@var{offset} must be a time duration specification,
+see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}.
+
+The offset is added to the timestamps of the input files. Specifying
+a positive offset means that the corresponding streams are delayed by
+the time duration specified in @var{offset}.
+
+@item -timestamp @var{date} (@emph{output})
+Set the recording timestamp in the container.
+
+@var{date} must be a time duration specification,
+see @ref{date syntax,,the Date section in the ffmpeg-utils(1) manual,ffmpeg-utils}.
+
+@item -metadata[:metadata_specifier] @var{key}=@var{value} (@emph{output,per-metadata})
+Set a metadata key/value pair.
+
+An optional @var{metadata_specifier} may be given to set metadata
+on streams or chapters. See @code{-map_metadata} documentation for
+details.
+
+This option overrides metadata set with @code{-map_metadata}. It is
+also possible to delete metadata by using an empty value.
+
+For example, for setting the title in the output file:
+@example
+ffmpeg -i in.avi -metadata title="my title" out.flv
+@end example
+
+To set the language of the first audio stream:
+@example
+ffmpeg -i INPUT -metadata:s:a:0 language=eng OUTPUT
+@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
+@code{film-} to use the corresponding standard. All the format options
+(bitrate, codecs, buffer sizes) are then set automatically. You can just type:
+
+@example
+ffmpeg -i myfile.avi -target vcd /tmp/vcd.mpg
+@end example
+
+Nevertheless you can specify additional options as long as you know
+they do not conflict with the standard, as in:
+
+@example
+ffmpeg -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg
+@end example
+
+@item -dframes @var{number} (@emph{output})
+Set the number of data frames to output. This is an alias for @code{-frames:d}.
+
+@item -frames[:@var{stream_specifier}] @var{framecount} (@emph{output,per-stream})
+Stop writing to the stream after @var{framecount} frames.
+
+@item -q[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
+@itemx -qscale[:@var{stream_specifier}] @var{q} (@emph{output,per-stream})
+Use fixed quality scale (VBR). The meaning of @var{q}/@var{qscale} is
+codec-dependent.
+If @var{qscale} is used without a @var{stream_specifier} then it applies only
+to the video stream, this is to maintain compatibility with previous behavior
+and as specifying the same codec specific value to 2 different codecs that is
+audio and video generally is not what is intended when no stream_specifier is
+used.
+
+@anchor{filter_option}
+@item -filter[:@var{stream_specifier}] @var{filtergraph} (@emph{output,per-stream})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+@var{filtergraph} is a description of the filtergraph to apply to
+the stream, and must have a single input and a single output of the
+same type of the stream. In the filtergraph, the input is associated
+to the label @code{in}, and the output to the label @code{out}. See
+the ffmpeg-filters manual for more information about the filtergraph
+syntax.
+
+See the @ref{filter_complex_option,,-filter_complex option} if you
+want to create filtergraphs with multiple inputs and/or outputs.
+
+@item -filter_script[:@var{stream_specifier}] @var{filename} (@emph{output,per-stream})
+This option is similar to @option{-filter}, the only difference is that its
+argument is the name of the file from which a filtergraph description is to be
+read.
+
+@item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream})
+Specify the preset for matching stream(s).
+
+@item -stats (@emph{global})
+Print encoding progress/statistics. It is on by default, to explicitly
+disable it you need to specify @code{-nostats}.
+
+@item -progress @var{url} (@emph{global})
+Send program-friendly progress information to @var{url}.
+
+Progress information is written approximately every second and at the end of
+the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key}
+consists of only alphanumeric characters. The last key of a sequence of
+progress information is always "progress".
+
+@item -stdin
+Enable interaction on standard input. On by default unless standard input is
+used as an input. To explicitly disable interaction you need to specify
+@code{-nostdin}.
+
+Disabling interaction on standard input is useful, for example, if
+ffmpeg is in the background process group. Roughly the same result can
+be achieved with @code{ffmpeg ... < /dev/null} but it requires a
+shell.
+
+@item -debug_ts (@emph{global})
+Print timestamp information. It is off by default. This option is
+mostly useful for testing and debugging purposes, and the output
+format may change from one version to another, so it should not be
+employed by portable scripts.
+
+See also the option @code{-fdebug ts}.
+
+@item -attach @var{filename} (@emph{output})
+Add an attachment to the output file. This is supported by a few formats
+like Matroska for e.g. fonts used in rendering subtitles. Attachments
+are implemented as a specific type of stream, so this option will add
+a new stream to the file. It is then possible to use per-stream options
+on this stream in the usual way. Attachment streams created with this
+option will be created after all the other streams (i.e. those created
+with @code{-map} or automatic mappings).
+
+Note that for Matroska you also have to set the mimetype metadata tag:
+@example
+ffmpeg -i INPUT -attach DejaVuSans.ttf -metadata:s:2 mimetype=application/x-truetype-font out.mkv
+@end example
+(assuming that the attachment stream will be third in the output file).
+
+@item -dump_attachment[:@var{stream_specifier}] @var{filename} (@emph{input,per-stream})
+Extract the matching attachment stream into a file named @var{filename}. If
+@var{filename} is empty, then the value of the @code{filename} metadata tag
+will be used.
+
+E.g. to extract the first attachment to a file named 'out.ttf':
+@example
+ffmpeg -dump_attachment:t:0 out.ttf -i INPUT
+@end example
+To extract all attachments to files determined by the @code{filename} tag:
+@example
+ffmpeg -dump_attachment:t "" -i INPUT
+@end example
+
+Technical note -- attachments are implemented as codec extradata, so this
+option can actually be used to extract extradata from any stream, not just
+attachments.
+
+@item -noautorotate
+Disable automatically rotating video based on file metadata.
+
+@end table
+
+@section Video Options
+
+@table @option
+@item -vframes @var{number} (@emph{output})
+Set the number of video frames to output. This is an alias for @code{-frames:v}.
+@item -r[:@var{stream_specifier}] @var{fps} (@emph{input/output,per-stream})
+Set frame rate (Hz value, fraction or abbreviation).
+
+As an input option, ignore any timestamps stored in the file and instead
+generate timestamps assuming constant frame rate @var{fps}.
+This is not the same as the @option{-framerate} option used for some input formats
+like image2 or v4l2 (it used to be the same in older versions of FFmpeg).
+If in doubt use @option{-framerate} instead of the input option @option{-r}.
+
+As an output option, duplicate or drop input frames to achieve constant output
+frame rate @var{fps}.
+
+@item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream})
+Set frame size.
+
+As an input option, this is a shortcut for the @option{video_size} private
+option, recognized by some demuxers for which the frame size is either not
+stored in the file or is configurable -- e.g. raw video or video grabbers.
+
+As an output option, this inserts the @code{scale} video filter to the
+@emph{end} of the corresponding filtergraph. Please use the @code{scale} filter
+directly to insert it at the beginning or some other place.
+
+The format is @samp{wxh} (default - same as source).
+
+@item -aspect[:@var{stream_specifier}] @var{aspect} (@emph{output,per-stream})
+Set the video display aspect ratio specified by @var{aspect}.
+
+@var{aspect} can be a floating point number string, or a string of the
+form @var{num}:@var{den}, where @var{num} and @var{den} are the
+numerator and denominator of the aspect ratio. For example "4:3",
+"16:9", "1.3333", and "1.7777" are valid argument values.
+
+If used together with @option{-vcodec copy}, it will affect the aspect ratio
+stored at container level, but not the aspect ratio stored in encoded
+frames, if it exists.
+
+@item -vn (@emph{output})
+Disable video recording.
+
+@item -vcodec @var{codec} (@emph{output})
+Set the video codec. This is an alias for @code{-codec:v}.
+
+@item -pass[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
+Select the pass number (1 or 2). It is used to do two-pass
+video encoding. The statistics of the video are recorded in the first
+pass into a log file (see also the option -passlogfile),
+and in the second pass that log file is used to generate the video
+at the exact requested bitrate.
+On pass 1, you may just deactivate audio and set output to null,
+examples for Windows and Unix:
+@example
+ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y NUL
+ffmpeg -i foo.mov -c:v libxvid -pass 1 -an -f rawvideo -y /dev/null
+@end example
+
+@item -passlogfile[:@var{stream_specifier}] @var{prefix} (@emph{output,per-stream})
+Set two-pass log file name prefix to @var{prefix}, the default file name
+prefix is ``ffmpeg2pass''. The complete file name will be
+@file{PREFIX-N.log}, where N is a number specific to the output
+stream
+
+@item -vf @var{filtergraph} (@emph{output})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+This is an alias for @code{-filter:v}, see the @ref{filter_option,,-filter option}.
+@end table
+
+@section Advanced Video options
+
+@table @option
+@item -pix_fmt[:@var{stream_specifier}] @var{format} (@emph{input/output,per-stream})
+Set pixel format. Use @code{-pix_fmts} to show all the supported
+pixel formats.
+If the selected pixel format can not be selected, ffmpeg will print a
+warning and select the best pixel format supported by the encoder.
+If @var{pix_fmt} is prefixed by a @code{+}, ffmpeg will exit with an error
+if the requested pixel format can not be selected, and automatic conversions
+inside filtergraphs are disabled.
+If @var{pix_fmt} is a single @code{+}, ffmpeg selects the same pixel format
+as the input (or graph output) and automatic conversions are disabled.
+
+@item -sws_flags @var{flags} (@emph{input/output})
+Set SwScaler flags.
+@item -vdt @var{n}
+Discard threshold.
+
+@item -rc_override[:@var{stream_specifier}] @var{override} (@emph{output,per-stream})
+Rate control override for specific intervals, formatted as "int,int,int"
+list separated with slashes. Two first values are the beginning and
+end frame numbers, last one is quantizer to use if positive, or quality
+factor if negative.
+
+@item -ilme
+Force interlacing support in encoder (MPEG-2 and MPEG-4 only).
+Use this option if your input file is interlaced and you want
+to keep the interlaced format for minimum losses.
+The alternative is to deinterlace the input stream with
+@option{-deinterlace}, but deinterlacing introduces losses.
+@item -psnr
+Calculate PSNR of compressed frames.
+@item -vstats
+Dump video coding statistics to @file{vstats_HHMMSS.log}.
+@item -vstats_file @var{file}
+Dump video coding statistics to @var{file}.
+@item -top[:@var{stream_specifier}] @var{n} (@emph{output,per-stream})
+top=1/bottom=0/auto=-1 field first
+@item -dc @var{precision}
+Intra_dc_precision.
+@item -vtag @var{fourcc/tag} (@emph{output})
+Force video tag/fourcc. This is an alias for @code{-tag:v}.
+@item -qphist (@emph{global})
+Show QP histogram
+@item -vbsf @var{bitstream_filter}
+Deprecated see -bsf
+
+@item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] (@emph{output,per-stream})
+@item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} (@emph{output,per-stream})
+Force key frames at the specified timestamps, more precisely at the first
+frames after each specified time.
+
+If the argument is prefixed with @code{expr:}, the string @var{expr}
+is interpreted like an expression and is evaluated for each frame. A
+key frame is forced in case the evaluation is non-zero.
+
+If one of the times is "@code{chapters}[@var{delta}]", it is expanded into
+the time of the beginning of all chapters in the file, shifted by
+@var{delta}, expressed as a time in seconds.
+This option can be useful to ensure that a seek point is present at a
+chapter mark or any other designated place in the output file.
+
+For example, to insert a key frame at 5 minutes, plus key frames 0.1 second
+before the beginning of every chapter:
+@example
+-force_key_frames 0:05:00,chapters-0.1
+@end example
+
+The expression in @var{expr} can contain the following constants:
+@table @option
+@item n
+the number of current processed frame, starting from 0
+@item n_forced
+the number of forced frames
+@item prev_forced_n
+the number of the previous forced frame, it is @code{NAN} when no
+keyframe was forced yet
+@item prev_forced_t
+the time of the previous forced frame, it is @code{NAN} when no
+keyframe was forced yet
+@item t
+the time of the current processed frame
+@end table
+
+For example to force a key frame every 5 seconds, you can specify:
+@example
+-force_key_frames expr:gte(t,n_forced*5)
+@end example
+
+To force a key frame 5 seconds after the time of the last forced one,
+starting from second 13:
+@example
+-force_key_frames expr:if(isnan(prev_forced_t),gte(t,13),gte(t,prev_forced_t+5))
+@end example
+
+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 -copyinkf[:@var{stream_specifier}] (@emph{output,per-stream})
+When doing stream copy, copy also non-key frames found at the
+beginning.
+
+@item -hwaccel[:@var{stream_specifier}] @var{hwaccel} (@emph{input,per-stream})
+Use hardware acceleration to decode the matching stream(s). The allowed values
+of @var{hwaccel} are:
+@table @option
+@item none
+Do not use any hardware acceleration (the default).
+
+@item auto
+Automatically select the hardware acceleration method.
+
+@item vda
+Use Apple VDA hardware acceleration.
+
+@item vdpau
+Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration.
+
+@item dxva2
+Use DXVA2 (DirectX Video Acceleration) hardware acceleration.
+@end table
+
+This option has no effect if the selected hwaccel is not available or not
+supported by the chosen decoder.
+
+Note that most acceleration methods are intended for playback and will not be
+faster than software decoding on modern CPUs. Additionally, @command{ffmpeg}
+will usually need to copy the decoded frames from the GPU memory into the system
+memory, resulting in further performance loss. This option is thus mainly
+useful for testing.
+
+@item -hwaccel_device[:@var{stream_specifier}] @var{hwaccel_device} (@emph{input,per-stream})
+Select a device to use for hardware acceleration.
+
+This option only makes sense when the @option{-hwaccel} option is also
+specified. Its exact meaning depends on the specific hardware acceleration
+method chosen.
+
+@table @option
+@item vdpau
+For VDPAU, this option specifies the X11 display/screen to use. If this option
+is not specified, the value of the @var{DISPLAY} environment variable is used
+
+@item dxva2
+For DXVA2, this option should contain the number of the display adapter to use.
+If this option is not specified, the default adapter is used.
+@end table
+@end table
+
+@section Audio Options
+
+@table @option
+@item -aframes @var{number} (@emph{output})
+Set the number of audio frames to output. This is an alias for @code{-frames:a}.
+@item -ar[:@var{stream_specifier}] @var{freq} (@emph{input/output,per-stream})
+Set the audio sampling frequency. For output streams it is set by
+default to the frequency of the corresponding input stream. For input
+streams this option only makes sense for audio grabbing devices and raw
+demuxers and is mapped to the corresponding demuxer options.
+@item -aq @var{q} (@emph{output})
+Set the audio quality (codec-specific, VBR). This is an alias for -q:a.
+@item -ac[:@var{stream_specifier}] @var{channels} (@emph{input/output,per-stream})
+Set the number of audio channels. For output streams it is set by
+default to the number of input audio channels. For input streams
+this option only makes sense for audio grabbing devices and raw demuxers
+and is mapped to the corresponding demuxer options.
+@item -an (@emph{output})
+Disable audio recording.
+@item -acodec @var{codec} (@emph{input/output})
+Set the audio codec. This is an alias for @code{-codec:a}.
+@item -sample_fmt[:@var{stream_specifier}] @var{sample_fmt} (@emph{output,per-stream})
+Set the audio sample format. Use @code{-sample_fmts} to get a list
+of supported sample formats.
+
+@item -af @var{filtergraph} (@emph{output})
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the stream.
+
+This is an alias for @code{-filter:a}, see the @ref{filter_option,,-filter option}.
+@end table
+
+@section Advanced Audio options
+
+@table @option
+@item -atag @var{fourcc/tag} (@emph{output})
+Force audio tag/fourcc. This is an alias for @code{-tag:a}.
+@item -absf @var{bitstream_filter}
+Deprecated, see -bsf
+@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.
+@end table
+
+@section Subtitle options
+
+@table @option
+@item -scodec @var{codec} (@emph{input/output})
+Set the subtitle codec. This is an alias for @code{-codec:s}.
+@item -sn (@emph{output})
+Disable subtitle recording.
+@item -sbsf @var{bitstream_filter}
+Deprecated, see -bsf
+@end table
+
+@section Advanced Subtitle options
+
+@table @option
+
+@item -fix_sub_duration
+Fix subtitles durations. For each subtitle, wait for the next packet in the
+same stream and adjust the duration of the first to avoid overlap. This is
+necessary with some subtitles codecs, especially DVB subtitles, because the
+duration in the original packet is only a rough estimate and the end is
+actually marked by an empty subtitle frame. Failing to use this option when
+necessary can result in exaggerated durations or muxing failures due to
+non-monotonic timestamps.
+
+Note that this option will delay the output of all data until the next
+subtitle packet is decoded: it may increase memory consumption and latency a
+lot.
+
+@item -canvas_size @var{size}
+Set the size of the canvas used to render subtitles.
+
+@end table
+
+@section Advanced options
+
+@table @option
+@item -map [-]@var{input_file_id}[:@var{stream_specifier}][,@var{sync_file_id}[:@var{stream_specifier}]] | @var{[linklabel]} (@emph{output})
+
+Designate one or more input streams as a source for the output file. Each input
+stream is identified by the input file index @var{input_file_id} and
+the input stream index @var{input_stream_id} within the input
+file. Both indices start at 0. If specified,
+@var{sync_file_id}:@var{stream_specifier} sets which input stream
+is used as a presentation sync reference.
+
+The first @code{-map} option on the command line specifies the
+source for output stream 0, the second @code{-map} option specifies
+the source for output stream 1, etc.
+
+A @code{-} character before the stream identifier creates a "negative" mapping.
+It disables matching streams from already created mappings.
+
+An alternative @var{[linklabel]} form will map outputs from complex filter
+graphs (see the @option{-filter_complex} option) to the output file.
+@var{linklabel} must correspond to a defined output link label in the graph.
+
+For example, to map ALL streams from the first input file to output
+@example
+ffmpeg -i INPUT -map 0 output
+@end example
+
+For example, if you have two audio streams in the first input file,
+these streams are identified by "0:0" and "0:1". You can use
+@code{-map} to select which streams to place in an output file. For
+example:
+@example
+ffmpeg -i INPUT -map 0:1 out.wav
+@end example
+will map the input stream in @file{INPUT} identified by "0:1" to
+the (single) output stream in @file{out.wav}.
+
+For example, to select the stream with index 2 from input file
+@file{a.mov} (specified by the identifier "0:2"), and stream with
+index 6 from input @file{b.mov} (specified by the identifier "1:6"),
+and copy them to the output file @file{out.mov}:
+@example
+ffmpeg -i a.mov -i b.mov -c copy -map 0:2 -map 1:6 out.mov
+@end example
+
+To select all video and the third audio stream from an input file:
+@example
+ffmpeg -i INPUT -map 0:v -map 0:a:2 OUTPUT
+@end example
+
+To map all the streams except the second audio, use negative mappings
+@example
+ffmpeg -i INPUT -map 0 -map -0:a:1 OUTPUT
+@end example
+
+To pick the English audio stream:
+@example
+ffmpeg -i INPUT -map 0:m:language:eng OUTPUT
+@end example
+
+Note that using this option disables the default mappings for this output file.
+
+@item -ignore_unknown
+Ignore input streams with unknown type instead of failing if copying
+such streams is attempted.
+
+@item -copy_unknown
+Allow input streams with unknown type to be copied instead of failing if copying
+such streams is attempted.
+
+@item -map_channel [@var{input_file_id}.@var{stream_specifier}.@var{channel_id}|-1][:@var{output_file_id}.@var{stream_specifier}]
+Map an audio channel from a given input to an output. If
+@var{output_file_id}.@var{stream_specifier} is not set, the audio channel will
+be mapped on all the audio streams.
+
+Using "-1" instead of
+@var{input_file_id}.@var{stream_specifier}.@var{channel_id} will map a muted
+channel.
+
+For example, assuming @var{INPUT} is a stereo audio file, you can switch the
+two audio channels with the following command:
+@example
+ffmpeg -i INPUT -map_channel 0.0.1 -map_channel 0.0.0 OUTPUT
+@end example
+
+If you want to mute the first channel and keep the second:
+@example
+ffmpeg -i INPUT -map_channel -1 -map_channel 0.0.1 OUTPUT
+@end example
+
+The order of the "-map_channel" option specifies the order of the channels in
+the output stream. The output channel layout is guessed from the number of
+channels mapped (mono if one "-map_channel", stereo if two, etc.). Using "-ac"
+in combination of "-map_channel" makes the channel gain levels to be updated if
+input and output channel layouts don't match (for instance two "-map_channel"
+options and "-ac 6").
+
+You can also extract each channel of an input to specific outputs; the following
+command extracts two channels of the @var{INPUT} audio stream (file 0, stream 0)
+to the respective @var{OUTPUT_CH0} and @var{OUTPUT_CH1} outputs:
+@example
+ffmpeg -i INPUT -map_channel 0.0.0 OUTPUT_CH0 -map_channel 0.0.1 OUTPUT_CH1
+@end example
+
+The following example splits the channels of a stereo input into two separate
+streams, which are put into the same output file:
+@example
+ffmpeg -i stereo.wav -map 0:0 -map 0:0 -map_channel 0.0.0:0.0 -map_channel 0.0.1:0.1 -y out.ogg
+@end example
+
+Note that currently each output stream can only contain channels from a single
+input stream; you can't for example use "-map_channel" to pick multiple input
+audio channels contained in different streams (from the same or different files)
+and merge them into a single output stream. It is therefore not currently
+possible, for example, to turn two separate mono streams into a single stereo
+stream. However splitting a stereo stream into two single channel mono streams
+is possible.
+
+If you need this feature, a possible workaround is to use the @emph{amerge}
+filter. For example, if you need to merge a media (here @file{input.mkv}) with 2
+mono audio streams into one single stereo channel audio stream (and keep the
+video stream), you can use the following command:
+@example
+ffmpeg -i input.mkv -filter_complex "[0:1] [0:2] amerge" -c:a pcm_s16le -c:v copy output.mkv
+@end example
+
+@item -map_metadata[:@var{metadata_spec_out}] @var{infile}[:@var{metadata_spec_in}] (@emph{output,per-metadata})
+Set metadata information of the next output file from @var{infile}. Note that
+those are file indices (zero-based), not filenames.
+Optional @var{metadata_spec_in/out} parameters specify, which metadata to copy.
+A metadata specifier can have the following forms:
+@table @option
+@item @var{g}
+global metadata, i.e. metadata that applies to the whole file
+
+@item @var{s}[:@var{stream_spec}]
+per-stream metadata. @var{stream_spec} is a stream specifier as described
+in the @ref{Stream specifiers} chapter. In an input metadata specifier, the first
+matching stream is copied from. In an output metadata specifier, all matching
+streams are copied to.
+
+@item @var{c}:@var{chapter_index}
+per-chapter metadata. @var{chapter_index} is the zero-based chapter index.
+
+@item @var{p}:@var{program_index}
+per-program metadata. @var{program_index} is the zero-based program index.
+@end table
+If metadata specifier is omitted, it defaults to global.
+
+By default, global metadata is copied from the first input file,
+per-stream and per-chapter metadata is copied along with streams/chapters. These
+default mappings are disabled by creating any mapping of the relevant type. A negative
+file index can be used to create a dummy mapping that just disables automatic copying.
+
+For example to copy metadata from the first stream of the input file to global metadata
+of the output file:
+@example
+ffmpeg -i in.ogg -map_metadata 0:s:0 out.mp3
+@end example
+
+To do the reverse, i.e. copy global metadata to all audio streams:
+@example
+ffmpeg -i in.mkv -map_metadata:s:a 0:g out.mkv
+@end example
+Note that simple @code{0} would work as well in this example, since global
+metadata is assumed by default.
+
+@item -map_chapters @var{input_file_index} (@emph{output})
+Copy chapters from input file with index @var{input_file_index} to the next
+output file. If no chapter mapping is specified, then chapters are copied from
+the first input file with at least one chapter. Use a negative file index to
+disable any chapter copying.
+
+@item -benchmark (@emph{global})
+Show benchmarking information at the end of an encode.
+Shows CPU time used and maximum memory consumption.
+Maximum memory consumption is not supported on all systems,
+it will usually display as 0 if not supported.
+@item -benchmark_all (@emph{global})
+Show benchmarking information during the encode.
+Shows CPU time used in various steps (audio/video encode/decode).
+@item -timelimit @var{duration} (@emph{global})
+Exit after ffmpeg has been running for @var{duration} seconds.
+@item -dump (@emph{global})
+Dump each input packet to stderr.
+@item -hex (@emph{global})
+When dumping packets, also dump the payload.
+@item -re (@emph{input})
+Read input at native frame rate. Mainly used to simulate a grab device.
+or live input stream (e.g. when reading from a file). Should not be used
+with actual grab devices or live input streams (where it can cause packet
+loss).
+By default @command{ffmpeg} attempts to read the input(s) as fast as possible.
+This option will slow down the reading of the input(s) to the native frame rate
+of the input(s). It is useful for real-time output (e.g. live streaming).
+@item -loop_input
+Loop over the input stream. Currently it works only for image
+streams. This option is used for automatic FFserver testing.
+This option is deprecated, use -loop 1.
+@item -loop_output @var{number_of_times}
+Repeatedly loop output for formats that support looping such as animated GIF
+(0 will loop the output infinitely).
+This option is deprecated, use -loop.
+@item -vsync @var{parameter}
+Video sync method.
+For compatibility reasons old values can be specified as numbers.
+Newly added values will have to be specified as strings always.
+
+@table @option
+@item 0, passthrough
+Each frame is passed with its timestamp from the demuxer to the muxer.
+@item 1, cfr
+Frames will be duplicated and dropped to achieve exactly the requested
+constant frame rate.
+@item 2, vfr
+Frames are passed through with their timestamp or dropped so as to
+prevent 2 frames from having the same timestamp.
+@item drop
+As passthrough but destroys all timestamps, making the muxer generate
+fresh timestamps based on frame-rate.
+@item -1, auto
+Chooses between 1 and 2 depending on muxer capabilities. This is the
+default method.
+@end table
+
+Note that the timestamps may be further modified by the muxer, after this.
+For example, in the case that the format option @option{avoid_negative_ts}
+is enabled.
+
+With -map you can select from which stream the timestamps should be
+taken. You can leave either video or audio unchanged and sync the
+remaining stream(s) to the unchanged one.
+
+@item -frame_drop_threshold @var{parameter}
+Frame drop threshold, which specifies how much behind video frames can
+be before they are dropped. In frame rate units, so 1.0 is one frame.
+The default is -1.1. One possible usecase is to avoid framedrops in case
+of noisy timestamps or to increase frame drop precision in case of exact
+timestamps.
+
+@item -async @var{samples_per_second}
+Audio sync method. "Stretches/squeezes" the audio stream to match the timestamps,
+the parameter is the maximum samples per second by which the audio is changed.
+-async 1 is a special case where only the start of the audio stream is corrected
+without any later correction.
+
+Note that the timestamps may be further modified by the muxer, after this.
+For example, in the case that the format option @option{avoid_negative_ts}
+is enabled.
+
+This option has been deprecated. Use the @code{aresample} audio filter instead.
+
+@item -copyts
+Do not process input timestamps, but keep their values without trying
+to sanitize them. In particular, do not remove the initial start time
+offset value.
+
+Note that, depending on the @option{vsync} option or on specific muxer
+processing (e.g. in case the format option @option{avoid_negative_ts}
+is enabled) the output timestamps may mismatch with the input
+timestamps even when this option is selected.
+
+@item -start_at_zero
+When used with @option{copyts}, shift input timestamps so they start at zero.
+
+This means that using e.g. @code{-ss 50} will make output timestamps start at
+50 seconds, regardless of what timestamp the input file started at.
+
+@item -copytb @var{mode}
+Specify how to set the encoder timebase when stream copying. @var{mode} is an
+integer numeric value, and can assume one of the following values:
+
+@table @option
+@item 1
+Use the demuxer timebase.
+
+The time base is copied to the output encoder from the corresponding input
+demuxer. This is sometimes required to avoid non monotonically increasing
+timestamps when copying video streams with variable frame rate.
+
+@item 0
+Use the decoder timebase.
+
+The time base is copied to the output encoder from the corresponding input
+decoder.
+
+@item -1
+Try to make the choice automatically, in order to generate a sane output.
+@end table
+
+Default value is -1.
+
+@item -shortest (@emph{output})
+Finish encoding when the shortest input stream ends.
+@item -dts_delta_threshold
+Timestamp discontinuity delta threshold.
+@item -muxdelay @var{seconds} (@emph{input})
+Set the maximum demux-decode delay.
+@item -muxpreload @var{seconds} (@emph{input})
+Set the initial demux-decode delay.
+@item -streamid @var{output-stream-index}:@var{new-value} (@emph{output})
+Assign a new stream-id value to an output stream. This option should be
+specified prior to the output filename to which it applies.
+For the situation where multiple output files exist, a streamid
+may be reassigned to a different value.
+
+For example, to set the stream 0 PID to 33 and the stream 1 PID to 36 for
+an output mpegts file:
+@example
+ffmpeg -i infile -streamid 0:33 -streamid 1:36 out.ts
+@end example
+
+@item -bsf[:@var{stream_specifier}] @var{bitstream_filters} (@emph{output,per-stream})
+Set bitstream filters for matching streams. @var{bitstream_filters} is
+a comma-separated list of bitstream filters. Use the @code{-bsfs} option
+to get the list of bitstream filters.
+@example
+ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
+@end example
+@example
+ffmpeg -i file.mov -an -vn -bsf:s mov2textsub -c:s copy -f rawvideo sub.txt
+@end example
+
+@item -tag[:@var{stream_specifier}] @var{codec_tag} (@emph{input/output,per-stream})
+Force a tag/fourcc for matching streams.
+
+@item -timecode @var{hh}:@var{mm}:@var{ss}SEP@var{ff}
+Specify Timecode for writing. @var{SEP} is ':' for non drop timecode and ';'
+(or '.') for drop.
+@example
+ffmpeg -i input.mpg -timecode 01:02:03.04 -r 30000/1001 -s ntsc output.mpg
+@end example
+
+@anchor{filter_complex_option}
+@item -filter_complex @var{filtergraph} (@emph{global})
+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.
+
+Input link labels must refer to input streams using 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. An unlabeled input will be connected to the first unused input stream of
+the matching type.
+
+Output link labels are referred to with @option{-map}. Unlabeled outputs are
+added to the first output file.
+
+Note that with this option it is possible to use only lavfi sources without
+normal input files.
+
+For example, to overlay an image over video
+@example
+ffmpeg -i video.mkv -i image.png -filter_complex '[0:v][1:v]overlay[out]' -map
+'[out]' out.mkv
+@end example
+Here @code{[0:v]} refers to the first video stream in the first input file,
+which is linked to the first (main) input of the overlay filter. Similarly the
+first video stream in the second input is linked to the second (overlay) input
+of overlay.
+
+Assuming there is only one video stream in each input file, we can omit input
+labels, so the above is equivalent to
+@example
+ffmpeg -i video.mkv -i image.png -filter_complex 'overlay[out]' -map
+'[out]' out.mkv
+@end example
+
+Furthermore we can omit the output label and the single output from the filter
+graph will be added to the output file automatically, so we can simply write
+@example
+ffmpeg -i video.mkv -i image.png -filter_complex 'overlay' out.mkv
+@end example
+
+To generate 5 seconds of pure red video using lavfi @code{color} source:
+@example
+ffmpeg -filter_complex 'color=c=red' -t 5 out.mkv
+@end example
+
+@item -lavfi @var{filtergraph} (@emph{global})
+Define a complex filtergraph, i.e. one with arbitrary number of inputs and/or
+outputs. Equivalent to @option{-filter_complex}.
+
+@item -filter_complex_script @var{filename} (@emph{global})
+This option is similar to @option{-filter_complex}, the only difference is that
+its argument is the name of the file from which a complex filtergraph
+description is to be read.
+
+@item -accurate_seek (@emph{input})
+This option enables or disables accurate seeking in input files with the
+@option{-ss} option. It is enabled by default, so seeking is accurate when
+transcoding. Use @option{-noaccurate_seek} to disable it, which may be useful
+e.g. when copying some streams and transcoding the others.
+
+@item -seek_timestamp (@emph{input})
+This option enables or disables seeking by timestamp in input files with the
+@option{-ss} option. It is disabled by default. If enabled, the argument
+to the @option{-ss} option is considered an actual timestamp, and is not
+offset by the start time of the file. This matters only for files which do
+not start from timestamp 0, such as transport streams.
+
+@item -thread_queue_size @var{size} (@emph{input})
+This option sets the maximum number of queued packets when reading from the
+file or device. With low latency / high rate live streams, packets may be
+discarded if they are not read in a timely manner; raising this value can
+avoid it.
+
+@item -override_ffserver (@emph{global})
+Overrides the input specifications from @command{ffserver}. Using this
+option you can map any input stream to @command{ffserver} and control
+many aspects of the encoding from @command{ffmpeg}. Without this
+option @command{ffmpeg} will transmit to @command{ffserver} what is
+requested by @command{ffserver}.
+
+The option is intended for cases where features are needed that cannot be
+specified to @command{ffserver} but can be to @command{ffmpeg}.
+
+@item -sdp_file @var{file} (@emph{global})
+Print sdp information to @var{file}.
+This allows dumping sdp information when at least one output isn't an
+rtp stream.
+
+@item -discard (@emph{input})
+Allows discarding specific streams or frames of streams at the demuxer.
+Not all demuxers support this.
+
+@table @option
+@item none
+Discard no frame.
+
+@item default
+Default, which discards no frames.
+
+@item noref
+Discard all non-reference frames.
+
+@item bidir
+Discard all bidirectional frames.
+
+@item nokey
+Discard all frames excepts keyframes.
+
+@item all
+Discard all frames.
+@end table
+
+@end table
+
+As a special exception, you can use a bitmap subtitle stream as input: it
+will be converted into a video with the same size as the largest video in
+the file, or 720x576 if no video is present. Note that this is an
+experimental and temporary solution. It will be removed once libavfilter has
+proper support for subtitles.
+
+For example, to hardcode subtitles on top of a DVB-T recording stored in
+MPEG-TS format, delaying the subtitles by 1 second:
+@example
+ffmpeg -i input.ts -filter_complex \
+ '[#0x2ef] setpts=PTS+1/TB [sub] ; [#0x2d0] [sub] overlay' \
+ -sn -map '#0x2dc' output.mkv
+@end example
+(0x2d0, 0x2dc and 0x2ef are the MPEG-TS PIDs of respectively the video,
+audio and subtitles streams; 0:0, 0:3 and 0:7 would have worked too)
+
+@section Preset files
+A preset file contains a sequence of @var{option}=@var{value} pairs,
+one for each line, specifying a sequence of options which would be
+awkward to specify on the command line. Lines starting with the hash
+('#') character are ignored and are used to provide comments. Check
+the @file{presets} directory in the FFmpeg source tree for examples.
+
+There are two types of preset files: ffpreset and avpreset files.
+
+@subsection ffpreset files
+ffpreset files are specified with the @code{vpre}, @code{apre},
+@code{spre}, and @code{fpre} options. The @code{fpre} option takes the
+filename of the preset instead of a preset name as input and can be
+used for any kind of codec. For the @code{vpre}, @code{apre}, and
+@code{spre} options, the options specified in a preset file are
+applied to the currently selected codec of the same type as the preset
+option.
+
+The argument passed to the @code{vpre}, @code{apre}, and @code{spre}
+preset options identifies the preset file to use according to the
+following rules:
+
+First ffmpeg searches for a file named @var{arg}.ffpreset in the
+directories @file{$FFMPEG_DATADIR} (if set), and @file{$HOME/.ffmpeg}, and in
+the datadir defined at configuration time (usually @file{PREFIX/share/ffmpeg})
+or in a @file{ffpresets} folder along the executable on win32,
+in that order. For example, if the argument is @code{libvpx-1080p}, it will
+search for the file @file{libvpx-1080p.ffpreset}.
+
+If no such file is found, then ffmpeg will search for a file named
+@var{codec_name}-@var{arg}.ffpreset in the above-mentioned
+directories, where @var{codec_name} is the name of the codec to which
+the preset file options will be applied. For example, if you select
+the video codec with @code{-vcodec libvpx} and use @code{-vpre 1080p},
+then it will search for the file @file{libvpx-1080p.ffpreset}.
+
+@subsection avpreset files
+avpreset files are specified with the @code{pre} option. They work similar to
+ffpreset files, but they only allow encoder- specific options. Therefore, an
+@var{option}=@var{value} pair specifying an encoder cannot be used.
+
+When the @code{pre} option is specified, ffmpeg will look for files with the
+suffix .avpreset in the directories @file{$AVCONV_DATADIR} (if set), and
+@file{$HOME/.avconv}, and in the datadir defined at configuration time (usually
+@file{PREFIX/share/ffmpeg}), in that order.
+
+First ffmpeg searches for a file named @var{codec_name}-@var{arg}.avpreset in
+the above-mentioned directories, where @var{codec_name} is the name of the codec
+to which the preset file options will be applied. For example, if you select the
+video codec with @code{-vcodec libvpx} and use @code{-pre 1080p}, then it will
+search for the file @file{libvpx-1080p.avpreset}.
+
+If no such file is found, then ffmpeg will search for a file named
+@var{arg}.avpreset in the same directories.
+
+@c man end OPTIONS
+
+@chapter Tips
+@c man begin TIPS
+
+@itemize
+@item
+For streaming at very low bitrates, use a low frame rate
+and a small GOP size. This is especially true for RealVideo where
+the Linux player does not seem to be very fast, so it can miss
+frames. An example is:
+
+@example
+ffmpeg -g 3 -r 3 -t 10 -b:v 50k -s qcif -f rv10 /tmp/b.rm
+@end example
+
+@item
+The parameter 'q' which is displayed while encoding is the current
+quantizer. The value 1 indicates that a very good quality could
+be achieved. The value 31 indicates the worst quality. If q=31 appears
+too often, it means that the encoder cannot compress enough to meet
+your bitrate. You must either increase the bitrate, decrease the
+frame rate or decrease the frame size.
+
+@item
+If your computer is not fast enough, you can speed up the
+compression at the expense of the compression ratio. You can use
+'-me zero' to speed up motion estimation, and '-g 0' to disable
+motion estimation completely (you have only I-frames, which means it
+is about as good as JPEG compression).
+
+@item
+To have very low audio bitrates, reduce the sampling frequency
+(down to 22050 Hz for MPEG audio, 22050 or 11025 for AC-3).
+
+@item
+To have a constant quality (but a variable bitrate), use the option
+'-qscale n' when 'n' is between 1 (excellent quality) and 31 (worst
+quality).
+
+@end itemize
+@c man end TIPS
+
+@chapter Examples
+@c man begin EXAMPLES
+
+@section Video and Audio grabbing
+
+If you specify the input format and device then ffmpeg can grab video
+and audio directly.
+
+@example
+ffmpeg -f oss -i /dev/dsp -f video4linux2 -i /dev/video0 /tmp/out.mpg
+@end example
+
+Or with an ALSA audio source (mono input, card id 1) instead of OSS:
+@example
+ffmpeg -f alsa -ac 1 -i hw:1 -f video4linux2 -i /dev/video0 /tmp/out.mpg
+@end example
+
+Note that you must activate the right video source and channel before
+launching ffmpeg with any TV viewer such as
+@uref{http://linux.bytesex.org/xawtv/, xawtv} by Gerd Knorr. You also
+have to set the audio recording levels correctly with a
+standard mixer.
+
+@section X11 grabbing
+
+Grab the X11 display with ffmpeg via
+
+@example
+ffmpeg -f x11grab -video_size cif -framerate 25 -i :0.0 /tmp/out.mpg
+@end example
+
+0.0 is display.screen number of your X11 server, same as
+the DISPLAY environment variable.
+
+@example
+ffmpeg -f x11grab -video_size cif -framerate 25 -i :0.0+10,20 /tmp/out.mpg
+@end example
+
+0.0 is display.screen number of your X11 server, same as the DISPLAY environment
+variable. 10 is the x-offset and 20 the y-offset for the grabbing.
+
+@section Video and Audio file format conversion
+
+Any supported file format and protocol can serve as input to ffmpeg:
+
+Examples:
+@itemize
+@item
+You can use YUV files as input:
+
+@example
+ffmpeg -i /tmp/test%d.Y /tmp/out.mpg
+@end example
+
+It will use the files:
+@example
+/tmp/test0.Y, /tmp/test0.U, /tmp/test0.V,
+/tmp/test1.Y, /tmp/test1.U, /tmp/test1.V, etc...
+@end example
+
+The Y files use twice the resolution of the U and V files. They are
+raw files, without header. They can be generated by all decent video
+decoders. You must specify the size of the image with the @option{-s} option
+if ffmpeg cannot guess it.
+
+@item
+You can input from a raw YUV420P file:
+
+@example
+ffmpeg -i /tmp/test.yuv /tmp/out.avi
+@end example
+
+test.yuv is a file containing raw YUV planar data. Each frame is composed
+of the Y plane followed by the U and V planes at half vertical and
+horizontal resolution.
+
+@item
+You can output to a raw YUV420P file:
+
+@example
+ffmpeg -i mydivx.avi hugefile.yuv
+@end example
+
+@item
+You can set several input files and output files:
+
+@example
+ffmpeg -i /tmp/a.wav -s 640x480 -i /tmp/a.yuv /tmp/a.mpg
+@end example
+
+Converts the audio file a.wav and the raw YUV video file a.yuv
+to MPEG file a.mpg.
+
+@item
+You can also do audio and video conversions at the same time:
+
+@example
+ffmpeg -i /tmp/a.wav -ar 22050 /tmp/a.mp2
+@end example
+
+Converts a.wav to MPEG audio at 22050 Hz sample rate.
+
+@item
+You can encode to several formats at the same time and define a
+mapping from input stream to output streams:
+
+@example
+ffmpeg -i /tmp/a.wav -map 0:a -b:a 64k /tmp/a.mp2 -map 0:a -b:a 128k /tmp/b.mp2
+@end example
+
+Converts a.wav to a.mp2 at 64 kbits and to b.mp2 at 128 kbits. '-map
+file:index' specifies which input stream is used for each output
+stream, in the order of the definition of output streams.
+
+@item
+You can transcode decrypted VOBs:
+
+@example
+ffmpeg -i snatch_1.vob -f avi -c:v mpeg4 -b:v 800k -g 300 -bf 2 -c:a libmp3lame -b:a 128k snatch.avi
+@end example
+
+This is a typical DVD ripping example; the input is a VOB file, the
+output an AVI file with MPEG-4 video and MP3 audio. Note that in this
+command we use B-frames so the MPEG-4 stream is DivX5 compatible, and
+GOP size is 300 which means one intra frame every 10 seconds for 29.97fps
+input video. Furthermore, the audio stream is MP3-encoded so you need
+to enable LAME support by passing @code{--enable-libmp3lame} to configure.
+The mapping is particularly useful for DVD transcoding
+to get the desired audio language.
+
+NOTE: To see the supported input formats, use @code{ffmpeg -formats}.
+
+@item
+You can extract images from a video, or create a video from many images:
+
+For extracting images from a video:
+@example
+ffmpeg -i foo.avi -r 1 -s WxH -f image2 foo-%03d.jpeg
+@end example
+
+This will extract one video frame per second from the video and will
+output them in files named @file{foo-001.jpeg}, @file{foo-002.jpeg},
+etc. Images will be rescaled to fit the new WxH values.
+
+If you want to extract just a limited number of frames, you can use the
+above command in combination with the -vframes or -t option, or in
+combination with -ss to start extracting from a certain point in time.
+
+For creating a video from many images:
+@example
+ffmpeg -f image2 -framerate 12 -i foo-%03d.jpeg -s WxH foo.avi
+@end example
+
+The syntax @code{foo-%03d.jpeg} specifies to use a decimal number
+composed of three digits padded with zeroes to express the sequence
+number. It is the same syntax supported by the C printf function, but
+only formats accepting a normal integer are suitable.
+
+When importing an image sequence, -i also supports expanding
+shell-like wildcard patterns (globbing) internally, by selecting the
+image2-specific @code{-pattern_type glob} option.
+
+For example, for creating a video from filenames matching the glob pattern
+@code{foo-*.jpeg}:
+@example
+ffmpeg -f image2 -pattern_type glob -framerate 12 -i 'foo-*.jpeg' -s WxH foo.avi
+@end example
+
+@item
+You can put many streams of the same type in the output:
+
+@example
+ffmpeg -i test1.avi -i test2.avi -map 1:1 -map 1:0 -map 0:1 -map 0:0 -c copy -y test12.nut
+@end example
+
+The resulting output file @file{test12.nut} will contain the first four streams
+from the input files in reverse order.
+
+@item
+To force CBR video output:
+@example
+ffmpeg -i myfile.avi -b 4000k -minrate 4000k -maxrate 4000k -bufsize 1835k out.m2v
+@end example
+
+@item
+The four options lmin, lmax, mblmin and mblmax use 'lambda' units,
+but you may use the QP2LAMBDA constant to easily convert from 'q' units:
+@example
+ffmpeg -i src.ext -lmax 21*QP2LAMBDA dst.ext
+@end example
+
+@end itemize
+@c man end EXAMPLES
+
+@include config.texi
+@ifset config-all
+@ifset config-avutil
+@include utils.texi
+@end ifset
+@ifset config-avcodec
+@include codecs.texi
+@include bitstream_filters.texi
+@end ifset
+@ifset config-avformat
+@include formats.texi
+@include protocols.texi
+@end ifset
+@ifset config-avdevice
+@include devices.texi
+@end ifset
+@ifset config-swresample
+@include resampler.texi
+@end ifset
+@ifset config-swscale
+@include scaler.texi
+@end ifset
+@ifset config-avfilter
+@include filters.texi
+@end ifset
+@end ifset
+
+@chapter See Also
+
+@ifhtml
+@ifset config-all
+@url{ffmpeg.html,ffmpeg}
+@end ifset
+@ifset config-not-all
+@url{ffmpeg-all.html,ffmpeg-all},
+@end ifset
+@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-utils.html,ffmpeg-utils},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{ffmpeg-codecs.html,ffmpeg-codecs},
+@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters},
+@url{ffmpeg-formats.html,ffmpeg-formats},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{ffmpeg-filters.html,ffmpeg-filters}
+@end ifhtml
+
+@ifnothtml
+@ifset config-all
+ffmpeg(1),
+@end ifset
+@ifset config-not-all
+ffmpeg-all(1),
+@end ifset
+ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1),
+ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffmpeg
+@settitle ffmpeg video converter
+
+@end ignore
+
+@bye
diff --git a/doc/ffmpeg.txt b/doc/ffmpeg.txt
new file mode 100644
index 0000000000..a028ca23d2
--- /dev/null
+++ b/doc/ffmpeg.txt
@@ -0,0 +1,47 @@
+ :
+ ffmpeg.c : libav*
+ ======== : ======
+ :
+ :
+ --------------------------------:---> AVStream...
+ InputStream input_streams[] / :
+ / :
+ InputFile input_files[] +==========================+ / ^ :
+ ------> 0 | : st ---:-----------:--/ : :
+ ^ +------+-----------+-----+ / +--------------------------+ : :
+ : | :ist_index--:-----:---------/ 1 | : st : | : :
+ : +------+-----------+-----+ +==========================+ : :
+ nb_input_files : | :ist_index--:-----:------------------> 2 | : st : | : :
+ : +------+-----------+-----+ +--------------------------+ : nb_input_streams :
+ : | :ist_index : | 3 | ... | : :
+ v +------+-----------+-----+ +--------------------------+ : :
+ --> 4 | | : :
+ | +--------------------------+ : :
+ | 5 | | : :
+ | +==========================+ v :
+ | :
+ | :
+ | :
+ | :
+ --------- --------------------------------:---> AVStream...
+ \ / :
+ OutputStream output_streams[] / :
+ \ / :
+ +======\======================/======+ ^ :
+ ------> 0 | : source_index : st-:--- | : :
+ OutputFile output_files[] / +------------------------------------+ : :
+ / 1 | : : : | : :
+ ^ +------+------------+-----+ / +------------------------------------+ : :
+ : | : ost_index -:-----:------/ 2 | : : : | : :
+ nb_output_files : +------+------------+-----+ +====================================+ : :
+ : | : ost_index -:-----|-----------------> 3 | : : : | : :
+ : +------+------------+-----+ +------------------------------------+ : nb_output_streams :
+ : | : : | 4 | | : :
+ : +------+------------+-----+ +------------------------------------+ : :
+ : | : : | 5 | | : :
+ v +------+------------+-----+ +------------------------------------+ : :
+ 6 | | : :
+ +------------------------------------+ : :
+ 7 | | : :
+ +====================================+ v :
+ :
diff --git a/doc/ffplay.texi b/doc/ffplay.texi
new file mode 100644
index 0000000000..1ee3c30469
--- /dev/null
+++ b/doc/ffplay.texi
@@ -0,0 +1,302 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle ffplay Documentation
+@titlepage
+@center @titlefont{ffplay Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Synopsis
+
+ffplay [@var{options}] [@file{input_file}]
+
+@chapter Description
+@c man begin DESCRIPTION
+
+FFplay is a very simple and portable media player using the FFmpeg
+libraries and the SDL library. It is mostly used as a testbed for the
+various FFmpeg APIs.
+@c man end
+
+@chapter Options
+@c man begin OPTIONS
+
+@include fftools-common-opts.texi
+
+@section Main options
+
+@table @option
+@item -x @var{width}
+Force displayed width.
+@item -y @var{height}
+Force displayed height.
+@item -s @var{size}
+Set frame size (WxH or abbreviation), needed for videos which do
+not contain a header with the frame size like raw YUV. This option
+has been deprecated in favor of private options, try -video_size.
+@item -fs
+Start in fullscreen mode.
+@item -an
+Disable audio.
+@item -vn
+Disable video.
+@item -sn
+Disable subtitles.
+@item -ss @var{pos}
+Seek to a given position in seconds.
+@item -t @var{duration}
+play <duration> seconds of audio/video
+@item -bytes
+Seek by bytes.
+@item -nodisp
+Disable graphical display.
+@item -f @var{fmt}
+Force format.
+@item -window_title @var{title}
+Set window title (default is the input filename).
+@item -loop @var{number}
+Loops movie playback <number> times. 0 means forever.
+@item -showmode @var{mode}
+Set the show mode to use.
+Available values for @var{mode} are:
+@table @samp
+@item 0, video
+show video
+@item 1, waves
+show audio waves
+@item 2, rdft
+show audio frequency band using RDFT ((Inverse) Real Discrete Fourier Transform)
+@end table
+
+Default value is "video", if video is not present or cannot be played
+"rdft" is automatically selected.
+
+You can interactively cycle through the available show modes by
+pressing the key @key{w}.
+
+@item -vf @var{filtergraph}
+Create the filtergraph specified by @var{filtergraph} and use it to
+filter the video stream.
+
+@var{filtergraph} is a description of the filtergraph to apply to
+the stream, and must have a single video input and a single video
+output. In the filtergraph, the input is associated to the label
+@code{in}, and the output to the label @code{out}. See the
+ffmpeg-filters manual for more information about the filtergraph
+syntax.
+
+You can specify this parameter multiple times and cycle through the specified
+filtergraphs along with the show modes by pressing the key @key{w}.
+
+@item -af @var{filtergraph}
+@var{filtergraph} is a description of the filtergraph to apply to
+the input audio.
+Use the option "-filters" to show all the available filters (including
+sources and sinks).
+
+@item -i @var{input_file}
+Read @var{input_file}.
+@end table
+
+@section Advanced options
+@table @option
+@item -pix_fmt @var{format}
+Set pixel format.
+This option has been deprecated in favor of private options, try -pixel_format.
+
+@item -stats
+Print several playback statistics, in particular show the stream
+duration, the codec parameters, the current position in the stream and
+the audio/video synchronisation drift. It is on by default, to
+explicitly disable it you need to specify @code{-nostats}.
+
+@item -fast
+Non-spec-compliant optimizations.
+@item -genpts
+Generate pts.
+@item -sync @var{type}
+Set the master clock to audio (@code{type=audio}), video
+(@code{type=video}) or external (@code{type=ext}). Default is audio. The
+master clock is used to control audio-video synchronization. Most media
+players use audio as master clock, but in some cases (streaming or high
+quality broadcast) it is necessary to change that. This option is mainly
+used for debugging purposes.
+@item -ast @var{audio_stream_specifier}
+Select the desired audio stream using the given stream specifier. The stream
+specifiers are described in the @ref{Stream specifiers} chapter. If this option
+is not specified, the "best" audio stream is selected in the program of the
+already selected video stream.
+@item -vst @var{video_stream_specifier}
+Select the desired video stream using the given stream specifier. The stream
+specifiers are described in the @ref{Stream specifiers} chapter. If this option
+is not specified, the "best" video stream is selected.
+@item -sst @var{subtitle_stream_specifier}
+Select the desired subtitle stream using the given stream specifier. The stream
+specifiers are described in the @ref{Stream specifiers} chapter. If this option
+is not specified, the "best" subtitle stream is selected in the program of the
+already selected video or audio stream.
+@item -autoexit
+Exit when video is done playing.
+@item -exitonkeydown
+Exit if any key is pressed.
+@item -exitonmousedown
+Exit if any mouse button is pressed.
+
+@item -codec:@var{media_specifier} @var{codec_name}
+Force a specific decoder implementation for the stream identified by
+@var{media_specifier}, which can assume the values @code{a} (audio),
+@code{v} (video), and @code{s} subtitle.
+
+@item -acodec @var{codec_name}
+Force a specific audio decoder.
+
+@item -vcodec @var{codec_name}
+Force a specific video decoder.
+
+@item -scodec @var{codec_name}
+Force a specific subtitle decoder.
+
+@item -autorotate
+Automatically rotate the video according to file metadata. Enabled by
+default, use @option{-noautorotate} to disable it.
+
+@item -framedrop
+Drop video frames if video is out of sync. Enabled by default if the master
+clock is not set to video. Use this option to enable frame dropping for all
+master clock sources, use @option{-noframedrop} to disable it.
+
+@item -infbuf
+Do not limit the input buffer size, read as much data as possible from the
+input as soon as possible. Enabled by default for realtime streams, where data
+may be dropped if not read in time. Use this option to enable infinite buffers
+for all inputs, use @option{-noinfbuf} to disable it.
+
+@end table
+
+@section While playing
+
+@table @key
+@item q, ESC
+Quit.
+
+@item f
+Toggle full screen.
+
+@item p, SPC
+Pause.
+
+@item a
+Cycle audio channel in the current program.
+
+@item v
+Cycle video channel.
+
+@item t
+Cycle subtitle channel in the current program.
+
+@item c
+Cycle program.
+
+@item w
+Cycle video filters or show modes.
+
+@item s
+Step to the next frame.
+
+Pause if the stream is not already paused, step to the next video
+frame, and pause.
+
+@item left/right
+Seek backward/forward 10 seconds.
+
+@item down/up
+Seek backward/forward 1 minute.
+
+@item page down/page up
+Seek to the previous/next chapter.
+or if there are no chapters
+Seek backward/forward 10 minutes.
+
+@item mouse click
+Seek to percentage in file corresponding to fraction of width.
+
+@end table
+
+@c man end
+
+@include config.texi
+@ifset config-all
+@set config-readonly
+@ifset config-avutil
+@include utils.texi
+@end ifset
+@ifset config-avcodec
+@include codecs.texi
+@include bitstream_filters.texi
+@end ifset
+@ifset config-avformat
+@include formats.texi
+@include protocols.texi
+@end ifset
+@ifset config-avdevice
+@include devices.texi
+@end ifset
+@ifset config-swresample
+@include resampler.texi
+@end ifset
+@ifset config-swscale
+@include scaler.texi
+@end ifset
+@ifset config-avfilter
+@include filters.texi
+@end ifset
+@end ifset
+
+@chapter See Also
+
+@ifhtml
+@ifset config-all
+@url{ffplay.html,ffplay},
+@end ifset
+@ifset config-not-all
+@url{ffplay-all.html,ffmpeg-all},
+@end ifset
+@url{ffmpeg.html,ffmpeg}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-utils.html,ffmpeg-utils},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{ffmpeg-codecs.html,ffmpeg-codecs},
+@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters},
+@url{ffmpeg-formats.html,ffmpeg-formats},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{ffmpeg-filters.html,ffmpeg-filters}
+@end ifhtml
+
+@ifnothtml
+@ifset config-all
+ffplay(1),
+@end ifset
+@ifset config-not-all
+ffplay-all(1),
+@end ifset
+ffmpeg(1), ffprobe(1), ffserver(1),
+ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1),
+ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffplay
+@settitle FFplay media player
+
+@end ignore
+
+@bye
diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
new file mode 100644
index 0000000000..2024eed4e5
--- /dev/null
+++ b/doc/ffprobe.texi
@@ -0,0 +1,683 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle ffprobe Documentation
+@titlepage
+@center @titlefont{ffprobe Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Synopsis
+
+ffprobe [@var{options}] [@file{input_file}]
+
+@chapter Description
+@c man begin DESCRIPTION
+
+ffprobe gathers information from multimedia streams and prints it in
+human- and machine-readable fashion.
+
+For example it can be used to check the format of the container used
+by a multimedia stream and the format and type of each media stream
+contained in it.
+
+If a filename is specified in input, ffprobe will try to open and
+probe the file content. If the file cannot be opened or recognized as
+a multimedia file, a positive exit code is returned.
+
+ffprobe may be employed both as a standalone application or in
+combination with a textual filter, which may perform more
+sophisticated processing, e.g. statistical processing or plotting.
+
+Options are used to list some of the formats supported by ffprobe or
+for specifying which information to display, and for setting how
+ffprobe will show it.
+
+ffprobe output is designed to be easily parsable by a textual filter,
+and consists of one or more sections of a form defined by the selected
+writer, which is specified by the @option{print_format} option.
+
+Sections may contain other nested sections, and are identified by a
+name (which may be shared by other sections), and an unique
+name. See the output of @option{sections}.
+
+Metadata tags stored in the container or in the streams are recognized
+and printed in the corresponding "FORMAT", "STREAM" or "PROGRAM_STREAM"
+section.
+
+@c man end
+
+@chapter Options
+@c man begin OPTIONS
+
+@include fftools-common-opts.texi
+
+@section Main options
+
+@table @option
+
+@item -f @var{format}
+Force format to use.
+
+@item -unit
+Show the unit of the displayed values.
+
+@item -prefix
+Use SI prefixes for the displayed values.
+Unless the "-byte_binary_prefix" option is used all the prefixes
+are decimal.
+
+@item -byte_binary_prefix
+Force the use of binary prefixes for byte values.
+
+@item -sexagesimal
+Use sexagesimal format HH:MM:SS.MICROSECONDS for time values.
+
+@item -pretty
+Prettify the format of the displayed values, it corresponds to the
+options "-unit -prefix -byte_binary_prefix -sexagesimal".
+
+@item -of, -print_format @var{writer_name}[=@var{writer_options}]
+Set the output printing format.
+
+@var{writer_name} specifies the name of the writer, and
+@var{writer_options} specifies the options to be passed to the writer.
+
+For example for printing the output in JSON format, specify:
+@example
+-print_format json
+@end example
+
+For more details on the available output printing formats, see the
+Writers section below.
+
+@item -sections
+Print sections structure and section information, and exit. The output
+is not meant to be parsed by a machine.
+
+@item -select_streams @var{stream_specifier}
+Select only the streams specified by @var{stream_specifier}. This
+option affects only the options related to streams
+(e.g. @code{show_streams}, @code{show_packets}, etc.).
+
+For example to show only audio streams, you can use the command:
+@example
+ffprobe -show_streams -select_streams a INPUT
+@end example
+
+To show only video packets belonging to the video stream with index 1:
+@example
+ffprobe -show_packets -select_streams v:1 INPUT
+@end example
+
+@item -show_data
+Show payload data, as a hexadecimal and ASCII dump. Coupled with
+@option{-show_packets}, it will dump the packets' data. Coupled with
+@option{-show_streams}, it will dump the codec extradata.
+
+The dump is printed as the "data" field. It may contain newlines.
+
+@item -show_data_hash @var{algorithm}
+Show a hash of payload data, for packets with @option{-show_packets} and for
+codec extradata with @option{-show_streams}.
+
+@item -show_error
+Show information about the error found when trying to probe the input.
+
+The error information is printed within a section with name "ERROR".
+
+@item -show_format
+Show information about the container format of the input multimedia
+stream.
+
+All the container format information is printed within a section with
+name "FORMAT".
+
+@item -show_format_entry @var{name}
+Like @option{-show_format}, but only prints the specified entry of the
+container format information, rather than all. This option may be given more
+than once, then all specified entries will be shown.
+
+This option is deprecated, use @code{show_entries} instead.
+
+@item -show_entries @var{section_entries}
+Set list of entries to show.
+
+Entries are specified according to the following
+syntax. @var{section_entries} contains a list of section entries
+separated by @code{:}. Each section entry is composed by a section
+name (or unique name), optionally followed by a list of entries local
+to that section, separated by @code{,}.
+
+If section name is specified but is followed by no @code{=}, all
+entries are printed to output, together with all the contained
+sections. Otherwise only the entries specified in the local section
+entries list are printed. In particular, if @code{=} is specified but
+the list of local entries is empty, then no entries will be shown for
+that section.
+
+Note that the order of specification of the local section entries is
+not honored in the output, and the usual display order will be
+retained.
+
+The formal syntax is given by:
+@example
+@var{LOCAL_SECTION_ENTRIES} ::= @var{SECTION_ENTRY_NAME}[,@var{LOCAL_SECTION_ENTRIES}]
+@var{SECTION_ENTRY} ::= @var{SECTION_NAME}[=[@var{LOCAL_SECTION_ENTRIES}]]
+@var{SECTION_ENTRIES} ::= @var{SECTION_ENTRY}[:@var{SECTION_ENTRIES}]
+@end example
+
+For example, to show only the index and type of each stream, and the PTS
+time, duration time, and stream index of the packets, you can specify
+the argument:
+@example
+packet=pts_time,duration_time,stream_index : stream=index,codec_type
+@end example
+
+To show all the entries in the section "format", but only the codec
+type in the section "stream", specify the argument:
+@example
+format : stream=codec_type
+@end example
+
+To show all the tags in the stream and format sections:
+@example
+stream_tags : format_tags
+@end example
+
+To show only the @code{title} tag (if available) in the stream
+sections:
+@example
+stream_tags=title
+@end example
+
+@item -show_packets
+Show information about each packet contained in the input multimedia
+stream.
+
+The information for each single packet is printed within a dedicated
+section with name "PACKET".
+
+@item -show_frames
+Show information about each frame and subtitle contained in the input
+multimedia stream.
+
+The information for each single frame is printed within a dedicated
+section with name "FRAME" or "SUBTITLE".
+
+@item -show_streams
+Show information about each media stream contained in the input
+multimedia stream.
+
+Each media stream information is printed within a dedicated section
+with name "STREAM".
+
+@item -show_programs
+Show information about programs and their streams contained in the input
+multimedia stream.
+
+Each media stream information is printed within a dedicated section
+with name "PROGRAM_STREAM".
+
+@item -show_chapters
+Show information about chapters stored in the format.
+
+Each chapter is printed within a dedicated section with name "CHAPTER".
+
+@item -count_frames
+Count the number of frames per stream and report it in the
+corresponding stream section.
+
+@item -count_packets
+Count the number of packets per stream and report it in the
+corresponding stream section.
+
+@item -read_intervals @var{read_intervals}
+
+Read only the specified intervals. @var{read_intervals} must be a
+sequence of interval specifications separated by ",".
+@command{ffprobe} will seek to the interval starting point, and will
+continue reading from that.
+
+Each interval is specified by two optional parts, separated by "%".
+
+The first part specifies the interval start position. It is
+interpreted as an abolute position, or as a relative offset from the
+current position if it is preceded by the "+" character. If this first
+part is not specified, no seeking will be performed when reading this
+interval.
+
+The second part specifies the interval end position. It is interpreted
+as an absolute position, or as a relative offset from the current
+position if it is preceded by the "+" character. If the offset
+specification starts with "#", it is interpreted as the number of
+packets to read (not including the flushing packets) from the interval
+start. If no second part is specified, the program will read until the
+end of the input.
+
+Note that seeking is not accurate, thus the actual interval start
+point may be different from the specified position. Also, when an
+interval duration is specified, the absolute end time will be computed
+by adding the duration to the interval start point found by seeking
+the file, rather than to the specified start value.
+
+The formal syntax is given by:
+@example
+@var{INTERVAL} ::= [@var{START}|+@var{START_OFFSET}][%[@var{END}|+@var{END_OFFSET}]]
+@var{INTERVALS} ::= @var{INTERVAL}[,@var{INTERVALS}]
+@end example
+
+A few examples follow.
+@itemize
+@item
+Seek to time 10, read packets until 20 seconds after the found seek
+point, then seek to position @code{01:30} (1 minute and thirty
+seconds) and read packets until position @code{01:45}.
+@example
+10%+20,01:30%01:45
+@end example
+
+@item
+Read only 42 packets after seeking to position @code{01:23}:
+@example
+01:23%+#42
+@end example
+
+@item
+Read only the first 20 seconds from the start:
+@example
+%+20
+@end example
+
+@item
+Read from the start until position @code{02:30}:
+@example
+%02:30
+@end example
+@end itemize
+
+@item -show_private_data, -private
+Show private data, that is data depending on the format of the
+particular shown element.
+This option is enabled by default, but you may need to disable it
+for specific uses, for example when creating XSD-compliant XML output.
+
+@item -show_program_version
+Show information related to program version.
+
+Version information is printed within a section with name
+"PROGRAM_VERSION".
+
+@item -show_library_versions
+Show information related to library versions.
+
+Version information for each library is printed within a section with
+name "LIBRARY_VERSION".
+
+@item -show_versions
+Show information related to program and library versions. This is the
+equivalent of setting both @option{-show_program_version} and
+@option{-show_library_versions} options.
+
+@item -show_pixel_formats
+Show information about all pixel formats supported by FFmpeg.
+
+Pixel format information for each format is printed within a section
+with name "PIXEL_FORMAT".
+
+@item -bitexact
+Force bitexact output, useful to produce output which is not dependent
+on the specific build.
+
+@item -i @var{input_file}
+Read @var{input_file}.
+
+@end table
+@c man end
+
+@chapter Writers
+@c man begin WRITERS
+
+A writer defines the output format adopted by @command{ffprobe}, and will be
+used for printing all the parts of the output.
+
+A writer may accept one or more arguments, which specify the options
+to adopt. The options are specified as a list of @var{key}=@var{value}
+pairs, separated by ":".
+
+All writers support the following options:
+
+@table @option
+@item string_validation, sv
+Set string validation mode.
+
+The following values are accepted.
+@table @samp
+@item fail
+The writer will fail immediately in case an invalid string (UTF-8)
+sequence or code point is found in the input. This is especially
+useful to validate input metadata.
+
+@item ignore
+Any validation error will be ignored. This will result in possibly
+broken output, especially with the json or xml writer.
+
+@item replace
+The writer will substitute invalid UTF-8 sequences or code points with
+the string specified with the @option{string_validation_replacement}.
+@end table
+
+Default value is @samp{replace}.
+
+@item string_validation_replacement, svr
+Set replacement string to use in case @option{string_validation} is
+set to @samp{replace}.
+
+In case the option is not specified, the writer will assume the empty
+string, that is it will remove the invalid sequences from the input
+strings.
+@end table
+
+A description of the currently available writers follows.
+
+@section default
+Default format.
+
+Print each section in the form:
+@example
+[SECTION]
+key1=val1
+...
+keyN=valN
+[/SECTION]
+@end example
+
+Metadata tags are printed as a line in the corresponding FORMAT, STREAM or
+PROGRAM_STREAM section, and are prefixed by the string "TAG:".
+
+A description of the accepted options follows.
+
+@table @option
+
+@item nokey, nk
+If set to 1 specify not to print the key of each field. Default value
+is 0.
+
+@item noprint_wrappers, nw
+If set to 1 specify not to print the section header and footer.
+Default value is 0.
+@end table
+
+@section compact, csv
+Compact and CSV format.
+
+The @code{csv} writer is equivalent to @code{compact}, but supports
+different defaults.
+
+Each section is printed on a single line.
+If no option is specifid, the output has the form:
+@example
+section|key1=val1| ... |keyN=valN
+@end example
+
+Metadata tags are printed in the corresponding "format" or "stream"
+section. A metadata tag key, if printed, is prefixed by the string
+"tag:".
+
+The description of the accepted options follows.
+
+@table @option
+
+@item item_sep, s
+Specify the character to use for separating fields in the output line.
+It must be a single printable character, it is "|" by default ("," for
+the @code{csv} writer).
+
+@item nokey, nk
+If set to 1 specify not to print the key of each field. Its default
+value is 0 (1 for the @code{csv} writer).
+
+@item escape, e
+Set the escape mode to use, default to "c" ("csv" for the @code{csv}
+writer).
+
+It can assume one of the following values:
+@table @option
+@item c
+Perform C-like escaping. Strings containing a newline (@samp{\n}), carriage
+return (@samp{\r}), a tab (@samp{\t}), a form feed (@samp{\f}), the escaping
+character (@samp{\}) or the item separator character @var{SEP} are escaped
+using C-like fashioned escaping, so that a newline is converted to the
+sequence @samp{\n}, a carriage return to @samp{\r}, @samp{\} to @samp{\\} and
+the separator @var{SEP} is converted to @samp{\@var{SEP}}.
+
+@item csv
+Perform CSV-like escaping, as described in RFC4180. Strings
+containing a newline (@samp{\n}), a carriage return (@samp{\r}), a double quote
+(@samp{"}), or @var{SEP} are enclosed in double-quotes.
+
+@item none
+Perform no escaping.
+@end table
+
+@item print_section, p
+Print the section name at the begin of each line if the value is
+@code{1}, disable it with value set to @code{0}. Default value is
+@code{1}.
+
+@end table
+
+@section flat
+Flat format.
+
+A free-form output where each line contains an explicit key=value, such as
+"streams.stream.3.tags.foo=bar". The output is shell escaped, so it can be
+directly embedded in sh scripts as long as the separator character is an
+alphanumeric character or an underscore (see @var{sep_char} option).
+
+The description of the accepted options follows.
+
+@table @option
+@item sep_char, s
+Separator character used to separate the chapter, the section name, IDs and
+potential tags in the printed field key.
+
+Default value is @samp{.}.
+
+@item hierarchical, h
+Specify if the section name specification should be hierarchical. If
+set to 1, and if there is more than one section in the current
+chapter, the section name will be prefixed by the name of the
+chapter. A value of 0 will disable this behavior.
+
+Default value is 1.
+@end table
+
+@section ini
+INI format output.
+
+Print output in an INI based format.
+
+The following conventions are adopted:
+
+@itemize
+@item
+all key and values are UTF-8
+@item
+@samp{.} is the subgroup separator
+@item
+newline, @samp{\t}, @samp{\f}, @samp{\b} and the following characters are
+escaped
+@item
+@samp{\} is the escape character
+@item
+@samp{#} is the comment indicator
+@item
+@samp{=} is the key/value separator
+@item
+@samp{:} is not used but usually parsed as key/value separator
+@end itemize
+
+This writer accepts options as a list of @var{key}=@var{value} pairs,
+separated by @samp{:}.
+
+The description of the accepted options follows.
+
+@table @option
+@item hierarchical, h
+Specify if the section name specification should be hierarchical. If
+set to 1, and if there is more than one section in the current
+chapter, the section name will be prefixed by the name of the
+chapter. A value of 0 will disable this behavior.
+
+Default value is 1.
+@end table
+
+@section json
+JSON based format.
+
+Each section is printed using JSON notation.
+
+The description of the accepted options follows.
+
+@table @option
+
+@item compact, c
+If set to 1 enable compact output, that is each section will be
+printed on a single line. Default value is 0.
+@end table
+
+For more information about JSON, see @url{http://www.json.org/}.
+
+@section xml
+XML based format.
+
+The XML output is described in the XML schema description file
+@file{ffprobe.xsd} installed in the FFmpeg datadir.
+
+An updated version of the schema can be retrieved at the url
+@url{http://www.ffmpeg.org/schema/ffprobe.xsd}, which redirects to the
+latest schema committed into the FFmpeg development source code tree.
+
+Note that the output issued will be compliant to the
+@file{ffprobe.xsd} schema only when no special global output options
+(@option{unit}, @option{prefix}, @option{byte_binary_prefix},
+@option{sexagesimal} etc.) are specified.
+
+The description of the accepted options follows.
+
+@table @option
+
+@item fully_qualified, q
+If set to 1 specify if the output should be fully qualified. Default
+value is 0.
+This is required for generating an XML file which can be validated
+through an XSD file.
+
+@item xsd_compliant, x
+If set to 1 perform more checks for ensuring that the output is XSD
+compliant. Default value is 0.
+This option automatically sets @option{fully_qualified} to 1.
+@end table
+
+For more information about the XML format, see
+@url{http://www.w3.org/XML/}.
+@c man end WRITERS
+
+@chapter Timecode
+@c man begin TIMECODE
+
+@command{ffprobe} supports Timecode extraction:
+
+@itemize
+
+@item
+MPEG1/2 timecode is extracted from the GOP, and is available in the video
+stream details (@option{-show_streams}, see @var{timecode}).
+
+@item
+MOV timecode is extracted from tmcd track, so is available in the tmcd
+stream metadata (@option{-show_streams}, see @var{TAG:timecode}).
+
+@item
+DV, GXF and AVI timecodes are available in format metadata
+(@option{-show_format}, see @var{TAG:timecode}).
+
+@end itemize
+@c man end TIMECODE
+
+@include config.texi
+@ifset config-all
+@set config-readonly
+@ifset config-avutil
+@include utils.texi
+@end ifset
+@ifset config-avcodec
+@include codecs.texi
+@include bitstream_filters.texi
+@end ifset
+@ifset config-avformat
+@include formats.texi
+@include protocols.texi
+@end ifset
+@ifset config-avdevice
+@include devices.texi
+@end ifset
+@ifset config-swresample
+@include resampler.texi
+@end ifset
+@ifset config-swscale
+@include scaler.texi
+@end ifset
+@ifset config-avfilter
+@include filters.texi
+@end ifset
+@end ifset
+
+@chapter See Also
+
+@ifhtml
+@ifset config-all
+@url{ffprobe.html,ffprobe},
+@end ifset
+@ifset config-not-all
+@url{ffprobe-all.html,ffprobe-all},
+@end ifset
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffserver.html,ffserver},
+@url{ffmpeg-utils.html,ffmpeg-utils},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{ffmpeg-codecs.html,ffmpeg-codecs},
+@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters},
+@url{ffmpeg-formats.html,ffmpeg-formats},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{ffmpeg-filters.html,ffmpeg-filters}
+@end ifhtml
+
+@ifnothtml
+@ifset config-all
+ffprobe(1),
+@end ifset
+@ifset config-not-all
+ffprobe-all(1),
+@end ifset
+ffmpeg(1), ffplay(1), ffserver(1),
+ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1),
+ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffprobe
+@settitle ffprobe media prober
+
+@end ignore
+
+@bye
diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd
new file mode 100644
index 0000000000..1481ad9eb0
--- /dev/null
+++ b/doc/ffprobe.xsd
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://www.ffmpeg.org/schema/ffprobe"
+ xmlns:ffprobe="http://www.ffmpeg.org/schema/ffprobe">
+
+ <xsd:element name="ffprobe" type="ffprobe:ffprobeType"/>
+
+ <xsd:complexType name="ffprobeType">
+ <xsd:sequence>
+ <xsd:element name="program_version" type="ffprobe:programVersionType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="library_versions" type="ffprobe:libraryVersionsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="pixel_formats" type="ffprobe:pixelFormatsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="packets" type="ffprobe:packetsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="frames" type="ffprobe:framesType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="packets_and_frames" type="ffprobe:packetsAndFramesType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="programs" type="ffprobe:programsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="streams" type="ffprobe:streamsType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="chapters" type="ffprobe:chaptersType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="format" type="ffprobe:formatType" minOccurs="0" maxOccurs="1" />
+ <xsd:element name="error" type="ffprobe:errorType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="packetsType">
+ <xsd:sequence>
+ <xsd:element name="packet" type="ffprobe:packetType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="framesType">
+ <xsd:sequence>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="subtitle" type="ffprobe:subtitleType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="packetsAndFramesType">
+ <xsd:sequence>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="packet" type="ffprobe:packetType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="subtitle" type="ffprobe:subtitleType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="packetType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="side_data_list" type="ffprobe:packetSideDataListType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+
+ <xsd:attribute name="codec_type" type="xsd:string" use="required" />
+ <xsd:attribute name="stream_index" type="xsd:int" use="required" />
+ <xsd:attribute name="pts" type="xsd:long" />
+ <xsd:attribute name="pts_time" type="xsd:float" />
+ <xsd:attribute name="dts" type="xsd:long" />
+ <xsd:attribute name="dts_time" type="xsd:float" />
+ <xsd:attribute name="duration" type="xsd:long" />
+ <xsd:attribute name="duration_time" type="xsd:float" />
+ <xsd:attribute name="convergence_duration" type="xsd:long" />
+ <xsd:attribute name="convergence_duration_time" type="xsd:float" />
+ <xsd:attribute name="size" type="xsd:long" use="required" />
+ <xsd:attribute name="pos" type="xsd:long" />
+ <xsd:attribute name="flags" type="xsd:string" use="required" />
+ <xsd:attribute name="data" type="xsd:string" />
+ <xsd:attribute name="data_hash" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="packetSideDataListType">
+ <xsd:sequence>
+ <xsd:element name="side_data" type="ffprobe:packetSideDataType" minOccurs="1" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="packetSideDataType">
+ <xsd:attribute name="side_data_type" type="xsd:string"/>
+ <xsd:attribute name="side_data_size" type="xsd:int" />
+ </xsd:complexType>
+
+ <xsd:complexType name="frameType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="side_data_list" type="ffprobe:frameSideDataListType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+
+ <xsd:attribute name="media_type" type="xsd:string" use="required"/>
+ <xsd:attribute name="key_frame" type="xsd:int" use="required"/>
+ <xsd:attribute name="pts" type="xsd:long" />
+ <xsd:attribute name="pts_time" type="xsd:float"/>
+ <xsd:attribute name="pkt_pts" type="xsd:long" />
+ <xsd:attribute name="pkt_pts_time" type="xsd:float"/>
+ <xsd:attribute name="pkt_dts" type="xsd:long" />
+ <xsd:attribute name="pkt_dts_time" type="xsd:float"/>
+ <xsd:attribute name="best_effort_timestamp" type="xsd:long" />
+ <xsd:attribute name="best_effort_timestamp_time" type="xsd:float" />
+ <xsd:attribute name="pkt_duration" type="xsd:long" />
+ <xsd:attribute name="pkt_duration_time" type="xsd:float"/>
+ <xsd:attribute name="pkt_pos" type="xsd:long" />
+ <xsd:attribute name="pkt_size" type="xsd:int" />
+
+ <!-- audio attributes -->
+ <xsd:attribute name="sample_fmt" type="xsd:string"/>
+ <xsd:attribute name="nb_samples" type="xsd:long" />
+ <xsd:attribute name="channels" type="xsd:int" />
+ <xsd:attribute name="channel_layout" type="xsd:string"/>
+
+ <!-- video attributes -->
+ <xsd:attribute name="width" type="xsd:long" />
+ <xsd:attribute name="height" type="xsd:long" />
+ <xsd:attribute name="pix_fmt" type="xsd:string"/>
+ <xsd:attribute name="sample_aspect_ratio" type="xsd:string"/>
+ <xsd:attribute name="pict_type" type="xsd:string"/>
+ <xsd:attribute name="coded_picture_number" type="xsd:long" />
+ <xsd:attribute name="display_picture_number" type="xsd:long" />
+ <xsd:attribute name="interlaced_frame" type="xsd:int" />
+ <xsd:attribute name="top_field_first" type="xsd:int" />
+ <xsd:attribute name="repeat_pict" type="xsd:int" />
+ </xsd:complexType>
+
+ <xsd:complexType name="frameSideDataListType">
+ <xsd:sequence>
+ <xsd:element name="side_data" type="ffprobe:frameSideDataType" minOccurs="1" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ <xsd:complexType name="frameSideDataType">
+ <xsd:attribute name="side_data_type" type="xsd:string"/>
+ <xsd:attribute name="side_data_size" type="xsd:int" />
+ </xsd:complexType>
+
+ <xsd:complexType name="subtitleType">
+ <xsd:attribute name="media_type" type="xsd:string" fixed="subtitle" use="required"/>
+ <xsd:attribute name="pts" type="xsd:long" />
+ <xsd:attribute name="pts_time" type="xsd:float"/>
+ <xsd:attribute name="format" type="xsd:int" />
+ <xsd:attribute name="start_display_time" type="xsd:int" />
+ <xsd:attribute name="end_display_time" type="xsd:int" />
+ <xsd:attribute name="num_rects" type="xsd:int" />
+ </xsd:complexType>
+
+ <xsd:complexType name="streamsType">
+ <xsd:sequence>
+ <xsd:element name="stream" type="ffprobe:streamType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="programsType">
+ <xsd:sequence>
+ <xsd:element name="program" type="ffprobe:programType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="streamDispositionType">
+ <xsd:attribute name="default" type="xsd:int" use="required" />
+ <xsd:attribute name="dub" type="xsd:int" use="required" />
+ <xsd:attribute name="original" type="xsd:int" use="required" />
+ <xsd:attribute name="comment" type="xsd:int" use="required" />
+ <xsd:attribute name="lyrics" type="xsd:int" use="required" />
+ <xsd:attribute name="karaoke" type="xsd:int" use="required" />
+ <xsd:attribute name="forced" type="xsd:int" use="required" />
+ <xsd:attribute name="hearing_impaired" type="xsd:int" use="required" />
+ <xsd:attribute name="visual_impaired" type="xsd:int" use="required" />
+ <xsd:attribute name="clean_effects" type="xsd:int" use="required" />
+ <xsd:attribute name="attached_pic" type="xsd:int" use="required" />
+ </xsd:complexType>
+
+ <xsd:complexType name="streamType">
+ <xsd:sequence>
+ <xsd:element name="disposition" type="ffprobe:streamDispositionType" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="side_data_list" type="ffprobe:packetSideDataListType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+
+ <xsd:attribute name="index" type="xsd:int" use="required"/>
+ <xsd:attribute name="codec_name" type="xsd:string" />
+ <xsd:attribute name="codec_long_name" type="xsd:string" />
+ <xsd:attribute name="profile" type="xsd:string" />
+ <xsd:attribute name="codec_type" type="xsd:string" />
+ <xsd:attribute name="codec_time_base" type="xsd:string" use="required"/>
+ <xsd:attribute name="codec_tag" type="xsd:string" use="required"/>
+ <xsd:attribute name="codec_tag_string" type="xsd:string" use="required"/>
+ <xsd:attribute name="extradata" type="xsd:string" />
+ <xsd:attribute name="extradata_hash" type="xsd:string" />
+
+ <!-- video attributes -->
+ <xsd:attribute name="width" type="xsd:int"/>
+ <xsd:attribute name="height" type="xsd:int"/>
+ <xsd:attribute name="coded_width" type="xsd:int"/>
+ <xsd:attribute name="coded_height" type="xsd:int"/>
+ <xsd:attribute name="has_b_frames" type="xsd:int"/>
+ <xsd:attribute name="sample_aspect_ratio" type="xsd:string"/>
+ <xsd:attribute name="display_aspect_ratio" type="xsd:string"/>
+ <xsd:attribute name="pix_fmt" type="xsd:string"/>
+ <xsd:attribute name="level" type="xsd:int"/>
+ <xsd:attribute name="color_range" type="xsd:string"/>
+ <xsd:attribute name="color_space" type="xsd:string"/>
+ <xsd:attribute name="color_transfer" type="xsd:string"/>
+ <xsd:attribute name="color_primaries" type="xsd:string"/>
+ <xsd:attribute name="chroma_location" type="xsd:string"/>
+ <xsd:attribute name="timecode" type="xsd:string"/>
+ <xsd:attribute name="refs" type="xsd:int"/>
+
+ <!-- audio attributes -->
+ <xsd:attribute name="sample_fmt" type="xsd:string"/>
+ <xsd:attribute name="sample_rate" type="xsd:int"/>
+ <xsd:attribute name="channels" type="xsd:int"/>
+ <xsd:attribute name="channel_layout" type="xsd:string"/>
+ <xsd:attribute name="bits_per_sample" type="xsd:int"/>
+
+ <xsd:attribute name="id" type="xsd:string"/>
+ <xsd:attribute name="r_frame_rate" type="xsd:string" use="required"/>
+ <xsd:attribute name="avg_frame_rate" type="xsd:string" use="required"/>
+ <xsd:attribute name="time_base" type="xsd:string" use="required"/>
+ <xsd:attribute name="start_pts" type="xsd:long"/>
+ <xsd:attribute name="start_time" type="xsd:float"/>
+ <xsd:attribute name="duration_ts" type="xsd:long"/>
+ <xsd:attribute name="duration" type="xsd:float"/>
+ <xsd:attribute name="bit_rate" type="xsd:int"/>
+ <xsd:attribute name="max_bit_rate" type="xsd:int"/>
+ <xsd:attribute name="bits_per_raw_sample" type="xsd:int"/>
+ <xsd:attribute name="nb_frames" type="xsd:int"/>
+ <xsd:attribute name="nb_read_frames" type="xsd:int"/>
+ <xsd:attribute name="nb_read_packets" type="xsd:int"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="programType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="streams" type="ffprobe:streamsType" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+
+ <xsd:attribute name="program_id" type="xsd:int" use="required"/>
+ <xsd:attribute name="program_num" type="xsd:int" use="required"/>
+ <xsd:attribute name="nb_streams" type="xsd:int" use="required"/>
+ <xsd:attribute name="start_time" type="xsd:float"/>
+ <xsd:attribute name="start_pts" type="xsd:long"/>
+ <xsd:attribute name="end_time" type="xsd:float"/>
+ <xsd:attribute name="end_pts" type="xsd:long"/>
+ <xsd:attribute name="pmt_pid" type="xsd:int" use="required"/>
+ <xsd:attribute name="pcr_pid" type="xsd:int" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="formatType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+
+ <xsd:attribute name="filename" type="xsd:string" use="required"/>
+ <xsd:attribute name="nb_streams" type="xsd:int" use="required"/>
+ <xsd:attribute name="nb_programs" type="xsd:int" use="required"/>
+ <xsd:attribute name="format_name" type="xsd:string" use="required"/>
+ <xsd:attribute name="format_long_name" type="xsd:string"/>
+ <xsd:attribute name="start_time" type="xsd:float"/>
+ <xsd:attribute name="duration" type="xsd:float"/>
+ <xsd:attribute name="size" type="xsd:long"/>
+ <xsd:attribute name="bit_rate" type="xsd:long"/>
+ <xsd:attribute name="probe_score" type="xsd:int"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="tagType">
+ <xsd:attribute name="key" type="xsd:string" use="required"/>
+ <xsd:attribute name="value" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="errorType">
+ <xsd:attribute name="code" type="xsd:int" use="required"/>
+ <xsd:attribute name="string" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="programVersionType">
+ <xsd:attribute name="version" type="xsd:string" use="required"/>
+ <xsd:attribute name="copyright" type="xsd:string" use="required"/>
+ <xsd:attribute name="build_date" type="xsd:string"/>
+ <xsd:attribute name="build_time" type="xsd:string"/>
+ <xsd:attribute name="compiler_ident" type="xsd:string" use="required"/>
+ <xsd:attribute name="configuration" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="chaptersType">
+ <xsd:sequence>
+ <xsd:element name="chapter" type="ffprobe:chapterType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="chapterType">
+ <xsd:sequence>
+ <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+
+ <xsd:attribute name="id" type="xsd:int" use="required"/>
+ <xsd:attribute name="time_base" type="xsd:string" use="required"/>
+ <xsd:attribute name="start" type="xsd:int" use="required"/>
+ <xsd:attribute name="start_time" type="xsd:float"/>
+ <xsd:attribute name="end" type="xsd:int" use="required"/>
+ <xsd:attribute name="end_time" type="xsd:float" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="libraryVersionType">
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ <xsd:attribute name="major" type="xsd:int" use="required"/>
+ <xsd:attribute name="minor" type="xsd:int" use="required"/>
+ <xsd:attribute name="micro" type="xsd:int" use="required"/>
+ <xsd:attribute name="version" type="xsd:int" use="required"/>
+ <xsd:attribute name="ident" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="libraryVersionsType">
+ <xsd:sequence>
+ <xsd:element name="library_version" type="ffprobe:libraryVersionType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="pixelFormatFlagsType">
+ <xsd:attribute name="big_endian" type="xsd:int" use="required"/>
+ <xsd:attribute name="palette" type="xsd:int" use="required"/>
+ <xsd:attribute name="bitstream" type="xsd:int" use="required"/>
+ <xsd:attribute name="hwaccel" type="xsd:int" use="required"/>
+ <xsd:attribute name="planar" type="xsd:int" use="required"/>
+ <xsd:attribute name="rgb" type="xsd:int" use="required"/>
+ <xsd:attribute name="pseudopal" type="xsd:int" use="required"/>
+ <xsd:attribute name="alpha" type="xsd:int" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="pixelFormatComponentType">
+ <xsd:attribute name="index" type="xsd:int" use="required"/>
+ <xsd:attribute name="bit_depth" type="xsd:int" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="pixelFormatComponentsType">
+ <xsd:sequence>
+ <xsd:element name="component" type="ffprobe:pixelFormatComponentType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="pixelFormatType">
+ <xsd:sequence>
+ <xsd:element name="flags" type="ffprobe:pixelFormatFlagsType" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="components" type="ffprobe:pixelFormatComponentsType" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ <xsd:attribute name="nb_components" type="xsd:int" use="required"/>
+ <xsd:attribute name="log2_chroma_w" type="xsd:int"/>
+ <xsd:attribute name="log2_chroma_h" type="xsd:int"/>
+ <xsd:attribute name="bits_per_pixel" type="xsd:int"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="pixelFormatsType">
+ <xsd:sequence>
+ <xsd:element name="pixel_format" type="ffprobe:pixelFormatType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+</xsd:schema>
diff --git a/doc/ffserver.conf b/doc/ffserver.conf
new file mode 100644
index 0000000000..b756961aa3
--- /dev/null
+++ b/doc/ffserver.conf
@@ -0,0 +1,371 @@
+# Port on which the server is listening. You must select a different
+# port from your standard HTTP web server if it is running on the same
+# computer.
+HTTPPort 8090
+
+# Address on which the server is bound. Only useful if you have
+# several network interfaces.
+HTTPBindAddress 0.0.0.0
+
+# Number of simultaneous HTTP connections that can be handled. It has
+# to be defined *before* the MaxClients parameter, since it defines the
+# MaxClients maximum limit.
+MaxHTTPConnections 2000
+
+# Number of simultaneous requests that can be handled. Since FFServer
+# is very fast, it is more likely that you will want to leave this high
+# and use MaxBandwidth, below.
+MaxClients 1000
+
+# This the maximum amount of kbit/sec that you are prepared to
+# consume when streaming to clients.
+MaxBandwidth 1000
+
+# Access log file (uses standard Apache log file format)
+# '-' is the standard output.
+CustomLog -
+
+##################################################################
+# Definition of the live feeds. Each live feed contains one video
+# and/or audio sequence coming from an ffmpeg encoder or another
+# ffserver. This sequence may be encoded simultaneously with several
+# codecs at several resolutions.
+
+<Feed feed1.ffm>
+
+# You must use 'ffmpeg' to send a live feed to ffserver. In this
+# example, you can type:
+#
+# ffmpeg http://localhost:8090/feed1.ffm
+
+# ffserver can also do time shifting. It means that it can stream any
+# previously recorded live stream. The request should contain:
+# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify
+# a path where the feed is stored on disk. You also specify the
+# maximum size of the feed, where zero means unlimited. Default:
+# File=/tmp/feed_name.ffm FileMaxSize=5M
+File /tmp/feed1.ffm
+FileMaxSize 200K
+
+# You could specify
+# ReadOnlyFile /saved/specialvideo.ffm
+# This marks the file as readonly and it will not be deleted or updated.
+
+# Specify launch in order to start ffmpeg automatically.
+# First ffmpeg must be defined with an appropriate path if needed,
+# after that options can follow, but avoid adding the http:// field
+#Launch ffmpeg
+
+# Only allow connections from localhost to the feed.
+ACL allow 127.0.0.1
+
+</Feed>
+
+
+##################################################################
+# Now you can define each stream which will be generated from the
+# original audio and video stream. Each format has a filename (here
+# 'test1.mpg'). FFServer will send this stream when answering a
+# request containing this filename.
+
+<Stream test1.mpg>
+
+# coming from live feed 'feed1'
+Feed feed1.ffm
+
+# Format of the stream : you can choose among:
+# mpeg : MPEG-1 multiplexed video and audio
+# mpegvideo : only MPEG-1 video
+# mp2 : MPEG-2 audio (use AudioCodec to select layer 2 and 3 codec)
+# ogg : Ogg format (Vorbis audio codec)
+# rm : RealNetworks-compatible stream. Multiplexed audio and video.
+# ra : RealNetworks-compatible stream. Audio only.
+# mpjpeg : Multipart JPEG (works with Netscape without any plugin)
+# jpeg : Generate a single JPEG image.
+# asf : ASF compatible streaming (Windows Media Player format).
+# swf : Macromedia Flash compatible stream
+# avi : AVI format (MPEG-4 video, MPEG audio sound)
+Format mpeg
+
+# Bitrate for the audio stream. Codecs usually support only a few
+# different bitrates.
+AudioBitRate 32
+
+# Number of audio channels: 1 = mono, 2 = stereo
+AudioChannels 1
+
+# Sampling frequency for audio. When using low bitrates, you should
+# lower this frequency to 22050 or 11025. The supported frequencies
+# depend on the selected audio codec.
+AudioSampleRate 44100
+
+# Bitrate for the video stream
+VideoBitRate 64
+
+# Ratecontrol buffer size
+VideoBufferSize 40
+
+# Number of frames per second
+VideoFrameRate 3
+
+# Size of the video frame: WxH (default: 160x128)
+# The following abbreviations are defined: sqcif, qcif, cif, 4cif, qqvga,
+# qvga, vga, svga, xga, uxga, qxga, sxga, qsxga, hsxga, wvga, wxga, wsxga,
+# wuxga, woxga, wqsxga, wquxga, whsxga, whuxga, cga, ega, hd480, hd720,
+# hd1080
+VideoSize 160x128
+
+# Transmit only intra frames (useful for low bitrates, but kills frame rate).
+#VideoIntraOnly
+
+# If non-intra only, an intra frame is transmitted every VideoGopSize
+# frames. Video synchronization can only begin at an intra frame.
+VideoGopSize 12
+
+# More MPEG-4 parameters
+# VideoHighQuality
+# Video4MotionVector
+
+# Choose your codecs:
+#AudioCodec mp2
+#VideoCodec mpeg1video
+
+# Suppress audio
+#NoAudio
+
+# Suppress video
+#NoVideo
+
+#VideoQMin 3
+#VideoQMax 31
+
+# Set this to the number of seconds backwards in time to start. Note that
+# most players will buffer 5-10 seconds of video, and also you need to allow
+# for a keyframe to appear in the data stream.
+#Preroll 15
+
+# ACL:
+
+# You can allow ranges of addresses (or single addresses)
+#ACL ALLOW <first address> <last address>
+
+# You can deny ranges of addresses (or single addresses)
+#ACL DENY <first address> <last address>
+
+# You can repeat the ACL allow/deny as often as you like. It is on a per
+# stream basis. The first match defines the action. If there are no matches,
+# then the default is the inverse of the last ACL statement.
+#
+# Thus 'ACL allow localhost' only allows access from localhost.
+# 'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and
+# allow everybody else.
+
+</Stream>
+
+
+##################################################################
+# Example streams
+
+
+# Multipart JPEG
+
+#<Stream test.mjpg>
+#Feed feed1.ffm
+#Format mpjpeg
+#VideoFrameRate 2
+#VideoIntraOnly
+#NoAudio
+#Strict -1
+#</Stream>
+
+
+# Single JPEG
+
+#<Stream test.jpg>
+#Feed feed1.ffm
+#Format jpeg
+#VideoFrameRate 2
+#VideoIntraOnly
+##VideoSize 352x240
+#NoAudio
+#Strict -1
+#</Stream>
+
+
+# Flash
+
+#<Stream test.swf>
+#Feed feed1.ffm
+#Format swf
+#VideoFrameRate 2
+#VideoIntraOnly
+#NoAudio
+#</Stream>
+
+
+# ASF compatible
+
+<Stream test.asf>
+Feed feed1.ffm
+Format asf
+VideoFrameRate 15
+VideoSize 352x240
+VideoBitRate 256
+VideoBufferSize 40
+VideoGopSize 30
+AudioBitRate 64
+StartSendOnKey
+</Stream>
+
+
+# MP3 audio
+
+#<Stream test.mp3>
+#Feed feed1.ffm
+#Format mp2
+#AudioCodec mp3
+#AudioBitRate 64
+#AudioChannels 1
+#AudioSampleRate 44100
+#NoVideo
+#</Stream>
+
+
+# Ogg Vorbis audio
+
+#<Stream test.ogg>
+#Feed feed1.ffm
+#Metadata title "Stream title"
+#AudioBitRate 64
+#AudioChannels 2
+#AudioSampleRate 44100
+#NoVideo
+#</Stream>
+
+
+# Real with audio only at 32 kbits
+
+#<Stream test.ra>
+#Feed feed1.ffm
+#Format rm
+#AudioBitRate 32
+#NoVideo
+#NoAudio
+#</Stream>
+
+
+# Real with audio and video at 64 kbits
+
+#<Stream test.rm>
+#Feed feed1.ffm
+#Format rm
+#AudioBitRate 32
+#VideoBitRate 128
+#VideoFrameRate 25
+#VideoGopSize 25
+#NoAudio
+#</Stream>
+
+
+##################################################################
+# A stream coming from a file: you only need to set the input
+# filename and optionally a new format. Supported conversions:
+# AVI -> ASF
+
+#<Stream file.rm>
+#File "/usr/local/httpd/htdocs/tlive.rm"
+#NoAudio
+#</Stream>
+
+#<Stream file.asf>
+#File "/usr/local/httpd/htdocs/test.asf"
+#NoAudio
+#Metadata author "Me"
+#Metadata copyright "Super MegaCorp"
+#Metadata title "Test stream from disk"
+#Metadata comment "Test comment"
+#</Stream>
+
+
+##################################################################
+# RTSP examples
+#
+# You can access this stream with the RTSP URL:
+# rtsp://localhost:5454/test1-rtsp.mpg
+#
+# A non-standard RTSP redirector is also created. Its URL is:
+# http://localhost:8090/test1-rtsp.rtsp
+
+#<Stream test1-rtsp.mpg>
+#Format rtp
+#File "/usr/local/httpd/htdocs/test1.mpg"
+#</Stream>
+
+
+# Transcode an incoming live feed to another live feed,
+# using libx264 and video presets
+
+#<Stream live.h264>
+#Format rtp
+#Feed feed1.ffm
+#VideoCodec libx264
+#VideoFrameRate 24
+#VideoBitRate 100
+#VideoSize 480x272
+#AVPresetVideo default
+#AVPresetVideo baseline
+#AVOptionVideo flags +global_header
+#
+#AudioCodec libfaac
+#AudioBitRate 32
+#AudioChannels 2
+#AudioSampleRate 22050
+#AVOptionAudio flags +global_header
+#</Stream>
+
+##################################################################
+# SDP/multicast examples
+#
+# If you want to send your stream in multicast, you must set the
+# multicast address with MulticastAddress. The port and the TTL can
+# also be set.
+#
+# An SDP file is automatically generated by ffserver by adding the
+# 'sdp' extension to the stream name (here
+# http://localhost:8090/test1-sdp.sdp). You should usually give this
+# file to your player to play the stream.
+#
+# The 'NoLoop' option can be used to avoid looping when the stream is
+# terminated.
+
+#<Stream test1-sdp.mpg>
+#Format rtp
+#File "/usr/local/httpd/htdocs/test1.mpg"
+#MulticastAddress 224.124.0.1
+#MulticastPort 5000
+#MulticastTTL 16
+#NoLoop
+#</Stream>
+
+
+##################################################################
+# Special streams
+
+# Server status
+
+<Stream stat.html>
+Format status
+
+# Only allow local people to get the status
+ACL allow localhost
+ACL allow 192.168.0.0 192.168.255.255
+
+#FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico
+</Stream>
+
+
+# Redirect index.html to the appropriate site
+
+<Redirect index.html>
+URL http://www.ffmpeg.org/
+</Redirect>
diff --git a/doc/ffserver.texi b/doc/ffserver.texi
new file mode 100644
index 0000000000..ad48f47a8f
--- /dev/null
+++ b/doc/ffserver.texi
@@ -0,0 +1,923 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle ffserver Documentation
+@titlepage
+@center @titlefont{ffserver Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Synopsis
+
+ffserver [@var{options}]
+
+@chapter Description
+@c man begin DESCRIPTION
+
+@command{ffserver} is a streaming server for both audio and video.
+It supports several live feeds, streaming from files and time shifting
+on live feeds. You can seek to positions in the past on each live
+feed, provided you specify a big enough feed storage.
+
+@command{ffserver} is configured through a configuration file, which
+is read at startup. If not explicitly specified, it will read from
+@file{/etc/ffserver.conf}.
+
+@command{ffserver} receives prerecorded files or FFM streams from some
+@command{ffmpeg} instance as input, then streams them over
+RTP/RTSP/HTTP.
+
+An @command{ffserver} instance will listen on some port as specified
+in the configuration file. You can launch one or more instances of
+@command{ffmpeg} and send one or more FFM streams to the port where
+ffserver is expecting to receive them. Alternately, you can make
+@command{ffserver} launch such @command{ffmpeg} instances at startup.
+
+Input streams are called feeds, and each one is specified by a
+@code{<Feed>} section in the configuration file.
+
+For each feed you can have different output streams in various
+formats, each one specified by a @code{<Stream>} section in the
+configuration file.
+
+@chapter Detailed description
+
+@command{ffserver} works by forwarding streams encoded by
+@command{ffmpeg}, or pre-recorded streams which are read from disk.
+
+Precisely, @command{ffserver} acts as an HTTP server, accepting POST
+requests from @command{ffmpeg} to acquire the stream to publish, and
+serving RTSP clients or HTTP clients GET requests with the stream
+media content.
+
+A feed is an @ref{FFM} stream created by @command{ffmpeg}, and sent to
+a port where @command{ffserver} is listening.
+
+Each feed is identified by a unique name, corresponding to the name
+of the resource published on @command{ffserver}, and is configured by
+a dedicated @code{Feed} section in the configuration file.
+
+The feed publish URL is given by:
+@example
+http://@var{ffserver_ip_address}:@var{http_port}/@var{feed_name}
+@end example
+
+where @var{ffserver_ip_address} is the IP address of the machine where
+@command{ffserver} is installed, @var{http_port} is the port number of
+the HTTP server (configured through the @option{HTTPPort} option), and
+@var{feed_name} is the name of the corresponding feed defined in the
+configuration file.
+
+Each feed is associated to a file which is stored on disk. This stored
+file is used to send pre-recorded data to a player as fast as
+possible when new content is added in real-time to the stream.
+
+A "live-stream" or "stream" is a resource published by
+@command{ffserver}, and made accessible through the HTTP protocol to
+clients.
+
+A stream can be connected to a feed, or to a file. In the first case,
+the published stream is forwarded from the corresponding feed
+generated by a running instance of @command{ffmpeg}, in the second
+case the stream is read from a pre-recorded file.
+
+Each stream is identified by a unique name, corresponding to the name
+of the resource served by @command{ffserver}, and is configured by
+a dedicated @code{Stream} section in the configuration file.
+
+The stream access HTTP URL is given by:
+@example
+http://@var{ffserver_ip_address}:@var{http_port}/@var{stream_name}[@var{options}]
+@end example
+
+The stream access RTSP URL is given by:
+@example
+http://@var{ffserver_ip_address}:@var{rtsp_port}/@var{stream_name}[@var{options}]
+@end example
+
+@var{stream_name} is the name of the corresponding stream defined in
+the configuration file. @var{options} is a list of options specified
+after the URL which affects how the stream is served by
+@command{ffserver}. @var{http_port} and @var{rtsp_port} are the HTTP
+and RTSP ports configured with the options @var{HTTPPort} and
+@var{RTSPPort} respectively.
+
+In case the stream is associated to a feed, the encoding parameters
+must be configured in the stream configuration. They are sent to
+@command{ffmpeg} when setting up the encoding. This allows
+@command{ffserver} to define the encoding parameters used by
+the @command{ffmpeg} encoders.
+
+The @command{ffmpeg} @option{override_ffserver} commandline option
+allows one to override the encoding parameters set by the server.
+
+Multiple streams can be connected to the same feed.
+
+For example, you can have a situation described by the following
+graph:
+
+@verbatim
+ _________ __________
+ | | | |
+ffmpeg 1 -----| feed 1 |-----| stream 1 |
+ \ |_________|\ |__________|
+ \ \
+ \ \ __________
+ \ \ | |
+ \ \| stream 2 |
+ \ |__________|
+ \
+ \ _________ __________
+ \ | | | |
+ \| feed 2 |-----| stream 3 |
+ |_________| |__________|
+
+ _________ __________
+ | | | |
+ffmpeg 2 -----| feed 3 |-----| stream 4 |
+ |_________| |__________|
+
+ _________ __________
+ | | | |
+ | file 1 |-----| stream 5 |
+ |_________| |__________|
+
+@end verbatim
+
+@anchor{FFM}
+@section FFM, FFM2 formats
+
+FFM and FFM2 are formats used by ffserver. They allow storing a wide variety of
+video and audio streams and encoding options, and can store a moving time segment
+of an infinite movie or a whole movie.
+
+FFM is version specific, and there is limited compatibility of FFM files
+generated by one version of ffmpeg/ffserver and another version of
+ffmpeg/ffserver. It may work but it is not guaranteed to work.
+
+FFM2 is extensible while maintaining compatibility and should work between
+differing versions of tools. FFM2 is the default.
+
+@section Status stream
+
+@command{ffserver} supports an HTTP interface which exposes the
+current status of the server.
+
+Simply point your browser to the address of the special status stream
+specified in the configuration file.
+
+For example if you have:
+@example
+<Stream status.html>
+Format status
+
+# Only allow local people to get the status
+ACL allow localhost
+ACL allow 192.168.0.0 192.168.255.255
+</Stream>
+@end example
+
+then the server will post a page with the status information when
+the special stream @file{status.html} is requested.
+
+@section How do I make it work?
+
+As a simple test, just run the following two command lines where INPUTFILE
+is some file which you can decode with ffmpeg:
+
+@example
+ffserver -f doc/ffserver.conf &
+ffmpeg -i INPUTFILE http://localhost:8090/feed1.ffm
+@end example
+
+At this point you should be able to go to your Windows machine and fire up
+Windows Media Player (WMP). Go to Open URL and enter
+
+@example
+ http://<linuxbox>:8090/test.asf
+@end example
+
+You should (after a short delay) see video and hear audio.
+
+WARNING: trying to stream test1.mpg doesn't work with WMP as it tries to
+transfer the entire file before starting to play.
+The same is true of AVI files.
+
+You should edit the @file{ffserver.conf} file to suit your needs (in
+terms of frame rates etc). Then install @command{ffserver} and
+@command{ffmpeg}, write a script to start them up, and off you go.
+
+@section What else can it do?
+
+You can replay video from .ffm files that was recorded earlier.
+However, there are a number of caveats, including the fact that the
+ffserver parameters must match the original parameters used to record the
+file. If they do not, then ffserver deletes the file before recording into it.
+(Now that I write this, it seems broken).
+
+You can fiddle with many of the codec choices and encoding parameters, and
+there are a bunch more parameters that you cannot control. Post a message
+to the mailing list if there are some 'must have' parameters. Look in
+ffserver.conf for a list of the currently available controls.
+
+It will automatically generate the ASX or RAM files that are often used
+in browsers. These files are actually redirections to the underlying ASF
+or RM file. The reason for this is that the browser often fetches the
+entire file before starting up the external viewer. The redirection files
+are very small and can be transferred quickly. [The stream itself is
+often 'infinite' and thus the browser tries to download it and never
+finishes.]
+
+@section Tips
+
+* When you connect to a live stream, most players (WMP, RA, etc) want to
+buffer a certain number of seconds of material so that they can display the
+signal continuously. However, ffserver (by default) starts sending data
+in realtime. This means that there is a pause of a few seconds while the
+buffering is being done by the player. The good news is that this can be
+cured by adding a '?buffer=5' to the end of the URL. This means that the
+stream should start 5 seconds in the past -- and so the first 5 seconds
+of the stream are sent as fast as the network will allow. It will then
+slow down to real time. This noticeably improves the startup experience.
+
+You can also add a 'Preroll 15' statement into the ffserver.conf that will
+add the 15 second prebuffering on all requests that do not otherwise
+specify a time. In addition, ffserver will skip frames until a key_frame
+is found. This further reduces the startup delay by not transferring data
+that will be discarded.
+
+@section Why does the ?buffer / Preroll stop working after a time?
+
+It turns out that (on my machine at least) the number of frames successfully
+grabbed is marginally less than the number that ought to be grabbed. This
+means that the timestamp in the encoded data stream gets behind realtime.
+This means that if you say 'Preroll 10', then when the stream gets 10
+or more seconds behind, there is no Preroll left.
+
+Fixing this requires a change in the internals of how timestamps are
+handled.
+
+@section Does the @code{?date=} stuff work.
+
+Yes (subject to the limitation outlined above). Also note that whenever you
+start ffserver, it deletes the ffm file (if any parameters have changed),
+thus wiping out what you had recorded before.
+
+The format of the @code{?date=xxxxxx} is fairly flexible. You should use one
+of the following formats (the 'T' is literal):
+
+@example
+* YYYY-MM-DDTHH:MM:SS (localtime)
+* YYYY-MM-DDTHH:MM:SSZ (UTC)
+@end example
+
+You can omit the YYYY-MM-DD, and then it refers to the current day. However
+note that @samp{?date=16:00:00} refers to 16:00 on the current day -- this
+may be in the future and so is unlikely to be useful.
+
+You use this by adding the ?date= to the end of the URL for the stream.
+For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}.
+@c man end
+
+@chapter Options
+@c man begin OPTIONS
+
+@include fftools-common-opts.texi
+
+@section Main options
+
+@table @option
+@item -f @var{configfile}
+Read configuration file @file{configfile}. If not specified it will
+read by default from @file{/etc/ffserver.conf}.
+
+@item -n
+Enable no-launch mode. This option disables all the @code{Launch}
+directives within the various @code{<Feed>} sections. Since
+@command{ffserver} will not launch any @command{ffmpeg} instances, you
+will have to launch them manually.
+
+@item -d
+Enable debug mode. This option increases log verbosity, and directs
+log messages to stdout. When specified, the @option{CustomLog} option
+is ignored.
+@end table
+
+@chapter Configuration file syntax
+
+@command{ffserver} reads a configuration file containing global
+options and settings for each stream and feed.
+
+The configuration file consists of global options and dedicated
+sections, which must be introduced by "<@var{SECTION_NAME}
+@var{ARGS}>" on a separate line and must be terminated by a line in
+the form "</@var{SECTION_NAME}>". @var{ARGS} is optional.
+
+Currently the following sections are recognized: @samp{Feed},
+@samp{Stream}, @samp{Redirect}.
+
+A line starting with @code{#} is ignored and treated as a comment.
+
+Name of options and sections are case-insensitive.
+
+@section ACL syntax
+An ACL (Access Control List) specifies the address which are allowed
+to access a given stream, or to write a given feed.
+
+It accepts the folling forms
+@itemize
+@item
+Allow/deny access to @var{address}.
+@example
+ACL ALLOW <address>
+ACL DENY <address>
+@end example
+
+@item
+Allow/deny access to ranges of addresses from @var{first_address} to
+@var{last_address}.
+@example
+ACL ALLOW <first_address> <last_address>
+ACL DENY <first_address> <last_address>
+@end example
+@end itemize
+
+You can repeat the ACL allow/deny as often as you like. It is on a per
+stream basis. The first match defines the action. If there are no matches,
+then the default is the inverse of the last ACL statement.
+
+Thus 'ACL allow localhost' only allows access from localhost.
+'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and
+allow everybody else.
+
+@section Global options
+@table @option
+@item HTTPPort @var{port_number}
+@item Port @var{port_number}
+@item RTSPPort @var{port_number}
+
+@var{HTTPPort} sets the HTTP server listening TCP port number,
+@var{RTSPPort} sets the RTSP server listening TCP port number.
+
+@var{Port} is the equivalent of @var{HTTPPort} and is deprecated.
+
+You must select a different port from your standard HTTP web server if
+it is running on the same computer.
+
+If not specified, no corresponding server will be created.
+
+@item HTTPBindAddress @var{ip_address}
+@item BindAddress @var{ip_address}
+@item RTSPBindAddress @var{ip_address}
+Set address on which the HTTP/RTSP server is bound. Only useful if you
+have several network interfaces.
+
+@var{BindAddress} is the equivalent of @var{HTTPBindAddress} and is
+deprecated.
+
+@item MaxHTTPConnections @var{n}
+Set number of simultaneous HTTP connections that can be handled. It
+has to be defined @emph{before} the @option{MaxClients} parameter,
+since it defines the @option{MaxClients} maximum limit.
+
+Default value is 2000.
+
+@item MaxClients @var{n}
+Set number of simultaneous requests that can be handled. Since
+@command{ffserver} is very fast, it is more likely that you will want
+to leave this high and use @option{MaxBandwidth}.
+
+Default value is 5.
+
+@item MaxBandwidth @var{kbps}
+Set the maximum amount of kbit/sec that you are prepared to consume
+when streaming to clients.
+
+Default value is 1000.
+
+@item CustomLog @var{filename}
+Set access log file (uses standard Apache log file format). '-' is the
+standard output.
+
+If not specified @command{ffserver} will produce no log.
+
+In case the commandline option @option{-d} is specified this option is
+ignored, and the log is written to standard output.
+
+@item NoDaemon
+Set no-daemon mode. This option is currently ignored since now
+@command{ffserver} will always work in no-daemon mode, and is
+deprecated.
+
+@item UseDefaults
+@item NoDefaults
+Control whether default codec options are used for the all streams or not.
+Each stream may overwrite this setting for its own. Default is @var{UseDefaults}.
+The lastest occurrence overrides previous if multiple definitions.
+@end table
+
+@section Feed section
+
+A Feed section defines a feed provided to @command{ffserver}.
+
+Each live feed contains one video and/or audio sequence coming from an
+@command{ffmpeg} encoder or another @command{ffserver}. This sequence
+may be encoded simultaneously with several codecs at several
+resolutions.
+
+A feed instance specification is introduced by a line in the form:
+@example
+<Feed FEED_FILENAME>
+@end example
+
+where @var{FEED_FILENAME} specifies the unique name of the FFM stream.
+
+The following options are recognized within a Feed section.
+
+@table @option
+@item File @var{filename}
+@item ReadOnlyFile @var{filename}
+Set the path where the feed file is stored on disk.
+
+If not specified, the @file{/tmp/FEED.ffm} is assumed, where
+@var{FEED} is the feed name.
+
+If @option{ReadOnlyFile} is used the file is marked as read-only and
+it will not be deleted or updated.
+
+@item Truncate
+Truncate the feed file, rather than appending to it. By default
+@command{ffserver} will append data to the file, until the maximum
+file size value is reached (see @option{FileMaxSize} option).
+
+@item FileMaxSize @var{size}
+Set maximum size of the feed file in bytes. 0 means unlimited. The
+postfixes @code{K} (2^10), @code{M} (2^20), and @code{G} (2^30) are
+recognized.
+
+Default value is 5M.
+
+@item Launch @var{args}
+Launch an @command{ffmpeg} command when creating @command{ffserver}.
+
+@var{args} must be a sequence of arguments to be provided to an
+@command{ffmpeg} instance. The first provided argument is ignored, and
+it is replaced by a path with the same dirname of the @command{ffserver}
+instance, followed by the remaining argument and terminated with a
+path corresponding to the feed.
+
+When the launched process exits, @command{ffserver} will launch
+another program instance.
+
+In case you need a more complex @command{ffmpeg} configuration,
+e.g. if you need to generate multiple FFM feeds with a single
+@command{ffmpeg} instance, you should launch @command{ffmpeg} by hand.
+
+This option is ignored in case the commandline option @option{-n} is
+specified.
+
+@item ACL @var{spec}
+Specify the list of IP address which are allowed or denied to write
+the feed. Multiple ACL options can be specified.
+@end table
+
+@section Stream section
+
+A Stream section defines a stream provided by @command{ffserver}, and
+identified by a single name.
+
+The stream is sent when answering a request containing the stream
+name.
+
+A stream section must be introduced by the line:
+@example
+<Stream STREAM_NAME>
+@end example
+
+where @var{STREAM_NAME} specifies the unique name of the stream.
+
+The following options are recognized within a Stream section.
+
+Encoding options are marked with the @emph{encoding} tag, and they are
+used to set the encoding parameters, and are mapped to libavcodec
+encoding options. Not all encoding options are supported, in
+particular it is not possible to set encoder private options. In order
+to override the encoding options specified by @command{ffserver}, you
+can use the @command{ffmpeg} @option{override_ffserver} commandline
+option.
+
+Only one of the @option{Feed} and @option{File} options should be set.
+
+@table @option
+@item Feed @var{feed_name}
+Set the input feed. @var{feed_name} must correspond to an existing
+feed defined in a @code{Feed} section.
+
+When this option is set, encoding options are used to setup the
+encoding operated by the remote @command{ffmpeg} process.
+
+@item File @var{filename}
+Set the filename of the pre-recorded input file to stream.
+
+When this option is set, encoding options are ignored and the input
+file content is re-streamed as is.
+
+@item Format @var{format_name}
+Set the format of the output stream.
+
+Must be the name of a format recognized by FFmpeg. If set to
+@samp{status}, it is treated as a status stream.
+
+@item InputFormat @var{format_name}
+Set input format. If not specified, it is automatically guessed.
+
+@item Preroll @var{n}
+Set this to the number of seconds backwards in time to start. Note that
+most players will buffer 5-10 seconds of video, and also you need to allow
+for a keyframe to appear in the data stream.
+
+Default value is 0.
+
+@item StartSendOnKey
+Do not send stream until it gets the first key frame. By default
+@command{ffserver} will send data immediately.
+
+@item MaxTime @var{n}
+Set the number of seconds to run. This value set the maximum duration
+of the stream a client will be able to receive.
+
+A value of 0 means that no limit is set on the stream duration.
+
+@item ACL @var{spec}
+Set ACL for the stream.
+
+@item DynamicACL @var{spec}
+
+@item RTSPOption @var{option}
+
+@item MulticastAddress @var{address}
+
+@item MulticastPort @var{port}
+
+@item MulticastTTL @var{integer}
+
+@item NoLoop
+
+@item FaviconURL @var{url}
+Set favicon (favourite icon) for the server status page. It is ignored
+for regular streams.
+
+@item Author @var{value}
+@item Comment @var{value}
+@item Copyright @var{value}
+@item Title @var{value}
+Set metadata corresponding to the option. All these options are
+deprecated in favor of @option{Metadata}.
+
+@item Metadata @var{key} @var{value}
+Set metadata value on the output stream.
+
+@item UseDefaults
+@item NoDefaults
+Control whether default codec options are used for the stream or not.
+Default is @var{UseDefaults} unless disabled globally.
+
+@item NoAudio
+@item NoVideo
+Suppress audio/video.
+
+@item AudioCodec @var{codec_name} (@emph{encoding,audio})
+Set audio codec.
+
+@item AudioBitRate @var{rate} (@emph{encoding,audio})
+Set bitrate for the audio stream in kbits per second.
+
+@item AudioChannels @var{n} (@emph{encoding,audio})
+Set number of audio channels.
+
+@item AudioSampleRate @var{n} (@emph{encoding,audio})
+Set sampling frequency for audio. When using low bitrates, you should
+lower this frequency to 22050 or 11025. The supported frequencies
+depend on the selected audio codec.
+
+@item AVOptionAudio [@var{codec}:]@var{option} @var{value} (@emph{encoding,audio})
+Set generic or private option for audio stream.
+Private option must be prefixed with codec name or codec must be defined before.
+
+@item AVPresetAudio @var{preset} (@emph{encoding,audio})
+Set preset for audio stream.
+
+@item VideoCodec @var{codec_name} (@emph{encoding,video})
+Set video codec.
+
+@item VideoBitRate @var{n} (@emph{encoding,video})
+Set bitrate for the video stream in kbits per second.
+
+@item VideoBitRateRange @var{range} (@emph{encoding,video})
+Set video bitrate range.
+
+A range must be specified in the form @var{minrate}-@var{maxrate}, and
+specifies the @option{minrate} and @option{maxrate} encoding options
+expressed in kbits per second.
+
+@item VideoBitRateRangeTolerance @var{n} (@emph{encoding,video})
+Set video bitrate tolerance in kbits per second.
+
+@item PixelFormat @var{pixel_format} (@emph{encoding,video})
+Set video pixel format.
+
+@item Debug @var{integer} (@emph{encoding,video})
+Set video @option{debug} encoding option.
+
+@item Strict @var{integer} (@emph{encoding,video})
+Set video @option{strict} encoding option.
+
+@item VideoBufferSize @var{n} (@emph{encoding,video})
+Set ratecontrol buffer size, expressed in KB.
+
+@item VideoFrameRate @var{n} (@emph{encoding,video})
+Set number of video frames per second.
+
+@item VideoSize (@emph{encoding,video})
+Set size of the video frame, must be an abbreviation or in the form
+@var{W}x@var{H}. See @ref{video size syntax,,the Video size section
+in the ffmpeg-utils(1) manual,ffmpeg-utils}.
+
+Default value is @code{160x128}.
+
+@item VideoIntraOnly (@emph{encoding,video})
+Transmit only intra frames (useful for low bitrates, but kills frame rate).
+
+@item VideoGopSize @var{n} (@emph{encoding,video})
+If non-intra only, an intra frame is transmitted every VideoGopSize
+frames. Video synchronization can only begin at an intra frame.
+
+@item VideoTag @var{tag} (@emph{encoding,video})
+Set video tag.
+
+@item VideoHighQuality (@emph{encoding,video})
+@item Video4MotionVector (@emph{encoding,video})
+
+@item BitExact (@emph{encoding,video})
+Set bitexact encoding flag.
+
+@item IdctSimple (@emph{encoding,video})
+Set simple IDCT algorithm.
+
+@item Qscale @var{n} (@emph{encoding,video})
+Enable constant quality encoding, and set video qscale (quantization
+scale) value, expressed in @var{n} QP units.
+
+@item VideoQMin @var{n} (@emph{encoding,video})
+@item VideoQMax @var{n} (@emph{encoding,video})
+Set video qmin/qmax.
+
+@item VideoQDiff @var{integer} (@emph{encoding,video})
+Set video @option{qdiff} encoding option.
+
+@item LumiMask @var{float} (@emph{encoding,video})
+@item DarkMask @var{float} (@emph{encoding,video})
+Set @option{lumi_mask}/@option{dark_mask} encoding options.
+
+@item AVOptionVideo [@var{codec}:]@var{option} @var{value} (@emph{encoding,video})
+Set generic or private option for video stream.
+Private option must be prefixed with codec name or codec must be defined before.
+
+@item AVPresetVideo @var{preset} (@emph{encoding,video})
+Set preset for video stream.
+
+@var{preset} must be the path of a preset file.
+@end table
+
+@subsection Server status stream
+
+A server status stream is a special stream which is used to show
+statistics about the @command{ffserver} operations.
+
+It must be specified setting the option @option{Format} to
+@samp{status}.
+
+@section Redirect section
+
+A redirect section specifies where to redirect the requested URL to
+another page.
+
+A redirect section must be introduced by the line:
+@example
+<Redirect NAME>
+@end example
+
+where @var{NAME} is the name of the page which should be redirected.
+
+It only accepts the option @option{URL}, which specify the redirection
+URL.
+
+@chapter Stream examples
+
+@itemize
+@item
+Multipart JPEG
+@example
+<Stream test.mjpg>
+Feed feed1.ffm
+Format mpjpeg
+VideoFrameRate 2
+VideoIntraOnly
+NoAudio
+Strict -1
+</Stream>
+@end example
+
+@item
+Single JPEG
+@example
+<Stream test.jpg>
+Feed feed1.ffm
+Format jpeg
+VideoFrameRate 2
+VideoIntraOnly
+VideoSize 352x240
+NoAudio
+Strict -1
+</Stream>
+@end example
+
+@item
+Flash
+@example
+<Stream test.swf>
+Feed feed1.ffm
+Format swf
+VideoFrameRate 2
+VideoIntraOnly
+NoAudio
+</Stream>
+@end example
+
+@item
+ASF compatible
+@example
+<Stream test.asf>
+Feed feed1.ffm
+Format asf
+VideoFrameRate 15
+VideoSize 352x240
+VideoBitRate 256
+VideoBufferSize 40
+VideoGopSize 30
+AudioBitRate 64
+StartSendOnKey
+</Stream>
+@end example
+
+@item
+MP3 audio
+@example
+<Stream test.mp3>
+Feed feed1.ffm
+Format mp2
+AudioCodec mp3
+AudioBitRate 64
+AudioChannels 1
+AudioSampleRate 44100
+NoVideo
+</Stream>
+@end example
+
+@item
+Ogg Vorbis audio
+@example
+<Stream test.ogg>
+Feed feed1.ffm
+Metadata title "Stream title"
+AudioBitRate 64
+AudioChannels 2
+AudioSampleRate 44100
+NoVideo
+</Stream>
+@end example
+
+@item
+Real with audio only at 32 kbits
+@example
+<Stream test.ra>
+Feed feed1.ffm
+Format rm
+AudioBitRate 32
+NoVideo
+</Stream>
+@end example
+
+@item
+Real with audio and video at 64 kbits
+@example
+<Stream test.rm>
+Feed feed1.ffm
+Format rm
+AudioBitRate 32
+VideoBitRate 128
+VideoFrameRate 25
+VideoGopSize 25
+</Stream>
+@end example
+
+@item
+For stream coming from a file: you only need to set the input filename
+and optionally a new format.
+
+@example
+<Stream file.rm>
+File "/usr/local/httpd/htdocs/tlive.rm"
+NoAudio
+</Stream>
+@end example
+
+@example
+<Stream file.asf>
+File "/usr/local/httpd/htdocs/test.asf"
+NoAudio
+Metadata author "Me"
+Metadata copyright "Super MegaCorp"
+Metadata title "Test stream from disk"
+Metadata comment "Test comment"
+</Stream>
+@end example
+@end itemize
+
+@c man end
+
+@include config.texi
+@ifset config-all
+@ifset config-avutil
+@include utils.texi
+@end ifset
+@ifset config-avcodec
+@include codecs.texi
+@include bitstream_filters.texi
+@end ifset
+@ifset config-avformat
+@include formats.texi
+@include protocols.texi
+@end ifset
+@ifset config-avdevice
+@include devices.texi
+@end ifset
+@ifset config-swresample
+@include resampler.texi
+@end ifset
+@ifset config-swscale
+@include scaler.texi
+@end ifset
+@ifset config-avfilter
+@include filters.texi
+@end ifset
+@end ifset
+
+@chapter See Also
+
+@ifhtml
+@ifset config-all
+@url{ffserver.html,ffserver},
+@end ifset
+@ifset config-not-all
+@url{ffserver-all.html,ffserver-all},
+@end ifset
+the @file{doc/ffserver.conf} example,
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe},
+@url{ffmpeg-utils.html,ffmpeg-utils},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{ffmpeg-codecs.html,ffmpeg-codecs},
+@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters},
+@url{ffmpeg-formats.html,ffmpeg-formats},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{ffmpeg-filters.html,ffmpeg-filters}
+@end ifhtml
+
+@ifnothtml
+@ifset config-all
+ffserver(1),
+@end ifset
+@ifset config-not-all
+ffserver-all(1),
+@end ifset
+the @file{doc/ffserver.conf} example, ffmpeg(1), ffplay(1), ffprobe(1),
+ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1),
+ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename ffserver
+@settitle ffserver video server
+
+@end ignore
+
+@bye
diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi
new file mode 100644
index 0000000000..3b8581368d
--- /dev/null
+++ b/doc/fftools-common-opts.texi
@@ -0,0 +1,387 @@
+All the numerical options, if not specified otherwise, accept a string
+representing a number as input, which may be followed by one of the SI
+unit prefixes, for example: 'K', 'M', or 'G'.
+
+If 'i' is appended to the SI unit prefix, the complete prefix will be
+interpreted as a unit prefix for binary multiples, which are based on
+powers of 1024 instead of powers of 1000. Appending 'B' to the SI unit
+prefix multiplies the value by 8. This allows using, for example:
+'KB', 'MiB', 'G' and 'B' as number suffixes.
+
+Options which do not take arguments are boolean options, and set the
+corresponding value to true. They can be set to false by prefixing
+the option name with "no". For example using "-nofoo"
+will set the boolean option with name "foo" to false.
+
+@anchor{Stream specifiers}
+@section Stream specifiers
+Some options are applied per-stream, e.g. bitrate or codec. Stream specifiers
+are used to precisely specify which stream(s) a given option belongs to.
+
+A stream specifier is a string generally appended to the option name and
+separated from it by a colon. E.g. @code{-codec:a:1 ac3} contains the
+@code{a:1} stream specifier, which matches the second audio stream. Therefore, it
+would select the ac3 codec for the second audio stream.
+
+A stream specifier can match several streams, so that the option is applied to all
+of them. E.g. the stream specifier in @code{-b:a 128k} matches all audio
+streams.
+
+An empty stream specifier matches all streams. For example, @code{-codec copy}
+or @code{-codec: copy} would copy all the streams without reencoding.
+
+Possible forms of stream specifiers are:
+@table @option
+@item @var{stream_index}
+Matches the stream with this index. E.g. @code{-threads:1 4} would set the
+thread count for the second stream to 4.
+@item @var{stream_type}[:@var{stream_index}]
+@var{stream_type} is one of following: 'v' for video, 'a' for audio, 's' for subtitle,
+'d' for data, and 't' for attachments. If @var{stream_index} is given, then it matches
+stream number @var{stream_index} of this type. Otherwise, it matches all
+streams of this type.
+@item p:@var{program_id}[:@var{stream_index}]
+If @var{stream_index} is given, then it matches the stream with number @var{stream_index}
+in the program with the id @var{program_id}. Otherwise, it matches all streams in the
+program.
+@item #@var{stream_id} or i:@var{stream_id}
+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.
+@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.
+
+Note that in @command{ffmpeg}, matching by metadata will only work properly for
+input files.
+@end table
+
+@section Generic options
+
+These options are shared amongst the ff* tools.
+
+@table @option
+
+@item -L
+Show license.
+
+@item -h, -?, -help, --help [@var{arg}]
+Show help. An optional parameter may be specified to print help about a specific
+item. If no argument is specified, only basic (non advanced) tool
+options are shown.
+
+Possible values of @var{arg} are:
+@table @option
+@item long
+Print advanced tool options in addition to the basic tool options.
+
+@item full
+Print complete list of options, including shared and private options
+for encoders, decoders, demuxers, muxers, filters, etc.
+
+@item decoder=@var{decoder_name}
+Print detailed information about the decoder named @var{decoder_name}. Use the
+@option{-decoders} option to get a list of all decoders.
+
+@item encoder=@var{encoder_name}
+Print detailed information about the encoder named @var{encoder_name}. Use the
+@option{-encoders} option to get a list of all encoders.
+
+@item demuxer=@var{demuxer_name}
+Print detailed information about the demuxer named @var{demuxer_name}. Use the
+@option{-formats} option to get a list of all demuxers and muxers.
+
+@item muxer=@var{muxer_name}
+Print detailed information about the muxer named @var{muxer_name}. Use the
+@option{-formats} option to get a list of all muxers and demuxers.
+
+@item filter=@var{filter_name}
+Print detailed information about the filter name @var{filter_name}. Use the
+@option{-filters} option to get a list of all filters.
+@end table
+
+@item -version
+Show version.
+
+@item -formats
+Show available formats (including devices).
+
+@item -devices
+Show available devices.
+
+@item -codecs
+Show all codecs known to libavcodec.
+
+Note that the term 'codec' is used throughout this documentation as a shortcut
+for what is more correctly called a media bitstream format.
+
+@item -decoders
+Show available decoders.
+
+@item -encoders
+Show all available encoders.
+
+@item -bsfs
+Show available bitstream filters.
+
+@item -protocols
+Show available protocols.
+
+@item -filters
+Show available libavfilter filters.
+
+@item -pix_fmts
+Show available pixel formats.
+
+@item -sample_fmts
+Show available sample formats.
+
+@item -layouts
+Show channel names and standard channel layouts.
+
+@item -colors
+Show recognized color names.
+
+@item -sources @var{device}[,@var{opt1}=@var{val1}[,@var{opt2}=@var{val2}]...]
+Show autodetected sources of the intput device.
+Some devices may provide system-dependent source names that cannot be autodetected.
+The returned list cannot be assumed to be always complete.
+@example
+ffmpeg -sources pulse,server=192.168.0.4
+@end example
+
+@item -sinks @var{device}[,@var{opt1}=@var{val1}[,@var{opt2}=@var{val2}]...]
+Show autodetected sinks of the output device.
+Some devices may provide system-dependent sink names that cannot be autodetected.
+The returned list cannot be assumed to be always complete.
+@example
+ffmpeg -sinks pulse,server=192.168.0.4
+@end example
+
+@item -loglevel [repeat+]@var{loglevel} | -v [repeat+]@var{loglevel}
+Set the logging level used by the library.
+Adding "repeat+" indicates that repeated log output should not be compressed
+to the first line and the "Last message repeated n times" line will be
+omitted. "repeat" can also be used alone.
+If "repeat" is used alone, and with no prior loglevel set, the default
+loglevel will be used. If multiple loglevel parameters are given, using
+'repeat' will not change the loglevel.
+@var{loglevel} is a string or a number containing one of the following values:
+@table @samp
+@item quiet, -8
+Show nothing at all; be silent.
+@item panic, 0
+Only show fatal errors which could lead the process to crash, such as
+and assert failure. This is not currently used for anything.
+@item fatal, 8
+Only show fatal errors. These are errors after which the process absolutely
+cannot continue after.
+@item error, 16
+Show all errors, including ones which can be recovered from.
+@item warning, 24
+Show all warnings and errors. Any message related to possibly
+incorrect or unexpected events will be shown.
+@item info, 32
+Show informative messages during processing. This is in addition to
+warnings and errors. This is the default value.
+@item verbose, 40
+Same as @code{info}, except more verbose.
+@item debug, 48
+Show everything, including debugging information.
+@item trace, 56
+@end table
+
+By default the program logs to stderr, if coloring is supported by the
+terminal, colors are used to mark errors and warnings. Log coloring
+can be disabled setting the environment variable
+@env{AV_LOG_FORCE_NOCOLOR} or @env{NO_COLOR}, or can be forced setting
+the environment variable @env{AV_LOG_FORCE_COLOR}.
+The use of the environment variable @env{NO_COLOR} is deprecated and
+will be dropped in a following FFmpeg version.
+
+@item -report
+Dump full command line and console output to a file named
+@code{@var{program}-@var{YYYYMMDD}-@var{HHMMSS}.log} in the current
+directory.
+This file can be useful for bug reports.
+It also implies @code{-loglevel verbose}.
+
+Setting the environment variable @env{FFREPORT} to any value has the
+same effect. If the value is a ':'-separated key=value sequence, these
+options will affect the report; option values must be escaped if they
+contain special characters or the options delimiter ':' (see the
+``Quoting and escaping'' section in the ffmpeg-utils manual).
+
+The following options are recognized:
+@table @option
+@item file
+set the file name to use for the report; @code{%p} is expanded to the name
+of the program, @code{%t} is expanded to a timestamp, @code{%%} is expanded
+to a plain @code{%}
+@item level
+set the log verbosity level using a numerical value (see @code{-loglevel}).
+@end table
+
+For example, to output a report to a file named @file{ffreport.log}
+using a log level of @code{32} (alias for log level @code{info}):
+
+@example
+FFREPORT=file=ffreport.log:level=32 ffmpeg -i input output
+@end example
+
+Errors in parsing the environment variable are not fatal, and will not
+appear in the report.
+
+@item -hide_banner
+Suppress printing banner.
+
+All FFmpeg tools will normally show a copyright notice, build options
+and library versions. This option can be used to suppress printing
+this information.
+
+@item -cpuflags flags (@emph{global})
+Allows setting and clearing cpu flags. This option is intended
+for testing. Do not use it unless you know what you're doing.
+@example
+ffmpeg -cpuflags -sse+mmx ...
+ffmpeg -cpuflags mmx ...
+ffmpeg -cpuflags 0 ...
+@end example
+Possible flags for this option are:
+@table @samp
+@item x86
+@table @samp
+@item mmx
+@item mmxext
+@item sse
+@item sse2
+@item sse2slow
+@item sse3
+@item sse3slow
+@item ssse3
+@item atom
+@item sse4.1
+@item sse4.2
+@item avx
+@item avx2
+@item xop
+@item fma3
+@item fma4
+@item 3dnow
+@item 3dnowext
+@item bmi1
+@item bmi2
+@item cmov
+@end table
+@item ARM
+@table @samp
+@item armv5te
+@item armv6
+@item armv6t2
+@item vfp
+@item vfpv3
+@item neon
+@item setend
+@end table
+@item AArch64
+@table @samp
+@item armv8
+@item vfp
+@item neon
+@end table
+@item PowerPC
+@table @samp
+@item altivec
+@end table
+@item Specific Processors
+@table @samp
+@item pentium2
+@item pentium3
+@item pentium4
+@item k6
+@item k62
+@item athlon
+@item athlonxp
+@item k8
+@end table
+@end table
+
+@item -opencl_bench
+This option is used to benchmark all available OpenCL devices and print the
+results. This option is only available when FFmpeg has been compiled with
+@code{--enable-opencl}.
+
+When FFmpeg is configured with @code{--enable-opencl}, the options for the
+global OpenCL context are set via @option{-opencl_options}. See the
+"OpenCL Options" section in the ffmpeg-utils manual for the complete list of
+supported options. Amongst others, these options include the ability to select
+a specific platform and device to run the OpenCL code on. By default, FFmpeg
+will run on the first device of the first platform. While the options for the
+global OpenCL context provide flexibility to the user in selecting the OpenCL
+device of their choice, most users would probably want to select the fastest
+OpenCL device for their system.
+
+This option assists the selection of the most efficient configuration by
+identifying the appropriate device for the user's system. The built-in
+benchmark is run on all the OpenCL devices and the performance is measured for
+each device. The devices in the results list are sorted based on their
+performance with the fastest device listed first. The user can subsequently
+invoke @command{ffmpeg} using the device deemed most appropriate via
+@option{-opencl_options} to obtain the best performance for the OpenCL
+accelerated code.
+
+Typical usage to use the fastest OpenCL device involve the following steps.
+
+Run the command:
+@example
+ffmpeg -opencl_bench
+@end example
+Note down the platform ID (@var{pidx}) and device ID (@var{didx}) of the first
+i.e. fastest device in the list.
+Select the platform and device using the command:
+@example
+ffmpeg -opencl_options platform_idx=@var{pidx}:device_idx=@var{didx} ...
+@end example
+
+@item -opencl_options options (@emph{global})
+Set OpenCL environment options. This option is only available when
+FFmpeg has been compiled with @code{--enable-opencl}.
+
+@var{options} must be a list of @var{key}=@var{value} option pairs
+separated by ':'. See the ``OpenCL Options'' section in the
+ffmpeg-utils manual for the list of supported options.
+@end table
+
+@section AVOptions
+
+These options are provided directly by the libavformat, libavdevice and
+libavcodec libraries. To see the list of available AVOptions, use the
+@option{-help} option. They are separated into two categories:
+@table @option
+@item generic
+These options can be set for any container, codec or device. Generic options
+are listed under AVFormatContext options for containers/devices and under
+AVCodecContext options for codecs.
+@item private
+These options are specific to the given container, device or codec. Private
+options are listed under their corresponding containers/devices/codecs.
+@end table
+
+For example to write an ID3v2.3 header instead of a default ID3v2.4 to
+an MP3 file, use the @option{id3v2_version} private option of the MP3
+muxer:
+@example
+ffmpeg -i input.flac -id3v2_version 3 out.mp3
+@end example
+
+All codec AVOptions are per-stream, and thus a stream specifier
+should be attached to them.
+
+Note: the @option{-nooption} syntax cannot be used for boolean
+AVOptions, use @option{-option 0}/@option{-option 1}.
+
+Note: the old undocumented way of specifying per-stream AVOptions by
+prepending v/a/s to the options name is now obsolete and will be
+removed soon.
diff --git a/doc/filter_design.txt b/doc/filter_design.txt
new file mode 100644
index 0000000000..fca24a94b5
--- /dev/null
+++ b/doc/filter_design.txt
@@ -0,0 +1,270 @@
+Filter design
+=============
+
+This document explains guidelines that should be observed (or ignored with
+good reason) when writing filters for libavfilter.
+
+In this document, the word “frame†indicates either a video frame or a group
+of audio samples, as stored in an AVFilterBuffer structure.
+
+
+Format negotiation
+==================
+
+ The query_formats method should set, for each input and each output links,
+ the list of supported formats.
+
+ For video links, that means pixel format. For audio links, that means
+ channel layout, sample format (the sample packing is implied by the sample
+ format) and sample rate.
+
+ The lists are not just lists, they are references to shared objects. When
+ the negotiation mechanism computes the intersection of the formats
+ supported at each end of a link, all references to both lists are replaced
+ with a reference to the intersection. And when a single format is
+ eventually chosen for a link amongst the remaining list, again, all
+ references to the list are updated.
+
+ That means that if a filter requires that its input and output have the
+ same format amongst a supported list, all it has to do is use a reference
+ to the same list of formats.
+
+ query_formats can leave some formats unset and return AVERROR(EAGAIN) to
+ cause the negotiation mechanism to try again later. That can be used by
+ filters with complex requirements to use the format negotiated on one link
+ to set the formats supported on another.
+
+
+Buffer references ownership and permissions
+===========================================
+
+ Principle
+ ---------
+
+ Audio and video data are voluminous; the buffer and buffer reference
+ mechanism is intended to avoid, as much as possible, expensive copies of
+ that data while still allowing the filters to produce correct results.
+
+ The data is stored in buffers represented by AVFilterBuffer structures.
+ They must not be accessed directly, but through references stored in
+ AVFilterBufferRef structures. Several references can point to the
+ same buffer; the buffer is automatically deallocated once all
+ corresponding references have been destroyed.
+
+ The characteristics of the data (resolution, sample rate, etc.) are
+ stored in the reference; different references for the same buffer can
+ show different characteristics. In particular, a video reference can
+ point to only a part of a video buffer.
+
+ A reference is usually obtained as input to the start_frame or
+ filter_frame method or requested using the ff_get_video_buffer or
+ ff_get_audio_buffer functions. A new reference on an existing buffer can
+ be created with the avfilter_ref_buffer. A reference is destroyed using
+ the avfilter_unref_bufferp function.
+
+ Reference ownership
+ -------------------
+
+ At any time, a reference “belongs†to a particular piece of code,
+ usually a filter. With a few caveats that will be explained below, only
+ that piece of code is allowed to access it. It is also responsible for
+ destroying it, although this is sometimes done automatically (see the
+ section on link reference fields).
+
+ Here are the (fairly obvious) rules for reference ownership:
+
+ * A reference received by the filter_frame method (or its start_frame
+ deprecated version) belongs to the corresponding filter.
+
+ Special exception: for video references: the reference may be used
+ internally for automatic copying and must not be destroyed before
+ end_frame; it can be given away to ff_start_frame.
+
+ * A reference passed to ff_filter_frame (or the deprecated
+ ff_start_frame) is given away and must no longer be used.
+
+ * A reference created with avfilter_ref_buffer belongs to the code that
+ created it.
+
+ * A reference obtained with ff_get_video_buffer or ff_get_audio_buffer
+ belongs to the code that requested it.
+
+ * A reference given as return value by the get_video_buffer or
+ get_audio_buffer method is given away and must no longer be used.
+
+ Link reference fields
+ ---------------------
+
+ The AVFilterLink structure has a few AVFilterBufferRef fields. The
+ cur_buf and out_buf were used with the deprecated
+ start_frame/draw_slice/end_frame API and should no longer be used.
+ src_buf, cur_buf_copy and partial_buf are used by libavfilter internally
+ and must not be accessed by filters.
+
+ Reference permissions
+ ---------------------
+
+ The AVFilterBufferRef structure has a perms field that describes what
+ the code that owns the reference is allowed to do to the buffer data.
+ Different references for the same buffer can have different permissions.
+
+ For video filters that implement the deprecated
+ start_frame/draw_slice/end_frame API, the permissions only apply to the
+ parts of the buffer that have already been covered by the draw_slice
+ method.
+
+ The value is a binary OR of the following constants:
+
+ * AV_PERM_READ: the owner can read the buffer data; this is essentially
+ always true and is there for self-documentation.
+
+ * AV_PERM_WRITE: the owner can modify the buffer data.
+
+ * AV_PERM_PRESERVE: the owner can rely on the fact that the buffer data
+ will not be modified by previous filters.
+
+ * AV_PERM_REUSE: the owner can output the buffer several times, without
+ modifying the data in between.
+
+ * AV_PERM_REUSE2: the owner can output the buffer several times and
+ modify the data in between (useless without the WRITE permissions).
+
+ * AV_PERM_ALIGN: the owner can access the data using fast operations
+ that require data alignment.
+
+ The READ, WRITE and PRESERVE permissions are about sharing the same
+ buffer between several filters to avoid expensive copies without them
+ doing conflicting changes on the data.
+
+ The REUSE and REUSE2 permissions are about special memory for direct
+ rendering. For example a buffer directly allocated in video memory must
+ not modified once it is displayed on screen, or it will cause tearing;
+ it will therefore not have the REUSE2 permission.
+
+ The ALIGN permission is about extracting part of the buffer, for
+ copy-less padding or cropping for example.
+
+
+ References received on input pads are guaranteed to have all the
+ permissions stated in the min_perms field and none of the permissions
+ stated in the rej_perms.
+
+ References obtained by ff_get_video_buffer and ff_get_audio_buffer are
+ guaranteed to have at least all the permissions requested as argument.
+
+ References created by avfilter_ref_buffer have the same permissions as
+ the original reference minus the ones explicitly masked; the mask is
+ usually ~0 to keep the same permissions.
+
+ Filters should remove permissions on reference they give to output
+ whenever necessary. It can be automatically done by setting the
+ rej_perms field on the output pad.
+
+ Here are a few guidelines corresponding to common situations:
+
+ * Filters that modify and forward their frame (like drawtext) need the
+ WRITE permission.
+
+ * Filters that read their input to produce a new frame on output (like
+ scale) need the READ permission on input and must request a buffer
+ with the WRITE permission.
+
+ * Filters that intend to keep a reference after the filtering process
+ is finished (after filter_frame returns) must have the PRESERVE
+ permission on it and remove the WRITE permission if they create a new
+ reference to give it away.
+
+ * Filters that intend to modify a reference they have kept after the end
+ of the filtering process need the REUSE2 permission and must remove
+ the PRESERVE permission if they create a new reference to give it
+ away.
+
+
+Frame scheduling
+================
+
+ The purpose of these rules is to ensure that frames flow in the filter
+ graph without getting stuck and accumulating somewhere.
+
+ Simple filters that output one frame for each input frame should not have
+ to worry about it.
+
+ filter_frame
+ ------------
+
+ This method is called when a frame is pushed to the filter's input. It
+ can be called at any time except in a reentrant way.
+
+ If the input frame is enough to produce output, then the filter should
+ push the output frames on the output link immediately.
+
+ As an exception to the previous rule, if the input frame is enough to
+ produce several output frames, then the filter needs output only at
+ least one per link. The additional frames can be left buffered in the
+ filter; these buffered frames must be flushed immediately if a new input
+ produces new output.
+
+ (Example: frame rate-doubling filter: filter_frame must (1) flush the
+ second copy of the previous frame, if it is still there, (2) push the
+ first copy of the incoming frame, (3) keep the second copy for later.)
+
+ If the input frame is not enough to produce output, the filter must not
+ call request_frame to get more. It must just process the frame or queue
+ it. The task of requesting more frames is left to the filter's
+ request_frame method or the application.
+
+ If a filter has several inputs, the filter must be ready for frames
+ arriving randomly on any input. Therefore, any filter with several inputs
+ will most likely require some kind of queuing mechanism. It is perfectly
+ acceptable to have a limited queue and to drop frames when the inputs
+ are too unbalanced.
+
+ request_frame
+ -------------
+
+ This method is called when a frame is wanted on an output.
+
+ For an input, it should directly call filter_frame on the corresponding
+ output.
+
+ For a filter, if there are queued frames already ready, one of these
+ frames should be pushed. If not, the filter should request a frame on
+ one of its inputs, repeatedly until at least one frame has been pushed.
+
+ Return values:
+ if request_frame could produce a frame, it should return 0;
+ if it could not for temporary reasons, it should return AVERROR(EAGAIN);
+ if it could not because there are no more frames, it should return
+ AVERROR_EOF.
+
+ The typical implementation of request_frame for a filter with several
+ inputs will look like that:
+
+ if (frames_queued) {
+ push_one_frame();
+ return 0;
+ }
+ while (!frame_pushed) {
+ input = input_where_a_frame_is_most_needed();
+ ret = ff_request_frame(input);
+ if (ret == AVERROR_EOF) {
+ process_eof_on_input();
+ } else if (ret < 0) {
+ return ret;
+ }
+ }
+ return 0;
+
+ Note that, except for filters that can have queued frames, request_frame
+ does not push frames: it requests them to its input, and as a reaction,
+ the filter_frame method will be called and do the work.
+
+Legacy API
+==========
+
+ Until libavfilter 3.23, the filter_frame method was split:
+
+ - for video filters, it was made of start_frame, draw_slice (that could be
+ called several times on distinct parts of the frame) and end_frame;
+
+ - for audio filters, it was called filter_samples.
diff --git a/doc/filters.texi b/doc/filters.texi
index e36f9a2a86..a79979360a 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1,3 +1,100 @@
+@chapter Filtering Introduction
+@c man begin FILTERING INTRODUCTION
+
+Filtering in FFmpeg is enabled through the libavfilter library.
+
+In libavfilter, a filter can have multiple inputs and multiple
+outputs.
+To illustrate the sorts of things that are possible, we consider the
+following filtergraph.
+
+@verbatim
+ [main]
+input --> split ---------------------> overlay --> output
+ | ^
+ |[tmp] [flip]|
+ +-----> crop --> vflip -------+
+@end verbatim
+
+This filtergraph splits the input stream in two streams, then sends one
+stream through the crop filter and the vflip filter, before merging it
+back with the other stream by overlaying it on top. You can use the
+following command to achieve this:
+
+@example
+ffmpeg -i INPUT -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT
+@end example
+
+The result will be that the top half of the video is mirrored
+onto the bottom half of the output video.
+
+Filters in the same linear chain are separated by commas, and distinct
+linear chains of filters are separated by semicolons. In our example,
+@var{crop,vflip} are in one linear chain, @var{split} and
+@var{overlay} are separately in another. The points where the linear
+chains join are labelled by names enclosed in square brackets. In the
+example, the split filter generates two outputs that are associated to
+the labels @var{[main]} and @var{[tmp]}.
+
+The stream sent to the second output of @var{split}, labelled as
+@var{[tmp]}, is processed through the @var{crop} filter, which crops
+away the lower half part of the video, and then vertically flipped. The
+@var{overlay} filter takes in input the first unchanged output of the
+split filter (which was labelled as @var{[main]}), and overlay on its
+lower half the output generated by the @var{crop,vflip} filterchain.
+
+Some filters take in input a list of parameters: they are specified
+after the filter name and an equal sign, and are separated from each other
+by a colon.
+
+There exist so-called @var{source filters} that do not have an
+audio/video input, and @var{sink filters} that will not have audio/video
+output.
+
+@c man end FILTERING INTRODUCTION
+
+@chapter graph2dot
+@c man begin GRAPH2DOT
+
+The @file{graph2dot} program included in the FFmpeg @file{tools}
+directory can be used to parse a filtergraph description and issue a
+corresponding textual representation in the dot language.
+
+Invoke the command:
+@example
+graph2dot -h
+@end example
+
+to see how to use @file{graph2dot}.
+
+You can then pass the dot description to the @file{dot} program (from
+the graphviz suite of programs) and obtain a graphical representation
+of the filtergraph.
+
+For example the sequence of commands:
+@example
+echo @var{GRAPH_DESCRIPTION} | \
+tools/graph2dot -o graph.tmp && \
+dot -Tpng graph.tmp -o graph.png && \
+display graph.png
+@end example
+
+can be used to create and display an image representing the graph
+described by the @var{GRAPH_DESCRIPTION} string. Note that this string must be
+a complete self-contained graph, with its inputs and outputs explicitly defined.
+For example if your command line is of the form:
+@example
+ffmpeg -i infile -vf scale=640:360 outfile
+@end example
+your @var{GRAPH_DESCRIPTION} string will need to be of the form:
+@example
+nullsrc,scale=640:360,nullsink
+@end example
+you may also need to set the @var{nullsrc} parameters and add a @var{format}
+filter in order to simulate a specific input file.
+
+@c man end GRAPH2DOT
+
@chapter Filtergraph description
@c man begin FILTERGRAPH DESCRIPTION
@@ -17,10 +114,11 @@ output pads is called a "sink".
@anchor{Filtergraph syntax}
@section Filtergraph syntax
-A filtergraph has a textual representation, which is
-recognized by the @option{-filter}/@option{-vf} and @option{-filter_complex}
-options in @command{avconv} and @option{-vf} in @command{avplay}, and by the
-@code{avfilter_graph_parse()}/@code{avfilter_graph_parse2()} functions defined in
+A filtergraph has a textual representation, which is recognized by the
+@option{-filter}/@option{-vf}/@option{-af} and
+@option{-filter_complex} options in @command{ffmpeg} and
+@option{-vf}/@option{-af} in @command{ffplay}, and by the
+@code{avfilter_graph_parse_ptr()} function defined in
@file{libavfilter/avfilter.h}.
A filterchain consists of a sequence of connected filters, each one
@@ -55,21 +153,27 @@ declares three options in this order -- @option{type}, @option{start_frame} and
@var{in} is assigned to the option @option{type}, @var{0} to
@option{start_frame} and @var{30} to @option{nb_frames}.
+@item
+A ':'-separated list of mixed direct @var{value} and long @var{key=value}
+pairs. The direct @var{value} must precede the @var{key=value} pairs, and
+follow the same constraints order of the previous point. The following
+@var{key=value} pairs can be set in any preferred order.
+
@end itemize
If the option value itself is a list of items (e.g. the @code{format} filter
takes a list of pixel formats), the items in the list are usually separated by
-'|'.
+@samp{|}.
-The list of arguments can be quoted using the character "'" as initial
-and ending mark, and the character '\' for escaping the characters
+The list of arguments can be quoted using the character @samp{'} as initial
+and ending mark, and the character @samp{\} for escaping the characters
within the quoted text; otherwise the argument string is considered
terminated when the next special character (belonging to the set
-"[]=;,") is encountered.
+@samp{[]=;,}) is encountered.
The name and arguments of the filter are optionally preceded and
followed by a list of link labels.
-A link label allows to name a link and associate it to a filter output
+A link label allows one to name a link and associate it to a filter output
or input pad. The preceding labels @var{in_link_1}
... @var{in_link_N}, are associated to the filter input pads,
the following labels @var{out_link_1} ... @var{out_link_M}, are
@@ -91,6 +195,10 @@ instance two input pads. The first output pad of split is labelled
output pad of split is linked to the second input pad of overlay,
which are both unlabelled.
+In a filter description, if the input label of the first filter is not
+specified, "in" is assumed; if the output label of the last filter is not
+specified, "out" is assumed.
+
In a complete filterchain all the unlabelled filter input and output
pads must be connected. A filtergraph is considered valid if all the
filter input and output pads of all the filterchains are connected.
@@ -112,21 +220,341 @@ Here is a BNF description of the filtergraph syntax:
@var{FILTERGRAPH} ::= [sws_flags=@var{flags};] @var{FILTERCHAIN} [;@var{FILTERGRAPH}]
@end example
+@section Notes on filtergraph escaping
+
+Filtergraph description composition entails several levels of
+escaping. See @ref{quoting_and_escaping,,the "Quoting and escaping"
+section in the ffmpeg-utils(1) manual,ffmpeg-utils} for more
+information about the employed escaping procedure.
+
+A first level escaping affects the content of each filter option
+value, which may contain the special character @code{:} used to
+separate values, or one of the escaping characters @code{\'}.
+
+A second level escaping affects the whole filter description, which
+may contain the escaping characters @code{\'} or the special
+characters @code{[],;} used by the filtergraph description.
+
+Finally, when you specify a filtergraph on a shell commandline, you
+need to perform a third level escaping for the shell special
+characters contained within it.
+
+For example, consider the following string to be embedded in
+the @ref{drawtext} filter description @option{text} value:
+@example
+this is a 'string': may contain one, or more, special characters
+@end example
+
+This string contains the @code{'} special escaping character, and the
+@code{:} special character, so it needs to be escaped in this way:
+@example
+text=this is a \'string\'\: may contain one, or more, special characters
+@end example
+
+A second level of escaping is required when embedding the filter
+description in a filtergraph description, in order to escape all the
+filtergraph special characters. Thus the example above becomes:
+@example
+drawtext=text=this is a \\\'string\\\'\\: may contain one\, or more\, special characters
+@end example
+(note that in addition to the @code{\'} escaping special characters,
+also @code{,} needs to be escaped).
+
+Finally an additional level of escaping is needed when writing the
+filtergraph description in a shell command, which depends on the
+escaping rules of the adopted shell. For example, assuming that
+@code{\} is special and needs to be escaped with another @code{\}, the
+previous string will finally result in:
+@example
+-vf "drawtext=text=this is a \\\\\\'string\\\\\\'\\\\: may contain one\\, or more\\, special characters"
+@end example
+
+@chapter Timeline editing
+
+Some filters support a generic @option{enable} option. For the filters
+supporting timeline editing, this option can be set to an expression which is
+evaluated before sending a frame to the filter. If the evaluation is non-zero,
+the filter will be enabled, otherwise the frame will be sent unchanged to the
+next filter in the filtergraph.
+
+The expression accepts the following values:
+@table @samp
+@item t
+timestamp expressed in seconds, NAN if the input timestamp is unknown
+
+@item n
+sequential number of the input frame, starting from 0
+
+@item pos
+the position in the file of the input frame, NAN if unknown
+
+@item w
+@item h
+width and height of the input frame if video
+@end table
+
+Additionally, these filters support an @option{enable} command that can be used
+to re-define the expression.
+
+Like any other filtering option, the @option{enable} option follows the same
+rules.
+
+For example, to enable a blur filter (@ref{smartblur}) from 10 seconds to 3
+minutes, and a @ref{curves} filter starting at 3 seconds:
+@example
+smartblur = enable='between(t,10,3*60)',
+curves = enable='gte(t,3)' : preset=cross_process
+@end example
+
@c man end FILTERGRAPH DESCRIPTION
@chapter Audio Filters
@c man begin AUDIO FILTERS
-When you configure your Libav build, you can disable any of the
-existing filters using --disable-filters.
+When you configure your FFmpeg build, you can disable any of the
+existing filters using @code{--disable-filters}.
The configure output will show the audio filters included in your
build.
Below is a description of the currently available audio filters.
+@section adelay
+
+Delay one or more audio channels.
+
+Samples in delayed channel are filled with silence.
+
+The filter accepts the following option:
+
+@table @option
+@item delays
+Set list of delays in milliseconds for each channel separated by '|'.
+At least one delay greater than 0 should be provided.
+Unused delays will be silently ignored. If number of given delays is
+smaller than number of channels all remaining channels will not be delayed.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Delay first channel by 1.5 seconds, the third channel by 0.5 seconds and leave
+the second channel (and any other channels that may be present) unchanged.
+@example
+adelay=1500|0|500
+@end example
+@end itemize
+
+@section aecho
+
+Apply echoing to the input audio.
+
+Echoes are reflected sound and can occur naturally amongst mountains
+(and sometimes large buildings) when talking or shouting; digital echo
+effects emulate this behaviour and are often used to help fill out the
+sound of a single instrument or vocal. The time difference between the
+original signal and the reflection is the @code{delay}, and the
+loudness of the reflected signal is the @code{decay}.
+Multiple echoes can have different delays and decays.
+
+A description of the accepted parameters follows.
+
+@table @option
+@item in_gain
+Set input gain of reflected signal. Default is @code{0.6}.
+
+@item out_gain
+Set output gain of reflected signal. Default is @code{0.3}.
+
+@item delays
+Set list of time intervals in milliseconds between original signal and reflections
+separated by '|'. Allowed range for each @code{delay} is @code{(0 - 90000.0]}.
+Default is @code{1000}.
+
+@item decays
+Set list of loudnesses of reflected signals separated by '|'.
+Allowed range for each @code{decay} is @code{(0 - 1.0]}.
+Default is @code{0.5}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Make it sound as if there are twice as many instruments as are actually playing:
+@example
+aecho=0.8:0.88:60:0.4
+@end example
+
+@item
+If delay is very short, then it sound like a (metallic) robot playing music:
+@example
+aecho=0.8:0.88:6:0.4
+@end example
+
+@item
+A longer delay will sound like an open air concert in the mountains:
+@example
+aecho=0.8:0.9:1000:0.3
+@end example
+
+@item
+Same as above but with one more mountain:
+@example
+aecho=0.8:0.9:1000|1800:0.3|0.25
+@end example
+@end itemize
+
+@section aeval
+
+Modify an audio signal according to the specified expressions.
+
+This filter accepts one or more expressions (one for each channel),
+which are evaluated and used to modify a corresponding audio signal.
+
+It accepts the following parameters:
+
+@table @option
+@item exprs
+Set the '|'-separated expressions list for each separate channel. If
+the number of input channels is greater than the number of
+expressions, the last specified expression is used for the remaining
+output channels.
+
+@item channel_layout, c
+Set output channel layout. If not specified, the channel layout is
+specified by the number of expressions. If set to @samp{same}, it will
+use by default the same input channel layout.
+@end table
+
+Each expression in @var{exprs} can contain the following constants and functions:
+
+@table @option
+@item ch
+channel number of the current expression
+
+@item n
+number of the evaluated sample, starting from 0
+
+@item s
+sample rate
+
+@item t
+time of the evaluated sample expressed in seconds
+
+@item nb_in_channels
+@item nb_out_channels
+input and output number of channels
+
+@item val(CH)
+the value of input channel with number @var{CH}
+@end table
+
+Note: this filter is slow. For faster processing you should use a
+dedicated filter.
+
+@subsection Examples
+
+@itemize
+@item
+Half volume:
+@example
+aeval=val(ch)/2:c=same
+@end example
+
+@item
+Invert phase of the second channel:
+@example
+aeval=val(0)|-val(1)
+@end example
+@end itemize
+
+@section afade
+
+Apply fade-in/out effect to input audio.
+
+A description of the accepted parameters follows.
+
+@table @option
+@item type, t
+Specify the effect type, can be either @code{in} for fade-in, or
+@code{out} for a fade-out effect. Default is @code{in}.
+
+@item start_sample, ss
+Specify the number of the start sample for starting to apply the fade
+effect. Default is 0.
+
+@item nb_samples, ns
+Specify the number of samples for which the fade effect has to last. At
+the end of the fade-in effect the output audio will have the same
+volume as the input audio, at the end of the fade-out transition
+the output audio will be silence. Default is 44100.
+
+@item start_time, st
+Specify the start time of the fade effect. Default is 0.
+The value must be specified as a time duration; see
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
+If set this option is used instead of @var{start_sample}.
+
+@item duration, d
+Specify the duration of the fade effect. See
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
+At the end of the fade-in effect the output audio will have the same
+volume as the input audio, at the end of the fade-out transition
+the output audio will be silence.
+By default the duration is determined by @var{nb_samples}.
+If set this option is used instead of @var{nb_samples}.
+
+@item curve
+Set curve for fade transition.
+
+It accepts the following values:
+@table @option
+@item tri
+select triangular, linear slope (default)
+@item qsin
+select quarter of sine wave
+@item hsin
+select half of sine wave
+@item esin
+select exponential sine wave
+@item log
+select logarithmic
+@item par
+select inverted parabola
+@item qua
+select quadratic
+@item cub
+select cubic
+@item squ
+select square root
+@item cbr
+select cubic root
+@end table
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Fade in first 15 seconds of audio:
+@example
+afade=t=in:ss=0:d=15
+@end example
+
+@item
+Fade out last 25 seconds of a 900 seconds audio:
+@example
+afade=t=out:st=875:d=25
+@end example
+@end itemize
+
+@anchor{aformat}
@section aformat
-Convert the input audio to one of the specified formats. The framework will
+Set output format constraints for the input audio. The framework will
negotiate the most appropriate format to minimize conversions.
It accepts the following parameters:
@@ -141,6 +569,8 @@ A '|'-separated list of requested sample rates.
@item channel_layouts
A '|'-separated list of requested channel layouts.
+See @ref{channel layout syntax,,the Channel Layout section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the required syntax.
@end table
If a parameter is omitted, all values are allowed.
@@ -150,13 +580,99 @@ Force the output to either unsigned 8-bit or signed 16-bit stereo
aformat=sample_fmts=u8|s16:channel_layouts=stereo
@end example
+@section allpass
+
+Apply a two-pole all-pass filter with central frequency (in Hz)
+@var{frequency}, and filter-width @var{width}.
+An all-pass filter changes the audio's frequency to phase relationship
+without changing its frequency to amplitude relationship.
+
+The filter accepts the following options:
+
+@table @option
+@item frequency, f
+Set frequency in Hz.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Specify the band-width of a filter in width_type units.
+@end table
+
+@section amerge
+
+Merge two or more audio streams into a single multi-channel stream.
+
+The filter accepts the following options:
+
+@table @option
+
+@item inputs
+Set the number of inputs. Default is 2.
+
+@end table
+
+If the channel layouts of the inputs are disjoint, and therefore compatible,
+the channel layout of the output will be set accordingly and the channels
+will be reordered as necessary. If the channel layouts of the inputs are not
+disjoint, the output will have all the channels of the first input then all
+the channels of the second input, in that order, and the channel layout of
+the output will be the default value corresponding to the total number of
+channels.
+
+For example, if the first input is in 2.1 (FL+FR+LF) and the second input
+is FC+BL+BR, then the output will be in 5.1, with the channels in the
+following order: a1, a2, b1, a3, b2, b3 (a1 is the first channel of the
+first input, b1 is the first channel of the second input).
+
+On the other hand, if both input are in stereo, the output channels will be
+in the default order: a1, a2, b1, b2, and the channel layout will be
+arbitrarily set to 4.0, which may or may not be the expected value.
+
+All inputs must have the same sample rate, and format.
+
+If inputs do not have the same duration, the output will stop with the
+shortest.
+
+@subsection Examples
+
+@itemize
+@item
+Merge two mono files into a stereo stream:
+@example
+amovie=left.wav [l] ; amovie=right.mp3 [r] ; [l] [r] amerge
+@end example
+
+@item
+Multiple merges assuming 1 video stream and 6 audio streams in @file{input.mkv}:
+@example
+ffmpeg -i input.mkv -filter_complex "[0:1][0:2][0:3][0:4][0:5][0:6] amerge=inputs=6" -c:a pcm_s16le output.mkv
+@end example
+@end itemize
+
@section amix
Mixes multiple audio inputs into a single output.
+Note that this filter only supports float samples (the @var{amerge}
+and @var{pan} audio filters support many formats). If the @var{amix}
+input has integer samples then @ref{aresample} will be automatically
+inserted to perform the conversion to float samples.
+
For example
@example
-avconv -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex amix=inputs=3:duration=first:dropout_transition=3 OUTPUT
+ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex amix=inputs=3:duration=first:dropout_transition=3 OUTPUT
@end example
will mix 3 input audio streams to a single output with the same duration as the
first input and a dropout transition time of 3 seconds.
@@ -192,110 +708,169 @@ stream ends. The default value is 2 seconds.
Pass the audio source unchanged to the output.
-@section asetpts
+@section apad
-Change the PTS (presentation timestamp) of the input audio frames.
+Pad the end of an audio stream with silence.
-It accepts the following parameters:
+This can be used together with @command{ffmpeg} @option{-shortest} to
+extend audio streams to the same length as the video stream.
+
+A description of the accepted options follows.
@table @option
+@item packet_size
+Set silence packet size. Default value is 4096.
+
+@item pad_len
+Set the number of samples of silence to add to the end. After the
+value is reached, the stream is terminated. This option is mutually
+exclusive with @option{whole_len}.
+
+@item whole_len
+Set the minimum total number of samples in the output audio stream. If
+the value is longer than the input audio length, silence is added to
+the end, until the value is reached. This option is mutually exclusive
+with @option{pad_len}.
+@end table
-@item expr
-The expression which is evaluated for each frame to construct its timestamp.
+If neither the @option{pad_len} nor the @option{whole_len} option is
+set, the filter will add silence to the end of the input stream
+indefinitely.
-@end table
+@subsection Examples
-The expression is evaluated through the eval API and can contain the following
-constants:
+@itemize
+@item
+Add 1024 samples of silence to the end of the input:
+@example
+apad=pad_len=1024
+@end example
-@table @option
-@item PTS
-the presentation timestamp in input
+@item
+Make sure the audio output will contain at least 10000 samples, pad
+the input with silence if required:
+@example
+apad=whole_len=10000
+@end example
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+@item
+Use @command{ffmpeg} to pad the audio input with silence, so that the
+video stream will always result the shortest and will be converted
+until the end in the output file when using the @option{shortest}
+option:
+@example
+ffmpeg -i VIDEO -i AUDIO -filter_complex "[1:0]apad" -shortest OUTPUT
+@end example
+@end itemize
-@item N
-The number of audio samples passed through the filter so far, starting at 0.
+@section aphaser
+Add a phasing effect to the input audio.
-@item S
-The number of audio samples in the current frame.
+A phaser filter creates series of peaks and troughs in the frequency spectrum.
+The position of the peaks and troughs are modulated so that they vary over time, creating a sweeping effect.
-@item SR
-The audio sample rate.
+A description of the accepted parameters follows.
-@item STARTPTS
-The PTS of the first frame.
+@table @option
+@item in_gain
+Set input gain. Default is 0.4.
-@item PREV_INPTS
-The previous input PTS.
+@item out_gain
+Set output gain. Default is 0.74
-@item PREV_OUTPTS
-The previous output PTS.
+@item delay
+Set delay in milliseconds. Default is 3.0.
-@item RTCTIME
-The wallclock (RTC) time in microseconds.
+@item decay
+Set decay. Default is 0.4.
-@item RTCSTART
-The wallclock (RTC) time at the start of the movie in microseconds.
+@item speed
+Set modulation speed in Hz. Default is 0.5.
+@item type
+Set modulation type. Default is triangular.
+
+It accepts the following values:
+@table @samp
+@item triangular, t
+@item sinusoidal, s
+@end table
@end table
-Some examples:
+@anchor{aresample}
+@section aresample
-@example
-# Start counting PTS from zero
-asetpts=expr=PTS-STARTPTS
+Resample the input audio to the specified parameters, using the
+libswresample library. If none are specified then the filter will
+automatically convert between its input and output.
-# Generate timestamps by counting samples
-asetpts=expr=N/SR/TB
+This filter is also able to stretch/squeeze the audio data to make it match
+the timestamps or to inject silence / cut out audio to make it match the
+timestamps, do a combination of both or do neither.
-# Generate timestamps from a "live source" and rebase onto the current timebase
-asetpts='(RTCTIME - RTCSTART) / (TB * 1000000)"
-@end example
+The filter accepts the syntax
+[@var{sample_rate}:]@var{resampler_options}, where @var{sample_rate}
+expresses a sample rate and @var{resampler_options} is a list of
+@var{key}=@var{value} pairs, separated by ":". See the
+ffmpeg-resampler manual for the complete list of supported options.
-@section asettb
+@subsection Examples
-Set the timebase to use for the output frames timestamps.
-It is mainly useful for testing timebase configuration.
+@itemize
+@item
+Resample the input audio to 44100Hz:
+@example
+aresample=44100
+@end example
+
+@item
+Stretch/squeeze samples to the given timestamps, with a maximum of 1000
+samples per second compensation:
+@example
+aresample=async=1000
+@end example
+@end itemize
-This filter accepts the following parameters:
+@section asetnsamples
-@table @option
+Set the number of samples per each output audio frame.
-@item expr
-The expression which is evaluated into the output timebase.
+The last output packet may contain a different number of samples, as
+the filter will flush all the remaining samples when the input audio
+signal its end.
-@end table
+The filter accepts the following options:
-The expression can contain the constants @var{PI}, @var{E}, @var{PHI}, @var{AVTB} (the
-default timebase), @var{intb} (the input timebase), and @var{sr} (the sample rate,
-audio only).
+@table @option
-The default value for the input is @var{intb}.
+@item nb_out_samples, n
+Set the number of frames per each output audio frame. The number is
+intended as the number of samples @emph{per each channel}.
+Default value is 1024.
-Some examples:
+@item pad, p
+If set to 1, the filter will pad the last audio frame with zeroes, so
+that the last frame will contain the same number of samples as the
+previous ones. Default value is 1.
+@end table
+For example, to set the number of per-frame samples to 1234 and
+disable padding for the last frame, use:
@example
-# Set the timebase to 1/25:
-settb=1/25
-
-# Set the timebase to 1/10:
-settb=0.1
+asetnsamples=n=1234:p=0
+@end example
-# Set the timebase to 1001/1000:
-settb=1+0.001
+@section asetrate
-# Set the timebase to 2*intb:
-settb=2*intb
+Set the sample rate without altering the PCM data.
+This will result in a change of speed and pitch.
-# Set the default timebase value:
-settb=AVTB
+The filter accepts the following options:
-# Set the timebase to twice the sample rate:
-asettb=sr*2
-@end example
+@table @option
+@item sample_rate, r
+Set the output sample rate. Default is 44100 Hz.
+@end table
@section ashowinfo
@@ -305,7 +880,7 @@ The input audio is not modified.
The shown line contains a sequence of key/value pairs of the form
@var{key}:@var{value}.
-It accepts the following parameters:
+The following values are shown in the output:
@table @option
@item n
@@ -318,6 +893,10 @@ depends on the filter input pad, and is usually 1/@var{sample_rate}.
@item pts_time
The presentation timestamp of the input frame in seconds.
+@item pos
+position of the frame in the input stream, -1 if this information in
+unavailable and/or meaningless (for example in case of synthetic audio)
+
@item fmt
The sample format.
@@ -338,23 +917,95 @@ audio, the data is treated as if all the planes were concatenated.
A list of Adler-32 checksums for each data plane.
@end table
-@section asplit
+@anchor{astats}
+@section astats
-Split input audio into several identical outputs.
+Display time domain statistical information about the audio channels.
+Statistics are calculated and displayed for each audio channel and,
+where applicable, an overall figure is also given.
-It accepts a single parameter, which specifies the number of outputs. If
-unspecified, it defaults to 2.
+It accepts the following option:
+@table @option
+@item length
+Short window length in seconds, used for peak and trough RMS measurement.
+Default is @code{0.05} (50 milliseconds). Allowed range is @code{[0.1 - 10]}.
+@end table
+
+A description of each shown parameter follows:
-For example,
+@table @option
+@item DC offset
+Mean amplitude displacement from zero.
+
+@item Min level
+Minimal sample level.
+
+@item Max level
+Maximal sample level.
+
+@item Peak level dB
+@item RMS level dB
+Standard peak and RMS level measured in dBFS.
+
+@item RMS peak dB
+@item RMS trough dB
+Peak and trough values for RMS level measured over a short window.
+
+@item Crest factor
+Standard ratio of peak to RMS level (note: not in dB).
+
+@item Flat factor
+Flatness (i.e. consecutive samples with the same value) of the signal at its peak levels
+(i.e. either @var{Min level} or @var{Max level}).
+
+@item Peak count
+Number of occasions (not the number of samples) that the signal attained either
+@var{Min level} or @var{Max level}.
+@end table
+
+@section astreamsync
+
+Forward two audio streams and control the order the buffers are forwarded.
+
+The filter accepts the following options:
+
+@table @option
+@item expr, e
+Set the expression deciding which stream should be
+forwarded next: if the result is negative, the first stream is forwarded; if
+the result is positive or zero, the second stream is forwarded. It can use
+the following variables:
+
+@table @var
+@item b1 b2
+number of buffers forwarded so far on each stream
+@item s1 s2
+number of samples forwarded so far on each stream
+@item t1 t2
+current timestamp of each stream
+@end table
+
+The default value is @code{t1-t2}, which means to always forward the stream
+that has a smaller timestamp.
+@end table
+
+@subsection Examples
+
+Stress-test @code{amerge} by randomly sending buffers on the wrong
+input, while avoiding too much of a desynchronization:
@example
-avconv -i INPUT -filter_complex asplit=5 OUTPUT
+amovie=file.ogg [a] ; amovie=file.mp3 [b] ;
+[a] [b] astreamsync=(2*random(1))-1+tanh(5*(t1-t2)) [a2] [b2] ;
+[a2] [b2] amerge
@end example
-will create 5 copies of the input audio.
@section asyncts
+
Synchronize audio data with timestamps by squeezing/stretching it and/or
dropping samples/adding silence when needed.
+This filter is not built by default, please use @ref{aresample} to do squeezing/stretching.
+
It accepts the following parameters:
@table @option
@@ -381,7 +1032,32 @@ with a negative PTS due to encoder delay.
@end table
+@section atempo
+
+Adjust audio tempo.
+
+The filter accepts exactly one parameter, the audio tempo. If not
+specified then the filter will assume nominal 1.0 tempo. Tempo must
+be in the [0.5, 2.0] range.
+
+@subsection Examples
+
+@itemize
+@item
+Slow down audio to 80% tempo:
+@example
+atempo=0.8
+@end example
+
+@item
+To speed up audio to 125% tempo:
+@example
+atempo=1.25
+@end example
+@end itemize
+
@section atrim
+
Trim the input so that the output contains one continuous subpart of the input.
It accepts the following parameters:
@@ -391,7 +1067,7 @@ Timestamp (in seconds) of the start of the section to keep. I.e. the audio
sample with the timestamp @var{start} will be the first sample in the output.
@item end
-Timestamp (in seconds) of the first audio sample that will be dropped. I.e. the
+Specify time of the first audio sample that will be dropped, i.e. the
audio sample immediately preceding the one with the timestamp @var{end} will be
the last sample in the output.
@@ -413,6 +1089,10 @@ The number of the first sample that should be output.
The number of the first sample that should be dropped.
@end table
+@option{start}, @option{end}, and @option{duration} are expressed as time
+duration specifications; see
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}.
+
Note that the first two sets of the start/end options and the @option{duration}
option look at the frame timestamp, while the _sample options simply count the
samples that pass through the filter. So start/end_pts and start/end_sample will
@@ -434,17 +1114,122 @@ Examples:
@item
Drop everything except the second minute of input:
@example
-avconv -i INPUT -af atrim=60:120
+ffmpeg -i INPUT -af atrim=60:120
@end example
@item
Keep only the first 1000 samples:
@example
-avconv -i INPUT -af atrim=end_sample=1000
+ffmpeg -i INPUT -af atrim=end_sample=1000
@end example
@end itemize
+@section bandpass
+
+Apply a two-pole Butterworth band-pass filter with central
+frequency @var{frequency}, and (3dB-point) band-width width.
+The @var{csg} option selects a constant skirt gain (peak gain = Q)
+instead of the default: constant 0dB peak gain.
+The filter roll off at 6dB per octave (20dB per decade).
+
+The filter accepts the following options:
+
+@table @option
+@item frequency, f
+Set the filter's central frequency. Default is @code{3000}.
+
+@item csg
+Constant skirt gain if set to 1. Defaults to 0.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Specify the band-width of a filter in width_type units.
+@end table
+
+@section bandreject
+
+Apply a two-pole Butterworth band-reject filter with central
+frequency @var{frequency}, and (3dB-point) band-width @var{width}.
+The filter roll off at 6dB per octave (20dB per decade).
+
+The filter accepts the following options:
+
+@table @option
+@item frequency, f
+Set the filter's central frequency. Default is @code{3000}.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Specify the band-width of a filter in width_type units.
+@end table
+
+@section bass
+
+Boost or cut the bass (lower) frequencies of the audio using a two-pole
+shelving filter with a response similar to that of a standard
+hi-fi's tone-controls. This is also known as shelving equalisation (EQ).
+
+The filter accepts the following options:
+
+@table @option
+@item gain, g
+Give the gain at 0 Hz. Its useful range is about -20
+(for a large cut) to +20 (for a large boost).
+Beware of clipping when using a positive gain.
+
+@item frequency, f
+Set the filter's central frequency and so can be used
+to extend or reduce the frequency range to be boosted or cut.
+The default value is @code{100} Hz.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Determine how steep is the filter's shelf transition.
+@end table
+
+@section biquad
+
+Apply a biquad IIR filter with the given coefficients.
+Where @var{b0}, @var{b1}, @var{b2} and @var{a0}, @var{a1}, @var{a2}
+are the numerator and denominator coefficients respectively.
+
@section bs2b
Bauer stereo to binaural transformation, which improves headphone listening of
stereo audio records.
@@ -475,7 +1260,42 @@ Feed level (in Hz).
@end table
+@section channelmap
+
+Remap input channels to new locations.
+
+It accepts the following parameters:
+@table @option
+@item channel_layout
+The channel layout of the output stream.
+
+@item map
+Map channels from input to output. The argument is a '|'-separated list of
+mappings, each in the @code{@var{in_channel}-@var{out_channel}} or
+@var{in_channel} form. @var{in_channel} can be either the name of the input
+channel (e.g. FL for front left) or its index in the input channel layout.
+@var{out_channel} is the name of the output channel or its index in the output
+channel layout. If @var{out_channel} is not given then it is implicitly an
+index, starting with zero and increasing by one for each mapping.
+@end table
+
+If no mapping is present, the filter will implicitly map input channels to
+output channels, preserving indices.
+
+For example, assuming a 5.1+downmix input MOV file,
+@example
+ffmpeg -i in.mov -filter 'channelmap=map=DL-FL|DR-FR' out.wav
+@end example
+will create an output WAV file tagged as stereo from the downmix channels of
+the input.
+
+To fix a 5.1 WAV improperly encoded in AAC's native channel order
+@example
+ffmpeg -i in.wav -filter 'channelmap=1|2|0|5|3|4:channel_layout=5.1' out.wav
+@end example
+
@section channelsplit
+
Split each channel from an input audio stream into a separate output stream.
It accepts the following parameters:
@@ -486,53 +1306,75 @@ The channel layout of the input stream. The default is "stereo".
For example, assuming a stereo input MP3 file,
@example
-avconv -i in.mp3 -filter_complex channelsplit out.mkv
+ffmpeg -i in.mp3 -filter_complex channelsplit out.mkv
@end example
will create an output Matroska file with two audio streams, one containing only
the left channel and the other the right channel.
Split a 5.1 WAV file into per-channel files:
@example
-avconv -i in.wav -filter_complex
+ffmpeg -i in.wav -filter_complex
'channelsplit=channel_layout=5.1[FL][FR][FC][LFE][SL][SR]'
-map '[FL]' front_left.wav -map '[FR]' front_right.wav -map '[FC]'
front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]'
side_right.wav
@end example
-@section channelmap
-Remap input channels to new locations.
+@section chorus
+Add a chorus effect to the audio.
+
+Can make a single vocal sound like a chorus, but can also be applied to instrumentation.
+
+Chorus resembles an echo effect with a short delay, but whereas with echo the delay is
+constant, with chorus, it is varied using using sinusoidal or triangular modulation.
+The modulation depth defines the range the modulated delay is played before or after
+the delay. Hence the delayed sound will sound slower or faster, that is the delayed
+sound tuned around the original one, like in a chorus where some vocals are slightly
+off key.
It accepts the following parameters:
@table @option
-@item channel_layout
-The channel layout of the output stream.
+@item in_gain
+Set input gain. Default is 0.4.
-@item map
-Map channels from input to output. The argument is a '|'-separated list of
-mappings, each in the @code{@var{in_channel}-@var{out_channel}} or
-@var{in_channel} form. @var{in_channel} can be either the name of the input
-channel (e.g. FL for front left) or its index in the input channel layout.
-@var{out_channel} is the name of the output channel or its index in the output
-channel layout. If @var{out_channel} is not given then it is implicitly an
-index, starting with zero and increasing by one for each mapping.
+@item out_gain
+Set output gain. Default is 0.4.
+
+@item delays
+Set delays. A typical delay is around 40ms to 60ms.
+
+@item decays
+Set decays.
+
+@item speeds
+Set speeds.
+
+@item depths
+Set depths.
@end table
-If no mapping is present, the filter will implicitly map input channels to
-output channels, preserving indices.
+@subsection Examples
-For example, assuming a 5.1+downmix input MOV file,
+@itemize
+@item
+A single delay:
@example
-avconv -i in.mov -filter 'channelmap=map=DL-FL|DR-FR' out.wav
+chorus=0.7:0.9:55:0.4:0.25:2
@end example
-will create an output WAV file tagged as stereo from the downmix channels of
-the input.
-To fix a 5.1 WAV improperly encoded in AAC's native channel order
+@item
+Two delays:
@example
-avconv -i in.wav -filter 'channelmap=1|2|0|5|3|4:channel_layout=5.1' out.wav
+chorus=0.6:0.9:50|60:0.4|0.32:0.25|0.4:2|1.3
@end example
+@item
+Fuller sounding chorus with three delays:
+@example
+chorus=0.5:0.9:50|60|40:0.4|0.32|0.3:0.25|0.4|0.3:2|2.3|1.3
+@end example
+@end itemize
+
@section compand
Compress or expand the audio's dynamic range.
@@ -553,7 +1395,8 @@ a typical value for decay is 0.8 seconds.
@item points
A list of points for the transfer function, specified in dB relative to the
maximum possible signal amplitude. Each key points list must be defined using
-the following syntax: @code{x0/y0|x1/y1|x2/y2|....}
+the following syntax: @code{x0/y0|x1/y1|x2/y2|....} or
+@code{x0/y0 x1/y1 x2/y2 ....}
The input values must be in strictly increasing order but the transfer function
does not have to be monotonically rising. The point @code{0/0} is assumed but
@@ -607,7 +1450,159 @@ compand=.1|.1:.1|.1:-45.1/-45.1|-45/-900|0/-900:.01:45:-90:.1
@end example
@end itemize
+@section dcshift
+Apply a DC shift to the audio.
+
+This can be useful to remove a DC offset (caused perhaps by a hardware problem
+in the recording chain) from the audio. The effect of a DC offset is reduced
+headroom and hence volume. The @ref{astats} filter can be used to determine if
+a signal has a DC offset.
+
+@table @option
+@item shift
+Set the DC shift, allowed range is [-1, 1]. It indicates the amount to shift
+the audio.
+
+@item limitergain
+Optional. It should have a value much less than 1 (e.g. 0.05 or 0.02) and is
+used to prevent clipping.
+@end table
+
+@section earwax
+
+Make audio easier to listen to on headphones.
+
+This filter adds `cues' to 44.1kHz stereo (i.e. audio CD format) audio
+so that when listened to on headphones the stereo image is moved from
+inside your head (standard for headphones) to outside and in front of
+the listener (standard for speakers).
+
+Ported from SoX.
+
+@section equalizer
+
+Apply a two-pole peaking equalisation (EQ) filter. With this
+filter, the signal-level at and around a selected frequency can
+be increased or decreased, whilst (unlike bandpass and bandreject
+filters) that at all other frequencies is unchanged.
+
+In order to produce complex equalisation curves, this filter can
+be given several times, each with a different central frequency.
+
+The filter accepts the following options:
+
+@table @option
+@item frequency, f
+Set the filter's central frequency in Hz.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Specify the band-width of a filter in width_type units.
+
+@item gain, g
+Set the required gain or attenuation in dB.
+Beware of clipping when using a positive gain.
+@end table
+
+@subsection Examples
+@itemize
+@item
+Attenuate 10 dB at 1000 Hz, with a bandwidth of 200 Hz:
+@example
+equalizer=f=1000:width_type=h:width=200:g=-10
+@end example
+
+@item
+Apply 2 dB gain at 1000 Hz with Q 1 and attenuate 5 dB at 100 Hz with Q 2:
+@example
+equalizer=f=1000:width_type=q:width=1:g=2,equalizer=f=100:width_type=q:width=2:g=-5
+@end example
+@end itemize
+
+@section flanger
+Apply a flanging effect to the audio.
+
+The filter accepts the following options:
+
+@table @option
+@item delay
+Set base delay in milliseconds. Range from 0 to 30. Default value is 0.
+
+@item depth
+Set added swep delay in milliseconds. Range from 0 to 10. Default value is 2.
+
+@item regen
+Set percentage regeneration (delayed signal feedback). Range from -95 to 95.
+Default value is 0.
+
+@item width
+Set percentage of delayed signal mixed with original. Range from 0 to 100.
+Default value is 71.
+
+@item speed
+Set sweeps per second (Hz). Range from 0.1 to 10. Default value is 0.5.
+
+@item shape
+Set swept wave shape, can be @var{triangular} or @var{sinusoidal}.
+Default value is @var{sinusoidal}.
+
+@item phase
+Set swept wave percentage-shift for multi channel. Range from 0 to 100.
+Default value is 25.
+
+@item interp
+Set delay-line interpolation, @var{linear} or @var{quadratic}.
+Default is @var{linear}.
+@end table
+
+@section highpass
+
+Apply a high-pass filter with 3dB point frequency.
+The filter can be either single-pole, or double-pole (the default).
+The filter roll off at 6dB per pole per octave (20dB per pole per decade).
+
+The filter accepts the following options:
+
+@table @option
+@item frequency, f
+Set frequency in Hz. Default is 3000.
+
+@item poles, p
+Set number of poles. Default is 2.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Specify the band-width of a filter in width_type units.
+Applies only to double-pole filter.
+The default is 0.707q and gives a Butterworth response.
+@end table
+
@section join
+
Join multiple input streams into one multi-channel stream.
It accepts the following parameters:
@@ -634,21 +1629,404 @@ and if that fails it picks the first unused input channel.
Join 3 inputs (with properly set channel layouts):
@example
-avconv -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT
+ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT
@end example
Build a 5.1 output from 6 single-channel streams:
@example
-avconv -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
+ffmpeg -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
'join=inputs=6:channel_layout=5.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-SL|4.0-SR|5.0-LFE'
out
@end example
+@section ladspa
+
+Load a LADSPA (Linux Audio Developer's Simple Plugin API) plugin.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-ladspa}.
+
+@table @option
+@item file, f
+Specifies the name of LADSPA plugin library to load. If the environment
+variable @env{LADSPA_PATH} is defined, the LADSPA plugin is searched in
+each one of the directories specified by the colon separated list in
+@env{LADSPA_PATH}, otherwise in the standard LADSPA paths, which are in
+this order: @file{HOME/.ladspa/lib/}, @file{/usr/local/lib/ladspa/},
+@file{/usr/lib/ladspa/}.
+
+@item plugin, p
+Specifies the plugin within the library. Some libraries contain only
+one plugin, but others contain many of them. If this is not set filter
+will list all available plugins within the specified library.
+
+@item controls, c
+Set the '|' separated list of controls which are zero or more floating point
+values that determine the behavior of the loaded plugin (for example delay,
+threshold or gain).
+Controls need to be defined using the following syntax:
+c0=@var{value0}|c1=@var{value1}|c2=@var{value2}|..., where
+@var{valuei} is the value set on the @var{i}-th control.
+If @option{controls} is set to @code{help}, all available controls and
+their valid ranges are printed.
+
+@item sample_rate, s
+Specify the sample rate, default to 44100. Only used if plugin have
+zero inputs.
+
+@item nb_samples, n
+Set the number of samples per channel per each output frame, default
+is 1024. Only used if plugin have zero inputs.
+
+@item duration, d
+Set the minimum duration of the sourced audio. See
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
+Note that the resulting duration may be greater than the specified duration,
+as the generated audio is always cut at the end of a complete frame.
+If not specified, or the expressed duration is negative, the audio is
+supposed to be generated forever.
+Only used if plugin have zero inputs.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+List all available plugins within amp (LADSPA example plugin) library:
+@example
+ladspa=file=amp
+@end example
+
+@item
+List all available controls and their valid ranges for @code{vcf_notch}
+plugin from @code{VCF} library:
+@example
+ladspa=f=vcf:p=vcf_notch:c=help
+@end example
+
+@item
+Simulate low quality audio equipment using @code{Computer Music Toolkit} (CMT)
+plugin library:
+@example
+ladspa=file=cmt:plugin=lofi:controls=c0=22|c1=12|c2=12
+@end example
+
+@item
+Add reverberation to the audio using TAP-plugins
+(Tom's Audio Processing plugins):
+@example
+ladspa=file=tap_reverb:tap_reverb
+@end example
+
+@item
+Generate white noise, with 0.2 amplitude:
+@example
+ladspa=file=cmt:noise_source_white:c=c0=.2
+@end example
+
+@item
+Generate 20 bpm clicks using plugin @code{C* Click - Metronome} from the
+@code{C* Audio Plugin Suite} (CAPS) library:
+@example
+ladspa=file=caps:Click:c=c1=20'
+@end example
+
+@item
+Apply @code{C* Eq10X2 - Stereo 10-band equaliser} effect:
+@example
+ladspa=caps:Eq10X2:c=c0=-48|c9=-24|c3=12|c4=2
+@end example
+@end itemize
+
+@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item cN
+Modify the @var{N}-th control value.
+
+If the specified value is not valid, it is ignored and prior one is kept.
+@end table
+
+@section lowpass
+
+Apply a low-pass filter with 3dB point frequency.
+The filter can be either single-pole or double-pole (the default).
+The filter roll off at 6dB per pole per octave (20dB per pole per decade).
+
+The filter accepts the following options:
+
+@table @option
+@item frequency, f
+Set frequency in Hz. Default is 500.
+
+@item poles, p
+Set number of poles. Default is 2.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Specify the band-width of a filter in width_type units.
+Applies only to double-pole filter.
+The default is 0.707q and gives a Butterworth response.
+@end table
+
+@section pan
+
+Mix channels with specific gain levels. The filter accepts the output
+channel layout followed by a set of channels definitions.
+
+This filter is also designed to efficiently remap the channels of an audio
+stream.
+
+The filter accepts parameters of the form:
+"@var{l}|@var{outdef}|@var{outdef}|..."
+
+@table @option
+@item l
+output channel layout or number of channels
+
+@item outdef
+output channel specification, of the form:
+"@var{out_name}=[@var{gain}*]@var{in_name}[+[@var{gain}*]@var{in_name}...]"
+
+@item out_name
+output channel to define, either a channel name (FL, FR, etc.) or a channel
+number (c0, c1, etc.)
+
+@item gain
+multiplicative coefficient for the channel, 1 leaving the volume unchanged
+
+@item in_name
+input channel to use, see out_name for details; it is not possible to mix
+named and numbered input channels
+@end table
+
+If the `=' in a channel specification is replaced by `<', then the gains for
+that specification will be renormalized so that the total is 1, thus
+avoiding clipping noise.
+
+@subsection Mixing examples
+
+For example, if you want to down-mix from stereo to mono, but with a bigger
+factor for the left channel:
+@example
+pan=1c|c0=0.9*c0+0.1*c1
+@end example
+
+A customized down-mix to stereo that works automatically for 3-, 4-, 5- and
+7-channels surround:
+@example
+pan=stereo| FL < FL + 0.5*FC + 0.6*BL + 0.6*SL | FR < FR + 0.5*FC + 0.6*BR + 0.6*SR
+@end example
+
+Note that @command{ffmpeg} integrates a default down-mix (and up-mix) system
+that should be preferred (see "-ac" option) unless you have very specific
+needs.
+
+@subsection Remapping examples
+
+The channel remapping will be effective if, and only if:
+
+@itemize
+@item gain coefficients are zeroes or ones,
+@item only one input per channel output,
+@end itemize
+
+If all these conditions are satisfied, the filter will notify the user ("Pure
+channel mapping detected"), and use an optimized and lossless method to do the
+remapping.
+
+For example, if you have a 5.1 source and want a stereo audio stream by
+dropping the extra channels:
+@example
+pan="stereo| c0=FL | c1=FR"
+@end example
+
+Given the same source, you can also switch front left and front right channels
+and keep the input channel layout:
+@example
+pan="5.1| c0=c1 | c1=c0 | c2=c2 | c3=c3 | c4=c4 | c5=c5"
+@end example
+
+If the input is a stereo audio stream, you can mute the front left channel (and
+still keep the stereo channel layout) with:
+@example
+pan="stereo|c1=c1"
+@end example
+
+Still with a stereo audio stream input, you can copy the right channel in both
+front left and right:
+@example
+pan="stereo| c0=FR | c1=FR"
+@end example
+
+@section replaygain
+
+ReplayGain scanner filter. This filter takes an audio stream as an input and
+outputs it unchanged.
+At end of filtering it displays @code{track_gain} and @code{track_peak}.
+
@section resample
+
Convert the audio sample format, sample rate and channel layout. It is
-not meant to be used directly; it is inserted automatically by libavfilter
-whenever conversion is needed. Use the @var{aformat} filter to force a specific
-conversion.
+not meant to be used directly.
+
+@section silencedetect
+
+Detect silence in an audio stream.
+
+This filter logs a message when it detects that the input audio volume is less
+or equal to a noise tolerance value for a duration greater or equal to the
+minimum detected noise duration.
+
+The printed times and duration are expressed in seconds.
+
+The filter accepts the following options:
+
+@table @option
+@item duration, d
+Set silence duration until notification (default is 2 seconds).
+
+@item noise, n
+Set noise tolerance. Can be specified in dB (in case "dB" is appended to the
+specified value) or amplitude ratio. Default is -60dB, or 0.001.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Detect 5 seconds of silence with -50dB noise tolerance:
+@example
+silencedetect=n=-50dB:d=5
+@end example
+
+@item
+Complete example with @command{ffmpeg} to detect silence with 0.0001 noise
+tolerance in @file{silence.mp3}:
+@example
+ffmpeg -i silence.mp3 -af silencedetect=noise=0.0001 -f null -
+@end example
+@end itemize
+
+@section silenceremove
+
+Remove silence from the beginning, middle or end of the audio.
+
+The filter accepts the following options:
+
+@table @option
+@item start_periods
+This value is used to indicate if audio should be trimmed at beginning of
+the audio. A value of zero indicates no silence should be trimmed from the
+beginning. When specifying a non-zero value, it trims audio up until it
+finds non-silence. Normally, when trimming silence from beginning of audio
+the @var{start_periods} will be @code{1} but it can be increased to higher
+values to trim all audio up to specific count of non-silence periods.
+Default value is @code{0}.
+
+@item start_duration
+Specify the amount of time that non-silence must be detected before it stops
+trimming audio. By increasing the duration, bursts of noises can be treated
+as silence and trimmed off. Default value is @code{0}.
+
+@item start_threshold
+This indicates what sample value should be treated as silence. For digital
+audio, a value of @code{0} may be fine but for audio recorded from analog,
+you may wish to increase the value to account for background noise.
+Can be specified in dB (in case "dB" is appended to the specified value)
+or amplitude ratio. Default value is @code{0}.
+
+@item stop_periods
+Set the count for trimming silence from the end of audio.
+To remove silence from the middle of a file, specify a @var{stop_periods}
+that is negative. This value is then treated as a positive value and is
+used to indicate the effect should restart processing as specified by
+@var{start_periods}, making it suitable for removing periods of silence
+in the middle of the audio.
+Default value is @code{0}.
+
+@item stop_duration
+Specify a duration of silence that must exist before audio is not copied any
+more. By specifying a higher duration, silence that is wanted can be left in
+the audio.
+Default value is @code{0}.
+
+@item stop_threshold
+This is the same as @option{start_threshold} but for trimming silence from
+the end of audio.
+Can be specified in dB (in case "dB" is appended to the specified value)
+or amplitude ratio. Default value is @code{0}.
+
+@item leave_silence
+This indicate that @var{stop_duration} length of audio should be left intact
+at the beginning of each period of silence.
+For example, if you want to remove long pauses between words but do not want
+to remove the pauses completely. Default value is @code{0}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+The following example shows how this filter can be used to start a recording
+that does not contain the delay at the start which usually occurs between
+pressing the record button and the start of the performance:
+@example
+silenceremove=1:5:0.02
+@end example
+@end itemize
+
+@section treble
+
+Boost or cut treble (upper) frequencies of the audio using a two-pole
+shelving filter with a response similar to that of a standard
+hi-fi's tone-controls. This is also known as shelving equalisation (EQ).
+
+The filter accepts the following options:
+
+@table @option
+@item gain, g
+Give the gain at whichever is the lower of ~22 kHz and the
+Nyquist frequency. Its useful range is about -20 (for a large cut)
+to +20 (for a large boost). Beware of clipping when using a positive gain.
+
+@item frequency, f
+Set the filter's central frequency and so can be used
+to extend or reduce the frequency range to be boosted or cut.
+The default value is @code{3000} Hz.
+
+@item width_type
+Set method to specify band-width of filter.
+@table @option
+@item h
+Hz
+@item q
+Q-Factor
+@item o
+octave
+@item s
+slope
+@end table
+
+@item width, w
+Determine how steep is the filter's shelf transition.
+@end table
@section volume
@@ -658,7 +2036,7 @@ It accepts the following parameters:
@table @option
@item volume
-This expresses how the audio volume will be increased or decreased.
+Set audio volume expression.
Output values are clipped to the maximum value.
@@ -667,7 +2045,7 @@ The output audio volume is given by the relation:
@var{output_volume} = @var{volume} * @var{input_volume}
@end example
-The default value for @var{volume} is 1.0.
+The default value for @var{volume} is "1.0".
@item precision
This parameter represents the mathematical precision.
@@ -706,6 +2084,65 @@ Pre-amplification gain in dB to apply to the selected replaygain gain.
Default value for @var{replaygain_preamp} is 0.0.
+@item eval
+Set when the volume expression is evaluated.
+
+It accepts the following values:
+@table @samp
+@item once
+only evaluate expression once during the filter initialization, or
+when the @samp{volume} command is sent
+
+@item frame
+evaluate expression for each incoming frame
+@end table
+
+Default value is @samp{once}.
+@end table
+
+The volume expression can contain the following parameters.
+
+@table @option
+@item n
+frame number (starting at zero)
+@item nb_channels
+number of channels
+@item nb_consumed_samples
+number of samples consumed by the filter
+@item nb_samples
+number of samples in the current frame
+@item pos
+original frame position in the file
+@item pts
+frame PTS
+@item sample_rate
+sample rate
+@item startpts
+PTS at start of stream
+@item startt
+time at start of stream
+@item t
+frame time
+@item tb
+timestamp timebase
+@item volume
+last set volume value
+@end table
+
+Note that when @option{eval} is set to @samp{once} only the
+@var{sample_rate} and @var{tb} variables are available, all other
+variables will evaluate to NAN.
+
+@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item volume
+Modify the volume 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.
@item replaygain_noclip
Prevent clipping by limiting the gain applied.
@@ -724,53 +2161,80 @@ volume=volume=1/2
volume=volume=-6.0206dB
@end example
+In all the above example the named key for @option{volume} can be
+omitted, for example like in:
+@example
+volume=0.5
+@end example
+
@item
Increase input audio power by 6 decibels using fixed-point precision:
@example
volume=volume=6dB:precision=fixed
@end example
+
+@item
+Fade volume after time 10 with an annihilation period of 5 seconds:
+@example
+volume='if(lt(t,10),1,max(1-(t-10)/5,0))':eval=frame
+@end example
@end itemize
-@c man end AUDIO FILTERS
+@section volumedetect
-@chapter Audio Sources
-@c man begin AUDIO SOURCES
+Detect the volume of the input video.
-Below is a description of the currently available audio sources.
+The filter has no parameters. The input is not modified. Statistics about
+the volume will be printed in the log when the input stream end is reached.
-@section anullsrc
+In particular it will show the mean volume (root mean square), maximum
+volume (on a per-sample basis), and the beginning of a histogram of the
+registered volume values (from the maximum value to a cumulated 1/1000 of
+the samples).
-The null audio source; it never returns audio frames. It is mainly useful as a
-template and for use in analysis / debugging tools.
+All volumes are in decibels relative to the maximum PCM value.
-It accepts, as an optional parameter, a string of the form
-@var{sample_rate}:@var{channel_layout}.
+@subsection Examples
-@var{sample_rate} specifies the sample rate, and defaults to 44100.
+Here is an excerpt of the output:
+@example
+[Parsed_volumedetect_0 @ 0xa23120] mean_volume: -27 dB
+[Parsed_volumedetect_0 @ 0xa23120] max_volume: -4 dB
+[Parsed_volumedetect_0 @ 0xa23120] histogram_4db: 6
+[Parsed_volumedetect_0 @ 0xa23120] histogram_5db: 62
+[Parsed_volumedetect_0 @ 0xa23120] histogram_6db: 286
+[Parsed_volumedetect_0 @ 0xa23120] histogram_7db: 1042
+[Parsed_volumedetect_0 @ 0xa23120] histogram_8db: 2551
+[Parsed_volumedetect_0 @ 0xa23120] histogram_9db: 4609
+[Parsed_volumedetect_0 @ 0xa23120] histogram_10db: 8409
+@end example
-@var{channel_layout} specifies the channel layout, and can be either an
-integer or a string representing a channel layout. The default value
-of @var{channel_layout} is 3, which corresponds to CH_LAYOUT_STEREO.
+It means that:
+@itemize
+@item
+The mean square energy is approximately -27 dB, or 10^-2.7.
+@item
+The largest sample is at -4 dB, or more precisely between -4 dB and -5 dB.
+@item
+There are 6 samples at -4 dB, 62 at -5 dB, 286 at -6 dB, etc.
+@end itemize
-Check the channel_layout_map definition in
-@file{libavutil/channel_layout.c} for the mapping between strings and
-channel layout values.
+In other words, raising the volume by +4 dB does not cause any clipping,
+raising it by +5 dB causes clipping for 6 samples, etc.
-Some examples:
-@example
-# Set the sample rate to 48000 Hz and the channel layout to CH_LAYOUT_MONO
-anullsrc=48000:4
+@c man end AUDIO FILTERS
-# The same as above
-anullsrc=48000:mono
-@end example
+@chapter Audio Sources
+@c man begin AUDIO SOURCES
+
+Below is a description of the currently available audio sources.
@section abuffer
+
Buffer audio frames, and make them available to the filter chain.
-This source is not intended to be part of user-supplied graph descriptions; it
-is for insertion by calling programs, through the interface defined in
-@file{libavfilter/buffersrc.h}.
+This source is mainly intended for a programmatic use, in particular
+through the interface defined in @file{libavfilter/asrc_abuffer.h}.
It accepts the following parameters:
@table @option
@@ -780,18 +2244,295 @@ The timebase which will be used for timestamps of submitted frames. It must be
either a floating-point number or in @var{numerator}/@var{denominator} form.
@item sample_rate
-The audio sample rate.
+The sample rate of the incoming audio buffers.
@item sample_fmt
-The name of the sample format, as returned by @code{av_get_sample_fmt_name()}.
+The sample format of the incoming audio buffers.
+Either a sample format name or its corresponding integer representation from
+the enum AVSampleFormat in @file{libavutil/samplefmt.h}
@item channel_layout
-The channel layout of the audio data, in the form that can be accepted by
-@code{av_get_channel_layout()}.
+The channel layout of the incoming audio buffers.
+Either a channel layout name from channel_layout_map in
+@file{libavutil/channel_layout.c} or its corresponding integer representation
+from the AV_CH_LAYOUT_* macros in @file{libavutil/channel_layout.h}
+
+@item channels
+The number of channels of the incoming audio buffers.
+If both @var{channels} and @var{channel_layout} are specified, then they
+must be consistent.
+
+@end table
+
+@subsection Examples
+
+@example
+abuffer=sample_rate=44100:sample_fmt=s16p:channel_layout=stereo
+@end example
+
+will instruct the source to accept planar 16bit signed stereo at 44100Hz.
+Since the sample format with name "s16p" corresponds to the number
+6 and the "stereo" channel layout corresponds to the value 0x3, this is
+equivalent to:
+@example
+abuffer=sample_rate=44100:sample_fmt=6:channel_layout=0x3
+@end example
+
+@section aevalsrc
+
+Generate an audio signal specified by an expression.
+
+This source accepts in input one or more expressions (one for each
+channel), which are evaluated and used to generate a corresponding
+audio signal.
+
+This source accepts the following options:
+
+@table @option
+@item exprs
+Set the '|'-separated expressions list for each separate channel. In case the
+@option{channel_layout} option is not specified, the selected channel layout
+depends on the number of provided expressions. Otherwise the last
+specified expression is applied to the remaining output channels.
+
+@item channel_layout, c
+Set the channel layout. The number of channels in the specified layout
+must be equal to the number of specified expressions.
+
+@item duration, d
+Set the minimum duration of the sourced audio. See
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
+Note that the resulting duration may be greater than the specified
+duration, as the generated audio is always cut at the end of a
+complete frame.
+
+If not specified, or the expressed duration is negative, the audio is
+supposed to be generated forever.
+
+@item nb_samples, n
+Set the number of samples per channel per each output frame,
+default to 1024.
+
+@item sample_rate, s
+Specify the sample rate, default to 44100.
+@end table
+
+Each expression in @var{exprs} can contain the following constants:
+
+@table @option
+@item n
+number of the evaluated sample, starting from 0
+
+@item t
+time of the evaluated sample expressed in seconds, starting from 0
+
+@item s
+sample rate
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Generate silence:
+@example
+aevalsrc=0
+@end example
+
+@item
+Generate a sin signal with frequency of 440 Hz, set sample rate to
+8000 Hz:
+@example
+aevalsrc="sin(440*2*PI*t):s=8000"
+@end example
+
+@item
+Generate a two channels signal, specify the channel layout (Front
+Center + Back Center) explicitly:
+@example
+aevalsrc="sin(420*2*PI*t)|cos(430*2*PI*t):c=FC|BC"
+@end example
+
+@item
+Generate white noise:
+@example
+aevalsrc="-2+random(0)"
+@end example
+
+@item
+Generate an amplitude modulated signal:
+@example
+aevalsrc="sin(10*2*PI*t)*sin(880*2*PI*t)"
+@end example
+
+@item
+Generate 2.5 Hz binaural beats on a 360 Hz carrier:
+@example
+aevalsrc="0.1*sin(2*PI*(360-2.5/2)*t) | 0.1*sin(2*PI*(360+2.5/2)*t)"
+@end example
+
+@end itemize
+
+@section anullsrc
+
+The null audio source, return unprocessed audio frames. It is mainly useful
+as a template and to be employed in analysis / debugging tools, or as
+the source for filters which ignore the input data (for example the sox
+synth filter).
+
+This source accepts the following options:
+
+@table @option
+
+@item channel_layout, cl
+
+Specifies the channel layout, and can be either an integer or a string
+representing a channel layout. The default value of @var{channel_layout}
+is "stereo".
+
+Check the channel_layout_map definition in
+@file{libavutil/channel_layout.c} for the mapping between strings and
+channel layout values.
+
+@item sample_rate, r
+Specifies the sample rate, and defaults to 44100.
+
+@item nb_samples, n
+Set the number of samples per requested frames.
+
@end table
+@subsection Examples
+
+@itemize
+@item
+Set the sample rate to 48000 Hz and the channel layout to AV_CH_LAYOUT_MONO.
+@example
+anullsrc=r=48000:cl=4
+@end example
+
+@item
+Do the same operation with a more obvious syntax:
+@example
+anullsrc=r=48000:cl=mono
+@end example
+@end itemize
+
All the parameters need to be explicitly defined.
+@section flite
+
+Synthesize a voice utterance using the libflite library.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libflite}.
+
+Note that the flite library is not thread-safe.
+
+The filter accepts the following options:
+
+@table @option
+
+@item list_voices
+If set to 1, list the names of the available voices and exit
+immediately. Default value is 0.
+
+@item nb_samples, n
+Set the maximum number of samples per frame. Default value is 512.
+
+@item textfile
+Set the filename containing the text to speak.
+
+@item text
+Set the text to speak.
+
+@item voice, v
+Set the voice to use for the speech synthesis. Default value is
+@code{kal}. See also the @var{list_voices} option.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Read from file @file{speech.txt}, and synthesize the text using the
+standard flite voice:
+@example
+flite=textfile=speech.txt
+@end example
+
+@item
+Read the specified text selecting the @code{slt} voice:
+@example
+flite=text='So fare thee well, poor devil of a Sub-Sub, whose commentator I am':voice=slt
+@end example
+
+@item
+Input text to ffmpeg:
+@example
+ffmpeg -f lavfi -i flite=text='So fare thee well, poor devil of a Sub-Sub, whose commentator I am':voice=slt
+@end example
+
+@item
+Make @file{ffplay} speak the specified text, using @code{flite} and
+the @code{lavfi} device:
+@example
+ffplay -f lavfi flite=text='No more be grieved for which that thou hast done.'
+@end example
+@end itemize
+
+For more information about libflite, check:
+@url{http://www.speech.cs.cmu.edu/flite/}
+
+@section sine
+
+Generate an audio signal made of a sine wave with amplitude 1/8.
+
+The audio signal is bit-exact.
+
+The filter accepts the following options:
+
+@table @option
+
+@item frequency, f
+Set the carrier frequency. Default is 440 Hz.
+
+@item beep_factor, b
+Enable a periodic beep every second with frequency @var{beep_factor} times
+the carrier frequency. Default is 0, meaning the beep is disabled.
+
+@item sample_rate, r
+Specify the sample rate, default is 44100.
+
+@item duration, d
+Specify the duration of the generated audio stream.
+
+@item samples_per_frame
+Set the number of samples per output frame, default is 1024.
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Generate a simple 440 Hz sine wave:
+@example
+sine
+@end example
+
+@item
+Generate a 220 Hz sine wave with a 880 Hz beep each second, for 5 seconds:
+@example
+sine=220:4:d=5
+sine=f=220:b=4:d=5
+sine=frequency=220:beep_factor=4:duration=5
+@end example
+
+@end itemize
+
@c man end AUDIO SOURCES
@chapter Audio Sinks
@@ -799,31 +2540,155 @@ All the parameters need to be explicitly defined.
Below is a description of the currently available audio sinks.
+@section abuffersink
+
+Buffer audio frames, and make them available to the end of filter chain.
+
+This sink is mainly intended for programmatic use, in particular
+through the interface defined in @file{libavfilter/buffersink.h}
+or the options system.
+
+It accepts a pointer to an AVABufferSinkContext structure, which
+defines the incoming buffers' formats, to be passed as the opaque
+parameter to @code{avfilter_init_filter} for initialization.
@section anullsink
Null audio sink; do absolutely nothing with the input audio. It is
mainly useful as a template and for use in analysis / debugging
tools.
-@section abuffersink
-This sink is intended for programmatic use. Frames that arrive on this sink can
-be retrieved by the calling program, using the interface defined in
-@file{libavfilter/buffersink.h}.
-
-It does not accept any parameters.
-
@c man end AUDIO SINKS
@chapter Video Filters
@c man begin VIDEO FILTERS
-When you configure your Libav build, you can disable any of the
-existing filters using --disable-filters.
+When you configure your FFmpeg build, you can disable any of the
+existing filters using @code{--disable-filters}.
The configure output will show the video filters included in your
build.
Below is a description of the currently available video filters.
+@section alphaextract
+
+Extract the alpha component from the input as a grayscale video. This
+is especially useful with the @var{alphamerge} filter.
+
+@section alphamerge
+
+Add or replace the alpha component of the primary input with the
+grayscale value of a second input. This is intended for use with
+@var{alphaextract} to allow the transmission or storage of frame
+sequences that have alpha in a format that doesn't support an alpha
+channel.
+
+For example, to reconstruct full frames from a normal YUV-encoded video
+and a separate video created with @var{alphaextract}, you might use:
+@example
+movie=in_alpha.mkv [alpha]; [in][alpha] alphamerge [out]
+@end example
+
+Since this filter is designed for reconstruction, it operates on frame
+sequences without considering timestamps, and terminates when either
+input reaches end of stream. This will cause problems if your encoding
+pipeline drops frames. If you're trying to apply an image as an
+overlay to a video stream, consider the @var{overlay} filter instead.
+
+@section ass
+
+Same as the @ref{subtitles} filter, except that it doesn't require libavcodec
+and libavformat to work. On the other hand, it is limited to ASS (Advanced
+Substation Alpha) subtitles files.
+
+This filter accepts the following option in addition to the common options from
+the @ref{subtitles} filter:
+
+@table @option
+@item shaping
+Set the shaping engine
+
+Available values are:
+@table @samp
+@item auto
+The default libass shaping engine, which is the best available.
+@item simple
+Fast, font-agnostic shaper that can do only substitutions
+@item complex
+Slower shaper using OpenType for substitutions and positioning
+@end table
+
+The default is @code{auto}.
+@end table
+
+@section bbox
+
+Compute the bounding box for the non-black pixels in the input frame
+luminance plane.
+
+This filter computes the bounding box containing all the pixels with a
+luminance value greater than the minimum allowed value.
+The parameters describing the bounding box are printed on the filter
+log.
+
+The filter accepts the following option:
+
+@table @option
+@item min_val
+Set the minimal luminance value. Default is @code{16}.
+@end table
+
+@section blackdetect
+
+Detect video intervals that are (almost) completely black. Can be
+useful to detect chapter transitions, commercials, or invalid
+recordings. Output lines contains the time for the start, end and
+duration of the detected black interval expressed in seconds.
+
+In order to display the output lines, you need to set the loglevel at
+least to the AV_LOG_INFO value.
+
+The filter accepts the following options:
+
+@table @option
+@item black_min_duration, d
+Set the minimum detected black duration expressed in seconds. It must
+be a non-negative floating point number.
+
+Default value is 2.0.
+
+@item picture_black_ratio_th, pic_th
+Set the threshold for considering a picture "black".
+Express the minimum value for the ratio:
+@example
+@var{nb_black_pixels} / @var{nb_pixels}
+@end example
+
+for which a picture is considered black.
+Default value is 0.98.
+
+@item pixel_black_th, pix_th
+Set the threshold for considering a pixel "black".
+
+The threshold expresses the maximum pixel luminance value for which a
+pixel is considered "black". The provided value is scaled according to
+the following equation:
+@example
+@var{absolute_threshold} = @var{luminance_minimum_value} + @var{pixel_black_th} * @var{luminance_range_size}
+@end example
+
+@var{luminance_range_size} and @var{luminance_minimum_value} depend on
+the input video format, the range is [0-255] for YUV full-range
+formats and [16-235] for YUV non full-range formats.
+
+Default value is 0.10.
+@end table
+
+The following example sets the maximum pixel threshold to the minimum
+value, and detects only black intervals of 2 or more seconds:
+@example
+blackdetect=d=2:pix_th=0.00
+@end example
+
@section blackframe
Detect frames that are (almost) completely black. Can be useful to
@@ -840,13 +2705,163 @@ It accepts the following parameters:
@item amount
The percentage of the pixels that have to be below the threshold; it defaults to
-98.
+@code{98}.
-@item threshold
-The threshold below which a pixel value is considered black; it defaults to 32.
+@item threshold, thresh
+The threshold below which a pixel value is considered black; it defaults to
+@code{32}.
+
+@end table
+
+@section blend, tblend
+
+Blend two video frames into each other.
+
+The @code{blend} filter takes two input streams and outputs one
+stream, the first input is the "top" layer and second input is
+"bottom" layer. Output terminates when shortest input terminates.
+
+The @code{tblend} (time blend) filter takes two consecutive frames
+from one single stream, and outputs the result obtained by blending
+the new frame on top of the old frame.
+A description of the accepted options follows.
+
+@table @option
+@item c0_mode
+@item c1_mode
+@item c2_mode
+@item c3_mode
+@item all_mode
+Set blend mode for specific pixel component or all pixel components in case
+of @var{all_mode}. Default value is @code{normal}.
+
+Available values for component modes are:
+@table @samp
+@item addition
+@item and
+@item average
+@item burn
+@item darken
+@item difference
+@item difference128
+@item divide
+@item dodge
+@item exclusion
+@item hardlight
+@item lighten
+@item multiply
+@item negation
+@item normal
+@item or
+@item overlay
+@item phoenix
+@item pinlight
+@item reflect
+@item screen
+@item softlight
+@item subtract
+@item vividlight
+@item xor
@end table
+@item c0_opacity
+@item c1_opacity
+@item c2_opacity
+@item c3_opacity
+@item all_opacity
+Set blend opacity for specific pixel component or all pixel components in case
+of @var{all_opacity}. Only used in combination with pixel component blend modes.
+
+@item c0_expr
+@item c1_expr
+@item c2_expr
+@item c3_expr
+@item all_expr
+Set blend expression for specific pixel component or all pixel components in case
+of @var{all_expr}. Note that related mode options will be ignored if those are set.
+
+The expressions can use the following variables:
+
+@table @option
+@item N
+The sequential number of the filtered frame, starting from @code{0}.
+
+@item X
+@item Y
+the coordinates of the current sample
+
+@item W
+@item H
+the width and height of currently filtered plane
+
+@item SW
+@item SH
+Width and height scale depending on the currently filtered plane. It is the
+ratio between the corresponding luma plane number of pixels and the current
+plane ones. E.g. for YUV4:2:0 the values are @code{1,1} for the luma plane, and
+@code{0.5,0.5} for chroma planes.
+
+@item T
+Time of the current frame, expressed in seconds.
+
+@item TOP, A
+Value of pixel component at current location for first video frame (top layer).
+
+@item BOTTOM, B
+Value of pixel component at current location for second video frame (bottom layer).
+@end table
+
+@item shortest
+Force termination when the shortest input terminates. Default is
+@code{0}. This option is only defined for the @code{blend} filter.
+
+@item repeatlast
+Continue applying the last bottom frame after the end of the stream. A value of
+@code{0} disable the filter after the last frame of the bottom layer is reached.
+Default is @code{1}. This option is only defined for the @code{blend} filter.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Apply transition from bottom layer to top layer in first 10 seconds:
+@example
+blend=all_expr='A*(if(gte(T,10),1,T/10))+B*(1-(if(gte(T,10),1,T/10)))'
+@end example
+
+@item
+Apply 1x1 checkerboard effect:
+@example
+blend=all_expr='if(eq(mod(X,2),mod(Y,2)),A,B)'
+@end example
+
+@item
+Apply uncover left effect:
+@example
+blend=all_expr='if(gte(N*SW+X,W),A,B)'
+@end example
+
+@item
+Apply uncover down effect:
+@example
+blend=all_expr='if(gte(Y-N*SH,0),A,B)'
+@end example
+
+@item
+Apply uncover up-left effect:
+@example
+blend=all_expr='if(gte(T*SH*40+Y,H)*gte((T*40*SW+X)*W/H,W),A,B)'
+@end example
+
+@item
+Display differences between the current and the previous frame:
+@example
+tblend=all_mode=difference128
+@end example
+@end itemize
+
@section boxblur
Apply a boxblur algorithm to the input video.
@@ -855,58 +2870,77 @@ It accepts the following parameters:
@table @option
-@item luma_radius
-@item luma_power
-@item chroma_radius
-@item chroma_power
-@item alpha_radius
-@item alpha_power
+@item luma_radius, lr
+@item luma_power, lp
+@item chroma_radius, cr
+@item chroma_power, cp
+@item alpha_radius, ar
+@item alpha_power, ap
@end table
-The chroma and alpha parameters are optional. If not specified, they default
-to the corresponding values set for @var{luma_radius} and
-@var{luma_power}.
+A description of the accepted options follows.
-@var{luma_radius}, @var{chroma_radius}, and @var{alpha_radius} represent
-the radius in pixels of the box used for blurring the corresponding
-input plane. They are expressions, and can contain the following
-constants:
@table @option
-@item w, h
+@item luma_radius, lr
+@item chroma_radius, cr
+@item alpha_radius, ar
+Set an expression for the box radius in pixels used for blurring the
+corresponding input plane.
+
+The radius value must be a non-negative number, and must not be
+greater than the value of the expression @code{min(w,h)/2} for the
+luma and alpha planes, and of @code{min(cw,ch)/2} for the chroma
+planes.
+
+Default value for @option{luma_radius} is "2". If not specified,
+@option{chroma_radius} and @option{alpha_radius} default to the
+corresponding value set for @option{luma_radius}.
+
+The expressions can contain the following constants:
+@table @option
+@item w
+@item h
The input width and height in pixels.
-@item cw, ch
+@item cw
+@item ch
The input chroma image width and height in pixels.
-@item hsub, vsub
+@item hsub
+@item vsub
The horizontal and vertical chroma subsample values. For example, for the
pixel format "yuv422p", @var{hsub} is 2 and @var{vsub} is 1.
@end table
-The radius must be a non-negative number, and must not be greater than
-the value of the expression @code{min(w,h)/2} for the luma and alpha planes,
-and of @code{min(cw,ch)/2} for the chroma planes.
+@item luma_power, lp
+@item chroma_power, cp
+@item alpha_power, ap
+Specify how many times the boxblur filter is applied to the
+corresponding plane.
-@var{luma_power}, @var{chroma_power}, and @var{alpha_power} represent
-how many times the boxblur filter is applied to the corresponding
-plane.
+Default value for @option{luma_power} is 2. If not specified,
+@option{chroma_power} and @option{alpha_power} default to the
+corresponding value set for @option{luma_power}.
-Some examples:
+A value of 0 will disable the effect.
+@end table
-@itemize
+@subsection Examples
+@itemize
@item
Apply a boxblur filter with the luma, chroma, and alpha radii
set to 2:
@example
boxblur=luma_radius=2:luma_power=1
+boxblur=2:1
@end example
@item
Set the luma radius to 2, and alpha and chroma radius to 0:
@example
-boxblur=2:1:0:0:0:0
+boxblur=2:1:cr=0:ar=0
@end example
@item
@@ -914,9 +2948,246 @@ Set the luma and chroma radii to a fraction of the video dimension:
@example
boxblur=luma_radius=min(h\,w)/10:luma_power=1:chroma_radius=min(cw\,ch)/10:chroma_power=1
@end example
+@end itemize
+
+@section codecview
+
+Visualize information exported by some codecs.
+
+Some codecs can export information through frames using side-data or other
+means. For example, some MPEG based codecs export motion vectors through the
+@var{export_mvs} flag in the codec @option{flags2} option.
+
+The filter accepts the following option:
+
+@table @option
+@item mv
+Set motion vectors to visualize.
+
+Available flags for @var{mv} are:
+
+@table @samp
+@item pf
+forward predicted MVs of P-frames
+@item bf
+forward predicted MVs of B-frames
+@item bb
+backward predicted MVs of B-frames
+@end table
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Visualizes multi-directionals MVs from P and B-Frames using @command{ffplay}:
+@example
+ffplay -flags2 +export_mvs input.mpg -vf codecview=mv=pf+bf+bb
+@end example
+@end itemize
+
+@section colorbalance
+Modify intensity of primary colors (red, green and blue) of input frames.
+
+The filter allows an input frame to be adjusted in the shadows, midtones or highlights
+regions for the red-cyan, green-magenta or blue-yellow balance.
+
+A positive adjustment value shifts the balance towards the primary color, a negative
+value towards the complementary color.
+
+The filter accepts the following options:
+
+@table @option
+@item rs
+@item gs
+@item bs
+Adjust red, green and blue shadows (darkest pixels).
+
+@item rm
+@item gm
+@item bm
+Adjust red, green and blue midtones (medium pixels).
+
+@item rh
+@item gh
+@item bh
+Adjust red, green and blue highlights (brightest pixels).
+
+Allowed ranges for options are @code{[-1.0, 1.0]}. Defaults are @code{0}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Add red color cast to shadows:
+@example
+colorbalance=rs=.3
+@end example
+@end itemize
+
+@section colorlevels
+
+Adjust video input frames using levels.
+
+The filter accepts the following options:
+
+@table @option
+@item rimin
+@item gimin
+@item bimin
+@item aimin
+Adjust red, green, blue and alpha input black point.
+Allowed ranges for options are @code{[-1.0, 1.0]}. Defaults are @code{0}.
+
+@item rimax
+@item gimax
+@item bimax
+@item aimax
+Adjust red, green, blue and alpha input white point.
+Allowed ranges for options are @code{[-1.0, 1.0]}. Defaults are @code{1}.
+
+Input levels are used to lighten highlights (bright tones), darken shadows
+(dark tones), change the balance of bright and dark tones.
+
+@item romin
+@item gomin
+@item bomin
+@item aomin
+Adjust red, green, blue and alpha output black point.
+Allowed ranges for options are @code{[0, 1.0]}. Defaults are @code{0}.
+
+@item romax
+@item gomax
+@item bomax
+@item aomax
+Adjust red, green, blue and alpha output white point.
+Allowed ranges for options are @code{[0, 1.0]}. Defaults are @code{1}.
+
+Output levels allows manual selection of a constrained output level range.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Make video output darker:
+@example
+colorlevels=rimin=0.058:gimin=0.058:bimin=0.058
+@end example
+
+@item
+Increase contrast:
+@example
+colorlevels=rimin=0.039:gimin=0.039:bimin=0.039:rimax=0.96:gimax=0.96:bimax=0.96
+@end example
+
+@item
+Make video output lighter:
+@example
+colorlevels=rimax=0.902:gimax=0.902:bimax=0.902
+@end example
+
+@item
+Increase brightness:
+@example
+colorlevels=romin=0.5:gomin=0.5:bomin=0.5
+@end example
+@end itemize
+
+@section colorchannelmixer
+
+Adjust video input frames by re-mixing color channels.
+
+This filter modifies a color channel by adding the values associated to
+the other channels of the same pixels. For example if the value to
+modify is red, the output value will be:
+@example
+@var{red}=@var{red}*@var{rr} + @var{blue}*@var{rb} + @var{green}*@var{rg} + @var{alpha}*@var{ra}
+@end example
+
+The filter accepts the following options:
+@table @option
+@item rr
+@item rg
+@item rb
+@item ra
+Adjust contribution of input red, green, blue and alpha channels for output red channel.
+Default is @code{1} for @var{rr}, and @code{0} for @var{rg}, @var{rb} and @var{ra}.
+
+@item gr
+@item gg
+@item gb
+@item ga
+Adjust contribution of input red, green, blue and alpha channels for output green channel.
+Default is @code{1} for @var{gg}, and @code{0} for @var{gr}, @var{gb} and @var{ga}.
+
+@item br
+@item bg
+@item bb
+@item ba
+Adjust contribution of input red, green, blue and alpha channels for output blue channel.
+Default is @code{1} for @var{bb}, and @code{0} for @var{br}, @var{bg} and @var{ba}.
+
+@item ar
+@item ag
+@item ab
+@item aa
+Adjust contribution of input red, green, blue and alpha channels for output alpha channel.
+Default is @code{1} for @var{aa}, and @code{0} for @var{ar}, @var{ag} and @var{ab}.
+
+Allowed ranges for options are @code{[-2.0, 2.0]}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Convert source to grayscale:
+@example
+colorchannelmixer=.3:.4:.3:0:.3:.4:.3:0:.3:.4:.3
+@end example
+@item
+Simulate sepia tones:
+@example
+colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131
+@end example
@end itemize
+@section colormatrix
+
+Convert color matrix.
+
+The filter accepts the following options:
+
+@table @option
+@item src
+@item dst
+Specify the source and destination color matrix. Both values must be
+specified.
+
+The accepted values are:
+@table @samp
+@item bt709
+BT.709
+
+@item bt601
+BT.601
+
+@item smpte240m
+SMPTE-240M
+
+@item fcc
+FCC
+@end table
+@end table
+
+For example to convert from BT.601 to SMPTE-240M, use the command:
+@example
+colormatrix=bt601:smpte240m
+@end example
+
@section copy
Copy the input source unchanged to the output. This is mainly useful for
@@ -929,60 +3200,82 @@ Crop the input video to given dimensions.
It accepts the following parameters:
@table @option
+@item w, out_w
+The width of the output video. It defaults to @code{iw}.
+This expression is evaluated only once during the filter
+configuration.
-@item out_w
-The width of the output video.
-
-@item out_h
-The height of the output video.
+@item h, out_h
+The height of the output video. It defaults to @code{ih}.
+This expression is evaluated only once during the filter
+configuration.
@item x
The horizontal position, in the input video, of the left edge of the output
-video.
+video. It defaults to @code{(in_w-out_w)/2}.
+This expression is evaluated per-frame.
@item y
The vertical position, in the input video, of the top edge of the output video.
+It defaults to @code{(in_h-out_h)/2}.
+This expression is evaluated per-frame.
+@item keep_aspect
+If set to 1 will force the output display aspect ratio
+to be the same of the input, by changing the output sample aspect
+ratio. It defaults to 0.
@end table
-The parameters are expressions containing the following constants:
+The @var{out_w}, @var{out_h}, @var{x}, @var{y} parameters are
+expressions containing the following constants:
@table @option
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
-
-@item x, y
+@item x
+@item y
The computed values for @var{x} and @var{y}. They are evaluated for
each new frame.
-@item in_w, in_h
+@item in_w
+@item in_h
The input width and height.
-@item iw, ih
+@item iw
+@item ih
These are the same as @var{in_w} and @var{in_h}.
-@item out_w, out_h
+@item out_w
+@item out_h
The output (cropped) width and height.
-@item ow, oh
+@item ow
+@item oh
These are the same as @var{out_w} and @var{out_h}.
+@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}
+
+@item hsub
+@item vsub
+horizontal and vertical chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+
@item n
The number of the input frame, starting from 0.
+@item pos
+the position in the file of the input frame, NAN if unknown
+
@item t
The timestamp expressed in seconds. It's NAN if the input timestamp is unknown.
@end table
-The @var{out_w} and @var{out_h} parameters specify the expressions for
-the width and height of the output (cropped) video. They are only
-evaluated during the configuration of the filter.
-
-The default value of @var{out_w} is "in_w", and the default value of
-@var{out_h} is "in_h".
-
The expression for @var{out_w} may depend on the value of @var{out_h},
and the expression for @var{out_h} may depend on @var{out_w}, but they
cannot depend on @var{x} and @var{y}, as @var{x} and @var{y} are
@@ -993,48 +3286,87 @@ position of the top-left corner of the output (non-cropped) area. They
are evaluated for each frame. If the evaluated value is not valid, it
is approximated to the nearest valid value.
-The default value of @var{x} is "(in_w-out_w)/2", and the default
-value for @var{y} is "(in_h-out_h)/2", which set the cropped area at
-the center of the input image.
-
The expression for @var{x} may depend on @var{y}, and the expression
for @var{y} may depend on @var{x}.
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Crop area with size 100x100 at position (12,34).
@example
-# Crop the central input area with size 100x100
-crop=out_w=100:out_h=100
+crop=100:100:12:34
+@end example
-# Crop the central input area with size 2/3 of the input video
-"crop=out_w=2/3*in_w:out_h=2/3*in_h"
+Using named options, the example above becomes:
+@example
+crop=w=100:h=100:x=12:y=34
+@end example
-# Crop the input video central square
+@item
+Crop the central input area with size 100x100:
+@example
+crop=100:100
+@end example
+
+@item
+Crop the central input area with size 2/3 of the input video:
+@example
+crop=2/3*in_w:2/3*in_h
+@end example
+
+@item
+Crop the input video central square:
+@example
crop=out_w=in_h
+crop=in_h
+@end example
-# Delimit the rectangle with the top-left corner placed at position
-# 100:100 and the right-bottom corner corresponding to the right-bottom
-# corner of the input image
-crop=out_w=in_w-100:out_h=in_h-100:x=100:y=100
+@item
+Delimit the rectangle with the top-left corner placed at position
+100:100 and the right-bottom corner corresponding to the right-bottom
+corner of the input image.
+@example
+crop=in_w-100:in_h-100:100:100
+@end example
-# Crop 10 pixels from the left and right borders, and 20 pixels from
-# the top and bottom borders
-"crop=out_w=in_w-2*10:out_h=in_h-2*20"
+@item
+Crop 10 pixels from the left and right borders, and 20 pixels from
+the top and bottom borders
+@example
+crop=in_w-2*10:in_h-2*20
+@end example
-# Keep only the bottom right quarter of the input image
-"crop=out_w=in_w/2:out_h=in_h/2:x=in_w/2:y=in_h/2"
+@item
+Keep only the bottom right quarter of the input image:
+@example
+crop=in_w/2:in_h/2:in_w/2:in_h/2
+@end example
-# Crop height for getting Greek harmony
-"crop=out_w=in_w:out_h=1/PHI*in_w"
+@item
+Crop height for getting Greek harmony:
+@example
+crop=in_w:1/PHI*in_w
+@end example
-# Trembling effect
-"crop=in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(n/10):(in_h-out_h)/2 +((in_h-out_h)/2)*sin(n/7)"
+@item
+Apply trembling effect:
+@example
+crop=in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(n/10):(in_h-out_h)/2 +((in_h-out_h)/2)*sin(n/7)
+@end example
-# Erratic camera effect depending on timestamp
-"crop=out_w=in_w/2:out_h=in_h/2:x=(in_w-out_w)/2+((in_w-out_w)/2)*sin(t*10):y=(in_h-out_h)/2 +((in_h-out_h)/2)*sin(t*13)"
+@item
+Apply erratic camera effect depending on timestamp:
+@example
+crop=in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(t*10):(in_h-out_h)/2 +((in_h-out_h)/2)*sin(t*13)"
+@end example
-# Set x depending on the value of y
-"crop=in_w/2:in_h/2:y:10+10*sin(n/10)"
+@item
+Set x depending on the value of y:
+@example
+crop=in_w/2:in_h/2:y:10+10*sin(n/10)
@end example
+@end itemize
@section cropdetect
@@ -1049,8 +3381,11 @@ It accepts the following parameters:
@table @option
@item limit
-The threshold, an optional parameter between nothing (0) and
-everything (255). It defaults to 24.
+Set higher black value threshold, which can be optionally specified
+from nothing (0) to everything (255 for 8bit based formats). An intensity
+value greater to the set value is considered non-black. It defaults to 24.
+You can also specify a value between 0.0 and 1.0 which will be scaled depending
+on the bitdepth of the pixel format.
@item round
The value which the width/height should be divisible by. It defaults to
@@ -1058,16 +3393,269 @@ The value which the width/height should be divisible by. It defaults to
get only even dimensions (needed for 4:2:2 video). 16 is best when
encoding to most video codecs.
-@item reset
-A counter that determines how many frames cropdetect will reset
-the previously detected largest video area after. It will then start over
-and detect the current optimal crop area. It defaults to 0.
+@item reset_count, reset
+Set the counter that determines after how many frames cropdetect will
+reset the previously detected largest video area and start over to
+detect the current optimal crop area. Default value is 0.
This can be useful when channel logos distort the video area. 0
indicates 'never reset', and returns the largest area encountered during
playback.
@end table
+@anchor{curves}
+@section curves
+
+Apply color adjustments using curves.
+
+This filter is similar to the Adobe Photoshop and GIMP curves tools. Each
+component (red, green and blue) has its values defined by @var{N} key points
+tied from each other using a smooth curve. The x-axis represents the pixel
+values from the input frame, and the y-axis the new pixel values to be set for
+the output frame.
+
+By default, a component curve is defined by the two points @var{(0;0)} and
+@var{(1;1)}. This creates a straight line where each original pixel value is
+"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 (using a natural cubic spline interpolation) 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 @var{x} and @var{y} values must
+be in the @var{[0;1]} interval. If the computed curves happened to go outside
+the vector spaces, the values will be clipped accordingly.
+
+If there is no key point defined in @code{x=0}, the filter will automatically
+insert a @var{(0;0)} point. In the same way, if there is no key point defined
+in @code{x=1}, the filter will automatically insert a @var{(1;1)} point.
+
+The filter accepts the following options:
+
+@table @option
+@item preset
+Select one of the available color presets. This option can be used in addition
+to the @option{r}, @option{g}, @option{b} parameters; in this case, the later
+options takes priority on the preset values.
+Available presets are:
+@table @samp
+@item none
+@item color_negative
+@item cross_process
+@item darker
+@item increase_contrast
+@item lighter
+@item linear_contrast
+@item medium_contrast
+@item negative
+@item strong_contrast
+@item vintage
+@end table
+Default is @code{none}.
+@item master, m
+Set the master key points. These points will define a second pass mapping. It
+is sometimes called a "luminance" or "value" mapping. It can be used with
+@option{r}, @option{g}, @option{b} or @option{all} since it acts like a
+post-processing LUT.
+@item red, r
+Set the key points for the red component.
+@item green, g
+Set the key points for the green component.
+@item blue, b
+Set the key points for the blue component.
+@item all
+Set the key points for all components (not including master).
+Can be used in addition to the other key points component
+options. In this case, the unset component(s) will fallback on this
+@option{all} setting.
+@item psfile
+Specify a Photoshop curves file (@code{.asv}) to import the settings from.
+@end table
+
+To avoid some filtergraph syntax conflicts, each key points list need to be
+defined using the following syntax: @code{x0/y0 x1/y1 x2/y2 ...}.
+
+@subsection Examples
+
+@itemize
+@item
+Increase slightly the middle level of blue:
+@example
+curves=blue='0.5/0.58'
+@end example
+
+@item
+Vintage effect:
+@example
+curves=r='0/0.11 .42/.51 1/0.95':g='0.50/0.48':b='0/0.22 .49/.44 1/0.8'
+@end example
+Here we obtain the following coordinates for each components:
+@table @var
+@item red
+@code{(0;0.11) (0.42;0.51) (1;0.95)}
+@item green
+@code{(0;0) (0.50;0.48) (1;1)}
+@item blue
+@code{(0;0.22) (0.49;0.44) (1;0.80)}
+@end table
+
+@item
+The previous example can also be achieved with the associated built-in preset:
+@example
+curves=preset=vintage
+@end example
+
+@item
+Or simply:
+@example
+curves=vintage
+@end example
+
+@item
+Use a Photoshop preset and redefine the points of the green component:
+@example
+curves=psfile='MyCurvesPresets/purple.asv':green='0.45/0.53'
+@end example
+@end itemize
+
+@section dctdnoiz
+
+Denoise frames using 2D DCT (frequency domain filtering).
+
+This filter is not designed for real time.
+
+The filter accepts the following options:
+
+@table @option
+@item sigma, s
+Set the noise sigma constant.
+
+This @var{sigma} defines a hard threshold of @code{3 * sigma}; every DCT
+coefficient (absolute value) below this threshold with be dropped.
+
+If you need a more advanced filtering, see @option{expr}.
+
+Default is @code{0}.
+
+@item overlap
+Set number overlapping pixels for each block. Since the filter can be slow, you
+may want to reduce this value, at the cost of a less effective filter and the
+risk of various artefacts.
+
+If the overlapping value doesn't permit processing the whole input width or
+height, a warning will be displayed and according borders won't be denoised.
+
+Default value is @var{blocksize}-1, which is the best possible setting.
+
+@item expr, e
+Set the coefficient factor expression.
+
+For each coefficient of a DCT block, this expression will be evaluated as a
+multiplier value for the coefficient.
+
+If this is option is set, the @option{sigma} option will be ignored.
+
+The absolute value of the coefficient can be accessed through the @var{c}
+variable.
+
+@item n
+Set the @var{blocksize} using the number of bits. @code{1<<@var{n}} defines the
+@var{blocksize}, which is the width and height of the processed blocks.
+
+The default value is @var{3} (8x8) and can be raised to @var{4} for a
+@var{blocksize} of 16x16. Note that changing this setting has huge consequences
+on the speed processing. Also, a larger block size does not necessarily means a
+better de-noising.
+@end table
+
+@subsection Examples
+
+Apply a denoise with a @option{sigma} of @code{4.5}:
+@example
+dctdnoiz=4.5
+@end example
+
+The same operation can be achieved using the expression system:
+@example
+dctdnoiz=e='gte(c, 4.5*3)'
+@end example
+
+Violent denoise using a block size of @code{16x16}:
+@example
+dctdnoiz=15:n=4
+@end example
+
+@anchor{decimate}
+@section decimate
+
+Drop duplicated frames at regular intervals.
+
+The filter accepts the following options:
+
+@table @option
+@item cycle
+Set the number of frames from which one will be dropped. Setting this to
+@var{N} means one frame in every batch of @var{N} frames will be dropped.
+Default is @code{5}.
+
+@item dupthresh
+Set the threshold for duplicate detection. If the difference metric for a frame
+is less than or equal to this value, then it is declared as duplicate. Default
+is @code{1.1}
+
+@item scthresh
+Set scene change threshold. Default is @code{15}.
+
+@item blockx
+@item blocky
+Set the size of the x and y-axis blocks used during metric calculations.
+Larger blocks give better noise suppression, but also give worse detection of
+small movements. Must be a power of two. Default is @code{32}.
+
+@item ppsrc
+Mark main input as a pre-processed input and activate clean source input
+stream. This allows the input to be pre-processed with various filters to help
+the metrics calculation while keeping the frame selection lossless. When set to
+@code{1}, the first stream is for the pre-processed input, and the second
+stream is the clean source from where the kept frames are chosen. Default is
+@code{0}.
+
+@item chroma
+Set whether or not chroma is considered in the metric calculations. Default is
+@code{1}.
+@end table
+
+@section dejudder
+
+Remove judder produced by partially interlaced telecined content.
+
+Judder can be introduced, for instance, by @ref{pullup} filter. If the original
+source was partially telecined content then the output of @code{pullup,dejudder}
+will have a variable frame rate. May change the recorded frame rate of the
+container. Aside from that change, this filter will not affect constant frame
+rate video.
+
+The option available in this filter is:
+@table @option
+
+@item cycle
+Specify the length of the window over which the judder repeats.
+
+Accepts any integer greater than 1. Useful values are:
+@table @samp
+
+@item 4
+If the original was telecined from 24 to 30 fps (Film to NTSC).
+
+@item 5
+If the original was telecined from 25 to 30 fps (PAL to NTSC).
+
+@item 20
+If a mixture of the two.
+@end table
+
+The default is @samp{4}.
+@end table
+
@section delogo
Suppress a TV station logo by a simple interpolation of the surrounding
@@ -1077,11 +3665,13 @@ pixels. Just set a rectangle covering the logo and watch it disappear
It accepts the following parameters:
@table @option
-@item x, y
+@item x
+@item y
Specify the top left corner coordinates of the logo. They must be
specified.
-@item w, h
+@item w
+@item h
Specify the width and height of the logo to clear. They must be
specified.
@@ -1091,15 +3681,19 @@ Specify the thickness of the fuzzy edge of the rectangle (added to
@item show
When set to 1, a green rectangle is drawn on the screen to simplify
-finding the right @var{x}, @var{y}, @var{w}, @var{h} parameters, and
-@var{band} is set to 4. The default value is 0.
+finding the right @var{x}, @var{y}, @var{w}, and @var{h} parameters.
+The default value is 0.
+
+The rectangle is drawn on the outermost pixels which will be (partly)
+replaced with interpolated values. The values of the next pixels
+immediately outside this rectangle in each direction will be used to
+compute the interpolated pixel values inside the rectangle.
@end table
-An example:
+@subsection Examples
@itemize
-
@item
Set a rectangle covering the area with top left corner coordinates 0,0
and size 100x77, and a band of size 10:
@@ -1109,6 +3703,113 @@ delogo=x=0:y=0:w=100:h=77:band=10
@end itemize
+@section deshake
+
+Attempt to fix small changes in horizontal and/or vertical shift. This
+filter helps remove camera shake from hand-holding a camera, bumping a
+tripod, moving on a vehicle, etc.
+
+The filter accepts the following options:
+
+@table @option
+
+@item x
+@item y
+@item w
+@item h
+Specify a rectangular area where to limit the search for motion
+vectors.
+If desired the search for motion vectors can be limited to a
+rectangular area of the frame defined by its top left corner, width
+and height. These parameters have the same meaning as the drawbox
+filter which can be used to visualise the position of the bounding
+box.
+
+This is useful when simultaneous movement of subjects within the frame
+might be confused for camera motion by the motion vector search.
+
+If any or all of @var{x}, @var{y}, @var{w} and @var{h} are set to -1
+then the full frame is used. This allows later options to be set
+without specifying the bounding box for the motion vector search.
+
+Default - search the whole frame.
+
+@item rx
+@item ry
+Specify the maximum extent of movement in x and y directions in the
+range 0-64 pixels. Default 16.
+
+@item edge
+Specify how to generate pixels to fill blanks at the edge of the
+frame. Available values are:
+@table @samp
+@item blank, 0
+Fill zeroes at blank locations
+@item original, 1
+Original image at blank locations
+@item clamp, 2
+Extruded edge value at blank locations
+@item mirror, 3
+Mirrored edge at blank locations
+@end table
+Default value is @samp{mirror}.
+
+@item blocksize
+Specify the blocksize to use for motion search. Range 4-128 pixels,
+default 8.
+
+@item contrast
+Specify the contrast threshold for blocks. Only blocks with more than
+the specified contrast (difference between darkest and lightest
+pixels) will be considered. Range 1-255, default 125.
+
+@item search
+Specify the search strategy. Available values are:
+@table @samp
+@item exhaustive, 0
+Set exhaustive search
+@item less, 1
+Set less exhaustive search.
+@end table
+Default value is @samp{exhaustive}.
+
+@item filename
+If set then a detailed log of the motion search is written to the
+specified file.
+
+@item opencl
+If set to 1, specify using OpenCL capabilities, only available if
+FFmpeg was configured with @code{--enable-opencl}. Default value is 0.
+
+@end table
+
+@section detelecine
+
+Apply an exact inverse of the telecine operation. It requires a predefined
+pattern specified using the pattern option which must be the same as that passed
+to the telecine filter.
+
+This filter accepts the following options:
+
+@table @option
+@item first_field
+@table @samp
+@item top, t
+top field first
+@item bottom, b
+bottom field first
+The default value is @code{top}.
+@end table
+
+@item pattern
+A string of numbers representing the pulldown pattern you wish to apply.
+The default value is @code{23}.
+
+@item start_frame
+A number representing position of the first frame with respect to the telecine
+pattern. This is to be used if the stream is cut. The default value is @code{0}.
+@end table
+
@section drawbox
Draw a colored box on the input image.
@@ -1116,141 +3817,265 @@ 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 x, y
-Specify the top left corner coordinates of the box. It defaults to 0.
-
-@item width, height
-Specify the width and height of the box; if 0 they are interpreted as
+@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
-Specify the color of the box to write. It can be the name of a color
-(case insensitive match) or a 0xRRGGBB[AA] sequence.
+@item color, c
+Specify the color of the box to write. For the general syntax of this option,
+check the "Color" section in the ffmpeg-utils manual. If the special
+value @code{invert} is used, the box edge color is the same as the
+video with inverted luma.
+
+@item thickness, t
+The expression which sets the thickness of the box edge. Default value is @code{3}.
+
+See below for the list of accepted constants.
@end table
-Some examples:
+The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the
+following constants:
+
+@table @option
+@item dar
+The input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}.
+
+@item hsub
+@item vsub
+horizontal and vertical chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+
+@item in_h, ih
+@item in_w, iw
+The input width and height.
+
+@item sar
+The input sample aspect ratio.
+
+@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.
+
+These constants allow the @var{x}, @var{y}, @var{w}, @var{h} and @var{t} expressions to refer to
+each other, so you may for example specify @code{y=x/dar} or @code{h=w/dar}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Draw a black box around the edge of the input image:
@example
-# Draw a black box around the edge of the input image
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=max
+@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
+
+@section drawgrid
+
+Draw a grid on the input image.
+
+It accepts the following parameters:
+
+@table @option
+@item x
+@item y
+The expressions which specify the coordinates of some point of grid intersection (meant to configure offset). Both default to 0.
+
+@item width, w
+@item height, h
+The expressions which specify the width and height of the grid cell, if 0 they are interpreted as the
+input width and height, respectively, minus @code{thickness}, so image gets
+framed. Default to 0.
+
+@item color, c
+Specify the color of the grid. For the general syntax of this option,
+check the "Color" section in the ffmpeg-utils manual. If the special
+value @code{invert} is used, the grid color is the same as the
+video with inverted luma.
+
+@item thickness, t
+The expression which sets the thickness of the grid line. Default value is @code{1}.
+
+See below for the list of accepted constants.
+@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 dar
+The input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}.
+
+@item hsub
+@item vsub
+horizontal and vertical chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+
+@item in_h, ih
+@item in_w, iw
+The input grid cell width and height.
+
+@item sar
+The input sample aspect ratio.
+
+@item x
+@item y
+The x and y coordinates of some point of grid intersection (meant to configure offset).
+
+@item w
+@item h
+The width and height of the drawn cell.
+
+@item t
+The thickness of the drawn cell.
-# Draw a box with color red and an opacity of 50%
-drawbox=x=10:y=20:width=200:height=60:color=red@@0.5"
+These constants allow the @var{x}, @var{y}, @var{w}, @var{h} and @var{t} expressions to refer to
+each other, so you may for example specify @code{y=x/dar} or @code{h=w/dar}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Draw a grid with cell 100x100 pixels, thickness 2 pixels, with color red and an opacity of 50%:
+@example
+drawgrid=width=100:height=100:thickness=2:color=red@@0.5
@end example
+@item
+Draw a white 3x3 grid with an opacity of 50%:
+@example
+drawgrid=w=iw/3:h=ih/3:t=2:c=white@@0.5
+@end example
+@end itemize
+
+@anchor{drawtext}
@section drawtext
Draw a text string or text from a specified file on top of a video, using the
libfreetype library.
-To enable compilation of this filter, you need to configure Libav with
+To enable compilation of this filter, you need to configure FFmpeg with
@code{--enable-libfreetype}.
To enable default font fallback and the @var{font} option you need to
-configure Libav with @code{--enable-libfontconfig}.
+configure FFmpeg with @code{--enable-libfontconfig}.
+To enable the @var{text_shaping} option, you need to configure FFmpeg with
+@code{--enable-libfribidi}.
-The filter also recognizes strftime() sequences in the provided text
-and expands them accordingly. Check the documentation of strftime().
+@subsection Syntax
It accepts the following parameters:
@table @option
-@item font
-The font family to be used for drawing text. By default Sans.
-
-@item fontfile
-The font file to be used for drawing text. The path must be included.
-This parameter is mandatory if the fontconfig support is disabled.
-
-@item text
-The text string to be drawn. The text must be a sequence of UTF-8
-encoded characters.
-This parameter is mandatory if no file is specified with the parameter
-@var{textfile}.
+@item box
+Used to draw a box around text using the background color.
+The value must be either 1 (enable) or 0 (disable).
+The default value of @var{box} is 0.
-@item textfile
-A text file containing text to be drawn. The text must be a sequence
-of UTF-8 encoded characters.
+@item boxborderw
+Set the width of the border to be drawn around the box using @var{boxcolor}.
+The default value of @var{boxborderw} is 0.
-This parameter is mandatory if no text string is specified with the
-parameter @var{text}.
+@item boxcolor
+The color to be used for drawing box around text. For the syntax of this
+option, check the "Color" section in the ffmpeg-utils manual.
-If both text and textfile are specified, an error is thrown.
+The default value of @var{boxcolor} is "white".
-@item x, y
-The offsets where text will be drawn within the video frame.
-It is relative to the top/left border of the output image.
-They accept expressions similar to the @ref{overlay} filter:
-@table @option
+@item borderw
+Set the width of the border to be drawn around the text using @var{bordercolor}.
+The default value of @var{borderw} is 0.
-@item x, y
-The computed values for @var{x} and @var{y}. They are evaluated for
-each new frame.
+@item bordercolor
+Set the color to be used for drawing border around text. For the syntax of this
+option, check the "Color" section in the ffmpeg-utils manual.
-@item main_w, main_h
-The main input width and height.
+The default value of @var{bordercolor} is "black".
-@item W, H
-These are the same as @var{main_w} and @var{main_h}.
+@item expansion
+Select how the @var{text} is expanded. Can be either @code{none},
+@code{strftime} (deprecated) or
+@code{normal} (default). See the @ref{drawtext_expansion, Text expansion} section
+below for details.
-@item text_w, text_h
-The rendered text's width and height.
+@item fix_bounds
+If true, check and fix text coords to avoid clipping.
-@item w, h
-These are the same as @var{text_w} and @var{text_h}.
+@item fontcolor
+The color to be used for drawing fonts. For the syntax of this option, check
+the "Color" section in the ffmpeg-utils manual.
-@item n
-The number of frames processed, starting from 0.
+The default value of @var{fontcolor} is "black".
-@item t
-The timestamp, expressed in seconds. It's NAN if the input timestamp is unknown.
+@item fontcolor_expr
+String which is expanded the same way as @var{text} to obtain dynamic
+@var{fontcolor} value. By default this option has empty value and is not
+processed. When this option is set, it overrides @var{fontcolor} option.
-@end table
+@item font
+The font family to be used for drawing text. By default Sans.
-The default value of @var{x} and @var{y} is 0.
+@item fontfile
+The font file to be used for drawing text. The path must be included.
+This parameter is mandatory if the fontconfig support is disabled.
@item draw
-Draw the text only if the expression evaluates as non-zero.
-The expression accepts the same variables @var{x, y} do.
-The default value is 1.
+This option does not exist, please see the timeline system
@item alpha
Draw the text applying alpha blending. The value can
be either a number between 0.0 and 1.0
The expression accepts the same variables @var{x, y} do.
The default value is 1.
+Please see fontcolor_expr
@item fontsize
The font size to be used for drawing text.
The default value of @var{fontsize} is 16.
-@item fontcolor
-The color to be used for drawing fonts.
-It is either a string (e.g. "red"), or in 0xRRGGBB[AA] format
-(e.g. "0xff000033"), possibly followed by an alpha specifier.
-The default value of @var{fontcolor} is "black".
-
-@item boxcolor
-The color to be used for drawing box around text.
-It is either a string (e.g. "yellow") or in 0xRRGGBB[AA] format
-(e.g. "0xff00ff"), possibly followed by an alpha specifier.
-The default value of @var{boxcolor} is "white".
-
-@item box
-Used to draw a box around text using the background color.
-The value must be either 1 (enable) or 0 (disable).
-The default value of @var{box} is 0.
-
-@item shadowx, shadowy
-The x and y offsets for the text shadow position with respect to the
-position of the text. They can be either positive or negative
-values. The default value for both is "0".
-
-@item shadowcolor
-The color to be used for drawing a shadow behind the drawn text. It
-can be a color name (e.g. "yellow") or a string in the 0xRRGGBB[AA]
-form (e.g. "0xff00ff"), possibly followed by an alpha specifier.
-The default value of @var{shadowcolor} is "black".
+@item text_shaping
+If set to 1, attempt to shape the text (for example, reverse the order of
+right-to-left text and join Arabic characters) before drawing it.
+Otherwise, just draw the text exactly as given.
+By default 1 (if supported).
@item ft_load_flags
The flags to be used for loading the fonts.
@@ -1273,47 +4098,538 @@ a combination of the following values:
@item monochrome
@item linear_design
@item no_autohint
-@item end table
@end table
-Default value is "render".
+Default value is "default".
For more information consult the documentation for the FT_LOAD_*
libfreetype flags.
+@item shadowcolor
+The color to be used for drawing a shadow behind the drawn text. For the
+syntax of this option, check the "Color" section in the ffmpeg-utils manual.
+
+The default value of @var{shadowcolor} is "black".
+
+@item shadowx
+@item shadowy
+The x and y offsets for the text shadow position with respect to the
+position of the text. They can be either positive or negative
+values. The default value for both is "0".
+
+@item start_number
+The starting frame number for the n/frame_num variable. The default value
+is "0".
+
@item tabsize
The size in number of spaces to use for rendering the tab.
Default value is 4.
-@item fix_bounds
-If true, check and fix text coords to avoid clipping.
+@item timecode
+Set the initial timecode representation in "hh:mm:ss[:;.]ff"
+format. It can be used with or without text parameter. @var{timecode_rate}
+option must be specified.
+
+@item timecode_rate, rate, r
+Set the timecode frame rate (timecode only).
+
+@item text
+The text string to be drawn. The text must be a sequence of UTF-8
+encoded characters.
+This parameter is mandatory if no file is specified with the parameter
+@var{textfile}.
+
+@item textfile
+A text file containing text to be drawn. The text must be a sequence
+of UTF-8 encoded characters.
+
+This parameter is mandatory if no text string is specified with the
+parameter @var{text}.
+
+If both @var{text} and @var{textfile} are specified, an error is thrown.
+
+@item reload
+If set to 1, the @var{textfile} will be reloaded before each frame.
+Be sure to update it atomically, or it may be read partially, or even fail.
+
+@item x
+@item y
+The expressions which specify the offsets where text will be drawn
+within the video frame. They are relative to the top/left border of the
+output image.
+
+The default value of @var{x} and @var{y} is "0".
+
+See below for the list of accepted constants and functions.
@end table
-For example the command:
+The parameters for @var{x} and @var{y} are expressions containing the
+following constants and functions:
+
+@table @option
+@item dar
+input display aspect ratio, it is the same as (@var{w} / @var{h}) * @var{sar}
+
+@item hsub
+@item vsub
+horizontal and vertical chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+
+@item line_h, lh
+the height of each text line
+
+@item main_h, h, H
+the input height
+
+@item main_w, w, W
+the input width
+
+@item max_glyph_a, ascent
+the maximum distance from the baseline to the highest/upper grid
+coordinate used to place a glyph outline point, for all the rendered
+glyphs.
+It is a positive value, due to the grid's orientation with the Y axis
+upwards.
+
+@item max_glyph_d, descent
+the maximum distance from the baseline to the lowest grid coordinate
+used to place a glyph outline point, for all the rendered glyphs.
+This is a negative value, due to the grid's orientation, with the Y axis
+upwards.
+
+@item max_glyph_h
+maximum glyph height, that is the maximum height for all the glyphs
+contained in the rendered text, it is equivalent to @var{ascent} -
+@var{descent}.
+
+@item max_glyph_w
+maximum glyph width, that is the maximum width for all the glyphs
+contained in the rendered text
+
+@item n
+the number of input frame, starting from 0
+
+@item rand(min, max)
+return a random number included between @var{min} and @var{max}
+
+@item sar
+The input sample aspect ratio.
+
+@item t
+timestamp expressed in seconds, NAN if the input timestamp is unknown
+
+@item text_h, th
+the height of the rendered text
+
+@item text_w, tw
+the width of the rendered text
+
+@item x
+@item y
+the x and y offset coordinates where the text is drawn.
+
+These parameters allow the @var{x} and @var{y} expressions to refer
+each other, so you can for example specify @code{y=x/dar}.
+@end table
+
+@anchor{drawtext_expansion}
+@subsection Text expansion
+
+If @option{expansion} is set to @code{strftime},
+the filter recognizes strftime() sequences in the provided text and
+expands them accordingly. Check the documentation of strftime(). This
+feature is deprecated.
+
+If @option{expansion} is set to @code{none}, the text is printed verbatim.
+
+If @option{expansion} is set to @code{normal} (which is the default),
+the following expansion mechanism is used.
+
+The backslash character @samp{\}, followed by any character, always expands to
+the second character.
+
+Sequence of the form @code{%@{...@}} are expanded. The text between the
+braces is a function name, possibly followed by arguments separated by ':'.
+If the arguments contain special characters or delimiters (':' or '@}'),
+they should be escaped.
+
+Note that they probably must also be escaped as the value for the
+@option{text} option in the filter argument string and as the filter
+argument in the filtergraph description, and possibly also for the shell,
+that makes up to four levels of escaping; using a text file avoids these
+problems.
+
+The following functions are available:
+
+@table @command
+
+@item expr, e
+The expression evaluation result.
+
+It must take one argument specifying the expression to be evaluated,
+which accepts the same constants and functions as the @var{x} and
+@var{y} values. Note that not all constants should be used, for
+example the text size is not known when evaluating the expression, so
+the constants @var{text_w} and @var{text_h} will have an undefined
+value.
+
+@item expr_int_format, eif
+Evaluate the expression's value and output as formatted integer.
+
+The first argument is the expression to be evaluated, just as for the @var{expr} function.
+The second argument specifies the output format. Allowed values are @samp{x},
+@samp{X}, @samp{d} and @samp{u}. They are treated exactly as in the
+@code{printf} function.
+The third parameter is optional and sets the number of positions taken by the output.
+It can be used to add padding with zeros from the left.
+
+@item gmtime
+The time at which the filter is running, expressed in UTC.
+It can accept an argument: a strftime() format string.
+
+@item localtime
+The time at which the filter is running, expressed in the local time zone.
+It can accept an argument: a strftime() format string.
+
+@item metadata
+Frame metadata. It must take one argument specifying metadata key.
+
+@item n, frame_num
+The frame number, starting from 0.
+
+@item pict_type
+A 1 character description of the current picture type.
+
+@item pts
+The timestamp of the current frame.
+It can take up to two arguments.
+
+The first argument is the format of the timestamp; it defaults to @code{flt}
+for seconds as a decimal number with microsecond accuracy; @code{hms} stands
+for a formatted @var{[-]HH:MM:SS.mmm} timestamp with millisecond accuracy.
+
+The second argument is an offset added to the timestamp.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Draw "Test Text" with font FreeSerif, using the default values for the
+optional parameters.
+
@example
drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Test Text'"
@end example
-will draw "Test Text" with font FreeSerif, using the default values
-for the optional parameters.
+@item
+Draw 'Test Text' with font FreeSerif of size 24 at position x=100
+and y=50 (counting from the top-left corner of the screen), text is
+yellow with a red box around it. Both the text and the box have an
+opacity of 20%.
-The command:
@example
drawtext="fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Test Text':\
x=100: y=50: fontsize=24: fontcolor=yellow@@0.2: box=1: boxcolor=red@@0.2"
@end example
-will draw 'Test Text' with font FreeSerif of size 24 at position x=100
-and y=50 (counting from the top-left corner of the screen), text is
-yellow with a red box around it. Both the text and the box have an
-opacity of 20%.
-
Note that the double quotes are not necessary if spaces are not used
within the parameter list.
+@item
+Show the text at the center of the video frame:
+@example
+drawtext="fontsize=30:fontfile=FreeSerif.ttf:text='hello world':x=(w-text_w)/2:y=(h-text_h-line_h)/2"
+@end example
+
+@item
+Show a text line sliding from right to left in the last row of the video
+frame. The file @file{LONG_LINE} is assumed to contain a single line
+with no newlines.
+@example
+drawtext="fontsize=15:fontfile=FreeSerif.ttf:text=LONG_LINE:y=h-line_h:x=-50*t"
+@end example
+
+@item
+Show the content of file @file{CREDITS} off the bottom of the frame and scroll up.
+@example
+drawtext="fontsize=20:fontfile=FreeSerif.ttf:textfile=CREDITS:y=h-20*t"
+@end example
+
+@item
+Draw a single green letter "g", at the center of the input video.
+The glyph baseline is placed at half screen height.
+@example
+drawtext="fontsize=60:fontfile=FreeSerif.ttf:fontcolor=green:text=g:x=(w-max_glyph_w)/2:y=h/2-ascent"
+@end example
+
+@item
+Show text for 1 second every 3 seconds:
+@example
+drawtext="fontfile=FreeSerif.ttf:fontcolor=white:x=100:y=x/dar:enable=lt(mod(t\,3)\,1):text='blink'"
+@end example
+
+@item
+Use fontconfig to set the font. Note that the colons need to be escaped.
+@example
+drawtext='fontfile=Linux Libertine O-40\:style=Semibold:text=FFmpeg'
+@end example
+
+@item
+Print the date of a real-time encoding (see strftime(3)):
+@example
+drawtext='fontfile=FreeSans.ttf:text=%@{localtime\:%a %b %d %Y@}'
+@end example
+
+@item
+Show text fading in and out (appearing/disappearing):
+@example
+#!/bin/sh
+DS=1.0 # display start
+DE=10.0 # display end
+FID=1.5 # fade in duration
+FOD=5 # fade out duration
+ffplay -f lavfi "color,drawtext=text=TEST:fontsize=50:fontfile=FreeSerif.ttf:fontcolor_expr=ff0000%@{eif\\\\: clip(255*(1*between(t\\, $DS + $FID\\, $DE - $FOD) + ((t - $DS)/$FID)*between(t\\, $DS\\, $DS + $FID) + (-(t - $DE)/$FOD)*between(t\\, $DE - $FOD\\, $DE) )\\, 0\\, 255) \\\\: x\\\\: 2 @}"
+@end example
+
+@end itemize
+
For more information about libfreetype, check:
@url{http://www.freetype.org/}.
+For more information about fontconfig, check:
+@url{http://freedesktop.org/software/fontconfig/fontconfig-user.html}.
+
+For more information about libfribidi, check:
+@url{http://fribidi.org/}.
+
+@section edgedetect
+
+Detect and draw edges. The filter uses the Canny Edge Detection algorithm.
+
+The filter accepts the following options:
+
+@table @option
+@item low
+@item high
+Set low and high threshold values used by the Canny thresholding
+algorithm.
+
+The high threshold selects the "strong" edge pixels, which are then
+connected through 8-connectivity with the "weak" edge pixels selected
+by the low threshold.
+
+@var{low} and @var{high} threshold values must be chosen in the range
+[0,1], and @var{low} should be lesser or equal to @var{high}.
+
+Default value for @var{low} is @code{20/255}, and default value for @var{high}
+is @code{50/255}.
+
+@item mode
+Define the drawing mode.
+
+@table @samp
+@item wires
+Draw white/gray wires on black background.
+
+@item colormix
+Mix the colors to create a paint/cartoon effect.
+@end table
+
+Default value is @var{wires}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Standard edge detection with custom values for the hysteresis thresholding:
+@example
+edgedetect=low=0.1:high=0.4
+@end example
+
+@item
+Painting effect without thresholding:
+@example
+edgedetect=mode=colormix:high=0
+@end example
+@end itemize
+
+@section eq
+Set brightness, contrast, saturation and approximate gamma adjustment.
+
+The filter accepts the following options:
+
+@table @option
+@item contrast
+Set the contrast expression. The value must be a float value in range
+@code{-2.0} to @code{2.0}. The default value is "0".
+
+@item brightness
+Set the brightness expression. The value must be a float value in
+range @code{-1.0} to @code{1.0}. The default value is "0".
+
+@item saturation
+Set the saturation expression. The value must be a float in
+range @code{0.0} to @code{3.0}. The default value is "1".
+
+@item gamma
+Set the gamma expression. The value must be a float in range
+@code{0.1} to @code{10.0}. The default value is "1".
+
+@item gamma_r
+Set the gamma expression for red. The value must be a float in
+range @code{0.1} to @code{10.0}. The default value is "1".
+
+@item gamma_g
+Set the gamma expression for green. The value must be a float in range
+@code{0.1} to @code{10.0}. The default value is "1".
+
+@item gamma_b
+Set the gamma expression for blue. The value must be a float in range
+@code{0.1} to @code{10.0}. The default value is "1".
+
+@item gamma_weight
+Set the gamma weight expression. It can be used to reduce the effect
+of a high gamma value on bright image areas, e.g. keep them from
+getting overamplified and just plain white. The value must be a float
+in range @code{0.0} to @code{1.0}. A value of @code{0.0} turns the
+gamma correction all the way down while @code{1.0} leaves it at its
+full strength. Default is "1".
+
+@item eval
+Set when the expressions for brightness, contrast, saturation and
+gamma expressions are evaluated.
+
+It accepts the following values:
+@table @samp
+@item init
+only evaluate expressions once during the filter initialization or
+when a command is processed
+
+@item frame
+evaluate expressions for each incoming frame
+@end table
+
+Default value is @samp{init}.
+@end table
+
+The expressions accept the following parameters:
+@table @option
+@item n
+frame count of the input frame starting from 0
+
+@item pos
+byte position of the corresponding packet in the input file, NAN if
+unspecified
+
+@item r
+frame rate of the input video, NAN if the input frame rate is unknown
+
+@item t
+timestamp expressed in seconds, NAN if the input timestamp is unknown
+@end table
+
+@subsection Commands
+The filter supports the following commands:
+
+@table @option
+@item contrast
+Set the contrast expression.
+
+@item brightness
+Set the brightness expression.
+
+@item saturation
+Set the saturation expression.
+
+@item gamma
+Set the gamma expression.
+
+@item gamma_r
+Set the gamma_r expression.
+
+@item gamma_g
+Set gamma_g expression.
+
+@item gamma_b
+Set gamma_b expression.
+
+@item gamma_weight
+Set gamma_weight 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 extractplanes
+
+Extract color channel components from input video stream into
+separate grayscale video streams.
+
+The filter accepts the following option:
+
+@table @option
+@item planes
+Set plane(s) to extract.
+
+Available values for planes are:
+@table @samp
+@item y
+@item u
+@item v
+@item a
+@item r
+@item g
+@item b
+@end table
+
+Choosing planes not available in the input will result in an error.
+That means you cannot select @code{r}, @code{g}, @code{b} planes
+with @code{y}, @code{u}, @code{v} planes at same time.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Extract luma, u and v color channel component from input video frame
+into 3 grayscale outputs:
+@example
+ffmpeg -i video.avi -filter_complex 'extractplanes=y+u+v[y][u][v]' -map '[y]' y.avi -map '[u]' u.avi -map '[v]' v.avi
+@end example
+@end itemize
+
+@section elbg
+
+Apply a posterize effect using the ELBG (Enhanced LBG) algorithm.
+
+For each input image, the filter will compute the optimal mapping from
+the input to the output given the codebook length, that is the number
+of distinct output colors.
+
+This filter accepts the following options.
+
+@table @option
+@item codebook_length, l
+Set codebook length. The value must be a positive integer, and
+represents the number of distinct output colors. Default value is 256.
+
+@item nb_steps, n
+Set the maximum number of iterations to apply for computing the optimal
+mapping. The higher the value the better the result and the higher the
+computation time. Default value is 1.
+
+@item seed, s
+Set a random seed, must be an integer included between 0 and
+UINT32_MAX. If not specified, or if explicitly set to -1, the filter
+will try to use a good random seed on a best effort basis.
+@end table
+
@section fade
Apply a fade-in/out effect to the input video.
@@ -1321,34 +4637,490 @@ Apply a fade-in/out effect to the input video.
It accepts the following parameters:
@table @option
-
-@item type
+@item type, t
The effect type can be either "in" for a fade-in, or "out" for a fade-out
effect.
+Default is @code{in}.
-@item start_frame
-The number of the frame to start applying the fade effect at.
+@item start_frame, s
+Specify the number of the frame to start applying the fade
+effect at. Default is 0.
-@item nb_frames
+@item nb_frames, n
The number of frames that the fade effect lasts. At the end of the
fade-in effect, the output video will have the same intensity as the input video.
-At the end of the fade-out transition, the output video will be completely black.
+At the end of the fade-out transition, the output video will be filled with the
+selected @option{color}.
+Default is 25.
+@item alpha
+If set to 1, fade only alpha channel, if one exists on the input.
+Default value is 0.
+
+@item start_time, st
+Specify the timestamp (in seconds) of the frame to start to apply the fade
+effect. If both start_frame and start_time are specified, the fade will start at
+whichever comes last. Default is 0.
+
+@item duration, d
+The number of seconds for which the fade effect has to last. At the end of the
+fade-in effect the output video will have the same intensity as the input video,
+at the end of the fade-out transition the output video will be filled with the
+selected @option{color}.
+If both duration and nb_frames are specified, duration is used. Default is 0
+(nb_frames is used by default).
+
+@item color, c
+Specify the color of the fade. Default is "black".
@end table
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Fade in the first 30 frames of video:
+@example
+fade=in:0:30
+@end example
+
+The command above is equivalent to:
@example
-# Fade in the first 30 frames of video
-fade=type=in:nb_frames=30
+fade=t=in:s=0:n=30
+@end example
-# Fade out the last 45 frames of a 200-frame video
+@item
+Fade out the last 45 frames of a 200-frame video:
+@example
+fade=out:155:45
fade=type=out:start_frame=155:nb_frames=45
+@end example
+
+@item
+Fade in the first 25 frames and fade out the last 25 frames of a 1000-frame video:
+@example
+fade=in:0:25, fade=out:975:25
+@end example
+
+@item
+Make the first 5 frames yellow, then fade in from frame 5-24:
+@example
+fade=in:5:20:color=yellow
+@end example
+
+@item
+Fade in alpha over first 25 frames of video:
+@example
+fade=in:0:25:alpha=1
+@end example
+
+@item
+Make the first 5.5 seconds black, then fade in for 0.5 seconds:
+@example
+fade=t=in:st=5.5:d=0.5
+@end example
+
+@end itemize
+
+@section fftfilt
+Apply arbitrary expressions to samples in frequency domain
+
+@table @option
+@item dc_Y
+Adjust the dc value (gain) of the luma plane of the image. The filter
+accepts an integer value in range @code{0} to @code{1000}. The default
+value is set to @code{0}.
+
+@item dc_U
+Adjust the dc value (gain) of the 1st chroma plane of the image. The
+filter accepts an integer value in range @code{0} to @code{1000}. The
+default value is set to @code{0}.
+
+@item dc_V
+Adjust the dc value (gain) of the 2nd chroma plane of the image. The
+filter accepts an integer value in range @code{0} to @code{1000}. The
+default value is set to @code{0}.
+
+@item weight_Y
+Set the frequency domain weight expression for the luma plane.
+
+@item weight_U
+Set the frequency domain weight expression for the 1st chroma plane.
+
+@item weight_V
+Set the frequency domain weight expression for the 2nd chroma plane.
+
+The filter accepts the following variables:
+@item X
+@item Y
+The coordinates of the current sample.
+
+@item W
+@item H
+The width and height of the image.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+High-pass:
+@example
+fftfilt=dc_Y=128:weight_Y='squish(1-(Y+X)/100)'
+@end example
+
+@item
+Low-pass:
+@example
+fftfilt=dc_Y=0:weight_Y='squish((Y+X)/100-1)'
+@end example
+
+@item
+Sharpen:
+@example
+fftfilt=dc_Y=0:weight_Y='1+squish(1-(Y+X)/100)'
+@end example
+
+@end itemize
+
+@section field
+
+Extract a single field from an interlaced image using stride
+arithmetic to avoid wasting CPU time. The output frames are marked as
+non-interlaced.
+
+The filter accepts the following options:
+
+@table @option
+@item type
+Specify whether to extract the top (if the value is @code{0} or
+@code{top}) or the bottom field (if the value is @code{1} or
+@code{bottom}).
+@end table
+
+@section fieldmatch
+
+Field matching filter for inverse telecine. It is meant to reconstruct the
+progressive frames from a telecined stream. The filter does not drop duplicated
+frames, so to achieve a complete inverse telecine @code{fieldmatch} needs to be
+followed by a decimation filter such as @ref{decimate} in the filtergraph.
+
+The separation of the field matching and the decimation is notably motivated by
+the possibility of inserting a de-interlacing filter fallback between the two.
+If the source has mixed telecined and real interlaced content,
+@code{fieldmatch} will not be able to match fields for the interlaced parts.
+But these remaining combed frames will be marked as interlaced, and thus can be
+de-interlaced by a later filter such as @ref{yadif} before decimation.
+
+In addition to the various configuration options, @code{fieldmatch} can take an
+optional second stream, activated through the @option{ppsrc} option. If
+enabled, the frames reconstruction will be based on the fields and frames from
+this second stream. This allows the first input to be pre-processed in order to
+help the various algorithms of the filter, while keeping the output lossless
+(assuming the fields are matched properly). Typically, a field-aware denoiser,
+or brightness/contrast adjustments can help.
+
+Note that this filter uses the same algorithms as TIVTC/TFM (AviSynth project)
+and VIVTC/VFM (VapourSynth project). The later is a light clone of TFM from
+which @code{fieldmatch} is based on. While the semantic and usage are very
+close, some behaviour and options names can differ.
+
+The @ref{decimate} filter currently only works for constant frame rate input.
+Do not use @code{fieldmatch} and @ref{decimate} if your input has mixed
+telecined and progressive content with changing framerate.
+
+The filter accepts the following options:
+
+@table @option
+@item order
+Specify the assumed field order of the input stream. Available values are:
+
+@table @samp
+@item auto
+Auto detect parity (use FFmpeg's internal parity value).
+@item bff
+Assume bottom field first.
+@item tff
+Assume top field first.
+@end table
+
+Note that it is sometimes recommended not to trust the parity announced by the
+stream.
+
+Default value is @var{auto}.
+
+@item mode
+Set the matching mode or strategy to use. @option{pc} mode is the safest in the
+sense that it won't risk creating jerkiness due to duplicate frames when
+possible, but if there are bad edits or blended fields it will end up
+outputting combed frames when a good match might actually exist. On the other
+hand, @option{pcn_ub} mode is the most risky in terms of creating jerkiness,
+but will almost always find a good frame if there is one. The other values are
+all somewhere in between @option{pc} and @option{pcn_ub} in terms of risking
+jerkiness and creating duplicate frames versus finding good matches in sections
+with bad edits, orphaned fields, blended fields, etc.
+
+More details about p/c/n/u/b are available in @ref{p/c/n/u/b meaning} section.
+
+Available values are:
+
+@table @samp
+@item pc
+2-way matching (p/c)
+@item pc_n
+2-way matching, and trying 3rd match if still combed (p/c + n)
+@item pc_u
+2-way matching, and trying 3rd match (same order) if still combed (p/c + u)
+@item pc_n_ub
+2-way matching, trying 3rd match if still combed, and trying 4th/5th matches if
+still combed (p/c + n + u/b)
+@item pcn
+3-way matching (p/c/n)
+@item pcn_ub
+3-way matching, and trying 4th/5th matches if all 3 of the original matches are
+detected as combed (p/c/n + u/b)
+@end table
+
+The parenthesis at the end indicate the matches that would be used for that
+mode assuming @option{order}=@var{tff} (and @option{field} on @var{auto} or
+@var{top}).
+
+In terms of speed @option{pc} mode is by far the fastest and @option{pcn_ub} is
+the slowest.
+
+Default value is @var{pc_n}.
+
+@item ppsrc
+Mark the main input stream as a pre-processed input, and enable the secondary
+input stream as the clean source to pick the fields from. See the filter
+introduction for more details. It is similar to the @option{clip2} feature from
+VFM/TFM.
+
+Default value is @code{0} (disabled).
+
+@item field
+Set the field to match from. It is recommended to set this to the same value as
+@option{order} unless you experience matching failures with that setting. In
+certain circumstances changing the field that is used to match from can have a
+large impact on matching performance. Available values are:
+
+@table @samp
+@item auto
+Automatic (same value as @option{order}).
+@item bottom
+Match from the bottom field.
+@item top
+Match from the top field.
+@end table
-# Fade in the first 25 frames and fade out the last 25 frames of a 1000-frame video
-fade=type=in:start_frame=0:nb_frames=25, fade=type=out:start_frame=975:nb_frames=25
+Default value is @var{auto}.
+
+@item mchroma
+Set whether or not chroma is included during the match comparisons. In most
+cases it is recommended to leave this enabled. You should set this to @code{0}
+only if your clip has bad chroma problems such as heavy rainbowing or other
+artifacts. Setting this to @code{0} could also be used to speed things up at
+the cost of some accuracy.
+
+Default value is @code{1}.
+
+@item y0
+@item y1
+These define an exclusion band which excludes the lines between @option{y0} and
+@option{y1} from being included in the field matching decision. An exclusion
+band can be used to ignore subtitles, a logo, or other things that may
+interfere with the matching. @option{y0} sets the starting scan line and
+@option{y1} sets the ending line; all lines in between @option{y0} and
+@option{y1} (including @option{y0} and @option{y1}) will be ignored. Setting
+@option{y0} and @option{y1} to the same value will disable the feature.
+@option{y0} and @option{y1} defaults to @code{0}.
+
+@item scthresh
+Set the scene change detection threshold as a percentage of maximum change on
+the luma plane. Good values are in the @code{[8.0, 14.0]} range. Scene change
+detection is only relevant in case @option{combmatch}=@var{sc}. The range for
+@option{scthresh} is @code{[0.0, 100.0]}.
+
+Default value is @code{12.0}.
+
+@item combmatch
+When @option{combatch} is not @var{none}, @code{fieldmatch} will take into
+account the combed scores of matches when deciding what match to use as the
+final match. Available values are:
-# Make the first 5 frames black, then fade in from frame 5-24
-fade=type=in:start_frame=5:nb_frames=20
+@table @samp
+@item none
+No final matching based on combed scores.
+@item sc
+Combed scores are only used when a scene change is detected.
+@item full
+Use combed scores all the time.
+@end table
+
+Default is @var{sc}.
+
+@item combdbg
+Force @code{fieldmatch} to calculate the combed metrics for certain matches and
+print them. This setting is known as @option{micout} in TFM/VFM vocabulary.
+Available values are:
+
+@table @samp
+@item none
+No forced calculation.
+@item pcn
+Force p/c/n calculations.
+@item pcnub
+Force p/c/n/u/b calculations.
+@end table
+
+Default value is @var{none}.
+
+@item cthresh
+This is the area combing threshold used for combed frame detection. This
+essentially controls how "strong" or "visible" combing must be to be detected.
+Larger values mean combing must be more visible and smaller values mean combing
+can be less visible or strong and still be detected. Valid settings are from
+@code{-1} (every pixel will be detected as combed) to @code{255} (no pixel will
+be detected as combed). This is basically a pixel difference value. A good
+range is @code{[8, 12]}.
+
+Default value is @code{9}.
+
+@item chroma
+Sets whether or not chroma is considered in the combed frame decision. Only
+disable this if your source has chroma problems (rainbowing, etc.) that are
+causing problems for the combed frame detection with chroma enabled. Actually,
+using @option{chroma}=@var{0} is usually more reliable, except for the case
+where there is chroma only combing in the source.
+
+Default value is @code{0}.
+
+@item blockx
+@item blocky
+Respectively set the x-axis and y-axis size of the window used during combed
+frame detection. This has to do with the size of the area in which
+@option{combpel} pixels are required to be detected as combed for a frame to be
+declared combed. See the @option{combpel} parameter description for more info.
+Possible values are any number that is a power of 2 starting at 4 and going up
+to 512.
+
+Default value is @code{16}.
+
+@item combpel
+The number of combed pixels inside any of the @option{blocky} by
+@option{blockx} size blocks on the frame for the frame to be detected as
+combed. While @option{cthresh} controls how "visible" the combing must be, this
+setting controls "how much" combing there must be in any localized area (a
+window defined by the @option{blockx} and @option{blocky} settings) on the
+frame. Minimum value is @code{0} and maximum is @code{blocky x blockx} (at
+which point no frames will ever be detected as combed). This setting is known
+as @option{MI} in TFM/VFM vocabulary.
+
+Default value is @code{80}.
+@end table
+
+@anchor{p/c/n/u/b meaning}
+@subsection p/c/n/u/b meaning
+
+@subsubsection p/c/n
+
+We assume the following telecined stream:
+
+@example
+Top fields: 1 2 2 3 4
+Bottom fields: 1 2 3 4 4
+@end example
+
+The numbers correspond to the progressive frame the fields relate to. Here, the
+first two frames are progressive, the 3rd and 4th are combed, and so on.
+
+When @code{fieldmatch} is configured to run a matching from bottom
+(@option{field}=@var{bottom}) this is how this input stream get transformed:
+
+@example
+Input stream:
+ T 1 2 2 3 4
+ B 1 2 3 4 4 <-- matching reference
+
+Matches: c c n n c
+
+Output stream:
+ T 1 2 3 4 4
+ B 1 2 3 4 4
+@end example
+
+As a result of the field matching, we can see that some frames get duplicated.
+To perform a complete inverse telecine, you need to rely on a decimation filter
+after this operation. See for instance the @ref{decimate} filter.
+
+The same operation now matching from top fields (@option{field}=@var{top})
+looks like this:
+
+@example
+Input stream:
+ T 1 2 2 3 4 <-- matching reference
+ B 1 2 3 4 4
+
+Matches: c c p p c
+
+Output stream:
+ T 1 2 2 3 4
+ B 1 2 2 3 4
+@end example
+
+In these examples, we can see what @var{p}, @var{c} and @var{n} mean;
+basically, they refer to the frame and field of the opposite parity:
+
+@itemize
+@item @var{p} matches the field of the opposite parity in the previous frame
+@item @var{c} matches the field of the opposite parity in the current frame
+@item @var{n} matches the field of the opposite parity in the next frame
+@end itemize
+
+@subsubsection u/b
+
+The @var{u} and @var{b} matching are a bit special in the sense that they match
+from the opposite parity flag. In the following examples, we assume that we are
+currently matching the 2nd frame (Top:2, bottom:2). According to the match, a
+'x' is placed above and below each matched fields.
+
+With bottom matching (@option{field}=@var{bottom}):
+@example
+Match: c p n b u
+
+ x x x x x
+ Top 1 2 2 1 2 2 1 2 2 1 2 2 1 2 2
+ Bottom 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
+ x x x x x
+
+Output frames:
+ 2 1 2 2 2
+ 2 2 2 1 3
+@end example
+
+With top matching (@option{field}=@var{top}):
+@example
+Match: c p n b u
+
+ x x x x x
+ Top 1 2 2 1 2 2 1 2 2 1 2 2 1 2 2
+ Bottom 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
+ x x x x x
+
+Output frames:
+ 2 2 2 1 2
+ 2 1 3 2 2
+@end example
+
+@subsection Examples
+
+Simple IVTC of a top field first telecined stream:
+@example
+fieldmatch=order=tff:combmatch=none, decimate
+@end example
+
+Advanced IVTC, with fallback on @ref{yadif} for still combed frames:
+@example
+fieldmatch=order=tff:combmatch=full, yadif=deint=interlaced, decimate
@end example
@section fieldorder
@@ -1364,7 +5136,7 @@ The output field order. Valid values are @var{tff} for top field first or @var{b
for bottom field first.
@end table
-The default value is "tff".
+The default value is @samp{tff}.
The transformation is done by shifting the picture content up or down
by one line, and filling the remaining line with appropriate picture content.
@@ -1379,7 +5151,7 @@ which is bottom field first.
For example:
@example
-./avconv -i in.vob -vf "fieldorder=order=bff" out.dv
+ffmpeg -i in.vob -vf "fieldorder=bff" out.dv
@end example
@section fifo
@@ -1391,6 +5163,71 @@ framework.
It does not take parameters.
+@section find_rect
+
+Find a rectangular object
+
+It accepts the following options:
+
+@table @option
+@item object
+Filepath of the object image, needs to be in gray8.
+
+@item threshold
+Detection threshold, default is 0.5.
+
+@item mipmaps
+Number of mipmaps, default is 3.
+
+@item xmin, ymin, xmax, ymax
+Specifies the rectangle in which to search.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Generate a representative palette of a given video using @command{ffmpeg}:
+@example
+ffmpeg -i file.ts -vf find_rect=newref.pgm,cover_rect=cover.jpg:mode=cover new.mkv
+@end example
+@end itemize
+
+@section cover_rect
+
+Cover a rectangular object
+
+It accepts the following options:
+
+@table @option
+@item cover
+Filepath of the optional cover image, needs to be in yuv420.
+
+@item mode
+Set covering mode.
+
+It accepts the following values:
+@table @samp
+@item cover
+cover it by the supplied image
+@item blur
+cover it by interpolating the surrounding pixels
+@end table
+
+Default value is @var{blur}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Generate a representative palette of a given video using @command{ffmpeg}:
+@example
+ffmpeg -i file.ts -vf find_rect=newref.pgm,cover_rect=cover.jpg:mode=cover new.mkv
+@end example
+@end itemize
+
+@anchor{format}
@section format
Convert the input video to one of the specified pixel formats.
@@ -1406,26 +5243,50 @@ A '|'-separated list of pixel format names, such as
@end table
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Convert the input video to the @var{yuv420p} format
@example
-# Convert the input video to the "yuv420p" format
format=pix_fmts=yuv420p
+@end example
-# Convert the input video to any of the formats in the list
+Convert the input video to any of the formats in the list
+@example
format=pix_fmts=yuv420p|yuv444p|yuv410p
@end example
+@end itemize
@anchor{fps}
@section fps
-Convert the video to specified constant framerate by duplicating or dropping
+Convert the video to specified constant frame rate by duplicating or dropping
frames as necessary.
It accepts the following parameters:
@table @option
@item fps
-The desired output framerate.
+The desired output frame rate. The default is @code{25}.
+
+@item round
+Rounding method.
+
+Possible values are:
+@table @option
+@item zero
+zero round towards 0
+@item inf
+round away from 0
+@item down
+round towards -infinity
+@item up
+round towards +infinity
+@item near
+round to nearest
+@end table
+The default is @code{near}.
@item start_time
Assume the first PTS should be the given value, in seconds. This allows for
@@ -1437,6 +5298,27 @@ frames with a negative PTS.
@end table
+Alternatively, the options can be specified as a flat string:
+@var{fps}[:@var{round}].
+
+See also the @ref{setpts} filter.
+
+@subsection Examples
+
+@itemize
+@item
+A typical usage in order to set the fps to 25:
+@example
+fps=fps=25
+@end example
+
+@item
+Sets the fps to 24, using abbreviation and rounding method to round to nearest:
+@example
+fps=fps=film:round=near
+@end example
+@end itemize
+
@section framepack
Pack two different video streams into a stereoscopic video, setting proper
@@ -1476,19 +5358,30 @@ Some examples:
@example
# Convert left and right views into a frame-sequential video
-avconv -i LEFT -i RIGHT -filter_complex framepack=frameseq OUTPUT
+ffmpeg -i LEFT -i RIGHT -filter_complex framepack=frameseq OUTPUT
# Convert views into a side-by-side video with the same output resolution as the input
-avconv -i LEFT -i RIGHT -filter_complex [0:v]scale=w=iw/2[left],[1:v]scale=w=iw/2[right],[left][right]framepack=sbs OUTPUT
+ffmpeg -i LEFT -i RIGHT -filter_complex [0:v]scale=w=iw/2[left],[1:v]scale=w=iw/2[right],[left][right]framepack=sbs OUTPUT
@end example
+@section framestep
+
+Select one frame every N-th frame.
+
+This filter accepts the following option:
+@table @option
+@item step
+Select frame after every @code{step} frames.
+Allowed values are positive integers higher than 0. Default value is @code{1}.
+@end table
+
@anchor{frei0r}
@section frei0r
Apply a frei0r effect to the input video.
To enable the compilation of this filter, you need to install the frei0r
-header and configure Libav with --enable-frei0r.
+header and configure FFmpeg with @code{--enable-frei0r}.
It accepts the following parameters:
@@ -1510,35 +5403,214 @@ A '|'-separated list of parameters to pass to the frei0r effect.
A frei0r effect parameter can be a boolean (its value is either
"y" or "n"), a double, a color (specified as
@var{R}/@var{G}/@var{B}, where @var{R}, @var{G}, and @var{B} are floating point
-numbers between 0.0 and 1.0, inclusive) or by an @code{av_parse_color()} color
-description), a position (specified as @var{X}/@var{Y}, where
+numbers between 0.0 and 1.0, inclusive) or by a color description specified in the "Color"
+section in the ffmpeg-utils manual), a position (specified as @var{X}/@var{Y}, where
@var{X} and @var{Y} are floating point numbers) and/or a string.
The number and types of parameters depend on the loaded effect. If an
effect parameter is not specified, the default value is set.
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Apply the distort0r effect, setting the first two double parameters:
@example
-# Apply the distort0r effect, setting the first two double parameters
frei0r=filter_name=distort0r:filter_params=0.5|0.01
+@end example
-# Apply the colordistance effect, taking a color as the first parameter
+@item
+Apply the colordistance effect, taking a color as the first parameter:
+@example
frei0r=colordistance:0.2/0.3/0.4
frei0r=colordistance:violet
frei0r=colordistance:0x112233
+@end example
-# Apply the perspective effect, specifying the top left and top right
-# image positions
+@item
+Apply the perspective effect, specifying the top left and top right image
+positions:
+@example
frei0r=perspective:0.2/0.2|0.8/0.2
@end example
+@end itemize
For more information, see
-@url{http://piksel.org/frei0r}
+@url{http://frei0r.dyne.org}
+
+@section fspp
+
+Apply fast and simple postprocessing. It is a faster version of @ref{spp}.
+
+It splits (I)DCT into horizontal/vertical passes. Unlike the simple post-
+processing filter, one of them is performed once per block, not per pixel.
+This allows for much higher speed.
+
+The filter accepts the following options:
+
+@table @option
+@item quality
+Set quality. This option defines the number of levels for averaging. It accepts
+an integer in the range 4-5. Default value is @code{4}.
+
+@item qp
+Force a constant quantization parameter. It accepts an integer in range 0-63.
+If not set, the filter will use the QP from the video stream (if available).
+
+@item strength
+Set filter strength. It accepts an integer in range -15 to 32. Lower values mean
+more details but also more artifacts, while higher values make the image smoother
+but also blurrier. Default value is @code{0} − PSNR optimal.
+
+@item use_bframe_qp
+Enable the use of the QP from the B-Frames if set to @code{1}. Using this
+option may cause flicker since the B-Frames have often larger QP. Default is
+@code{0} (not enabled).
+
+@end table
+
+@section geq
+
+The filter accepts the following options:
+
+@table @option
+@item lum_expr, lum
+Set the luminance expression.
+@item cb_expr, cb
+Set the chrominance blue expression.
+@item cr_expr, cr
+Set the chrominance red expression.
+@item alpha_expr, a
+Set the alpha expression.
+@item red_expr, r
+Set the red expression.
+@item green_expr, g
+Set the green expression.
+@item blue_expr, b
+Set the blue expression.
+@end table
+
+The colorspace is selected according to the specified options. If one
+of the @option{lum_expr}, @option{cb_expr}, or @option{cr_expr}
+options is specified, the filter will automatically select a YCbCr
+colorspace. If one of the @option{red_expr}, @option{green_expr}, or
+@option{blue_expr} options is specified, it will select an RGB
+colorspace.
+
+If one of the chrominance expression is not defined, it falls back on the other
+one. If no alpha expression is specified it will evaluate to opaque value.
+If none of chrominance expressions are specified, they will evaluate
+to the luminance expression.
+
+The expressions can use the following variables and functions:
+
+@table @option
+@item N
+The sequential number of the filtered frame, starting from @code{0}.
+
+@item X
+@item Y
+The coordinates of the current sample.
+
+@item W
+@item H
+The width and height of the image.
+
+@item SW
+@item SH
+Width and height scale depending on the currently filtered plane. It is the
+ratio between the corresponding luma plane number of pixels and the current
+plane ones. E.g. for YUV4:2:0 the values are @code{1,1} for the luma plane, and
+@code{0.5,0.5} for chroma planes.
+
+@item T
+Time of the current frame, expressed in seconds.
+
+@item p(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the current
+plane.
+
+@item lum(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the luminance
+plane.
+
+@item cb(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the
+blue-difference chroma plane. Return 0 if there is no such plane.
+
+@item cr(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the
+red-difference chroma plane. Return 0 if there is no such plane.
+
+@item r(x, y)
+@item g(x, y)
+@item b(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the
+red/green/blue component. Return 0 if there is no such component.
+
+@item alpha(x, y)
+Return the value of the pixel at location (@var{x},@var{y}) of the alpha
+plane. Return 0 if there is no such plane.
+@end table
+
+For functions, if @var{x} and @var{y} are outside the area, the value will be
+automatically clipped to the closer edge.
+
+@subsection Examples
+
+@itemize
+@item
+Flip the image horizontally:
+@example
+geq=p(W-X\,Y)
+@end example
+
+@item
+Generate a bidimensional sine wave, with angle @code{PI/3} and a
+wavelength of 100 pixels:
+@example
+geq=128 + 100*sin(2*(PI/100)*(cos(PI/3)*(X-50*T) + sin(PI/3)*Y)):128:128
+@end example
+
+@item
+Generate a fancy enigmatic moving light:
+@example
+nullsrc=s=256x256,geq=random(1)/hypot(X-cos(N*0.07)*W/2-W/2\,Y-sin(N*0.09)*H/2-H/2)^2*1000000*sin(N*0.02):128:128
+@end example
+
+@item
+Generate a quick emboss effect:
+@example
+format=gray,geq=lum_expr='(p(X,Y)+(256-p(X-4,Y-4)))/2'
+@end example
+
+@item
+Modify RGB components depending on pixel position:
+@example
+geq=r='X/W*r(X,Y)':g='(1-X/W)*g(X,Y)':b='(H-Y)/H*b(X,Y)'
+@end example
+
+@item
+Create a radial gradient that is the same size as the input (also see
+the @ref{vignette} filter):
+@example
+geq=lum=255*gauss((X/W-0.5)*3)*gauss((Y/H-0.5)*3)/gauss(0)/gauss(0),format=gray
+@end example
+
+@item
+Create a linear gradient to use as a mask for another filter, then
+compose with @ref{overlay}. In this example the video will gradually
+become more blurry from the top to the bottom of the y-axis as defined
+by the linear gradient:
+@example
+ffmpeg -i input.mp4 -filter_complex "geq=lum=255*(Y/H),format=gray[grad];[0:v]boxblur=4[blur];[blur][grad]alphamerge[alpha];[0:v][alpha]overlay" output.mp4
+@end example
+@end itemize
@section gradfun
Fix the banding artifacts that are sometimes introduced into nearly flat
-regions by truncation to 8bit colordepth.
+regions by truncation to 8bit color depth.
Interpolate the gradients that should go where the bands are, and
dither them.
@@ -1564,23 +5636,264 @@ values will be clipped to the valid range.
@end table
+Alternatively, the options can be specified as a flat string:
+@var{strength}[:@var{radius}]
+
+@subsection Examples
+
+@itemize
+@item
+Apply the filter with a @code{3.5} strength and radius of @code{8}:
@example
-# Default parameters
-gradfun=strength=1.2:radius=16
+gradfun=3.5:8
+@end example
-# Omitting the radius
-gradfun=1.2
+@item
+Specify radius, omitting the strength (which will fall-back to the default
+value):
+@example
+gradfun=radius=8
+@end example
+
+@end itemize
+
+@anchor{haldclut}
+@section haldclut
+
+Apply a Hald CLUT to a video stream.
+
+First input is the video stream to process, and second one is the Hald CLUT.
+The Hald CLUT input can be a simple picture or a complete video stream.
+
+The filter accepts the following options:
+
+@table @option
+@item shortest
+Force termination when the shortest input terminates. Default is @code{0}.
+@item repeatlast
+Continue applying the last CLUT after the end of the stream. A value of
+@code{0} disable the filter after the last frame of the CLUT is reached.
+Default is @code{1}.
+@end table
+
+@code{haldclut} also has the same interpolation options as @ref{lut3d} (both
+filters share the same internals).
+
+More information about the Hald CLUT can be found on Eskil Steenberg's website
+(Hald CLUT author) at @url{http://www.quelsolaar.com/technology/clut.html}.
+
+@subsection Workflow examples
+
+@subsubsection Hald CLUT video stream
+
+Generate an identity Hald CLUT stream altered with various effects:
+@example
+ffmpeg -f lavfi -i @ref{haldclutsrc}=8 -vf "hue=H=2*PI*t:s=sin(2*PI*t)+1, curves=cross_process" -t 10 -c:v ffv1 clut.nut
+@end example
+
+Note: make sure you use a lossless codec.
+
+Then use it with @code{haldclut} to apply it on some random stream:
+@example
+ffmpeg -f lavfi -i mandelbrot -i clut.nut -filter_complex '[0][1] haldclut' -t 20 mandelclut.mkv
+@end example
+
+The Hald CLUT will be applied to the 10 first seconds (duration of
+@file{clut.nut}), then the latest picture of that CLUT stream will be applied
+to the remaining frames of the @code{mandelbrot} stream.
+
+@subsubsection Hald CLUT with preview
+
+A Hald CLUT is supposed to be a squared image of @code{Level*Level*Level} by
+@code{Level*Level*Level} pixels. For a given Hald CLUT, FFmpeg will select the
+biggest possible square starting at the top left of the picture. The remaining
+padding pixels (bottom or right) will be ignored. This area can be used to add
+a preview of the Hald CLUT.
+
+Typically, the following generated Hald CLUT will be supported by the
+@code{haldclut} filter:
+
+@example
+ffmpeg -f lavfi -i @ref{haldclutsrc}=8 -vf "
+ pad=iw+320 [padded_clut];
+ smptebars=s=320x256, split [a][b];
+ [padded_clut][a] overlay=W-320:h, curves=color_negative [main];
+ [main][b] overlay=W-320" -frames:v 1 clut.png
+@end example
+
+It contains the original and a preview of the effect of the CLUT: SMPTE color
+bars are displayed on the right-top, and below the same color bars processed by
+the color changes.
+
+Then, the effect of this Hald CLUT can be visualized with:
+@example
+ffplay input.mkv -vf "movie=clut.png, [in] haldclut"
@end example
@section hflip
Flip the input video horizontally.
-For example, to horizontally flip the input video with @command{avconv}:
+For example, to horizontally flip the input video with @command{ffmpeg}:
+@example
+ffmpeg -i in.avi -vf "hflip" out.avi
+@end example
+
+@section histeq
+This filter applies a global color histogram equalization on a
+per-frame basis.
+
+It can be used to correct video that has a compressed range of pixel
+intensities. The filter redistributes the pixel intensities to
+equalize their distribution across the intensity range. It may be
+viewed as an "automatically adjusting contrast filter". This filter is
+useful only for correcting degraded or poorly captured source
+video.
+
+The filter accepts the following options:
+
+@table @option
+@item strength
+Determine the amount of equalization to be applied. As the strength
+is reduced, the distribution of pixel intensities more-and-more
+approaches that of the input frame. The value must be a float number
+in the range [0,1] and defaults to 0.200.
+
+@item intensity
+Set the maximum intensity that can generated and scale the output
+values appropriately. The strength should be set as desired and then
+the intensity can be limited if needed to avoid washing-out. The value
+must be a float number in the range [0,1] and defaults to 0.210.
+
+@item antibanding
+Set the antibanding level. If enabled the filter will randomly vary
+the luminance of output pixels by a small amount to avoid banding of
+the histogram. Possible values are @code{none}, @code{weak} or
+@code{strong}. It defaults to @code{none}.
+@end table
+
+@section histogram
+
+Compute and draw a color distribution histogram for the input video.
+
+The computed histogram is a representation of the color component
+distribution in an image.
+
+The filter accepts the following options:
+
+@table @option
+@item mode
+Set histogram mode.
+
+It accepts the following values:
+@table @samp
+@item levels
+Standard histogram that displays the color components distribution in an
+image. Displays color graph for each color component. Shows distribution of
+the Y, U, V, A or R, G, B components, depending on input format, in the
+current frame. Below each graph a color component scale meter is shown.
+
+@item color
+Displays chroma values (U/V color placement) in a two dimensional
+graph (which is called a vectorscope). The brighter a pixel in the
+vectorscope, the more pixels of the input frame correspond to that pixel
+(i.e., more pixels have this chroma value). The V component is displayed on
+the horizontal (X) axis, with the leftmost side being V = 0 and the rightmost
+side being V = 255. The U component is displayed on the vertical (Y) axis,
+with the top representing U = 0 and the bottom representing U = 255.
+
+The position of a white pixel in the graph corresponds to the chroma value of
+a pixel of the input clip. The graph can therefore be used to read the hue
+(color flavor) and the saturation (the dominance of the hue in the color). As
+the hue of a color changes, it moves around the square. At the center of the
+square the saturation is zero, which means that the corresponding pixel has no
+color. If the amount of a specific color is increased (while leaving the other
+colors unchanged) the saturation increases, and the indicator moves towards
+the edge of the square.
+
+@item color2
+Chroma values in vectorscope, similar as @code{color} but actual chroma values
+are displayed.
+
+@item waveform
+Per row/column color component graph. In row mode, the graph on the left side
+represents color component value 0 and the right side represents value = 255.
+In column mode, the top side represents color component value = 0 and bottom
+side represents value = 255.
+@end table
+Default value is @code{levels}.
+
+@item level_height
+Set height of level in @code{levels}. Default value is @code{200}.
+Allowed range is [50, 2048].
+
+@item scale_height
+Set height of color scale in @code{levels}. Default value is @code{12}.
+Allowed range is [0, 40].
+
+@item step
+Set step for @code{waveform} mode. Smaller values are useful to find out how
+many values of the same luminance are distributed across input rows/columns.
+Default value is @code{10}. Allowed range is [1, 255].
+
+@item waveform_mode
+Set mode for @code{waveform}. Can be either @code{row}, or @code{column}.
+Default is @code{row}.
+
+@item waveform_mirror
+Set mirroring mode for @code{waveform}. @code{0} means unmirrored, @code{1}
+means mirrored. In mirrored mode, higher values will be represented on the left
+side for @code{row} mode and at the top for @code{column} mode. Default is
+@code{0} (unmirrored).
+
+@item display_mode
+Set display mode for @code{waveform} and @code{levels}.
+It accepts the following values:
+@table @samp
+@item parade
+Display separate graph for the color components side by side in
+@code{row} waveform mode or one below the other in @code{column} waveform mode
+for @code{waveform} histogram mode. For @code{levels} histogram mode,
+per color component graphs are placed below each other.
+
+Using this display mode in @code{waveform} histogram mode makes it easy to
+spot color casts in the highlights and shadows of an image, by comparing the
+contours of the top and the bottom graphs of each waveform. Since whites,
+grays, and blacks are characterized by exactly equal amounts of red, green,
+and blue, neutral areas of the picture should display three waveforms of
+roughly equal width/height. If not, the correction is easy to perform by
+making level adjustments the three waveforms.
+
+@item overlay
+Presents information identical to that in the @code{parade}, except
+that the graphs representing color components are superimposed directly
+over one another.
+
+This display mode in @code{waveform} histogram mode makes it easier to spot
+relative differences or similarities in overlapping areas of the color
+components that are supposed to be identical, such as neutral whites, grays,
+or blacks.
+@end table
+Default is @code{parade}.
+
+@item levels_mode
+Set mode for @code{levels}. Can be either @code{linear}, or @code{logarithmic}.
+Default is @code{linear}.
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Calculate and draw histogram:
@example
-avconv -i in.avi -vf "hflip" out.avi
+ffplay -i input -vf histogram
@end example
+@end itemize
+
+@anchor{hqdn3d}
@section hqdn3d
This is a high precision/quality 3d denoise filter. It aims to reduce
@@ -1607,6 +5920,249 @@ A floating point number which specifies chroma temporal strength. It defaults to
@var{luma_tmp}*@var{chroma_spatial}/@var{luma_spatial}.
@end table
+@section hqx
+
+Apply a high-quality magnification filter designed for pixel art. This filter
+was originally created by Maxim Stepin.
+
+It accepts the following option:
+
+@table @option
+@item n
+Set the scaling dimension: @code{2} for @code{hq2x}, @code{3} for
+@code{hq3x} and @code{4} for @code{hq4x}.
+Default is @code{3}.
+@end table
+
+@section hue
+
+Modify the hue and/or the saturation of the input.
+
+It accepts the following parameters:
+
+@table @option
+@item h
+Specify the hue angle as a number of degrees. It accepts an expression,
+and defaults to "0".
+
+@item s
+Specify the saturation in the [-10,10] range. It accepts an expression and
+defaults to "1".
+
+@item H
+Specify the hue angle as a number of radians. It accepts an
+expression, and defaults to "0".
+
+@item b
+Specify the brightness in the [-10,10] range. It accepts an expression and
+defaults to "0".
+@end table
+
+@option{h} and @option{H} are mutually exclusive, and can't be
+specified at the same time.
+
+The @option{b}, @option{h}, @option{H} and @option{s} option values are
+expressions containing the following constants:
+
+@table @option
+@item n
+frame count of the input frame starting from 0
+
+@item pts
+presentation timestamp of the input frame expressed in time base units
+
+@item r
+frame rate of the input video, NAN if the input frame rate is unknown
+
+@item t
+timestamp expressed in seconds, NAN if the input timestamp is unknown
+
+@item tb
+time base of the input video
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Set the hue to 90 degrees and the saturation to 1.0:
+@example
+hue=h=90:s=1
+@end example
+
+@item
+Same command but expressing the hue in radians:
+@example
+hue=H=PI/2:s=1
+@end example
+
+@item
+Rotate hue and make the saturation swing between 0
+and 2 over a period of 1 second:
+@example
+hue="H=2*PI*t: s=sin(2*PI*t)+1"
+@end example
+
+@item
+Apply a 3 seconds saturation fade-in effect starting at 0:
+@example
+hue="s=min(t/3\,1)"
+@end example
+
+The general fade-in expression can be written as:
+@example
+hue="s=min(0\, max((t-START)/DURATION\, 1))"
+@end example
+
+@item
+Apply a 3 seconds saturation fade-out effect starting at 5 seconds:
+@example
+hue="s=max(0\, min(1\, (8-t)/3))"
+@end example
+
+The general fade-out expression can be written as:
+@example
+hue="s=max(0\, min(1\, (START+DURATION-t)/DURATION))"
+@end example
+
+@end itemize
+
+@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item b
+@item s
+@item h
+@item H
+Modify the hue and/or the saturation and/or brightness of the input video.
+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 idet
+
+Detect video interlacing type.
+
+This filter tries to detect if the input frames as interlaced, progressive,
+top or bottom field first. It will also try and detect fields that are
+repeated between adjacent frames (a sign of telecine).
+
+Single frame detection considers only immediately adjacent frames when classifying each frame.
+Multiple frame detection incorporates the classification history of previous frames.
+
+The filter will log these metadata values:
+
+@table @option
+@item single.current_frame
+Detected type of current frame using single-frame detection. One of:
+``tff'' (top field first), ``bff'' (bottom field first),
+``progressive'', or ``undetermined''
+
+@item single.tff
+Cumulative number of frames detected as top field first using single-frame detection.
+
+@item multiple.tff
+Cumulative number of frames detected as top field first using multiple-frame detection.
+
+@item single.bff
+Cumulative number of frames detected as bottom field first using single-frame detection.
+
+@item multiple.current_frame
+Detected type of current frame using multiple-frame detection. One of:
+``tff'' (top field first), ``bff'' (bottom field first),
+``progressive'', or ``undetermined''
+
+@item multiple.bff
+Cumulative number of frames detected as bottom field first using multiple-frame detection.
+
+@item single.progressive
+Cumulative number of frames detected as progressive using single-frame detection.
+
+@item multiple.progressive
+Cumulative number of frames detected as progressive using multiple-frame detection.
+
+@item single.undetermined
+Cumulative number of frames that could not be classified using single-frame detection.
+
+@item multiple.undetermined
+Cumulative number of frames that could not be classified using multiple-frame detection.
+
+@item repeated.current_frame
+Which field in the current frame is repeated from the last. One of ``neither'', ``top'', or ``bottom''.
+
+@item repeated.neither
+Cumulative number of frames with no repeated field.
+
+@item repeated.top
+Cumulative number of frames with the top field repeated from the previous frame's top field.
+
+@item repeated.bottom
+Cumulative number of frames with the bottom field repeated from the previous frame's bottom field.
+@end table
+
+The filter accepts the following options:
+
+@table @option
+@item intl_thres
+Set interlacing threshold.
+@item prog_thres
+Set progressive threshold.
+@item repeat_thres
+Threshold for repeated field detection.
+@item half_life
+Number of frames after which a given frame's contribution to the
+statistics is halved (i.e., it contributes only 0.5 to it's
+classification). The default of 0 means that all frames seen are given
+full weight of 1.0 forever.
+@item analyze_interlaced_flag
+When this is not 0 then idet will use the specified number of frames to determine
+if the interlaced flag is accurate, it will not count undetermined frames.
+If the flag is found to be accurate it will be used without any further
+computations, if it is found to be inaccuarte it will be cleared without any
+further computations. This allows inserting the idet filter as a low computational
+method to clean up the interlaced flag
+@end table
+
+@section il
+
+Deinterleave or interleave fields.
+
+This filter allows one to process interlaced images fields without
+deinterlacing them. Deinterleaving splits the input frame into 2
+fields (so called half pictures). Odd lines are moved to the top
+half of the output image, even lines to the bottom half.
+You can process (filter) them independently and then re-interleave them.
+
+The filter accepts the following options:
+
+@table @option
+@item luma_mode, l
+@item chroma_mode, c
+@item alpha_mode, a
+Available values for @var{luma_mode}, @var{chroma_mode} and
+@var{alpha_mode} are:
+
+@table @samp
+@item none
+Do nothing.
+
+@item deinterleave, d
+Deinterleave fields, placing one above the other.
+
+@item interleave, i
+Interleave fields. Reverse the effect of deinterleaving.
+@end table
+Default value is @code{none}.
+
+@item luma_swap, ls
+@item chroma_swap, cs
+@item alpha_swap, as
+Swap luma/chroma/alpha fields. Exchange even & odd lines. Default value is @code{0}.
+@end table
+
@section interlace
Simple interlacing filter from progressive contents. This interleaves upper (or
@@ -1637,6 +6193,140 @@ Enable (default) or disable the vertical lowpass filter to avoid twitter
interlacing and reduce moire patterns.
@end table
+@section kerndeint
+
+Deinterlace input video by applying Donald Graft's adaptive kernel
+deinterling. Work on interlaced parts of a video to produce
+progressive frames.
+
+The description of the accepted parameters follows.
+
+@table @option
+@item thresh
+Set the threshold which affects the filter's tolerance when
+determining if a pixel line must be processed. It must be an integer
+in the range [0,255] and defaults to 10. A value of 0 will result in
+applying the process on every pixels.
+
+@item map
+Paint pixels exceeding the threshold value to white if set to 1.
+Default is 0.
+
+@item order
+Set the fields order. Swap fields if set to 1, leave fields alone if
+0. Default is 0.
+
+@item sharp
+Enable additional sharpening if set to 1. Default is 0.
+
+@item twoway
+Enable twoway sharpening if set to 1. Default is 0.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Apply default values:
+@example
+kerndeint=thresh=10:map=0:order=0:sharp=0:twoway=0
+@end example
+
+@item
+Enable additional sharpening:
+@example
+kerndeint=sharp=1
+@end example
+
+@item
+Paint processed pixels in white:
+@example
+kerndeint=map=1
+@end example
+@end itemize
+
+@section lenscorrection
+
+Correct radial lens distortion
+
+This filter can be used to correct for radial distortion as can result from the use
+of wide angle lenses, and thereby re-rectify the image. To find the right parameters
+one can use tools available for example as part of opencv or simply trial-and-error.
+To use opencv use the calibration sample (under samples/cpp) from the opencv sources
+and extract the k1 and k2 coefficients from the resulting matrix.
+
+Note that effectively the same filter is available in the open-source tools Krita and
+Digikam from the KDE project.
+
+In contrast to the @ref{vignette} filter, which can also be used to compensate lens errors,
+this filter corrects the distortion of the image, whereas @ref{vignette} corrects the
+brightness distribution, so you may want to use both filters together in certain
+cases, though you will have to take care of ordering, i.e. whether vignetting should
+be applied before or after lens correction.
+
+@subsection Options
+
+The filter accepts the following options:
+
+@table @option
+@item cx
+Relative x-coordinate of the focal point of the image, and thereby the center of the
+distortion. This value has a range [0,1] and is expressed as fractions of the image
+width.
+@item cy
+Relative y-coordinate of the focal point of the image, and thereby the center of the
+distortion. This value has a range [0,1] and is expressed as fractions of the image
+height.
+@item k1
+Coefficient of the quadratic correction term. 0.5 means no correction.
+@item k2
+Coefficient of the double quadratic correction term. 0.5 means no correction.
+@end table
+
+The formula that generates the correction is:
+
+@var{r_src} = @var{r_tgt} * (1 + @var{k1} * (@var{r_tgt} / @var{r_0})^2 + @var{k2} * (@var{r_tgt} / @var{r_0})^4)
+
+where @var{r_0} is halve of the image diagonal and @var{r_src} and @var{r_tgt} are the
+distances from the focal point in the source and target images, respectively.
+
+@anchor{lut3d}
+@section lut3d
+
+Apply a 3D LUT to an input video.
+
+The filter accepts the following options:
+
+@table @option
+@item file
+Set the 3D LUT file name.
+
+Currently supported formats:
+@table @samp
+@item 3dl
+AfterEffects
+@item cube
+Iridas
+@item dat
+DaVinci
+@item m3d
+Pandora
+@end table
+@item interp
+Select interpolation mode.
+
+Available values are:
+
+@table @samp
+@item nearest
+Use values from the nearest defined point.
+@item trilinear
+Interpolate values using the 8 points defining a cube.
+@item tetrahedral
+Interpolate values using a tetrahedron.
+@end table
+@end table
+
@section lut, lutrgb, lutyuv
Compute a look-up table for binding each pixel component input value
@@ -1647,19 +6337,30 @@ to an RGB input video.
These filters accept the following parameters:
@table @option
-@item @var{c0} (first pixel component)
-@item @var{c1} (second pixel component)
-@item @var{c2} (third pixel component)
-@item @var{c3} (fourth pixel component, corresponds to the alpha component)
-
-@item @var{r} (red component)
-@item @var{g} (green component)
-@item @var{b} (blue component)
-@item @var{a} (alpha component)
+@item c0
+set first pixel component expression
+@item c1
+set second pixel component expression
+@item c2
+set third pixel component expression
+@item c3
+set fourth pixel component expression, corresponds to the alpha component
+
+@item r
+set red component expression
+@item g
+set green component expression
+@item b
+set blue component expression
+@item a
+alpha component expression
-@item @var{y} (Y/luminance component)
-@item @var{u} (U/Cb component)
-@item @var{v} (V/Cr component)
+@item y
+set Y/luminance component expression
+@item u
+set U/Cb component expression
+@item v
+set V/Cr component expression
@end table
Each of them specifies the expression to use for computing the lookup table for
@@ -1674,11 +6375,8 @@ The @var{lut} filter requires either YUV or RGB pixel formats in input,
The expressions can contain the following constants and functions:
@table @option
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
-
-@item w, h
+@item w
+@item h
The input width and height.
@item val
@@ -1712,35 +6410,207 @@ expression
All expressions default to "val".
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Negate input video:
@example
-# Negate input video
lutrgb="r=maxval+minval-val:g=maxval+minval-val:b=maxval+minval-val"
lutyuv="y=maxval+minval-val:u=maxval+minval-val:v=maxval+minval-val"
+@end example
-# The above is the same as
+The above is the same as:
+@example
lutrgb="r=negval:g=negval:b=negval"
lutyuv="y=negval:u=negval:v=negval"
+@end example
-# Negate luminance
-lutyuv=negval
+@item
+Negate luminance:
+@example
+lutyuv=y=negval
+@end example
-# Remove chroma components, turning the video into a graytone image
+@item
+Remove chroma components, turning the video into a graytone image:
+@example
lutyuv="u=128:v=128"
+@end example
-# Apply a luma burning effect
+@item
+Apply a luma burning effect:
+@example
lutyuv="y=2*val"
+@end example
-# Remove green and blue components
+@item
+Remove green and blue components:
+@example
lutrgb="g=0:b=0"
+@end example
-# Set a constant alpha channel value on input
+@item
+Set a constant alpha channel value on input:
+@example
format=rgba,lutrgb=a="maxval-minval/2"
+@end example
-# Correct luminance gamma by a factor of 0.5
+@item
+Correct luminance gamma by a factor of 0.5:
+@example
lutyuv=y=gammaval(0.5)
@end example
+@item
+Discard least significant bits of luma:
+@example
+lutyuv=y='bitand(val, 128+64+32)'
+@end example
+@end itemize
+
+@section mergeplanes
+
+Merge color channel components from several video streams.
+
+The filter accepts up to 4 input streams, and merge selected input
+planes to the output video.
+
+This filter accepts the following options:
+@table @option
+@item mapping
+Set input to output plane mapping. Default is @code{0}.
+
+The mappings is specified as a bitmap. It should be specified as a
+hexadecimal number in the form 0xAa[Bb[Cc[Dd]]]. 'Aa' describes the
+mapping for the first plane of the output stream. 'A' sets the number of
+the input stream to use (from 0 to 3), and 'a' the plane number of the
+corresponding input to use (from 0 to 3). The rest of the mappings is
+similar, 'Bb' describes the mapping for the output stream second
+plane, 'Cc' describes the mapping for the output stream third plane and
+'Dd' describes the mapping for the output stream fourth plane.
+
+@item format
+Set output pixel format. Default is @code{yuva444p}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Merge three gray video streams of same width and height into single video stream:
+@example
+[a0][a1][a2]mergeplanes=0x001020:yuv444p
+@end example
+
+@item
+Merge 1st yuv444p stream and 2nd gray video stream into yuva444p video stream:
+@example
+[a0][a1]mergeplanes=0x00010210:yuva444p
+@end example
+
+@item
+Swap Y and A plane in yuva444p stream:
+@example
+format=yuva444p,mergeplanes=0x03010200:yuva444p
+@end example
+
+@item
+Swap U and V plane in yuv420p stream:
+@example
+format=yuv420p,mergeplanes=0x000201:yuv420p
+@end example
+
+@item
+Cast a rgb24 clip to yuv444p:
+@example
+format=rgb24,mergeplanes=0x000102:yuv444p
+@end example
+@end itemize
+
+@section mcdeint
+
+Apply motion-compensation deinterlacing.
+
+It needs one field per frame as input and must thus be used together
+with yadif=1/3 or equivalent.
+
+This filter accepts the following options:
+@table @option
+@item mode
+Set the deinterlacing mode.
+
+It accepts one of the following values:
+@table @samp
+@item fast
+@item medium
+@item slow
+use iterative motion estimation
+@item extra_slow
+like @samp{slow}, but use multiple reference frames.
+@end table
+Default value is @samp{fast}.
+
+@item parity
+Set the picture field parity assumed for the input video. It must be
+one of the following values:
+
+@table @samp
+@item 0, tff
+assume top field first
+@item 1, bff
+assume bottom field first
+@end table
+
+Default value is @samp{bff}.
+
+@item qp
+Set per-block quantization parameter (QP) used by the internal
+encoder.
+
+Higher values should result in a smoother motion vector field but less
+optimal individual vectors. Default value is 1.
+@end table
+
+@section mpdecimate
+
+Drop frames that do not differ greatly from the previous frame in
+order to reduce frame rate.
+
+The main use of this filter is for very-low-bitrate encoding
+(e.g. streaming over dialup modem), but it could in theory be used for
+fixing movies that were inverse-telecined incorrectly.
+
+A description of the accepted options follows.
+
+@table @option
+@item max
+Set the maximum number of consecutive frames which can be dropped (if
+positive), or the minimum interval between dropped frames (if
+negative). If the value is 0, the frame is dropped unregarding the
+number of previous sequentially dropped frames.
+
+Default value is 0.
+
+@item hi
+@item lo
+@item frac
+Set the dropping threshold values.
+
+Values for @option{hi} and @option{lo} are for 8x8 pixel blocks and
+represent actual pixel value differences, so a threshold of 64
+corresponds to 1 unit of difference for each pixel, or the same spread
+out differently over the block.
+
+A frame is a candidate for dropping if no 8x8 blocks differ by more
+than a threshold of @option{hi}, and if no more than @option{frac} blocks (1
+meaning the whole image) differ by more than a threshold of @option{lo}.
+
+Default value for @option{hi} is 64*12, default value for @option{lo} is
+64*5, and default value for @option{frac} is 0.33.
+@end table
+
+
@section negate
Negate input video.
@@ -1762,15 +6632,71 @@ apix_fmts=yuv420p|monow|rgb24".
@end table
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Force libavfilter to use a format different from @var{yuv420p} for the
+input to the vflip filter:
@example
-# Force libavfilter to use a format different from "yuv420p" for the
-# input to the vflip filter
noformat=pix_fmts=yuv420p,vflip
+@end example
-# Convert the input video to any of the formats not contained in the list
+@item
+Convert the input video to any of the formats not contained in the list:
+@example
noformat=yuv420p|yuv444p|yuv410p
@end example
+@end itemize
+
+@section noise
+
+Add noise on video input frame.
+
+The filter accepts the following options:
+
+@table @option
+@item all_seed
+@item c0_seed
+@item c1_seed
+@item c2_seed
+@item c3_seed
+Set noise seed for specific pixel component or all pixel components in case
+of @var{all_seed}. Default value is @code{123457}.
+
+@item all_strength, alls
+@item c0_strength, c0s
+@item c1_strength, c1s
+@item c2_strength, c2s
+@item c3_strength, c3s
+Set noise strength for specific pixel component or all pixel components in case
+@var{all_strength}. Default value is @code{0}. Allowed range is [0, 100].
+
+@item all_flags, allf
+@item c0_flags, c0f
+@item c1_flags, c1f
+@item c2_flags, c2f
+@item c3_flags, c3f
+Set pixel component flags or set flags for all components if @var{all_flags}.
+Available values for component flags are:
+@table @samp
+@item a
+averaged temporal noise (smoother)
+@item p
+mix random noise with a (semi)regular pattern
+@item t
+temporal noise (noise pattern changes between frames)
+@item u
+uniform noise (gaussian otherwise)
+@end table
+@end table
+
+@subsection Examples
+
+Add temporal and uniform noise to input video:
+@example
+noise=alls=20:allf=t+u
+@end example
@section null
@@ -1781,7 +6707,7 @@ Pass the video source unchanged to the output.
Apply a video transform using libopencv.
To enable this filter, install the libopencv library and headers and
-configure Libav with --enable-libopencv.
+configure FFmpeg with @code{--enable-libopencv}.
It accepts the following parameters:
@@ -1798,7 +6724,7 @@ values are assumed.
Refer to the official libopencv documentation for more precise
information:
-@url{http://opencv.willowgarage.com/documentation/c/image_filtering.html}
+@url{http://docs.opencv.org/master/modules/imgproc/doc/filtering.html}
Several libopencv filters are supported; see the following subsections.
@@ -1886,34 +6812,19 @@ libopencv function @code{cvSmooth}.
Overlay one video on top of another.
It takes two inputs and has one output. The first input is the "main"
-video on which the second input is overlayed.
+video on which the second input is overlaid.
It accepts the following parameters:
-@table @option
+A description of the accepted options follows.
+@table @option
@item x
-The horizontal position of the left edge of the overlaid video on the main video.
-
@item y
-The vertical position of the top edge of the overlaid video on the main video.
-
-@end table
-
-The parameters are expressions containing the following parameters:
-
-@table @option
-@item main_w, main_h
-The main input width and height.
-
-@item W, H
-These are the same as @var{main_w} and @var{main_h}.
-
-@item overlay_w, overlay_h
-The overlay input width and height.
-
-@item w, h
-These are the same as @var{overlay_w} and @var{overlay_h}.
+Set the expression for the x and y coordinates of the overlaid video
+on the main video. Default value is "0" for both expressions. In case
+the expression is invalid, it is set to a huge value (meaning that the
+overlay will not be displayed within the output visible area).
@item eof_action
The action to take when EOF is encountered on the secondary input; it accepts
@@ -1928,40 +6839,229 @@ End both streams.
Pass the main input through.
@end table
+@item eval
+Set when the expressions for @option{x}, and @option{y} are evaluated.
+
+It accepts the following values:
+@table @samp
+@item init
+only evaluate expressions once during the filter initialization or
+when a command is processed
+
+@item frame
+evaluate expressions for each incoming frame
+@end table
+
+Default value is @samp{frame}.
+
+@item shortest
+If set to 1, force the output to terminate when the shortest input
+terminates. Default value is 0.
+
+@item format
+Set the format for the output video.
+
+It accepts the following values:
+@table @samp
+@item yuv420
+force YUV420 output
+
+@item yuv422
+force YUV422 output
+
+@item yuv444
+force YUV444 output
+
+@item rgb
+force RGB output
+@end table
+
+Default value is @samp{yuv420}.
+
+@item rgb @emph{(deprecated)}
+If set to 1, force the filter to accept inputs in the RGB
+color space. Default value is 0. This option is deprecated, use
+@option{format} instead.
+
+@item repeatlast
+If set to 1, force the filter to draw the last overlay frame over the
+main input until the end of the stream. A value of 0 disables this
+behavior. Default value is 1.
+@end table
+
+The @option{x}, and @option{y} expressions can contain the following
+parameters.
+
+@table @option
+@item main_w, W
+@item main_h, H
+The main input width and height.
+
+@item overlay_w, w
+@item overlay_h, h
+The overlay input width and height.
+
+@item x
+@item y
+The computed values for @var{x} and @var{y}. They are evaluated for
+each new frame.
+
+@item hsub
+@item vsub
+horizontal and vertical chroma subsample values of the output
+format. For example for the pixel format "yuv422p" @var{hsub} is 2 and
+@var{vsub} is 1.
+
+@item n
+the number of input frame, starting from 0
+
+@item pos
+the position in the file of the input frame, NAN if unknown
+
+@item t
+The timestamp, expressed in seconds. It's NAN if the input timestamp is unknown.
+
@end table
+Note that the @var{n}, @var{pos}, @var{t} variables are available only
+when evaluation is done @emph{per frame}, and will evaluate to NAN
+when @option{eval} is set to @samp{init}.
+
Be aware that frames are taken from each input video in timestamp
-order, hence, if their initial timestamps differ, it is a a good idea
+order, hence, if their initial timestamps differ, it is a good idea
to pass the two inputs through a @var{setpts=PTS-STARTPTS} filter to
have them begin in the same zero timestamp, as the example for
the @var{movie} filter does.
-Some examples:
+You can chain together more overlays but you should test the
+efficiency of such approach.
+
+@subsection Commands
+
+This filter supports the following commands:
+@table @option
+@item x
+@item y
+Modify the x and y of the overlay input.
+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
+
+@subsection Examples
+
+@itemize
+@item
+Draw the overlay at 10 pixels from the bottom right corner of the main
+video:
+@example
+overlay=main_w-overlay_w-10:main_h-overlay_h-10
+@end example
+
+Using named options the example above becomes:
@example
-# Draw the overlay at 10 pixels from the bottom right
-# corner of the main video
overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10
+@end example
-# Insert a transparent PNG logo in the bottom left corner of the input
-avconv -i input -i logo -filter_complex 'overlay=x=10:y=main_h-overlay_h-10' output
+@item
+Insert a transparent PNG logo in the bottom left corner of the input,
+using the @command{ffmpeg} tool with the @code{-filter_complex} option:
+@example
+ffmpeg -i input -i logo -filter_complex 'overlay=10:main_h-overlay_h-10' output
+@end example
-# Insert 2 different transparent PNG logos (second logo on bottom
-# right corner)
-avconv -i input -i logo1 -i logo2 -filter_complex
-'overlay=x=10:y=H-h-10,overlay=x=W-w-10:y=H-h-10' output
+@item
+Insert 2 different transparent PNG logos (second logo on bottom
+right corner) using the @command{ffmpeg} tool:
+@example
+ffmpeg -i input -i logo1 -i logo2 -filter_complex 'overlay=x=10:y=H-h-10,overlay=x=W-w-10:y=H-h-10' output
+@end example
-# Add a transparent color layer on top of the main video;
-# WxH specifies the size of the main input to the overlay filter
-color=red@.3:WxH [over]; [in][over] overlay [out]
+@item
+Add a transparent color layer on top of the main video; @code{WxH}
+must specify the size of the main input to the overlay filter:
+@example
+color=color=red@@.3:size=WxH [over]; [in][over] overlay [out]
+@end example
-# Mask 10-20 seconds of a video by applying the delogo filter to a section
-avconv -i test.avi -codec:v:0 wmv2 -ar 11025 -b:v 9000k
+@item
+Play an original video and a filtered version (here with the deshake
+filter) side by side using the @command{ffplay} tool:
+@example
+ffplay input.avi -vf 'split[a][b]; [a]pad=iw*2:ih[src]; [b]deshake[filt]; [src][filt]overlay=w'
+@end example
+
+The above command is the same as:
+@example
+ffplay input.avi -vf 'split[b], pad=iw*2[src], [b]deshake, [src]overlay=w'
+@end example
+
+@item
+Make a sliding overlay appearing from the left to the right top part of the
+screen starting since time 2:
+@example
+overlay=x='if(gte(t,2), -w+(t-2)*20, NAN)':y=0
+@end example
+
+@item
+Compose output by putting two input videos side to side:
+@example
+ffmpeg -i left.avi -i right.avi -filter_complex "
+nullsrc=size=200x100 [background];
+[0:v] setpts=PTS-STARTPTS, scale=100x100 [left];
+[1:v] setpts=PTS-STARTPTS, scale=100x100 [right];
+[background][left] overlay=shortest=1 [background+left];
+[background+left][right] overlay=shortest=1:x=100 [left+right]
+"
+@end example
+
+@item
+Mask 10-20 seconds of a video by applying the delogo filter to a section
+@example
+ffmpeg -i test.avi -codec:v:0 wmv2 -ar 11025 -b:v 9000k
-vf '[in]split[split_main][split_delogo];[split_delogo]trim=start=360:end=371,delogo=0:0:640:480[delogoed];[split_main][delogoed]overlay=eof_action=pass[out]'
masked.avi
@end example
-You can chain together more overlays but the efficiency of such
-approach is yet to be tested.
+@item
+Chain several overlays in cascade:
+@example
+nullsrc=s=200x200 [bg];
+testsrc=s=100x100, split=4 [in0][in1][in2][in3];
+[in0] lutrgb=r=0, [bg] overlay=0:0 [mid0];
+[in1] lutrgb=g=0, [mid0] overlay=100:0 [mid1];
+[in2] lutrgb=b=0, [mid1] overlay=0:100 [mid2];
+[in3] null, [mid2] overlay=100:100 [out0]
+@end example
+
+@end itemize
+
+@section owdenoise
+
+Apply Overcomplete Wavelet denoiser.
+
+The filter accepts the following options:
+
+@table @option
+@item depth
+Set depth.
+
+Larger depth values will denoise lower frequency components more, but
+slow down filtering.
+
+Must be an int in the range 8-16, default is @code{8}.
+
+@item luma_strength, ls
+Set luma strength.
+
+Must be a double value in the range 0-1000, default is @code{1.0}.
+
+@item chroma_strength, cs
+Set chroma strength.
+
+Must be a double value in the range 0-1000, default is @code{1.0}.
+@end table
@section pad
@@ -1971,19 +7071,19 @@ provided @var{x}, @var{y} coordinates.
It accepts the following parameters:
@table @option
-@item width, height
-
-Specify 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.
+@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, y
-
+@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.
@@ -1993,71 +7093,346 @@ expression, and vice versa.
The default value of @var{x} and @var{y} is 0.
@item color
-
-Specify the color of the padded area. It can be the name of a color
-(case insensitive match) or an 0xRRGGBB[AA] sequence.
+Specify the color of the padded area. For the syntax of this option,
+check the "Color" section in the ffmpeg-utils manual.
The default value of @var{color} is "black".
-
@end table
-The parameters @var{width}, @var{height}, @var{x}, and @var{y} are
-expressions containing the following constants:
+The value for the @var{width}, @var{height}, @var{x}, and @var{y}
+options are expressions containing the following constants:
@table @option
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
-
-@item in_w, in_h
+@item in_w
+@item in_h
The input video width and height.
-@item iw, ih
+@item iw
+@item ih
These are the same as @var{in_w} and @var{in_h}.
-@item out_w, out_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, oh
+@item ow
+@item oh
These are the same as @var{out_w} and @var{out_h}.
-@item x, y
+@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
-The input display aspect ratio, same as @var{iw} / @var{ih}.
+same as @var{iw} / @var{ih}
-@item hsub, vsub
+@item sar
+input sample aspect ratio
+
+@item dar
+input display aspect ratio, it is the same as (@var{iw} / @var{ih}) * @var{sar}
+
+@item hsub
+@item vsub
The horizontal and vertical chroma subsample values. For example for the
pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
@end table
-Some examples:
+@subsection Examples
+
+@itemize
+@item
+Add paddings with the color "violet" to the input video. The output video
+size is 640x480, and the top-left corner of the input video is placed at
+column 0, row 40
+@example
+pad=640:480:0:40:violet
+@end example
+The example above is equivalent to the following command:
@example
-# Add paddings with the color "violet" to the input video. The output video
-# size is 640x480, and the top-left corner of the input video is placed at
-# column 0, row 40
pad=width=640:height=480:x=0:y=40:color=violet
+@end example
-# Pad the input to get an output with dimensions increased by 3/2,
-# and put the input video at the center of the padded area
+@item
+Pad the input to get an output with dimensions increased by 3/2,
+and put the input video at the center of the padded area:
+@example
pad="3/2*iw:3/2*ih:(ow-iw)/2:(oh-ih)/2"
+@end example
-# Pad the input to get a squared output with size equal to the maximum
-# value between the input width and height, and put the input video at
-# the center of the padded area
+@item
+Pad the input to get a squared output with size equal to the maximum
+value between the input width and height, and put the input video at
+the center of the padded area:
+@example
pad="max(iw\,ih):ow:(ow-iw)/2:(oh-ih)/2"
+@end example
-# Pad the input to get a final w/h ratio of 16:9
+@item
+Pad the input to get a final w/h ratio of 16:9:
+@example
pad="ih*16/9:ih:(ow-iw)/2:(oh-ih)/2"
+@end example
+
+@item
+In case of anamorphic video, in order to set the output display aspect
+correctly, it is necessary to use @var{sar} in the expression,
+according to the relation:
+@example
+(ih * X / ih) * sar = output_dar
+X = output_dar / sar
+@end example
+
+Thus the previous example needs to be modified to:
+@example
+pad="ih*16/9/sar:ih:(ow-iw)/2:(oh-ih)/2"
+@end example
-# Double the output size and put the input video in the bottom-right
-# corner of the output padded area
+@item
+Double the output size and put the input video in the bottom-right
+corner of the output padded area:
+@example
pad="2*iw:2*ih:ow-iw:oh-ih"
@end example
+@end itemize
+
+@anchor{palettegen}
+@section palettegen
+
+Generate one palette for a whole video stream.
+
+It accepts the following options:
+
+@table @option
+@item max_colors
+Set the maximum number of colors to quantize in the palette.
+Note: the palette will still contain 256 colors; the unused palette entries
+will be black.
+
+@item reserve_transparent
+Create a palette of 255 colors maximum and reserve the last one for
+transparency. Reserving the transparency color is useful for GIF optimization.
+If not set, the maximum of colors in the palette will be 256. You probably want
+to disable this option for a standalone image.
+Set by default.
+
+@item stats_mode
+Set statistics mode.
+
+It accepts the following values:
+@table @samp
+@item full
+Compute full frame histograms.
+@item diff
+Compute histograms only for the part that differs from previous frame. This
+might be relevant to give more importance to the moving part of your input if
+the background is static.
+@end table
+
+Default value is @var{full}.
+@end table
+
+The filter also exports the frame metadata @code{lavfi.color_quant_ratio}
+(@code{nb_color_in / nb_color_out}) which you can use to evaluate the degree of
+color quantization of the palette. This information is also visible at
+@var{info} logging level.
+
+@subsection Examples
+
+@itemize
+@item
+Generate a representative palette of a given video using @command{ffmpeg}:
+@example
+ffmpeg -i input.mkv -vf palettegen palette.png
+@end example
+@end itemize
+
+@section paletteuse
+
+Use a palette to downsample an input video stream.
+
+The filter takes two inputs: one video stream and a palette. The palette must
+be a 256 pixels image.
+
+It accepts the following options:
+
+@table @option
+@item dither
+Select dithering mode. Available algorithms are:
+@table @samp
+@item bayer
+Ordered 8x8 bayer dithering (deterministic)
+@item heckbert
+Dithering as defined by Paul Heckbert in 1982 (simple error diffusion).
+Note: this dithering is sometimes considered "wrong" and is included as a
+reference.
+@item floyd_steinberg
+Floyd and Steingberg dithering (error diffusion)
+@item sierra2
+Frankie Sierra dithering v2 (error diffusion)
+@item sierra2_4a
+Frankie Sierra dithering v2 "Lite" (error diffusion)
+@end table
+
+Default is @var{sierra2_4a}.
+
+@item bayer_scale
+When @var{bayer} dithering is selected, this option defines the scale of the
+pattern (how much the crosshatch pattern is visible). A low value means more
+visible pattern for less banding, and higher value means less visible pattern
+at the cost of more banding.
+
+The option must be an integer value in the range [0,5]. Default is @var{2}.
+
+@item diff_mode
+If set, define the zone to process
+
+@table @samp
+@item rectangle
+Only the changing rectangle will be reprocessed. This is similar to GIF
+cropping/offsetting compression mechanism. This option can be useful for speed
+if only a part of the image is changing, and has use cases such as limiting the
+scope of the error diffusal @option{dither} to the rectangle that bounds the
+moving scene (it leads to more deterministic output if the scene doesn't change
+much, and as a result less moving noise and better GIF compression).
+@end table
+
+Default is @var{none}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Use a palette (generated for example with @ref{palettegen}) to encode a GIF
+using @command{ffmpeg}:
+@example
+ffmpeg -i input.mkv -i palette.png -lavfi paletteuse output.gif
+@end example
+@end itemize
+
+@section perspective
+
+Correct perspective of video not recorded perpendicular to the screen.
+
+A description of the accepted parameters follows.
+
+@table @option
+@item x0
+@item y0
+@item x1
+@item y1
+@item x2
+@item y2
+@item x3
+@item y3
+Set coordinates expression for top left, top right, bottom left and bottom right corners.
+Default values are @code{0:0:W:0:0:H:W:H} with which perspective will remain unchanged.
+If the @code{sense} option is set to @code{source}, then the specified points will be sent
+to the corners of the destination. If the @code{sense} option is set to @code{destination},
+then the corners of the source will be sent to the specified coordinates.
+
+The expressions can use the following variables:
+
+@table @option
+@item W
+@item H
+the width and height of video frame.
+@end table
+
+@item interpolation
+Set interpolation for perspective correction.
+
+It accepts the following values:
+@table @samp
+@item linear
+@item cubic
+@end table
+
+Default value is @samp{linear}.
+
+@item sense
+Set interpretation of coordinate options.
+
+It accepts the following values:
+@table @samp
+@item 0, source
+
+Send point in the source specified by the given coordinates to
+the corners of the destination.
+
+@item 1, destination
+
+Send the corners of the source to the point in the destination specified
+by the given coordinates.
+
+Default value is @samp{source}.
+@end table
+@end table
+
+@section phase
+
+Delay interlaced video by one field time so that the field order changes.
+
+The intended use is to fix PAL movies that have been captured with the
+opposite field order to the film-to-video transfer.
+
+A description of the accepted parameters follows.
+
+@table @option
+@item mode
+Set phase mode.
+
+It accepts the following values:
+@table @samp
+@item t
+Capture field order top-first, transfer bottom-first.
+Filter will delay the bottom field.
+
+@item b
+Capture field order bottom-first, transfer top-first.
+Filter will delay the top field.
+
+@item p
+Capture and transfer with the same field order. This mode only exists
+for the documentation of the other options to refer to, but if you
+actually select it, the filter will faithfully do nothing.
+
+@item a
+Capture field order determined automatically by field flags, transfer
+opposite.
+Filter selects among @samp{t} and @samp{b} modes on a frame by frame
+basis using field flags. If no field information is available,
+then this works just like @samp{u}.
+
+@item u
+Capture unknown or varying, transfer opposite.
+Filter selects among @samp{t} and @samp{b} on a frame by frame basis by
+analyzing the images and selecting the alternative that produces best
+match between the fields.
+
+@item T
+Capture top-first, transfer unknown or varying.
+Filter selects among @samp{t} and @samp{p} using image analysis.
+
+@item B
+Capture bottom-first, transfer unknown or varying.
+Filter selects among @samp{b} and @samp{p} using image analysis.
+
+@item A
+Capture determined by field flags, transfer unknown or varying.
+Filter selects among @samp{t}, @samp{b} and @samp{p} using field flags and
+image analysis. If no field information is available, then this works just
+like @samp{U}. This is the default mode.
+
+@item U
+Both capture and transfer unknown or varying.
+Filter selects among @samp{t}, @samp{b} and @samp{p} using image analysis only.
+@end table
+@end table
@section pixdesctest
@@ -2071,367 +7446,916 @@ format=monow, pixdesctest
can be used to test the monowhite pixel format descriptor definition.
-@anchor{scale}
-@section scale
+@section pp
-Scale the input video and/or convert the image format.
+Enable the specified chain of postprocessing subfilters using libpostproc. This
+library should be automatically selected with a GPL build (@code{--enable-gpl}).
+Subfilters must be separated by '/' and can be disabled by prepending a '-'.
+Each subfilter and some options have a short and a long name that can be used
+interchangeably, i.e. dr/dering are the same.
-It accepts the following parameters:
+The filters accept the following options:
@table @option
+@item subfilters
+Set postprocessing subfilters string.
+@end table
-@item w
-The output video width.
+All subfilters share common options to determine their scope:
-@item h
-The output video height.
+@table @option
+@item a/autoq
+Honor the quality commands for this subfilter.
+
+@item c/chrom
+Do chrominance filtering, too (default).
+@item y/nochrom
+Do luminance filtering only (no chrominance).
+
+@item n/noluma
+Do chrominance filtering only (no luminance).
@end table
-The parameters @var{w} and @var{h} are expressions containing
-the following constants:
+These options can be appended after the subfilter name, separated by a '|'.
+
+Available subfilters are:
@table @option
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+@item hb/hdeblock[|difference[|flatness]]
+Horizontal deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
-@item in_w, in_h
-The input width and height.
+@item vb/vdeblock[|difference[|flatness]]
+Vertical deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
-@item iw, ih
-These are the same as @var{in_w} and @var{in_h}.
+@item ha/hadeblock[|difference[|flatness]]
+Accurate horizontal deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
-@item out_w, out_h
-The output (cropped) width and height.
+@item va/vadeblock[|difference[|flatness]]
+Accurate vertical deblocking filter
+@table @option
+@item difference
+Difference factor where higher values mean more deblocking (default: @code{32}).
+@item flatness
+Flatness threshold where lower values mean more deblocking (default: @code{39}).
+@end table
+@end table
-@item ow, oh
-These are the same as @var{out_w} and @var{out_h}.
+The horizontal and vertical deblocking filters share the difference and
+flatness values so you cannot set different horizontal and vertical
+thresholds.
-@item a
-This is the same as @var{iw} / @var{ih}.
+@table @option
+@item h1/x1hdeblock
+Experimental horizontal deblocking filter
-@item sar
-input sample aspect ratio
+@item v1/x1vdeblock
+Experimental vertical deblocking filter
-@item dar
-The input display aspect ratio; it is the same as
-(@var{iw} / @var{ih}) * @var{sar}.
+@item dr/dering
+Deringing filter
-@item hsub, vsub
-The horizontal and vertical chroma subsample values. For example, for the
-pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+@item tn/tmpnoise[|threshold1[|threshold2[|threshold3]]], temporal noise reducer
+@table @option
+@item threshold1
+larger -> stronger filtering
+@item threshold2
+larger -> stronger filtering
+@item threshold3
+larger -> stronger filtering
@end table
-If the input image format is different from the format requested by
-the next filter, the scale filter will convert the input to the
-requested format.
+@item al/autolevels[:f/fullyrange], automatic brightness / contrast correction
+@table @option
+@item f/fullyrange
+Stretch luminance to @code{0-255}.
+@end table
-If the value for @var{w} or @var{h} is 0, the respective input
-size is used for the output.
+@item lb/linblenddeint
+Linear blend deinterlacing filter that deinterlaces the given block by
+filtering all lines with a @code{(1 2 1)} filter.
-If the value for @var{w} or @var{h} is -1, the scale filter will use, for the
-respective output size, a value that maintains the aspect ratio of the input
-image.
+@item li/linipoldeint
+Linear interpolating deinterlacing filter that deinterlaces the given block by
+linearly interpolating every second line.
-The default value of @var{w} and @var{h} is 0.
+@item ci/cubicipoldeint
+Cubic interpolating deinterlacing filter deinterlaces the given block by
+cubically interpolating every second line.
-Some examples:
-@example
-# Scale the input video to a size of 200x100
-scale=w=200:h=100
+@item md/mediandeint
+Median deinterlacing filter that deinterlaces the given block by applying a
+median filter to every second line.
-# Scale the input to 2x
-scale=w=2*iw:h=2*ih
-# The above is the same as
-scale=2*in_w:2*in_h
+@item fd/ffmpegdeint
+FFmpeg deinterlacing filter that deinterlaces the given block by filtering every
+second line with a @code{(-1 4 2 4 -1)} filter.
-# Scale the input to half the original size
-scale=w=iw/2:h=ih/2
+@item l5/lowpass5
+Vertically applied FIR lowpass deinterlacing filter that deinterlaces the given
+block by filtering all lines with a @code{(-1 2 6 2 -1)} filter.
-# Increase the width, and set the height to the same size
-scale=3/2*iw:ow
+@item fq/forceQuant[|quantizer]
+Overrides the quantizer table from the input with the constant quantizer you
+specify.
+@table @option
+@item quantizer
+Quantizer to use
+@end table
-# Seek Greek harmony
-scale=iw:1/PHI*iw
-scale=ih*PHI:ih
+@item de/default
+Default pp filter combination (@code{hb|a,vb|a,dr|a})
-# Increase the height, and set the width to 3/2 of the height
-scale=w=3/2*oh:h=3/5*ih
+@item fa/fast
+Fast pp filter combination (@code{h1|a,v1|a,dr|a})
-# Increase the size, making the size a multiple of the chroma
-scale="trunc(3/2*iw/hsub)*hsub:trunc(3/2*ih/vsub)*vsub"
+@item ac
+High quality pp filter combination (@code{ha|a|128|7,va|a,dr|a})
+@end table
-# Increase the width to a maximum of 500 pixels,
-# keeping the same aspect ratio as the input
-scale=w='min(500\, iw*3/2):h=-1'
+@subsection Examples
+
+@itemize
+@item
+Apply horizontal and vertical deblocking, deringing and automatic
+brightness/contrast:
+@example
+pp=hb/vb/dr/al
@end example
-@section select
-Select frames to pass in output.
+@item
+Apply default filters without brightness/contrast correction:
+@example
+pp=de/-al
+@end example
-It accepts the following parameters:
+@item
+Apply default filters and temporal denoiser:
+@example
+pp=default/tmpnoise|1|2|3
+@end example
+
+@item
+Apply deblocking on luminance only, and switch vertical deblocking on or off
+automatically depending on available CPU time:
+@example
+pp=hb|y/vb|a
+@end example
+@end itemize
+
+@section pp7
+Apply Postprocessing filter 7. It is variant of the @ref{spp} filter,
+similar to spp = 6 with 7 point DCT, where only the center sample is
+used after IDCT.
+
+The filter accepts the following options:
@table @option
+@item qp
+Force a constant quantization parameter. It accepts an integer in range
+0 to 63. If not set, the filter will use the QP from the video stream
+(if available).
-@item expr
-An expression, which is evaluated for each input frame. If the expression is
-evaluated to a non-zero value, the frame is selected and passed to the output,
-otherwise it is discarded.
+@item mode
+Set thresholding mode. Available modes are:
+@table @samp
+@item hard
+Set hard thresholding.
+@item soft
+Set soft thresholding (better de-ringing effect, but likely blurrier).
+@item medium
+Set medium thresholding (good results, default).
+@end table
@end table
-The expression can contain the following constants:
+@section psnr
+
+Obtain the average, maximum and minimum PSNR (Peak Signal to Noise
+Ratio) between two input videos.
+
+This filter takes in input two input videos, the first input is
+considered the "main" source and is passed unchanged to the
+output. The second input is used as a "reference" video for computing
+the PSNR.
+
+Both video inputs must have the same resolution and pixel format for
+this filter to work correctly. Also it assumes that both inputs
+have the same number of frames, which are compared one by one.
+
+The obtained average PSNR is printed through the logging system.
+
+The filter stores the accumulated MSE (mean squared error) of each
+frame, and at the end of the processing it is averaged across all frames
+equally, and the following formula is applied to obtain the PSNR:
+
+@example
+PSNR = 10*log10(MAX^2/MSE)
+@end example
+
+Where MAX is the average of the maximum values of each component of the
+image.
+
+The description of the accepted parameters follows.
@table @option
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+@item stats_file, f
+If specified the filter will use the named file to save the PSNR of
+each individual frame.
+@end table
+
+The file printed if @var{stats_file} is selected, contains a sequence of
+key/value pairs of the form @var{key}:@var{value} for each compared
+couple of frames.
+A description of each shown parameter follows:
+
+@table @option
@item n
-The (sequential) number of the filtered frame, starting from 0.
+sequential number of the input frame, starting from 1
-@item selected_n
-The (sequential) number of the selected frame, starting from 0.
+@item mse_avg
+Mean Square Error pixel-by-pixel average difference of the compared
+frames, averaged over all the image components.
-@item prev_selected_n
-The sequential number of the last selected frame. It's NAN if undefined.
+@item mse_y, mse_u, mse_v, mse_r, mse_g, mse_g, mse_a
+Mean Square Error pixel-by-pixel average difference of the compared
+frames for the component specified by the suffix.
-@item TB
-The timebase of the input timestamps.
+@item psnr_y, psnr_u, psnr_v, psnr_r, psnr_g, psnr_b, psnr_a
+Peak Signal to Noise ratio of the compared frames for the component
+specified by the suffix.
+@end table
-@item pts
-The PTS (Presentation TimeStamp) of the filtered video frame,
-expressed in @var{TB} units. It's NAN if undefined.
+For example:
+@example
+movie=ref_movie.mpg, setpts=PTS-STARTPTS [main];
+[main][ref] psnr="stats_file=stats.log" [out]
+@end example
-@item t
-The PTS of the filtered video frame,
-expressed in seconds. It's NAN if undefined.
+On this example the input file being processed is compared with the
+reference file @file{ref_movie.mpg}. The PSNR of each individual frame
+is stored in @file{stats.log}.
-@item prev_pts
-The PTS of the previously filtered video frame. It's NAN if undefined.
+@anchor{pullup}
+@section pullup
-@item prev_selected_pts
-The PTS of the last previously filtered video frame. It's NAN if undefined.
+Pulldown reversal (inverse telecine) filter, capable of handling mixed
+hard-telecine, 24000/1001 fps progressive, and 30000/1001 fps progressive
+content.
-@item prev_selected_t
-The PTS of the last previously selected video frame. It's NAN if undefined.
+The pullup filter is designed to take advantage of future context in making
+its decisions. This filter is stateless in the sense that it does not lock
+onto a pattern to follow, but it instead looks forward to the following
+fields in order to identify matches and rebuild progressive frames.
-@item start_pts
-The PTS of the first video frame in the video. It's NAN if undefined.
+To produce content with an even framerate, insert the fps filter after
+pullup, use @code{fps=24000/1001} if the input frame rate is 29.97fps,
+@code{fps=24} for 30fps and the (rare) telecined 25fps input.
-@item start_t
-The time of the first video frame in the video. It's NAN if undefined.
+The filter accepts the following options:
-@item pict_type
-The type of the filtered frame. It can assume one of the following
-values:
@table @option
-@item I
-@item P
-@item B
-@item S
-@item SI
-@item SP
-@item BI
+@item jl
+@item jr
+@item jt
+@item jb
+These options set the amount of "junk" to ignore at the left, right, top, and
+bottom of the image, respectively. Left and right are in units of 8 pixels,
+while top and bottom are in units of 2 lines.
+The default is 8 pixels on each side.
+
+@item sb
+Set the strict breaks. Setting this option to 1 will reduce the chances of
+filter generating an occasional mismatched frame, but it may also cause an
+excessive number of frames to be dropped during high motion sequences.
+Conversely, setting it to -1 will make filter match fields more easily.
+This may help processing of video where there is slight blurring between
+the fields, but may also cause there to be interlaced frames in the output.
+Default value is @code{0}.
+
+@item mp
+Set the metric plane to use. It accepts the following values:
+@table @samp
+@item l
+Use luma plane.
+
+@item u
+Use chroma blue plane.
+
+@item v
+Use chroma red plane.
@end table
-@item interlace_type
-The frame interlace type. It can assume one of the following values:
-@table @option
-@item PROGRESSIVE
-The frame is progressive (not interlaced).
-@item TOPFIRST
-The frame is top-field-first.
-@item BOTTOMFIRST
-The frame is bottom-field-first.
+This option may be set to use chroma plane instead of the default luma plane
+for doing filter's computations. This may improve accuracy on very clean
+source material, but more likely will decrease accuracy, especially if there
+is chroma noise (rainbow effect) or any grayscale video.
+The main purpose of setting @option{mp} to a chroma plane is to reduce CPU
+load and make pullup usable in realtime on slow machines.
@end table
-@item key
-This is 1 if the filtered frame is a key-frame, 0 otherwise.
+For best results (without duplicated frames in the output file) it is
+necessary to change the output frame rate. For example, to inverse
+telecine NTSC input:
+@example
+ffmpeg -i input -vf pullup -r 24000/1001 ...
+@end example
+
+@section qp
+
+Change video quantization parameters (QP).
+
+The filter accepts the following option:
+@table @option
+@item qp
+Set expression for quantization parameter.
@end table
-The default value of the select expression is "1".
+The expression is evaluated through the eval API and can contain, among others,
+the following constants:
-Some examples:
+@table @var
+@item known
+1 if index is not 129, 0 otherwise.
-@example
-# Select all the frames in input
-select
+@item qp
+Sequentional index starting from -129 to 128.
+@end table
-# The above is the same as
-select=expr=1
+@subsection Examples
-# Skip all frames
-select=expr=0
+@itemize
+@item
+Some equation like:
+@example
+qp=2+2*sin(PI*qp)
+@end example
+@end itemize
-# Select only I-frames
-select='expr=eq(pict_type\,I)'
+@section removelogo
-# Select one frame per 100
-select='not(mod(n\,100))'
+Suppress a TV station logo, using an image file to determine which
+pixels comprise the logo. It works by filling in the pixels that
+comprise the logo with neighboring pixels.
-# Select only frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)'
+The filter accepts the following options:
-# Select only I frames contained in the 10-20 time interval
-select='gte(t\,10)*lte(t\,20)*eq(pict_type\,I)'
+@table @option
+@item filename, f
+Set the filter bitmap file, which can be any image format supported by
+libavformat. The width and height of the image file must match those of the
+video stream being processed.
+@end table
-# Select frames with a minimum distance of 10 seconds
-select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)'
-@end example
+Pixels in the provided bitmap image with a value of zero are not
+considered part of the logo, non-zero pixels are considered part of
+the logo. If you use white (255) for the logo and black (0) for the
+rest, you will be safe. For making the filter bitmap, it is
+recommended to take a screen capture of a black frame with the logo
+visible, and then using a threshold filter followed by the erode
+filter once or twice.
-@anchor{setdar}
-@section setdar
+If needed, little splotches can be fixed manually. Remember that if
+logo pixels are not covered, the filter quality will be much
+reduced. Marking too many pixels as part of the logo does not hurt as
+much, but it will increase the amount of blurring needed to cover over
+the image and will destroy more information than necessary, and extra
+pixels will slow things down on a large logo.
-Set the Display Aspect Ratio for the filter output video.
+@section repeatfields
-This is done by changing the specified Sample (aka Pixel) Aspect
-Ratio, according to the following equation:
-@math{DAR = HORIZONTAL_RESOLUTION / VERTICAL_RESOLUTION * SAR}
+This filter uses the repeat_field flag from the Video ES headers and hard repeats
+fields based on its value.
-Keep in mind that this filter does not modify the pixel dimensions of
-the video frame. Also, the display aspect ratio set by this filter may
-be changed by later filters in the filterchain, e.g. in case of
-scaling or if another "setdar" or a "setsar" filter is applied.
+@section rotate
-It accepts the following parameters:
+Rotate video by an arbitrary angle expressed in radians.
+The filter accepts the following options:
+
+A description of the optional parameters follows.
@table @option
+@item angle, a
+Set an expression for the angle by which to rotate the input video
+clockwise, expressed as a number of radians. A negative value will
+result in a counter-clockwise rotation. By default it is set to "0".
-@item dar
-The output display aspect ratio.
+This expression is evaluated for each frame.
+
+@item out_w, ow
+Set the output width expression, default value is "iw".
+This expression is evaluated just once during configuration.
+
+@item out_h, oh
+Set the output height expression, default value is "ih".
+This expression is evaluated just once during configuration.
+@item bilinear
+Enable bilinear interpolation if set to 1, a value of 0 disables
+it. Default value is 1.
+
+@item fillcolor, c
+Set the color used to fill the output area not covered by the rotated
+image. For the general syntax of this option, check the "Color" section in the
+ffmpeg-utils manual. If the special value "none" is selected then no
+background is printed (useful for example if the background is never shown).
+
+Default value is "black".
@end table
-The parameter @var{dar} is an expression containing
-the following constants:
+The expressions for the angle and the output size can contain the
+following constants and functions:
@table @option
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+@item n
+sequential number of the input frame, starting from 0. It is always NAN
+before the first frame is filtered.
-@item w, h
-The input width and height.
+@item t
+time in seconds of the input frame, it is set to 0 when the filter is
+configured. It is always NAN before the first frame is filtered.
-@item a
-This is the same as @var{w} / @var{h}.
+@item hsub
+@item vsub
+horizontal and vertical chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
-@item sar
-The input sample aspect ratio.
+@item in_w, iw
+@item in_h, ih
+the input video width and height
-@item dar
-The input display aspect ratio. It is the same as
-(@var{w} / @var{h}) * @var{sar}.
+@item out_w, ow
+@item out_h, oh
+the output width and height, that is the size of the padded area as
+specified by the @var{width} and @var{height} expressions
-@item hsub, vsub
-The horizontal and vertical chroma subsample values. For example, for the
-pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+@item rotw(a)
+@item roth(a)
+the minimal width/height required for completely containing the input
+video rotated by @var{a} radians.
+
+These are only available when computing the @option{out_w} and
+@option{out_h} expressions.
@end table
-To change the display aspect ratio to 16:9, specify:
+@subsection Examples
+
+@itemize
+@item
+Rotate the input by PI/6 radians clockwise:
@example
-setdar=dar=16/9
-# The above is equivalent to
-setdar=dar=1.77777
+rotate=PI/6
@end example
-Also see the the @ref{setsar} filter documentation.
+@item
+Rotate the input by PI/6 radians counter-clockwise:
+@example
+rotate=-PI/6
+@end example
-@section setpts
+@item
+Rotate the input by 45 degrees clockwise:
+@example
+rotate=45*PI/180
+@end example
-Change the PTS (presentation timestamp) of the input video frames.
+@item
+Apply a constant rotation with period T, starting from an angle of PI/3:
+@example
+rotate=PI/3+2*PI*t/T
+@end example
-It accepts the following parameters:
+@item
+Make the input video rotation oscillating with a period of T
+seconds and an amplitude of A radians:
+@example
+rotate=A*sin(2*PI/T*t)
+@end example
+
+@item
+Rotate the video, output size is chosen so that the whole rotating
+input video is always completely contained in the output:
+@example
+rotate='2*PI*t:ow=hypot(iw,ih):oh=ow'
+@end example
+
+@item
+Rotate the video, reduce the output size so that no background is ever
+shown:
+@example
+rotate=2*PI*t:ow='min(iw,ih)/sqrt(2)':oh=ow:c=none
+@end example
+@end itemize
+
+@subsection Commands
+
+The filter supports the following commands:
@table @option
+@item a, angle
+Set the angle expression.
+The command accepts the same syntax of the corresponding option.
-@item expr
-The expression which is evaluated for each frame to construct its timestamp.
+If the specified expression is not valid, it is kept at its current
+value.
+@end table
+
+@section sab
+
+Apply Shape Adaptive Blur.
+
+The filter accepts the following options:
+@table @option
+@item luma_radius, lr
+Set luma blur filter strength, must be a value in range 0.1-4.0, default
+value is 1.0. A greater value will result in a more blurred image, and
+in slower processing.
+
+@item luma_pre_filter_radius, lpfr
+Set luma pre-filter radius, must be a value in the 0.1-2.0 range, default
+value is 1.0.
+
+@item luma_strength, ls
+Set luma maximum difference between pixels to still be considered, must
+be a value in the 0.1-100.0 range, default value is 1.0.
+
+@item chroma_radius, cr
+Set chroma blur filter strength, must be a value in range 0.1-4.0. A
+greater value will result in a more blurred image, and in slower
+processing.
+
+@item chroma_pre_filter_radius, cpfr
+Set chroma pre-filter radius, must be a value in the 0.1-2.0 range.
+
+@item chroma_strength, cs
+Set chroma maximum difference between pixels to still be considered,
+must be a value in the 0.1-100.0 range.
@end table
-The expression is evaluated through the eval API and can contain the following
-constants:
+Each chroma option value, if not explicitly specified, is set to the
+corresponding luma option value.
+
+@anchor{scale}
+@section scale
+
+Scale (resize) the input video, using the libswscale library.
+
+The scale filter forces the output display aspect ratio to be the same
+of the input, by changing the output sample aspect ratio.
+
+If the input image format is different from the format requested by
+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.
+
+See @ref{scaler_options,,the ffmpeg-scaler manual,ffmpeg-scaler} for
+the complete list of scaler options.
@table @option
-@item PTS
-The presentation timestamp in input.
+@item width, w
+@item height, h
+Set the output video dimension expression. Default value is the input
+dimension.
-@item E, PI, PHI
-These are approximated values for the mathematical constants e
-(Euler's number), pi (Greek pi), and phi (the golden ratio).
+If the value is 0, the input width is used for the output.
-@item N
-The count of the input frame, starting from 0.
+If one of the values is -1, the scale filter will use a value that
+maintains the aspect ratio of the input image, calculated from the
+other specified dimension. If both of them are -1, the input size is
+used
-@item STARTPTS
-The PTS of the first video frame.
+If one of the values is -n with n > 1, the scale filter will also use a value
+that maintains the aspect ratio of the input image, calculated from the other
+specified dimension. After that it will, however, make sure that the calculated
+dimension is divisible by n and adjust the value if necessary.
-@item INTERLACED
-State whether the current frame is interlaced.
+See below for the list of accepted constants for use in the dimension
+expression.
-@item PREV_INPTS
-The previous input PTS.
+@item interl
+Set the interlacing mode. It accepts the following values:
-@item PREV_OUTPTS
-The previous output PTS.
+@table @samp
+@item 1
+Force interlaced aware scaling.
-@item RTCTIME
-The wallclock (RTC) time in microseconds.
+@item 0
+Do not apply interlaced scaling.
-@item RTCSTART
-The wallclock (RTC) time at the start of the movie in microseconds.
+@item -1
+Select interlaced aware scaling depending on whether the source frames
+are flagged as interlaced or not.
+@end table
-@item TB
-The timebase of the input timestamps.
+Default value is @samp{0}.
+
+@item flags
+Set libswscale scaling flags. See
+@ref{sws_flags,,the ffmpeg-scaler manual,ffmpeg-scaler} for the
+complete list of values. If not explicitly specified the filter applies
+the default flags.
+
+@item size, s
+Set the video size. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+
+@item in_color_matrix
+@item out_color_matrix
+Set in/output YCbCr color space type.
+
+This allows the autodetected value to be overridden as well as allows forcing
+a specific value used for the output and encoder.
+
+If not specified, the color space type depends on the pixel format.
+
+Possible values:
+
+@table @samp
+@item auto
+Choose automatically.
+@item bt709
+Format conforming to International Telecommunication Union (ITU)
+Recommendation BT.709.
+
+@item fcc
+Set color space conforming to the United States Federal Communications
+Commission (FCC) Code of Federal Regulations (CFR) Title 47 (2003) 73.682 (a).
+
+@item bt601
+Set color space conforming to:
+
+@itemize
+@item
+ITU Radiocommunication Sector (ITU-R) Recommendation BT.601
+
+@item
+ITU-R Rec. BT.470-6 (1998) Systems B, B1, and G
+
+@item
+Society of Motion Picture and Television Engineers (SMPTE) ST 170:2004
+
+@end itemize
+
+@item smpte240m
+Set color space conforming to SMPTE ST 240:1999.
@end table
-Some examples:
+@item in_range
+@item out_range
+Set in/output YCbCr sample range.
+
+This allows the autodetected value to be overridden as well as allows forcing
+a specific value used for the output and encoder. If not specified, the
+range depends on the pixel format. Possible values:
+
+@table @samp
+@item auto
+Choose automatically.
+
+@item jpeg/full/pc
+Set full range (0-255 in case of 8-bit luma).
+@item mpeg/tv
+Set "MPEG" range (16-235 in case of 8-bit luma).
+@end table
+
+@item force_original_aspect_ratio
+Enable decreasing or increasing output video width or height if necessary to
+keep the original aspect ratio. Possible values:
+
+@table @samp
+@item disable
+Scale the video as specified and disable this feature.
+
+@item decrease
+The output video dimensions will automatically be decreased if needed.
+
+@item increase
+The output video dimensions will automatically be increased if needed.
+
+@end table
+
+One useful instance of this option is that when you know a specific device's
+maximum allowed resolution, you can use this to limit the output video to
+that, while retaining the aspect ratio. For example, device A allows
+1280x720 playback, and your video is 1920x800. Using this option (set it to
+decrease) and specifying 1280x720 to the command line makes the output
+1280x533.
+
+Please note that this is a different thing than specifying -1 for @option{w}
+or @option{h}, you still need to specify the output resolution for this option
+to work.
+
+@end table
+
+The values of the @option{w} and @option{h} options are expressions
+containing the following constants:
+
+@table @var
+@item in_w
+@item in_h
+The input width and height
+
+@item iw
+@item ih
+These are the same as @var{in_w} and @var{in_h}.
+
+@item out_w
+@item out_h
+The output (scaled) width and height
+
+@item ow
+@item oh
+These are the same as @var{out_w} and @var{out_h}
+
+@item a
+The same as @var{iw} / @var{ih}
+
+@item sar
+input sample aspect ratio
+
+@item dar
+The input display aspect ratio. Calculated from @code{(iw / ih) * sar}.
+
+@item hsub
+@item vsub
+horizontal and vertical input chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+
+@item ohsub
+@item ovsub
+horizontal and vertical output chroma subsample values. For example for the
+pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Scale the input video to a size of 200x100
@example
-# Start counting the PTS from zero
-setpts=expr=PTS-STARTPTS
+scale=w=200:h=100
+@end example
-# Fast motion
-setpts=expr=0.5*PTS
+This is equivalent to:
+@example
+scale=200:100
+@end example
-# Slow motion
-setpts=2.0*PTS
+or:
+@example
+scale=200x100
+@end example
-# Fixed rate 25 fps
-setpts=N/(25*TB)
+@item
+Specify a size abbreviation for the output size:
+@example
+scale=qcif
+@end example
-# Fixed rate 25 fps with some jitter
-setpts='1/(25*TB) * (N + 0.05 * sin(N*2*PI/25))'
+which can also be written as:
+@example
+scale=size=qcif
+@end example
-# Generate timestamps from a "live source" and rebase onto the current timebase
-setpts='(RTCTIME - RTCSTART) / (TB * 1000000)"
+@item
+Scale the input to 2x:
+@example
+scale=w=2*iw:h=2*ih
+@end example
+
+@item
+The above is the same as:
+@example
+scale=2*in_w:2*in_h
@end example
-@anchor{setsar}
-@section setsar
+@item
+Scale the input to 2x with forced interlaced scaling:
+@example
+scale=2*iw:2*ih:interl=1
+@end example
-Set the Sample (aka Pixel) Aspect Ratio for the filter output video.
+@item
+Scale the input to half size:
+@example
+scale=w=iw/2:h=ih/2
+@end example
+
+@item
+Increase the width, and set the height to the same size:
+@example
+scale=3/2*iw:ow
+@end example
+
+@item
+Seek Greek harmony:
+@example
+scale=iw:1/PHI*iw
+scale=ih*PHI:ih
+@end example
+
+@item
+Increase the height, and set the width to 3/2 of the height:
+@example
+scale=w=3/2*oh:h=3/5*ih
+@end example
+
+@item
+Increase the size, making the size a multiple of the chroma
+subsample values:
+@example
+scale="trunc(3/2*iw/hsub)*hsub:trunc(3/2*ih/vsub)*vsub"
+@end example
+
+@item
+Increase the width to a maximum of 500 pixels,
+keeping the same aspect ratio as the input:
+@example
+scale=w='min(500\, iw*3/2):h=-1'
+@end example
+@end itemize
+
+@section separatefields
+
+The @code{separatefields} takes a frame-based video input and splits
+each frame into its components fields, producing a new half height clip
+with twice the frame rate and twice the frame count.
+
+This filter use field-dominance information in frame to decide which
+of each pair of fields to place first in the output.
+If it gets it wrong use @ref{setfield} filter before @code{separatefields} filter.
+
+@section setdar, setsar
+
+The @code{setdar} filter sets the Display Aspect Ratio for the filter
+output video.
+
+This is done by changing the specified Sample (aka Pixel) Aspect
+Ratio, according to the following equation:
+@example
+@var{DAR} = @var{HORIZONTAL_RESOLUTION} / @var{VERTICAL_RESOLUTION} * @var{SAR}
+@end example
+
+Keep in mind that the @code{setdar} filter does not modify the pixel
+dimensions of the video frame. Also, the display aspect ratio set by
+this filter may be changed by later filters in the filterchain,
+e.g. in case of scaling or if another "setdar" or a "setsar" filter is
+applied.
+
+The @code{setsar} filter sets the Sample (aka Pixel) Aspect Ratio for
+the filter output video.
Note that as a consequence of the application of this filter, the
-output display aspect ratio will change according to the following
-equation:
-@math{DAR = HORIZONTAL_RESOLUTION / VERTICAL_RESOLUTION * SAR}
+output display aspect ratio will change according to the equation
+above.
-Keep in mind that the sample aspect ratio set by this filter may be
-changed by later filters in the filterchain, e.g. if another "setsar"
-or a "setdar" filter is applied.
+Keep in mind that the sample aspect ratio set by the @code{setsar}
+filter may be changed by later filters in the filterchain, e.g. if
+another "setsar" or a "setdar" filter is applied.
It accepts the following parameters:
@table @option
+@item r, ratio, dar (@code{setdar} only), sar (@code{setsar} only)
+Set the aspect ratio used by the filter.
-@item sar
-The output sample aspect ratio.
+The parameter can be a floating point number string, an expression, or
+a string of the form @var{num}:@var{den}, where @var{num} and
+@var{den} are the numerator and denominator of the aspect ratio. If
+the parameter is not specified, it is assumed the value "0".
+In case the form "@var{num}:@var{den}" is used, the @code{:} character
+should be escaped.
+
+@item max
+Set the maximum integer value to use for expressing numerator and
+denominator when reducing the expressed aspect ratio to a rational.
+Default value is @code{100}.
@end table
@@ -2461,48 +8385,64 @@ Horizontal and vertical chroma subsample values. For example, for the
pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1.
@end table
+@subsection Examples
+
+@itemize
+
+@item
+To change the display aspect ratio to 16:9, specify one of the following:
+@example
+setdar=dar=1.77777
+setdar=dar=16/9
+setdar=dar=1.77777
+@end example
+
+@item
To change the sample aspect ratio to 10:11, specify:
@example
setsar=sar=10/11
@end example
-@section settb
-
-Set the timebase to use for the output frames timestamps.
-It is mainly useful for testing timebase configuration.
-
-It accepts the following parameters:
+@item
+To set a display aspect ratio of 16:9, and specify a maximum integer value of
+1000 in the aspect ratio reduction, use the command:
+@example
+setdar=ratio=16/9:max=1000
+@end example
-@table @option
+@end itemize
-@item expr
-The expression which is evaluated into the output timebase.
+@anchor{setfield}
+@section setfield
-@end table
+Force field for the output video frame.
-The expression can contain the constants "PI", "E", "PHI", "AVTB" (the
-default timebase), and "intb" (the input timebase).
+The @code{setfield} filter marks the interlace type field for the
+output frames. It does not change the input frame, but only sets the
+corresponding property, which affects how the frame is treated by
+following filters (e.g. @code{fieldorder} or @code{yadif}).
-The default value for the input is "intb".
+The filter accepts the following options:
-Some examples:
+@table @option
-@example
-# Set the timebase to 1/25
-settb=expr=1/25
+@item mode
+Available values are:
-# Set the timebase to 1/10
-settb=expr=0.1
+@table @samp
+@item auto
+Keep the same field property.
-# Set the timebase to 1001/1000
-settb=1+0.001
+@item bff
+Mark the frame as bottom-field-first.
-#Set the timebase to 2*intb
-settb=2*intb
+@item tff
+Mark the frame as top-field-first.
-#Set the default timebase value
-settb=AVTB
-@end example
+@item prog
+Mark the frame as progressive.
+@end table
+@end table
@section showinfo
@@ -2512,7 +8452,7 @@ The input video is not modified.
The shown line contains a sequence of key/value pairs of the form
@var{key}:@var{value}.
-It accepts the following parameters:
+The following values are shown in the output:
@table @option
@item n
@@ -2538,8 +8478,8 @@ The sample aspect ratio of the input frame, expressed in the form
@var{num}/@var{den}.
@item s
-The size of the input frame, expressed in the form
-@var{width}x@var{height}.
+The size of the input frame. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
@item i
The type of interlaced mode ("P" for "progressive", "T" for top field first, "B"
@@ -2556,11 +8496,24 @@ the @code{av_get_picture_type_char} function defined in
@file{libavutil/avutil.h}.
@item checksum
-The Adler-32 checksum of all the planes of the input frame.
+The Adler-32 checksum (printed in hexadecimal) of all the planes of the input frame.
@item plane_checksum
-The Adler-32 checksum of each plane of the input frame, expressed in the form
-"[@var{c0} @var{c1} @var{c2} @var{c3}]".
+The Adler-32 checksum (printed in hexadecimal) of each plane of the input frame,
+expressed in the form "[@var{c0} @var{c1} @var{c2} @var{c3}]".
+@end table
+
+@section showpalette
+
+Displays the 256 colors palette of each frame. This filter is only relevant for
+@var{pal8} pixel format frames.
+
+It accepts the following option:
+
+@table @option
+@item s
+Set the size of the box used to represent one palette color entry. Default is
+@code{30} (for a @code{30x30} pixel box).
@end table
@section shuffleplanes
@@ -2589,21 +8542,821 @@ The first plane has the index 0. The default is to keep the input unchanged.
Swap the second and third planes of the input:
@example
-avconv -i INPUT -vf shuffleplanes=0:2:1:3 OUTPUT
+ffmpeg -i INPUT -vf shuffleplanes=0:2:1:3 OUTPUT
@end example
-@section split
+@section signalstats
+Evaluate various visual metrics that assist in determining issues associated
+with the digitization of analog video media.
-Split input video into several identical outputs.
+By default the filter will log these metadata values:
-It accepts a single parameter, which specifies the number of outputs. If
-unspecified, it defaults to 2.
+@table @option
+@item YMIN
+Display the minimal Y value contained within the input frame. Expressed in
+range of [0-255].
+
+@item YLOW
+Display the Y value at the 10% percentile within the input frame. Expressed in
+range of [0-255].
+
+@item YAVG
+Display the average Y value within the input frame. Expressed in range of
+[0-255].
+
+@item YHIGH
+Display the Y value at the 90% percentile within the input frame. Expressed in
+range of [0-255].
+
+@item YMAX
+Display the maximum Y value contained within the input frame. Expressed in
+range of [0-255].
+
+@item UMIN
+Display the minimal U value contained within the input frame. Expressed in
+range of [0-255].
+
+@item ULOW
+Display the U value at the 10% percentile within the input frame. Expressed in
+range of [0-255].
+
+@item UAVG
+Display the average U value within the input frame. Expressed in range of
+[0-255].
+
+@item UHIGH
+Display the U value at the 90% percentile within the input frame. Expressed in
+range of [0-255].
+
+@item UMAX
+Display the maximum U value contained within the input frame. Expressed in
+range of [0-255].
+
+@item VMIN
+Display the minimal V value contained within the input frame. Expressed in
+range of [0-255].
+
+@item VLOW
+Display the V value at the 10% percentile within the input frame. Expressed in
+range of [0-255].
+
+@item VAVG
+Display the average V value within the input frame. Expressed in range of
+[0-255].
+
+@item VHIGH
+Display the V value at the 90% percentile within the input frame. Expressed in
+range of [0-255].
+
+@item VMAX
+Display the maximum V value contained within the input frame. Expressed in
+range of [0-255].
+
+@item SATMIN
+Display the minimal saturation value contained within the input frame.
+Expressed in range of [0-~181.02].
+
+@item SATLOW
+Display the saturation value at the 10% percentile within the input frame.
+Expressed in range of [0-~181.02].
+
+@item SATAVG
+Display the average saturation value within the input frame. Expressed in range
+of [0-~181.02].
+
+@item SATHIGH
+Display the saturation value at the 90% percentile within the input frame.
+Expressed in range of [0-~181.02].
+
+@item SATMAX
+Display the maximum saturation value contained within the input frame.
+Expressed in range of [0-~181.02].
+
+@item HUEMED
+Display the median value for hue within the input frame. Expressed in range of
+[0-360].
+
+@item HUEAVG
+Display the average value for hue within the input frame. Expressed in range of
+[0-360].
+
+@item YDIF
+Display the average of sample value difference between all values of the Y
+plane in the current frame and corresponding values of the previous input frame.
+Expressed in range of [0-255].
+
+@item UDIF
+Display the average of sample value difference between all values of the U
+plane in the current frame and corresponding values of the previous input frame.
+Expressed in range of [0-255].
+
+@item VDIF
+Display the average of sample value difference between all values of the V
+plane in the current frame and corresponding values of the previous input frame.
+Expressed in range of [0-255].
+@end table
+
+The filter accepts the following options:
+
+@table @option
+@item stat
+@item out
+
+@option{stat} specify an additional form of image analysis.
+@option{out} output video with the specified type of pixel highlighted.
+
+Both options accept the following values:
+
+@table @samp
+@item tout
+Identify @var{temporal outliers} pixels. A @var{temporal outlier} is a pixel
+unlike the neighboring pixels of the same field. Examples of temporal outliers
+include the results of video dropouts, head clogs, or tape tracking issues.
+
+@item vrep
+Identify @var{vertical line repetition}. Vertical line repetition includes
+similar rows of pixels within a frame. In born-digital video vertical line
+repetition is common, but this pattern is uncommon in video digitized from an
+analog source. When it occurs in video that results from the digitization of an
+analog source it can indicate concealment from a dropout compensator.
+
+@item brng
+Identify pixels that fall outside of legal broadcast range.
+@end table
+
+@item color, c
+Set the highlight color for the @option{out} option. The default color is
+yellow.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Output data of various video metrics:
+@example
+ffprobe -f lavfi movie=example.mov,signalstats="stat=tout+vrep+brng" -show_frames
+@end example
-Create 5 copies of the input video:
+@item
+Output specific data about the minimum and maximum values of the Y plane per frame:
@example
-avconv -i INPUT -filter_complex split=5 OUTPUT
+ffprobe -f lavfi movie=example.mov,signalstats -show_entries frame_tags=lavfi.signalstats.YMAX,lavfi.signalstats.YMIN
@end example
+@item
+Playback video while highlighting pixels that are outside of broadcast range in red.
+@example
+ffplay example.mov -vf signalstats="out=brng:color=red"
+@end example
+
+@item
+Playback video with signalstats metadata drawn over the frame.
+@example
+ffplay example.mov -vf signalstats=stat=brng+vrep+tout,drawtext=fontfile=FreeSerif.ttf:textfile=signalstat_drawtext.txt
+@end example
+
+The contents of signalstat_drawtext.txt used in the command are:
+@example
+time %@{pts:hms@}
+Y (%@{metadata:lavfi.signalstats.YMIN@}-%@{metadata:lavfi.signalstats.YMAX@})
+U (%@{metadata:lavfi.signalstats.UMIN@}-%@{metadata:lavfi.signalstats.UMAX@})
+V (%@{metadata:lavfi.signalstats.VMIN@}-%@{metadata:lavfi.signalstats.VMAX@})
+saturation maximum: %@{metadata:lavfi.signalstats.SATMAX@}
+
+@end example
+@end itemize
+
+@anchor{smartblur}
+@section smartblur
+
+Blur the input video without impacting the outlines.
+
+It accepts the following options:
+
+@table @option
+@item luma_radius, lr
+Set the luma 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 1.0.
+
+@item luma_strength, ls
+Set the luma 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 1.0.
+
+@item luma_threshold, lt
+Set the luma 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 0.
+
+@item chroma_radius, cr
+Set the chroma 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 1.0.
+
+@item chroma_strength, cs
+Set the chroma 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 1.0.
+
+@item chroma_threshold, ct
+Set the chroma 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 0.
+@end table
+
+If a chroma option is not explicitly set, the corresponding luma value
+is set.
+
+@section stereo3d
+
+Convert between different stereoscopic image formats.
+
+The filters accept the following options:
+
+@table @option
+@item in
+Set stereoscopic image format of input.
+
+Available values for input image formats are:
+@table @samp
+@item sbsl
+side by side parallel (left eye left, right eye right)
+
+@item sbsr
+side by side crosseye (right eye left, left eye right)
+
+@item sbs2l
+side by side parallel with half width resolution
+(left eye left, right eye right)
+
+@item sbs2r
+side by side crosseye with half width resolution
+(right eye left, left eye right)
+
+@item abl
+above-below (left eye above, right eye below)
+
+@item abr
+above-below (right eye above, left eye below)
+
+@item ab2l
+above-below with half height resolution
+(left eye above, right eye below)
+
+@item ab2r
+above-below with half height resolution
+(right eye above, left eye below)
+
+@item al
+alternating frames (left eye first, right eye second)
+
+@item ar
+alternating frames (right eye first, left eye second)
+
+Default value is @samp{sbsl}.
+@end table
+
+@item out
+Set stereoscopic image format of output.
+
+Available values for output image formats are all the input formats as well as:
+@table @samp
+@item arbg
+anaglyph red/blue gray
+(red filter on left eye, blue filter on right eye)
+
+@item argg
+anaglyph red/green gray
+(red filter on left eye, green filter on right eye)
+
+@item arcg
+anaglyph red/cyan gray
+(red filter on left eye, cyan filter on right eye)
+
+@item arch
+anaglyph red/cyan half colored
+(red filter on left eye, cyan filter on right eye)
+
+@item arcc
+anaglyph red/cyan color
+(red filter on left eye, cyan filter on right eye)
+
+@item arcd
+anaglyph red/cyan color optimized with the least squares projection of dubois
+(red filter on left eye, cyan filter on right eye)
+
+@item agmg
+anaglyph green/magenta gray
+(green filter on left eye, magenta filter on right eye)
+
+@item agmh
+anaglyph green/magenta half colored
+(green filter on left eye, magenta filter on right eye)
+
+@item agmc
+anaglyph green/magenta colored
+(green filter on left eye, magenta filter on right eye)
+
+@item agmd
+anaglyph green/magenta color optimized with the least squares projection of dubois
+(green filter on left eye, magenta filter on right eye)
+
+@item aybg
+anaglyph yellow/blue gray
+(yellow filter on left eye, blue filter on right eye)
+
+@item aybh
+anaglyph yellow/blue half colored
+(yellow filter on left eye, blue filter on right eye)
+
+@item aybc
+anaglyph yellow/blue colored
+(yellow filter on left eye, blue filter on right eye)
+
+@item aybd
+anaglyph yellow/blue color optimized with the least squares projection of dubois
+(yellow filter on left eye, blue filter on right eye)
+
+@item irl
+interleaved rows (left eye has top row, right eye starts on next row)
+
+@item irr
+interleaved rows (right eye has top row, left eye starts on next row)
+
+@item ml
+mono output (left eye only)
+
+@item mr
+mono output (right eye only)
+@end table
+
+Default value is @samp{arcd}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Convert input video from side by side parallel to anaglyph yellow/blue dubois:
+@example
+stereo3d=sbsl:aybd
+@end example
+
+@item
+Convert input video from above bellow (left eye above, right eye below) to side by side crosseye.
+@example
+stereo3d=abl:sbsr
+@end example
+@end itemize
+
+@anchor{spp}
+@section spp
+
+Apply a simple postprocessing filter that compresses and decompresses the image
+at several (or - in the case of @option{quality} level @code{6} - all) shifts
+and average the results.
+
+The filter accepts the following options:
+
+@table @option
+@item quality
+Set quality. This option defines the number of levels for averaging. It accepts
+an integer in the range 0-6. If set to @code{0}, the filter will have no
+effect. A value of @code{6} means the higher quality. For each increment of
+that value the speed drops by a factor of approximately 2. Default value is
+@code{3}.
+
+@item qp
+Force a constant quantization parameter. If not set, the filter will use the QP
+from the video stream (if available).
+
+@item mode
+Set thresholding mode. Available modes are:
+
+@table @samp
+@item hard
+Set hard thresholding (default).
+@item soft
+Set soft thresholding (better de-ringing effect, but likely blurrier).
+@end table
+
+@item use_bframe_qp
+Enable the use of the QP from the B-Frames if set to @code{1}. Using this
+option may cause flicker since the B-Frames have often larger QP. Default is
+@code{0} (not enabled).
+@end table
+
+@anchor{subtitles}
+@section subtitles
+
+Draw subtitles on top of input video using the libass library.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libass}. This filter also requires a build with libavcodec and
+libavformat to convert the passed subtitles file to ASS (Advanced Substation
+Alpha) subtitles format.
+
+The filter accepts the following options:
+
+@table @option
+@item filename, f
+Set the filename of the subtitle file to read. It must be specified.
+
+@item original_size
+Specify the size of the original video, the video for which the ASS file
+was composed. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+Due to a misdesign in ASS aspect ratio arithmetic, this is necessary to
+correctly scale the fonts if the aspect ratio has been changed.
+
+@item charenc
+Set subtitles input character encoding. @code{subtitles} filter only. Only
+useful if not UTF-8.
+
+@item stream_index, si
+Set subtitles stream index. @code{subtitles} filter only.
+
+@item force_style
+Override default style or script info parameters of the subtitles. It accepts a
+string containing ASS style format @code{KEY=VALUE} couples separated by ",".
+@end table
+
+If the first key is not specified, it is assumed that the first value
+specifies the @option{filename}.
+
+For example, to render the file @file{sub.srt} on top of the input
+video, use the command:
+@example
+subtitles=sub.srt
+@end example
+
+which is equivalent to:
+@example
+subtitles=filename=sub.srt
+@end example
+
+To render the default subtitles stream from file @file{video.mkv}, use:
+@example
+subtitles=video.mkv
+@end example
+
+To render the second subtitles stream from that file, use:
+@example
+subtitles=video.mkv:si=1
+@end example
+
+To make the subtitles stream from @file{sub.srt} appear in transparent green
+@code{DejaVu Serif}, use:
+@example
+subtitles=sub.srt:force_style='FontName=DejaVu Serif,PrimaryColour=&HAA00FF00'
+@end example
+
+@section super2xsai
+
+Scale the input by 2x and smooth using the Super2xSaI (Scale and
+Interpolate) pixel art scaling algorithm.
+
+Useful for enlarging pixel art images without reducing sharpness.
+
+@section swapuv
+Swap U & V plane.
+
+@section telecine
+
+Apply telecine process to the video.
+
+This filter accepts the following options:
+
+@table @option
+@item first_field
+@table @samp
+@item top, t
+top field first
+@item bottom, b
+bottom field first
+The default value is @code{top}.
+@end table
+
+@item pattern
+A string of numbers representing the pulldown pattern you wish to apply.
+The default value is @code{23}.
+@end table
+
+@example
+Some typical patterns:
+
+NTSC output (30i):
+27.5p: 32222
+24p: 23 (classic)
+24p: 2332 (preferred)
+20p: 33
+18p: 334
+16p: 3444
+
+PAL output (25i):
+27.5p: 12222
+24p: 222222222223 ("Euro pulldown")
+16.67p: 33
+16p: 33333334
+@end example
+
+@section thumbnail
+Select the most representative frame in a given sequence of consecutive frames.
+
+The filter accepts the following options:
+
+@table @option
+@item n
+Set the frames batch size to analyze; in a set of @var{n} frames, the filter
+will pick one of them, and then handle the next batch of @var{n} frames until
+the end. Default is @code{100}.
+@end table
+
+Since the filter keeps track of the whole frames sequence, a bigger @var{n}
+value will result in a higher memory usage, so a high value is not recommended.
+
+@subsection Examples
+
+@itemize
+@item
+Extract one picture each 50 frames:
+@example
+thumbnail=50
+@end example
+
+@item
+Complete example of a thumbnail creation with @command{ffmpeg}:
+@example
+ffmpeg -i in.avi -vf thumbnail,scale=300:200 -frames:v 1 out.png
+@end example
+@end itemize
+
+@section tile
+
+Tile several successive frames together.
+
+The filter accepts the following options:
+
+@table @option
+
+@item layout
+Set the grid size (i.e. the number of lines and columns). For the syntax of
+this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+
+@item nb_frames
+Set the maximum number of frames to render in the given area. It must be less
+than or equal to @var{w}x@var{h}. The default value is @code{0}, meaning all
+the area will be used.
+
+@item margin
+Set the outer border margin in pixels.
+
+@item padding
+Set the inner border thickness (i.e. the number of pixels between frames). For
+more advanced padding options (such as having different values for the edges),
+refer to the pad video filter.
+
+@item color
+Specify the color of the unused area. For the syntax of this option, check the
+"Color" section in the ffmpeg-utils manual. The default value of @var{color}
+is "black".
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Produce 8x8 PNG tiles of all keyframes (@option{-skip_frame nokey}) in a movie:
+@example
+ffmpeg -skip_frame nokey -i file.avi -vf 'scale=128:72,tile=8x8' -an -vsync 0 keyframes%03d.png
+@end example
+The @option{-vsync 0} is necessary to prevent @command{ffmpeg} from
+duplicating each output frame to accommodate the originally detected frame
+rate.
+
+@item
+Display @code{5} pictures in an area of @code{3x2} frames,
+with @code{7} pixels between them, and @code{2} pixels of initial margin, using
+mixed flat and named options:
+@example
+tile=3x2:nb_frames=5:padding=7:margin=2
+@end example
+@end itemize
+
+@section tinterlace
+
+Perform various types of temporal field interlacing.
+
+Frames are counted starting from 1, so the first input frame is
+considered odd.
+
+The filter accepts the following options:
+
+@table @option
+
+@item mode
+Specify the mode of the interlacing. This option can also be specified
+as a value alone. See below for a list of values for this option.
+
+Available values are:
+
+@table @samp
+@item merge, 0
+Move odd frames into the upper field, even into the lower field,
+generating a double height frame at half frame rate.
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+
+Output:
+11111 33333
+22222 44444
+11111 33333
+22222 44444
+11111 33333
+22222 44444
+11111 33333
+22222 44444
+@end example
+
+@item drop_odd, 1
+Only output even frames, odd frames are dropped, generating a frame with
+unchanged height at half frame rate.
+
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+
+Output:
+ 22222 44444
+ 22222 44444
+ 22222 44444
+ 22222 44444
+@end example
+
+@item drop_even, 2
+Only output odd frames, even frames are dropped, generating a frame with
+unchanged height at half frame rate.
+
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+
+Output:
+11111 33333
+11111 33333
+11111 33333
+11111 33333
+@end example
+
+@item pad, 3
+Expand each frame to full height, but pad alternate lines with black,
+generating a frame with double height at the same input frame rate.
+
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+11111 22222 33333 44444
+
+Output:
+11111 ..... 33333 .....
+..... 22222 ..... 44444
+11111 ..... 33333 .....
+..... 22222 ..... 44444
+11111 ..... 33333 .....
+..... 22222 ..... 44444
+11111 ..... 33333 .....
+..... 22222 ..... 44444
+@end example
+
+
+@item interleave_top, 4
+Interleave the upper field from odd frames with the lower field from
+even frames, generating a frame with unchanged height at half frame rate.
+
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111<- 22222 33333<- 44444
+11111 22222<- 33333 44444<-
+11111<- 22222 33333<- 44444
+11111 22222<- 33333 44444<-
+
+Output:
+11111 33333
+22222 44444
+11111 33333
+22222 44444
+@end example
+
+
+@item interleave_bottom, 5
+Interleave the lower field from odd frames with the upper field from
+even frames, generating a frame with unchanged height at half frame rate.
+
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111 22222<- 33333 44444<-
+11111<- 22222 33333<- 44444
+11111 22222<- 33333 44444<-
+11111<- 22222 33333<- 44444
+
+Output:
+22222 44444
+11111 33333
+22222 44444
+11111 33333
+@end example
+
+
+@item interlacex2, 6
+Double frame rate with unchanged height. Frames are inserted each
+containing the second temporal field from the previous input frame and
+the first temporal field from the next input frame. This mode relies on
+the top_field_first flag. Useful for interlaced video displays with no
+field synchronisation.
+
+@example
+ ------> time
+Input:
+Frame 1 Frame 2 Frame 3 Frame 4
+
+11111 22222 33333 44444
+ 11111 22222 33333 44444
+11111 22222 33333 44444
+ 11111 22222 33333 44444
+
+Output:
+11111 22222 22222 33333 33333 44444 44444
+ 11111 11111 22222 22222 33333 33333 44444
+11111 22222 22222 33333 33333 44444 44444
+ 11111 11111 22222 22222 33333 33333 44444
+@end example
+
+
+@end table
+
+Numeric values are deprecated but are accepted for backward
+compatibility reasons.
+
+Default mode is @code{merge}.
+
+@item flags
+Specify flags influencing the filter process.
+
+Available value for @var{flags} is:
+
+@table @option
+@item low_pass_filter, vlfp
+Enable vertical low-pass filtering in the filter.
+Vertical low-pass filtering is required when creating an interlaced
+destination from a progressive source which contains high-frequency
+vertical detail. Filtering will reduce interlace 'twitter' and Moire
+patterning.
+
+Vertical low-pass filtering can only be enabled for @option{mode}
+@var{interleave_top} and @var{interleave_bottom}.
+
+@end table
+@end table
+
@section transpose
Transpose rows with columns in the input video and optionally flip it.
@@ -2613,14 +9366,11 @@ It accepts the following parameters:
@table @option
@item dir
-The direction of the transpose.
-
-@end table
-
-The direction can assume the following values:
+Specify the transposition direction.
+Can assume the following values:
@table @samp
-@item cclock_flip
+@item 0, 4, cclock_flip
Rotate by 90 degrees counterclockwise and vertically flip (default), that is:
@example
L.R L.l
@@ -2628,7 +9378,7 @@ L.R L.l
l.r R.r
@end example
-@item clock
+@item 1, 5, clock
Rotate by 90 degrees clockwise, that is:
@example
L.R l.L
@@ -2636,7 +9386,7 @@ L.R l.L
l.r r.R
@end example
-@item cclock
+@item 2, 6, cclock
Rotate by 90 degrees counterclockwise, that is:
@example
L.R R.r
@@ -2644,7 +9394,7 @@ L.R R.r
l.r L.l
@end example
-@item clock_flip
+@item 3, 7, clock_flip
Rotate by 90 degrees clockwise and vertically flip, that is:
@example
L.R r.R
@@ -2653,17 +9403,50 @@ l.r l.L
@end example
@end table
+For values between 4-7, the transposition is only done if the input
+video geometry is portrait and not landscape. These values are
+deprecated, the @code{passthrough} option should be used instead.
+
+Numerical values are deprecated, and should be dropped in favor of
+symbolic constants.
+
+@item passthrough
+Do not apply the transposition if the input geometry matches the one
+specified by the specified value. It accepts the following values:
+@table @samp
+@item none
+Always apply transposition.
+@item portrait
+Preserve portrait geometry (when @var{height} >= @var{width}).
+@item landscape
+Preserve landscape geometry (when @var{width} >= @var{height}).
+@end table
+
+Default value is @code{none}.
+@end table
+
+For example to rotate by 90 degrees clockwise and preserve portrait
+layout:
+@example
+transpose=dir=1:passthrough=portrait
+@end example
+
+The command above can also be specified as:
+@example
+transpose=1:portrait
+@end example
+
@section trim
Trim the input so that the output contains one continuous subpart of the input.
It accepts the following parameters:
@table @option
@item start
-The timestamp (in seconds) of the start of the kept section. The frame with the
+Specify the time of the start of the kept section, i.e. the frame with the
timestamp @var{start} will be the first frame in the output.
@item end
-The timestamp (in seconds) of the first frame that will be dropped. The frame
+Specify the time of the first frame that will be dropped, i.e. the frame
immediately preceding the one with the timestamp @var{end} will be the last
frame in the output.
@@ -2685,6 +9468,11 @@ The number of the first frame that should be passed to the output.
The number of the first frame that should be dropped.
@end table
+@option{start}, @option{end}, and @option{duration} are expressed as time
+duration specifications; see
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
+
Note that the first two sets of the start/end options and the @option{duration}
option look at the frame timestamp, while the _frame variants simply count the
frames that pass through the filter. Also note that this filter does not modify
@@ -2704,16 +9492,19 @@ Examples:
@item
Drop everything except the second minute of input:
@example
-avconv -i INPUT -vf trim=60:120
+ffmpeg -i INPUT -vf trim=60:120
@end example
@item
Keep only the first second:
@example
-avconv -i INPUT -vf trim=duration=1
+ffmpeg -i INPUT -vf trim=duration=1
@end example
@end itemize
+
+
+@anchor{unsharp}
@section unsharp
Sharpen or blur the input video.
@@ -2721,56 +9512,497 @@ Sharpen or blur the input video.
It accepts the following parameters:
@table @option
+@item luma_msize_x, lx
+Set the luma matrix horizontal size. It must be an odd integer between
+3 and 63. The default value is 5.
-@item luma_msize_x
-Set the luma matrix horizontal size. It must be an integer between 3
-and 13. The default value is 5.
+@item luma_msize_y, ly
+Set the luma matrix vertical size. It must be an odd integer between 3
+and 63. The default value is 5.
-@item luma_msize_y
-Set the luma matrix vertical size. It must be an integer between 3
-and 13. The default value is 5.
+@item luma_amount, la
+Set the luma effect strength. It must be a floating point number, reasonable
+values lay between -1.5 and 1.5.
-@item luma_amount
-Set the luma effect strength. It must be a floating point number between -2.0
-and 5.0. The default value is 1.0.
+Negative values will blur the input video, while positive values will
+sharpen it, a value of zero will disable the effect.
-@item chroma_msize_x
-Set the chroma matrix horizontal size. It must be an integer between 3
-and 13. The default value is 5.
+Default value is 1.0.
-@item chroma_msize_y
-Set the chroma matrix vertical size. It must be an integer between 3
-and 13. The default value is 5.
+@item chroma_msize_x, cx
+Set the chroma matrix horizontal size. It must be an odd integer
+between 3 and 63. The default value is 5.
-@item chroma_amount
-Set the chroma effect strength. It must be a floating point number between -2.0
-and 5.0. The default value is 0.0.
+@item chroma_msize_y, cy
+Set the chroma matrix vertical size. It must be an odd integer
+between 3 and 63. The default value is 5.
+
+@item chroma_amount, ca
+Set the chroma effect strength. It must be a floating point number, reasonable
+values lay between -1.5 and 1.5.
+
+Negative values will blur the input video, while positive values will
+sharpen it, a value of zero will disable the effect.
+
+Default value is 0.0.
+
+@item opencl
+If set to 1, specify using OpenCL capabilities, only available if
+FFmpeg was configured with @code{--enable-opencl}. Default value is 0.
@end table
-Negative values for the amount will blur the input video, while positive
-values will sharpen. All parameters are optional and default to the
-equivalent of the string '5:5:1.0:5:5:0.0'.
+All parameters are optional and default to the equivalent of the
+string '5:5:1.0:5:5:0.0'.
+@subsection Examples
+
+@itemize
+@item
+Apply strong luma sharpen effect:
@example
-# Strong luma sharpen effect parameters
unsharp=luma_msize_x=7:luma_msize_y=7:luma_amount=2.5
+@end example
-# A strong blur of both luma and chroma parameters
+@item
+Apply a strong blur of both luma and chroma parameters:
+@example
unsharp=7:7:-2:7:7:-2
+@end example
+@end itemize
+
+@section uspp
+
+Apply ultra slow/simple postprocessing filter that compresses and decompresses
+the image at several (or - in the case of @option{quality} level @code{8} - all)
+shifts and average the results.
+
+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.
+
+The filter accepts the following options:
+
+@table @option
+@item quality
+Set quality. This option defines the number of levels for averaging. It accepts
+an integer in the range 0-8. If set to @code{0}, the filter will have no
+effect. A value of @code{8} means the higher quality. For each increment of
+that value the speed drops by a factor of approximately 2. Default value is
+@code{3}.
+
+@item qp
+Force a constant quantization parameter. If not set, the filter will use the QP
+from the video stream (if available).
+@end table
+
+@anchor{vidstabdetect}
+@section vidstabdetect
+
+Analyze video stabilization/deshaking. Perform pass 1 of 2, see
+@ref{vidstabtransform} for pass 2.
+
+This filter generates a file with relative translation and rotation
+transform information about subsequent frames, which is then used by
+the @ref{vidstabtransform} filter.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libvidstab}.
+
+This filter accepts the following options:
+
+@table @option
+@item result
+Set the path to the file used to write the transforms information.
+Default value is @file{transforms.trf}.
+
+@item shakiness
+Set how shaky the video is and how quick the camera is. It accepts an
+integer in the range 1-10, a value of 1 means little shakiness, a
+value of 10 means strong shakiness. Default value is 5.
+
+@item accuracy
+Set the accuracy of the detection process. It must be a value in the
+range 1-15. A value of 1 means low accuracy, a value of 15 means high
+accuracy. Default value is 15.
+
+@item stepsize
+Set stepsize of the search process. The region around minimum is
+scanned with 1 pixel resolution. Default value is 6.
+
+@item mincontrast
+Set minimum contrast. Below this value a local measurement field is
+discarded. Must be a floating point value in the range 0-1. Default
+value is 0.3.
+
+@item tripod
+Set reference frame number for tripod mode.
+
+If enabled, the motion of the frames is compared to a reference frame
+in the filtered stream, identified by the specified number. The idea
+is to compensate all movements in a more-or-less static scene and keep
+the camera view absolutely still.
+
+If set to 0, it is disabled. The frames are counted starting from 1.
+
+@item show
+Show fields and transforms in the resulting frames. It accepts an
+integer in the range 0-2. Default value is 0, which disables any
+visualization.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Use default values:
+@example
+vidstabdetect
+@end example
+
+@item
+Analyze strongly shaky movie and put the results in file
+@file{mytransforms.trf}:
+@example
+vidstabdetect=shakiness=10:accuracy=15:result="mytransforms.trf"
+@end example
+
+@item
+Visualize the result of internal transformations in the resulting
+video:
+@example
+vidstabdetect=show=1
+@end example
-# Use the default values with @command{avconv}
-./avconv -i in.avi -vf "unsharp" out.mp4
+@item
+Analyze a video with medium shakiness using @command{ffmpeg}:
+@example
+ffmpeg -i input -vf vidstabdetect=shakiness=5:show=1 dummy.avi
@end example
+@end itemize
+
+@anchor{vidstabtransform}
+@section vidstabtransform
+
+Video stabilization/deshaking: pass 2 of 2,
+see @ref{vidstabdetect} for pass 1.
+
+Read a file with transform information for each frame and
+apply/compensate them. Together with the @ref{vidstabdetect}
+filter this can be used to deshake videos. See also
+@url{http://public.hronopik.de/vid.stab}. It is important to also use
+the @ref{unsharp} filter, see below.
+
+To enable compilation of this filter you need to configure FFmpeg with
+@code{--enable-libvidstab}.
+
+@subsection Options
+
+@table @option
+@item input
+Set path to the file used to read the transforms. Default value is
+@file{transforms.trf}.
+
+@item smoothing
+Set the number of frames (value*2 + 1) used for lowpass filtering the
+camera movements. Default value is 10.
+
+For example a number of 10 means that 21 frames are used (10 in the
+past and 10 in the future) to smoothen the motion in the video. A
+larger value leads to a smoother video, but limits the acceleration of
+the camera (pan/tilt movements). 0 is a special case where a static
+camera is simulated.
+
+@item optalgo
+Set the camera path optimization algorithm.
+
+Accepted values are:
+@table @samp
+@item gauss
+gaussian kernel low-pass filter on camera motion (default)
+@item avg
+averaging on transformations
+@end table
+
+@item maxshift
+Set maximal number of pixels to translate frames. Default value is -1,
+meaning no limit.
+
+@item maxangle
+Set maximal angle in radians (degree*PI/180) to rotate frames. Default
+value is -1, meaning no limit.
+
+@item crop
+Specify how to deal with borders that may be visible due to movement
+compensation.
+
+Available values are:
+@table @samp
+@item keep
+keep image information from previous frame (default)
+@item black
+fill the border black
+@end table
+
+@item invert
+Invert transforms if set to 1. Default value is 0.
+
+@item relative
+Consider transforms as relative to previous frame if set to 1,
+absolute if set to 0. Default value is 0.
+
+@item zoom
+Set percentage to zoom. A positive value will result in a zoom-in
+effect, a negative value in a zoom-out effect. Default value is 0 (no
+zoom).
+
+@item optzoom
+Set optimal zooming to avoid borders.
+
+Accepted values are:
+@table @samp
+@item 0
+disabled
+@item 1
+optimal static zoom value is determined (only very strong movements
+will lead to visible borders) (default)
+@item 2
+optimal adaptive zoom value is determined (no borders will be
+visible), see @option{zoomspeed}
+@end table
+
+Note that the value given at zoom is added to the one calculated here.
+
+@item zoomspeed
+Set percent to zoom maximally each frame (enabled when
+@option{optzoom} is set to 2). Range is from 0 to 5, default value is
+0.25.
+
+@item interpol
+Specify type of interpolation.
+
+Available values are:
+@table @samp
+@item no
+no interpolation
+@item linear
+linear only horizontal
+@item bilinear
+linear in both directions (default)
+@item bicubic
+cubic in both directions (slow)
+@end table
+
+@item tripod
+Enable virtual tripod mode if set to 1, which is equivalent to
+@code{relative=0:smoothing=0}. Default value is 0.
+
+Use also @code{tripod} option of @ref{vidstabdetect}.
+
+@item debug
+Increase log verbosity if set to 1. Also the detected global motions
+are written to the temporary file @file{global_motions.trf}. Default
+value is 0.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Use @command{ffmpeg} for a typical stabilization with default values:
+@example
+ffmpeg -i inp.mpeg -vf vidstabtransform,unsharp=5:5:0.8:3:3:0.4 inp_stabilized.mpeg
+@end example
+
+Note the use of the @ref{unsharp} filter which is always recommended.
+
+@item
+Zoom in a bit more and load transform data from a given file:
+@example
+vidstabtransform=zoom=5:input="mytransforms.trf"
+@end example
+
+@item
+Smoothen the video even more:
+@example
+vidstabtransform=smoothing=30
+@end example
+@end itemize
@section vflip
Flip the input video vertically.
+For example, to vertically flip a video with @command{ffmpeg}:
@example
-./avconv -i in.avi -vf "vflip" out.avi
+ffmpeg -i in.avi -vf "vflip" out.avi
@end example
+@anchor{vignette}
+@section vignette
+
+Make or reverse a natural vignetting effect.
+
+The filter accepts the following options:
+
+@table @option
+@item angle, a
+Set lens angle expression as a number of radians.
+
+The value is clipped in the @code{[0,PI/2]} range.
+
+Default value: @code{"PI/5"}
+
+@item x0
+@item y0
+Set center coordinates expressions. Respectively @code{"w/2"} and @code{"h/2"}
+by default.
+
+@item mode
+Set forward/backward mode.
+
+Available modes are:
+@table @samp
+@item forward
+The larger the distance from the central point, the darker the image becomes.
+
+@item backward
+The larger the distance from the central point, the brighter the image becomes.
+This can be used to reverse a vignette effect, though there is no automatic
+detection to extract the lens @option{angle} and other settings (yet). It can
+also be used to create a burning effect.
+@end table
+
+Default value is @samp{forward}.
+
+@item eval
+Set evaluation mode for the expressions (@option{angle}, @option{x0}, @option{y0}).
+
+It accepts the following values:
+@table @samp
+@item init
+Evaluate expressions only once during the filter initialization.
+
+@item frame
+Evaluate expressions for each incoming frame. This is way slower than the
+@samp{init} mode since it requires all the scalers to be re-computed, but it
+allows advanced dynamic expressions.
+@end table
+
+Default value is @samp{init}.
+
+@item dither
+Set dithering to reduce the circular banding effects. Default is @code{1}
+(enabled).
+
+@item aspect
+Set vignette aspect. This setting allows one to adjust the shape of the vignette.
+Setting this value to the SAR of the input will make a rectangular vignetting
+following the dimensions of the video.
+
+Default is @code{1/1}.
+@end table
+
+@subsection Expressions
+
+The @option{alpha}, @option{x0} and @option{y0} expressions can contain the
+following parameters.
+
+@table @option
+@item w
+@item h
+input width and height
+
+@item n
+the number of input frame, starting from 0
+
+@item pts
+the PTS (Presentation TimeStamp) time of the filtered video frame, expressed in
+@var{TB} units, NAN if undefined
+
+@item r
+frame rate of the input video, NAN if the input frame rate is unknown
+
+@item t
+the PTS (Presentation TimeStamp) of the filtered video frame,
+expressed in seconds, NAN if undefined
+
+@item tb
+time base of the input video
+@end table
+
+
+@subsection Examples
+
+@itemize
+@item
+Apply simple strong vignetting effect:
+@example
+vignette=PI/4
+@end example
+
+@item
+Make a flickering vignetting:
+@example
+vignette='PI/4+random(1)*PI/50':eval=frame
+@end example
+
+@end itemize
+
+@section w3fdif
+
+Deinterlace the input video ("w3fdif" stands for "Weston 3 Field
+Deinterlacing Filter").
+
+Based on the process described by Martin Weston for BBC R&D, and
+implemented based on the de-interlace algorithm written by Jim
+Easterbrook for BBC R&D, the Weston 3 field deinterlacing filter
+uses filter coefficients calculated by BBC R&D.
+
+There are two sets of filter coefficients, so called "simple":
+and "complex". Which set of filter coefficients is used can
+be set by passing an optional parameter:
+
+@table @option
+@item filter
+Set the interlacing filter coefficients. Accepts one of the following values:
+
+@table @samp
+@item simple
+Simple filter coefficient set.
+@item complex
+More-complex filter coefficient set.
+@end table
+Default value is @samp{complex}.
+
+@item deint
+Specify which frames to deinterlace. Accept one of the following values:
+
+@table @samp
+@item all
+Deinterlace all frames,
+@item interlaced
+Only deinterlace frames marked as interlaced.
+@end table
+
+Default value is @samp{all}.
+@end table
+
+@section xbr
+Apply the xBR high-quality magnification filter which is designed for pixel
+art. It follows a set of edge-detection rules, see
+@url{http://www.libretro.com/forums/viewtopic.php?f=6&t=134}.
+
+It accepts the following option:
+
+@table @option
+@item n
+Set the scaling dimension: @code{2} for @code{2xBR}, @code{3} for
+@code{3xBR} and @code{4} for @code{4xBR}.
+Default is @code{3}.
+@end table
+
+@anchor{yadif}
@section yadif
Deinterlace the input video ("yadif" means "yet another deinterlacing
@@ -2778,56 +10010,144 @@ filter").
It accepts the following parameters:
+
@table @option
@item mode
The interlacing mode to adopt. It accepts one of the following values:
@table @option
-@item 0
+@item 0, send_frame
Output one frame for each frame.
-@item 1
+@item 1, send_field
Output one frame for each field.
-@item 2
-Like 0, but it skips the spatial interlacing check.
-@item 3
-Like 1, but it skips the spatial interlacing check.
+@item 2, send_frame_nospatial
+Like @code{send_frame}, but it skips the spatial interlacing check.
+@item 3, send_field_nospatial
+Like @code{send_field}, but it skips the spatial interlacing check.
@end table
-The default value is 0.
+The default value is @code{send_frame}.
@item parity
The picture field parity assumed for the input interlaced video. It accepts one
of the following values:
@table @option
-@item 0
+@item 0, tff
Assume the top field is first.
-@item 1
+@item 1, bff
Assume the bottom field is first.
-@item -1
+@item -1, auto
Enable automatic detection of field parity.
@end table
-The default value is -1.
+The default value is @code{auto}.
If the interlacing is unknown or the decoder does not export this information,
top field first will be assumed.
-@item auto
-Whether the deinterlacer should trust the interlaced flag and only deinterlace
-frames marked as interlaced.
+@item deint
+Specify which frames to deinterlace. Accept one of the following
+values:
@table @option
-@item 0
+@item 0, all
Deinterlace all frames.
-@item 1
+@item 1, interlaced
Only deinterlace frames marked as interlaced.
@end table
-The default value is 0.
+The default value is @code{all}.
+@end table
+
+@section zoompan
+
+Apply Zoom & Pan effect.
+
+This filter accepts the following options:
+@table @option
+@item zoom, z
+Set the zoom expression. Default is 1.
+
+@item x
+@item y
+Set the x and y expression. Default is 0.
+
+@item d
+Set the duration expression in number of frames.
+This sets for how many number of frames effect will last for
+single input image.
+
+@item s
+Set the output image size, default is 'hd720'.
@end table
+Each expression can contain the following constants:
+
+@table @option
+@item in_w, iw
+Input width.
+
+@item in_h, ih
+Input height.
+
+@item out_w, ow
+Output width.
+
+@item out_h, oh
+Output height.
+
+@item in
+Input frame count.
+
+@item on
+Output frame count.
+
+@item x
+@item y
+Last calculated 'x' and 'y' position from 'x' and 'y' expression
+for current input frame.
+
+@item px
+@item py
+'x' and 'y' of last output frame of previous input frame or 0 when there was
+not yet such frame (first input frame).
+
+@item zoom
+Last calculated zoom from 'z' expression for current input frame.
+
+@item pzoom
+Last calculated zoom of last output frame of previous input frame.
+
+@item duration
+Number of output frames for current input frame. Calculated from 'd' expression
+for each input frame.
+
+@item pduration
+number of output frames created for previous input frame
+
+@item a
+Rational number: input width / input height
+
+@item sar
+sample aspect ratio
+
+@item dar
+display aspect ratio
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Zoom-in up to 1.5 and pan at same time to some spot near center of picture:
+@example
+zoompan=z='min(zoom+0.0015,1.5)':d=700:x='if(gte(zoom,1.5),x,x+1/a)':y='if(gte(zoom,1.5),y,y+1)':s=640x360
+@end example
+@end itemize
+
@c man end VIDEO FILTERS
@chapter Video Sources
@@ -2846,6 +10166,11 @@ It accepts the following parameters:
@table @option
+@item video_size
+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}.
+
@item width
The input video width.
@@ -2853,14 +10178,23 @@ The input video width.
The input video height.
@item pix_fmt
-The name of the input video pixel format.
+A string representing the pixel format of the buffered video frames.
+It may be a number corresponding to a pixel format, or a pixel format
+name.
@item time_base
-The time base used for input timestamps.
+Specify the timebase assumed by the timestamps of the buffered frames.
-@item sar
+@item frame_rate
+Specify the frame rate expected for the video stream.
+
+@item pixel_aspect, sar
The sample (pixel) aspect ratio of the input video.
+@item sws_param
+Specify the optional parameters to be used for the scale filter which
+is automatically inserted when an input change is detected in the
+input size or format.
@end table
For example:
@@ -2871,131 +10205,272 @@ buffer=width=320:height=240:pix_fmt=yuv410p:time_base=1/24:sar=1
will instruct the source to accept video frames with size 320x240 and
with format "yuv410p", assuming 1/24 as the timestamps timebase and
square pixels (1:1 sample aspect ratio).
+Since the pixel format with name "yuv410p" corresponds to the number 6
+(check the enum AVPixelFormat definition in @file{libavutil/pixfmt.h}),
+this example corresponds to:
+@example
+buffer=size=320x240:pixfmt=6:time_base=1/24:pixel_aspect=1/1
+@end example
-@section color
+Alternatively, the options can be specified as a flat string, but this
+syntax is deprecated:
-Provide an uniformly colored input.
+@var{width}:@var{height}:@var{pix_fmt}:@var{time_base.num}:@var{time_base.den}:@var{pixel_aspect.num}:@var{pixel_aspect.den}[:@var{sws_param}]
-It accepts the following parameters:
+@section cellauto
+
+Create a pattern generated by an elementary cellular automaton.
+
+The initial state of the cellular automaton can be defined through the
+@option{filename}, and @option{pattern} options. If such options are
+not specified an initial state is created randomly.
+
+At each new frame a new row in the video is filled with the result of
+the cellular automaton next generation. The behavior when the whole
+frame is filled is defined by the @option{scroll} option.
+
+This source accepts the following options:
@table @option
+@item filename, f
+Read the initial cellular automaton state, i.e. the starting row, from
+the specified file.
+In the file, each non-whitespace character is considered an alive
+cell, a newline will terminate the row, and further characters in the
+file will be ignored.
-@item color
-Specify the color of the source. It can be the name of a color (case
-insensitive match) or a 0xRRGGBB[AA] sequence, possibly followed by an
-alpha specifier. The default value is "black".
+@item pattern, p
+Read the initial cellular automaton state, i.e. the starting row, from
+the specified string.
-@item size
-Specify the size of the sourced video, it may be a string of the form
-@var{width}x@var{height}, or the name of a size abbreviation. The
-default value is "320x240".
+Each non-whitespace character in the string is considered an alive
+cell, a newline will terminate the row, and further characters in the
+string will be ignored.
-@item framerate
-Specify the frame rate of the sourced video, as the number of frames
-generated per second. It has to be a string in the format
-@var{frame_rate_num}/@var{frame_rate_den}, an integer number, a floating point
-number or a valid video frame rate abbreviation. The default value is
-"25".
+@item rate, r
+Set the video rate, that is the number of frames generated per second.
+Default is 25.
+
+@item random_fill_ratio, ratio
+Set the random fill ratio for the initial cellular automaton row. It
+is a floating point number value ranging from 0 to 1, defaults to
+1/PHI.
+This option is ignored when a file or a pattern is specified.
+
+@item random_seed, seed
+Set the seed for filling randomly the initial row, must be an integer
+included between 0 and UINT32_MAX. If not specified, or if explicitly
+set to -1, the filter will try to use a good random seed on a best
+effort basis.
+
+@item rule
+Set the cellular automaton rule, it is a number ranging from 0 to 255.
+Default value is 110.
+
+@item size, s
+Set the size of the output video. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+
+If @option{filename} or @option{pattern} is specified, the size is set
+by default to the width of the specified initial state row, and the
+height is set to @var{width} * PHI.
+
+If @option{size} is set, it must contain the width of the specified
+pattern string, and the specified pattern will be centered in the
+larger row.
+
+If a filename or a pattern string is not specified, the size value
+defaults to "320x518" (used for a randomly generated initial state).
+
+@item scroll
+If set to 1, scroll the output upward when all the rows in the output
+have been already filled. If set to 0, the new generated row will be
+written over the top row just after the bottom row is filled.
+Defaults to 1.
+
+@item start_full, full
+If set to 1, completely fill the output with generated rows before
+outputting the first frame.
+This is the default behavior, for disabling set the value to 0.
+
+@item stitch
+If set to 1, stitch the left and right row edges together.
+This is the default behavior, for disabling set the value to 0.
@end table
-The following graph description will generate a red source
-with an opacity of 0.2, with size "qcif" and a frame rate of 10
-frames per second, which will be overlayed over the source connected
-to the pad with identifier "in":
+@subsection Examples
+@itemize
+@item
+Read the initial state from @file{pattern}, and specify an output of
+size 200x400.
@example
-"color=red@@0.2:qcif:10 [color]; [in][color] overlay [out]"
+cellauto=f=pattern:s=200x400
@end example
-@section movie
+@item
+Generate a random initial row with a width of 200 cells, with a fill
+ratio of 2/3:
+@example
+cellauto=ratio=2/3:s=200x200
+@end example
-Read a video stream from a movie container.
+@item
+Create a pattern generated by rule 18 starting by a single alive cell
+centered on an initial row with width 100:
+@example
+cellauto=p=@@:s=100x400:full=0:rule=18
+@end example
-Note that this source is a hack that bypasses the standard input path. It can be
-useful in applications that do not support arbitrary filter graphs, but its use
-is discouraged in those that do. It should never be used with
-@command{avconv}; the @option{-filter_complex} option fully replaces it.
+@item
+Specify a more elaborated initial pattern:
+@example
+cellauto=p='@@@@ @@ @@@@':s=100x400:full=0:rule=18
+@end example
-It accepts the following parameters:
+@end itemize
+
+@section mandelbrot
+
+Generate a Mandelbrot set fractal, and progressively zoom towards the
+point specified with @var{start_x} and @var{start_y}.
+
+This source accepts the following options:
@table @option
-@item filename
-The name of the resource to read (not necessarily a file; it can also be a
-device or a stream accessed through some protocol).
+@item end_pts
+Set the terminal pts value. Default value is 400.
-@item format_name, f
-Specifies the format assumed for the movie to read, and can be either
-the name of a container or an input device. If not specified, the
-format is guessed from @var{movie_name} or by probing.
+@item end_scale
+Set the terminal scale value.
+Must be a floating point value. Default value is 0.3.
-@item seek_point, sp
-Specifies the seek point in seconds. The frames will be output
-starting from this seek point. The parameter is evaluated with
-@code{av_strtod}, so the numerical value may be suffixed by an IS
-postfix. The default value is "0".
+@item inner
+Set the inner coloring mode, that is the algorithm used to draw the
+Mandelbrot fractal internal region.
-@item stream_index, si
-Specifies the index of the video stream to read. If the value is -1,
-the most suitable video stream will be automatically selected. The default
-value is "-1".
+It shall assume one of the following values:
+@table @option
+@item black
+Set black mode.
+@item convergence
+Show time until convergence.
+@item mincol
+Set color based on point closest to the origin of the iterations.
+@item period
+Set period mode.
+@end table
+
+Default value is @var{mincol}.
+@item bailout
+Set the bailout value. Default value is 10.0.
+
+@item maxiter
+Set the maximum of iterations performed by the rendering
+algorithm. Default value is 7189.
+
+@item outer
+Set outer coloring mode.
+It shall assume one of following values:
+@table @option
+@item iteration_count
+Set iteration cound mode.
+@item normalized_iteration_count
+set normalized iteration count mode.
@end table
+Default value is @var{normalized_iteration_count}.
-It allows overlaying a second video on top of the main input of
-a filtergraph, as shown in this graph:
-@example
-input -----------> deltapts0 --> overlay --> output
- ^
- |
-movie --> scale--> deltapts1 -------+
-@end example
+@item rate, r
+Set frame rate, expressed as number of frames per second. Default
+value is "25".
-Some examples:
-@example
-# Skip 3.2 seconds from the start of the AVI file in.avi, and overlay it
-# on top of the input labelled "in"
-movie=in.avi:seek_point=3.2, scale=180:-1, setpts=PTS-STARTPTS [movie];
-[in] setpts=PTS-STARTPTS, [movie] overlay=16:16 [out]
+@item size, s
+Set frame size. For the syntax of this option, check the "Video
+size" section in the ffmpeg-utils manual. Default value is "640x480".
-# Read from a video4linux2 device, and overlay it on top of the input
-# labelled "in"
-movie=/dev/video0:f=video4linux2, scale=180:-1, setpts=PTS-STARTPTS [movie];
-[in] setpts=PTS-STARTPTS, [movie] overlay=16:16 [out]
+@item start_scale
+Set the initial scale value. Default value is 3.0.
-@end example
+@item start_x
+Set the initial x position. Must be a floating point value between
+-100 and 100. Default value is -0.743643887037158704752191506114774.
+
+@item start_y
+Set the initial y position. Must be a floating point value between
+-100 and 100. Default value is -0.131825904205311970493132056385139.
+@end table
+
+@section mptestsrc
+
+Generate various test patterns, as generated by the MPlayer test filter.
+
+The size of the generated video is fixed, and is 256x256.
+This source is useful in particular for testing encoding features.
-@section nullsrc
+This source accepts the following options:
-Null video source: never return images. It is mainly useful as a
-template and to be employed in analysis / debugging tools.
+@table @option
-It accepts a string of the form
-@var{width}:@var{height}:@var{timebase} as an optional parameter.
+@item rate, r
+Specify the frame rate of the sourced video, as the number of frames
+generated per second. It has to be a string in the format
+@var{frame_rate_num}/@var{frame_rate_den}, an integer number, a floating point
+number or a valid video frame rate abbreviation. The default value is
+"25".
-@var{width} and @var{height} specify the size of the configured
-source. The default values of @var{width} and @var{height} are
-respectively 352 and 288 (corresponding to the CIF size format).
+@item duration, d
+Set the duration of the sourced video. See
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
-@var{timebase} specifies an arithmetic expression representing a
-timebase. The expression can contain the constants "PI", "E", "PHI", and
-"AVTB" (the default timebase), and defaults to the value "AVTB".
+If not specified, or the expressed duration is negative, the video is
+supposed to be generated forever.
+
+@item test, t
+
+Set the number or the name of the test to perform. Supported tests are:
+@table @option
+@item dc_luma
+@item dc_chroma
+@item freq_luma
+@item freq_chroma
+@item amp_luma
+@item amp_chroma
+@item cbp
+@item mv
+@item ring1
+@item ring2
+@item all
+
+@end table
+
+Default value is "all", which will cycle through the list of all tests.
+@end table
+
+Some examples:
+@example
+mptestsrc=t=dc_luma
+@end example
+
+will generate a "dc_luma" test pattern.
@section frei0r_src
Provide a frei0r source.
To enable compilation of this filter you need to install the frei0r
-header and configure Libav with --enable-frei0r.
+header and configure FFmpeg with @code{--enable-frei0r}.
This source accepts the following parameters:
@table @option
@item size
-The size of the video to generate. It may be a string of the form
-@var{width}x@var{height} or a frame size abbreviation.
+The size of the video to generate. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
@item framerate
The framerate of the generated video. It may be a string of the form
@@ -3011,19 +10486,169 @@ A '|'-separated list of parameters to pass to the frei0r source.
@end table
-An example:
+For example, to generate a frei0r partik0l source with size 200x200
+and frame rate 10 which is overlaid on the overlay filter main input:
@example
-# Generate a frei0r partik0l source with size 200x200 and framerate 10
-# which is overlayed on the overlay filter main input
frei0r_src=size=200x200:framerate=10:filter_name=partik0l:filter_params=1234 [overlay]; [in][overlay] overlay
@end example
-@section rgbtestsrc, testsrc
+@section life
+
+Generate a life pattern.
+
+This source is based on a generalization of John Conway's life game.
+
+The sourced input represents a life grid, each pixel represents a cell
+which can be in one of two possible states, alive or dead. Every cell
+interacts with its eight neighbours, which are the cells that are
+horizontally, vertically, or diagonally adjacent.
+
+At each interaction the grid evolves according to the adopted rule,
+which specifies the number of neighbor alive cells which will make a
+cell stay alive or born. The @option{rule} option allows one to specify
+the rule to adopt.
+
+This source accepts the following options:
+
+@table @option
+@item filename, f
+Set the file from which to read the initial grid state. In the file,
+each non-whitespace character is considered an alive cell, and newline
+is used to delimit the end of each row.
+
+If this option is not specified, the initial grid is generated
+randomly.
+
+@item rate, r
+Set the video rate, that is the number of frames generated per second.
+Default is 25.
+
+@item random_fill_ratio, ratio
+Set the random fill ratio for the initial random grid. It is a
+floating point number value ranging from 0 to 1, defaults to 1/PHI.
+It is ignored when a file is specified.
+
+@item random_seed, seed
+Set the seed for filling the initial random grid, must be an integer
+included between 0 and UINT32_MAX. If not specified, or if explicitly
+set to -1, the filter will try to use a good random seed on a best
+effort basis.
+
+@item rule
+Set the life rule.
+
+A rule can be specified with a code of the kind "S@var{NS}/B@var{NB}",
+where @var{NS} and @var{NB} are sequences of numbers in the range 0-8,
+@var{NS} specifies the number of alive neighbor cells which make a
+live cell stay alive, and @var{NB} the number of alive neighbor cells
+which make a dead cell to become alive (i.e. to "born").
+"s" and "b" can be used in place of "S" and "B", respectively.
+
+Alternatively a rule can be specified by an 18-bits integer. The 9
+high order bits are used to encode the next cell state if it is alive
+for each number of neighbor alive cells, the low order bits specify
+the rule for "borning" new cells. Higher order bits encode for an
+higher number of neighbor cells.
+For example the number 6153 = @code{(12<<9)+9} specifies a stay alive
+rule of 12 and a born rule of 9, which corresponds to "S23/B03".
+
+Default value is "S23/B3", which is the original Conway's game of life
+rule, and will keep a cell alive if it has 2 or 3 neighbor alive
+cells, and will born a new cell if there are three alive cells around
+a dead cell.
+
+@item size, s
+Set the size of the output video. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+
+If @option{filename} is specified, the size is set by default to the
+same size of the input file. If @option{size} is set, it must contain
+the size specified in the input file, and the initial grid defined in
+that file is centered in the larger resulting area.
+
+If a filename is not specified, the size value defaults to "320x240"
+(used for a randomly generated initial grid).
+
+@item stitch
+If set to 1, stitch the left and right grid edges together, and the
+top and bottom edges also. Defaults to 1.
+
+@item mold
+Set cell mold speed. If set, a dead cell will go from @option{death_color} to
+@option{mold_color} with a step of @option{mold}. @option{mold} can have a
+value from 0 to 255.
+
+@item life_color
+Set the color of living (or new born) cells.
+
+@item death_color
+Set the color of dead cells. If @option{mold} is set, this is the first color
+used to represent a dead cell.
+
+@item mold_color
+Set mold color, for definitely dead and moldy cells.
+
+For the syntax of these 3 color options, check the "Color" section in the
+ffmpeg-utils manual.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Read a grid from @file{pattern}, and center it on a grid of size
+300x300 pixels:
+@example
+life=f=pattern:s=300x300
+@end example
+
+@item
+Generate a random grid of size 200x200, with a fill ratio of 2/3:
+@example
+life=ratio=2/3:s=200x200
+@end example
+
+@item
+Specify a custom rule for evolving a randomly generated grid:
+@example
+life=rule=S14/B34
+@end example
+
+@item
+Full example with slow death effect (mold) using @command{ffplay}:
+@example
+ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_color=#00ff00,scale=1200:800:flags=16
+@end example
+@end itemize
+
+@anchor{color}
+@anchor{haldclutsrc}
+@anchor{nullsrc}
+@anchor{rgbtestsrc}
+@anchor{smptebars}
+@anchor{smptehdbars}
+@anchor{testsrc}
+@section color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc
+
+The @code{color} source provides an uniformly colored input.
+
+The @code{haldclutsrc} source provides an identity Hald CLUT. See also
+@ref{haldclut} filter.
+
+The @code{nullsrc} source returns unprocessed video frames. It is
+mainly useful to be employed in analysis / debugging tools, or as the
+source for filters which ignore the input data.
The @code{rgbtestsrc} source generates an RGB test pattern useful for
detecting RGB vs BGR issues. You should see a red, green and blue
stripe from top to bottom.
+The @code{smptebars} source generates a color bars pattern, based on
+the SMPTE Engineering Guideline EG 1-1990.
+
+The @code{smptehdbars} source generates a color bars pattern, based on
+the SMPTE RP 219-2002.
+
The @code{testsrc} source generates a test video pattern, showing a
color pattern, a scrolling gradient and a timestamp. This is mainly
intended for testing purposes.
@@ -3032,10 +10657,23 @@ The sources accept the following parameters:
@table @option
+@item color, c
+Specify the color of the source, only available in the @code{color}
+source. For the syntax of this option, check the "Color" section in the
+ffmpeg-utils manual.
+
+@item level
+Specify the level of the Hald CLUT, only available in the @code{haldclutsrc}
+source. A level of @code{N} generates a picture of @code{N*N*N} by @code{N*N*N}
+pixels to be used as identity matrix for 3D lookup tables. Each component is
+coded on a @code{1/(N*N)} scale.
+
@item size, s
-Specify the size of the sourced video, it may be a string of the form
-@var{width}x@var{height}, or the name of a size abbreviation. The
-default value is "320x240".
+Specify the size of the sourced video. For the syntax of this option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+The default value is @code{320x240}.
+
+This option is not available with the @code{haldclutsrc} filter.
@item rate, r
Specify the frame rate of the sourced video, as the number of frames
@@ -3047,16 +10685,21 @@ number or a valid video frame rate abbreviation. The default value is
@item sar
Set the sample aspect ratio of the sourced video.
-@item duration
-Set the video duration of the sourced video. The accepted syntax is:
-@example
-[-]HH[:MM[:SS[.m...]]]
-[-]S+[.m...]
-@end example
-Also see the the @code{av_parse_time()} function.
+@item duration, d
+Set the duration of the sourced video. See
+@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the accepted syntax.
If not specified, or the expressed duration is negative, the video is
supposed to be generated forever.
+
+@item decimals, n
+Set the number of decimals to show in the timestamp, only available in the
+@code{testsrc} source.
+
+The displayed timestamp value will correspond to the original
+timestamp value multiplied by the power of 10 of the specified
+value. Default value is 0.
@end table
For example the following:
@@ -3065,7 +10708,31 @@ testsrc=duration=5.3:size=qcif:rate=10
@end example
will generate a video with a duration of 5.3 seconds, with size
-176x144 and a framerate of 10 frames per second.
+176x144 and a frame rate of 10 frames per second.
+
+The following graph description will generate a red source
+with an opacity of 0.2, with size "qcif" and a frame rate of 10
+frames per second.
+@example
+color=c=red@@0.2:s=qcif:r=10
+@end example
+
+If the input content is to be ignored, @code{nullsrc} can be used. The
+following command generates noise in the luminance plane by employing
+the @code{geq} filter:
+@example
+nullsrc=s=256x256, geq=random(1)*255:128:128
+@end example
+
+@subsection Commands
+
+The @code{color} source supports the following commands:
+
+@table @option
+@item c, color
+Set the color of the created image. Accepts the same syntax of the
+corresponding @option{color} option.
+@end table
@c man end VIDEO SOURCES
@@ -3079,8 +10746,13 @@ Below is a description of the currently available video sinks.
Buffer video frames, and make them available to the end of the filter
graph.
-This sink is intended for programmatic use through the interface defined in
-@file{libavfilter/buffersink.h}.
+This sink is mainly intended for programmatic use, in particular
+through the interface defined in @file{libavfilter/buffersink.h}
+or the options system.
+
+It accepts a pointer to an AVBufferSinkContext structure, which
+defines the incoming buffers' formats, to be passed as the opaque
+parameter to @code{avfilter_init_filter} for initialization.
@section nullsink
@@ -3089,3 +10761,1409 @@ mainly useful as a template and for use in analysis / debugging
tools.
@c man end VIDEO SINKS
+
+@chapter Multimedia Filters
+@c man begin MULTIMEDIA FILTERS
+
+Below is a description of the currently available multimedia filters.
+
+@section avectorscope
+
+Convert input audio to a video output, representing the audio vector
+scope.
+
+The filter is used to measure the difference between channels of stereo
+audio stream. A monoaural signal, consisting of identical left and right
+signal, results in straight vertical line. Any stereo separation is visible
+as a deviation from this line, creating a Lissajous figure.
+If the straight (or deviation from it) but horizontal line appears this
+indicates that the left and right channels are out of phase.
+
+The filter accepts the following options:
+
+@table @option
+@item mode, m
+Set the vectorscope mode.
+
+Available values are:
+@table @samp
+@item lissajous
+Lissajous rotated by 45 degrees.
+
+@item lissajous_xy
+Same as above but not rotated.
+@end table
+
+Default value is @samp{lissajous}.
+
+@item size, s
+Set the video size for the output. 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{400x400}.
+
+@item rate, r
+Set the output frame rate. Default value is @code{25}.
+
+@item rc
+@item gc
+@item bc
+Specify the red, green and blue contrast. Default values are @code{40}, @code{160} and @code{80}.
+Allowed range is @code{[0, 255]}.
+
+@item rf
+@item gf
+@item bf
+Specify the red, green and blue fade. Default values are @code{15}, @code{10} and @code{5}.
+Allowed range is @code{[0, 255]}.
+
+@item zoom
+Set the zoom factor. Default value is @code{1}. Allowed range is @code{[1, 10]}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Complete example using @command{ffplay}:
+@example
+ffplay -f lavfi 'amovie=input.mp3, asplit [a][out1];
+ [a] avectorscope=zoom=1.3:rc=2:gc=200:bc=10:rf=1:gf=8:bf=7 [out0]'
+@end example
+@end itemize
+
+@section concat
+
+Concatenate audio and video streams, joining them together one after the
+other.
+
+The filter works on segments of synchronized video and audio streams. All
+segments must have the same number of streams of each type, and that will
+also be the number of streams at output.
+
+The filter accepts the following options:
+
+@table @option
+
+@item n
+Set the number of segments. Default is 2.
+
+@item v
+Set the number of output video streams, that is also the number of video
+streams in each segment. Default is 1.
+
+@item a
+Set the number of output audio streams, that is also the number of audio
+streams in each segment. Default is 0.
+
+@item unsafe
+Activate unsafe mode: do not fail if segments have a different format.
+
+@end table
+
+The filter has @var{v}+@var{a} outputs: first @var{v} video outputs, then
+@var{a} audio outputs.
+
+There are @var{n}x(@var{v}+@var{a}) inputs: first the inputs for the first
+segment, in the same order as the outputs, then the inputs for the second
+segment, etc.
+
+Related streams do not always have exactly the same duration, for various
+reasons including codec frame size or sloppy authoring. For that reason,
+related synchronized streams (e.g. a video and its audio track) should be
+concatenated at once. The concat filter will use the duration of the longest
+stream in each segment (except the last one), and if necessary pad shorter
+audio streams with silence.
+
+For this filter to work correctly, all segments must start at timestamp 0.
+
+All corresponding streams must have the same parameters in all segments; the
+filtering system will automatically select a common pixel format for video
+streams, and a common sample format, sample rate and channel layout for
+audio streams, but other settings, such as resolution, must be converted
+explicitly by the user.
+
+Different frame rates are acceptable but will result in variable frame rate
+at output; be sure to configure the output file to handle it.
+
+@subsection Examples
+
+@itemize
+@item
+Concatenate an opening, an episode and an ending, all in bilingual version
+(video in stream 0, audio in streams 1 and 2):
+@example
+ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv -filter_complex \
+ '[0:0] [0:1] [0:2] [1:0] [1:1] [1:2] [2:0] [2:1] [2:2]
+ concat=n=3:v=1:a=2 [v] [a1] [a2]' \
+ -map '[v]' -map '[a1]' -map '[a2]' output.mkv
+@end example
+
+@item
+Concatenate two parts, handling audio and video separately, using the
+(a)movie sources, and adjusting the resolution:
+@example
+movie=part1.mp4, scale=512:288 [v1] ; amovie=part1.mp4 [a1] ;
+movie=part2.mp4, scale=512:288 [v2] ; amovie=part2.mp4 [a2] ;
+[v1] [v2] concat [outv] ; [a1] [a2] concat=v=0:a=1 [outa]
+@end example
+Note that a desync will happen at the stitch if the audio and video streams
+do not have exactly the same duration in the first file.
+
+@end itemize
+
+@section ebur128
+
+EBU R128 scanner filter. This filter takes an audio stream as input and outputs
+it unchanged. By default, it logs a message at a frequency of 10Hz with the
+Momentary loudness (identified by @code{M}), Short-term loudness (@code{S}),
+Integrated loudness (@code{I}) and Loudness Range (@code{LRA}).
+
+The filter also has a video output (see the @var{video} option) with a real
+time graph to observe the loudness evolution. The graphic contains the logged
+message mentioned above, so it is not printed anymore when this option is set,
+unless the verbose logging is set. The main graphing area contains the
+short-term loudness (3 seconds of analysis), and the gauge on the right is for
+the momentary loudness (400 milliseconds).
+
+More information about the Loudness Recommendation EBU R128 on
+@url{http://tech.ebu.ch/loudness}.
+
+The filter accepts the following options:
+
+@table @option
+
+@item video
+Activate the video output. The audio stream is passed unchanged whether this
+option is set or no. The video stream will be the first output stream if
+activated. Default is @code{0}.
+
+@item size
+Set the video size. This option is for video only. For the syntax of this
+option, check the
+@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}.
+Default and minimum resolution is @code{640x480}.
+
+@item meter
+Set the EBU scale meter. Default is @code{9}. Common values are @code{9} and
+@code{18}, respectively for EBU scale meter +9 and EBU scale meter +18. Any
+other integer value between this range is allowed.
+
+@item metadata
+Set metadata injection. If set to @code{1}, the audio input will be segmented
+into 100ms output frames, each of them containing various loudness information
+in metadata. All the metadata keys are prefixed with @code{lavfi.r128.}.
+
+Default is @code{0}.
+
+@item framelog
+Force the frame logging level.
+
+Available values are:
+@table @samp
+@item info
+information logging level
+@item verbose
+verbose logging level
+@end table
+
+By default, the logging level is set to @var{info}. If the @option{video} or
+the @option{metadata} options are set, it switches to @var{verbose}.
+
+@item peak
+Set peak mode(s).
+
+Available modes can be cumulated (the option is a @code{flag} type). Possible
+values are:
+@table @samp
+@item none
+Disable any peak mode (default).
+@item sample
+Enable sample-peak mode.
+
+Simple peak mode looking for the higher sample value. It logs a message
+for sample-peak (identified by @code{SPK}).
+@item true
+Enable true-peak mode.
+
+If enabled, the peak lookup is done on an over-sampled version of the input
+stream for better peak accuracy. It logs a message for true-peak.
+(identified by @code{TPK}) and true-peak per frame (identified by @code{FTPK}).
+This mode requires a build with @code{libswresample}.
+@end table
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Real-time graph using @command{ffplay}, with a EBU scale meter +18:
+@example
+ffplay -f lavfi -i "amovie=input.mp3,ebur128=video=1:meter=18 [out0][out1]"
+@end example
+
+@item
+Run an analysis with @command{ffmpeg}:
+@example
+ffmpeg -nostats -i input.mp3 -filter_complex ebur128 -f null -
+@end example
+@end itemize
+
+@section interleave, ainterleave
+
+Temporally interleave frames from several inputs.
+
+@code{interleave} works with video inputs, @code{ainterleave} with audio.
+
+These filters read frames from several inputs and send the oldest
+queued frame to the output.
+
+Input streams must have a well defined, monotonically increasing frame
+timestamp values.
+
+In order to submit one frame to output, these filters need to enqueue
+at least one frame for each input, so they cannot work in case one
+input is not yet terminated and will not receive incoming frames.
+
+For example consider the case when one input is a @code{select} filter
+which always drop input frames. The @code{interleave} filter will keep
+reading from that input, but it will never be able to send new frames
+to output until the input will send an end-of-stream signal.
+
+Also, depending on inputs synchronization, the filters will drop
+frames in case one input receives more frames than the other ones, and
+the queue is already filled.
+
+These filters accept the following options:
+
+@table @option
+@item nb_inputs, n
+Set the number of different inputs, it is 2 by default.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Interleave frames belonging to different streams using @command{ffmpeg}:
+@example
+ffmpeg -i bambi.avi -i pr0n.mkv -filter_complex "[0:v][1:v] interleave" out.avi
+@end example
+
+@item
+Add flickering blur effect:
+@example
+select='if(gt(random(0), 0.2), 1, 2)':n=2 [tmp], boxblur=2:2, [tmp] interleave
+@end example
+@end itemize
+
+@section perms, aperms
+
+Set read/write permissions for the output frames.
+
+These filters are mainly aimed at developers to test direct path in the
+following filter in the filtergraph.
+
+The filters accept the following options:
+
+@table @option
+@item mode
+Select the permissions mode.
+
+It accepts the following values:
+@table @samp
+@item none
+Do nothing. This is the default.
+@item ro
+Set all the output frames read-only.
+@item rw
+Set all the output frames directly writable.
+@item toggle
+Make the frame read-only if writable, and writable if read-only.
+@item random
+Set each output frame read-only or writable randomly.
+@end table
+
+@item seed
+Set the seed for the @var{random} mode, must be an integer included between
+@code{0} and @code{UINT32_MAX}. If not specified, or if explicitly set to
+@code{-1}, the filter will try to use a good random seed on a best effort
+basis.
+@end table
+
+Note: in case of auto-inserted filter between the permission filter and the
+following one, the permission might not be received as expected in that
+following filter. Inserting a @ref{format} or @ref{aformat} filter before the
+perms/aperms filter can avoid this problem.
+
+@section select, aselect
+
+Select frames to pass in output.
+
+This filter accepts the following options:
+
+@table @option
+
+@item expr, e
+Set expression, which is evaluated for each input frame.
+
+If the expression is evaluated to zero, the frame is discarded.
+
+If the evaluation result is negative or NaN, the frame is sent to the
+first output; otherwise it is sent to the output with index
+@code{ceil(val)-1}, assuming that the input index starts from 0.
+
+For example a value of @code{1.2} corresponds to the output with index
+@code{ceil(1.2)-1 = 2-1 = 1}, that is the second output.
+
+@item outputs, n
+Set the number of outputs. The output to which to send the selected
+frame is based on the result of the evaluation. Default value is 1.
+@end table
+
+The expression can contain the following constants:
+
+@table @option
+@item n
+The (sequential) number of the filtered frame, starting from 0.
+
+@item selected_n
+The (sequential) number of the selected frame, starting from 0.
+
+@item prev_selected_n
+The sequential number of the last selected frame. It's NAN if undefined.
+
+@item TB
+The timebase of the input timestamps.
+
+@item pts
+The PTS (Presentation TimeStamp) of the filtered video frame,
+expressed in @var{TB} units. It's NAN if undefined.
+
+@item t
+The PTS of the filtered video frame,
+expressed in seconds. It's NAN if undefined.
+
+@item prev_pts
+The PTS of the previously filtered video frame. It's NAN if undefined.
+
+@item prev_selected_pts
+The PTS of the last previously filtered video frame. It's NAN if undefined.
+
+@item prev_selected_t
+The PTS of the last previously selected video frame. It's NAN if undefined.
+
+@item start_pts
+The PTS of the first video frame in the video. It's NAN if undefined.
+
+@item start_t
+The time of the first video frame in the video. It's NAN if undefined.
+
+@item pict_type @emph{(video only)}
+The type of the filtered frame. It can assume one of the following
+values:
+@table @option
+@item I
+@item P
+@item B
+@item S
+@item SI
+@item SP
+@item BI
+@end table
+
+@item interlace_type @emph{(video only)}
+The frame interlace type. It can assume one of the following values:
+@table @option
+@item PROGRESSIVE
+The frame is progressive (not interlaced).
+@item TOPFIRST
+The frame is top-field-first.
+@item BOTTOMFIRST
+The frame is bottom-field-first.
+@end table
+
+@item consumed_sample_n @emph{(audio only)}
+the number of selected samples before the current frame
+
+@item samples_n @emph{(audio only)}
+the number of samples in the current frame
+
+@item sample_rate @emph{(audio only)}
+the input sample rate
+
+@item key
+This is 1 if the filtered frame is a key-frame, 0 otherwise.
+
+@item pos
+the position in the file of the filtered frame, -1 if the information
+is not available (e.g. for synthetic video)
+
+@item scene @emph{(video only)}
+value between 0 and 1 to indicate a new scene; a low value reflects a low
+probability for the current frame to introduce a new scene, while a higher
+value means the current frame is more likely to be one (see the example below)
+
+@end table
+
+The default value of the select expression is "1".
+
+@subsection Examples
+
+@itemize
+@item
+Select all frames in input:
+@example
+select
+@end example
+
+The example above is the same as:
+@example
+select=1
+@end example
+
+@item
+Skip all frames:
+@example
+select=0
+@end example
+
+@item
+Select only I-frames:
+@example
+select='eq(pict_type\,I)'
+@end example
+
+@item
+Select one frame every 100:
+@example
+select='not(mod(n\,100))'
+@end example
+
+@item
+Select only frames contained in the 10-20 time interval:
+@example
+select=between(t\,10\,20)
+@end example
+
+@item
+Select only I frames contained in the 10-20 time interval:
+@example
+select=between(t\,10\,20)*eq(pict_type\,I)
+@end example
+
+@item
+Select frames with a minimum distance of 10 seconds:
+@example
+select='isnan(prev_selected_t)+gte(t-prev_selected_t\,10)'
+@end example
+
+@item
+Use aselect to select only audio frames with samples number > 100:
+@example
+aselect='gt(samples_n\,100)'
+@end example
+
+@item
+Create a mosaic of the first scenes:
+@example
+ffmpeg -i video.avi -vf select='gt(scene\,0.4)',scale=160:120,tile -frames:v 1 preview.png
+@end example
+
+Comparing @var{scene} against a value between 0.3 and 0.5 is generally a sane
+choice.
+
+@item
+Send even and odd frames to separate outputs, and compose them:
+@example
+select=n=2:e='mod(n, 2)+1' [odd][even]; [odd] pad=h=2*ih [tmp]; [tmp][even] overlay=y=h
+@end example
+@end itemize
+
+@section sendcmd, asendcmd
+
+Send commands to filters in the filtergraph.
+
+These filters read commands to be sent to other filters in the
+filtergraph.
+
+@code{sendcmd} must be inserted between two video filters,
+@code{asendcmd} must be inserted between two audio filters, but apart
+from that they act the same way.
+
+The specification of commands can be provided in the filter arguments
+with the @var{commands} option, or in a file specified by the
+@var{filename} option.
+
+These filters accept the following options:
+@table @option
+@item commands, c
+Set the commands to be read and sent to the other filters.
+@item filename, f
+Set the filename of the commands to be read and sent to the other
+filters.
+@end table
+
+@subsection Commands syntax
+
+A commands description consists of a sequence of interval
+specifications, comprising a list of commands to be executed when a
+particular event related to that interval occurs. The occurring event
+is typically the current frame time entering or leaving a given time
+interval.
+
+An interval is specified by the following syntax:
+@example
+@var{START}[-@var{END}] @var{COMMANDS};
+@end example
+
+The time interval is specified by the @var{START} and @var{END} times.
+@var{END} is optional and defaults to the maximum time.
+
+The current frame time is considered within the specified interval if
+it is included in the interval [@var{START}, @var{END}), that is when
+the time is greater or equal to @var{START} and is lesser than
+@var{END}.
+
+@var{COMMANDS} consists of a sequence of one or more command
+specifications, separated by ",", relating to that interval. The
+syntax of a command specification is given by:
+@example
+[@var{FLAGS}] @var{TARGET} @var{COMMAND} @var{ARG}
+@end example
+
+@var{FLAGS} is optional and specifies the type of events relating to
+the time interval which enable sending the specified command, and must
+be a non-null sequence of identifier flags separated by "+" or "|" and
+enclosed between "[" and "]".
+
+The following flags are recognized:
+@table @option
+@item enter
+The command is sent when the current frame timestamp enters the
+specified interval. In other words, the command is sent when the
+previous frame timestamp was not in the given interval, and the
+current is.
+
+@item leave
+The command is sent when the current frame timestamp leaves the
+specified interval. In other words, the command is sent when the
+previous frame timestamp was in the given interval, and the
+current is not.
+@end table
+
+If @var{FLAGS} is not specified, a default value of @code{[enter]} is
+assumed.
+
+@var{TARGET} specifies the target of the command, usually the name of
+the filter class or a specific filter instance name.
+
+@var{COMMAND} specifies the name of the command for the target filter.
+
+@var{ARG} is optional and specifies the optional list of argument for
+the given @var{COMMAND}.
+
+Between one interval specification and another, whitespaces, or
+sequences of characters starting with @code{#} until the end of line,
+are ignored and can be used to annotate comments.
+
+A simplified BNF description of the commands specification syntax
+follows:
+@example
+@var{COMMAND_FLAG} ::= "enter" | "leave"
+@var{COMMAND_FLAGS} ::= @var{COMMAND_FLAG} [(+|"|")@var{COMMAND_FLAG}]
+@var{COMMAND} ::= ["[" @var{COMMAND_FLAGS} "]"] @var{TARGET} @var{COMMAND} [@var{ARG}]
+@var{COMMANDS} ::= @var{COMMAND} [,@var{COMMANDS}]
+@var{INTERVAL} ::= @var{START}[-@var{END}] @var{COMMANDS}
+@var{INTERVALS} ::= @var{INTERVAL}[;@var{INTERVALS}]
+@end example
+
+@subsection Examples
+
+@itemize
+@item
+Specify audio tempo change at second 4:
+@example
+asendcmd=c='4.0 atempo tempo 1.5',atempo
+@end example
+
+@item
+Specify a list of drawtext and hue commands in a file.
+@example
+# show text in the interval 5-10
+5.0-10.0 [enter] drawtext reinit 'fontfile=FreeSerif.ttf:text=hello world',
+ [leave] drawtext reinit 'fontfile=FreeSerif.ttf:text=';
+
+# desaturate the image in the interval 15-20
+15.0-20.0 [enter] hue s 0,
+ [enter] drawtext reinit 'fontfile=FreeSerif.ttf:text=nocolor',
+ [leave] hue s 1,
+ [leave] drawtext reinit 'fontfile=FreeSerif.ttf:text=color';
+
+# apply an exponential saturation fade-out effect, starting from time 25
+25 [enter] hue s exp(25-t)
+@end example
+
+A filtergraph allowing to read and process the above command list
+stored in a file @file{test.cmd}, can be specified with:
+@example
+sendcmd=f=test.cmd,drawtext=fontfile=FreeSerif.ttf:text='',hue
+@end example
+@end itemize
+
+@anchor{setpts}
+@section setpts, asetpts
+
+Change the PTS (presentation timestamp) of the input frames.
+
+@code{setpts} works on video frames, @code{asetpts} on audio frames.
+
+This filter accepts the following options:
+
+@table @option
+
+@item expr
+The expression which is evaluated for each frame to construct its timestamp.
+
+@end table
+
+The expression is evaluated through the eval API and can contain the following
+constants:
+
+@table @option
+@item FRAME_RATE
+frame rate, only defined for constant frame-rate video
+
+@item PTS
+The presentation timestamp in input
+
+@item N
+The count of the input frame for video or the number of consumed samples,
+not including the current frame for audio, starting from 0.
+
+@item NB_CONSUMED_SAMPLES
+The number of consumed samples, not including the current frame (only
+audio)
+
+@item NB_SAMPLES, S
+The number of samples in the current frame (only audio)
+
+@item SAMPLE_RATE, SR
+The audio sample rate.
+
+@item STARTPTS
+The PTS of the first frame.
+
+@item STARTT
+the time in seconds of the first frame
+
+@item INTERLACED
+State whether the current frame is interlaced.
+
+@item T
+the time in seconds of the current frame
+
+@item POS
+original position in the file of the frame, or undefined if undefined
+for the current frame
+
+@item PREV_INPTS
+The previous input PTS.
+
+@item PREV_INT
+previous input time in seconds
+
+@item PREV_OUTPTS
+The previous output PTS.
+
+@item PREV_OUTT
+previous output time in seconds
+
+@item RTCTIME
+The wallclock (RTC) time in microseconds. This is deprecated, use time(0)
+instead.
+
+@item RTCSTART
+The wallclock (RTC) time at the start of the movie in microseconds.
+
+@item TB
+The timebase of the input timestamps.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Start counting PTS from zero
+@example
+setpts=PTS-STARTPTS
+@end example
+
+@item
+Apply fast motion effect:
+@example
+setpts=0.5*PTS
+@end example
+
+@item
+Apply slow motion effect:
+@example
+setpts=2.0*PTS
+@end example
+
+@item
+Set fixed rate of 25 frames per second:
+@example
+setpts=N/(25*TB)
+@end example
+
+@item
+Set fixed rate 25 fps with some jitter:
+@example
+setpts='1/(25*TB) * (N + 0.05 * sin(N*2*PI/25))'
+@end example
+
+@item
+Apply an offset of 10 seconds to the input PTS:
+@example
+setpts=PTS+10/TB
+@end example
+
+@item
+Generate timestamps from a "live source" and rebase onto the current timebase:
+@example
+setpts='(RTCTIME - RTCSTART) / (TB * 1000000)'
+@end example
+
+@item
+Generate timestamps by counting samples:
+@example
+asetpts=N/SR/TB
+@end example
+
+@end itemize
+
+@section settb, asettb
+
+Set the timebase to use for the output frames timestamps.
+It is mainly useful for testing timebase configuration.
+
+It accepts the following parameters:
+
+@table @option
+
+@item expr, tb
+The expression which is evaluated into the output timebase.
+
+@end table
+
+The value for @option{tb} is an arithmetic expression representing a
+rational. The expression can contain the constants "AVTB" (the default
+timebase), "intb" (the input timebase) and "sr" (the sample rate,
+audio only). Default value is "intb".
+
+@subsection Examples
+
+@itemize
+@item
+Set the timebase to 1/25:
+@example
+settb=expr=1/25
+@end example
+
+@item
+Set the timebase to 1/10:
+@example
+settb=expr=0.1
+@end example
+
+@item
+Set the timebase to 1001/1000:
+@example
+settb=1+0.001
+@end example
+
+@item
+Set the timebase to 2*intb:
+@example
+settb=2*intb
+@end example
+
+@item
+Set the default timebase value:
+@example
+settb=AVTB
+@end example
+@end itemize
+
+@section showcqt
+Convert input audio to a video output representing
+frequency spectrum logarithmically (using constant Q transform with
+Brown-Puckette algorithm), with musical tone scale, from E0 to D#10 (10 octaves).
+
+The filter accepts the following options:
+
+@table @option
+@item volume
+Specify transform volume (multiplier) expression. The expression can contain
+variables:
+@table @option
+@item frequency, freq, f
+the frequency where transform is evaluated
+@item timeclamp, tc
+value of timeclamp option
+@end table
+and functions:
+@table @option
+@item a_weighting(f)
+A-weighting of equal loudness
+@item b_weighting(f)
+B-weighting of equal loudness
+@item c_weighting(f)
+C-weighting of equal loudness
+@end table
+Default value is @code{16}.
+
+@item tlength
+Specify transform length expression. The expression can contain variables:
+@table @option
+@item frequency, freq, f
+the frequency where transform is evaluated
+@item timeclamp, tc
+value of timeclamp option
+@end table
+Default value is @code{384/f*tc/(384/f+tc)}.
+
+@item timeclamp
+Specify the transform timeclamp. At low frequency, there is trade-off between
+accuracy in time domain and frequency domain. If timeclamp is lower,
+event in time domain is represented more accurately (such as fast bass drum),
+otherwise event in frequency domain is represented more accurately
+(such as bass guitar). Acceptable value is [0.1, 1.0]. Default value is @code{0.17}.
+
+@item coeffclamp
+Specify the transform coeffclamp. If coeffclamp is lower, transform is
+more accurate, otherwise transform is faster. Acceptable value is [0.1, 10.0].
+Default value is @code{1.0}.
+
+@item gamma
+Specify gamma. Lower gamma makes the spectrum more contrast, higher gamma
+makes the spectrum having more range. Acceptable value is [1.0, 7.0].
+Default value is @code{3.0}.
+
+@item gamma2
+Specify gamma of bargraph. Acceptable value is [1.0, 7.0].
+Default value is @code{1.0}.
+
+@item fontfile
+Specify font file for use with freetype. If not specified, use embedded font.
+
+@item fontcolor
+Specify font color expression. This is arithmetic expression that should return
+integer value 0xRRGGBB. The expression can contain variables:
+@table @option
+@item frequency, freq, f
+the frequency where transform is evaluated
+@item timeclamp, tc
+value of timeclamp option
+@end table
+and functions:
+@table @option
+@item midi(f)
+midi number of frequency f, some midi numbers: E0(16), C1(24), C2(36), A4(69)
+@item r(x), g(x), b(x)
+red, green, and blue value of intensity x
+@end table
+Default value is @code{st(0, (midi(f)-59.5)/12);
+st(1, if(between(ld(0),0,1), 0.5-0.5*cos(2*PI*ld(0)), 0));
+r(1-ld(1)) + b(ld(1))}
+
+@item fullhd
+If set to 1 (the default), the video size is 1920x1080 (full HD),
+if set to 0, the video size is 960x540. Use this option to make CPU usage lower.
+
+@item fps
+Specify video fps. Default value is @code{25}.
+
+@item count
+Specify number of transform per frame, so there are fps*count transforms
+per second. Note that audio data rate must be divisible by fps*count.
+Default value is @code{6}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Playing audio while showing the spectrum:
+@example
+ffplay -f lavfi 'amovie=a.mp3, asplit [a][out1]; [a] showcqt [out0]'
+@end example
+
+@item
+Same as above, but with frame rate 30 fps:
+@example
+ffplay -f lavfi 'amovie=a.mp3, asplit [a][out1]; [a] showcqt=fps=30:count=5 [out0]'
+@end example
+
+@item
+Playing at 960x540 and lower CPU usage:
+@example
+ffplay -f lavfi 'amovie=a.mp3, asplit [a][out1]; [a] showcqt=fullhd=0:count=3 [out0]'
+@end example
+
+@item
+A1 and its harmonics: A1, A2, (near)E3, A3:
+@example
+ffplay -f lavfi 'aevalsrc=0.1*sin(2*PI*55*t)+0.1*sin(4*PI*55*t)+0.1*sin(6*PI*55*t)+0.1*sin(8*PI*55*t),
+ asplit[a][out1]; [a] showcqt [out0]'
+@end example
+
+@item
+Same as above, but with more accuracy in frequency domain (and slower):
+@example
+ffplay -f lavfi 'aevalsrc=0.1*sin(2*PI*55*t)+0.1*sin(4*PI*55*t)+0.1*sin(6*PI*55*t)+0.1*sin(8*PI*55*t),
+ asplit[a][out1]; [a] showcqt=timeclamp=0.5 [out0]'
+@end example
+
+@item
+B-weighting of equal loudness
+@example
+volume=16*b_weighting(f)
+@end example
+
+@item
+Lower Q factor
+@example
+tlength=100/f*tc/(100/f+tc)
+@end example
+
+@item
+Custom fontcolor, C-note is colored green, others are colored blue
+@example
+fontcolor='if(mod(floor(midi(f)+0.5),12), 0x0000FF, g(1))'
+@end example
+
+@item
+Custom gamma, now spectrum is linear to the amplitude.
+@example
+gamma=2:gamma2=2
+@end example
+
+@end itemize
+
+@section showspectrum
+
+Convert input audio to a video output, representing the audio frequency
+spectrum.
+
+The filter accepts the following options:
+
+@table @option
+@item size, s
+Specify the video size for the output. 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{640x512}.
+
+@item slide
+Specify how the spectrum should slide along the window.
+
+It accepts the following values:
+@table @samp
+@item replace
+the samples start again on the left when they reach the right
+@item scroll
+the samples scroll from right to left
+@item fullframe
+frames are only produced when the samples reach the right
+@end table
+
+Default value is @code{replace}.
+
+@item mode
+Specify display mode.
+
+It accepts the following values:
+@table @samp
+@item combined
+all channels are displayed in the same row
+@item separate
+all channels are displayed in separate rows
+@end table
+
+Default value is @samp{combined}.
+
+@item color
+Specify display color mode.
+
+It accepts the following values:
+@table @samp
+@item channel
+each channel is displayed in a separate color
+@item intensity
+each channel is is displayed using the same color scheme
+@end table
+
+Default value is @samp{channel}.
+
+@item scale
+Specify scale used for calculating intensity color values.
+
+It accepts the following values:
+@table @samp
+@item lin
+linear
+@item sqrt
+square root, default
+@item cbrt
+cubic root
+@item log
+logarithmic
+@end table
+
+Default value is @samp{sqrt}.
+
+@item saturation
+Set saturation modifier for displayed colors. Negative values provide
+alternative color scheme. @code{0} is no saturation at all.
+Saturation must be in [-10.0, 10.0] range.
+Default value is @code{1}.
+
+@item win_func
+Set window function.
+
+It accepts the following values:
+@table @samp
+@item none
+No samples pre-processing (do not expect this to be faster)
+@item hann
+Hann window
+@item hamming
+Hamming window
+@item blackman
+Blackman window
+@end table
+
+Default value is @code{hann}.
+@end table
+
+The usage is very similar to the showwaves filter; see the examples in that
+section.
+
+@subsection Examples
+
+@itemize
+@item
+Large window with logarithmic color scaling:
+@example
+showspectrum=s=1280x480:scale=log
+@end example
+
+@item
+Complete example for a colored and sliding spectrum per channel using @command{ffplay}:
+@example
+ffplay -f lavfi 'amovie=input.mp3, asplit [a][out1];
+ [a] showspectrum=mode=separate:color=intensity:slide=1:scale=cbrt [out0]'
+@end example
+@end itemize
+
+@section showwaves
+
+Convert input audio to a video output, representing the samples waves.
+
+The filter accepts the following options:
+
+@table @option
+@item size, s
+Specify the video size for the output. 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{600x240}.
+
+@item mode
+Set display mode.
+
+Available values are:
+@table @samp
+@item point
+Draw a point for each sample.
+
+@item line
+Draw a vertical line for each sample.
+
+@item p2p
+Draw a point for each sample and a line between them.
+
+@item cline
+Draw a centered vertical line for each sample.
+@end table
+
+Default value is @code{point}.
+
+@item n
+Set the number of samples which are printed on the same column. A
+larger value will decrease the frame rate. Must be a positive
+integer. This option can be set only if the value for @var{rate}
+is not explicitly specified.
+
+@item rate, r
+Set the (approximate) output frame rate. This is done by setting the
+option @var{n}. Default value is "25".
+
+@item split_channels
+Set if channels should be drawn separately or overlap. Default value is 0.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Output the input file audio and the corresponding video representation
+at the same time:
+@example
+amovie=a.mp3,asplit[out0],showwaves[out1]
+@end example
+
+@item
+Create a synthetic signal and show it with showwaves, forcing a
+frame rate of 30 frames per second:
+@example
+aevalsrc=sin(1*2*PI*t)*sin(880*2*PI*t):cos(2*PI*200*t),asplit[out0],showwaves=r=30[out1]
+@end example
+@end itemize
+
+@section showwavespic
+
+Convert input audio to a single video frame, representing the samples waves.
+
+The filter accepts the following options:
+
+@table @option
+@item size, s
+Specify the video size for the output. 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{600x240}.
+
+@item split_channels
+Set if channels should be drawn separately or overlap. Default value is 0.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Extract a channel split representation of the wave form of a whole audio track
+in a 1024x800 picture using @command{ffmpeg}:
+@example
+ffmpeg -i audio.flac -lavfi showwavespic=split_channels=1:s=1024x800 waveform.png
+@end example
+@end itemize
+
+@section split, asplit
+
+Split input into several identical outputs.
+
+@code{asplit} works with audio input, @code{split} with video.
+
+The filter accepts a single parameter which specifies the number of outputs. If
+unspecified, it defaults to 2.
+
+@subsection Examples
+
+@itemize
+@item
+Create two separate outputs from the same input:
+@example
+[in] split [out0][out1]
+@end example
+
+@item
+To create 3 or more outputs, you need to specify the number of
+outputs, like in:
+@example
+[in] asplit=3 [out0][out1][out2]
+@end example
+
+@item
+Create two separate outputs from the same input, one cropped and
+one padded:
+@example
+[in] split [splitout1][splitout2];
+[splitout1] crop=100:100:0:0 [cropout];
+[splitout2] pad=200:200:100:100 [padout];
+@end example
+
+@item
+Create 5 copies of the input audio with @command{ffmpeg}:
+@example
+ffmpeg -i INPUT -filter_complex asplit=5 OUTPUT
+@end example
+@end itemize
+
+@section zmq, azmq
+
+Receive commands sent through a libzmq client, and forward them to
+filters in the filtergraph.
+
+@code{zmq} and @code{azmq} work as a pass-through filters. @code{zmq}
+must be inserted between two video filters, @code{azmq} between two
+audio filters.
+
+To enable these filters you need to install the libzmq library and
+headers and configure FFmpeg with @code{--enable-libzmq}.
+
+For more information about libzmq see:
+@url{http://www.zeromq.org/}
+
+The @code{zmq} and @code{azmq} filters work as a libzmq server, which
+receives messages sent through a network interface defined by the
+@option{bind_address} option.
+
+The received message must be in the form:
+@example
+@var{TARGET} @var{COMMAND} [@var{ARG}]
+@end example
+
+@var{TARGET} specifies the target of the command, usually the name of
+the filter class or a specific filter instance name.
+
+@var{COMMAND} specifies the name of the command for the target filter.
+
+@var{ARG} is optional and specifies the optional argument list for the
+given @var{COMMAND}.
+
+Upon reception, the message is processed and the corresponding command
+is injected into the filtergraph. Depending on the result, the filter
+will send a reply to the client, adopting the format:
+@example
+@var{ERROR_CODE} @var{ERROR_REASON}
+@var{MESSAGE}
+@end example
+
+@var{MESSAGE} is optional.
+
+@subsection Examples
+
+Look at @file{tools/zmqsend} for an example of a zmq client which can
+be used to send commands processed by these filters.
+
+Consider the following filtergraph generated by @command{ffplay}
+@example
+ffplay -dumpgraph 1 -f lavfi "
+color=s=100x100:c=red [l];
+color=s=100x100:c=blue [r];
+nullsrc=s=200x100, zmq [bg];
+[bg][l] overlay [bg+l];
+[bg+l][r] overlay=x=100 "
+@end example
+
+To change the color of the left side of the video, the following
+command can be used:
+@example
+echo Parsed_color_0 c yellow | tools/zmqsend
+@end example
+
+To change the right side:
+@example
+echo Parsed_color_1 c pink | tools/zmqsend
+@end example
+
+@c man end MULTIMEDIA FILTERS
+
+@chapter Multimedia Sources
+@c man begin MULTIMEDIA SOURCES
+
+Below is a description of the currently available multimedia sources.
+
+@section amovie
+
+This is the same as @ref{movie} source, except it selects an audio
+stream by default.
+
+@anchor{movie}
+@section movie
+
+Read audio and/or video stream(s) from a movie container.
+
+It accepts the following parameters:
+
+@table @option
+@item filename
+The name of the resource to read (not necessarily a file; it can also be a
+device or a stream accessed through some protocol).
+
+@item format_name, f
+Specifies the format assumed for the movie to read, and can be either
+the name of a container or an input device. If not specified, the
+format is guessed from @var{movie_name} or by probing.
+
+@item seek_point, sp
+Specifies the seek point in seconds. The frames will be output
+starting from this seek point. The parameter is evaluated with
+@code{av_strtod}, so the numerical value may be suffixed by an IS
+postfix. The default value is "0".
+
+@item streams, s
+Specifies the streams to read. Several streams can be specified,
+separated by "+". The source will then have as many outputs, in the
+same order. The syntax is explained in the ``Stream specifiers''
+section in the ffmpeg manual. Two special names, "dv" and "da" specify
+respectively the default (best suited) video and audio stream. Default
+is "dv", or "da" if the filter is called as "amovie".
+
+@item stream_index, si
+Specifies the index of the video stream to read. If the value is -1,
+the most suitable video stream will be automatically selected. The default
+value is "-1". Deprecated. If the filter is called "amovie", it will select
+audio instead of video.
+
+@item loop
+Specifies how many times to read the stream in sequence.
+If the value is less than 1, the stream will be read again and again.
+Default value is "1".
+
+Note that when the movie is looped the source timestamps are not
+changed, so it will generate non monotonically increasing timestamps.
+@end table
+
+It allows overlaying a second video on top of the main input of
+a filtergraph, as shown in this graph:
+@example
+input -----------> deltapts0 --> overlay --> output
+ ^
+ |
+movie --> scale--> deltapts1 -------+
+@end example
+@subsection Examples
+
+@itemize
+@item
+Skip 3.2 seconds from the start of the AVI file in.avi, and overlay it
+on top of the input labelled "in":
+@example
+movie=in.avi:seek_point=3.2, scale=180:-1, setpts=PTS-STARTPTS [over];
+[in] setpts=PTS-STARTPTS [main];
+[main][over] overlay=16:16 [out]
+@end example
+
+@item
+Read from a video4linux2 device, and overlay it on top of the input
+labelled "in":
+@example
+movie=/dev/video0:f=video4linux2, scale=180:-1, setpts=PTS-STARTPTS [over];
+[in] setpts=PTS-STARTPTS [main];
+[main][over] overlay=16:16 [out]
+@end example
+
+@item
+Read the first video stream and the audio stream with id 0x81 from
+dvd.vob; the video is connected to the pad named "video" and the audio is
+connected to the pad named "audio":
+@example
+movie=dvd.vob:s=v:0+#0x81 [video] [audio]
+@end example
+@end itemize
+
+@c man end MULTIMEDIA SOURCES
diff --git a/doc/formats.texi b/doc/formats.texi
new file mode 100644
index 0000000000..aa39d4bdef
--- /dev/null
+++ b/doc/formats.texi
@@ -0,0 +1,230 @@
+@chapter Format Options
+@c man begin FORMAT OPTIONS
+
+The libavformat library provides some generic global options, which
+can be set on all the muxers and demuxers. In addition each muxer or
+demuxer may support so-called private options, which are specific for
+that component.
+
+Options may be set by specifying -@var{option} @var{value} in the
+FFmpeg tools, or by setting the value explicitly in the
+@code{AVFormatContext} options or using the @file{libavutil/opt.h} API
+for programmatic use.
+
+The list of supported options follows:
+
+@table @option
+@item avioflags @var{flags} (@emph{input/output})
+Possible values:
+@table @samp
+@item direct
+Reduce buffering.
+@end table
+
+@item probesize @var{integer} (@emph{input})
+Set probing size in bytes, i.e. the size of the data to analyze to get
+stream information. A higher value will enable detecting more
+information in case it is dispersed into the stream, but will increase
+latency. Must be an integer not lesser than 32. It is 5000000 by default.
+
+@item packetsize @var{integer} (@emph{output})
+Set packet size.
+
+@item fflags @var{flags} (@emph{input/output})
+Set format flags.
+
+Possible values:
+@table @samp
+@item ignidx
+Ignore index.
+@item fastseek
+Enable fast, but inaccurate seeks for some formats.
+@item genpts
+Generate PTS.
+@item nofillin
+Do not fill in missing values that can be exactly calculated.
+@item noparse
+Disable AVParsers, this needs @code{+nofillin} too.
+@item igndts
+Ignore DTS.
+@item discardcorrupt
+Discard corrupted frames.
+@item sortdts
+Try to interleave output packets by DTS.
+@item keepside
+Do not merge side data.
+@item latm
+Enable RTP MP4A-LATM payload.
+@item nobuffer
+Reduce the latency introduced by optional buffering
+@item bitexact
+Only write platform-, build- and time-independent data.
+This ensures that file and data checksums are reproducible and match between
+platforms. Its primary use is for regression testing.
+@end table
+
+@item seek2any @var{integer} (@emph{input})
+Allow seeking to non-keyframes on demuxer level when supported if set to 1.
+Default is 0.
+
+@item analyzeduration @var{integer} (@emph{input})
+Specify how many microseconds are analyzed to probe the input. A
+higher value will enable detecting more accurate information, but will
+increase latency. It defaults to 5,000,000 microseconds = 5 seconds.
+
+@item cryptokey @var{hexadecimal string} (@emph{input})
+Set decryption key.
+
+@item indexmem @var{integer} (@emph{input})
+Set max memory used for timestamp index (per stream).
+
+@item rtbufsize @var{integer} (@emph{input})
+Set max memory used for buffering real-time frames.
+
+@item fdebug @var{flags} (@emph{input/output})
+Print specific debug info.
+
+Possible values:
+@table @samp
+@item ts
+@end table
+
+@item max_delay @var{integer} (@emph{input/output})
+Set maximum muxing or demuxing delay in microseconds.
+
+@item fpsprobesize @var{integer} (@emph{input})
+Set number of frames used to probe fps.
+
+@item audio_preload @var{integer} (@emph{output})
+Set microseconds by which audio packets should be interleaved earlier.
+
+@item chunk_duration @var{integer} (@emph{output})
+Set microseconds for each chunk.
+
+@item chunk_size @var{integer} (@emph{output})
+Set size in bytes for each chunk.
+
+@item err_detect, f_err_detect @var{flags} (@emph{input})
+Set error detection flags. @code{f_err_detect} is deprecated and
+should be used only via the @command{ffmpeg} tool.
+
+Possible values:
+@table @samp
+@item crccheck
+Verify embedded CRCs.
+@item bitstream
+Detect bitstream specification deviations.
+@item buffer
+Detect improper bitstream length.
+@item explode
+Abort decoding on minor error detection.
+@item careful
+Consider things that violate the spec and have not been seen in the
+wild as errors.
+@item compliant
+Consider all spec non compliancies as errors.
+@item aggressive
+Consider things that a sane encoder should not do as an error.
+@end table
+
+@item use_wallclock_as_timestamps @var{integer} (@emph{input})
+Use wallclock as timestamps.
+
+@item avoid_negative_ts @var{integer} (@emph{output})
+
+Possible values:
+@table @samp
+@item make_non_negative
+Shift timestamps to make them non-negative.
+Also note that this affects only leading negative timestamps, and not
+non-monotonic negative timestamps.
+@item make_zero
+Shift timestamps so that the first timestamp is 0.
+@item auto (default)
+Enables shifting when required by the target format.
+@item disabled
+Disables shifting of timestamp.
+@end table
+
+When shifting is enabled, all output timestamps are shifted by the
+same amount. Audio, video, and subtitles desynching and relative
+timestamp differences are preserved compared to how they would have
+been without shifting.
+
+@item skip_initial_bytes @var{integer} (@emph{input})
+Set number of bytes to skip before reading header and frames if set to 1.
+Default is 0.
+
+@item correct_ts_overflow @var{integer} (@emph{input})
+Correct single timestamp overflows if set to 1. Default is 1.
+
+@item flush_packets @var{integer} (@emph{output})
+Flush the underlying I/O stream after each packet. Default 1 enables it, and
+has the effect of reducing the latency; 0 disables it and may slightly
+increase performance in some cases.
+
+@item output_ts_offset @var{offset} (@emph{output})
+Set the output time offset.
+
+@var{offset} must be a time duration specification,
+see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}.
+
+The offset is added by the muxer to the output timestamps.
+
+Specifying a positive offset means that the corresponding streams are
+delayed bt the time duration specified in @var{offset}. Default value
+is @code{0} (meaning that no offset is applied).
+
+@item format_whitelist @var{list} (@emph{input})
+"," separated List of allowed demuxers. By default all are allowed.
+
+@item dump_separator @var{string} (@emph{input})
+Separator used to separate the fields printed on the command line about the
+Stream parameters.
+For example to separate the fields with newlines and indention:
+@example
+ffprobe -dump_separator "
+ " -i ~/videos/matrixbench_mpeg2.mpg
+@end example
+@end table
+
+@c man end FORMAT OPTIONS
+
+@anchor{Format stream specifiers}
+@section Format stream specifiers
+
+Format stream specifiers allow selection of one or more streams that
+match specific properties.
+
+Possible forms of stream specifiers are:
+@table @option
+@item @var{stream_index}
+Matches the stream with this index.
+
+@item @var{stream_type}[:@var{stream_index}]
+@var{stream_type} is one of following: 'v' for video, 'a' for audio,
+'s' for subtitle, 'd' for data, and 't' for attachments. If
+@var{stream_index} is given, then it matches the stream number
+@var{stream_index} of this type. Otherwise, it matches all streams of
+this type.
+
+@item p:@var{program_id}[:@var{stream_index}]
+If @var{stream_index} is given, then it matches the stream with number
+@var{stream_index} in the program with the id
+@var{program_id}. Otherwise, it matches all streams in the program.
+
+@item #@var{stream_id}
+Matches the stream by a format-specific ID.
+@end table
+
+The exact semantics of stream specifiers is defined by the
+@code{avformat_match_stream_specifier()} function declared in the
+@file{libavformat/avformat.h} header.
+
+@ifclear config-writeonly
+@include demuxers.texi
+@end ifclear
+@ifclear config-readonly
+@include muxers.texi
+@end ifclear
+@include metadata.texi
diff --git a/doc/general.texi b/doc/general.texi
index ab8673a1c9..ba79503d3f 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -1,4 +1,5 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
@settitle General Documentation
@titlepage
@@ -11,12 +12,20 @@
@chapter External libraries
-Libav can be hooked up with a number of external libraries to add support
+FFmpeg can be hooked up with a number of external libraries to add support
for more formats. None of them are used by default, their use has to be
explicitly requested by passing the appropriate flags to
@command{./configure}.
-@section OpenCORE and VisualOn libraries
+@section OpenJPEG
+
+FFmpeg can use the OpenJPEG libraries for encoding/decoding J2K videos. Go to
+@url{http://www.openjpeg.org/} to get the libraries and follow the installation
+instructions. To enable using OpenJPEG in FFmpeg, pass @code{--enable-libopenjpeg} to
+@file{./configure}.
+
+
+@section OpenCORE, VisualOn, and Fraunhofer libraries
Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer
libraries provide encoders for a number of audio codecs.
@@ -24,14 +33,19 @@ libraries provide encoders for a number of audio codecs.
@float NOTE
OpenCORE and VisualOn libraries are under the Apache License 2.0
(see @url{http://www.apache.org/licenses/LICENSE-2.0} for details), which is
-incompatible with the LGPL version 2.1 and GPL version 2. You have to
-upgrade Libav's license to LGPL version 3 (or if you have enabled
-GPL components, GPL version 3) to use it.
+incompatible to the LGPL version 2.1 and GPL version 2. You have to
+upgrade FFmpeg's license to LGPL version 3 (or if you have enabled
+GPL components, GPL version 3) by passing @code{--enable-version3} to configure in
+order to use it.
+
+The Fraunhofer AAC library is licensed under a license incompatible to the GPL
+and is not known to be compatible to the LGPL. Therefore, you have to pass
+@code{--enable-nonfree} to configure to use it.
@end float
@subsection OpenCORE AMR
-Libav can make use of the OpenCORE libraries for AMR-NB
+FFmpeg can make use of the OpenCORE libraries for AMR-NB
decoding/encoding and AMR-WB decoding.
Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the
@@ -41,7 +55,7 @@ Then pass @code{--enable-libopencore-amrnb} and/or
@subsection VisualOn AAC encoder library
-Libav can make use of the VisualOn AACenc library for AAC encoding.
+FFmpeg can make use of the VisualOn AACenc library for AAC encoding.
Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the
instructions for installing the library.
@@ -49,7 +63,7 @@ Then pass @code{--enable-libvo-aacenc} to configure to enable it.
@subsection VisualOn AMR-WB encoder library
-Libav can make use of the VisualOn AMR-WBenc library for AMR-WB encoding.
+FFmpeg can make use of the VisualOn AMR-WBenc library for AMR-WB encoding.
Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the
instructions for installing the library.
@@ -57,7 +71,7 @@ Then pass @code{--enable-libvo-amrwbenc} to configure to enable it.
@subsection Fraunhofer AAC library
-Libav can make use of the Fraunhofer AAC library for AAC encoding.
+FFmpeg can make use of the Fraunhofer AAC library for AAC encoding.
Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the
instructions for installing the library.
@@ -65,7 +79,7 @@ Then pass @code{--enable-libfdk-aac} to configure to enable it.
@section LAME
-Libav can make use of the LAME library for MP3 encoding.
+FFmpeg can make use of the LAME library for MP3 encoding.
Go to @url{http://lame.sourceforge.net/} and follow the
instructions for installing the library.
@@ -73,7 +87,7 @@ Then pass @code{--enable-libmp3lame} to configure to enable it.
@section TwoLAME
-Libav can make use of the TwoLAME library for MP2 encoding.
+FFmpeg can make use of the TwoLAME library for MP2 encoding.
Go to @url{http://www.twolame.org/} and follow the
instructions for installing the library.
@@ -81,7 +95,7 @@ Then pass @code{--enable-libtwolame} to configure to enable it.
@section libvpx
-Libav can make use of the libvpx library for VP8 encoding.
+FFmpeg can make use of the libvpx library for VP8/VP9 encoding.
Go to @url{http://www.webmproject.org/} and follow the instructions for
installing the library. Then pass @code{--enable-libvpx} to configure to
@@ -89,7 +103,7 @@ enable it.
@section libwavpack
-Libav can make use of the libwavpack library for WavPack encoding.
+FFmpeg can make use of the libwavpack library for WavPack encoding.
Go to @url{http://www.wavpack.com/} and follow the instructions for
installing the library. Then pass @code{--enable-libwavpack} to configure to
@@ -97,7 +111,7 @@ enable it.
@section OpenH264
-Libav can make use of the OpenH264 library for H.264 encoding.
+FFmpeg can make use of the OpenH264 library for H.264 encoding.
Go to @url{http://www.openh264.org/} and follow the instructions for
installing the library. Then pass @code{--enable-libopenh264} to configure to
@@ -105,7 +119,7 @@ enable it.
@section x264
-Libav can make use of the x264 library for H.264 encoding.
+FFmpeg can make use of the x264 library for H.264 encoding.
Go to @url{http://www.videolan.org/developers/x264.html} and follow the
instructions for installing the library. Then pass @code{--enable-libx264} to
@@ -114,80 +128,78 @@ configure to enable it.
@float NOTE
x264 is under the GNU Public License Version 2 or later
(see @url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html} for
-details), you must upgrade Libav's license to GPL in order to use it.
+details), you must upgrade FFmpeg's license to GPL in order to use it.
@end float
@section x265
-Libav can make use of the x265 library for HEVC encoding.
+FFmpeg can make use of the x265 library for HEVC encoding.
Go to @url{http://x265.org/developers.html} and follow the instructions
for installing the library. Then pass @code{--enable-libx265} to configure
to enable it.
-@float note
+@float NOTE
x265 is under the GNU Public License Version 2 or later
(see @url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html} for
-details), you must upgrade Libav's license to GPL in order to use it.
+details), you must upgrade FFmpeg's license to GPL in order to use it.
@end float
@section libilbc
iLBC is a narrowband speech codec that has been made freely available
by Google as part of the WebRTC project. libilbc is a packaging friendly
-copy of the iLBC codec. Libav can make use of the libilbc library for
+copy of the iLBC codec. FFmpeg can make use of the libilbc library for
iLBC encoding and decoding.
-Go to @url{https://github.com/dekkers/libilbc} and follow the instructions for
+Go to @url{https://github.com/TimothyGu/libilbc} and follow the instructions for
installing the library. Then pass @code{--enable-libilbc} to configure to
enable it.
+@section libzvbi
+
+libzvbi is a VBI decoding library which can be used by FFmpeg to decode DVB
+teletext pages and DVB teletext subtitles.
+
+Go to @url{http://sourceforge.net/projects/zapping/} and follow the instructions for
+installing the library. Then pass @code{--enable-libzvbi} to configure to
+enable it.
+
+@float NOTE
+libzvbi is licensed under the GNU General Public License Version 2 or later
+(see @url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html} for details),
+you must upgrade FFmpeg's license to GPL in order to use it.
+@end float
+
@section AviSynth
-Libav can read AviSynth scripts as input. To enable support you need a
-suitable @file{avisynth_c.h} header to compile against. The header as
-provided by AviSynth+ is fully compatible. AviSynth 2.5 is not supported
-by Libav. Once you have the appropriate header, pass
-@code{--enable-avisynth} to configure to enable AviSynth support.
+FFmpeg can read AviSynth scripts as input. To enable support, pass
+@code{--enable-avisynth} to configure. The correct headers are
+included in compat/avisynth/, which allows the user to enable support
+without needing to search for these headers themselves.
For Windows, supported AviSynth variants are
@url{http://avisynth.nl, AviSynth 2.6 RC1 or higher} for 32-bit builds and
@url{http://avs-plus.net, AviSynth+ r1718 or higher} for 32-bit and 64-bit builds.
-@url{https://github.com/AviSynth/AviSynthPlus, AviSynth+'s git repository}
-provides a GNU-style Makefile which can install just the headers using
-@code{make install PREFIX=/install/prefix}.
-
-@float NOTE
-When using AviSynth+'s installed headers, the user must also pass
-the avisynth/ include directory to @code{--extra-cflags}. For example,
-if the PREFIX given to AviSynth+'s Makefile was /usr/i686-w64-mingw32,
-then the correct command would be
-@code{--extra-cflags="-I/usr/i686-w64-mingw32/include/avisynth"}.
-@end float
For Linux and OS X, the supported AviSynth variant is
@url{https://github.com/avxsynth/avxsynth, AvxSynth}.
-@file{avxsynth_c.h} is installed as part of the normal
-build routine, as illustrated on
-@url{https://github.com/avxsynth/avxsynth/wiki/System-Setup, AvxSynth's wiki}.
-(the instructions for compiling its prerequisites are outdated, as FFMS 2.18
-or higher is now needed; the list of dependencies to be downloaded from the
-repositories is still the same, though).
@float NOTE
-AviSynth and AvxSynth are loaded dynamically. Distributors can build Libav
+AviSynth and AvxSynth are loaded dynamically. Distributors can build FFmpeg
with @code{--enable-avisynth}, and the binaries will work regardless of the
end user having AviSynth or AvxSynth installed - they'll only need to be
installed to use AviSynth scripts (obviously).
@end float
-@chapter Supported File Formats and Codecs
+
+@chapter Supported File Formats, Codecs or Features
You can use the @code{-formats} and @code{-codecs} options to have an exhaustive list.
@section File Formats
-Libav supports the following file formats through the @code{libavformat}
+FFmpeg supports the following file formats through the @code{libavformat}
library:
@multitable @columnfractions .4 .1 .1 .4
@@ -195,6 +207,8 @@ library:
@item 4xm @tab @tab X
@tab 4X Technologies format, used in some games.
@item 8088flex TMV @tab @tab X
+@item ACT Voice @tab @tab X
+ @tab contains G.729 audio
@item Adobe Filmstrip @tab X @tab X
@item Audio IFF (AIFF) @tab X @tab X
@item American Laser Games MM @tab @tab X
@@ -203,21 +217,34 @@ library:
@item Amazing Studio Packed Animation File @tab @tab X
@tab Multimedia format used in game Heart Of Darkness.
@item Apple HTTP Live Streaming @tab @tab X
+@item Artworx Data Format @tab @tab X
+@item ADP @tab @tab X
+ @tab Audio format used on the Nintendo Gamecube.
+@item AFC @tab @tab X
+ @tab Audio format used on the Nintendo Gamecube.
+@item APNG @tab X @tab X
@item ASF @tab X @tab X
+@item AST @tab X @tab X
+ @tab Audio format used on the Nintendo Wii.
@item AVI @tab X @tab X
@item AviSynth @tab @tab X
+@item AVR @tab @tab X
+ @tab Audio format used on Mac.
@item AVS @tab @tab X
@tab Multimedia format used by the Creature Shock game.
@item Beam Software SIFF @tab @tab X
@tab Audio and video format used in some games by Beam Software.
@item Bethesda Softworks VID @tab @tab X
@tab Used in some games from Bethesda Softworks.
+@item Binary text @tab @tab X
@item Bink @tab @tab X
@tab Multimedia format used by many games.
@item Bitmap Brothers JV @tab @tab X
@tab Used in Z and Z95 games.
@item Brute Force & Ignorance @tab @tab X
@tab Used in the game Flash Traffic: City of Angels.
+@item BRSTM @tab @tab X
+ @tab Audio format used on the Nintendo Wii.
@item BWF @tab X @tab X
@item CRI ADX @tab X @tab X
@tab Audio-only format used in console video games.
@@ -232,9 +259,10 @@ library:
@item Canopus HQX @tab @tab X
@item CD+G @tab @tab X
@tab Video format used by CD+G karaoke disks
+@item Phantom Cine @tab @tab X
@item Commodore CDXL @tab @tab X
@tab Amiga CD video format
-@item Core Audio Format @tab @tab X
+@item Core Audio Format @tab X @tab X
@tab Apple Core Audio Format
@item CRC testing format @tab X @tab
@item Creative Voice @tab X @tab X
@@ -245,6 +273,7 @@ library:
@item Deluxe Paint Animation @tab @tab X
@item DFA @tab @tab X
@tab This format is used in Chronomaster game
+@item DSD Stream File (DSF) @tab @tab X
@item DV video @tab X @tab X
@item DXA @tab @tab X
@tab This format is used in the non-Windows version of the Feeble Files
@@ -252,6 +281,8 @@ library:
@item Electronic Arts cdata @tab @tab X
@item Electronic Arts Multimedia @tab @tab X
@tab Used in various EA games; files have extensions like WVE and UV2.
+@item Ensoniq Paris Audio File @tab @tab X
+@item FFM (FFserver live feed) @tab X @tab X
@item Flash (SWF) @tab X @tab X
@item Flash 9 (AVM2) @tab X @tab X
@tab Only embedded audio is decoded.
@@ -262,15 +293,21 @@ library:
@item framecrc testing format @tab X @tab
@item FunCom ISS @tab @tab X
@tab Audio format used in various games from FunCom like The Longest Journey.
-@item GIF Animation @tab X @tab
+@item G.723.1 @tab X @tab X
+@item G.729 BIT @tab X @tab X
+@item G.729 raw @tab @tab X
+@item GIF Animation @tab X @tab X
@item GXF @tab X @tab X
@tab General eXchange Format SMPTE 360M, used by Thomson Grass Valley
playout servers.
@item HNM @tab @tab X
@tab Only version 4 supported, used in some games from Cryo Interactive
+@item iCEDraw File @tab @tab X
+@item ICO @tab X @tab X
+ @tab Microsoft Windows ICO
@item id Quake II CIN video @tab @tab X
@item id RoQ @tab X @tab X
- @tab Used in Quake III, Jedi Knight 2, other computer games.
+ @tab Used in Quake III, Jedi Knight 2 and other computer games.
@item IEC61937 encapsulation @tab X @tab X
@item IFF @tab @tab X
@tab Interchange File Format
@@ -281,11 +318,17 @@ library:
@tab A format generated by IndigoVision 8000 video server.
@item IVF (On2) @tab X @tab X
@tab A format used by libvpx
+@item IRCAM @tab X @tab X
@item LATM @tab X @tab X
@item LMLM4 @tab @tab X
@tab Used by Linux Media Labs MPEG-4 PCI boards
+@item LOAS @tab @tab X
+ @tab contains LATM multiplexed AAC audio
+@item LRC @tab X @tab X
+@item LVF @tab @tab X
@item LXF @tab @tab X
@tab VR native stream format, used by Leitch/Harris' video servers.
+@item Magic Lantern Video (MLV) @tab @tab X
@item Matroska @tab X @tab X
@item Matroska audio @tab X @tab
@item FFmpeg metadata @tab X @tab X
@@ -293,6 +336,9 @@ library:
@item MAXIS XA @tab @tab X
@tab Used in Sim City 3000; file extension .xa.
@item MD Studio @tab @tab X
+@item Metal Gear Solid: The Twin Snakes @tab @tab X
+@item Megalux Frame @tab @tab X
+ @tab Used by Megalux Ultimate Paint
@item Mobotix .mxg @tab @tab X
@item Monkey's Audio @tab @tab X
@item Motion Pixels MVI @tab @tab X
@@ -322,6 +368,7 @@ library:
@tab SMPTE 386M, D-10/IMX Mapping.
@item NC camera feed @tab @tab X
@tab NC (AVIP NC4600) camera streams
+@item NIST SPeech HEader REsources @tab @tab X
@item NTT TwinVQ (VQF) @tab @tab X
@tab Nippon Telegraph and Telephone Corporation TwinVQ.
@item Nullsoft Streaming Video @tab @tab X
@@ -330,6 +377,7 @@ library:
@tab NUT Open Container Format
@item Ogg @tab X @tab X
@item Playstation Portable PMP @tab @tab X
+@item Portable Voice Format @tab @tab X
@item TechnoTrend PVA @tab @tab X
@tab Used by TechnoTrend DVB PCI boards.
@item QCP @tab @tab X
@@ -340,6 +388,7 @@ library:
@item raw Dirac @tab X @tab X
@item raw DNxHD @tab X @tab X
@item raw DTS @tab X @tab X
+@item raw DTS-HD @tab @tab X
@item raw E-AC-3 @tab X @tab X
@item raw FLAC @tab X @tab X
@item raw GSM @tab @tab X
@@ -360,7 +409,7 @@ library:
@item raw Shorten @tab @tab X
@item raw TAK @tab @tab X
@item raw TrueHD @tab X @tab X
-@item raw VC-1 @tab @tab X
+@item raw VC-1 @tab X @tab X
@item raw PCM A-law @tab X @tab X
@item raw PCM mu-law @tab X @tab X
@item raw PCM signed 8 bit @tab X @tab X
@@ -386,16 +435,19 @@ library:
@tab File format used by RED Digital cameras, contains JPEG 2000 frames and PCM audio.
@item RealMedia @tab X @tab X
@item Redirector @tab @tab X
+@item RedSpark @tab @tab X
@item Renderware TeXture Dictionary @tab @tab X
@item RL2 @tab @tab X
@tab Audio and video format used in some games by Entertainment Software Partners.
@item RPL/ARMovie @tab @tab X
@item Lego Mindstorms RSO @tab X @tab X
+@item RSD @tab @tab X
@item RTMP @tab X @tab X
@tab Output is performed by publishing stream to RTMP server
@item RTP @tab X @tab X
@item RTSP @tab X @tab X
@item SAP @tab X @tab X
+@item SBG @tab @tab X
@item SDP @tab @tab X
@item Sega FILM/CPK @tab @tab X
@tab Used in many Sega Saturn console games.
@@ -408,14 +460,15 @@ library:
@tab Multimedia format used by many games.
@item SMJPEG @tab X @tab X
@tab Used in certain Loki game ports.
-@item Smush
+@item Smush @tab @tab X
@tab Multimedia format used in some LucasArts games.
@item Sony OpenMG (OMA) @tab X @tab X
@tab Audio format used in Sony Sonic Stage and Sony Vegas.
@item Sony PlayStation STR @tab @tab X
-@item Sony Wave64 (W64) @tab @tab X
+@item Sony Wave64 (W64) @tab X @tab X
@item SoX native format @tab X @tab X
@item SUN AU format @tab X @tab X
+@item SUP raw PGS subtitles @tab @tab X
@item TDSC @tab @tab X
@item Text files @tab @tab X
@item THP @tab @tab X
@@ -424,10 +477,11 @@ library:
@tab Tiertex .seq files used in the DOS CD-ROM version of the game Flashback.
@item True Audio @tab @tab X
@item VC-1 test bitstream @tab X @tab X
+@item Vivo @tab @tab X
@item WAV @tab X @tab X
-@item WavPack @tab @tab X
+@item WavPack @tab X @tab X
@item WebM @tab X @tab X
-@item Windows Televison (WTV) @tab @tab X
+@item Windows Televison (WTV) @tab X @tab X
@item Wing Commander III movie @tab @tab X
@tab Multimedia format used in Origin's Wing Commander III computer game.
@item Westwood Studios audio @tab @tab X
@@ -438,16 +492,16 @@ library:
@tab Microsoft video container used in Xbox games.
@item xWMA @tab @tab X
@tab Microsoft audio container used by XAudio 2.
+@item eXtended BINary text (XBIN) @tab @tab X
@item YUV4MPEG pipe @tab X @tab X
@item Psygnosis YOP @tab @tab X
-@item ZeroCodec Lossless Video @tab @tab X
@end multitable
@code{X} means that encoding (resp. decoding) is supported.
@section Image Formats
-Libav can read and write images for each frame of a video sequence. The
+FFmpeg can read and write images for each frame of a video sequence. The
following image formats are supported:
@multitable @columnfractions .4 .1 .1 .4
@@ -457,7 +511,7 @@ following image formats are supported:
@item Alias PIX @tab X @tab X
@tab Alias/Wavefront PIX image format
@item animated GIF @tab X @tab X
- @tab Only uncompressed GIFs are generated.
+@item APNG @tab X @tab X
@item BMP @tab X @tab X
@tab Microsoft BMP image
@item BRender PIX @tab @tab X
@@ -468,8 +522,7 @@ following image formats are supported:
@tab OpenEXR
@item JPEG @tab X @tab X
@tab Progressive JPEG is not supported.
-@item JPEG 2000 @tab E @tab X
- @tab encoding supported through external library libopenjpeg
+@item JPEG 2000 @tab X @tab X
@item JPEG-LS @tab X @tab X
@item LJPEG @tab X @tab
@tab Lossless JPEG
@@ -486,7 +539,6 @@ following image formats are supported:
@item PIC @tab @tab X
@tab Pictor/PC Paint
@item PNG @tab X @tab X
- @tab 2/4 bpp not supported yet
@item PPM @tab X @tab X
@tab Portable PixelMap image
@item PTX @tab @tab X
@@ -503,6 +555,8 @@ following image formats are supported:
@tab WebP image format, encoding supported through external library libwebp
@item XBM @tab X @tab X
@tab X BitMap image format
+@item XFace @tab X @tab X
+ @tab X-Face image format
@item XWD @tab X @tab X
@tab X Window Dump image format
@end multitable
@@ -518,14 +572,12 @@ following image formats are supported:
@item 4X Movie @tab @tab X
@tab Used in certain computer games.
@item 8088flex TMV @tab @tab X
-@item 8SVX exponential @tab @tab X
-@item 8SVX fibonacci @tab @tab X
@item A64 multicolor @tab X @tab
@tab Creates video suitable to be played on a commodore 64 (multicolor mode).
@item Amazing Studio PAF Video @tab @tab X
@item American Laser Games MM @tab @tab X
@tab Used in games like Mad Dog McCree.
-@item AMV Video @tab @tab X
+@item AMV Video @tab X @tab X
@tab Used in Chinese MP3 players.
@item ANSI/ASCII art @tab @tab X
@item Apple Intermediate Codec @tab @tab X
@@ -546,13 +598,18 @@ following image formats are supported:
@item Autodesk Animator Flic video @tab @tab X
@item Autodesk RLE @tab @tab X
@tab fourcc: AASC
+@item Avid 1:1 10-bit RGB Packer @tab X @tab X
+ @tab fourcc: AVrp
@item AVS (Audio Video Standard) video @tab @tab X
@tab Video encoding used by the Creature Shock game.
+@item AYUV @tab X @tab X
+ @tab Microsoft uncompressed packed 4:4:4:4
@item Beam Software VB @tab @tab X
@item Bethesda VID video @tab @tab X
@tab Used in some games from Bethesda Softworks.
@item Bink Video @tab @tab X
@item Bitmap Brothers JV video @tab @tab X
+@item y41p Brooktree uncompressed 4:1:1 12-bit @tab X @tab X
@item Brute Force & Ignorance @tab @tab X
@tab Used in the game Flash Traffic: City of Angels.
@item C93 video @tab @tab X
@@ -572,10 +629,11 @@ following image formats are supported:
@item Cinepak @tab @tab X
@item Cirrus Logic AccuPak @tab X @tab X
@tab fourcc: CLJR
+@item CPiA Video Format @tab @tab X
@item Creative YUV (CYUV) @tab @tab X
@item DFA @tab @tab X
@tab Codec used in Chronomaster game.
-@item Dirac @tab E @tab E
+@item Dirac @tab E @tab X
@tab supported through external library libschroedinger
@item Deluxe Paint Animation @tab @tab X
@item DNxHD @tab X @tab X
@@ -597,10 +655,10 @@ following image formats are supported:
@item Escape 124 @tab @tab X
@item Escape 130 @tab @tab X
@item FFmpeg video codec #1 @tab X @tab X
- @tab experimental lossless codec (fourcc: FFV1)
+ @tab lossless codec (fourcc: FFV1)
@item Flash Screen Video v1 @tab X @tab X
@tab fourcc: FSV1
-@item Flash Screen Video v2 @tab @tab X
+@item Flash Screen Video v2 @tab X @tab X
@item Flash Video (FLV) @tab X @tab X
@tab Sorenson H.263 used in Flash
@item Forward Uncompressed @tab @tab X
@@ -636,6 +694,7 @@ following image formats are supported:
@tab Used in the game Cyberia from Interplay.
@item Interplay MVE video @tab @tab X
@tab Used in Interplay .MVE files.
+@item J2K @tab X @tab X
@item Karl Morton's video codec @tab @tab X
@tab Codec used in Worms games.
@item Kega Game Video (KGV1) @tab @tab X
@@ -644,8 +703,8 @@ following image formats are supported:
@item LCL (LossLess Codec Library) MSZH @tab @tab X
@item LCL (LossLess Codec Library) ZLIB @tab E @tab E
@item LOCO @tab @tab X
-@item LucasArts SANM @tab @tab X
- @tab Used in LucasArts SMUSH animations.
+@item LucasArts SANM/Smush @tab @tab X
+ @tab Used in LucasArts games / SMUSH animations.
@item lossless MJPEG @tab X @tab X
@item Microsoft ATC Screen @tab @tab X
@tab Also known as Microsoft Screen 3.
@@ -685,9 +744,11 @@ following image formats are supported:
@item VP8 @tab E @tab X
@tab fourcc: VP80, encoding supported through external library libvpx
@item VP9 @tab E @tab X
- @tab Encoding supported through external library libvpx
-@item planar RGB @tab @tab X
- @tab fourcc: 8BPS
+ @tab encoding supported through external library libvpx
+@item Pinnacle TARGA CineWave YUV16 @tab @tab X
+ @tab fourcc: Y216
+@item Prores @tab @tab X
+ @tab fourcc: apch,apcn,apcs,apco
@item Q-team QPEG @tab @tab X
@tab fourccs: QPEG, Q1.0, Q1.1
@item QuickTime 8BPS video @tab @tab X
@@ -697,8 +758,8 @@ following image formats are supported:
@tab fourcc: 'smc '
@item QuickTime video (RPZA) @tab @tab X
@tab fourcc: rpza
-@item R10K AJA Kona 10-bit RGB Codec @tab @tab X
-@item R210 Quicktime Uncompressed RGB 10-bit @tab @tab X
+@item R10K AJA Kona 10-bit RGB Codec @tab X @tab X
+@item R210 Quicktime Uncompressed RGB 10-bit @tab X @tab X
@item Raw Video @tab X @tab X
@item RealVideo 1.0 @tab X @tab X
@item RealVideo 2.0 @tab X @tab X
@@ -717,6 +778,8 @@ following image formats are supported:
@item Smacker video @tab @tab X
@tab Video encoding used in Smacker.
@item SMPTE VC-1 @tab @tab X
+@item Snow @tab X @tab X
+ @tab experimental wavelet codec (fourcc: SNOW)
@item Sony PlayStation MDEC (Motion DECoder) @tab @tab X
@item Sorenson Vector Quantizer 1 @tab X @tab X
@tab fourcc: SVQ1
@@ -734,6 +797,8 @@ following image formats are supported:
@tab Codec used in DOS CD-ROM FlashBack game.
@item Ut Video @tab X @tab X
@item v210 QuickTime uncompressed 4:2:2 10-bit @tab X @tab X
+@item v308 QuickTime uncompressed 4:4:4 @tab X @tab X
+@item v408 QuickTime uncompressed 4:4:4:4 @tab X @tab X
@item v410 QuickTime uncompressed 4:4:4 10-bit @tab X @tab X
@item VBLE Lossless Codec @tab @tab X
@item VMware Screen Codec / VMware Video @tab @tab X
@@ -752,6 +817,9 @@ following image formats are supported:
@item WMV7 @tab X @tab X
@item YAMAHA SMAF @tab X @tab X
@item Psygnosis YOP Video @tab @tab X
+@item yuv4 @tab X @tab X
+ @tab libquicktime uncompressed packed 4:2:0
+@item ZeroCodec Lossless Video @tab @tab X
@item ZLIB @tab X @tab X
@tab part of LCL, encoder experimental
@item Zip Motion Blocks Video @tab X @tab X
@@ -766,10 +834,13 @@ following image formats are supported:
@multitable @columnfractions .4 .1 .1 .4
@item Name @tab Encoding @tab Decoding @tab Comments
-@item 8SVX audio @tab @tab X
+@item 8SVX exponential @tab @tab X
+@item 8SVX fibonacci @tab @tab X
+@item AAC+ @tab E @tab X
+ @tab encoding supported through external library libaacplus
@item AAC @tab E @tab X
@tab encoding supported through external library libfaac and libvo-aacenc
-@item AC-3 @tab IX @tab X
+@item AC-3 @tab IX @tab IX
@item ADPCM 4X Movie @tab @tab X
@item ADPCM CDROM XA @tab @tab X
@item ADPCM Creative Technology @tab @tab X
@@ -795,19 +866,21 @@ following image formats are supported:
@item ADPCM IMA Westwood @tab @tab X
@item ADPCM ISS IMA @tab @tab X
@tab Used in FunCom games.
+@item ADPCM IMA Dialogic @tab @tab X
@item ADPCM IMA Duck DK3 @tab @tab X
@tab Used in some Sega Saturn console games.
@item ADPCM IMA Duck DK4 @tab @tab X
@tab Used in some Sega Saturn console games.
+@item ADPCM IMA Radical @tab @tab X
@item ADPCM Microsoft @tab X @tab X
@item ADPCM MS IMA @tab X @tab X
+@item ADPCM Nintendo Gamecube AFC @tab @tab X
+@item ADPCM Nintendo Gamecube DTK @tab @tab X
@item ADPCM Nintendo Gamecube THP @tab @tab X
@item ADPCM QT IMA @tab X @tab X
@item ADPCM SEGA CRI ADX @tab X @tab X
@tab Used in Sega Dreamcast games.
@item ADPCM Shockwave Flash @tab X @tab X
-@item ADPCM SMJPEG IMA @tab @tab X
- @tab Used in certain Loki game ports.
@item ADPCM Sound Blaster Pro 2-bit @tab @tab X
@item ADPCM Sound Blaster Pro 2.6-bit @tab @tab X
@item ADPCM Sound Blaster Pro 4-bit @tab @tab X
@@ -828,16 +901,18 @@ following image formats are supported:
@item ATRAC3+ @tab @tab X
@item Bink Audio @tab @tab X
@tab Used in Bink and Smacker files in many games.
+@item CELT @tab @tab E
+ @tab decoding supported through external library libcelt
@item Delphine Software International CIN audio @tab @tab X
@tab Codec used in Delphine Software International games.
@item Digital Speech Standard - Standard Play mode (DSS SP) @tab @tab X
@item Discworld II BMV Audio @tab @tab X
@item COOK @tab @tab X
@tab All versions except 5.1 are supported.
-@item DCA (DTS Coherent Acoustics) @tab @tab X
+@item DCA (DTS Coherent Acoustics) @tab X @tab X
@tab supported extensions: XCh, XLL (partially)
@item DPCM id RoQ @tab X @tab X
- @tab Used in Quake III, Jedi Knight 2, other computer games.
+ @tab Used in Quake III, Jedi Knight 2 and other computer games.
@item DPCM Interplay @tab @tab X
@tab Used in various Interplay computer games.
@item DPCM Sierra Online @tab @tab X
@@ -845,11 +920,17 @@ following image formats are supported:
@item DPCM Sol @tab @tab X
@item DPCM Xan @tab @tab X
@tab Used in Origin's Wing Commander IV AVI files.
+@item DSD (Direct Stream Digitial), least significant bit first @tab @tab X
+@item DSD (Direct Stream Digitial), most significant bit first @tab @tab X
+@item DSD (Direct Stream Digitial), least significant bit first, planar @tab @tab X
+@item DSD (Direct Stream Digitial), most significant bit first, planar @tab @tab X
@item DSP Group TrueSpeech @tab @tab X
@item DV audio @tab @tab X
@item Enhanced AC-3 @tab X @tab X
+@item EVRC (Enhanced Variable Rate Codec) @tab @tab X
@item FLAC (Free Lossless Audio Codec) @tab X @tab IX
-@item G.723.1 @tab @tab X
+@item G.723.1 @tab X @tab X
+@item G.729 @tab @tab X
@item GSM @tab E @tab X
@tab encoding supported through external library libgsm
@item GSM Microsoft variant @tab E @tab X
@@ -863,9 +944,8 @@ following image formats are supported:
@item MLP (Meridian Lossless Packing) @tab @tab X
@tab Used in DVD-Audio discs.
@item Monkey's Audio @tab @tab X
- @tab Only versions 3.97-3.99 are supported.
@item MP1 (MPEG audio layer 1) @tab @tab IX
-@item MP2 (MPEG audio layer 2) @tab IE @tab IX
+@item MP2 (MPEG audio layer 2) @tab IX @tab IX
@tab encoding supported also through external library TwoLAME
@item MP3 (MPEG audio layer 3) @tab E @tab IX
@tab encoding supported through external library LAME, ADU MP3 and MP3onMP4 also supported
@@ -878,9 +958,11 @@ following image formats are supported:
@tab supported through external library libopus
@item PCM A-law @tab X @tab X
@item PCM mu-law @tab X @tab X
-@item PCM signed 16-bit little-endian planar @tab @tab X
-@item PCM signed 24-bit little-endian planar @tab @tab X
-@item PCM signed 32-bit little-endian planar @tab @tab X
+@item PCM signed 8-bit planar @tab X @tab X
+@item PCM signed 16-bit big-endian planar @tab X @tab X
+@item PCM signed 16-bit little-endian planar @tab X @tab X
+@item PCM signed 24-bit little-endian planar @tab X @tab X
+@item PCM signed 32-bit little-endian planar @tab X @tab X
@item PCM 32-bit floating point big-endian @tab X @tab X
@item PCM 32-bit floating point little-endian @tab X @tab X
@item PCM 64-bit floating point big-endian @tab X @tab X
@@ -917,19 +999,24 @@ following image formats are supported:
@item Sierra VMD audio @tab @tab X
@tab Used in Sierra VMD files.
@item Smacker audio @tab @tab X
-@item SMPTE 302M AES3 audio @tab @tab X
+@item SMPTE 302M AES3 audio @tab X @tab X
+@item Sonic @tab X @tab X
+ @tab experimental codec
+@item Sonic lossless @tab X @tab X
+ @tab experimental codec
@item Speex @tab E @tab E
@tab supported through external library libspeex
@item TAK (Tom's lossless Audio Kompressor) @tab @tab X
-@item True Audio (TTA) @tab @tab X
+@item True Audio (TTA) @tab X @tab X
@item TrueHD @tab @tab X
@tab Used in HD-DVD and Blu-Ray discs.
@item TwinVQ (VQF flavor) @tab @tab X
+@item VIMA @tab @tab X
+ @tab Used in LucasArts SMUSH animations.
@item Vorbis @tab E @tab X
@tab A native but very primitive encoder exists.
@item Voxware MetaSound @tab @tab X
-@item WavPack @tab E @tab X
- @tab supported through external library libwavpack
+@item WavPack @tab X @tab X
@item Westwood Audio (SND1) @tab @tab X
@item Windows Media Audio 1 @tab X @tab X
@item Windows Media Audio 2 @tab X @tab X
@@ -949,21 +1036,41 @@ performance on systems without hardware floating point support).
@multitable @columnfractions .4 .1 .1 .1 .1
@item Name @tab Muxing @tab Demuxing @tab Encoding @tab Decoding
-@item SSA/ASS @tab X @tab X @tab X @tab X
-@item DVB @tab X @tab X @tab X @tab X
-@item DVD @tab X @tab X @tab X @tab X
-@item PGS @tab @tab @tab @tab X
-@item SubRip (SRT) @tab X @tab X @tab @tab X
-@item XSUB @tab @tab @tab X @tab X
+@item 3GPP Timed Text @tab @tab @tab X @tab X
+@item AQTitle @tab @tab X @tab @tab X
+@item DVB @tab X @tab X @tab X @tab X
+@item DVB teletext @tab @tab X @tab @tab E
+@item DVD @tab X @tab X @tab X @tab X
+@item JACOsub @tab X @tab X @tab @tab X
+@item MicroDVD @tab X @tab X @tab @tab X
+@item MPL2 @tab @tab X @tab @tab X
+@item MPsub (MPlayer) @tab @tab X @tab @tab X
+@item PGS @tab @tab @tab @tab X
+@item PJS (Phoenix) @tab @tab X @tab @tab X
+@item RealText @tab @tab X @tab @tab X
+@item SAMI @tab @tab X @tab @tab X
+@item Spruce format (STL) @tab @tab X @tab @tab X
+@item SSA/ASS @tab X @tab X @tab X @tab X
+@item SubRip (SRT) @tab X @tab X @tab X @tab X
+@item SubViewer v1 @tab @tab X @tab @tab X
+@item SubViewer @tab @tab X @tab @tab X
+@item TED Talks captions @tab @tab X @tab @tab X
+@item VobSub (IDX+SUB) @tab @tab X @tab @tab X
+@item VPlayer @tab @tab X @tab @tab X
+@item WebVTT @tab X @tab X @tab X @tab X
+@item XSUB @tab @tab @tab X @tab X
@end multitable
@code{X} means that the feature is supported.
+@code{E} means that support is provided through an external library.
+
@section Network Protocols
@multitable @columnfractions .4 .1
@item Name @tab Support
@item file @tab X
+@item FTP @tab X
@item Gopher @tab X
@item HLS @tab X
@item HTTP @tab X
@@ -979,7 +1086,9 @@ performance on systems without hardware floating point support).
@item RTMPTE @tab X
@item RTMPTS @tab X
@item RTP @tab X
+@item SAMBA @tab E
@item SCTP @tab X
+@item SFTP @tab E
@item TCP @tab X
@item TLS @tab X
@item UDP @tab X
@@ -996,18 +1105,36 @@ performance on systems without hardware floating point support).
@item Name @tab Input @tab Output
@item ALSA @tab X @tab X
@item BKTR @tab X @tab
+@item caca @tab @tab X
@item DV1394 @tab X @tab
-@item Linux framebuffer @tab X @tab
+@item Lavfi virtual device @tab X @tab
+@item Linux framebuffer @tab X @tab X
@item JACK @tab X @tab
@item LIBCDIO @tab X
@item LIBDC1394 @tab X @tab
+@item OpenAL @tab X
+@item OpenGL @tab @tab X
@item OSS @tab X @tab X
-@item Pulseaudio @tab X @tab
-@item Video4Linux2 @tab X @tab
+@item PulseAudio @tab X @tab X
+@item SDL @tab @tab X
+@item Video4Linux2 @tab X @tab X
@item VfW capture @tab X @tab
@item X11 grabbing @tab X @tab
+@item Win32 grabbing @tab X @tab
@end multitable
@code{X} means that input/output is supported.
+@section Timecode
+
+@multitable @columnfractions .4 .1 .1
+@item Codec/format @tab Read @tab Write
+@item AVI @tab X @tab X
+@item DV @tab X @tab X
+@item GXF @tab X @tab X
+@item MOV @tab X @tab X
+@item MPEG1/2 @tab X @tab X
+@item MXF @tab X @tab X
+@end multitable
+
@bye
diff --git a/doc/git-howto.texi b/doc/git-howto.texi
index 5a8e2a3823..b7b5d43480 100644
--- a/doc/git-howto.texi
+++ b/doc/git-howto.texi
@@ -1,9 +1,10 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
-@settitle Using git to develop Libav
+@settitle Using git to develop FFmpeg
@titlepage
-@center @titlefont{Using git to develop Libav}
+@center @titlefont{Using git to develop FFmpeg}
@end titlepage
@top
@@ -39,7 +40,7 @@ For more information about the Git project, visit the
Consult these resources whenever you have problems, they are quite exhaustive.
-What follows now is a basic introduction to Git and some Libav-specific
+What follows now is a basic introduction to Git and some FFmpeg-specific
guidelines to ease the contribution to the project
@chapter Basics Usage
@@ -53,16 +54,16 @@ Most distribution and operating system provide a package for it.
@section Cloning the source tree
@example
-git clone git://git.libav.org/libav.git <target>
+git clone git://source.ffmpeg.org/ffmpeg <target>
@end example
-This will put the Libav sources into the directory @var{<target>}.
+This will put the FFmpeg sources into the directory @var{<target>}.
@example
-git clone git@@git.libav.org:libav.git <target>
+git clone git@@source.ffmpeg.org:ffmpeg <target>
@end example
-This will put the Libav sources into the directory @var{<target>} and let
+This will put the FFmpeg sources into the directory @var{<target>} and let
you push back your changes to the remote repository.
Make sure that you do not have Windows line endings in your checkouts,
@@ -74,6 +75,7 @@ git config --global core.autocrlf false
@end example
+@anchor{Updating the source tree to the latest revision}
@section Updating the source tree to the latest revision
@example
@@ -85,7 +87,7 @@ can be remote. By default the master branch tracks the branch master in
the remote origin.
@float IMPORTANT
-Since merge commits are forbidden @command{--rebase} (see below) is recommended.
+@command{--rebase} (see below) is recommended.
@end float
@section Rebasing your local branches
@@ -96,7 +98,7 @@ git pull --rebase
fetches the changes from the main repository and replays your local commits
over it. This is required to keep all your local changes at the top of
-Libav's master tree. The master tree will reject pushes with merge commits.
+FFmpeg's master tree. The master tree will reject pushes with merge commits.
@section Adding/removing files/directories
@@ -127,7 +129,7 @@ git log <filename(s)>
@end example
You may also use the graphical tools like gitview or gitk or the web
-interface available at http://git.libav.org/
+interface available at http://source.ffmpeg.org/
@section Checking source tree status
@@ -261,7 +263,7 @@ git commit
@chapter Git configuration
In order to simplify a few workflows, it is advisable to configure both
-your personal Git installation and your local Libav repository.
+your personal Git installation and your local FFmpeg repository.
@section Personal Git installation
@@ -276,15 +278,15 @@ and @command{git format-patch} detect renames:
@section Repository configuration
In order to have @command{git send-email} automatically send patches
-to the libav-devel mailing list, add the following stanza
-to @file{/path/to/libav/repository/.git/config}:
+to the ffmpeg-devel mailing list, add the following stanza
+to @file{/path/to/ffmpeg/repository/.git/config}:
@example
[sendemail]
- to = libav-devel@@libav.org
+ to = ffmpeg-devel@@ffmpeg.org
@end example
-@chapter Libav specific
+@chapter FFmpeg specific
@section Reverting broken commits
@@ -299,7 +301,7 @@ the current branch history.
git commit --amend
@end example
-allows to amend the last commit details quickly.
+allows one to amend the last commit details quickly.
@example
git rebase -i origin/master
@@ -329,7 +331,7 @@ git push
Will push the changes to the default remote (@var{origin}).
Git will prevent you from pushing changes if the local and remote trees are
-out of sync. Refer to and to sync the local tree.
+out of sync. Refer to @ref{Updating the source tree to the latest revision}.
@example
git remote add <name> <url>
@@ -381,60 +383,35 @@ proper order. This list tries to be exhaustive. In case you are just
pushing a typo in a comment, some of the steps may be unnecessary.
Apply your common sense, but if in doubt, err on the side of caution.
-First make sure your Git repository is on a branch that is a direct
-descendant of the Libav master branch, which is the only one from which
-pushing to Libav is possible. Then run the following command:
+First, make sure that the commits and branches you are going to push
+match what you want pushed and that nothing is missing, extraneous or
+wrong. You can see what will be pushed by running the git push command
+with --dry-run first. And then inspecting the commits listed with
+@command{git log -p 1234567..987654}. The @command{git status} command
+may help in finding local changes that have been forgotten to be added.
-@itemize
-@item @command{git log --patch --stat origin/master..}
-
-to make sure that only the commits you want to push are pending, that
-the log messages of the commits are correct and descriptive and contain
-no cruft from @command{git am} and to doublecheck that the commits you
-want to push really only contain the changes they are supposed to contain.
-
-@item @command{git status}
-
-to ensure no local changes still need to be committed and that no local
-changes may have thrown off the results of your testing.
-@end itemize
-
-Next let the code pass through a full run of our testsuite. Before you do,
-the command @command{make fate-rsync} will update the test samples. Changes
-to the samples set are not very common and commits depending on samples
-changes are delayed for at least 24 hours to allow the new samples to
-propagate, so updating it once per day is sufficient. Now execute
+Next let the code pass through a full run of our testsuite.
@itemize
@item @command{make distclean}
-@item @command{/path/to/libav/configure}
+@item @command{/path/to/ffmpeg/configure}
@item @command{make check}
+@item if fate fails due to missing samples run @command{make fate-rsync} and retry
@end itemize
-While the test suite covers a wide range of possible problems, it is not
-a panacea. Do not hesitate to perform any other tests necessary to convince
-yourself that the changes you are about to push actually work as expected.
+Make sure all your changes have been checked before pushing them, the
+testsuite only checks against regressions and that only to some extend. It does
+obviously not check newly added features/code to be working unless you have
+added a test for that (which is recommended).
Also note that every single commit should pass the test suite, not just
-the result of a series of patches. So if you have a series of commits
-to push, run the test suite on every single commit.
-
-Give other developers a reasonable amount of time to look at and review
-patches before you push them. Not everybody is online 24/7, but may wish
-to look at and comment on a patch nonetheless. The time you leave depends
-on the urgency and complexity of the patch. Use your common sense to pick
-a timeframe that allows everybody that you think may wish to comment
-and/or should comment on the change an opportunity to see it.
-
-Finally, after pushing, mark all patches as committed on
-@url{http://patches.libav.org/,patchwork}.
-Sometimes this is not automatically done when a patch has been
-slightly modified from the version on the mailing list.
-Also update previous incarnations of the patches you push so that
-patchwork is not cluttered with cruft.
+the result of a series of patches.
+Once everything passed, push the changes to your public ffmpeg clone and post a
+merge request to ffmpeg-devel. You can also push them directly but this is not
+recommended.
@chapter Server Issues
-Contact the project admins @email{git@@libav.org} if you have technical
+Contact the project admins @email{root@@ffmpeg.org} if you have technical
problems with the GIT server.
diff --git a/doc/git-howto.txt b/doc/git-howto.txt
deleted file mode 100644
index 036b567084..0000000000
--- a/doc/git-howto.txt
+++ /dev/null
@@ -1,272 +0,0 @@
-
-About Git write access:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Before everything else, you should know how to use GIT properly.
-Luckily Git comes with excellent documentation.
-
- git --help
- man git
-
-shows you the available subcommands,
-
- git <command> --help
- man git-<command>
-
-shows information about the subcommand <command>.
-
-The most comprehensive manual is the website Git Reference
-
-http://gitref.org/
-
-For more information about the Git project, visit
-
-http://git-scm.com/
-
-Consult these resources whenever you have problems, they are quite exhaustive.
-
-You do not need a special username or password.
-All you need is to provide a ssh public key to the Git server admin.
-
-What follows now is a basic introduction to Git and some Libav-specific
-guidelines. Read it at least once, if you are granted commit privileges to the
-Libav project you are expected to be familiar with these rules.
-
-
-
-I. BASICS:
-==========
-
-0. Get GIT:
-
- You can get git from http://git-scm.com/
-
-
-1. Cloning the source tree:
-
- git clone git://git.libav.org/libav.git <target>
-
- This will put the Libav sources into the directory <target>.
-
- git clone git@git.libav.org:libav.git <target>
-
- This will put the Libav sources into the directory <target> and let
- you push back your changes to the remote repository.
-
-
-2. Updating the source tree to the latest revision:
-
- git pull (--ff-only)
-
- pulls in the latest changes from the tracked branch. The tracked branch
- can be remote. By default the master branch tracks the branch master in
- the remote origin.
- Caveat: Since merge commits are forbidden at least for the initial
- months of git --ff-only or --rebase (see below) are recommended.
- --ff-only will fail and not create merge commits if your branch
- has diverged (has a different history) from the tracked branch.
-
-2.a Rebasing your local branches:
-
- git pull --rebase
-
- fetches the changes from the main repository and replays your local commits
- over it. This is required to keep all your local changes at the top of
- Libav's master tree. The master tree will reject pushes with merge commits.
-
-
-3. Adding/removing files/directories:
-
- git add [-A] <filename/dirname>
- git rm [-r] <filename/dirname>
-
- GIT needs to get notified of all changes you make to your working
- directory that makes files appear or disappear.
- Line moves across files are automatically tracked.
-
-
-4. Showing modifications:
-
- git diff <filename(s)>
-
- will show all local modifications in your working directory as unified diff.
-
-
-5. Inspecting the changelog:
-
- git log <filename(s)>
-
- You may also use the graphical tools like gitview or gitk or the web
- interface available at http://git.libav.org/
-
-6. Checking source tree status:
-
- git status
-
- detects all the changes you made and lists what actions will be taken in case
- of a commit (additions, modifications, deletions, etc.).
-
-
-7. Committing:
-
- git diff --check
-
- to double check your changes before committing them to avoid trouble later
- on. All experienced developers do this on each and every commit, no matter
- how small.
- Every one of them has been saved from looking like a fool by this many times.
- It's very easy for stray debug output or cosmetic modifications to slip in,
- please avoid problems through this extra level of scrutiny.
-
- For cosmetics-only commits you should get (almost) empty output from
-
- git diff -w -b <filename(s)>
-
- Also check the output of
-
- git status
-
- to make sure you don't have untracked files or deletions.
-
- git add [-i|-p|-A] <filenames/dirnames>
-
- Make sure you have told git your name and email address, e.g. by running
- git config --global user.name "My Name"
- git config --global user.email my@email.invalid
- (--global to set the global configuration for all your git checkouts).
-
- Git will select the changes to the files for commit. Optionally you can use
- the interactive or the patch mode to select hunk by hunk what should be
- added to the commit.
-
- git commit
-
- Git will commit the selected changes to your current local branch.
-
- You will be prompted for a log message in an editor, which is either
- set in your personal configuration file through
-
- git config core.editor
-
- or set by one of the following environment variables:
- GIT_EDITOR, VISUAL or EDITOR.
-
- Log messages should be concise but descriptive. Explain why you made a change,
- what you did will be obvious from the changes themselves most of the time.
- Saying just "bug fix" or "10l" is bad. Remember that people of varying skill
- levels look at and educate themselves while reading through your code. Don't
- include filenames in log messages, Git provides that information.
-
- Possibly make the commit message have a terse, descriptive first line, an
- empty line and then a full description. The first line will be used to name
- the patch by git format-patch.
-
-
-8. Renaming/moving/copying files or contents of files:
-
- Git automatically tracks such changes, making those normal commits.
-
- mv/cp path/file otherpath/otherfile
-
- git add [-A] .
-
- git commit
-
- Do not move, rename or copy files of which you are not the maintainer without
- discussing it on the mailing list first!
-
-9. Reverting broken commits
-
- git revert <commit>
-
- git revert will generate a revert commit. This will not make the faulty
- commit disappear from the history.
-
- git reset <commit>
-
- git reset will uncommit the changes till <commit> rewriting the current
- branch history.
-
- git commit --amend
-
- allows to amend the last commit details quickly.
-
- git rebase -i origin/master
-
- will replay local commits over the main repository allowing to edit,
- merge or remove some of them in the process.
-
- Note that the reset, commit --amend and rebase rewrite history, so you
- should use them ONLY on your local or topic branches.
-
- The main repository will reject those changes.
-
-10. Preparing a patchset.
-
- git format-patch <commit> [-o directory]
-
- will generate a set of patches for each commit between <commit> and
- current HEAD. E.g.
-
- git format-patch origin/master
-
- will generate patches for all commits on current branch which are not
- present in upstream.
- A useful shortcut is also
-
- git format-patch -n
-
- which will generate patches from last n commits.
- By default the patches are created in the current directory.
-
-11. Sending patches for review
-
- git send-email <commit list|directory>
-
- will send the patches created by git format-patch or directly generates
- them. All the email fields can be configured in the global/local
- configuration or overridden by command line.
- Note that this tool must often be installed separately (e.g. git-email
- package on Debian-based distros).
-
-12. Pushing changes to remote trees
-
- git push
-
- Will push the changes to the default remote (origin).
- Git will prevent you from pushing changes if the local and remote trees are
- out of sync. Refer to 2 and 2.a to sync the local tree.
-
- git remote add <name> <url>
-
- Will add additional remote with a name reference, it is useful if you want
- to push your local branch for review on a remote host.
-
- git push <remote> <refspec>
-
- Will push the changes to the remote repository. Omitting refspec makes git
- push update all the remote branches matching the local ones.
-
-13. Finding a specific svn revision
-
- Since version 1.7.1 git supports ':/foo' syntax for specifying commits
- based on a regular expression. see man gitrevisions
-
- git show :/'as revision 23456'
-
- will show the svn changeset r23456. With older git versions searching in
- the git log output is the easiest option (especially if a pager with
- search capabilities is used).
- This commit can be checked out with
-
- git checkout -b svn_23456 :/'as revision 23456'
-
- or for git < 1.7.1 with
-
- git checkout -b svn_23456 $SHA1
-
- where $SHA1 is the commit SHA1 from the 'git log' output.
-
-
-Contact the project admins <git at libav dot org> if you have technical
-problems with the GIT server.
diff --git a/doc/indevs.texi b/doc/indevs.texi
index 30427905ff..d5415bbc7c 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -1,10 +1,10 @@
@chapter Input Devices
@c man begin INPUT DEVICES
-Input devices are configured elements in Libav which allow to access
+Input devices are configured elements in FFmpeg which enable accessing
the data coming from a multimedia device attached to your system.
-When you configure your Libav build, all the supported input devices
+When you configure your FFmpeg build, all the supported input devices
are enabled by default. You can list all available ones using the
configure option "--list-indevs".
@@ -13,8 +13,8 @@ You can disable all the input devices using the configure option
option "--enable-indev=@var{INDEV}", or you can disable a particular
input device using the option "--disable-indev=@var{INDEV}".
-The option "-formats" of the av* tools will display the list of
-supported input devices (amongst the demuxers).
+The option "-devices" of the ff* tools will display the list of
+supported input devices.
A description of the currently available input devices follows.
@@ -42,19 +42,389 @@ specify card number or identifier, device number and subdevice number
To see the list of cards currently recognized by your system check the
files @file{/proc/asound/cards} and @file{/proc/asound/devices}.
-For example to capture with @command{avconv} from an ALSA device with
+For example to capture with @command{ffmpeg} from an ALSA device with
card id 0, you may run the command:
@example
-avconv -f alsa -i hw:0 alsaout.wav
+ffmpeg -f alsa -i hw:0 alsaout.wav
@end example
For more information see:
@url{http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html}
+@section avfoundation
+
+AVFoundation input device.
+
+AVFoundation is the currently recommended framework by Apple for streamgrabbing on OSX >= 10.7 as well as on iOS.
+The older QTKit framework has been marked deprecated since OSX version 10.7.
+
+The input filename has to be given in the following syntax:
+@example
+-i "[[VIDEO]:[AUDIO]]"
+@end example
+The first entry selects the video input while the latter selects the audio input.
+The stream has to be specified by the device name or the device index as shown by the device list.
+Alternatively, the video and/or audio input device can be chosen by index using the
+@option{
+ -video_device_index <INDEX>
+}
+and/or
+@option{
+ -audio_device_index <INDEX>
+}
+, overriding any
+device name or index given in the input filename.
+
+All available devices can be enumerated by using @option{-list_devices true}, listing
+all device names and corresponding indices.
+
+There are two device name aliases:
+@table @code
+
+@item default
+Select the AVFoundation default device of the corresponding type.
+
+@item none
+Do not record the corresponding media type.
+This is equivalent to specifying an empty device name or index.
+
+@end table
+
+@subsection Options
+
+AVFoundation supports the following options:
+
+@table @option
+
+@item -list_devices <TRUE|FALSE>
+If set to true, a list of all available input devices is given showing all
+device names and indices.
+
+@item -video_device_index <INDEX>
+Specify the video device by its index. Overrides anything given in the input filename.
+
+@item -audio_device_index <INDEX>
+Specify the audio device by its index. Overrides anything given in the input filename.
+
+@item -pixel_format <FORMAT>
+Request the video device to use a specific pixel format.
+If the specified format is not supported, a list of available formats is given
+und the first one in this list is used instead. Available pixel formats are:
+@code{monob, rgb555be, rgb555le, rgb565be, rgb565le, rgb24, bgr24, 0rgb, bgr0, 0bgr, rgb0,
+ bgr48be, uyvy422, yuva444p, yuva444p16le, yuv444p, yuv422p16, yuv422p10, yuv444p10,
+ yuv420p, nv12, yuyv422, gray}
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Print the list of AVFoundation supported devices and exit:
+@example
+$ ffmpeg -f avfoundation -list_devices true -i ""
+@end example
+
+@item
+Record video from video device 0 and audio from audio device 0 into out.avi:
+@example
+$ ffmpeg -f avfoundation -i "0:0" out.avi
+@end example
+
+@item
+Record video from video device 2 and audio from audio device 1 into out.avi:
+@example
+$ ffmpeg -f avfoundation -video_device_index 2 -i ":1" out.avi
+@end example
+
+@item
+Record video from the system default video device using the pixel format bgr0 and do not record any audio into out.avi:
+@example
+$ ffmpeg -f avfoundation -pixel_format bgr0 -i "default:none" out.avi
+@end example
+
+@end itemize
+
@section bktr
BSD video input device.
+@section decklink
+
+The decklink input device provides capture capabilities for Blackmagic
+DeckLink devices.
+
+To enable this input device, you need the Blackmagic DeckLink SDK and you
+need to configure with the appropriate @code{--extra-cflags}
+and @code{--extra-ldflags}.
+On Windows, you need to run the IDL files through @command{widl}.
+
+DeckLink is very picky about the formats it supports. Pixel format is
+uyvy422 or v210, framerate and video size must be determined for your device with
+@command{-list_formats 1}. Audio sample rate is always 48 kHz and the number
+of channels can be 2, 8 or 16.
+
+@subsection Options
+
+@table @option
+
+@item list_devices
+If set to @option{true}, print a list of devices and exit.
+Defaults to @option{false}.
+
+@item list_formats
+If set to @option{true}, print a list of supported formats and exit.
+Defaults to @option{false}.
+
+@item bm_v210
+If set to @samp{1}, video is captured in 10 bit v210 instead
+of uyvy422. Not all Blackmagic devices support this option.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+List input devices:
+@example
+ffmpeg -f decklink -list_devices 1 -i dummy
+@end example
+
+@item
+List supported formats:
+@example
+ffmpeg -f decklink -list_formats 1 -i 'Intensity Pro'
+@end example
+
+@item
+Capture video clip at 1080i50 (format 11):
+@example
+ffmpeg -f decklink -i 'Intensity Pro@@11' -acodec copy -vcodec copy output.avi
+@end example
+
+@item
+Capture video clip at 1080i50 10 bit:
+@example
+ffmpeg -bm_v210 1 -f decklink -i 'UltraStudio Mini Recorder@@11' -acodec copy -vcodec copy output.avi
+@end example
+
+@item
+Capture video clip at 720p50 with 32bit audio:
+@example
+ffmpeg -bm_audiodepth 32 -f decklink -i 'UltraStudio Mini Recorder@@14' -acodec copy -vcodec copy output.avi
+@end example
+
+@item
+Capture video clip at 576i50 with 8 audio channels:
+@example
+ffmpeg -bm_channels 8 -f decklink -i 'UltraStudio Mini Recorder@@3' -acodec copy -vcodec copy output.avi
+@end example
+
+@end itemize
+
+@section dshow
+
+Windows DirectShow input device.
+
+DirectShow support is enabled when FFmpeg is built with the mingw-w64 project.
+Currently only audio and video devices are supported.
+
+Multiple devices may be opened as separate inputs, but they may also be
+opened on the same input, which should improve synchronism between them.
+
+The input name should be in the format:
+
+@example
+@var{TYPE}=@var{NAME}[:@var{TYPE}=@var{NAME}]
+@end example
+
+where @var{TYPE} can be either @var{audio} or @var{video},
+and @var{NAME} is the device's name or alternative name..
+
+@subsection Options
+
+If no options are specified, the device's defaults are used.
+If the device does not support the requested options, it will
+fail to open.
+
+@table @option
+
+@item video_size
+Set the video size in the captured video.
+
+@item framerate
+Set the frame rate in the captured video.
+
+@item sample_rate
+Set the sample rate (in Hz) of the captured audio.
+
+@item sample_size
+Set the sample size (in bits) of the captured audio.
+
+@item channels
+Set the number of channels in the captured audio.
+
+@item list_devices
+If set to @option{true}, print a list of devices and exit.
+
+@item list_options
+If set to @option{true}, print a list of selected device's options
+and exit.
+
+@item video_device_number
+Set video device number for devices with same name (starts at 0,
+defaults to 0).
+
+@item audio_device_number
+Set audio device number for devices with same name (starts at 0,
+defaults to 0).
+
+@item pixel_format
+Select pixel format to be used by DirectShow. This may only be set when
+the video codec is not set or set to rawvideo.
+
+@item audio_buffer_size
+Set audio device buffer size in milliseconds (which can directly
+impact latency, depending on the device).
+Defaults to using the audio device's
+default buffer size (typically some multiple of 500ms).
+Setting this value too low can degrade performance.
+See also
+@url{http://msdn.microsoft.com/en-us/library/windows/desktop/dd377582(v=vs.85).aspx}
+
+@item video_pin_name
+Select video capture pin to use by name or alternative name.
+
+@item audio_pin_name
+Select audio capture pin to use by name or alternative name.
+
+@item crossbar_video_input_pin_number
+Select video input pin number for crossbar device. This will be
+routed to the crossbar device's Video Decoder output pin.
+Note that changing this value can affect future invocations
+(sets a new default) until system reboot occurs.
+
+@item crossbar_audio_input_pin_number
+Select audio input pin number for crossbar device. This will be
+routed to the crossbar device's Audio Decoder output pin.
+Note that changing this value can affect future invocations
+(sets a new default) until system reboot occurs.
+
+@item show_video_device_dialog
+If set to @option{true}, before capture starts, popup a display dialog
+to the end user, allowing them to change video filter properties
+and configurations manually.
+Note that for crossbar devices, adjusting values in this dialog
+may be needed at times to toggle between PAL (25 fps) and NTSC (29.97)
+input frame rates, sizes, interlacing, etc. Changing these values can
+enable different scan rates/frame rates and avoiding green bars at
+the bottom, flickering scan lines, etc.
+Note that with some devices, changing these properties can also affect future
+invocations (sets new defaults) until system reboot occurs.
+
+@item show_audio_device_dialog
+If set to @option{true}, before capture starts, popup a display dialog
+to the end user, allowing them to change audio filter properties
+and configurations manually.
+
+@item show_video_crossbar_connection_dialog
+If set to @option{true}, before capture starts, popup a display
+dialog to the end user, allowing them to manually
+modify crossbar pin routings, when it opens a video device.
+
+@item show_audio_crossbar_connection_dialog
+If set to @option{true}, before capture starts, popup a display
+dialog to the end user, allowing them to manually
+modify crossbar pin routings, when it opens an audio device.
+
+@item show_analog_tv_tuner_dialog
+If set to @option{true}, before capture starts, popup a display
+dialog to the end user, allowing them to manually
+modify TV channels and frequencies.
+
+@item show_analog_tv_tuner_audio_dialog
+If set to @option{true}, before capture starts, popup a display
+dialog to the end user, allowing them to manually
+modify TV audio (like mono vs. stereo, Language A,B or C).
+
+@item audio_device_load
+Load an audio capture filter device from file instead of searching
+it by name. It may load additional parameters too, if the filter
+supports the serialization of its properties to.
+To use this an audio capture source has to be specified, but it can
+be anything even fake one.
+
+@item audio_device_save
+Save the currently used audio capture filter device and its
+parameters (if the filter supports it) to a file.
+If a file with the same name exists it will be overwritten.
+
+@item video_device_load
+Load a video capture filter device from file instead of searching
+it by name. It may load additional parameters too, if the filter
+supports the serialization of its properties to.
+To use this a video capture source has to be specified, but it can
+be anything even fake one.
+
+@item video_device_save
+Save the currently used video capture filter device and its
+parameters (if the filter supports it) to a file.
+If a file with the same name exists it will be overwritten.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Print the list of DirectShow supported devices and exit:
+@example
+$ ffmpeg -list_devices true -f dshow -i dummy
+@end example
+
+@item
+Open video device @var{Camera}:
+@example
+$ ffmpeg -f dshow -i video="Camera"
+@end example
+
+@item
+Open second video device with name @var{Camera}:
+@example
+$ ffmpeg -f dshow -video_device_number 1 -i video="Camera"
+@end example
+
+@item
+Open video device @var{Camera} and audio device @var{Microphone}:
+@example
+$ ffmpeg -f dshow -i video="Camera":audio="Microphone"
+@end example
+
+@item
+Print the list of supported options in selected device and exit:
+@example
+$ ffmpeg -list_options true -f dshow -i video="Camera"
+@end example
+
+@item
+Specify pin names to capture by name or alternative name, specify alternative device name:
+@example
+$ ffmpeg -f dshow -audio_pin_name "Audio Out" -video_pin_name 2 -i video=video="@@device_pnp_\\?\pci#ven_1a0a&dev_6200&subsys_62021461&rev_01#4&e2c7dd6&0&00e1#@{65e8773d-8f56-11d0-a3b9-00a0c9223196@}\@{ca465100-deb0-4d59-818f-8c477184adf6@}":audio="Microphone"
+@end example
+
+@item
+Configure a crossbar device, specifying crossbar pins, allow user to adjust video capture properties at startup:
+@example
+$ ffmpeg -f dshow -show_video_device_dialog true -crossbar_video_input_pin_number 0
+ -crossbar_audio_input_pin_number 3 -i video="AVerMedia BDA Analog Capture":audio="AVerMedia BDA Analog Capture"
+@end example
+
+@end itemize
+
@section dv1394
Linux DV 1394 input device.
@@ -72,18 +442,153 @@ For more detailed information read the file
Documentation/fb/framebuffer.txt included in the Linux source tree.
To record from the framebuffer device @file{/dev/fb0} with
-@command{avconv}:
+@command{ffmpeg}:
@example
-avconv -f fbdev -r 10 -i /dev/fb0 out.avi
+ffmpeg -f fbdev -r 10 -i /dev/fb0 out.avi
@end example
You can take a single screenshot image with the command:
@example
-avconv -f fbdev -frames:v 1 -r 1 -i /dev/fb0 screenshot.jpeg
+ffmpeg -f fbdev -frames:v 1 -r 1 -i /dev/fb0 screenshot.jpeg
@end example
See also @url{http://linux-fbdev.sourceforge.net/}, and fbset(1).
+@section gdigrab
+
+Win32 GDI-based screen capture device.
+
+This device allows you to capture a region of the display on Windows.
+
+There are two options for the input filename:
+@example
+desktop
+@end example
+or
+@example
+title=@var{window_title}
+@end example
+
+The first option will capture the entire desktop, or a fixed region of the
+desktop. The second option will instead capture the contents of a single
+window, regardless of its position on the screen.
+
+For example, to grab the entire desktop using @command{ffmpeg}:
+@example
+ffmpeg -f gdigrab -framerate 6 -i desktop out.mpg
+@end example
+
+Grab a 640x480 region at position @code{10,20}:
+@example
+ffmpeg -f gdigrab -framerate 6 -offset_x 10 -offset_y 20 -video_size vga -i desktop out.mpg
+@end example
+
+Grab the contents of the window named "Calculator"
+@example
+ffmpeg -f gdigrab -framerate 6 -i title=Calculator out.mpg
+@end example
+
+@subsection Options
+
+@table @option
+@item draw_mouse
+Specify whether to draw the mouse pointer. Use the value @code{0} to
+not draw the pointer. Default value is @code{1}.
+
+@item framerate
+Set the grabbing frame rate. Default value is @code{ntsc},
+corresponding to a frame rate of @code{30000/1001}.
+
+@item show_region
+Show grabbed region on screen.
+
+If @var{show_region} is specified with @code{1}, then the grabbing
+region will be indicated on screen. With this option, it is easy to
+know what is being grabbed if only a portion of the screen is grabbed.
+
+Note that @var{show_region} is incompatible with grabbing the contents
+of a single window.
+
+For example:
+@example
+ffmpeg -f gdigrab -show_region 1 -framerate 6 -video_size cif -offset_x 10 -offset_y 20 -i desktop out.mpg
+@end example
+
+@item video_size
+Set the video frame size. The default is to capture the full screen if @file{desktop} is selected, or the full window size if @file{title=@var{window_title}} is selected.
+
+@item offset_x
+When capturing a region with @var{video_size}, set the distance from the left edge of the screen or desktop.
+
+Note that the offset calculation is from the top left corner of the primary monitor on Windows. If you have a monitor positioned to the left of your primary monitor, you will need to use a negative @var{offset_x} value to move the region to that monitor.
+
+@item offset_y
+When capturing a region with @var{video_size}, set the distance from the top edge of the screen or desktop.
+
+Note that the offset calculation is from the top left corner of the primary monitor on Windows. If you have a monitor positioned above your primary monitor, you will need to use a negative @var{offset_y} value to move the region to that monitor.
+
+@end table
+
+@section iec61883
+
+FireWire DV/HDV input device using libiec61883.
+
+To enable this input device, you need libiec61883, libraw1394 and
+libavc1394 installed on your system. Use the configure option
+@code{--enable-libiec61883} to compile with the device enabled.
+
+The iec61883 capture device supports capturing from a video device
+connected via IEEE1394 (FireWire), using libiec61883 and the new Linux
+FireWire stack (juju). This is the default DV/HDV input method in Linux
+Kernel 2.6.37 and later, since the old FireWire stack was removed.
+
+Specify the FireWire port to be used as input file, or "auto"
+to choose the first port connected.
+
+@subsection Options
+
+@table @option
+
+@item dvtype
+Override autodetection of DV/HDV. This should only be used if auto
+detection does not work, or if usage of a different device type
+should be prohibited. Treating a DV device as HDV (or vice versa) will
+not work and result in undefined behavior.
+The values @option{auto}, @option{dv} and @option{hdv} are supported.
+
+@item dvbuffer
+Set maximum size of buffer for incoming data, in frames. For DV, this
+is an exact value. For HDV, it is not frame exact, since HDV does
+not have a fixed frame size.
+
+@item dvguid
+Select the capture device by specifying it's GUID. Capturing will only
+be performed from the specified device and fails if no device with the
+given GUID is found. This is useful to select the input if multiple
+devices are connected at the same time.
+Look at /sys/bus/firewire/devices to find out the GUIDs.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+Grab and show the input of a FireWire DV/HDV device.
+@example
+ffplay -f iec61883 -i auto
+@end example
+
+@item
+Grab and record the input of a FireWire DV/HDV device,
+using a packet buffer of 100000 packets if the source is HDV.
+@example
+ffmpeg -f iec61883 -i auto -hdvbuffer 100000 out.mpg
+@end example
+
+@end itemize
+
@section jack
JACK input device.
@@ -95,24 +600,24 @@ A JACK input device creates one or more JACK writable clients, one for
each audio channel, with name @var{client_name}:input_@var{N}, where
@var{client_name} is the name provided by the application, and @var{N}
is a number which identifies the channel.
-Each writable client will send the acquired data to the Libav input
+Each writable client will send the acquired data to the FFmpeg input
device.
Once you have created one or more JACK readable clients, you need to
connect them to one or more JACK writable clients.
-To connect or disconnect JACK clients you can use the
-@file{jack_connect} and @file{jack_disconnect} programs, or do it
-through a graphical interface, for example with @file{qjackctl}.
+To connect or disconnect JACK clients you can use the @command{jack_connect}
+and @command{jack_disconnect} programs, or do it through a graphical interface,
+for example with @command{qjackctl}.
To list the JACK clients and their properties you can invoke the command
-@file{jack_lsp}.
+@command{jack_lsp}.
Follows an example which shows how to capture a JACK readable client
-with @command{avconv}.
+with @command{ffmpeg}.
@example
-# Create a JACK writable client with name "libav".
-$ avconv -f jack -i libav -y out.wav
+# Create a JACK writable client with name "ffmpeg".
+$ ffmpeg -f jack -i ffmpeg -y out.wav
# Start the sample jack_metro readable client.
$ jack_metro -b 120 -d 0.2 -f 4000
@@ -123,20 +628,240 @@ system:capture_1
system:capture_2
system:playback_1
system:playback_2
-libav:input_1
+ffmpeg:input_1
metro:120_bpm
-# Connect metro to the avconv writable client.
-$ jack_connect metro:120_bpm libav:input_1
+# Connect metro to the ffmpeg writable client.
+$ jack_connect metro:120_bpm ffmpeg:input_1
@end example
For more information read:
@url{http://jackaudio.org/}
+@section lavfi
+
+Libavfilter input virtual device.
+
+This input device reads data from the open output pads of a libavfilter
+filtergraph.
+
+For each filtergraph open output, the input device will create a
+corresponding stream which is mapped to the generated output. Currently
+only video data is supported. The filtergraph is specified through the
+option @option{graph}.
+
+@subsection Options
+
+@table @option
+
+@item graph
+Specify the filtergraph to use as input. Each video open output must be
+labelled by a unique string of the form "out@var{N}", where @var{N} is a
+number starting from 0 corresponding to the mapped input stream
+generated by the device.
+The first unlabelled output is automatically assigned to the "out0"
+label, but all the others need to be specified explicitly.
+
+The suffix "+subcc" can be appended to the output label to create an extra
+stream with the closed captions packets attached to that output
+(experimental; only for EIA-608 / CEA-708 for now).
+The subcc streams are created after all the normal streams, in the order of
+the corresponding stream.
+For example, if there is "out19+subcc", "out7+subcc" and up to "out42", the
+stream #43 is subcc for stream #7 and stream #44 is subcc for stream #19.
+
+If not specified defaults to the filename specified for the input
+device.
+
+@item graph_file
+Set the filename of the filtergraph to be read and sent to the other
+filters. Syntax of the filtergraph is the same as the one specified by
+the option @var{graph}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Create a color video stream and play it back with @command{ffplay}:
+@example
+ffplay -f lavfi -graph "color=c=pink [out0]" dummy
+@end example
+
+@item
+As the previous example, but use filename for specifying the graph
+description, and omit the "out0" label:
+@example
+ffplay -f lavfi color=c=pink
+@end example
+
+@item
+Create three different video test filtered sources and play them:
+@example
+ffplay -f lavfi -graph "testsrc [out0]; testsrc,hflip [out1]; testsrc,negate [out2]" test3
+@end example
+
+@item
+Read an audio stream from a file using the amovie source and play it
+back with @command{ffplay}:
+@example
+ffplay -f lavfi "amovie=test.wav"
+@end example
+
+@item
+Read an audio stream and a video stream and play it back with
+@command{ffplay}:
+@example
+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):
+@example
+ffmpeg -f lavfi -i "movie=test.ts[out0+subcc]" -map v frame%08d.png -map s -c copy -f rawvideo subcc.bin
+@end example
+
+@end itemize
+
+@section libcdio
+
+Audio-CD input device based on libcdio.
+
+To enable this input device during configuration you need libcdio
+installed on your system. It requires the configure option
+@code{--enable-libcdio}.
+
+This device allows playing and grabbing from an Audio-CD.
+
+For example to copy with @command{ffmpeg} the entire Audio-CD in @file{/dev/sr0},
+you may run the command:
+@example
+ffmpeg -f libcdio -i /dev/sr0 cd.wav
+@end example
+
+@subsection Options
+@table @option
+@item speed
+Set drive reading speed. Default value is 0.
+
+The speed is specified CD-ROM speed units. The speed is set through
+the libcdio @code{cdio_cddap_speed_set} function. On many CD-ROM
+drives, specifying a value too large will result in using the fastest
+speed.
+
+@item paranoia_mode
+Set paranoia recovery mode flags. It accepts one of the following values:
+
+@table @samp
+@item disable
+@item verify
+@item overlap
+@item neverskip
+@item full
+@end table
+
+Default value is @samp{disable}.
+
+For more information about the available recovery modes, consult the
+paranoia project documentation.
+@end table
+
@section libdc1394
IIDC1394 input device, based on libdc1394 and libraw1394.
+Requires the configure option @code{--enable-libdc1394}.
+
+@section openal
+
+The OpenAL input device provides audio capture on all systems with a
+working OpenAL 1.1 implementation.
+
+To enable this input device during configuration, you need OpenAL
+headers and libraries installed on your system, and need to configure
+FFmpeg with @code{--enable-openal}.
+
+OpenAL headers and libraries should be provided as part of your OpenAL
+implementation, or as an additional download (an SDK). Depending on your
+installation you may need to specify additional flags via the
+@code{--extra-cflags} and @code{--extra-ldflags} for allowing the build
+system to locate the OpenAL headers and libraries.
+
+An incomplete list of OpenAL implementations follows:
+
+@table @strong
+@item Creative
+The official Windows implementation, providing hardware acceleration
+with supported devices and software fallback.
+See @url{http://openal.org/}.
+@item OpenAL Soft
+Portable, open source (LGPL) software implementation. Includes
+backends for the most common sound APIs on the Windows, Linux,
+Solaris, and BSD operating systems.
+See @url{http://kcat.strangesoft.net/openal.html}.
+@item Apple
+OpenAL is part of Core Audio, the official Mac OS X Audio interface.
+See @url{http://developer.apple.com/technologies/mac/audio-and-video.html}
+@end table
+
+This device allows one to capture from an audio input device handled
+through OpenAL.
+
+You need to specify the name of the device to capture in the provided
+filename. If the empty string is provided, the device will
+automatically select the default device. You can get the list of the
+supported devices by using the option @var{list_devices}.
+
+@subsection Options
+
+@table @option
+
+@item channels
+Set the number of channels in the captured audio. Only the values
+@option{1} (monaural) and @option{2} (stereo) are currently supported.
+Defaults to @option{2}.
+
+@item sample_size
+Set the sample size (in bits) of the captured audio. Only the values
+@option{8} and @option{16} are currently supported. Defaults to
+@option{16}.
+
+@item sample_rate
+Set the sample rate (in Hz) of the captured audio.
+Defaults to @option{44.1k}.
+
+@item list_devices
+If set to @option{true}, print a list of devices and exit.
+Defaults to @option{false}.
+
+@end table
+
+@subsection Examples
+
+Print the list of OpenAL supported devices and exit:
+@example
+$ ffmpeg -list_devices true -f openal -i dummy out.ogg
+@end example
+
+Capture from the OpenAL device @file{DR-BT101 via PulseAudio}:
+@example
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out.ogg
+@end example
+
+Capture from the default device (note the empty string '' as filename):
+@example
+$ ffmpeg -f openal -i '' out.ogg
+@end example
+
+Capture from two devices simultaneously, writing to two different files,
+within the same @command{ffmpeg} command:
+@example
+$ ffmpeg -f openal -i 'DR-BT101 via PulseAudio' out1.ogg -f openal -i 'ALSA Default' out2.ogg
+@end example
+Note: not all OpenAL implementations support multiple simultaneous capture -
+try the latest OpenAL Soft if the above does not work.
+
@section oss
Open Sound System input device.
@@ -145,10 +870,10 @@ The filename to provide to the input device is the device node
representing the OSS input device, and is usually set to
@file{/dev/dsp}.
-For example to grab from @file{/dev/dsp} using @command{avconv} use the
+For example to grab from @file{/dev/dsp} using @command{ffmpeg} use the
command:
@example
-avconv -f oss -i /dev/dsp /tmp/oss.wav
+ffmpeg -f oss -i /dev/dsp /tmp/oss.wav
@end example
For more information about OSS see:
@@ -156,87 +881,79 @@ For more information about OSS see:
@section pulse
-pulseaudio input device.
+PulseAudio input device.
-To enable this input device during configuration you need libpulse-simple
-installed in your system.
+To enable this output device you need to configure FFmpeg with @code{--enable-libpulse}.
The filename to provide to the input device is a source device or the
string "default"
-To list the pulse source devices and their properties you can invoke
-the command @file{pactl list sources}.
+To list the PulseAudio source devices and their properties you can invoke
+the command @command{pactl list sources}.
-@example
-avconv -f pulse -i default /tmp/pulse.wav
-@end example
+More information about PulseAudio can be found on @url{http://www.pulseaudio.org}.
-@subsection @var{server} AVOption
+@subsection Options
+@table @option
+@item server
+Connect to a specific PulseAudio server, specified by an IP address.
+Default server is used when not provided.
-The syntax is:
-@example
--server @var{server name}
-@end example
+@item name
+Specify the application name PulseAudio will use when showing active clients,
+by default it is the @code{LIBAVFORMAT_IDENT} string.
-Connects to a specific server.
+@item stream_name
+Specify the stream name PulseAudio will use when showing active streams,
+by default it is "record".
-@subsection @var{name} AVOption
+@item sample_rate
+Specify the samplerate in Hz, by default 48kHz is used.
-The syntax is:
-@example
--name @var{application name}
-@end example
+@item channels
+Specify the channels in use, by default 2 (stereo) is set.
-Specify the application name pulse will use when showing active clients,
-by default it is "libav"
+@item frame_size
+Specify the number of bytes per frame, by default it is set to 1024.
-@subsection @var{stream_name} AVOption
+@item fragment_size
+Specify the minimal buffering fragment in PulseAudio, it will affect the
+audio latency. By default it is unset.
+@end table
-The syntax is:
+@subsection Examples
+Record a stream from default device:
@example
--stream_name @var{stream name}
+ffmpeg -f pulse -i default /tmp/pulse.wav
@end example
-Specify the stream name pulse will use when showing active streams,
-by default it is "record"
+@section qtkit
-@subsection @var{sample_rate} AVOption
+QTKit input device.
+
+The filename passed as input is parsed to contain either a device name or index.
+The device index can also be given by using -video_device_index.
+A given device index will override any given device name.
+If the desired device consists of numbers only, use -video_device_index to identify it.
+The default device will be chosen if an empty string or the device name "default" is given.
+The available devices can be enumerated by using -list_devices.
-The syntax is:
@example
--sample_rate @var{samplerate}
+ffmpeg -f qtkit -i "0" out.mpg
@end example
-Specify the samplerate in Hz, by default 48kHz is used.
-
-@subsection @var{channels} AVOption
-
-The syntax is:
@example
--channels @var{N}
+ffmpeg -f qtkit -video_device_index 0 -i "" out.mpg
@end example
-Specify the channels in use, by default 2 (stereo) is set.
-
-@subsection @var{frame_size} AVOption
-
-The syntax is:
@example
--frame_size @var{bytes}
+ffmpeg -f qtkit -i "default" out.mpg
@end example
-Specify the number of byte per frame, by default it is set to 1024.
-
-@subsection @var{fragment_size} AVOption
-
-The syntax is:
@example
--fragment_size @var{bytes}
+ffmpeg -f qtkit -list_devices true -i ""
@end example
-Specify the minimal buffering fragment in pulseaudio, it will affect the
-audio latency. By default it is unset.
-
@section sndio
sndio input device.
@@ -248,16 +965,22 @@ The filename to provide to the input device is the device node
representing the sndio input device, and is usually set to
@file{/dev/audio0}.
-For example to grab from @file{/dev/audio0} using @command{avconv} use the
+For example to grab from @file{/dev/audio0} using @command{ffmpeg} use the
command:
@example
-avconv -f sndio -i /dev/audio0 /tmp/oss.wav
+ffmpeg -f sndio -i /dev/audio0 /tmp/oss.wav
@end example
-@section video4linux2
+@section video4linux2, v4l2
Video4Linux2 input video device.
+"v4l2" can be used as alias for "video4linux2".
+
+If FFmpeg is built with v4l-utils support (by using the
+@code{--enable-libv4l2} configure option), it is possible to use it with the
+@code{-use_libv4l2} input device option.
+
The name of the device to grab is a file device node, usually Linux
systems tend to automatically create such nodes when the device
(e.g. an USB webcam) is plugged into the system, and has a name of the
@@ -265,22 +988,112 @@ kind @file{/dev/video@var{N}}, where @var{N} is a number associated to
the device.
Video4Linux2 devices usually support a limited set of
-@var{width}x@var{height} sizes and framerates. You can check which are
+@var{width}x@var{height} sizes and frame rates. You can check which are
supported using @command{-list_formats all} for Video4Linux2 devices.
+Some devices, like TV cards, support one or more standards. It is possible
+to list all the supported standards using @command{-list_standards all}.
+
+The time base for the timestamps is 1 microsecond. Depending on the kernel
+version and configuration, the timestamps may be derived from the real time
+clock (origin at the Unix Epoch) or the monotonic clock (origin usually at
+boot time, unaffected by NTP or manual changes to the clock). The
+@option{-timestamps abs} or @option{-ts abs} option can be used to force
+conversion into the real time clock.
+
+Some usage examples of the video4linux2 device with @command{ffmpeg}
+and @command{ffplay}:
+@itemize
+@item
+List supported formats for a video4linux2 device:
+@example
+ffplay -f video4linux2 -list_formats all /dev/video0
+@end example
-Some usage examples of the video4linux2 devices with avconv and avplay:
+@item
+Grab and show the input of a video4linux2 device:
+@example
+ffplay -f video4linux2 -framerate 30 -video_size hd720 /dev/video0
+@end example
+@item
+Grab and record the input of a video4linux2 device, leave the
+frame rate and size as previously set:
@example
-# List supported formats for a video4linux2 device.
-avplay -f video4linux2 -list_formats all /dev/video0
+ffmpeg -f video4linux2 -input_format mjpeg -i /dev/video0 out.mpeg
+@end example
+@end itemize
-# Grab and show the input of a video4linux2 device.
-avplay -f video4linux2 -framerate 30 -video_size hd720 /dev/video0
+For more information about Video4Linux, check @url{http://linuxtv.org/}.
-# Grab and record the input of a video4linux2 device, leave the
-framerate and size as previously set.
-avconv -f video4linux2 -input_format mjpeg -i /dev/video0 out.mpeg
-@end example
+@subsection Options
+
+@table @option
+@item standard
+Set the standard. Must be the name of a supported standard. To get a
+list of the supported standards, use the @option{list_standards}
+option.
+
+@item channel
+Set the input channel number. Default to -1, which means using the
+previously selected channel.
+
+@item video_size
+Set the video frame size. The argument must be a string in the form
+@var{WIDTH}x@var{HEIGHT} or a valid size abbreviation.
+
+@item pixel_format
+Select the pixel format (only valid for raw video input).
+
+@item input_format
+Set the preferred pixel format (for raw video) or a codec name.
+This option allows one to select the input format, when several are
+available.
+
+@item framerate
+Set the preferred video frame rate.
+
+@item list_formats
+List available formats (supported pixel formats, codecs, and frame
+sizes) and exit.
+
+Available values are:
+@table @samp
+@item all
+Show all available (compressed and non-compressed) formats.
+
+@item raw
+Show only raw video (non-compressed) formats.
+
+@item compressed
+Show only compressed formats.
+@end table
+
+@item list_standards
+List supported standards and exit.
+
+Available values are:
+@table @samp
+@item all
+Show all supported standards.
+@end table
+
+@item timestamps, ts
+Set type of timestamps for grabbed frames.
+
+Available values are:
+@table @samp
+@item default
+Use timestamps from the kernel.
+
+@item abs
+Use absolute timestamps (wall clock).
+
+@item mono2abs
+Force conversion from monotonic to absolute timestamps.
+@end table
+
+Default value is @code{default}.
+@end table
@section vfwcap
@@ -294,7 +1107,14 @@ other filename will be interpreted as device number 0.
X11 video input device.
-This device allows to capture a region of an X11 display.
+To enable this input device during configuration you need libxcb
+installed on your system. It will be automatically detected during
+configuration.
+
+Alternatively, the configure option @option{--enable-x11grab} exists
+for legacy Xlib users.
+
+This device allows one to capture a region of an X11 display.
The filename passed as input has the syntax:
@example
@@ -310,26 +1130,34 @@ omitted, and defaults to "localhost". The environment variable
area with respect to the top-left border of the X11 screen. They
default to 0.
-Check the X11 documentation (e.g. man X) for more detailed information.
+Check the X11 documentation (e.g. @command{man X}) for more detailed
+information.
-Use the @file{dpyinfo} program for getting basic information about the
-properties of your X11 display (e.g. grep for "name" or "dimensions").
+Use the @command{xdpyinfo} program for getting basic information about
+the properties of your X11 display (e.g. grep for "name" or
+"dimensions").
-For example to grab from @file{:0.0} using @command{avconv}:
+For example to grab from @file{:0.0} using @command{ffmpeg}:
@example
-avconv -f x11grab -r 25 -s cif -i :0.0 out.mpg
-
-# Grab at position 10,20.
-avconv -f x11grab -r 25 -s cif -i :0.0+10,20 out.mpg
+ffmpeg -f x11grab -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
-@subsection @var{follow_mouse} AVOption
-
-The syntax is:
+Grab at position @code{10,20}:
@example
--follow_mouse centered|@var{PIXELS}
+ffmpeg -f x11grab -framerate 25 -video_size cif -i :0.0+10,20 out.mpg
@end example
+@subsection Options
+
+@table @option
+@item draw_mouse
+Specify whether to draw the mouse pointer. A value of @code{0} specify
+not to draw the pointer. Default value is @code{1}.
+
+@item follow_mouse
+Make the grabbed area follow the mouse. The argument can be
+@code{centered} or a number of pixels @var{PIXELS}.
+
When it is specified with "centered", the grabbing region follows the mouse
pointer and keeps the pointer at the center of region; otherwise, the region
follows only when the mouse pointer reaches within @var{PIXELS} (greater than
@@ -337,31 +1165,48 @@ zero) to the edge of region.
For example:
@example
-avconv -f x11grab -follow_mouse centered -r 25 -s cif -i :0.0 out.mpg
-
-# Follows only when the mouse pointer reaches within 100 pixels to edge
-avconv -f x11grab -follow_mouse 100 -r 25 -s cif -i :0.0 out.mpg
+ffmpeg -f x11grab -follow_mouse centered -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
-@subsection @var{show_region} AVOption
-
-The syntax is:
+To follow only when the mouse pointer reaches within 100 pixels to edge:
@example
--show_region 1
+ffmpeg -f x11grab -follow_mouse 100 -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
-If @var{show_region} AVOption is specified with @var{1}, then the grabbing
-region will be indicated on screen. With this option, it's easy to know what is
-being grabbed if only a portion of the screen is grabbed.
+@item framerate
+Set the grabbing frame rate. Default value is @code{ntsc},
+corresponding to a frame rate of @code{30000/1001}.
+
+@item show_region
+Show grabbed region on screen.
+
+If @var{show_region} is specified with @code{1}, then the grabbing
+region will be indicated on screen. With this option, it is easy to
+know what is being grabbed if only a portion of the screen is grabbed.
+
+@item region_border
+Set the region border thickness if @option{-show_region 1} is used.
+Range is 1 to 128 and default is 3 (XCB-based x11grab only).
For example:
@example
-avconv -f x11grab -show_region 1 -r 25 -s cif -i :0.0+10,20 out.mpg
+ffmpeg -f x11grab -show_region 1 -framerate 25 -video_size cif -i :0.0+10,20 out.mpg
+@end example
-# With follow_mouse
-avconv -f x11grab -follow_mouse centered -show_region 1 -r 25 -s cif -i :0.0 out.mpg
+With @var{follow_mouse}:
+@example
+ffmpeg -f x11grab -follow_mouse centered -show_region 1 -framerate 25 -video_size cif -i :0.0 out.mpg
@end example
+@item video_size
+Set the video frame size. Default value is @code{vga}.
+
+@item use_shm
+Use the MIT-SHM extension for shared memory. Default value is @code{1}.
+It may be necessary to disable it for remote displays (legacy x11grab
+only).
+@end table
+
@subsection @var{grab_x} @var{grab_y} AVOption
The syntax is:
@@ -369,7 +1214,8 @@ The syntax is:
-grab_x @var{x_offset} -grab_y @var{y_offset}
@end example
-Set the grabing region coordinates. The are expressed as offset from the top left
+Set the grabbing region coordinates. They are expressed as offset from the top left
corner of the X11 window. The default value is 0.
+
@c man end INPUT DEVICES
diff --git a/doc/issue_tracker.txt b/doc/issue_tracker.txt
new file mode 100644
index 0000000000..095c04c519
--- /dev/null
+++ b/doc/issue_tracker.txt
@@ -0,0 +1,194 @@
+FFmpeg's bug/feature request tracker manual
+=================================================
+
+NOTE: This is a draft.
+
+Overview:
+---------
+
+FFmpeg uses Trac for tracking issues, new issues and changes to
+existing issues can be done through a web interface.
+
+Issues can be different kinds of things we want to keep track of
+but that do not belong into the source tree itself. This includes
+bug reports, feature requests and license violations. We
+might add more items to this list in the future, so feel free to
+propose a new `type of issue' on the ffmpeg-devel mailing list if
+you feel it is worth tracking.
+
+It is possible to subscribe to individual issues by adding yourself to the
+Cc list or to subscribe to the ffmpeg-trac mailing list which receives
+a mail for every change to every issue.
+(the above does all work already after light testing)
+
+The subscription URL for the ffmpeg-trac list is:
+http(s)://lists.ffmpeg.org/mailman/listinfo/ffmpeg-trac
+The URL of the webinterface of the tracker is:
+http(s)://trac.ffmpeg.org
+
+Type:
+-----
+art
+ Artwork such as photos, music, banners, and logos.
+
+bug / defect
+ An error, flaw, mistake, failure, or fault in FFmpeg or libav* that
+ prevents it from behaving as intended.
+
+feature request / enhancement
+ Request of support for encoding or decoding of a new codec, container
+ or variant.
+ Request of support for more, less or plain different output or behavior
+ where the current implementation cannot be considered wrong.
+
+license violation
+ ticket to keep track of (L)GPL violations of ffmpeg by others
+
+sponsoring request
+ Developer requests for hardware, software, specifications, money,
+ refunds, etc.
+
+Priority:
+---------
+critical
+ Bugs about data loss and security issues.
+ No feature request can be critical.
+
+important
+ Bugs which make FFmpeg unusable for a significant number of users.
+ Examples here might be completely broken MPEG-4 decoding or a build issue
+ on Linux.
+ While broken 4xm decoding or a broken OS/2 build would not be important,
+ the separation to normal is somewhat fuzzy.
+ For feature requests this priority would be used for things many people
+ want.
+ Regressions also should be marked as important, regressions are bugs that
+ don't exist in a past revision or another branch.
+
+normal
+
+
+minor
+ Bugs about things like spelling errors, "mp2" instead of
+ "mp3" being shown and such.
+ Feature requests about things few people want or which do not make a big
+ difference.
+
+wish
+ Something that is desirable to have but that there is no urgency at
+ all to implement, e.g. something completely cosmetic like a website
+ restyle or a personalized doxy template or the FFmpeg logo.
+ This priority is not valid for bugs.
+
+
+Status:
+-------
+new
+ initial state
+
+open
+ intermediate states
+
+closed
+ final state
+
+
+Analyzed flag:
+--------------
+Bugs which have been analyzed and where it is understood what causes them
+and which exact chain of events triggers them. This analysis should be
+available as a message in the bug report.
+Note, do not change the status to analyzed without also providing a clear
+and understandable analysis.
+This state implicates that the bug either has been reproduced or that
+reproduction is not needed as the bug is already understood.
+
+
+Type/Status:
+----------
+*/new
+ Initial state of new bugs and feature requests submitted by
+ users.
+
+*/open
+ Issues which have been briefly looked at and which did not look outright
+ invalid.
+ This implicates that no real more detailed state applies yet. Conversely,
+ the more detailed states below implicate that the issue has been briefly
+ looked at.
+
+*/closed/duplicate
+ Bugs or feature requests which are duplicates.
+ Note, if you mark something as duplicate, do not forget setting the
+ superseder so bug reports are properly linked.
+
+*/closed/invalid
+ Bugs caused by user errors, random ineligible or otherwise nonsense stuff.
+
+*/closed/needs_more_info
+ Issues for which some information has been requested by the developers,
+ but which has not been provided by anyone within reasonable time.
+
+
+bug/closed/fixed
+ Bugs which have to the best of our knowledge been fixed.
+
+bug/closed/wontfix
+ Bugs which we will not fix. Possible reasons include legality, high
+ complexity for the sake of supporting obscure corner cases, speed loss
+ for similarly esoteric purposes, et cetera.
+ This also means that we would reject a patch.
+ If we are just too lazy to fix a bug then the correct state is open
+ and unassigned. Closed means that the case is closed which is not
+ the case if we are just waiting for a patch.
+
+bug/closed/works_for_me
+ Bugs for which sufficient information was provided to reproduce but
+ reproduction failed - that is the code seems to work correctly to the
+ best of our knowledge.
+
+feature_request/closed/fixed
+ Feature requests which have been implemented.
+
+feature_request/closed/wontfix
+ Feature requests which will not be implemented. The reasons here could
+ be legal, philosophical or others.
+
+Note2, if you provide the requested info do not forget to remove the
+needs_more_info resolution.
+
+Component:
+----------
+
+avcodec
+ issues in libavcodec/*
+
+avformat
+ issues in libavformat/*
+
+avutil
+ issues in libavutil/*
+
+regression test
+ issues in tests/*
+
+ffmpeg
+ issues in or related to ffmpeg.c
+
+ffplay
+ issues in or related to ffplay.c
+
+ffprobe
+ issues in or related to ffprobe.c
+
+ffserver
+ issues in or related to ffserver.c
+
+build system
+ issues in or related to configure/Makefile
+
+regression
+ bugs which were not present in a past revision
+
+trac
+ issues related to our issue tracker
diff --git a/doc/libavcodec.texi b/doc/libavcodec.texi
new file mode 100644
index 0000000000..87b90db48c
--- /dev/null
+++ b/doc/libavcodec.texi
@@ -0,0 +1,49 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle Libavcodec Documentation
+@titlepage
+@center @titlefont{Libavcodec Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libavcodec library provides a generic encoding/decoding framework
+and contains multiple decoders and encoders for audio, video and
+subtitle streams, and several bitstream filters.
+
+The shared architecture provides various services ranging from bit
+stream I/O to DSP optimizations, and makes it suitable for
+implementing robust and fast codecs as well as for experimentation.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-codecs.html,ffmpeg-codecs}, @url{ffmpeg-bitstream-filters.html,bitstream-filters},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-codecs(1), ffmpeg-bitstream-filters(1),
+libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libavcodec
+@settitle media streams decoding and encoding library
+
+@end ignore
+
+@bye
diff --git a/doc/libavdevice.texi b/doc/libavdevice.texi
new file mode 100644
index 0000000000..9b10282cde
--- /dev/null
+++ b/doc/libavdevice.texi
@@ -0,0 +1,46 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle Libavdevice Documentation
+@titlepage
+@center @titlefont{Libavdevice Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libavdevice library provides a generic framework for grabbing from
+and rendering to many common multimedia input/output devices, and
+supports several input and output devices, including Video4Linux2,
+VfW, DShow, and ALSA.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-devices.html,ffmpeg-devices},
+@url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-devices(1),
+libavutil(3), libavcodec(3), libavformat(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libavdevice
+@settitle multimedia device handling library
+
+@end ignore
+
+@bye
diff --git a/doc/libavfilter.texi b/doc/libavfilter.texi
index 84bad29dab..52e075369c 100644
--- a/doc/libavfilter.texi
+++ b/doc/libavfilter.texi
@@ -1,4 +1,5 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
@settitle Libavfilter Documentation
@titlepage
@@ -9,84 +10,36 @@
@contents
-@chapter Introduction
+@chapter Description
+@c man begin DESCRIPTION
-Libavfilter is the filtering API of Libav. It replaces 'vhooks', and
-started as a Google Summer of Code project.
+The libavfilter library provides a generic audio/video filtering
+framework containing several filters, sources and sinks.
-Note that there may still be serious bugs in the code and its API
-and ABI should not be considered stable yet!
+@c man end DESCRIPTION
-@chapter Tutorial
+@chapter See Also
-In libavfilter, it is possible for filters to have multiple inputs and
-multiple outputs.
-To illustrate the sorts of things that are possible, we can
-use a complex filter graph. For example, the following one:
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-filters.html,ffmpeg-filters},
+@url{libavutil.html,libavutil}, @url{libswscale.html,libswscale}, @url{libswresample.html,libswresample},
+@url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat}, @url{libavdevice.html,libavdevice}
+@end ifhtml
-@example
-input --> split --> fifo -----------------------> overlay --> output
- | ^
- | |
- +------> fifo --> crop --> vflip --------+
-@end example
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-filters(1),
+libavutil(3), libswscale(3), libswresample(3), libavcodec(3), libavformat(3), libavdevice(3)
+@end ifnothtml
-splits the stream in two streams, then sends one stream through the crop filter
-and the vflip filter, before merging it back with the other stream by
-overlaying it on top. You can use the following command to achieve this:
+@include authors.texi
-@example
-./avconv -i input -vf "[in] split [T1], fifo, [T2] overlay=0:H/2 [out]; [T1] fifo, crop=iw:ih/2:0:ih/2, vflip [T2]" output
-@end example
+@ignore
-The result will be that the top half of the video is mirrored
-onto the bottom half of the output video.
+@setfilename libavfilter
+@settitle multimedia filtering library
-Video filters are loaded using the @var{-vf} option passed to
-avconv or to avplay. Filters in the same linear chain are separated by
-commas. In our example, @var{split}, @var{fifo}, and @var{overlay} are in one
-linear chain, and @var{fifo}, @var{crop}, and @var{vflip} are in another. The
-points where the linear chains join are labeled by names enclosed in square
-brackets. In our example, they join at @var{[T1]} and @var{[T2]}. The magic
-labels @var{[in]} and @var{[out]} are the points where video is input
-and output.
-
-Some filters take a list of parameters: they are specified
-after the filter name and an equal sign, and are separated
-by a semicolon.
-
-There are so-called @var{source filters} that do not take video
-input, and we expect that some @var{sink filters} will
-not have video output, at some point in the future.
-
-@chapter graph2dot
-
-The @file{graph2dot} program included in the Libav @file{tools}
-directory can be used to parse a filter graph description and issue a
-corresponding textual representation in the dot language.
-
-Invoke the command:
-@example
-graph2dot -h
-@end example
-
-to see how to use @file{graph2dot}.
-
-You can then pass the dot description to the @file{dot} program (from
-the graphviz suite of programs) and obtain a graphical representation
-of the filter graph.
-
-For example the sequence of commands:
-@example
-echo @var{GRAPH_DESCRIPTION} | \
-tools/graph2dot -o graph.tmp && \
-dot -Tpng graph.tmp -o graph.png && \
-display graph.png
-@end example
-
-can be used to create and display an image representing the graph
-described by the @var{GRAPH_DESCRIPTION} string.
-
-@include filters.texi
+@end ignore
@bye
diff --git a/doc/libavformat.texi b/doc/libavformat.texi
new file mode 100644
index 0000000000..d505d644f6
--- /dev/null
+++ b/doc/libavformat.texi
@@ -0,0 +1,49 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle Libavformat Documentation
+@titlepage
+@center @titlefont{Libavformat Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libavformat library provides a generic framework for multiplexing
+and demultiplexing (muxing and demuxing) audio, video and subtitle
+streams. It encompasses multiple muxers and demuxers for multimedia
+container formats.
+
+It also supports several input and output protocols to access a media
+resource.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-formats.html,ffmpeg-formats}, @url{ffmpeg-protocols.html,ffmpeg-protocols},
+@url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-formats(1), ffmpeg-protocols(1),
+libavutil(3), libavcodec(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libavformat
+@settitle multimedia muxing and demuxing library
+
+@end ignore
+
+@bye
diff --git a/doc/libavutil.texi b/doc/libavutil.texi
new file mode 100644
index 0000000000..7a1c332b81
--- /dev/null
+++ b/doc/libavutil.texi
@@ -0,0 +1,63 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle Libavutil Documentation
+@titlepage
+@center @titlefont{Libavutil Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libavutil library is a utility library to aid portable
+multimedia programming. It contains safe portable string functions,
+random number generators, data structures, additional mathematics
+functions, cryptography and multimedia related functionality (like
+enumerations for pixel and sample formats). It is not a library for
+code needed by both libavcodec and libavformat.
+
+The goals for this library is to be:
+
+@table @strong
+@item Modular
+It should have few interdependencies and the possibility of disabling individual
+parts during @command{./configure}.
+
+@item Small
+Both sources and objects should be small.
+
+@item Efficient
+It should have low CPU and memory usage.
+
+@item Useful
+It should avoid useless features that almost no one needs.
+@end table
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-utils.html,ffmpeg-utils}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-utils(1)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libavutil
+@settitle multimedia-biased utility library
+
+@end ignore
+
+@bye
diff --git a/doc/libswresample.texi b/doc/libswresample.texi
new file mode 100644
index 0000000000..bb57278314
--- /dev/null
+++ b/doc/libswresample.texi
@@ -0,0 +1,71 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle Libswresample Documentation
+@titlepage
+@center @titlefont{Libswresample Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libswresample library performs highly optimized audio resampling,
+rematrixing and sample format conversion operations.
+
+Specifically, this library performs the following conversions:
+
+@itemize
+@item
+@emph{Resampling}: is the process of changing the audio rate, for
+example from a high sample rate of 44100Hz to 8000Hz. Audio
+conversion from high to low sample rate is a lossy process. Several
+resampling options and algorithms are available.
+
+@item
+@emph{Format conversion}: is the process of converting the type of
+samples, for example from 16-bit signed samples to unsigned 8-bit or
+float samples. It also handles packing conversion, when passing from
+packed layout (all samples belonging to distinct channels interleaved
+in the same buffer), to planar layout (all samples belonging to the
+same channel stored in a dedicated buffer or "plane").
+
+@item
+@emph{Rematrixing}: is the process of changing the channel layout, for
+example from stereo to mono. When the input channels cannot be mapped
+to the output streams, the process is lossy, since it involves
+different gain factors and mixing.
+@end itemize
+
+Various other audio conversions (e.g. stretching and padding) are
+enabled through dedicated options.
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-resampler.html,ffmpeg-resampler},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-resampler(1),
+libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libswresample
+@settitle audio resampling library
+
+@end ignore
+
+@bye
diff --git a/doc/libswscale.texi b/doc/libswscale.texi
new file mode 100644
index 0000000000..757fd24139
--- /dev/null
+++ b/doc/libswscale.texi
@@ -0,0 +1,64 @@
+\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
+
+@settitle Libswscale Documentation
+@titlepage
+@center @titlefont{Libswscale Documentation}
+@end titlepage
+
+@top
+
+@contents
+
+@chapter Description
+@c man begin DESCRIPTION
+
+The libswscale library performs highly optimized image scaling and
+colorspace and pixel format conversion operations.
+
+Specifically, this library performs the following conversions:
+
+@itemize
+@item
+@emph{Rescaling}: is the process of changing the video size. Several
+rescaling options and algorithms are available. This is usually a
+lossy process.
+
+@item
+@emph{Pixel format conversion}: is the process of converting the image
+format and colorspace of the image, for example from planar YUV420P to
+RGB24 packed. It also handles packing conversion, that is converts
+from packed layout (all pixels belonging to distinct planes
+interleaved in the same buffer), to planar layout (all samples
+belonging to the same plane stored in a dedicated buffer or "plane").
+
+This is usually a lossy process in case the source and destination
+colorspaces differ.
+@end itemize
+
+@c man end DESCRIPTION
+
+@chapter See Also
+
+@ifhtml
+@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver},
+@url{ffmpeg-scaler.html,ffmpeg-scaler},
+@url{libavutil.html,libavutil}
+@end ifhtml
+
+@ifnothtml
+ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1),
+ffmpeg-scaler(1),
+libavutil(3)
+@end ifnothtml
+
+@include authors.texi
+
+@ignore
+
+@setfilename libswscale
+@settitle video scaling and pixel format conversion library
+
+@end ignore
+
+@bye
diff --git a/doc/metadata.texi b/doc/metadata.texi
index cfaf491c2d..bddcc99470 100644
--- a/doc/metadata.texi
+++ b/doc/metadata.texi
@@ -1,7 +1,7 @@
@chapter Metadata
@c man begin METADATA
-Libav is able to dump metadata from media files into a simple UTF-8-encoded
+FFmpeg is able to dump metadata from media files into a simple UTF-8-encoded
INI-like text file and then load it back using the metadata muxer/demuxer.
The file format is as follows:
@@ -12,10 +12,10 @@ A file consists of a header and a number of metadata tags divided into sections,
each on its own line.
@item
-The header is a ';FFMETADATA' string, followed by a version number (now 1).
+The header is a @samp{;FFMETADATA} string, followed by a version number (now 1).
@item
-Metadata tags are of the form 'key=value'
+Metadata tags are of the form @samp{key=value}
@item
Immediately after header follows global metadata
@@ -26,26 +26,30 @@ metadata.
@item
A section starts with the section name in uppercase (i.e. STREAM or CHAPTER) in
-brackets ('[', ']') and ends with next section or end of file.
+brackets (@samp{[}, @samp{]}) and ends with next section or end of file.
@item
At the beginning of a chapter section there may be an optional timebase to be
-used for start/end values. It must be in form 'TIMEBASE=num/den', where num and
-den are integers. If the timebase is missing then start/end times are assumed to
+used for start/end values. It must be in form
+@samp{TIMEBASE=@var{num}/@var{den}}, where @var{num} and @var{den} are
+integers. If the timebase is missing then start/end times are assumed to
be in milliseconds.
+
Next a chapter section must contain chapter start and end times in form
-'START=num', 'END=num', where num is a positive integer.
+@samp{START=@var{num}}, @samp{END=@var{num}}, where @var{num} is a positive
+integer.
@item
-Empty lines and lines starting with ';' or '#' are ignored.
+Empty lines and lines starting with @samp{;} or @samp{#} are ignored.
@item
-Metadata keys or values containing special characters ('=', ';', '#', '\' and a
-newline) must be escaped with a backslash '\'.
+Metadata keys or values containing special characters (@samp{=}, @samp{;},
+@samp{#}, @samp{\} and a newline) must be escaped with a backslash @samp{\}.
@item
-Note that whitespace in metadata (e.g. foo = bar) is considered to be a part of
-the tag (in the example above key is 'foo ', value is ' bar').
+Note that whitespace in metadata (e.g. @samp{foo = bar}) is considered to be
+a part of the tag (in the example above key is @samp{foo }, value is
+@samp{ bar}).
@end enumerate
A ffmetadata file might look like this:
@@ -53,7 +57,7 @@ A ffmetadata file might look like this:
;FFMETADATA1
title=bike\\shed
;this is a comment
-artist=Libav troll team
+artist=FFmpeg troll team
[CHAPTER]
TIMEBASE=1/1000
@@ -65,4 +69,20 @@ title=chapter \#1
title=multi\
line
@end example
+
+By using the ffmetadata muxer and demuxer it is possible to extract
+metadata from an input file to an ffmetadata file, and then transcode
+the file into an output file with the edited ffmetadata file.
+
+Extracting an ffmetadata file with @file{ffmpeg} goes as follows:
+@example
+ffmpeg -i INPUT -f ffmetadata FFMETADATAFILE
+@end example
+
+Reinserting edited metadata information from the FFMETADATAFILE file can
+be done as:
+@example
+ffmpeg -i INPUT -i FFMETADATAFILE -map_metadata 1 -codec copy OUTPUT
+@end example
+
@c man end METADATA
diff --git a/doc/mips.txt b/doc/mips.txt
new file mode 100644
index 0000000000..8c6779f67d
--- /dev/null
+++ b/doc/mips.txt
@@ -0,0 +1,75 @@
+MIPS optimizations info
+===============================================
+
+MIPS optimizations of codecs are targeting MIPS 74k family of
+CPUs. Some of these optimizations are relying more on properties of
+this architecture and some are relying less (and can be used on most
+MIPS architectures without degradation in performance).
+
+Along with FFMPEG copyright notice, there is MIPS copyright notice in
+all the files that are created by people from MIPS Technologies.
+
+Example of copyright notice:
+===============================================
+/*
+ * 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: Author Name (author_name@@mips.com)
+ */
+
+Files that have MIPS copyright notice in them:
+===============================================
+* libavutil/mips/
+ float_dsp_mips.c
+ libm_mips.h
+* libavcodec/
+ fft_fixed_32.c
+ fft_init_table.c
+ fft_table.h
+ mdct_fixed_32.c
+* libavcodec/mips/
+ aaccoder_mips.c
+ aacpsy_mips.h
+ ac3dsp_mips.c
+ acelp_filters_mips.c
+ acelp_vectors_mips.c
+ amrwbdec_mips.c
+ amrwbdec_mips.h
+ celp_filters_mips.c
+ celp_math_mips.c
+ compute_antialias_fixed.h
+ compute_antialias_float.h
+ lsp_mips.h
+ dsputil_mips.c
+ fft_mips.c
+ fft_table.h
+ fft_init_table.c
+ fmtconvert_mips.c
+ iirfilter_mips.c
+ mpegaudiodsp_mips_fixed.c
+ mpegaudiodsp_mips_float.c
diff --git a/doc/multithreading.txt b/doc/multithreading.txt
index 9b27b108c6..2b992fcbc5 100644
--- a/doc/multithreading.txt
+++ b/doc/multithreading.txt
@@ -1,7 +1,7 @@
-Libav multithreading methods
+FFmpeg multithreading methods
==============================================
-Libav provides two methods for multithreading codecs.
+FFmpeg provides two methods for multithreading codecs.
Slice threading decodes multiple parts of a frame at the same time, using
AVCodecContext execute() and execute2().
diff --git a/doc/muxers.texi b/doc/muxers.texi
index bcfdb49b87..ddd7c7aa10 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1,10 +1,10 @@
@chapter Muxers
@c man begin MUXERS
-Muxers are configured elements in Libav which allow writing
+Muxers are configured elements in FFmpeg which allow writing
multimedia streams to a particular type of file.
-When you configure your Libav build, all the supported muxers
+When you configure your FFmpeg build, all the supported muxers
are enabled by default. You can list all available muxers using the
configure option @code{--list-muxers}.
@@ -13,11 +13,30 @@ You can disable all the muxers with the configure option
with the options @code{--enable-muxer=@var{MUXER}} /
@code{--disable-muxer=@var{MUXER}}.
-The option @code{-formats} of the av* tools will display the list of
+The option @code{-formats} of the ff* tools will display the list of
enabled muxers.
A description of some of the currently available muxers follows.
+@anchor{aiff}
+@section aiff
+
+Audio Interchange File Format muxer.
+
+@subsection Options
+
+It accepts the following options:
+
+@table @option
+@item write_id3v2
+Enable ID3v2 tags writing when set to 1. Default is 0 (disabled).
+
+@item id3v2_version
+Select ID3v2 version to write. Currently only version 3 and 4 (aka.
+ID3v2.3 and ID3v2.4) are supported. The default is version 4.
+
+@end table
+
@anchor{crc}
@section crc
@@ -32,95 +51,267 @@ The output of the muxer consists of a single line of the form:
CRC=0x@var{CRC}, where @var{CRC} is a hexadecimal number 0-padded to
8 digits containing the CRC for all the decoded input frames.
+See also the @ref{framecrc} muxer.
+
+@subsection Examples
+
For example to compute the CRC of the input, and store it in the file
@file{out.crc}:
@example
-avconv -i INPUT -f crc out.crc
+ffmpeg -i INPUT -f crc out.crc
@end example
You can print the CRC to stdout with the command:
@example
-avconv -i INPUT -f crc -
+ffmpeg -i INPUT -f crc -
@end example
-You can select the output format of each frame with @command{avconv} by
+You can select the output format of each frame with @command{ffmpeg} by
specifying the audio and video codec and format. For example to
compute the CRC of the input audio converted to PCM unsigned 8-bit
and the input video converted to MPEG-2 video, use the command:
@example
-avconv -i INPUT -c:a pcm_u8 -c:v mpeg2video -f crc -
+ffmpeg -i INPUT -c:a pcm_u8 -c:v mpeg2video -f crc -
@end example
-See also the @ref{framecrc} muxer.
-
@anchor{framecrc}
@section framecrc
-Per-frame CRC (Cyclic Redundancy Check) testing format.
+Per-packet CRC (Cyclic Redundancy Check) testing format.
-This muxer computes and prints the Adler-32 CRC for each decoded audio
-and video frame. By default audio frames are converted to signed
+This muxer computes and prints the Adler-32 CRC for each audio
+and video packet. By default audio frames are converted to signed
16-bit raw audio and video frames to raw video before computing the
CRC.
The output of the muxer consists of a line for each audio and video
-frame of the form: @var{stream_index}, @var{frame_dts},
-@var{frame_size}, 0x@var{CRC}, where @var{CRC} is a hexadecimal
-number 0-padded to 8 digits containing the CRC of the decoded frame.
+packet of the form:
+@example
+@var{stream_index}, @var{packet_dts}, @var{packet_pts}, @var{packet_duration}, @var{packet_size}, 0x@var{CRC}
+@end example
+
+@var{CRC} is a hexadecimal number 0-padded to 8 digits containing the
+CRC of the packet.
+
+@subsection Examples
-For example to compute the CRC of each decoded frame in the input, and
-store it in the file @file{out.crc}:
+For example to compute the CRC of the audio and video frames in
+@file{INPUT}, converted to raw audio and video packets, and store it
+in the file @file{out.crc}:
@example
-avconv -i INPUT -f framecrc out.crc
+ffmpeg -i INPUT -f framecrc out.crc
@end example
-You can print the CRC of each decoded frame to stdout with the command:
+To print the information to stdout, use the command:
@example
-avconv -i INPUT -f framecrc -
+ffmpeg -i INPUT -f framecrc -
@end example
-You can select the output format of each frame with @command{avconv} by
-specifying the audio and video codec and format. For example, to
+With @command{ffmpeg}, you can select the output format to which the
+audio and video frames are encoded before computing the CRC for each
+packet by specifying the audio and video codec. For example, to
compute the CRC of each decoded input audio frame converted to PCM
unsigned 8-bit and of each decoded input video frame converted to
MPEG-2 video, use the command:
@example
-avconv -i INPUT -c:a pcm_u8 -c:v mpeg2video -f framecrc -
+ffmpeg -i INPUT -c:a pcm_u8 -c:v mpeg2video -f framecrc -
@end example
See also the @ref{crc} muxer.
+@anchor{framemd5}
+@section framemd5
+
+Per-packet MD5 testing format.
+
+This muxer computes and prints the MD5 hash for each audio
+and video packet. By default audio frames are converted to signed
+16-bit raw audio and video frames to raw video before computing the
+hash.
+
+The output of the muxer consists of a line for each audio and video
+packet of the form:
+@example
+@var{stream_index}, @var{packet_dts}, @var{packet_pts}, @var{packet_duration}, @var{packet_size}, @var{MD5}
+@end example
+
+@var{MD5} is a hexadecimal number representing the computed MD5 hash
+for the packet.
+
+@subsection Examples
+
+For example to compute the MD5 of the audio and video frames in
+@file{INPUT}, converted to raw audio and video packets, and store it
+in the file @file{out.md5}:
+@example
+ffmpeg -i INPUT -f framemd5 out.md5
+@end example
+
+To print the information to stdout, use the command:
+@example
+ffmpeg -i INPUT -f framemd5 -
+@end example
+
+See also the @ref{md5} muxer.
+
+@anchor{gif}
+@section gif
+
+Animated GIF muxer.
+
+It accepts the following options:
+
+@table @option
+@item loop
+Set the number of times to loop the output. Use @code{-1} for no loop, @code{0}
+for looping indefinitely (default).
+
+@item final_delay
+Force the delay (expressed in centiseconds) after the last frame. Each frame
+ends with a delay until the next frame. The default is @code{-1}, which is a
+special value to tell the muxer to re-use the previous delay. In case of a
+loop, you might want to customize this value to mark a pause for instance.
+@end table
+
+For example, to encode a gif looping 10 times, with a 5 seconds delay between
+the loops:
+@example
+ffmpeg -i INPUT -loop 10 -final_delay 500 out.gif
+@end example
+
+Note 1: if you wish to extract the frames in separate GIF files, you need to
+force the @ref{image2} muxer:
+@example
+ffmpeg -i INPUT -c:v gif -f image2 "out%d.gif"
+@end example
+
+Note 2: the GIF format has a very small time base: the delay between two frames
+can not be smaller than one centi second.
+
@anchor{hls}
@section hls
Apple HTTP Live Streaming muxer that segments MPEG-TS according to
-the HTTP Live Streaming specification.
+the HTTP Live Streaming (HLS) specification.
-It creates a playlist file and numbered segment files. The output
-filename specifies the playlist filename; the segment filenames
-receive the same basename as the playlist, a sequential number and
-a .ts extension.
+It creates a playlist file, and one or more segment files. The output filename
+specifies the playlist filename.
+By default, the muxer creates a file for each segment produced. These files
+have the same name as the playlist, followed by a sequential number and a
+.ts extension.
+
+For example, to convert an input file with @command{ffmpeg}:
@example
-avconv -i in.nut out.m3u8
+ffmpeg -i in.nut out.m3u8
@end example
+This example will produce the playlist, @file{out.m3u8}, and segment files:
+@file{out0.ts}, @file{out1.ts}, @file{out2.ts}, etc.
+
+See also the @ref{segment} muxer, which provides a more generic and
+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_time @var{seconds}
-Set the segment length in seconds.
-@item -hls_list_size @var{size}
-Set the maximum number of playlist entries.
-@item -hls_wrap @var{wrap}
-Set the number after which index wraps.
-@item -start_number @var{number}
-Start the sequence from @var{number}.
-@item -hls_base_url @var{baseurl}
+@item hls_time @var{seconds}
+Set the segment length in seconds. Default value is 2.
+
+@item hls_list_size @var{size}
+Set the maximum number of playlist entries. If set to 0 the list file
+will contain all the segments. Default value is 5.
+
+@item hls_ts_options @var{options_list}
+Set output format options using a :-separated list of key=value
+parameters. Values containing @code{:} special characters must be
+escaped.
+
+@item hls_wrap @var{wrap}
+Set the number after which the segment filename number (the number
+specified in each segment file) wraps. If set to 0 the number will be
+never wrapped. Default value is 0.
+
+This option is useful to avoid to fill the disk with many segment
+files, and limits the maximum number of segment files written to disk
+to @var{wrap}.
+
+@item start_number @var{number}
+Start the playlist sequence number from @var{number}. Default value is
+0.
+
+@item hls_allow_cache @var{allowcache}
+Explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments.
+
+@item hls_base_url @var{baseurl}
Append @var{baseurl} to every entry in the playlist.
Useful to generate playlists with absolute paths.
-@item -hls_allow_cache @var{allowcache}
-Explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments
+
+Note that the playlist sequence number must be unique for each segment
+and it is not to be confused with the segment filename sequence number
+which can be cyclic, for example if the @option{wrap} option is
+specified.
+
+@item hls_segment_filename @var{filename}
+Set the segment filename. Unless hls_flags single_file is set @var{filename}
+is used as a string format with the segment number:
+@example
+ffmpeg in.nut -hls_segment_filename 'file%03d.ts' out.m3u8
+@end example
+This example will produce the playlist, @file{out.m3u8}, and segment files:
+@file{file000.ts}, @file{file001.ts}, @file{file002.ts}, etc.
+
+@item hls_flags single_file
+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,
+@file{out.ts}.
+
+@item hls_flags delete_segments
+Segment files removed from the playlist are deleted after a period of time
+equal to the duration of the segment plus the duration of the playlist.
@end table
+@anchor{ico}
+@section ico
+
+ICO file muxer.
+
+Microsoft's icon file format (ICO) has some strict limitations that should be noted:
+
+@itemize
+@item
+Size cannot exceed 256 pixels in any dimension
+
+@item
+Only BMP and PNG images can be stored
+
+@item
+If a BMP image is used, it must be one of the following pixel formats:
+@example
+BMP Bit Depth FFmpeg Pixel Format
+1bit pal8
+4bit pal8
+8bit pal8
+16bit rgb555le
+24bit bgr24
+32bit bgra
+@end example
+
+@item
+If a BMP image is used, it must use the BITMAPINFOHEADER DIB header
+
+@item
+If a PNG image is used, it must use the rgba pixel format
+@end itemize
+
@anchor{image2}
@section image2
@@ -151,64 +342,90 @@ The pattern "img%%-%d.jpg" will specify a sequence of filenames of the
form @file{img%-1.jpg}, @file{img%-2.jpg}, ..., @file{img%-10.jpg},
etc.
-The following example shows how to use @command{avconv} for creating a
+@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:
@example
-avconv -i in.avi -vsync 1 -r 1 -f image2 'img-%03d.jpeg'
+ffmpeg -i in.avi -vsync 1 -r 1 -f image2 'img-%03d.jpeg'
@end example
-Note that with @command{avconv}, if the format is not specified with the
+Note that with @command{ffmpeg}, if the format is not specified with the
@code{-f} option and the output filename specifies an image file
format, the image2 muxer is automatically selected, so the previous
command can be written as:
@example
-avconv -i in.avi -vsync 1 -r 1 'img-%03d.jpeg'
+ffmpeg -i in.avi -vsync 1 -r 1 'img-%03d.jpeg'
@end example
Note also that the pattern must not necessarily contain "%d" or
"%0@var{N}d", for example to create a single image file
@file{img.jpeg} from the input video you can employ the command:
@example
-avconv -i in.avi -f image2 -frames:v 1 img.jpeg
+ffmpeg -i in.avi -f image2 -frames:v 1 img.jpeg
@end example
+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:
+@example
+ffmpeg -f v4l2 -r 1 -i /dev/video0 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S.jpg"
+@end example
+
+@subsection Options
+
@table @option
-@item -start_number @var{number}
-Start the sequence from @var{number}.
+@item start_number
+Start the sequence from the specified number. Default value is 0.
-@item -update @var{number}
-If @var{number} is nonzero, the filename will always be interpreted as just a
-filename, not a pattern, and this file will be continuously overwritten with new
-images.
+@item update
+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
+If set to 1, expand the filename with date and time information from
+@code{strftime()}. Default value is 0.
@end table
+The image muxer supports the .Y.U.V image file format. This format is
+special in that that each image frame consists of three files, for
+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.
+
@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
+@item title
+Set title name provided to a single track.
-@item title=@var{title name}
-Name provided to a single track
-@end table
+@item language
+Specify the language of the track in the Matroska languages form.
-@table @option
+The language can be either the 3 letters bibliographic ISO-639-2 (ISO
+639-2/B) form (like "fre" for French), or a language code mixed with a
+country code for specialities in languages (like "fre-ca" for Canadian
+French).
-@item language=@var{language name}
-Specifies the language of the track in the Matroska languages form
-@end table
+@item stereo_mode
+Set stereo 3D video layout of two views in a single video track.
-@table @option
-
-@item STEREO_MODE=@var{mode}
-Stereo 3D video layout of two views in a single video track
-@table @option
+The following values are recognized:
+@table @samp
@item mono
video is not stereo
@item left_right
@@ -244,13 +461,14 @@ Both eyes laced in one Block, Right-eye view is first
For example a 3D WebM clip can be created using the following command line:
@example
-avconv -i sample_left_right_clip.mpg -an -c:v libvpx -metadata STEREO_MODE=left_right -y stereo_clip.webm
+ffmpeg -i sample_left_right_clip.mpg -an -c:v libvpx -metadata stereo_mode=left_right -y stereo_clip.webm
@end example
+@subsection Options
+
This muxer supports the following options:
@table @option
-
@item reserve_index_space
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
@@ -265,15 +483,44 @@ 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.
-
@end table
+@anchor{md5}
+@section md5
+
+MD5 testing format.
+
+This muxer computes and prints the MD5 hash of all the input audio
+and video frames. By default audio frames are converted to signed
+16-bit raw audio and video frames to raw video before computing the
+hash.
+
+The output of the muxer consists of a single line of the form:
+MD5=@var{MD5}, where @var{MD5} is a hexadecimal number representing
+the computed MD5 hash.
+
+For example 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:
+@example
+ffmpeg -i INPUT -f md5 -
+@end example
+
+See also the @ref{framemd5} muxer.
+
@section mov, mp4, ismv
+MOV/MP4/ISMV (Smooth Streaming) muxer.
+
The mov/mp4/ismv muxer supports fragmentation. Normally, a MOV/MP4
file has all the metadata about all packets stored in one location
(written at the end of the file, it can be moved to the start for
-better playback using the @command{qt-faststart} tool). A fragmented
+better playback by adding @var{faststart} to the @var{movflags}, or
+using the @command{qt-faststart} tool). A fragmented
file consists of a number of fragments, where packets and metadata
about these packets are stored together. Writing a fragmented
file has the advantage that the file is decodable even if the
@@ -283,10 +530,15 @@ very long files (since writing normal MOV/MP4 files stores info about
every single packet in memory until the file is closed). The downside
is that it is less compatible with other applications.
+@subsection Options
+
Fragmentation is enabled by setting one of the AVOptions that define
how to cut the file into fragments:
@table @option
+@item -moov_size @var{bytes}
+Reserves space for the moov atom at the beginning of the file instead of placing the
+moov atom at the end. If the space reserved is insufficient, muxing will fail.
@item -movflags frag_keyframe
Start a new fragment at each video keyframe.
@item -frag_duration @var{duration}
@@ -297,7 +549,7 @@ Create fragments that contain up to @var{size} bytes of payload data.
Allow the caller to manually choose when to cut fragments, by
calling @code{av_write_frame(ctx, NULL)} to write a fragment with
the packets written so far. (This is only useful with other
-applications integrating libavformat, not from @command{avconv}.)
+applications integrating libavformat, not from @command{ffmpeg}.)
@item -min_frag_duration @var{duration}
Don't create fragments that are shorter than @var{duration} microseconds long.
@end table
@@ -331,11 +583,14 @@ This option is implicitly set when writing ismv (Smooth Streaming) files.
Run a second pass moving the index (moov atom) to the beginning of the file.
This operation can take a while, and will not work in various situations such
as fragmented output, thus it is not enabled by default.
+@item -movflags rtphint
+Add RTP hinting tracks to the output file.
@item -movflags disable_chpl
Disable Nero chapter markers (chpl atom). Normally, both Nero chapters
and a QuickTime chapter track are written to the file. With this option
set, only the QuickTime chapter track will be written. Nero chapters can
-cause failures when the file is reprocessed with certain tagging programs.
+cause failures when the file is reprocessed with certain tagging programs, like
+mp3Tag 2.61a and iTunes 11.3, most likely other versions are affected as well.
@item -movflags omit_tfhd_offset
Do not write any absolute base_data_offset in tfhd atoms. This avoids
tying fragments to absolute byte positions in the file/streams.
@@ -348,10 +603,12 @@ circumstances (avoiding basing track fragment location calculations
on the implicit end of the previous track fragment).
@end table
+@subsection Example
+
Smooth Streaming content can be pushed in real time to a publishing
point on IIS with this muxer. Example:
@example
-avconv -re @var{<normal input/transcoding options>} -movflags isml+frag_keyframe -f ismv http://server/publishingpoint.isml/Streams(Encoder1)
+ffmpeg -re @var{<normal input/transcoding options>} -movflags isml+frag_keyframe -f ismv http://server/publishingpoint.isml/Streams(Encoder1)
@end example
@section mp3
@@ -392,18 +649,19 @@ Examples:
Write an mp3 with an ID3v2.3 header and an ID3v1 footer:
@example
-avconv -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3
+ffmpeg -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3
@end example
-Attach a picture to an mp3:
+To attach a picture to an mp3 file select both the audio and the picture stream
+with @code{map}:
@example
-avconv -i input.mp3 -i cover.png -c copy -metadata:s:v title="Album cover"
--metadata:s:v comment="Cover (Front)" out.mp3
+ffmpeg -i input.mp3 -i cover.png -c copy -map 0 -map 1
+-metadata:s:v title="Album cover" -metadata:s:v comment="Cover (Front)" out.mp3
@end example
Write a "clean" MP3 without any extra features:
@example
-avconv -i input.wav -write_xing 0 -id3v2_version 0 out.mp3
+ffmpeg -i input.wav -write_xing 0 -id3v2_version 0 out.mp3
@end example
@section mpegts
@@ -412,6 +670,13 @@ MPEG transport stream muxer.
This muxer implements ISO 13818-1 and part of ETSI EN 300 468.
+The recognized metadata settings in mpegts muxer are @code{service_provider}
+and @code{service_name}. If they are not set the default for
+@code{service_provider} is "FFmpeg" and the default for
+@code{service_name} is "Service01".
+
+@subsection Options
+
The muxer options are:
@table @option
@@ -424,24 +689,77 @@ Set the transport_stream_id (default 0x0001). This identifies a
transponder in DVB.
@item -mpegts_service_id @var{number}
Set the service_id (default 0x0001) also known as program in DVB.
+@item -mpegts_service_type @var{number}
+Set the program service_type (default @var{digital_tv}), see below
+a list of pre defined values.
@item -mpegts_pmt_start_pid @var{number}
Set the first PID for PMT (default 0x1000, max 0x1f00).
@item -mpegts_start_pid @var{number}
Set the first PID for data packets (default 0x0100, max 0x0f00).
+@item -mpegts_m2ts_mode @var{number}
+Enable m2ts mode if set to 1. Default value is -1 which disables m2ts mode.
@item -muxrate @var{number}
Set a constant muxrate (default VBR).
@item -pcr_period @var{numer}
Override the default PCR retransmission time (default 20ms), ignored
if variable muxrate is selected.
+@item -pes_payload_size @var{number}
+Set minimum PES packet payload in bytes.
+@item -mpegts_flags @var{flags}
+Set flags (see below).
+@item -mpegts_copyts @var{number}
+Preserve original timestamps, if value is set to 1. Default value is -1, which
+results in shifting timestamps so that they start from 0.
+@item -tables_version @var{number}
+Set PAT, PMT and SDT version (default 0, valid values are from 0 to 31, inclusively).
+This option allows updating stream structure so that standard consumer may
+detect the change. To do so, reopen output AVFormatContext (in case of API
+usage) or restart ffmpeg instance, cyclically changing tables_version value:
+@example
+ffmpeg -i source1.ts -codec copy -f mpegts -tables_version 0 udp://1.1.1.1:1111
+ffmpeg -i source2.ts -codec copy -f mpegts -tables_version 1 udp://1.1.1.1:1111
+...
+ffmpeg -i source3.ts -codec copy -f mpegts -tables_version 31 udp://1.1.1.1:1111
+ffmpeg -i source1.ts -codec copy -f mpegts -tables_version 0 udp://1.1.1.1:1111
+ffmpeg -i source2.ts -codec copy -f mpegts -tables_version 1 udp://1.1.1.1:1111
+...
+@end example
@end table
-The recognized metadata settings in mpegts muxer are @code{service_provider}
-and @code{service_name}. If they are not set the default for
-@code{service_provider} is "Libav" and the default for
-@code{service_name} is "Service01".
+Option mpegts_service_type accepts the following values:
+
+@table @option
+@item hex_value
+Any hexdecimal value between 0x01 to 0xff as defined in ETSI 300 468.
+@item digital_tv
+Digital TV service.
+@item digital_radio
+Digital Radio service.
+@item teletext
+Teletext service.
+@item advanced_codec_digital_radio
+Advanced Codec Digital Radio service.
+@item mpeg2_digital_hdtv
+MPEG2 Digital HDTV service.
+@item advanced_codec_digital_sdtv
+Advanced Codec Digital SDTV service.
+@item advanced_codec_digital_hdtv
+Advanced Codec Digital HDTV service.
+@end table
+
+Option mpegts_flags may take a set of such flags:
+
+@table @option
+@item resend_headers
+Reemit PAT/PMT before writing the next packet.
+@item latm
+Use LATM packetization for AAC.
+@end table
+
+@subsection Example
@example
-avconv -i file.mpg -c copy \
+ffmpeg -i file.mpg -c copy \
-mpegts_original_network_id 0x1122 \
-mpegts_transport_stream_id 0x3344 \
-mpegts_service_id 0x5566 \
@@ -459,19 +777,19 @@ Null muxer.
This muxer does not generate any output file, it is mainly useful for
testing or benchmarking purposes.
-For example to benchmark decoding with @command{avconv} you can use the
+For example to benchmark decoding with @command{ffmpeg} you can use the
command:
@example
-avconv -benchmark -i INPUT -f null out.null
+ffmpeg -benchmark -i INPUT -f null out.null
@end example
Note that the above command does not read or write the @file{out.null}
-file, but specifying the output file is required by the @command{avconv}
+file, but specifying the output file is required by the @command{ffmpeg}
syntax.
Alternatively you can write the command as:
@example
-avconv -benchmark -i INPUT -f null -
+ffmpeg -benchmark -i INPUT -f null -
@end example
@section nut
@@ -482,13 +800,20 @@ Change the syncpoint usage in nut:
@table @option
@item @var{default} use the normal low-overhead seeking aids.
@item @var{none} do not use the syncpoints at all, reducing the overhead but making the stream non-seekable;
+ Use of this option is not recommended, as the resulting files are very damage
+ sensitive and seeking is not possible. Also in general the overhead from
+ syncpoints is negligible. Note, -@code{write_index} 0 can be used to disable
+ all growing data tables, allowing to mux endless streams with limited memory
+ and without these disadvantages.
@item @var{timestamped} extend the syncpoint with a wallclock field.
@end table
The @var{none} and @var{timestamped} flags are experimental.
+@item -write_index @var{bool}
+Write index at the end, the default is to write an index.
@end table
@example
-avconv -i INPUT -f_strict experimental -syncpoints none - | processor
+ffmpeg -i INPUT -f_strict experimental -syncpoints none - | processor
@end example
@section ogg
@@ -511,44 +836,483 @@ ogg files can be safely chained.
@end table
-@section segment
+@anchor{segment}
+@section segment, stream_segment, ssegment
Basic stream segmenter.
-The segmenter muxer outputs streams to a number of separate files of nearly
-fixed duration. Output filename pattern can be set in a fashion similar to
-@ref{image2}.
+This muxer outputs streams to a number of separate files of nearly
+fixed duration. Output filename pattern can be set in a fashion
+similar to @ref{image2}, or by using a @code{strftime} template if
+the @option{strftime} option is enabled.
+
+@code{stream_segment} is a variant of the muxer used to write to
+streaming output formats, i.e. which do not require global headers,
+and is recommended for outputting e.g. to MPEG transport stream segments.
+@code{ssegment} is a shorter alias for @code{stream_segment}.
+
+Every segment starts with a keyframe of the selected reference stream,
+which is set through the @option{reference_stream} option.
+
+Note that if you want accurate splitting for a video file, you need to
+make the input key frames correspond to the exact splitting times
+expected by the segmenter, or the segment muxer will start the new
+segment with the key frame found next after the specified start
+time.
-Every segment starts with a video keyframe, if a video stream is present.
The segment muxer works best with a single constant frame rate video.
-Optionally it can generate a flat list of the created segments, one segment
-per line.
+Optionally it can generate a list of the created segments, by setting
+the option @var{segment_list}. The list type is specified by the
+@var{segment_list_type} option. The entry filenames in the segment
+list are set by default to the basename of the corresponding segment
+files.
+
+See also the @ref{hls} muxer, which provides a more specific
+implementation for HLS segmentation.
+
+@subsection Options
+
+The segment muxer supports the following options:
@table @option
+@item reference_stream @var{specifier}
+Set the reference stream, as specified by the string @var{specifier}.
+If @var{specifier} is set to @code{auto}, the reference is chosen
+automatically. Otherwise it must be a stream specifier (see the ``Stream
+specifiers'' chapter in the ffmpeg manual) which specifies the
+reference stream. The default value is @code{auto}.
+
@item segment_format @var{format}
Override the inner container format, by default it is guessed by the filename
extension.
-@item segment_time @var{t}
-Set segment duration to @var{t} seconds.
+
+@item segment_format_options @var{options_list}
+Set output format options using a :-separated list of key=value
+parameters. Values containing the @code{:} special character must be
+escaped.
+
@item segment_list @var{name}
-Generate also a listfile named @var{name}.
+Generate also a listfile named @var{name}. If not specified no
+listfile is generated.
+
+@item segment_list_flags @var{flags}
+Set flags affecting the segment list generation.
+
+It currently supports the following flags:
+@table @samp
+@item cache
+Allow caching (only affects M3U8 list files).
+
+@item live
+Allow live-friendly file generation.
+@end table
+
@item segment_list_type @var{type}
Select the listing format.
@table @option
@item @var{flat} use a simple flat list of entries.
@item @var{hls} use a m3u8-like structure.
@end table
+
@item segment_list_size @var{size}
-Overwrite the listfile once it reaches @var{size} entries.
+Update the list file so that it contains at most @var{size}
+segments. If 0 the list file will contain all the segments. Default
+value is 0.
+
@item segment_list_entry_prefix @var{prefix}
Prepend @var{prefix} to each entry. Useful to generate absolute paths.
+By default no prefix is applied.
+
+The following values are recognized:
+@table @samp
+@item flat
+Generate a flat list for the created segments, one segment per line.
+
+@item csv, ext
+Generate a list for the created segments, one segment per line,
+each line matching the format (comma-separated values):
+@example
+@var{segment_filename},@var{segment_start_time},@var{segment_end_time}
+@end example
+
+@var{segment_filename} is the name of the output file generated by the
+muxer according to the provided pattern. CSV escaping (according to
+RFC4180) is applied if required.
+
+@var{segment_start_time} and @var{segment_end_time} specify
+the segment start and end time expressed in seconds.
+
+A list file with the suffix @code{".csv"} or @code{".ext"} will
+auto-select this format.
+
+@samp{ext} is deprecated in favor or @samp{csv}.
+
+@item ffconcat
+Generate an ffconcat file for the created segments. The resulting file
+can be read using the FFmpeg @ref{concat} demuxer.
+
+A list file with the suffix @code{".ffcat"} or @code{".ffconcat"} will
+auto-select this format.
+
+@item m3u8
+Generate an extended M3U8 file, version 3, compliant with
+@url{http://tools.ietf.org/id/draft-pantos-http-live-streaming}.
+
+A list file with the suffix @code{".m3u8"} will auto-select this format.
+@end table
+
+If not specified the type is guessed from the list file name suffix.
+
+@item segment_time @var{time}
+Set segment duration to @var{time}, the value must be a duration
+specification. Default value is "2". See also the
+@option{segment_times} option.
+
+Note that splitting may not be accurate, unless you force the
+reference stream key-frames at the given time. See the introductory
+notice and the examples below.
+
+@item segment_atclocktime @var{1|0}
+If set to "1" split at regular clock time intervals starting from 00:00
+o'clock. The @var{time} value specified in @option{segment_time} is
+used for setting the length of the splitting interval.
+
+For example with @option{segment_time} set to "900" this makes it possible
+to create files at 12:00 o'clock, 12:15, 12:30, etc.
+
+Default value is "0".
+
+@item segment_time_delta @var{delta}
+Specify the accuracy time when selecting the start time for a
+segment, expressed as a duration specification. Default value is "0".
+
+When delta is specified a key-frame will start a new segment if its
+PTS satisfies the relation:
+@example
+PTS >= start_time - time_delta
+@end example
+
+This option is useful when splitting video content, which is always
+split at GOP boundaries, in case a key frame is found just before the
+specified split time.
+
+In particular may be used in combination with the @file{ffmpeg} option
+@var{force_key_frames}. The key frame times specified by
+@var{force_key_frames} may not be set accurately because of rounding
+issues, with the consequence that a key frame time may result set just
+before the specified time. For constant frame rate videos a value of
+1/(2*@var{frame_rate}) should address the worst case mismatch between
+the specified time and the time set by @var{force_key_frames}.
+
+@item segment_times @var{times}
+Specify a list of split points. @var{times} contains a list of comma
+separated duration specifications, in increasing order. See also
+the @option{segment_time} option.
+
+@item segment_frames @var{frames}
+Specify a list of split video frame numbers. @var{frames} contains a
+list of comma separated integer numbers, in increasing order.
+
+This option specifies to start a new segment whenever a reference
+stream key frame is found and the sequential number (starting from 0)
+of the frame is greater or equal to the next value in the list.
+
@item segment_wrap @var{limit}
Wrap around segment index once it reaches @var{limit}.
+
+@item segment_start_number @var{number}
+Set the sequence number of the first segment. Defaults to @code{0}.
+
+@item strftime @var{1|0}
+Use the @code{strftime} function to define the name of the new
+segments to write. If this is selected, the output segment name must
+contain a @code{strftime} function template. Default value is
+@code{0}.
+
+@item reset_timestamps @var{1|0}
+Reset timestamps at the begin of each segment, so that each segment
+will start with near-zero timestamps. It is meant to ease the playback
+of the generated segments. May not work with some combinations of
+muxers/codecs. It is set to @code{0} by default.
+
+@item initial_offset @var{offset}
+Specify timestamp offset to apply to the output packet timestamps. The
+argument must be a time duration specification, and defaults to 0.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Remux the content of file @file{in.mkv} to a list of segments
+@file{out-000.nut}, @file{out-001.nut}, etc., and write the list of
+generated segments to @file{out.list}:
+@example
+ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.list out%03d.nut
+@end example
+
+@item
+Segment input and set output format options for the output segments:
+@example
+ffmpeg -i in.mkv -f segment -segment_time 10 -segment_format_options movflags=+faststart out%03d.mp4
+@end example
+
+@item
+Segment the input file according to the split points specified by the
+@var{segment_times} option:
+@example
+ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.csv -segment_times 1,2,3,5,8,13,21 out%03d.nut
+@end example
+
+@item
+Use the @command{ffmpeg} @option{force_key_frames}
+option to force key frames in the input at the specified location, together
+with the segment option @option{segment_time_delta} to account for
+possible roundings operated when setting key frame times.
+@example
+ffmpeg -i in.mkv -force_key_frames 1,2,3,5,8,13,21 -codec:v mpeg4 -codec:a pcm_s16le -map 0 \
+-f segment -segment_list out.csv -segment_times 1,2,3,5,8,13,21 -segment_time_delta 0.05 out%03d.nut
+@end example
+In order to force key frames on the input file, transcoding is
+required.
+
+@item
+Segment the input file by splitting the input file according to the
+frame numbers sequence specified with the @option{segment_frames} option:
+@example
+ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.csv -segment_frames 100,200,300,500,800 out%03d.nut
+@end example
+
+@item
+Convert the @file{in.mkv} to TS segments using the @code{libx264}
+and @code{libfaac} encoders:
+@example
+ffmpeg -i in.mkv -map 0 -codec:v libx264 -codec:a libfaac -f ssegment -segment_list out.list out%03d.ts
+@end example
+
+@item
+Segment the input file, and create an M3U8 live playlist (can be used
+as live HLS source):
+@example
+ffmpeg -re -i in.mkv -codec copy -map 0 -f segment -segment_list playlist.m3u8 \
+-segment_list_flags +live -segment_time 10 out%03d.mkv
+@end example
+@end itemize
+
+@section smoothstreaming
+
+Smooth Streaming muxer generates a set of files (Manifest, chunks) suitable for serving with conventional web server.
+
+@table @option
+@item window_size
+Specify the number of fragments kept in the manifest. Default 0 (keep all).
+
+@item extra_window_size
+Specify the number of fragments kept outside of the manifest before removing from disk. Default 5.
+
+@item lookahead_count
+Specify the number of lookahead fragments. Default 2.
+
+@item min_frag_duration
+Specify the minimum fragment duration (in microseconds). Default 5000000.
+
+@item remove_at_exit
+Specify whether to remove all fragments when finished. Default 0 (do not remove).
+
+@end table
+
+@section tee
+
+The tee muxer can be used to write the same data to several files or any
+other kind of muxer. It can be used, for example, to both stream a video to
+the network and save it to disk at the same time.
+
+It is different from specifying several outputs to the @command{ffmpeg}
+command-line tool because the audio and video data will be encoded only once
+with the tee muxer; encoding can be a very expensive process. It is not
+useful when using the libavformat API directly because it is then possible
+to feed the same packets to several muxers directly.
+
+The slave outputs are specified in the file name given to the muxer,
+separated by '|'. If any of the slave name contains the '|' separator,
+leading or trailing spaces or any special character, it must be
+escaped (see @ref{quoting_and_escaping,,the "Quoting and escaping"
+section in the ffmpeg-utils(1) manual,ffmpeg-utils}).
+
+Muxer options can be specified for each slave by prepending them as a list of
+@var{key}=@var{value} pairs separated by ':', between square brackets. If
+the options values contain a special character or the ':' separator, they
+must be escaped; note that this is a second level escaping.
+
+The following special options are also recognized:
+@table @option
+@item f
+Specify the format name. Useful if it cannot be guessed from the
+output name suffix.
+
+@item bsfs[/@var{spec}]
+Specify a list of bitstream filters to apply to the specified
+output.
+
+It is possible to specify to which streams a given bitstream filter
+applies, by appending a stream specifier to the option separated by
+@code{/}. @var{spec} must be a stream specifier (see @ref{Format
+stream specifiers}). If the stream specifier is not specified, the
+bitstream filters will be applied to all streams in the output.
+
+Several bitstream filters can be specified, separated by ",".
+
+@item select
+Select the streams that should be mapped to the slave output,
+specified by a stream specifier. If not specified, this defaults to
+all the input streams.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+Encode something and both archive it in a WebM file and stream it
+as MPEG-TS over UDP (the streams need to be explicitly mapped):
+@example
+ffmpeg -i ... -c:v libx264 -c:a mp2 -f tee -map 0:v -map 0:a
+ "archive-20121107.mkv|[f=mpegts]udp://10.0.1.255:1234/"
+@end example
+
+@item
+Use @command{ffmpeg} to encode the input, and send the output
+to three different destinations. The @code{dump_extra} bitstream
+filter is used to add extradata information to all the output video
+keyframes packets, as requested by the MPEG-TS format. The select
+option is applied to @file{out.aac} in order to make it contain only
+audio packets.
+@example
+ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac -strict experimental
+ -f tee "[bsfs/v=dump_extra]out.ts|[movflags=+faststart]out.mp4|[select=a]out.aac"
+@end example
+
+@item
+As below, but select only stream @code{a:1} for the audio output. Note
+that a second level escaping must be performed, as ":" is a special
+character used to separate options.
+@example
+ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac -strict experimental
+ -f tee "[bsfs/v=dump_extra]out.ts|[movflags=+faststart]out.mp4|[select=\'a:1\']out.aac"
+@end example
+@end itemize
+
+Note: some codecs may need different options depending on the output format;
+the auto-detection of this can not work with the tee muxer. The main example
+is the @option{global_header} flag.
+
+@section webm_dash_manifest
+
+WebM DASH Manifest muxer.
+
+This muxer implements the WebM DASH Manifest specification to generate the DASH
+manifest XML. It also supports manifest generation for DASH live streams.
+
+For more information see:
+
+@itemize @bullet
+@item
+WebM DASH Specification: @url{https://sites.google.com/a/webmproject.org/wiki/adaptive-streaming/webm-dash-specification}
+@item
+ISO DASH Specification: @url{http://standards.iso.org/ittf/PubliclyAvailableStandards/c065274_ISO_IEC_23009-1_2014.zip}
+@end itemize
+
+@subsection Options
+
+This muxer supports the following options:
+
+@table @option
+@item adaptation_sets
+This option has the following syntax: "id=x,streams=a,b,c id=y,streams=d,e" where x and y are the
+unique identifiers of the adaptation sets and a,b,c,d and e are the indices of the corresponding
+audio and video streams. Any number of adaptation sets can be added using this option.
+
+@item live
+Set this to 1 to create a live stream DASH Manifest. Default: 0.
+
+@item chunk_start_index
+Start index of the first chunk. This will go in the @samp{startNumber} attribute
+of the @samp{SegmentTemplate} element in the manifest. Default: 0.
+
+@item chunk_duration_ms
+Duration of each chunk in milliseconds. This will go in the @samp{duration}
+attribute of the @samp{SegmentTemplate} element in the manifest. Default: 1000.
+
+@item utc_timing_url
+URL of the page that will return the UTC timestamp in ISO format. This will go
+in the @samp{value} attribute of the @samp{UTCTiming} element in the manifest.
+Default: None.
+
+@item time_shift_buffer_depth
+Smallest time (in seconds) shifting buffer for which any Representation is
+guaranteed to be available. This will go in the @samp{timeShiftBufferDepth}
+attribute of the @samp{MPD} element. Default: 60.
+
+@item minimum_update_period
+Minimum update period (in seconds) of the manifest. This will go in the
+@samp{minimumUpdatePeriod} attribute of the @samp{MPD} element. Default: 0.
+
+@end table
+
+@subsection Example
+@example
+ffmpeg -f webm_dash_manifest -i video1.webm \
+ -f webm_dash_manifest -i video2.webm \
+ -f webm_dash_manifest -i audio1.webm \
+ -f webm_dash_manifest -i audio2.webm \
+ -map 0 -map 1 -map 2 -map 3 \
+ -c copy \
+ -f webm_dash_manifest \
+ -adaptation_sets "id=0,streams=0,1 id=1,streams=2,3" \
+ manifest.xml
+@end example
+
+@section webm_chunk
+
+WebM Live Chunk Muxer.
+
+This muxer writes out WebM headers and chunks as separate files which can be
+consumed by clients that support WebM Live streams via DASH.
+
+@subsection Options
+
+This muxer supports the following options:
+
+@table @option
+@item chunk_start_index
+Index of the first chunk (defaults to 0).
+
+@item header
+Filename of the header where the initialization data will be written.
+
+@item audio_chunk_duration
+Duration of each audio chunk in milliseconds (defaults to 5000).
@end table
+@subsection Example
@example
-avconv -i in.mkv -c copy -map 0 -f segment -list out.list out%03d.nut
+ffmpeg -f v4l2 -i /dev/video0 \
+ -f alsa -i hw:0 \
+ -map 0:0 \
+ -c:v libvpx-vp9 \
+ -s 640x360 -keyint_min 30 -g 30 \
+ -f webm_chunk \
+ -header webm_live_video_360.hdr \
+ -chunk_start_index 1 \
+ webm_live_video_360_%d.chk \
+ -map 1:0 \
+ -c:a libvorbis \
+ -b:a 128k \
+ -f webm_chunk \
+ -header webm_live_audio_128.hdr \
+ -chunk_start_index 1 \
+ -audio_chunk_duration 1000 \
+ webm_live_audio_128_%d.chk
@end example
@c man end MUXERS
diff --git a/doc/nut.texi b/doc/nut.texi
index 042c88a3ab..a02f86ace0 100644
--- a/doc/nut.texi
+++ b/doc/nut.texi
@@ -1,4 +1,5 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
@settitle NUT
@@ -17,6 +18,10 @@ subtitle and user-defined streams in a simple, yet efficient, way.
It was created by a group of FFmpeg and MPlayer developers in 2003
and was finalized in 2008.
+The official nut specification is at svn://svn.mplayerhq.hu/nut
+In case of any differences between this text and the official specification,
+the official specification shall prevail.
+
@chapter Modes
NUT has some variants signaled by using the flags field in its main header.
@@ -130,6 +135,7 @@ PFD[32] would for example be signed 32 bit little-endian IEEE float
@item RV20 @tab RealVideo 2.0
@item RV30 @tab RealVideo 3.0
@item RV40 @tab RealVideo 4.0
+@item SNOW @tab FFmpeg Snow
@item SVQ1 @tab Sorenson Video 1
@item SVQ3 @tab Sorenson Video 3
@item theo @tab Xiph Theora
diff --git a/doc/optimization.txt b/doc/optimization.txt
index b3dca645a8..1a0b98cd0e 100644
--- a/doc/optimization.txt
+++ b/doc/optimization.txt
@@ -17,15 +17,15 @@ Understanding these overoptimized functions:
As many functions tend to be a bit difficult to understand because
of optimizations, it can be hard to optimize them further, or write
architecture-specific versions. It is recommended to look at older
-revisions of the interesting files (web frontends for the various Libav
-branches are listed at http://libav.org/download.html).
+revisions of the interesting files (web frontends for the various FFmpeg
+branches are listed at http://ffmpeg.org/download.html).
Alternatively, look into the other architecture-specific versions in
the x86/, ppc/, alpha/ subdirectories. Even if you don't exactly
comprehend the instructions, it could help understanding the functions
and how they can be optimized.
NOTE: If you still don't understand some function, ask at our mailing list!!!
-(https://lists.libav.org/mailman/listinfo/libav-devel)
+(http://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel)
When is an optimization justified?
@@ -191,11 +191,16 @@ __asm__() block.
Use external asm (nasm/yasm) or inline asm (__asm__()), do not use intrinsics.
The latter requires a good optimizing compiler which gcc is not.
+When debugging a x86 external asm compilation issue, if lost in the macro
+expansions, add DBG=1 to your make command-line: the input file will be
+preprocessed, stripped of the debug/empty lines, then compiled, showing the
+actual lines causing issues.
+
Inline asm vs. external asm
---------------------------
Both inline asm (__asm__("..") in a .c file, handled by a compiler such as gcc)
and external asm (.s or .asm files, handled by an assembler such as yasm/nasm)
-are accepted in Libav. Which one to use differs per specific case.
+are accepted in FFmpeg. Which one to use differs per specific case.
- if your code is intended to be inlined in a C function, inline asm is always
better, because external asm cannot be inlined
diff --git a/doc/outdevs.texi b/doc/outdevs.texi
index dd7bd6475d..e68653fd7a 100644
--- a/doc/outdevs.texi
+++ b/doc/outdevs.texi
@@ -1,10 +1,10 @@
@chapter Output Devices
@c man begin OUTPUT DEVICES
-Output devices are configured elements in Libav which allow to write
+Output devices are configured elements in FFmpeg that can write
multimedia data to an output device attached to your system.
-When you configure your Libav build, all the supported output devices
+When you configure your FFmpeg build, all the supported output devices
are enabled by default. You can list all available ones using the
configure option "--list-outdevs".
@@ -13,8 +13,8 @@ You can disable all the output devices using the configure option
option "--enable-outdev=@var{OUTDEV}", or you can disable a particular
input device using the option "--disable-outdev=@var{OUTDEV}".
-The option "-formats" of the av* tools will display the list of
-enabled output devices (amongst the muxers).
+The option "-devices" of the ff* tools will display the list of
+enabled output devices.
A description of the currently available output devices follows.
@@ -22,12 +22,429 @@ A description of the currently available output devices follows.
ALSA (Advanced Linux Sound Architecture) output device.
+@subsection Examples
+
+@itemize
+@item
+Play a file on default ALSA device:
+@example
+ffmpeg -i INPUT -f alsa default
+@end example
+
+@item
+Play a file on soundcard 1, audio device 7:
+@example
+ffmpeg -i INPUT -f alsa hw:1,7
+@end example
+@end itemize
+
+@section caca
+
+CACA output device.
+
+This output device allows one to show a video stream in CACA window.
+Only one CACA window is allowed per application, so you can
+have only one instance of this output device in an application.
+
+To enable this output device you need to configure FFmpeg with
+@code{--enable-libcaca}.
+libcaca is a graphics library that outputs text instead of pixels.
+
+For more information about libcaca, check:
+@url{http://caca.zoy.org/wiki/libcaca}
+
+@subsection Options
+
+@table @option
+
+@item window_title
+Set the CACA window title, if not specified default to the filename
+specified for the output device.
+
+@item window_size
+Set the CACA window size, can be a string of the form
+@var{width}x@var{height} or a video size abbreviation.
+If not specified it defaults to the size of the input video.
+
+@item driver
+Set display driver.
+
+@item algorithm
+Set dithering algorithm. Dithering is necessary
+because the picture being rendered has usually far more colours than
+the available palette.
+The accepted values are listed with @code{-list_dither algorithms}.
+
+@item antialias
+Set antialias method. Antialiasing smoothens the rendered
+image and avoids the commonly seen staircase effect.
+The accepted values are listed with @code{-list_dither antialiases}.
+
+@item charset
+Set which characters are going to be used when rendering text.
+The accepted values are listed with @code{-list_dither charsets}.
+
+@item color
+Set color to be used when rendering text.
+The accepted values are listed with @code{-list_dither colors}.
+
+@item list_drivers
+If set to @option{true}, print a list of available drivers and exit.
+
+@item list_dither
+List available dither options related to the argument.
+The argument must be one of @code{algorithms}, @code{antialiases},
+@code{charsets}, @code{colors}.
+@end table
+
+@subsection Examples
+
+@itemize
+@item
+The following command shows the @command{ffmpeg} output is an
+CACA window, forcing its size to 80x25:
+@example
+ffmpeg -i INPUT -vcodec rawvideo -pix_fmt rgb24 -window_size 80x25 -f caca -
+@end example
+
+@item
+Show the list of available drivers and exit:
+@example
+ffmpeg -i INPUT -pix_fmt rgb24 -f caca -list_drivers true -
+@end example
+
+@item
+Show the list of available dither colors and exit:
+@example
+ffmpeg -i INPUT -pix_fmt rgb24 -f caca -list_dither colors -
+@end example
+@end itemize
+
+@section decklink
+
+The decklink output device provides playback capabilities for Blackmagic
+DeckLink devices.
+
+To enable this output device, you need the Blackmagic DeckLink SDK and you
+need to configure with the appropriate @code{--extra-cflags}
+and @code{--extra-ldflags}.
+On Windows, you need to run the IDL files through @command{widl}.
+
+DeckLink is very picky about the formats it supports. Pixel format is always
+uyvy422, framerate and video size must be determined for your device with
+@command{-list_formats 1}. Audio sample rate is always 48 kHz.
+
+@subsection Options
+
+@table @option
+
+@item list_devices
+If set to @option{true}, print a list of devices and exit.
+Defaults to @option{false}.
+
+@item list_formats
+If set to @option{true}, print a list of supported formats and exit.
+Defaults to @option{false}.
+
+@item preroll
+Amount of time to preroll video in seconds.
+Defaults to @option{0.5}.
+
+@end table
+
+@subsection Examples
+
+@itemize
+
+@item
+List output devices:
+@example
+ffmpeg -i test.avi -f decklink -list_devices 1 dummy
+@end example
+
+@item
+List supported formats:
+@example
+ffmpeg -i test.avi -f decklink -list_formats 1 'DeckLink Mini Monitor'
+@end example
+
+@item
+Play video clip:
+@example
+ffmpeg -i test.avi -f decklink -pix_fmt uyvy422 'DeckLink Mini Monitor'
+@end example
+
+@item
+Play video clip with non-standard framerate or video size:
+@example
+ffmpeg -i test.avi -f decklink -pix_fmt uyvy422 -s 720x486 -r 24000/1001 'DeckLink Mini Monitor'
+@end example
+
+@end itemize
+
+@section fbdev
+
+Linux framebuffer output device.
+
+The Linux framebuffer is a graphic hardware-independent abstraction
+layer to show graphics on a computer monitor, typically on the
+console. It is accessed through a file device node, usually
+@file{/dev/fb0}.
+
+For more detailed information read the file
+@file{Documentation/fb/framebuffer.txt} included in the Linux source tree.
+
+@subsection Options
+@table @option
+
+@item xoffset
+@item yoffset
+Set x/y coordinate of top left corner. Default is 0.
+@end table
+
+@subsection Examples
+Play a file on framebuffer device @file{/dev/fb0}.
+Required pixel format depends on current framebuffer settings.
+@example
+ffmpeg -re -i INPUT -vcodec rawvideo -pix_fmt bgra -f fbdev /dev/fb0
+@end example
+
+See also @url{http://linux-fbdev.sourceforge.net/}, and fbset(1).
+
+@section opengl
+OpenGL output device.
+
+To enable this output device you need to configure FFmpeg with @code{--enable-opengl}.
+
+This output device allows one to render to OpenGL context.
+Context may be provided by application or default SDL window is created.
+
+When device renders to external context, application must implement handlers for following messages:
+@code{AV_DEV_TO_APP_CREATE_WINDOW_BUFFER} - create OpenGL context on current thread.
+@code{AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER} - make OpenGL context current.
+@code{AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER} - swap buffers.
+@code{AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER} - destroy OpenGL context.
+Application is also required to inform a device about current resolution by sending @code{AV_APP_TO_DEV_WINDOW_SIZE} message.
+
+@subsection Options
+@table @option
+
+@item background
+Set background color. Black is a default.
+@item no_window
+Disables default SDL window when set to non-zero value.
+Application must provide OpenGL context and both @code{window_size_cb} and @code{window_swap_buffers_cb} callbacks when set.
+@item window_title
+Set the SDL window title, if not specified default to the filename specified for the output device.
+Ignored when @option{no_window} is set.
+@item window_size
+Set preferred window size, can be a string of the form widthxheight or a video size abbreviation.
+If not specified it defaults to the size of the input video, downscaled according to the aspect ratio.
+Mostly usable when @option{no_window} is not set.
+
+@end table
+
+@subsection Examples
+Play a file on SDL window using OpenGL rendering:
+@example
+ffmpeg -i INPUT -f opengl "window title"
+@end example
+
@section oss
OSS (Open Sound System) output device.
+@section pulse
+
+PulseAudio output device.
+
+To enable this output device you need to configure FFmpeg with @code{--enable-libpulse}.
+
+More information about PulseAudio can be found on @url{http://www.pulseaudio.org}
+
+@subsection Options
+@table @option
+
+@item server
+Connect to a specific PulseAudio server, specified by an IP address.
+Default server is used when not provided.
+
+@item name
+Specify the application name PulseAudio will use when showing active clients,
+by default it is the @code{LIBAVFORMAT_IDENT} string.
+
+@item stream_name
+Specify the stream name PulseAudio will use when showing active streams,
+by default it is set to the specified output name.
+
+@item device
+Specify the device to use. Default device is used when not provided.
+List of output devices can be obtained with command @command{pactl list sinks}.
+
+@item buffer_size
+@item buffer_duration
+Control the size and duration of the PulseAudio buffer. A small buffer
+gives more control, but requires more frequent updates.
+
+@option{buffer_size} specifies size in bytes while
+@option{buffer_duration} specifies duration in milliseconds.
+
+When both options are provided then the highest value is used
+(duration is recalculated to bytes using stream parameters). If they
+are set to 0 (which is default), the device will use the default
+PulseAudio duration value. By default PulseAudio set buffer duration
+to around 2 seconds.
+
+@item prebuf
+Specify pre-buffering size in bytes. The server does not start with
+playback before at least @option{prebuf} bytes are available in the
+buffer. By default this option is initialized to the same value as
+@option{buffer_size} or @option{buffer_duration} (whichever is bigger).
+
+@item minreq
+Specify minimum request size in bytes. The server does not request less
+than @option{minreq} bytes from the client, instead waits until the buffer
+is free enough to request more bytes at once. It is recommended to not set
+this option, which will initialize this to a value that is deemed sensible
+by the server.
+
+@end table
+
+@subsection Examples
+Play a file on default device on default server:
+@example
+ffmpeg -i INPUT -f pulse "stream name"
+@end example
+
+@section sdl
+
+SDL (Simple DirectMedia Layer) output device.
+
+This output device allows one to show a video stream in an SDL
+window. Only one SDL window is allowed per application, so you can
+have only one instance of this output device in an application.
+
+To enable this output device you need libsdl installed on your system
+when configuring your build.
+
+For more information about SDL, check:
+@url{http://www.libsdl.org/}
+
+@subsection Options
+
+@table @option
+
+@item window_title
+Set the SDL window title, if not specified default to the filename
+specified for the output device.
+
+@item icon_title
+Set the name of the iconified SDL window, if not specified it is set
+to the same value of @var{window_title}.
+
+@item window_size
+Set the SDL window size, can be a string of the form
+@var{width}x@var{height} or a video size abbreviation.
+If not specified it defaults to the size of the input video,
+downscaled according to the aspect ratio.
+
+@item window_fullscreen
+Set fullscreen mode when non-zero value is provided.
+Default value is zero.
+@end table
+
+@subsection Interactive commands
+
+The window created by the device can be controlled through the
+following interactive commands.
+
+@table @key
+@item q, ESC
+Quit the device immediately.
+@end table
+
+@subsection Examples
+
+The following command shows the @command{ffmpeg} output is an
+SDL window, forcing its size to the qcif format:
+@example
+ffmpeg -i INPUT -vcodec rawvideo -pix_fmt yuv420p -window_size qcif -f sdl "SDL output"
+@end example
+
@section sndio
sndio audio output device.
+@section xv
+
+XV (XVideo) output device.
+
+This output device allows one to show a video stream in a X Window System
+window.
+
+@subsection Options
+
+@table @option
+@item display_name
+Specify the hardware display name, which determines the display and
+communications domain to be used.
+
+The display name or DISPLAY environment variable can be a string in
+the format @var{hostname}[:@var{number}[.@var{screen_number}]].
+
+@var{hostname} specifies the name of the host machine on which the
+display is physically attached. @var{number} specifies the number of
+the display server on that host machine. @var{screen_number} specifies
+the screen to be used on that server.
+
+If unspecified, it defaults to the value of the DISPLAY environment
+variable.
+
+For example, @code{dual-headed:0.1} would specify screen 1 of display
+0 on the machine named ``dual-headed''.
+
+Check the X11 specification for more detailed information about the
+display name format.
+
+@item window_id
+When set to non-zero value then device doesn't create new window,
+but uses existing one with provided @var{window_id}. By default
+this options is set to zero and device creates its own window.
+
+@item window_size
+Set the created window size, can be a string of the form
+@var{width}x@var{height} or a video size abbreviation. If not
+specified it defaults to the size of the input video.
+Ignored when @var{window_id} is set.
+
+@item window_x
+@item window_y
+Set the X and Y window offsets for the created window. They are both
+set to 0 by default. The values may be ignored by the window manager.
+Ignored when @var{window_id} is set.
+
+@item window_title
+Set the window title, if not specified default to the filename
+specified for the output device. Ignored when @var{window_id} is set.
+@end table
+
+For more information about XVideo see @url{http://www.x.org/}.
+
+@subsection Examples
+
+@itemize
+@item
+Decode, display and encode video input with @command{ffmpeg} at the
+same time:
+@example
+ffmpeg -i INPUT OUTPUT -f xv display
+@end example
+
+@item
+Decode and display the input video to multiple X11 windows:
+@example
+ffmpeg -i INPUT -f xv normal -vf negate -f xv negated
+@end example
+@end itemize
+
@c man end OUTPUT DEVICES
diff --git a/doc/platform.texi b/doc/platform.texi
index edd75770d6..705a68006f 100644
--- a/doc/platform.texi
+++ b/doc/platform.texi
@@ -1,8 +1,9 @@
\input texinfo @c -*- texinfo -*-
+@documentencoding UTF-8
-@settitle Platform Specific information
+@settitle Platform Specific Information
@titlepage
-@center @titlefont{Platform Specific information}
+@center @titlefont{Platform Specific Information}
@end titlepage
@top
@@ -11,7 +12,7 @@
@chapter Unix-like
-Some parts of Libav cannot be built with version 2.15 of the GNU
+Some parts of FFmpeg cannot be built with version 2.15 of the GNU
assembler which is still provided by a few AMD64 distributions. To
make sure your compiler really uses the required version of gas
after a binutils upgrade, run:
@@ -26,9 +27,9 @@ to configure.
@section Advanced linking configuration
-If you compiled Libav libraries statically and you want to use them to
+If you compiled FFmpeg libraries statically and you want to use them to
build your own shared library, you may need to force PIC support (with
-@code{--enable-pic} during Libav configure) and add the following option
+@code{--enable-pic} during FFmpeg configure) and add the following option
to your project LDFLAGS:
@example
@@ -40,12 +41,12 @@ pass the correct linking flag (e.g. @code{-pie}) to @code{--extra-ldexeflags}.
@section BSD
-BSD make will not build Libav, you need to install and use GNU Make
+BSD make will not build FFmpeg, you need to install and use GNU Make
(@command{gmake}).
@section (Open)Solaris
-GNU Make is required to build Libav, so you have to invoke (@command{gmake}),
+GNU Make is required to build FFmpeg, so you have to invoke (@command{gmake}),
standard Solaris Make will not work. When building with a non-c99 front-end
(gcc, generic suncc) add either @code{--extra-libs=/usr/lib/values-xpg6.o}
or @code{--extra-libs=/usr/lib/64/values-xpg6.o} to the configure options
@@ -59,20 +60,22 @@ bash ./configure
@end example
@anchor{Darwin}
-@section Darwin (OS X, iPhone)
+@section Darwin (Mac OS X, iPhone)
The toolchain provided with Xcode is sufficient to build the basic
unacelerated code.
-OS X on PowerPC or ARM (iPhone) requires a preprocessor from
-@url{git://git.libav.org/gas-preprocessor.git} to build the optimized
+Mac OS X on PowerPC or ARM (iPhone) requires a preprocessor from
+@url{https://github.com/FFmpeg/gas-preprocessor} or
+@url{https://github.com/yuvi/gas-preprocessor}(currently outdated) to build the optimized
assembly functions. Put the Perl script somewhere
-in your PATH, Libav's configure will pick it up automatically.
+in your PATH, FFmpeg's configure will pick it up automatically.
-OS X on AMD64 and x86 requires @command{yasm} to build most of the
-optimized assembly functions @url{http://mxcl.github.com/homebrew/, Homebrew},
-@url{http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap-macos.xml, Gentoo Prefix}
-or @url{http://www.macports.org, MacPorts} can easily provide it.
+Mac OS X on amd64 and x86 requires @command{yasm} to build most of the
+optimized assembly functions. @uref{http://www.finkproject.org/, Fink},
+@uref{http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap-macos.xml, Gentoo Prefix},
+@uref{https://mxcl.github.com/homebrew/, Homebrew}
+or @uref{http://www.macports.org, MacPorts} can easily provide it.
@chapter DOS
@@ -83,15 +86,18 @@ Using a cross-compiler is preferred for various reasons.
@chapter OS/2
-For information about compiling Libav on OS/2 see
+For information about compiling FFmpeg on OS/2 see
@url{http://www.edm2.com/index.php/FFmpeg}.
@chapter Windows
+To get help and instructions for building FFmpeg under Windows, check out
+the FFmpeg Windows Help Forum at @url{http://ffmpeg.zeranoe.com/forum/}.
+
@section Native Windows compilation using MinGW or MinGW-w64
-Libav can be built to run natively on Windows using the MinGW-w64
+FFmpeg can be built to run natively on Windows using the MinGW-w64
toolchain. Install the latest versions of MSYS2 and MinGW-w64 from
@url{http://msys2.github.io/} and/or @url{http://mingw-w64.sourceforge.net/}.
You can find detailed installation instructions in the download section and
@@ -107,17 +113,18 @@ speed up is close to non-existent for normal one-off builds and is only
noticeable when running make for a second time (for example during
@code{make install}).
-@item In order to compile AVplay, you must have the MinGW development library
+@item In order to compile FFplay, you must have the MinGW development library
of @uref{http://www.libsdl.org/, SDL} and @code{pkg-config} installed.
-@item By using @code{./configure --enable-shared} when configuring Libav,
-you can build all libraries as DLLs.
+@item By using @code{./configure --enable-shared} when configuring FFmpeg,
+you can build the FFmpeg libraries (e.g. libavutil, libavcodec,
+libavformat) as DLLs.
@end itemize
@section Microsoft Visual C++ or Intel C++ Compiler for Windows
-Libav can be built with MSVC 2012 or earlier using a C99-to-C89 conversion utility
+FFmpeg can be built with MSVC 2012 or earlier using a C99-to-C89 conversion utility
and wrapper, or with MSVC 2013 and ICL natively.
You will need the following prerequisites:
@@ -182,15 +189,15 @@ follow step 3, or compilation will fail.
@enumerate
@item Grab the @uref{http://zlib.net/, zlib sources}.
@item Edit @code{win32/Makefile.msc} so that it uses -MT instead of -MD, since
-this is how Libav is built as well.
+this is how FFmpeg is built as well.
@item Edit @code{zconf.h} and remove its inclusion of @code{unistd.h}. This gets
-erroneously included when building Libav.
+erroneously included when building FFmpeg.
@item Run @code{nmake -f win32/Makefile.msc}.
@item Move @code{zlib.lib}, @code{zconf.h}, and @code{zlib.h} to somewhere MSVC
can see.
@end enumerate
-@item Libav has been tested with the following on i686 and x86_64:
+@item FFmpeg has been tested with the following on i686 and x86_64:
@itemize
@item Visual Studio 2010 Pro and Express
@item Visual Studio 2012 Pro and Express
@@ -202,7 +209,7 @@ Anything else is not officially supported.
@end itemize
-@subsection Linking to Libav with Microsoft Visual C++
+@subsection Linking to FFmpeg with Microsoft Visual C++
If you plan to link with MSVC-built static libraries, you will need
to make sure you have @code{Runtime Library} set to
@@ -254,14 +261,14 @@ Replace @code{foo-version} and @code{foo} with the respective library names.
You must use the MinGW cross compilation tools available at
@url{http://www.mingw.org/}.
-Then configure Libav with the following options:
+Then configure FFmpeg with the following options:
@example
./configure --target-os=mingw32 --cross-prefix=i386-mingw32msvc-
@end example
(you can change the cross-prefix according to the prefix chosen for the
MinGW tools).
-Then you can easily test Libav with @uref{http://www.winehq.com/, Wine}.
+Then you can easily test FFmpeg with @uref{http://www.winehq.com/, Wine}.
@section Compilation under Cygwin
@@ -271,7 +278,7 @@ llrint() in its C library.
Install your Cygwin with all the "Base" packages, plus the
following "Devel" ones:
@example
-binutils, gcc4-core, make, git, mingw-runtime, texi2html
+binutils, gcc4-core, make, git, mingw-runtime, texinfo
@end example
In order to run FATE you will also need the following "Utils" packages:
@@ -279,7 +286,7 @@ In order to run FATE you will also need the following "Utils" packages:
diffutils
@end example
-If you want to build Libav with additional libraries, download Cygwin
+If you want to build FFmpeg with additional libraries, download Cygwin
"Devel" packages for Ogg and Vorbis from any Cygwin packages repository:
@example
libogg-devel, libvorbis-devel
@@ -289,7 +296,7 @@ These library packages are only available from
@uref{http://sourceware.org/cygwinports/, Cygwin Ports}:
@example
-yasm, libSDL-devel, libfaac-devel, libgsm-devel, libmp3lame-devel,
+yasm, libSDL-devel, libfaac-devel, libaacplus-devel, libgsm-devel, libmp3lame-devel,
libschroedinger1.0-devel, speex-devel, libtheora-devel, libxvidcore-devel
@end example
@@ -321,7 +328,7 @@ and for a build with shared libraries
@chapter Plan 9
The native @uref{http://plan9.bell-labs.com/plan9/, Plan 9} compiler
-does not implement all the C99 features needed by Libav so the gcc
+does not implement all the C99 features needed by FFmpeg so the gcc
port must be used. Furthermore, a few items missing from the C
library and shell environment need to be fixed.
@@ -337,7 +344,7 @@ utility by setting @code{pkgpath} to
@item Missing/broken @code{head} and @code{printf} commands
-Replacements adequate for building Libav can be found in the
+Replacements adequate for building FFmpeg can be found in the
@code{compat/plan9} directory. Place these somewhere they will be
found by the shell. These are not full implementations of the
commands and are @emph{not} suitable for general use.
@@ -375,7 +382,7 @@ build system of this library.
@item FPU exceptions enabled by default
Unlike most other systems, Plan 9 enables FPU exceptions by default.
-These must be disabled before calling any Libav functions. While the
+These must be disabled before calling any FFmpeg functions. While the
included tools will do this automatically, other users of the
libraries must do it themselves.
diff --git a/doc/print_options.c b/doc/print_options.c
index aa75a00ba2..9fd66ca380 100644
--- a/doc/print_options.c
+++ b/doc/print_options.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,10 @@
#include <string.h>
#include <float.h>
+// print_options is build for the host, os_support.h isn't needed and is setup
+// for the target. without this build breaks on mingw
+#define AVFORMAT_OS_SUPPORT_H
+
#include "libavformat/avformat.h"
#include "libavformat/options_table.h"
#include "libavcodec/avcodec.h"
@@ -113,6 +117,8 @@ int main(int argc, char **argv)
if (argc < 2)
print_usage();
+ printf("@c DO NOT EDIT THIS FILE!\n"
+ "@c It was generated by print_options.\n\n");
if (!strcmp(argv[1], "format"))
show_format_opts();
else if (!strcmp(argv[1], "codec"))
diff --git a/doc/protocols.texi b/doc/protocols.texi
index 4957aff081..f822d81223 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1,10 +1,10 @@
@chapter Protocols
@c man begin PROTOCOLS
-Protocols are configured elements in Libav which allow to access
-resources which require the use of a particular protocol.
+Protocols are configured elements in FFmpeg that enable access to
+resources that require specific protocols.
-When you configure your Libav build, all the supported protocols are
+When you configure your FFmpeg build, all the supported protocols are
enabled by default. You can list all available ones using the
configure option "--list-protocols".
@@ -14,16 +14,56 @@ option "--enable-protocol=@var{PROTOCOL}", or you can disable a
particular protocol using the option
"--disable-protocol=@var{PROTOCOL}".
-The option "-protocols" of the av* tools will display the list of
+The option "-protocols" of the ff* tools will display the list of
supported protocols.
A description of the currently available protocols follows.
+@section bluray
+
+Read BluRay playlist.
+
+The accepted options are:
+@table @option
+
+@item angle
+BluRay angle
+
+@item chapter
+Start chapter (1...N)
+
+@item playlist
+Playlist to read (BDMV/PLAYLIST/?????.mpls)
+
+@end table
+
+Examples:
+
+Read longest playlist from BluRay mounted to /mnt/bluray:
+@example
+bluray:/mnt/bluray
+@end example
+
+Read angle 2 of playlist 4 from BluRay mounted to /mnt/bluray, start from chapter 2:
+@example
+-playlist 4 -angle 2 -chapter 2 bluray:/mnt/bluray
+@end example
+
+@section cache
+
+Caching wrapper for input stream.
+
+Cache the input stream to temporary file. It brings seeking capability to live streams.
+
+@example
+cache:@var{URL}
+@end example
+
@section concat
Physical concatenation protocol.
-Allow to read and seek from many resource in sequence as if they were
+Read and seek from many resources in sequence as if they were
a unique resource.
A URL accepted by this protocol has the syntax:
@@ -36,30 +76,114 @@ resource to be concatenated, each one possibly specifying a distinct
protocol.
For example to read a sequence of files @file{split1.mpeg},
-@file{split2.mpeg}, @file{split3.mpeg} with @command{avplay} use the
+@file{split2.mpeg}, @file{split3.mpeg} with @command{ffplay} use the
command:
@example
-avplay concat:split1.mpeg\|split2.mpeg\|split3.mpeg
+ffplay concat:split1.mpeg\|split2.mpeg\|split3.mpeg
@end example
Note that you may need to escape the character "|" which is special for
many shells.
+@section crypto
+
+AES-encrypted stream reading protocol.
+
+The accepted options are:
+@table @option
+@item key
+Set the AES decryption key binary block from given hexadecimal representation.
+
+@item iv
+Set the AES decryption initialization vector binary block from given hexadecimal representation.
+@end table
+
+Accepted URL formats:
+@example
+crypto:@var{URL}
+crypto+@var{URL}
+@end example
+
+@section data
+
+Data in-line in the URI. See @url{http://en.wikipedia.org/wiki/Data_URI_scheme}.
+
+For example, to convert a GIF file given inline with @command{ffmpeg}:
+@example
+ffmpeg -i "data:image/gif;base64,R0lGODdhCAAIAMIEAAAAAAAA//8AAP//AP///////////////ywAAAAACAAIAAADF0gEDLojDgdGiJdJqUX02iB4E8Q9jUMkADs=" smiley.png
+@end example
+
@section file
File access protocol.
-Allow to read from or read to a file.
+Read from or write to a file.
+
+A file URL can have the form:
+@example
+file:@var{filename}
+@end example
-For example to read from a file @file{input.mpeg} with @command{avconv}
+where @var{filename} is the path of the file to read.
+
+An URL that does not have a protocol prefix will be assumed to be a
+file URL. Depending on the build, an URL that looks like a Windows
+path with the drive letter at the beginning will also be assumed to be
+a file URL (usually not the case in builds for unix-like systems).
+
+For example to read from a file @file{input.mpeg} with @command{ffmpeg}
use the command:
@example
-avconv -i file:input.mpeg output.mpeg
+ffmpeg -i file:input.mpeg output.mpeg
+@end example
+
+This protocol accepts the following options:
+
+@table @option
+@item truncate
+Truncate existing files on write, if set to 1. A value of 0 prevents
+truncating. Default value is 1.
+
+@item blocksize
+Set I/O operation maximum block size, in bytes. Default value is
+@code{INT_MAX}, which results in not limiting the requested block size.
+Setting this value reasonably low improves user termination request reaction
+time, which is valuable for files on slow medium.
+@end table
+
+@section ftp
+
+FTP (File Transfer Protocol).
+
+Read from or write to remote resources using FTP protocol.
+
+Following syntax is required.
+@example
+ftp://[user[:password]@@]server[:port]/path/to/remote/resource.mpeg
@end example
-The av* tools default to the file protocol, that is a resource
-specified with the name "FILE.mpeg" is interpreted as the URL
-"file:FILE.mpeg".
+This protocol accepts the following options.
+
+@table @option
+@item timeout
+Set timeout in microseconds of socket I/O operations used by the underlying low level
+operation. By default it is set to -1, which means that the timeout is
+not specified.
+
+@item ftp-anonymous-password
+Password used when login as anonymous user. Typically an e-mail address
+should be used.
+
+@item ftp-write-seekable
+Control seekability of connection during encoding. If set to 1 the
+resource is supposed to be seekable, if set to 0 it is assumed not
+to be seekable. Default value is 0.
+@end table
+
+NOTE: Protocol can be used as output, but it is recommended to not do
+it, unless special care is taken (tests, customized server configuration
+etc.). Different FTP servers behave in different way during seek
+operation. ff* tools may produce incomplete content due to server limitations.
@section gopher
@@ -92,6 +216,12 @@ HTTP (Hyper Text Transfer Protocol).
This protocol accepts the following options:
@table @option
+@item seekable
+Control seekability of connection. If set to 1 the resource is
+supposed to be seekable, if set to 0 it is assumed not to be seekable,
+if set to -1 it will try to autodetect if it is seekable. Default
+value is -1.
+
@item chunked_post
If set to 1 use chunked Transfer-Encoding for posts, default is 1.
@@ -108,9 +238,15 @@ Use persistent connections if set to 1, default is 0.
@item post_data
Set custom HTTP post data.
+@item user-agent
@item user_agent
-Override the User-Agent header. If not specified a string of the form
-"Lavf/<version>" will be used.
+Override the User-Agent header. If not specified the protocol will use a
+string describing the libavformat build. ("Lavf/<version>")
+
+@item timeout
+Set timeout in microseconds of socket I/O operations used by the underlying low level
+operation. By default it is set to -1, which means that the timeout is
+not specified.
@item mime_type
Export the MIME type.
@@ -131,16 +267,60 @@ 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 offset
Set initial byte offset.
@item end_offset
Try to limit the request to bytes preceding this offset.
+
+@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
+an input option.
+@example
+# Server side (sending):
+ffmpeg -i somefile.ogg -c copy -listen 1 -f ogg http://@var{server}:@var{port}
+
+# Client side (receiving):
+ffmpeg -i http://@var{server}:@var{port} -c copy somefile.ogg
+
+# Client can also be done with wget:
+wget http://@var{server}:@var{port} -O somefile.ogg
+
+# Server side (receiving):
+ffmpeg -listen 1 -i http://@var{server}:@var{port} -c copy somefile.ogg
+
+# Client side (sending):
+ffmpeg -i somefile.ogg -chunked_post 0 -c copy -f ogg http://@var{server}:@var{port}
+
+# Client can also be done with wget:
+wget --post-file=somefile.ogg http://@var{server}:@var{port}
+@end example
+
@end table
+@subsection HTTP Cookies
+
+Some HTTP requests will be denied unless cookie values are passed in with the
+request. The @option{cookies} option allows these cookies to be specified. At
+the very least, each cookie must specify a value along with a path and domain.
+HTTP requests that match both the domain and path will automatically include the
+cookie value in the HTTP Cookie header field. Multiple cookies can be delimited
+by a newline.
+
+The required syntax to play a stream specifying a cookie is:
+@example
+ffplay -cookies "nlqptid=nltid=tsn; path=/; domain=somedomain.com;" http://somedomain.com/somestream.m3u8
+@end example
+
@section Icecast
-Icecast (stream to Icecast servers)
+Icecast protocol (stream to Icecast servers)
This protocol accepts the following options:
@@ -158,7 +338,7 @@ Set the stream description.
Set the stream website URL.
@item ice_public
-Set if the stream should be public or not.
+Set if the stream should be public.
The default is 0 (not public).
@item user_agent
@@ -178,6 +358,10 @@ HTTP PUT method but the SOURCE method.
@end table
+@example
+icecast://[@var{username}[:@var{password}]@@]@var{server}:@var{port}/@var{mountpoint}
+@end example
+
@section mmst
MMS (Microsoft Media Server) protocol over TCP.
@@ -202,10 +386,10 @@ be used to test muxers without writing an actual file.
Some examples follow.
@example
# Write the MD5 hash of the encoded AVI file to the file output.avi.md5.
-avconv -i input.flv -f avi -y md5:output.avi.md5
+ffmpeg -i input.flv -f avi -y md5:output.avi.md5
# Write the MD5 hash of the encoded AVI file to stdout.
-avconv -i input.flv -f avi -y md5:
+ffmpeg -i input.flv -f avi -y md5:
@end example
Note that some formats (typically MOV) require the output protocol to
@@ -215,7 +399,7 @@ be seekable, so they will fail with the MD5 output protocol.
UNIX pipe access protocol.
-Allow to read and write from UNIX pipes.
+Read and write from UNIX pipes.
The accepted syntax is:
@example
@@ -227,20 +411,30 @@ pipe (e.g. 0 for stdin, 1 for stdout, 2 for stderr). If @var{number}
is not specified, by default the stdout file descriptor will be used
for writing, stdin for reading.
-For example to read from stdin with @command{avconv}:
+For example to read from stdin with @command{ffmpeg}:
@example
-cat test.wav | avconv -i pipe:0
+cat test.wav | ffmpeg -i pipe:0
# ...this is the same as...
-cat test.wav | avconv -i pipe:
+cat test.wav | ffmpeg -i pipe:
@end example
-For writing to stdout with @command{avconv}:
+For writing to stdout with @command{ffmpeg}:
@example
-avconv -i test.wav -f avi pipe:1 | cat > test.avi
+ffmpeg -i test.wav -f avi pipe:1 | cat > test.avi
# ...this is the same as...
-avconv -i test.wav -f avi pipe: | cat > test.avi
+ffmpeg -i test.wav -f avi pipe: | cat > test.avi
@end example
+This protocol accepts the following options:
+
+@table @option
+@item blocksize
+Set I/O operation maximum block size, in bytes. Default value is
+@code{INT_MAX}, which results in not limiting the requested block size.
+Setting this value reasonably low improves user termination request reaction
+time, which is valuable if data transmission is slow.
+@end table
+
Note that some formats (typically MOV), require the output protocol to
be seekable, so they will fail with the pipe output protocol.
@@ -360,16 +554,16 @@ URL of the target stream. Defaults to proto://host[:port]/app.
@end table
-For example to read with @command{avplay} a multimedia resource named
+For example to read with @command{ffplay} a multimedia resource named
"sample" from the application "vod" from an RTMP server "myserver":
@example
-avplay rtmp://myserver/vod/sample
+ffplay rtmp://myserver/vod/sample
@end example
To publish to a password protected server, passing the playpath and
app names separately:
@example
-avconv -re -i <input> -f flv -rtmp_playpath some/long/path -rtmp_app long/app/name rtmp://username:password@@myserver/
+ffmpeg -re -i <input> -f flv -rtmp_playpath some/long/path -rtmp_app long/app/name rtmp://username:password@@myserver/
@end example
@section rtmpe
@@ -412,6 +606,71 @@ The Real-Time Messaging Protocol tunneled through HTTPS (RTMPTS) is used
for streaming multimedia content within HTTPS requests to traverse
firewalls.
+@section libsmbclient
+
+libsmbclient permits one to manipulate CIFS/SMB network resources.
+
+Following syntax is required.
+
+@example
+smb://[[domain:]user[:password@@]]server[/share[/path[/file]]]
+@end example
+
+This protocol accepts the following options.
+
+@table @option
+@item timeout
+Set timeout in miliseconds of socket I/O operations used by the underlying
+low level operation. By default it is set to -1, which means that the timeout
+is not specified.
+
+@item truncate
+Truncate existing files on write, if set to 1. A value of 0 prevents
+truncating. Default value is 1.
+
+@item workgroup
+Set the workgroup used for making connections. By default workgroup is not specified.
+
+@end table
+
+For more information see: @url{http://www.samba.org/}.
+
+@section libssh
+
+Secure File Transfer Protocol via libssh
+
+Read from or write to remote resources using SFTP protocol.
+
+Following syntax is required.
+
+@example
+sftp://[user[:password]@@]server[:port]/path/to/remote/resource.mpeg
+@end example
+
+This protocol accepts the following options.
+
+@table @option
+@item timeout
+Set timeout of socket I/O operations used by the underlying low level
+operation. By default it is set to -1, which means that the timeout
+is not specified.
+
+@item truncate
+Truncate existing files on write, if set to 1. A value of 0 prevents
+truncating. Default value is 1.
+
+@item private_key
+Specify the path of the file containing private key to use during authorization.
+By default libssh searches for keys in the @file{~/.ssh/} directory.
+
+@end table
+
+Example: Play a file stored on remote server.
+
+@example
+ffplay sftp://user:password@@server_address:22/home/user/resource.mpeg
+@end example
+
@section librtmp rtmp, rtmpe, rtmps, rtmpt, rtmpte
Real-Time Messaging Protocol and its variants supported through
@@ -442,22 +701,87 @@ meaning as specified for the RTMP native protocol.
See the librtmp manual page (man 3 librtmp) for more information.
For example, to stream a file in real-time to an RTMP server using
-@command{avconv}:
+@command{ffmpeg}:
@example
-avconv -re -i myfile -f flv rtmp://myserver/live/mystream
+ffmpeg -re -i myfile -f flv rtmp://myserver/live/mystream
@end example
-To play the same stream using @command{avplay}:
+To play the same stream using @command{ffplay}:
@example
-avplay "rtmp://myserver/live/mystream live=1"
+ffplay "rtmp://myserver/live/mystream live=1"
@end example
@section rtp
-Real-Time Protocol.
+Real-time Transport Protocol.
+
+The required syntax for an RTP URL is:
+rtp://@var{hostname}[:@var{port}][?@var{option}=@var{val}...]
+
+@var{port} specifies the RTP port to use.
+
+The following URL options are supported:
+
+@table @option
+
+@item ttl=@var{n}
+Set the TTL (Time-To-Live) value (for multicast only).
+
+@item rtcpport=@var{n}
+Set the remote RTCP port to @var{n}.
+
+@item localrtpport=@var{n}
+Set the local RTP port to @var{n}.
+
+@item localrtcpport=@var{n}'
+Set the local RTCP port to @var{n}.
+
+@item pkt_size=@var{n}
+Set max packet size (in bytes) to @var{n}.
+
+@item connect=0|1
+Do a @code{connect()} on the UDP socket (if set to 1) or not (if set
+to 0).
+
+@item sources=@var{ip}[,@var{ip}]
+List allowed source IP addresses.
+
+@item block=@var{ip}[,@var{ip}]
+List disallowed (blocked) source IP addresses.
+
+@item write_to_source=0|1
+Send packets to the source address of the latest received packet (if
+set to 1) or to a default remote address (if set to 0).
+
+@item localport=@var{n}
+Set the local RTP port to @var{n}.
+
+This is a deprecated option. Instead, @option{localrtpport} should be
+used.
+
+@end table
+
+Important notes:
+
+@enumerate
+
+@item
+If @option{rtcpport} is not set the RTCP port will be set to the RTP
+port value plus 1.
+
+@item
+If @option{localrtpport} (the local RTP port) is not set any available
+port will be used for the local RTP and RTCP ports.
+
+@item
+If @option{localrtcpport} (the local RTCP port) is not set it will be
+set to the local RTP port value plus 1.
+@end enumerate
@section rtsp
+Real-Time Streaming Protocol.
+
RTSP is not technically a protocol handler in libavformat, it is a demuxer
and muxer. The demuxer supports both normal RTSP (with data transferred
over RTP; this is used by e.g. Apple and Microsoft) and Real-RTSP (with
@@ -465,21 +789,29 @@ data transferred over RDT).
The muxer can be used to send a stream using RTSP ANNOUNCE to a server
supporting it (currently Darwin Streaming Server and Mischa Spiegelmock's
-@uref{http://github.com/revmischa/rtsp-server, RTSP server}).
+@uref{https://github.com/revmischa/rtsp-server, RTSP server}).
The required syntax for a RTSP url is:
@example
rtsp://@var{hostname}[:@var{port}]/@var{path}
@end example
-The following options (set on the @command{avconv}/@command{avplay} command
-line, or set in code via @code{AVOption}s or in @code{avformat_open_input}),
-are supported:
+Options can be set on the @command{ffmpeg}/@command{ffplay} command
+line, or set in code via @code{AVOption}s or in
+@code{avformat_open_input}.
-Flags for @code{rtsp_transport}:
+The following options are supported.
@table @option
+@item initial_pause
+Do not start playing the stream immediately if set to 1. Default value
+is 0.
+
+@item rtsp_transport
+Set RTSP transport protocols.
+It accepts the following values:
+@table @samp
@item udp
Use UDP as lower transport protocol.
@@ -497,15 +829,56 @@ passing proxies.
Multiple lower transport protocols may be specified, in that case they are
tried one at a time (if the setup of one fails, the next one is tried).
-For the muxer, only the @code{tcp} and @code{udp} options are supported.
+For the muxer, only the @samp{tcp} and @samp{udp} options are supported.
-Flags for @code{rtsp_flags}:
+@item rtsp_flags
+Set RTSP flags.
-@table @option
+The following values are accepted:
+@table @samp
@item filter_src
Accept packets only from negotiated peer address and port.
@item listen
Act as a server, listening for an incoming connection.
+@item prefer_tcp
+Try TCP for RTP transport first, if TCP is available as RTSP RTP transport.
+@end table
+
+Default value is @samp{none}.
+
+@item allowed_media_types
+Set media types to accept from the server.
+
+The following flags are accepted:
+@table @samp
+@item video
+@item audio
+@item data
+@end table
+
+By default it accepts all media types.
+
+@item min_port
+Set minimum local UDP port. Default value is 5000.
+
+@item max_port
+Set maximum local UDP port. Default value is 65000.
+
+@item timeout
+Set maximum timeout (in seconds) to wait for incoming connections.
+
+A value of -1 means infinite (default). This option implies the
+@option{rtsp_flags} set to @samp{listen}.
+
+@item reorder_queue_size
+Set number of packets to buffer for handling of reordered packets.
+
+@item stimeout
+Set socket TCP I/O timeout in microseconds.
+
+@item user-agent
+Override User-Agent header. If not specified, it defaults to the
+libavformat identifier string.
@end table
When receiving data over UDP, the demuxer tries to reorder received packets
@@ -513,36 +886,41 @@ When receiving data over UDP, the demuxer tries to reorder received packets
can be disabled by setting the maximum demuxing delay to zero (via
the @code{max_delay} field of AVFormatContext).
-When watching multi-bitrate Real-RTSP streams with @command{avplay}, the
+When watching multi-bitrate Real-RTSP streams with @command{ffplay}, the
streams to display can be chosen with @code{-vst} @var{n} and
@code{-ast} @var{n} for video and audio respectively, and can be switched
on the fly by pressing @code{v} and @code{a}.
-Example command lines:
+@subsection Examples
-To watch a stream over UDP, with a max reordering delay of 0.5 seconds:
+The following examples all make use of the @command{ffplay} and
+@command{ffmpeg} tools.
+@itemize
+@item
+Watch a stream over UDP, with a max reordering delay of 0.5 seconds:
@example
-avplay -max_delay 500000 -rtsp_transport udp rtsp://server/video.mp4
+ffplay -max_delay 500000 -rtsp_transport udp rtsp://server/video.mp4
@end example
-To watch a stream tunneled over HTTP:
-
+@item
+Watch a stream tunneled over HTTP:
@example
-avplay -rtsp_transport http rtsp://server/video.mp4
+ffplay -rtsp_transport http rtsp://server/video.mp4
@end example
-To send a stream in realtime to a RTSP server, for others to watch:
-
+@item
+Send a stream in realtime to a RTSP server, for others to watch:
@example
-avconv -re -i @var{input} -f rtsp -muxdelay 0.1 rtsp://server/live.sdp
+ffmpeg -re -i @var{input} -f rtsp -muxdelay 0.1 rtsp://server/live.sdp
@end example
-To receive a stream in realtime:
-
+@item
+Receive a stream in realtime:
@example
-avconv -rtsp_flags listen -i rtsp://ownaddress/live.sdp @var{output}
+ffmpeg -rtsp_flags listen -i rtsp://ownaddress/live.sdp @var{output}
@end example
+@end itemize
@section sap
@@ -593,19 +971,19 @@ Example command lines follow.
To broadcast a stream on the local subnet, for watching in VLC:
@example
-avconv -re -i @var{input} -f sap sap://224.0.0.255?same_port=1
+ffmpeg -re -i @var{input} -f sap sap://224.0.0.255?same_port=1
@end example
-Similarly, for watching in avplay:
+Similarly, for watching in @command{ffplay}:
@example
-avconv -re -i @var{input} -f sap sap://224.0.0.255
+ffmpeg -re -i @var{input} -f sap sap://224.0.0.255
@end example
-And for watching in avplay, over IPv6:
+And for watching in @command{ffplay}, over IPv6:
@example
-avconv -re -i @var{input} -f sap sap://[ff0e::1:2:3:4]
+ffmpeg -re -i @var{input} -f sap sap://[ff0e::1:2:3:4]
@end example
@subsection Demuxer
@@ -627,43 +1005,127 @@ Example command lines follow.
To play back the first stream announced on the normal SAP multicast address:
@example
-avplay sap://
+ffplay sap://
@end example
To play back the first stream announced on one the default IPv6 SAP multicast address:
@example
-avplay sap://[ff0e::2:7ffe]
+ffplay sap://[ff0e::2:7ffe]
+@end example
+
+@section sctp
+
+Stream Control Transmission Protocol.
+
+The accepted URL syntax is:
+@example
+sctp://@var{host}:@var{port}[?@var{options}]
+@end example
+
+The protocol accepts the following options:
+@table @option
+@item listen
+If set to any value, listen for an incoming connection. Outgoing connection is done by default.
+
+@item max_streams
+Set the maximum number of streams. By default no limit is set.
+@end table
+
+@section srtp
+
+Secure Real-time Transport Protocol.
+
+The accepted options are:
+@table @option
+@item srtp_in_suite
+@item srtp_out_suite
+Select input and output encoding suites.
+
+Supported values:
+@table @samp
+@item AES_CM_128_HMAC_SHA1_80
+@item SRTP_AES128_CM_HMAC_SHA1_80
+@item AES_CM_128_HMAC_SHA1_32
+@item SRTP_AES128_CM_HMAC_SHA1_32
+@end table
+
+@item srtp_in_params
+@item srtp_out_params
+Set input and output encoding parameters, which are expressed by a
+base64-encoded representation of a binary block. The first 16 bytes of
+this binary block are used as master key, the following 14 bytes are
+used as master salt.
+@end table
+
+@section subfile
+
+Virtually extract a segment of a file or another stream.
+The underlying stream must be seekable.
+
+Accepted options:
+@table @option
+@item start
+Start offset of the extracted segment, in bytes.
+@item end
+End offset of the extracted segment, in bytes.
+@end table
+
+Examples:
+
+Extract a chapter from a DVD VOB file (start and end sectors obtained
+externally and multiplied by 2048):
+@example
+subfile,,start,153391104,end,268142592,,:/media/dvd/VIDEO_TS/VTS_08_1.VOB
+@end example
+
+Play an AVI file directly from a TAR archive:
+@example
+subfile,,start,183241728,end,366490624,,:archive.tar
@end example
@section tcp
-Trasmission Control Protocol.
+Transmission Control Protocol.
The required syntax for a TCP url is:
@example
tcp://@var{hostname}:@var{port}[?@var{options}]
@end example
+@var{options} contains a list of &-separated options of the form
+@var{key}=@var{val}.
+
+The list of supported options follows.
+
@table @option
+@item listen=@var{1|0}
+Listen for an incoming connection. Default value is 0.
-@item listen
-Listen for an incoming connection
+@item timeout=@var{microseconds}
+Set raise error timeout, expressed in microseconds.
-@example
-avconv -i @var{input} -f @var{format} tcp://@var{hostname}:@var{port}?listen
-avplay tcp://@var{hostname}:@var{port}
-@end example
+This option is only relevant in read mode: if no data arrived in more
+than this time interval, raise error.
+@item listen_timeout=@var{milliseconds}
+Set listen timeout, expressed in milliseconds.
@end table
+The following example shows how to setup a listening TCP connection
+with @command{ffmpeg}, which is then accessed with @command{ffplay}:
+@example
+ffmpeg -i @var{input} -f @var{format} tcp://@var{hostname}:@var{port}?listen
+ffplay tcp://@var{hostname}:@var{port}
+@end example
+
@section tls
Transport Layer Security (TLS) / Secure Sockets Layer (SSL)
-The required syntax for a TLS url is:
+The required syntax for a TLS/SSL url is:
@example
-tls://@var{hostname}:@var{port}
+tls://@var{hostname}:@var{port}[?@var{options}]
@end example
The following parameters can be set via command line options
@@ -671,11 +1133,12 @@ The following parameters can be set via command line options
@table @option
-@item ca_file
+@item ca_file, cafile=@var{filename}
A file containing certificate authority (CA) root certificates to treat
as trusted. If the linked TLS library contains a default this might not
need to be specified for verification to work, but not all libraries and
setups have defaults built in.
+The file must be in OpenSSL PEM format.
@item tls_verify=@var{1|0}
If enabled, try to verify the peer that we are communicating with.
@@ -688,13 +1151,13 @@ the host name is validated as well.)
This is disabled by default since it requires a CA database to be
provided by the caller in many cases.
-@item cert_file
+@item cert_file, cert=@var{filename}
A file containing a certificate to use in the handshake with the peer.
(When operating as server, in listen mode, this is more often required
by the peer, while client certificates only are mandated in certain
setups.)
-@item key_file
+@item key_file, key=@var{filename}
A file containing the private key for the certificate.
@item listen=@var{1|0}
@@ -703,25 +1166,46 @@ the server role in the handshake instead of the client role.
@end table
+Example command lines:
+
+To create a TLS/SSL server that serves an input stream.
+
+@example
+ffmpeg -i @var{input} -f @var{format} tls://@var{hostname}:@var{port}?listen&cert=@var{server.crt}&key=@var{server.key}
+@end example
+
+To play back a stream from the TLS/SSL server using @command{ffplay}:
+
+@example
+ffplay tls://@var{hostname}:@var{port}
+@end example
+
@section udp
User Datagram Protocol.
-The required syntax for a UDP url is:
+The required syntax for an UDP URL is:
@example
udp://@var{hostname}:@var{port}[?@var{options}]
@end example
@var{options} contains a list of &-separated options of the form @var{key}=@var{val}.
-Follow the list of supported options.
-@table @option
+In case threading is enabled on the system, a circular buffer is used
+to store the incoming data, which allows one to reduce loss of data due to
+UDP socket buffer overruns. The @var{fifo_size} and
+@var{overrun_nonfatal} options are related to this buffer.
+
+The list of supported options follows.
+@table @option
@item buffer_size=@var{size}
-set the UDP buffer size in bytes
+Set the UDP maximum socket buffer size in bytes. This is used to set either
+the receive or send buffer size, depending on what the socket is used for.
+Default is 64KB. See also @var{fifo_size}.
@item localport=@var{port}
-override the local UDP port to bind with
+Override the local UDP port to bind with.
@item localaddr=@var{addr}
Choose the local IP address. This is useful e.g. if sending multicast
@@ -729,13 +1213,13 @@ and the host has multiple interfaces, where the user can choose
which interface to send on by specifying the IP address of that interface.
@item pkt_size=@var{size}
-set the size in bytes of UDP packets
+Set the size in bytes of UDP packets.
@item reuse=@var{1|0}
-explicitly allow or disallow reusing UDP sockets
+Explicitly allow or disallow reusing UDP sockets.
@item ttl=@var{ttl}
-set the time to live value (for multicast only)
+Set the time to live value (for multicast only).
@item connect=@var{1|0}
Initialize the UDP socket with @code{connect()}. In this case, the
@@ -755,24 +1239,50 @@ specified sender IP addresses.
@item block=@var{address}[,@var{address}]
Ignore packets sent to the multicast group from the specified
sender IP addresses.
+
+@item fifo_size=@var{units}
+Set the UDP receiving circular buffer size, expressed as a number of
+packets with size of 188 bytes. If not specified defaults to 7*4096.
+
+@item overrun_nonfatal=@var{1|0}
+Survive in case of UDP receiving circular buffer overrun. Default
+value is 0.
+
+@item timeout=@var{microseconds}
+Set raise error timeout, expressed in microseconds.
+
+This option is only relevant in read mode: if no data arrived in more
+than this time interval, raise error.
+
+@item broadcast=@var{1|0}
+Explicitly allow or disallow UDP broadcasting.
+
+Note that broadcasting may not work properly on networks having
+a broadcast storm protection.
@end table
-Some usage examples of the udp protocol with @command{avconv} follow.
+@subsection Examples
-To stream over UDP to a remote endpoint:
+@itemize
+@item
+Use @command{ffmpeg} to stream over UDP to a remote endpoint:
@example
-avconv -i @var{input} -f @var{format} udp://@var{hostname}:@var{port}
+ffmpeg -i @var{input} -f @var{format} udp://@var{hostname}:@var{port}
@end example
-To stream in mpegts format over UDP using 188 sized UDP packets, using a large input buffer:
+@item
+Use @command{ffmpeg} to stream in mpegts format over UDP using 188
+sized UDP packets, using a large input buffer:
@example
-avconv -i @var{input} -f mpegts udp://@var{hostname}:@var{port}?pkt_size=188&buffer_size=65535
+ffmpeg -i @var{input} -f mpegts udp://@var{hostname}:@var{port}?pkt_size=188&buffer_size=65535
@end example
-To receive over UDP from a remote endpoint:
+@item
+Use @command{ffmpeg} to receive over UDP from a remote endpoint:
@example
-avconv -i udp://[@var{multicast-address}]:@var{port}
+ffmpeg -i udp://[@var{multicast-address}]:@var{port} ...
@end example
+@end itemize
@section unix
diff --git a/doc/resampler.texi b/doc/resampler.texi
new file mode 100644
index 0000000000..f9eef03f20
--- /dev/null
+++ b/doc/resampler.texi
@@ -0,0 +1,232 @@
+@chapter Resampler Options
+@c man begin RESAMPLER OPTIONS
+
+The audio resampler supports the following named options.
+
+Options may be set by specifying -@var{option} @var{value} in the
+FFmpeg tools, @var{option}=@var{value} for the aresample filter,
+by setting the value explicitly in the
+@code{SwrContext} options or using the @file{libavutil/opt.h} API for
+programmatic use.
+
+@table @option
+
+@item ich, in_channel_count
+Set the number of input channels. Default value is 0. Setting this
+value is not mandatory if the corresponding channel layout
+@option{in_channel_layout} is set.
+
+@item och, out_channel_count
+Set the number of output channels. Default value is 0. Setting this
+value is not mandatory if the corresponding channel layout
+@option{out_channel_layout} is set.
+
+@item uch, used_channel_count
+Set the number of used input channels. Default value is 0. This option is
+only used for special remapping.
+
+@item isr, in_sample_rate
+Set the input sample rate. Default value is 0.
+
+@item osr, out_sample_rate
+Set the output sample rate. Default value is 0.
+
+@item isf, in_sample_fmt
+Specify the input sample format. It is set by default to @code{none}.
+
+@item osf, out_sample_fmt
+Specify the output sample format. It is set by default to @code{none}.
+
+@item tsf, internal_sample_fmt
+Set the internal sample format. Default value is @code{none}.
+This will automatically be chosen when it is not explicitly set.
+
+@item icl, in_channel_layout
+@item ocl, out_channel_layout
+Set the input/output channel layout.
+
+See @ref{channel layout syntax,,the Channel Layout section in the ffmpeg-utils(1) manual,ffmpeg-utils}
+for the required syntax.
+
+@item clev, center_mix_level
+Set the center mix level. It is a value expressed in deciBel, and must be
+in the interval [-32,32].
+
+@item slev, surround_mix_level
+Set the surround mix level. It is a value expressed in deciBel, and must
+be in the interval [-32,32].
+
+@item lfe_mix_level
+Set LFE mix into non LFE level. It is used when there is a LFE input but no
+LFE output. It is a value expressed in deciBel, and must
+be in the interval [-32,32].
+
+@item rmvol, rematrix_volume
+Set rematrix volume. Default value is 1.0.
+
+@item rematrix_maxval
+Set maximum output value for rematrixing.
+This can be used to prevent clipping vs. preventing volumn reduction
+A value of 1.0 prevents cliping.
+
+@item flags, swr_flags
+Set flags used by the converter. Default value is 0.
+
+It supports the following individual flags:
+@table @option
+@item res
+force resampling, this flag forces resampling to be used even when the
+input and output sample rates match.
+@end table
+
+@item dither_scale
+Set the dither scale. Default value is 1.
+
+@item dither_method
+Set dither method. Default value is 0.
+
+Supported values:
+@table @samp
+@item rectangular
+select rectangular dither
+@item triangular
+select triangular dither
+@item triangular_hp
+select triangular dither with high pass
+@item lipshitz
+select lipshitz noise shaping dither
+@item shibata
+select shibata noise shaping dither
+@item low_shibata
+select low shibata noise shaping dither
+@item high_shibata
+select high shibata noise shaping dither
+@item f_weighted
+select f-weighted noise shaping dither
+@item modified_e_weighted
+select modified-e-weighted noise shaping dither
+@item improved_e_weighted
+select improved-e-weighted noise shaping dither
+
+@end table
+
+@item resampler
+Set resampling engine. Default value is swr.
+
+Supported values:
+@table @samp
+@item swr
+select the native SW Resampler; filter options precision and cheby are not
+applicable in this case.
+@item soxr
+select the SoX Resampler (where available); compensation, and filter options
+filter_size, phase_shift, filter_type & kaiser_beta, are not applicable in this
+case.
+@end table
+
+@item filter_size
+For swr only, set resampling filter size, default value is 32.
+
+@item phase_shift
+For swr only, set resampling phase shift, default value is 10, and must be in
+the interval [0,30].
+
+@item linear_interp
+Use Linear Interpolation if set to 1, default value is 0.
+
+@item cutoff
+Set cutoff frequency (swr: 6dB point; soxr: 0dB point) ratio; must be a float
+value between 0 and 1. Default value is 0.97 with swr, and 0.91 with soxr
+(which, with a sample-rate of 44100, preserves the entire audio band to 20kHz).
+
+@item precision
+For soxr only, the precision in bits to which the resampled signal will be
+calculated. The default value of 20 (which, with suitable dithering, is
+appropriate for a destination bit-depth of 16) gives SoX's 'High Quality'; a
+value of 28 gives SoX's 'Very High Quality'.
+
+@item cheby
+For soxr only, selects passband rolloff none (Chebyshev) & higher-precision
+approximation for 'irrational' ratios. Default value is 0.
+
+@item async
+For swr only, simple 1 parameter audio sync to timestamps using stretching,
+squeezing, filling and trimming. Setting this to 1 will enable filling and
+trimming, larger values represent the maximum amount in samples that the data
+may be stretched or squeezed for each second.
+Default value is 0, thus no compensation is applied to make the samples match
+the audio timestamps.
+
+@item first_pts
+For swr only, assume the first pts should be this value. The time unit is 1 / sample rate.
+This allows for padding/trimming at the start of stream. By default, no
+assumption is made about the first frame's expected pts, so no padding or
+trimming is done. For example, this could be set to 0 to pad the beginning with
+silence if an audio stream starts after the video stream or to trim any samples
+with a negative pts due to encoder delay.
+
+@item min_comp
+For swr only, set the minimum difference between timestamps and audio data (in
+seconds) to trigger stretching/squeezing/filling or trimming of the
+data to make it match the timestamps. The default is that
+stretching/squeezing/filling and trimming is disabled
+(@option{min_comp} = @code{FLT_MAX}).
+
+@item min_hard_comp
+For swr only, set the minimum difference between timestamps and audio data (in
+seconds) to trigger adding/dropping samples to make it match the
+timestamps. This option effectively is a threshold to select between
+hard (trim/fill) and soft (squeeze/stretch) compensation. Note that
+all compensation is by default disabled through @option{min_comp}.
+The default is 0.1.
+
+@item comp_duration
+For swr only, set duration (in seconds) over which data is stretched/squeezed
+to make it match the timestamps. Must be a non-negative double float value,
+default value is 1.0.
+
+@item max_soft_comp
+For swr only, set maximum factor by which data is stretched/squeezed to make it
+match the timestamps. Must be a non-negative double float value, default value
+is 0.
+
+@item matrix_encoding
+Select matrixed stereo encoding.
+
+It accepts the following values:
+@table @samp
+@item none
+select none
+@item dolby
+select Dolby
+@item dplii
+select Dolby Pro Logic II
+@end table
+
+Default value is @code{none}.
+
+@item filter_type
+For swr only, select resampling filter type. This only affects resampling
+operations.
+
+It accepts the following values:
+@table @samp
+@item cubic
+select cubic
+@item blackman_nuttall
+select Blackman Nuttall Windowed Sinc
+@item kaiser
+select Kaiser Windowed Sinc
+@end table
+
+@item kaiser_beta
+For swr only, set Kaiser Window Beta value. Must be an integer in the
+interval [2,16], default value is 9.
+
+@item output_sample_bits
+For swr only, set number of used output sample bits for dithering. Must be an integer in the
+interval [0,64], default value is 0, which means it's not used.
+
+@end table
+
+@c man end RESAMPLER OPTIONS
diff --git a/doc/scaler.texi b/doc/scaler.texi
new file mode 100644
index 0000000000..23d6393883
--- /dev/null
+++ b/doc/scaler.texi
@@ -0,0 +1,127 @@
+@anchor{scaler_options}
+@chapter Scaler Options
+@c man begin SCALER OPTIONS
+
+The video scaler supports the following named options.
+
+Options may be set by specifying -@var{option} @var{value} in the
+FFmpeg tools. For programmatic use, they can be set explicitly in the
+@code{SwsContext} options or through the @file{libavutil/opt.h} API.
+
+@table @option
+
+@anchor{sws_flags}
+@item sws_flags
+Set the scaler flags. This is also used to set the scaling
+algorithm. Only a single algorithm should be selected.
+
+It accepts the following values:
+@table @samp
+@item fast_bilinear
+Select fast bilinear scaling algorithm.
+
+@item bilinear
+Select bilinear scaling algorithm.
+
+@item bicubic
+Select bicubic scaling algorithm.
+
+@item experimental
+Select experimental scaling algorithm.
+
+@item neighbor
+Select nearest neighbor rescaling algorithm.
+
+@item area
+Select averaging area rescaling algorithm.
+
+@item bicublin
+Select bicubic scaling algorithm for the luma component, bilinear for
+chroma components.
+
+@item gauss
+Select Gaussian rescaling algorithm.
+
+@item sinc
+Select sinc rescaling algorithm.
+
+@item lanczos
+Select lanczos rescaling algorithm.
+
+@item spline
+Select natural bicubic spline rescaling algorithm.
+
+@item print_info
+Enable printing/debug logging.
+
+@item accurate_rnd
+Enable accurate rounding.
+
+@item full_chroma_int
+Enable full chroma interpolation.
+
+@item full_chroma_inp
+Select full chroma input.
+
+@item bitexact
+Enable bitexact output.
+@end table
+
+@item srcw
+Set source width.
+
+@item srch
+Set source height.
+
+@item dstw
+Set destination width.
+
+@item dsth
+Set destination height.
+
+@item src_format
+Set source pixel format (must be expressed as an integer).
+
+@item dst_format
+Set destination pixel format (must be expressed as an integer).
+
+@item src_range
+Select source range.
+
+@item dst_range
+Select destination range.
+
+@item param0, param1
+Set scaling algorithm parameters. The specified values are specific of
+some scaling algorithms and ignored by others. The specified values
+are floating point number values.
+
+@item sws_dither
+Set the dithering algorithm. Accepts one of the following
+values. Default value is @samp{auto}.
+
+@table @samp
+@item auto
+automatic choice
+
+@item none
+no dithering
+
+@item bayer
+bayer dither
+
+@item ed
+error diffusion dither
+
+@item a_dither
+arithmetic dither, based using addition
+
+@item x_dither
+arithmetic dither, based using xor (more random/less apparent patterning that
+a_dither).
+
+@end table
+
+@end table
+
+@c man end SCALER OPTIONS
diff --git a/doc/snow.txt b/doc/snow.txt
new file mode 100644
index 0000000000..9d5778d55d
--- /dev/null
+++ b/doc/snow.txt
@@ -0,0 +1,637 @@
+=============================================
+Snow Video Codec Specification Draft 20080110
+=============================================
+
+Introduction:
+=============
+This specification describes the Snow bitstream syntax and semantics as
+well as the formal Snow decoding process.
+
+The decoding process is described precisely and any compliant decoder
+MUST produce the exact same output for a spec-conformant Snow stream.
+For encoding, though, any process which generates a stream compliant to
+the syntactical and semantic requirements and which is decodable by
+the process described in this spec shall be considered a conformant
+Snow encoder.
+
+Definitions:
+============
+
+MUST the specific part must be done to conform to this standard
+SHOULD it is recommended to be done that way, but not strictly required
+
+ilog2(x) is the rounded down logarithm of x with basis 2
+ilog2(0) = 0
+
+Type definitions:
+=================
+
+b 1-bit range coded
+u unsigned scalar value range coded
+s signed scalar value range coded
+
+
+Bitstream syntax:
+=================
+
+frame:
+ header
+ prediction
+ residual
+
+header:
+ keyframe b MID_STATE
+ if(keyframe || always_reset)
+ reset_contexts
+ if(keyframe){
+ version u header_state
+ always_reset b header_state
+ temporal_decomposition_type u header_state
+ temporal_decomposition_count u header_state
+ spatial_decomposition_count u header_state
+ colorspace_type u header_state
+ if (nb_planes > 2) {
+ chroma_h_shift u header_state
+ chroma_v_shift u header_state
+ }
+ spatial_scalability b header_state
+ max_ref_frames-1 u header_state
+ qlogs
+ }
+ if(!keyframe){
+ update_mc b header_state
+ if(update_mc){
+ for(plane=0; plane<nb_plane_types; plane++){
+ diag_mc b header_state
+ htaps/2-1 u header_state
+ for(i= p->htaps/2; i; i--)
+ |hcoeff[i]| u header_state
+ }
+ }
+ update_qlogs b header_state
+ if(update_qlogs){
+ spatial_decomposition_count u header_state
+ qlogs
+ }
+ }
+
+ spatial_decomposition_type s header_state
+ qlog s header_state
+ mv_scale s header_state
+ qbias s header_state
+ block_max_depth s header_state
+
+qlogs:
+ for(plane=0; plane<nb_plane_types; plane++){
+ quant_table[plane][0][0] s header_state
+ for(level=0; level < spatial_decomposition_count; level++){
+ quant_table[plane][level][1]s header_state
+ quant_table[plane][level][3]s header_state
+ }
+ }
+
+reset_contexts
+ *_state[*]= MID_STATE
+
+prediction:
+ for(y=0; y<block_count_vertical; y++)
+ for(x=0; x<block_count_horizontal; x++)
+ block(0)
+
+block(level):
+ mvx_diff=mvy_diff=y_diff=cb_diff=cr_diff=0
+ if(keyframe){
+ intra=1
+ }else{
+ if(level!=max_block_depth){
+ s_context= 2*left->level + 2*top->level + topleft->level + topright->level
+ leaf b block_state[4 + s_context]
+ }
+ if(level==max_block_depth || leaf){
+ intra b block_state[1 + left->intra + top->intra]
+ if(intra){
+ y_diff s block_state[32]
+ cb_diff s block_state[64]
+ cr_diff s block_state[96]
+ }else{
+ ref_context= ilog2(2*left->ref) + ilog2(2*top->ref)
+ if(ref_frames > 1)
+ ref u block_state[128 + 1024 + 32*ref_context]
+ mx_context= ilog2(2*abs(left->mx - top->mx))
+ my_context= ilog2(2*abs(left->my - top->my))
+ mvx_diff s block_state[128 + 32*(mx_context + 16*!!ref)]
+ mvy_diff s block_state[128 + 32*(my_context + 16*!!ref)]
+ }
+ }else{
+ block(level+1)
+ block(level+1)
+ block(level+1)
+ block(level+1)
+ }
+ }
+
+
+residual:
+ residual2(luma)
+ if (nb_planes > 2) {
+ residual2(chroma_cr)
+ residual2(chroma_cb)
+ }
+
+residual2:
+ for(level=0; level<spatial_decomposition_count; level++){
+ if(level==0)
+ subband(LL, 0)
+ subband(HL, level)
+ subband(LH, level)
+ subband(HH, level)
+ }
+
+subband:
+ FIXME
+
+nb_plane_types = gray ? 1 : 2;
+
+Tag description:
+----------------
+
+version
+ 0
+ this MUST NOT change within a bitstream
+
+always_reset
+ if 1 then the range coder contexts will be reset after each frame
+
+temporal_decomposition_type
+ 0
+
+temporal_decomposition_count
+ 0
+
+spatial_decomposition_count
+ FIXME
+
+colorspace_type
+ 0 unspecified YcbCr
+ 1 Gray
+ 2 Gray + Alpha
+ 3 GBR
+ 4 GBRA
+ this MUST NOT change within a bitstream
+
+chroma_h_shift
+ log2(luma.width / chroma.width)
+ this MUST NOT change within a bitstream
+
+chroma_v_shift
+ log2(luma.height / chroma.height)
+ this MUST NOT change within a bitstream
+
+spatial_scalability
+ 0
+
+max_ref_frames
+ maximum number of reference frames
+ this MUST NOT change within a bitstream
+
+update_mc
+ indicates that motion compensation filter parameters are stored in the
+ header
+
+diag_mc
+ flag to enable faster diagonal interpolation
+ this SHOULD be 1 unless it turns out to be covered by a valid patent
+
+htaps
+ number of half pel interpolation filter taps, MUST be even, >0 and <10
+
+hcoeff
+ half pel interpolation filter coefficients, hcoeff[0] are the 2 middle
+ coefficients [1] are the next outer ones and so on, resulting in a filter
+ like: ...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2] ...
+ the sign of the coefficients is not explicitly stored but alternates
+ after each coeff and coeff[0] is positive, so ...,+,-,+,-,+,+,-,+,-,+,...
+ hcoeff[0] is not explicitly stored but found by subtracting the sum
+ of all stored coefficients with signs from 32
+ hcoeff[0]= 32 - hcoeff[1] - hcoeff[2] - ...
+ a good choice for hcoeff and htaps is
+ htaps= 6
+ hcoeff={40,-10,2}
+ an alternative which requires more computations at both encoder and
+ decoder side and may or may not be better is
+ htaps= 8
+ hcoeff={42,-14,6,-2}
+
+
+ref_frames
+ minimum of the number of available reference frames and max_ref_frames
+ for example the first frame after a key frame always has ref_frames=1
+
+spatial_decomposition_type
+ wavelet type
+ 0 is a 9/7 symmetric compact integer wavelet
+ 1 is a 5/3 symmetric compact integer wavelet
+ others are reserved
+ stored as delta from last, last is reset to 0 if always_reset || keyframe
+
+qlog
+ quality (logarthmic quantizer scale)
+ stored as delta from last, last is reset to 0 if always_reset || keyframe
+
+mv_scale
+ stored as delta from last, last is reset to 0 if always_reset || keyframe
+ FIXME check that everything works fine if this changes between frames
+
+qbias
+ dequantization bias
+ stored as delta from last, last is reset to 0 if always_reset || keyframe
+
+block_max_depth
+ maximum depth of the block tree
+ stored as delta from last, last is reset to 0 if always_reset || keyframe
+
+quant_table
+ quantiztation table
+
+
+Highlevel bitstream structure:
+=============================
+ --------------------------------------------
+| Header |
+ --------------------------------------------
+| ------------------------------------ |
+| | Block0 | |
+| | split? | |
+| | yes no | |
+| | ......... intra? | |
+| | : Block01 : yes no | |
+| | : Block02 : ....... .......... | |
+| | : Block03 : : y DC : : ref index: | |
+| | : Block04 : : cb DC : : motion x : | |
+| | ......... : cr DC : : motion y : | |
+| | ....... .......... | |
+| ------------------------------------ |
+| ------------------------------------ |
+| | Block1 | |
+| ... |
+ --------------------------------------------
+| ------------ ------------ ------------ |
+|| Y subbands | | Cb subbands| | Cr subbands||
+|| --- --- | | --- --- | | --- --- ||
+|| |LL0||HL0| | | |LL0||HL0| | | |LL0||HL0| ||
+|| --- --- | | --- --- | | --- --- ||
+|| --- --- | | --- --- | | --- --- ||
+|| |LH0||HH0| | | |LH0||HH0| | | |LH0||HH0| ||
+|| --- --- | | --- --- | | --- --- ||
+|| --- --- | | --- --- | | --- --- ||
+|| |HL1||LH1| | | |HL1||LH1| | | |HL1||LH1| ||
+|| --- --- | | --- --- | | --- --- ||
+|| --- --- | | --- --- | | --- --- ||
+|| |HH1||HL2| | | |HH1||HL2| | | |HH1||HL2| ||
+|| ... | | ... | | ... ||
+| ------------ ------------ ------------ |
+ --------------------------------------------
+
+Decoding process:
+=================
+
+ ------------
+ | |
+ | Subbands |
+ ------------ | |
+ | | ------------
+ | Intra DC | |
+ | | LL0 subband prediction
+ ------------ |
+ \ Dequantizaton
+ ------------------- \ |
+| Reference frames | \ IDWT
+| ------- ------- | Motion \ |
+||Frame 0| |Frame 1|| Compensation . OBMC v -------
+| ------- ------- | --------------. \------> + --->|Frame n|-->output
+| ------- ------- | -------
+||Frame 2| |Frame 3||<----------------------------------/
+| ... |
+ -------------------
+
+
+Range Coder:
+============
+
+Binary Range Coder:
+-------------------
+The implemented range coder is an adapted version based upon "Range encoding:
+an algorithm for removing redundancy from a digitised message." by G. N. N.
+Martin.
+The symbols encoded by the Snow range coder are bits (0|1). The
+associated probabilities are not fix but change depending on the symbol mix
+seen so far.
+
+
+bit seen | new state
+---------+-----------------------------------------------
+ 0 | 256 - state_transition_table[256 - old_state];
+ 1 | state_transition_table[ old_state];
+
+state_transition_table = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
+104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118,
+119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133,
+134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194,
+195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209,
+210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225,
+226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240,
+241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};
+
+FIXME
+
+
+Range Coding of integers:
+-------------------------
+FIXME
+
+
+Neighboring Blocks:
+===================
+left and top are set to the respective blocks unless they are outside of
+the image in which case they are set to the Null block
+
+top-left is set to the top left block unless it is outside of the image in
+which case it is set to the left block
+
+if this block has no larger parent block or it is at the left side of its
+parent block and the top right block is not outside of the image then the
+top right block is used for top-right else the top-left block is used
+
+Null block
+y,cb,cr are 128
+level, ref, mx and my are 0
+
+
+Motion Vector Prediction:
+=========================
+1. the motion vectors of all the neighboring blocks are scaled to
+compensate for the difference of reference frames
+
+scaled_mv= (mv * (256 * (current_reference+1) / (mv.reference+1)) + 128)>>8
+
+2. the median of the scaled left, top and top-right vectors is used as
+motion vector prediction
+
+3. the used motion vector is the sum of the predictor and
+ (mvx_diff, mvy_diff)*mv_scale
+
+
+Intra DC Predicton:
+======================
+the luma and chroma values of the left block are used as predictors
+
+the used luma and chroma is the sum of the predictor and y_diff, cb_diff, cr_diff
+to reverse this in the decoder apply the following:
+block[y][x].dc[0] = block[y][x-1].dc[0] + y_diff;
+block[y][x].dc[1] = block[y][x-1].dc[1] + cb_diff;
+block[y][x].dc[2] = block[y][x-1].dc[2] + cr_diff;
+block[*][-1].dc[*]= 128;
+
+
+Motion Compensation:
+====================
+
+Halfpel interpolation:
+----------------------
+halfpel interpolation is done by convolution with the halfpel filter stored
+in the header:
+
+horizontal halfpel samples are found by
+H1[y][x] = hcoeff[0]*(F[y][x ] + F[y][x+1])
+ + hcoeff[1]*(F[y][x-1] + F[y][x+2])
+ + hcoeff[2]*(F[y][x-2] + F[y][x+3])
+ + ...
+h1[y][x] = (H1[y][x] + 32)>>6;
+
+vertical halfpel samples are found by
+H2[y][x] = hcoeff[0]*(F[y ][x] + F[y+1][x])
+ + hcoeff[1]*(F[y-1][x] + F[y+2][x])
+ + ...
+h2[y][x] = (H2[y][x] + 32)>>6;
+
+vertical+horizontal halfpel samples are found by
+H3[y][x] = hcoeff[0]*(H2[y][x ] + H2[y][x+1])
+ + hcoeff[1]*(H2[y][x-1] + H2[y][x+2])
+ + ...
+H3[y][x] = hcoeff[0]*(H1[y ][x] + H1[y+1][x])
+ + hcoeff[1]*(H1[y+1][x] + H1[y+2][x])
+ + ...
+h3[y][x] = (H3[y][x] + 2048)>>12;
+
+
+ F H1 F
+ | | |
+ | | |
+ | | |
+ F H1 F
+ | | |
+ | | |
+ | | |
+ F-------F-------F-> H1<-F-------F-------F
+ v v v
+ H2 H3 H2
+ ^ ^ ^
+ F-------F-------F-> H1<-F-------F-------F
+ | | |
+ | | |
+ | | |
+ F H1 F
+ | | |
+ | | |
+ | | |
+ F H1 F
+
+
+unavailable fullpel samples (outside the picture for example) shall be equal
+to the closest available fullpel sample
+
+
+Smaller pel interpolation:
+--------------------------
+if diag_mc is set then points which lie on a line between 2 vertically,
+horiziontally or diagonally adjacent halfpel points shall be interpolated
+linearls with rounding to nearest and halfway values rounded up.
+points which lie on 2 diagonals at the same time should only use the one
+diagonal not containing the fullpel point
+
+
+
+ F-->O---q---O<--h1->O---q---O<--F
+ v \ / v \ / v
+ O O O O O O O
+ | / | \ |
+ q q q q q
+ | / | \ |
+ O O O O O O O
+ ^ / \ ^ / \ ^
+ h2-->O---q---O<--h3->O---q---O<--h2
+ v \ / v \ / v
+ O O O O O O O
+ | \ | / |
+ q q q q q
+ | \ | / |
+ O O O O O O O
+ ^ / \ ^ / \ ^
+ F-->O---q---O<--h1->O---q---O<--F
+
+
+
+the remaining points shall be bilinearly interpolated from the
+up to 4 surrounding halfpel and fullpel points, again rounding should be to
+nearest and halfway values rounded up
+
+compliant Snow decoders MUST support 1-1/8 pel luma and 1/2-1/16 pel chroma
+interpolation at least
+
+
+Overlapped block motion compensation:
+-------------------------------------
+FIXME
+
+LL band prediction:
+===================
+Each sample in the LL0 subband is predicted by the median of the left, top and
+left+top-topleft samples, samples outside the subband shall be considered to
+be 0. To reverse this prediction in the decoder apply the following.
+for(y=0; y<height; y++){
+ for(x=0; x<width; x++){
+ sample[y][x] += median(sample[y-1][x],
+ sample[y][x-1],
+ sample[y-1][x]+sample[y][x-1]-sample[y-1][x-1]);
+ }
+}
+sample[-1][*]=sample[*][-1]= 0;
+width,height here are the width and height of the LL0 subband not of the final
+video
+
+
+Dequantizaton:
+==============
+FIXME
+
+Wavelet Transform:
+==================
+
+Snow supports 2 wavelet transforms, the symmetric biorthogonal 5/3 integer
+transform and a integer approximation of the symmetric biorthogonal 9/7
+daubechies wavelet.
+
+2D IDWT (inverse discrete wavelet transform)
+--------------------------------------------
+The 2D IDWT applies a 2D filter recursively, each time combining the
+4 lowest frequency subbands into a single subband until only 1 subband
+remains.
+The 2D filter is done by first applying a 1D filter in the vertical direction
+and then applying it in the horizontal one.
+ --------------- --------------- --------------- ---------------
+|LL0|HL0| | | | | | | | | | | |
+|---+---| HL1 | | L0|H0 | HL1 | | LL1 | HL1 | | | |
+|LH0|HH0| | | | | | | | | | | |
+|-------+-------|->|-------+-------|->|-------+-------|->| L1 | H1 |->...
+| | | | | | | | | | | |
+| LH1 | HH1 | | LH1 | HH1 | | LH1 | HH1 | | | |
+| | | | | | | | | | | |
+ --------------- --------------- --------------- ---------------
+
+
+1D Filter:
+----------
+1. interleave the samples of the low and high frequency subbands like
+s={L0, H0, L1, H1, L2, H2, L3, H3, ... }
+note, this can end with a L or a H, the number of elements shall be w
+s[-1] shall be considered equivalent to s[1 ]
+s[w ] shall be considered equivalent to s[w-2]
+
+2. perform the lifting steps in order as described below
+
+5/3 Integer filter:
+1. s[i] -= (s[i-1] + s[i+1] + 2)>>2; for all even i < w
+2. s[i] += (s[i-1] + s[i+1] )>>1; for all odd i < w
+
+\ | /|\ | /|\ | /|\ | /|\
+ \|/ | \|/ | \|/ | \|/ |
+ + | + | + | + | -1/4
+ /|\ | /|\ | /|\ | /|\ |
+/ | \|/ | \|/ | \|/ | \|/
+ | + | + | + | + +1/2
+
+
+Snow's 9/7 Integer filter:
+1. s[i] -= (3*(s[i-1] + s[i+1]) + 4)>>3; for all even i < w
+2. s[i] -= s[i-1] + s[i+1] ; for all odd i < w
+3. s[i] += ( s[i-1] + s[i+1] + 4*s[i] + 8)>>4; for all even i < w
+4. s[i] += (3*(s[i-1] + s[i+1]) )>>1; for all odd i < w
+
+\ | /|\ | /|\ | /|\ | /|\
+ \|/ | \|/ | \|/ | \|/ |
+ + | + | + | + | -3/8
+ /|\ | /|\ | /|\ | /|\ |
+/ | \|/ | \|/ | \|/ | \|/
+ (| + (| + (| + (| + -1
+\ + /|\ + /|\ + /|\ + /|\ +1/4
+ \|/ | \|/ | \|/ | \|/ |
+ + | + | + | + | +1/16
+ /|\ | /|\ | /|\ | /|\ |
+/ | \|/ | \|/ | \|/ | \|/
+ | + | + | + | + +3/2
+
+optimization tips:
+following are exactly identical
+(3a)>>1 == a + (a>>1)
+(a + 4b + 8)>>4 == ((a>>2) + b + 2)>>2
+
+16bit implementation note:
+The IDWT can be implemented with 16bits, but this requires some care to
+prevent overflows, the following list, lists the minimum number of bits needed
+for some terms
+1. lifting step
+A= s[i-1] + s[i+1] 16bit
+3*A + 4 18bit
+A + (A>>1) + 2 17bit
+
+3. lifting step
+s[i-1] + s[i+1] 17bit
+
+4. lifiting step
+3*(s[i-1] + s[i+1]) 17bit
+
+
+TODO:
+=====
+Important:
+finetune initial contexts
+flip wavelet?
+try to use the wavelet transformed predicted image (motion compensated image) as context for coding the residual coefficients
+try the MV length as context for coding the residual coefficients
+use extradata for stuff which is in the keyframes now?
+implement per picture halfpel interpolation
+try different range coder state transition tables for different contexts
+
+Not Important:
+compare the 6 tap and 8 tap hpel filters (psnr/bitrate and subjective quality)
+spatial_scalability b vs u (!= 0 breaks syntax anyway so we can add a u later)
+
+
+Credits:
+========
+Michael Niedermayer
+Loren Merritt
+
+
+Copyright:
+==========
+GPL + GFDL + whatever is needed to make this a RFC
diff --git a/doc/soc.txt b/doc/soc.txt
deleted file mode 100644
index 89728b5201..0000000000
--- a/doc/soc.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Google Summer of Code and similar project guidelines
-
-Summer of Code is a project by Google in which students are paid to implement
-some nice new features for various participating open source projects ...
-
-This text is a collection of things to take care of for the next soc as
-it's a little late for this year's soc (2006).
-
-The Goal:
-Our goal in respect to soc is and must be of course exactly one thing and
-that is to improve Libav, to reach this goal, code must
-* conform to the development policy and patch submission guidelines
-* must improve Libav somehow (faster, smaller, "better",
- more codecs supported, fewer bugs, cleaner, ...)
-
-for mentors and other developers to help students to reach that goal it is
-essential that changes to their codebase are publicly visible, clean and
-easy reviewable that again leads us to:
-* use of a revision control system like git
-* separation of cosmetic from non-cosmetic changes (this is almost entirely
- ignored by mentors and students in soc 2006 which might lead to a surprise
- when the code will be reviewed at the end before a possible inclusion in
- Libav, individual changes were generally not reviewable due to cosmetics).
-* frequent commits, so that comments can be provided early
diff --git a/doc/style.min.css b/doc/style.min.css
new file mode 100644
index 0000000000..6843fda57d
--- /dev/null
+++ b/doc/style.min.css
@@ -0,0 +1,23 @@
+/*!
+The MIT License (MIT)
+
+Copyright (c) 2014 Barbara Lepage <db0company@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */body{background-color:#313131;color:#e6e6e6;text-align:justify}body, h1, h2, h3, h4, h5, h6{font-family:"Lucida Grande","Lucida Sans Unicode","Lucida Sans","Helvetica Neue",Helvetica,Verdana,Tahoma,sans-serif}a{color:#4cae4c}a strong{color:#e6e6e6}a:hover{color:#7fc77f}a:hover strong{color:#4cae4c}main{width:100% ! important;min-height:600px;margin:auto}h1, h2, h3, h4{font-weight:bold;text-align:left}h1, h2, h3{color:#bebebe}h1 strong, h2 strong, h3 strong{color:#e6e6e6}h4, h5, h6{color:#3c8b3c}h1{border-bottom:4px #bebebe solid;padding:20px 2%}h3{border-bottom:2px #bebebe solid;padding:15px 1%}h4{border-bottom:1px solid #e6e6e6;padding:10px 0;margin:20px 0;color:#e6e6e6}.list-group .list-group-item{background-color:#3e3e3e;border-color:black}.list-group.list-group-big .list-group-item{padding:25px}.list-group a.list-group-item{color:#7fc77f}.list-group a.list-group-item:hover{background-color:#313131;color:#4cae4c}.well{background-color:#242424;border-color:black;color:#bebebe}.well strong{color:#e6e6e6}.well code{background-color:#313131}.well hr{border-color:#3c8b3c}.well h3{margin:5px 0 15px 0;border:0;padding:0}.well a{color:#4cae4c}.well a.btn{color:white}.well small{display:block;padding:0 10px;font-style:italic}.well.example{padding-top:40px;margin-bottom:130px}.well.example pre{margin:50px;margin-bottom:30px;font-size:1.5em}.well.example .btn{margin-right:50px;margin-bottom:20px}.well.well-with-icon{min-height:136px}.well.well-with-icon .pull-right,.well.well-with-icon .pull-left{background-color:#4cae4c;color:#e6e6e6;padding:10px;border-radius:5px;margin:5px}.well.well-with-icon .pull-right{margin-left:20px}.well.well-with-icon .pull-left{margin-right:20px}a.well{display:block}a.well:hover{text-decoration:none;opacity:0.8}.info, .warning{margin:10px;padding:10px;background-color:#3e3e3e;color:#e6e6e6}.info code, .warning code{background-color:#313131}.info{border-left:10px #4cae4c solid}.warning{border-left:10px #ae4c4c solid}.with-icon{padding:30px}.with-icon .pull-left{padding-right:30px}.with-icon .pull-right{padding-left:30px}dd{margin-left:20px}code{background-color:#242424;color:#7fc77f;display:inline-block;margin:5px}.table{margin:20px 0;border-radius:4px}.table th,.table td,.table tr{border:1px solid #171717}.table tr th{background-color:#3e3e3e;border-bottom:2px solid #e6e6e6}.table tr:nth-child(odd){background-color:#242424}#sidebar-wrapper, .navbar{background-color:#171717;overflow-x:hidden}#sidebar-wrapper .sidebar-brand img,#sidebar-wrapper .navbar-brand img, .navbar .sidebar-brand img, .navbar .navbar-brand img{opacity:0.6;margin-right:8px}#sidebar-wrapper .sidebar-brand:hover,#sidebar-wrapper .navbar-brand:hover, .navbar .sidebar-brand:hover, .navbar .navbar-brand:hover{color:#fff}#sidebar-wrapper .sidebar-brand:hover img,#sidebar-wrapper .navbar-brand:hover img, .navbar .sidebar-brand:hover img, .navbar .navbar-brand:hover img{opacity:1}#sidebar-wrapper .sidebar-nav li ul, .navbar .sidebar-nav li ul{list-style-type:none;padding:0}#sidebar-wrapper .sidebar-nav li ul li, .navbar .sidebar-nav li ul li{line-height:20px}#sidebar-wrapper .sidebar-nav li ul li a, .navbar .sidebar-nav li ul li a{padding-left:20px}.content-header{height:auto;background-color:#242424}.content-header h1{color:#e6e6e6;display:block;margin:0;margin-bottom:20px;line-height:normal;border-bottom:none}#download h4, #index h4{margin-top:180px}#download h4.first, #index h4.first{margin-top:20px}#download h4.first small, #index h4.first small{color:inherit;font-size:1em}#download .btn-download-wrapper, #index .btn-download-wrapper{text-align:center;margin:160px auto}#download .btn-download-wrapper .btn, #index .btn-download-wrapper .btn{font-size:3em;padding:3%;display:inline-block;margin-bottom:5px}#download .btn-download-wrapper small, #index .btn-download-wrapper small{display:block;font-size:0.4em}#download h2.description, #index h2.description{color:#e6e6e6;font-size:2em;font-weight:bold;margin:120px 50px;line-height:2em}#download h2.description .label, #index h2.description .label{font-size:0.5em}#download .btn-download-wrapper{margin:40px auto}#download .os-selector{text-align:center;color:#e6e6e6;margin:30px 0}#download .os-selector a.btn-build{color:#e6e6e6;display:block;padding:20px;border-radius:2px}#download .os-selector .btn-build[href="#build-linux"]{background-color:#e43}#download .os-selector .btn-build[href="#build-linux"]:hover{color:#e43;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-windows"]{background-color:#06a}#download .os-selector .btn-build[href="#build-windows"]:hover{color:#06a;background-color:#e6e6e6}#download .os-selector .btn-build[href="#build-mac"]{background-color:darkgrey}#download .os-selector .btn-build[href="#build-mac"]:hover{color:darkgrey;background-color:#e6e6e6}#download .os-selector .tab-content{margin-top:20px}#download .os-selector #build-linux h3{color:#e43}#download .os-selector #build-windows h3{color:#06a}#download .os-selector #build-mac h3{color:darkgrey}footer{background-color:#242424;border-top:1px #101010 solid;padding:20px 0%}footer a{display:block}footer img[alt="FFmpeg"]{width:50%;display:block;margin:auto}
diff --git a/doc/swresample.txt b/doc/swresample.txt
new file mode 100644
index 0000000000..2d192a394e
--- /dev/null
+++ b/doc/swresample.txt
@@ -0,0 +1,46 @@
+ The official guide to swresample for confused developers.
+ =========================================================
+
+Current (simplified) Architecture:
+---------------------------------
+ Input
+ v
+ __________________/|\___________
+ / | \
+ / input sample format convert v
+ / | ___________/
+ | |/
+ | v
+ | ___________/|\___________ _____________
+ | / | \ | |
+ | Rematrix | resample <---->| Buffers |
+ | \___________ | ___________/ |_____________|
+ v \|/
+Special Converter v
+ v ___________/|\___________ _____________
+ | / | \ | |
+ | Rematrix | resample <---->| Buffers |
+ | \___________ | ___________/ |_____________|
+ | \|/
+ | v
+ | |\___________
+ \ | \
+ \ output sample format convert v
+ \_________________ | ___________/
+ \|/
+ v
+ Output
+
+Planar/Packed conversion is done when needed during sample format conversion.
+Every step can be skipped without memcpy when it is not needed.
+Either Resampling and Rematrixing can be performed first depending on which
+way it is faster.
+The Buffers are needed for resampling due to resamplng being a process that
+requires future and past data, it thus also introduces inevitably a delay when
+used.
+Internally 32bit float and 16bit int is supported currently, other formats can
+easily be added.
+Externally all sample formats in packed and planar configuration are supported
+It's also trivial to add special converters for common cases.
+If only sample format and/or packed/planar conversion is needed, it
+is performed from input to output directly in a single pass with no intermediates.
diff --git a/doc/t2h.init b/doc/t2h.init
index a42637ae0a..c41be2ef37 100644
--- a/doc/t2h.init
+++ b/doc/t2h.init
@@ -1,160 +1,53 @@
-# no horiz rules between sections
-$end_section = \&Libav_end_section;
-sub Libav_end_section($$)
-{
-}
-
-$EXTRA_HEAD =
-'<link rel="icon" href="favicon.png" type="image/png" />
-';
-
-$CSS_LINES = $ENV{"LIBAV_CSS"} || <<EOT;
-<style type="text/css">
-<!--
-.container {
- margin-right: auto;
- margin-left: auto;
- width: 1070px;
-}
-body {
- font-size: 14px;
- line-height: 20px;
- color: #333333;
- background-color: #ffffff;
-}
-a {
- color: #0088cc;
- text-decoration: none;
-}
-a:hover {
- color: #005580;
- text-decoration: underline;
-}
-p {
- margin: 0 0 10px;
-}
-h2,
-h3,
-h4 {
- margin: 10px 0;
- font-family: inherit;
- font-weight: bold;
- line-height: 1;
- border-color: #D6E9C6;
- color: #468847;
- border-style: solid;
- border-width: 0 0 1px;
- padding-left: 0.5em;
-}
+# Init file for texi2html.
-h1 a,
-h2 a,
-h3 a,
-h4 a {
- color: inherit;
-}
-h1 {
- font-size: 30px;
- line-height: 40px;
-}
-h2 {
- font-size: 20px;
- line-height: 40px;
-}
-h3 {
- font-size: 18px;
- line-height: 40px;
-}
-code,
-pre {
- padding: 0 3px 2px;
- font-family: monospace;
- font-size: 12px;
- color: #333333;
- border-radius: 3px;
-}
-pre {
- display: block;
- padding: 9.5px;
- margin: 0 0 10px;
- font-size: 13px;
- line-height: 20px;
- word-break: break-all;
- word-wrap: break-word;
- white-space: pre;
- white-space: pre-wrap;
- background-color: #f5f5f5;
- border: 1px solid #ccc;
- border-radius: 4px;
-}
-
-code {
- padding: 2px 4px;
- color: #d14;
- background-color: #f7f7f9;
- border: 1px solid #e1e1e8;
-}
-pre code {
- padding: 0;
- color: inherit;
- background-color: transparent;
- border: 0;
-}
-.alert {
- padding: 8px 35px 8px 14px;
- margin-bottom: 20px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- background-color: #fcf8e3;
- border: 1px solid #fbeed5;
- border-radius: 4px;
- color: #c09853;
-}
+# This is deprecated, and the makeinfo/texi2any version is doc/t2h.pm
-.alert-danger,
-.alert-error {
- background-color: #f2dede;
- border-color: #eed3d7;
- color: #b94a48;
-}
-.alert-info {
- background-color: #d9edf7;
- border-color: #bce8f1;
- color: #3a87ad;
+# no horiz rules between sections
+$end_section = \&FFmpeg_end_section;
+sub FFmpeg_end_section($$)
+{
}
-ul.toc {
- list-style-type: none;
-}
--->
-</style>
+my $TEMPLATE_HEADER1 = $ENV{"FFMPEG_HEADER1"} || <<EOT;
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <title>FFmpeg documentation</title>
+ <link rel="stylesheet" href="bootstrap.min.css" />
+ <link rel="stylesheet" href="style.min.css" />
EOT
-my $TEMPLATE_HEADER = $ENV{"LIBAV_HEADER"} || <<EOT;
-<link rel="icon" href="favicon.png" type="image/png" />
-</head>
-<body>
-<div class="container">
+my $TEMPLATE_HEADER2 = $ENV{"FFMPEG_HEADER2"} || <<EOT;
+ </head>
+ <body>
+ <div style="width: 95%; margin: auto">
EOT
-$PRE_BODY_CLOSE = '</div></div>';
+my $TEMPLATE_FOOTER = $ENV{"FFMPEG_FOOTER"} || <<EOT;
+ </div>
+ </body>
+</html>
+EOT
$SMALL_RULE = '';
$BODYTEXT = '';
-$print_page_foot = \&Libav_print_page_foot;
-sub Libav_print_page_foot($$)
+$print_page_foot = \&FFmpeg_print_page_foot;
+sub FFmpeg_print_page_foot($$)
{
my $fh = shift;
my $program_string = defined &T2H_DEFAULT_program_string ?
T2H_DEFAULT_program_string() : program_string();
print $fh '<footer class="footer pagination-right">' . "\n";
print $fh '<span class="label label-info">' . $program_string;
- print $fh "</span></footer></div>\n";
+ print $fh "</span></footer></div></div></body>\n";
}
-$float = \&Libav_float;
+$float = \&FFmpeg_float;
-sub Libav_float($$$$)
+sub FFmpeg_float($$$$)
{
my $text = shift;
my $float = shift;
@@ -181,8 +74,8 @@ sub Libav_float($$$$)
return '<div class="float ' . $class . '">' . "$label\n" . $text . '</div>';
}
-$print_page_head = \&Libav_print_page_head;
-sub Libav_print_page_head($$)
+$print_page_head = \&FFmpeg_print_page_head;
+sub FFmpeg_print_page_head($$)
{
my $fh = shift;
my $longtitle = "$Texi2HTML::THISDOC{'fulltitle_no_texi'}";
@@ -195,29 +88,34 @@ sub Libav_print_page_head($$)
my $encoding = '';
$encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$ENCODING\">" if (defined($ENCODING) and ($ENCODING ne ''));
$longtitle =~ s/Documentation.*//g;
- $longtitle = "Libav documentation : " . $longtitle;
+ $longtitle = "FFmpeg documentation : " . $longtitle;
print $fh <<EOT;
-<!DOCTYPE html>
-<html>
+$TEMPLATE_HEADER1
+$description
+<meta name="keywords" content="$longtitle">
+<meta name="Generator" content="$Texi2HTML::THISDOC{program}">
$Texi2HTML::THISDOC{'copying'}<!-- Created on $Texi2HTML::THISDOC{today} by $Texi2HTML::THISDOC{program} -->
<!--
$Texi2HTML::THISDOC{program_authors}
-->
-<head>
-<title>$longtitle</title>
-
-$description
-<meta name="keywords" content="$longtitle">
-<meta name="resource-type" content="document">
-<meta name="distribution" content="global">
-<meta name="Generator" content="$Texi2HTML::THISDOC{program}">
$encoding
-$CSS_LINES
-$TEMPLATE_HEADER
+$TEMPLATE_HEADER2
EOT
}
+$print_page_foot = \&FFmpeg_print_page_foot;
+sub FFmpeg_print_page_foot($$)
+{
+ my $fh = shift;
+ print $fh <<EOT;
+$TEMPLATE_FOOTER
+EOT
+}
+
+# declare encoding in header
+$IN_ENCODING = $ENCODING = "utf-8";
+
# no navigation elements
$SECTION_NAVIGATION = 0;
# the same for texi2html 5.0
diff --git a/doc/t2h.pm b/doc/t2h.pm
new file mode 100644
index 0000000000..5efb2da483
--- /dev/null
+++ b/doc/t2h.pm
@@ -0,0 +1,339 @@
+# makeinfo HTML output init file
+#
+# Copyright (c) 2011, 2012 Free Software Foundation, Inc.
+# Copyright (c) 2014 Andreas Cadhalpun
+# Copyright (c) 2014 Tiancheng "Timothy" Gu
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that 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
+
+# no navigation elements
+set_from_init_file('HEADERS', 0);
+
+sub ffmpeg_heading_command($$$$$)
+{
+ my $self = shift;
+ my $cmdname = shift;
+ my $command = shift;
+ my $args = shift;
+ my $content = shift;
+
+ my $result = '';
+
+ # not clear that it may really happen
+ if ($self->in_string) {
+ $result .= $self->command_string($command) ."\n" if ($cmdname ne 'node');
+ $result .= $content if (defined($content));
+ return $result;
+ }
+
+ my $element_id = $self->command_id($command);
+ $result .= "<a name=\"$element_id\"></a>\n"
+ if (defined($element_id) and $element_id ne '');
+
+ 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'};
+ }
+ if ($element) {
+ $result .= &{$self->{'format_element_header'}}($self, $cmdname,
+ $command, $element);
+ }
+
+ 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
+ # bogus node may not have been normalized
+ and defined($command->{'extra'}->{'normalized'}))) {
+ if ($command->{'extra'}->{'normalized'} eq 'Top') {
+ $heading_level = 0;
+ } else {
+ $heading_level = 3;
+ }
+ }
+ } else {
+ $heading_level = $command->{'level'};
+ }
+
+ my $heading = $self->command_text($command);
+ # $heading not defined may happen if the command is a @node, for example
+ # 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}) {
+ my $content_href = $self->command_contents_href($command, 'contents',
+ $self->{'current_filename'});
+ if ($content_href) {
+ my $this_href = $content_href =~ s/^\#toc-/\#/r;
+ $heading .= '<span class="pull-right">'.
+ '<a class="anchor hidden-xs" '.
+ "href=\"$this_href\" aria-hidden=\"true\">".
+ ($ENV{"FA_ICONS"} ? '<i class="fa fa-link"></i>'
+ : '#').
+ '</a> '.
+ '<a class="anchor hidden-xs"'.
+ "href=\"$content_href\" aria-hidden=\"true\">".
+ ($ENV{"FA_ICONS"} ? '<i class="fa fa-navicon"></i>'
+ : 'TOC').
+ '</a>'.
+ '</span>';
+ }
+ }
+
+ if ($self->in_preformatted()) {
+ $result .= $heading."\n";
+ } else {
+ # if the level was changed, set the command name right
+ if ($cmdname ne 'node'
+ and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) {
+ $cmdname
+ = $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level];
+ }
+ $result .= &{$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') {
+ texinfo_register_command_formatting($command, \&ffmpeg_heading_command);
+}
+
+# print the TOC where @contents is used
+set_from_init_file('INLINE_CONTENTS', 1);
+
+# make chapters <h2>
+set_from_init_file('CHAPTER_HEADER_LEVEL', 2);
+
+# Do not add <hr>
+set_from_init_file('DEFAULT_RULE', '');
+set_from_init_file('BIG_RULE', '');
+
+# Customized file beginning
+sub ffmpeg_begin_file($$$)
+{
+ my $self = shift;
+ my $filename = shift;
+ my $element = shift;
+
+ my $command;
+ if ($element and $self->get_conf('SPLIT')) {
+ $command = $self->element_command($element);
+ }
+
+ my ($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);
+
+ my $links = $self->_get_links ($filename, $element);
+
+ my $head1 = $ENV{"FFMPEG_HEADER1"} || <<EOT;
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!-- Created by $program_and_version, $program_homepage -->
+ <head>
+ <meta charset="utf-8">
+ <title>
+EOT
+ my $head_title = <<EOT;
+ $title
+EOT
+
+ my $head2 = $ENV{"FFMPEG_HEADER2"} || <<EOT;
+ </title>
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
+ <link rel="stylesheet" type="text/css" href="bootstrap.min.css">
+ <link rel="stylesheet" type="text/css" href="style.min.css">
+ </head>
+ <body>
+ <div style="width: 95%; margin: auto">
+ <h1>
+EOT
+
+ my $head3 = $ENV{"FFMPEG_HEADER3"} || <<EOT;
+ </h1>
+EOT
+
+ return $head1 . $head_title . $head2 . $head_title . $head3;
+}
+texinfo_register_formatting_function('begin_file', \&ffmpeg_begin_file);
+
+sub ffmpeg_program_string($)
+{
+ my $self = shift;
+ if (defined($self->get_conf('PROGRAM'))
+ and $self->get_conf('PROGRAM') ne ''
+ and defined($self->get_conf('PACKAGE_URL'))) {
+ 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') }));
+ } else {
+ return $self->convert_tree(
+ $self->gdt('This document was generated automatically.'));
+ }
+}
+texinfo_register_formatting_function('program_string', \&ffmpeg_program_string);
+
+# Customized file ending
+sub ffmpeg_end_file($)
+{
+ my $self = shift;
+ my $program_string = &{$self->{'format_program_string'}}($self);
+ my $program_text = <<EOT;
+ <p style="font-size: small;">
+ $program_string
+ </p>
+EOT
+ my $footer = $ENV{FFMPEG_FOOTER} || <<EOT;
+ </div>
+ </body>
+</html>
+EOT
+ return $program_text . $footer;
+}
+texinfo_register_formatting_function('end_file', \&ffmpeg_end_file);
+
+# Dummy title command
+# Ignore title. Title is handled through ffmpeg_begin_file().
+set_from_init_file('USE_TITLEPAGE_FOR_TITLE', 1);
+sub ffmpeg_title($$$$)
+{
+ return '';
+}
+
+texinfo_register_command_formatting('titlefont',
+ \&ffmpeg_title);
+
+# Customized float command. Part of code borrowed from GNU Texinfo.
+sub ffmpeg_float($$$$$)
+{
+ my $self = shift;
+ my $cmdname = shift;
+ my $command = shift;
+ my $args = shift;
+ my $content = shift;
+
+ my ($caption, $prepended) = Texinfo::Common::float_name_caption($self,
+ $command);
+ my $caption_text = '';
+ my $prepended_text;
+ my $prepended_save = '';
+
+ if ($self->in_string()) {
+ if ($prepended) {
+ $prepended_text = $self->convert_tree_new_formatting_context(
+ $prepended, 'float prepended');
+ } else {
+ $prepended_text = '';
+ }
+ if ($caption) {
+ $caption_text = $self->convert_tree_new_formatting_context(
+ {'contents' => $caption->{'args'}->[0]->{'contents'}},
+ 'float caption');
+ }
+ return $prepended.$content.$caption_text;
+ }
+
+ my $id = $self->command_id($command);
+ my $label;
+ if (defined($id) and $id ne '') {
+ $label = "<a name=\"$id\"></a>";
+ } else {
+ $label = '';
+ }
+
+ if ($prepended) {
+ if ($caption) {
+ # prepend the prepended tree to the first paragraph
+ my @caption_original_contents = @{$caption->{'args'}->[0]->{'contents'}};
+ my @caption_contents;
+ my $new_paragraph;
+ while (@caption_original_contents) {
+ my $content = shift @caption_original_contents;
+ if ($content->{'type'} and $content->{'type'} eq 'paragraph') {
+ %{$new_paragraph} = %{$content};
+ $new_paragraph->{'contents'} = [@{$content->{'contents'}}];
+ unshift (@{$new_paragraph->{'contents'}}, {'cmdname' => 'strong',
+ 'args' => [{'type' => 'brace_command_arg',
+ 'contents' => [$prepended]}]});
+ push @caption_contents, $new_paragraph;
+ last;
+ } else {
+ push @caption_contents, $content;
+ }
+ }
+ push @caption_contents, @caption_original_contents;
+ if ($new_paragraph) {
+ $caption_text = $self->convert_tree_new_formatting_context(
+ {'contents' => \@caption_contents}, 'float caption');
+ $prepended_text = '';
+ }
+ }
+ if ($caption_text eq '') {
+ $prepended_text = $self->convert_tree_new_formatting_context(
+ $prepended, 'float prepended');
+ if ($prepended_text ne '') {
+ $prepended_save = $prepended_text;
+ $prepended_text = '<p><strong>'.$prepended_text.'</strong></p>';
+ }
+ }
+ } else {
+ $prepended_text = '';
+ }
+
+ if ($caption and $caption_text eq '') {
+ $caption_text = $self->convert_tree_new_formatting_context(
+ $caption->{'args'}->[0], 'float caption');
+ }
+ if ($prepended_text.$caption_text ne '') {
+ $prepended_text = $self->_attribute_class('div','float-caption'). '>'
+ . $prepended_text;
+ $caption_text .= '</div>';
+ }
+ my $html_class = '';
+ if ($prepended_save =~ /NOTE/) {
+ $html_class = 'info';
+ $prepended_text = '';
+ $caption_text = '';
+ } elsif ($prepended_save =~ /IMPORTANT/) {
+ $html_class = 'warning';
+ $prepended_text = '';
+ $caption_text = '';
+ }
+ return $self->_attribute_class('div', $html_class). '>' . "\n" .
+ $prepended_text . $caption_text . $content . '</div>';
+}
+
+texinfo_register_command_formatting('float',
+ \&ffmpeg_float);
+
+1;
diff --git a/doc/texi2pod.pl b/doc/texi2pod.pl
index e4eb61c26c..e1ff6b46d4 100755..100644
--- a/doc/texi2pod.pl
+++ b/doc/texi2pod.pl
@@ -27,9 +27,9 @@ use warnings;
$output = 0;
$skipping = 0;
-%sects = ();
-@sects_sequence = ();
-$section = "";
+%chapters = ();
+@chapters_sequence = ();
+$chapter = "";
@icstack = ();
@endwstack = ();
@skstack = ();
@@ -116,18 +116,24 @@ INF: while(<$inf>) {
die "cannot open $1: $!\n";
};
- # Look for blocks surrounded by @c man begin SECTION ... @c man end.
- # This really oughta be @ifman ... @end ifman and the like, but such
- # would require rev'ing all other Texinfo translators.
- /^\@c\s+man\s+begin\s+([A-Za-z ]+)/ and $sect = $1, push (@sects_sequence, $sect), $output = 1, next;
- /^\@c\s+man\s+end/ and do {
- $sects{$sect} = "" unless exists $sects{$sect};
- $sects{$sect} .= postprocess($section);
- $section = "";
- $output = 0;
+ /^\@chapter\s+([A-Za-z ]+)/ and do {
+ # close old chapter
+ $chapters{$chapter_name} .= postprocess($chapter) if ($chapter_name);
+
+ # start new chapter
+ $chapter_name = $1, push (@chapters_sequence, $chapter_name) unless $skipping;
+ $chapters{$chapter_name} = "" unless exists $chapters{$chapter_name};
+ $chapter = "";
+ $output = 1;
next;
};
+ /^\@bye/ and do {
+ # close old chapter
+ $chapters{$chapter_name} .= postprocess($chapter) if ($chapter_name);
+ last INF;
+ };
+
# handle variables
/^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
$defs{$1} = $2;
@@ -150,17 +156,17 @@ INF: while(<$inf>) {
# Ignore @end foo, where foo is not an operation which may
# cause us to skip, if we are presently skipping.
my $ended = $1;
- next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex)$/;
+ next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|ifhtml|ifnothtml)$/;
die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
$endw = pop @endwstack;
- if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
+ if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex|ifhtml|ifnothtml)$/) {
$skipping = pop @skstack;
next;
- } elsif ($ended =~ /^(?:example|smallexample|display)$/) {
+ } elsif ($ended =~ /^(?:example|smallexample|verbatim|display)$/) {
$shift = "";
$_ = ""; # need a paragraph break
} elsif ($ended =~ /^(?:itemize|enumerate|(?:multi|[fv])?table)$/) {
@@ -190,11 +196,11 @@ INF: while(<$inf>) {
next;
};
- /^\@(ignore|menu|iftex)\b/ and do {
+ /^\@(ignore|menu|iftex|ifhtml|ifnothtml)\b/ and do {
push @endwstack, $endw;
push @skstack, $skipping;
$endw = $1;
- $skipping = 1;
+ $skipping = $endw !~ /ifnothtml/;
next;
};
@@ -211,7 +217,6 @@ INF: while(<$inf>) {
s/\@TeX\{\}/TeX/g;
s/\@pounds\{\}/\#/g;
s/\@minus(?:\{\})?/-/g;
- s/\\,/,/g;
# Now the ones that have to be replaced by special escapes
# (which will be turned back into text by unmunge())
@@ -269,7 +274,7 @@ INF: while(<$inf>) {
push @icstack, $ic;
$endw = $1;
$ic = $2;
- $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env)/B/;
+ $ic =~ s/\@(?:samp|strong|key|gcctabopt|option|env|command)/B/;
$ic =~ s/\@(?:code|kbd)/C/;
$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
$ic =~ s/\@(?:file)/F/;
@@ -285,7 +290,7 @@ INF: while(<$inf>) {
$_ = "\n=over 4\n";
};
- /^\@((?:small)?example|display)/ and do {
+ /^\@((?:small)?example|verbatim|display)/ and do {
push @endwstack, $endw;
$endw = $1;
$shift = "\t";
@@ -304,7 +309,7 @@ INF: while(<$inf>) {
$columns =~ s/\@tab//;
$_ = $columns;
- $section =~ s/$//;
+ $chapter =~ s/$//;
};
/^\@itemx?\s*(.+)?$/ and do {
@@ -318,7 +323,7 @@ INF: while(<$inf>) {
}
};
- $section .= $shift.$_."\n";
+ $chapter .= $shift.$_."\n";
}
# End of current file.
close($inf);
@@ -330,16 +335,15 @@ die "No filename or title\n" unless defined $fn && defined $tl;
# always use utf8
print "=encoding utf8\n\n";
-$sects{NAME} = "$fn \- $tl\n";
-$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
+$chapters{NAME} = "$fn \- $tl\n";
+$chapters{FOOTNOTES} .= "=back\n" if exists $chapters{FOOTNOTES};
-unshift @sects_sequence, "NAME";
-for $sect (@sects_sequence) {
- if(exists $sects{$sect}) {
- $head = $sect;
- $head =~ s/SEEALSO/SEE ALSO/;
+unshift @chapters_sequence, "NAME";
+for $chapter (@chapters_sequence) {
+ if (exists $chapters{$chapter}) {
+ $head = uc($chapter);
print "=head1 $head\n\n";
- print scalar unmunge ($sects{$sect});
+ print scalar unmunge ($chapters{$chapter});
print "\n";
}
}
@@ -384,7 +388,8 @@ sub postprocess
s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
s/;\s+\@pxref\{(?:[^\}]*)\}//g;
- s/\@ref\{([^\}]*)\}/$1/g;
+ s/\@ref\{(?:[^,\}]*,)(?:[^,\}]*,)([^,\}]*).*\}/B<$1>/g;
+ s/\@ref\{([^\}]*)\}/B<$1>/g;
s/\@noindent\s*//g;
s/\@refill//g;
s/\@gol//g;
@@ -393,7 +398,7 @@ sub postprocess
# @uref can take one, two, or three arguments, with different
# semantics each time. @url and @email are just like @uref with
# one argument, for our purposes.
- s/\@(?:uref|url|email)\{([^\},]*)\}/&lt;B<$1>&gt;/g;
+ s/\@(?:uref|url|email)\{([^\},]*),?[^\}]*\}/&lt;B<$1>&gt;/g;
s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
@@ -437,13 +442,13 @@ sub unmunge
sub add_footnote
{
- unless (exists $sects{FOOTNOTES}) {
- $sects{FOOTNOTES} = "\n=over 4\n\n";
+ unless (exists $chapters{FOOTNOTES}) {
+ $chapters{FOOTNOTES} = "\n=over 4\n\n";
}
- $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
- $sects{FOOTNOTES} .= $_[0];
- $sects{FOOTNOTES} .= "\n\n";
+ $chapters{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
+ $chapters{FOOTNOTES} .= $_[0];
+ $chapters{FOOTNOTES} .= "\n\n";
}
# stolen from Symbol.pm
diff --git a/doc/texidep.pl b/doc/texidep.pl
new file mode 100644
index 0000000000..099690378e
--- /dev/null
+++ b/doc/texidep.pl
@@ -0,0 +1,32 @@
+#! /usr/bin/env perl
+
+# This script will print the dependency of a Texinfo file to stdout.
+# texidep.pl <src-path> <input.texi> <output.ext>
+
+use warnings;
+use strict;
+
+die unless @ARGV == 3;
+
+my ($src_path, $root, $target) = @ARGV;
+
+sub print_deps {
+ my ($file, $deps) = @_;
+ $deps->{$file} = 1;
+
+ open(my $fh, "<", "$file") or die "Cannot open file '$file': $!";
+ while (<$fh>) {
+ if (my ($i) = /^\@(?:verbatim)?include\s+(\S+)/) {
+ die "Circular dependency found in file $root\n" if exists $deps->{"doc/$1"};
+ print "$target: doc/$1\n";
+
+ # skip looking for config.texi dependencies, since it has
+ # none, and is not located in the source tree
+ if ("$1" ne "config.texi") {
+ print_deps("$src_path/doc/$1", {%$deps});
+ }
+ }
+ }
+}
+
+print_deps($root, {});
diff --git a/doc/utils.texi b/doc/utils.texi
new file mode 100644
index 0000000000..6517ac0a97
--- /dev/null
+++ b/doc/utils.texi
@@ -0,0 +1,1067 @@
+@chapter Syntax
+@c man begin SYNTAX
+
+This section documents the syntax and formats employed by the FFmpeg
+libraries and tools.
+
+@anchor{quoting_and_escaping}
+@section Quoting and escaping
+
+FFmpeg adopts the following quoting and escaping mechanism, unless
+explicitly specified. The following rules are applied:
+
+@itemize
+@item
+@samp{'} and @samp{\} are special characters (respectively used for
+quoting and escaping). In addition to them, there might be other
+special characters depending on the specific syntax where the escaping
+and quoting are employed.
+
+@item
+A special character is escaped by prefixing it with a @samp{\}.
+
+@item
+All characters enclosed between @samp{''} are included literally in the
+parsed string. The quote character @samp{'} itself cannot be quoted,
+so you may need to close the quote and escape it.
+
+@item
+Leading and trailing whitespaces, unless escaped or quoted, are
+removed from the parsed string.
+@end itemize
+
+Note that you may need to add a second level of escaping when using
+the command line or a script, which depends on the syntax of the
+adopted shell language.
+
+The function @code{av_get_token} defined in
+@file{libavutil/avstring.h} can be used to parse a token quoted or
+escaped according to the rules defined above.
+
+The tool @file{tools/ffescape} in the FFmpeg source tree can be used
+to automatically quote or escape a string in a script.
+
+@subsection Examples
+
+@itemize
+@item
+Escape the string @code{Crime d'Amour} containing the @code{'} special
+character:
+@example
+Crime d\'Amour
+@end example
+
+@item
+The string above contains a quote, so the @code{'} needs to be escaped
+when quoting it:
+@example
+'Crime d'\''Amour'
+@end example
+
+@item
+Include leading or trailing whitespaces using quoting:
+@example
+' this string starts and ends with whitespaces '
+@end example
+
+@item
+Escaping and quoting can be mixed together:
+@example
+' The string '\'string\'' is a string '
+@end example
+
+@item
+To include a literal @samp{\} you can use either escaping or quoting:
+@example
+'c:\foo' can be written as c:\\foo
+@end example
+@end itemize
+
+@anchor{date syntax}
+@section Date
+
+The accepted syntax is:
+@example
+[(YYYY-MM-DD|YYYYMMDD)[T|t| ]]((HH:MM:SS[.m...]]])|(HHMMSS[.m...]]]))[Z]
+now
+@end example
+
+If the value is "now" it takes the current time.
+
+Time is local time unless Z is appended, in which case it is
+interpreted as UTC.
+If the year-month-day part is not specified it takes the current
+year-month-day.
+
+@anchor{time duration syntax}
+@section Time duration
+
+There are two accepted syntaxes for expressing time duration.
+
+@example
+[-][@var{HH}:]@var{MM}:@var{SS}[.@var{m}...]
+@end example
+
+@var{HH} expresses the number of hours, @var{MM} the number of minutes
+for a maximum of 2 digits, and @var{SS} the number of seconds for a
+maximum of 2 digits. The @var{m} at the end expresses decimal value for
+@var{SS}.
+
+@emph{or}
+
+@example
+[-]@var{S}+[.@var{m}...]
+@end example
+
+@var{S} expresses the number of seconds, with the optional decimal part
+@var{m}.
+
+In both expressions, the optional @samp{-} indicates negative duration.
+
+@subsection Examples
+
+The following examples are all valid time duration:
+
+@table @samp
+@item 55
+55 seconds
+
+@item 12:03:45
+12 hours, 03 minutes and 45 seconds
+
+@item 23.189
+23.189 seconds
+@end table
+
+@anchor{video size syntax}
+@section Video size
+Specify the size of the sourced video, it may be a string of the form
+@var{width}x@var{height}, or the name of a size abbreviation.
+
+The following abbreviations are recognized:
+@table @samp
+@item ntsc
+720x480
+@item pal
+720x576
+@item qntsc
+352x240
+@item qpal
+352x288
+@item sntsc
+640x480
+@item spal
+768x576
+@item film
+352x240
+@item ntsc-film
+352x240
+@item sqcif
+128x96
+@item qcif
+176x144
+@item cif
+352x288
+@item 4cif
+704x576
+@item 16cif
+1408x1152
+@item qqvga
+160x120
+@item qvga
+320x240
+@item vga
+640x480
+@item svga
+800x600
+@item xga
+1024x768
+@item uxga
+1600x1200
+@item qxga
+2048x1536
+@item sxga
+1280x1024
+@item qsxga
+2560x2048
+@item hsxga
+5120x4096
+@item wvga
+852x480
+@item wxga
+1366x768
+@item wsxga
+1600x1024
+@item wuxga
+1920x1200
+@item woxga
+2560x1600
+@item wqsxga
+3200x2048
+@item wquxga
+3840x2400
+@item whsxga
+6400x4096
+@item whuxga
+7680x4800
+@item cga
+320x200
+@item ega
+640x350
+@item hd480
+852x480
+@item hd720
+1280x720
+@item hd1080
+1920x1080
+@item 2k
+2048x1080
+@item 2kflat
+1998x1080
+@item 2kscope
+2048x858
+@item 4k
+4096x2160
+@item 4kflat
+3996x2160
+@item 4kscope
+4096x1716
+@item nhd
+640x360
+@item hqvga
+240x160
+@item wqvga
+400x240
+@item fwqvga
+432x240
+@item hvga
+480x320
+@item qhd
+960x540
+@end table
+
+@anchor{video rate syntax}
+@section Video rate
+
+Specify the frame rate of a video, expressed as the number of frames
+generated per second. It has to be a string in the format
+@var{frame_rate_num}/@var{frame_rate_den}, an integer number, a float
+number or a valid video frame rate abbreviation.
+
+The following abbreviations are recognized:
+@table @samp
+@item ntsc
+30000/1001
+@item pal
+25/1
+@item qntsc
+30000/1001
+@item qpal
+25/1
+@item sntsc
+30000/1001
+@item spal
+25/1
+@item film
+24/1
+@item ntsc-film
+24000/1001
+@end table
+
+@anchor{ratio syntax}
+@section Ratio
+
+A ratio can be expressed as an expression, or in the form
+@var{numerator}:@var{denominator}.
+
+Note that a ratio with infinite (1/0) or negative value is
+considered valid, so you should check on the returned value if you
+want to exclude those values.
+
+The undefined value can be expressed using the "0:0" string.
+
+@anchor{color syntax}
+@section Color
+
+It can be the name of a color as defined below (case insensitive match) or a
+@code{[0x|#]RRGGBB[AA]} sequence, possibly followed by @@ and a string
+representing the alpha component.
+
+The alpha component may be a string composed by "0x" followed by an
+hexadecimal number or a decimal number between 0.0 and 1.0, which
+represents the opacity value (@samp{0x00} or @samp{0.0} means completely
+transparent, @samp{0xff} or @samp{1.0} completely opaque). If the alpha
+component is not specified then @samp{0xff} is assumed.
+
+The string @samp{random} will result in a random color.
+
+The following names of colors are recognized:
+@table @samp
+@item AliceBlue
+0xF0F8FF
+@item AntiqueWhite
+0xFAEBD7
+@item Aqua
+0x00FFFF
+@item Aquamarine
+0x7FFFD4
+@item Azure
+0xF0FFFF
+@item Beige
+0xF5F5DC
+@item Bisque
+0xFFE4C4
+@item Black
+0x000000
+@item BlanchedAlmond
+0xFFEBCD
+@item Blue
+0x0000FF
+@item BlueViolet
+0x8A2BE2
+@item Brown
+0xA52A2A
+@item BurlyWood
+0xDEB887
+@item CadetBlue
+0x5F9EA0
+@item Chartreuse
+0x7FFF00
+@item Chocolate
+0xD2691E
+@item Coral
+0xFF7F50
+@item CornflowerBlue
+0x6495ED
+@item Cornsilk
+0xFFF8DC
+@item Crimson
+0xDC143C
+@item Cyan
+0x00FFFF
+@item DarkBlue
+0x00008B
+@item DarkCyan
+0x008B8B
+@item DarkGoldenRod
+0xB8860B
+@item DarkGray
+0xA9A9A9
+@item DarkGreen
+0x006400
+@item DarkKhaki
+0xBDB76B
+@item DarkMagenta
+0x8B008B
+@item DarkOliveGreen
+0x556B2F
+@item Darkorange
+0xFF8C00
+@item DarkOrchid
+0x9932CC
+@item DarkRed
+0x8B0000
+@item DarkSalmon
+0xE9967A
+@item DarkSeaGreen
+0x8FBC8F
+@item DarkSlateBlue
+0x483D8B
+@item DarkSlateGray
+0x2F4F4F
+@item DarkTurquoise
+0x00CED1
+@item DarkViolet
+0x9400D3
+@item DeepPink
+0xFF1493
+@item DeepSkyBlue
+0x00BFFF
+@item DimGray
+0x696969
+@item DodgerBlue
+0x1E90FF
+@item FireBrick
+0xB22222
+@item FloralWhite
+0xFFFAF0
+@item ForestGreen
+0x228B22
+@item Fuchsia
+0xFF00FF
+@item Gainsboro
+0xDCDCDC
+@item GhostWhite
+0xF8F8FF
+@item Gold
+0xFFD700
+@item GoldenRod
+0xDAA520
+@item Gray
+0x808080
+@item Green
+0x008000
+@item GreenYellow
+0xADFF2F
+@item HoneyDew
+0xF0FFF0
+@item HotPink
+0xFF69B4
+@item IndianRed
+0xCD5C5C
+@item Indigo
+0x4B0082
+@item Ivory
+0xFFFFF0
+@item Khaki
+0xF0E68C
+@item Lavender
+0xE6E6FA
+@item LavenderBlush
+0xFFF0F5
+@item LawnGreen
+0x7CFC00
+@item LemonChiffon
+0xFFFACD
+@item LightBlue
+0xADD8E6
+@item LightCoral
+0xF08080
+@item LightCyan
+0xE0FFFF
+@item LightGoldenRodYellow
+0xFAFAD2
+@item LightGreen
+0x90EE90
+@item LightGrey
+0xD3D3D3
+@item LightPink
+0xFFB6C1
+@item LightSalmon
+0xFFA07A
+@item LightSeaGreen
+0x20B2AA
+@item LightSkyBlue
+0x87CEFA
+@item LightSlateGray
+0x778899
+@item LightSteelBlue
+0xB0C4DE
+@item LightYellow
+0xFFFFE0
+@item Lime
+0x00FF00
+@item LimeGreen
+0x32CD32
+@item Linen
+0xFAF0E6
+@item Magenta
+0xFF00FF
+@item Maroon
+0x800000
+@item MediumAquaMarine
+0x66CDAA
+@item MediumBlue
+0x0000CD
+@item MediumOrchid
+0xBA55D3
+@item MediumPurple
+0x9370D8
+@item MediumSeaGreen
+0x3CB371
+@item MediumSlateBlue
+0x7B68EE
+@item MediumSpringGreen
+0x00FA9A
+@item MediumTurquoise
+0x48D1CC
+@item MediumVioletRed
+0xC71585
+@item MidnightBlue
+0x191970
+@item MintCream
+0xF5FFFA
+@item MistyRose
+0xFFE4E1
+@item Moccasin
+0xFFE4B5
+@item NavajoWhite
+0xFFDEAD
+@item Navy
+0x000080
+@item OldLace
+0xFDF5E6
+@item Olive
+0x808000
+@item OliveDrab
+0x6B8E23
+@item Orange
+0xFFA500
+@item OrangeRed
+0xFF4500
+@item Orchid
+0xDA70D6
+@item PaleGoldenRod
+0xEEE8AA
+@item PaleGreen
+0x98FB98
+@item PaleTurquoise
+0xAFEEEE
+@item PaleVioletRed
+0xD87093
+@item PapayaWhip
+0xFFEFD5
+@item PeachPuff
+0xFFDAB9
+@item Peru
+0xCD853F
+@item Pink
+0xFFC0CB
+@item Plum
+0xDDA0DD
+@item PowderBlue
+0xB0E0E6
+@item Purple
+0x800080
+@item Red
+0xFF0000
+@item RosyBrown
+0xBC8F8F
+@item RoyalBlue
+0x4169E1
+@item SaddleBrown
+0x8B4513
+@item Salmon
+0xFA8072
+@item SandyBrown
+0xF4A460
+@item SeaGreen
+0x2E8B57
+@item SeaShell
+0xFFF5EE
+@item Sienna
+0xA0522D
+@item Silver
+0xC0C0C0
+@item SkyBlue
+0x87CEEB
+@item SlateBlue
+0x6A5ACD
+@item SlateGray
+0x708090
+@item Snow
+0xFFFAFA
+@item SpringGreen
+0x00FF7F
+@item SteelBlue
+0x4682B4
+@item Tan
+0xD2B48C
+@item Teal
+0x008080
+@item Thistle
+0xD8BFD8
+@item Tomato
+0xFF6347
+@item Turquoise
+0x40E0D0
+@item Violet
+0xEE82EE
+@item Wheat
+0xF5DEB3
+@item White
+0xFFFFFF
+@item WhiteSmoke
+0xF5F5F5
+@item Yellow
+0xFFFF00
+@item YellowGreen
+0x9ACD32
+@end table
+
+@anchor{channel layout syntax}
+@section Channel Layout
+
+A channel layout specifies the spatial disposition of the channels in
+a multi-channel audio stream. To specify a channel layout, FFmpeg
+makes use of a special syntax.
+
+Individual channels are identified by an id, as given by the table
+below:
+@table @samp
+@item FL
+front left
+@item FR
+front right
+@item FC
+front center
+@item LFE
+low frequency
+@item BL
+back left
+@item BR
+back right
+@item FLC
+front left-of-center
+@item FRC
+front right-of-center
+@item BC
+back center
+@item SL
+side left
+@item SR
+side right
+@item TC
+top center
+@item TFL
+top front left
+@item TFC
+top front center
+@item TFR
+top front right
+@item TBL
+top back left
+@item TBC
+top back center
+@item TBR
+top back right
+@item DL
+downmix left
+@item DR
+downmix right
+@item WL
+wide left
+@item WR
+wide right
+@item SDL
+surround direct left
+@item SDR
+surround direct right
+@item LFE2
+low frequency 2
+@end table
+
+Standard channel layout compositions can be specified by using the
+following identifiers:
+@table @samp
+@item mono
+FC
+@item stereo
+FL+FR
+@item 2.1
+FL+FR+LFE
+@item 3.0
+FL+FR+FC
+@item 3.0(back)
+FL+FR+BC
+@item 4.0
+FL+FR+FC+BC
+@item quad
+FL+FR+BL+BR
+@item quad(side)
+FL+FR+SL+SR
+@item 3.1
+FL+FR+FC+LFE
+@item 5.0
+FL+FR+FC+BL+BR
+@item 5.0(side)
+FL+FR+FC+SL+SR
+@item 4.1
+FL+FR+FC+LFE+BC
+@item 5.1
+FL+FR+FC+LFE+BL+BR
+@item 5.1(side)
+FL+FR+FC+LFE+SL+SR
+@item 6.0
+FL+FR+FC+BC+SL+SR
+@item 6.0(front)
+FL+FR+FLC+FRC+SL+SR
+@item hexagonal
+FL+FR+FC+BL+BR+BC
+@item 6.1
+FL+FR+FC+LFE+BC+SL+SR
+@item 6.1
+FL+FR+FC+LFE+BL+BR+BC
+@item 6.1(front)
+FL+FR+LFE+FLC+FRC+SL+SR
+@item 7.0
+FL+FR+FC+BL+BR+SL+SR
+@item 7.0(front)
+FL+FR+FC+FLC+FRC+SL+SR
+@item 7.1
+FL+FR+FC+LFE+BL+BR+SL+SR
+@item 7.1(wide)
+FL+FR+FC+LFE+BL+BR+FLC+FRC
+@item 7.1(wide-side)
+FL+FR+FC+LFE+FLC+FRC+SL+SR
+@item octagonal
+FL+FR+FC+BL+BR+BC+SL+SR
+@item downmix
+DL+DR
+@end table
+
+A custom channel layout can be specified as a sequence of terms, separated by
+'+' or '|'. Each term can be:
+@itemize
+@item
+the name of a standard channel layout (e.g. @samp{mono},
+@samp{stereo}, @samp{4.0}, @samp{quad}, @samp{5.0}, etc.)
+
+@item
+the name of a single channel (e.g. @samp{FL}, @samp{FR}, @samp{FC}, @samp{LFE}, etc.)
+
+@item
+a number of channels, in decimal, optionally followed by 'c', yielding
+the default channel layout for that number of channels (see the
+function @code{av_get_default_channel_layout})
+
+@item
+a channel layout mask, in hexadecimal starting with "0x" (see the
+@code{AV_CH_*} macros in @file{libavutil/channel_layout.h}.
+@end itemize
+
+Starting from libavutil version 53 the trailing character "c" to
+specify a number of channels will be required, while a channel layout
+mask could also be specified as a decimal number (if and only if not
+followed by "c").
+
+See also the function @code{av_get_channel_layout} defined in
+@file{libavutil/channel_layout.h}.
+@c man end SYNTAX
+
+@chapter Expression Evaluation
+@c man begin EXPRESSION EVALUATION
+
+When evaluating an arithmetic expression, FFmpeg uses an internal
+formula evaluator, implemented through the @file{libavutil/eval.h}
+interface.
+
+An expression may contain unary, binary operators, constants, and
+functions.
+
+Two expressions @var{expr1} and @var{expr2} can be combined to form
+another expression "@var{expr1};@var{expr2}".
+@var{expr1} and @var{expr2} are evaluated in turn, and the new
+expression evaluates to the value of @var{expr2}.
+
+The following binary operators are available: @code{+}, @code{-},
+@code{*}, @code{/}, @code{^}.
+
+The following unary operators are available: @code{+}, @code{-}.
+
+The following functions are available:
+@table @option
+@item abs(x)
+Compute absolute value of @var{x}.
+
+@item acos(x)
+Compute arccosine of @var{x}.
+
+@item asin(x)
+Compute arcsine of @var{x}.
+
+@item atan(x)
+Compute arctangent of @var{x}.
+
+@item between(x, min, max)
+Return 1 if @var{x} is greater than or equal to @var{min} and lesser than or
+equal to @var{max}, 0 otherwise.
+
+@item bitand(x, y)
+@item bitor(x, y)
+Compute bitwise and/or operation on @var{x} and @var{y}.
+
+The results of the evaluation of @var{x} and @var{y} are converted to
+integers before executing the bitwise operation.
+
+Note that both the conversion to integer and the conversion back to
+floating point can lose precision. Beware of unexpected results for
+large numbers (usually 2^53 and larger).
+
+@item ceil(expr)
+Round the value of expression @var{expr} upwards to the nearest
+integer. For example, "ceil(1.5)" is "2.0".
+
+@item clip(x, min, max)
+Return the value of @var{x} clipped between @var{min} and @var{max}.
+
+@item cos(x)
+Compute cosine of @var{x}.
+
+@item cosh(x)
+Compute hyperbolic cosine of @var{x}.
+
+@item eq(x, y)
+Return 1 if @var{x} and @var{y} are equivalent, 0 otherwise.
+
+@item exp(x)
+Compute exponential of @var{x} (with base @code{e}, the Euler's number).
+
+@item floor(expr)
+Round the value of expression @var{expr} downwards to the nearest
+integer. For example, "floor(-1.5)" is "-2.0".
+
+@item gauss(x)
+Compute Gauss function of @var{x}, corresponding to
+@code{exp(-x*x/2) / sqrt(2*PI)}.
+
+@item gcd(x, y)
+Return the greatest common divisor of @var{x} and @var{y}. If both @var{x} and
+@var{y} are 0 or either or both are less than zero then behavior is undefined.
+
+@item gt(x, y)
+Return 1 if @var{x} is greater than @var{y}, 0 otherwise.
+
+@item gte(x, y)
+Return 1 if @var{x} is greater than or equal to @var{y}, 0 otherwise.
+
+@item hypot(x, y)
+This function is similar to the C function with the same name; it returns
+"sqrt(@var{x}*@var{x} + @var{y}*@var{y})", the length of the hypotenuse of a
+right triangle with sides of length @var{x} and @var{y}, or the distance of the
+point (@var{x}, @var{y}) from the origin.
+
+@item if(x, y)
+Evaluate @var{x}, and if the result is non-zero return the result of
+the evaluation of @var{y}, return 0 otherwise.
+
+@item if(x, y, z)
+Evaluate @var{x}, and if the result is non-zero return the evaluation
+result of @var{y}, otherwise the evaluation result of @var{z}.
+
+@item ifnot(x, y)
+Evaluate @var{x}, and if the result is zero return the result of the
+evaluation of @var{y}, return 0 otherwise.
+
+@item ifnot(x, y, z)
+Evaluate @var{x}, and if the result is zero return the evaluation
+result of @var{y}, otherwise the evaluation result of @var{z}.
+
+@item isinf(x)
+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}).
+The function returns the loaded value.
+
+@item log(x)
+Compute natural logarithm of @var{x}.
+
+@item lt(x, y)
+Return 1 if @var{x} is lesser than @var{y}, 0 otherwise.
+
+@item lte(x, y)
+Return 1 if @var{x} is lesser than or equal to @var{y}, 0 otherwise.
+
+@item max(x, y)
+Return the maximum between @var{x} and @var{y}.
+
+@item min(x, y)
+Return the maximum between @var{x} and @var{y}.
+
+@item mod(x, y)
+Compute the remainder of division of @var{x} by @var{y}.
+
+@item not(expr)
+Return 1.0 if @var{expr} is zero, 0.0 otherwise.
+
+@item pow(x, y)
+Compute the power of @var{x} elevated @var{y}, it is equivalent to
+"(@var{x})^(@var{y})".
+
+@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
+
+@item random(x)
+Return a pseudo random value between 0.0 and 1.0. @var{x} is the index of the
+internal variable which will be used to save the seed/state.
+
+@item root(expr, max)
+Find an input value for which the function represented by @var{expr}
+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.
+
+@item sin(x)
+Compute sine of @var{x}.
+
+@item sinh(x)
+Compute hyperbolic sine of @var{x}.
+
+@item sqrt(expr)
+Compute the square root of @var{expr}. This is equivalent to
+"(@var{expr})^.5".
+
+@item squish(x)
+Compute expression @code{1/(1 + exp(4*x))}.
+
+@item st(var, 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.
+
+@item tan(x)
+Compute tangent of @var{x}.
+
+@item tanh(x)
+Compute hyperbolic tangent of @var{x}.
+
+@item taylor(expr, x)
+@item taylor(expr, x, id)
+Evaluate a Taylor series at @var{x}, given an expression representing
+the @code{ld(id)}-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},
+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.
+
+Note, when you have the derivatives at y instead of 0,
+@code{taylor(expr, x-y)} can be used.
+
+@item time(0)
+Return the current (wallclock) time in seconds.
+
+@item trunc(expr)
+Round the value of expression @var{expr} towards zero to the nearest
+integer. For example, "trunc(-1.5)" is "-1.0".
+
+@item while(cond, expr)
+Evaluate expression @var{expr} while the expression @var{cond} is
+non-zero, and returns the value of the last @var{expr} evaluation, or
+NAN if @var{cond} was always false.
+@end table
+
+The following constants are available:
+@table @option
+@item PI
+area of the unit disc, approximately 3.14
+@item E
+exp(1) (Euler's number), approximately 2.718
+@item PHI
+golden ratio (1+sqrt(5))/2, approximately 1.618
+@end table
+
+Assuming that an expression is considered "true" if it has a non-zero
+value, note that:
+
+@code{*} works like AND
+
+@code{+} works like OR
+
+For example the construct:
+@example
+if (A AND B) then C
+@end example
+is equivalent to:
+@example
+if(A*B, C)
+@end example
+
+In your C code, you can extend the list of unary and binary functions,
+and define recognized constants, so that they are available for your
+expressions.
+
+The evaluator also recognizes the International System unit prefixes.
+If 'i' is appended after the prefix, binary prefixes are used, which
+are based on powers of 1024 instead of powers of 1000.
+The 'B' postfix multiplies the value by 8, and can be appended after a
+unit prefix or used alone. This allows using for example 'KB', 'MiB',
+'G' and 'B' as number postfix.
+
+The list of available International System prefixes follows, with
+indication of the corresponding powers of 10 and of 2.
+@table @option
+@item y
+10^-24 / 2^-80
+@item z
+10^-21 / 2^-70
+@item a
+10^-18 / 2^-60
+@item f
+10^-15 / 2^-50
+@item p
+10^-12 / 2^-40
+@item n
+10^-9 / 2^-30
+@item u
+10^-6 / 2^-20
+@item m
+10^-3 / 2^-10
+@item c
+10^-2
+@item d
+10^-1
+@item h
+10^2
+@item k
+10^3 / 2^10
+@item K
+10^3 / 2^10
+@item M
+10^6 / 2^20
+@item G
+10^9 / 2^30
+@item T
+10^12 / 2^40
+@item P
+10^15 / 2^40
+@item E
+10^18 / 2^50
+@item Z
+10^21 / 2^60
+@item Y
+10^24 / 2^70
+@end table
+
+@c man end EXPRESSION EVALUATION
+
+@chapter OpenCL Options
+@c man begin OPENCL OPTIONS
+
+When FFmpeg is configured with @code{--enable-opencl}, it is possible
+to set the options for the global OpenCL context.
+
+The list of supported options follows:
+
+@table @option
+@item build_options
+Set build options used to compile the registered kernels.
+
+See reference "OpenCL Specification Version: 1.2 chapter 5.6.4".
+
+@item platform_idx
+Select the index of the platform to run OpenCL code.
+
+The specified index must be one of the indexes in the device list
+which can be obtained with @code{ffmpeg -opencl_bench} or @code{av_opencl_get_device_list()}.
+
+@item device_idx
+Select the index of the device used to run OpenCL code.
+
+The specified index must be one of the indexes in the device list which
+can be obtained with @code{ffmpeg -opencl_bench} or @code{av_opencl_get_device_list()}.
+
+@end table
+
+@c man end OPENCL OPTIONS
diff --git a/doc/viterbi.txt b/doc/viterbi.txt
deleted file mode 100644
index 97825462cc..0000000000
--- a/doc/viterbi.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-This is a quick description of the viterbi aka dynamic programing
-algorthm.
-
-Its reason for existence is that wikipedia has become very poor on
-describing algorithms in a way that makes it useable for understanding
-them or anything else actually. It tends now to describe the very same
-algorithm under 50 different names and pages with few understandable
-by even people who fully understand the algorithm and the theory behind.
-
-Problem description: (that is what it can solve)
-assume we have a 2d table, or you could call it a graph or matrix if you
-prefer
-
- O O O O O O O
-
- O O O O O O O
-
- O O O O O O O
-
- O O O O O O O
-
-
-That table has edges connecting points from each column to the next column
-and each edge has a score like: (only some edge and scores shown to keep it
-readable)
-
-
- O--5--O-----O-----O-----O-----O
- 2 / 7 / \ / \ / \ /
- \ / \ / \ / \ / \ /
- O7-/--O--/--O--/--O--/--O--/--O
- \/ \/ 1/ \/ \/ \/ \/ \/ \/ \/
- /\ /\ 2\ /\ /\ /\ /\ /\ /\ /\
- O3-/--O--/--O--/--O--/--O--/--O
- / \ / \ / \ / \ / \
- 1 \ 9 \ / \ / \ / \
- O--2--O--1--O--5--O--3--O--8--O
-
-
-
-Our goal is to find a path from left to right through it which
-minimizes the sum of the score of all edges.
-(and of course left/right is just a convention here it could be top down too)
-Similarly the minimum could be the maximum by just fliping the sign,
-Example of a path with scores:
-
- O O O O O O O
-
->---O. O O .O-2-O O O
- 5. .7 .
- O O-1-O O O 8 O O
- .
- O O O O O O-1-O---> (sum here is 24)
-
-
-The viterbi algorthm now solves this simply column by column
-For the previous column each point has a best path and a associated
-score:
-
- O-----5 O
- \
- \
- O \ 1 O
- \/
- /\
- O / 2 O
- /
- /
- O-----2 O
-
-
-To move one column forward we just need to find the best path and associated
-scores for the next column
-here are some edges we could choose from:
-
-
- O-----5--3--O
- \ \8
- \ \
- O \ 1--9--O
- \/ \3
- /\ \
- O / 2--1--O
- / \2
- / \
- O-----2--4--O
-
-Finding the new best paths and scores for each point of our new column is
-trivial given we know the previous column best paths and scores:
-
- O-----0-----8
- \
- \
- O \ 0----10
- \/
- /\
- O / 0-----3
- / \
- / \
- O 0 4
-
-
-the viterbi algorthm continues exactly like this column for column until the
-end and then just picks the path with the best score (above that would be the
-one with score 3)
-
-
-Author: Michael niedermayer
-Copyright LGPL
diff --git a/doc/writing_filters.txt b/doc/writing_filters.txt
new file mode 100644
index 0000000000..eb16d42480
--- /dev/null
+++ b/doc/writing_filters.txt
@@ -0,0 +1,423 @@
+This document is a tutorial/initiation for writing simple filters in
+libavfilter.
+
+Foreword: just like everything else in FFmpeg, libavfilter is monolithic, which
+means that it is highly recommended that you submit your filters to the FFmpeg
+development mailing-list and make sure it is applied. Otherwise, your filter is
+likely to have a very short lifetime due to more a less regular internal API
+changes, and a limited distribution, review, and testing.
+
+Bootstrap
+=========
+
+Let's say you want to write a new simple video filter called "foobar" which
+takes one frame in input, changes the pixels in whatever fashion you fancy, and
+outputs the modified frame. The most simple way of doing this is to take a
+similar filter. We'll pick edgedetect, but any other should do. You can look
+for others using the `./ffmpeg -v 0 -filters|grep ' V->V '` command.
+
+ - sed 's/edgedetect/foobar/g;s/EdgeDetect/Foobar/g' libavfilter/vf_edgedetect.c > libavfilter/vf_foobar.c
+ - edit libavfilter/Makefile, and add an entry for "foobar" following the
+ pattern of the other filters.
+ - edit libavfilter/allfilters.c, and add an entry for "foobar" following the
+ pattern of the other filters.
+ - ./configure ...
+ - make -j<whatever> ffmpeg
+ - ./ffmpeg -i http://samples.ffmpeg.org/image-samples/lena.pnm -vf foobar foobar.png
+ Note here: you can obviously use a random local image instead of a remote URL.
+
+If everything went right, you should get a foobar.png with Lena edge-detected.
+
+That's it, your new playground is ready.
+
+Some little details about what's going on:
+libavfilter/allfilters.c:avfilter_register_all() is called at runtime to create
+a list of the available filters, but it's important to know that this file is
+also parsed by the configure script, which in turn will define variables for
+the build system and the C:
+
+ --- after running configure ---
+
+ $ grep FOOBAR config.mak
+ CONFIG_FOOBAR_FILTER=yes
+ $ grep FOOBAR config.h
+ #define CONFIG_FOOBAR_FILTER 1
+
+CONFIG_FOOBAR_FILTER=yes from the config.mak is later used to enable the filter in
+libavfilter/Makefile and CONFIG_FOOBAR_FILTER=1 from the config.h will be used
+for registering the filter in libavfilter/allfilters.c.
+
+Filter code layout
+==================
+
+You now need some theory about the general code layout of a filter. Open your
+libavfilter/vf_foobar.c. This section will detail the important parts of the
+code you need to understand before messing with it.
+
+Copyright
+---------
+
+First chunk is the copyright. Most filters are LGPL, and we are assuming
+vf_foobar is as well. We are also assuming vf_foobar is not an edge detector
+filter, so you can update the boilerplate with your credits.
+
+Doxy
+----
+
+Next chunk is the Doxygen about the file. See http://ffmpeg.org/doxygen/trunk/.
+Detail here what the filter is, does, and add some references if you feel like
+it.
+
+Context
+-------
+
+Skip the headers and scroll down to the definition of FoobarContext. This is
+your local state context. It is already filled with 0 when you get it so do not
+worry about uninitialized read into this context. This is where you put every
+"global" information you need, typically the variable storing the user options.
+You'll notice the first field "const AVClass *class"; it's the only field you
+need to keep assuming you have a context. There are some magic you don't care
+about around this field, just let it be (in first position) for now.
+
+Options
+-------
+
+Then comes the options array. This is what will define the user accessible
+options. For example, -vf foobar=mode=colormix:high=0.4:low=0.1. Most options
+have the following pattern:
+ name, description, offset, type, default value, minimum value, maximum value, flags
+
+ - name is the option name, keep it simple, lowercase
+ - description are short, in lowercase, without period, and describe what they
+ do, for example "set the foo of the bar"
+ - offset is the offset of the field in your local context, see the OFFSET()
+ macro; the option parser will use that information to fill the fields
+ according to the user input
+ - type is any of AV_OPT_TYPE_* defined in libavutil/opt.h
+ - default value is an union where you pick the appropriate type; "{.dbl=0.3}",
+ "{.i64=0x234}", "{.str=NULL}", ...
+ - min and max values define the range of available values, inclusive
+ - flags are AVOption generic flags. See AV_OPT_FLAG_* definitions
+
+In doubt, just look at the other AVOption definitions all around the codebase,
+there are tons of examples.
+
+Class
+-----
+
+AVFILTER_DEFINE_CLASS(foobar) will define a unique foobar_class with some kind
+of signature referencing the options, etc. which will be referenced in the
+definition of the AVFilter.
+
+Filter definition
+-----------------
+
+At the end of the file, you will find foobar_inputs, foobar_outputs and
+the AVFilter ff_vf_foobar. Don't forget to update the AVFilter.description with
+a description of what the filter does, starting with a capitalized letter and
+ending with a period. You'd better drop the AVFilter.flags entry for now, and
+re-add them later depending on the capabilities of your filter.
+
+Callbacks
+---------
+
+Let's now study the common callbacks. Before going into details, note that all
+these callbacks are explained in details in libavfilter/avfilter.h, so in
+doubt, refer to the doxy in that file.
+
+init()
+~~~~~~
+
+First one to be called is init(). It's flagged as cold because not called
+often. Look for "cold" on
+http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html for more
+information.
+
+As the name suggests, init() is where you eventually initialize and allocate
+your buffers, pre-compute your data, etc. Note that at this point, your local
+context already has the user options initialized, but you still haven't any
+clue about the kind of data input you will get, so this function is often
+mainly used to sanitize the user options.
+
+Some init()s will also define the number of inputs or outputs dynamically
+according to the user options. A good example of this is the split filter, but
+we won't cover this here since vf_foobar is just a simple 1:1 filter.
+
+uninit()
+~~~~~~~~
+
+Similarly, there is the uninit() callback, doing what the name suggest. Free
+everything you allocated here.
+
+query_formats()
+~~~~~~~~~~~~~~~
+
+This is following the init() and is used for the format negotiation, basically
+where you say what pixel format(s) (gray, rgb 32, yuv 4:2:0, ...) you accept
+for your inputs, and what you can output. All pixel formats are defined in
+libavutil/pixfmt.h. If you don't change the pixel format between the input and
+the output, you just have to define a pixel formats array and call
+ff_set_common_formats(). For more complex negotiation, you can refer to other
+filters such as vf_scale.
+
+config_props()
+~~~~~~~~~~~~~~
+
+This callback is not necessary, but you will probably have one or more
+config_props() anyway. It's not a callback for the filter itself but for its
+inputs or outputs (they're called "pads" - AVFilterPad - in libavfilter's
+lexicon).
+
+Inside the input config_props(), you are at a point where you know which pixel
+format has been picked after query_formats(), and more information such as the
+video width and height (inlink->{w,h}). So if you need to update your internal
+context state depending on your input you can do it here. In edgedetect you can
+see that this callback is used to allocate buffers depending on these
+information. They will be destroyed in uninit().
+
+Inside the output config_props(), you can define what you want to change in the
+output. Typically, if your filter is going to double the size of the video, you
+will update outlink->w and outlink->h.
+
+filter_frame()
+~~~~~~~~~~~~~~
+
+This is the callback you are waiting from the beginning: it is where you
+process the received frames. Along with the frame, you get the input link from
+where the frame comes from.
+
+ static int filter_frame(AVFilterLink *inlink, AVFrame *in) { ... }
+
+You can get the filter context through that input link:
+
+ AVFilterContext *ctx = inlink->dst;
+
+Then access your internal state context:
+
+ FoobarContext *foobar = ctx->priv;
+
+And also the output link where you will send your frame when you are done:
+
+ AVFilterLink *outlink = ctx->outputs[0];
+
+Here, we are picking the first output. You can have several, but in our case we
+only have one since we are in a 1:1 input-output situation.
+
+If you want to define a simple pass-through filter, you can just do:
+
+ return ff_filter_frame(outlink, in);
+
+But of course, you probably want to change the data of that frame.
+
+This can be done by accessing frame->data[] and frame->linesize[]. Important
+note here: the width does NOT match the linesize. The linesize is always
+greater or equal to the width. The padding created should not be changed or
+even read. Typically, keep in mind that a previous filter in your chain might
+have altered the frame dimension but not the linesize. Imagine a crop filter
+that halves the video size: the linesizes won't be changed, just the width.
+
+ <-------------- linesize ------------------------>
+ +-------------------------------+----------------+ ^
+ | | | |
+ | | | |
+ | picture | padding | | height
+ | | | |
+ | | | |
+ +-------------------------------+----------------+ v
+ <----------- width ------------->
+
+Before modifying the "in" frame, you have to make sure it is writable, or get a
+new one. Multiple scenarios are possible here depending on the kind of
+processing you are doing.
+
+Let's say you want to change one pixel depending on multiple pixels (typically
+the surrounding ones) of the input. In that case, you can't do an in-place
+processing of the input so you will need to allocate a new frame, with the same
+properties as the input one, and send that new frame to the next filter:
+
+ AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ // out->data[...] = foobar(in->data[...])
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+
+In-place processing
+~~~~~~~~~~~~~~~~~~~
+
+If you can just alter the input frame, you probably just want to do that
+instead:
+
+ av_frame_make_writable(in);
+ // in->data[...] = foobar(in->data[...])
+ return ff_filter_frame(outlink, in);
+
+You may wonder why a frame might not be writable. The answer is that for
+example a previous filter might still own the frame data: imagine a filter
+prior to yours in the filtergraph that needs to cache the frame. You must not
+alter that frame, otherwise it will make that previous filter buggy. This is
+where av_frame_make_writable() helps (it won't have any effect if the frame
+already is writable).
+
+The problem with using av_frame_make_writable() is that in the worst case it
+will copy the whole input frame before you change it all over again with your
+filter: if the frame is not writable, av_frame_make_writable() will allocate
+new buffers, and copy the input frame data. You don't want that, and you can
+avoid it by just allocating a new buffer if necessary, and process from in to
+out in your filter, saving the memcpy. Generally, this is done following this
+scheme:
+
+ int direct = 0;
+ AVFrame *out;
+
+ if (av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ // out->data[...] = foobar(in->data[...])
+
+ if (!direct)
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+
+Of course, this will only work if you can do in-place processing. To test if
+your filter handles well the permissions, you can use the perms filter. For
+example with:
+
+ -vf perms=random,foobar
+
+Make sure no automatic pixel conversion is inserted between perms and foobar,
+otherwise the frames permissions might change again and the test will be
+meaningless: add av_log(0,0,"direct=%d\n",direct) in your code to check that.
+You can avoid the issue with something like:
+
+ -vf format=rgb24,perms=random,foobar
+
+...assuming your filter accepts rgb24 of course. This will make sure the
+necessary conversion is inserted before the perms filter.
+
+Timeline
+~~~~~~~~
+
+Adding timeline support
+(http://ffmpeg.org/ffmpeg-filters.html#Timeline-editing) is often an easy
+feature to add. In the most simple case, you just have to add
+AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC to the AVFilter.flags. You can typically
+do this when your filter does not need to save the previous context frames, or
+basically if your filter just alter whatever goes in and doesn't need
+previous/future information. See for instance commit 86cb986ce that adds
+timeline support to the fieldorder filter.
+
+In some cases, you might need to reset your context somehow. This is handled by
+the AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL flag which is used if the filter
+must not process the frames but still wants to keep track of the frames going
+through (to keep them in cache for when it's enabled again). See for example
+commit 69d72140a that adds timeline support to the phase filter.
+
+Threading
+~~~~~~~~~
+
+libavfilter does not yet support frame threading, but you can add slice
+threading to your filters.
+
+Let's say the foobar filter has the following frame processing function:
+
+ dst = out->data[0];
+ src = in ->data[0];
+
+ for (y = 0; y < inlink->h; y++) {
+ for (x = 0; x < inlink->w; x++)
+ dst[x] = foobar(src[x]);
+ dst += out->linesize[0];
+ src += in ->linesize[0];
+ }
+
+The first thing is to make this function work into slices. The new code will
+look like this:
+
+ for (y = slice_start; y < slice_end; y++) {
+ for (x = 0; x < inlink->w; x++)
+ dst[x] = foobar(src[x]);
+ dst += out->linesize[0];
+ src += in ->linesize[0];
+ }
+
+The source and destination pointers, and slice_start/slice_end will be defined
+according to the number of jobs. Generally, it looks like this:
+
+ const int slice_start = (in->height * jobnr ) / nb_jobs;
+ const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
+ uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
+ const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
+
+This new code will be isolated in a new filter_slice():
+
+ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ... }
+
+Note that we need our input and output frame to define slice_{start,end} and
+dst/src, which are not available in that callback. They will be transmitted
+through the opaque void *arg. You have to define a structure which contains
+everything you need:
+
+ typedef struct ThreadData {
+ AVFrame *in, *out;
+ } ThreadData;
+
+If you need some more information from your local context, put them here.
+
+In you filter_slice function, you access it like that:
+
+ const ThreadData *td = arg;
+
+Then in your filter_frame() callback, you need to call the threading
+distributor with something like this:
+
+ ThreadData td;
+
+ // ...
+
+ td.in = in;
+ td.out = out;
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
+
+ // ...
+
+ return ff_filter_frame(outlink, out);
+
+Last step is to add AVFILTER_FLAG_SLICE_THREADS flag to AVFilter.flags.
+
+For more example of slice threading additions, you can try to run git log -p
+--grep 'slice threading' libavfilter/
+
+Finalization
+~~~~~~~~~~~~
+
+When your awesome filter is finished, you have a few more steps before you're
+done:
+
+ - write its documentation in doc/filters.texi, and test the output with make
+ doc/ffmpeg-filters.html.
+ - add a FATE test, generally by adding an entry in
+ tests/fate/filter-video.mak, add running make fate-filter-foobar GEN=1 to
+ generate the data.
+ - add an entry in the Changelog
+ - edit libavfilter/version.h and increase LIBAVFILTER_VERSION_MINOR by one
+ (and reset LIBAVFILTER_VERSION_MICRO to 100)
+ - git add ... && git commit -m "avfilter: add foobar filter." && git format-patch -1
+
+When all of this is done, you can submit your patch to the ffmpeg-devel
+mailing-list for review. If you need any help, feel free to come on our IRC
+channel, #ffmpeg-devel on irc.freenode.net.
diff --git a/ffmpeg.c b/ffmpeg.c
new file mode 100644
index 0000000000..da3ab911f1
--- /dev/null
+++ b/ffmpeg.c
@@ -0,0 +1,4095 @@
+/*
+ * Copyright (c) 2000-2003 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * multimedia converter based on the FFmpeg libraries
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+
+#if HAVE_ISATTY
+#if HAVE_IO_H
+#include <io.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#endif
+
+#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
+#include "libswresample/swresample.h"
+#include "libavutil/opt.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/samplefmt.h"
+#include "libavutil/fifo.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/dict.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/avstring.h"
+#include "libavutil/libm.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/timestamp.h"
+#include "libavutil/bprint.h"
+#include "libavutil/time.h"
+#include "libavutil/threadmessage.h"
+#include "libavcodec/mathops.h"
+#include "libavformat/os_support.h"
+
+# include "libavfilter/avcodec.h"
+# include "libavfilter/avfilter.h"
+# include "libavfilter/buffersrc.h"
+# include "libavfilter/buffersink.h"
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#elif HAVE_GETPROCESSTIMES
+#include <windows.h>
+#endif
+#if HAVE_GETPROCESSMEMORYINFO
+#include <windows.h>
+#include <psapi.h>
+#endif
+
+#if HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if HAVE_TERMIOS_H
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <termios.h>
+#elif HAVE_KBHIT
+#include <conio.h>
+#endif
+
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include <time.h>
+
+#include "ffmpeg.h"
+#include "cmdutils.h"
+
+#include "libavutil/avassert.h"
+
+const char program_name[] = "ffmpeg";
+const int program_birth_year = 2000;
+
+static FILE *vstats_file;
+
+const char *const forced_keyframes_const_names[] = {
+ "n",
+ "n_forced",
+ "prev_forced_n",
+ "prev_forced_t",
+ "t",
+ NULL
+};
+
+static void do_video_stats(OutputStream *ost, int frame_size);
+static int64_t getutime(void);
+static int64_t getmaxrss(void);
+
+static int run_as_daemon = 0;
+static int nb_frames_dup = 0;
+static int nb_frames_drop = 0;
+static int64_t decode_error_stat[2];
+
+static int current_time;
+AVIOContext *progress_avio = NULL;
+
+static uint8_t *subtitle_out;
+
+#define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
+
+InputStream **input_streams = NULL;
+int nb_input_streams = 0;
+InputFile **input_files = NULL;
+int nb_input_files = 0;
+
+OutputStream **output_streams = NULL;
+int nb_output_streams = 0;
+OutputFile **output_files = NULL;
+int nb_output_files = 0;
+
+FilterGraph **filtergraphs;
+int nb_filtergraphs;
+
+#if HAVE_TERMIOS_H
+
+/* init terminal so that we can grab keys */
+static struct termios oldtty;
+static int restore_tty;
+#endif
+
+#if HAVE_PTHREADS
+static void free_input_threads(void);
+#endif
+
+/* sub2video hack:
+ Convert subtitles to video with alpha to insert them in filter graphs.
+ This is a temporary solution until libavfilter gets real subtitles support.
+ */
+
+static int sub2video_get_blank_frame(InputStream *ist)
+{
+ int ret;
+ AVFrame *frame = ist->sub2video.frame;
+
+ av_frame_unref(frame);
+ ist->sub2video.frame->width = ist->sub2video.w;
+ ist->sub2video.frame->height = ist->sub2video.h;
+ ist->sub2video.frame->format = AV_PIX_FMT_RGB32;
+ if ((ret = av_frame_get_buffer(frame, 32)) < 0)
+ return ret;
+ memset(frame->data[0], 0, frame->height * frame->linesize[0]);
+ return 0;
+}
+
+static void sub2video_copy_rect(uint8_t *dst, int dst_linesize, int w, int h,
+ AVSubtitleRect *r)
+{
+ uint32_t *pal, *dst2;
+ uint8_t *src, *src2;
+ int x, y;
+
+ if (r->type != SUBTITLE_BITMAP) {
+ av_log(NULL, AV_LOG_WARNING, "sub2video: non-bitmap subtitle\n");
+ return;
+ }
+ if (r->x < 0 || r->x + r->w > w || r->y < 0 || r->y + r->h > h) {
+ av_log(NULL, AV_LOG_WARNING, "sub2video: rectangle overflowing\n");
+ return;
+ }
+
+ dst += r->y * dst_linesize + r->x * 4;
+ src = r->pict.data[0];
+ pal = (uint32_t *)r->pict.data[1];
+ for (y = 0; y < r->h; y++) {
+ dst2 = (uint32_t *)dst;
+ src2 = src;
+ for (x = 0; x < r->w; x++)
+ *(dst2++) = pal[*(src2++)];
+ dst += dst_linesize;
+ src += r->pict.linesize[0];
+ }
+}
+
+static void sub2video_push_ref(InputStream *ist, int64_t pts)
+{
+ AVFrame *frame = ist->sub2video.frame;
+ int i;
+
+ av_assert1(frame->data[0]);
+ ist->sub2video.last_pts = frame->pts = pts;
+ for (i = 0; i < ist->nb_filters; i++)
+ av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame,
+ AV_BUFFERSRC_FLAG_KEEP_REF |
+ AV_BUFFERSRC_FLAG_PUSH);
+}
+
+static void sub2video_update(InputStream *ist, AVSubtitle *sub)
+{
+ int w = ist->sub2video.w, h = ist->sub2video.h;
+ AVFrame *frame = ist->sub2video.frame;
+ int8_t *dst;
+ int dst_linesize;
+ int num_rects, i;
+ int64_t pts, end_pts;
+
+ if (!frame)
+ return;
+ if (sub) {
+ pts = av_rescale_q(sub->pts + sub->start_display_time * 1000LL,
+ AV_TIME_BASE_Q, ist->st->time_base);
+ end_pts = av_rescale_q(sub->pts + sub->end_display_time * 1000LL,
+ AV_TIME_BASE_Q, ist->st->time_base);
+ num_rects = sub->num_rects;
+ } else {
+ pts = ist->sub2video.end_pts;
+ end_pts = INT64_MAX;
+ num_rects = 0;
+ }
+ if (sub2video_get_blank_frame(ist) < 0) {
+ av_log(ist->dec_ctx, AV_LOG_ERROR,
+ "Impossible to get a blank canvas.\n");
+ return;
+ }
+ dst = frame->data [0];
+ dst_linesize = frame->linesize[0];
+ for (i = 0; i < num_rects; i++)
+ sub2video_copy_rect(dst, dst_linesize, w, h, sub->rects[i]);
+ sub2video_push_ref(ist, pts);
+ ist->sub2video.end_pts = end_pts;
+}
+
+static void sub2video_heartbeat(InputStream *ist, int64_t pts)
+{
+ InputFile *infile = input_files[ist->file_index];
+ int i, j, nb_reqs;
+ int64_t pts2;
+
+ /* When a frame is read from a file, examine all sub2video streams in
+ the same file and send the sub2video frame again. Otherwise, decoded
+ video frames could be accumulating in the filter graph while a filter
+ (possibly overlay) is desperately waiting for a subtitle frame. */
+ for (i = 0; i < infile->nb_streams; i++) {
+ InputStream *ist2 = input_streams[infile->ist_index + i];
+ if (!ist2->sub2video.frame)
+ continue;
+ /* subtitles seem to be usually muxed ahead of other streams;
+ if not, subtracting a larger time here is necessary */
+ pts2 = av_rescale_q(pts, ist->st->time_base, ist2->st->time_base) - 1;
+ /* do not send the heartbeat frame if the subtitle is already ahead */
+ if (pts2 <= ist2->sub2video.last_pts)
+ continue;
+ if (pts2 >= ist2->sub2video.end_pts || !ist2->sub2video.frame->data[0])
+ sub2video_update(ist2, NULL);
+ for (j = 0, nb_reqs = 0; j < ist2->nb_filters; j++)
+ nb_reqs += av_buffersrc_get_nb_failed_requests(ist2->filters[j]->filter);
+ if (nb_reqs)
+ sub2video_push_ref(ist2, pts2);
+ }
+}
+
+static void sub2video_flush(InputStream *ist)
+{
+ int i;
+
+ if (ist->sub2video.end_pts < INT64_MAX)
+ sub2video_update(ist, NULL);
+ for (i = 0; i < ist->nb_filters; i++)
+ av_buffersrc_add_ref(ist->filters[i]->filter, NULL, 0);
+}
+
+/* end of sub2video hack */
+
+static void term_exit_sigsafe(void)
+{
+#if HAVE_TERMIOS_H
+ if(restore_tty)
+ tcsetattr (0, TCSANOW, &oldtty);
+#endif
+}
+
+void term_exit(void)
+{
+ av_log(NULL, AV_LOG_QUIET, "%s", "");
+ term_exit_sigsafe();
+}
+
+static volatile int received_sigterm = 0;
+static volatile int received_nb_signals = 0;
+static volatile int transcode_init_done = 0;
+static int main_return_code = 0;
+
+static void
+sigterm_handler(int sig)
+{
+ received_sigterm = sig;
+ received_nb_signals++;
+ term_exit_sigsafe();
+ if(received_nb_signals > 3)
+ exit(123);
+}
+
+void term_init(void)
+{
+#if HAVE_TERMIOS_H
+ if(!run_as_daemon){
+ struct termios tty;
+ int istty = 1;
+#if HAVE_ISATTY
+ istty = isatty(0) && isatty(2);
+#endif
+ if (istty && tcgetattr (0, &tty) == 0) {
+ oldtty = tty;
+ restore_tty = 1;
+
+ tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+ |INLCR|IGNCR|ICRNL|IXON);
+ tty.c_oflag |= OPOST;
+ tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
+ tty.c_cflag &= ~(CSIZE|PARENB);
+ tty.c_cflag |= CS8;
+ tty.c_cc[VMIN] = 1;
+ tty.c_cc[VTIME] = 0;
+
+ tcsetattr (0, TCSANOW, &tty);
+ }
+ signal(SIGQUIT, sigterm_handler); /* Quit (POSIX). */
+ }
+#endif
+
+ signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
+ signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
+#ifdef SIGXCPU
+ signal(SIGXCPU, sigterm_handler);
+#endif
+}
+
+/* read a key without blocking */
+static int read_key(void)
+{
+ unsigned char ch;
+#if HAVE_TERMIOS_H
+ int n = 1;
+ struct timeval tv;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+ FD_SET(0, &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ n = select(1, &rfds, NULL, NULL, &tv);
+ if (n > 0) {
+ n = read(0, &ch, 1);
+ if (n == 1)
+ return ch;
+
+ return n;
+ }
+#elif HAVE_KBHIT
+# if HAVE_PEEKNAMEDPIPE
+ static int is_pipe;
+ static HANDLE input_handle;
+ DWORD dw, nchars;
+ if(!input_handle){
+ input_handle = GetStdHandle(STD_INPUT_HANDLE);
+ is_pipe = !GetConsoleMode(input_handle, &dw);
+ }
+
+ if (stdin->_cnt > 0) {
+ read(0, &ch, 1);
+ return ch;
+ }
+ if (is_pipe) {
+ /* When running under a GUI, you will end here. */
+ if (!PeekNamedPipe(input_handle, NULL, 0, NULL, &nchars, NULL)) {
+ // input pipe may have been closed by the program that ran ffmpeg
+ return -1;
+ }
+ //Read it
+ if(nchars != 0) {
+ read(0, &ch, 1);
+ return ch;
+ }else{
+ return -1;
+ }
+ }
+# endif
+ if(kbhit())
+ return(getch());
+#endif
+ return -1;
+}
+
+static int decode_interrupt_cb(void *ctx)
+{
+ return received_nb_signals > transcode_init_done;
+}
+
+const AVIOInterruptCB int_cb = { decode_interrupt_cb, NULL };
+
+static void ffmpeg_cleanup(int ret)
+{
+ int i, j;
+
+ if (do_benchmark) {
+ int maxrss = getmaxrss() / 1024;
+ printf("bench: maxrss=%ikB\n", maxrss);
+ }
+
+ for (i = 0; i < nb_filtergraphs; i++) {
+ FilterGraph *fg = filtergraphs[i];
+ avfilter_graph_free(&fg->graph);
+ for (j = 0; j < fg->nb_inputs; j++) {
+ av_freep(&fg->inputs[j]->name);
+ av_freep(&fg->inputs[j]);
+ }
+ av_freep(&fg->inputs);
+ for (j = 0; j < fg->nb_outputs; j++) {
+ av_freep(&fg->outputs[j]->name);
+ av_freep(&fg->outputs[j]);
+ }
+ av_freep(&fg->outputs);
+ av_freep(&fg->graph_desc);
+
+ av_freep(&filtergraphs[i]);
+ }
+ av_freep(&filtergraphs);
+
+ av_freep(&subtitle_out);
+
+ /* close files */
+ for (i = 0; i < nb_output_files; i++) {
+ OutputFile *of = output_files[i];
+ AVFormatContext *s = of->ctx;
+ if (s && s->oformat && !(s->oformat->flags & AVFMT_NOFILE))
+ avio_closep(&s->pb);
+ avformat_free_context(s);
+ av_dict_free(&of->opts);
+
+ av_freep(&output_files[i]);
+ }
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
+ while (bsfc) {
+ AVBitStreamFilterContext *next = bsfc->next;
+ av_bitstream_filter_close(bsfc);
+ bsfc = next;
+ }
+ ost->bitstream_filters = NULL;
+ av_frame_free(&ost->filtered_frame);
+ av_frame_free(&ost->last_frame);
+
+ av_parser_close(ost->parser);
+
+ av_freep(&ost->forced_keyframes);
+ av_expr_free(ost->forced_keyframes_pexpr);
+ av_freep(&ost->avfilter);
+ av_freep(&ost->logfile_prefix);
+
+ av_freep(&ost->audio_channels_map);
+ ost->audio_channels_mapped = 0;
+
+ avcodec_free_context(&ost->enc_ctx);
+
+ av_freep(&output_streams[i]);
+ }
+#if HAVE_PTHREADS
+ free_input_threads();
+#endif
+ for (i = 0; i < nb_input_files; i++) {
+ avformat_close_input(&input_files[i]->ctx);
+ av_freep(&input_files[i]);
+ }
+ for (i = 0; i < nb_input_streams; i++) {
+ InputStream *ist = input_streams[i];
+
+ av_frame_free(&ist->decoded_frame);
+ av_frame_free(&ist->filter_frame);
+ av_dict_free(&ist->decoder_opts);
+ avsubtitle_free(&ist->prev_sub.subtitle);
+ av_frame_free(&ist->sub2video.frame);
+ av_freep(&ist->filters);
+ av_freep(&ist->hwaccel_device);
+
+ avcodec_free_context(&ist->dec_ctx);
+
+ av_freep(&input_streams[i]);
+ }
+
+ if (vstats_file)
+ fclose(vstats_file);
+ av_freep(&vstats_filename);
+
+ av_freep(&input_streams);
+ av_freep(&input_files);
+ av_freep(&output_streams);
+ av_freep(&output_files);
+
+ uninit_opts();
+
+ avformat_network_deinit();
+
+ if (received_sigterm) {
+ av_log(NULL, AV_LOG_INFO, "Received signal %d: terminating.\n",
+ (int) received_sigterm);
+ } else if (ret && transcode_init_done) {
+ av_log(NULL, AV_LOG_INFO, "Conversion failed!\n");
+ }
+ term_exit();
+}
+
+void remove_avoptions(AVDictionary **a, AVDictionary *b)
+{
+ AVDictionaryEntry *t = NULL;
+
+ while ((t = av_dict_get(b, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ av_dict_set(a, t->key, NULL, AV_DICT_MATCH_CASE);
+ }
+}
+
+void assert_avoptions(AVDictionary *m)
+{
+ 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);
+ exit_program(1);
+ }
+}
+
+static void abort_codec_experimental(AVCodec *c, int encoder)
+{
+ exit_program(1);
+}
+
+static void update_benchmark(const char *fmt, ...)
+{
+ if (do_benchmark_all) {
+ int64_t t = getutime();
+ va_list va;
+ char buf[1024];
+
+ if (fmt) {
+ va_start(va, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, va);
+ va_end(va);
+ printf("bench: %8"PRIu64" %s \n", t - current_time, buf);
+ }
+ current_time = t;
+ }
+}
+
+static void close_all_output_streams(OutputStream *ost, OSTFinished this_stream, OSTFinished others)
+{
+ int i;
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost2 = output_streams[i];
+ ost2->finished |= ost == ost2 ? this_stream : others;
+ }
+}
+
+static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
+{
+ AVBitStreamFilterContext *bsfc = ost->bitstream_filters;
+ AVCodecContext *avctx = ost->encoding_needed ? ost->enc_ctx : ost->st->codec;
+ int ret;
+
+ if (!ost->st->codec->extradata_size && ost->enc_ctx->extradata_size) {
+ ost->st->codec->extradata = av_mallocz(ost->enc_ctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (ost->st->codec->extradata) {
+ memcpy(ost->st->codec->extradata, ost->enc_ctx->extradata, ost->enc_ctx->extradata_size);
+ ost->st->codec->extradata_size = ost->enc_ctx->extradata_size;
+ }
+ }
+
+ if ((avctx->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
+ (avctx->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
+ pkt->pts = pkt->dts = AV_NOPTS_VALUE;
+
+ /*
+ * Audio encoders may split the packets -- #frames in != #packets out.
+ * But there is no reordering, so we can limit the number of output packets
+ * by simply dropping them here.
+ * Counting encoded video frames needs to be done separately because of
+ * reordering, see do_video_out()
+ */
+ if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
+ if (ost->frame_number >= ost->max_frames) {
+ av_free_packet(pkt);
+ return;
+ }
+ ost->frame_number++;
+ }
+
+ if (bsfc)
+ av_packet_split_side_data(pkt);
+
+ while (bsfc) {
+ AVPacket new_pkt = *pkt;
+ AVDictionaryEntry *bsf_arg = av_dict_get(ost->bsf_args,
+ bsfc->filter->name,
+ NULL, 0);
+ int a = av_bitstream_filter_filter(bsfc, avctx,
+ bsf_arg ? bsf_arg->value : NULL,
+ &new_pkt.data, &new_pkt.size,
+ pkt->data, pkt->size,
+ pkt->flags & AV_PKT_FLAG_KEY);
+ if(a == 0 && new_pkt.data != pkt->data && new_pkt.destruct) {
+ uint8_t *t = av_malloc(new_pkt.size + FF_INPUT_BUFFER_PADDING_SIZE); //the new should be a subset of the old so cannot overflow
+ if(t) {
+ memcpy(t, new_pkt.data, new_pkt.size);
+ memset(t + new_pkt.size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ new_pkt.data = t;
+ new_pkt.buf = NULL;
+ a = 1;
+ } else
+ a = AVERROR(ENOMEM);
+ }
+ if (a > 0) {
+ pkt->side_data = NULL;
+ pkt->side_data_elems = 0;
+ av_free_packet(pkt);
+ new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
+ av_buffer_default_free, NULL, 0);
+ if (!new_pkt.buf)
+ exit_program(1);
+ } else if (a < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s",
+ bsfc->filter->name, pkt->stream_index,
+ avctx->codec ? avctx->codec->name : "copy");
+ print_error("", a);
+ if (exit_on_error)
+ exit_program(1);
+ }
+ *pkt = new_pkt;
+
+ bsfc = bsfc->next;
+ }
+
+ if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
+ if (pkt->dts != AV_NOPTS_VALUE &&
+ pkt->pts != AV_NOPTS_VALUE &&
+ pkt->dts > pkt->pts) {
+ av_log(s, AV_LOG_WARNING, "Invalid DTS: %"PRId64" PTS: %"PRId64" in output stream %d:%d, replacing by guess\n",
+ pkt->dts, pkt->pts,
+ ost->file_index, ost->st->index);
+ pkt->pts =
+ pkt->dts = pkt->pts + pkt->dts + ost->last_mux_dts + 1
+ - FFMIN3(pkt->pts, pkt->dts, ost->last_mux_dts + 1)
+ - FFMAX3(pkt->pts, pkt->dts, ost->last_mux_dts + 1);
+ }
+ if(
+ (avctx->codec_type == AVMEDIA_TYPE_AUDIO || avctx->codec_type == AVMEDIA_TYPE_VIDEO) &&
+ pkt->dts != AV_NOPTS_VALUE &&
+ ost->last_mux_dts != AV_NOPTS_VALUE) {
+ int64_t max = ost->last_mux_dts + !(s->oformat->flags & AVFMT_TS_NONSTRICT);
+ if (pkt->dts < max) {
+ int loglevel = max - pkt->dts > 2 || avctx->codec_type == AVMEDIA_TYPE_VIDEO ? AV_LOG_WARNING : AV_LOG_DEBUG;
+ av_log(s, loglevel, "Non-monotonous DTS in output stream "
+ "%d:%d; previous: %"PRId64", current: %"PRId64"; ",
+ ost->file_index, ost->st->index, ost->last_mux_dts, pkt->dts);
+ if (exit_on_error) {
+ av_log(NULL, AV_LOG_FATAL, "aborting.\n");
+ exit_program(1);
+ }
+ av_log(s, loglevel, "changing to %"PRId64". This may result "
+ "in incorrect timestamps in the output file.\n",
+ max);
+ if(pkt->pts >= pkt->dts)
+ pkt->pts = FFMAX(pkt->pts, max);
+ pkt->dts = max;
+ }
+ }
+ }
+ ost->last_mux_dts = pkt->dts;
+
+ ost->data_size += pkt->size;
+ ost->packets_written++;
+
+ pkt->stream_index = ost->index;
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "muxer <- type:%s "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s size:%d\n",
+ av_get_media_type_string(ost->enc_ctx->codec_type),
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &ost->st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &ost->st->time_base),
+ pkt->size
+ );
+ }
+
+ ret = av_interleaved_write_frame(s, pkt);
+ if (ret < 0) {
+ print_error("av_interleaved_write_frame()", ret);
+ main_return_code = 1;
+ close_all_output_streams(ost, MUXER_FINISHED | ENCODER_FINISHED, ENCODER_FINISHED);
+ }
+ av_free_packet(pkt);
+}
+
+static void close_output_stream(OutputStream *ost)
+{
+ OutputFile *of = output_files[ost->file_index];
+
+ ost->finished |= ENCODER_FINISHED;
+ if (of->shortest) {
+ int64_t end = av_rescale_q(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, AV_TIME_BASE_Q);
+ of->recording_time = FFMIN(of->recording_time, end);
+ }
+}
+
+static int check_recording_time(OutputStream *ost)
+{
+ OutputFile *of = output_files[ost->file_index];
+
+ if (of->recording_time != INT64_MAX &&
+ av_compare_ts(ost->sync_opts - ost->first_pts, ost->enc_ctx->time_base, of->recording_time,
+ AV_TIME_BASE_Q) >= 0) {
+ close_output_stream(ost);
+ return 0;
+ }
+ return 1;
+}
+
+static void do_audio_out(AVFormatContext *s, OutputStream *ost,
+ AVFrame *frame)
+{
+ AVCodecContext *enc = ost->enc_ctx;
+ AVPacket pkt;
+ int got_packet = 0;
+
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ if (!check_recording_time(ost))
+ return;
+
+ if (frame->pts == AV_NOPTS_VALUE || audio_sync_method < 0)
+ frame->pts = ost->sync_opts;
+ ost->sync_opts = frame->pts + frame->nb_samples;
+ ost->samples_encoded += frame->nb_samples;
+ ost->frames_encoded++;
+
+ av_assert0(pkt.size || !pkt.data);
+ update_benchmark(NULL);
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "encoder <- type:audio "
+ "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n",
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &enc->time_base),
+ enc->time_base.num, enc->time_base.den);
+ }
+
+ if (avcodec_encode_audio2(enc, &pkt, frame, &got_packet) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Audio encoding failed (avcodec_encode_audio2)\n");
+ exit_program(1);
+ }
+ update_benchmark("encode_audio %d.%d", ost->file_index, ost->index);
+
+ if (got_packet) {
+ av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "encoder -> type:audio "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
+ av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
+ av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
+ }
+
+ write_frame(s, &pkt, ost);
+ }
+}
+
+static void do_subtitle_out(AVFormatContext *s,
+ OutputStream *ost,
+ InputStream *ist,
+ AVSubtitle *sub)
+{
+ int subtitle_out_max_size = 1024 * 1024;
+ int subtitle_out_size, nb, i;
+ AVCodecContext *enc;
+ AVPacket pkt;
+ int64_t pts;
+
+ if (sub->pts == AV_NOPTS_VALUE) {
+ av_log(NULL, AV_LOG_ERROR, "Subtitle packets must have a pts\n");
+ if (exit_on_error)
+ exit_program(1);
+ return;
+ }
+
+ enc = ost->enc_ctx;
+
+ if (!subtitle_out) {
+ subtitle_out = av_malloc(subtitle_out_max_size);
+ if (!subtitle_out) {
+ av_log(NULL, AV_LOG_FATAL, "Failed to allocate subtitle_out\n");
+ exit_program(1);
+ }
+ }
+
+ /* Note: DVB subtitle need one packet to draw them and one other
+ packet to clear them */
+ /* XXX: signal it in the codec context ? */
+ if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
+ nb = 2;
+ else
+ nb = 1;
+
+ /* shift timestamp to honor -ss and make check_recording_time() work with -t */
+ pts = sub->pts;
+ if (output_files[ost->file_index]->start_time != AV_NOPTS_VALUE)
+ pts -= output_files[ost->file_index]->start_time;
+ for (i = 0; i < nb; i++) {
+ unsigned save_num_rects = sub->num_rects;
+
+ ost->sync_opts = av_rescale_q(pts, AV_TIME_BASE_Q, enc->time_base);
+ if (!check_recording_time(ost))
+ return;
+
+ sub->pts = pts;
+ // start_display_time is required to be 0
+ sub->pts += av_rescale_q(sub->start_display_time, (AVRational){ 1, 1000 }, AV_TIME_BASE_Q);
+ sub->end_display_time -= sub->start_display_time;
+ sub->start_display_time = 0;
+ if (i == 1)
+ sub->num_rects = 0;
+
+ ost->frames_encoded++;
+
+ subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
+ subtitle_out_max_size, sub);
+ if (i == 1)
+ sub->num_rects = save_num_rects;
+ if (subtitle_out_size < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Subtitle encoding failed\n");
+ exit_program(1);
+ }
+
+ av_init_packet(&pkt);
+ pkt.data = subtitle_out;
+ pkt.size = subtitle_out_size;
+ pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
+ pkt.duration = av_rescale_q(sub->end_display_time, (AVRational){ 1, 1000 }, ost->st->time_base);
+ if (enc->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
+ /* XXX: the pts correction is handled here. Maybe handling
+ it in the codec would be better */
+ if (i == 0)
+ pkt.pts += 90 * sub->start_display_time;
+ else
+ pkt.pts += 90 * sub->end_display_time;
+ }
+ pkt.dts = pkt.pts;
+ write_frame(s, &pkt, ost);
+ }
+}
+
+static void do_video_out(AVFormatContext *s,
+ OutputStream *ost,
+ AVFrame *next_picture,
+ double sync_ipts)
+{
+ int ret, format_video_sync;
+ AVPacket pkt;
+ AVCodecContext *enc = ost->enc_ctx;
+ AVCodecContext *mux_enc = ost->st->codec;
+ int nb_frames, nb0_frames, i;
+ double delta, delta0;
+ double duration = 0;
+ int frame_size = 0;
+ InputStream *ist = NULL;
+ AVFilterContext *filter = ost->filter->filter;
+
+ if (ost->source_index >= 0)
+ ist = input_streams[ost->source_index];
+
+ if (filter->inputs[0]->frame_rate.num > 0 &&
+ filter->inputs[0]->frame_rate.den > 0)
+ duration = 1/(av_q2d(filter->inputs[0]->frame_rate) * av_q2d(enc->time_base));
+
+ if(ist && ist->st->start_time != AV_NOPTS_VALUE && ist->st->first_dts != AV_NOPTS_VALUE && ost->frame_rate.num)
+ duration = FFMIN(duration, 1/(av_q2d(ost->frame_rate) * av_q2d(enc->time_base)));
+
+ if (!ost->filters_script &&
+ !ost->filters &&
+ next_picture &&
+ ist &&
+ lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)) > 0) {
+ duration = lrintf(av_frame_get_pkt_duration(next_picture) * av_q2d(ist->st->time_base) / av_q2d(enc->time_base));
+ }
+
+ if (!next_picture) {
+ //end, flushing
+ nb0_frames = nb_frames = mid_pred(ost->last_nb0_frames[0],
+ ost->last_nb0_frames[1],
+ ost->last_nb0_frames[2]);
+ } else {
+ delta0 = sync_ipts - ost->sync_opts;
+ delta = delta0 + duration;
+
+ /* by default, we output a single frame */
+ nb0_frames = 0;
+ nb_frames = 1;
+
+ format_video_sync = video_sync_method;
+ if (format_video_sync == VSYNC_AUTO) {
+ if(!strcmp(s->oformat->name, "avi")) {
+ format_video_sync = VSYNC_VFR;
+ } else
+ format_video_sync = (s->oformat->flags & AVFMT_VARIABLE_FPS) ? ((s->oformat->flags & AVFMT_NOTIMESTAMPS) ? VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR;
+ if ( ist
+ && format_video_sync == VSYNC_CFR
+ && input_files[ist->file_index]->ctx->nb_streams == 1
+ && input_files[ist->file_index]->input_ts_offset == 0) {
+ format_video_sync = VSYNC_VSCFR;
+ }
+ if (format_video_sync == VSYNC_CFR && copy_ts) {
+ format_video_sync = VSYNC_VSCFR;
+ }
+ }
+
+ if (delta0 < 0 &&
+ delta > 0 &&
+ format_video_sync != VSYNC_PASSTHROUGH &&
+ format_video_sync != VSYNC_DROP) {
+ double cor = FFMIN(-delta0, duration);
+ if (delta0 < -0.6) {
+ av_log(NULL, AV_LOG_WARNING, "Past duration %f too large\n", -delta0);
+ } else
+ av_log(NULL, AV_LOG_DEBUG, "Cliping frame in rate conversion by %f\n", -delta0);
+ sync_ipts += cor;
+ duration -= cor;
+ delta0 += cor;
+ }
+
+ switch (format_video_sync) {
+ case VSYNC_VSCFR:
+ if (ost->frame_number == 0 && delta - duration >= 0.5) {
+ av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta - duration));
+ delta = duration;
+ delta0 = 0;
+ ost->sync_opts = lrint(sync_ipts);
+ }
+ case VSYNC_CFR:
+ // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
+ if (frame_drop_threshold && delta < frame_drop_threshold && ost->frame_number) {
+ nb_frames = 0;
+ } else if (delta < -1.1)
+ nb_frames = 0;
+ else if (delta > 1.1) {
+ nb_frames = lrintf(delta);
+ if (delta0 > 1.1)
+ nb0_frames = lrintf(delta0 - 0.6);
+ }
+ break;
+ case VSYNC_VFR:
+ if (delta <= -0.6)
+ nb_frames = 0;
+ else if (delta > 0.6)
+ ost->sync_opts = lrint(sync_ipts);
+ break;
+ case VSYNC_DROP:
+ case VSYNC_PASSTHROUGH:
+ ost->sync_opts = lrint(sync_ipts);
+ break;
+ default:
+ av_assert0(0);
+ }
+ }
+
+ nb_frames = FFMIN(nb_frames, ost->max_frames - ost->frame_number);
+ nb0_frames = FFMIN(nb0_frames, nb_frames);
+
+ memmove(ost->last_nb0_frames + 1,
+ ost->last_nb0_frames,
+ sizeof(ost->last_nb0_frames[0]) * (FF_ARRAY_ELEMS(ost->last_nb0_frames) - 1));
+ ost->last_nb0_frames[0] = nb0_frames;
+
+ if (nb0_frames == 0 && ost->last_droped) {
+ nb_frames_drop++;
+ av_log(NULL, AV_LOG_VERBOSE,
+ "*** dropping frame %d from stream %d at ts %"PRId64"\n",
+ ost->frame_number, ost->st->index, ost->last_frame->pts);
+ }
+ if (nb_frames > (nb0_frames && ost->last_droped) + (nb_frames > nb0_frames)) {
+ if (nb_frames > dts_error_threshold * 30) {
+ av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skipping\n", nb_frames - 1);
+ nb_frames_drop++;
+ return;
+ }
+ nb_frames_dup += nb_frames - (nb0_frames && ost->last_droped) - (nb_frames > nb0_frames);
+ av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
+ }
+ ost->last_droped = nb_frames == nb0_frames && next_picture;
+
+ /* duplicates frame if needed */
+ for (i = 0; i < nb_frames; i++) {
+ AVFrame *in_picture;
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ if (i < nb0_frames && ost->last_frame) {
+ in_picture = ost->last_frame;
+ } else
+ in_picture = next_picture;
+
+ if (!in_picture)
+ return;
+
+ in_picture->pts = ost->sync_opts;
+
+#if 1
+ if (!check_recording_time(ost))
+#else
+ if (ost->frame_number >= ost->max_frames)
+#endif
+ return;
+
+ if (s->oformat->flags & AVFMT_RAWPICTURE &&
+ enc->codec->id == AV_CODEC_ID_RAWVIDEO) {
+ /* raw pictures are written as AVPicture structure to
+ avoid any copies. We support temporarily the older
+ method. */
+ if (in_picture->interlaced_frame)
+ mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+ else
+ mux_enc->field_order = AV_FIELD_PROGRESSIVE;
+ pkt.data = (uint8_t *)in_picture;
+ pkt.size = sizeof(AVPicture);
+ pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->st->time_base);
+ pkt.flags |= AV_PKT_FLAG_KEY;
+
+ write_frame(s, &pkt, ost);
+ } else {
+ int got_packet, forced_keyframe = 0;
+ double pts_time;
+
+ if (enc->flags & (CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME) &&
+ ost->top_field_first >= 0)
+ in_picture->top_field_first = !!ost->top_field_first;
+
+ if (in_picture->interlaced_frame) {
+ if (enc->codec->id == AV_CODEC_ID_MJPEG)
+ mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TT:AV_FIELD_BB;
+ else
+ mux_enc->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT;
+ } else
+ mux_enc->field_order = AV_FIELD_PROGRESSIVE;
+
+ in_picture->quality = enc->global_quality;
+ in_picture->pict_type = 0;
+
+ pts_time = in_picture->pts != AV_NOPTS_VALUE ?
+ in_picture->pts * av_q2d(enc->time_base) : NAN;
+ if (ost->forced_kf_index < ost->forced_kf_count &&
+ in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
+ ost->forced_kf_index++;
+ forced_keyframe = 1;
+ } else if (ost->forced_keyframes_pexpr) {
+ double res;
+ ost->forced_keyframes_expr_const_values[FKF_T] = pts_time;
+ res = av_expr_eval(ost->forced_keyframes_pexpr,
+ ost->forced_keyframes_expr_const_values, NULL);
+ av_dlog(NULL, "force_key_frame: n:%f n_forced:%f prev_forced_n:%f t:%f prev_forced_t:%f -> res:%f\n",
+ ost->forced_keyframes_expr_const_values[FKF_N],
+ ost->forced_keyframes_expr_const_values[FKF_N_FORCED],
+ ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N],
+ ost->forced_keyframes_expr_const_values[FKF_T],
+ ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T],
+ res);
+ if (res) {
+ forced_keyframe = 1;
+ ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] =
+ ost->forced_keyframes_expr_const_values[FKF_N];
+ ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] =
+ ost->forced_keyframes_expr_const_values[FKF_T];
+ ost->forced_keyframes_expr_const_values[FKF_N_FORCED] += 1;
+ }
+
+ ost->forced_keyframes_expr_const_values[FKF_N] += 1;
+ } else if ( ost->forced_keyframes
+ && !strncmp(ost->forced_keyframes, "source", 6)
+ && in_picture->key_frame==1) {
+ forced_keyframe = 1;
+ }
+
+ if (forced_keyframe) {
+ in_picture->pict_type = AV_PICTURE_TYPE_I;
+ av_log(NULL, AV_LOG_DEBUG, "Forced keyframe at time %f\n", pts_time);
+ }
+
+ update_benchmark(NULL);
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "encoder <- type:video "
+ "frame_pts:%s frame_pts_time:%s time_base:%d/%d\n",
+ av_ts2str(in_picture->pts), av_ts2timestr(in_picture->pts, &enc->time_base),
+ enc->time_base.num, enc->time_base.den);
+ }
+
+ ost->frames_encoded++;
+
+ ret = avcodec_encode_video2(enc, &pkt, in_picture, &got_packet);
+ update_benchmark("encode_video %d.%d", ost->file_index, ost->index);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Video encoding failed\n");
+ exit_program(1);
+ }
+
+ if (got_packet) {
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
+ av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &enc->time_base),
+ av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &enc->time_base));
+ }
+
+ if (pkt.pts == AV_NOPTS_VALUE && !(enc->codec->capabilities & CODEC_CAP_DELAY))
+ pkt.pts = ost->sync_opts;
+
+ av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "encoder -> type:video "
+ "pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s\n",
+ av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ost->st->time_base),
+ av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ost->st->time_base));
+ }
+
+ frame_size = pkt.size;
+ write_frame(s, &pkt, ost);
+
+ /* if two pass, output log */
+ if (ost->logfile && enc->stats_out) {
+ fprintf(ost->logfile, "%s", enc->stats_out);
+ }
+ }
+ }
+ ost->sync_opts++;
+ /*
+ * For video, number of frames in == number of packets out.
+ * But there may be reordering, so we can't throw away frames on encoder
+ * flush, we need to limit them here, before they go into encoder.
+ */
+ ost->frame_number++;
+
+ if (vstats_filename && frame_size)
+ do_video_stats(ost, frame_size);
+ }
+
+ if (!ost->last_frame)
+ ost->last_frame = av_frame_alloc();
+ av_frame_unref(ost->last_frame);
+ if (next_picture)
+ av_frame_ref(ost->last_frame, next_picture);
+}
+
+static double psnr(double d)
+{
+ return -10.0 * log(d) / log(10.0);
+}
+
+static void do_video_stats(OutputStream *ost, int frame_size)
+{
+ AVCodecContext *enc;
+ int frame_number;
+ double ti1, bitrate, avg_bitrate;
+
+ /* this is executed just the first time do_video_stats is called */
+ if (!vstats_file) {
+ vstats_file = fopen(vstats_filename, "w");
+ if (!vstats_file) {
+ perror("fopen");
+ exit_program(1);
+ }
+ }
+
+ enc = ost->enc_ctx;
+ if (enc->codec_type == AVMEDIA_TYPE_VIDEO) {
+ frame_number = ost->st->nb_frames;
+ fprintf(vstats_file, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame ? enc->coded_frame->quality / (float)FF_QP2LAMBDA : 0);
+ if (enc->coded_frame && (enc->flags&CODEC_FLAG_PSNR))
+ fprintf(vstats_file, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0] / (enc->width * enc->height * 255.0 * 255.0)));
+
+ fprintf(vstats_file,"f_size= %6d ", frame_size);
+ /* compute pts value */
+ ti1 = av_stream_get_end_pts(ost->st) * av_q2d(ost->st->time_base);
+ if (ti1 < 0.01)
+ ti1 = 0.01;
+
+ bitrate = (frame_size * 8) / av_q2d(enc->time_base) / 1000.0;
+ avg_bitrate = (double)(ost->data_size * 8) / ti1 / 1000.0;
+ fprintf(vstats_file, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
+ (double)ost->data_size / 1024, ti1, bitrate, avg_bitrate);
+ fprintf(vstats_file, "type= %c\n", enc->coded_frame ? av_get_picture_type_char(enc->coded_frame->pict_type) : 'I');
+ }
+}
+
+static void finish_output_stream(OutputStream *ost)
+{
+ OutputFile *of = output_files[ost->file_index];
+ int i;
+
+ ost->finished = ENCODER_FINISHED | MUXER_FINISHED;
+
+ if (of->shortest) {
+ for (i = 0; i < of->ctx->nb_streams; i++)
+ output_streams[of->ost_index + i]->finished = ENCODER_FINISHED | MUXER_FINISHED;
+ }
+}
+
+/**
+ * Get and encode new output from any of the filtergraphs, without causing
+ * activity.
+ *
+ * @return 0 for success, <0 for severe errors
+ */
+static int reap_filters(int flush)
+{
+ AVFrame *filtered_frame = NULL;
+ int i;
+
+ /* Reap all buffers present in the buffer sinks */
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ OutputFile *of = output_files[ost->file_index];
+ AVFilterContext *filter;
+ AVCodecContext *enc = ost->enc_ctx;
+ int ret = 0;
+
+ if (!ost->filter)
+ continue;
+ filter = ost->filter->filter;
+
+ if (!ost->filtered_frame && !(ost->filtered_frame = av_frame_alloc())) {
+ return AVERROR(ENOMEM);
+ }
+ filtered_frame = ost->filtered_frame;
+
+ while (1) {
+ double float_pts = AV_NOPTS_VALUE; // this is identical to filtered_frame.pts but with higher precision
+ ret = av_buffersink_get_frame_flags(filter, filtered_frame,
+ AV_BUFFERSINK_FLAG_NO_REQUEST);
+ if (ret < 0) {
+ if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Error in av_buffersink_get_frame_flags(): %s\n", av_err2str(ret));
+ } else if (flush && ret == AVERROR_EOF) {
+ if (filter->inputs[0]->type == AVMEDIA_TYPE_VIDEO)
+ do_video_out(of->ctx, ost, NULL, AV_NOPTS_VALUE);
+ }
+ break;
+ }
+ if (ost->finished) {
+ av_frame_unref(filtered_frame);
+ continue;
+ }
+ if (filtered_frame->pts != AV_NOPTS_VALUE) {
+ int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
+ AVRational tb = enc->time_base;
+ int extra_bits = av_clip(29 - av_log2(tb.den), 0, 16);
+
+ tb.den <<= extra_bits;
+ float_pts =
+ av_rescale_q(filtered_frame->pts, filter->inputs[0]->time_base, tb) -
+ av_rescale_q(start_time, AV_TIME_BASE_Q, tb);
+ float_pts /= 1 << extra_bits;
+ // avoid exact midoints to reduce the chance of rounding differences, this can be removed in case the fps code is changed to work with integers
+ float_pts += FFSIGN(float_pts) * 1.0 / (1<<17);
+
+ filtered_frame->pts =
+ av_rescale_q(filtered_frame->pts, filter->inputs[0]->time_base, enc->time_base) -
+ av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);
+ }
+ //if (ost->source_index >= 0)
+ // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold
+
+ switch (filter->inputs[0]->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (!ost->frame_aspect_ratio.num)
+ enc->sample_aspect_ratio = filtered_frame->sample_aspect_ratio;
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f time_base:%d/%d\n",
+ av_ts2str(filtered_frame->pts), av_ts2timestr(filtered_frame->pts, &enc->time_base),
+ float_pts,
+ enc->time_base.num, enc->time_base.den);
+ }
+
+ do_video_out(of->ctx, ost, filtered_frame, float_pts);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if (!(enc->codec->capabilities & CODEC_CAP_PARAM_CHANGE) &&
+ enc->channels != av_frame_get_channels(filtered_frame)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Audio filter graph output is not normalized and encoder does not support parameter changes\n");
+ break;
+ }
+ do_audio_out(of->ctx, ost, filtered_frame);
+ break;
+ default:
+ // TODO support subtitle filters
+ av_assert0(0);
+ }
+
+ av_frame_unref(filtered_frame);
+ }
+ }
+
+ return 0;
+}
+
+static void print_final_stats(int64_t total_size)
+{
+ uint64_t video_size = 0, audio_size = 0, extra_size = 0, other_size = 0;
+ uint64_t subtitle_size = 0;
+ uint64_t data_size = 0;
+ float percent = -1.0;
+ int i, j;
+
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ switch (ost->enc_ctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO: video_size += ost->data_size; break;
+ case AVMEDIA_TYPE_AUDIO: audio_size += ost->data_size; break;
+ case AVMEDIA_TYPE_SUBTITLE: subtitle_size += ost->data_size; break;
+ default: other_size += ost->data_size; break;
+ }
+ extra_size += ost->enc_ctx->extradata_size;
+ data_size += ost->data_size;
+ }
+
+ if (data_size && total_size>0 && total_size >= data_size)
+ percent = 100.0 * (total_size - data_size) / data_size;
+
+ av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB subtitle:%1.0fkB other streams:%1.0fkB global headers:%1.0fkB muxing overhead: ",
+ video_size / 1024.0,
+ audio_size / 1024.0,
+ subtitle_size / 1024.0,
+ other_size / 1024.0,
+ extra_size / 1024.0);
+ if (percent >= 0.0)
+ av_log(NULL, AV_LOG_INFO, "%f%%", percent);
+ else
+ av_log(NULL, AV_LOG_INFO, "unknown");
+ av_log(NULL, AV_LOG_INFO, "\n");
+
+ /* print verbose per-stream stats */
+ for (i = 0; i < nb_input_files; i++) {
+ InputFile *f = input_files[i];
+ uint64_t total_packets = 0, total_size = 0;
+
+ av_log(NULL, AV_LOG_VERBOSE, "Input file #%d (%s):\n",
+ i, f->ctx->filename);
+
+ for (j = 0; j < f->nb_streams; j++) {
+ InputStream *ist = input_streams[f->ist_index + j];
+ enum AVMediaType type = ist->dec_ctx->codec_type;
+
+ total_size += ist->data_size;
+ total_packets += ist->nb_packets;
+
+ av_log(NULL, AV_LOG_VERBOSE, " Input stream #%d:%d (%s): ",
+ i, j, media_type_string(type));
+ av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets read (%"PRIu64" bytes); ",
+ ist->nb_packets, ist->data_size);
+
+ if (ist->decoding_needed) {
+ av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames decoded",
+ ist->frames_decoded);
+ if (type == AVMEDIA_TYPE_AUDIO)
+ av_log(NULL, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ist->samples_decoded);
+ av_log(NULL, AV_LOG_VERBOSE, "; ");
+ }
+
+ av_log(NULL, AV_LOG_VERBOSE, "\n");
+ }
+
+ av_log(NULL, AV_LOG_VERBOSE, " Total: %"PRIu64" packets (%"PRIu64" bytes) demuxed\n",
+ total_packets, total_size);
+ }
+
+ for (i = 0; i < nb_output_files; i++) {
+ OutputFile *of = output_files[i];
+ uint64_t total_packets = 0, total_size = 0;
+
+ av_log(NULL, AV_LOG_VERBOSE, "Output file #%d (%s):\n",
+ i, of->ctx->filename);
+
+ for (j = 0; j < of->ctx->nb_streams; j++) {
+ OutputStream *ost = output_streams[of->ost_index + j];
+ enum AVMediaType type = ost->enc_ctx->codec_type;
+
+ total_size += ost->data_size;
+ total_packets += ost->packets_written;
+
+ av_log(NULL, AV_LOG_VERBOSE, " Output stream #%d:%d (%s): ",
+ i, j, media_type_string(type));
+ if (ost->encoding_needed) {
+ av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" frames encoded",
+ ost->frames_encoded);
+ if (type == AVMEDIA_TYPE_AUDIO)
+ av_log(NULL, AV_LOG_VERBOSE, " (%"PRIu64" samples)", ost->samples_encoded);
+ av_log(NULL, AV_LOG_VERBOSE, "; ");
+ }
+
+ av_log(NULL, AV_LOG_VERBOSE, "%"PRIu64" packets muxed (%"PRIu64" bytes); ",
+ ost->packets_written, ost->data_size);
+
+ av_log(NULL, AV_LOG_VERBOSE, "\n");
+ }
+
+ av_log(NULL, AV_LOG_VERBOSE, " Total: %"PRIu64" packets (%"PRIu64" bytes) muxed\n",
+ total_packets, total_size);
+ }
+ if(video_size + data_size + audio_size + subtitle_size + extra_size == 0){
+ av_log(NULL, AV_LOG_WARNING, "Output file is empty, nothing was encoded (check -ss / -t / -frames parameters if used)\n");
+ }
+}
+
+static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)
+{
+ char buf[1024];
+ AVBPrint buf_script;
+ OutputStream *ost;
+ AVFormatContext *oc;
+ int64_t total_size;
+ AVCodecContext *enc;
+ int frame_number, vid, i;
+ double bitrate;
+ int64_t pts = INT64_MIN;
+ static int64_t last_time = -1;
+ static int qp_histogram[52];
+ int hours, mins, secs, us;
+
+ if (!print_stats && !is_last_report && !progress_avio)
+ return;
+
+ if (!is_last_report) {
+ if (last_time == -1) {
+ last_time = cur_time;
+ return;
+ }
+ if ((cur_time - last_time) < 500000)
+ return;
+ last_time = cur_time;
+ }
+
+
+ oc = output_files[0]->ctx;
+
+ total_size = avio_size(oc->pb);
+ if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too
+ total_size = avio_tell(oc->pb);
+
+ buf[0] = '\0';
+ vid = 0;
+ av_bprint_init(&buf_script, 0, 1);
+ for (i = 0; i < nb_output_streams; i++) {
+ float q = -1;
+ ost = output_streams[i];
+ enc = ost->enc_ctx;
+ if (!ost->stream_copy && enc->coded_frame)
+ q = enc->coded_frame->quality / (float)FF_QP2LAMBDA;
+ if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q);
+ av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n",
+ ost->file_index, ost->index, q);
+ }
+ if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
+ float fps, t = (cur_time-timer_start) / 1000000.0;
+
+ frame_number = ost->frame_number;
+ fps = t > 1 ? frame_number / t : 0;
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3.*f q=%3.1f ",
+ frame_number, fps < 9.95, fps, q);
+ av_bprintf(&buf_script, "frame=%d\n", frame_number);
+ av_bprintf(&buf_script, "fps=%.1f\n", fps);
+ av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n",
+ ost->file_index, ost->index, q);
+ if (is_last_report)
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L");
+ if (qp_hist) {
+ int j;
+ int qp = lrintf(q);
+ if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram))
+ qp_histogram[qp]++;
+ for (j = 0; j < 32; j++)
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log2(qp_histogram[j] + 1)));
+ }
+ if ((enc->flags&CODEC_FLAG_PSNR) && (enc->coded_frame || is_last_report)) {
+ int j;
+ double error, error_sum = 0;
+ double scale, scale_sum = 0;
+ double p;
+ char type[3] = { 'Y','U','V' };
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR=");
+ for (j = 0; j < 3; j++) {
+ if (is_last_report) {
+ error = enc->error[j];
+ scale = enc->width * enc->height * 255.0 * 255.0 * frame_number;
+ } else {
+ error = enc->coded_frame->error[j];
+ scale = enc->width * enc->height * 255.0 * 255.0;
+ }
+ if (j)
+ scale /= 4;
+ error_sum += error;
+ scale_sum += scale;
+ p = psnr(error / scale);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], p);
+ av_bprintf(&buf_script, "stream_%d_%d_psnr_%c=%2.2f\n",
+ ost->file_index, ost->index, type[j] | 32, p);
+ }
+ p = psnr(error_sum / scale_sum);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum));
+ av_bprintf(&buf_script, "stream_%d_%d_psnr_all=%2.2f\n",
+ ost->file_index, ost->index, p);
+ }
+ vid = 1;
+ }
+ /* compute min output value */
+ if (av_stream_get_end_pts(ost->st) != AV_NOPTS_VALUE)
+ pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st),
+ ost->st->time_base, AV_TIME_BASE_Q));
+ if (is_last_report)
+ nb_frames_drop += ost->last_droped;
+ }
+
+ secs = FFABS(pts) / AV_TIME_BASE;
+ us = FFABS(pts) % AV_TIME_BASE;
+ mins = secs / 60;
+ secs %= 60;
+ hours = mins / 60;
+ mins %= 60;
+
+ bitrate = pts && total_size >= 0 ? total_size * 8 / (pts / 1000.0) : -1;
+
+ if (total_size < 0) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "size=N/A time=");
+ else snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "size=%8.0fkB time=", total_size / 1024.0);
+ if (pts < 0)
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "-");
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
+ "%02d:%02d:%02d.%02d ", hours, mins, secs,
+ (100 * us) / AV_TIME_BASE);
+
+ if (bitrate < 0) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),"bitrate=N/A");
+ av_bprintf(&buf_script, "bitrate=N/A\n");
+ }else{
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),"bitrate=%6.1fkbits/s", bitrate);
+ av_bprintf(&buf_script, "bitrate=%6.1fkbits/s\n", bitrate);
+ }
+
+ if (total_size < 0) av_bprintf(&buf_script, "total_size=N/A\n");
+ else av_bprintf(&buf_script, "total_size=%"PRId64"\n", total_size);
+ av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts);
+ av_bprintf(&buf_script, "out_time=%02d:%02d:%02d.%06d\n",
+ hours, mins, secs, us);
+
+ if (nb_frames_dup || nb_frames_drop)
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d",
+ nb_frames_dup, nb_frames_drop);
+ av_bprintf(&buf_script, "dup_frames=%d\n", nb_frames_dup);
+ av_bprintf(&buf_script, "drop_frames=%d\n", nb_frames_drop);
+
+ if (print_stats || is_last_report) {
+ const char end = is_last_report ? '\n' : '\r';
+ if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) {
+ fprintf(stderr, "%s %c", buf, end);
+ } else
+ av_log(NULL, AV_LOG_INFO, "%s %c", buf, end);
+
+ fflush(stderr);
+ }
+
+ if (progress_avio) {
+ av_bprintf(&buf_script, "progress=%s\n",
+ is_last_report ? "end" : "continue");
+ avio_write(progress_avio, buf_script.str,
+ FFMIN(buf_script.len, buf_script.size - 1));
+ avio_flush(progress_avio);
+ av_bprint_finalize(&buf_script, NULL);
+ if (is_last_report) {
+ avio_closep(&progress_avio);
+ }
+ }
+
+ if (is_last_report)
+ print_final_stats(total_size);
+}
+
+static void flush_encoders(void)
+{
+ int i, ret;
+
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ AVCodecContext *enc = ost->enc_ctx;
+ AVFormatContext *os = output_files[ost->file_index]->ctx;
+ int stop_encoding = 0;
+
+ if (!ost->encoding_needed)
+ continue;
+
+ if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
+ continue;
+ if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO)
+ continue;
+
+ for (;;) {
+ int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
+ const char *desc;
+
+ switch (enc->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ encode = avcodec_encode_audio2;
+ desc = "Audio";
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ encode = avcodec_encode_video2;
+ desc = "Video";
+ break;
+ default:
+ stop_encoding = 1;
+ }
+
+ if (encode) {
+ AVPacket pkt;
+ int pkt_size;
+ int got_packet;
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+
+ update_benchmark(NULL);
+ ret = encode(enc, &pkt, NULL, &got_packet);
+ update_benchmark("flush %s %d.%d", desc, ost->file_index, ost->index);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "%s encoding failed\n", desc);
+ exit_program(1);
+ }
+ if (ost->logfile && enc->stats_out) {
+ fprintf(ost->logfile, "%s", enc->stats_out);
+ }
+ if (!got_packet) {
+ stop_encoding = 1;
+ break;
+ }
+ if (ost->finished & MUXER_FINISHED) {
+ av_free_packet(&pkt);
+ continue;
+ }
+ av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
+ pkt_size = pkt.size;
+ write_frame(os, &pkt, ost);
+ if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) {
+ do_video_stats(ost, pkt_size);
+ }
+ }
+
+ if (stop_encoding)
+ break;
+ }
+ }
+}
+
+/*
+ * Check whether a packet from ist should be written into ost at this time
+ */
+static int check_output_constraints(InputStream *ist, OutputStream *ost)
+{
+ OutputFile *of = output_files[ost->file_index];
+ int ist_index = input_files[ist->file_index]->ist_index + ist->st->index;
+
+ if (ost->source_index != ist_index)
+ return 0;
+
+ if (ost->finished)
+ return 0;
+
+ if (of->start_time != AV_NOPTS_VALUE && ist->pts < of->start_time)
+ return 0;
+
+ return 1;
+}
+
+static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *pkt)
+{
+ OutputFile *of = output_files[ost->file_index];
+ InputFile *f = input_files [ist->file_index];
+ int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
+ int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
+ int64_t ist_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ist->st->time_base);
+ AVPicture pict;
+ AVPacket opkt;
+
+ av_init_packet(&opkt);
+
+ if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) &&
+ !ost->copy_initial_nonkeyframes)
+ return;
+
+ if (pkt->pts == AV_NOPTS_VALUE) {
+ if (!ost->frame_number && ist->pts < start_time &&
+ !ost->copy_prior_start)
+ return;
+ } else {
+ if (!ost->frame_number && pkt->pts < ist_tb_start_time &&
+ !ost->copy_prior_start)
+ return;
+ }
+
+ if (of->recording_time != INT64_MAX &&
+ ist->pts >= of->recording_time + start_time) {
+ close_output_stream(ost);
+ return;
+ }
+
+ if (f->recording_time != INT64_MAX) {
+ start_time = f->ctx->start_time;
+ if (f->start_time != AV_NOPTS_VALUE)
+ start_time += f->start_time;
+ if (ist->pts >= f->recording_time + start_time) {
+ close_output_stream(ost);
+ return;
+ }
+ }
+
+ /* force the input stream PTS */
+ if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ ost->sync_opts++;
+
+ if (pkt->pts != AV_NOPTS_VALUE)
+ opkt.pts = av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base) - ost_tb_start_time;
+ else
+ opkt.pts = AV_NOPTS_VALUE;
+
+ if (pkt->dts == AV_NOPTS_VALUE)
+ opkt.dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ost->st->time_base);
+ else
+ opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
+ opkt.dts -= ost_tb_start_time;
+
+ if (ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO && pkt->dts != AV_NOPTS_VALUE) {
+ int duration = av_get_audio_frame_duration(ist->dec_ctx, pkt->size);
+ if(!duration)
+ duration = ist->dec_ctx->frame_size;
+ opkt.dts = opkt.pts = av_rescale_delta(ist->st->time_base, pkt->dts,
+ (AVRational){1, ist->dec_ctx->sample_rate}, duration, &ist->filter_in_rescale_delta_last,
+ ost->st->time_base) - ost_tb_start_time;
+ }
+
+ opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
+ opkt.flags = pkt->flags;
+
+ // FIXME remove the following 2 lines they shall be replaced by the bitstream filters
+ if ( ost->enc_ctx->codec_id != AV_CODEC_ID_H264
+ && ost->enc_ctx->codec_id != AV_CODEC_ID_MPEG1VIDEO
+ && ost->enc_ctx->codec_id != AV_CODEC_ID_MPEG2VIDEO
+ && ost->enc_ctx->codec_id != AV_CODEC_ID_VC1
+ ) {
+ if (av_parser_change(ost->parser, ost->st->codec,
+ &opkt.data, &opkt.size,
+ pkt->data, pkt->size,
+ pkt->flags & AV_PKT_FLAG_KEY)) {
+ opkt.buf = av_buffer_create(opkt.data, opkt.size, av_buffer_default_free, NULL, 0);
+ if (!opkt.buf)
+ exit_program(1);
+ }
+ } else {
+ opkt.data = pkt->data;
+ opkt.size = pkt->size;
+ }
+ av_copy_packet_side_data(&opkt, pkt);
+
+ if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO && (of->ctx->oformat->flags & AVFMT_RAWPICTURE)) {
+ /* store AVPicture in AVPacket, as expected by the output format */
+ avpicture_fill(&pict, opkt.data, ost->st->codec->pix_fmt, ost->st->codec->width, ost->st->codec->height);
+ opkt.data = (uint8_t *)&pict;
+ opkt.size = sizeof(AVPicture);
+ opkt.flags |= AV_PKT_FLAG_KEY;
+ }
+
+ write_frame(of->ctx, &opkt, ost);
+}
+
+int guess_input_channel_layout(InputStream *ist)
+{
+ AVCodecContext *dec = ist->dec_ctx;
+
+ if (!dec->channel_layout) {
+ char layout_name[256];
+
+ if (dec->channels > ist->guess_layout_max)
+ return 0;
+ dec->channel_layout = av_get_default_channel_layout(dec->channels);
+ if (!dec->channel_layout)
+ return 0;
+ av_get_channel_layout_string(layout_name, sizeof(layout_name),
+ dec->channels, dec->channel_layout);
+ av_log(NULL, AV_LOG_WARNING, "Guessed Channel Layout for Input Stream "
+ "#%d.%d : %s\n", ist->file_index, ist->st->index, layout_name);
+ }
+ return 1;
+}
+
+static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
+{
+ AVFrame *decoded_frame, *f;
+ AVCodecContext *avctx = ist->dec_ctx;
+ int i, ret, err = 0, resample_changed;
+ AVRational decoded_frame_tb;
+
+ if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ decoded_frame = ist->decoded_frame;
+
+ update_benchmark(NULL);
+ ret = avcodec_decode_audio4(avctx, decoded_frame, got_output, pkt);
+ update_benchmark("decode_audio %d.%d", ist->file_index, ist->st->index);
+
+ if (ret >= 0 && avctx->sample_rate <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Sample rate %d invalid\n", avctx->sample_rate);
+ ret = AVERROR_INVALIDDATA;
+ }
+
+ if (*got_output || ret<0 || pkt->size)
+ decode_error_stat[ret<0] ++;
+
+ if (!*got_output || ret < 0) {
+ if (!pkt->size) {
+ for (i = 0; i < ist->nb_filters; i++)
+#if 1
+ av_buffersrc_add_ref(ist->filters[i]->filter, NULL, 0);
+#else
+ av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
+#endif
+ }
+ return ret;
+ }
+
+ ist->samples_decoded += decoded_frame->nb_samples;
+ ist->frames_decoded++;
+
+#if 1
+ /* increment next_dts to use for the case where the input stream does not
+ have timestamps or there are multiple frames in the packet */
+ ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
+ avctx->sample_rate;
+ ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) /
+ avctx->sample_rate;
+#endif
+
+ resample_changed = ist->resample_sample_fmt != decoded_frame->format ||
+ ist->resample_channels != avctx->channels ||
+ ist->resample_channel_layout != decoded_frame->channel_layout ||
+ ist->resample_sample_rate != decoded_frame->sample_rate;
+ if (resample_changed) {
+ char layout1[64], layout2[64];
+
+ if (!guess_input_channel_layout(ist)) {
+ av_log(NULL, AV_LOG_FATAL, "Unable to find default channel "
+ "layout for Input Stream #%d.%d\n", ist->file_index,
+ ist->st->index);
+ exit_program(1);
+ }
+ decoded_frame->channel_layout = avctx->channel_layout;
+
+ av_get_channel_layout_string(layout1, sizeof(layout1), ist->resample_channels,
+ ist->resample_channel_layout);
+ av_get_channel_layout_string(layout2, sizeof(layout2), avctx->channels,
+ decoded_frame->channel_layout);
+
+ av_log(NULL, AV_LOG_INFO,
+ "Input stream #%d:%d frame changed from rate:%d fmt:%s ch:%d chl:%s to rate:%d fmt:%s ch:%d chl:%s\n",
+ ist->file_index, ist->st->index,
+ ist->resample_sample_rate, av_get_sample_fmt_name(ist->resample_sample_fmt),
+ ist->resample_channels, layout1,
+ decoded_frame->sample_rate, av_get_sample_fmt_name(decoded_frame->format),
+ avctx->channels, layout2);
+
+ ist->resample_sample_fmt = decoded_frame->format;
+ ist->resample_sample_rate = decoded_frame->sample_rate;
+ ist->resample_channel_layout = decoded_frame->channel_layout;
+ ist->resample_channels = avctx->channels;
+
+ for (i = 0; i < nb_filtergraphs; i++)
+ if (ist_in_filtergraph(filtergraphs[i], ist)) {
+ FilterGraph *fg = filtergraphs[i];
+ if (configure_filtergraph(fg) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
+ exit_program(1);
+ }
+ }
+ }
+
+ /* if the decoder provides a pts, use it instead of the last packet pts.
+ the decoder could be delaying output by a packet or more. */
+ if (decoded_frame->pts != AV_NOPTS_VALUE) {
+ ist->dts = ist->next_dts = ist->pts = ist->next_pts = av_rescale_q(decoded_frame->pts, avctx->time_base, AV_TIME_BASE_Q);
+ decoded_frame_tb = avctx->time_base;
+ } else if (decoded_frame->pkt_pts != AV_NOPTS_VALUE) {
+ decoded_frame->pts = decoded_frame->pkt_pts;
+ decoded_frame_tb = ist->st->time_base;
+ } else if (pkt->pts != AV_NOPTS_VALUE) {
+ decoded_frame->pts = pkt->pts;
+ decoded_frame_tb = ist->st->time_base;
+ }else {
+ decoded_frame->pts = ist->dts;
+ decoded_frame_tb = AV_TIME_BASE_Q;
+ }
+ pkt->pts = AV_NOPTS_VALUE;
+ if (decoded_frame->pts != AV_NOPTS_VALUE)
+ decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts,
+ (AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,
+ (AVRational){1, avctx->sample_rate});
+ for (i = 0; i < ist->nb_filters; i++) {
+ if (i < ist->nb_filters - 1) {
+ f = ist->filter_frame;
+ err = av_frame_ref(f, decoded_frame);
+ if (err < 0)
+ break;
+ } else
+ f = decoded_frame;
+ err = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f,
+ AV_BUFFERSRC_FLAG_PUSH);
+ if (err == AVERROR_EOF)
+ err = 0; /* ignore */
+ if (err < 0)
+ break;
+ }
+ decoded_frame->pts = AV_NOPTS_VALUE;
+
+ av_frame_unref(ist->filter_frame);
+ av_frame_unref(decoded_frame);
+ return err < 0 ? err : ret;
+}
+
+static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
+{
+ AVFrame *decoded_frame, *f;
+ int i, ret = 0, err = 0, resample_changed;
+ int64_t best_effort_timestamp;
+ AVRational *frame_sample_aspect;
+
+ if (!ist->decoded_frame && !(ist->decoded_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ if (!ist->filter_frame && !(ist->filter_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ decoded_frame = ist->decoded_frame;
+ pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
+
+ update_benchmark(NULL);
+ ret = avcodec_decode_video2(ist->dec_ctx,
+ decoded_frame, got_output, pkt);
+ update_benchmark("decode_video %d.%d", ist->file_index, ist->st->index);
+
+ // The following line may be required in some cases where there is no parser
+ // or the parser does not has_b_frames correctly
+ if (ist->st->codec->has_b_frames < ist->dec_ctx->has_b_frames) {
+ if (ist->dec_ctx->codec_id == AV_CODEC_ID_H264) {
+ ist->st->codec->has_b_frames = ist->dec_ctx->has_b_frames;
+ } else
+ av_log_ask_for_sample(
+ ist->dec_ctx,
+ "has_b_frames is larger in decoder than demuxer %d > %d ",
+ ist->dec_ctx->has_b_frames,
+ ist->st->codec->has_b_frames
+ );
+ }
+
+ if (*got_output || ret<0 || pkt->size)
+ decode_error_stat[ret<0] ++;
+
+ if (*got_output && ret >= 0) {
+ if (ist->dec_ctx->width != decoded_frame->width ||
+ ist->dec_ctx->height != decoded_frame->height ||
+ ist->dec_ctx->pix_fmt != decoded_frame->format) {
+ av_log(NULL, AV_LOG_DEBUG, "Frame parameters mismatch context %d,%d,%d != %d,%d,%d\n",
+ decoded_frame->width,
+ decoded_frame->height,
+ decoded_frame->format,
+ ist->dec_ctx->width,
+ ist->dec_ctx->height,
+ ist->dec_ctx->pix_fmt);
+ }
+ }
+
+ if (!*got_output || ret < 0) {
+ if (!pkt->size) {
+ for (i = 0; i < ist->nb_filters; i++)
+#if 1
+ av_buffersrc_add_ref(ist->filters[i]->filter, NULL, 0);
+#else
+ av_buffersrc_add_frame(ist->filters[i]->filter, NULL);
+#endif
+ }
+ return ret;
+ }
+
+ if(ist->top_field_first>=0)
+ decoded_frame->top_field_first = ist->top_field_first;
+
+ ist->frames_decoded++;
+
+ if (ist->hwaccel_retrieve_data && decoded_frame->format == ist->hwaccel_pix_fmt) {
+ err = ist->hwaccel_retrieve_data(ist->dec_ctx, decoded_frame);
+ if (err < 0)
+ goto fail;
+ }
+ ist->hwaccel_retrieved_pix_fmt = decoded_frame->format;
+
+ best_effort_timestamp= av_frame_get_best_effort_timestamp(decoded_frame);
+ if(best_effort_timestamp != AV_NOPTS_VALUE)
+ ist->next_pts = ist->pts = av_rescale_q(decoded_frame->pts = best_effort_timestamp, ist->st->time_base, AV_TIME_BASE_Q);
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "decoder -> ist_index:%d type:video "
+ "frame_pts:%s frame_pts_time:%s best_effort_ts:%"PRId64" best_effort_ts_time:%s keyframe:%d frame_type:%d time_base:%d/%d\n",
+ ist->st->index, av_ts2str(decoded_frame->pts),
+ av_ts2timestr(decoded_frame->pts, &ist->st->time_base),
+ best_effort_timestamp,
+ av_ts2timestr(best_effort_timestamp, &ist->st->time_base),
+ decoded_frame->key_frame, decoded_frame->pict_type,
+ ist->st->time_base.num, ist->st->time_base.den);
+ }
+
+ pkt->size = 0;
+
+ if (ist->st->sample_aspect_ratio.num)
+ decoded_frame->sample_aspect_ratio = ist->st->sample_aspect_ratio;
+
+ resample_changed = ist->resample_width != decoded_frame->width ||
+ ist->resample_height != decoded_frame->height ||
+ ist->resample_pix_fmt != decoded_frame->format;
+ if (resample_changed) {
+ av_log(NULL, AV_LOG_INFO,
+ "Input stream #%d:%d frame changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s\n",
+ ist->file_index, ist->st->index,
+ ist->resample_width, ist->resample_height, av_get_pix_fmt_name(ist->resample_pix_fmt),
+ decoded_frame->width, decoded_frame->height, av_get_pix_fmt_name(decoded_frame->format));
+
+ ist->resample_width = decoded_frame->width;
+ ist->resample_height = decoded_frame->height;
+ ist->resample_pix_fmt = decoded_frame->format;
+
+ for (i = 0; i < nb_filtergraphs; i++) {
+ if (ist_in_filtergraph(filtergraphs[i], ist) && ist->reinit_filters &&
+ configure_filtergraph(filtergraphs[i]) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error reinitializing filters!\n");
+ exit_program(1);
+ }
+ }
+ }
+
+ frame_sample_aspect= av_opt_ptr(avcodec_get_frame_class(), decoded_frame, "sample_aspect_ratio");
+ for (i = 0; i < ist->nb_filters; i++) {
+ if (!frame_sample_aspect->num)
+ *frame_sample_aspect = ist->st->sample_aspect_ratio;
+
+ if (i < ist->nb_filters - 1) {
+ f = ist->filter_frame;
+ err = av_frame_ref(f, decoded_frame);
+ if (err < 0)
+ break;
+ } else
+ f = decoded_frame;
+ ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, f, AV_BUFFERSRC_FLAG_PUSH);
+ if (ret == AVERROR_EOF) {
+ ret = 0; /* ignore */
+ } else if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Failed to inject frame into filter network: %s\n", av_err2str(ret));
+ exit_program(1);
+ }
+ }
+
+fail:
+ av_frame_unref(ist->filter_frame);
+ av_frame_unref(decoded_frame);
+ return err < 0 ? err : ret;
+}
+
+static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
+{
+ AVSubtitle subtitle;
+ int i, ret = avcodec_decode_subtitle2(ist->dec_ctx,
+ &subtitle, got_output, pkt);
+
+ if (*got_output || ret<0 || pkt->size)
+ decode_error_stat[ret<0] ++;
+
+ if (ret < 0 || !*got_output) {
+ if (!pkt->size)
+ sub2video_flush(ist);
+ return ret;
+ }
+
+ if (ist->fix_sub_duration) {
+ int end = 1;
+ if (ist->prev_sub.got_output) {
+ end = av_rescale(subtitle.pts - ist->prev_sub.subtitle.pts,
+ 1000, AV_TIME_BASE);
+ if (end < ist->prev_sub.subtitle.end_display_time) {
+ av_log(ist->dec_ctx, AV_LOG_DEBUG,
+ "Subtitle duration reduced from %d to %d%s\n",
+ ist->prev_sub.subtitle.end_display_time, end,
+ end <= 0 ? ", dropping it" : "");
+ ist->prev_sub.subtitle.end_display_time = end;
+ }
+ }
+ FFSWAP(int, *got_output, ist->prev_sub.got_output);
+ FFSWAP(int, ret, ist->prev_sub.ret);
+ FFSWAP(AVSubtitle, subtitle, ist->prev_sub.subtitle);
+ if (end <= 0)
+ goto out;
+ }
+
+ if (!*got_output)
+ return ret;
+
+ sub2video_update(ist, &subtitle);
+
+ if (!subtitle.num_rects)
+ goto out;
+
+ ist->frames_decoded++;
+
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+
+ if (!check_output_constraints(ist, ost) || !ost->encoding_needed
+ || ost->enc->type != AVMEDIA_TYPE_SUBTITLE)
+ continue;
+
+ do_subtitle_out(output_files[ost->file_index]->ctx, ost, ist, &subtitle);
+ }
+
+out:
+ avsubtitle_free(&subtitle);
+ return ret;
+}
+
+/* pkt = NULL means EOF (needed to flush decoder buffers) */
+static int process_input_packet(InputStream *ist, const AVPacket *pkt)
+{
+ int ret = 0, i;
+ int got_output = 0;
+
+ AVPacket avpkt;
+ if (!ist->saw_first_ts) {
+ ist->dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
+ ist->pts = 0;
+ if (pkt && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) {
+ ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
+ ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong
+ }
+ ist->saw_first_ts = 1;
+ }
+
+ if (ist->next_dts == AV_NOPTS_VALUE)
+ ist->next_dts = ist->dts;
+ if (ist->next_pts == AV_NOPTS_VALUE)
+ ist->next_pts = ist->pts;
+
+ if (!pkt) {
+ /* EOF handling */
+ av_init_packet(&avpkt);
+ avpkt.data = NULL;
+ avpkt.size = 0;
+ goto handle_eof;
+ } else {
+ avpkt = *pkt;
+ }
+
+ if (pkt->dts != AV_NOPTS_VALUE) {
+ ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
+ if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)
+ ist->next_pts = ist->pts = ist->dts;
+ }
+
+ // while we have more to decode or while the decoder did output something on EOF
+ while (ist->decoding_needed && (avpkt.size > 0 || (!pkt && got_output))) {
+ int duration;
+ handle_eof:
+
+ ist->pts = ist->next_pts;
+ ist->dts = ist->next_dts;
+
+ if (avpkt.size && avpkt.size != pkt->size &&
+ !(ist->dec->capabilities & CODEC_CAP_SUBFRAMES)) {
+ av_log(NULL, ist->showed_multi_packet_warning ? AV_LOG_VERBOSE : AV_LOG_WARNING,
+ "Multiple frames in a packet from stream %d\n", pkt->stream_index);
+ ist->showed_multi_packet_warning = 1;
+ }
+
+ switch (ist->dec_ctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ ret = decode_audio (ist, &avpkt, &got_output);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ ret = decode_video (ist, &avpkt, &got_output);
+ if (avpkt.duration) {
+ duration = av_rescale_q(avpkt.duration, ist->st->time_base, AV_TIME_BASE_Q);
+ } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {
+ int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict+1 : ist->dec_ctx->ticks_per_frame;
+ duration = ((int64_t)AV_TIME_BASE *
+ ist->dec_ctx->framerate.den * ticks) /
+ ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
+ } else
+ duration = 0;
+
+ if(ist->dts != AV_NOPTS_VALUE && duration) {
+ ist->next_dts += duration;
+ }else
+ ist->next_dts = AV_NOPTS_VALUE;
+
+ if (got_output)
+ ist->next_pts += duration; //FIXME the duration is not correct in some cases
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ ret = transcode_subtitles(ist, &avpkt, &got_output);
+ break;
+ default:
+ return -1;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ avpkt.dts=
+ avpkt.pts= AV_NOPTS_VALUE;
+
+ // touch data and size only if not EOF
+ if (pkt) {
+ if(ist->dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO)
+ ret = avpkt.size;
+ avpkt.data += ret;
+ avpkt.size -= ret;
+ }
+ if (!got_output) {
+ continue;
+ }
+ if (got_output && !pkt)
+ break;
+ }
+
+ /* handle stream copy */
+ if (!ist->decoding_needed) {
+ ist->dts = ist->next_dts;
+ switch (ist->dec_ctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) /
+ ist->dec_ctx->sample_rate;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (ist->framerate.num) {
+ // TODO: Remove work-around for c99-to-c89 issue 7
+ AVRational time_base_q = AV_TIME_BASE_Q;
+ int64_t next_dts = av_rescale_q(ist->next_dts, time_base_q, av_inv_q(ist->framerate));
+ ist->next_dts = av_rescale_q(next_dts + 1, av_inv_q(ist->framerate), time_base_q);
+ } else if (pkt->duration) {
+ ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
+ } else if(ist->dec_ctx->framerate.num != 0) {
+ int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame;
+ ist->next_dts += ((int64_t)AV_TIME_BASE *
+ ist->dec_ctx->framerate.den * ticks) /
+ ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
+ }
+ break;
+ }
+ ist->pts = ist->dts;
+ ist->next_pts = ist->next_dts;
+ }
+ for (i = 0; pkt && i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+
+ if (!check_output_constraints(ist, ost) || ost->encoding_needed)
+ continue;
+
+ do_streamcopy(ist, ost, pkt);
+ }
+
+ return got_output;
+}
+
+static void print_sdp(void)
+{
+ char sdp[16384];
+ int i;
+ int j;
+ AVIOContext *sdp_pb;
+ AVFormatContext **avc = av_malloc_array(nb_output_files, sizeof(*avc));
+
+ if (!avc)
+ exit_program(1);
+ for (i = 0, j = 0; i < nb_output_files; i++) {
+ if (!strcmp(output_files[i]->ctx->oformat->name, "rtp")) {
+ avc[j] = output_files[i]->ctx;
+ j++;
+ }
+ }
+
+ av_sdp_create(avc, j, sdp, sizeof(sdp));
+
+ if (!sdp_filename) {
+ printf("SDP:\n%s\n", sdp);
+ fflush(stdout);
+ } else {
+ if (avio_open2(&sdp_pb, sdp_filename, AVIO_FLAG_WRITE, &int_cb, NULL) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open sdp file '%s'\n", sdp_filename);
+ } else {
+ avio_printf(sdp_pb, "SDP:\n%s", sdp);
+ avio_closep(&sdp_pb);
+ av_freep(&sdp_filename);
+ }
+ }
+
+ av_freep(&avc);
+}
+
+static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt)
+{
+ int i;
+ for (i = 0; hwaccels[i].name; i++)
+ if (hwaccels[i].pix_fmt == pix_fmt)
+ return &hwaccels[i];
+ return NULL;
+}
+
+static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
+{
+ InputStream *ist = s->opaque;
+ const enum AVPixelFormat *p;
+ int ret;
+
+ for (p = pix_fmts; *p != -1; p++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
+ const HWAccel *hwaccel;
+
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ break;
+
+ hwaccel = get_hwaccel(*p);
+ if (!hwaccel ||
+ (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) ||
+ (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != hwaccel->id))
+ continue;
+
+ ret = hwaccel->init(s);
+ if (ret < 0) {
+ if (ist->hwaccel_id == hwaccel->id) {
+ av_log(NULL, AV_LOG_FATAL,
+ "%s hwaccel requested for input stream #%d:%d, "
+ "but cannot be initialized.\n", hwaccel->name,
+ ist->file_index, ist->st->index);
+ return AV_PIX_FMT_NONE;
+ }
+ continue;
+ }
+ ist->active_hwaccel_id = hwaccel->id;
+ ist->hwaccel_pix_fmt = *p;
+ break;
+ }
+
+ return *p;
+}
+
+static int get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
+{
+ InputStream *ist = s->opaque;
+
+ if (ist->hwaccel_get_buffer && frame->format == ist->hwaccel_pix_fmt)
+ return ist->hwaccel_get_buffer(s, frame, flags);
+
+ return avcodec_default_get_buffer2(s, frame, flags);
+}
+
+static int init_input_stream(int ist_index, char *error, int error_len)
+{
+ int ret;
+ InputStream *ist = input_streams[ist_index];
+
+ if (ist->decoding_needed) {
+ AVCodec *codec = ist->dec;
+ if (!codec) {
+ snprintf(error, error_len, "Decoder (codec %s) not found for input stream #%d:%d",
+ avcodec_get_name(ist->dec_ctx->codec_id), ist->file_index, ist->st->index);
+ return AVERROR(EINVAL);
+ }
+
+ ist->dec_ctx->opaque = ist;
+ ist->dec_ctx->get_format = get_format;
+ ist->dec_ctx->get_buffer2 = get_buffer;
+ ist->dec_ctx->thread_safe_callbacks = 1;
+
+ av_opt_set_int(ist->dec_ctx, "refcounted_frames", 1, 0);
+ if (ist->dec_ctx->codec_id == AV_CODEC_ID_DVB_SUBTITLE &&
+ (ist->decoding_needed & DECODING_FOR_OST)) {
+ av_dict_set(&ist->decoder_opts, "compute_edt", "1", AV_DICT_DONT_OVERWRITE);
+ if (ist->decoding_needed & DECODING_FOR_FILTER)
+ av_log(NULL, AV_LOG_WARNING, "Warning using DVB subtitles for filtering and output at the same time is not fully supported, also see -compute_edt [0|1]\n");
+ }
+
+ if (!av_dict_get(ist->decoder_opts, "threads", NULL, 0))
+ av_dict_set(&ist->decoder_opts, "threads", "auto", 0);
+ if ((ret = avcodec_open2(ist->dec_ctx, codec, &ist->decoder_opts)) < 0) {
+ if (ret == AVERROR_EXPERIMENTAL)
+ abort_codec_experimental(codec, 0);
+
+ snprintf(error, error_len,
+ "Error while opening decoder for input stream "
+ "#%d:%d : %s",
+ ist->file_index, ist->st->index, av_err2str(ret));
+ return ret;
+ }
+ assert_avoptions(ist->decoder_opts);
+ }
+
+ ist->next_pts = AV_NOPTS_VALUE;
+ ist->next_dts = AV_NOPTS_VALUE;
+
+ return 0;
+}
+
+static InputStream *get_input_stream(OutputStream *ost)
+{
+ if (ost->source_index >= 0)
+ return input_streams[ost->source_index];
+ return NULL;
+}
+
+static int compare_int64(const void *a, const void *b)
+{
+ int64_t va = *(int64_t *)a, vb = *(int64_t *)b;
+ return va < vb ? -1 : va > vb ? +1 : 0;
+}
+
+static void parse_forced_key_frames(char *kf, OutputStream *ost,
+ AVCodecContext *avctx)
+{
+ char *p;
+ int n = 1, i, size, index = 0;
+ int64_t t, *pts;
+
+ for (p = kf; *p; p++)
+ if (*p == ',')
+ n++;
+ size = n;
+ pts = av_malloc_array(size, sizeof(*pts));
+ if (!pts) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate forced key frames array.\n");
+ exit_program(1);
+ }
+
+ p = kf;
+ for (i = 0; i < n; i++) {
+ char *next = strchr(p, ',');
+
+ if (next)
+ *next++ = 0;
+
+ if (!memcmp(p, "chapters", 8)) {
+
+ AVFormatContext *avf = output_files[ost->file_index]->ctx;
+ int j;
+
+ if (avf->nb_chapters > INT_MAX - size ||
+ !(pts = av_realloc_f(pts, size += avf->nb_chapters - 1,
+ sizeof(*pts)))) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Could not allocate forced key frames array.\n");
+ exit_program(1);
+ }
+ t = p[8] ? parse_time_or_die("force_key_frames", p + 8, 1) : 0;
+ t = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
+
+ for (j = 0; j < avf->nb_chapters; j++) {
+ AVChapter *c = avf->chapters[j];
+ av_assert1(index < size);
+ pts[index++] = av_rescale_q(c->start, c->time_base,
+ avctx->time_base) + t;
+ }
+
+ } else {
+
+ t = parse_time_or_die("force_key_frames", p, 1);
+ av_assert1(index < size);
+ pts[index++] = av_rescale_q(t, AV_TIME_BASE_Q, avctx->time_base);
+
+ }
+
+ p = next;
+ }
+
+ av_assert0(index == size);
+ qsort(pts, size, sizeof(*pts), compare_int64);
+ ost->forced_kf_count = size;
+ ost->forced_kf_pts = pts;
+}
+
+static void report_new_stream(int input_index, AVPacket *pkt)
+{
+ InputFile *file = input_files[input_index];
+ AVStream *st = file->ctx->streams[pkt->stream_index];
+
+ if (pkt->stream_index < file->nb_streams_warn)
+ return;
+ av_log(file->ctx, AV_LOG_WARNING,
+ "New %s stream %d:%d at pos:%"PRId64" and DTS:%ss\n",
+ av_get_media_type_string(st->codec->codec_type),
+ input_index, pkt->stream_index,
+ pkt->pos, av_ts2timestr(pkt->dts, &st->time_base));
+ file->nb_streams_warn = pkt->stream_index + 1;
+}
+
+static void set_encoder_id(OutputFile *of, OutputStream *ost)
+{
+ AVDictionaryEntry *e;
+
+ uint8_t *encoder_string;
+ int encoder_string_len;
+ int format_flags = 0;
+ int codec_flags = 0;
+
+ if (av_dict_get(ost->st->metadata, "encoder", NULL, 0))
+ return;
+
+ e = av_dict_get(of->opts, "fflags", NULL, 0);
+ if (e) {
+ const AVOption *o = av_opt_find(of->ctx, "fflags", NULL, 0, 0);
+ if (!o)
+ return;
+ av_opt_eval_flags(of->ctx, o, e->value, &format_flags);
+ }
+ e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
+ if (e) {
+ const AVOption *o = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
+ if (!o)
+ return;
+ av_opt_eval_flags(ost->enc_ctx, o, e->value, &codec_flags);
+ }
+
+ encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(ost->enc->name) + 2;
+ encoder_string = av_mallocz(encoder_string_len);
+ if (!encoder_string)
+ exit_program(1);
+
+ if (!(format_flags & AVFMT_FLAG_BITEXACT) && !(codec_flags & CODEC_FLAG_BITEXACT))
+ av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len);
+ else
+ av_strlcpy(encoder_string, "Lavc ", encoder_string_len);
+ av_strlcat(encoder_string, ost->enc->name, encoder_string_len);
+ av_dict_set(&ost->st->metadata, "encoder", encoder_string,
+ AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE);
+}
+
+static int transcode_init(void)
+{
+ int ret = 0, i, j, k;
+ AVFormatContext *oc;
+ OutputStream *ost;
+ InputStream *ist;
+ char error[1024] = {0};
+ int want_sdp = 1;
+
+ for (i = 0; i < nb_filtergraphs; i++) {
+ FilterGraph *fg = filtergraphs[i];
+ for (j = 0; j < fg->nb_outputs; j++) {
+ OutputFilter *ofilter = fg->outputs[j];
+ if (!ofilter->ost || ofilter->ost->source_index >= 0)
+ continue;
+ if (fg->nb_inputs != 1)
+ continue;
+ for (k = nb_input_streams-1; k >= 0 ; k--)
+ if (fg->inputs[0]->ist == input_streams[k])
+ break;
+ ofilter->ost->source_index = k;
+ }
+ }
+
+ /* init framerate emulation */
+ for (i = 0; i < nb_input_files; i++) {
+ InputFile *ifile = input_files[i];
+ if (ifile->rate_emu)
+ for (j = 0; j < ifile->nb_streams; j++)
+ input_streams[j + ifile->ist_index]->start = av_gettime_relative();
+ }
+
+ /* output stream init */
+ for (i = 0; i < nb_output_files; i++) {
+ oc = output_files[i]->ctx;
+ if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) {
+ av_dump_format(oc, i, oc->filename, 1);
+ av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", i);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ /* init complex filtergraphs */
+ for (i = 0; i < nb_filtergraphs; i++)
+ if ((ret = avfilter_graph_config(filtergraphs[i]->graph, NULL)) < 0)
+ return ret;
+
+ /* for each output stream, we compute the right encoding parameters */
+ for (i = 0; i < nb_output_streams; i++) {
+ AVCodecContext *enc_ctx;
+ AVCodecContext *dec_ctx = NULL;
+ ost = output_streams[i];
+ oc = output_files[ost->file_index]->ctx;
+ ist = get_input_stream(ost);
+
+ if (ost->attachment_filename)
+ continue;
+
+ enc_ctx = ost->stream_copy ? ost->st->codec : ost->enc_ctx;
+
+ if (ist) {
+ dec_ctx = ist->dec_ctx;
+
+ ost->st->disposition = ist->st->disposition;
+ enc_ctx->bits_per_raw_sample = dec_ctx->bits_per_raw_sample;
+ enc_ctx->chroma_sample_location = dec_ctx->chroma_sample_location;
+ } else {
+ for (j=0; j<oc->nb_streams; j++) {
+ AVStream *st = oc->streams[j];
+ if (st != ost->st && st->codec->codec_type == enc_ctx->codec_type)
+ break;
+ }
+ if (j == oc->nb_streams)
+ if (enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO || enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ ost->st->disposition = AV_DISPOSITION_DEFAULT;
+ }
+
+ if (ost->stream_copy) {
+ AVRational sar;
+ uint64_t extra_size;
+
+ av_assert0(ist && !ost->filter);
+
+ extra_size = (uint64_t)dec_ctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE;
+
+ if (extra_size > INT_MAX) {
+ return AVERROR(EINVAL);
+ }
+
+ /* if stream_copy is selected, no need to decode or encode */
+ enc_ctx->codec_id = dec_ctx->codec_id;
+ enc_ctx->codec_type = dec_ctx->codec_type;
+
+ if (!enc_ctx->codec_tag) {
+ unsigned int codec_tag;
+ if (!oc->oformat->codec_tag ||
+ av_codec_get_id (oc->oformat->codec_tag, dec_ctx->codec_tag) == enc_ctx->codec_id ||
+ !av_codec_get_tag2(oc->oformat->codec_tag, dec_ctx->codec_id, &codec_tag))
+ enc_ctx->codec_tag = dec_ctx->codec_tag;
+ }
+
+ enc_ctx->bit_rate = dec_ctx->bit_rate;
+ enc_ctx->rc_max_rate = dec_ctx->rc_max_rate;
+ enc_ctx->rc_buffer_size = dec_ctx->rc_buffer_size;
+ enc_ctx->field_order = dec_ctx->field_order;
+ if (dec_ctx->extradata_size) {
+ enc_ctx->extradata = av_mallocz(extra_size);
+ if (!enc_ctx->extradata) {
+ return AVERROR(ENOMEM);
+ }
+ memcpy(enc_ctx->extradata, dec_ctx->extradata, dec_ctx->extradata_size);
+ }
+ enc_ctx->extradata_size= dec_ctx->extradata_size;
+ enc_ctx->bits_per_coded_sample = dec_ctx->bits_per_coded_sample;
+
+ enc_ctx->time_base = ist->st->time_base;
+ /*
+ * Avi is a special case here because it supports variable fps but
+ * having the fps and timebase differe significantly adds quite some
+ * overhead
+ */
+ if(!strcmp(oc->oformat->name, "avi")) {
+ if ( copy_tb<0 && av_q2d(ist->st->r_frame_rate) >= av_q2d(ist->st->avg_frame_rate)
+ && 0.5/av_q2d(ist->st->r_frame_rate) > av_q2d(ist->st->time_base)
+ && 0.5/av_q2d(ist->st->r_frame_rate) > av_q2d(dec_ctx->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500 && av_q2d(dec_ctx->time_base) < 1.0/500
+ || copy_tb==2){
+ enc_ctx->time_base.num = ist->st->r_frame_rate.den;
+ enc_ctx->time_base.den = 2*ist->st->r_frame_rate.num;
+ enc_ctx->ticks_per_frame = 2;
+ } else if ( copy_tb<0 && av_q2d(dec_ctx->time_base)*dec_ctx->ticks_per_frame > 2*av_q2d(ist->st->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500
+ || copy_tb==0){
+ enc_ctx->time_base = dec_ctx->time_base;
+ enc_ctx->time_base.num *= dec_ctx->ticks_per_frame;
+ enc_ctx->time_base.den *= 2;
+ enc_ctx->ticks_per_frame = 2;
+ }
+ } else if(!(oc->oformat->flags & AVFMT_VARIABLE_FPS)
+ && strcmp(oc->oformat->name, "mov") && strcmp(oc->oformat->name, "mp4") && strcmp(oc->oformat->name, "3gp")
+ && strcmp(oc->oformat->name, "3g2") && strcmp(oc->oformat->name, "psp") && strcmp(oc->oformat->name, "ipod")
+ && strcmp(oc->oformat->name, "f4v")
+ ) {
+ if( copy_tb<0 && dec_ctx->time_base.den
+ && av_q2d(dec_ctx->time_base)*dec_ctx->ticks_per_frame > av_q2d(ist->st->time_base)
+ && av_q2d(ist->st->time_base) < 1.0/500
+ || copy_tb==0){
+ enc_ctx->time_base = dec_ctx->time_base;
+ enc_ctx->time_base.num *= dec_ctx->ticks_per_frame;
+ }
+ }
+ if ( enc_ctx->codec_tag == AV_RL32("tmcd")
+ && dec_ctx->time_base.num < dec_ctx->time_base.den
+ && dec_ctx->time_base.num > 0
+ && 121LL*dec_ctx->time_base.num > dec_ctx->time_base.den) {
+ enc_ctx->time_base = dec_ctx->time_base;
+ }
+
+ if (ist && !ost->frame_rate.num)
+ ost->frame_rate = ist->framerate;
+ if(ost->frame_rate.num)
+ enc_ctx->time_base = av_inv_q(ost->frame_rate);
+
+ av_reduce(&enc_ctx->time_base.num, &enc_ctx->time_base.den,
+ enc_ctx->time_base.num, enc_ctx->time_base.den, INT_MAX);
+
+ if (ist->st->nb_side_data) {
+ ost->st->side_data = av_realloc_array(NULL, ist->st->nb_side_data,
+ sizeof(*ist->st->side_data));
+ if (!ost->st->side_data)
+ return AVERROR(ENOMEM);
+
+ ost->st->nb_side_data = 0;
+ for (j = 0; j < ist->st->nb_side_data; j++) {
+ const AVPacketSideData *sd_src = &ist->st->side_data[j];
+ AVPacketSideData *sd_dst = &ost->st->side_data[ost->st->nb_side_data];
+
+ if (ost->rotate_overridden && sd_src->type == AV_PKT_DATA_DISPLAYMATRIX)
+ continue;
+
+ sd_dst->data = av_malloc(sd_src->size);
+ if (!sd_dst->data)
+ return AVERROR(ENOMEM);
+ memcpy(sd_dst->data, sd_src->data, sd_src->size);
+ sd_dst->size = sd_src->size;
+ sd_dst->type = sd_src->type;
+ ost->st->nb_side_data++;
+ }
+ }
+
+ ost->parser = av_parser_init(enc_ctx->codec_id);
+
+ switch (enc_ctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (audio_volume != 256) {
+ av_log(NULL, AV_LOG_FATAL, "-acodec copy and -vol are incompatible (frames are not decoded)\n");
+ exit_program(1);
+ }
+ enc_ctx->channel_layout = dec_ctx->channel_layout;
+ enc_ctx->sample_rate = dec_ctx->sample_rate;
+ enc_ctx->channels = dec_ctx->channels;
+ enc_ctx->frame_size = dec_ctx->frame_size;
+ enc_ctx->audio_service_type = dec_ctx->audio_service_type;
+ enc_ctx->block_align = dec_ctx->block_align;
+ enc_ctx->initial_padding = dec_ctx->delay;
+#if FF_API_AUDIOENC_DELAY
+ enc_ctx->delay = dec_ctx->delay;
+#endif
+ if((enc_ctx->block_align == 1 || enc_ctx->block_align == 1152 || enc_ctx->block_align == 576) && enc_ctx->codec_id == AV_CODEC_ID_MP3)
+ enc_ctx->block_align= 0;
+ if(enc_ctx->codec_id == AV_CODEC_ID_AC3)
+ enc_ctx->block_align= 0;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ enc_ctx->pix_fmt = dec_ctx->pix_fmt;
+ enc_ctx->width = dec_ctx->width;
+ enc_ctx->height = dec_ctx->height;
+ enc_ctx->has_b_frames = dec_ctx->has_b_frames;
+ if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option
+ sar =
+ av_mul_q(ost->frame_aspect_ratio,
+ (AVRational){ enc_ctx->height, enc_ctx->width });
+ av_log(NULL, AV_LOG_WARNING, "Overriding aspect ratio "
+ "with stream copy may produce invalid files\n");
+ }
+ else if (ist->st->sample_aspect_ratio.num)
+ sar = ist->st->sample_aspect_ratio;
+ else
+ sar = dec_ctx->sample_aspect_ratio;
+ ost->st->sample_aspect_ratio = enc_ctx->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;
+ case AVMEDIA_TYPE_SUBTITLE:
+ enc_ctx->width = dec_ctx->width;
+ enc_ctx->height = dec_ctx->height;
+ break;
+ case AVMEDIA_TYPE_UNKNOWN:
+ case AVMEDIA_TYPE_DATA:
+ case AVMEDIA_TYPE_ATTACHMENT:
+ break;
+ default:
+ abort();
+ }
+ } else {
+ if (!ost->enc)
+ ost->enc = avcodec_find_encoder(enc_ctx->codec_id);
+ if (!ost->enc) {
+ /* should only happen when a default codec is not present. */
+ snprintf(error, sizeof(error), "Encoder (codec %s) not found for output stream #%d:%d",
+ avcodec_get_name(ost->st->codec->codec_id), ost->file_index, ost->index);
+ ret = AVERROR(EINVAL);
+ goto dump_format;
+ }
+
+ if (ist)
+ ist->decoding_needed |= DECODING_FOR_OST;
+ ost->encoding_needed = 1;
+
+ set_encoder_id(output_files[ost->file_index], ost);
+
+ if (!ost->filter &&
+ (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO)) {
+ FilterGraph *fg;
+ fg = init_simple_filtergraph(ist, ost);
+ if (configure_filtergraph(fg)) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening filters!\n");
+ exit_program(1);
+ }
+ }
+
+ if (enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (!ost->frame_rate.num)
+ ost->frame_rate = av_buffersink_get_frame_rate(ost->filter->filter);
+ if (ist && !ost->frame_rate.num)
+ ost->frame_rate = ist->framerate;
+ if (ist && !ost->frame_rate.num)
+ ost->frame_rate = ist->st->r_frame_rate;
+ if (ist && !ost->frame_rate.num) {
+ ost->frame_rate = (AVRational){25, 1};
+ av_log(NULL, AV_LOG_WARNING,
+ "No information "
+ "about the input framerate is available. Falling "
+ "back to a default value of 25fps for output stream #%d:%d. Use the -r option "
+ "if you want a different framerate.\n",
+ ost->file_index, ost->index);
+ }
+// ost->frame_rate = ist->st->avg_frame_rate.num ? ist->st->avg_frame_rate : (AVRational){25, 1};
+ if (ost->enc && ost->enc->supported_framerates && !ost->force_fps) {
+ int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates);
+ ost->frame_rate = ost->enc->supported_framerates[idx];
+ }
+ // reduce frame rate for mpeg4 to be within the spec limits
+ if (enc_ctx->codec_id == AV_CODEC_ID_MPEG4) {
+ av_reduce(&ost->frame_rate.num, &ost->frame_rate.den,
+ ost->frame_rate.num, ost->frame_rate.den, 65535);
+ }
+ }
+
+ switch (enc_ctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ enc_ctx->sample_fmt = ost->filter->filter->inputs[0]->format;
+ enc_ctx->sample_rate = ost->filter->filter->inputs[0]->sample_rate;
+ enc_ctx->channel_layout = ost->filter->filter->inputs[0]->channel_layout;
+ enc_ctx->channels = avfilter_link_get_channels(ost->filter->filter->inputs[0]);
+ enc_ctx->time_base = (AVRational){ 1, enc_ctx->sample_rate };
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ enc_ctx->time_base = av_inv_q(ost->frame_rate);
+ if (!(enc_ctx->time_base.num && enc_ctx->time_base.den))
+ enc_ctx->time_base = ost->filter->filter->inputs[0]->time_base;
+ if ( av_q2d(enc_ctx->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH
+ && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR || (video_sync_method == VSYNC_AUTO && !(oc->oformat->flags & AVFMT_VARIABLE_FPS)))){
+ av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
+ "Please consider specifying a lower framerate, a different muxer or -vsync 2\n");
+ }
+ for (j = 0; j < ost->forced_kf_count; j++)
+ ost->forced_kf_pts[j] = av_rescale_q(ost->forced_kf_pts[j],
+ AV_TIME_BASE_Q,
+ enc_ctx->time_base);
+
+ enc_ctx->width = ost->filter->filter->inputs[0]->w;
+ enc_ctx->height = ost->filter->filter->inputs[0]->h;
+ enc_ctx->sample_aspect_ratio = ost->st->sample_aspect_ratio =
+ ost->frame_aspect_ratio.num ? // overridden by the -aspect cli option
+ av_mul_q(ost->frame_aspect_ratio, (AVRational){ enc_ctx->height, enc_ctx->width }) :
+ ost->filter->filter->inputs[0]->sample_aspect_ratio;
+ if (!strncmp(ost->enc->name, "libx264", 7) &&
+ enc_ctx->pix_fmt == AV_PIX_FMT_NONE &&
+ ost->filter->filter->inputs[0]->format != AV_PIX_FMT_YUV420P)
+ av_log(NULL, AV_LOG_WARNING,
+ "No pixel format specified, %s for H.264 encoding chosen.\n"
+ "Use -pix_fmt yuv420p for compatibility with outdated media players.\n",
+ av_get_pix_fmt_name(ost->filter->filter->inputs[0]->format));
+ if (!strncmp(ost->enc->name, "mpeg2video", 10) &&
+ enc_ctx->pix_fmt == AV_PIX_FMT_NONE &&
+ ost->filter->filter->inputs[0]->format != AV_PIX_FMT_YUV420P)
+ av_log(NULL, AV_LOG_WARNING,
+ "No pixel format specified, %s for MPEG-2 encoding chosen.\n"
+ "Use -pix_fmt yuv420p for compatibility with outdated media players.\n",
+ av_get_pix_fmt_name(ost->filter->filter->inputs[0]->format));
+ enc_ctx->pix_fmt = ost->filter->filter->inputs[0]->format;
+
+ ost->st->avg_frame_rate = ost->frame_rate;
+
+ if (!dec_ctx ||
+ enc_ctx->width != dec_ctx->width ||
+ enc_ctx->height != dec_ctx->height ||
+ enc_ctx->pix_fmt != dec_ctx->pix_fmt) {
+ enc_ctx->bits_per_raw_sample = frame_bits_per_raw_sample;
+ }
+
+ if (ost->forced_keyframes) {
+ if (!strncmp(ost->forced_keyframes, "expr:", 5)) {
+ ret = av_expr_parse(&ost->forced_keyframes_pexpr, ost->forced_keyframes+5,
+ forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid force_key_frames expression '%s'\n", ost->forced_keyframes+5);
+ return ret;
+ }
+ ost->forced_keyframes_expr_const_values[FKF_N] = 0;
+ ost->forced_keyframes_expr_const_values[FKF_N_FORCED] = 0;
+ ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = NAN;
+ ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = NAN;
+
+ // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes',
+ // parse it only for static kf timings
+ } else if(strncmp(ost->forced_keyframes, "source", 6)) {
+ parse_forced_key_frames(ost->forced_keyframes, ost, ost->enc_ctx);
+ }
+ }
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ enc_ctx->time_base = (AVRational){1, 1000};
+ if (!enc_ctx->width) {
+ enc_ctx->width = input_streams[ost->source_index]->st->codec->width;
+ enc_ctx->height = input_streams[ost->source_index]->st->codec->height;
+ }
+ break;
+ case AVMEDIA_TYPE_DATA:
+ break;
+ default:
+ abort();
+ break;
+ }
+ /* two pass mode */
+ if (enc_ctx->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2)) {
+ char logfilename[1024];
+ FILE *f;
+
+ snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
+ ost->logfile_prefix ? ost->logfile_prefix :
+ DEFAULT_PASS_LOGFILENAME_PREFIX,
+ i);
+ if (!strcmp(ost->enc->name, "libx264")) {
+ av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
+ } else {
+ if (enc_ctx->flags & CODEC_FLAG_PASS2) {
+ char *logbuffer;
+ size_t logbuffer_size;
+ if (cmdutils_read_file(logfilename, &logbuffer, &logbuffer_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n",
+ logfilename);
+ exit_program(1);
+ }
+ enc_ctx->stats_in = logbuffer;
+ }
+ if (enc_ctx->flags & CODEC_FLAG_PASS1) {
+ f = av_fopen_utf8(logfilename, "wb");
+ if (!f) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot write log file '%s' for pass-1 encoding: %s\n",
+ logfilename, strerror(errno));
+ exit_program(1);
+ }
+ ost->logfile = f;
+ }
+ }
+ }
+ }
+
+ if (ost->disposition) {
+ static const AVOption opts[] = {
+ { "disposition" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
+ { "default" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEFAULT }, .unit = "flags" },
+ { "dub" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DUB }, .unit = "flags" },
+ { "original" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_ORIGINAL }, .unit = "flags" },
+ { "comment" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_COMMENT }, .unit = "flags" },
+ { "lyrics" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_LYRICS }, .unit = "flags" },
+ { "karaoke" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_KARAOKE }, .unit = "flags" },
+ { "forced" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_FORCED }, .unit = "flags" },
+ { "hearing_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_HEARING_IMPAIRED }, .unit = "flags" },
+ { "visual_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_VISUAL_IMPAIRED }, .unit = "flags" },
+ { "clean_effects" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CLEAN_EFFECTS }, .unit = "flags" },
+ { "captions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, .unit = "flags" },
+ { "descriptions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, .unit = "flags" },
+ { "metadata" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, .unit = "flags" },
+ { NULL },
+ };
+ static const AVClass class = {
+ .class_name = "",
+ .item_name = av_default_item_name,
+ .option = opts,
+ .version = LIBAVUTIL_VERSION_INT,
+ };
+ const AVClass *pclass = &class;
+
+ ret = av_opt_eval_flags(&pclass, &opts[0], ost->disposition, &ost->st->disposition);
+ if (ret < 0)
+ goto dump_format;
+ }
+ }
+
+ /* open each encoder */
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = output_streams[i];
+ if (ost->encoding_needed) {
+ AVCodec *codec = ost->enc;
+ AVCodecContext *dec = NULL;
+
+ if ((ist = get_input_stream(ost)))
+ dec = ist->dec_ctx;
+ if (dec && dec->subtitle_header) {
+ /* ASS code assumes this buffer is null terminated so add extra byte. */
+ ost->enc_ctx->subtitle_header = av_mallocz(dec->subtitle_header_size + 1);
+ if (!ost->enc_ctx->subtitle_header) {
+ ret = AVERROR(ENOMEM);
+ goto dump_format;
+ }
+ memcpy(ost->enc_ctx->subtitle_header, dec->subtitle_header, dec->subtitle_header_size);
+ ost->enc_ctx->subtitle_header_size = dec->subtitle_header_size;
+ }
+ if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
+ av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
+ av_dict_set(&ost->encoder_opts, "side_data_only_packets", "1", 0);
+
+ if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) {
+ if (ret == AVERROR_EXPERIMENTAL)
+ abort_codec_experimental(codec, 1);
+ snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d:%d - maybe incorrect parameters such as bit_rate, rate, width or height",
+ ost->file_index, ost->index);
+ goto dump_format;
+ }
+ if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
+ !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE))
+ av_buffersink_set_frame_size(ost->filter->filter,
+ ost->enc_ctx->frame_size);
+ assert_avoptions(ost->encoder_opts);
+ if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000)
+ av_log(NULL, AV_LOG_WARNING, "The bitrate parameter is set too low."
+ " It takes bits/s as argument, not kbits/s\n");
+
+ ret = avcodec_copy_context(ost->st->codec, ost->enc_ctx);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Error initializing the output stream codec context.\n");
+ exit_program(1);
+ }
+
+ // copy timebase while removing common factors
+ ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
+ ost->st->codec->codec= ost->enc_ctx->codec;
+ } else {
+ ret = av_opt_set_dict(ost->enc_ctx, &ost->encoder_opts);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Error setting up codec context options.\n");
+ return ret;
+ }
+ // copy timebase while removing common factors
+ ost->st->time_base = av_add_q(ost->st->codec->time_base, (AVRational){0, 1});
+ }
+ }
+
+ /* init input streams */
+ for (i = 0; i < nb_input_streams; i++)
+ if ((ret = init_input_stream(i, error, sizeof(error))) < 0) {
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = output_streams[i];
+ avcodec_close(ost->enc_ctx);
+ }
+ goto dump_format;
+ }
+
+ /* discard unused programs */
+ for (i = 0; i < nb_input_files; i++) {
+ InputFile *ifile = input_files[i];
+ for (j = 0; j < ifile->ctx->nb_programs; j++) {
+ AVProgram *p = ifile->ctx->programs[j];
+ int discard = AVDISCARD_ALL;
+
+ for (k = 0; k < p->nb_stream_indexes; k++)
+ if (!input_streams[ifile->ist_index + p->stream_index[k]]->discard) {
+ discard = AVDISCARD_DEFAULT;
+ break;
+ }
+ p->discard = discard;
+ }
+ }
+
+ /* open files and write file headers */
+ for (i = 0; i < nb_output_files; i++) {
+ oc = output_files[i]->ctx;
+ oc->interrupt_callback = int_cb;
+ if ((ret = avformat_write_header(oc, &output_files[i]->opts)) < 0) {
+ snprintf(error, sizeof(error),
+ "Could not write header for output file #%d "
+ "(incorrect codec parameters ?): %s",
+ i, av_err2str(ret));
+ ret = AVERROR(EINVAL);
+ goto dump_format;
+ }
+// assert_avoptions(output_files[i]->opts);
+ if (strcmp(oc->oformat->name, "rtp")) {
+ want_sdp = 0;
+ }
+ }
+
+ dump_format:
+ /* dump the file output parameters - cannot be done before in case
+ of stream copy */
+ for (i = 0; i < nb_output_files; i++) {
+ av_dump_format(output_files[i]->ctx, i, output_files[i]->ctx->filename, 1);
+ }
+
+ /* dump the stream mapping */
+ av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+
+ for (j = 0; j < ist->nb_filters; j++) {
+ if (ist->filters[j]->graph->graph_desc) {
+ av_log(NULL, AV_LOG_INFO, " Stream #%d:%d (%s) -> %s",
+ ist->file_index, ist->st->index, ist->dec ? ist->dec->name : "?",
+ ist->filters[j]->name);
+ if (nb_filtergraphs > 1)
+ av_log(NULL, AV_LOG_INFO, " (graph %d)", ist->filters[j]->graph->index);
+ av_log(NULL, AV_LOG_INFO, "\n");
+ }
+ }
+ }
+
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = output_streams[i];
+
+ if (ost->attachment_filename) {
+ /* an attached file */
+ av_log(NULL, AV_LOG_INFO, " File %s -> Stream #%d:%d\n",
+ ost->attachment_filename, ost->file_index, ost->index);
+ continue;
+ }
+
+ if (ost->filter && ost->filter->graph->graph_desc) {
+ /* output from a complex graph */
+ av_log(NULL, AV_LOG_INFO, " %s", ost->filter->name);
+ if (nb_filtergraphs > 1)
+ av_log(NULL, AV_LOG_INFO, " (graph %d)", ost->filter->graph->index);
+
+ av_log(NULL, AV_LOG_INFO, " -> Stream #%d:%d (%s)\n", ost->file_index,
+ ost->index, ost->enc ? ost->enc->name : "?");
+ continue;
+ }
+
+ av_log(NULL, AV_LOG_INFO, " Stream #%d:%d -> #%d:%d",
+ input_streams[ost->source_index]->file_index,
+ input_streams[ost->source_index]->st->index,
+ ost->file_index,
+ ost->index);
+ if (ost->sync_ist != input_streams[ost->source_index])
+ av_log(NULL, AV_LOG_INFO, " [sync #%d:%d]",
+ ost->sync_ist->file_index,
+ ost->sync_ist->st->index);
+ if (ost->stream_copy)
+ av_log(NULL, AV_LOG_INFO, " (copy)");
+ else {
+ const AVCodec *in_codec = input_streams[ost->source_index]->dec;
+ const AVCodec *out_codec = ost->enc;
+ const char *decoder_name = "?";
+ const char *in_codec_name = "?";
+ const char *encoder_name = "?";
+ const char *out_codec_name = "?";
+ const AVCodecDescriptor *desc;
+
+ if (in_codec) {
+ decoder_name = in_codec->name;
+ desc = avcodec_descriptor_get(in_codec->id);
+ if (desc)
+ in_codec_name = desc->name;
+ if (!strcmp(decoder_name, in_codec_name))
+ decoder_name = "native";
+ }
+
+ if (out_codec) {
+ encoder_name = out_codec->name;
+ desc = avcodec_descriptor_get(out_codec->id);
+ if (desc)
+ out_codec_name = desc->name;
+ if (!strcmp(encoder_name, out_codec_name))
+ encoder_name = "native";
+ }
+
+ av_log(NULL, AV_LOG_INFO, " (%s (%s) -> %s (%s))",
+ in_codec_name, decoder_name,
+ out_codec_name, encoder_name);
+ }
+ av_log(NULL, AV_LOG_INFO, "\n");
+ }
+
+ if (ret) {
+ av_log(NULL, AV_LOG_ERROR, "%s\n", error);
+ return ret;
+ }
+
+ if (sdp_filename || want_sdp) {
+ print_sdp();
+ }
+
+ transcode_init_done = 1;
+
+ return 0;
+}
+
+/* Return 1 if there remain streams where more output is wanted, 0 otherwise. */
+static int need_output(void)
+{
+ int i;
+
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ OutputFile *of = output_files[ost->file_index];
+ AVFormatContext *os = output_files[ost->file_index]->ctx;
+
+ if (ost->finished ||
+ (os->pb && avio_tell(os->pb) >= of->limit_filesize))
+ continue;
+ if (ost->frame_number >= ost->max_frames) {
+ int j;
+ for (j = 0; j < of->ctx->nb_streams; j++)
+ close_output_stream(output_streams[of->ost_index + j]);
+ continue;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Select the output stream to process.
+ *
+ * @return selected output stream, or NULL if none available
+ */
+static OutputStream *choose_output(void)
+{
+ int i;
+ int64_t opts_min = INT64_MAX;
+ OutputStream *ost_min = NULL;
+
+ for (i = 0; i < nb_output_streams; i++) {
+ OutputStream *ost = output_streams[i];
+ int64_t opts = av_rescale_q(ost->st->cur_dts, ost->st->time_base,
+ AV_TIME_BASE_Q);
+ if (!ost->finished && opts < opts_min) {
+ opts_min = opts;
+ ost_min = ost->unavailable ? NULL : ost;
+ }
+ }
+ return ost_min;
+}
+
+static int check_keyboard_interaction(int64_t cur_time)
+{
+ int i, ret, key;
+ static int64_t last_time;
+ if (received_nb_signals)
+ return AVERROR_EXIT;
+ /* read_key() returns 0 on EOF */
+ if(cur_time - last_time >= 100000 && !run_as_daemon){
+ key = read_key();
+ last_time = cur_time;
+ }else
+ key = -1;
+ if (key == 'q')
+ return AVERROR_EXIT;
+ if (key == '+') av_log_set_level(av_log_get_level()+10);
+ if (key == '-') av_log_set_level(av_log_get_level()-10);
+ if (key == 's') qp_hist ^= 1;
+ if (key == 'h'){
+ if (do_hex_dump){
+ do_hex_dump = do_pkt_dump = 0;
+ } else if(do_pkt_dump){
+ do_hex_dump = 1;
+ } else
+ do_pkt_dump = 1;
+ av_log_set_level(AV_LOG_DEBUG);
+ }
+ if (key == 'c' || key == 'C'){
+ char buf[4096], target[64], command[256], arg[256] = {0};
+ double time;
+ int k, n = 0;
+ fprintf(stderr, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
+ i = 0;
+ while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)
+ if (k > 0)
+ buf[i++] = k;
+ buf[i] = 0;
+ if (k > 0 &&
+ (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 (i = 0; i < nb_filtergraphs; i++) {
+ FilterGraph *fg = filtergraphs[i];
+ if (fg->graph) {
+ if (time < 0) {
+ ret = avfilter_graph_send_command(fg->graph, target, command, arg, buf, sizeof(buf),
+ key == 'c' ? AVFILTER_CMD_FLAG_ONE : 0);
+ fprintf(stderr, "Command reply for stream %d: ret:%d res:\n%s", i, ret, buf);
+ } else if (key == 'c') {
+ fprintf(stderr, "Queing commands only on filters supporting the specific command is unsupported\n");
+ ret = AVERROR_PATCHWELCOME;
+ } else {
+ ret = avfilter_graph_queue_command(fg->graph, target, command, arg, 0, time);
+ if (ret < 0)
+ fprintf(stderr, "Queing command failed with error %s\n", av_err2str(ret));
+ }
+ }
+ }
+ } else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Parse error, at least 3 arguments were expected, "
+ "only %d given in string '%s'\n", n, buf);
+ }
+ }
+ if (key == 'd' || key == 'D'){
+ int debug=0;
+ if(key == 'D') {
+ debug = input_streams[0]->st->codec->debug<<1;
+ if(!debug) debug = 1;
+ while(debug & (FF_DEBUG_DCT_COEFF|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) //unsupported, would just crash
+ debug += debug;
+ }else
+ if(scanf("%d", &debug)!=1)
+ fprintf(stderr,"error parsing debug value\n");
+ for(i=0;i<nb_input_streams;i++) {
+ input_streams[i]->st->codec->debug = debug;
+ }
+ for(i=0;i<nb_output_streams;i++) {
+ OutputStream *ost = output_streams[i];
+ ost->enc_ctx->debug = debug;
+ }
+ if(debug) av_log_set_level(AV_LOG_DEBUG);
+ fprintf(stderr,"debug=%d\n", debug);
+ }
+ if (key == '?'){
+ fprintf(stderr, "key function\n"
+ "? show this help\n"
+ "+ increase verbosity\n"
+ "- decrease verbosity\n"
+ "c Send command to first matching filter supporting it\n"
+ "C Send/Que command to all matching filters\n"
+ "D cycle through available debug modes\n"
+ "h dump packets/hex press to cycle through the 3 states\n"
+ "q quit\n"
+ "s Show QP histogram\n"
+ );
+ }
+ return 0;
+}
+
+#if HAVE_PTHREADS
+static void *input_thread(void *arg)
+{
+ InputFile *f = arg;
+ unsigned flags = f->non_blocking ? AV_THREAD_MESSAGE_NONBLOCK : 0;
+ int ret = 0;
+
+ while (1) {
+ AVPacket pkt;
+ ret = av_read_frame(f->ctx, &pkt);
+
+ if (ret == AVERROR(EAGAIN)) {
+ av_usleep(10000);
+ continue;
+ }
+ if (ret < 0) {
+ av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
+ break;
+ }
+ av_dup_packet(&pkt);
+ ret = av_thread_message_queue_send(f->in_thread_queue, &pkt, flags);
+ if (flags && ret == AVERROR(EAGAIN)) {
+ flags = 0;
+ ret = av_thread_message_queue_send(f->in_thread_queue, &pkt, flags);
+ av_log(f->ctx, AV_LOG_WARNING,
+ "Thread message queue blocking; consider raising the "
+ "thread_queue_size option (current value: %d)\n",
+ f->thread_queue_size);
+ }
+ if (ret < 0) {
+ if (ret != AVERROR_EOF)
+ av_log(f->ctx, AV_LOG_ERROR,
+ "Unable to send packet to main thread: %s\n",
+ av_err2str(ret));
+ av_free_packet(&pkt);
+ av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static void free_input_threads(void)
+{
+ int i;
+
+ for (i = 0; i < nb_input_files; i++) {
+ InputFile *f = input_files[i];
+ AVPacket pkt;
+
+ if (!f->in_thread_queue)
+ continue;
+ av_thread_message_queue_set_err_send(f->in_thread_queue, AVERROR_EOF);
+ while (av_thread_message_queue_recv(f->in_thread_queue, &pkt, 0) >= 0)
+ av_free_packet(&pkt);
+
+ pthread_join(f->thread, NULL);
+ f->joined = 1;
+ av_thread_message_queue_free(&f->in_thread_queue);
+ }
+}
+
+static int init_input_threads(void)
+{
+ int i, ret;
+
+ if (nb_input_files == 1)
+ return 0;
+
+ for (i = 0; i < nb_input_files; i++) {
+ InputFile *f = input_files[i];
+
+ if (f->ctx->pb ? !f->ctx->pb->seekable :
+ strcmp(f->ctx->iformat->name, "lavfi"))
+ f->non_blocking = 1;
+ ret = av_thread_message_queue_alloc(&f->in_thread_queue,
+ f->thread_queue_size, sizeof(AVPacket));
+ if (ret < 0)
+ return ret;
+
+ if ((ret = pthread_create(&f->thread, NULL, input_thread, f))) {
+ av_log(NULL, AV_LOG_ERROR, "pthread_create failed: %s. Try to increase `ulimit -v` or decrease `ulimit -s`.\n", strerror(ret));
+ av_thread_message_queue_free(&f->in_thread_queue);
+ return AVERROR(ret);
+ }
+ }
+ return 0;
+}
+
+static int get_input_packet_mt(InputFile *f, AVPacket *pkt)
+{
+ return av_thread_message_queue_recv(f->in_thread_queue, pkt,
+ f->non_blocking ?
+ AV_THREAD_MESSAGE_NONBLOCK : 0);
+}
+#endif
+
+static int get_input_packet(InputFile *f, AVPacket *pkt)
+{
+ if (f->rate_emu) {
+ int i;
+ for (i = 0; i < f->nb_streams; i++) {
+ InputStream *ist = input_streams[f->ist_index + i];
+ int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
+ int64_t now = av_gettime_relative() - ist->start;
+ if (pts > now)
+ return AVERROR(EAGAIN);
+ }
+ }
+
+#if HAVE_PTHREADS
+ if (nb_input_files > 1)
+ return get_input_packet_mt(f, pkt);
+#endif
+ return av_read_frame(f->ctx, pkt);
+}
+
+static int got_eagain(void)
+{
+ int i;
+ for (i = 0; i < nb_output_streams; i++)
+ if (output_streams[i]->unavailable)
+ return 1;
+ return 0;
+}
+
+static void reset_eagain(void)
+{
+ int i;
+ for (i = 0; i < nb_input_files; i++)
+ input_files[i]->eagain = 0;
+ for (i = 0; i < nb_output_streams; i++)
+ output_streams[i]->unavailable = 0;
+}
+
+/*
+ * Return
+ * - 0 -- one packet was read and processed
+ * - AVERROR(EAGAIN) -- no packets were available for selected file,
+ * this function should be called again
+ * - AVERROR_EOF -- this function should not be called again
+ */
+static int process_input(int file_index)
+{
+ InputFile *ifile = input_files[file_index];
+ AVFormatContext *is;
+ InputStream *ist;
+ AVPacket pkt;
+ int ret, i, j;
+
+ is = ifile->ctx;
+ ret = get_input_packet(ifile, &pkt);
+
+ if (ret == AVERROR(EAGAIN)) {
+ ifile->eagain = 1;
+ return ret;
+ }
+ if (ret < 0) {
+ if (ret != AVERROR_EOF) {
+ print_error(is->filename, ret);
+ if (exit_on_error)
+ exit_program(1);
+ }
+
+ for (i = 0; i < ifile->nb_streams; i++) {
+ ist = input_streams[ifile->ist_index + i];
+ if (ist->decoding_needed) {
+ ret = process_input_packet(ist, NULL);
+ if (ret>0)
+ return 0;
+ }
+
+ /* mark all outputs that don't go through lavfi as finished */
+ for (j = 0; j < nb_output_streams; j++) {
+ OutputStream *ost = output_streams[j];
+
+ if (ost->source_index == ifile->ist_index + i &&
+ (ost->stream_copy || ost->enc->type == AVMEDIA_TYPE_SUBTITLE))
+ finish_output_stream(ost);
+ }
+ }
+
+ ifile->eof_reached = 1;
+ return AVERROR(EAGAIN);
+ }
+
+ reset_eagain();
+
+ if (do_pkt_dump) {
+ av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
+ is->streams[pkt.stream_index]);
+ }
+ /* the following test is needed in case new streams appear
+ dynamically in stream : we ignore them */
+ if (pkt.stream_index >= ifile->nb_streams) {
+ report_new_stream(file_index, &pkt);
+ goto discard_packet;
+ }
+
+ ist = input_streams[ifile->ist_index + pkt.stream_index];
+
+ ist->data_size += pkt.size;
+ ist->nb_packets++;
+
+ if (ist->discard)
+ goto discard_packet;
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "demuxer -> ist_index:%d type:%s "
+ "next_dts:%s next_dts_time:%s next_pts:%s next_pts_time:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n",
+ ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
+ av_ts2str(ist->next_dts), av_ts2timestr(ist->next_dts, &AV_TIME_BASE_Q),
+ av_ts2str(ist->next_pts), av_ts2timestr(ist->next_pts, &AV_TIME_BASE_Q),
+ av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
+ av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
+ av_ts2str(input_files[ist->file_index]->ts_offset),
+ av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));
+ }
+
+ if(!ist->wrap_correction_done && is->start_time != AV_NOPTS_VALUE && ist->st->pts_wrap_bits < 64){
+ int64_t stime, stime2;
+ // Correcting starttime based on the enabled streams
+ // FIXME this ideally should be done before the first use of starttime but we do not know which are the enabled streams at that point.
+ // so we instead do it here as part of discontinuity handling
+ if ( ist->next_dts == AV_NOPTS_VALUE
+ && ifile->ts_offset == -is->start_time
+ && (is->iformat->flags & AVFMT_TS_DISCONT)) {
+ int64_t new_start_time = INT64_MAX;
+ for (i=0; i<is->nb_streams; i++) {
+ AVStream *st = is->streams[i];
+ if(st->discard == AVDISCARD_ALL || st->start_time == AV_NOPTS_VALUE)
+ continue;
+ new_start_time = FFMIN(new_start_time, av_rescale_q(st->start_time, st->time_base, AV_TIME_BASE_Q));
+ }
+ if (new_start_time > is->start_time) {
+ av_log(is, AV_LOG_VERBOSE, "Correcting start time by %"PRId64"\n", new_start_time - is->start_time);
+ ifile->ts_offset = -new_start_time;
+ }
+ }
+
+ stime = av_rescale_q(is->start_time, AV_TIME_BASE_Q, ist->st->time_base);
+ stime2= stime + (1ULL<<ist->st->pts_wrap_bits);
+ ist->wrap_correction_done = 1;
+
+ if(stime2 > stime && pkt.dts != AV_NOPTS_VALUE && pkt.dts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
+ pkt.dts -= 1ULL<<ist->st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ if(stime2 > stime && pkt.pts != AV_NOPTS_VALUE && pkt.pts > stime + (1LL<<(ist->st->pts_wrap_bits-1))) {
+ pkt.pts -= 1ULL<<ist->st->pts_wrap_bits;
+ ist->wrap_correction_done = 0;
+ }
+ }
+
+ /* add the stream-global side data to the first packet */
+ if (ist->nb_packets == 1) {
+ if (ist->st->nb_side_data)
+ av_packet_split_side_data(&pkt);
+ for (i = 0; i < ist->st->nb_side_data; i++) {
+ AVPacketSideData *src_sd = &ist->st->side_data[i];
+ uint8_t *dst_data;
+
+ if (av_packet_get_side_data(&pkt, src_sd->type, NULL))
+ continue;
+ if (ist->autorotate && src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)
+ continue;
+
+ dst_data = av_packet_new_side_data(&pkt, src_sd->type, src_sd->size);
+ if (!dst_data)
+ exit_program(1);
+
+ memcpy(dst_data, src_sd->data, src_sd->size);
+ }
+ }
+
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts += av_rescale_q(ifile->ts_offset, AV_TIME_BASE_Q, ist->st->time_base);
+
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts *= ist->ts_scale;
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts *= ist->ts_scale;
+
+ if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
+ pkt.dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts
+ && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) {
+ int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
+ int64_t delta = pkt_dts - ifile->last_ts;
+ if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
+ delta > 1LL*dts_delta_threshold*AV_TIME_BASE){
+ ifile->ts_offset -= delta;
+ av_log(NULL, AV_LOG_DEBUG,
+ "Inter stream timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
+ delta, ifile->ts_offset);
+ pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ }
+ }
+
+ if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
+ pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
+ !copy_ts) {
+ int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
+ int64_t delta = pkt_dts - ist->next_dts;
+ if (is->iformat->flags & AVFMT_TS_DISCONT) {
+ if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
+ delta > 1LL*dts_delta_threshold*AV_TIME_BASE ||
+ pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) {
+ ifile->ts_offset -= delta;
+ av_log(NULL, AV_LOG_DEBUG,
+ "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n",
+ delta, ifile->ts_offset);
+ pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+ }
+ } else {
+ if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
+ delta > 1LL*dts_error_threshold*AV_TIME_BASE) {
+ av_log(NULL, AV_LOG_WARNING, "DTS %"PRId64", next:%"PRId64" st:%d invalid dropping\n", pkt.dts, ist->next_dts, pkt.stream_index);
+ pkt.dts = AV_NOPTS_VALUE;
+ }
+ if (pkt.pts != AV_NOPTS_VALUE){
+ int64_t pkt_pts = av_rescale_q(pkt.pts, ist->st->time_base, AV_TIME_BASE_Q);
+ delta = pkt_pts - ist->next_dts;
+ if ( delta < -1LL*dts_error_threshold*AV_TIME_BASE ||
+ delta > 1LL*dts_error_threshold*AV_TIME_BASE) {
+ av_log(NULL, AV_LOG_WARNING, "PTS %"PRId64", next:%"PRId64" invalid dropping st:%d\n", pkt.pts, ist->next_dts, pkt.stream_index);
+ pkt.pts = AV_NOPTS_VALUE;
+ }
+ }
+ }
+ }
+
+ if (pkt.dts != AV_NOPTS_VALUE)
+ ifile->last_ts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
+
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s off:%s off_time:%s\n",
+ ifile->ist_index + pkt.stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
+ av_ts2str(pkt.pts), av_ts2timestr(pkt.pts, &ist->st->time_base),
+ av_ts2str(pkt.dts), av_ts2timestr(pkt.dts, &ist->st->time_base),
+ av_ts2str(input_files[ist->file_index]->ts_offset),
+ av_ts2timestr(input_files[ist->file_index]->ts_offset, &AV_TIME_BASE_Q));
+ }
+
+ sub2video_heartbeat(ist, pkt.pts);
+
+ ret = process_input_packet(ist, &pkt);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
+ ist->file_index, ist->st->index, av_err2str(ret));
+ if (exit_on_error)
+ exit_program(1);
+ }
+
+discard_packet:
+ av_free_packet(&pkt);
+
+ return 0;
+}
+
+/**
+ * Perform a step of transcoding for the specified filter graph.
+ *
+ * @param[in] graph filter graph to consider
+ * @param[out] best_ist input stream where a frame would allow to continue
+ * @return 0 for success, <0 for error
+ */
+static int transcode_from_filter(FilterGraph *graph, InputStream **best_ist)
+{
+ int i, ret;
+ int nb_requests, nb_requests_max = 0;
+ InputFilter *ifilter;
+ InputStream *ist;
+
+ *best_ist = NULL;
+ ret = avfilter_graph_request_oldest(graph->graph);
+ if (ret >= 0)
+ return reap_filters(0);
+
+ if (ret == AVERROR_EOF) {
+ ret = reap_filters(1);
+ for (i = 0; i < graph->nb_outputs; i++)
+ close_output_stream(graph->outputs[i]->ost);
+ return ret;
+ }
+ if (ret != AVERROR(EAGAIN))
+ return ret;
+
+ for (i = 0; i < graph->nb_inputs; i++) {
+ ifilter = graph->inputs[i];
+ ist = ifilter->ist;
+ if (input_files[ist->file_index]->eagain ||
+ input_files[ist->file_index]->eof_reached)
+ continue;
+ nb_requests = av_buffersrc_get_nb_failed_requests(ifilter->filter);
+ if (nb_requests > nb_requests_max) {
+ nb_requests_max = nb_requests;
+ *best_ist = ist;
+ }
+ }
+
+ if (!*best_ist)
+ for (i = 0; i < graph->nb_outputs; i++)
+ graph->outputs[i]->ost->unavailable = 1;
+
+ return 0;
+}
+
+/**
+ * Run a single step of transcoding.
+ *
+ * @return 0 for success, <0 for error
+ */
+static int transcode_step(void)
+{
+ OutputStream *ost;
+ InputStream *ist;
+ int ret;
+
+ ost = choose_output();
+ if (!ost) {
+ if (got_eagain()) {
+ reset_eagain();
+ av_usleep(10000);
+ return 0;
+ }
+ av_log(NULL, AV_LOG_VERBOSE, "No more inputs to read from, finishing.\n");
+ return AVERROR_EOF;
+ }
+
+ if (ost->filter) {
+ if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0)
+ return ret;
+ if (!ist)
+ return 0;
+ } else {
+ av_assert0(ost->source_index >= 0);
+ ist = input_streams[ost->source_index];
+ }
+
+ ret = process_input(ist->file_index);
+ if (ret == AVERROR(EAGAIN)) {
+ if (input_files[ist->file_index]->eagain)
+ ost->unavailable = 1;
+ return 0;
+ }
+
+ if (ret < 0)
+ return ret == AVERROR_EOF ? 0 : ret;
+
+ return reap_filters(0);
+}
+
+/*
+ * The following code is the main loop of the file converter
+ */
+static int transcode(void)
+{
+ int ret, i;
+ AVFormatContext *os;
+ OutputStream *ost;
+ InputStream *ist;
+ int64_t timer_start;
+
+ ret = transcode_init();
+ if (ret < 0)
+ goto fail;
+
+ if (stdin_interaction) {
+ av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
+ }
+
+ timer_start = av_gettime_relative();
+
+#if HAVE_PTHREADS
+ if ((ret = init_input_threads()) < 0)
+ goto fail;
+#endif
+
+ while (!received_sigterm) {
+ int64_t cur_time= av_gettime_relative();
+
+ /* if 'q' pressed, exits */
+ if (stdin_interaction)
+ if (check_keyboard_interaction(cur_time) < 0)
+ break;
+
+ /* check if there's any stream where output is still needed */
+ if (!need_output()) {
+ av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
+ break;
+ }
+
+ ret = transcode_step();
+ if (ret < 0) {
+ if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
+ continue;
+ } else {
+ char errbuf[128];
+ av_strerror(ret, errbuf, sizeof(errbuf));
+
+ av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf);
+ break;
+ }
+ }
+
+ /* dump report by using the output first video and audio streams */
+ print_report(0, timer_start, cur_time);
+ }
+#if HAVE_PTHREADS
+ free_input_threads();
+#endif
+
+ /* at the end of stream, we must flush the decoder buffers */
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
+ process_input_packet(ist, NULL);
+ }
+ }
+ flush_encoders();
+
+ term_exit();
+
+ /* write the trailer if needed and close file */
+ for (i = 0; i < nb_output_files; i++) {
+ os = output_files[i]->ctx;
+ av_write_trailer(os);
+ }
+
+ /* dump report by using the first video and audio streams */
+ print_report(1, timer_start, av_gettime_relative());
+
+ /* close each encoder */
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = output_streams[i];
+ if (ost->encoding_needed) {
+ av_freep(&ost->enc_ctx->stats_in);
+ }
+ }
+
+ /* close each decoder */
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (ist->decoding_needed) {
+ avcodec_close(ist->dec_ctx);
+ if (ist->hwaccel_uninit)
+ ist->hwaccel_uninit(ist->dec_ctx);
+ }
+ }
+
+ /* finished ! */
+ ret = 0;
+
+ fail:
+#if HAVE_PTHREADS
+ free_input_threads();
+#endif
+
+ if (output_streams) {
+ for (i = 0; i < nb_output_streams; i++) {
+ ost = output_streams[i];
+ if (ost) {
+ if (ost->logfile) {
+ fclose(ost->logfile);
+ ost->logfile = NULL;
+ }
+ av_freep(&ost->forced_kf_pts);
+ av_freep(&ost->apad);
+ av_freep(&ost->disposition);
+ av_dict_free(&ost->encoder_opts);
+ av_dict_free(&ost->swr_opts);
+ av_dict_free(&ost->resample_opts);
+ av_dict_free(&ost->bsf_args);
+ }
+ }
+ }
+ return ret;
+}
+
+
+static int64_t getutime(void)
+{
+#if HAVE_GETRUSAGE
+ struct rusage rusage;
+
+ getrusage(RUSAGE_SELF, &rusage);
+ return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
+#elif HAVE_GETPROCESSTIMES
+ HANDLE proc;
+ FILETIME c, e, k, u;
+ proc = GetCurrentProcess();
+ GetProcessTimes(proc, &c, &e, &k, &u);
+ return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
+#else
+ return av_gettime_relative();
+#endif
+}
+
+static int64_t getmaxrss(void)
+{
+#if HAVE_GETRUSAGE && HAVE_STRUCT_RUSAGE_RU_MAXRSS
+ struct rusage rusage;
+ getrusage(RUSAGE_SELF, &rusage);
+ return (int64_t)rusage.ru_maxrss * 1024;
+#elif HAVE_GETPROCESSMEMORYINFO
+ HANDLE proc;
+ PROCESS_MEMORY_COUNTERS memcounters;
+ proc = GetCurrentProcess();
+ memcounters.cb = sizeof(memcounters);
+ GetProcessMemoryInfo(proc, &memcounters, sizeof(memcounters));
+ return memcounters.PeakPagefileUsage;
+#else
+ return 0;
+#endif
+}
+
+static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ int64_t ti;
+
+ register_exit(ffmpeg_cleanup);
+
+ setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */
+
+ av_log_set_flags(AV_LOG_SKIP_REPEATED);
+ parse_loglevel(argc, argv, options);
+
+ if(argc>1 && !strcmp(argv[1], "-d")){
+ run_as_daemon=1;
+ av_log_set_callback(log_callback_null);
+ argc--;
+ argv++;
+ }
+
+ avcodec_register_all();
+#if CONFIG_AVDEVICE
+ avdevice_register_all();
+#endif
+ avfilter_register_all();
+ av_register_all();
+ avformat_network_init();
+
+ show_banner(argc, argv, options);
+
+ term_init();
+
+ /* parse options and open all input/output files */
+ ret = ffmpeg_parse_options(argc, argv);
+ if (ret < 0)
+ exit_program(1);
+
+ if (nb_output_files <= 0 && nb_input_files == 0) {
+ show_usage();
+ av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
+ exit_program(1);
+ }
+
+ /* file converter / grab */
+ if (nb_output_files <= 0) {
+ av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
+ exit_program(1);
+ }
+
+// if (nb_input_files == 0) {
+// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n");
+// exit_program(1);
+// }
+
+ current_time = ti = getutime();
+ if (transcode() < 0)
+ exit_program(1);
+ ti = getutime() - ti;
+ if (do_benchmark) {
+ printf("bench: utime=%0.3fs\n", ti / 1000000.0);
+ }
+ av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n",
+ decode_error_stat[0], decode_error_stat[1]);
+ if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1])
+ exit_program(69);
+
+ exit_program(received_nb_signals ? 255 : main_return_code);
+ return main_return_code;
+}
diff --git a/ffmpeg.h b/ffmpeg.h
new file mode 100644
index 0000000000..7fd129a283
--- /dev/null
+++ b/ffmpeg.h
@@ -0,0 +1,546 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 FFMPEG_H
+#define FFMPEG_H
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <signal.h>
+
+#if HAVE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "cmdutils.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/avio.h"
+
+#include "libavcodec/avcodec.h"
+
+#include "libavfilter/avfilter.h"
+
+#include "libavutil/avutil.h"
+#include "libavutil/dict.h"
+#include "libavutil/eval.h"
+#include "libavutil/fifo.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/rational.h"
+#include "libavutil/threadmessage.h"
+
+#include "libswresample/swresample.h"
+
+#define VSYNC_AUTO -1
+#define VSYNC_PASSTHROUGH 0
+#define VSYNC_CFR 1
+#define VSYNC_VFR 2
+#define VSYNC_VSCFR 0xfe
+#define VSYNC_DROP 0xff
+
+#define MAX_STREAMS 1024 /* arbitrary sanity check value */
+
+enum HWAccelID {
+ HWACCEL_NONE = 0,
+ HWACCEL_AUTO,
+ HWACCEL_VDPAU,
+ HWACCEL_DXVA2,
+ HWACCEL_VDA,
+};
+
+typedef struct HWAccel {
+ const char *name;
+ int (*init)(AVCodecContext *s);
+ enum HWAccelID id;
+ enum AVPixelFormat pix_fmt;
+} HWAccel;
+
+/* 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;
+ int sync_file_index;
+ int sync_stream_index;
+ char *linklabel; /* name of an output link, for mapping lavfi outputs */
+} StreamMap;
+
+typedef struct {
+ int file_idx, stream_idx, channel_idx; // input
+ int ofile_idx, ostream_idx; // output
+} AudioChannelMap;
+
+typedef struct OptionsContext {
+ OptionGroup *g;
+
+ /* input/output options */
+ int64_t start_time;
+ int seek_timestamp;
+ const char *format;
+
+ SpecifierOpt *codec_names;
+ int nb_codec_names;
+ SpecifierOpt *audio_channels;
+ int nb_audio_channels;
+ SpecifierOpt *audio_sample_rate;
+ int nb_audio_sample_rate;
+ SpecifierOpt *frame_rates;
+ int nb_frame_rates;
+ SpecifierOpt *frame_sizes;
+ int nb_frame_sizes;
+ SpecifierOpt *frame_pix_fmts;
+ int nb_frame_pix_fmts;
+
+ /* input options */
+ int64_t input_ts_offset;
+ int rate_emu;
+ int accurate_seek;
+ int thread_queue_size;
+
+ SpecifierOpt *ts_scale;
+ int nb_ts_scale;
+ SpecifierOpt *dump_attachment;
+ int nb_dump_attachment;
+ SpecifierOpt *hwaccels;
+ int nb_hwaccels;
+ SpecifierOpt *hwaccel_devices;
+ int nb_hwaccel_devices;
+ SpecifierOpt *autorotate;
+ int nb_autorotate;
+
+ /* output options */
+ StreamMap *stream_maps;
+ int nb_stream_maps;
+ AudioChannelMap *audio_channel_maps; /* one info entry per -map_channel */
+ int nb_audio_channel_maps; /* number of (valid) -map_channel settings */
+ int metadata_global_manual;
+ int metadata_streams_manual;
+ int metadata_chapters_manual;
+ const char **attachments;
+ int nb_attachments;
+
+ int chapters_input_file;
+
+ int64_t recording_time;
+ int64_t stop_time;
+ uint64_t limit_filesize;
+ float mux_preload;
+ float mux_max_delay;
+ int shortest;
+
+ int video_disable;
+ int audio_disable;
+ int subtitle_disable;
+ int data_disable;
+
+ /* indexed by output file stream index */
+ int *streamid_map;
+ int nb_streamid_map;
+
+ SpecifierOpt *metadata;
+ int nb_metadata;
+ SpecifierOpt *max_frames;
+ int nb_max_frames;
+ SpecifierOpt *bitstream_filters;
+ int nb_bitstream_filters;
+ SpecifierOpt *codec_tags;
+ int nb_codec_tags;
+ SpecifierOpt *sample_fmts;
+ int nb_sample_fmts;
+ SpecifierOpt *qscale;
+ int nb_qscale;
+ SpecifierOpt *forced_key_frames;
+ int nb_forced_key_frames;
+ SpecifierOpt *force_fps;
+ int nb_force_fps;
+ SpecifierOpt *frame_aspect_ratios;
+ int nb_frame_aspect_ratios;
+ SpecifierOpt *rc_overrides;
+ int nb_rc_overrides;
+ SpecifierOpt *intra_matrices;
+ int nb_intra_matrices;
+ SpecifierOpt *inter_matrices;
+ int nb_inter_matrices;
+ SpecifierOpt *chroma_intra_matrices;
+ int nb_chroma_intra_matrices;
+ SpecifierOpt *top_field_first;
+ int nb_top_field_first;
+ SpecifierOpt *metadata_map;
+ int nb_metadata_map;
+ SpecifierOpt *presets;
+ int nb_presets;
+ SpecifierOpt *copy_initial_nonkeyframes;
+ int nb_copy_initial_nonkeyframes;
+ SpecifierOpt *copy_prior_start;
+ int nb_copy_prior_start;
+ SpecifierOpt *filters;
+ int nb_filters;
+ SpecifierOpt *filter_scripts;
+ int nb_filter_scripts;
+ SpecifierOpt *reinit_filters;
+ int nb_reinit_filters;
+ SpecifierOpt *fix_sub_duration;
+ int nb_fix_sub_duration;
+ SpecifierOpt *canvas_sizes;
+ int nb_canvas_sizes;
+ SpecifierOpt *pass;
+ int nb_pass;
+ SpecifierOpt *passlogfiles;
+ int nb_passlogfiles;
+ SpecifierOpt *guess_layout_max;
+ int nb_guess_layout_max;
+ SpecifierOpt *apad;
+ int nb_apad;
+ SpecifierOpt *discard;
+ int nb_discard;
+ SpecifierOpt *disposition;
+ int nb_disposition;
+} OptionsContext;
+
+typedef struct InputFilter {
+ AVFilterContext *filter;
+ struct InputStream *ist;
+ struct FilterGraph *graph;
+ uint8_t *name;
+} InputFilter;
+
+typedef struct OutputFilter {
+ AVFilterContext *filter;
+ struct OutputStream *ost;
+ struct FilterGraph *graph;
+ uint8_t *name;
+
+ /* temporary storage until stream maps are processed */
+ AVFilterInOut *out_tmp;
+} OutputFilter;
+
+typedef struct FilterGraph {
+ int index;
+ const char *graph_desc;
+
+ AVFilterGraph *graph;
+ int reconfiguration;
+
+ InputFilter **inputs;
+ int nb_inputs;
+ OutputFilter **outputs;
+ int nb_outputs;
+} FilterGraph;
+
+typedef struct InputStream {
+ int file_index;
+ AVStream *st;
+ int discard; /* true if stream data should be discarded */
+ int user_set_discard;
+ int decoding_needed; /* non zero if the packets must be decoded in 'raw_fifo', see DECODING_FOR_* */
+#define DECODING_FOR_OST 1
+#define DECODING_FOR_FILTER 2
+
+ AVCodecContext *dec_ctx;
+ AVCodec *dec;
+ AVFrame *decoded_frame;
+ AVFrame *filter_frame; /* a ref of decoded_frame, to be sent to filters */
+
+ int64_t start; /* time when read started */
+ /* predicted dts of the next packet read for this stream or (when there are
+ * several frames in a packet) of the next frame in current packet (in AV_TIME_BASE units) */
+ int64_t next_dts;
+ int64_t dts; ///< dts of the last packet read for this stream (in AV_TIME_BASE units)
+
+ int64_t next_pts; ///< synthetic pts for the next decode frame (in AV_TIME_BASE units)
+ int64_t pts; ///< current pts of the decoded frame (in AV_TIME_BASE units)
+ int wrap_correction_done;
+
+ int64_t filter_in_rescale_delta_last;
+
+ double ts_scale;
+ int saw_first_ts;
+ int showed_multi_packet_warning;
+ AVDictionary *decoder_opts;
+ AVRational framerate; /* framerate forced with -r */
+ int top_field_first;
+ int guess_layout_max;
+
+ int autorotate;
+ int resample_height;
+ int resample_width;
+ int resample_pix_fmt;
+
+ int resample_sample_fmt;
+ int resample_sample_rate;
+ int resample_channels;
+ uint64_t resample_channel_layout;
+
+ int fix_sub_duration;
+ struct { /* previous decoded subtitle and related variables */
+ int got_output;
+ int ret;
+ AVSubtitle subtitle;
+ } prev_sub;
+
+ struct sub2video {
+ int64_t last_pts;
+ int64_t end_pts;
+ AVFrame *frame;
+ int w, h;
+ } sub2video;
+
+ int dr1;
+
+ /* decoded data from this stream goes into all those filters
+ * currently video and audio only */
+ InputFilter **filters;
+ int nb_filters;
+
+ int reinit_filters;
+
+ /* hwaccel options */
+ enum HWAccelID hwaccel_id;
+ char *hwaccel_device;
+
+ /* hwaccel context */
+ enum HWAccelID active_hwaccel_id;
+ void *hwaccel_ctx;
+ void (*hwaccel_uninit)(AVCodecContext *s);
+ int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags);
+ int (*hwaccel_retrieve_data)(AVCodecContext *s, AVFrame *frame);
+ enum AVPixelFormat hwaccel_pix_fmt;
+ enum AVPixelFormat hwaccel_retrieved_pix_fmt;
+
+ /* stats */
+ // combined size of all the packets read
+ uint64_t data_size;
+ /* number of packets successfully read for this stream */
+ uint64_t nb_packets;
+ // number of frames/samples retrieved from the decoder
+ uint64_t frames_decoded;
+ uint64_t samples_decoded;
+} InputStream;
+
+typedef struct InputFile {
+ AVFormatContext *ctx;
+ int eof_reached; /* true if eof reached */
+ int eagain; /* true if last read attempt returned EAGAIN */
+ int ist_index; /* index of first stream in input_streams */
+ int64_t input_ts_offset;
+ int64_t ts_offset;
+ int64_t last_ts;
+ int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
+ int seek_timestamp;
+ int64_t recording_time;
+ int nb_streams; /* number of stream that ffmpeg is aware of; may be different
+ from ctx.nb_streams if new streams appear during av_read_frame() */
+ int nb_streams_warn; /* number of streams that the user was warned of */
+ int rate_emu;
+ int accurate_seek;
+
+#if HAVE_PTHREADS
+ AVThreadMessageQueue *in_thread_queue;
+ pthread_t thread; /* thread reading from this file */
+ int non_blocking; /* reading packets from the thread should not block */
+ int joined; /* the thread has been joined */
+ int thread_queue_size; /* maximum number of queued packets */
+#endif
+} InputFile;
+
+enum forced_keyframes_const {
+ FKF_N,
+ FKF_N_FORCED,
+ FKF_PREV_FORCED_N,
+ FKF_PREV_FORCED_T,
+ FKF_T,
+ FKF_NB
+};
+
+extern const char *const forced_keyframes_const_names[];
+
+typedef enum {
+ ENCODER_FINISHED = 1,
+ MUXER_FINISHED = 2,
+} OSTFinished ;
+
+typedef struct OutputStream {
+ int file_index; /* file index */
+ int index; /* stream index in the output file */
+ int source_index; /* InputStream index */
+ AVStream *st; /* stream in the output file */
+ int encoding_needed; /* true if encoding needed for this stream */
+ int frame_number;
+ /* input pts and corresponding output pts
+ for A/V sync */
+ struct InputStream *sync_ist; /* input stream to sync against */
+ int64_t sync_opts; /* output frame counter, could be changed to some true timestamp */ // FIXME look at frame_number
+ /* pts of the first frame encoded for this stream, used for limiting
+ * recording time */
+ int64_t first_pts;
+ /* dts of the last packet sent to the muxer */
+ int64_t last_mux_dts;
+ AVBitStreamFilterContext *bitstream_filters;
+ AVCodecContext *enc_ctx;
+ AVCodec *enc;
+ int64_t max_frames;
+ AVFrame *filtered_frame;
+ AVFrame *last_frame;
+ int last_droped;
+ int last_nb0_frames[3];
+
+ /* video only */
+ AVRational frame_rate;
+ int force_fps;
+ int top_field_first;
+ int rotate_overridden;
+
+ AVRational frame_aspect_ratio;
+
+ /* forced key frames */
+ int64_t *forced_kf_pts;
+ int forced_kf_count;
+ int forced_kf_index;
+ char *forced_keyframes;
+ AVExpr *forced_keyframes_pexpr;
+ double forced_keyframes_expr_const_values[FKF_NB];
+
+ /* audio only */
+ int *audio_channels_map; /* list of the channels id to pick from the source stream */
+ int audio_channels_mapped; /* number of channels in audio_channels_map */
+
+ char *logfile_prefix;
+ FILE *logfile;
+
+ OutputFilter *filter;
+ char *avfilter;
+ char *filters; ///< filtergraph associated to the -filter option
+ char *filters_script; ///< filtergraph script associated to the -filter_script option
+
+ int64_t sws_flags;
+ AVDictionary *encoder_opts;
+ AVDictionary *swr_opts;
+ AVDictionary *resample_opts;
+ AVDictionary *bsf_args;
+ char *apad;
+ OSTFinished finished; /* no more packets should be written for this stream */
+ int unavailable; /* true if the steram is unavailable (possibly temporarily) */
+ int stream_copy;
+ const char *attachment_filename;
+ int copy_initial_nonkeyframes;
+ int copy_prior_start;
+ char *disposition;
+
+ int keep_pix_fmt;
+
+ AVCodecParserContext *parser;
+
+ /* stats */
+ // combined size of all the packets written
+ uint64_t data_size;
+ // number of packets send to the muxer
+ uint64_t packets_written;
+ // number of frames/samples sent to the encoder
+ uint64_t frames_encoded;
+ uint64_t samples_encoded;
+} OutputStream;
+
+typedef struct OutputFile {
+ AVFormatContext *ctx;
+ AVDictionary *opts;
+ int ost_index; /* index of the first stream in output_streams */
+ 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
+ uint64_t limit_filesize; /* filesize limit expressed in bytes */
+
+ int shortest;
+} OutputFile;
+
+extern InputStream **input_streams;
+extern int nb_input_streams;
+extern InputFile **input_files;
+extern int nb_input_files;
+
+extern OutputStream **output_streams;
+extern int nb_output_streams;
+extern OutputFile **output_files;
+extern int nb_output_files;
+
+extern FilterGraph **filtergraphs;
+extern int nb_filtergraphs;
+
+extern char *vstats_filename;
+extern char *sdp_filename;
+
+extern float audio_drift_threshold;
+extern float dts_delta_threshold;
+extern float dts_error_threshold;
+
+extern int audio_volume;
+extern int audio_sync_method;
+extern int video_sync_method;
+extern float frame_drop_threshold;
+extern int do_benchmark;
+extern int do_benchmark_all;
+extern int do_deinterlace;
+extern int do_hex_dump;
+extern int do_pkt_dump;
+extern int copy_ts;
+extern int start_at_zero;
+extern int copy_tb;
+extern int debug_ts;
+extern int exit_on_error;
+extern int print_stats;
+extern int qp_hist;
+extern int stdin_interaction;
+extern int frame_bits_per_raw_sample;
+extern AVIOContext *progress_avio;
+extern float max_error_rate;
+extern int vdpau_api_ver;
+
+extern const AVIOInterruptCB int_cb;
+
+extern const OptionDef options[];
+extern const HWAccel hwaccels[];
+
+
+void term_init(void);
+void term_exit(void);
+
+void reset_options(OptionsContext *o, int is_input);
+void show_usage(void);
+
+void opt_output_file(void *optctx, const char *filename);
+
+void remove_avoptions(AVDictionary **a, AVDictionary *b);
+void assert_avoptions(AVDictionary *m);
+
+int guess_input_channel_layout(InputStream *ist);
+
+enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *avctx, AVCodec *codec, enum AVPixelFormat target);
+void choose_sample_fmt(AVStream *st, AVCodec *codec);
+
+int configure_filtergraph(FilterGraph *fg);
+int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out);
+int ist_in_filtergraph(FilterGraph *fg, InputStream *ist);
+FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost);
+
+int ffmpeg_parse_options(int argc, char **argv);
+
+int vdpau_init(AVCodecContext *s);
+int dxva2_init(AVCodecContext *s);
+int vda_init(AVCodecContext *s);
+
+#endif /* FFMPEG_H */
diff --git a/ffmpeg_dxva2.c b/ffmpeg_dxva2.c
new file mode 100644
index 0000000000..741c55b015
--- /dev/null
+++ b/ffmpeg_dxva2.c
@@ -0,0 +1,628 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0600
+#define DXVA2API_USE_BITFIELDS
+#define COBJMACROS
+
+#include <stdint.h>
+
+#include <d3d9.h>
+#include <dxva2api.h>
+
+#include "ffmpeg.h"
+
+#include "libavcodec/dxva2.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/buffer.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixfmt.h"
+
+/* define all the GUIDs used directly here,
+ to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */
+#include <initguid.h>
+DEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
+
+DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
+DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60);
+DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
+DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
+DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
+DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
+DEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
+DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0);
+DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
+DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
+
+typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
+typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **);
+
+typedef struct dxva2_mode {
+ const GUID *guid;
+ enum AVCodecID codec;
+} dxva2_mode;
+
+static const dxva2_mode dxva2_modes[] = {
+ /* MPEG-2 */
+ { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO },
+ { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO },
+
+ /* H.264 */
+ { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 },
+ { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 },
+ /* Intel specific H.264 mode */
+ { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 },
+
+ /* VC-1 / WMV3 */
+ { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 },
+ { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 },
+ { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 },
+ { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 },
+
+ /* HEVC/H.265 */
+ { &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC },
+
+ { NULL, 0 },
+};
+
+typedef struct surface_info {
+ int used;
+ uint64_t age;
+} surface_info;
+
+typedef struct DXVA2Context {
+ HMODULE d3dlib;
+ HMODULE dxva2lib;
+
+ HANDLE deviceHandle;
+
+ IDirect3D9 *d3d9;
+ IDirect3DDevice9 *d3d9device;
+ IDirect3DDeviceManager9 *d3d9devmgr;
+ IDirectXVideoDecoderService *decoder_service;
+ IDirectXVideoDecoder *decoder;
+
+ GUID decoder_guid;
+ DXVA2_ConfigPictureDecode decoder_config;
+
+ LPDIRECT3DSURFACE9 *surfaces;
+ surface_info *surface_infos;
+ uint32_t num_surfaces;
+ uint64_t surface_age;
+
+ AVFrame *tmp_frame;
+} DXVA2Context;
+
+typedef struct DXVA2SurfaceWrapper {
+ DXVA2Context *ctx;
+ LPDIRECT3DSURFACE9 surface;
+ IDirectXVideoDecoder *decoder;
+} DXVA2SurfaceWrapper;
+
+static void dxva2_destroy_decoder(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ DXVA2Context *ctx = ist->hwaccel_ctx;
+ int i;
+
+ if (ctx->surfaces) {
+ for (i = 0; i < ctx->num_surfaces; i++) {
+ if (ctx->surfaces[i])
+ IDirect3DSurface9_Release(ctx->surfaces[i]);
+ }
+ }
+ av_freep(&ctx->surfaces);
+ av_freep(&ctx->surface_infos);
+ ctx->num_surfaces = 0;
+ ctx->surface_age = 0;
+
+ if (ctx->decoder) {
+ IDirectXVideoDecoder_Release(ctx->decoder);
+ ctx->decoder = NULL;
+ }
+}
+
+static void dxva2_uninit(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ DXVA2Context *ctx = ist->hwaccel_ctx;
+
+ ist->hwaccel_uninit = NULL;
+ ist->hwaccel_get_buffer = NULL;
+ ist->hwaccel_retrieve_data = NULL;
+
+ if (ctx->decoder)
+ dxva2_destroy_decoder(s);
+
+ if (ctx->decoder_service)
+ IDirectXVideoDecoderService_Release(ctx->decoder_service);
+
+ if (ctx->d3d9devmgr && ctx->deviceHandle != INVALID_HANDLE_VALUE)
+ IDirect3DDeviceManager9_CloseDeviceHandle(ctx->d3d9devmgr, ctx->deviceHandle);
+
+ if (ctx->d3d9devmgr)
+ IDirect3DDeviceManager9_Release(ctx->d3d9devmgr);
+
+ if (ctx->d3d9device)
+ IDirect3DDevice9_Release(ctx->d3d9device);
+
+ if (ctx->d3d9)
+ IDirect3D9_Release(ctx->d3d9);
+
+ if (ctx->d3dlib)
+ FreeLibrary(ctx->d3dlib);
+
+ if (ctx->dxva2lib)
+ FreeLibrary(ctx->dxva2lib);
+
+ av_frame_free(&ctx->tmp_frame);
+
+ av_freep(&ist->hwaccel_ctx);
+ av_freep(&s->hwaccel_context);
+}
+
+static void dxva2_release_buffer(void *opaque, uint8_t *data)
+{
+ DXVA2SurfaceWrapper *w = opaque;
+ DXVA2Context *ctx = w->ctx;
+ int i;
+
+ for (i = 0; i < ctx->num_surfaces; i++) {
+ if (ctx->surfaces[i] == w->surface) {
+ ctx->surface_infos[i].used = 0;
+ break;
+ }
+ }
+ IDirect3DSurface9_Release(w->surface);
+ IDirectXVideoDecoder_Release(w->decoder);
+ av_free(w);
+}
+
+static int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
+{
+ InputStream *ist = s->opaque;
+ DXVA2Context *ctx = ist->hwaccel_ctx;
+ int i, old_unused = -1;
+ LPDIRECT3DSURFACE9 surface;
+ DXVA2SurfaceWrapper *w = NULL;
+
+ av_assert0(frame->format == AV_PIX_FMT_DXVA2_VLD);
+
+ for (i = 0; i < ctx->num_surfaces; i++) {
+ surface_info *info = &ctx->surface_infos[i];
+ if (!info->used && (old_unused == -1 || info->age < ctx->surface_infos[old_unused].age))
+ old_unused = i;
+ }
+ if (old_unused == -1) {
+ av_log(NULL, AV_LOG_ERROR, "No free DXVA2 surface!\n");
+ return AVERROR(ENOMEM);
+ }
+ i = old_unused;
+
+ surface = ctx->surfaces[i];
+
+ w = av_mallocz(sizeof(*w));
+ if (!w)
+ return AVERROR(ENOMEM);
+
+ frame->buf[0] = av_buffer_create((uint8_t*)surface, 0,
+ dxva2_release_buffer, w,
+ AV_BUFFER_FLAG_READONLY);
+ if (!frame->buf[0]) {
+ av_free(w);
+ return AVERROR(ENOMEM);
+ }
+
+ w->ctx = ctx;
+ w->surface = surface;
+ IDirect3DSurface9_AddRef(w->surface);
+ w->decoder = ctx->decoder;
+ IDirectXVideoDecoder_AddRef(w->decoder);
+
+ ctx->surface_infos[i].used = 1;
+ ctx->surface_infos[i].age = ctx->surface_age++;
+
+ frame->data[3] = (uint8_t *)surface;
+
+ return 0;
+}
+
+static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame)
+{
+ LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)frame->data[3];
+ InputStream *ist = s->opaque;
+ DXVA2Context *ctx = ist->hwaccel_ctx;
+ D3DSURFACE_DESC surfaceDesc;
+ D3DLOCKED_RECT LockedRect;
+ HRESULT hr;
+ int ret;
+
+ IDirect3DSurface9_GetDesc(surface, &surfaceDesc);
+
+ ctx->tmp_frame->width = frame->width;
+ ctx->tmp_frame->height = frame->height;
+ ctx->tmp_frame->format = AV_PIX_FMT_NV12;
+
+ ret = av_frame_get_buffer(ctx->tmp_frame, 32);
+ if (ret < 0)
+ return ret;
+
+ hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, D3DLOCK_READONLY);
+ if (FAILED(hr)) {
+ av_log(NULL, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ av_image_copy_plane(ctx->tmp_frame->data[0], ctx->tmp_frame->linesize[0],
+ (uint8_t*)LockedRect.pBits,
+ LockedRect.Pitch, frame->width, frame->height);
+
+ av_image_copy_plane(ctx->tmp_frame->data[1], ctx->tmp_frame->linesize[1],
+ (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height,
+ LockedRect.Pitch, frame->width, frame->height / 2);
+
+ IDirect3DSurface9_UnlockRect(surface);
+
+ ret = av_frame_copy_props(ctx->tmp_frame, frame);
+ if (ret < 0)
+ goto fail;
+
+ av_frame_unref(frame);
+ av_frame_move_ref(frame, ctx->tmp_frame);
+
+ return 0;
+fail:
+ av_frame_unref(ctx->tmp_frame);
+ return ret;
+}
+
+static int dxva2_alloc(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ DXVA2Context *ctx;
+ pDirect3DCreate9 *createD3D = NULL;
+ pCreateDeviceManager9 *createDeviceManager = NULL;
+ HRESULT hr;
+ D3DPRESENT_PARAMETERS d3dpp = {0};
+ D3DDISPLAYMODE d3ddm;
+ unsigned resetToken = 0;
+ UINT adapter = D3DADAPTER_DEFAULT;
+
+ ctx = av_mallocz(sizeof(*ctx));
+ if (!ctx)
+ return AVERROR(ENOMEM);
+
+ ctx->deviceHandle = INVALID_HANDLE_VALUE;
+
+ ist->hwaccel_ctx = ctx;
+ ist->hwaccel_uninit = dxva2_uninit;
+ ist->hwaccel_get_buffer = dxva2_get_buffer;
+ ist->hwaccel_retrieve_data = dxva2_retrieve_data;
+
+ ctx->d3dlib = LoadLibrary("d3d9.dll");
+ if (!ctx->d3dlib) {
+ av_log(NULL, loglevel, "Failed to load D3D9 library\n");
+ goto fail;
+ }
+ ctx->dxva2lib = LoadLibrary("dxva2.dll");
+ if (!ctx->dxva2lib) {
+ av_log(NULL, loglevel, "Failed to load DXVA2 library\n");
+ goto fail;
+ }
+
+ createD3D = (pDirect3DCreate9 *)GetProcAddress(ctx->d3dlib, "Direct3DCreate9");
+ if (!createD3D) {
+ av_log(NULL, loglevel, "Failed to locate Direct3DCreate9\n");
+ goto fail;
+ }
+ createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(ctx->dxva2lib, "DXVA2CreateDirect3DDeviceManager9");
+ if (!createDeviceManager) {
+ av_log(NULL, loglevel, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n");
+ goto fail;
+ }
+
+ ctx->d3d9 = createD3D(D3D_SDK_VERSION);
+ if (!ctx->d3d9) {
+ av_log(NULL, loglevel, "Failed to create IDirect3D object\n");
+ goto fail;
+ }
+
+ if (ist->hwaccel_device) {
+ adapter = atoi(ist->hwaccel_device);
+ av_log(NULL, AV_LOG_INFO, "Using HWAccel device %d\n", adapter);
+ }
+
+ IDirect3D9_GetAdapterDisplayMode(ctx->d3d9, adapter, &d3ddm);
+ d3dpp.Windowed = TRUE;
+ d3dpp.BackBufferWidth = 640;
+ d3dpp.BackBufferHeight = 480;
+ d3dpp.BackBufferCount = 0;
+ d3dpp.BackBufferFormat = d3ddm.Format;
+ d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ d3dpp.Flags = D3DPRESENTFLAG_VIDEO;
+
+ hr = IDirect3D9_CreateDevice(ctx->d3d9, adapter, D3DDEVTYPE_HAL, GetShellWindow(),
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
+ &d3dpp, &ctx->d3d9device);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to create Direct3D device\n");
+ goto fail;
+ }
+
+ hr = createDeviceManager(&resetToken, &ctx->d3d9devmgr);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to create Direct3D device manager\n");
+ goto fail;
+ }
+
+ hr = IDirect3DDeviceManager9_ResetDevice(ctx->d3d9devmgr, ctx->d3d9device, resetToken);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to bind Direct3D device to device manager\n");
+ goto fail;
+ }
+
+ hr = IDirect3DDeviceManager9_OpenDeviceHandle(ctx->d3d9devmgr, &ctx->deviceHandle);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to open device handle\n");
+ goto fail;
+ }
+
+ hr = IDirect3DDeviceManager9_GetVideoService(ctx->d3d9devmgr, ctx->deviceHandle, &IID_IDirectXVideoDecoderService, (void **)&ctx->decoder_service);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to create IDirectXVideoDecoderService\n");
+ goto fail;
+ }
+
+ ctx->tmp_frame = av_frame_alloc();
+ if (!ctx->tmp_frame)
+ goto fail;
+
+ s->hwaccel_context = av_mallocz(sizeof(struct dxva_context));
+ if (!s->hwaccel_context)
+ goto fail;
+
+ return 0;
+fail:
+ dxva2_uninit(s);
+ return AVERROR(EINVAL);
+}
+
+static int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid,
+ const DXVA2_VideoDesc *desc,
+ DXVA2_ConfigPictureDecode *config)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ DXVA2Context *ctx = ist->hwaccel_ctx;
+ unsigned cfg_count = 0, best_score = 0;
+ DXVA2_ConfigPictureDecode *cfg_list = NULL;
+ DXVA2_ConfigPictureDecode best_cfg = {{0}};
+ HRESULT hr;
+ int i;
+
+ hr = IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, device_guid, desc, NULL, &cfg_count, &cfg_list);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Unable to retrieve decoder configurations\n");
+ return AVERROR(EINVAL);
+ }
+
+ for (i = 0; i < cfg_count; i++) {
+ DXVA2_ConfigPictureDecode *cfg = &cfg_list[i];
+
+ unsigned score;
+ if (cfg->ConfigBitstreamRaw == 1)
+ score = 1;
+ else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)
+ score = 2;
+ else
+ continue;
+ if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt))
+ score += 16;
+ if (score > best_score) {
+ best_score = score;
+ best_cfg = *cfg;
+ }
+ }
+ CoTaskMemFree(cfg_list);
+
+ if (!best_score) {
+ av_log(NULL, loglevel, "No valid decoder configuration available\n");
+ return AVERROR(EINVAL);
+ }
+
+ *config = best_cfg;
+ return 0;
+}
+
+static int dxva2_create_decoder(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ DXVA2Context *ctx = ist->hwaccel_ctx;
+ struct dxva_context *dxva_ctx = s->hwaccel_context;
+ GUID *guid_list = NULL;
+ unsigned guid_count = 0, i, j;
+ GUID device_guid = GUID_NULL;
+ D3DFORMAT target_format = 0;
+ DXVA2_VideoDesc desc = { 0 };
+ DXVA2_ConfigPictureDecode config;
+ HRESULT hr;
+ int surface_alignment;
+ int ret;
+
+ hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n");
+ goto fail;
+ }
+
+ for (i = 0; dxva2_modes[i].guid; i++) {
+ D3DFORMAT *target_list = NULL;
+ unsigned target_count = 0;
+ const dxva2_mode *mode = &dxva2_modes[i];
+ if (mode->codec != s->codec_id)
+ continue;
+
+ for (j = 0; j < guid_count; j++) {
+ if (IsEqualGUID(mode->guid, &guid_list[j]))
+ break;
+ }
+ if (j == guid_count)
+ continue;
+
+ hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list);
+ if (FAILED(hr)) {
+ continue;
+ }
+ for (j = 0; j < target_count; j++) {
+ const D3DFORMAT format = target_list[j];
+ if (format == MKTAG('N','V','1','2')) {
+ target_format = format;
+ break;
+ }
+ }
+ CoTaskMemFree(target_list);
+ if (target_format) {
+ device_guid = *mode->guid;
+ break;
+ }
+ }
+ CoTaskMemFree(guid_list);
+
+ if (IsEqualGUID(&device_guid, &GUID_NULL)) {
+ av_log(NULL, loglevel, "No decoder device for codec found\n");
+ goto fail;
+ }
+
+ desc.SampleWidth = s->coded_width;
+ desc.SampleHeight = s->coded_height;
+ desc.Format = target_format;
+
+ ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
+ but it causes issues for H.264 on certain AMD GPUs..... */
+ if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+ surface_alignment = 32;
+ /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
+ all coding features have enough room to work with */
+ else if (s->codec_id == AV_CODEC_ID_HEVC)
+ surface_alignment = 128;
+ else
+ surface_alignment = 16;
+
+ /* 4 base work surfaces */
+ ctx->num_surfaces = 4;
+
+ /* add surfaces based on number of possible refs */
+ if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)
+ ctx->num_surfaces += 16;
+ else
+ ctx->num_surfaces += 2;
+
+ /* add extra surfaces for frame threading */
+ if (s->active_thread_type & FF_THREAD_FRAME)
+ ctx->num_surfaces += s->thread_count;
+
+ ctx->surfaces = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));
+ ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos));
+
+ if (!ctx->surfaces || !ctx->surface_infos) {
+ av_log(NULL, loglevel, "Unable to allocate surface arrays\n");
+ goto fail;
+ }
+
+ hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service,
+ FFALIGN(s->coded_width, surface_alignment),
+ FFALIGN(s->coded_height, surface_alignment),
+ ctx->num_surfaces - 1,
+ target_format, D3DPOOL_DEFAULT, 0,
+ DXVA2_VideoDecoderRenderTarget,
+ ctx->surfaces, NULL);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to create %d video surfaces\n", ctx->num_surfaces);
+ goto fail;
+ }
+
+ hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid,
+ &desc, &config, ctx->surfaces,
+ ctx->num_surfaces, &ctx->decoder);
+ if (FAILED(hr)) {
+ av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n");
+ goto fail;
+ }
+
+ ctx->decoder_guid = device_guid;
+ ctx->decoder_config = config;
+
+ dxva_ctx->cfg = &ctx->decoder_config;
+ dxva_ctx->decoder = ctx->decoder;
+ dxva_ctx->surface = ctx->surfaces;
+ dxva_ctx->surface_count = ctx->num_surfaces;
+
+ if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E))
+ dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
+
+ return 0;
+fail:
+ dxva2_destroy_decoder(s);
+ return AVERROR(EINVAL);
+}
+
+int dxva2_init(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ DXVA2Context *ctx;
+ int ret;
+
+ if (!ist->hwaccel_ctx) {
+ ret = dxva2_alloc(s);
+ if (ret < 0)
+ return ret;
+ }
+ ctx = ist->hwaccel_ctx;
+
+ if (s->codec_id == AV_CODEC_ID_H264 &&
+ (s->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) {
+ av_log(NULL, loglevel, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s->profile);
+ return AVERROR(EINVAL);
+ }
+
+ if (ctx->decoder)
+ dxva2_destroy_decoder(s);
+
+ ret = dxva2_create_decoder(s);
+ if (ret < 0) {
+ av_log(NULL, loglevel, "Error creating the DXVA2 decoder\n");
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/ffmpeg_filter.c b/ffmpeg_filter.c
new file mode 100644
index 0000000000..0be49bea87
--- /dev/null
+++ b/ffmpeg_filter.c
@@ -0,0 +1,1010 @@
+/*
+ * ffmpeg filter configuration
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdint.h>
+
+#include "ffmpeg.h"
+
+#include "libavfilter/avfilter.h"
+#include "libavfilter/buffersink.h"
+
+#include "libavresample/avresample.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/display.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/samplefmt.h"
+
+enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCodec *codec, enum AVPixelFormat target)
+{
+ if (codec && codec->pix_fmts) {
+ const enum AVPixelFormat *p = codec->pix_fmts;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target);
+ int has_alpha = desc ? desc->nb_components % 2 == 0 : 0;
+ enum AVPixelFormat best= AV_PIX_FMT_NONE;
+ static const enum AVPixelFormat mjpeg_formats[] =
+ { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE };
+ static const enum AVPixelFormat ljpeg_formats[] =
+ { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
+
+ if (enc_ctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
+ if (enc_ctx->codec_id == AV_CODEC_ID_MJPEG) {
+ p = mjpeg_formats;
+ } else if (enc_ctx->codec_id == AV_CODEC_ID_LJPEG) {
+ p =ljpeg_formats;
+ }
+ }
+ for (; *p != AV_PIX_FMT_NONE; p++) {
+ best= avcodec_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL);
+ if (*p == target)
+ break;
+ }
+ if (*p == AV_PIX_FMT_NONE) {
+ if (target != AV_PIX_FMT_NONE)
+ 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,
+ av_get_pix_fmt_name(best));
+ return best;
+ }
+ }
+ return target;
+}
+
+void choose_sample_fmt(AVStream *st, AVCodec *codec)
+{
+ if (codec && codec->sample_fmts) {
+ const enum AVSampleFormat *p = codec->sample_fmts;
+ for (; *p != -1; p++) {
+ if (*p == st->codec->sample_fmt)
+ break;
+ }
+ if (*p == -1) {
+ if((codec->capabilities & CODEC_CAP_LOSSLESS) && av_get_sample_fmt_name(st->codec->sample_fmt) > av_get_sample_fmt_name(codec->sample_fmts[0]))
+ av_log(NULL, AV_LOG_ERROR, "Conversion will not be lossless.\n");
+ if(av_get_sample_fmt_name(st->codec->sample_fmt))
+ av_log(NULL, AV_LOG_WARNING,
+ "Incompatible sample format '%s' for codec '%s', auto-selecting format '%s'\n",
+ av_get_sample_fmt_name(st->codec->sample_fmt),
+ codec->name,
+ av_get_sample_fmt_name(codec->sample_fmts[0]));
+ st->codec->sample_fmt = codec->sample_fmts[0];
+ }
+ }
+}
+
+static char *choose_pix_fmts(OutputStream *ost)
+{
+ AVDictionaryEntry *strict_dict = av_dict_get(ost->encoder_opts, "strict", NULL, 0);
+ if (strict_dict)
+ // used by choose_pixel_fmt() and below
+ av_opt_set(ost->enc_ctx, "strict", strict_dict->value, 0);
+
+ if (ost->keep_pix_fmt) {
+ if (ost->filter)
+ avfilter_graph_set_auto_convert(ost->filter->graph->graph,
+ AVFILTER_AUTO_CONVERT_NONE);
+ if (ost->enc_ctx->pix_fmt == AV_PIX_FMT_NONE)
+ return NULL;
+ return av_strdup(av_get_pix_fmt_name(ost->enc_ctx->pix_fmt));
+ }
+ if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
+ return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->pix_fmt)));
+ } else if (ost->enc && ost->enc->pix_fmts) {
+ const enum AVPixelFormat *p;
+ AVIOContext *s = NULL;
+ uint8_t *ret;
+ int len;
+
+ if (avio_open_dyn_buf(&s) < 0)
+ exit_program(1);
+
+ p = ost->enc->pix_fmts;
+ if (ost->enc_ctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
+ if (ost->enc_ctx->codec_id == AV_CODEC_ID_MJPEG) {
+ p = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE };
+ } else if (ost->enc_ctx->codec_id == AV_CODEC_ID_LJPEG) {
+ p = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
+ }
+ }
+
+ for (; *p != AV_PIX_FMT_NONE; p++) {
+ const char *name = av_get_pix_fmt_name(*p);
+ avio_printf(s, "%s|", name);
+ }
+ len = avio_close_dyn_buf(s, &ret);
+ ret[len - 1] = 0;
+ return ret;
+ } else
+ return NULL;
+}
+
+/* Define a function for building a string containing a list of
+ * allowed formats. */
+#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \
+static char *choose_ ## var ## s(OutputStream *ost) \
+{ \
+ if (ost->enc_ctx->var != none) { \
+ get_name(ost->enc_ctx->var); \
+ return av_strdup(name); \
+ } else if (ost->enc && ost->enc->supported_list) { \
+ const type *p; \
+ AVIOContext *s = NULL; \
+ uint8_t *ret; \
+ int len; \
+ \
+ if (avio_open_dyn_buf(&s) < 0) \
+ exit_program(1); \
+ \
+ for (p = ost->enc->supported_list; *p != none; p++) { \
+ get_name(*p); \
+ avio_printf(s, "%s|", name); \
+ } \
+ len = avio_close_dyn_buf(s, &ret); \
+ ret[len - 1] = 0; \
+ return ret; \
+ } else \
+ return NULL; \
+}
+
+// DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE,
+// GET_PIX_FMT_NAME)
+
+DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts,
+ AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME)
+
+DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0,
+ GET_SAMPLE_RATE_NAME)
+
+DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0,
+ GET_CH_LAYOUT_NAME)
+
+FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost)
+{
+ FilterGraph *fg = av_mallocz(sizeof(*fg));
+
+ if (!fg)
+ exit_program(1);
+ fg->index = nb_filtergraphs;
+
+ GROW_ARRAY(fg->outputs, fg->nb_outputs);
+ if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0]))))
+ exit_program(1);
+ fg->outputs[0]->ost = ost;
+ fg->outputs[0]->graph = fg;
+
+ ost->filter = fg->outputs[0];
+
+ GROW_ARRAY(fg->inputs, fg->nb_inputs);
+ if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0]))))
+ exit_program(1);
+ fg->inputs[0]->ist = ist;
+ fg->inputs[0]->graph = fg;
+
+ GROW_ARRAY(ist->filters, ist->nb_filters);
+ ist->filters[ist->nb_filters - 1] = fg->inputs[0];
+
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ filtergraphs[nb_filtergraphs - 1] = fg;
+
+ return fg;
+}
+
+static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
+{
+ InputStream *ist = NULL;
+ enum AVMediaType type = avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx);
+ int i;
+
+ // TODO: support other filter types
+ if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported "
+ "currently.\n");
+ exit_program(1);
+ }
+
+ if (in->name) {
+ AVFormatContext *s;
+ AVStream *st = NULL;
+ char *p;
+ int file_idx = strtol(in->name, &p, 0);
+
+ if (file_idx < 0 || file_idx >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtergraph description %s.\n",
+ file_idx, fg->graph_desc);
+ exit_program(1);
+ }
+ s = input_files[file_idx]->ctx;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ enum AVMediaType stream_type = s->streams[i]->codec->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) {
+ st = s->streams[i];
+ break;
+ }
+ }
+ if (!st) {
+ av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s "
+ "matches no streams.\n", p, fg->graph_desc);
+ exit_program(1);
+ }
+ ist = input_streams[input_files[file_idx]->ist_index + st->index];
+ } else {
+ /* find the first unused stream of corresponding type */
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (ist->dec_ctx->codec_type == type && ist->discard)
+ break;
+ }
+ if (i == nb_input_streams) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for "
+ "unlabeled input pad %d on filter %s\n", in->pad_idx,
+ in->filter_ctx->name);
+ exit_program(1);
+ }
+ }
+ av_assert0(ist);
+
+ ist->discard = 0;
+ ist->decoding_needed |= DECODING_FOR_FILTER;
+ ist->st->discard = AVDISCARD_NONE;
+
+ GROW_ARRAY(fg->inputs, fg->nb_inputs);
+ if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0]))))
+ exit_program(1);
+ fg->inputs[fg->nb_inputs - 1]->ist = ist;
+ fg->inputs[fg->nb_inputs - 1]->graph = fg;
+
+ GROW_ARRAY(ist->filters, ist->nb_filters);
+ ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
+}
+
+static int insert_trim(int64_t start_time, int64_t duration,
+ AVFilterContext **last_filter, int *pad_idx,
+ const char *filter_name)
+{
+ AVFilterGraph *graph = (*last_filter)->graph;
+ AVFilterContext *ctx;
+ const AVFilter *trim;
+ enum AVMediaType type = avfilter_pad_get_type((*last_filter)->output_pads, *pad_idx);
+ const char *name = (type == AVMEDIA_TYPE_VIDEO) ? "trim" : "atrim";
+ int ret = 0;
+
+ if (duration == INT64_MAX && start_time == AV_NOPTS_VALUE)
+ return 0;
+
+ trim = avfilter_get_by_name(name);
+ if (!trim) {
+ av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit "
+ "recording time.\n", name);
+ return AVERROR_FILTER_NOT_FOUND;
+ }
+
+ ctx = avfilter_graph_alloc_filter(graph, trim, filter_name);
+ if (!ctx)
+ return AVERROR(ENOMEM);
+
+ if (duration != INT64_MAX) {
+ ret = av_opt_set_int(ctx, "durationi", duration,
+ AV_OPT_SEARCH_CHILDREN);
+ }
+ if (ret >= 0 && start_time != AV_NOPTS_VALUE) {
+ ret = av_opt_set_int(ctx, "starti", start_time,
+ AV_OPT_SEARCH_CHILDREN);
+ }
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name);
+ return ret;
+ }
+
+ ret = avfilter_init_str(ctx, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
+ if (ret < 0)
+ return ret;
+
+ *last_filter = ctx;
+ *pad_idx = 0;
+ return 0;
+}
+
+static int insert_filter(AVFilterContext **last_filter, int *pad_idx,
+ const char *filter_name, const char *args)
+{
+ AVFilterGraph *graph = (*last_filter)->graph;
+ AVFilterContext *ctx;
+ int ret;
+
+ ret = avfilter_graph_create_filter(&ctx,
+ avfilter_get_by_name(filter_name),
+ filter_name, args, NULL, graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
+ if (ret < 0)
+ return ret;
+
+ *last_filter = ctx;
+ *pad_idx = 0;
+ return 0;
+}
+
+static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+ char *pix_fmts;
+ OutputStream *ost = ofilter->ost;
+ OutputFile *of = output_files[ost->file_index];
+ AVCodecContext *codec = ost->enc_ctx;
+ AVFilterContext *last_filter = out->filter_ctx;
+ int pad_idx = out->pad_idx;
+ int ret;
+ char name[255];
+
+ snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&ofilter->filter,
+ avfilter_get_by_name("buffersink"),
+ name, NULL, NULL, fg->graph);
+
+ if (ret < 0)
+ return ret;
+
+ if (codec->width || codec->height) {
+ char args[255];
+ AVFilterContext *filter;
+
+ snprintf(args, sizeof(args), "%d:%d:0x%X",
+ codec->width,
+ codec->height,
+ (unsigned)ost->sws_flags);
+ snprintf(name, sizeof(name), "scaler for output stream %d:%d",
+ ost->file_index, ost->index);
+ if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
+ name, args, NULL, fg->graph)) < 0)
+ return ret;
+ if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
+ return ret;
+
+ last_filter = filter;
+ pad_idx = 0;
+ }
+
+ if ((pix_fmts = choose_pix_fmts(ost))) {
+ AVFilterContext *filter;
+ snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&filter,
+ avfilter_get_by_name("format"),
+ "format", pix_fmts, NULL, fg->graph);
+ av_freep(&pix_fmts);
+ if (ret < 0)
+ return ret;
+ if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
+ return ret;
+
+ last_filter = filter;
+ pad_idx = 0;
+ }
+
+ if (ost->frame_rate.num && 0) {
+ AVFilterContext *fps;
+ char args[255];
+
+ snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
+ ost->frame_rate.den);
+ snprintf(name, sizeof(name), "fps for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
+ name, args, NULL, fg->graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(last_filter, pad_idx, fps, 0);
+ if (ret < 0)
+ return ret;
+ last_filter = fps;
+ pad_idx = 0;
+ }
+
+ snprintf(name, sizeof(name), "trim for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = insert_trim(of->start_time, of->recording_time,
+ &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+
+ if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+ OutputStream *ost = ofilter->ost;
+ OutputFile *of = output_files[ost->file_index];
+ AVCodecContext *codec = ost->enc_ctx;
+ AVFilterContext *last_filter = out->filter_ctx;
+ int pad_idx = out->pad_idx;
+ char *sample_fmts, *sample_rates, *channel_layouts;
+ char name[255];
+ int ret;
+
+ snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&ofilter->filter,
+ avfilter_get_by_name("abuffersink"),
+ name, NULL, NULL, fg->graph);
+ if (ret < 0)
+ return ret;
+ if ((ret = av_opt_set_int(ofilter->filter, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
+ return ret;
+
+#define AUTO_INSERT_FILTER(opt_name, filter_name, arg) do { \
+ AVFilterContext *filt_ctx; \
+ \
+ av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
+ "similarly to -af " filter_name "=%s.\n", arg); \
+ \
+ ret = avfilter_graph_create_filter(&filt_ctx, \
+ avfilter_get_by_name(filter_name), \
+ filter_name, arg, NULL, fg->graph); \
+ if (ret < 0) \
+ return ret; \
+ \
+ ret = avfilter_link(last_filter, pad_idx, filt_ctx, 0); \
+ if (ret < 0) \
+ return ret; \
+ \
+ last_filter = filt_ctx; \
+ pad_idx = 0; \
+} while (0)
+ if (ost->audio_channels_mapped) {
+ int i;
+ AVBPrint pan_buf;
+ av_bprint_init(&pan_buf, 256, 8192);
+ av_bprintf(&pan_buf, "0x%"PRIx64,
+ av_get_default_channel_layout(ost->audio_channels_mapped));
+ for (i = 0; i < ost->audio_channels_mapped; i++)
+ if (ost->audio_channels_map[i] != -1)
+ av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+
+ AUTO_INSERT_FILTER("-map_channel", "pan", pan_buf.str);
+ av_bprint_finalize(&pan_buf, NULL);
+ }
+
+ if (codec->channels && !codec->channel_layout)
+ codec->channel_layout = av_get_default_channel_layout(codec->channels);
+
+ sample_fmts = choose_sample_fmts(ost);
+ sample_rates = choose_sample_rates(ost);
+ channel_layouts = choose_channel_layouts(ost);
+ if (sample_fmts || sample_rates || channel_layouts) {
+ AVFilterContext *format;
+ char args[256];
+ args[0] = 0;
+
+ if (sample_fmts)
+ av_strlcatf(args, sizeof(args), "sample_fmts=%s:",
+ sample_fmts);
+ if (sample_rates)
+ av_strlcatf(args, sizeof(args), "sample_rates=%s:",
+ sample_rates);
+ if (channel_layouts)
+ av_strlcatf(args, sizeof(args), "channel_layouts=%s:",
+ channel_layouts);
+
+ av_freep(&sample_fmts);
+ av_freep(&sample_rates);
+ av_freep(&channel_layouts);
+
+ snprintf(name, sizeof(name), "audio format for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = avfilter_graph_create_filter(&format,
+ avfilter_get_by_name("aformat"),
+ name, args, NULL, fg->graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(last_filter, pad_idx, format, 0);
+ if (ret < 0)
+ return ret;
+
+ last_filter = format;
+ pad_idx = 0;
+ }
+
+ if (audio_volume != 256 && 0) {
+ char args[256];
+
+ snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER("-vol", "volume", args);
+ }
+
+ if (ost->apad && of->shortest) {
+ char args[256];
+ int i;
+
+ for (i=0; i<of->ctx->nb_streams; i++)
+ if (of->ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ break;
+
+ if (i<of->ctx->nb_streams) {
+ snprintf(args, sizeof(args), "%s", ost->apad);
+ AUTO_INSERT_FILTER("-apad", "apad", args);
+ }
+ }
+
+ snprintf(name, sizeof(name), "trim for output stream %d:%d",
+ ost->file_index, ost->index);
+ ret = insert_trim(of->start_time, of->recording_time,
+ &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0)
+ return ret;
+
+ return 0;
+}
+
+#define DESCRIBE_FILTER_LINK(f, inout, in) \
+{ \
+ AVFilterContext *ctx = inout->filter_ctx; \
+ AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
+ int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
+ AVIOContext *pb; \
+ \
+ if (avio_open_dyn_buf(&pb) < 0) \
+ exit_program(1); \
+ \
+ avio_printf(pb, "%s", ctx->filter->name); \
+ if (nb_pads > 1) \
+ avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
+ avio_w8(pb, 0); \
+ avio_close_dyn_buf(pb, &f->name); \
+}
+
+int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
+{
+ av_freep(&ofilter->name);
+ DESCRIBE_FILTER_LINK(ofilter, out, 0);
+
+ switch (avfilter_pad_get_type(out->filter_ctx->output_pads, out->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: return configure_output_video_filter(fg, ofilter, out);
+ case AVMEDIA_TYPE_AUDIO: return configure_output_audio_filter(fg, ofilter, out);
+ default: av_assert0(0);
+ }
+}
+
+static int sub2video_prepare(InputStream *ist)
+{
+ AVFormatContext *avf = input_files[ist->file_index]->ctx;
+ int i, w, h;
+
+ /* Compute the size of the canvas for the subtitles stream.
+ If the subtitles codec has set a size, use it. Otherwise use the
+ maximum dimensions of the video streams in the same file. */
+ w = ist->dec_ctx->width;
+ h = ist->dec_ctx->height;
+ if (!(w && h)) {
+ for (i = 0; i < avf->nb_streams; i++) {
+ if (avf->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ w = FFMAX(w, avf->streams[i]->codec->width);
+ h = FFMAX(h, avf->streams[i]->codec->height);
+ }
+ }
+ if (!(w && h)) {
+ w = FFMAX(w, 720);
+ h = FFMAX(h, 576);
+ }
+ av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
+ }
+ ist->sub2video.w = ist->dec_ctx->width = ist->resample_width = w;
+ ist->sub2video.h = ist->dec_ctx->height = ist->resample_height = h;
+
+ /* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the
+ palettes for all rectangles are identical or compatible */
+ ist->resample_pix_fmt = ist->dec_ctx->pix_fmt = AV_PIX_FMT_RGB32;
+
+ ist->sub2video.frame = av_frame_alloc();
+ if (!ist->sub2video.frame)
+ return AVERROR(ENOMEM);
+ ist->sub2video.last_pts = INT64_MIN;
+ return 0;
+}
+
+static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
+ AVFilterInOut *in)
+{
+ AVFilterContext *last_filter;
+ const AVFilter *buffer_filt = avfilter_get_by_name("buffer");
+ InputStream *ist = ifilter->ist;
+ InputFile *f = input_files[ist->file_index];
+ AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) :
+ ist->st->time_base;
+ AVRational fr = ist->framerate;
+ AVRational sar;
+ AVBPrint args;
+ char name[255];
+ int ret, pad_idx = 0;
+ int64_t tsoffset = 0;
+
+ if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!fr.num)
+ fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL);
+
+ if (ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ ret = sub2video_prepare(ist);
+ if (ret < 0)
+ return ret;
+ }
+
+ sar = ist->st->sample_aspect_ratio.num ?
+ ist->st->sample_aspect_ratio :
+ ist->dec_ctx->sample_aspect_ratio;
+ if(!sar.den)
+ sar = (AVRational){0,1};
+ av_bprint_init(&args, 0, 1);
+ av_bprintf(&args,
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
+ "pixel_aspect=%d/%d:sws_param=flags=%d", ist->resample_width,
+ ist->resample_height,
+ ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->resample_pix_fmt,
+ tb.num, tb.den, sar.num, sar.den,
+ SWS_BILINEAR + ((ist->dec_ctx->flags&CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
+ if (fr.num && fr.den)
+ av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
+ snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
+ ist->file_index, ist->st->index);
+
+ if ((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name,
+ args.str, NULL, fg->graph)) < 0)
+ return ret;
+ last_filter = ifilter->filter;
+
+ if (ist->autorotate) {
+ double theta = get_rotation(ist->st);
+
+ if (fabs(theta - 90) < 1.0) {
+ ret = insert_filter(&last_filter, &pad_idx, "transpose", "clock");
+ } else if (fabs(theta - 180) < 1.0) {
+ ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
+ if (ret < 0)
+ return ret;
+ ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+ } else if (fabs(theta - 270) < 1.0) {
+ ret = insert_filter(&last_filter, &pad_idx, "transpose", "cclock");
+ } else if (fabs(theta) > 1.0) {
+ char rotate_buf[64];
+ snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta);
+ ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf);
+ }
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ist->framerate.num) {
+ AVFilterContext *setpts;
+
+ snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
+ ist->file_index, ist->st->index);
+ if ((ret = avfilter_graph_create_filter(&setpts,
+ avfilter_get_by_name("setpts"),
+ name, "N", NULL,
+ fg->graph)) < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
+ return ret;
+
+ last_filter = setpts;
+ }
+
+ if (do_deinterlace) {
+ AVFilterContext *yadif;
+
+ snprintf(name, sizeof(name), "deinterlace input from stream %d:%d",
+ ist->file_index, ist->st->index);
+ if ((ret = avfilter_graph_create_filter(&yadif,
+ avfilter_get_by_name("yadif"),
+ name, "", NULL,
+ fg->graph)) < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, yadif, 0)) < 0)
+ return ret;
+
+ last_filter = yadif;
+ }
+
+ snprintf(name, sizeof(name), "trim for input stream %d:%d",
+ ist->file_index, ist->st->index);
+ if (copy_ts) {
+ tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
+ if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)
+ tsoffset += f->ctx->start_time;
+ }
+ ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
+ AV_NOPTS_VALUE : tsoffset, f->recording_time,
+ &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
+ return ret;
+ return 0;
+}
+
+static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter,
+ AVFilterInOut *in)
+{
+ AVFilterContext *last_filter;
+ const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer");
+ InputStream *ist = ifilter->ist;
+ InputFile *f = input_files[ist->file_index];
+ AVBPrint args;
+ char name[255];
+ int ret, pad_idx = 0;
+ int64_t tsoffset = 0;
+
+ if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_ERROR, "Cannot connect audio filter to non audio input\n");
+ return AVERROR(EINVAL);
+ }
+
+ av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ av_bprintf(&args, "time_base=%d/%d:sample_rate=%d:sample_fmt=%s",
+ 1, ist->dec_ctx->sample_rate,
+ ist->dec_ctx->sample_rate,
+ av_get_sample_fmt_name(ist->dec_ctx->sample_fmt));
+ if (ist->dec_ctx->channel_layout)
+ av_bprintf(&args, ":channel_layout=0x%"PRIx64,
+ ist->dec_ctx->channel_layout);
+ else
+ av_bprintf(&args, ":channels=%d", ist->dec_ctx->channels);
+ snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
+ ist->file_index, ist->st->index);
+
+ if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
+ name, args.str, NULL,
+ fg->graph)) < 0)
+ return ret;
+ last_filter = ifilter->filter;
+
+#define AUTO_INSERT_FILTER_INPUT(opt_name, filter_name, arg) do { \
+ AVFilterContext *filt_ctx; \
+ \
+ av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
+ "similarly to -af " filter_name "=%s.\n", arg); \
+ \
+ snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d", \
+ fg->index, filter_name, ist->file_index, ist->st->index); \
+ ret = avfilter_graph_create_filter(&filt_ctx, \
+ avfilter_get_by_name(filter_name), \
+ name, arg, NULL, fg->graph); \
+ if (ret < 0) \
+ return ret; \
+ \
+ ret = avfilter_link(last_filter, 0, filt_ctx, 0); \
+ if (ret < 0) \
+ return ret; \
+ \
+ last_filter = filt_ctx; \
+} while (0)
+
+ if (audio_sync_method > 0) {
+ char args[256] = {0};
+
+ av_strlcatf(args, sizeof(args), "async=%d", audio_sync_method);
+ if (audio_drift_threshold != 0.1)
+ av_strlcatf(args, sizeof(args), ":min_hard_comp=%f", audio_drift_threshold);
+ if (!fg->reconfiguration)
+ av_strlcatf(args, sizeof(args), ":first_pts=0");
+ AUTO_INSERT_FILTER_INPUT("-async", "aresample", args);
+ }
+
+// if (ost->audio_channels_mapped) {
+// int i;
+// AVBPrint pan_buf;
+// av_bprint_init(&pan_buf, 256, 8192);
+// av_bprintf(&pan_buf, "0x%"PRIx64,
+// av_get_default_channel_layout(ost->audio_channels_mapped));
+// for (i = 0; i < ost->audio_channels_mapped; i++)
+// if (ost->audio_channels_map[i] != -1)
+// av_bprintf(&pan_buf, ":c%d=c%d", i, ost->audio_channels_map[i]);
+// AUTO_INSERT_FILTER_INPUT("-map_channel", "pan", pan_buf.str);
+// av_bprint_finalize(&pan_buf, NULL);
+// }
+
+ if (audio_volume != 256) {
+ char args[256];
+
+ av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume "
+ "audio filter instead.\n");
+
+ snprintf(args, sizeof(args), "%f", audio_volume / 256.);
+ AUTO_INSERT_FILTER_INPUT("-vol", "volume", args);
+ }
+
+ snprintf(name, sizeof(name), "trim for input stream %d:%d",
+ ist->file_index, ist->st->index);
+ if (copy_ts) {
+ tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
+ if (!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE)
+ tsoffset += f->ctx->start_time;
+ }
+ ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ?
+ AV_NOPTS_VALUE : tsoffset, f->recording_time,
+ &last_filter, &pad_idx, name);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
+ AVFilterInOut *in)
+{
+ av_freep(&ifilter->name);
+ DESCRIBE_FILTER_LINK(ifilter, in, 1);
+
+ if (!ifilter->ist->dec) {
+ av_log(NULL, AV_LOG_ERROR,
+ "No decoder for stream #%d:%d, filtering impossible\n",
+ ifilter->ist->file_index, ifilter->ist->st->index);
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+ switch (avfilter_pad_get_type(in->filter_ctx->input_pads, in->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: return configure_input_video_filter(fg, ifilter, in);
+ case AVMEDIA_TYPE_AUDIO: return configure_input_audio_filter(fg, ifilter, in);
+ default: av_assert0(0);
+ }
+}
+
+int configure_filtergraph(FilterGraph *fg)
+{
+ AVFilterInOut *inputs, *outputs, *cur;
+ int ret, i, init = !fg->graph, simple = !fg->graph_desc;
+ const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
+ fg->graph_desc;
+
+ avfilter_graph_free(&fg->graph);
+ if (!(fg->graph = avfilter_graph_alloc()))
+ return AVERROR(ENOMEM);
+
+ if (simple) {
+ OutputStream *ost = fg->outputs[0]->ost;
+ char args[512];
+ AVDictionaryEntry *e = NULL;
+
+ snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags);
+ fg->graph->scale_sws_opts = av_strdup(args);
+
+ args[0] = 0;
+ while ((e = av_dict_get(ost->swr_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX))) {
+ av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ }
+ if (strlen(args))
+ args[strlen(args)-1] = 0;
+ av_opt_set(fg->graph, "aresample_swr_opts", args, 0);
+
+ args[0] = '\0';
+ while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX))) {
+ av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value);
+ }
+ if (strlen(args))
+ args[strlen(args) - 1] = '\0';
+ fg->graph->resample_lavr_opts = av_strdup(args);
+
+ e = av_dict_get(ost->encoder_opts, "threads", NULL, 0);
+ if (e)
+ av_opt_set(fg->graph, "threads", e->value, 0);
+ }
+
+ if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
+ return ret;
+
+ if (simple && (!inputs || inputs->next || !outputs || outputs->next)) {
+ av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have "
+ "exactly one input and output.\n", graph_desc);
+ return AVERROR(EINVAL);
+ }
+
+ for (cur = inputs; !simple && init && cur; cur = cur->next)
+ init_input_filter(fg, cur);
+
+ for (cur = inputs, i = 0; cur; cur = cur->next, i++)
+ if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {
+ avfilter_inout_free(&inputs);
+ avfilter_inout_free(&outputs);
+ return ret;
+ }
+ avfilter_inout_free(&inputs);
+
+ if (!init || simple) {
+ /* we already know the mappings between lavfi outputs and output streams,
+ * so we can finish the setup */
+ for (cur = outputs, i = 0; cur; cur = cur->next, i++)
+ configure_output_filter(fg, fg->outputs[i], cur);
+ avfilter_inout_free(&outputs);
+
+ if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
+ return ret;
+ } else {
+ /* wait until output mappings are processed */
+ for (cur = outputs; cur;) {
+ GROW_ARRAY(fg->outputs, fg->nb_outputs);
+ if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0]))))
+ exit_program(1);
+ fg->outputs[fg->nb_outputs - 1]->graph = fg;
+ fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
+ cur = cur->next;
+ fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
+ }
+ }
+
+ fg->reconfiguration = 1;
+
+ for (i = 0; i < fg->nb_outputs; i++) {
+ OutputStream *ost = fg->outputs[i]->ost;
+ if (ost &&
+ ost->enc->type == AVMEDIA_TYPE_AUDIO &&
+ !(ost->enc->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE))
+ av_buffersink_set_frame_size(ost->filter->filter,
+ ost->enc_ctx->frame_size);
+ }
+
+ return 0;
+}
+
+int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
+{
+ int i;
+ for (i = 0; i < fg->nb_inputs; i++)
+ if (fg->inputs[i]->ist == ist)
+ return 1;
+ return 0;
+}
+
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
new file mode 100644
index 0000000000..1c5794ce09
--- /dev/null
+++ b/ffmpeg_opt.c
@@ -0,0 +1,3213 @@
+/*
+ * ffmpeg option parsing
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdint.h>
+
+#include "ffmpeg.h"
+#include "cmdutils.h"
+
+#include "libavformat/avformat.h"
+
+#include "libavcodec/avcodec.h"
+
+#include "libavfilter/avfilter.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/avutil.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/fifo.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/pixfmt.h"
+
+#define MATCH_PER_STREAM_OPT(name, type, outvar, fmtctx, st)\
+{\
+ int i, ret;\
+ for (i = 0; i < o->nb_ ## name; i++) {\
+ char *spec = o->name[i].specifier;\
+ if ((ret = check_stream_specifier(fmtctx, st, spec)) > 0)\
+ outvar = o->name[i].u.type;\
+ else if (ret < 0)\
+ exit_program(1);\
+ }\
+}
+
+#define MATCH_PER_TYPE_OPT(name, type, outvar, fmtctx, mediatype)\
+{\
+ int i;\
+ for (i = 0; i < o->nb_ ## name; i++) {\
+ char *spec = o->name[i].specifier;\
+ if (!strcmp(spec, mediatype))\
+ outvar = o->name[i].u.type;\
+ }\
+}
+
+const HWAccel hwaccels[] = {
+#if HAVE_VDPAU_X11
+ { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
+#endif
+#if HAVE_DXVA2_LIB
+ { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD },
+#endif
+#if CONFIG_VDA
+ { "vda", vda_init, HWACCEL_VDA, AV_PIX_FMT_VDA },
+#endif
+ { 0 },
+};
+
+char *vstats_filename;
+char *sdp_filename;
+
+float audio_drift_threshold = 0.1;
+float dts_delta_threshold = 10;
+float dts_error_threshold = 3600*30;
+
+int audio_volume = 256;
+int audio_sync_method = 0;
+int video_sync_method = VSYNC_AUTO;
+float frame_drop_threshold = 0;
+int do_deinterlace = 0;
+int do_benchmark = 0;
+int do_benchmark_all = 0;
+int do_hex_dump = 0;
+int do_pkt_dump = 0;
+int copy_ts = 0;
+int start_at_zero = 0;
+int copy_tb = -1;
+int debug_ts = 0;
+int exit_on_error = 0;
+int print_stats = -1;
+int qp_hist = 0;
+int stdin_interaction = 1;
+int frame_bits_per_raw_sample = 0;
+float max_error_rate = 2.0/3;
+
+
+static int intra_only = 0;
+static int file_overwrite = 0;
+static int no_file_overwrite = 0;
+static int do_psnr = 0;
+static int input_sync;
+static int override_ffserver = 0;
+static int input_stream_potentially_available = 0;
+static int ignore_unknown_streams = 0;
+static int copy_unknown_streams = 0;
+
+static void uninit_options(OptionsContext *o)
+{
+ const OptionDef *po = options;
+ int i;
+
+ /* all OPT_SPEC and OPT_STRING can be freed in generic way */
+ while (po->name) {
+ void *dst = (uint8_t*)o + po->u.off;
+
+ if (po->flags & OPT_SPEC) {
+ SpecifierOpt **so = dst;
+ int i, *count = (int*)(so + 1);
+ for (i = 0; i < *count; i++) {
+ av_freep(&(*so)[i].specifier);
+ if (po->flags & OPT_STRING)
+ av_freep(&(*so)[i].u.str);
+ }
+ av_freep(so);
+ *count = 0;
+ } else if (po->flags & OPT_OFFSET && po->flags & OPT_STRING)
+ av_freep(dst);
+ po++;
+ }
+
+ for (i = 0; i < o->nb_stream_maps; i++)
+ av_freep(&o->stream_maps[i].linklabel);
+ av_freep(&o->stream_maps);
+ av_freep(&o->audio_channel_maps);
+ av_freep(&o->streamid_map);
+ av_freep(&o->attachments);
+}
+
+static void init_options(OptionsContext *o)
+{
+ memset(o, 0, sizeof(*o));
+
+ o->stop_time = INT64_MAX;
+ o->mux_max_delay = 0.7;
+ o->start_time = AV_NOPTS_VALUE;
+ o->recording_time = INT64_MAX;
+ o->limit_filesize = UINT64_MAX;
+ o->chapters_input_file = INT_MAX;
+ o->accurate_seek = 1;
+}
+
+/* return a copy of the input with the stream specifiers removed from the keys */
+static AVDictionary *strip_specifiers(AVDictionary *dict)
+{
+ AVDictionaryEntry *e = NULL;
+ AVDictionary *ret = NULL;
+
+ while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ char *p = strchr(e->key, ':');
+
+ if (p)
+ *p = 0;
+ av_dict_set(&ret, e->key, e->value, 0);
+ if (p)
+ *p = ':';
+ }
+ return ret;
+}
+
+static int opt_sameq(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. "
+ "If you are looking for an option to preserve the quality (which is not "
+ "what -%s was for), use -qscale 0 or an equivalent quality factor option.\n",
+ opt, opt);
+ return AVERROR(EINVAL);
+}
+
+static int opt_video_channel(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -channel.\n");
+ return opt_default(optctx, "channel", arg);
+}
+
+static int opt_video_standard(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "This option is deprecated, use -standard.\n");
+ return opt_default(optctx, "standard", arg);
+}
+
+static int opt_audio_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:a", arg, options);
+}
+
+static int opt_video_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:v", arg, options);
+}
+
+static int opt_subtitle_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:s", arg, options);
+}
+
+static int opt_data_codec(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "codec:d", arg, options);
+}
+
+static int opt_map(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ StreamMap *m = NULL;
+ int i, negative = 0, file_idx;
+ int sync_file_idx = -1, sync_stream_idx = 0;
+ char *p, *sync;
+ char *map;
+
+ if (*arg == '-') {
+ negative = 1;
+ arg++;
+ }
+ map = av_strdup(arg);
+ if (!map)
+ return AVERROR(ENOMEM);
+
+ /* parse sync stream first, just pick first matching stream */
+ if (sync = strchr(map, ',')) {
+ *sync = 0;
+ sync_file_idx = strtol(sync + 1, &sync, 0);
+ if (sync_file_idx >= nb_input_files || sync_file_idx < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid sync file index: %d.\n", sync_file_idx);
+ exit_program(1);
+ }
+ if (*sync)
+ sync++;
+ for (i = 0; i < input_files[sync_file_idx]->nb_streams; i++)
+ if (check_stream_specifier(input_files[sync_file_idx]->ctx,
+ input_files[sync_file_idx]->ctx->streams[i], sync) == 1) {
+ sync_stream_idx = i;
+ break;
+ }
+ if (i == input_files[sync_file_idx]->nb_streams) {
+ av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s does not "
+ "match any streams.\n", arg);
+ exit_program(1);
+ }
+ }
+
+
+ if (map[0] == '[') {
+ /* this mapping refers to lavfi output */
+ const char *c = map + 1;
+ GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
+ 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);
+ exit_program(1);
+ }
+ } else {
+ file_idx = strtol(map, &p, 0);
+ if (file_idx >= nb_input_files || file_idx < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index: %d.\n", file_idx);
+ exit_program(1);
+ }
+ 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,
+ input_files[m->file_index]->ctx->streams[m->stream_index],
+ *p == ':' ? p + 1 : p) > 0)
+ 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)
+ continue;
+ GROW_ARRAY(o->stream_maps, o->nb_stream_maps);
+ m = &o->stream_maps[o->nb_stream_maps - 1];
+
+ m->file_index = file_idx;
+ m->stream_index = i;
+
+ if (sync_file_idx >= 0) {
+ m->sync_file_index = sync_file_idx;
+ m->sync_stream_index = sync_stream_idx;
+ } else {
+ m->sync_file_index = file_idx;
+ m->sync_stream_index = i;
+ }
+ }
+ }
+
+ if (!m) {
+ av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n", arg);
+ exit_program(1);
+ }
+
+ av_freep(&map);
+ return 0;
+}
+
+static int opt_attach(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ GROW_ARRAY(o->attachments, o->nb_attachments);
+ o->attachments[o->nb_attachments - 1] = arg;
+ return 0;
+}
+
+static int opt_map_channel(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ int n;
+ AVStream *st;
+ AudioChannelMap *m;
+
+ GROW_ARRAY(o->audio_channel_maps, o->nb_audio_channel_maps);
+ m = &o->audio_channel_maps[o->nb_audio_channel_maps - 1];
+
+ /* muted channel syntax */
+ n = sscanf(arg, "%d:%d.%d", &m->channel_idx, &m->ofile_idx, &m->ostream_idx);
+ if ((n == 1 || n == 3) && m->channel_idx == -1) {
+ m->file_idx = m->stream_idx = -1;
+ if (n == 1)
+ m->ofile_idx = m->ostream_idx = -1;
+ return 0;
+ }
+
+ /* normal syntax */
+ n = sscanf(arg, "%d.%d.%d:%d.%d",
+ &m->file_idx, &m->stream_idx, &m->channel_idx,
+ &m->ofile_idx, &m->ostream_idx);
+
+ if (n != 3 && n != 5) {
+ av_log(NULL, AV_LOG_FATAL, "Syntax error, mapchan usage: "
+ "[file.stream.channel|-1][:syncfile:syncstream]\n");
+ exit_program(1);
+ }
+
+ if (n != 5) // only file.stream.channel specified
+ m->ofile_idx = m->ostream_idx = -1;
+
+ /* check input */
+ if (m->file_idx < 0 || m->file_idx >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file index: %d\n",
+ m->file_idx);
+ exit_program(1);
+ }
+ if (m->stream_idx < 0 ||
+ m->stream_idx >= input_files[m->file_idx]->nb_streams) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid input file stream index #%d.%d\n",
+ m->file_idx, m->stream_idx);
+ exit_program(1);
+ }
+ st = input_files[m->file_idx]->ctx->streams[m->stream_idx];
+ if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: stream #%d.%d is not an audio stream.\n",
+ m->file_idx, m->stream_idx);
+ exit_program(1);
+ }
+ if (m->channel_idx < 0 || m->channel_idx >= st->codec->channels) {
+ av_log(NULL, AV_LOG_FATAL, "mapchan: invalid audio channel #%d.%d.%d\n",
+ m->file_idx, m->stream_idx, m->channel_idx);
+ exit_program(1);
+ }
+ return 0;
+}
+
+static int opt_sdp_file(void *optctx, const char *opt, const char *arg)
+{
+ av_free(sdp_filename);
+ sdp_filename = av_strdup(arg);
+ return 0;
+}
+
+/**
+ * Parse a metadata specifier passed as 'arg' parameter.
+ * @param arg metadata string to parse
+ * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram)
+ * @param index for type c/p, chapter/program index is written here
+ * @param stream_spec for type s, the stream specifier is written here
+ */
+static void parse_meta_type(char *arg, char *type, int *index, const char **stream_spec)
+{
+ if (*arg) {
+ *type = *arg;
+ switch (*arg) {
+ case 'g':
+ break;
+ case 's':
+ if (*(++arg) && *arg != ':') {
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg);
+ exit_program(1);
+ }
+ *stream_spec = *arg == ':' ? arg + 1 : "";
+ break;
+ case 'c':
+ case 'p':
+ if (*(++arg) == ':')
+ *index = strtol(++arg, NULL, 0);
+ break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg);
+ exit_program(1);
+ }
+ } else
+ *type = 'g';
+}
+
+static int copy_metadata(char *outspec, char *inspec, AVFormatContext *oc, AVFormatContext *ic, OptionsContext *o)
+{
+ AVDictionary **meta_in = NULL;
+ AVDictionary **meta_out = NULL;
+ int i, ret = 0;
+ char type_in, type_out;
+ const char *istream_spec = NULL, *ostream_spec = NULL;
+ int idx_in = 0, idx_out = 0;
+
+ parse_meta_type(inspec, &type_in, &idx_in, &istream_spec);
+ parse_meta_type(outspec, &type_out, &idx_out, &ostream_spec);
+
+ if (!ic) {
+ if (type_out == 'g' || !*outspec)
+ o->metadata_global_manual = 1;
+ if (type_out == 's' || !*outspec)
+ o->metadata_streams_manual = 1;
+ if (type_out == 'c' || !*outspec)
+ o->metadata_chapters_manual = 1;
+ return 0;
+ }
+
+ if (type_in == 'g' || type_out == 'g')
+ o->metadata_global_manual = 1;
+ if (type_in == 's' || type_out == 's')
+ o->metadata_streams_manual = 1;
+ if (type_in == 'c' || type_out == 'c')
+ o->metadata_chapters_manual = 1;
+
+ /* ic is NULL when just disabling automatic mappings */
+ if (!ic)
+ return 0;
+
+#define METADATA_CHECK_INDEX(index, nb_elems, desc)\
+ if ((index) < 0 || (index) >= (nb_elems)) {\
+ av_log(NULL, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\
+ (desc), (index));\
+ exit_program(1);\
+ }
+
+#define SET_DICT(type, meta, context, index)\
+ switch (type) {\
+ case 'g':\
+ meta = &context->metadata;\
+ break;\
+ case 'c':\
+ METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\
+ meta = &context->chapters[index]->metadata;\
+ break;\
+ case 'p':\
+ METADATA_CHECK_INDEX(index, context->nb_programs, "program")\
+ meta = &context->programs[index]->metadata;\
+ break;\
+ case 's':\
+ break; /* handled separately below */ \
+ default: av_assert0(0);\
+ }\
+
+ SET_DICT(type_in, meta_in, ic, idx_in);
+ SET_DICT(type_out, meta_out, oc, idx_out);
+
+ /* for input streams choose first matching stream */
+ if (type_in == 's') {
+ for (i = 0; i < ic->nb_streams; i++) {
+ if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) {
+ meta_in = &ic->streams[i]->metadata;
+ break;
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ if (!meta_in) {
+ av_log(NULL, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec);
+ exit_program(1);
+ }
+ }
+
+ if (type_out == 's') {
+ for (i = 0; i < oc->nb_streams; i++) {
+ if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) {
+ meta_out = &oc->streams[i]->metadata;
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ } else
+ av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE);
+
+ return 0;
+}
+
+static int opt_recording_timestamp(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char buf[128];
+ int64_t recording_timestamp = parse_time_or_die(opt, arg, 0) / 1E6;
+ struct tm time = *gmtime((time_t*)&recording_timestamp);
+ if (!strftime(buf, sizeof(buf), "creation_time=%Y-%m-%dT%H:%M:%S%z", &time))
+ return -1;
+ parse_option(o, "metadata", buf, options);
+
+ av_log(NULL, AV_LOG_WARNING, "%s is deprecated, set the 'creation_time' metadata "
+ "tag instead.\n", opt);
+ return 0;
+}
+
+static AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
+{
+ const AVCodecDescriptor *desc;
+ const char *codec_string = encoder ? "encoder" : "decoder";
+ AVCodec *codec;
+
+ codec = encoder ?
+ avcodec_find_encoder_by_name(name) :
+ avcodec_find_decoder_by_name(name);
+
+ if (!codec && (desc = avcodec_descriptor_get_by_name(name))) {
+ codec = encoder ? avcodec_find_encoder(desc->id) :
+ avcodec_find_decoder(desc->id);
+ if (codec)
+ av_log(NULL, AV_LOG_VERBOSE, "Matched %s '%s' for codec '%s'.\n",
+ codec_string, codec->name, desc->name);
+ }
+
+ if (!codec) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown %s '%s'\n", codec_string, name);
+ exit_program(1);
+ }
+ if (codec->type != type) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid %s type '%s'\n", codec_string, name);
+ exit_program(1);
+ }
+ return codec;
+}
+
+static AVCodec *choose_decoder(OptionsContext *o, AVFormatContext *s, AVStream *st)
+{
+ char *codec_name = NULL;
+
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
+ if (codec_name) {
+ AVCodec *codec = find_codec_or_die(codec_name, st->codec->codec_type, 0);
+ st->codec->codec_id = codec->id;
+ return codec;
+ } else
+ return avcodec_find_decoder(st->codec->codec_id);
+}
+
+/* Add all the streams from the given input file to the global
+ * list of input streams. */
+static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
+{
+ int i, ret;
+
+ for (i = 0; i < ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+ AVCodecContext *dec = st->codec;
+ InputStream *ist = av_mallocz(sizeof(*ist));
+ char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL;
+ char *codec_tag = NULL;
+ char *next;
+ char *discard_str = NULL;
+ const AVOption *discard_opt = av_opt_find(dec, "skip_frame", NULL, 0, 0);
+
+ if (!ist)
+ exit_program(1);
+
+ GROW_ARRAY(input_streams, nb_input_streams);
+ input_streams[nb_input_streams - 1] = ist;
+
+ ist->st = st;
+ ist->file_index = nb_input_files;
+ ist->discard = 1;
+ st->discard = AVDISCARD_ALL;
+
+ ist->ts_scale = 1.0;
+ MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
+
+ ist->autorotate = 1;
+ MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ st->codec->codec_tag = tag;
+ }
+
+ ist->dec = choose_decoder(o, ic, st);
+ ist->decoder_opts = filter_codec_opts(o->g->codec_opts, ist->st->codec->codec_id, ic, st, ist->dec);
+
+ ist->reinit_filters = -1;
+ MATCH_PER_STREAM_OPT(reinit_filters, i, ist->reinit_filters, ic, st);
+
+ MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);
+ ist->user_set_discard = AVDISCARD_NONE;
+ if (discard_str && av_opt_eval_int(dec, discard_opt, discard_str, &ist->user_set_discard) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing discard %s.\n",
+ discard_str);
+ exit_program(1);
+ }
+
+ ist->filter_in_rescale_delta_last = AV_NOPTS_VALUE;
+
+ ist->dec_ctx = avcodec_alloc_context3(ist->dec);
+ if (!ist->dec_ctx) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating the decoder context.\n");
+ exit_program(1);
+ }
+
+ ret = avcodec_copy_context(ist->dec_ctx, dec);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error initializing the decoder context.\n");
+ exit_program(1);
+ }
+
+ switch (dec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ if (av_codec_get_lowres(dec)) {
+ dec->flags |= CODEC_FLAG_EMU_EDGE;
+ }
+
+ ist->resample_height = ist->dec_ctx->height;
+ ist->resample_width = ist->dec_ctx->width;
+ ist->resample_pix_fmt = ist->dec_ctx->pix_fmt;
+
+ MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
+ if (framerate && av_parse_video_rate(&ist->framerate,
+ framerate) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing framerate %s.\n",
+ framerate);
+ exit_program(1);
+ }
+
+ ist->top_field_first = -1;
+ MATCH_PER_STREAM_OPT(top_field_first, i, ist->top_field_first, ic, st);
+
+ MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
+ if (hwaccel) {
+ if (!strcmp(hwaccel, "none"))
+ ist->hwaccel_id = HWACCEL_NONE;
+ else if (!strcmp(hwaccel, "auto"))
+ ist->hwaccel_id = HWACCEL_AUTO;
+ else {
+ int i;
+ for (i = 0; hwaccels[i].name; i++) {
+ if (!strcmp(hwaccels[i].name, hwaccel)) {
+ ist->hwaccel_id = hwaccels[i].id;
+ break;
+ }
+ }
+
+ if (!ist->hwaccel_id) {
+ av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n",
+ hwaccel);
+ av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: ");
+ for (i = 0; hwaccels[i].name; i++)
+ av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name);
+ av_log(NULL, AV_LOG_FATAL, "\n");
+ exit_program(1);
+ }
+ }
+ }
+
+ MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
+ if (hwaccel_device) {
+ ist->hwaccel_device = av_strdup(hwaccel_device);
+ if (!ist->hwaccel_device)
+ exit_program(1);
+ }
+ ist->hwaccel_pix_fmt = AV_PIX_FMT_NONE;
+
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ ist->guess_layout_max = INT_MAX;
+ MATCH_PER_STREAM_OPT(guess_layout_max, i, ist->guess_layout_max, ic, st);
+ guess_input_channel_layout(ist);
+
+ ist->resample_sample_fmt = ist->dec_ctx->sample_fmt;
+ ist->resample_sample_rate = ist->dec_ctx->sample_rate;
+ ist->resample_channels = ist->dec_ctx->channels;
+ ist->resample_channel_layout = ist->dec_ctx->channel_layout;
+
+ break;
+ case AVMEDIA_TYPE_DATA:
+ case AVMEDIA_TYPE_SUBTITLE: {
+ char *canvas_size = NULL;
+ if(!ist->dec)
+ ist->dec = avcodec_find_decoder(dec->codec_id);
+ 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);
+ if (canvas_size &&
+ av_parse_video_size(&ist->dec_ctx->width, &ist->dec_ctx->height, canvas_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid canvas size: %s.\n", canvas_size);
+ exit_program(1);
+ }
+ break;
+ }
+ case AVMEDIA_TYPE_ATTACHMENT:
+ case AVMEDIA_TYPE_UNKNOWN:
+ break;
+ default:
+ abort();
+ }
+ }
+}
+
+static void assert_file_overwrite(const char *filename)
+{
+ if (file_overwrite && no_file_overwrite) {
+ fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n");
+ exit_program(1);
+ }
+
+ if (!file_overwrite) {
+ const char *proto_name = avio_find_protocol_name(filename);
+ if (proto_name && !strcmp(proto_name, "file") && avio_check(filename, 0) == 0) {
+ if (stdin_interaction && !no_file_overwrite) {
+ fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename);
+ fflush(stderr);
+ term_exit();
+ signal(SIGINT, SIG_DFL);
+ if (!read_yesno()) {
+ av_log(NULL, AV_LOG_FATAL, "Not overwriting - exiting\n");
+ exit_program(1);
+ }
+ term_init();
+ }
+ else {
+ av_log(NULL, AV_LOG_FATAL, "File '%s' already exists. Exiting.\n", filename);
+ exit_program(1);
+ }
+ }
+ }
+}
+
+static void dump_attachment(AVStream *st, const char *filename)
+{
+ int ret;
+ AVIOContext *out = NULL;
+ AVDictionaryEntry *e;
+
+ if (!st->codec->extradata_size) {
+ av_log(NULL, AV_LOG_WARNING, "No extradata to dump in stream #%d:%d.\n",
+ nb_input_files - 1, st->index);
+ return;
+ }
+ if (!*filename && (e = av_dict_get(st->metadata, "filename", NULL, 0)))
+ filename = e->value;
+ if (!*filename) {
+ av_log(NULL, AV_LOG_FATAL, "No filename specified and no 'filename' tag"
+ "in stream #%d:%d.\n", nb_input_files - 1, st->index);
+ exit_program(1);
+ }
+
+ assert_file_overwrite(filename);
+
+ if ((ret = avio_open2(&out, filename, AVIO_FLAG_WRITE, &int_cb, NULL)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open file %s for writing.\n",
+ filename);
+ exit_program(1);
+ }
+
+ avio_write(out, st->codec->extradata, st->codec->extradata_size);
+ avio_flush(out);
+ avio_close(out);
+}
+
+static int open_input_file(OptionsContext *o, const char *filename)
+{
+ InputFile *f;
+ AVFormatContext *ic;
+ AVInputFormat *file_iformat = NULL;
+ int err, i, ret;
+ int64_t timestamp;
+ AVDictionary **opts;
+ AVDictionary *unused_opts = NULL;
+ AVDictionaryEntry *e = NULL;
+ int orig_nb_streams; // number of streams before avformat_find_stream_info
+ char * video_codec_name = NULL;
+ char * audio_codec_name = NULL;
+ char *subtitle_codec_name = NULL;
+ char * data_codec_name = NULL;
+ int scan_all_pmts_set = 0;
+
+ if (o->format) {
+ if (!(file_iformat = av_find_input_format(o->format))) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format);
+ exit_program(1);
+ }
+ }
+
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+
+ stdin_interaction &= strncmp(filename, "pipe:", 5) &&
+ strcmp(filename, "/dev/stdin");
+
+ /* get default parameters from command line */
+ ic = avformat_alloc_context();
+ if (!ic) {
+ print_error(filename, AVERROR(ENOMEM));
+ exit_program(1);
+ }
+ if (o->nb_audio_sample_rate) {
+ av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0);
+ }
+ if (o->nb_audio_channels) {
+ /* because we set audio_channels based on both the "ac" and
+ * "channel_layout" options, we need to check that the specified
+ * demuxer actually has the "channels" option before setting it */
+ if (file_iformat && file_iformat->priv_class &&
+ av_opt_find(&file_iformat->priv_class, "channels", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ av_dict_set_int(&o->g->format_opts, "channels", o->audio_channels[o->nb_audio_channels - 1].u.i, 0);
+ }
+ }
+ if (o->nb_frame_rates) {
+ /* set the format-level framerate option;
+ * this is important for video grabbers, e.g. x11 */
+ if (file_iformat && file_iformat->priv_class &&
+ av_opt_find(&file_iformat->priv_class, "framerate", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ)) {
+ av_dict_set(&o->g->format_opts, "framerate",
+ o->frame_rates[o->nb_frame_rates - 1].u.str, 0);
+ }
+ }
+ if (o->nb_frame_sizes) {
+ av_dict_set(&o->g->format_opts, "video_size", o->frame_sizes[o->nb_frame_sizes - 1].u.str, 0);
+ }
+ if (o->nb_frame_pix_fmts)
+ av_dict_set(&o->g->format_opts, "pixel_format", o->frame_pix_fmts[o->nb_frame_pix_fmts - 1].u.str, 0);
+
+ MATCH_PER_TYPE_OPT(codec_names, str, video_codec_name, ic, "v");
+ MATCH_PER_TYPE_OPT(codec_names, str, audio_codec_name, ic, "a");
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s");
+ MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d");
+
+ ic->video_codec_id = video_codec_name ?
+ find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE;
+ ic->audio_codec_id = audio_codec_name ?
+ find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE;
+ ic->subtitle_codec_id= subtitle_codec_name ?
+ find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE;
+ ic->data_codec_id = data_codec_name ?
+ find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE;
+
+ if (video_codec_name)
+ av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0));
+ if (audio_codec_name)
+ av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0));
+ if (subtitle_codec_name)
+ av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0));
+ if (data_codec_name)
+ av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0));
+
+ ic->flags |= AVFMT_FLAG_NONBLOCK;
+ ic->interrupt_callback = int_cb;
+
+ if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
+ av_dict_set(&o->g->format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
+ scan_all_pmts_set = 1;
+ }
+ /* open the input file with generic avformat function */
+ err = avformat_open_input(&ic, filename, file_iformat, &o->g->format_opts);
+ if (err < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ if (scan_all_pmts_set)
+ av_dict_set(&o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
+ remove_avoptions(&o->g->format_opts, o->g->codec_opts);
+ assert_avoptions(o->g->format_opts);
+
+ /* apply forced codec ids */
+ for (i = 0; i < ic->nb_streams; i++)
+ choose_decoder(o, ic, ic->streams[i]);
+
+ /* Set AVCodecContext options for avformat_find_stream_info */
+ opts = setup_find_stream_info_opts(ic, o->g->codec_opts);
+ orig_nb_streams = ic->nb_streams;
+
+ /* If not enough info to get the stream parameters, we decode the
+ first frames to get it. (used in mpeg case for example) */
+ ret = avformat_find_stream_info(ic, opts);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "%s: could not find codec parameters\n", filename);
+ if (ic->nb_streams == 0) {
+ avformat_close_input(&ic);
+ exit_program(1);
+ }
+ }
+
+ timestamp = (o->start_time == AV_NOPTS_VALUE) ? 0 : o->start_time;
+ /* add the stream start time */
+ if (!o->seek_timestamp && ic->start_time != AV_NOPTS_VALUE)
+ timestamp += ic->start_time;
+
+ /* if seeking requested, we execute it */
+ if (o->start_time != AV_NOPTS_VALUE) {
+ int64_t seek_timestamp = timestamp;
+
+ if (!(ic->iformat->flags & AVFMT_SEEK_TO_PTS)) {
+ int dts_heuristic = 0;
+ for (i=0; i<ic->nb_streams; i++) {
+ AVCodecContext *avctx = ic->streams[i]->codec;
+ if (avctx->has_b_frames)
+ dts_heuristic = 1;
+ }
+ if (dts_heuristic) {
+ seek_timestamp -= 3*AV_TIME_BASE / 23;
+ }
+ }
+ ret = avformat_seek_file(ic, -1, INT64_MIN, seek_timestamp, seek_timestamp, 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
+ filename, (double)timestamp / AV_TIME_BASE);
+ }
+ }
+
+ /* update the current parameters so that they match the one of the input stream */
+ add_input_streams(o, ic);
+
+ /* dump the file content */
+ av_dump_format(ic, nb_input_files, filename, 0);
+
+ GROW_ARRAY(input_files, nb_input_files);
+ f = av_mallocz(sizeof(*f));
+ if (!f)
+ exit_program(1);
+ input_files[nb_input_files - 1] = f;
+
+ f->ctx = ic;
+ f->ist_index = nb_input_streams - ic->nb_streams;
+ f->start_time = o->start_time;
+ f->recording_time = o->recording_time;
+ f->input_ts_offset = o->input_ts_offset;
+ f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
+ f->nb_streams = ic->nb_streams;
+ f->rate_emu = o->rate_emu;
+ f->accurate_seek = o->accurate_seek;
+#if HAVE_PTHREADS
+ f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;
+#endif
+
+ /* check if all codec options have been used */
+ unused_opts = strip_specifiers(o->g->codec_opts);
+ for (i = f->ist_index; i < nb_input_streams; i++) {
+ e = NULL;
+ while ((e = av_dict_get(input_streams[i]->decoder_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX)))
+ av_dict_set(&unused_opts, e->key, NULL, 0);
+ }
+
+ e = NULL;
+ while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ 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(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
+ "input file #%d (%s) is not a decoding option.\n", e->key,
+ option->help ? option->help : "", nb_input_files - 1,
+ filename);
+ exit_program(1);
+ }
+
+ av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
+ "input file #%d (%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 : "", nb_input_files - 1, filename);
+ }
+ av_dict_free(&unused_opts);
+
+ for (i = 0; i < o->nb_dump_attachment; i++) {
+ int j;
+
+ for (j = 0; j < ic->nb_streams; j++) {
+ AVStream *st = ic->streams[j];
+
+ if (check_stream_specifier(ic, st, o->dump_attachment[i].specifier) == 1)
+ dump_attachment(st, o->dump_attachment[i].u.str);
+ }
+ }
+
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ input_stream_potentially_available = 1;
+
+ return 0;
+}
+
+static uint8_t *get_line(AVIOContext *s)
+{
+ AVIOContext *line;
+ uint8_t *buf;
+ char c;
+
+ if (avio_open_dyn_buf(&line) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not alloc buffer for reading preset.\n");
+ exit_program(1);
+ }
+
+ while ((c = avio_r8(s)) && c != '\n')
+ avio_w8(line, c);
+ avio_w8(line, 0);
+ avio_close_dyn_buf(line, &buf);
+
+ return buf;
+}
+
+static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s)
+{
+ int i, ret = -1;
+ char filename[1000];
+ const char *base[3] = { getenv("AVCONV_DATADIR"),
+ getenv("HOME"),
+ AVCONV_DATADIR,
+ };
+
+ for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) {
+ if (!base[i])
+ continue;
+ if (codec_name) {
+ snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", codec_name, preset_name);
+ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
+ }
+ if (ret < 0) {
+ snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i],
+ i != 1 ? "" : "/.avconv", preset_name);
+ ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL);
+ }
+ }
+ return ret;
+}
+
+static void choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *ost)
+{
+ char *codec_name = NULL;
+
+ MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
+ if (!codec_name) {
+ ost->st->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename,
+ NULL, ost->st->codec->codec_type);
+ ost->enc = avcodec_find_encoder(ost->st->codec->codec_id);
+ } else if (!strcmp(codec_name, "copy"))
+ ost->stream_copy = 1;
+ else {
+ ost->enc = find_codec_or_die(codec_name, ost->st->codec->codec_type, 1);
+ ost->st->codec->codec_id = ost->enc->id;
+ }
+}
+
+static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, enum AVMediaType type, int source_index)
+{
+ OutputStream *ost;
+ AVStream *st = avformat_new_stream(oc, NULL);
+ int idx = oc->nb_streams - 1, ret = 0;
+ char *bsf = NULL, *next, *codec_tag = NULL;
+ AVBitStreamFilterContext *bsfc, *bsfc_prev = NULL;
+ double qscale = -1;
+ int i;
+
+ if (!st) {
+ av_log(NULL, AV_LOG_FATAL, "Could not alloc stream.\n");
+ exit_program(1);
+ }
+
+ if (oc->nb_streams - 1 < o->nb_streamid_map)
+ st->id = o->streamid_map[oc->nb_streams - 1];
+
+ GROW_ARRAY(output_streams, nb_output_streams);
+ if (!(ost = av_mallocz(sizeof(*ost))))
+ exit_program(1);
+ output_streams[nb_output_streams - 1] = ost;
+
+ ost->file_index = nb_output_files - 1;
+ ost->index = idx;
+ ost->st = st;
+ st->codec->codec_type = type;
+ choose_encoder(o, oc, ost);
+
+ ost->enc_ctx = avcodec_alloc_context3(ost->enc);
+ if (!ost->enc_ctx) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating the encoding context.\n");
+ exit_program(1);
+ }
+ ost->enc_ctx->codec_type = type;
+
+ if (ost->enc) {
+ AVIOContext *s = NULL;
+ char *buf = NULL, *arg = NULL, *preset = NULL;
+
+ ost->encoder_opts = filter_codec_opts(o->g->codec_opts, ost->enc->id, oc, st, ost->enc);
+
+ MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
+ if (preset && (!(ret = get_preset_file_2(preset, ost->enc->name, &s)))) {
+ do {
+ buf = get_line(s);
+ if (!buf[0] || buf[0] == '#') {
+ av_free(buf);
+ continue;
+ }
+ if (!(arg = strchr(buf, '='))) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid line found in the preset file.\n");
+ exit_program(1);
+ }
+ *arg++ = 0;
+ av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE);
+ av_free(buf);
+ } while (!s->eof_reached);
+ avio_closep(&s);
+ }
+ if (ret) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Preset %s specified for stream %d:%d, but could not be opened.\n",
+ preset, ost->file_index, ost->index);
+ exit_program(1);
+ }
+ } else {
+ ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL);
+ }
+
+ ost->max_frames = INT64_MAX;
+ MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st);
+ for (i = 0; i<o->nb_max_frames; i++) {
+ char *p = o->max_frames[i].specifier;
+ if (!*p && type != AVMEDIA_TYPE_VIDEO) {
+ av_log(NULL, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n");
+ break;
+ }
+ }
+
+ ost->copy_prior_start = -1;
+ MATCH_PER_STREAM_OPT(copy_prior_start, i, ost->copy_prior_start, oc ,st);
+
+ MATCH_PER_STREAM_OPT(bitstream_filters, str, bsf, oc, st);
+ while (bsf) {
+ char *arg = NULL;
+ if (next = strchr(bsf, ','))
+ *next++ = 0;
+ if (arg = strchr(bsf, '='))
+ *arg++ = 0;
+ if (!(bsfc = av_bitstream_filter_init(bsf))) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown bitstream filter %s\n", bsf);
+ exit_program(1);
+ }
+ if (bsfc_prev)
+ bsfc_prev->next = bsfc;
+ else
+ ost->bitstream_filters = bsfc;
+ av_dict_set(&ost->bsf_args, bsfc->filter->name, arg, 0);
+
+ bsfc_prev = bsfc;
+ bsf = next;
+ }
+
+ MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
+ if (codec_tag) {
+ uint32_t tag = strtol(codec_tag, &next, 0);
+ if (*next)
+ tag = AV_RL32(codec_tag);
+ ost->enc_ctx->codec_tag = tag;
+ }
+
+ MATCH_PER_STREAM_OPT(qscale, dbl, qscale, oc, st);
+ if (qscale >= 0) {
+ ost->enc_ctx->flags |= CODEC_FLAG_QSCALE;
+ ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;
+ }
+
+ MATCH_PER_STREAM_OPT(disposition, str, ost->disposition, oc, st);
+ ost->disposition = av_strdup(ost->disposition);
+
+ if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+ ost->enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ av_opt_get_int(o->g->sws_opts, "sws_flags", 0, &ost->sws_flags);
+
+ av_dict_copy(&ost->swr_opts, o->g->swr_opts, 0);
+ if (ost->enc && av_get_exact_bits_per_sample(ost->enc->id) == 24)
+ av_dict_set(&ost->swr_opts, "output_sample_bits", "24", 0);
+
+ av_dict_copy(&ost->resample_opts, o->g->resample_opts, 0);
+
+ ost->source_index = source_index;
+ if (source_index >= 0) {
+ ost->sync_ist = input_streams[source_index];
+ input_streams[source_index]->discard = 0;
+ input_streams[source_index]->st->discard = input_streams[source_index]->user_set_discard;
+ }
+ ost->last_mux_dts = AV_NOPTS_VALUE;
+
+ return ost;
+}
+
+static void parse_matrix_coeffs(uint16_t *dest, const char *str)
+{
+ int i;
+ const char *p = str;
+ for (i = 0;; i++) {
+ dest[i] = atoi(p);
+ if (i == 63)
+ break;
+ p = strchr(p, ',');
+ if (!p) {
+ av_log(NULL, AV_LOG_FATAL, "Syntax error in matrix \"%s\" at coeff %d\n", str, i);
+ exit_program(1);
+ }
+ p++;
+ }
+}
+
+/* read file contents into a string */
+static uint8_t *read_file(const char *filename)
+{
+ AVIOContext *pb = NULL;
+ AVIOContext *dyn_buf = NULL;
+ int ret = avio_open(&pb, filename, AVIO_FLAG_READ);
+ uint8_t buf[1024], *str;
+
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename);
+ return NULL;
+ }
+
+ ret = avio_open_dyn_buf(&dyn_buf);
+ if (ret < 0) {
+ avio_closep(&pb);
+ return NULL;
+ }
+ while ((ret = avio_read(pb, buf, sizeof(buf))) > 0)
+ avio_write(dyn_buf, buf, ret);
+ avio_w8(dyn_buf, 0);
+ avio_closep(&pb);
+
+ ret = avio_close_dyn_buf(dyn_buf, &str);
+ if (ret < 0)
+ return NULL;
+ return str;
+}
+
+static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc,
+ OutputStream *ost)
+{
+ AVStream *st = ost->st;
+
+ if (ost->filters_script && ost->filters) {
+ av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for "
+ "output stream #%d:%d.\n", nb_output_files, st->index);
+ exit_program(1);
+ }
+
+ if (ost->filters_script)
+ return read_file(ost->filters_script);
+ else if (ost->filters)
+ return av_strdup(ost->filters);
+
+ return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ?
+ "null" : "anull");
+}
+
+static void check_streamcopy_filters(OptionsContext *o, AVFormatContext *oc,
+ const OutputStream *ost, enum AVMediaType type)
+{
+ if (ost->filters_script || ost->filters) {
+ av_log(NULL, AV_LOG_ERROR,
+ "%s '%s' was defined for %s output stream %d:%d but codec copy was selected.\n"
+ "Filtering and streamcopy cannot be used together.\n",
+ ost->filters ? "Filtergraph" : "Filtergraph script",
+ ost->filters ? ost->filters : ost->filters_script,
+ av_get_media_type_string(type), ost->file_index, ost->index);
+ exit_program(1);
+ }
+}
+
+static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ AVStream *st;
+ OutputStream *ost;
+ AVCodecContext *video_enc;
+ char *frame_rate = NULL, *frame_aspect_ratio = NULL;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index);
+ st = ost->st;
+ video_enc = ost->enc_ctx;
+
+ MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
+ if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
+ exit_program(1);
+ }
+ if (frame_rate && video_sync_method == VSYNC_PASSTHROUGH)
+ av_log(NULL, AV_LOG_ERROR, "Using -vsync 0 and -r can produce invalid output files\n");
+
+ MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
+ if (frame_aspect_ratio) {
+ AVRational q;
+ if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
+ q.num <= 0 || q.den <= 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio);
+ exit_program(1);
+ }
+ ost->frame_aspect_ratio = q;
+ }
+
+ MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
+ MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
+
+ if (!ost->stream_copy) {
+ const char *p = NULL;
+ char *frame_size = NULL;
+ char *frame_pix_fmt = NULL;
+ char *intra_matrix = NULL, *inter_matrix = NULL;
+ char *chroma_intra_matrix = NULL;
+ int do_pass = 0;
+ int i;
+
+ MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ if (frame_size && av_parse_video_size(&video_enc->width, &video_enc->height, frame_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+ exit_program(1);
+ }
+
+ video_enc->bits_per_raw_sample = frame_bits_per_raw_sample;
+ MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
+ if (frame_pix_fmt && *frame_pix_fmt == '+') {
+ ost->keep_pix_fmt = 1;
+ if (!*++frame_pix_fmt)
+ frame_pix_fmt = NULL;
+ }
+ if (frame_pix_fmt && (video_enc->pix_fmt = av_get_pix_fmt(frame_pix_fmt)) == AV_PIX_FMT_NONE) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", frame_pix_fmt);
+ exit_program(1);
+ }
+ st->sample_aspect_ratio = video_enc->sample_aspect_ratio;
+
+ if (intra_only)
+ video_enc->gop_size = 0;
+ MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
+ if (intra_matrix) {
+ if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
+ exit_program(1);
+ }
+ parse_matrix_coeffs(video_enc->intra_matrix, intra_matrix);
+ }
+ MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);
+ if (chroma_intra_matrix) {
+ uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
+ if (!p) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n");
+ exit_program(1);
+ }
+ av_codec_set_chroma_intra_matrix(video_enc, p);
+ parse_matrix_coeffs(p, chroma_intra_matrix);
+ }
+ MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
+ if (inter_matrix) {
+ if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for inter matrix.\n");
+ exit_program(1);
+ }
+ parse_matrix_coeffs(video_enc->inter_matrix, inter_matrix);
+ }
+
+ MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
+ for (i = 0; p; i++) {
+ int start, end, q;
+ int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
+ if (e != 3) {
+ av_log(NULL, AV_LOG_FATAL, "error parsing rc_override\n");
+ exit_program(1);
+ }
+ video_enc->rc_override =
+ av_realloc_array(video_enc->rc_override,
+ i + 1, sizeof(RcOverride));
+ if (!video_enc->rc_override) {
+ av_log(NULL, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n");
+ exit_program(1);
+ }
+ video_enc->rc_override[i].start_frame = start;
+ video_enc->rc_override[i].end_frame = end;
+ if (q > 0) {
+ video_enc->rc_override[i].qscale = q;
+ video_enc->rc_override[i].quality_factor = 1.0;
+ }
+ else {
+ video_enc->rc_override[i].qscale = 0;
+ video_enc->rc_override[i].quality_factor = -q/100.0;
+ }
+ p = strchr(p, '/');
+ if (p) p++;
+ }
+ video_enc->rc_override_count = i;
+
+ if (do_psnr)
+ video_enc->flags|= CODEC_FLAG_PSNR;
+
+ /* two pass mode */
+ MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st);
+ if (do_pass) {
+ if (do_pass & 1) {
+ video_enc->flags |= CODEC_FLAG_PASS1;
+ av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND);
+ }
+ if (do_pass & 2) {
+ video_enc->flags |= 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);
+ if (ost->logfile_prefix &&
+ !(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
+ exit_program(1);
+
+ MATCH_PER_STREAM_OPT(forced_key_frames, str, ost->forced_keyframes, oc, st);
+ if (ost->forced_keyframes)
+ ost->forced_keyframes = av_strdup(ost->forced_keyframes);
+
+ MATCH_PER_STREAM_OPT(force_fps, i, ost->force_fps, oc, st);
+
+ ost->top_field_first = -1;
+ MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
+
+
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
+ } else {
+ MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st);
+ }
+
+ if (ost->stream_copy)
+ check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_VIDEO);
+
+ return ost;
+}
+
+static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ int n;
+ AVStream *st;
+ OutputStream *ost;
+ AVCodecContext *audio_enc;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_AUDIO, source_index);
+ st = ost->st;
+
+ audio_enc = ost->enc_ctx;
+ audio_enc->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st);
+ MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st);
+
+ if (!ost->stream_copy) {
+ char *sample_fmt = NULL;
+
+ MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st);
+
+ MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
+ if (sample_fmt &&
+ (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
+ exit_program(1);
+ }
+
+ MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
+
+ MATCH_PER_STREAM_OPT(apad, str, ost->apad, oc, st);
+ ost->apad = av_strdup(ost->apad);
+
+ ost->avfilter = get_ost_filters(o, oc, ost);
+ if (!ost->avfilter)
+ exit_program(1);
+
+ /* check for channel mapping for this audio stream */
+ for (n = 0; n < o->nb_audio_channel_maps; n++) {
+ AudioChannelMap *map = &o->audio_channel_maps[n];
+ if ((map->ofile_idx == -1 || ost->file_index == map->ofile_idx) &&
+ (map->ostream_idx == -1 || ost->st->index == map->ostream_idx)) {
+ InputStream *ist;
+
+ if (map->channel_idx == -1) {
+ ist = NULL;
+ } else if (ost->source_index < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot determine input stream for channel mapping %d.%d\n",
+ ost->file_index, ost->st->index);
+ continue;
+ } else {
+ ist = input_streams[ost->source_index];
+ }
+
+ if (!ist || (ist->file_index == map->file_idx && ist->st->index == map->stream_idx)) {
+ if (av_reallocp_array(&ost->audio_channels_map,
+ ost->audio_channels_mapped + 1,
+ sizeof(*ost->audio_channels_map)
+ ) < 0 )
+ exit_program(1);
+
+ ost->audio_channels_map[ost->audio_channels_mapped++] = map->channel_idx;
+ }
+ }
+ }
+ }
+
+ if (ost->stream_copy)
+ check_streamcopy_filters(o, oc, ost, AVMEDIA_TYPE_AUDIO);
+
+ return ost;
+}
+
+static OutputStream *new_data_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ OutputStream *ost;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_DATA, source_index);
+ if (!ost->stream_copy) {
+ av_log(NULL, AV_LOG_FATAL, "Data stream encoding not supported yet (only streamcopy)\n");
+ exit_program(1);
+ }
+
+ return ost;
+}
+
+static OutputStream *new_unknown_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ OutputStream *ost;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_UNKNOWN, source_index);
+ if (!ost->stream_copy) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown stream encoding not supported yet (only streamcopy)\n");
+ exit_program(1);
+ }
+
+ return ost;
+}
+
+static OutputStream *new_attachment_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ OutputStream *ost = new_output_stream(o, oc, AVMEDIA_TYPE_ATTACHMENT, source_index);
+ ost->stream_copy = 1;
+ ost->finished = 1;
+ return ost;
+}
+
+static OutputStream *new_subtitle_stream(OptionsContext *o, AVFormatContext *oc, int source_index)
+{
+ AVStream *st;
+ OutputStream *ost;
+ AVCodecContext *subtitle_enc;
+
+ ost = new_output_stream(o, oc, AVMEDIA_TYPE_SUBTITLE, source_index);
+ st = ost->st;
+ subtitle_enc = ost->enc_ctx;
+
+ subtitle_enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
+
+ MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc, st);
+
+ if (!ost->stream_copy) {
+ char *frame_size = NULL;
+
+ MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ if (frame_size && av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size);
+ exit_program(1);
+ }
+ }
+
+ return ost;
+}
+
+/* arg format is "output-stream-index:streamid-value". */
+static int opt_streamid(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ int idx;
+ char *p;
+ char idx_str[16];
+
+ av_strlcpy(idx_str, arg, sizeof(idx_str));
+ p = strchr(idx_str, ':');
+ if (!p) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Invalid value '%s' for option '%s', required syntax is 'index:value'\n",
+ arg, opt);
+ exit_program(1);
+ }
+ *p++ = '\0';
+ idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1);
+ o->streamid_map = grow_array(o->streamid_map, sizeof(*o->streamid_map), &o->nb_streamid_map, idx+1);
+ o->streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX);
+ return 0;
+}
+
+static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata)
+{
+ AVFormatContext *is = ifile->ctx;
+ AVFormatContext *os = ofile->ctx;
+ AVChapter **tmp;
+ int i;
+
+ tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ os->chapters = tmp;
+
+ for (i = 0; i < is->nb_chapters; i++) {
+ AVChapter *in_ch = is->chapters[i], *out_ch;
+ int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time;
+ int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset,
+ AV_TIME_BASE_Q, in_ch->time_base);
+ int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX :
+ av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base);
+
+
+ if (in_ch->end < ts_off)
+ continue;
+ if (rt != INT64_MAX && in_ch->start > rt + ts_off)
+ break;
+
+ out_ch = av_mallocz(sizeof(AVChapter));
+ if (!out_ch)
+ return AVERROR(ENOMEM);
+
+ out_ch->id = in_ch->id;
+ out_ch->time_base = in_ch->time_base;
+ out_ch->start = FFMAX(0, in_ch->start - ts_off);
+ out_ch->end = FFMIN(rt, in_ch->end - ts_off);
+
+ if (copy_metadata)
+ av_dict_copy(&out_ch->metadata, in_ch->metadata, 0);
+
+ os->chapters[os->nb_chapters++] = out_ch;
+ }
+ return 0;
+}
+
+static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename)
+{
+ int i, err;
+ AVFormatContext *ic = avformat_alloc_context();
+
+ ic->interrupt_callback = int_cb;
+ err = avformat_open_input(&ic, filename, NULL, NULL);
+ if (err < 0)
+ return err;
+ /* copy stream format */
+ for(i=0;i<ic->nb_streams;i++) {
+ AVStream *st;
+ OutputStream *ost;
+ AVCodec *codec;
+ const char *enc_config;
+
+ codec = avcodec_find_encoder(ic->streams[i]->codec->codec_id);
+ if (!codec) {
+ av_log(s, AV_LOG_ERROR, "no encoder found for codec id %i\n", ic->streams[i]->codec->codec_id);
+ return AVERROR(EINVAL);
+ }
+ if (codec->type == AVMEDIA_TYPE_AUDIO)
+ opt_audio_codec(o, "c:a", codec->name);
+ else if (codec->type == AVMEDIA_TYPE_VIDEO)
+ opt_video_codec(o, "c:v", codec->name);
+ ost = new_output_stream(o, s, codec->type, -1);
+ st = ost->st;
+
+ avcodec_get_context_defaults3(st->codec, codec);
+ enc_config = av_stream_get_recommended_encoder_configuration(ic->streams[i]);
+ if (enc_config) {
+ AVDictionary *opts = NULL;
+ av_dict_parse_string(&opts, enc_config, "=", ",", 0);
+ av_opt_set_dict2(st->codec, &opts, AV_OPT_SEARCH_CHILDREN);
+ av_dict_free(&opts);
+ }
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy)
+ choose_sample_fmt(st, codec);
+ else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy)
+ choose_pixel_fmt(st, st->codec, codec, st->codec->pix_fmt);
+ avcodec_copy_context(ost->enc_ctx, st->codec);
+ if (enc_config)
+ av_dict_parse_string(&ost->encoder_opts, enc_config, "=", ",", 0);
+ }
+
+ avformat_close_input(&ic);
+ return err;
+}
+
+static void init_output_filter(OutputFilter *ofilter, OptionsContext *o,
+ AVFormatContext *oc)
+{
+ OutputStream *ost;
+
+ switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
+ ofilter->out_tmp->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream(o, oc, -1); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream(o, oc, -1); break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Only video and audio filters are supported "
+ "currently.\n");
+ exit_program(1);
+ }
+
+ ost->source_index = -1;
+ ost->filter = ofilter;
+
+ ofilter->ost = ost;
+
+ if (ost->stream_copy) {
+ av_log(NULL, AV_LOG_ERROR, "Streamcopy requested for output stream %d:%d, "
+ "which is fed from a complex filtergraph. Filtering and streamcopy "
+ "cannot be used together.\n", ost->file_index, ost->index);
+ exit_program(1);
+ }
+
+ if (ost->avfilter && (ost->filters || ost->filters_script)) {
+ const char *opt = ost->filters ? "-vf/-af/-filter" : "-filter_script";
+ av_log(NULL, AV_LOG_ERROR,
+ "%s '%s' was specified through the %s option "
+ "for output stream %d:%d, which is fed from a complex filtergraph.\n"
+ "%s and -filter_complex cannot be used together for the same stream.\n",
+ ost->filters ? "Filtergraph" : "Filtergraph script",
+ ost->filters ? ost->filters : ost->filters_script,
+ opt, ost->file_index, ost->index, opt);
+ exit_program(1);
+ }
+
+ if (configure_output_filter(ofilter->graph, ofilter, ofilter->out_tmp) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error configuring filter.\n");
+ exit_program(1);
+ }
+ avfilter_inout_free(&ofilter->out_tmp);
+}
+
+static int configure_complex_filters(void)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < nb_filtergraphs; i++)
+ if (!filtergraphs[i]->graph &&
+ (ret = configure_filtergraph(filtergraphs[i])) < 0)
+ return ret;
+ return 0;
+}
+
+static int open_output_file(OptionsContext *o, const char *filename)
+{
+ AVFormatContext *oc;
+ int i, j, err;
+ AVOutputFormat *file_oformat;
+ OutputFile *of;
+ OutputStream *ost;
+ InputStream *ist;
+ AVDictionary *unused_opts = NULL;
+ AVDictionaryEntry *e = NULL;
+
+ if (configure_complex_filters() < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
+ exit_program(1);
+ }
+
+ if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {
+ o->stop_time = INT64_MAX;
+ av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
+ }
+
+ if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {
+ int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
+ if (o->stop_time <= start_time) {
+ av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n");
+ exit_program(1);
+ } else {
+ o->recording_time = o->stop_time - start_time;
+ }
+ }
+
+ GROW_ARRAY(output_files, nb_output_files);
+ of = av_mallocz(sizeof(*of));
+ if (!of)
+ exit_program(1);
+ output_files[nb_output_files - 1] = of;
+
+ of->ost_index = nb_output_streams;
+ of->recording_time = o->recording_time;
+ of->start_time = o->start_time;
+ of->limit_filesize = o->limit_filesize;
+ of->shortest = o->shortest;
+ av_dict_copy(&of->opts, o->g->format_opts, 0);
+
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+
+ err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
+ if (!oc) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+
+ of->ctx = oc;
+ if (o->recording_time != INT64_MAX)
+ oc->duration = o->recording_time;
+
+ file_oformat= oc->oformat;
+ oc->interrupt_callback = int_cb;
+
+ /* create streams for all unlabeled output pads */
+ for (i = 0; i < nb_filtergraphs; i++) {
+ FilterGraph *fg = filtergraphs[i];
+ for (j = 0; j < fg->nb_outputs; j++) {
+ OutputFilter *ofilter = fg->outputs[j];
+
+ if (!ofilter->out_tmp || ofilter->out_tmp->name)
+ continue;
+
+ switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
+ ofilter->out_tmp->pad_idx)) {
+ case AVMEDIA_TYPE_VIDEO: o->video_disable = 1; break;
+ case AVMEDIA_TYPE_AUDIO: o->audio_disable = 1; break;
+ case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
+ }
+ init_output_filter(ofilter, o, oc);
+ }
+ }
+
+ /* ffserver seeking with date=... needs a date reference */
+ if (!strcmp(file_oformat->name, "ffm") &&
+ av_strstart(filename, "http:", NULL)) {
+ int err = parse_option(o, "metadata", "creation_time=now", options);
+ if (err < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ }
+
+ if (!strcmp(file_oformat->name, "ffm") && !override_ffserver &&
+ av_strstart(filename, "http:", NULL)) {
+ int j;
+ /* special case for files sent to ffserver: we get the stream
+ parameters from ffserver */
+ int err = read_ffserver_streams(o, oc, filename);
+ if (err < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
+ ost = output_streams[j];
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if(ist->st->codec->codec_type == ost->st->codec->codec_type){
+ ost->sync_ist= ist;
+ ost->source_index= i;
+ if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
+ if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
+ ist->discard = 0;
+ ist->st->discard = ist->user_set_discard;
+ break;
+ }
+ }
+ if(!ost->sync_ist){
+ av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codec->codec_type));
+ exit_program(1);
+ }
+ }
+ } else if (!o->nb_stream_maps) {
+ char *subtitle_codec_name = NULL;
+ /* pick the "best" stream of each type */
+
+ /* video: highest resolution */
+ if (!o->video_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO) != AV_CODEC_ID_NONE) {
+ int area = 0, idx = -1;
+ int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
+ for (i = 0; i < nb_input_streams; i++) {
+ int new_area;
+ ist = input_streams[i];
+ new_area = ist->st->codec->width * ist->st->codec->height;
+ if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ new_area = 1;
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ new_area > area) {
+ if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ continue;
+ area = new_area;
+ idx = i;
+ }
+ }
+ if (idx >= 0)
+ new_video_stream(o, oc, idx);
+ }
+
+ /* audio: most channels */
+ if (!o->audio_disable && av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_AUDIO) != AV_CODEC_ID_NONE) {
+ int channels = 0, idx = -1;
+ for (i = 0; i < nb_input_streams; i++) {
+ ist = input_streams[i];
+ if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ ist->st->codec->channels > channels) {
+ channels = ist->st->codec->channels;
+ idx = i;
+ }
+ }
+ if (idx >= 0)
+ new_audio_stream(o, oc, idx);
+ }
+
+ /* subtitles: pick first */
+ MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
+ if (!o->subtitle_disable && (avcodec_find_encoder(oc->oformat->subtitle_codec) || subtitle_codec_name)) {
+ for (i = 0; i < nb_input_streams; i++)
+ if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ AVCodecDescriptor const *input_descriptor =
+ avcodec_descriptor_get(input_streams[i]->st->codec->codec_id);
+ AVCodecDescriptor const *output_descriptor = NULL;
+ AVCodec const *output_codec =
+ avcodec_find_encoder(oc->oformat->subtitle_codec);
+ int input_props = 0, output_props = 0;
+ if (output_codec)
+ output_descriptor = avcodec_descriptor_get(output_codec->id);
+ if (input_descriptor)
+ input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+ if (output_descriptor)
+ output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB);
+ if (subtitle_codec_name ||
+ input_props & output_props ||
+ // Map dvb teletext which has neither property to any output subtitle encoder
+ input_descriptor && output_descriptor &&
+ (!input_descriptor->props ||
+ !output_descriptor->props)) {
+ new_subtitle_stream(o, oc, i);
+ break;
+ }
+ }
+ }
+ /* Data only if codec id match */
+ if (!o->data_disable ) {
+ enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA);
+ for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) {
+ if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_DATA
+ && input_streams[i]->st->codec->codec_id == codec_id )
+ new_data_stream(o, oc, i);
+ }
+ }
+ } else {
+ for (i = 0; i < o->nb_stream_maps; i++) {
+ StreamMap *map = &o->stream_maps[i];
+
+ if (map->disabled)
+ continue;
+
+ if (map->linklabel) {
+ FilterGraph *fg;
+ OutputFilter *ofilter = NULL;
+ int j, k;
+
+ for (j = 0; j < nb_filtergraphs; j++) {
+ fg = filtergraphs[j];
+ for (k = 0; k < fg->nb_outputs; k++) {
+ AVFilterInOut *out = fg->outputs[k]->out_tmp;
+ if (out && !strcmp(out->name, map->linklabel)) {
+ ofilter = fg->outputs[k];
+ goto loop_end;
+ }
+ }
+ }
+loop_end:
+ if (!ofilter) {
+ av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
+ "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
+ exit_program(1);
+ }
+ init_output_filter(ofilter, o, oc);
+ } else {
+ int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
+
+ ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
+ if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ continue;
+ if(o-> audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ continue;
+ if(o-> video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ continue;
+ if(o-> data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
+ continue;
+
+ switch (ist->st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO: ost = new_video_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_AUDIO: ost = new_audio_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_SUBTITLE: ost = new_subtitle_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_DATA: ost = new_data_stream (o, oc, src_idx); break;
+ case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
+ case AVMEDIA_TYPE_UNKNOWN:
+ if (copy_unknown_streams) {
+ ost = new_unknown_stream (o, oc, src_idx);
+ break;
+ }
+ default:
+ av_log(NULL, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL,
+ "Cannot map stream #%d:%d - unsupported type.\n",
+ map->file_index, map->stream_index);
+ if (!ignore_unknown_streams) {
+ av_log(NULL, AV_LOG_FATAL,
+ "If you want unsupported types ignored instead "
+ "of failing, please use the -ignore_unknown option\n"
+ "If you want them copied, please use -copy_unknown\n");
+ exit_program(1);
+ }
+ }
+ }
+ }
+ }
+
+ /* handle attached files */
+ for (i = 0; i < o->nb_attachments; i++) {
+ AVIOContext *pb;
+ uint8_t *attachment;
+ const char *p;
+ int64_t len;
+
+ if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if ((len = avio_size(pb)) <= 0) {
+ av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ if (!(attachment = av_malloc(len))) {
+ av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
+ o->attachments[i]);
+ exit_program(1);
+ }
+ avio_read(pb, attachment, len);
+
+ ost = new_attachment_stream(o, oc, -1);
+ ost->stream_copy = 0;
+ ost->attachment_filename = o->attachments[i];
+ ost->finished = 1;
+ ost->st->codec->extradata = attachment;
+ ost->st->codec->extradata_size = len;
+
+ p = strrchr(o->attachments[i], '/');
+ av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
+ avio_closep(&pb);
+ }
+
+ for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
+ AVDictionaryEntry *e;
+ ost = output_streams[i];
+
+ if ((ost->stream_copy || ost->attachment_filename)
+ && (e = av_dict_get(o->g->codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
+ && (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
+ if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
+ exit_program(1);
+ }
+
+ /* check if all codec options have been used */
+ unused_opts = strip_specifiers(o->g->codec_opts);
+ for (i = of->ost_index; i < nb_output_streams; i++) {
+ e = NULL;
+ while ((e = av_dict_get(output_streams[i]->encoder_opts, "", e,
+ AV_DICT_IGNORE_SUFFIX)))
+ av_dict_set(&unused_opts, e->key, NULL, 0);
+ }
+
+ e = NULL;
+ while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ 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_ENCODING_PARAM)) {
+ av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
+ "output file #%d (%s) is not an encoding option.\n", e->key,
+ option->help ? option->help : "", nb_output_files - 1,
+ filename);
+ exit_program(1);
+ }
+
+ // gop_timecode is injected by generic code but not always used
+ if (!strcmp(e->key, "gop_timecode"))
+ continue;
+
+ av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
+ "output file #%d (%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 : "", nb_output_files - 1, filename);
+ }
+ av_dict_free(&unused_opts);
+
+ /* check filename in case of an image number is expected */
+ if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
+ if (!av_filename_number_test(oc->filename)) {
+ print_error(oc->filename, AVERROR(EINVAL));
+ exit_program(1);
+ }
+ }
+
+ if (!(oc->oformat->flags & AVFMT_NOSTREAMS) && !input_stream_potentially_available) {
+ av_log(NULL, AV_LOG_ERROR,
+ "No input streams but output needs an input stream\n");
+ exit_program(1);
+ }
+
+ if (!(oc->oformat->flags & AVFMT_NOFILE)) {
+ /* test if it already exists to avoid losing precious files */
+ assert_file_overwrite(filename);
+
+ /* open the file */
+ if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
+ &oc->interrupt_callback,
+ &of->opts)) < 0) {
+ print_error(filename, err);
+ exit_program(1);
+ }
+ } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
+ assert_file_overwrite(filename);
+
+ if (o->mux_preload) {
+ av_dict_set_int(&of->opts, "preload", o->mux_preload*AV_TIME_BASE, 0);
+ }
+ oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
+
+ /* copy metadata */
+ for (i = 0; i < o->nb_metadata_map; i++) {
+ char *p;
+ int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
+
+ if (in_file_index >= nb_input_files) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
+ exit_program(1);
+ }
+ copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
+ in_file_index >= 0 ?
+ input_files[in_file_index]->ctx : NULL, o);
+ }
+
+ /* copy chapters */
+ if (o->chapters_input_file >= nb_input_files) {
+ if (o->chapters_input_file == INT_MAX) {
+ /* copy chapters from the first input file that has them*/
+ o->chapters_input_file = -1;
+ for (i = 0; i < nb_input_files; i++)
+ if (input_files[i]->ctx->nb_chapters) {
+ o->chapters_input_file = i;
+ break;
+ }
+ } else {
+ av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
+ o->chapters_input_file);
+ exit_program(1);
+ }
+ }
+ if (o->chapters_input_file >= 0)
+ copy_chapters(input_files[o->chapters_input_file], of,
+ !o->metadata_chapters_manual);
+
+ /* copy global metadata by default */
+ if (!o->metadata_global_manual && nb_input_files){
+ av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
+ AV_DICT_DONT_OVERWRITE);
+ if(o->recording_time != INT64_MAX)
+ av_dict_set(&oc->metadata, "duration", NULL, 0);
+ av_dict_set(&oc->metadata, "creation_time", NULL, 0);
+ }
+ if (!o->metadata_streams_manual)
+ for (i = of->ost_index; i < nb_output_streams; i++) {
+ InputStream *ist;
+ if (output_streams[i]->source_index < 0) /* this is true e.g. for attached files */
+ continue;
+ ist = input_streams[output_streams[i]->source_index];
+ av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
+ if (!output_streams[i]->stream_copy) {
+ av_dict_set(&output_streams[i]->st->metadata, "encoder", NULL, 0);
+ if (ist->autorotate)
+ av_dict_set(&output_streams[i]->st->metadata, "rotate", NULL, 0);
+ }
+ }
+
+ /* process manually set metadata */
+ for (i = 0; i < o->nb_metadata; i++) {
+ AVDictionary **m;
+ char type, *val;
+ const char *stream_spec;
+ int index = 0, j, ret = 0;
+
+ val = strchr(o->metadata[i].u.str, '=');
+ if (!val) {
+ av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
+ o->metadata[i].u.str);
+ exit_program(1);
+ }
+ *val++ = 0;
+
+ parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
+ if (type == 's') {
+ for (j = 0; j < oc->nb_streams; j++) {
+ ost = output_streams[nb_output_streams - oc->nb_streams + j];
+ if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
+ av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
+ if (!strcmp(o->metadata[i].u.str, "rotate")) {
+ ost->rotate_overridden = 1;
+ }
+ } else if (ret < 0)
+ exit_program(1);
+ }
+ }
+ else {
+ switch (type) {
+ case 'g':
+ m = &oc->metadata;
+ break;
+ case 'c':
+ if (index < 0 || index >= oc->nb_chapters) {
+ av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
+ exit_program(1);
+ }
+ m = &oc->chapters[index]->metadata;
+ break;
+ default:
+ av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
+ exit_program(1);
+ }
+ av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
+ }
+ }
+
+ return 0;
+}
+
+static int opt_target(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ enum { PAL, NTSC, FILM, UNKNOWN } norm = UNKNOWN;
+ static const char *const frame_rates[] = { "25", "30000/1001", "24000/1001" };
+
+ if (!strncmp(arg, "pal-", 4)) {
+ norm = PAL;
+ arg += 4;
+ } else if (!strncmp(arg, "ntsc-", 5)) {
+ norm = NTSC;
+ arg += 5;
+ } else if (!strncmp(arg, "film-", 5)) {
+ norm = FILM;
+ arg += 5;
+ } else {
+ /* Try to determine PAL/NTSC by peeking in the input files */
+ if (nb_input_files) {
+ int i, j, fr;
+ for (j = 0; j < nb_input_files; j++) {
+ for (i = 0; i < input_files[j]->nb_streams; i++) {
+ AVCodecContext *c = input_files[j]->ctx->streams[i]->codec;
+ if (c->codec_type != AVMEDIA_TYPE_VIDEO ||
+ !c->time_base.num)
+ continue;
+ fr = c->time_base.den * 1000 / c->time_base.num;
+ if (fr == 25000) {
+ norm = PAL;
+ break;
+ } else if ((fr == 29970) || (fr == 23976)) {
+ norm = NTSC;
+ break;
+ }
+ }
+ if (norm != UNKNOWN)
+ break;
+ }
+ }
+ if (norm != UNKNOWN)
+ av_log(NULL, AV_LOG_INFO, "Assuming %s for target.\n", norm == PAL ? "PAL" : "NTSC");
+ }
+
+ if (norm == UNKNOWN) {
+ av_log(NULL, AV_LOG_FATAL, "Could not determine norm (PAL/NTSC/NTSC-Film) for target.\n");
+ av_log(NULL, AV_LOG_FATAL, "Please prefix target with \"pal-\", \"ntsc-\" or \"film-\",\n");
+ av_log(NULL, AV_LOG_FATAL, "or set a framerate with \"-r xxx\".\n");
+ exit_program(1);
+ }
+
+ if (!strcmp(arg, "vcd")) {
+ opt_video_codec(o, "c:v", "mpeg1video");
+ opt_audio_codec(o, "c:a", "mp2");
+ parse_option(o, "f", "vcd", options);
+
+ parse_option(o, "s", norm == PAL ? "352x288" : "352x240", options);
+ parse_option(o, "r", frame_rates[norm], options);
+ opt_default(NULL, "g", norm == PAL ? "15" : "18");
+
+ opt_default(NULL, "b:v", "1150000");
+ opt_default(NULL, "maxrate:v", "1150000");
+ opt_default(NULL, "minrate:v", "1150000");
+ opt_default(NULL, "bufsize:v", "327680"); // 40*1024*8;
+
+ opt_default(NULL, "b:a", "224000");
+ parse_option(o, "ar", "44100", options);
+ parse_option(o, "ac", "2", options);
+
+ opt_default(NULL, "packetsize", "2324");
+ opt_default(NULL, "muxrate", "1411200"); // 2352 * 75 * 8;
+
+ /* We have to offset the PTS, so that it is consistent with the SCR.
+ SCR starts at 36000, but the first two packs contain only padding
+ and the first pack from the other stream, respectively, may also have
+ been written before.
+ So the real data starts at SCR 36000+3*1200. */
+ o->mux_preload = (36000 + 3 * 1200) / 90000.0; // 0.44
+ } else if (!strcmp(arg, "svcd")) {
+
+ opt_video_codec(o, "c:v", "mpeg2video");
+ opt_audio_codec(o, "c:a", "mp2");
+ parse_option(o, "f", "svcd", options);
+
+ parse_option(o, "s", norm == PAL ? "480x576" : "480x480", options);
+ parse_option(o, "r", frame_rates[norm], options);
+ parse_option(o, "pix_fmt", "yuv420p", options);
+ opt_default(NULL, "g", norm == PAL ? "15" : "18");
+
+ opt_default(NULL, "b:v", "2040000");
+ opt_default(NULL, "maxrate:v", "2516000");
+ opt_default(NULL, "minrate:v", "0"); // 1145000;
+ opt_default(NULL, "bufsize:v", "1835008"); // 224*1024*8;
+ opt_default(NULL, "scan_offset", "1");
+
+ opt_default(NULL, "b:a", "224000");
+ parse_option(o, "ar", "44100", options);
+
+ opt_default(NULL, "packetsize", "2324");
+
+ } else if (!strcmp(arg, "dvd")) {
+
+ opt_video_codec(o, "c:v", "mpeg2video");
+ opt_audio_codec(o, "c:a", "ac3");
+ parse_option(o, "f", "dvd", options);
+
+ parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
+ parse_option(o, "r", frame_rates[norm], options);
+ parse_option(o, "pix_fmt", "yuv420p", options);
+ opt_default(NULL, "g", norm == PAL ? "15" : "18");
+
+ opt_default(NULL, "b:v", "6000000");
+ opt_default(NULL, "maxrate:v", "9000000");
+ opt_default(NULL, "minrate:v", "0"); // 1500000;
+ opt_default(NULL, "bufsize:v", "1835008"); // 224*1024*8;
+
+ opt_default(NULL, "packetsize", "2048"); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
+ opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
+
+ opt_default(NULL, "b:a", "448000");
+ parse_option(o, "ar", "48000", options);
+
+ } else if (!strncmp(arg, "dv", 2)) {
+
+ parse_option(o, "f", "dv", options);
+
+ parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
+ parse_option(o, "pix_fmt", !strncmp(arg, "dv50", 4) ? "yuv422p" :
+ norm == PAL ? "yuv420p" : "yuv411p", options);
+ parse_option(o, "r", frame_rates[norm], options);
+
+ parse_option(o, "ar", "48000", options);
+ parse_option(o, "ac", "2", options);
+
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Unknown target: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+
+ av_dict_copy(&o->g->codec_opts, codec_opts, AV_DICT_DONT_OVERWRITE);
+ av_dict_copy(&o->g->format_opts, format_opts, AV_DICT_DONT_OVERWRITE);
+
+ return 0;
+}
+
+static int opt_vstats_file(void *optctx, const char *opt, const char *arg)
+{
+ av_free (vstats_filename);
+ vstats_filename = av_strdup (arg);
+ return 0;
+}
+
+static int opt_vstats(void *optctx, const char *opt, const char *arg)
+{
+ char filename[40];
+ time_t today2 = time(NULL);
+ struct tm *today = localtime(&today2);
+
+ snprintf(filename, sizeof(filename), "vstats_%02d%02d%02d.log", today->tm_hour, today->tm_min,
+ today->tm_sec);
+ return opt_vstats_file(NULL, opt, filename);
+}
+
+static int opt_video_frames(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "frames:v", arg, options);
+}
+
+static int opt_audio_frames(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "frames:a", arg, options);
+}
+
+static int opt_data_frames(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "frames:d", arg, options);
+}
+
+static int opt_default_new(OptionsContext *o, const char *opt, const char *arg)
+{
+ int ret;
+ AVDictionary *cbak = codec_opts;
+ AVDictionary *fbak = format_opts;
+ codec_opts = NULL;
+ format_opts = NULL;
+
+ ret = opt_default(NULL, opt, arg);
+
+ av_dict_copy(&o->g->codec_opts , codec_opts, 0);
+ av_dict_copy(&o->g->format_opts, format_opts, 0);
+ av_dict_free(&codec_opts);
+ av_dict_free(&format_opts);
+ codec_opts = cbak;
+ format_opts = fbak;
+
+ return ret;
+}
+
+static int opt_preset(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ FILE *f=NULL;
+ char filename[1000], line[1000], tmp_line[1000];
+ const char *codec_name = NULL;
+
+ tmp_line[0] = *opt;
+ tmp_line[1] = 0;
+ MATCH_PER_TYPE_OPT(codec_names, str, codec_name, NULL, tmp_line);
+
+ if (!(f = get_preset_file(filename, sizeof(filename), arg, *opt == 'f', codec_name))) {
+ if(!strncmp(arg, "libx264-lossless", strlen("libx264-lossless"))){
+ av_log(NULL, AV_LOG_FATAL, "Please use -preset <speed> -qp 0\n");
+ }else
+ av_log(NULL, AV_LOG_FATAL, "File for preset '%s' not found\n", arg);
+ exit_program(1);
+ }
+
+ while (fgets(line, sizeof(line), f)) {
+ char *key = tmp_line, *value, *endptr;
+
+ if (strcspn(line, "#\n\r") == 0)
+ continue;
+ av_strlcpy(tmp_line, line, sizeof(tmp_line));
+ if (!av_strtok(key, "=", &value) ||
+ !av_strtok(value, "\r\n", &endptr)) {
+ av_log(NULL, AV_LOG_FATAL, "%s: Invalid syntax: '%s'\n", filename, line);
+ exit_program(1);
+ }
+ av_log(NULL, AV_LOG_DEBUG, "ffpreset[%s]: set '%s' = '%s'\n", filename, key, value);
+
+ if (!strcmp(key, "acodec")) opt_audio_codec (o, key, value);
+ else if (!strcmp(key, "vcodec")) opt_video_codec (o, key, value);
+ else if (!strcmp(key, "scodec")) opt_subtitle_codec(o, key, value);
+ else if (!strcmp(key, "dcodec")) opt_data_codec (o, key, value);
+ else if (opt_default_new(o, key, value) < 0) {
+ av_log(NULL, AV_LOG_FATAL, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n",
+ filename, line, key, value);
+ exit_program(1);
+ }
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static int opt_old2new(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char *s = av_asprintf("%s:%c", opt + 1, *opt);
+ int ret = parse_option(o, s, arg, options);
+ av_free(s);
+ return ret;
+}
+
+static int opt_bitrate(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+
+ if(!strcmp(opt, "ab")){
+ av_dict_set(&o->g->codec_opts, "b:a", arg, 0);
+ return 0;
+ } else if(!strcmp(opt, "b")){
+ av_log(NULL, AV_LOG_WARNING, "Please use -b:a or -b:v, -b is ambiguous\n");
+ av_dict_set(&o->g->codec_opts, "b:v", arg, 0);
+ return 0;
+ }
+ av_dict_set(&o->g->codec_opts, opt, arg, 0);
+ return 0;
+}
+
+static int opt_qscale(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char *s;
+ int ret;
+ if(!strcmp(opt, "qscale")){
+ av_log(NULL, AV_LOG_WARNING, "Please use -q:a or -q:v, -qscale is ambiguous\n");
+ return parse_option(o, "q:v", arg, options);
+ }
+ s = av_asprintf("q%s", opt + 6);
+ ret = parse_option(o, s, arg, options);
+ av_free(s);
+ return ret;
+}
+
+static int opt_profile(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ if(!strcmp(opt, "profile")){
+ av_log(NULL, AV_LOG_WARNING, "Please use -profile:a or -profile:v, -profile is ambiguous\n");
+ av_dict_set(&o->g->codec_opts, "profile:v", arg, 0);
+ return 0;
+ }
+ av_dict_set(&o->g->codec_opts, opt, arg, 0);
+ return 0;
+}
+
+static int opt_video_filters(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "filter:v", arg, options);
+}
+
+static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "filter:a", arg, options);
+}
+
+static int opt_vsync(void *optctx, const char *opt, const char *arg)
+{
+ if (!av_strcasecmp(arg, "cfr")) video_sync_method = VSYNC_CFR;
+ else if (!av_strcasecmp(arg, "vfr")) video_sync_method = VSYNC_VFR;
+ else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
+ else if (!av_strcasecmp(arg, "drop")) video_sync_method = VSYNC_DROP;
+
+ if (video_sync_method == VSYNC_AUTO)
+ video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
+ return 0;
+}
+
+static int opt_timecode(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char *tcr = av_asprintf("timecode=%s", arg);
+ int ret = parse_option(o, "metadata:g", tcr, options);
+ if (ret >= 0)
+ ret = av_dict_set(&o->g->codec_opts, "gop_timecode", arg, 0);
+ av_free(tcr);
+ return 0;
+}
+
+static int opt_channel_layout(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ char layout_str[32];
+ char *stream_str;
+ char *ac_str;
+ int ret, channels, ac_str_size;
+ uint64_t layout;
+
+ layout = av_get_channel_layout(arg);
+ if (!layout) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown channel layout: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+ snprintf(layout_str, sizeof(layout_str), "%"PRIu64, layout);
+ ret = opt_default_new(o, opt, layout_str);
+ if (ret < 0)
+ return ret;
+
+ /* set 'ac' option based on channel layout */
+ channels = av_get_channel_layout_nb_channels(layout);
+ snprintf(layout_str, sizeof(layout_str), "%d", channels);
+ stream_str = strchr(opt, ':');
+ ac_str_size = 3 + (stream_str ? strlen(stream_str) : 0);
+ ac_str = av_mallocz(ac_str_size);
+ if (!ac_str)
+ return AVERROR(ENOMEM);
+ av_strlcpy(ac_str, "ac", 3);
+ if (stream_str)
+ av_strlcat(ac_str, stream_str, ac_str_size);
+ ret = parse_option(o, ac_str, layout_str, options);
+ av_free(ac_str);
+
+ return ret;
+}
+
+static int opt_audio_qscale(void *optctx, const char *opt, const char *arg)
+{
+ OptionsContext *o = optctx;
+ return parse_option(o, "q:a", arg, options);
+}
+
+static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
+{
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
+ return AVERROR(ENOMEM);
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
+ if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
+ return AVERROR(ENOMEM);
+
+ input_stream_potentially_available = 1;
+
+ return 0;
+}
+
+static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
+{
+ uint8_t *graph_desc = read_file(arg);
+ if (!graph_desc)
+ return AVERROR(EINVAL);
+
+ GROW_ARRAY(filtergraphs, nb_filtergraphs);
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
+ return AVERROR(ENOMEM);
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc;
+
+ input_stream_potentially_available = 1;
+
+ return 0;
+}
+
+void show_help_default(const char *opt, const char *arg)
+{
+ /* per-file options have at least one of those set */
+ const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
+ int show_advanced = 0, show_avoptions = 0;
+
+ if (opt && *opt) {
+ if (!strcmp(opt, "long"))
+ show_advanced = 1;
+ else if (!strcmp(opt, "full"))
+ show_advanced = show_avoptions = 1;
+ else
+ av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
+ }
+
+ show_usage();
+
+ printf("Getting help:\n"
+ " -h -- print basic options\n"
+ " -h long -- print more options\n"
+ " -h full -- print all options (including all format and codec specific options, very long)\n"
+ " See man %s for detailed description of the options.\n"
+ "\n", program_name);
+
+ show_help_options(options, "Print help / information / capabilities:",
+ OPT_EXIT, 0, 0);
+
+ show_help_options(options, "Global options (affect whole program "
+ "instead of just one file:",
+ 0, per_file | OPT_EXIT | OPT_EXPERT, 0);
+ if (show_advanced)
+ show_help_options(options, "Advanced global options:", OPT_EXPERT,
+ per_file | OPT_EXIT, 0);
+
+ show_help_options(options, "Per-file main options:", 0,
+ OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE |
+ OPT_EXIT, per_file);
+ if (show_advanced)
+ show_help_options(options, "Advanced per-file options:",
+ OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);
+
+ show_help_options(options, "Video options:",
+ OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
+ if (show_advanced)
+ show_help_options(options, "Advanced Video options:",
+ OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0);
+
+ show_help_options(options, "Audio options:",
+ OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0);
+ if (show_advanced)
+ show_help_options(options, "Advanced Audio options:",
+ OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);
+ show_help_options(options, "Subtitle options:",
+ OPT_SUBTITLE, 0, 0);
+ printf("\n");
+
+ if (show_avoptions) {
+ int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
+ show_help_children(avcodec_get_class(), flags);
+ show_help_children(avformat_get_class(), flags);
+#if CONFIG_SWSCALE
+ show_help_children(sws_get_class(), flags);
+#endif
+ show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM);
+ show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM);
+ }
+}
+
+void show_usage(void)
+{
+ av_log(NULL, AV_LOG_INFO, "Hyper fast Audio and Video encoder\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [options] [[infile options] -i infile]... {[outfile options] outfile}...\n", program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
+}
+
+enum OptGroup {
+ GROUP_OUTFILE,
+ GROUP_INFILE,
+};
+
+static const OptionGroupDef groups[] = {
+ [GROUP_OUTFILE] = { "output file", NULL, OPT_OUTPUT },
+ [GROUP_INFILE] = { "input file", "i", OPT_INPUT },
+};
+
+static int open_files(OptionGroupList *l, const char *inout,
+ int (*open_file)(OptionsContext*, const char*))
+{
+ int i, ret;
+
+ for (i = 0; i < l->nb_groups; i++) {
+ OptionGroup *g = &l->groups[i];
+ OptionsContext o;
+
+ init_options(&o);
+ o.g = g;
+
+ ret = parse_optgroup(&o, g);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing options for %s file "
+ "%s.\n", inout, g->arg);
+ return ret;
+ }
+
+ av_log(NULL, AV_LOG_DEBUG, "Opening an %s file: %s.\n", inout, g->arg);
+ ret = open_file(&o, g->arg);
+ uninit_options(&o);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error opening %s file %s.\n",
+ inout, g->arg);
+ return ret;
+ }
+ av_log(NULL, AV_LOG_DEBUG, "Successfully opened the file.\n");
+ }
+
+ return 0;
+}
+
+int ffmpeg_parse_options(int argc, char **argv)
+{
+ OptionParseContext octx;
+ uint8_t error[128];
+ int ret;
+
+ memset(&octx, 0, sizeof(octx));
+
+ /* split the commandline into an internal representation */
+ ret = split_commandline(&octx, argc, argv, options, groups,
+ FF_ARRAY_ELEMS(groups));
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");
+ goto fail;
+ }
+
+ /* apply global options */
+ ret = parse_optgroup(NULL, &octx.global_opts);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");
+ goto fail;
+ }
+
+ /* open input files */
+ ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
+ goto fail;
+ }
+
+ /* open output files */
+ ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
+ goto fail;
+ }
+
+fail:
+ uninit_parse_context(&octx);
+ if (ret < 0) {
+ av_strerror(ret, error, sizeof(error));
+ av_log(NULL, AV_LOG_FATAL, "%s\n", error);
+ }
+ return ret;
+}
+
+static int opt_progress(void *optctx, const char *opt, const char *arg)
+{
+ AVIOContext *avio = NULL;
+ int ret;
+
+ if (!strcmp(arg, "-"))
+ arg = "pipe:";
+ ret = avio_open2(&avio, arg, AVIO_FLAG_WRITE, &int_cb, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to open progress URL \"%s\": %s\n",
+ arg, av_err2str(ret));
+ return ret;
+ }
+ progress_avio = avio;
+ return 0;
+}
+
+#define OFFSET(x) offsetof(OptionsContext, x)
+const OptionDef options[] = {
+ /* main options */
+#include "cmdutils_common_opts.h"
+ { "f", HAS_ARG | OPT_STRING | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(format) },
+ "force format", "fmt" },
+ { "y", OPT_BOOL, { &file_overwrite },
+ "overwrite output files" },
+ { "n", OPT_BOOL, { &no_file_overwrite },
+ "never overwrite output files" },
+ { "ignore_unknown", OPT_BOOL, { &ignore_unknown_streams },
+ "Ignore unknown stream types" },
+ { "copy_unknown", OPT_BOOL | OPT_EXPERT, { &copy_unknown_streams },
+ "Copy unknown stream types" },
+ { "c", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
+ "codec name", "codec" },
+ { "codec", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(codec_names) },
+ "codec name", "codec" },
+ { "pre", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(presets) },
+ "preset name", "preset" },
+ { "map", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_map },
+ "set input stream mapping",
+ "[-]input_file_id[:stream_specifier][,sync_file_id[:stream_specifier]]" },
+ { "map_channel", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_map_channel },
+ "map an audio channel from one stream to another", "file.stream.channel[:syncfile.syncstream]" },
+ { "map_metadata", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(metadata_map) },
+ "set metadata information of outfile from infile",
+ "outfile[,metadata]:infile[,metadata]" },
+ { "map_chapters", HAS_ARG | OPT_INT | OPT_EXPERT | OPT_OFFSET |
+ OPT_OUTPUT, { .off = OFFSET(chapters_input_file) },
+ "set chapters mapping", "input_file_index" },
+ { "t", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) },
+ "record or transcode \"duration\" seconds of audio/video",
+ "duration" },
+ { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(stop_time) },
+ "record or transcode stop time", "time_stop" },
+ { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) },
+ "set the limit file size in bytes", "limit_size" },
+ { "ss", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) },
+ "set the start time offset", "time_off" },
+ { "seek_timestamp", HAS_ARG | OPT_INT | OPT_OFFSET |
+ OPT_INPUT, { .off = OFFSET(seek_timestamp) },
+ "enable/disable seeking by timestamp with -ss" },
+ { "accurate_seek", OPT_BOOL | OPT_OFFSET | OPT_EXPERT |
+ OPT_INPUT, { .off = OFFSET(accurate_seek) },
+ "enable/disable accurate seeking with -ss" },
+ { "itsoffset", HAS_ARG | OPT_TIME | OPT_OFFSET |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(input_ts_offset) },
+ "set the input ts offset", "time_off" },
+ { "itsscale", HAS_ARG | OPT_DOUBLE | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(ts_scale) },
+ "set the input ts scale", "scale" },
+ { "timestamp", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_recording_timestamp },
+ "set the recording timestamp ('now' to set the current time)", "time" },
+ { "metadata", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(metadata) },
+ "add metadata", "string=string" },
+ { "dframes", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
+ OPT_OUTPUT, { .func_arg = opt_data_frames },
+ "set the number of data frames to output", "number" },
+ { "benchmark", OPT_BOOL | OPT_EXPERT, { &do_benchmark },
+ "add timings for benchmarking" },
+ { "benchmark_all", OPT_BOOL | OPT_EXPERT, { &do_benchmark_all },
+ "add timings for each task" },
+ { "progress", HAS_ARG | OPT_EXPERT, { .func_arg = opt_progress },
+ "write program-readable progress information", "url" },
+ { "stdin", OPT_BOOL | OPT_EXPERT, { &stdin_interaction },
+ "enable or disable interaction on standard input" },
+ { "timelimit", HAS_ARG | OPT_EXPERT, { .func_arg = opt_timelimit },
+ "set max runtime in seconds", "limit" },
+ { "dump", OPT_BOOL | OPT_EXPERT, { &do_pkt_dump },
+ "dump each input packet" },
+ { "hex", OPT_BOOL | OPT_EXPERT, { &do_hex_dump },
+ "when dumping packets, also dump the payload" },
+ { "re", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
+ OPT_INPUT, { .off = OFFSET(rate_emu) },
+ "read input at native frame rate", "" },
+ { "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
+ "specify target file type (\"vcd\", \"svcd\", \"dvd\","
+ " \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" },
+ { "vsync", HAS_ARG | OPT_EXPERT, { opt_vsync },
+ "video sync method", "" },
+ { "frame_drop_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &frame_drop_threshold },
+ "frame drop threshold", "" },
+ { "async", HAS_ARG | OPT_INT | OPT_EXPERT, { &audio_sync_method },
+ "audio sync method", "" },
+ { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &audio_drift_threshold },
+ "audio drift threshold", "threshold" },
+ { "copyts", OPT_BOOL | OPT_EXPERT, { &copy_ts },
+ "copy timestamps" },
+ { "start_at_zero", OPT_BOOL | OPT_EXPERT, { &start_at_zero },
+ "shift input timestamps to start at 0 when using copyts" },
+ { "copytb", HAS_ARG | OPT_INT | OPT_EXPERT, { &copy_tb },
+ "copy input stream time base when stream copying", "mode" },
+ { "shortest", OPT_BOOL | OPT_EXPERT | OPT_OFFSET |
+ OPT_OUTPUT, { .off = OFFSET(shortest) },
+ "finish encoding within shortest input" },
+ { "apad", OPT_STRING | HAS_ARG | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(apad) },
+ "audio pad", "" },
+ { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_delta_threshold },
+ "timestamp discontinuity delta threshold", "threshold" },
+ { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_error_threshold },
+ "timestamp error delta threshold", "threshold" },
+ { "xerror", OPT_BOOL | OPT_EXPERT, { &exit_on_error },
+ "exit on error", "error" },
+ { "copyinkf", OPT_BOOL | OPT_EXPERT | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(copy_initial_nonkeyframes) },
+ "copy initial non-keyframes" },
+ { "copypriorss", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(copy_prior_start) },
+ "copy or discard frames before start time" },
+ { "frames", OPT_INT64 | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frames) },
+ "set the number of frames to output", "number" },
+ { "tag", OPT_STRING | HAS_ARG | OPT_SPEC |
+ OPT_EXPERT | OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(codec_tags) },
+ "force codec tag/fourcc", "fourcc/tag" },
+ { "q", HAS_ARG | OPT_EXPERT | OPT_DOUBLE |
+ OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(qscale) },
+ "use fixed quality scale (VBR)", "q" },
+ { "qscale", HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_qscale },
+ "use fixed quality scale (VBR)", "q" },
+ { "profile", HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_profile },
+ "set profile", "profile" },
+ { "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) },
+ "set stream filtergraph", "filter_graph" },
+ { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) },
+ "read stream filtergraph description from a file", "filename" },
+ { "reinit_filter", HAS_ARG | OPT_INT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(reinit_filters) },
+ "reinit filtergraph on input parameter changes", "" },
+ { "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
+ "create a complex filtergraph", "graph_description" },
+ { "lavfi", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
+ "create a complex filtergraph", "graph_description" },
+ { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script },
+ "read complex filtergraph description from a file", "filename" },
+ { "stats", OPT_BOOL, { &print_stats },
+ "print progress report during encoding", },
+ { "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
+ OPT_OUTPUT, { .func_arg = opt_attach },
+ "add an attachment to the output file", "filename" },
+ { "dump_attachment", HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(dump_attachment) },
+ "extract an attachment into a file", "filename" },
+ { "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
+ "print timestamp debugging info" },
+ { "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate },
+ "maximum error rate", "ratio of errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success." },
+ { "discard", OPT_STRING | HAS_ARG | OPT_SPEC |
+ OPT_INPUT, { .off = OFFSET(discard) },
+ "discard", "" },
+ { "disposition", OPT_STRING | HAS_ARG | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(disposition) },
+ "disposition", "" },
+ { "thread_queue_size", HAS_ARG | OPT_INT | OPT_OFFSET | OPT_EXPERT | OPT_INPUT,
+ { .off = OFFSET(thread_queue_size) },
+ "set the maximum number of queued packets from the demuxer" },
+
+ /* video options */
+ { "vframes", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_frames },
+ "set the number of video frames to output", "number" },
+ { "r", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_rates) },
+ "set frame rate (Hz value, fraction or abbreviation)", "rate" },
+ { "s", OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) },
+ "set frame size (WxH or abbreviation)", "size" },
+ { "aspect", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(frame_aspect_ratios) },
+ "set aspect ratio (4:3, 16:9 or 1.3333, 1.7777)", "aspect" },
+ { "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
+ "set pixel format", "format" },
+ { "bits_per_raw_sample", OPT_VIDEO | OPT_INT | HAS_ARG, { &frame_bits_per_raw_sample },
+ "set the number of bits per raw sample", "number" },
+ { "intra", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &intra_only },
+ "deprecated use -g 1" },
+ { "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(video_disable) },
+ "disable video" },
+ { "rc_override", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(rc_overrides) },
+ "rate control override for specific intervals", "override" },
+ { "vcodec", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_INPUT |
+ OPT_OUTPUT, { .func_arg = opt_video_codec },
+ "force video codec ('copy' to copy stream)", "codec" },
+ { "sameq", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_sameq },
+ "Removed" },
+ { "same_quant", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_sameq },
+ "Removed" },
+ { "timecode", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_timecode },
+ "set initial TimeCode value.", "hh:mm:ss[:;.]ff" },
+ { "pass", OPT_VIDEO | HAS_ARG | OPT_SPEC | OPT_INT | OPT_OUTPUT, { .off = OFFSET(pass) },
+ "select the pass number (1 to 3)", "n" },
+ { "passlogfile", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(passlogfiles) },
+ "select two pass log file name prefix", "prefix" },
+ { "deinterlace", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_deinterlace },
+ "this option is deprecated, use the yadif filter instead" },
+ { "psnr", OPT_VIDEO | OPT_BOOL | OPT_EXPERT, { &do_psnr },
+ "calculate PSNR of compressed frames" },
+ { "vstats", OPT_VIDEO | OPT_EXPERT , { &opt_vstats },
+ "dump video coding statistics to file" },
+ { "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
+ "dump video coding statistics to file", "file" },
+ { "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
+ "set video filters", "filter_graph" },
+ { "intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(intra_matrices) },
+ "specify intra matrix coeffs", "matrix" },
+ { "inter_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(inter_matrices) },
+ "specify inter matrix coeffs", "matrix" },
+ { "chroma_intra_matrix", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(chroma_intra_matrices) },
+ "specify intra matrix coeffs", "matrix" },
+ { "top", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_INT| OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(top_field_first) },
+ "top=1/bottom=0/auto=-1 field first", "" },
+ { "vtag", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_old2new },
+ "force video tag/fourcc", "fourcc/tag" },
+ { "qphist", OPT_VIDEO | OPT_BOOL | OPT_EXPERT , { &qp_hist },
+ "show QP histogram" },
+ { "force_fps", OPT_VIDEO | OPT_BOOL | OPT_EXPERT | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(force_fps) },
+ "force the selected framerate, disable the best supported framerate selection" },
+ { "streamid", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_streamid },
+ "set the value of an outfile streamid", "streamIndex:value" },
+ { "force_key_frames", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(forced_key_frames) },
+ "force key frames at specified timestamps", "timestamps" },
+ { "ab", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
+ "audio bitrate (please use -b:a)", "bitrate" },
+ { "b", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_bitrate },
+ "video bitrate (please use -b:v)", "bitrate" },
+ { "hwaccel", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccels) },
+ "use HW accelerated decoding", "hwaccel name" },
+ { "hwaccel_device", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
+ OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_devices) },
+ "select a device for HW acceleration" "devicename" },
+#if HAVE_VDPAU_X11
+ { "vdpau_api_ver", HAS_ARG | OPT_INT | OPT_EXPERT, { &vdpau_api_ver }, "" },
+#endif
+ { "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) },
+ "automatically insert correct rotate filters" },
+
+ /* audio options */
+ { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },
+ "set the number of audio frames to output", "number" },
+ { "aq", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_qscale },
+ "set audio quality (codec-specific)", "quality", },
+ { "ar", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_sample_rate) },
+ "set audio sampling rate (in Hz)", "rate" },
+ { "ac", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC |
+ OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(audio_channels) },
+ "set number of audio channels", "channels" },
+ { "an", OPT_AUDIO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(audio_disable) },
+ "disable audio" },
+ { "acodec", OPT_AUDIO | HAS_ARG | OPT_PERFILE |
+ OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_audio_codec },
+ "force audio codec ('copy' to copy stream)", "codec" },
+ { "atag", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_OUTPUT, { .func_arg = opt_old2new },
+ "force audio tag/fourcc", "fourcc/tag" },
+ { "vol", OPT_AUDIO | HAS_ARG | OPT_INT, { &audio_volume },
+ "change audio volume (256=normal)" , "volume" },
+ { "sample_fmt", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_SPEC |
+ OPT_STRING | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(sample_fmts) },
+ "set sample format", "format" },
+ { "channel_layout", OPT_AUDIO | HAS_ARG | OPT_EXPERT | OPT_PERFILE |
+ OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_channel_layout },
+ "set channel layout", "layout" },
+ { "af", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_filters },
+ "set audio filters", "filter_graph" },
+ { "guess_layout_max", OPT_AUDIO | HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(guess_layout_max) },
+ "set the maximum number of channels to try to guess the channel layout" },
+
+ /* subtitle options */
+ { "sn", OPT_SUBTITLE | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(subtitle_disable) },
+ "disable subtitle" },
+ { "scodec", OPT_SUBTITLE | HAS_ARG | OPT_PERFILE | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_subtitle_codec },
+ "force subtitle codec ('copy' to copy stream)", "codec" },
+ { "stag", OPT_SUBTITLE | HAS_ARG | OPT_EXPERT | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new }
+ , "force subtitle tag/fourcc", "fourcc/tag" },
+ { "fix_sub_duration", OPT_BOOL | OPT_EXPERT | OPT_SUBTITLE | OPT_SPEC | OPT_INPUT, { .off = OFFSET(fix_sub_duration) },
+ "fix subtitles duration" },
+ { "canvas_size", OPT_SUBTITLE | HAS_ARG | OPT_STRING | OPT_SPEC | OPT_INPUT, { .off = OFFSET(canvas_sizes) },
+ "set canvas size (WxH or abbreviation)", "size" },
+
+ /* grab options */
+ { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_channel },
+ "deprecated, use -channel", "channel" },
+ { "tvstd", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_video_standard },
+ "deprecated, use -standard", "standard" },
+ { "isync", OPT_BOOL | OPT_EXPERT, { &input_sync }, "this option is deprecated and does nothing", "" },
+
+ /* muxer options */
+ { "muxdelay", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_max_delay) },
+ "set the maximum demux-decode delay", "seconds" },
+ { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) },
+ "set the initial demux-decode delay", "seconds" },
+ { "override_ffserver", OPT_BOOL | OPT_EXPERT | OPT_OUTPUT, { &override_ffserver },
+ "override the options from ffserver", "" },
+ { "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { opt_sdp_file },
+ "specify a file in which to print sdp information", "file" },
+
+ { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },
+ "A comma-separated list of bitstream filters", "bitstream_filters" },
+ { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new },
+ "deprecated", "audio bitstream_filters" },
+ { "vbsf", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new },
+ "deprecated", "video bitstream_filters" },
+
+ { "apre", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },
+ "set the audio options to the indicated preset", "preset" },
+ { "vpre", OPT_VIDEO | HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },
+ "set the video options to the indicated preset", "preset" },
+ { "spre", HAS_ARG | OPT_SUBTITLE | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },
+ "set the subtitle options to the indicated preset", "preset" },
+ { "fpre", HAS_ARG | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_preset },
+ "set options from indicated preset file", "filename" },
+ /* data codec support */
+ { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },
+ "force data codec ('copy' to copy stream)", "codec" },
+ { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(data_disable) },
+ "disable data" },
+
+ { NULL, },
+};
diff --git a/ffmpeg_vda.c b/ffmpeg_vda.c
new file mode 100644
index 0000000000..d15648dd8e
--- /dev/null
+++ b/ffmpeg_vda.c
@@ -0,0 +1,134 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/avcodec.h"
+#include "libavcodec/vda.h"
+#include "libavutil/imgutils.h"
+
+#include "ffmpeg.h"
+
+typedef struct VDAContext {
+ AVFrame *tmp_frame;
+} VDAContext;
+
+static int vda_retrieve_data(AVCodecContext *s, AVFrame *frame)
+{
+ InputStream *ist = s->opaque;
+ VDAContext *vda = ist->hwaccel_ctx;
+ CVPixelBufferRef pixbuf = (CVPixelBufferRef)frame->data[3];
+ OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
+ CVReturn err;
+ uint8_t *data[4] = { 0 };
+ int linesize[4] = { 0 };
+ int planes, ret, i;
+
+ av_frame_unref(vda->tmp_frame);
+
+ switch (pixel_format) {
+ case kCVPixelFormatType_420YpCbCr8Planar: vda->tmp_frame->format = AV_PIX_FMT_YUV420P; break;
+ case kCVPixelFormatType_422YpCbCr8: vda->tmp_frame->format = AV_PIX_FMT_UYVY422; break;
+ default:
+ av_log(NULL, AV_LOG_ERROR,
+ "Unsupported pixel format: %u\n", pixel_format);
+ return AVERROR(ENOSYS);
+ }
+
+ vda->tmp_frame->width = frame->width;
+ vda->tmp_frame->height = frame->height;
+ ret = av_frame_get_buffer(vda->tmp_frame, 32);
+ if (ret < 0)
+ return ret;
+
+ err = CVPixelBufferLockBaseAddress(pixbuf, kCVPixelBufferLock_ReadOnly);
+ if (err != kCVReturnSuccess) {
+ av_log(NULL, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ if (CVPixelBufferIsPlanar(pixbuf)) {
+
+ planes = CVPixelBufferGetPlaneCount(pixbuf);
+ for (i = 0; i < planes; i++) {
+ data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
+ linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
+ }
+ } else {
+ data[0] = CVPixelBufferGetBaseAddress(pixbuf);
+ linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
+ }
+
+ av_image_copy(vda->tmp_frame->data, vda->tmp_frame->linesize,
+ (const uint8_t **)data, linesize, vda->tmp_frame->format,
+ frame->width, frame->height);
+
+ ret = av_frame_copy_props(vda->tmp_frame, frame);
+ if (ret < 0)
+ return ret;
+
+ av_frame_unref(frame);
+ av_frame_move_ref(frame, vda->tmp_frame);
+
+ return 0;
+}
+
+static void vda_uninit(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ VDAContext *vda = ist->hwaccel_ctx;
+
+ ist->hwaccel_uninit = NULL;
+ ist->hwaccel_retrieve_data = NULL;
+
+ av_frame_free(&vda->tmp_frame);
+
+ av_vda_default_free(s);
+ av_freep(&ist->hwaccel_ctx);
+}
+
+int vda_init(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ VDAContext *vda;
+ int ret;
+
+ vda = av_mallocz(sizeof(*vda));
+ if (!vda)
+ return AVERROR(ENOMEM);
+
+ ist->hwaccel_ctx = vda;
+ ist->hwaccel_uninit = vda_uninit;
+ ist->hwaccel_retrieve_data = vda_retrieve_data;
+
+ vda->tmp_frame = av_frame_alloc();
+ if (!vda->tmp_frame) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ret = av_vda_default_init(s);
+ if (ret < 0) {
+ av_log(NULL, loglevel, "Error creating VDA decoder.\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ vda_uninit(s);
+ return ret;
+}
diff --git a/ffmpeg_vdpau.c b/ffmpeg_vdpau.c
new file mode 100644
index 0000000000..b05e557613
--- /dev/null
+++ b/ffmpeg_vdpau.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 <stdint.h>
+
+#include <vdpau/vdpau.h>
+#include <vdpau/vdpau_x11.h>
+
+#include <X11/Xlib.h>
+
+#include "ffmpeg.h"
+
+#include "libavcodec/vdpau.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/buffer.h"
+#include "libavutil/frame.h"
+#include "libavutil/pixfmt.h"
+
+typedef struct VDPAUContext {
+ Display *dpy;
+
+ VdpDevice device;
+ VdpDecoder decoder;
+ VdpGetProcAddress *get_proc_address;
+
+ VdpGetErrorString *get_error_string;
+ VdpGetInformationString *get_information_string;
+ VdpDeviceDestroy *device_destroy;
+#if 1 // for ffmpegs older vdpau API, not the oldest though
+ VdpDecoderCreate *decoder_create;
+ VdpDecoderDestroy *decoder_destroy;
+ VdpDecoderRender *decoder_render;
+#endif
+ VdpVideoSurfaceCreate *video_surface_create;
+ VdpVideoSurfaceDestroy *video_surface_destroy;
+ VdpVideoSurfaceGetBitsYCbCr *video_surface_get_bits;
+ VdpVideoSurfaceGetParameters *video_surface_get_parameters;
+ VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *video_surface_query;
+
+ AVFrame *tmp_frame;
+
+ enum AVPixelFormat pix_fmt;
+ VdpYCbCrFormat vdpau_format;
+} VDPAUContext;
+
+int vdpau_api_ver = 2;
+
+static void vdpau_uninit(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ VDPAUContext *ctx = ist->hwaccel_ctx;
+
+ ist->hwaccel_uninit = NULL;
+ ist->hwaccel_get_buffer = NULL;
+ ist->hwaccel_retrieve_data = NULL;
+
+ if (ctx->decoder_destroy)
+ ctx->decoder_destroy(ctx->decoder);
+
+ if (ctx->device_destroy)
+ ctx->device_destroy(ctx->device);
+
+ if (ctx->dpy)
+ XCloseDisplay(ctx->dpy);
+
+ av_frame_free(&ctx->tmp_frame);
+
+ av_freep(&ist->hwaccel_ctx);
+ av_freep(&s->hwaccel_context);
+}
+
+static void vdpau_release_buffer(void *opaque, uint8_t *data)
+{
+ VdpVideoSurface surface = *(VdpVideoSurface*)data;
+ VDPAUContext *ctx = opaque;
+
+ ctx->video_surface_destroy(surface);
+ av_freep(&data);
+}
+
+static int vdpau_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
+{
+ InputStream *ist = s->opaque;
+ VDPAUContext *ctx = ist->hwaccel_ctx;
+ VdpVideoSurface *surface;
+ VdpStatus err;
+ VdpChromaType chroma;
+ uint32_t width, height;
+
+ av_assert0(frame->format == AV_PIX_FMT_VDPAU);
+
+ if (av_vdpau_get_surface_parameters(s, &chroma, &width, &height))
+ return AVERROR(ENOSYS);
+
+ surface = av_malloc(sizeof(*surface));
+ if (!surface)
+ return AVERROR(ENOMEM);
+
+ frame->buf[0] = av_buffer_create((uint8_t*)surface, sizeof(*surface),
+ vdpau_release_buffer, ctx,
+ AV_BUFFER_FLAG_READONLY);
+ if (!frame->buf[0]) {
+ av_freep(&surface);
+ return AVERROR(ENOMEM);
+ }
+
+ // properly we should keep a pool of surfaces instead of creating
+ // them anew for each frame, but since we don't care about speed
+ // much in this code, we don't bother
+ err = ctx->video_surface_create(ctx->device, chroma, width, height,
+ surface);
+ if (err != VDP_STATUS_OK) {
+ av_log(NULL, AV_LOG_ERROR, "Error allocating a VDPAU video surface: %s\n",
+ ctx->get_error_string(err));
+ av_buffer_unref(&frame->buf[0]);
+ return AVERROR_UNKNOWN;
+ }
+
+ frame->data[3] = (uint8_t*)(uintptr_t)*surface;
+
+ return 0;
+}
+
+static int vdpau_retrieve_data(AVCodecContext *s, AVFrame *frame)
+{
+ VdpVideoSurface surface = (VdpVideoSurface)(uintptr_t)frame->data[3];
+ InputStream *ist = s->opaque;
+ VDPAUContext *ctx = ist->hwaccel_ctx;
+ VdpStatus err;
+ int ret, chroma_type;
+
+ err = ctx->video_surface_get_parameters(surface, &chroma_type,
+ &ctx->tmp_frame->width,
+ &ctx->tmp_frame->height);
+ if (err != VDP_STATUS_OK) {
+ av_log(NULL, AV_LOG_ERROR, "Error getting surface parameters: %s\n",
+ ctx->get_error_string(err));
+ return AVERROR_UNKNOWN;
+ }
+ ctx->tmp_frame->format = ctx->pix_fmt;
+
+ ret = av_frame_get_buffer(ctx->tmp_frame, 32);
+ if (ret < 0)
+ return ret;
+
+ ctx->tmp_frame->width = frame->width;
+ ctx->tmp_frame->height = frame->height;
+
+ err = ctx->video_surface_get_bits(surface, ctx->vdpau_format,
+ (void * const *)ctx->tmp_frame->data,
+ ctx->tmp_frame->linesize);
+ if (err != VDP_STATUS_OK) {
+ av_log(NULL, AV_LOG_ERROR, "Error retrieving frame data from VDPAU: %s\n",
+ ctx->get_error_string(err));
+ ret = AVERROR_UNKNOWN;
+ goto fail;
+ }
+
+ if (ctx->vdpau_format == VDP_YCBCR_FORMAT_YV12)
+ FFSWAP(uint8_t*, ctx->tmp_frame->data[1], ctx->tmp_frame->data[2]);
+
+ ret = av_frame_copy_props(ctx->tmp_frame, frame);
+ if (ret < 0)
+ goto fail;
+
+ av_frame_unref(frame);
+ av_frame_move_ref(frame, ctx->tmp_frame);
+ return 0;
+
+fail:
+ av_frame_unref(ctx->tmp_frame);
+ return ret;
+}
+
+static const int vdpau_formats[][2] = {
+ { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV420P },
+ { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV12 },
+ { VDP_YCBCR_FORMAT_YUYV, AV_PIX_FMT_YUYV422 },
+ { VDP_YCBCR_FORMAT_UYVY, AV_PIX_FMT_UYVY422 },
+};
+
+static int vdpau_alloc(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ AVVDPAUContext *vdpau_ctx;
+ VDPAUContext *ctx;
+ const char *display, *vendor;
+ VdpStatus err;
+ int i;
+
+ ctx = av_mallocz(sizeof(*ctx));
+ if (!ctx)
+ return AVERROR(ENOMEM);
+
+ ist->hwaccel_ctx = ctx;
+ ist->hwaccel_uninit = vdpau_uninit;
+ ist->hwaccel_get_buffer = vdpau_get_buffer;
+ ist->hwaccel_retrieve_data = vdpau_retrieve_data;
+
+ ctx->tmp_frame = av_frame_alloc();
+ if (!ctx->tmp_frame)
+ goto fail;
+
+ ctx->dpy = XOpenDisplay(ist->hwaccel_device);
+ if (!ctx->dpy) {
+ av_log(NULL, loglevel, "Cannot open the X11 display %s.\n",
+ XDisplayName(ist->hwaccel_device));
+ goto fail;
+ }
+ display = XDisplayString(ctx->dpy);
+
+ err = vdp_device_create_x11(ctx->dpy, XDefaultScreen(ctx->dpy), &ctx->device,
+ &ctx->get_proc_address);
+ if (err != VDP_STATUS_OK) {
+ av_log(NULL, loglevel, "VDPAU device creation on X11 display %s failed.\n",
+ display);
+ goto fail;
+ }
+
+#define GET_CALLBACK(id, result) \
+do { \
+ void *tmp; \
+ err = ctx->get_proc_address(ctx->device, id, &tmp); \
+ if (err != VDP_STATUS_OK) { \
+ av_log(NULL, loglevel, "Error getting the " #id " callback.\n"); \
+ goto fail; \
+ } \
+ ctx->result = tmp; \
+} while (0)
+
+ GET_CALLBACK(VDP_FUNC_ID_GET_ERROR_STRING, get_error_string);
+ GET_CALLBACK(VDP_FUNC_ID_GET_INFORMATION_STRING, get_information_string);
+ GET_CALLBACK(VDP_FUNC_ID_DEVICE_DESTROY, device_destroy);
+ if (vdpau_api_ver == 1) {
+ GET_CALLBACK(VDP_FUNC_ID_DECODER_CREATE, decoder_create);
+ GET_CALLBACK(VDP_FUNC_ID_DECODER_DESTROY, decoder_destroy);
+ GET_CALLBACK(VDP_FUNC_ID_DECODER_RENDER, decoder_render);
+ }
+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_CREATE, video_surface_create);
+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, video_surface_destroy);
+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, video_surface_get_bits);
+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, video_surface_get_parameters);
+ GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES,
+ video_surface_query);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(vdpau_formats); i++) {
+ VdpBool supported;
+ err = ctx->video_surface_query(ctx->device, VDP_CHROMA_TYPE_420,
+ vdpau_formats[i][0], &supported);
+ if (err != VDP_STATUS_OK) {
+ av_log(NULL, loglevel,
+ "Error querying VDPAU surface capabilities: %s\n",
+ ctx->get_error_string(err));
+ goto fail;
+ }
+ if (supported)
+ break;
+ }
+ if (i == FF_ARRAY_ELEMS(vdpau_formats)) {
+ av_log(NULL, loglevel,
+ "No supported VDPAU format for retrieving the data.\n");
+ return AVERROR(EINVAL);
+ }
+ ctx->vdpau_format = vdpau_formats[i][0];
+ ctx->pix_fmt = vdpau_formats[i][1];
+
+ if (vdpau_api_ver == 1) {
+ vdpau_ctx = av_vdpau_alloc_context();
+ if (!vdpau_ctx)
+ goto fail;
+ vdpau_ctx->render = ctx->decoder_render;
+
+ s->hwaccel_context = vdpau_ctx;
+ } else
+ if (av_vdpau_bind_context(s, ctx->device, ctx->get_proc_address, 0))
+ goto fail;
+
+ ctx->get_information_string(&vendor);
+ av_log(NULL, AV_LOG_VERBOSE, "Using VDPAU -- %s -- on X11 display %s, "
+ "to decode input stream #%d:%d.\n", vendor,
+ display, ist->file_index, ist->st->index);
+
+ return 0;
+
+fail:
+ av_log(NULL, loglevel, "VDPAU init failed for stream #%d:%d.\n",
+ ist->file_index, ist->st->index);
+ vdpau_uninit(s);
+ return AVERROR(EINVAL);
+}
+
+static int vdpau_old_init(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+ int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;
+ AVVDPAUContext *vdpau_ctx;
+ VDPAUContext *ctx;
+ VdpStatus err;
+ int profile, ret;
+
+ if (!ist->hwaccel_ctx) {
+ ret = vdpau_alloc(s);
+ if (ret < 0)
+ return ret;
+ }
+ ctx = ist->hwaccel_ctx;
+ vdpau_ctx = s->hwaccel_context;
+
+ ret = av_vdpau_get_profile(s, &profile);
+ if (ret < 0) {
+ av_log(NULL, loglevel, "No known VDPAU decoder profile for this stream.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (ctx->decoder)
+ ctx->decoder_destroy(ctx->decoder);
+
+ err = ctx->decoder_create(ctx->device, profile,
+ s->coded_width, s->coded_height,
+ 16, &ctx->decoder);
+ if (err != VDP_STATUS_OK) {
+ av_log(NULL, loglevel, "Error creating the VDPAU decoder: %s\n",
+ ctx->get_error_string(err));
+ return AVERROR_UNKNOWN;
+ }
+
+ vdpau_ctx->decoder = ctx->decoder;
+
+ ist->hwaccel_get_buffer = vdpau_get_buffer;
+ ist->hwaccel_retrieve_data = vdpau_retrieve_data;
+
+ return 0;
+}
+
+int vdpau_init(AVCodecContext *s)
+{
+ InputStream *ist = s->opaque;
+
+ if (vdpau_api_ver == 1)
+ return vdpau_old_init(s);
+
+ if (!ist->hwaccel_ctx) {
+ int ret = vdpau_alloc(s);
+ if (ret < 0)
+ return ret;
+ }
+
+ ist->hwaccel_get_buffer = vdpau_get_buffer;
+ ist->hwaccel_retrieve_data = vdpau_retrieve_data;
+
+ return 0;
+}
diff --git a/ffplay.c b/ffplay.c
new file mode 100644
index 0000000000..9ce13d71fb
--- /dev/null
+++ b/ffplay.c
@@ -0,0 +1,3873 @@
+/*
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * simple media player based on the FFmpeg libraries
+ */
+
+#include "config.h"
+#include <inttypes.h>
+#include <math.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdint.h>
+
+#include "libavutil/avstring.h"
+#include "libavutil/colorspace.h"
+#include "libavutil/eval.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/dict.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/samplefmt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/time.h"
+#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
+#include "libswscale/swscale.h"
+#include "libavutil/opt.h"
+#include "libavcodec/avfft.h"
+#include "libswresample/swresample.h"
+
+#if CONFIG_AVFILTER
+# include "libavfilter/avcodec.h"
+# include "libavfilter/avfilter.h"
+# include "libavfilter/buffersink.h"
+# include "libavfilter/buffersrc.h"
+#endif
+
+#include <SDL.h>
+#include <SDL_thread.h>
+
+#include "cmdutils.h"
+
+#include <assert.h>
+
+const char program_name[] = "ffplay";
+const int program_birth_year = 2003;
+
+#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
+#define MIN_FRAMES 5
+
+/* Minimum SDL audio buffer size, in samples. */
+#define SDL_AUDIO_MIN_BUFFER_SIZE 512
+/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
+#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
+
+/* no AV sync correction is done if below the minimum AV sync threshold */
+#define AV_SYNC_THRESHOLD_MIN 0.04
+/* AV sync correction is done if above the maximum AV sync threshold */
+#define AV_SYNC_THRESHOLD_MAX 0.1
+/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
+#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
+/* no AV correction is done if too big error */
+#define AV_NOSYNC_THRESHOLD 10.0
+
+/* maximum audio speed change to get correct sync */
+#define SAMPLE_CORRECTION_PERCENT_MAX 10
+
+/* external clock speed adjustment constants for realtime sources based on buffer fullness */
+#define EXTERNAL_CLOCK_SPEED_MIN 0.900
+#define EXTERNAL_CLOCK_SPEED_MAX 1.010
+#define EXTERNAL_CLOCK_SPEED_STEP 0.001
+
+/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
+#define AUDIO_DIFF_AVG_NB 20
+
+/* polls for possible required screen refresh at least this often, should be less than 1/fps */
+#define REFRESH_RATE 0.01
+
+/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
+/* TODO: We assume that a decoded and resampled frame fits into this buffer */
+#define SAMPLE_ARRAY_SIZE (8 * 65536)
+
+#define CURSOR_HIDE_DELAY 1000000
+
+static int64_t sws_flags = SWS_BICUBIC;
+
+typedef struct MyAVPacketList {
+ AVPacket pkt;
+ struct MyAVPacketList *next;
+ int serial;
+} MyAVPacketList;
+
+typedef struct PacketQueue {
+ MyAVPacketList *first_pkt, *last_pkt;
+ int nb_packets;
+ int size;
+ int abort_request;
+ int serial;
+ SDL_mutex *mutex;
+ SDL_cond *cond;
+} PacketQueue;
+
+#define VIDEO_PICTURE_QUEUE_SIZE 3
+#define SUBPICTURE_QUEUE_SIZE 16
+#define SAMPLE_QUEUE_SIZE 9
+#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
+
+typedef struct AudioParams {
+ int freq;
+ int channels;
+ int64_t channel_layout;
+ enum AVSampleFormat fmt;
+ int frame_size;
+ int bytes_per_sec;
+} AudioParams;
+
+typedef struct Clock {
+ double pts; /* clock base */
+ double pts_drift; /* clock base minus time at which we updated the clock */
+ double last_updated;
+ double speed;
+ int serial; /* clock is based on a packet with this serial */
+ int paused;
+ int *queue_serial; /* pointer to the current packet queue serial, used for obsolete clock detection */
+} Clock;
+
+/* Common struct for handling all types of decoded data and allocated render buffers. */
+typedef struct Frame {
+ AVFrame *frame;
+ AVSubtitle sub;
+ int serial;
+ double pts; /* presentation timestamp for the frame */
+ double duration; /* estimated duration of the frame */
+ int64_t pos; /* byte position of the frame in the input file */
+ SDL_Overlay *bmp;
+ int allocated;
+ int reallocate;
+ int width;
+ int height;
+ AVRational sar;
+} Frame;
+
+typedef struct FrameQueue {
+ Frame queue[FRAME_QUEUE_SIZE];
+ int rindex;
+ int windex;
+ int size;
+ int max_size;
+ int keep_last;
+ int rindex_shown;
+ SDL_mutex *mutex;
+ SDL_cond *cond;
+ PacketQueue *pktq;
+} FrameQueue;
+
+enum {
+ AV_SYNC_AUDIO_MASTER, /* default choice */
+ AV_SYNC_VIDEO_MASTER,
+ AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
+};
+
+typedef struct Decoder {
+ AVPacket pkt;
+ AVPacket pkt_temp;
+ PacketQueue *queue;
+ AVCodecContext *avctx;
+ int pkt_serial;
+ int finished;
+ int packet_pending;
+ SDL_cond *empty_queue_cond;
+ int64_t start_pts;
+ AVRational start_pts_tb;
+ int64_t next_pts;
+ AVRational next_pts_tb;
+ SDL_Thread *decoder_tid;
+} Decoder;
+
+typedef struct VideoState {
+ SDL_Thread *read_tid;
+ AVInputFormat *iformat;
+ int abort_request;
+ int force_refresh;
+ int paused;
+ int last_paused;
+ int queue_attachments_req;
+ int seek_req;
+ int seek_flags;
+ int64_t seek_pos;
+ int64_t seek_rel;
+ int read_pause_return;
+ AVFormatContext *ic;
+ int realtime;
+
+ Clock audclk;
+ Clock vidclk;
+ Clock extclk;
+
+ FrameQueue pictq;
+ FrameQueue subpq;
+ FrameQueue sampq;
+
+ Decoder auddec;
+ Decoder viddec;
+ Decoder subdec;
+
+ int audio_stream;
+
+ int av_sync_type;
+
+ double audio_clock;
+ int audio_clock_serial;
+ double audio_diff_cum; /* used for AV difference average computation */
+ double audio_diff_avg_coef;
+ double audio_diff_threshold;
+ int audio_diff_avg_count;
+ AVStream *audio_st;
+ PacketQueue audioq;
+ int audio_hw_buf_size;
+ uint8_t silence_buf[SDL_AUDIO_MIN_BUFFER_SIZE];
+ uint8_t *audio_buf;
+ uint8_t *audio_buf1;
+ unsigned int audio_buf_size; /* in bytes */
+ unsigned int audio_buf1_size;
+ int audio_buf_index; /* in bytes */
+ int audio_write_buf_size;
+ struct AudioParams audio_src;
+#if CONFIG_AVFILTER
+ struct AudioParams audio_filter_src;
+#endif
+ struct AudioParams audio_tgt;
+ struct SwrContext *swr_ctx;
+ int frame_drops_early;
+ int frame_drops_late;
+
+ enum ShowMode {
+ SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
+ } show_mode;
+ int16_t sample_array[SAMPLE_ARRAY_SIZE];
+ int sample_array_index;
+ int last_i_start;
+ RDFTContext *rdft;
+ int rdft_bits;
+ FFTSample *rdft_data;
+ int xpos;
+ double last_vis_time;
+
+ int subtitle_stream;
+ AVStream *subtitle_st;
+ PacketQueue subtitleq;
+
+ double frame_timer;
+ double frame_last_returned_time;
+ double frame_last_filter_delay;
+ int video_stream;
+ AVStream *video_st;
+ PacketQueue videoq;
+ double max_frame_duration; // maximum duration of a frame - above this, we consider the jump a timestamp discontinuity
+#if !CONFIG_AVFILTER
+ struct SwsContext *img_convert_ctx;
+#endif
+ SDL_Rect last_display_rect;
+ int eof;
+
+ char filename[1024];
+ int width, height, xleft, ytop;
+ int step;
+
+#if CONFIG_AVFILTER
+ int vfilter_idx;
+ AVFilterContext *in_video_filter; // the first filter in the video chain
+ AVFilterContext *out_video_filter; // the last filter in the video chain
+ AVFilterContext *in_audio_filter; // the first filter in the audio chain
+ AVFilterContext *out_audio_filter; // the last filter in the audio chain
+ AVFilterGraph *agraph; // audio filter graph
+#endif
+
+ int last_video_stream, last_audio_stream, last_subtitle_stream;
+
+ SDL_cond *continue_read_thread;
+} VideoState;
+
+/* options specified by the user */
+static AVInputFormat *file_iformat;
+static const char *input_filename;
+static const char *window_title;
+static int fs_screen_width;
+static int fs_screen_height;
+static int default_width = 640;
+static int default_height = 480;
+static int screen_width = 0;
+static int screen_height = 0;
+static int audio_disable;
+static int video_disable;
+static int subtitle_disable;
+static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0};
+static int seek_by_bytes = -1;
+static int display_disable;
+static int show_status = 1;
+static int av_sync_type = AV_SYNC_AUDIO_MASTER;
+static int64_t start_time = AV_NOPTS_VALUE;
+static int64_t duration = AV_NOPTS_VALUE;
+static int fast = 0;
+static int genpts = 0;
+static int lowres = 0;
+static int decoder_reorder_pts = -1;
+static int autoexit;
+static int exit_on_keydown;
+static int exit_on_mousedown;
+static int loop = 1;
+static int framedrop = -1;
+static int infinite_buffer = -1;
+static enum ShowMode show_mode = SHOW_MODE_NONE;
+static const char *audio_codec_name;
+static const char *subtitle_codec_name;
+static const char *video_codec_name;
+double rdftspeed = 0.02;
+static int64_t cursor_last_shown;
+static int cursor_hidden = 0;
+#if CONFIG_AVFILTER
+static const char **vfilters_list = NULL;
+static int nb_vfilters = 0;
+static char *afilters = NULL;
+#endif
+static int autorotate = 1;
+
+/* current context */
+static int is_full_screen;
+static int64_t audio_callback_time;
+
+static AVPacket flush_pkt;
+
+#define FF_ALLOC_EVENT (SDL_USEREVENT)
+#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
+
+static SDL_Surface *screen;
+
+#if CONFIG_AVFILTER
+static int opt_add_vfilter(void *optctx, const char *opt, const char *arg)
+{
+ GROW_ARRAY(vfilters_list, nb_vfilters);
+ vfilters_list[nb_vfilters - 1] = arg;
+ return 0;
+}
+#endif
+
+static inline
+int cmp_audio_fmts(enum AVSampleFormat fmt1, int64_t channel_count1,
+ enum AVSampleFormat fmt2, int64_t channel_count2)
+{
+ /* If channel count == 1, planar and non-planar formats are the same */
+ if (channel_count1 == 1 && channel_count2 == 1)
+ return av_get_packed_sample_fmt(fmt1) != av_get_packed_sample_fmt(fmt2);
+ else
+ return channel_count1 != channel_count2 || fmt1 != fmt2;
+}
+
+static inline
+int64_t get_valid_channel_layout(int64_t channel_layout, int channels)
+{
+ if (channel_layout && av_get_channel_layout_nb_channels(channel_layout) == channels)
+ return channel_layout;
+ else
+ return 0;
+}
+
+static void free_picture(Frame *vp);
+
+static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
+{
+ MyAVPacketList *pkt1;
+
+ if (q->abort_request)
+ return -1;
+
+ pkt1 = av_malloc(sizeof(MyAVPacketList));
+ if (!pkt1)
+ return -1;
+ pkt1->pkt = *pkt;
+ pkt1->next = NULL;
+ if (pkt == &flush_pkt)
+ q->serial++;
+ pkt1->serial = q->serial;
+
+ if (!q->last_pkt)
+ q->first_pkt = pkt1;
+ else
+ q->last_pkt->next = pkt1;
+ q->last_pkt = pkt1;
+ q->nb_packets++;
+ q->size += pkt1->pkt.size + sizeof(*pkt1);
+ /* XXX: should duplicate packet data in DV case */
+ SDL_CondSignal(q->cond);
+ return 0;
+}
+
+static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
+{
+ int ret;
+
+ /* duplicate the packet */
+ if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
+ return -1;
+
+ SDL_LockMutex(q->mutex);
+ ret = packet_queue_put_private(q, pkt);
+ SDL_UnlockMutex(q->mutex);
+
+ if (pkt != &flush_pkt && ret < 0)
+ av_free_packet(pkt);
+
+ return ret;
+}
+
+static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
+{
+ AVPacket pkt1, *pkt = &pkt1;
+ av_init_packet(pkt);
+ pkt->data = NULL;
+ pkt->size = 0;
+ pkt->stream_index = stream_index;
+ return packet_queue_put(q, pkt);
+}
+
+/* packet queue handling */
+static void packet_queue_init(PacketQueue *q)
+{
+ memset(q, 0, sizeof(PacketQueue));
+ q->mutex = SDL_CreateMutex();
+ q->cond = SDL_CreateCond();
+ q->abort_request = 1;
+}
+
+static void packet_queue_flush(PacketQueue *q)
+{
+ MyAVPacketList *pkt, *pkt1;
+
+ SDL_LockMutex(q->mutex);
+ for (pkt = q->first_pkt; pkt; pkt = pkt1) {
+ pkt1 = pkt->next;
+ av_free_packet(&pkt->pkt);
+ av_freep(&pkt);
+ }
+ q->last_pkt = NULL;
+ q->first_pkt = NULL;
+ q->nb_packets = 0;
+ q->size = 0;
+ SDL_UnlockMutex(q->mutex);
+}
+
+static void packet_queue_destroy(PacketQueue *q)
+{
+ packet_queue_flush(q);
+ SDL_DestroyMutex(q->mutex);
+ SDL_DestroyCond(q->cond);
+}
+
+static void packet_queue_abort(PacketQueue *q)
+{
+ SDL_LockMutex(q->mutex);
+
+ q->abort_request = 1;
+
+ SDL_CondSignal(q->cond);
+
+ SDL_UnlockMutex(q->mutex);
+}
+
+static void packet_queue_start(PacketQueue *q)
+{
+ SDL_LockMutex(q->mutex);
+ q->abort_request = 0;
+ packet_queue_put_private(q, &flush_pkt);
+ SDL_UnlockMutex(q->mutex);
+}
+
+/* return < 0 if aborted, 0 if no packet and > 0 if packet. */
+static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
+{
+ MyAVPacketList *pkt1;
+ int ret;
+
+ SDL_LockMutex(q->mutex);
+
+ for (;;) {
+ if (q->abort_request) {
+ ret = -1;
+ break;
+ }
+
+ pkt1 = q->first_pkt;
+ if (pkt1) {
+ q->first_pkt = pkt1->next;
+ if (!q->first_pkt)
+ q->last_pkt = NULL;
+ q->nb_packets--;
+ q->size -= pkt1->pkt.size + sizeof(*pkt1);
+ *pkt = pkt1->pkt;
+ if (serial)
+ *serial = pkt1->serial;
+ av_free(pkt1);
+ ret = 1;
+ break;
+ } else if (!block) {
+ ret = 0;
+ break;
+ } else {
+ SDL_CondWait(q->cond, q->mutex);
+ }
+ }
+ SDL_UnlockMutex(q->mutex);
+ return ret;
+}
+
+static void decoder_init(Decoder *d, AVCodecContext *avctx, PacketQueue *queue, SDL_cond *empty_queue_cond) {
+ memset(d, 0, sizeof(Decoder));
+ d->avctx = avctx;
+ d->queue = queue;
+ d->empty_queue_cond = empty_queue_cond;
+ d->start_pts = AV_NOPTS_VALUE;
+}
+
+static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
+ int got_frame = 0;
+
+ do {
+ int ret = -1;
+
+ if (d->queue->abort_request)
+ return -1;
+
+ if (!d->packet_pending || d->queue->serial != d->pkt_serial) {
+ AVPacket pkt;
+ do {
+ if (d->queue->nb_packets == 0)
+ SDL_CondSignal(d->empty_queue_cond);
+ if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
+ return -1;
+ if (pkt.data == flush_pkt.data) {
+ avcodec_flush_buffers(d->avctx);
+ d->finished = 0;
+ d->next_pts = d->start_pts;
+ d->next_pts_tb = d->start_pts_tb;
+ }
+ } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
+ av_free_packet(&d->pkt);
+ d->pkt_temp = d->pkt = pkt;
+ d->packet_pending = 1;
+ }
+
+ switch (d->avctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
+ if (got_frame) {
+ if (decoder_reorder_pts == -1) {
+ frame->pts = av_frame_get_best_effort_timestamp(frame);
+ } else if (decoder_reorder_pts) {
+ frame->pts = frame->pkt_pts;
+ } else {
+ frame->pts = frame->pkt_dts;
+ }
+ }
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
+ if (got_frame) {
+ AVRational tb = (AVRational){1, frame->sample_rate};
+ if (frame->pts != AV_NOPTS_VALUE)
+ frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb);
+ else if (frame->pkt_pts != AV_NOPTS_VALUE)
+ frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb);
+ else if (d->next_pts != AV_NOPTS_VALUE)
+ frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
+ if (frame->pts != AV_NOPTS_VALUE) {
+ d->next_pts = frame->pts + frame->nb_samples;
+ d->next_pts_tb = tb;
+ }
+ }
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp);
+ break;
+ }
+
+ if (ret < 0) {
+ d->packet_pending = 0;
+ } else {
+ d->pkt_temp.dts =
+ d->pkt_temp.pts = AV_NOPTS_VALUE;
+ if (d->pkt_temp.data) {
+ if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)
+ ret = d->pkt_temp.size;
+ d->pkt_temp.data += ret;
+ d->pkt_temp.size -= ret;
+ if (d->pkt_temp.size <= 0)
+ d->packet_pending = 0;
+ } else {
+ if (!got_frame) {
+ d->packet_pending = 0;
+ d->finished = d->pkt_serial;
+ }
+ }
+ }
+ } while (!got_frame && !d->finished);
+
+ return got_frame;
+}
+
+static void decoder_destroy(Decoder *d) {
+ av_free_packet(&d->pkt);
+}
+
+static void frame_queue_unref_item(Frame *vp)
+{
+ av_frame_unref(vp->frame);
+ avsubtitle_free(&vp->sub);
+}
+
+static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last)
+{
+ int i;
+ memset(f, 0, sizeof(FrameQueue));
+ if (!(f->mutex = SDL_CreateMutex()))
+ return AVERROR(ENOMEM);
+ if (!(f->cond = SDL_CreateCond()))
+ return AVERROR(ENOMEM);
+ f->pktq = pktq;
+ f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
+ f->keep_last = !!keep_last;
+ for (i = 0; i < f->max_size; i++)
+ if (!(f->queue[i].frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static void frame_queue_destory(FrameQueue *f)
+{
+ int i;
+ for (i = 0; i < f->max_size; i++) {
+ Frame *vp = &f->queue[i];
+ frame_queue_unref_item(vp);
+ av_frame_free(&vp->frame);
+ free_picture(vp);
+ }
+ SDL_DestroyMutex(f->mutex);
+ SDL_DestroyCond(f->cond);
+}
+
+static void frame_queue_signal(FrameQueue *f)
+{
+ SDL_LockMutex(f->mutex);
+ SDL_CondSignal(f->cond);
+ SDL_UnlockMutex(f->mutex);
+}
+
+static Frame *frame_queue_peek(FrameQueue *f)
+{
+ return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
+}
+
+static Frame *frame_queue_peek_next(FrameQueue *f)
+{
+ return &f->queue[(f->rindex + f->rindex_shown + 1) % f->max_size];
+}
+
+static Frame *frame_queue_peek_last(FrameQueue *f)
+{
+ return &f->queue[f->rindex];
+}
+
+static Frame *frame_queue_peek_writable(FrameQueue *f)
+{
+ /* wait until we have space to put a new frame */
+ SDL_LockMutex(f->mutex);
+ while (f->size >= f->max_size &&
+ !f->pktq->abort_request) {
+ SDL_CondWait(f->cond, f->mutex);
+ }
+ SDL_UnlockMutex(f->mutex);
+
+ if (f->pktq->abort_request)
+ return NULL;
+
+ return &f->queue[f->windex];
+}
+
+static Frame *frame_queue_peek_readable(FrameQueue *f)
+{
+ /* wait until we have a readable a new frame */
+ SDL_LockMutex(f->mutex);
+ while (f->size - f->rindex_shown <= 0 &&
+ !f->pktq->abort_request) {
+ SDL_CondWait(f->cond, f->mutex);
+ }
+ SDL_UnlockMutex(f->mutex);
+
+ if (f->pktq->abort_request)
+ return NULL;
+
+ return &f->queue[(f->rindex + f->rindex_shown) % f->max_size];
+}
+
+static void frame_queue_push(FrameQueue *f)
+{
+ if (++f->windex == f->max_size)
+ f->windex = 0;
+ SDL_LockMutex(f->mutex);
+ f->size++;
+ SDL_CondSignal(f->cond);
+ SDL_UnlockMutex(f->mutex);
+}
+
+static void frame_queue_next(FrameQueue *f)
+{
+ if (f->keep_last && !f->rindex_shown) {
+ f->rindex_shown = 1;
+ return;
+ }
+ frame_queue_unref_item(&f->queue[f->rindex]);
+ if (++f->rindex == f->max_size)
+ f->rindex = 0;
+ SDL_LockMutex(f->mutex);
+ f->size--;
+ SDL_CondSignal(f->cond);
+ SDL_UnlockMutex(f->mutex);
+}
+
+/* jump back to the previous frame if available by resetting rindex_shown */
+static int frame_queue_prev(FrameQueue *f)
+{
+ int ret = f->rindex_shown;
+ f->rindex_shown = 0;
+ return ret;
+}
+
+/* return the number of undisplayed frames in the queue */
+static int frame_queue_nb_remaining(FrameQueue *f)
+{
+ return f->size - f->rindex_shown;
+}
+
+/* return last shown position */
+static int64_t frame_queue_last_pos(FrameQueue *f)
+{
+ Frame *fp = &f->queue[f->rindex];
+ if (f->rindex_shown && fp->serial == f->pktq->serial)
+ return fp->pos;
+ else
+ return -1;
+}
+
+static void decoder_abort(Decoder *d, FrameQueue *fq)
+{
+ packet_queue_abort(d->queue);
+ frame_queue_signal(fq);
+ SDL_WaitThread(d->decoder_tid, NULL);
+ d->decoder_tid = NULL;
+ packet_queue_flush(d->queue);
+}
+
+static inline void fill_rectangle(SDL_Surface *screen,
+ int x, int y, int w, int h, int color, int update)
+{
+ SDL_Rect rect;
+ rect.x = x;
+ rect.y = y;
+ rect.w = w;
+ rect.h = h;
+ SDL_FillRect(screen, &rect, color);
+ if (update && w > 0 && h > 0)
+ SDL_UpdateRect(screen, x, y, w, h);
+}
+
+/* draw only the border of a rectangle */
+static void fill_border(int xleft, int ytop, int width, int height, int x, int y, int w, int h, int color, int update)
+{
+ int w1, w2, h1, h2;
+
+ /* fill the background */
+ w1 = x;
+ if (w1 < 0)
+ w1 = 0;
+ w2 = width - (x + w);
+ if (w2 < 0)
+ w2 = 0;
+ h1 = y;
+ if (h1 < 0)
+ h1 = 0;
+ h2 = height - (y + h);
+ if (h2 < 0)
+ h2 = 0;
+ fill_rectangle(screen,
+ xleft, ytop,
+ w1, height,
+ color, update);
+ fill_rectangle(screen,
+ xleft + width - w2, ytop,
+ w2, height,
+ color, update);
+ fill_rectangle(screen,
+ xleft + w1, ytop,
+ width - w1 - w2, h1,
+ color, update);
+ fill_rectangle(screen,
+ xleft + w1, ytop + height - h2,
+ width - w1 - w2, h2,
+ color, update);
+}
+
+#define ALPHA_BLEND(a, oldp, newp, s)\
+((((oldp << s) * (255 - (a))) + (newp * (a))) / (255 << s))
+
+#define RGBA_IN(r, g, b, a, s)\
+{\
+ unsigned int v = ((const uint32_t *)(s))[0];\
+ a = (v >> 24) & 0xff;\
+ r = (v >> 16) & 0xff;\
+ g = (v >> 8) & 0xff;\
+ b = v & 0xff;\
+}
+
+#define YUVA_IN(y, u, v, a, s, pal)\
+{\
+ unsigned int val = ((const uint32_t *)(pal))[*(const uint8_t*)(s)];\
+ a = (val >> 24) & 0xff;\
+ y = (val >> 16) & 0xff;\
+ u = (val >> 8) & 0xff;\
+ v = val & 0xff;\
+}
+
+#define YUVA_OUT(d, y, u, v, a)\
+{\
+ ((uint32_t *)(d))[0] = (a << 24) | (y << 16) | (u << 8) | v;\
+}
+
+
+#define BPP 1
+
+static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
+{
+ int wrap, wrap3, width2, skip2;
+ int y, u, v, a, u1, v1, a1, w, h;
+ uint8_t *lum, *cb, *cr;
+ const uint8_t *p;
+ const uint32_t *pal;
+ int dstx, dsty, dstw, dsth;
+
+ dstw = av_clip(rect->w, 0, imgw);
+ dsth = av_clip(rect->h, 0, imgh);
+ dstx = av_clip(rect->x, 0, imgw - dstw);
+ dsty = av_clip(rect->y, 0, imgh - dsth);
+ lum = dst->data[0] + dsty * dst->linesize[0];
+ cb = dst->data[1] + (dsty >> 1) * dst->linesize[1];
+ cr = dst->data[2] + (dsty >> 1) * dst->linesize[2];
+
+ width2 = ((dstw + 1) >> 1) + (dstx & ~dstw & 1);
+ skip2 = dstx >> 1;
+ wrap = dst->linesize[0];
+ wrap3 = rect->pict.linesize[0];
+ p = rect->pict.data[0];
+ pal = (const uint32_t *)rect->pict.data[1]; /* Now in YCrCb! */
+
+ if (dsty & 1) {
+ lum += dstx;
+ cb += skip2;
+ cr += skip2;
+
+ if (dstx & 1) {
+ YUVA_IN(y, u, v, a, p, pal);
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
+ cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
+ cb++;
+ cr++;
+ lum++;
+ p += BPP;
+ }
+ for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 = u;
+ v1 = v;
+ a1 = a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+
+ YUVA_IN(y, u, v, a, p + BPP, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
+ cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
+ cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
+ cb++;
+ cr++;
+ p += 2 * BPP;
+ lum += 2;
+ }
+ if (w) {
+ YUVA_IN(y, u, v, a, p, pal);
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
+ cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
+ p++;
+ lum++;
+ }
+ p += wrap3 - dstw * BPP;
+ lum += wrap - dstw - dstx;
+ cb += dst->linesize[1] - width2 - skip2;
+ cr += dst->linesize[2] - width2 - skip2;
+ }
+ for (h = dsth - (dsty & 1); h >= 2; h -= 2) {
+ lum += dstx;
+ cb += skip2;
+ cr += skip2;
+
+ if (dstx & 1) {
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 = u;
+ v1 = v;
+ a1 = a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ p += wrap3;
+ lum += wrap;
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
+ cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
+ cb++;
+ cr++;
+ p += -wrap3 + BPP;
+ lum += -wrap + 1;
+ }
+ for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 = u;
+ v1 = v;
+ a1 = a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+
+ YUVA_IN(y, u, v, a, p + BPP, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
+ p += wrap3;
+ lum += wrap;
+
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+
+ YUVA_IN(y, u, v, a, p + BPP, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
+
+ cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2);
+ cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2);
+
+ cb++;
+ cr++;
+ p += -wrap3 + 2 * BPP;
+ lum += -wrap + 2;
+ }
+ if (w) {
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 = u;
+ v1 = v;
+ a1 = a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ p += wrap3;
+ lum += wrap;
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
+ cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
+ cb++;
+ cr++;
+ p += -wrap3 + BPP;
+ lum += -wrap + 1;
+ }
+ p += wrap3 + (wrap3 - dstw * BPP);
+ lum += wrap + (wrap - dstw - dstx);
+ cb += dst->linesize[1] - width2 - skip2;
+ cr += dst->linesize[2] - width2 - skip2;
+ }
+ /* handle odd height */
+ if (h) {
+ lum += dstx;
+ cb += skip2;
+ cr += skip2;
+
+ if (dstx & 1) {
+ YUVA_IN(y, u, v, a, p, pal);
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
+ cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
+ cb++;
+ cr++;
+ lum++;
+ p += BPP;
+ }
+ for (w = dstw - (dstx & 1); w >= 2; w -= 2) {
+ YUVA_IN(y, u, v, a, p, pal);
+ u1 = u;
+ v1 = v;
+ a1 = a;
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+
+ YUVA_IN(y, u, v, a, p + BPP, pal);
+ u1 += u;
+ v1 += v;
+ a1 += a;
+ lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
+ cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1);
+ cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1);
+ cb++;
+ cr++;
+ p += 2 * BPP;
+ lum += 2;
+ }
+ if (w) {
+ YUVA_IN(y, u, v, a, p, pal);
+ lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
+ cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
+ cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
+ }
+ }
+}
+
+static void free_picture(Frame *vp)
+{
+ if (vp->bmp) {
+ SDL_FreeYUVOverlay(vp->bmp);
+ vp->bmp = NULL;
+ }
+}
+
+static void calculate_display_rect(SDL_Rect *rect,
+ int scr_xleft, int scr_ytop, int scr_width, int scr_height,
+ int pic_width, int pic_height, AVRational pic_sar)
+{
+ float aspect_ratio;
+ int width, height, x, y;
+
+ if (pic_sar.num == 0)
+ aspect_ratio = 0;
+ else
+ aspect_ratio = av_q2d(pic_sar);
+
+ if (aspect_ratio <= 0.0)
+ aspect_ratio = 1.0;
+ aspect_ratio *= (float)pic_width / (float)pic_height;
+
+ /* XXX: we suppose the screen has a 1.0 pixel ratio */
+ height = scr_height;
+ width = ((int)rint(height * aspect_ratio)) & ~1;
+ if (width > scr_width) {
+ width = scr_width;
+ height = ((int)rint(width / aspect_ratio)) & ~1;
+ }
+ x = (scr_width - width) / 2;
+ y = (scr_height - height) / 2;
+ rect->x = scr_xleft + x;
+ rect->y = scr_ytop + y;
+ rect->w = FFMAX(width, 1);
+ rect->h = FFMAX(height, 1);
+}
+
+static void video_image_display(VideoState *is)
+{
+ Frame *vp;
+ Frame *sp;
+ AVPicture pict;
+ SDL_Rect rect;
+ int i;
+
+ vp = frame_queue_peek(&is->pictq);
+ if (vp->bmp) {
+ if (is->subtitle_st) {
+ if (frame_queue_nb_remaining(&is->subpq) > 0) {
+ sp = frame_queue_peek(&is->subpq);
+
+ if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
+ SDL_LockYUVOverlay (vp->bmp);
+
+ pict.data[0] = vp->bmp->pixels[0];
+ pict.data[1] = vp->bmp->pixels[2];
+ pict.data[2] = vp->bmp->pixels[1];
+
+ pict.linesize[0] = vp->bmp->pitches[0];
+ pict.linesize[1] = vp->bmp->pitches[2];
+ pict.linesize[2] = vp->bmp->pitches[1];
+
+ for (i = 0; i < sp->sub.num_rects; i++)
+ blend_subrect(&pict, sp->sub.rects[i],
+ vp->bmp->w, vp->bmp->h);
+
+ SDL_UnlockYUVOverlay (vp->bmp);
+ }
+ }
+ }
+
+ calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar);
+
+ SDL_DisplayYUVOverlay(vp->bmp, &rect);
+
+ if (rect.x != is->last_display_rect.x || rect.y != is->last_display_rect.y || rect.w != is->last_display_rect.w || rect.h != is->last_display_rect.h || is->force_refresh) {
+ int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
+ fill_border(is->xleft, is->ytop, is->width, is->height, rect.x, rect.y, rect.w, rect.h, bgcolor, 1);
+ is->last_display_rect = rect;
+ }
+ }
+}
+
+static inline int compute_mod(int a, int b)
+{
+ return a < 0 ? a%b + b : a%b;
+}
+
+static void video_audio_display(VideoState *s)
+{
+ int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
+ int ch, channels, h, h2, bgcolor, fgcolor;
+ int64_t time_diff;
+ int rdft_bits, nb_freq;
+
+ for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++)
+ ;
+ nb_freq = 1 << (rdft_bits - 1);
+
+ /* compute display index : center on currently output samples */
+ channels = s->audio_tgt.channels;
+ nb_display_channels = channels;
+ if (!s->paused) {
+ int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq);
+ n = 2 * channels;
+ delay = s->audio_write_buf_size;
+ delay /= n;
+
+ /* to be more precise, we take into account the time spent since
+ the last buffer computation */
+ if (audio_callback_time) {
+ time_diff = av_gettime_relative() - audio_callback_time;
+ delay -= (time_diff * s->audio_tgt.freq) / 1000000;
+ }
+
+ delay += 2 * data_used;
+ if (delay < data_used)
+ delay = data_used;
+
+ i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
+ if (s->show_mode == SHOW_MODE_WAVES) {
+ h = INT_MIN;
+ for (i = 0; i < 1000; i += channels) {
+ int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE;
+ int a = s->sample_array[idx];
+ int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE];
+ int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE];
+ int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE];
+ int score = a - d;
+ if (h < score && (b ^ c) < 0) {
+ h = score;
+ i_start = idx;
+ }
+ }
+ }
+
+ s->last_i_start = i_start;
+ } else {
+ i_start = s->last_i_start;
+ }
+
+ bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
+ if (s->show_mode == SHOW_MODE_WAVES) {
+ fill_rectangle(screen,
+ s->xleft, s->ytop, s->width, s->height,
+ bgcolor, 0);
+
+ fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
+
+ /* total height for one channel */
+ h = s->height / nb_display_channels;
+ /* graph height / 2 */
+ h2 = (h * 9) / 20;
+ for (ch = 0; ch < nb_display_channels; ch++) {
+ i = i_start + ch;
+ y1 = s->ytop + ch * h + (h / 2); /* position of center line */
+ for (x = 0; x < s->width; x++) {
+ y = (s->sample_array[i] * h2) >> 15;
+ if (y < 0) {
+ y = -y;
+ ys = y1 - y;
+ } else {
+ ys = y1;
+ }
+ fill_rectangle(screen,
+ s->xleft + x, ys, 1, y,
+ fgcolor, 0);
+ i += channels;
+ if (i >= SAMPLE_ARRAY_SIZE)
+ i -= SAMPLE_ARRAY_SIZE;
+ }
+ }
+
+ fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
+
+ for (ch = 1; ch < nb_display_channels; ch++) {
+ y = s->ytop + ch * h;
+ fill_rectangle(screen,
+ s->xleft, y, s->width, 1,
+ fgcolor, 0);
+ }
+ SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
+ } else {
+ nb_display_channels= FFMIN(nb_display_channels, 2);
+ if (rdft_bits != s->rdft_bits) {
+ av_rdft_end(s->rdft);
+ av_free(s->rdft_data);
+ s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
+ s->rdft_bits = rdft_bits;
+ s->rdft_data = av_malloc_array(nb_freq, 4 *sizeof(*s->rdft_data));
+ }
+ if (!s->rdft || !s->rdft_data){
+ av_log(NULL, AV_LOG_ERROR, "Failed to allocate buffers for RDFT, switching to waves display\n");
+ s->show_mode = SHOW_MODE_WAVES;
+ } else {
+ FFTSample *data[2];
+ for (ch = 0; ch < nb_display_channels; ch++) {
+ data[ch] = s->rdft_data + 2 * nb_freq * ch;
+ i = i_start + ch;
+ for (x = 0; x < 2 * nb_freq; x++) {
+ double w = (x-nb_freq) * (1.0 / nb_freq);
+ data[ch][x] = s->sample_array[i] * (1.0 - w * w);
+ i += channels;
+ if (i >= SAMPLE_ARRAY_SIZE)
+ i -= SAMPLE_ARRAY_SIZE;
+ }
+ av_rdft_calc(s->rdft, data[ch]);
+ }
+ /* Least efficient way to do this, we should of course
+ * directly access it but it is more than fast enough. */
+ for (y = 0; y < s->height; y++) {
+ double w = 1 / sqrt(nb_freq);
+ int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1]));
+ int b = (nb_display_channels == 2 ) ? sqrt(w * sqrt(data[1][2 * y + 0] * data[1][2 * y + 0]
+ + data[1][2 * y + 1] * data[1][2 * y + 1])) : a;
+ a = FFMIN(a, 255);
+ b = FFMIN(b, 255);
+ fgcolor = SDL_MapRGB(screen->format, a, b, (a + b) / 2);
+
+ fill_rectangle(screen,
+ s->xpos, s->height-y, 1, 1,
+ fgcolor, 0);
+ }
+ }
+ SDL_UpdateRect(screen, s->xpos, s->ytop, 1, s->height);
+ if (!s->paused)
+ s->xpos++;
+ if (s->xpos >= s->width)
+ s->xpos= s->xleft;
+ }
+}
+
+static void stream_close(VideoState *is)
+{
+ /* XXX: use a special url_shutdown call to abort parse cleanly */
+ is->abort_request = 1;
+ SDL_WaitThread(is->read_tid, NULL);
+ packet_queue_destroy(&is->videoq);
+ packet_queue_destroy(&is->audioq);
+ packet_queue_destroy(&is->subtitleq);
+
+ /* free all pictures */
+ frame_queue_destory(&is->pictq);
+ frame_queue_destory(&is->sampq);
+ frame_queue_destory(&is->subpq);
+ SDL_DestroyCond(is->continue_read_thread);
+#if !CONFIG_AVFILTER
+ sws_freeContext(is->img_convert_ctx);
+#endif
+ av_free(is);
+}
+
+static void do_exit(VideoState *is)
+{
+ if (is) {
+ stream_close(is);
+ }
+ av_lockmgr_register(NULL);
+ uninit_opts();
+#if CONFIG_AVFILTER
+ av_freep(&vfilters_list);
+#endif
+ avformat_network_deinit();
+ if (show_status)
+ printf("\n");
+ SDL_Quit();
+ av_log(NULL, AV_LOG_QUIET, "%s", "");
+ exit(0);
+}
+
+static void sigterm_handler(int sig)
+{
+ exit(123);
+}
+
+static void set_default_window_size(int width, int height, AVRational sar)
+{
+ SDL_Rect rect;
+ calculate_display_rect(&rect, 0, 0, INT_MAX, height, width, height, sar);
+ default_width = rect.w;
+ default_height = rect.h;
+}
+
+static int video_open(VideoState *is, int force_set_video_mode, Frame *vp)
+{
+ int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
+ int w,h;
+
+ if (is_full_screen) flags |= SDL_FULLSCREEN;
+ else flags |= SDL_RESIZABLE;
+
+ if (vp && vp->width)
+ set_default_window_size(vp->width, vp->height, vp->sar);
+
+ if (is_full_screen && fs_screen_width) {
+ w = fs_screen_width;
+ h = fs_screen_height;
+ } else if (!is_full_screen && screen_width) {
+ w = screen_width;
+ h = screen_height;
+ } else {
+ w = default_width;
+ h = default_height;
+ }
+ w = FFMIN(16383, w);
+ if (screen && is->width == screen->w && screen->w == w
+ && is->height== screen->h && screen->h == h && !force_set_video_mode)
+ return 0;
+ screen = SDL_SetVideoMode(w, h, 0, flags);
+ if (!screen) {
+ av_log(NULL, AV_LOG_FATAL, "SDL: could not set video mode - exiting\n");
+ do_exit(is);
+ }
+ if (!window_title)
+ window_title = input_filename;
+ SDL_WM_SetCaption(window_title, window_title);
+
+ is->width = screen->w;
+ is->height = screen->h;
+
+ return 0;
+}
+
+/* display the current picture, if any */
+static void video_display(VideoState *is)
+{
+ if (!screen)
+ video_open(is, 0, NULL);
+ if (is->audio_st && is->show_mode != SHOW_MODE_VIDEO)
+ video_audio_display(is);
+ else if (is->video_st)
+ video_image_display(is);
+}
+
+static double get_clock(Clock *c)
+{
+ if (*c->queue_serial != c->serial)
+ return NAN;
+ if (c->paused) {
+ return c->pts;
+ } else {
+ double time = av_gettime_relative() / 1000000.0;
+ return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
+ }
+}
+
+static void set_clock_at(Clock *c, double pts, int serial, double time)
+{
+ c->pts = pts;
+ c->last_updated = time;
+ c->pts_drift = c->pts - time;
+ c->serial = serial;
+}
+
+static void set_clock(Clock *c, double pts, int serial)
+{
+ double time = av_gettime_relative() / 1000000.0;
+ set_clock_at(c, pts, serial, time);
+}
+
+static void set_clock_speed(Clock *c, double speed)
+{
+ set_clock(c, get_clock(c), c->serial);
+ c->speed = speed;
+}
+
+static void init_clock(Clock *c, int *queue_serial)
+{
+ c->speed = 1.0;
+ c->paused = 0;
+ c->queue_serial = queue_serial;
+ set_clock(c, NAN, -1);
+}
+
+static void sync_clock_to_slave(Clock *c, Clock *slave)
+{
+ double clock = get_clock(c);
+ double slave_clock = get_clock(slave);
+ if (!isnan(slave_clock) && (isnan(clock) || fabs(clock - slave_clock) > AV_NOSYNC_THRESHOLD))
+ set_clock(c, slave_clock, slave->serial);
+}
+
+static int get_master_sync_type(VideoState *is) {
+ if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
+ if (is->video_st)
+ return AV_SYNC_VIDEO_MASTER;
+ else
+ return AV_SYNC_AUDIO_MASTER;
+ } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
+ if (is->audio_st)
+ return AV_SYNC_AUDIO_MASTER;
+ else
+ return AV_SYNC_EXTERNAL_CLOCK;
+ } else {
+ return AV_SYNC_EXTERNAL_CLOCK;
+ }
+}
+
+/* get the current master clock value */
+static double get_master_clock(VideoState *is)
+{
+ double val;
+
+ switch (get_master_sync_type(is)) {
+ case AV_SYNC_VIDEO_MASTER:
+ val = get_clock(&is->vidclk);
+ break;
+ case AV_SYNC_AUDIO_MASTER:
+ val = get_clock(&is->audclk);
+ break;
+ default:
+ val = get_clock(&is->extclk);
+ break;
+ }
+ return val;
+}
+
+static void check_external_clock_speed(VideoState *is) {
+ if (is->video_stream >= 0 && is->videoq.nb_packets <= MIN_FRAMES / 2 ||
+ is->audio_stream >= 0 && is->audioq.nb_packets <= MIN_FRAMES / 2) {
+ set_clock_speed(&is->extclk, FFMAX(EXTERNAL_CLOCK_SPEED_MIN, is->extclk.speed - EXTERNAL_CLOCK_SPEED_STEP));
+ } else if ((is->video_stream < 0 || is->videoq.nb_packets > MIN_FRAMES * 2) &&
+ (is->audio_stream < 0 || is->audioq.nb_packets > MIN_FRAMES * 2)) {
+ set_clock_speed(&is->extclk, FFMIN(EXTERNAL_CLOCK_SPEED_MAX, is->extclk.speed + EXTERNAL_CLOCK_SPEED_STEP));
+ } else {
+ double speed = is->extclk.speed;
+ if (speed != 1.0)
+ set_clock_speed(&is->extclk, speed + EXTERNAL_CLOCK_SPEED_STEP * (1.0 - speed) / fabs(1.0 - speed));
+ }
+}
+
+/* seek in the stream */
+static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes)
+{
+ if (!is->seek_req) {
+ is->seek_pos = pos;
+ is->seek_rel = rel;
+ is->seek_flags &= ~AVSEEK_FLAG_BYTE;
+ if (seek_by_bytes)
+ is->seek_flags |= AVSEEK_FLAG_BYTE;
+ is->seek_req = 1;
+ SDL_CondSignal(is->continue_read_thread);
+ }
+}
+
+/* pause or resume the video */
+static void stream_toggle_pause(VideoState *is)
+{
+ if (is->paused) {
+ is->frame_timer += av_gettime_relative() / 1000000.0 - is->vidclk.last_updated;
+ if (is->read_pause_return != AVERROR(ENOSYS)) {
+ is->vidclk.paused = 0;
+ }
+ set_clock(&is->vidclk, get_clock(&is->vidclk), is->vidclk.serial);
+ }
+ set_clock(&is->extclk, get_clock(&is->extclk), is->extclk.serial);
+ is->paused = is->audclk.paused = is->vidclk.paused = is->extclk.paused = !is->paused;
+}
+
+static void toggle_pause(VideoState *is)
+{
+ stream_toggle_pause(is);
+ is->step = 0;
+}
+
+static void step_to_next_frame(VideoState *is)
+{
+ /* if the stream is paused unpause it, then step */
+ if (is->paused)
+ stream_toggle_pause(is);
+ is->step = 1;
+}
+
+static double compute_target_delay(double delay, VideoState *is)
+{
+ double sync_threshold, diff = 0;
+
+ /* update delay to follow master synchronisation source */
+ if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
+ /* if video is slave, we try to correct big delays by
+ duplicating or deleting a frame */
+ diff = get_clock(&is->vidclk) - get_master_clock(is);
+
+ /* skip or repeat frame. We take into account the
+ delay to compute the threshold. I still don't know
+ if it is the best guess */
+ sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
+ if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {
+ if (diff <= -sync_threshold)
+ delay = FFMAX(0, delay + diff);
+ else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
+ delay = delay + diff;
+ else if (diff >= sync_threshold)
+ delay = 2 * delay;
+ }
+ }
+
+ av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n",
+ delay, -diff);
+
+ return delay;
+}
+
+static double vp_duration(VideoState *is, Frame *vp, Frame *nextvp) {
+ if (vp->serial == nextvp->serial) {
+ double duration = nextvp->pts - vp->pts;
+ if (isnan(duration) || duration <= 0 || duration > is->max_frame_duration)
+ return vp->duration;
+ else
+ return duration;
+ } else {
+ return 0.0;
+ }
+}
+
+static void update_video_pts(VideoState *is, double pts, int64_t pos, int serial) {
+ /* update current video pts */
+ set_clock(&is->vidclk, pts, serial);
+ sync_clock_to_slave(&is->extclk, &is->vidclk);
+}
+
+/* called to display each frame */
+static void video_refresh(void *opaque, double *remaining_time)
+{
+ VideoState *is = opaque;
+ double time;
+
+ Frame *sp, *sp2;
+
+ if (!is->paused && get_master_sync_type(is) == AV_SYNC_EXTERNAL_CLOCK && is->realtime)
+ check_external_clock_speed(is);
+
+ if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
+ time = av_gettime_relative() / 1000000.0;
+ if (is->force_refresh || is->last_vis_time + rdftspeed < time) {
+ video_display(is);
+ is->last_vis_time = time;
+ }
+ *remaining_time = FFMIN(*remaining_time, is->last_vis_time + rdftspeed - time);
+ }
+
+ if (is->video_st) {
+ int redisplay = 0;
+ if (is->force_refresh)
+ redisplay = frame_queue_prev(&is->pictq);
+retry:
+ if (frame_queue_nb_remaining(&is->pictq) == 0) {
+ // nothing to do, no picture to display in the queue
+ } else {
+ double last_duration, duration, delay;
+ Frame *vp, *lastvp;
+
+ /* dequeue the picture */
+ lastvp = frame_queue_peek_last(&is->pictq);
+ vp = frame_queue_peek(&is->pictq);
+
+ if (vp->serial != is->videoq.serial) {
+ frame_queue_next(&is->pictq);
+ redisplay = 0;
+ goto retry;
+ }
+
+ if (lastvp->serial != vp->serial && !redisplay)
+ is->frame_timer = av_gettime_relative() / 1000000.0;
+
+ if (is->paused)
+ goto display;
+
+ /* compute nominal last_duration */
+ last_duration = vp_duration(is, lastvp, vp);
+ if (redisplay)
+ delay = 0.0;
+ else
+ delay = compute_target_delay(last_duration, is);
+
+ time= av_gettime_relative()/1000000.0;
+ if (time < is->frame_timer + delay && !redisplay) {
+ *remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
+ return;
+ }
+
+ is->frame_timer += delay;
+ if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)
+ is->frame_timer = time;
+
+ SDL_LockMutex(is->pictq.mutex);
+ if (!redisplay && !isnan(vp->pts))
+ update_video_pts(is, vp->pts, vp->pos, vp->serial);
+ SDL_UnlockMutex(is->pictq.mutex);
+
+ if (frame_queue_nb_remaining(&is->pictq) > 1) {
+ Frame *nextvp = frame_queue_peek_next(&is->pictq);
+ duration = vp_duration(is, vp, nextvp);
+ if(!is->step && (redisplay || framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) && time > is->frame_timer + duration){
+ if (!redisplay)
+ is->frame_drops_late++;
+ frame_queue_next(&is->pictq);
+ redisplay = 0;
+ goto retry;
+ }
+ }
+
+ if (is->subtitle_st) {
+ while (frame_queue_nb_remaining(&is->subpq) > 0) {
+ sp = frame_queue_peek(&is->subpq);
+
+ if (frame_queue_nb_remaining(&is->subpq) > 1)
+ sp2 = frame_queue_peek_next(&is->subpq);
+ else
+ sp2 = NULL;
+
+ if (sp->serial != is->subtitleq.serial
+ || (is->vidclk.pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
+ || (sp2 && is->vidclk.pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
+ {
+ frame_queue_next(&is->subpq);
+ } else {
+ break;
+ }
+ }
+ }
+
+display:
+ /* display picture */
+ if (!display_disable && is->show_mode == SHOW_MODE_VIDEO)
+ video_display(is);
+
+ frame_queue_next(&is->pictq);
+
+ if (is->step && !is->paused)
+ stream_toggle_pause(is);
+ }
+ }
+ is->force_refresh = 0;
+ if (show_status) {
+ static int64_t last_time;
+ int64_t cur_time;
+ int aqsize, vqsize, sqsize;
+ double av_diff;
+
+ cur_time = av_gettime_relative();
+ if (!last_time || (cur_time - last_time) >= 30000) {
+ aqsize = 0;
+ vqsize = 0;
+ sqsize = 0;
+ if (is->audio_st)
+ aqsize = is->audioq.size;
+ if (is->video_st)
+ vqsize = is->videoq.size;
+ if (is->subtitle_st)
+ sqsize = is->subtitleq.size;
+ av_diff = 0;
+ if (is->audio_st && is->video_st)
+ av_diff = get_clock(&is->audclk) - get_clock(&is->vidclk);
+ else if (is->video_st)
+ av_diff = get_master_clock(is) - get_clock(&is->vidclk);
+ else if (is->audio_st)
+ av_diff = get_master_clock(is) - get_clock(&is->audclk);
+ av_log(NULL, AV_LOG_INFO,
+ "%7.2f %s:%7.3f fd=%4d aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64" \r",
+ get_master_clock(is),
+ (is->audio_st && is->video_st) ? "A-V" : (is->video_st ? "M-V" : (is->audio_st ? "M-A" : " ")),
+ av_diff,
+ is->frame_drops_early + is->frame_drops_late,
+ aqsize / 1024,
+ vqsize / 1024,
+ sqsize,
+ is->video_st ? is->video_st->codec->pts_correction_num_faulty_dts : 0,
+ is->video_st ? is->video_st->codec->pts_correction_num_faulty_pts : 0);
+ fflush(stdout);
+ last_time = cur_time;
+ }
+ }
+}
+
+/* allocate a picture (needs to do that in main thread to avoid
+ potential locking problems */
+static void alloc_picture(VideoState *is)
+{
+ Frame *vp;
+ int64_t bufferdiff;
+
+ vp = &is->pictq.queue[is->pictq.windex];
+
+ free_picture(vp);
+
+ video_open(is, 0, vp);
+
+ vp->bmp = SDL_CreateYUVOverlay(vp->width, vp->height,
+ SDL_YV12_OVERLAY,
+ screen);
+ bufferdiff = vp->bmp ? FFMAX(vp->bmp->pixels[0], vp->bmp->pixels[1]) - FFMIN(vp->bmp->pixels[0], vp->bmp->pixels[1]) : 0;
+ if (!vp->bmp || vp->bmp->pitches[0] < vp->width || bufferdiff < (int64_t)vp->height * vp->bmp->pitches[0]) {
+ /* SDL allocates a buffer smaller than requested if the video
+ * overlay hardware is unable to support the requested size. */
+ av_log(NULL, AV_LOG_FATAL,
+ "Error: the video system does not support an image\n"
+ "size of %dx%d pixels. Try using -lowres or -vf \"scale=w:h\"\n"
+ "to reduce the image size.\n", vp->width, vp->height );
+ do_exit(is);
+ }
+
+ SDL_LockMutex(is->pictq.mutex);
+ vp->allocated = 1;
+ SDL_CondSignal(is->pictq.cond);
+ SDL_UnlockMutex(is->pictq.mutex);
+}
+
+static void duplicate_right_border_pixels(SDL_Overlay *bmp) {
+ int i, width, height;
+ Uint8 *p, *maxp;
+ for (i = 0; i < 3; i++) {
+ width = bmp->w;
+ height = bmp->h;
+ if (i > 0) {
+ width >>= 1;
+ height >>= 1;
+ }
+ if (bmp->pitches[i] > width) {
+ maxp = bmp->pixels[i] + bmp->pitches[i] * height - 1;
+ for (p = bmp->pixels[i] + width - 1; p < maxp; p += bmp->pitches[i])
+ *(p+1) = *p;
+ }
+ }
+}
+
+static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double duration, int64_t pos, int serial)
+{
+ Frame *vp;
+
+#if defined(DEBUG_SYNC) && 0
+ printf("frame_type=%c pts=%0.3f\n",
+ av_get_picture_type_char(src_frame->pict_type), pts);
+#endif
+
+ if (!(vp = frame_queue_peek_writable(&is->pictq)))
+ return -1;
+
+ vp->sar = src_frame->sample_aspect_ratio;
+
+ /* alloc or resize hardware picture buffer */
+ if (!vp->bmp || vp->reallocate || !vp->allocated ||
+ vp->width != src_frame->width ||
+ vp->height != src_frame->height) {
+ SDL_Event event;
+
+ vp->allocated = 0;
+ vp->reallocate = 0;
+ vp->width = src_frame->width;
+ vp->height = src_frame->height;
+
+ /* the allocation must be done in the main thread to avoid
+ locking problems. */
+ event.type = FF_ALLOC_EVENT;
+ event.user.data1 = is;
+ SDL_PushEvent(&event);
+
+ /* wait until the picture is allocated */
+ SDL_LockMutex(is->pictq.mutex);
+ while (!vp->allocated && !is->videoq.abort_request) {
+ SDL_CondWait(is->pictq.cond, is->pictq.mutex);
+ }
+ /* if the queue is aborted, we have to pop the pending ALLOC event or wait for the allocation to complete */
+ if (is->videoq.abort_request && SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENTMASK(FF_ALLOC_EVENT)) != 1) {
+ while (!vp->allocated && !is->abort_request) {
+ SDL_CondWait(is->pictq.cond, is->pictq.mutex);
+ }
+ }
+ SDL_UnlockMutex(is->pictq.mutex);
+
+ if (is->videoq.abort_request)
+ return -1;
+ }
+
+ /* if the frame is not skipped, then display it */
+ if (vp->bmp) {
+ AVPicture pict = { { 0 } };
+
+ /* get a pointer on the bitmap */
+ SDL_LockYUVOverlay (vp->bmp);
+
+ pict.data[0] = vp->bmp->pixels[0];
+ pict.data[1] = vp->bmp->pixels[2];
+ pict.data[2] = vp->bmp->pixels[1];
+
+ pict.linesize[0] = vp->bmp->pitches[0];
+ pict.linesize[1] = vp->bmp->pitches[2];
+ pict.linesize[2] = vp->bmp->pitches[1];
+
+#if CONFIG_AVFILTER
+ // FIXME use direct rendering
+ av_picture_copy(&pict, (AVPicture *)src_frame,
+ src_frame->format, vp->width, vp->height);
+#else
+ av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags);
+ is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
+ vp->width, vp->height, src_frame->format, vp->width, vp->height,
+ AV_PIX_FMT_YUV420P, sws_flags, NULL, NULL, NULL);
+ if (!is->img_convert_ctx) {
+ av_log(NULL, AV_LOG_FATAL, "Cannot initialize the conversion context\n");
+ exit(1);
+ }
+ sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
+ 0, vp->height, pict.data, pict.linesize);
+#endif
+ /* workaround SDL PITCH_WORKAROUND */
+ duplicate_right_border_pixels(vp->bmp);
+ /* update the bitmap content */
+ SDL_UnlockYUVOverlay(vp->bmp);
+
+ vp->pts = pts;
+ vp->duration = duration;
+ vp->pos = pos;
+ vp->serial = serial;
+
+ /* now we can update the picture count */
+ frame_queue_push(&is->pictq);
+ }
+ return 0;
+}
+
+static int get_video_frame(VideoState *is, AVFrame *frame)
+{
+ int got_picture;
+
+ if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL)) < 0)
+ return -1;
+
+ if (got_picture) {
+ double dpts = NAN;
+
+ if (frame->pts != AV_NOPTS_VALUE)
+ dpts = av_q2d(is->video_st->time_base) * frame->pts;
+
+ frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic, is->video_st, frame);
+
+ if (framedrop>0 || (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER)) {
+ if (frame->pts != AV_NOPTS_VALUE) {
+ double diff = dpts - get_master_clock(is);
+ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD &&
+ diff - is->frame_last_filter_delay < 0 &&
+ is->viddec.pkt_serial == is->vidclk.serial &&
+ is->videoq.nb_packets) {
+ is->frame_drops_early++;
+ av_frame_unref(frame);
+ got_picture = 0;
+ }
+ }
+ }
+ }
+
+ return got_picture;
+}
+
+#if CONFIG_AVFILTER
+static int configure_filtergraph(AVFilterGraph *graph, const char *filtergraph,
+ AVFilterContext *source_ctx, AVFilterContext *sink_ctx)
+{
+ int ret, i;
+ int nb_filters = graph->nb_filters;
+ AVFilterInOut *outputs = NULL, *inputs = NULL;
+
+ if (filtergraph) {
+ outputs = avfilter_inout_alloc();
+ inputs = avfilter_inout_alloc();
+ if (!outputs || !inputs) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ outputs->name = av_strdup("in");
+ outputs->filter_ctx = source_ctx;
+ outputs->pad_idx = 0;
+ outputs->next = NULL;
+
+ inputs->name = av_strdup("out");
+ inputs->filter_ctx = sink_ctx;
+ inputs->pad_idx = 0;
+ inputs->next = NULL;
+
+ if ((ret = avfilter_graph_parse_ptr(graph, filtergraph, &inputs, &outputs, NULL)) < 0)
+ goto fail;
+ } else {
+ if ((ret = avfilter_link(source_ctx, 0, sink_ctx, 0)) < 0)
+ goto fail;
+ }
+
+ /* Reorder the filters to ensure that inputs of the custom filters are merged first */
+ for (i = 0; i < graph->nb_filters - nb_filters; i++)
+ FFSWAP(AVFilterContext*, graph->filters[i], graph->filters[i + nb_filters]);
+
+ ret = avfilter_graph_config(graph, NULL);
+fail:
+ avfilter_inout_free(&outputs);
+ avfilter_inout_free(&inputs);
+ return ret;
+}
+
+static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const char *vfilters, AVFrame *frame)
+{
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
+ char sws_flags_str[128];
+ char buffersrc_args[256];
+ int ret;
+ AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL;
+ AVCodecContext *codec = is->video_st->codec;
+ AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
+
+ av_opt_get_int(sws_opts, "sws_flags", 0, &sws_flags);
+ snprintf(sws_flags_str, sizeof(sws_flags_str), "flags=%"PRId64, sws_flags);
+ graph->scale_sws_opts = av_strdup(sws_flags_str);
+
+ snprintf(buffersrc_args, sizeof(buffersrc_args),
+ "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
+ frame->width, frame->height, frame->format,
+ is->video_st->time_base.num, is->video_st->time_base.den,
+ codec->sample_aspect_ratio.num, FFMAX(codec->sample_aspect_ratio.den, 1));
+ if (fr.num && fr.den)
+ av_strlcatf(buffersrc_args, sizeof(buffersrc_args), ":frame_rate=%d/%d", fr.num, fr.den);
+
+ if ((ret = avfilter_graph_create_filter(&filt_src,
+ avfilter_get_by_name("buffer"),
+ "ffplay_buffer", buffersrc_args, NULL,
+ graph)) < 0)
+ goto fail;
+
+ ret = avfilter_graph_create_filter(&filt_out,
+ avfilter_get_by_name("buffersink"),
+ "ffplay_buffersink", NULL, NULL, graph);
+ if (ret < 0)
+ goto fail;
+
+ if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto fail;
+
+ last_filter = filt_out;
+
+/* Note: this macro adds a filter before the lastly added filter, so the
+ * processing order of the filters is in reverse */
+#define INSERT_FILT(name, arg) do { \
+ AVFilterContext *filt_ctx; \
+ \
+ ret = avfilter_graph_create_filter(&filt_ctx, \
+ avfilter_get_by_name(name), \
+ "ffplay_" name, arg, NULL, graph); \
+ if (ret < 0) \
+ goto fail; \
+ \
+ ret = avfilter_link(filt_ctx, 0, last_filter, 0); \
+ if (ret < 0) \
+ goto fail; \
+ \
+ last_filter = filt_ctx; \
+} while (0)
+
+ /* SDL YUV code is not handling odd width/height for some driver
+ * combinations, therefore we crop the picture to an even width/height. */
+ INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2");
+
+ if (autorotate) {
+ double theta = get_rotation(is->video_st);
+
+ if (fabs(theta - 90) < 1.0) {
+ INSERT_FILT("transpose", "clock");
+ } else if (fabs(theta - 180) < 1.0) {
+ INSERT_FILT("hflip", NULL);
+ INSERT_FILT("vflip", NULL);
+ } else if (fabs(theta - 270) < 1.0) {
+ INSERT_FILT("transpose", "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);
+ }
+ }
+
+ if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)
+ goto fail;
+
+ is->in_video_filter = filt_src;
+ is->out_video_filter = filt_out;
+
+fail:
+ return ret;
+}
+
+static int configure_audio_filters(VideoState *is, const char *afilters, int force_output_format)
+{
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
+ int sample_rates[2] = { 0, -1 };
+ int64_t channel_layouts[2] = { 0, -1 };
+ int channels[2] = { 0, -1 };
+ AVFilterContext *filt_asrc = NULL, *filt_asink = NULL;
+ char aresample_swr_opts[512] = "";
+ AVDictionaryEntry *e = NULL;
+ char asrc_args[256];
+ int ret;
+
+ avfilter_graph_free(&is->agraph);
+ if (!(is->agraph = avfilter_graph_alloc()))
+ return AVERROR(ENOMEM);
+
+ while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX)))
+ av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value);
+ if (strlen(aresample_swr_opts))
+ aresample_swr_opts[strlen(aresample_swr_opts)-1] = '\0';
+ av_opt_set(is->agraph, "aresample_swr_opts", aresample_swr_opts, 0);
+
+ ret = snprintf(asrc_args, sizeof(asrc_args),
+ "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d",
+ is->audio_filter_src.freq, av_get_sample_fmt_name(is->audio_filter_src.fmt),
+ is->audio_filter_src.channels,
+ 1, is->audio_filter_src.freq);
+ if (is->audio_filter_src.channel_layout)
+ snprintf(asrc_args + ret, sizeof(asrc_args) - ret,
+ ":channel_layout=0x%"PRIx64, is->audio_filter_src.channel_layout);
+
+ ret = avfilter_graph_create_filter(&filt_asrc,
+ avfilter_get_by_name("abuffer"), "ffplay_abuffer",
+ asrc_args, NULL, is->agraph);
+ if (ret < 0)
+ goto end;
+
+
+ ret = avfilter_graph_create_filter(&filt_asink,
+ avfilter_get_by_name("abuffersink"), "ffplay_abuffersink",
+ NULL, NULL, is->agraph);
+ if (ret < 0)
+ goto end;
+
+ if ((ret = av_opt_set_int_list(filt_asink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto end;
+ if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto end;
+
+ if (force_output_format) {
+ channel_layouts[0] = is->audio_tgt.channel_layout;
+ channels [0] = is->audio_tgt.channels;
+ sample_rates [0] = is->audio_tgt.freq;
+ if ((ret = av_opt_set_int(filt_asink, "all_channel_counts", 0, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto end;
+ if ((ret = av_opt_set_int_list(filt_asink, "channel_layouts", channel_layouts, -1, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto end;
+ if ((ret = av_opt_set_int_list(filt_asink, "channel_counts" , channels , -1, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto end;
+ if ((ret = av_opt_set_int_list(filt_asink, "sample_rates" , sample_rates , -1, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto end;
+ }
+
+
+ if ((ret = configure_filtergraph(is->agraph, afilters, filt_asrc, filt_asink)) < 0)
+ goto end;
+
+ is->in_audio_filter = filt_asrc;
+ is->out_audio_filter = filt_asink;
+
+end:
+ if (ret < 0)
+ avfilter_graph_free(&is->agraph);
+ return ret;
+}
+#endif /* CONFIG_AVFILTER */
+
+static int audio_thread(void *arg)
+{
+ VideoState *is = arg;
+ AVFrame *frame = av_frame_alloc();
+ Frame *af;
+#if CONFIG_AVFILTER
+ int last_serial = -1;
+ int64_t dec_channel_layout;
+ int reconfigure;
+#endif
+ int got_frame = 0;
+ AVRational tb;
+ int ret = 0;
+
+ if (!frame)
+ return AVERROR(ENOMEM);
+
+ do {
+ if ((got_frame = decoder_decode_frame(&is->auddec, frame, NULL)) < 0)
+ goto the_end;
+
+ if (got_frame) {
+ tb = (AVRational){1, frame->sample_rate};
+
+#if CONFIG_AVFILTER
+ dec_channel_layout = get_valid_channel_layout(frame->channel_layout, av_frame_get_channels(frame));
+
+ reconfigure =
+ cmp_audio_fmts(is->audio_filter_src.fmt, is->audio_filter_src.channels,
+ frame->format, av_frame_get_channels(frame)) ||
+ is->audio_filter_src.channel_layout != dec_channel_layout ||
+ is->audio_filter_src.freq != frame->sample_rate ||
+ is->auddec.pkt_serial != last_serial;
+
+ if (reconfigure) {
+ char buf1[1024], buf2[1024];
+ av_get_channel_layout_string(buf1, sizeof(buf1), -1, is->audio_filter_src.channel_layout);
+ av_get_channel_layout_string(buf2, sizeof(buf2), -1, dec_channel_layout);
+ av_log(NULL, AV_LOG_DEBUG,
+ "Audio frame changed from rate:%d ch:%d fmt:%s layout:%s serial:%d to rate:%d ch:%d fmt:%s layout:%s serial:%d\n",
+ is->audio_filter_src.freq, is->audio_filter_src.channels, av_get_sample_fmt_name(is->audio_filter_src.fmt), buf1, last_serial,
+ frame->sample_rate, av_frame_get_channels(frame), av_get_sample_fmt_name(frame->format), buf2, is->auddec.pkt_serial);
+
+ is->audio_filter_src.fmt = frame->format;
+ is->audio_filter_src.channels = av_frame_get_channels(frame);
+ is->audio_filter_src.channel_layout = dec_channel_layout;
+ is->audio_filter_src.freq = frame->sample_rate;
+ last_serial = is->auddec.pkt_serial;
+
+ if ((ret = configure_audio_filters(is, afilters, 1)) < 0)
+ goto the_end;
+ }
+
+ if ((ret = av_buffersrc_add_frame(is->in_audio_filter, frame)) < 0)
+ goto the_end;
+
+ while ((ret = av_buffersink_get_frame_flags(is->out_audio_filter, frame, 0)) >= 0) {
+ tb = is->out_audio_filter->inputs[0]->time_base;
+#endif
+ if (!(af = frame_queue_peek_writable(&is->sampq)))
+ goto the_end;
+
+ af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
+ af->pos = av_frame_get_pkt_pos(frame);
+ af->serial = is->auddec.pkt_serial;
+ af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});
+
+ av_frame_move_ref(af->frame, frame);
+ frame_queue_push(&is->sampq);
+
+#if CONFIG_AVFILTER
+ if (is->audioq.serial != is->auddec.pkt_serial)
+ break;
+ }
+ if (ret == AVERROR_EOF)
+ is->auddec.finished = is->auddec.pkt_serial;
+#endif
+ }
+ } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
+ the_end:
+#if CONFIG_AVFILTER
+ avfilter_graph_free(&is->agraph);
+#endif
+ av_frame_free(&frame);
+ return ret;
+}
+
+static void decoder_start(Decoder *d, int (*fn)(void *), void *arg)
+{
+ packet_queue_start(d->queue);
+ d->decoder_tid = SDL_CreateThread(fn, arg);
+}
+
+static int video_thread(void *arg)
+{
+ VideoState *is = arg;
+ AVFrame *frame = av_frame_alloc();
+ double pts;
+ double duration;
+ int ret;
+ AVRational tb = is->video_st->time_base;
+ AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL);
+
+#if CONFIG_AVFILTER
+ AVFilterGraph *graph = avfilter_graph_alloc();
+ AVFilterContext *filt_out = NULL, *filt_in = NULL;
+ int last_w = 0;
+ int last_h = 0;
+ enum AVPixelFormat last_format = -2;
+ int last_serial = -1;
+ int last_vfilter_idx = 0;
+ if (!graph) {
+ av_frame_free(&frame);
+ return AVERROR(ENOMEM);
+ }
+
+#endif
+
+ if (!frame) {
+#if CONFIG_AVFILTER
+ avfilter_graph_free(&graph);
+#endif
+ return AVERROR(ENOMEM);
+ }
+
+ for (;;) {
+ ret = get_video_frame(is, frame);
+ if (ret < 0)
+ goto the_end;
+ if (!ret)
+ continue;
+
+#if CONFIG_AVFILTER
+ if ( last_w != frame->width
+ || last_h != frame->height
+ || last_format != frame->format
+ || last_serial != is->viddec.pkt_serial
+ || last_vfilter_idx != is->vfilter_idx) {
+ av_log(NULL, AV_LOG_DEBUG,
+ "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n",
+ last_w, last_h,
+ (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial,
+ frame->width, frame->height,
+ (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial);
+ avfilter_graph_free(&graph);
+ graph = avfilter_graph_alloc();
+ if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) {
+ SDL_Event event;
+ event.type = FF_QUIT_EVENT;
+ event.user.data1 = is;
+ SDL_PushEvent(&event);
+ goto the_end;
+ }
+ filt_in = is->in_video_filter;
+ filt_out = is->out_video_filter;
+ last_w = frame->width;
+ last_h = frame->height;
+ last_format = frame->format;
+ last_serial = is->viddec.pkt_serial;
+ last_vfilter_idx = is->vfilter_idx;
+ frame_rate = filt_out->inputs[0]->frame_rate;
+ }
+
+ ret = av_buffersrc_add_frame(filt_in, frame);
+ if (ret < 0)
+ goto the_end;
+
+ while (ret >= 0) {
+ is->frame_last_returned_time = av_gettime_relative() / 1000000.0;
+
+ ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
+ if (ret < 0) {
+ if (ret == AVERROR_EOF)
+ is->viddec.finished = is->viddec.pkt_serial;
+ ret = 0;
+ break;
+ }
+
+ is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time;
+ if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
+ is->frame_last_filter_delay = 0;
+ tb = filt_out->inputs[0]->time_base;
+#endif
+ duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0);
+ pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
+ ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec.pkt_serial);
+ av_frame_unref(frame);
+#if CONFIG_AVFILTER
+ }
+#endif
+
+ if (ret < 0)
+ goto the_end;
+ }
+ the_end:
+#if CONFIG_AVFILTER
+ avfilter_graph_free(&graph);
+#endif
+ av_frame_free(&frame);
+ return 0;
+}
+
+static int subtitle_thread(void *arg)
+{
+ VideoState *is = arg;
+ Frame *sp;
+ int got_subtitle;
+ double pts;
+ int i, j;
+ int r, g, b, y, u, v, a;
+
+ for (;;) {
+ if (!(sp = frame_queue_peek_writable(&is->subpq)))
+ return 0;
+
+ if ((got_subtitle = decoder_decode_frame(&is->subdec, NULL, &sp->sub)) < 0)
+ break;
+
+ pts = 0;
+
+ if (got_subtitle && sp->sub.format == 0) {
+ if (sp->sub.pts != AV_NOPTS_VALUE)
+ pts = sp->sub.pts / (double)AV_TIME_BASE;
+ sp->pts = pts;
+ sp->serial = is->subdec.pkt_serial;
+
+ for (i = 0; i < sp->sub.num_rects; i++)
+ {
+ for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
+ {
+ RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
+ y = RGB_TO_Y_CCIR(r, g, b);
+ u = RGB_TO_U_CCIR(r, g, b, 0);
+ v = RGB_TO_V_CCIR(r, g, b, 0);
+ YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
+ }
+ }
+
+ /* now we can update the picture count */
+ frame_queue_push(&is->subpq);
+ } else if (got_subtitle) {
+ avsubtitle_free(&sp->sub);
+ }
+ }
+ return 0;
+}
+
+/* copy samples for viewing in editor window */
+static void update_sample_display(VideoState *is, short *samples, int samples_size)
+{
+ int size, len;
+
+ size = samples_size / sizeof(short);
+ while (size > 0) {
+ len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
+ if (len > size)
+ len = size;
+ memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
+ samples += len;
+ is->sample_array_index += len;
+ if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
+ is->sample_array_index = 0;
+ size -= len;
+ }
+}
+
+/* return the wanted number of samples to get better sync if sync_type is video
+ * or external master clock */
+static int synchronize_audio(VideoState *is, int nb_samples)
+{
+ int wanted_nb_samples = nb_samples;
+
+ /* if not master, then we try to remove or add samples to correct the clock */
+ if (get_master_sync_type(is) != AV_SYNC_AUDIO_MASTER) {
+ double diff, avg_diff;
+ int min_nb_samples, max_nb_samples;
+
+ diff = get_clock(&is->audclk) - get_master_clock(is);
+
+ if (!isnan(diff) && fabs(diff) < AV_NOSYNC_THRESHOLD) {
+ is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
+ if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
+ /* not enough measures to have a correct estimate */
+ is->audio_diff_avg_count++;
+ } else {
+ /* estimate the A-V difference */
+ avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
+
+ if (fabs(avg_diff) >= is->audio_diff_threshold) {
+ wanted_nb_samples = nb_samples + (int)(diff * is->audio_src.freq);
+ min_nb_samples = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100));
+ max_nb_samples = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100));
+ wanted_nb_samples = FFMIN(FFMAX(wanted_nb_samples, min_nb_samples), max_nb_samples);
+ }
+ av_log(NULL, AV_LOG_TRACE, "diff=%f adiff=%f sample_diff=%d apts=%0.3f %f\n",
+ diff, avg_diff, wanted_nb_samples - nb_samples,
+ is->audio_clock, is->audio_diff_threshold);
+ }
+ } else {
+ /* too big difference : may be initial PTS errors, so
+ reset A-V filter */
+ is->audio_diff_avg_count = 0;
+ is->audio_diff_cum = 0;
+ }
+ }
+
+ return wanted_nb_samples;
+}
+
+/**
+ * Decode one audio frame and return its uncompressed size.
+ *
+ * The processed audio frame is decoded, converted if required, and
+ * stored in is->audio_buf, with size in bytes given by the return
+ * value.
+ */
+static int audio_decode_frame(VideoState *is)
+{
+ int data_size, resampled_data_size;
+ int64_t dec_channel_layout;
+ av_unused double audio_clock0;
+ int wanted_nb_samples;
+ Frame *af;
+
+ if (is->paused)
+ return -1;
+
+ do {
+ if (!(af = frame_queue_peek_readable(&is->sampq)))
+ return -1;
+ frame_queue_next(&is->sampq);
+ } while (af->serial != is->audioq.serial);
+
+ data_size = av_samples_get_buffer_size(NULL, av_frame_get_channels(af->frame),
+ af->frame->nb_samples,
+ af->frame->format, 1);
+
+ dec_channel_layout =
+ (af->frame->channel_layout && av_frame_get_channels(af->frame) == av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?
+ af->frame->channel_layout : av_get_default_channel_layout(av_frame_get_channels(af->frame));
+ wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);
+
+ if (af->frame->format != is->audio_src.fmt ||
+ dec_channel_layout != is->audio_src.channel_layout ||
+ af->frame->sample_rate != is->audio_src.freq ||
+ (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) {
+ swr_free(&is->swr_ctx);
+ is->swr_ctx = swr_alloc_set_opts(NULL,
+ is->audio_tgt.channel_layout, is->audio_tgt.fmt, is->audio_tgt.freq,
+ dec_channel_layout, af->frame->format, af->frame->sample_rate,
+ 0, NULL);
+ if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",
+ af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), av_frame_get_channels(af->frame),
+ is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.channels);
+ swr_free(&is->swr_ctx);
+ return -1;
+ }
+ is->audio_src.channel_layout = dec_channel_layout;
+ is->audio_src.channels = av_frame_get_channels(af->frame);
+ is->audio_src.freq = af->frame->sample_rate;
+ is->audio_src.fmt = af->frame->format;
+ }
+
+ if (is->swr_ctx) {
+ const uint8_t **in = (const uint8_t **)af->frame->extended_data;
+ uint8_t **out = &is->audio_buf1;
+ int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;
+ int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0);
+ int len2;
+ if (out_size < 0) {
+ av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");
+ return -1;
+ }
+ if (wanted_nb_samples != af->frame->nb_samples) {
+ if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,
+ wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n");
+ return -1;
+ }
+ }
+ av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);
+ if (!is->audio_buf1)
+ return AVERROR(ENOMEM);
+ len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);
+ if (len2 < 0) {
+ av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");
+ return -1;
+ }
+ if (len2 == out_count) {
+ av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");
+ if (swr_init(is->swr_ctx) < 0)
+ swr_free(&is->swr_ctx);
+ }
+ is->audio_buf = is->audio_buf1;
+ resampled_data_size = len2 * is->audio_tgt.channels * av_get_bytes_per_sample(is->audio_tgt.fmt);
+ } else {
+ is->audio_buf = af->frame->data[0];
+ resampled_data_size = data_size;
+ }
+
+ audio_clock0 = is->audio_clock;
+ /* update the audio clock with the pts */
+ if (!isnan(af->pts))
+ is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;
+ else
+ is->audio_clock = NAN;
+ is->audio_clock_serial = af->serial;
+#ifdef DEBUG
+ {
+ static double last_clock;
+ printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n",
+ is->audio_clock - last_clock,
+ is->audio_clock, audio_clock0);
+ last_clock = is->audio_clock;
+ }
+#endif
+ return resampled_data_size;
+}
+
+/* prepare a new audio buffer */
+static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
+{
+ VideoState *is = opaque;
+ int audio_size, len1;
+
+ audio_callback_time = av_gettime_relative();
+
+ while (len > 0) {
+ if (is->audio_buf_index >= is->audio_buf_size) {
+ audio_size = audio_decode_frame(is);
+ if (audio_size < 0) {
+ /* if error, just output silence */
+ is->audio_buf = is->silence_buf;
+ is->audio_buf_size = sizeof(is->silence_buf) / is->audio_tgt.frame_size * is->audio_tgt.frame_size;
+ } else {
+ if (is->show_mode != SHOW_MODE_VIDEO)
+ update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
+ is->audio_buf_size = audio_size;
+ }
+ is->audio_buf_index = 0;
+ }
+ len1 = is->audio_buf_size - is->audio_buf_index;
+ if (len1 > len)
+ len1 = len;
+ memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
+ len -= len1;
+ stream += len1;
+ is->audio_buf_index += len1;
+ }
+ is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;
+ /* Let's assume the audio driver that is used by SDL has two periods. */
+ if (!isnan(is->audio_clock)) {
+ set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0);
+ sync_clock_to_slave(&is->extclk, &is->audclk);
+ }
+}
+
+static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params)
+{
+ SDL_AudioSpec wanted_spec, spec;
+ const char *env;
+ static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
+ static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
+ int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;
+
+ env = SDL_getenv("SDL_AUDIO_CHANNELS");
+ if (env) {
+ wanted_nb_channels = atoi(env);
+ wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
+ }
+ if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
+ wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
+ wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
+ }
+ wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
+ wanted_spec.channels = wanted_nb_channels;
+ wanted_spec.freq = wanted_sample_rate;
+ if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");
+ return -1;
+ }
+ while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)
+ next_sample_rate_idx--;
+ wanted_spec.format = AUDIO_S16SYS;
+ wanted_spec.silence = 0;
+ wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));
+ wanted_spec.callback = sdl_audio_callback;
+ wanted_spec.userdata = opaque;
+ while (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
+ av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n",
+ wanted_spec.channels, wanted_spec.freq, SDL_GetError());
+ wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
+ if (!wanted_spec.channels) {
+ wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
+ wanted_spec.channels = wanted_nb_channels;
+ if (!wanted_spec.freq) {
+ av_log(NULL, AV_LOG_ERROR,
+ "No more combinations to try, audio open failed\n");
+ return -1;
+ }
+ }
+ wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
+ }
+ if (spec.format != AUDIO_S16SYS) {
+ av_log(NULL, AV_LOG_ERROR,
+ "SDL advised audio format %d is not supported!\n", spec.format);
+ return -1;
+ }
+ if (spec.channels != wanted_spec.channels) {
+ wanted_channel_layout = av_get_default_channel_layout(spec.channels);
+ if (!wanted_channel_layout) {
+ av_log(NULL, AV_LOG_ERROR,
+ "SDL advised channel count %d is not supported!\n", spec.channels);
+ return -1;
+ }
+ }
+
+ audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
+ audio_hw_params->freq = spec.freq;
+ audio_hw_params->channel_layout = wanted_channel_layout;
+ audio_hw_params->channels = spec.channels;
+ audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->channels, 1, audio_hw_params->fmt, 1);
+ audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->channels, audio_hw_params->freq, audio_hw_params->fmt, 1);
+ if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {
+ av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
+ return -1;
+ }
+ return spec.size;
+}
+
+/* open a given stream. Return 0 if OK */
+static int stream_component_open(VideoState *is, int stream_index)
+{
+ AVFormatContext *ic = is->ic;
+ AVCodecContext *avctx;
+ AVCodec *codec;
+ const char *forced_codec_name = NULL;
+ AVDictionary *opts;
+ AVDictionaryEntry *t = NULL;
+ int sample_rate, nb_channels;
+ int64_t channel_layout;
+ int ret = 0;
+ int stream_lowres = lowres;
+
+ if (stream_index < 0 || stream_index >= ic->nb_streams)
+ return -1;
+ avctx = ic->streams[stream_index]->codec;
+
+ codec = avcodec_find_decoder(avctx->codec_id);
+
+ switch(avctx->codec_type){
+ case AVMEDIA_TYPE_AUDIO : is->last_audio_stream = stream_index; forced_codec_name = audio_codec_name; break;
+ case AVMEDIA_TYPE_SUBTITLE: is->last_subtitle_stream = stream_index; forced_codec_name = subtitle_codec_name; break;
+ case AVMEDIA_TYPE_VIDEO : is->last_video_stream = stream_index; forced_codec_name = video_codec_name; break;
+ }
+ if (forced_codec_name)
+ codec = avcodec_find_decoder_by_name(forced_codec_name);
+ if (!codec) {
+ if (forced_codec_name) av_log(NULL, AV_LOG_WARNING,
+ "No codec could be found with name '%s'\n", forced_codec_name);
+ else av_log(NULL, AV_LOG_WARNING,
+ "No codec could be found with id %d\n", avctx->codec_id);
+ return -1;
+ }
+
+ avctx->codec_id = codec->id;
+ if(stream_lowres > av_codec_get_max_lowres(codec)){
+ av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n",
+ av_codec_get_max_lowres(codec));
+ stream_lowres = av_codec_get_max_lowres(codec);
+ }
+ av_codec_set_lowres(avctx, stream_lowres);
+
+ if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE;
+ if (fast) avctx->flags2 |= CODEC_FLAG2_FAST;
+ if(codec->capabilities & CODEC_CAP_DR1)
+ avctx->flags |= CODEC_FLAG_EMU_EDGE;
+
+ opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec);
+ if (!av_dict_get(opts, "threads", NULL, 0))
+ av_dict_set(&opts, "threads", "auto", 0);
+ if (stream_lowres)
+ av_dict_set_int(&opts, "lowres", stream_lowres, 0);
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ av_dict_set(&opts, "refcounted_frames", "1", 0);
+ 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;
+ goto fail;
+ }
+
+ is->eof = 0;
+ ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+#if CONFIG_AVFILTER
+ {
+ AVFilterLink *link;
+
+ is->audio_filter_src.freq = avctx->sample_rate;
+ is->audio_filter_src.channels = avctx->channels;
+ is->audio_filter_src.channel_layout = get_valid_channel_layout(avctx->channel_layout, avctx->channels);
+ is->audio_filter_src.fmt = avctx->sample_fmt;
+ if ((ret = configure_audio_filters(is, afilters, 0)) < 0)
+ goto fail;
+ link = is->out_audio_filter->inputs[0];
+ sample_rate = link->sample_rate;
+ nb_channels = link->channels;
+ channel_layout = link->channel_layout;
+ }
+#else
+ sample_rate = avctx->sample_rate;
+ nb_channels = avctx->channels;
+ channel_layout = avctx->channel_layout;
+#endif
+
+ /* prepare audio output */
+ if ((ret = audio_open(is, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) < 0)
+ goto fail;
+ is->audio_hw_buf_size = ret;
+ is->audio_src = is->audio_tgt;
+ is->audio_buf_size = 0;
+ is->audio_buf_index = 0;
+
+ /* init averaging filter */
+ is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
+ is->audio_diff_avg_count = 0;
+ /* since we do not have a precise anough audio fifo fullness,
+ we correct audio sync only if larger than this threshold */
+ is->audio_diff_threshold = (double)(is->audio_hw_buf_size) / is->audio_tgt.bytes_per_sec;
+
+ is->audio_stream = stream_index;
+ is->audio_st = ic->streams[stream_index];
+
+ decoder_init(&is->auddec, avctx, &is->audioq, is->continue_read_thread);
+ if ((is->ic->iformat->flags & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) && !is->ic->iformat->read_seek) {
+ is->auddec.start_pts = is->audio_st->start_time;
+ is->auddec.start_pts_tb = is->audio_st->time_base;
+ }
+ decoder_start(&is->auddec, audio_thread, is);
+ SDL_PauseAudio(0);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ is->video_stream = stream_index;
+ is->video_st = ic->streams[stream_index];
+
+ decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
+ decoder_start(&is->viddec, video_thread, is);
+ is->queue_attachments_req = 1;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ is->subtitle_stream = stream_index;
+ is->subtitle_st = ic->streams[stream_index];
+
+ decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
+ decoder_start(&is->subdec, subtitle_thread, is);
+ break;
+ default:
+ break;
+ }
+
+fail:
+ av_dict_free(&opts);
+
+ return ret;
+}
+
+static void stream_component_close(VideoState *is, int stream_index)
+{
+ AVFormatContext *ic = is->ic;
+ AVCodecContext *avctx;
+
+ if (stream_index < 0 || stream_index >= ic->nb_streams)
+ return;
+ avctx = ic->streams[stream_index]->codec;
+
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ decoder_abort(&is->auddec, &is->sampq);
+ SDL_CloseAudio();
+ decoder_destroy(&is->auddec);
+ swr_free(&is->swr_ctx);
+ av_freep(&is->audio_buf1);
+ is->audio_buf1_size = 0;
+ is->audio_buf = NULL;
+
+ if (is->rdft) {
+ av_rdft_end(is->rdft);
+ av_freep(&is->rdft_data);
+ is->rdft = NULL;
+ is->rdft_bits = 0;
+ }
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ decoder_abort(&is->viddec, &is->pictq);
+ decoder_destroy(&is->viddec);
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ decoder_abort(&is->subdec, &is->subpq);
+ decoder_destroy(&is->subdec);
+ break;
+ default:
+ break;
+ }
+
+ ic->streams[stream_index]->discard = AVDISCARD_ALL;
+ avcodec_close(avctx);
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ is->audio_st = NULL;
+ is->audio_stream = -1;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ is->video_st = NULL;
+ is->video_stream = -1;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ is->subtitle_st = NULL;
+ is->subtitle_stream = -1;
+ break;
+ default:
+ break;
+ }
+}
+
+static int decode_interrupt_cb(void *ctx)
+{
+ VideoState *is = ctx;
+ return is->abort_request;
+}
+
+static int is_realtime(AVFormatContext *s)
+{
+ if( !strcmp(s->iformat->name, "rtp")
+ || !strcmp(s->iformat->name, "rtsp")
+ || !strcmp(s->iformat->name, "sdp")
+ )
+ return 1;
+
+ if(s->pb && ( !strncmp(s->filename, "rtp:", 4)
+ || !strncmp(s->filename, "udp:", 4)
+ )
+ )
+ return 1;
+ return 0;
+}
+
+/* this thread gets the stream from the disk or the network */
+static int read_thread(void *arg)
+{
+ VideoState *is = arg;
+ AVFormatContext *ic = NULL;
+ int err, i, ret;
+ int st_index[AVMEDIA_TYPE_NB];
+ AVPacket pkt1, *pkt = &pkt1;
+ int64_t stream_start_time;
+ int pkt_in_play_range = 0;
+ AVDictionaryEntry *t;
+ AVDictionary **opts;
+ int orig_nb_streams;
+ SDL_mutex *wait_mutex = SDL_CreateMutex();
+ int scan_all_pmts_set = 0;
+ int64_t pkt_ts;
+
+ memset(st_index, -1, sizeof(st_index));
+ is->last_video_stream = is->video_stream = -1;
+ is->last_audio_stream = is->audio_stream = -1;
+ is->last_subtitle_stream = is->subtitle_stream = -1;
+ is->eof = 0;
+
+ ic = avformat_alloc_context();
+ if (!ic) {
+ av_log(NULL, AV_LOG_FATAL, "Could not allocate context.\n");
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ ic->interrupt_callback.callback = decode_interrupt_cb;
+ ic->interrupt_callback.opaque = is;
+ if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
+ av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
+ scan_all_pmts_set = 1;
+ }
+ err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
+ if (err < 0) {
+ print_error(is->filename, err);
+ ret = -1;
+ goto fail;
+ }
+ if (scan_all_pmts_set)
+ av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
+
+ 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;
+ goto fail;
+ }
+ is->ic = ic;
+
+ if (genpts)
+ ic->flags |= AVFMT_FLAG_GENPTS;
+
+ av_format_inject_global_side_data(ic);
+
+ opts = setup_find_stream_info_opts(ic, codec_opts);
+ orig_nb_streams = ic->nb_streams;
+
+ err = avformat_find_stream_info(ic, opts);
+
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ if (err < 0) {
+ av_log(NULL, AV_LOG_WARNING,
+ "%s: could not find codec parameters\n", is->filename);
+ ret = -1;
+ goto fail;
+ }
+
+ if (ic->pb)
+ ic->pb->eof_reached = 0; // FIXME hack, ffplay maybe should not use avio_feof() to test for the end
+
+ if (seek_by_bytes < 0)
+ seek_by_bytes = !!(ic->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", ic->iformat->name);
+
+ is->max_frame_duration = (ic->iformat->flags & AVFMT_TS_DISCONT) ? 10.0 : 3600.0;
+
+ if (!window_title && (t = av_dict_get(ic->metadata, "title", NULL, 0)))
+ window_title = av_asprintf("%s - %s", t->value, input_filename);
+
+ /* if seeking requested, we execute it */
+ if (start_time != AV_NOPTS_VALUE) {
+ int64_t timestamp;
+
+ timestamp = start_time;
+ /* add the stream start time */
+ if (ic->start_time != AV_NOPTS_VALUE)
+ timestamp += ic->start_time;
+ ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
+ is->filename, (double)timestamp / AV_TIME_BASE);
+ }
+ }
+
+ is->realtime = is_realtime(ic);
+
+ if (show_status)
+ av_dump_format(ic, 0, is->filename, 0);
+
+ for (i = 0; i < ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+ enum AVMediaType type = st->codec->codec_type;
+ st->discard = AVDISCARD_ALL;
+ if (wanted_stream_spec[type] && st_index[type] == -1)
+ if (avformat_match_stream_specifier(ic, st, wanted_stream_spec[type]) > 0)
+ st_index[type] = i;
+ }
+ for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
+ if (wanted_stream_spec[i] && st_index[i] == -1) {
+ av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not match any %s stream\n", wanted_stream_spec[i], av_get_media_type_string(i));
+ st_index[i] = INT_MAX;
+ }
+ }
+
+ if (!video_disable)
+ st_index[AVMEDIA_TYPE_VIDEO] =
+ av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
+ st_index[AVMEDIA_TYPE_VIDEO], -1, NULL, 0);
+ if (!audio_disable)
+ st_index[AVMEDIA_TYPE_AUDIO] =
+ av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
+ st_index[AVMEDIA_TYPE_AUDIO],
+ st_index[AVMEDIA_TYPE_VIDEO],
+ NULL, 0);
+ if (!video_disable && !subtitle_disable)
+ st_index[AVMEDIA_TYPE_SUBTITLE] =
+ av_find_best_stream(ic, AVMEDIA_TYPE_SUBTITLE,
+ st_index[AVMEDIA_TYPE_SUBTITLE],
+ (st_index[AVMEDIA_TYPE_AUDIO] >= 0 ?
+ st_index[AVMEDIA_TYPE_AUDIO] :
+ st_index[AVMEDIA_TYPE_VIDEO]),
+ NULL, 0);
+
+ is->show_mode = show_mode;
+ if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
+ AVStream *st = ic->streams[st_index[AVMEDIA_TYPE_VIDEO]];
+ AVCodecContext *avctx = st->codec;
+ AVRational sar = av_guess_sample_aspect_ratio(ic, st, NULL);
+ if (avctx->width)
+ set_default_window_size(avctx->width, avctx->height, sar);
+ }
+
+ /* open the streams */
+ if (st_index[AVMEDIA_TYPE_AUDIO] >= 0) {
+ stream_component_open(is, st_index[AVMEDIA_TYPE_AUDIO]);
+ }
+
+ ret = -1;
+ if (st_index[AVMEDIA_TYPE_VIDEO] >= 0) {
+ ret = stream_component_open(is, st_index[AVMEDIA_TYPE_VIDEO]);
+ }
+ if (is->show_mode == SHOW_MODE_NONE)
+ is->show_mode = ret >= 0 ? SHOW_MODE_VIDEO : SHOW_MODE_RDFT;
+
+ if (st_index[AVMEDIA_TYPE_SUBTITLE] >= 0) {
+ stream_component_open(is, st_index[AVMEDIA_TYPE_SUBTITLE]);
+ }
+
+ if (is->video_stream < 0 && is->audio_stream < 0) {
+ av_log(NULL, AV_LOG_FATAL, "Failed to open file '%s' or configure filtergraph\n",
+ is->filename);
+ ret = -1;
+ goto fail;
+ }
+
+ if (infinite_buffer < 0 && is->realtime)
+ infinite_buffer = 1;
+
+ for (;;) {
+ if (is->abort_request)
+ break;
+ if (is->paused != is->last_paused) {
+ is->last_paused = is->paused;
+ if (is->paused)
+ is->read_pause_return = av_read_pause(ic);
+ else
+ av_read_play(ic);
+ }
+#if CONFIG_RTSP_DEMUXER || CONFIG_MMSH_PROTOCOL
+ if (is->paused &&
+ (!strcmp(ic->iformat->name, "rtsp") ||
+ (ic->pb && !strncmp(input_filename, "mmsh:", 5)))) {
+ /* wait 10 ms to avoid trying to get another packet */
+ /* XXX: horrible */
+ SDL_Delay(10);
+ continue;
+ }
+#endif
+ if (is->seek_req) {
+ int64_t seek_target = is->seek_pos;
+ int64_t seek_min = is->seek_rel > 0 ? seek_target - is->seek_rel + 2: INT64_MIN;
+ int64_t seek_max = is->seek_rel < 0 ? seek_target - is->seek_rel - 2: INT64_MAX;
+// FIXME the +-2 is due to rounding being not done in the correct direction in generation
+// of the seek_pos/seek_rel variables
+
+ ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "%s: error while seeking\n", is->ic->filename);
+ } else {
+ if (is->audio_stream >= 0) {
+ packet_queue_flush(&is->audioq);
+ packet_queue_put(&is->audioq, &flush_pkt);
+ }
+ if (is->subtitle_stream >= 0) {
+ packet_queue_flush(&is->subtitleq);
+ packet_queue_put(&is->subtitleq, &flush_pkt);
+ }
+ if (is->video_stream >= 0) {
+ packet_queue_flush(&is->videoq);
+ packet_queue_put(&is->videoq, &flush_pkt);
+ }
+ if (is->seek_flags & AVSEEK_FLAG_BYTE) {
+ set_clock(&is->extclk, NAN, 0);
+ } else {
+ set_clock(&is->extclk, seek_target / (double)AV_TIME_BASE, 0);
+ }
+ }
+ is->seek_req = 0;
+ is->queue_attachments_req = 1;
+ is->eof = 0;
+ if (is->paused)
+ step_to_next_frame(is);
+ }
+ if (is->queue_attachments_req) {
+ if (is->video_st && is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
+ AVPacket copy;
+ if ((ret = av_copy_packet(&copy, &is->video_st->attached_pic)) < 0)
+ goto fail;
+ packet_queue_put(&is->videoq, &copy);
+ packet_queue_put_nullpacket(&is->videoq, is->video_stream);
+ }
+ is->queue_attachments_req = 0;
+ }
+
+ /* if the queue are full, no need to read more */
+ if (infinite_buffer<1 &&
+ (is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QUEUE_SIZE
+ || ( (is->audioq .nb_packets > MIN_FRAMES || is->audio_stream < 0 || is->audioq.abort_request)
+ && (is->videoq .nb_packets > MIN_FRAMES || is->video_stream < 0 || is->videoq.abort_request
+ || (is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ && (is->subtitleq.nb_packets > MIN_FRAMES || is->subtitle_stream < 0 || is->subtitleq.abort_request)))) {
+ /* wait 10 ms */
+ SDL_LockMutex(wait_mutex);
+ SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
+ SDL_UnlockMutex(wait_mutex);
+ continue;
+ }
+ if (!is->paused &&
+ (!is->audio_st || (is->auddec.finished == is->audioq.serial && frame_queue_nb_remaining(&is->sampq) == 0)) &&
+ (!is->video_st || (is->viddec.finished == is->videoq.serial && frame_queue_nb_remaining(&is->pictq) == 0))) {
+ if (loop != 1 && (!loop || --loop)) {
+ stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);
+ } else if (autoexit) {
+ ret = AVERROR_EOF;
+ goto fail;
+ }
+ }
+ ret = av_read_frame(ic, pkt);
+ if (ret < 0) {
+ if ((ret == AVERROR_EOF || avio_feof(ic->pb)) && !is->eof) {
+ if (is->video_stream >= 0)
+ packet_queue_put_nullpacket(&is->videoq, is->video_stream);
+ if (is->audio_stream >= 0)
+ packet_queue_put_nullpacket(&is->audioq, is->audio_stream);
+ if (is->subtitle_stream >= 0)
+ packet_queue_put_nullpacket(&is->subtitleq, is->subtitle_stream);
+ is->eof = 1;
+ }
+ if (ic->pb && ic->pb->error)
+ break;
+ SDL_LockMutex(wait_mutex);
+ SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);
+ SDL_UnlockMutex(wait_mutex);
+ continue;
+ } else {
+ is->eof = 0;
+ }
+ /* check if packet is in play range specified by user, then queue, otherwise discard */
+ stream_start_time = ic->streams[pkt->stream_index]->start_time;
+ pkt_ts = pkt->pts == AV_NOPTS_VALUE ? pkt->dts : pkt->pts;
+ pkt_in_play_range = duration == AV_NOPTS_VALUE ||
+ (pkt_ts - (stream_start_time != AV_NOPTS_VALUE ? stream_start_time : 0)) *
+ av_q2d(ic->streams[pkt->stream_index]->time_base) -
+ (double)(start_time != AV_NOPTS_VALUE ? start_time : 0) / 1000000
+ <= ((double)duration / 1000000);
+ if (pkt->stream_index == is->audio_stream && pkt_in_play_range) {
+ packet_queue_put(&is->audioq, pkt);
+ } else if (pkt->stream_index == is->video_stream && pkt_in_play_range
+ && !(is->video_st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
+ packet_queue_put(&is->videoq, pkt);
+ } else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
+ packet_queue_put(&is->subtitleq, pkt);
+ } else {
+ av_free_packet(pkt);
+ }
+ }
+ /* wait until the end */
+ while (!is->abort_request) {
+ SDL_Delay(100);
+ }
+
+ ret = 0;
+ fail:
+ /* close each stream */
+ if (is->audio_stream >= 0)
+ stream_component_close(is, is->audio_stream);
+ if (is->video_stream >= 0)
+ stream_component_close(is, is->video_stream);
+ if (is->subtitle_stream >= 0)
+ stream_component_close(is, is->subtitle_stream);
+ if (ic) {
+ avformat_close_input(&ic);
+ is->ic = NULL;
+ }
+
+ if (ret != 0) {
+ SDL_Event event;
+
+ event.type = FF_QUIT_EVENT;
+ event.user.data1 = is;
+ SDL_PushEvent(&event);
+ }
+ SDL_DestroyMutex(wait_mutex);
+ return 0;
+}
+
+static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
+{
+ VideoState *is;
+
+ is = av_mallocz(sizeof(VideoState));
+ if (!is)
+ return NULL;
+ av_strlcpy(is->filename, filename, sizeof(is->filename));
+ is->iformat = iformat;
+ is->ytop = 0;
+ is->xleft = 0;
+
+ /* start video display */
+ if (frame_queue_init(&is->pictq, &is->videoq, VIDEO_PICTURE_QUEUE_SIZE, 1) < 0)
+ goto fail;
+ if (frame_queue_init(&is->subpq, &is->subtitleq, SUBPICTURE_QUEUE_SIZE, 0) < 0)
+ goto fail;
+ if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
+ goto fail;
+
+ packet_queue_init(&is->videoq);
+ packet_queue_init(&is->audioq);
+ packet_queue_init(&is->subtitleq);
+
+ is->continue_read_thread = SDL_CreateCond();
+
+ init_clock(&is->vidclk, &is->videoq.serial);
+ init_clock(&is->audclk, &is->audioq.serial);
+ init_clock(&is->extclk, &is->extclk.serial);
+ is->audio_clock_serial = -1;
+ is->av_sync_type = av_sync_type;
+ is->read_tid = SDL_CreateThread(read_thread, is);
+ if (!is->read_tid) {
+fail:
+ stream_close(is);
+ return NULL;
+ }
+ return is;
+}
+
+static void stream_cycle_channel(VideoState *is, int codec_type)
+{
+ AVFormatContext *ic = is->ic;
+ int start_index, stream_index;
+ int old_index;
+ AVStream *st;
+ AVProgram *p = NULL;
+ int nb_streams = is->ic->nb_streams;
+
+ if (codec_type == AVMEDIA_TYPE_VIDEO) {
+ start_index = is->last_video_stream;
+ old_index = is->video_stream;
+ } else if (codec_type == AVMEDIA_TYPE_AUDIO) {
+ start_index = is->last_audio_stream;
+ old_index = is->audio_stream;
+ } else {
+ start_index = is->last_subtitle_stream;
+ old_index = is->subtitle_stream;
+ }
+ stream_index = start_index;
+
+ if (codec_type != AVMEDIA_TYPE_VIDEO && is->video_stream != -1) {
+ p = av_find_program_from_stream(ic, NULL, is->video_stream);
+ if (p) {
+ nb_streams = p->nb_stream_indexes;
+ for (start_index = 0; start_index < nb_streams; start_index++)
+ if (p->stream_index[start_index] == stream_index)
+ break;
+ if (start_index == nb_streams)
+ start_index = -1;
+ stream_index = start_index;
+ }
+ }
+
+ for (;;) {
+ if (++stream_index >= nb_streams)
+ {
+ if (codec_type == AVMEDIA_TYPE_SUBTITLE)
+ {
+ stream_index = -1;
+ is->last_subtitle_stream = -1;
+ goto the_end;
+ }
+ if (start_index == -1)
+ return;
+ stream_index = 0;
+ }
+ if (stream_index == start_index)
+ return;
+ st = is->ic->streams[p ? p->stream_index[stream_index] : stream_index];
+ if (st->codec->codec_type == codec_type) {
+ /* check that parameters are OK */
+ switch (codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (st->codec->sample_rate != 0 &&
+ st->codec->channels != 0)
+ goto the_end;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_SUBTITLE:
+ goto the_end;
+ default:
+ break;
+ }
+ }
+ }
+ the_end:
+ if (p && stream_index != -1)
+ stream_index = p->stream_index[stream_index];
+ av_log(NULL, AV_LOG_INFO, "Switch %s stream from #%d to #%d\n",
+ av_get_media_type_string(codec_type),
+ old_index,
+ stream_index);
+
+ stream_component_close(is, old_index);
+ stream_component_open(is, stream_index);
+}
+
+
+static void toggle_full_screen(VideoState *is)
+{
+#if defined(__APPLE__) && SDL_VERSION_ATLEAST(1, 2, 14)
+ /* OS X needs to reallocate the SDL overlays */
+ int i;
+ for (i = 0; i < VIDEO_PICTURE_QUEUE_SIZE; i++)
+ is->pictq.queue[i].reallocate = 1;
+#endif
+ is_full_screen = !is_full_screen;
+ video_open(is, 1, NULL);
+}
+
+static void toggle_audio_display(VideoState *is)
+{
+ int bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
+ int next = is->show_mode;
+ do {
+ next = (next + 1) % SHOW_MODE_NB;
+ } while (next != is->show_mode && (next == SHOW_MODE_VIDEO && !is->video_st || next != SHOW_MODE_VIDEO && !is->audio_st));
+ if (is->show_mode != next) {
+ fill_rectangle(screen,
+ is->xleft, is->ytop, is->width, is->height,
+ bgcolor, 1);
+ is->force_refresh = 1;
+ is->show_mode = next;
+ }
+}
+
+static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
+ double remaining_time = 0.0;
+ SDL_PumpEvents();
+ while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
+ if (!cursor_hidden && av_gettime_relative() - cursor_last_shown > CURSOR_HIDE_DELAY) {
+ SDL_ShowCursor(0);
+ cursor_hidden = 1;
+ }
+ if (remaining_time > 0.0)
+ av_usleep((int64_t)(remaining_time * 1000000.0));
+ remaining_time = REFRESH_RATE;
+ if (is->show_mode != SHOW_MODE_NONE && (!is->paused || is->force_refresh))
+ video_refresh(is, &remaining_time);
+ SDL_PumpEvents();
+ }
+}
+
+static void seek_chapter(VideoState *is, int incr)
+{
+ int64_t pos = get_master_clock(is) * AV_TIME_BASE;
+ int i;
+
+ if (!is->ic->nb_chapters)
+ return;
+
+ /* find the current chapter */
+ for (i = 0; i < is->ic->nb_chapters; i++) {
+ AVChapter *ch = is->ic->chapters[i];
+ if (av_compare_ts(pos, AV_TIME_BASE_Q, ch->start, ch->time_base) < 0) {
+ i--;
+ break;
+ }
+ }
+
+ i += incr;
+ i = FFMAX(i, 0);
+ if (i >= is->ic->nb_chapters)
+ return;
+
+ av_log(NULL, AV_LOG_VERBOSE, "Seeking to chapter %d.\n", i);
+ stream_seek(is, av_rescale_q(is->ic->chapters[i]->start, is->ic->chapters[i]->time_base,
+ AV_TIME_BASE_Q), 0, 0);
+}
+
+/* handle an event sent by the GUI */
+static void event_loop(VideoState *cur_stream)
+{
+ SDL_Event event;
+ double incr, pos, frac;
+
+ for (;;) {
+ double x;
+ refresh_loop_wait_event(cur_stream, &event);
+ switch (event.type) {
+ case SDL_KEYDOWN:
+ if (exit_on_keydown) {
+ do_exit(cur_stream);
+ break;
+ }
+ switch (event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ case SDLK_q:
+ do_exit(cur_stream);
+ break;
+ case SDLK_f:
+ toggle_full_screen(cur_stream);
+ cur_stream->force_refresh = 1;
+ break;
+ case SDLK_p:
+ case SDLK_SPACE:
+ toggle_pause(cur_stream);
+ break;
+ case SDLK_s: // S: Step to next frame
+ step_to_next_frame(cur_stream);
+ break;
+ case SDLK_a:
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
+ break;
+ case SDLK_v:
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
+ break;
+ case SDLK_c:
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_VIDEO);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_AUDIO);
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
+ break;
+ case SDLK_t:
+ stream_cycle_channel(cur_stream, AVMEDIA_TYPE_SUBTITLE);
+ break;
+ case SDLK_w:
+#if CONFIG_AVFILTER
+ if (cur_stream->show_mode == SHOW_MODE_VIDEO && cur_stream->vfilter_idx < nb_vfilters - 1) {
+ if (++cur_stream->vfilter_idx >= nb_vfilters)
+ cur_stream->vfilter_idx = 0;
+ } else {
+ cur_stream->vfilter_idx = 0;
+ toggle_audio_display(cur_stream);
+ }
+#else
+ toggle_audio_display(cur_stream);
+#endif
+ break;
+ case SDLK_PAGEUP:
+ if (cur_stream->ic->nb_chapters <= 1) {
+ incr = 600.0;
+ goto do_seek;
+ }
+ seek_chapter(cur_stream, 1);
+ break;
+ case SDLK_PAGEDOWN:
+ if (cur_stream->ic->nb_chapters <= 1) {
+ incr = -600.0;
+ goto do_seek;
+ }
+ seek_chapter(cur_stream, -1);
+ break;
+ case SDLK_LEFT:
+ incr = -10.0;
+ goto do_seek;
+ case SDLK_RIGHT:
+ incr = 10.0;
+ goto do_seek;
+ case SDLK_UP:
+ incr = 60.0;
+ goto do_seek;
+ case SDLK_DOWN:
+ incr = -60.0;
+ do_seek:
+ if (seek_by_bytes) {
+ pos = -1;
+ if (pos < 0 && cur_stream->video_stream >= 0)
+ pos = frame_queue_last_pos(&cur_stream->pictq);
+ if (pos < 0 && cur_stream->audio_stream >= 0)
+ pos = frame_queue_last_pos(&cur_stream->sampq);
+ if (pos < 0)
+ pos = avio_tell(cur_stream->ic->pb);
+ if (cur_stream->ic->bit_rate)
+ incr *= cur_stream->ic->bit_rate / 8.0;
+ else
+ incr *= 180000.0;
+ pos += incr;
+ stream_seek(cur_stream, pos, incr, 1);
+ } else {
+ pos = get_master_clock(cur_stream);
+ if (isnan(pos))
+ pos = (double)cur_stream->seek_pos / AV_TIME_BASE;
+ pos += incr;
+ if (cur_stream->ic->start_time != AV_NOPTS_VALUE && pos < cur_stream->ic->start_time / (double)AV_TIME_BASE)
+ pos = cur_stream->ic->start_time / (double)AV_TIME_BASE;
+ stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), (int64_t)(incr * AV_TIME_BASE), 0);
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case SDL_VIDEOEXPOSE:
+ cur_stream->force_refresh = 1;
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ if (exit_on_mousedown) {
+ do_exit(cur_stream);
+ break;
+ }
+ case SDL_MOUSEMOTION:
+ if (cursor_hidden) {
+ SDL_ShowCursor(1);
+ cursor_hidden = 0;
+ }
+ cursor_last_shown = av_gettime_relative();
+ if (event.type == SDL_MOUSEBUTTONDOWN) {
+ x = event.button.x;
+ } else {
+ if (event.motion.state != SDL_PRESSED)
+ break;
+ x = event.motion.x;
+ }
+ if (seek_by_bytes || cur_stream->ic->duration <= 0) {
+ uint64_t size = avio_size(cur_stream->ic->pb);
+ stream_seek(cur_stream, size*x/cur_stream->width, 0, 1);
+ } else {
+ int64_t ts;
+ int ns, hh, mm, ss;
+ int tns, thh, tmm, tss;
+ tns = cur_stream->ic->duration / 1000000LL;
+ thh = tns / 3600;
+ tmm = (tns % 3600) / 60;
+ tss = (tns % 60);
+ frac = x / cur_stream->width;
+ ns = frac * tns;
+ hh = ns / 3600;
+ mm = (ns % 3600) / 60;
+ ss = (ns % 60);
+ av_log(NULL, AV_LOG_INFO,
+ "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
+ hh, mm, ss, thh, tmm, tss);
+ ts = frac * cur_stream->ic->duration;
+ if (cur_stream->ic->start_time != AV_NOPTS_VALUE)
+ ts += cur_stream->ic->start_time;
+ stream_seek(cur_stream, ts, 0, 0);
+ }
+ break;
+ case SDL_VIDEORESIZE:
+ screen = SDL_SetVideoMode(FFMIN(16383, event.resize.w), event.resize.h, 0,
+ SDL_HWSURFACE|(is_full_screen?SDL_FULLSCREEN:SDL_RESIZABLE)|SDL_ASYNCBLIT|SDL_HWACCEL);
+ if (!screen) {
+ av_log(NULL, AV_LOG_FATAL, "Failed to set video mode\n");
+ do_exit(cur_stream);
+ }
+ screen_width = cur_stream->width = screen->w;
+ screen_height = cur_stream->height = screen->h;
+ cur_stream->force_refresh = 1;
+ break;
+ case SDL_QUIT:
+ case FF_QUIT_EVENT:
+ do_exit(cur_stream);
+ break;
+ case FF_ALLOC_EVENT:
+ alloc_picture(event.user.data1);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int opt_frame_size(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "Option -s is deprecated, use -video_size.\n");
+ return opt_default(NULL, "video_size", arg);
+}
+
+static int opt_width(void *optctx, const char *opt, const char *arg)
+{
+ screen_width = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
+ return 0;
+}
+
+static int opt_height(void *optctx, const char *opt, const char *arg)
+{
+ screen_height = parse_number_or_die(opt, arg, OPT_INT64, 1, INT_MAX);
+ return 0;
+}
+
+static int opt_format(void *optctx, const char *opt, const char *arg)
+{
+ file_iformat = av_find_input_format(arg);
+ if (!file_iformat) {
+ av_log(NULL, AV_LOG_FATAL, "Unknown input format: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static int opt_frame_pix_fmt(void *optctx, const char *opt, const char *arg)
+{
+ av_log(NULL, AV_LOG_WARNING, "Option -pix_fmt is deprecated, use -pixel_format.\n");
+ return opt_default(NULL, "pixel_format", arg);
+}
+
+static int opt_sync(void *optctx, const char *opt, const char *arg)
+{
+ if (!strcmp(arg, "audio"))
+ av_sync_type = AV_SYNC_AUDIO_MASTER;
+ else if (!strcmp(arg, "video"))
+ av_sync_type = AV_SYNC_VIDEO_MASTER;
+ else if (!strcmp(arg, "ext"))
+ av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
+ else {
+ av_log(NULL, AV_LOG_ERROR, "Unknown value for %s: %s\n", opt, arg);
+ exit(1);
+ }
+ return 0;
+}
+
+static int opt_seek(void *optctx, const char *opt, const char *arg)
+{
+ start_time = parse_time_or_die(opt, arg, 1);
+ return 0;
+}
+
+static int opt_duration(void *optctx, const char *opt, const char *arg)
+{
+ duration = parse_time_or_die(opt, arg, 1);
+ return 0;
+}
+
+static int opt_show_mode(void *optctx, const char *opt, const char *arg)
+{
+ show_mode = !strcmp(arg, "video") ? SHOW_MODE_VIDEO :
+ !strcmp(arg, "waves") ? SHOW_MODE_WAVES :
+ !strcmp(arg, "rdft" ) ? SHOW_MODE_RDFT :
+ parse_number_or_die(opt, arg, OPT_INT, 0, SHOW_MODE_NB-1);
+ return 0;
+}
+
+static void opt_input_file(void *optctx, const char *filename)
+{
+ if (input_filename) {
+ av_log(NULL, AV_LOG_FATAL,
+ "Argument '%s' provided as input filename, but '%s' was already specified.\n",
+ filename, input_filename);
+ exit(1);
+ }
+ if (!strcmp(filename, "-"))
+ filename = "pipe:";
+ input_filename = filename;
+}
+
+static int opt_codec(void *optctx, const char *opt, const char *arg)
+{
+ const char *spec = strchr(opt, ':');
+ if (!spec) {
+ av_log(NULL, AV_LOG_ERROR,
+ "No media specifier was specified in '%s' in option '%s'\n",
+ arg, opt);
+ return AVERROR(EINVAL);
+ }
+ spec++;
+ switch (spec[0]) {
+ case 'a' : audio_codec_name = arg; break;
+ case 's' : subtitle_codec_name = arg; break;
+ case 'v' : video_codec_name = arg; break;
+ default:
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid media specifier '%s' in option '%s'\n", spec, opt);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static int dummy;
+
+static const OptionDef options[] = {
+#include "cmdutils_common_opts.h"
+ { "x", HAS_ARG, { .func_arg = opt_width }, "force displayed width", "width" },
+ { "y", HAS_ARG, { .func_arg = opt_height }, "force displayed height", "height" },
+ { "s", HAS_ARG | OPT_VIDEO, { .func_arg = opt_frame_size }, "set frame size (WxH or abbreviation)", "size" },
+ { "fs", OPT_BOOL, { &is_full_screen }, "force full screen" },
+ { "an", OPT_BOOL, { &audio_disable }, "disable audio" },
+ { "vn", OPT_BOOL, { &video_disable }, "disable video" },
+ { "sn", OPT_BOOL, { &subtitle_disable }, "disable subtitling" },
+ { "ast", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_AUDIO] }, "select desired audio stream", "stream_specifier" },
+ { "vst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_VIDEO] }, "select desired video stream", "stream_specifier" },
+ { "sst", OPT_STRING | HAS_ARG | OPT_EXPERT, { &wanted_stream_spec[AVMEDIA_TYPE_SUBTITLE] }, "select desired subtitle stream", "stream_specifier" },
+ { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" },
+ { "t", HAS_ARG, { .func_arg = opt_duration }, "play \"duration\" seconds of audio/video", "duration" },
+ { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" },
+ { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" },
+ { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" },
+ { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" },
+ { "stats", OPT_BOOL | OPT_EXPERT, { &show_status }, "show status", "" },
+ { "fast", OPT_BOOL | OPT_EXPERT, { &fast }, "non spec compliant optimizations", "" },
+ { "genpts", OPT_BOOL | OPT_EXPERT, { &genpts }, "generate pts", "" },
+ { "drp", OPT_INT | HAS_ARG | OPT_EXPERT, { &decoder_reorder_pts }, "let decoder reorder pts 0=off 1=on -1=auto", ""},
+ { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, { &lowres }, "", "" },
+ { "sync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_sync }, "set audio-video sync. type (type=audio/video/ext)", "type" },
+ { "autoexit", OPT_BOOL | OPT_EXPERT, { &autoexit }, "exit at the end", "" },
+ { "exitonkeydown", OPT_BOOL | OPT_EXPERT, { &exit_on_keydown }, "exit on key down", "" },
+ { "exitonmousedown", OPT_BOOL | OPT_EXPERT, { &exit_on_mousedown }, "exit on mouse down", "" },
+ { "loop", OPT_INT | HAS_ARG | OPT_EXPERT, { &loop }, "set number of times the playback shall be looped", "loop count" },
+ { "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" },
+ { "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" },
+ { "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" },
+#if CONFIG_AVFILTER
+ { "vf", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" },
+ { "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" },
+#endif
+ { "rdftspeed", OPT_INT | HAS_ARG| OPT_AUDIO | OPT_EXPERT, { &rdftspeed }, "rdft speed", "msecs" },
+ { "showmode", HAS_ARG, { .func_arg = opt_show_mode}, "select show mode (0 = video, 1 = waves, 2 = RDFT)", "mode" },
+ { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
+ { "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
+ { "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder_name" },
+ { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" },
+ { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" },
+ { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" },
+ { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
+ { NULL, },
+};
+
+static void show_usage(void)
+{
+ av_log(NULL, AV_LOG_INFO, "Simple media player\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [options] input_file\n", program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
+}
+
+void show_help_default(const char *opt, const char *arg)
+{
+ av_log_set_callback(log_callback_help);
+ show_usage();
+ show_help_options(options, "Main options:", 0, OPT_EXPERT, 0);
+ show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0);
+ printf("\n");
+ show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM);
+ show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
+#if !CONFIG_AVFILTER
+ show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM);
+#else
+ show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM);
+#endif
+ printf("\nWhile playing:\n"
+ "q, ESC quit\n"
+ "f toggle full screen\n"
+ "p, SPC pause\n"
+ "a cycle audio channel in the current program\n"
+ "v cycle video channel\n"
+ "t cycle subtitle channel in the current program\n"
+ "c cycle program\n"
+ "w cycle video filters or show modes\n"
+ "s activate frame-step mode\n"
+ "left/right seek backward/forward 10 seconds\n"
+ "down/up seek backward/forward 1 minute\n"
+ "page down/page up seek backward/forward 10 minutes\n"
+ "mouse click seek to percentage in file corresponding to fraction of width\n"
+ );
+}
+
+static int lockmgr(void **mtx, enum AVLockOp op)
+{
+ switch(op) {
+ case AV_LOCK_CREATE:
+ *mtx = SDL_CreateMutex();
+ if(!*mtx)
+ return 1;
+ return 0;
+ case AV_LOCK_OBTAIN:
+ return !!SDL_LockMutex(*mtx);
+ case AV_LOCK_RELEASE:
+ return !!SDL_UnlockMutex(*mtx);
+ case AV_LOCK_DESTROY:
+ SDL_DestroyMutex(*mtx);
+ return 0;
+ }
+ return 1;
+}
+
+/* Called from the main */
+int main(int argc, char **argv)
+{
+ int flags;
+ VideoState *is;
+ char dummy_videodriver[] = "SDL_VIDEODRIVER=dummy";
+
+ av_log_set_flags(AV_LOG_SKIP_REPEATED);
+ parse_loglevel(argc, argv, options);
+
+ /* register all codecs, demux and protocols */
+#if CONFIG_AVDEVICE
+ avdevice_register_all();
+#endif
+#if CONFIG_AVFILTER
+ avfilter_register_all();
+#endif
+ av_register_all();
+ avformat_network_init();
+
+ init_opts();
+
+ signal(SIGINT , sigterm_handler); /* Interrupt (ANSI). */
+ signal(SIGTERM, sigterm_handler); /* Termination (ANSI). */
+
+ show_banner(argc, argv, options);
+
+ parse_options(NULL, argc, argv, options, opt_input_file);
+
+ if (!input_filename) {
+ show_usage();
+ av_log(NULL, AV_LOG_FATAL, "An input file must be specified\n");
+ av_log(NULL, AV_LOG_FATAL,
+ "Use -h to get full help or, even better, run 'man %s'\n", program_name);
+ exit(1);
+ }
+
+ if (display_disable) {
+ video_disable = 1;
+ }
+ flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
+ if (audio_disable)
+ flags &= ~SDL_INIT_AUDIO;
+ if (display_disable)
+ SDL_putenv(dummy_videodriver); /* For the event queue, we always need a video driver. */
+#if !defined(_WIN32) && !defined(__APPLE__)
+ flags |= SDL_INIT_EVENTTHREAD; /* Not supported on Windows or Mac OS X */
+#endif
+ if (SDL_Init (flags)) {
+ av_log(NULL, AV_LOG_FATAL, "Could not initialize SDL - %s\n", SDL_GetError());
+ av_log(NULL, AV_LOG_FATAL, "(Did you set the DISPLAY variable?)\n");
+ exit(1);
+ }
+
+ if (!display_disable) {
+ const SDL_VideoInfo *vi = SDL_GetVideoInfo();
+ fs_screen_width = vi->current_w;
+ fs_screen_height = vi->current_h;
+ }
+
+ SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
+ SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
+ SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
+
+ if (av_lockmgr_register(lockmgr)) {
+ av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
+ do_exit(NULL);
+ }
+
+ av_init_packet(&flush_pkt);
+ flush_pkt.data = (uint8_t *)&flush_pkt;
+
+ is = stream_open(input_filename, file_iformat);
+ if (!is) {
+ av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n");
+ do_exit(NULL);
+ }
+
+ event_loop(is);
+
+ /* never returns */
+
+ return 0;
+}
diff --git a/ffprobe.c b/ffprobe.c
new file mode 100644
index 0000000000..fadcd9336e
--- /dev/null
+++ b/ffprobe.c
@@ -0,0 +1,3262 @@
+/*
+ * Copyright (c) 2007-2010 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * simple media prober based on the FFmpeg libraries
+ */
+
+#include "config.h"
+#include "libavutil/ffversion.h"
+
+#include <string.h>
+
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/display.h"
+#include "libavutil/hash.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/libm.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/timecode.h"
+#include "libavutil/timestamp.h"
+#include "libavdevice/avdevice.h"
+#include "libswscale/swscale.h"
+#include "libswresample/swresample.h"
+#include "libpostproc/postprocess.h"
+#include "cmdutils.h"
+
+const char program_name[] = "ffprobe";
+const int program_birth_year = 2007;
+
+static int do_bitexact = 0;
+static int do_count_frames = 0;
+static int do_count_packets = 0;
+static int do_read_frames = 0;
+static int do_read_packets = 0;
+static int do_show_chapters = 0;
+static int do_show_error = 0;
+static int do_show_format = 0;
+static int do_show_frames = 0;
+static int do_show_packets = 0;
+static int do_show_programs = 0;
+static int do_show_streams = 0;
+static int do_show_stream_disposition = 0;
+static int do_show_data = 0;
+static int do_show_program_version = 0;
+static int do_show_library_versions = 0;
+static int do_show_pixel_formats = 0;
+static int do_show_pixel_format_flags = 0;
+static int do_show_pixel_format_components = 0;
+
+static int do_show_chapter_tags = 0;
+static int do_show_format_tags = 0;
+static int do_show_frame_tags = 0;
+static int do_show_program_tags = 0;
+static int do_show_stream_tags = 0;
+
+static int show_value_unit = 0;
+static int use_value_prefix = 0;
+static int use_byte_value_binary_prefix = 0;
+static int use_value_sexagesimal_format = 0;
+static int show_private_data = 1;
+
+static char *print_format;
+static char *stream_specifier;
+static char *show_data_hash;
+
+typedef struct ReadInterval {
+ int id; ///< identifier
+ int64_t start, end; ///< start, end in second/AV_TIME_BASE units
+ int has_start, has_end;
+ int start_is_offset, end_is_offset;
+ int duration_frames;
+} ReadInterval;
+
+static ReadInterval *read_intervals;
+static int read_intervals_nb = 0;
+
+/* section structure definition */
+
+#define SECTION_MAX_NB_CHILDREN 10
+
+struct section {
+ int id; ///< unique id identifying a section
+ const char *name;
+
+#define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level
+#define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type
+#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys.
+ /// For these sections the element_name field is mandatory.
+ int flags;
+ int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1
+ const char *element_name; ///< name of the contained element, if provided
+ const char *unique_name; ///< unique section name, in case the name is ambiguous
+ AVDictionary *entries_to_show;
+ int show_all_entries;
+};
+
+typedef enum {
+ SECTION_ID_NONE = -1,
+ SECTION_ID_CHAPTER,
+ SECTION_ID_CHAPTER_TAGS,
+ SECTION_ID_CHAPTERS,
+ SECTION_ID_ERROR,
+ SECTION_ID_FORMAT,
+ SECTION_ID_FORMAT_TAGS,
+ SECTION_ID_FRAME,
+ SECTION_ID_FRAMES,
+ SECTION_ID_FRAME_TAGS,
+ SECTION_ID_FRAME_SIDE_DATA_LIST,
+ SECTION_ID_FRAME_SIDE_DATA,
+ SECTION_ID_LIBRARY_VERSION,
+ SECTION_ID_LIBRARY_VERSIONS,
+ SECTION_ID_PACKET,
+ SECTION_ID_PACKETS,
+ SECTION_ID_PACKETS_AND_FRAMES,
+ SECTION_ID_PACKET_SIDE_DATA_LIST,
+ SECTION_ID_PACKET_SIDE_DATA,
+ SECTION_ID_PIXEL_FORMAT,
+ SECTION_ID_PIXEL_FORMAT_FLAGS,
+ SECTION_ID_PIXEL_FORMAT_COMPONENT,
+ SECTION_ID_PIXEL_FORMAT_COMPONENTS,
+ SECTION_ID_PIXEL_FORMATS,
+ SECTION_ID_PROGRAM_STREAM_DISPOSITION,
+ SECTION_ID_PROGRAM_STREAM_TAGS,
+ SECTION_ID_PROGRAM,
+ SECTION_ID_PROGRAM_STREAMS,
+ SECTION_ID_PROGRAM_STREAM,
+ SECTION_ID_PROGRAM_TAGS,
+ SECTION_ID_PROGRAM_VERSION,
+ SECTION_ID_PROGRAMS,
+ SECTION_ID_ROOT,
+ SECTION_ID_STREAM,
+ SECTION_ID_STREAM_DISPOSITION,
+ SECTION_ID_STREAMS,
+ SECTION_ID_STREAM_TAGS,
+ SECTION_ID_STREAM_SIDE_DATA_LIST,
+ SECTION_ID_STREAM_SIDE_DATA,
+ SECTION_ID_SUBTITLE,
+} SectionID;
+
+static struct section sections[] = {
+ [SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
+ [SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
+ [SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
+ [SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
+ [SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
+ [SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
+ [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } },
+ [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, -1 } },
+ [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
+ [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 } },
+ [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { -1 } },
+ [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
+ [SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
+ [SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
+ [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
+ [SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },
+ [SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 } },
+ [SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 } },
+ [SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } },
+ [SECTION_ID_PIXEL_FORMAT] = { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } },
+ [SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" },
+ [SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" },
+ [SECTION_ID_PIXEL_FORMAT_COMPONENT] = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } },
+ [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
+ [SECTION_ID_PROGRAM_STREAM_TAGS] = { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" },
+ [SECTION_ID_PROGRAM] = { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },
+ [SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
+ [SECTION_ID_PROGRAM_STREAM] = { SECTION_ID_PROGRAM_STREAM, "stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 }, .unique_name = "program_stream" },
+ [SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
+ [SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
+ [SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
+ [SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
+ { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
+ SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,
+ SECTION_ID_PIXEL_FORMATS, -1} },
+ [SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
+ [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } },
+ [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
+ [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
+ [SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 } },
+ [SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", 0, { -1 } },
+ [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } },
+};
+
+static const OptionDef *options;
+
+/* FFprobe context */
+static const char *input_filename;
+static AVInputFormat *iformat = NULL;
+
+static struct AVHashContext *hash;
+
+static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
+static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P" };
+
+static const char unit_second_str[] = "s" ;
+static const char unit_hertz_str[] = "Hz" ;
+static const char unit_byte_str[] = "byte" ;
+static const char unit_bit_per_second_str[] = "bit/s";
+
+static int nb_streams;
+static uint64_t *nb_streams_packets;
+static uint64_t *nb_streams_frames;
+static int *selected_streams;
+
+static void ffprobe_cleanup(int ret)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
+ av_dict_free(&(sections[i].entries_to_show));
+}
+
+struct unit_value {
+ union { double d; long long int i; } val;
+ const char *unit;
+};
+
+static char *value_string(char *buf, int buf_size, struct unit_value uv)
+{
+ double vald;
+ long long int vali;
+ int show_float = 0;
+
+ if (uv.unit == unit_second_str) {
+ vald = uv.val.d;
+ show_float = 1;
+ } else {
+ vald = vali = uv.val.i;
+ }
+
+ if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
+ double secs;
+ int hours, mins;
+ secs = vald;
+ mins = (int)secs / 60;
+ secs = secs - mins * 60;
+ hours = mins / 60;
+ mins %= 60;
+ snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
+ } else {
+ const char *prefix_string = "";
+
+ if (use_value_prefix && vald > 1) {
+ long long int index;
+
+ if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
+ index = (long long int) (log2(vald)) / 10;
+ index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) - 1);
+ vald /= exp2(index * 10);
+ prefix_string = binary_unit_prefixes[index];
+ } else {
+ index = (long long int) (log10(vald)) / 3;
+ index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) - 1);
+ vald /= pow(10, index * 3);
+ prefix_string = decimal_unit_prefixes[index];
+ }
+ vali = vald;
+ }
+
+ if (show_float || (use_value_prefix && vald != (long long int)vald))
+ snprintf(buf, buf_size, "%f", vald);
+ else
+ snprintf(buf, buf_size, "%lld", vali);
+ av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
+ prefix_string, show_value_unit ? uv.unit : "");
+ }
+
+ return buf;
+}
+
+/* WRITERS API */
+
+typedef struct WriterContext WriterContext;
+
+#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
+#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
+
+typedef enum {
+ WRITER_STRING_VALIDATION_FAIL,
+ WRITER_STRING_VALIDATION_REPLACE,
+ WRITER_STRING_VALIDATION_IGNORE,
+ WRITER_STRING_VALIDATION_NB
+} StringValidation;
+
+typedef struct Writer {
+ const AVClass *priv_class; ///< private class of the writer, if any
+ int priv_size; ///< private size for the writer context
+ const char *name;
+
+ int (*init) (WriterContext *wctx);
+ void (*uninit)(WriterContext *wctx);
+
+ void (*print_section_header)(WriterContext *wctx);
+ void (*print_section_footer)(WriterContext *wctx);
+ void (*print_integer) (WriterContext *wctx, const char *, long long int);
+ void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep);
+ void (*print_string) (WriterContext *wctx, const char *, const char *);
+ int flags; ///< a combination or WRITER_FLAG_*
+} Writer;
+
+#define SECTION_MAX_NB_LEVELS 10
+
+struct WriterContext {
+ const AVClass *class; ///< class of the writer
+ const Writer *writer; ///< the Writer of which this is an instance
+ char *name; ///< name of this writer instance
+ void *priv; ///< private data for use by the filter
+
+ const struct section *sections; ///< array containing all sections
+ int nb_sections; ///< number of sections
+
+ int level; ///< current level, starting from 0
+
+ /** number of the item printed in the given section, starting from 0 */
+ unsigned int nb_item[SECTION_MAX_NB_LEVELS];
+
+ /** section per each level */
+ const struct section *section[SECTION_MAX_NB_LEVELS];
+ AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section,
+ /// used by various writers
+
+ unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
+ unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section
+ unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
+
+ int string_validation;
+ char *string_validation_replacement;
+ unsigned int string_validation_utf8_flags;
+};
+
+static const char *writer_get_name(void *p)
+{
+ WriterContext *wctx = p;
+ return wctx->writer->name;
+}
+
+#define OFFSET(x) offsetof(WriterContext, x)
+
+static const AVOption writer_options[] = {
+ { "string_validation", "set string validation mode",
+ OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
+ { "sv", "set string validation mode",
+ OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" },
+ { "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" },
+ { "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" },
+ { "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" },
+ { "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}},
+ { "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}},
+ { NULL }
+};
+
+static void *writer_child_next(void *obj, void *prev)
+{
+ WriterContext *ctx = obj;
+ if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv)
+ return ctx->priv;
+ return NULL;
+}
+
+static const AVClass writer_class = {
+ .class_name = "Writer",
+ .item_name = writer_get_name,
+ .option = writer_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .child_next = writer_child_next,
+};
+
+static void writer_close(WriterContext **wctx)
+{
+ int i;
+
+ if (!*wctx)
+ return;
+
+ if ((*wctx)->writer->uninit)
+ (*wctx)->writer->uninit(*wctx);
+ for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
+ av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL);
+ if ((*wctx)->writer->priv_class)
+ av_opt_free((*wctx)->priv);
+ av_freep(&((*wctx)->priv));
+ av_opt_free(*wctx);
+ av_freep(wctx);
+}
+
+static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size)
+{
+ int i;
+ av_bprintf(bp, "0X");
+ for (i = 0; i < ubuf_size; i++)
+ av_bprintf(bp, "%02X", ubuf[i]);
+}
+
+
+static int writer_open(WriterContext **wctx, const Writer *writer, const char *args,
+ const struct section *sections, int nb_sections)
+{
+ int i, ret = 0;
+
+ if (!(*wctx = av_mallocz(sizeof(WriterContext)))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (!((*wctx)->priv = av_mallocz(writer->priv_size))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ (*wctx)->class = &writer_class;
+ (*wctx)->writer = writer;
+ (*wctx)->level = -1;
+ (*wctx)->sections = sections;
+ (*wctx)->nb_sections = nb_sections;
+
+ av_opt_set_defaults(*wctx);
+
+ if (writer->priv_class) {
+ void *priv_ctx = (*wctx)->priv;
+ *((const AVClass **)priv_ctx) = writer->priv_class;
+ av_opt_set_defaults(priv_ctx);
+ }
+
+ /* convert options to dictionary */
+ if (args) {
+ AVDictionary *opts = NULL;
+ AVDictionaryEntry *opt = NULL;
+
+ if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) {
+ av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args);
+ av_dict_free(&opts);
+ goto fail;
+ }
+
+ while ((opt = av_dict_get(opts, "", opt, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) {
+ av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n",
+ opt->key, opt->value);
+ av_dict_free(&opts);
+ goto fail;
+ }
+ }
+
+ av_dict_free(&opts);
+ }
+
+ /* validate replace string */
+ {
+ const uint8_t *p = (*wctx)->string_validation_replacement;
+ const uint8_t *endp = p + strlen(p);
+ while (*p) {
+ const uint8_t *p0 = p;
+ int32_t code;
+ ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags);
+ if (ret < 0) {
+ AVBPrint bp;
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ bprint_bytes(&bp, p0, p-p0),
+ av_log(wctx, AV_LOG_ERROR,
+ "Invalid UTF8 sequence %s found in string validation replace '%s'\n",
+ bp.str, (*wctx)->string_validation_replacement);
+ return ret;
+ }
+ }
+ }
+
+ for (i = 0; i < SECTION_MAX_NB_LEVELS; i++)
+ av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ if ((*wctx)->writer->init)
+ ret = (*wctx)->writer->init(*wctx);
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+
+fail:
+ writer_close(wctx);
+ return ret;
+}
+
+static inline void writer_print_section_header(WriterContext *wctx,
+ int section_id)
+{
+ int parent_section_id;
+ wctx->level++;
+ av_assert0(wctx->level < SECTION_MAX_NB_LEVELS);
+ parent_section_id = wctx->level ?
+ (wctx->section[wctx->level-1])->id : SECTION_ID_NONE;
+
+ wctx->nb_item[wctx->level] = 0;
+ wctx->section[wctx->level] = &wctx->sections[section_id];
+
+ if (section_id == SECTION_ID_PACKETS_AND_FRAMES) {
+ wctx->nb_section_packet = wctx->nb_section_frame =
+ wctx->nb_section_packet_frame = 0;
+ } else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
+ wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ?
+ wctx->nb_section_packet : wctx->nb_section_frame;
+ }
+
+ if (wctx->writer->print_section_header)
+ wctx->writer->print_section_header(wctx);
+}
+
+static inline void writer_print_section_footer(WriterContext *wctx)
+{
+ int section_id = wctx->section[wctx->level]->id;
+ int parent_section_id = wctx->level ?
+ wctx->section[wctx->level-1]->id : SECTION_ID_NONE;
+
+ if (parent_section_id != SECTION_ID_NONE)
+ wctx->nb_item[wctx->level-1]++;
+ if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) {
+ if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++;
+ else wctx->nb_section_frame++;
+ }
+ if (wctx->writer->print_section_footer)
+ wctx->writer->print_section_footer(wctx);
+ wctx->level--;
+}
+
+static inline void writer_print_integer(WriterContext *wctx,
+ const char *key, long long int val)
+{
+ const struct section *section = wctx->section[wctx->level];
+
+ if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+ wctx->writer->print_integer(wctx, key, val);
+ wctx->nb_item[wctx->level]++;
+ }
+}
+
+static inline int validate_string(WriterContext *wctx, char **dstp, const char *src)
+{
+ const uint8_t *p, *endp;
+ AVBPrint dstbuf;
+ int invalid_chars_nb = 0, ret = 0;
+
+ av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ endp = src + strlen(src);
+ for (p = (uint8_t *)src; *p;) {
+ uint32_t code;
+ int invalid = 0;
+ const uint8_t *p0 = p;
+
+ if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) {
+ AVBPrint bp;
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ bprint_bytes(&bp, p0, p-p0);
+ av_log(wctx, AV_LOG_DEBUG,
+ "Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src);
+ invalid = 1;
+ }
+
+ if (invalid) {
+ invalid_chars_nb++;
+
+ switch (wctx->string_validation) {
+ case WRITER_STRING_VALIDATION_FAIL:
+ av_log(wctx, AV_LOG_ERROR,
+ "Invalid UTF-8 sequence found in string '%s'\n", src);
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ break;
+
+ case WRITER_STRING_VALIDATION_REPLACE:
+ av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement);
+ break;
+ }
+ }
+
+ if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE)
+ av_bprint_append_data(&dstbuf, p0, p-p0);
+ }
+
+ if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) {
+ av_log(wctx, AV_LOG_WARNING,
+ "%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n",
+ invalid_chars_nb, src, wctx->string_validation_replacement);
+ }
+
+end:
+ av_bprint_finalize(&dstbuf, dstp);
+ return ret;
+}
+
+#define PRINT_STRING_OPT 1
+#define PRINT_STRING_VALIDATE 2
+
+static inline int writer_print_string(WriterContext *wctx,
+ const char *key, const char *val, int flags)
+{
+ const struct section *section = wctx->section[wctx->level];
+ int ret = 0;
+
+ if ((flags & PRINT_STRING_OPT)
+ && !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS))
+ return 0;
+
+ if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) {
+ if (flags & PRINT_STRING_VALIDATE) {
+ char *key1 = NULL, *val1 = NULL;
+ ret = validate_string(wctx, &key1, key);
+ if (ret < 0) goto end;
+ ret = validate_string(wctx, &val1, val);
+ if (ret < 0) goto end;
+ wctx->writer->print_string(wctx, key1, val1);
+ end:
+ if (ret < 0) {
+ av_log(wctx, AV_LOG_ERROR,
+ "Invalid key=value string combination %s=%s in section %s\n",
+ key, val, section->unique_name);
+ }
+ av_free(key1);
+ av_free(val1);
+ } else {
+ wctx->writer->print_string(wctx, key, val);
+ }
+
+ wctx->nb_item[wctx->level]++;
+ }
+
+ return ret;
+}
+
+static inline void writer_print_rational(WriterContext *wctx,
+ const char *key, AVRational q, char sep)
+{
+ AVBPrint buf;
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ av_bprintf(&buf, "%d%c%d", q.num, sep, q.den);
+ writer_print_string(wctx, key, buf.str, 0);
+}
+
+static void writer_print_time(WriterContext *wctx, const char *key,
+ int64_t ts, const AVRational *time_base, int is_duration)
+{
+ char buf[128];
+
+ if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
+ writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
+ } else {
+ double d = ts * av_q2d(*time_base);
+ struct unit_value uv;
+ uv.val.d = d;
+ uv.unit = unit_second_str;
+ value_string(buf, sizeof(buf), uv);
+ writer_print_string(wctx, key, buf, 0);
+ }
+}
+
+static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration)
+{
+ if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) {
+ writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT);
+ } else {
+ writer_print_integer(wctx, key, ts);
+ }
+}
+
+static void writer_print_data(WriterContext *wctx, const char *name,
+ uint8_t *data, int size)
+{
+ AVBPrint bp;
+ int offset = 0, l, i;
+
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&bp, "\n");
+ while (size) {
+ av_bprintf(&bp, "%08x: ", offset);
+ l = FFMIN(size, 16);
+ for (i = 0; i < l; i++) {
+ av_bprintf(&bp, "%02x", data[i]);
+ if (i & 1)
+ av_bprintf(&bp, " ");
+ }
+ av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2);
+ for (i = 0; i < l; i++)
+ av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1);
+ av_bprintf(&bp, "\n");
+ offset += l;
+ data += l;
+ size -= l;
+ }
+ writer_print_string(wctx, name, bp.str, 0);
+ av_bprint_finalize(&bp, NULL);
+}
+
+static void writer_print_data_hash(WriterContext *wctx, const char *name,
+ uint8_t *data, int size)
+{
+ char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 };
+
+ if (!hash)
+ return;
+ av_hash_init(hash);
+ av_hash_update(hash, data, size);
+ snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash));
+ p = buf + strlen(buf);
+ av_hash_final_hex(hash, p, buf + sizeof(buf) - p);
+ writer_print_string(wctx, name, buf, 0);
+}
+
+static void writer_print_integers(WriterContext *wctx, const char *name,
+ uint8_t *data, int size, const char *format,
+ int columns, int bytes, int offset_add)
+{
+ AVBPrint bp;
+ int offset = 0, l, i;
+
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&bp, "\n");
+ while (size) {
+ av_bprintf(&bp, "%08x: ", offset);
+ l = FFMIN(size, columns);
+ for (i = 0; i < l; i++) {
+ if (bytes == 1) av_bprintf(&bp, format, *data);
+ else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data));
+ else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data));
+ data += bytes;
+ size --;
+ }
+ av_bprintf(&bp, "\n");
+ offset += offset_add;
+ }
+ writer_print_string(wctx, name, bp.str, 0);
+ av_bprint_finalize(&bp, NULL);
+}
+
+#define MAX_REGISTERED_WRITERS_NB 64
+
+static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1];
+
+static int writer_register(const Writer *writer)
+{
+ static int next_registered_writer_idx = 0;
+
+ if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB)
+ return AVERROR(ENOMEM);
+
+ registered_writers[next_registered_writer_idx++] = writer;
+ return 0;
+}
+
+static const Writer *writer_get_by_name(const char *name)
+{
+ int i;
+
+ for (i = 0; registered_writers[i]; i++)
+ if (!strcmp(registered_writers[i]->name, name))
+ return registered_writers[i];
+
+ return NULL;
+}
+
+
+/* WRITERS */
+
+#define DEFINE_WRITER_CLASS(name) \
+static const char *name##_get_name(void *ctx) \
+{ \
+ return #name ; \
+} \
+static const AVClass name##_class = { \
+ .class_name = #name, \
+ .item_name = name##_get_name, \
+ .option = name##_options \
+}
+
+/* Default output */
+
+typedef struct DefaultContext {
+ const AVClass *class;
+ int nokey;
+ int noprint_wrappers;
+ int nested_section[SECTION_MAX_NB_LEVELS];
+} DefaultContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(DefaultContext, x)
+
+static const AVOption default_options[] = {
+ { "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ { "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ { "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ { "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(default);
+
+/* lame uppercasing routine, assumes the string is lower case ASCII */
+static inline char *upcase_string(char *dst, size_t dst_size, const char *src)
+{
+ int i;
+ for (i = 0; src[i] && i < dst_size-1; i++)
+ dst[i] = av_toupper(src[i]);
+ dst[i] = 0;
+ return dst;
+}
+
+static void default_print_section_header(WriterContext *wctx)
+{
+ DefaultContext *def = wctx->priv;
+ char buf[32];
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ av_bprint_clear(&wctx->section_pbuf[wctx->level]);
+ if (parent_section &&
+ !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
+ def->nested_section[wctx->level] = 1;
+ av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
+ wctx->section_pbuf[wctx->level-1].str,
+ upcase_string(buf, sizeof(buf),
+ av_x_if_null(section->element_name, section->name)));
+ }
+
+ if (def->noprint_wrappers || def->nested_section[wctx->level])
+ return;
+
+ if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name));
+}
+
+static void default_print_section_footer(WriterContext *wctx)
+{
+ DefaultContext *def = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+ char buf[32];
+
+ if (def->noprint_wrappers || def->nested_section[wctx->level])
+ return;
+
+ if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name));
+}
+
+static void default_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ DefaultContext *def = wctx->priv;
+
+ if (!def->nokey)
+ printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ printf("%s\n", value);
+}
+
+static void default_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ DefaultContext *def = wctx->priv;
+
+ if (!def->nokey)
+ printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ printf("%lld\n", value);
+}
+
+static const Writer default_writer = {
+ .name = "default",
+ .priv_size = sizeof(DefaultContext),
+ .print_section_header = default_print_section_header,
+ .print_section_footer = default_print_section_footer,
+ .print_integer = default_print_int,
+ .print_string = default_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
+ .priv_class = &default_class,
+};
+
+/* Compact output */
+
+/**
+ * Apply C-language-like string escaping.
+ */
+static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ switch (*p) {
+ case '\b': av_bprintf(dst, "%s", "\\b"); break;
+ case '\f': av_bprintf(dst, "%s", "\\f"); break;
+ case '\n': av_bprintf(dst, "%s", "\\n"); break;
+ case '\r': av_bprintf(dst, "%s", "\\r"); break;
+ case '\\': av_bprintf(dst, "%s", "\\\\"); break;
+ default:
+ if (*p == sep)
+ av_bprint_chars(dst, '\\', 1);
+ av_bprint_chars(dst, *p, 1);
+ }
+ }
+ return dst->str;
+}
+
+/**
+ * Quote fields containing special characters, check RFC4180.
+ */
+static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
+{
+ char meta_chars[] = { sep, '"', '\n', '\r', '\0' };
+ int needs_quoting = !!src[strcspn(src, meta_chars)];
+
+ if (needs_quoting)
+ av_bprint_chars(dst, '"', 1);
+
+ for (; *src; src++) {
+ if (*src == '"')
+ av_bprint_chars(dst, '"', 1);
+ av_bprint_chars(dst, *src, 1);
+ }
+ if (needs_quoting)
+ av_bprint_chars(dst, '"', 1);
+ return dst->str;
+}
+
+static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx)
+{
+ return src;
+}
+
+typedef struct CompactContext {
+ const AVClass *class;
+ char *item_sep_str;
+ char item_sep;
+ int nokey;
+ int print_section;
+ char *escape_mode_str;
+ const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx);
+ int nested_section[SECTION_MAX_NB_LEVELS];
+ int has_nested_elems[SECTION_MAX_NB_LEVELS];
+ int terminate_line[SECTION_MAX_NB_LEVELS];
+} CompactContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(CompactContext, x)
+
+static const AVOption compact_options[]= {
+ {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, CHAR_MIN, CHAR_MAX },
+ {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, CHAR_MIN, CHAR_MAX },
+ {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, CHAR_MIN, CHAR_MAX },
+ {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, CHAR_MIN, CHAR_MAX },
+ {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(compact);
+
+static av_cold int compact_init(WriterContext *wctx)
+{
+ CompactContext *compact = wctx->priv;
+
+ if (strlen(compact->item_sep_str) != 1) {
+ av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
+ compact->item_sep_str);
+ return AVERROR(EINVAL);
+ }
+ compact->item_sep = compact->item_sep_str[0];
+
+ if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str;
+ else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str;
+ else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str;
+ else {
+ av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static void compact_print_section_header(WriterContext *wctx)
+{
+ CompactContext *compact = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+ compact->terminate_line[wctx->level] = 1;
+ compact->has_nested_elems[wctx->level] = 0;
+
+ av_bprint_clear(&wctx->section_pbuf[wctx->level]);
+ if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section &&
+ !(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) {
+ compact->nested_section[wctx->level] = 1;
+ compact->has_nested_elems[wctx->level-1] = 1;
+ av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:",
+ wctx->section_pbuf[wctx->level-1].str,
+ (char *)av_x_if_null(section->element_name, section->name));
+ wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1];
+ } else {
+ if (parent_section && compact->has_nested_elems[wctx->level-1] &&
+ (section->flags & SECTION_FLAG_IS_ARRAY)) {
+ compact->terminate_line[wctx->level-1] = 0;
+ printf("\n");
+ }
+ if (compact->print_section &&
+ !(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ printf("%s%c", section->name, compact->item_sep);
+ }
+}
+
+static void compact_print_section_footer(WriterContext *wctx)
+{
+ CompactContext *compact = wctx->priv;
+
+ if (!compact->nested_section[wctx->level] &&
+ compact->terminate_line[wctx->level] &&
+ !(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY)))
+ printf("\n");
+}
+
+static void compact_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ CompactContext *compact = wctx->priv;
+ AVBPrint buf;
+
+ if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
+ if (!compact->nokey)
+ printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void compact_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ CompactContext *compact = wctx->priv;
+
+ if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep);
+ if (!compact->nokey)
+ printf("%s%s=", wctx->section_pbuf[wctx->level].str, key);
+ printf("%lld", value);
+}
+
+static const Writer compact_writer = {
+ .name = "compact",
+ .priv_size = sizeof(CompactContext),
+ .init = compact_init,
+ .print_section_header = compact_print_section_header,
+ .print_section_footer = compact_print_section_footer,
+ .print_integer = compact_print_int,
+ .print_string = compact_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
+ .priv_class = &compact_class,
+};
+
+/* CSV output */
+
+#undef OFFSET
+#define OFFSET(x) offsetof(CompactContext, x)
+
+static const AVOption csv_options[] = {
+ {"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, CHAR_MIN, CHAR_MAX },
+ {"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, CHAR_MIN, CHAR_MAX },
+ {"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
+ {"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, CHAR_MIN, CHAR_MAX },
+ {"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(csv);
+
+static const Writer csv_writer = {
+ .name = "csv",
+ .priv_size = sizeof(CompactContext),
+ .init = compact_init,
+ .print_section_header = compact_print_section_header,
+ .print_section_footer = compact_print_section_footer,
+ .print_integer = compact_print_int,
+ .print_string = compact_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS,
+ .priv_class = &csv_class,
+};
+
+/* Flat output */
+
+typedef struct FlatContext {
+ const AVClass *class;
+ const char *sep_str;
+ char sep;
+ int hierarchical;
+} FlatContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(FlatContext, x)
+
+static const AVOption flat_options[]= {
+ {"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, CHAR_MIN, CHAR_MAX },
+ {"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, CHAR_MIN, CHAR_MAX },
+ {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(flat);
+
+static av_cold int flat_init(WriterContext *wctx)
+{
+ FlatContext *flat = wctx->priv;
+
+ if (strlen(flat->sep_str) != 1) {
+ av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n",
+ flat->sep_str);
+ return AVERROR(EINVAL);
+ }
+ flat->sep = flat->sep_str[0];
+
+ return 0;
+}
+
+static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ if (!((*p >= '0' && *p <= '9') ||
+ (*p >= 'a' && *p <= 'z') ||
+ (*p >= 'A' && *p <= 'Z')))
+ av_bprint_chars(dst, '_', 1);
+ else
+ av_bprint_chars(dst, *p, 1);
+ }
+ return dst->str;
+}
+
+static const char *flat_escape_value_str(AVBPrint *dst, const char *src)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ switch (*p) {
+ case '\n': av_bprintf(dst, "%s", "\\n"); break;
+ case '\r': av_bprintf(dst, "%s", "\\r"); break;
+ case '\\': av_bprintf(dst, "%s", "\\\\"); break;
+ case '"': av_bprintf(dst, "%s", "\\\""); break;
+ case '`': av_bprintf(dst, "%s", "\\`"); break;
+ case '$': av_bprintf(dst, "%s", "\\$"); break;
+ default: av_bprint_chars(dst, *p, 1); break;
+ }
+ }
+ return dst->str;
+}
+
+static void flat_print_section_header(WriterContext *wctx)
+{
+ FlatContext *flat = wctx->priv;
+ AVBPrint *buf = &wctx->section_pbuf[wctx->level];
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ /* build section header */
+ av_bprint_clear(buf);
+ if (!parent_section)
+ return;
+ av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
+
+ if (flat->hierarchical ||
+ !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
+ av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str);
+
+ if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
+ int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
+ wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
+ av_bprintf(buf, "%d%s", n, flat->sep_str);
+ }
+ }
+}
+
+static void flat_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ printf("%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value);
+}
+
+static void flat_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ FlatContext *flat = wctx->priv;
+ AVBPrint buf;
+
+ printf("%s", wctx->section_pbuf[wctx->level].str);
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ printf("%s=", flat_escape_key_str(&buf, key, flat->sep));
+ av_bprint_clear(&buf);
+ printf("\"%s\"\n", flat_escape_value_str(&buf, value));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static const Writer flat_writer = {
+ .name = "flat",
+ .priv_size = sizeof(FlatContext),
+ .init = flat_init,
+ .print_section_header = flat_print_section_header,
+ .print_integer = flat_print_int,
+ .print_string = flat_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &flat_class,
+};
+
+/* INI format output */
+
+typedef struct INIContext {
+ const AVClass *class;
+ int hierarchical;
+} INIContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(INIContext, x)
+
+static const AVOption ini_options[] = {
+ {"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.i64=1}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(ini);
+
+static char *ini_escape_str(AVBPrint *dst, const char *src)
+{
+ int i = 0;
+ char c = 0;
+
+ while (c = src[i++]) {
+ switch (c) {
+ case '\b': av_bprintf(dst, "%s", "\\b"); break;
+ case '\f': av_bprintf(dst, "%s", "\\f"); break;
+ case '\n': av_bprintf(dst, "%s", "\\n"); break;
+ case '\r': av_bprintf(dst, "%s", "\\r"); break;
+ case '\t': av_bprintf(dst, "%s", "\\t"); break;
+ case '\\':
+ case '#' :
+ case '=' :
+ case ':' : av_bprint_chars(dst, '\\', 1);
+ default:
+ if ((unsigned char)c < 32)
+ av_bprintf(dst, "\\x00%02x", c & 0xff);
+ else
+ av_bprint_chars(dst, c, 1);
+ break;
+ }
+ }
+ return dst->str;
+}
+
+static void ini_print_section_header(WriterContext *wctx)
+{
+ INIContext *ini = wctx->priv;
+ AVBPrint *buf = &wctx->section_pbuf[wctx->level];
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ av_bprint_clear(buf);
+ if (!parent_section) {
+ printf("# ffprobe output\n\n");
+ return;
+ }
+
+ if (wctx->nb_item[wctx->level-1])
+ printf("\n");
+
+ av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str);
+ if (ini->hierarchical ||
+ !(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) {
+ av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name);
+
+ if (parent_section->flags & SECTION_FLAG_IS_ARRAY) {
+ int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ?
+ wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1];
+ av_bprintf(buf, ".%d", n);
+ }
+ }
+
+ if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER)))
+ printf("[%s]\n", buf->str);
+}
+
+static void ini_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ printf("%s=", ini_escape_str(&buf, key));
+ av_bprint_clear(&buf);
+ printf("%s\n", ini_escape_str(&buf, value));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void ini_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ printf("%s=%lld\n", key, value);
+}
+
+static const Writer ini_writer = {
+ .name = "ini",
+ .priv_size = sizeof(INIContext),
+ .print_section_header = ini_print_section_header,
+ .print_integer = ini_print_int,
+ .print_string = ini_print_str,
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &ini_class,
+};
+
+/* JSON output */
+
+typedef struct JSONContext {
+ const AVClass *class;
+ int indent_level;
+ int compact;
+ const char *item_sep, *item_start_end;
+} JSONContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(JSONContext, x)
+
+static const AVOption json_options[]= {
+ { "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ { "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ { NULL }
+};
+
+DEFINE_WRITER_CLASS(json);
+
+static av_cold int json_init(WriterContext *wctx)
+{
+ JSONContext *json = wctx->priv;
+
+ json->item_sep = json->compact ? ", " : ",\n";
+ json->item_start_end = json->compact ? " " : "\n";
+
+ return 0;
+}
+
+static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
+{
+ static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0};
+ static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0};
+ const char *p;
+
+ for (p = src; *p; p++) {
+ char *s = strchr(json_escape, *p);
+ if (s) {
+ av_bprint_chars(dst, '\\', 1);
+ av_bprint_chars(dst, json_subst[s - json_escape], 1);
+ } else if ((unsigned char)*p < 32) {
+ av_bprintf(dst, "\\u00%02x", *p & 0xff);
+ } else {
+ av_bprint_chars(dst, *p, 1);
+ }
+ }
+ return dst->str;
+}
+
+#define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ')
+
+static void json_print_section_header(WriterContext *wctx)
+{
+ JSONContext *json = wctx->priv;
+ AVBPrint buf;
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ if (wctx->level && wctx->nb_item[wctx->level-1])
+ printf(",\n");
+
+ if (section->flags & SECTION_FLAG_IS_WRAPPER) {
+ printf("{\n");
+ json->indent_level++;
+ } else {
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ json_escape_str(&buf, section->name, wctx);
+ JSON_INDENT();
+
+ json->indent_level++;
+ if (section->flags & SECTION_FLAG_IS_ARRAY) {
+ printf("\"%s\": [\n", buf.str);
+ } else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) {
+ printf("\"%s\": {%s", buf.str, json->item_start_end);
+ } else {
+ printf("{%s", json->item_start_end);
+
+ /* this is required so the parser can distinguish between packets and frames */
+ if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) {
+ if (!json->compact)
+ JSON_INDENT();
+ printf("\"type\": \"%s\"%s", section->name, json->item_sep);
+ }
+ }
+ av_bprint_finalize(&buf, NULL);
+ }
+}
+
+static void json_print_section_footer(WriterContext *wctx)
+{
+ JSONContext *json = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+
+ if (wctx->level == 0) {
+ json->indent_level--;
+ printf("\n}\n");
+ } else if (section->flags & SECTION_FLAG_IS_ARRAY) {
+ printf("\n");
+ json->indent_level--;
+ JSON_INDENT();
+ printf("]");
+ } else {
+ printf("%s", json->item_start_end);
+ json->indent_level--;
+ if (!json->compact)
+ JSON_INDENT();
+ printf("}");
+ }
+}
+
+static inline void json_print_item_str(WriterContext *wctx,
+ const char *key, const char *value)
+{
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ printf("\"%s\":", json_escape_str(&buf, key, wctx));
+ av_bprint_clear(&buf);
+ printf(" \"%s\"", json_escape_str(&buf, value, wctx));
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void json_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ JSONContext *json = wctx->priv;
+
+ if (wctx->nb_item[wctx->level])
+ printf("%s", json->item_sep);
+ if (!json->compact)
+ JSON_INDENT();
+ json_print_item_str(wctx, key, value);
+}
+
+static void json_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ JSONContext *json = wctx->priv;
+ AVBPrint buf;
+
+ if (wctx->nb_item[wctx->level])
+ printf("%s", json->item_sep);
+ if (!json->compact)
+ JSON_INDENT();
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value);
+ av_bprint_finalize(&buf, NULL);
+}
+
+static const Writer json_writer = {
+ .name = "json",
+ .priv_size = sizeof(JSONContext),
+ .init = json_init,
+ .print_section_header = json_print_section_header,
+ .print_section_footer = json_print_section_footer,
+ .print_integer = json_print_int,
+ .print_string = json_print_str,
+ .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &json_class,
+};
+
+/* XML output */
+
+typedef struct XMLContext {
+ const AVClass *class;
+ int within_tag;
+ int indent_level;
+ int fully_qualified;
+ int xsd_strict;
+} XMLContext;
+
+#undef OFFSET
+#define OFFSET(x) offsetof(XMLContext, x)
+
+static const AVOption xml_options[] = {
+ {"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 },
+ {NULL},
+};
+
+DEFINE_WRITER_CLASS(xml);
+
+static av_cold int xml_init(WriterContext *wctx)
+{
+ XMLContext *xml = wctx->priv;
+
+ if (xml->xsd_strict) {
+ xml->fully_qualified = 1;
+#define CHECK_COMPLIANCE(opt, opt_name) \
+ if (opt) { \
+ av_log(wctx, AV_LOG_ERROR, \
+ "XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \
+ "You need to disable such option with '-no%s'\n", opt_name, opt_name); \
+ return AVERROR(EINVAL); \
+ }
+ CHECK_COMPLIANCE(show_private_data, "private");
+ CHECK_COMPLIANCE(show_value_unit, "unit");
+ CHECK_COMPLIANCE(use_value_prefix, "prefix");
+
+ if (do_show_frames && do_show_packets) {
+ av_log(wctx, AV_LOG_ERROR,
+ "Interleaved frames and packets are not allowed in XSD. "
+ "Select only one between the -show_frames and the -show_packets options.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return 0;
+}
+
+static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx)
+{
+ const char *p;
+
+ for (p = src; *p; p++) {
+ switch (*p) {
+ case '&' : av_bprintf(dst, "%s", "&amp;"); break;
+ case '<' : av_bprintf(dst, "%s", "&lt;"); break;
+ case '>' : av_bprintf(dst, "%s", "&gt;"); break;
+ case '"' : av_bprintf(dst, "%s", "&quot;"); break;
+ case '\'': av_bprintf(dst, "%s", "&apos;"); break;
+ default: av_bprint_chars(dst, *p, 1);
+ }
+ }
+
+ return dst->str;
+}
+
+#define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ')
+
+static void xml_print_section_header(WriterContext *wctx)
+{
+ XMLContext *xml = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+ const struct section *parent_section = wctx->level ?
+ wctx->section[wctx->level-1] : NULL;
+
+ if (wctx->level == 0) {
+ const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
+ "xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' "
+ "xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'";
+
+ printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ printf("<%sffprobe%s>\n",
+ xml->fully_qualified ? "ffprobe:" : "",
+ xml->fully_qualified ? qual : "");
+ return;
+ }
+
+ if (xml->within_tag) {
+ xml->within_tag = 0;
+ printf(">\n");
+ }
+ if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
+ xml->indent_level++;
+ } else {
+ if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) &&
+ wctx->level && wctx->nb_item[wctx->level-1])
+ printf("\n");
+ xml->indent_level++;
+
+ if (section->flags & SECTION_FLAG_IS_ARRAY) {
+ XML_INDENT(); printf("<%s>\n", section->name);
+ } else {
+ XML_INDENT(); printf("<%s ", section->name);
+ xml->within_tag = 1;
+ }
+ }
+}
+
+static void xml_print_section_footer(WriterContext *wctx)
+{
+ XMLContext *xml = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+
+ if (wctx->level == 0) {
+ printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : "");
+ } else if (xml->within_tag) {
+ xml->within_tag = 0;
+ printf("/>\n");
+ xml->indent_level--;
+ } else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
+ xml->indent_level--;
+ } else {
+ XML_INDENT(); printf("</%s>\n", section->name);
+ xml->indent_level--;
+ }
+}
+
+static void xml_print_str(WriterContext *wctx, const char *key, const char *value)
+{
+ AVBPrint buf;
+ XMLContext *xml = wctx->priv;
+ const struct section *section = wctx->section[wctx->level];
+
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) {
+ XML_INDENT();
+ printf("<%s key=\"%s\"",
+ section->element_name, xml_escape_str(&buf, key, wctx));
+ av_bprint_clear(&buf);
+ printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx));
+ } else {
+ if (wctx->nb_item[wctx->level])
+ printf(" ");
+ printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx));
+ }
+
+ av_bprint_finalize(&buf, NULL);
+}
+
+static void xml_print_int(WriterContext *wctx, const char *key, long long int value)
+{
+ if (wctx->nb_item[wctx->level])
+ printf(" ");
+ printf("%s=\"%lld\"", key, value);
+}
+
+static Writer xml_writer = {
+ .name = "xml",
+ .priv_size = sizeof(XMLContext),
+ .init = xml_init,
+ .print_section_header = xml_print_section_header,
+ .print_section_footer = xml_print_section_footer,
+ .print_integer = xml_print_int,
+ .print_string = xml_print_str,
+ .flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER,
+ .priv_class = &xml_class,
+};
+
+static void writer_register_all(void)
+{
+ static int initialized;
+
+ if (initialized)
+ return;
+ initialized = 1;
+
+ writer_register(&default_writer);
+ writer_register(&compact_writer);
+ writer_register(&csv_writer);
+ writer_register(&flat_writer);
+ writer_register(&ini_writer);
+ writer_register(&json_writer);
+ writer_register(&xml_writer);
+}
+
+#define print_fmt(k, f, ...) do { \
+ av_bprint_clear(&pbuf); \
+ av_bprintf(&pbuf, f, __VA_ARGS__); \
+ writer_print_string(w, k, pbuf.str, 0); \
+} while (0)
+
+#define print_int(k, v) writer_print_integer(w, k, v)
+#define print_q(k, v, s) writer_print_rational(w, k, v, s)
+#define print_str(k, v) writer_print_string(w, k, v, 0)
+#define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT)
+#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE)
+#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0)
+#define print_ts(k, v) writer_print_ts(w, k, v, 0)
+#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1)
+#define print_duration_ts(k, v) writer_print_ts(w, k, v, 1)
+#define print_val(k, v, u) do { \
+ struct unit_value uv; \
+ uv.val.i = v; \
+ uv.unit = u; \
+ writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \
+} while (0)
+
+#define print_section_header(s) writer_print_section_header(w, s)
+#define print_section_footer(s) writer_print_section_footer(w, s)
+
+#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \
+{ \
+ ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \
+ if (ret < 0) \
+ goto end; \
+ memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \
+}
+
+static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id)
+{
+ AVDictionaryEntry *tag = NULL;
+ int ret = 0;
+
+ if (!tags)
+ return 0;
+ writer_print_section_header(w, section_id);
+
+ while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = print_str_validate(tag->key, tag->value)) < 0)
+ break;
+ }
+ writer_print_section_footer(w);
+
+ return ret;
+}
+
+static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pkt, int packet_idx)
+{
+ char val_str[128];
+ AVStream *st = fmt_ctx->streams[pkt->stream_index];
+ AVBPrint pbuf;
+ const char *s;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_PACKET);
+
+ s = av_get_media_type_string(st->codec->codec_type);
+ if (s) print_str ("codec_type", s);
+ else print_str_opt("codec_type", "unknown");
+ print_int("stream_index", pkt->stream_index);
+ print_ts ("pts", pkt->pts);
+ print_time("pts_time", pkt->pts, &st->time_base);
+ print_ts ("dts", pkt->dts);
+ print_time("dts_time", pkt->dts, &st->time_base);
+ print_duration_ts("duration", pkt->duration);
+ print_duration_time("duration_time", pkt->duration, &st->time_base);
+ print_duration_ts("convergence_duration", pkt->convergence_duration);
+ print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base);
+ print_val("size", pkt->size, unit_byte_str);
+ if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
+ else print_str_opt("pos", "N/A");
+ print_fmt("flags", "%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_');
+
+ if (pkt->side_data_elems) {
+ int i;
+ writer_print_section_header(w, SECTION_ID_PACKET_SIDE_DATA_LIST);
+ for (i = 0; i < pkt->side_data_elems; i++) {
+ AVPacketSideData *sd = &pkt->side_data[i];
+ const char *name = av_packet_side_data_name(sd->type);
+ writer_print_section_header(w, SECTION_ID_PACKET_SIDE_DATA);
+ print_str("side_data_type", name ? name : "unknown");
+ print_int("side_data_size", sd->size);
+ if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+ writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
+ print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+
+ if (do_show_data)
+ writer_print_data(w, "data", pkt->data, pkt->size);
+ writer_print_data_hash(w, "data_hash", pkt->data, pkt->size);
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+}
+
+static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream,
+ AVFormatContext *fmt_ctx)
+{
+ AVBPrint pbuf;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_SUBTITLE);
+
+ print_str ("media_type", "subtitle");
+ print_ts ("pts", sub->pts);
+ print_time("pts_time", sub->pts, &AV_TIME_BASE_Q);
+ print_int ("format", sub->format);
+ print_int ("start_display_time", sub->start_display_time);
+ print_int ("end_display_time", sub->end_display_time);
+ print_int ("num_rects", sub->num_rects);
+
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+}
+
+static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
+ AVFormatContext *fmt_ctx)
+{
+ AVBPrint pbuf;
+ const char *s;
+ int i;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_FRAME);
+
+ s = av_get_media_type_string(stream->codec->codec_type);
+ if (s) print_str ("media_type", s);
+ else print_str_opt("media_type", "unknown");
+ print_int("key_frame", frame->key_frame);
+ print_ts ("pkt_pts", frame->pkt_pts);
+ print_time("pkt_pts_time", frame->pkt_pts, &stream->time_base);
+ print_ts ("pkt_dts", frame->pkt_dts);
+ print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base);
+ print_ts ("best_effort_timestamp", av_frame_get_best_effort_timestamp(frame));
+ print_time("best_effort_timestamp_time", av_frame_get_best_effort_timestamp(frame), &stream->time_base);
+ print_duration_ts ("pkt_duration", av_frame_get_pkt_duration(frame));
+ print_duration_time("pkt_duration_time", av_frame_get_pkt_duration(frame), &stream->time_base);
+ if (av_frame_get_pkt_pos (frame) != -1) print_fmt ("pkt_pos", "%"PRId64, av_frame_get_pkt_pos(frame));
+ else print_str_opt("pkt_pos", "N/A");
+ if (av_frame_get_pkt_size(frame) != -1) print_fmt ("pkt_size", "%d", av_frame_get_pkt_size(frame));
+ else print_str_opt("pkt_size", "N/A");
+
+ switch (stream->codec->codec_type) {
+ AVRational sar;
+
+ case AVMEDIA_TYPE_VIDEO:
+ print_int("width", frame->width);
+ print_int("height", frame->height);
+ s = av_get_pix_fmt_name(frame->format);
+ if (s) print_str ("pix_fmt", s);
+ else print_str_opt("pix_fmt", "unknown");
+ sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame);
+ if (sar.num) {
+ print_q("sample_aspect_ratio", sar, ':');
+ } else {
+ print_str_opt("sample_aspect_ratio", "N/A");
+ }
+ print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type));
+ print_int("coded_picture_number", frame->coded_picture_number);
+ print_int("display_picture_number", frame->display_picture_number);
+ print_int("interlaced_frame", frame->interlaced_frame);
+ print_int("top_field_first", frame->top_field_first);
+ print_int("repeat_pict", frame->repeat_pict);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ s = av_get_sample_fmt_name(frame->format);
+ if (s) print_str ("sample_fmt", s);
+ else print_str_opt("sample_fmt", "unknown");
+ print_int("nb_samples", frame->nb_samples);
+ print_int("channels", av_frame_get_channels(frame));
+ if (av_frame_get_channel_layout(frame)) {
+ av_bprint_clear(&pbuf);
+ av_bprint_channel_layout(&pbuf, av_frame_get_channels(frame),
+ av_frame_get_channel_layout(frame));
+ print_str ("channel_layout", pbuf.str);
+ } else
+ print_str_opt("channel_layout", "unknown");
+ break;
+ }
+ if (do_show_frame_tags)
+ show_tags(w, av_frame_get_metadata(frame), SECTION_ID_FRAME_TAGS);
+ if (frame->nb_side_data) {
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST);
+ for (i = 0; i < frame->nb_side_data; i++) {
+ AVFrameSideData *sd = frame->side_data[i];
+ const char *name;
+
+ writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA);
+ name = av_frame_side_data_name(sd->type);
+ print_str("side_data_type", name ? name : "unknown");
+ print_int("side_data_size", sd->size);
+ if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+ abort();
+ writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
+ print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+}
+
+static av_always_inline int process_frame(WriterContext *w,
+ AVFormatContext *fmt_ctx,
+ AVFrame *frame, AVPacket *pkt)
+{
+ AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
+ AVSubtitle sub;
+ int ret = 0, got_frame = 0;
+
+ if (dec_ctx->codec) {
+ switch (dec_ctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, pkt);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
+ break;
+
+ case AVMEDIA_TYPE_SUBTITLE:
+ ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt);
+ break;
+ }
+ }
+
+ if (ret < 0)
+ return ret;
+ ret = FFMIN(ret, pkt->size); /* guard against bogus return values */
+ pkt->data += ret;
+ pkt->size -= ret;
+ if (got_frame) {
+ int is_sub = (dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE);
+ nb_streams_frames[pkt->stream_index]++;
+ if (do_show_frames)
+ if (is_sub)
+ show_subtitle(w, &sub, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
+ else
+ show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx);
+ if (is_sub)
+ avsubtitle_free(&sub);
+ }
+ return got_frame;
+}
+
+static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level)
+{
+ av_log(log_ctx, log_level, "id:%d", interval->id);
+
+ if (interval->has_start) {
+ av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "",
+ av_ts2timestr(interval->start, &AV_TIME_BASE_Q));
+ } else {
+ av_log(log_ctx, log_level, " start:N/A");
+ }
+
+ if (interval->has_end) {
+ av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : "");
+ if (interval->duration_frames)
+ av_log(log_ctx, log_level, "#%"PRId64, interval->end);
+ else
+ av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q));
+ } else {
+ av_log(log_ctx, log_level, " end:N/A");
+ }
+
+ av_log(log_ctx, log_level, "\n");
+}
+
+static int read_interval_packets(WriterContext *w, AVFormatContext *fmt_ctx,
+ const ReadInterval *interval, int64_t *cur_ts)
+{
+ AVPacket pkt, pkt1;
+ AVFrame *frame = NULL;
+ int ret = 0, i = 0, frame_count = 0;
+ int64_t start = -INT64_MAX, end = interval->end;
+ int has_start = 0, has_end = interval->has_end && !interval->end_is_offset;
+
+ av_init_packet(&pkt);
+
+ av_log(NULL, AV_LOG_VERBOSE, "Processing read interval ");
+ log_read_interval(interval, NULL, AV_LOG_VERBOSE);
+
+ if (interval->has_start) {
+ int64_t target;
+ if (interval->start_is_offset) {
+ if (*cur_ts == AV_NOPTS_VALUE) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not seek to relative position since current "
+ "timestamp is not defined\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ target = *cur_ts + interval->start;
+ } else {
+ target = interval->start;
+ }
+
+ av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n",
+ av_ts2timestr(target, &AV_TIME_BASE_Q));
+ if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n",
+ interval->start, av_err2str(ret));
+ goto end;
+ }
+ }
+
+ frame = av_frame_alloc();
+ if (!frame) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ while (!av_read_frame(fmt_ctx, &pkt)) {
+ if (fmt_ctx->nb_streams > nb_streams) {
+ REALLOCZ_ARRAY_STREAM(nb_streams_frames, nb_streams, fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(selected_streams, nb_streams, fmt_ctx->nb_streams);
+ nb_streams = fmt_ctx->nb_streams;
+ }
+ if (selected_streams[pkt.stream_index]) {
+ AVRational tb = fmt_ctx->streams[pkt.stream_index]->time_base;
+
+ if (pkt.pts != AV_NOPTS_VALUE)
+ *cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q);
+
+ if (!has_start && *cur_ts != AV_NOPTS_VALUE) {
+ start = *cur_ts;
+ has_start = 1;
+ }
+
+ if (has_start && !has_end && interval->end_is_offset) {
+ end = start + interval->end;
+ has_end = 1;
+ }
+
+ if (interval->end_is_offset && interval->duration_frames) {
+ if (frame_count >= interval->end)
+ break;
+ } else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) {
+ break;
+ }
+
+ frame_count++;
+ if (do_read_packets) {
+ if (do_show_packets)
+ show_packet(w, fmt_ctx, &pkt, i++);
+ nb_streams_packets[pkt.stream_index]++;
+ }
+ if (do_read_frames) {
+ pkt1 = pkt;
+ while (pkt1.size && process_frame(w, fmt_ctx, frame, &pkt1) > 0);
+ }
+ }
+ av_free_packet(&pkt);
+ }
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+ //Flush remaining frames that are cached in the decoder
+ for (i = 0; i < fmt_ctx->nb_streams; i++) {
+ pkt.stream_index = i;
+ if (do_read_frames)
+ while (process_frame(w, fmt_ctx, frame, &pkt) > 0);
+ }
+
+end:
+ av_frame_free(&frame);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval ");
+ log_read_interval(interval, NULL, AV_LOG_ERROR);
+ }
+ return ret;
+}
+
+static int read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i, ret = 0;
+ int64_t cur_ts = fmt_ctx->start_time;
+
+ if (read_intervals_nb == 0) {
+ ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
+ ret = read_interval_packets(w, fmt_ctx, &interval, &cur_ts);
+ } else {
+ for (i = 0; i < read_intervals_nb; i++) {
+ ret = read_interval_packets(w, fmt_ctx, &read_intervals[i], &cur_ts);
+ if (ret < 0)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, int in_program)
+{
+ AVStream *stream = fmt_ctx->streams[stream_idx];
+ AVCodecContext *dec_ctx;
+ const AVCodec *dec;
+ char val_str[128];
+ const char *s;
+ AVRational sar, dar;
+ AVBPrint pbuf;
+ const AVCodecDescriptor *cd;
+ int ret = 0;
+
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
+
+ print_int("index", stream->index);
+
+ if ((dec_ctx = stream->codec)) {
+ const char *profile = NULL;
+ dec = dec_ctx->codec;
+ if (dec) {
+ print_str("codec_name", dec->name);
+ if (!do_bitexact) {
+ if (dec->long_name) print_str ("codec_long_name", dec->long_name);
+ else print_str_opt("codec_long_name", "unknown");
+ }
+ } else if ((cd = avcodec_descriptor_get(stream->codec->codec_id))) {
+ print_str_opt("codec_name", cd->name);
+ if (!do_bitexact) {
+ print_str_opt("codec_long_name",
+ cd->long_name ? cd->long_name : "unknown");
+ }
+ } else {
+ print_str_opt("codec_name", "unknown");
+ if (!do_bitexact) {
+ print_str_opt("codec_long_name", "unknown");
+ }
+ }
+
+ if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
+ print_str("profile", profile);
+ else
+ print_str_opt("profile", "unknown");
+
+ s = av_get_media_type_string(dec_ctx->codec_type);
+ if (s) print_str ("codec_type", s);
+ else print_str_opt("codec_type", "unknown");
+ print_q("codec_time_base", dec_ctx->time_base, '/');
+
+ /* print AVI/FourCC tag */
+ av_get_codec_tag_string(val_str, sizeof(val_str), dec_ctx->codec_tag);
+ print_str("codec_tag_string", val_str);
+ print_fmt("codec_tag", "0x%04x", dec_ctx->codec_tag);
+
+ switch (dec_ctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ print_int("width", dec_ctx->width);
+ print_int("height", dec_ctx->height);
+ print_int("coded_width", dec_ctx->coded_width);
+ print_int("coded_height", dec_ctx->coded_height);
+ print_int("has_b_frames", dec_ctx->has_b_frames);
+ sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL);
+ if (sar.den) {
+ print_q("sample_aspect_ratio", sar, ':');
+ av_reduce(&dar.num, &dar.den,
+ dec_ctx->width * sar.num,
+ dec_ctx->height * sar.den,
+ 1024*1024);
+ print_q("display_aspect_ratio", dar, ':');
+ } else {
+ print_str_opt("sample_aspect_ratio", "N/A");
+ print_str_opt("display_aspect_ratio", "N/A");
+ }
+ s = av_get_pix_fmt_name(dec_ctx->pix_fmt);
+ if (s) print_str ("pix_fmt", s);
+ else print_str_opt("pix_fmt", "unknown");
+ print_int("level", dec_ctx->level);
+ if (dec_ctx->color_range != AVCOL_RANGE_UNSPECIFIED)
+ print_str ("color_range", av_color_range_name(dec_ctx->color_range));
+ else
+ print_str_opt("color_range", "N/A");
+ s = av_get_colorspace_name(dec_ctx->colorspace);
+ if (s) print_str ("color_space", s);
+ else print_str_opt("color_space", "unknown");
+
+ if (dec_ctx->color_trc != AVCOL_TRC_UNSPECIFIED)
+ print_str("color_transfer", av_color_transfer_name(dec_ctx->color_trc));
+ else
+ print_str_opt("color_transfer", av_color_transfer_name(dec_ctx->color_trc));
+
+ if (dec_ctx->color_primaries != AVCOL_PRI_UNSPECIFIED)
+ print_str("color_primaries", av_color_primaries_name(dec_ctx->color_primaries));
+ else
+ print_str_opt("color_primaries", av_color_primaries_name(dec_ctx->color_primaries));
+
+ if (dec_ctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
+ print_str("chroma_location", av_chroma_location_name(dec_ctx->chroma_sample_location));
+ else
+ print_str_opt("chroma_location", av_chroma_location_name(dec_ctx->chroma_sample_location));
+
+ if (dec_ctx->timecode_frame_start >= 0) {
+ char tcbuf[AV_TIMECODE_STR_SIZE];
+ av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start);
+ print_str("timecode", tcbuf);
+ } else {
+ print_str_opt("timecode", "N/A");
+ }
+ print_int("refs", dec_ctx->refs);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ s = av_get_sample_fmt_name(dec_ctx->sample_fmt);
+ if (s) print_str ("sample_fmt", s);
+ else print_str_opt("sample_fmt", "unknown");
+ print_val("sample_rate", dec_ctx->sample_rate, unit_hertz_str);
+ print_int("channels", dec_ctx->channels);
+
+ if (dec_ctx->channel_layout) {
+ av_bprint_clear(&pbuf);
+ av_bprint_channel_layout(&pbuf, dec_ctx->channels, dec_ctx->channel_layout);
+ print_str ("channel_layout", pbuf.str);
+ } else {
+ print_str_opt("channel_layout", "unknown");
+ }
+
+ print_int("bits_per_sample", av_get_bits_per_sample(dec_ctx->codec_id));
+ break;
+
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (dec_ctx->width)
+ print_int("width", dec_ctx->width);
+ else
+ print_str_opt("width", "N/A");
+ if (dec_ctx->height)
+ print_int("height", dec_ctx->height);
+ else
+ print_str_opt("height", "N/A");
+ break;
+ }
+ } else {
+ print_str_opt("codec_type", "unknown");
+ }
+ if (dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) {
+ const AVOption *opt = NULL;
+ while (opt = av_opt_next(dec_ctx->priv_data,opt)) {
+ uint8_t *str;
+ if (opt->flags) continue;
+ if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) {
+ print_str(opt->name, str);
+ av_free(str);
+ }
+ }
+ }
+
+ if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id);
+ else print_str_opt("id", "N/A");
+ print_q("r_frame_rate", stream->r_frame_rate, '/');
+ print_q("avg_frame_rate", stream->avg_frame_rate, '/');
+ print_q("time_base", stream->time_base, '/');
+ print_ts ("start_pts", stream->start_time);
+ print_time("start_time", stream->start_time, &stream->time_base);
+ print_ts ("duration_ts", stream->duration);
+ print_time("duration", stream->duration, &stream->time_base);
+ if (dec_ctx->bit_rate > 0) print_val ("bit_rate", dec_ctx->bit_rate, unit_bit_per_second_str);
+ else print_str_opt("bit_rate", "N/A");
+ if (dec_ctx->rc_max_rate > 0) print_val ("max_bit_rate", dec_ctx->rc_max_rate, unit_bit_per_second_str);
+ else print_str_opt("max_bit_rate", "N/A");
+ if (dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample);
+ else print_str_opt("bits_per_raw_sample", "N/A");
+ if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames);
+ else print_str_opt("nb_frames", "N/A");
+ if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]);
+ else print_str_opt("nb_read_frames", "N/A");
+ if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]);
+ else print_str_opt("nb_read_packets", "N/A");
+ if (do_show_data)
+ writer_print_data(w, "extradata", dec_ctx->extradata,
+ dec_ctx->extradata_size);
+ writer_print_data_hash(w, "extradata_hash", dec_ctx->extradata,
+ dec_ctx->extradata_size);
+
+ /* Print disposition information */
+#define PRINT_DISPOSITION(flagname, name) do { \
+ print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \
+ } while (0)
+
+ if (do_show_stream_disposition) {
+ writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
+ PRINT_DISPOSITION(DEFAULT, "default");
+ PRINT_DISPOSITION(DUB, "dub");
+ PRINT_DISPOSITION(ORIGINAL, "original");
+ PRINT_DISPOSITION(COMMENT, "comment");
+ PRINT_DISPOSITION(LYRICS, "lyrics");
+ PRINT_DISPOSITION(KARAOKE, "karaoke");
+ PRINT_DISPOSITION(FORCED, "forced");
+ PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired");
+ PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired");
+ PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects");
+ PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic");
+ writer_print_section_footer(w);
+ }
+
+ if (do_show_stream_tags)
+ ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
+
+ if (stream->nb_side_data) {
+ int i;
+ writer_print_section_header(w, SECTION_ID_STREAM_SIDE_DATA_LIST);
+ for (i = 0; i < stream->nb_side_data; i++) {
+ AVPacketSideData *sd = &stream->side_data[i];
+ const char *name = av_packet_side_data_name(sd->type);
+
+ writer_print_section_header(w, SECTION_ID_STREAM_SIDE_DATA);
+ print_str("side_data_type", name ? name : "unknown");
+ print_int("side_data_size", sd->size);
+ if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
+ writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
+ print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+
+ writer_print_section_footer(w);
+ av_bprint_finalize(&pbuf, NULL);
+ fflush(stdout);
+
+ return ret;
+}
+
+static int show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_STREAMS);
+ for (i = 0; i < fmt_ctx->nb_streams; i++)
+ if (selected_streams[i]) {
+ ret = show_stream(w, fmt_ctx, i, 0);
+ if (ret < 0)
+ break;
+ }
+ writer_print_section_footer(w);
+
+ return ret;
+}
+
+static int show_program(WriterContext *w, AVFormatContext *fmt_ctx, AVProgram *program)
+{
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_PROGRAM);
+ print_int("program_id", program->id);
+ print_int("program_num", program->program_num);
+ print_int("nb_streams", program->nb_stream_indexes);
+ print_int("pmt_pid", program->pmt_pid);
+ print_int("pcr_pid", program->pcr_pid);
+ print_ts("start_pts", program->start_time);
+ print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
+ print_ts("end_pts", program->end_time);
+ print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
+ if (do_show_program_tags)
+ ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
+ if (ret < 0)
+ goto end;
+
+ writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
+ for (i = 0; i < program->nb_stream_indexes; i++) {
+ if (selected_streams[program->stream_index[i]]) {
+ ret = show_stream(w, fmt_ctx, program->stream_index[i], 1);
+ if (ret < 0)
+ break;
+ }
+ }
+ writer_print_section_footer(w);
+
+end:
+ writer_print_section_footer(w);
+ return ret;
+}
+
+static int show_programs(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_PROGRAMS);
+ for (i = 0; i < fmt_ctx->nb_programs; i++) {
+ AVProgram *program = fmt_ctx->programs[i];
+ if (!program)
+ continue;
+ ret = show_program(w, fmt_ctx, program);
+ if (ret < 0)
+ break;
+ }
+ writer_print_section_footer(w);
+ return ret;
+}
+
+static int show_chapters(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ int i, ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_CHAPTERS);
+ for (i = 0; i < fmt_ctx->nb_chapters; i++) {
+ AVChapter *chapter = fmt_ctx->chapters[i];
+
+ writer_print_section_header(w, SECTION_ID_CHAPTER);
+ print_int("id", chapter->id);
+ print_q ("time_base", chapter->time_base, '/');
+ print_int("start", chapter->start);
+ print_time("start_time", chapter->start, &chapter->time_base);
+ print_int("end", chapter->end);
+ print_time("end_time", chapter->end, &chapter->time_base);
+ if (do_show_chapter_tags)
+ ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+
+ return ret;
+}
+
+static int show_format(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+ char val_str[128];
+ int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1;
+ int ret = 0;
+
+ writer_print_section_header(w, SECTION_ID_FORMAT);
+ print_str_validate("filename", fmt_ctx->filename);
+ print_int("nb_streams", fmt_ctx->nb_streams);
+ print_int("nb_programs", fmt_ctx->nb_programs);
+ print_str("format_name", fmt_ctx->iformat->name);
+ if (!do_bitexact) {
+ if (fmt_ctx->iformat->long_name) print_str ("format_long_name", fmt_ctx->iformat->long_name);
+ else print_str_opt("format_long_name", "unknown");
+ }
+ print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
+ print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
+ if (size >= 0) print_val ("size", size, unit_byte_str);
+ else print_str_opt("size", "N/A");
+ if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
+ else print_str_opt("bit_rate", "N/A");
+ print_int("probe_score", av_format_get_probe_score(fmt_ctx));
+ if (do_show_format_tags)
+ ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS);
+
+ writer_print_section_footer(w);
+ fflush(stdout);
+ return ret;
+}
+
+static void show_error(WriterContext *w, int err)
+{
+ char errbuf[128];
+ const char *errbuf_ptr = errbuf;
+
+ if (av_strerror(err, errbuf, sizeof(errbuf)) < 0)
+ errbuf_ptr = strerror(AVUNERROR(err));
+
+ writer_print_section_header(w, SECTION_ID_ERROR);
+ print_int("code", err);
+ print_str("string", errbuf_ptr);
+ writer_print_section_footer(w);
+}
+
+static int open_input_file(AVFormatContext **fmt_ctx_ptr, const char *filename)
+{
+ int err, i, orig_nb_streams;
+ AVFormatContext *fmt_ctx = NULL;
+ AVDictionaryEntry *t;
+ AVDictionary **opts;
+ int scan_all_pmts_set = 0;
+
+ if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
+ av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
+ scan_all_pmts_set = 1;
+ }
+ if ((err = avformat_open_input(&fmt_ctx, filename,
+ iformat, &format_opts)) < 0) {
+ print_error(filename, err);
+ return err;
+ }
+ *fmt_ctx_ptr = fmt_ctx;
+ if (scan_all_pmts_set)
+ av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE);
+ 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);
+ return AVERROR_OPTION_NOT_FOUND;
+ }
+
+ /* fill the streams in the format context */
+ opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
+ orig_nb_streams = fmt_ctx->nb_streams;
+
+ err = avformat_find_stream_info(fmt_ctx, opts);
+
+ for (i = 0; i < orig_nb_streams; i++)
+ av_dict_free(&opts[i]);
+ av_freep(&opts);
+
+ if (err < 0) {
+ print_error(filename, err);
+ return err;
+ }
+
+ av_dump_format(fmt_ctx, 0, filename, 0);
+
+ /* bind a decoder to each input stream */
+ for (i = 0; i < fmt_ctx->nb_streams; i++) {
+ AVStream *stream = fmt_ctx->streams[i];
+ AVCodec *codec;
+
+ if (stream->codec->codec_id == AV_CODEC_ID_PROBE) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Failed to probe codec for input stream %d\n",
+ stream->index);
+ } else if (!(codec = avcodec_find_decoder(stream->codec->codec_id))) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Unsupported codec with id %d for input stream %d\n",
+ stream->codec->codec_id, stream->index);
+ } else {
+ AVDictionary *opts = filter_codec_opts(codec_opts, stream->codec->codec_id,
+ fmt_ctx, stream, codec);
+ if (avcodec_open2(stream->codec, codec, &opts) < 0) {
+ av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n",
+ stream->index);
+ }
+ if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
+ av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n",
+ t->key, stream->index);
+ return AVERROR_OPTION_NOT_FOUND;
+ }
+ }
+ }
+
+ *fmt_ctx_ptr = fmt_ctx;
+ return 0;
+}
+
+static void close_input_file(AVFormatContext **ctx_ptr)
+{
+ int i;
+ AVFormatContext *fmt_ctx = *ctx_ptr;
+
+ /* close decoder for each stream */
+ for (i = 0; i < fmt_ctx->nb_streams; i++)
+ if (fmt_ctx->streams[i]->codec->codec_id != AV_CODEC_ID_NONE)
+ avcodec_close(fmt_ctx->streams[i]->codec);
+
+ avformat_close_input(ctx_ptr);
+}
+
+static int probe_file(WriterContext *wctx, const char *filename)
+{
+ AVFormatContext *fmt_ctx = NULL;
+ int ret, i;
+ int section_id;
+
+ do_read_frames = do_show_frames || do_count_frames;
+ do_read_packets = do_show_packets || do_count_packets;
+
+ ret = open_input_file(&fmt_ctx, filename);
+ if (ret < 0)
+ goto end;
+
+#define CHECK_END if (ret < 0) goto end
+
+ nb_streams = fmt_ctx->nb_streams;
+ REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,fmt_ctx->nb_streams);
+ REALLOCZ_ARRAY_STREAM(selected_streams,0,fmt_ctx->nb_streams);
+
+ for (i = 0; i < fmt_ctx->nb_streams; i++) {
+ if (stream_specifier) {
+ ret = avformat_match_stream_specifier(fmt_ctx,
+ fmt_ctx->streams[i],
+ stream_specifier);
+ CHECK_END;
+ else
+ selected_streams[i] = ret;
+ ret = 0;
+ } else {
+ selected_streams[i] = 1;
+ }
+ }
+
+ if (do_read_frames || do_read_packets) {
+ if (do_show_frames && do_show_packets &&
+ wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER)
+ section_id = SECTION_ID_PACKETS_AND_FRAMES;
+ else if (do_show_packets && !do_show_frames)
+ section_id = SECTION_ID_PACKETS;
+ else // (!do_show_packets && do_show_frames)
+ section_id = SECTION_ID_FRAMES;
+ if (do_show_frames || do_show_packets)
+ writer_print_section_header(wctx, section_id);
+ ret = read_packets(wctx, fmt_ctx);
+ if (do_show_frames || do_show_packets)
+ writer_print_section_footer(wctx);
+ CHECK_END;
+ }
+
+ if (do_show_programs) {
+ ret = show_programs(wctx, fmt_ctx);
+ CHECK_END;
+ }
+
+ if (do_show_streams) {
+ ret = show_streams(wctx, fmt_ctx);
+ CHECK_END;
+ }
+ if (do_show_chapters) {
+ ret = show_chapters(wctx, fmt_ctx);
+ CHECK_END;
+ }
+ if (do_show_format) {
+ ret = show_format(wctx, fmt_ctx);
+ CHECK_END;
+ }
+
+end:
+ if (fmt_ctx)
+ close_input_file(&fmt_ctx);
+ av_freep(&nb_streams_frames);
+ av_freep(&nb_streams_packets);
+ av_freep(&selected_streams);
+
+ return ret;
+}
+
+static void show_usage(void)
+{
+ av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n");
+ av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name);
+ av_log(NULL, AV_LOG_INFO, "\n");
+}
+
+static void ffprobe_show_program_version(WriterContext *w)
+{
+ AVBPrint pbuf;
+ av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+
+ writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION);
+ print_str("version", FFMPEG_VERSION);
+ print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers",
+ program_birth_year, CONFIG_THIS_YEAR);
+ print_str("compiler_ident", CC_IDENT);
+ print_str("configuration", FFMPEG_CONFIGURATION);
+ writer_print_section_footer(w);
+
+ av_bprint_finalize(&pbuf, NULL);
+}
+
+#define SHOW_LIB_VERSION(libname, LIBNAME) \
+ do { \
+ if (CONFIG_##LIBNAME) { \
+ unsigned int version = libname##_version(); \
+ writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \
+ print_str("name", "lib" #libname); \
+ print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \
+ print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \
+ print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \
+ print_int("version", version); \
+ print_str("ident", LIB##LIBNAME##_IDENT); \
+ writer_print_section_footer(w); \
+ } \
+ } while (0)
+
+static void ffprobe_show_library_versions(WriterContext *w)
+{
+ writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS);
+ SHOW_LIB_VERSION(avutil, AVUTIL);
+ SHOW_LIB_VERSION(avcodec, AVCODEC);
+ SHOW_LIB_VERSION(avformat, AVFORMAT);
+ SHOW_LIB_VERSION(avdevice, AVDEVICE);
+ SHOW_LIB_VERSION(avfilter, AVFILTER);
+ SHOW_LIB_VERSION(swscale, SWSCALE);
+ SHOW_LIB_VERSION(swresample, SWRESAMPLE);
+ SHOW_LIB_VERSION(postproc, POSTPROC);
+ writer_print_section_footer(w);
+}
+
+#define PRINT_PIX_FMT_FLAG(flagname, name) \
+ do { \
+ print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \
+ } while (0)
+
+static void ffprobe_show_pixel_formats(WriterContext *w)
+{
+ const AVPixFmtDescriptor *pixdesc = NULL;
+ int i, n;
+
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS);
+ while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT);
+ print_str("name", pixdesc->name);
+ print_int("nb_components", pixdesc->nb_components);
+ if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) {
+ print_int ("log2_chroma_w", pixdesc->log2_chroma_w);
+ print_int ("log2_chroma_h", pixdesc->log2_chroma_h);
+ } else {
+ print_str_opt("log2_chroma_w", "N/A");
+ print_str_opt("log2_chroma_h", "N/A");
+ }
+ n = av_get_bits_per_pixel(pixdesc);
+ if (n) print_int ("bits_per_pixel", n);
+ else print_str_opt("bits_per_pixel", "N/A");
+ if (do_show_pixel_format_flags) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS);
+ PRINT_PIX_FMT_FLAG(BE, "big_endian");
+ PRINT_PIX_FMT_FLAG(PAL, "palette");
+ PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream");
+ PRINT_PIX_FMT_FLAG(HWACCEL, "hwaccel");
+ PRINT_PIX_FMT_FLAG(PLANAR, "planar");
+ PRINT_PIX_FMT_FLAG(RGB, "rgb");
+ PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal");
+ PRINT_PIX_FMT_FLAG(ALPHA, "alpha");
+ writer_print_section_footer(w);
+ }
+ if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS);
+ for (i = 0; i < pixdesc->nb_components; i++) {
+ writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
+ print_int("index", i + 1);
+ print_int("bit_depth", pixdesc->comp[i].depth_minus1 + 1);
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+ }
+ writer_print_section_footer(w);
+}
+
+static int opt_format(void *optctx, const char *opt, const char *arg)
+{
+ iformat = av_find_input_format(arg);
+ if (!iformat) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static inline void mark_section_show_entries(SectionID section_id,
+ int show_all_entries, AVDictionary *entries)
+{
+ struct section *section = &sections[section_id];
+
+ section->show_all_entries = show_all_entries;
+ if (show_all_entries) {
+ SectionID *id;
+ for (id = section->children_ids; *id != -1; id++)
+ mark_section_show_entries(*id, show_all_entries, entries);
+ } else {
+ av_dict_copy(&section->entries_to_show, entries, 0);
+ }
+}
+
+static int match_section(const char *section_name,
+ int show_all_entries, AVDictionary *entries)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
+ const struct section *section = &sections[i];
+ if (!strcmp(section_name, section->name) ||
+ (section->unique_name && !strcmp(section_name, section->unique_name))) {
+ av_log(NULL, AV_LOG_DEBUG,
+ "'%s' matches section with unique name '%s'\n", section_name,
+ (char *)av_x_if_null(section->unique_name, section->name));
+ ret++;
+ mark_section_show_entries(section->id, show_all_entries, entries);
+ }
+ }
+ return ret;
+}
+
+static int opt_show_entries(void *optctx, const char *opt, const char *arg)
+{
+ const char *p = arg;
+ int ret = 0;
+
+ while (*p) {
+ AVDictionary *entries = NULL;
+ char *section_name = av_get_token(&p, "=:");
+ int show_all_entries = 0;
+
+ if (!section_name) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Missing section name for option '%s'\n", opt);
+ return AVERROR(EINVAL);
+ }
+
+ if (*p == '=') {
+ p++;
+ while (*p && *p != ':') {
+ char *entry = av_get_token(&p, ",:");
+ if (!entry)
+ break;
+ av_log(NULL, AV_LOG_VERBOSE,
+ "Adding '%s' to the entries to show in section '%s'\n",
+ entry, section_name);
+ av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
+ if (*p == ',')
+ p++;
+ }
+ } else {
+ show_all_entries = 1;
+ }
+
+ ret = match_section(section_name, show_all_entries, entries);
+ if (ret == 0) {
+ av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
+ ret = AVERROR(EINVAL);
+ }
+ av_dict_free(&entries);
+ av_free(section_name);
+
+ if (ret <= 0)
+ break;
+ if (*p)
+ p++;
+ }
+
+ return ret;
+}
+
+static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
+{
+ char *buf = av_asprintf("format=%s", arg);
+ int ret;
+
+ av_log(NULL, AV_LOG_WARNING,
+ "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
+ opt, arg);
+ ret = opt_show_entries(optctx, opt, buf);
+ av_free(buf);
+ return ret;
+}
+
+static void opt_input_file(void *optctx, const char *arg)
+{
+ if (input_filename) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Argument '%s' provided as input filename, but '%s' was already specified.\n",
+ arg, input_filename);
+ exit_program(1);
+ }
+ if (!strcmp(arg, "-"))
+ arg = "pipe:";
+ input_filename = arg;
+}
+
+static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
+{
+ opt_input_file(optctx, arg);
+ return 0;
+}
+
+void show_help_default(const char *opt, const char *arg)
+{
+ av_log_set_callback(log_callback_help);
+ show_usage();
+ show_help_options(options, "Main options:", 0, 0, 0);
+ printf("\n");
+
+ show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
+}
+
+/**
+ * Parse interval specification, according to the format:
+ * INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]]
+ * INTERVALS ::= INTERVAL[,INTERVALS]
+*/
+static int parse_read_interval(const char *interval_spec,
+ ReadInterval *interval)
+{
+ int ret = 0;
+ char *next, *p, *spec = av_strdup(interval_spec);
+ if (!spec)
+ return AVERROR(ENOMEM);
+
+ if (!*spec) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid empty interval specification\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ p = spec;
+ next = strchr(spec, '%');
+ if (next)
+ *next++ = 0;
+
+ /* parse first part */
+ if (*p) {
+ interval->has_start = 1;
+
+ if (*p == '+') {
+ interval->start_is_offset = 1;
+ p++;
+ } else {
+ interval->start_is_offset = 0;
+ }
+
+ ret = av_parse_time(&interval->start, p, 1);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid interval start specification '%s'\n", p);
+ goto end;
+ }
+ } else {
+ interval->has_start = 0;
+ }
+
+ /* parse second part */
+ p = next;
+ if (p && *p) {
+ int64_t us;
+ interval->has_end = 1;
+
+ if (*p == '+') {
+ interval->end_is_offset = 1;
+ p++;
+ } else {
+ interval->end_is_offset = 0;
+ }
+
+ if (interval->end_is_offset && *p == '#') {
+ long long int lli;
+ char *tail;
+ interval->duration_frames = 1;
+ p++;
+ lli = strtoll(p, &tail, 10);
+ if (*tail || lli < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid or negative value '%s' for duration number of frames\n", p);
+ goto end;
+ }
+ interval->end = lli;
+ } else {
+ ret = av_parse_time(&us, p, 1);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid interval end/duration specification '%s'\n", p);
+ goto end;
+ }
+ interval->end = us;
+ }
+ } else {
+ interval->has_end = 0;
+ }
+
+end:
+ av_free(spec);
+ return ret;
+}
+
+static int parse_read_intervals(const char *intervals_spec)
+{
+ int ret, n, i;
+ char *p, *spec = av_strdup(intervals_spec);
+ if (!spec)
+ return AVERROR(ENOMEM);
+
+ /* preparse specification, get number of intervals */
+ for (n = 0, p = spec; *p; p++)
+ if (*p == ',')
+ n++;
+ n++;
+
+ read_intervals = av_malloc_array(n, sizeof(*read_intervals));
+ if (!read_intervals) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ read_intervals_nb = n;
+
+ /* parse intervals */
+ p = spec;
+ for (i = 0; p; i++) {
+ char *next;
+
+ av_assert0(i < read_intervals_nb);
+ next = strchr(p, ',');
+ if (next)
+ *next++ = 0;
+
+ read_intervals[i].id = i;
+ ret = parse_read_interval(p, &read_intervals[i]);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error parsing read interval #%d '%s'\n",
+ i, p);
+ goto end;
+ }
+ av_log(NULL, AV_LOG_VERBOSE, "Parsed log interval ");
+ log_read_interval(&read_intervals[i], NULL, AV_LOG_VERBOSE);
+ p = next;
+ }
+ av_assert0(i == read_intervals_nb);
+
+end:
+ av_free(spec);
+ return ret;
+}
+
+static int opt_read_intervals(void *optctx, const char *opt, const char *arg)
+{
+ return parse_read_intervals(arg);
+}
+
+static int opt_pretty(void *optctx, const char *opt, const char *arg)
+{
+ show_value_unit = 1;
+ use_value_prefix = 1;
+ use_byte_value_binary_prefix = 1;
+ use_value_sexagesimal_format = 1;
+ return 0;
+}
+
+static void print_section(SectionID id, int level)
+{
+ const SectionID *pid;
+ const struct section *section = &sections[id];
+ printf("%c%c%c",
+ section->flags & SECTION_FLAG_IS_WRAPPER ? 'W' : '.',
+ section->flags & SECTION_FLAG_IS_ARRAY ? 'A' : '.',
+ section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS ? 'V' : '.');
+ printf("%*c %s", level * 4, ' ', section->name);
+ if (section->unique_name)
+ printf("/%s", section->unique_name);
+ printf("\n");
+
+ for (pid = section->children_ids; *pid != -1; pid++)
+ print_section(*pid, level+1);
+}
+
+static int opt_sections(void *optctx, const char *opt, const char *arg)
+{
+ printf("Sections:\n"
+ "W.. = Section is a wrapper (contains other sections, no local entries)\n"
+ ".A. = Section contains an array of elements of the same type\n"
+ "..V = Section may contain a variable number of fields with variable keys\n"
+ "FLAGS NAME/UNIQUE_NAME\n"
+ "---\n");
+ print_section(SECTION_ID_ROOT, 0);
+ return 0;
+}
+
+static int opt_show_versions(const char *opt, const char *arg)
+{
+ mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
+ mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);
+ return 0;
+}
+
+#define DEFINE_OPT_SHOW_SECTION(section, target_section_id) \
+ static int opt_show_##section(const char *opt, const char *arg) \
+ { \
+ mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
+ return 0; \
+ }
+
+DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS);
+DEFINE_OPT_SHOW_SECTION(error, ERROR);
+DEFINE_OPT_SHOW_SECTION(format, FORMAT);
+DEFINE_OPT_SHOW_SECTION(frames, FRAMES);
+DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
+DEFINE_OPT_SHOW_SECTION(packets, PACKETS);
+DEFINE_OPT_SHOW_SECTION(pixel_formats, PIXEL_FORMATS);
+DEFINE_OPT_SHOW_SECTION(program_version, PROGRAM_VERSION);
+DEFINE_OPT_SHOW_SECTION(streams, STREAMS);
+DEFINE_OPT_SHOW_SECTION(programs, PROGRAMS);
+
+static const OptionDef real_options[] = {
+#include "cmdutils_common_opts.h"
+ { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
+ { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
+ { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
+ { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
+ "use binary prefixes for byte units" },
+ { "sexagesimal", OPT_BOOL, {&use_value_sexagesimal_format},
+ "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
+ { "pretty", 0, {.func_arg = opt_pretty},
+ "prettify the format of displayed values, make it more human readable" },
+ { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
+ "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
+ { "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
+ { "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
+ { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
+ { "show_data", OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
+ { "show_data_hash", OPT_STRING | HAS_ARG, {(void*)&show_data_hash}, "show packets data hash" },
+ { "show_error", 0, {(void*)&opt_show_error}, "show probing error" },
+ { "show_format", 0, {(void*)&opt_show_format}, "show format/container info" },
+ { "show_frames", 0, {(void*)&opt_show_frames}, "show frames info" },
+ { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
+ "show a particular entry from the format/container info", "entry" },
+ { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
+ "show a set of specified entries", "entry_list" },
+ { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
+ { "show_programs", 0, {(void*)&opt_show_programs}, "show programs info" },
+ { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
+ { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
+ { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
+ { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
+ { "show_program_version", 0, {(void*)&opt_show_program_version}, "show ffprobe version" },
+ { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
+ { "show_versions", 0, {(void*)&opt_show_versions}, "show program and library versions" },
+ { "show_pixel_formats", 0, {(void*)&opt_show_pixel_formats}, "show pixel format descriptions" },
+ { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
+ { "private", OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
+ { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
+ { "read_intervals", HAS_ARG, {.func_arg = opt_read_intervals}, "set read intervals", "read_intervals" },
+ { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default}, "generic catch all option", "" },
+ { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
+ { NULL, },
+};
+
+static inline int check_section_show_entries(int section_id)
+{
+ int *id;
+ struct section *section = &sections[section_id];
+ if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
+ return 1;
+ for (id = section->children_ids; *id != -1; id++)
+ if (check_section_show_entries(*id))
+ return 1;
+ return 0;
+}
+
+#define SET_DO_SHOW(id, varname) do { \
+ if (check_section_show_entries(SECTION_ID_##id)) \
+ do_show_##varname = 1; \
+ } while (0)
+
+int main(int argc, char **argv)
+{
+ const Writer *w;
+ WriterContext *wctx;
+ char *buf;
+ char *w_name = NULL, *w_args = NULL;
+ int ret, i;
+
+ av_log_set_flags(AV_LOG_SKIP_REPEATED);
+ register_exit(ffprobe_cleanup);
+
+ options = real_options;
+ parse_loglevel(argc, argv, options);
+ av_register_all();
+ avformat_network_init();
+ init_opts();
+#if CONFIG_AVDEVICE
+ avdevice_register_all();
+#endif
+
+ show_banner(argc, argv, options);
+ parse_options(NULL, argc, argv, options, opt_input_file);
+
+ /* mark things to show, based on -show_entries */
+ SET_DO_SHOW(CHAPTERS, chapters);
+ SET_DO_SHOW(ERROR, error);
+ SET_DO_SHOW(FORMAT, format);
+ SET_DO_SHOW(FRAMES, frames);
+ SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
+ SET_DO_SHOW(PACKETS, packets);
+ SET_DO_SHOW(PIXEL_FORMATS, pixel_formats);
+ SET_DO_SHOW(PIXEL_FORMAT_FLAGS, pixel_format_flags);
+ SET_DO_SHOW(PIXEL_FORMAT_COMPONENTS, pixel_format_components);
+ SET_DO_SHOW(PROGRAM_VERSION, program_version);
+ SET_DO_SHOW(PROGRAMS, programs);
+ SET_DO_SHOW(STREAMS, streams);
+ SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
+ SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
+
+ SET_DO_SHOW(CHAPTER_TAGS, chapter_tags);
+ SET_DO_SHOW(FORMAT_TAGS, format_tags);
+ SET_DO_SHOW(FRAME_TAGS, frame_tags);
+ SET_DO_SHOW(PROGRAM_TAGS, program_tags);
+ SET_DO_SHOW(STREAM_TAGS, stream_tags);
+
+ if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "-bitexact and -show_program_version or -show_library_versions "
+ "options are incompatible\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ writer_register_all();
+
+ if (!print_format)
+ print_format = av_strdup("default");
+ if (!print_format) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ w_name = av_strtok(print_format, "=", &buf);
+ w_args = buf;
+
+ if (show_data_hash) {
+ if ((ret = av_hash_alloc(&hash, show_data_hash)) < 0) {
+ if (ret == AVERROR(EINVAL)) {
+ const char *n;
+ av_log(NULL, AV_LOG_ERROR,
+ "Unknown hash algorithm '%s'\nKnown algorithms:",
+ show_data_hash);
+ for (i = 0; (n = av_hash_names(i)); i++)
+ av_log(NULL, AV_LOG_ERROR, " %s", n);
+ av_log(NULL, AV_LOG_ERROR, "\n");
+ }
+ goto end;
+ }
+ }
+
+ w = writer_get_by_name(w_name);
+ if (!w) {
+ av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ if ((ret = writer_open(&wctx, w, w_args,
+ sections, FF_ARRAY_ELEMS(sections))) >= 0) {
+ if (w == &xml_writer)
+ wctx->string_validation_utf8_flags |= AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES;
+
+ writer_print_section_header(wctx, SECTION_ID_ROOT);
+
+ if (do_show_program_version)
+ ffprobe_show_program_version(wctx);
+ if (do_show_library_versions)
+ ffprobe_show_library_versions(wctx);
+ if (do_show_pixel_formats)
+ ffprobe_show_pixel_formats(wctx);
+
+ if (!input_filename &&
+ ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
+ (!do_show_program_version && !do_show_library_versions && !do_show_pixel_formats))) {
+ show_usage();
+ av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
+ av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
+ ret = AVERROR(EINVAL);
+ } else if (input_filename) {
+ ret = probe_file(wctx, input_filename);
+ if (ret < 0 && do_show_error)
+ show_error(wctx, ret);
+ }
+
+ writer_print_section_footer(wctx);
+ writer_close(&wctx);
+ }
+
+end:
+ av_freep(&print_format);
+ av_freep(&read_intervals);
+ av_hash_freep(&hash);
+
+ uninit_opts();
+ for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
+ av_dict_free(&(sections[i].entries_to_show));
+
+ avformat_network_deinit();
+
+ return ret < 0;
+}
diff --git a/ffserver.c b/ffserver.c
new file mode 100644
index 0000000000..4803b96cd4
--- /dev/null
+++ b/ffserver.c
@@ -0,0 +1,3824 @@
+/*
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * multiple format streaming server based on the FFmpeg libraries
+ */
+
+#include "config.h"
+#if !HAVE_CLOSESOCKET
+#define closesocket close
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "libavformat/avformat.h"
+// FIXME those are internal headers, ffserver _really_ shouldn't use them
+#include "libavformat/ffm.h"
+#include "libavformat/network.h"
+#include "libavformat/os_support.h"
+#include "libavformat/rtpdec.h"
+#include "libavformat/rtpproto.h"
+#include "libavformat/rtsp.h"
+#include "libavformat/rtspcodes.h"
+#include "libavformat/avio_internal.h"
+#include "libavformat/internal.h"
+#include "libavformat/url.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/lfg.h"
+#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/random_seed.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+
+#include <stdarg.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+#include <errno.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "cmdutils.h"
+#include "ffserver_config.h"
+
+const char program_name[] = "ffserver";
+const int program_birth_year = 2000;
+
+static const OptionDef options[];
+
+enum HTTPState {
+ HTTPSTATE_WAIT_REQUEST,
+ HTTPSTATE_SEND_HEADER,
+ HTTPSTATE_SEND_DATA_HEADER,
+ HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
+ HTTPSTATE_SEND_DATA_TRAILER,
+ HTTPSTATE_RECEIVE_DATA,
+ HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
+ HTTPSTATE_READY,
+
+ RTSPSTATE_WAIT_REQUEST,
+ RTSPSTATE_SEND_REPLY,
+ RTSPSTATE_SEND_PACKET,
+};
+
+static const char * const http_state[] = {
+ "HTTP_WAIT_REQUEST",
+ "HTTP_SEND_HEADER",
+
+ "SEND_DATA_HEADER",
+ "SEND_DATA",
+ "SEND_DATA_TRAILER",
+ "RECEIVE_DATA",
+ "WAIT_FEED",
+ "READY",
+
+ "RTSP_WAIT_REQUEST",
+ "RTSP_SEND_REPLY",
+ "RTSP_SEND_PACKET",
+};
+
+#define IOBUFFER_INIT_SIZE 8192
+
+/* timeouts are in ms */
+#define HTTP_REQUEST_TIMEOUT (15 * 1000)
+#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
+
+#define SYNC_TIMEOUT (10 * 1000)
+
+typedef struct RTSPActionServerSetup {
+ uint32_t ipaddr;
+ char transport_option[512];
+} RTSPActionServerSetup;
+
+typedef struct {
+ int64_t count1, count2;
+ int64_t time1, time2;
+} DataRateData;
+
+/* context associated with one connection */
+typedef struct HTTPContext {
+ enum HTTPState state;
+ int fd; /* socket file descriptor */
+ struct sockaddr_in from_addr; /* origin */
+ struct pollfd *poll_entry; /* used when polling */
+ int64_t timeout;
+ uint8_t *buffer_ptr, *buffer_end;
+ int http_error;
+ int post;
+ int chunked_encoding;
+ int chunk_size; /* 0 if it needs to be read */
+ struct HTTPContext *next;
+ int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
+ int64_t data_count;
+ /* feed input */
+ int feed_fd;
+ /* input format handling */
+ AVFormatContext *fmt_in;
+ int64_t start_time; /* In milliseconds - this wraps fairly often */
+ int64_t first_pts; /* initial pts value */
+ int64_t cur_pts; /* current pts value from the stream in us */
+ int64_t cur_frame_duration; /* duration of the current frame in us */
+ int cur_frame_bytes; /* output frame size, needed to compute
+ the time at which we send each
+ packet */
+ int pts_stream_index; /* stream we choose as clock reference */
+ int64_t cur_clock; /* current clock reference value in us */
+ /* output format handling */
+ struct FFServerStream *stream;
+ /* -1 is invalid stream */
+ int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
+ int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
+ int switch_pending;
+ AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
+ int last_packet_sent; /* true if last data packet was sent */
+ int suppress_log;
+ DataRateData datarate;
+ int wmp_client_id;
+ char protocol[16];
+ char method[16];
+ char url[128];
+ int buffer_size;
+ uint8_t *buffer;
+ int is_packetized; /* if true, the stream is packetized */
+ int packet_stream_index; /* current stream for output in state machine */
+
+ /* RTSP state specific */
+ uint8_t *pb_buffer; /* XXX: use that in all the code */
+ AVIOContext *pb;
+ int seq; /* RTSP sequence number */
+
+ /* RTP state specific */
+ enum RTSPLowerTransport rtp_protocol;
+ char session_id[32]; /* session id */
+ AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS];
+
+ /* RTP/UDP specific */
+ URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
+
+ /* RTP/TCP specific */
+ struct HTTPContext *rtsp_c;
+ uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
+} HTTPContext;
+
+typedef struct FeedData {
+ long long data_count;
+ float avg_frame_size; /* frame size averaged over last frames with exponential mean */
+} FeedData;
+
+static HTTPContext *first_http_ctx;
+
+static FFServerConfig config = {
+ .nb_max_http_connections = 2000,
+ .nb_max_connections = 5,
+ .max_bandwidth = 1000,
+ .use_defaults = 1,
+};
+
+static void new_connection(int server_fd, int is_rtsp);
+static void close_connection(HTTPContext *c);
+
+/* HTTP handling */
+static int handle_connection(HTTPContext *c);
+static void compute_status(HTTPContext *c);
+static int open_input_stream(HTTPContext *c, const char *info);
+static int http_parse_request(HTTPContext *c);
+static int http_send_data(HTTPContext *c);
+static int http_start_receive_data(HTTPContext *c);
+static int http_receive_data(HTTPContext *c);
+
+/* RTSP handling */
+static int rtsp_parse_request(HTTPContext *c);
+static void rtsp_cmd_describe(HTTPContext *c, const char *url);
+static void rtsp_cmd_options(HTTPContext *c, const char *url);
+static void rtsp_cmd_setup(HTTPContext *c, const char *url,
+ RTSPMessageHeader *h);
+static void rtsp_cmd_play(HTTPContext *c, const char *url,
+ RTSPMessageHeader *h);
+static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
+ RTSPMessageHeader *h, int pause_only);
+
+/* SDP handling */
+static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
+ struct in_addr my_ip);
+
+/* RTP handling */
+static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
+ FFServerStream *stream,
+ const char *session_id,
+ enum RTSPLowerTransport rtp_protocol);
+static int rtp_new_av_stream(HTTPContext *c,
+ int stream_index, struct sockaddr_in *dest_addr,
+ HTTPContext *rtsp_c);
+
+static const char *my_program_name;
+
+static int no_launch;
+static int need_to_start_children;
+
+/* maximum number of simultaneous HTTP connections */
+static unsigned int nb_connections;
+
+static uint64_t current_bandwidth;
+
+static int64_t cur_time; // Making this global saves on passing it around everywhere
+
+static AVLFG random_state;
+
+static FILE *logfile = NULL;
+
+static void htmlstrip(char *s) {
+ while (s && *s) {
+ s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
+ if (*s)
+ *s++ = '?';
+ }
+}
+
+static int64_t ffm_read_write_index(int fd)
+{
+ uint8_t buf[8];
+
+ if (lseek(fd, 8, SEEK_SET) < 0)
+ return AVERROR(EIO);
+ if (read(fd, buf, 8) != 8)
+ return AVERROR(EIO);
+ return AV_RB64(buf);
+}
+
+static int ffm_write_write_index(int fd, int64_t pos)
+{
+ uint8_t buf[8];
+ int i;
+
+ for(i=0;i<8;i++)
+ buf[i] = (pos >> (56 - i * 8)) & 0xff;
+ if (lseek(fd, 8, SEEK_SET) < 0)
+ return AVERROR(EIO);
+ if (write(fd, buf, 8) != 8)
+ return AVERROR(EIO);
+ return 8;
+}
+
+static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
+ int64_t file_size)
+{
+ FFMContext *ffm = s->priv_data;
+ ffm->write_index = pos;
+ ffm->file_size = file_size;
+}
+
+static char *ctime1(char *buf2, int buf_size)
+{
+ time_t ti;
+ char *p;
+
+ ti = time(NULL);
+ p = ctime(&ti);
+ av_strlcpy(buf2, p, buf_size);
+ p = buf2 + strlen(p) - 1;
+ if (*p == '\n')
+ *p = '\0';
+ return buf2;
+}
+
+static void http_vlog(const char *fmt, va_list vargs)
+{
+ static int print_prefix = 1;
+
+ if (!logfile)
+ return;
+
+ if (print_prefix) {
+ char buf[32];
+ ctime1(buf, sizeof(buf));
+ fprintf(logfile, "%s ", buf);
+ }
+ print_prefix = strstr(fmt, "\n") != NULL;
+ vfprintf(logfile, fmt, vargs);
+ fflush(logfile);
+}
+
+#ifdef __GNUC__
+__attribute__ ((format (printf, 1, 2)))
+#endif
+static void http_log(const char *fmt, ...)
+{
+ va_list vargs;
+ va_start(vargs, fmt);
+ http_vlog(fmt, vargs);
+ va_end(vargs);
+}
+
+static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
+{
+ static int print_prefix = 1;
+ AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
+ if (level > av_log_get_level())
+ return;
+ if (print_prefix && avc)
+ http_log("[%s @ %p]", avc->item_name(ptr), ptr);
+ print_prefix = strstr(fmt, "\n") != NULL;
+ http_vlog(fmt, vargs);
+}
+
+static void log_connection(HTTPContext *c)
+{
+ if (c->suppress_log)
+ return;
+
+ http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
+ inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
+ c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
+}
+
+static void update_datarate(DataRateData *drd, int64_t count)
+{
+ if (!drd->time1 && !drd->count1) {
+ drd->time1 = drd->time2 = cur_time;
+ drd->count1 = drd->count2 = count;
+ } else if (cur_time - drd->time2 > 5000) {
+ drd->time1 = drd->time2;
+ drd->count1 = drd->count2;
+ drd->time2 = cur_time;
+ drd->count2 = count;
+ }
+}
+
+/* In bytes per second */
+static int compute_datarate(DataRateData *drd, int64_t count)
+{
+ if (cur_time == drd->time1)
+ return 0;
+
+ return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
+}
+
+
+static void start_children(FFServerStream *feed)
+{
+ char pathname[1024];
+ char *slash;
+ int i;
+
+ if (no_launch)
+ return;
+
+ /* replace "ffserver" with "ffmpeg" in the path of current
+ * program. Ignore user provided path */
+ av_strlcpy(pathname, my_program_name, sizeof(pathname));
+
+ slash = strrchr(pathname, '/');
+ if (!slash)
+ slash = pathname;
+ else
+ slash++;
+ strcpy(slash, "ffmpeg");
+
+ for (; feed; feed = feed->next) {
+
+ if (!feed->child_argv || feed->pid)
+ continue;
+
+ feed->pid_start = time(0);
+
+ feed->pid = fork();
+ if (feed->pid < 0) {
+ http_log("Unable to create children\n");
+ exit(1);
+ }
+
+ if (feed->pid)
+ continue;
+
+ /* In child */
+
+ http_log("Launch command line: ");
+ http_log("%s ", pathname);
+
+ for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
+ http_log("%s ", feed->child_argv[i]);
+ http_log("\n");
+
+ for (i = 3; i < 256; i++)
+ close(i);
+
+ if (!config.debug) {
+ if (!freopen("/dev/null", "r", stdin))
+ http_log("failed to redirect STDIN to /dev/null\n;");
+ if (!freopen("/dev/null", "w", stdout))
+ http_log("failed to redirect STDOUT to /dev/null\n;");
+ if (!freopen("/dev/null", "w", stderr))
+ http_log("failed to redirect STDERR to /dev/null\n;");
+ }
+
+ signal(SIGPIPE, SIG_DFL);
+ execvp(pathname, feed->child_argv);
+ _exit(1);
+ }
+}
+
+/* open a listening socket */
+static int socket_open_listen(struct sockaddr_in *my_addr)
+{
+ int server_fd, tmp;
+
+ server_fd = socket(AF_INET,SOCK_STREAM,0);
+ if (server_fd < 0) {
+ perror ("socket");
+ return -1;
+ }
+
+ tmp = 1;
+ if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
+ av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
+
+ my_addr->sin_family = AF_INET;
+ if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
+ char bindmsg[32];
+ snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)",
+ ntohs(my_addr->sin_port));
+ perror (bindmsg);
+ closesocket(server_fd);
+ return -1;
+ }
+
+ if (listen (server_fd, 5) < 0) {
+ perror ("listen");
+ closesocket(server_fd);
+ return -1;
+ }
+
+ if (ff_socket_nonblock(server_fd, 1) < 0)
+ av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
+
+ return server_fd;
+}
+
+/* start all multicast streams */
+static void start_multicast(void)
+{
+ FFServerStream *stream;
+ char session_id[32];
+ HTTPContext *rtp_c;
+ struct sockaddr_in dest_addr = {0};
+ int default_port, stream_index;
+ unsigned int random0, random1;
+
+ default_port = 6000;
+ for(stream = config.first_stream; stream; stream = stream->next) {
+
+ if (!stream->is_multicast)
+ continue;
+
+ random0 = av_lfg_get(&random_state);
+ random1 = av_lfg_get(&random_state);
+
+ /* open the RTP connection */
+ snprintf(session_id, sizeof(session_id), "%08x%08x",
+ random0, random1);
+
+ /* choose a port if none given */
+ if (stream->multicast_port == 0) {
+ stream->multicast_port = default_port;
+ default_port += 100;
+ }
+
+ dest_addr.sin_family = AF_INET;
+ dest_addr.sin_addr = stream->multicast_ip;
+ dest_addr.sin_port = htons(stream->multicast_port);
+
+ rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
+ RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
+ if (!rtp_c)
+ continue;
+
+ if (open_input_stream(rtp_c, "") < 0) {
+ http_log("Could not open input stream for stream '%s'\n",
+ stream->filename);
+ continue;
+ }
+
+ /* open each RTP stream */
+ for(stream_index = 0; stream_index < stream->nb_streams;
+ stream_index++) {
+ dest_addr.sin_port = htons(stream->multicast_port +
+ 2 * stream_index);
+ if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0)
+ continue;
+
+ http_log("Could not open output stream '%s/streamid=%d'\n",
+ stream->filename, stream_index);
+ exit(1);
+ }
+
+ rtp_c->state = HTTPSTATE_SEND_DATA;
+ }
+}
+
+/* main loop of the HTTP server */
+static int http_server(void)
+{
+ int server_fd = 0, rtsp_server_fd = 0;
+ int ret, delay;
+ struct pollfd *poll_table, *poll_entry;
+ HTTPContext *c, *c_next;
+
+ poll_table = av_mallocz_array(config.nb_max_http_connections + 2,
+ sizeof(*poll_table));
+ if(!poll_table) {
+ http_log("Impossible to allocate a poll table handling %d "
+ "connections.\n", config.nb_max_http_connections);
+ return -1;
+ }
+
+ if (config.http_addr.sin_port) {
+ server_fd = socket_open_listen(&config.http_addr);
+ if (server_fd < 0) {
+ av_free(poll_table);
+ return -1;
+ }
+ }
+
+ if (config.rtsp_addr.sin_port) {
+ rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
+ if (rtsp_server_fd < 0) {
+ av_free(poll_table);
+ closesocket(server_fd);
+ return -1;
+ }
+ }
+
+ if (!rtsp_server_fd && !server_fd) {
+ http_log("HTTP and RTSP disabled.\n");
+ av_free(poll_table);
+ return -1;
+ }
+
+ http_log("FFserver started.\n");
+
+ start_children(config.first_feed);
+
+ start_multicast();
+
+ for(;;) {
+ poll_entry = poll_table;
+ if (server_fd) {
+ poll_entry->fd = server_fd;
+ poll_entry->events = POLLIN;
+ poll_entry++;
+ }
+ if (rtsp_server_fd) {
+ poll_entry->fd = rtsp_server_fd;
+ poll_entry->events = POLLIN;
+ poll_entry++;
+ }
+
+ /* wait for events on each HTTP handle */
+ c = first_http_ctx;
+ delay = 1000;
+ while (c) {
+ int fd;
+ fd = c->fd;
+ switch(c->state) {
+ case HTTPSTATE_SEND_HEADER:
+ case RTSPSTATE_SEND_REPLY:
+ case RTSPSTATE_SEND_PACKET:
+ c->poll_entry = poll_entry;
+ poll_entry->fd = fd;
+ poll_entry->events = POLLOUT;
+ poll_entry++;
+ break;
+ case HTTPSTATE_SEND_DATA_HEADER:
+ case HTTPSTATE_SEND_DATA:
+ case HTTPSTATE_SEND_DATA_TRAILER:
+ if (!c->is_packetized) {
+ /* for TCP, we output as much as we can
+ * (may need to put a limit) */
+ c->poll_entry = poll_entry;
+ poll_entry->fd = fd;
+ poll_entry->events = POLLOUT;
+ poll_entry++;
+ } else {
+ /* when ffserver is doing the timing, we work by
+ looking at which packet needs to be sent every
+ 10 ms */
+ /* one tick wait XXX: 10 ms assumed */
+ if (delay > 10)
+ delay = 10;
+ }
+ break;
+ case HTTPSTATE_WAIT_REQUEST:
+ case HTTPSTATE_RECEIVE_DATA:
+ case HTTPSTATE_WAIT_FEED:
+ case RTSPSTATE_WAIT_REQUEST:
+ /* need to catch errors */
+ c->poll_entry = poll_entry;
+ poll_entry->fd = fd;
+ poll_entry->events = POLLIN;/* Maybe this will work */
+ poll_entry++;
+ break;
+ default:
+ c->poll_entry = NULL;
+ break;
+ }
+ c = c->next;
+ }
+
+ /* wait for an event on one connection. We poll at least every
+ second to handle timeouts */
+ do {
+ ret = poll(poll_table, poll_entry - poll_table, delay);
+ if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR)) {
+ av_free(poll_table);
+ return -1;
+ }
+ } while (ret < 0);
+
+ cur_time = av_gettime() / 1000;
+
+ if (need_to_start_children) {
+ need_to_start_children = 0;
+ start_children(config.first_feed);
+ }
+
+ /* now handle the events */
+ for(c = first_http_ctx; c; c = c_next) {
+ c_next = c->next;
+ if (handle_connection(c) < 0) {
+ log_connection(c);
+ /* close and free the connection */
+ close_connection(c);
+ }
+ }
+
+ poll_entry = poll_table;
+ if (server_fd) {
+ /* new HTTP connection request ? */
+ if (poll_entry->revents & POLLIN)
+ new_connection(server_fd, 0);
+ poll_entry++;
+ }
+ if (rtsp_server_fd) {
+ /* new RTSP connection request ? */
+ if (poll_entry->revents & POLLIN)
+ new_connection(rtsp_server_fd, 1);
+ }
+ }
+}
+
+/* start waiting for a new HTTP/RTSP request */
+static void start_wait_request(HTTPContext *c, int is_rtsp)
+{
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
+
+ if (is_rtsp) {
+ c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
+ c->state = RTSPSTATE_WAIT_REQUEST;
+ } else {
+ c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
+ c->state = HTTPSTATE_WAIT_REQUEST;
+ }
+}
+
+static void http_send_too_busy_reply(int fd)
+{
+ char buffer[400];
+ int len = snprintf(buffer, sizeof(buffer),
+ "HTTP/1.0 503 Server too busy\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Too busy</title></head><body>\r\n"
+ "<p>The server is too busy to serve your request at this time.</p>\r\n"
+ "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
+ "</body></html>\r\n",
+ nb_connections, config.nb_max_connections);
+ av_assert0(len < sizeof(buffer));
+ if (send(fd, buffer, len, 0) < len)
+ av_log(NULL, AV_LOG_WARNING,
+ "Could not send too-busy reply, send() failed\n");
+}
+
+
+static void new_connection(int server_fd, int is_rtsp)
+{
+ struct sockaddr_in from_addr;
+ socklen_t len;
+ int fd;
+ HTTPContext *c = NULL;
+
+ len = sizeof(from_addr);
+ fd = accept(server_fd, (struct sockaddr *)&from_addr,
+ &len);
+ if (fd < 0) {
+ http_log("error during accept %s\n", strerror(errno));
+ return;
+ }
+ if (ff_socket_nonblock(fd, 1) < 0)
+ av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
+
+ if (nb_connections >= config.nb_max_connections) {
+ http_send_too_busy_reply(fd);
+ goto fail;
+ }
+
+ /* add a new connection */
+ c = av_mallocz(sizeof(HTTPContext));
+ if (!c)
+ goto fail;
+
+ c->fd = fd;
+ c->poll_entry = NULL;
+ c->from_addr = from_addr;
+ c->buffer_size = IOBUFFER_INIT_SIZE;
+ c->buffer = av_malloc(c->buffer_size);
+ if (!c->buffer)
+ goto fail;
+
+ c->next = first_http_ctx;
+ first_http_ctx = c;
+ nb_connections++;
+
+ start_wait_request(c, is_rtsp);
+
+ return;
+
+ fail:
+ if (c) {
+ av_freep(&c->buffer);
+ av_free(c);
+ }
+ closesocket(fd);
+}
+
+static void close_connection(HTTPContext *c)
+{
+ HTTPContext **cp, *c1;
+ int i, nb_streams;
+ AVFormatContext *ctx;
+ URLContext *h;
+ AVStream *st;
+
+ /* remove connection from list */
+ cp = &first_http_ctx;
+ while (*cp) {
+ c1 = *cp;
+ if (c1 == c)
+ *cp = c->next;
+ else
+ cp = &c1->next;
+ }
+
+ /* remove references, if any (XXX: do it faster) */
+ for(c1 = first_http_ctx; c1; c1 = c1->next) {
+ if (c1->rtsp_c == c)
+ c1->rtsp_c = NULL;
+ }
+
+ /* remove connection associated resources */
+ if (c->fd >= 0)
+ closesocket(c->fd);
+ if (c->fmt_in) {
+ /* close each frame parser */
+ for(i=0;i<c->fmt_in->nb_streams;i++) {
+ st = c->fmt_in->streams[i];
+ if (st->codec->codec)
+ avcodec_close(st->codec);
+ }
+ avformat_close_input(&c->fmt_in);
+ }
+
+ /* free RTP output streams if any */
+ nb_streams = 0;
+ if (c->stream)
+ nb_streams = c->stream->nb_streams;
+
+ for(i=0;i<nb_streams;i++) {
+ ctx = c->rtp_ctx[i];
+ if (ctx) {
+ av_write_trailer(ctx);
+ av_dict_free(&ctx->metadata);
+ av_freep(&ctx->streams[0]);
+ av_freep(&ctx);
+ }
+ h = c->rtp_handles[i];
+ if (h)
+ ffurl_close(h);
+ }
+
+ ctx = &c->fmt_ctx;
+
+ if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
+ /* prepare header */
+ if (ctx->oformat && avio_open_dyn_buf(&ctx->pb) >= 0) {
+ av_write_trailer(ctx);
+ av_freep(&c->pb_buffer);
+ avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
+ }
+ }
+
+ for(i=0; i<ctx->nb_streams; i++)
+ av_freep(&ctx->streams[i]);
+ av_freep(&ctx->streams);
+ av_freep(&ctx->priv_data);
+
+ if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
+ current_bandwidth -= c->stream->bandwidth;
+
+ /* signal that there is no feed if we are the feeder socket */
+ if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
+ c->stream->feed_opened = 0;
+ close(c->feed_fd);
+ }
+
+ av_freep(&c->pb_buffer);
+ av_freep(&c->packet_buffer);
+ av_freep(&c->buffer);
+ av_free(c);
+ nb_connections--;
+}
+
+static int handle_connection(HTTPContext *c)
+{
+ int len, ret;
+ uint8_t *ptr;
+
+ switch(c->state) {
+ case HTTPSTATE_WAIT_REQUEST:
+ case RTSPSTATE_WAIT_REQUEST:
+ /* timeout ? */
+ if ((c->timeout - cur_time) < 0)
+ return -1;
+ if (c->poll_entry->revents & (POLLERR | POLLHUP))
+ return -1;
+
+ /* no need to read if no events */
+ if (!(c->poll_entry->revents & POLLIN))
+ return 0;
+ /* read the data */
+ read_loop:
+ if (!(len = recv(c->fd, c->buffer_ptr, 1, 0)))
+ return -1;
+
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR))
+ return -1;
+ break;
+ }
+ /* search for end of request. */
+ c->buffer_ptr += len;
+ ptr = c->buffer_ptr;
+ if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
+ (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
+ /* request found : parse it and reply */
+ if (c->state == HTTPSTATE_WAIT_REQUEST) {
+ ret = http_parse_request(c);
+ } else {
+ ret = rtsp_parse_request(c);
+ }
+ if (ret < 0)
+ return -1;
+ } else if (ptr >= c->buffer_end) {
+ /* request too long: cannot do anything */
+ return -1;
+ } else goto read_loop;
+
+ break;
+
+ case HTTPSTATE_SEND_HEADER:
+ if (c->poll_entry->revents & (POLLERR | POLLHUP))
+ return -1;
+
+ /* no need to write if no events */
+ if (!(c->poll_entry->revents & POLLOUT))
+ return 0;
+ len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR)) {
+ goto close_connection;
+ }
+ break;
+ }
+ c->buffer_ptr += len;
+ if (c->stream)
+ c->stream->bytes_served += len;
+ c->data_count += len;
+ if (c->buffer_ptr >= c->buffer_end) {
+ av_freep(&c->pb_buffer);
+ /* if error, exit */
+ if (c->http_error)
+ return -1;
+ /* all the buffer was sent : synchronize to the incoming
+ * stream */
+ c->state = HTTPSTATE_SEND_DATA_HEADER;
+ c->buffer_ptr = c->buffer_end = c->buffer;
+ }
+ break;
+
+ case HTTPSTATE_SEND_DATA:
+ case HTTPSTATE_SEND_DATA_HEADER:
+ case HTTPSTATE_SEND_DATA_TRAILER:
+ /* for packetized output, we consider we can always write (the
+ input streams set the speed). It may be better to verify
+ that we do not rely too much on the kernel queues */
+ if (!c->is_packetized) {
+ if (c->poll_entry->revents & (POLLERR | POLLHUP))
+ return -1;
+
+ /* no need to read if no events */
+ if (!(c->poll_entry->revents & POLLOUT))
+ return 0;
+ }
+ if (http_send_data(c) < 0)
+ return -1;
+ /* close connection if trailer sent */
+ if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
+ return -1;
+ break;
+ case HTTPSTATE_RECEIVE_DATA:
+ /* no need to read if no events */
+ if (c->poll_entry->revents & (POLLERR | POLLHUP))
+ return -1;
+ if (!(c->poll_entry->revents & POLLIN))
+ return 0;
+ if (http_receive_data(c) < 0)
+ return -1;
+ break;
+ case HTTPSTATE_WAIT_FEED:
+ /* no need to read if no events */
+ if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
+ return -1;
+
+ /* nothing to do, we'll be waken up by incoming feed packets */
+ break;
+
+ case RTSPSTATE_SEND_REPLY:
+ if (c->poll_entry->revents & (POLLERR | POLLHUP))
+ goto close_connection;
+ /* no need to write if no events */
+ if (!(c->poll_entry->revents & POLLOUT))
+ return 0;
+ len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR)) {
+ goto close_connection;
+ }
+ break;
+ }
+ c->buffer_ptr += len;
+ c->data_count += len;
+ if (c->buffer_ptr >= c->buffer_end) {
+ /* all the buffer was sent : wait for a new request */
+ av_freep(&c->pb_buffer);
+ start_wait_request(c, 1);
+ }
+ break;
+ case RTSPSTATE_SEND_PACKET:
+ if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
+ av_freep(&c->packet_buffer);
+ return -1;
+ }
+ /* no need to write if no events */
+ if (!(c->poll_entry->revents & POLLOUT))
+ return 0;
+ len = send(c->fd, c->packet_buffer_ptr,
+ c->packet_buffer_end - c->packet_buffer_ptr, 0);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR)) {
+ /* error : close connection */
+ av_freep(&c->packet_buffer);
+ return -1;
+ }
+ break;
+ }
+ c->packet_buffer_ptr += len;
+ if (c->packet_buffer_ptr >= c->packet_buffer_end) {
+ /* all the buffer was sent : wait for a new request */
+ av_freep(&c->packet_buffer);
+ c->state = RTSPSTATE_WAIT_REQUEST;
+ }
+ break;
+ case HTTPSTATE_READY:
+ /* nothing to do */
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+
+close_connection:
+ av_freep(&c->pb_buffer);
+ return -1;
+}
+
+static int extract_rates(char *rates, int ratelen, const char *request)
+{
+ const char *p;
+
+ for (p = request; *p && *p != '\r' && *p != '\n'; ) {
+ if (av_strncasecmp(p, "Pragma:", 7) == 0) {
+ const char *q = p + 7;
+
+ while (*q && *q != '\n' && av_isspace(*q))
+ q++;
+
+ if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
+ int stream_no;
+ int rate_no;
+
+ q += 20;
+
+ memset(rates, 0xff, ratelen);
+
+ while (1) {
+ while (*q && *q != '\n' && *q != ':')
+ q++;
+
+ if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
+ break;
+
+ stream_no--;
+ if (stream_no < ratelen && stream_no >= 0)
+ rates[stream_no] = rate_no;
+
+ while (*q && *q != '\n' && !av_isspace(*q))
+ q++;
+ }
+
+ return 1;
+ }
+ }
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+
+ p++;
+ }
+
+ return 0;
+}
+
+static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec,
+ int bit_rate)
+{
+ int i;
+ int best_bitrate = 100000000;
+ int best = -1;
+
+ for (i = 0; i < feed->nb_streams; i++) {
+ AVCodecContext *feed_codec = feed->streams[i]->codec;
+
+ if (feed_codec->codec_id != codec->codec_id ||
+ feed_codec->sample_rate != codec->sample_rate ||
+ feed_codec->width != codec->width ||
+ feed_codec->height != codec->height)
+ continue;
+
+ /* Potential stream */
+
+ /* We want the fastest stream less than bit_rate, or the slowest
+ * faster than bit_rate
+ */
+
+ if (feed_codec->bit_rate <= bit_rate) {
+ if (best_bitrate > bit_rate ||
+ feed_codec->bit_rate > best_bitrate) {
+ best_bitrate = feed_codec->bit_rate;
+ best = i;
+ }
+ continue;
+ }
+ if (feed_codec->bit_rate < best_bitrate) {
+ best_bitrate = feed_codec->bit_rate;
+ best = i;
+ }
+ }
+ return best;
+}
+
+static int modify_current_stream(HTTPContext *c, char *rates)
+{
+ int i;
+ FFServerStream *req = c->stream;
+ int action_required = 0;
+
+ /* Not much we can do for a feed */
+ if (!req->feed)
+ return 0;
+
+ for (i = 0; i < req->nb_streams; i++) {
+ AVCodecContext *codec = req->streams[i]->codec;
+
+ switch(rates[i]) {
+ case 0:
+ c->switch_feed_streams[i] = req->feed_streams[i];
+ break;
+ case 1:
+ c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
+ break;
+ case 2:
+ /* Wants off or slow */
+ c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
+#ifdef WANTS_OFF
+ /* This doesn't work well when it turns off the only stream! */
+ c->switch_feed_streams[i] = -2;
+ c->feed_streams[i] = -2;
+#endif
+ break;
+ }
+
+ if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
+ action_required = 1;
+ }
+
+ return action_required;
+}
+
+static void get_word(char *buf, int buf_size, const char **pp)
+{
+ const char *p;
+ char *q;
+
+ p = *pp;
+ p += strspn(p, SPACE_CHARS);
+ q = buf;
+ while (!av_isspace(*p) && *p != '\0') {
+ if ((q - buf) < buf_size - 1)
+ *q++ = *p;
+ p++;
+ }
+ if (buf_size > 0)
+ *q = '\0';
+ *pp = p;
+}
+
+static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream,
+ HTTPContext *c)
+{
+ FILE* f;
+ char line[1024];
+ char cmd[1024];
+ FFServerIPAddressACL *acl = NULL;
+ int line_num = 0;
+ const char *p;
+
+ f = fopen(stream->dynamic_acl, "r");
+ if (!f) {
+ perror(stream->dynamic_acl);
+ return NULL;
+ }
+
+ acl = av_mallocz(sizeof(FFServerIPAddressACL));
+
+ /* Build ACL */
+ while (fgets(line, sizeof(line), f)) {
+ line_num++;
+ p = line;
+ while (av_isspace(*p))
+ p++;
+ if (*p == '\0' || *p == '#')
+ continue;
+ ffserver_get_arg(cmd, sizeof(cmd), &p);
+
+ if (!av_strcasecmp(cmd, "ACL"))
+ ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl,
+ line_num);
+ }
+ fclose(f);
+ return acl;
+}
+
+
+static void free_acl_list(FFServerIPAddressACL *in_acl)
+{
+ FFServerIPAddressACL *pacl, *pacl2;
+
+ pacl = in_acl;
+ while(pacl) {
+ pacl2 = pacl;
+ pacl = pacl->next;
+ av_freep(pacl2);
+ }
+}
+
+static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
+{
+ enum FFServerIPAddressAction last_action = IP_DENY;
+ FFServerIPAddressACL *acl;
+ struct in_addr *src = &c->from_addr.sin_addr;
+ unsigned long src_addr = src->s_addr;
+
+ for (acl = in_acl; acl; acl = acl->next) {
+ if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
+ return (acl->action == IP_ALLOW) ? 1 : 0;
+ last_action = acl->action;
+ }
+
+ /* Nothing matched, so return not the last action */
+ return (last_action == IP_DENY) ? 1 : 0;
+}
+
+static int validate_acl(FFServerStream *stream, HTTPContext *c)
+{
+ int ret = 0;
+ FFServerIPAddressACL *acl;
+
+ /* if stream->acl is null validate_acl_list will return 1 */
+ ret = validate_acl_list(stream->acl, c);
+
+ if (stream->dynamic_acl[0]) {
+ acl = parse_dynamic_acl(stream, c);
+
+ ret = validate_acl_list(acl, c);
+
+ free_acl_list(acl);
+ }
+
+ return ret;
+}
+
+/* compute the real filename of a file by matching it without its
+ extensions to all the stream's filenames */
+static void compute_real_filename(char *filename, int max_size)
+{
+ char file1[1024];
+ char file2[1024];
+ char *p;
+ FFServerStream *stream;
+
+ /* compute filename by matching without the file extensions */
+ av_strlcpy(file1, filename, sizeof(file1));
+ p = strrchr(file1, '.');
+ if (p)
+ *p = '\0';
+ for(stream = config.first_stream; stream; stream = stream->next) {
+ av_strlcpy(file2, stream->filename, sizeof(file2));
+ p = strrchr(file2, '.');
+ if (p)
+ *p = '\0';
+ if (!strcmp(file1, file2)) {
+ av_strlcpy(filename, stream->filename, max_size);
+ break;
+ }
+ }
+}
+
+enum RedirType {
+ REDIR_NONE,
+ REDIR_ASX,
+ REDIR_RAM,
+ REDIR_ASF,
+ REDIR_RTSP,
+ REDIR_SDP,
+};
+
+/* parse HTTP request and prepare header */
+static int http_parse_request(HTTPContext *c)
+{
+ const char *p;
+ char *p1;
+ enum RedirType redir_type;
+ char cmd[32];
+ char info[1024], filename[1024];
+ char url[1024], *q;
+ char protocol[32];
+ char msg[1024];
+ const char *mime_type;
+ FFServerStream *stream;
+ int i;
+ char ratebuf[32];
+ const char *useragent = 0;
+
+ p = c->buffer;
+ get_word(cmd, sizeof(cmd), &p);
+ av_strlcpy(c->method, cmd, sizeof(c->method));
+
+ if (!strcmp(cmd, "GET"))
+ c->post = 0;
+ else if (!strcmp(cmd, "POST"))
+ c->post = 1;
+ else
+ return -1;
+
+ get_word(url, sizeof(url), &p);
+ av_strlcpy(c->url, url, sizeof(c->url));
+
+ get_word(protocol, sizeof(protocol), (const char **)&p);
+ if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
+ return -1;
+
+ av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
+
+ if (config.debug)
+ http_log("%s - - New connection: %s %s\n",
+ inet_ntoa(c->from_addr.sin_addr), cmd, url);
+
+ /* find the filename and the optional info string in the request */
+ p1 = strchr(url, '?');
+ if (p1) {
+ av_strlcpy(info, p1, sizeof(info));
+ *p1 = '\0';
+ } else
+ info[0] = '\0';
+
+ av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
+
+ for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
+ if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
+ useragent = p + 11;
+ if (*useragent && *useragent != '\n' && av_isspace(*useragent))
+ useragent++;
+ break;
+ }
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+
+ p++;
+ }
+
+ redir_type = REDIR_NONE;
+ if (av_match_ext(filename, "asx")) {
+ redir_type = REDIR_ASX;
+ filename[strlen(filename)-1] = 'f';
+ } else if (av_match_ext(filename, "asf") &&
+ (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
+ /* if this isn't WMP or lookalike, return the redirector file */
+ redir_type = REDIR_ASF;
+ } else if (av_match_ext(filename, "rpm,ram")) {
+ redir_type = REDIR_RAM;
+ strcpy(filename + strlen(filename)-2, "m");
+ } else if (av_match_ext(filename, "rtsp")) {
+ redir_type = REDIR_RTSP;
+ compute_real_filename(filename, sizeof(filename) - 1);
+ } else if (av_match_ext(filename, "sdp")) {
+ redir_type = REDIR_SDP;
+ compute_real_filename(filename, sizeof(filename) - 1);
+ }
+
+ // "redirect" / request to index.html
+ if (!strlen(filename))
+ av_strlcpy(filename, "index.html", sizeof(filename) - 1);
+
+ stream = config.first_stream;
+ while (stream) {
+ if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
+ break;
+ stream = stream->next;
+ }
+ if (!stream) {
+ snprintf(msg, sizeof(msg), "File '%s' not found", url);
+ http_log("File '%s' not found\n", url);
+ goto send_error;
+ }
+
+ c->stream = stream;
+ memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
+ memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
+
+ if (stream->stream_type == STREAM_TYPE_REDIRECT) {
+ c->http_error = 301;
+ q = c->buffer;
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 301 Moved\r\n"
+ "Location: %s\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Moved</title></head><body>\r\n"
+ "You should be <a href=\"%s\">redirected</a>.\r\n"
+ "</body></html>\r\n",
+ stream->feed_filename, stream->feed_filename);
+ q += strlen(q);
+ /* prepare output buffer */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = q;
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+ }
+
+ /* If this is WMP, get the rate information */
+ if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
+ if (modify_current_stream(c, ratebuf)) {
+ for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
+ if (c->switch_feed_streams[i] >= 0)
+ c->switch_feed_streams[i] = -1;
+ }
+ }
+ }
+
+ if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
+ current_bandwidth += stream->bandwidth;
+
+ /* If already streaming this feed, do not let start another feeder. */
+ if (stream->feed_opened) {
+ snprintf(msg, sizeof(msg), "This feed is already being received.");
+ http_log("Feed '%s' already being received\n", stream->feed_filename);
+ goto send_error;
+ }
+
+ if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
+ c->http_error = 503;
+ q = c->buffer;
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 503 Server too busy\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html><head><title>Too busy</title></head><body>\r\n"
+ "<p>The server is too busy to serve your request at this time.</p>\r\n"
+ "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
+ "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
+ "</body></html>\r\n",
+ current_bandwidth, config.max_bandwidth);
+ q += strlen(q);
+ /* prepare output buffer */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = q;
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+ }
+
+ if (redir_type != REDIR_NONE) {
+ const char *hostinfo = 0;
+
+ for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
+ if (av_strncasecmp(p, "Host:", 5) == 0) {
+ hostinfo = p + 5;
+ break;
+ }
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+
+ p++;
+ }
+
+ if (hostinfo) {
+ char *eoh;
+ char hostbuf[260];
+
+ while (av_isspace(*hostinfo))
+ hostinfo++;
+
+ eoh = strchr(hostinfo, '\n');
+ if (eoh) {
+ if (eoh[-1] == '\r')
+ eoh--;
+
+ if (eoh - hostinfo < sizeof(hostbuf) - 1) {
+ memcpy(hostbuf, hostinfo, eoh - hostinfo);
+ hostbuf[eoh - hostinfo] = 0;
+
+ c->http_error = 200;
+ q = c->buffer;
+ switch(redir_type) {
+ case REDIR_ASX:
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 ASX Follows\r\n"
+ "Content-type: video/x-ms-asf\r\n"
+ "\r\n"
+ "<ASX Version=\"3\">\r\n"
+ //"<!-- Autogenerated by ffserver -->\r\n"
+ "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
+ "</ASX>\r\n", hostbuf, filename, info);
+ q += strlen(q);
+ break;
+ case REDIR_RAM:
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 RAM Follows\r\n"
+ "Content-type: audio/x-pn-realaudio\r\n"
+ "\r\n"
+ "# Autogenerated by ffserver\r\n"
+ "http://%s/%s%s\r\n", hostbuf, filename, info);
+ q += strlen(q);
+ break;
+ case REDIR_ASF:
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 ASF Redirect follows\r\n"
+ "Content-type: video/x-ms-asf\r\n"
+ "\r\n"
+ "[Reference]\r\n"
+ "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
+ q += strlen(q);
+ break;
+ case REDIR_RTSP:
+ {
+ char hostname[256], *p;
+ /* extract only hostname */
+ av_strlcpy(hostname, hostbuf, sizeof(hostname));
+ p = strrchr(hostname, ':');
+ if (p)
+ *p = '\0';
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 RTSP Redirect follows\r\n"
+ /* XXX: incorrect MIME type ? */
+ "Content-type: application/x-rtsp\r\n"
+ "\r\n"
+ "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
+ q += strlen(q);
+ }
+ break;
+ case REDIR_SDP:
+ {
+ uint8_t *sdp_data;
+ int sdp_data_size;
+ socklen_t len;
+ struct sockaddr_in my_addr;
+
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 200 OK\r\n"
+ "Content-type: application/sdp\r\n"
+ "\r\n");
+ q += strlen(q);
+
+ len = sizeof(my_addr);
+
+ /* XXX: Should probably fail? */
+ if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
+ http_log("getsockname() failed\n");
+
+ /* XXX: should use a dynamic buffer */
+ sdp_data_size = prepare_sdp_description(stream,
+ &sdp_data,
+ my_addr.sin_addr);
+ if (sdp_data_size > 0) {
+ memcpy(q, sdp_data, sdp_data_size);
+ q += sdp_data_size;
+ *q = '\0';
+ av_free(sdp_data);
+ }
+ }
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ /* prepare output buffer */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = q;
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+ }
+ }
+ }
+
+ snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
+ goto send_error;
+ }
+
+ stream->conns_served++;
+
+ /* XXX: add there authenticate and IP match */
+
+ if (c->post) {
+ /* if post, it means a feed is being sent */
+ if (!stream->is_feed) {
+ /* However it might be a status report from WMP! Let us log the
+ * data as it might come handy one day. */
+ const char *logline = 0;
+ int client_id = 0;
+
+ for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
+ if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
+ logline = p;
+ break;
+ }
+ if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
+ client_id = strtol(p + 18, 0, 10);
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+
+ p++;
+ }
+
+ if (logline) {
+ char *eol = strchr(logline, '\n');
+
+ logline += 17;
+
+ if (eol) {
+ if (eol[-1] == '\r')
+ eol--;
+ http_log("%.*s\n", (int) (eol - logline), logline);
+ c->suppress_log = 1;
+ }
+ }
+
+#ifdef DEBUG
+ http_log("\nGot request:\n%s\n", c->buffer);
+#endif
+
+ if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
+ HTTPContext *wmpc;
+
+ /* Now we have to find the client_id */
+ for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
+ if (wmpc->wmp_client_id == client_id)
+ break;
+ }
+
+ if (wmpc && modify_current_stream(wmpc, ratebuf))
+ wmpc->switch_pending = 1;
+ }
+
+ snprintf(msg, sizeof(msg), "POST command not handled");
+ c->stream = 0;
+ goto send_error;
+ }
+ if (http_start_receive_data(c) < 0) {
+ snprintf(msg, sizeof(msg), "could not open feed");
+ goto send_error;
+ }
+ c->http_error = 0;
+ c->state = HTTPSTATE_RECEIVE_DATA;
+ return 0;
+ }
+
+#ifdef DEBUG
+ if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
+ http_log("\nGot request:\n%s\n", c->buffer);
+#endif
+
+ if (c->stream->stream_type == STREAM_TYPE_STATUS)
+ goto send_status;
+
+ /* open input stream */
+ if (open_input_stream(c, info) < 0) {
+ snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
+ goto send_error;
+ }
+
+ /* prepare HTTP header */
+ c->buffer[0] = 0;
+ av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
+ mime_type = c->stream->fmt->mime_type;
+ if (!mime_type)
+ mime_type = "application/x-octet-stream";
+ av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
+
+ /* for asf, we need extra headers */
+ if (!strcmp(c->stream->fmt->name,"asf_stream")) {
+ /* Need to allocate a client id */
+
+ c->wmp_client_id = av_lfg_get(&random_state);
+
+ av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
+ }
+ av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
+ av_strlcatf(c->buffer, c->buffer_size, "\r\n");
+ q = c->buffer + strlen(c->buffer);
+
+ /* prepare output buffer */
+ c->http_error = 0;
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = q;
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+ send_error:
+ c->http_error = 404;
+ q = c->buffer;
+ htmlstrip(msg);
+ snprintf(q, c->buffer_size,
+ "HTTP/1.0 404 Not Found\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<html>\n"
+ "<head><title>404 Not Found</title></head>\n"
+ "<body>%s</body>\n"
+ "</html>\n", msg);
+ q += strlen(q);
+ /* prepare output buffer */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = q;
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+ send_status:
+ compute_status(c);
+ c->http_error = 200; /* horrible : we use this value to avoid
+ going to the send data state */
+ c->state = HTTPSTATE_SEND_HEADER;
+ return 0;
+}
+
+static void fmt_bytecount(AVIOContext *pb, int64_t count)
+{
+ static const char suffix[] = " kMGTP";
+ const char *s;
+
+ for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
+
+ avio_printf(pb, "%"PRId64"%c", count, *s);
+}
+
+static void compute_status(HTTPContext *c)
+{
+ HTTPContext *c1;
+ FFServerStream *stream;
+ char *p;
+ time_t ti;
+ int i, len;
+ AVIOContext *pb;
+
+ if (avio_open_dyn_buf(&pb) < 0) {
+ /* XXX: return an error ? */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = c->buffer;
+ return;
+ }
+
+ avio_printf(pb, "HTTP/1.0 200 OK\r\n");
+ avio_printf(pb, "Content-type: text/html\r\n");
+ avio_printf(pb, "Pragma: no-cache\r\n");
+ avio_printf(pb, "\r\n");
+
+ avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
+ if (c->stream->feed_filename[0])
+ avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
+ c->stream->feed_filename);
+ avio_printf(pb, "</head>\n<body>");
+ avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
+ /* format status */
+ avio_printf(pb, "<h2>Available Streams</h2>\n");
+ avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
+ avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
+ stream = config.first_stream;
+ while (stream) {
+ char sfilename[1024];
+ char *eosf;
+
+ if (stream->feed == stream) {
+ stream = stream->next;
+ continue;
+ }
+
+ av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
+ eosf = sfilename + strlen(sfilename);
+ if (eosf - sfilename >= 4) {
+ if (strcmp(eosf - 4, ".asf") == 0)
+ strcpy(eosf - 4, ".asx");
+ else if (strcmp(eosf - 3, ".rm") == 0)
+ strcpy(eosf - 3, ".ram");
+ else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
+ /* generate a sample RTSP director if
+ unicast. Generate an SDP redirector if
+ multicast */
+ eosf = strrchr(sfilename, '.');
+ if (!eosf)
+ eosf = sfilename + strlen(sfilename);
+ if (stream->is_multicast)
+ strcpy(eosf, ".sdp");
+ else
+ strcpy(eosf, ".rtsp");
+ }
+ }
+
+ avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
+ sfilename, stream->filename);
+ avio_printf(pb, "<td align=right> %d <td align=right> ",
+ stream->conns_served);
+ fmt_bytecount(pb, stream->bytes_served);
+
+ switch(stream->stream_type) {
+ case STREAM_TYPE_LIVE: {
+ int audio_bit_rate = 0;
+ int video_bit_rate = 0;
+ const char *audio_codec_name = "";
+ const char *video_codec_name = "";
+ const char *audio_codec_name_extra = "";
+ const char *video_codec_name_extra = "";
+
+ for(i=0;i<stream->nb_streams;i++) {
+ AVStream *st = stream->streams[i];
+ AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
+
+ switch(st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ audio_bit_rate += st->codec->bit_rate;
+ if (codec) {
+ if (*audio_codec_name)
+ audio_codec_name_extra = "...";
+ audio_codec_name = codec->name;
+ }
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ video_bit_rate += st->codec->bit_rate;
+ if (codec) {
+ if (*video_codec_name)
+ video_codec_name_extra = "...";
+ video_codec_name = codec->name;
+ }
+ break;
+ case AVMEDIA_TYPE_DATA:
+ video_bit_rate += st->codec->bit_rate;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ avio_printf(pb, "<td align=center> %s <td align=right> %d "
+ "<td align=right> %d <td> %s %s <td align=right> "
+ "%d <td> %s %s",
+ stream->fmt->name, stream->bandwidth,
+ video_bit_rate / 1000, video_codec_name,
+ video_codec_name_extra, audio_bit_rate / 1000,
+ audio_codec_name, audio_codec_name_extra);
+
+ if (stream->feed)
+ avio_printf(pb, "<td>%s", stream->feed->filename);
+ else
+ avio_printf(pb, "<td>%s", stream->feed_filename);
+ avio_printf(pb, "\n");
+ }
+ break;
+ default:
+ avio_printf(pb, "<td align=center> - <td align=right> - "
+ "<td align=right> - <td><td align=right> - <td>\n");
+ break;
+ }
+ stream = stream->next;
+ }
+ avio_printf(pb, "</table>\n");
+
+ stream = config.first_stream;
+ while (stream) {
+
+ if (stream->feed != stream) {
+ stream = stream->next;
+ continue;
+ }
+
+ avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
+ if (stream->pid) {
+ avio_printf(pb, "Running as pid %d.\n", stream->pid);
+
+#if defined(linux)
+ {
+ FILE *pid_stat;
+ char ps_cmd[64];
+
+ /* This is somewhat linux specific I guess */
+ snprintf(ps_cmd, sizeof(ps_cmd),
+ "ps -o \"%%cpu,cputime\" --no-headers %d",
+ stream->pid);
+
+ pid_stat = popen(ps_cmd, "r");
+ if (pid_stat) {
+ char cpuperc[10];
+ char cpuused[64];
+
+ if (fscanf(pid_stat, "%9s %63s", cpuperc, cpuused) == 2) {
+ avio_printf(pb, "Currently using %s%% of the cpu. "
+ "Total time used %s.\n",
+ cpuperc, cpuused);
+ }
+ fclose(pid_stat);
+ }
+ }
+#endif
+
+ avio_printf(pb, "<p>");
+ }
+
+ avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
+ "type<th>kbits/s<th align=left>codec<th align=left>"
+ "Parameters\n");
+
+ for (i = 0; i < stream->nb_streams; i++) {
+ AVStream *st = stream->streams[i];
+ AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
+ const char *type = "unknown";
+ char parameters[64];
+
+ parameters[0] = 0;
+
+ switch(st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ type = "audio";
+ snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz",
+ st->codec->channels, st->codec->sample_rate);
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ type = "video";
+ snprintf(parameters, sizeof(parameters),
+ "%dx%d, q=%d-%d, fps=%d", st->codec->width,
+ st->codec->height, st->codec->qmin, st->codec->qmax,
+ st->codec->time_base.den / st->codec->time_base.num);
+ break;
+ default:
+ abort();
+ }
+
+ avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
+ "<td>%s<td>%s\n",
+ i, type, st->codec->bit_rate/1000,
+ codec ? codec->name : "", parameters);
+ }
+
+ avio_printf(pb, "</table>\n");
+ stream = stream->next;
+ }
+
+ /* connection status */
+ avio_printf(pb, "<h2>Connection Status</h2>\n");
+
+ avio_printf(pb, "Number of connections: %d / %d<br>\n",
+ nb_connections, config.nb_max_connections);
+
+ avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
+ current_bandwidth, config.max_bandwidth);
+
+ avio_printf(pb, "<table>\n");
+ avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
+ "bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
+ c1 = first_http_ctx;
+ i = 0;
+ while (c1) {
+ int bitrate;
+ int j;
+
+ bitrate = 0;
+ if (c1->stream) {
+ for (j = 0; j < c1->stream->nb_streams; j++) {
+ if (!c1->stream->feed)
+ bitrate += c1->stream->streams[j]->codec->bit_rate;
+ else if (c1->feed_streams[j] >= 0)
+ bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
+ }
+ }
+
+ i++;
+ p = inet_ntoa(c1->from_addr.sin_addr);
+ avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s"
+ "<td align=right>",
+ i, c1->stream ? c1->stream->filename : "",
+ c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", p,
+ c1->protocol, http_state[c1->state]);
+ fmt_bytecount(pb, bitrate);
+ avio_printf(pb, "<td align=right>");
+ fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
+ avio_printf(pb, "<td align=right>");
+ fmt_bytecount(pb, c1->data_count);
+ avio_printf(pb, "\n");
+ c1 = c1->next;
+ }
+ avio_printf(pb, "</table>\n");
+
+ /* date */
+ ti = time(NULL);
+ p = ctime(&ti);
+ avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
+ avio_printf(pb, "</body>\n</html>\n");
+
+ len = avio_close_dyn_buf(pb, &c->pb_buffer);
+ c->buffer_ptr = c->pb_buffer;
+ c->buffer_end = c->pb_buffer + len;
+}
+
+static int open_input_stream(HTTPContext *c, const char *info)
+{
+ char buf[128];
+ char input_filename[1024];
+ AVFormatContext *s = NULL;
+ int buf_size, i, ret;
+ int64_t stream_pos;
+
+ /* find file name */
+ if (c->stream->feed) {
+ strcpy(input_filename, c->stream->feed->feed_filename);
+ buf_size = FFM_PACKET_SIZE;
+ /* compute position (absolute time) */
+ if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
+ if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
+ http_log("Invalid date specification '%s' for stream\n", buf);
+ return ret;
+ }
+ } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
+ int prebuffer = strtol(buf, 0, 10);
+ stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
+ } else
+ stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
+ } else {
+ strcpy(input_filename, c->stream->feed_filename);
+ buf_size = 0;
+ /* compute position (relative time) */
+ if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
+ if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
+ http_log("Invalid date specification '%s' for stream\n", buf);
+ return ret;
+ }
+ } else
+ stream_pos = 0;
+ }
+ if (!input_filename[0]) {
+ http_log("No filename was specified for stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* open stream */
+ ret = avformat_open_input(&s, input_filename, c->stream->ifmt,
+ &c->stream->in_opts);
+ if (ret < 0) {
+ http_log("Could not open input '%s': %s\n",
+ input_filename, av_err2str(ret));
+ return ret;
+ }
+
+ /* set buffer size */
+ if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
+
+ s->flags |= AVFMT_FLAG_GENPTS;
+ c->fmt_in = s;
+ if (strcmp(s->iformat->name, "ffm") &&
+ (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
+ http_log("Could not find stream info for input '%s'\n", input_filename);
+ avformat_close_input(&s);
+ return ret;
+ }
+
+ /* choose stream as clock source (we favor the video stream if
+ * present) for packet sending */
+ c->pts_stream_index = 0;
+ for(i=0;i<c->stream->nb_streams;i++) {
+ if (c->pts_stream_index == 0 &&
+ c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ c->pts_stream_index = i;
+ }
+ }
+
+ if (c->fmt_in->iformat->read_seek)
+ av_seek_frame(c->fmt_in, -1, stream_pos, 0);
+ /* set the start time (needed for maxtime and RTP packet timing) */
+ c->start_time = cur_time;
+ c->first_pts = AV_NOPTS_VALUE;
+ return 0;
+}
+
+/* return the server clock (in us) */
+static int64_t get_server_clock(HTTPContext *c)
+{
+ /* compute current pts value from system time */
+ return (cur_time - c->start_time) * 1000;
+}
+
+/* return the estimated time at which the current packet must be sent
+ (in us) */
+static int64_t get_packet_send_clock(HTTPContext *c)
+{
+ int bytes_left, bytes_sent, frame_bytes;
+
+ frame_bytes = c->cur_frame_bytes;
+ if (frame_bytes <= 0)
+ return c->cur_pts;
+ else {
+ bytes_left = c->buffer_end - c->buffer_ptr;
+ bytes_sent = frame_bytes - bytes_left;
+ return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
+ }
+}
+
+
+static int http_prepare_data(HTTPContext *c)
+{
+ int i, len, ret;
+ AVFormatContext *ctx;
+
+ av_freep(&c->pb_buffer);
+ switch(c->state) {
+ case HTTPSTATE_SEND_DATA_HEADER:
+ ctx = avformat_alloc_context();
+ c->fmt_ctx = *ctx;
+ av_freep(&ctx);
+ av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
+ c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams,
+ sizeof(AVStream *));
+
+ for(i=0;i<c->stream->nb_streams;i++) {
+ AVStream *src;
+ c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
+ /* if file or feed, then just take streams from FFServerStream struct */
+ if (!c->stream->feed ||
+ c->stream->feed == c->stream)
+ src = c->stream->streams[i];
+ else
+ src = c->stream->feed->streams[c->stream->feed_streams[i]];
+
+ *(c->fmt_ctx.streams[i]) = *src;
+ c->fmt_ctx.streams[i]->priv_data = 0;
+ /* XXX: should be done in AVStream, not in codec */
+ c->fmt_ctx.streams[i]->codec->frame_number = 0;
+ }
+ /* set output format parameters */
+ c->fmt_ctx.oformat = c->stream->fmt;
+ c->fmt_ctx.nb_streams = c->stream->nb_streams;
+
+ c->got_key_frame = 0;
+
+ /* prepare header and save header data in a stream */
+ if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
+ /* XXX: potential leak */
+ return -1;
+ }
+ c->fmt_ctx.pb->seekable = 0;
+
+ /*
+ * HACK to avoid MPEG-PS muxer to spit many underflow errors
+ * Default value from FFmpeg
+ * Try to set it using configuration option
+ */
+ c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
+
+ if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
+ http_log("Error writing output header for stream '%s': %s\n",
+ c->stream->filename, av_err2str(ret));
+ return ret;
+ }
+ av_dict_free(&c->fmt_ctx.metadata);
+
+ len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
+ c->buffer_ptr = c->pb_buffer;
+ c->buffer_end = c->pb_buffer + len;
+
+ c->state = HTTPSTATE_SEND_DATA;
+ c->last_packet_sent = 0;
+ break;
+ case HTTPSTATE_SEND_DATA:
+ /* find a new packet */
+ /* read a packet from the input stream */
+ if (c->stream->feed)
+ ffm_set_write_index(c->fmt_in,
+ c->stream->feed->feed_write_index,
+ c->stream->feed->feed_size);
+
+ if (c->stream->max_time &&
+ c->stream->max_time + c->start_time - cur_time < 0)
+ /* We have timed out */
+ c->state = HTTPSTATE_SEND_DATA_TRAILER;
+ else {
+ AVPacket pkt;
+ redo:
+ ret = av_read_frame(c->fmt_in, &pkt);
+ if (ret < 0) {
+ if (c->stream->feed) {
+ /* if coming from feed, it means we reached the end of the
+ ffm file, so must wait for more data */
+ c->state = HTTPSTATE_WAIT_FEED;
+ return 1; /* state changed */
+ } else if (ret == AVERROR(EAGAIN)) {
+ /* input not ready, come back later */
+ return 0;
+ } else {
+ if (c->stream->loop) {
+ avformat_close_input(&c->fmt_in);
+ if (open_input_stream(c, "") < 0)
+ goto no_loop;
+ goto redo;
+ } else {
+ no_loop:
+ /* must send trailer now because EOF or error */
+ c->state = HTTPSTATE_SEND_DATA_TRAILER;
+ }
+ }
+ } else {
+ int source_index = pkt.stream_index;
+ /* update first pts if needed */
+ if (c->first_pts == AV_NOPTS_VALUE) {
+ c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
+ c->start_time = cur_time;
+ }
+ /* send it to the appropriate stream */
+ if (c->stream->feed) {
+ /* if coming from a feed, select the right stream */
+ if (c->switch_pending) {
+ c->switch_pending = 0;
+ for(i=0;i<c->stream->nb_streams;i++) {
+ if (c->switch_feed_streams[i] == pkt.stream_index)
+ if (pkt.flags & AV_PKT_FLAG_KEY)
+ c->switch_feed_streams[i] = -1;
+ if (c->switch_feed_streams[i] >= 0)
+ c->switch_pending = 1;
+ }
+ }
+ for(i=0;i<c->stream->nb_streams;i++) {
+ if (c->stream->feed_streams[i] == pkt.stream_index) {
+ AVStream *st = c->fmt_in->streams[source_index];
+ pkt.stream_index = i;
+ if (pkt.flags & AV_PKT_FLAG_KEY &&
+ (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
+ c->stream->nb_streams == 1))
+ c->got_key_frame = 1;
+ if (!c->stream->send_on_key || c->got_key_frame)
+ goto send_it;
+ }
+ }
+ } else {
+ AVCodecContext *codec;
+ AVStream *ist, *ost;
+ send_it:
+ ist = c->fmt_in->streams[source_index];
+ /* specific handling for RTP: we use several
+ * output streams (one for each RTP connection).
+ * XXX: need more abstract handling */
+ if (c->is_packetized) {
+ /* compute send time and duration */
+ c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
+ c->cur_pts -= c->first_pts;
+ c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
+ /* find RTP context */
+ c->packet_stream_index = pkt.stream_index;
+ ctx = c->rtp_ctx[c->packet_stream_index];
+ if(!ctx) {
+ av_free_packet(&pkt);
+ break;
+ }
+ codec = ctx->streams[0]->codec;
+ /* only one stream per RTP connection */
+ pkt.stream_index = 0;
+ } else {
+ ctx = &c->fmt_ctx;
+ /* Fudge here */
+ codec = ctx->streams[pkt.stream_index]->codec;
+ }
+
+ if (c->is_packetized) {
+ int max_packet_size;
+ if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
+ max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
+ else
+ max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
+ ret = ffio_open_dyn_packet_buf(&ctx->pb,
+ max_packet_size);
+ } else {
+ ret = avio_open_dyn_buf(&ctx->pb);
+ }
+ if (ret < 0) {
+ /* XXX: potential leak */
+ return -1;
+ }
+ ost = ctx->streams[pkt.stream_index];
+
+ ctx->pb->seekable = 0;
+ if (pkt.dts != AV_NOPTS_VALUE)
+ pkt.dts = av_rescale_q(pkt.dts, ist->time_base,
+ ost->time_base);
+ if (pkt.pts != AV_NOPTS_VALUE)
+ pkt.pts = av_rescale_q(pkt.pts, ist->time_base,
+ ost->time_base);
+ pkt.duration = av_rescale_q(pkt.duration, ist->time_base,
+ ost->time_base);
+ if ((ret = av_write_frame(ctx, &pkt)) < 0) {
+ http_log("Error writing frame to output for stream '%s': %s\n",
+ c->stream->filename, av_err2str(ret));
+ c->state = HTTPSTATE_SEND_DATA_TRAILER;
+ }
+
+ av_freep(&c->pb_buffer);
+ len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
+ c->cur_frame_bytes = len;
+ c->buffer_ptr = c->pb_buffer;
+ c->buffer_end = c->pb_buffer + len;
+
+ codec->frame_number++;
+ if (len == 0) {
+ av_free_packet(&pkt);
+ goto redo;
+ }
+ }
+ av_free_packet(&pkt);
+ }
+ }
+ break;
+ default:
+ case HTTPSTATE_SEND_DATA_TRAILER:
+ /* last packet test ? */
+ if (c->last_packet_sent || c->is_packetized)
+ return -1;
+ ctx = &c->fmt_ctx;
+ /* prepare header */
+ if (avio_open_dyn_buf(&ctx->pb) < 0) {
+ /* XXX: potential leak */
+ return -1;
+ }
+ c->fmt_ctx.pb->seekable = 0;
+ av_write_trailer(ctx);
+ len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
+ c->buffer_ptr = c->pb_buffer;
+ c->buffer_end = c->pb_buffer + len;
+
+ c->last_packet_sent = 1;
+ break;
+ }
+ return 0;
+}
+
+/* should convert the format at the same time */
+/* send data starting at c->buffer_ptr to the output connection
+ * (either UDP or TCP) */
+static int http_send_data(HTTPContext *c)
+{
+ int len, ret;
+
+ for(;;) {
+ if (c->buffer_ptr >= c->buffer_end) {
+ ret = http_prepare_data(c);
+ if (ret < 0)
+ return -1;
+ else if (ret)
+ /* state change requested */
+ break;
+ } else {
+ if (c->is_packetized) {
+ /* RTP data output */
+ len = c->buffer_end - c->buffer_ptr;
+ if (len < 4) {
+ /* fail safe - should never happen */
+ fail1:
+ c->buffer_ptr = c->buffer_end;
+ return 0;
+ }
+ len = (c->buffer_ptr[0] << 24) |
+ (c->buffer_ptr[1] << 16) |
+ (c->buffer_ptr[2] << 8) |
+ (c->buffer_ptr[3]);
+ if (len > (c->buffer_end - c->buffer_ptr))
+ goto fail1;
+ if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
+ /* nothing to send yet: we can wait */
+ return 0;
+ }
+
+ c->data_count += len;
+ update_datarate(&c->datarate, c->data_count);
+ if (c->stream)
+ c->stream->bytes_served += len;
+
+ if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
+ /* RTP packets are sent inside the RTSP TCP connection */
+ AVIOContext *pb;
+ int interleaved_index, size;
+ uint8_t header[4];
+ HTTPContext *rtsp_c;
+
+ rtsp_c = c->rtsp_c;
+ /* if no RTSP connection left, error */
+ if (!rtsp_c)
+ return -1;
+ /* if already sending something, then wait. */
+ if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
+ break;
+ if (avio_open_dyn_buf(&pb) < 0)
+ goto fail1;
+ interleaved_index = c->packet_stream_index * 2;
+ /* RTCP packets are sent at odd indexes */
+ if (c->buffer_ptr[1] == 200)
+ interleaved_index++;
+ /* write RTSP TCP header */
+ header[0] = '$';
+ header[1] = interleaved_index;
+ header[2] = len >> 8;
+ header[3] = len;
+ avio_write(pb, header, 4);
+ /* write RTP packet data */
+ c->buffer_ptr += 4;
+ avio_write(pb, c->buffer_ptr, len);
+ size = avio_close_dyn_buf(pb, &c->packet_buffer);
+ /* prepare asynchronous TCP sending */
+ rtsp_c->packet_buffer_ptr = c->packet_buffer;
+ rtsp_c->packet_buffer_end = c->packet_buffer + size;
+ c->buffer_ptr += len;
+
+ /* send everything we can NOW */
+ len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
+ rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
+ if (len > 0)
+ rtsp_c->packet_buffer_ptr += len;
+ if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
+ /* if we could not send all the data, we will
+ send it later, so a new state is needed to
+ "lock" the RTSP TCP connection */
+ rtsp_c->state = RTSPSTATE_SEND_PACKET;
+ break;
+ } else
+ /* all data has been sent */
+ av_freep(&c->packet_buffer);
+ } else {
+ /* send RTP packet directly in UDP */
+ c->buffer_ptr += 4;
+ ffurl_write(c->rtp_handles[c->packet_stream_index],
+ c->buffer_ptr, len);
+ c->buffer_ptr += len;
+ /* here we continue as we can send several packets
+ * per 10 ms slot */
+ }
+ } else {
+ /* TCP data output */
+ len = send(c->fd, c->buffer_ptr,
+ c->buffer_end - c->buffer_ptr, 0);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR))
+ /* error : close connection */
+ return -1;
+ else
+ return 0;
+ }
+ c->buffer_ptr += len;
+
+ c->data_count += len;
+ update_datarate(&c->datarate, c->data_count);
+ if (c->stream)
+ c->stream->bytes_served += len;
+ break;
+ }
+ }
+ } /* for(;;) */
+ return 0;
+}
+
+static int http_start_receive_data(HTTPContext *c)
+{
+ int fd;
+ int ret;
+
+ if (c->stream->feed_opened) {
+ http_log("Stream feed '%s' was not opened\n",
+ c->stream->feed_filename);
+ return AVERROR(EINVAL);
+ }
+
+ /* Don't permit writing to this one */
+ if (c->stream->readonly) {
+ http_log("Cannot write to read-only file '%s'\n",
+ c->stream->feed_filename);
+ return AVERROR(EINVAL);
+ }
+
+ /* open feed */
+ fd = open(c->stream->feed_filename, O_RDWR);
+ if (fd < 0) {
+ ret = AVERROR(errno);
+ http_log("Could not open feed file '%s': %s\n",
+ c->stream->feed_filename, strerror(errno));
+ return ret;
+ }
+ c->feed_fd = fd;
+
+ if (c->stream->truncate) {
+ /* truncate feed file */
+ ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
+ http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
+ if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
+ ret = AVERROR(errno);
+ http_log("Error truncating feed file '%s': %s\n",
+ c->stream->feed_filename, strerror(errno));
+ return ret;
+ }
+ } else {
+ ret = ffm_read_write_index(fd);
+ if (ret < 0) {
+ http_log("Error reading write index from feed file '%s': %s\n",
+ c->stream->feed_filename, strerror(errno));
+ return ret;
+ } else {
+ c->stream->feed_write_index = ret;
+ }
+ }
+
+ c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd),
+ FFM_PACKET_SIZE);
+ c->stream->feed_size = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ /* init buffer input */
+ c->buffer_ptr = c->buffer;
+ c->buffer_end = c->buffer + FFM_PACKET_SIZE;
+ c->stream->feed_opened = 1;
+ c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
+ return 0;
+}
+
+static int http_receive_data(HTTPContext *c)
+{
+ HTTPContext *c1;
+ int len, loop_run = 0;
+
+ while (c->chunked_encoding && !c->chunk_size &&
+ c->buffer_end > c->buffer_ptr) {
+ /* read chunk header, if present */
+ len = recv(c->fd, c->buffer_ptr, 1, 0);
+
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR))
+ /* error : close connection */
+ goto fail;
+ return 0;
+ } else if (len == 0) {
+ /* end of connection : close it */
+ goto fail;
+ } else if (c->buffer_ptr - c->buffer >= 2 &&
+ !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
+ c->chunk_size = strtol(c->buffer, 0, 16);
+ if (c->chunk_size == 0) // end of stream
+ goto fail;
+ c->buffer_ptr = c->buffer;
+ break;
+ } else if (++loop_run > 10) {
+ /* no chunk header, abort */
+ goto fail;
+ } else {
+ c->buffer_ptr++;
+ }
+ }
+
+ if (c->buffer_end > c->buffer_ptr) {
+ len = recv(c->fd, c->buffer_ptr,
+ FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) &&
+ ff_neterrno() != AVERROR(EINTR))
+ /* error : close connection */
+ goto fail;
+ } else if (len == 0)
+ /* end of connection : close it */
+ goto fail;
+ else {
+ c->chunk_size -= len;
+ c->buffer_ptr += len;
+ c->data_count += len;
+ update_datarate(&c->datarate, c->data_count);
+ }
+ }
+
+ if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
+ if (c->buffer[0] != 'f' ||
+ c->buffer[1] != 'm') {
+ http_log("Feed stream has become desynchronized -- disconnecting\n");
+ goto fail;
+ }
+ }
+
+ if (c->buffer_ptr >= c->buffer_end) {
+ FFServerStream *feed = c->stream;
+ /* a packet has been received : write it in the store, except
+ if header */
+ if (c->data_count > FFM_PACKET_SIZE) {
+ /* XXX: use llseek or url_seek
+ * XXX: Should probably fail? */
+ if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
+ http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
+
+ if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
+ http_log("Error writing to feed file: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ feed->feed_write_index += FFM_PACKET_SIZE;
+ /* update file size */
+ if (feed->feed_write_index > c->stream->feed_size)
+ feed->feed_size = feed->feed_write_index;
+
+ /* handle wrap around if max file size reached */
+ if (c->stream->feed_max_size &&
+ feed->feed_write_index >= c->stream->feed_max_size)
+ feed->feed_write_index = FFM_PACKET_SIZE;
+
+ /* write index */
+ if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
+ http_log("Error writing index to feed file: %s\n",
+ strerror(errno));
+ goto fail;
+ }
+
+ /* wake up any waiting connections */
+ for(c1 = first_http_ctx; c1; c1 = c1->next) {
+ if (c1->state == HTTPSTATE_WAIT_FEED &&
+ c1->stream->feed == c->stream->feed)
+ c1->state = HTTPSTATE_SEND_DATA;
+ }
+ } else {
+ /* We have a header in our hands that contains useful data */
+ AVFormatContext *s = avformat_alloc_context();
+ AVIOContext *pb;
+ AVInputFormat *fmt_in;
+ int i;
+
+ if (!s)
+ goto fail;
+
+ /* use feed output format name to find corresponding input format */
+ fmt_in = av_find_input_format(feed->fmt->name);
+ if (!fmt_in)
+ goto fail;
+
+ pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
+ 0, NULL, NULL, NULL, NULL);
+ pb->seekable = 0;
+
+ s->pb = pb;
+ if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
+ av_freep(&pb);
+ goto fail;
+ }
+
+ /* Now we have the actual streams */
+ if (s->nb_streams != feed->nb_streams) {
+ avformat_close_input(&s);
+ av_freep(&pb);
+ http_log("Feed '%s' stream number does not match registered feed\n",
+ c->stream->feed_filename);
+ goto fail;
+ }
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *fst = feed->streams[i];
+ AVStream *st = s->streams[i];
+ avcodec_copy_context(fst->codec, st->codec);
+ }
+
+ avformat_close_input(&s);
+ av_freep(&pb);
+ }
+ c->buffer_ptr = c->buffer;
+ }
+
+ return 0;
+ fail:
+ c->stream->feed_opened = 0;
+ close(c->feed_fd);
+ /* wake up any waiting connections to stop waiting for feed */
+ for(c1 = first_http_ctx; c1; c1 = c1->next) {
+ if (c1->state == HTTPSTATE_WAIT_FEED &&
+ c1->stream->feed == c->stream->feed)
+ c1->state = HTTPSTATE_SEND_DATA_TRAILER;
+ }
+ return -1;
+}
+
+/********************************************************************/
+/* RTSP handling */
+
+static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
+{
+ const char *str;
+ time_t ti;
+ struct tm *tm;
+ char buf2[32];
+
+ str = RTSP_STATUS_CODE2STRING(error_number);
+ if (!str)
+ str = "Unknown Error";
+
+ avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
+ avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
+
+ /* output GMT time */
+ ti = time(NULL);
+ tm = gmtime(&ti);
+ strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
+ avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
+}
+
+static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
+{
+ rtsp_reply_header(c, error_number);
+ avio_printf(c->pb, "\r\n");
+}
+
+static int rtsp_parse_request(HTTPContext *c)
+{
+ const char *p, *p1, *p2;
+ char cmd[32];
+ char url[1024];
+ char protocol[32];
+ char line[1024];
+ int len;
+ RTSPMessageHeader header1 = { 0 }, *header = &header1;
+
+ c->buffer_ptr[0] = '\0';
+ p = c->buffer;
+
+ get_word(cmd, sizeof(cmd), &p);
+ get_word(url, sizeof(url), &p);
+ get_word(protocol, sizeof(protocol), &p);
+
+ av_strlcpy(c->method, cmd, sizeof(c->method));
+ av_strlcpy(c->url, url, sizeof(c->url));
+ av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
+
+ if (avio_open_dyn_buf(&c->pb) < 0) {
+ /* XXX: cannot do more */
+ c->pb = NULL; /* safety */
+ return -1;
+ }
+
+ /* check version name */
+ if (strcmp(protocol, "RTSP/1.0")) {
+ rtsp_reply_error(c, RTSP_STATUS_VERSION);
+ goto the_end;
+ }
+
+ /* parse each header line */
+ /* skip to next line */
+ while (*p != '\n' && *p != '\0')
+ p++;
+ if (*p == '\n')
+ p++;
+ while (*p != '\0') {
+ p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
+ if (!p1)
+ break;
+ p2 = p1;
+ if (p2 > p && p2[-1] == '\r')
+ p2--;
+ /* skip empty line */
+ if (p2 == p)
+ break;
+ len = p2 - p;
+ if (len > sizeof(line) - 1)
+ len = sizeof(line) - 1;
+ memcpy(line, p, len);
+ line[len] = '\0';
+ ff_rtsp_parse_line(header, line, NULL, NULL);
+ p = p1 + 1;
+ }
+
+ /* handle sequence number */
+ c->seq = header->seq;
+
+ if (!strcmp(cmd, "DESCRIBE"))
+ rtsp_cmd_describe(c, url);
+ else if (!strcmp(cmd, "OPTIONS"))
+ rtsp_cmd_options(c, url);
+ else if (!strcmp(cmd, "SETUP"))
+ rtsp_cmd_setup(c, url, header);
+ else if (!strcmp(cmd, "PLAY"))
+ rtsp_cmd_play(c, url, header);
+ else if (!strcmp(cmd, "PAUSE"))
+ rtsp_cmd_interrupt(c, url, header, 1);
+ else if (!strcmp(cmd, "TEARDOWN"))
+ rtsp_cmd_interrupt(c, url, header, 0);
+ else
+ rtsp_reply_error(c, RTSP_STATUS_METHOD);
+
+ the_end:
+ len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
+ c->pb = NULL; /* safety */
+ if (len < 0) {
+ /* XXX: cannot do more */
+ return -1;
+ }
+ c->buffer_ptr = c->pb_buffer;
+ c->buffer_end = c->pb_buffer + len;
+ c->state = RTSPSTATE_SEND_REPLY;
+ return 0;
+}
+
+static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
+ struct in_addr my_ip)
+{
+ AVFormatContext *avc;
+ AVStream *avs = NULL;
+ AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
+ AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
+ int i;
+
+ *pbuffer = NULL;
+
+ avc = avformat_alloc_context();
+ if (!avc || !rtp_format) {
+ return -1;
+ }
+ avc->oformat = rtp_format;
+ av_dict_set(&avc->metadata, "title",
+ entry ? entry->value : "No Title", 0);
+ avc->nb_streams = stream->nb_streams;
+ if (stream->is_multicast) {
+ snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
+ inet_ntoa(stream->multicast_ip),
+ stream->multicast_port, stream->multicast_ttl);
+ } else {
+ snprintf(avc->filename, 1024, "rtp://0.0.0.0");
+ }
+
+ avc->streams = av_malloc_array(avc->nb_streams, sizeof(*avc->streams));
+ if (!avc->streams)
+ goto sdp_done;
+
+ avs = av_malloc_array(avc->nb_streams, sizeof(*avs));
+ if (!avs)
+ goto sdp_done;
+
+ for(i = 0; i < stream->nb_streams; i++) {
+ avc->streams[i] = &avs[i];
+ avc->streams[i]->codec = stream->streams[i]->codec;
+ }
+ *pbuffer = av_mallocz(2048);
+ av_sdp_create(&avc, 1, *pbuffer, 2048);
+
+ sdp_done:
+ av_freep(&avc->streams);
+ av_dict_free(&avc->metadata);
+ av_free(avc);
+ av_free(avs);
+
+ return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
+}
+
+static void rtsp_cmd_options(HTTPContext *c, const char *url)
+{
+// rtsp_reply_header(c, RTSP_STATUS_OK);
+ avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
+ avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
+ avio_printf(c->pb, "Public: %s\r\n",
+ "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
+ avio_printf(c->pb, "\r\n");
+}
+
+static void rtsp_cmd_describe(HTTPContext *c, const char *url)
+{
+ FFServerStream *stream;
+ char path1[1024];
+ const char *path;
+ uint8_t *content;
+ int content_length;
+ socklen_t len;
+ struct sockaddr_in my_addr;
+
+ /* find which URL is asked */
+ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
+ path = path1;
+ if (*path == '/')
+ path++;
+
+ for(stream = config.first_stream; stream; stream = stream->next) {
+ if (!stream->is_feed &&
+ stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
+ !strcmp(path, stream->filename)) {
+ goto found;
+ }
+ }
+ /* no stream found */
+ rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
+ return;
+
+ found:
+ /* prepare the media description in SDP format */
+
+ /* get the host IP */
+ len = sizeof(my_addr);
+ getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
+ content_length = prepare_sdp_description(stream, &content,
+ my_addr.sin_addr);
+ if (content_length < 0) {
+ rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
+ return;
+ }
+ rtsp_reply_header(c, RTSP_STATUS_OK);
+ avio_printf(c->pb, "Content-Base: %s/\r\n", url);
+ avio_printf(c->pb, "Content-Type: application/sdp\r\n");
+ avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
+ avio_printf(c->pb, "\r\n");
+ avio_write(c->pb, content, content_length);
+ av_free(content);
+}
+
+static HTTPContext *find_rtp_session(const char *session_id)
+{
+ HTTPContext *c;
+
+ if (session_id[0] == '\0')
+ return NULL;
+
+ for(c = first_http_ctx; c; c = c->next) {
+ if (!strcmp(c->session_id, session_id))
+ return c;
+ }
+ return NULL;
+}
+
+static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
+{
+ RTSPTransportField *th;
+ int i;
+
+ for(i=0;i<h->nb_transports;i++) {
+ th = &h->transports[i];
+ if (th->lower_transport == lower_transport)
+ return th;
+ }
+ return NULL;
+}
+
+static void rtsp_cmd_setup(HTTPContext *c, const char *url,
+ RTSPMessageHeader *h)
+{
+ FFServerStream *stream;
+ int stream_index, rtp_port, rtcp_port;
+ char buf[1024];
+ char path1[1024];
+ const char *path;
+ HTTPContext *rtp_c;
+ RTSPTransportField *th;
+ struct sockaddr_in dest_addr;
+ RTSPActionServerSetup setup;
+
+ /* find which URL is asked */
+ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
+ path = path1;
+ if (*path == '/')
+ path++;
+
+ /* now check each stream */
+ for(stream = config.first_stream; stream; stream = stream->next) {
+ if (stream->is_feed || !stream->fmt ||
+ strcmp(stream->fmt->name, "rtp")) {
+ continue;
+ }
+ /* accept aggregate filenames only if single stream */
+ if (!strcmp(path, stream->filename)) {
+ if (stream->nb_streams != 1) {
+ rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
+ return;
+ }
+ stream_index = 0;
+ goto found;
+ }
+
+ for(stream_index = 0; stream_index < stream->nb_streams;
+ stream_index++) {
+ snprintf(buf, sizeof(buf), "%s/streamid=%d",
+ stream->filename, stream_index);
+ if (!strcmp(path, buf))
+ goto found;
+ }
+ }
+ /* no stream found */
+ rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
+ return;
+ found:
+
+ /* generate session id if needed */
+ if (h->session_id[0] == '\0') {
+ unsigned random0 = av_lfg_get(&random_state);
+ unsigned random1 = av_lfg_get(&random_state);
+ snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
+ random0, random1);
+ }
+
+ /* find RTP session, and create it if none found */
+ rtp_c = find_rtp_session(h->session_id);
+ if (!rtp_c) {
+ /* always prefer UDP */
+ th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
+ if (!th) {
+ th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
+ if (!th) {
+ rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
+ return;
+ }
+ }
+
+ rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
+ th->lower_transport);
+ if (!rtp_c) {
+ rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
+ return;
+ }
+
+ /* open input stream */
+ if (open_input_stream(rtp_c, "") < 0) {
+ rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
+ return;
+ }
+ }
+
+ /* test if stream is OK (test needed because several SETUP needs
+ to be done for a given file) */
+ if (rtp_c->stream != stream) {
+ rtsp_reply_error(c, RTSP_STATUS_SERVICE);
+ return;
+ }
+
+ /* test if stream is already set up */
+ if (rtp_c->rtp_ctx[stream_index]) {
+ rtsp_reply_error(c, RTSP_STATUS_STATE);
+ return;
+ }
+
+ /* check transport */
+ th = find_transport(h, rtp_c->rtp_protocol);
+ if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
+ th->client_port_min <= 0)) {
+ rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
+ return;
+ }
+
+ /* setup default options */
+ setup.transport_option[0] = '\0';
+ dest_addr = rtp_c->from_addr;
+ dest_addr.sin_port = htons(th->client_port_min);
+
+ /* setup stream */
+ if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
+ rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
+ return;
+ }
+
+ /* now everything is OK, so we can send the connection parameters */
+ rtsp_reply_header(c, RTSP_STATUS_OK);
+ /* session ID */
+ avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
+
+ switch(rtp_c->rtp_protocol) {
+ case RTSP_LOWER_TRANSPORT_UDP:
+ rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
+ rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
+ avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
+ "client_port=%d-%d;server_port=%d-%d",
+ th->client_port_min, th->client_port_max,
+ rtp_port, rtcp_port);
+ break;
+ case RTSP_LOWER_TRANSPORT_TCP:
+ avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
+ stream_index * 2, stream_index * 2 + 1);
+ break;
+ default:
+ break;
+ }
+ if (setup.transport_option[0] != '\0')
+ avio_printf(c->pb, ";%s", setup.transport_option);
+ avio_printf(c->pb, "\r\n");
+
+
+ avio_printf(c->pb, "\r\n");
+}
+
+
+/* find an RTP connection by using the session ID. Check consistency
+ with filename */
+static HTTPContext *find_rtp_session_with_url(const char *url,
+ const char *session_id)
+{
+ HTTPContext *rtp_c;
+ char path1[1024];
+ const char *path;
+ char buf[1024];
+ int s, len;
+
+ rtp_c = find_rtp_session(session_id);
+ if (!rtp_c)
+ return NULL;
+
+ /* find which URL is asked */
+ av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
+ path = path1;
+ if (*path == '/')
+ path++;
+ if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
+ for(s=0; s<rtp_c->stream->nb_streams; ++s) {
+ snprintf(buf, sizeof(buf), "%s/streamid=%d",
+ rtp_c->stream->filename, s);
+ if(!strncmp(path, buf, sizeof(buf))) {
+ // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
+ return rtp_c;
+ }
+ }
+ len = strlen(path);
+ if (len > 0 && path[len - 1] == '/' &&
+ !strncmp(path, rtp_c->stream->filename, len - 1))
+ return rtp_c;
+ return NULL;
+}
+
+static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
+{
+ HTTPContext *rtp_c;
+
+ rtp_c = find_rtp_session_with_url(url, h->session_id);
+ if (!rtp_c) {
+ rtsp_reply_error(c, RTSP_STATUS_SESSION);
+ return;
+ }
+
+ if (rtp_c->state != HTTPSTATE_SEND_DATA &&
+ rtp_c->state != HTTPSTATE_WAIT_FEED &&
+ rtp_c->state != HTTPSTATE_READY) {
+ rtsp_reply_error(c, RTSP_STATUS_STATE);
+ return;
+ }
+
+ rtp_c->state = HTTPSTATE_SEND_DATA;
+
+ /* now everything is OK, so we can send the connection parameters */
+ rtsp_reply_header(c, RTSP_STATUS_OK);
+ /* session ID */
+ avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
+ avio_printf(c->pb, "\r\n");
+}
+
+static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
+ RTSPMessageHeader *h, int pause_only)
+{
+ HTTPContext *rtp_c;
+
+ rtp_c = find_rtp_session_with_url(url, h->session_id);
+ if (!rtp_c) {
+ rtsp_reply_error(c, RTSP_STATUS_SESSION);
+ return;
+ }
+
+ if (pause_only) {
+ if (rtp_c->state != HTTPSTATE_SEND_DATA &&
+ rtp_c->state != HTTPSTATE_WAIT_FEED) {
+ rtsp_reply_error(c, RTSP_STATUS_STATE);
+ return;
+ }
+ rtp_c->state = HTTPSTATE_READY;
+ rtp_c->first_pts = AV_NOPTS_VALUE;
+ }
+
+ /* now everything is OK, so we can send the connection parameters */
+ rtsp_reply_header(c, RTSP_STATUS_OK);
+ /* session ID */
+ avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
+ avio_printf(c->pb, "\r\n");
+
+ if (!pause_only)
+ close_connection(rtp_c);
+}
+
+/********************************************************************/
+/* RTP handling */
+
+static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
+ FFServerStream *stream,
+ const char *session_id,
+ enum RTSPLowerTransport rtp_protocol)
+{
+ HTTPContext *c = NULL;
+ const char *proto_str;
+
+ /* XXX: should output a warning page when coming
+ close to the connection limit */
+ if (nb_connections >= config.nb_max_connections)
+ goto fail;
+
+ /* add a new connection */
+ c = av_mallocz(sizeof(HTTPContext));
+ if (!c)
+ goto fail;
+
+ c->fd = -1;
+ c->poll_entry = NULL;
+ c->from_addr = *from_addr;
+ c->buffer_size = IOBUFFER_INIT_SIZE;
+ c->buffer = av_malloc(c->buffer_size);
+ if (!c->buffer)
+ goto fail;
+ nb_connections++;
+ c->stream = stream;
+ av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
+ c->state = HTTPSTATE_READY;
+ c->is_packetized = 1;
+ c->rtp_protocol = rtp_protocol;
+
+ /* protocol is shown in statistics */
+ switch(c->rtp_protocol) {
+ case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
+ proto_str = "MCAST";
+ break;
+ case RTSP_LOWER_TRANSPORT_UDP:
+ proto_str = "UDP";
+ break;
+ case RTSP_LOWER_TRANSPORT_TCP:
+ proto_str = "TCP";
+ break;
+ default:
+ proto_str = "???";
+ break;
+ }
+ av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
+ av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
+
+ current_bandwidth += stream->bandwidth;
+
+ c->next = first_http_ctx;
+ first_http_ctx = c;
+ return c;
+
+ fail:
+ if (c) {
+ av_freep(&c->buffer);
+ av_free(c);
+ }
+ return NULL;
+}
+
+/* add a new RTP stream in an RTP connection (used in RTSP SETUP
+ command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
+ used. */
+static int rtp_new_av_stream(HTTPContext *c,
+ int stream_index, struct sockaddr_in *dest_addr,
+ HTTPContext *rtsp_c)
+{
+ AVFormatContext *ctx;
+ AVStream *st;
+ char *ipaddr;
+ URLContext *h = NULL;
+ uint8_t *dummy_buf;
+ int max_packet_size;
+
+ /* now we can open the relevant output stream */
+ ctx = avformat_alloc_context();
+ if (!ctx)
+ return -1;
+ ctx->oformat = av_guess_format("rtp", NULL, NULL);
+
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ goto fail;
+ ctx->nb_streams = 1;
+ ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
+ if (!ctx->streams)
+ goto fail;
+ ctx->streams[0] = st;
+
+ if (!c->stream->feed ||
+ c->stream->feed == c->stream)
+ memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
+ else
+ memcpy(st,
+ c->stream->feed->streams[c->stream->feed_streams[stream_index]],
+ sizeof(AVStream));
+ st->priv_data = NULL;
+
+ /* build destination RTP address */
+ ipaddr = inet_ntoa(dest_addr->sin_addr);
+
+ switch(c->rtp_protocol) {
+ case RTSP_LOWER_TRANSPORT_UDP:
+ case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
+ /* RTP/UDP case */
+
+ /* XXX: also pass as parameter to function ? */
+ if (c->stream->is_multicast) {
+ int ttl;
+ ttl = c->stream->multicast_ttl;
+ if (!ttl)
+ ttl = 16;
+ snprintf(ctx->filename, sizeof(ctx->filename),
+ "rtp://%s:%d?multicast=1&ttl=%d",
+ ipaddr, ntohs(dest_addr->sin_port), ttl);
+ } else {
+ snprintf(ctx->filename, sizeof(ctx->filename),
+ "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
+ }
+
+ if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
+ goto fail;
+ c->rtp_handles[stream_index] = h;
+ max_packet_size = h->max_packet_size;
+ break;
+ case RTSP_LOWER_TRANSPORT_TCP:
+ /* RTP/TCP case */
+ c->rtsp_c = rtsp_c;
+ max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
+ break;
+ default:
+ goto fail;
+ }
+
+ http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
+ ipaddr, ntohs(dest_addr->sin_port),
+ c->stream->filename, stream_index, c->protocol);
+
+ /* normally, no packets should be output here, but the packet size may
+ * be checked */
+ if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
+ /* XXX: close stream */
+ goto fail;
+ }
+ if (avformat_write_header(ctx, NULL) < 0) {
+ fail:
+ if (h)
+ ffurl_close(h);
+ av_free(st);
+ av_free(ctx);
+ return -1;
+ }
+ avio_close_dyn_buf(ctx->pb, &dummy_buf);
+ av_free(dummy_buf);
+
+ c->rtp_ctx[stream_index] = ctx;
+ return 0;
+}
+
+/********************************************************************/
+/* ffserver initialization */
+
+static AVStream *add_av_stream1(FFServerStream *stream,
+ AVCodecContext *codec, int copy)
+{
+ AVStream *fst;
+
+ if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
+ return NULL;
+
+ fst = av_mallocz(sizeof(AVStream));
+ if (!fst)
+ return NULL;
+ if (copy) {
+ fst->codec = avcodec_alloc_context3(codec->codec);
+ avcodec_copy_context(fst->codec, codec);
+ } else {
+ /* live streams must use the actual feed's codec since it may be
+ * updated later to carry extradata needed by them.
+ */
+ fst->codec = codec;
+ }
+ fst->priv_data = av_mallocz(sizeof(FeedData));
+ fst->index = stream->nb_streams;
+ avpriv_set_pts_info(fst, 33, 1, 90000);
+ fst->sample_aspect_ratio = codec->sample_aspect_ratio;
+ stream->streams[stream->nb_streams++] = fst;
+ return fst;
+}
+
+/* return the stream number in the feed */
+static int add_av_stream(FFServerStream *feed, AVStream *st)
+{
+ AVStream *fst;
+ AVCodecContext *av, *av1;
+ int i;
+
+ av = st->codec;
+ for(i=0;i<feed->nb_streams;i++) {
+ av1 = feed->streams[i]->codec;
+ if (av1->codec_id == av->codec_id &&
+ av1->codec_type == av->codec_type &&
+ av1->bit_rate == av->bit_rate) {
+
+ switch(av->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (av1->channels == av->channels &&
+ av1->sample_rate == av->sample_rate)
+ return i;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (av1->width == av->width &&
+ av1->height == av->height &&
+ av1->time_base.den == av->time_base.den &&
+ av1->time_base.num == av->time_base.num &&
+ av1->gop_size == av->gop_size)
+ return i;
+ break;
+ default:
+ abort();
+ }
+ }
+ }
+
+ fst = add_av_stream1(feed, av, 0);
+ if (!fst)
+ return -1;
+ if (av_stream_get_recommended_encoder_configuration(st))
+ av_stream_set_recommended_encoder_configuration(fst,
+ av_strdup(av_stream_get_recommended_encoder_configuration(st)));
+ return feed->nb_streams - 1;
+}
+
+static void remove_stream(FFServerStream *stream)
+{
+ FFServerStream **ps;
+ ps = &config.first_stream;
+ while (*ps) {
+ if (*ps == stream)
+ *ps = (*ps)->next;
+ else
+ ps = &(*ps)->next;
+ }
+}
+
+/* specific MPEG4 handling : we extract the raw parameters */
+static void extract_mpeg4_header(AVFormatContext *infile)
+{
+ int mpeg4_count, i, size;
+ AVPacket pkt;
+ AVStream *st;
+ const uint8_t *p;
+
+ infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
+
+ mpeg4_count = 0;
+ for(i=0;i<infile->nb_streams;i++) {
+ st = infile->streams[i];
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
+ st->codec->extradata_size == 0) {
+ mpeg4_count++;
+ }
+ }
+ if (!mpeg4_count)
+ return;
+
+ printf("MPEG4 without extra data: trying to find header in %s\n",
+ infile->filename);
+ while (mpeg4_count > 0) {
+ if (av_read_frame(infile, &pkt) < 0)
+ break;
+ st = infile->streams[pkt.stream_index];
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
+ st->codec->extradata_size == 0) {
+ av_freep(&st->codec->extradata);
+ /* fill extradata with the header */
+ /* XXX: we make hard suppositions here ! */
+ p = pkt.data;
+ while (p < pkt.data + pkt.size - 4) {
+ /* stop when vop header is found */
+ if (p[0] == 0x00 && p[1] == 0x00 &&
+ p[2] == 0x01 && p[3] == 0xb6) {
+ size = p - pkt.data;
+ st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ st->codec->extradata_size = size;
+ memcpy(st->codec->extradata, pkt.data, size);
+ break;
+ }
+ p++;
+ }
+ mpeg4_count--;
+ }
+ av_free_packet(&pkt);
+ }
+}
+
+/* compute the needed AVStream for each file */
+static void build_file_streams(void)
+{
+ FFServerStream *stream, *stream_next;
+ int i, ret;
+
+ /* gather all streams */
+ for(stream = config.first_stream; stream; stream = stream_next) {
+ AVFormatContext *infile = NULL;
+ stream_next = stream->next;
+ if (stream->stream_type == STREAM_TYPE_LIVE &&
+ !stream->feed) {
+ /* the stream comes from a file */
+ /* try to open the file */
+ /* open stream */
+ if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
+ /* specific case : if transport stream output to RTP,
+ we use a raw transport stream reader */
+ av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
+ }
+
+ if (!stream->feed_filename[0]) {
+ http_log("Unspecified feed file for stream '%s'\n",
+ stream->filename);
+ goto fail;
+ }
+
+ http_log("Opening feed file '%s' for stream '%s'\n",
+ stream->feed_filename, stream->filename);
+ ret = avformat_open_input(&infile, stream->feed_filename,
+ stream->ifmt, &stream->in_opts);
+ if (ret < 0) {
+ http_log("Could not open '%s': %s\n", stream->feed_filename,
+ av_err2str(ret));
+ /* remove stream (no need to spend more time on it) */
+ fail:
+ remove_stream(stream);
+ } else {
+ /* find all the AVStreams inside and reference them in
+ 'stream' */
+ if (avformat_find_stream_info(infile, NULL) < 0) {
+ http_log("Could not find codec parameters from '%s'\n",
+ stream->feed_filename);
+ avformat_close_input(&infile);
+ goto fail;
+ }
+ extract_mpeg4_header(infile);
+
+ for(i=0;i<infile->nb_streams;i++)
+ add_av_stream1(stream, infile->streams[i]->codec, 1);
+
+ avformat_close_input(&infile);
+ }
+ }
+ }
+}
+
+/* compute the needed AVStream for each feed */
+static void build_feed_streams(void)
+{
+ FFServerStream *stream, *feed;
+ int i;
+
+ /* gather all streams */
+ for(stream = config.first_stream; stream; stream = stream->next) {
+ feed = stream->feed;
+ if (feed) {
+ if (stream->is_feed) {
+ for(i=0;i<stream->nb_streams;i++)
+ stream->feed_streams[i] = i;
+ } else {
+ /* we handle a stream coming from a feed */
+ for(i=0;i<stream->nb_streams;i++)
+ stream->feed_streams[i] = add_av_stream(feed,
+ stream->streams[i]);
+ }
+ }
+ }
+
+ /* create feed files if needed */
+ for(feed = config.first_feed; feed; feed = feed->next_feed) {
+ int fd;
+
+ if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
+ /* See if it matches */
+ AVFormatContext *s = NULL;
+ int matches = 0;
+
+ if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
+ /* set buffer size */
+ ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
+ /* Now see if it matches */
+ if (s->nb_streams == feed->nb_streams) {
+ matches = 1;
+ for(i=0;i<s->nb_streams;i++) {
+ AVStream *sf, *ss;
+ sf = feed->streams[i];
+ ss = s->streams[i];
+
+ if (sf->index != ss->index ||
+ sf->id != ss->id) {
+ http_log("Index & Id do not match for stream %d (%s)\n",
+ i, feed->feed_filename);
+ matches = 0;
+ } else {
+ AVCodecContext *ccf, *ccs;
+
+ ccf = sf->codec;
+ ccs = ss->codec;
+#define CHECK_CODEC(x) (ccf->x != ccs->x)
+
+ if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
+ http_log("Codecs do not match for stream %d\n", i);
+ matches = 0;
+ } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
+ http_log("Codec bitrates do not match for stream %d\n", i);
+ matches = 0;
+ } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (CHECK_CODEC(time_base.den) ||
+ CHECK_CODEC(time_base.num) ||
+ CHECK_CODEC(width) ||
+ CHECK_CODEC(height)) {
+ http_log("Codec width, height and framerate do not match for stream %d\n", i);
+ matches = 0;
+ }
+ } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (CHECK_CODEC(sample_rate) ||
+ CHECK_CODEC(channels) ||
+ CHECK_CODEC(frame_size)) {
+ http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
+ matches = 0;
+ }
+ } else {
+ http_log("Unknown codec type\n");
+ matches = 0;
+ }
+ }
+ if (!matches)
+ break;
+ }
+ } else
+ http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
+ feed->feed_filename, s->nb_streams, feed->nb_streams);
+
+ avformat_close_input(&s);
+ } else
+ http_log("Deleting feed file '%s' as it appears to be corrupt\n",
+ feed->feed_filename);
+
+ if (!matches) {
+ if (feed->readonly) {
+ http_log("Unable to delete feed file '%s' as it is marked readonly\n",
+ feed->feed_filename);
+ exit(1);
+ }
+ unlink(feed->feed_filename);
+ }
+ }
+ if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
+ AVFormatContext *s = avformat_alloc_context();
+
+ if (feed->readonly) {
+ http_log("Unable to create feed file '%s' as it is marked readonly\n",
+ feed->feed_filename);
+ exit(1);
+ }
+
+ /* only write the header of the ffm file */
+ if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
+ http_log("Could not open output feed file '%s'\n",
+ feed->feed_filename);
+ exit(1);
+ }
+ s->oformat = feed->fmt;
+ s->nb_streams = feed->nb_streams;
+ s->streams = feed->streams;
+ if (avformat_write_header(s, NULL) < 0) {
+ http_log("Container doesn't support the required parameters\n");
+ exit(1);
+ }
+ /* XXX: need better API */
+ av_freep(&s->priv_data);
+ avio_closep(&s->pb);
+ s->streams = NULL;
+ s->nb_streams = 0;
+ avformat_free_context(s);
+ }
+ /* get feed size and write index */
+ fd = open(feed->feed_filename, O_RDONLY);
+ if (fd < 0) {
+ http_log("Could not open output feed file '%s'\n",
+ feed->feed_filename);
+ exit(1);
+ }
+
+ feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
+ feed->feed_size = lseek(fd, 0, SEEK_END);
+ /* ensure that we do not wrap before the end of file */
+ if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
+ feed->feed_max_size = feed->feed_size;
+
+ close(fd);
+ }
+}
+
+/* compute the bandwidth used by each stream */
+static void compute_bandwidth(void)
+{
+ unsigned bandwidth;
+ int i;
+ FFServerStream *stream;
+
+ for(stream = config.first_stream; stream; stream = stream->next) {
+ bandwidth = 0;
+ for(i=0;i<stream->nb_streams;i++) {
+ AVStream *st = stream->streams[i];
+ switch(st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ case AVMEDIA_TYPE_VIDEO:
+ bandwidth += st->codec->bit_rate;
+ break;
+ default:
+ break;
+ }
+ }
+ stream->bandwidth = (bandwidth + 999) / 1000;
+ }
+}
+
+static void handle_child_exit(int sig)
+{
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ FFServerStream *feed;
+
+ for (feed = config.first_feed; feed; feed = feed->next) {
+ if (feed->pid == pid) {
+ int uptime = time(0) - feed->pid_start;
+
+ feed->pid = 0;
+ fprintf(stderr,
+ "%s: Pid %d exited with status %d after %d seconds\n",
+ feed->filename, pid, status, uptime);
+
+ if (uptime < 30)
+ /* Turn off any more restarts */
+ ffserver_free_child_args(&feed->child_argv);
+ }
+ }
+ }
+
+ need_to_start_children = 1;
+}
+
+static void opt_debug(void)
+{
+ config.debug = 1;
+ snprintf(config.logfilename, sizeof(config.logfilename), "-");
+}
+
+void show_help_default(const char *opt, const char *arg)
+{
+ printf("usage: ffserver [options]\n"
+ "Hyper fast multi format Audio/Video streaming server\n");
+ printf("\n");
+ show_help_options(options, "Main options:", 0, 0, 0);
+}
+
+static const OptionDef options[] = {
+#include "cmdutils_common_opts.h"
+ { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
+ { "d", 0, {(void*)opt_debug}, "enable debug mode" },
+ { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
+ { NULL },
+};
+
+int main(int argc, char **argv)
+{
+ struct sigaction sigact = { { 0 } };
+ int ret = 0;
+
+ config.filename = av_strdup("/etc/ffserver.conf");
+
+ parse_loglevel(argc, argv, options);
+ av_register_all();
+ avformat_network_init();
+
+ show_banner(argc, argv, options);
+
+ my_program_name = argv[0];
+
+ parse_options(NULL, argc, argv, options, NULL);
+
+ unsetenv("http_proxy"); /* Kill the http_proxy */
+
+ av_lfg_init(&random_state, av_get_random_seed());
+
+ sigact.sa_handler = handle_child_exit;
+ sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+ sigaction(SIGCHLD, &sigact, 0);
+
+ if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
+ fprintf(stderr, "Error reading configuration file '%s': %s\n",
+ config.filename, av_err2str(ret));
+ exit(1);
+ }
+ av_freep(&config.filename);
+
+ /* open log file if needed */
+ if (config.logfilename[0] != '\0') {
+ if (!strcmp(config.logfilename, "-"))
+ logfile = stdout;
+ else
+ logfile = fopen(config.logfilename, "a");
+ av_log_set_callback(http_av_log);
+ }
+
+ build_file_streams();
+
+ build_feed_streams();
+
+ compute_bandwidth();
+
+ /* signal init */
+ signal(SIGPIPE, SIG_IGN);
+
+ if (http_server() < 0) {
+ http_log("Could not start server\n");
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/ffserver_config.c b/ffserver_config.c
new file mode 100644
index 0000000000..017af48434
--- /dev/null
+++ b/ffserver_config.c
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <float.h>
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/avstring.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
+
+// FIXME those are internal headers, ffserver _really_ shouldn't use them
+#include "libavformat/ffm.h"
+
+#include "cmdutils.h"
+#include "ffserver_config.h"
+
+#define MAX_CHILD_ARGS 64
+
+static int ffserver_save_avoption(const char *opt, const char *arg, int type,
+ FFServerConfig *config);
+static void vreport_config_error(const char *filename, int line_num,
+ int log_level, int *errors, const char *fmt,
+ va_list vl);
+static void report_config_error(const char *filename, int line_num,
+ int log_level, int *errors, const char *fmt,
+ ...);
+
+#define ERROR(...) report_config_error(config->filename, config->line_num,\
+ AV_LOG_ERROR, &config->errors, __VA_ARGS__)
+#define WARNING(...) report_config_error(config->filename, config->line_num,\
+ AV_LOG_WARNING, &config->warnings, __VA_ARGS__)
+
+/* FIXME: make ffserver work with IPv6 */
+/* resolve host with also IP address parsing */
+static int resolve_host(struct in_addr *sin_addr, const char *hostname)
+{
+
+ if (!ff_inet_aton(hostname, sin_addr)) {
+#if HAVE_GETADDRINFO
+ struct addrinfo *ai, *cur;
+ struct addrinfo hints = { 0 };
+ hints.ai_family = AF_INET;
+ if (getaddrinfo(hostname, NULL, &hints, &ai))
+ return -1;
+ /* getaddrinfo returns a linked list of addrinfo structs.
+ * Even if we set ai_family = AF_INET above, make sure
+ * that the returned one actually is of the correct type. */
+ for (cur = ai; cur; cur = cur->ai_next) {
+ if (cur->ai_family == AF_INET) {
+ *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
+ freeaddrinfo(ai);
+ return 0;
+ }
+ }
+ freeaddrinfo(ai);
+ return -1;
+#else
+ struct hostent *hp;
+ hp = gethostbyname(hostname);
+ if (!hp)
+ return -1;
+ memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
+#endif
+ }
+ return 0;
+}
+
+void ffserver_get_arg(char *buf, int buf_size, const char **pp)
+{
+ const char *p;
+ char *q;
+ int quote = 0;
+
+ p = *pp;
+ q = buf;
+
+ while (av_isspace(*p)) p++;
+
+ if (*p == '\"' || *p == '\'')
+ quote = *p++;
+
+ while (*p != '\0') {
+ if (quote && *p == quote || !quote && av_isspace(*p))
+ break;
+ if ((q - buf) < buf_size - 1)
+ *q++ = *p;
+ p++;
+ }
+
+ *q = '\0';
+ if (quote && *p == quote)
+ p++;
+ *pp = p;
+}
+
+void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,
+ FFServerIPAddressACL *ext_acl,
+ const char *p, const char *filename, int line_num)
+{
+ char arg[1024];
+ FFServerIPAddressACL acl;
+ int errors = 0;
+
+ ffserver_get_arg(arg, sizeof(arg), &p);
+ if (av_strcasecmp(arg, "allow") == 0)
+ acl.action = IP_ALLOW;
+ else if (av_strcasecmp(arg, "deny") == 0)
+ acl.action = IP_DENY;
+ else {
+ fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n",
+ filename, line_num, arg);
+ errors++;
+ }
+
+ ffserver_get_arg(arg, sizeof(arg), &p);
+
+ if (resolve_host(&acl.first, arg)) {
+ fprintf(stderr,
+ "%s:%d: ACL refers to invalid host or IP address '%s'\n",
+ filename, line_num, arg);
+ errors++;
+ } else
+ acl.last = acl.first;
+
+ ffserver_get_arg(arg, sizeof(arg), &p);
+
+ if (arg[0]) {
+ if (resolve_host(&acl.last, arg)) {
+ fprintf(stderr,
+ "%s:%d: ACL refers to invalid host or IP address '%s'\n",
+ filename, line_num, arg);
+ errors++;
+ }
+ }
+
+ if (!errors) {
+ FFServerIPAddressACL *nacl = av_mallocz(sizeof(*nacl));
+ FFServerIPAddressACL **naclp = 0;
+
+ acl.next = 0;
+ *nacl = acl;
+
+ if (stream)
+ naclp = &stream->acl;
+ else if (feed)
+ naclp = &feed->acl;
+ else if (ext_acl)
+ naclp = &ext_acl;
+ else {
+ fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n",
+ filename, line_num);
+ errors++;
+ }
+
+ if (naclp) {
+ while (*naclp)
+ naclp = &(*naclp)->next;
+
+ *naclp = nacl;
+ } else
+ av_free(nacl);
+ }
+}
+
+/* add a codec and set the default parameters */
+static void add_codec(FFServerStream *stream, AVCodecContext *av,
+ FFServerConfig *config)
+{
+ AVStream *st;
+ AVDictionary **opts, *recommended = NULL;
+ char *enc_config;
+
+ if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
+ return;
+
+ opts = av->codec_type == AVMEDIA_TYPE_AUDIO ?
+ &config->audio_opts : &config->video_opts;
+ av_dict_copy(&recommended, *opts, 0);
+ av_opt_set_dict2(av->priv_data, opts, AV_OPT_SEARCH_CHILDREN);
+ av_opt_set_dict2(av, opts, AV_OPT_SEARCH_CHILDREN);
+
+ if (av_dict_count(*opts))
+ av_log(NULL, AV_LOG_WARNING,
+ "Something is wrong, %d options are not set!\n",
+ av_dict_count(*opts));
+
+ if (!config->stream_use_defaults) {
+ switch(av->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (av->bit_rate == 0)
+ report_config_error(config->filename, config->line_num,
+ AV_LOG_ERROR, &config->errors,
+ "audio bit rate is not set\n");
+ if (av->sample_rate == 0)
+ report_config_error(config->filename, config->line_num,
+ AV_LOG_ERROR, &config->errors,
+ "audio sample rate is not set\n");
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (av->width == 0 || av->height == 0)
+ report_config_error(config->filename, config->line_num,
+ AV_LOG_ERROR, &config->errors,
+ "video size is not set\n");
+ break;
+ default:
+ av_assert0(0);
+ }
+ goto done;
+ }
+
+ /* stream_use_defaults = true */
+
+ /* compute default parameters */
+ switch(av->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ if (!av_dict_get(recommended, "ab", NULL, 0)) {
+ av->bit_rate = 64000;
+ av_dict_set_int(&recommended, "ab", av->bit_rate, 0);
+ WARNING("Setting default value for audio bit rate = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->bit_rate);
+ }
+ if (!av_dict_get(recommended, "ar", NULL, 0)) {
+ av->sample_rate = 22050;
+ av_dict_set_int(&recommended, "ar", av->sample_rate, 0);
+ WARNING("Setting default value for audio sample rate = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->sample_rate);
+ }
+ if (!av_dict_get(recommended, "ac", NULL, 0)) {
+ av->channels = 1;
+ av_dict_set_int(&recommended, "ac", av->channels, 0);
+ WARNING("Setting default value for audio channel count = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->channels);
+ }
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ if (!av_dict_get(recommended, "b", NULL, 0)) {
+ av->bit_rate = 64000;
+ av_dict_set_int(&recommended, "b", av->bit_rate, 0);
+ WARNING("Setting default value for video bit rate = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->bit_rate);
+ }
+ if (!av_dict_get(recommended, "time_base", NULL, 0)){
+ av->time_base.den = 5;
+ av->time_base.num = 1;
+ av_dict_set(&recommended, "time_base", "1/5", 0);
+ WARNING("Setting default value for video frame rate = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->time_base.den);
+ }
+ if (!av_dict_get(recommended, "video_size", NULL, 0)) {
+ av->width = 160;
+ av->height = 128;
+ av_dict_set(&recommended, "video_size", "160x128", 0);
+ WARNING("Setting default value for video size = %dx%d. "
+ "Use NoDefaults to disable it.\n",
+ av->width, av->height);
+ }
+ /* Bitrate tolerance is less for streaming */
+ if (!av_dict_get(recommended, "bt", NULL, 0)) {
+ av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
+ (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
+ av_dict_set_int(&recommended, "bt", av->bit_rate_tolerance, 0);
+ WARNING("Setting default value for video bit rate tolerance = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->bit_rate_tolerance);
+ }
+
+ if (!av_dict_get(recommended, "rc_eq", NULL, 0)) {
+ av->rc_eq = av_strdup("tex^qComp");
+ av_dict_set(&recommended, "rc_eq", "tex^qComp", 0);
+ WARNING("Setting default value for video rate control equation = "
+ "%s. Use NoDefaults to disable it.\n",
+ av->rc_eq);
+ }
+ if (!av_dict_get(recommended, "maxrate", NULL, 0)) {
+ av->rc_max_rate = av->bit_rate * 2;
+ av_dict_set_int(&recommended, "maxrate", av->rc_max_rate, 0);
+ WARNING("Setting default value for video max rate = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->rc_max_rate);
+ }
+
+ if (av->rc_max_rate && !av_dict_get(recommended, "bufsize", NULL, 0)) {
+ av->rc_buffer_size = av->rc_max_rate;
+ av_dict_set_int(&recommended, "bufsize", av->rc_buffer_size, 0);
+ WARNING("Setting default value for video buffer size = %d. "
+ "Use NoDefaults to disable it.\n",
+ av->rc_buffer_size);
+ }
+ break;
+ default:
+ abort();
+ }
+
+done:
+ st = av_mallocz(sizeof(AVStream));
+ if (!st)
+ return;
+ av_dict_get_string(recommended, &enc_config, '=', ',');
+ av_dict_free(&recommended);
+ av_stream_set_recommended_encoder_configuration(st, enc_config);
+ st->codec = av;
+ stream->streams[stream->nb_streams++] = st;
+}
+
+static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name,
+ FFServerConfig *config)
+{
+ int ret;
+ AVCodec *codec = avcodec_find_encoder_by_name(codec_name);
+ if (!codec || codec->type != ctx->codec_type) {
+ report_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors,
+ "Invalid codec name: '%s'\n", codec_name);
+ return 0;
+ }
+ if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) {
+ if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0)
+ return ret;
+ ctx->codec = codec;
+ }
+ if (ctx->codec_id != codec->id)
+ report_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors,
+ "Inconsistent configuration: trying to set '%s' "
+ "codec option, but '%s' codec is used previously\n",
+ codec_name, avcodec_get_name(ctx->codec_id));
+ return 0;
+}
+
+static int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config)
+{
+ FILE *f=NULL;
+ char filename[1000], tmp[1000], tmp2[1000], line[1000];
+ int ret = 0;
+ AVCodecContext *avctx;
+ const AVCodec *codec;
+
+ switch(type) {
+ case AV_OPT_FLAG_AUDIO_PARAM:
+ avctx = config->dummy_actx;
+ break;
+ case AV_OPT_FLAG_VIDEO_PARAM:
+ avctx = config->dummy_vctx;
+ break;
+ default:
+ av_assert0(0);
+ }
+ codec = avcodec_find_encoder(avctx->codec_id);
+
+ if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
+ codec ? codec->name : NULL))) {
+ av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg);
+ return AVERROR(EINVAL);
+ }
+
+ while(!feof(f)){
+ int e= fscanf(f, "%999[^\n]\n", line) - 1;
+ if(line[0] == '#' && !e)
+ continue;
+ e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
+ if(e){
+ av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename,
+ line);
+ ret = AVERROR(EINVAL);
+ break;
+ }
+ if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO ||
+ !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ {
+ if (ffserver_set_codec(avctx, tmp2, config) < 0)
+ break;
+ } else if (!strcmp(tmp, "scodec")) {
+ av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n");
+ ret = AVERROR(EINVAL);
+ break;
+ } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0)
+ break;
+ }
+
+ fclose(f);
+
+ return ret;
+}
+
+static AVOutputFormat *ffserver_guess_format(const char *short_name,
+ const char *filename,
+ const char *mime_type)
+{
+ AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
+
+ if (fmt) {
+ AVOutputFormat *stream_fmt;
+ char stream_format_name[64];
+
+ snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream",
+ fmt->name);
+ stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
+
+ if (stream_fmt)
+ fmt = stream_fmt;
+ }
+
+ return fmt;
+}
+
+static void vreport_config_error(const char *filename, int line_num,
+ int log_level, int *errors, const char *fmt,
+ va_list vl)
+{
+ av_log(NULL, log_level, "%s:%d: ", filename, line_num);
+ av_vlog(NULL, log_level, fmt, vl);
+ if (errors)
+ (*errors)++;
+}
+
+static void report_config_error(const char *filename, int line_num,
+ int log_level, int *errors,
+ const char *fmt, ...)
+{
+ va_list vl;
+ va_start(vl, fmt);
+ vreport_config_error(filename, line_num, log_level, errors, fmt, vl);
+ va_end(vl);
+}
+
+static int ffserver_set_int_param(int *dest, const char *value, int factor,
+ int min, int max, FFServerConfig *config,
+ const char *error_msg, ...)
+{
+ int tmp;
+ char *tailp;
+ if (!value || !value[0])
+ goto error;
+ errno = 0;
+ tmp = strtol(value, &tailp, 0);
+ if (tmp < min || tmp > max)
+ goto error;
+ if (factor) {
+ if (FFABS(tmp) > INT_MAX / FFABS(factor))
+ goto error;
+ tmp *= factor;
+ }
+ if (tailp[0] || errno)
+ goto error;
+ if (dest)
+ *dest = tmp;
+ return 0;
+ error:
+ if (config) {
+ va_list vl;
+ va_start(vl, error_msg);
+ vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors, error_msg, vl);
+ va_end(vl);
+ }
+ return AVERROR(EINVAL);
+}
+
+static int ffserver_set_float_param(float *dest, const char *value,
+ float factor, float min, float max,
+ FFServerConfig *config,
+ const char *error_msg, ...)
+{
+ double tmp;
+ char *tailp;
+ if (!value || !value[0])
+ goto error;
+ errno = 0;
+ tmp = strtod(value, &tailp);
+ if (tmp < min || tmp > max)
+ goto error;
+ if (factor)
+ tmp *= factor;
+ if (tailp[0] || errno)
+ goto error;
+ if (dest)
+ *dest = tmp;
+ return 0;
+ error:
+ if (config) {
+ va_list vl;
+ va_start(vl, error_msg);
+ vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors, error_msg, vl);
+ va_end(vl);
+ }
+ return AVERROR(EINVAL);
+}
+
+static int ffserver_save_avoption(const char *opt, const char *arg, int type,
+ FFServerConfig *config)
+{
+ static int hinted = 0;
+ int ret = 0;
+ AVDictionaryEntry *e;
+ const AVOption *o = NULL;
+ const char *option = NULL;
+ const char *codec_name = NULL;
+ char buff[1024];
+ AVCodecContext *ctx;
+ AVDictionary **dict;
+ enum AVCodecID guessed_codec_id;
+
+ switch (type) {
+ case AV_OPT_FLAG_VIDEO_PARAM:
+ ctx = config->dummy_vctx;
+ dict = &config->video_opts;
+ guessed_codec_id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ?
+ config->guessed_video_codec_id : AV_CODEC_ID_H264;
+ break;
+ case AV_OPT_FLAG_AUDIO_PARAM:
+ ctx = config->dummy_actx;
+ dict = &config->audio_opts;
+ guessed_codec_id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ?
+ config->guessed_audio_codec_id : AV_CODEC_ID_AAC;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ if (strchr(opt, ':')) {
+ //explicit private option
+ snprintf(buff, sizeof(buff), "%s", opt);
+ codec_name = buff;
+ if(!(option = strchr(buff, ':'))){
+ report_config_error(config->filename, config->line_num,
+ AV_LOG_ERROR, &config->errors,
+ "Syntax error. Unmatched ':'\n");
+ return -1;
+
+ }
+ buff[option - buff] = '\0';
+ option++;
+ if ((ret = ffserver_set_codec(ctx, codec_name, config)) < 0)
+ return ret;
+ if (!ctx->codec || !ctx->priv_data)
+ return -1;
+ } else {
+ option = opt;
+ }
+
+ o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM,
+ AV_OPT_SEARCH_CHILDREN);
+ if (!o &&
+ (!strcmp(option, "time_base") || !strcmp(option, "pixel_format") ||
+ !strcmp(option, "video_size") || !strcmp(option, "codec_tag")))
+ o = av_opt_find(ctx, option, NULL, 0, 0);
+ if (!o) {
+ report_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors, "Option not found: '%s'\n", opt);
+ if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) {
+ hinted = 1;
+ report_config_error(config->filename, config->line_num,
+ AV_LOG_ERROR, NULL, "If '%s' is a codec private"
+ "option, then prefix it with codec name, for "
+ "example '%s:%s %s' or define codec earlier.\n",
+ opt, avcodec_get_name(guessed_codec_id) ,opt,
+ arg);
+ }
+ } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) {
+ report_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors, "Invalid value for option %s (%s): %s\n", opt,
+ arg, av_err2str(ret));
+ } else if ((e = av_dict_get(*dict, option, NULL, 0))) {
+ if ((o->type == AV_OPT_TYPE_FLAGS) && arg &&
+ (arg[0] == '+' || arg[0] == '-'))
+ return av_dict_set(dict, option, arg, AV_DICT_APPEND);
+ report_config_error(config->filename, config->line_num, AV_LOG_ERROR,
+ &config->errors, "Redeclaring value of option '%s'."
+ "Previous value was: '%s'.\n", opt, e->value);
+ } else if (av_dict_set(dict, option, arg, 0) < 0) {
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+}
+
+static int ffserver_save_avoption_int(const char *opt, int64_t arg,
+ int type, FFServerConfig *config)
+{
+ char buf[22];
+ snprintf(buf, sizeof(buf), "%"PRId64, arg);
+ return ffserver_save_avoption(opt, buf, type, config);
+}
+
+static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd,
+ const char **p)
+{
+ int val;
+ char arg[1024];
+ if (!av_strcasecmp(cmd, "Port") || !av_strcasecmp(cmd, "HTTPPort")) {
+ if (!av_strcasecmp(cmd, "Port"))
+ WARNING("Port option is deprecated. Use HTTPPort instead.\n");
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
+ "Invalid port: %s\n", arg);
+ if (val < 1024)
+ WARNING("Trying to use IETF assigned system port: '%d'\n", val);
+ config->http_addr.sin_port = htons(val);
+ } else if (!av_strcasecmp(cmd, "HTTPBindAddress") ||
+ !av_strcasecmp(cmd, "BindAddress")) {
+ if (!av_strcasecmp(cmd, "BindAddress"))
+ WARNING("BindAddress option is deprecated. Use HTTPBindAddress "
+ "instead.\n");
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (resolve_host(&config->http_addr.sin_addr, arg))
+ ERROR("Invalid host/IP address: '%s'\n", arg);
+ } else if (!av_strcasecmp(cmd, "NoDaemon")) {
+ WARNING("NoDaemon option has no effect. You should remove it.\n");
+ } else if (!av_strcasecmp(cmd, "RTSPPort")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
+ "Invalid port: %s\n", arg);
+ config->rtsp_addr.sin_port = htons(val);
+ } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (resolve_host(&config->rtsp_addr.sin_addr, arg))
+ ERROR("Invalid host/IP address: %s\n", arg);
+ } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
+ "Invalid MaxHTTPConnections: %s\n", arg);
+ config->nb_max_http_connections = val;
+ if (config->nb_max_connections > config->nb_max_http_connections) {
+ ERROR("Inconsistent configuration: MaxClients(%d) > "
+ "MaxHTTPConnections(%d)\n", config->nb_max_connections,
+ config->nb_max_http_connections);
+ }
+ } else if (!av_strcasecmp(cmd, "MaxClients")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
+ "Invalid MaxClients: '%s'\n", arg);
+ config->nb_max_connections = val;
+ if (config->nb_max_connections > config->nb_max_http_connections) {
+ ERROR("Inconsistent configuration: MaxClients(%d) > "
+ "MaxHTTPConnections(%d)\n", config->nb_max_connections,
+ config->nb_max_http_connections);
+ }
+ } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
+ int64_t llval;
+ char *tailp;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ errno = 0;
+ llval = strtoll(arg, &tailp, 10);
+ if (llval < 10 || llval > 10000000 || tailp[0] || errno)
+ ERROR("Invalid MaxBandwidth: '%s'\n", arg);
+ else
+ config->max_bandwidth = llval;
+ } else if (!av_strcasecmp(cmd, "CustomLog")) {
+ if (!config->debug) {
+ ffserver_get_arg(config->logfilename, sizeof(config->logfilename),
+ p);
+ }
+ } else if (!av_strcasecmp(cmd, "LoadModule")) {
+ ERROR("Loadable modules are no longer supported\n");
+ } else if (!av_strcasecmp(cmd, "NoDefaults")) {
+ config->use_defaults = 0;
+ } else if (!av_strcasecmp(cmd, "UseDefaults")) {
+ config->use_defaults = 1;
+ } else
+ ERROR("Incorrect keyword: '%s'\n", cmd);
+ return 0;
+}
+
+static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, const char **p,
+ FFServerStream **pfeed)
+{
+ FFServerStream *feed;
+ char arg[1024];
+ av_assert0(pfeed);
+ feed = *pfeed;
+ if (!av_strcasecmp(cmd, "<Feed")) {
+ char *q;
+ FFServerStream *s;
+ feed = av_mallocz(sizeof(FFServerStream));
+ if (!feed)
+ return AVERROR(ENOMEM);
+ ffserver_get_arg(feed->filename, sizeof(feed->filename), p);
+ q = strrchr(feed->filename, '>');
+ if (*q)
+ *q = '\0';
+
+ for (s = config->first_feed; s; s = s->next) {
+ if (!strcmp(feed->filename, s->filename))
+ ERROR("Feed '%s' already registered\n", s->filename);
+ }
+
+ feed->fmt = av_guess_format("ffm", NULL, NULL);
+ /* default feed file */
+ snprintf(feed->feed_filename, sizeof(feed->feed_filename),
+ "/tmp/%s.ffm", feed->filename);
+ feed->feed_max_size = 5 * 1024 * 1024;
+ feed->is_feed = 1;
+ feed->feed = feed; /* self feeding :-) */
+ *pfeed = feed;
+ return 0;
+ }
+ av_assert0(feed);
+ if (!av_strcasecmp(cmd, "Launch")) {
+ int i;
+
+ feed->child_argv = av_mallocz_array(MAX_CHILD_ARGS, sizeof(char *));
+ if (!feed->child_argv)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < MAX_CHILD_ARGS - 2; i++) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (!arg[0])
+ break;
+
+ feed->child_argv[i] = av_strdup(arg);
+ if (!feed->child_argv[i])
+ return AVERROR(ENOMEM);
+ }
+
+ feed->child_argv[i] =
+ av_asprintf("http://%s:%d/%s",
+ (config->http_addr.sin_addr.s_addr == INADDR_ANY) ?
+ "127.0.0.1" : inet_ntoa(config->http_addr.sin_addr),
+ ntohs(config->http_addr.sin_port), feed->filename);
+ if (!feed->child_argv[i])
+ return AVERROR(ENOMEM);
+ } else if (!av_strcasecmp(cmd, "ACL")) {
+ ffserver_parse_acl_row(NULL, feed, NULL, *p, config->filename,
+ config->line_num);
+ } else if (!av_strcasecmp(cmd, "File") ||
+ !av_strcasecmp(cmd, "ReadOnlyFile")) {
+ ffserver_get_arg(feed->feed_filename, sizeof(feed->feed_filename), p);
+ feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
+ } else if (!av_strcasecmp(cmd, "Truncate")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ /* assume Truncate is true in case no argument is specified */
+ if (!arg[0]) {
+ feed->truncate = 1;
+ } else {
+ WARNING("Truncate N syntax in configuration file is deprecated. "
+ "Use Truncate alone with no arguments.\n");
+ feed->truncate = strtod(arg, NULL);
+ }
+ } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
+ char *p1;
+ double fsize;
+
+ ffserver_get_arg(arg, sizeof(arg), p);
+ p1 = arg;
+ fsize = strtod(p1, &p1);
+ switch(av_toupper(*p1)) {
+ case 'K':
+ fsize *= 1024;
+ break;
+ case 'M':
+ fsize *= 1024 * 1024;
+ break;
+ case 'G':
+ fsize *= 1024 * 1024 * 1024;
+ break;
+ default:
+ ERROR("Invalid file size: '%s'\n", arg);
+ break;
+ }
+ feed->feed_max_size = (int64_t)fsize;
+ if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
+ ERROR("Feed max file size is too small. Must be at least %d.\n",
+ FFM_PACKET_SIZE*4);
+ }
+ } else if (!av_strcasecmp(cmd, "</Feed>")) {
+ *pfeed = NULL;
+ } else {
+ ERROR("Invalid entry '%s' inside <Feed></Feed>\n", cmd);
+ }
+ return 0;
+}
+
+static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
+ FFServerStream **pstream)
+{
+ char arg[1024], arg2[1024];
+ FFServerStream *stream;
+ int val;
+
+ av_assert0(pstream);
+ stream = *pstream;
+
+ if (!av_strcasecmp(cmd, "<Stream")) {
+ char *q;
+ FFServerStream *s;
+ stream = av_mallocz(sizeof(FFServerStream));
+ if (!stream)
+ return AVERROR(ENOMEM);
+ config->dummy_actx = avcodec_alloc_context3(NULL);
+ config->dummy_vctx = avcodec_alloc_context3(NULL);
+ if (!config->dummy_vctx || !config->dummy_actx) {
+ av_free(stream);
+ avcodec_free_context(&config->dummy_vctx);
+ avcodec_free_context(&config->dummy_actx);
+ return AVERROR(ENOMEM);
+ }
+ config->dummy_actx->codec_type = AVMEDIA_TYPE_AUDIO;
+ config->dummy_vctx->codec_type = AVMEDIA_TYPE_VIDEO;
+ ffserver_get_arg(stream->filename, sizeof(stream->filename), p);
+ q = strrchr(stream->filename, '>');
+ if (q)
+ *q = '\0';
+
+ for (s = config->first_stream; s; s = s->next) {
+ if (!strcmp(stream->filename, s->filename))
+ ERROR("Stream '%s' already registered\n", s->filename);
+ }
+
+ stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
+ if (stream->fmt) {
+ config->guessed_audio_codec_id = stream->fmt->audio_codec;
+ config->guessed_video_codec_id = stream->fmt->video_codec;
+ } else {
+ config->guessed_audio_codec_id = AV_CODEC_ID_NONE;
+ config->guessed_video_codec_id = AV_CODEC_ID_NONE;
+ }
+ config->stream_use_defaults = config->use_defaults;
+ *pstream = stream;
+ return 0;
+ }
+ av_assert0(stream);
+ if (!av_strcasecmp(cmd, "Feed")) {
+ FFServerStream *sfeed;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ sfeed = config->first_feed;
+ while (sfeed) {
+ if (!strcmp(sfeed->filename, arg))
+ break;
+ sfeed = sfeed->next_feed;
+ }
+ if (!sfeed)
+ ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg,
+ stream->filename);
+ else
+ stream->feed = sfeed;
+ } else if (!av_strcasecmp(cmd, "Format")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (!strcmp(arg, "status")) {
+ stream->stream_type = STREAM_TYPE_STATUS;
+ stream->fmt = NULL;
+ } else {
+ stream->stream_type = STREAM_TYPE_LIVE;
+ /* JPEG cannot be used here, so use single frame MJPEG */
+ if (!strcmp(arg, "jpeg"))
+ strcpy(arg, "mjpeg");
+ stream->fmt = ffserver_guess_format(arg, NULL, NULL);
+ if (!stream->fmt)
+ ERROR("Unknown Format: '%s'\n", arg);
+ }
+ if (stream->fmt) {
+ config->guessed_audio_codec_id = stream->fmt->audio_codec;
+ config->guessed_video_codec_id = stream->fmt->video_codec;
+ }
+ } else if (!av_strcasecmp(cmd, "InputFormat")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ stream->ifmt = av_find_input_format(arg);
+ if (!stream->ifmt)
+ ERROR("Unknown input format: '%s'\n", arg);
+ } else if (!av_strcasecmp(cmd, "FaviconURL")) {
+ if (stream->stream_type == STREAM_TYPE_STATUS)
+ ffserver_get_arg(stream->feed_filename,
+ sizeof(stream->feed_filename), p);
+ else
+ ERROR("FaviconURL only permitted for status streams\n");
+ } else if (!av_strcasecmp(cmd, "Author") ||
+ !av_strcasecmp(cmd, "Comment") ||
+ !av_strcasecmp(cmd, "Copyright") ||
+ !av_strcasecmp(cmd, "Title")) {
+ char key[32];
+ int i;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ for (i = 0; i < strlen(cmd); i++)
+ key[i] = av_tolower(cmd[i]);
+ key[i] = 0;
+ WARNING("Deprecated '%s' option in configuration file. Use "
+ "'Metadata %s VALUE' instead.\n", cmd, key);
+ if (av_dict_set(&stream->metadata, key, arg, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Metadata")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_get_arg(arg2, sizeof(arg2), p);
+ if (av_dict_set(&stream->metadata, arg, arg2, 0) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Preroll")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ stream->prebuffer = atof(arg) * 1000;
+ } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
+ stream->send_on_key = 1;
+ } else if (!av_strcasecmp(cmd, "AudioCodec")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_codec(config->dummy_actx, arg, config);
+ } else if (!av_strcasecmp(cmd, "VideoCodec")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_codec(config->dummy_vctx, arg, config);
+ } else if (!av_strcasecmp(cmd, "MaxTime")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ stream->max_time = atof(arg) * 1000;
+ } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
+ float f;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_float_param(&f, arg, 1000, -FLT_MAX, FLT_MAX, config,
+ "Invalid %s: '%s'\n", cmd, arg);
+ if (ffserver_save_avoption_int("ab", (int64_t)lrintf(f),
+ AV_OPT_FLAG_AUDIO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AudioChannels")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("ac", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("ar", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
+ int minrate, maxrate;
+ char *dash;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ dash = strchr(arg, '-');
+ if (dash) {
+ *dash = '\0';
+ dash++;
+ if (ffserver_set_int_param(&minrate, arg, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0 &&
+ ffserver_set_int_param(&maxrate, dash, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0) {
+ if (ffserver_save_avoption_int("minrate", minrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0 ||
+ ffserver_save_avoption_int("maxrate", maxrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ }
+ } else
+ ERROR("Incorrect format for VideoBitRateRange. It should be "
+ "<min>-<max>: '%s'.\n", arg);
+ } else if (!av_strcasecmp(cmd, "Debug")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("debug", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 ||
+ ffserver_save_avoption("debug", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Strict")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("strict", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 ||
+ ffserver_save_avoption("strict", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 8*1024, 0, INT_MAX, config,
+ "Invalid %s: '%s'", cmd, arg);
+ if (ffserver_save_avoption_int("bufsize", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config,
+ "Invalid %s: '%s'", cmd, arg);
+ if (ffserver_save_avoption_int("bt", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config,
+ "Invalid %s: '%s'", cmd, arg);
+ if (ffserver_save_avoption_int("b", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoSize")) {
+ int ret, w, h;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ret = av_parse_video_size(&w, &h, arg);
+ if (ret < 0)
+ ERROR("Invalid video size '%s'\n", arg);
+ else {
+ if (w % 2 || h % 2)
+ WARNING("Image size is not a multiple of 2\n");
+ if (ffserver_save_avoption("video_size", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ }
+ } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
+ ffserver_get_arg(&arg[2], sizeof(arg) - 2, p);
+ arg[0] = '1'; arg[1] = '/';
+ if (ffserver_save_avoption("time_base", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "PixelFormat")) {
+ enum AVPixelFormat pix_fmt;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ pix_fmt = av_get_pix_fmt(arg);
+ if (pix_fmt == AV_PIX_FMT_NONE)
+ ERROR("Unknown pixel format: '%s'\n", arg);
+ else if (ffserver_save_avoption("pixel_format", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("g", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
+ if (ffserver_save_avoption("g", "1", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
+ if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
+ if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || //FIXME remove
+ ffserver_save_avoption("flags", "+mv4", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
+ !av_strcasecmp(cmd, "AVOptionAudio")) {
+ int ret;
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_get_arg(arg2, sizeof(arg2), p);
+ if (!av_strcasecmp(cmd, "AVOptionVideo"))
+ ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_VIDEO_PARAM,
+ config);
+ else
+ ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_AUDIO_PARAM,
+ config);
+ if (ret < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
+ !av_strcasecmp(cmd, "AVPresetAudio")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (!av_strcasecmp(cmd, "AVPresetVideo"))
+ ffserver_opt_preset(arg, AV_OPT_FLAG_VIDEO_PARAM, config);
+ else
+ ffserver_opt_preset(arg, AV_OPT_FLAG_AUDIO_PARAM, config);
+ } else if (!av_strcasecmp(cmd, "VideoTag")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (strlen(arg) == 4 &&
+ ffserver_save_avoption_int("codec_tag",
+ MKTAG(arg[0], arg[1], arg[2], arg[3]),
+ AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "BitExact")) {
+ if (ffserver_save_avoption("flags", "+bitexact", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "DctFastint")) {
+ if (ffserver_save_avoption("dct", "fastint", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "IdctSimple")) {
+ if (ffserver_save_avoption("idct", "simple", AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "Qscale")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config,
+ "Invalid Qscale: '%s'\n", arg);
+ if (ffserver_save_avoption("flags", "+qscale", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 ||
+ ffserver_save_avoption_int("global_quality", FF_QP2LAMBDA * val,
+ AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("qdiff", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoQMax")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("qmax", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "VideoQMin")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("qmin", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "LumiMask")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("lumi_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "DarkMask")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (ffserver_save_avoption("dark_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0)
+ goto nomem;
+ } else if (!av_strcasecmp(cmd, "NoVideo")) {
+ config->no_video = 1;
+ } else if (!av_strcasecmp(cmd, "NoAudio")) {
+ config->no_audio = 1;
+ } else if (!av_strcasecmp(cmd, "ACL")) {
+ ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename,
+ config->line_num);
+ } else if (!av_strcasecmp(cmd, "DynamicACL")) {
+ ffserver_get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), p);
+ } else if (!av_strcasecmp(cmd, "RTSPOption")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ av_freep(&stream->rtsp_option);
+ stream->rtsp_option = av_strdup(arg);
+ } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ if (resolve_host(&stream->multicast_ip, arg))
+ ERROR("Invalid host/IP address: '%s'\n", arg);
+ stream->is_multicast = 1;
+ stream->loop = 1; /* default is looping */
+ } else if (!av_strcasecmp(cmd, "MulticastPort")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, 1, 65535, config,
+ "Invalid MulticastPort: '%s'\n", arg);
+ stream->multicast_port = val;
+ } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
+ ffserver_get_arg(arg, sizeof(arg), p);
+ ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config,
+ "Invalid MulticastTTL: '%s'\n", arg);
+ stream->multicast_ttl = val;
+ } else if (!av_strcasecmp(cmd, "NoLoop")) {
+ stream->loop = 0;
+ } else if (!av_strcasecmp(cmd, "</Stream>")) {
+ config->stream_use_defaults &= 1;
+ if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) {
+ if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE)
+ config->dummy_actx->codec_id = config->guessed_audio_codec_id;
+ if (!config->no_audio &&
+ config->dummy_actx->codec_id != AV_CODEC_ID_NONE) {
+ AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_actx->codec_id));
+ add_codec(stream, audio_enc, config);
+ }
+ if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE)
+ config->dummy_vctx->codec_id = config->guessed_video_codec_id;
+ if (!config->no_video &&
+ config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) {
+ AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_vctx->codec_id));
+ add_codec(stream, video_enc, config);
+ }
+ }
+ av_dict_free(&config->video_opts);
+ av_dict_free(&config->audio_opts);
+ avcodec_free_context(&config->dummy_vctx);
+ avcodec_free_context(&config->dummy_actx);
+ *pstream = NULL;
+ } else if (!av_strcasecmp(cmd, "File") ||
+ !av_strcasecmp(cmd, "ReadOnlyFile")) {
+ ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename),
+ p);
+ } else if (!av_strcasecmp(cmd, "UseDefaults")) {
+ if (config->stream_use_defaults > 1)
+ WARNING("Multiple UseDefaults/NoDefaults entries.\n");
+ config->stream_use_defaults = 3;
+ } else if (!av_strcasecmp(cmd, "NoDefaults")) {
+ if (config->stream_use_defaults > 1)
+ WARNING("Multiple UseDefaults/NoDefaults entries.\n");
+ config->stream_use_defaults = 2;
+ } else {
+ ERROR("Invalid entry '%s' inside <Stream></Stream>\n", cmd);
+ }
+ return 0;
+ nomem:
+ av_log(NULL, AV_LOG_ERROR, "Out of memory. Aborting.\n");
+ av_dict_free(&config->video_opts);
+ av_dict_free(&config->audio_opts);
+ avcodec_free_context(&config->dummy_vctx);
+ avcodec_free_context(&config->dummy_actx);
+ return AVERROR(ENOMEM);
+}
+
+static int ffserver_parse_config_redirect(FFServerConfig *config,
+ const char *cmd, const char **p,
+ FFServerStream **predirect)
+{
+ FFServerStream *redirect;
+ av_assert0(predirect);
+ redirect = *predirect;
+
+ if (!av_strcasecmp(cmd, "<Redirect")) {
+ char *q;
+ redirect = av_mallocz(sizeof(FFServerStream));
+ if (!redirect)
+ return AVERROR(ENOMEM);
+
+ ffserver_get_arg(redirect->filename, sizeof(redirect->filename), p);
+ q = strrchr(redirect->filename, '>');
+ if (*q)
+ *q = '\0';
+ redirect->stream_type = STREAM_TYPE_REDIRECT;
+ *predirect = redirect;
+ return 0;
+ }
+ av_assert0(redirect);
+ if (!av_strcasecmp(cmd, "URL")) {
+ ffserver_get_arg(redirect->feed_filename,
+ sizeof(redirect->feed_filename), p);
+ } else if (!av_strcasecmp(cmd, "</Redirect>")) {
+ if (!redirect->feed_filename[0])
+ ERROR("No URL found for <Redirect>\n");
+ *predirect = NULL;
+ } else {
+ ERROR("Invalid entry '%s' inside <Redirect></Redirect>\n", cmd);
+ }
+ return 0;
+}
+
+int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config)
+{
+ FILE *f;
+ char line[1024];
+ char cmd[64];
+ const char *p;
+ FFServerStream **last_stream, *stream = NULL, *redirect = NULL;
+ FFServerStream **last_feed, *feed = NULL;
+ int ret = 0;
+
+ av_assert0(config);
+
+ f = fopen(filename, "r");
+ if (!f) {
+ ret = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not open the configuration file '%s'\n", filename);
+ return ret;
+ }
+
+ config->first_stream = NULL;
+ config->first_feed = NULL;
+ config->errors = config->warnings = 0;
+
+ last_stream = &config->first_stream;
+ last_feed = &config->first_feed;
+
+ config->line_num = 0;
+ while (fgets(line, sizeof(line), f) != NULL) {
+ config->line_num++;
+ p = line;
+ while (av_isspace(*p))
+ p++;
+ if (*p == '\0' || *p == '#')
+ continue;
+
+ ffserver_get_arg(cmd, sizeof(cmd), &p);
+
+ if (feed || !av_strcasecmp(cmd, "<Feed")) {
+ int opening = !av_strcasecmp(cmd, "<Feed");
+ if (opening && (stream || feed || redirect)) {
+ ERROR("Already in a tag\n");
+ } else {
+ ret = ffserver_parse_config_feed(config, cmd, &p, &feed);
+ if (ret < 0)
+ break;
+ if (opening) {
+ /* add in stream & feed list */
+ *last_stream = feed;
+ *last_feed = feed;
+ last_stream = &feed->next;
+ last_feed = &feed->next_feed;
+ }
+ }
+ } else if (stream || !av_strcasecmp(cmd, "<Stream")) {
+ int opening = !av_strcasecmp(cmd, "<Stream");
+ if (opening && (stream || feed || redirect)) {
+ ERROR("Already in a tag\n");
+ } else {
+ ret = ffserver_parse_config_stream(config, cmd, &p, &stream);
+ if (ret < 0)
+ break;
+ if (opening) {
+ /* add in stream list */
+ *last_stream = stream;
+ last_stream = &stream->next;
+ }
+ }
+ } else if (redirect || !av_strcasecmp(cmd, "<Redirect")) {
+ int opening = !av_strcasecmp(cmd, "<Redirect");
+ if (opening && (stream || feed || redirect))
+ ERROR("Already in a tag\n");
+ else {
+ ret = ffserver_parse_config_redirect(config, cmd, &p,
+ &redirect);
+ if (ret < 0)
+ break;
+ if (opening) {
+ /* add in stream list */
+ *last_stream = redirect;
+ last_stream = &redirect->next;
+ }
+ }
+ } else {
+ ffserver_parse_config_global(config, cmd, &p);
+ }
+ }
+ if (stream || feed || redirect)
+ ERROR("Missing closing </%s> tag\n",
+ stream ? "Stream" : (feed ? "Feed" : "Redirect"));
+
+ fclose(f);
+ if (ret < 0)
+ return ret;
+ if (config->errors)
+ return AVERROR(EINVAL);
+ else
+ return 0;
+}
+
+#undef ERROR
+#undef WARNING
+
+void ffserver_free_child_args(void *argsp)
+{
+ int i;
+ char **args;
+ if (!argsp)
+ return;
+ args = *(char ***)argsp;
+ if (!args)
+ return;
+ for (i = 0; i < MAX_CHILD_ARGS; i++)
+ av_free(args[i]);
+ av_freep(argsp);
+}
diff --git a/ffserver_config.h b/ffserver_config.h
new file mode 100644
index 0000000000..bdeb3c990a
--- /dev/null
+++ b/ffserver_config.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FFSERVER_CONFIG_H
+#define FFSERVER_CONFIG_H
+
+#include "libavutil/dict.h"
+#include "libavformat/avformat.h"
+#include "libavformat/network.h"
+
+#define FFSERVER_MAX_STREAMS 20
+
+/* each generated stream is described here */
+enum FFServerStreamType {
+ STREAM_TYPE_LIVE,
+ STREAM_TYPE_STATUS,
+ STREAM_TYPE_REDIRECT,
+};
+
+enum FFServerIPAddressAction {
+ IP_ALLOW = 1,
+ IP_DENY,
+};
+
+typedef struct FFServerIPAddressACL {
+ struct FFServerIPAddressACL *next;
+ enum FFServerIPAddressAction action;
+ /* These are in host order */
+ struct in_addr first;
+ struct in_addr last;
+} FFServerIPAddressACL;
+
+/* description of each stream of the ffserver.conf file */
+typedef struct FFServerStream {
+ enum FFServerStreamType stream_type;
+ char filename[1024]; /* stream filename */
+ struct FFServerStream *feed; /* feed we are using (can be null if coming from file) */
+ AVDictionary *in_opts; /* input parameters */
+ AVDictionary *metadata; /* metadata to set on the stream */
+ AVInputFormat *ifmt; /* if non NULL, force input format */
+ AVOutputFormat *fmt;
+ FFServerIPAddressACL *acl;
+ char dynamic_acl[1024];
+ int nb_streams;
+ int prebuffer; /* Number of milliseconds early to start */
+ int64_t max_time; /* Number of milliseconds to run */
+ int send_on_key;
+ AVStream *streams[FFSERVER_MAX_STREAMS];
+ int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
+ char feed_filename[1024]; /* file name of the feed storage, or
+ input file name for a stream */
+ pid_t pid; /* Of ffmpeg process */
+ time_t pid_start; /* Of ffmpeg process */
+ char **child_argv;
+ struct FFServerStream *next;
+ unsigned bandwidth; /* bandwidth, in kbits/s */
+ /* RTSP options */
+ char *rtsp_option;
+ /* multicast specific */
+ int is_multicast;
+ struct in_addr multicast_ip;
+ int multicast_port; /* first port used for multicast */
+ int multicast_ttl;
+ int loop; /* if true, send the stream in loops (only meaningful if file) */
+
+ /* feed specific */
+ int feed_opened; /* true if someone is writing to the feed */
+ int is_feed; /* true if it is a feed */
+ int readonly; /* True if writing is prohibited to the file */
+ int truncate; /* True if feeder connection truncate the feed file */
+ int conns_served;
+ int64_t bytes_served;
+ int64_t feed_max_size; /* maximum storage size, zero means unlimited */
+ int64_t feed_write_index; /* current write position in feed (it wraps around) */
+ int64_t feed_size; /* current size of feed */
+ struct FFServerStream *next_feed;
+} FFServerStream;
+
+typedef struct FFServerConfig {
+ char *filename;
+ FFServerStream *first_feed; /* contains only feeds */
+ FFServerStream *first_stream; /* contains all streams, including feeds */
+ unsigned int nb_max_http_connections;
+ unsigned int nb_max_connections;
+ uint64_t max_bandwidth;
+ int debug;
+ char logfilename[1024];
+ struct sockaddr_in http_addr;
+ struct sockaddr_in rtsp_addr;
+ int errors;
+ int warnings;
+ int use_defaults;
+ // Following variables MUST NOT be used outside configuration parsing code.
+ enum AVCodecID guessed_audio_codec_id;
+ enum AVCodecID guessed_video_codec_id;
+ AVDictionary *video_opts; /* AVOptions for video encoder */
+ AVDictionary *audio_opts; /* AVOptions for audio encoder */
+ AVCodecContext *dummy_actx; /* Used internally to test audio AVOptions. */
+ AVCodecContext *dummy_vctx; /* Used internally to test video AVOptions. */
+ int no_audio;
+ int no_video;
+ int line_num;
+ int stream_use_defaults;
+} FFServerConfig;
+
+void ffserver_get_arg(char *buf, int buf_size, const char **pp);
+
+void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,
+ FFServerIPAddressACL *ext_acl,
+ const char *p, const char *filename, int line_num);
+
+int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config);
+
+void ffserver_free_child_args(void *argsp);
+
+#endif /* FFSERVER_CONFIG_H */
diff --git a/libavcodec/012v.c b/libavcodec/012v.c
new file mode 100644
index 0000000000..b87551e0a5
--- /dev/null
+++ b/libavcodec/012v.c
@@ -0,0 +1,155 @@
+/*
+ * 012v decoder
+ *
+ * Copyright (C) 2012 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+static av_cold int zero12v_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P16;
+ avctx->bits_per_raw_sample = 10;
+
+ if (avctx->codec_tag == MKTAG('a', '1', '2', 'v'))
+ avpriv_request_sample(avctx, "transparency");
+
+ return 0;
+}
+
+static int zero12v_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ int line, ret;
+ const int width = avctx->width;
+ AVFrame *pic = data;
+ uint16_t *y, *u, *v;
+ const uint8_t *line_end, *src = avpkt->data;
+ int stride = avctx->width * 8 / 3;
+
+ if (width <= 1 || avctx->height <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Dimensions %dx%d not supported.\n", width, avctx->height);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ( avctx->codec_tag == MKTAG('0', '1', '2', 'v')
+ && avpkt->size % avctx->height == 0
+ && avpkt->size / avctx->height * 3 >= width * 8)
+ stride = avpkt->size / avctx->height;
+
+ if (avpkt->size < avctx->height * stride) {
+ av_log(avctx, AV_LOG_ERROR, "Packet too small: %d instead of %d\n",
+ avpkt->size, avctx->height * stride);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->pict_type = AV_PICTURE_TYPE_I;
+ pic->key_frame = 1;
+
+ line_end = avpkt->data + stride;
+ for (line = 0; line < avctx->height; line++) {
+ uint16_t y_temp[6] = {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000};
+ uint16_t u_temp[3] = {0x8000, 0x8000, 0x8000};
+ uint16_t v_temp[3] = {0x8000, 0x8000, 0x8000};
+ int x;
+ y = (uint16_t *)(pic->data[0] + line * pic->linesize[0]);
+ u = (uint16_t *)(pic->data[1] + line * pic->linesize[1]);
+ v = (uint16_t *)(pic->data[2] + line * pic->linesize[2]);
+
+ for (x = 0; x < width; x += 6) {
+ uint32_t t;
+
+ if (width - x < 6 || line_end - src < 16) {
+ y = y_temp;
+ u = u_temp;
+ v = v_temp;
+ }
+
+ if (line_end - src < 4)
+ break;
+
+ t = AV_RL32(src);
+ src += 4;
+ *u++ = t << 6 & 0xFFC0;
+ *y++ = t >> 4 & 0xFFC0;
+ *v++ = t >> 14 & 0xFFC0;
+
+ if (line_end - src < 4)
+ break;
+
+ t = AV_RL32(src);
+ src += 4;
+ *y++ = t << 6 & 0xFFC0;
+ *u++ = t >> 4 & 0xFFC0;
+ *y++ = t >> 14 & 0xFFC0;
+
+ if (line_end - src < 4)
+ break;
+
+ t = AV_RL32(src);
+ src += 4;
+ *v++ = t << 6 & 0xFFC0;
+ *y++ = t >> 4 & 0xFFC0;
+ *u++ = t >> 14 & 0xFFC0;
+
+ if (line_end - src < 4)
+ break;
+
+ t = AV_RL32(src);
+ src += 4;
+ *y++ = t << 6 & 0xFFC0;
+ *v++ = t >> 4 & 0xFFC0;
+ *y++ = t >> 14 & 0xFFC0;
+
+ if (width - x < 6)
+ break;
+ }
+
+ if (x < width) {
+ y = x + (uint16_t *)(pic->data[0] + line * pic->linesize[0]);
+ u = x/2 + (uint16_t *)(pic->data[1] + line * pic->linesize[1]);
+ v = x/2 + (uint16_t *)(pic->data[2] + line * pic->linesize[2]);
+ memcpy(y, y_temp, sizeof(*y) * (width - x));
+ memcpy(u, u_temp, sizeof(*u) * (width - x + 1) / 2);
+ memcpy(v, v_temp, sizeof(*v) * (width - x + 1) / 2);
+ }
+
+ line_end += stride;
+ src = line_end - stride;
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_zero12v_decoder = {
+ .name = "012v",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_012V,
+ .init = zero12v_decode_init,
+ .decode = zero12v_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c
index b248d87569..3a25622860 100644
--- a/libavcodec/4xm.c
+++ b/libavcodec/4xm.c
@@ -2,20 +2,20 @@
* 4XM codec
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
@@ -36,6 +37,7 @@
#include "get_bits.h"
#include "internal.h"
+
#define BLOCK_TYPE_VLC_BITS 5
#define ACDC_VLC_BITS 9
@@ -289,7 +291,7 @@ static void init_mv(FourXContext *f, int linesize)
}
#endif
-static inline void mcdc(uint16_t *dst, uint16_t *src, int log2w,
+static inline void mcdc(uint16_t *dst, const uint16_t *src, int log2w,
int h, int stride, int scale, unsigned dc)
{
int i;
@@ -333,36 +335,32 @@ static inline void mcdc(uint16_t *dst, uint16_t *src, int log2w,
}
break;
default:
- break;
+ av_assert0(0);
}
}
-static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
+static int decode_p_block(FourXContext *f, uint16_t *dst, const uint16_t *src,
int log2w, int log2h, int stride)
{
int index, h, code, ret, scale = 1;
uint16_t *start, *end;
unsigned dc = 0;
- if (log2h < 0 || log2w < 0)
- return AVERROR_INVALIDDATA;
+ av_assert0(log2w >= 0 && log2h >= 0);
index = size2index[log2h][log2w];
- if (index < 0)
- return AVERROR_INVALIDDATA;
+ av_assert0(index >= 0);
h = 1 << log2h;
code = get_vlc2(&f->gb, block_type_vlc[1 - (f->version > 1)][index].table,
BLOCK_TYPE_VLC_BITS, 1);
- if (code < 0 || code > 6)
- return AVERROR_INVALIDDATA;
+ av_assert0(code >= 0 && code <= 6);
start = f->last_frame_buffer;
end = start + stride * (f->avctx->height - h + 1) - (1 << log2w);
if (code == 1) {
- if (--log2h < 0)
- return AVERROR_INVALIDDATA;
+ log2h--;
if ((ret = decode_p_block(f, dst, src, log2w, log2h, stride)) < 0)
return ret;
return decode_p_block(f, dst + (stride << log2h),
@@ -376,24 +374,42 @@ static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
src + (1 << log2w),
log2w, log2h, stride);
} else if (code == 6) {
+ if (bytestream2_get_bytes_left(&f->g2) < 4) {
+ av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
+ return AVERROR_INVALIDDATA;
+ }
if (log2w) {
- dst[0] = bytestream2_get_le16(&f->g2);
- dst[1] = bytestream2_get_le16(&f->g2);
+ dst[0] = bytestream2_get_le16u(&f->g2);
+ dst[1] = bytestream2_get_le16u(&f->g2);
} else {
- dst[0] = bytestream2_get_le16(&f->g2);
- dst[stride] = bytestream2_get_le16(&f->g2);
+ dst[0] = bytestream2_get_le16u(&f->g2);
+ dst[stride] = bytestream2_get_le16u(&f->g2);
}
return 0;
}
+ if ((code&3)==0 && bytestream2_get_bytes_left(&f->g) < 1) {
+ av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
+ return AVERROR_INVALIDDATA;
+ }
+
if (code == 0) {
src += f->mv[bytestream2_get_byte(&f->g)];
} else if (code == 3 && f->version >= 2) {
return 0;
} else if (code == 4) {
src += f->mv[bytestream2_get_byte(&f->g)];
+ if (bytestream2_get_bytes_left(&f->g2) < 2){
+ av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
+ return AVERROR_INVALIDDATA;
+ }
dc = bytestream2_get_le16(&f->g2);
} else if (code == 5) {
+ if (bytestream2_get_bytes_left(&f->g2) < 2){
+ av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
+ return AVERROR_INVALIDDATA;
+ }
+ av_assert0(start <= src && src <= end);
scale = 0;
dc = bytestream2_get_le16(&f->g2);
}
@@ -422,9 +438,9 @@ static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length)
src = f->last_frame_buffer;
if (f->version > 1) {
- if (length < 20)
- return AVERROR_INVALIDDATA;
extra = 20;
+ if (length < extra)
+ return AVERROR_INVALIDDATA;
bitstream_size = AV_RL32(buf + 8);
wordstream_size = AV_RL32(buf + 12);
bytestream_size = AV_RL32(buf + 16);
@@ -435,24 +451,21 @@ static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length)
bytestream_size = FFMAX(length - bitstream_size - wordstream_size, 0);
}
- if (bitstream_size + bytestream_size + wordstream_size + extra != length
- || bitstream_size > (1 << 26)
- || bytestream_size > (1 << 26)
- || wordstream_size > (1 << 26)) {
- av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n",
- bitstream_size, bytestream_size, wordstream_size,
- bitstream_size + bytestream_size + wordstream_size - length);
+ if (bitstream_size > length || bitstream_size >= INT_MAX/8 ||
+ bytestream_size > length - bitstream_size ||
+ wordstream_size > length - bytestream_size - bitstream_size ||
+ extra > length - bytestream_size - bitstream_size - wordstream_size) {
+ av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n", bitstream_size, bytestream_size, wordstream_size,
+ bitstream_size+ bytestream_size+ wordstream_size - length);
return AVERROR_INVALIDDATA;
}
- av_fast_malloc(&f->bitstream_buffer, &f->bitstream_buffer_size,
- bitstream_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_fast_padded_malloc(&f->bitstream_buffer, &f->bitstream_buffer_size,
+ bitstream_size);
if (!f->bitstream_buffer)
return AVERROR(ENOMEM);
f->bbdsp.bswap_buf(f->bitstream_buffer, (const uint32_t *) (buf + extra),
bitstream_size / 4);
- memset((uint8_t*)f->bitstream_buffer + bitstream_size,
- 0, FF_INPUT_BUFFER_PADDING_SIZE);
init_get_bits(&f->gb, f->bitstream_buffer, 8 * bitstream_size);
wordstream_offset = extra + bitstream_size;
@@ -483,10 +496,17 @@ static int decode_i_block(FourXContext *f, int16_t *block)
{
int code, i, j, level, val;
+ if (get_bits_left(&f->gb) < 2){
+ av_log(f->avctx, AV_LOG_ERROR, "%d bits left before decode_i_block()\n", get_bits_left(&f->gb));
+ return -1;
+ }
+
/* DC coef */
val = get_vlc2(&f->pre_gb, f->pre_vlc.table, ACDC_VLC_BITS, 3);
- if (val >> 4)
+ if (val >> 4) {
av_log(f->avctx, AV_LOG_ERROR, "error dc run != 0\n");
+ return AVERROR_INVALIDDATA;
+ }
if (val)
val = get_xbits(&f->gb, val);
@@ -504,7 +524,12 @@ static int decode_i_block(FourXContext *f, int16_t *block)
if (code == 0xf0) {
i += 16;
} else {
- level = get_xbits(&f->gb, code & 0xf);
+ if (code & 0xf) {
+ level = get_xbits(&f->gb, code & 0xf);
+ } else {
+ av_log(f->avctx, AV_LOG_ERROR, "0 coeff\n");
+ return AVERROR_INVALIDDATA;
+ }
i += code >> 4;
if (i >= 64) {
av_log(f->avctx, AV_LOG_ERROR, "run %d oveflow\n", i);
@@ -584,7 +609,7 @@ static int decode_i_mb(FourXContext *f)
static const uint8_t *read_huffman_tables(FourXContext *f,
const uint8_t * const buf,
- int len)
+ int buf_size)
{
int frequency[512] = { 0 };
uint8_t flag[512];
@@ -593,6 +618,7 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
int bits_tab[257];
int start, end;
const uint8_t *ptr = buf;
+ const uint8_t *ptr_end = buf + buf_size;
int j;
memset(up, -1, sizeof(up));
@@ -602,10 +628,10 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
for (;;) {
int i;
- len -= end - start + 1;
-
- if (end < start || len < 0)
+ if (ptr_end - ptr < FFMAX(end - start + 1, 0) + 1) {
+ av_log(f->avctx, AV_LOG_ERROR, "invalid data in read_huffman_tables\n");
return NULL;
+ }
for (i = start; i <= end; i++)
frequency[i] = *ptr++;
@@ -613,9 +639,6 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
if (start == 0)
break;
- if (--len < 0)
- return NULL;
-
end = *ptr++;
}
frequency[256] = 1;
@@ -623,6 +646,11 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
while ((ptr - buf) & 3)
ptr++; // 4byte align
+ if (ptr > ptr_end) {
+ av_log(f->avctx, AV_LOG_ERROR, "ptr overflow in read_huffman_tables\n");
+ return NULL;
+ }
+
for (j = 257; j < 512; j++) {
int min_freq[2] = { 256 * 256, 256 * 256 };
int smallest[2] = { 0, 0 };
@@ -691,6 +719,7 @@ static int decode_i2_frame(FourXContext *f, const uint8_t *buf, int length)
const int height = f->avctx->height;
const int mbs = (FFALIGN(width, 16) >> 4) * (FFALIGN(height, 16) >> 4);
uint16_t *dst = f->frame_buffer;
+ const uint8_t *buf_end = buf + length;
GetByteContext g3;
if (length < mbs * 8) {
@@ -702,6 +731,8 @@ static int decode_i2_frame(FourXContext *f, const uint8_t *buf, int length)
for (y = 0; y < height; y += 16) {
for (x = 0; x < width; x += 16) {
unsigned int color[4] = { 0 }, bits;
+ if (buf_end - buf < 8)
+ return -1;
// warning following is purely guessed ...
color[0] = bytestream2_get_le16u(&g3);
color[1] = bytestream2_get_le16u(&g3);
@@ -735,7 +766,6 @@ static int decode_i_frame(FourXContext *f, const uint8_t *buf, int length)
const int width = f->avctx->width;
const int height = f->avctx->height;
const unsigned int bitstream_size = AV_RL32(buf);
- int token_count av_unused;
unsigned int prestream_size;
const uint8_t *prestream;
@@ -747,7 +777,6 @@ static int decode_i_frame(FourXContext *f, const uint8_t *buf, int length)
return AVERROR_INVALIDDATA;
}
- token_count = AV_RL32(buf + bitstream_size + 8);
prestream_size = 4 * AV_RL32(buf + bitstream_size + 4);
prestream = buf + bitstream_size + 12;
@@ -764,18 +793,18 @@ static int decode_i_frame(FourXContext *f, const uint8_t *buf, int length)
return AVERROR_INVALIDDATA;
}
+ av_assert0(prestream <= buf + length);
+
init_get_bits(&f->gb, buf + 4, 8 * bitstream_size);
prestream_size = length + buf - prestream;
- av_fast_malloc(&f->bitstream_buffer, &f->bitstream_buffer_size,
- prestream_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_fast_padded_malloc(&f->bitstream_buffer, &f->bitstream_buffer_size,
+ prestream_size);
if (!f->bitstream_buffer)
return AVERROR(ENOMEM);
f->bbdsp.bswap_buf(f->bitstream_buffer, (const uint32_t *) prestream,
prestream_size / 4);
- memset((uint8_t*)f->bitstream_buffer + prestream_size,
- 0, FF_INPUT_BUFFER_PADDING_SIZE);
init_get_bits(&f->pre_gb, f->bitstream_buffer, 8 * prestream_size);
f->last_dc = 0 * 128 * 8 * 8;
@@ -807,11 +836,7 @@ static int decode_frame(AVCodecContext *avctx, void *data,
if (buf_size < 20)
return AVERROR_INVALIDDATA;
- if (avctx->width % 16 || avctx->height % 16) {
- av_log(avctx, AV_LOG_ERROR,
- "Dimensions non-multiple of 16 are invalid.\n");
- return AVERROR_INVALIDDATA;
- }
+ av_assert0(avctx->width % 16 == 0 && avctx->height % 16 == 0);
if (buf_size < AV_RL32(buf + 4) + 8) {
av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %"PRIu32"\n",
@@ -827,9 +852,19 @@ static int decode_frame(AVCodecContext *avctx, void *data,
const int data_size = buf_size - 20;
CFrameBuffer *cfrm;
+ if (f->version <= 1) {
+ av_log(f->avctx, AV_LOG_ERROR, "cfrm in version %d\n", f->version);
+ return AVERROR_INVALIDDATA;
+ }
+
id = AV_RL32(buf + 12);
whole_size = AV_RL32(buf + 16);
+ if (data_size < 0 || whole_size < 0) {
+ av_log(f->avctx, AV_LOG_ERROR, "sizes invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+
for (i = 0; i < CFRAME_BUFFER_COUNT; i++)
if (f->cfrm[i].id && f->cfrm[i].id < avctx->frame_number)
av_log(f->avctx, AV_LOG_ERROR, "lost c frame %d\n",
@@ -848,11 +883,14 @@ static int decode_frame(AVCodecContext *avctx, void *data,
}
cfrm = &f->cfrm[i];
+ if (data_size > UINT_MAX - cfrm->size - FF_INPUT_BUFFER_PADDING_SIZE)
+ return AVERROR_INVALIDDATA;
+
cfrm->data = av_fast_realloc(cfrm->data, &cfrm->allocated_size,
cfrm->size + data_size + FF_INPUT_BUFFER_PADDING_SIZE);
// explicit check needed as memcpy below might not catch a NULL
if (!cfrm->data) {
- av_log(f->avctx, AV_LOG_ERROR, "realloc failure");
+ av_log(f->avctx, AV_LOG_ERROR, "realloc failure\n");
return AVERROR(ENOMEM);
}
@@ -879,24 +917,27 @@ static int decode_frame(AVCodecContext *avctx, void *data,
frame_size = buf_size - 12;
}
-
- if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
return ret;
- }
if (frame_4cc == AV_RL32("ifr2")) {
picture->pict_type = AV_PICTURE_TYPE_I;
- if ((ret = decode_i2_frame(f, buf - 4, frame_size + 4)) < 0)
+ if ((ret = decode_i2_frame(f, buf - 4, frame_size + 4)) < 0) {
+ av_log(f->avctx, AV_LOG_ERROR, "decode i2 frame failed\n");
return ret;
+ }
} else if (frame_4cc == AV_RL32("ifrm")) {
picture->pict_type = AV_PICTURE_TYPE_I;
- if ((ret = decode_i_frame(f, buf, frame_size)) < 0)
+ if ((ret = decode_i_frame(f, buf, frame_size)) < 0) {
+ av_log(f->avctx, AV_LOG_ERROR, "decode i frame failed\n");
return ret;
+ }
} else if (frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) {
picture->pict_type = AV_PICTURE_TYPE_P;
- if ((ret = decode_p_frame(f, buf, frame_size)) < 0)
+ if ((ret = decode_p_frame(f, buf, frame_size)) < 0) {
+ av_log(f->avctx, AV_LOG_ERROR, "decode p frame failed\n");
return ret;
+ }
} else if (frame_4cc == AV_RL32("snd_")) {
av_log(avctx, AV_LOG_ERROR, "ignoring snd_ chunk length:%d\n",
buf_size);
@@ -946,6 +987,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "extradata wrong or missing\n");
return AVERROR_INVALIDDATA;
}
+ if((avctx->width % 16) || (avctx->height % 16)) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported width/height\n");
+ return AVERROR_INVALIDDATA;
+ }
ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
if (ret < 0)
diff --git a/libavcodec/8bps.c b/libavcodec/8bps.c
index 3fd15e05eb..e00bdfc808 100644
--- a/libavcodec/8bps.c
+++ b/libavcodec/8bps.c
@@ -2,20 +2,20 @@
* Quicktime Planar RGB (8BPS) Video Decoder
* Copyright (C) 2003 Roberto Togni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
*
* Supports: PAL8 (RGB 8bpp, paletted)
* : BGR24 (RGB 24bpp) (can also output it as RGB32)
- * : RGB32 (RGB 32bpp, 4th plane is probably alpha and it's ignored)
+ * : RGB32 (RGB 32bpp, 4th plane is alpha)
*
*/
@@ -66,27 +66,18 @@ static int decode_frame(AVCodecContext *avctx, void *data,
unsigned int dlen, p, row;
const unsigned char *lp, *dp, *ep;
unsigned char count;
- unsigned int px_inc;
unsigned int planes = c->planes;
unsigned char *planemap = c->planemap;
int ret;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
ep = encoded + buf_size;
/* Set data pointer after line lengths */
dp = encoded + planes * (height << 1);
- /* Ignore alpha plane, don't know what to do with it */
- if (planes == 4)
- planes--;
-
- px_inc = planes + (avctx->pix_fmt == AV_PIX_FMT_RGB32);
-
for (p = 0; p < planes; p++) {
/* Lines length pointer for this plane */
lp = encoded + p * (height << 1);
@@ -105,21 +96,21 @@ static int decode_frame(AVCodecContext *avctx, void *data,
if ((count = *dp++) <= 127) {
count++;
dlen -= count + 1;
- if (pixptr_end - pixptr < count * px_inc)
+ if (pixptr_end - pixptr < count * planes)
break;
if (ep - dp < count)
return AVERROR_INVALIDDATA;
while (count--) {
*pixptr = *dp++;
- pixptr += px_inc;
+ pixptr += planes;
}
} else {
count = 257 - count;
- if (pixptr_end - pixptr < count * px_inc)
+ if (pixptr_end - pixptr < count * planes)
break;
while (count--) {
*pixptr = *dp;
- pixptr += px_inc;
+ pixptr += planes;
}
dp++;
dlen -= 2;
@@ -180,7 +171,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->planemap[0] = HAVE_BIGENDIAN ? 1 : 2; // 1st plane is red
c->planemap[1] = HAVE_BIGENDIAN ? 2 : 1; // 2nd plane is green
c->planemap[2] = HAVE_BIGENDIAN ? 3 : 0; // 3rd plane is blue
- c->planemap[3] = HAVE_BIGENDIAN ? 0 : 3; // 4th plane is alpha???
+ c->planemap[3] = HAVE_BIGENDIAN ? 0 : 3; // 4th plane is alpha
}
return 0;
}
diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c
index b973771fa5..26496e506c 100644
--- a/libavcodec/8svx.c
+++ b/libavcodec/8svx.c
@@ -1,21 +1,21 @@
/*
- * 8SVX audio decoder
* Copyright (C) 2008 Jaikrishnan Menon
+ * Copyright (C) 2011 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,18 @@
*
* supports: fibonacci delta encoding
* : exponential encoding
+ *
+ * For more information about the 8SVX format:
+ * http://netghost.narod.ru/gff/vendspec/iff/iff.txt
+ * http://sox.sourceforge.net/AudioFormats-11.html
+ * http://aminet.net/package/mus/misc/wavepak
+ * http://amigan.1emu.net/reg/8SVX.txt
+ *
+ * Samples can be found here:
+ * http://aminet.net/mods/smpl/
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "internal.h"
#include "libavutil/common.h"
@@ -44,18 +54,17 @@ typedef struct EightSvxContext {
int data_idx;
} EightSvxContext;
-static const int8_t fibonacci[16] = { -34, -21, -13, -8, -5, -3, -2, -1,
- 0, 1, 2, 3, 5, 8, 13, 21 };
-static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1,
- 0, 1, 2, 4, 8, 16, 32, 64 };
+static const int8_t fibonacci[16] = { -34, -21, -13, -8, -5, -3, -2, -1, 0, 1, 2, 3, 5, 8, 13, 21 };
+static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 };
-#define MAX_FRAME_SIZE 32768
+#define MAX_FRAME_SIZE 2048
/**
* Delta decode the compressed values in src, and put the resulting
* decoded samples in dst.
*
* @param[in,out] state starting value. it is saved for use in the next call.
+ * @param table delta sequence table
*/
static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size,
uint8_t *state, const int8_t *table)
@@ -73,12 +82,6 @@ static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size,
*state = val;
}
-static void raw_decode(uint8_t *dst, const int8_t *src, int src_size)
-{
- while (src_size--)
- *dst++ = *src++ + 128;
-}
-
/** decode a frame */
static int eightsvx_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
@@ -87,27 +90,23 @@ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data,
AVFrame *frame = data;
int buf_size;
int ch, ret;
- int is_compr = (avctx->codec_id != AV_CODEC_ID_PCM_S8_PLANAR);
+ int hdr_size = 2;
- /* for the first packet, copy data to buffer */
- if (avpkt->data) {
- int hdr_size = is_compr ? 2 : 0;
- int chan_size = (avpkt->size - hdr_size * avctx->channels) / avctx->channels;
+ /* decode and interleave the first packet */
+ if (!esc->data[0] && avpkt) {
+ int chan_size = avpkt->size / avctx->channels - hdr_size;
- if (avpkt->size < hdr_size * avctx->channels) {
- av_log(avctx, AV_LOG_ERROR, "packet size is too small\n");
- return AVERROR_INVALIDDATA;
+ if (avpkt->size % avctx->channels) {
+ av_log(avctx, AV_LOG_WARNING, "Packet with odd size, ignoring last byte\n");
}
- if (esc->data[0]) {
- av_log(avctx, AV_LOG_ERROR, "unexpected data after first packet\n");
+ if (avpkt->size < (hdr_size + 1) * avctx->channels) {
+ av_log(avctx, AV_LOG_ERROR, "packet size is too small\n");
return AVERROR_INVALIDDATA;
}
- if (is_compr) {
esc->fib_acc[0] = avpkt->data[1] + 128;
if (avctx->channels == 2)
esc->fib_acc[1] = avpkt->data[2+chan_size+1] + 128;
- }
esc->data_idx = 0;
esc->data_size = chan_size;
@@ -136,30 +135,22 @@ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data,
}
/* get output buffer */
- frame->nb_samples = buf_size * (is_compr + 1);
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ frame->nb_samples = buf_size * 2;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
for (ch = 0; ch < avctx->channels; ch++) {
- if (is_compr) {
- delta_decode(frame->data[ch], &esc->data[ch][esc->data_idx],
- buf_size, &esc->fib_acc[ch], esc->table);
- } else {
- raw_decode(frame->data[ch], &esc->data[ch][esc->data_idx],
- buf_size);
- }
+ delta_decode(frame->data[ch], &esc->data[ch][esc->data_idx],
+ buf_size, &esc->fib_acc[ch], esc->table);
}
esc->data_idx += buf_size;
*got_frame_ptr = 1;
- return avpkt->size;
+ return ((avctx->frame_number == 0)*hdr_size + buf_size)*avctx->channels;
}
-/** initialize 8svx decoder */
static av_cold int eightsvx_decode_init(AVCodecContext *avctx)
{
EightSvxContext *esc = avctx->priv_data;
@@ -169,17 +160,12 @@ static av_cold int eightsvx_decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- switch(avctx->codec->id) {
- case AV_CODEC_ID_8SVX_FIB:
- esc->table = fibonacci;
- break;
- case AV_CODEC_ID_8SVX_EXP:
- esc->table = exponential;
- break;
- case AV_CODEC_ID_PCM_S8_PLANAR:
- break;
- default:
- return AVERROR_INVALIDDATA;
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_8SVX_FIB: esc->table = fibonacci; break;
+ case AV_CODEC_ID_8SVX_EXP: esc->table = exponential; break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Invalid codec id %d.\n", avctx->codec->id);
+ return AVERROR_INVALIDDATA;
}
avctx->sample_fmt = AV_SAMPLE_FMT_U8P;
@@ -192,10 +178,13 @@ static av_cold int eightsvx_decode_close(AVCodecContext *avctx)
av_freep(&esc->data[0]);
av_freep(&esc->data[1]);
+ esc->data_size = 0;
+ esc->data_idx = 0;
return 0;
}
+#if CONFIG_EIGHTSVX_FIB_DECODER
AVCodec ff_eightsvx_fib_decoder = {
.name = "8svx_fib",
.long_name = NULL_IF_CONFIG_SMALL("8SVX fibonacci"),
@@ -203,13 +192,14 @@ AVCodec ff_eightsvx_fib_decoder = {
.id = AV_CODEC_ID_8SVX_FIB,
.priv_data_size = sizeof (EightSvxContext),
.init = eightsvx_decode_init,
- .close = eightsvx_decode_close,
.decode = eightsvx_decode_frame,
- .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
+ .close = eightsvx_decode_close,
+ .capabilities = CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_NONE },
};
-
+#endif
+#if CONFIG_EIGHTSVX_EXP_DECODER
AVCodec ff_eightsvx_exp_decoder = {
.name = "8svx_exp",
.long_name = NULL_IF_CONFIG_SMALL("8SVX exponential"),
@@ -217,23 +207,10 @@ AVCodec ff_eightsvx_exp_decoder = {
.id = AV_CODEC_ID_8SVX_EXP,
.priv_data_size = sizeof (EightSvxContext),
.init = eightsvx_decode_init,
- .close = eightsvx_decode_close,
.decode = eightsvx_decode_frame,
- .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
+ .close = eightsvx_decode_close,
+ .capabilities = CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_NONE },
};
-
-AVCodec ff_pcm_s8_planar_decoder = {
- .name = "pcm_s8_planar",
- .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_PCM_S8_PLANAR,
- .priv_data_size = sizeof(EightSvxContext),
- .init = eightsvx_decode_init,
- .close = eightsvx_decode_close,
- .decode = eightsvx_decode_frame,
- .capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P,
- AV_SAMPLE_FMT_NONE },
-};
+#endif
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index e4ca551085..8bbf78c9cf 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avcodec
HEADERS = avcodec.h \
@@ -5,6 +7,7 @@ HEADERS = avcodec.h \
dv_profile.h \
d3d11va.h \
dxva2.h \
+ old_codec_ids.h \
qsv.h \
vaapi.h \
vda.h \
@@ -14,6 +17,8 @@ HEADERS = avcodec.h \
xvmc.h \
OBJS = allcodecs.o \
+ audioconvert.o \
+ avdct.o \
avpacket.o \
avpicture.o \
bitstream.o \
@@ -21,12 +26,13 @@ OBJS = allcodecs.o \
codec_desc.o \
dv_profile.o \
imgconvert.o \
- log2_tab.o \
mathtables.o \
options.o \
parser.o \
qsv_api.o \
raw.o \
+ resample.o \
+ resample2.o \
utils.o \
vorbis_parser.o \
xiph.o \
@@ -39,13 +45,16 @@ OBJS-$(CONFIG_AUDIODSP) += audiodsp.o
OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o
OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o
OBJS-$(CONFIG_CABAC) += cabac.o
+OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o
OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o
OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o
+OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o
OBJS-$(CONFIG_FAANDCT) += faandct.o
OBJS-$(CONFIG_FAANIDCT) += faanidct.o
OBJS-$(CONFIG_FDCTDSP) += fdctdsp.o jfdctfst.o jfdctint.o
FFT-OBJS-$(CONFIG_HARDCODED_TABLES) += cos_tables.o cos_fixed_tables.o
OBJS-$(CONFIG_FFT) += avfft.o fft_fixed.o fft_float.o \
+ fft_fixed_32.o fft_init_table.o \
$(FFT-OBJS-yes)
OBJS-$(CONFIG_FMTCONVERT) += fmtconvert.o
OBJS-$(CONFIG_GOLOMB) += golomb.o
@@ -64,9 +73,11 @@ OBJS-$(CONFIG_IMDCT15) += imdct15.o
OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o
OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o
OBJS-$(CONFIG_LIBXVID) += libxvid_rc.o
+OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o
+OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o
OBJS-$(CONFIG_LPC) += lpc.o
OBJS-$(CONFIG_LSP) += lsp.o
-OBJS-$(CONFIG_MDCT) += mdct_fixed.o mdct_float.o
+OBJS-$(CONFIG_MDCT) += mdct_fixed.o mdct_float.o mdct_fixed_32.o
OBJS-$(CONFIG_ME_CMP) += me_cmp.o
OBJS-$(CONFIG_MPEG_ER) += mpeg_er.o
OBJS-$(CONFIG_MPEGAUDIO) += mpegaudio.o mpegaudiodata.o \
@@ -80,6 +91,7 @@ OBJS-$(CONFIG_MPEGVIDEO) += mpegvideo.o mpegvideodsp.o \
OBJS-$(CONFIG_MPEGVIDEOENC) += mpegvideo_enc.o mpeg12data.o \
motion_est.o ratecontrol.o \
mpegvideoencdsp.o
+OBJS-$(CONFIG_NVENC) += nvenc.o
OBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o
OBJS-$(CONFIG_QPELDSP) += qpeldsp.o
OBJS-$(CONFIG_QSV) += qsv.o
@@ -88,6 +100,7 @@ OBJS-$(CONFIG_QSVENC) += qsvenc.o
OBJS-$(CONFIG_RANGECODER) += rangecoder.o
RDFT-OBJS-$(CONFIG_HARDCODED_TABLES) += sin_tables.o
OBJS-$(CONFIG_RDFT) += rdft.o $(RDFT-OBJS-yes)
+OBJS-$(CONFIG_SHARED) += log2_tab.o
OBJS-$(CONFIG_SINEWIN) += sinewin.o
OBJS-$(CONFIG_STARTCODE) += startcode.o
OBJS-$(CONFIG_TPELDSP) += tpeldsp.o
@@ -96,6 +109,7 @@ OBJS-$(CONFIG_VP3DSP) += vp3dsp.o
OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o
# decoders/encoders
+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 aactab.o aacsbr.o aacps.o \
@@ -105,7 +119,8 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o \
aacpsy.o aactab.o \
psymodel.o mpeg4audio.o kbdwin.o
OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o
-OBJS-$(CONFIG_AC3_DECODER) += ac3dec.o ac3dec_data.o ac3.o kbdwin.o
+OBJS-$(CONFIG_AC3_DECODER) += ac3dec_float.o ac3dec_data.o ac3.o kbdwin.o
+OBJS-$(CONFIG_AC3_FIXED_DECODER) += ac3dec_fixed.o ac3dec_data.o ac3.o kbdwin.o
OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \
ac3.o kbdwin.o
OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o
@@ -123,10 +138,18 @@ OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \
celp_math.o acelp_filters.o \
acelp_vectors.o \
acelp_pitch_delay.o
+OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpegenc_common.o \
+ mpegvideo_enc.o motion_est.o \
+ ratecontrol.o mpeg12data.o \
+ mpegvideo.o
OBJS-$(CONFIG_ANM_DECODER) += anm.o
OBJS-$(CONFIG_ANSI_DECODER) += ansi.o cga_data.o
OBJS-$(CONFIG_APE_DECODER) += apedec.o
-OBJS-$(CONFIG_ASS_DECODER) += assdec.o ass.o
+OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o
+OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o
+OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o ass_split.o
+OBJS-$(CONFIG_SSA_ENCODER) += assenc.o ass.o
+OBJS-$(CONFIG_ASS_DECODER) += assdec.o ass.o ass_split.o
OBJS-$(CONFIG_ASS_ENCODER) += assenc.o ass.o
OBJS-$(CONFIG_ASV1_DECODER) += asvdec.o asv.o mpeg12data.o
OBJS-$(CONFIG_ASV1_ENCODER) += asvenc.o asv.o mpeg12data.o
@@ -138,12 +161,20 @@ OBJS-$(CONFIG_ATRAC3P_DECODER) += atrac3plusdec.o atrac3plus.o \
atrac3plusdsp.o atrac.o
OBJS-$(CONFIG_AURA_DECODER) += cyuv.o
OBJS-$(CONFIG_AURA2_DECODER) += aura.o
+OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o mjpegdec.o
+OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o
+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
OBJS-$(CONFIG_BINKAUDIO_DCT_DECODER) += binkaudio.o
OBJS-$(CONFIG_BINKAUDIO_RDFT_DECODER) += binkaudio.o
+OBJS-$(CONFIG_BINTEXT_DECODER) += bintext.o cga_data.o
OBJS-$(CONFIG_BMP_DECODER) += bmp.o msrledec.o
OBJS-$(CONFIG_BMP_ENCODER) += bmpenc.o
OBJS-$(CONFIG_BMV_AUDIO_DECODER) += bmvaudio.o
@@ -152,25 +183,35 @@ 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 mpeg12data.o
+OBJS-$(CONFIG_CCAPTION_DECODER) += ccaption_dec.o
OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o
OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o
OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o
+OBJS-$(CONFIG_CINEPAK_ENCODER) += cinepakenc.o elbg.o
OBJS-$(CONFIG_CLJR_DECODER) += cljrdec.o
OBJS-$(CONFIG_CLJR_ENCODER) += cljrenc.o
OBJS-$(CONFIG_CLLC_DECODER) += cllc.o canopus.o
OBJS-$(CONFIG_COOK_DECODER) += cook.o
OBJS-$(CONFIG_COMFORTNOISE_DECODER) += cngdec.o celp_filters.o
OBJS-$(CONFIG_COMFORTNOISE_ENCODER) += cngenc.o
+OBJS-$(CONFIG_CPIA_DECODER) += cpia.o
OBJS-$(CONFIG_CSCD_DECODER) += cscd.o
OBJS-$(CONFIG_CYUV_DECODER) += cyuv.o
OBJS-$(CONFIG_DCA_DECODER) += dcadec.o dca.o dcadsp.o \
dcadata.o dca_exss.o \
dca_xll.o synth_filter.o
+OBJS-$(CONFIG_DCA_ENCODER) += dcaenc.o dca.o dcadata.o
+OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o \
+ dirac_arith.o mpeg12data.o dirac_dwt.o
OBJS-$(CONFIG_DFA_DECODER) += dfa.o
OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o dnxhddata.o
OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o dnxhddata.o
OBJS-$(CONFIG_DPX_DECODER) += dpx.o
OBJS-$(CONFIG_DPX_ENCODER) += dpxenc.o
+OBJS-$(CONFIG_DSD_LSBF_DECODER) += dsddec.o
+OBJS-$(CONFIG_DSD_MSBF_DECODER) += dsddec.o
+OBJS-$(CONFIG_DSD_LSBF_PLANAR_DECODER) += dsddec.o
+OBJS-$(CONFIG_DSD_MSBF_PLANAR_DECODER) += dsddec.o
OBJS-$(CONFIG_DSICINAUDIO_DECODER) += dsicinaudio.o
OBJS-$(CONFIG_DSICINVIDEO_DECODER) += dsicinvideo.o
OBJS-$(CONFIG_DSS_SP_DECODER) += dss_sp.o
@@ -182,7 +223,7 @@ OBJS-$(CONFIG_DVVIDEO_DECODER) += dvdec.o dv.o dvdata.o
OBJS-$(CONFIG_DVVIDEO_ENCODER) += dvenc.o dv.o dvdata.o
OBJS-$(CONFIG_DXA_DECODER) += dxa.o
OBJS-$(CONFIG_DXTORY_DECODER) += dxtory.o
-OBJS-$(CONFIG_EAC3_DECODER) += eac3dec.o eac3_data.o
+OBJS-$(CONFIG_EAC3_DECODER) += eac3_data.o
OBJS-$(CONFIG_EAC3_ENCODER) += eac3enc.o eac3_data.o
OBJS-$(CONFIG_EACMV_DECODER) += eacmv.o
OBJS-$(CONFIG_EAMAD_DECODER) += eamad.o eaidct.o mpeg12.o \
@@ -195,14 +236,17 @@ OBJS-$(CONFIG_EIGHTSVX_EXP_DECODER) += 8svx.o
OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER) += 8svx.o
OBJS-$(CONFIG_ESCAPE124_DECODER) += escape124.o
OBJS-$(CONFIG_ESCAPE130_DECODER) += escape130.o
+OBJS-$(CONFIG_EVRC_DECODER) += evrcdec.o acelp_vectors.o lsp.o
OBJS-$(CONFIG_EXR_DECODER) += exr.o
OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o
OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o
+OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o
OBJS-$(CONFIG_FIC_DECODER) += fic.o
OBJS-$(CONFIG_FLAC_DECODER) += flacdec.o flacdata.o flac.o flacdsp.o
-OBJS-$(CONFIG_FLAC_ENCODER) += flacenc.o flacdata.o flac.o flacdsp.o
+OBJS-$(CONFIG_FLAC_ENCODER) += flacenc.o flacdata.o flac.o flacdsp.o vorbis_data.o
OBJS-$(CONFIG_FLASHSV_DECODER) += flashsv.o
OBJS-$(CONFIG_FLASHSV_ENCODER) += flashsvenc.o
+OBJS-$(CONFIG_FLASHSV2_ENCODER) += flashsv2enc.o
OBJS-$(CONFIG_FLASHSV2_DECODER) += flashsv.o
OBJS-$(CONFIG_FLIC_DECODER) += flicvideo.o
OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o
@@ -210,7 +254,9 @@ OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o
OBJS-$(CONFIG_FRWU_DECODER) += frwu.o
OBJS-$(CONFIG_G2M_DECODER) += g2meet.o
OBJS-$(CONFIG_G723_1_DECODER) += g723_1.o acelp_vectors.o \
- celp_filters.o
+ celp_filters.o celp_math.o
+OBJS-$(CONFIG_G723_1_ENCODER) += g723_1.o acelp_vectors.o celp_math.o
+OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_math.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o
OBJS-$(CONFIG_GIF_DECODER) += gifdec.o lzw.o
OBJS-$(CONFIG_GIF_ENCODER) += gif.o lzwenc.o
OBJS-$(CONFIG_GSM_DECODER) += gsmdec.o gsmdec_data.o msgsmdec.o
@@ -227,6 +273,7 @@ OBJS-$(CONFIG_H264_DECODER) += h264.o h264_cabac.o h264_cavlc.o \
h264_mb.o h264_picture.o h264_ps.o \
h264_refs.o h264_sei.o h264_slice.o
OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
+OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.o
OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h264.o
OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \
@@ -239,6 +286,7 @@ OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxvlc.o hqxdsp.o canopus.o
OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o
OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o
+OBJS-$(CONFIG_IDF_DECODER) += bintext.o cga_data.o
OBJS-$(CONFIG_IFF_BYTERUN1_DECODER) += iff.o
OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o
OBJS-$(CONFIG_IMC_DECODER) += imc.o
@@ -248,6 +296,9 @@ OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o ivi_dsp.o
OBJS-$(CONFIG_INDEO5_DECODER) += indeo5.o ivi.o ivi_dsp.o
OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o
+OBJS-$(CONFIG_JACOSUB_DECODER) += jacosubdec.o ass.o
+OBJS-$(CONFIG_JPEG2000_ENCODER) += j2kenc.o mqcenc.o mqc.o jpeg2000.o \
+ jpeg2000dwt.o
OBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dec.o jpeg2000.o jpeg2000dsp.o \
jpeg2000dwt.o mqcdec.o mqc.o
OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o
@@ -263,6 +314,7 @@ OBJS-$(CONFIG_MACE6_DECODER) += mace.o
OBJS-$(CONFIG_MDEC_DECODER) += mdec.o mpeg12.o mpeg12data.o
OBJS-$(CONFIG_METASOUND_DECODER) += metasound.o metasound_data.o \
twinvq.o
+OBJS-$(CONFIG_MICRODVD_DECODER) += microdvddec.o ass.o
OBJS-$(CONFIG_MIMIC_DECODER) += mimic.o
OBJS-$(CONFIG_MJPEG_DECODER) += mjpegdec.o
OBJS-$(CONFIG_MJPEG_ENCODER) += mjpegenc.o mjpegenc_common.o
@@ -270,10 +322,14 @@ OBJS-$(CONFIG_MJPEGB_DECODER) += mjpegbdec.o
OBJS-$(CONFIG_MLP_DECODER) += mlpdec.o mlpdsp.o
OBJS-$(CONFIG_MMVIDEO_DECODER) += mmvideo.o
OBJS-$(CONFIG_MOTIONPIXELS_DECODER) += motionpixels.o
+OBJS-$(CONFIG_MOVTEXT_DECODER) += movtextdec.o ass.o
+OBJS-$(CONFIG_MOVTEXT_ENCODER) += movtextenc.o ass_split.o
OBJS-$(CONFIG_MP1_DECODER) += mpegaudiodec_fixed.o
OBJS-$(CONFIG_MP1FLOAT_DECODER) += mpegaudiodec_float.o
OBJS-$(CONFIG_MP2_DECODER) += mpegaudiodec_fixed.o
-OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc.o mpegaudio.o \
+OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc_float.o mpegaudio.o \
+ mpegaudiodata.o mpegaudiodsp_data.o
+OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \
mpegaudiodata.o mpegaudiodsp_data.o
OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o
OBJS-$(CONFIG_MP3_DECODER) += mpegaudiodec_fixed.o
@@ -284,12 +340,13 @@ OBJS-$(CONFIG_MP3ON4_DECODER) += mpegaudiodec_fixed.o mpeg4audio.o
OBJS-$(CONFIG_MP3ON4FLOAT_DECODER) += mpegaudiodec_float.o mpeg4audio.o
OBJS-$(CONFIG_MPC7_DECODER) += mpc7.o mpc.o
OBJS-$(CONFIG_MPC8_DECODER) += mpc8.o mpc.o
-OBJS-$(CONFIG_MPEG_XVMC_DECODER) += mpegvideo_xvmc.o
+OBJS-$(CONFIG_MPEGVIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o
OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o
OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o
OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o
OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o
OBJS-$(CONFIG_MPEG4_DECODER) += xvididct.o
+OBJS-$(CONFIG_MPL2_DECODER) += mpl2dec.o ass.o
OBJS-$(CONFIG_MSMPEG4V1_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o
OBJS-$(CONFIG_MSMPEG4V2_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o
OBJS-$(CONFIG_MSMPEG4V2_ENCODER) += msmpeg4enc.o msmpeg4.o msmpeg4data.o
@@ -300,6 +357,7 @@ OBJS-$(CONFIG_MSA1_DECODER) += mss3.o mss34dsp.o
OBJS-$(CONFIG_MSS1_DECODER) += mss1.o mss12.o
OBJS-$(CONFIG_MSS2_DECODER) += mss2.o mss12.o mss2dsp.o
OBJS-$(CONFIG_MSVIDEO1_DECODER) += msvideo1.o
+OBJS-$(CONFIG_MSVIDEO1_ENCODER) += msvideo1enc.o elbg.o
OBJS-$(CONFIG_MSZH_DECODER) += lcldec.o
OBJS-$(CONFIG_MTS2_DECODER) += mss4.o mss34dsp.o
OBJS-$(CONFIG_MVC1_DECODER) += mvcdec.o
@@ -325,12 +383,16 @@ OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o
OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o
OBJS-$(CONFIG_PGSSUB_DECODER) += pgssubdec.o
OBJS-$(CONFIG_PICTOR_DECODER) += pictordec.o cga_data.o
+OBJS-$(CONFIG_PJS_DECODER) += textdec.o ass.o
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) += proresdec.o proresdata.o proresdsp.o
-OBJS-$(CONFIG_PRORES_ENCODER) += proresenc.o proresdata.o
+OBJS-$(CONFIG_PRORES_DECODER) += proresdec2.o proresdsp.o proresdata.o
+OBJS-$(CONFIG_PRORES_LGPL_DECODER) += proresdec_lgpl.o proresdsp.o proresdata.o
+OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o
+OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o
+OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o
OBJS-$(CONFIG_PTX_DECODER) += ptx.o
OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \
celp_filters.o acelp_vectors.o \
@@ -341,13 +403,16 @@ OBJS-$(CONFIG_QPEG_DECODER) += qpeg.o
OBJS-$(CONFIG_QTRLE_DECODER) += qtrle.o
OBJS-$(CONFIG_QTRLE_ENCODER) += qtrleenc.o
OBJS-$(CONFIG_R10K_DECODER) += r210dec.o
+OBJS-$(CONFIG_R10K_ENCODER) += r210enc.o
OBJS-$(CONFIG_R210_DECODER) += r210dec.o
+OBJS-$(CONFIG_R210_ENCODER) += r210enc.o
OBJS-$(CONFIG_RA_144_DECODER) += ra144dec.o ra144.o celp_filters.o
OBJS-$(CONFIG_RA_144_ENCODER) += ra144enc.o ra144.o celp_filters.o
OBJS-$(CONFIG_RA_288_DECODER) += ra288.o celp_filters.o
OBJS-$(CONFIG_RALF_DECODER) += ralf.o
OBJS-$(CONFIG_RAWVIDEO_DECODER) += rawdec.o
OBJS-$(CONFIG_RAWVIDEO_ENCODER) += rawenc.o
+OBJS-$(CONFIG_REALTEXT_DECODER) += realtextdec.o ass.o
OBJS-$(CONFIG_RL2_DECODER) += rl2.o
OBJS-$(CONFIG_ROQ_DECODER) += roqvideodec.o roqvideo.o
OBJS-$(CONFIG_ROQ_ENCODER) += roqvideoenc.o roqvideo.o elbg.o
@@ -360,7 +425,9 @@ OBJS-$(CONFIG_RV20_DECODER) += rv10.o
OBJS-$(CONFIG_RV20_ENCODER) += rv20enc.o
OBJS-$(CONFIG_RV30_DECODER) += rv30.o rv34.o rv30dsp.o rv34dsp.o
OBJS-$(CONFIG_RV40_DECODER) += rv40.o rv34.o rv34dsp.o rv40dsp.o
+OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o
OBJS-$(CONFIG_S302M_DECODER) += s302m.o
+OBJS-$(CONFIG_S302M_ENCODER) += s302menc.o
OBJS-$(CONFIG_SANM_DECODER) += sanm.o
OBJS-$(CONFIG_SGI_DECODER) += sgidec.o
OBJS-$(CONFIG_SGI_ENCODER) += sgienc.o rle.o
@@ -373,29 +440,46 @@ OBJS-$(CONFIG_SIPR_DECODER) += sipr.o acelp_pitch_delay.o \
OBJS-$(CONFIG_SMACKAUD_DECODER) += smacker.o
OBJS-$(CONFIG_SMACKER_DECODER) += smacker.o
OBJS-$(CONFIG_SMC_DECODER) += smc.o
+OBJS-$(CONFIG_SMVJPEG_DECODER) += smvjpegdec.o
+OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o snow_dwt.o
+OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o \
+ h263.o ituh263enc.o
OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o
+OBJS-$(CONFIG_SONIC_DECODER) += sonic.o
+OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o
+OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o
OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o
OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o
+OBJS-$(CONFIG_SRT_ENCODER) += srtenc.o ass_split.o
+OBJS-$(CONFIG_STL_DECODER) += textdec.o ass.o
+OBJS-$(CONFIG_SUBRIP_DECODER) += srtdec.o ass.o
+OBJS-$(CONFIG_SUBRIP_ENCODER) += srtenc.o ass_split.o
+OBJS-$(CONFIG_SUBVIEWER1_DECODER) += textdec.o ass.o
+OBJS-$(CONFIG_SUBVIEWER_DECODER) += subviewerdec.o ass.o
OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o
OBJS-$(CONFIG_SUNRAST_ENCODER) += sunrastenc.o
OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o svq13.o h263.o
OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o \
h263.o ituh263enc.o
OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o mpegutils.o
+OBJS-$(CONFIG_TEXT_DECODER) += textdec.o ass.o
OBJS-$(CONFIG_TAK_DECODER) += takdec.o tak.o
OBJS-$(CONFIG_TARGA_DECODER) += targa.o
OBJS-$(CONFIG_TARGA_ENCODER) += targaenc.o rle.o
+OBJS-$(CONFIG_TARGA_Y216_DECODER) += targa_y216dec.o
OBJS-$(CONFIG_TDSC_DECODER) += tdsc.o
OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o
-OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o faxcompr.o
-OBJS-$(CONFIG_TIFF_ENCODER) += tiffenc.o rle.o lzwenc.o
+OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o faxcompr.o tiff_data.o tiff_common.o
+OBJS-$(CONFIG_TIFF_ENCODER) += tiffenc.o rle.o lzwenc.o tiff_data.o
OBJS-$(CONFIG_TMV_DECODER) += tmv.o cga_data.o
+OBJS-$(CONFIG_TRUEHD_DECODER) += mlpdec.o mlpdsp.o
OBJS-$(CONFIG_TRUEMOTION1_DECODER) += truemotion1.o
OBJS-$(CONFIG_TRUEMOTION2_DECODER) += truemotion2.o
OBJS-$(CONFIG_TRUESPEECH_DECODER) += truespeech.o
OBJS-$(CONFIG_TSCC_DECODER) += tscc.o msrledec.o
OBJS-$(CONFIG_TSCC2_DECODER) += tscc2.o
-OBJS-$(CONFIG_TTA_DECODER) += tta.o
+OBJS-$(CONFIG_TTA_DECODER) += tta.o ttadata.o ttadsp.o
+OBJS-$(CONFIG_TTA_ENCODER) += ttaenc.o ttadata.o
OBJS-$(CONFIG_TWINVQ_DECODER) += twinvqdec.o twinvq.o
OBJS-$(CONFIG_TXD_DECODER) += txd.o s3tc.o
OBJS-$(CONFIG_ULTI_DECODER) += ulti.o
@@ -403,6 +487,10 @@ OBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodec.o utvideo.o
OBJS-$(CONFIG_UTVIDEO_ENCODER) += utvideoenc.o utvideo.o
OBJS-$(CONFIG_V210_DECODER) += v210dec.o
OBJS-$(CONFIG_V210_ENCODER) += v210enc.o
+OBJS-$(CONFIG_V308_DECODER) += v308dec.o
+OBJS-$(CONFIG_V308_ENCODER) += v308enc.o
+OBJS-$(CONFIG_V408_DECODER) += v408dec.o
+OBJS-$(CONFIG_V408_ENCODER) += v408enc.o
OBJS-$(CONFIG_V410_DECODER) += v410dec.o
OBJS-$(CONFIG_V410_ENCODER) += v410enc.o
OBJS-$(CONFIG_V210X_DECODER) += v210x.o
@@ -411,7 +499,8 @@ OBJS-$(CONFIG_VBLE_DECODER) += vble.o
OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1_block.o vc1_loopfilter.o \
vc1_mc.o vc1_pred.o vc1.o vc1data.o \
vc1dsp.o \
- msmpeg4dec.o msmpeg4.o msmpeg4data.o
+ msmpeg4dec.o msmpeg4.o msmpeg4data.o \
+ wmv2dsp.o
OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o
OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o
OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o
@@ -427,11 +516,16 @@ OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp56dsp.o \
vp6dsp.o vp56rac.o
OBJS-$(CONFIG_VP7_DECODER) += vp8.o vp8dsp.o vp56rac.o
OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp8dsp.o vp56rac.o
-OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o \
- vp9block.o vp9prob.o vp9mvs.o vp56rac.o
+OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9dsp.o vp56rac.o vp9dsp_8bpp.o \
+ vp9dsp_10bpp.o vp9dsp_12bpp.o
+OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o
OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o
OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o
-OBJS-$(CONFIG_WEBP_DECODER) += webp.o
+OBJS-$(CONFIG_WAVPACK_ENCODER) += wavpackenc.o
+OBJS-$(CONFIG_WEBP_DECODER) += vp8.o vp8dsp.o vp56rac.o
+OBJS-$(CONFIG_WEBP_DECODER) += webp.o exif.o tiff_common.o
+OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o
+OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o
OBJS-$(CONFIG_WMALOSSLESS_DECODER) += wmalosslessdec.o wma_common.o
OBJS-$(CONFIG_WMAPRO_DECODER) += wmaprodec.o wma.o wma_common.o
OBJS-$(CONFIG_WMAV1_DECODER) += wmadec.o wma.o wma_common.o aactab.o
@@ -442,6 +536,7 @@ OBJS-$(CONFIG_WMAVOICE_DECODER) += wmavoice.o \
celp_filters.o \
acelp_vectors.o acelp_filters.o
OBJS-$(CONFIG_WMV1_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o
+OBJS-$(CONFIG_WMV1_ENCODER) += msmpeg4enc.o
OBJS-$(CONFIG_WMV2_DECODER) += wmv2dec.o wmv2.o wmv2dsp.o \
msmpeg4dec.o msmpeg4.o msmpeg4data.o
OBJS-$(CONFIG_WMV2_ENCODER) += wmv2enc.o wmv2.o wmv2dsp.o \
@@ -451,14 +546,21 @@ OBJS-$(CONFIG_WS_SND1_DECODER) += ws-snd1.o
OBJS-$(CONFIG_XAN_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_XAN_WC3_DECODER) += xan.o
OBJS-$(CONFIG_XAN_WC4_DECODER) += xxan.o
+OBJS-$(CONFIG_XBIN_DECODER) += bintext.o cga_data.o
OBJS-$(CONFIG_XBM_DECODER) += xbmdec.o
OBJS-$(CONFIG_XBM_ENCODER) += xbmenc.o
+OBJS-$(CONFIG_XFACE_DECODER) += xfacedec.o xface.o
+OBJS-$(CONFIG_XFACE_ENCODER) += xfaceenc.o xface.o
OBJS-$(CONFIG_XL_DECODER) += xl.o
OBJS-$(CONFIG_XSUB_DECODER) += xsubdec.o
OBJS-$(CONFIG_XSUB_ENCODER) += xsubenc.o
OBJS-$(CONFIG_XWD_DECODER) += xwddec.o
OBJS-$(CONFIG_XWD_ENCODER) += xwdenc.o
+OBJS-$(CONFIG_Y41P_DECODER) += y41pdec.o
+OBJS-$(CONFIG_Y41P_ENCODER) += y41penc.o
OBJS-$(CONFIG_YOP_DECODER) += yop.o
+OBJS-$(CONFIG_YUV4_DECODER) += yuv4dec.o
+OBJS-$(CONFIG_YUV4_ENCODER) += yuv4enc.o
OBJS-$(CONFIG_ZEROCODEC_DECODER) += zerocodec.o
OBJS-$(CONFIG_ZLIB_DECODER) += lcldec.o
OBJS-$(CONFIG_ZLIB_ENCODER) += lclenc.o
@@ -483,12 +585,16 @@ OBJS-$(CONFIG_PCM_MULAW_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_MULAW_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S8_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S8_ENCODER) += pcm.o
-OBJS-$(CONFIG_PCM_S8_PLANAR_DECODER) += 8svx.o
+OBJS-$(CONFIG_PCM_S8_PLANAR_DECODER) += pcm.o
+OBJS-$(CONFIG_PCM_S8_PLANAR_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S16BE_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S16BE_ENCODER) += pcm.o
+OBJS-$(CONFIG_PCM_S16BE_PLANAR_DECODER) += pcm.o
+OBJS-$(CONFIG_PCM_S16BE_PLANAR_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S16LE_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S16LE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S16LE_PLANAR_DECODER) += pcm.o
+OBJS-$(CONFIG_PCM_S16LE_PLANAR_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S24BE_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S24BE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S24DAUD_DECODER) += pcm.o
@@ -496,11 +602,13 @@ OBJS-$(CONFIG_PCM_S24DAUD_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S24LE_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S24LE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S24LE_PLANAR_DECODER) += pcm.o
+OBJS-$(CONFIG_PCM_S24LE_PLANAR_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S32BE_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S32BE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S32LE_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_S32LE_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_S32LE_PLANAR_DECODER) += pcm.o
+OBJS-$(CONFIG_PCM_S32LE_PLANAR_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_U8_DECODER) += pcm.o
OBJS-$(CONFIG_PCM_U8_ENCODER) += pcm.o
OBJS-$(CONFIG_PCM_U16BE_DECODER) += pcm.o
@@ -520,7 +628,9 @@ OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o
OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o
OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o
+OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_DTK_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_MAXIS_XA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_R1_DECODER) += adpcm.o adpcm_data.o
@@ -531,6 +641,7 @@ OBJS-$(CONFIG_ADPCM_G722_DECODER) += g722.o g722dsp.o g722dec.o
OBJS-$(CONFIG_ADPCM_G722_ENCODER) += g722.o g722dsp.o g722enc.o
OBJS-$(CONFIG_ADPCM_G726_DECODER) += g726.o
OBJS-$(CONFIG_ADPCM_G726_ENCODER) += g726.o
+OBJS-$(CONFIG_ADPCM_G726LE_DECODER) += g726.o
OBJS-$(CONFIG_ADPCM_IMA_AMV_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_APC_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_DK3_DECODER) += adpcm.o adpcm_data.o
@@ -538,8 +649,10 @@ OBJS-$(CONFIG_ADPCM_IMA_DK4_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_EA_EACS_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_EA_SEAD_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER) += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o
@@ -556,6 +669,7 @@ OBJS-$(CONFIG_ADPCM_VIMA_DECODER) += vima.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_XA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o
+OBJS-$(CONFIG_VIMA_DECODER) += vima.o adpcm_data.o
# hardware accelerators
OBJS-$(CONFIG_D3D11VA) += dxva2.o
@@ -574,10 +688,12 @@ OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o
OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o
OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o
OBJS-$(CONFIG_MPEG1_VDPAU_HWACCEL) += vdpau_mpeg12.o
+OBJS-$(CONFIG_MPEG1_XVMC_HWACCEL) += mpegvideo_xvmc.o
OBJS-$(CONFIG_MPEG2_D3D11VA_HWACCEL) += dxva2_mpeg2.o
OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o
OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o
OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o
+OBJS-$(CONFIG_MPEG2_XVMC_HWACCEL) += mpegvideo_xvmc.o
OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o
OBJS-$(CONFIG_MPEG4_VDPAU_HWACCEL) += vdpau_mpeg4.o
OBJS-$(CONFIG_VC1_D3D11VA_HWACCEL) += dxva2_vc1.o
@@ -589,36 +705,47 @@ OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o
OBJS-$(CONFIG_ADTS_MUXER) += mpeg4audio.o
OBJS-$(CONFIG_CAF_DEMUXER) += mpeg4audio.o mpegaudiodata.o \
ac3tab.o
-OBJS-$(CONFIG_FLAC_MUXER) += flac.o flacdata.o
+OBJS-$(CONFIG_FLAC_DEMUXER) += flac.o flacdata.o vorbis_data.o
+OBJS-$(CONFIG_FLAC_MUXER) += flac.o flacdata.o vorbis_data.o
OBJS-$(CONFIG_FLV_DEMUXER) += mpeg4audio.o
OBJS-$(CONFIG_GXF_DEMUXER) += mpeg12data.o
OBJS-$(CONFIG_IFF_DEMUXER) += iff.o
OBJS-$(CONFIG_ISMV_MUXER) += mpeg4audio.o mpegaudiodata.o
OBJS-$(CONFIG_LATM_MUXER) += mpeg4audio.o
-OBJS-$(CONFIG_MATROSKA_AUDIO_MUXER) += mpeg4audio.o \
+OBJS-$(CONFIG_MATROSKA_AUDIO_MUXER) += mpeg4audio.o vorbis_data.o \
flac.o flacdata.o
OBJS-$(CONFIG_MATROSKA_DEMUXER) += mpeg4audio.o mpegaudiodata.o
OBJS-$(CONFIG_MATROSKA_MUXER) += mpeg4audio.o mpegaudiodata.o \
- flac.o flacdata.o
+ flac.o flacdata.o vorbis_data.o
OBJS-$(CONFIG_MP2_MUXER) += mpegaudiodata.o mpegaudiodecheader.o
OBJS-$(CONFIG_MP3_MUXER) += mpegaudiodata.o mpegaudiodecheader.o
OBJS-$(CONFIG_MOV_DEMUXER) += mpeg4audio.o mpegaudiodata.o ac3tab.o
OBJS-$(CONFIG_MOV_MUXER) += mpeg4audio.o mpegaudiodata.o
OBJS-$(CONFIG_MPEGTS_MUXER) += mpeg4audio.o
OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpeg4audio.o mpegaudiodata.o
+OBJS-$(CONFIG_MXF_MUXER) += dnxhddata.o
OBJS-$(CONFIG_NUT_MUXER) += mpegaudiodata.o
+OBJS-$(CONFIG_NUT_DEMUXER) += mpegaudiodata.o mpeg4audio.o
+OBJS-$(CONFIG_OGA_MUXER) += flac.o flacdata.o
OBJS-$(CONFIG_OGG_DEMUXER) += mpeg12data.o \
- dirac.o
-OBJS-$(CONFIG_OGG_MUXER) += flac.o flacdata.o
+ dirac.o vorbis_data.o
+OBJS-$(CONFIG_OGG_MUXER) += flac.o flacdata.o \
+ vorbis_data.o
OBJS-$(CONFIG_RTP_MUXER) += mpeg4audio.o
OBJS-$(CONFIG_SPDIF_DEMUXER) += aacadtsdec.o mpeg4audio.o
OBJS-$(CONFIG_SPDIF_MUXER) += dca.o
OBJS-$(CONFIG_TAK_DEMUXER) += tak.o
OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o mpegaudiodata.o \
- flac.o flacdata.o
+ flac.o flacdata.o \
+ vorbis_data.o
OBJS-$(CONFIG_WTV_DEMUXER) += mpeg4audio.o mpegaudiodata.o
+# libavfilter dependencies
+OBJS-$(CONFIG_ELBG_FILTER) += elbg.o
+
# external codec libraries
+OBJS-$(CONFIG_LIBAACPLUS_ENCODER) += libaacplus.o
+OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o
OBJS-$(CONFIG_LIBDCADEC_DECODER) += libdcadec.o dca.o
OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o
OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o
@@ -644,24 +771,31 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER) += libschroedingerdec.o \
libschroedinger.o
OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o \
libschroedinger.o
+OBJS-$(CONFIG_LIBSHINE_ENCODER) += libshine.o
OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o
OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o
+OBJS-$(CONFIG_LIBSTAGEFRIGHT_H264_DECODER)+= libstagefright.o
OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o
OBJS-$(CONFIG_LIBTWOLAME_ENCODER) += libtwolame.o
+OBJS-$(CONFIG_LIBUTVIDEO_DECODER) += libutvideodec.o
+OBJS-$(CONFIG_LIBUTVIDEO_ENCODER) += libutvideoenc.o
OBJS-$(CONFIG_LIBVO_AACENC_ENCODER) += libvo-aacenc.o mpeg4audio.o
OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER) += libvo-amrwbenc.o
-OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbis.o \
+OBJS-$(CONFIG_LIBVORBIS_DECODER) += libvorbisdec.o
+OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbisenc.o \
vorbis_data.o
OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o
OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o
OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o libvpx.o
OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o libvpx.o
OBJS-$(CONFIG_LIBWAVPACK_ENCODER) += libwavpackenc.o
-OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc.o
+OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o
+OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o
OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o
OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o
OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o
OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o
+OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o
# parsers
OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \
@@ -678,8 +812,10 @@ OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o
OBJS-$(CONFIG_DNXHD_PARSER) += dnxhd_parser.o
OBJS-$(CONFIG_DPX_PARSER) += dpx_parser.o
OBJS-$(CONFIG_DVBSUB_PARSER) += dvbsub_parser.o
+OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o
OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o
-OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o
+OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o \
+ vorbis_data.o
OBJS-$(CONFIG_GSM_PARSER) += gsm_parser.o
OBJS-$(CONFIG_H261_PARSER) += h261_parser.o
OBJS-$(CONFIG_H263_PARSER) += h263_parser.o
@@ -690,6 +826,7 @@ OBJS-$(CONFIG_MLP_PARSER) += mlp_parser.o mlp.o
OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \
mpeg4videodec.o mpeg4video.o \
ituh263dec.o h263dec.o
+OBJS-$(CONFIG_PNG_PARSER) += png_parser.o
OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \
mpegaudiodecheader.o mpegaudiodata.o
OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \
@@ -703,6 +840,7 @@ OBJS-$(CONFIG_TAK_PARSER) += tak_parser.o tak.o
OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o
OBJS-$(CONFIG_VP3_PARSER) += vp3_parser.o
OBJS-$(CONFIG_VP8_PARSER) += vp8_parser.o
+OBJS-$(CONFIG_VP9_PARSER) += vp9_parser.o
# bitstream filters
OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o aacadtsdec.o \
@@ -713,7 +851,10 @@ OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o
OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o
OBJS-$(CONFIG_MJPEG2JPEG_BSF) += mjpeg2jpeg_bsf.o
OBJS-$(CONFIG_MJPEGA_DUMP_HEADER_BSF) += mjpega_dump_header_bsf.o
+OBJS-$(CONFIG_MPEG4_UNPACK_BFRAMES_BSF) += mpeg4_unpack_bframes_bsf.o
OBJS-$(CONFIG_MOV2TEXTSUB_BSF) += movsub_bsf.o
+OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \
+ mpegaudiodata.o
OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o
OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o
OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o
@@ -722,36 +863,60 @@ OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o
OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
OBJS-$(HAVE_THREADS) += pthread.o pthread_slice.o pthread_frame.o
+OBJS-$(CONFIG_FRAME_THREAD_ENCODER) += frame_thread_encoder.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avcodecres.o
+
SKIPHEADERS += %_tablegen.h \
%_tables.h \
aac_tablegen_decl.h \
fft-internal.h \
+ libutvideo.h \
+ old_codec_ids.h \
tableprint.h \
+ tableprint_vlc.h \
$(ARCH)/vp56_arith.h \
SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h
SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h
SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h
-SKIPHEADERS-$(CONFIG_MPEG_XVMC_DECODER) += xvmc.h
+SKIPHEADERS-$(CONFIG_LIBUTVIDEO) += libutvideo.h
SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h
SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h
SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h
+SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h
SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_internal.h
SKIPHEADERS-$(CONFIG_VDA) += vda.h vda_internal.h
SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h
-TESTPROGS-$(CONFIG_FFT) += fft fft-fixed
+TESTPROGS = imgconvert \
+ mathops \
+ options \
+ avfft \
+
+TESTPROGS += api-flac
+
+TESTPROGS-$(CONFIG_CABAC) += cabac
+TESTPROGS-$(CONFIG_FFT) += fft fft-fixed fft-fixed32
TESTPROGS-$(CONFIG_IDCTDSP) += dct
TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter
+TESTPROGS-$(HAVE_MMX) += motion
TESTPROGS-$(CONFIG_GOLOMB) += golomb
TESTPROGS-$(CONFIG_RANGECODER) += rangecoder
+TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc
TESTOBJS = dctref.o
+TOOLS = fourcc2pixfmt
+
HOSTPROGS = aac_tablegen \
aacps_tablegen \
+ aacsbr_tablegen \
+ cabac_tablegen \
cbrt_tablegen \
cos_tablegen \
+ dsd_tablegen \
dv_tablegen \
motionpixels_tablegen \
mpegaudio_tablegen \
@@ -776,7 +941,7 @@ else
$(SUBDIR)%_tablegen$(HOSTEXESUF): HOSTCFLAGS += -DCONFIG_SMALL=0
endif
-GEN_HEADERS = cbrt_tables.h aacps_tables.h aac_tables.h dv_tables.h \
+GEN_HEADERS = cabac_tables.h cbrt_tables.h aacps_tables.h aacsbr_tables.h aac_tables.h dsd_tables.h dv_tables.h \
sinewin_tables.h mpegaudio_tables.h motionpixels_tables.h \
pcm_tables.h qdm2_tables.h
GEN_HEADERS := $(addprefix $(SUBDIR), $(GEN_HEADERS))
@@ -787,7 +952,10 @@ $(GEN_HEADERS): $(SUBDIR)%_tables.h: $(SUBDIR)%_tablegen$(HOSTEXESUF)
ifdef CONFIG_HARDCODED_TABLES
$(SUBDIR)aacdec.o: $(SUBDIR)cbrt_tables.h
$(SUBDIR)aacps.o: $(SUBDIR)aacps_tables.h
+$(SUBDIR)aacsbr.o: $(SUBDIR)aacsbr_tables.h
$(SUBDIR)aactab.o: $(SUBDIR)aac_tables.h
+$(SUBDIR)cabac.o: $(SUBDIR)cabac_tables.h
+$(SUBDIR)dsddec.o: $(SUBDIR)dsd_tables.h
$(SUBDIR)dvenc.o: $(SUBDIR)dv_tables.h
$(SUBDIR)sinewin.o: $(SUBDIR)sinewin_tables.h
$(SUBDIR)mpegaudiodec_fixed.o: $(SUBDIR)mpegaudio_tables.h
diff --git a/libavcodec/a64colors.h b/libavcodec/a64colors.h
index d977426fc0..a9cdb6fa76 100644
--- a/libavcodec/a64colors.h
+++ b/libavcodec/a64colors.h
@@ -2,20 +2,20 @@
* a64 video encoder - c64 colors in rgb (Pepto)
* Copyright (c) 2009 Tobias Bindhammer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/a64enc.h b/libavcodec/a64enc.h
deleted file mode 100644
index 65c1d30951..0000000000
--- a/libavcodec/a64enc.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * a64 video encoder - basic headers
- * Copyright (c) 2009 Tobias Bindhammer
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * a64 video encoder - basic headers
- */
-
-#ifndef AVCODEC_A64ENC_H
-#define AVCODEC_A64ENC_H
-
-#include "libavutil/lfg.h"
-#include "avcodec.h"
-
-#define C64XRES 320
-#define C64YRES 200
-
-typedef struct A64Context {
- /* variables for multicolor modes */
- AVLFG randctx;
- int mc_lifetime;
- int mc_use_5col;
- unsigned mc_frame_counter;
- int *mc_meta_charset;
- int *mc_charmap;
- int *mc_best_cb;
- int mc_luma_vals[5];
- uint8_t *mc_charset;
- uint8_t *mc_colram;
- uint8_t *mc_palette;
- int mc_pal_size;
-
- /* pts of the next packet that will be output */
- int64_t next_pts;
-} A64Context;
-
-#endif /* AVCODEC_A64ENC_H */
diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c
index d742deeaf7..f9c4f36e7d 100644
--- a/libavcodec/a64multienc.c
+++ b/libavcodec/a64multienc.c
@@ -2,20 +2,20 @@
* a64 video encoder - multicolor modes
* Copyright (c) 2009 Tobias Bindhammer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,11 +24,11 @@
* a64 video encoder - multicolor modes
*/
-#include "a64enc.h"
#include "a64colors.h"
#include "a64tables.h"
#include "elbg.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
@@ -37,6 +37,28 @@
#define INTERLACED 1
#define CROP_SCREENS 1
+#define C64XRES 320
+#define C64YRES 200
+
+typedef struct A64Context {
+ /* variables for multicolor modes */
+ AVLFG randctx;
+ int mc_lifetime;
+ int mc_use_5col;
+ unsigned mc_frame_counter;
+ int *mc_meta_charset;
+ int *mc_charmap;
+ int *mc_best_cb;
+ int mc_luma_vals[5];
+ uint8_t *mc_charset;
+ uint8_t *mc_colram;
+ uint8_t *mc_palette;
+ int mc_pal_size;
+
+ /* pts of the next packet that will be output */
+ int64_t next_pts;
+} A64Context;
+
/* gray gradient */
static const int mc_colors[5]={0x0,0xb,0xc,0xf,0x1};
@@ -44,7 +66,7 @@ static const int mc_colors[5]={0x0,0xb,0xc,0xf,0x1};
//static const int mc_colors[5]={0x0,0x8,0xa,0xf,0x7};
//static const int mc_colors[5]={0x0,0x9,0x8,0xa,0x3};
-static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest)
+static void to_meta_with_crop(AVCodecContext *avctx, const AVFrame *p, int *dest)
{
int blockx, blocky, x, y;
int luma = 0;
@@ -57,9 +79,13 @@ static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest)
for (y = blocky; y < blocky + 8 && y < C64YRES; y++) {
for (x = blockx; x < blockx + 8 && x < C64XRES; x += 2) {
if(x < width && y < height) {
- /* build average over 2 pixels */
- luma = (src[(x + 0 + y * p->linesize[0])] +
- src[(x + 1 + y * p->linesize[0])]) / 2;
+ if (x + 1 < width) {
+ /* build average over 2 pixels */
+ luma = (src[(x + 0 + y * p->linesize[0])] +
+ src[(x + 1 + y * p->linesize[0])]) / 2;
+ } else {
+ luma = src[(x + y * p->linesize[0])];
+ }
/* write blocks as linear data now so they are suitable for elbg */
dest[0] = luma;
}
@@ -165,12 +191,11 @@ static void render_charset(AVCodecContext *avctx, uint8_t *charset,
static av_cold int a64multi_close_encoder(AVCodecContext *avctx)
{
A64Context *c = avctx->priv_data;
- av_frame_free(&avctx->coded_frame);
- av_free(c->mc_meta_charset);
- av_free(c->mc_best_cb);
- av_free(c->mc_charset);
- av_free(c->mc_charmap);
- av_free(c->mc_colram);
+ av_freep(&c->mc_meta_charset);
+ av_freep(&c->mc_best_cb);
+ av_freep(&c->mc_charset);
+ av_freep(&c->mc_charmap);
+ av_freep(&c->mc_colram);
return 0;
}
@@ -199,9 +224,9 @@ static av_cold int a64multi_encode_init(AVCodecContext *avctx)
a64_palette[mc_colors[a]][2] * 0.11;
}
- if (!(c->mc_meta_charset = av_malloc(32000 * c->mc_lifetime * sizeof(int))) ||
+ if (!(c->mc_meta_charset = av_mallocz_array(c->mc_lifetime, 32000 * sizeof(int))) ||
!(c->mc_best_cb = av_malloc(CHARSET_CHARS * 32 * sizeof(int))) ||
- !(c->mc_charmap = av_mallocz(1000 * c->mc_lifetime * sizeof(int))) ||
+ !(c->mc_charmap = av_mallocz_array(c->mc_lifetime, 1000 * sizeof(int))) ||
!(c->mc_colram = av_mallocz(CHARSET_CHARS * sizeof(uint8_t))) ||
!(c->mc_charset = av_malloc(0x800 * (INTERLACED+1) * sizeof(uint8_t)))) {
av_log(avctx, AV_LOG_ERROR, "Failed to allocate buffer memory.\n");
@@ -217,14 +242,6 @@ static av_cold int a64multi_encode_init(AVCodecContext *avctx)
AV_WB32(avctx->extradata, c->mc_lifetime);
AV_WB32(avctx->extradata + 16, INTERLACED);
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame) {
- a64multi_close_encoder(avctx);
- return AVERROR(ENOMEM);
- }
-
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
if (!avctx->codec_tag)
avctx->codec_tag = AV_RL32("a64m");
@@ -249,10 +266,9 @@ static void a64_compress_colram(unsigned char *buf, int *charmap, uint8_t *colra
}
static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+ const AVFrame *p, int *got_packet)
{
A64Context *c = avctx->priv_data;
- AVFrame *const p = avctx->coded_frame;
int frame;
int x, y;
@@ -260,7 +276,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
int b_width;
int req_size, ret;
- uint8_t *buf;
+ uint8_t *buf = NULL;
int *charmap = c->mc_charmap;
uint8_t *colram = c->mc_colram;
@@ -283,7 +299,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
/* no data, means end encoding asap */
- if (!pict) {
+ if (!p) {
/* all done, end encoding */
if (!c->mc_lifetime) return 0;
/* no more frames in queue, prepare to flush remaining frames */
@@ -296,13 +312,10 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
} else {
/* fill up mc_meta_charset with data until lifetime exceeds */
if (c->mc_frame_counter < c->mc_lifetime) {
- *p = *pict;
- p->pict_type = AV_PICTURE_TYPE_I;
- p->key_frame = 1;
to_meta_with_crop(avctx, p, meta + 32000 * c->mc_frame_counter);
c->mc_frame_counter++;
if (c->next_pts == AV_NOPTS_VALUE)
- c->next_pts = pict->pts;
+ c->next_pts = p->pts;
/* lifetime is not reached so wait for next frame first */
return 0;
}
@@ -313,19 +326,17 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
req_size = 0;
/* any frames to encode? */
if (c->mc_lifetime) {
- req_size = charset_size + c->mc_lifetime*(screen_size + colram_size);
- if ((ret = ff_alloc_packet(pkt, req_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", req_size);
+ int alloc_size = charset_size + c->mc_lifetime*(screen_size + colram_size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, alloc_size)) < 0)
return ret;
- }
buf = pkt->data;
/* calc optimal new charset + charmaps */
- ret = ff_init_elbg(meta, 32, 1000 * c->mc_lifetime, best_cb,
+ ret = avpriv_init_elbg(meta, 32, 1000 * c->mc_lifetime, best_cb,
CHARSET_CHARS, 50, charmap, &c->randctx);
if (ret < 0)
return ret;
- ret = ff_do_elbg(meta, 32, 1000 * c->mc_lifetime, best_cb,
+ ret = avpriv_do_elbg(meta, 32, 1000 * c->mc_lifetime, best_cb,
CHARSET_CHARS, 50, charmap, &c->randctx);
if (ret < 0)
return ret;
@@ -338,7 +349,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* advance pointers */
buf += charset_size;
- charset += charset_size;
+ req_size += charset_size;
}
/* write x frames to buf */
@@ -375,6 +386,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
pkt->pts = pkt->dts = c->next_pts;
c->next_pts = AV_NOPTS_VALUE;
+ av_assert0(pkt->size >= req_size);
pkt->size = req_size;
pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = !!req_size;
@@ -382,6 +394,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
+#if CONFIG_A64MULTI_ENCODER
AVCodec ff_a64multi_encoder = {
.name = "a64multi",
.long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64"),
@@ -394,7 +407,8 @@ AVCodec ff_a64multi_encoder = {
.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE},
.capabilities = CODEC_CAP_DELAY,
};
-
+#endif
+#if CONFIG_A64MULTI5_ENCODER
AVCodec ff_a64multi5_encoder = {
.name = "a64multi5",
.long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64, extended with 5th color (colram)"),
@@ -407,3 +421,4 @@ AVCodec ff_a64multi5_encoder = {
.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE},
.capabilities = CODEC_CAP_DELAY,
};
+#endif
diff --git a/libavcodec/a64tables.h b/libavcodec/a64tables.h
index b95c5ce754..a955ef4caa 100644
--- a/libavcodec/a64tables.h
+++ b/libavcodec/a64tables.h
@@ -2,20 +2,20 @@
* a64 video encoder - tables used by a64 encoders
* Copyright (c) 2009 Tobias Bindhammer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aac.h b/libavcodec/aac.h
index fed6bf4214..23ec085d8e 100644
--- a/libavcodec/aac.h
+++ b/libavcodec/aac.h
@@ -3,20 +3,20 @@
* 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,7 +81,7 @@ enum BandType {
INTENSITY_BT = 15, ///< Scalefactor data are intensity stereo positions.
};
-#define IS_CODEBOOK_UNSIGNED(x) ((x - 1) & 10)
+#define IS_CODEBOOK_UNSIGNED(x) (((x) - 1) & 10)
enum ChannelPosition {
AAC_CHANNEL_OFF = 0,
@@ -141,6 +141,10 @@ typedef struct PredictorState {
#define SCALE_MAX_DIFF 60 ///< maximum scalefactor difference allowed by standard
#define SCALE_DIFF_ZERO 60 ///< codebook index corresponding to zero scalefactor indices difference
+#define NOISE_PRE 256 ///< preamble for NOISE_BT, put in bitstream with the first noise band
+#define NOISE_PRE_BITS 9 ///< length of preamble
+#define NOISE_OFFSET 90 ///< subtracted from global gain, used as offset for the preamble
+
/**
* Long Term Prediction
*/
@@ -233,7 +237,8 @@ typedef struct SingleChannelElement {
float sf[120]; ///< scalefactors
int sf_idx[128]; ///< scalefactor indices (used by encoder)
uint8_t zeroes[128]; ///< band is not coded (used by encoder)
- DECLARE_ALIGNED(32, float, coeffs)[1024]; ///< coefficients for IMDCT
+ DECLARE_ALIGNED(32, float, pcoeffs)[1024]; ///< coefficients for IMDCT, pristine
+ DECLARE_ALIGNED(32, float, coeffs)[1024]; ///< coefficients for IMDCT, maybe processed
DECLARE_ALIGNED(32, float, saved)[1536]; ///< overlap
DECLARE_ALIGNED(32, float, ret_buf)[2048]; ///< PCM output buffer
DECLARE_ALIGNED(16, float, ltp_state)[3072]; ///< time signal for LTP
@@ -245,6 +250,7 @@ typedef struct SingleChannelElement {
* channel element - generic struct for SCE/CPE/CCE/LFE
*/
typedef struct ChannelElement {
+ int present;
// CPE specific
int common_window; ///< Set if channels share a common 'IndividualChannelStream' in bitstream.
int ms_mode; ///< Signals mid/side stereo flags coding mode (used by encoder)
@@ -259,7 +265,8 @@ typedef struct ChannelElement {
/**
* main AAC context
*/
-typedef struct AACContext {
+struct AACContext {
+ AVClass *class;
AVCodecContext *avctx;
AVFrame *frame;
@@ -273,6 +280,7 @@ typedef struct AACContext {
ChannelElement *che[4][MAX_ELEM_ID];
ChannelElement *tag_che_map[4][MAX_ELEM_ID];
int tags_mapped;
+ int warned_remapping_once;
/** @} */
/**
@@ -292,7 +300,7 @@ typedef struct AACContext {
FFTContext mdct_ld;
FFTContext mdct_ltp;
IMDCT15Context *mdct480;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
int random_state;
/** @} */
@@ -303,9 +311,31 @@ typedef struct AACContext {
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
+ /** @} */
+
DECLARE_ALIGNED(32, float, temp)[128];
OutputConfiguration oc[2];
-} AACContext;
+ int warned_num_aac_frames;
+
+ /* aacdec functions pointers */
+ void (*imdct_and_windowing)(AACContext *ac, SingleChannelElement *sce);
+ void (*apply_ltp)(AACContext *ac, SingleChannelElement *sce);
+ void (*apply_tns)(float coef[1024], TemporalNoiseShaping *tns,
+ IndividualChannelStream *ics, int decode);
+ void (*windowing_and_mdct_ltp)(AACContext *ac, float *out,
+ float *in, IndividualChannelStream *ics);
+ void (*update_ltp)(AACContext *ac, SingleChannelElement *sce);
+
+};
+
+void ff_aacdec_init_mips(AACContext *c);
#endif /* AVCODEC_AAC_H */
diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c
index d3da9b7696..7fefda5ce9 100644
--- a/libavcodec/aac_ac3_parser.c
+++ b/libavcodec/aac_ac3_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aac_ac3_parser.h b/libavcodec/aac_ac3_parser.h
index 99286f0711..c2506a5bfd 100644
--- a/libavcodec/aac_ac3_parser.h
+++ b/libavcodec/aac_ac3_parser.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aac_adtstoasc_bsf.c b/libavcodec/aac_adtstoasc_bsf.c
index bedaa4961b..1f11d02499 100644
--- a/libavcodec/aac_adtstoasc_bsf.c
+++ b/libavcodec/aac_adtstoasc_bsf.c
@@ -2,20 +2,20 @@
* MPEG-2/4 AAC ADTS to MPEG-4 Audio Specific Configuration bitstream filter
* Copyright (c) 2009 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -87,10 +87,13 @@ static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc,
buf_size -= get_bits_count(&gb)/8;
buf += get_bits_count(&gb)/8;
}
+ av_free(avctx->extradata);
avctx->extradata_size = 2 + pce_size;
avctx->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
+ if (!avctx->extradata) {
+ avctx->extradata_size = 0;
return AVERROR(ENOMEM);
+ }
init_put_bits(&pb, avctx->extradata, avctx->extradata_size);
put_bits(&pb, 5, hdr.object_type);
@@ -114,7 +117,7 @@ static int aac_adtstoasc_filter(AVBitStreamFilterContext *bsfc,
}
AVBitStreamFilter ff_aac_adtstoasc_bsf = {
- "aac_adtstoasc",
- sizeof(AACBSFContext),
- aac_adtstoasc_filter,
+ .name = "aac_adtstoasc",
+ .priv_data_size = sizeof(AACBSFContext),
+ .filter = aac_adtstoasc_filter,
};
diff --git a/libavcodec/aac_parser.c b/libavcodec/aac_parser.c
index fdaa5f8144..cb93ba9482 100644
--- a/libavcodec/aac_parser.c
+++ b/libavcodec/aac_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,7 +34,7 @@ static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info,
int size;
union {
uint64_t u64;
- uint8_t u8[8];
+ uint8_t u8[8 + FF_INPUT_BUFFER_PADDING_SIZE];
} tmp;
tmp.u64 = av_be2ne64(state);
diff --git a/libavcodec/aac_tablegen.c b/libavcodec/aac_tablegen.c
index b2c6c954e0..33a179f51e 100644
--- a/libavcodec/aac_tablegen.c
+++ b/libavcodec/aac_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aac_tablegen.h b/libavcodec/aac_tablegen.h
index 8a05ec5973..bf71e59cb5 100644
--- a/libavcodec/aac_tablegen.h
+++ b/libavcodec/aac_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,7 @@
#include "libavutil/mathematics.h"
float ff_aac_pow2sf_tab[428];
-void ff_aac_tableinit(void)
+av_cold void ff_aac_tableinit(void)
{
int i;
for (i = 0; i < 428; i++)
diff --git a/libavcodec/aac_tablegen_decl.h b/libavcodec/aac_tablegen_decl.h
index a5fd1cf345..5105dae483 100644
--- a/libavcodec/aac_tablegen_decl.h
+++ b/libavcodec/aac_tablegen_decl.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aacadtsdec.c b/libavcodec/aacadtsdec.c
index 2994bce243..d0814ac27e 100644
--- a/libavcodec/aacadtsdec.c
+++ b/libavcodec/aacadtsdec.c
@@ -4,20 +4,20 @@
* Copyright (c) 2003 Michael Niedermayer
* Copyright (c) 2009 Alex Converse
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aacadtsdec.h b/libavcodec/aacadtsdec.h
index 6319efcea3..d0584ef36a 100644
--- a/libavcodec/aacadtsdec.h
+++ b/libavcodec/aacadtsdec.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c
index ee89148ef4..2929f3ac44 100644
--- a/libavcodec/aaccoder.c
+++ b/libavcodec/aaccoder.c
@@ -2,20 +2,20 @@
* AAC coefficients encoder
* Copyright (C) 2008-2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,6 +40,12 @@
#include "aacenc.h"
#include "aactab.h"
+/** Frequency in Hz for lower limit of noise substitution **/
+#define NOISE_LOW_LIMIT 4000
+
+/** Total number of usable codebooks **/
+#define CB_TOT 13
+
/** bits needed to code codebook run value for long windows */
static const uint8_t run_value_bits_long[64] = {
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
@@ -53,10 +59,14 @@ static const uint8_t run_value_bits_short[16] = {
3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 9
};
-static const uint8_t *run_value_bits[2] = {
+static const uint8_t * const run_value_bits[2] = {
run_value_bits_long, run_value_bits_short
};
+/** Map to convert values from BandCodingPath index to a codebook index **/
+static const uint8_t aac_cb_out_map[CB_TOT] = {0,1,2,3,4,5,6,7,8,9,10,11,13};
+/** Inverse map to convert from codebooks to BandCodingPath indices **/
+static const uint8_t aac_cb_in_map[CB_TOT+1] = {0,1,2,3,4,5,6,7,8,9,10,11,0,12};
/**
* Quantize one coefficient.
@@ -108,7 +118,7 @@ static av_always_inline float quantize_and_encode_band_cost_template(
const float *scaled, int size, int scale_idx,
int cb, const float lambda, const float uplim,
int *bits, int BT_ZERO, int BT_UNSIGNED,
- int BT_PAIR, int BT_ESC)
+ int BT_PAIR, int BT_ESC, int BT_NOISE)
{
const int q_idx = POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512;
const float Q = ff_aac_pow2sf_tab [q_idx];
@@ -119,8 +129,6 @@ static av_always_inline float quantize_and_encode_band_cost_template(
float cost = 0;
const int dim = BT_PAIR ? 2 : 4;
int resbits = 0;
- const int range = aac_cb_range[cb];
- const int maxval = aac_cb_maxval[cb];
int off;
if (BT_ZERO) {
@@ -130,15 +138,22 @@ static av_always_inline float quantize_and_encode_band_cost_template(
*bits = 0;
return cost * lambda;
}
+ if (BT_NOISE) {
+ for (i = 0; i < size; i++)
+ cost += in[i]*in[i];
+ if (bits)
+ *bits = 0;
+ return cost * lambda;
+ }
if (!scaled) {
abs_pow34_v(s->scoefs, in, size);
scaled = s->scoefs;
}
- quantize_bands(s->qcoefs, in, scaled, size, Q34, !BT_UNSIGNED, maxval);
+ quantize_bands(s->qcoefs, in, scaled, size, Q34, !BT_UNSIGNED, aac_cb_maxval[cb]);
if (BT_UNSIGNED) {
off = 0;
} else {
- off = maxval;
+ off = aac_cb_maxval[cb];
}
for (i = 0; i < size; i += dim) {
const float *vec;
@@ -147,7 +162,7 @@ static av_always_inline float quantize_and_encode_band_cost_template(
int curbits;
float rd = 0.0f;
for (j = 0; j < dim; j++) {
- curidx *= range;
+ curidx *= aac_cb_range[cb];
curidx += quants[j] + off;
}
curbits = ff_aac_spectral_bits[cb-1][curidx];
@@ -195,7 +210,7 @@ static av_always_inline float quantize_and_encode_band_cost_template(
int len = av_log2(coef);
put_bits(pb, len - 4 + 1, (1 << (len - 4 + 1)) - 2);
- put_bits(pb, len, coef & ((1 << len) - 1));
+ put_sbits(pb, len, coef);
}
}
}
@@ -207,8 +222,17 @@ static av_always_inline float quantize_and_encode_band_cost_template(
return cost;
}
-#define QUANTIZE_AND_ENCODE_BAND_COST_FUNC(NAME, BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC) \
-static float quantize_and_encode_band_cost_ ## NAME( \
+static float quantize_and_encode_band_cost_NONE(struct AACEncContext *s, PutBitContext *pb,
+ const float *in, const float *scaled,
+ int size, int scale_idx, int cb,
+ const float lambda, const float uplim,
+ int *bits) {
+ av_assert0(0);
+ return 0.0f;
+}
+
+#define QUANTIZE_AND_ENCODE_BAND_COST_FUNC(NAME, BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC, BT_NOISE) \
+static float quantize_and_encode_band_cost_ ## NAME( \
struct AACEncContext *s, \
PutBitContext *pb, const float *in, \
const float *scaled, int size, int scale_idx, \
@@ -217,15 +241,16 @@ static float quantize_and_encode_band_cost_ ## NAME(
return quantize_and_encode_band_cost_template( \
s, pb, in, scaled, size, scale_idx, \
BT_ESC ? ESC_BT : cb, lambda, uplim, bits, \
- BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC); \
+ BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC, BT_NOISE); \
}
-QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ZERO, 1, 0, 0, 0)
-QUANTIZE_AND_ENCODE_BAND_COST_FUNC(SQUAD, 0, 0, 0, 0)
-QUANTIZE_AND_ENCODE_BAND_COST_FUNC(UQUAD, 0, 1, 0, 0)
-QUANTIZE_AND_ENCODE_BAND_COST_FUNC(SPAIR, 0, 0, 1, 0)
-QUANTIZE_AND_ENCODE_BAND_COST_FUNC(UPAIR, 0, 1, 1, 0)
-QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ESC, 0, 1, 1, 1)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ZERO, 1, 0, 0, 0, 0)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(SQUAD, 0, 0, 0, 0, 0)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(UQUAD, 0, 1, 0, 0, 0)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(SPAIR, 0, 0, 1, 0, 0)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(UPAIR, 0, 1, 1, 0, 0)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ESC, 0, 1, 1, 1, 0)
+QUANTIZE_AND_ENCODE_BAND_COST_FUNC(NOISE, 0, 0, 0, 0, 1)
static float (*const quantize_and_encode_band_cost_arr[])(
struct AACEncContext *s,
@@ -245,6 +270,8 @@ static float (*const quantize_and_encode_band_cost_arr[])(
quantize_and_encode_band_cost_UPAIR,
quantize_and_encode_band_cost_UPAIR,
quantize_and_encode_band_cost_ESC,
+ quantize_and_encode_band_cost_NONE, /* CB 12 doesn't exist */
+ quantize_and_encode_band_cost_NOISE,
};
#define quantize_and_encode_band_cost( \
@@ -312,7 +339,7 @@ typedef struct BandCodingPath {
static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce,
int win, int group_len, const float lambda)
{
- BandCodingPath path[120][12];
+ BandCodingPath path[120][CB_TOT];
int w, swb, cb, start, size;
int i, j;
const int max_sfb = sce->ics.max_sfb;
@@ -325,7 +352,7 @@ static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce
abs_pow34_v(s->scoefs, sce->coeffs, 1024);
start = win*128;
- for (cb = 0; cb < 12; cb++) {
+ for (cb = 0; cb < CB_TOT; cb++) {
path[0][cb].cost = 0.0f;
path[0][cb].prev_idx = -1;
path[0][cb].run = 0;
@@ -333,7 +360,7 @@ static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce
for (swb = 0; swb < max_sfb; swb++) {
size = sce->ics.swb_sizes[swb];
if (sce->zeroes[win*16 + swb]) {
- for (cb = 0; cb < 12; cb++) {
+ for (cb = 0; cb < CB_TOT; cb++) {
path[swb+1][cb].prev_idx = cb;
path[swb+1][cb].cost = path[swb][cb].cost;
path[swb+1][cb].run = path[swb][cb].run + 1;
@@ -343,14 +370,14 @@ static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce
int mincb = next_mincb;
next_minrd = INFINITY;
next_mincb = 0;
- for (cb = 0; cb < 12; cb++) {
+ for (cb = 0; cb < CB_TOT; cb++) {
float cost_stay_here, cost_get_here;
float rd = 0.0f;
for (w = 0; w < group_len; w++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(win+w)*16+swb];
rd += quantize_band_cost(s, sce->coeffs + start + w*128,
s->scoefs + start + w*128, size,
- sce->sf_idx[(win+w)*16+swb], cb,
+ sce->sf_idx[(win+w)*16+swb], aac_cb_out_map[cb],
lambda / band->threshold, INFINITY, NULL);
}
cost_stay_here = path[swb][cb].cost + rd;
@@ -379,7 +406,7 @@ static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce
//convert resulting path from backward-linked list
stack_len = 0;
idx = 0;
- for (cb = 1; cb < 12; cb++)
+ for (cb = 1; cb < CB_TOT; cb++)
if (path[max_sfb][cb].cost < path[max_sfb][idx].cost)
idx = cb;
ppos = max_sfb;
@@ -394,12 +421,13 @@ static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce
//perform actual band info encoding
start = 0;
for (i = stack_len - 1; i >= 0; i--) {
- put_bits(&s->pb, 4, stackcb[i]);
+ cb = aac_cb_out_map[stackcb[i]];
+ put_bits(&s->pb, 4, cb);
count = stackrun[i];
- memset(sce->zeroes + win*16 + start, !stackcb[i], count);
+ memset(sce->zeroes + win*16 + start, !cb, count);
//XXX: memset when band_type is also uint8_t
for (j = 0; j < count; j++) {
- sce->band_type[win*16 + start] = stackcb[i];
+ sce->band_type[win*16 + start] = cb;
start++;
}
while (count >= run_esc) {
@@ -413,7 +441,7 @@ static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce
static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
int win, int group_len, const float lambda)
{
- BandCodingPath path[120][12];
+ BandCodingPath path[120][CB_TOT];
int w, swb, cb, start, size;
int i, j;
const int max_sfb = sce->ics.max_sfb;
@@ -426,7 +454,7 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
abs_pow34_v(s->scoefs, sce->coeffs, 1024);
start = win*128;
- for (cb = 0; cb < 12; cb++) {
+ for (cb = 0; cb < CB_TOT; cb++) {
path[0][cb].cost = run_bits+4;
path[0][cb].prev_idx = -1;
path[0][cb].run = 0;
@@ -450,7 +478,7 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
}
next_minbits = path[swb+1][0].cost;
next_mincb = 0;
- for (cb = 1; cb < 12; cb++) {
+ for (cb = 1; cb < CB_TOT; cb++) {
path[swb+1][cb].cost = 61450;
path[swb+1][cb].prev_idx = -1;
path[swb+1][cb].run = 0;
@@ -459,6 +487,7 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
float minbits = next_minbits;
int mincb = next_mincb;
int startcb = sce->band_type[win*16+swb];
+ startcb = aac_cb_in_map[startcb];
next_minbits = INFINITY;
next_mincb = 0;
for (cb = 0; cb < startcb; cb++) {
@@ -466,13 +495,20 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
path[swb+1][cb].prev_idx = -1;
path[swb+1][cb].run = 0;
}
- for (cb = startcb; cb < 12; cb++) {
+ for (cb = startcb; cb < CB_TOT; cb++) {
float cost_stay_here, cost_get_here;
float bits = 0.0f;
+ if (cb == 12 && sce->band_type[win*16+swb] != NOISE_BT) {
+ path[swb+1][cb].cost = 61450;
+ path[swb+1][cb].prev_idx = -1;
+ path[swb+1][cb].run = 0;
+ continue;
+ }
for (w = 0; w < group_len; w++) {
bits += quantize_band_cost(s, sce->coeffs + start + w*128,
s->scoefs + start + w*128, size,
- sce->sf_idx[(win+w)*16+swb], cb,
+ sce->sf_idx[(win+w)*16+swb],
+ aac_cb_out_map[cb],
0, INFINITY, NULL);
}
cost_stay_here = path[swb][cb].cost + bits;
@@ -501,12 +537,12 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
//convert resulting path from backward-linked list
stack_len = 0;
idx = 0;
- for (cb = 1; cb < 12; cb++)
+ for (cb = 1; cb < CB_TOT; cb++)
if (path[max_sfb][cb].cost < path[max_sfb][idx].cost)
idx = cb;
ppos = max_sfb;
while (ppos > 0) {
- assert(idx >= 0);
+ av_assert1(idx >= 0);
cb = idx;
stackrun[stack_len] = path[ppos][cb].run;
stackcb [stack_len] = cb;
@@ -517,12 +553,13 @@ static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
//perform actual band info encoding
start = 0;
for (i = stack_len - 1; i >= 0; i--) {
- put_bits(&s->pb, 4, stackcb[i]);
+ cb = aac_cb_out_map[stackcb[i]];
+ put_bits(&s->pb, 4, cb);
count = stackrun[i];
- memset(sce->zeroes + win*16 + start, !stackcb[i], count);
+ memset(sce->zeroes + win*16 + start, !cb, count);
//XXX: memset when band_type is also uint8_t
for (j = 0; j < count; j++) {
- sce->band_type[win*16 + start] = stackcb[i];
+ sce->band_type[win*16 + start] = cb;
start++;
}
while (count >= run_esc) {
@@ -711,9 +748,11 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
{
int start = 0, i, w, w2, g;
int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels * (lambda / 120.f);
- float dists[128] = { 0 }, uplims[128];
+ const float freq_mult = avctx->sample_rate/(1024.0f/sce->ics.num_windows)/2.0f;
+ float dists[128] = { 0 }, uplims[128] = { 0 };
float maxvals[128];
- int fflag, minscaler;
+ int noise_sf[128] = { 0 };
+ int fflag, minscaler, minscaler_n;
int its = 0;
int allz = 0;
float minthr = INFINITY;
@@ -724,12 +763,14 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
//XXX: some heuristic to determine initial quantizers will reduce search time
//determine zero bands and upper limits
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+ start = 0;
for (g = 0; g < sce->ics.num_swb; g++) {
int nz = 0;
- float uplim = 0.0f;
+ float uplim = 0.0f, energy = 0.0f;
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
uplim += band->threshold;
+ energy += band->energy;
if (band->energy <= band->threshold || band->threshold == 0.0f) {
sce->zeroes[(w+w2)*16+g] = 1;
continue;
@@ -737,10 +778,18 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
nz = 1;
}
uplims[w*16+g] = uplim *512;
+ if (s->options.pns && start*freq_mult > NOISE_LOW_LIMIT && energy < uplim * 1.2f) {
+ noise_sf[w*16+g] = av_clip(4+FFMIN(log2f(energy)*2,255), -100, 155);
+ sce->band_type[w*16+g] = NOISE_BT;
+ nz= 1;
+ } else { /** Band type will be determined by the twoloop algorithm */
+ sce->band_type[w*16+g] = 0;
+ }
sce->zeroes[w*16+g] = !nz;
if (nz)
minthr = FFMIN(minthr, uplim);
allz |= nz;
+ start += sce->ics.swb_sizes[g];
}
}
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
@@ -771,12 +820,12 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
do {
int tbits, qstep;
minscaler = sce->sf_idx[0];
+ minscaler_n = sce->sf_idx[0];
//inner loop - quantize spectrum to fit into given number of bits
qstep = its ? 1 : 32;
do {
int prev = -1;
tbits = 0;
- fflag = 0;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
start = w*128;
for (g = 0; g < sce->ics.num_swb; g++) {
@@ -786,7 +835,11 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
int cb;
float dist = 0.0f;
- if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) {
+ if (sce->band_type[w*16+g] == NOISE_BT) {
+ minscaler_n = FFMIN(minscaler_n, noise_sf[w*16+g]);
+ start += sce->ics.swb_sizes[g];
+ continue;
+ } else if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) {
start += sce->ics.swb_sizes[g];
continue;
}
@@ -829,9 +882,17 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
fflag = 0;
minscaler = av_clip(minscaler, 60, 255 - SCALE_MAX_DIFF);
+
+ 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->band_type[w*16+g] == NOISE_BT)
+ sce->sf_idx[w*16+g] = av_clip(noise_sf[w*16+g], minscaler_n, minscaler_n + SCALE_MAX_DIFF);
+
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (g = 0; g < sce->ics.num_swb; g++) {
int prevsc = sce->sf_idx[w*16+g];
+ if (sce->band_type[w*16+g] == NOISE_BT)
+ continue;
if (dists[w*16+g] > uplims[w*16+g] && sce->sf_idx[w*16+g] > 60) {
if (find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]-1))
sce->sf_idx[w*16+g]--;
@@ -875,7 +936,7 @@ static void search_for_quantizers_faac(AVCodecContext *avctx, AACEncContext *s,
} else {
for (w = 0; w < 8; w++) {
const float *coeffs = sce->coeffs + w*128;
- start = 0;
+ curband = start = 0;
for (i = 0; i < 128; i++) {
if (i - start >= sce->ics.swb_sizes[curband]) {
start += sce->ics.swb_sizes[curband];
@@ -953,7 +1014,6 @@ static void search_for_quantizers_faac(AVCodecContext *avctx, AACEncContext *s,
}
sce->zeroes[w*16+g] = 0;
scf = prev_scf = av_clip(SCALE_ONE_POS - SCALE_DIV_512 - log2f(1/maxq[w*16+g])*16/3, 60, 218);
- step = 16;
for (;;) {
float dist = 0.0f;
int quant_max;
@@ -1071,10 +1131,10 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe,
float minthr = FFMIN(band0->threshold, band1->threshold);
float maxthr = FFMAX(band0->threshold, band1->threshold);
for (i = 0; i < sce0->ics.swb_sizes[g]; i++) {
- M[i] = (sce0->coeffs[start+w2*128+i]
- + sce1->coeffs[start+w2*128+i]) * 0.5;
+ M[i] = (sce0->pcoeffs[start+w2*128+i]
+ + sce1->pcoeffs[start+w2*128+i]) * 0.5;
S[i] = M[i]
- - sce1->coeffs[start+w2*128+i];
+ - sce1->pcoeffs[start+w2*128+i];
}
abs_pow34_v(L34, sce0->coeffs+start+w2*128, sce0->ics.swb_sizes[g]);
abs_pow34_v(R34, sce1->coeffs+start+w2*128, sce0->ics.swb_sizes[g]);
@@ -1112,26 +1172,26 @@ static void search_for_ms(AACEncContext *s, ChannelElement *cpe,
}
}
-AACCoefficientsEncoder ff_aac_coders[] = {
- {
+AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
+ [AAC_CODER_FAAC] = {
search_for_quantizers_faac,
encode_window_bands_info,
quantize_and_encode_band,
search_for_ms,
},
- {
+ [AAC_CODER_ANMR] = {
search_for_quantizers_anmr,
encode_window_bands_info,
quantize_and_encode_band,
search_for_ms,
},
- {
+ [AAC_CODER_TWOLOOP] = {
search_for_quantizers_twoloop,
codebook_trellis_rate,
quantize_and_encode_band,
search_for_ms,
},
- {
+ [AAC_CODER_FAST] = {
search_for_quantizers_fast,
encode_window_bands_info,
quantize_and_encode_band,
diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c
index 7b306c9c41..48cf637b79 100644
--- a/libavcodec/aacdec.c
+++ b/libavcodec/aacdec.c
@@ -8,20 +8,20 @@
* Copyright (c) 2008-2010 Paul Kendall <paul@kcbbs.gen.nz>
* Copyright (c) 2010 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -74,6 +74,7 @@
* N SinuSoidal Coding (Transient, Sinusoid, Noise)
* Y Parametric Stereo
* N Direct Stream Transfer
+ * Y Enhanced AAC Low Delay (ER AAC ELD)
*
* Note: - HE AAC v1 comprises LC AAC with Spectral Band Replication.
* - HE AAC v2 comprises LC AAC with Spectral Band Replication and
@@ -81,6 +82,7 @@
*/
#include "libavutil/float_dsp.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "get_bits.h"
@@ -100,7 +102,6 @@
#include "aacadtsdec.h"
#include "libavutil/intfloat.h"
-#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdint.h>
@@ -108,12 +109,18 @@
#if ARCH_ARM
# include "arm/aac.h"
+#elif ARCH_MIPS
+# include "mips/aacdec_mips.h"
#endif
static VLC vlc_scalefactors;
static VLC vlc_spectral[11];
-static const char overread_err[] = "Input buffer exhausted before END element found\n";
+static int output_configure(AACContext *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)
{
@@ -130,7 +137,7 @@ static int count_channels(uint8_t (*layout)[3], int tags)
/**
* Check for the channel element in the current channel position configuration.
* If it exists, make sure the appropriate element is allocated and map the
- * channel order to match the internal Libav channel layout.
+ * channel order to match the internal FFmpeg channel layout.
*
* @param che_pos current channel position configuration
* @param type channel element type
@@ -143,6 +150,8 @@ static av_cold int che_configure(AACContext *ac,
enum ChannelPosition che_pos,
int type, int id, int *channels)
{
+ if (*channels >= MAX_CHANNELS)
+ return AVERROR_INVALIDDATA;
if (che_pos) {
if (!ac->che[type][id]) {
if (!(ac->che[type][id] = av_mallocz(sizeof(ChannelElement))))
@@ -150,8 +159,10 @@ static av_cold int che_configure(AACContext *ac,
ff_aac_sbr_ctx_init(ac, &ac->che[type][id]->sbr);
}
if (type != TYPE_CCE) {
- if (*channels >= MAX_CHANNELS - 2)
+ if (*channels >= MAX_CHANNELS - (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1))) {
+ av_log(ac->avctx, AV_LOG_ERROR, "Too many channels\n");
return AVERROR_INVALIDDATA;
+ }
ac->output_element[(*channels)++] = &ac->che[type][id]->ch[0];
if (type == TYPE_CPE ||
(type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) {
@@ -184,11 +195,12 @@ static int frame_configure_elements(AVCodecContext *avctx)
/* get output buffer */
av_frame_unref(ac->frame);
+ if (!avctx->channels)
+ return 1;
+
ac->frame->nb_samples = 2048;
- if ((ret = ff_get_buffer(avctx, ac->frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, ac->frame, 0)) < 0)
return ret;
- }
/* map output channel pointers to AVFrame data */
for (ch = 0; ch < avctx->channels; ch++) {
@@ -412,7 +424,7 @@ static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags)
* Save current output configuration if and only if it has been locked.
*/
static void push_output_configuration(AACContext *ac) {
- if (ac->oc[1].status == OC_LOCKED) {
+ if (ac->oc[1].status == OC_LOCKED || ac->oc[0].status == OC_NONE) {
ac->oc[0] = ac->oc[1];
}
ac->oc[1].status = OC_NONE;
@@ -427,6 +439,8 @@ static void pop_output_configuration(AACContext *ac) {
ac->oc[1] = ac->oc[0];
ac->avctx->channels = ac->oc[1].channels;
ac->avctx->channel_layout = ac->oc[1].channel_layout;
+ output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags,
+ ac->oc[1].status, 0);
}
}
@@ -472,7 +486,8 @@ static int output_configure(AACContext *ac,
}
memcpy(ac->tag_che_map, ac->che, 4 * MAX_ELEM_ID * sizeof(ac->che[0][0]));
- avctx->channel_layout = ac->oc[1].channel_layout = layout;
+ if (layout) avctx->channel_layout = layout;
+ ac->oc[1].channel_layout = layout;
avctx->channels = ac->oc[1].channels = channels;
ac->oc[1].status = oc_type;
@@ -484,6 +499,23 @@ static int output_configure(AACContext *ac,
return 0;
}
+static void flush(AVCodecContext *avctx)
+{
+ AACContext *ac= avctx->priv_data;
+ int type, i, j;
+
+ for (type = 3; type >= 0; type--) {
+ for (i = 0; i < MAX_ELEM_ID; i++) {
+ ChannelElement *che = ac->che[type][i];
+ if (che) {
+ for (j = 0; j <= 1; j++) {
+ memset(che->ch[j].saved, 0, sizeof(che->ch[j].saved));
+ }
+ }
+ }
+ }
+}
+
/**
* Set up channel positions based on a default channel configuration
* as specified in table 1.17.
@@ -504,6 +536,25 @@ static int set_default_channel_config(AVCodecContext *avctx,
*tags = tags_per_config[channel_config];
memcpy(layout_map, aac_channel_layout_map[channel_config - 1],
*tags * sizeof(*layout_map));
+
+ /*
+ * AAC specification has 7.1(wide) as a default layout for 8-channel streams.
+ * However, at least Nero AAC encoder encodes 7.1 streams using the default
+ * channel config 7, mapping the side channels of the original audio stream
+ * to the second AAC_CHANNEL_FRONT pair in the AAC stream. Similarly, e.g. FAAD
+ * decodes the second AAC_CHANNEL_FRONT pair as side channels, therefore decoding
+ * the incorrect streams as if they were correct (and as the encoder intended).
+ *
+ * As actual intended 7.1(wide) streams are very rare, default to assuming a
+ * 7.1 layout was intended.
+ */
+ if (channel_config == 7 && avctx->strict_std_compliance < FF_COMPLIANCE_STRICT) {
+ av_log(avctx, AV_LOG_INFO, "Assuming an incorrectly encoded 7.1 channel layout"
+ " instead of a spec-compliant 7.1(wide) layout, use -strict %d to decode"
+ " according to the specification instead.\n", FF_COMPLIANCE_STRICT);
+ layout_map[2][2] = AAC_CHANNEL_SIDE;
+ }
+
return 0;
}
@@ -521,6 +572,8 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id)
int layout_map_tags;
push_output_configuration(ac);
+ av_log(ac->avctx, AV_LOG_DEBUG, "mono with CPE\n");
+
if (set_default_channel_config(ac->avctx, layout_map,
&layout_map_tags, 2) < 0)
return NULL;
@@ -538,6 +591,8 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id)
int layout_map_tags;
push_output_configuration(ac);
+ av_log(ac->avctx, AV_LOG_DEBUG, "stereo with SCE\n");
+
if (set_default_channel_config(ac->avctx, layout_map,
&layout_map_tags, 1) < 0)
return NULL;
@@ -565,6 +620,12 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id)
* If we seem to have encountered such a stream, transfer
* the LFE[0] element to the SCE[1]'s mapping */
if (ac->tags_mapped == tags_per_config[ac->oc[1].m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) {
+ if (!ac->warned_remapping_once && (type != TYPE_LFE || elem_id != 0)) {
+ av_log(ac->avctx, AV_LOG_WARNING,
+ "This stream seems to incorrectly report its last channel as %s[%d], mapping to LFE[0]\n",
+ type == TYPE_SCE ? "SCE" : "LFE", elem_id);
+ ac->warned_remapping_once++;
+ }
ac->tags_mapped++;
return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0];
}
@@ -574,6 +635,22 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id)
return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1];
}
case 4:
+ /* Some streams incorrectly code 4.0 audio as
+ * SCE[0] CPE[0] LFE[0]
+ * instead of
+ * SCE[0] CPE[0] SCE[1].
+ * If we seem to have encountered such a stream, transfer
+ * the SCE[1] element to the LFE[0]'s mapping */
+ if (ac->tags_mapped == tags_per_config[ac->oc[1].m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) {
+ if (!ac->warned_remapping_once && (type != TYPE_SCE || elem_id != 1)) {
+ av_log(ac->avctx, AV_LOG_WARNING,
+ "This stream seems to incorrectly report its last channel as %s[%d], mapping to SCE[1]\n",
+ type == TYPE_SCE ? "SCE" : "LFE", elem_id);
+ ac->warned_remapping_once++;
+ }
+ ac->tags_mapped++;
+ return ac->tag_che_map[type][elem_id] = ac->che[TYPE_SCE][1];
+ }
if (ac->tags_mapped == 2 &&
ac->oc[1].m4ac.chan_config == 4 &&
type == TYPE_SCE) {
@@ -626,7 +703,7 @@ static void decode_channel_map(uint8_t layout_map[][3],
break;
default:
// AAC_CHANNEL_OFF has no channel map
- return;
+ av_assert0(0);
}
layout_map[0][0] = syn_ele;
layout_map[0][1] = get_bits(gb, 4);
@@ -672,6 +749,10 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
if (get_bits1(gb))
skip_bits(gb, 3); // mixdown_coeff_index and pseudo_surround
+ if (get_bits_left(gb) < 4 * (num_front + num_side + num_back + num_lfe + num_assoc_data + num_cc)) {
+ av_log(avctx, AV_LOG_ERROR, "decode_pce: " overread_err);
+ return -1;
+ }
decode_channel_map(layout_map , AAC_CHANNEL_FRONT, gb, num_front);
tags = num_front;
decode_channel_map(layout_map + tags, AAC_CHANNEL_SIDE, gb, num_side);
@@ -691,7 +772,7 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
/* comment field, first byte is length */
comment_len = get_bits(gb, 8) * 8;
if (get_bits_left(gb) < comment_len) {
- av_log(avctx, AV_LOG_ERROR, overread_err);
+ av_log(avctx, AV_LOG_ERROR, "decode_pce: " overread_err);
return AVERROR_INVALIDDATA;
}
skip_bits_long(gb, comment_len);
@@ -862,9 +943,9 @@ static int decode_audio_specific_config(AACContext *ac,
GetBitContext gb;
int i, ret;
- ff_dlog(avctx, "extradata size %d\n", avctx->extradata_size);
- for (i = 0; i < avctx->extradata_size; i++)
- ff_dlog(avctx, "%02x ", avctx->extradata[i]);
+ ff_dlog(avctx, "audio specific config size %d\n", bit_size >> 3);
+ for (i = 0; i < bit_size >> 3; i++)
+ ff_dlog(avctx, "%02x ", data[i]);
ff_dlog(avctx, "\n");
if ((ret = init_get_bits(&gb, data, bit_size)) < 0)
@@ -928,7 +1009,7 @@ static int decode_audio_specific_config(AACContext *ac,
*
* @return Returns a 32-bit pseudorandom integer
*/
-static av_always_inline int lcg_random(int previous_val)
+static av_always_inline int lcg_random(unsigned previous_val)
{
union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 };
return v.s;
@@ -982,6 +1063,8 @@ static void reset_predictor_group(PredictorState *ps, int group_num)
sizeof(ff_aac_spectral_codes[num][0]), \
size);
+static void aacdec_init(AACContext *ac);
+
static av_cold int aac_decode_init(AVCodecContext *avctx)
{
AACContext *ac = avctx->priv_data;
@@ -990,6 +1073,8 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
ac->avctx = avctx;
ac->oc[1].m4ac.sample_rate = avctx->sample_rate;
+ aacdec_init(ac);
+
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
if (avctx->extradata_size > 0) {
@@ -1028,6 +1113,11 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
}
}
+ if (avctx->channels > MAX_CHANNELS) {
+ av_log(avctx, AV_LOG_ERROR, "Too many channels\n");
+ return AVERROR_INVALIDDATA;
+ }
+
AAC_INIT_VLC_STATIC( 0, 304);
AAC_INIT_VLC_STATIC( 1, 270);
AAC_INIT_VLC_STATIC( 2, 550);
@@ -1042,7 +1132,10 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
ff_aac_sbr_init();
- avpriv_float_dsp_init(&ac->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ ac->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!ac->fdsp) {
+ return AVERROR(ENOMEM);
+ }
ac->random_state = 0x1f2e3d4c;
@@ -1091,7 +1184,7 @@ static int skip_data_stream_element(AACContext *ac, GetBitContext *gb)
align_get_bits(gb);
if (get_bits_left(gb) < 8 * count) {
- av_log(ac->avctx, AV_LOG_ERROR, overread_err);
+ av_log(ac->avctx, AV_LOG_ERROR, "skip_data_stream_element: "overread_err);
return AVERROR_INVALIDDATA;
}
skip_bits_long(gb, 8 * count);
@@ -1204,13 +1297,13 @@ static int decode_ics_info(AACContext *ac, IndividualChannelStream *ics,
if (ics->predictor_present) {
if (aot == AOT_AAC_MAIN) {
if (decode_prediction(ac, ics, gb)) {
- return AVERROR_INVALIDDATA;
+ goto fail;
}
} else if (aot == AOT_AAC_LC ||
aot == AOT_ER_AAC_LC) {
av_log(ac->avctx, AV_LOG_ERROR,
"Prediction is not allowed in AAC-LC.\n");
- return AVERROR_INVALIDDATA;
+ goto fail;
} else {
if (aot == AOT_ER_AAC_LD) {
av_log(ac->avctx, AV_LOG_ERROR,
@@ -1228,10 +1321,13 @@ static int decode_ics_info(AACContext *ac, IndividualChannelStream *ics,
"Number of scalefactor bands in group (%d) "
"exceeds limit (%d).\n",
ics->max_sfb, ics->num_swb);
- return AVERROR_INVALIDDATA;
+ goto fail;
}
return 0;
+fail:
+ ics->max_sfb = 0;
+ return AVERROR_INVALIDDATA;
}
/**
@@ -1262,7 +1358,7 @@ static int decode_band_types(AACContext *ac, enum BandType band_type[120],
sect_len_incr = get_bits(gb, bits);
sect_end += sect_len_incr;
if (get_bits_left(gb) < 0) {
- av_log(ac->avctx, AV_LOG_ERROR, overread_err);
+ av_log(ac->avctx, AV_LOG_ERROR, "decode_band_types: "overread_err);
return AVERROR_INVALIDDATA;
}
if (sect_end > ics->max_sfb) {
@@ -1298,7 +1394,7 @@ static int decode_scalefactors(AACContext *ac, float sf[120], GetBitContext *gb,
int band_type_run_end[120])
{
int g, i, idx = 0;
- int offset[3] = { global_gain, global_gain - 90, 0 };
+ 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++) {
@@ -1310,7 +1406,7 @@ static int decode_scalefactors(AACContext *ac, float sf[120], GetBitContext *gb,
} else if ((band_type[idx] == INTENSITY_BT) ||
(band_type[idx] == INTENSITY_BT2)) {
for (; i < run_end; i++, idx++) {
- offset[2] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60;
+ offset[2] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - SCALE_DIFF_ZERO;
clipped_offset = av_clip(offset[2], -155, 100);
if (offset[2] != clipped_offset) {
avpriv_request_sample(ac->avctx,
@@ -1323,9 +1419,9 @@ static int decode_scalefactors(AACContext *ac, float sf[120], GetBitContext *gb,
} else if (band_type[idx] == NOISE_BT) {
for (; i < run_end; i++, idx++) {
if (noise_flag-- > 0)
- offset[1] += get_bits(gb, 9) - 256;
+ offset[1] += get_bits(gb, NOISE_PRE_BITS) - NOISE_PRE;
else
- offset[1] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60;
+ offset[1] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - SCALE_DIFF_ZERO;
clipped_offset = av_clip(offset[1], -100, 155);
if (offset[1] != clipped_offset) {
avpriv_request_sample(ac->avctx,
@@ -1337,7 +1433,7 @@ static int decode_scalefactors(AACContext *ac, float sf[120], GetBitContext *gb,
}
} else {
for (; i < run_end; i++, idx++) {
- offset[0] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60;
+ offset[0] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - SCALE_DIFF_ZERO;
if (offset[0] > 255U) {
av_log(ac->avctx, AV_LOG_ERROR,
"Scalefactor (%d) out of range.\n", offset[0]);
@@ -1364,12 +1460,12 @@ static int decode_pulses(Pulse *pulse, GetBitContext *gb,
return -1;
pulse->pos[0] = swb_offset[pulse_swb];
pulse->pos[0] += get_bits(gb, 5);
- if (pulse->pos[0] > 1023)
+ if (pulse->pos[0] >= swb_offset[num_swb])
return -1;
pulse->amp[0] = get_bits(gb, 4);
for (i = 1; i < pulse->num_pulse; i++) {
pulse->pos[i] = get_bits(gb, 5) + pulse->pos[i - 1];
- if (pulse->pos[i] > 1023)
+ if (pulse->pos[i] >= swb_offset[num_swb])
return -1;
pulse->amp[i] = get_bits(gb, 4);
}
@@ -1555,9 +1651,9 @@ static int decode_spectrum_and_dequant(AACContext *ac, float coef[1024],
cfo[k] = ac->random_state;
}
- band_energy = ac->fdsp.scalarproduct_float(cfo, cfo, off_len);
+ 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);
+ ac->fdsp->vector_fmul_scalar(cfo, cfo, scale, off_len);
}
} else {
const float *vq = ff_aac_codebook_vector_vals[cbt_m1];
@@ -1703,7 +1799,7 @@ static int decode_spectrum_and_dequant(AACContext *ac, float coef[1024],
}
} while (len -= 2);
- ac->fdsp.vector_fmul_scalar(cfo, cfo, sf[idx], off_len);
+ ac->fdsp->vector_fmul_scalar(cfo, cfo, sf[idx], off_len);
}
}
@@ -1883,7 +1979,7 @@ static int decode_ics(AACContext *ac, SingleChannelElement *sce,
avpriv_request_sample(ac->avctx, "SSR");
return AVERROR_PATCHWELCOME;
}
- // I see no textual basis in the spec for this occuring after SSR gain
+ // 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)
if (decode_tns(ac, tns, gb, ics) < 0)
@@ -1916,7 +2012,7 @@ static void apply_mid_side_stereo(AACContext *ac, ChannelElement *cpe)
cpe->ch[0].band_type[idx] < NOISE_BT &&
cpe->ch[1].band_type[idx] < NOISE_BT) {
for (group = 0; group < ics->group_len[g]; group++) {
- ac->fdsp.butterflies_float(ch0 + group * 128 + offsets[i],
+ ac->fdsp->butterflies_float(ch0 + group * 128 + offsets[i],
ch1 + group * 128 + offsets[i],
offsets[i+1] - offsets[i]);
}
@@ -1955,7 +2051,7 @@ static void apply_intensity_stereo(AACContext *ac,
c *= 1 - 2 * cpe->ms_mask[idx];
scale = c * sce1->sf[idx];
for (group = 0; group < ics->group_len[g]; group++)
- ac->fdsp.vector_fmul_scalar(coef1 + group * 128 + offsets[i],
+ ac->fdsp->vector_fmul_scalar(coef1 + group * 128 + offsets[i],
coef0 + group * 128 + offsets[i],
scale,
offsets[i + 1] - offsets[i]);
@@ -2167,6 +2263,32 @@ static int decode_dynamic_range(DynamicRangeControl *che_drc,
return n;
}
+static int decode_fill(AACContext *ac, GetBitContext *gb, int len) {
+ uint8_t buf[256];
+ int i, major, minor;
+
+ if (len < 13+7*8)
+ goto unknown;
+
+ get_bits(gb, 13); len -= 13;
+
+ for(i=0; i+1<sizeof(buf) && len>=8; i++, len-=8)
+ buf[i] = get_bits(gb, 8);
+
+ buf[i] = 0;
+ if (ac->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(ac->avctx, AV_LOG_DEBUG, "FILL:%s\n", buf);
+
+ if (sscanf(buf, "libfaac %d.%d", &major, &minor) == 2){
+ ac->avctx->internal->skip_samples = 1024;
+ }
+
+unknown:
+ skip_bits_long(gb, len);
+
+ return 0;
+}
+
/**
* Decode extension data (incomplete); reference: table 4.51.
*
@@ -2179,7 +2301,12 @@ static int decode_extension_payload(AACContext *ac, GetBitContext *gb, int cnt,
{
int crc_flag = 0;
int res = cnt;
- switch (get_bits(gb, 4)) { // extension type
+ int type = get_bits(gb, 4);
+
+ if (ac->avctx->debug & FF_DEBUG_STARTCODE)
+ av_log(ac->avctx, AV_LOG_DEBUG, "extension type: %d len:%d\n", type, cnt);
+
+ switch (type) { // extension type
case EXT_SBR_DATA_CRC:
crc_flag++;
case EXT_SBR_DATA:
@@ -2210,6 +2337,8 @@ static int decode_extension_payload(AACContext *ac, GetBitContext *gb, int cnt,
res = decode_dynamic_range(&ac->che_drc, gb);
break;
case EXT_FILL:
+ decode_fill(ac, gb, 8 * cnt - 4);
+ break;
case EXT_FILL_DATA:
case EXT_DATA_ELEMENT:
default:
@@ -2232,7 +2361,7 @@ static void apply_tns(float coef[1024], TemporalNoiseShaping *tns,
int w, filt, m, i;
int bottom, top, order, start, end, size, inc;
float lpc[TNS_MAX_ORDER];
- float tmp[TNS_MAX_ORDER + 1];
+ float tmp[TNS_MAX_ORDER+1];
for (w = 0; w < ics->num_windows; w++) {
bottom = ics->num_swb;
@@ -2290,15 +2419,15 @@ static void windowing_and_mdct_ltp(AACContext *ac, float *out,
const float *swindow_prev = ics->use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128;
if (ics->window_sequence[0] != LONG_STOP_SEQUENCE) {
- ac->fdsp.vector_fmul(in, in, lwindow_prev, 1024);
+ ac->fdsp->vector_fmul(in, in, lwindow_prev, 1024);
} else {
memset(in, 0, 448 * sizeof(float));
- ac->fdsp.vector_fmul(in + 448, in + 448, swindow_prev, 128);
+ 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);
+ 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);
+ ac->fdsp->vector_fmul_reverse(in + 1024 + 448, in + 1024 + 448, swindow, 128);
memset(in + 1024 + 576, 0, 448 * sizeof(float));
}
ac->mdct_ltp.mdct_calc(&ac->mdct_ltp, out, in);
@@ -2324,10 +2453,10 @@ static void apply_ltp(AACContext *ac, SingleChannelElement *sce)
predTime[i] = sce->ltp_state[i + 2048 - ltp->lag] * ltp->coef;
memset(&predTime[i], 0, (2048 - i) * sizeof(float));
- windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics);
+ ac->windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics);
if (sce->tns.present)
- apply_tns(predFreq, &sce->tns, &sce->ics, 0);
+ 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])
@@ -2351,17 +2480,17 @@ static void update_ltp(AACContext *ac, SingleChannelElement *sce)
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
memcpy(saved_ltp, saved, 512 * sizeof(float));
memset(saved_ltp + 576, 0, 448 * sizeof(float));
- ac->fdsp.vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64);
+ 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] = 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(float));
memset(saved_ltp + 576, 0, 448 * sizeof(float));
- ac->fdsp.vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64);
+ 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] = 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);
+ ac->fdsp->vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512);
for (i = 0; i < 512; i++)
saved_ltp[i + 512] = ac->buf_mdct[1023 - i] * lwindow[511 - i];
}
@@ -2402,19 +2531,19 @@ static void imdct_and_windowing(AACContext *ac, SingleChannelElement *sce)
*/
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);
+ ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512);
} else {
memcpy( out, saved, 448 * sizeof(float));
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);
+ 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(float));
} else {
- ac->fdsp.vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64);
+ ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64);
memcpy( out + 576, buf + 64, 448 * sizeof(float));
}
}
@@ -2422,9 +2551,9 @@ static void imdct_and_windowing(AACContext *ac, SingleChannelElement *sce)
// buffer update
if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
memcpy( saved, temp + 64, 64 * sizeof(float));
- 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);
+ 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(float));
} else if (ics->window_sequence[0] == LONG_START_SEQUENCE) {
memcpy( saved, buf + 512, 448 * sizeof(float));
@@ -2449,10 +2578,10 @@ static void imdct_and_windowing_ld(AACContext *ac, SingleChannelElement *sce)
if (ics->use_kb_window[1]) {
// AAC LD uses a low overlap sine window instead of a KBD window
memcpy(out, saved, 192 * sizeof(float));
- ac->fdsp.vector_fmul_window(out + 192, saved + 192, buf, ff_sine_128, 64);
+ ac->fdsp->vector_fmul_window(out + 192, saved + 192, buf, ff_sine_128, 64);
memcpy( out + 320, buf + 64, 192 * sizeof(float));
} else {
- ac->fdsp.vector_fmul_window(out, saved, buf, ff_sine_512, 256);
+ ac->fdsp->vector_fmul_window(out, saved, buf, ff_sine_512, 256);
}
// buffer update
@@ -2475,7 +2604,7 @@ static void imdct_and_windowing_eld(AACContext *ac, SingleChannelElement *sce)
// 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,"
- // Audio, Language and Image Processing, 2008. ICALIP 2008. International Conference on
+ // 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) {
float temp;
@@ -2624,36 +2753,36 @@ static void spectral_to_sample(AACContext *ac)
imdct_and_window = imdct_and_windowing_eld;
break;
default:
- imdct_and_window = imdct_and_windowing;
+ imdct_and_window = ac->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) {
+ if (che && che->present) {
if (type <= TYPE_CPE)
apply_channel_coupling(ac, che, type, i, BEFORE_TNS, 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)
- apply_ltp(ac, &che->ch[0]);
+ ac->apply_ltp(ac, &che->ch[0]);
if (che->ch[1].ics.ltp.present && type == TYPE_CPE)
- apply_ltp(ac, &che->ch[1]);
+ ac->apply_ltp(ac, &che->ch[1]);
}
}
if (che->ch[0].tns.present)
- apply_tns(che->ch[0].coeffs, &che->ch[0].tns, &che->ch[0].ics, 1);
+ ac->apply_tns(che->ch[0].coeffs, &che->ch[0].tns, &che->ch[0].ics, 1);
if (che->ch[1].tns.present)
- apply_tns(che->ch[1].coeffs, &che->ch[1].tns, &che->ch[1].ics, 1);
+ ac->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, 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)
- update_ltp(ac, &che->ch[0]);
+ ac->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)
- update_ltp(ac, &che->ch[1]);
+ ac->update_ltp(ac, &che->ch[1]);
}
if (ac->oc[1].m4ac.sbr > 0) {
ff_sbr_apply(ac, &che->sbr, type, che->ch[0].ret, che->ch[1].ret);
@@ -2661,6 +2790,9 @@ static void spectral_to_sample(AACContext *ac)
}
if (type <= TYPE_CCE)
apply_channel_coupling(ac, che, type, i, AFTER_IMDCT, apply_independent_coupling);
+ che->present = 0;
+ } else if (che) {
+ av_log(ac->avctx, AV_LOG_VERBOSE, "ChannelElement %d.%d missing \n", type, i);
}
}
}
@@ -2675,10 +2807,12 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb)
size = avpriv_aac_parse_header(gb, &hdr_info);
if (size > 0) {
- if (hdr_info.num_aac_frames != 1) {
+ if (!ac->warned_num_aac_frames && hdr_info.num_aac_frames != 1) {
+ // This is 2 for "VLB " audio in NSV files.
+ // See samples/nsv/vlb_audio.
avpriv_report_missing_feature(ac->avctx,
"More than one AAC RDB per ADTS frame");
- return AVERROR_PATCHWELCOME;
+ ac->warned_num_aac_frames = 1;
}
push_output_configuration(ac);
if (hdr_info.chan_config) {
@@ -2694,6 +2828,21 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb)
return ret;
} else {
ac->oc[1].m4ac.chan_config = 0;
+ /**
+ * dual mono frames in Japanese DTV can have chan_config 0
+ * WITHOUT specifying PCE.
+ * thus, set dual mono as default.
+ */
+ if (ac->dmono_mode && ac->oc[0].status == OC_NONE) {
+ layout_map_tags = 2;
+ layout_map[0][0] = layout_map[1][0] = TYPE_SCE;
+ 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))
+ return -7;
+ }
}
ac->oc[1].m4ac.sample_rate = hdr_info.sample_rate;
ac->oc[1].m4ac.sampling_index = hdr_info.sampling_index;
@@ -2750,6 +2899,7 @@ static int aac_decode_er_frame(AVCodecContext *avctx, void *data,
elem_type, elem_id);
return AVERROR_INVALIDDATA;
}
+ che->present = 1;
if (aot != AOT_ER_AAC_ELD)
skip_bits(gb, 4);
switch (elem_type) {
@@ -2778,13 +2928,14 @@ static int aac_decode_er_frame(AVCodecContext *avctx, void *data,
}
static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
- int *got_frame_ptr, GetBitContext *gb)
+ int *got_frame_ptr, GetBitContext *gb, AVPacket *avpkt)
{
AACContext *ac = avctx->priv_data;
ChannelElement *che = NULL, *che_prev = NULL;
enum RawDataBlockType elem_type, elem_type_prev = TYPE_END;
int err, elem_id;
int samples = 0, multiplier, audio_found = 0, pce_found = 0;
+ int is_dmono, sce_count = 0;
ac->frame = data;
@@ -2812,6 +2963,9 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
while ((elem_type = get_bits(gb, 3)) != TYPE_END) {
elem_id = get_bits(gb, 4);
+ if (avctx->debug & FF_DEBUG_STARTCODE)
+ av_log(avctx, AV_LOG_DEBUG, "Elem type:%x id:%x\n", elem_type, elem_id);
+
if (elem_type < TYPE_DSE) {
if (!(che=get_che(ac, elem_type, elem_id))) {
av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n",
@@ -2820,6 +2974,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
goto fail;
}
samples = 1024;
+ che->present = 1;
}
switch (elem_type) {
@@ -2827,6 +2982,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
case TYPE_SCE:
err = decode_ics(ac, &che->ch[0], gb, 0, 0);
audio_found = 1;
+ sce_count++;
break;
case TYPE_CPE:
@@ -2859,9 +3015,10 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
if (pce_found) {
av_log(avctx, AV_LOG_ERROR,
"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);
+ if (!err)
+ ac->oc[1].m4ac.chan_config = 0;
pce_found = 1;
}
break;
@@ -2871,7 +3028,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
if (elem_id == 15)
elem_id += get_bits(gb, 8) - 1;
if (get_bits_left(gb) < 8 * elem_id) {
- av_log(avctx, AV_LOG_ERROR, overread_err);
+ av_log(avctx, AV_LOG_ERROR, "TYPE_FIL: "overread_err);
err = AVERROR_INVALIDDATA;
goto fail;
}
@@ -2909,12 +3066,36 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data,
ac->oc[1].status = OC_LOCKED;
}
+ if (multiplier) {
+ int side_size;
+ const uint8_t *side = av_packet_get_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, &side_size);
+ if (side && side_size>=4)
+ AV_WL32(side, 2*AV_RL32(side));
+ }
+
+ if (!ac->frame->data[0] && samples) {
+ av_log(avctx, AV_LOG_ERROR, "no frame data found\n");
+ err = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
if (samples) {
ac->frame->nb_samples = samples;
ac->frame->sample_rate = avctx->sample_rate;
- }
+ } else
+ av_frame_unref(ac->frame);
*got_frame_ptr = !!samples;
+ /* for dual-mono audio (SCE + SCE) */
+ is_dmono = ac->dmono_mode && sce_count == 2 &&
+ ac->oc[1].channel_layout == (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT);
+ if (is_dmono) {
+ if (ac->dmono_mode == 1)
+ ((AVFrame *)data)->data[1] =((AVFrame *)data)->data[0];
+ else if (ac->dmono_mode == 2)
+ ((AVFrame *)data)->data[0] =((AVFrame *)data)->data[1];
+ }
+
return 0;
fail:
pop_output_configuration(ac);
@@ -2935,8 +3116,12 @@ static int aac_decode_frame(AVCodecContext *avctx, void *data,
const uint8_t *new_extradata = av_packet_get_side_data(avpkt,
AV_PKT_DATA_NEW_EXTRADATA,
&new_extradata_size);
+ int jp_dualmono_size;
+ const uint8_t *jp_dualmono = av_packet_get_side_data(avpkt,
+ AV_PKT_DATA_JP_DUALMONO,
+ &jp_dualmono_size);
- if (new_extradata) {
+ if (new_extradata && 0) {
av_free(avctx->extradata);
avctx->extradata = av_mallocz(new_extradata_size +
FF_INPUT_BUFFER_PADDING_SIZE);
@@ -2953,6 +3138,15 @@ static int aac_decode_frame(AVCodecContext *avctx, void *data,
}
}
+ ac->dmono_mode = 0;
+ if (jp_dualmono && jp_dualmono_size > 0)
+ ac->dmono_mode = 1 + *jp_dualmono;
+ if (ac->force_dmono_mode >= 0)
+ ac->dmono_mode = ac->force_dmono_mode;
+
+ if (INT_MAX / 8 <= buf_size)
+ return AVERROR_INVALIDDATA;
+
if ((err = init_get_bits(&gb, buf, buf_size * 8)) < 0)
return err;
@@ -2964,7 +3158,7 @@ static int aac_decode_frame(AVCodecContext *avctx, void *data,
err = aac_decode_er_frame(avctx, data, got_frame_ptr, &gb);
break;
default:
- err = aac_decode_frame_int(avctx, data, got_frame_ptr, &gb);
+ err = aac_decode_frame_int(avctx, data, got_frame_ptr, &gb, avpkt);
}
if (err < 0)
return err;
@@ -2995,6 +3189,7 @@ static av_cold int aac_decode_close(AVCodecContext *avctx)
ff_mdct_end(&ac->mdct_ld);
ff_mdct_end(&ac->mdct_ltp);
ff_imdct15_uninit(&ac->mdct480);
+ av_freep(&ac->fdsp);
return 0;
}
@@ -3003,7 +3198,7 @@ static av_cold int aac_decode_close(AVCodecContext *avctx)
struct LATMContext {
AACContext aac_ctx; ///< containing AACContext
- int initialized; ///< initilized after a valid extradata was seen
+ int initialized; ///< initialized after a valid extradata was seen
// parser data
int audio_mux_version_A; ///< LATM syntax version
@@ -3052,7 +3247,11 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx,
ac->oc[1].m4ac.sample_rate != m4ac.sample_rate ||
ac->oc[1].m4ac.chan_config != m4ac.chan_config) {
- av_log(avctx, AV_LOG_INFO, "audio config changed\n");
+ if(latmctx->initialized) {
+ av_log(avctx, AV_LOG_INFO, "audio config changed\n");
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "initializing latmctx\n");
+ }
latmctx->initialized = 0;
esize = (bits_consumed+7) / 8;
@@ -3095,9 +3294,9 @@ static int read_stream_mux_config(struct LATMContext *latmctx,
return AVERROR_PATCHWELCOME;
}
- // for each program (which there is only on in DVB)
+ // for each program (which there is only one in DVB)
- // for each layer (which there is only on in DVB)
+ // for each layer (which there is only one in DVB)
if (get_bits(gb, 3)) { // numLayer
avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple layers");
return AVERROR_PATCHWELCOME;
@@ -3210,7 +3409,7 @@ static int latm_decode_frame(AVCodecContext *avctx, void *out,
int muxlength, err;
GetBitContext gb;
- if ((err = init_get_bits(&gb, avpkt->data, avpkt->size * 8)) < 0)
+ if ((err = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
return err;
// check for LOAS sync word
@@ -3218,7 +3417,7 @@ static int latm_decode_frame(AVCodecContext *avctx, void *out,
return AVERROR_INVALIDDATA;
muxlength = get_bits(&gb, 13) + 3;
- // not enough data, the parser should have sorted this
+ // not enough data, the parser should have sorted this out
if (muxlength > avpkt->size)
return AVERROR_INVALIDDATA;
@@ -3256,7 +3455,7 @@ static int latm_decode_frame(AVCodecContext *avctx, void *out,
err = aac_decode_er_frame(avctx, out, got_frame_ptr, &gb);
break;
default:
- err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb);
+ err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb, avpkt);
}
if (err < 0)
return err;
@@ -3275,6 +3474,52 @@ static av_cold int latm_decode_init(AVCodecContext *avctx)
return ret;
}
+static void aacdec_init(AACContext *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(ARCH_MIPS)
+ ff_aacdec_init_mips(c);
+}
+/**
+ * AVOptions for Japanese DTV specific extensions (ADTS only)
+ */
+#define AACDEC_FLAGS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption options[] = {
+ {"dual_mono_mode", "Select the channel to decode for dual mono",
+ offsetof(AACContext, force_dmono_mode), AV_OPT_TYPE_INT, {.i64=-1}, -1, 2,
+ AACDEC_FLAGS, "dual_mono_mode"},
+
+ {"auto", "autoselection", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
+ {"main", "Select Main/Left channel", 0, AV_OPT_TYPE_CONST, {.i64= 1}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
+ {"sub" , "Select Sub/Right channel", 0, AV_OPT_TYPE_CONST, {.i64= 2}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
+ {"both", "Select both channels", 0, AV_OPT_TYPE_CONST, {.i64= 0}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"},
+
+ {NULL},
+};
+
+static const AVClass aac_decoder_class = {
+ .class_name = "AAC decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVProfile profiles[] = {
+ { FF_PROFILE_AAC_MAIN, "Main" },
+ { FF_PROFILE_AAC_LOW, "LC" },
+ { FF_PROFILE_AAC_SSR, "SSR" },
+ { FF_PROFILE_AAC_LTP, "LTP" },
+ { FF_PROFILE_AAC_HE, "HE-AAC" },
+ { FF_PROFILE_AAC_HE_V2, "HE-AACv2" },
+ { FF_PROFILE_AAC_LD, "LD" },
+ { FF_PROFILE_AAC_ELD, "ELD" },
+ { FF_PROFILE_UNKNOWN },
+};
AVCodec ff_aac_decoder = {
.name = "aac",
@@ -3290,6 +3535,9 @@ AVCodec ff_aac_decoder = {
},
.capabilities = CODEC_CAP_CHANNEL_CONF | CODEC_CAP_DR1,
.channel_layouts = aac_channel_layout,
+ .flush = flush,
+ .priv_class = &aac_decoder_class,
+ .profiles = profiles,
};
/*
@@ -3311,4 +3559,6 @@ AVCodec ff_aac_latm_decoder = {
},
.capabilities = CODEC_CAP_CHANNEL_CONF | CODEC_CAP_DR1,
.channel_layouts = aac_channel_layout,
+ .flush = flush,
+ .profiles = profiles,
};
diff --git a/libavcodec/aacdectab.h b/libavcodec/aacdectab.h
index 4c23f2d03d..4a12b4fb32 100644
--- a/libavcodec/aacdectab.h
+++ b/libavcodec/aacdectab.h
@@ -3,20 +3,20 @@
* 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c
index a28e1a1290..897c3a10df 100644
--- a/libavcodec/aacenc.c
+++ b/libavcodec/aacenc.c
@@ -2,20 +2,20 @@
* AAC encoder
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -53,6 +53,11 @@
return AVERROR(EINVAL); \
}
+#define WARN_IF(cond, ...) \
+ if (cond) { \
+ av_log(avctx, AV_LOG_WARNING, __VA_ARGS__); \
+ }
+
float ff_aac_pow34sf_tab[428];
static const uint8_t swb_size_1024_96[] = {
@@ -102,7 +107,8 @@ static const uint8_t *swb_size_1024[] = {
swb_size_1024_96, swb_size_1024_96, swb_size_1024_64,
swb_size_1024_48, swb_size_1024_48, swb_size_1024_32,
swb_size_1024_24, swb_size_1024_24, swb_size_1024_16,
- swb_size_1024_16, swb_size_1024_16, swb_size_1024_8
+ swb_size_1024_16, swb_size_1024_16, swb_size_1024_8,
+ swb_size_1024_8
};
static const uint8_t swb_size_128_96[] = {
@@ -131,7 +137,8 @@ static const uint8_t *swb_size_128[] = {
swb_size_128_96, swb_size_128_96, swb_size_128_96,
swb_size_128_48, swb_size_128_48, swb_size_128_48,
swb_size_128_24, swb_size_128_24, swb_size_128_16,
- swb_size_128_16, swb_size_128_16, swb_size_128_8
+ swb_size_128_16, swb_size_128_16, swb_size_128_8,
+ swb_size_128_8
};
/** default channel configurations */
@@ -145,7 +152,7 @@ static const uint8_t aac_chan_configs[6][5] = {
};
/**
- * Table to remap channels from Libav's default order to AAC order.
+ * Table to remap channels from libavcodec's default order to AAC order.
*/
static const uint8_t aac_chan_maps[AAC_MAX_CHANNELS][AAC_MAX_CHANNELS] = {
{ 0 },
@@ -165,7 +172,7 @@ static void put_audio_specific_config(AVCodecContext *avctx)
PutBitContext pb;
AACEncContext *s = avctx->priv_data;
- init_put_bits(&pb, avctx->extradata, avctx->extradata_size*8);
+ init_put_bits(&pb, avctx->extradata, avctx->extradata_size);
put_bits(&pb, 5, 2); //object type - AAC-LC
put_bits(&pb, 4, s->samplerate_index); //sample rate index
put_bits(&pb, 4, s->channels);
@@ -252,7 +259,7 @@ static void apply_window_and_mdct(AACEncContext *s, SingleChannelElement *sce,
int i;
float *output = sce->ret_buf;
- apply_window[sce->ics.window_sequence[0]](&s->fdsp, sce, audio);
+ apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, audio);
if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE)
s->mdct1024.mdct_calc(&s->mdct1024, sce->coeffs, output);
@@ -260,6 +267,7 @@ static void apply_window_and_mdct(AACEncContext *s, SingleChannelElement *sce,
for (i = 0; i < 1024; i += 128)
s->mdct128.mdct_calc(&s->mdct128, sce->coeffs + i, output + i*2);
memcpy(audio, audio + 1024, sizeof(audio[0]) * 1024);
+ memcpy(sce->pcoeffs, sce->coeffs, sizeof(sce->pcoeffs));
}
/**
@@ -311,20 +319,23 @@ static void adjust_frame_information(ChannelElement *cpe, int chans)
start = 0;
maxsfb = 0;
cpe->ch[ch].pulse.num_pulse = 0;
- for (w = 0; w < ics->num_windows*16; w += 16) {
- for (g = 0; g < ics->num_swb; g++) {
- //apply M/S
- if (cpe->common_window && !ch && cpe->ms_mask[w + g]) {
- for (i = 0; i < ics->swb_sizes[g]; i++) {
- cpe->ch[0].coeffs[start+i] = (cpe->ch[0].coeffs[start+i] + cpe->ch[1].coeffs[start+i]) / 2.0;
- cpe->ch[1].coeffs[start+i] = cpe->ch[0].coeffs[start+i] - cpe->ch[1].coeffs[start+i];
+ for (w = 0; w < ics->num_windows; w += ics->group_len[w]) {
+ for (w2 = 0; w2 < ics->group_len[w]; w2++) {
+ start = (w+w2) * 128;
+ for (g = 0; g < ics->num_swb; g++) {
+ //apply M/S
+ if (cpe->common_window && !ch && cpe->ms_mask[w*16 + g]) {
+ for (i = 0; i < ics->swb_sizes[g]; i++) {
+ cpe->ch[0].coeffs[start+i] = (cpe->ch[0].pcoeffs[start+i] + cpe->ch[1].pcoeffs[start+i]) * 0.5f;
+ cpe->ch[1].coeffs[start+i] = cpe->ch[0].coeffs[start+i] - cpe->ch[1].pcoeffs[start+i];
+ }
}
+ start += ics->swb_sizes[g];
}
- start += ics->swb_sizes[g];
+ 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+cmaxsfb-1]; cmaxsfb--)
- ;
- maxsfb = FFMAX(maxsfb, cmaxsfb);
}
ics->max_sfb = maxsfb;
@@ -377,16 +388,26 @@ static void encode_band_info(AACEncContext *s, SingleChannelElement *sce)
static void encode_scale_factors(AVCodecContext *avctx, AACEncContext *s,
SingleChannelElement *sce)
{
- int off = sce->sf_idx[0], diff;
+ int diff, off_sf = sce->sf_idx[0], off_pns = sce->sf_idx[0] - NOISE_OFFSET;
+ int noise_flag = 1;
int i, w;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (i = 0; i < sce->ics.max_sfb; i++) {
if (!sce->zeroes[w*16 + i]) {
- diff = sce->sf_idx[w*16 + i] - off + SCALE_DIFF_ZERO;
- if (diff < 0 || diff > 120)
- av_log(avctx, AV_LOG_ERROR, "Scalefactor difference is too big to be coded\n");
- off = sce->sf_idx[w*16 + i];
+ if (sce->band_type[w*16 + i] == NOISE_BT) {
+ diff = sce->sf_idx[w*16 + i] - off_pns;
+ off_pns = sce->sf_idx[w*16 + i];
+ if (noise_flag-- > 0) {
+ put_bits(&s->pb, NOISE_PRE_BITS, diff + NOISE_PRE);
+ continue;
+ }
+ } else {
+ diff = sce->sf_idx[w*16 + i] - off_sf;
+ off_sf = sce->sf_idx[w*16 + i];
+ }
+ diff += SCALE_DIFF_ZERO;
+ av_assert0(diff >= 0 && diff <= 120);
put_bits(&s->pb, ff_aac_scalefactor_bits[diff], ff_aac_scalefactor_code[diff]);
}
}
@@ -478,7 +499,7 @@ static void put_bitstream_info(AACEncContext *s, const char *name)
/*
* Copy input samples.
- * Channels are reordered from Libav's default order to AAC order.
+ * Channels are reordered from libavcodec's default order to AAC order.
*/
static void copy_input_samples(AACEncContext *s, const AVFrame *frame)
{
@@ -508,7 +529,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
AACEncContext *s = avctx->priv_data;
float **samples = s->planar_samples, *samples2, *la, *overlap;
ChannelElement *cpe;
- int i, ch, w, g, chans, tag, start_ch, ret;
+ int i, ch, w, g, chans, tag, start_ch, ret, ms_mode = 0;
int chan_el_counter[4];
FFPsyWindowInfo windows[AAC_MAX_CHANNELS];
@@ -568,14 +589,15 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
ics->group_len[w] = wi[ch].grouping[w];
apply_window_and_mdct(s, &cpe->ch[ch], overlap);
+ if (isnan(cpe->ch->coeffs[0])) {
+ av_log(avctx, AV_LOG_ERROR, "Input contains NaN\n");
+ return AVERROR(EINVAL);
+ }
}
start_ch += chans;
}
- if ((ret = ff_alloc_packet(avpkt, 768 * s->channels))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 8192 * s->channels)) < 0)
return ret;
- }
-
do {
int frame_bits;
@@ -630,6 +652,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
if (cpe->common_window) {
put_ics_info(s, &cpe->ch[0].ics);
encode_ms_info(&s->pb, cpe);
+ if (cpe->ms_mode) ms_mode = 1;
}
}
for (ch = 0; ch < chans; ch++) {
@@ -644,6 +667,15 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
s->psy.bitres.bits = frame_bits / s->channels;
break;
}
+ if (ms_mode) {
+ for (i = 0; i < s->chan_map[0]; i++) {
+ // Must restore coeffs
+ chans = tag == TYPE_CPE ? 2 : 1;
+ cpe = &s->cpe[i];
+ for (ch = 0; ch < chans; ch++)
+ memcpy(cpe->ch[ch].coeffs, cpe->ch[ch].pcoeffs, sizeof(cpe->ch[ch].coeffs));
+ }
+ }
s->lambda *= avctx->bit_rate * 1024.0f / avctx->sample_rate / frame_bits;
@@ -682,6 +714,7 @@ static av_cold int aac_encode_end(AVCodecContext *avctx)
ff_psy_preprocess_end(s->psypp);
av_freep(&s->buffer.samples);
av_freep(&s->cpe);
+ av_freep(&s->fdsp);
ff_af_queue_close(&s->afq);
return 0;
}
@@ -690,7 +723,9 @@ static av_cold int dsp_init(AVCodecContext *avctx, AACEncContext *s)
{
int ret = 0;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
// window init
ff_kbd_window_init(ff_aac_kbd_long_1024, 4.0, 1024);
@@ -698,9 +733,9 @@ static av_cold int dsp_init(AVCodecContext *avctx, AACEncContext *s)
ff_init_ff_sine_windows(10);
ff_init_ff_sine_windows(7);
- if (ret = ff_mdct_init(&s->mdct1024, 11, 0, 32768.0))
+ if ((ret = ff_mdct_init(&s->mdct1024, 11, 0, 32768.0)) < 0)
return ret;
- if (ret = ff_mdct_init(&s->mdct128, 8, 0, 32768.0))
+ if ((ret = ff_mdct_init(&s->mdct128, 8, 0, 32768.0)) < 0)
return ret;
return 0;
@@ -709,8 +744,8 @@ static av_cold int dsp_init(AVCodecContext *avctx, AACEncContext *s)
static av_cold int alloc_buffers(AVCodecContext *avctx, AACEncContext *s)
{
int ch;
- FF_ALLOCZ_OR_GOTO(avctx, s->buffer.samples, 3 * 1024 * s->channels * sizeof(s->buffer.samples[0]), alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, s->cpe, sizeof(ChannelElement) * s->chan_map[0], alloc_fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->buffer.samples, s->channels, 3 * 1024 * sizeof(s->buffer.samples[0]), alloc_fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->cpe, s->chan_map[0], sizeof(ChannelElement), alloc_fail);
FF_ALLOCZ_OR_GOTO(avctx, avctx->extradata, 5 + FF_INPUT_BUFFER_PADDING_SIZE, alloc_fail);
for(ch = 0; ch < s->channels; ch++)
@@ -737,14 +772,20 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
s->channels = avctx->channels;
- ERROR_IF(i == 16,
+ ERROR_IF(i == 16
+ || i >= (sizeof(swb_size_1024) / sizeof(*swb_size_1024))
+ || i >= (sizeof(swb_size_128) / sizeof(*swb_size_128)),
"Unsupported sample rate %d\n", avctx->sample_rate);
ERROR_IF(s->channels > AAC_MAX_CHANNELS,
"Unsupported number of channels: %d\n", s->channels);
ERROR_IF(avctx->profile != FF_PROFILE_UNKNOWN && avctx->profile != FF_PROFILE_AAC_LOW,
"Unsupported profile %d\n", avctx->profile);
- ERROR_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels,
- "Too many bits per frame requested\n");
+ WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels,
+ "Too many bits per frame requested, clamping to max\n");
+
+ avctx->bit_rate = (int)FFMIN(
+ 6144 * s->channels / 1024.0 * avctx->sample_rate,
+ avctx->bit_rate);
s->samplerate_index = i;
@@ -769,9 +810,12 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
s->chan_map[0], grouping)) < 0)
goto fail;
s->psypp = ff_psy_preprocess_init(avctx);
- s->coder = &ff_aac_coders[2];
+ s->coder = &ff_aac_coders[s->options.aac_coder];
- s->lambda = avctx->global_quality ? avctx->global_quality : 120;
+ if (HAVE_MIPSDSPR1)
+ ff_aac_coder_init_mips(s);
+
+ s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120;
ff_aac_tableinit();
@@ -793,6 +837,14 @@ static const AVOption aacenc_options[] = {
{"auto", "Selected by the Encoder", 0, AV_OPT_TYPE_CONST, {.i64 = -1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"},
{"ms_off", "Disable Mid/Side coding", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"},
{"ms_force", "Force Mid/Side for the whole frame if possible", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "stereo_mode"},
+ {"aac_coder", "", offsetof(AACEncContext, options.aac_coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "aac_coder"},
+ {"faac", "FAAC-inspired method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAAC}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
+ {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
+ {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
+ {"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
+ {"aac_pns", "Perceptual Noise Substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AACENC_FLAGS, "aac_pns"},
+ {"disable", "Disable PNS", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_pns"},
+ {"enable", "Enable PNS (Proof of concept)", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_pns"},
{NULL}
};
@@ -803,6 +855,13 @@ static const AVClass aacenc_class = {
LIBAVUTIL_VERSION_INT,
};
+/* duplicated from avpriv_mpeg4audio_sample_rates to avoid shared build
+ * failures */
+static const int mpeg4audio_sample_rates[16] = {
+ 96000, 88200, 64000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000, 11025, 8000, 7350
+};
+
AVCodec ff_aac_encoder = {
.name = "aac",
.long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"),
@@ -812,6 +871,7 @@ AVCodec ff_aac_encoder = {
.init = aac_encode_init,
.encode2 = aac_encode_frame,
.close = aac_encode_end,
+ .supported_samplerates = mpeg4audio_sample_rates,
.capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY |
CODEC_CAP_EXPERIMENTAL,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h
index dec445ce34..7c1f277fa1 100644
--- a/libavcodec/aacenc.h
+++ b/libavcodec/aacenc.h
@@ -2,20 +2,20 @@
* AAC encoder
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,8 +30,19 @@
#include "audio_frame_queue.h"
#include "psymodel.h"
+typedef enum AACCoder {
+ AAC_CODER_FAAC = 0,
+ AAC_CODER_ANMR,
+ AAC_CODER_TWOLOOP,
+ AAC_CODER_FAST,
+
+ AAC_CODER_NB,
+}AACCoder;
+
typedef struct AACEncOptions {
int stereo_mode;
+ int aac_coder;
+ int pns;
} AACEncOptions;
struct AACEncContext;
@@ -57,7 +68,7 @@ typedef struct AACEncContext {
PutBitContext pb;
FFTContext mdct1024; ///< long (1024 samples) frame transform context
FFTContext mdct128; ///< short (128 samples) frame transform context
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
float *planar_samples[6]; ///< saved preprocessed input
int samplerate_index; ///< MPEG-4 samplerate index
@@ -82,4 +93,6 @@ typedef struct AACEncContext {
extern float ff_aac_pow34sf_tab[428];
+void ff_aac_coder_init_mips(AACEncContext *c);
+
#endif /* AVCODEC_AACENC_H */
diff --git a/libavcodec/aacps.c b/libavcodec/aacps.c
index df069c3e6d..ea5a5d2331 100644
--- a/libavcodec/aacps.c
+++ b/libavcodec/aacps.c
@@ -2,20 +2,20 @@
* MPEG-4 Parametric Stereo decoding functions
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -236,6 +236,7 @@ int ff_ps_read_data(AVCodecContext *avctx, GetBitContext *gb_host, PSContext *ps
if (!ps->num_env || ps->border_position[ps->num_env] < numQMFSlots - 1) {
//Create a fake envelope
int source = ps->num_env ? ps->num_env - 1 : ps->num_env_old - 1;
+ int b;
if (source >= 0 && source != ps->num_env) {
if (ps->enable_iid) {
memcpy(ps->iid_par+ps->num_env, ps->iid_par+source, sizeof(ps->iid_par[0]));
@@ -248,6 +249,22 @@ int ff_ps_read_data(AVCodecContext *avctx, GetBitContext *gb_host, PSContext *ps
memcpy(ps->opd_par+ps->num_env, ps->opd_par+source, sizeof(ps->opd_par[0]));
}
}
+ if (ps->enable_iid){
+ for (b = 0; b < ps->nr_iid_par; b++) {
+ if (FFABS(ps->iid_par[ps->num_env][b]) > 7 + 8 * ps->iid_quant) {
+ av_log(avctx, AV_LOG_ERROR, "iid_par invalid\n");
+ goto err;
+ }
+ }
+ }
+ if (ps->enable_icc){
+ for (b = 0; b < ps->nr_iid_par; b++) {
+ if (ps->icc_par[ps->num_env][b] > 7U) {
+ av_log(avctx, AV_LOG_ERROR, "icc_par invalid\n");
+ goto err;
+ }
+ }
+ }
ps->num_env++;
ps->border_position[ps->num_env] = numQMFSlots - 1;
}
@@ -415,6 +432,7 @@ static void hybrid_synthesis(PSDSPContext *dsp, float out[2][38][64],
#define DECAY_SLOPE 0.05f
/// Number of frequency bands that can be addressed by the parameter index, b(k)
static const int NR_PAR_BANDS[] = { 20, 34 };
+static const int NR_IPDOPD_BANDS[] = { 11, 17 };
/// Number of frequency bands that can be addressed by the sub subband index, k
static const int NR_BANDS[] = { 71, 91 };
/// Start frequency band for the all-pass filter decay slope
@@ -606,7 +624,6 @@ static void map_val_20_to_34(float par[PS_MAX_NR_IIDICC])
par[ 3] = par[ 2];
par[ 2] = par[ 1];
par[ 1] = (par[ 0] + par[ 1]) * 0.5f;
- par[ 0] = par[ 0];
}
static void decorrelation(PSContext *ps, float (*out)[32][2], const float (*s)[32][2], int is34)
@@ -811,7 +828,8 @@ static void stereo_processing(PSContext *ps, float (*l)[32][2], float (*r)[32][2
h12 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][1];
h21 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][2];
h22 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][3];
- if (!PS_BASELINE && ps->enable_ipdopd && b < ps->nr_ipdopd_par) {
+
+ if (!PS_BASELINE && ps->enable_ipdopd && b < NR_IPDOPD_BANDS[is34]) {
//The spec say says to only run this smoother when enable_ipdopd
//is set but the reference decoder appears to run it constantly
float h11i, h12i, h21i, h22i;
@@ -890,8 +908,8 @@ static void stereo_processing(PSContext *ps, float (*l)[32][2], float (*r)[32][2
int ff_ps_apply(AVCodecContext *avctx, PSContext *ps, float L[2][38][64], float R[2][38][64], int top)
{
- LOCAL_ALIGNED_16(float, Lbuf, [91], [32][2]);
- LOCAL_ALIGNED_16(float, Rbuf, [91], [32][2]);
+ float (*Lbuf)[32][2] = ps->Lbuf;
+ float (*Rbuf)[32][2] = ps->Rbuf;
const int len = 32;
int is34 = ps->is34bands;
diff --git a/libavcodec/aacps.h b/libavcodec/aacps.h
index e8a195ab2b..174770d6e4 100644
--- a/libavcodec/aacps.h
+++ b/libavcodec/aacps.h
@@ -2,20 +2,20 @@
* MPEG-4 Parametric Stereo definitions and declarations
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,6 +71,8 @@ typedef struct PSContext {
DECLARE_ALIGNED(16, float, H12)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC];
DECLARE_ALIGNED(16, float, H21)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC];
DECLARE_ALIGNED(16, float, H22)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC];
+ DECLARE_ALIGNED(16, float, Lbuf)[91][32][2];
+ DECLARE_ALIGNED(16, float, Rbuf)[91][32][2];
int8_t opd_hist[PS_MAX_NR_IIDICC];
int8_t ipd_hist[PS_MAX_NR_IIDICC];
PSDSPContext dsp;
diff --git a/libavcodec/aacps_tablegen.c b/libavcodec/aacps_tablegen.c
index 537b6ba651..f56930b958 100644
--- a/libavcodec/aacps_tablegen.c
+++ b/libavcodec/aacps_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -82,7 +82,7 @@ int main(void)
write_float_3d_array(f34_2_4, 4, 8, 2);
printf("};\n");
- printf("static TABLE_CONST DECLARE_ALIGNED(16, float, Q_fract_allpass)[2][50][3][2] = {\n");
+ printf("static const DECLARE_ALIGNED(16, float, Q_fract_allpass)[2][50][3][2] = {\n");
write_float_4d_array(Q_fract_allpass, 2, 50, 3, 2);
printf("};\n");
printf("static const DECLARE_ALIGNED(16, float, phi_fract)[2][50][2] = {\n");
diff --git a/libavcodec/aacps_tablegen.h b/libavcodec/aacps_tablegen.h
index a53f9fac1f..ca1112ddd0 100644
--- a/libavcodec/aacps_tablegen.h
+++ b/libavcodec/aacps_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -70,7 +70,7 @@ static const float g2_Q4[] = {
0.16486303567403f, 0.23279856662996f, 0.25f
};
-static void make_filters_from_proto(float (*filter)[8][2], const float *proto, int bands)
+static av_cold void make_filters_from_proto(float (*filter)[8][2], const float *proto, int bands)
{
int q, n;
for (q = 0; q < bands; q++) {
@@ -82,7 +82,7 @@ static void make_filters_from_proto(float (*filter)[8][2], const float *proto, i
}
}
-static void ps_tableinit(void)
+static av_cold void ps_tableinit(void)
{
static const float ipdopd_sin[] = { 0, M_SQRT1_2, 1, M_SQRT1_2, 0, -M_SQRT1_2, -1, -M_SQRT1_2 };
static const float ipdopd_cos[] = { 1, M_SQRT1_2, 0, -M_SQRT1_2, -1, -M_SQRT1_2, 0, M_SQRT1_2 };
diff --git a/libavcodec/aacpsdata.c b/libavcodec/aacpsdata.c
index 675bd8e2b3..7431caebc6 100644
--- a/libavcodec/aacpsdata.c
+++ b/libavcodec/aacpsdata.c
@@ -2,20 +2,20 @@
* MPEG-4 Parametric Stereo data tables
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aacpsdsp.c b/libavcodec/aacpsdsp.c
index 88e731f925..5dc1a6aba9 100644
--- a/libavcodec/aacpsdsp.c
+++ b/libavcodec/aacpsdsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -211,4 +211,6 @@ av_cold void ff_psdsp_init(PSDSPContext *s)
if (ARCH_ARM)
ff_psdsp_init_arm(s);
+ if (ARCH_MIPS)
+ ff_psdsp_init_mips(s);
}
diff --git a/libavcodec/aacpsdsp.h b/libavcodec/aacpsdsp.h
index dc380b10d0..0ef30236ec 100644
--- a/libavcodec/aacpsdsp.h
+++ b/libavcodec/aacpsdsp.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,5 +49,6 @@ typedef struct PSDSPContext {
void ff_psdsp_init(PSDSPContext *s);
void ff_psdsp_init_arm(PSDSPContext *s);
+void ff_psdsp_init_mips(PSDSPContext *s);
#endif /* LIBAVCODEC_AACPSDSP_H */
diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c
index ac58968ab3..49ff3fe139 100644
--- a/libavcodec/aacpsy.c
+++ b/libavcodec/aacpsy.c
@@ -2,20 +2,20 @@
* AAC encoder psychoacoustic model
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,8 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/libm.h"
+
#include "avcodec.h"
#include "aactab.h"
#include "psymodel.h"
@@ -216,6 +218,10 @@ 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.
*/
@@ -294,7 +300,7 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) {
int i, j, g, start;
float prev, minscale, minath, minsnr, pe_min;
const int chan_bitrate = ctx->avctx->bit_rate / ctx->avctx->channels;
- const int bandwidth = ctx->avctx->cutoff ? ctx->avctx->cutoff : ctx->avctx->sample_rate / 2;
+ const int bandwidth = ctx->avctx->cutoff ? ctx->avctx->cutoff : AAC_CUTOFF(ctx->avctx);
const float num_bark = calc_bark((float)bandwidth);
ctx->model_priv_data = av_mallocz(sizeof(AacPsyContext));
@@ -335,7 +341,7 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) {
coeff->spread_low[1] = pow(10.0, -bark_width * en_spread_low);
coeff->spread_hi [1] = pow(10.0, -bark_width * en_spread_hi);
pe_min = bark_pe * bark_width;
- minsnr = pow(2.0f, pe_min / band_sizes[g]) - 1.5f;
+ minsnr = exp2(pe_min / band_sizes[g]) - 1.5f;
coeff->min_snr = av_clipf(1.0f / minsnr, PSY_SNR_25DB, PSY_SNR_1DB);
}
start = 0;
@@ -348,7 +354,7 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) {
}
}
- pctx->ch = av_mallocz(sizeof(AacPsyChannel) * ctx->avctx->channels);
+ pctx->ch = av_mallocz_array(ctx->avctx->channels, sizeof(AacPsyChannel));
lame_window_init(pctx, ctx->avctx);
@@ -526,8 +532,11 @@ static float calc_reduction_3gpp(float a, float desired_pe, float pe,
{
float thr_avg, reduction;
- thr_avg = powf(2.0f, (a - pe) / (4.0f * active_lines));
- reduction = powf(2.0f, (a - desired_pe) / (4.0f * active_lines)) - thr_avg;
+ if(active_lines == 0.0)
+ return 0;
+
+ thr_avg = exp2f((a - pe) / (4.0f * active_lines));
+ reduction = exp2f((a - desired_pe) / (4.0f * active_lines)) - thr_avg;
return FFMAX(reduction, 0.0f);
}
@@ -538,8 +547,10 @@ static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr,
float thr = band->thr;
if (band->energy > thr) {
- thr = powf(thr, 0.25f) + reduction;
- thr = powf(thr, 4.0f);
+ thr = sqrtf(thr);
+ thr = sqrtf(thr) + reduction;
+ thr *= thr;
+ thr *= thr;
/* This deviates from the 3GPP spec to match the reference encoder.
* It performs min(thr_reduced, max(thr, energy/min_snr)) only for bands
@@ -555,6 +566,52 @@ static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr,
return thr;
}
+#ifndef calc_thr_3gpp
+static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsyChannel *pch,
+ const uint8_t *band_sizes, const float *coefs)
+{
+ int i, w, g;
+ int start = 0;
+ for (w = 0; w < wi->num_windows*16; w += 16) {
+ for (g = 0; g < num_bands; g++) {
+ AacPsyBand *band = &pch->band[w+g];
+
+ float form_factor = 0.0f;
+ float Temp;
+ band->energy = 0.0f;
+ for (i = 0; i < band_sizes[g]; i++) {
+ band->energy += coefs[start+i] * coefs[start+i];
+ form_factor += sqrtf(fabs(coefs[start+i]));
+ }
+ Temp = band->energy > 0 ? sqrtf((float)band_sizes[g] / band->energy) : 0;
+ band->thr = band->energy * 0.001258925f;
+ band->nz_lines = form_factor * sqrtf(Temp);
+
+ start += band_sizes[g];
+ }
+ }
+}
+#endif /* calc_thr_3gpp */
+
+#ifndef psy_hp_filter
+static void psy_hp_filter(const float *firbuf, float *hpfsmpl, const float *psy_fir_coeffs)
+{
+ int i, j;
+ for (i = 0; i < AAC_BLOCK_SIZE_LONG; i++) {
+ float sum1, sum2;
+ sum1 = firbuf[i + (PSY_LAME_FIR_LEN - 1) / 2];
+ sum2 = 0.0;
+ for (j = 0; j < ((PSY_LAME_FIR_LEN - 1) / 2) - 1; j += 2) {
+ sum1 += psy_fir_coeffs[j] * (firbuf[i + j] + firbuf[i + PSY_LAME_FIR_LEN - j]);
+ sum2 += psy_fir_coeffs[j + 1] * (firbuf[i + j + 1] + firbuf[i + PSY_LAME_FIR_LEN - j - 1]);
+ }
+ /* NOTE: The LAME psymodel expects it's input in the range -32768 to 32768.
+ * Tuning this for normalized floats would be difficult. */
+ hpfsmpl[i] = (sum1 + sum2) * 32768.0f;
+ }
+}
+#endif /* psy_hp_filter */
+
/**
* Calculate band thresholds as suggested in 3GPP TS26.403
*/
@@ -563,9 +620,8 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
{
AacPsyContext *pctx = (AacPsyContext*) ctx->model_priv_data;
AacPsyChannel *pch = &pctx->ch[channel];
- int start = 0;
int i, w, g;
- float desired_bits, desired_pe, delta_pe, reduction, spread_en[128] = {0};
+ float desired_bits, desired_pe, delta_pe, reduction= NAN, spread_en[128] = {0};
float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f;
float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f);
const int num_bands = ctx->num_bands[wi->num_windows == 8];
@@ -574,22 +630,8 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG;
//calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation"
- for (w = 0; w < wi->num_windows*16; w += 16) {
- for (g = 0; g < num_bands; g++) {
- AacPsyBand *band = &pch->band[w+g];
+ calc_thr_3gpp(wi, num_bands, pch, band_sizes, coefs);
- float form_factor = 0.0f;
- band->energy = 0.0f;
- for (i = 0; i < band_sizes[g]; i++) {
- band->energy += coefs[start+i] * coefs[start+i];
- form_factor += sqrtf(fabs(coefs[start+i]));
- }
- band->thr = band->energy * 0.001258925f;
- band->nz_lines = form_factor / powf(band->energy / band_sizes[g], 0.25f);
-
- start += band_sizes[g];
- }
- }
//modify thresholds and energies - spread, threshold in quiet, pre-echo control
for (w = 0; w < wi->num_windows*16; w += 16) {
AacPsyBand *bands = &pch->band[w];
@@ -675,7 +717,7 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
}
desired_pe_no_ah = FFMAX(desired_pe - (pe - pe_no_ah), 0.0f);
if (active_lines > 0.0f)
- reduction += calc_reduction_3gpp(a, desired_pe_no_ah, pe_no_ah, active_lines);
+ reduction = calc_reduction_3gpp(a, desired_pe_no_ah, pe_no_ah, active_lines);
pe = 0.0f;
for (w = 0; w < wi->num_windows*16; w += 16) {
@@ -685,7 +727,10 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
if (active_lines > 0.0f)
band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction);
pe += calc_pe_3gpp(band);
- band->norm_fac = band->active_lines / band->thr;
+ if (band->thr > 0.0f)
+ band->norm_fac = band->active_lines / band->thr;
+ else
+ band->norm_fac = 0.0f;
norm_fac += band->norm_fac;
}
}
@@ -705,7 +750,7 @@ static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel,
float delta_sfb_pe = band->norm_fac * norm_fac * delta_pe;
float thr = band->thr;
- thr *= powf(2.0f, delta_sfb_pe / band->active_lines);
+ thr *= exp2f(delta_sfb_pe / band->active_lines);
if (thr > coeffs[g].min_snr * band->energy && band->avoid_holes == PSY_3GPP_AH_INACTIVE)
thr = FFMAX(band->thr, coeffs[g].min_snr * band->energy);
band->thr = thr;
@@ -795,21 +840,10 @@ static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio,
float energy_subshort[(AAC_NUM_BLOCKS_SHORT + 1) * PSY_LAME_NUM_SUBBLOCKS];
float energy_short[AAC_NUM_BLOCKS_SHORT + 1] = { 0 };
const float *firbuf = la + (AAC_BLOCK_SIZE_SHORT/4 - PSY_LAME_FIR_LEN);
- int j, att_sum = 0;
+ int att_sum = 0;
/* LAME comment: apply high pass filter of fs/4 */
- for (i = 0; i < AAC_BLOCK_SIZE_LONG; i++) {
- float sum1, sum2;
- sum1 = firbuf[i + (PSY_LAME_FIR_LEN - 1) / 2];
- sum2 = 0.0;
- for (j = 0; j < ((PSY_LAME_FIR_LEN - 1) / 2) - 1; j += 2) {
- sum1 += psy_fir_coeffs[j] * (firbuf[i + j] + firbuf[i + PSY_LAME_FIR_LEN - j]);
- sum2 += psy_fir_coeffs[j + 1] * (firbuf[i + j + 1] + firbuf[i + PSY_LAME_FIR_LEN - j - 1]);
- }
- /* NOTE: The LAME psymodel expects its input in the range -32768 to
- * 32768. Tuning this for normalized floats would be difficult. */
- hpfsmpl[i] = (sum1 + sum2) * 32768.0f;
- }
+ psy_hp_filter(firbuf, hpfsmpl, psy_fir_coeffs);
/* Calculate the energies of each sub-shortblock */
for (i = 0; i < PSY_LAME_NUM_SUBBLOCKS; i++) {
diff --git a/libavcodec/aacsbr.c b/libavcodec/aacsbr.c
index b389e10817..7e98834c49 100644
--- a/libavcodec/aacsbr.c
+++ b/libavcodec/aacsbr.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008-2009 Robert Swain ( rob opendot cl )
* Copyright (c) 2009-2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,18 +30,25 @@
#include "sbr.h"
#include "aacsbr.h"
#include "aacsbrdata.h"
+#include "aacsbr_tablegen.h"
#include "fft.h"
#include "aacps.h"
#include "sbrdsp.h"
#include "libavutil/internal.h"
#include "libavutil/libm.h"
+#include "libavutil/avassert.h"
#include <stdint.h>
#include <float.h>
+#include <math.h>
#define ENVELOPE_ADJUSTMENT_OFFSET 2
#define NOISE_FLOOR_OFFSET 6.0f
+#if ARCH_MIPS
+#include "mips/aacsbr_mips.h"
+#endif /* ARCH_MIPS */
+
/**
* SBR VLC tables
*/
@@ -85,9 +92,10 @@ static const int8_t vlc_sbr_lav[10] =
#define SBR_VLC_ROW(name) \
{ name ## _codes, name ## _bits, sizeof(name ## _codes), sizeof(name ## _codes[0]) }
+static void aacsbr_func_ptr_init(AACSBRContext *c);
+
av_cold void ff_aac_sbr_init(void)
{
- int n;
static const struct {
const void *sbr_codes, *sbr_bits;
const unsigned int table_size, elem_size;
@@ -116,13 +124,7 @@ av_cold void ff_aac_sbr_init(void)
SBR_INIT_VLC_STATIC(8, 592);
SBR_INIT_VLC_STATIC(9, 512);
- for (n = 1; n < 320; n++)
- sbr_qmf_window_us[320 + n] = sbr_qmf_window_us[320 - n];
- sbr_qmf_window_us[384] = -sbr_qmf_window_us[384];
- sbr_qmf_window_us[512] = -sbr_qmf_window_us[512];
-
- for (n = 0; n < 320; n++)
- sbr_qmf_window_ds[n] = sbr_qmf_window_us[2*n];
+ aacsbr_tableinit();
ff_ps_init();
}
@@ -140,6 +142,8 @@ static void sbr_turnoff(SpectralBandReplication *sbr) {
av_cold void ff_aac_sbr_ctx_init(AACContext *ac, SpectralBandReplication *sbr)
{
+ if(sbr->mdct.mdct_bits)
+ return;
sbr->kx[0] = sbr->kx[1];
sbr_turnoff(sbr);
sbr->data[0].synthesis_filterbank_samples_offset = SBR_SYNTHESIS_BUF_SIZE - (1280 - 128);
@@ -151,6 +155,7 @@ av_cold void ff_aac_sbr_ctx_init(AACContext *ac, SpectralBandReplication *sbr)
ff_mdct_init(&sbr->mdct_ana, 7, 1, -2.0 * 32768.0);
ff_ps_ctx_init(&sbr->ps);
ff_sbrdsp_init(&sbr->dsp);
+ aacsbr_func_ptr_init(&sbr->c);
}
av_cold void ff_aac_sbr_ctx_close(SpectralBandReplication *sbr)
@@ -334,9 +339,6 @@ static int sbr_make_f_master(AACContext *ac, SpectralBandReplication *sbr,
} else
temp = 5000;
- start_min = ((temp << 7) + (sbr->sample_rate >> 1)) / sbr->sample_rate;
- stop_min = ((temp << 8) + (sbr->sample_rate >> 1)) / sbr->sample_rate;
-
switch (sbr->sample_rate) {
case 16000:
sbr_offset_ptr = sbr_offset[0];
@@ -362,6 +364,9 @@ static int sbr_make_f_master(AACContext *ac, SpectralBandReplication *sbr,
return -1;
}
+ start_min = ((temp << 7) + (sbr->sample_rate >> 1)) / sbr->sample_rate;
+ stop_min = ((temp << 8) + (sbr->sample_rate >> 1)) / sbr->sample_rate;
+
sbr->k[0] = start_min + sbr_offset_ptr[spectrum->bs_start_freq];
if (spectrum->bs_stop_freq < 14) {
@@ -388,6 +393,8 @@ static int sbr_make_f_master(AACContext *ac, SpectralBandReplication *sbr,
max_qmf_subbands = 35;
} else if (sbr->sample_rate >= 48000)
max_qmf_subbands = 32;
+ else
+ av_assert0(0);
if (sbr->k[2] - sbr->k[0] > max_qmf_subbands) {
av_log(ac->avctx, AV_LOG_ERROR,
@@ -507,7 +514,7 @@ static int sbr_make_f_master(AACContext *ac, SpectralBandReplication *sbr,
/// High Frequency Generation - Patch Construction (14496-3 sp04 p216 fig. 4.46)
static int sbr_hf_calc_npatches(AACContext *ac, SpectralBandReplication *sbr)
{
- int i, k, sb = 0;
+ int i, k, last_k = -1, last_msb = -1, sb = 0;
int msb = sbr->k[0];
int usb = sbr->kx[1];
int goal_sb = ((1000 << 11) + (sbr->sample_rate >> 1)) / sbr->sample_rate;
@@ -521,6 +528,12 @@ static int sbr_hf_calc_npatches(AACContext *ac, SpectralBandReplication *sbr)
do {
int odd = 0;
+ if (k == last_k && msb == last_msb) {
+ av_log(ac->avctx, AV_LOG_ERROR, "patch construction failed\n");
+ return AVERROR_INVALIDDATA;
+ }
+ last_k = k;
+ last_msb = msb;
for (i = k; i == k || sb > (sbr->k[0] - 1 + msb - odd); i--) {
sb = sbr->f_master[i];
odd = (sb + sbr->k[0]) & 1;
@@ -721,7 +734,8 @@ static int read_sbr_grid(AACContext *ac, SpectralBandReplication *sbr,
break;
}
- if (bs_pointer < 0 || bs_pointer > ch_data->bs_num_env + 1) {
+ av_assert0(bs_pointer >= 0);
+ if (bs_pointer > ch_data->bs_num_env + 1) {
av_log(ac->avctx, AV_LOG_ERROR,
"Invalid bitstream, bs_pointer points to a middle noise border outside the time borders table: %d\n",
bs_pointer);
@@ -1120,7 +1134,12 @@ static void sbr_dequant(SpectralBandReplication *sbr, int id_aac)
for (k = 0; k < sbr->n[sbr->data[0].bs_freq_res[e]]; k++) {
float temp1 = exp2f(sbr->data[0].env_facs[e][k] * alpha + 7.0f);
float temp2 = exp2f((pan_offset - sbr->data[1].env_facs[e][k]) * alpha);
- float fac = temp1 / (1.0f + temp2);
+ float fac;
+ if (temp1 > 1E20) {
+ av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n");
+ temp1 = 1;
+ }
+ fac = temp1 / (1.0f + temp2);
sbr->data[0].env_facs[e][k] = fac;
sbr->data[1].env_facs[e][k] = fac * temp2;
}
@@ -1129,7 +1148,12 @@ static void sbr_dequant(SpectralBandReplication *sbr, int id_aac)
for (k = 0; k < sbr->n_q; k++) {
float temp1 = exp2f(NOISE_FLOOR_OFFSET - sbr->data[0].noise_facs[e][k] + 1);
float temp2 = exp2f(12 - sbr->data[1].noise_facs[e][k]);
- float fac = temp1 / (1.0f + temp2);
+ float fac;
+ if (temp1 > 1E20) {
+ av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n");
+ temp1 = 1;
+ }
+ fac = temp1 / (1.0f + temp2);
sbr->data[0].noise_facs[e][k] = fac;
sbr->data[1].noise_facs[e][k] = fac * temp2;
}
@@ -1138,9 +1162,15 @@ static void sbr_dequant(SpectralBandReplication *sbr, int id_aac)
for (ch = 0; ch < (id_aac == TYPE_CPE) + 1; ch++) {
float alpha = sbr->data[ch].bs_amp_res ? 1.0f : 0.5f;
for (e = 1; e <= sbr->data[ch].bs_num_env; e++)
- for (k = 0; k < sbr->n[sbr->data[ch].bs_freq_res[e]]; k++)
+ for (k = 0; k < sbr->n[sbr->data[ch].bs_freq_res[e]]; k++){
sbr->data[ch].env_facs[e][k] =
exp2f(alpha * sbr->data[ch].env_facs[e][k] + 6.0f);
+ if (sbr->data[ch].env_facs[e][k] > 1E20) {
+ av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n");
+ sbr->data[ch].env_facs[e][k] = 1;
+ }
+ }
+
for (e = 1; e <= sbr->data[ch].bs_num_noise; e++)
for (k = 0; k < sbr->n_q; k++)
sbr->data[ch].noise_facs[e][k] =
@@ -1155,6 +1185,7 @@ static void sbr_dequant(SpectralBandReplication *sbr, int id_aac)
* @param x pointer to the beginning of the first sample window
* @param W array of complex-valued samples split into subbands
*/
+#ifndef sbr_qmf_analysis
static void sbr_qmf_analysis(AVFloatDSPContext *dsp, FFTContext *mdct,
SBRDSPContext *sbrdsp, const float *in, float *x,
float z[320], float W[2][32][32][2], int buf_idx)
@@ -1172,11 +1203,13 @@ static void sbr_qmf_analysis(AVFloatDSPContext *dsp, FFTContext *mdct,
x += 32;
}
}
+#endif
/**
* Synthesis QMF Bank (14496-3 sp04 p206) and Downsampled Synthesis QMF Bank
* (14496-3 sp04 p206)
*/
+#ifndef sbr_qmf_synthesis
static void sbr_qmf_synthesis(FFTContext *mdct,
SBRDSPContext *sbrdsp, AVFloatDSPContext *dsp,
float *out, float X[2][38][64],
@@ -1222,6 +1255,7 @@ static void sbr_qmf_synthesis(FFTContext *mdct,
out += 64 >> div;
}
}
+#endif
/** High Frequency Generation (14496-3 sp04 p214+) and Inverse Filtering
* (14496-3 sp04 p214)
@@ -1575,10 +1609,6 @@ static void sbr_hf_assemble(float Y1[38][64][2],
0.11516383427084,
0.03183050093751,
};
- static const int8_t phi[2][4] = {
- { 1, 0, -1, 0}, // real
- { 0, 1, 0, -1}, // imaginary
- };
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;
@@ -1608,7 +1638,6 @@ static void sbr_hf_assemble(float Y1[38][64][2],
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++) {
- int phi_sign = (1 - 2*(kx & 1));
LOCAL_ALIGNED_16(float, g_filt_tab, [48]);
LOCAL_ALIGNED_16(float, q_filt_tab, [48]);
float *g_filt, *q_filt;
@@ -1638,13 +1667,17 @@ static void sbr_hf_assemble(float Y1[38][64][2],
q_filt, indexnoise,
kx, m_max);
} else {
- for (m = 0; m < m_max; m++) {
- Y1[i][m + kx][0] +=
- sbr->s_m[e][m] * phi[0][indexsine];
- Y1[i][m + kx][1] +=
- sbr->s_m[e][m] * (phi[1][indexsine] * phi_sign);
- phi_sign = -phi_sign;
+ 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];
+ for (m = 0; m+1 < m_max; m+=2) {
+ out[2*m ] += in[m ] * A;
+ out[2*m+2] += in[m+1] * B;
}
+ if(m_max&1)
+ out[2*m ] += in[m ] * A;
}
indexnoise = (indexnoise + m_max) & 0x1ff;
indexsine = (indexsine + 1) & 3;
@@ -1674,16 +1707,16 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
}
for (ch = 0; ch < nch; ch++) {
/* decode channel */
- sbr_qmf_analysis(&ac->fdsp, &sbr->mdct_ana, &sbr->dsp, ch ? R : L, sbr->data[ch].analysis_filterbank_samples,
+ sbr_qmf_analysis(ac->fdsp, &sbr->mdct_ana, &sbr->dsp, ch ? R : L, sbr->data[ch].analysis_filterbank_samples,
(float*)sbr->qmf_filter_scratch,
sbr->data[ch].W, sbr->data[ch].Ypos);
- sbr_lf_gen(ac, sbr, sbr->X_low,
- (const float (*)[32][32][2]) sbr->data[ch].W,
- sbr->data[ch].Ypos);
+ sbr->c.sbr_lf_gen(ac, sbr, sbr->X_low,
+ (const float (*)[32][32][2]) sbr->data[ch].W,
+ sbr->data[ch].Ypos);
sbr->data[ch].Ypos ^= 1;
if (sbr->start) {
- sbr_hf_inverse_filter(&sbr->dsp, sbr->alpha0, sbr->alpha1,
- (const float (*)[40][2]) sbr->X_low, sbr->k[0]);
+ sbr->c.sbr_hf_inverse_filter(&sbr->dsp, sbr->alpha0, sbr->alpha1,
+ (const float (*)[40][2]) sbr->X_low, sbr->k[0]);
sbr_chirp(sbr, &sbr->data[ch]);
sbr_hf_gen(ac, sbr, sbr->X_high,
(const float (*)[40][2]) sbr->X_low,
@@ -1697,7 +1730,7 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
if (!err) {
sbr_env_estimate(sbr->e_curr, sbr->X_high, sbr, &sbr->data[ch]);
sbr_gain_calc(ac, sbr, &sbr->data[ch], sbr->data[ch].e_a);
- sbr_hf_assemble(sbr->data[ch].Y[sbr->data[ch].Ypos],
+ sbr->c.sbr_hf_assemble(sbr->data[ch].Y[sbr->data[ch].Ypos],
(const float (*)[40][2]) sbr->X_high,
sbr, &sbr->data[ch],
sbr->data[ch].e_a);
@@ -1705,7 +1738,7 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
}
/* synthesis */
- sbr_x_gen(sbr, sbr->X[ch],
+ sbr->c.sbr_x_gen(sbr, sbr->X[ch],
(const float (*)[64][2]) sbr->data[ch].Y[1-sbr->data[ch].Ypos],
(const float (*)[64][2]) sbr->data[ch].Y[ sbr->data[ch].Ypos],
(const float (*)[40][2]) sbr->X_low, ch);
@@ -1720,15 +1753,26 @@ void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
nch = 2;
}
- sbr_qmf_synthesis(&sbr->mdct, &sbr->dsp, &ac->fdsp,
+ sbr_qmf_synthesis(&sbr->mdct, &sbr->dsp, ac->fdsp,
L, sbr->X[0], sbr->qmf_filter_scratch,
sbr->data[0].synthesis_filterbank_samples,
&sbr->data[0].synthesis_filterbank_samples_offset,
downsampled);
if (nch == 2)
- sbr_qmf_synthesis(&sbr->mdct, &sbr->dsp, &ac->fdsp,
+ sbr_qmf_synthesis(&sbr->mdct, &sbr->dsp, ac->fdsp,
R, sbr->X[1], sbr->qmf_filter_scratch,
sbr->data[1].synthesis_filterbank_samples,
&sbr->data[1].synthesis_filterbank_samples_offset,
downsampled);
}
+
+static void aacsbr_func_ptr_init(AACSBRContext *c)
+{
+ c->sbr_lf_gen = sbr_lf_gen;
+ c->sbr_hf_assemble = sbr_hf_assemble;
+ c->sbr_x_gen = sbr_x_gen;
+ c->sbr_hf_inverse_filter = sbr_hf_inverse_filter;
+
+ if(ARCH_MIPS)
+ ff_aacsbr_func_ptr_init_mips(c);
+}
diff --git a/libavcodec/aacsbr.h b/libavcodec/aacsbr.h
index 9bc5e29d33..f5e33ab688 100644
--- a/libavcodec/aacsbr.h
+++ b/libavcodec/aacsbr.h
@@ -3,20 +3,20 @@
* Copyright (c) 2008-2009 Robert Swain ( rob opendot cl )
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,4 +46,6 @@ int ff_decode_sbr_extension(AACContext *ac, SpectralBandReplication *sbr,
void ff_sbr_apply(AACContext *ac, SpectralBandReplication *sbr, int id_aac,
float* L, float *R);
+void ff_aacsbr_func_ptr_init_mips(AACSBRContext *c);
+
#endif /* AVCODEC_AACSBR_H */
diff --git a/libavcodec/aacsbr_tablegen.c b/libavcodec/aacsbr_tablegen.c
new file mode 100644
index 0000000000..c3c0f0ce2b
--- /dev/null
+++ b/libavcodec/aacsbr_tablegen.c
@@ -0,0 +1,39 @@
+/*
+ * Header file for hardcoded AAC SBR windows
+ *
+ * Copyright (c) 2014 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdlib.h>
+#define CONFIG_HARDCODED_TABLES 0
+#include "libavutil/common.h"
+#include "aacsbr_tablegen.h"
+#include "tableprint.h"
+
+int main(void)
+{
+ aacsbr_tableinit();
+
+ write_fileheader();
+
+ WRITE_ARRAY_ALIGNED("static const", 32, float, sbr_qmf_window_ds);
+ WRITE_ARRAY_ALIGNED("static const", 32, float, sbr_qmf_window_us);
+
+ return 0;
+}
diff --git a/libavcodec/aacsbr_tablegen.h b/libavcodec/aacsbr_tablegen.h
new file mode 100644
index 0000000000..56fdccce6a
--- /dev/null
+++ b/libavcodec/aacsbr_tablegen.h
@@ -0,0 +1,129 @@
+/*
+ * Header file for hardcoded AAC SBR windows
+ *
+ * Copyright (c) 2014 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_AACSBR_TABLEGEN_H
+#define AVCODEC_AACSBR_TABLEGEN_H
+
+#if CONFIG_HARDCODED_TABLES
+#define aacsbr_tableinit()
+#include "libavcodec/aacsbr_tables.h"
+#else
+///< window coefficients for analysis/synthesis QMF banks
+static DECLARE_ALIGNED(32, float, sbr_qmf_window_ds)[320];
+static DECLARE_ALIGNED(32, float, sbr_qmf_window_us)[640] = {
+ 0.0000000000, -0.0005525286, -0.0005617692, -0.0004947518,
+ -0.0004875227, -0.0004893791, -0.0005040714, -0.0005226564,
+ -0.0005466565, -0.0005677802, -0.0005870930, -0.0006132747,
+ -0.0006312493, -0.0006540333, -0.0006777690, -0.0006941614,
+ -0.0007157736, -0.0007255043, -0.0007440941, -0.0007490598,
+ -0.0007681371, -0.0007724848, -0.0007834332, -0.0007779869,
+ -0.0007803664, -0.0007801449, -0.0007757977, -0.0007630793,
+ -0.0007530001, -0.0007319357, -0.0007215391, -0.0006917937,
+ -0.0006650415, -0.0006341594, -0.0005946118, -0.0005564576,
+ -0.0005145572, -0.0004606325, -0.0004095121, -0.0003501175,
+ -0.0002896981, -0.0002098337, -0.0001446380, -0.0000617334,
+ 0.0000134949, 0.0001094383, 0.0002043017, 0.0002949531,
+ 0.0004026540, 0.0005107388, 0.0006239376, 0.0007458025,
+ 0.0008608443, 0.0009885988, 0.0011250155, 0.0012577884,
+ 0.0013902494, 0.0015443219, 0.0016868083, 0.0018348265,
+ 0.0019841140, 0.0021461583, 0.0023017254, 0.0024625616,
+ 0.0026201758, 0.0027870464, 0.0029469447, 0.0031125420,
+ 0.0032739613, 0.0034418874, 0.0036008268, 0.0037603922,
+ 0.0039207432, 0.0040819753, 0.0042264269, 0.0043730719,
+ 0.0045209852, 0.0046606460, 0.0047932560, 0.0049137603,
+ 0.0050393022, 0.0051407353, 0.0052461166, 0.0053471681,
+ 0.0054196775, 0.0054876040, 0.0055475714, 0.0055938023,
+ 0.0056220643, 0.0056455196, 0.0056389199, 0.0056266114,
+ 0.0055917128, 0.0055404363, 0.0054753783, 0.0053838975,
+ 0.0052715758, 0.0051382275, 0.0049839687, 0.0048109469,
+ 0.0046039530, 0.0043801861, 0.0041251642, 0.0038456408,
+ 0.0035401246, 0.0032091885, 0.0028446757, 0.0024508540,
+ 0.0020274176, 0.0015784682, 0.0010902329, 0.0005832264,
+ 0.0000276045, -0.0005464280, -0.0011568135, -0.0018039472,
+ -0.0024826723, -0.0031933778, -0.0039401124, -0.0047222596,
+ -0.0055337211, -0.0063792293, -0.0072615816, -0.0081798233,
+ -0.0091325329, -0.0101150215, -0.0111315548, -0.0121849995,
+ 0.0132718220, 0.0143904666, 0.0155405553, 0.0167324712,
+ 0.0179433381, 0.0191872431, 0.0204531793, 0.0217467550,
+ 0.0230680169, 0.0244160992, 0.0257875847, 0.0271859429,
+ 0.0286072173, 0.0300502657, 0.0315017608, 0.0329754081,
+ 0.0344620948, 0.0359697560, 0.0374812850, 0.0390053679,
+ 0.0405349170, 0.0420649094, 0.0436097542, 0.0451488405,
+ 0.0466843027, 0.0482165720, 0.0497385755, 0.0512556155,
+ 0.0527630746, 0.0542452768, 0.0557173648, 0.0571616450,
+ 0.0585915683, 0.0599837480, 0.0613455171, 0.0626857808,
+ 0.0639715898, 0.0652247106, 0.0664367512, 0.0676075985,
+ 0.0687043828, 0.0697630244, 0.0707628710, 0.0717002673,
+ 0.0725682583, 0.0733620255, 0.0741003642, 0.0747452558,
+ 0.0753137336, 0.0758008358, 0.0761992479, 0.0764992170,
+ 0.0767093490, 0.0768173975, 0.0768230011, 0.0767204924,
+ 0.0765050718, 0.0761748321, 0.0757305756, 0.0751576255,
+ 0.0744664394, 0.0736406005, 0.0726774642, 0.0715826364,
+ 0.0703533073, 0.0689664013, 0.0674525021, 0.0657690668,
+ 0.0639444805, 0.0619602779, 0.0598166570, 0.0575152691,
+ 0.0550460034, 0.0524093821, 0.0495978676, 0.0466303305,
+ 0.0434768782, 0.0401458278, 0.0366418116, 0.0329583930,
+ 0.0290824006, 0.0250307561, 0.0207997072, 0.0163701258,
+ 0.0117623832, 0.0069636862, 0.0019765601, -0.0032086896,
+ -0.0085711749, -0.0141288827, -0.0198834129, -0.0258227288,
+ -0.0319531274, -0.0382776572, -0.0447806821, -0.0514804176,
+ -0.0583705326, -0.0654409853, -0.0726943300, -0.0801372934,
+ -0.0877547536, -0.0955533352, -0.1035329531, -0.1116826931,
+ -0.1200077984, -0.1285002850, -0.1371551761, -0.1459766491,
+ -0.1549607071, -0.1640958855, -0.1733808172, -0.1828172548,
+ -0.1923966745, -0.2021250176, -0.2119735853, -0.2219652696,
+ -0.2320690870, -0.2423016884, -0.2526480309, -0.2631053299,
+ -0.2736634040, -0.2843214189, -0.2950716717, -0.3059098575,
+ -0.3168278913, -0.3278113727, -0.3388722693, -0.3499914122,
+ 0.3611589903, 0.3723795546, 0.3836350013, 0.3949211761,
+ 0.4062317676, 0.4175696896, 0.4289119920, 0.4402553754,
+ 0.4515996535, 0.4629308085, 0.4742453214, 0.4855253091,
+ 0.4967708254, 0.5079817500, 0.5191234970, 0.5302240895,
+ 0.5412553448, 0.5522051258, 0.5630789140, 0.5738524131,
+ 0.5845403235, 0.5951123086, 0.6055783538, 0.6159109932,
+ 0.6261242695, 0.6361980107, 0.6461269695, 0.6559016302,
+ 0.6655139880, 0.6749663190, 0.6842353293, 0.6933282376,
+ 0.7022388719, 0.7109410426, 0.7194462634, 0.7277448900,
+ 0.7358211758, 0.7436827863, 0.7513137456, 0.7587080760,
+ 0.7658674865, 0.7727780881, 0.7794287519, 0.7858353120,
+ 0.7919735841, 0.7978466413, 0.8034485751, 0.8087695004,
+ 0.8138191270, 0.8185776004, 0.8230419890, 0.8272275347,
+ 0.8311038457, 0.8346937361, 0.8379717337, 0.8409541392,
+ 0.8436238281, 0.8459818469, 0.8480315777, 0.8497805198,
+ 0.8511971524, 0.8523047035, 0.8531020949, 0.8535720573,
+ 0.8537385600,
+};
+
+static av_cold void aacsbr_tableinit(void)
+{
+ int n;
+ for (n = 1; n < 320; n++)
+ sbr_qmf_window_us[320 + n] = sbr_qmf_window_us[320 - n];
+ sbr_qmf_window_us[384] = -sbr_qmf_window_us[384];
+ sbr_qmf_window_us[512] = -sbr_qmf_window_us[512];
+
+ for (n = 0; n < 320; n++)
+ sbr_qmf_window_ds[n] = sbr_qmf_window_us[2*n];
+}
+#endif /* CONFIG_HARDCODED_TABLES */
+
+#endif /* AVCODEC_AACSBR_TABLEGEN_H */
diff --git a/libavcodec/aacsbrdata.h b/libavcodec/aacsbrdata.h
index f3090591ed..c667e0b4ec 100644
--- a/libavcodec/aacsbrdata.h
+++ b/libavcodec/aacsbrdata.h
@@ -2,20 +2,20 @@
* AAC Spectral Band Replication decoding data
* Copyright (c) 2008-2009 Robert Swain ( rob opendot cl )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -266,93 +266,7 @@ static const int8_t sbr_offset[6][16] = {
{-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}, // 64000 Hz < fs_sbr
};
-///< window coefficients for analysis/synthesis QMF banks
-static DECLARE_ALIGNED(32, float, sbr_qmf_window_ds)[320];
-static DECLARE_ALIGNED(32, float, sbr_qmf_window_us)[640] = {
- 0.0000000000, -0.0005525286, -0.0005617692, -0.0004947518,
- -0.0004875227, -0.0004893791, -0.0005040714, -0.0005226564,
- -0.0005466565, -0.0005677802, -0.0005870930, -0.0006132747,
- -0.0006312493, -0.0006540333, -0.0006777690, -0.0006941614,
- -0.0007157736, -0.0007255043, -0.0007440941, -0.0007490598,
- -0.0007681371, -0.0007724848, -0.0007834332, -0.0007779869,
- -0.0007803664, -0.0007801449, -0.0007757977, -0.0007630793,
- -0.0007530001, -0.0007319357, -0.0007215391, -0.0006917937,
- -0.0006650415, -0.0006341594, -0.0005946118, -0.0005564576,
- -0.0005145572, -0.0004606325, -0.0004095121, -0.0003501175,
- -0.0002896981, -0.0002098337, -0.0001446380, -0.0000617334,
- 0.0000134949, 0.0001094383, 0.0002043017, 0.0002949531,
- 0.0004026540, 0.0005107388, 0.0006239376, 0.0007458025,
- 0.0008608443, 0.0009885988, 0.0011250155, 0.0012577884,
- 0.0013902494, 0.0015443219, 0.0016868083, 0.0018348265,
- 0.0019841140, 0.0021461583, 0.0023017254, 0.0024625616,
- 0.0026201758, 0.0027870464, 0.0029469447, 0.0031125420,
- 0.0032739613, 0.0034418874, 0.0036008268, 0.0037603922,
- 0.0039207432, 0.0040819753, 0.0042264269, 0.0043730719,
- 0.0045209852, 0.0046606460, 0.0047932560, 0.0049137603,
- 0.0050393022, 0.0051407353, 0.0052461166, 0.0053471681,
- 0.0054196775, 0.0054876040, 0.0055475714, 0.0055938023,
- 0.0056220643, 0.0056455196, 0.0056389199, 0.0056266114,
- 0.0055917128, 0.0055404363, 0.0054753783, 0.0053838975,
- 0.0052715758, 0.0051382275, 0.0049839687, 0.0048109469,
- 0.0046039530, 0.0043801861, 0.0041251642, 0.0038456408,
- 0.0035401246, 0.0032091885, 0.0028446757, 0.0024508540,
- 0.0020274176, 0.0015784682, 0.0010902329, 0.0005832264,
- 0.0000276045, -0.0005464280, -0.0011568135, -0.0018039472,
- -0.0024826723, -0.0031933778, -0.0039401124, -0.0047222596,
- -0.0055337211, -0.0063792293, -0.0072615816, -0.0081798233,
- -0.0091325329, -0.0101150215, -0.0111315548, -0.0121849995,
- 0.0132718220, 0.0143904666, 0.0155405553, 0.0167324712,
- 0.0179433381, 0.0191872431, 0.0204531793, 0.0217467550,
- 0.0230680169, 0.0244160992, 0.0257875847, 0.0271859429,
- 0.0286072173, 0.0300502657, 0.0315017608, 0.0329754081,
- 0.0344620948, 0.0359697560, 0.0374812850, 0.0390053679,
- 0.0405349170, 0.0420649094, 0.0436097542, 0.0451488405,
- 0.0466843027, 0.0482165720, 0.0497385755, 0.0512556155,
- 0.0527630746, 0.0542452768, 0.0557173648, 0.0571616450,
- 0.0585915683, 0.0599837480, 0.0613455171, 0.0626857808,
- 0.0639715898, 0.0652247106, 0.0664367512, 0.0676075985,
- 0.0687043828, 0.0697630244, 0.0707628710, 0.0717002673,
- 0.0725682583, 0.0733620255, 0.0741003642, 0.0747452558,
- 0.0753137336, 0.0758008358, 0.0761992479, 0.0764992170,
- 0.0767093490, 0.0768173975, 0.0768230011, 0.0767204924,
- 0.0765050718, 0.0761748321, 0.0757305756, 0.0751576255,
- 0.0744664394, 0.0736406005, 0.0726774642, 0.0715826364,
- 0.0703533073, 0.0689664013, 0.0674525021, 0.0657690668,
- 0.0639444805, 0.0619602779, 0.0598166570, 0.0575152691,
- 0.0550460034, 0.0524093821, 0.0495978676, 0.0466303305,
- 0.0434768782, 0.0401458278, 0.0366418116, 0.0329583930,
- 0.0290824006, 0.0250307561, 0.0207997072, 0.0163701258,
- 0.0117623832, 0.0069636862, 0.0019765601, -0.0032086896,
- -0.0085711749, -0.0141288827, -0.0198834129, -0.0258227288,
- -0.0319531274, -0.0382776572, -0.0447806821, -0.0514804176,
- -0.0583705326, -0.0654409853, -0.0726943300, -0.0801372934,
- -0.0877547536, -0.0955533352, -0.1035329531, -0.1116826931,
- -0.1200077984, -0.1285002850, -0.1371551761, -0.1459766491,
- -0.1549607071, -0.1640958855, -0.1733808172, -0.1828172548,
- -0.1923966745, -0.2021250176, -0.2119735853, -0.2219652696,
- -0.2320690870, -0.2423016884, -0.2526480309, -0.2631053299,
- -0.2736634040, -0.2843214189, -0.2950716717, -0.3059098575,
- -0.3168278913, -0.3278113727, -0.3388722693, -0.3499914122,
- 0.3611589903, 0.3723795546, 0.3836350013, 0.3949211761,
- 0.4062317676, 0.4175696896, 0.4289119920, 0.4402553754,
- 0.4515996535, 0.4629308085, 0.4742453214, 0.4855253091,
- 0.4967708254, 0.5079817500, 0.5191234970, 0.5302240895,
- 0.5412553448, 0.5522051258, 0.5630789140, 0.5738524131,
- 0.5845403235, 0.5951123086, 0.6055783538, 0.6159109932,
- 0.6261242695, 0.6361980107, 0.6461269695, 0.6559016302,
- 0.6655139880, 0.6749663190, 0.6842353293, 0.6933282376,
- 0.7022388719, 0.7109410426, 0.7194462634, 0.7277448900,
- 0.7358211758, 0.7436827863, 0.7513137456, 0.7587080760,
- 0.7658674865, 0.7727780881, 0.7794287519, 0.7858353120,
- 0.7919735841, 0.7978466413, 0.8034485751, 0.8087695004,
- 0.8138191270, 0.8185776004, 0.8230419890, 0.8272275347,
- 0.8311038457, 0.8346937361, 0.8379717337, 0.8409541392,
- 0.8436238281, 0.8459818469, 0.8480315777, 0.8497805198,
- 0.8511971524, 0.8523047035, 0.8531020949, 0.8535720573,
- 0.8537385600,
-};
-
-/* First two entries repeated at end to simplify SIMD implementations. */
+/* First eight entries repeated at end to simplify SIMD implementations. */
const DECLARE_ALIGNED(16, float, ff_sbr_noise_table)[][2] = {
{-0.99948153278296, -0.59483417516607}, { 0.97113454393991, -0.67528515225647},
{ 0.14130051758487, -0.95090983575689}, {-0.47005496701697, -0.37340549728647},
@@ -610,7 +524,11 @@ const DECLARE_ALIGNED(16, float, ff_sbr_noise_table)[][2] = {
{-0.93412041758744, 0.41374052024363}, { 0.96063943315511, 0.93116709541280},
{ 0.97534253457837, 0.86150930812689}, { 0.99642466504163, 0.70190043427512},
{-0.94705089665984, -0.29580042814306}, { 0.91599807087376, -0.98147830385781},
+// Start of duplicated table
{-0.99948153278296, -0.59483417516607}, { 0.97113454393991, -0.67528515225647},
+{ 0.14130051758487, -0.95090983575689}, {-0.47005496701697, -0.37340549728647},
+{ 0.80705063769351, 0.29653668284408}, {-0.38981478896926, 0.89572605717087},
+{-0.01053049862020, -0.66959058036166}, {-0.91266367957293, -0.11522938140034},
};
#endif /* AVCODEC_AACSBRDATA_H */
diff --git a/libavcodec/aactab.c b/libavcodec/aactab.c
index 9f1e8afafd..25f6de2927 100644
--- a/libavcodec/aactab.c
+++ b/libavcodec/aactab.c
@@ -3,20 +3,20 @@
* 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aactab.h b/libavcodec/aactab.h
index fc26db8a4d..9f5a7e47bd 100644
--- a/libavcodec/aactab.h
+++ b/libavcodec/aactab.h
@@ -3,20 +3,20 @@
* 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aandcttab.c b/libavcodec/aandcttab.c
index 0c5b573412..97013d2b52 100644
--- a/libavcodec/aandcttab.c
+++ b/libavcodec/aandcttab.c
@@ -1,24 +1,24 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * AAN (Arai Agui Aakajima) (I)DCT tables
+ * AAN (Arai, Agui and Nakajima) (I)DCT tables
*/
#include <stdint.h>
diff --git a/libavcodec/aandcttab.h b/libavcodec/aandcttab.h
index daccb7bb0b..b0a2f44ecd 100644
--- a/libavcodec/aandcttab.h
+++ b/libavcodec/aandcttab.h
@@ -1,24 +1,24 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * AAN (Arai Agui Nakajima) (I)DCT tables
+ * AAN (Arai, Agui and Nakajima) (I)DCT tables
*/
#ifndef AVCODEC_AANDCTTAB_H
diff --git a/libavcodec/aarch64/asm-offsets.h b/libavcodec/aarch64/asm-offsets.h
index 45b5c40f80..8defd7c9ec 100644
--- a/libavcodec/aarch64/asm-offsets.h
+++ b/libavcodec/aarch64/asm-offsets.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/cabac.h b/libavcodec/aarch64/cabac.h
index e12953e86c..6b9b77eb30 100644
--- a/libavcodec/aarch64/cabac.h
+++ b/libavcodec/aarch64/cabac.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/fft_init_aarch64.c b/libavcodec/aarch64/fft_init_aarch64.c
index 589e82d331..8514d3b07b 100644
--- a/libavcodec/aarch64/fft_init_aarch64.c
+++ b/libavcodec/aarch64/fft_init_aarch64.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/fft_neon.S b/libavcodec/aarch64/fft_neon.S
index e205e23d88..862039f97d 100644
--- a/libavcodec/aarch64/fft_neon.S
+++ b/libavcodec/aarch64/fft_neon.S
@@ -8,20 +8,20 @@
* This algorithm (though not any of the implementation details) is
* based on libdjbfft by D. J. Bernstein.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/h264chroma_init_aarch64.c b/libavcodec/aarch64/h264chroma_init_aarch64.c
index c7679ab4cc..2af62becf7 100644
--- a/libavcodec/aarch64/h264chroma_init_aarch64.c
+++ b/libavcodec/aarch64/h264chroma_init_aarch64.c
@@ -2,20 +2,20 @@
* ARM NEON optimised H.264 chroma functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/h264cmc_neon.S b/libavcodec/aarch64/h264cmc_neon.S
index d1025c7a25..486079f87c 100644
--- a/libavcodec/aarch64/h264cmc_neon.S
+++ b/libavcodec/aarch64/h264cmc_neon.S
@@ -2,20 +2,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2013 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/h264dsp_init_aarch64.c b/libavcodec/aarch64/h264dsp_init_aarch64.c
index b106f11134..e0f378f5ab 100644
--- a/libavcodec/aarch64/h264dsp_init_aarch64.c
+++ b/libavcodec/aarch64/h264dsp_init_aarch64.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -78,6 +78,7 @@ av_cold void ff_h264dsp_init_aarch64(H264DSPContext *c, const int bit_depth,
c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon;
c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon;
c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon;
+ if (chroma_format_idc <= 1)
c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon;
c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon;
diff --git a/libavcodec/aarch64/h264dsp_neon.S b/libavcodec/aarch64/h264dsp_neon.S
index 9b4610a4d4..4ec35f2905 100644
--- a/libavcodec/aarch64/h264dsp_neon.S
+++ b/libavcodec/aarch64/h264dsp_neon.S
@@ -2,20 +2,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2013 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/h264idct_neon.S b/libavcodec/aarch64/h264idct_neon.S
index 99c2cb5030..04b5a47f04 100644
--- a/libavcodec/aarch64/h264idct_neon.S
+++ b/libavcodec/aarch64/h264idct_neon.S
@@ -2,20 +2,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2013 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/h264qpel_init_aarch64.c b/libavcodec/aarch64/h264qpel_init_aarch64.c
index 4beb11b7b5..77f41d9a21 100644
--- a/libavcodec/aarch64/h264qpel_init_aarch64.c
+++ b/libavcodec/aarch64/h264qpel_init_aarch64.c
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,73 +27,73 @@
#include "libavutil/aarch64/cpu.h"
#include "libavcodec/h264qpel.h"
-void ff_put_h264_qpel16_mc00_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc10_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc20_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc30_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc01_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc11_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc21_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc31_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc02_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc12_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc22_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc32_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc03_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc13_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc23_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel16_mc33_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel16_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc00_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc10_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc20_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc30_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc01_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc11_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc21_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc31_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc02_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc12_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc22_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc32_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc03_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc13_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc23_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_put_h264_qpel8_mc33_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_put_h264_qpel8_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc00_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc10_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc20_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc30_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc01_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc11_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc21_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc31_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc02_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc12_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc22_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc32_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc03_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc13_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc23_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel16_mc33_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel16_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc00_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc10_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc20_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc30_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc01_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc11_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc21_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc31_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc02_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc12_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc22_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc32_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc03_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc13_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc23_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
-void ff_avg_h264_qpel8_mc33_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
+void ff_avg_h264_qpel8_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride);
av_cold void ff_h264qpel_init_aarch64(H264QpelContext *c, int bit_depth)
{
diff --git a/libavcodec/aarch64/h264qpel_neon.S b/libavcodec/aarch64/h264qpel_neon.S
index 731dc0658d..d27cfac494 100644
--- a/libavcodec/aarch64/h264qpel_neon.S
+++ b/libavcodec/aarch64/h264qpel_neon.S
@@ -2,20 +2,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2013 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/hpeldsp_init_aarch64.c b/libavcodec/aarch64/hpeldsp_init_aarch64.c
index 6bc4c09f6c..144ae2bcc4 100644
--- a/libavcodec/aarch64/hpeldsp_init_aarch64.c
+++ b/libavcodec/aarch64/hpeldsp_init_aarch64.c
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/hpeldsp_neon.S b/libavcodec/aarch64/hpeldsp_neon.S
index 29782908f8..a491c173bb 100644
--- a/libavcodec/aarch64/hpeldsp_neon.S
+++ b/libavcodec/aarch64/hpeldsp_neon.S
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2013 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/imdct15_init.c b/libavcodec/aarch64/imdct15_init.c
index 38018f2b4a..58af9f00c0 100644
--- a/libavcodec/aarch64/imdct15_init.c
+++ b/libavcodec/aarch64/imdct15_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/imdct15_neon.S b/libavcodec/aarch64/imdct15_neon.S
index d99edf4108..97e1442ccc 100644
--- a/libavcodec/aarch64/imdct15_neon.S
+++ b/libavcodec/aarch64/imdct15_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/mdct_neon.S b/libavcodec/aarch64/mdct_neon.S
index bccd8323fd..1fd199c972 100644
--- a/libavcodec/aarch64/mdct_neon.S
+++ b/libavcodec/aarch64/mdct_neon.S
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/mpegaudiodsp_init.c b/libavcodec/aarch64/mpegaudiodsp_init.c
index a8b2baf955..b94514645f 100644
--- a/libavcodec/aarch64/mpegaudiodsp_init.c
+++ b/libavcodec/aarch64/mpegaudiodsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/mpegaudiodsp_neon.S b/libavcodec/aarch64/mpegaudiodsp_neon.S
index 808576af72..733fc8406b 100644
--- a/libavcodec/aarch64/mpegaudiodsp_neon.S
+++ b/libavcodec/aarch64/mpegaudiodsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/neon.S b/libavcodec/aarch64/neon.S
index f1072b73e5..619aec6426 100644
--- a/libavcodec/aarch64/neon.S
+++ b/libavcodec/aarch64/neon.S
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/neontest.c b/libavcodec/aarch64/neontest.c
index 041482913f..6e41f3736e 100644
--- a/libavcodec/aarch64/neontest.c
+++ b/libavcodec/aarch64/neontest.c
@@ -2,20 +2,20 @@
* check NEON registers for clobbers
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/rv40dsp_init_aarch64.c b/libavcodec/aarch64/rv40dsp_init_aarch64.c
index 0bb404f6d2..764bc1ef39 100644
--- a/libavcodec/aarch64/rv40dsp_init_aarch64.c
+++ b/libavcodec/aarch64/rv40dsp_init_aarch64.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/vc1dsp_init_aarch64.c b/libavcodec/aarch64/vc1dsp_init_aarch64.c
index 11cd81eb5c..e59e55ec88 100644
--- a/libavcodec/aarch64/vc1dsp_init_aarch64.c
+++ b/libavcodec/aarch64/vc1dsp_init_aarch64.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/videodsp.S b/libavcodec/aarch64/videodsp.S
index 7ce5a7ddf6..24067cc2af 100644
--- a/libavcodec/aarch64/videodsp.S
+++ b/libavcodec/aarch64/videodsp.S
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/videodsp_init.c b/libavcodec/aarch64/videodsp_init.c
index 59b697d4f4..6f667a6d3e 100644
--- a/libavcodec/aarch64/videodsp_init.c
+++ b/libavcodec/aarch64/videodsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/vorbisdsp_init.c b/libavcodec/aarch64/vorbisdsp_init.c
index 3559b54a30..c796f95e61 100644
--- a/libavcodec/aarch64/vorbisdsp_init.c
+++ b/libavcodec/aarch64/vorbisdsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aarch64/vorbisdsp_neon.S b/libavcodec/aarch64/vorbisdsp_neon.S
index 11f71f1d89..e76feebc54 100644
--- a/libavcodec/aarch64/vorbisdsp_neon.S
+++ b/libavcodec/aarch64/vorbisdsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aasc.c b/libavcodec/aasc.c
index 1e457ce962..469fc5eef6 100644
--- a/libavcodec/aasc.c
+++ b/libavcodec/aasc.c
@@ -1,21 +1,21 @@
/*
* Autodesk RLE Decoder
- * Copyright (C) 2005 the ffmpeg project
+ * Copyright (c) 2005 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,15 +36,39 @@ typedef struct AascContext {
AVCodecContext *avctx;
GetByteContext gb;
AVFrame *frame;
+
+ uint32_t palette[AVPALETTE_COUNT];
+ int palette_size;
} AascContext;
static av_cold int aasc_decode_init(AVCodecContext *avctx)
{
AascContext *s = avctx->priv_data;
+ uint8_t *ptr;
+ int i;
s->avctx = avctx;
-
- avctx->pix_fmt = AV_PIX_FMT_BGR24;
+ switch (avctx->bits_per_coded_sample) {
+ case 8:
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+
+ ptr = avctx->extradata;
+ s->palette_size = FFMIN(avctx->extradata_size, AVPALETTE_SIZE);
+ for (i = 0; i < s->palette_size / 4; i++) {
+ s->palette[i] = 0xFFU << 24 | AV_RL32(ptr);
+ ptr += 4;
+ }
+ break;
+ case 16:
+ avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
+ break;
+ case 24:
+ avctx->pix_fmt = AV_PIX_FMT_BGR24;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %d\n", avctx->bits_per_coded_sample);
+ return -1;
+ }
s->frame = av_frame_alloc();
if (!s->frame)
@@ -60,27 +84,35 @@ static int aasc_decode_frame(AVCodecContext *avctx,
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
AascContext *s = avctx->priv_data;
- int compr, i, stride, ret;
+ int compr, i, stride, psize, ret;
- if (buf_size < 4)
+ if (buf_size < 4) {
+ av_log(avctx, AV_LOG_ERROR, "frame too short\n");
return AVERROR_INVALIDDATA;
+ }
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
compr = AV_RL32(buf);
buf += 4;
buf_size -= 4;
+ psize = avctx->bits_per_coded_sample / 8;
+ switch (avctx->codec_tag) {
+ case MKTAG('A', 'A', 'S', '4'):
+ bytestream2_init(&s->gb, buf - 4, buf_size + 4);
+ ff_msrle_decode(avctx, (AVPicture*)s->frame, 8, &s->gb);
+ break;
+ case MKTAG('A', 'A', 'S', 'C'):
switch (compr) {
case 0:
- stride = (avctx->width * 3 + 3) & ~3;
+ stride = (avctx->width * psize + psize) & ~psize;
if (buf_size < stride * avctx->height)
return AVERROR_INVALIDDATA;
for (i = avctx->height - 1; i >= 0; i--) {
- memcpy(s->frame->data[0] + i * s->frame->linesize[0], buf, avctx->width * 3);
+ memcpy(s->frame->data[0] + i * s->frame->linesize[0], buf, avctx->width * psize);
buf += stride;
+ buf_size -= stride;
}
break;
case 1:
@@ -91,6 +123,14 @@ static int aasc_decode_frame(AVCodecContext *avctx,
av_log(avctx, AV_LOG_ERROR, "Unknown compression type %d\n", compr);
return AVERROR_INVALIDDATA;
}
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unknown FourCC: %X\n", avctx->codec_tag);
+ return -1;
+ }
+
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
+ memcpy(s->frame->data[1], s->palette, s->palette_size);
*got_frame = 1;
if ((ret = av_frame_ref(data, s->frame)) < 0)
diff --git a/libavcodec/ac3.c b/libavcodec/ac3.c
index 99e5b50acb..b54315dcb3 100644
--- a/libavcodec/ac3.c
+++ b/libavcodec/ac3.c
@@ -2,20 +2,20 @@
* Common code between the AC-3 encoder and decoder
* Copyright (c) 2000 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -131,6 +131,9 @@ int ff_ac3_bit_alloc_calc_mask(AC3BitAllocParameters *s, int16_t *band_psd,
int band_start, band_end, begin, end1;
int lowcomp, fastleak, slowleak;
+ if (end <= 0)
+ return AVERROR_INVALIDDATA;
+
/* excitation function */
band_start = ff_ac3_bin_to_band_tab[start];
band_end = ff_ac3_bin_to_band_tab[end-1] + 1;
@@ -200,9 +203,9 @@ int ff_ac3_bit_alloc_calc_mask(AC3BitAllocParameters *s, int16_t *band_psd,
if (band >= AC3_CRITICAL_BANDS || dba_lengths[seg] > AC3_CRITICAL_BANDS-band)
return -1;
if (dba_values[seg] >= 4) {
- delta = (dba_values[seg] - 3) << 7;
+ delta = (dba_values[seg] - 3) * 128;
} else {
- delta = (dba_values[seg] - 4) << 7;
+ delta = (dba_values[seg] - 4) * 128;
}
for (i = 0; i < dba_lengths[seg]; i++) {
mask[band++] += delta;
diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h
index f2cb6c39df..1fe30b9587 100644
--- a/libavcodec/ac3.h
+++ b/libavcodec/ac3.h
@@ -2,20 +2,20 @@
* Common code between the AC-3 encoder and decoder
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,6 +39,8 @@
#define AC3_CRITICAL_BANDS 50
#define AC3_MAX_CPL_BANDS 18
+#include "libavutil/opt.h"
+#include "avcodec.h"
#include "ac3tab.h"
/* exponent encoding strategy */
@@ -49,6 +51,54 @@
#define EXP_D25 2
#define EXP_D45 3
+#ifndef USE_FIXED
+#define USE_FIXED 0
+#endif
+
+#if USE_FIXED
+
+#define FFT_FLOAT 0
+
+#define FIXR(a) ((int)((a) * 0 + 0.5))
+#define FIXR12(a) ((int)((a) * 4096 + 0.5))
+#define FIXR15(a) ((int)((a) * 32768 + 0.5))
+#define ROUND15(x) ((x) + 16384) >> 15
+
+#define AC3_RENAME(x) x ## _fixed
+#define AC3_NORM(norm) (1<<24)/(norm)
+#define AC3_MUL(a,b) ((((int64_t) (a)) * (b))>>12)
+#define AC3_RANGE(x) ((x)|(((x)&128)<<1))
+#define AC3_HEAVY_RANGE(x) ((x)<<1)
+#define AC3_DYNAMIC_RANGE(x) (x)
+#define AC3_SPX_BLEND(x) (x)
+#define AC3_DYNAMIC_RANGE1 0
+
+#define INTFLOAT int
+#define SHORTFLOAT int16_t
+
+#else /* USE_FIXED */
+
+#define FIXR(x) ((float)(x))
+#define FIXR12(x) ((float)(x))
+#define FIXR15(x) ((float)(x))
+#define ROUND15(x) (x)
+
+#define AC3_RENAME(x) x
+#define AC3_NORM(norm) (1.0f/(norm))
+#define AC3_MUL(a,b) ((a) * (b))
+#define AC3_RANGE(x) (dynamic_range_tab[(x)])
+#define AC3_HEAVY_RANGE(x) (heavy_dynamic_range_tab[(x)])
+#define AC3_DYNAMIC_RANGE(x) (powf(x, s->drc_scale))
+#define AC3_SPX_BLEND(x) (x)* (1.0f/32)
+#define AC3_DYNAMIC_RANGE1 1.0f
+
+#define INTFLOAT float
+#define SHORTFLOAT float
+
+#endif /* USE_FIXED */
+
+#define AC3_LEVEL(x) ROUND15((x) * FIXR15(0.7071067811865476))
+
/* pre-defined gain values */
#define LEVEL_PLUS_3DB 1.4142135623730950
#define LEVEL_PLUS_1POINT5DB 1.1892071150027209
@@ -140,7 +190,9 @@ typedef struct AC3HeaderInfo {
int surround_mix_level; ///< Surround mix level index
uint16_t channel_map;
int num_blocks; ///< number of audio blocks
+#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
int dolby_surround_mode;
+#endif
/** @} */
/** @name Derived values
@@ -153,6 +205,9 @@ typedef struct AC3HeaderInfo {
uint16_t frame_size;
uint64_t channel_layout;
/** @} */
+#if !AV_HAVE_INCOMPATIBLE_LIBAV_ABI
+ int dolby_surround_mode;
+#endif
} AC3HeaderInfo;
typedef enum {
diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c
index 5ea09f8fcd..131e180360 100644
--- a/libavcodec/ac3_parser.c
+++ b/libavcodec/ac3_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,9 +47,16 @@ static const uint8_t center_levels[4] = { 4, 5, 6, 5 };
static const uint8_t surround_levels[4] = { 4, 6, 7, 6 };
-int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
+int avpriv_ac3_parse_header2(GetBitContext *gbc, AC3HeaderInfo **phdr)
{
int frame_size_code;
+ AC3HeaderInfo *hdr;
+
+ if (!*phdr)
+ *phdr = av_mallocz(sizeof(AC3HeaderInfo));
+ if (!*phdr)
+ return AVERROR(ENOMEM);
+ hdr = *phdr;
memset(hdr, 0, sizeof(*hdr));
@@ -144,19 +151,28 @@ int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
return 0;
}
+int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr)
+{
+ AC3HeaderInfo tmp, *ptmp = &tmp;
+ int ret = avpriv_ac3_parse_header2(gbc, &ptmp);
+
+ memcpy(hdr, ptmp, ((intptr_t)&tmp.channel_layout) - ((intptr_t)&tmp) + sizeof(uint64_t));
+ return ret;
+}
+
static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info,
int *need_next_header, int *new_frame_start)
{
int err;
union {
uint64_t u64;
- uint8_t u8[8];
+ uint8_t u8[8 + FF_INPUT_BUFFER_PADDING_SIZE];
} tmp = { av_be2ne64(state) };
- AC3HeaderInfo hdr;
+ AC3HeaderInfo hdr, *phdr = &hdr;
GetBitContext gbc;
init_get_bits(&gbc, tmp.u8+8-AC3_HEADER_SIZE, 54);
- err = avpriv_ac3_parse_header(&gbc, &hdr);
+ err = avpriv_ac3_parse_header2(&gbc, &phdr);
if(err < 0)
return 0;
diff --git a/libavcodec/ac3_parser.h b/libavcodec/ac3_parser.h
index 9322550ea5..f37387d76c 100644
--- a/libavcodec/ac3_parser.h
+++ b/libavcodec/ac3_parser.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,11 +31,14 @@
* 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.
+ * @param[out] hdr Pointer to Pointer to struct where header info is written.
+ * will be allocated if NULL
* @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.
*/
+int avpriv_ac3_parse_header2(GetBitContext *gbc, AC3HeaderInfo **hdr);
+
int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr);
#endif /* AVCODEC_AC3_PARSER_H */
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index a0359faa2d..234b469bc0 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -7,20 +7,20 @@
* Copyright (c) 2007-2008 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
* Copyright (c) 2007 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,6 +65,7 @@ static const uint8_t quantization_tab[16] = {
/** dynamic range table. converts codes to scale factors. */
static float dynamic_range_tab[256];
+static float heavy_dynamic_range_tab[256];
/** Adjustments in dB gain */
static const float gain_levels[9] = {
@@ -111,7 +112,7 @@ static const uint8_t ac3_default_coeffs[8][5][2] = {
static inline int
symmetric_dequant(int code, int levels)
{
- return ((code - (levels >> 1)) << 24) / levels;
+ return ((code - (levels >> 1)) * (1 << 24)) / levels;
}
/*
@@ -164,6 +165,14 @@ static av_cold void ac3_tables_init(void)
int v = (i >> 5) - ((i >> 7) << 3) - 5;
dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0x1F) | 0x20);
}
+
+ /* generate compr dynamic range table
+ reference: Section 7.7.2 Heavy Compression */
+ for (i = 0; i < 256; i++) {
+ int v = (i >> 4) - ((i >> 7) << 4) - 4;
+ heavy_dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0xF) | 0x10);
+ }
+
}
/**
@@ -180,14 +189,23 @@ static av_cold int ac3_decode_init(AVCodecContext *avctx)
ac3_tables_init();
ff_mdct_init(&s->imdct_256, 8, 1, 1.0);
ff_mdct_init(&s->imdct_512, 9, 1, 1.0);
- ff_kbd_window_init(s->window, 5.0, 256);
+ AC3_RENAME(ff_kbd_window_init)(s->window, 5.0, 256);
ff_bswapdsp_init(&s->bdsp);
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
- ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT);
+
+#if (USE_FIXED)
+ s->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & CODEC_FLAG_BITEXACT);
+#else
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
ff_fmt_convert_init(&s->fmt_conv, avctx);
+#endif
+
+ ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT);
av_lfg_init(&s->dith_state, 0);
- avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+ if (USE_FIXED)
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
+ else
+ avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
/* allow downmixing to stereo or mono */
#if FF_API_REQUEST_CHANNELS
@@ -227,9 +245,19 @@ static int ac3_parse_header(AC3DecodeContext *s)
/* read the rest of the bsi. read twice for dual mono mode. */
i = !s->channel_mode;
do {
- skip_bits(gbc, 5); // skip dialog normalization
- if (get_bits1(gbc))
- skip_bits(gbc, 8); //skip compression
+ s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5);
+ if (s->dialog_normalization[(!s->channel_mode)-i] == 0) {
+ s->dialog_normalization[(!s->channel_mode)-i] = -31;
+ }
+ if (s->target_level != 0) {
+ s->level_gain[(!s->channel_mode)-i] = powf(2.0f,
+ (float)(s->target_level -
+ s->dialog_normalization[(!s->channel_mode)-i])/6.0f);
+ }
+ if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) {
+ s->heavy_dynamic_range[(!s->channel_mode)-i] =
+ AC3_HEAVY_RANGE(get_bits(gbc, 8));
+ }
if (get_bits1(gbc))
skip_bits(gbc, 8); //skip language code
if (get_bits1(gbc))
@@ -275,10 +303,10 @@ static int ac3_parse_header(AC3DecodeContext *s)
*/
static int parse_frame_header(AC3DecodeContext *s)
{
- AC3HeaderInfo hdr;
+ AC3HeaderInfo hdr, *phdr=&hdr;
int err;
- err = avpriv_ac3_parse_header(&s->gbc, &hdr);
+ err = avpriv_ac3_parse_header2(&s->gbc, &phdr);
if (err)
return err;
@@ -346,40 +374,45 @@ static void set_downmix_coeffs(AC3DecodeContext *s)
float cmix = gain_levels[s-> center_mix_level];
float smix = gain_levels[s->surround_mix_level];
float norm0, norm1;
+ float downmix_coeffs[AC3_MAX_CHANNELS][2];
for (i = 0; i < s->fbw_channels; i++) {
- s->downmix_coeffs[i][0] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]];
- s->downmix_coeffs[i][1] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]];
+ downmix_coeffs[i][0] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]];
+ downmix_coeffs[i][1] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]];
}
if (s->channel_mode > 1 && s->channel_mode & 1) {
- s->downmix_coeffs[1][0] = s->downmix_coeffs[1][1] = cmix;
+ downmix_coeffs[1][0] = downmix_coeffs[1][1] = cmix;
}
if (s->channel_mode == AC3_CHMODE_2F1R || s->channel_mode == AC3_CHMODE_3F1R) {
int nf = s->channel_mode - 2;
- s->downmix_coeffs[nf][0] = s->downmix_coeffs[nf][1] = smix * LEVEL_MINUS_3DB;
+ downmix_coeffs[nf][0] = downmix_coeffs[nf][1] = smix * LEVEL_MINUS_3DB;
}
if (s->channel_mode == AC3_CHMODE_2F2R || s->channel_mode == AC3_CHMODE_3F2R) {
int nf = s->channel_mode - 4;
- s->downmix_coeffs[nf][0] = s->downmix_coeffs[nf+1][1] = smix;
+ downmix_coeffs[nf][0] = downmix_coeffs[nf+1][1] = smix;
}
/* renormalize */
norm0 = norm1 = 0.0;
for (i = 0; i < s->fbw_channels; i++) {
- norm0 += s->downmix_coeffs[i][0];
- norm1 += s->downmix_coeffs[i][1];
+ norm0 += downmix_coeffs[i][0];
+ norm1 += downmix_coeffs[i][1];
}
norm0 = 1.0f / norm0;
norm1 = 1.0f / norm1;
for (i = 0; i < s->fbw_channels; i++) {
- s->downmix_coeffs[i][0] *= norm0;
- s->downmix_coeffs[i][1] *= norm1;
+ downmix_coeffs[i][0] *= norm0;
+ downmix_coeffs[i][1] *= norm1;
}
if (s->output_mode == AC3_CHMODE_MONO) {
for (i = 0; i < s->fbw_channels; i++)
- s->downmix_coeffs[i][0] = (s->downmix_coeffs[i][0] +
- s->downmix_coeffs[i][1]) * LEVEL_MINUS_3DB;
+ downmix_coeffs[i][0] = (downmix_coeffs[i][0] +
+ downmix_coeffs[i][1]) * LEVEL_MINUS_3DB;
+ }
+ for (i = 0; i < s->fbw_channels; i++) {
+ s->downmix_coeffs[i][0] = FIXR12(downmix_coeffs[i][0]);
+ s->downmix_coeffs[i][1] = FIXR12(downmix_coeffs[i][1]);
}
}
@@ -437,7 +470,7 @@ static void calc_transform_coeffs_cpl(AC3DecodeContext *s)
int cpl_coord = s->cpl_coords[ch][band] << 5;
for (bin = band_start; bin < band_end; bin++) {
s->fixed_coeffs[ch][bin] =
- MULH(s->fixed_coeffs[CPL_CH][bin] << 4, cpl_coord);
+ MULH(s->fixed_coeffs[CPL_CH][bin] * (1 << 4), cpl_coord);
}
if (ch == 2 && s->phase_flags[band]) {
for (bin = band_start; bin < band_end; bin++)
@@ -483,7 +516,7 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma
case 0:
/* random noise with approximate range of -0.707 to 0.707 */
if (dither)
- mantissa = (av_lfg_get(&s->dith_state) / 362) - 5932275;
+ mantissa = (((av_lfg_get(&s->dith_state)>>8)*181)>>8) - 5931008;
else
mantissa = 0;
break;
@@ -530,8 +563,11 @@ static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, ma
break;
default: /* 6 to 15 */
/* Shift mantissa and sign-extend it. */
- mantissa = get_sbits(gbc, quantization_tab[bap]);
- mantissa <<= 24 - quantization_tab[bap];
+ if (bap > 15) {
+ av_log(s->avctx, AV_LOG_ERROR, "bap %d is invalid in plain AC-3\n", bap);
+ bap = 15;
+ }
+ mantissa = (unsigned)get_sbits(gbc, quantization_tab[bap]) << (24 - quantization_tab[bap]);
break;
}
coeffs[freq] = mantissa >> exps[freq];
@@ -565,7 +601,7 @@ static void decode_transform_coeffs_ch(AC3DecodeContext *s, int blk, int ch,
/* if AHT is used, mantissas for all blocks are encoded in the first
block of the frame. */
int bin;
- if (!blk && CONFIG_EAC3_DECODER)
+ if (CONFIG_EAC3_DECODER && !blk)
ff_eac3_decode_transform_coeffs_aht_ch(s, ch);
for (bin = s->start_freq[ch]; bin < s->end_freq[ch]; bin++) {
s->fixed_coeffs[ch][bin] = s->pre_mantissa[ch][bin][blk] >> s->dexps[ch][bin];
@@ -643,20 +679,30 @@ static inline void do_imdct(AC3DecodeContext *s, int channels)
for (ch = 1; ch <= channels; ch++) {
if (s->block_switch[ch]) {
int i;
- float *x = s->tmp_output + 128;
+ FFTSample *x = s->tmp_output + 128;
for (i = 0; i < 128; i++)
x[i] = s->transform_coeffs[ch][2 * i];
s->imdct_256.imdct_half(&s->imdct_256, s->tmp_output, x);
- s->fdsp.vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1],
+#if USE_FIXED
+ s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1],
+ s->tmp_output, s->window, 128, 8);
+#else
+ s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1],
s->tmp_output, s->window, 128);
+#endif
for (i = 0; i < 128; i++)
x[i] = s->transform_coeffs[ch][2 * i + 1];
s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1], x);
} else {
s->imdct_512.imdct_half(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]);
- s->fdsp.vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1],
+#if USE_FIXED
+ s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1],
+ s->tmp_output, s->window, 128, 8);
+#else
+ s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1],
s->tmp_output, s->window, 128);
- memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(float));
+#endif
+ memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(FFTSample));
}
}
}
@@ -791,13 +837,14 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
if (get_bits1(gbc)) {
/* Allow asymmetric application of DRC when drc_scale > 1.
Amplification of quiet sounds is enhanced */
- float range = dynamic_range_tab[get_bits(gbc, 8)];
- if (range > 1.0 || s->drc_scale <= 1.0)
- s->dynamic_range[i] = powf(range, s->drc_scale);
+ int range_bits = get_bits(gbc, 8);
+ INTFLOAT range = AC3_RANGE(range_bits);
+ if (range_bits <= 127 || s->drc_scale <= 1.0)
+ s->dynamic_range[i] = AC3_DYNAMIC_RANGE(range);
else
s->dynamic_range[i] = range;
} else if (blk == 0) {
- s->dynamic_range[i] = 1.0f;
+ s->dynamic_range[i] = AC3_DYNAMIC_RANGE1;
}
} while (i--);
@@ -823,6 +870,9 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
if (start_subband > 7)
start_subband += start_subband - 7;
end_subband = get_bits(gbc, 3) + 5;
+#if USE_FIXED
+ s->spx_dst_end_freq = end_freq_inv_tab[end_subband-5];
+#endif
if (end_subband > 7)
end_subband += end_subband - 7;
dst_start_freq = dst_start_freq * 12 + 25;
@@ -843,7 +893,8 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
s->spx_dst_start_freq = dst_start_freq;
s->spx_src_start_freq = src_start_freq;
- s->spx_dst_end_freq = dst_end_freq;
+ if (!USE_FIXED)
+ s->spx_dst_end_freq = dst_end_freq;
decode_band_structure(gbc, blk, s->eac3, 0,
start_subband, end_subband,
@@ -863,26 +914,47 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
for (ch = 1; ch <= fbw_channels; ch++) {
if (s->channel_uses_spx[ch]) {
if (s->first_spx_coords[ch] || get_bits1(gbc)) {
- float spx_blend;
+ INTFLOAT spx_blend;
int bin, master_spx_coord;
s->first_spx_coords[ch] = 0;
- spx_blend = get_bits(gbc, 5) * (1.0f/32);
+ spx_blend = AC3_SPX_BLEND(get_bits(gbc, 5));
master_spx_coord = get_bits(gbc, 2) * 3;
bin = s->spx_src_start_freq;
for (bnd = 0; bnd < s->num_spx_bands; bnd++) {
- int bandsize;
+ int bandsize = s->spx_band_sizes[bnd];
int spx_coord_exp, spx_coord_mant;
- float nratio, sblend, nblend, spx_coord;
+ INTFLOAT nratio, sblend, nblend;
+#if USE_FIXED
+ /* calculate blending factors */
+ int64_t accu = ((bin << 23) + (bandsize << 22))
+ * (int64_t)s->spx_dst_end_freq;
+ nratio = (int)(accu >> 32);
+ nratio -= spx_blend << 18;
+
+ if (nratio < 0) {
+ nblend = 0;
+ sblend = 0x800000;
+ } else if (nratio > 0x7fffff) {
+ nblend = 14529495; // sqrt(3) in FP.23
+ sblend = 0;
+ } else {
+ nblend = fixed_sqrt(nratio, 23);
+ accu = (int64_t)nblend * 1859775393;
+ nblend = (int)((accu + (1<<29)) >> 30);
+ sblend = fixed_sqrt(0x800000 - nratio, 23);
+ }
+#else
+ float spx_coord;
/* calculate blending factors */
- bandsize = s->spx_band_sizes[bnd];
nratio = ((float)((bin + (bandsize >> 1))) / s->spx_dst_end_freq) - spx_blend;
nratio = av_clipf(nratio, 0.0f, 1.0f);
nblend = sqrtf(3.0f * nratio); // noise is scaled by sqrt(3)
// to give unity variance
sblend = sqrtf(1.0f - nratio);
+#endif
bin += bandsize;
/* decode spx coordinates */
@@ -891,11 +963,18 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
if (spx_coord_exp == 15) spx_coord_mant <<= 1;
else spx_coord_mant += 4;
spx_coord_mant <<= (25 - spx_coord_exp - master_spx_coord);
- spx_coord = spx_coord_mant * (1.0f / (1 << 23));
/* multiply noise and signal blending factors by spx coordinate */
+#if USE_FIXED
+ accu = (int64_t)nblend * spx_coord_mant;
+ s->spx_noise_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23);
+ accu = (int64_t)sblend * spx_coord_mant;
+ s->spx_signal_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23);
+#else
+ spx_coord = spx_coord_mant * (1.0f / (1 << 23));
s->spx_noise_blend [ch][bnd] = nblend * spx_coord;
s->spx_signal_blend[ch][bnd] = sblend * spx_coord;
+#endif
}
}
} else {
@@ -1252,18 +1331,28 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
/* apply scaling to coefficients (headroom, dynrng) */
for (ch = 1; ch <= s->channels; ch++) {
- float gain = 1.0 / 4194304.0f;
- if (s->channel_mode == AC3_CHMODE_DUALMONO) {
- gain *= s->dynamic_range[2 - ch];
- } else {
- gain *= s->dynamic_range[0];
- }
+ int audio_channel = 0;
+ INTFLOAT gain;
+ if (s->channel_mode == AC3_CHMODE_DUALMONO)
+ audio_channel = 2-ch;
+ if (s->heavy_compression && s->compression_exists[audio_channel])
+ gain = s->heavy_dynamic_range[audio_channel];
+ else
+ gain = s->dynamic_range[audio_channel];
+
+#if USE_FIXED
+ scale_coefs(s->transform_coeffs[ch], s->fixed_coeffs[ch], gain, 256);
+#else
+ if (s->target_level != 0)
+ gain = gain * s->level_gain[audio_channel];
+ gain *= 1.0 / 4194304.0f;
s->fmt_conv.int32_to_float_fmul_scalar(s->transform_coeffs[ch],
s->fixed_coeffs[ch], gain, 256);
+#endif
}
/* apply spectral extension to high frequency bins */
- if (s->spx_in_use && CONFIG_EAC3_DECODER) {
+ if (CONFIG_EAC3_DECODER && s->spx_in_use) {
ff_eac3_apply_spectral_extension(s);
}
@@ -1284,19 +1373,24 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
do_imdct(s, s->channels);
if (downmix_output) {
+#if USE_FIXED
+ ac3_downmix_c_fixed16(s->outptr, s->downmix_coeffs,
+ s->out_channels, s->fbw_channels, 256);
+#else
s->ac3dsp.downmix(s->outptr, s->downmix_coeffs,
s->out_channels, s->fbw_channels, 256);
+#endif
}
} else {
if (downmix_output) {
- s->ac3dsp.downmix(s->xcfptr + 1, s->downmix_coeffs,
- s->out_channels, s->fbw_channels, 256);
+ s->ac3dsp.AC3_RENAME(downmix)(s->xcfptr + 1, s->downmix_coeffs,
+ s->out_channels, s->fbw_channels, 256);
}
if (downmix_output && !s->downmixed) {
s->downmixed = 1;
- s->ac3dsp.downmix(s->dlyptr, s->downmix_coeffs, s->out_channels,
- s->fbw_channels, 128);
+ s->ac3dsp.AC3_RENAME(downmix)(s->dlyptr, s->downmix_coeffs,
+ s->out_channels, s->fbw_channels, 128);
}
do_imdct(s, s->out_channels);
@@ -1317,7 +1411,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
AC3DecodeContext *s = avctx->priv_data;
int blk, ch, err, ret;
const uint8_t *channel_map;
- const float *output[AC3_MAX_CHANNELS];
+ const SHORTFLOAT *output[AC3_MAX_CHANNELS];
enum AVMatrixEncoding matrix_encoding;
AVDownmixInfo *downmix_info;
@@ -1332,7 +1426,8 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
memcpy(s->input_buffer, buf, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE));
buf = s->input_buffer;
/* initialize the GetBitContext with the start of valid AC-3 Frame */
- init_get_bits(&s->gbc, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&s->gbc, buf, buf_size)) < 0)
+ return ret;
/* parse the syncinfo */
err = parse_frame_header(s);
@@ -1375,7 +1470,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
if (s->frame_size > buf_size) {
av_log(avctx, AV_LOG_ERROR, "incomplete frame\n");
err = AAC_AC3_PARSE_ERROR_FRAME_SIZE;
- } else if (avctx->err_recognition & AV_EF_CRCCHECK) {
+ } 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],
s->frame_size - 2)) {
@@ -1409,6 +1504,10 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
s->output_mode = AC3_CHMODE_STEREO;
}
+ s->loro_center_mix_level = gain_levels[s-> center_mix_level];
+ s->loro_surround_mix_level = gain_levels[s->surround_mix_level];
+ s->ltrt_center_mix_level = LEVEL_MINUS_3DB;
+ s->ltrt_surround_mix_level = LEVEL_MINUS_3DB;
/* set downmixing coefficients if needed */
if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) &&
s->fbw_channels == s->out_channels)) {
@@ -1430,19 +1529,18 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
/* get output buffer */
frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
/* decode the audio blocks */
channel_map = ff_ac3_dec_channel_map[s->output_mode & ~AC3_OUTPUT_LFEON][s->lfe_on];
+ for (ch = 0; ch < AC3_MAX_CHANNELS; ch++) {
+ output[ch] = s->output[ch];
+ s->outptr[ch] = s->output[ch];
+ }
for (ch = 0; ch < s->channels; ch++) {
if (ch < s->out_channels)
- s->outptr[channel_map[ch]] = (float *)frame->data[ch];
- else
- s->outptr[ch] = s->output[ch];
- output[ch] = s->output[ch];
+ s->outptr[channel_map[ch]] = (SHORTFLOAT *)frame->data[ch];
}
for (blk = 0; blk < s->num_blocks; blk++) {
if (!err && decode_audio_block(s, blk)) {
@@ -1451,16 +1549,20 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data,
}
if (err)
for (ch = 0; ch < s->out_channels; ch++)
- memcpy(s->outptr[channel_map[ch]], output[ch], sizeof(**output) * AC3_BLOCK_SIZE);
+ memcpy(((SHORTFLOAT*)frame->data[ch]) + AC3_BLOCK_SIZE*blk, output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT));
for (ch = 0; ch < s->out_channels; ch++)
output[ch] = s->outptr[channel_map[ch]];
- for (ch = 0; ch < s->out_channels; ch++)
- s->outptr[ch] += AC3_BLOCK_SIZE;
+ for (ch = 0; ch < s->out_channels; ch++) {
+ if (!ch || channel_map[ch])
+ s->outptr[channel_map[ch]] += AC3_BLOCK_SIZE;
+ }
}
+ av_frame_set_decode_error_flags(frame, err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0);
+
/* keep last block for error concealment in next frame */
for (ch = 0; ch < s->out_channels; ch++)
- memcpy(s->output[ch], output[ch], sizeof(**output) * AC3_BLOCK_SIZE);
+ memcpy(s->output[ch], output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT));
/*
* AVMatrixEncoding
@@ -1531,59 +1633,10 @@ static av_cold int ac3_decode_end(AVCodecContext *avctx)
AC3DecodeContext *s = avctx->priv_data;
ff_mdct_end(&s->imdct_512);
ff_mdct_end(&s->imdct_256);
+ av_freep(&s->fdsp);
return 0;
}
#define OFFSET(x) offsetof(AC3DecodeContext, x)
#define PAR (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM)
-static const AVOption options[] = {
- { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR },
- { NULL},
-};
-
-static const AVClass ac3_decoder_class = {
- .class_name = "AC3 decoder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_ac3_decoder = {
- .name = "ac3",
- .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_AC3,
- .priv_data_size = sizeof (AC3DecodeContext),
- .init = ac3_decode_init,
- .close = ac3_decode_end,
- .decode = ac3_decode_frame,
- .capabilities = CODEC_CAP_DR1,
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
- AV_SAMPLE_FMT_NONE },
- .priv_class = &ac3_decoder_class,
-};
-
-#if CONFIG_EAC3_DECODER
-static const AVClass eac3_decoder_class = {
- .class_name = "E-AC3 decoder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_eac3_decoder = {
- .name = "eac3",
- .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_EAC3,
- .priv_data_size = sizeof (AC3DecodeContext),
- .init = ac3_decode_init,
- .close = ac3_decode_end,
- .decode = ac3_decode_frame,
- .capabilities = CODEC_CAP_DR1,
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
- AV_SAMPLE_FMT_NONE },
- .priv_class = &eac3_decoder_class,
-};
-#endif
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index babd0a7d70..5259c60009 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -2,20 +2,20 @@
* Common code between the AC-3 and E-AC-3 decoders
* Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,6 +51,7 @@
#define AVCODEC_AC3DEC_H
#include "libavutil/float_dsp.h"
+#include "libavutil/fixed_dsp.h"
#include "libavutil/lfg.h"
#include "ac3.h"
#include "ac3dsp.h"
@@ -83,6 +84,9 @@ typedef struct AC3DecodeContext {
int bitstream_mode; ///< bitstream mode (bsmod)
int channel_mode; ///< channel mode (acmod)
int lfe_on; ///< lfe channel in use
+ int dialog_normalization[2]; ///< dialog level in dBFS (dialnorm)
+ int compression_exists[2]; ///< compression field is valid for frame (compre)
+ int compression_gain[2]; ///< gain to apply for heavy compression (compr)
int channel_map; ///< custom channel map
int preferred_downmix; ///< Preferred 2-channel downmix mode (dmixmod)
int center_mix_level; ///< Center mix level index
@@ -97,6 +101,14 @@ typedef struct AC3DecodeContext {
int dolby_headphone_mode; ///< dolby headphone mode (dheadphonmod)
///@}
+ int preferred_stereo_downmix;
+ float ltrt_center_mix_level;
+ float ltrt_surround_mix_level;
+ float loro_center_mix_level;
+ float loro_surround_mix_level;
+ int target_level; ///< target level in dBFS
+ float level_gain[2];
+
///@name Frame syntax parameters
int snr_offset_strategy; ///< SNR offset strategy (snroffststr)
int block_switch_syntax; ///< block switch syntax enabled (blkswe)
@@ -132,8 +144,8 @@ typedef struct AC3DecodeContext {
int num_spx_bands; ///< number of spx bands (nspxbnds)
uint8_t spx_band_sizes[SPX_MAX_BANDS]; ///< number of bins in each spx band
uint8_t first_spx_coords[AC3_MAX_CHANNELS]; ///< first spx coordinates states (firstspxcos)
- float spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor (nblendfact)
- float spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact)
+ INTFLOAT spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor (nblendfact)
+ INTFLOAT spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact)
///@}
///@name Adaptive hybrid transform
@@ -145,15 +157,17 @@ typedef struct AC3DecodeContext {
int fbw_channels; ///< number of full-bandwidth channels
int channels; ///< number of total channels
int lfe_ch; ///< index of LFE channel
- float downmix_coeffs[AC3_MAX_CHANNELS][2]; ///< stereo downmix coefficients
+ SHORTFLOAT downmix_coeffs[AC3_MAX_CHANNELS][2]; ///< stereo downmix coefficients
int downmixed; ///< indicates if coeffs are currently downmixed
int output_mode; ///< output channel configuration
int out_channels; ///< number of output channels
///@}
///@name Dynamic range
- float dynamic_range[2]; ///< dynamic range
- float drc_scale; ///< percentage of dynamic range compression to be applied
+ INTFLOAT dynamic_range[2]; ///< dynamic range
+ INTFLOAT drc_scale; ///< percentage of dynamic range compression to be applied
+ int heavy_compression; ///< apply heavy compression
+ INTFLOAT heavy_dynamic_range[2]; ///< heavy dynamic range compression
///@}
///@name Bandwidth
@@ -201,22 +215,26 @@ typedef struct AC3DecodeContext {
///@name Optimization
BswapDSPContext bdsp;
- AVFloatDSPContext fdsp;
+#if USE_FIXED
+ AVFixedDSPContext *fdsp;
+#else
+ AVFloatDSPContext *fdsp;
+#endif
AC3DSPContext ac3dsp;
FmtConvertContext fmt_conv; ///< optimized conversion functions
///@}
- float *outptr[AC3_MAX_CHANNELS];
- float *xcfptr[AC3_MAX_CHANNELS];
- float *dlyptr[AC3_MAX_CHANNELS];
+ SHORTFLOAT *outptr[AC3_MAX_CHANNELS];
+ INTFLOAT *xcfptr[AC3_MAX_CHANNELS];
+ INTFLOAT *dlyptr[AC3_MAX_CHANNELS];
///@name Aligned arrays
- DECLARE_ALIGNED(16, int32_t, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients
- DECLARE_ALIGNED(32, float, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< transform coefficients
- DECLARE_ALIGNED(32, float, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block
- DECLARE_ALIGNED(32, float, window)[AC3_BLOCK_SIZE]; ///< window coefficients
- DECLARE_ALIGNED(32, float, tmp_output)[AC3_BLOCK_SIZE]; ///< temporary storage for output before windowing
- DECLARE_ALIGNED(32, float, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing
+ DECLARE_ALIGNED(16, int, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients
+ DECLARE_ALIGNED(32, INTFLOAT, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< transform coefficients
+ DECLARE_ALIGNED(32, INTFLOAT, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block
+ DECLARE_ALIGNED(32, INTFLOAT, window)[AC3_BLOCK_SIZE]; ///< window coefficients
+ DECLARE_ALIGNED(32, INTFLOAT, tmp_output)[AC3_BLOCK_SIZE]; ///< temporary storage for output before windowing
+ DECLARE_ALIGNED(32, SHORTFLOAT, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing
DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread
///@}
} AC3DecodeContext;
@@ -225,19 +243,19 @@ typedef struct AC3DecodeContext {
* Parse the E-AC-3 frame header.
* This parses both the bit stream info and audio frame header.
*/
-int ff_eac3_parse_header(AC3DecodeContext *s);
+static int ff_eac3_parse_header(AC3DecodeContext *s);
/**
* Decode mantissas in a single channel for the entire frame.
* This is used when AHT mode is enabled.
*/
-void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch);
+static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch);
/**
* Apply spectral extension to each channel by copying lower frequency
* coefficients to higher frequency bins and applying side information to
* approximate the original high frequency signal.
*/
-void ff_eac3_apply_spectral_extension(AC3DecodeContext *s);
+static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s);
#endif /* AVCODEC_AC3DEC_H */
diff --git a/libavcodec/ac3dec_data.c b/libavcodec/ac3dec_data.c
index 272a963f08..d0a9b1ec40 100644
--- a/libavcodec/ac3dec_data.c
+++ b/libavcodec/ac3dec_data.c
@@ -2,20 +2,20 @@
* AC-3 and E-AC-3 decoder tables
* Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ac3dec_data.h b/libavcodec/ac3dec_data.h
index c0a584e7b3..975b52ef2c 100644
--- a/libavcodec/ac3dec_data.h
+++ b/libavcodec/ac3dec_data.h
@@ -2,20 +2,20 @@
* AC-3 and E-AC-3 decoder tables
* Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c
new file mode 100644
index 0000000000..b4beee6dd7
--- /dev/null
+++ b/libavcodec/ac3dec_fixed.c
@@ -0,0 +1,196 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ *
+ * AC3 fixed-point decoder for MIPS platforms
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 FFT_FLOAT 0
+#define USE_FIXED 1
+#define FFT_FIXED_32 1
+#include "ac3dec.h"
+
+
+static const int end_freq_inv_tab[8] =
+{
+ 50529027, 44278013, 39403370, 32292987, 27356480, 23729101, 20951060, 18755316
+};
+
+static void scale_coefs (
+ int32_t *dst,
+ const int32_t *src,
+ int dynrng,
+ int len)
+{
+ int i, shift, round;
+ int16_t mul;
+ int temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ mul = (dynrng & 0x1f) + 0x20;
+ shift = 4 - ((dynrng << 23) >> 28);
+ if (shift > 0 ) {
+ round = 1 << (shift-1);
+ for (i=0; i<len; i+=8) {
+
+ temp = src[i] * mul;
+ temp1 = src[i+1] * mul;
+ temp = temp + round;
+ temp2 = src[i+2] * mul;
+
+ temp1 = temp1 + round;
+ dst[i] = temp >> shift;
+ temp3 = src[i+3] * mul;
+ temp2 = temp2 + round;
+
+ dst[i+1] = temp1 >> shift;
+ temp4 = src[i + 4] * mul;
+ temp3 = temp3 + round;
+ dst[i+2] = temp2 >> shift;
+
+ temp5 = src[i+5] * mul;
+ temp4 = temp4 + round;
+ dst[i+3] = temp3 >> shift;
+ temp6 = src[i+6] * mul;
+
+ dst[i+4] = temp4 >> shift;
+ temp5 = temp5 + round;
+ temp7 = src[i+7] * mul;
+ temp6 = temp6 + round;
+
+ dst[i+5] = temp5 >> shift;
+ temp7 = temp7 + round;
+ dst[i+6] = temp6 >> shift;
+ dst[i+7] = temp7 >> shift;
+
+ }
+ } else {
+ shift = -shift;
+ for (i=0; i<len; i+=8) {
+
+ temp = src[i] * mul;
+ temp1 = src[i+1] * mul;
+ temp2 = src[i+2] * mul;
+
+ dst[i] = temp << shift;
+ temp3 = src[i+3] * mul;
+
+ dst[i+1] = temp1 << shift;
+ temp4 = src[i + 4] * mul;
+ dst[i+2] = temp2 << shift;
+
+ temp5 = src[i+5] * mul;
+ dst[i+3] = temp3 << shift;
+ temp6 = src[i+6] * mul;
+
+ dst[i+4] = temp4 << shift;
+ temp7 = src[i+7] * mul;
+
+ dst[i+5] = temp5 << shift;
+ dst[i+6] = temp6 << shift;
+ dst[i+7] = temp7 << shift;
+
+ }
+ }
+}
+
+/**
+ * Downmix samples from original signal to stereo or mono (this is for 16-bit samples
+ * and fixed point decoder - original (for 32-bit samples) is in ac3dsp.c).
+ */
+static void ac3_downmix_c_fixed16(int16_t **samples, int16_t (*matrix)[2],
+ int out_ch, int in_ch, int len)
+{
+ int i, j;
+ int v0, v1;
+ if (out_ch == 2) {
+ for (i = 0; i < len; i++) {
+ v0 = v1 = 0;
+ for (j = 0; j < in_ch; j++) {
+ v0 += samples[j][i] * matrix[j][0];
+ v1 += samples[j][i] * matrix[j][1];
+ }
+ samples[0][i] = (v0+2048)>>12;
+ samples[1][i] = (v1+2048)>>12;
+ }
+ } else if (out_ch == 1) {
+ for (i = 0; i < len; i++) {
+ v0 = 0;
+ for (j = 0; j < in_ch; j++)
+ v0 += samples[j][i] * matrix[j][0];
+ samples[0][i] = (v0+2048)>>12;
+ }
+ }
+}
+
+#include "eac3dec.c"
+#include "ac3dec.c"
+
+static const AVOption options[] = {
+ { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR },
+ { "heavy_compr", "heavy dynamic range compression enabled", OFFSET(heavy_compression), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, PAR },
+ { NULL},
+};
+
+static const AVClass ac3_decoder_class = {
+ .class_name = "Fixed-Point AC-3 Decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ac3_fixed_decoder = {
+ .name = "ac3_fixed",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_AC3,
+ .priv_data_size = sizeof (AC3DecodeContext),
+ .init = ac3_decode_init,
+ .close = ac3_decode_end,
+ .decode = ac3_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &ac3_decoder_class,
+};
diff --git a/libavcodec/ac3dec_float.c b/libavcodec/ac3dec_float.c
new file mode 100644
index 0000000000..d74a0df68d
--- /dev/null
+++ b/libavcodec/ac3dec_float.c
@@ -0,0 +1,92 @@
+/*
+ * AC-3 Audio Decoder
+ * This code was developed as part of Google Summer of Code 2006.
+ * E-AC-3 support was added as part of Google Summer of Code 2007.
+ *
+ * Copyright (c) 2006 Kartikey Mahendra BHATT (bhattkm at gmail dot com)
+ * Copyright (c) 2007-2008 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
+ * Copyright (c) 2007 Justin Ruggles <justin.ruggles@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
+ */
+
+/**
+ * Upmix delay samples from stereo to original channel layout.
+ */
+#include "ac3dec.h"
+#include "eac3dec.c"
+#include "ac3dec.c"
+
+static const AVOption options[] = {
+ { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR },
+ { "heavy_compr", "heavy dynamic range compression enabled", OFFSET(heavy_compression), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, PAR },
+ { "target_level", "target level in -dBFS (0 not applied)", OFFSET(target_level), AV_OPT_TYPE_INT, {.i64 = 0 }, -31, 0, PAR },
+
+{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, 0, "dmix_mode"},
+{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0},
+{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0},
+{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0},
+{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0},
+
+ { NULL},
+};
+
+static const AVClass ac3_decoder_class = {
+ .class_name = "AC3 decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ac3_decoder = {
+ .name = "ac3",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_AC3,
+ .priv_data_size = sizeof (AC3DecodeContext),
+ .init = ac3_decode_init,
+ .close = ac3_decode_end,
+ .decode = ac3_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"),
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &ac3_decoder_class,
+};
+
+#if CONFIG_EAC3_DECODER
+static const AVClass eac3_decoder_class = {
+ .class_name = "E-AC3 decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_eac3_decoder = {
+ .name = "eac3",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_EAC3,
+ .priv_data_size = sizeof (AC3DecodeContext),
+ .init = ac3_decode_init,
+ .close = ac3_decode_end,
+ .decode = ac3_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"),
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &eac3_decoder_class,
+};
+#endif
diff --git a/libavcodec/ac3dsp.c b/libavcodec/ac3dsp.c
index 933550bfdc..fe87b5bde5 100644
--- a/libavcodec/ac3dsp.c
+++ b/libavcodec/ac3dsp.c
@@ -2,20 +2,20 @@
* AC-3 DSP functions
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -172,6 +172,48 @@ static void ac3_extract_exponents_c(uint8_t *exp, int32_t *coef, int nb_coefs)
}
}
+static void ac3_sum_square_butterfly_int32_c(int64_t sum[4],
+ const int32_t *coef0,
+ const int32_t *coef1,
+ int len)
+{
+ int i;
+
+ sum[0] = sum[1] = sum[2] = sum[3] = 0;
+
+ for (i = 0; i < len; i++) {
+ int lt = coef0[i];
+ int rt = coef1[i];
+ int md = lt + rt;
+ int sd = lt - rt;
+ MAC64(sum[0], lt, lt);
+ MAC64(sum[1], rt, rt);
+ MAC64(sum[2], md, md);
+ MAC64(sum[3], sd, sd);
+ }
+}
+
+static void ac3_sum_square_butterfly_float_c(float sum[4],
+ const float *coef0,
+ const float *coef1,
+ int len)
+{
+ int i;
+
+ sum[0] = sum[1] = sum[2] = sum[3] = 0;
+
+ for (i = 0; i < len; i++) {
+ float lt = coef0[i];
+ float rt = coef1[i];
+ float md = lt + rt;
+ float sd = lt - rt;
+ sum[0] += lt * lt;
+ sum[1] += rt * rt;
+ sum[2] += md * md;
+ sum[3] += sd * sd;
+ }
+}
+
static void ac3_downmix_c(float **samples, float (*matrix)[2],
int out_ch, int in_ch, int len)
{
@@ -197,6 +239,31 @@ static void ac3_downmix_c(float **samples, float (*matrix)[2],
}
}
+static void ac3_downmix_c_fixed(int32_t **samples, int16_t (*matrix)[2],
+ int out_ch, int in_ch, int len)
+{
+ int i, j;
+ int64_t v0, v1;
+ if (out_ch == 2) {
+ for (i = 0; i < len; i++) {
+ v0 = v1 = 0;
+ for (j = 0; j < in_ch; j++) {
+ v0 += (int64_t)samples[j][i] * matrix[j][0];
+ v1 += (int64_t)samples[j][i] * matrix[j][1];
+ }
+ samples[0][i] = (v0+2048)>>12;
+ samples[1][i] = (v1+2048)>>12;
+ }
+ } else if (out_ch == 1) {
+ for (i = 0; i < len; i++) {
+ v0 = 0;
+ for (j = 0; j < in_ch; j++)
+ v0 += (int64_t)samples[j][i] * matrix[j][0];
+ samples[0][i] = (v0+2048)>>12;
+ }
+ }
+}
+
static void apply_window_int16_c(int16_t *output, const int16_t *input,
const int16_t *window, unsigned int len)
{
@@ -221,11 +288,16 @@ av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact)
c->update_bap_counts = ac3_update_bap_counts_c;
c->compute_mantissa_size = ac3_compute_mantissa_size_c;
c->extract_exponents = ac3_extract_exponents_c;
+ c->sum_square_butterfly_int32 = ac3_sum_square_butterfly_int32_c;
+ c->sum_square_butterfly_float = ac3_sum_square_butterfly_float_c;
c->downmix = ac3_downmix_c;
+ c->downmix_fixed = ac3_downmix_c_fixed;
c->apply_window_int16 = apply_window_int16_c;
if (ARCH_ARM)
ff_ac3dsp_init_arm(c, bit_exact);
if (ARCH_X86)
ff_ac3dsp_init_x86(c, bit_exact);
+ if (ARCH_MIPS)
+ ff_ac3dsp_init_mips(c, bit_exact);
}
diff --git a/libavcodec/ac3dsp.h b/libavcodec/ac3dsp.h
index 6ca0c5b8e8..ed98c8ce6a 100644
--- a/libavcodec/ac3dsp.h
+++ b/libavcodec/ac3dsp.h
@@ -2,20 +2,20 @@
* AC-3 DSP functions
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -126,9 +126,18 @@ typedef struct AC3DSPContext {
void (*extract_exponents)(uint8_t *exp, int32_t *coef, int nb_coefs);
+ void (*sum_square_butterfly_int32)(int64_t sum[4], const int32_t *coef0,
+ const int32_t *coef1, int len);
+
+ void (*sum_square_butterfly_float)(float sum[4], const float *coef0,
+ const float *coef1, int len);
+
void (*downmix)(float **samples, float (*matrix)[2], int out_ch,
int in_ch, int len);
+ void (*downmix_fixed)(int32_t **samples, int16_t (*matrix)[2], int out_ch,
+ int in_ch, int len);
+
/**
* Apply symmetric window in 16-bit fixed-point.
* @param output destination array
@@ -147,5 +156,6 @@ typedef struct AC3DSPContext {
void ff_ac3dsp_init (AC3DSPContext *c, int bit_exact);
void ff_ac3dsp_init_arm(AC3DSPContext *c, int bit_exact);
void ff_ac3dsp_init_x86(AC3DSPContext *c, int bit_exact);
+void ff_ac3dsp_init_mips(AC3DSPContext *c, int bit_exact);
#endif /* AVCODEC_AC3DSP_H */
diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c
index 4215c10ac7..50803de359 100644
--- a/libavcodec/ac3enc.c
+++ b/libavcodec/ac3enc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2010 Justin Ruggles <justin.ruggles@gmail.com>
* Copyright (c) 2006-2010 Prakash Punnoor <prakash@punnoor.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,6 +36,7 @@
#include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "avcodec.h"
+#include "internal.h"
#include "me_cmp.h"
#include "put_bits.h"
#include "audiodsp.h"
@@ -273,7 +274,7 @@ void ff_ac3_apply_rematrixing(AC3EncodeContext *s)
int nb_coefs;
int blk, bnd, i;
int start, end;
- uint8_t *flags;
+ uint8_t *flags = NULL;
if (!s->rematrixing_enabled)
return;
@@ -1210,14 +1211,11 @@ static void quantize_mantissas_blk_ch(AC3Mant *s, int32_t *fixed_coef,
int i;
for (i = start_freq; i < end_freq; i++) {
- int v;
int c = fixed_coef[i];
int e = exp[i];
- int b = bap[i];
- switch (b) {
- case 0:
- v = 0;
- break;
+ int v = bap[i];
+ if (v)
+ switch (v) {
case 1:
v = sym_quant(c, e, 3);
switch (s->mant1_cnt) {
@@ -1286,7 +1284,7 @@ static void quantize_mantissas_blk_ch(AC3Mant *s, int32_t *fixed_coef,
v = asym_quant(c, e, 16);
break;
default:
- v = asym_quant(c, e, b - 1);
+ v = asym_quant(c, e, v - 1);
break;
}
qmant[i] = v;
@@ -1386,7 +1384,7 @@ static void ac3_output_frame_header(AC3EncodeContext *s)
*/
static void output_audio_block(AC3EncodeContext *s, int blk)
{
- int ch, i, baie, bnd, got_cpl, ch0;
+ int ch, i, baie, bnd, got_cpl, av_uninit(ch0);
AC3Block *block = &s->blocks[blk];
/* block switching */
@@ -2022,6 +2020,7 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx)
AC3EncodeContext *s = avctx->priv_data;
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);
@@ -2037,6 +2036,7 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx)
av_freep(&s->qmant_buffer);
av_freep(&s->cpl_coord_exp_buffer);
av_freep(&s->cpl_coord_mant_buffer);
+ av_freep(&s->fdsp);
for (blk = 0; blk < s->num_blocks; blk++) {
AC3Block *block = &s->blocks[blk];
av_freep(&block->mdct_coef);
@@ -2250,7 +2250,7 @@ static av_cold int validate_options(AC3EncodeContext *s)
*/
static av_cold void set_bandwidth(AC3EncodeContext *s)
{
- int blk, ch, cpl_start;
+ int blk, ch, av_uninit(cpl_start);
if (s->cutoff) {
/* calculate bandwidth based on user-specified cutoff frequency */
@@ -2329,50 +2329,50 @@ static av_cold int allocate_buffers(AC3EncodeContext *s)
if (s->allocate_sample_buffers(s))
goto alloc_fail;
- FF_ALLOC_OR_GOTO(avctx, s->bap_buffer, total_coefs *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->bap_buffer, total_coefs,
sizeof(*s->bap_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->bap1_buffer, total_coefs *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->bap1_buffer, total_coefs,
sizeof(*s->bap1_buffer), alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, s->mdct_coef_buffer, total_coefs *
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->mdct_coef_buffer, total_coefs,
sizeof(*s->mdct_coef_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->exp_buffer, total_coefs *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->exp_buffer, total_coefs,
sizeof(*s->exp_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->grouped_exp_buffer, channel_blocks * 128 *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->grouped_exp_buffer, channel_blocks, 128 *
sizeof(*s->grouped_exp_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->psd_buffer, total_coefs *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->psd_buffer, total_coefs,
sizeof(*s->psd_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->band_psd_buffer, channel_blocks * 64 *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->band_psd_buffer, channel_blocks, 64 *
sizeof(*s->band_psd_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->mask_buffer, channel_blocks * 64 *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->mask_buffer, channel_blocks, 64 *
sizeof(*s->mask_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->qmant_buffer, total_coefs *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->qmant_buffer, total_coefs,
sizeof(*s->qmant_buffer), alloc_fail);
if (s->cpl_enabled) {
- FF_ALLOC_OR_GOTO(avctx, s->cpl_coord_exp_buffer, channel_blocks * 16 *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->cpl_coord_exp_buffer, channel_blocks, 16 *
sizeof(*s->cpl_coord_exp_buffer), alloc_fail);
- FF_ALLOC_OR_GOTO(avctx, s->cpl_coord_mant_buffer, channel_blocks * 16 *
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->cpl_coord_mant_buffer, channel_blocks, 16 *
sizeof(*s->cpl_coord_mant_buffer), alloc_fail);
}
for (blk = 0; blk < s->num_blocks; blk++) {
AC3Block *block = &s->blocks[blk];
- FF_ALLOCZ_OR_GOTO(avctx, block->mdct_coef, channels * sizeof(*block->mdct_coef),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->mdct_coef, channels, sizeof(*block->mdct_coef),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->exp, channels * sizeof(*block->exp),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->exp, channels, sizeof(*block->exp),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->grouped_exp, channels * sizeof(*block->grouped_exp),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->grouped_exp, channels, sizeof(*block->grouped_exp),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->psd, channels * sizeof(*block->psd),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->psd, channels, sizeof(*block->psd),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->band_psd, channels * sizeof(*block->band_psd),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->band_psd, channels, sizeof(*block->band_psd),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->mask, channels * sizeof(*block->mask),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->mask, channels, sizeof(*block->mask),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->qmant, channels * sizeof(*block->qmant),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->qmant, channels, sizeof(*block->qmant),
alloc_fail);
if (s->cpl_enabled) {
- FF_ALLOCZ_OR_GOTO(avctx, block->cpl_coord_exp, channels * sizeof(*block->cpl_coord_exp),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->cpl_coord_exp, channels, sizeof(*block->cpl_coord_exp),
alloc_fail);
- FF_ALLOCZ_OR_GOTO(avctx, block->cpl_coord_mant, channels * sizeof(*block->cpl_coord_mant),
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->cpl_coord_mant, channels, sizeof(*block->cpl_coord_mant),
alloc_fail);
}
@@ -2395,11 +2395,11 @@ static av_cold int allocate_buffers(AC3EncodeContext *s)
}
if (!s->fixed_point) {
- FF_ALLOCZ_OR_GOTO(avctx, s->fixed_coef_buffer, total_coefs *
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->fixed_coef_buffer, total_coefs,
sizeof(*s->fixed_coef_buffer), alloc_fail);
for (blk = 0; blk < s->num_blocks; blk++) {
AC3Block *block = &s->blocks[blk];
- FF_ALLOCZ_OR_GOTO(avctx, block->fixed_coef, channels *
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->fixed_coef, channels,
sizeof(*block->fixed_coef), alloc_fail);
for (ch = 0; ch < channels; ch++)
block->fixed_coef[ch] = &s->fixed_coef_buffer[AC3_MAX_COEFS * (s->num_blocks * ch + blk)];
@@ -2407,7 +2407,7 @@ static av_cold int allocate_buffers(AC3EncodeContext *s)
} else {
for (blk = 0; blk < s->num_blocks; blk++) {
AC3Block *block = &s->blocks[blk];
- FF_ALLOCZ_OR_GOTO(avctx, block->fixed_coef, channels *
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->fixed_coef, channels,
sizeof(*block->fixed_coef), alloc_fail);
for (ch = 0; ch < channels; ch++)
block->fixed_coef[ch] = (int32_t *)block->mdct_coef[ch];
diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h
index 76b6d7f6e5..a2442d0e55 100644
--- a/libavcodec/ac3enc.h
+++ b/libavcodec/ac3enc.h
@@ -3,20 +3,20 @@
* Copyright (c) 2000 Fabrice Bellard
* Copyright (c) 2006-2010 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -165,7 +165,7 @@ typedef struct AC3EncodeContext {
AVCodecContext *avctx; ///< parent AVCodecContext
PutBitContext pb; ///< bitstream writer context
AudioDSPContext adsp;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
MECmpContext mecc;
AC3DSPContext ac3dsp; ///< AC-3 optimized functions
FFTContext mdct; ///< FFT context for MDCT calculation
diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c
index 2bb82ef3b6..9d39026dd5 100644
--- a/libavcodec/ac3enc_fixed.c
+++ b/libavcodec/ac3enc_fixed.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2010 Justin Ruggles <justin.ruggles@gmail.com>
* Copyright (c) 2006-2010 Prakash Punnoor <prakash@punnoor.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,8 +35,13 @@
#define AC3ENC_TYPE AC3ENC_TYPE_AC3_FIXED
#include "ac3enc_opts_template.c"
-static const AVClass ac3enc_class = { "Fixed-Point AC-3 Encoder", av_default_item_name,
- ac3_options, LIBAVUTIL_VERSION_INT };
+
+static const AVClass ac3enc_class = {
+ .class_name = "Fixed-Point AC-3 Encoder",
+ .item_name = av_default_item_name,
+ .option = ac3_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
#include "ac3enc_template.c"
@@ -97,6 +102,12 @@ static void scale_coefficients(AC3EncodeContext *s)
}
}
+static void sum_square_butterfly(AC3EncodeContext *s, int64_t sum[4],
+ const int32_t *coef0, const int32_t *coef1,
+ int len)
+{
+ s->ac3dsp.sum_square_butterfly_int32(sum, coef0, coef1, len);
+}
/*
* Clip MDCT coefficients to allowable range.
diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c
index d106d1b263..766b14ec13 100644
--- a/libavcodec/ac3enc_float.c
+++ b/libavcodec/ac3enc_float.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2010 Justin Ruggles <justin.ruggles@gmail.com>
* Copyright (c) 2006-2010 Prakash Punnoor <prakash@punnoor.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,8 +36,12 @@
#define AC3ENC_TYPE AC3ENC_TYPE_AC3
#include "ac3enc_opts_template.c"
-static const AVClass ac3enc_class = { "AC-3 Encoder", av_default_item_name,
- ac3_options, LIBAVUTIL_VERSION_INT };
+static const AVClass ac3enc_class = {
+ .class_name = "AC-3 Encoder",
+ .item_name = av_default_item_name,
+ .option = ac3_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
#include "ac3enc_template.c"
@@ -68,7 +72,7 @@ av_cold int ff_ac3_float_mdct_init(AC3EncodeContext *s)
n = 1 << 9;
n2 = n >> 1;
- window = av_malloc(n * sizeof(*window));
+ window = av_malloc_array(n, sizeof(*window));
if (!window) {
av_log(s->avctx, AV_LOG_ERROR, "Cannot allocate memory.\n");
return AVERROR(ENOMEM);
@@ -104,6 +108,12 @@ static void scale_coefficients(AC3EncodeContext *s)
chan_size * (s->channels + cpl));
}
+static void sum_square_butterfly(AC3EncodeContext *s, float sum[4],
+ const float *coef0, const float *coef1,
+ int len)
+{
+ s->ac3dsp.sum_square_butterfly_float(sum, coef0, coef1, len);
+}
/*
* Clip MDCT coefficients to allowable range.
@@ -129,7 +139,9 @@ static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl)
av_cold int ff_ac3_float_encode_init(AVCodecContext *avctx)
{
AC3EncodeContext *s = avctx->priv_data;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
return ff_ac3_encode_init(avctx);
}
diff --git a/libavcodec/ac3enc_opts_template.c b/libavcodec/ac3enc_opts_template.c
index a08c70d2c5..83113b8d12 100644
--- a/libavcodec/ac3enc_opts_template.c
+++ b/libavcodec/ac3enc_opts_template.c
@@ -2,20 +2,20 @@
* AC-3 encoder options
* Copyright (c) 2011 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c
index 79b4946b65..c3ad76f429 100644
--- a/libavcodec/ac3enc_template.c
+++ b/libavcodec/ac3enc_template.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2011 Justin Ruggles <justin.ruggles@gmail.com>
* Copyright (c) 2006-2010 Prakash Punnoor <prakash@punnoor.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,6 +47,9 @@ static void clip_coefficients(AudioDSPContext *adsp, CoefType *coef,
static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl);
+static void sum_square_butterfly(AC3EncodeContext *s, CoefSumType sum[4],
+ const CoefType *coef0, const CoefType *coef1,
+ int len);
int AC3_NAME(allocate_sample_buffers)(AC3EncodeContext *s)
{
@@ -54,7 +57,7 @@ int AC3_NAME(allocate_sample_buffers)(AC3EncodeContext *s)
FF_ALLOC_OR_GOTO(s->avctx, s->windowed_samples, AC3_WINDOW_SIZE *
sizeof(*s->windowed_samples), alloc_fail);
- FF_ALLOC_OR_GOTO(s->avctx, s->planar_samples, s->channels * sizeof(*s->planar_samples),
+ FF_ALLOC_ARRAY_OR_GOTO(s->avctx, s->planar_samples, s->channels, sizeof(*s->planar_samples),
alloc_fail);
for (ch = 0; ch < s->channels; ch++) {
FF_ALLOCZ_OR_GOTO(s->avctx, s->planar_samples[ch],
@@ -70,7 +73,7 @@ alloc_fail:
/*
* Copy input samples.
- * Channels are reordered from Libav's default order to AC-3 order.
+ * Channels are reordered from FFmpeg's default order to AC-3 order.
*/
static void copy_input_samples(AC3EncodeContext *s, SampleType **samples)
{
@@ -105,7 +108,7 @@ static void apply_mdct(AC3EncodeContext *s)
const SampleType *input_samples = &s->planar_samples[ch][blk * AC3_BLOCK_SIZE];
#if CONFIG_AC3ENC_FLOAT
- s->fdsp.vector_fmul(s->windowed_samples, input_samples,
+ s->fdsp->vector_fmul(s->windowed_samples, input_samples,
s->mdct_window, AC3_WINDOW_SIZE);
#else
s->ac3dsp.apply_window_int16(s->windowed_samples, input_samples,
@@ -133,7 +136,7 @@ static void apply_channel_coupling(AC3EncodeContext *s)
#else
int32_t (*fixed_cpl_coords)[AC3_MAX_CHANNELS][16] = cpl_coords;
#endif
- int blk, ch, bnd, i, j;
+ int av_uninit(blk), ch, bnd, i, j;
CoefSumType energy[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}};
int cpl_start, num_cpl_coefs;
@@ -260,7 +263,7 @@ static void apply_channel_coupling(AC3EncodeContext *s)
energy_cpl = energy[blk][CPL_CH][bnd];
energy_ch = energy[blk][ch][bnd];
blk1 = blk+1;
- while (!s->blocks[blk1].new_cpl_coords[ch] && blk1 < s->num_blocks) {
+ while (blk1 < s->num_blocks && !s->blocks[blk1].new_cpl_coords[ch]) {
if (s->blocks[blk1].cpl_in_use) {
energy_cpl += energy[blk1][CPL_CH][bnd];
energy_ch += energy[blk1][ch][bnd];
@@ -336,8 +339,8 @@ static void apply_channel_coupling(AC3EncodeContext *s)
static void compute_rematrixing_strategy(AC3EncodeContext *s)
{
int nb_coefs;
- int blk, bnd, i;
- AC3Block *block, *block0;
+ int blk, bnd;
+ AC3Block *block, *block0 = NULL;
if (s->channel_mode != AC3_CHMODE_STEREO)
return;
@@ -361,20 +364,12 @@ static void compute_rematrixing_strategy(AC3EncodeContext *s)
}
for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) {
- /* calculate calculate sum of squared coeffs for one band in one block */
+ /* calculate sum of squared coeffs for one band in one block */
int start = ff_ac3_rematrix_band_tab[bnd];
int end = FFMIN(nb_coefs, ff_ac3_rematrix_band_tab[bnd+1]);
- CoefSumType sum[4] = {0,};
- for (i = start; i < end; i++) {
- CoefType lt = block->mdct_coef[1][i];
- CoefType rt = block->mdct_coef[2][i];
- CoefType md = lt + rt;
- CoefType sd = lt - rt;
- MAC_COEF(sum[0], lt, lt);
- MAC_COEF(sum[1], rt, rt);
- MAC_COEF(sum[2], md, md);
- MAC_COEF(sum[3], sd, sd);
- }
+ CoefSumType sum[4];
+ sum_square_butterfly(s, sum, block->mdct_coef[1] + start,
+ block->mdct_coef[2] + start, end - start);
/* compare sums to determine if rematrixing will be used for this band */
if (FFMIN(sum[2], sum[3]) < FFMIN(sum[0], sum[1]))
@@ -443,14 +438,12 @@ int AC3_NAME(encode_frame)(AVCodecContext *avctx, AVPacket *avpkt,
ff_ac3_quantize_mantissas(s);
- if ((ret = ff_alloc_packet(avpkt, s->frame_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, s->frame_size)) < 0)
return ret;
- }
ff_ac3_output_frame(s, avpkt->data);
if (frame->pts != AV_NOPTS_VALUE)
- avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->delay);
+ avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding);
*got_packet_ptr = 1;
return 0;
diff --git a/libavcodec/ac3tab.c b/libavcodec/ac3tab.c
index 3cd07f9e4b..d62d8bfbf5 100644
--- a/libavcodec/ac3tab.c
+++ b/libavcodec/ac3tab.c
@@ -2,20 +2,20 @@
* AC-3 tables
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -116,7 +116,7 @@ const uint8_t ff_ac3_enc_channel_map[8][2][6] = {
};
/**
- * Table to remap channels from from AC-3 order to SMPTE order.
+ * Table to remap channels from AC-3 order to SMPTE order.
* [channel_mode][lfe][ch]
*/
const uint8_t ff_ac3_dec_channel_map[8][2][6] = {
diff --git a/libavcodec/ac3tab.h b/libavcodec/ac3tab.h
index 83edec52d1..74cbd9ed65 100644
--- a/libavcodec/ac3tab.h
+++ b/libavcodec/ac3tab.h
@@ -2,20 +2,20 @@
* AC-3 tables
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/acelp_filters.c b/libavcodec/acelp_filters.c
index 93bec6589a..9ab758b977 100644
--- a/libavcodec/acelp_filters.c
+++ b/libavcodec/acelp_filters.c
@@ -3,25 +3,26 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "avcodec.h"
#include "acelp_filters.h"
@@ -46,7 +47,7 @@ void ff_acelp_interpolate(int16_t* out, const int16_t* in,
{
int n, i;
- assert(frac_pos >= 0 && frac_pos < precision);
+ av_assert1(frac_pos >= 0 && frac_pos < precision);
for (n = 0; n < length; n++) {
int idx = 0;
@@ -143,3 +144,12 @@ void ff_tilt_compensation(float *mem, float tilt, float *samples, int size)
samples[0] -= tilt * *mem;
*mem = new_tilt_mem;
}
+
+void ff_acelp_filter_init(ACELPFContext *c)
+{
+ c->acelp_interpolatef = ff_acelp_interpolatef;
+ c->acelp_apply_order_2_transfer_function = ff_acelp_apply_order_2_transfer_function;
+
+ if(HAVE_MIPSFPU)
+ ff_acelp_filter_init_mips(c);
+}
diff --git a/libavcodec/acelp_filters.h b/libavcodec/acelp_filters.h
index 6a9ebd943e..7a3061bd1f 100644
--- a/libavcodec/acelp_filters.h
+++ b/libavcodec/acelp_filters.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,39 @@
#include <stdint.h>
+typedef struct ACELPFContext {
+ /**
+ * Floating point version of ff_acelp_interpolate()
+ */
+ void (*acelp_interpolatef)(float *out, const float *in,
+ const float *filter_coeffs, int precision,
+ int frac_pos, int filter_length, int length);
+
+ /**
+ * Apply an order 2 rational transfer function in-place.
+ *
+ * @param out output buffer for filtered speech samples
+ * @param in input buffer containing speech data (may be the same as out)
+ * @param zero_coeffs z^-1 and z^-2 coefficients of the numerator
+ * @param pole_coeffs z^-1 and z^-2 coefficients of the denominator
+ * @param gain scale factor for final output
+ * @param mem intermediate values used by filter (should be 0 initially)
+ * @param n number of samples (should be a multiple of eight)
+ */
+ void (*acelp_apply_order_2_transfer_function)(float *out, const float *in,
+ const float zero_coeffs[2],
+ const float pole_coeffs[2],
+ float gain,
+ float mem[2], int n);
+
+}ACELPFContext;
+
+/**
+ * Initialize ACELPFContext.
+ */
+void ff_acelp_filter_init(ACELPFContext *c);
+void ff_acelp_filter_init_mips(ACELPFContext *c);
+
/**
* low-pass Finite Impulse Response filter coefficients.
*
@@ -76,7 +109,7 @@ void ff_acelp_interpolatef(float *out, const float *in,
*
* The filter has a cut-off frequency of 1/80 of the sampling freq
*
- * @note Two items before the top of the out buffer must contain two items from the
+ * @note Two items before the top of the in buffer must contain two items from the
* tail of the previous subframe.
*
* @remark It is safe to pass the same array in in and out parameters.
diff --git a/libavcodec/acelp_pitch_delay.c b/libavcodec/acelp_pitch_delay.c
index 19657729ce..3ecec01cbe 100644
--- a/libavcodec/acelp_pitch_delay.c
+++ b/libavcodec/acelp_pitch_delay.c
@@ -3,25 +3,26 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/float_dsp.h"
+#include "libavutil/libm.h"
#include "libavutil/mathematics.h"
#include "avcodec.h"
#include "acelp_pitch_delay.h"
@@ -107,9 +108,20 @@ int16_t ff_acelp_decode_gain_code(
for(i=0; i<ma_pred_order; i++)
mr_energy += quant_energy[i] * ma_prediction_coeff[i];
+#ifdef G729_BITEXACT
+ mr_energy += (((-6165LL * ff_log2(dsp->scalarproduct_int16(fc_v, fc_v, subframe_size, 0))) >> 3) & ~0x3ff);
+
+ mr_energy = (5439 * (mr_energy >> 15)) >> 8; // (0.15) = (0.15) * (7.23)
+
+ return bidir_sal(
+ ((ff_exp2(mr_energy & 0x7fff) + 16) >> 5) * (gain_corr_factor >> 1),
+ (mr_energy >> 15) - 25
+ );
+#else
mr_energy = gain_corr_factor * exp(M_LN10 / (20 << 23) * mr_energy) /
sqrt(adsp->scalarproduct_int16(fc_v, fc_v, subframe_size));
return mr_energy >> 12;
+#endif
}
float ff_amr_set_fixed_gain(float fixed_gain_factor, float fixed_mean_energy,
diff --git a/libavcodec/acelp_pitch_delay.h b/libavcodec/acelp_pitch_delay.h
index 7b5b33d9b4..2aade2f226 100644
--- a/libavcodec/acelp_pitch_delay.h
+++ b/libavcodec/acelp_pitch_delay.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/acelp_vectors.c b/libavcodec/acelp_vectors.c
index 0c660acb5a..798217d73b 100644
--- a/libavcodec/acelp_vectors.c
+++ b/libavcodec/acelp_vectors.c
@@ -3,25 +3,26 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/float_dsp.h"
#include "avcodec.h"
@@ -50,6 +51,26 @@ const uint8_t ff_fc_2pulses_9bits_track1_gray[16] =
28, 26,
};
+const uint8_t ff_fc_2pulses_9bits_track2_gray[32] =
+{
+ 0, 2,
+ 5, 4,
+ 12, 10,
+ 7, 9,
+ 25, 24,
+ 20, 22,
+ 14, 15,
+ 19, 17,
+ 36, 31,
+ 21, 26,
+ 1, 6,
+ 16, 11,
+ 27, 29,
+ 32, 30,
+ 39, 37,
+ 34, 35,
+};
+
const uint8_t ff_fc_4pulses_8bits_tracks_13[16] =
{
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75,
@@ -219,11 +240,13 @@ void ff_set_fixed_vector(float *out, const AMRFixed *in, float scale, int size)
int x = in->x[i], repeats = !((in->no_repeat_mask >> i) & 1);
float y = in->y[i] * scale;
- do {
- out[x] += y;
- y *= in->pitch_fac;
- x += in->pitch_lag;
- } while (x < size && repeats);
+ if (in->pitch_lag > 0)
+ av_assert0(x < size);
+ do {
+ out[x] += y;
+ y *= in->pitch_fac;
+ x += in->pitch_lag;
+ } while (x < size && repeats);
}
}
@@ -234,9 +257,18 @@ void ff_clear_fixed_vector(float *out, const AMRFixed *in, int size)
for (i=0; i < in->n; i++) {
int x = in->x[i], repeats = !((in->no_repeat_mask >> i) & 1);
- do {
- out[x] = 0.0;
- x += in->pitch_lag;
- } while (x < size && repeats);
+ if (in->pitch_lag > 0)
+ do {
+ out[x] = 0.0;
+ x += in->pitch_lag;
+ } while (x < size && repeats);
}
}
+
+void ff_acelp_vectors_init(ACELPVContext *c)
+{
+ c->weighted_vector_sumf = ff_weighted_vector_sumf;
+
+ if(HAVE_MIPSFPU)
+ ff_acelp_vectors_init_mips(c);
+}
diff --git a/libavcodec/acelp_vectors.h b/libavcodec/acelp_vectors.h
index d6226bf020..fae834dac1 100644
--- a/libavcodec/acelp_vectors.h
+++ b/libavcodec/acelp_vectors.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,30 @@
#include <stdint.h>
+typedef struct ACELPVContext {
+ /**
+ * float implementation of weighted sum of two vectors.
+ * @param[out] out result of addition
+ * @param in_a first vector
+ * @param in_b second vector
+ * @param weight_coeff_a first vector weight coefficient
+ * @param weight_coeff_a second vector weight coefficient
+ * @param length vectors length (should be a multiple of two)
+ *
+ * @note It is safe to pass the same buffer for out and in_a or in_b.
+ */
+ void (*weighted_vector_sumf)(float *out, const float *in_a, const float *in_b,
+ float weight_coeff_a, float weight_coeff_b,
+ int length);
+
+}ACELPVContext;
+
+/**
+ * Initialize ACELPVContext.
+ */
+void ff_acelp_vectors_init(ACELPVContext *c);
+void ff_acelp_vectors_init_mips(ACELPVContext *c);
+
/** Sparse representation for the algebraic codebook (fixed) vector */
typedef struct AMRFixed {
int n;
@@ -82,6 +106,37 @@ extern const uint8_t ff_fc_2pulses_9bits_track1[16];
extern const uint8_t ff_fc_2pulses_9bits_track1_gray[16];
/**
+ * Track|Pulse| Positions
+ * -----------------------------------------
+ * 2 | 1 | 0, 7, 14, 20, 27, 34, 1, 21
+ * | | 2, 9, 15, 22, 29, 35, 6, 26
+ * | | 4,10, 17, 24, 30, 37, 11, 31
+ * | | 5,12, 19, 25, 32, 39, 16, 36
+ * -----------------------------------------
+ *
+ * @remark Track in the table should be read top-to-bottom, left-to-right.
+ *
+ * @note (EE.1) This table (from the reference code) does not comply with
+ * the specification.
+ * The specification contains the following table:
+ *
+ * Track|Pulse| Positions
+ * -----------------------------------------
+ * 2 | 1 | 0, 5, 10, 15, 20, 25, 30, 35
+ * | | 1, 6, 11, 16, 21, 26, 31, 36
+ * | | 2, 7, 12, 17, 22, 27, 32, 37
+ * | | 4, 9, 14, 19, 24, 29, 34, 39
+ *
+ * -----------------------------------------
+ *
+ * @note (EE.2) Reference G.729D code also uses gray decoding for each
+ * pulse index before looking up the value in the table.
+ *
+ * Used in G.729 @@6.4k (with gray coding)
+ */
+extern const uint8_t ff_fc_2pulses_9bits_track2_gray[32];
+
+/**
* b60 hamming windowed sinc function coefficients
*/
extern const float ff_b60_sinc[61];
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index c6bc4d09d7..251ed1d5ea 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2003 The ffmpeg Project
+ * Copyright (c) 2001-2003 The FFmpeg Project
*
* first version by Francois Revol (revol@free.fr)
* fringe ADPCM codecs (e.g., DK3, DK4, Westwood)
@@ -13,25 +13,24 @@
* MAXIS EA ADPCM decoder by Robert Marston (rmarston@gmail.com)
* THP ADPCM decoder by Marco Gerards (mgerards@xs4all.nl)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "get_bits.h"
-#include "put_bits.h"
#include "bytestream.h"
#include "adpcm.h"
#include "adpcm_data.h"
@@ -96,13 +95,16 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
unsigned int max_channels = 2;
switch(avctx->codec->id) {
+ 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:
case AV_CODEC_ID_ADPCM_EA_R3:
case AV_CODEC_ID_ADPCM_EA_XAS:
+ case AV_CODEC_ID_ADPCM_THP:
max_channels = 6;
break;
}
@@ -116,10 +118,8 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
c->status[0].step = c->status[1].step = 511;
break;
case AV_CODEC_ID_ADPCM_IMA_WAV:
- if (avctx->bits_per_coded_sample != 4) {
- av_log(avctx, AV_LOG_ERROR, "Only 4-bit ADPCM IMA WAV files are supported\n");
- return -1;
- }
+ if (avctx->bits_per_coded_sample < 2 || avctx->bits_per_coded_sample > 5)
+ return AVERROR_INVALIDDATA;
break;
case AV_CODEC_ID_ADPCM_IMA_APC:
if (avctx->extradata && avctx->extradata_size >= 8) {
@@ -145,6 +145,8 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
case AV_CODEC_ID_ADPCM_EA_R3:
case AV_CODEC_ID_ADPCM_EA_XAS:
case AV_CODEC_ID_ADPCM_THP:
+ case AV_CODEC_ID_ADPCM_AFC:
+ case AV_CODEC_ID_ADPCM_DTK:
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
break;
case AV_CODEC_ID_ADPCM_IMA_WS:
@@ -184,6 +186,29 @@ static inline short adpcm_ima_expand_nibble(ADPCMChannelStatus *c, char nibble,
return (short)c->predictor;
}
+static inline int16_t adpcm_ima_wav_expand_nibble(ADPCMChannelStatus *c, GetBitContext *gb, int bps)
+{
+ int nibble, step_index, predictor, sign, delta, diff, step, shift;
+
+ shift = bps - 1;
+ nibble = get_bits_le(gb, bps),
+ step = ff_adpcm_step_table[c->step_index];
+ step_index = c->step_index + ff_adpcm_index_tables[bps - 2][nibble];
+ step_index = av_clip(step_index, 0, 88);
+
+ sign = nibble & (1 << shift);
+ delta = av_mod_uintp2(nibble, shift);
+ diff = ((2 * delta + 1) * step) >> shift;
+ predictor = c->predictor;
+ if (sign) predictor -= diff;
+ else predictor += diff;
+
+ c->predictor = av_clip_int16(predictor);
+ c->step_index = step_index;
+
+ return (int16_t)c->predictor;
+}
+
static inline int adpcm_ima_qt_expand_nibble(ADPCMChannelStatus *c, int nibble, int shift)
{
int step_index;
@@ -221,10 +246,35 @@ static inline short adpcm_ms_expand_nibble(ADPCMChannelStatus *c, int nibble)
c->sample1 = av_clip_int16(predictor);
c->idelta = (ff_adpcm_AdaptationTable[(int)nibble] * c->idelta) >> 8;
if (c->idelta < 16) c->idelta = 16;
+ if (c->idelta > INT_MAX/768) {
+ av_log(NULL, AV_LOG_WARNING, "idelta overflow\n");
+ c->idelta = INT_MAX/768;
+ }
return c->sample1;
}
+static inline short adpcm_ima_oki_expand_nibble(ADPCMChannelStatus *c, int nibble)
+{
+ int step_index, predictor, sign, delta, diff, step;
+
+ step = ff_adpcm_oki_step_table[c->step_index];
+ step_index = c->step_index + ff_adpcm_index_table[(unsigned)nibble];
+ step_index = av_clip(step_index, 0, 48);
+
+ sign = nibble & 8;
+ delta = nibble & 7;
+ diff = ((2 * delta + 1) * step) >> 3;
+ predictor = c->predictor;
+ if (sign) predictor -= diff;
+ else predictor += diff;
+
+ c->predictor = av_clip_intp2(predictor, 11);
+ c->step_index = step_index;
+
+ return c->predictor << 4;
+}
+
static inline short adpcm_ct_expand_nibble(ADPCMChannelStatus *c, char nibble)
{
int sign, delta, diff;
@@ -298,11 +348,9 @@ static int xa_decode(AVCodecContext *avctx, int16_t *out0, int16_t *out1,
for(i=0;i<4;i++) {
shift = 12 - (in[4+i*2] & 15);
filter = in[4+i*2] >> 4;
- if (filter > 4) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid XA-ADPCM filter %d (max. allowed is 4)\n",
- filter);
- return AVERROR_INVALIDDATA;
+ if (filter >= FF_ARRAY_ELEMS(xa_adpcm_table)) {
+ avpriv_request_sample(avctx, "unknown XA-ADPCM filter %d", filter);
+ filter=0;
}
f0 = xa_adpcm_table[filter][0];
f1 = xa_adpcm_table[filter][1];
@@ -329,12 +377,11 @@ static int xa_decode(AVCodecContext *avctx, int16_t *out0, int16_t *out1,
shift = 12 - (in[5+i*2] & 15);
filter = in[5+i*2] >> 4;
- if (filter > 4) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid XA-ADPCM filter %d (max. allowed is 4)\n",
- filter);
- return AVERROR_INVALIDDATA;
+ if (filter >= FF_ARRAY_ELEMS(xa_adpcm_table)) {
+ avpriv_request_sample(avctx, "unknown XA-ADPCM filter %d", filter);
+ filter=0;
}
+
f0 = xa_adpcm_table[filter][0];
f1 = xa_adpcm_table[filter][1];
@@ -428,9 +475,11 @@ static void adpcm_swf_decode(AVCodecContext *avctx, const uint8_t *buf, int buf_
* @param[out] coded_samples set to the number of samples as coded in the
* packet, or 0 if the codec does not encode the
* number of samples in each frame.
+ * @param[out] approx_nb_samples set to non-zero if the number of samples
+ * returned is an approximation.
*/
static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
- int buf_size, int *coded_samples)
+ int buf_size, int *coded_samples, int *approx_nb_samples)
{
ADPCMDecodeContext *s = avctx->priv_data;
int nb_samples = 0;
@@ -439,6 +488,10 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
int header_size;
*coded_samples = 0;
+ *approx_nb_samples = 0;
+
+ if(ch <= 0)
+ return 0;
switch (avctx->codec->id) {
/* constant, only check buf_size */
@@ -456,6 +509,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
case AV_CODEC_ID_ADPCM_CT:
case AV_CODEC_ID_ADPCM_IMA_APC:
case AV_CODEC_ID_ADPCM_IMA_EA_SEAD:
+ case AV_CODEC_ID_ADPCM_IMA_OKI:
case AV_CODEC_ID_ADPCM_IMA_WS:
case AV_CODEC_ID_ADPCM_YAMAHA:
nb_samples = buf_size * 2 / ch;
@@ -470,7 +524,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
case AV_CODEC_ID_ADPCM_4XM:
case AV_CODEC_ID_ADPCM_IMA_ISS: header_size = 4 * ch; break;
case AV_CODEC_ID_ADPCM_IMA_AMV: header_size = 8; break;
- case AV_CODEC_ID_ADPCM_IMA_SMJPEG: header_size = 4; break;
+ case AV_CODEC_ID_ADPCM_IMA_SMJPEG: header_size = 4 * ch; break;
}
if (header_size > 0)
return (buf_size - header_size) * 2 / ch;
@@ -514,6 +568,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
*coded_samples -= *coded_samples % 28;
nb_samples = (buf_size - header_size) * 2 / ch;
nb_samples -= nb_samples % 28;
+ *approx_nb_samples = 1;
break;
case AV_CODEC_ID_ADPCM_IMA_DK3:
if (avctx->block_align > 0)
@@ -525,11 +580,20 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
buf_size = FFMIN(buf_size, avctx->block_align);
nb_samples = 1 + (buf_size - 4 * ch) * 2 / ch;
break;
+ case AV_CODEC_ID_ADPCM_IMA_RAD:
+ if (avctx->block_align > 0)
+ buf_size = FFMIN(buf_size, avctx->block_align);
+ nb_samples = (buf_size - 4 * ch) * 2 / ch;
+ break;
case AV_CODEC_ID_ADPCM_IMA_WAV:
+ {
+ int bsize = ff_adpcm_ima_block_sizes[avctx->bits_per_coded_sample - 2];
+ int bsamples = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2];
if (avctx->block_align > 0)
buf_size = FFMIN(buf_size, avctx->block_align);
- nb_samples = 1 + (buf_size - 4 * ch) / (4 * ch) * 8;
+ nb_samples = 1 + (buf_size - 4 * ch) / (bsize * ch) * bsamples;
break;
+ }
case AV_CODEC_ID_ADPCM_MS:
if (avctx->block_align > 0)
buf_size = FFMIN(buf_size, avctx->block_align);
@@ -566,15 +630,25 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
break;
}
case AV_CODEC_ID_ADPCM_THP:
+ if (avctx->extradata) {
+ nb_samples = buf_size / (8 * ch) * 14;
+ break;
+ }
has_coded_samples = 1;
bytestream2_skip(gb, 4); // channel size
*coded_samples = bytestream2_get_be32(gb);
*coded_samples -= *coded_samples % 14;
- nb_samples = (buf_size - 80) / (8 * ch) * 14;
+ nb_samples = (buf_size - (8 + 36 * ch)) / (8 * ch) * 14;
+ break;
+ case AV_CODEC_ID_ADPCM_AFC:
+ nb_samples = buf_size / (9 * ch) * 16;
break;
case AV_CODEC_ID_ADPCM_XA:
nb_samples = (buf_size / 128) * 224 / ch;
break;
+ case AV_CODEC_ID_ADPCM_DTK:
+ nb_samples = buf_size / (16 * ch) * 28;
+ break;
}
/* validate coded sample count */
@@ -597,11 +671,11 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
int16_t **samples_p;
int st; /* stereo */
int count1, count2;
- int nb_samples, coded_samples, ret;
+ int nb_samples, coded_samples, approx_nb_samples, ret;
GetByteContext gb;
bytestream2_init(&gb, buf, buf_size);
- nb_samples = get_nb_samples(avctx, &gb, buf_size, &coded_samples);
+ nb_samples = get_nb_samples(avctx, &gb, buf_size, &coded_samples, &approx_nb_samples);
if (nb_samples <= 0) {
av_log(avctx, AV_LOG_ERROR, "invalid number of samples in packet\n");
return AVERROR_INVALIDDATA;
@@ -609,17 +683,15 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = nb_samples;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (short *)frame->data[0];
samples_p = (int16_t **)frame->extended_data;
/* use coded_samples when applicable */
/* it is always <= nb_samples, so the output buffer will be large enough */
if (coded_samples) {
- if (coded_samples != nb_samples)
+ if (!approx_nb_samples && coded_samples != nb_samples)
av_log(avctx, AV_LOG_WARNING, "mismatch in coded sample count\n");
frame->nb_samples = nb_samples = coded_samples;
}
@@ -681,6 +753,23 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
}
+ if (avctx->bits_per_coded_sample != 4) {
+ int samples_per_block = ff_adpcm_ima_block_samples[avctx->bits_per_coded_sample - 2];
+ GetBitContext g;
+
+ init_get_bits8(&g, gb.buffer, bytestream2_get_bytes_left(&gb));
+ for (n = 0; n < (nb_samples - 1) / samples_per_block; n++) {
+ for (i = 0; i < avctx->channels; i++) {
+ cs = &c->status[i];
+ samples = &samples_p[i][1 + n * samples_per_block];
+ for (m = 0; m < samples_per_block; m++) {
+ samples[m] = adpcm_ima_wav_expand_nibble(cs, &g,
+ avctx->bits_per_coded_sample);
+ }
+ }
+ }
+ bytestream2_skip(&gb, avctx->block_align - avctx->channels * 4);
+ } else {
for (n = 0; n < (nb_samples - 1) / 8; n++) {
for (i = 0; i < avctx->channels; i++) {
cs = &c->status[i];
@@ -692,6 +781,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
}
}
+ }
break;
case AV_CODEC_ID_ADPCM_4XM:
for (i = 0; i < avctx->channels; i++)
@@ -770,7 +860,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
}
- for (n = (nb_samples >> (1 - st)) - 1; n > 0; n--) {
+ for (n = (nb_samples - 1) >> (1 - st); n > 0; n--) {
int v = bytestream2_get_byteu(&gb);
*samples++ = adpcm_ima_expand_nibble(&c->status[0 ], v >> 4 , 3);
*samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
@@ -835,6 +925,9 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
*samples++ = c->status[0].predictor + c->status[1].predictor;
*samples++ = c->status[0].predictor - c->status[1].predictor;
}
+
+ if ((bytestream2_tell(&gb) & 1))
+ bytestream2_skip(&gb, 1);
break;
}
case AV_CODEC_ID_ADPCM_IMA_ISS:
@@ -871,6 +964,38 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
*samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
}
break;
+ case AV_CODEC_ID_ADPCM_IMA_OKI:
+ while (bytestream2_get_bytes_left(&gb) > 0) {
+ int v = bytestream2_get_byteu(&gb);
+ *samples++ = adpcm_ima_oki_expand_nibble(&c->status[0], v >> 4 );
+ *samples++ = adpcm_ima_oki_expand_nibble(&c->status[st], v & 0x0F);
+ }
+ break;
+ case AV_CODEC_ID_ADPCM_IMA_RAD:
+ for (channel = 0; channel < avctx->channels; channel++) {
+ cs = &c->status[channel];
+ cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16);
+ cs->predictor = sign_extend(bytestream2_get_le16u(&gb), 16);
+ if (cs->step_index > 88u){
+ av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n",
+ channel, cs->step_index);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ for (n = 0; n < nb_samples / 2; n++) {
+ int byte[2];
+
+ byte[0] = bytestream2_get_byteu(&gb);
+ if (st)
+ byte[1] = bytestream2_get_byteu(&gb);
+ for(channel = 0; channel < avctx->channels; channel++) {
+ *samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] & 0x0F, 3);
+ }
+ for(channel = 0; channel < avctx->channels; channel++) {
+ *samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] >> 4 , 3);
+ }
+ }
+ break;
case AV_CODEC_ID_ADPCM_IMA_WS:
if (c->vqa_version == 3) {
for (channel = 0; channel < avctx->channels; channel++) {
@@ -946,6 +1071,9 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
/* Each EA ADPCM frame has a 12-byte header followed by 30-byte pieces,
each coding 28 stereo samples. */
+ if(avctx->channels != 2)
+ return AVERROR_INVALIDDATA;
+
current_left_sample = sign_extend(bytestream2_get_le16u(&gb), 16);
previous_left_sample = sign_extend(bytestream2_get_le16u(&gb), 16);
current_right_sample = sign_extend(bytestream2_get_le16u(&gb), 16);
@@ -1131,16 +1259,9 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
break;
case AV_CODEC_ID_ADPCM_IMA_AMV:
- case AV_CODEC_ID_ADPCM_IMA_SMJPEG:
- if (avctx->codec->id == AV_CODEC_ID_ADPCM_IMA_AMV) {
- c->status[0].predictor = sign_extend(bytestream2_get_le16u(&gb), 16);
- c->status[0].step_index = bytestream2_get_le16u(&gb);
- bytestream2_skipu(&gb, 4);
- } else {
- c->status[0].predictor = sign_extend(bytestream2_get_be16u(&gb), 16);
- c->status[0].step_index = bytestream2_get_byteu(&gb);
- bytestream2_skipu(&gb, 1);
- }
+ c->status[0].predictor = sign_extend(bytestream2_get_le16u(&gb), 16);
+ c->status[0].step_index = bytestream2_get_le16u(&gb);
+ bytestream2_skipu(&gb, 4);
if (c->status[0].step_index > 88u) {
av_log(avctx, AV_LOG_ERROR, "ERROR: step_index = %i\n",
c->status[0].step_index);
@@ -1148,18 +1269,29 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
for (n = nb_samples >> (1 - st); n > 0; n--) {
- int hi, lo, v = bytestream2_get_byteu(&gb);
+ int v = bytestream2_get_byteu(&gb);
- if (avctx->codec->id == AV_CODEC_ID_ADPCM_IMA_AMV) {
- hi = v & 0x0F;
- lo = v >> 4;
- } else {
- lo = v & 0x0F;
- hi = v >> 4;
+ *samples++ = adpcm_ima_expand_nibble(&c->status[0], v >> 4, 3);
+ *samples++ = adpcm_ima_expand_nibble(&c->status[0], v & 0xf, 3);
+ }
+ break;
+ case AV_CODEC_ID_ADPCM_IMA_SMJPEG:
+ for (i = 0; i < avctx->channels; i++) {
+ c->status[i].predictor = sign_extend(bytestream2_get_be16u(&gb), 16);
+ c->status[i].step_index = bytestream2_get_byteu(&gb);
+ bytestream2_skipu(&gb, 1);
+ if (c->status[i].step_index > 88u) {
+ av_log(avctx, AV_LOG_ERROR, "ERROR: step_index = %i\n",
+ c->status[i].step_index);
+ return AVERROR_INVALIDDATA;
}
+ }
+
+ for (n = nb_samples >> (1 - st); n > 0; n--) {
+ int v = bytestream2_get_byteu(&gb);
- *samples++ = adpcm_ima_expand_nibble(&c->status[0], lo, 3);
- *samples++ = adpcm_ima_expand_nibble(&c->status[0], hi, 3);
+ *samples++ = adpcm_ima_qt_expand_nibble(&c->status[0 ], v >> 4, 3);
+ *samples++ = adpcm_ima_qt_expand_nibble(&c->status[st], v & 0xf, 3);
}
break;
case AV_CODEC_ID_ADPCM_CT:
@@ -1189,7 +1321,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
byte & 0x0F, 4, 0);
}
} else if (avctx->codec->id == AV_CODEC_ID_ADPCM_SBPRO_3) {
- for (n = nb_samples / 3; n > 0; n--) {
+ for (n = (nb_samples<<st) / 3; n > 0; n--) {
int byte = bytestream2_get_byteu(&gb);
*samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
byte >> 5 , 3, 0);
@@ -1223,22 +1355,88 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
*samples++ = adpcm_yamaha_expand_nibble(&c->status[st], v >> 4 );
}
break;
+ case AV_CODEC_ID_ADPCM_AFC:
+ {
+ int samples_per_block;
+ int blocks;
+
+ if (avctx->extradata && avctx->extradata_size == 1 && avctx->extradata[0]) {
+ samples_per_block = avctx->extradata[0] / 16;
+ blocks = nb_samples / avctx->extradata[0];
+ } else {
+ samples_per_block = nb_samples / 16;
+ blocks = 1;
+ }
+
+ for (m = 0; m < blocks; m++) {
+ for (channel = 0; channel < avctx->channels; channel++) {
+ int prev1 = c->status[channel].sample1;
+ int prev2 = c->status[channel].sample2;
+
+ samples = samples_p[channel] + m * 16;
+ /* Read in every sample for this channel. */
+ for (i = 0; i < samples_per_block; i++) {
+ int byte = bytestream2_get_byteu(&gb);
+ int scale = 1 << (byte >> 4);
+ int index = byte & 0xf;
+ int factor1 = ff_adpcm_afc_coeffs[0][index];
+ int factor2 = ff_adpcm_afc_coeffs[1][index];
+
+ /* Decode 16 samples. */
+ for (n = 0; n < 16; n++) {
+ int32_t sampledat;
+
+ if (n & 1) {
+ sampledat = sign_extend(byte, 4);
+ } else {
+ byte = bytestream2_get_byteu(&gb);
+ sampledat = sign_extend(byte >> 4, 4);
+ }
+
+ sampledat = ((prev1 * factor1 + prev2 * factor2) +
+ ((sampledat * scale) << 11)) >> 11;
+ *samples = av_clip_int16(sampledat);
+ prev2 = prev1;
+ prev1 = *samples++;
+ }
+ }
+
+ c->status[channel].sample1 = prev1;
+ c->status[channel].sample2 = prev2;
+ }
+ }
+ bytestream2_seek(&gb, 0, SEEK_END);
+ break;
+ }
case AV_CODEC_ID_ADPCM_THP:
{
- int table[2][16];
- int prev[2][2];
+ int table[6][16];
int ch;
- for (i = 0; i < 2; i++)
+ if (avctx->extradata) {
+ GetByteContext tb;
+ if (avctx->extradata_size < 32 * avctx->channels) {
+ av_log(avctx, AV_LOG_ERROR, "Missing coeff table\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ bytestream2_init(&tb, avctx->extradata, avctx->extradata_size);
+ for (i = 0; i < avctx->channels; i++)
+ for (n = 0; n < 16; n++)
+ table[i][n] = sign_extend(bytestream2_get_be16u(&tb), 16);
+ } else {
+ for (i = 0; i < avctx->channels; i++)
for (n = 0; n < 16; n++)
table[i][n] = sign_extend(bytestream2_get_be16u(&gb), 16);
/* Initialize the previous sample. */
- for (i = 0; i < 2; i++)
- for (n = 0; n < 2; n++)
- prev[i][n] = sign_extend(bytestream2_get_be16u(&gb), 16);
+ for (i = 0; i < avctx->channels; i++) {
+ c->status[i].sample1 = sign_extend(bytestream2_get_be16u(&gb), 16);
+ c->status[i].sample2 = sign_extend(bytestream2_get_be16u(&gb), 16);
+ }
+ }
- for (ch = 0; ch <= st; ch++) {
+ for (ch = 0; ch < avctx->channels; ch++) {
samples = samples_p[ch];
/* Read in every sample for this channel. */
@@ -1260,21 +1458,74 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
sampledat = sign_extend(byte >> 4, 4);
}
- sampledat = ((prev[ch][0]*factor1
- + prev[ch][1]*factor2) >> 11) + (sampledat << exp);
+ sampledat = ((c->status[ch].sample1 * factor1
+ + c->status[ch].sample2 * factor2) >> 11) + (sampledat << exp);
*samples = av_clip_int16(sampledat);
- prev[ch][1] = prev[ch][0];
- prev[ch][0] = *samples++;
+ c->status[ch].sample2 = c->status[ch].sample1;
+ c->status[ch].sample1 = *samples++;
}
}
}
break;
}
+ case AV_CODEC_ID_ADPCM_DTK:
+ for (channel = 0; channel < avctx->channels; channel++) {
+ samples = samples_p[channel];
+
+ /* Read in every sample for this channel. */
+ for (i = 0; i < nb_samples / 28; i++) {
+ int byte, header;
+ if (channel)
+ bytestream2_skipu(&gb, 1);
+ header = bytestream2_get_byteu(&gb);
+ bytestream2_skipu(&gb, 3 - channel);
+
+ /* Decode 28 samples. */
+ for (n = 0; n < 28; n++) {
+ int32_t sampledat, prev;
+
+ switch (header >> 4) {
+ case 1:
+ prev = (c->status[channel].sample1 * 0x3c);
+ break;
+ case 2:
+ prev = (c->status[channel].sample1 * 0x73) - (c->status[channel].sample2 * 0x34);
+ break;
+ case 3:
+ prev = (c->status[channel].sample1 * 0x62) - (c->status[channel].sample2 * 0x37);
+ break;
+ default:
+ prev = 0;
+ }
+
+ prev = av_clip_intp2((prev + 0x20) >> 6, 21);
+
+ byte = bytestream2_get_byteu(&gb);
+ if (!channel)
+ sampledat = sign_extend(byte, 4);
+ else
+ sampledat = sign_extend(byte >> 4, 4);
+
+ sampledat = (((sampledat << 12) >> (header & 0xf)) << 6) + prev;
+ *samples++ = av_clip_int16(sampledat >> 6);
+ c->status[channel].sample2 = c->status[channel].sample1;
+ c->status[channel].sample1 = sampledat;
+ }
+ }
+ if (!channel)
+ bytestream2_seek(&gb, 0, SEEK_SET);
+ }
+ break;
default:
return -1;
}
+ if (avpkt->size && bytestream2_tell(&gb) == 0) {
+ av_log(avctx, AV_LOG_ERROR, "Nothing consumed\n");
+ return AVERROR_INVALIDDATA;
+ }
+
*got_frame_ptr = 1;
return bytestream2_tell(&gb);
@@ -1283,7 +1534,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
static const enum AVSampleFormat sample_fmts_s16[] = { AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE };
-static const enum AVSampleFormat sample_fmts_s16p[] = { AV_SAMPLE_FMT_S16,
+static const enum AVSampleFormat sample_fmts_s16p[] = { AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_NONE };
static const enum AVSampleFormat sample_fmts_both[] = { AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_S16P,
@@ -1304,7 +1555,9 @@ AVCodec ff_ ## name_ ## _decoder = { \
/* Note: Do not forget to add new entries to the Makefile as well. */
ADPCM_DECODER(AV_CODEC_ID_ADPCM_4XM, sample_fmts_s16p, adpcm_4xm, "ADPCM 4X Movie");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_MAXIS_XA, sample_fmts_s16, adpcm_ea_maxis_xa, "ADPCM Electronic Arts Maxis CDROM XA");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_R1, sample_fmts_s16p, adpcm_ea_r1, "ADPCM Electronic Arts R1");
@@ -1318,7 +1571,9 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_DK4, sample_fmts_s16, adpcm_ima_dk4,
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_EACS, sample_fmts_s16, adpcm_ima_ea_eacs, "ADPCM IMA Electronic Arts EACS");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_SEAD, sample_fmts_s16, adpcm_ima_ea_sead, "ADPCM IMA Electronic Arts SEAD");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_ISS, sample_fmts_s16, adpcm_ima_iss, "ADPCM IMA Funcom ISS");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_OKI, sample_fmts_s16, adpcm_ima_oki, "ADPCM IMA Dialogic OKI");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_QT, sample_fmts_s16p, adpcm_ima_qt, "ADPCM IMA QuickTime");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_RAD, sample_fmts_s16, adpcm_ima_rad, "ADPCM IMA Radical");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_SMJPEG, sample_fmts_s16, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WAV, sample_fmts_s16p, adpcm_ima_wav, "ADPCM IMA WAV");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA Westwood");
diff --git a/libavcodec/adpcm.h b/libavcodec/adpcm.h
index 16facb6d0f..fcbb70b3ca 100644
--- a/libavcodec/adpcm.h
+++ b/libavcodec/adpcm.h
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2001-2003 The ffmpeg Project
+ * Copyright (c) 2001-2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,8 +38,8 @@ typedef struct ADPCMChannelStatus {
int prev_sample;
/* MS version */
- int16_t sample1;
- int16_t sample2;
+ int sample1;
+ int sample2;
int coeff1;
int coeff2;
int idelta;
diff --git a/libavcodec/adpcm_data.c b/libavcodec/adpcm_data.c
index 3bc5de23b3..9c38360a91 100644
--- a/libavcodec/adpcm_data.c
+++ b/libavcodec/adpcm_data.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2001-2003 The ffmpeg Project
+ * Copyright (c) 2001-2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,12 +27,33 @@
/* ff_adpcm_step_table[] and ff_adpcm_index_table[] are from the ADPCM
reference source */
-/* This is the index table: */
+static const int8_t adpcm_index_table2[4] = {
+ -1, 2,
+ -1, 2,
+};
+
+static const int8_t adpcm_index_table3[8] = {
+ -1, -1, 1, 2,
+ -1, -1, 1, 2,
+};
+
const int8_t ff_adpcm_index_table[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8,
};
+static const int8_t adpcm_index_table5[32] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16,
+ -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16,
+};
+
+const int8_t * const ff_adpcm_index_tables[4] = {
+ &adpcm_index_table2[0],
+ &adpcm_index_table3[0],
+ &ff_adpcm_index_table[0],
+ &adpcm_index_table5[0],
+};
+
/**
* This is the step table. Note that many programs use slight deviations from
* this table, but such deviations are negligible:
@@ -49,6 +70,14 @@ const int16_t ff_adpcm_step_table[89] = {
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
+const int16_t ff_adpcm_oki_step_table[49] = {
+ 16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
+ 41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
+ 107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
+ 279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
+ 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
+};
+
/* These are for MS-ADPCM */
/* ff_adpcm_AdaptationTable[], ff_adpcm_AdaptCoeff1[], and
ff_adpcm_AdaptCoeff2[] are from libsndfile */
@@ -76,3 +105,8 @@ const int8_t ff_adpcm_yamaha_difflookup[] = {
1, 3, 5, 7, 9, 11, 13, 15,
-1, -3, -5, -7, -9, -11, -13, -15
};
+
+const int16_t ff_adpcm_afc_coeffs[2][16] = {
+ { 0, 2048, 0, 1024, 4096, 3584, 3072, 4608, 4200, 4800, 5120, 2048, 1024, 64512, 64512, 63488 },
+ { 0, 0, 2048, 1024, 63488, 64000, 64512, 62976, 63288, 63236, 62464, 63488, 64512, 1024, 0, 0 }
+};
diff --git a/libavcodec/adpcm_data.h b/libavcodec/adpcm_data.h
index a46cb5bdec..b179d65f7a 100644
--- a/libavcodec/adpcm_data.h
+++ b/libavcodec/adpcm_data.h
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2001-2003 The ffmpeg Project
+ * Copyright (c) 2001-2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,12 +28,18 @@
#include <stdint.h>
+static const uint8_t ff_adpcm_ima_block_sizes[4] = { 4, 12, 4, 20 };
+static const uint8_t ff_adpcm_ima_block_samples[4] = { 16, 32, 8, 32 };
+
+extern const int8_t * const ff_adpcm_index_tables[4];
extern const int8_t ff_adpcm_index_table[16];
extern const int16_t ff_adpcm_step_table[89];
+extern const int16_t ff_adpcm_oki_step_table[49];
extern const int16_t ff_adpcm_AdaptationTable[];
extern const uint8_t ff_adpcm_AdaptCoeff1[];
extern const int8_t ff_adpcm_AdaptCoeff2[];
extern const int16_t ff_adpcm_yamaha_indexscale[];
extern const int8_t ff_adpcm_yamaha_difflookup[];
+extern const int16_t ff_adpcm_afc_coeffs[2][16];
#endif /* AVCODEC_ADPCM_DATA_H */
diff --git a/libavcodec/adpcmenc.c b/libavcodec/adpcmenc.c
index 341dda475a..50872c3e46 100644
--- a/libavcodec/adpcmenc.c
+++ b/libavcodec/adpcmenc.c
@@ -1,29 +1,28 @@
/*
- * Copyright (c) 2001-2003 The ffmpeg Project
+ * Copyright (c) 2001-2003 The FFmpeg Project
*
* first version by Francois Revol (revol@free.fr)
* fringe ADPCM codecs (e.g., DK3, DK4, Westwood)
* by Mike Melanson (melanson@pcisys.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
-#include "get_bits.h"
#include "put_bits.h"
#include "bytestream.h"
#include "adpcm.h"
@@ -59,6 +58,8 @@ typedef struct ADPCMEncodeContext {
#define FREEZE_INTERVAL 128
+static av_cold int adpcm_encode_close(AVCodecContext *avctx);
+
static av_cold int adpcm_encode_init(AVCodecContext *avctx)
{
ADPCMEncodeContext *s = avctx->priv_data;
@@ -100,6 +101,7 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx)
/* seems frame_size isn't taken into account...
have to buffer the samples :-( */
avctx->block_align = BLKSIZE;
+ avctx->bits_per_coded_sample = 4;
break;
case AV_CODEC_ID_ADPCM_IMA_QT:
avctx->frame_size = 64;
@@ -108,8 +110,8 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx)
case AV_CODEC_ID_ADPCM_MS:
/* each 16 bits sample gives one nibble
and we have 7 bytes per channel overhead */
- avctx->frame_size = (BLKSIZE - 7 * avctx->channels) * 2 /
- avctx->channels + 2;
+ avctx->frame_size = (BLKSIZE - 7 * avctx->channels) * 2 / avctx->channels + 2;
+ avctx->bits_per_coded_sample = 4;
avctx->block_align = BLKSIZE;
if (!(avctx->extradata = av_malloc(32 + FF_INPUT_BUFFER_PADDING_SIZE)))
goto error;
@@ -144,10 +146,7 @@ static av_cold int adpcm_encode_init(AVCodecContext *avctx)
return 0;
error:
- av_freep(&s->paths);
- av_freep(&s->node_buf);
- av_freep(&s->nodep_buf);
- av_freep(&s->trellis_hash);
+ adpcm_encode_close(avctx);
return ret;
}
@@ -180,24 +179,27 @@ static inline uint8_t adpcm_ima_qt_compress_sample(ADPCMChannelStatus *c,
int16_t sample)
{
int delta = sample - c->prev_sample;
- int mask, step = ff_adpcm_step_table[c->step_index];
- int diff = step >> 3;
- int nibble = 0;
+ int diff, step = ff_adpcm_step_table[c->step_index];
+ int nibble = 8*(delta < 0);
- if (delta < 0) {
- nibble = 8;
- delta = -delta;
- }
+ delta= abs(delta);
+ diff = delta + (step >> 3);
- for (mask = 4; mask;) {
- if (delta >= step) {
- nibble |= mask;
- delta -= step;
- diff += step;
- }
- step >>= 1;
- mask >>= 1;
+ if (delta >= step) {
+ nibble |= 4;
+ delta -= step;
+ }
+ step >>= 1;
+ if (delta >= step) {
+ nibble |= 2;
+ delta -= step;
}
+ step >>= 1;
+ if (delta >= step) {
+ nibble |= 1;
+ delta -= step;
+ }
+ diff -= delta;
if (nibble & 8)
c->prev_sample -= diff;
@@ -225,7 +227,7 @@ static inline uint8_t adpcm_ms_compress_sample(ADPCMChannelStatus *c,
bias = -c->idelta / 2;
nibble = (nibble + bias) / c->idelta;
- nibble = av_clip(nibble, -8, 7) & 0x0F;
+ nibble = av_clip_intp2(nibble, 3) & 0x0F;
predictor += ((nibble & 0x08) ? (nibble - 0x10) : nibble) * c->idelta;
@@ -330,7 +332,7 @@ static void adpcm_compress_trellis(AVCodecContext *avctx,
uint8_t *h;\
dec_sample = av_clip_int16(dec_sample);\
d = sample - dec_sample;\
- ssd = nodes[j]->ssd + d*d;\
+ ssd = nodes[j]->ssd + d*(unsigned)d;\
/* Check for wraparound, skip such samples completely. \
* Note, changing ssd to a 64 bit variable would be \
* simpler, avoiding this check, but it's slower on \
@@ -365,7 +367,7 @@ static void adpcm_compress_trellis(AVCodecContext *avctx,
*h = generation;\
u = nodes_next[pos];\
if (!u) {\
- assert(pathn < FREEZE_INTERVAL << avctx->trellis);\
+ av_assert1(pathn < FREEZE_INTERVAL << avctx->trellis);\
u = t++;\
nodes_next[pos] = u;\
u->path = pathn++;\
@@ -484,10 +486,8 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
pkt_size = (2 + avctx->channels * (22 + 4 * (frame->nb_samples - 1)) + 7) / 8;
else
pkt_size = avctx->block_align;
- if ((ret = ff_alloc_packet(avpkt, pkt_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, pkt_size)) < 0)
return ret;
- }
dst = avpkt->data;
switch(avctx->codec->id) {
@@ -509,7 +509,7 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
/* stereo: 4 bytes (8 samples) for left, 4 bytes for right */
if (avctx->trellis > 0) {
- FF_ALLOC_OR_GOTO(avctx, buf, avctx->channels * blocks * 8, error);
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, buf, avctx->channels, blocks * 8, error);
for (ch = 0; ch < avctx->channels; ch++) {
adpcm_compress_trellis(avctx, &samples_p[ch][1],
buf + ch * blocks * 8, &c->status[ch],
@@ -541,7 +541,7 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
case AV_CODEC_ID_ADPCM_IMA_QT:
{
PutBitContext pb;
- init_put_bits(&pb, dst, pkt_size * 8);
+ init_put_bits(&pb, dst, pkt_size);
for (ch = 0; ch < avctx->channels; ch++) {
ADPCMChannelStatus *status = &c->status[ch];
@@ -571,7 +571,7 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
case AV_CODEC_ID_ADPCM_SWF:
{
PutBitContext pb;
- init_put_bits(&pb, dst, pkt_size * 8);
+ init_put_bits(&pb, dst, pkt_size);
n = frame->nb_samples - 1;
@@ -581,7 +581,7 @@ static int adpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
// init the encoder state
for (i = 0; i < avctx->channels; i++) {
// clip step so it fits 6 bits
- c->status[i].step_index = av_clip(c->status[i].step_index, 0, 63);
+ c->status[i].step_index = av_clip_uintp2(c->status[i].step_index, 6);
put_sbits(&pb, 16, samples[i]);
put_bits(&pb, 6, c->status[i].step_index);
c->status[i].prev_sample = samples[i];
diff --git a/libavcodec/adx.c b/libavcodec/adx.c
index d941d7b89c..cd88b16660 100644
--- a/libavcodec/adx.c
+++ b/libavcodec/adx.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/adx.h b/libavcodec/adx.h
index 9ae84dcec1..08f749a046 100644
--- a/libavcodec/adx.h
+++ b/libavcodec/adx.h
@@ -2,20 +2,20 @@
* ADX ADPCM codecs
* Copyright (c) 2001,2003 BERO
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/adx_parser.c b/libavcodec/adx_parser.c
index 706e242c82..1fa718f694 100644
--- a/libavcodec/adx_parser.c
+++ b/libavcodec/adx_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/adxdec.c b/libavcodec/adxdec.c
index 14fddf5520..5115cede6a 100644
--- a/libavcodec/adxdec.c
+++ b/libavcodec/adxdec.c
@@ -2,20 +2,20 @@
* ADX ADPCM codecs
* Copyright (c) 2001,2003 BERO
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -101,6 +101,7 @@ static int adx_decode_frame(AVCodecContext *avctx, void *data,
int16_t **samples;
int samples_offset;
const uint8_t *buf = avpkt->data;
+ const uint8_t *buf_end = buf + avpkt->size;
int num_blocks, ch, ret;
if (c->eof) {
@@ -141,16 +142,14 @@ static int adx_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = num_blocks * BLOCK_SAMPLES;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t **)frame->extended_data;
samples_offset = 0;
while (num_blocks--) {
for (ch = 0; ch < c->channels; ch++) {
- if (adx_decode(c, samples[ch], samples_offset, buf, ch)) {
+ if (buf_end - buf < BLOCK_SIZE || adx_decode(c, samples[ch], samples_offset, buf, ch)) {
c->eof = 1;
buf = avpkt->data + avpkt->size;
break;
@@ -158,9 +157,11 @@ static int adx_decode_frame(AVCodecContext *avctx, void *data,
buf_size -= BLOCK_SIZE;
buf += BLOCK_SIZE;
}
- samples_offset += BLOCK_SAMPLES;
+ if (!c->eof)
+ samples_offset += BLOCK_SAMPLES;
}
+ frame->nb_samples = samples_offset;
*got_frame_ptr = 1;
return buf - avpkt->data;
diff --git a/libavcodec/adxenc.c b/libavcodec/adxenc.c
index e730811744..7736d09b56 100644
--- a/libavcodec/adxenc.c
+++ b/libavcodec/adxenc.c
@@ -2,20 +2,20 @@
* ADX ADPCM codecs
* Copyright (c) 2001,2003 BERO
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,14 +43,12 @@ static void adx_encode(ADXContext *c, uint8_t *adx, const int16_t *wav,
int s0, s1, s2, d;
int max = 0;
int min = 0;
- int data[BLOCK_SAMPLES];
s1 = prev->s1;
s2 = prev->s2;
for (i = 0, j = 0; j < 32; i += channels, j++) {
s0 = wav[i];
d = ((s0 << COEFF_BITS) - c->coeff[0] * s1 - c->coeff[1] * s2) >> COEFF_BITS;
- data[j] = d;
if (max < d)
max = d;
if (min > d)
@@ -58,10 +56,10 @@ static void adx_encode(ADXContext *c, uint8_t *adx, const int16_t *wav,
s2 = s1;
s1 = s0;
}
- prev->s1 = s1;
- prev->s2 = s2;
if (max == 0 && min == 0) {
+ prev->s1 = s1;
+ prev->s2 = s2;
memset(adx, 0, BLOCK_SIZE);
return;
}
@@ -77,8 +75,23 @@ static void adx_encode(ADXContext *c, uint8_t *adx, const int16_t *wav,
AV_WB16(adx, scale);
init_put_bits(&pb, adx + 2, 16);
- for (i = 0; i < BLOCK_SAMPLES; i++)
- put_sbits(&pb, 4, av_clip(data[i] / scale, -8, 7));
+
+ s1 = prev->s1;
+ s2 = prev->s2;
+ for (i = 0, j = 0; j < 32; i += channels, j++) {
+ d = ((wav[i] << COEFF_BITS) - c->coeff[0] * s1 - c->coeff[1] * s2) >> COEFF_BITS;
+
+ d = av_clip_intp2(ROUNDED_DIV(d, scale), 3);
+
+ put_sbits(&pb, 4, d);
+
+ s0 = ((d << COEFF_BITS) * scale + c->coeff[0] * s1 + c->coeff[1] * s2) >> COEFF_BITS;
+ s2 = s1;
+ s1 = s0;
+ }
+ prev->s1 = s1;
+ prev->s2 = s2;
+
flush_put_bits(&pb);
}
@@ -133,10 +146,8 @@ static int adx_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
int ch, out_size, ret;
out_size = BLOCK_SIZE * avctx->channels + !c->header_parsed * HEADER_SIZE;
- if ((ret = ff_alloc_packet(avpkt, out_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, out_size)) < 0)
return ret;
- }
dst = avpkt->data;
if (!c->header_parsed) {
diff --git a/libavcodec/aic.c b/libavcodec/aic.c
index 5687dbeb00..648ccba52c 100644
--- a/libavcodec/aic.c
+++ b/libavcodec/aic.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2013 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -132,7 +132,7 @@ static const uint8_t aic_c_ext_scan[192] = {
177, 184, 176, 169, 162, 161, 168, 160,
};
-static const uint8_t *aic_scan[NUM_BANDS] = {
+static const uint8_t * const aic_scan[NUM_BANDS] = {
aic_y_scan, aic_c_scan, aic_y_ext_scan, aic_c_ext_scan
};
@@ -152,6 +152,7 @@ typedef struct AICContext {
int16_t *data_ptr[NUM_BANDS];
DECLARE_ALIGNED(16, int16_t, block)[64];
+ DECLARE_ALIGNED(16, uint8_t, quant_matrix)[64];
} AICContext;
static int aic_decode_header(AICContext *ctx, const uint8_t *src, int size)
@@ -203,7 +204,8 @@ static int aic_decode_coeffs(GetBitContext *gb, int16_t *dst,
int has_skips, coeff_type, coeff_bits, skip_type, skip_bits;
const int num_coeffs = aic_num_band_coeffs[band];
const uint8_t *scan = aic_scan[band | force_chroma];
- int mb, idx, val;
+ int mb, idx;
+ unsigned val;
has_skips = get_bits1(gb);
coeff_type = get_bits1(gb);
@@ -217,14 +219,14 @@ static int aic_decode_coeffs(GetBitContext *gb, int16_t *dst,
idx = -1;
do {
GET_CODE(val, skip_type, skip_bits);
- if (val < 0)
+ if (val >= 0x10000)
return AVERROR_INVALIDDATA;
idx += val + 1;
if (idx >= num_coeffs)
break;
GET_CODE(val, coeff_type, coeff_bits);
val++;
- if (val >= 0x10000 || val < 0)
+ if (val >= 0x10000)
return AVERROR_INVALIDDATA;
dst[scan[idx]] = val;
} while (idx < num_coeffs - 1);
@@ -234,7 +236,7 @@ static int aic_decode_coeffs(GetBitContext *gb, int16_t *dst,
for (mb = 0; mb < slice_width; mb++) {
for (idx = 0; idx < num_coeffs; idx++) {
GET_CODE(val, coeff_type, coeff_bits);
- if (val >= 0x10000 || val < 0)
+ if (val >= 0x10000)
return AVERROR_INVALIDDATA;
dst[scan[idx]] = val;
}
@@ -286,7 +288,7 @@ static void recombine_block_il(int16_t *dst, const uint8_t *scan,
}
}
-static void unquant_block(int16_t *block, int q)
+static void unquant_block(int16_t *block, int q, uint8_t *quant_matrix)
{
int i;
@@ -294,7 +296,7 @@ static void unquant_block(int16_t *block, int q)
int val = (uint16_t)block[i];
int sign = val & 1;
- block[i] = (((val >> 1) ^ -sign) * q * aic_quant_matrix[i] >> 4)
+ block[i] = (((val >> 1) ^ -sign) * q * quant_matrix[i] >> 4)
+ sign;
}
}
@@ -335,7 +337,7 @@ static int aic_decode_slice(AICContext *ctx, int mb_x, int mb_y,
else
recombine_block_il(ctx->block, ctx->scantable.permutated,
&base_y, &ext_y, blk);
- unquant_block(ctx->block, ctx->quant);
+ unquant_block(ctx->block, ctx->quant, ctx->quant_matrix);
ctx->idsp.idct(ctx->block);
if (!ctx->interlaced) {
@@ -352,7 +354,7 @@ static int aic_decode_slice(AICContext *ctx, int mb_x, int mb_y,
for (blk = 0; blk < 2; blk++) {
recombine_block(ctx->block, ctx->scantable.permutated,
&base_c, &ext_c);
- unquant_block(ctx->block, ctx->quant);
+ unquant_block(ctx->block, ctx->quant, ctx->quant_matrix);
ctx->idsp.idct(ctx->block);
ctx->idsp.put_signed_pixels_clamped(ctx->block, C[blk],
ctx->frame->linesize[blk + 1]);
@@ -430,6 +432,8 @@ static av_cold int aic_decode_init(AVCodecContext *avctx)
for (i = 0; i < 64; i++)
scan[i] = i;
ff_init_scantable(ctx->idsp.idct_permutation, &ctx->scantable, scan);
+ for (i = 0; i < 64; i++)
+ ctx->quant_matrix[ctx->idsp.idct_permutation[i]] = aic_quant_matrix[i];
ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
@@ -444,7 +448,7 @@ static av_cold int aic_decode_init(AVCodecContext *avctx)
}
}
- ctx->slice_data = av_malloc(ctx->slice_width * AIC_BAND_COEFFS
+ ctx->slice_data = av_malloc_array(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 9579e18185..b0527f1439 100644
--- a/libavcodec/alac.c
+++ b/libavcodec/alac.c
@@ -2,20 +2,20 @@
* ALAC (Apple Lossless Audio Codec) decoder
* Copyright (c) 2005 David Hammerton
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,8 +36,8 @@
* 8bit compatible version (0)
* 8bit sample size
* 8bit history mult (40)
- * 8bit initial history (14)
- * 8bit rice param limit (10)
+ * 8bit initial history (10)
+ * 8bit rice param limit (14)
* 8bit channels
* 16bit maxRun (255)
* 32bit max coded frame size (0 means unknown)
@@ -48,10 +48,12 @@
#include <inttypes.h>
#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "get_bits.h"
#include "bytestream.h"
#include "internal.h"
+#include "thread.h"
#include "unary.h"
#include "mathops.h"
#include "alac_data.h"
@@ -59,6 +61,7 @@
#define ALAC_EXTRADATA_SIZE 36
typedef struct ALACContext {
+ AVClass *class;
AVCodecContext *avctx;
GetBitContext gb;
int channels;
@@ -75,6 +78,9 @@ typedef struct ALACContext {
int extra_bits; /**< number of extra bits beyond 16-bit */
int nb_samples; /**< number of samples in the current frame */
+
+ int direct_output;
+ int extra_bit_bug;
} ALACContext;
static inline unsigned int decode_scalar(GetBitContext *gb, int k, int bps)
@@ -99,7 +105,7 @@ static inline unsigned int decode_scalar(GetBitContext *gb, int k, int bps)
return x;
}
-static void rice_decompress(ALACContext *alac, int32_t *output_buffer,
+static int rice_decompress(ALACContext *alac, int32_t *output_buffer,
int nb_samples, int bps, int rice_history_mult)
{
int i;
@@ -110,6 +116,9 @@ static void rice_decompress(ALACContext *alac, int32_t *output_buffer,
int k;
unsigned int x;
+ if(get_bits_left(&alac->gb) <= 0)
+ return -1;
+
/* calculate rice param and decode next value */
k = av_log2((history >> 9) + 3);
k = FFMIN(k, alac->rice_limit);
@@ -150,6 +159,7 @@ static void rice_decompress(ALACContext *alac, int32_t *output_buffer,
history = 0;
}
}
+ return 0;
}
static inline int sign_only(int v)
@@ -186,7 +196,7 @@ static void lpc_prediction(int32_t *error_buffer, int32_t *buffer_out,
}
/* read warm-up samples */
- for (i = 1; i <= lpc_order; i++)
+ for (i = 1; i <= lpc_order && i < nb_samples; i++)
buffer_out[i] = sign_extend(buffer_out[i - 1] + error_buffer[i], bps);
/* NOTE: 4 and 8 are very common cases that could be optimized. */
@@ -265,7 +275,7 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
alac->extra_bits = get_bits(&alac->gb, 2) << 3;
bps = alac->sample_size - alac->extra_bits + channels - 1;
- if (bps > 32) {
+ if (bps > 32U) {
av_log(avctx, AV_LOG_ERROR, "bps is unsupported: %d\n", bps);
return AVERROR_PATCHWELCOME;
}
@@ -283,19 +293,18 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
return AVERROR_INVALIDDATA;
}
if (!alac->nb_samples) {
+ ThreadFrame tframe = { .f = frame };
/* get output buffer */
frame->nb_samples = output_samples;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0)
return ret;
- }
} else if (output_samples != alac->nb_samples) {
av_log(avctx, AV_LOG_ERROR, "sample count mismatch: %"PRIu32" != %d\n",
output_samples, alac->nb_samples);
return AVERROR_INVALIDDATA;
}
alac->nb_samples = output_samples;
- if (alac->sample_size > 16) {
+ if (alac->direct_output) {
for (ch = 0; ch < channels; ch++)
alac->output_samples_buffer[ch] = (int32_t *)frame->extended_data[ch_index + ch];
}
@@ -332,14 +341,18 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
if (alac->extra_bits) {
for (i = 0; i < alac->nb_samples; i++) {
+ if(get_bits_left(&alac->gb) <= 0)
+ return -1;
for (ch = 0; ch < channels; ch++)
alac->extra_bits_buffer[ch][i] = get_bits(&alac->gb, alac->extra_bits);
}
}
for (ch = 0; ch < channels; ch++) {
- rice_decompress(alac, alac->predict_error_buffer[ch],
+ int ret=rice_decompress(alac, alac->predict_error_buffer[ch],
alac->nb_samples, bps,
rice_history_mult[ch] * alac->rice_history_mult / 4);
+ if(ret<0)
+ return ret;
/* adaptive FIR filter */
if (prediction_type[ch] == 15) {
@@ -364,6 +377,8 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
} else {
/* not compressed, easy case */
for (i = 0; i < alac->nb_samples; i++) {
+ if(get_bits_left(&alac->gb) <= 0)
+ return -1;
for (ch = 0; ch < channels; ch++) {
alac->output_samples_buffer[ch][i] =
get_sbits_long(&alac->gb, alac->sample_size);
@@ -374,16 +389,22 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
decorr_left_weight = 0;
}
+ if (alac->extra_bits && alac->extra_bit_bug) {
+ append_extra_bits(alac->output_samples_buffer, alac->extra_bits_buffer,
+ alac->extra_bits, channels, alac->nb_samples);
+ }
+
if (channels == 2 && decorr_left_weight) {
decorrelate_stereo(alac->output_samples_buffer, alac->nb_samples,
decorr_shift, decorr_left_weight);
}
- if (alac->extra_bits) {
+ if (alac->extra_bits && !alac->extra_bit_bug) {
append_extra_bits(alac->output_samples_buffer, alac->extra_bits_buffer,
alac->extra_bits, channels, alac->nb_samples);
}
+ if(av_sample_fmt_is_planar(avctx->sample_fmt)) {
switch(alac->sample_size) {
case 16: {
for (ch = 0; ch < channels; ch++) {
@@ -399,6 +420,37 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index,
}}
break;
}
+ }else{
+ switch(alac->sample_size) {
+ case 16: {
+ int16_t *outbuffer = ((int16_t *)frame->extended_data[0]) + ch_index;
+ for (i = 0; i < alac->nb_samples; i++) {
+ for (ch = 0; ch < channels; ch++)
+ *outbuffer++ = alac->output_samples_buffer[ch][i];
+ outbuffer += alac->channels - channels;
+ }
+ }
+ break;
+ case 24: {
+ int32_t *outbuffer = ((int32_t *)frame->extended_data[0]) + ch_index;
+ for (i = 0; i < alac->nb_samples; i++) {
+ for (ch = 0; ch < channels; ch++)
+ *outbuffer++ = alac->output_samples_buffer[ch][i] << 8;
+ outbuffer += alac->channels - channels;
+ }
+ }
+ break;
+ case 32: {
+ int32_t *outbuffer = ((int32_t *)frame->extended_data[0]) + ch_index;
+ for (i = 0; i < alac->nb_samples; i++) {
+ for (ch = 0; ch < channels; ch++)
+ *outbuffer++ = alac->output_samples_buffer[ch][i];
+ outbuffer += alac->channels - channels;
+ }
+ }
+ break;
+ }
+ }
return 0;
}
@@ -412,7 +464,8 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data,
int channels;
int ch, ret, got_end;
- init_get_bits(&alac->gb, avpkt->data, avpkt->size * 8);
+ if ((ret = init_get_bits8(&alac->gb, avpkt->data, avpkt->size)) < 0)
+ return ret;
got_end = 0;
alac->nb_samples = 0;
@@ -424,7 +477,7 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data,
break;
}
if (element > TYPE_CPE && element != TYPE_LFE) {
- av_log(avctx, AV_LOG_ERROR, "syntax element unsupported: %d", element);
+ av_log(avctx, AV_LOG_ERROR, "syntax element unsupported: %d\n", element);
return AVERROR_PATCHWELCOME;
}
@@ -453,7 +506,10 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data,
avpkt->size * 8 - get_bits_count(&alac->gb));
}
- *got_frame_ptr = 1;
+ if (alac->channels == ch)
+ *got_frame_ptr = 1;
+ else
+ av_log(avctx, AV_LOG_WARNING, "Failed to decode all channels\n");
return avpkt->size;
}
@@ -465,7 +521,7 @@ static av_cold int alac_decode_close(AVCodecContext *avctx)
int ch;
for (ch = 0; ch < FFMIN(alac->channels, 2); ch++) {
av_freep(&alac->predict_error_buffer[ch]);
- if (alac->sample_size == 16)
+ if (!alac->direct_output)
av_freep(&alac->output_samples_buffer[ch]);
av_freep(&alac->extra_bits_buffer[ch]);
}
@@ -482,7 +538,8 @@ static int allocate_buffers(ALACContext *alac)
FF_ALLOC_OR_GOTO(alac->avctx, alac->predict_error_buffer[ch],
buf_size, buf_alloc_fail);
- if (alac->sample_size == 16) {
+ alac->direct_output = alac->sample_size > 16 && av_sample_fmt_is_planar(alac->avctx->sample_fmt);
+ if (!alac->direct_output) {
FF_ALLOC_OR_GOTO(alac->avctx, alac->output_samples_buffer[ch],
buf_size, buf_alloc_fail);
}
@@ -530,24 +587,26 @@ static int alac_set_info(ALACContext *alac)
static av_cold int alac_decode_init(AVCodecContext * avctx)
{
int ret;
+ int req_packed;
ALACContext *alac = avctx->priv_data;
alac->avctx = avctx;
/* initialize from the extradata */
if (alac->avctx->extradata_size < ALAC_EXTRADATA_SIZE) {
- av_log(avctx, AV_LOG_ERROR, "alac: extradata is too small\n");
+ av_log(avctx, AV_LOG_ERROR, "extradata is too small\n");
return AVERROR_INVALIDDATA;
}
if (alac_set_info(alac)) {
- av_log(avctx, AV_LOG_ERROR, "alac: set_info failed\n");
+ av_log(avctx, AV_LOG_ERROR, "set_info failed\n");
return -1;
}
+ req_packed = LIBAVCODEC_VERSION_MAJOR < 55 && !av_sample_fmt_is_planar(avctx->request_sample_fmt);
switch (alac->sample_size) {
- case 16: avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
+ case 16: avctx->sample_fmt = req_packed ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_S16P;
break;
case 24:
- case 32: avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
+ case 32: avctx->sample_fmt = req_packed ? AV_SAMPLE_FMT_S32 : AV_SAMPLE_FMT_S32P;
break;
default: avpriv_request_sample(avctx, "Sample depth %d", alac->sample_size);
return AVERROR_PATCHWELCOME;
@@ -563,7 +622,7 @@ static av_cold int alac_decode_init(AVCodecContext * avctx)
else
avctx->channels = alac->channels;
}
- if (avctx->channels > ALAC_MAX_CHANNELS) {
+ if (avctx->channels > ALAC_MAX_CHANNELS || avctx->channels <= 0 ) {
av_log(avctx, AV_LOG_ERROR, "Unsupported channel count: %d\n",
avctx->channels);
return AVERROR_PATCHWELCOME;
@@ -578,6 +637,27 @@ static av_cold int alac_decode_init(AVCodecContext * avctx)
return 0;
}
+static int init_thread_copy(AVCodecContext *avctx)
+{
+ ALACContext *alac = avctx->priv_data;
+ alac->avctx = avctx;
+ return allocate_buffers(alac);
+}
+
+static const AVOption options[] = {
+ { "extra_bits_bug", "Force non-standard decoding process",
+ offsetof(ALACContext, extra_bit_bug), AV_OPT_TYPE_INT, { .i64 = 0 },
+ 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass alac_class = {
+ .class_name = "alac",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_alac_decoder = {
.name = "alac",
.long_name = NULL_IF_CONFIG_SMALL("ALAC (Apple Lossless Audio Codec)"),
@@ -587,5 +667,7 @@ AVCodec ff_alac_decoder = {
.init = alac_decode_init,
.close = alac_decode_close,
.decode = alac_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
+ .priv_class = &alac_class
};
diff --git a/libavcodec/alac_data.c b/libavcodec/alac_data.c
index 9e131199b1..0bcb06c075 100644
--- a/libavcodec/alac_data.c
+++ b/libavcodec/alac_data.c
@@ -1,20 +1,20 @@
/*
* ALAC encoder and decoder common data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/alac_data.h b/libavcodec/alac_data.h
index ebb1f33a93..650d6dcd15 100644
--- a/libavcodec/alac_data.h
+++ b/libavcodec/alac_data.h
@@ -1,20 +1,20 @@
/*
* ALAC encoder and decoder common data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/alacenc.c b/libavcodec/alacenc.c
index 401f26f66c..ce63da6637 100644
--- a/libavcodec/alacenc.c
+++ b/libavcodec/alacenc.c
@@ -2,20 +2,20 @@
* ALAC audio encoder
* Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,7 +66,7 @@ typedef struct AlacEncodeContext {
int write_sample_size;
int extra_bits;
int32_t sample_buf[2][DEFAULT_FRAME_SIZE];
- int32_t predictor_buf[DEFAULT_FRAME_SIZE];
+ int32_t predictor_buf[2][DEFAULT_FRAME_SIZE];
int interlacing_shift;
int interlacing_leftweight;
PutBitContext pbctx;
@@ -253,13 +253,14 @@ static void alac_linear_predictor(AlacEncodeContext *s, int ch)
{
int i;
AlacLPCContext lpc = s->lpc[ch];
+ int32_t *residual = s->predictor_buf[ch];
if (lpc.lpc_order == 31) {
- s->predictor_buf[0] = s->sample_buf[ch][0];
+ residual[0] = s->sample_buf[ch][0];
for (i = 1; i < s->frame_size; i++) {
- s->predictor_buf[i] = s->sample_buf[ch][i ] -
- s->sample_buf[ch][i - 1];
+ residual[i] = s->sample_buf[ch][i ] -
+ s->sample_buf[ch][i - 1];
}
return;
@@ -269,12 +270,11 @@ static void alac_linear_predictor(AlacEncodeContext *s, int ch)
if (lpc.lpc_order > 0) {
int32_t *samples = s->sample_buf[ch];
- int32_t *residual = s->predictor_buf;
// generate warm-up samples
residual[0] = samples[0];
for (i = 1; i <= lpc.lpc_order; i++)
- residual[i] = samples[i] - samples[i-1];
+ residual[i] = sign_extend(samples[i] - samples[i-1], s->write_sample_size);
// perform lpc on remaining samples
for (i = lpc.lpc_order + 1; i < s->frame_size; i++) {
@@ -313,11 +313,11 @@ static void alac_linear_predictor(AlacEncodeContext *s, int ch)
}
}
-static void alac_entropy_coder(AlacEncodeContext *s)
+static void alac_entropy_coder(AlacEncodeContext *s, int ch)
{
unsigned int history = s->rc.initial_history;
int sign_modifier = 0, i, k;
- int32_t *samples = s->predictor_buf;
+ int32_t *samples = s->predictor_buf[ch];
for (i = 0; i < s->frame_size;) {
int x;
@@ -394,6 +394,19 @@ static void write_element(AlacEncodeContext *s,
init_sample_buffers(s, channels, samples);
write_element_header(s, element, instance);
+ // extract extra bits if needed
+ if (s->extra_bits) {
+ uint32_t mask = (1 << s->extra_bits) - 1;
+ for (j = 0; j < channels; j++) {
+ int32_t *extra = s->predictor_buf[j];
+ int32_t *smp = s->sample_buf[j];
+ for (i = 0; i < s->frame_size; i++) {
+ extra[i] = smp[i] & mask;
+ smp[i] >>= s->extra_bits;
+ }
+ }
+ }
+
if (channels == 2)
alac_stereo_decorrelation(s);
else
@@ -416,11 +429,9 @@ static void write_element(AlacEncodeContext *s,
// write extra bits if needed
if (s->extra_bits) {
- uint32_t mask = (1 << s->extra_bits) - 1;
for (i = 0; i < s->frame_size; i++) {
for (j = 0; j < channels; j++) {
- put_bits(pb, s->extra_bits, s->sample_buf[j][i] & mask);
- s->sample_buf[j][i] >>= s->extra_bits;
+ put_bits(pb, s->extra_bits, s->predictor_buf[j][i]);
}
}
}
@@ -432,10 +443,11 @@ static void write_element(AlacEncodeContext *s,
// TODO: determine when this will actually help. for now it's not used.
if (prediction_type == 15) {
// 2nd pass 1st order filter
+ int32_t *residual = s->predictor_buf[i];
for (j = s->frame_size - 1; j > 0; j--)
- s->predictor_buf[j] -= s->predictor_buf[j - 1];
+ residual[j] -= residual[j - 1];
}
- alac_entropy_coder(s);
+ alac_entropy_coder(s, i);
}
}
}
@@ -483,7 +495,6 @@ static av_cold int alac_encode_close(AVCodecContext *avctx)
ff_lpc_end(&s->lpc_ctx);
av_freep(&avctx->extradata);
avctx->extradata_size = 0;
- av_freep(&avctx->coded_frame);
return 0;
}
@@ -579,12 +590,6 @@ static av_cold int alac_encode_init(AVCodecContext *avctx)
goto error;
}
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame) {
- ret = AVERROR(ENOMEM);
- goto error;
- }
-
s->avctx = avctx;
if ((ret = ff_lpc_init(&s->lpc_ctx, avctx->frame_size,
@@ -613,10 +618,8 @@ static int alac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
else
max_frame_size = s->max_coded_frame_size;
- if ((ret = ff_alloc_packet(avpkt, 2 * max_frame_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 2 * max_frame_size)) < 0)
return ret;
- }
/* use verbatim mode for compression_level 0 */
if (s->compression_level) {
diff --git a/libavcodec/aliaspixdec.c b/libavcodec/aliaspixdec.c
index 8969e1765e..bdc4c72c21 100644
--- a/libavcodec/aliaspixdec.c
+++ b/libavcodec/aliaspixdec.c
@@ -2,20 +2,20 @@
* Alias PIX image decoder
* Copyright (C) 2014 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aliaspixenc.c b/libavcodec/aliaspixenc.c
index 47e06129d5..1fcea08415 100644
--- a/libavcodec/aliaspixenc.c
+++ b/libavcodec/aliaspixenc.c
@@ -2,20 +2,20 @@
* Alias PIX image encoder
* Copyright (C) 2014 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index a8b5b5388a..a94d1dc8f6 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -2,20 +2,20 @@
* Provide registration of all codecs, parsers and bitstream filters for libavcodec.
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -86,7 +86,9 @@ void avcodec_register_all(void)
REGISTER_HWACCEL(H264_VDPAU, h264_vdpau);
REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va);
REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2);
+ REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc);
REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau);
+ REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc);
REGISTER_HWACCEL(MPEG2_D3D11VA, mpeg2_d3d11va);
REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2);
REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi);
@@ -108,14 +110,19 @@ void avcodec_register_all(void)
REGISTER_DECODER(AASC, aasc);
REGISTER_DECODER(AIC, aic);
REGISTER_ENCDEC (ALIAS_PIX, alias_pix);
- REGISTER_DECODER(AMV, amv);
+ REGISTER_ENCDEC (AMV, amv);
REGISTER_DECODER(ANM, anm);
REGISTER_DECODER(ANSI, ansi);
+ REGISTER_ENCDEC (APNG, apng);
REGISTER_ENCDEC (ASV1, asv1);
REGISTER_ENCDEC (ASV2, asv2);
REGISTER_DECODER(AURA, aura);
REGISTER_DECODER(AURA2, aura2);
+ REGISTER_ENCDEC (AVRP, avrp);
+ REGISTER_DECODER(AVRN, avrn);
REGISTER_DECODER(AVS, avs);
+ REGISTER_ENCDEC (AVUI, avui);
+ REGISTER_ENCDEC (AYUV, ayuv);
REGISTER_DECODER(BETHSOFTVID, bethsoftvid);
REGISTER_DECODER(BFI, bfi);
REGISTER_DECODER(BINK, bink);
@@ -126,13 +133,15 @@ void avcodec_register_all(void)
REGISTER_DECODER(CAVS, cavs);
REGISTER_DECODER(CDGRAPHICS, cdgraphics);
REGISTER_DECODER(CDXL, cdxl);
- REGISTER_DECODER(CINEPAK, cinepak);
+ REGISTER_ENCDEC (CINEPAK, cinepak);
REGISTER_ENCDEC (CLJR, cljr);
REGISTER_DECODER(CLLC, cllc);
REGISTER_ENCDEC (COMFORTNOISE, comfortnoise);
+ REGISTER_DECODER(CPIA, cpia);
REGISTER_DECODER(CSCD, cscd);
REGISTER_DECODER(CYUV, cyuv);
REGISTER_DECODER(DFA, dfa);
+ REGISTER_DECODER(DIRAC, dirac);
REGISTER_ENCDEC (DNXHD, dnxhd);
REGISTER_ENCDEC (DPX, dpx);
REGISTER_DECODER(DSICINVIDEO, dsicinvideo);
@@ -154,7 +163,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (FFVHUFF, ffvhuff);
REGISTER_DECODER(FIC, fic);
REGISTER_ENCDEC (FLASHSV, flashsv);
- REGISTER_DECODER(FLASHSV2, flashsv2);
+ REGISTER_ENCDEC (FLASHSV2, flashsv2);
REGISTER_DECODER(FLIC, flic);
REGISTER_ENCDEC (FLV, flv);
REGISTER_DECODER(FOURXM, fourxm);
@@ -165,10 +174,13 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (H261, h261);
REGISTER_ENCDEC (H263, h263);
REGISTER_DECODER(H263I, h263i);
- REGISTER_ENCODER(H263P, h263p);
+ REGISTER_ENCDEC (H263P, h263p);
REGISTER_DECODER(H264, h264);
+ REGISTER_DECODER(H264_CRYSTALHD, h264_crystalhd);
REGISTER_DECODER(H264_MMAL, h264_mmal);
REGISTER_DECODER(H264_QSV, h264_qsv);
+ REGISTER_DECODER(H264_VDA, h264_vda);
+ REGISTER_DECODER(H264_VDPAU, h264_vdpau);
REGISTER_DECODER(HEVC, hevc);
REGISTER_DECODER(HNM4_VIDEO, hnm4_video);
REGISTER_DECODER(HQ_HQA, hq_hqa);
@@ -182,7 +194,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(INDEO4, indeo4);
REGISTER_DECODER(INDEO5, indeo5);
REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video);
- REGISTER_DECODER(JPEG2000, jpeg2000);
+ REGISTER_ENCDEC (JPEG2000, jpeg2000);
REGISTER_ENCDEC (JPEGLS, jpegls);
REGISTER_DECODER(JV, jv);
REGISTER_DECODER(KGV1, kgv1);
@@ -202,20 +214,29 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (MPEG1VIDEO, mpeg1video);
REGISTER_ENCDEC (MPEG2VIDEO, mpeg2video);
REGISTER_ENCDEC (MPEG4, mpeg4);
+ REGISTER_DECODER(MPEG4_CRYSTALHD, mpeg4_crystalhd);
+ REGISTER_DECODER(MPEG4_VDPAU, mpeg4_vdpau);
+ REGISTER_DECODER(MPEGVIDEO, mpegvideo);
+ REGISTER_DECODER(MPEG_VDPAU, mpeg_vdpau);
+ REGISTER_DECODER(MPEG1_VDPAU, mpeg1_vdpau);
+ REGISTER_DECODER(MPEG2_CRYSTALHD, mpeg2_crystalhd);
REGISTER_DECODER(MSA1, msa1);
+ REGISTER_DECODER(MSMPEG4_CRYSTALHD, msmpeg4_crystalhd);
REGISTER_DECODER(MSMPEG4V1, msmpeg4v1);
REGISTER_ENCDEC (MSMPEG4V2, msmpeg4v2);
REGISTER_ENCDEC (MSMPEG4V3, msmpeg4v3);
REGISTER_DECODER(MSRLE, msrle);
REGISTER_DECODER(MSS1, mss1);
REGISTER_DECODER(MSS2, mss2);
- REGISTER_DECODER(MSVIDEO1, msvideo1);
+ REGISTER_ENCDEC (MSVIDEO1, msvideo1);
REGISTER_DECODER(MSZH, mszh);
REGISTER_DECODER(MTS2, mts2);
REGISTER_DECODER(MVC1, mvc1);
REGISTER_DECODER(MVC2, mvc2);
REGISTER_DECODER(MXPEG, mxpeg);
REGISTER_DECODER(NUV, nuv);
+ REGISTER_ENCODER(NVENC, nvenc);
+ REGISTER_ENCODER(NVENC_H265, nvenc_h265);
REGISTER_DECODER(PAF_VIDEO, paf_video);
REGISTER_ENCDEC (PAM, pam);
REGISTER_ENCDEC (PBM, pbm);
@@ -226,12 +247,15 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (PNG, png);
REGISTER_ENCDEC (PPM, ppm);
REGISTER_ENCDEC (PRORES, prores);
+ REGISTER_ENCODER(PRORES_AW, prores_aw);
+ REGISTER_ENCODER(PRORES_KS, prores_ks);
+ REGISTER_DECODER(PRORES_LGPL, prores_lgpl);
REGISTER_DECODER(PTX, ptx);
REGISTER_DECODER(QDRAW, qdraw);
REGISTER_DECODER(QPEG, qpeg);
REGISTER_ENCDEC (QTRLE, qtrle);
- REGISTER_DECODER(R10K, r10k);
- REGISTER_DECODER(R210, r210);
+ REGISTER_ENCDEC (R10K, r10k);
+ REGISTER_ENCDEC (R210, r210);
REGISTER_ENCDEC (RAWVIDEO, rawvideo);
REGISTER_DECODER(RL2, rl2);
REGISTER_ENCDEC (ROQ, roq);
@@ -240,17 +264,20 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (RV20, rv20);
REGISTER_DECODER(RV30, rv30);
REGISTER_DECODER(RV40, rv40);
- REGISTER_DECODER(S302M, s302m);
+ REGISTER_ENCDEC (S302M, s302m);
REGISTER_DECODER(SANM, sanm);
REGISTER_ENCDEC (SGI, sgi);
REGISTER_DECODER(SGIRLE, sgirle);
REGISTER_DECODER(SMACKER, smacker);
REGISTER_DECODER(SMC, smc);
+ REGISTER_DECODER(SMVJPEG, smvjpeg);
+ REGISTER_ENCDEC (SNOW, snow);
REGISTER_DECODER(SP5X, sp5x);
REGISTER_ENCDEC (SUNRAST, sunrast);
REGISTER_ENCDEC (SVQ1, svq1);
REGISTER_DECODER(SVQ3, svq3);
REGISTER_ENCDEC (TARGA, targa);
+ REGISTER_DECODER(TARGA_Y216, targa_y216);
REGISTER_DECODER(TDSC, tdsc);
REGISTER_DECODER(THEORA, theora);
REGISTER_DECODER(THP, thp);
@@ -266,10 +293,14 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (UTVIDEO, utvideo);
REGISTER_ENCDEC (V210, v210);
REGISTER_DECODER(V210X, v210x);
+ REGISTER_ENCDEC (V308, v308);
+ REGISTER_ENCDEC (V408, v408);
REGISTER_ENCDEC (V410, v410);
REGISTER_DECODER(VB, vb);
REGISTER_DECODER(VBLE, vble);
REGISTER_DECODER(VC1, vc1);
+ REGISTER_DECODER(VC1_CRYSTALHD, vc1_crystalhd);
+ REGISTER_DECODER(VC1_VDPAU, vc1_vdpau);
REGISTER_DECODER(VC1IMAGE, vc1image);
REGISTER_DECODER(VCR1, vcr1);
REGISTER_DECODER(VMDVIDEO, vmdvideo);
@@ -287,14 +318,20 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (WMV1, wmv1);
REGISTER_ENCDEC (WMV2, wmv2);
REGISTER_DECODER(WMV3, wmv3);
+ REGISTER_DECODER(WMV3_CRYSTALHD, wmv3_crystalhd);
+ REGISTER_DECODER(WMV3_VDPAU, wmv3_vdpau);
REGISTER_DECODER(WMV3IMAGE, wmv3image);
REGISTER_DECODER(WNV1, wnv1);
REGISTER_DECODER(XAN_WC3, xan_wc3);
REGISTER_DECODER(XAN_WC4, xan_wc4);
REGISTER_ENCDEC (XBM, xbm);
+ REGISTER_ENCDEC (XFACE, xface);
REGISTER_DECODER(XL, xl);
REGISTER_ENCDEC (XWD, xwd);
+ REGISTER_ENCDEC (Y41P, y41p);
REGISTER_DECODER(YOP, yop);
+ REGISTER_ENCDEC (YUV4, yuv4);
+ REGISTER_DECODER(ZERO12V, zero12v);
REGISTER_DECODER(ZEROCODEC, zerocodec);
REGISTER_ENCDEC (ZLIB, zlib);
REGISTER_ENCDEC (ZMBV, zmbv);
@@ -303,7 +340,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (AAC, aac);
REGISTER_DECODER(AAC_LATM, aac_latm);
REGISTER_ENCDEC (AC3, ac3);
- REGISTER_ENCODER(AC3_FIXED, ac3_fixed);
+ REGISTER_ENCDEC (AC3_FIXED, ac3_fixed);
REGISTER_ENCDEC (ALAC, alac);
REGISTER_DECODER(ALS, als);
REGISTER_DECODER(AMRNB, amrnb);
@@ -316,12 +353,19 @@ void avcodec_register_all(void)
REGISTER_DECODER(BINKAUDIO_RDFT, binkaudio_rdft);
REGISTER_DECODER(BMV_AUDIO, bmv_audio);
REGISTER_DECODER(COOK, cook);
- REGISTER_DECODER(DCA, dca);
+ REGISTER_ENCDEC (DCA, dca);
+ REGISTER_DECODER(DSD_LSBF, dsd_lsbf);
+ REGISTER_DECODER(DSD_MSBF, dsd_msbf);
+ REGISTER_DECODER(DSD_LSBF_PLANAR, dsd_lsbf_planar);
+ REGISTER_DECODER(DSD_MSBF_PLANAR, dsd_msbf_planar);
REGISTER_DECODER(DSICINAUDIO, dsicinaudio);
REGISTER_DECODER(DSS_SP, dss_sp);
REGISTER_ENCDEC (EAC3, eac3);
+ REGISTER_DECODER(EVRC, evrc);
+ REGISTER_DECODER(FFWAVESYNTH, ffwavesynth);
REGISTER_ENCDEC (FLAC, flac);
- REGISTER_DECODER(G723_1, g723_1);
+ REGISTER_ENCDEC (G723_1, g723_1);
+ REGISTER_DECODER(G729, g729);
REGISTER_DECODER(GSM, gsm);
REGISTER_DECODER(GSM_MS, gsm_ms);
REGISTER_DECODER(IAC, iac);
@@ -334,6 +378,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(MP1FLOAT, mp1float);
REGISTER_ENCDEC (MP2, mp2);
REGISTER_DECODER(MP2FLOAT, mp2float);
+ REGISTER_ENCODER(MP2FIXED, mp2fixed);
REGISTER_DECODER(MP3, mp3);
REGISTER_DECODER(MP3FLOAT, mp3float);
REGISTER_DECODER(MP3ADU, mp3adu);
@@ -354,14 +399,16 @@ void avcodec_register_all(void)
REGISTER_DECODER(SHORTEN, shorten);
REGISTER_DECODER(SIPR, sipr);
REGISTER_DECODER(SMACKAUD, smackaud);
+ REGISTER_ENCDEC (SONIC, sonic);
+ REGISTER_ENCODER(SONIC_LS, sonic_ls);
REGISTER_DECODER(TAK, tak);
REGISTER_DECODER(TRUEHD, truehd);
REGISTER_DECODER(TRUESPEECH, truespeech);
- REGISTER_DECODER(TTA, tta);
+ REGISTER_ENCDEC (TTA, tta);
REGISTER_DECODER(TWINVQ, twinvq);
REGISTER_DECODER(VMDAUDIO, vmdaudio);
REGISTER_ENCDEC (VORBIS, vorbis);
- REGISTER_DECODER(WAVPACK, wavpack);
+ REGISTER_ENCDEC (WAVPACK, wavpack);
REGISTER_DECODER(WMALOSSLESS, wmalossless);
REGISTER_DECODER(WMAPRO, wmapro);
REGISTER_ENCDEC (WMAV1, wmav1);
@@ -380,17 +427,18 @@ void avcodec_register_all(void)
REGISTER_DECODER(PCM_LXF, pcm_lxf);
REGISTER_ENCDEC (PCM_MULAW, pcm_mulaw);
REGISTER_ENCDEC (PCM_S8, pcm_s8);
- REGISTER_DECODER(PCM_S8_PLANAR, pcm_s8_planar);
+ REGISTER_ENCDEC (PCM_S8_PLANAR, pcm_s8_planar);
REGISTER_ENCDEC (PCM_S16BE, pcm_s16be);
+ REGISTER_ENCDEC (PCM_S16BE_PLANAR, pcm_s16be_planar);
REGISTER_ENCDEC (PCM_S16LE, pcm_s16le);
- REGISTER_DECODER(PCM_S16LE_PLANAR, pcm_s16le_planar);
+ REGISTER_ENCDEC (PCM_S16LE_PLANAR, pcm_s16le_planar);
REGISTER_ENCDEC (PCM_S24BE, pcm_s24be);
REGISTER_ENCDEC (PCM_S24DAUD, pcm_s24daud);
REGISTER_ENCDEC (PCM_S24LE, pcm_s24le);
- REGISTER_DECODER(PCM_S24LE_PLANAR, pcm_s24le_planar);
+ REGISTER_ENCDEC (PCM_S24LE_PLANAR, pcm_s24le_planar);
REGISTER_ENCDEC (PCM_S32BE, pcm_s32be);
REGISTER_ENCDEC (PCM_S32LE, pcm_s32le);
- REGISTER_DECODER(PCM_S32LE_PLANAR, pcm_s32le_planar);
+ REGISTER_ENCDEC (PCM_S32LE_PLANAR, pcm_s32le_planar);
REGISTER_ENCDEC (PCM_U8, pcm_u8);
REGISTER_ENCDEC (PCM_U16BE, pcm_u16be);
REGISTER_ENCDEC (PCM_U16LE, pcm_u16le);
@@ -398,7 +446,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (PCM_U24LE, pcm_u24le);
REGISTER_ENCDEC (PCM_U32BE, pcm_u32be);
REGISTER_ENCDEC (PCM_U32LE, pcm_u32le);
- REGISTER_DECODER(PCM_ZORK , pcm_zork);
+ REGISTER_DECODER(PCM_ZORK, pcm_zork);
/* DPCM codecs */
REGISTER_DECODER(INTERPLAY_DPCM, interplay_dpcm);
@@ -409,7 +457,9 @@ void avcodec_register_all(void)
/* ADPCM codecs */
REGISTER_DECODER(ADPCM_4XM, adpcm_4xm);
REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx);
+ REGISTER_DECODER(ADPCM_AFC, adpcm_afc);
REGISTER_DECODER(ADPCM_CT, adpcm_ct);
+ REGISTER_DECODER(ADPCM_DTK, adpcm_dtk);
REGISTER_DECODER(ADPCM_EA, adpcm_ea);
REGISTER_DECODER(ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa);
REGISTER_DECODER(ADPCM_EA_R1, adpcm_ea_r1);
@@ -418,6 +468,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_EA_XAS, adpcm_ea_xas);
REGISTER_ENCDEC (ADPCM_G722, adpcm_g722);
REGISTER_ENCDEC (ADPCM_G726, adpcm_g726);
+ REGISTER_DECODER(ADPCM_G726LE, adpcm_g726le);
REGISTER_DECODER(ADPCM_IMA_AMV, adpcm_ima_amv);
REGISTER_DECODER(ADPCM_IMA_APC, adpcm_ima_apc);
REGISTER_DECODER(ADPCM_IMA_DK3, adpcm_ima_dk3);
@@ -425,7 +476,9 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs);
REGISTER_DECODER(ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead);
REGISTER_DECODER(ADPCM_IMA_ISS, adpcm_ima_iss);
+ REGISTER_DECODER(ADPCM_IMA_OKI, adpcm_ima_oki);
REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt);
+ REGISTER_DECODER(ADPCM_IMA_RAD, adpcm_ima_rad);
REGISTER_DECODER(ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg);
REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav);
REGISTER_DECODER(ADPCM_IMA_WS, adpcm_ima_ws);
@@ -438,16 +491,36 @@ void avcodec_register_all(void)
REGISTER_DECODER(ADPCM_VIMA, adpcm_vima);
REGISTER_DECODER(ADPCM_XA, adpcm_xa);
REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha);
+#if FF_API_VIMA_DECODER
+ REGISTER_DECODER(VIMA, vima);
+#endif
/* subtitles */
+ REGISTER_ENCDEC (SSA, ssa);
REGISTER_ENCDEC (ASS, ass);
+ REGISTER_DECODER(CCAPTION, ccaption);
REGISTER_ENCDEC (DVBSUB, dvbsub);
REGISTER_ENCDEC (DVDSUB, dvdsub);
+ REGISTER_DECODER(JACOSUB, jacosub);
+ REGISTER_DECODER(MICRODVD, microdvd);
+ REGISTER_ENCDEC (MOVTEXT, movtext);
+ REGISTER_DECODER(MPL2, mpl2);
REGISTER_DECODER(PGSSUB, pgssub);
- REGISTER_DECODER(SRT, srt);
+ REGISTER_DECODER(PJS, pjs);
+ REGISTER_DECODER(REALTEXT, realtext);
+ REGISTER_DECODER(SAMI, sami);
+ REGISTER_ENCDEC (SRT, srt);
+ REGISTER_DECODER(STL, stl);
+ REGISTER_ENCDEC (SUBRIP, subrip);
+ REGISTER_DECODER(SUBVIEWER, subviewer);
+ REGISTER_DECODER(SUBVIEWER1, subviewer1);
+ REGISTER_DECODER(TEXT, text);
+ REGISTER_DECODER(VPLAYER, vplayer);
+ REGISTER_ENCDEC (WEBVTT, webvtt);
REGISTER_ENCDEC (XSUB, xsub);
/* external libraries */
+ REGISTER_DECODER(LIBCELT, libcelt);
REGISTER_DECODER(LIBDCADEC, libdcadec)
REGISTER_ENCODER(LIBFAAC, libfaac);
REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac);
@@ -460,20 +533,32 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (LIBOPENJPEG, libopenjpeg);
REGISTER_ENCDEC (LIBOPUS, libopus);
REGISTER_ENCDEC (LIBSCHROEDINGER, libschroedinger);
+ REGISTER_ENCODER(LIBSHINE, libshine);
REGISTER_ENCDEC (LIBSPEEX, libspeex);
+ REGISTER_DECODER(LIBSTAGEFRIGHT_H264, libstagefright_h264);
REGISTER_ENCODER(LIBTHEORA, libtheora);
REGISTER_ENCODER(LIBTWOLAME, libtwolame);
+ REGISTER_ENCDEC (LIBUTVIDEO, libutvideo);
REGISTER_ENCODER(LIBVO_AACENC, libvo_aacenc);
REGISTER_ENCODER(LIBVO_AMRWBENC, libvo_amrwbenc);
- REGISTER_ENCODER(LIBVORBIS, libvorbis);
+ REGISTER_ENCDEC (LIBVORBIS, libvorbis);
REGISTER_ENCDEC (LIBVPX_VP8, libvpx_vp8);
REGISTER_ENCDEC (LIBVPX_VP9, libvpx_vp9);
REGISTER_ENCODER(LIBWAVPACK, libwavpack);
+ REGISTER_ENCODER(LIBWEBP_ANIM, libwebp_anim); /* preferred over libwebp */
REGISTER_ENCODER(LIBWEBP, libwebp);
REGISTER_ENCODER(LIBX264, libx264);
+ REGISTER_ENCODER(LIBX264RGB, libx264rgb);
REGISTER_ENCODER(LIBX265, libx265);
REGISTER_ENCODER(LIBXAVS, libxavs);
REGISTER_ENCODER(LIBXVID, libxvid);
+ REGISTER_DECODER(LIBZVBI_TELETEXT, libzvbi_teletext);
+ REGISTER_ENCODER(LIBAACPLUS, libaacplus);
+
+ /* text */
+ REGISTER_DECODER(BINTEXT, bintext);
+ REGISTER_DECODER(XBIN, xbin);
+ REGISTER_DECODER(IDF, idf);
/* external libraries, that shouldn't be used by default if one of the
* above is available */
@@ -494,6 +579,7 @@ void avcodec_register_all(void)
REGISTER_PARSER(DPX, dpx);
REGISTER_PARSER(DVBSUB, dvbsub);
REGISTER_PARSER(DVDSUB, dvdsub);
+ REGISTER_PARSER(DVD_NAV, dvd_nav);
REGISTER_PARSER(FLAC, flac);
REGISTER_PARSER(GSM, gsm);
REGISTER_PARSER(H261, h261);
@@ -515,6 +601,7 @@ void avcodec_register_all(void)
REGISTER_PARSER(VORBIS, vorbis);
REGISTER_PARSER(VP3, vp3);
REGISTER_PARSER(VP8, vp8);
+ REGISTER_PARSER(VP9, vp9);
/* bitstream filters */
REGISTER_BSF(AAC_ADTSTOASC, aac_adtstoasc);
@@ -524,6 +611,8 @@ void avcodec_register_all(void)
REGISTER_BSF(IMX_DUMP_HEADER, imx_dump_header);
REGISTER_BSF(MJPEG2JPEG, mjpeg2jpeg);
REGISTER_BSF(MJPEGA_DUMP_HEADER, mjpega_dump_header);
+ REGISTER_BSF(MP3_HEADER_DECOMPRESS, mp3_header_decompress);
+ REGISTER_BSF(MPEG4_UNPACK_BFRAMES, mpeg4_unpack_bframes);
REGISTER_BSF(MOV2TEXTSUB, mov2textsub);
REGISTER_BSF(NOISE, noise);
REGISTER_BSF(REMOVE_EXTRADATA, remove_extradata);
diff --git a/libavcodec/alpha/Makefile b/libavcodec/alpha/Makefile
new file mode 100644
index 0000000000..796d9762b3
--- /dev/null
+++ b/libavcodec/alpha/Makefile
@@ -0,0 +1,10 @@
+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
new file mode 100644
index 0000000000..827721e777
--- /dev/null
+++ b/libavcodec/alpha/asm.h
@@ -0,0 +1,186 @@
+/*
+ * Alpha optimized DSP utils
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <inttypes.h>
+
+#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
+
+#elif defined(__DECC) /* Digital/Compaq/hp "ccc" compiler */
+
+#include <c_asm.h>
+#define ldq(p) (*(const uint64_t *) (p))
+#define ldl(p) (*(const int32_t *) (p))
+#define stq(l, p) do { *(uint64_t *) (p) = (l); } while (0)
+#define stl(l, p) do { *(int32_t *) (p) = (l); } while (0)
+#define ldq_u(a) asm ("ldq_u %v0,0(%a0)", a)
+#define uldq(a) (*(const __unaligned uint64_t *) (a))
+#define cmpbge(a, b) asm ("cmpbge %a0,%a1,%v0", a, b)
+#define extql(a, b) asm ("extql %a0,%a1,%v0", a, b)
+#define extwl(a, b) asm ("extwl %a0,%a1,%v0", a, b)
+#define extqh(a, b) asm ("extqh %a0,%a1,%v0", a, b)
+#define zap(a, b) asm ("zap %a0,%a1,%v0", a, b)
+#define zapnot(a, b) asm ("zapnot %a0,%a1,%v0", a, b)
+#define amask(a) asm ("amask %a0,%v0", a)
+#define implver() asm ("implver %v0")
+#define rpcc() asm ("rpcc %v0")
+#define minub8(a, b) asm ("minub8 %a0,%a1,%v0", a, b)
+#define minsb8(a, b) asm ("minsb8 %a0,%a1,%v0", a, b)
+#define minuw4(a, b) asm ("minuw4 %a0,%a1,%v0", a, b)
+#define minsw4(a, b) asm ("minsw4 %a0,%a1,%v0", a, b)
+#define maxub8(a, b) asm ("maxub8 %a0,%a1,%v0", a, b)
+#define maxsb8(a, b) asm ("maxsb8 %a0,%a1,%v0", a, b)
+#define maxuw4(a, b) asm ("maxuw4 %a0,%a1,%v0", a, b)
+#define maxsw4(a, b) asm ("maxsw4 %a0,%a1,%v0", a, b)
+#define perr(a, b) asm ("perr %a0,%a1,%v0", a, b)
+#define pklb(a) asm ("pklb %a0,%v0", a)
+#define pkwb(a) asm ("pkwb %a0,%v0", a)
+#define unpkbl(a) asm ("unpkbl %a0,%v0", a)
+#define unpkbw(a) asm ("unpkbw %a0,%v0", a)
+#define wh64(a) asm ("wh64 %a0", a)
+
+#else
+#error "Unknown compiler!"
+#endif
+
+#endif /* AVCODEC_ALPHA_ASM_H */
diff --git a/libavcodec/alpha/blockdsp_alpha.c b/libavcodec/alpha/blockdsp_alpha.c
new file mode 100644
index 0000000000..ded439d842
--- /dev/null
+++ b/libavcodec/alpha/blockdsp_alpha.c
@@ -0,0 +1,51 @@
+/*
+ * Alpha optimised block operations
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavcodec/blockdsp.h"
+#include "asm.h"
+
+static void clear_blocks_axp(int16_t *blocks) {
+ uint64_t *p = (uint64_t *) blocks;
+ int n = sizeof(int16_t) * 6 * 64;
+
+ 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, unsigned high_bit_depth)
+{
+ if (!high_bit_depth) {
+ c->clear_blocks = clear_blocks_axp;
+ }
+}
diff --git a/libavcodec/alpha/hpeldsp_alpha.c b/libavcodec/alpha/hpeldsp_alpha.c
new file mode 100644
index 0000000000..8d54807d8f
--- /dev/null
+++ b/libavcodec/alpha/hpeldsp_alpha.c
@@ -0,0 +1,213 @@
+/*
+ * Alpha optimized DSP utils
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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.h b/libavcodec/alpha/hpeldsp_alpha.h
new file mode 100644
index 0000000000..985182c67b
--- /dev/null
+++ b/libavcodec/alpha/hpeldsp_alpha.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_HPELDSP_ALPHA_H
+#define AVCODEC_ALPHA_HPELDSP_ALPHA_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+void put_pixels_axp_asm(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+
+#endif /* AVCODEC_ALPHA_HPELDSP_ALPHA_H */
diff --git a/libavcodec/alpha/hpeldsp_alpha_asm.S b/libavcodec/alpha/hpeldsp_alpha_asm.S
new file mode 100644
index 0000000000..df386c429e
--- /dev/null
+++ b/libavcodec/alpha/hpeldsp_alpha_asm.S
@@ -0,0 +1,125 @@
+/*
+ * Alpha optimized DSP utils
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
new file mode 100644
index 0000000000..1923ebbc5f
--- /dev/null
+++ b/libavcodec/alpha/idctdsp_alpha.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/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 ||
+ avctx->idct_algo == FF_IDCT_SIMPLEALPHA)) {
+ 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
new file mode 100644
index 0000000000..bf984950f2
--- /dev/null
+++ b/libavcodec/alpha/idctdsp_alpha.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_ALPHA_IDCTDSP_ALPHA_H
+#define AVCODEC_ALPHA_IDCTDSP_ALPHA_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+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, int line_size, int16_t *block);
+void ff_simple_idct_add_axp(uint8_t *dest, int 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
new file mode 100644
index 0000000000..f545df9e4f
--- /dev/null
+++ b/libavcodec/alpha/idctdsp_alpha_asm.S
@@ -0,0 +1,167 @@
+/*
+ * Alpha optimized IDCT-related routines
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
new file mode 100644
index 0000000000..8f360190f4
--- /dev/null
+++ b/libavcodec/alpha/me_cmp_alpha.c
@@ -0,0 +1,317 @@
+/*
+ * Alpha optimized DSP utils
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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(void *v, uint8_t *pix1, uint8_t *pix2, int 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(void *v, uint8_t *pix1, uint8_t *pix2, int 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;
+}
+
+#if 0 /* now done in assembly */
+int pix_abs16x16_mvi(uint8_t *pix1, uint8_t *pix2, int line_size)
+{
+ int result = 0;
+ int h = 16;
+
+ if ((size_t) pix2 & 0x7) {
+ /* works only when pix2 is actually unaligned */
+ do { /* do 16 pixel a time */
+ uint64_t p1_l, p1_r, p2_l, p2_r;
+ uint64_t t;
+
+ p1_l = ldq(pix1);
+ p1_r = ldq(pix1 + 8);
+ 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);
+ pix1 += line_size;
+ pix2 += line_size;
+
+ result += perr(p1_l, p2_l)
+ + perr(p1_r, p2_r);
+ } while (--h);
+ } else {
+ do {
+ uint64_t p1_l, p1_r, p2_l, p2_r;
+
+ p1_l = ldq(pix1);
+ p1_r = ldq(pix1 + 8);
+ p2_l = ldq(pix2);
+ p2_r = ldq(pix2 + 8);
+ pix1 += line_size;
+ pix2 += line_size;
+
+ result += perr(p1_l, p2_l)
+ + perr(p1_r, p2_r);
+ } while (--h);
+ }
+
+ return result;
+}
+#endif
+
+static int pix_abs16x16_x2_mvi(void *v, uint8_t *pix1, uint8_t *pix2, int 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(void *v, uint8_t *pix1, uint8_t *pix2, int 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(void *v, uint8_t *pix1, uint8_t *pix2, int 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
new file mode 100644
index 0000000000..2399085bcb
--- /dev/null
+++ b/libavcodec/alpha/me_cmp_mvi_asm.S
@@ -0,0 +1,179 @@
+/*
+ * Alpha optimized DSP utils
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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(uint8_t *pix1, 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
new file mode 100644
index 0000000000..126fe264a1
--- /dev/null
+++ b/libavcodec/alpha/mpegvideo_alpha.c
@@ -0,0 +1,110 @@
+/*
+ * Alpha optimized DSP utils
+ * Copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
new file mode 100644
index 0000000000..866b762b16
--- /dev/null
+++ b/libavcodec/alpha/pixblockdsp_alpha.c
@@ -0,0 +1,78 @@
+/*
+ * 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 line_size)
+{
+ int h = 8;
+
+ do {
+ uint64_t p;
+
+ p = ldq(pixels);
+ stq(unpkbw(p), block);
+ stq(unpkbw(p >> 32), block + 4);
+
+ pixels += line_size;
+ block += 8;
+ } while (--h);
+}
+
+static void diff_pixels_mvi(int16_t *block, const uint8_t *s1, const uint8_t *s2,
+ int 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
new file mode 100644
index 0000000000..f05577a89b
--- /dev/null
+++ b/libavcodec/alpha/regdef.h
@@ -0,0 +1,77 @@
+/*
+ * Alpha optimized DSP utils
+ * copyright (c) 2002 Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
new file mode 100644
index 0000000000..04be0cef06
--- /dev/null
+++ b/libavcodec/alpha/simple_idct_alpha.c
@@ -0,0 +1,303 @@
+/*
+ * Simple IDCT (Alpha optimized)
+ *
+ * Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * based upon some outcommented C code from mpeg2dec (idct_mmx.c
+ * written by Aaron Holtzman <aholtzma@ess.engr.uvic.ca>)
+ *
+ * Alpha optimizations by MĂ¥ns RullgĂ¥rd <mans@mansr.com>
+ * and Falk Hueffner <falk@debian.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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, int 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, int 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 1ade656118..75be55cc1e 100644
--- a/libavcodec/alsdec.c
+++ b/libavcodec/alsdec.c
@@ -1,28 +1,28 @@
/*
* MPEG-4 ALS decoder
- * Copyright (c) 2009 Thilo Borgmann <thilo.borgmann _at_ googlemail.com>
+ * Copyright (c) 2009 Thilo Borgmann <thilo.borgmann _at_ mail.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* MPEG-4 ALS decoder
- * @author Thilo Borgmann <thilo.borgmann _at_ googlemail.com>
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
*/
#include <inttypes.h>
@@ -199,6 +199,7 @@ typedef struct ALSDecContext {
unsigned int cur_frame_length; ///< length of the current frame to decode
unsigned int frame_id; ///< the frame ID / number of the current frame
unsigned int js_switch; ///< if true, joint-stereo decoding is enforced
+ unsigned int cs_switch; ///< if true, channel rearrangement is done
unsigned int num_blocks; ///< number of blocks used in the current frame
unsigned int s_max; ///< maximum Rice parameter allowed in entropy coding
uint8_t *bgmc_lut; ///< pointer at lookup tables used for BGMC
@@ -281,12 +282,14 @@ static av_cold int read_specific_config(ALSDecContext *ctx)
GetBitContext gb;
uint64_t ht_size;
int i, config_offset;
- MPEG4AudioConfig m4ac;
+ MPEG4AudioConfig m4ac = {0};
ALSSpecificConfig *sconf = &ctx->sconf;
AVCodecContext *avctx = ctx->avctx;
uint32_t als_id, header_size, trailer_size;
+ int ret;
- init_get_bits(&gb, avctx->extradata, avctx->extradata_size * 8);
+ if ((ret = init_get_bits8(&gb, avctx->extradata, avctx->extradata_size)) < 0)
+ return ret;
config_offset = avpriv_mpeg4audio_get_config(&m4ac, avctx->extradata,
avctx->extradata_size * 8, 1);
@@ -305,7 +308,7 @@ static av_cold int read_specific_config(ALSDecContext *ctx)
skip_bits_long(&gb, 32); // sample rate already known
sconf->samples = get_bits_long(&gb, 32);
avctx->channels = m4ac.channels;
- skip_bits(&gb, 16); // number of channels already knwon
+ skip_bits(&gb, 16); // number of channels already known
skip_bits(&gb, 3); // skip file_type
sconf->resolution = get_bits(&gb, 3);
sconf->floating = get_bits1(&gb);
@@ -349,16 +352,28 @@ static av_cold int read_specific_config(ALSDecContext *ctx)
if (get_bits_left(&gb) < bits_needed)
return AVERROR_INVALIDDATA;
- if (!(sconf->chan_pos = av_malloc(avctx->channels * sizeof(*sconf->chan_pos))))
+ if (!(sconf->chan_pos = av_malloc_array(avctx->channels, sizeof(*sconf->chan_pos))))
return AVERROR(ENOMEM);
- for (i = 0; i < avctx->channels; i++)
- sconf->chan_pos[i] = get_bits(&gb, chan_pos_bits);
+ ctx->cs_switch = 1;
+
+ for (i = 0; i < avctx->channels; i++) {
+ sconf->chan_pos[i] = -1;
+ }
+
+ for (i = 0; i < avctx->channels; i++) {
+ int idx;
+
+ idx = get_bits(&gb, chan_pos_bits);
+ if (idx >= avctx->channels || sconf->chan_pos[idx] != -1) {
+ av_log(avctx, AV_LOG_WARNING, "Invalid channel reordering.\n");
+ ctx->cs_switch = 0;
+ break;
+ }
+ sconf->chan_pos[idx] = i;
+ }
align_get_bits(&gb);
- // TODO: use this to actually do channel sorting
- } else {
- sconf->chan_sort = 0;
}
@@ -392,7 +407,7 @@ static av_cold int read_specific_config(ALSDecContext *ctx)
if (get_bits_left(&gb) < 32)
return AVERROR_INVALIDDATA;
- if (avctx->err_recognition & AV_EF_CRCCHECK) {
+ if (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL)) {
ctx->crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
ctx->crc = 0xFFFFFFFF;
ctx->crc_org = ~get_bits_long(&gb, 32);
@@ -428,7 +443,6 @@ static int check_specific_config(ALSDecContext *ctx)
MISSING_ERR(sconf->floating, "Floating point decoding", AVERROR_PATCHWELCOME);
MISSING_ERR(sconf->rlslms, "Adaptive RLS-LMS prediction", AVERROR_PATCHWELCOME);
- MISSING_ERR(sconf->chan_sort, "Channel sorting", 0);
return error;
}
@@ -551,12 +565,15 @@ static void get_block_sizes(ALSDecContext *ctx, unsigned int *div_blocks,
/** Read the block data for a constant block
*/
-static void read_const_block_data(ALSDecContext *ctx, ALSBlockData *bd)
+static int read_const_block_data(ALSDecContext *ctx, ALSBlockData *bd)
{
ALSSpecificConfig *sconf = &ctx->sconf;
AVCodecContext *avctx = ctx->avctx;
GetBitContext *gb = &ctx->gb;
+ if (bd->block_length <= 0)
+ return AVERROR_INVALIDDATA;
+
*bd->raw_samples = 0;
*bd->const_block = get_bits1(gb); // 1 = constant value, 0 = zero block (silence)
bd->js_blocks = get_bits1(gb);
@@ -571,6 +588,8 @@ static void read_const_block_data(ALSDecContext *ctx, ALSBlockData *bd)
// ensure constant block decoding by reusing this field
*bd->const_block = 1;
+
+ return 0;
}
@@ -669,13 +688,17 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd)
*bd->opt_order = get_bits(gb, opt_order_length);
if (*bd->opt_order > sconf->max_order) {
*bd->opt_order = sconf->max_order;
- av_log(avctx, AV_LOG_ERROR, "Predictor order too large!\n");
+ av_log(avctx, AV_LOG_ERROR, "Predictor order too large.\n");
return AVERROR_INVALIDDATA;
}
} else {
*bd->opt_order = sconf->max_order;
}
-
+ if (*bd->opt_order > bd->block_length) {
+ *bd->opt_order = bd->block_length;
+ av_log(avctx, AV_LOG_ERROR, "Predictor order too large.\n");
+ return AVERROR_INVALIDDATA;
+ }
opt_order = *bd->opt_order;
if (opt_order) {
@@ -706,7 +729,7 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd)
quant_cof[k] = decode_rice(gb, rice_param) + offset;
if (quant_cof[k] < -64 || quant_cof[k] > 63) {
av_log(avctx, AV_LOG_ERROR,
- "quant_cof %"PRIu32" is out of range\n",
+ "quant_cof %"PRIu32" is out of range.\n",
quant_cof[k]);
return AVERROR_INVALIDDATA;
}
@@ -964,7 +987,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd)
*/
static int read_block(ALSDecContext *ctx, ALSBlockData *bd)
{
- int ret = 0;
+ int ret;
GetBitContext *gb = &ctx->gb;
*bd->shift_lsbs = 0;
@@ -972,7 +995,7 @@ static int read_block(ALSDecContext *ctx, ALSBlockData *bd)
if (get_bits1(gb)) {
ret = read_var_block_data(ctx, bd);
} else {
- read_const_block_data(ctx, bd);
+ ret = read_const_block_data(ctx, bd);
}
return ret;
@@ -1026,8 +1049,8 @@ static void zero_remaining(unsigned int b, unsigned int b_max,
{
unsigned int count = 0;
- for (; b < b_max; b++)
- count += div_blocks[b];
+ while (b < b_max)
+ count += div_blocks[b++];
if (count)
memset(buf, 0, sizeof(*buf) * count);
@@ -1132,7 +1155,7 @@ static int decode_blocks(ALSDecContext *ctx, unsigned int ra_frame,
// reconstruct joint-stereo blocks
if (bd[0].js_blocks) {
if (bd[1].js_blocks)
- av_log(ctx->avctx, AV_LOG_WARNING, "Invalid channel pair!\n");
+ av_log(ctx->avctx, AV_LOG_WARNING, "Invalid channel pair.\n");
for (s = 0; s < div_blocks[b]; s++)
bd[0].raw_samples[s] = bd[1].raw_samples[s] - bd[0].raw_samples[s];
@@ -1180,7 +1203,7 @@ static int read_channel_data(ALSDecContext *ctx, ALSChannelData *cd, int c)
current->master_channel = get_bits_long(gb, av_ceil_log2(channels));
if (current->master_channel >= channels) {
- av_log(ctx->avctx, AV_LOG_ERROR, "Invalid master channel!\n");
+ av_log(ctx->avctx, AV_LOG_ERROR, "Invalid master channel.\n");
return AVERROR_INVALIDDATA;
}
@@ -1205,7 +1228,7 @@ static int read_channel_data(ALSDecContext *ctx, ALSChannelData *cd, int c)
}
if (entries == channels) {
- av_log(ctx->avctx, AV_LOG_ERROR, "Damaged channel data!\n");
+ av_log(ctx->avctx, AV_LOG_ERROR, "Damaged channel data.\n");
return AVERROR_INVALIDDATA;
}
@@ -1238,7 +1261,7 @@ static int revert_channel_correlation(ALSDecContext *ctx, ALSBlockData *bd,
}
if (dep == channels) {
- av_log(ctx->avctx, AV_LOG_WARNING, "Invalid channel correlation!\n");
+ av_log(ctx->avctx, AV_LOG_WARNING, "Invalid channel correlation.\n");
return AVERROR_INVALIDDATA;
}
@@ -1253,21 +1276,31 @@ static int revert_channel_correlation(ALSDecContext *ctx, ALSBlockData *bd,
bd->quant_cof = ctx->quant_cof[c];
bd->raw_samples = ctx->raw_samples[c] + offset;
- dep = 0;
- while (!ch[dep].stop_flag) {
+ for (dep = 0; !ch[dep].stop_flag; dep++) {
ptrdiff_t smp;
ptrdiff_t begin = 1;
ptrdiff_t end = bd->block_length - 1;
int64_t y;
int32_t *master = ctx->raw_samples[ch[dep].master_channel] + offset;
+ if (ch[dep].master_channel == c)
+ continue;
+
if (ch[dep].time_diff_flag) {
int t = ch[dep].time_diff_index;
if (ch[dep].time_diff_sign) {
t = -t;
+ if (begin < t) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "begin %td smaller than time diff index %d.\n", begin, t);
+ return AVERROR_INVALIDDATA;
+ }
begin -= t;
} else {
+ if (end < t) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "end %td smaller than time diff index %d.\n", end, t);
+ return AVERROR_INVALIDDATA;
+ }
end -= t;
}
@@ -1311,8 +1344,6 @@ static int revert_channel_correlation(ALSDecContext *ctx, ALSBlockData *bd,
bd->raw_samples[smp] += y >> 7;
}
}
-
- dep++;
}
return 0;
@@ -1387,7 +1418,7 @@ static int read_frame_data(ALSDecContext *ctx, unsigned int ra_frame)
for (c = 0; c < avctx->channels; c++)
if (ctx->chan_data[c] < ctx->chan_data_buffer) {
- av_log(ctx->avctx, AV_LOG_ERROR, "Invalid channel data!\n");
+ av_log(ctx->avctx, AV_LOG_ERROR, "Invalid channel data.\n");
return AVERROR_INVALIDDATA;
}
@@ -1443,6 +1474,7 @@ static int read_frame_data(ALSDecContext *ctx, unsigned int ra_frame)
bd.lpc_cof = ctx->lpc_cof[c];
bd.quant_cof = ctx->quant_cof[c];
bd.raw_samples = ctx->raw_samples[c] + offset;
+
if ((ret = decode_block(ctx, &bd)) < 0)
return ret;
}
@@ -1478,7 +1510,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr,
int invalid_frame, ret;
unsigned int c, sample, ra_frame, bytes_read, shift;
- init_get_bits(&ctx->gb, buffer, buffer_size * 8);
+ if ((ret = init_get_bits8(&ctx->gb, buffer, buffer_size)) < 0)
+ return ret;
// In the case that the distance between random access frames is set to zero
// (sconf->ra_distance == 0) no frame is treated as a random access frame.
@@ -1502,19 +1535,23 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr,
/* get output buffer */
frame->nb_samples = ctx->cur_frame_length;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
// transform decoded frame into output format
- #define INTERLEAVE_OUTPUT(bps) \
- { \
- int##bps##_t *dest = (int##bps##_t*)frame->data[0]; \
- shift = bps - ctx->avctx->bits_per_raw_sample; \
- for (sample = 0; sample < ctx->cur_frame_length; sample++) \
- for (c = 0; c < avctx->channels; c++) \
- *dest++ = ctx->raw_samples[c][sample] << shift; \
+ #define INTERLEAVE_OUTPUT(bps) \
+ { \
+ int##bps##_t *dest = (int##bps##_t*)frame->data[0]; \
+ shift = bps - ctx->avctx->bits_per_raw_sample; \
+ if (!ctx->cs_switch) { \
+ for (sample = 0; sample < ctx->cur_frame_length; sample++) \
+ for (c = 0; c < avctx->channels; c++) \
+ *dest++ = ctx->raw_samples[c][sample] << shift; \
+ } else { \
+ for (sample = 0; sample < ctx->cur_frame_length; sample++) \
+ for (c = 0; c < avctx->channels; c++) \
+ *dest++ = ctx->raw_samples[sconf->chan_pos[c]][sample] << shift; \
+ } \
}
if (ctx->avctx->bits_per_raw_sample <= 16) {
@@ -1524,7 +1561,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr,
}
// update CRC
- if (sconf->crc_enabled && (avctx->err_recognition & AV_EF_CRCCHECK)) {
+ if (sconf->crc_enabled && (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL))) {
int swap = HAVE_BIGENDIAN != sconf->msb_first;
if (ctx->avctx->bits_per_raw_sample == 24) {
@@ -1681,14 +1718,14 @@ static av_cold int decode_init(AVCodecContext *avctx)
// allocate quantized parcor coefficient buffer
num_buffers = sconf->mc_coding ? avctx->channels : 1;
- ctx->quant_cof = av_malloc(sizeof(*ctx->quant_cof) * num_buffers);
- ctx->lpc_cof = av_malloc(sizeof(*ctx->lpc_cof) * num_buffers);
- ctx->quant_cof_buffer = av_malloc(sizeof(*ctx->quant_cof_buffer) *
- num_buffers * sconf->max_order);
- ctx->lpc_cof_buffer = av_malloc(sizeof(*ctx->lpc_cof_buffer) *
- num_buffers * sconf->max_order);
- ctx->lpc_cof_reversed_buffer = av_malloc(sizeof(*ctx->lpc_cof_buffer) *
- sconf->max_order);
+ ctx->quant_cof = av_malloc_array(num_buffers, sizeof(*ctx->quant_cof));
+ ctx->lpc_cof = av_malloc_array(num_buffers, sizeof(*ctx->lpc_cof));
+ ctx->quant_cof_buffer = av_malloc_array(num_buffers * sconf->max_order,
+ sizeof(*ctx->quant_cof_buffer));
+ ctx->lpc_cof_buffer = av_malloc_array(num_buffers * sconf->max_order,
+ sizeof(*ctx->lpc_cof_buffer));
+ ctx->lpc_cof_reversed_buffer = av_malloc_array(sconf->max_order,
+ sizeof(*ctx->lpc_cof_buffer));
if (!ctx->quant_cof || !ctx->lpc_cof ||
!ctx->quant_cof_buffer || !ctx->lpc_cof_buffer ||
@@ -1705,15 +1742,14 @@ static av_cold int decode_init(AVCodecContext *avctx)
}
// allocate and assign lag and gain data buffer for ltp mode
- ctx->const_block = av_malloc (sizeof(*ctx->const_block) * num_buffers);
- ctx->shift_lsbs = av_malloc (sizeof(*ctx->shift_lsbs) * num_buffers);
- ctx->opt_order = av_malloc (sizeof(*ctx->opt_order) * num_buffers);
- ctx->store_prev_samples = av_malloc(sizeof(*ctx->store_prev_samples) * num_buffers);
- ctx->use_ltp = av_mallocz(sizeof(*ctx->use_ltp) * num_buffers);
- ctx->ltp_lag = av_malloc (sizeof(*ctx->ltp_lag) * num_buffers);
- ctx->ltp_gain = av_malloc (sizeof(*ctx->ltp_gain) * num_buffers);
- ctx->ltp_gain_buffer = av_malloc (sizeof(*ctx->ltp_gain_buffer) *
- num_buffers * 5);
+ ctx->const_block = av_malloc_array(num_buffers, sizeof(*ctx->const_block));
+ ctx->shift_lsbs = av_malloc_array(num_buffers, sizeof(*ctx->shift_lsbs));
+ ctx->opt_order = av_malloc_array(num_buffers, sizeof(*ctx->opt_order));
+ ctx->store_prev_samples = av_malloc_array(num_buffers, sizeof(*ctx->store_prev_samples));
+ ctx->use_ltp = av_mallocz_array(num_buffers, sizeof(*ctx->use_ltp));
+ ctx->ltp_lag = av_malloc_array(num_buffers, sizeof(*ctx->ltp_lag));
+ ctx->ltp_gain = av_malloc_array(num_buffers, sizeof(*ctx->ltp_gain));
+ ctx->ltp_gain_buffer = av_malloc_array(num_buffers * 5, sizeof(*ctx->ltp_gain_buffer));
if (!ctx->const_block || !ctx->shift_lsbs ||
!ctx->opt_order || !ctx->store_prev_samples ||
@@ -1729,12 +1765,12 @@ static av_cold int decode_init(AVCodecContext *avctx)
// allocate and assign channel data buffer for mcc mode
if (sconf->mc_coding) {
- ctx->chan_data_buffer = av_malloc(sizeof(*ctx->chan_data_buffer) *
- num_buffers * num_buffers);
- ctx->chan_data = av_malloc(sizeof(*ctx->chan_data) *
- num_buffers);
- ctx->reverted_channels = av_malloc(sizeof(*ctx->reverted_channels) *
- num_buffers);
+ ctx->chan_data_buffer = av_mallocz_array(num_buffers * num_buffers,
+ sizeof(*ctx->chan_data_buffer));
+ ctx->chan_data = av_mallocz_array(num_buffers,
+ sizeof(*ctx->chan_data));
+ ctx->reverted_channels = av_malloc_array(num_buffers,
+ sizeof(*ctx->reverted_channels));
if (!ctx->chan_data_buffer || !ctx->chan_data || !ctx->reverted_channels) {
av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
@@ -1752,9 +1788,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
channel_size = sconf->frame_length + sconf->max_order;
- ctx->prev_raw_samples = av_malloc (sizeof(*ctx->prev_raw_samples) * sconf->max_order);
- ctx->raw_buffer = av_mallocz(sizeof(*ctx-> raw_buffer) * avctx->channels * channel_size);
- ctx->raw_samples = av_malloc (sizeof(*ctx-> raw_samples) * avctx->channels);
+ ctx->prev_raw_samples = av_malloc_array(sconf->max_order, sizeof(*ctx->prev_raw_samples));
+ ctx->raw_buffer = av_mallocz_array(avctx->channels * channel_size, sizeof(*ctx->raw_buffer));
+ ctx->raw_samples = av_malloc_array(avctx->channels, sizeof(*ctx->raw_samples));
// allocate previous raw sample buffer
if (!ctx->prev_raw_samples || !ctx->raw_buffer|| !ctx->raw_samples) {
@@ -1770,11 +1806,11 @@ static av_cold int decode_init(AVCodecContext *avctx)
// allocate crc buffer
if (HAVE_BIGENDIAN != sconf->msb_first && sconf->crc_enabled &&
- (avctx->err_recognition & AV_EF_CRCCHECK)) {
- ctx->crc_buffer = av_malloc(sizeof(*ctx->crc_buffer) *
- ctx->cur_frame_length *
- avctx->channels *
- av_get_bytes_per_sample(avctx->sample_fmt));
+ (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL))) {
+ ctx->crc_buffer = av_malloc_array(ctx->cur_frame_length *
+ avctx->channels *
+ av_get_bytes_per_sample(avctx->sample_fmt),
+ sizeof(*ctx->crc_buffer));
if (!ctx->crc_buffer) {
av_log(avctx, AV_LOG_ERROR, "Allocating buffer memory failed.\n");
ret = AVERROR(ENOMEM);
diff --git a/libavcodec/amr.h b/libavcodec/amr.h
index 676c9630df..1ac73abe86 100644
--- a/libavcodec/amr.h
+++ b/libavcodec/amr.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Marcelo Galvao Povoa
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/amrnbdata.h b/libavcodec/amrnbdata.h
index b7d1b89608..435fd9924b 100644
--- a/libavcodec/amrnbdata.h
+++ b/libavcodec/amrnbdata.h
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Robert Swain
* Copyright (c) 2009 Colin McQuillan
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -1655,10 +1655,10 @@ static const float ir_filter_medium[AMR_SUBFRAME_SIZE] = {
0.016998, 0.023804, -0.041779, 0.025696, 0.019989,
};
-static const float *ir_filters_lookup[2] = {
+static const float * const ir_filters_lookup[2] = {
ir_filter_strong, ir_filter_medium
};
-static const float *ir_filters_lookup_MODE_7k95[2] = {
+static const float * const ir_filters_lookup_MODE_7k95[2] = {
ir_filter_strong_MODE_7k95, ir_filter_medium
};
diff --git a/libavcodec/amrnbdec.c b/libavcodec/amrnbdec.c
index 7692cf01c6..3fa639de27 100644
--- a/libavcodec/amrnbdec.c
+++ b/libavcodec/amrnbdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Robert Swain
* Copyright (c) 2009 Colin McQuillan
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,6 +47,8 @@
#include "libavutil/float_dsp.h"
#include "avcodec.h"
#include "libavutil/common.h"
+#include "libavutil/avassert.h"
+#include "celp_math.h"
#include "celp_filters.h"
#include "acelp_filters.h"
#include "acelp_vectors.h"
@@ -84,7 +86,7 @@
/** Maximum sharpening factor
*
* The specification says 0.8, which should be 13107, but the reference C code
- * uses 13017 instead. (Amusingly the same applies to SHARP_MAX in bitexact G.729.)
+ * uses 13017 instead. (Amusingly the same applies to SHARP_MAX in g729dec.c.)
*/
#define SHARP_MAX 0.79449462890625
@@ -136,6 +138,11 @@ typedef struct AMRContext {
float samples_in[LP_FILTER_ORDER + AMR_SUBFRAME_SIZE]; ///< floating point samples
+ ACELPFContext acelpf_ctx; ///< context for filters for ACELP-based codecs
+ ACELPVContext acelpv_ctx; ///< context for vector operations for ACELP-based codecs
+ CELPFContext celpf_ctx; ///< context for filters for CELP-based codecs
+ CELPMContext celpm_ctx; ///< context for fixed point math operations
+
} AMRContext;
/** Double version of ff_weighted_vector_sumf() */
@@ -162,7 +169,8 @@ static av_cold int amrnb_decode_init(AVCodecContext *avctx)
avctx->channels = 1;
avctx->channel_layout = AV_CH_LAYOUT_MONO;
- avctx->sample_rate = 8000;
+ if (!avctx->sample_rate)
+ avctx->sample_rate = 8000;
avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
// p->excitation always points to the same position in p->excitation_buf
@@ -176,6 +184,11 @@ static av_cold int amrnb_decode_init(AVCodecContext *avctx)
for (i = 0; i < 4; i++)
p->prediction_error[i] = MIN_ENERGY;
+ ff_acelp_filter_init(&p->acelpf_ctx);
+ ff_acelp_vectors_init(&p->acelpv_ctx);
+ ff_celp_filter_init(&p->celpf_ctx);
+ ff_celp_math_init(&p->celpm_ctx);
+
return 0;
}
@@ -219,15 +232,16 @@ static enum Mode unpack_bitstream(AMRContext *p, const uint8_t *buf,
* Interpolate the LSF vector (used for fixed gain smoothing).
* The interpolation is done over all four subframes even in MODE_12k2.
*
+ * @param[in] ctx The Context
* @param[in,out] lsf_q LSFs in [0,1] for each subframe
* @param[in] lsf_new New LSFs in [0,1] for subframe 4
*/
-static void interpolate_lsf(float lsf_q[4][LP_FILTER_ORDER], float *lsf_new)
+static void interpolate_lsf(ACELPVContext *ctx, float lsf_q[4][LP_FILTER_ORDER], float *lsf_new)
{
int i;
for (i = 0; i < 4; i++)
- ff_weighted_vector_sumf(lsf_q[i], lsf_q[3], lsf_new,
+ ctx->weighted_vector_sumf(lsf_q[i], lsf_q[3], lsf_new,
0.25 * (3 - i), 0.25 * (i + 1),
LP_FILTER_ORDER);
}
@@ -271,7 +285,7 @@ static void lsf2lsp_for_mode12k2(AMRContext *p, double lsp[LP_FILTER_ORDER],
ff_set_min_dist_lsf(lsf_q, MIN_LSF_SPACING, LP_FILTER_ORDER);
if (update)
- interpolate_lsf(p->lsf_q, lsf_q);
+ interpolate_lsf(&p->acelpv_ctx, p->lsf_q, lsf_q);
ff_acelp_lsf2lspd(lsp, lsf_q, LP_FILTER_ORDER);
}
@@ -334,7 +348,7 @@ static void lsf2lsp_3(AMRContext *p)
ff_set_min_dist_lsf(lsf_q, MIN_LSF_SPACING, LP_FILTER_ORDER);
// store data for computing the next frame's LSFs
- interpolate_lsf(p->lsf_q, lsf_q);
+ interpolate_lsf(&p->acelpv_ctx, p->lsf_q, lsf_q);
memcpy(p->prev_lsf_r, lsf_r, LP_FILTER_ORDER * sizeof(*lsf_r));
ff_acelp_lsf2lspd(p->lsp[3], lsf_q, LP_FILTER_ORDER);
@@ -385,22 +399,23 @@ static void decode_pitch_vector(AMRContext *p,
decode_pitch_lag_1_6(&pitch_lag_int, &pitch_lag_frac,
amr_subframe->p_lag, p->pitch_lag_int,
subframe);
- } else
+ } else {
ff_decode_pitch_lag(&pitch_lag_int, &pitch_lag_frac,
amr_subframe->p_lag,
p->pitch_lag_int, subframe,
mode != MODE_4k75 && mode != MODE_5k15,
mode <= MODE_6k7 ? 4 : (mode == MODE_7k95 ? 5 : 6));
+ pitch_lag_frac *= 2;
+ }
p->pitch_lag_int = pitch_lag_int; // store previous lag in a uint8_t
- pitch_lag_frac <<= (p->cur_frame_mode != MODE_12k2);
-
pitch_lag_int += pitch_lag_frac > 0;
/* Calculate the pitch vector by interpolating the past excitation at the
pitch lag using a b60 hamming windowed sinc function. */
- ff_acelp_interpolatef(p->excitation, p->excitation + 1 - pitch_lag_int,
+ p->acelpf_ctx.acelp_interpolatef(p->excitation,
+ p->excitation + 1 - pitch_lag_int,
ff_b60_sinc, 6,
pitch_lag_frac + 6 - 6*(pitch_lag_frac > 0),
10, AMR_SUBFRAME_SIZE);
@@ -484,7 +499,7 @@ static void decode_8_pulses_31bits(const int16_t *fixed_index,
static void decode_fixed_sparse(AMRFixed *fixed_sparse, const uint16_t *pulses,
const enum Mode mode, const int subframe)
{
- assert(MODE_4k75 <= mode && mode <= MODE_12k2);
+ av_assert1(MODE_4k75 <= (signed)mode && mode <= MODE_12k2);
if (mode == MODE_12k2) {
ff_decode_10_pulses_35bits(pulses, fixed_sparse, gray_decode, 5, 3);
@@ -785,12 +800,12 @@ static int synthesis(AMRContext *p, float *lpc,
for (i = 0; i < AMR_SUBFRAME_SIZE; i++)
p->pitch_vector[i] *= 0.25;
- ff_weighted_vector_sumf(excitation, p->pitch_vector, fixed_vector,
+ p->acelpv_ctx.weighted_vector_sumf(excitation, p->pitch_vector, fixed_vector,
p->pitch_gain[4], fixed_gain, AMR_SUBFRAME_SIZE);
// emphasize pitch vector contribution
if (p->pitch_gain[4] > 0.5 && !overflow) {
- float energy = avpriv_scalarproduct_float_c(excitation, excitation,
+ float energy = p->celpm_ctx.dot_productf(excitation, excitation,
AMR_SUBFRAME_SIZE);
float pitch_factor =
p->pitch_gain[4] *
@@ -805,7 +820,8 @@ static int synthesis(AMRContext *p, float *lpc,
AMR_SUBFRAME_SIZE);
}
- ff_celp_lp_synthesis_filterf(samples, lpc, excitation, AMR_SUBFRAME_SIZE,
+ p->celpf_ctx.celp_lp_synthesis_filterf(samples, lpc, excitation,
+ AMR_SUBFRAME_SIZE,
LP_FILTER_ORDER);
// detect overflow
@@ -851,10 +867,11 @@ static void update_state(AMRContext *p)
/**
* Get the tilt factor of a formant filter from its transfer function
*
+ * @param p The Context
* @param lpc_n LP_FILTER_ORDER coefficients of the numerator
* @param lpc_d LP_FILTER_ORDER coefficients of the denominator
*/
-static float tilt_factor(float *lpc_n, float *lpc_d)
+static float tilt_factor(AMRContext *p, float *lpc_n, float *lpc_d)
{
float rh0, rh1; // autocorrelation at lag 0 and 1
@@ -864,11 +881,12 @@ static float tilt_factor(float *lpc_n, float *lpc_d)
hf[0] = 1.0;
memcpy(hf + 1, lpc_n, sizeof(float) * LP_FILTER_ORDER);
- ff_celp_lp_synthesis_filterf(hf, lpc_d, hf, AMR_TILT_RESPONSE,
+ p->celpf_ctx.celp_lp_synthesis_filterf(hf, lpc_d, hf,
+ AMR_TILT_RESPONSE,
LP_FILTER_ORDER);
- rh0 = avpriv_scalarproduct_float_c(hf, hf, AMR_TILT_RESPONSE);
- rh1 = avpriv_scalarproduct_float_c(hf, hf + 1, AMR_TILT_RESPONSE - 1);
+ rh0 = p->celpm_ctx.dot_productf(hf, hf, AMR_TILT_RESPONSE);
+ rh1 = p->celpm_ctx.dot_productf(hf, hf + 1, AMR_TILT_RESPONSE - 1);
// The spec only specifies this check for 12.2 and 10.2 kbit/s
// modes. But in the ref source the tilt is always non-negative.
@@ -888,7 +906,7 @@ static void postfilter(AMRContext *p, float *lpc, float *buf_out)
int i;
float *samples = p->samples_in + LP_FILTER_ORDER; // Start of input
- float speech_gain = avpriv_scalarproduct_float_c(samples, samples,
+ float speech_gain = p->celpm_ctx.dot_productf(samples, samples,
AMR_SUBFRAME_SIZE);
float pole_out[AMR_SUBFRAME_SIZE + LP_FILTER_ORDER]; // Output of pole filter
@@ -909,16 +927,16 @@ static void postfilter(AMRContext *p, float *lpc, float *buf_out)
}
memcpy(pole_out, p->postfilter_mem, sizeof(float) * LP_FILTER_ORDER);
- ff_celp_lp_synthesis_filterf(pole_out + LP_FILTER_ORDER, lpc_d, samples,
+ p->celpf_ctx.celp_lp_synthesis_filterf(pole_out + LP_FILTER_ORDER, lpc_d, samples,
AMR_SUBFRAME_SIZE, LP_FILTER_ORDER);
memcpy(p->postfilter_mem, pole_out + AMR_SUBFRAME_SIZE,
sizeof(float) * LP_FILTER_ORDER);
- ff_celp_lp_zero_synthesis_filterf(buf_out, lpc_n,
+ p->celpf_ctx.celp_lp_zero_synthesis_filterf(buf_out, lpc_n,
pole_out + LP_FILTER_ORDER,
AMR_SUBFRAME_SIZE, LP_FILTER_ORDER);
- ff_tilt_compensation(&p->tilt_mem, tilt_factor(lpc_n, lpc_d), buf_out,
+ ff_tilt_compensation(&p->tilt_mem, tilt_factor(p, lpc_n, lpc_d), buf_out,
AMR_SUBFRAME_SIZE);
ff_adaptive_gain_control(buf_out, buf_out, speech_gain, AMR_SUBFRAME_SIZE,
@@ -945,10 +963,8 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = AMR_BLOCK_SIZE;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
buf_out = (float *)frame->data[0];
p->cur_frame_mode = unpack_bitstream(p, buf, buf_size);
@@ -957,7 +973,8 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
if (p->cur_frame_mode == MODE_DTX) {
- avpriv_request_sample(avctx, "dtx mode");
+ avpriv_report_missing_feature(avctx, "dtx mode");
+ av_log(avctx, AV_LOG_INFO, "Note: libopencore_amrnb supports dtx\n");
return AVERROR_PATCHWELCOME;
}
@@ -995,7 +1012,7 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data,
p->fixed_gain[4] =
ff_amr_set_fixed_gain(fixed_gain_factor,
- avpriv_scalarproduct_float_c(p->fixed_vector,
+ p->celpm_ctx.dot_productf(p->fixed_vector,
p->fixed_vector,
AMR_SUBFRAME_SIZE) /
AMR_SUBFRAME_SIZE,
@@ -1041,7 +1058,8 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data,
update_state(p);
}
- ff_acelp_apply_order_2_transfer_function(buf_out, buf_out, highpass_zeros,
+ p->acelpf_ctx.acelp_apply_order_2_transfer_function(buf_out,
+ buf_out, highpass_zeros,
highpass_poles,
highpass_gain * AMR_SAMPLE_SCALE,
p->high_pass_mem, AMR_BLOCK_SIZE);
@@ -1052,7 +1070,7 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data,
* for fixed_gain_smooth.
* The specification has an incorrect formula: the reference decoder uses
* qbar(n-1) rather than qbar(n) in section 6.1(4) equation 71. */
- ff_weighted_vector_sumf(p->lsf_avg, p->lsf_avg, p->lsf_q[3],
+ p->acelpv_ctx.weighted_vector_sumf(p->lsf_avg, p->lsf_avg, p->lsf_q[3],
0.84, 0.16, LP_FILTER_ORDER);
*got_frame_ptr = 1;
diff --git a/libavcodec/amrwbdata.h b/libavcodec/amrwbdata.h
index 81f8b47d1b..8390582b05 100644
--- a/libavcodec/amrwbdata.h
+++ b/libavcodec/amrwbdata.h
@@ -2,20 +2,20 @@
* AMR wideband data and definitions
* Copyright (c) 2010 Marcelo Galvao Povoa
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -1805,7 +1805,7 @@ static const float ir_filter_mid[64] = {
-7.501221e-02, 2.920532e-02, 1.660156e-02, 7.751465e-02
};
-static const float *ir_filters_lookup[2] = {
+static const float * const ir_filters_lookup[2] = {
ir_filter_str, ir_filter_mid
};
diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c
index 5ef22d3d4d..8771a2afc2 100644
--- a/libavcodec/amrwbdec.c
+++ b/libavcodec/amrwbdec.c
@@ -2,20 +2,20 @@
* AMR wideband decoder
* Copyright (c) 2010 Marcelo Galvao Povoa
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A particular PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,7 @@
#include "avcodec.h"
#include "lsp.h"
#include "celp_filters.h"
+#include "celp_math.h"
#include "acelp_filters.h"
#include "acelp_vectors.h"
#include "acelp_pitch_delay.h"
@@ -41,6 +42,7 @@
#include "amr.h"
#include "amrwbdata.h"
+#include "mips/amrwbdec_mips.h"
typedef struct AMRWBContext {
AMRWBFrame frame; ///< AMRWB parameters decoded from bitstream
@@ -84,6 +86,11 @@ typedef struct AMRWBContext {
AVLFG prng; ///< random number generator for white noise excitation
uint8_t first_frame; ///< flag active during decoding of the first frame
+ ACELPFContext acelpf_ctx; ///< context for filters for ACELP-based codecs
+ ACELPVContext acelpv_ctx; ///< context for vector operations for ACELP-based codecs
+ CELPFContext celpf_ctx; ///< context for filters for CELP-based codecs
+ CELPMContext celpm_ctx; ///< context for fixed point math operations
+
} AMRWBContext;
static av_cold int amrwb_decode_init(AVCodecContext *avctx)
@@ -98,7 +105,8 @@ static av_cold int amrwb_decode_init(AVCodecContext *avctx)
avctx->channels = 1;
avctx->channel_layout = AV_CH_LAYOUT_MONO;
- avctx->sample_rate = 16000;
+ if (!avctx->sample_rate)
+ avctx->sample_rate = 16000;
avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
av_lfg_init(&ctx->prng, 1);
@@ -112,6 +120,11 @@ static av_cold int amrwb_decode_init(AVCodecContext *avctx)
for (i = 0; i < 4; i++)
ctx->prediction_error[i] = MIN_ENERGY;
+ ff_acelp_filter_init(&ctx->acelpf_ctx);
+ ff_acelp_vectors_init(&ctx->acelpv_ctx);
+ ff_celp_filter_init(&ctx->celpf_ctx);
+ ff_celp_math_init(&ctx->celpm_ctx);
+
return 0;
}
@@ -326,7 +339,8 @@ static void decode_pitch_vector(AMRWBContext *ctx,
/* Calculate the pitch vector by interpolating the past excitation at the
pitch lag using a hamming windowed sinc function */
- ff_acelp_interpolatef(exc, exc + 1 - pitch_lag_int,
+ ctx->acelpf_ctx.acelp_interpolatef(exc,
+ exc + 1 - pitch_lag_int,
ac_inter, 4,
pitch_lag_frac + (pitch_lag_frac > 0 ? 0 : 4),
LP_ORDER, AMRWB_SFR_SIZE + 1);
@@ -585,16 +599,18 @@ static void pitch_sharpening(AMRWBContext *ctx, float *fixed_vector)
*
* @param[in] p_vector, f_vector Pitch and fixed excitation vectors
* @param[in] p_gain, f_gain Pitch and fixed gains
+ * @param[in] ctx The context
*/
// XXX: There is something wrong with the precision here! The magnitudes
// of the energies are not correct. Please check the reference code carefully
static float voice_factor(float *p_vector, float p_gain,
- float *f_vector, float f_gain)
+ float *f_vector, float f_gain,
+ CELPMContext *ctx)
{
- double p_ener = (double) avpriv_scalarproduct_float_c(p_vector, p_vector,
+ double p_ener = (double) ctx->dot_productf(p_vector, p_vector,
AMRWB_SFR_SIZE) *
p_gain * p_gain;
- double f_ener = (double) avpriv_scalarproduct_float_c(f_vector, f_vector,
+ double f_ener = (double) ctx->dot_productf(f_vector, f_vector,
AMRWB_SFR_SIZE) *
f_gain * f_gain;
@@ -758,13 +774,13 @@ static void synthesis(AMRWBContext *ctx, float *lpc, float *excitation,
float fixed_gain, const float *fixed_vector,
float *samples)
{
- ff_weighted_vector_sumf(excitation, ctx->pitch_vector, fixed_vector,
+ ctx->acelpv_ctx.weighted_vector_sumf(excitation, ctx->pitch_vector, fixed_vector,
ctx->pitch_gain[0], fixed_gain, AMRWB_SFR_SIZE);
/* emphasize pitch vector contribution in low bitrate modes */
if (ctx->pitch_gain[0] > 0.5 && ctx->fr_cur_mode <= MODE_8k85) {
int i;
- float energy = avpriv_scalarproduct_float_c(excitation, excitation,
+ float energy = ctx->celpm_ctx.dot_productf(excitation, excitation,
AMRWB_SFR_SIZE);
// XXX: Weird part in both ref code and spec. A unknown parameter
@@ -778,7 +794,7 @@ static void synthesis(AMRWBContext *ctx, float *lpc, float *excitation,
energy, AMRWB_SFR_SIZE);
}
- ff_celp_lp_synthesis_filterf(samples, lpc, excitation,
+ ctx->celpf_ctx.celp_lp_synthesis_filterf(samples, lpc, excitation,
AMRWB_SFR_SIZE, LP_ORDER);
}
@@ -810,8 +826,9 @@ static void de_emphasis(float *out, float *in, float m, float mem[1])
* @param[out] out Buffer for interpolated signal
* @param[in] in Current signal data (length 0.8*o_size)
* @param[in] o_size Output signal length
+ * @param[in] ctx The context
*/
-static void upsample_5_4(float *out, const float *in, int o_size)
+static void upsample_5_4(float *out, const float *in, int o_size, CELPMContext *ctx)
{
const float *in0 = in - UPS_FIR_SIZE + 1;
int i, j, k;
@@ -824,7 +841,7 @@ static void upsample_5_4(float *out, const float *in, int o_size)
i++;
for (k = 1; k < 5; k++) {
- out[i] = avpriv_scalarproduct_float_c(in0 + int_part,
+ out[i] = ctx->dot_productf(in0 + int_part,
upsample_fir[4 - frac_part],
UPS_MEM_SIZE);
int_part++;
@@ -852,8 +869,8 @@ static float find_hb_gain(AMRWBContext *ctx, const float *synth,
if (ctx->fr_cur_mode == MODE_23k85)
return qua_hb_gain[hb_idx] * (1.0f / (1 << 14));
- tilt = avpriv_scalarproduct_float_c(synth, synth + 1, AMRWB_SFR_SIZE - 1) /
- avpriv_scalarproduct_float_c(synth, synth, AMRWB_SFR_SIZE);
+ tilt = ctx->celpm_ctx.dot_productf(synth, synth + 1, AMRWB_SFR_SIZE - 1) /
+ ctx->celpm_ctx.dot_productf(synth, synth, AMRWB_SFR_SIZE);
/* return gain bounded by [0.1, 1.0] */
return av_clipf((1.0 - FFMAX(0.0, tilt)) * (1.25 - 0.25 * wsp), 0.1, 1.0);
@@ -872,7 +889,7 @@ static void scaled_hb_excitation(AMRWBContext *ctx, float *hb_exc,
const float *synth_exc, float hb_gain)
{
int i;
- float energy = avpriv_scalarproduct_float_c(synth_exc, synth_exc,
+ float energy = ctx->celpm_ctx.dot_productf(synth_exc, synth_exc,
AMRWB_SFR_SIZE);
/* Generate a white-noise excitation */
@@ -1003,7 +1020,7 @@ static void hb_synthesis(AMRWBContext *ctx, int subframe, float *samples,
float e_isf[LP_ORDER_16k]; // ISF vector for extrapolation
double e_isp[LP_ORDER_16k];
- ff_weighted_vector_sumf(e_isf, isf_past, isf, isfp_inter[subframe],
+ ctx->acelpv_ctx.weighted_vector_sumf(e_isf, isf_past, isf, isfp_inter[subframe],
1.0 - isfp_inter[subframe], LP_ORDER);
extrapolate_isf(e_isf);
@@ -1017,7 +1034,7 @@ static void hb_synthesis(AMRWBContext *ctx, int subframe, float *samples,
lpc_weighting(hb_lpc, ctx->lp_coef[subframe], 0.6, LP_ORDER);
}
- ff_celp_lp_synthesis_filterf(samples, hb_lpc, exc, AMRWB_SFR_SIZE_16k,
+ ctx->celpf_ctx.celp_lp_synthesis_filterf(samples, hb_lpc, exc, AMRWB_SFR_SIZE_16k,
(mode == MODE_6k60) ? LP_ORDER_16k : LP_ORDER);
}
@@ -1032,6 +1049,8 @@ static void hb_synthesis(AMRWBContext *ctx, int subframe, float *samples,
*
* @remark It is safe to pass the same array in in and out parameters
*/
+
+#ifndef hb_fir_filter
static void hb_fir_filter(float *out, const float fir_coef[HB_FIR_SIZE + 1],
float mem[HB_FIR_SIZE], const float *in)
{
@@ -1049,6 +1068,7 @@ static void hb_fir_filter(float *out, const float fir_coef[HB_FIR_SIZE + 1],
memcpy(mem, data + AMRWB_SFR_SIZE_16k, HB_FIR_SIZE * sizeof(float));
}
+#endif /* hb_fir_filter */
/**
* Update context state before the next subframe.
@@ -1092,10 +1112,8 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = 4 * AMRWB_SFR_SIZE_16k;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
buf_out = (float *)frame->data[0];
header_size = decode_mime_header(ctx, buf);
@@ -1166,7 +1184,7 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data,
ctx->fixed_gain[0] =
ff_amr_set_fixed_gain(fixed_gain_factor,
- avpriv_scalarproduct_float_c(ctx->fixed_vector,
+ ctx->celpm_ctx.dot_productf(ctx->fixed_vector,
ctx->fixed_vector,
AMRWB_SFR_SIZE) /
AMRWB_SFR_SIZE,
@@ -1175,7 +1193,8 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data,
/* Calculate voice factor and store tilt for next subframe */
voice_fac = voice_factor(ctx->pitch_vector, ctx->pitch_gain[0],
- ctx->fixed_vector, ctx->fixed_gain[0]);
+ ctx->fixed_vector, ctx->fixed_gain[0],
+ &ctx->celpm_ctx);
ctx->tilt_coef = voice_fac * 0.25 + 0.25;
/* Construct current excitation */
@@ -1201,15 +1220,15 @@ static int amrwb_decode_frame(AVCodecContext *avctx, void *data,
de_emphasis(&ctx->samples_up[UPS_MEM_SIZE],
&ctx->samples_az[LP_ORDER], PREEMPH_FAC, ctx->demph_mem);
- ff_acelp_apply_order_2_transfer_function(&ctx->samples_up[UPS_MEM_SIZE],
+ ctx->acelpf_ctx.acelp_apply_order_2_transfer_function(&ctx->samples_up[UPS_MEM_SIZE],
&ctx->samples_up[UPS_MEM_SIZE], hpf_zeros, hpf_31_poles,
hpf_31_gain, ctx->hpf_31_mem, AMRWB_SFR_SIZE);
upsample_5_4(sub_buf, &ctx->samples_up[UPS_FIR_SIZE],
- AMRWB_SFR_SIZE_16k);
+ AMRWB_SFR_SIZE_16k, &ctx->celpm_ctx);
/* High frequency band (6.4 - 7.0 kHz) generation part */
- ff_acelp_apply_order_2_transfer_function(hb_samples,
+ ctx->acelpf_ctx.acelp_apply_order_2_transfer_function(hb_samples,
&ctx->samples_up[UPS_MEM_SIZE], hpf_zeros, hpf_400_poles,
hpf_400_gain, ctx->hpf_400_mem, AMRWB_SFR_SIZE);
diff --git a/libavcodec/anm.c b/libavcodec/anm.c
index 3d5affbd63..3727534729 100644
--- a/libavcodec/anm.c
+++ b/libavcodec/anm.c
@@ -2,20 +2,20 @@
* Deluxe Paint Animation decoder
* Copyright (c) 2009 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,8 +47,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size);
- if (bytestream2_get_bytes_left(&s->gb) < 16 * 8 + 4 * 256)
+ if (bytestream2_get_bytes_left(&s->gb) < 16 * 8 + 4 * 256) {
+ av_frame_free(&s->frame);
return AVERROR_INVALIDDATA;
+ }
bytestream2_skipu(&s->gb, 16 * 8);
for (i = 0; i < 256; i++)
@@ -117,10 +119,8 @@ static int decode_frame(AVCodecContext *avctx,
uint8_t *dst, *dst_end;
int count, ret;
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0){
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
dst = s->frame->data[0];
dst_end = s->frame->data[0] + s->frame->linesize[0]*avctx->height;
@@ -128,11 +128,11 @@ static int decode_frame(AVCodecContext *avctx,
if (bytestream2_get_byte(&s->gb) != 0x42) {
avpriv_request_sample(avctx, "Unknown record type");
- return buf_size;
+ return AVERROR_INVALIDDATA;
}
if (bytestream2_get_byte(&s->gb)) {
avpriv_request_sample(avctx, "Padding bytes");
- return buf_size;
+ return AVERROR_PATCHWELCOME;
}
bytestream2_skip(&s->gb, 2);
diff --git a/libavcodec/ansi.c b/libavcodec/ansi.c
index 346a9ca413..202335914f 100644
--- a/libavcodec/ansi.c
+++ b/libavcodec/ansi.c
@@ -2,20 +2,20 @@
* ASCII/ANSI art decoder
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "libavutil/common.h"
#include "libavutil/frame.h"
#include "libavutil/lfg.h"
+#include "libavutil/xga_font_data.h"
#include "avcodec.h"
#include "cga_data.h"
#include "internal.h"
@@ -60,6 +61,7 @@ typedef struct AnsiContext {
int attributes; /**< attribute flags */
int fg; /**< foreground color */
int bg; /**< background color */
+ int first_frame;
/* ansi parser state machine */
enum {
@@ -83,7 +85,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
/* defaults */
- s->font = ff_vga16_font;
+ s->font = avpriv_vga16_font;
s->font_height = 16;
s->fg = DEFAULT_FG_COLOR;
s->bg = DEFAULT_BG_COLOR;
@@ -96,12 +98,27 @@ static av_cold int decode_init(AVCodecContext *avctx)
return 0;
}
+static void set_palette(uint32_t *pal)
+{
+ int r, g, b;
+ memcpy(pal, ff_cga_palette, 16 * 4);
+ pal += 16;
+#define COLOR(x) ((x) * 40 + 55)
+ for (r = 0; r < 6; r++)
+ for (g = 0; g < 6; g++)
+ for (b = 0; b < 6; b++)
+ *pal++ = 0xFF000000 | (COLOR(r) << 16) | (COLOR(g) << 8) | COLOR(b);
+#define GRAY(x) ((x) * 10 + 8)
+ for (g = 0; g < 24; g++)
+ *pal++ = 0xFF000000 | (GRAY(g) << 16) | (GRAY(g) << 8) | GRAY(g);
+}
+
static void hscroll(AVCodecContext *avctx)
{
AnsiContext *s = avctx->priv_data;
int i;
- if (s->y < avctx->height - s->font_height) {
+ if (s->y <= avctx->height - 2*s->font_height) {
s->y += s->font_height;
return;
}
@@ -154,7 +171,7 @@ static void draw_char(AVCodecContext *avctx, int c)
ff_draw_pc_font(s->frame->data[0] + s->y * s->frame->linesize[0] + s->x,
s->frame->linesize[0], s->font, s->font_height, c, fg, bg);
s->x += FONT_WIDTH;
- if (s->x >= avctx->width) {
+ if (s->x > avctx->width - FONT_WIDTH) {
s->x = 0;
hscroll(avctx);
}
@@ -168,8 +185,8 @@ static int execute_code(AVCodecContext * avctx, int c)
{
AnsiContext *s = avctx->priv_data;
int ret, i;
- int width = 0;
- int height = 0;
+ int width = avctx->width;
+ int height = avctx->height;
switch(c) {
case 'A': //Cursor Up
@@ -195,19 +212,19 @@ static int execute_code(AVCodecContext * avctx, int c)
s->args[0] = DEFAULT_SCREEN_MODE;
switch(s->args[0]) {
case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 40<<3;
height = 25<<3;
break;
case 2: case 3: //640x400 (25 rows)
- s->font = ff_vga16_font;
+ s->font = avpriv_vga16_font;
s->font_height = 16;
width = 80<<3;
height = 25<<4;
break;
case 6: case 14: //640x200 (25 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 80<<3;
height = 25<<3;
@@ -215,13 +232,13 @@ static int execute_code(AVCodecContext * avctx, int c)
case 7: //set line wrapping
break;
case 15: case 16: //640x350 (43 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 80<<3;
height = 43<<3;
break;
case 17: case 18: //640x480 (60 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 80<<3;
height = 60<<4;
@@ -229,20 +246,19 @@ static int execute_code(AVCodecContext * avctx, int c)
default:
avpriv_request_sample(avctx, "Unsupported screen mode");
}
- if (width != 0 && height != 0 &&
- (width != avctx->width || height != avctx->height)) {
+ s->x = av_clip(s->x, 0, width - FONT_WIDTH);
+ s->y = av_clip(s->y, 0, height - s->font_height);
+ if (width != avctx->width || height != avctx->height) {
av_frame_unref(s->frame);
ret = ff_set_dimensions(avctx, width, height);
if (ret < 0)
return ret;
- ret = ff_get_buffer(avctx, s->frame, AV_GET_BUFFER_FLAG_REF);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, s->frame,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
s->frame->pict_type = AV_PICTURE_TYPE_I;
s->frame->palette_has_changed = 1;
- memcpy(s->frame->data[1], ff_cga_palette, 16 * 4);
+ set_palette((uint32_t *)s->frame->data[1]);
erase_screen(avctx);
} else if (c == 'l') {
erase_screen(avctx);
@@ -290,12 +306,20 @@ static int execute_code(AVCodecContext * avctx, int c)
s->bg = DEFAULT_BG_COLOR;
} else if (m == 1 || m == 2 || m == 4 || m == 5 || m == 7 || m == 8) {
s->attributes |= 1 << (m - 1);
- } else if (m >= 30 && m <= 38) {
+ } else if (m >= 30 && m <= 37) {
s->fg = ansi_to_cga[m - 30];
+ } else if (m == 38 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
+ int index = s->args[i + 2];
+ s->fg = index < 16 ? ansi_to_cga[index] : index;
+ i += 2;
} else if (m == 39) {
s->fg = ansi_to_cga[DEFAULT_FG_COLOR];
} else if (m >= 40 && m <= 47) {
s->bg = ansi_to_cga[m - 40];
+ } else if (m == 48 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
+ int index = s->args[i + 2];
+ s->bg = index < 16 ? ansi_to_cga[index] : index;
+ i += 2;
} else if (m == 49) {
s->fg = ansi_to_cga[DEFAULT_BG_COLOR];
} else {
@@ -319,6 +343,8 @@ static int execute_code(AVCodecContext * avctx, int c)
avpriv_request_sample(avctx, "Unknown escape code");
break;
}
+ s->x = av_clip(s->x, 0, avctx->width - FONT_WIDTH);
+ s->y = av_clip(s->y, 0, avctx->height - s->font_height);
return 0;
}
@@ -332,19 +358,21 @@ static int decode_frame(AVCodecContext *avctx,
const uint8_t *buf_end = buf+buf_size;
int ret, i, count;
- ret = ff_reget_buffer(avctx, s->frame);
- if (ret < 0){
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
if (!avctx->frame_number) {
- memset(s->frame->data[0], 0, avctx->height * FFABS(s->frame->linesize[0]));
+ for (i=0; i<avctx->height; i++)
+ memset(s->frame->data[0]+ i*s->frame->linesize[0], 0, avctx->width);
memset(s->frame->data[1], 0, AVPALETTE_SIZE);
}
s->frame->pict_type = AV_PICTURE_TYPE_I;
s->frame->palette_has_changed = 1;
- memcpy(s->frame->data[1], ff_cga_palette, 16 * 4);
+ set_palette((uint32_t *)s->frame->data[1]);
+ if (!s->first_frame) {
+ erase_screen(avctx);
+ s->first_frame = 1;
+ }
while(buf < buf_end) {
switch(s->state) {
@@ -383,7 +411,7 @@ static int decode_frame(AVCodecContext *avctx,
if (buf[0] == '[') {
s->state = STATE_CODE;
s->nb_args = 0;
- s->args[0] = 0;
+ s->args[0] = -1;
} else {
s->state = STATE_NORMAL;
draw_char(avctx, 0x1B);
@@ -394,8 +422,8 @@ static int decode_frame(AVCodecContext *avctx,
switch(buf[0]) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- if (s->nb_args < MAX_NB_ARGS)
- s->args[s->nb_args] = s->args[s->nb_args] * 10 + buf[0] - '0';
+ if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args] < 6553)
+ s->args[s->nb_args] = FFMAX(s->args[s->nb_args], 0) * 10 + buf[0] - '0';
break;
case ';':
s->nb_args++;
@@ -411,7 +439,7 @@ static int decode_frame(AVCodecContext *avctx,
default:
if (s->nb_args > MAX_NB_ARGS)
av_log(avctx, AV_LOG_WARNING, "args overflow (%i)\n", s->nb_args);
- if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args])
+ if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args] >= 0)
s->nb_args++;
if ((ret = execute_code(avctx, buf[0])) < 0)
return ret;
diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c
index 131c6f32d7..03afd756dc 100644
--- a/libavcodec/apedec.c
+++ b/libavcodec/apedec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,7 @@
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
-#include "apedsp.h"
+#include "lossless_audiodsp.h"
#include "avcodec.h"
#include "bswapdsp.h"
#include "bytestream.h"
@@ -137,7 +137,7 @@ typedef struct APEContext {
AVClass *class; ///< class for AVOptions
AVCodecContext *avctx;
BswapDSPContext bdsp;
- APEDSPContext adsp;
+ LLAudDSPContext adsp;
int channels;
int samples; ///< samples left to decode in current frame
int bps;
@@ -212,19 +212,6 @@ static av_cold int ape_decode_close(AVCodecContext *avctx)
return 0;
}
-static int32_t scalarproduct_and_madd_int16_c(int16_t *v1, const int16_t *v2,
- const int16_t *v3,
- int order, int mul)
-{
- int res = 0;
-
- while (order--) {
- res += *v1 * *v2++;
- *v1++ += mul * *v3++;
- }
- return res;
-}
-
static av_cold int ape_decode_init(AVCodecContext *avctx)
{
APEContext *s = avctx->priv_data;
@@ -263,6 +250,7 @@ static av_cold int ape_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_DEBUG, "Compression Level: %d - Flags: %d\n",
s->compression_level, s->flags);
if (s->compression_level % 1000 || s->compression_level > COMPRESSION_LEVEL_INSANE ||
+ !s->compression_level ||
(s->fileversion < 3930 && s->compression_level == COMPRESSION_LEVEL_INSANE)) {
av_log(avctx, AV_LOG_ERROR, "Incorrect compression level %d\n",
s->compression_level);
@@ -305,16 +293,8 @@ static av_cold int ape_decode_init(AVCodecContext *avctx)
s->predictor_decode_stereo = predictor_decode_stereo_3950;
}
- s->adsp.scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_c;
-
- if (ARCH_ARM)
- ff_apedsp_init_arm(&s->adsp);
- if (ARCH_PPC)
- ff_apedsp_init_ppc(&s->adsp);
- if (ARCH_X86)
- ff_apedsp_init_x86(&s->adsp);
-
ff_bswapdsp_init(&s->bdsp);
+ ff_llauddsp_init(&s->adsp);
avctx->channel_layout = (avctx->channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
return 0;
@@ -512,9 +492,12 @@ static inline int ape_decode_value_3860(APEContext *ctx, GetBitContext *gb,
if (!rice->k)
x = overflow;
- else
+ else if(rice->k <= MIN_CACHE_BITS) {
x = (overflow << rice->k) + get_bits(gb, rice->k);
-
+ } else {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Too many bits: %d\n", rice->k);
+ return AVERROR_INVALIDDATA;
+ }
rice->ksum += x - (rice->ksum + 8 >> 4);
if (rice->ksum < (rice->k ? 1 << (rice->k + 4) : 0))
rice->k--;
@@ -522,10 +505,7 @@ static inline int ape_decode_value_3860(APEContext *ctx, GetBitContext *gb,
rice->k++;
/* Convert to signed */
- if (x & 1)
- return (x >> 1) + 1;
- else
- return -(x >> 1);
+ return ((x >> 1) ^ ((x & 1) - 1)) + 1;
}
static inline int ape_decode_value_3900(APEContext *ctx, APERice *rice)
@@ -541,9 +521,13 @@ static inline int ape_decode_value_3900(APEContext *ctx, APERice *rice)
} else
tmpk = (rice->k < 1) ? 0 : rice->k - 1;
- if (tmpk <= 16 || ctx->fileversion < 3910)
+ if (tmpk <= 16 || ctx->fileversion < 3910) {
+ if (tmpk > 23) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Too many bits: %d\n", tmpk);
+ return AVERROR_INVALIDDATA;
+ }
x = range_decode_bits(ctx, tmpk);
- else if (tmpk <= 32) {
+ } else if (tmpk <= 31) {
x = range_decode_bits(ctx, 16);
x |= (range_decode_bits(ctx, tmpk - 16) << 16);
} else {
@@ -555,10 +539,7 @@ static inline int ape_decode_value_3900(APEContext *ctx, APERice *rice)
update_rice(rice, x);
/* Convert to signed */
- if (x & 1)
- return (x >> 1) + 1;
- else
- return -(x >> 1);
+ return ((x >> 1) ^ ((x & 1) - 1)) + 1;
}
static inline int ape_decode_value_3990(APEContext *ctx, APERice *rice)
@@ -601,10 +582,7 @@ static inline int ape_decode_value_3990(APEContext *ctx, APERice *rice)
update_rice(rice, x);
/* Convert to signed */
- if (x & 1)
- return (x >> 1) + 1;
- else
- return -(x >> 1);
+ return ((x >> 1) ^ ((x & 1) - 1)) + 1;
}
static void decode_array_0000(APEContext *ctx, GetBitContext *gb,
@@ -619,10 +597,14 @@ static void decode_array_0000(APEContext *ctx, GetBitContext *gb,
rice->ksum += out[i];
}
rice->k = av_log2(rice->ksum / 10) + 1;
+ if (rice->k >= 24)
+ return;
for (; i < FFMIN(blockstodecode, 64); i++) {
out[i] = get_rice_ook(&ctx->gb, rice->k);
rice->ksum += out[i];
rice->k = av_log2(rice->ksum / ((i + 1) * 2)) + 1;
+ if (rice->k >= 24)
+ return;
}
ksummax = 1 << rice->k + 7;
ksummin = rice->k ? (1 << rice->k + 6) : 0;
@@ -643,12 +625,8 @@ static void decode_array_0000(APEContext *ctx, GetBitContext *gb,
}
}
- for (i = 0; i < blockstodecode; i++) {
- if (out[i] & 1)
- out[i] = (out[i] >> 1) + 1;
- else
- out[i] = -(out[i] >> 1);
- }
+ for (i = 0; i < blockstodecode; i++)
+ out[i] = ((out[i] >> 1) ^ ((out[i] & 1) - 1)) + 1;
}
static void entropy_decode_mono_0000(APEContext *ctx, int blockstodecode)
@@ -908,11 +886,11 @@ static av_always_inline int filter_3800(APEPredictor *p,
return p->filterA[filter];
}
-static void long_filter_high_3800(int32_t *buffer, int order, int shift,
- int32_t *coeffs, int32_t *delay, int length)
+static void long_filter_high_3800(int32_t *buffer, int order, int shift, int length)
{
int i, j;
int32_t dotprod, sign;
+ int32_t coeffs[256], delay[256];
memset(coeffs, 0, order * sizeof(*coeffs));
for (i = 0; i < order; i++)
@@ -922,7 +900,7 @@ static void long_filter_high_3800(int32_t *buffer, int order, int shift,
sign = APESIGN(buffer[i]);
for (j = 0; j < order; j++) {
dotprod += delay[j] * coeffs[j];
- coeffs[j] -= (((delay[j] >> 30) & 2) - 1) * sign;
+ coeffs[j] += ((delay[j] >> 31) | 1) * sign;
}
buffer[i] -= dotprod >> shift;
for (j = 0; j < order - 1; j++)
@@ -942,7 +920,7 @@ static void long_filter_ehigh_3830(int32_t *buffer, int length)
sign = APESIGN(buffer[i]);
for (j = 7; j >= 0; j--) {
dotprod += delay[j] * coeffs[j];
- coeffs[j] -= (((delay[j] >> 30) & 2) - 1) * sign;
+ coeffs[j] += ((delay[j] >> 31) | 1) * sign;
}
for (j = 7; j > 0; j--)
delay[j] = delay[j - 1];
@@ -956,13 +934,12 @@ static void predictor_decode_stereo_3800(APEContext *ctx, int count)
APEPredictor *p = &ctx->predictor;
int32_t *decoded0 = ctx->decoded[0];
int32_t *decoded1 = ctx->decoded[1];
- int32_t coeffs[256], delay[256];
int start = 4, shift = 10;
if (ctx->compression_level == COMPRESSION_LEVEL_HIGH) {
start = 16;
- long_filter_high_3800(decoded0, 16, 9, coeffs, delay, count);
- long_filter_high_3800(decoded1, 16, 9, coeffs, delay, count);
+ long_filter_high_3800(decoded0, 16, 9, count);
+ long_filter_high_3800(decoded1, 16, 9, count);
} else if (ctx->compression_level == COMPRESSION_LEVEL_EXTRA_HIGH) {
int order = 128, shift2 = 11;
@@ -974,8 +951,8 @@ static void predictor_decode_stereo_3800(APEContext *ctx, int count)
long_filter_ehigh_3830(decoded1 + order, count - order);
}
start = order;
- long_filter_high_3800(decoded0, order, shift2, coeffs, delay, count);
- long_filter_high_3800(decoded1, order, shift2, coeffs, delay, count);
+ long_filter_high_3800(decoded0, order, shift2, count);
+ long_filter_high_3800(decoded1, order, shift2, count);
}
while (count--) {
@@ -1011,12 +988,11 @@ static void predictor_decode_mono_3800(APEContext *ctx, int count)
{
APEPredictor *p = &ctx->predictor;
int32_t *decoded0 = ctx->decoded[0];
- int32_t coeffs[256], delay[256];
int start = 4, shift = 10;
if (ctx->compression_level == COMPRESSION_LEVEL_HIGH) {
start = 16;
- long_filter_high_3800(decoded0, 16, 9, coeffs, delay, count);
+ long_filter_high_3800(decoded0, 16, 9, count);
} else if (ctx->compression_level == COMPRESSION_LEVEL_EXTRA_HIGH) {
int order = 128, shift2 = 11;
@@ -1027,7 +1003,7 @@ static void predictor_decode_mono_3800(APEContext *ctx, int count)
long_filter_ehigh_3830(decoded0 + order, count - order);
}
start = order;
- long_filter_high_3800(decoded0, order, shift2, coeffs, delay, count);
+ long_filter_high_3800(decoded0, order, shift2, count);
}
while (count--) {
@@ -1449,7 +1425,7 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
}
if (s->fileversion < 3950) // previous versions overread two bytes
buf_size += 2;
- av_fast_malloc(&s->data, &s->data_size, buf_size);
+ av_fast_padded_malloc(&s->data, &s->data_size, buf_size);
if (!s->data)
return AVERROR(ENOMEM);
s->bdsp.bswap_buf((uint32_t *) s->data, (const uint32_t *) buf,
@@ -1472,7 +1448,8 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
}
s->ptr += offset;
} else {
- init_get_bits(&s->gb, s->ptr, (s->data_end - s->ptr) * 8);
+ if ((ret = init_get_bits8(&s->gb, s->ptr, s->data_end - s->ptr)) < 0)
+ return ret;
if (s->fileversion > 3800)
skip_bits_long(&s->gb, offset * 8);
else
@@ -1484,14 +1461,13 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
nblocks);
return AVERROR_INVALIDDATA;
}
- s->samples = nblocks;
/* Initialize the frame decoder */
if (init_frame_decoder(s) < 0) {
av_log(avctx, AV_LOG_ERROR, "Error reading frame header\n");
return AVERROR_INVALIDDATA;
}
-
+ s->samples = nblocks;
}
if (!s->data) {
@@ -1516,10 +1492,8 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = blockstodecode;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
s->error=0;
@@ -1563,7 +1537,7 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
*got_frame_ptr = 1;
- return (s->samples == 0) ? avpkt->size : 0;
+ return !s->samples ? avpkt->size : 0;
}
static void ape_flush(AVCodecContext *avctx)
diff --git a/libavcodec/apedsp.h b/libavcodec/apedsp.h
deleted file mode 100644
index 64e2749679..0000000000
--- a/libavcodec/apedsp.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Monkey's Audio lossless audio decoder
- * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
- * based upon libdemac from Dave Chapman.
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_APEDSP_H
-#define AVCODEC_APEDSP_H
-
-#include <stdint.h>
-
-typedef struct APEDSPContext {
- /**
- * Calculate scalar product of v1 and v2,
- * and v1[i] += v3[i] * mul
- * @param len length of vectors, should be multiple of 16
- */
- int32_t (*scalarproduct_and_madd_int16)(int16_t *v1 /* align 16 */,
- const int16_t *v2,
- const int16_t *v3,
- int len, int mul);
-} APEDSPContext;
-
-void ff_apedsp_init_arm(APEDSPContext *c);
-void ff_apedsp_init_ppc(APEDSPContext *c);
-void ff_apedsp_init_x86(APEDSPContext *c);
-
-#endif /* AVCODEC_APEDSP_H */
diff --git a/libavcodec/api-flac-test.c b/libavcodec/api-flac-test.c
new file mode 100644
index 0000000000..402d4df2e1
--- /dev/null
+++ b/libavcodec/api-flac-test.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015 Ludmila Glinskih
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * FLAC codec test.
+ * Encodes raw data to FLAC format and decodes it back to raw. Compares raw-data
+ * after that.
+ */
+
+#include "avcodec.h"
+#include "libavutil/common.h"
+#include "libavutil/samplefmt.h"
+
+#define NUMBER_OF_FRAMES 200
+#define NAME_BUFF_SIZE 100
+
+/* generate i-th frame of test audio */
+static int generate_raw_frame(uint16_t *frame_data, int i, int sample_rate,
+ int channels, int frame_size)
+{
+ int j, k;
+
+ for (j = 0; j < frame_size; j++) {
+ frame_data[channels * j] = 10000 * ((j / 10 * i) % 2);
+ for (k = 1; k < channels; k++)
+ frame_data[channels * j + k] = frame_data[channels * j] * (k + 1);
+ }
+ return 0;
+}
+
+static int init_encoder(AVCodec *enc, AVCodecContext **enc_ctx,
+ int64_t ch_layout, int sample_rate)
+{
+ AVCodecContext *ctx;
+ int result;
+ char name_buff[NAME_BUFF_SIZE];
+
+ av_get_channel_layout_string(name_buff, NAME_BUFF_SIZE, 0, ch_layout);
+ av_log(NULL, AV_LOG_INFO, "channel layout: %s, sample rate: %i\n", name_buff, sample_rate);
+
+ ctx = avcodec_alloc_context3(enc);
+ if (!ctx) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate encoder context\n");
+ return AVERROR(ENOMEM);
+ }
+
+ ctx->sample_fmt = AV_SAMPLE_FMT_S16;
+ ctx->sample_rate = sample_rate;
+ ctx->channel_layout = ch_layout;
+
+ result = avcodec_open2(ctx, enc, NULL);
+ if (result < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Can't open encoder\n");
+ return result;
+ }
+
+ *enc_ctx = ctx;
+ return 0;
+}
+
+static int init_decoder(AVCodec *dec, AVCodecContext **dec_ctx,
+ int64_t ch_layout)
+{
+ AVCodecContext *ctx;
+ int result;
+
+ ctx = avcodec_alloc_context3(dec);
+ if (!ctx) {
+ av_log(NULL, AV_LOG_ERROR , "Can't allocate decoder context\n");
+ return AVERROR(ENOMEM);
+ }
+
+ ctx->request_sample_fmt = AV_SAMPLE_FMT_S16;
+ /* XXX: FLAC ignores it for some reason */
+ ctx->request_channel_layout = ch_layout;
+ ctx->channel_layout = ch_layout;
+
+ result = avcodec_open2(ctx, dec, NULL);
+ if (result < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Can't open decoder\n");
+ return result;
+ }
+
+ *dec_ctx = ctx;
+ return 0;
+}
+
+static int run_test(AVCodec *enc, AVCodec *dec, AVCodecContext *enc_ctx,
+ AVCodecContext *dec_ctx)
+{
+ AVPacket enc_pkt;
+ AVFrame *in_frame, *out_frame;
+ uint8_t *raw_in = NULL, *raw_out = NULL;
+ int in_offset = 0, out_offset = 0;
+ int frame_data_size = 0;
+ int result = 0;
+ int got_output = 0;
+ int i = 0;
+
+ in_frame = av_frame_alloc();
+ if (!in_frame) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate input frame\n");
+ return AVERROR(ENOMEM);
+ }
+
+ in_frame->nb_samples = enc_ctx->frame_size;
+ in_frame->format = enc_ctx->sample_fmt;
+ in_frame->channel_layout = enc_ctx->channel_layout;
+ if (av_frame_get_buffer(in_frame, 32) != 0) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate a buffer for input frame\n");
+ return AVERROR(ENOMEM);
+ }
+
+ out_frame = av_frame_alloc();
+ if (!out_frame) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate output frame\n");
+ return AVERROR(ENOMEM);
+ }
+
+ raw_in = av_malloc(in_frame->linesize[0] * NUMBER_OF_FRAMES);
+ if (!raw_in) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_in\n");
+ return AVERROR(ENOMEM);
+ }
+
+ raw_out = av_malloc(in_frame->linesize[0] * NUMBER_OF_FRAMES);
+ if (!raw_out) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_out\n");
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < NUMBER_OF_FRAMES; i++) {
+ av_init_packet(&enc_pkt);
+ enc_pkt.data = NULL;
+ enc_pkt.size = 0;
+
+ generate_raw_frame((uint16_t*)(in_frame->data[0]), i, enc_ctx->sample_rate,
+ enc_ctx->channels, enc_ctx->frame_size);
+ memcpy(raw_in + in_offset, in_frame->data[0], in_frame->linesize[0]);
+ in_offset += in_frame->linesize[0];
+ result = avcodec_encode_audio2(enc_ctx, &enc_pkt, in_frame, &got_output);
+ if (result < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error encoding audio frame\n");
+ return result;
+ }
+
+ /* if we get an encoded packet, feed it straight to the decoder */
+ if (got_output) {
+ result = avcodec_decode_audio4(dec_ctx, out_frame, &got_output, &enc_pkt);
+ if (result < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Error decoding audio packet\n");
+ return result;
+ }
+
+ if (got_output) {
+ if (result != enc_pkt.size) {
+ av_log(NULL, AV_LOG_INFO, "Decoder consumed only part of a packet, it is allowed to do so -- need to update this test\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ if (in_frame->nb_samples != out_frame->nb_samples) {
+ av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different number of samples\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ if (in_frame->channel_layout != out_frame->channel_layout) {
+ av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different channel layout\n");
+ return AVERROR_UNKNOWN;
+ }
+
+ if (in_frame->format != out_frame->format) {
+ av_log(NULL, AV_LOG_ERROR, "Error frames before and after decoding has different sample format\n");
+ return AVERROR_UNKNOWN;
+ }
+ memcpy(raw_out + out_offset, out_frame->data[0], out_frame->linesize[0]);
+ out_offset += out_frame->linesize[0];
+ }
+ }
+ av_free_packet(&enc_pkt);
+ }
+
+ if (memcmp(raw_in, raw_out, frame_data_size * NUMBER_OF_FRAMES) != 0) {
+ av_log(NULL, AV_LOG_ERROR, "Output differs\n");
+ return 1;
+ }
+
+ av_log(NULL, AV_LOG_INFO, "OK\n");
+
+ av_freep(&raw_in);
+ av_freep(&raw_out);
+ av_frame_free(&in_frame);
+ av_frame_free(&out_frame);
+ return 0;
+}
+
+static int close_encoder(AVCodecContext **enc_ctx)
+{
+ avcodec_close(*enc_ctx);
+ av_freep(enc_ctx);
+ return 0;
+}
+
+static int close_decoder(AVCodecContext **dec_ctx)
+{
+ avcodec_close(*dec_ctx);
+ av_freep(dec_ctx);
+ return 0;
+}
+
+int main(void)
+{
+ AVCodec *enc = NULL, *dec = NULL;
+ AVCodecContext *enc_ctx = NULL, *dec_ctx = NULL;
+ uint64_t channel_layouts[] = {AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_5POINT1_BACK, AV_CH_LAYOUT_SURROUND, AV_CH_LAYOUT_STEREO_DOWNMIX};
+ int sample_rates[] = {8000, 44100, 48000, 192000};
+ int cl, sr;
+
+ avcodec_register_all();
+
+ enc = avcodec_find_encoder(AV_CODEC_ID_FLAC);
+ if (!enc) {
+ av_log(NULL, AV_LOG_ERROR, "Can't find encoder\n");
+ return 1;
+ }
+
+ dec = avcodec_find_decoder(AV_CODEC_ID_FLAC);
+ if (!dec) {
+ av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n");
+ return 1;
+ }
+
+ for (cl = 0; cl < FF_ARRAY_ELEMS(channel_layouts); cl++) {
+ for (sr = 0; sr < FF_ARRAY_ELEMS(sample_rates); sr++) {
+ if (init_encoder(enc, &enc_ctx, channel_layouts[cl], sample_rates[sr]) != 0)
+ return 1;
+ if (init_decoder(dec, &dec_ctx, channel_layouts[cl]) != 0)
+ return 1;
+ if (run_test(enc, dec, enc_ctx, dec_ctx) != 0)
+ return 1;
+ close_encoder(&enc_ctx);
+ close_decoder(&dec_ctx);
+ }
+ }
+
+ return 0;
+}
diff --git a/libavcodec/apng.h b/libavcodec/apng.h
new file mode 100644
index 0000000000..41249e0df0
--- /dev/null
+++ b/libavcodec/apng.h
@@ -0,0 +1,41 @@
+/*
+ * APNG common header
+ * Copyright (c) 2014 Benoit Fouet
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * APNG common header
+ */
+
+#ifndef AVCODEC_APNG_H
+#define AVCODEC_APNG_H
+
+enum {
+ APNG_DISPOSE_OP_NONE = 0,
+ APNG_DISPOSE_OP_BACKGROUND = 1,
+ APNG_DISPOSE_OP_PREVIOUS = 2,
+};
+
+enum {
+ APNG_BLEND_OP_SOURCE = 0,
+ APNG_BLEND_OP_OVER = 1,
+};
+
+#endif /* AVCODEC_APNG_H */
diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
index 57f5bc4d6f..2f8739691e 100644
--- a/libavcodec/arm/Makefile
+++ b/libavcodec/arm/Makefile
@@ -18,6 +18,7 @@ OBJS-$(CONFIG_IDCTDSP) += arm/idctdsp_init_arm.o \
arm/idctdsp_arm.o \
arm/jrevdct_arm.o \
arm/simple_idct_arm.o
+OBJS-$(CONFIG_LLAUDDSP) += arm/lossless_audiodsp_init_arm.o
OBJS-$(CONFIG_ME_CMP) += arm/me_cmp_init_arm.o
OBJS-$(CONFIG_MPEGAUDIODSP) += arm/mpegaudiodsp_init_arm.o
OBJS-$(CONFIG_MPEGVIDEO) += arm/mpegvideo_arm.o
@@ -30,12 +31,13 @@ OBJS-$(CONFIG_VP3DSP) += arm/vp3dsp_init_arm.o
# decoders/encoders
OBJS-$(CONFIG_AAC_DECODER) += arm/aacpsdsp_init_arm.o \
arm/sbrdsp_init_arm.o
-OBJS-$(CONFIG_APE_DECODER) += arm/apedsp_init_arm.o
+OBJS-$(CONFIG_ADPCM_G722_DECODER) += arm/g722dsp_init_arm.o
+OBJS-$(CONFIG_ADPCM_G722_ENCODER) += arm/g722dsp_init_arm.o
OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_init_arm.o
OBJS-$(CONFIG_FLAC_DECODER) += arm/flacdsp_init_arm.o \
arm/flacdsp_arm.o
-OBJS-$(CONFIG_ADPCM_G722_DECODER) += arm/g722dsp_init_arm.o
-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += arm/g722dsp_init_arm.o
+OBJS-$(CONFIG_FLAC_ENCODER) += arm/flacdsp_init_arm.o
+OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_arm.o
OBJS-$(CONFIG_MLP_DECODER) += arm/mlpdsp_init_arm.o
OBJS-$(CONFIG_VC1_DECODER) += arm/vc1dsp_init_arm.o
OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_init_arm.o
@@ -128,11 +130,15 @@ NEON-OBJS-$(CONFIG_VP3DSP) += arm/vp3dsp_neon.o
# decoders/encoders
NEON-OBJS-$(CONFIG_AAC_DECODER) += arm/aacpsdsp_neon.o \
arm/sbrdsp_neon.o
-NEON-OBJS-$(CONFIG_APE_DECODER) += arm/apedsp_neon.o
-NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_neon.o \
- arm/synth_filter_neon.o
NEON-OBJS-$(CONFIG_ADPCM_G722_DECODER) += arm/g722dsp_neon.o
NEON-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += arm/g722dsp_neon.o
+NEON-OBJS-$(CONFIG_LLAUDDSP) += arm/lossless_audiodsp_neon.o
+NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_neon.o \
+ arm/synth_filter_neon.o
+NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \
+ arm/hevcdsp_deblock_neon.o \
+ arm/hevcdsp_idct_neon.o \
+ arm/hevcdsp_qpel_neon.o
NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o
NEON-OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_neon.o \
arm/rv40dsp_neon.o
diff --git a/libavcodec/arm/aac.h b/libavcodec/arm/aac.h
index 4f143cb8a9..cafa881fc7 100644
--- a/libavcodec/arm/aac.h
+++ b/libavcodec/arm/aac.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/aacpsdsp_init_arm.c b/libavcodec/arm/aacpsdsp_init_arm.c
index 6326376004..e04787caae 100644
--- a/libavcodec/arm/aacpsdsp_init_arm.c
+++ b/libavcodec/arm/aacpsdsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/aacpsdsp_neon.S b/libavcodec/arm/aacpsdsp_neon.S
index fb00900a4d..a93bbfea9c 100644
--- a/libavcodec/arm/aacpsdsp_neon.S
+++ b/libavcodec/arm/aacpsdsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/ac3dsp_arm.S b/libavcodec/arm/ac3dsp_arm.S
index ed8eb37845..1aea190de9 100644
--- a/libavcodec/arm/ac3dsp_arm.S
+++ b/libavcodec/arm/ac3dsp_arm.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/ac3dsp_armv6.S b/libavcodec/arm/ac3dsp_armv6.S
index 2028d0b89f..1d2563d4f7 100644
--- a/libavcodec/arm/ac3dsp_armv6.S
+++ b/libavcodec/arm/ac3dsp_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/ac3dsp_init_arm.c b/libavcodec/arm/ac3dsp_init_arm.c
index a48353a099..a3c32ff407 100644
--- a/libavcodec/arm/ac3dsp_init_arm.c
+++ b/libavcodec/arm/ac3dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,14 @@ void ff_float_to_fixed24_neon(int32_t *dst, const float *src, unsigned int len);
void ff_ac3_extract_exponents_neon(uint8_t *exp, int32_t *coef, int nb_coefs);
void ff_apply_window_int16_neon(int16_t *dst, const int16_t *src,
const int16_t *window, unsigned n);
+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);
void ff_ac3_bit_alloc_calc_bap_armv6(int16_t *mask, int16_t *psd,
int start, int end,
@@ -59,5 +67,7 @@ av_cold void ff_ac3dsp_init_arm(AC3DSPContext *c, int bit_exact)
c->float_to_fixed24 = ff_float_to_fixed24_neon;
c->extract_exponents = ff_ac3_extract_exponents_neon;
c->apply_window_int16 = ff_apply_window_int16_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/arm/ac3dsp_neon.S b/libavcodec/arm/ac3dsp_neon.S
index f97b1907df..89d0ae8048 100644
--- a/libavcodec/arm/ac3dsp_neon.S
+++ b/libavcodec/arm/ac3dsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -131,3 +131,47 @@ function ff_apply_window_int16_neon, export=1
pop {r4,pc}
endfunc
+
+function ff_ac3_sum_square_butterfly_int32_neon, export=1
+ vmov.i64 q0, #0
+ vmov.i64 q1, #0
+ vmov.i64 q2, #0
+ vmov.i64 q3, #0
+1:
+ vld1.32 {d16}, [r1]!
+ vld1.32 {d17}, [r2]!
+ vadd.s32 d18, d16, d17
+ vsub.s32 d19, d16, d17
+ vmlal.s32 q0, d16, d16
+ vmlal.s32 q1, d17, d17
+ vmlal.s32 q2, d18, d18
+ vmlal.s32 q3, d19, d19
+ subs r3, r3, #2
+ bgt 1b
+ vadd.s64 d0, d0, d1
+ vadd.s64 d1, d2, d3
+ vadd.s64 d2, d4, d5
+ vadd.s64 d3, d6, d7
+ vst1.64 {q0-q1}, [r0]
+ bx lr
+endfunc
+
+function ff_ac3_sum_square_butterfly_float_neon, export=1
+ vmov.f32 q0, #0.0
+ vmov.f32 q1, #0.0
+1:
+ vld1.32 {d16}, [r1]!
+ vld1.32 {d17}, [r2]!
+ vadd.f32 d18, d16, d17
+ vsub.f32 d19, d16, d17
+ vmla.f32 d0, d16, d16
+ vmla.f32 d1, d17, d17
+ vmla.f32 d2, d18, d18
+ vmla.f32 d3, d19, d19
+ subs r3, r3, #2
+ bgt 1b
+ vpadd.f32 d0, d0, d1
+ vpadd.f32 d1, d2, d3
+ vst1.32 {q0}, [r0]
+ bx lr
+endfunc
diff --git a/libavcodec/arm/apedsp_init_arm.c b/libavcodec/arm/apedsp_init_arm.c
deleted file mode 100644
index 47ea034359..0000000000
--- a/libavcodec/arm/apedsp_init_arm.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-#include "libavutil/attributes.h"
-#include "libavutil/cpu.h"
-#include "libavutil/arm/cpu.h"
-#include "libavcodec/apedsp.h"
-
-int32_t ff_scalarproduct_and_madd_int16_neon(int16_t *v1, const int16_t *v2,
- const int16_t *v3, int len, int mul);
-
-av_cold void ff_apedsp_init_arm(APEDSPContext *c)
-{
- int cpu_flags = av_get_cpu_flags();
-
- if (have_neon(cpu_flags)) {
- c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_neon;
- }
-}
diff --git a/libavcodec/arm/apedsp_neon.S b/libavcodec/arm/apedsp_neon.S
deleted file mode 100644
index 7cfbf43c6d..0000000000
--- a/libavcodec/arm/apedsp_neon.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * ARM NEON optimised integer operations
- * Copyright (c) 2009 Kostya Shishkov
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavutil/arm/asm.S"
-
-@ scalarproduct_and_madd_int16(/*aligned*/v0,v1,v2,order,mul)
-function ff_scalarproduct_and_madd_int16_neon, export=1
- vld1.16 {d28[],d29[]}, [sp]
- vmov.i16 q0, #0
- vmov.i16 q1, #0
- vmov.i16 q2, #0
- vmov.i16 q3, #0
- mov r12, r0
-
-1: vld1.16 {d16-d17}, [r0,:128]!
- vld1.16 {d18-d19}, [r1]!
- vld1.16 {d20-d21}, [r2]!
- vld1.16 {d22-d23}, [r0,:128]!
- vld1.16 {d24-d25}, [r1]!
- vld1.16 {d26-d27}, [r2]!
- vmul.s16 q10, q10, q14
- vmul.s16 q13, q13, q14
- vmlal.s16 q0, d16, d18
- vmlal.s16 q1, d17, d19
- vadd.s16 q10, q8, q10
- vadd.s16 q13, q11, q13
- vmlal.s16 q2, d22, d24
- vmlal.s16 q3, d23, d25
- vst1.16 {q10}, [r12,:128]!
- subs r3, r3, #16
- vst1.16 {q13}, [r12,:128]!
- bne 1b
-
- vpadd.s32 d16, d0, d1
- vpadd.s32 d17, d2, d3
- vpadd.s32 d18, d4, d5
- vpadd.s32 d19, d6, d7
- vpadd.s32 d0, d16, d17
- vpadd.s32 d1, d18, d19
- vpadd.s32 d2, d0, d1
- vpaddl.s32 d3, d2
- vmov.32 r0, d3[0]
- bx lr
-endfunc
diff --git a/libavcodec/arm/asm-offsets.h b/libavcodec/arm/asm-offsets.h
index 0ea2f04e4a..a2174b0a08 100644
--- a/libavcodec/arm/asm-offsets.h
+++ b/libavcodec/arm/asm-offsets.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/audiodsp_arm.h b/libavcodec/arm/audiodsp_arm.h
index e97e804de7..213660dae7 100644
--- a/libavcodec/arm/audiodsp_arm.h
+++ b/libavcodec/arm/audiodsp_arm.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/audiodsp_init_arm.c b/libavcodec/arm/audiodsp_init_arm.c
index ea9ec3ca10..74aa52a4ef 100644
--- a/libavcodec/arm/audiodsp_init_arm.c
+++ b/libavcodec/arm/audiodsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* ARM optimized audio functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/audiodsp_init_neon.c b/libavcodec/arm/audiodsp_init_neon.c
index af532724c8..f7bd162482 100644
--- a/libavcodec/arm/audiodsp_init_neon.c
+++ b/libavcodec/arm/audiodsp_init_neon.c
@@ -2,20 +2,20 @@
* ARM NEON optimised audio functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/audiodsp_neon.S b/libavcodec/arm/audiodsp_neon.S
index dfb998de32..ab32cef7ab 100644
--- a/libavcodec/arm/audiodsp_neon.S
+++ b/libavcodec/arm/audiodsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised audio functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/blockdsp_arm.h b/libavcodec/arm/blockdsp_arm.h
index 6d9c2c3ed2..2688d36254 100644
--- a/libavcodec/arm/blockdsp_arm.h
+++ b/libavcodec/arm/blockdsp_arm.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/blockdsp_init_arm.c b/libavcodec/arm/blockdsp_init_arm.c
index a0c03674d7..3b86a71096 100644
--- a/libavcodec/arm/blockdsp_init_arm.c
+++ b/libavcodec/arm/blockdsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* ARM optimized block operations
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/blockdsp_init_neon.c b/libavcodec/arm/blockdsp_init_neon.c
index 5081cf0cdf..62b51fc788 100644
--- a/libavcodec/arm/blockdsp_init_neon.c
+++ b/libavcodec/arm/blockdsp_init_neon.c
@@ -2,20 +2,20 @@
* ARM NEON optimised block operations
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/blockdsp_neon.S b/libavcodec/arm/blockdsp_neon.S
index 98df2c60c4..9fc63cba5b 100644
--- a/libavcodec/arm/blockdsp_neon.S
+++ b/libavcodec/arm/blockdsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised block functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/cabac.h b/libavcodec/arm/cabac.h
index 6ff5f1a385..fdbf86b45e 100644
--- a/libavcodec/arm/cabac.h
+++ b/libavcodec/arm/cabac.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,12 +59,18 @@ static av_always_inline int get_cabac_inline_arm(CABACContext *c,
"tst %[r_c] , %[r_c] \n\t"
"bne 2f \n\t"
"ldr %[r_c] , [%[c], %[byte]] \n\t"
+#if UNCHECKED_BITSTREAM_READER
+ "ldrh %[tmp] , [%[r_c]] \n\t"
+ "add %[r_c] , %[r_c] , #2 \n\t"
+ "str %[r_c] , [%[c], %[byte]] \n\t"
+#else
"ldr %[r_b] , [%[c], %[end]] \n\t"
"ldrh %[tmp] , [%[r_c]] \n\t"
"cmp %[r_c] , %[r_b] \n\t"
"itt lt \n\t"
"addlt %[r_c] , %[r_c] , #2 \n\t"
"strlt %[r_c] , [%[c], %[byte]] \n\t"
+#endif
"sub %[r_c] , %[low] , #1 \n\t"
"add %[r_b] , %[tables] , %[norm_off] \n\t"
"eor %[r_c] , %[low] , %[r_c] \n\t"
diff --git a/libavcodec/arm/dca.h b/libavcodec/arm/dca.h
index 4aed57603e..6e87111a32 100644
--- a/libavcodec/arm/dca.h
+++ b/libavcodec/arm/dca.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
#include "libavcodec/dcadsp.h"
#include "libavcodec/mathops.h"
-#if HAVE_ARMV6_INLINE && AV_GCC_VERSION_AT_LEAST(4,4)
+#if HAVE_ARMV6_INLINE && AV_GCC_VERSION_AT_LEAST(4,4) && !CONFIG_THUMB
#define decode_blockcodes decode_blockcodes
static inline int decode_blockcodes(int code1, int code2, int levels,
@@ -35,46 +35,44 @@ static inline int decode_blockcodes(int code1, int code2, int levels,
{
int32_t v0, v1, v2, v3, v4, v5;
- __asm__ ("smmul %8, %14, %18 \n"
- "smmul %11, %15, %18 \n"
- "smlabb %14, %8, %17, %14 \n"
- "smlabb %15, %11, %17, %15 \n"
- "smmul %9, %8, %18 \n"
- "smmul %12, %11, %18 \n"
- "sub %14, %14, %16, lsr #1 \n"
- "sub %15, %15, %16, lsr #1 \n"
- "smlabb %8, %9, %17, %8 \n"
- "smlabb %11, %12, %17, %11 \n"
- "smmul %10, %9, %18 \n"
- "smmul %13, %12, %18 \n"
- "str %14, %0 \n"
- "str %15, %4 \n"
- "sub %8, %8, %16, lsr #1 \n"
- "sub %11, %11, %16, lsr #1 \n"
- "smlabb %9, %10, %17, %9 \n"
- "smlabb %12, %13, %17, %12 \n"
- "smmul %14, %10, %18 \n"
- "smmul %15, %13, %18 \n"
- "str %8, %1 \n"
- "str %11, %5 \n"
- "sub %9, %9, %16, lsr #1 \n"
- "sub %12, %12, %16, lsr #1 \n"
- "smlabb %10, %14, %17, %10 \n"
- "smlabb %13, %15, %17, %13 \n"
- "str %9, %2 \n"
- "str %12, %6 \n"
- "sub %10, %10, %16, lsr #1 \n"
- "sub %13, %13, %16, lsr #1 \n"
- "str %10, %3 \n"
- "str %13, %7 \n"
- : "=m"(values[0]), "=m"(values[1]),
- "=m"(values[2]), "=m"(values[3]),
- "=m"(values[4]), "=m"(values[5]),
- "=m"(values[6]), "=m"(values[7]),
- "=&r"(v0), "=&r"(v1), "=&r"(v2),
+ __asm__ ("smmul %0, %6, %10 \n"
+ "smmul %3, %7, %10 \n"
+ "smlabb %6, %0, %9, %6 \n"
+ "smlabb %7, %3, %9, %7 \n"
+ "smmul %1, %0, %10 \n"
+ "smmul %4, %3, %10 \n"
+ "sub %6, %6, %8, lsr #1 \n"
+ "sub %7, %7, %8, lsr #1 \n"
+ "smlabb %0, %1, %9, %0 \n"
+ "smlabb %3, %4, %9, %3 \n"
+ "smmul %2, %1, %10 \n"
+ "smmul %5, %4, %10 \n"
+ "str %6, [%11, #0] \n"
+ "str %7, [%11, #16] \n"
+ "sub %0, %0, %8, lsr #1 \n"
+ "sub %3, %3, %8, lsr #1 \n"
+ "smlabb %1, %2, %9, %1 \n"
+ "smlabb %4, %5, %9, %4 \n"
+ "smmul %6, %2, %10 \n"
+ "smmul %7, %5, %10 \n"
+ "str %0, [%11, #4] \n"
+ "str %3, [%11, #20] \n"
+ "sub %1, %1, %8, lsr #1 \n"
+ "sub %4, %4, %8, lsr #1 \n"
+ "smlabb %2, %6, %9, %2 \n"
+ "smlabb %5, %7, %9, %5 \n"
+ "str %1, [%11, #8] \n"
+ "str %4, [%11, #24] \n"
+ "sub %2, %2, %8, lsr #1 \n"
+ "sub %5, %5, %8, lsr #1 \n"
+ "str %2, [%11, #12] \n"
+ "str %5, [%11, #28] \n"
+ : "=&r"(v0), "=&r"(v1), "=&r"(v2),
"=&r"(v3), "=&r"(v4), "=&r"(v5),
"+&r"(code1), "+&r"(code2)
- : "r"(levels - 1), "r"(-levels), "r"(ff_inverse[levels]));
+ : "r"(levels - 1), "r"(-levels),
+ "r"(ff_inverse[levels]), "r"(values)
+ : "memory");
return code1 | code2;
}
diff --git a/libavcodec/arm/dcadsp_init_arm.c b/libavcodec/arm/dcadsp_init_arm.c
index 540048415f..a54951584f 100644
--- a/libavcodec/arm/dcadsp_init_arm.c
+++ b/libavcodec/arm/dcadsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/dcadsp_neon.S b/libavcodec/arm/dcadsp_neon.S
index 70580cdeec..cdc41367e9 100644
--- a/libavcodec/arm/dcadsp_neon.S
+++ b/libavcodec/arm/dcadsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/dcadsp_vfp.S b/libavcodec/arm/dcadsp_vfp.S
index c9114d499a..2e09f0ee5d 100644
--- a/libavcodec/arm/dcadsp_vfp.S
+++ b/libavcodec/arm/dcadsp_vfp.S
@@ -2,20 +2,20 @@
* Copyright (c) 2013 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/dct-test.c b/libavcodec/arm/dct-test.c
index 70e5c1cb82..f9076b394f 100644
--- a/libavcodec/arm/dct-test.c
+++ b/libavcodec/arm/dct-test.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/fft_fixed_init_arm.c b/libavcodec/arm/fft_fixed_init_arm.c
index 2f749e49df..b60bb9fa85 100644
--- a/libavcodec/arm/fft_fixed_init_arm.c
+++ b/libavcodec/arm/fft_fixed_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,9 @@ av_cold void ff_fft_fixed_init_arm(FFTContext *s)
if (have_neon(cpu_flags)) {
s->fft_permutation = FF_FFT_PERM_SWAP_LSBS;
+#if CONFIG_FFT
s->fft_calc = ff_fft_fixed_calc_neon;
+#endif
#if CONFIG_MDCT
if (!s->inverse && s->nbits >= 3) {
diff --git a/libavcodec/arm/fft_fixed_neon.S b/libavcodec/arm/fft_fixed_neon.S
index c70a18991a..2651607544 100644
--- a/libavcodec/arm/fft_fixed_neon.S
+++ b/libavcodec/arm/fft_fixed_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/fft_init_arm.c b/libavcodec/arm/fft_init_arm.c
index bc143c10fb..5087f5f64d 100644
--- a/libavcodec/arm/fft_init_arm.c
+++ b/libavcodec/arm/fft_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,8 +48,10 @@ av_cold void ff_fft_init_arm(FFTContext *s)
}
if (have_neon(cpu_flags)) {
+#if CONFIG_FFT
s->fft_permute = ff_fft_permute_neon;
s->fft_calc = ff_fft_calc_neon;
+#endif
#if CONFIG_MDCT
s->imdct_calc = ff_imdct_calc_neon;
s->imdct_half = ff_imdct_half_neon;
diff --git a/libavcodec/arm/fft_neon.S b/libavcodec/arm/fft_neon.S
index b161015e39..48f8dfc424 100644
--- a/libavcodec/arm/fft_neon.S
+++ b/libavcodec/arm/fft_neon.S
@@ -7,20 +7,20 @@
* This algorithm (though not any of the implementation details) is
* based on libdjbfft by D. J. Bernstein.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/fft_vfp.S b/libavcodec/arm/fft_vfp.S
index c2801fa1a9..ac601325f2 100644
--- a/libavcodec/arm/fft_vfp.S
+++ b/libavcodec/arm/fft_vfp.S
@@ -2,20 +2,20 @@
* Copyright (c) 2013 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/flacdsp_arm.S b/libavcodec/arm/flacdsp_arm.S
index d4441da1bb..f8861c5967 100644
--- a/libavcodec/arm/flacdsp_arm.S
+++ b/libavcodec/arm/flacdsp_arm.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/flacdsp_init_arm.c b/libavcodec/arm/flacdsp_init_arm.c
index 0530cf7a85..564e3dc79b 100644
--- a/libavcodec/arm/flacdsp_init_arm.c
+++ b/libavcodec/arm/flacdsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,9 +24,9 @@
void ff_flac_lpc_16_arm(int32_t *samples, const int coeffs[32], int order,
int qlevel, int len);
-av_cold void ff_flacdsp_init_arm(FLACDSPContext *c, enum AVSampleFormat fmt,
+av_cold void ff_flacdsp_init_arm(FLACDSPContext *c, enum AVSampleFormat fmt, int channels,
int bps)
{
- if (bps <= 16)
- c->lpc = ff_flac_lpc_16_arm;
+ if (CONFIG_FLAC_DECODER)
+ c->lpc16 = ff_flac_lpc_16_arm;
}
diff --git a/libavcodec/arm/fmtconvert_init_arm.c b/libavcodec/arm/fmtconvert_init_arm.c
index 27d3c88011..58589c46ef 100644
--- a/libavcodec/arm/fmtconvert_init_arm.c
+++ b/libavcodec/arm/fmtconvert_init_arm.c
@@ -1,20 +1,20 @@
/*
* ARM optimized Format Conversion Utils
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/fmtconvert_neon.S b/libavcodec/arm/fmtconvert_neon.S
index 5e0ac68843..a9ad57f793 100644
--- a/libavcodec/arm/fmtconvert_neon.S
+++ b/libavcodec/arm/fmtconvert_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised Format Conversion Utils
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/fmtconvert_vfp.S b/libavcodec/arm/fmtconvert_vfp.S
index 4e43f425a5..b14af454eb 100644
--- a/libavcodec/arm/fmtconvert_vfp.S
+++ b/libavcodec/arm/fmtconvert_vfp.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 RISC OS Open Ltd <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/g722dsp_init_arm.c b/libavcodec/arm/g722dsp_init_arm.c
index 5edf619f17..c0e5d8b989 100644
--- a/libavcodec/arm/g722dsp_init_arm.c
+++ b/libavcodec/arm/g722dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2015 Peter Meerwald <pmeerw@pmeerw.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/g722dsp_neon.S b/libavcodec/arm/g722dsp_neon.S
index 5fa3c279e9..757e53f167 100644
--- a/libavcodec/arm/g722dsp_neon.S
+++ b/libavcodec/arm/g722dsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions for G722 coding
* Copyright (c) 2015 Peter Meerwald <pmeerw@pmeerw.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264chroma_init_arm.c b/libavcodec/arm/h264chroma_init_arm.c
index 6f365533cf..13f7e0d702 100644
--- a/libavcodec/arm/h264chroma_init_arm.c
+++ b/libavcodec/arm/h264chroma_init_arm.c
@@ -2,20 +2,20 @@
* ARM NEON optimised H.264 chroma functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264cmc_neon.S b/libavcodec/arm/h264cmc_neon.S
index ee7011b00b..77ed3c0daa 100644
--- a/libavcodec/arm/h264cmc_neon.S
+++ b/libavcodec/arm/h264cmc_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c
index 7afd350890..90144d0da2 100644
--- a/libavcodec/arm/h264dsp_init_arm.c
+++ b/libavcodec/arm/h264dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,11 +72,14 @@ void ff_h264_idct8_add4_neon(uint8_t *dst, const int *block_offset,
static av_cold void h264dsp_init_neon(H264DSPContext *c, const int bit_depth,
const int chroma_format_idc)
{
+#if HAVE_NEON
if (bit_depth == 8) {
c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon;
c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon;
c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon;
+ if(chroma_format_idc == 1){
c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon;
+ }
c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon;
c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels_8_neon;
@@ -96,6 +99,7 @@ static av_cold void h264dsp_init_neon(H264DSPContext *c, const int bit_depth,
c->h264_idct8_dc_add = ff_h264_idct8_dc_add_neon;
c->h264_idct8_add4 = ff_h264_idct8_add4_neon;
}
+#endif // HAVE_NEON
}
av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
@@ -103,8 +107,10 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
{
int cpu_flags = av_get_cpu_flags();
+#if HAVE_ARMV6
if (have_setend(cpu_flags))
c->startcode_find_candidate = ff_startcode_find_candidate_armv6;
+#endif
if (have_neon(cpu_flags))
h264dsp_init_neon(c, bit_depth, chroma_format_idc);
}
diff --git a/libavcodec/arm/h264dsp_neon.S b/libavcodec/arm/h264dsp_neon.S
index 5e75565b3e..274a547f26 100644
--- a/libavcodec/arm/h264dsp_neon.S
+++ b/libavcodec/arm/h264dsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264idct_neon.S b/libavcodec/arm/h264idct_neon.S
index f588f3e744..4f68bdb9f5 100644
--- a/libavcodec/arm/h264idct_neon.S
+++ b/libavcodec/arm/h264idct_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264pred_init_arm.c b/libavcodec/arm/h264pred_init_arm.c
index bbfe63f2aa..6ba7592fe7 100644
--- a/libavcodec/arm/h264pred_init_arm.c
+++ b/libavcodec/arm/h264pred_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,11 +49,12 @@ static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id,
const int bit_depth,
const int chroma_format_idc)
{
+#if HAVE_NEON
const int high_depth = bit_depth > 8;
if (high_depth)
return;
-
+ if(chroma_format_idc == 1){
h->pred8x8[VERT_PRED8x8 ] = ff_pred8x8_vert_neon;
h->pred8x8[HOR_PRED8x8 ] = ff_pred8x8_hor_neon;
if (codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8)
@@ -69,6 +70,7 @@ static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id,
h->pred8x8[ALZHEIMER_DC_L00_PRED8x8] = ff_pred8x8_l00_dc_neon;
h->pred8x8[ALZHEIMER_DC_0L0_PRED8x8] = ff_pred8x8_0l0_dc_neon;
}
+ }
h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_neon;
h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vert_neon;
@@ -79,6 +81,7 @@ static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id,
if (codec_id != AV_CODEC_ID_SVQ3 && codec_id != AV_CODEC_ID_RV40 &&
codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8)
h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_neon;
+#endif // HAVE_NEON
}
av_cold void ff_h264_pred_init_arm(H264PredContext *h, int codec_id,
diff --git a/libavcodec/arm/h264pred_neon.S b/libavcodec/arm/h264pred_neon.S
index 332f94bd53..4dc47ba8f1 100644
--- a/libavcodec/arm/h264pred_neon.S
+++ b/libavcodec/arm/h264pred_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264qpel_init_arm.c b/libavcodec/arm/h264qpel_init_arm.c
index 01615b5719..71237be359 100644
--- a/libavcodec/arm/h264qpel_init_arm.c
+++ b/libavcodec/arm/h264qpel_init_arm.c
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/h264qpel_neon.S b/libavcodec/arm/h264qpel_neon.S
index 6c51250d5b..21336c6c32 100644
--- a/libavcodec/arm/h264qpel_neon.S
+++ b/libavcodec/arm/h264qpel_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/hevcdsp_arm.h b/libavcodec/arm/hevcdsp_arm.h
new file mode 100644
index 0000000000..7735df9cd2
--- /dev/null
+++ b/libavcodec/arm/hevcdsp_arm.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_ARM_HEVCDSP_ARM_H
+#define AVCODEC_ARM_HEVCDSP_ARM_H
+
+#include "libavcodec/hevcdsp.h"
+
+void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth);
+
+#endif /* AVCODEC_ARM_HEVCDSP_ARM_H */
diff --git a/libavcodec/arm/hevcdsp_deblock_neon.S b/libavcodec/arm/hevcdsp_deblock_neon.S
new file mode 100644
index 0000000000..166bddb104
--- /dev/null
+++ b/libavcodec/arm/hevcdsp_deblock_neon.S
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2014 Seppo Tomperi <seppo.tomperi@vtt.fi>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libavutil/arm/asm.S"
+#include "neon.S"
+
+.macro hevc_loop_filter_chroma_start
+ ldr r12, [r2]
+ ldr r3, [r2, #4]
+ add r2, r3, r12
+ cmp r2, #0
+ it eq
+ bxeq lr
+.endm
+
+.macro hevc_loop_filter_chroma_body
+ vsubl.u8 q3, d4, d2
+ vsubl.u8 q11, d18, d19
+ vshl.i16 q3, #2
+ vadd.i16 q11, q3
+ vdup.16 d0, r12
+ vdup.16 d1, r3
+ vrshr.s16 q11, q11, #3
+ vneg.s16 q12, q0
+ vmovl.u8 q2, d4
+ vmin.s16 q11, q11, q0
+ vmax.s16 q11, q11, q12
+ vaddw.u8 q1, q11, d2
+ vsub.i16 q2, q11
+ vqmovun.s16 d2, q1
+ vqmovun.s16 d4, q2
+.endm
+
+.macro hevc_loop_filter_luma_start
+ ldr r12, [r3]
+ ldr r3, [r3, #4]
+ lsl r3, #16
+ orr r3, r12
+ cmp r3, #0
+ it eq
+ bxeq lr
+ lsr r3, #16
+.endm
+
+.macro hevc_loop_filter_luma_body
+ vmovl.u8 q8, d16
+ vmovl.u8 q9, d18
+ vmovl.u8 q10, d20
+ vmovl.u8 q11, d22
+ vmovl.u8 q12, d24
+ vmovl.u8 q13, d26
+ vmovl.u8 q14, d28
+ vmovl.u8 q15, d30
+
+ vadd.i16 q7, q9, q11
+ vadd.i16 q6, q14, q12
+ vsub.i16 q7, q10
+ vsub.i16 q6, q13
+ vabd.s16 q7, q7, q10
+ vabd.s16 q6, q6, q13
+
+
+ vdup.16 q0, r2
+ vmov q4, q7
+ vmov q5, q6
+ vdup.16 d4, r12
+ vtrn.16 q7, q4
+ vtrn.16 q6, q5
+
+ vshl.u64 q7, #32
+ vshr.u64 q4, #32
+ vshl.u64 q6, #32
+ vshr.u64 q5, #32
+ vshr.u64 q7, #32
+ vshr.u64 q6, #32
+ vshl.u64 q5, #32
+ vshl.u64 q4, #32
+ vorr q6, q5
+ vorr q7, q4
+ vdup.16 d5, r3
+ vadd.i16 q5, q7, q6
+
+ vmov q4, q5
+ vmov q3, q5
+ vtrn.32 q3, q4
+
+ vadd.i16 q4, q3
+
+ vshl.s16 q5, q5, #1
+ vcgt.s16 q3, q0, q4
+
+ vmovn.i16 d6, q3
+ vshr.s16 q1, q0, #2
+ vmovn.i16 d6, q3
+ vcgt.s16 q5, q1, q5
+ vmov r7, s12
+ cmp r7, #0
+ beq bypasswrite
+
+ vpadd.i32 d0, d14, d12
+ vpadd.i32 d1, d15, d13
+ vmov q4, q2
+ vshl.s16 q2, #2
+ vshr.s16 q1, q1, #1
+ vrhadd.s16 q2, q4
+
+ vabd.s16 q7, q8, q11
+ vaba.s16 q7, q15, q12
+
+ vmovn.i32 d0, q0
+ vmov r5, r6, s0, s1
+ vcgt.s16 q6, q1, q7
+ vand q5, q5, q6
+ vabd.s16 q7, q11, q12
+ vcgt.s16 q6, q2, q7
+ vand q5, q5, q6
+
+ vmov q2, q5
+ vtrn.s16 q5, q2
+ vshr.u64 q2, #32
+ vshl.u64 q5, #32
+ vshl.u64 q2, #32
+ vshr.u64 q5, #32
+ vorr q5, q2
+
+ vmov q2, q5
+ vshl.i16 q7, q4, #1
+ vtrn.32 q2, q5
+ vand q5, q2
+ vneg.s16 q6, q7
+ vmovn.i16 d4, q5
+ vmovn.i16 d4, q2
+ vmov r8, s8
+
+ and r9, r8, r7
+ cmp r9, #0
+ beq weakfilter_\@
+
+ vadd.i16 q2, q11, q12
+ vadd.i16 q4, q9, q8
+ vadd.i16 q1, q2, q10
+ vdup.16 d10, r9
+ vadd.i16 q0, q1, q9
+ vshl.i16 q4, #1
+ lsr r9, #16
+ vadd.i16 q1, q0
+ vrshr.s16 q3, q0, #2
+ vadd.i16 q1, q13
+ vadd.i16 q4, q0
+ vsub.i16 q3, q10
+ vrshr.s16 q1, #3
+ vrshr.s16 q4, #3
+ vmax.s16 q3, q6
+ vsub.i16 q1, q11
+ vsub.i16 q4, q9
+ vmin.s16 q3, q7
+ vmax.s16 q4, q6
+ vmax.s16 q1, q6
+ vadd.i16 q3, q10
+ vmin.s16 q4, q7
+ vmin.s16 q1, q7
+ vdup.16 d11, r9
+ vadd.i16 q4, q9
+ vadd.i16 q1, q11
+ vbit q9, q4, q5
+ vadd.i16 q4, q2, q13
+ vbit q11, q1, q5
+ vadd.i16 q0, q4, q14
+ vadd.i16 q2, q15, q14
+ vadd.i16 q4, q0
+
+ vshl.i16 q2, #1
+ vadd.i16 q4, q10
+ vbit q10, q3, q5
+ vrshr.s16 q4, #3
+ vadd.i16 q2, q0
+ vrshr.s16 q3, q0, #2
+ vsub.i16 q4, q12
+ vrshr.s16 q2, #3
+ vsub.i16 q3, q13
+ vmax.s16 q4, q6
+ vsub.i16 q2, q14
+ vmax.s16 q3, q6
+ vmin.s16 q4, q7
+ vmax.s16 q2, q6
+ vmin.s16 q3, q7
+ vadd.i16 q4, q12
+ vmin.s16 q2, q7
+ vadd.i16 q3, q13
+ vbit q12, q4, q5
+ vadd.i16 q2, q14
+ vbit q13, q3, q5
+ vbit q14, q2, q5
+
+weakfilter_\@:
+ mvn r8, r8
+ and r9, r8, r7
+ cmp r9, #0
+ beq ready_\@
+
+ vdup.16 q4, r2
+
+ vdup.16 d10, r9
+ lsr r9, #16
+ vmov q1, q4
+ vdup.16 d11, r9
+ vshr.s16 q1, #1
+ vsub.i16 q2, q12, q11
+ vadd.i16 q4, q1
+ vshl.s16 q0, q2, #3
+ vshr.s16 q4, #3
+ vadd.i16 q2, q0
+ vsub.i16 q0, q13, q10
+ vsub.i16 q2, q0
+ vshl.i16 q0, q0, #1
+ vsub.i16 q2, q0
+ vshl.s16 q1, q7, 2
+ vrshr.s16 q2, q2, #4
+ vadd.i16 q1, q7
+ vabs.s16 q3, q2
+ vshr.s16 q6, q6, #1
+ vcgt.s16 q1, q1, q3
+ vand q5, q1
+ vshr.s16 q7, q7, #1
+ vmax.s16 q2, q2, q6
+ vmin.s16 q2, q2, q7
+
+ vshr.s16 q7, q7, #1
+ vrhadd.s16 q3, q9, q11
+ vneg.s16 q6, q7
+ vsub.s16 q3, q10
+ vdup.16 d2, r5
+ vhadd.s16 q3, q2
+ vdup.16 d3, r6
+ vmax.s16 q3, q3, q6
+ vcgt.s16 q1, q4, q1
+ vmin.s16 q3, q3, q7
+ vand q1, q5
+ vadd.i16 q3, q10
+ lsr r5, #16
+ lsr r6, #16
+ vbit q10, q3, q1
+
+ vrhadd.s16 q3, q14, q12
+ vdup.16 d2, r5
+ vsub.s16 q3, q13
+ vdup.16 d3, r6
+ vhsub.s16 q3, q2
+ vcgt.s16 q1, q4, q1
+ vmax.s16 q3, q3, q6
+ vand q1, q5
+ vmin.s16 q3, q3, q7
+ vadd.i16 q3, q13
+ vbit q13, q3, q1
+ vadd.i16 q0, q11, q2
+ vsub.i16 q4, q12, q2
+ vbit q11, q0, q5
+ vbit q12, q4, q5
+
+ready_\@:
+ vqmovun.s16 d16, q8
+ vqmovun.s16 d18, q9
+ vqmovun.s16 d20, q10
+ vqmovun.s16 d22, q11
+ vqmovun.s16 d24, q12
+ vqmovun.s16 d26, q13
+ vqmovun.s16 d28, q14
+ vqmovun.s16 d30, q15
+.endm
+
+function ff_hevc_v_loop_filter_luma_neon, export=1
+ hevc_loop_filter_luma_start
+ push {r5-r11}
+ vpush {d8-d15}
+ sub r0, #4
+ vld1.8 {d16}, [r0], r1
+ vld1.8 {d18}, [r0], r1
+ vld1.8 {d20}, [r0], r1
+ vld1.8 {d22}, [r0], r1
+ vld1.8 {d24}, [r0], r1
+ vld1.8 {d26}, [r0], r1
+ vld1.8 {d28}, [r0], r1
+ vld1.8 {d30}, [r0], r1
+ sub r0, r0, r1, lsl #3
+ transpose_8x8 d16, d18, d20, d22, d24, d26, d28, d30
+ hevc_loop_filter_luma_body
+ transpose_8x8 d16, d18, d20, d22, d24, d26, d28, d30
+ vst1.8 {d16}, [r0], r1
+ vst1.8 {d18}, [r0], r1
+ vst1.8 {d20}, [r0], r1
+ vst1.8 {d22}, [r0], r1
+ vst1.8 {d24}, [r0], r1
+ vst1.8 {d26}, [r0], r1
+ vst1.8 {d28}, [r0], r1
+ vst1.8 {d30}, [r0]
+ vpop {d8-d15}
+ pop {r5-r11}
+ bx lr
+endfunc
+
+function ff_hevc_h_loop_filter_luma_neon, export=1
+ hevc_loop_filter_luma_start
+ push {r5-r11}
+ vpush {d8-d15}
+ sub r0, r0, r1, lsl #2
+ vld1.8 {d16}, [r0], r1
+ vld1.8 {d18}, [r0], r1
+ vld1.8 {d20}, [r0], r1
+ vld1.8 {d22}, [r0], r1
+ vld1.8 {d24}, [r0], r1
+ vld1.8 {d26}, [r0], r1
+ vld1.8 {d28}, [r0], r1
+ vld1.8 {d30}, [r0], r1
+ sub r0, r0, r1, lsl #3
+ add r0, r1
+ hevc_loop_filter_luma_body
+ vst1.8 {d18}, [r0], r1
+ vst1.8 {d20}, [r0], r1
+ vst1.8 {d22}, [r0], r1
+ vst1.8 {d24}, [r0], r1
+ vst1.8 {d26}, [r0], r1
+ vst1.8 {d28}, [r0]
+bypasswrite:
+ vpop {d8-d15}
+ pop {r5-r11}
+ bx lr
+endfunc
+
+function ff_hevc_v_loop_filter_chroma_neon, export=1
+ hevc_loop_filter_chroma_start
+ sub r0, #4
+ vld1.8 {d16}, [r0], r1
+ vld1.8 {d17}, [r0], r1
+ vld1.8 {d18}, [r0], r1
+ vld1.8 {d2}, [r0], r1
+ vld1.8 {d4}, [r0], r1
+ vld1.8 {d19}, [r0], r1
+ vld1.8 {d20}, [r0], r1
+ vld1.8 {d21}, [r0], r1
+ sub r0, r0, r1, lsl #3
+ transpose_8x8 d16, d17, d18, d2, d4, d19, d20, d21
+ hevc_loop_filter_chroma_body
+ transpose_8x8 d16, d17, d18, d2, d4, d19, d20, d21
+ vst1.8 {d16}, [r0], r1
+ vst1.8 {d17}, [r0], r1
+ vst1.8 {d18}, [r0], r1
+ vst1.8 {d2}, [r0], r1
+ vst1.8 {d4}, [r0], r1
+ vst1.8 {d19}, [r0], r1
+ vst1.8 {d20}, [r0], r1
+ vst1.8 {d21}, [r0]
+ bx lr
+endfunc
+
+function ff_hevc_h_loop_filter_chroma_neon, export=1
+ hevc_loop_filter_chroma_start
+ sub r0, r0, r1, lsl #1
+ vld1.8 {d18}, [r0], r1
+ vld1.8 {d2}, [r0], r1
+ vld1.8 {d4}, [r0], r1
+ vld1.8 {d19}, [r0]
+ sub r0, r0, r1, lsl #1
+ hevc_loop_filter_chroma_body
+ vst1.8 {d2}, [r0], r1
+ vst1.8 {d4}, [r0]
+ bx lr
+endfunc
diff --git a/libavcodec/arm/hevcdsp_idct_neon.S b/libavcodec/arm/hevcdsp_idct_neon.S
new file mode 100644
index 0000000000..13d540e5ff
--- /dev/null
+++ b/libavcodec/arm/hevcdsp_idct_neon.S
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2014 Seppo Tomperi <seppo.tomperi@vtt.fi>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/arm/asm.S"
+#include "neon.S"
+
+function ff_hevc_idct_4x4_dc_neon_8, export=1
+ ldrsh r1, [r0]
+ ldr r2, =0x20
+ add r1, #1
+ asr r1, #1
+ add r1, r2
+ asr r1, #6
+ vdup.16 q0, r1
+ vdup.16 q1, r1
+ vst1.16 {q0, q1}, [r0]
+ bx lr
+endfunc
+
+function ff_hevc_idct_8x8_dc_neon_8, export=1
+ ldrsh r1, [r0]
+ ldr r2, =0x20
+ add r1, #1
+ asr r1, #1
+ add r1, r2
+ asr r1, #6
+ vdup.16 q8, r1
+ vdup.16 q9, r1
+ vmov.16 q10, q8
+ vmov.16 q11, q8
+ vmov.16 q12, q8
+ vmov.16 q13, q8
+ vmov.16 q14, q8
+ vmov.16 q15, q8
+ vstm r0, {q8-q15}
+ bx lr
+endfunc
+
+function ff_hevc_idct_16x16_dc_neon_8, export=1
+ ldrsh r1, [r0]
+ ldr r2, =0x20
+ add r1, #1
+ asr r1, #1
+ add r1, r2
+ asr r1, #6
+ vdup.16 q8, r1
+ vdup.16 q9, r1
+ vmov.16 q10, q8
+ vmov.16 q11, q8
+ vmov.16 q12, q8
+ vmov.16 q13, q8
+ vmov.16 q14, q8
+ vmov.16 q15, q8
+ vstm r0!, {q8-q15}
+ vstm r0!, {q8-q15}
+ vstm r0!, {q8-q15}
+ vstm r0, {q8-q15}
+ bx lr
+endfunc
+
+function ff_hevc_idct_32x32_dc_neon_8, export=1
+ ldrsh r1, [r0]
+ ldr r2, =0x20
+ add r1, #1
+ asr r1, #1
+ add r1, r2
+ asr r1, #6
+ mov r3, #16
+ vdup.16 q8, r1
+ vdup.16 q9, r1
+ vmov.16 q10, q8
+ vmov.16 q11, q8
+ vmov.16 q12, q8
+ vmov.16 q13, q8
+ vmov.16 q14, q8
+ vmov.16 q15, q8
+1: subs r3, #1
+ vstm r0!, {q8-q15}
+ bne 1b
+ bx lr
+endfunc
+
+function ff_hevc_transform_add_4x4_neon_8, export=1
+ vldm r1, {q0-q1}
+ vld1.32 d4[0], [r0], r2
+ vld1.32 d4[1], [r0], r2
+ vld1.32 d5[0], [r0], r2
+ vld1.32 d5[1], [r0], r2
+ sub r0, r0, r2, lsl #2
+ vmovl.u8 q8, d4
+ vmovl.u8 q9, d5
+ vqadd.s16 q0, q0, q8
+ vqadd.s16 q1, q1, q9
+ vqmovun.s16 d0, q0
+ vqmovun.s16 d1, q1
+ vst1.32 d0[0], [r0], r2
+ vst1.32 d0[1], [r0], r2
+ vst1.32 d1[0], [r0], r2
+ vst1.32 d1[1], [r0], r2
+ bx lr
+endfunc
+
+function ff_hevc_transform_add_8x8_neon_8, export=1
+ mov r3, #8
+1: subs r3, #1
+ vld1.16 {q0}, [r1]!
+ vld1.8 d16, [r0]
+ vmovl.u8 q8, d16
+ vqadd.s16 q0, q8
+ vqmovun.s16 d0, q0
+ vst1.32 d0, [r0], r2
+ bne 1b
+ bx lr
+endfunc
+
+function ff_hevc_transform_add_16x16_neon_8, export=1
+ mov r3, #16
+1: subs r3, #1
+ vld1.16 {q0, q1}, [r1]!
+ vld1.8 {q8}, [r0]
+ vmovl.u8 q9, d16
+ vmovl.u8 q10, d17
+ vqadd.s16 q0, q9
+ vqadd.s16 q1, q10
+ vqmovun.s16 d0, q0
+ vqmovun.s16 d1, q1
+ vst1.8 {q0}, [r0], r2
+ bne 1b
+ bx lr
+endfunc
+
+function ff_hevc_transform_add_32x32_neon_8, export=1
+ mov r3, #32
+1: subs r3, #1
+ vldm r1!, {q0-q3}
+ vld1.8 {q8, q9}, [r0]
+ vmovl.u8 q10, d16
+ vmovl.u8 q11, d17
+ vmovl.u8 q12, d18
+ vmovl.u8 q13, d19
+ vqadd.s16 q0, q10
+ vqadd.s16 q1, q11
+ vqadd.s16 q2, q12
+ vqadd.s16 q3, q13
+ vqmovun.s16 d0, q0
+ vqmovun.s16 d1, q1
+ vqmovun.s16 d2, q2
+ vqmovun.s16 d3, q3
+ vst1.8 {q0, q1}, [r0], r2
+ bne 1b
+ bx lr
+endfunc
+
+.macro transpose_16b_8x8 r0, r1, r2, r3, r4, r5, r6, r7
+ vtrn.64 \r0, \r4
+ vtrn.64 \r1, \r5
+ vtrn.64 \r2, \r6
+ vtrn.64 \r3, \r7
+ vtrn.32 \r0, \r2
+ vtrn.32 \r1, \r3
+ vtrn.32 \r4, \r6
+ vtrn.32 \r5, \r7
+ vtrn.16 \r0, \r1
+ vtrn.16 \r2, \r3
+ vtrn.16 \r4, \r5
+ vtrn.16 \r6, \r7
+.endm
+
+// in 4 q regs
+// output 8 d regs
+.macro transpose_16b_4x4 r0, r1, r2, r3
+ vtrn.32 \r0, \r2
+ vtrn.32 \r1, \r3
+ vtrn.16 \r0, \r1
+ vtrn.16 \r2, \r3
+.endm
+
+/* uses registers q2 - q9 for temp values */
+/* TODO: reorder */
+.macro tr4_luma_shift r0, r1, r2, r3, shift
+ vaddl.s16 q5, \r0, \r2 // c0 = src0 + src2
+ vaddl.s16 q2, \r2, \r3 // c1 = src2 + src3
+ vsubl.s16 q4, \r0, \r3 // c2 = src0 - src3
+ vmull.s16 q6, \r1, d0[0] // c3 = 74 * src1
+
+ vaddl.s16 q7, \r0, \r3 // src0 + src3
+ vsubw.s16 q7, q7, \r2 // src0 - src2 + src3
+ vmul.s32 q7, q7, d0[0] // dst2 = 74 * (src0 - src2 + src3)
+
+ vmul.s32 q8, q5, d0[1] // 29 * c0
+ vmul.s32 q9, q2, d1[0] // 55 * c1
+ vadd.s32 q8, q9 // 29 * c0 + 55 * c1
+ vadd.s32 q8, q6 // dst0 = 29 * c0 + 55 * c1 + c3
+
+ vmul.s32 q2, q2, d0[1] // 29 * c1
+ vmul.s32 q9, q4, d1[0] // 55 * c2
+ vsub.s32 q9, q2 // 55 * c2 - 29 * c1
+ vadd.s32 q9, q6 // dst1 = 55 * c2 - 29 * c1 + c3
+
+ vmul.s32 q5, q5, d1[0] // 55 * c0
+ vmul.s32 q4, q4, d0[1] // 29 * c2
+ vadd.s32 q5, q4 // 55 * c0 + 29 * c2
+ vsub.s32 q5, q6 // dst3 = 55 * c0 + 29 * c2 - c3
+
+ vqrshrn.s32 \r0, q8, \shift
+ vqrshrn.s32 \r1, q9, \shift
+ vqrshrn.s32 \r2, q7, \shift
+ vqrshrn.s32 \r3, q5, \shift
+.endm
+
+/* uses registers q2 - q6 for temp values */
+.macro tr4 r0, r1, r2, r3
+ vmull.s16 q4, \r1, d0[0] // 83 * src1
+ vmull.s16 q6, \r1, d0[1] // 36 * src1
+ vshll.s16 q2, \r0, #6 // 64 * src0
+ vshll.s16 q3, \r2, #6 // 64 * src2
+ vadd.s32 q5, q2, q3 // 64 * (src0 + src2) e0
+ vsub.s32 q2, q2, q3 // 64 * (src0 - src2) e1
+ vmlal.s16 q4, \r3, d0[1] // 83 * src1 + 36 * src3 o0
+ vmlsl.s16 q6, \r3, d0[0] // 36 * src1 - 83 * src3 o1
+
+ vsub.s32 q3, q5, q4 // e0 - o0
+ vadd.s32 q4, q5, q4 // e0 + o0
+ vadd.s32 q5, q2, q6 // e1 + o1
+ vsub.s32 q6, q2, q6 // e1 - o1
+.endm
+
+.macro tr4_shift r0, r1, r2, r3, shift
+ vmull.s16 q4, \r1, d0[0] // 83 * src1
+ vmull.s16 q6, \r1, d0[1] // 36 * src1
+ vshll.s16 q2, \r0, #6 // 64 * src0
+ vshll.s16 q3, \r2, #6 // 64 * src2
+ vadd.s32 q5, q2, q3 // 64 * (src0 + src2) e0
+ vsub.s32 q2, q2, q3 // 64 * (src0 - src2) e1
+ vmlal.s16 q4, \r3, d0[1] // 83 * src1 + 36 * src3 o0
+ vmlsl.s16 q6, \r3, d0[0] // 36 * src1 - 83 * src3 o1
+
+ vsub.s32 q3, q5, q4 // e0 - o0
+ vadd.s32 q4, q5, q4 // e0 + o0
+ vadd.s32 q5, q2, q6 // e1 + o1
+ vsub.s32 q6, q2, q6 // e1 - o1
+
+ vqrshrn.s32 \r0, q4, \shift
+ vqrshrn.s32 \r1, q5, \shift
+ vqrshrn.s32 \r2, q6, \shift
+ vqrshrn.s32 \r3, q3, \shift
+.endm
+
+function ff_hevc_transform_4x4_neon_8, export=1
+ vpush {d8-d15}
+ vld1.16 {q14, q15}, [r0] // coeffs
+ ldr r3, =0x00240053 // 36 and 83
+ vmov.32 d0[0], r3
+
+ tr4_shift d28, d29, d30, d31, #7
+
+ vtrn.16 d28, d29
+ vtrn.16 d30, d31
+ vtrn.32 q14, q15
+
+ tr4_shift d28, d29, d30, d31, #12
+
+ vtrn.16 d28, d29
+ vtrn.16 d30, d31
+ vtrn.32 q14, q15
+
+ vst1.16 {q14, q15}, [r0]
+ vpop {d8-d15}
+ bx lr
+endfunc
+
+function ff_hevc_transform_luma_4x4_neon_8, export=1
+ vpush {d8-d15}
+ vld1.16 {q14, q15}, [r0] // coeffs
+ ldr r3, =0x4a // 74
+ vmov.32 d0[0], r3
+ ldr r3, =0x1d // 29
+ vmov.32 d0[1], r3
+ ldr r3, =0x37 // 55
+ vmov.32 d1[0], r3
+
+ tr4_luma_shift d28, d29, d30, d31, #7
+
+ vtrn.16 d28, d29
+ vtrn.16 d30, d31
+ vtrn.32 q14, q15
+
+ tr4_luma_shift d28, d29, d30, d31, #12
+
+ vtrn.16 d28, d29
+ vtrn.16 d30, d31
+ vtrn.32 q14, q15
+ vst1.16 {q14, q15}, [r0]
+ vpop {d8-d15}
+ bx lr
+endfunc
+
+.macro tr8_begin in0, in1, in2, in3
+ vmull.s16 q7, \in0, d1[1] // 89 * src1
+ vmull.s16 q8, \in0, d1[0] // 75 * src1
+ vmull.s16 q9, \in0, d1[3] // 50 * src1
+ vmull.s16 q10, \in0, d1[2] // 18 * src1
+
+ vmlal.s16 q7, \in1, d1[0] // 75 * src3
+ vmlsl.s16 q8, \in1, d1[2] //-18 * src3
+ vmlsl.s16 q9, \in1, d1[1] //-89 * src3
+ vmlsl.s16 q10, \in1, d1[3] //-50 * src3
+
+ vmlal.s16 q7, \in2, d1[3] // 50 * src5
+ vmlsl.s16 q8, \in2, d1[1] //-89 * src5
+ vmlal.s16 q9, \in2, d1[2] // 18 * src5
+ vmlal.s16 q10, \in2, d1[0] // 75 * src5
+
+ vmlal.s16 q7, \in3, d1[2] // 18 * src7
+ vmlsl.s16 q8, \in3, d1[3] //-50 * src7
+ vmlal.s16 q9, \in3, d1[0] // 75 * src7
+ vmlsl.s16 q10, \in3, d1[1] //-89 * src7
+.endm
+
+.macro tr8_end shift
+ vadd.s32 q1, q4, q7 // e_8[0] + o_8[0], dst[0]
+ vsub.s32 q4, q4, q7 // e_8[0] - o_8[0], dst[7]
+
+ vadd.s32 q2, q5, q8 // e_8[1] + o_8[1], dst[1]
+ vsub.s32 q5, q5, q8 // e_8[1] - o_8[1], dst[6]
+
+ vadd.s32 q11, q6, q9 // e_8[2] + o_8[2], dst[2]
+ vsub.s32 q6, q6, q9 // e_8[2] - o_8[2], dst[5]
+
+ vadd.s32 q12, q3, q10 // e_8[3] + o_8[3], dst[3]
+ vsub.s32 q3, q3, q10 // e_8[3] - o_8[3], dst[4]
+ vqrshrn.s32 d2, q1, \shift
+ vqrshrn.s32 d3, q2, \shift
+ vqrshrn.s32 d4, q11, \shift
+ vqrshrn.s32 d5, q12, \shift
+ vqrshrn.s32 d6, q3, \shift
+ vqrshrn.s32 d7, q6, \shift
+ vqrshrn.s32 d9, q4, \shift
+ vqrshrn.s32 d8, q5, \shift
+.endm
+
+function ff_hevc_transform_8x8_neon_8, export=1
+ push {r4-r8}
+ vpush {d8-d15}
+ mov r5, #16
+
+ adr r3, tr4f
+ vld1.16 {d0, d1}, [r3]
+
+ // left half
+ vld1.16 {d24}, [r0], r5
+ vld1.16 {d25}, [r0], r5
+ vld1.16 {d26}, [r0], r5
+ vld1.16 {d27}, [r0], r5
+ vld1.16 {d28}, [r0], r5
+ vld1.16 {d29}, [r0], r5
+ vld1.16 {d30}, [r0], r5
+ vld1.16 {d31}, [r0], r5
+ sub r0, #128
+ tr8_begin d25, d27, d29, d31
+ tr4 d24, d26, d28, d30
+ tr8_end #7
+ vst1.16 {d2}, [r0], r5
+ vst1.16 {d3}, [r0], r5
+ vst1.16 {d4}, [r0], r5
+ vst1.16 {d5}, [r0], r5
+ vst1.16 {d6}, [r0], r5
+ vst1.16 {d7}, [r0], r5
+ vst1.16 {d8}, [r0], r5
+ vst1.16 {d9}, [r0], r5
+ sub r0, #128
+ //skip right half if col_limit in r1 is less than 4
+ cmp r1, #4
+ blt 1f
+ //right half
+ add r0, #8
+ vld1.16 {d24}, [r0], r5
+ vld1.16 {d25}, [r0], r5
+ vld1.16 {d26}, [r0], r5
+ vld1.16 {d27}, [r0], r5
+ vld1.16 {d28}, [r0], r5
+ vld1.16 {d29}, [r0], r5
+ vld1.16 {d30}, [r0], r5
+ vld1.16 {d31}, [r0], r5
+ sub r0, #128
+ tr8_begin d25, d27, d29, d31
+ tr4 d24, d26, d28, d30
+ tr8_end #7
+ vst1.16 {d2}, [r0], r5
+ vst1.16 {d3}, [r0], r5
+ vst1.16 {d4}, [r0], r5
+ vst1.16 {d5}, [r0], r5
+ vst1.16 {d6}, [r0], r5
+ vst1.16 {d7}, [r0], r5
+ vst1.16 {d8}, [r0], r5
+ vst1.16 {d9}, [r0], r5
+ sub r0, #136
+1:
+ // top half
+ vldm r0, {q12-q15} // coeffs
+ transpose_16b_4x4 d24, d26, d28, d30
+ transpose_16b_4x4 d25, d27, d29, d31
+ tr8_begin d26, d30, d27, d31
+ tr4 d24, d28, d25, d29
+ tr8_end #12
+ transpose_16b_4x4 d2, d3, d4, d5
+ transpose_16b_4x4 d6, d7, d8, d9
+ vswp d7, d5
+ vswp d7, d8
+ vswp d3, d6
+ vswp d6, d4
+ vstm r0!, {q1-q4}
+
+ // bottom half
+ vldm r0, {q12-q15} // coeffs
+ transpose_16b_4x4 d24, d26, d28, d30
+ transpose_16b_4x4 d25, d27, d29, d31
+ tr8_begin d26, d30, d27, d31
+ tr4 d24, d28, d25, d29
+ tr8_end #12
+ transpose_16b_4x4 d2, d3, d4, d5
+ transpose_16b_4x4 d6, d7, d8, d9
+ vswp d7, d5
+ vswp d7, d8
+ vswp d3, d6
+ vswp d6, d4
+ //vstm r0, {q1-q4}
+ vst1.16 {q1-q2}, [r0]
+ add r0, #32
+ vst1.16 {q3-q4}, [r0]
+ sub r0, #32
+ vpop {d8-d15}
+ pop {r4-r8}
+ bx lr
+endfunc
+
+.align 4
+tr4f:
+.word 0x00240053 // 36 and d1[0] = 83
+.word 0x00000000
+tr8f:
+.word 0x0059004b // 89, d0[0] = 75
+.word 0x00320012 // 50, d0[2] = 18
+tr16:
+.word 0x005a0057 // 90, d2[0] = 87
+.word 0x00500046 // 80, d2[2] = 70
+.word 0x0039002b // 57, d2[0] = 43
+.word 0x00190009 // 25, d2[2] = 9
diff --git a/libavcodec/arm/hevcdsp_init_arm.c b/libavcodec/arm/hevcdsp_init_arm.c
new file mode 100644
index 0000000000..adcc454511
--- /dev/null
+++ b/libavcodec/arm/hevcdsp_init_arm.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2014 Seppo Tomperi <seppo.tomperi@vtt.fi>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/arm/cpu.h"
+#include "libavcodec/hevcdsp.h"
+#include "hevcdsp_arm.h"
+
+av_cold void ff_hevcdsp_init_arm(HEVCDSPContext *c, const int bit_depth)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (have_neon(cpu_flags))
+ ff_hevcdsp_init_neon(c, bit_depth);
+}
diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
new file mode 100644
index 0000000000..55918077e2
--- /dev/null
+++ b/libavcodec/arm/hevcdsp_init_neon.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2014 Seppo Tomperi <seppo.tomperi@vtt.fi>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/arm/cpu.h"
+#include "libavcodec/hevcdsp.h"
+#include "hevcdsp_arm.h"
+
+void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+void ff_hevc_v_loop_filter_chroma_neon(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+void ff_hevc_h_loop_filter_chroma_neon(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+void ff_hevc_transform_4x4_neon_8(int16_t *coeffs, int col_limit);
+void ff_hevc_transform_8x8_neon_8(int16_t *coeffs, int col_limit);
+void ff_hevc_idct_4x4_dc_neon_8(int16_t *coeffs);
+void ff_hevc_idct_8x8_dc_neon_8(int16_t *coeffs);
+void ff_hevc_idct_16x16_dc_neon_8(int16_t *coeffs);
+void ff_hevc_idct_32x32_dc_neon_8(int16_t *coeffs);
+void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs);
+void ff_hevc_transform_add_4x4_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+void ff_hevc_transform_add_8x8_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+
+#define PUT_PIXELS(name) \
+ void name(int16_t *dst, uint8_t *src, \
+ ptrdiff_t srcstride, int height, \
+ intptr_t mx, intptr_t my, int width)
+PUT_PIXELS(ff_hevc_put_pixels_w2_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w4_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w6_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w8_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w12_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w16_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w24_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w32_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w48_neon_8);
+PUT_PIXELS(ff_hevc_put_pixels_w64_neon_8);
+#undef PUT_PIXELS
+
+static void (*put_hevc_qpel_neon[4][4])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int height, int width);
+static void (*put_hevc_qpel_uw_neon[4][4])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int width, int height, int16_t* src2, ptrdiff_t src2stride);
+void ff_hevc_put_qpel_neon_wrapper(int16_t *dst, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_qpel_uni_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width);
+#define QPEL_FUNC(name) \
+ void name(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, \
+ int height, int width)
+
+QPEL_FUNC(ff_hevc_put_qpel_v1_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_v2_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_v3_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h1_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h2_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h3_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h1v1_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h1v2_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h1v3_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h2v1_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h2v2_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h2v3_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h3v1_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h3v2_neon_8);
+QPEL_FUNC(ff_hevc_put_qpel_h3v3_neon_8);
+#undef QPEL_FUNC
+
+#define QPEL_FUNC_UW_PIX(name) \
+ void name(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride, \
+ int height, intptr_t mx, intptr_t my, int width);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w4_neon_8);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w8_neon_8);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w16_neon_8);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w24_neon_8);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w32_neon_8);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w48_neon_8);
+QPEL_FUNC_UW_PIX(ff_hevc_put_qpel_uw_pixels_w64_neon_8);
+#undef QPEL_FUNC_UW_PIX
+
+#define QPEL_FUNC_UW(name) \
+ void name(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride, \
+ int width, int height, int16_t* src2, ptrdiff_t src2stride);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_pixels_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_v1_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_v2_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_v3_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h1_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h2_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h1v1_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h1v2_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h1v3_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h2v1_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h2v2_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h2v3_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v1_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v2_neon_8);
+QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v3_neon_8);
+#undef QPEL_FUNC_UW
+
+void ff_hevc_put_qpel_neon_wrapper(int16_t *dst, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width) {
+
+ put_hevc_qpel_neon[my][mx](dst, MAX_PB_SIZE, src, srcstride, height, width);
+}
+
+void ff_hevc_put_qpel_uni_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width) {
+
+ put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, NULL, 0);
+}
+
+void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width) {
+ put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE);
+}
+
+av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
+{
+ if (bit_depth == 8) {
+ int x;
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_neon;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_neon;
+ c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_neon;
+ c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_neon;
+ c->idct[0] = ff_hevc_transform_4x4_neon_8;
+ c->idct[1] = ff_hevc_transform_8x8_neon_8;
+ c->idct_dc[0] = ff_hevc_idct_4x4_dc_neon_8;
+ c->idct_dc[1] = ff_hevc_idct_8x8_dc_neon_8;
+ c->idct_dc[2] = ff_hevc_idct_16x16_dc_neon_8;
+ c->idct_dc[3] = ff_hevc_idct_32x32_dc_neon_8;
+ c->transform_add[0] = ff_hevc_transform_add_4x4_neon_8;
+ c->transform_add[1] = ff_hevc_transform_add_8x8_neon_8;
+ c->transform_add[2] = ff_hevc_transform_add_16x16_neon_8;
+ c->transform_add[3] = ff_hevc_transform_add_32x32_neon_8;
+ c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8;
+ put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8;
+ put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8;
+ put_hevc_qpel_neon[3][0] = ff_hevc_put_qpel_v3_neon_8;
+ put_hevc_qpel_neon[0][1] = ff_hevc_put_qpel_h1_neon_8;
+ put_hevc_qpel_neon[0][2] = ff_hevc_put_qpel_h2_neon_8;
+ put_hevc_qpel_neon[0][3] = ff_hevc_put_qpel_h3_neon_8;
+ put_hevc_qpel_neon[1][1] = ff_hevc_put_qpel_h1v1_neon_8;
+ put_hevc_qpel_neon[1][2] = ff_hevc_put_qpel_h2v1_neon_8;
+ put_hevc_qpel_neon[1][3] = ff_hevc_put_qpel_h3v1_neon_8;
+ put_hevc_qpel_neon[2][1] = ff_hevc_put_qpel_h1v2_neon_8;
+ put_hevc_qpel_neon[2][2] = ff_hevc_put_qpel_h2v2_neon_8;
+ put_hevc_qpel_neon[2][3] = ff_hevc_put_qpel_h3v2_neon_8;
+ put_hevc_qpel_neon[3][1] = ff_hevc_put_qpel_h1v3_neon_8;
+ put_hevc_qpel_neon[3][2] = ff_hevc_put_qpel_h2v3_neon_8;
+ put_hevc_qpel_neon[3][3] = ff_hevc_put_qpel_h3v3_neon_8;
+ put_hevc_qpel_uw_neon[1][0] = ff_hevc_put_qpel_uw_v1_neon_8;
+ put_hevc_qpel_uw_neon[2][0] = ff_hevc_put_qpel_uw_v2_neon_8;
+ put_hevc_qpel_uw_neon[3][0] = ff_hevc_put_qpel_uw_v3_neon_8;
+ put_hevc_qpel_uw_neon[0][1] = ff_hevc_put_qpel_uw_h1_neon_8;
+ put_hevc_qpel_uw_neon[0][2] = ff_hevc_put_qpel_uw_h2_neon_8;
+ put_hevc_qpel_uw_neon[0][3] = ff_hevc_put_qpel_uw_h3_neon_8;
+ put_hevc_qpel_uw_neon[1][1] = ff_hevc_put_qpel_uw_h1v1_neon_8;
+ put_hevc_qpel_uw_neon[1][2] = ff_hevc_put_qpel_uw_h2v1_neon_8;
+ put_hevc_qpel_uw_neon[1][3] = ff_hevc_put_qpel_uw_h3v1_neon_8;
+ put_hevc_qpel_uw_neon[2][1] = ff_hevc_put_qpel_uw_h1v2_neon_8;
+ put_hevc_qpel_uw_neon[2][2] = ff_hevc_put_qpel_uw_h2v2_neon_8;
+ put_hevc_qpel_uw_neon[2][3] = ff_hevc_put_qpel_uw_h3v2_neon_8;
+ put_hevc_qpel_uw_neon[3][1] = ff_hevc_put_qpel_uw_h1v3_neon_8;
+ put_hevc_qpel_uw_neon[3][2] = ff_hevc_put_qpel_uw_h2v3_neon_8;
+ put_hevc_qpel_uw_neon[3][3] = ff_hevc_put_qpel_uw_h3v3_neon_8;
+ for (x = 0; x < 10; x++) {
+ c->put_hevc_qpel[x][1][0] = ff_hevc_put_qpel_neon_wrapper;
+ c->put_hevc_qpel[x][0][1] = ff_hevc_put_qpel_neon_wrapper;
+ c->put_hevc_qpel[x][1][1] = ff_hevc_put_qpel_neon_wrapper;
+ c->put_hevc_qpel_uni[x][1][0] = ff_hevc_put_qpel_uni_neon_wrapper;
+ c->put_hevc_qpel_uni[x][0][1] = ff_hevc_put_qpel_uni_neon_wrapper;
+ c->put_hevc_qpel_uni[x][1][1] = ff_hevc_put_qpel_uni_neon_wrapper;
+ c->put_hevc_qpel_bi[x][1][0] = ff_hevc_put_qpel_bi_neon_wrapper;
+ c->put_hevc_qpel_bi[x][0][1] = ff_hevc_put_qpel_bi_neon_wrapper;
+ c->put_hevc_qpel_bi[x][1][1] = ff_hevc_put_qpel_bi_neon_wrapper;
+ }
+ c->put_hevc_qpel[0][0][0] = ff_hevc_put_pixels_w2_neon_8;
+ c->put_hevc_qpel[1][0][0] = ff_hevc_put_pixels_w4_neon_8;
+ c->put_hevc_qpel[2][0][0] = ff_hevc_put_pixels_w6_neon_8;
+ c->put_hevc_qpel[3][0][0] = ff_hevc_put_pixels_w8_neon_8;
+ c->put_hevc_qpel[4][0][0] = ff_hevc_put_pixels_w12_neon_8;
+ c->put_hevc_qpel[5][0][0] = ff_hevc_put_pixels_w16_neon_8;
+ c->put_hevc_qpel[6][0][0] = ff_hevc_put_pixels_w24_neon_8;
+ c->put_hevc_qpel[7][0][0] = ff_hevc_put_pixels_w32_neon_8;
+ c->put_hevc_qpel[8][0][0] = ff_hevc_put_pixels_w48_neon_8;
+ c->put_hevc_qpel[9][0][0] = ff_hevc_put_pixels_w64_neon_8;
+
+ c->put_hevc_qpel_uni[1][0][0] = ff_hevc_put_qpel_uw_pixels_w4_neon_8;
+ c->put_hevc_qpel_uni[3][0][0] = ff_hevc_put_qpel_uw_pixels_w8_neon_8;
+ c->put_hevc_qpel_uni[5][0][0] = ff_hevc_put_qpel_uw_pixels_w16_neon_8;
+ c->put_hevc_qpel_uni[6][0][0] = ff_hevc_put_qpel_uw_pixels_w24_neon_8;
+ c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_qpel_uw_pixels_w32_neon_8;
+ c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_qpel_uw_pixels_w48_neon_8;
+ c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_qpel_uw_pixels_w64_neon_8;
+ }
+}
diff --git a/libavcodec/arm/hevcdsp_qpel_neon.S b/libavcodec/arm/hevcdsp_qpel_neon.S
new file mode 100644
index 0000000000..86f92cf75a
--- /dev/null
+++ b/libavcodec/arm/hevcdsp_qpel_neon.S
@@ -0,0 +1,999 @@
+/*
+ * Copyright (c) 2014 - 2015 Seppo Tomperi <seppo.tomperi@vtt.fi>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/arm/asm.S"
+#include "neon.S"
+
+#define MAX_PB_SIZE #64
+
+.macro regshuffle_d8
+ vmov d16, d17
+ vmov d17, d18
+ vmov d18, d19
+ vmov d19, d20
+ vmov d20, d21
+ vmov d21, d22
+ vmov d22, d23
+.endm
+
+.macro regshuffle_q8
+ vmov q0, q1
+ vmov q1, q2
+ vmov q2, q3
+ vmov q3, q4
+ vmov q4, q5
+ vmov q5, q6
+ vmov q6, q7
+.endm
+
+.macro vextin8
+ pld [r2]
+ vld1.8 {q11}, [r2], r3
+ vext.8 d16, d22, d23, #1
+ vext.8 d17, d22, d23, #2
+ vext.8 d18, d22, d23, #3
+ vext.8 d19, d22, d23, #4
+ vext.8 d20, d22, d23, #5
+ vext.8 d21, d22, d23, #6
+ vext.8 d22, d22, d23, #7
+.endm
+
+.macro loadin8
+ pld [r2]
+ vld1.8 {d16}, [r2], r3
+ pld [r2]
+ vld1.8 {d17}, [r2], r3
+ pld [r2]
+ vld1.8 {d18}, [r2], r3
+ pld [r2]
+ vld1.8 {d19}, [r2], r3
+ pld [r2]
+ vld1.8 {d20}, [r2], r3
+ pld [r2]
+ vld1.8 {d21}, [r2], r3
+ pld [r2]
+ vld1.8 {d22}, [r2], r3
+ pld [r2]
+ vld1.8 {d23}, [r2], r3
+.endm
+
+.macro qpel_filter_1_32b
+ vmov.i16 d16, #58
+ vmov.i16 d17, #10
+ vmull.s16 q9, d6, d16 // 58 * d0
+ vmull.s16 q10, d7, d16 // 58 * d1
+ vmov.i16 d16, #17
+ vmull.s16 q11, d4, d17 // 10 * c0
+ vmull.s16 q12, d5, d17 // 10 * c1
+ vmov.i16 d17, #5
+ vmull.s16 q13, d8, d16 // 17 * e0
+ vmull.s16 q14, d9, d16 // 17 * e1
+ vmull.s16 q15, d10, d17 // 5 * f0
+ vmull.s16 q8, d11, d17 // 5 * f1
+ vsub.s32 q9, q11 // 58 * d0 - 10 * c0
+ vsub.s32 q10, q12 // 58 * d1 - 10 * c1
+ vshll.s16 q11, d2, #2 // 4 * b0
+ vshll.s16 q12, d3, #2 // 4 * b1
+ vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0
+ vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1
+ vsubl.s16 q13, d12, d0 // g0 - a0
+ vsubl.s16 q14, d13, d1 // g1 - a1
+ vadd.s32 q9, q11 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0
+ vadd.s32 q10, q12 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1
+ vsub.s32 q13, q15 // g0 - a0 - 5 * f0
+ vsub.s32 q14, q8 // g1 - a1 - 5 * f1
+ vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0 + g0 - a0 - 5 * f0
+ vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1 + g1 - a1 - 5 * f1
+ vqshrn.s32 d16, q9, #6
+ vqshrn.s32 d17, q10, #6
+.endm
+
+// input q0 - q7
+// output q8
+.macro qpel_filter_2_32b
+ vmov.i32 q8, #11
+ vaddl.s16 q9, d6, d8 // d0 + e0
+ vaddl.s16 q10, d7, d9 // d1 + e1
+ vaddl.s16 q11, d4, d10 // c0 + f0
+ vaddl.s16 q12, d5, d11 // c1 + f1
+ vmul.s32 q11, q8 // 11 * (c0 + f0)
+ vmul.s32 q12, q8 // 11 * (c1 + f1)
+ vmov.i32 q8, #40
+ vaddl.s16 q15, d2, d12 // b0 + g0
+ vmul.s32 q9, q8 // 40 * (d0 + e0)
+ vmul.s32 q10, q8 // 40 * (d1 + e1)
+ vaddl.s16 q8, d3, d13 // b1 + g1
+ vaddl.s16 q13, d0, d14 // a0 + h0
+ vaddl.s16 q14, d1, d15 // a1 + h1
+ vshl.s32 q15, #2 // 4*(b0+g0)
+ vshl.s32 q8, #2 // 4*(b1+g1)
+ vadd.s32 q11, q13 // 11 * (c0 + f0) + a0 + h0
+ vadd.s32 q12, q14 // 11 * (c1 + f1) + a1 + h1
+ vadd.s32 q9, q15 // 40 * (d0 + e0) + 4*(b0+g0)
+ vadd.s32 q10, q8 // 40 * (d1 + e1) + 4*(b1+g1)
+ vsub.s32 q9, q11 // 40 * (d0 + e0) + 4*(b0+g0) - (11 * (c0 + f0) + a0 + h0)
+ vsub.s32 q10, q12 // 40 * (d1 + e1) + 4*(b1+g1) - (11 * (c1 + f1) + a1 + h1)
+ vqshrn.s32 d16, q9, #6
+ vqshrn.s32 d17, q10, #6
+.endm
+
+.macro qpel_filter_3_32b
+ vmov.i16 d16, #58
+ vmov.i16 d17, #10
+ vmull.s16 q9, d8, d16 // 58 * d0
+ vmull.s16 q10, d9, d16 // 58 * d1
+ vmov.i16 d16, #17
+ vmull.s16 q11, d10, d17 // 10 * c0
+ vmull.s16 q12, d11, d17 // 10 * c1
+ vmov.i16 d17, #5
+ vmull.s16 q13, d6, d16 // 17 * e0
+ vmull.s16 q14, d7, d16 // 17 * e1
+ vmull.s16 q15, d4, d17 // 5 * f0
+ vmull.s16 q8, d5, d17 // 5 * f1
+ vsub.s32 q9, q11 // 58 * d0 - 10 * c0
+ vsub.s32 q10, q12 // 58 * d1 - 10 * c1
+ vshll.s16 q11, d12, #2 // 4 * b0
+ vshll.s16 q12, d13, #2 // 4 * b1
+ vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0
+ vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1
+ vsubl.s16 q13, d2, d14 // g0 - a0
+ vsubl.s16 q14, d3, d15 // g1 - a1
+ vadd.s32 q9, q11 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0
+ vadd.s32 q10, q12 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1
+ vsub.s32 q13, q15 // g0 - a0 - 5 * f0
+ vsub.s32 q14, q8 // g1 - a1 - 5 * f1
+ vadd.s32 q9, q13 // 58 * d0 - 10 * c0 + 17 * e0 + 4 * b0 + g0 - a0 - 5 * f0
+ vadd.s32 q10, q14 // 58 * d1 - 10 * c1 + 17 * e1 + 4 * b1 + g1 - a1 - 5 * f1
+ vqshrn.s32 d16, q9, #6
+ vqshrn.s32 d17, q10, #6
+.endm
+
+.macro qpel_filter_1 out=q7
+ vmov.u8 d24, #58
+ vmov.u8 d25, #10
+ vshll.u8 q13, d20, #4 // 16*e
+ vshll.u8 q14, d21, #2 // 4*f
+ vmull.u8 \out, d19, d24 // 58*d
+ vaddw.u8 q13, q13, d20 // 17*e
+ vmull.u8 q15, d18, d25 // 10*c
+ vaddw.u8 q14, q14, d21 // 5*f
+ vsubl.u8 q12, d22, d16 // g - a
+ vadd.u16 \out, q13 // 58d + 17e
+ vshll.u8 q13, d17, #2 // 4*b
+ vadd.u16 q15, q14 // 10*c + 5*f
+ vadd.s16 q13, q12 // - a + 4*b + g
+ vsub.s16 \out, q15 // -10*c + 58*d + 17*e -5*f
+ vadd.s16 \out, q13 // -a + 4*b -10*c + 58*d + 17*e -5*f
+.endm
+
+.macro qpel_filter_2 out=q7
+ vmov.i16 q12, #10
+ vmov.i16 q14, #11
+ vaddl.u8 q13, d19, d20 // d + e
+ vaddl.u8 q15, d18, d21 // c + f
+ vmul.u16 q13, q12 // 10 * (d+e)
+ vmul.u16 q15, q14 // 11 * ( c + f)
+ vaddl.u8 \out, d17, d22 // b + g
+ vaddl.u8 q12, d16, d23 // a + h
+ vadd.u16 \out, q13 // b + 10 * (d + e) + g
+ vadd.s16 q12, q15
+ vshl.u16 \out, #2 // 4 * (b + 10 * (d + e) + g)
+ vsub.s16 \out, q12
+.endm
+
+.macro qpel_filter_3 out=q7
+ vmov.u8 d24, #58
+ vmov.u8 d25, #10
+ vshll.u8 q13, d19, #4 // 16*e
+ vshll.u8 q14, d18, #2 // 4*f
+ vmull.u8 \out, d20, d24 // 58*d
+ vaddw.u8 q13, q13, d19 // 17*e
+ vmull.u8 q15, d21, d25 // 10*c
+ vaddw.u8 q14, q14, d18 // 5*f
+ vsubl.u8 q12, d17, d23 // g - a
+ vadd.u16 \out, q13 // 58d + 17e
+ vshll.u8 q13, d22, #2 // 4*b
+ vadd.u16 q15, q14 // 10*c + 5*f
+ vadd.s16 q13, q12 // - a + 4*b + g
+ vsub.s16 \out, q15 // -10*c + 58*d + 17*e -5*f
+ vadd.s16 \out, q13 // -a + 4*b -10*c + 58*d + 17*e -5*f
+.endm
+
+.macro hevc_put_qpel_vX_neon_8 filter
+ push {r4, r5, r6, r7}
+ ldr r4, [sp, #16] // height
+ ldr r5, [sp, #20] // width
+ vpush {d8-d15}
+ sub r2, r2, r3, lsl #1
+ sub r2, r3
+ mov r12, r4
+ mov r6, r0
+ mov r7, r2
+ lsl r1, #1
+0: loadin8
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ \filter
+ vst1.16 {q7}, [r0], r1
+ regshuffle_d8
+ vld1.8 {d23}, [r2], r3
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #16
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ b 0b
+4: subs r4, #1
+ \filter
+ vst1.16 d14, [r0], r1
+ regshuffle_d8
+ vld1.32 {d23[0]}, [r2], r3
+ bne 4b
+99: vpop {d8-d15}
+ pop {r4, r5, r6, r7}
+ bx lr
+.endm
+
+.macro hevc_put_qpel_uw_vX_neon_8 filter
+ push {r4-r10}
+ ldr r5, [sp, #28] // width
+ ldr r4, [sp, #32] // height
+ ldr r8, [sp, #36] // src2
+ ldr r9, [sp, #40] // src2stride
+ vpush {d8-d15}
+ sub r2, r2, r3, lsl #1
+ sub r2, r3
+ mov r12, r4
+ mov r6, r0
+ mov r7, r2
+ cmp r8, #0
+ bne .Lbi\@
+0: loadin8
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ \filter
+ vqrshrun.s16 d0, q7, #6
+ vst1.8 d0, [r0], r1
+ regshuffle_d8
+ vld1.8 {d23}, [r2], r3
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #8
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ b 0b
+4: subs r4, #1
+ \filter
+ vqrshrun.s16 d0, q7, #6
+ vst1.32 d0[0], [r0], r1
+ regshuffle_d8
+ vld1.32 {d23[0]}, [r2], r3
+ bne 4b
+ b 99f
+.Lbi\@: lsl r9, #1
+ mov r10, r8
+0: loadin8
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ \filter
+ vld1.16 {q0}, [r8], r9
+ vqadd.s16 q0, q7
+ vqrshrun.s16 d0, q0, #7
+ vst1.8 d0, [r0], r1
+ regshuffle_d8
+ vld1.8 {d23}, [r2], r3
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #8
+ mov r0, r6
+ add r10, #16
+ mov r8, r10
+ add r7, #8
+ mov r2, r7
+ b 0b
+4: subs r4, #1
+ \filter
+ vld1.16 d0, [r8], r9
+ vqadd.s16 d0, d14
+ vqrshrun.s16 d0, q0, #7
+ vst1.32 d0[0], [r0], r1
+ regshuffle_d8
+ vld1.32 {d23[0]}, [r2], r3
+ bne 4b
+99: vpop {d8-d15}
+ pop {r4-r10}
+ bx lr
+.endm
+
+function ff_hevc_put_qpel_v1_neon_8, export=1
+ hevc_put_qpel_vX_neon_8 qpel_filter_1
+endfunc
+
+function ff_hevc_put_qpel_v2_neon_8, export=1
+ hevc_put_qpel_vX_neon_8 qpel_filter_2
+endfunc
+
+function ff_hevc_put_qpel_v3_neon_8, export=1
+ hevc_put_qpel_vX_neon_8 qpel_filter_3
+endfunc
+
+
+function ff_hevc_put_qpel_uw_v1_neon_8, export=1
+ hevc_put_qpel_uw_vX_neon_8 qpel_filter_1
+endfunc
+
+function ff_hevc_put_qpel_uw_v2_neon_8, export=1
+ hevc_put_qpel_uw_vX_neon_8 qpel_filter_2
+endfunc
+
+function ff_hevc_put_qpel_uw_v3_neon_8, export=1
+ hevc_put_qpel_uw_vX_neon_8 qpel_filter_3
+endfunc
+
+.macro hevc_put_qpel_hX_neon_8 filter
+ push {r4, r5, r6, r7}
+ ldr r4, [sp, #16] // height
+ ldr r5, [sp, #20] // width
+
+ vpush {d8-d15}
+ sub r2, #4
+ lsl r1, #1
+ mov r12, r4
+ mov r6, r0
+ mov r7, r2
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ vextin8
+ \filter
+ vst1.16 {q7}, [r0], r1
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #16
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ cmp r5, #4
+ bne 8b
+4: subs r4, #1
+ vextin8
+ \filter
+ vst1.16 d14, [r0], r1
+ bne 4b
+99: vpop {d8-d15}
+ pop {r4, r5, r6, r7}
+ bx lr
+.endm
+
+.macro hevc_put_qpel_uw_hX_neon_8 filter
+ push {r4-r10}
+ ldr r5, [sp, #28] // width
+ ldr r4, [sp, #32] // height
+ ldr r8, [sp, #36] // src2
+ ldr r9, [sp, #40] // src2stride
+ vpush {d8-d15}
+ sub r2, #4
+ mov r12, r4
+ mov r6, r0
+ mov r7, r2
+ cmp r8, #0
+ bne .Lbi\@
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ vextin8
+ \filter
+ vqrshrun.s16 d0, q7, #6
+ vst1.8 d0, [r0], r1
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #8
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ cmp r5, #4
+ bne 8b
+4: subs r4, #1
+ vextin8
+ \filter
+ vqrshrun.s16 d0, q7, #6
+ vst1.32 d0[0], [r0], r1
+ bne 4b
+ b 99f
+.Lbi\@:
+ lsl r9, #1
+ cmp r5, #4
+ beq 4f
+ mov r10, r8
+8: subs r4, #1
+ vextin8
+ \filter
+ vld1.16 {q0}, [r8], r9
+ vqadd.s16 q0, q7
+ vqrshrun.s16 d0, q0, #7
+ vst1.8 d0, [r0], r1
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #8
+ add r10, #16
+ mov r8, r10
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ cmp r5, #4
+ bne 8b
+4: subs r4, #1
+ vextin8
+ \filter
+ vld1.16 d0, [r8], r9
+ vqadd.s16 d0, d14
+ vqrshrun.s16 d0, q0, #7
+ vst1.32 d0[0], [r0], r1
+ bne 4b
+99: vpop {d8-d15}
+ pop {r4-r10}
+ bx lr
+.endm
+
+function ff_hevc_put_qpel_h1_neon_8, export=1
+ hevc_put_qpel_hX_neon_8 qpel_filter_1
+endfunc
+
+function ff_hevc_put_qpel_h2_neon_8, export=1
+ hevc_put_qpel_hX_neon_8 qpel_filter_2
+endfunc
+
+function ff_hevc_put_qpel_h3_neon_8, export=1
+ hevc_put_qpel_hX_neon_8 qpel_filter_3
+endfunc
+
+
+function ff_hevc_put_qpel_uw_h1_neon_8, export=1
+ hevc_put_qpel_uw_hX_neon_8 qpel_filter_1
+endfunc
+
+function ff_hevc_put_qpel_uw_h2_neon_8, export=1
+ hevc_put_qpel_uw_hX_neon_8 qpel_filter_2
+endfunc
+
+function ff_hevc_put_qpel_uw_h3_neon_8, export=1
+ hevc_put_qpel_uw_hX_neon_8 qpel_filter_3
+endfunc
+
+.macro hevc_put_qpel_hXvY_neon_8 filterh filterv
+ push {r4, r5, r6, r7}
+ ldr r4, [sp, #16] // height
+ ldr r5, [sp, #20] // width
+
+ vpush {d8-d15}
+ sub r2, #4
+ sub r2, r2, r3, lsl #1
+ sub r2, r3 // extra_before 3
+ lsl r1, #1
+ mov r12, r4
+ mov r6, r0
+ mov r7, r2
+0: vextin8
+ \filterh q0
+ vextin8
+ \filterh q1
+ vextin8
+ \filterh q2
+ vextin8
+ \filterh q3
+ vextin8
+ \filterh q4
+ vextin8
+ \filterh q5
+ vextin8
+ \filterh q6
+ vextin8
+ \filterh q7
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ \filterv
+ vst1.16 {q8}, [r0], r1
+ regshuffle_q8
+ vextin8
+ \filterh q7
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #16
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ b 0b
+4: subs r4, #1
+ \filterv
+ vst1.16 d16, [r0], r1
+ regshuffle_q8
+ vextin8
+ \filterh q7
+ bne 4b
+99: vpop {d8-d15}
+ pop {r4, r5, r6, r7}
+ bx lr
+.endm
+
+.macro hevc_put_qpel_uw_hXvY_neon_8 filterh filterv
+ push {r4-r10}
+ ldr r5, [sp, #28] // width
+ ldr r4, [sp, #32] // height
+ ldr r8, [sp, #36] // src2
+ ldr r9, [sp, #40] // src2stride
+ vpush {d8-d15}
+ sub r2, #4
+ sub r2, r2, r3, lsl #1
+ sub r2, r3 // extra_before 3
+ mov r12, r4
+ mov r6, r0
+ mov r7, r2
+ cmp r8, #0
+ bne .Lbi\@
+0: vextin8
+ \filterh q0
+ vextin8
+ \filterh q1
+ vextin8
+ \filterh q2
+ vextin8
+ \filterh q3
+ vextin8
+ \filterh q4
+ vextin8
+ \filterh q5
+ vextin8
+ \filterh q6
+ vextin8
+ \filterh q7
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ \filterv
+ vqrshrun.s16 d0, q8, #6
+ vst1.8 d0, [r0], r1
+ regshuffle_q8
+ vextin8
+ \filterh q7
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #8
+ mov r0, r6
+ add r7, #8
+ mov r2, r7
+ b 0b
+4: subs r4, #1
+ \filterv
+ vqrshrun.s16 d0, q8, #6
+ vst1.32 d0[0], [r0], r1
+ regshuffle_q8
+ vextin8
+ \filterh q7
+ bne 4b
+ b 99f
+.Lbi\@: lsl r9, #1
+ mov r10, r8
+0: vextin8
+ \filterh q0
+ vextin8
+ \filterh q1
+ vextin8
+ \filterh q2
+ vextin8
+ \filterh q3
+ vextin8
+ \filterh q4
+ vextin8
+ \filterh q5
+ vextin8
+ \filterh q6
+ vextin8
+ \filterh q7
+ cmp r5, #4
+ beq 4f
+8: subs r4, #1
+ \filterv
+ vld1.16 {q0}, [r8], r9
+ vqadd.s16 q0, q8
+ vqrshrun.s16 d0, q0, #7
+ vst1.8 d0, [r0], r1
+ regshuffle_q8
+ vextin8
+ \filterh q7
+ bne 8b
+ subs r5, #8
+ beq 99f
+ mov r4, r12
+ add r6, #8
+ mov r0, r6
+ add r10, #16
+ mov r8, r10
+ add r7, #8
+ mov r2, r7
+ b 0b
+4: subs r4, #1
+ \filterv
+ vld1.16 d0, [r8], r9
+ vqadd.s16 d0, d16
+ vqrshrun.s16 d0, q0, #7
+ vst1.32 d0[0], [r0], r1
+ regshuffle_q8
+ vextin8
+ \filterh q7
+ bne 4b
+99: vpop {d8-d15}
+ pop {r4-r10}
+ bx lr
+.endm
+
+
+function ff_hevc_put_qpel_h1v1_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_h2v1_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_h3v1_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_h1v2_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_h2v2_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_h3v2_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_h1v3_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b
+endfunc
+
+function ff_hevc_put_qpel_h2v3_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b
+endfunc
+
+function ff_hevc_put_qpel_h3v3_neon_8, export=1
+ hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b
+endfunc
+
+
+function ff_hevc_put_qpel_uw_h1v1_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h2v1_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h3v1_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h1v2_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h2v2_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h3v2_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h1v3_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h2v3_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b
+endfunc
+
+function ff_hevc_put_qpel_uw_h3v3_neon_8, export=1
+ hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b
+endfunc
+
+.macro init_put_pixels
+ pld [r1]
+ pld [r1, r2]
+ mov r12, MAX_PB_SIZE
+ lsl r12, #1
+.endm
+
+function ff_hevc_put_pixels_w2_neon_8, export=1
+ init_put_pixels
+ vmov.u8 d5, #255
+ vshr.u64 d5, #32
+0: subs r3, #1
+ vld1.32 {d0[0]}, [r1], r2
+ pld [r1]
+ vld1.32 d6, [r0]
+ vshll.u8 q0, d0, #6
+ vbit d6, d0, d5
+ vst1.32 d6, [r0], r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w4_neon_8, export=1
+ init_put_pixels
+0: subs r3, #2
+ vld1.32 {d0[0]}, [r1], r2
+ vld1.32 {d0[1]}, [r1], r2
+ pld [r1]
+ pld [r1, r2]
+ vshll.u8 q0, d0, #6
+ vst1.64 {d0}, [r0], r12
+ vst1.64 {d1}, [r0], r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w6_neon_8, export=1
+ init_put_pixels
+ vmov.u8 q10, #255
+ vshr.u64 d21, #32
+0: subs r3, #1
+ vld1.16 {d0}, [r1], r2
+ pld [r1]
+ vshll.u8 q0, d0, #6
+ vld1.8 {q12}, [r0]
+ vbit q12, q0, q10
+ vst1.8 {q12}, [r0], r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w8_neon_8, export=1
+ init_put_pixels
+0: subs r3, #2
+ vld1.8 {d0}, [r1], r2
+ vld1.8 {d2}, [r1], r2
+ pld [r1]
+ pld [r1, r2]
+ vshll.u8 q0, d0, #6
+ vshll.u8 q1, d2, #6
+ vst1.16 {q0}, [r0], r12
+ vst1.16 {q1}, [r0], r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w12_neon_8, export=1
+ init_put_pixels
+0: subs r3, #2
+ vld1.64 {d0}, [r1]
+ add r1, #8
+ vld1.32 {d1[0]}, [r1], r2
+ sub r1, #8
+ vld1.64 {d2}, [r1]
+ add r1, #8
+ vld1.32 {d1[1]}, [r1], r2
+ sub r1, #8
+ pld [r1]
+ pld [r1, r2]
+ vshll.u8 q8, d0, #6
+ vshll.u8 q9, d1, #6
+ vshll.u8 q10, d2, #6
+ vmov d22, d19
+ vst1.64 {d16, d17, d18}, [r0], r12
+ vst1.64 {d20, d21, d22}, [r0], r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w16_neon_8, export=1
+ init_put_pixels
+0: subs r3, #2
+ vld1.8 {q0}, [r1], r2
+ vld1.8 {q1}, [r1], r2
+ pld [r1]
+ pld [r1, r2]
+ vshll.u8 q8, d0, #6
+ vshll.u8 q9, d1, #6
+ vshll.u8 q10, d2, #6
+ vshll.u8 q11, d3, #6
+ vst1.8 {q8, q9}, [r0], r12
+ vst1.8 {q10, q11}, [r0], r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w24_neon_8, export=1
+ init_put_pixels
+0: subs r3, #1
+ vld1.8 {d0, d1, d2}, [r1], r2
+ pld [r1]
+ vshll.u8 q10, d0, #6
+ vshll.u8 q11, d1, #6
+ vshll.u8 q12, d2, #6
+ vstm r0, {q10, q11, q12}
+ add r0, r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w32_neon_8, export=1
+ init_put_pixels
+0: subs r3, #1
+ vld1.8 {q0, q1}, [r1], r2
+ pld [r1]
+ vshll.u8 q8, d0, #6
+ vshll.u8 q9, d1, #6
+ vshll.u8 q10, d2, #6
+ vshll.u8 q11, d3, #6
+ vstm r0, {q8, q9, q10, q11}
+ add r0, r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w48_neon_8, export=1
+ init_put_pixels
+0: subs r3, #1
+ vld1.8 {q0, q1}, [r1]
+ add r1, #32
+ vld1.8 {q2}, [r1], r2
+ sub r1, #32
+ pld [r1]
+ vshll.u8 q8, d0, #6
+ vshll.u8 q9, d1, #6
+ vshll.u8 q10, d2, #6
+ vshll.u8 q11, d3, #6
+ vshll.u8 q12, d4, #6
+ vshll.u8 q13, d5, #6
+ vstm r0, {q8, q9, q10, q11, q12, q13}
+ add r0, r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_pixels_w64_neon_8, export=1
+ init_put_pixels
+0: subs r3, #1
+ vld1.8 {q0, q1}, [r1]
+ add r1, #32
+ vld1.8 {q2, q3}, [r1], r2
+ sub r1, #32
+ pld [r1]
+ vshll.u8 q8, d0, #6
+ vshll.u8 q9, d1, #6
+ vshll.u8 q10, d2, #6
+ vshll.u8 q11, d3, #6
+ vshll.u8 q12, d4, #6
+ vshll.u8 q13, d5, #6
+ vshll.u8 q14, d6, #6
+ vshll.u8 q15, d7, #6
+ vstm r0, {q8, q9, q10, q11, q12, q13, q14, q15}
+ add r0, r12
+ bne 0b
+ bx lr
+endfunc
+
+function ff_hevc_put_qpel_uw_pixels_neon_8, export=1
+ push {r4-r9}
+ ldr r5, [sp, #24] // width
+ ldr r4, [sp, #28] // height
+ ldr r8, [sp, #32] // src2
+ ldr r9, [sp, #36] // src2stride
+ vpush {d8-d15}
+ cmp r8, #0
+ bne 2f
+1: subs r4, #1
+ vld1.8 {d0}, [r2], r3
+ vst1.8 d0, [r0], r1
+ bne 1b
+ vpop {d8-d15}
+ pop {r4-r9}
+ bx lr
+2: subs r4, #1
+ vld1.8 {d0}, [r2], r3
+ vld1.16 {q1}, [r8], r9
+ vshll.u8 q0, d0, #6
+ vqadd.s16 q0, q1
+ vqrshrun.s16 d0, q0, #7
+ vst1.8 d0, [r0], r1
+ bne 2b
+ vpop {d8-d15}
+ pop {r4-r9}
+ bx lr
+endfunc
+
+.macro put_qpel_uw_pixels width, regs, regs2, regs3, regs4
+function ff_hevc_put_qpel_uw_pixels_w\width\()_neon_8, export=1
+ ldr r12, [sp] // height
+1: subs r12, #4
+ vld1.32 {\regs} , [r2], r3
+ vld1.32 {\regs2} , [r2], r3
+ vld1.32 {\regs3} , [r2], r3
+ vld1.32 {\regs4} , [r2], r3
+ vst1.32 {\regs} , [r0], r1
+ vst1.32 {\regs2} , [r0], r1
+ vst1.32 {\regs3} , [r0], r1
+ vst1.32 {\regs4} , [r0], r1
+ bne 1b
+ bx lr
+endfunc
+.endm
+
+.macro put_qpel_uw_pixels_m width, regs, regs2, regs3, regs4
+function ff_hevc_put_qpel_uw_pixels_w\width\()_neon_8, export=1
+ push {r4-r5}
+ ldr r12, [sp, #8] // height
+1: subs r12, #2
+ mov r4, r2
+ vld1.32 {\regs} , [r2]!
+ vld1.32 {\regs2} , [r2]
+ add r2, r4, r3
+ mov r4, r2
+ vld1.32 {\regs3} , [r2]!
+ vld1.32 {\regs4} , [r2]
+ add r2, r4, r3
+ mov r5, r0
+ vst1.32 {\regs} , [r0]!
+ vst1.32 {\regs2} , [r0]
+ add r0, r5, r1
+ mov r5, r0
+ vst1.32 {\regs3} , [r0]!
+ vst1.32 {\regs4} , [r0]
+ add r0, r5, r1
+ bne 1b
+ pop {r4-r5}
+ bx lr
+endfunc
+.endm
+
+put_qpel_uw_pixels 4, d0[0], d0[1], d1[0], d1[1]
+put_qpel_uw_pixels 8, d0, d1, d2, d3
+put_qpel_uw_pixels_m 12, d0, d1[0], d2, d3[0]
+put_qpel_uw_pixels 16, q0, q1, q2, q3
+put_qpel_uw_pixels 24, d0-d2, d3-d5, d16-d18, d19-d21
+put_qpel_uw_pixels 32, q0-q1, q2-q3, q8-q9, q10-q11
+put_qpel_uw_pixels_m 48, q0-q1, q2, q8-q9, q10
+put_qpel_uw_pixels_m 64, q0-q1, q2-q3, q8-q9, q10-q11
diff --git a/libavcodec/arm/hpeldsp_arm.S b/libavcodec/arm/hpeldsp_arm.S
index 0f8092e15e..219f793d99 100644
--- a/libavcodec/arm/hpeldsp_arm.S
+++ b/libavcodec/arm/hpeldsp_arm.S
@@ -2,20 +2,20 @@
@ ARMv4-optimized halfpel functions
@ Copyright (c) 2004 AGAWA Koji <i (AT) atty (DOT) jp>
@
-@ This file is part of Libav.
+@ This file is part of FFmpeg.
@
-@ Libav is free software; you can redistribute it and/or
+@ FFmpeg is free software; you can redistribute it and/or
@ modify it under the terms of the GNU Lesser General Public
@ License as published by the Free Software Foundation; either
@ version 2.1 of the License, or (at your option) any later version.
@
-@ Libav is distributed in the hope that it will be useful,
+@ FFmpeg is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@ Lesser General Public License for more details.
@
@ You should have received a copy of the GNU Lesser General Public
-@ License along with Libav; if not, write to the Free Software
+@ License along with FFmpeg; if not, write to the Free Software
@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@
diff --git a/libavcodec/arm/hpeldsp_arm.h b/libavcodec/arm/hpeldsp_arm.h
index a8641529d5..5f3c7741c1 100644
--- a/libavcodec/arm/hpeldsp_arm.h
+++ b/libavcodec/arm/hpeldsp_arm.h
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/hpeldsp_armv6.S b/libavcodec/arm/hpeldsp_armv6.S
index f1abc328eb..a8bd459c20 100644
--- a/libavcodec/arm/hpeldsp_armv6.S
+++ b/libavcodec/arm/hpeldsp_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/hpeldsp_init_arm.c b/libavcodec/arm/hpeldsp_init_arm.c
index 63906606a2..1977b1379b 100644
--- a/libavcodec/arm/hpeldsp_init_arm.c
+++ b/libavcodec/arm/hpeldsp_init_arm.c
@@ -2,20 +2,20 @@
* ARM-optimized halfpel functions
* Copyright (c) 2001 Lionel Ulmer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/hpeldsp_init_armv6.c b/libavcodec/arm/hpeldsp_init_armv6.c
index 67a500d513..967a8e0427 100644
--- a/libavcodec/arm/hpeldsp_init_armv6.c
+++ b/libavcodec/arm/hpeldsp_init_armv6.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/hpeldsp_init_neon.c b/libavcodec/arm/hpeldsp_init_neon.c
index 76d4eafceb..d9feadd1dd 100644
--- a/libavcodec/arm/hpeldsp_init_neon.c
+++ b/libavcodec/arm/hpeldsp_init_neon.c
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/hpeldsp_neon.S b/libavcodec/arm/hpeldsp_neon.S
index 90bc3cb8ae..cf4a6cfb8d 100644
--- a/libavcodec/arm/hpeldsp_neon.S
+++ b/libavcodec/arm/hpeldsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/idct.h b/libavcodec/arm/idct.h
index 168d64b666..39cef3a874 100644
--- a/libavcodec/arm/idct.h
+++ b/libavcodec/arm/idct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/idctdsp_arm.S b/libavcodec/arm/idctdsp_arm.S
index 34f467e86f..057eff9be8 100644
--- a/libavcodec/arm/idctdsp_arm.S
+++ b/libavcodec/arm/idctdsp_arm.S
@@ -2,27 +2,27 @@
@ ARMv4-optimized IDCT functions
@ Copyright (c) 2004 AGAWA Koji <i (AT) atty (DOT) jp>
@
-@ This file is part of Libav.
+@ This file is part of FFmpeg.
@
-@ Libav is free software; you can redistribute it and/or
+@ FFmpeg is free software; you can redistribute it and/or
@ modify it under the terms of the GNU Lesser General Public
@ License as published by the Free Software Foundation; either
@ version 2.1 of the License, or (at your option) any later version.
@
-@ Libav is distributed in the hope that it will be useful,
+@ FFmpeg is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@ Lesser General Public License for more details.
@
@ You should have received a copy of the GNU Lesser General Public
-@ License along with Libav; if not, write to the Free Software
+@ 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/arm/asm.S"
-@ void ff_add_pixels_clamped_arm(int16_t *block, uint8_t *dest, int stride)
+@ void ff_add_pixels_clamped_arm(int16_t *block, uint8_t *dest, ptrdiff_t stride)
function ff_add_pixels_clamped_arm, export=1, align=5
push {r4-r10}
mov r10, #8
diff --git a/libavcodec/arm/idctdsp_arm.h b/libavcodec/arm/idctdsp_arm.h
index 9012b82904..d7bc5cd02a 100644
--- a/libavcodec/arm/idctdsp_arm.h
+++ b/libavcodec/arm/idctdsp_arm.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/idctdsp_armv6.S b/libavcodec/arm/idctdsp_armv6.S
index c180d732fa..a6e77d6da1 100644
--- a/libavcodec/arm/idctdsp_armv6.S
+++ b/libavcodec/arm/idctdsp_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/idctdsp_init_arm.c b/libavcodec/arm/idctdsp_init_arm.c
index 8207c31589..da5da068be 100644
--- a/libavcodec/arm/idctdsp_init_arm.c
+++ b/libavcodec/arm/idctdsp_init_arm.c
@@ -2,20 +2,20 @@
* ARM-optimized IDCT functions
* Copyright (c) 2001 Lionel Ulmer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,7 @@
#include "idctdsp_arm.h"
void ff_add_pixels_clamped_arm(const int16_t *block, uint8_t *dest,
- int line_size);
+ ptrdiff_t line_size);
/* XXX: those functions should be suppressed ASAP when all IDCTs are
* converted */
@@ -63,8 +63,8 @@ av_cold void ff_idctdsp_init_arm(IDCTDSPContext *c, AVCodecContext *avctx,
{
int cpu_flags = av_get_cpu_flags();
- if (!high_bit_depth) {
- if (avctx->idct_algo == FF_IDCT_AUTO ||
+ if (!avctx->lowres && !high_bit_depth) {
+ if ((avctx->idct_algo == FF_IDCT_AUTO && !(avctx->flags & CODEC_FLAG_BITEXACT)) ||
avctx->idct_algo == FF_IDCT_ARM) {
c->idct_put = j_rev_dct_arm_put;
c->idct_add = j_rev_dct_arm_add;
diff --git a/libavcodec/arm/idctdsp_init_armv5te.c b/libavcodec/arm/idctdsp_init_armv5te.c
index 251165dd74..3d881e1f18 100644
--- a/libavcodec/arm/idctdsp_init_armv5te.c
+++ b/libavcodec/arm/idctdsp_init_armv5te.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,8 +29,9 @@
av_cold void ff_idctdsp_init_armv5te(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
- if (!high_bit_depth &&
+ if (!avctx->lowres && !high_bit_depth &&
(avctx->idct_algo == FF_IDCT_AUTO ||
+ avctx->idct_algo == FF_IDCT_SIMPLEAUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEARMV5TE)) {
c->idct_put = ff_simple_idct_put_armv5te;
c->idct_add = ff_simple_idct_add_armv5te;
diff --git a/libavcodec/arm/idctdsp_init_armv6.c b/libavcodec/arm/idctdsp_init_armv6.c
index 8f0c49b142..a3470a83df 100644
--- a/libavcodec/arm/idctdsp_init_armv6.c
+++ b/libavcodec/arm/idctdsp_init_armv6.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,13 +27,13 @@
#include "idctdsp_arm.h"
void ff_add_pixels_clamped_armv6(const int16_t *block, uint8_t *pixels,
- int line_size);
+ ptrdiff_t line_size);
av_cold void ff_idctdsp_init_armv6(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
- if (!high_bit_depth) {
- if (avctx->idct_algo == FF_IDCT_AUTO ||
+ if (!avctx->lowres && !high_bit_depth) {
+ if ((avctx->idct_algo == FF_IDCT_AUTO && !(avctx->flags & CODEC_FLAG_BITEXACT)) ||
avctx->idct_algo == FF_IDCT_SIMPLEARMV6) {
c->idct_put = ff_simple_idct_put_armv6;
c->idct_add = ff_simple_idct_add_armv6;
diff --git a/libavcodec/arm/idctdsp_init_neon.c b/libavcodec/arm/idctdsp_init_neon.c
index c94f7b6e5d..b70c5b0d44 100644
--- a/libavcodec/arm/idctdsp_init_neon.c
+++ b/libavcodec/arm/idctdsp_init_neon.c
@@ -2,20 +2,20 @@
* ARM-NEON-optimized IDCT functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,15 +27,16 @@
#include "idct.h"
#include "idctdsp_arm.h"
-void ff_add_pixels_clamped_neon(const int16_t *, uint8_t *, int);
-void ff_put_pixels_clamped_neon(const int16_t *, uint8_t *, int);
-void ff_put_signed_pixels_clamped_neon(const int16_t *, uint8_t *, int);
+void ff_add_pixels_clamped_neon(const int16_t *, uint8_t *, ptrdiff_t);
+void ff_put_pixels_clamped_neon(const int16_t *, uint8_t *, ptrdiff_t);
+void ff_put_signed_pixels_clamped_neon(const int16_t *, uint8_t *, ptrdiff_t);
av_cold void ff_idctdsp_init_neon(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
- if (!high_bit_depth) {
+ if (!avctx->lowres && !high_bit_depth) {
if (avctx->idct_algo == FF_IDCT_AUTO ||
+ avctx->idct_algo == FF_IDCT_SIMPLEAUTO ||
avctx->idct_algo == FF_IDCT_SIMPLENEON) {
c->idct_put = ff_simple_idct_put_neon;
c->idct_add = ff_simple_idct_add_neon;
diff --git a/libavcodec/arm/idctdsp_neon.S b/libavcodec/arm/idctdsp_neon.S
index 7095879bae..1911a33468 100644
--- a/libavcodec/arm/idctdsp_neon.S
+++ b/libavcodec/arm/idctdsp_neon.S
@@ -2,20 +2,20 @@
* ARM-NEON-optimized IDCT functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/int_neon.S b/libavcodec/arm/int_neon.S
index 42f37392e1..72c4c77c45 100644
--- a/libavcodec/arm/int_neon.S
+++ b/libavcodec/arm/int_neon.S
@@ -1,21 +1,21 @@
/*
* ARM NEON optimised integer operations
- * Copyright (c) 2009 Kostya Shishkov
+ * Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,7 +35,7 @@ function ff_scalarproduct_int16_neon, export=1
vmlal.s16 q2, d18, d22
vmlal.s16 q3, d19, d23
subs r2, r2, #16
- bne 1b
+ bgt 1b
vpadd.s32 d16, d0, d1
vpadd.s32 d17, d2, d3
@@ -48,3 +48,4 @@ function ff_scalarproduct_int16_neon, export=1
vmov.32 r0, d3[0]
bx lr
endfunc
+
diff --git a/libavcodec/arm/lossless_audiodsp_init_arm.c b/libavcodec/arm/lossless_audiodsp_init_arm.c
new file mode 100644
index 0000000000..981a39aff9
--- /dev/null
+++ b/libavcodec/arm/lossless_audiodsp_init_arm.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011 Mans Rullgard <mans@mansr.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
+ */
+
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/arm/cpu.h"
+#include "libavcodec/lossless_audiodsp.h"
+
+int32_t ff_scalarproduct_and_madd_int16_neon(int16_t *v1, const int16_t *v2,
+ const int16_t *v3, int len, int mul);
+
+av_cold void ff_llauddsp_init_arm(LLAudDSPContext *c)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (have_neon(cpu_flags)) {
+ c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_neon;
+ }
+}
diff --git a/libavcodec/arm/lossless_audiodsp_neon.S b/libavcodec/arm/lossless_audiodsp_neon.S
new file mode 100644
index 0000000000..ba7c45fcef
--- /dev/null
+++ b/libavcodec/arm/lossless_audiodsp_neon.S
@@ -0,0 +1,62 @@
+/*
+ * ARM NEON optimised integer operations
+ * Copyright (c) 2009 Kostya Shishkov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/arm/asm.S"
+
+@ scalarproduct_and_madd_int16(/*aligned*/v0,v1,v2,order,mul)
+function ff_scalarproduct_and_madd_int16_neon, export=1
+ vld1.16 {d28[],d29[]}, [sp]
+ vmov.i16 q0, #0
+ vmov.i16 q1, #0
+ vmov.i16 q2, #0
+ vmov.i16 q3, #0
+ mov r12, r0
+
+1: vld1.16 {d16-d17}, [r0,:128]!
+ vld1.16 {d18-d19}, [r1]!
+ vld1.16 {d20-d21}, [r2]!
+ vld1.16 {d22-d23}, [r0,:128]!
+ vld1.16 {d24-d25}, [r1]!
+ vld1.16 {d26-d27}, [r2]!
+ vmul.s16 q10, q10, q14
+ vmul.s16 q13, q13, q14
+ vmlal.s16 q0, d16, d18
+ vmlal.s16 q1, d17, d19
+ vadd.s16 q10, q8, q10
+ vadd.s16 q13, q11, q13
+ vmlal.s16 q2, d22, d24
+ vmlal.s16 q3, d23, d25
+ vst1.16 {q10}, [r12,:128]!
+ subs r3, r3, #16
+ vst1.16 {q13}, [r12,:128]!
+ bgt 1b
+
+ vpadd.s32 d16, d0, d1
+ vpadd.s32 d17, d2, d3
+ vpadd.s32 d18, d4, d5
+ vpadd.s32 d19, d6, d7
+ vpadd.s32 d0, d16, d17
+ vpadd.s32 d1, d18, d19
+ vpadd.s32 d2, d0, d1
+ vpaddl.s32 d3, d2
+ vmov.32 r0, d3[0]
+ bx lr
+endfunc
diff --git a/libavcodec/arm/mathops.h b/libavcodec/arm/mathops.h
index 45ac67d436..dc57c5571c 100644
--- a/libavcodec/arm/mathops.h
+++ b/libavcodec/arm/mathops.h
@@ -2,20 +2,20 @@
* simple math operations
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mdct_fixed_neon.S b/libavcodec/arm/mdct_fixed_neon.S
index c77be59c65..365c5e7faf 100644
--- a/libavcodec/arm/mdct_fixed_neon.S
+++ b/libavcodec/arm/mdct_fixed_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mdct_neon.S b/libavcodec/arm/mdct_neon.S
index bfe259c396..a6952fa571 100644
--- a/libavcodec/arm/mdct_neon.S
+++ b/libavcodec/arm/mdct_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised MDCT
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mdct_vfp.S b/libavcodec/arm/mdct_vfp.S
index f3fe668eae..43f6d14c0c 100644
--- a/libavcodec/arm/mdct_vfp.S
+++ b/libavcodec/arm/mdct_vfp.S
@@ -2,20 +2,20 @@
* Copyright (c) 2013 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/me_cmp_armv6.S b/libavcodec/arm/me_cmp_armv6.S
index 436e20dd25..fa5a82301e 100644
--- a/libavcodec/arm/me_cmp_armv6.S
+++ b/libavcodec/arm/me_cmp_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/me_cmp_init_arm.c b/libavcodec/arm/me_cmp_init_arm.c
index 4d73f3e0fd..03870a2bfa 100644
--- a/libavcodec/arm/me_cmp_init_arm.c
+++ b/libavcodec/arm/me_cmp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mlpdsp_armv5te.S b/libavcodec/arm/mlpdsp_armv5te.S
index 4272dae029..4f9aa485fd 100644
--- a/libavcodec/arm/mlpdsp_armv5te.S
+++ b/libavcodec/arm/mlpdsp_armv5te.S
@@ -2,20 +2,20 @@
* Copyright (c) 2014 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mlpdsp_armv6.S b/libavcodec/arm/mlpdsp_armv6.S
index 3c88021a35..d98f807559 100644
--- a/libavcodec/arm/mlpdsp_armv6.S
+++ b/libavcodec/arm/mlpdsp_armv6.S
@@ -2,20 +2,20 @@
* Copyright (c) 2014 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mlpdsp_init_arm.c b/libavcodec/arm/mlpdsp_init_arm.c
index 4cdd10caf5..34a5f61e1d 100644
--- a/libavcodec/arm/mlpdsp_init_arm.c
+++ b/libavcodec/arm/mlpdsp_init_arm.c
@@ -2,20 +2,20 @@
* Copyright (c) 2014 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegaudiodsp_fixed_armv6.S b/libavcodec/arm/mpegaudiodsp_fixed_armv6.S
index 49bd0bcaf2..977abb6939 100644
--- a/libavcodec/arm/mpegaudiodsp_fixed_armv6.S
+++ b/libavcodec/arm/mpegaudiodsp_fixed_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegaudiodsp_init_arm.c b/libavcodec/arm/mpegaudiodsp_init_arm.c
index e73aee6a2b..98e0c8a3a8 100644
--- a/libavcodec/arm/mpegaudiodsp_init_arm.c
+++ b/libavcodec/arm/mpegaudiodsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegvideo_arm.c b/libavcodec/arm/mpegvideo_arm.c
index 34e9cf18b5..918be16d03 100644
--- a/libavcodec/arm/mpegvideo_arm.c
+++ b/libavcodec/arm/mpegvideo_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2002 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegvideo_arm.h b/libavcodec/arm/mpegvideo_arm.h
index 17e3a5b024..709ae6b247 100644
--- a/libavcodec/arm/mpegvideo_arm.h
+++ b/libavcodec/arm/mpegvideo_arm.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegvideo_armv5te.c b/libavcodec/arm/mpegvideo_armv5te.c
index 3c44cd80b5..88c5f4fdad 100644
--- a/libavcodec/arm/mpegvideo_armv5te.c
+++ b/libavcodec/arm/mpegvideo_armv5te.c
@@ -2,24 +2,25 @@
* Optimization of some functions from mpegvideo.c for armv5te
* Copyright (c) 2007 Siarhei Siamashka <ssvb@users.sourceforge.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avassert.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/mpegvideo.h"
#include "mpegvideo_arm.h"
@@ -55,7 +56,7 @@ static void dct_unquantize_h263_intra_armv5te(MpegEncContext *s,
int level, qmul, qadd;
int nCoeffs;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
qmul = qscale << 1;
@@ -84,7 +85,7 @@ static void dct_unquantize_h263_inter_armv5te(MpegEncContext *s,
int qmul, qadd;
int nCoeffs;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
qadd = (qscale - 1) | 1;
qmul = qscale << 1;
diff --git a/libavcodec/arm/mpegvideo_armv5te_s.S b/libavcodec/arm/mpegvideo_armv5te_s.S
index 4426e15e91..8687d6b31c 100644
--- a/libavcodec/arm/mpegvideo_armv5te_s.S
+++ b/libavcodec/arm/mpegvideo_armv5te_s.S
@@ -2,20 +2,20 @@
* Optimization of some functions from mpegvideo.c for armv5te
* Copyright (c) 2007 Siarhei Siamashka <ssvb@users.sourceforge.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegvideo_neon.S b/libavcodec/arm/mpegvideo_neon.S
index 3e1f7b53e2..1889d7a912 100644
--- a/libavcodec/arm/mpegvideo_neon.S
+++ b/libavcodec/arm/mpegvideo_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegvideoencdsp_armv6.S b/libavcodec/arm/mpegvideoencdsp_armv6.S
index 99db501b25..ab0dad7b18 100644
--- a/libavcodec/arm/mpegvideoencdsp_armv6.S
+++ b/libavcodec/arm/mpegvideoencdsp_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/mpegvideoencdsp_init_arm.c b/libavcodec/arm/mpegvideoencdsp_init_arm.c
index ab9ba3e1be..4bfe835684 100644
--- a/libavcodec/arm/mpegvideoencdsp_init_arm.c
+++ b/libavcodec/arm/mpegvideoencdsp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/neon.S b/libavcodec/arm/neon.S
index 716a607af7..787bc4bf36 100644
--- a/libavcodec/arm/neon.S
+++ b/libavcodec/arm/neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/neontest.c b/libavcodec/arm/neontest.c
index b77bcd7223..a3b5b8e2e3 100644
--- a/libavcodec/arm/neontest.c
+++ b/libavcodec/arm/neontest.c
@@ -2,20 +2,20 @@
* check NEON registers for clobbers
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/pixblockdsp_armv6.S b/libavcodec/arm/pixblockdsp_armv6.S
index 4c925a4daa..b10ea78e88 100644
--- a/libavcodec/arm/pixblockdsp_armv6.S
+++ b/libavcodec/arm/pixblockdsp_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/pixblockdsp_init_arm.c b/libavcodec/arm/pixblockdsp_init_arm.c
index f20769b3bc..76d7509728 100644
--- a/libavcodec/arm/pixblockdsp_init_arm.c
+++ b/libavcodec/arm/pixblockdsp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,7 +24,7 @@
#include "libavcodec/avcodec.h"
#include "libavcodec/pixblockdsp.h"
-void ff_get_pixels_armv6(int16_t *block, const uint8_t *pixels, int stride);
+void ff_get_pixels_armv6(int16_t *block, const uint8_t *pixels, ptrdiff_t stride);
void ff_diff_pixels_armv6(int16_t *block, const uint8_t *s1,
const uint8_t *s2, int stride);
diff --git a/libavcodec/arm/rdft_neon.S b/libavcodec/arm/rdft_neon.S
index 7d01d53f1a..781d976354 100644
--- a/libavcodec/arm/rdft_neon.S
+++ b/libavcodec/arm/rdft_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised RDFT
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/rv34dsp_init_arm.c b/libavcodec/arm/rv34dsp_init_arm.c
index 5ce787ba7f..8bfe90b3d3 100644
--- a/libavcodec/arm/rv34dsp_init_arm.c
+++ b/libavcodec/arm/rv34dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/rv34dsp_neon.S b/libavcodec/arm/rv34dsp_neon.S
index a29123f772..3d4a83d9ac 100644
--- a/libavcodec/arm/rv34dsp_neon.S
+++ b/libavcodec/arm/rv34dsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/rv40dsp_init_arm.c b/libavcodec/arm/rv40dsp_init_arm.c
index df3e4611a1..c24854d1cd 100644
--- a/libavcodec/arm/rv40dsp_init_arm.c
+++ b/libavcodec/arm/rv40dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/rv40dsp_neon.S b/libavcodec/arm/rv40dsp_neon.S
index 6bd45eb5ad..099f88c092 100644
--- a/libavcodec/arm/rv40dsp_neon.S
+++ b/libavcodec/arm/rv40dsp_neon.S
@@ -2,20 +2,20 @@
* Copyright (c) 2011 Janne Grunau <janne-libav@jannau.net>
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/sbrdsp_init_arm.c b/libavcodec/arm/sbrdsp_init_arm.c
index 4da7967b49..4fb69f922b 100644
--- a/libavcodec/arm/sbrdsp_init_arm.c
+++ b/libavcodec/arm/sbrdsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/sbrdsp_neon.S b/libavcodec/arm/sbrdsp_neon.S
index 610397f9e2..e66abd682a 100644
--- a/libavcodec/arm/sbrdsp_neon.S
+++ b/libavcodec/arm/sbrdsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/simple_idct_arm.S b/libavcodec/arm/simple_idct_arm.S
index bf9ee3d4e6..c6300737a8 100644
--- a/libavcodec/arm/simple_idct_arm.S
+++ b/libavcodec/arm/simple_idct_arm.S
@@ -4,22 +4,22 @@
* Author: Frederic Boulay <dilb@handhelds.org>
*
* The function defined in this file is derived from the simple_idct function
- * from the libavcodec library part of the Libav project.
+ * from the libavcodec library part of the FFmpeg project.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/simple_idct_armv5te.S b/libavcodec/arm/simple_idct_armv5te.S
index bf509eeffc..d1f10b75cb 100644
--- a/libavcodec/arm/simple_idct_armv5te.S
+++ b/libavcodec/arm/simple_idct_armv5te.S
@@ -4,20 +4,20 @@
* Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2006 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/simple_idct_armv6.S b/libavcodec/arm/simple_idct_armv6.S
index 60723467a0..79cf5d41fb 100644
--- a/libavcodec/arm/simple_idct_armv6.S
+++ b/libavcodec/arm/simple_idct_armv6.S
@@ -4,20 +4,20 @@
* Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2007 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/simple_idct_neon.S b/libavcodec/arm/simple_idct_neon.S
index a1cde8d80a..c3e573c00a 100644
--- a/libavcodec/arm/simple_idct_neon.S
+++ b/libavcodec/arm/simple_idct_neon.S
@@ -6,20 +6,20 @@
* Based on Simple IDCT
* Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/startcode.h b/libavcodec/arm/startcode.h
index d7996c1a4b..cf25d9d4df 100644
--- a/libavcodec/arm/startcode.h
+++ b/libavcodec/arm/startcode.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/startcode_armv6.S b/libavcodec/arm/startcode_armv6.S
index 64078b2898..a46f009375 100644
--- a/libavcodec/arm/startcode_armv6.S
+++ b/libavcodec/arm/startcode_armv6.S
@@ -2,20 +2,20 @@
* Copyright (c) 2013 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/synth_filter_neon.S b/libavcodec/arm/synth_filter_neon.S
index 62bb6674ed..5417be7d53 100644
--- a/libavcodec/arm/synth_filter_neon.S
+++ b/libavcodec/arm/synth_filter_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/synth_filter_vfp.S b/libavcodec/arm/synth_filter_vfp.S
index 5d79e509f9..596734c5bc 100644
--- a/libavcodec/arm/synth_filter_vfp.S
+++ b/libavcodec/arm/synth_filter_vfp.S
@@ -2,20 +2,20 @@
* Copyright (c) 2013 RISC OS Open Ltd
* Author: Ben Avison <bavison@riscosopen.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vc1dsp.h b/libavcodec/arm/vc1dsp.h
index 30f059f28c..cd01ac5384 100644
--- a/libavcodec/arm/vc1dsp.h
+++ b/libavcodec/arm/vc1dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vc1dsp_init_arm.c b/libavcodec/arm/vc1dsp_init_arm.c
index a6a97c8bf9..5f2c759048 100644
--- a/libavcodec/arm/vc1dsp_init_arm.c
+++ b/libavcodec/arm/vc1dsp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,8 +28,10 @@ av_cold void ff_vc1dsp_init_arm(VC1DSPContext *dsp)
{
int cpu_flags = av_get_cpu_flags();
+#if HAVE_ARMV6
if (have_setend(cpu_flags))
dsp->startcode_find_candidate = ff_startcode_find_candidate_armv6;
+#endif
if (have_neon(cpu_flags))
ff_vc1dsp_init_neon(dsp);
}
diff --git a/libavcodec/arm/vc1dsp_init_neon.c b/libavcodec/arm/vc1dsp_init_neon.c
index 9ded7a28b9..bb873e687e 100644
--- a/libavcodec/arm/vc1dsp_init_neon.c
+++ b/libavcodec/arm/vc1dsp_init_neon.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,40 +37,38 @@ void ff_vc1_inv_trans_4x4_dc_neon(uint8_t *dest, int linesize, int16_t *block);
void ff_put_pixels8x8_neon(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int rnd);
-void ff_put_vc1_mspel_mc10_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc20_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc30_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-
-void ff_put_vc1_mspel_mc01_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc02_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc03_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-
-void ff_put_vc1_mspel_mc11_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc12_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc13_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-
-void ff_put_vc1_mspel_mc21_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc22_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc23_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-
-void ff_put_vc1_mspel_mc31_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc32_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
-void ff_put_vc1_mspel_mc33_neon(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd);
+#define DECL_PUT(X, Y) \
+void ff_put_vc1_mspel_mc##X##Y##_neon(uint8_t *dst, const uint8_t *src, \
+ ptrdiff_t stride, int rnd); \
+static void ff_put_vc1_mspel_mc##X##Y##_16_neon(uint8_t *dst, const uint8_t *src, \
+ ptrdiff_t stride, int rnd) \
+{ \
+ ff_put_vc1_mspel_mc##X##Y##_neon(dst+0, src+0, stride, rnd); \
+ ff_put_vc1_mspel_mc##X##Y##_neon(dst+8, src+8, stride, rnd); \
+ dst += 8*stride; src += 8*stride; \
+ ff_put_vc1_mspel_mc##X##Y##_neon(dst+0, src+0, stride, rnd); \
+ ff_put_vc1_mspel_mc##X##Y##_neon(dst+8, src+8, stride, rnd); \
+}
+
+DECL_PUT(1, 0)
+DECL_PUT(2, 0)
+DECL_PUT(3, 0)
+
+DECL_PUT(0, 1)
+DECL_PUT(0, 2)
+DECL_PUT(0, 3)
+
+DECL_PUT(1, 1)
+DECL_PUT(1, 2)
+DECL_PUT(1, 3)
+
+DECL_PUT(2, 1)
+DECL_PUT(2, 2)
+DECL_PUT(2, 3)
+
+DECL_PUT(3, 1)
+DECL_PUT(3, 2)
+DECL_PUT(3, 3)
void ff_put_vc1_chroma_mc8_neon(uint8_t *dst, uint8_t *src, int stride, int h,
int x, int y);
@@ -81,6 +79,10 @@ void ff_put_vc1_chroma_mc4_neon(uint8_t *dst, uint8_t *src, int stride, int h,
void ff_avg_vc1_chroma_mc4_neon(uint8_t *dst, uint8_t *src, int stride, int h,
int x, int y);
+#define FN_ASSIGN(X, Y) \
+ dsp->put_vc1_mspel_pixels_tab[0][X+4*Y] = ff_put_vc1_mspel_mc##X##Y##_16_neon; \
+ dsp->put_vc1_mspel_pixels_tab[1][X+4*Y] = ff_put_vc1_mspel_mc##X##Y##_neon
+
av_cold void ff_vc1dsp_init_neon(VC1DSPContext *dsp)
{
dsp->vc1_inv_trans_8x8 = ff_vc1_inv_trans_8x8_neon;
@@ -92,23 +94,26 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPContext *dsp)
dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_neon;
dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_neon;
- dsp->put_vc1_mspel_pixels_tab[ 0] = ff_put_pixels8x8_neon;
+ dsp->put_vc1_mspel_pixels_tab[1][ 0] = ff_put_pixels8x8_neon;
if (HAVE_AS_DN_DIRECTIVE) {
- dsp->put_vc1_mspel_pixels_tab[ 1] = ff_put_vc1_mspel_mc10_neon;
- dsp->put_vc1_mspel_pixels_tab[ 2] = ff_put_vc1_mspel_mc20_neon;
- dsp->put_vc1_mspel_pixels_tab[ 3] = ff_put_vc1_mspel_mc30_neon;
- dsp->put_vc1_mspel_pixels_tab[ 4] = ff_put_vc1_mspel_mc01_neon;
- dsp->put_vc1_mspel_pixels_tab[ 5] = ff_put_vc1_mspel_mc11_neon;
- dsp->put_vc1_mspel_pixels_tab[ 6] = ff_put_vc1_mspel_mc21_neon;
- dsp->put_vc1_mspel_pixels_tab[ 7] = ff_put_vc1_mspel_mc31_neon;
- dsp->put_vc1_mspel_pixels_tab[ 8] = ff_put_vc1_mspel_mc02_neon;
- dsp->put_vc1_mspel_pixels_tab[ 9] = ff_put_vc1_mspel_mc12_neon;
- dsp->put_vc1_mspel_pixels_tab[10] = ff_put_vc1_mspel_mc22_neon;
- dsp->put_vc1_mspel_pixels_tab[11] = ff_put_vc1_mspel_mc32_neon;
- dsp->put_vc1_mspel_pixels_tab[12] = ff_put_vc1_mspel_mc03_neon;
- dsp->put_vc1_mspel_pixels_tab[13] = ff_put_vc1_mspel_mc13_neon;
- dsp->put_vc1_mspel_pixels_tab[14] = ff_put_vc1_mspel_mc23_neon;
- dsp->put_vc1_mspel_pixels_tab[15] = ff_put_vc1_mspel_mc33_neon;
+ FN_ASSIGN(1, 0);
+ FN_ASSIGN(2, 0);
+ FN_ASSIGN(3, 0);
+
+ FN_ASSIGN(0, 1);
+ FN_ASSIGN(1, 1);
+ FN_ASSIGN(2, 1);
+ FN_ASSIGN(3, 1);
+
+ FN_ASSIGN(0, 2);
+ FN_ASSIGN(1, 2);
+ FN_ASSIGN(2, 2);
+ FN_ASSIGN(3, 2);
+
+ FN_ASSIGN(0, 3);
+ FN_ASSIGN(1, 3);
+ FN_ASSIGN(2, 3);
+ FN_ASSIGN(3, 3);
}
dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_neon;
diff --git a/libavcodec/arm/vc1dsp_neon.S b/libavcodec/arm/vc1dsp_neon.S
index fa87eded61..c4f4db9c8e 100644
--- a/libavcodec/arm/vc1dsp_neon.S
+++ b/libavcodec/arm/vc1dsp_neon.S
@@ -4,20 +4,20 @@
* Copyright (c) 2010 Rob Clark <rob@ti.com>
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/videodsp_arm.h b/libavcodec/arm/videodsp_arm.h
index a7087599cc..112cbb86c7 100644
--- a/libavcodec/arm/videodsp_arm.h
+++ b/libavcodec/arm/videodsp_arm.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/videodsp_armv5te.S b/libavcodec/arm/videodsp_armv5te.S
index bbd0a61da6..aff1161ada 100644
--- a/libavcodec/arm/videodsp_armv5te.S
+++ b/libavcodec/arm/videodsp_armv5te.S
@@ -2,20 +2,20 @@
@ ARMv5te-optimized core video DSP functions
@ Copyright (c) 2004 AGAWA Koji <i (AT) atty (DOT) jp>
@
-@ This file is part of Libav.
+@ This file is part of FFmpeg
@
-@ Libav is free software; you can redistribute it and/or
+@ FFmpeg is free software; you can redistribute it and/or
@ modify it under the terms of the GNU Lesser General Public
@ License as published by the Free Software Foundation; either
@ version 2.1 of the License, or (at your option) any later version.
@
-@ Libav is distributed in the hope that it will be useful,
+@ FFmpeg is distributed in the hope that it will be useful,
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@ Lesser General Public License for more details.
@
@ You should have received a copy of the GNU Lesser General Public
-@ License along with Libav; if not, write to the Free Software
+@ License along with FFmpeg; if not, write to the Free Software
@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@
@@ -23,9 +23,10 @@
#include "libavutil/arm/asm.S"
function ff_prefetch_arm, export=1
+1:
subs r2, r2, #1
pld [r0]
add r0, r0, r1
- bne X(ff_prefetch_arm)
+ bne 1b
bx lr
endfunc
diff --git a/libavcodec/arm/videodsp_init_arm.c b/libavcodec/arm/videodsp_init_arm.c
index 20c6e4a605..a89abb25d5 100644
--- a/libavcodec/arm/videodsp_init_arm.c
+++ b/libavcodec/arm/videodsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/videodsp_init_armv5te.c b/libavcodec/arm/videodsp_init_armv5te.c
index 832191f6d2..1ea1f3438d 100644
--- a/libavcodec/arm/videodsp_init_armv5te.c
+++ b/libavcodec/arm/videodsp_init_armv5te.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,5 +27,7 @@ void ff_prefetch_arm(uint8_t *mem, ptrdiff_t stride, int h);
av_cold void ff_videodsp_init_armv5te(VideoDSPContext *ctx, int bpc)
{
+#if HAVE_ARMV5TE_EXTERNAL
ctx->prefetch = ff_prefetch_arm;
+#endif
}
diff --git a/libavcodec/arm/vorbisdsp_init_arm.c b/libavcodec/arm/vorbisdsp_init_arm.c
index 853ba2d865..f4b3d80ef6 100644
--- a/libavcodec/arm/vorbisdsp_init_arm.c
+++ b/libavcodec/arm/vorbisdsp_init_arm.c
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vorbisdsp_neon.S b/libavcodec/arm/vorbisdsp_neon.S
index 7df876c2bc..79ce54f938 100644
--- a/libavcodec/arm/vorbisdsp_neon.S
+++ b/libavcodec/arm/vorbisdsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp3dsp_init_arm.c b/libavcodec/arm/vp3dsp_init_arm.c
index 11e1f1ca11..d9246365df 100644
--- a/libavcodec/arm/vp3dsp_init_arm.c
+++ b/libavcodec/arm/vp3dsp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp3dsp_neon.S b/libavcodec/arm/vp3dsp_neon.S
index 58bd97d548..2942d488f5 100644
--- a/libavcodec/arm/vp3dsp_neon.S
+++ b/libavcodec/arm/vp3dsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp56_arith.h b/libavcodec/arm/vp56_arith.h
index 6bc9456336..feb1247916 100644
--- a/libavcodec/arm/vp56_arith.h
+++ b/libavcodec/arm/vp56_arith.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp6dsp_init_arm.c b/libavcodec/arm/vp6dsp_init_arm.c
index 4ec41ed9f1..ed6832145e 100644
--- a/libavcodec/arm/vp6dsp_init_arm.c
+++ b/libavcodec/arm/vp6dsp_init_arm.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp6dsp_neon.S b/libavcodec/arm/vp6dsp_neon.S
index 10b4d0f14c..03dd28d1cb 100644
--- a/libavcodec/arm/vp6dsp_neon.S
+++ b/libavcodec/arm/vp6dsp_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8.h b/libavcodec/arm/vp8.h
index 93b2788835..965342d93b 100644
--- a/libavcodec/arm/vp8.h
+++ b/libavcodec/arm/vp8.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8_armv6.S b/libavcodec/arm/vp8_armv6.S
index 3863dc31a5..e7d25a45c1 100644
--- a/libavcodec/arm/vp8_armv6.S
+++ b/libavcodec/arm/vp8_armv6.S
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2010 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8dsp.h b/libavcodec/arm/vp8dsp.h
index 0d55e0ffc0..7281d0bfb1 100644
--- a/libavcodec/arm/vp8dsp.h
+++ b/libavcodec/arm/vp8dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8dsp_armv6.S b/libavcodec/arm/vp8dsp_armv6.S
index 03100cdf2f..1adcbbdbb1 100644
--- a/libavcodec/arm/vp8dsp_armv6.S
+++ b/libavcodec/arm/vp8dsp_armv6.S
@@ -5,20 +5,20 @@
* Copyright (c) 2010 Rob Clark <rob@ti.com>
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* This code was partially ported from libvpx, which uses this license:
diff --git a/libavcodec/arm/vp8dsp_init_arm.c b/libavcodec/arm/vp8dsp_init_arm.c
index aa77dbab98..8b801766d7 100644
--- a/libavcodec/arm/vp8dsp_init_arm.c
+++ b/libavcodec/arm/vp8dsp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8dsp_init_armv6.c b/libavcodec/arm/vp8dsp_init_armv6.c
index febe4e71a2..a5bcd733e0 100644
--- a/libavcodec/arm/vp8dsp_init_armv6.c
+++ b/libavcodec/arm/vp8dsp_init_armv6.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8dsp_init_neon.c b/libavcodec/arm/vp8dsp_init_neon.c
index 2b6c7750d3..53f1f23380 100644
--- a/libavcodec/arm/vp8dsp_init_neon.c
+++ b/libavcodec/arm/vp8dsp_init_neon.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/arm/vp8dsp_neon.S b/libavcodec/arm/vp8dsp_neon.S
index 544332c3c2..5319346951 100644
--- a/libavcodec/arm/vp8dsp_neon.S
+++ b/libavcodec/arm/vp8dsp_neon.S
@@ -4,20 +4,20 @@
* Copyright (c) 2010 Rob Clark <rob@ti.com>
* Copyright (c) 2011 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ass.c b/libavcodec/ass.c
index 098050a1a6..468b8bb6cb 100644
--- a/libavcodec/ass.c
+++ b/libavcodec/ass.c
@@ -1,66 +1,76 @@
/*
- * SSA/ASS common funtions
+ * SSA/ASS common functions
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "ass.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/common.h"
-/**
- * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS.
- *
- * @param avctx pointer to the AVCodecContext
- * @param font name of the default font face to use
- * @param font_size default font size to use
- * @param color default text color to use (ABGR)
- * @param back_color default background color to use (ABGR)
- * @param bold 1 for bold text, 0 for normal text
- * @param italic 1 for italic text, 0 for normal text
- * @param underline 1 for underline text, 0 for normal text
- * @param alignment position of the text (left, center, top...), defined after
- * the layout of the numpad (1-3 sub, 4-6 mid, 7-9 top)
- * @return >= 0 on success otherwise an error code <0
- */
-static int ass_subtitle_header(AVCodecContext *avctx,
- const char *font, int font_size,
- int color, int back_color,
- int bold, int italic, int underline,
- int alignment)
+int ff_ass_subtitle_header(AVCodecContext *avctx,
+ const char *font, int font_size,
+ int color, int back_color,
+ int bold, int italic, int underline,
+ int alignment)
{
- char header[512];
-
- snprintf(header, sizeof(header),
+ avctx->subtitle_header = av_asprintf(
"[Script Info]\r\n"
+ "; Script generated by FFmpeg/Lavc%s\r\n"
"ScriptType: v4.00+\r\n"
+ "PlayResX: %d\r\n"
+ "PlayResY: %d\r\n"
"\r\n"
"[V4+ Styles]\r\n"
- "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\r\n"
- "Style: Default,%s,%d,&H%x,&H%x,&H%x,&H%x,%d,%d,%d,1,1,0,%d,10,10,10,0,0\r\n"
+
+ /* ASSv4 header */
+ "Format: Name, "
+ "Fontname, Fontsize, "
+ "PrimaryColour, SecondaryColour, OutlineColour, BackColour, "
+ "Bold, Italic, Underline, StrikeOut, "
+ "ScaleX, ScaleY, "
+ "Spacing, Angle, "
+ "BorderStyle, Outline, Shadow, "
+ "Alignment, MarginL, MarginR, MarginV, "
+ "Encoding\r\n"
+
+ "Style: "
+ "Default," /* Name */
+ "%s,%d," /* Font{name,size} */
+ "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */
+ "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */
+ "100,100," /* Scale{X,Y} */
+ "0,0," /* Spacing, Angle */
+ "1,1,0," /* BorderStyle, Outline, Shadow */
+ "%d,10,10,10," /* Alignment, Margin[LRV] */
+ "0\r\n" /* Encoding */
+
"\r\n"
"[Events]\r\n"
- "Format: Layer, Start, End, Text\r\n",
+ "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n",
+ !(avctx->flags & CODEC_FLAG_BITEXACT) ? AV_STRINGIFY(LIBAVCODEC_VERSION) : "",
+ ASS_DEFAULT_PLAYRESX, ASS_DEFAULT_PLAYRESY,
font, font_size, color, color, back_color, back_color,
-bold, -italic, -underline, alignment);
- avctx->subtitle_header = av_strdup(header);
if (!avctx->subtitle_header)
return AVERROR(ENOMEM);
avctx->subtitle_header_size = strlen(avctx->subtitle_header);
@@ -69,7 +79,7 @@ static int ass_subtitle_header(AVCodecContext *avctx,
int ff_ass_subtitle_header_default(AVCodecContext *avctx)
{
- return ass_subtitle_header(avctx, ASS_DEFAULT_FONT,
+ return ff_ass_subtitle_header(avctx, ASS_DEFAULT_FONT,
ASS_DEFAULT_FONT_SIZE,
ASS_DEFAULT_COLOR,
ASS_DEFAULT_BACK_COLOR,
@@ -79,47 +89,135 @@ int ff_ass_subtitle_header_default(AVCodecContext *avctx)
ASS_DEFAULT_ALIGNMENT);
}
-void ff_ass_init(AVSubtitle *sub)
+static void insert_ts(AVBPrint *buf, int ts)
{
- memset(sub, 0, sizeof(*sub));
-}
+ if (ts == -1) {
+ av_bprintf(buf, "9:59:59.99,");
+ } else {
+ int h, m, s;
-static int ts_to_string(char *str, int strlen, int ts)
-{
- int h, m, s;
- h = ts/360000; ts -= 360000*h;
- m = ts/ 6000; ts -= 6000*m;
- s = ts/ 100; ts -= 100*s;
- return snprintf(str, strlen, "%d:%02d:%02d.%02d", h, m, s, ts);
+ h = ts/360000; ts -= 360000*h;
+ m = ts/ 6000; ts -= 6000*m;
+ s = ts/ 100; ts -= 100*s;
+ av_bprintf(buf, "%d:%02d:%02d.%02d,", h, m, s, ts);
+ }
}
-int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
- int ts_start, int ts_end, int raw)
+int ff_ass_bprint_dialog(AVBPrint *buf, const char *dialog,
+ int ts_start, int duration, int raw)
{
- int len = 0, dlen, duration = ts_end - ts_start;
- char s_start[16], s_end[16], header[48] = {0};
- AVSubtitleRect **rects;
+ int dlen;
+
+ if (!raw || raw == 2) {
+ long int layer = 0;
+
+ if (raw == 2) {
+ /* skip ReadOrder */
+ dialog = strchr(dialog, ',');
+ if (!dialog)
+ return AVERROR_INVALIDDATA;
+ dialog++;
- if (!raw) {
- ts_to_string(s_start, sizeof(s_start), ts_start);
- ts_to_string(s_end, sizeof(s_end), ts_end );
- len = snprintf(header, sizeof(header), "Dialogue: 0,%s,%s,",
- s_start, s_end);
+ /* extract Layer or Marked */
+ layer = strtol(dialog, (char**)&dialog, 10);
+ if (*dialog != ',')
+ return AVERROR_INVALIDDATA;
+ dialog++;
+ }
+ av_bprintf(buf, "Dialogue: %ld,", layer);
+ insert_ts(buf, ts_start);
+ insert_ts(buf, duration == -1 ? -1 : ts_start + duration);
+ if (raw != 2)
+ av_bprintf(buf, "Default,,0,0,0,,");
}
dlen = strcspn(dialog, "\n");
dlen += dialog[dlen] == '\n';
- rects = av_realloc(sub->rects, (sub->num_rects+1) * sizeof(*sub->rects));
+ av_bprintf(buf, "%.*s", dlen, dialog);
+ if (raw == 2)
+ av_bprintf(buf, "\r\n");
+
+ return dlen;
+}
+
+int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+ int ts_start, int duration, int raw)
+{
+ AVBPrint buf;
+ int ret, dlen;
+ AVSubtitleRect **rects;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if ((ret = ff_ass_bprint_dialog(&buf, dialog, ts_start, duration, raw)) < 0)
+ goto err;
+ dlen = ret;
+ if (!av_bprint_is_complete(&buf))
+ goto errnomem;
+
+ rects = av_realloc_array(sub->rects, (sub->num_rects+1), sizeof(*sub->rects));
if (!rects)
- return AVERROR(ENOMEM);
+ goto errnomem;
sub->rects = rects;
sub->end_display_time = FFMAX(sub->end_display_time, 10 * duration);
rects[sub->num_rects] = av_mallocz(sizeof(*rects[0]));
rects[sub->num_rects]->type = SUBTITLE_ASS;
- rects[sub->num_rects]->ass = av_malloc(len + dlen + 1);
- strcpy (rects[sub->num_rects]->ass , header);
- av_strlcpy(rects[sub->num_rects]->ass + len, dialog, dlen + 1);
+ ret = av_bprint_finalize(&buf, &rects[sub->num_rects]->ass);
+ if (ret < 0)
+ goto err;
sub->num_rects++;
return dlen;
+
+errnomem:
+ ret = AVERROR(ENOMEM);
+err:
+ av_bprint_finalize(&buf, NULL);
+ return ret;
+}
+
+int ff_ass_add_rect_bprint(AVSubtitle *sub, AVBPrint *buf,
+ int ts_start, int duration)
+{
+ av_bprintf(buf, "\r\n");
+ if (!av_bprint_is_complete(buf))
+ return AVERROR(ENOMEM);
+ return ff_ass_add_rect(sub, buf->str, ts_start, duration, 0);
+}
+
+void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size,
+ const char *linebreaks, int keep_ass_markup)
+{
+ const char *p_end = p + size;
+
+ for (; p < p_end && *p; p++) {
+
+ /* forced custom line breaks, not accounted as "normal" EOL */
+ 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);
+
+ /* some packets might end abruptly (no \0 at the end, like for example
+ * in some cases of demuxing from a classic video container), some
+ * might be terminated with \n or \r\n which we have to remove (for
+ * consistency with those who haven't), and we also have to deal with
+ * evil cases such as \r at the end of the buffer (and no \0 terminated
+ * character) */
+ } else if (p[0] == '\n') {
+ /* some stuff left so we can insert a line break */
+ if (p < p_end - 1)
+ av_bprintf(buf, "\\N");
+ } else if (p[0] == '\r' && p < p_end - 1 && p[1] == '\n') {
+ /* \r followed by a \n, we can skip it. We don't insert the \N yet
+ * because we don't know if it is followed by more text */
+ continue;
+
+ /* finally, a sane character */
+ } else {
+ av_bprint_chars(buf, *p, 1);
+ }
+ }
}
diff --git a/libavcodec/ass.h b/libavcodec/ass.h
index 594b5f3ac6..f3046efb79 100644
--- a/libavcodec/ass.h
+++ b/libavcodec/ass.h
@@ -1,21 +1,21 @@
/*
- * SSA/ASS common funtions
+ * SSA/ASS common functions
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,10 @@
#define AVCODEC_ASS_H
#include "avcodec.h"
+#include "libavutil/bprint.h"
+
+#define ASS_DEFAULT_PLAYRESX 384
+#define ASS_DEFAULT_PLAYRESY 288
/**
* @name Default values for ASS style
@@ -39,6 +43,27 @@
/** @} */
/**
+ * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS.
+ *
+ * @param avctx pointer to the AVCodecContext
+ * @param font name of the default font face to use
+ * @param font_size default font size to use
+ * @param color default text color to use (ABGR)
+ * @param back_color default background color to use (ABGR)
+ * @param bold 1 for bold text, 0 for normal text
+ * @param italic 1 for italic text, 0 for normal text
+ * @param underline 1 for underline text, 0 for normal text
+ * @param alignment position of the text (left, center, top...), defined after
+ * the layout of the numpad (1-3 sub, 4-6 mid, 7-9 top)
+ * @return >= 0 on success otherwise an error code <0
+ */
+int ff_ass_subtitle_header(AVCodecContext *avctx,
+ const char *font, int font_size,
+ int color, int back_color,
+ int bold, int italic, int underline,
+ int alignment);
+
+/**
* Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS
* with default style.
*
@@ -48,20 +73,45 @@
int ff_ass_subtitle_header_default(AVCodecContext *avctx);
/**
- * Initialize an AVSubtitle structure for use with ff_ass_add_rect().
+ * Add an ASS dialog line to an AVSubtitle as a new AVSubtitleRect.
*
* @param sub pointer to the AVSubtitle
+ * @param dialog ASS dialog to add to sub
+ * @param ts_start start timestamp for this dialog (in 1/100 second unit)
+ * @param duration duration for this dialog (in 1/100 second unit), can be -1
+ * to last until the end of the presentation
+ * @param raw when set to 2, it indicates that dialog contains an ASS
+ * dialog line as muxed in Matroska
+ * when set to 1, it indicates that dialog contains a whole SSA
+ * dialog line which should be copied as is.
+ * when set to 0, it indicates that dialog contains only the Text
+ * part of the ASS dialog line, the rest of the line
+ * will be generated.
+ * @return number of characters read from dialog. It can be less than the whole
+ * length of dialog, if dialog contains several lines of text.
+ * A negative value indicates an error.
*/
-void ff_ass_init(AVSubtitle *sub);
+int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+ int ts_start, int duration, int raw);
/**
- * Add an ASS dialog line to an AVSubtitle as a new AVSubtitleRect.
+ * Same as ff_ass_add_rect_bprint, but taking an AVBPrint buffer instead of a
+ * string, and assuming raw=0.
+ */
+int ff_ass_add_rect_bprint(AVSubtitle *sub, AVBPrint *buf,
+ int ts_start, int duration);
+
+/**
+ * Add an ASS dialog line to an AVBPrint buffer.
*
- * @param sub pointer to the AVSubtitle
+ * @param buf pointer to an initialized AVBPrint buffer
* @param dialog ASS dialog to add to sub
* @param ts_start start timestamp for this dialog (in 1/100 second unit)
- * @param ts_end end timestamp for this dialog (in 1/100 second unit)
- * @param raw when set to 1, it indicates that dialog contains a whole ASS
+ * @param duration duration for this dialog (in 1/100 second unit), can be -1
+ * to last until the end of the presentation
+ * @param raw when set to 2, it indicates that dialog contains an ASS
+ * dialog line as muxed in Matroska
+ * when set to 1, it indicates that dialog contains a whole SSA
* dialog line which should be copied as is.
* when set to 0, it indicates that dialog contains only the Text
* part of the ASS dialog line, the rest of the line
@@ -70,7 +120,19 @@ void ff_ass_init(AVSubtitle *sub);
* length of dialog, if dialog contains several lines of text.
* A negative value indicates an error.
*/
-int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
- int ts_start, int ts_end, int raw);
+int ff_ass_bprint_dialog(AVBPrint *buf, const char *dialog,
+ int ts_start, int duration, int raw);
+/**
+ * Escape a text subtitle using ASS syntax into an AVBPrint buffer.
+ * Newline characters will be escaped to \N.
+ *
+ * @param buf pointer to an initialized AVBPrint buffer
+ * @param p source text
+ * @param size size of the source text
+ * @param linebreaks additional newline chars, which will be escaped to \N
+ * @param keep_ass_markup braces and backslash will not be escaped if set
+ */
+void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size,
+ const char *linebreaks, int keep_ass_markup);
#endif /* AVCODEC_ASS_H */
diff --git a/libavcodec/ass_split.c b/libavcodec/ass_split.c
new file mode 100644
index 0000000000..2458cb9225
--- /dev/null
+++ b/libavcodec/ass_split.c
@@ -0,0 +1,529 @@
+/*
+ * SSA/ASS spliting functions
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "ass_split.h"
+
+typedef enum {
+ ASS_STR,
+ ASS_INT,
+ ASS_FLT,
+ ASS_COLOR,
+ ASS_TIMESTAMP,
+ ASS_ALGN,
+} ASSFieldType;
+
+typedef struct {
+ const char *name;
+ int type;
+ int offset;
+} ASSFields;
+
+typedef struct {
+ const char *section;
+ const char *format_header;
+ const char *fields_header;
+ int size;
+ int offset;
+ int offset_count;
+ ASSFields fields[24];
+} ASSSection;
+
+static const ASSSection ass_sections[] = {
+ { .section = "Script Info",
+ .offset = offsetof(ASS, script_info),
+ .fields = {{"ScriptType", ASS_STR, offsetof(ASSScriptInfo, script_type)},
+ {"Collisions", ASS_STR, offsetof(ASSScriptInfo, collisions) },
+ {"PlayResX", ASS_INT, offsetof(ASSScriptInfo, play_res_x) },
+ {"PlayResY", ASS_INT, offsetof(ASSScriptInfo, play_res_y) },
+ {"Timer", ASS_FLT, offsetof(ASSScriptInfo, timer) },
+ {0},
+ }
+ },
+ { .section = "V4+ Styles",
+ .format_header = "Format",
+ .fields_header = "Style",
+ .size = sizeof(ASSStyle),
+ .offset = offsetof(ASS, styles),
+ .offset_count = offsetof(ASS, styles_count),
+ .fields = {{"Name", ASS_STR, offsetof(ASSStyle, name) },
+ {"Fontname", ASS_STR, offsetof(ASSStyle, font_name) },
+ {"Fontsize", ASS_INT, offsetof(ASSStyle, font_size) },
+ {"PrimaryColour", ASS_COLOR, offsetof(ASSStyle, primary_color) },
+ {"SecondaryColour", ASS_COLOR, offsetof(ASSStyle, secondary_color)},
+ {"OutlineColour", ASS_COLOR, offsetof(ASSStyle, outline_color) },
+ {"BackColour", ASS_COLOR, offsetof(ASSStyle, back_color) },
+ {"Bold", ASS_INT, offsetof(ASSStyle, bold) },
+ {"Italic", ASS_INT, offsetof(ASSStyle, italic) },
+ {"Underline", ASS_INT, offsetof(ASSStyle, underline) },
+ {"StrikeOut", ASS_INT, offsetof(ASSStyle, strikeout) },
+ {"ScaleX", ASS_FLT, offsetof(ASSStyle, scalex) },
+ {"ScaleY", ASS_FLT, offsetof(ASSStyle, scaley) },
+ {"Spacing", ASS_FLT, offsetof(ASSStyle, spacing) },
+ {"Angle", ASS_FLT, offsetof(ASSStyle, angle) },
+ {"BorderStyle", ASS_INT, offsetof(ASSStyle, border_style) },
+ {"Outline", ASS_FLT, offsetof(ASSStyle, outline) },
+ {"Shadow", ASS_FLT, offsetof(ASSStyle, shadow) },
+ {"Alignment", ASS_INT, offsetof(ASSStyle, alignment) },
+ {"MarginL", ASS_INT, offsetof(ASSStyle, margin_l) },
+ {"MarginR", ASS_INT, offsetof(ASSStyle, margin_r) },
+ {"MarginV", ASS_INT, offsetof(ASSStyle, margin_v) },
+ {"Encoding", ASS_INT, offsetof(ASSStyle, encoding) },
+ {0},
+ }
+ },
+ { .section = "V4 Styles",
+ .format_header = "Format",
+ .fields_header = "Style",
+ .size = sizeof(ASSStyle),
+ .offset = offsetof(ASS, styles),
+ .offset_count = offsetof(ASS, styles_count),
+ .fields = {{"Name", ASS_STR, offsetof(ASSStyle, name) },
+ {"Fontname", ASS_STR, offsetof(ASSStyle, font_name) },
+ {"Fontsize", ASS_INT, offsetof(ASSStyle, font_size) },
+ {"PrimaryColour", ASS_COLOR, offsetof(ASSStyle, primary_color) },
+ {"SecondaryColour", ASS_COLOR, offsetof(ASSStyle, secondary_color)},
+ {"TertiaryColour", ASS_COLOR, offsetof(ASSStyle, outline_color) },
+ {"BackColour", ASS_COLOR, offsetof(ASSStyle, back_color) },
+ {"Bold", ASS_INT, offsetof(ASSStyle, bold) },
+ {"Italic", ASS_INT, offsetof(ASSStyle, italic) },
+ {"BorderStyle", ASS_INT, offsetof(ASSStyle, border_style) },
+ {"Outline", ASS_FLT, offsetof(ASSStyle, outline) },
+ {"Shadow", ASS_FLT, offsetof(ASSStyle, shadow) },
+ {"Alignment", ASS_ALGN, offsetof(ASSStyle, alignment) },
+ {"MarginL", ASS_INT, offsetof(ASSStyle, margin_l) },
+ {"MarginR", ASS_INT, offsetof(ASSStyle, margin_r) },
+ {"MarginV", ASS_INT, offsetof(ASSStyle, margin_v) },
+ {"AlphaLevel", ASS_INT, offsetof(ASSStyle, alpha_level) },
+ {"Encoding", ASS_INT, offsetof(ASSStyle, encoding) },
+ {0},
+ }
+ },
+ { .section = "Events",
+ .format_header = "Format",
+ .fields_header = "Dialogue",
+ .size = sizeof(ASSDialog),
+ .offset = offsetof(ASS, dialogs),
+ .offset_count = offsetof(ASS, dialogs_count),
+ .fields = {{"Layer", ASS_INT, offsetof(ASSDialog, layer) },
+ {"Start", ASS_TIMESTAMP, offsetof(ASSDialog, start) },
+ {"End", ASS_TIMESTAMP, offsetof(ASSDialog, end) },
+ {"Style", ASS_STR, offsetof(ASSDialog, style) },
+ {"Name", ASS_STR, offsetof(ASSDialog, name) },
+ {"MarginL", ASS_INT, offsetof(ASSDialog, margin_l)},
+ {"MarginR", ASS_INT, offsetof(ASSDialog, margin_r)},
+ {"MarginV", ASS_INT, offsetof(ASSDialog, margin_v)},
+ {"Effect", ASS_STR, offsetof(ASSDialog, effect) },
+ {"Text", ASS_STR, offsetof(ASSDialog, text) },
+ {0},
+ }
+ },
+};
+
+
+typedef int (*ASSConvertFunc)(void *dest, const char *buf, int len);
+
+static int convert_str(void *dest, const char *buf, int len)
+{
+ char *str = av_malloc(len + 1);
+ if (str) {
+ memcpy(str, buf, len);
+ str[len] = 0;
+ if (*(void **)dest)
+ av_free(*(void **)dest);
+ *(char **)dest = str;
+ }
+ return !str;
+}
+static int convert_int(void *dest, const char *buf, int len)
+{
+ return sscanf(buf, "%d", (int *)dest) == 1;
+}
+static int convert_flt(void *dest, const char *buf, int len)
+{
+ return sscanf(buf, "%f", (float *)dest) == 1;
+}
+static int convert_color(void *dest, const char *buf, int len)
+{
+ return sscanf(buf, "&H%8x", (int *)dest) == 1 ||
+ sscanf(buf, "%d", (int *)dest) == 1;
+}
+static int convert_timestamp(void *dest, const char *buf, int len)
+{
+ int c, h, m, s, cs;
+ if ((c = sscanf(buf, "%d:%02d:%02d.%02d", &h, &m, &s, &cs)) == 4)
+ *(int *)dest = 360000*h + 6000*m + 100*s + cs;
+ return c == 4;
+}
+static int convert_alignment(void *dest, const char *buf, int len)
+{
+ int a;
+ if (sscanf(buf, "%d", &a) == 1) {
+ /* convert V4 Style alignment to V4+ Style */
+ *(int *)dest = a + ((a&4) >> 1) - 5*!!(a&8);
+ return 1;
+ }
+ return 0;
+}
+
+static const ASSConvertFunc convert_func[] = {
+ [ASS_STR] = convert_str,
+ [ASS_INT] = convert_int,
+ [ASS_FLT] = convert_flt,
+ [ASS_COLOR] = convert_color,
+ [ASS_TIMESTAMP] = convert_timestamp,
+ [ASS_ALGN] = convert_alignment,
+};
+
+
+struct ASSSplitContext {
+ ASS ass;
+ int current_section;
+ int field_number[FF_ARRAY_ELEMS(ass_sections)];
+ int *field_order[FF_ARRAY_ELEMS(ass_sections)];
+};
+
+
+static uint8_t *realloc_section_array(ASSSplitContext *ctx)
+{
+ const ASSSection *section = &ass_sections[ctx->current_section];
+ int *count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
+ void **section_ptr = (void **)((uint8_t *)&ctx->ass + section->offset);
+ uint8_t *tmp = av_realloc_array(*section_ptr, (*count+1), section->size);
+ if (!tmp)
+ return NULL;
+ *section_ptr = tmp;
+ tmp += *count * section->size;
+ memset(tmp, 0, section->size);
+ (*count)++;
+ return tmp;
+}
+
+static inline int is_eol(char buf)
+{
+ return buf == '\r' || buf == '\n' || buf == 0;
+}
+
+static inline const char *skip_space(const char *buf)
+{
+ while (*buf == ' ')
+ buf++;
+ return buf;
+}
+
+static int *get_default_field_orders(const ASSSection *section)
+{
+ int i;
+ int *order = av_malloc_array(FF_ARRAY_ELEMS(section->fields), sizeof(*order));
+
+ if (!order)
+ return NULL;
+ for (i = 0; section->fields[i].name; i++)
+ order[i] = i;
+ while (i < FF_ARRAY_ELEMS(section->fields))
+ order[i] = -1;
+ return order;
+}
+
+static const char *ass_split_section(ASSSplitContext *ctx, const char *buf)
+{
+ const ASSSection *section = &ass_sections[ctx->current_section];
+ int *number = &ctx->field_number[ctx->current_section];
+ int *order = ctx->field_order[ctx->current_section];
+ int *tmp, i, len;
+
+ while (buf && *buf) {
+ if (buf[0] == '[') {
+ ctx->current_section = -1;
+ break;
+ }
+ if (buf[0] == ';' || (buf[0] == '!' && buf[1] == ':')) {
+ /* skip comments */
+ } else if (section->format_header && !order) {
+ len = strlen(section->format_header);
+ if (strncmp(buf, section->format_header, len) || buf[len] != ':')
+ goto next_line;
+ buf += len + 1;
+ while (!is_eol(*buf)) {
+ buf = skip_space(buf);
+ len = strcspn(buf, ", \r\n");
+ if (!(tmp = av_realloc_array(order, (*number + 1), sizeof(*order))))
+ return NULL;
+ order = tmp;
+ order[*number] = -1;
+ for (i=0; section->fields[i].name; i++)
+ if (!strncmp(buf, section->fields[i].name, len)) {
+ order[*number] = i;
+ break;
+ }
+ (*number)++;
+ buf = skip_space(buf + len + (buf[len] == ','));
+ }
+ ctx->field_order[ctx->current_section] = order;
+ } else if (section->fields_header) {
+ len = strlen(section->fields_header);
+ if (!strncmp(buf, section->fields_header, len) && buf[len] == ':') {
+ uint8_t *ptr, *struct_ptr = realloc_section_array(ctx);
+ if (!struct_ptr) return NULL;
+
+ /* No format header line found so far, assume default */
+ if (!order) {
+ order = get_default_field_orders(section);
+ if (!order)
+ return NULL;
+ ctx->field_order[ctx->current_section] = order;
+ }
+
+ buf += len + 1;
+ for (i=0; !is_eol(*buf) && i < *number; i++) {
+ int last = i == *number - 1;
+ buf = skip_space(buf);
+ len = strcspn(buf, last ? "\r\n" : ",\r\n");
+ if (order[i] >= 0) {
+ ASSFieldType type = section->fields[order[i]].type;
+ ptr = struct_ptr + section->fields[order[i]].offset;
+ convert_func[type](ptr, buf, len);
+ }
+ buf += len;
+ if (!last && *buf) buf++;
+ buf = skip_space(buf);
+ }
+ }
+ } else {
+ len = strcspn(buf, ":\r\n");
+ if (buf[len] == ':') {
+ for (i=0; section->fields[i].name; i++)
+ if (!strncmp(buf, section->fields[i].name, len)) {
+ ASSFieldType type = section->fields[i].type;
+ uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
+ ptr += section->fields[i].offset;
+ buf = skip_space(buf + len + 1);
+ convert_func[type](ptr, buf, strcspn(buf, "\r\n"));
+ break;
+ }
+ }
+ }
+next_line:
+ buf += strcspn(buf, "\n");
+ buf += !!*buf;
+ }
+ return buf;
+}
+
+static int ass_split(ASSSplitContext *ctx, const char *buf)
+{
+ char c, section[16];
+ int i;
+
+ if (ctx->current_section >= 0)
+ buf = ass_split_section(ctx, buf);
+
+ while (buf && *buf) {
+ if (sscanf(buf, "[%15[0-9A-Za-z+ ]]%c", section, &c) == 2) {
+ buf += strcspn(buf, "\n");
+ buf += !!*buf;
+ for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++)
+ if (!strcmp(section, ass_sections[i].section)) {
+ ctx->current_section = i;
+ buf = ass_split_section(ctx, buf);
+ }
+ } else {
+ buf += strcspn(buf, "\n");
+ buf += !!*buf;
+ }
+ }
+ return buf ? 0 : AVERROR_INVALIDDATA;
+}
+
+ASSSplitContext *ff_ass_split(const char *buf)
+{
+ ASSSplitContext *ctx = av_mallocz(sizeof(*ctx));
+ ctx->current_section = -1;
+ if (ass_split(ctx, buf) < 0) {
+ ff_ass_split_free(ctx);
+ return NULL;
+ }
+ return ctx;
+}
+
+static void free_section(ASSSplitContext *ctx, const ASSSection *section)
+{
+ uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
+ int i, j, *count, c = 1;
+
+ if (section->format_header) {
+ ptr = *(void **)ptr;
+ count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
+ } else
+ count = &c;
+
+ if (ptr)
+ for (i=0; i<*count; i++, ptr += section->size)
+ for (j=0; section->fields[j].name; j++) {
+ const ASSFields *field = &section->fields[j];
+ if (field->type == ASS_STR)
+ av_freep(ptr + field->offset);
+ }
+ *count = 0;
+
+ if (section->format_header)
+ av_freep((uint8_t *)&ctx->ass + section->offset);
+}
+
+ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf,
+ int cache, int *number)
+{
+ ASSDialog *dialog = NULL;
+ int i, count;
+ if (!cache)
+ for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++)
+ if (!strcmp(ass_sections[i].section, "Events")) {
+ free_section(ctx, &ass_sections[i]);
+ break;
+ }
+ count = ctx->ass.dialogs_count;
+ if (ass_split(ctx, buf) == 0)
+ dialog = ctx->ass.dialogs + count;
+ if (number)
+ *number = ctx->ass.dialogs_count - count;
+ return dialog;
+}
+
+void ff_ass_split_free(ASSSplitContext *ctx)
+{
+ if (ctx) {
+ int i;
+ for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++) {
+ free_section(ctx, &ass_sections[i]);
+ av_freep(&(ctx->field_order[i]));
+ }
+ av_free(ctx);
+ }
+}
+
+
+int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv,
+ const char *buf)
+{
+ const char *text = NULL;
+ char new_line[2];
+ int text_len = 0;
+
+ while (buf && *buf) {
+ if (text && callbacks->text &&
+ (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
+ !strncmp(buf, "{\\", 2))) {
+ callbacks->text(priv, text, text_len);
+ text = NULL;
+ }
+ if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
+ if (callbacks->new_line)
+ callbacks->new_line(priv, new_line[0] == 'N');
+ buf += 2;
+ } else if (!strncmp(buf, "{\\", 2)) {
+ buf++;
+ while (*buf == '\\') {
+ char style[2], c[2], sep[2], c_num[2] = "0", tmp[128] = {0};
+ unsigned int color = 0xFFFFFFFF;
+ int len, size = -1, an = -1, alpha = -1;
+ int x1, y1, x2, y2, t1 = -1, t2 = -1;
+ if (sscanf(buf, "\\%1[bisu]%1[01\\}]%n", style, c, &len) > 1) {
+ int close = c[0] == '0' ? 1 : c[0] == '1' ? 0 : -1;
+ len += close != -1;
+ if (callbacks->style)
+ callbacks->style(priv, style[0], close);
+ } else if (sscanf(buf, "\\c%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\c&H%X&%1[\\}]%n", &color, sep, &len) > 1 ||
+ sscanf(buf, "\\%1[1234]c%1[\\}]%n", c_num, sep, &len) > 1 ||
+ sscanf(buf, "\\%1[1234]c&H%X&%1[\\}]%n", c_num, &color, sep, &len) > 2) {
+ if (callbacks->color)
+ callbacks->color(priv, color, c_num[0] - '0');
+ } else if (sscanf(buf, "\\alpha%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\alpha&H%2X&%1[\\}]%n", &alpha, sep, &len) > 1 ||
+ sscanf(buf, "\\%1[1234]a%1[\\}]%n", c_num, sep, &len) > 1 ||
+ sscanf(buf, "\\%1[1234]a&H%2X&%1[\\}]%n", c_num, &alpha, sep, &len) > 2) {
+ if (callbacks->alpha)
+ callbacks->alpha(priv, alpha, c_num[0] - '0');
+ } else if (sscanf(buf, "\\fn%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\fn%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
+ if (callbacks->font_name)
+ callbacks->font_name(priv, tmp[0] ? tmp : NULL);
+ } else if (sscanf(buf, "\\fs%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\fs%u%1[\\}]%n", &size, sep, &len) > 1) {
+ if (callbacks->font_size)
+ callbacks->font_size(priv, size);
+ } else if (sscanf(buf, "\\a%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\a%2u%1[\\}]%n", &an, sep, &len) > 1 ||
+ sscanf(buf, "\\an%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\an%1u%1[\\}]%n", &an, sep, &len) > 1) {
+ if (an != -1 && buf[2] != 'n')
+ an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
+ if (callbacks->alignment)
+ callbacks->alignment(priv, an);
+ } else if (sscanf(buf, "\\r%1[\\}]%n", sep, &len) > 0 ||
+ sscanf(buf, "\\r%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
+ if (callbacks->cancel_overrides)
+ callbacks->cancel_overrides(priv, tmp);
+ } else if (sscanf(buf, "\\move(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &len) > 4 ||
+ sscanf(buf, "\\move(%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, &t1, &t2, sep, &len) > 6) {
+ if (callbacks->move)
+ callbacks->move(priv, x1, y1, x2, y2, t1, t2);
+ } else if (sscanf(buf, "\\pos(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
+ if (callbacks->move)
+ callbacks->move(priv, x1, y1, x1, y1, -1, -1);
+ } else if (sscanf(buf, "\\org(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
+ if (callbacks->origin)
+ callbacks->origin(priv, x1, y1);
+ } else {
+ len = strcspn(buf+1, "\\}") + 2; /* skip unknown code */
+ }
+ buf += len - 1;
+ }
+ if (*buf++ != '}')
+ return AVERROR_INVALIDDATA;
+ } else {
+ if (!text) {
+ text = buf;
+ text_len = 1;
+ } else
+ text_len++;
+ buf++;
+ }
+ }
+ if (text && callbacks->text)
+ callbacks->text(priv, text, text_len);
+ if (callbacks->end)
+ callbacks->end(priv);
+ return 0;
+}
+
+ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style)
+{
+ ASS *ass = &ctx->ass;
+ int i;
+
+ if (!style || !*style)
+ style = "Default";
+ for (i=0; i<ass->styles_count; i++)
+ if (!strcmp(ass->styles[i].name, style))
+ return ass->styles + i;
+ return NULL;
+}
diff --git a/libavcodec/ass_split.h b/libavcodec/ass_split.h
new file mode 100644
index 0000000000..c9122526c0
--- /dev/null
+++ b/libavcodec/ass_split.h
@@ -0,0 +1,192 @@
+/*
+ * SSA/ASS spliting functions
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_ASS_SPLIT_H
+#define AVCODEC_ASS_SPLIT_H
+
+/**
+ * fields extracted from the [Script Info] section
+ */
+typedef struct {
+ char *script_type; /**< SSA script format version (eg. v4.00) */
+ char *collisions; /**< how subtitles are moved to prevent collisions */
+ int play_res_x; /**< video width that ASS coords are referring to */
+ int play_res_y; /**< video height that ASS coords are referring to */
+ float timer; /**< time multiplier to apply to SSA clock (in %) */
+} ASSScriptInfo;
+
+/**
+ * fields extracted from the [V4(+) Styles] section
+ */
+typedef struct {
+ char *name; /**< name of the tyle (case sensitive) */
+ char *font_name; /**< font face (case sensitive) */
+ int font_size; /**< font height */
+ int primary_color; /**< color that a subtitle will normally appear in */
+ int secondary_color;
+ int outline_color; /**< color for outline in ASS, called tertiary in SSA */
+ int back_color; /**< color of the subtitle outline or shadow */
+ int bold; /**< whether text is bold (1) or not (0) */
+ int italic; /**< whether text is italic (1) or not (0) */
+ int underline; /**< whether text is underlined (1) or not (0) */
+ int strikeout;
+ float scalex;
+ float scaley;
+ float spacing;
+ float angle;
+ int border_style;
+ float outline;
+ float shadow;
+ int alignment; /**< position of the text (left, center, top...),
+ defined after the layout of the numpad
+ (1-3 sub, 4-6 mid, 7-9 top) */
+ int margin_l;
+ int margin_r;
+ int margin_v;
+ int alpha_level;
+ int encoding;
+} ASSStyle;
+
+/**
+ * fields extracted from the [Events] section
+ */
+typedef struct {
+ int layer; /**< higher numbered layers are drawn over lower numbered */
+ int start; /**< start time of the dialog in centiseconds */
+ int end; /**< end time of the dialog in centiseconds */
+ char *style; /**< name of the ASSStyle to use with this dialog */
+ char *name;
+ int margin_l;
+ int margin_r;
+ int margin_v;
+ char *effect;
+ char *text; /**< actual text which will be displayed as a subtitle,
+ can include style override control codes (see
+ ff_ass_split_override_codes()) */
+} ASSDialog;
+
+/**
+ * structure containing the whole split ASS data
+ */
+typedef struct {
+ ASSScriptInfo script_info; /**< general information about the SSA script*/
+ ASSStyle *styles; /**< array of split out styles */
+ int styles_count; /**< number of ASSStyle in the styles array */
+ ASSDialog *dialogs; /**< array of split out dialogs */
+ int dialogs_count; /**< number of ASSDialog in the dialogs array*/
+} ASS;
+
+/**
+ * This struct can be casted to ASS to access to the split data.
+ */
+typedef struct ASSSplitContext ASSSplitContext;
+
+/**
+ * Split a full ASS file or a ASS header from a string buffer and store
+ * the split structure in a newly allocated context.
+ *
+ * @param buf String containing the ASS formated data.
+ * @return Newly allocated struct containing split data.
+ */
+ASSSplitContext *ff_ass_split(const char *buf);
+
+/**
+ * Split one or several ASS "Dialogue" lines from a string buffer and store
+ * them in a already initialized context.
+ *
+ * @param ctx Context previously initialized by ff_ass_split().
+ * @param buf String containing the ASS "Dialogue" lines.
+ * @param cache Set to 1 to keep all the previously split ASSDialog in
+ * the context, or set to 0 to free all the previously split
+ * ASSDialog.
+ * @param number If not NULL, the pointed integer will be set to the number
+ * of split ASSDialog.
+ * @return Pointer to the first split ASSDialog.
+ */
+ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf,
+ int cache, int *number);
+
+/**
+ * Free all the memory allocated for an ASSSplitContext.
+ *
+ * @param ctx Context previously initialized by ff_ass_split().
+ */
+void ff_ass_split_free(ASSSplitContext *ctx);
+
+
+/**
+ * Set of callback functions corresponding to each override codes that can
+ * be encountered in a "Dialogue" Text field.
+ */
+typedef struct {
+ /**
+ * @defgroup ass_styles ASS styles
+ * @{
+ */
+ void (*text)(void *priv, const char *text, int len);
+ void (*new_line)(void *priv, int forced);
+ void (*style)(void *priv, char style, int close);
+ void (*color)(void *priv, unsigned int /* color */, unsigned int color_id);
+ void (*alpha)(void *priv, int alpha, int alpha_id);
+ void (*font_name)(void *priv, const char *name);
+ void (*font_size)(void *priv, int size);
+ void (*alignment)(void *priv, int alignment);
+ void (*cancel_overrides)(void *priv, const char *style);
+ /** @} */
+
+ /**
+ * @defgroup ass_functions ASS functions
+ * @{
+ */
+ void (*move)(void *priv, int x1, int y1, int x2, int y2, int t1, int t2);
+ void (*origin)(void *priv, int x, int y);
+ /** @} */
+
+ /**
+ * @defgroup ass_end end of Dialogue Event
+ * @{
+ */
+ void (*end)(void *priv);
+ /** @} */
+} ASSCodesCallbacks;
+
+/**
+ * Split override codes out of a ASS "Dialogue" Text field.
+ *
+ * @param callbacks Set of callback functions called for each override code
+ * encountered.
+ * @param priv Opaque pointer passed to the callback functions.
+ * @param buf The ASS "Dialogue" Text field to split.
+ * @return >= 0 on success otherwise an error code <0
+ */
+int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv,
+ const char *buf);
+
+/**
+ * Find an ASSStyle structure by its name.
+ *
+ * @param ctx Context previously initialized by ff_ass_split().
+ * @param style name of the style to search for.
+ * @return the ASSStyle corresponding to style, or NULL if style can't be found
+ */
+ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style);
+
+#endif /* AVCODEC_ASS_SPLIT_H */
diff --git a/libavcodec/assdec.c b/libavcodec/assdec.c
index 48fe32ee99..11dbde0b8a 100644
--- a/libavcodec/assdec.c
+++ b/libavcodec/assdec.c
@@ -2,20 +2,20 @@
* SSA/ASS decoder
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,29 +23,45 @@
#include "avcodec.h"
#include "ass.h"
+#include "ass_split.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
static av_cold int ass_decode_init(AVCodecContext *avctx)
{
- avctx->subtitle_header = av_malloc(avctx->extradata_size);
+ avctx->subtitle_header = av_malloc(avctx->extradata_size + 1);
if (!avctx->subtitle_header)
return AVERROR(ENOMEM);
memcpy(avctx->subtitle_header, avctx->extradata, avctx->extradata_size);
+ avctx->subtitle_header[avctx->extradata_size] = 0;
avctx->subtitle_header_size = avctx->extradata_size;
+ avctx->priv_data = ff_ass_split(avctx->extradata);
+ if(!avctx->priv_data)
+ return -1;
return 0;
}
-static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
+static int ass_decode_close(AVCodecContext *avctx)
+{
+ ff_ass_split_free(avctx->priv_data);
+ avctx->priv_data = NULL;
+ return 0;
+}
+
+#if CONFIG_SSA_DECODER
+static int ssa_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
AVPacket *avpkt)
{
const char *ptr = avpkt->data;
int len, size = avpkt->size;
- ff_ass_init(data);
-
while (size > 0) {
- len = ff_ass_add_rect(data, ptr, 0, 0/* FIXME: duration */, 1);
+ int duration;
+ ASSDialog *dialog = ff_ass_split_dialog(avctx->priv_data, ptr, 0, NULL);
+ if (!dialog)
+ return AVERROR_INVALIDDATA;
+ duration = dialog->end - dialog->start;
+ len = ff_ass_add_rect(data, ptr, 0, duration, 1);
if (len < 0)
return len;
ptr += len;
@@ -56,11 +72,49 @@ static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
return avpkt->size;
}
-AVCodec ff_ass_decoder = {
- .name = "ass",
+AVCodec ff_ssa_decoder = {
+ .name = "ssa",
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_SSA,
.init = ass_decode_init,
+ .decode = ssa_decode_frame,
+ .close = ass_decode_close,
+};
+#endif
+
+#if CONFIG_ASS_DECODER
+static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
+ AVPacket *avpkt)
+{
+ int ret;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ static const AVRational ass_tb = {1, 100};
+ const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, ass_tb);
+ const int ts_duration = av_rescale_q(avpkt->duration, avctx->time_base, ass_tb);
+
+ if (avpkt->size <= 0)
+ return avpkt->size;
+
+ ret = ff_ass_add_rect(sub, ptr, ts_start, ts_duration, 2);
+ if (ret < 0) {
+ if (ret == AVERROR_INVALIDDATA)
+ av_log(avctx, AV_LOG_ERROR, "Invalid ASS packet\n");
+ return ret;
+ }
+
+ *got_sub_ptr = avpkt->size > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_ass_decoder = {
+ .name = "ass",
+ .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_ASS,
+ .init = ass_decode_init,
.decode = ass_decode_frame,
+ .close = ass_decode_close,
};
+#endif
diff --git a/libavcodec/assenc.c b/libavcodec/assenc.c
index caf266e037..5dc3b09d65 100644
--- a/libavcodec/assenc.c
+++ b/libavcodec/assenc.c
@@ -2,37 +2,44 @@
* SSA/ASS encoder
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "avcodec.h"
+#include "ass_split.h"
+#include "ass.h"
#include "libavutil/avstring.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
+typedef struct {
+ int id; ///< current event id, ReadOrder field
+} ASSEncodeContext;
+
static av_cold int ass_encode_init(AVCodecContext *avctx)
{
- avctx->extradata = av_malloc(avctx->subtitle_header_size);
+ avctx->extradata = av_malloc(avctx->subtitle_header_size + 1);
if (!avctx->extradata)
return AVERROR(ENOMEM);
memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size);
avctx->extradata_size = avctx->subtitle_header_size;
+ avctx->extradata[avctx->extradata_size] = 0;
return 0;
}
@@ -40,15 +47,54 @@ static int ass_encode_frame(AVCodecContext *avctx,
unsigned char *buf, int bufsize,
const AVSubtitle *sub)
{
+ ASSEncodeContext *s = avctx->priv_data;
int i, len, total_len = 0;
for (i=0; i<sub->num_rects; i++) {
+ char ass_line[2048];
+ const char *ass = sub->rects[i]->ass;
+
if (sub->rects[i]->type != SUBTITLE_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
return -1;
}
- len = av_strlcpy(buf+total_len, sub->rects[i]->ass, bufsize-total_len);
+ if (strncmp(ass, "Dialogue: ", 10)) {
+ av_log(avctx, AV_LOG_ERROR, "AVSubtitle rectangle ass \"%s\""
+ " does not look like a SSA markup\n", ass);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (avctx->codec->id == AV_CODEC_ID_ASS) {
+ long int layer;
+ char *p;
+
+ if (i > 0) {
+ av_log(avctx, AV_LOG_ERROR, "ASS encoder supports only one "
+ "ASS rectangle field.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ass += 10; // skip "Dialogue: "
+ /* parse Layer field. If it's a Marked field, the content
+ * will be "Marked=N" instead of the layer num, so we will
+ * have layer=0, which is fine. */
+ layer = strtol(ass, &p, 10);
+
+#define SKIP_ENTRY(ptr) do { \
+ char *sep = strchr(ptr, ','); \
+ if (sep) \
+ ptr = sep + 1; \
+} while (0)
+
+ SKIP_ENTRY(p); // skip layer or marked
+ SKIP_ENTRY(p); // skip start timestamp
+ SKIP_ENTRY(p); // skip end timestamp
+ snprintf(ass_line, sizeof(ass_line), "%d,%ld,%s", ++s->id, layer, p);
+ ass_line[strcspn(ass_line, "\r\n")] = 0;
+ ass = ass_line;
+ }
+ len = av_strlcpy(buf+total_len, ass, bufsize-total_len);
if (len > bufsize-total_len-1) {
av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
@@ -61,11 +107,26 @@ static int ass_encode_frame(AVCodecContext *avctx,
return total_len;
}
-AVCodec ff_ass_encoder = {
- .name = "ass",
+#if CONFIG_SSA_ENCODER
+AVCodec ff_ssa_encoder = {
+ .name = "ssa",
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_SSA,
.init = ass_encode_init,
.encode_sub = ass_encode_frame,
+ .priv_data_size = sizeof(ASSEncodeContext),
+};
+#endif
+
+#if CONFIG_ASS_ENCODER
+AVCodec ff_ass_encoder = {
+ .name = "ass",
+ .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_ASS,
+ .init = ass_encode_init,
+ .encode_sub = ass_encode_frame,
+ .priv_data_size = sizeof(ASSEncodeContext),
};
+#endif
diff --git a/libavcodec/asv.c b/libavcodec/asv.c
index b9e93f7989..14fdf73333 100644
--- a/libavcodec/asv.c
+++ b/libavcodec/asv.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/asv.h b/libavcodec/asv.h
index 18f7a9571d..e2cdc81300 100644
--- a/libavcodec/asv.h
+++ b/libavcodec/asv.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/asvdec.c b/libavcodec/asvdec.c
index 9d1be5f391..18e2faacd3 100644
--- a/libavcodec/asvdec.c
+++ b/libavcodec/asvdec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,7 +29,6 @@
#include "asv.h"
#include "avcodec.h"
#include "blockdsp.h"
-#include "put_bits.h"
#include "idctdsp.h"
#include "internal.h"
#include "mathops.h"
@@ -211,10 +210,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVFrame *const p = data;
int mb_x, mb_y, ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
@@ -277,8 +274,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
int i;
if (avctx->extradata_size < 1) {
- av_log(avctx, AV_LOG_ERROR, "No extradata provided\n");
- return AVERROR_INVALIDDATA;
+ av_log(avctx, AV_LOG_WARNING, "No extradata provided\n");
}
ff_asv_common_init(avctx);
@@ -288,8 +284,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
ff_init_scantable(a->idsp.idct_permutation, &a->scantable, ff_asv_scantab);
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
- a->inv_qscale = avctx->extradata[0];
- if (a->inv_qscale == 0) {
+ if (avctx->extradata_size < 1 || (a->inv_qscale = avctx->extradata[0]) == 0) {
av_log(avctx, AV_LOG_ERROR, "illegal qscale 0\n");
if (avctx->codec_id == AV_CODEC_ID_ASV1)
a->inv_qscale = 6;
@@ -317,6 +312,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
return 0;
}
+#if CONFIG_ASV1_DECODER
AVCodec ff_asv1_decoder = {
.name = "asv1",
.long_name = NULL_IF_CONFIG_SMALL("ASUS V1"),
@@ -328,7 +324,9 @@ AVCodec ff_asv1_decoder = {
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+#endif
+#if CONFIG_ASV2_DECODER
AVCodec ff_asv2_decoder = {
.name = "asv2",
.long_name = NULL_IF_CONFIG_SMALL("ASUS V2"),
@@ -340,3 +338,4 @@ AVCodec ff_asv2_decoder = {
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+#endif
diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c
index f8c52af18b..e6f5a1a252 100644
--- a/libavcodec/asvenc.c
+++ b/libavcodec/asvenc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,10 @@
#include "libavutil/attributes.h"
#include "libavutil/mem.h"
+#include "aandcttab.h"
#include "asv.h"
#include "avcodec.h"
+#include "dct.h"
#include "fdctdsp.h"
#include "internal.h"
#include "mathops.h"
@@ -50,7 +52,7 @@ static inline void asv1_put_level(PutBitContext *pb, int level)
}
}
-static inline void asv2_put_level(PutBitContext *pb, int level)
+static inline void asv2_put_level(ASV1Context *a, PutBitContext *pb, int level)
{
unsigned int index = level + 31;
@@ -58,6 +60,10 @@ static inline void asv2_put_level(PutBitContext *pb, int level)
put_bits(pb, ff_asv2_level_tab[index][1], ff_asv2_level_tab[index][0]);
} else {
put_bits(pb, ff_asv2_level_tab[31][1], ff_asv2_level_tab[31][0]);
+ if (level < -128 || level > 127) {
+ av_log(a->avctx, AV_LOG_WARNING, "Cliping level %d, increase qscale\n", level);
+ level = av_clip_int8(level);
+ }
asv2_put_bits(pb, 8, level & 0xFF);
}
}
@@ -108,7 +114,7 @@ static inline void asv1_encode_block(ASV1Context *a, int16_t block[64])
put_bits(&a->pb, ff_asv_ccp_tab[16][1], ff_asv_ccp_tab[16][0]);
}
-static inline int asv2_encode_block(ASV1Context *a, int16_t block[64])
+static inline void asv2_encode_block(ASV1Context *a, int16_t block[64])
{
int i;
int count = 0;
@@ -142,8 +148,7 @@ static inline int asv2_encode_block(ASV1Context *a, int16_t block[64])
a->q_intra_matrix[index + 9] + (1 << 15)) >> 16))
ccp |= 1;
- if (!i && ccp >= 8)
- return AVERROR_BUG;
+ av_assert2(i || ccp < 8);
if (i)
put_bits(&a->pb, ff_asv_ac_ccp_tab[ccp][1], ff_asv_ac_ccp_tab[ccp][0]);
else
@@ -151,24 +156,22 @@ static inline int asv2_encode_block(ASV1Context *a, int16_t block[64])
if (ccp) {
if (ccp & 8)
- asv2_put_level(&a->pb, block[index + 0]);
+ asv2_put_level(a, &a->pb, block[index + 0]);
if (ccp & 4)
- asv2_put_level(&a->pb, block[index + 8]);
+ asv2_put_level(a, &a->pb, block[index + 8]);
if (ccp & 2)
- asv2_put_level(&a->pb, block[index + 1]);
+ asv2_put_level(a, &a->pb, block[index + 1]);
if (ccp & 1)
- asv2_put_level(&a->pb, block[index + 9]);
+ asv2_put_level(a, &a->pb, block[index + 9]);
}
}
-
- return 0;
}
#define MAX_MB_SIZE (30 * 16 * 16 * 3 / 2 / 8)
static inline int encode_mb(ASV1Context *a, int16_t block[6][64])
{
- int i, ret;
+ int i;
if (a->pb.buf_end - a->pb.buf - (put_bits_count(&a->pb) >> 3) < MAX_MB_SIZE) {
av_log(a->avctx, AV_LOG_ERROR, "encoded frame too large\n");
@@ -180,9 +183,7 @@ static inline int encode_mb(ASV1Context *a, int16_t block[6][64])
asv1_encode_block(a, block[i]);
} else {
for (i = 0; i < 6; i++) {
- ret = asv2_encode_block(a, block[i]);
- if (ret < 0)
- return ret;
+ asv2_encode_block(a, block[i]);
}
}
return 0;
@@ -221,13 +222,52 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
int size, ret;
int mb_x, mb_y;
- if (!pkt->data &&
- (ret = av_new_packet(pkt, a->mb_height * a->mb_width * MAX_MB_SIZE +
- FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if (pict->width % 16 || pict->height % 16) {
+ AVFrame *clone = av_frame_alloc();
+ int i;
+
+ if (!clone)
+ return AVERROR(ENOMEM);
+ clone->format = pict->format;
+ clone->width = FFALIGN(pict->width, 16);
+ clone->height = FFALIGN(pict->height, 16);
+ ret = av_frame_get_buffer(clone, 32);
+ if (ret < 0) {
+ av_frame_free(&clone);
+ return ret;
+ }
+
+ ret = av_frame_copy(clone, pict);
+ if (ret < 0) {
+ av_frame_free(&clone);
+ return ret;
+ }
+
+ for (i = 0; i<3; i++) {
+ int x, y;
+ int w = FF_CEIL_RSHIFT(pict->width, !!i);
+ int h = FF_CEIL_RSHIFT(pict->height, !!i);
+ int w2 = FF_CEIL_RSHIFT(clone->width, !!i);
+ int h2 = FF_CEIL_RSHIFT(clone->height, !!i);
+ for (y=0; y<h; y++)
+ for (x=w; x<w2; x++)
+ clone->data[i][x + y*clone->linesize[i]] =
+ clone->data[i][w - 1 + y*clone->linesize[i]];
+ for (y=h; y<h2; y++)
+ for (x=0; x<w2; x++)
+ clone->data[i][x + y*clone->linesize[i]] =
+ clone->data[i][x + (h-1)*clone->linesize[i]];
+ }
+ ret = encode_frame(avctx, pkt, clone, got_packet);
+
+ av_frame_free(&clone);
return ret;
}
+ if ((ret = ff_alloc_packet2(avctx, pkt, a->mb_height * a->mb_width * MAX_MB_SIZE +
+ FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+
init_put_bits(&a->pb, pkt->data, pkt->size);
for (mb_y = 0; mb_y < a->mb_height2; mb_y++) {
@@ -282,17 +322,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
int i;
const int scale = avctx->codec_id == AV_CODEC_ID_ASV1 ? 1 : 2;
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
-
ff_asv_common_init(avctx);
ff_fdctdsp_init(&a->fdsp, avctx);
ff_pixblockdsp_init(&a->pdsp, avctx);
- if (avctx->global_quality == 0)
+ if (avctx->global_quality <= 0)
avctx->global_quality = 4 * FF_QUALITY_SCALE;
a->inv_qscale = (32 * scale * FF_QUALITY_SCALE +
@@ -304,20 +338,18 @@ static av_cold int encode_init(AVCodecContext *avctx)
((uint32_t *) avctx->extradata)[1] = av_le2ne32(AV_RL32("ASUS"));
for (i = 0; i < 64; i++) {
- int q = 32 * scale * ff_mpeg1_default_intra_matrix[i];
- a->q_intra_matrix[i] = ((a->inv_qscale << 16) + q / 2) / q;
+ if (a->fdsp.fdct == ff_fdct_ifast) {
+ int q = 32LL * scale * ff_mpeg1_default_intra_matrix[i] * ff_aanscales[i];
+ a->q_intra_matrix[i] = (((int64_t)a->inv_qscale << 30) + q / 2) / q;
+ } else {
+ int q = 32 * scale * ff_mpeg1_default_intra_matrix[i];
+ a->q_intra_matrix[i] = ((a->inv_qscale << 16) + q / 2) / q;
+ }
}
return 0;
}
-static av_cold int asv_encode_close(AVCodecContext *avctx)
-{
- av_frame_free(&avctx->coded_frame);
-
- return 0;
-}
-
#if CONFIG_ASV1_ENCODER
AVCodec ff_asv1_encoder = {
.name = "asv1",
@@ -327,7 +359,6 @@ AVCodec ff_asv1_encoder = {
.priv_data_size = sizeof(ASV1Context),
.init = encode_init,
.encode2 = encode_frame,
- .close = asv_encode_close,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
@@ -344,7 +375,6 @@ AVCodec ff_asv2_encoder = {
.priv_data_size = sizeof(ASV1Context),
.init = encode_init,
.encode2 = encode_frame,
- .close = asv_encode_close,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
diff --git a/libavcodec/atrac.c b/libavcodec/atrac.c
index f36db9e8c5..12e8997dbc 100644
--- a/libavcodec/atrac.c
+++ b/libavcodec/atrac.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2013 Maxim Poliakovski
* Copyright (c) 2006-2008 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -124,7 +124,8 @@ void ff_atrac_gain_compensation(AtracGCContext *gctx, float *in, float *prev,
memcpy(prev, &in[num_samples], num_samples * sizeof(float));
}
-void ff_atrac_iqmf (float *inlo, float *inhi, unsigned int nIn, float *pOut, float *delayBuf, float *temp)
+void ff_atrac_iqmf(float *inlo, float *inhi, unsigned int nIn, float *pOut,
+ float *delayBuf, float *temp)
{
int i, j;
float *p1, *p3;
diff --git a/libavcodec/atrac.h b/libavcodec/atrac.h
index 8909323b01..05208bbee6 100644
--- a/libavcodec/atrac.h
+++ b/libavcodec/atrac.h
@@ -4,20 +4,20 @@
* Copyright (c) 2009-2013 Maxim Poliakovski
* Copyright (c) 2009 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -91,6 +91,7 @@ void ff_atrac_gain_compensation(AtracGCContext *gctx, float *in, float *prev,
* @param delayBuf delayBuf buffer
* @param temp temp buffer
*/
-void ff_atrac_iqmf (float *inlo, float *inhi, unsigned int nIn, float *pOut, float *delayBuf, float *temp);
+void ff_atrac_iqmf(float *inlo, float *inhi, unsigned int nIn, float *pOut,
+ float *delayBuf, float *temp);
#endif /* AVCODEC_ATRAC_H */
diff --git a/libavcodec/atrac1.c b/libavcodec/atrac1.c
index 5c8f96a31c..f965dcc20c 100644
--- a/libavcodec/atrac1.c
+++ b/libavcodec/atrac1.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Maxim Poliakovski
* Copyright (c) 2009 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,7 +80,7 @@ typedef struct AT1Ctx {
DECLARE_ALIGNED(32, float, high)[512];
float* bands[3];
FFTContext mdct_ctx[3];
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
} AT1Ctx;
/** size of the transform in samples in the long mode for each QMF band */
@@ -140,7 +140,7 @@ static int at1_imdct_block(AT1SUCtx* su, AT1Ctx *q)
at1_imdct(q, &q->spec[pos], &su->spectrum[0][ref_pos + start_pos], nbits, band_num);
/* overlap and window */
- q->fdsp.vector_fmul_window(&q->bands[band_num][start_pos], prev_buf,
+ q->fdsp->vector_fmul_window(&q->bands[band_num][start_pos], prev_buf,
&su->spectrum[0][ref_pos + start_pos], ff_sine_32, 16);
prev_buf = &su->spectrum[0][ref_pos+start_pos + 16];
@@ -242,7 +242,7 @@ static int at1_unpack_dequant(GetBitContext* gb, AT1SUCtx* su,
*/
spec[pos+i] = get_sbits(gb, word_len) * scale_factor * max_quant;
}
- } else { /* word_len = 0 -> empty BFU, zero all specs in the emty BFU */
+ } else { /* word_len = 0 -> empty BFU, zero all specs in the empty BFU */
memset(&spec[pos], 0, num_specs * sizeof(float));
}
}
@@ -287,10 +287,8 @@ static int atrac1_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = AT1_SU_SAMPLES;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
for (ch = 0; ch < avctx->channels; ch++) {
AT1SUCtx* su = &q->SUs[ch];
@@ -326,6 +324,8 @@ static av_cold int atrac1_decode_end(AVCodecContext * avctx)
ff_mdct_end(&q->mdct_ctx[1]);
ff_mdct_end(&q->mdct_ctx[2]);
+ av_freep(&q->fdsp);
+
return 0;
}
@@ -343,6 +343,11 @@ static av_cold int atrac1_decode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
+ if (avctx->block_align <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported block align.");
+ return AVERROR_PATCHWELCOME;
+ }
+
/* Init the mdct transforms */
if ((ret = ff_mdct_init(&q->mdct_ctx[0], 6, 1, -1.0/ (1 << 15))) ||
(ret = ff_mdct_init(&q->mdct_ctx[1], 8, 1, -1.0/ (1 << 15))) ||
@@ -356,7 +361,7 @@ static av_cold int atrac1_decode_init(AVCodecContext *avctx)
ff_atrac_generate_tables();
- avpriv_float_dsp_init(&q->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ q->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
q->bands[0] = q->low;
q->bands[1] = q->mid;
diff --git a/libavcodec/atrac1data.h b/libavcodec/atrac1data.h
index d4b8cd0def..62c218b790 100644
--- a/libavcodec/atrac1data.h
+++ b/libavcodec/atrac1data.h
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Maxim Poliakovski
* Copyright (c) 2009 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,7 +43,7 @@ static const uint8_t bfu_bands_t[4] = {0, 20, 36, 52};
*/
static const uint8_t specs_per_bfu[52] = {
8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, // low band
- 6, 6, 6, 6, 7, 7, 7, 7, 9, 9, 9, 9, 10, 10, 10, 10, // midle band
+ 6, 6, 6, 6, 7, 7, 7, 7, 9, 9, 9, 9, 10, 10, 10, 10, // middle band
12, 12, 12, 12, 12, 12, 12, 12, 20, 20, 20, 20, 20, 20, 20, 20 // high band
};
diff --git a/libavcodec/atrac3.c b/libavcodec/atrac3.c
index e8d2e2a875..5aa3d8df1a 100644
--- a/libavcodec/atrac3.c
+++ b/libavcodec/atrac3.c
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2008 Maxim Poliakovski
* Copyright (c) 2006-2008 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,6 +38,7 @@
#include "libavutil/attributes.h"
#include "libavutil/float_dsp.h"
+#include "libavutil/libm.h"
#include "avcodec.h"
#include "bytestream.h"
#include "fft.h"
@@ -104,9 +105,9 @@ typedef struct ATRAC3Context {
int scrambled_stream;
//@}
- AtracGCContext gainc_ctx;
- FFTContext mdct_ctx;
- AVFloatDSPContext fdsp;
+ AtracGCContext gainc_ctx;
+ FFTContext mdct_ctx;
+ AVFloatDSPContext *fdsp;
} ATRAC3Context;
static DECLARE_ALIGNED(32, float, mdct_window)[MDCT_SIZE];
@@ -139,7 +140,7 @@ static void imlt(ATRAC3Context *q, float *input, float *output, int odd_band)
q->mdct_ctx.imdct_calc(&q->mdct_ctx, output, input);
/* Perform windowing on the output. */
- q->fdsp.vector_fmul(output, output, mdct_window, MDCT_SIZE);
+ q->fdsp->vector_fmul(output, output, mdct_window, MDCT_SIZE);
}
/*
@@ -187,8 +188,9 @@ static av_cold int atrac3_decode_close(AVCodecContext *avctx)
{
ATRAC3Context *q = avctx->priv_data;
- av_free(q->units);
- av_free(q->decoded_bytes_buffer);
+ av_freep(&q->units);
+ av_freep(&q->decoded_bytes_buffer);
+ av_freep(&q->fdsp);
ff_mdct_end(&q->mdct_ctx);
@@ -407,17 +409,17 @@ static int decode_tonal_components(GetBitContext *gb,
static int decode_gain_control(GetBitContext *gb, GainBlock *block,
int num_bands)
{
- int i, j;
+ int b, j;
int *level, *loc;
AtracGainInfo *gain = block->g_block;
- for (i = 0; i <= num_bands; i++) {
- gain[i].num_points = get_bits(gb, 3);
- level = gain[i].lev_code;
- loc = gain[i].loc_code;
+ for (b = 0; b <= num_bands; b++) {
+ gain[b].num_points = get_bits(gb, 3);
+ level = gain[b].lev_code;
+ loc = gain[b].loc_code;
- for (j = 0; j < gain[i].num_points; j++) {
+ for (j = 0; j < gain[b].num_points; j++) {
level[j] = get_bits(gb, 4);
loc[j] = get_bits(gb, 5);
if (j && loc[j] <= loc[j - 1])
@@ -426,8 +428,8 @@ static int decode_gain_control(GetBitContext *gb, GainBlock *block,
}
/* Clear the unused blocks. */
- for (; i < 4 ; i++)
- gain[i].num_points = 0;
+ for (; b < 4 ; b++)
+ gain[b].num_points = 0;
return 0;
}
@@ -518,7 +520,7 @@ static void reverse_matrixing(float *su1, float *su2, int *prev_code,
}
break;
default:
- assert(0);
+ av_assert1(0);
}
}
}
@@ -673,7 +675,7 @@ static int decode_frame(AVCodecContext *avctx, const uint8_t *databuf,
/* set the bitstream reader at the start of the second Sound Unit*/
- init_get_bits(&q->gb, ptr1, (avctx->block_align - i) * 8);
+ init_get_bits8(&q->gb, ptr1, q->decoded_bytes_buffer + avctx->block_align - ptr1);
/* Fill the Weighting coeffs delay buffer */
memmove(q->weighting_delay, &q->weighting_delay[2],
@@ -747,10 +749,8 @@ static int atrac3_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = SAMPLES_PER_FRAME;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
/* Check if we need to descramble and what buffer to pass on. */
if (q->scrambled_stream) {
@@ -771,7 +771,7 @@ static int atrac3_decode_frame(AVCodecContext *avctx, void *data,
return avctx->block_align;
}
-static av_cold void atrac3_init_static_data(AVCodec *codec)
+static av_cold void atrac3_init_static_data(void)
{
int i;
@@ -791,6 +791,7 @@ static av_cold void atrac3_init_static_data(AVCodec *codec)
static av_cold int atrac3_decode_init(AVCodecContext *avctx)
{
+ static int static_init_done;
int i, ret;
int version, delay, samples_per_frame, frame_factor;
const uint8_t *edata_ptr = avctx->extradata;
@@ -801,6 +802,10 @@ static av_cold int atrac3_decode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
+ if (!static_init_done)
+ atrac3_init_static_data();
+ static_init_done = 1;
+
/* Take care of the codec-specific extradata. */
if (avctx->extradata_size == 14) {
/* Parse the extradata, WAV format */
@@ -829,7 +834,7 @@ static av_cold int atrac3_decode_init(AVCodecContext *avctx)
avctx->channels, frame_factor);
return AVERROR_INVALIDDATA;
}
- } else if (avctx->extradata_size == 10) {
+ } else if (avctx->extradata_size == 12 || avctx->extradata_size == 10) {
/* Parse the extradata, RM format. */
version = bytestream_get_be32(&edata_ptr);
samples_per_frame = bytestream_get_be16(&edata_ptr);
@@ -866,8 +871,10 @@ static av_cold int atrac3_decode_init(AVCodecContext *avctx)
if (q->coding_mode == STEREO)
av_log(avctx, AV_LOG_DEBUG, "Normal stereo detected.\n");
else if (q->coding_mode == JOINT_STEREO) {
- if (avctx->channels != 2)
+ if (avctx->channels != 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid coding mode\n");
return AVERROR_INVALIDDATA;
+ }
av_log(avctx, AV_LOG_DEBUG, "Joint stereo detected.\n");
} else {
av_log(avctx, AV_LOG_ERROR, "Unknown channel coding mode %x!\n",
@@ -907,10 +914,10 @@ static av_cold int atrac3_decode_init(AVCodecContext *avctx)
}
ff_atrac_init_gain_compensation(&q->gainc_ctx, 4, 3);
- avpriv_float_dsp_init(&q->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ q->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
- q->units = av_mallocz(sizeof(*q->units) * avctx->channels);
- if (!q->units) {
+ q->units = av_mallocz_array(avctx->channels, sizeof(*q->units));
+ if (!q->units || !q->fdsp) {
atrac3_decode_close(avctx);
return AVERROR(ENOMEM);
}
@@ -925,7 +932,6 @@ AVCodec ff_atrac3_decoder = {
.id = AV_CODEC_ID_ATRAC3,
.priv_data_size = sizeof(ATRAC3Context),
.init = atrac3_decode_init,
- .init_static_data = atrac3_init_static_data,
.close = atrac3_decode_close,
.decode = atrac3_decode_frame,
.capabilities = CODEC_CAP_SUBFRAMES | CODEC_CAP_DR1,
diff --git a/libavcodec/atrac3data.h b/libavcodec/atrac3data.h
index 4f5c122021..5d91274f48 100644
--- a/libavcodec/atrac3data.h
+++ b/libavcodec/atrac3data.h
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Maxim Poliakovski
* Copyright (c) 2006-2007 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/atrac3plus.c b/libavcodec/atrac3plus.c
index 7071596a8c..f998a7f9ee 100644
--- a/libavcodec/atrac3plus.c
+++ b/libavcodec/atrac3plus.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2013 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,56 +80,56 @@ static av_cold void build_canonical_huff(const uint8_t *cb, const uint8_t *xlat,
*tab_offset += 1 << max_len;
}
-av_cold void ff_atrac3p_init_vlcs(AVCodec *codec)
+av_cold void ff_atrac3p_init_vlcs(void)
{
int i, wl_vlc_offs, ct_vlc_offs, sf_vlc_offs, tab_offset;
- static int wl_nb_bits[4] = { 2, 3, 5, 5 };
- static int wl_nb_codes[4] = { 3, 5, 8, 8 };
- static const uint8_t *wl_bits[4] = {
+ static const int wl_nb_bits[4] = { 2, 3, 5, 5 };
+ static const int wl_nb_codes[4] = { 3, 5, 8, 8 };
+ static const uint8_t * const wl_bits[4] = {
atrac3p_wl_huff_bits1, atrac3p_wl_huff_bits2,
atrac3p_wl_huff_bits3, atrac3p_wl_huff_bits4
};
- static const uint8_t *wl_codes[4] = {
+ static const uint8_t * const wl_codes[4] = {
atrac3p_wl_huff_code1, atrac3p_wl_huff_code2,
atrac3p_wl_huff_code3, atrac3p_wl_huff_code4
};
- static const uint8_t *wl_xlats[4] = {
+ static const uint8_t * const wl_xlats[4] = {
atrac3p_wl_huff_xlat1, atrac3p_wl_huff_xlat2, NULL, NULL
};
- static int ct_nb_bits[4] = { 3, 4, 4, 4 };
- static int ct_nb_codes[4] = { 4, 8, 8, 8 };
- static const uint8_t *ct_bits[4] = {
+ static const int ct_nb_bits[4] = { 3, 4, 4, 4 };
+ static const int ct_nb_codes[4] = { 4, 8, 8, 8 };
+ static const uint8_t * const ct_bits[4] = {
atrac3p_ct_huff_bits1, atrac3p_ct_huff_bits2,
atrac3p_ct_huff_bits2, atrac3p_ct_huff_bits3
};
- static const uint8_t *ct_codes[4] = {
+ static const uint8_t * const ct_codes[4] = {
atrac3p_ct_huff_code1, atrac3p_ct_huff_code2,
atrac3p_ct_huff_code2, atrac3p_ct_huff_code3
};
- static const uint8_t *ct_xlats[4] = {
+ static const uint8_t * const ct_xlats[4] = {
NULL, NULL, atrac3p_ct_huff_xlat1, NULL
};
- static int sf_nb_bits[8] = { 9, 9, 9, 9, 6, 6, 7, 7 };
- static int sf_nb_codes[8] = { 64, 64, 64, 64, 16, 16, 16, 16 };
- static const uint8_t *sf_bits[8] = {
+ static const int sf_nb_bits[8] = { 9, 9, 9, 9, 6, 6, 7, 7 };
+ static const int sf_nb_codes[8] = { 64, 64, 64, 64, 16, 16, 16, 16 };
+ static const uint8_t * const sf_bits[8] = {
atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits2,
atrac3p_sf_huff_bits3, atrac3p_sf_huff_bits4, atrac3p_sf_huff_bits4,
atrac3p_sf_huff_bits5, atrac3p_sf_huff_bits6
};
- static const uint16_t *sf_codes[8] = {
+ static const uint16_t * const sf_codes[8] = {
atrac3p_sf_huff_code1, atrac3p_sf_huff_code1, atrac3p_sf_huff_code2,
atrac3p_sf_huff_code3, atrac3p_sf_huff_code4, atrac3p_sf_huff_code4,
atrac3p_sf_huff_code5, atrac3p_sf_huff_code6
};
- static const uint8_t *sf_xlats[8] = {
+ static const uint8_t * const sf_xlats[8] = {
atrac3p_sf_huff_xlat1, atrac3p_sf_huff_xlat2, NULL, NULL,
atrac3p_sf_huff_xlat4, atrac3p_sf_huff_xlat5, NULL, NULL
};
- static const uint8_t *gain_cbs[11] = {
+ static const uint8_t * const gain_cbs[11] = {
atrac3p_huff_gain_npoints1_cb, atrac3p_huff_gain_npoints1_cb,
atrac3p_huff_gain_lev1_cb, atrac3p_huff_gain_lev2_cb,
atrac3p_huff_gain_lev3_cb, atrac3p_huff_gain_lev4_cb,
@@ -137,7 +137,7 @@ av_cold void ff_atrac3p_init_vlcs(AVCodec *codec)
atrac3p_huff_gain_loc4_cb, atrac3p_huff_gain_loc2_cb,
atrac3p_huff_gain_loc5_cb
};
- static const uint8_t *gain_xlats[11] = {
+ static const uint8_t * const gain_xlats[11] = {
NULL, atrac3p_huff_gain_npoints2_xlat, atrac3p_huff_gain_lev1_xlat,
atrac3p_huff_gain_lev2_xlat, atrac3p_huff_gain_lev3_xlat,
atrac3p_huff_gain_lev4_xlat, atrac3p_huff_gain_loc3_xlat,
@@ -145,13 +145,13 @@ av_cold void ff_atrac3p_init_vlcs(AVCodec *codec)
atrac3p_huff_gain_loc2_xlat, atrac3p_huff_gain_loc5_xlat
};
- static const uint8_t *tone_cbs[7] = {
+ static const uint8_t * const tone_cbs[7] = {
atrac3p_huff_tonebands_cb, atrac3p_huff_numwavs1_cb,
atrac3p_huff_numwavs2_cb, atrac3p_huff_wav_ampsf1_cb,
atrac3p_huff_wav_ampsf2_cb, atrac3p_huff_wav_ampsf3_cb,
atrac3p_huff_freq_cb
};
- static const uint8_t *tone_xlats[7] = {
+ static const uint8_t * const tone_xlats[7] = {
NULL, NULL, atrac3p_huff_numwavs2_xlat, atrac3p_huff_wav_ampsf1_xlat,
atrac3p_huff_wav_ampsf2_xlat, atrac3p_huff_wav_ampsf3_xlat,
atrac3p_huff_freq_xlat
@@ -820,7 +820,7 @@ static void decode_qu_spectra(GetBitContext *gb, const Atrac3pSpecCodeTab *tab,
int num_coeffs = tab->num_coeffs;
int bits = tab->bits;
int is_signed = tab->is_signed;
- unsigned val, mask = (1 << bits) - 1;
+ unsigned val;
for (pos = 0; pos < num_specs;) {
if (group_size == 1 || get_bits1(gb)) {
@@ -828,7 +828,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 = val & mask;
+ cf = av_mod_uintp2(val, bits);
if (is_signed)
cf = sign_extend(cf, bits);
else if (cf && get_bits1(gb))
diff --git a/libavcodec/atrac3plus.h b/libavcodec/atrac3plus.h
index e56c4441b6..1b001fae6d 100644
--- a/libavcodec/atrac3plus.h
+++ b/libavcodec/atrac3plus.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2013 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -155,10 +155,8 @@ typedef struct Atrac3pChanUnitCtx {
/**
* Initialize VLC tables for bitstream parsing.
- *
- * @param[in] codec ptr to the AVCodec
*/
-void ff_atrac3p_init_vlcs(AVCodec *codec);
+void ff_atrac3p_init_vlcs(void);
/**
* Decode bitstream data of a channel unit.
@@ -169,8 +167,8 @@ void ff_atrac3p_init_vlcs(AVCodec *codec);
* @param[in] avctx ptr to the AVCodecContext
* @return result code: 0 = OK, otherwise - error code
*/
-int ff_atrac3p_decode_channel_unit(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
- int num_channels, AVCodecContext *avctx);
+int ff_atrac3p_decode_channel_unit(GetBitContext *gb, Atrac3pChanUnitCtx *ctx,
+ int num_channels, AVCodecContext *avctx);
/**
* Initialize IMDCT transform.
diff --git a/libavcodec/atrac3plus_data.h b/libavcodec/atrac3plus_data.h
index 5026a59930..2a107eef1f 100644
--- a/libavcodec/atrac3plus_data.h
+++ b/libavcodec/atrac3plus_data.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2013 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/atrac3plusdec.c b/libavcodec/atrac3plusdec.c
index ddbfb5365f..f858497d46 100644
--- a/libavcodec/atrac3plusdec.c
+++ b/libavcodec/atrac3plusdec.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2013 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,7 +47,7 @@
typedef struct ATRAC3PContext {
GetBitContext gb;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
DECLARE_ALIGNED(32, float, samples)[2][ATRAC3P_FRAME_SAMPLES]; ///< quantized MDCT spectrum
DECLARE_ALIGNED(32, float, mdct_buf)[2][ATRAC3P_FRAME_SAMPLES]; ///< output of the IMDCT
@@ -67,7 +67,13 @@ typedef struct ATRAC3PContext {
static av_cold int atrac3p_decode_close(AVCodecContext *avctx)
{
- av_free(((ATRAC3PContext *)(avctx->priv_data))->ch_units);
+ ATRAC3PContext *ctx = avctx->priv_data;
+
+ av_freep(&ctx->ch_units);
+ av_freep(&ctx->fdsp);
+
+ ff_mdct_end(&ctx->mdct_ctx);
+ ff_mdct_end(&ctx->ipqf_dct_ctx);
return 0;
}
@@ -148,7 +154,7 @@ static av_cold int atrac3p_decode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
- avpriv_float_dsp_init(&ctx->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ ff_atrac3p_init_vlcs();
/* initialize IPQF */
ff_mdct_init(&ctx->ipqf_dct_ctx, 5, 1, 32.0 / 32768.0);
@@ -164,9 +170,10 @@ static av_cold int atrac3p_decode_init(AVCodecContext *avctx)
ctx->my_channel_layout = avctx->channel_layout;
- ctx->ch_units = av_mallocz(sizeof(*ctx->ch_units) *
- ctx->num_channel_blocks);
- if (!ctx->ch_units) {
+ ctx->ch_units = av_mallocz_array(ctx->num_channel_blocks, sizeof(*ctx->ch_units));
+ ctx->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+
+ if (!ctx->ch_units || !ctx->fdsp) {
atrac3p_decode_close(avctx);
return AVERROR(ENOMEM);
}
@@ -263,7 +270,7 @@ static void reconstruct_frame(ATRAC3PContext *ctx, Atrac3pChanUnitCtx *ch_unit,
for (ch = 0; ch < num_channels; ch++) {
for (sb = 0; sb < ch_unit->num_subbands; sb++) {
/* inverse transform and windowing */
- ff_atrac3p_imdct(&ctx->fdsp, &ctx->mdct_ctx,
+ ff_atrac3p_imdct(ctx->fdsp, &ctx->mdct_ctx,
&ctx->samples[ch][sb * ATRAC3P_SUBBAND_SAMPLES],
&ctx->mdct_buf[ch][sb * ATRAC3P_SUBBAND_SAMPLES],
(ch_unit->channels[ch].wnd_shape_prev[sb] << 1) +
@@ -297,7 +304,7 @@ static void reconstruct_frame(ATRAC3PContext *ctx, Atrac3pChanUnitCtx *ch_unit,
for (sb = 0; sb < ch_unit->num_subbands; sb++)
if (ch_unit->channels[ch].tones_info[sb].num_wavs ||
ch_unit->channels[ch].tones_info_prev[sb].num_wavs) {
- ff_atrac3p_generate_tones(ch_unit, &ctx->fdsp, ch, sb,
+ ff_atrac3p_generate_tones(ch_unit, ctx->fdsp, ch, sb,
&ctx->time_buf[ch][sb * 128]);
}
}
@@ -329,10 +336,8 @@ static int atrac3p_decode_frame(AVCodecContext *avctx, void *data,
float **samples_p = (float **)frame->extended_data;
frame->nb_samples = ATRAC3P_FRAME_SAMPLES;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if ((ret = init_get_bits8(&ctx->gb, avpkt->data, avpkt->size)) < 0)
return ret;
@@ -383,13 +388,12 @@ static int atrac3p_decode_frame(AVCodecContext *avctx, void *data,
}
AVCodec ff_atrac3p_decoder = {
- .name = "atrac3plus",
- .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_ATRAC3P,
- .priv_data_size = sizeof(ATRAC3PContext),
- .init = atrac3p_decode_init,
- .init_static_data = ff_atrac3p_init_vlcs,
- .close = atrac3p_decode_close,
- .decode = atrac3p_decode_frame,
+ .name = "atrac3plus",
+ .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_ATRAC3P,
+ .priv_data_size = sizeof(ATRAC3PContext),
+ .init = atrac3p_decode_init,
+ .close = atrac3p_decode_close,
+ .decode = atrac3p_decode_frame,
};
diff --git a/libavcodec/atrac3plusdsp.c b/libavcodec/atrac3plusdsp.c
index 468f098383..3c68f74d25 100644
--- a/libavcodec/atrac3plusdsp.c
+++ b/libavcodec/atrac3plusdsp.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2013 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -599,8 +599,8 @@ void ff_atrac3p_ipqf(FFTContext *dct_ctx, Atrac3pIPQFChannelCtx *hist,
const float *in, float *out)
{
int i, s, sb, t, pos_now, pos_next;
- DECLARE_ALIGNED(32, float, idct_in)[ATRAC3P_SUBBANDS];
- DECLARE_ALIGNED(32, float, idct_out)[ATRAC3P_SUBBANDS];
+ LOCAL_ALIGNED(32, float, idct_in, [ATRAC3P_SUBBANDS]);
+ LOCAL_ALIGNED(32, float, idct_out, [ATRAC3P_SUBBANDS]);
memset(out, 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out));
diff --git a/libavcodec/audio_frame_queue.c b/libavcodec/audio_frame_queue.c
index 15ffa82e49..4f6bccce36 100644
--- a/libavcodec/audio_frame_queue.c
+++ b/libavcodec/audio_frame_queue.c
@@ -2,110 +2,72 @@
* Audio Frame Queue
* Copyright (c) 2012 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/attributes.h"
#include "libavutil/common.h"
-#include "libavutil/mathematics.h"
-#include "internal.h"
#include "audio_frame_queue.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
av_cold void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq)
{
- afq->avctx = avctx;
- afq->next_pts = AV_NOPTS_VALUE;
+ afq->avctx = avctx;
afq->remaining_delay = avctx->initial_padding;
afq->remaining_samples = avctx->initial_padding;
- afq->frame_queue = NULL;
-}
-
-static void delete_next_frame(AudioFrameQueue *afq)
-{
- AudioFrame *f = afq->frame_queue;
- if (f) {
- afq->frame_queue = f->next;
- f->next = NULL;
- av_freep(&f);
- }
+ afq->frame_count = 0;
}
void ff_af_queue_close(AudioFrameQueue *afq)
{
- /* remove/free any remaining frames */
- while (afq->frame_queue)
- delete_next_frame(afq);
+ if(afq->frame_count)
+ av_log(afq->avctx, AV_LOG_WARNING, "%d frames left in the queue on closing\n", afq->frame_count);
+ av_freep(&afq->frames);
memset(afq, 0, sizeof(*afq));
}
-#ifdef DEBUG
-static void af_queue_log_state(AudioFrameQueue *afq)
-{
- AudioFrame *f;
- ff_dlog(afq->avctx, "remaining delay = %d\n", afq->remaining_delay);
- ff_dlog(afq->avctx, "remaining samples = %d\n", afq->remaining_samples);
- ff_dlog(afq->avctx, "frames:\n");
- f = afq->frame_queue;
- while (f) {
- ff_dlog(afq->avctx, " [ pts=%9"PRId64" duration=%d ]\n",
- f->pts, f->duration);
- f = f->next;
- }
-}
-#endif /* DEBUG */
-
int ff_af_queue_add(AudioFrameQueue *afq, const AVFrame *f)
{
- AudioFrame *new_frame;
- AudioFrame *queue_end = afq->frame_queue;
-
- /* find the end of the queue */
- while (queue_end && queue_end->next)
- queue_end = queue_end->next;
-
- /* allocate new frame queue entry */
- if (!(new_frame = av_malloc(sizeof(*new_frame))))
+ AudioFrame *new = av_fast_realloc(afq->frames, &afq->frame_alloc, sizeof(*afq->frames)*(afq->frame_count+1));
+ if(!new)
return AVERROR(ENOMEM);
+ afq->frames = new;
+ new += afq->frame_count;
/* get frame parameters */
- new_frame->next = NULL;
- new_frame->duration = f->nb_samples;
+ new->duration = f->nb_samples;
+ new->duration += afq->remaining_delay;
if (f->pts != AV_NOPTS_VALUE) {
- new_frame->pts = av_rescale_q(f->pts,
+ new->pts = av_rescale_q(f->pts,
afq->avctx->time_base,
(AVRational){ 1, afq->avctx->sample_rate });
- afq->next_pts = new_frame->pts + new_frame->duration;
+ new->pts -= afq->remaining_delay;
+ if(afq->frame_count && new[-1].pts >= new->pts)
+ av_log(afq->avctx, AV_LOG_WARNING, "Queue input is backward in time\n");
} else {
- new_frame->pts = AV_NOPTS_VALUE;
- afq->next_pts = AV_NOPTS_VALUE;
+ new->pts = AV_NOPTS_VALUE;
}
-
- /* add new frame to the end of the queue */
- if (!queue_end)
- afq->frame_queue = new_frame;
- else
- queue_end->next = new_frame;
+ afq->remaining_delay = 0;
/* add frame sample count */
afq->remaining_samples += f->nb_samples;
-#ifdef DEBUG
- af_queue_log_state(afq);
-#endif
+ afq->frame_count++;
return 0;
}
@@ -115,50 +77,37 @@ void ff_af_queue_remove(AudioFrameQueue *afq, int nb_samples, int64_t *pts,
{
int64_t out_pts = AV_NOPTS_VALUE;
int removed_samples = 0;
+ int i;
-#ifdef DEBUG
- af_queue_log_state(afq);
-#endif
-
- /* get output pts from the next frame or generated pts */
- if (afq->frame_queue) {
- if (afq->frame_queue->pts != AV_NOPTS_VALUE)
- out_pts = afq->frame_queue->pts - afq->remaining_delay;
- } else {
- if (afq->next_pts != AV_NOPTS_VALUE)
- out_pts = afq->next_pts - afq->remaining_delay;
+ if (afq->frame_count || afq->frame_alloc) {
+ if (afq->frames->pts != AV_NOPTS_VALUE)
+ out_pts = afq->frames->pts;
}
- if (pts) {
- if (out_pts != AV_NOPTS_VALUE)
- *pts = ff_samples_to_time_base(afq->avctx, out_pts);
- else
- *pts = AV_NOPTS_VALUE;
- }
-
- /* if the delay is larger than the packet duration, we use up delay samples
- for the output packet and leave all frames in the queue */
- if (afq->remaining_delay >= nb_samples) {
- removed_samples += nb_samples;
- afq->remaining_delay -= nb_samples;
- }
- /* remove frames from the queue until we have enough to cover the
- requested number of samples or until the queue is empty */
- while (removed_samples < nb_samples && afq->frame_queue) {
- removed_samples += afq->frame_queue->duration;
- delete_next_frame(afq);
+ if(!afq->frame_count)
+ av_log(afq->avctx, AV_LOG_WARNING, "Trying to remove %d samples, but the queue is empty\n", nb_samples);
+ if (pts)
+ *pts = ff_samples_to_time_base(afq->avctx, out_pts);
+
+ for(i=0; nb_samples && i<afq->frame_count; i++){
+ int n= FFMIN(afq->frames[i].duration, nb_samples);
+ afq->frames[i].duration -= n;
+ nb_samples -= n;
+ removed_samples += n;
+ if(afq->frames[i].pts != AV_NOPTS_VALUE)
+ afq->frames[i].pts += n;
}
afq->remaining_samples -= removed_samples;
-
- /* if there are no frames left and we have room for more samples, use
- any remaining delay samples */
- if (removed_samples < nb_samples && afq->remaining_samples > 0) {
- int add_samples = FFMIN(afq->remaining_samples,
- nb_samples - removed_samples);
- removed_samples += add_samples;
- afq->remaining_samples -= add_samples;
+ i -= i && afq->frames[i-1].duration;
+ memmove(afq->frames, afq->frames + i, sizeof(*afq->frames) * (afq->frame_count - i));
+ afq->frame_count -= i;
+
+ if(nb_samples){
+ av_assert0(!afq->frame_count);
+ av_assert0(afq->remaining_samples == afq->remaining_delay);
+ if(afq->frames && afq->frames[0].pts != AV_NOPTS_VALUE)
+ afq->frames[0].pts += nb_samples;
+ av_log(afq->avctx, AV_LOG_DEBUG, "Trying to remove %d more samples than there are in the queue\n", nb_samples);
}
- if (removed_samples > nb_samples)
- av_log(afq->avctx, AV_LOG_WARNING, "frame_size is too large\n");
if (duration)
*duration = ff_samples_to_time_base(afq->avctx, removed_samples);
}
diff --git a/libavcodec/audio_frame_queue.h b/libavcodec/audio_frame_queue.h
index 4a2977094b..2e317bbf41 100644
--- a/libavcodec/audio_frame_queue.h
+++ b/libavcodec/audio_frame_queue.h
@@ -2,20 +2,20 @@
* Audio Frame Queue
* Copyright (c) 2012 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,15 +27,15 @@
typedef struct AudioFrame {
int64_t pts;
int duration;
- struct AudioFrame *next;
} AudioFrame;
typedef struct AudioFrameQueue {
AVCodecContext *avctx;
- int64_t next_pts;
int remaining_delay;
int remaining_samples;
- AudioFrame *frame_queue;
+ AudioFrame *frames;
+ unsigned frame_count;
+ unsigned frame_alloc;
} AudioFrameQueue;
/**
diff --git a/libavcodec/audioconvert.c b/libavcodec/audioconvert.c
new file mode 100644
index 0000000000..5e46fae2df
--- /dev/null
+++ b/libavcodec/audioconvert.c
@@ -0,0 +1,120 @@
+/*
+ * audio conversion
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio conversion
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/common.h"
+#include "libavutil/libm.h"
+#include "libavutil/samplefmt.h"
+#include "avcodec.h"
+#include "audioconvert.h"
+
+#if FF_API_AUDIO_CONVERT
+
+struct AVAudioConvert {
+ int in_channels, out_channels;
+ int fmt_pair;
+};
+
+AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels,
+ enum AVSampleFormat in_fmt, int in_channels,
+ const float *matrix, int flags)
+{
+ AVAudioConvert *ctx;
+ if (in_channels!=out_channels)
+ return NULL; /* FIXME: not supported */
+ ctx = av_malloc(sizeof(AVAudioConvert));
+ if (!ctx)
+ return NULL;
+ ctx->in_channels = in_channels;
+ ctx->out_channels = out_channels;
+ ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt;
+ return ctx;
+}
+
+void av_audio_convert_free(AVAudioConvert *ctx)
+{
+ av_free(ctx);
+}
+
+int av_audio_convert(AVAudioConvert *ctx,
+ void * const out[6], const int out_stride[6],
+ const void * const in[6], const int in_stride[6], int len)
+{
+ int ch;
+
+ //FIXME optimize common cases
+
+ for(ch=0; ch<ctx->out_channels; ch++){
+ const int is= in_stride[ch];
+ const int os= out_stride[ch];
+ const uint8_t *pi= in[ch];
+ uint8_t *po= out[ch];
+ uint8_t *end= po + os*len;
+ if(!out[ch])
+ continue;
+
+#define CONV(ofmt, otype, ifmt, expr)\
+if(ctx->fmt_pair == ofmt + AV_SAMPLE_FMT_NB*ifmt){\
+ do{\
+ *(otype*)po = expr; pi += is; po += os;\
+ }while(po < end);\
+}
+
+//FIXME put things below under ifdefs so we do not waste space for cases no codec will need
+//FIXME rounding ?
+
+ CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi)
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8)
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24)
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80)
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi)
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16)
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15)))
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15)))
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80)
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16)
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi)
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31)))
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31)))
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80))
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15))))
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31))))
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi)
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi)
+ else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80))
+ else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15))))
+ else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31))))
+ else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi)
+ else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi)
+ else return -1;
+ }
+ return 0;
+}
+
+#endif /* FF_API_AUDIO_CONVERT */
diff --git a/libavcodec/audioconvert.h b/libavcodec/audioconvert.h
new file mode 100644
index 0000000000..996c3f37ad
--- /dev/null
+++ b/libavcodec/audioconvert.h
@@ -0,0 +1,86 @@
+/*
+ * audio conversion
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2008 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_AUDIOCONVERT_H
+#define AVCODEC_AUDIOCONVERT_H
+
+#include "version.h"
+
+/**
+ * @file
+ * Audio format conversion routines
+ * This interface is deprecated and will be dropped in a future
+ * version. You should use the libswresample library instead.
+ */
+
+#if FF_API_AUDIO_CONVERT
+
+#include "libavutil/cpu.h"
+#include "avcodec.h"
+#include "libavutil/channel_layout.h"
+
+struct AVAudioConvert;
+typedef struct AVAudioConvert AVAudioConvert;
+
+/**
+ * Create an audio sample format converter context
+ * @param out_fmt Output sample format
+ * @param out_channels Number of output channels
+ * @param in_fmt Input sample format
+ * @param in_channels Number of input channels
+ * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore.
+ * @param flags See AV_CPU_FLAG_xx
+ * @return NULL on error
+ * @deprecated See libswresample
+ */
+
+attribute_deprecated
+AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels,
+ enum AVSampleFormat in_fmt, int in_channels,
+ const float *matrix, int flags);
+
+/**
+ * Free audio sample format converter context
+ * @deprecated See libswresample
+ */
+
+attribute_deprecated
+void av_audio_convert_free(AVAudioConvert *ctx);
+
+/**
+ * Convert between audio sample formats
+ * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel.
+ * @param[in] out_stride distance between consecutive output samples (measured in bytes)
+ * @param[in] in array of input buffers for each channel
+ * @param[in] in_stride distance between consecutive input samples (measured in bytes)
+ * @param len length of audio frame size (measured in samples)
+ * @deprecated See libswresample
+ */
+
+attribute_deprecated
+int av_audio_convert(AVAudioConvert *ctx,
+ void * const out[6], const int out_stride[6],
+ const void * const in[6], const int in_stride[6], int len);
+
+#endif /* FF_API_AUDIO_CONVERT */
+
+#endif /* AVCODEC_AUDIOCONVERT_H */
diff --git a/libavcodec/audiodsp.c b/libavcodec/audiodsp.c
index f7e6167cb0..85b5a74947 100644
--- a/libavcodec/audiodsp.c
+++ b/libavcodec/audiodsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/audiodsp.h b/libavcodec/audiodsp.h
index 58205a1f19..b55bf858e0 100644
--- a/libavcodec/audiodsp.h
+++ b/libavcodec/audiodsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/aura.c b/libavcodec/aura.c
index a32c18b363..8d0f16a4de 100644
--- a/libavcodec/aura.c
+++ b/libavcodec/aura.c
@@ -1,20 +1,20 @@
/*
* Aura 2 decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,10 +59,8 @@ static int aura_decode_frame(AVCodecContext *avctx,
/* pixel data starts 48 bytes in, after 3x16-byte tables */
buf += 48;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
Y = frame->data[0];
U = frame->data[1];
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 3440126662..4aeb57aed4 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,7 @@
#include "libavutil/avutil.h"
#include "libavutil/buffer.h"
#include "libavutil/cpu.h"
+#include "libavutil/channel_layout.h"
#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
@@ -41,11 +42,6 @@
#include "version.h"
-#if FF_API_FAST_MALLOC
-// to provide fast_*alloc
-#include "libavutil/mem.h"
-#endif
-
/**
* @defgroup libavc Encoding/Decoding Library
* @{
@@ -97,7 +93,8 @@
*
* If you add a codec ID to this list, add it so that
* 1. no value of a existing codec ID changes (that would break ABI),
- * 2. it is as close as possible to similar codecs.
+ * 2. Give it a value which when taken as ASCII is recognized uniquely by a human as this specific codec.
+ * This ensures that 2 forks can independently add AVCodecIDs without producing conflicts.
*
* After adding new codec IDs, do not forget to add an entry to the codec
* descriptor list and bump libavcodec minor version.
@@ -278,25 +275,55 @@ enum AVCodecID {
AV_CODEC_ID_MSS2,
AV_CODEC_ID_VP9,
AV_CODEC_ID_AIC,
- AV_CODEC_ID_ESCAPE130,
- AV_CODEC_ID_G2M,
- AV_CODEC_ID_WEBP,
+ AV_CODEC_ID_ESCAPE130_DEPRECATED,
+ AV_CODEC_ID_G2M_DEPRECATED,
+ AV_CODEC_ID_WEBP_DEPRECATED,
AV_CODEC_ID_HNM4_VIDEO,
- AV_CODEC_ID_HEVC,
+ AV_CODEC_ID_HEVC_DEPRECATED,
AV_CODEC_ID_FIC,
AV_CODEC_ID_ALIAS_PIX,
- AV_CODEC_ID_BRENDER_PIX,
- AV_CODEC_ID_PAF_VIDEO,
- AV_CODEC_ID_EXR,
- AV_CODEC_ID_VP7,
- AV_CODEC_ID_SANM,
- AV_CODEC_ID_SGIRLE,
- AV_CODEC_ID_MVC1,
- AV_CODEC_ID_MVC2,
+ AV_CODEC_ID_BRENDER_PIX_DEPRECATED,
+ AV_CODEC_ID_PAF_VIDEO_DEPRECATED,
+ AV_CODEC_ID_EXR_DEPRECATED,
+ AV_CODEC_ID_VP7_DEPRECATED,
+ AV_CODEC_ID_SANM_DEPRECATED,
+ AV_CODEC_ID_SGIRLE_DEPRECATED,
+ AV_CODEC_ID_MVC1_DEPRECATED,
+ AV_CODEC_ID_MVC2_DEPRECATED,
AV_CODEC_ID_HQX,
AV_CODEC_ID_TDSC,
AV_CODEC_ID_HQ_HQA,
+ AV_CODEC_ID_BRENDER_PIX= MKBETAG('B','P','I','X'),
+ AV_CODEC_ID_Y41P = MKBETAG('Y','4','1','P'),
+ AV_CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'),
+ AV_CODEC_ID_EXR = MKBETAG('0','E','X','R'),
+ AV_CODEC_ID_AVRP = MKBETAG('A','V','R','P'),
+
+ AV_CODEC_ID_012V = MKBETAG('0','1','2','V'),
+ AV_CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'),
+ AV_CODEC_ID_AVUI = MKBETAG('A','V','U','I'),
+ AV_CODEC_ID_AYUV = MKBETAG('A','Y','U','V'),
+ AV_CODEC_ID_TARGA_Y216 = MKBETAG('T','2','1','6'),
+ AV_CODEC_ID_V308 = MKBETAG('V','3','0','8'),
+ AV_CODEC_ID_V408 = MKBETAG('V','4','0','8'),
+ AV_CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'),
+ AV_CODEC_ID_SANM = MKBETAG('S','A','N','M'),
+ AV_CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'),
+ AV_CODEC_ID_AVRN = MKBETAG('A','V','R','n'),
+ AV_CODEC_ID_CPIA = MKBETAG('C','P','I','A'),
+ AV_CODEC_ID_XFACE = MKBETAG('X','F','A','C'),
+ AV_CODEC_ID_SGIRLE = MKBETAG('S','G','I','R'),
+ AV_CODEC_ID_MVC1 = MKBETAG('M','V','C','1'),
+ AV_CODEC_ID_MVC2 = MKBETAG('M','V','C','2'),
+ AV_CODEC_ID_SNOW = MKBETAG('S','N','O','W'),
+ AV_CODEC_ID_WEBP = MKBETAG('W','E','B','P'),
+ AV_CODEC_ID_SMVJPEG = MKBETAG('S','M','V','J'),
+ AV_CODEC_ID_HEVC = MKBETAG('H','2','6','5'),
+#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
+ AV_CODEC_ID_VP7 = MKBETAG('V','P','7','0'),
+ AV_CODEC_ID_APNG = MKBETAG('A','P','N','G'),
+
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
AV_CODEC_ID_PCM_S16LE = 0x10000,
@@ -327,8 +354,11 @@ enum AVCodecID {
AV_CODEC_ID_PCM_LXF,
AV_CODEC_ID_S302M,
AV_CODEC_ID_PCM_S8_PLANAR,
- AV_CODEC_ID_PCM_S24LE_PLANAR,
- AV_CODEC_ID_PCM_S32LE_PLANAR,
+ AV_CODEC_ID_PCM_S24LE_PLANAR_DEPRECATED,
+ AV_CODEC_ID_PCM_S32LE_PLANAR_DEPRECATED,
+ AV_CODEC_ID_PCM_S24LE_PLANAR = MKBETAG(24,'P','S','P'),
+ AV_CODEC_ID_PCM_S32LE_PLANAR = MKBETAG(32,'P','S','P'),
+ AV_CODEC_ID_PCM_S16BE_PLANAR = MKBETAG('P','S','P',16),
/* various ADPCM codecs */
AV_CODEC_ID_ADPCM_IMA_QT = 0x11000,
@@ -361,7 +391,16 @@ enum AVCodecID {
AV_CODEC_ID_ADPCM_IMA_ISS,
AV_CODEC_ID_ADPCM_G722,
AV_CODEC_ID_ADPCM_IMA_APC,
- AV_CODEC_ID_ADPCM_VIMA,
+ AV_CODEC_ID_ADPCM_VIMA_DEPRECATED,
+ AV_CODEC_ID_ADPCM_VIMA = MKBETAG('V','I','M','A'),
+#if FF_API_VIMA_DECODER
+ AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'),
+#endif
+ AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '),
+ AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '),
+ AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '),
+ AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '),
+ AV_CODEC_ID_ADPCM_G726LE = MKBETAG('6','2','7','G'),
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,
@@ -441,13 +480,25 @@ enum AVCodecID {
AV_CODEC_ID_RALF,
AV_CODEC_ID_IAC,
AV_CODEC_ID_ILBC,
- AV_CODEC_ID_OPUS,
+ AV_CODEC_ID_OPUS_DEPRECATED,
AV_CODEC_ID_COMFORT_NOISE,
- AV_CODEC_ID_TAK,
+ AV_CODEC_ID_TAK_DEPRECATED,
AV_CODEC_ID_METASOUND,
- AV_CODEC_ID_PAF_AUDIO,
+ AV_CODEC_ID_PAF_AUDIO_DEPRECATED,
AV_CODEC_ID_ON2AVC,
AV_CODEC_ID_DSS_SP,
+ AV_CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'),
+ AV_CODEC_ID_SONIC = MKBETAG('S','O','N','C'),
+ AV_CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'),
+ AV_CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'),
+ AV_CODEC_ID_OPUS = MKBETAG('O','P','U','S'),
+ AV_CODEC_ID_TAK = MKBETAG('t','B','a','K'),
+ AV_CODEC_ID_EVRC = MKBETAG('s','e','v','c'),
+ AV_CODEC_ID_SMV = MKBETAG('s','s','m','v'),
+ AV_CODEC_ID_DSD_LSBF = MKBETAG('D','S','D','L'),
+ AV_CODEC_ID_DSD_MSBF = MKBETAG('D','S','D','M'),
+ AV_CODEC_ID_DSD_LSBF_PLANAR = MKBETAG('D','S','D','1'),
+ AV_CODEC_ID_DSD_MSBF_PLANAR = MKBETAG('D','S','D','8'),
/* subtitle codecs */
AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
@@ -460,10 +511,33 @@ enum AVCodecID {
AV_CODEC_ID_HDMV_PGS_SUBTITLE,
AV_CODEC_ID_DVB_TELETEXT,
AV_CODEC_ID_SRT,
+ AV_CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'),
+ AV_CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'),
+ AV_CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'),
+ AV_CODEC_ID_SAMI = MKBETAG('S','A','M','I'),
+ AV_CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'),
+ AV_CODEC_ID_STL = MKBETAG('S','p','T','L'),
+ AV_CODEC_ID_SUBVIEWER1 = MKBETAG('S','b','V','1'),
+ AV_CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'),
+ AV_CODEC_ID_SUBRIP = MKBETAG('S','R','i','p'),
+ AV_CODEC_ID_WEBVTT = MKBETAG('W','V','T','T'),
+ AV_CODEC_ID_MPL2 = MKBETAG('M','P','L','2'),
+ AV_CODEC_ID_VPLAYER = MKBETAG('V','P','l','r'),
+ AV_CODEC_ID_PJS = MKBETAG('P','h','J','S'),
+ AV_CODEC_ID_ASS = MKBETAG('A','S','S',' '), ///< ASS as defined in Matroska
/* other specific kind of codecs (generally used for attachments) */
AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
AV_CODEC_ID_TTF = 0x18000,
+ AV_CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'),
+ AV_CODEC_ID_XBIN = MKBETAG('X','B','I','N'),
+ AV_CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'),
+ AV_CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'),
+ AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'),
+ AV_CODEC_ID_DVD_NAV = MKBETAG('D','N','A','V'),
+ AV_CODEC_ID_TIMED_ID3 = MKBETAG('T','I','D','3'),
+ AV_CODEC_ID_BIN_DATA = MKBETAG('D','A','T','A'),
+
AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
@@ -472,6 +546,10 @@ enum AVCodecID {
AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems
* stream (only used by libavformat) */
AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information.
+
+#if FF_API_CODEC_ID
+#include "old_codec_ids.h"
+#endif
};
/**
@@ -496,6 +574,13 @@ typedef struct AVCodecDescriptor {
* Codec properties, a combination of AV_CODEC_PROP_* flags.
*/
int props;
+
+ /**
+ * MIME type(s) associated with the codec.
+ * May be NULL; if not, a NULL-terminated array of MIME types.
+ * The first item is always non-NULL and is the preferred MIME type.
+ */
+ const char *const *mime_types;
} AVCodecDescriptor;
/**
@@ -523,6 +608,16 @@ typedef struct AVCodecDescriptor {
* equal.
*/
#define AV_CODEC_PROP_REORDER (1 << 3)
+/**
+ * Subtitle codec is bitmap based
+ * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field.
+ */
+#define AV_CODEC_PROP_BITMAP_SUB (1 << 16)
+/**
+ * Subtitle codec is text based.
+ * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field.
+ */
+#define AV_CODEC_PROP_TEXT_SUB (1 << 17)
/**
* @ingroup lavc_decoding
@@ -532,7 +627,7 @@ typedef struct AVCodecDescriptor {
* Note: If the first 23 bits of the additional bytes are not 0, then damaged
* MPEG bitstreams could cause overread and segfault.
*/
-#define FF_INPUT_BUFFER_PADDING_SIZE 8
+#define FF_INPUT_BUFFER_PADDING_SIZE 32
/**
* @ingroup lavc_encoding
@@ -556,6 +651,7 @@ enum Motion_Est_ID {
ME_HEX, ///< hexagon based search
ME_UMH, ///< uneven multi-hexagon search
ME_TESA, ///< transformed exhaustive search algorithm
+ ME_ITER=50, ///< iterative search
};
/**
@@ -568,6 +664,7 @@ enum AVDiscard{
AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi
AVDISCARD_NONREF = 8, ///< discard all non reference
AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames
+ AVDISCARD_NONINTRA= 24, ///< discard all non intra frames
AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes
AVDISCARD_ALL = 48, ///< discard all
};
@@ -668,9 +765,13 @@ typedef struct RcOverride{
#define CODEC_FLAG2_FAST 0x00000001 ///< Allow non spec compliant speedup tricks.
#define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding.
#define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata.
+#define CODEC_FLAG2_DROP_FRAME_TIMECODE 0x00002000 ///< timecode is in drop frame format. DEPRECATED!!!!
#define CODEC_FLAG2_IGNORE_CROP 0x00010000 ///< Discard cropping information from SPS.
#define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries.
+#define CODEC_FLAG2_SHOW_ALL 0x00400000 ///< Show all frames before the first keyframe
+#define CODEC_FLAG2_EXPORT_MVS 0x10000000 ///< Export motion vectors through frame side data
+#define CODEC_FLAG2_SKIP_MANUAL 0x20000000 ///< Do not skip samples and export skip information as frame side data
/* Unsupported options :
* Syntax Arithmetic coding (SAC)
@@ -688,7 +789,13 @@ typedef struct RcOverride{
#define CODEC_CAP_DR1 0x0002
#define CODEC_CAP_TRUNCATED 0x0008
#if FF_API_XVMC
-/* Codec can export data for HW decoding (XvMC). */
+/* Codec can export data for HW decoding. This flag indicates that
+ * the codec would call get_format() with list that might contain HW accelerated
+ * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them
+ * including raw image format.
+ * The application can use the passed context to determine bitstream version,
+ * chroma format, resolution etc.
+ */
#define CODEC_CAP_HWACCEL 0x0010
#endif /* FF_API_XVMC */
/**
@@ -773,6 +880,14 @@ typedef struct RcOverride{
* Audio encoder supports receiving a different number of samples in each call.
*/
#define CODEC_CAP_VARIABLE_FRAME_SIZE 0x10000
+/**
+ * Codec is intra only.
+ */
+#define CODEC_CAP_INTRA_ONLY 0x40000000
+/**
+ * Codec is lossless.
+ */
+#define CODEC_CAP_LOSSLESS 0x80000000
#if FF_API_MB_TYPE
//The following defines may change, don't expect compatibility if you use them.
@@ -927,6 +1042,70 @@ enum AVPacketSideDataType {
* to enum AVAudioServiceType.
*/
AV_PKT_DATA_AUDIO_SERVICE_TYPE,
+
+ /**
+ * Recommmends skipping the specified number of samples
+ * @code
+ * u32le number of samples to skip from start of this packet
+ * u32le number of samples to skip from end of this packet
+ * u8 reason for start skip
+ * u8 reason for end skip (0=padding silence, 1=convergence)
+ * @endcode
+ */
+ AV_PKT_DATA_SKIP_SAMPLES=70,
+
+ /**
+ * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that
+ * the packet may contain "dual mono" audio specific to Japanese DTV
+ * and if it is true, recommends only the selected channel to be used.
+ * @code
+ * u8 selected channels (0=mail/left, 1=sub/right, 2=both)
+ * @endcode
+ */
+ AV_PKT_DATA_JP_DUALMONO,
+
+ /**
+ * A list of zero terminated key/value strings. There is no end marker for
+ * the list, so it is required to rely on the side data size to stop.
+ */
+ AV_PKT_DATA_STRINGS_METADATA,
+
+ /**
+ * Subtitle event position
+ * @code
+ * u32le x1
+ * u32le y1
+ * u32le x2
+ * u32le y2
+ * @endcode
+ */
+ AV_PKT_DATA_SUBTITLE_POSITION,
+
+ /**
+ * Data found in BlockAdditional element of matroska container. There is
+ * no end marker for the data, so it is required to rely on the side data
+ * size to recognize the end. 8 byte id (as found in BlockAddId) followed
+ * by data.
+ */
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
+
+ /**
+ * The optional first identifier line of a WebVTT cue.
+ */
+ AV_PKT_DATA_WEBVTT_IDENTIFIER,
+
+ /**
+ * The optional settings (rendering instructions) that immediately
+ * follow the timestamp specifier of a WebVTT cue.
+ */
+ AV_PKT_DATA_WEBVTT_SETTINGS,
+
+ /**
+ * A list of zero terminated key/value strings. There is no end marker for
+ * the list, so it is required to rely on the side data size to stop. This
+ * side data includes updated metadata which appeared in the stream.
+ */
+ AV_PKT_DATA_METADATA_UPDATE,
};
typedef struct AVPacketSideData {
@@ -943,7 +1122,7 @@ typedef struct AVPacketSideData {
* For video, it should typically contain one compressed frame. For audio it may
* contain several compressed frames.
*
- * AVPacket is one of the few structs in Libav, whose size is a part of public
+ * AVPacket is one of the few structs in FFmpeg, whose size is a part of public
* ABI. Thus it may be allocated on stack and no new fields can be added to it
* without libavcodec and libavformat major bump.
*
@@ -1055,6 +1234,8 @@ enum AVFieldOrder {
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
* version bump.
+ * Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user
+ * applications.
* sizeof(AVCodecContext) must not be used outside libav*.
*/
typedef struct AVCodecContext {
@@ -1166,7 +1347,7 @@ typedef struct AVCodecContext {
* rv10: additional flags
* mpeg4: global headers (they can be in the bitstream or here)
* The allocated memory should be FF_INPUT_BUFFER_PADDING_SIZE bytes larger
- * than extradata_size to avoid prolems if it is read with the bitstream reader.
+ * than extradata_size to avoid problems if it is read with the bitstream reader.
* The bytewise contents of extradata must not depend on the architecture or CPU endianness.
* - encoding: Set/allocated/freed by libavcodec.
* - decoding: Set/allocated/freed by user.
@@ -1179,6 +1360,8 @@ typedef struct AVCodecContext {
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identically 1.
+ * This often, but not always is the inverse of the frame rate or field rate
+ * for video.
* - encoding: MUST be set by user.
* - decoding: the use of this field for decoding is deprecated.
* Use framerate instead.
@@ -1197,6 +1380,11 @@ typedef struct AVCodecContext {
/**
* Codec delay.
*
+ * Encoding: Number of frames delay there will be from the encoder input to
+ * the decoder output. (we assume the decoder matches the spec)
+ * Decoding: Number of frames delay in addition to what a standard decoder
+ * as specified in the spec would produce.
+ *
* Video:
* Number of frames the decoded output will be delayed relative to the
* encoded input.
@@ -1227,7 +1415,7 @@ typedef struct AVCodecContext {
/**
* Bitstream width / height, may be different from width/height e.g. when
- * the decoded frame is cropped before being output.
+ * the decoded frame is cropped before being output or lowres is enabled.
* - encoding: unused
* - decoding: May be set by the user before opening the decoder if known
* e.g. from the container. During decoding, the decoder may
@@ -1249,7 +1437,7 @@ typedef struct AVCodecContext {
/**
* Pixel format, see AV_PIX_FMT_xxx.
* May be set by the demuxer if known from headers.
- * May be overriden by the decoder if it knows better.
+ * May be overridden by the decoder if it knows better.
* - encoding: Set by user.
* - decoding: Set by user if known, overridden by libavcodec if known
*/
@@ -1258,7 +1446,7 @@ typedef struct AVCodecContext {
/**
* Motion estimation algorithm used for video coding.
* 1 (zero), 2 (full), 3 (log), 4 (phods), 5 (epzs), 6 (x1), 7 (hex),
- * 8 (umh), 10 (tesa) [7, 8, 10 are x264 specific]
+ * 8 (umh), 9 (iter), 10 (tesa) [7, 8, 10 are x264 specific, 9 is snow specific]
* - encoding: MUST be set by user.
* - decoding: unused
*/
@@ -1469,6 +1657,8 @@ typedef struct AVCodecContext {
#define FF_CMP_VSAD 8
#define FF_CMP_VSSE 9
#define FF_CMP_NSSE 10
+#define FF_CMP_W53 11
+#define FF_CMP_W97 12
#define FF_CMP_DCTMAX 13
#define FF_CMP_DCT264 14
#define FF_CMP_CHROMA 256
@@ -1574,7 +1764,7 @@ typedef struct AVCodecContext {
* XVideo Motion Acceleration
* - encoding: forbidden
* - decoding: set by decoder
- * @deprecated XvMC support is slated for removal.
+ * @deprecated XvMC doesn't need it anymore.
*/
attribute_deprecated int xvmc_acceleration;
#endif /* FF_API_XVMC */
@@ -1635,7 +1825,7 @@ typedef struct AVCodecContext {
/**
* precision of the intra DC coefficient - 8
* - encoding: Set by user.
- * - decoding: unused
+ * - decoding: Set by libavcodec
*/
int intra_dc_precision;
@@ -1787,7 +1977,7 @@ typedef struct AVCodecContext {
/** Field order
* - encoding: set by libavcodec
- * - decoding: Set by libavcodec
+ * - decoding: Set by user.
*/
enum AVFieldOrder field_order;
@@ -1851,7 +2041,7 @@ typedef struct AVCodecContext {
/**
* Audio channel layout.
* - encoding: set by user.
- * - decoding: set by libavcodec.
+ * - decoding: set by user, may be overwritten by libavcodec.
*/
uint64_t channel_layout;
@@ -1870,9 +2060,10 @@ typedef struct AVCodecContext {
enum AVAudioServiceType audio_service_type;
/**
- * Used to request a sample format from the decoder.
- * - encoding: unused.
+ * desired sample format
+ * - encoding: Not used.
* - decoding: Set by user.
+ * Decoder will decode to this format if it can.
*/
enum AVSampleFormat request_sample_fmt;
@@ -2026,6 +2217,8 @@ typedef struct AVCodecContext {
* avcodec_align_dimensions2() should be used to find the required width and
* height, as they normally need to be rounded up to the next multiple of 16.
*
+ * Some decoders do not support linesizes changing between frames.
+ *
* If frame multithreading is used and thread_safe_callbacks is set,
* this callback may be called from a different thread, but not from more
* than one at once. Does not need to be reentrant.
@@ -2129,7 +2322,7 @@ typedef struct AVCodecContext {
/**
* maximum bitrate
* - encoding: Set by user.
- * - decoding: unused
+ * - decoding: Set by libavcodec.
*/
int rc_max_rate;
@@ -2255,9 +2448,9 @@ typedef struct AVCodecContext {
int max_prediction_order;
/**
- * GOP timecode frame start number, in non drop frame format
- * - encoding: Set by user.
- * - decoding: unused
+ * GOP timecode frame start number
+ * - encoding: Set by user, in non drop frame format
+ * - decoding: Set by libavcodec (timecode in the 25 bits format, -1 if unset)
*/
int64_t timecode_frame_start;
@@ -2362,6 +2555,7 @@ typedef struct AVCodecContext {
int error_concealment;
#define FF_EC_GUESS_MVS 1
#define FF_EC_DEBLOCK 2
+#define FF_EC_FAVOR_INTER 256
/**
* debug
@@ -2390,17 +2584,20 @@ typedef struct AVCodecContext {
#define FF_DEBUG_MMCO 0x00000800
#define FF_DEBUG_BUGS 0x00001000
#if FF_API_DEBUG_MV
-#define FF_DEBUG_VIS_QP 0x00002000
-#define FF_DEBUG_VIS_MB_TYPE 0x00004000
+#define FF_DEBUG_VIS_QP 0x00002000 ///< only access through AVOptions from outside libavcodec
+#define FF_DEBUG_VIS_MB_TYPE 0x00004000 ///< only access through AVOptions from outside libavcodec
#endif
#define FF_DEBUG_BUFFERS 0x00008000
#define FF_DEBUG_THREADS 0x00010000
+#define FF_DEBUG_NOMC 0x01000000
#if FF_API_DEBUG_MV
/**
- * @deprecated this option does not have any effect
+ * debug
+ * Code outside libavcodec should access this field using AVOptions
+ * - encoding: Set by user.
+ * - decoding: Set by user.
*/
- attribute_deprecated
int debug_mv;
#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames
#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames
@@ -2421,9 +2618,15 @@ typedef struct AVCodecContext {
* decoder returning an error.
*/
#define AV_EF_CRCCHECK (1<<0)
-#define AV_EF_BITSTREAM (1<<1)
-#define AV_EF_BUFFER (1<<2)
-#define AV_EF_EXPLODE (1<<3)
+#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations
+#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length
+#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection
+
+#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue
+#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors
+#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors
+#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error
+
/**
* opaque 64bit number (generally a PTS) that will be reordered and
@@ -2444,8 +2647,8 @@ typedef struct AVCodecContext {
* Hardware accelerator context.
* For some hardware accelerators, a global context needs to be
* provided by the user. In that case, this holds display-dependent
- * data Libav cannot instantiate itself. Please refer to the
- * Libav HW accelerator documentation to know how to fill this
+ * data FFmpeg cannot instantiate itself. Please refer to the
+ * FFmpeg HW accelerator documentation to know how to fill this
* is. e.g. for VA API, this is a struct vaapi_context.
* - encoding: unused
* - decoding: Set by user
@@ -2507,6 +2710,7 @@ typedef struct AVCodecContext {
#if FF_API_ARCH_ALPHA
#define FF_IDCT_SIMPLEALPHA 23
#endif
+#define FF_IDCT_SIMPLEAUTO 128
/**
* bits per sample/pixel from the demuxer (needed for huffyuv).
@@ -2527,10 +2731,10 @@ typedef struct AVCodecContext {
* low resolution decoding, 1-> 1/2 size, 2->1/4 size
* - encoding: unused
* - decoding: Set by user.
- *
- * @deprecated use decoder private options instead
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_lowres(avctx)
*/
- attribute_deprecated int lowres;
+ int lowres;
#endif
/**
@@ -2617,7 +2821,7 @@ typedef struct AVCodecContext {
#endif
/**
- * noise vs. sse weight for the nsse comparsion function
+ * noise vs. sse weight for the nsse comparison function
* - encoding: Set by user.
* - decoding: unused
*/
@@ -2706,6 +2910,12 @@ typedef struct AVCodecContext {
#define FF_PROFILE_HEVC_MAIN 1
#define FF_PROFILE_HEVC_MAIN_10 2
#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3
+#define FF_PROFILE_HEVC_REXT 4
+
+#define FF_PROFILE_VP9_0 0
+#define FF_PROFILE_VP9_1 1
+#define FF_PROFILE_VP9_2 2
+#define FF_PROFILE_VP9_3 3
/**
* level
@@ -2716,21 +2926,21 @@ typedef struct AVCodecContext {
#define FF_LEVEL_UNKNOWN -99
/**
- *
+ * Skip loop filtering for selected frames.
* - encoding: unused
* - decoding: Set by user.
*/
enum AVDiscard skip_loop_filter;
/**
- *
+ * Skip IDCT/dequantization for selected frames.
* - encoding: unused
* - decoding: Set by user.
*/
enum AVDiscard skip_idct;
/**
- *
+ * Skip decoding for selected frames.
* - encoding: unused
* - decoding: Set by user.
*/
@@ -2804,7 +3014,7 @@ typedef struct AVCodecContext {
*/
int initial_padding;
- /*
+ /**
* - decoding: For codecs that store a framerate value in the compressed
* bitstream, the decoder may export it here. { 0, 1} when
* unknown.
@@ -2818,8 +3028,141 @@ typedef struct AVCodecContext {
* - decoding: Set by libavcodec before calling get_format()
*/
enum AVPixelFormat sw_pix_fmt;
+
+ /**
+ * Timebase in which pkt_dts/pts and AVPacket.dts/pts are.
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_pkt_timebase(avctx)
+ * - encoding unused.
+ * - decoding set by user.
+ */
+ AVRational pkt_timebase;
+
+ /**
+ * AVCodecDescriptor
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_codec_descriptor(avctx)
+ * - encoding: unused.
+ * - decoding: set by libavcodec.
+ */
+ const AVCodecDescriptor *codec_descriptor;
+
+#if !FF_API_LOWRES
+ /**
+ * low resolution decoding, 1-> 1/2 size, 2->1/4 size
+ * - encoding: unused
+ * - decoding: Set by user.
+ * Code outside libavcodec should access this field using:
+ * av_codec_{get,set}_lowres(avctx)
+ */
+ int lowres;
+#endif
+
+ /**
+ * Current statistics for PTS correction.
+ * - decoding: maintained and used by libavcodec, not intended to be used by user apps
+ * - encoding: unused
+ */
+ int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far
+ int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far
+ int64_t pts_correction_last_pts; /// PTS of the last frame
+ int64_t pts_correction_last_dts; /// DTS of the last frame
+
+ /**
+ * Character encoding of the input subtitles file.
+ * - decoding: set by user
+ * - encoding: unused
+ */
+ char *sub_charenc;
+
+ /**
+ * Subtitles character encoding mode. Formats or codecs might be adjusting
+ * this setting (if they are doing the conversion themselves for instance).
+ * - decoding: set by libavcodec
+ * - encoding: unused
+ */
+ int sub_charenc_mode;
+#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance)
+#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself
+#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv
+
+ /**
+ * Skip processing alpha if supported by codec.
+ * Note that if the format uses pre-multiplied alpha (common with VP6,
+ * and recommended due to better video quality/compression)
+ * the image will look as if alpha-blended onto a black background.
+ * However for formats that do not use pre-multiplied alpha
+ * there might be serious artefacts (though e.g. libswscale currently
+ * assumes pre-multiplied alpha anyway).
+ * Code outside libavcodec should access this field using AVOptions
+ *
+ * - decoding: set by user
+ * - encoding: unused
+ */
+ int skip_alpha;
+
+ /**
+ * Number of samples to skip after a discontinuity
+ * - decoding: unused
+ * - encoding: set by libavcodec
+ */
+ int seek_preroll;
+
+#if !FF_API_DEBUG_MV
+ /**
+ * debug motion vectors
+ * Code outside libavcodec should access this field using AVOptions
+ * - encoding: Set by user.
+ * - decoding: Set by user.
+ */
+ int debug_mv;
+#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames
+#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames
+#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames
+#endif
+
+ /**
+ * custom intra quantization matrix
+ * Code outside libavcodec should access this field using av_codec_g/set_chroma_intra_matrix()
+ * - encoding: Set by user, can be NULL.
+ * - decoding: unused.
+ */
+ uint16_t *chroma_intra_matrix;
+
+ /**
+ * dump format separator.
+ * can be ", " or "\n " or anything else
+ * Code outside libavcodec should access this field using AVOptions
+ * (NO direct access).
+ * - encoding: Set by user.
+ * - decoding: Set by user.
+ */
+ uint8_t *dump_separator;
+
+ /**
+ * ',' separated list of allowed decoders.
+ * If NULL then all are allowed
+ * - encoding: unused
+ * - decoding: set by user through AVOPtions (NO direct access)
+ */
+ char *codec_whitelist;
} AVCodecContext;
+AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);
+void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val);
+
+const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx);
+void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc);
+
+int av_codec_get_lowres(const AVCodecContext *avctx);
+void av_codec_set_lowres(AVCodecContext *avctx, int val);
+
+int av_codec_get_seek_preroll(const AVCodecContext *avctx);
+void av_codec_set_seek_preroll(AVCodecContext *avctx, int val);
+
+uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx);
+void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val);
+
/**
* AVProfile.
*/
@@ -2861,7 +3204,7 @@ typedef struct AVCodec {
const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1
const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0
#if FF_API_LOWRES
- attribute_deprecated uint8_t max_lowres; ///< maximum value for lowres supported by the decoder
+ uint8_t max_lowres; ///< maximum value for lowres supported by the decoder, no direct access, use av_codec_get_max_lowres()
#endif
const AVClass *priv_class; ///< AVClass for the private context
const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN}
@@ -2934,6 +3277,10 @@ typedef struct AVCodec {
int caps_internal;
} AVCodec;
+int av_codec_get_max_lowres(const AVCodec *codec);
+
+struct MpegEncContext;
+
/**
* @defgroup lavc_hwaccel AVHWAccel
* @{
@@ -3008,6 +3355,7 @@ typedef struct AVHWAccel {
*
* Meaningful slice information (codec specific) is guaranteed to
* be parsed at this point. This function is mandatory.
+ * The only exception is XvMC, that works on MB level.
*
* @param avctx the codec context
* @param buf the slice data buffer base
@@ -3037,6 +3385,17 @@ typedef struct AVHWAccel {
int frame_priv_data_size;
/**
+ * Called for every Macroblock in a slice.
+ *
+ * XvMC uses it to replace the ff_mpv_decode_mb().
+ * Instead of decoding to raw picture, MB parameters are
+ * stored in an array provided by the video driver.
+ *
+ * @param s the mpeg context
+ */
+ void (*decode_mb)(struct MpegEncContext *s);
+
+ /**
* Initialize the hwaccel private data.
*
* This will be called from ff_get_format(), after hwaccel and
@@ -3085,11 +3444,13 @@ typedef struct AVHWAccel {
*/
/**
- * four components are given, that's all.
- * the last component is alpha
+ * Picture data structure.
+ *
+ * Up to four components can be stored into it, the last component is
+ * alpha.
*/
typedef struct AVPicture {
- uint8_t *data[AV_NUM_DATA_POINTERS];
+ uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes
int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line
} AVPicture;
@@ -3097,9 +3458,6 @@ typedef struct AVPicture {
* @}
*/
-#define AVPALETTE_SIZE 1024
-#define AVPALETTE_COUNT 256
-
enum AVSubtitleType {
SUBTITLE_NONE,
@@ -3129,7 +3487,7 @@ typedef struct AVSubtitleRect {
/**
* data+linesize for the bitmap of this subtitle.
- * can be set for text/ass as well once they where rendered
+ * can be set for text/ass as well once they are rendered
*/
AVPicture pict;
enum AVSubtitleType type;
@@ -3138,10 +3496,11 @@ typedef struct AVSubtitleRect {
/**
* 0 terminated ASS/SSA compatible event line.
- * The pressentation of this is unaffected by the other values in this
+ * The presentation of this is unaffected by the other values in this
* struct.
*/
char *ass;
+
int flags;
} AVSubtitleRect;
@@ -3240,13 +3599,29 @@ int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec);
const AVClass *avcodec_get_class(void);
/**
+ * Get the AVClass for AVFrame. It can be used in combination with
+ * AV_OPT_SEARCH_FAKE_OBJ for examining options.
+ *
+ * @see av_opt_find().
+ */
+const AVClass *avcodec_get_frame_class(void);
+
+/**
+ * Get the AVClass for AVSubtitleRect. It can be used in combination with
+ * AV_OPT_SEARCH_FAKE_OBJ for examining options.
+ *
+ * @see av_opt_find().
+ */
+const AVClass *avcodec_get_subtitle_rect_class(void);
+
+/**
* Copy the settings of the source AVCodecContext into the destination
* AVCodecContext. The resulting destination codec context will be
* unopened, i.e. you are required to call avcodec_open2() before you
* can use this AVCodecContext to decode/encode video/audio data.
*
* @param dest target codec context, should be initialized with
- * avcodec_alloc_context3(), but otherwise uninitialized
+ * avcodec_alloc_context3(NULL), but otherwise uninitialized
* @param src source codec context
* @return AVERROR() on error (e.g. memory allocation error), 0 on success
*/
@@ -3420,6 +3795,20 @@ int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size);
int av_dup_packet(AVPacket *pkt);
/**
+ * Copy packet, including contents
+ *
+ * @return 0 on success, negative AVERROR on fail
+ */
+int av_copy_packet(AVPacket *dst, const AVPacket *src);
+
+/**
+ * Copy packet side data
+ *
+ * @return 0 on success, negative AVERROR on fail
+ */
+int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src);
+
+/**
* Free a packet.
*
* @param pkt packet to free
@@ -3459,6 +3848,31 @@ int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int *size);
+int av_packet_merge_side_data(AVPacket *pkt);
+
+int av_packet_split_side_data(AVPacket *pkt);
+
+const char *av_packet_side_data_name(enum AVPacketSideDataType type);
+
+/**
+ * Pack a dictionary for use in side_data.
+ *
+ * @param dict The dictionary to pack.
+ * @param size pointer to store the size of the returned data
+ * @return pointer to data if successful, NULL otherwise
+ */
+uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size);
+/**
+ * Unpack a dictionary from side_data.
+ *
+ * @param data data from side_data
+ * @param size size of the data
+ * @param dict the metadata storage dictionary
+ * @return 0 on success, < 0 on failure
+ */
+int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict);
+
+
/**
* Convenience function to free all the side data stored.
* All the other fields stay untouched.
@@ -3483,7 +3897,7 @@ void av_packet_free_side_data(AVPacket *pkt);
*
* @return 0 on success, a negative AVERROR on error.
*/
-int av_packet_ref(AVPacket *dst, AVPacket *src);
+int av_packet_ref(AVPacket *dst, const AVPacket *src);
/**
* Wipe the packet.
@@ -3605,6 +4019,88 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
int linesize_align[AV_NUM_DATA_POINTERS]);
/**
+ * Converts AVChromaLocation to swscale x/y chroma position.
+ *
+ * The positions represent the chroma (0,0) position in a coordinates system
+ * with luma (0,0) representing the origin and luma(1,1) representing 256,256
+ *
+ * @param xpos horizontal chroma sample position
+ * @param ypos vertical chroma sample position
+ */
+int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos);
+
+/**
+ * Converts swscale x/y chroma position to AVChromaLocation.
+ *
+ * The positions represent the chroma (0,0) position in a coordinates system
+ * with luma (0,0) representing the origin and luma(1,1) representing 256,256
+ *
+ * @param xpos horizontal chroma sample position
+ * @param ypos vertical chroma sample position
+ */
+enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos);
+
+#if FF_API_OLD_DECODE_AUDIO
+/**
+ * Wrapper function which calls avcodec_decode_audio4.
+ *
+ * @deprecated Use avcodec_decode_audio4 instead.
+ *
+ * Decode the audio frame of size avpkt->size from avpkt->data into samples.
+ * Some decoders may support multiple frames in a single AVPacket, such
+ * decoders would then just decode the first frame. In this case,
+ * avcodec_decode_audio3 has to be called again with an AVPacket that contains
+ * the remaining data in order to decode the second frame etc.
+ * If no frame
+ * could be outputted, frame_size_ptr is zero. Otherwise, it is the
+ * decompressed frame size in bytes.
+ *
+ * @warning You must set frame_size_ptr to the allocated size of the
+ * output buffer before calling avcodec_decode_audio3().
+ *
+ * @warning The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than
+ * the actual read bytes because some optimized bitstream readers read 32 or 64
+ * bits at once and could read over the end.
+ *
+ * @warning The end of the input buffer avpkt->data should be set to 0 to ensure that
+ * no overreading happens for damaged MPEG streams.
+ *
+ * @warning You must not provide a custom get_buffer() when using
+ * avcodec_decode_audio3(). Doing so will override it with
+ * avcodec_default_get_buffer. Use avcodec_decode_audio4() instead,
+ * which does allow the application to provide a custom get_buffer().
+ *
+ * @note You might have to align the input buffer avpkt->data and output buffer
+ * samples. The alignment requirements depend on the CPU: On some CPUs it isn't
+ * necessary at all, on others it won't work at all if not aligned and on others
+ * it will work but it will have an impact on performance.
+ *
+ * In practice, avpkt->data should have 4 byte alignment at minimum and
+ * samples should be 16 byte aligned unless the CPU doesn't need it
+ * (AltiVec and SSE do).
+ *
+ * @note Codecs which have the CODEC_CAP_DELAY capability set have a delay
+ * between input and output, these need to be fed with avpkt->data=NULL,
+ * avpkt->size=0 at the end to return the remaining frames.
+ *
+ * @param avctx the codec context
+ * @param[out] samples the output buffer, sample type in avctx->sample_fmt
+ * If the sample format is planar, each channel plane will
+ * be the same size, with no padding between channels.
+ * @param[in,out] frame_size_ptr the output buffer size in bytes
+ * @param[in] avpkt The input AVPacket containing the input buffer.
+ * You can create such packet with av_init_packet() and by then setting
+ * data and size, some decoders might in addition need other fields.
+ * All decoders are designed to use the least fields possible though.
+ * @return On error a negative value is returned, otherwise the number of bytes
+ * used or zero if no frame data was decompressed (used) from the input AVPacket.
+ */
+attribute_deprecated int avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
+ int *frame_size_ptr,
+ AVPacket *avpkt);
+#endif
+
+/**
* Decode the audio frame of size avpkt->size from avpkt->data into frame.
*
* Some decoders may support multiple frames in a single AVPacket. Such
@@ -3656,7 +4152,7 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
* AVPacket is returned.
*/
int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
- int *got_frame_ptr, AVPacket *avpkt);
+ int *got_frame_ptr, const AVPacket *avpkt);
/**
* Decode the video frame of size avpkt->size from avpkt->data into picture.
@@ -3692,7 +4188,7 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
* next call to this function or until closing or flushing the
* decoder. The caller may not write to it.
*
- * @param[in] avpkt The input AVpacket containing the input buffer.
+ * @param[in] avpkt The input AVPacket containing the input buffer.
* You can create such packet with av_init_packet() and by then setting
* data and size, some decoders might in addition need other fields like
* flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least
@@ -3703,7 +4199,7 @@ int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame,
*/
int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
- AVPacket *avpkt);
+ const AVPacket *avpkt);
/**
* Decode a subtitle message.
@@ -3715,12 +4211,20 @@ int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
* and reusing a get_buffer written for video codecs would probably perform badly
* due to a potentially very different allocation pattern.
*
+ * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input
+ * and output. This means that for some packets they will not immediately
+ * produce decoded output and need to be flushed at the end of decoding to get
+ * all the decoded data. Flushing is done by calling this function with packets
+ * with avpkt->data set to NULL and avpkt->size set to 0 until it stops
+ * returning subtitles. It is safe to flush even those decoders that are not
+ * marked with CODEC_CAP_DELAY, then no subtitles will be returned.
+ *
* @note The AVCodecContext MUST have been opened with @ref avcodec_open2()
* before packets may be fed to the decoder.
*
* @param avctx the codec context
- * @param[out] sub The AVSubtitle in which the decoded subtitle will be stored, must be
- freed with avsubtitle_free if *got_sub_ptr is set.
+ * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored,
+ * must be freed with avsubtitle_free if *got_sub_ptr is set.
* @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero.
* @param[in] avpkt The input AVPacket containing the input buffer.
*/
@@ -3778,6 +4282,7 @@ typedef struct AVCodecParserContext {
#define PARSER_FLAG_ONCE 0x0002
/// Set if the parser has a valid file offset
#define PARSER_FLAG_FETCHED_OFFSET 0x0004
+#define PARSER_FLAG_USE_CODEC_TS 0x1000
int64_t offset; ///< byte offset from starting packet start
int64_t cur_frame_end[AV_PARSER_PTS_NB];
@@ -3974,7 +4479,7 @@ int av_parser_parse2(AVCodecParserContext *s,
/**
* @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed
- * @deprecated use AVBitstreamFilter
+ * @deprecated use AVBitStreamFilter
*/
int av_parser_change(AVCodecParserContext *s,
AVCodecContext *avctx,
@@ -4008,6 +4513,36 @@ AVCodec *avcodec_find_encoder(enum AVCodecID id);
*/
AVCodec *avcodec_find_encoder_by_name(const char *name);
+#if FF_API_OLD_ENCODE_AUDIO
+/**
+ * Encode an audio frame from samples into buf.
+ *
+ * @deprecated Use avcodec_encode_audio2 instead.
+ *
+ * @note The output buffer should be at least FF_MIN_BUFFER_SIZE bytes large.
+ * However, for codecs with avctx->frame_size equal to 0 (e.g. PCM) the user
+ * will know how much space is needed because it depends on the value passed
+ * in buf_size as described below. In that case a lower value can be used.
+ *
+ * @param avctx the codec context
+ * @param[out] buf the output buffer
+ * @param[in] buf_size the output buffer size
+ * @param[in] samples the input buffer containing the samples
+ * The number of samples read from this buffer is frame_size*channels,
+ * both of which are defined in avctx.
+ * For codecs which have avctx->frame_size equal to 0 (e.g. PCM) the number of
+ * samples read from samples is equal to:
+ * buf_size * 8 / (avctx->channels * av_get_bits_per_sample(avctx->codec_id))
+ * This also implies that av_get_bits_per_sample() must not return 0 for these
+ * codecs.
+ * @return On error a negative value is returned, on success zero or the number
+ * of bytes used to encode the data read from the input buffer.
+ */
+int attribute_deprecated avcodec_encode_audio(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size,
+ const short *samples);
+#endif
+
/**
* Encode a frame of audio.
*
@@ -4021,11 +4556,12 @@ AVCodec *avcodec_find_encoder_by_name(const char *name);
* The user can supply an output buffer by setting
* avpkt->data and avpkt->size prior to calling the
* function, but if the size of the user-provided data is not
- * large enough, encoding will fail. All other AVPacket fields
- * will be reset by the encoder using av_init_packet(). If
- * avpkt->data is NULL, the encoder will allocate it.
- * The encoder will set avpkt->size to the size of the
- * output packet.
+ * large enough, encoding will fail. If avpkt->data and
+ * avpkt->size are set, avpkt->destruct must also be set. All
+ * other AVPacket fields will be reset by the encoder using
+ * av_init_packet(). If avpkt->data is NULL, the encoder will
+ * allocate it. The encoder will set avpkt->size to the size
+ * of the output packet.
*
* If this function fails or produces no output, avpkt will be
* freed using av_free_packet() (i.e. avpkt->destruct will be
@@ -4049,6 +4585,26 @@ AVCodec *avcodec_find_encoder_by_name(const char *name);
int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr);
+#if FF_API_OLD_ENCODE_VIDEO
+/**
+ * @deprecated use avcodec_encode_video2() instead.
+ *
+ * Encode a video frame from pict into buf.
+ * The input picture should be
+ * stored using a specific format, namely avctx.pix_fmt.
+ *
+ * @param avctx the codec context
+ * @param[out] buf the output buffer for the bitstream of encoded frame
+ * @param[in] buf_size the size of the output buffer in bytes
+ * @param[in] pict the input picture to encode
+ * @return On error a negative value is returned, on success zero or the number
+ * of bytes used from the output buffer.
+ */
+attribute_deprecated
+int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
+ const AVFrame *pict);
+#endif
+
/**
* Encode a frame of video.
*
@@ -4094,21 +4650,121 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
* @}
*/
+#if FF_API_AVCODEC_RESAMPLE
+/**
+ * @defgroup lavc_resample Audio resampling
+ * @ingroup libavc
+ * @deprecated use libswresample instead
+ *
+ * @{
+ */
+struct ReSampleContext;
+struct AVResampleContext;
+
+typedef struct ReSampleContext ReSampleContext;
+
+/**
+ * Initialize audio resampling context.
+ *
+ * @param output_channels number of output channels
+ * @param input_channels number of input channels
+ * @param output_rate output sample rate
+ * @param input_rate input sample rate
+ * @param sample_fmt_out requested output sample format
+ * @param sample_fmt_in input sample format
+ * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency
+ * @param log2_phase_count log2 of the number of entries in the polyphase filterbank
+ * @param linear if 1 then the used FIR filter will be linearly interpolated
+ between the 2 closest, if 0 the closest will be used
+ * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate
+ * @return allocated ReSampleContext, NULL if error occurred
+ */
+attribute_deprecated
+ReSampleContext *av_audio_resample_init(int output_channels, int input_channels,
+ int output_rate, int input_rate,
+ enum AVSampleFormat sample_fmt_out,
+ enum AVSampleFormat sample_fmt_in,
+ int filter_length, int log2_phase_count,
+ int linear, double cutoff);
+
+attribute_deprecated
+int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples);
+
+/**
+ * Free resample context.
+ *
+ * @param s a non-NULL pointer to a resample context previously
+ * created with av_audio_resample_init()
+ */
+attribute_deprecated
+void audio_resample_close(ReSampleContext *s);
+
+
+/**
+ * Initialize an audio resampler.
+ * Note, if either rate is not an integer then simply scale both rates up so they are.
+ * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq
+ * @param log2_phase_count log2 of the number of entries in the polyphase filterbank
+ * @param linear If 1 then the used FIR filter will be linearly interpolated
+ between the 2 closest, if 0 the closest will be used
+ * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate
+ */
+attribute_deprecated
+struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff);
+
+/**
+ * Resample an array of samples using a previously configured context.
+ * @param src an array of unconsumed samples
+ * @param consumed the number of samples of src which have been consumed are returned here
+ * @param src_size the number of unconsumed samples available
+ * @param dst_size the amount of space in samples available in dst
+ * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context.
+ * @return the number of samples written in dst or -1 if an error occurred
+ */
+attribute_deprecated
+int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx);
+
+
+/**
+ * Compensate samplerate/timestamp drift. The compensation is done by changing
+ * the resampler parameters, so no audible clicks or similar distortions occur
+ * @param compensation_distance distance in output samples over which the compensation should be performed
+ * @param sample_delta number of output samples which should be output less
+ *
+ * example: av_resample_compensate(c, 10, 500)
+ * here instead of 510 samples only 500 samples would be output
+ *
+ * note, due to rounding the actual compensation might be slightly different,
+ * especially if the compensation_distance is large and the in_rate used during init is small
+ */
+attribute_deprecated
+void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance);
+attribute_deprecated
+void av_resample_close(struct AVResampleContext *c);
+
+/**
+ * @}
+ */
+#endif
+
/**
* @addtogroup lavc_picture
* @{
*/
/**
- * Allocate memory for a picture. Call avpicture_free() to free it.
+ * Allocate memory for the pixels of a picture and setup the AVPicture
+ * fields for it.
*
- * @see avpicture_fill()
+ * Call avpicture_free() to free it.
*
- * @param picture the picture to be filled in
- * @param pix_fmt the format of the picture
- * @param width the width of the picture
- * @param height the height of the picture
- * @return zero if successful, a negative value if not
+ * @param picture the picture structure to be filled in
+ * @param pix_fmt the pixel format of the picture
+ * @param width the width of the picture
+ * @param height the height of the picture
+ * @return zero if successful, a negative error code otherwise
+ *
+ * @see av_image_alloc(), avpicture_fill()
*/
int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height);
@@ -4122,27 +4778,62 @@ int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, i
void avpicture_free(AVPicture *picture);
/**
- * Fill in the AVPicture fields, always assume a linesize alignment of 1.
+ * Setup the picture fields based on the specified image parameters
+ * and the provided image data buffer.
+ *
+ * The picture fields are filled in by using the image data buffer
+ * pointed to by ptr.
+ *
+ * If ptr is NULL, the function will fill only the picture linesize
+ * array and return the required size for the image buffer.
+ *
+ * To allocate an image buffer and fill the picture data in one call,
+ * use avpicture_alloc().
+ *
+ * @param picture the picture to be filled in
+ * @param ptr buffer where the image data is stored, or NULL
+ * @param pix_fmt the pixel format of the image
+ * @param width the width of the image in pixels
+ * @param height the height of the image in pixels
+ * @return the size in bytes required for src, a negative error code
+ * in case of failure
*
- * @see av_image_fill_arrays().
+ * @see av_image_fill_arrays()
*/
-int avpicture_fill(AVPicture *picture, uint8_t *ptr,
+int avpicture_fill(AVPicture *picture, const uint8_t *ptr,
enum AVPixelFormat pix_fmt, int width, int height);
/**
- * Copy pixel data from an AVPicture into a buffer, always assume a
- * linesize alignment of 1.
+ * Copy pixel data from an AVPicture into a buffer.
*
- * @see av_image_copy_to_buffer().
+ * avpicture_get_size() can be used to compute the required size for
+ * the buffer to fill.
+ *
+ * @param src source picture with filled data
+ * @param pix_fmt picture pixel format
+ * @param width picture width
+ * @param height picture height
+ * @param dest destination buffer
+ * @param dest_size destination buffer size in bytes
+ * @return the number of bytes written to dest, or a negative value
+ * (error code) on error, for example if the destination buffer is not
+ * big enough
+ *
+ * @see av_image_copy_to_buffer()
*/
-int avpicture_layout(const AVPicture* src, enum AVPixelFormat pix_fmt,
+int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt,
int width, int height,
unsigned char *dest, int dest_size);
/**
* Calculate the size in bytes that a picture of the given width and height
* would occupy if stored in the given picture format.
- * Always assume a linesize alignment of 1.
+ *
+ * @param pix_fmt picture pixel format
+ * @param width picture width
+ * @param height picture height
+ * @return the computed picture buffer size or a negative error code
+ * in case of error
*
* @see av_image_get_buffer_size().
*/
@@ -4159,7 +4850,7 @@ int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
enum AVPixelFormat pix_fmt, int width, int height);
#endif
/**
- * Copy image src to dst. Wraps av_picture_data_copy() above.
+ * Copy image src to dst. Wraps av_image_copy().
*/
void av_picture_copy(AVPicture *dst, const AVPicture *src,
enum AVPixelFormat pix_fmt, int width, int height);
@@ -4197,10 +4888,21 @@ int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width,
*/
/**
- * @deprecated Use av_pix_fmt_get_chroma_sub_sample
+ * Utility function to access log2_chroma_w log2_chroma_h from
+ * the pixel format AVPixFmtDescriptor.
+ *
+ * This function asserts that pix_fmt is valid. See av_pix_fmt_get_chroma_sub_sample
+ * for one that returns a failure code and continues in case of invalid
+ * pix_fmts.
+ *
+ * @param[in] pix_fmt the pixel format
+ * @param[out] h_shift store log2_chroma_w
+ * @param[out] v_shift store log2_chroma_h
+ *
+ * @see av_pix_fmt_get_chroma_sub_sample
*/
-void attribute_deprecated avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift);
+void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift);
/**
* Return a value representing the fourCC code associated to the
@@ -4209,29 +4911,8 @@ void attribute_deprecated avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_f
*/
unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt);
-#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */
-#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */
-#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */
-#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */
-#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */
-#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */
-
-/**
- * Compute what kind of losses will occur when converting from one specific
- * pixel format to another.
- * When converting from one pixel format to another, information loss may occur.
- * For example, when converting from RGB24 to GRAY, the color information will
- * be lost. Similarly, other losses occur when converting from some formats to
- * other formats. These losses can involve loss of chroma, but also loss of
- * resolution, loss of color depth, loss due to the color space conversion, loss
- * of the alpha bits or loss due to color quantization.
- * avcodec_get_fix_fmt_loss() informs you about the various types of losses
- * which will occur when converting from one pixel format to another.
- *
- * @param[in] dst_pix_fmt destination pixel format
- * @param[in] src_pix_fmt source pixel format
- * @param[in] has_alpha Whether the source pixel format alpha channel is used.
- * @return Combination of flags informing you what kind of losses will occur.
+/**
+ * @deprecated see av_get_pix_fmt_loss()
*/
int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt,
int has_alpha);
@@ -4241,7 +4922,7 @@ int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat
* format. When converting from one pixel format to another, information loss
* may occur. For example, when converting from RGB24 to GRAY, the color
* information will be lost. Similarly, other losses occur when converting from
- * some formats to other formats. avcodec_find_best_pix_fmt2() searches which of
+ * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of
* the given pixel formats should be used to suffer the least amount of loss.
* The pixel formats from which it chooses one, are determined by the
* pix_fmt_list parameter.
@@ -4253,9 +4934,26 @@ int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat
* @param[out] loss_ptr Combination of flags informing you what kind of losses will occur.
* @return The best pixel format to convert to or -1 if none was found.
*/
-enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat *pix_fmt_list,
+enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list,
+ enum AVPixelFormat src_pix_fmt,
+ int has_alpha, int *loss_ptr);
+
+/**
+ * @deprecated see av_find_best_pix_fmt_of_2()
+ */
+enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
+ enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr);
+
+attribute_deprecated
+#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
+enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list,
enum AVPixelFormat src_pix_fmt,
int has_alpha, int *loss_ptr);
+#else
+enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
+ enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr);
+#endif
+
enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
@@ -4298,7 +4996,12 @@ int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2,
//FIXME func typedef
/**
- * Fill audio frame data and linesize.
+ * Fill AVFrame audio data and linesize pointers.
+ *
+ * The buffer buf must be a preallocated buffer with a size big enough
+ * to contain the specified samples amount. The filled AVFrame data
+ * pointers will point to this buffer.
+ *
* AVFrame extended_data channel pointers are allocated if necessary for
* planar audio.
*
@@ -4311,7 +5014,9 @@ int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2,
* @param buf buffer to use for frame data
* @param buf_size size of buffer
* @param align plane size sample alignment (0 = default)
- * @return 0 on success, negative error code on failure
+ * @return >=0 on success, negative error code on failure
+ * @todo return the size in bytes required to store the samples in
+ * case of success, at the next libavutil bump
*/
int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
enum AVSampleFormat sample_fmt, const uint8_t *buf,
@@ -4337,6 +5042,14 @@ void avcodec_flush_buffers(AVCodecContext *avctx);
int av_get_bits_per_sample(enum AVCodecID codec_id);
/**
+ * Return the PCM codec associated with a sample format.
+ * @param be endianness, 0 for little, 1 for big,
+ * -1 (or anything else) for native
+ * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE
+ */
+enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be);
+
+/**
* Return codec bits per sample.
* Only return non-zero if the bits per sample is exactly correct, not an
* approximation.
@@ -4376,28 +5089,98 @@ typedef struct AVBitStreamFilter {
struct AVBitStreamFilter *next;
} AVBitStreamFilter;
+/**
+ * Register a bitstream filter.
+ *
+ * The filter will be accessible to the application code through
+ * av_bitstream_filter_next() or can be directly initialized with
+ * av_bitstream_filter_init().
+ *
+ * @see avcodec_register_all()
+ */
void av_register_bitstream_filter(AVBitStreamFilter *bsf);
+
+/**
+ * Create and initialize a bitstream filter context given a bitstream
+ * filter name.
+ *
+ * The returned context must be freed with av_bitstream_filter_close().
+ *
+ * @param name the name of the bitstream filter
+ * @return a bitstream filter context if a matching filter was found
+ * and successfully initialized, NULL otherwise
+ */
AVBitStreamFilterContext *av_bitstream_filter_init(const char *name);
+
+/**
+ * Filter bitstream.
+ *
+ * This function filters the buffer buf with size buf_size, and places the
+ * filtered buffer in the buffer pointed to by poutbuf.
+ *
+ * The output buffer must be freed by the caller.
+ *
+ * @param bsfc bitstream filter context created by av_bitstream_filter_init()
+ * @param avctx AVCodecContext accessed by the filter, may be NULL.
+ * If specified, this must point to the encoder context of the
+ * output stream the packet is sent to.
+ * @param args arguments which specify the filter configuration, may be NULL
+ * @param poutbuf pointer which is updated to point to the filtered buffer
+ * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes
+ * @param buf buffer containing the data to filter
+ * @param buf_size size in bytes of buf
+ * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data
+ * @return >= 0 in case of success, or a negative error code in case of failure
+ *
+ * If the return value is positive, an output buffer is allocated and
+ * is available in *poutbuf, and is distinct from the input buffer.
+ *
+ * If the return value is 0, the output buffer is not allocated and
+ * should be considered identical to the input buffer, or in case
+ * *poutbuf was set it points to the input buffer (not necessarily to
+ * its starting address).
+ */
int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe);
+
+/**
+ * Release bitstream filter context.
+ *
+ * @param bsf the bitstream filter context created with
+ * av_bitstream_filter_init(), can be NULL
+ */
void av_bitstream_filter_close(AVBitStreamFilterContext *bsf);
+/**
+ * If f is NULL, return the first registered bitstream filter,
+ * if f is non-NULL, return the next registered bitstream filter
+ * after f, or NULL if f is the last one.
+ *
+ * This function can be used to iterate over all registered bitstream
+ * filters.
+ */
AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f);
/* memory */
/**
- * Allocate a buffer with padding, reusing the given one if large enough.
- *
* Same behaviour av_fast_malloc but the buffer has additional
- * FF_INPUT_PADDING_SIZE at the end which will always memset to 0.
+ * FF_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0.
*
+ * In addition the whole buffer will initially and after resizes
+ * be 0-initialized so that no uninitialized data will ever appear.
*/
void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size);
/**
+ * Same behaviour av_fast_padded_malloc except that buffer will always
+ * be 0-initialized after call.
+ */
+void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size);
+
+/**
* Encode extradata length to a buffer. Used by xiph codecs.
*
* @param s buffer to write to; must be at least (v/255+1) bytes long
@@ -4409,7 +5192,7 @@ unsigned int av_xiphlacing(unsigned char *s, unsigned int v);
#if FF_API_MISSING_SAMPLE
/**
* Log a generic warning message about a missing feature. This function is
- * intended to be used internally by Libav (libavcodec, libavformat, etc.)
+ * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.)
* only, and would normally not be used by applications.
* @param[in] avc a pointer to an arbitrary struct of which the first field is
* a pointer to an AVClass struct
@@ -4425,7 +5208,7 @@ void av_log_missing_feature(void *avc, const char *feature, int want_sample);
/**
* Log a generic warning message asking for a sample. This function is
- * intended to be used internally by Libav (libavcodec, libavformat, etc.)
+ * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.)
* only, and would normally not be used by applications.
* @param[in] avc a pointer to an arbitrary struct of which the first field is
* a pointer to an AVClass struct
@@ -4490,6 +5273,12 @@ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op));
enum AVMediaType avcodec_get_type(enum AVCodecID codec_id);
/**
+ * Get the name of a codec.
+ * @return a static string identifying the codec; never NULL
+ */
+const char *avcodec_get_name(enum AVCodecID id);
+
+/**
* @return a positive value if s is open (i.e. avcodec_open2() was called on it
* with no corresponding avcodec_close()), 0 otherwise.
*/
diff --git a/libavcodec/avcodecres.rc b/libavcodec/avcodecres.rc
new file mode 100644
index 0000000000..4b69686177
--- /dev/null
+++ b/libavcodec/avcodecres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libavcodec
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libavcodec/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO, 0
+PRODUCTVERSION LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg codec library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBAVCODEC_VERSION)
+ VALUE "InternalName", "libavcodec"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "avcodec" BUILDSUF "-" AV_STRINGIFY(LIBAVCODEC_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libavcodec/avdct.c b/libavcodec/avdct.c
new file mode 100644
index 0000000000..f92c691adb
--- /dev/null
+++ b/libavcodec/avdct.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "idctdsp.h"
+#include "fdctdsp.h"
+#include "pixblockdsp.h"
+#include "avdct.h"
+
+#define OFFSET(x) offsetof(AVDCT,x)
+#define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C
+//these names are too long to be readable
+#define V AV_OPT_FLAG_VIDEO_PARAM
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+#define D AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption avdct_options[] = {
+{"dct", "DCT algorithm", OFFSET(dct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E, "dct"},
+{"auto", "autoselect a good one (default)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_AUTO }, INT_MIN, INT_MAX, V|E, "dct"},
+{"fastint", "fast integer (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FASTINT }, INT_MIN, INT_MAX, V|E, "dct"},
+{"int", "accurate integer", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_INT }, INT_MIN, INT_MAX, V|E, "dct"},
+{"mmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_MMX }, INT_MIN, INT_MAX, V|E, "dct"},
+{"altivec", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_ALTIVEC }, INT_MIN, INT_MAX, V|E, "dct"},
+{"faan", "floating point AAN DCT (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FAAN }, INT_MIN, INT_MAX, V|E, "dct"},
+
+{"idct", "select IDCT implementation", OFFSET(idct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E|D, "idct"},
+{"auto", "autoselect a good one (default)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_AUTO }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"int", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_INT }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"simple", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLE }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"simplemmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEMMX }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"arm", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ARM }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"altivec", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ALTIVEC }, INT_MIN, INT_MAX, V|E|D, "idct"},
+#if FF_API_ARCH_SH4
+{"sh4", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SH4 }, INT_MIN, INT_MAX, V|E|D, "idct"},
+#endif
+{"simplearm", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARM }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"simplearmv5te", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV5TE }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"simplearmv6", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV6 }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"simpleneon", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLENEON }, INT_MIN, INT_MAX, V|E|D, "idct"},
+#if FF_API_ARCH_ALPHA
+{"simplealpha", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEALPHA }, INT_MIN, INT_MAX, V|E|D, "idct"},
+#endif
+{"ipp", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_IPP }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"xvid", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"xvidmmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"},
+{"faani", "floating point AAN IDCT (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_FAAN }, INT_MIN, INT_MAX, V|D|E, "idct"},
+{"simpleauto", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEAUTO }, INT_MIN, INT_MAX, V|E|D, "idct"},
+
+{"bits_per_sample", "", OFFSET(bits_per_sample), AV_OPT_TYPE_INT, {.i64 = 8 }, 0, 14, 0,},
+{NULL},
+};
+
+static const AVClass avdct_class = {
+ .class_name = "AVDCT",
+ .option = avdct_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const AVClass *avcodec_dct_get_class(void)
+{
+ return &avdct_class;
+}
+
+AVDCT *avcodec_dct_alloc(void)
+{
+ AVDCT *dsp = av_mallocz(sizeof(AVDCT));
+
+ if (!dsp)
+ return NULL;
+
+ dsp->av_class = &avdct_class;
+ av_opt_set_defaults(dsp);
+
+ return dsp;
+}
+
+int avcodec_dct_init(AVDCT *dsp)
+{
+ AVCodecContext *avctx = avcodec_alloc_context3(NULL);
+
+ if (!avctx)
+ return AVERROR(ENOMEM);
+
+ avctx->idct_algo = dsp->idct_algo;
+ avctx->dct_algo = dsp->dct_algo;
+ avctx->bits_per_raw_sample = dsp->bits_per_sample;
+
+#define COPY(src, name) memcpy(&dsp->name, &src.name, sizeof(dsp->name))
+
+#if CONFIG_IDCTDSP
+ {
+ IDCTDSPContext idsp;
+ ff_idctdsp_init(&idsp, avctx);
+ COPY(idsp, idct);
+ COPY(idsp, idct_permutation);
+ }
+#endif
+
+#if CONFIG_FDCTDSP
+ {
+ FDCTDSPContext fdsp;
+ ff_fdctdsp_init(&fdsp, avctx);
+ COPY(fdsp, fdct);
+ }
+#endif
+
+#if CONFIG_PIXBLOCKDSP
+ {
+ PixblockDSPContext pdsp;
+ ff_pixblockdsp_init(&pdsp, avctx);
+ COPY(pdsp, get_pixels);
+ }
+#endif
+
+ avcodec_close(avctx);
+ av_free(avctx);
+
+ return 0;
+}
diff --git a/libavcodec/avdct.h b/libavcodec/avdct.h
new file mode 100644
index 0000000000..272422e44c
--- /dev/null
+++ b/libavcodec/avdct.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_AVDCT_H
+#define AVCODEC_AVDCT_H
+
+#include "libavutil/opt.h"
+
+/**
+ * AVDCT context.
+ * @note function pointers can be NULL if the specific features have been
+ * disabled at build time.
+ */
+typedef struct AVDCT {
+ const AVClass *av_class;
+
+ void (*idct)(int16_t *block /* align 16 */);
+
+ /**
+ * IDCT input permutation.
+ * Several optimized IDCTs need a permutated input (relative to the
+ * normal order of the reference IDCT).
+ * This permutation must be performed before the idct_put/add.
+ * Note, normally this can be merged with the zigzag/alternate scan<br>
+ * An example to avoid confusion:
+ * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...)
+ * - (x -> reference DCT -> reference IDCT -> x)
+ * - (x -> reference DCT -> simple_mmx_perm = idct_permutation
+ * -> simple_idct_mmx -> x)
+ * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant
+ * -> simple_idct_mmx -> ...)
+ */
+ uint8_t idct_permutation[64];
+
+ void (*fdct)(int16_t *block /* align 16 */);
+
+
+ /**
+ * DCT algorithm.
+ * must use AVOptions to set this field.
+ */
+ int dct_algo;
+
+ /**
+ * IDCT algorithm.
+ * must use AVOptions to set this field.
+ */
+ int idct_algo;
+
+ void (*get_pixels)(int16_t *block /* align 16 */,
+ const uint8_t *pixels /* align 8 */,
+ ptrdiff_t line_size);
+
+ int bits_per_sample;
+} AVDCT;
+
+/**
+ * Allocates a AVDCT context.
+ * This needs to be initialized with avcodec_dct_init() after optionally
+ * configuring it with AVOptions.
+ *
+ * To free it use av_free()
+ */
+AVDCT *avcodec_dct_alloc(void);
+int avcodec_dct_init(AVDCT *);
+
+const AVClass *avcodec_dct_get_class(void);
+
+#endif /* AVCODEC_AVDCT_H */
diff --git a/libavcodec/avfft.c b/libavcodec/avfft.c
index 513f57e5f4..675d2b906b 100644
--- a/libavcodec/avfft.c
+++ b/libavcodec/avfft.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
FFTContext *av_fft_init(int nbits, int inverse)
{
- FFTContext *s = av_malloc(sizeof(*s));
+ FFTContext *s = av_mallocz(sizeof(*s));
if (s && ff_fft_init(s, nbits, inverse))
av_freep(&s);
@@ -142,4 +142,38 @@ av_cold void av_dct_end(DCTContext *s)
}
}
+#ifdef TEST
+int main(int argc, char **argv)
+{
+ int i;
+#define LEN 1024
+ FFTSample *ref = av_malloc_array(LEN, sizeof(*ref));
+ FFTSample *data = av_malloc_array(LEN, sizeof(*data));
+ RDFTContext *rdft_context = av_rdft_init(10, DFT_R2C);
+ RDFTContext *irdft_context = av_rdft_init(10, IDFT_C2R);
+
+ if (!ref || !data || !rdft_context || !irdft_context)
+ return 2;
+ for (i=0; i<LEN; i++) {
+ ref[i] = data[i] = i*456 + 123 + i*i;
+ }
+ av_rdft_calc(rdft_context, data);
+ av_rdft_calc(irdft_context, data);
+
+ for (i=0; i<LEN; i++) {
+ if (fabs(ref[i] - data[i]/LEN*2) > 1) {
+ fprintf(stderr, "Failed at %d (%f %f)\n", i, ref[i], data[i]/LEN*2);
+ return 1;
+ }
+ }
+
+ av_rdft_end(rdft_context);
+ av_rdft_end(irdft_context);
+ av_free(data);
+ av_free(ref);
+
+ return 0;
+}
+#endif
+
#endif /* CONFIG_DCT */
diff --git a/libavcodec/avfft.h b/libavcodec/avfft.h
index e2e727da9e..0c0f9b8d8d 100644
--- a/libavcodec/avfft.h
+++ b/libavcodec/avfft.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index 557258d839..aae67c5a00 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -2,20 +2,20 @@
* AVPacket functions for libavcodec
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,12 +27,14 @@
#include "libavutil/mathematics.h"
#include "libavutil/mem.h"
#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
#if FF_API_DESTRUCT_PACKET
void av_destruct_packet(AVPacket *pkt)
{
- av_free(pkt->data);
- pkt->data = NULL;
+ av_freep(&pkt->data);
pkt->size = 0;
}
@@ -187,43 +189,55 @@ do { \
dst = data; \
} while (0)
-int av_dup_packet(AVPacket *pkt)
+/* Makes duplicates of data, side_data, but does not copy any other fields */
+static int copy_packet_data(AVPacket *pkt, const AVPacket *src, int dup)
{
- AVPacket tmp_pkt;
-
-FF_DISABLE_DEPRECATION_WARNINGS
- if (!pkt->buf && pkt->data
-#if FF_API_DESTRUCT_PACKET
- && !pkt->destruct
-#endif
- ) {
-FF_ENABLE_DEPRECATION_WARNINGS
- tmp_pkt = *pkt;
-
- pkt->data = NULL;
- pkt->side_data = NULL;
- DUP_DATA(pkt->data, tmp_pkt.data, pkt->size, 1, ALLOC_BUF);
+ pkt->data = NULL;
+ pkt->side_data = NULL;
+ if (pkt->buf) {
+ AVBufferRef *ref = av_buffer_ref(src->buf);
+ if (!ref)
+ return AVERROR(ENOMEM);
+ pkt->buf = ref;
+ pkt->data = ref->data;
+ } else {
+ DUP_DATA(pkt->data, src->data, pkt->size, 1, ALLOC_BUF);
+ }
#if FF_API_DESTRUCT_PACKET
FF_DISABLE_DEPRECATION_WARNINGS
- pkt->destruct = dummy_destruct_packet;
+ pkt->destruct = dummy_destruct_packet;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
+ if (pkt->side_data_elems && dup)
+ pkt->side_data = src->side_data;
+ if (pkt->side_data_elems && !dup) {
+ return av_copy_packet_side_data(pkt, src);
+ }
+ return 0;
- if (pkt->side_data_elems) {
- int i;
+failed_alloc:
+ av_free_packet(pkt);
+ return AVERROR(ENOMEM);
+}
- DUP_DATA(pkt->side_data, tmp_pkt.side_data,
- pkt->side_data_elems * sizeof(*pkt->side_data), 0, ALLOC_MALLOC);
+int av_copy_packet_side_data(AVPacket *pkt, const AVPacket *src)
+{
+ if (src->side_data_elems) {
+ int i;
+ DUP_DATA(pkt->side_data, src->side_data,
+ src->side_data_elems * sizeof(*src->side_data), 0, ALLOC_MALLOC);
+ if (src != pkt) {
memset(pkt->side_data, 0,
- pkt->side_data_elems * sizeof(*pkt->side_data));
- for (i = 0; i < pkt->side_data_elems; i++) {
- DUP_DATA(pkt->side_data[i].data, tmp_pkt.side_data[i].data,
- tmp_pkt.side_data[i].size, 1, ALLOC_MALLOC);
- pkt->side_data[i].size = tmp_pkt.side_data[i].size;
- pkt->side_data[i].type = tmp_pkt.side_data[i].type;
- }
+ src->side_data_elems * sizeof(*src->side_data));
+ }
+ for (i = 0; i < src->side_data_elems; i++) {
+ DUP_DATA(pkt->side_data[i].data, src->side_data[i].data,
+ src->side_data[i].size, 1, ALLOC_MALLOC);
+ pkt->side_data[i].size = src->side_data[i].size;
+ pkt->side_data[i].type = src->side_data[i].type;
}
}
+ pkt->side_data_elems = src->side_data_elems;
return 0;
failed_alloc:
@@ -231,11 +245,34 @@ failed_alloc:
return AVERROR(ENOMEM);
}
+int av_dup_packet(AVPacket *pkt)
+{
+ AVPacket tmp_pkt;
+
+FF_DISABLE_DEPRECATION_WARNINGS
+ if (!pkt->buf && pkt->data
+#if FF_API_DESTRUCT_PACKET
+ && !pkt->destruct
+#endif
+ ) {
+FF_ENABLE_DEPRECATION_WARNINGS
+ tmp_pkt = *pkt;
+ return copy_packet_data(pkt, &tmp_pkt, 1);
+ }
+ return 0;
+}
+
+int av_copy_packet(AVPacket *dst, const AVPacket *src)
+{
+ *dst = *src;
+ return copy_packet_data(dst, src, 0);
+}
+
void av_packet_free_side_data(AVPacket *pkt)
{
int i;
for (i = 0; i < pkt->side_data_elems; i++)
- av_free(pkt->side_data[i].data);
+ av_freep(&pkt->side_data[i].data);
av_freep(&pkt->side_data);
pkt->side_data_elems = 0;
}
@@ -274,7 +311,7 @@ uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
if (!pkt->side_data)
return NULL;
- pkt->side_data[elems].data = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ pkt->side_data[elems].data = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!pkt->side_data[elems].data)
return NULL;
pkt->side_data[elems].size = size;
@@ -299,6 +336,173 @@ uint8_t *av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
return NULL;
}
+const char *av_packet_side_data_name(enum AVPacketSideDataType type)
+{
+ switch(type) {
+ case AV_PKT_DATA_PALETTE: return "Palette";
+ case AV_PKT_DATA_NEW_EXTRADATA: return "New Extradata";
+ case AV_PKT_DATA_PARAM_CHANGE: return "Param Change";
+ case AV_PKT_DATA_H263_MB_INFO: return "H263 MB Info";
+ case AV_PKT_DATA_REPLAYGAIN: return "Replay Gain";
+ case AV_PKT_DATA_DISPLAYMATRIX: return "Display Matrix";
+ case AV_PKT_DATA_STEREO3D: return "Stereo 3D";
+ case AV_PKT_DATA_AUDIO_SERVICE_TYPE: return "Audio Service Type";
+ case AV_PKT_DATA_SKIP_SAMPLES: return "Skip Samples";
+ case AV_PKT_DATA_JP_DUALMONO: return "JP Dual Mono";
+ case AV_PKT_DATA_STRINGS_METADATA: return "Strings Metadata";
+ case AV_PKT_DATA_SUBTITLE_POSITION: return "Subtitle Position";
+ case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL: return "Matroska BlockAdditional";
+ case AV_PKT_DATA_WEBVTT_IDENTIFIER: return "WebVTT ID";
+ case AV_PKT_DATA_WEBVTT_SETTINGS: return "WebVTT Settings";
+ case AV_PKT_DATA_METADATA_UPDATE: return "Metadata Update";
+ }
+ return NULL;
+}
+
+#define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL
+
+int av_packet_merge_side_data(AVPacket *pkt){
+ if(pkt->side_data_elems){
+ AVBufferRef *buf;
+ int i;
+ uint8_t *p;
+ uint64_t size= pkt->size + 8LL + FF_INPUT_BUFFER_PADDING_SIZE;
+ AVPacket old= *pkt;
+ for (i=0; i<old.side_data_elems; i++) {
+ size += old.side_data[i].size + 5LL;
+ }
+ if (size > INT_MAX)
+ return AVERROR(EINVAL);
+ buf = av_buffer_alloc(size);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ pkt->buf = buf;
+ pkt->data = p = buf->data;
+#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
+ pkt->destruct = dummy_destruct_packet;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ pkt->size = size - FF_INPUT_BUFFER_PADDING_SIZE;
+ bytestream_put_buffer(&p, old.data, old.size);
+ for (i=old.side_data_elems-1; i>=0; i--) {
+ bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size);
+ bytestream_put_be32(&p, old.side_data[i].size);
+ *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128);
+ }
+ bytestream_put_be64(&p, FF_MERGE_MARKER);
+ av_assert0(p-pkt->data == pkt->size);
+ memset(p, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ av_free_packet(&old);
+ pkt->side_data_elems = 0;
+ pkt->side_data = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+int av_packet_split_side_data(AVPacket *pkt){
+ if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){
+ int i;
+ unsigned int size;
+ uint8_t *p;
+
+ p = pkt->data + pkt->size - 8 - 5;
+ for (i=1; ; i++){
+ size = AV_RB32(p);
+ if (size>INT_MAX || p - pkt->data < size)
+ return 0;
+ if (p[4]&128)
+ break;
+ p-= size+5;
+ }
+
+ pkt->side_data = av_malloc_array(i, sizeof(*pkt->side_data));
+ if (!pkt->side_data)
+ return AVERROR(ENOMEM);
+
+ p= pkt->data + pkt->size - 8 - 5;
+ for (i=0; ; i++){
+ size= AV_RB32(p);
+ av_assert0(size<=INT_MAX && p - pkt->data >= size);
+ pkt->side_data[i].data = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ pkt->side_data[i].size = size;
+ pkt->side_data[i].type = p[4]&127;
+ if (!pkt->side_data[i].data)
+ return AVERROR(ENOMEM);
+ memcpy(pkt->side_data[i].data, p-size, size);
+ pkt->size -= size + 5;
+ if(p[4]&128)
+ break;
+ p-= size+5;
+ }
+ pkt->size -= 8;
+ pkt->side_data_elems = i+1;
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size)
+{
+ AVDictionaryEntry *t = NULL;
+ uint8_t *data = NULL;
+ *size = 0;
+
+ if (!dict)
+ return NULL;
+
+ while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ const size_t keylen = strlen(t->key);
+ const size_t valuelen = strlen(t->value);
+ const size_t new_size = *size + keylen + 1 + valuelen + 1;
+ uint8_t *const new_data = av_realloc(data, new_size);
+
+ if (!new_data)
+ goto fail;
+ data = new_data;
+ if (new_size > INT_MAX)
+ goto fail;
+
+ memcpy(data + *size, t->key, keylen + 1);
+ memcpy(data + *size + keylen + 1, t->value, valuelen + 1);
+
+ *size = new_size;
+ }
+
+ return data;
+
+fail:
+ av_freep(&data);
+ *size = 0;
+ return NULL;
+}
+
+int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict)
+{
+ const uint8_t *end = data + size;
+ int ret = 0;
+
+ if (!dict || !data || !size)
+ return ret;
+ if (size && end[-1])
+ return AVERROR_INVALIDDATA;
+ while (data < end) {
+ const uint8_t *key = data;
+ const uint8_t *val = data + strlen(key) + 1;
+
+ if (val >= end)
+ return AVERROR_INVALIDDATA;
+
+ ret = av_dict_set(dict, key, val, 0);
+ if (ret < 0)
+ break;
+ data = val + strlen(val) + 1;
+ }
+
+ return ret;
+}
+
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
int size)
{
@@ -352,7 +556,7 @@ void av_packet_unref(AVPacket *pkt)
pkt->size = 0;
}
-int av_packet_ref(AVPacket *dst, AVPacket *src)
+int av_packet_ref(AVPacket *dst, const AVPacket *src)
{
int ret;
diff --git a/libavcodec/avpicture.c b/libavcodec/avpicture.c
index 6bde0f8445..0484dc3f7b 100644
--- a/libavcodec/avpicture.c
+++ b/libavcodec/avpicture.c
@@ -2,20 +2,20 @@
* AVPicture management routines
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,19 +31,18 @@
#include "libavutil/imgutils.h"
#include "libavutil/colorspace.h"
-int avpicture_fill(AVPicture *picture, uint8_t *ptr,
+int avpicture_fill(AVPicture *picture, const uint8_t *ptr,
enum AVPixelFormat pix_fmt, int width, int height)
{
return av_image_fill_arrays(picture->data, picture->linesize,
ptr, pix_fmt, width, height, 1);
}
-int avpicture_layout(const AVPicture* src, enum AVPixelFormat pix_fmt,
- int width, int height,
+int avpicture_layout(const AVPicture* src, enum AVPixelFormat pix_fmt, int width, int height,
unsigned char *dest, int dest_size)
{
return av_image_copy_to_buffer(dest, dest_size,
- src->data, src->linesize,
+ (const uint8_t * const*)src->data, src->linesize,
pix_fmt, width, height, 1);
}
@@ -67,13 +66,13 @@ int avpicture_alloc(AVPicture *picture,
void avpicture_free(AVPicture *picture)
{
- av_free(picture->data[0]);
+ av_freep(&picture->data[0]);
}
void av_picture_copy(AVPicture *dst, const AVPicture *src,
enum AVPixelFormat pix_fmt, int width, int height)
{
- av_image_copy(dst->data, dst->linesize, src->data,
+ av_image_copy(dst->data, dst->linesize, (const uint8_t **)src->data,
src->linesize, pix_fmt, width, height);
}
diff --git a/libavcodec/avr32/mathops.h b/libavcodec/avr32/mathops.h
index 528b7adb33..85f42b594d 100644
--- a/libavcodec/avr32/mathops.h
+++ b/libavcodec/avr32/mathops.h
@@ -2,20 +2,20 @@
* Simple math operations
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/avrndec.c b/libavcodec/avrndec.c
new file mode 100644
index 0000000000..7a50a5c3b1
--- /dev/null
+++ b/libavcodec/avrndec.c
@@ -0,0 +1,131 @@
+/*
+ * AVRn decoder
+ * Copyright (c) 2012 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "mjpeg.h"
+#include "mjpegdec.h"
+#include "libavutil/imgutils.h"
+
+typedef struct {
+ MJpegDecodeContext mjpeg_ctx;
+ int is_mjpeg;
+ int interlace; //FIXME use frame.interlaced_frame
+ int tff;
+} AVRnContext;
+
+static av_cold int init(AVCodecContext *avctx)
+{
+ AVRnContext *a = avctx->priv_data;
+ int ret;
+
+ // Support "Resolution 1:1" for Avid AVI Codec
+ a->is_mjpeg = avctx->extradata_size < 31 || memcmp(&avctx->extradata[28], "1:1", 3);
+
+ if(!a->is_mjpeg && avctx->lowres) {
+ av_log(avctx, AV_LOG_ERROR, "lowres is not possible with rawvideo\n");
+ return AVERROR(EINVAL);
+ }
+
+ if(a->is_mjpeg)
+ return ff_mjpeg_decode_init(avctx);
+
+ if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
+ return ret;
+
+ avctx->pix_fmt = AV_PIX_FMT_UYVY422;
+
+ if(avctx->extradata_size >= 9 && avctx->extradata[4]+28 < avctx->extradata_size) {
+ int ndx = avctx->extradata[4] + 4;
+ a->interlace = !memcmp(avctx->extradata + ndx, "1:1(", 4);
+ if(a->interlace) {
+ a->tff = avctx->extradata[ndx + 24] == 1;
+ }
+ }
+
+ return 0;
+}
+
+static av_cold int end(AVCodecContext *avctx)
+{
+ AVRnContext *a = avctx->priv_data;
+
+ if(a->is_mjpeg)
+ ff_mjpeg_decode_end(avctx);
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVRnContext *a = avctx->priv_data;
+ AVFrame *p = data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int y, ret, true_height;
+
+ if(a->is_mjpeg)
+ return ff_mjpeg_decode_frame(avctx, data, got_frame, avpkt);
+
+ true_height = buf_size / (2*avctx->width);
+
+ if(buf_size < 2*avctx->width * avctx->height) {
+ av_log(avctx, AV_LOG_ERROR, "packet too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
+ return ret;
+ p->pict_type= AV_PICTURE_TYPE_I;
+ p->key_frame= 1;
+
+ if(a->interlace) {
+ buf += (true_height - avctx->height)*avctx->width;
+ for(y = 0; y < avctx->height-1; y+=2) {
+ memcpy(p->data[0] + (y+ a->tff)*p->linesize[0], buf , 2*avctx->width);
+ memcpy(p->data[0] + (y+!a->tff)*p->linesize[0], buf + avctx->width*true_height+4, 2*avctx->width);
+ buf += 2*avctx->width;
+ }
+ } else {
+ buf += (true_height - avctx->height)*avctx->width*2;
+ for(y = 0; y < avctx->height; y++) {
+ memcpy(p->data[0] + y*p->linesize[0], buf, 2*avctx->width);
+ buf += 2*avctx->width;
+ }
+ }
+
+ *got_frame = 1;
+ return buf_size;
+}
+
+AVCodec ff_avrn_decoder = {
+ .name = "avrn",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVRN,
+ .priv_data_size = sizeof(AVRnContext),
+ .init = init,
+ .close = end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
+};
diff --git a/libavcodec/avs.c b/libavcodec/avs.c
index 85d18fd41a..820568964a 100644
--- a/libavcodec/avs.c
+++ b/libavcodec/avs.c
@@ -2,20 +2,20 @@
* AVS video decoder.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,12 +57,10 @@ avs_decode_frame(AVCodecContext * avctx,
int i, j, x, y, stride, ret, vect_w = 3, vect_h = 3;
AvsVideoSubType sub_type;
AvsBlockType type;
- GetBitContext change_map;
+ GetBitContext change_map = {0}; //init to silence warning
- if ((ret = ff_reget_buffer(avctx, p)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, p)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_P;
p->key_frame = 0;
@@ -84,8 +82,10 @@ avs_decode_frame(AVCodecContext * avctx,
if (first >= 256 || last > 256 || buf_end - buf < 4 + 4 + 3 * (last - first))
return AVERROR_INVALIDDATA;
buf += 4;
- for (i=first; i<last; i++, buf+=3)
+ for (i=first; i<last; i++, buf+=3) {
pal[i] = (buf[0] << 18) | (buf[1] << 10) | (buf[2] << 2);
+ pal[i] |= 0xFFU << 24 | (pal[i] >> 6) & 0x30303;
+ }
sub_type = buf[0];
type = buf[1];
diff --git a/libavcodec/avuidec.c b/libavcodec/avuidec.c
new file mode 100644
index 0000000000..7fb644cc6a
--- /dev/null
+++ b/libavcodec/avuidec.c
@@ -0,0 +1,130 @@
+/*
+ * AVID Meridien decoder
+ *
+ * Copyright (c) 2012 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+static av_cold int avui_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUVA422P;
+ return 0;
+}
+
+static int avui_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ int ret;
+ AVFrame *pic = data;
+ const uint8_t *src = avpkt->data, *extradata = avctx->extradata;
+ const uint8_t *srca;
+ uint8_t *y, *u, *v, *a;
+ int transparent, interlaced = 1, skip, opaque_length, i, j, k;
+ uint32_t extradata_size = avctx->extradata_size;
+
+ while (extradata_size >= 24) {
+ uint32_t atom_size = AV_RB32(extradata);
+ if (!memcmp(&extradata[4], "APRGAPRG0001", 12)) {
+ interlaced = extradata[19] != 1;
+ break;
+ }
+ if (atom_size && atom_size <= extradata_size) {
+ extradata += atom_size;
+ extradata_size -= atom_size;
+ } else {
+ break;
+ }
+ }
+ if (avctx->height == 486) {
+ skip = 10;
+ } else {
+ skip = 16;
+ }
+ opaque_length = 2 * avctx->width * (avctx->height + skip) + 4 * interlaced;
+ if (avpkt->size < opaque_length) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ return AVERROR(EINVAL);
+ }
+ transparent = avctx->bits_per_coded_sample == 32 &&
+ avpkt->size >= opaque_length * 2 + 4;
+ srca = src + opaque_length + 5;
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->key_frame = 1;
+ pic->pict_type = AV_PICTURE_TYPE_I;
+
+ if (!interlaced) {
+ src += avctx->width * skip;
+ srca += avctx->width * skip;
+ }
+
+ for (i = 0; i < interlaced + 1; i++) {
+ src += avctx->width * skip;
+ srca += avctx->width * skip;
+ if (interlaced && avctx->height == 486) {
+ y = pic->data[0] + (1 - i) * pic->linesize[0];
+ u = pic->data[1] + (1 - i) * pic->linesize[1];
+ v = pic->data[2] + (1 - i) * pic->linesize[2];
+ a = pic->data[3] + (1 - i) * pic->linesize[3];
+ } else {
+ y = pic->data[0] + i * pic->linesize[0];
+ u = pic->data[1] + i * pic->linesize[1];
+ v = pic->data[2] + i * pic->linesize[2];
+ a = pic->data[3] + i * pic->linesize[3];
+ }
+
+ for (j = 0; j < avctx->height >> interlaced; j++) {
+ for (k = 0; k < avctx->width >> 1; k++) {
+ u[ k ] = *src++;
+ y[2 * k ] = *src++;
+ a[2 * k ] = 0xFF - (transparent ? *srca++ : 0);
+ srca++;
+ v[ k ] = *src++;
+ y[2 * k + 1] = *src++;
+ a[2 * k + 1] = 0xFF - (transparent ? *srca++ : 0);
+ srca++;
+ }
+
+ y += (interlaced + 1) * pic->linesize[0];
+ u += (interlaced + 1) * pic->linesize[1];
+ v += (interlaced + 1) * pic->linesize[2];
+ a += (interlaced + 1) * pic->linesize[3];
+ }
+ src += 4;
+ srca += 4;
+ }
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_avui_decoder = {
+ .name = "avui",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVUI,
+ .init = avui_decode_init,
+ .decode = avui_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/avuienc.c b/libavcodec/avuienc.c
new file mode 100644
index 0000000000..b91f782955
--- /dev/null
+++ b/libavcodec/avuienc.c
@@ -0,0 +1,117 @@
+/*
+ * AVID Meridien encoder
+ *
+ * Copyright (c) 2012 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+static av_cold int avui_encode_init(AVCodecContext *avctx)
+{
+ if (avctx->width != 720 || avctx->height != 486 && avctx->height != 576) {
+ av_log(avctx, AV_LOG_ERROR, "Only 720x486 and 720x576 are supported.\n");
+ return AVERROR(EINVAL);
+ }
+ if (!(avctx->extradata = av_mallocz(144 + FF_INPUT_BUFFER_PADDING_SIZE)))
+ return AVERROR(ENOMEM);
+ avctx->extradata_size = 144;
+ memcpy(avctx->extradata, "\0\0\0\x18""APRGAPRG0001", 16);
+ if (avctx->field_order > AV_FIELD_PROGRESSIVE) {
+ avctx->extradata[19] = 2;
+ } else {
+ avctx->extradata[19] = 1;
+ }
+ memcpy(avctx->extradata + 24, "\0\0\0\x78""ARESARES0001""\0\0\0\x98", 20);
+ AV_WB32(avctx->extradata + 44, avctx->width);
+ AV_WB32(avctx->extradata + 48, avctx->height);
+ memcpy(avctx->extradata + 52, "\0\0\0\x1\0\0\0\x20\0\0\0\x2", 12);
+
+ avctx->coded_frame = av_frame_alloc();
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static int avui_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ uint8_t *dst;
+ int i, j, skip, ret, size, interlaced;
+
+ interlaced = avctx->field_order > AV_FIELD_PROGRESSIVE;
+
+ if (avctx->height == 486) {
+ skip = 10;
+ } else {
+ skip = 16;
+ }
+ size = 2 * avctx->width * (avctx->height + skip) + 8 * interlaced;
+ if ((ret = ff_alloc_packet2(avctx, pkt, size)) < 0)
+ return ret;
+ dst = pkt->data;
+ if (!interlaced) {
+ dst += avctx->width * skip;
+ }
+
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ for (i = 0; i <= interlaced; i++) {
+ uint8_t *src;
+ if (interlaced && avctx->height == 486) {
+ src = pic->data[0] + (1 - i) * pic->linesize[0];
+ } else {
+ src = pic->data[0] + i * pic->linesize[0];
+ }
+ dst += avctx->width * skip + 4 * i;
+ for (j = 0; j < avctx->height; j += interlaced + 1) {
+ memcpy(dst, src, avctx->width * 2);
+ src += (interlaced + 1) * pic->linesize[0];
+ dst += avctx->width * 2;
+ }
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int avui_encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+AVCodec ff_avui_encoder = {
+ .name = "avui",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVUI,
+ .init = avui_encode_init,
+ .encode2 = avui_encode_frame,
+ .close = avui_encode_close,
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_UYVY422, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/bethsoftvideo.c b/libavcodec/bethsoftvideo.c
index 7e93a2749c..37cd22eb39 100644
--- a/libavcodec/bethsoftvideo.c
+++ b/libavcodec/bethsoftvideo.c
@@ -2,20 +2,20 @@
* Bethesda VID video decoder
* Copyright (C) 2007 Nicholas Tung
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,7 +59,8 @@ static int set_palette(BethsoftvidContext *ctx)
return AVERROR_INVALIDDATA;
for(a = 0; a < 256; a++){
- palette[a] = bytestream2_get_be24u(&ctx->g) * 4;
+ palette[a] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->g) * 4;
+ palette[a] |= palette[a] >> 6 & 0x30303;
}
ctx->frame->palette_has_changed = 1;
return 0;
@@ -78,10 +79,8 @@ static int bethsoftvid_decode_frame(AVCodecContext *avctx,
int code, ret;
int yoffset;
- if ((ret = ff_reget_buffer(avctx, vid->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, vid->frame)) < 0)
return ret;
- }
wrap_to_next_line = vid->frame->linesize[0] - avctx->width;
if (avpkt->side_data_elems > 0 &&
diff --git a/libavcodec/bethsoftvideo.h b/libavcodec/bethsoftvideo.h
index 5cbbdfdff0..d5b5d0a525 100644
--- a/libavcodec/bethsoftvideo.h
+++ b/libavcodec/bethsoftvideo.h
@@ -2,20 +2,20 @@
* Bethesda VID video decoder
* Copyright (C) 2007 Nicholas Tung
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c
index 75b6710189..77bca4902f 100644
--- a/libavcodec/bfi.c
+++ b/libavcodec/bfi.c
@@ -2,20 +2,20 @@
* Brute Force & Ignorance (BFI) video decoder
* Copyright (c) 2008 Sisir Koppaka
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@
typedef struct BFIContext {
AVCodecContext *avctx;
uint8_t *dst;
+ uint32_t pal[256];
} BFIContext;
static av_cold int bfi_decode_init(AVCodecContext *avctx)
@@ -41,6 +42,8 @@ static av_cold int bfi_decode_init(AVCodecContext *avctx)
BFIContext *bfi = avctx->priv_data;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
bfi->dst = av_mallocz(avctx->width * avctx->height);
+ if (!bfi->dst)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -57,10 +60,8 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data,
uint32_t *pal;
int i, j, ret, height = avctx->height;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
bytestream2_init(&g, avpkt->data, buf_size);
@@ -76,16 +77,19 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data,
pal = (uint32_t *)frame->data[1];
for (i = 0; i < avctx->extradata_size / 3; i++) {
int shift = 16;
- *pal = 0;
+ *pal = 0xFFU << 24;
for (j = 0; j < 3; j++, shift -= 8)
*pal += ((avctx->extradata[i * 3 + j] << 2) |
(avctx->extradata[i * 3 + j] >> 4)) << shift;
pal++;
}
+ memcpy(bfi->pal, frame->data[1], sizeof(bfi->pal));
frame->palette_has_changed = 1;
} else {
frame->pict_type = AV_PICTURE_TYPE_P;
frame->key_frame = 0;
+ frame->palette_has_changed = 0;
+ memcpy(frame->data[1], bfi->pal, sizeof(bfi->pal));
}
bytestream2_skip(&g, 4); // Unpacked size, not required.
@@ -167,7 +171,7 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data,
static av_cold int bfi_decode_close(AVCodecContext *avctx)
{
BFIContext *bfi = avctx->priv_data;
- av_free(bfi->dst);
+ av_freep(&bfi->dst);
return 0;
}
diff --git a/libavcodec/bfin/README b/libavcodec/bfin/README
new file mode 100644
index 0000000000..afb3461b72
--- /dev/null
+++ b/libavcodec/bfin/README
@@ -0,0 +1,6 @@
+BFIN optimizations have been removed in
+commit 880e2aa23645ed9871c66ee1cbd00f93c72d2d73
+The last revission with the optimizations is fa4e17c14035ebf43130fb369e1728cdd98d0b72
+
+If you want to maintain these (or other) BFIN optimizations in ffmpeg, then please
+contact ffmpeg-devel@ffmpeg.org
diff --git a/libavcodec/bgmc.c b/libavcodec/bgmc.c
index ad8baaecac..1a6817b73f 100644
--- a/libavcodec/bgmc.c
+++ b/libavcodec/bgmc.c
@@ -1,28 +1,28 @@
/*
* Block Gilbert-Moore decoder
- * Copyright (c) 2010 Thilo Borgmann <thilo.borgmann _at_ googlemail.com>
+ * Copyright (c) 2010 Thilo Borgmann <thilo.borgmann _at_ mail.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Block Gilbert-Moore decoder as used by MPEG-4 ALS
- * @author Thilo Borgmann <thilo.borgmann _at_ googlemail.com>
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
*/
#include "libavutil/attributes.h"
diff --git a/libavcodec/bgmc.h b/libavcodec/bgmc.h
index 3d5b49034d..4893736af5 100644
--- a/libavcodec/bgmc.h
+++ b/libavcodec/bgmc.h
@@ -1,28 +1,28 @@
/*
* Block Gilbert-Moore decoder
- * Copyright (c) 2010 Thilo Borgmann <thilo.borgmann _at_ googlemail.com>
+ * Copyright (c) 2010 Thilo Borgmann <thilo.borgmann _at_ mail.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Block Gilbert-Moore decoder header
- * @author Thilo Borgmann <thilo.borgmann _at_ googlemail.com>
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
*/
diff --git a/libavcodec/bink.c b/libavcodec/bink.c
index e34585b8a5..bc3d25c739 100644
--- a/libavcodec/bink.c
+++ b/libavcodec/bink.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Konstantin Shishkov
* Copyright (C) 2011 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -120,6 +120,7 @@ typedef struct BinkContext {
int version; ///< internal Bink file version
int has_alpha;
int swap_planes;
+ unsigned frame_num;
Bundle bundle[BINKB_NB_SRC]; ///< bundles for decoding all data types
Tree col_high[16]; ///< trees for decoding high nibble in "colours" data type
@@ -143,7 +144,7 @@ enum BlockTypes {
};
/**
- * Initialize length length in all bundles.
+ * Initialize length in all bundles.
*
* @param c decoder context
* @param width plane width
@@ -174,7 +175,7 @@ static void init_lengths(BinkContext *c, int width, int bw)
*
* @param c decoder context
*/
-static av_cold void init_bundles(BinkContext *c)
+static av_cold int init_bundles(BinkContext *c)
{
int bw, bh, blocks;
int i;
@@ -184,9 +185,13 @@ static av_cold void init_bundles(BinkContext *c)
blocks = bw * bh;
for (i = 0; i < BINKB_NB_SRC; i++) {
- c->bundle[i].data = av_malloc(blocks * 64);
+ c->bundle[i].data = av_mallocz(blocks * 64);
+ if (!c->bundle[i].data)
+ return AVERROR(ENOMEM);
c->bundle[i].data_end = c->bundle[i].data + blocks * 64;
}
+
+ return 0;
}
/**
@@ -679,11 +684,12 @@ static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], const uint8_t *
quant_idx = get_bits(gb, 4);
} else {
quant_idx = q;
+ if (quant_idx > 15U) {
+ av_log(NULL, AV_LOG_ERROR, "quant_index %d out of range\n", quant_idx);
+ return AVERROR_INVALIDDATA;
+ }
}
- if (quant_idx >= 16)
- return AVERROR_INVALIDDATA;
-
quant = quant_matrices[quant_idx];
block[0] = (block[0] * quant[0]) >> 11;
@@ -866,7 +872,7 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb,
memset(dctblock, 0, sizeof(*dctblock) * 64);
dctblock[0] = binkb_get_value(c, BINKB_SRC_INTRA_DC);
qp = binkb_get_value(c, BINKB_SRC_INTRA_Q);
- read_dct_coeffs(gb, dctblock, bink_scan, binkb_intra_quant, qp);
+ read_dct_coeffs(gb, dctblock, bink_scan, (const int32_t (*)[64])binkb_intra_quant, qp);
c->binkdsp.idct_put(dst, stride, dctblock);
break;
case 3:
@@ -899,7 +905,7 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb,
memset(dctblock, 0, sizeof(*dctblock) * 64);
dctblock[0] = binkb_get_value(c, BINKB_SRC_INTER_DC);
qp = binkb_get_value(c, BINKB_SRC_INTER_Q);
- read_dct_coeffs(gb, dctblock, bink_scan, binkb_inter_quant, qp);
+ read_dct_coeffs(gb, dctblock, bink_scan, (const int32_t (*)[64])binkb_inter_quant, qp);
c->binkdsp.idct_add(dst, stride, dctblock);
break;
case 5:
@@ -1136,6 +1142,11 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb,
xoff = get_value(c, BINK_SRC_X_OFF);
yoff = get_value(c, BINK_SRC_Y_OFF);
ref = prev + xoff + yoff * stride;
+ if (ref < ref_start || ref > ref_end) {
+ av_log(c->avctx, AV_LOG_ERROR, "Copy out of bounds @%d, %d\n",
+ bx*8 + xoff, by*8 + yoff);
+ return -1;
+ }
c->hdsp.put_pixels_tab[1][0](dst, ref, stride, 8);
memset(dctblock, 0, sizeof(*dctblock) * 64);
dctblock[0] = get_value(c, BINK_SRC_INTER_DC);
@@ -1177,15 +1188,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
int bits_count = pkt->size << 3;
if (c->version > 'b') {
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
} else {
- if ((ret = ff_reget_buffer(avctx, c->last)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, c->last)) < 0)
return ret;
- }
if ((ret = av_frame_ref(frame, c->last)) < 0)
return ret;
}
@@ -1200,6 +1207,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
if (c->version >= 'i')
skip_bits_long(&gb, 32);
+ c->frame_num++;
+
for (plane = 0; plane < 3; plane++) {
plane_idx = (!plane || !c->swap_planes) ? plane : (plane ^ 3);
@@ -1208,7 +1217,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
return ret;
} else {
if ((ret = binkb_decode_plane(c, frame, &gb, plane_idx,
- !avctx->frame_number, !!plane)) < 0)
+ c->frame_num == 1, !!plane)) < 0)
return ret;
}
if (get_bits_count(&gb) >= bits_count)
@@ -1234,41 +1243,28 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
static av_cold void binkb_calc_quant(void)
{
uint8_t inv_bink_scan[64];
- double s[64];
+ static const int s[64]={
+ 1073741824,1489322693,1402911301,1262586814,1073741824, 843633538, 581104888, 296244703,
+ 1489322693,2065749918,1945893874,1751258219,1489322693,1170153332, 806015634, 410903207,
+ 1402911301,1945893874,1832991949,1649649171,1402911301,1102260336, 759250125, 387062357,
+ 1262586814,1751258219,1649649171,1484645031,1262586814, 992008094, 683307060, 348346918,
+ 1073741824,1489322693,1402911301,1262586814,1073741824, 843633538, 581104888, 296244703,
+ 843633538,1170153332,1102260336, 992008094, 843633538, 662838617, 456571181, 232757969,
+ 581104888, 806015634, 759250125, 683307060, 581104888, 456571181, 314491699, 160326478,
+ 296244703, 410903207, 387062357, 348346918, 296244703, 232757969, 160326478, 81733730,
+ };
int i, j;
-
- for (j = 0; j < 8; j++) {
- for (i = 0; i < 8; i++) {
- if (j && j != 4)
- if (i && i != 4)
- s[j*8 + i] = cos(j * M_PI/16.0) * cos(i * M_PI/16.0) * 2.0;
- else
- s[j*8 + i] = cos(j * M_PI/16.0) * sqrt(2.0);
- else
- if (i && i != 4)
- s[j*8 + i] = cos(i * M_PI/16.0) * sqrt(2.0);
- else
- s[j*8 + i] = 1.0;
- }
- }
-
+#define C (1LL<<30)
for (i = 0; i < 64; i++)
inv_bink_scan[bink_scan[i]] = i;
for (j = 0; j < 16; j++) {
for (i = 0; i < 64; i++) {
int k = inv_bink_scan[i];
- if (s[i] == 1.0) {
- binkb_intra_quant[j][k] = (1L << 12) * binkb_intra_seed[i] *
- binkb_num[j]/binkb_den[j];
- binkb_inter_quant[j][k] = (1L << 12) * binkb_inter_seed[i] *
- binkb_num[j]/binkb_den[j];
- } else {
- binkb_intra_quant[j][k] = (1L << 12) * binkb_intra_seed[i] * s[i] *
- binkb_num[j]/(double)binkb_den[j];
- binkb_inter_quant[j][k] = (1L << 12) * binkb_inter_seed[i] * s[i] *
- binkb_num[j]/(double)binkb_den[j];
- }
+ binkb_intra_quant[j][k] = binkb_intra_seed[i] * (int64_t)s[i] *
+ binkb_num[j]/(binkb_den[j] * (C>>12));
+ binkb_inter_quant[j][k] = binkb_inter_seed[i] * (int64_t)s[i] *
+ binkb_num[j]/(binkb_den[j] * (C>>12));
}
}
}
@@ -1314,7 +1310,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
ff_hpeldsp_init(&c->hdsp, avctx->flags);
ff_binkdsp_init(&c->binkdsp);
- init_bundles(c);
+ if ((ret = init_bundles(c)) < 0) {
+ free_bundles(c);
+ return ret;
+ }
if (c->version == 'b') {
if (!binkb_initialised) {
@@ -1336,6 +1335,13 @@ static av_cold int decode_end(AVCodecContext *avctx)
return 0;
}
+static void flush(AVCodecContext *avctx)
+{
+ BinkContext * const c = avctx->priv_data;
+
+ c->frame_num = 0;
+}
+
AVCodec ff_bink_decoder = {
.name = "binkvideo",
.long_name = NULL_IF_CONFIG_SMALL("Bink video"),
@@ -1345,5 +1351,6 @@ AVCodec ff_bink_decoder = {
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
+ .flush = flush,
.capabilities = CODEC_CAP_DR1,
};
diff --git a/libavcodec/binkaudio.c b/libavcodec/binkaudio.c
index 0b427bfb90..f30ea1236f 100644
--- a/libavcodec/binkaudio.c
+++ b/libavcodec/binkaudio.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007-2011 Peter Ross (pross@xvid.org)
* Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,14 +81,14 @@ static av_cold int decode_init(AVCodecContext *avctx)
frame_len_bits = 11;
}
- if (avctx->channels > MAX_CHANNELS) {
- av_log(avctx, AV_LOG_ERROR, "too many channels: %d\n", avctx->channels);
- return -1;
+ if (avctx->channels < 1 || avctx->channels > MAX_CHANNELS) {
+ av_log(avctx, AV_LOG_ERROR, "invalid number of channels: %d\n", avctx->channels);
+ return AVERROR_INVALIDDATA;
}
avctx->channel_layout = avctx->channels == 1 ? AV_CH_LAYOUT_MONO :
AV_CH_LAYOUT_STEREO;
- s->version_b = avctx->extradata && avctx->extradata[3] == 'b';
+ s->version_b = avctx->extradata_size >= 4 && avctx->extradata[3] == 'b';
if (avctx->codec->id == AV_CODEC_ID_BINKAUDIO_RDFT) {
// audio is already interleaved for the RDFT format variant
@@ -305,9 +305,11 @@ static int decode_frame(AVCodecContext *avctx, void *data,
buf = av_realloc(s->packet_buffer, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!buf)
return AVERROR(ENOMEM);
+ memset(buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
s->packet_buffer = buf;
memcpy(s->packet_buffer, avpkt->data, avpkt->size);
- init_get_bits(gb, s->packet_buffer, avpkt->size * 8);
+ if ((ret = init_get_bits8(gb, s->packet_buffer, avpkt->size)) < 0)
+ return ret;
consumed = avpkt->size;
/* skip reported size */
@@ -316,10 +318,8 @@ static int decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = s->frame_len;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if (decode_block(s, (float **)frame->extended_data,
avctx->codec->id == AV_CODEC_ID_BINKAUDIO_DCT)) {
diff --git a/libavcodec/binkdata.h b/libavcodec/binkdata.h
index 3da6b7e987..57619beee2 100644
--- a/libavcodec/binkdata.h
+++ b/libavcodec/binkdata.h
@@ -2,20 +2,20 @@
* Bink video decoder
* Copyright (C) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/binkdsp.c b/libavcodec/binkdsp.c
index 0dfe12cd4f..9d70e2326f 100644
--- a/libavcodec/binkdsp.c
+++ b/libavcodec/binkdsp.c
@@ -2,20 +2,20 @@
* Bink DSP routines
* Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -129,7 +129,7 @@ static void scale_block_c(const uint8_t src[64]/*align 8*/, uint8_t *dst/*align
}
}
-static void add_pixels8_c(uint8_t *restrict pixels, int16_t *block,
+static void add_pixels8_c(uint8_t *av_restrict pixels, int16_t *block,
int line_size)
{
int i;
diff --git a/libavcodec/binkdsp.h b/libavcodec/binkdsp.h
index 418afb9895..f319d1ffe5 100644
--- a/libavcodec/binkdsp.h
+++ b/libavcodec/binkdsp.h
@@ -2,20 +2,20 @@
* Bink DSP routines
* Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c
new file mode 100644
index 0000000000..97fceb12b8
--- /dev/null
+++ b/libavcodec/bintext.c
@@ -0,0 +1,258 @@
+/*
+ * Binary text decoder
+ * eXtended BINary text (XBIN) decoder
+ * iCEDraw File decoder
+ * Copyright (c) 2010 Peter Ross (pross@xvid.org)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Binary text decoder
+ * eXtended BINary text (XBIN) decoder
+ * iCEDraw File decoder
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/xga_font_data.h"
+#include "avcodec.h"
+#include "cga_data.h"
+#include "bintext.h"
+#include "internal.h"
+
+typedef struct XbinContext {
+ AVFrame *frame;
+ int palette[16];
+ int flags;
+ int font_height;
+ const uint8_t *font;
+ int x, y;
+} XbinContext;
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ XbinContext *s = avctx->priv_data;
+ uint8_t *p;
+ int i;
+
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ p = avctx->extradata;
+ if (p) {
+ s->font_height = p[0];
+ s->flags = p[1];
+ p += 2;
+ if(avctx->extradata_size < 2 + (!!(s->flags & BINTEXT_PALETTE))*3*16
+ + (!!(s->flags & BINTEXT_FONT))*s->font_height*256) {
+ av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ } else {
+ s->font_height = 8;
+ s->flags = 0;
+ }
+
+ if ((s->flags & BINTEXT_PALETTE)) {
+ for (i = 0; i < 16; i++) {
+ s->palette[i] = 0xFF000000 | (AV_RB24(p) << 2) | ((AV_RB24(p) >> 4) & 0x30303);
+ p += 3;
+ }
+ } else {
+ for (i = 0; i < 16; i++)
+ s->palette[i] = 0xFF000000 | ff_cga_palette[i];
+ }
+
+ if ((s->flags & BINTEXT_FONT)) {
+ s->font = p;
+ } else {
+ switch(s->font_height) {
+ default:
+ av_log(avctx, AV_LOG_WARNING, "font height %i not supported\n", s->font_height);
+ s->font_height = 8;
+ case 8:
+ s->font = avpriv_cga_font;
+ break;
+ case 16:
+ s->font = avpriv_vga16_font;
+ break;
+ }
+ }
+
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+#define DEFAULT_BG_COLOR 0
+av_unused static void hscroll(AVCodecContext *avctx)
+{
+ XbinContext *s = avctx->priv_data;
+ if (s->y < avctx->height - s->font_height) {
+ s->y += s->font_height;
+ } else {
+ memmove(s->frame->data[0], s->frame->data[0] + s->font_height*s->frame->linesize[0],
+ (avctx->height - s->font_height)*s->frame->linesize[0]);
+ memset(s->frame->data[0] + (avctx->height - s->font_height)*s->frame->linesize[0],
+ DEFAULT_BG_COLOR, s->font_height * s->frame->linesize[0]);
+ }
+}
+
+#define FONT_WIDTH 8
+
+/**
+ * Draw character to screen
+ */
+static void draw_char(AVCodecContext *avctx, int c, int a)
+{
+ XbinContext *s = avctx->priv_data;
+ if (s->y > avctx->height - s->font_height)
+ return;
+ ff_draw_pc_font(s->frame->data[0] + s->y * s->frame->linesize[0] + s->x,
+ s->frame->linesize[0], s->font, s->font_height, c,
+ a & 0x0F, a >> 4);
+ s->x += FONT_WIDTH;
+ if (s->x > avctx->width - FONT_WIDTH) {
+ s->x = 0;
+ s->y += s->font_height;
+ }
+}
+
+static int decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ XbinContext *s = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ const uint8_t *buf_end = buf+buf_size;
+ int ret;
+
+ s->x = s->y = 0;
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+ return ret;
+ s->frame->pict_type = AV_PICTURE_TYPE_I;
+ s->frame->palette_has_changed = 1;
+ memcpy(s->frame->data[1], s->palette, 16 * 4);
+
+ if (avctx->codec_id == AV_CODEC_ID_XBIN) {
+ while (buf + 2 < buf_end) {
+ int i,c,a;
+ int type = *buf >> 6;
+ int count = (*buf & 0x3F) + 1;
+ buf++;
+ switch (type) {
+ case 0: //no compression
+ for (i = 0; i < count && buf + 1 < buf_end; i++) {
+ draw_char(avctx, buf[0], buf[1]);
+ buf += 2;
+ }
+ break;
+ case 1: //character compression
+ c = *buf++;
+ for (i = 0; i < count && buf < buf_end; i++)
+ draw_char(avctx, c, *buf++);
+ break;
+ case 2: //attribute compression
+ a = *buf++;
+ for (i = 0; i < count && buf < buf_end; i++)
+ draw_char(avctx, *buf++, a);
+ break;
+ case 3: //character/attribute compression
+ c = *buf++;
+ a = *buf++;
+ for (i = 0; i < count && buf < buf_end; i++)
+ draw_char(avctx, c, a);
+ break;
+ }
+ }
+ } else if (avctx->codec_id == AV_CODEC_ID_IDF) {
+ while (buf + 2 < buf_end) {
+ if (AV_RL16(buf) == 1) {
+ int i;
+ if (buf + 6 > buf_end)
+ break;
+ for (i = 0; i < buf[2]; i++)
+ draw_char(avctx, buf[4], buf[5]);
+ buf += 6;
+ } else {
+ draw_char(avctx, buf[0], buf[1]);
+ buf += 2;
+ }
+ }
+ } else {
+ while (buf + 1 < buf_end) {
+ draw_char(avctx, buf[0], buf[1]);
+ buf += 2;
+ }
+ }
+
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
+ return ret;
+ *got_frame = 1;
+ return buf_size;
+}
+
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+ XbinContext *s = avctx->priv_data;
+
+ av_frame_free(&s->frame);
+
+ return 0;
+}
+
+#if CONFIG_BINTEXT_DECODER
+AVCodec ff_bintext_decoder = {
+ .name = "bintext",
+ .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_BINTEXT,
+ .priv_data_size = sizeof(XbinContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
+#if CONFIG_XBIN_DECODER
+AVCodec ff_xbin_decoder = {
+ .name = "xbin",
+ .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_XBIN,
+ .priv_data_size = sizeof(XbinContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
+#if CONFIG_IDF_DECODER
+AVCodec ff_idf_decoder = {
+ .name = "idf",
+ .long_name = NULL_IF_CONFIG_SMALL("iCEDraw text"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_IDF,
+ .priv_data_size = sizeof(XbinContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
diff --git a/libavcodec/bintext.h b/libavcodec/bintext.h
new file mode 100644
index 0000000000..21428ba476
--- /dev/null
+++ b/libavcodec/bintext.h
@@ -0,0 +1,37 @@
+/*
+ * Binary text decoder
+ * Copyright (c) 2010 Peter Ross (pross@xvid.org)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Binary text decoder
+ */
+
+#ifndef AVCODEC_BINTEXT_H
+#define AVCODEC_BINTEXT_H
+
+/* flag values passed between avformat and avcodec;
+ * while these are identical to the XBIN flags, they are also used
+ * for the BINTEXT and IDF decoders.
+ */
+#define BINTEXT_PALETTE 0x1
+#define BINTEXT_FONT 0x2
+
+#endif /* AVCODEC_BINTEXT_H */
diff --git a/libavcodec/bit_depth_template.c b/libavcodec/bit_depth_template.c
index 27e658ba75..80184892f5 100644
--- a/libavcodec/bit_depth_template.c
+++ b/libavcodec/bit_depth_template.c
@@ -1,23 +1,24 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mathops.h"
#include "rnd_avg.h"
+#include "libavutil/intreadwrite.h"
#ifndef BIT_DEPTH
#define BIT_DEPTH 8
@@ -71,7 +72,7 @@
# define pixel4 uint32_t
# define dctcoef int16_t
-# define INIT_CLIP const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
+# define INIT_CLIP
# define no_rnd_avg_pixel4 no_rnd_avg32
# define rnd_avg_pixel4 rnd_avg32
# define AV_RN2P AV_RN16
@@ -83,7 +84,7 @@
# define PIXEL_SPLAT_X4(x) ((x)*0x01010101U)
# define av_clip_pixel(a) av_clip_uint8(a)
-# define CLIP(a) cm[a]
+# define CLIP(a) av_clip_uint8(a)
#endif
#define FUNC3(a, b, c) a ## _ ## b ## c
diff --git a/libavcodec/bitstream.c b/libavcodec/bitstream.c
index 93047a2b91..20eae6b1bf 100644
--- a/libavcodec/bitstream.c
+++ b/libavcodec/bitstream.c
@@ -6,20 +6,20 @@
*
* alternative bitstream reader & writer by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,8 @@
* bitstream api.
*/
+#include "libavutil/atomic.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "internal.h"
#include "mathops.h"
@@ -68,6 +70,8 @@ void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length)
if (length == 0)
return;
+ av_assert0(length <= put_bits_left(pb));
+
if (CONFIG_SMALL || words < 16 || put_bits_count(pb) & 7) {
for (i = 0; i < words; i++)
put_bits(pb, 16, AV_RB16(src + 2 * i));
@@ -107,17 +111,16 @@ static int alloc_table(VLC *vlc, int size, int use_static)
vlc->table_size += size;
if (vlc->table_size > vlc->table_allocated) {
- int err;
if (use_static)
- return AVERROR_BUG;
+ abort(); // cannot do anything, init_vlc() is used with too little memory
vlc->table_allocated += (1 << vlc->bits);
- if ((err = av_reallocp(&vlc->table,
- sizeof(VLC_TYPE) * 2 *
- vlc->table_allocated)) < 0) {
+ vlc->table = av_realloc_f(vlc->table, vlc->table_allocated, sizeof(VLC_TYPE) * 2);
+ if (!vlc->table) {
vlc->table_allocated = 0;
vlc->table_size = 0;
- return err;
+ return AVERROR(ENOMEM);
}
+ memset(vlc->table + vlc->table_allocated - (1 << vlc->bits), 0, sizeof(VLC_TYPE) * 2 << vlc->bits);
}
return index;
}
@@ -163,19 +166,16 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes,
int table_size, table_index, index, code_prefix, symbol, subtable_bits;
int i, j, k, n, nb, inc;
uint32_t code;
- VLC_TYPE (*table)[2];
+ volatile VLC_TYPE (* volatile table)[2]; // the double volatile is needed to prevent a internal compiler error in gcc 4.2
table_size = 1 << table_nb_bits;
+ if (table_nb_bits > 30)
+ return -1;
table_index = alloc_table(vlc, table_size, flags & INIT_VLC_USE_NEW_STATIC);
ff_dlog(NULL, "new table index=%d size=%d\n", table_index, table_size);
if (table_index < 0)
return table_index;
- table = &vlc->table[table_index];
-
- for (i = 0; i < table_size; i++) {
- table[i][1] = 0; //bits
- table[i][0] = -1; //codes
- }
+ table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index];
/* first pass: map codes and compute auxiliary table sizes */
for (i = 0; i < nb_codes; i++) {
@@ -193,8 +193,9 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes,
inc = 1 << n;
}
for (k = 0; k < nb; k++) {
+ int bits = table[j][1];
ff_dlog(NULL, "%4x: code=%d n=%d\n", j, i, n);
- if (table[j][1] /*bits*/ != 0) {
+ if (bits != 0 && bits != n) {
av_log(NULL, AV_LOG_ERROR, "incorrect codes\n");
return AVERROR_INVALIDDATA;
}
@@ -229,11 +230,17 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes,
if (index < 0)
return index;
/* note: realloc has been done, so reload tables */
- table = &vlc->table[table_index];
+ table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index];
table[j][0] = index; //code
i = k-1;
}
}
+
+ for (i = 0; i < table_size; i++) {
+ if (table[i][1] == 0) //bits
+ table[i][0] = -1; //codes
+ }
+
return table_index;
}
@@ -264,7 +271,7 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes,
'use_static' should be set to 1 for tables, which should be freed
with av_free_static(), 0 if ff_free_vlc() will be used.
*/
-int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
+int ff_init_vlc_sparse(VLC *vlc_arg, int nb_bits, int nb_codes,
const void *bits, int bits_wrap, int bits_size,
const void *codes, int codes_wrap, int codes_size,
const void *symbols, int symbols_wrap, int symbols_size,
@@ -272,42 +279,56 @@ int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
{
VLCcode *buf;
int i, j, ret;
+ VLCcode localbuf[1500]; // the maximum currently needed is 1296 by rv34
+ VLC localvlc, *vlc;
+ vlc = vlc_arg;
vlc->bits = nb_bits;
if (flags & INIT_VLC_USE_NEW_STATIC) {
- if (vlc->table_size && vlc->table_size == vlc->table_allocated) {
- return 0;
- } else if (vlc->table_size) {
- return AVERROR_BUG;
- }
+ av_assert0(nb_codes + 1 <= FF_ARRAY_ELEMS(localbuf));
+ buf = localbuf;
+ localvlc = *vlc_arg;
+ vlc = &localvlc;
+ vlc->table_size = 0;
} else {
vlc->table = NULL;
vlc->table_allocated = 0;
vlc->table_size = 0;
- }
- ff_dlog(NULL, "build table nb_codes=%d\n", nb_codes);
+ buf = av_malloc_array((nb_codes + 1), sizeof(VLCcode));
+ if (!buf)
+ return AVERROR(ENOMEM);
+ }
- buf = av_malloc((nb_codes + 1) * sizeof(VLCcode));
- if (!buf)
- return AVERROR(ENOMEM);
- assert(symbols_size <= 2 || !symbols);
+ av_assert0(symbols_size <= 2 || !symbols);
j = 0;
-#define COPY(condition) \
+#define COPY(condition)\
for (i = 0; i < nb_codes; i++) { \
GET_DATA(buf[j].bits, bits, i, bits_wrap, bits_size); \
if (!(condition)) \
continue; \
+ if (buf[j].bits > 3*nb_bits || buf[j].bits>32) { \
+ av_log(NULL, AV_LOG_ERROR, "Too long VLC (%d) in init_vlc\n", buf[j].bits);\
+ if (!(flags & INIT_VLC_USE_NEW_STATIC)) \
+ av_free(buf); \
+ return -1; \
+ } \
GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size); \
+ if (buf[j].code >= (1LL<<buf[j].bits)) { \
+ av_log(NULL, AV_LOG_ERROR, "Invalid code in init_vlc\n"); \
+ if (!(flags & INIT_VLC_USE_NEW_STATIC)) \
+ av_free(buf); \
+ return -1; \
+ } \
if (flags & INIT_VLC_LE) \
buf[j].code = bitswap_32(buf[j].code); \
else \
buf[j].code <<= 32 - buf[j].bits; \
if (symbols) \
GET_DATA(buf[j].symbol, symbols, i, symbols_wrap, symbols_size) \
- else \
- buf[j].symbol = i; \
+ else \
+ buf[j].symbol = i; \
j++; \
}
COPY(buf[j].bits > nb_bits);
@@ -318,15 +339,19 @@ int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes,
ret = build_table(vlc, nb_bits, nb_codes, buf, flags);
- av_free(buf);
- if (ret < 0) {
- av_freep(&vlc->table);
- return ret;
+ if (flags & INIT_VLC_USE_NEW_STATIC) {
+ if(vlc->table_size != vlc->table_allocated)
+ av_log(NULL, AV_LOG_ERROR, "needed %d had %d\n", vlc->table_size, vlc->table_allocated);
+
+ av_assert0(ret >= 0);
+ *vlc_arg = *vlc;
+ } else {
+ av_free(buf);
+ if (ret < 0) {
+ av_freep(&vlc->table);
+ return ret;
+ }
}
- if ((flags & INIT_VLC_USE_NEW_STATIC) &&
- vlc->table_size != vlc->table_allocated)
- av_log(NULL, AV_LOG_ERROR, "needed %d had %d\n",
- vlc->table_size, vlc->table_allocated);
return 0;
}
diff --git a/libavcodec/bitstream_filter.c b/libavcodec/bitstream_filter.c
index 3b19bbdc76..a4e437df5f 100644
--- a/libavcodec/bitstream_filter.c
+++ b/libavcodec/bitstream_filter.c
@@ -1,26 +1,27 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "avcodec.h"
+#include "libavutil/atomic.h"
#include "libavutil/mem.h"
static AVBitStreamFilter *first_bitstream_filter = NULL;
@@ -35,15 +36,16 @@ AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f)
void av_register_bitstream_filter(AVBitStreamFilter *bsf)
{
- bsf->next = first_bitstream_filter;
- first_bitstream_filter = bsf;
+ do {
+ bsf->next = first_bitstream_filter;
+ } while(bsf->next != avpriv_atomic_ptr_cas((void * volatile *)&first_bitstream_filter, bsf->next, bsf));
}
AVBitStreamFilterContext *av_bitstream_filter_init(const char *name)
{
- AVBitStreamFilter *bsf = first_bitstream_filter;
+ AVBitStreamFilter *bsf = NULL;
- while (bsf) {
+ while (bsf = av_bitstream_filter_next(bsf)) {
if (!strcmp(name, bsf->name)) {
AVBitStreamFilterContext *bsfc =
av_mallocz(sizeof(AVBitStreamFilterContext));
@@ -60,13 +62,14 @@ AVBitStreamFilterContext *av_bitstream_filter_init(const char *name)
}
return bsfc;
}
- bsf = bsf->next;
}
return NULL;
}
void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc)
{
+ if (!bsfc)
+ return;
if (bsfc->filter->close)
bsfc->filter->close(bsfc);
av_freep(&bsfc->priv_data);
diff --git a/libavcodec/blockdsp.c b/libavcodec/blockdsp.c
index e3d2ca1fdc..f5259f637f 100644
--- a/libavcodec/blockdsp.c
+++ b/libavcodec/blockdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,6 +65,8 @@ av_cold void ff_blockdsp_init(BlockDSPContext *c, AVCodecContext *avctx)
c->fill_block_tab[0] = fill_block16_c;
c->fill_block_tab[1] = fill_block8_c;
+ if (ARCH_ALPHA)
+ ff_blockdsp_init_alpha(c, high_bit_depth);
if (ARCH_ARM)
ff_blockdsp_init_arm(c, high_bit_depth);
if (ARCH_PPC)
diff --git a/libavcodec/blockdsp.h b/libavcodec/blockdsp.h
index 32c671cf5a..c7ad265db1 100644
--- a/libavcodec/blockdsp.h
+++ b/libavcodec/blockdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,6 +40,7 @@ typedef struct BlockDSPContext {
void ff_blockdsp_init(BlockDSPContext *c, AVCodecContext *avctx);
+void ff_blockdsp_init_alpha(BlockDSPContext *c, unsigned high_bit_depth);
void ff_blockdsp_init_arm(BlockDSPContext *c, unsigned high_bit_depth);
void ff_blockdsp_init_ppc(BlockDSPContext *c, unsigned high_bit_depth);
#if FF_API_XVMC
diff --git a/libavcodec/bmp.c b/libavcodec/bmp.c
index 15c33a07c6..a35ed1ac1e 100644
--- a/libavcodec/bmp.c
+++ b/libavcodec/bmp.c
@@ -2,20 +2,20 @@
* BMP image format decoder
* Copyright (c) 2005 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,7 +40,8 @@ static int bmp_decode_frame(AVCodecContext *avctx,
BiCompression comp;
unsigned int ihsize;
int i, j, n, linesize, ret;
- uint32_t rgb[3];
+ uint32_t rgb[3] = {0};
+ uint32_t alpha = 0;
uint8_t *ptr;
int dsize;
const uint8_t *buf0 = buf;
@@ -69,7 +70,7 @@ static int bmp_decode_frame(AVCodecContext *avctx,
hsize = bytestream_get_le32(&buf); /* header size */
ihsize = bytestream_get_le32(&buf); /* more header size */
- if (ihsize + 14 > hsize) {
+ if (ihsize + 14LL > hsize) {
av_log(avctx, AV_LOG_ERROR, "invalid header size %u\n", hsize);
return AVERROR_INVALIDDATA;
}
@@ -86,7 +87,8 @@ static int bmp_decode_frame(AVCodecContext *avctx,
}
switch (ihsize) {
- case 40: // windib v3
+ case 40: // windib
+ case 56: // windib v3
case 64: // OS/2 v2
case 108: // windib v4
case 124: // windib v5
@@ -110,7 +112,7 @@ static int bmp_decode_frame(AVCodecContext *avctx,
depth = bytestream_get_le16(&buf);
- if (ihsize == 40)
+ if (ihsize >= 40)
comp = bytestream_get_le32(&buf);
else
comp = BMP_RGB;
@@ -126,6 +128,8 @@ static int bmp_decode_frame(AVCodecContext *avctx,
rgb[0] = bytestream_get_le32(&buf);
rgb[1] = bytestream_get_le32(&buf);
rgb[2] = bytestream_get_le32(&buf);
+ if (ihsize > 40)
+ alpha = bytestream_get_le32(&buf);
}
avctx->width = width;
@@ -136,21 +140,21 @@ static int bmp_decode_frame(AVCodecContext *avctx,
switch (depth) {
case 32:
if (comp == BMP_BITFIELDS) {
- rgb[0] = (rgb[0] >> 15) & 3;
- rgb[1] = (rgb[1] >> 15) & 3;
- rgb[2] = (rgb[2] >> 15) & 3;
-
- if (rgb[0] + rgb[1] + rgb[2] != 3 ||
- rgb[0] == rgb[1] || rgb[0] == rgb[2] || rgb[1] == rgb[2]) {
- break;
+ if (rgb[0] == 0xFF000000 && rgb[1] == 0x00FF0000 && rgb[2] == 0x0000FF00)
+ avctx->pix_fmt = alpha ? AV_PIX_FMT_ABGR : AV_PIX_FMT_0BGR;
+ else if (rgb[0] == 0x00FF0000 && rgb[1] == 0x0000FF00 && rgb[2] == 0x000000FF)
+ avctx->pix_fmt = alpha ? AV_PIX_FMT_BGRA : AV_PIX_FMT_BGR0;
+ else if (rgb[0] == 0x0000FF00 && rgb[1] == 0x00FF0000 && rgb[2] == 0xFF000000)
+ avctx->pix_fmt = alpha ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB;
+ else if (rgb[0] == 0x000000FF && rgb[1] == 0x0000FF00 && rgb[2] == 0x00FF0000)
+ avctx->pix_fmt = alpha ? AV_PIX_FMT_RGBA : AV_PIX_FMT_RGB0;
+ else {
+ av_log(avctx, AV_LOG_ERROR, "Unknown bitfields %0X %0X %0X\n", rgb[0], rgb[1], rgb[2]);
+ return AVERROR(EINVAL);
}
} else {
- rgb[0] = 2;
- rgb[1] = 1;
- rgb[2] = 0;
+ avctx->pix_fmt = AV_PIX_FMT_BGRA;
}
-
- avctx->pix_fmt = AV_PIX_FMT_BGR24;
break;
case 24:
avctx->pix_fmt = AV_PIX_FMT_BGR24;
@@ -199,10 +203,8 @@ static int bmp_decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
@@ -210,12 +212,16 @@ static int bmp_decode_frame(AVCodecContext *avctx,
dsize = buf_size - hsize;
/* Line size in file multiple of 4 */
- n = ((avctx->width * depth) / 8 + 3) & ~3;
+ n = ((avctx->width * depth + 31) / 8) & ~3;
if (n * avctx->height > dsize && comp != BMP_RLE4 && comp != BMP_RLE8) {
- av_log(avctx, AV_LOG_ERROR, "not enough data (%d < %d)\n",
- dsize, n * avctx->height);
- return AVERROR_INVALIDDATA;
+ n = (avctx->width * depth + 7) / 8;
+ if (n * avctx->height > dsize) {
+ av_log(avctx, AV_LOG_ERROR, "not enough data (%d < %d)\n",
+ dsize, n * avctx->height);
+ return AVERROR_INVALIDDATA;
+ }
+ av_log(avctx, AV_LOG_ERROR, "data size too small, assuming missing line alignment\n");
}
// RLE may skip decoding some picture areas, so blank picture before decoding
@@ -246,20 +252,26 @@ static int bmp_decode_frame(AVCodecContext *avctx,
} else if (t) {
colors = t;
}
+ } else {
+ colors = FFMIN(256, (hsize-ihsize-14) / 3);
}
buf = buf0 + 14 + ihsize; //palette location
// OS/2 bitmap, 3 bytes per palette entry
if ((hsize-ihsize-14) < (colors << 2)) {
+ if ((hsize-ihsize-14) < colors * 3) {
+ av_log(avctx, AV_LOG_ERROR, "palette doesn't fit in packet\n");
+ return AVERROR_INVALIDDATA;
+ }
for (i = 0; i < colors; i++)
- ((uint32_t*)p->data[1])[i] = bytestream_get_le24(&buf);
+ ((uint32_t*)p->data[1])[i] = (0xFFU<<24) | bytestream_get_le24(&buf);
} else {
for (i = 0; i < colors; i++)
- ((uint32_t*)p->data[1])[i] = bytestream_get_le32(&buf);
+ ((uint32_t*)p->data[1])[i] = 0xFFU << 24 | bytestream_get_le32(&buf);
}
buf = buf0 + hsize;
}
if (comp == BMP_RLE4 || comp == BMP_RLE8) {
- if (height < 0) {
+ if (comp == BMP_RLE8 && height < 0) {
p->data[0] += p->linesize[0] * (avctx->height - 1);
p->linesize[0] = -p->linesize[0];
}
@@ -290,6 +302,7 @@ static int bmp_decode_frame(AVCodecContext *avctx,
break;
case 8:
case 24:
+ case 32:
for (i = 0; i < avctx->height; i++) {
memcpy(ptr, buf, n);
buf += n;
@@ -319,23 +332,6 @@ static int bmp_decode_frame(AVCodecContext *avctx,
ptr += linesize;
}
break;
- case 32:
- for (i = 0; i < avctx->height; i++) {
- const uint8_t *src = buf;
- uint8_t *dst = ptr;
-
- for (j = 0; j < avctx->width; j++) {
- dst[0] = src[rgb[2]];
- dst[1] = src[rgb[1]];
- dst[2] = src[rgb[0]];
- dst += 3;
- src += 4;
- }
-
- buf += n;
- ptr += linesize;
- }
- break;
default:
av_log(avctx, AV_LOG_ERROR, "BMP decoder is broken\n");
return AVERROR_INVALIDDATA;
diff --git a/libavcodec/bmp.h b/libavcodec/bmp.h
index a472f59d3c..fb21090678 100644
--- a/libavcodec/bmp.h
+++ b/libavcodec/bmp.h
@@ -2,20 +2,20 @@
* internals for BMP codecs
* Copyright (c) 2005 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bmp_parser.c b/libavcodec/bmp_parser.c
index b85dd8bcb5..c9493dc32d 100644
--- a/libavcodec/bmp_parser.c
+++ b/libavcodec/bmp_parser.c
@@ -2,20 +2,20 @@
* BMP parser
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,21 +45,32 @@ static int bmp_parse(AVCodecParserContext *s, AVCodecContext *avctx,
int i = 0;
*poutbuf_size = 0;
- if (buf_size == 0)
- return 0;
- if (!bpc->pc.frame_start_found) {
+restart:
+ if (bpc->pc.frame_start_found <= 2+4+4) {
for (; i < buf_size; i++) {
state = (state << 8) | buf[i];
- if ((state >> 48) == (('B' << 8) | 'M')) {
- bpc->fsize = av_bswap32(state >> 16);
- bpc->pc.frame_start_found = 1;
- if (bpc->fsize > buf_size - i + 7)
- bpc->remaining_size = bpc->fsize - buf_size + i - 7;
- else
- next = bpc->fsize + i - 7;
- break;
- }
+ if (bpc->pc.frame_start_found == 0) {
+ if ((state >> 48) == (('B' << 8) | 'M')) {
+ bpc->fsize = av_bswap32(state >> 16);
+ bpc->pc.frame_start_found = 1;
+ }
+ } else if (bpc->pc.frame_start_found == 2+4+4) {
+// unsigned hsize = av_bswap32(state>>32);
+ unsigned ihsize = av_bswap32(state);
+ if (ihsize < 12 || ihsize > 200) {
+ bpc->pc.frame_start_found = 0;
+ continue;
+ }
+ bpc->pc.frame_start_found++;
+ bpc->remaining_size = bpc->fsize + i - 17;
+
+ if (bpc->pc.index + i > 17) {
+ next = i - 17;
+ } else
+ goto restart;
+ } else if (bpc->pc.frame_start_found)
+ bpc->pc.frame_start_found++;
}
bpc->pc.state64 = state;
} else {
@@ -68,7 +79,9 @@ static int bmp_parse(AVCodecParserContext *s, AVCodecContext *avctx,
bpc->remaining_size -= i;
if (bpc->remaining_size)
goto flush;
- next = i;
+
+ bpc->pc.frame_start_found = 0;
+ goto restart;
}
}
diff --git a/libavcodec/bmpenc.c b/libavcodec/bmpenc.c
index a14fc61c15..2a1956dc4a 100644
--- a/libavcodec/bmpenc.c
+++ b/libavcodec/bmpenc.c
@@ -3,24 +3,25 @@
* Copyright (c) 2006, 2007 Michel Bardiaux
* Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "bytestream.h"
#include "bmp.h"
@@ -32,6 +33,9 @@ static const uint32_t rgb444_masks[] = { 0x0F00, 0x00F0, 0x000F };
static av_cold int bmp_encode_init(AVCodecContext *avctx){
switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_BGRA:
+ avctx->bits_per_coded_sample = 32;
+ break;
case AV_PIX_FMT_BGR24:
avctx->bits_per_coded_sample = 24;
break;
@@ -53,7 +57,7 @@ static av_cold int bmp_encode_init(AVCodecContext *avctx){
break;
default:
av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n");
- return -1;
+ return AVERROR(EINVAL);
}
avctx->coded_frame = av_frame_alloc();
@@ -69,6 +73,7 @@ static int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame * const p = pict;
int n_bytes_image, n_bytes_per_row, n_bytes, i, n, hsize, ret;
const uint32_t *pal = NULL;
+ uint32_t palette256[256];
int pad_bytes_per_row, pal_entries = 0, compression = BMP_RGB;
int bit_count = avctx->bits_per_coded_sample;
uint8_t *ptr, *buf;
@@ -91,7 +96,10 @@ static int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case AV_PIX_FMT_RGB4_BYTE:
case AV_PIX_FMT_BGR4_BYTE:
case AV_PIX_FMT_GRAY8:
- avpriv_set_systematic_pal2((uint32_t*)p->data[1], avctx->pix_fmt);
+ av_assert1(bit_count == 8);
+ avpriv_set_systematic_pal2(palette256, avctx->pix_fmt);
+ pal = palette256;
+ break;
case AV_PIX_FMT_PAL8:
pal = (uint32_t *)p->data[1];
break;
@@ -110,10 +118,8 @@ static int bmp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
#define SIZE_BITMAPINFOHEADER 40
hsize = SIZE_BITMAPFILEHEADER + SIZE_BITMAPINFOHEADER + (pal_entries << 2);
n_bytes = n_bytes_image + hsize;
- if ((ret = ff_alloc_packet(pkt, n_bytes)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, n_bytes)) < 0)
return ret;
- }
buf = pkt->data;
bytestream_put_byte(&buf, 'B'); // BITMAPFILEHEADER.bfType
bytestream_put_byte(&buf, 'M'); // do.
@@ -172,8 +178,8 @@ AVCodec ff_bmp_encoder = {
.encode2 = bmp_encode_frame,
.close = bmp_encode_close,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_BGR24,
- AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444, AV_PIX_FMT_RGB565,
+ AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGB565, AV_PIX_FMT_RGB555, AV_PIX_FMT_RGB444,
AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8,
AV_PIX_FMT_MONOBLACK,
AV_PIX_FMT_NONE
diff --git a/libavcodec/bmvaudio.c b/libavcodec/bmvaudio.c
index 0f8c2249b2..0e473df90c 100644
--- a/libavcodec/bmvaudio.c
+++ b/libavcodec/bmvaudio.c
@@ -2,20 +2,20 @@
* Discworld II BMV audio decoder
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,10 +58,8 @@ static int bmv_aud_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = total_blocks * 32;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
output_samples = (int16_t *)frame->data[0];
for (blocks = 0; blocks < total_blocks; blocks++) {
diff --git a/libavcodec/bmvvideo.c b/libavcodec/bmvvideo.c
index ebc8e7a082..76a3d6f1f6 100644
--- a/libavcodec/bmvvideo.c
+++ b/libavcodec/bmvvideo.c
@@ -2,23 +2,24 @@
* Discworld II BMV video decoder
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avcodec.h"
@@ -50,7 +51,7 @@ typedef struct BMVDecContext {
const uint8_t *stream;
} BMVDecContext;
-#define NEXT_BYTE(v) v = forward ? v + 1 : v - 1;
+#define NEXT_BYTE(v) (v) = forward ? (v) + 1 : (v) - 1;
static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame, int frame_off)
{
@@ -100,6 +101,8 @@ static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame,
}
if (!(val & 0xC)) {
for (;;) {
+ if(shift>22)
+ return -1;
if (!read_two_nibbles) {
if (src < source || src >= source_end)
return AVERROR_INVALIDDATA;
@@ -133,6 +136,7 @@ static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame,
}
advance_mode = val & 1;
len = (val >> 1) - 1;
+ av_assert0(len>0);
mode += 1 + advance_mode;
if (mode >= 4)
mode -= 3;
@@ -185,8 +189,6 @@ static int decode_bmv_frame(const uint8_t *source, int src_len, uint8_t *frame,
memset(dst, val, len);
}
break;
- default:
- break;
}
if (dst == dst_end)
return 0;
@@ -227,7 +229,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
for (i = 0; i < 256; i++)
- c->pal[i] = bytestream_get_be24(&c->stream);
+ c->pal[i] = 0xFFU << 24 | bytestream_get_be24(&c->stream);
}
if (type & BMV_SCROLL) {
if (c->stream - pkt->data > pkt->size - 2) {
@@ -241,10 +243,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
scr_off = 0;
}
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if (decode_bmv_frame(c->stream, pkt->size - (c->stream - pkt->data), c->frame, scr_off)) {
av_log(avctx, AV_LOG_ERROR, "Error decoding frame data\n");
@@ -276,6 +276,11 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ if (avctx->width != SCREEN_WIDE || avctx->height != SCREEN_HIGH) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid dimension %dx%d\n", avctx->width, avctx->height);
+ return AVERROR_INVALIDDATA;
+ }
+
c->frame = c->frame_base + 640;
return 0;
diff --git a/libavcodec/brenderpix.c b/libavcodec/brenderpix.c
index 25aebed7d7..02d922f8f5 100644
--- a/libavcodec/brenderpix.c
+++ b/libavcodec/brenderpix.c
@@ -2,20 +2,20 @@
* BRender PIX (.pix) image decoder
* Copyright (c) 2012 Aleksi Nurmi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -134,7 +134,7 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
{
AVFrame *frame = data;
- int ret, i, j;
+ int ret, i;
GetByteContext gb;
unsigned int bytes_pp;
@@ -142,6 +142,7 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
unsigned int chunk_type;
unsigned int data_len;
unsigned int bytes_per_scanline;
+ unsigned int bytes_left;
PixHeader hdr;
bytestream2_init(&gb, avpkt->data, avpkt->size);
@@ -168,7 +169,7 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ret = pix_decode_header(&hdr, &gb);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Invalid header length.\n");
- return AVERROR_INVALIDDATA;
+ return ret;
}
switch (hdr.format) {
case 3:
@@ -187,7 +188,10 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
avctx->pix_fmt = AV_PIX_FMT_RGB24;
bytes_pp = 3;
break;
- case 7: // XRGB
+ case 7:
+ avctx->pix_fmt = AV_PIX_FMT_0RGB;
+ bytes_pp = 4;
+ break;
case 8: // ARGB
avctx->pix_fmt = AV_PIX_FMT_ARGB;
bytes_pp = 4;
@@ -219,22 +223,21 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ret = pix_decode_header(&palhdr, &gb);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Invalid palette header length.\n");
- return AVERROR_INVALIDDATA;
+ return ret;
}
if (palhdr.format != 7)
avpriv_request_sample(avctx, "Palette not in RGB format");
chunk_type = bytestream2_get_be32(&gb);
data_len = bytestream2_get_be32(&gb);
- if (chunk_type != IMAGE_DATA_CHUNK ||
- bytestream2_get_bytes_left(&gb) < data_len) {
+ bytestream2_skip(&gb, 8);
+ if (chunk_type != IMAGE_DATA_CHUNK || data_len != 1032 ||
+ bytestream2_get_bytes_left(&gb) < 1032) {
av_log(avctx, AV_LOG_ERROR, "Invalid palette data.\n");
return AVERROR_INVALIDDATA;
}
-
// palette data is surrounded by 8 null bytes (both top and bottom)
- bytestream2_skip(&gb, 8);
- // convert to machine endian format (ARGB)
+ // convert 0RGB to machine endian format (ARGB32)
for (i = 0; i < 256; ++i)
*pal_out++ = (0xFFU << 24) | bytestream2_get_be32u(&gb);
bytestream2_skip(&gb, 8);
@@ -259,9 +262,10 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
// read the image data to the buffer
bytes_per_scanline = bytes_pp * hdr.width;
- if (chunk_type != IMAGE_DATA_CHUNK ||
- data_len < bytes_per_scanline * hdr.height ||
- bytestream2_get_bytes_left(&gb) < data_len) {
+ bytes_left = bytestream2_get_bytes_left(&gb);
+
+ if (chunk_type != IMAGE_DATA_CHUNK || data_len != bytes_left ||
+ bytes_left / bytes_per_scanline < hdr.height) {
av_log(avctx, AV_LOG_ERROR, "Invalid image data.\n");
return AVERROR_INVALIDDATA;
}
@@ -271,12 +275,6 @@ static int pix_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
bytes_per_scanline,
bytes_per_scanline, hdr.height);
- // make alpha opaque for XRGB
- if (hdr.format == 7)
- for (j = 0; j < frame->height; j++)
- for (i = 0; i < frame->linesize[0]; i += 4)
- frame->data[0][j * frame->linesize[0] + i] = 0xFF;
-
frame->pict_type = AV_PICTURE_TYPE_I;
frame->key_frame = 1;
*got_frame = 1;
diff --git a/libavcodec/bswapdsp.c b/libavcodec/bswapdsp.c
index 6700cfd980..a6e1ec069c 100644
--- a/libavcodec/bswapdsp.c
+++ b/libavcodec/bswapdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bswapdsp.h b/libavcodec/bswapdsp.h
index fd10a8892c..f167d77fea 100644
--- a/libavcodec/bswapdsp.h
+++ b/libavcodec/bswapdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/bytestream.h b/libavcodec/bytestream.h
index 3eab225f9c..c2cb601806 100644
--- a/libavcodec/bytestream.h
+++ b/libavcodec/bytestream.h
@@ -3,20 +3,20 @@
* copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@free.fr>
* Copyright (c) 2012 Aneesh Dogra (lionaneesh) <lionaneesh@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include <stdint.h>
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
@@ -131,6 +132,7 @@ static av_always_inline void bytestream2_init(GetByteContext *g,
const uint8_t *buf,
int buf_size)
{
+ av_assert0(buf_size >= 0);
g->buffer = buf;
g->buffer_start = buf;
g->buffer_end = buf + buf_size;
@@ -140,6 +142,7 @@ static av_always_inline void bytestream2_init_writer(PutByteContext *p,
uint8_t *buf,
int buf_size)
{
+ av_assert0(buf_size >= 0);
p->buffer = buf;
p->buffer_start = buf;
p->buffer_end = buf + buf_size;
diff --git a/libavcodec/c93.c b/libavcodec/c93.c
index 2729ee8fcb..eff8887c27 100644
--- a/libavcodec/c93.c
+++ b/libavcodec/c93.c
@@ -2,20 +2,20 @@
* Interplay C93 video decoder
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -133,12 +133,13 @@ static int decode_frame(AVCodecContext *avctx, void *data,
uint8_t *out;
int stride, ret, i, x, y, b, bt = 0;
+ if ((ret = ff_set_dimensions(avctx, WIDTH, HEIGHT)) < 0)
+ return ret;
+
c93->currentpic ^= 1;
- if ((ret = ff_reget_buffer(avctx, newpic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, newpic)) < 0)
return ret;
- }
stride = newpic->linesize[0];
@@ -176,7 +177,14 @@ static int decode_frame(AVCodecContext *avctx, void *data,
case C93_4X4_FROM_PREV:
for (j = 0; j < 8; j += 4) {
for (i = 0; i < 8; i += 4) {
- offset = bytestream2_get_le16(&gb);
+ int offset = bytestream2_get_le16(&gb);
+ int from_x = offset % WIDTH;
+ int from_y = offset / WIDTH;
+ if (block_type == C93_4X4_FROM_CURR && from_y == y+j &&
+ (FFABS(from_x - x-i) < 4 || FFABS(from_x - x-i) > WIDTH-4)) {
+ avpriv_request_sample(avctx, "block overlap %d %d %d %d\n", from_x, x+i, from_y, y+j);
+ return AVERROR_INVALIDDATA;
+ }
if ((ret = copy_block(avctx, &out[j*stride+i],
copy_from, offset, 4, stride)) < 0)
return ret;
@@ -236,7 +244,7 @@ static int decode_frame(AVCodecContext *avctx, void *data,
if (b & C93_HAS_PALETTE) {
uint32_t *palette = (uint32_t *) newpic->data[1];
for (i = 0; i < 256; i++) {
- palette[i] = bytestream2_get_be24(&gb);
+ palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb);
}
newpic->palette_has_changed = 1;
} else {
diff --git a/libavcodec/cabac.c b/libavcodec/cabac.c
index b6f56f05ec..8cc9333e09 100644
--- a/libavcodec/cabac.c
+++ b/libavcodec/cabac.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,80 +27,25 @@
#include <string.h>
#include "libavutil/common.h"
+#include "libavutil/timer.h"
#include "get_bits.h"
#include "cabac.h"
#include "cabac_functions.h"
-uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63] = {
- 9,8,7,7,6,6,6,6,5,5,5,5,5,5,5,5,
- 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-};
-
-static const uint8_t lps_range[64][4]= {
-{128,176,208,240}, {128,167,197,227}, {128,158,187,216}, {123,150,178,205},
-{116,142,169,195}, {111,135,160,185}, {105,128,152,175}, {100,122,144,166},
-{ 95,116,137,158}, { 90,110,130,150}, { 85,104,123,142}, { 81, 99,117,135},
-{ 77, 94,111,128}, { 73, 89,105,122}, { 69, 85,100,116}, { 66, 80, 95,110},
-{ 62, 76, 90,104}, { 59, 72, 86, 99}, { 56, 69, 81, 94}, { 53, 65, 77, 89},
-{ 51, 62, 73, 85}, { 48, 59, 69, 80}, { 46, 56, 66, 76}, { 43, 53, 63, 72},
-{ 41, 50, 59, 69}, { 39, 48, 56, 65}, { 37, 45, 54, 62}, { 35, 43, 51, 59},
-{ 33, 41, 48, 56}, { 32, 39, 46, 53}, { 30, 37, 43, 50}, { 29, 35, 41, 48},
-{ 27, 33, 39, 45}, { 26, 31, 37, 43}, { 24, 30, 35, 41}, { 23, 28, 33, 39},
-{ 22, 27, 32, 37}, { 21, 26, 30, 35}, { 20, 24, 29, 33}, { 19, 23, 27, 31},
-{ 18, 22, 26, 30}, { 17, 21, 25, 28}, { 16, 20, 23, 27}, { 15, 19, 22, 25},
-{ 14, 18, 21, 24}, { 14, 17, 20, 23}, { 13, 16, 19, 22}, { 12, 15, 18, 21},
-{ 12, 14, 17, 20}, { 11, 14, 16, 19}, { 11, 13, 15, 18}, { 10, 12, 15, 17},
-{ 10, 12, 14, 16}, { 9, 11, 13, 15}, { 9, 11, 12, 14}, { 8, 10, 12, 14},
-{ 8, 9, 11, 13}, { 7, 9, 11, 12}, { 7, 9, 10, 12}, { 7, 8, 10, 11},
-{ 6, 8, 9, 11}, { 6, 7, 9, 10}, { 6, 7, 8, 9}, { 2, 2, 2, 2},
-};
-
-static const uint8_t mps_state[64]= {
- 1, 2, 3, 4, 5, 6, 7, 8,
- 9,10,11,12,13,14,15,16,
- 17,18,19,20,21,22,23,24,
- 25,26,27,28,29,30,31,32,
- 33,34,35,36,37,38,39,40,
- 41,42,43,44,45,46,47,48,
- 49,50,51,52,53,54,55,56,
- 57,58,59,60,61,62,62,63,
-};
-
-static const uint8_t lps_state[64]= {
- 0, 0, 1, 2, 2, 4, 4, 5,
- 6, 7, 8, 9, 9,11,11,12,
- 13,13,15,15,16,16,18,18,
- 19,19,21,21,22,22,23,24,
- 24,25,26,26,27,27,28,29,
- 29,30,30,30,31,32,32,33,
- 33,33,34,34,35,35,35,36,
- 36,36,37,37,37,38,38,63,
-};
-
-static const uint8_t last_coeff_flag_offset_8x8[63] = {
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8
-};
+#include "cabac_tablegen.h"
+
+/**
+ *
+ * @param buf_size size of buf in bits
+ */
+void ff_init_cabac_encoder(CABACContext *c, uint8_t *buf, int buf_size){
+ init_put_bits(&c->pb, buf, buf_size);
+
+ c->low= 0;
+ c->range= 0x1FE;
+ c->outstanding_count= 0;
+ c->pb.bit_left++; //avoids firstBitFlag
+}
/**
*
@@ -123,32 +68,158 @@ void ff_init_cabac_decoder(CABACContext *c, const uint8_t *buf, int buf_size){
void ff_init_cabac_states(void)
{
- int i, j;
static int initialized = 0;
if (initialized)
return;
- for(i=0; i<64; i++){
- for(j=0; j<4; j++){ //FIXME check if this is worth the 1 shift we save
- ff_h264_lps_range[j*2*64+2*i+0]=
- ff_h264_lps_range[j*2*64+2*i+1]= lps_range[i][j];
- }
+ cabac_tableinit();
+
+ initialized = 1;
+}
- ff_h264_mlps_state[128 + 2 * i + 0] = 2 * mps_state[i] + 0;
- ff_h264_mlps_state[128 + 2 * i + 1] = 2 * mps_state[i] + 1;
+#ifdef TEST
+#define SIZE 10240
- if( i ){
- ff_h264_mlps_state[128-2*i-1]= 2*lps_state[i]+0;
- ff_h264_mlps_state[128-2*i-2]= 2*lps_state[i]+1;
+#include "libavutil/lfg.h"
+#include "avcodec.h"
+
+static inline void put_cabac_bit(CABACContext *c, int b){
+ put_bits(&c->pb, 1, b);
+ for(;c->outstanding_count; c->outstanding_count--){
+ put_bits(&c->pb, 1, 1-b);
+ }
+}
+
+static inline void renorm_cabac_encoder(CABACContext *c){
+ while(c->range < 0x100){
+ //FIXME optimize
+ if(c->low<0x100){
+ put_cabac_bit(c, 0);
+ }else if(c->low<0x200){
+ c->outstanding_count++;
+ c->low -= 0x100;
}else{
- ff_h264_mlps_state[128-2*i-1]= 1;
- ff_h264_mlps_state[128-2*i-2]= 0;
+ put_cabac_bit(c, 1);
+ c->low -= 0x200;
}
+
+ c->range+= c->range;
+ c->low += c->low;
}
- for(i=0; i< 63; i++){
- ff_h264_last_coeff_flag_offset_8x8[i] = last_coeff_flag_offset_8x8[i];
+}
+
+static void put_cabac(CABACContext *c, uint8_t * const state, int bit){
+ int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + *state];
+
+ if(bit == ((*state)&1)){
+ c->range -= RangeLPS;
+ *state = ff_h264_mlps_state[128 + *state];
+ }else{
+ c->low += c->range - RangeLPS;
+ c->range = RangeLPS;
+ *state= ff_h264_mlps_state[127 - *state];
}
- initialized = 1;
+ renorm_cabac_encoder(c);
+}
+
+/**
+ * @param bit 0 -> write zero bit, !=0 write one bit
+ */
+static void put_cabac_bypass(CABACContext *c, int bit){
+ c->low += c->low;
+
+ if(bit){
+ c->low += c->range;
+ }
+//FIXME optimize
+ if(c->low<0x200){
+ put_cabac_bit(c, 0);
+ }else if(c->low<0x400){
+ c->outstanding_count++;
+ c->low -= 0x200;
+ }else{
+ put_cabac_bit(c, 1);
+ c->low -= 0x400;
+ }
+}
+
+/**
+ *
+ * @return the number of bytes written
+ */
+static int put_cabac_terminate(CABACContext *c, int bit){
+ c->range -= 2;
+
+ if(!bit){
+ renorm_cabac_encoder(c);
+ }else{
+ c->low += c->range;
+ c->range= 2;
+
+ renorm_cabac_encoder(c);
+
+ av_assert0(c->low <= 0x1FF);
+ put_cabac_bit(c, c->low>>9);
+ put_bits(&c->pb, 2, ((c->low>>7)&3)|1);
+
+ flush_put_bits(&c->pb); //FIXME FIXME FIXME XXX wrong
+ }
+
+ return (put_bits_count(&c->pb)+7)>>3;
}
+
+int main(void){
+ CABACContext c;
+ uint8_t b[9*SIZE];
+ uint8_t r[9*SIZE];
+ int i, ret = 0;
+ uint8_t state[10]= {0};
+ AVLFG prng;
+
+ av_lfg_init(&prng, 1);
+ ff_init_cabac_encoder(&c, b, SIZE);
+ ff_init_cabac_states();
+
+ for(i=0; i<SIZE; i++){
+ if(2*i<SIZE) r[i] = av_lfg_get(&prng) % 7;
+ else r[i] = (i>>8)&1;
+ }
+
+ for(i=0; i<SIZE; i++){
+ put_cabac_bypass(&c, r[i]&1);
+ }
+
+ for(i=0; i<SIZE; i++){
+ put_cabac(&c, state, r[i]&1);
+ }
+
+ put_cabac_terminate(&c, 1);
+
+ ff_init_cabac_decoder(&c, b, SIZE);
+
+ memset(state, 0, sizeof(state));
+
+ for(i=0; i<SIZE; i++){
+ if( (r[i]&1) != get_cabac_bypass(&c) ) {
+ av_log(NULL, AV_LOG_ERROR, "CABAC bypass failure at %d\n", i);
+ ret = 1;
+ }
+ }
+
+ for(i=0; i<SIZE; i++){
+ if( (r[i]&1) != get_cabac_noinline(&c, state) ) {
+ av_log(NULL, AV_LOG_ERROR, "CABAC failure at %d\n", i);
+ ret = 1;
+ }
+ }
+ if(!get_cabac_terminate(&c)) {
+ av_log(NULL, AV_LOG_ERROR, "where's the Terminator?\n");
+ ret = 1;
+ }
+
+ return ret;
+}
+
+#endif /* TEST */
diff --git a/libavcodec/cabac.h b/libavcodec/cabac.h
index 426f338e34..f9eafed105 100644
--- a/libavcodec/cabac.h
+++ b/libavcodec/cabac.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,12 @@
#include "put_bits.h"
-extern uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
+#if CONFIG_HARDCODED_TABLES
+#define CABAC_TABLE_CONST const
+#else
+#define CABAC_TABLE_CONST
+#endif
+extern CABAC_TABLE_CONST uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
#define H264_NORM_SHIFT_OFFSET 0
#define H264_LPS_RANGE_OFFSET 512
#define H264_MLPS_STATE_OFFSET 1024
@@ -43,11 +48,14 @@ extern uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
typedef struct CABACContext{
int low;
int range;
+ int outstanding_count;
const uint8_t *bytestream_start;
const uint8_t *bytestream;
const uint8_t *bytestream_end;
+ PutBitContext pb;
}CABACContext;
+void ff_init_cabac_encoder(CABACContext *c, uint8_t *buf, int buf_size);
void ff_init_cabac_decoder(CABACContext *c, const uint8_t *buf, int buf_size);
void ff_init_cabac_states(void);
diff --git a/libavcodec/cabac_functions.h b/libavcodec/cabac_functions.h
index 4b8f1bca8a..15dba29f8e 100644
--- a/libavcodec/cabac_functions.h
+++ b/libavcodec/cabac_functions.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,10 @@
#include "cabac.h"
#include "config.h"
+#ifndef UNCHECKED_BITSTREAM_READER
+#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
+#endif
+
#if ARCH_AARCH64
# include "aarch64/cabac.h"
#endif
@@ -42,10 +46,10 @@
# include "x86/cabac.h"
#endif
-static uint8_t * const ff_h264_norm_shift = ff_h264_cabac_tables + H264_NORM_SHIFT_OFFSET;
-static uint8_t * const ff_h264_lps_range = ff_h264_cabac_tables + H264_LPS_RANGE_OFFSET;
-static uint8_t * const ff_h264_mlps_state = ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET;
-static uint8_t * const ff_h264_last_coeff_flag_offset_8x8 = ff_h264_cabac_tables + H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET;
+static CABAC_TABLE_CONST uint8_t * const ff_h264_norm_shift = ff_h264_cabac_tables + H264_NORM_SHIFT_OFFSET;
+static CABAC_TABLE_CONST uint8_t * const ff_h264_lps_range = ff_h264_cabac_tables + H264_LPS_RANGE_OFFSET;
+static CABAC_TABLE_CONST uint8_t * const ff_h264_mlps_state = ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET;
+static CABAC_TABLE_CONST uint8_t * const ff_h264_last_coeff_flag_offset_8x8 = ff_h264_cabac_tables + H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET;
static void refill(CABACContext *c){
#if CABAC_BITS == 16
@@ -54,7 +58,9 @@ static void refill(CABACContext *c){
c->low+= c->bytestream[0]<<1;
#endif
c->low -= CABAC_MASK;
+#if !UNCHECKED_BITSTREAM_READER
if (c->bytestream < c->bytestream_end)
+#endif
c->bytestream += CABAC_BITS / 8;
}
@@ -82,7 +88,9 @@ static void refill2(CABACContext *c){
#endif
c->low += x<<i;
+#if !UNCHECKED_BITSTREAM_READER
if (c->bytestream < c->bytestream_end)
+#endif
c->bytestream += CABAC_BITS/8;
}
diff --git a/libavcodec/cabac_tablegen.c b/libavcodec/cabac_tablegen.c
new file mode 100644
index 0000000000..ed5444759a
--- /dev/null
+++ b/libavcodec/cabac_tablegen.c
@@ -0,0 +1,41 @@
+/*
+ * Header file for hardcoded AAC SBR windows
+ *
+ * Copyright (c) 2014 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdlib.h>
+#include "libavutil/common.h"
+#include "cabac_functions.h"
+#undef CONFIG_HARDCODED_TABLES
+#define CONFIG_HARDCODED_TABLES 0
+av_const int av_log2(unsigned v) { int r = 0; while (v >>= 1) r++; return r; }
+#include "cabac_tablegen.h"
+#include "tableprint.h"
+
+int main(void)
+{
+ cabac_tableinit();
+
+ write_fileheader();
+
+ WRITE_ARRAY("const", uint8_t, ff_h264_cabac_tables);
+
+ return 0;
+}
diff --git a/libavcodec/cabac_tablegen.h b/libavcodec/cabac_tablegen.h
new file mode 100644
index 0000000000..a637912204
--- /dev/null
+++ b/libavcodec/cabac_tablegen.h
@@ -0,0 +1,108 @@
+/*
+ * Header file for hardcoded CABAC table
+ *
+ * Copyright (c) 2014 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_CABAC_TABLEGEN_H
+#define AVCODEC_CABAC_TABLEGEN_H
+
+#if CONFIG_HARDCODED_TABLES
+#define cabac_tableinit()
+#include "libavcodec/cabac_tables.h"
+#else
+uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
+
+static const uint8_t lps_range[64][4]= {
+{128,176,208,240}, {128,167,197,227}, {128,158,187,216}, {123,150,178,205},
+{116,142,169,195}, {111,135,160,185}, {105,128,152,175}, {100,122,144,166},
+{ 95,116,137,158}, { 90,110,130,150}, { 85,104,123,142}, { 81, 99,117,135},
+{ 77, 94,111,128}, { 73, 89,105,122}, { 69, 85,100,116}, { 66, 80, 95,110},
+{ 62, 76, 90,104}, { 59, 72, 86, 99}, { 56, 69, 81, 94}, { 53, 65, 77, 89},
+{ 51, 62, 73, 85}, { 48, 59, 69, 80}, { 46, 56, 66, 76}, { 43, 53, 63, 72},
+{ 41, 50, 59, 69}, { 39, 48, 56, 65}, { 37, 45, 54, 62}, { 35, 43, 51, 59},
+{ 33, 41, 48, 56}, { 32, 39, 46, 53}, { 30, 37, 43, 50}, { 29, 35, 41, 48},
+{ 27, 33, 39, 45}, { 26, 31, 37, 43}, { 24, 30, 35, 41}, { 23, 28, 33, 39},
+{ 22, 27, 32, 37}, { 21, 26, 30, 35}, { 20, 24, 29, 33}, { 19, 23, 27, 31},
+{ 18, 22, 26, 30}, { 17, 21, 25, 28}, { 16, 20, 23, 27}, { 15, 19, 22, 25},
+{ 14, 18, 21, 24}, { 14, 17, 20, 23}, { 13, 16, 19, 22}, { 12, 15, 18, 21},
+{ 12, 14, 17, 20}, { 11, 14, 16, 19}, { 11, 13, 15, 18}, { 10, 12, 15, 17},
+{ 10, 12, 14, 16}, { 9, 11, 13, 15}, { 9, 11, 12, 14}, { 8, 10, 12, 14},
+{ 8, 9, 11, 13}, { 7, 9, 11, 12}, { 7, 9, 10, 12}, { 7, 8, 10, 11},
+{ 6, 8, 9, 11}, { 6, 7, 9, 10}, { 6, 7, 8, 9}, { 2, 2, 2, 2},
+};
+
+static const uint8_t mps_state[64]= {
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9,10,11,12,13,14,15,16,
+ 17,18,19,20,21,22,23,24,
+ 25,26,27,28,29,30,31,32,
+ 33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,
+ 49,50,51,52,53,54,55,56,
+ 57,58,59,60,61,62,62,63,
+};
+
+static const uint8_t lps_state[64]= {
+ 0, 0, 1, 2, 2, 4, 4, 5,
+ 6, 7, 8, 9, 9,11,11,12,
+ 13,13,15,15,16,16,18,18,
+ 19,19,21,21,22,22,23,24,
+ 24,25,26,26,27,27,28,29,
+ 29,30,30,30,31,32,32,33,
+ 33,33,34,34,35,35,35,36,
+ 36,36,37,37,37,38,38,63,
+};
+
+static const uint8_t last_coeff_flag_offset_8x8[63] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8
+};
+
+static av_cold void cabac_tableinit(void)
+{
+ int i, j;
+ for (i = 0; i < 512; i++)
+ ff_h264_norm_shift[i] = i ? 8 - av_log2(i) : 9;
+
+ for(i=0; i<64; i++){
+ for(j=0; j<4; j++){ //FIXME check if this is worth the 1 shift we save
+ ff_h264_lps_range[j*2*64+2*i+0]=
+ ff_h264_lps_range[j*2*64+2*i+1]= lps_range[i][j];
+ }
+ ff_h264_mlps_state[128 + 2 * i + 0] = 2 * mps_state[i] + 0;
+ ff_h264_mlps_state[128 + 2 * i + 1] = 2 * mps_state[i] + 1;
+
+ if( i ){
+ ff_h264_mlps_state[128-2*i-1]= 2*lps_state[i]+0;
+ ff_h264_mlps_state[128-2*i-2]= 2*lps_state[i]+1;
+ }else{
+ ff_h264_mlps_state[128-2*i-1]= 1;
+ ff_h264_mlps_state[128-2*i-2]= 0;
+ }
+ }
+ for(i=0; i< 63; i++){
+ ff_h264_last_coeff_flag_offset_8x8[i] = last_coeff_flag_offset_8x8[i];
+ }
+}
+#endif /* CONFIG_HARDCODED_TABLES */
+
+#endif /* AVCODEC_CABAC_TABLEGEN_H */
diff --git a/libavcodec/canopus.c b/libavcodec/canopus.c
index 729e7ef876..ea6cc647d3 100644
--- a/libavcodec/canopus.c
+++ b/libavcodec/canopus.c
@@ -2,20 +2,20 @@
* Canopus common routines
* Copyright (c) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/canopus.h b/libavcodec/canopus.h
index 9e5702da30..faa1e8dfbf 100644
--- a/libavcodec/canopus.h
+++ b/libavcodec/canopus.h
@@ -2,20 +2,20 @@
* Canopus common routines
* Copyright (c) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/cavs.c b/libavcodec/cavs.c
index fac695843c..10a25d8749 100644
--- a/libavcodec/cavs.c
+++ b/libavcodec/cavs.c
@@ -2,20 +2,20 @@
* Chinese AVS video (AVS1-P2, JiZhun profile) decoder.
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -75,15 +75,16 @@ static inline int get_bs(cavs_vector *mvP, cavs_vector *mvQ, int b)
{
if ((mvP->ref == REF_INTRA) || (mvQ->ref == REF_INTRA))
return 2;
- if ((abs(mvP->x - mvQ->x) >= 4) || (abs(mvP->y - mvQ->y) >= 4))
+ if((abs(mvP->x - mvQ->x) >= 4) ||
+ (abs(mvP->y - mvQ->y) >= 4) ||
+ (mvP->ref != mvQ->ref))
return 1;
if (b) {
mvP += MV_BWD_OFFS;
mvQ += MV_BWD_OFFS;
- if ((abs(mvP->x - mvQ->x) >= 4) || (abs(mvP->y - mvQ->y) >= 4))
- return 1;
- } else {
- if (mvP->ref != mvQ->ref)
+ if((abs(mvP->x - mvQ->x) >= 4) ||
+ (abs(mvP->y - mvQ->y) >= 4) ||
+ (mvP->ref != mvQ->ref))
return 1;
}
return 0;
@@ -149,6 +150,8 @@ void ff_cavs_filter(AVSContext *h, enum cavs_mb mb_type)
qp_avg = (h->qp + h->left_qp + 1) >> 1;
SET_PARAMS;
h->cdsp.cavs_filter_lv(h->cy, h->l_stride, alpha, beta, tc, bs[0], bs[1]);
+ qp_avg = (ff_cavs_chroma_qp[h->qp] + ff_cavs_chroma_qp[h->left_qp] + 1) >> 1;
+ SET_PARAMS;
h->cdsp.cavs_filter_cv(h->cu, h->c_stride, alpha, beta, tc, bs[0], bs[1]);
h->cdsp.cavs_filter_cv(h->cv, h->c_stride, alpha, beta, tc, bs[0], bs[1]);
}
@@ -161,6 +164,8 @@ void ff_cavs_filter(AVSContext *h, enum cavs_mb mb_type)
qp_avg = (h->qp + h->top_qp[h->mbx] + 1) >> 1;
SET_PARAMS;
h->cdsp.cavs_filter_lh(h->cy, h->l_stride, alpha, beta, tc, bs[4], bs[5]);
+ qp_avg = (ff_cavs_chroma_qp[h->qp] + ff_cavs_chroma_qp[h->top_qp[h->mbx]] + 1) >> 1;
+ SET_PARAMS;
h->cdsp.cavs_filter_ch(h->cu, h->c_stride, alpha, beta, tc, bs[4], bs[5]);
h->cdsp.cavs_filter_ch(h->cv, h->c_stride, alpha, beta, tc, bs[4], bs[5]);
}
@@ -234,9 +239,14 @@ void ff_cavs_load_intra_pred_chroma(AVSContext *h)
/* extend borders by one pixel */
h->left_border_u[9] = h->left_border_u[8];
h->left_border_v[9] = h->left_border_v[8];
- h->top_border_u[h->mbx * 10 + 9] = h->top_border_u[h->mbx * 10 + 8];
- h->top_border_v[h->mbx * 10 + 9] = h->top_border_v[h->mbx * 10 + 8];
- if (h->mbx && h->mby) {
+ if(h->flags & C_AVAIL) {
+ h->top_border_u[h->mbx*10 + 9] = h->top_border_u[h->mbx*10 + 11];
+ h->top_border_v[h->mbx*10 + 9] = h->top_border_v[h->mbx*10 + 11];
+ } else {
+ h->top_border_u[h->mbx * 10 + 9] = h->top_border_u[h->mbx * 10 + 8];
+ h->top_border_v[h->mbx * 10 + 9] = h->top_border_v[h->mbx * 10 + 8];
+ }
+ if((h->flags & A_AVAIL) && (h->flags & B_AVAIL)) {
h->top_border_u[h->mbx * 10] = h->left_border_u[0] = h->topleft_border_u;
h->top_border_v[h->mbx * 10] = h->left_border_v[0] = h->topleft_border_v;
} else {
@@ -528,7 +538,7 @@ void ff_cavs_inter(AVSContext *h, enum cavs_mb mb_type)
static inline void scale_mv(AVSContext *h, int *d_x, int *d_y,
cavs_vector *src, int distp)
{
- int den = h->scale_den[src->ref];
+ int den = h->scale_den[FFMAX(src->ref, 0)];
*d_x = (src->x * distp * den + 256 + FF_SIGNBIT(src->x)) >> 9;
*d_y = (src->y * distp * den + 256 + FF_SIGNBIT(src->y)) >> 9;
@@ -575,7 +585,7 @@ void ff_cavs_mv(AVSContext *h, enum cavs_mv_loc nP, enum cavs_mv_loc nC,
mvP->ref = ref;
mvP->dist = h->dist[mvP->ref];
- if (mvC->ref == NOT_AVAIL)
+ if (mvC->ref == NOT_AVAIL || (nP == MV_FWD_X3) || (nP == MV_BWD_X3 ))
mvC = &h->mv[nP - 5]; // set to top-left (mvD)
if (mode == MV_PRED_PSKIP &&
(mvA->ref == NOT_AVAIL ||
@@ -705,7 +715,7 @@ int ff_cavs_next_mb(AVSContext *h)
*
****************************************************************************/
-void ff_cavs_init_pic(AVSContext *h)
+int ff_cavs_init_pic(AVSContext *h)
{
int i;
@@ -726,6 +736,8 @@ void ff_cavs_init_pic(AVSContext *h)
h->luma_scan[3] = 8 * h->l_stride + 8;
h->mbx = h->mby = h->mbidx = 0;
h->flags = 0;
+
+ return 0;
}
/*****************************************************************************
@@ -739,22 +751,39 @@ void ff_cavs_init_pic(AVSContext *h)
* this data has to be stored for one complete row of macroblocks
* and this storage space is allocated here
*/
-void ff_cavs_init_top_lines(AVSContext *h)
+int ff_cavs_init_top_lines(AVSContext *h)
{
/* alloc top line of predictors */
h->top_qp = av_mallocz(h->mb_width);
- h->top_mv[0] = av_mallocz((h->mb_width * 2 + 1) * sizeof(cavs_vector));
- h->top_mv[1] = av_mallocz((h->mb_width * 2 + 1) * sizeof(cavs_vector));
- h->top_pred_Y = av_mallocz(h->mb_width * 2 * sizeof(*h->top_pred_Y));
- h->top_border_y = av_mallocz((h->mb_width + 1) * 16);
- h->top_border_u = av_mallocz(h->mb_width * 10);
- h->top_border_v = av_mallocz(h->mb_width * 10);
+ h->top_mv[0] = av_mallocz_array(h->mb_width * 2 + 1, sizeof(cavs_vector));
+ h->top_mv[1] = av_mallocz_array(h->mb_width * 2 + 1, sizeof(cavs_vector));
+ h->top_pred_Y = av_mallocz_array(h->mb_width * 2, sizeof(*h->top_pred_Y));
+ h->top_border_y = av_mallocz_array(h->mb_width + 1, 16);
+ h->top_border_u = av_mallocz_array(h->mb_width, 10);
+ h->top_border_v = av_mallocz_array(h->mb_width, 10);
/* alloc space for co-located MVs and types */
- h->col_mv = av_mallocz(h->mb_width * h->mb_height * 4 *
- sizeof(cavs_vector));
+ h->col_mv = av_mallocz_array(h->mb_width * h->mb_height,
+ 4 * sizeof(cavs_vector));
h->col_type_base = av_mallocz(h->mb_width * h->mb_height);
h->block = av_mallocz(64 * sizeof(int16_t));
+
+ if (!h->top_qp || !h->top_mv[0] || !h->top_mv[1] || !h->top_pred_Y ||
+ !h->top_border_y || !h->top_border_u || !h->top_border_v ||
+ !h->col_mv || !h->col_type_base || !h->block) {
+ av_freep(&h->top_qp);
+ av_freep(&h->top_mv[0]);
+ av_freep(&h->top_mv[1]);
+ av_freep(&h->top_pred_Y);
+ av_freep(&h->top_border_y);
+ av_freep(&h->top_border_u);
+ av_freep(&h->top_border_v);
+ av_freep(&h->col_mv);
+ av_freep(&h->col_type_base);
+ av_freep(&h->block);
+ return AVERROR(ENOMEM);
+ }
+ return 0;
}
av_cold int ff_cavs_init(AVCodecContext *avctx)
@@ -811,16 +840,16 @@ av_cold int ff_cavs_end(AVCodecContext *avctx)
av_frame_free(&h->DPB[0].f);
av_frame_free(&h->DPB[1].f);
- av_free(h->top_qp);
- av_free(h->top_mv[0]);
- av_free(h->top_mv[1]);
- av_free(h->top_pred_Y);
- av_free(h->top_border_y);
- av_free(h->top_border_u);
- av_free(h->top_border_v);
- av_free(h->col_mv);
- av_free(h->col_type_base);
- av_free(h->block);
+ av_freep(&h->top_qp);
+ av_freep(&h->top_mv[0]);
+ av_freep(&h->top_mv[1]);
+ av_freep(&h->top_pred_Y);
+ av_freep(&h->top_border_y);
+ av_freep(&h->top_border_u);
+ av_freep(&h->top_border_v);
+ av_freep(&h->col_mv);
+ av_freep(&h->col_type_base);
+ av_freep(&h->block);
av_freep(&h->edge_emu_buffer);
return 0;
}
diff --git a/libavcodec/cavs.h b/libavcodec/cavs.h
index cfae05576b..fb9df15194 100644
--- a/libavcodec/cavs.h
+++ b/libavcodec/cavs.h
@@ -2,20 +2,20 @@
* Chinese AVS video (AVS1-P2, JiZhun profile) decoder.
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -216,6 +216,7 @@ typedef struct AVSContext {
int luma_scan[4];
int qp;
int qp_fixed;
+ int pic_qp_fixed;
int cbp;
ScanTable scantable;
@@ -241,6 +242,7 @@ typedef struct AVSContext {
int16_t *block;
} AVSContext;
+extern const uint8_t ff_cavs_chroma_qp[64];
extern const uint8_t ff_cavs_partition_flags[30];
extern const cavs_vector ff_cavs_intra_mv;
extern const cavs_vector ff_cavs_dir_mv;
@@ -269,8 +271,8 @@ void ff_cavs_mv(AVSContext *h, enum cavs_mv_loc nP, enum cavs_mv_loc nC,
enum cavs_mv_pred mode, enum cavs_block size, int ref);
void ff_cavs_init_mb(AVSContext *h);
int ff_cavs_next_mb(AVSContext *h);
-void ff_cavs_init_pic(AVSContext *h);
-void ff_cavs_init_top_lines(AVSContext *h);
+int ff_cavs_init_pic(AVSContext *h);
+int ff_cavs_init_top_lines(AVSContext *h);
int ff_cavs_init(AVCodecContext *avctx);
int ff_cavs_end (AVCodecContext *avctx);
diff --git a/libavcodec/cavs_parser.c b/libavcodec/cavs_parser.c
index 84f647c196..6067a39826 100644
--- a/libavcodec/cavs_parser.c
+++ b/libavcodec/cavs_parser.c
@@ -2,20 +2,20 @@
* Chinese AVS video (AVS1-P2, JiZhun profile) parser.
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/cavsdata.c b/libavcodec/cavsdata.c
index 4e4a131987..2835a4be09 100644
--- a/libavcodec/cavsdata.c
+++ b/libavcodec/cavsdata.c
@@ -2,20 +2,20 @@
* Chinese AVS video (AVS1-P2, JiZhun profile) decoder.
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,6 +54,13 @@ const uint8_t ff_cavs_partition_flags[30] = {
SPLITH|SPLITV, //B_8X8 = 29
};
+const uint8_t ff_cavs_chroma_qp[64] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 42, 43, 43, 44, 44,
+ 45, 45, 46, 46, 47, 47, 48, 48, 48, 49, 49, 49, 50, 50, 50, 51
+};
+
/** mark block as "no prediction from this direction"
e.g. forward motion vector in BWD partition */
const cavs_vector ff_cavs_dir_mv = {0,0,1,REF_DIR};
diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c
index cf21a8bb03..bf8c301e2e 100644
--- a/libavcodec/cavsdec.c
+++ b/libavcodec/cavsdec.c
@@ -2,20 +2,20 @@
* Chinese AVS video (AVS1-P2, JiZhun profile) decoder.
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
* @author Stefan Gehrer <stefan.gehrer@gmx.de>
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "get_bits.h"
#include "golomb.h"
@@ -51,13 +52,6 @@ static const uint8_t cbp_tab[64][2] = {
static const uint8_t scan3x3[4] = { 4, 5, 7, 8 };
-static const uint8_t cavs_chroma_qp[64] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 42, 43, 43, 44, 44,
- 45, 45, 46, 46, 47, 47, 48, 48, 48, 49, 49, 49, 50, 50, 50, 51
-};
-
static const uint8_t dequant_shift[64] = {
14, 14, 14, 14, 14, 14, 14, 14,
13, 13, 13, 13, 13, 13, 13, 13,
@@ -509,11 +503,15 @@ static inline void mv_pred_sym(AVSContext *h, cavs_vector *src,
/** kth-order exponential golomb code */
static inline int get_ue_code(GetBitContext *gb, int order)
{
+ unsigned ret = get_ue_golomb(gb);
+ if (ret >= ((1U<<31)>>order)) {
+ av_log(NULL, AV_LOG_ERROR, "get_ue_code: value too larger\n");
+ return AVERROR_INVALIDDATA;
+ }
if (order) {
- int ret = get_ue_golomb(gb) << order;
- return ret + get_bits(gb, order);
+ return (ret<<order) + get_bits(gb, order);
}
- return get_ue_golomb(gb);
+ return ret;
}
static inline int dequant(AVSContext *h, int16_t *level_buf, uint8_t *run_buf,
@@ -550,29 +548,37 @@ static int decode_residual_block(AVSContext *h, GetBitContext *gb,
const struct dec_2dvlc *r, int esc_golomb_order,
int qp, uint8_t *dst, int stride)
{
- int i, level_code, esc_code, level, run, mask, ret;
+ int i, esc_code, level, mask, ret;
+ unsigned int level_code, run;
int16_t level_buf[65];
uint8_t run_buf[65];
int16_t *block = h->block;
- for (i = 0;i < 65; i++) {
+ for (i = 0; i < 65; i++) {
level_code = get_ue_code(gb, r->golomb_order);
if (level_code >= ESCAPE_CODE) {
run = ((level_code - ESCAPE_CODE) >> 1) + 1;
+ if(run > 64) {
+ av_log(h->avctx, AV_LOG_ERROR, "run %d is too large\n", run);
+ return AVERROR_INVALIDDATA;
+ }
esc_code = get_ue_code(gb, esc_golomb_order);
+ if (esc_code < 0 || esc_code > 32767) {
+ av_log(h->avctx, AV_LOG_ERROR, "esc_code invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+
level = esc_code + (run > r->max_run ? 1 : r->level_add[run]);
while (level > r->inc_limit)
r++;
mask = -(level_code & 1);
level = (level ^ mask) - mask;
- } else if (level_code >= 0) {
+ } else {
level = r->rltab[level_code][0];
if (!level) //end of block signal
break;
run = r->rltab[level_code][1];
r += r->rltab[level_code][2];
- } else {
- break;
}
level_buf[i] = level;
run_buf[i] = run;
@@ -590,10 +596,10 @@ static inline void decode_residual_chroma(AVSContext *h)
{
if (h->cbp & (1 << 4))
decode_residual_block(h, &h->gb, chroma_dec, 0,
- cavs_chroma_qp[h->qp], h->cu, h->c_stride);
+ ff_cavs_chroma_qp[h->qp], h->cu, h->c_stride);
if (h->cbp & (1 << 5))
decode_residual_block(h, &h->gb, chroma_dec, 0,
- cavs_chroma_qp[h->qp], h->cv, h->c_stride);
+ ff_cavs_chroma_qp[h->qp], h->cv, h->c_stride);
}
static inline int decode_residual_inter(AVSContext *h)
@@ -602,7 +608,7 @@ static inline int decode_residual_inter(AVSContext *h)
/* get coded block pattern */
int cbp = get_ue_golomb(&h->gb);
- if (cbp > 63 || cbp < 0) {
+ if (cbp > 63U) {
av_log(h->avctx, AV_LOG_ERROR, "illegal inter cbp %d\n", cbp);
return AVERROR_INVALIDDATA;
}
@@ -673,7 +679,7 @@ static int decode_mb_i(AVSContext *h, int cbp_code)
/* get coded block pattern */
if (h->cur.f->pict_type == AV_PICTURE_TYPE_I)
cbp_code = get_ue_golomb(gb);
- if (cbp_code > 63 || cbp_code < 0) {
+ if (cbp_code > 63U) {
av_log(h->avctx, AV_LOG_ERROR, "illegal intra cbp\n");
return AVERROR_INVALIDDATA;
}
@@ -760,7 +766,7 @@ static void decode_mb_p(AVSContext *h, enum cavs_mb mb_type)
h->col_type_base[h->mbidx] = mb_type;
}
-static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
+static int decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
{
int block;
enum cavs_sub_mb sub_type[4];
@@ -797,6 +803,8 @@ static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
ff_cavs_mv(h, MV_BWD_X0, MV_BWD_C2, MV_PRED_MEDIAN, BLK_16X16, 0);
break;
case B_8X8:
+#define TMP_UNUSED_INX 7
+ flags = 0;
for (block = 0; block < 4; block++)
sub_type[block] = get_bits(&h->gb, 2);
for (block = 0; block < 4; block++) {
@@ -804,11 +812,30 @@ static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
case B_SUB_DIRECT:
if (!h->col_type_base[h->mbidx]) {
/* intra MB at co-location, do in-plane prediction */
- ff_cavs_mv(h, mv_scan[block], mv_scan[block] - 3,
- MV_PRED_BSKIP, BLK_8X8, 1);
- ff_cavs_mv(h, mv_scan[block] + MV_BWD_OFFS,
- mv_scan[block] - 3 + MV_BWD_OFFS,
- MV_PRED_BSKIP, BLK_8X8, 0);
+ if(flags==0) {
+ // if col-MB is a Intra MB, current Block size is 16x16.
+ // AVS standard section 9.9.1
+ if(block>0){
+ h->mv[TMP_UNUSED_INX ] = h->mv[MV_FWD_X0 ];
+ h->mv[TMP_UNUSED_INX + MV_BWD_OFFS] = h->mv[MV_FWD_X0 + MV_BWD_OFFS];
+ }
+ ff_cavs_mv(h, MV_FWD_X0, MV_FWD_C2,
+ MV_PRED_BSKIP, BLK_8X8, 1);
+ ff_cavs_mv(h, MV_FWD_X0+MV_BWD_OFFS,
+ MV_FWD_C2+MV_BWD_OFFS,
+ MV_PRED_BSKIP, BLK_8X8, 0);
+ if(block>0) {
+ flags = mv_scan[block];
+ h->mv[flags ] = h->mv[MV_FWD_X0 ];
+ h->mv[flags + MV_BWD_OFFS] = h->mv[MV_FWD_X0 + MV_BWD_OFFS];
+ h->mv[MV_FWD_X0 ] = h->mv[TMP_UNUSED_INX ];
+ h->mv[MV_FWD_X0 + MV_BWD_OFFS] = h->mv[TMP_UNUSED_INX + MV_BWD_OFFS];
+ } else
+ flags = MV_FWD_X0;
+ } else {
+ h->mv[mv_scan[block] ] = h->mv[flags ];
+ h->mv[mv_scan[block] + MV_BWD_OFFS] = h->mv[flags + MV_BWD_OFFS];
+ }
} else
mv_pred_direct(h, &h->mv[mv_scan[block]],
&h->col_mv[h->mbidx * 4 + block]);
@@ -824,6 +851,7 @@ static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
break;
}
}
+#undef TMP_UNUSED_INX
for (block = 0; block < 4; block++) {
if (sub_type[block] == B_SUB_BWD)
ff_cavs_mv(h, mv_scan[block] + MV_BWD_OFFS,
@@ -832,7 +860,11 @@ static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
}
break;
default:
- assert((mb_type > B_SYM_16X16) && (mb_type < B_8X8));
+ if (mb_type <= B_SYM_16X16) {
+ av_log(h->avctx, AV_LOG_ERROR, "Invalid mb_type %d in B frame\n", mb_type);
+ return AVERROR_INVALIDDATA;
+ }
+ av_assert2(mb_type < B_8X8);
flags = ff_cavs_partition_flags[mb_type];
if (mb_type & 1) { /* 16x8 macroblock types */
if (flags & FWD0)
@@ -867,6 +899,8 @@ static void decode_mb_b(AVSContext *h, enum cavs_mb mb_type)
if (mb_type != B_SKIP)
decode_residual_inter(h);
ff_cavs_filter(h, mb_type);
+
+ return 0;
}
/*****************************************************************************
@@ -879,12 +913,18 @@ static inline int decode_slice_header(AVSContext *h, GetBitContext *gb)
{
if (h->stc > 0xAF)
av_log(h->avctx, AV_LOG_ERROR, "unexpected start code 0x%02x\n", h->stc);
+
+ if (h->stc >= h->mb_height) {
+ av_log(h->avctx, AV_LOG_ERROR, "stc 0x%02x is too large\n", h->stc);
+ return AVERROR_INVALIDDATA;
+ }
+
h->mby = h->stc;
h->mbidx = h->mby * h->mb_width;
/* mark top macroblocks as unavailable */
h->flags &= ~(B_AVAIL | C_AVAIL);
- if ((h->mby == 0) && (!h->qp_fixed)) {
+ if (!h->pic_qp_fixed) {
h->qp_fixed = get_bits1(gb);
h->qp = get_bits(gb, 6);
}
@@ -977,16 +1017,17 @@ static int decode_pic(AVSContext *h)
return AVERROR(ENOMEM);
}
- ff_cavs_init_pic(h);
+ if ((ret = ff_cavs_init_pic(h)) < 0)
+ return ret;
h->cur.poc = get_bits(&h->gb, 8) * 2;
/* get temporal distances and MV scaling factors */
if (h->cur.f->pict_type != AV_PICTURE_TYPE_B) {
- h->dist[0] = (h->cur.poc - h->DPB[0].poc + 512) % 512;
+ h->dist[0] = (h->cur.poc - h->DPB[0].poc) & 511;
} else {
- h->dist[0] = (h->DPB[0].poc - h->cur.poc + 512) % 512;
+ h->dist[0] = (h->DPB[0].poc - h->cur.poc) & 511;
}
- h->dist[1] = (h->cur.poc - h->DPB[1].poc + 512) % 512;
+ h->dist[1] = (h->cur.poc - h->DPB[1].poc) & 511;
h->scale_den[0] = h->dist[0] ? 512/h->dist[0] : 0;
h->scale_den[1] = h->dist[1] ? 512/h->dist[1] : 0;
if (h->cur.f->pict_type == AV_PICTURE_TYPE_B) {
@@ -1006,6 +1047,7 @@ static int decode_pic(AVSContext *h)
skip_bits1(&h->gb); //advanced_pred_mode_disable
skip_bits1(&h->gb); //top_field_first
skip_bits1(&h->gb); //repeat_first_field
+ h->pic_qp_fixed =
h->qp_fixed = get_bits1(&h->gb);
h->qp = get_bits(&h->gb, 6);
if (h->cur.f->pict_type == AV_PICTURE_TYPE_I) {
@@ -1081,6 +1123,7 @@ static int decode_seq_header(AVSContext *h)
{
int frame_rate_code;
int width, height;
+ int ret;
h->profile = get_bits(&h->gb, 8);
h->level = get_bits(&h->gb, 8);
@@ -1093,24 +1136,36 @@ static int decode_seq_header(AVSContext *h)
"Width/height changing in CAVS");
return AVERROR_PATCHWELCOME;
}
- h->width = width;
- h->height = height;
-
+ if (width <= 0 || height <= 0) {
+ av_log(h->avctx, AV_LOG_ERROR, "Dimensions invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
skip_bits(&h->gb, 2); //chroma format
skip_bits(&h->gb, 3); //sample_precision
h->aspect_ratio = get_bits(&h->gb, 4);
frame_rate_code = get_bits(&h->gb, 4);
+ if (frame_rate_code == 0 || frame_rate_code > 13) {
+ av_log(h->avctx, AV_LOG_WARNING,
+ "frame_rate_code %d is invalid\n", frame_rate_code);
+ frame_rate_code = 1;
+ }
+
skip_bits(&h->gb, 18); //bit_rate_lower
skip_bits1(&h->gb); //marker_bit
skip_bits(&h->gb, 12); //bit_rate_upper
h->low_delay = get_bits1(&h->gb);
+
+ ret = ff_set_dimensions(h->avctx, width, height);
+ if (ret < 0)
+ return ret;
+
+ h->width = width;
+ h->height = height;
h->mb_width = (h->width + 15) >> 4;
h->mb_height = (h->height + 15) >> 4;
h->avctx->framerate = ff_mpeg12_frame_rate_tab[frame_rate_code];
- h->avctx->width = h->width;
- h->avctx->height = h->height;
if (!h->top_qp)
- ff_cavs_init_top_lines(h);
+ return ff_cavs_init_top_lines(h);
return 0;
}
@@ -1139,12 +1194,17 @@ static int cavs_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return 0;
}
+ h->stc = 0;
+
buf_ptr = buf;
buf_end = buf + buf_size;
for(;;) {
buf_ptr = avpriv_find_start_code(buf_ptr, buf_end, &stc);
- if ((stc & 0xFFFFFE00) || buf_ptr == buf_end)
+ if ((stc & 0xFFFFFE00) || buf_ptr == buf_end) {
+ if (!h->stc)
+ av_log(h->avctx, AV_LOG_WARNING, "no frame decoded\n");
return FFMAX(0, buf_ptr - buf);
+ }
input_size = (buf_end - buf_ptr) * 8;
switch (stc) {
case CAVS_START_CODE:
@@ -1167,8 +1227,8 @@ static int cavs_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
break;
*got_frame = 1;
if (h->cur.f->pict_type != AV_PICTURE_TYPE_B) {
- if (h->DPB[1].f->data[0]) {
- if ((ret = av_frame_ref(data, h->DPB[1].f)) < 0)
+ if (h->DPB[!h->low_delay].f->data[0]) {
+ if ((ret = av_frame_ref(data, h->DPB[!h->low_delay].f)) < 0)
return ret;
} else {
*got_frame = 0;
diff --git a/libavcodec/cavsdsp.c b/libavcodec/cavsdsp.c
index cc7898968f..91f6d7350b 100644
--- a/libavcodec/cavsdsp.c
+++ b/libavcodec/cavsdsp.c
@@ -5,20 +5,20 @@
*
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/cavsdsp.h b/libavcodec/cavsdsp.h
index 248afd508c..847f5c4c87 100644
--- a/libavcodec/cavsdsp.h
+++ b/libavcodec/cavsdsp.h
@@ -2,20 +2,20 @@
* Chinese AVS video (AVS1-P2, JiZhun profile) decoder.
* Copyright (c) 2006 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/cbrt_tablegen.c b/libavcodec/cbrt_tablegen.c
index e92c0f1db1..e0a8e63a8b 100644
--- a/libavcodec/cbrt_tablegen.c
+++ b/libavcodec/cbrt_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/cbrt_tablegen.h b/libavcodec/cbrt_tablegen.h
index 60d900a94f..d8c77c2221 100644
--- a/libavcodec/cbrt_tablegen.h
+++ b/libavcodec/cbrt_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <math.h>
+#include "libavutil/attributes.h"
#if CONFIG_HARDCODED_TABLES
#define cbrt_tableinit()
@@ -32,7 +33,7 @@
#else
static uint32_t cbrt_tab[1 << 13];
-static void cbrt_tableinit(void)
+static av_cold void cbrt_tableinit(void)
{
if (!cbrt_tab[(1<<13) - 1]) {
int i;
@@ -42,7 +43,7 @@ static void cbrt_tableinit(void)
float f;
uint32_t i;
} f;
- f.f = powf(i, 1.0 / 3.0) * i;
+ f.f = pow(i, 1.0 / 3.0) * i;
cbrt_tab[i] = f.i;
}
}
diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c
new file mode 100644
index 0000000000..264d21cf8b
--- /dev/null
+++ b/libavcodec/ccaption_dec.c
@@ -0,0 +1,591 @@
+/*
+ * Closed Caption Decoding
+ * Copyright (c) 2015 Anshul Maheshwari
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/opt.h"
+
+#define SCREEN_ROWS 15
+#define SCREEN_COLUMNS 32
+
+#define SET_FLAG(var, val) ( (var) |= ( 1 << (val)) )
+#define UNSET_FLAG(var, val) ( (var) &= ~( 1 << (val)) )
+#define CHECK_FLAG(var, val) ( (var) & ( 1 << (val)) )
+
+/*
+ * TODO list
+ * 1) handle font and color completely
+ */
+enum cc_mode {
+ CCMODE_POPON,
+ CCMODE_PAINTON,
+ CCMODE_ROLLUP_2,
+ CCMODE_ROLLUP_3,
+ CCMODE_ROLLUP_4,
+ CCMODE_TEXT,
+};
+
+enum cc_color_code {
+ CCCOL_WHITE,
+ CCCOL_GREEN,
+ CCCOL_BLUE,
+ CCCOL_CYAN,
+ CCCOL_RED,
+ CCCOL_YELLOW,
+ CCCOL_MAGENTA,
+ CCCOL_USERDEFINED,
+ CCCOL_BLACK,
+ CCCOL_TRANSPARENT,
+};
+
+enum cc_font {
+ CCFONT_REGULAR,
+ CCFONT_ITALICS,
+ CCFONT_UNDERLINED,
+ CCFONT_UNDERLINED_ITALICS,
+};
+
+static const unsigned char pac2_attribs[32][3] = // Color, font, ident
+{
+ { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x40 || 0x60
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 0 }, // 0x41 || 0x61
+ { CCCOL_GREEN, CCFONT_REGULAR, 0 }, // 0x42 || 0x62
+ { CCCOL_GREEN, CCFONT_UNDERLINED, 0 }, // 0x43 || 0x63
+ { CCCOL_BLUE, CCFONT_REGULAR, 0 }, // 0x44 || 0x64
+ { CCCOL_BLUE, CCFONT_UNDERLINED, 0 }, // 0x45 || 0x65
+ { CCCOL_CYAN, CCFONT_REGULAR, 0 }, // 0x46 || 0x66
+ { CCCOL_CYAN, CCFONT_UNDERLINED, 0 }, // 0x47 || 0x67
+ { CCCOL_RED, CCFONT_REGULAR, 0 }, // 0x48 || 0x68
+ { CCCOL_RED, CCFONT_UNDERLINED, 0 }, // 0x49 || 0x69
+ { CCCOL_YELLOW, CCFONT_REGULAR, 0 }, // 0x4a || 0x6a
+ { CCCOL_YELLOW, CCFONT_UNDERLINED, 0 }, // 0x4b || 0x6b
+ { CCCOL_MAGENTA, CCFONT_REGULAR, 0 }, // 0x4c || 0x6c
+ { CCCOL_MAGENTA, CCFONT_UNDERLINED, 0 }, // 0x4d || 0x6d
+ { CCCOL_WHITE, CCFONT_ITALICS, 0 }, // 0x4e || 0x6e
+ { CCCOL_WHITE, CCFONT_UNDERLINED_ITALICS, 0 }, // 0x4f || 0x6f
+ { CCCOL_WHITE, CCFONT_REGULAR, 0 }, // 0x50 || 0x70
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 0 }, // 0x51 || 0x71
+ { CCCOL_WHITE, CCFONT_REGULAR, 4 }, // 0x52 || 0x72
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 4 }, // 0x53 || 0x73
+ { CCCOL_WHITE, CCFONT_REGULAR, 8 }, // 0x54 || 0x74
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 8 }, // 0x55 || 0x75
+ { CCCOL_WHITE, CCFONT_REGULAR, 12 }, // 0x56 || 0x76
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 12 }, // 0x57 || 0x77
+ { CCCOL_WHITE, CCFONT_REGULAR, 16 }, // 0x58 || 0x78
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 16 }, // 0x59 || 0x79
+ { CCCOL_WHITE, CCFONT_REGULAR, 20 }, // 0x5a || 0x7a
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 20 }, // 0x5b || 0x7b
+ { CCCOL_WHITE, CCFONT_REGULAR, 24 }, // 0x5c || 0x7c
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 24 }, // 0x5d || 0x7d
+ { CCCOL_WHITE, CCFONT_REGULAR, 28 }, // 0x5e || 0x7e
+ { CCCOL_WHITE, CCFONT_UNDERLINED, 28 } // 0x5f || 0x7f
+ /* total 32 entries */
+};
+
+/* 0-255 needs 256 spaces */
+static const uint8_t parity_table[256] = { 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0 };
+
+struct Screen {
+ /* +1 is used to compensate null character of string */
+ uint8_t characters[SCREEN_ROWS][SCREEN_COLUMNS+1];
+ uint8_t colors[SCREEN_ROWS][SCREEN_COLUMNS+1];
+ uint8_t fonts[SCREEN_ROWS][SCREEN_COLUMNS+1];
+ /*
+ * Bitmask of used rows; if a bit is not set, the
+ * corresponding row is not used.
+ * for setting row 1 use row | (1 << 0)
+ * for setting row 15 use row | (1 << 14)
+ */
+ int16_t row_used;
+};
+
+
+typedef struct CCaptionSubContext {
+ AVClass *class;
+ struct Screen screen[2];
+ int active_screen;
+ uint8_t cursor_row;
+ uint8_t cursor_column;
+ uint8_t cursor_color;
+ uint8_t cursor_font;
+ AVBPrint buffer;
+ int screen_changed;
+ int rollup;
+ enum cc_mode mode;
+ int64_t start_time;
+ /* visible screen time */
+ int64_t startv_time;
+ int64_t end_time;
+ char prev_cmd[2];
+ /* buffer to store pkt data */
+ AVBufferRef *pktbuf;
+}CCaptionSubContext;
+
+
+static av_cold int init_decoder(AVCodecContext *avctx)
+{
+ int ret;
+ CCaptionSubContext *ctx = avctx->priv_data;
+
+ av_bprint_init(&ctx->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
+ /* taking by default roll up to 2 */
+ ctx->mode = CCMODE_ROLLUP_2;
+ ctx->rollup = 2;
+ ret = ff_ass_subtitle_header_default(avctx);
+ if(ret < 0) {
+ return ret;
+ }
+ /* allocate pkt buffer */
+ ctx->pktbuf = av_buffer_alloc(128);
+ if( !ctx->pktbuf) {
+ ret = AVERROR(ENOMEM);
+ }
+ return ret;
+}
+
+static av_cold int close_decoder(AVCodecContext *avctx)
+{
+ CCaptionSubContext *ctx = avctx->priv_data;
+ av_bprint_finalize( &ctx->buffer, NULL);
+ av_buffer_unref(&ctx->pktbuf);
+ return 0;
+}
+
+/**
+ * @param ctx closed caption context just to print log
+ */
+static int write_char (CCaptionSubContext *ctx, char *row,uint8_t col, char ch)
+{
+ if(col < SCREEN_COLUMNS) {
+ row[col] = ch;
+ return 0;
+ }
+ /* We have extra space at end only for null character */
+ else if ( col == SCREEN_COLUMNS && ch == 0) {
+ row[col] = ch;
+ return 0;
+ }
+ else {
+ av_log(ctx, AV_LOG_WARNING,"Data Ignored since exceeding screen width\n");
+ return AVERROR_INVALIDDATA;
+ }
+}
+
+/**
+ * This function after validating parity bit, also remove it from data pair.
+ * The first byte doesn't pass parity, we replace it with a solid blank
+ * and process the pair.
+ * If the second byte doesn't pass parity, it returns INVALIDDATA
+ * user can ignore the whole pair and pass the other pair.
+ */
+static int validate_cc_data_pair (uint8_t *cc_data_pair)
+{
+ uint8_t cc_valid = (*cc_data_pair & 4) >>2;
+ uint8_t cc_type = *cc_data_pair & 3;
+
+ if (!cc_valid)
+ return AVERROR_INVALIDDATA;
+
+ // if EIA-608 data then verify parity.
+ if (cc_type==0 || cc_type==1) {
+ if (!parity_table[cc_data_pair[2]]) {
+ return AVERROR_INVALIDDATA;
+ }
+ if (!parity_table[cc_data_pair[1]]) {
+ cc_data_pair[1]=0x7F;
+ }
+ }
+
+ //Skip non-data
+ if( (cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD )
+ && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0)
+ return AVERROR_PATCHWELCOME;
+
+ //skip 708 data
+ if(cc_type == 3 || cc_type == 2 )
+ return AVERROR_PATCHWELCOME;
+
+ /* remove parity bit */
+ cc_data_pair[1] &= 0x7F;
+ cc_data_pair[2] &= 0x7F;
+
+
+ return 0;
+
+}
+
+static struct Screen *get_writing_screen(CCaptionSubContext *ctx)
+{
+ switch (ctx->mode) {
+ case CCMODE_POPON:
+ // use Inactive screen
+ return ctx->screen + !ctx->active_screen;
+ case CCMODE_PAINTON:
+ case CCMODE_ROLLUP_2:
+ case CCMODE_ROLLUP_3:
+ case CCMODE_ROLLUP_4:
+ case CCMODE_TEXT:
+ // use active screen
+ return ctx->screen + ctx->active_screen;
+ }
+ /* It was never an option */
+ return NULL;
+}
+
+static void roll_up(CCaptionSubContext *ctx)
+{
+ struct Screen *screen;
+ int i, keep_lines;
+
+ if(ctx->mode == CCMODE_TEXT)
+ return;
+
+ screen = get_writing_screen(ctx);
+
+ /* +1 signify cursor_row starts from 0
+ * Can't keep lines less then row cursor pos
+ */
+ keep_lines = FFMIN(ctx->cursor_row + 1, ctx->rollup);
+
+ for( i = 0; i < ctx->cursor_row - keep_lines; i++ )
+ UNSET_FLAG(screen->row_used, i);
+
+
+ for( i = 0; i < keep_lines && screen->row_used; i++ ) {
+ const int i_row = ctx->cursor_row - keep_lines + i + 1;
+
+ memcpy( screen->characters[i_row], screen->characters[i_row+1], SCREEN_COLUMNS );
+ memcpy( screen->colors[i_row], screen->colors[i_row+1], SCREEN_COLUMNS);
+ memcpy( screen->fonts[i_row], screen->fonts[i_row+1], SCREEN_COLUMNS);
+ if(CHECK_FLAG(screen->row_used, i_row + 1))
+ SET_FLAG(screen->row_used, i_row);
+
+ }
+ UNSET_FLAG(screen->row_used, ctx->cursor_row);
+
+}
+
+static int reap_screen(CCaptionSubContext *ctx, int64_t pts)
+{
+ int i;
+ int ret = 0;
+ struct Screen *screen = ctx->screen + ctx->active_screen;
+ ctx->start_time = ctx->startv_time;
+
+ for( i = 0; screen->row_used && i < SCREEN_ROWS; i++)
+ {
+ if(CHECK_FLAG(screen->row_used,i)) {
+ char *str = screen->characters[i];
+ /* skip space */
+ while (*str == ' ')
+ str++;
+
+ av_bprintf(&ctx->buffer, "%s\\N", str);
+ ret = av_bprint_is_complete(&ctx->buffer);
+ if( ret == 0) {
+ ret = AVERROR(ENOMEM);
+ break;
+ }
+ }
+
+ }
+ if(screen->row_used && ctx->buffer.len >= 2 ) {
+ ctx->buffer.len -= 2;
+ ctx->buffer.str[ctx->buffer.len] = 0;
+ }
+ ctx->startv_time = pts;
+ ctx->end_time = pts;
+ return ret;
+}
+
+static void handle_textattr( CCaptionSubContext *ctx, uint8_t hi, uint8_t lo )
+{
+ int i = lo - 0x20;
+ int ret;
+ struct Screen *screen = get_writing_screen(ctx);
+ char *row = screen->characters[ctx->cursor_row];
+
+ if( i >= 32)
+ return;
+
+ ctx->cursor_color = pac2_attribs[i][0];
+ ctx->cursor_font = pac2_attribs[i][1];
+
+ SET_FLAG(screen->row_used,ctx->cursor_row);
+ ret = write_char(ctx, row, ctx->cursor_column, ' ');
+ if(ret == 0)
+ ctx->cursor_column++;
+}
+
+static void handle_pac( CCaptionSubContext *ctx, uint8_t hi, uint8_t lo )
+{
+ static const int8_t row_map[] = {
+ 11, -1, 1, 2, 3, 4, 12, 13, 14, 15, 5, 6, 7, 8, 9, 10
+ };
+ const int index = ( (hi<<1) & 0x0e) | ( (lo>>5) & 0x01 );
+ struct Screen *screen = get_writing_screen(ctx);
+ char *row;
+ int indent,i,ret;
+
+ if( row_map[index] <= 0 ) {
+ av_log(ctx, AV_LOG_DEBUG,"Invalid pac index encountered\n");
+ return;
+ }
+
+ lo &= 0x1f;
+
+ ctx->cursor_row = row_map[index] - 1;
+ ctx->cursor_color = pac2_attribs[lo][0];
+ ctx->cursor_font = pac2_attribs[lo][1];
+ ctx->cursor_column = 0;
+ indent = pac2_attribs[lo][2];
+ row = screen->characters[ctx->cursor_row];
+ for(i = 0;i < indent; i++) {
+ ret = write_char(ctx, row, ctx->cursor_column, ' ');
+ if( ret == 0 )
+ ctx->cursor_column++;
+ }
+
+}
+
+/**
+ * @param pts it is required to set end time
+ */
+static int handle_edm(CCaptionSubContext *ctx,int64_t pts)
+{
+ int ret = 0;
+ struct Screen *screen = ctx->screen + ctx->active_screen;
+
+ reap_screen(ctx, pts);
+ screen->row_used = 0;
+ ctx->screen_changed = 1;
+ return ret;
+}
+
+static int handle_eoc(CCaptionSubContext *ctx, int64_t pts)
+{
+ int ret;
+ ret = handle_edm(ctx,pts);
+ ctx->active_screen = !ctx->active_screen;
+ ctx->cursor_column = 0;
+ return ret;
+}
+
+static void handle_delete_end_of_row( CCaptionSubContext *ctx, char hi, char lo)
+{
+ struct Screen *screen = get_writing_screen(ctx);
+ char *row = screen->characters[ctx->cursor_row];
+ write_char(ctx, row, ctx->cursor_column, 0);
+
+}
+
+static void handle_char(CCaptionSubContext *ctx, char hi, char lo, int64_t pts)
+{
+ struct Screen *screen = get_writing_screen(ctx);
+ char *row = screen->characters[ctx->cursor_row];
+ int ret;
+
+ SET_FLAG(screen->row_used,ctx->cursor_row);
+
+ ret = write_char(ctx, row, ctx->cursor_column, hi);
+ if( ret == 0 )
+ ctx->cursor_column++;
+
+ if(lo) {
+ ret = write_char(ctx, row, ctx->cursor_column, lo);
+ if ( ret == 0 )
+ ctx->cursor_column++;
+ }
+ write_char(ctx, row, ctx->cursor_column, 0);
+
+ /* reset prev command since character can repeat */
+ ctx->prev_cmd[0] = 0;
+ ctx->prev_cmd[1] = 0;
+ if (lo)
+ av_dlog(ctx, "(%c,%c)\n",hi,lo);
+ else
+ av_dlog(ctx, "(%c)\n",hi);
+}
+
+static int process_cc608(CCaptionSubContext *ctx, int64_t pts, uint8_t hi, uint8_t lo)
+{
+ int ret = 0;
+#define COR3(var, with1, with2, with3) ( (var) == (with1) || (var) == (with2) || (var) == (with3) )
+ if ( hi == ctx->prev_cmd[0] && lo == ctx->prev_cmd[1]) {
+ /* ignore redundant command */
+ } else if ( (hi == 0x10 && (lo >= 0x40 || lo <= 0x5f)) ||
+ ( (hi >= 0x11 && hi <= 0x17) && (lo >= 0x40 && lo <= 0x7f) ) ) {
+ handle_pac(ctx, hi, lo);
+ } else if ( ( hi == 0x11 && lo >= 0x20 && lo <= 0x2f ) ||
+ ( hi == 0x17 && lo >= 0x2e && lo <= 0x2f) ) {
+ handle_textattr(ctx, hi, lo);
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x20 ) {
+ /* resume caption loading */
+ ctx->mode = CCMODE_POPON;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x24 ) {
+ handle_delete_end_of_row(ctx, hi, lo);
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x25 ) {
+ ctx->rollup = 2;
+ ctx->mode = CCMODE_ROLLUP_2;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x26 ) {
+ ctx->rollup = 3;
+ ctx->mode = CCMODE_ROLLUP_3;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x27 ) {
+ ctx->rollup = 4;
+ ctx->mode = CCMODE_ROLLUP_4;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x29 ) {
+ /* resume direct captioning */
+ ctx->mode = CCMODE_PAINTON;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x2B ) {
+ /* resume text display */
+ ctx->mode = CCMODE_TEXT;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x2C ) {
+ /* erase display memory */
+ ret = handle_edm(ctx, pts);
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x2D ) {
+ /* carriage return */
+ av_dlog(ctx, "carriage return\n");
+ reap_screen(ctx, pts);
+ roll_up(ctx);
+ ctx->screen_changed = 1;
+ ctx->cursor_column = 0;
+ } else if ( COR3(hi, 0x14, 0x15, 0x1C) && lo == 0x2F ) {
+ /* end of caption */
+ av_dlog(ctx, "handle_eoc\n");
+ ret = handle_eoc(ctx, pts);
+ } else if (hi>=0x20) {
+ /* Standard characters (always in pairs) */
+ handle_char(ctx, hi, lo, pts);
+ } else {
+ /* Ignoring all other non data code */
+ av_dlog(ctx, "Unknown command 0x%hhx 0x%hhx\n", hi, lo);
+ }
+
+ /* set prev command */
+ ctx->prev_cmd[0] = hi;
+ ctx->prev_cmd[1] = lo;
+
+#undef COR3
+ return ret;
+
+}
+
+static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
+{
+ CCaptionSubContext *ctx = avctx->priv_data;
+ AVSubtitle *sub = data;
+ uint8_t *bptr = NULL;
+ int len = avpkt->size;
+ int ret = 0;
+ int i;
+
+ if ( ctx->pktbuf->size < len) {
+ ret = av_buffer_realloc(&ctx->pktbuf, len);
+ if(ret < 0) {
+ av_log(ctx, AV_LOG_WARNING, "Insufficient Memory of %d truncated to %d\n",len, ctx->pktbuf->size);
+ len = ctx->pktbuf->size;
+ ret = 0;
+ }
+ }
+ memcpy(ctx->pktbuf->data, avpkt->data, len);
+ bptr = ctx->pktbuf->data;
+
+
+ for (i = 0; i < len; i += 3) {
+ uint8_t cc_type = *(bptr + i) & 3;
+ if (validate_cc_data_pair( bptr + i) )
+ continue;
+ /* ignoring data field 1 */
+ if(cc_type == 1)
+ continue;
+ else
+ process_cc608(ctx, avpkt->pts, *(bptr + i + 1) & 0x7f, *(bptr + i + 2) & 0x7f);
+ if(ctx->screen_changed && *ctx->buffer.str)
+ {
+ int start_time = av_rescale_q(ctx->start_time, avctx->time_base, (AVRational){ 1, 100 });
+ int end_time = av_rescale_q(ctx->end_time, avctx->time_base, (AVRational){ 1, 100 });
+ av_dlog(ctx, "cdp writing data (%s)\n",ctx->buffer.str);
+ ret = ff_ass_add_rect_bprint(sub, &ctx->buffer, start_time, end_time - start_time);
+ if (ret < 0)
+ return ret;
+ sub->pts = av_rescale_q(ctx->start_time, avctx->time_base, AV_TIME_BASE_Q);
+ ctx->screen_changed = 0;
+ av_bprint_clear(&ctx->buffer);
+ }
+ }
+
+ *got_sub = sub->num_rects > 0;
+ return ret;
+}
+
+static const AVOption options[] = {
+ {NULL}
+};
+
+static const AVClass ccaption_dec_class = {
+ .class_name = "Closed caption Decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_ccaption_decoder = {
+ .name = "cc_dec",
+ .long_name = NULL_IF_CONFIG_SMALL("Closed Caption (EIA-608 / CEA-708) Decoder"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_EIA_608,
+ .priv_data_size = sizeof(CCaptionSubContext),
+ .init = init_decoder,
+ .close = close_decoder,
+ .decode = decode,
+ .priv_class = &ccaption_dec_class,
+};
diff --git a/libavcodec/cdgraphics.c b/libavcodec/cdgraphics.c
index c3e42e750a..340df44818 100644
--- a/libavcodec/cdgraphics.c
+++ b/libavcodec/cdgraphics.c
@@ -2,20 +2,20 @@
* CD Graphics Video Decoder
* Copyright (c) 2009 Michael Tison
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -119,7 +119,7 @@ static void cdg_load_palette(CDGraphicsContext *cc, uint8_t *data, int low)
r = ((color >> 8) & 0x000F) * 17;
g = ((color >> 4) & 0x000F) * 17;
b = ((color ) & 0x000F) * 17;
- palette[i + array_offset] = r << 16 | g << 8 | b;
+ palette[i + array_offset] = 0xFFU << 24 | r << 16 | g << 8 | b;
}
cc->frame->palette_has_changed = 1;
}
@@ -265,20 +265,27 @@ static int cdg_decode_frame(AVCodecContext *avctx,
int buf_size = avpkt->size;
int ret;
uint8_t command, inst;
- uint8_t cdg_data[CDG_DATA_SIZE];
+ uint8_t cdg_data[CDG_DATA_SIZE] = {0};
AVFrame *frame = data;
CDGraphicsContext *cc = avctx->priv_data;
- bytestream2_init(&gb, avpkt->data, avpkt->size);
+ if (buf_size < CDG_MINIMUM_PKT_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "buffer too small for decoder\n");
+ return AVERROR(EINVAL);
+ }
+ if (buf_size > CDG_HEADER_SIZE + CDG_DATA_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "buffer too big for decoder\n");
+ return AVERROR(EINVAL);
+ }
+ bytestream2_init(&gb, avpkt->data, avpkt->size);
- ret = ff_reget_buffer(avctx, cc->frame);
- if (ret) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, cc->frame)) < 0)
return ret;
- }
- if (!avctx->frame_number)
+ if (!avctx->frame_number) {
memset(cc->frame->data[0], 0, cc->frame->linesize[0] * avctx->height);
+ memset(cc->frame->data[1], 0, AVPALETTE_SIZE);
+ }
command = bytestream2_get_byte(&gb);
inst = bytestream2_get_byte(&gb);
@@ -325,11 +332,8 @@ static int cdg_decode_frame(AVCodecContext *avctx,
return AVERROR(EINVAL);
}
- ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF);
- if (ret) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
cdg_scroll(cc, cdg_data, frame, inst == CDG_INST_SCROLL_COPY);
av_frame_unref(cc->frame);
diff --git a/libavcodec/cdxl.c b/libavcodec/cdxl.c
index e45e722be5..adccd52e27 100644
--- a/libavcodec/cdxl.c
+++ b/libavcodec/cdxl.c
@@ -2,23 +2,31 @@
* CDXL video decoder
* Copyright (c) 2011-2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/**
+ * @file
+ * Commodore CDXL video decoder
+ * @author Paul B Mahol
+ */
+
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/intreadwrite.h"
#include "libavutil/imgutils.h"
#include "avcodec.h"
@@ -26,8 +34,8 @@
#include "internal.h"
#define BIT_PLANAR 0x00
-#define BYTE_PLANAR 0x20
-#define CHUNKY 0x40
+#define CHUNKY 0x20
+#define BYTE_PLANAR 0x40
#define BIT_LINE 0x80
#define BYTE_LINE 0xC0
@@ -63,7 +71,7 @@ static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
unsigned r = ((rgb >> 8) & 0xF) * 0x11;
unsigned g = ((rgb >> 4) & 0xF) * 0x11;
unsigned b = (rgb & 0xF) * 0x11;
- AV_WN32(&new_palette[i], (r << 16) | (g << 8) | b);
+ AV_WN32(&new_palette[i], (0xFFU << 24) | (r << 16) | (g << 8) | b);
}
}
@@ -72,7 +80,8 @@ static void bitplanar2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
GetBitContext gb;
int x, y, plane;
- init_get_bits(&gb, c->video, c->video_size * 8);
+ if (init_get_bits8(&gb, c->video, c->video_size) < 0)
+ return;
for (plane = 0; plane < c->bpp; plane++) {
for (y = 0; y < c->avctx->height; y++) {
for (x = 0; x < c->avctx->width; x++)
@@ -87,7 +96,8 @@ static void bitline2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
GetBitContext gb;
int x, y, plane;
- init_get_bits(&gb, c->video, c->video_size * 8);
+ if (init_get_bits8(&gb, c->video, c->video_size) < 0)
+ return;
for (y = 0; y < c->avctx->height; y++) {
for (plane = 0; plane < c->bpp; plane++) {
for (x = 0; x < c->avctx->width; x++)
@@ -115,6 +125,7 @@ static void cdxl_decode_rgb(CDXLVideoContext *c, AVFrame *frame)
{
uint32_t *new_palette = (uint32_t *)frame->data[1];
+ memset(frame->data[1], 0, AVPALETTE_SIZE);
import_palette(c, new_palette);
import_format(c, frame->linesize[0], frame->data[0]);
}
@@ -255,10 +266,8 @@ static int cdxl_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_PATCHWELCOME;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
if (encoding) {
@@ -282,7 +291,7 @@ static av_cold int cdxl_decode_end(AVCodecContext *avctx)
{
CDXLVideoContext *c = avctx->priv_data;
- av_free(c->new_video);
+ av_freep(&c->new_video);
return 0;
}
diff --git a/libavcodec/celp_filters.c b/libavcodec/celp_filters.c
index 61474f5906..a81fd8831b 100644
--- a/libavcodec/celp_filters.c
+++ b/libavcodec/celp_filters.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include "avcodec.h"
#include "celp_filters.h"
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
void ff_celp_convolve_circ(int16_t* fc_out, const int16_t* fc_in,
@@ -104,6 +105,8 @@ void ff_celp_lp_synthesis_filterf(float *out, const float *filter_coeffs,
c -= filter_coeffs[1] * filter_coeffs[0];
c -= filter_coeffs[0] * b;
+ av_assert2((filter_length&1)==0 && filter_length>=4);
+
old_out0 = out[-4];
old_out1 = out[-3];
old_out2 = out[-2];
@@ -205,3 +208,12 @@ void ff_celp_lp_zero_synthesis_filterf(float *out, const float *filter_coeffs,
out[n] += filter_coeffs[i-1] * in[n-i];
}
}
+
+void ff_celp_filter_init(CELPFContext *c)
+{
+ c->celp_lp_synthesis_filterf = ff_celp_lp_synthesis_filterf;
+ c->celp_lp_zero_synthesis_filterf = ff_celp_lp_zero_synthesis_filterf;
+
+ if(HAVE_MIPSFPU)
+ ff_celp_filter_init_mips(c);
+}
diff --git a/libavcodec/celp_filters.h b/libavcodec/celp_filters.h
index c328258460..f644ec325e 100644
--- a/libavcodec/celp_filters.h
+++ b/libavcodec/celp_filters.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,55 @@
#include <stdint.h>
+typedef struct CELPFContext {
+ /**
+ * LP synthesis filter.
+ * @param[out] out pointer to output buffer
+ * - the array out[-filter_length, -1] must
+ * contain the previous result of this filter
+ * @param filter_coeffs filter coefficients.
+ * @param in input signal
+ * @param buffer_length amount of data to process
+ * @param filter_length filter length (10 for 10th order LP filter). Must be
+ * greater than 4 and even.
+ *
+ * @note Output buffer must contain filter_length samples of past
+ * speech data before pointer.
+ *
+ * Routine applies 1/A(z) filter to given speech data.
+ */
+ void (*celp_lp_synthesis_filterf)(float *out, const float *filter_coeffs,
+ const float *in, int buffer_length,
+ int filter_length);
+
+ /**
+ * LP zero synthesis filter.
+ * @param[out] out pointer to output buffer
+ * @param filter_coeffs filter coefficients.
+ * @param in input signal
+ * - the array in[-filter_length, -1] must
+ * contain the previous input of this filter
+ * @param buffer_length amount of data to process (should be a multiple of eight)
+ * @param filter_length filter length (10 for 10th order LP filter;
+ * should be a multiple of two)
+ *
+ * @note Output buffer must contain filter_length samples of past
+ * speech data before pointer.
+ *
+ * Routine applies A(z) filter to given speech data.
+ */
+ void (*celp_lp_zero_synthesis_filterf)(float *out, const float *filter_coeffs,
+ const float *in, int buffer_length,
+ int filter_length);
+
+}CELPFContext;
+
+/**
+ * Initialize CELPFContext.
+ */
+void ff_celp_filter_init(CELPFContext *c);
+void ff_celp_filter_init_mips(CELPFContext *c);
+
/**
* Circularly convolve fixed vector with a phase dispersion impulse
* response filter (D.6.2 of G.729 and 6.1.5 of AMR).
diff --git a/libavcodec/celp_math.c b/libavcodec/celp_math.c
index a9ebef697c..a96b1aed9e 100644
--- a/libavcodec/celp_math.c
+++ b/libavcodec/celp_math.c
@@ -3,28 +3,29 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
-#include <assert.h>
+#include "libavutil/avassert.h"
#include "avcodec.h"
+#include "mathops.h"
#include "celp_math.h"
#include "libavutil/common.h"
@@ -48,7 +49,7 @@ int ff_exp2(uint16_t power)
{
unsigned int result= exp2a[power>>10] + 0x10000;
- assert(power <= 0x7fff);
+ av_assert2(power <= 0x7fff);
result= (result<<3) + ((result*exp2b[(power>>5)&31])>>17);
return result + ((result*(power&31)*89)>>22);
@@ -61,10 +62,17 @@ int ff_exp2(uint16_t power)
*/
static const uint16_t tab_log2[33] =
{
+#ifdef G729_BITEXACT
+ 0, 1455, 2866, 4236, 5568, 6863, 8124, 9352,
+ 10549, 11716, 12855, 13967, 15054, 16117, 17156, 18172,
+ 19167, 20142, 21097, 22033, 22951, 23852, 24735, 25603,
+ 26455, 27291, 28113, 28922, 29716, 30497, 31266, 32023, 32767,
+#else
4, 1459, 2870, 4240, 5572, 6867, 8127, 9355,
10552, 11719, 12858, 13971, 15057, 16120, 17158, 18175,
19170, 20145, 21100, 22036, 22954, 23854, 24738, 25605,
26457, 27294, 28116, 28924, 29719, 30500, 31269, 32025, 32769,
+#endif
};
int ff_log2_q15(uint32_t value)
@@ -86,3 +94,33 @@ int ff_log2_q15(uint32_t value)
return (power_int << 15) + value;
}
+
+int64_t ff_dot_product(const int16_t *a, const int16_t *b, int length)
+{
+ int i;
+ int64_t sum = 0;
+
+ for (i = 0; i < length; i++)
+ sum += MUL16(a[i], b[i]);
+
+ return sum;
+}
+
+float ff_dot_productf(const float* a, const float* b, int length)
+{
+ float sum = 0;
+ int i;
+
+ for(i=0; i<length; i++)
+ sum += a[i] * b[i];
+
+ return sum;
+}
+
+void ff_celp_math_init(CELPMContext *c)
+{
+ c->dot_productf = ff_dot_productf;
+
+ if(HAVE_MIPSFPU)
+ ff_celp_math_init_mips(c);
+}
diff --git a/libavcodec/celp_math.h b/libavcodec/celp_math.h
index ed3f8c0fe2..18d3ad94d1 100644
--- a/libavcodec/celp_math.h
+++ b/libavcodec/celp_math.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,25 @@
#include <stdint.h>
+typedef struct CELPMContext {
+ /**
+ * Return the dot product.
+ * @param a input data array
+ * @param b input data array
+ * @param length number of elements
+ *
+ * @return dot product = sum of elementwise products
+ */
+ float (*dot_productf)(const float* a, const float* b, int length);
+
+}CELPMContext;
+
+/**
+ * Initialize CELPMContext.
+ */
+void ff_celp_math_init(CELPMContext *c);
+void ff_celp_math_init_mips(CELPMContext *c);
+
/**
* fixed-point implementation of exp2(x) in [0; 1] domain.
* @param power argument to exp2, 0 <= power <= 0x7fff
@@ -55,4 +74,24 @@ static inline int bidir_sal(int value, int offset)
else return value << offset;
}
+/**
+ * returns the dot product of 2 int16_t vectors.
+ * @param a input data array
+ * @param b input data array
+ * @param length number of elements
+ *
+ * @return dot product = sum of elementwise products
+ */
+int64_t ff_dot_product(const int16_t *a, const int16_t *b, int length);
+
+/**
+ * Return the dot product.
+ * @param a input data array
+ * @param b input data array
+ * @param length number of elements
+ *
+ * @return dot product = sum of elementwise products
+ */
+float ff_dot_productf(const float* a, const float* b, int length);
+
#endif /* AVCODEC_CELP_MATH_H */
diff --git a/libavcodec/cga_data.c b/libavcodec/cga_data.c
index 2c63ff2001..023a86b175 100644
--- a/libavcodec/cga_data.c
+++ b/libavcodec/cga_data.c
@@ -1,435 +1,46 @@
/*
* CGA/EGA/VGA ROM data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* CGA/EGA/VGA ROM data
+ * @note fonts are in libavutil/xga_font_data.[ch]
*/
#include <stdint.h>
#include "cga_data.h"
-const uint8_t ff_cga_font[2048] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
- 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
- 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
- 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
- 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
- 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
- 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
- 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
- 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
- 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
- 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
- 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
- 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
- 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
- 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
- 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
- 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
- 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
- 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
- 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
- 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
- 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
- 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
- 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
- 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
- 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
- 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
- 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
- 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
- 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
- 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
- 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
- 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
- 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
- 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
- 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
- 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
- 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
- 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
- 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
- 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
- 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
- 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
- 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
- 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
- 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
- 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
- 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
- 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
- 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
- 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
- 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
- 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
- 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
- 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
- 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
- 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
- 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
- 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
- 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
- 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
- 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
- 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
- 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
- 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
- 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
- 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
- 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
- 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
- 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
- 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
- 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
- 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
- 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
- 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
- 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
- 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
- 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
- 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
- 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
- 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
- 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
- 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
- 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
- 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
- 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
- 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
- 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
- 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
- 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
- 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
- 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
- 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-const uint8_t ff_vga16_font[4096] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
- 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
- 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
- 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
- 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
- 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
- 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
- 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
- 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
- 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
- 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
- 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
- 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
const uint32_t ff_cga_palette[16] = {
- 0x000000, 0x0000AA, 0x00AA00, 0x00AAAA, 0xAA0000, 0xAA00AA, 0xAA5500, 0xAAAAAA,
- 0x555555, 0x5555FF, 0x55FF55, 0x55FFFF, 0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF,
+ 0xFF000000, 0xFF0000AA, 0xFF00AA00, 0xFF00AAAA, 0xFFAA0000, 0xFFAA00AA, 0xFFAA5500, 0xFFAAAAAA,
+ 0xFF555555, 0xFF5555FF, 0xFF55FF55, 0xFF55FFFF, 0xFFFF5555, 0xFFFF55FF, 0xFFFFFF55, 0xFFFFFFFF,
};
const uint32_t ff_ega_palette[64] = {
- 0x000000, 0x0000AA, 0x00AA00, 0x00AAAA, 0xAA0000, 0xAA00AA, 0xAAAA00, 0xAAAAAA,
- 0x000055, 0x0000FF, 0x00AA55, 0x00AAFF, 0xAA0055, 0xAA00FF, 0xAAAA55, 0xAAAAFF,
- 0x005500, 0x0055AA, 0x00FF00, 0x00FFAA, 0xAA5500, 0xAA55AA, 0xAAFF00, 0xAAFFAA,
- 0x005555, 0x0055FF, 0x00FF55, 0x00FFFF, 0xAA5555, 0xAA55FF, 0xAAFF55, 0xAAFFFF,
- 0x550000, 0x5500AA, 0x55AA00, 0x55AAAA, 0xFF0000, 0xFF00AA, 0xFFAA00, 0xFFAAAA,
- 0x550055, 0x5500FF, 0x55AA55, 0x55AAFF, 0xFF0055, 0xFF00FF, 0xFFAA55, 0xFFAAFF,
- 0x555500, 0x5555AA, 0x55FF00, 0x55FFAA, 0xFF5500, 0xFF55AA, 0xFFFF00, 0xFFFFAA,
- 0x555555, 0x5555FF, 0x55FF55, 0x55FFFF, 0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF
+ 0xFF000000, 0xFF0000AA, 0xFF00AA00, 0xFF00AAAA, 0xFFAA0000, 0xFFAA00AA, 0xFFAAAA00, 0xFFAAAAAA,
+ 0xFF000055, 0xFF0000FF, 0xFF00AA55, 0xFF00AAFF, 0xFFAA0055, 0xFFAA00FF, 0xFFAAAA55, 0xFFAAAAFF,
+ 0xFF005500, 0xFF0055AA, 0xFF00FF00, 0xFF00FFAA, 0xFFAA5500, 0xFFAA55AA, 0xFFAAFF00, 0xFFAAFFAA,
+ 0xFF005555, 0xFF0055FF, 0xFF00FF55, 0xFF00FFFF, 0xFFAA5555, 0xFFAA55FF, 0xFFAAFF55, 0xFFAAFFFF,
+ 0xFF550000, 0xFF5500AA, 0xFF55AA00, 0xFF55AAAA, 0xFFFF0000, 0xFFFF00AA, 0xFFFFAA00, 0xFFFFAAAA,
+ 0xFF550055, 0xFF5500FF, 0xFF55AA55, 0xFF55AAFF, 0xFFFF0055, 0xFFFF00FF, 0xFFFFAA55, 0xFFFFAAFF,
+ 0xFF555500, 0xFF5555AA, 0xFF55FF00, 0xFF55FFAA, 0xFFFF5500, 0xFFFF55AA, 0xFFFFFF00, 0xFFFFFFAA,
+ 0xFF555555, 0xFF5555FF, 0xFF55FF55, 0xFF55FFFF, 0xFFFF5555, 0xFFFF55FF, 0xFFFFFF55, 0xFFFFFFFF
};
void ff_draw_pc_font(uint8_t *dst, int linesize, const uint8_t *font, int font_height, int ch, int fg, int bg)
diff --git a/libavcodec/cga_data.h b/libavcodec/cga_data.h
index 2149cfd2f1..3f5281a264 100644
--- a/libavcodec/cga_data.h
+++ b/libavcodec/cga_data.h
@@ -1,26 +1,27 @@
/*
* CGA/EGA/VGA ROM data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* CGA/EGA/VGA ROM data
+ * @note fonts are in libavutil/xga_font_data.[ch]
*/
#ifndef AVCODEC_CGA_DATA_H
@@ -28,8 +29,6 @@
#include <stdint.h>
-extern const uint8_t ff_cga_font[2048];
-extern const uint8_t ff_vga16_font[4096];
extern const uint32_t ff_cga_palette[16];
extern const uint32_t ff_ega_palette[64];
diff --git a/libavcodec/chomp_bsf.c b/libavcodec/chomp_bsf.c
index 9ed7496930..2b93fa999e 100644
--- a/libavcodec/chomp_bsf.c
+++ b/libavcodec/chomp_bsf.c
@@ -2,20 +2,20 @@
* Chomp bitstream filter
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,7 +41,6 @@ static int chomp_filter(AVBitStreamFilterContext *bsfc,
* This filter removes a string of NULL bytes from the end of a packet.
*/
AVBitStreamFilter ff_chomp_bsf = {
- "chomp",
- 0,
- chomp_filter,
+ .name = "chomp",
+ .filter = chomp_filter,
};
diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c
index 3a740b22c1..1a6d4f55fb 100644
--- a/libavcodec/cinepak.c
+++ b/libavcodec/cinepak.c
@@ -1,21 +1,21 @@
/*
* Cinepak Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,9 @@
* http://www.csse.monash.edu.au/~timf/
* @see For more information on the quirky data inside Sega FILM/CPK files, visit:
* http://wiki.multimedia.cx/index.php?title=Sega_FILM
+ *
+ * Cinepak colorspace support (c) 2013 Rl, Aetey Global Technologies AB
+ * @author Cinepak colorspace, Rl, Aetey Global Technologies AB
*/
#include <stdio.h>
@@ -40,10 +43,7 @@
#include "internal.h"
-typedef struct cvid_codebook {
- uint8_t y0, y1, y2, y3;
- uint8_t u, v;
-} cvid_codebook;
+typedef uint8_t cvid_codebook[12];
#define MAX_STRIPS 32
@@ -79,12 +79,14 @@ static void cinepak_decode_codebook (cvid_codebook *codebook,
const uint8_t *eod = (data + size);
uint32_t flag, mask;
int i, n;
+ uint8_t *p;
/* check if this chunk contains 4- or 6-element vectors */
n = (chunk_id & 0x04) ? 4 : 6;
flag = 0;
mask = 0;
+ p = codebook[0];
for (i=0; i < 256; i++) {
if ((chunk_id & 0x01) && !(mask >>= 1)) {
if ((data + 4) > eod)
@@ -96,28 +98,33 @@ static void cinepak_decode_codebook (cvid_codebook *codebook,
}
if (!(chunk_id & 0x01) || (flag & mask)) {
+ int k, kk;
+
if ((data + n) > eod)
break;
+ for (k = 0; k < 4; ++k) {
+ int r = *data++;
+ for (kk = 0; kk < 3; ++kk)
+ *p++ = r;
+ }
if (n == 6) {
- codebook[i].y0 = *data++;
- codebook[i].y1 = *data++;
- codebook[i].y2 = *data++;
- codebook[i].y3 = *data++;
- codebook[i].u = 128 + *data++;
- codebook[i].v = 128 + *data++;
- } else {
- /* this codebook type indicates either greyscale or
- * palettized video; if palettized, U & V components will
- * not be used so it is safe to set them to 128 for the
- * benefit of greyscale rendering in YUV420P */
- codebook[i].y0 = *data++;
- codebook[i].y1 = *data++;
- codebook[i].y2 = *data++;
- codebook[i].y3 = *data++;
- codebook[i].u = 128;
- codebook[i].v = 128;
+ int r, g, b, u, v;
+ u = *(int8_t *)data++;
+ v = *(int8_t *)data++;
+ p -= 12;
+ for(k=0; k<4; ++k) {
+ r = *p++ + v*2;
+ g = *p++ - (u/2) - v;
+ b = *p + u*2;
+ p -= 2;
+ *p++ = av_clip_uint8(r);
+ *p++ = av_clip_uint8(g);
+ *p++ = av_clip_uint8(b);
+ }
}
+ } else {
+ p += 12;
}
}
}
@@ -127,25 +134,31 @@ static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip,
{
const uint8_t *eod = (data + size);
uint32_t flag, mask;
- cvid_codebook *codebook;
- unsigned int x, y;
- uint32_t iy[4];
- uint32_t iu[2];
- uint32_t iv[2];
+ uint8_t *cb0, *cb1, *cb2, *cb3;
+ int x, y;
+ char *ip0, *ip1, *ip2, *ip3;
flag = 0;
mask = 0;
for (y=strip->y1; y < strip->y2; y+=4) {
- iy[0] = strip->x1 + (y * s->frame->linesize[0]);
- iy[1] = iy[0] + s->frame->linesize[0];
- iy[2] = iy[1] + s->frame->linesize[0];
- iy[3] = iy[2] + s->frame->linesize[0];
- iu[0] = (strip->x1/2) + ((y/2) * s->frame->linesize[1]);
- iu[1] = iu[0] + s->frame->linesize[1];
- iv[0] = (strip->x1/2) + ((y/2) * s->frame->linesize[2]);
- iv[1] = iv[0] + s->frame->linesize[2];
+/* take care of y dimension not being multiple of 4, such streams exist */
+ ip0 = ip1 = ip2 = ip3 = s->frame->data[0] +
+ (s->palette_video?strip->x1:strip->x1*3) + (y * s->frame->linesize[0]);
+ if(s->avctx->height - y > 1) {
+ ip1 = ip0 + s->frame->linesize[0];
+ if(s->avctx->height - y > 2) {
+ ip2 = ip1 + s->frame->linesize[0];
+ if(s->avctx->height - y > 3) {
+ ip3 = ip2 + s->frame->linesize[0];
+ }
+ }
+ }
+/* to get the correct picture for not-multiple-of-4 cases let us fill
+ * each block from the bottom up, thus possibly overwriting the top line
+ * more than once but ending with the correct data in place
+ * (instead of in-loop checking) */
for (x=strip->x1; x < strip->x2; x+=4) {
if ((chunk_id & 0x01) && !(mask >>= 1)) {
@@ -168,97 +181,82 @@ static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip,
}
if ((chunk_id & 0x02) || (~flag & mask)) {
+ uint8_t *p;
if (data >= eod)
return AVERROR_INVALIDDATA;
- codebook = &strip->v1_codebook[*data++];
- s->frame->data[0][iy[0] + 0] = codebook->y0;
- s->frame->data[0][iy[0] + 1] = codebook->y0;
- s->frame->data[0][iy[1] + 0] = codebook->y0;
- s->frame->data[0][iy[1] + 1] = codebook->y0;
- if (!s->palette_video) {
- s->frame->data[1][iu[0]] = codebook->u;
- s->frame->data[2][iv[0]] = codebook->v;
- }
-
- s->frame->data[0][iy[0] + 2] = codebook->y1;
- s->frame->data[0][iy[0] + 3] = codebook->y1;
- s->frame->data[0][iy[1] + 2] = codebook->y1;
- s->frame->data[0][iy[1] + 3] = codebook->y1;
- if (!s->palette_video) {
- s->frame->data[1][iu[0] + 1] = codebook->u;
- s->frame->data[2][iv[0] + 1] = codebook->v;
- }
-
- s->frame->data[0][iy[2] + 0] = codebook->y2;
- s->frame->data[0][iy[2] + 1] = codebook->y2;
- s->frame->data[0][iy[3] + 0] = codebook->y2;
- s->frame->data[0][iy[3] + 1] = codebook->y2;
- if (!s->palette_video) {
- s->frame->data[1][iu[1]] = codebook->u;
- s->frame->data[2][iv[1]] = codebook->v;
- }
-
- s->frame->data[0][iy[2] + 2] = codebook->y3;
- s->frame->data[0][iy[2] + 3] = codebook->y3;
- s->frame->data[0][iy[3] + 2] = codebook->y3;
- s->frame->data[0][iy[3] + 3] = codebook->y3;
- if (!s->palette_video) {
- s->frame->data[1][iu[1] + 1] = codebook->u;
- s->frame->data[2][iv[1] + 1] = codebook->v;
+ p = strip->v1_codebook[*data++];
+ if (s->palette_video) {
+ ip3[0] = ip3[1] = ip2[0] = ip2[1] = p[6];
+ ip3[2] = ip3[3] = ip2[2] = ip2[3] = p[9];
+ ip1[0] = ip1[1] = ip0[0] = ip0[1] = p[0];
+ ip1[2] = ip1[3] = ip0[2] = ip0[3] = p[3];
+ } else {
+ p += 6;
+ memcpy(ip3 + 0, p, 3); memcpy(ip3 + 3, p, 3);
+ memcpy(ip2 + 0, p, 3); memcpy(ip2 + 3, p, 3);
+ p += 3; /* ... + 9 */
+ memcpy(ip3 + 6, p, 3); memcpy(ip3 + 9, p, 3);
+ memcpy(ip2 + 6, p, 3); memcpy(ip2 + 9, p, 3);
+ p -= 9; /* ... + 0 */
+ memcpy(ip1 + 0, p, 3); memcpy(ip1 + 3, p, 3);
+ memcpy(ip0 + 0, p, 3); memcpy(ip0 + 3, p, 3);
+ p += 3; /* ... + 3 */
+ memcpy(ip1 + 6, p, 3); memcpy(ip1 + 9, p, 3);
+ memcpy(ip0 + 6, p, 3); memcpy(ip0 + 9, p, 3);
}
} else if (flag & mask) {
if ((data + 4) > eod)
return AVERROR_INVALIDDATA;
- codebook = &strip->v4_codebook[*data++];
- s->frame->data[0][iy[0] + 0] = codebook->y0;
- s->frame->data[0][iy[0] + 1] = codebook->y1;
- s->frame->data[0][iy[1] + 0] = codebook->y2;
- s->frame->data[0][iy[1] + 1] = codebook->y3;
- if (!s->palette_video) {
- s->frame->data[1][iu[0]] = codebook->u;
- s->frame->data[2][iv[0]] = codebook->v;
- }
-
- codebook = &strip->v4_codebook[*data++];
- s->frame->data[0][iy[0] + 2] = codebook->y0;
- s->frame->data[0][iy[0] + 3] = codebook->y1;
- s->frame->data[0][iy[1] + 2] = codebook->y2;
- s->frame->data[0][iy[1] + 3] = codebook->y3;
- if (!s->palette_video) {
- s->frame->data[1][iu[0] + 1] = codebook->u;
- s->frame->data[2][iv[0] + 1] = codebook->v;
- }
-
- codebook = &strip->v4_codebook[*data++];
- s->frame->data[0][iy[2] + 0] = codebook->y0;
- s->frame->data[0][iy[2] + 1] = codebook->y1;
- s->frame->data[0][iy[3] + 0] = codebook->y2;
- s->frame->data[0][iy[3] + 1] = codebook->y3;
- if (!s->palette_video) {
- s->frame->data[1][iu[1]] = codebook->u;
- s->frame->data[2][iv[1]] = codebook->v;
- }
-
- codebook = &strip->v4_codebook[*data++];
- s->frame->data[0][iy[2] + 2] = codebook->y0;
- s->frame->data[0][iy[2] + 3] = codebook->y1;
- s->frame->data[0][iy[3] + 2] = codebook->y2;
- s->frame->data[0][iy[3] + 3] = codebook->y3;
- if (!s->palette_video) {
- s->frame->data[1][iu[1] + 1] = codebook->u;
- s->frame->data[2][iv[1] + 1] = codebook->v;
+ cb0 = strip->v4_codebook[*data++];
+ cb1 = strip->v4_codebook[*data++];
+ cb2 = strip->v4_codebook[*data++];
+ cb3 = strip->v4_codebook[*data++];
+ if (s->palette_video) {
+ uint8_t *p;
+ p = ip3;
+ *p++ = cb2[6];
+ *p++ = cb2[9];
+ *p++ = cb3[6];
+ *p = cb3[9];
+ p = ip2;
+ *p++ = cb2[0];
+ *p++ = cb2[3];
+ *p++ = cb3[0];
+ *p = cb3[3];
+ p = ip1;
+ *p++ = cb0[6];
+ *p++ = cb0[9];
+ *p++ = cb1[6];
+ *p = cb1[9];
+ p = ip0;
+ *p++ = cb0[0];
+ *p++ = cb0[3];
+ *p++ = cb1[0];
+ *p = cb1[3];
+ } else {
+ memcpy(ip3 + 0, cb2 + 6, 6);
+ memcpy(ip3 + 6, cb3 + 6, 6);
+ memcpy(ip2 + 0, cb2 + 0, 6);
+ memcpy(ip2 + 6, cb3 + 0, 6);
+ memcpy(ip1 + 0, cb0 + 6, 6);
+ memcpy(ip1 + 6, cb1 + 6, 6);
+ memcpy(ip0 + 0, cb0 + 0, 6);
+ memcpy(ip0 + 6, cb1 + 0, 6);
}
}
}
- iy[0] += 4; iy[1] += 4;
- iy[2] += 4; iy[3] += 4;
- iu[0] += 2; iu[1] += 2;
- iv[0] += 2; iv[1] += 2;
+ if (s->palette_video) {
+ ip0 += 4; ip1 += 4;
+ ip2 += 4; ip3 += 4;
+ } else {
+ ip0 += 12; ip1 += 12;
+ ip2 += 12; ip3 += 12;
+ }
}
}
@@ -362,15 +360,23 @@ static int cinepak_decode (CinepakContext *s)
num_strips = FFMIN(num_strips, MAX_STRIPS);
+ s->frame->key_frame = 0;
+
for (i=0; i < num_strips; i++) {
if ((s->data + 12) > eod)
return AVERROR_INVALIDDATA;
s->strips[i].id = s->data[0];
- s->strips[i].y1 = y0;
- s->strips[i].x1 = 0;
- s->strips[i].y2 = y0 + AV_RB16 (&s->data[8]);
- s->strips[i].x2 = s->avctx->width;
+/* zero y1 means "relative to the previous stripe" */
+ if (!(s->strips[i].y1 = AV_RB16 (&s->data[4])))
+ s->strips[i].y2 = (s->strips[i].y1 = y0) + AV_RB16 (&s->data[8]);
+ else
+ s->strips[i].y2 = AV_RB16 (&s->data[8]);
+ s->strips[i].x1 = AV_RB16 (&s->data[6]);
+ s->strips[i].x2 = AV_RB16 (&s->data[10]);
+
+ if (s->strips[i].id == 0x10)
+ s->frame->key_frame = 1;
strip_size = AV_RB24 (&s->data[1]) - 12;
if (strip_size < 0)
@@ -403,12 +409,13 @@ static av_cold int cinepak_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
s->width = (avctx->width + 3) & ~3;
s->height = (avctx->height + 3) & ~3;
+
s->sega_film_skip_bytes = -1; /* uninitialized state */
// check for paletted data
if (avctx->bits_per_coded_sample != 8) {
s->palette_video = 0;
- avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
} else {
s->palette_video = 1;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
@@ -432,10 +439,8 @@ static int cinepak_decode_frame(AVCodecContext *avctx,
s->data = buf;
s->size = buf_size;
- if ((ret = ff_reget_buffer(avctx, s->frame))) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
if (s->palette_video) {
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
@@ -445,7 +450,9 @@ static int cinepak_decode_frame(AVCodecContext *avctx,
}
}
- cinepak_decode(s);
+ if ((ret = cinepak_decode(s)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "cinepak_decode failed\n");
+ }
if (s->palette_video)
memcpy (s->frame->data[1], s->pal, AVPALETTE_SIZE);
diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c
new file mode 100644
index 0000000000..727734519c
--- /dev/null
+++ b/libavcodec/cinepakenc.c
@@ -0,0 +1,1335 @@
+/*
+ * Cinepak encoder (c) 2011 Tomas Härdin
+ * http://titan.codemill.se/~tomhar/cinepakenc.patch
+ *
+ * Fixes and improvements, vintage decoders compatibility
+ * (c) 2013, 2014 Rl, Aetey Global Technologies AB
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+ * TODO:
+ * - optimize: color space conversion, ...
+ * - implement options to set the min/max number of strips?
+ * MAYBE:
+ * - "optimally" split the frame into several non-regular areas
+ * using a separate codebook pair for each area and approximating
+ * the area by several rectangular strips (generally not full width ones)
+ * (use quadtree splitting? a simple fixed-granularity grid?)
+ *
+ *
+ * version 2014-01-23 Rl
+ * - added option handling for flexibility
+ *
+ * version 2014-01-21 Rl
+ * - believe it or not, now we get even smaller files, with better quality
+ * (which means I missed an optimization earlier :)
+ *
+ * version 2014-01-20 Rl
+ * - made the encoder compatible with vintage decoders
+ * and added some yet unused code for possible future
+ * incremental codebook updates
+ * - fixed a small memory leak
+ *
+ * version 2013-04-28 Rl
+ * - bugfixed codebook optimization logic
+ *
+ * version 2013-02-14 Rl
+ * "Valentine's Day" version:
+ * - made strip division more robust
+ * - minimized bruteforcing the number of strips,
+ * (costs some R/D but speeds up compession a lot), the heuristic
+ * assumption is that score as a function of the number of strips has
+ * one wide minimum which moves slowly, of course not fully true
+ * - simplified codebook generation,
+ * the old code was meant for other optimizations than we actually do
+ * - optimized the codebook generation / error estimation for MODE_MC
+ *
+ * version 2013-02-12 Rl
+ * - separated codebook training sets, avoided the transfer of wasted bytes,
+ * which yields both better quality and smaller files
+ * - now using the correct colorspace (TODO: move conversion to libswscale)
+ *
+ * version 2013-02-08 Rl
+ * - fixes/optimization in multistrip encoding and codebook size choice,
+ * quality/bitrate is now better than that of the binary proprietary encoder
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avcodec.h"
+#include "libavutil/lfg.h"
+#include "elbg.h"
+#include "internal.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+
+#define CVID_HEADER_SIZE 10
+#define STRIP_HEADER_SIZE 12
+#define CHUNK_HEADER_SIZE 4
+
+#define MB_SIZE 4 //4x4 MBs
+#define MB_AREA (MB_SIZE*MB_SIZE)
+
+#define VECTOR_MAX 6 //six or four entries per vector depending on format
+#define CODEBOOK_MAX 256 //size of a codebook
+
+#define MAX_STRIPS 32 //Note: having fewer choices regarding the number of strips speeds up encoding (obviously)
+#define MIN_STRIPS 1 //Note: having more strips speeds up encoding the frame (this is less obvious)
+// MAX_STRIPS limits the maximum quality you can reach
+// when you want hight quality on high resolutions,
+// MIN_STRIPS limits the minimum efficiently encodable bit rate
+// on low resolutions
+// the numbers are only used for brute force optimization for the first frame,
+// for the following frames they are adaptively readjusted
+// NOTE the decoder in ffmpeg has its own arbitrary limitation on the number
+// of strips, currently 32
+
+typedef enum {
+ MODE_V1_ONLY = 0,
+ MODE_V1_V4,
+ MODE_MC,
+
+ MODE_COUNT,
+} CinepakMode;
+
+typedef enum {
+ ENC_V1,
+ ENC_V4,
+ ENC_SKIP,
+
+ ENC_UNCERTAIN
+} mb_encoding;
+
+typedef struct {
+ int v1_vector; //index into v1 codebook
+ int v1_error; //error when using V1 encoding
+ int v4_vector[4]; //indices into v4 codebooks
+ int v4_error; //error when using V4 encoding
+ int skip_error; //error when block is skipped (aka copied from last frame)
+ mb_encoding best_encoding; //last result from calculate_mode_score()
+} mb_info;
+
+typedef struct {
+ int v1_codebook[CODEBOOK_MAX*VECTOR_MAX];
+ int v4_codebook[CODEBOOK_MAX*VECTOR_MAX];
+ int v1_size;
+ int v4_size;
+ CinepakMode mode;
+} strip_info;
+
+typedef struct {
+ const AVClass *class;
+ AVCodecContext *avctx;
+ unsigned char *pict_bufs[4], *strip_buf, *frame_buf;
+ AVFrame *last_frame;
+ AVFrame *best_frame;
+ AVFrame *scratch_frame;
+ AVFrame *input_frame;
+ enum AVPixelFormat pix_fmt;
+ int w, h;
+ int frame_buf_size;
+ int curframe, keyint;
+ AVLFG randctx;
+ uint64_t lambda;
+ int *codebook_input;
+ int *codebook_closest;
+ mb_info *mb; //MB RD state
+ int min_strips; //the current limit
+ int max_strips; //the current limit
+#ifdef CINEPAKENC_DEBUG
+ mb_info *best_mb; //TODO: remove. only used for printing stats
+ int num_v1_mode, num_v4_mode, num_mc_mode;
+ int num_v1_encs, num_v4_encs, num_skips;
+#endif
+// options
+ int max_extra_cb_iterations;
+ int skip_empty_cb;
+ int min_min_strips;
+ int max_max_strips;
+ int strip_number_delta_range;
+} CinepakEncContext;
+
+#define OFFSET(x) offsetof(CinepakEncContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "max_extra_cb_iterations", "Max extra codebook recalculation passes, more is better and slower", OFFSET(max_extra_cb_iterations), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, VE },
+ { "skip_empty_cb", "Avoid wasting bytes, ignore vintage MacOS decoder", OFFSET(skip_empty_cb), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "max_strips", "Limit strips/frame, vintage compatible is 1..3, otherwise the more the better", OFFSET(max_max_strips), AV_OPT_TYPE_INT, { .i64 = 3 }, MIN_STRIPS, MAX_STRIPS, VE },
+ { "min_strips", "Enforce min strips/frame, more is worse and faster, must be <= max_strips", OFFSET(min_min_strips), AV_OPT_TYPE_INT, { .i64 = MIN_STRIPS }, MIN_STRIPS, MAX_STRIPS, VE },
+ { "strip_number_adaptivity", "How fast the strip number adapts, more is slightly better, much slower", OFFSET(strip_number_delta_range), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_STRIPS-MIN_STRIPS, VE },
+ { NULL },
+};
+
+static const AVClass cinepak_class = {
+ .class_name = "cinepak",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static av_cold int cinepak_encode_init(AVCodecContext *avctx)
+{
+ CinepakEncContext *s = avctx->priv_data;
+ int x, mb_count, strip_buf_size, frame_buf_size;
+
+ if (avctx->width & 3 || avctx->height & 3) {
+ av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of four (got %ix%i)\n",
+ avctx->width, avctx->height);
+ return AVERROR(EINVAL);
+ }
+
+ if (s->min_min_strips > s->max_max_strips) {
+ av_log(avctx, AV_LOG_ERROR, "minimal number of strips can not exceed maximal (got %i and %i)\n",
+ s->min_min_strips, s->max_max_strips);
+ return AVERROR(EINVAL);
+ }
+
+ if (!(s->last_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ if (!(s->best_frame = av_frame_alloc()))
+ goto enomem;
+ if (!(s->scratch_frame = av_frame_alloc()))
+ goto enomem;
+ if (avctx->pix_fmt == AV_PIX_FMT_RGB24)
+ if (!(s->input_frame = av_frame_alloc()))
+ goto enomem;
+
+ if (!(s->codebook_input = av_malloc(sizeof(int) * (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2)))
+ goto enomem;
+
+ if (!(s->codebook_closest = av_malloc(sizeof(int) * (avctx->width * avctx->height) >> 2)))
+ goto enomem;
+
+ for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++)
+ if(!(s->pict_bufs[x] = av_malloc((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2)))
+ goto enomem;
+
+ mb_count = avctx->width * avctx->height / MB_AREA;
+
+ //the largest possible chunk is 0x31 with all MBs encoded in V4 mode
+ //and full codebooks being replaced in INTER mode,
+ // which is 34 bits per MB
+ //and 2*256 extra flag bits per strip
+ strip_buf_size = STRIP_HEADER_SIZE + 3 * CHUNK_HEADER_SIZE + 2 * VECTOR_MAX * CODEBOOK_MAX + 4 * (mb_count + (mb_count + 15) / 16) + (2 * CODEBOOK_MAX)/8;
+
+ frame_buf_size = CVID_HEADER_SIZE + s->max_max_strips * strip_buf_size;
+
+ if (!(s->strip_buf = av_malloc(strip_buf_size)))
+ goto enomem;
+
+ if (!(s->frame_buf = av_malloc(frame_buf_size)))
+ goto enomem;
+
+ if (!(s->mb = av_malloc_array(mb_count, sizeof(mb_info))))
+ goto enomem;
+
+#ifdef CINEPAKENC_DEBUG
+ if (!(s->best_mb = av_malloc_array(mb_count, sizeof(mb_info))))
+ goto enomem;
+#endif
+
+ av_lfg_init(&s->randctx, 1);
+ s->avctx = avctx;
+ s->w = avctx->width;
+ s->h = avctx->height;
+ s->frame_buf_size = frame_buf_size;
+ s->curframe = 0;
+ s->keyint = avctx->keyint_min;
+ s->pix_fmt = avctx->pix_fmt;
+
+ //set up AVFrames
+ s->last_frame->data[0] = s->pict_bufs[0];
+ s->last_frame->linesize[0] = s->w;
+ s->best_frame->data[0] = s->pict_bufs[1];
+ s->best_frame->linesize[0] = s->w;
+ s->scratch_frame->data[0] = s->pict_bufs[2];
+ s->scratch_frame->linesize[0] = s->w;
+
+ if (s->pix_fmt == AV_PIX_FMT_RGB24) {
+ s->last_frame->data[1] = s->last_frame->data[0] + s->w * s->h;
+ s->last_frame->data[2] = s->last_frame->data[1] + ((s->w * s->h) >> 2);
+ s->last_frame->linesize[1] = s->last_frame->linesize[2] = s->w >> 1;
+
+ s->best_frame->data[1] = s->best_frame->data[0] + s->w * s->h;
+ s->best_frame->data[2] = s->best_frame->data[1] + ((s->w * s->h) >> 2);
+ s->best_frame->linesize[1] = s->best_frame->linesize[2] = s->w >> 1;
+
+ s->scratch_frame->data[1] = s->scratch_frame->data[0] + s->w * s->h;
+ s->scratch_frame->data[2] = s->scratch_frame->data[1] + ((s->w * s->h) >> 2);
+ s->scratch_frame->linesize[1] = s->scratch_frame->linesize[2] = s->w >> 1;
+
+ s->input_frame->data[0] = s->pict_bufs[3];
+ s->input_frame->linesize[0] = s->w;
+ s->input_frame->data[1] = s->input_frame->data[0] + s->w * s->h;
+ s->input_frame->data[2] = s->input_frame->data[1] + ((s->w * s->h) >> 2);
+ s->input_frame->linesize[1] = s->input_frame->linesize[2] = s->w >> 1;
+ }
+
+ s->min_strips = s->min_min_strips;
+ s->max_strips = s->max_max_strips;
+
+#ifdef CINEPAKENC_DEBUG
+ s->num_v1_mode = s->num_v4_mode = s->num_mc_mode = s->num_v1_encs = s->num_v4_encs = s->num_skips = 0;
+#endif
+
+ return 0;
+
+enomem:
+ av_frame_free(&s->last_frame);
+ av_frame_free(&s->best_frame);
+ av_frame_free(&s->scratch_frame);
+ if (avctx->pix_fmt == AV_PIX_FMT_RGB24)
+ av_frame_free(&s->input_frame);
+ av_freep(&s->codebook_input);
+ av_freep(&s->codebook_closest);
+ av_freep(&s->strip_buf);
+ av_freep(&s->frame_buf);
+ av_freep(&s->mb);
+#ifdef CINEPAKENC_DEBUG
+ av_freep(&s->best_mb);
+#endif
+
+ for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++)
+ av_freep(&s->pict_bufs[x]);
+
+ return AVERROR(ENOMEM);
+}
+
+static int64_t calculate_mode_score(CinepakEncContext *s, int h, strip_info *info, int report, int *training_set_v1_shrunk, int *training_set_v4_shrunk
+#ifdef CINEPAK_REPORT_SERR
+, int64_t *serr
+#endif
+)
+{
+ //score = FF_LAMBDA_SCALE * error + lambda * bits
+ int x;
+ int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
+ int mb_count = s->w * h / MB_AREA;
+ mb_info *mb;
+ int64_t score1, score2, score3;
+ int64_t ret = s->lambda * ((info->v1_size ? CHUNK_HEADER_SIZE + info->v1_size * entry_size : 0) +
+ (info->v4_size ? CHUNK_HEADER_SIZE + info->v4_size * entry_size : 0) +
+ CHUNK_HEADER_SIZE) << 3;
+
+ //av_log(s->avctx, AV_LOG_INFO, "sizes %3i %3i -> %9lli score mb_count %i", info->v1_size, info->v4_size, (long long int)ret, mb_count);
+
+#ifdef CINEPAK_REPORT_SERR
+ *serr = 0;
+#endif
+
+ switch(info->mode) {
+ case MODE_V1_ONLY:
+ //one byte per MB
+ ret += s->lambda * 8 * mb_count;
+
+// while calculating we assume all blocks are ENC_V1
+ for(x = 0; x < mb_count; x++) {
+ mb = &s->mb[x];
+ ret += FF_LAMBDA_SCALE * mb->v1_error;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v1_error;
+#endif
+// this function is never called for report in MODE_V1_ONLY
+// if(!report)
+ mb->best_encoding = ENC_V1;
+ }
+
+ break;
+ case MODE_V1_V4:
+ //9 or 33 bits per MB
+ if(report) {
+// no moves between the corresponding training sets are allowed
+ *training_set_v1_shrunk = *training_set_v4_shrunk = 0;
+ for(x = 0; x < mb_count; x++) {
+ int mberr;
+ mb = &s->mb[x];
+ if(mb->best_encoding == ENC_V1)
+ score1 = s->lambda * 9 + FF_LAMBDA_SCALE * (mberr=mb->v1_error);
+ else
+ score1 = s->lambda * 33 + FF_LAMBDA_SCALE * (mberr=mb->v4_error);
+ ret += score1;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mberr;
+#endif
+ }
+ } else { // find best mode per block
+ for(x = 0; x < mb_count; x++) {
+ mb = &s->mb[x];
+ score1 = s->lambda * 9 + FF_LAMBDA_SCALE * mb->v1_error;
+ score2 = s->lambda * 33 + FF_LAMBDA_SCALE * mb->v4_error;
+
+ if(score1 <= score2) {
+ ret += score1;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v1_error;
+#endif
+ mb->best_encoding = ENC_V1;
+ } else {
+ ret += score2;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v4_error;
+#endif
+ mb->best_encoding = ENC_V4;
+ }
+ }
+ }
+
+ break;
+ case MODE_MC:
+ //1, 10 or 34 bits per MB
+ if(report) {
+ int v1_shrunk = 0, v4_shrunk = 0;
+ for(x = 0; x < mb_count; x++) {
+ mb = &s->mb[x];
+// it is OK to move blocks to ENC_SKIP here
+// but not to any codebook encoding!
+ score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error;
+ if(mb->best_encoding == ENC_SKIP) {
+ ret += score1;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->skip_error;
+#endif
+ } else if(mb->best_encoding == ENC_V1) {
+ if((score2=s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error) >= score1) {
+ mb->best_encoding = ENC_SKIP;
+ ++v1_shrunk;
+ ret += score1;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->skip_error;
+#endif
+ } else {
+ ret += score2;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v1_error;
+#endif
+ }
+ } else {
+ if((score3=s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error) >= score1) {
+ mb->best_encoding = ENC_SKIP;
+ ++v4_shrunk;
+ ret += score1;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->skip_error;
+#endif
+ } else {
+ ret += score3;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v4_error;
+#endif
+ }
+ }
+ }
+ *training_set_v1_shrunk = v1_shrunk;
+ *training_set_v4_shrunk = v4_shrunk;
+ } else { // find best mode per block
+ for(x = 0; x < mb_count; x++) {
+ mb = &s->mb[x];
+ score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error;
+ score2 = s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error;
+ score3 = s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error;
+
+ if(score1 <= score2 && score1 <= score3) {
+ ret += score1;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->skip_error;
+#endif
+ mb->best_encoding = ENC_SKIP;
+ } else if(score2 <= score3) {
+ ret += score2;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v1_error;
+#endif
+ mb->best_encoding = ENC_V1;
+ } else {
+ ret += score3;
+#ifdef CINEPAK_REPORT_SERR
+ *serr += mb->v4_error;
+#endif
+ mb->best_encoding = ENC_V4;
+ }
+ }
+ }
+
+ break;
+ }
+
+ return ret;
+}
+
+static int write_chunk_header(unsigned char *buf, int chunk_type, int chunk_size)
+{
+ buf[0] = chunk_type;
+ AV_WB24(&buf[1], chunk_size + CHUNK_HEADER_SIZE);
+ return CHUNK_HEADER_SIZE;
+}
+
+static int encode_codebook(CinepakEncContext *s, int *codebook, int size, int chunk_type_yuv, int chunk_type_gray, unsigned char *buf)
+{
+ int x, y, ret, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
+ int incremental_codebook_replacement_mode = 0; // hardcoded here,
+ // the compiler should notice that this is a constant -- rl
+
+ ret = write_chunk_header(buf,
+ s->pix_fmt == AV_PIX_FMT_RGB24 ?
+ chunk_type_yuv+(incremental_codebook_replacement_mode?1:0) :
+ chunk_type_gray+(incremental_codebook_replacement_mode?1:0),
+ entry_size * size
+ + (incremental_codebook_replacement_mode?(size+31)/32*4:0) );
+
+// we do codebook encoding according to the "intra" mode
+// but we keep the "dead" code for reference in case we will want
+// to use incremental codebook updates (which actually would give us
+// "kind of" motion compensation, especially in 1 strip/frame case) -- rl
+// (of course, the code will be not useful as-is)
+ if(incremental_codebook_replacement_mode) {
+ int flags = 0;
+ int flagsind;
+ for(x = 0; x < size; x++) {
+ if(flags == 0) {
+ flagsind = ret;
+ ret += 4;
+ flags = 0x80000000;
+ } else
+ flags = ((flags>>1) | 0x80000000);
+ for(y = 0; y < entry_size; y++)
+ buf[ret++] = codebook[y + x*entry_size] ^ (y >= 4 ? 0x80 : 0);
+ if((flags&0xffffffff) == 0xffffffff) {
+ AV_WB32(&buf[flagsind], flags);
+ flags = 0;
+ }
+ }
+ if(flags)
+ AV_WB32(&buf[flagsind], flags);
+ } else
+ for(x = 0; x < size; x++)
+ for(y = 0; y < entry_size; y++)
+ buf[ret++] = codebook[y + x*entry_size] ^ (y >= 4 ? 0x80 : 0);
+
+ return ret;
+}
+
+//sets out to the sub picture starting at (x,y) in in
+static void get_sub_picture(CinepakEncContext *s, int x, int y, AVPicture *in, AVPicture *out)
+{
+ out->data[0] = in->data[0] + x + y * in->linesize[0];
+ out->linesize[0] = in->linesize[0];
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24) {
+ out->data[1] = in->data[1] + (x >> 1) + (y >> 1) * in->linesize[1];
+ out->linesize[1] = in->linesize[1];
+
+ out->data[2] = in->data[2] + (x >> 1) + (y >> 1) * in->linesize[2];
+ out->linesize[2] = in->linesize[2];
+ }
+}
+
+//decodes the V1 vector in mb into the 4x4 MB pointed to by sub_pict
+static void decode_v1_vector(CinepakEncContext *s, AVPicture *sub_pict, int v1_vector, strip_info *info)
+{
+ int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
+
+ sub_pict->data[0][0] =
+ sub_pict->data[0][1] =
+ sub_pict->data[0][ sub_pict->linesize[0]] =
+ sub_pict->data[0][1+ sub_pict->linesize[0]] = info->v1_codebook[v1_vector*entry_size];
+
+ sub_pict->data[0][2] =
+ sub_pict->data[0][3] =
+ sub_pict->data[0][2+ sub_pict->linesize[0]] =
+ sub_pict->data[0][3+ sub_pict->linesize[0]] = info->v1_codebook[v1_vector*entry_size+1];
+
+ sub_pict->data[0][2*sub_pict->linesize[0]] =
+ sub_pict->data[0][1+2*sub_pict->linesize[0]] =
+ sub_pict->data[0][ 3*sub_pict->linesize[0]] =
+ sub_pict->data[0][1+3*sub_pict->linesize[0]] = info->v1_codebook[v1_vector*entry_size+2];
+
+ sub_pict->data[0][2+2*sub_pict->linesize[0]] =
+ sub_pict->data[0][3+2*sub_pict->linesize[0]] =
+ sub_pict->data[0][2+3*sub_pict->linesize[0]] =
+ sub_pict->data[0][3+3*sub_pict->linesize[0]] = info->v1_codebook[v1_vector*entry_size+3];
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24) {
+ sub_pict->data[1][0] =
+ sub_pict->data[1][1] =
+ sub_pict->data[1][ sub_pict->linesize[1]] =
+ sub_pict->data[1][1+ sub_pict->linesize[1]] = info->v1_codebook[v1_vector*entry_size+4];
+
+ sub_pict->data[2][0] =
+ sub_pict->data[2][1] =
+ sub_pict->data[2][ sub_pict->linesize[2]] =
+ sub_pict->data[2][1+ sub_pict->linesize[2]] = info->v1_codebook[v1_vector*entry_size+5];
+ }
+}
+
+//decodes the V4 vectors in mb into the 4x4 MB pointed to by sub_pict
+static void decode_v4_vector(CinepakEncContext *s, AVPicture *sub_pict, int *v4_vector, strip_info *info)
+{
+ int i, x, y, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
+
+ for(i = y = 0; y < 4; y += 2) {
+ for(x = 0; x < 4; x += 2, i++) {
+ sub_pict->data[0][x + y*sub_pict->linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size];
+ sub_pict->data[0][x+1 + y*sub_pict->linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+1];
+ sub_pict->data[0][x + (y+1)*sub_pict->linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+2];
+ sub_pict->data[0][x+1 + (y+1)*sub_pict->linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+3];
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24) {
+ sub_pict->data[1][(x>>1) + (y>>1)*sub_pict->linesize[1]] = info->v4_codebook[v4_vector[i]*entry_size+4];
+ sub_pict->data[2][(x>>1) + (y>>1)*sub_pict->linesize[2]] = info->v4_codebook[v4_vector[i]*entry_size+5];
+ }
+ }
+ }
+}
+
+static void copy_mb(CinepakEncContext *s, AVPicture *a, AVPicture *b)
+{
+ int y, p;
+
+ for(y = 0; y < MB_SIZE; y++) {
+ memcpy(a->data[0]+y*a->linesize[0], b->data[0]+y*b->linesize[0],
+ MB_SIZE);
+ }
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24) {
+ for(p = 1; p <= 2; p++) {
+ for(y = 0; y < MB_SIZE/2; y++) {
+ memcpy(a->data[p] + y*a->linesize[p],
+ b->data[p] + y*b->linesize[p],
+ MB_SIZE/2);
+ }
+ }
+ }
+}
+
+static int encode_mode(CinepakEncContext *s, int h, AVPicture *scratch_pict, AVPicture *last_pict, strip_info *info, unsigned char *buf)
+{
+ int x, y, z, flags, bits, temp_size, header_ofs, ret = 0, mb_count = s->w * h / MB_AREA;
+ int needs_extra_bit, should_write_temp;
+ unsigned char temp[64]; //32/2 = 16 V4 blocks at 4 B each -> 64 B
+ mb_info *mb;
+ AVPicture sub_scratch = {{0}}, sub_last = {{0}};
+
+ //encode codebooks
+////// MacOS vintage decoder compatibility dictates the presence of
+////// the codebook chunk even when the codebook is empty - pretty dumb...
+////// and also the certain order of the codebook chunks -- rl
+ if(info->v4_size || !s->skip_empty_cb)
+ ret += encode_codebook(s, info->v4_codebook, info->v4_size, 0x20, 0x24, buf + ret);
+
+ if(info->v1_size || !s->skip_empty_cb)
+ ret += encode_codebook(s, info->v1_codebook, info->v1_size, 0x22, 0x26, buf + ret);
+
+ //update scratch picture
+ for(z = y = 0; y < h; y += MB_SIZE) {
+ for(x = 0; x < s->w; x += MB_SIZE, z++) {
+ mb = &s->mb[z];
+
+ get_sub_picture(s, x, y, scratch_pict, &sub_scratch);
+
+ if(info->mode == MODE_MC && mb->best_encoding == ENC_SKIP) {
+ get_sub_picture(s, x, y, last_pict, &sub_last);
+ copy_mb(s, &sub_scratch, &sub_last);
+ } else if(info->mode == MODE_V1_ONLY || mb->best_encoding == ENC_V1)
+ decode_v1_vector(s, &sub_scratch, mb->v1_vector, info);
+ else
+ decode_v4_vector(s, &sub_scratch, mb->v4_vector, info);
+ }
+ }
+
+ switch(info->mode) {
+ case MODE_V1_ONLY:
+ //av_log(s->avctx, AV_LOG_INFO, "mb_count = %i\n", mb_count);
+ ret += write_chunk_header(buf + ret, 0x32, mb_count);
+
+ for(x = 0; x < mb_count; x++)
+ buf[ret++] = s->mb[x].v1_vector;
+
+ break;
+ case MODE_V1_V4:
+ //remember header position
+ header_ofs = ret;
+ ret += CHUNK_HEADER_SIZE;
+
+ for(x = 0; x < mb_count; x += 32) {
+ flags = 0;
+ for(y = x; y < FFMIN(x+32, mb_count); y++)
+ if(s->mb[y].best_encoding == ENC_V4)
+ flags |= 1 << (31 - y + x);
+
+ AV_WB32(&buf[ret], flags);
+ ret += 4;
+
+ for(y = x; y < FFMIN(x+32, mb_count); y++) {
+ mb = &s->mb[y];
+
+ if(mb->best_encoding == ENC_V1)
+ buf[ret++] = mb->v1_vector;
+ else
+ for(z = 0; z < 4; z++)
+ buf[ret++] = mb->v4_vector[z];
+ }
+ }
+
+ write_chunk_header(buf + header_ofs, 0x30, ret - header_ofs - CHUNK_HEADER_SIZE);
+
+ break;
+ case MODE_MC:
+ //remember header position
+ header_ofs = ret;
+ ret += CHUNK_HEADER_SIZE;
+ flags = bits = temp_size = 0;
+
+ for(x = 0; x < mb_count; x++) {
+ mb = &s->mb[x];
+ flags |= (mb->best_encoding != ENC_SKIP) << (31 - bits++);
+ needs_extra_bit = 0;
+ should_write_temp = 0;
+
+ if(mb->best_encoding != ENC_SKIP) {
+ if(bits < 32)
+ flags |= (mb->best_encoding == ENC_V4) << (31 - bits++);
+ else
+ needs_extra_bit = 1;
+ }
+
+ if(bits == 32) {
+ AV_WB32(&buf[ret], flags);
+ ret += 4;
+ flags = bits = 0;
+
+ if(mb->best_encoding == ENC_SKIP || needs_extra_bit) {
+ memcpy(&buf[ret], temp, temp_size);
+ ret += temp_size;
+ temp_size = 0;
+ } else
+ should_write_temp = 1;
+ }
+
+ if(needs_extra_bit) {
+ flags = (mb->best_encoding == ENC_V4) << 31;
+ bits = 1;
+ }
+
+ if(mb->best_encoding == ENC_V1)
+ temp[temp_size++] = mb->v1_vector;
+ else if(mb->best_encoding == ENC_V4)
+ for(z = 0; z < 4; z++)
+ temp[temp_size++] = mb->v4_vector[z];
+
+ if(should_write_temp) {
+ memcpy(&buf[ret], temp, temp_size);
+ ret += temp_size;
+ temp_size = 0;
+ }
+ }
+
+ if(bits > 0) {
+ AV_WB32(&buf[ret], flags);
+ ret += 4;
+ memcpy(&buf[ret], temp, temp_size);
+ ret += temp_size;
+ }
+
+ write_chunk_header(buf + header_ofs, 0x31, ret - header_ofs - CHUNK_HEADER_SIZE);
+
+ break;
+ }
+
+ return ret;
+}
+
+//computes distortion of 4x4 MB in b compared to a
+static int compute_mb_distortion(CinepakEncContext *s, AVPicture *a, AVPicture *b)
+{
+ int x, y, p, d, ret = 0;
+
+ for(y = 0; y < MB_SIZE; y++) {
+ for(x = 0; x < MB_SIZE; x++) {
+ d = a->data[0][x + y*a->linesize[0]] - b->data[0][x + y*b->linesize[0]];
+ ret += d*d;
+ }
+ }
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24) {
+ for(p = 1; p <= 2; p++) {
+ for(y = 0; y < MB_SIZE/2; y++) {
+ for(x = 0; x < MB_SIZE/2; x++) {
+ d = a->data[p][x + y*a->linesize[p]] - b->data[p][x + y*b->linesize[p]];
+ ret += d*d;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// return the possibly adjusted size of the codebook
+#define CERTAIN(x) ((x)!=ENC_UNCERTAIN)
+static int quantize(CinepakEncContext *s, int h, AVPicture *pict,
+ int v1mode, strip_info *info,
+ mb_encoding encoding)
+{
+ int x, y, i, j, k, x2, y2, x3, y3, plane, shift, mbn;
+ int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4;
+ int *codebook = v1mode ? info->v1_codebook : info->v4_codebook;
+ int size = v1mode ? info->v1_size : info->v4_size;
+ int64_t total_error = 0;
+ uint8_t vq_pict_buf[(MB_AREA*3)/2];
+ AVPicture sub_pict, vq_pict;
+
+ for(mbn = i = y = 0; y < h; y += MB_SIZE) {
+ for(x = 0; x < s->w; x += MB_SIZE, ++mbn) {
+ int *base;
+
+ if(CERTAIN(encoding)) {
+// use for the training only the blocks known to be to be encoded [sic:-]
+ if(s->mb[mbn].best_encoding != encoding) continue;
+ }
+
+ base = s->codebook_input + i*entry_size;
+ if(v1mode) {
+ //subsample
+ for(j = y2 = 0; y2 < entry_size; y2 += 2) {
+ for(x2 = 0; x2 < 4; x2 += 2, j++) {
+ plane = y2 < 4 ? 0 : 1 + (x2 >> 1);
+ shift = y2 < 4 ? 0 : 1;
+ x3 = shift ? 0 : x2;
+ y3 = shift ? 0 : y2;
+ base[j] = (pict->data[plane][((x+x3) >> shift) + ((y+y3) >> shift) * pict->linesize[plane]] +
+ pict->data[plane][((x+x3) >> shift) + 1 + ((y+y3) >> shift) * pict->linesize[plane]] +
+ pict->data[plane][((x+x3) >> shift) + (((y+y3) >> shift) + 1) * pict->linesize[plane]] +
+ pict->data[plane][((x+x3) >> shift) + 1 + (((y+y3) >> shift) + 1) * pict->linesize[plane]]) >> 2;
+ }
+ }
+ } else {
+ //copy
+ for(j = y2 = 0; y2 < MB_SIZE; y2 += 2) {
+ for(x2 = 0; x2 < MB_SIZE; x2 += 2) {
+ for(k = 0; k < entry_size; k++, j++) {
+ plane = k >= 4 ? k - 3 : 0;
+
+ if(k >= 4) {
+ x3 = (x+x2) >> 1;
+ y3 = (y+y2) >> 1;
+ } else {
+ x3 = x + x2 + (k & 1);
+ y3 = y + y2 + (k >> 1);
+ }
+
+ base[j] = pict->data[plane][x3 + y3*pict->linesize[plane]];
+ }
+ }
+ }
+ }
+ i += v1mode ? 1 : 4;
+ }
+ }
+// if(i < mbn*(v1mode ? 1 : 4)) {
+// av_log(s->avctx, AV_LOG_INFO, "reducing training set for %s from %i to %i (encoding %i)\n", v1mode?"v1":"v4", mbn*(v1mode ? 1 : 4), i, encoding);
+// }
+
+ if(i == 0) // empty training set, nothing to do
+ return 0;
+ if(i < size) {
+ //av_log(s->avctx, (CERTAIN(encoding) ? AV_LOG_ERROR : AV_LOG_INFO), "WOULD WASTE: %s cbsize %i bigger than training set size %i (encoding %i)\n", v1mode?"v1":"v4", size, i, encoding);
+ size = i;
+ }
+
+ avpriv_init_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx);
+ avpriv_do_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx);
+
+ //setup vq_pict, which contains a single MB
+ vq_pict.data[0] = vq_pict_buf;
+ vq_pict.linesize[0] = MB_SIZE;
+ vq_pict.data[1] = &vq_pict_buf[MB_AREA];
+ vq_pict.data[2] = vq_pict.data[1] + (MB_AREA >> 2);
+ vq_pict.linesize[1] = vq_pict.linesize[2] = MB_SIZE >> 1;
+
+ //copy indices
+ for(i = j = y = 0; y < h; y += MB_SIZE) {
+ for(x = 0; x < s->w; x += MB_SIZE, j++) {
+ mb_info *mb = &s->mb[j];
+// skip uninteresting blocks if we know their preferred encoding
+ if(CERTAIN(encoding) && mb->best_encoding != encoding)
+ continue;
+
+ //point sub_pict to current MB
+ get_sub_picture(s, x, y, pict, &sub_pict);
+
+ if(v1mode) {
+ mb->v1_vector = s->codebook_closest[i];
+
+ //fill in vq_pict with V1 data
+ decode_v1_vector(s, &vq_pict, mb->v1_vector, info);
+
+ mb->v1_error = compute_mb_distortion(s, &sub_pict, &vq_pict);
+ total_error += mb->v1_error;
+ } else {
+ for(k = 0; k < 4; k++)
+ mb->v4_vector[k] = s->codebook_closest[i+k];
+
+ //fill in vq_pict with V4 data
+ decode_v4_vector(s, &vq_pict, mb->v4_vector, info);
+
+ mb->v4_error = compute_mb_distortion(s, &sub_pict, &vq_pict);
+ total_error += mb->v4_error;
+ }
+ i += v1mode ? 1 : 4;
+ }
+ }
+// check that we did it right in the beginning of the function
+ av_assert0(i >= size); // training set is no smaller than the codebook
+
+ //av_log(s->avctx, AV_LOG_INFO, "isv1 %i size= %i i= %i error %lli\n", v1mode, size, i, (long long int)total_error);
+
+ return size;
+}
+
+static void calculate_skip_errors(CinepakEncContext *s, int h, AVPicture *last_pict, AVPicture *pict, strip_info *info)
+{
+ int x, y, i;
+ AVPicture sub_last, sub_pict;
+
+ for(i = y = 0; y < h; y += MB_SIZE) {
+ for(x = 0; x < s->w; x += MB_SIZE, i++) {
+ get_sub_picture(s, x, y, last_pict, &sub_last);
+ get_sub_picture(s, x, y, pict, &sub_pict);
+
+ s->mb[i].skip_error = compute_mb_distortion(s, &sub_last, &sub_pict);
+ }
+ }
+}
+
+static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe, unsigned char *buf, int strip_size)
+{
+// actually we are exclusively using intra strip coding (how much can we win
+// otherwise? how to choose which part of a codebook to update?),
+// keyframes are different only because we disallow ENC_SKIP on them -- rl
+// (besides, the logic here used to be inverted: )
+// buf[0] = keyframe ? 0x11: 0x10;
+ buf[0] = keyframe ? 0x10: 0x11;
+ AV_WB24(&buf[1], strip_size + STRIP_HEADER_SIZE);
+// AV_WB16(&buf[4], y); /* using absolute y values works -- rl */
+ AV_WB16(&buf[4], 0); /* using relative values works as well -- rl */
+ AV_WB16(&buf[6], 0);
+// AV_WB16(&buf[8], y+h); /* using absolute y values works -- rl */
+ AV_WB16(&buf[8], h); /* using relative values works as well -- rl */
+ AV_WB16(&buf[10], s->w);
+ //av_log(s->avctx, AV_LOG_INFO, "write_strip_header() %x keyframe=%d\n", buf[0], keyframe);
+}
+
+static int rd_strip(CinepakEncContext *s, int y, int h, int keyframe, AVPicture *last_pict, AVPicture *pict, AVPicture *scratch_pict, unsigned char *buf, int64_t *best_score
+#ifdef CINEPAK_REPORT_SERR
+, int64_t *best_serr
+#endif
+)
+{
+ int64_t score = 0;
+#ifdef CINEPAK_REPORT_SERR
+ int64_t serr;
+#endif
+ int best_size = 0;
+ strip_info info;
+// for codebook optimization:
+ int v1enough, v1_size, v4enough, v4_size;
+ int new_v1_size, new_v4_size;
+ int v1shrunk, v4shrunk;
+
+ if(!keyframe)
+ calculate_skip_errors(s, h, last_pict, pict, &info);
+
+ //try some powers of 4 for the size of the codebooks
+ //constraint the v4 codebook to be no bigger than v1 one,
+ //(and no less than v1_size/4)
+ //thus making v1 preferable and possibly losing small details? should be ok
+#define SMALLEST_CODEBOOK 1
+ for(v1enough = 0, v1_size = SMALLEST_CODEBOOK; v1_size <= CODEBOOK_MAX && !v1enough; v1_size <<= 2) {
+ for(v4enough = 0, v4_size = 0; v4_size <= v1_size && !v4enough; v4_size = v4_size ? v4_size << 2 : v1_size >= SMALLEST_CODEBOOK << 2 ? v1_size >> 2 : SMALLEST_CODEBOOK) {
+ //try all modes
+ for(CinepakMode mode = 0; mode < MODE_COUNT; mode++) {
+ //don't allow MODE_MC in intra frames
+ if(keyframe && mode == MODE_MC)
+ continue;
+
+ if(mode == MODE_V1_ONLY) {
+ info.v1_size = v1_size;
+// the size may shrink even before optimizations if the input is short:
+ info.v1_size = quantize(s, h, pict, 1, &info, ENC_UNCERTAIN);
+ if(info.v1_size < v1_size)
+// too few eligible blocks, no sense in trying bigger sizes
+ v1enough = 1;
+
+ info.v4_size = 0;
+ } else { // mode != MODE_V1_ONLY
+ // if v4 codebook is empty then only allow V1-only mode
+ if(!v4_size)
+ continue;
+
+ if(mode == MODE_V1_V4) {
+ info.v4_size = v4_size;
+ info.v4_size = quantize(s, h, pict, 0, &info, ENC_UNCERTAIN);
+ if(info.v4_size < v4_size)
+// too few eligible blocks, no sense in trying bigger sizes
+ v4enough = 1;
+ }
+ }
+
+ info.mode = mode;
+// choose the best encoding per block, based on current experience
+ score = calculate_mode_score(s, h, &info, 0,
+ &v1shrunk, &v4shrunk
+#ifdef CINEPAK_REPORT_SERR
+, &serr
+#endif
+);
+
+ if(mode != MODE_V1_ONLY){
+ int extra_iterations_limit = s->max_extra_cb_iterations;
+// recompute the codebooks, omitting the extra blocks
+// we assume we _may_ come here with more blocks to encode than before
+ info.v1_size = v1_size;
+ new_v1_size = quantize(s, h, pict, 1, &info, ENC_V1);
+ if(new_v1_size < info.v1_size){
+ //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v1 codebook to %i entries\n", mode, v1_size, v4_size, new_v1_size);
+ info.v1_size = new_v1_size;
+ }
+// we assume we _may_ come here with more blocks to encode than before
+ info.v4_size = v4_size;
+ new_v4_size = quantize(s, h, pict, 0, &info, ENC_V4);
+ if(new_v4_size < info.v4_size) {
+ //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v4 codebook to %i entries at first iteration\n", mode, v1_size, v4_size, new_v4_size);
+ info.v4_size = new_v4_size;
+ }
+// calculate the resulting score
+// (do not move blocks to codebook encodings now, as some blocks may have
+// got bigger errors despite a smaller training set - but we do not
+// ever grow the training sets back)
+ for(;;) {
+ score = calculate_mode_score(s, h, &info, 1,
+ &v1shrunk, &v4shrunk
+#ifdef CINEPAK_REPORT_SERR
+, &serr
+#endif
+);
+// do we have a reason to reiterate? if so, have we reached the limit?
+ if((!v1shrunk && !v4shrunk) || !extra_iterations_limit--) break;
+// recompute the codebooks, omitting the extra blocks
+ if(v1shrunk) {
+ info.v1_size = v1_size;
+ new_v1_size = quantize(s, h, pict, 1, &info, ENC_V1);
+ if(new_v1_size < info.v1_size){
+ //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v1 codebook to %i entries\n", mode, v1_size, v4_size, new_v1_size);
+ info.v1_size = new_v1_size;
+ }
+ }
+ if(v4shrunk) {
+ info.v4_size = v4_size;
+ new_v4_size = quantize(s, h, pict, 0, &info, ENC_V4);
+ if(new_v4_size < info.v4_size) {
+ //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v4 codebook to %i entries\n", mode, v1_size, v4_size, new_v4_size);
+ info.v4_size = new_v4_size;
+ }
+ }
+ }
+ }
+
+ //av_log(s->avctx, AV_LOG_INFO, "%3i %3i score = %lli\n", v1_size, v4_size, (long long int)score);
+
+ if(best_size == 0 || score < *best_score) {
+
+ *best_score = score;
+#ifdef CINEPAK_REPORT_SERR
+ *best_serr = serr;
+#endif
+ best_size = encode_mode(s, h, scratch_pict, last_pict, &info, s->strip_buf + STRIP_HEADER_SIZE);
+
+ //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: %18lli %i B", mode, info.v1_size, info.v4_size, (long long int)score, best_size);
+ //av_log(s->avctx, AV_LOG_INFO, "\n");
+#ifdef CINEPAK_REPORT_SERR
+ av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: %18lli %i B\n", mode, v1_size, v4_size, (long long int)serr, best_size);
+#endif
+
+#ifdef CINEPAKENC_DEBUG
+ //save MB encoding choices
+ memcpy(s->best_mb, s->mb, mb_count*sizeof(mb_info));
+#endif
+
+ //memcpy(strip_temp + STRIP_HEADER_SIZE, strip_temp, best_size);
+ write_strip_header(s, y, h, keyframe, s->strip_buf, best_size);
+
+ }
+ }
+ }
+ }
+
+#ifdef CINEPAKENC_DEBUG
+ //gather stats. this will only work properly of MAX_STRIPS == 1
+ if(best_info.mode == MODE_V1_ONLY) {
+ s->num_v1_mode++;
+ s->num_v1_encs += s->w*h/MB_AREA;
+ } else {
+ if(best_info.mode == MODE_V1_V4)
+ s->num_v4_mode++;
+ else
+ s->num_mc_mode++;
+
+ int x;
+ for(x = 0; x < s->w*h/MB_AREA; x++)
+ if(s->best_mb[x].best_encoding == ENC_V1)
+ s->num_v1_encs++;
+ else if(s->best_mb[x].best_encoding == ENC_V4)
+ s->num_v4_encs++;
+ else
+ s->num_skips++;
+ }
+#endif
+
+ best_size += STRIP_HEADER_SIZE;
+ memcpy(buf, s->strip_buf, best_size);
+
+ return best_size;
+}
+
+static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, int num_strips, int data_size, int isakeyframe)
+{
+ buf[0] = isakeyframe ? 0 : 1;
+ AV_WB24(&buf[1], data_size + CVID_HEADER_SIZE);
+ AV_WB16(&buf[4], s->w);
+ AV_WB16(&buf[6], s->h);
+ AV_WB16(&buf[8], num_strips);
+
+ return CVID_HEADER_SIZE;
+}
+
+static int rd_frame(CinepakEncContext *s, const AVFrame *frame, int isakeyframe, unsigned char *buf, int buf_size)
+{
+ int num_strips, strip, i, y, nexty, size, temp_size;
+ AVPicture last_pict, pict, scratch_pict;
+ int64_t best_score = 0, score, score_temp;
+#ifdef CINEPAK_REPORT_SERR
+ int64_t best_serr = 0, serr, serr_temp;
+#endif
+
+ int best_nstrips = -1, best_size = -1; // mark as uninitialzed
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24) {
+ int x;
+// build a copy of the given frame in the correct colorspace
+ for(y = 0; y < s->h; y += 2) {
+ for(x = 0; x < s->w; x += 2) {
+ uint8_t *ir[2]; int32_t r, g, b, rr, gg, bb;
+ ir[0] = ((AVPicture*)frame)->data[0] + x*3 + y*((AVPicture*)frame)->linesize[0];
+ ir[1] = ir[0] + ((AVPicture*)frame)->linesize[0];
+ get_sub_picture(s, x, y, (AVPicture*)s->input_frame, &scratch_pict);
+ r = g = b = 0;
+ for(i=0; i<4; ++i) {
+ int i1, i2;
+ i1 = (i&1); i2 = (i>=2);
+ rr = ir[i2][i1*3+0];
+ gg = ir[i2][i1*3+1];
+ bb = ir[i2][i1*3+2];
+ r += rr; g += gg; b += bb;
+// using fixed point arithmetic for portable repeatability, scaling by 2^23
+// "Y"
+// rr = 0.2857*rr + 0.5714*gg + 0.1429*bb;
+ rr = (2396625*rr + 4793251*gg + 1198732*bb) >> 23;
+ if( rr < 0) rr = 0;
+ else if (rr > 255) rr = 255;
+ scratch_pict.data[0][i1 + i2*scratch_pict.linesize[0]] = rr;
+ }
+// let us scale down as late as possible
+// r /= 4; g /= 4; b /= 4;
+// "U"
+// rr = -0.1429*r - 0.2857*g + 0.4286*b;
+ rr = (-299683*r - 599156*g + 898839*b) >> 23;
+ if( rr < -128) rr = -128;
+ else if (rr > 127) rr = 127;
+ scratch_pict.data[1][0] = rr + 128; // quantize needs unsigned
+// "V"
+// rr = 0.3571*r - 0.2857*g - 0.0714*b;
+ rr = (748893*r - 599156*g - 149737*b) >> 23;
+ if( rr < -128) rr = -128;
+ else if (rr > 127) rr = 127;
+ scratch_pict.data[2][0] = rr + 128; // quantize needs unsigned
+ }
+ }
+ }
+
+ //would be nice but quite certainly incompatible with vintage players:
+ // support encoding zero strips (meaning skip the whole frame)
+ for(num_strips = s->min_strips; num_strips <= s->max_strips && num_strips <= s->h / MB_SIZE; num_strips++) {
+ score = 0;
+ size = 0;
+#ifdef CINEPAK_REPORT_SERR
+ serr = 0;
+#endif
+
+ for(y = 0, strip = 1; y < s->h; strip++, y = nexty) {
+ int strip_height;
+
+ nexty = strip * s->h / num_strips; // <= s->h
+ //make nexty the next multiple of 4 if not already there
+ if(nexty & 3)
+ nexty += 4 - (nexty & 3);
+
+ strip_height = nexty - y;
+ if(strip_height <= 0) { // can this ever happen?
+ av_log(s->avctx, AV_LOG_INFO, "skipping zero height strip %i of %i\n", strip, num_strips);
+ continue;
+ }
+
+ if(s->pix_fmt == AV_PIX_FMT_RGB24)
+ get_sub_picture(s, 0, y, (AVPicture*)s->input_frame, &pict);
+ else
+ get_sub_picture(s, 0, y, (AVPicture*)frame, &pict);
+ get_sub_picture(s, 0, y, (AVPicture*)s->last_frame, &last_pict);
+ get_sub_picture(s, 0, y, (AVPicture*)s->scratch_frame, &scratch_pict);
+
+ if((temp_size = rd_strip(s, y, strip_height, isakeyframe, &last_pict, &pict, &scratch_pict, s->frame_buf + size + CVID_HEADER_SIZE, &score_temp
+#ifdef CINEPAK_REPORT_SERR
+, &serr_temp
+#endif
+)) < 0)
+ return temp_size;
+
+ score += score_temp;
+#ifdef CINEPAK_REPORT_SERR
+ serr += serr_temp;
+#endif
+ size += temp_size;
+ //av_log(s->avctx, AV_LOG_INFO, "strip %d, isakeyframe=%d", strip, isakeyframe);
+ //av_log(s->avctx, AV_LOG_INFO, "\n");
+ }
+
+ if(best_score == 0 || score < best_score) {
+ best_score = score;
+#ifdef CINEPAK_REPORT_SERR
+ best_serr = serr;
+#endif
+ best_size = size + write_cvid_header(s, s->frame_buf, num_strips, size, isakeyframe);
+ //av_log(s->avctx, AV_LOG_INFO, "best number of strips so far: %2i, %12lli, %i B\n", num_strips, (long long int)score, best_size);
+#ifdef CINEPAK_REPORT_SERR
+ av_log(s->avctx, AV_LOG_INFO, "best number of strips so far: %2i, %12lli, %i B\n", num_strips, (long long int)serr, best_size);
+#endif
+
+ FFSWAP(AVFrame *, s->best_frame, s->scratch_frame);
+ memcpy(buf, s->frame_buf, best_size);
+ best_nstrips = num_strips;
+ }
+// avoid trying too many strip numbers without a real reason
+// (this makes the processing of the very first frame faster)
+ if(num_strips - best_nstrips > 4)
+ break;
+ }
+
+ av_assert0(best_nstrips >= 0 && best_size >= 0);
+
+// let the number of strips slowly adapt to the changes in the contents,
+// compared to full bruteforcing every time this will occasionally lead
+// to some r/d performance loss but makes encoding up to several times faster
+ if(!s->strip_number_delta_range) {
+ if(best_nstrips == s->max_strips) { // let us try to step up
+ s->max_strips = best_nstrips + 1;
+ if(s->max_strips >= s->max_max_strips)
+ s->max_strips = s->max_max_strips;
+ } else { // try to step down
+ s->max_strips = best_nstrips;
+ }
+ s->min_strips = s->max_strips - 1;
+ if(s->min_strips < s->min_min_strips)
+ s->min_strips = s->min_min_strips;
+ } else {
+ s->max_strips = best_nstrips + s->strip_number_delta_range;
+ if(s->max_strips >= s->max_max_strips)
+ s->max_strips = s->max_max_strips;
+ s->min_strips = best_nstrips - s->strip_number_delta_range;
+ if(s->min_strips < s->min_min_strips)
+ s->min_strips = s->min_min_strips;
+ }
+
+ return best_size;
+}
+
+static int cinepak_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ CinepakEncContext *s = avctx->priv_data;
+ int ret;
+
+ s->lambda = frame->quality ? frame->quality - 1 : 2 * FF_LAMBDA_SCALE;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, s->frame_buf_size)) < 0)
+ return ret;
+ ret = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size);
+ pkt->size = ret;
+ if (s->curframe == 0)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ FFSWAP(AVFrame *, s->last_frame, s->best_frame);
+
+ if (++s->curframe >= s->keyint)
+ s->curframe = 0;
+
+ return 0;
+}
+
+static av_cold int cinepak_encode_end(AVCodecContext *avctx)
+{
+ CinepakEncContext *s = avctx->priv_data;
+ int x;
+
+ av_frame_free(&s->last_frame);
+ av_frame_free(&s->best_frame);
+ av_frame_free(&s->scratch_frame);
+ if (avctx->pix_fmt == AV_PIX_FMT_RGB24)
+ av_frame_free(&s->input_frame);
+ av_freep(&s->codebook_input);
+ av_freep(&s->codebook_closest);
+ av_freep(&s->strip_buf);
+ av_freep(&s->frame_buf);
+ av_freep(&s->mb);
+#ifdef CINEPAKENC_DEBUG
+ av_freep(&s->best_mb);
+#endif
+
+ for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++)
+ av_freep(&s->pict_bufs[x]);
+
+#ifdef CINEPAKENC_DEBUG
+ av_log(avctx, AV_LOG_INFO, "strip coding stats: %i V1 mode, %i V4 mode, %i MC mode (%i V1 encs, %i V4 encs, %i skips)\n",
+ s->num_v1_mode, s->num_v4_mode, s->num_mc_mode, s->num_v1_encs, s->num_v4_encs, s->num_skips);
+#endif
+
+ return 0;
+}
+
+AVCodec ff_cinepak_encoder = {
+ .name = "cinepak",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_CINEPAK,
+ .priv_data_size = sizeof(CinepakEncContext),
+ .init = cinepak_encode_init,
+ .encode2 = cinepak_encode_frame,
+ .close = cinepak_encode_end,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE},
+ .long_name = NULL_IF_CONFIG_SMALL("Cinepak / CVID"),
+ .priv_class = &cinepak_class,
+};
diff --git a/libavcodec/cljrdec.c b/libavcodec/cljrdec.c
index e74d1fafa4..68c877175b 100644
--- a/libavcodec/cljrdec.c
+++ b/libavcodec/cljrdec.c
@@ -2,20 +2,20 @@
* Cirrus Logic AccuPak (CLJR) decoder
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,16 +43,14 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
- if (buf_size < avctx->height * avctx->width) {
+ if (buf_size / avctx->height < avctx->width) {
av_log(avctx, AV_LOG_ERROR,
"Resolution larger than buffer size. Invalid header?\n");
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
@@ -63,10 +61,10 @@ static int decode_frame(AVCodecContext *avctx,
uint8_t *cb = &p->data[1][y * p->linesize[1]];
uint8_t *cr = &p->data[2][y * p->linesize[2]];
for (x = 0; x < avctx->width; x += 4) {
- luma[3] = get_bits(&gb, 5) << 3;
- luma[2] = get_bits(&gb, 5) << 3;
- luma[1] = get_bits(&gb, 5) << 3;
- luma[0] = get_bits(&gb, 5) << 3;
+ luma[3] = (get_bits(&gb, 5)*33) >> 2;
+ luma[2] = (get_bits(&gb, 5)*33) >> 2;
+ luma[1] = (get_bits(&gb, 5)*33) >> 2;
+ luma[0] = (get_bits(&gb, 5)*33) >> 2;
luma += 4;
*(cb++) = get_bits(&gb, 6) << 2;
*(cr++) = get_bits(&gb, 6) << 2;
@@ -93,3 +91,4 @@ AVCodec ff_cljr_decoder = {
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+
diff --git a/libavcodec/cljrenc.c b/libavcodec/cljrenc.c
index 2c315555e6..c672f800f6 100644
--- a/libavcodec/cljrenc.c
+++ b/libavcodec/cljrenc.c
@@ -2,20 +2,20 @@
* Cirrus Logic AccuPak (CLJR) encoder
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,39 +25,39 @@
*/
#include "libavutil/common.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "put_bits.h"
-static av_cold int encode_init(AVCodecContext *avctx)
-{
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- return 0;
-}
-
-static av_cold int encode_close(AVCodecContext *avctx)
-{
- av_frame_free(&avctx->coded_frame);
- return 0;
-}
+typedef struct CLJRContext {
+ AVClass *avclass;
+ int dither_type;
+} CLJRContext;
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *p, int *got_packet)
{
+ CLJRContext *a = avctx->priv_data;
PutBitContext pb;
int x, y, ret;
+ uint32_t dither= avctx->frame_number;
+ static const uint32_t ordered_dither[2][2] =
+ {
+ { 0x10400000, 0x104F0000 },
+ { 0xCB2A0000, 0xCB250000 },
+ };
- if ((ret = ff_alloc_packet(pkt, 32*avctx->height*avctx->width/4)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
- return ret;
+ if (avctx->width%4 && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Widths which are not a multiple of 4 might fail with some decoders, "
+ "use vstrict=-1 / -strict -1 to use %d anyway.\n", avctx->width);
+ return AVERROR_EXPERIMENTAL;
}
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
+ if ((ret = ff_alloc_packet2(avctx, pkt, 32*avctx->height*avctx->width/4)) < 0)
+ return ret;
init_put_bits(&pb, pkt->data, pkt->size);
@@ -65,14 +65,25 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
uint8_t *luma = &p->data[0][y * p->linesize[0]];
uint8_t *cb = &p->data[1][y * p->linesize[1]];
uint8_t *cr = &p->data[2][y * p->linesize[2]];
+ uint8_t luma_tmp[4];
for (x = 0; x < avctx->width; x += 4) {
- put_bits(&pb, 5, luma[3] >> 3);
- put_bits(&pb, 5, luma[2] >> 3);
- put_bits(&pb, 5, luma[1] >> 3);
- put_bits(&pb, 5, luma[0] >> 3);
+ switch (a->dither_type) {
+ case 0: dither = 0x492A0000; break;
+ case 1: dither = dither * 1664525 + 1013904223; break;
+ case 2: dither = ordered_dither[ y&1 ][ (x>>2)&1 ];break;
+ }
+ if (x+3 >= avctx->width) {
+ memset(luma_tmp, 0, sizeof(luma_tmp));
+ memcpy(luma_tmp, luma, avctx->width - x);
+ luma = luma_tmp;
+ }
+ put_bits(&pb, 5, (249*(luma[3] + (dither>>29) )) >> 11);
+ put_bits(&pb, 5, (249*(luma[2] + ((dither>>26)&7))) >> 11);
+ put_bits(&pb, 5, (249*(luma[1] + ((dither>>23)&7))) >> 11);
+ put_bits(&pb, 5, (249*(luma[0] + ((dither>>20)&7))) >> 11);
luma += 4;
- put_bits(&pb, 6, *(cb++) >> 2);
- put_bits(&pb, 6, *(cr++) >> 2);
+ put_bits(&pb, 6, (253*(*(cb++) + ((dither>>18)&3))) >> 10);
+ put_bits(&pb, 6, (253*(*(cr++) + ((dither>>16)&3))) >> 10);
}
}
@@ -84,14 +95,28 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
+#define OFFSET(x) offsetof(CLJRContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "dither_type", "Dither type", OFFSET(dither_type), AV_OPT_TYPE_INT, { .i64=1 }, 0, 2, VE},
+ { NULL },
+};
+
+static const AVClass cljr_class = {
+ .class_name = "cljr encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_cljr_encoder = {
.name = "cljr",
.long_name = NULL_IF_CONFIG_SMALL("Cirrus Logic AccuPak"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_CLJR,
- .init = encode_init,
+ .priv_data_size = sizeof(CLJRContext),
.encode2 = encode_frame,
- .close = encode_close,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P,
AV_PIX_FMT_NONE },
+ .priv_class = &cljr_class,
};
diff --git a/libavcodec/cllc.c b/libavcodec/cllc.c
index 578299fcae..c9ab8b9346 100644
--- a/libavcodec/cllc.c
+++ b/libavcodec/cllc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012-2013 Derek Buitenhuis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -398,7 +398,8 @@ static int cllc_decode_frame(AVCodecContext *avctx, void *data,
ctx->bdsp.bswap16_buf((uint16_t *) ctx->swapped_buf, (uint16_t *) src,
data_size / 2);
- init_get_bits(&gb, ctx->swapped_buf, data_size * 8);
+ if ((ret = init_get_bits8(&gb, ctx->swapped_buf, data_size)) < 0)
+ return ret;
/*
* Read in coding type. The types are as follows:
@@ -416,11 +417,8 @@ static int cllc_decode_frame(AVCodecContext *avctx, void *data,
avctx->pix_fmt = AV_PIX_FMT_YUV422P;
avctx->bits_per_raw_sample = 8;
- ret = ff_get_buffer(avctx, pic, 0);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
return ret;
- }
ret = decode_yuv_frame(ctx, &gb, pic);
if (ret < 0)
@@ -432,11 +430,8 @@ static int cllc_decode_frame(AVCodecContext *avctx, void *data,
avctx->pix_fmt = AV_PIX_FMT_RGB24;
avctx->bits_per_raw_sample = 8;
- ret = ff_get_buffer(avctx, pic, 0);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
return ret;
- }
ret = decode_rgb24_frame(ctx, &gb, pic);
if (ret < 0)
@@ -447,11 +442,8 @@ static int cllc_decode_frame(AVCodecContext *avctx, void *data,
avctx->pix_fmt = AV_PIX_FMT_ARGB;
avctx->bits_per_raw_sample = 8;
- ret = ff_get_buffer(avctx, pic, 0);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
return ret;
- }
ret = decode_argb_frame(ctx, &gb, pic);
if (ret < 0)
diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c
index 89f5c81f10..c49e903ce8 100644
--- a/libavcodec/cngdec.c
+++ b/libavcodec/cngdec.c
@@ -2,20 +2,20 @@
* RFC 3389 comfort noise generator
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,11 +41,11 @@ typedef struct CNGContext {
static av_cold int cng_decode_close(AVCodecContext *avctx)
{
CNGContext *p = avctx->priv_data;
- av_free(p->refl_coef);
- av_free(p->target_refl_coef);
- av_free(p->lpc_coef);
- av_free(p->filter_out);
- av_free(p->excitation);
+ av_freep(&p->refl_coef);
+ av_freep(&p->target_refl_coef);
+ av_freep(&p->lpc_coef);
+ av_freep(&p->filter_out);
+ av_freep(&p->excitation);
return 0;
}
@@ -59,12 +59,12 @@ static av_cold int cng_decode_init(AVCodecContext *avctx)
p->order = 12;
avctx->frame_size = 640;
- p->refl_coef = av_mallocz(p->order * sizeof(*p->refl_coef));
- p->target_refl_coef = av_mallocz(p->order * sizeof(*p->target_refl_coef));
- p->lpc_coef = av_mallocz(p->order * sizeof(*p->lpc_coef));
- p->filter_out = av_mallocz((avctx->frame_size + p->order) *
+ p->refl_coef = av_mallocz_array(p->order, sizeof(*p->refl_coef));
+ p->target_refl_coef = av_mallocz_array(p->order, sizeof(*p->target_refl_coef));
+ p->lpc_coef = av_mallocz_array(p->order, sizeof(*p->lpc_coef));
+ p->filter_out = av_mallocz_array(avctx->frame_size + p->order,
sizeof(*p->filter_out));
- p->excitation = av_mallocz(avctx->frame_size * sizeof(*p->excitation));
+ p->excitation = av_mallocz_array(avctx->frame_size, sizeof(*p->excitation));
if (!p->refl_coef || !p->target_refl_coef || !p->lpc_coef ||
!p->filter_out || !p->excitation) {
cng_decode_close(avctx);
@@ -142,10 +142,8 @@ static int cng_decode_frame(AVCodecContext *avctx, void *data,
p->excitation, avctx->frame_size, p->order);
frame->nb_samples = avctx->frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
buf_out = (int16_t *)frame->data[0];
for (i = 0; i < avctx->frame_size; i++)
buf_out[i] = p->filter_out[i + p->order];
diff --git a/libavcodec/cngenc.c b/libavcodec/cngenc.c
index 98f3c4e91a..58918aa958 100644
--- a/libavcodec/cngenc.c
+++ b/libavcodec/cngenc.c
@@ -2,20 +2,20 @@
* RFC 3389 comfort noise generator
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,8 +56,8 @@ static av_cold int cng_encode_init(AVCodecContext *avctx)
p->order = 10;
if ((ret = ff_lpc_init(&p->lpc, avctx->frame_size, p->order, FF_LPC_TYPE_LEVINSON)) < 0)
return ret;
- p->samples32 = av_malloc(avctx->frame_size * sizeof(*p->samples32));
- p->ref_coef = av_malloc(p->order * sizeof(*p->ref_coef));
+ p->samples32 = av_malloc_array(avctx->frame_size, sizeof(*p->samples32));
+ p->ref_coef = av_malloc_array(p->order, sizeof(*p->ref_coef));
if (!p->samples32 || !p->ref_coef) {
cng_encode_close(avctx);
return AVERROR(ENOMEM);
@@ -87,7 +87,7 @@ static int cng_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
energy /= frame->nb_samples;
if (energy > 0) {
double dbov = 10 * log10(energy / 1081109975);
- qdbov = av_clip(-floor(dbov), 0, 127);
+ qdbov = av_clip_uintp2(-floor(dbov), 7);
} else {
qdbov = 127;
}
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 4f2a63a56d..c1694f3383 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1,18 +1,21 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * This table was generated from the long and short names of AVCodecs
+ * please see the respective codec sources for authorship
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +26,8 @@
#include "avcodec.h"
#include "version.h"
+#define MT(...) (const char *const[]){ __VA_ARGS__, NULL }
+
static const AVCodecDescriptor codec_descriptors[] = {
/* video codecs */
{
@@ -82,6 +87,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "mjpeg",
.long_name = NULL_IF_CONFIG_SMALL("Motion JPEG"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ .mime_types= MT("image/jpeg"),
},
{
.id = AV_CODEC_ID_MJPEGB,
@@ -399,6 +405,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSLESS,
},
{
+ .id = AV_CODEC_ID_SNOW,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "snow",
+ .long_name = NULL_IF_CONFIG_SMALL("Snow"),
+ .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
+ },
+ {
.id = AV_CODEC_ID_TSCC,
.type = AVMEDIA_TYPE_VIDEO,
.name = "tscc",
@@ -516,6 +529,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "bmp",
.long_name = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-ms-bmp"),
},
{
.id = AV_CODEC_ID_CSCD,
@@ -587,6 +601,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/jp2"),
},
{
.id = AV_CODEC_ID_VMNC,
@@ -1013,7 +1028,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.type = AVMEDIA_TYPE_VIDEO,
.name = "cdxl",
.long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
- .props = AV_CODEC_PROP_LOSSY,
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_ZEROCODEC,
@@ -1072,6 +1087,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_Y41P,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "y41p",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
.id = AV_CODEC_ID_ESCAPE130,
.type = AVMEDIA_TYPE_VIDEO,
.name = "escape130",
@@ -1079,6 +1101,88 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_AVRP,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "avrp",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_012V,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "012v",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_AVUI,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "avui",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_AYUV,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "ayuv",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_TARGA_Y216,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "targa_y216",
+ .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_V308,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "v308",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_V408,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "v408",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_YUV4,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "yuv4",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_AVRN,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "avrn",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"),
+ },
+ {
+ .id = AV_CODEC_ID_CPIA,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "cpia",
+ .long_name = NULL_IF_CONFIG_SMALL("CPiA video format"),
+ },
+ {
+ .id = AV_CODEC_ID_XFACE,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "xface",
+ .long_name = NULL_IF_CONFIG_SMALL("X-face image"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_SMVJPEG,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "smv",
+ .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"),
+ },
+
+ {
.id = AV_CODEC_ID_G2M,
.type = AVMEDIA_TYPE_VIDEO,
.name = "g2m",
@@ -1096,7 +1200,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_HEVC,
.type = AVMEDIA_TYPE_VIDEO,
.name = "hevc",
- .long_name = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),
+ .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding)"),
.props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
},
{
@@ -1124,7 +1228,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_SANM,
.type = AVMEDIA_TYPE_VIDEO,
.name = "sanm",
- .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM video"),
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM/SMUSH video"),
.props = AV_CODEC_PROP_LOSSY,
},
{
@@ -1175,7 +1279,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_DPX,
.type = AVMEDIA_TYPE_VIDEO,
.name = "dpx",
- .long_name = NULL_IF_CONFIG_SMALL("DPX image"),
+ .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
},
{
@@ -1192,6 +1296,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "gif",
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
.props = AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/gif"),
},
{
.id = AV_CODEC_ID_JPEGLS,
@@ -1214,6 +1319,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "pam",
.long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-portable-pixmap"),
},
{
.id = AV_CODEC_ID_PBM,
@@ -1228,6 +1334,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "pcx",
.long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-pcx"),
},
{
.id = AV_CODEC_ID_PGM,
@@ -1249,6 +1356,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "png",
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
.props = AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/png"),
},
{
.id = AV_CODEC_ID_PPM,
@@ -1291,6 +1399,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "targa",
.long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-targa", "image/x-tga"),
},
{
.id = AV_CODEC_ID_TDSC,
@@ -1305,6 +1414,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "tiff",
.long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/tiff"),
},
{
.id = AV_CODEC_ID_TXD,
@@ -1327,6 +1437,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("WebP"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/webp"),
},
{
.id = AV_CODEC_ID_WMV3IMAGE,
@@ -1348,6 +1459,15 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "xwd",
.long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-xwindowdump"),
+ },
+ {
+ .id = AV_CODEC_ID_APNG,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "apng",
+ .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/png"),
},
/* various PCM "codecs" */
@@ -1397,13 +1517,15 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_PCM_MULAW,
.type = AVMEDIA_TYPE_AUDIO,
.name = "pcm_mulaw",
- .long_name = NULL_IF_CONFIG_SMALL("PCM mu-law"),
+ .long_name = NULL_IF_CONFIG_SMALL("PCM mu-law / G.711 mu-law"),
+ .props = AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_PCM_ALAW,
.type = AVMEDIA_TYPE_AUDIO,
.name = "pcm_alaw",
- .long_name = NULL_IF_CONFIG_SMALL("PCM A-law"),
+ .long_name = NULL_IF_CONFIG_SMALL("PCM A-law / G.711 A-law"),
+ .props = AV_CODEC_PROP_LOSSY,
},
{
.id = AV_CODEC_ID_PCM_S32LE,
@@ -1476,10 +1598,17 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_PCM_S16BE_PLANAR,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s16be_planar",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit big-endian planar"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
+ {
.id = AV_CODEC_ID_PCM_S16LE_PLANAR,
.type = AVMEDIA_TYPE_AUDIO,
.name = "pcm_s16le_planar",
- .long_name = NULL_IF_CONFIG_SMALL("PCM 16-bit little-endian planar"),
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit little-endian planar"),
.props = AV_CODEC_PROP_LOSSLESS,
},
{
@@ -1550,7 +1679,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.type = AVMEDIA_TYPE_AUDIO,
.name = "s302m",
.long_name = NULL_IF_CONFIG_SMALL("SMPTE 302M"),
- .props = AV_CODEC_PROP_LOSSY,
+ .props = AV_CODEC_PROP_LOSSLESS,
},
{
.id = AV_CODEC_ID_PCM_S8_PLANAR,
@@ -1772,6 +1901,41 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_ADPCM_AFC,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_afc",
+ .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube AFC"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_ADPCM_IMA_OKI,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_ima_oki",
+ .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Dialogic OKI"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_ADPCM_DTK,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_dtk",
+ .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube DTK"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_ADPCM_IMA_RAD,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_ima_rad",
+ .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Radical"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_ADPCM_G726LE,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_g726le",
+ .long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM little-endian"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
.id = AV_CODEC_ID_ADPCM_VIMA,
.type = AVMEDIA_TYPE_AUDIO,
.name = "adpcm_vima",
@@ -2279,6 +2443,24 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_LOSSY,
},
{
+ .id = AV_CODEC_ID_FFWAVESYNTH,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "wavesynth",
+ .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"),
+ },
+ {
+ .id = AV_CODEC_ID_SONIC,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "sonic",
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic"),
+ },
+ {
+ .id = AV_CODEC_ID_SONIC_LS,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "sonicls",
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"),
+ },
+ {
.id = AV_CODEC_ID_OPUS,
.type = AVMEDIA_TYPE_AUDIO,
.name = "opus",
@@ -2320,6 +2502,48 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("On2 Audio for Video Codec"),
.props = AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_EVRC,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "evrc",
+ .long_name = NULL_IF_CONFIG_SMALL("EVRC (Enhanced Variable Rate Codec)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_SMV,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "smv",
+ .long_name = NULL_IF_CONFIG_SMALL("SMV (Selectable Mode Vocoder)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_DSD_LSBF,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "dsd_lsbf",
+ .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), least significant bit first"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_DSD_MSBF,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "dsd_msbf",
+ .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), most significant bit first"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_DSD_LSBF_PLANAR,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "dsd_lsbf_planar",
+ .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), least significant bit first, planar"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_DSD_MSBF_PLANAR,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "dsd_msbf_planar",
+ .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), most significant bit first, planar"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
/* subtitle codecs */
{
@@ -2327,42 +2551,56 @@ static const AVCodecDescriptor codec_descriptors[] = {
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "dvd_subtitle",
.long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
+ .props = AV_CODEC_PROP_BITMAP_SUB,
},
{
.id = AV_CODEC_ID_DVB_SUBTITLE,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "dvb_subtitle",
.long_name = NULL_IF_CONFIG_SMALL("DVB subtitles"),
+ .props = AV_CODEC_PROP_BITMAP_SUB,
},
{
.id = AV_CODEC_ID_TEXT,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "text",
.long_name = NULL_IF_CONFIG_SMALL("raw UTF-8 text"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
},
{
.id = AV_CODEC_ID_XSUB,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "xsub",
.long_name = NULL_IF_CONFIG_SMALL("XSUB"),
+ .props = AV_CODEC_PROP_BITMAP_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_ASS,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "ass",
+ .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SSA) subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
},
{
.id = AV_CODEC_ID_SSA,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "ssa",
- .long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) / ASS (Advanced SSA) subtitle"),
+ .long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
},
{
.id = AV_CODEC_ID_MOV_TEXT,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "mov_text",
.long_name = NULL_IF_CONFIG_SMALL("MOV text"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
},
{
.id = AV_CODEC_ID_HDMV_PGS_SUBTITLE,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "hdmv_pgs_subtitle",
.long_name = NULL_IF_CONFIG_SMALL("HDMV Presentation Graphic Stream subtitles"),
+ .props = AV_CODEC_PROP_BITMAP_SUB,
},
{
.id = AV_CODEC_ID_DVB_TELETEXT,
@@ -2374,7 +2612,279 @@ static const AVCodecDescriptor codec_descriptors[] = {
.id = AV_CODEC_ID_SRT,
.type = AVMEDIA_TYPE_SUBTITLE,
.name = "srt",
- .long_name = NULL_IF_CONFIG_SMALL("SubRip Text"),
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_SUBRIP,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "subrip",
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_MICRODVD,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "microdvd",
+ .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_MPL2,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "mpl2",
+ .long_name = NULL_IF_CONFIG_SMALL("MPL2 subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_EIA_608,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "eia_608",
+ .long_name = NULL_IF_CONFIG_SMALL("EIA-608 closed captions"),
+ },
+ {
+ .id = AV_CODEC_ID_JACOSUB,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "jacosub",
+ .long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_PJS,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "pjs",
+ .long_name = NULL_IF_CONFIG_SMALL("PJS (Phoenix Japanimation Society) subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_SAMI,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "sami",
+ .long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_REALTEXT,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "realtext",
+ .long_name = NULL_IF_CONFIG_SMALL("RealText subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_STL,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "stl",
+ .long_name = NULL_IF_CONFIG_SMALL("Spruce subtitle format"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_SUBVIEWER1,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "subviewer1",
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer v1 subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_SUBVIEWER,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "subviewer",
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_VPLAYER,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "vplayer",
+ .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+ {
+ .id = AV_CODEC_ID_WEBVTT,
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .name = "webvtt",
+ .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
+ .props = AV_CODEC_PROP_TEXT_SUB,
+ },
+
+ /* other kind of codecs and pseudo-codecs */
+ {
+ .id = AV_CODEC_ID_TTF,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "ttf",
+ .long_name = NULL_IF_CONFIG_SMALL("TrueType font"),
+ .mime_types= MT("application/x-truetype-font", "application/x-font"),
+ },
+ {
+ .id = AV_CODEC_ID_BINTEXT,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "bintext",
+ .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_XBIN,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "xbin",
+ .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_IDF,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "idf",
+ .long_name = NULL_IF_CONFIG_SMALL("iCEDraw text"),
+ .props = AV_CODEC_PROP_INTRA_ONLY,
+ },
+ {
+ .id = AV_CODEC_ID_OTF,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "otf",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenType font"),
+ .mime_types= MT("application/vnd.ms-opentype"),
+ },
+ {
+ .id = AV_CODEC_ID_SMPTE_KLV,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "klv",
+ .long_name = NULL_IF_CONFIG_SMALL("SMPTE 336M Key-Length-Value (KLV) metadata"),
+ },
+ {
+ .id = AV_CODEC_ID_DVD_NAV,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "dvd_nav_packet",
+ .long_name = NULL_IF_CONFIG_SMALL("DVD Nav packet"),
+ },
+ {
+ .id = AV_CODEC_ID_TIMED_ID3,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "timed_id3",
+ .long_name = NULL_IF_CONFIG_SMALL("timed ID3 metadata"),
+ },
+ {
+ .id = AV_CODEC_ID_BIN_DATA,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "bin_data",
+ .long_name = NULL_IF_CONFIG_SMALL("binary data"),
+ .mime_types= MT("application/octet-stream"),
+ },
+
+ /* deprecated codec ids */
+ {
+ .id = AV_CODEC_ID_BRENDER_PIX_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "brender_pix_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image (deprecated id)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_ESCAPE130_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "escape130_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Escape 130 (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_EXR_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "exr_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image (deprecated id)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
+ AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_G2M_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "g2m_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Go2Meeting (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_HEVC_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "hevc_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding) (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PAF_VIDEO_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "paf_video_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_SANM_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "sanm_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM/SMUSH video (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_VP7_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "vp7_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("On2 VP7 (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_WEBP_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "webp_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("WebP (deprecated id)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
+ AV_CODEC_PROP_LOSSLESS,
+ },
+
+#if FF_API_VIMA_DECODER
+ {
+ .id = AV_CODEC_ID_VIMA,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "vima",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+#endif
+ {
+ .id = AV_CODEC_ID_ADPCM_VIMA_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_vima_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_OPUS_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "opus_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Opus (Opus Interactive Audio Codec) (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PAF_AUDIO_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "paf_audio_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Audio (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PCM_S24LE_PLANAR_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s24le_planar_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian planar (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_PCM_S32LE_PLANAR_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s32le_planar_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian planar (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_TAK_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "tak_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("TAK (Tom's lossless Audio Kompressor) (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
},
};
diff --git a/libavcodec/cook.c b/libavcodec/cook.c
index d122041f26..75b184a94f 100644
--- a/libavcodec/cook.c
+++ b/libavcodec/cook.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Sascha Sommer
* Copyright (c) 2005 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,6 +52,7 @@
#include "fft.h"
#include "internal.h"
#include "sinewin.h"
+#include "unary.h"
#include "cookdata.h"
@@ -219,7 +220,7 @@ static av_cold int init_cook_mlt(COOKContext *q)
int j, ret;
int mlt_size = q->samples_per_channel;
- if ((q->mlt_window = av_malloc(mlt_size * sizeof(*q->mlt_window))) == 0)
+ if ((q->mlt_window = av_malloc_array(mlt_size, sizeof(*q->mlt_window))) == 0)
return AVERROR(ENOMEM);
/* Initialize the MLT window: simple sine window. */
@@ -229,7 +230,7 @@ static av_cold int init_cook_mlt(COOKContext *q)
/* Initialize the MDCT. */
if ((ret = ff_mdct_init(&q->mdct_ctx, av_log2(mlt_size) + 1, 1, 1.0 / 32768.0))) {
- av_free(q->mlt_window);
+ av_freep(&q->mlt_window);
return ret;
}
av_log(q->avctx, AV_LOG_DEBUG, "MDCT initialized, order = %d.\n",
@@ -303,8 +304,8 @@ static av_cold int cook_decode_close(AVCodecContext *avctx)
av_log(avctx, AV_LOG_DEBUG, "Deallocating memory.\n");
/* Free allocated memory buffers. */
- av_free(q->mlt_window);
- av_free(q->decoded_bytes_buffer);
+ av_freep(&q->mlt_window);
+ av_freep(&q->decoded_bytes_buffer);
/* Free the transform. */
ff_mdct_end(&q->mdct_ctx);
@@ -332,11 +333,7 @@ static void decode_gain_info(GetBitContext *gb, int *gaininfo)
{
int i, n;
- while (get_bits1(gb)) {
- /* NOTHING */
- }
-
- n = get_bits_count(gb) - 1; // amount of elements*2 to update
+ n = get_unary(gb, 0, get_bits_left(gb)); // amount of elements*2 to update
i = 0;
while (n--) {
@@ -397,7 +394,7 @@ static int decode_envelope(COOKContext *q, COOKSubpacket *p,
* @param category pointer to the category array
* @param category_index pointer to the category_index array
*/
-static void categorize(COOKContext *q, COOKSubpacket *p, int *quant_index_table,
+static void categorize(COOKContext *q, COOKSubpacket *p, const int *quant_index_table,
int *category, int *category_index)
{
int exp_idx, bias, tmpbias1, tmpbias2, bits_left, num_bits, index, v, i, j;
@@ -421,7 +418,7 @@ static void categorize(COOKContext *q, COOKSubpacket *p, int *quant_index_table,
num_bits = 0;
index = 0;
for (j = p->total_subbands; j > 0; j--) {
- exp_idx = av_clip((i - quant_index_table[index] + bias) / 2, 0, 7);
+ exp_idx = av_clip_uintp2((i - quant_index_table[index] + bias) / 2, 3);
index++;
num_bits += expbits_tab[exp_idx];
}
@@ -432,7 +429,7 @@ static void categorize(COOKContext *q, COOKSubpacket *p, int *quant_index_table,
/* Calculate total number of bits. */
num_bits = 0;
for (i = 0; i < p->total_subbands; i++) {
- exp_idx = av_clip((bias - quant_index_table[i]) / 2, 0, 7);
+ exp_idx = av_clip_uintp2((bias - quant_index_table[i]) / 2, 3);
num_bits += expbits_tab[exp_idx];
exp_index1[i] = exp_idx;
exp_index2[i] = exp_idx;
@@ -630,13 +627,17 @@ static int mono_decode(COOKContext *q, COOKSubpacket *p, float *mlt_buffer)
int category_index[128] = { 0 };
int category[128] = { 0 };
int quant_index_table[102];
- int res;
+ int res, i;
if ((res = decode_envelope(q, p, quant_index_table)) < 0)
return res;
q->num_vectors = get_bits(&q->gb, p->log2_numvector_size);
categorize(q, p, quant_index_table, category, category_index);
expand_category(q, category, category_index);
+ for (i=0; i<p->total_subbands; i++) {
+ if (category[i] > 7)
+ return AVERROR_INVALIDDATA;
+ }
decode_vectors(q, p, category, quant_index_table, mlt_buffer);
return 0;
@@ -736,7 +737,7 @@ static void imlt_gain(COOKContext *q, float *inbuffer,
* @param q pointer to the COOKContext
* @param decouple_tab decoupling array
*/
-static void decouple_info(COOKContext *q, COOKSubpacket *p, int *decouple_tab)
+static int decouple_info(COOKContext *q, COOKSubpacket *p, int *decouple_tab)
{
int i;
int vlc = get_bits1(&q->gb);
@@ -745,7 +746,7 @@ static void decouple_info(COOKContext *q, COOKSubpacket *p, int *decouple_tab)
int length = end - start + 1;
if (start > end)
- return;
+ return 0;
if (vlc)
for (i = 0; i < length; i++)
@@ -753,11 +754,18 @@ static void decouple_info(COOKContext *q, COOKSubpacket *p, int *decouple_tab)
p->channel_coupling.table,
p->channel_coupling.bits, 2);
else
- for (i = 0; i < length; i++)
- decouple_tab[start + i] = get_bits(&q->gb, p->js_vlc_bits);
+ for (i = 0; i < length; i++) {
+ int v = get_bits(&q->gb, p->js_vlc_bits);
+ if (v == (1<<p->js_vlc_bits)-1) {
+ av_log(q->avctx, AV_LOG_ERROR, "decouple value too large\n");
+ return AVERROR_INVALIDDATA;
+ }
+ decouple_tab[start + i] = v;
+ }
+ return 0;
}
-/*
+/**
* function decouples a pair of signals from a single signal via multiplication.
*
* @param q pointer to the COOKContext
@@ -805,10 +813,10 @@ static int joint_decode(COOKContext *q, COOKSubpacket *p,
/* Make sure the buffers are zeroed out. */
memset(mlt_buffer_left, 0, 1024 * sizeof(*mlt_buffer_left));
memset(mlt_buffer_right, 0, 1024 * sizeof(*mlt_buffer_right));
- decouple_info(q, p, decouple_tab);
+ if ((res = decouple_info(q, p, decouple_tab)) < 0)
+ return res;
if ((res = mono_decode(q, p, decode_buffer)) < 0)
return res;
-
/* The two channels are stored interleaved in decode_buffer. */
for (i = 0; i < p->js_subband_start; i++) {
for (j = 0; j < SUBBAND_SIZE; j++) {
@@ -927,7 +935,7 @@ static int decode_subpacket(COOKContext *q, COOKSubpacket *p,
p->mono_previous_buffer1,
outbuffer ? outbuffer[p->ch_idx] : NULL);
- if (p->num_channels == 2)
+ if (p->num_channels == 2) {
if (p->joint_stereo)
mlt_compensate_output(q, q->decode_buffer_2, &p->gains1,
p->mono_previous_buffer2,
@@ -936,6 +944,7 @@ static int decode_subpacket(COOKContext *q, COOKSubpacket *p,
mlt_compensate_output(q, q->decode_buffer_2, &p->gains2,
p->mono_previous_buffer2,
outbuffer ? outbuffer[p->ch_idx + 1] : NULL);
+ }
return 0;
}
@@ -959,10 +968,8 @@ static int cook_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
if (q->discarded_packets >= 2) {
frame->nb_samples = q->samples_per_channel;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (float **)frame->extended_data;
}
@@ -1009,7 +1016,6 @@ static int cook_decode_frame(AVCodecContext *avctx, void *data,
return avctx->block_align;
}
-#ifdef DEBUG
static void dump_cook_context(COOKContext *q)
{
//int i=0;
@@ -1031,7 +1037,6 @@ static void dump_cook_context(COOKContext *q)
PRINT("numvector_size", q->subpacket[0].numvector_size);
PRINT("total_subbands", q->subpacket[0].total_subbands);
}
-#endif
/**
* Cook initialization
@@ -1046,7 +1051,7 @@ static av_cold int cook_decode_init(AVCodecContext *avctx)
int extradata_size = avctx->extradata_size;
int s = 0;
unsigned int channel_mask = 0;
- int samples_per_frame;
+ int samples_per_frame = 0;
int ret;
q->avctx = avctx;
@@ -1080,6 +1085,11 @@ static av_cold int cook_decode_init(AVCodecContext *avctx)
if (extradata_size >= 8) {
bytestream_get_be32(&edata_ptr); // Unknown unused
q->subpacket[s].js_subband_start = bytestream_get_be16(&edata_ptr);
+ if (q->subpacket[s].js_subband_start >= 51) {
+ av_log(avctx, AV_LOG_ERROR, "js_subband_start %d is too large\n", q->subpacket[s].js_subband_start);
+ return AVERROR_INVALIDDATA;
+ }
+
q->subpacket[s].js_vlc_bits = bytestream_get_be16(&edata_ptr);
extradata_size -= 8;
}
@@ -1187,15 +1197,24 @@ static av_cold int cook_decode_init(AVCodecContext *avctx)
avpriv_request_sample(avctx, "subbands > 50");
return AVERROR_PATCHWELCOME;
}
+ if (q->subpacket[s].subbands == 0) {
+ avpriv_request_sample(avctx, "subbands = 0");
+ return AVERROR_PATCHWELCOME;
+ }
q->subpacket[s].gains1.now = q->subpacket[s].gain_1;
q->subpacket[s].gains1.previous = q->subpacket[s].gain_2;
q->subpacket[s].gains2.now = q->subpacket[s].gain_3;
q->subpacket[s].gains2.previous = q->subpacket[s].gain_4;
+ if (q->num_subpackets + q->subpacket[s].num_channels > q->avctx->channels) {
+ av_log(avctx, AV_LOG_ERROR, "Too many subpackets %d for channels %d\n", q->num_subpackets, q->avctx->channels);
+ return AVERROR_INVALIDDATA;
+ }
+
q->num_subpackets++;
s++;
- if (s > MAX_SUBPACKETS) {
- avpriv_request_sample(avctx, "subpackets > %d", MAX_SUBPACKETS);
+ if (s > FFMIN(MAX_SUBPACKETS, avctx->block_align)) {
+ avpriv_request_sample(avctx, "subpackets > %d", FFMIN(MAX_SUBPACKETS, avctx->block_align));
return AVERROR_PATCHWELCOME;
}
}
@@ -1248,9 +1267,9 @@ static av_cold int cook_decode_init(AVCodecContext *avctx)
else
avctx->channel_layout = (avctx->channels == 2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
-#ifdef DEBUG
+
dump_cook_context(q);
-#endif
+
return 0;
}
diff --git a/libavcodec/cook_parser.c b/libavcodec/cook_parser.c
index f140e90461..6dbbfd8a53 100644
--- a/libavcodec/cook_parser.c
+++ b/libavcodec/cook_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,11 +40,12 @@ static int cook_parse(AVCodecParserContext *s1, AVCodecContext *avctx,
{
CookParseContext *s = s1->priv_data;
- if (s->duration)
- s1->duration = s->duration;
- else if (avctx->extradata && avctx->extradata_size >= 8 && avctx->channels)
+ if (!s->duration &&
+ avctx->extradata && avctx->extradata_size >= 8 && avctx->channels)
s->duration = AV_RB16(avctx->extradata + 4) / avctx->channels;
+ s1->duration = s->duration;
+
/* always return the full packet. this parser isn't doing any splitting or
combining, only setting packet duration */
*poutbuf = buf;
diff --git a/libavcodec/cookdata.h b/libavcodec/cookdata.h
index c4c26fae5f..7b9cba3c11 100644
--- a/libavcodec/cookdata.h
+++ b/libavcodec/cookdata.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Sascha Sommer
* Copyright (c) 2005 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/copy_block.h b/libavcodec/copy_block.h
index 10718ccfda..9ed451f294 100644
--- a/libavcodec/copy_block.h
+++ b/libavcodec/copy_block.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,17 @@
#include "libavutil/intreadwrite.h"
+static inline void copy_block2(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h)
+{
+ int i;
+ for(i=0; i<h; i++)
+ {
+ AV_COPY16U(dst, src);
+ dst+=dstStride;
+ src+=srcStride;
+ }
+}
+
static inline void copy_block4(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h)
{
int i;
diff --git a/libavcodec/cos_tablegen.c b/libavcodec/cos_tablegen.c
index 92b8295336..9af83f4d7d 100644
--- a/libavcodec/cos_tablegen.c
+++ b/libavcodec/cos_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,7 +61,7 @@ int main(int argc, char *argv[])
printf("#include \"libavcodec/%s\"\n", do_sin ? "rdft.h" : "fft.h");
for (i = 4; i <= BITS; i++) {
int m = 1 << i;
- double freq = 2*M_PI/m;
+ double freq = 2*3.14159265358979323846/m;
printf("%s(%i) = {\n ", do_sin ? "SINTABLE" : "COSTABLE", m);
for (j = 0; j < m/2 - 1; j++) {
int idx = j > m/4 ? m/2 - j : j;
diff --git a/libavcodec/cpia.c b/libavcodec/cpia.c
new file mode 100644
index 0000000000..9036cb37fc
--- /dev/null
+++ b/libavcodec/cpia.c
@@ -0,0 +1,233 @@
+/*
+ * CPiA video decoder.
+ * Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This decoder is based on the LGPL code available at
+ * https://v4l4j.googlecode.com/svn/v4l4j/trunk/libvideo/libv4lconvert/cpia1.c
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "get_bits.h"
+#include "internal.h"
+
+
+#define FRAME_HEADER_SIZE 64
+#define MAGIC_0 0x19 /**< First header byte */
+#define MAGIC_1 0x68 /**< Second header byte */
+#define SUBSAMPLE_420 0
+#define SUBSAMPLE_422 1
+#define YUVORDER_YUYV 0
+#define YUVORDER_UYVY 1
+#define NOT_COMPRESSED 0
+#define COMPRESSED 1
+#define NO_DECIMATION 0
+#define DECIMATION_ENAB 1
+#define EOL 0xfd /**< End Of Line marker */
+#define EOI 0xff /**< End Of Image marker */
+
+
+typedef struct {
+ AVFrame *frame;
+} CpiaContext;
+
+
+static int cpia_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame, AVPacket* avpkt)
+{
+ CpiaContext* const cpia = avctx->priv_data;
+ int i,j,ret;
+
+ uint8_t* const header = avpkt->data;
+ uint8_t* src;
+ int src_size;
+ uint16_t linelength;
+ uint8_t skip;
+
+ AVFrame *frame = cpia->frame;
+ uint8_t *y, *u, *v, *y_end, *u_end, *v_end;
+
+ // Check header
+ if ( avpkt->size < FRAME_HEADER_SIZE
+ || header[0] != MAGIC_0 || header[1] != MAGIC_1
+ || (header[17] != SUBSAMPLE_420 && header[17] != SUBSAMPLE_422)
+ || (header[18] != YUVORDER_YUYV && header[18] != YUVORDER_UYVY)
+ || (header[28] != NOT_COMPRESSED && header[28] != COMPRESSED)
+ || (header[29] != NO_DECIMATION && header[29] != DECIMATION_ENAB)
+ ) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid header!\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ // currently unsupported properties
+ if (header[17] == SUBSAMPLE_422) {
+ avpriv_report_missing_feature(avctx, "4:2:2 subsampling");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (header[18] == YUVORDER_UYVY) {
+ avpriv_report_missing_feature(avctx, "YUV byte order UYVY");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (header[29] == DECIMATION_ENAB) {
+ avpriv_report_missing_feature(avctx, "Decimation");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ src = header + FRAME_HEADER_SIZE;
+ src_size = avpkt->size - FRAME_HEADER_SIZE;
+
+ if (header[28] == NOT_COMPRESSED) {
+ frame->pict_type = AV_PICTURE_TYPE_I;
+ frame->key_frame = 1;
+ } else {
+ frame->pict_type = AV_PICTURE_TYPE_P;
+ frame->key_frame = 0;
+ }
+
+ // Get buffer filled with previous frame
+ if ((ret = ff_reget_buffer(avctx, frame)) < 0)
+ return ret;
+
+
+ for ( i = 0;
+ i < frame->height;
+ i++, src += linelength, src_size -= linelength
+ ) {
+ // Read line length, two byte little endian
+ linelength = AV_RL16(src);
+ src += 2;
+
+ if (src_size < linelength) {
+ av_frame_set_decode_error_flags(frame, FF_DECODE_ERROR_INVALID_BITSTREAM);
+ av_log(avctx, AV_LOG_WARNING, "Frame ended unexpectedly!\n");
+ break;
+ }
+ if (src[linelength - 1] != EOL) {
+ av_frame_set_decode_error_flags(frame, FF_DECODE_ERROR_INVALID_BITSTREAM);
+ av_log(avctx, AV_LOG_WARNING, "Wrong line length %d or line not terminated properly (found 0x%02x)!\n", linelength, src[linelength - 1]);
+ break;
+ }
+
+ /* Update the data pointers. Y data is on every line.
+ * U and V data on every second line
+ */
+ y = &frame->data[0][i * frame->linesize[0]];
+ u = &frame->data[1][(i >> 1) * frame->linesize[1]];
+ v = &frame->data[2][(i >> 1) * frame->linesize[2]];
+ y_end = y + frame->linesize[0] - 1;
+ u_end = u + frame->linesize[1] - 1;
+ v_end = v + frame->linesize[2] - 1;
+
+ if ((i & 1) && header[17] == SUBSAMPLE_420) {
+ /* We are on a odd line and 420 subsample is used.
+ * On this line only Y values are specified, one per pixel.
+ */
+ for (j = 0; j < linelength - 1; j++) {
+ if (y > y_end) {
+ av_frame_set_decode_error_flags(frame, FF_DECODE_ERROR_INVALID_BITSTREAM);
+ av_log(avctx, AV_LOG_WARNING, "Decoded data exceeded linesize!\n");
+ break;
+ }
+ if ((src[j] & 1) && header[28] == COMPRESSED) {
+ /* It seems that odd lines are always uncompressed, but
+ * we do it according to specification anyways.
+ */
+ skip = src[j] >> 1;
+ y += skip;
+ } else {
+ *(y++) = src[j];
+ }
+ }
+ } else if (header[17] == SUBSAMPLE_420) {
+ /* We are on an even line and 420 subsample is used.
+ * On this line each pair of pixels is described by four bytes.
+ */
+ for (j = 0; j < linelength - 4; ) {
+ if (y + 1 > y_end || u > u_end || v > v_end) {
+ av_frame_set_decode_error_flags(frame, FF_DECODE_ERROR_INVALID_BITSTREAM);
+ av_log(avctx, AV_LOG_WARNING, "Decoded data exceeded linesize!\n");
+ break;
+ }
+ if ((src[j] & 1) && header[28] == COMPRESSED) {
+ // Skip amount of pixels and move forward one byte
+ skip = src[j] >> 1;
+ y += skip;
+ u += skip >> 1;
+ v += skip >> 1;
+ j++;
+ } else {
+ // Set image data as specified and move forward 4 bytes
+ *(y++) = src[j];
+ *(u++) = src[j+1];
+ *(y++) = src[j+2];
+ *(v++) = src[j+3];
+ j += 4;
+ }
+ }
+ }
+ }
+
+ *got_frame = 1;
+ if ((ret = av_frame_ref(data, cpia->frame)) < 0)
+ return ret;
+
+ return avpkt->size;
+}
+
+static av_cold int cpia_decode_init(AVCodecContext *avctx)
+{
+ CpiaContext *s = avctx->priv_data;
+
+ // output pixel format
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
+ /* The default timebase set by the v4l2 demuxer leads to probing which is buggy.
+ * Set some reasonable time_base to skip this.
+ */
+ if (avctx->time_base.num == 1 && avctx->time_base.den == 1000000) {
+ avctx->time_base.num = 1;
+ avctx->time_base.den = 60;
+ }
+
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static av_cold int cpia_decode_end(AVCodecContext *avctx)
+{
+ CpiaContext *s = avctx->priv_data;
+
+ av_frame_free(&s->frame);
+
+ return 0;
+}
+
+AVCodec ff_cpia_decoder = {
+ .name = "cpia",
+ .long_name = NULL_IF_CONFIG_SMALL("CPiA video format"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_CPIA,
+ .priv_data_size = sizeof(CpiaContext),
+ .init = cpia_decode_init,
+ .close = cpia_decode_end,
+ .decode = cpia_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c
new file mode 100644
index 0000000000..001afa4ff4
--- /dev/null
+++ b/libavcodec/crystalhd.c
@@ -0,0 +1,1226 @@
+/*
+ * - CrystalHD decoder module -
+ *
+ * Copyright(C) 2010,2011 Philip Langdale <ffmpeg.philipl@overt.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * - Principles of Operation -
+ *
+ * The CrystalHD decoder operates at the bitstream level - which is an even
+ * higher level than the decoding hardware you typically see in modern GPUs.
+ * This means it has a very simple interface, in principle. You feed demuxed
+ * packets in one end and get decoded picture (fields/frames) out the other.
+ *
+ * Of course, nothing is ever that simple. Due, at the very least, to b-frame
+ * dependencies in the supported formats, the hardware has a delay between
+ * when a packet goes in, and when a picture comes out. Furthermore, this delay
+ * is not just a function of time, but also one of the dependency on additional
+ * frames being fed into the decoder to satisfy the b-frame dependencies.
+ *
+ * As such, a pipeline will build up that is roughly equivalent to the required
+ * DPB for the file being played. If that was all it took, things would still
+ * be simple - so, of course, it isn't.
+ *
+ * The hardware has a way of indicating that a picture is ready to be copied out,
+ * but this is unreliable - and sometimes the attempt will still fail so, based
+ * on testing, the code will wait until 3 pictures are ready before starting
+ * to copy out - and this has the effect of extending the pipeline.
+ *
+ * Finally, while it is tempting to say that once the decoder starts outputting
+ * frames, the software should never fail to return a frame from a decode(),
+ * this is a hard assertion to make, because the stream may switch between
+ * differently encoded content (number of b-frames, interlacing, etc) which
+ * might require a longer pipeline than before. If that happened, you could
+ * deadlock trying to retrieve a frame that can't be decoded without feeding
+ * in additional packets.
+ *
+ * As such, the code will return in the event that a picture cannot be copied
+ * out, leading to an increase in the length of the pipeline. This in turn,
+ * means we have to be sensitive to the time it takes to decode a picture;
+ * We do not want to give up just because the hardware needed a little more
+ * time to prepare the picture! For this reason, there are delays included
+ * in the decode() path that ensure that, under normal conditions, the hardware
+ * will only fail to return a frame if it really needs additional packets to
+ * complete the decoding.
+ *
+ * Finally, to be explicit, we do not want the pipeline to grow without bound
+ * for two reasons: 1) The hardware can only buffer a finite number of packets,
+ * and 2) The client application may not be able to cope with arbitrarily long
+ * delays in the video path relative to the audio path. For example. MPlayer
+ * can only handle a 20 picture delay (although this is arbitrary, and needs
+ * to be extended to fully support the CrystalHD where the delay could be up
+ * to 32 pictures - consider PAFF H.264 content with 16 b-frames).
+ */
+
+/*****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#define _XOPEN_SOURCE 600
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libcrystalhd/bc_dts_types.h>
+#include <libcrystalhd/bc_dts_defs.h>
+#include <libcrystalhd/libcrystalhd_if.h>
+
+#include "avcodec.h"
+#include "h264.h"
+#include "internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/** Timeout parameter passed to DtsProcOutput() in us */
+#define OUTPUT_PROC_TIMEOUT 50
+/** Step between fake timestamps passed to hardware in units of 100ns */
+#define TIMESTAMP_UNIT 100000
+/** Initial value in us of the wait in decode() */
+#define BASE_WAIT 10000
+/** Increment in us to adjust wait in decode() */
+#define WAIT_UNIT 1000
+
+
+/*****************************************************************************
+ * Module private data
+ ****************************************************************************/
+
+typedef enum {
+ RET_ERROR = -1,
+ RET_OK = 0,
+ RET_COPY_AGAIN = 1,
+ RET_SKIP_NEXT_COPY = 2,
+ RET_COPY_NEXT_FIELD = 3,
+} CopyRet;
+
+typedef struct OpaqueList {
+ struct OpaqueList *next;
+ uint64_t fake_timestamp;
+ uint64_t reordered_opaque;
+ uint8_t pic_type;
+} OpaqueList;
+
+typedef struct {
+ AVClass *av_class;
+ AVCodecContext *avctx;
+ AVFrame *pic;
+ HANDLE dev;
+
+ uint8_t *orig_extradata;
+ uint32_t orig_extradata_size;
+
+ AVBitStreamFilterContext *bsfc;
+ AVCodecParserContext *parser;
+
+ uint8_t is_70012;
+ uint8_t *sps_pps_buf;
+ uint32_t sps_pps_size;
+ uint8_t is_nal;
+ uint8_t output_ready;
+ uint8_t need_second_field;
+ uint8_t skip_next_output;
+ uint64_t decode_wait;
+
+ uint64_t last_picture;
+
+ OpaqueList *head;
+ OpaqueList *tail;
+
+ /* Options */
+ uint32_t sWidth;
+ uint8_t bframe_bug;
+} CHDContext;
+
+static const AVOption options[] = {
+ { "crystalhd_downscale_width",
+ "Turn on downscaling to the specified width",
+ offsetof(CHDContext, sWidth),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT32_MAX,
+ AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM, },
+ { NULL, },
+};
+
+
+/*****************************************************************************
+ * Helper functions
+ ****************************************************************************/
+
+static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
+{
+ switch (id) {
+ case AV_CODEC_ID_MPEG4:
+ return BC_MSUBTYPE_DIVX;
+ case AV_CODEC_ID_MSMPEG4V3:
+ return BC_MSUBTYPE_DIVX311;
+ case AV_CODEC_ID_MPEG2VIDEO:
+ return BC_MSUBTYPE_MPEG2VIDEO;
+ case AV_CODEC_ID_VC1:
+ return BC_MSUBTYPE_VC1;
+ case AV_CODEC_ID_WMV3:
+ return BC_MSUBTYPE_WMV3;
+ case AV_CODEC_ID_H264:
+ return priv->is_nal ? BC_MSUBTYPE_AVC1 : BC_MSUBTYPE_H264;
+ default:
+ return BC_MSUBTYPE_INVALID;
+ }
+}
+
+static inline void print_frame_info(CHDContext *priv, BC_DTS_PROC_OUT *output)
+{
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tYBuffSz: %u\n", output->YbuffSz);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tYBuffDoneSz: %u\n",
+ output->YBuffDoneSz);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tUVBuffDoneSz: %u\n",
+ output->UVBuffDoneSz);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tTimestamp: %"PRIu64"\n",
+ output->PicInfo.timeStamp);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tPicture Number: %u\n",
+ output->PicInfo.picture_number);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tWidth: %u\n",
+ output->PicInfo.width);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tHeight: %u\n",
+ output->PicInfo.height);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tChroma: 0x%03x\n",
+ output->PicInfo.chroma_format);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tPulldown: %u\n",
+ output->PicInfo.pulldown);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tFlags: 0x%08x\n",
+ output->PicInfo.flags);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tFrame Rate/Res: %u\n",
+ output->PicInfo.frame_rate);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tAspect Ratio: %u\n",
+ output->PicInfo.aspect_ratio);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tColor Primaries: %u\n",
+ output->PicInfo.colour_primaries);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tMetaData: %u\n",
+ output->PicInfo.picture_meta_payload);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tSession Number: %u\n",
+ output->PicInfo.sess_num);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tycom: %u\n",
+ output->PicInfo.ycom);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tCustom Aspect: %u\n",
+ output->PicInfo.custom_aspect_ratio_width_height);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tFrames to Drop: %u\n",
+ output->PicInfo.n_drop);
+ av_log(priv->avctx, AV_LOG_VERBOSE, "\tH264 Valid Fields: 0x%08x\n",
+ output->PicInfo.other.h264.valid);
+}
+
+
+/*****************************************************************************
+ * OpaqueList functions
+ ****************************************************************************/
+
+static uint64_t opaque_list_push(CHDContext *priv, uint64_t reordered_opaque,
+ uint8_t pic_type)
+{
+ OpaqueList *newNode = av_mallocz(sizeof (OpaqueList));
+ if (!newNode) {
+ av_log(priv->avctx, AV_LOG_ERROR,
+ "Unable to allocate new node in OpaqueList.\n");
+ return 0;
+ }
+ if (!priv->head) {
+ newNode->fake_timestamp = TIMESTAMP_UNIT;
+ priv->head = newNode;
+ } else {
+ newNode->fake_timestamp = priv->tail->fake_timestamp + TIMESTAMP_UNIT;
+ priv->tail->next = newNode;
+ }
+ priv->tail = newNode;
+ newNode->reordered_opaque = reordered_opaque;
+ newNode->pic_type = pic_type;
+
+ return newNode->fake_timestamp;
+}
+
+/*
+ * The OpaqueList is built in decode order, while elements will be removed
+ * in presentation order. If frames are reordered, this means we must be
+ * able to remove elements that are not the first element.
+ *
+ * Returned node must be freed by caller.
+ */
+static OpaqueList *opaque_list_pop(CHDContext *priv, uint64_t fake_timestamp)
+{
+ OpaqueList *node = priv->head;
+
+ if (!priv->head) {
+ av_log(priv->avctx, AV_LOG_ERROR,
+ "CrystalHD: Attempted to query non-existent timestamps.\n");
+ return NULL;
+ }
+
+ /*
+ * The first element is special-cased because we have to manipulate
+ * the head pointer rather than the previous element in the list.
+ */
+ if (priv->head->fake_timestamp == fake_timestamp) {
+ priv->head = node->next;
+
+ if (!priv->head->next)
+ priv->tail = priv->head;
+
+ node->next = NULL;
+ return node;
+ }
+
+ /*
+ * The list is processed at arm's length so that we have the
+ * previous element available to rewrite its next pointer.
+ */
+ while (node->next) {
+ OpaqueList *current = node->next;
+ if (current->fake_timestamp == fake_timestamp) {
+ node->next = current->next;
+
+ if (!node->next)
+ priv->tail = node;
+
+ current->next = NULL;
+ return current;
+ } else {
+ node = current;
+ }
+ }
+
+ av_log(priv->avctx, AV_LOG_VERBOSE,
+ "CrystalHD: Couldn't match fake_timestamp.\n");
+ return NULL;
+}
+
+
+/*****************************************************************************
+ * Video decoder API function definitions
+ ****************************************************************************/
+
+static void flush(AVCodecContext *avctx)
+{
+ CHDContext *priv = avctx->priv_data;
+
+ avctx->has_b_frames = 0;
+ priv->last_picture = -1;
+ priv->output_ready = 0;
+ priv->need_second_field = 0;
+ priv->skip_next_output = 0;
+ priv->decode_wait = BASE_WAIT;
+
+ av_frame_unref (priv->pic);
+
+ /* Flush mode 4 flushes all software and hardware buffers. */
+ DtsFlushInput(priv->dev, 4);
+}
+
+
+static av_cold int uninit(AVCodecContext *avctx)
+{
+ CHDContext *priv = avctx->priv_data;
+ HANDLE device;
+
+ device = priv->dev;
+ DtsStopDecoder(device);
+ DtsCloseDecoder(device);
+ DtsDeviceClose(device);
+
+ /*
+ * Restore original extradata, so that if the decoder is
+ * reinitialised, the bitstream detection and filtering
+ * will work as expected.
+ */
+ if (priv->orig_extradata) {
+ av_free(avctx->extradata);
+ avctx->extradata = priv->orig_extradata;
+ avctx->extradata_size = priv->orig_extradata_size;
+ priv->orig_extradata = NULL;
+ priv->orig_extradata_size = 0;
+ }
+
+ av_parser_close(priv->parser);
+ if (priv->bsfc) {
+ av_bitstream_filter_close(priv->bsfc);
+ }
+
+ av_freep(&priv->sps_pps_buf);
+
+ av_frame_free (&priv->pic);
+
+ if (priv->head) {
+ OpaqueList *node = priv->head;
+ while (node) {
+ OpaqueList *next = node->next;
+ av_free(node);
+ node = next;
+ }
+ }
+
+ return 0;
+}
+
+
+static av_cold int init(AVCodecContext *avctx)
+{
+ CHDContext* priv;
+ BC_STATUS ret;
+ BC_INFO_CRYSTAL version;
+ BC_INPUT_FORMAT format = {
+ .FGTEnable = FALSE,
+ .Progressive = TRUE,
+ .OptFlags = 0x80000000 | vdecFrameRate59_94 | 0x40,
+ .width = avctx->width,
+ .height = avctx->height,
+ };
+
+ BC_MEDIA_SUBTYPE subtype;
+
+ uint32_t mode = DTS_PLAYBACK_MODE |
+ DTS_LOAD_FILE_PLAY_FW |
+ DTS_SKIP_TX_CHK_CPB |
+ DTS_PLAYBACK_DROP_RPT_MODE |
+ DTS_SINGLE_THREADED_MODE |
+ DTS_DFLT_RESOLUTION(vdecRESOLUTION_1080p23_976);
+
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD Init for %s\n",
+ avctx->codec->name);
+
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+
+ /* Initialize the library */
+ priv = avctx->priv_data;
+ priv->avctx = avctx;
+ priv->is_nal = avctx->extradata_size > 0 && *(avctx->extradata) == 1;
+ priv->last_picture = -1;
+ priv->decode_wait = BASE_WAIT;
+ priv->pic = av_frame_alloc();
+
+ subtype = id2subtype(priv, avctx->codec->id);
+ switch (subtype) {
+ case BC_MSUBTYPE_AVC1:
+ {
+ uint8_t *dummy_p;
+ int dummy_int;
+
+ /* Back up the extradata so it can be restored at close time. */
+ priv->orig_extradata = av_malloc(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!priv->orig_extradata) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to allocate copy of extradata\n");
+ return AVERROR(ENOMEM);
+ }
+ priv->orig_extradata_size = avctx->extradata_size;
+ memcpy(priv->orig_extradata, avctx->extradata, avctx->extradata_size);
+
+ priv->bsfc = av_bitstream_filter_init("h264_mp4toannexb");
+ if (!priv->bsfc) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Cannot open the h264_mp4toannexb BSF!\n");
+ return AVERROR_BSF_NOT_FOUND;
+ }
+ av_bitstream_filter_filter(priv->bsfc, avctx, NULL, &dummy_p,
+ &dummy_int, NULL, 0, 0);
+ }
+ subtype = BC_MSUBTYPE_H264;
+ // Fall-through
+ case BC_MSUBTYPE_H264:
+ format.startCodeSz = 4;
+ // Fall-through
+ case BC_MSUBTYPE_VC1:
+ case BC_MSUBTYPE_WVC1:
+ case BC_MSUBTYPE_WMV3:
+ case BC_MSUBTYPE_WMVA:
+ case BC_MSUBTYPE_MPEG2VIDEO:
+ case BC_MSUBTYPE_DIVX:
+ case BC_MSUBTYPE_DIVX311:
+ format.pMetaData = avctx->extradata;
+ format.metaDataSz = avctx->extradata_size;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: Unknown codec name\n");
+ return AVERROR(EINVAL);
+ }
+ format.mSubtype = subtype;
+
+ if (priv->sWidth) {
+ format.bEnableScaling = 1;
+ format.ScalingParams.sWidth = priv->sWidth;
+ }
+
+ /* Get a decoder instance */
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: starting up\n");
+ // Initialize the Link and Decoder devices
+ ret = DtsDeviceOpen(&priv->dev, mode);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: DtsDeviceOpen failed\n");
+ goto fail;
+ }
+
+ ret = DtsCrystalHDVersion(priv->dev, &version);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: DtsCrystalHDVersion failed\n");
+ goto fail;
+ }
+ priv->is_70012 = version.device == 0;
+
+ if (priv->is_70012 &&
+ (subtype == BC_MSUBTYPE_DIVX || subtype == BC_MSUBTYPE_DIVX311)) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: BCM70012 doesn't support MPEG4-ASP/DivX/Xvid\n");
+ goto fail;
+ }
+
+ ret = DtsSetInputFormat(priv->dev, &format);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: SetInputFormat failed\n");
+ goto fail;
+ }
+
+ ret = DtsOpenDecoder(priv->dev, BC_STREAM_TYPE_ES);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsOpenDecoder failed\n");
+ goto fail;
+ }
+
+ ret = DtsSetColorSpace(priv->dev, OUTPUT_MODE422_YUY2);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsSetColorSpace failed\n");
+ goto fail;
+ }
+ ret = DtsStartDecoder(priv->dev);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartDecoder failed\n");
+ goto fail;
+ }
+ ret = DtsStartCapture(priv->dev);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: DtsStartCapture failed\n");
+ goto fail;
+ }
+
+ if (avctx->codec->id == AV_CODEC_ID_H264) {
+ priv->parser = av_parser_init(avctx->codec->id);
+ if (!priv->parser)
+ av_log(avctx, AV_LOG_WARNING,
+ "Cannot open the h.264 parser! Interlaced h.264 content "
+ "will not be detected reliably.\n");
+ priv->parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
+ }
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Init complete.\n");
+
+ return 0;
+
+ fail:
+ uninit(avctx);
+ return -1;
+}
+
+
+static inline CopyRet copy_frame(AVCodecContext *avctx,
+ BC_DTS_PROC_OUT *output,
+ void *data, int *got_frame)
+{
+ BC_STATUS ret;
+ BC_DTS_STATUS decoder_status = { 0, };
+ uint8_t trust_interlaced;
+ uint8_t interlaced;
+
+ CHDContext *priv = avctx->priv_data;
+ int64_t pkt_pts = AV_NOPTS_VALUE;
+ uint8_t pic_type = 0;
+
+ uint8_t bottom_field = (output->PicInfo.flags & VDEC_FLAG_BOTTOMFIELD) ==
+ VDEC_FLAG_BOTTOMFIELD;
+ uint8_t bottom_first = !!(output->PicInfo.flags & VDEC_FLAG_BOTTOM_FIRST);
+
+ int width = output->PicInfo.width;
+ int height = output->PicInfo.height;
+ int bwidth;
+ uint8_t *src = output->Ybuff;
+ int sStride;
+ uint8_t *dst;
+ int dStride;
+
+ if (output->PicInfo.timeStamp != 0) {
+ OpaqueList *node = opaque_list_pop(priv, output->PicInfo.timeStamp);
+ if (node) {
+ pkt_pts = node->reordered_opaque;
+ pic_type = node->pic_type;
+ av_free(node);
+ } else {
+ /*
+ * We will encounter a situation where a timestamp cannot be
+ * popped if a second field is being returned. In this case,
+ * each field has the same timestamp and the first one will
+ * cause it to be popped. To keep subsequent calculations
+ * simple, pic_type should be set a FIELD value - doesn't
+ * matter which, but I chose BOTTOM.
+ */
+ pic_type = PICT_BOTTOM_FIELD;
+ }
+ av_log(avctx, AV_LOG_VERBOSE, "output \"pts\": %"PRIu64"\n",
+ output->PicInfo.timeStamp);
+ av_log(avctx, AV_LOG_VERBOSE, "output picture type %d\n",
+ pic_type);
+ }
+
+ ret = DtsGetDriverStatus(priv->dev, &decoder_status);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR,
+ "CrystalHD: GetDriverStatus failed: %u\n", ret);
+ return RET_ERROR;
+ }
+
+ /*
+ * For most content, we can trust the interlaced flag returned
+ * by the hardware, but sometimes we can't. These are the
+ * conditions under which we can trust the flag:
+ *
+ * 1) It's not h.264 content
+ * 2) The UNKNOWN_SRC flag is not set
+ * 3) We know we're expecting a second field
+ * 4) The hardware reports this picture and the next picture
+ * have the same picture number.
+ *
+ * Note that there can still be interlaced content that will
+ * fail this check, if the hardware hasn't decoded the next
+ * picture or if there is a corruption in the stream. (In either
+ * case a 0 will be returned for the next picture number)
+ */
+ trust_interlaced = avctx->codec->id != AV_CODEC_ID_H264 ||
+ !(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) ||
+ priv->need_second_field ||
+ (decoder_status.picNumFlags & ~0x40000000) ==
+ output->PicInfo.picture_number;
+
+ /*
+ * If we got a false negative for trust_interlaced on the first field,
+ * we will realise our mistake here when we see that the picture number is that
+ * of the previous picture. We cannot recover the frame and should discard the
+ * second field to keep the correct number of output frames.
+ */
+ if (output->PicInfo.picture_number == priv->last_picture && !priv->need_second_field) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Incorrectly guessed progressive frame. Discarding second field\n");
+ /* Returning without providing a picture. */
+ return RET_OK;
+ }
+
+ interlaced = (output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
+ trust_interlaced;
+
+ if (!trust_interlaced && (decoder_status.picNumFlags & ~0x40000000) == 0) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "Next picture number unknown. Assuming progressive frame.\n");
+ }
+
+ av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d | trust_interlaced %d\n",
+ interlaced, trust_interlaced);
+
+ if (priv->pic->data[0] && !priv->need_second_field)
+ av_frame_unref(priv->pic);
+
+ priv->need_second_field = interlaced && !priv->need_second_field;
+
+ if (!priv->pic->data[0]) {
+ if (ff_get_buffer(avctx, priv->pic, AV_GET_BUFFER_FLAG_REF) < 0)
+ return RET_ERROR;
+ }
+
+ bwidth = av_image_get_linesize(avctx->pix_fmt, width, 0);
+ if (priv->is_70012) {
+ int pStride;
+
+ if (width <= 720)
+ pStride = 720;
+ else if (width <= 1280)
+ pStride = 1280;
+ else pStride = 1920;
+ sStride = av_image_get_linesize(avctx->pix_fmt, pStride, 0);
+ } else {
+ sStride = bwidth;
+ }
+
+ dStride = priv->pic->linesize[0];
+ dst = priv->pic->data[0];
+
+ av_log(priv->avctx, AV_LOG_VERBOSE, "CrystalHD: Copying out frame\n");
+
+ if (interlaced) {
+ int dY = 0;
+ int sY = 0;
+
+ height /= 2;
+ if (bottom_field) {
+ av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: bottom field\n");
+ dY = 1;
+ } else {
+ av_log(priv->avctx, AV_LOG_VERBOSE, "Interlaced: top field\n");
+ dY = 0;
+ }
+
+ for (sY = 0; sY < height; dY++, sY++) {
+ memcpy(&(dst[dY * dStride]), &(src[sY * sStride]), bwidth);
+ dY++;
+ }
+ } else {
+ av_image_copy_plane(dst, dStride, src, sStride, bwidth, height);
+ }
+
+ priv->pic->interlaced_frame = interlaced;
+ if (interlaced)
+ priv->pic->top_field_first = !bottom_first;
+
+ priv->pic->pkt_pts = pkt_pts;
+
+ if (!priv->need_second_field) {
+ *got_frame = 1;
+ if ((ret = av_frame_ref(data, priv->pic)) < 0) {
+ return ret;
+ }
+ }
+
+ /*
+ * Two types of PAFF content have been observed. One form causes the
+ * hardware to return a field pair and the other individual fields,
+ * even though the input is always individual fields. We must skip
+ * copying on the next decode() call to maintain pipeline length in
+ * the first case.
+ */
+ if (!interlaced && (output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) &&
+ (pic_type == PICT_TOP_FIELD || pic_type == PICT_BOTTOM_FIELD)) {
+ av_log(priv->avctx, AV_LOG_VERBOSE, "Fieldpair from two packets.\n");
+ return RET_SKIP_NEXT_COPY;
+ }
+
+ /*
+ * The logic here is purely based on empirical testing with samples.
+ * If we need a second field, it could come from a second input packet,
+ * or it could come from the same field-pair input packet at the current
+ * field. In the first case, we should return and wait for the next time
+ * round to get the second field, while in the second case, we should
+ * ask the decoder for it immediately.
+ *
+ * Testing has shown that we are dealing with the fieldpair -> two fields
+ * case if the VDEC_FLAG_UNKNOWN_SRC is not set or if the input picture
+ * type was PICT_FRAME (in this second case, the flag might still be set)
+ */
+ return priv->need_second_field &&
+ (!(output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) ||
+ pic_type == PICT_FRAME) ?
+ RET_COPY_NEXT_FIELD : RET_OK;
+}
+
+
+static inline CopyRet receive_frame(AVCodecContext *avctx,
+ void *data, int *got_frame)
+{
+ BC_STATUS ret;
+ BC_DTS_PROC_OUT output = {
+ .PicInfo.width = avctx->width,
+ .PicInfo.height = avctx->height,
+ };
+ CHDContext *priv = avctx->priv_data;
+ HANDLE dev = priv->dev;
+
+ *got_frame = 0;
+
+ // Request decoded data from the driver
+ ret = DtsProcOutputNoCopy(dev, OUTPUT_PROC_TIMEOUT, &output);
+ if (ret == BC_STS_FMT_CHANGE) {
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Initial format change\n");
+ avctx->width = output.PicInfo.width;
+ avctx->height = output.PicInfo.height;
+ switch ( output.PicInfo.aspect_ratio ) {
+ case vdecAspectRatioSquare:
+ avctx->sample_aspect_ratio = (AVRational) { 1, 1};
+ break;
+ case vdecAspectRatio12_11:
+ avctx->sample_aspect_ratio = (AVRational) { 12, 11};
+ break;
+ case vdecAspectRatio10_11:
+ avctx->sample_aspect_ratio = (AVRational) { 10, 11};
+ break;
+ case vdecAspectRatio16_11:
+ avctx->sample_aspect_ratio = (AVRational) { 16, 11};
+ break;
+ case vdecAspectRatio40_33:
+ avctx->sample_aspect_ratio = (AVRational) { 40, 33};
+ break;
+ case vdecAspectRatio24_11:
+ avctx->sample_aspect_ratio = (AVRational) { 24, 11};
+ break;
+ case vdecAspectRatio20_11:
+ avctx->sample_aspect_ratio = (AVRational) { 20, 11};
+ break;
+ case vdecAspectRatio32_11:
+ avctx->sample_aspect_ratio = (AVRational) { 32, 11};
+ break;
+ case vdecAspectRatio80_33:
+ avctx->sample_aspect_ratio = (AVRational) { 80, 33};
+ break;
+ case vdecAspectRatio18_11:
+ avctx->sample_aspect_ratio = (AVRational) { 18, 11};
+ break;
+ case vdecAspectRatio15_11:
+ avctx->sample_aspect_ratio = (AVRational) { 15, 11};
+ break;
+ case vdecAspectRatio64_33:
+ avctx->sample_aspect_ratio = (AVRational) { 64, 33};
+ break;
+ case vdecAspectRatio160_99:
+ avctx->sample_aspect_ratio = (AVRational) {160, 99};
+ break;
+ case vdecAspectRatio4_3:
+ avctx->sample_aspect_ratio = (AVRational) { 4, 3};
+ break;
+ case vdecAspectRatio16_9:
+ avctx->sample_aspect_ratio = (AVRational) { 16, 9};
+ break;
+ case vdecAspectRatio221_1:
+ avctx->sample_aspect_ratio = (AVRational) {221, 1};
+ break;
+ }
+ return RET_COPY_AGAIN;
+ } else if (ret == BC_STS_SUCCESS) {
+ int copy_ret = -1;
+ if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) {
+ if (priv->last_picture == -1) {
+ /*
+ * Init to one less, so that the incrementing code doesn't
+ * need to be special-cased.
+ */
+ priv->last_picture = output.PicInfo.picture_number - 1;
+ }
+
+ if (avctx->codec->id == AV_CODEC_ID_MPEG4 &&
+ output.PicInfo.timeStamp == 0 && priv->bframe_bug) {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: Not returning packed frame twice.\n");
+ priv->last_picture++;
+ DtsReleaseOutputBuffs(dev, NULL, FALSE);
+ return RET_COPY_AGAIN;
+ }
+
+ print_frame_info(priv, &output);
+
+ if (priv->last_picture + 1 < output.PicInfo.picture_number) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: Picture Number discontinuity\n");
+ /*
+ * Have we lost frames? If so, we need to shrink the
+ * pipeline length appropriately.
+ *
+ * XXX: I have no idea what the semantics of this situation
+ * are so I don't even know if we've lost frames or which
+ * ones.
+ *
+ * In any case, only warn the first time.
+ */
+ priv->last_picture = output.PicInfo.picture_number - 1;
+ }
+
+ copy_ret = copy_frame(avctx, &output, data, got_frame);
+ if (*got_frame > 0) {
+ avctx->has_b_frames--;
+ priv->last_picture++;
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Pipeline length: %u\n",
+ avctx->has_b_frames);
+ }
+ } else {
+ /*
+ * An invalid frame has been consumed.
+ */
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput succeeded with "
+ "invalid PIB\n");
+ avctx->has_b_frames--;
+ copy_ret = RET_OK;
+ }
+ DtsReleaseOutputBuffs(dev, NULL, FALSE);
+
+ return copy_ret;
+ } else if (ret == BC_STS_BUSY) {
+ return RET_COPY_AGAIN;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: ProcOutput failed %d\n", ret);
+ return RET_ERROR;
+ }
+}
+
+
+static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
+{
+ BC_STATUS ret;
+ BC_DTS_STATUS decoder_status = { 0, };
+ CopyRet rec_ret;
+ CHDContext *priv = avctx->priv_data;
+ HANDLE dev = priv->dev;
+ uint8_t *in_data = avpkt->data;
+ int len = avpkt->size;
+ int free_data = 0;
+ uint8_t pic_type = 0;
+
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_frame\n");
+
+ if (avpkt->size == 7 && !priv->bframe_bug) {
+ /*
+ * The use of a drop frame triggers the bug
+ */
+ av_log(avctx, AV_LOG_INFO,
+ "CrystalHD: Enabling work-around for packed b-frame bug\n");
+ priv->bframe_bug = 1;
+ } else if (avpkt->size == 8 && priv->bframe_bug) {
+ /*
+ * Delay frames don't trigger the bug
+ */
+ av_log(avctx, AV_LOG_INFO,
+ "CrystalHD: Disabling work-around for packed b-frame bug\n");
+ priv->bframe_bug = 0;
+ }
+
+ if (len) {
+ int32_t tx_free = (int32_t)DtsTxFreeSize(dev);
+
+ if (priv->parser) {
+ int ret = 0;
+
+ if (priv->bsfc) {
+ ret = av_bitstream_filter_filter(priv->bsfc, avctx, NULL,
+ &in_data, &len,
+ avpkt->data, len, 0);
+ }
+ free_data = ret > 0;
+
+ if (ret >= 0) {
+ uint8_t *pout;
+ int psize;
+ int index;
+ H264Context *h = priv->parser->priv_data;
+
+ index = av_parser_parse2(priv->parser, avctx, &pout, &psize,
+ in_data, len, avctx->internal->pkt->pts,
+ avctx->internal->pkt->dts, 0);
+ if (index < 0) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: Failed to parse h.264 packet to "
+ "detect interlacing.\n");
+ } else if (index != len) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: Failed to parse h.264 packet "
+ "completely. Interlaced frames may be "
+ "incorrectly detected.\n");
+ } else {
+ av_log(avctx, AV_LOG_VERBOSE,
+ "CrystalHD: parser picture type %d\n",
+ h->picture_structure);
+ pic_type = h->picture_structure;
+ }
+ } else {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: mp4toannexb filter failed to filter "
+ "packet. Interlaced frames may be incorrectly "
+ "detected.\n");
+ }
+ }
+
+ if (len < tx_free - 1024) {
+ /*
+ * Despite being notionally opaque, either libcrystalhd or
+ * the hardware itself will mangle pts values that are too
+ * small or too large. The docs claim it should be in units
+ * of 100ns. Given that we're nominally dealing with a black
+ * box on both sides, any transform we do has no guarantee of
+ * avoiding mangling so we need to build a mapping to values
+ * we know will not be mangled.
+ */
+ uint64_t pts = opaque_list_push(priv, avctx->internal->pkt->pts, pic_type);
+ if (!pts) {
+ if (free_data) {
+ av_freep(&in_data);
+ }
+ return AVERROR(ENOMEM);
+ }
+ av_log(priv->avctx, AV_LOG_VERBOSE,
+ "input \"pts\": %"PRIu64"\n", pts);
+ ret = DtsProcInput(dev, in_data, len, pts, 0);
+ if (free_data) {
+ av_freep(&in_data);
+ }
+ if (ret == BC_STS_BUSY) {
+ av_log(avctx, AV_LOG_WARNING,
+ "CrystalHD: ProcInput returned busy\n");
+ usleep(BASE_WAIT);
+ return AVERROR(EBUSY);
+ } else if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR,
+ "CrystalHD: ProcInput failed: %u\n", ret);
+ return -1;
+ }
+ avctx->has_b_frames++;
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "CrystalHD: Input buffer full\n");
+ len = 0; // We didn't consume any bytes.
+ }
+ } else {
+ av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
+ }
+
+ if (priv->skip_next_output) {
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Skipping next output.\n");
+ priv->skip_next_output = 0;
+ avctx->has_b_frames--;
+ return len;
+ }
+
+ ret = DtsGetDriverStatus(dev, &decoder_status);
+ if (ret != BC_STS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "CrystalHD: GetDriverStatus failed\n");
+ return -1;
+ }
+
+ /*
+ * No frames ready. Don't try to extract.
+ *
+ * Empirical testing shows that ReadyListCount can be a damn lie,
+ * and ProcOut still fails when count > 0. The same testing showed
+ * that two more iterations were needed before ProcOutput would
+ * succeed.
+ */
+ if (priv->output_ready < 2) {
+ if (decoder_status.ReadyListCount != 0)
+ priv->output_ready++;
+ usleep(BASE_WAIT);
+ av_log(avctx, AV_LOG_INFO, "CrystalHD: Filling pipeline.\n");
+ return len;
+ } else if (decoder_status.ReadyListCount == 0) {
+ /*
+ * After the pipeline is established, if we encounter a lack of frames
+ * that probably means we're not giving the hardware enough time to
+ * decode them, so start increasing the wait time at the end of a
+ * decode call.
+ */
+ usleep(BASE_WAIT);
+ priv->decode_wait += WAIT_UNIT;
+ av_log(avctx, AV_LOG_INFO, "CrystalHD: No frames ready. Returning\n");
+ return len;
+ }
+
+ do {
+ rec_ret = receive_frame(avctx, data, got_frame);
+ if (rec_ret == RET_OK && *got_frame == 0) {
+ /*
+ * This case is for when the encoded fields are stored
+ * separately and we get a separate avpkt for each one. To keep
+ * the pipeline stable, we should return nothing and wait for
+ * the next time round to grab the second field.
+ * H.264 PAFF is an example of this.
+ */
+ av_log(avctx, AV_LOG_VERBOSE, "Returning after first field.\n");
+ avctx->has_b_frames--;
+ } else if (rec_ret == RET_COPY_NEXT_FIELD) {
+ /*
+ * This case is for when the encoded fields are stored in a
+ * single avpkt but the hardware returns then separately. Unless
+ * we grab the second field before returning, we'll slip another
+ * frame in the pipeline and if that happens a lot, we're sunk.
+ * So we have to get that second field now.
+ * Interlaced mpeg2 and vc1 are examples of this.
+ */
+ av_log(avctx, AV_LOG_VERBOSE, "Trying to get second field.\n");
+ while (1) {
+ usleep(priv->decode_wait);
+ ret = DtsGetDriverStatus(dev, &decoder_status);
+ if (ret == BC_STS_SUCCESS &&
+ decoder_status.ReadyListCount > 0) {
+ rec_ret = receive_frame(avctx, data, got_frame);
+ if ((rec_ret == RET_OK && *got_frame > 0) ||
+ rec_ret == RET_ERROR)
+ break;
+ }
+ }
+ av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Got second field.\n");
+ } else if (rec_ret == RET_SKIP_NEXT_COPY) {
+ /*
+ * Two input packets got turned into a field pair. Gawd.
+ */
+ av_log(avctx, AV_LOG_VERBOSE,
+ "Don't output on next decode call.\n");
+ priv->skip_next_output = 1;
+ }
+ /*
+ * If rec_ret == RET_COPY_AGAIN, that means that either we just handled
+ * a FMT_CHANGE event and need to go around again for the actual frame,
+ * we got a busy status and need to try again, or we're dealing with
+ * packed b-frames, where the hardware strangely returns the packed
+ * p-frame twice. We choose to keep the second copy as it carries the
+ * valid pts.
+ */
+ } while (rec_ret == RET_COPY_AGAIN);
+ usleep(priv->decode_wait);
+ return len;
+}
+
+
+#if CONFIG_H264_CRYSTALHD_DECODER
+static AVClass h264_class = {
+ "h264_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_h264_crystalhd_decoder = {
+ .name = "h264_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &h264_class,
+};
+#endif
+
+#if CONFIG_MPEG2_CRYSTALHD_DECODER
+static AVClass mpeg2_class = {
+ "mpeg2_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_mpeg2_crystalhd_decoder = {
+ .name = "mpeg2_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 Video (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG2VIDEO,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &mpeg2_class,
+};
+#endif
+
+#if CONFIG_MPEG4_CRYSTALHD_DECODER
+static AVClass mpeg4_class = {
+ "mpeg4_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_mpeg4_crystalhd_decoder = {
+ .name = "mpeg4_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Part 2 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG4,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &mpeg4_class,
+};
+#endif
+
+#if CONFIG_MSMPEG4_CRYSTALHD_DECODER
+static AVClass msmpeg4_class = {
+ "msmpeg4_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_msmpeg4_crystalhd_decoder = {
+ .name = "msmpeg4_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Part 2 Microsoft variant version 3 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MSMPEG4V3,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_EXPERIMENTAL,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &msmpeg4_class,
+};
+#endif
+
+#if CONFIG_VC1_CRYSTALHD_DECODER
+static AVClass vc1_class = {
+ "vc1_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_vc1_crystalhd_decoder = {
+ .name = "vc1_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_VC1,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &vc1_class,
+};
+#endif
+
+#if CONFIG_WMV3_CRYSTALHD_DECODER
+static AVClass wmv3_class = {
+ "wmv3_crystalhd",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_wmv3_crystalhd_decoder = {
+ .name = "wmv3_crystalhd",
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 (CrystalHD acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_WMV3,
+ .priv_data_size = sizeof(CHDContext),
+ .init = init,
+ .close = uninit,
+ .decode = decode,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
+ .flush = flush,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE},
+ .priv_class = &wmv3_class,
+};
+#endif
diff --git a/libavcodec/cscd.c b/libavcodec/cscd.c
index 358240b7a9..07f2f5ed8f 100644
--- a/libavcodec/cscd.c
+++ b/libavcodec/cscd.c
@@ -2,20 +2,20 @@
* CamStudio decoder
* Copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
@@ -31,14 +31,15 @@
#include "libavutil/lzo.h"
typedef struct CamStudioContext {
+ AVFrame *pic;
int linelen, height, bpp;
unsigned int decomp_size;
unsigned char* decomp_buf;
} CamStudioContext;
-static void copy_frame_default(AVFrame *f, const uint8_t *src, int src_stride,
+static void copy_frame_default(AVFrame *f, const uint8_t *src,
int linelen, int height) {
- int i;
+ int i, src_stride = FFALIGN(linelen, 4);
uint8_t *dst = f->data[0];
dst += (height - 1) * f->linesize[0];
for (i = height; i; i--) {
@@ -48,9 +49,9 @@ static void copy_frame_default(AVFrame *f, const uint8_t *src, int src_stride,
}
}
-static void add_frame_default(AVFrame *f, const uint8_t *src, int src_stride,
+static void add_frame_default(AVFrame *f, const uint8_t *src,
int linelen, int height) {
- int i, j;
+ int i, j, src_stride = FFALIGN(linelen, 4);
uint8_t *dst = f->data[0];
dst += (height - 1) * f->linesize[0];
for (i = height; i; i--) {
@@ -61,87 +62,11 @@ static void add_frame_default(AVFrame *f, const uint8_t *src, int src_stride,
}
}
-#if !HAVE_BIGENDIAN
-#define copy_frame_16(f, s, l, h) copy_frame_default(f, s, l, l, h)
-#define copy_frame_32(f, s, l, h) copy_frame_default(f, s, l, l, h)
-#define add_frame_16(f, s, l, h) add_frame_default(f, s, l, l, h)
-#define add_frame_32(f, s, l, h) add_frame_default(f, s, l, l, h)
-#else
-static void copy_frame_16(AVFrame *f, const uint8_t *src,
- int linelen, int height) {
- int i, j;
- uint8_t *dst = f->data[0];
- dst += (height - 1) * f->linesize[0];
- for (i = height; i; i--) {
- for (j = linelen / 2; j; j--) {
- dst[0] = src[1];
- dst[1] = src[0];
- src += 2;
- dst += 2;
- }
- dst -= f->linesize[0] + linelen;
- }
-}
-
-static void copy_frame_32(AVFrame *f, const uint8_t *src,
- int linelen, int height) {
- int i, j;
- uint8_t *dst = f->data[0];
- dst += (height - 1) * f->linesize[0];
- for (i = height; i; i--) {
- for (j = linelen / 4; j; j--) {
- dst[0] = src[3];
- dst[1] = src[2];
- dst[2] = src[1];
- dst[3] = src[0];
- src += 4;
- dst += 4;
- }
- dst -= f->linesize[0] + linelen;
- }
-}
-
-static void add_frame_16(AVFrame *f, const uint8_t *src,
- int linelen, int height) {
- int i, j;
- uint8_t *dst = f->data[0];
- dst += (height - 1) * f->linesize[0];
- for (i = height; i; i--) {
- for (j = linelen / 2; j; j--) {
- dst[0] += src[1];
- dst[1] += src[0];
- src += 2;
- dst += 2;
- }
- dst -= f->linesize[0] + linelen;
- }
-}
-
-static void add_frame_32(AVFrame *f, const uint8_t *src,
- int linelen, int height) {
- int i, j;
- uint8_t *dst = f->data[0];
- dst += (height - 1) * f->linesize[0];
- for (i = height; i; i--) {
- for (j = linelen / 4; j; j--) {
- dst[0] += src[3];
- dst[1] += src[2];
- dst[2] += src[1];
- dst[3] += src[0];
- src += 4;
- dst += 4;
- }
- dst -= f->linesize[0] + linelen;
- }
-}
-#endif
-
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt) {
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
CamStudioContext *c = avctx->priv_data;
- AVFrame *picture = data;
int ret;
if (buf_size < 2) {
@@ -149,10 +74,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
return ret;
- }
// decompress data
switch ((buf[0] >> 1) & 7) {
@@ -180,36 +103,21 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
// flip upside down, add difference frame
if (buf[0] & 1) { // keyframe
- picture->pict_type = AV_PICTURE_TYPE_I;
- picture->key_frame = 1;
- switch (c->bpp) {
- case 16:
- copy_frame_16(picture, c->decomp_buf, c->linelen, c->height);
- break;
- case 32:
- copy_frame_32(picture, c->decomp_buf, c->linelen, c->height);
- break;
- default:
- copy_frame_default(picture, c->decomp_buf, FFALIGN(c->linelen, 4),
+ c->pic->pict_type = AV_PICTURE_TYPE_I;
+ c->pic->key_frame = 1;
+ copy_frame_default(c->pic, c->decomp_buf,
c->linelen, c->height);
- }
} else {
- picture->pict_type = AV_PICTURE_TYPE_P;
- picture->key_frame = 0;
- switch (c->bpp) {
- case 16:
- add_frame_16(picture, c->decomp_buf, c->linelen, c->height);
- break;
- case 32:
- add_frame_32(picture, c->decomp_buf, c->linelen, c->height);
- break;
- default:
- add_frame_default(picture, c->decomp_buf, FFALIGN(c->linelen, 4),
+ c->pic->pict_type = AV_PICTURE_TYPE_P;
+ c->pic->key_frame = 0;
+ add_frame_default(c->pic, c->decomp_buf,
c->linelen, c->height);
- }
}
*got_frame = 1;
+ if ((ret = av_frame_ref(data, c->pic)) < 0)
+ return ret;
+
return buf_size;
}
@@ -217,9 +125,9 @@ static av_cold int decode_init(AVCodecContext *avctx) {
CamStudioContext *c = avctx->priv_data;
int stride;
switch (avctx->bits_per_coded_sample) {
- case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break;
+ case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555LE; break;
case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break;
- case 32: avctx->pix_fmt = AV_PIX_FMT_RGB32; break;
+ case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break;
default:
av_log(avctx, AV_LOG_ERROR,
"CamStudio codec error: invalid depth %i bpp\n",
@@ -229,21 +137,23 @@ static av_cold int decode_init(AVCodecContext *avctx) {
c->bpp = avctx->bits_per_coded_sample;
c->linelen = avctx->width * avctx->bits_per_coded_sample / 8;
c->height = avctx->height;
- stride = c->linelen;
- if (avctx->bits_per_coded_sample == 24)
- stride = FFALIGN(stride, 4);
+ stride = FFALIGN(c->linelen, 4);
c->decomp_size = c->height * stride;
c->decomp_buf = av_malloc(c->decomp_size + AV_LZO_OUTPUT_PADDING);
if (!c->decomp_buf) {
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return AVERROR(ENOMEM);
}
+ c->pic = av_frame_alloc();
+ if (!c->pic)
+ return AVERROR(ENOMEM);
return 0;
}
static av_cold int decode_end(AVCodecContext *avctx) {
CamStudioContext *c = avctx->priv_data;
av_freep(&c->decomp_buf);
+ av_frame_free(&c->pic);
return 0;
}
diff --git a/libavcodec/cyuv.c b/libavcodec/cyuv.c
index f628ba1828..6e8e461ae0 100644
--- a/libavcodec/cyuv.c
+++ b/libavcodec/cyuv.c
@@ -4,22 +4,22 @@
* based on "Creative YUV (CYUV) stream format for AVI":
* http://www.csse.monash.edu.au/~timf/videocodec/cyuv.txt
*
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,7 +52,6 @@ static av_cold int cyuv_decode_init(AVCodecContext *avctx)
if (s->width & 0x3)
return AVERROR_INVALIDDATA;
s->height = avctx->height;
- avctx->pix_fmt = AV_PIX_FMT_YUV411P;
return 0;
}
@@ -82,6 +81,7 @@ static int cyuv_decode_frame(AVCodecContext *avctx,
int stream_ptr;
unsigned char cur_byte;
int pixel_groups;
+ int rawsize = s->height * FFALIGN(s->width,2) * 2;
int ret;
if (avctx->codec_id == AV_CODEC_ID_AURA) {
@@ -92,7 +92,11 @@ static int cyuv_decode_frame(AVCodecContext *avctx,
* followed by (height) lines each with 3 bytes to represent groups
* of 4 pixels. Thus, the total size of the buffer ought to be:
* (3 * 16) + height * (width * 3 / 4) */
- if (buf_size != 48 + s->height * (s->width * 3 / 4)) {
+ if (buf_size == 48 + s->height * (s->width * 3 / 4)) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV411P;
+ } else if(buf_size == rawsize ) {
+ avctx->pix_fmt = AV_PIX_FMT_UYVY422;
+ } else {
av_log(avctx, AV_LOG_ERROR, "got a buffer with %d bytes when %d were expected\n",
buf_size, 48 + s->height * (s->width * 3 / 4));
return AVERROR_INVALIDDATA;
@@ -101,15 +105,22 @@ static int cyuv_decode_frame(AVCodecContext *avctx,
/* pixel data starts 48 bytes in, after 3x16-byte tables */
stream_ptr = 48;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
y_plane = frame->data[0];
u_plane = frame->data[1];
v_plane = frame->data[2];
+ if (buf_size == rawsize) {
+ int linesize = FFALIGN(s->width,2) * 2;
+ y_plane += frame->linesize[0] * s->height;
+ for (stream_ptr = 0; stream_ptr < rawsize; stream_ptr += linesize) {
+ y_plane -= frame->linesize[0];
+ memcpy(y_plane, buf+stream_ptr, linesize);
+ }
+ } else {
+
/* iterate through each line in the height */
for (y_ptr = 0, u_ptr = 0, v_ptr = 0;
y_ptr < (s->height * frame->linesize[0]);
@@ -157,6 +168,7 @@ static int cyuv_decode_frame(AVCodecContext *avctx,
}
}
+ }
*got_frame = 1;
diff --git a/libavcodec/d3d11va.h b/libavcodec/d3d11va.h
index 2163b350aa..d51e2ff8f5 100644
--- a/libavcodec/d3d11va.h
+++ b/libavcodec/d3d11va.h
@@ -4,20 +4,20 @@
* copyright (c) 2009 Laurent Aimar
* copyright (c) 2015 Steve Lhomme
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,7 @@
/**
* This structure is used to provides the necessary configurations and data
- * to the Direct3D11 Libav HWAccel implementation.
+ * to the Direct3D11 FFmpeg HWAccel implementation.
*
* The application must make it available as AVCodecContext.hwaccel_context.
*/
@@ -86,7 +86,7 @@ struct AVD3D11VAContext {
uint64_t workaround;
/**
- * Private to the Libav AVHWAccel implementation
+ * Private to the FFmpeg AVHWAccel implementation
*/
unsigned report_id;
};
diff --git a/libavcodec/dca.c b/libavcodec/dca.c
index ebe9fdb47c..8dd043088e 100644
--- a/libavcodec/dca.c
+++ b/libavcodec/dca.c
@@ -1,20 +1,24 @@
/*
* DCA compatible decoder data
+ * Copyright (C) 2004 Gildas Bazin
+ * Copyright (C) 2004 Benjamin Zores
+ * Copyright (C) 2006 Benjamin Larsson
+ * Copyright (C) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,7 +36,7 @@ const uint32_t avpriv_dca_sample_rates[16] = {
12000, 24000, 48000, 96000, 192000
};
-int ff_dca_convert_bitstream(const uint8_t *src, int src_size, uint8_t *dst,
+int avpriv_dca_convert_bitstream(const uint8_t *src, int src_size, uint8_t *dst,
int max_size)
{
uint32_t mrk;
diff --git a/libavcodec/dca.h b/libavcodec/dca.h
index 887eb375f2..897ebf4b73 100644
--- a/libavcodec/dca.h
+++ b/libavcodec/dca.h
@@ -5,20 +5,20 @@
* Copyright (C) 2006 Benjamin Larsson
* Copyright (C) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,6 +41,8 @@
#define DCA_SUBFRAMES_MAX (16)
#define DCA_BLOCKS_MAX (16)
#define DCA_LFE_MAX (3)
+#define DCA_CHSETS_MAX (4)
+#define DCA_CHSET_CHANS_MAX (8)
#define DCA_PRIM_CHANNELS_MAX (7)
#define DCA_ABITS_MAX (32) /* Should be 28 */
@@ -131,7 +133,7 @@ typedef struct QMF64_table {
} QMF64_table;
typedef struct DCAContext {
- AVClass *class; ///< class for AVOptions
+ const AVClass *class; ///< class for AVOptions
AVCodecContext *avctx;
/* Frame header */
int frame_type; ///< type of the current frame
@@ -234,6 +236,20 @@ typedef struct DCAContext {
int xch_base_channel; ///< index of first (only) channel containing XCH data
int xch_disable; ///< whether the XCh extension should be decoded or not
+ /* XXCH extension information */
+ int xxch_chset;
+ int xxch_nbits_spk_mask;
+ uint32_t xxch_core_spkmask;
+ uint32_t xxch_spk_masks[4]; /* speaker masks, last element is core mask */
+ int xxch_chset_nch[4];
+ float xxch_dmix_sf[DCA_CHSETS_MAX];
+
+ uint32_t xxch_dmix_embedded; /* lower layer has mix pre-embedded, per chset */
+ float xxch_dmix_coeff[DCA_PRIM_CHANNELS_MAX][32]; /* worst case sizing */
+
+ int8_t xxch_order_tab[32];
+ int8_t lfe_index;
+
/* XLL extension information */
int xll_disable;
int xll_nch_sets; ///< number of channel sets per frame
@@ -262,7 +278,7 @@ typedef struct DCAContext {
int one2one_map_chtospkr;
int debug_flag; ///< used for suppressing repeated error messages output
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext imdct;
SynthFilterContext synth;
DCADSPContext dcadsp;
@@ -275,9 +291,12 @@ extern av_export const uint32_t avpriv_dca_sample_rates[16];
/**
* Convert bitstream to one representation based on sync marker
*/
-int ff_dca_convert_bitstream(const uint8_t *src, int src_size, uint8_t *dst,
+int avpriv_dca_convert_bitstream(const uint8_t *src, int src_size, uint8_t *dst,
int max_size);
+int ff_dca_xbr_parse_frame(DCAContext *s);
+int ff_dca_xxch_decode_frame(DCAContext *s);
+
void ff_dca_exss_parse_header(DCAContext *s);
int ff_dca_xll_decode_header(DCAContext *s);
diff --git a/libavcodec/dca_exss.c b/libavcodec/dca_exss.c
index 2895e2096e..ed014906ce 100644
--- a/libavcodec/dca_exss.c
+++ b/libavcodec/dca_exss.c
@@ -1,20 +1,20 @@
/*
* DCA ExSS extension
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -316,6 +316,8 @@ void ff_dca_exss_parse_header(DCAContext *s)
}
}
+ av_assert0(num_assets > 0); // silence a warning
+
for (i = 0; i < num_assets; i++)
asset_size[i] = get_bits_long(&s->gb, 16 + 4 * blownup) + 1;
@@ -324,7 +326,6 @@ void ff_dca_exss_parse_header(DCAContext *s)
return;
}
- if (num_assets > 0) {
j = get_bits_count(&s->gb);
if (start_pos + hdrsize * 8 > j)
skip_bits_long(&s->gb, start_pos + hdrsize * 8 - j);
@@ -337,6 +338,13 @@ void ff_dca_exss_parse_header(DCAContext *s)
/* parse extensions that we know about */
switch (mkr) {
+ case DCA_SYNCWORD_XBR:
+ ff_dca_xbr_parse_frame(s);
+ break;
+ case DCA_SYNCWORD_XXCH:
+ ff_dca_xxch_decode_frame(s);
+ s->core_ext_mask |= DCA_EXT_XXCH; /* xxx use for chan reordering */
+ break;
case DCA_SYNCWORD_XLL:
if (s->xll_disable) {
av_log(s->avctx, AV_LOG_DEBUG,
@@ -349,11 +357,9 @@ void ff_dca_exss_parse_header(DCAContext *s)
ff_dca_xll_decode_navi(s, end_pos) == 0)
s->exss_ext_mask |= DCA_EXT_EXSS_XLL;
break;
- case DCA_SYNCWORD_XBR:
- case DCA_SYNCWORD_XXCH:
default:
- av_log(s->avctx, AV_LOG_VERBOSE,
- "DTS-ExSS: unknown marker = 0x%08"PRIx32"\n", mkr);
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "DTS-ExSS: unknown marker = 0x%08x\n", mkr);
}
/* skip to end of block */
@@ -364,5 +370,4 @@ void ff_dca_exss_parse_header(DCAContext *s)
if (j < end_pos)
skip_bits_long(&s->gb, end_pos - j);
}
- }
}
diff --git a/libavcodec/dca_parser.c b/libavcodec/dca_parser.c
index d827daac37..9dafe706e2 100644
--- a/libavcodec/dca_parser.c
+++ b/libavcodec/dca_parser.c
@@ -5,20 +5,20 @@
* Copyright (C) 2006 Benjamin Larsson
* Copyright (C) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -119,7 +119,7 @@ static int dca_parse_params(const uint8_t *buf, int buf_size, int *duration,
if (buf_size < 12)
return AVERROR_INVALIDDATA;
- if ((ret = ff_dca_convert_bitstream(buf, 12, hdr, 12)) < 0)
+ if ((ret = avpriv_dca_convert_bitstream(buf, 12, hdr, 12)) < 0)
return ret;
init_get_bits(&gb, hdr, 96);
diff --git a/libavcodec/dca_syncwords.h b/libavcodec/dca_syncwords.h
index 07b60e080d..3466b6bc6f 100644
--- a/libavcodec/dca_syncwords.h
+++ b/libavcodec/dca_syncwords.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dca_xll.c b/libavcodec/dca_xll.c
index 5a558b8c48..98fd4c8eaa 100644
--- a/libavcodec/dca_xll.c
+++ b/libavcodec/dca_xll.c
@@ -4,20 +4,20 @@
* Copyright (C) 2012 Paul B Mahol
* Copyright (C) 2014 Niels Möller
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -393,7 +393,7 @@ static void dca_xll_inv_adapt_pred(int *samples, int nsamples, unsigned order,
for (; j < order; j++)
s += (int64_t) c[j] * prev[DCA_XLL_AORDER_MAX + i - 1 - j];
- samples[i] -= av_clip((s + 0x8000) >> 16, -0x1000000, 0xffffff);
+ samples[i] -= av_clip_intp2((s + 0x8000) >> 16, 24);
}
}
for (i = order; i < nsamples; i++) {
@@ -402,7 +402,7 @@ static void dca_xll_inv_adapt_pred(int *samples, int nsamples, unsigned order,
/* NOTE: Equations seem to imply addition, while the
* pseudocode seems to use subtraction.*/
- samples[i] -= av_clip((s + 0x8000) >> 16, -0x1000000, 0xffffff);
+ samples[i] -= av_clip_intp2((s + 0x8000) >> 16, 24);
}
}
diff --git a/libavcodec/dcadata.c b/libavcodec/dcadata.c
index 1db1938b29..5d7d5943a1 100644
--- a/libavcodec/dcadata.c
+++ b/libavcodec/dcadata.c
@@ -3,27 +3,29 @@
* Copyright (C) 2004 Gildas Bazin
* Copyright (c) 2006 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
+#include "libavutil/channel_layout.h"
#include "libavutil/mem.h"
+#include "dca.h"
#include "dcadata.h"
/* Generic tables */
@@ -8316,6 +8318,95 @@ const int32_t ff_dca_sampling_freqs[16] = {
* where Ch(n) represents the subband samples in the (n)th audio channel.
*/
+const uint32_t ff_dca_map_xxch_to_native[28] = {
+ AV_CH_FRONT_CENTER,
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ AV_CH_LOW_FREQUENCY,
+ AV_CH_BACK_CENTER,
+ AV_CH_BACK_LEFT,
+ AV_CH_BACK_RIGHT,
+ AV_CH_SIDE_LEFT, /* side surround left -- dup sur side L */
+ AV_CH_SIDE_RIGHT, /* side surround right -- dup sur side R */
+ AV_CH_FRONT_LEFT_OF_CENTER,
+ AV_CH_FRONT_RIGHT_OF_CENTER,
+ AV_CH_TOP_FRONT_LEFT,
+ AV_CH_TOP_FRONT_CENTER,
+ AV_CH_TOP_FRONT_RIGHT,
+ AV_CH_LOW_FREQUENCY, /* lfe2 -- duplicate lfe1 position */
+ AV_CH_FRONT_LEFT_OF_CENTER, /* side front left -- dup front cntr L */
+ AV_CH_FRONT_RIGHT_OF_CENTER,/* side front right -- dup front cntr R */
+ AV_CH_TOP_CENTER, /* overhead */
+ AV_CH_TOP_FRONT_LEFT, /* side high left -- dup */
+ AV_CH_TOP_FRONT_RIGHT, /* side high right -- dup */
+ AV_CH_TOP_BACK_CENTER,
+ AV_CH_TOP_BACK_LEFT,
+ AV_CH_TOP_BACK_RIGHT,
+ AV_CH_BACK_CENTER, /* rear low center -- dup */
+ AV_CH_BACK_LEFT, /* rear low left -- dup */
+ AV_CH_BACK_RIGHT /* read low right -- dup */
+};
+
+/* -1 are reserved or unknown */
+const int ff_dca_ext_audio_descr_mask[8] = {
+ DCA_EXT_XCH,
+ -1,
+ DCA_EXT_X96,
+ DCA_EXT_XCH | DCA_EXT_X96,
+ -1,
+ -1,
+ DCA_EXT_XXCH,
+ -1,
+};
+
+/* Tables for mapping dts channel configurations to libavcodec multichannel api.
+ * Some compromises have been made for special configurations. Most configurations
+ * are never used so complete accuracy is not needed.
+ *
+ * L = left, R = right, C = center, S = surround, F = front, R = rear, T = total, OV = overhead.
+ * S -> side, when both rear and back are configured move one of them to the side channel
+ * OV -> center back
+ * All 2 channel configurations -> AV_CH_LAYOUT_STEREO
+ */
+const uint64_t ff_dca_core_channel_layout[16] = {
+ AV_CH_FRONT_CENTER, ///< 1, A
+ AV_CH_LAYOUT_STEREO, ///< 2, A + B (dual mono)
+ AV_CH_LAYOUT_STEREO, ///< 2, L + R (stereo)
+ AV_CH_LAYOUT_STEREO, ///< 2, (L + R) + (L - R) (sum-difference)
+ AV_CH_LAYOUT_STEREO, ///< 2, LT + RT (left and right total)
+ AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER, ///< 3, C + L + R
+ AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER, ///< 3, L + R + S
+ AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER | AV_CH_BACK_CENTER, ///< 4, C + L + R + S
+ AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT, ///< 4, L + R + SL + SR
+
+ AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER | AV_CH_SIDE_LEFT |
+ AV_CH_SIDE_RIGHT, ///< 5, C + L + R + SL + SR
+
+ AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT |
+ AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER, ///< 6, CL + CR + L + R + SL + SR
+
+ AV_CH_LAYOUT_STEREO | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT |
+ AV_CH_FRONT_CENTER | AV_CH_BACK_CENTER, ///< 6, C + L + R + LR + RR + OV
+
+ AV_CH_FRONT_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER |
+ AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_BACK_CENTER |
+ AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT, ///< 6, CF + CR + LF + RF + LR + RR
+
+ AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_CENTER |
+ AV_CH_FRONT_RIGHT_OF_CENTER | AV_CH_LAYOUT_STEREO |
+ AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT, ///< 7, CL + C + CR + L + R + SL + SR
+
+ AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER |
+ AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT |
+ AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT, ///< 8, CL + CR + L + R + SL1 + SL2 + SR1 + SR2
+
+ AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_CENTER |
+ AV_CH_FRONT_RIGHT_OF_CENTER | AV_CH_LAYOUT_STEREO |
+ AV_CH_SIDE_LEFT | AV_CH_BACK_CENTER | AV_CH_SIDE_RIGHT, ///< 8, CL + C + CR + L + R + SL + S + SR
+};
+
const int8_t ff_dca_lfe_index[16] = {
1, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 1, 3, 2, 3
};
diff --git a/libavcodec/dcadata.h b/libavcodec/dcadata.h
index 7a9d994ed2..1d3d605b9e 100644
--- a/libavcodec/dcadata.h
+++ b/libavcodec/dcadata.h
@@ -1,20 +1,20 @@
/*
* DCA compatible decoder data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,6 +58,11 @@ extern const uint32_t ff_dca_inv_dmixtable[FF_DCA_INV_DMIXTABLE_SIZE];
extern const float ff_dca_default_coeffs[10][6][2];
+extern const uint32_t ff_dca_map_xxch_to_native[28];
+extern const int ff_dca_ext_audio_descr_mask[8];
+
+extern const uint64_t ff_dca_core_channel_layout[16];
+
extern const int32_t ff_dca_sampling_freqs[16];
extern const int8_t ff_dca_lfe_index[16];
diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c
index c4dbf50bb7..3ea1bcfc9d 100644
--- a/libavcodec/dcadec.c
+++ b/libavcodec/dcadec.c
@@ -7,20 +7,20 @@
* Copyright (C) 2012 Paul B Mahol
* Copyright (C) 2014 Niels Möller
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,6 @@
#include "get_bits.h"
#include "internal.h"
#include "mathops.h"
-#include "put_bits.h"
#include "synth_filter.h"
#if ARCH_ARM
@@ -70,62 +69,36 @@ enum DCAMode {
DCA_4F2R
};
-/* -1 are reserved or unknown */
-static const int dca_ext_audio_descr_mask[] = {
- DCA_EXT_XCH,
- -1,
- DCA_EXT_X96,
- DCA_EXT_XCH | DCA_EXT_X96,
- -1,
- -1,
- DCA_EXT_XXCH,
- -1,
-};
-/* Tables for mapping dts channel configurations to libavcodec multichannel api.
- * Some compromises have been made for special configurations. Most configurations
- * are never used so complete accuracy is not needed.
- *
- * L = left, R = right, C = center, S = surround, F = front, R = rear, T = total, OV = overhead.
- * S -> side, when both rear and back are configured move one of them to the side channel
- * OV -> center back
- * All 2 channel configurations -> AV_CH_LAYOUT_STEREO
- */
-static const uint64_t dca_core_channel_layout[] = {
- AV_CH_FRONT_CENTER, ///< 1, A
- AV_CH_LAYOUT_STEREO, ///< 2, A + B (dual mono)
- AV_CH_LAYOUT_STEREO, ///< 2, L + R (stereo)
- AV_CH_LAYOUT_STEREO, ///< 2, (L + R) + (L - R) (sum-difference)
- AV_CH_LAYOUT_STEREO, ///< 2, LT + RT (left and right total)
- AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER, ///< 3, C + L + R
- AV_CH_LAYOUT_STEREO | AV_CH_BACK_CENTER, ///< 3, L + R + S
- AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER | AV_CH_BACK_CENTER, ///< 4, C + L + R + S
- AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT, ///< 4, L + R + SL + SR
-
- AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER | AV_CH_SIDE_LEFT |
- AV_CH_SIDE_RIGHT, ///< 5, C + L + R + SL + SR
-
- AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT |
- AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER, ///< 6, CL + CR + L + R + SL + SR
-
- AV_CH_LAYOUT_STEREO | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT |
- AV_CH_FRONT_CENTER | AV_CH_BACK_CENTER, ///< 6, C + L + R + LR + RR + OV
-
- AV_CH_FRONT_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER |
- AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_BACK_CENTER |
- AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT, ///< 6, CF + CR + LF + RF + LR + RR
-
- AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_CENTER |
- AV_CH_FRONT_RIGHT_OF_CENTER | AV_CH_LAYOUT_STEREO |
- AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT, ///< 7, CL + C + CR + L + R + SL + SR
-
- AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER |
- AV_CH_LAYOUT_STEREO | AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT |
- AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT, ///< 8, CL + CR + L + R + SL1 + SL2 + SR1 + SR2
-
- AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_CENTER |
- AV_CH_FRONT_RIGHT_OF_CENTER | AV_CH_LAYOUT_STEREO |
- AV_CH_SIDE_LEFT | AV_CH_BACK_CENTER | AV_CH_SIDE_RIGHT, ///< 8, CL + C + CR + L + R + SL + S + SR
+enum DCAXxchSpeakerMask {
+ DCA_XXCH_FRONT_CENTER = 0x0000001,
+ DCA_XXCH_FRONT_LEFT = 0x0000002,
+ DCA_XXCH_FRONT_RIGHT = 0x0000004,
+ DCA_XXCH_SIDE_REAR_LEFT = 0x0000008,
+ DCA_XXCH_SIDE_REAR_RIGHT = 0x0000010,
+ DCA_XXCH_LFE1 = 0x0000020,
+ DCA_XXCH_REAR_CENTER = 0x0000040,
+ DCA_XXCH_SURROUND_REAR_LEFT = 0x0000080,
+ DCA_XXCH_SURROUND_REAR_RIGHT = 0x0000100,
+ DCA_XXCH_SIDE_SURROUND_LEFT = 0x0000200,
+ DCA_XXCH_SIDE_SURROUND_RIGHT = 0x0000400,
+ DCA_XXCH_FRONT_CENTER_LEFT = 0x0000800,
+ DCA_XXCH_FRONT_CENTER_RIGHT = 0x0001000,
+ DCA_XXCH_FRONT_HIGH_LEFT = 0x0002000,
+ DCA_XXCH_FRONT_HIGH_CENTER = 0x0004000,
+ DCA_XXCH_FRONT_HIGH_RIGHT = 0x0008000,
+ DCA_XXCH_LFE2 = 0x0010000,
+ DCA_XXCH_SIDE_FRONT_LEFT = 0x0020000,
+ DCA_XXCH_SIDE_FRONT_RIGHT = 0x0040000,
+ DCA_XXCH_OVERHEAD = 0x0080000,
+ DCA_XXCH_SIDE_HIGH_LEFT = 0x0100000,
+ DCA_XXCH_SIDE_HIGH_RIGHT = 0x0200000,
+ DCA_XXCH_REAR_HIGH_CENTER = 0x0400000,
+ DCA_XXCH_REAR_HIGH_LEFT = 0x0800000,
+ DCA_XXCH_REAR_HIGH_RIGHT = 0x1000000,
+ DCA_XXCH_REAR_LOW_CENTER = 0x2000000,
+ DCA_XXCH_REAR_LOW_LEFT = 0x4000000,
+ DCA_XXCH_REAR_LOW_RIGHT = 0x8000000,
};
#define DCA_DOLBY 101 /* FIXME */
@@ -139,6 +112,7 @@ static const uint64_t dca_core_channel_layout[] = {
#define DCA_NSYNCAUX 0x9A1105A0
+
/** Bit allocation */
typedef struct BitAlloc {
int offset; ///< code values offset
@@ -159,6 +133,8 @@ static av_always_inline int get_bitalloc(GetBitContext *gb, BitAlloc *ba,
ba->offset;
}
+static float dca_dmix_code(unsigned code);
+
static av_cold void dca_init_vlcs(void)
{
static int vlcs_initialized = 0;
@@ -220,16 +196,103 @@ static inline void get_array(GetBitContext *gb, int *dst, int len, int bits)
*dst++ = get_bits(gb, bits);
}
-static int dca_parse_audio_coding_header(DCAContext *s, int base_channel)
+static inline int dca_xxch2index(DCAContext *s, int xxch_ch)
+{
+ int i, base, mask;
+
+ /* locate channel set containing the channel */
+ for (i = -1, base = 0, mask = (s->xxch_core_spkmask & ~DCA_XXCH_LFE1);
+ i <= s->xxch_chset && !(mask & xxch_ch); mask = s->xxch_spk_masks[++i])
+ base += av_popcount(mask);
+
+ return base + av_popcount(mask & (xxch_ch - 1));
+}
+
+static int dca_parse_audio_coding_header(DCAContext *s, int base_channel,
+ int xxch)
{
int i, j;
static const float adj_table[4] = { 1.0, 1.1250, 1.2500, 1.4375 };
static const int bitlen[11] = { 0, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3 };
static const int thr[11] = { 0, 1, 3, 3, 3, 3, 7, 7, 7, 7, 7 };
+ int hdr_pos = 0, hdr_size = 0;
+ float scale_factor;
+ int this_chans, acc_mask;
+ int embedded_downmix;
+ int nchans, mask[8];
+ int coeff, ichan;
+
+ /* xxch has arbitrary sized audio coding headers */
+ if (xxch) {
+ hdr_pos = get_bits_count(&s->gb);
+ hdr_size = get_bits(&s->gb, 7) + 1;
+ }
+
+ nchans = get_bits(&s->gb, 3) + 1;
+ if (xxch && nchans >= 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "nchans %d is too large\n", nchans);
+ return AVERROR_INVALIDDATA;
+ } else if (nchans + base_channel > DCA_PRIM_CHANNELS_MAX) {
+ av_log(s->avctx, AV_LOG_ERROR, "channel sum %d + %d is too large\n", nchans, base_channel);
+ return AVERROR_INVALIDDATA;
+ }
- s->total_channels = get_bits(&s->gb, 3) + 1 + base_channel;
+ s->total_channels = nchans + base_channel;
s->prim_channels = s->total_channels;
+ /* obtain speaker layout mask & downmix coefficients for XXCH */
+ if (xxch) {
+ acc_mask = s->xxch_core_spkmask;
+
+ this_chans = get_bits(&s->gb, s->xxch_nbits_spk_mask - 6) << 6;
+ s->xxch_spk_masks[s->xxch_chset] = this_chans;
+ s->xxch_chset_nch[s->xxch_chset] = nchans;
+
+ for (i = 0; i <= s->xxch_chset; i++)
+ acc_mask |= s->xxch_spk_masks[i];
+
+ /* check for downmixing information */
+ if (get_bits1(&s->gb)) {
+ embedded_downmix = get_bits1(&s->gb);
+ coeff = get_bits(&s->gb, 6);
+
+ if (coeff<1 || coeff>61) {
+ av_log(s->avctx, AV_LOG_ERROR, "6bit coeff %d is out of range\n", coeff);
+ return AVERROR_INVALIDDATA;
+ }
+
+ scale_factor = -1.0f / dca_dmix_code((coeff<<2)-3);
+
+ s->xxch_dmix_sf[s->xxch_chset] = scale_factor;
+
+ for (i = base_channel; i < s->prim_channels; i++) {
+ mask[i] = get_bits(&s->gb, s->xxch_nbits_spk_mask);
+ }
+
+ for (j = base_channel; j < s->prim_channels; j++) {
+ memset(s->xxch_dmix_coeff[j], 0, sizeof(s->xxch_dmix_coeff[0]));
+ s->xxch_dmix_embedded |= (embedded_downmix << j);
+ for (i = 0; i < s->xxch_nbits_spk_mask; i++) {
+ if (mask[j] & (1 << i)) {
+ if ((1 << i) == DCA_XXCH_LFE1) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "DCA-XXCH: dmix to LFE1 not supported.\n");
+ continue;
+ }
+
+ coeff = get_bits(&s->gb, 7);
+ ichan = dca_xxch2index(s, 1 << i);
+ if ((coeff&63)<1 || (coeff&63)>61) {
+ av_log(s->avctx, AV_LOG_ERROR, "7bit coeff %d is out of range\n", coeff);
+ return AVERROR_INVALIDDATA;
+ }
+ s->xxch_dmix_coeff[j][ichan] = dca_dmix_code((coeff<<2)-3);
+ }
+ }
+ }
+ }
+ }
+
if (s->prim_channels > DCA_PRIM_CHANNELS_MAX)
s->prim_channels = DCA_PRIM_CHANNELS_MAX;
@@ -265,9 +328,16 @@ static int dca_parse_audio_coding_header(DCAContext *s, int base_channel)
if (s->quant_index_huffman[i][j] < thr[j])
s->scalefactor_adj[i][j] = adj_table[get_bits(&s->gb, 2)];
- if (s->crc_present) {
- /* Audio header CRC check */
- get_bits(&s->gb, 16);
+ if (!xxch) {
+ if (s->crc_present) {
+ /* Audio header CRC check */
+ get_bits(&s->gb, 16);
+ }
+ } else {
+ /* Skip to the end of the header, also ignore CRC if present */
+ i = get_bits_count(&s->gb);
+ if (hdr_pos + 8 * hdr_size > i)
+ skip_bits_long(&s->gb, hdr_pos + 8 * hdr_size - i);
}
s->current_subframe = 0;
@@ -312,6 +382,7 @@ static int dca_parse_frame_header(DCAContext *s)
s->predictor_history = get_bits(&s->gb, 1);
if (s->lfe > 2) {
+ s->lfe = 0;
av_log(s->avctx, AV_LOG_ERROR, "Invalid LFE value: %d\n", s->lfe);
return AVERROR_INVALIDDATA;
}
@@ -336,7 +407,7 @@ static int dca_parse_frame_header(DCAContext *s)
/* Primary audio coding header */
s->subframes = get_bits(&s->gb, 4) + 1;
- return dca_parse_audio_coding_header(s, 0);
+ return dca_parse_audio_coding_header(s, 0, 0);
}
static inline int get_scale(GetBitContext *gb, int level, int value, int log2range)
@@ -366,6 +437,10 @@ static int dca_subframe_header(DCAContext *s, int base_channel, int block_index)
if (!base_channel) {
s->subsubframes[s->current_subframe] = get_bits(&s->gb, 2) + 1;
+ if (block_index + s->subsubframes[s->current_subframe] > s->sample_blocks/8) {
+ s->subsubframes[s->current_subframe] = 1;
+ return AVERROR_INVALIDDATA;
+ }
s->partial_samples[s->current_subframe] = get_bits(&s->gb, 3);
}
@@ -511,6 +586,7 @@ static int dca_subframe_header(DCAContext *s, int base_channel, int block_index)
/* Low frequency effect data */
if (!base_channel && s->lfe) {
+ int quant7;
/* LFE samples */
int lfe_samples = 2 * s->lfe * (4 + block_index);
int lfe_end_sample = 2 * s->lfe * (4 + block_index + s->subsubframes[s->current_subframe]);
@@ -522,8 +598,12 @@ static int dca_subframe_header(DCAContext *s, int base_channel, int block_index)
}
/* Scale factor index */
- skip_bits(&s->gb, 1);
- s->lfe_scale_factor = ff_dca_scale_factor_quant7[get_bits(&s->gb, 7)];
+ quant7 = get_bits(&s->gb, 8);
+ if (quant7 > 127) {
+ avpriv_request_sample(s->avctx, "LFEScaleIndex larger than 127");
+ return AVERROR_INVALIDDATA;
+ }
+ s->lfe_scale_factor = ff_dca_scale_factor_quant7[quant7];
/* Quantization step size * scale factor */
lfe_scale = 0.035 * s->lfe_scale_factor;
@@ -701,7 +781,7 @@ static void dca_downmix(float **samples, int srcfmt, int lfe_present,
switch (srcfmt) {
case DCA_MONO:
case DCA_4F2R:
- av_log(NULL, 0, "Not implemented!\n");
+ av_log(NULL, AV_LOG_ERROR, "Not implemented!\n");
break;
case DCA_CHANNEL:
case DCA_STEREO:
@@ -893,7 +973,7 @@ static int dca_subsubframe(DCAContext *s, int base_channel, int block_index)
else if (s->predictor_history)
sum += ff_dca_adpcm_vb[s->prediction_vq[k][l]][n - 1] *
s->subband_samples_hist[k][l][m - n + 4];
- subband_samples[k][l][m] += sum * 1.0f / 8192;
+ subband_samples[k][l][m] += sum * (1.0f / 8192);
}
}
}
@@ -902,7 +982,7 @@ static int dca_subsubframe(DCAContext *s, int base_channel, int block_index)
* Decode VQ encoded high frequencies
*/
if (s->subband_activity[k] > s->vq_start_subband[k]) {
- if (!s->debug_flag & 0x01) {
+ if (!(s->debug_flag & 0x01)) {
av_log(s->avctx, AV_LOG_DEBUG,
"Stream with high frequencies VQ coding\n");
s->debug_flag |= 0x01;
@@ -962,7 +1042,7 @@ static int dca_filter_channels(DCAContext *s, int block_index, int upsample)
/* Generate LFE samples for this subsubframe FIXME!!! */
if (s->lfe) {
- float *samples = s->samples_chanptr[ff_dca_lfe_index[s->amode]];
+ float *samples = s->samples_chanptr[s->lfe_index];
lfe_interpolation_fir(s,
s->lfe_data + 2 * s->lfe * (block_index + 4),
samples);
@@ -970,7 +1050,7 @@ static int dca_filter_channels(DCAContext *s, int block_index, int upsample)
unsigned i;
/* Should apply the filter in Table 6-11 when upsampling. For
* now, just duplicate. */
- for (i = 511; i > 0; i--) {
+ for (i = 255; i > 0; i--) {
samples[2 * i] =
samples[2 * i + 1] = samples[i];
}
@@ -1135,11 +1215,242 @@ static int dca_decode_block(DCAContext *s, int base_channel, int block_index)
return 0;
}
+int ff_dca_xbr_parse_frame(DCAContext *s)
+{
+ int scale_table_high[DCA_CHSET_CHANS_MAX][DCA_SUBBANDS][2];
+ int active_bands[DCA_CHSETS_MAX][DCA_CHSET_CHANS_MAX];
+ int abits_high[DCA_CHSET_CHANS_MAX][DCA_SUBBANDS];
+ int anctemp[DCA_CHSET_CHANS_MAX];
+ int chset_fsize[DCA_CHSETS_MAX];
+ int n_xbr_ch[DCA_CHSETS_MAX];
+ int hdr_size, num_chsets, xbr_tmode, hdr_pos;
+ int i, j, k, l, chset, chan_base;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "DTS-XBR: decoding XBR extension\n");
+
+ /* get bit position of sync header */
+ hdr_pos = get_bits_count(&s->gb) - 32;
+
+ hdr_size = get_bits(&s->gb, 6) + 1;
+ num_chsets = get_bits(&s->gb, 2) + 1;
+
+ for(i = 0; i < num_chsets; i++)
+ chset_fsize[i] = get_bits(&s->gb, 14) + 1;
+
+ xbr_tmode = get_bits1(&s->gb);
+
+ for(i = 0; i < num_chsets; i++) {
+ n_xbr_ch[i] = get_bits(&s->gb, 3) + 1;
+ k = get_bits(&s->gb, 2) + 5;
+ for(j = 0; j < n_xbr_ch[i]; j++) {
+ active_bands[i][j] = get_bits(&s->gb, k) + 1;
+ if (active_bands[i][j] > DCA_SUBBANDS) {
+ av_log(s->avctx, AV_LOG_ERROR, "too many active subbands (%d)\n", active_bands[i][j]);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+
+ /* skip to the end of the header */
+ i = get_bits_count(&s->gb);
+ if(hdr_pos + hdr_size * 8 > i)
+ skip_bits_long(&s->gb, hdr_pos + hdr_size * 8 - i);
+
+ /* loop over the channel data sets */
+ /* only decode as many channels as we've decoded base data for */
+ for(chset = 0, chan_base = 0;
+ chset < num_chsets && chan_base + n_xbr_ch[chset] <= s->prim_channels;
+ chan_base += n_xbr_ch[chset++]) {
+ int start_posn = get_bits_count(&s->gb);
+ int subsubframe = 0;
+ int subframe = 0;
+
+ /* loop over subframes */
+ for (k = 0; k < (s->sample_blocks / 8); k++) {
+ /* parse header if we're on first subsubframe of a block */
+ if(subsubframe == 0) {
+ /* Parse subframe header */
+ for(i = 0; i < n_xbr_ch[chset]; i++) {
+ anctemp[i] = get_bits(&s->gb, 2) + 2;
+ }
+
+ for(i = 0; i < n_xbr_ch[chset]; i++) {
+ get_array(&s->gb, abits_high[i], active_bands[chset][i], anctemp[i]);
+ }
+
+ for(i = 0; i < n_xbr_ch[chset]; i++) {
+ anctemp[i] = get_bits(&s->gb, 3);
+ if(anctemp[i] < 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "DTS-XBR: SYNC ERROR\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ /* generate scale factors */
+ for(i = 0; i < n_xbr_ch[chset]; i++) {
+ const uint32_t *scale_table;
+ int nbits;
+ int scale_table_size;
+
+ if (s->scalefactor_huffman[chan_base+i] == 6) {
+ scale_table = ff_dca_scale_factor_quant7;
+ scale_table_size = FF_ARRAY_ELEMS(ff_dca_scale_factor_quant7);
+ } else {
+ scale_table = ff_dca_scale_factor_quant6;
+ scale_table_size = FF_ARRAY_ELEMS(ff_dca_scale_factor_quant6);
+ }
+
+ nbits = anctemp[i];
+
+ for(j = 0; j < active_bands[chset][i]; j++) {
+ if(abits_high[i][j] > 0) {
+ int index = get_bits(&s->gb, nbits);
+ if (index >= scale_table_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "scale table index %d invalid\n", index);
+ return AVERROR_INVALIDDATA;
+ }
+ scale_table_high[i][j][0] = scale_table[index];
+
+ if(xbr_tmode && s->transition_mode[i][j]) {
+ int index = get_bits(&s->gb, nbits);
+ if (index >= scale_table_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "scale table index %d invalid\n", index);
+ return AVERROR_INVALIDDATA;
+ }
+ scale_table_high[i][j][1] = scale_table[index];
+ }
+ }
+ }
+ }
+ }
+
+ /* decode audio array for this block */
+ for(i = 0; i < n_xbr_ch[chset]; i++) {
+ for(j = 0; j < active_bands[chset][i]; j++) {
+ const int xbr_abits = abits_high[i][j];
+ const float quant_step_size = ff_dca_lossless_quant_d[xbr_abits];
+ const int sfi = xbr_tmode && s->transition_mode[i][j] && subsubframe >= s->transition_mode[i][j];
+ const float rscale = quant_step_size * scale_table_high[i][j][sfi];
+ float *subband_samples = s->subband_samples[k][chan_base+i][j];
+ int block[8];
+
+ if(xbr_abits <= 0)
+ continue;
+
+ if(xbr_abits > 7) {
+ get_array(&s->gb, block, 8, xbr_abits - 3);
+ } else {
+ int block_code1, block_code2, size, levels, err;
+
+ size = abits_sizes[xbr_abits - 1];
+ levels = abits_levels[xbr_abits - 1];
+
+ block_code1 = get_bits(&s->gb, size);
+ block_code2 = get_bits(&s->gb, size);
+ err = decode_blockcodes(block_code1, block_code2,
+ levels, block);
+ if (err) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "ERROR: DTS-XBR: block code look-up failed\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ /* scale & sum into subband */
+ for(l = 0; l < 8; l++)
+ subband_samples[l] += (float)block[l] * rscale;
+ }
+ }
+
+ /* check DSYNC marker */
+ if(s->aspf || subsubframe == s->subsubframes[subframe] - 1) {
+ if(get_bits(&s->gb, 16) != 0xffff) {
+ av_log(s->avctx, AV_LOG_ERROR, "DTS-XBR: Didn't get subframe DSYNC\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ /* advance sub-sub-frame index */
+ if(++subsubframe >= s->subsubframes[subframe]) {
+ subsubframe = 0;
+ subframe++;
+ }
+ }
+
+ /* skip to next channel set */
+ i = get_bits_count(&s->gb);
+ if(start_posn + chset_fsize[chset] * 8 != i) {
+ j = start_posn + chset_fsize[chset] * 8 - i;
+ if(j < 0 || j >= 8)
+ av_log(s->avctx, AV_LOG_ERROR, "DTS-XBR: end of channel set,"
+ " skipping further than expected (%d bits)\n", j);
+ skip_bits_long(&s->gb, j);
+ }
+ }
+
+ return 0;
+}
+
+
+/* parse initial header for XXCH and dump details */
+int ff_dca_xxch_decode_frame(DCAContext *s)
+{
+ int hdr_size, spkmsk_bits, num_chsets, core_spk, hdr_pos;
+ int i, chset, base_channel, chstart, fsize[8];
+
+ /* assume header word has already been parsed */
+ hdr_pos = get_bits_count(&s->gb) - 32;
+ hdr_size = get_bits(&s->gb, 6) + 1;
+ /*chhdr_crc =*/ skip_bits1(&s->gb);
+ spkmsk_bits = get_bits(&s->gb, 5) + 1;
+ num_chsets = get_bits(&s->gb, 2) + 1;
+
+ for (i = 0; i < num_chsets; i++)
+ fsize[i] = get_bits(&s->gb, 14) + 1;
+
+ core_spk = get_bits(&s->gb, spkmsk_bits);
+ s->xxch_core_spkmask = core_spk;
+ s->xxch_nbits_spk_mask = spkmsk_bits;
+ s->xxch_dmix_embedded = 0;
+
+ /* skip to the end of the header */
+ i = get_bits_count(&s->gb);
+ if (hdr_pos + hdr_size * 8 > i)
+ skip_bits_long(&s->gb, hdr_pos + hdr_size * 8 - i);
+
+ for (chset = 0; chset < num_chsets; chset++) {
+ chstart = get_bits_count(&s->gb);
+ base_channel = s->prim_channels;
+ s->xxch_chset = chset;
+
+ /* XXCH and Core headers differ, see 6.4.2 "XXCH Channel Set Header" vs.
+ 5.3.2 "Primary Audio Coding Header", DTS Spec 1.3.1 */
+ dca_parse_audio_coding_header(s, base_channel, 1);
+
+ /* decode channel data */
+ for (i = 0; i < (s->sample_blocks / 8); i++) {
+ if (dca_decode_block(s, base_channel, i)) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Error decoding DTS-XXCH extension\n");
+ continue;
+ }
+ }
+
+ /* skip to end of this section */
+ i = get_bits_count(&s->gb);
+ if (chstart + fsize[chset] * 8 > i)
+ skip_bits_long(&s->gb, chstart + fsize[chset] * 8 - i);
+ }
+ s->xxch_chset = num_chsets;
+
+ return 0;
+}
+
static float dca_dmix_code(unsigned code)
{
int sign = (code >> 8) - 1;
code &= 0xff;
- return ((ff_dca_dmixtable[code] ^ sign) - sign) * (1.0 / (1U << 15));
+ return ((ff_dca_dmixtable[code] ^ sign) - sign) * (1.0 / (1 << 15));
}
/**
@@ -1152,21 +1463,35 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
AVFrame *frame = data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
-
+ int channel_mask;
+ int channel_layout;
int lfe_samples;
int num_core_channels = 0;
int i, ret;
- float **samples_flt;
+ float **samples_flt;
+ float *src_chan;
+ float *dst_chan;
DCAContext *s = avctx->priv_data;
- int channels, full_channels;
int core_ss_end;
+ int channels, full_channels;
+ float scale;
+ int achan;
+ int chset;
+ int mask;
+ int lavc;
+ int posn;
+ int j, k;
+ int endch;
int upsample = 0;
s->exss_ext_mask = 0;
s->xch_present = 0;
- s->dca_buffer_size = ff_dca_convert_bitstream(buf, buf_size, s->dca_buffer,
- DCA_MAX_FRAME_SIZE + DCA_MAX_EXSS_HEADER_SIZE);
+ s->dca_buffer_size = AVERROR_INVALIDDATA;
+ for (i = 0; i < buf_size - 3 && s->dca_buffer_size == AVERROR_INVALIDDATA; i++)
+ s->dca_buffer_size = avpriv_dca_convert_bitstream(buf + i, buf_size - i, s->dca_buffer,
+ DCA_MAX_FRAME_SIZE + DCA_MAX_EXSS_HEADER_SIZE);
+
if (s->dca_buffer_size == AVERROR_INVALIDDATA) {
av_log(avctx, AV_LOG_ERROR, "Not a valid DCA frame\n");
return AVERROR_INVALIDDATA;
@@ -1178,7 +1503,6 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
}
// set AVCodec values with parsed data
avctx->sample_rate = s->sample_rate;
- avctx->bit_rate = s->bit_rate;
s->profile = FF_PROFILE_DTS;
@@ -1192,8 +1516,51 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
/* record number of core channels incase less than max channels are requested */
num_core_channels = s->prim_channels;
+ if (s->prim_channels + !!s->lfe > 2 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
+ /* Stereo downmix coefficients
+ *
+ * The decoder can only downmix to 2-channel, so we need to ensure
+ * embedded downmix coefficients are actually targeting 2-channel.
+ */
+ if (s->core_downmix && (s->core_downmix_amode == DCA_STEREO ||
+ s->core_downmix_amode == DCA_STEREO_TOTAL)) {
+ for (i = 0; i < num_core_channels + !!s->lfe; i++) {
+ /* Range checked earlier */
+ s->downmix_coef[i][0] = dca_dmix_code(s->core_downmix_codes[i][0]);
+ s->downmix_coef[i][1] = dca_dmix_code(s->core_downmix_codes[i][1]);
+ }
+ s->output = s->core_downmix_amode;
+ } else {
+ int am = s->amode & DCA_CHANNEL_MASK;
+ if (am >= FF_ARRAY_ELEMS(ff_dca_default_coeffs)) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Invalid channel mode %d\n", am);
+ return AVERROR_INVALIDDATA;
+ }
+ if (num_core_channels + !!s->lfe >
+ FF_ARRAY_ELEMS(ff_dca_default_coeffs[0])) {
+ avpriv_request_sample(s->avctx, "Downmixing %d channels",
+ s->prim_channels + !!s->lfe);
+ return AVERROR_PATCHWELCOME;
+ }
+ for (i = 0; i < num_core_channels + !!s->lfe; i++) {
+ s->downmix_coef[i][0] = ff_dca_default_coeffs[am][i][0];
+ s->downmix_coef[i][1] = ff_dca_default_coeffs[am][i][1];
+ }
+ }
+ ff_dlog(s->avctx, "Stereo downmix coeffs:\n");
+ for (i = 0; i < num_core_channels + !!s->lfe; i++) {
+ ff_dlog(s->avctx, "L, input channel %d = %f\n", i,
+ s->downmix_coef[i][0]);
+ ff_dlog(s->avctx, "R, input channel %d = %f\n", i,
+ s->downmix_coef[i][1]);
+ }
+ ff_dlog(s->avctx, "\n");
+ }
+
if (s->ext_coding)
- s->core_ext_mask = dca_ext_audio_descr_mask[s->ext_descr];
+ s->core_ext_mask = ff_dca_ext_audio_descr_mask[s->ext_descr];
else
s->core_ext_mask = 0;
@@ -1201,7 +1568,7 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
/* only scan for extensions if ext_descr was unknown or indicated a
* supported XCh extension */
- if (s->core_ext_mask < 0 || s->core_ext_mask & DCA_EXT_XCH) {
+ if (s->core_ext_mask < 0 || s->core_ext_mask & (DCA_EXT_XCH | DCA_EXT_XXCH)) {
/* if ext_descr was unknown, clear s->core_ext_mask so that the
* extensions scan can fill it up */
s->core_ext_mask = FFMAX(s->core_ext_mask, 0);
@@ -1238,8 +1605,13 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
continue;
}
+ if (s->xch_base_channel < 2) {
+ avpriv_request_sample(avctx, "XCh with fewer than 2 base channels");
+ continue;
+ }
+
/* much like core primary audio coding header */
- dca_parse_audio_coding_header(s, s->xch_base_channel);
+ dca_parse_audio_coding_header(s, s->xch_base_channel, 0);
for (i = 0; i < (s->sample_blocks / 8); i++)
if ((ret = dca_decode_block(s, s->xch_base_channel, i))) {
@@ -1255,6 +1627,7 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
/* usually found either in core or HD part in DTS-HD HRA streams,
* but not in DTS-ES which contains XCh extensions instead */
s->core_ext_mask |= DCA_EXT_XXCH;
+ ff_dca_xxch_decode_frame(s);
break;
case 0x1d95f262: {
@@ -1294,100 +1667,147 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data,
full_channels = channels = s->prim_channels + !!s->lfe;
- if (s->amode < 16) {
- avctx->channel_layout = dca_core_channel_layout[s->amode];
-
- if (s->prim_channels + !!s->lfe > 2 &&
- avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
- /*
- * Neither the core's auxiliary data nor our default tables contain
- * downmix coefficients for the additional channel coded in the XCh
- * extension, so when we're doing a Stereo downmix, don't decode it.
- */
- s->xch_disable = 1;
- }
+ /* If we have XXCH then the channel layout is managed differently */
+ /* note that XLL will also have another way to do things */
+ if (!(s->core_ext_mask & DCA_EXT_XXCH)
+ || (s->core_ext_mask & DCA_EXT_XXCH && avctx->request_channels > 0
+ && avctx->request_channels
+ < num_core_channels + !!s->lfe + s->xxch_chset_nch[0]))
+ { /* xxx should also do MA extensions */
+ if (s->amode < 16) {
+ avctx->channel_layout = ff_dca_core_channel_layout[s->amode];
+
+ if (s->prim_channels + !!s->lfe > 2 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
+ /*
+ * Neither the core's auxiliary data nor our default tables contain
+ * downmix coefficients for the additional channel coded in the XCh
+ * extension, so when we're doing a Stereo downmix, don't decode it.
+ */
+ s->xch_disable = 1;
+ }
#if FF_API_REQUEST_CHANNELS
FF_DISABLE_DEPRECATION_WARNINGS
- if (s->xch_present && !s->xch_disable &&
- (!avctx->request_channels ||
- avctx->request_channels > num_core_channels + !!s->lfe)) {
+ if (s->xch_present && !s->xch_disable &&
+ (!avctx->request_channels ||
+ avctx->request_channels > num_core_channels + !!s->lfe)) {
FF_ENABLE_DEPRECATION_WARNINGS
#else
- if (s->xch_present && !s->xch_disable) {
+ if (s->xch_present && !s->xch_disable) {
#endif
- avctx->channel_layout |= AV_CH_BACK_CENTER;
- if (s->lfe) {
- avctx->channel_layout |= AV_CH_LOW_FREQUENCY;
- s->channel_order_tab = ff_dca_channel_reorder_lfe_xch[s->amode];
+ if (avctx->channel_layout & AV_CH_BACK_CENTER) {
+ avpriv_request_sample(avctx, "XCh with Back center channel");
+ return AVERROR_INVALIDDATA;
+ }
+ avctx->channel_layout |= AV_CH_BACK_CENTER;
+ if (s->lfe) {
+ avctx->channel_layout |= AV_CH_LOW_FREQUENCY;
+ s->channel_order_tab = ff_dca_channel_reorder_lfe_xch[s->amode];
+ } else {
+ s->channel_order_tab = ff_dca_channel_reorder_nolfe_xch[s->amode];
+ }
+ if (s->channel_order_tab[s->xch_base_channel] < 0)
+ return AVERROR_INVALIDDATA;
} else {
- s->channel_order_tab = ff_dca_channel_reorder_nolfe_xch[s->amode];
+ channels = num_core_channels + !!s->lfe;
+ s->xch_present = 0; /* disable further xch processing */
+ if (s->lfe) {
+ avctx->channel_layout |= AV_CH_LOW_FREQUENCY;
+ s->channel_order_tab = ff_dca_channel_reorder_lfe[s->amode];
+ } else
+ s->channel_order_tab = ff_dca_channel_reorder_nolfe[s->amode];
+ }
+
+ if (channels > !!s->lfe &&
+ s->channel_order_tab[channels - 1 - !!s->lfe] < 0)
+ return AVERROR_INVALIDDATA;
+
+ if (av_get_channel_layout_nb_channels(avctx->channel_layout) != channels) {
+ av_log(avctx, AV_LOG_ERROR, "Number of channels %d mismatches layout %d\n", channels, av_get_channel_layout_nb_channels(avctx->channel_layout));
+ return AVERROR_INVALIDDATA;
}
+
+ if (num_core_channels + !!s->lfe > 2 &&
+ avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
+ channels = 2;
+ s->output = s->prim_channels == 2 ? s->amode : DCA_STEREO;
+ avctx->channel_layout = AV_CH_LAYOUT_STEREO;
+ }
+ else if (avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE) {
+ static const int8_t dca_channel_order_native[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+ s->channel_order_tab = dca_channel_order_native;
+ }
+ s->lfe_index = ff_dca_lfe_index[s->amode];
} else {
- channels = num_core_channels + !!s->lfe;
- s->xch_present = 0; /* disable further xch processing */
- if (s->lfe) {
- avctx->channel_layout |= AV_CH_LOW_FREQUENCY;
- s->channel_order_tab = ff_dca_channel_reorder_lfe[s->amode];
- } else
- s->channel_order_tab = ff_dca_channel_reorder_nolfe[s->amode];
+ av_log(avctx, AV_LOG_ERROR,
+ "Non standard configuration %d !\n", s->amode);
+ return AVERROR_INVALIDDATA;
}
- if (channels > !!s->lfe &&
- s->channel_order_tab[channels - 1 - !!s->lfe] < 0)
- return AVERROR_INVALIDDATA;
+ s->xxch_dmix_embedded = 0;
+ } else {
+ /* we only get here if an XXCH channel set can be added to the mix */
+ channel_mask = s->xxch_core_spkmask;
+
+ if (avctx->request_channels > 0
+ && avctx->request_channels < s->prim_channels) {
+ channels = num_core_channels + !!s->lfe;
+ for (i = 0; i < s->xxch_chset && channels + s->xxch_chset_nch[i]
+ <= avctx->request_channels; i++) {
+ channels += s->xxch_chset_nch[i];
+ channel_mask |= s->xxch_spk_masks[i];
+ }
+ } else {
+ channels = s->prim_channels + !!s->lfe;
+ for (i = 0; i < s->xxch_chset; i++) {
+ channel_mask |= s->xxch_spk_masks[i];
+ }
+ }
- if (num_core_channels + !!s->lfe > 2 &&
- avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) {
- channels = 2;
- s->output = s->prim_channels == 2 ? s->amode : DCA_STEREO;
- avctx->channel_layout = AV_CH_LAYOUT_STEREO;
+ /* Given the DTS spec'ed channel mask, generate an avcodec version */
+ channel_layout = 0;
+ for (i = 0; i < s->xxch_nbits_spk_mask; ++i) {
+ if (channel_mask & (1 << i)) {
+ channel_layout |= ff_dca_map_xxch_to_native[i];
+ }
+ }
- /* Stereo downmix coefficients
- *
- * The decoder can only downmix to 2-channel, so we need to ensure
- * embedded downmix coefficients are actually targeting 2-channel.
- */
- if (s->core_downmix && (s->core_downmix_amode == DCA_STEREO ||
- s->core_downmix_amode == DCA_STEREO_TOTAL)) {
- for (i = 0; i < num_core_channels + !!s->lfe; i++) {
- /* Range checked earlier */
- s->downmix_coef[i][0] = dca_dmix_code(s->core_downmix_codes[i][0]);
- s->downmix_coef[i][1] = dca_dmix_code(s->core_downmix_codes[i][1]);
- }
- s->output = s->core_downmix_amode;
- } else {
- int am = s->amode & DCA_CHANNEL_MASK;
- if (am >= FF_ARRAY_ELEMS(ff_dca_default_coeffs)) {
- av_log(s->avctx, AV_LOG_ERROR,
- "Invalid channel mode %d\n", am);
- return AVERROR_INVALIDDATA;
- }
- if (num_core_channels + !!s->lfe >
- FF_ARRAY_ELEMS(ff_dca_default_coeffs[0])) {
- avpriv_request_sample(s->avctx, "Downmixing %d channels",
- s->prim_channels + !!s->lfe);
- return AVERROR_PATCHWELCOME;
- }
- for (i = 0; i < num_core_channels + !!s->lfe; i++) {
- s->downmix_coef[i][0] = ff_dca_default_coeffs[am][i][0];
- s->downmix_coef[i][1] = ff_dca_default_coeffs[am][i][1];
+ /* make sure that we have managed to get equivalent dts/avcodec channel
+ * masks in some sense -- unfortunately some channels could overlap */
+ if (av_popcount(channel_mask) != av_popcount(channel_layout)) {
+ av_log(avctx, AV_LOG_DEBUG,
+ "DTS-XXCH: Inconsistent avcodec/dts channel layouts\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avctx->channel_layout = channel_layout;
+
+ if (!(avctx->request_channel_layout & AV_CH_LAYOUT_NATIVE)) {
+ /* Estimate DTS --> avcodec ordering table */
+ for (chset = -1, j = 0; chset < s->xxch_chset; ++chset) {
+ mask = chset >= 0 ? s->xxch_spk_masks[chset]
+ : s->xxch_core_spkmask;
+ for (i = 0; i < s->xxch_nbits_spk_mask; i++) {
+ if (mask & ~(DCA_XXCH_LFE1 | DCA_XXCH_LFE2) & (1 << i)) {
+ lavc = ff_dca_map_xxch_to_native[i];
+ posn = av_popcount(channel_layout & (lavc - 1));
+ s->xxch_order_tab[j++] = posn;
+ }
}
+
}
- ff_dlog(s->avctx, "Stereo downmix coeffs:\n");
- for (i = 0; i < num_core_channels + !!s->lfe; i++) {
- ff_dlog(s->avctx, "L, input channel %d = %f\n", i,
- s->downmix_coef[i][0]);
- ff_dlog(s->avctx, "R, input channel %d = %f\n", i,
- s->downmix_coef[i][1]);
- }
- ff_dlog(s->avctx, "\n");
+
+ s->lfe_index = av_popcount(channel_layout & (AV_CH_LOW_FREQUENCY-1));
+ } else { /* native ordering */
+ for (i = 0; i < channels; i++)
+ s->xxch_order_tab[i] = i;
+
+ s->lfe_index = channels - 1;
}
- } else {
- av_log(avctx, AV_LOG_ERROR, "Non standard configuration %d !\n", s->amode);
- return AVERROR_INVALIDDATA;
+
+ s->channel_order_tab = s->xxch_order_tab;
}
- avctx->channels = channels;
/* get output buffer */
frame->nb_samples = 256 * (s->sample_blocks / 8);
@@ -1418,20 +1838,24 @@ FF_ENABLE_DEPRECATION_WARNINGS
/* If downmixing to stereo, don't decode additional channels.
* FIXME: Using the xch_disable flag for this doesn't seem right. */
if (!s->xch_disable)
- avctx->channels += s->xll_channels - s->xll_residual_channels;
+ channels = s->xll_channels;
}
}
+ if (avctx->channels != channels) {
+ if (avctx->channels)
+ av_log(avctx, AV_LOG_INFO, "Number of channels changed in DCA decoder (%d -> %d)\n", avctx->channels, channels);
+ avctx->channels = channels;
+ }
+
/* FIXME: This is an ugly hack, to just revert to the default
* layout if we have additional channels. Need to convert the XLL
- * channel masks to libav channel_layout mask. */
+ * channel masks to ffmpeg channel_layout mask. */
if (av_get_channel_layout_nb_channels(avctx->channel_layout) != avctx->channels)
avctx->channel_layout = 0;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples_flt = (float **) frame->extended_data;
/* allocate buffer for extra channels if downmixing */
@@ -1472,8 +1896,55 @@ FF_ENABLE_DEPRECATION_WARNINGS
float *back_chan = s->samples_chanptr[s->channel_order_tab[s->xch_base_channel]];
float *lt_chan = s->samples_chanptr[s->channel_order_tab[s->xch_base_channel - 2]];
float *rt_chan = s->samples_chanptr[s->channel_order_tab[s->xch_base_channel - 1]];
- s->fdsp.vector_fmac_scalar(lt_chan, back_chan, -M_SQRT1_2, 256);
- s->fdsp.vector_fmac_scalar(rt_chan, back_chan, -M_SQRT1_2, 256);
+ s->fdsp->vector_fmac_scalar(lt_chan, back_chan, -M_SQRT1_2, 256);
+ s->fdsp->vector_fmac_scalar(rt_chan, back_chan, -M_SQRT1_2, 256);
+ }
+
+ /* If stream contains XXCH, we might need to undo an embedded downmix */
+ if (s->xxch_dmix_embedded) {
+ /* Loop over channel sets in turn */
+ ch = num_core_channels;
+ for (chset = 0; chset < s->xxch_chset; chset++) {
+ endch = ch + s->xxch_chset_nch[chset];
+ mask = s->xxch_dmix_embedded;
+
+ /* undo downmix */
+ for (j = ch; j < endch; j++) {
+ if (mask & (1 << j)) { /* this channel has been mixed-out */
+ src_chan = s->samples_chanptr[s->channel_order_tab[j]];
+ for (k = 0; k < endch; k++) {
+ achan = s->channel_order_tab[k];
+ scale = s->xxch_dmix_coeff[j][k];
+ if (scale != 0.0) {
+ dst_chan = s->samples_chanptr[achan];
+ s->fdsp->vector_fmac_scalar(dst_chan, src_chan,
+ -scale, 256);
+ }
+ }
+ }
+ }
+
+ /* if a downmix has been embedded then undo the pre-scaling */
+ if ((mask & (1 << ch)) && s->xxch_dmix_sf[chset] != 1.0f) {
+ scale = s->xxch_dmix_sf[chset];
+
+ for (j = 0; j < ch; j++) {
+ src_chan = s->samples_chanptr[s->channel_order_tab[j]];
+ for (k = 0; k < 256; k++)
+ src_chan[k] *= scale;
+ }
+
+ /* LFE channel is always part of core, scale if it exists */
+ if (s->lfe) {
+ src_chan = s->samples_chanptr[s->lfe_index];
+ for (k = 0; k < 256; k++)
+ src_chan[k] *= scale;
+ }
+ }
+
+ ch = endch;
+ }
+
}
}
@@ -1496,6 +1967,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (ret < 0)
return ret;
+ if ( avctx->profile != FF_PROFILE_DTS_HD_MA
+ && avctx->profile != FF_PROFILE_DTS_HD_HRA)
+ avctx->bit_rate = s->bit_rate;
*got_frame_ptr = 1;
return buf_size;
@@ -1514,7 +1988,10 @@ static av_cold int dca_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
dca_init_vlcs();
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
+
ff_mdct_init(&s->imdct, 6, 1, 1.0);
ff_synth_filter_init(&s->synth);
ff_dcadsp_init(&s->dcadsp);
@@ -1541,6 +2018,7 @@ static av_cold int dca_decode_end(AVCodecContext *avctx)
DCAContext *s = avctx->priv_data;
ff_mdct_end(&s->imdct);
av_freep(&s->extra_channels_buffer);
+ av_freep(&s->fdsp);
av_freep(&s->xll_sample_buf);
av_freep(&s->qmf64_table);
return 0;
@@ -1566,6 +2044,7 @@ static const AVClass dca_decoder_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DECODER,
};
AVCodec ff_dca_decoder = {
diff --git a/libavcodec/dcadsp.c b/libavcodec/dcadsp.c
index 34b5da2d24..b32d962c33 100644
--- a/libavcodec/dcadsp.c
+++ b/libavcodec/dcadsp.c
@@ -2,20 +2,20 @@
* Copyright (c) 2004 Gildas Bazin
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dcadsp.h b/libavcodec/dcadsp.h
index 0fa75a5ed6..abf577b61f 100644
--- a/libavcodec/dcadsp.h
+++ b/libavcodec/dcadsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,7 +22,7 @@
#include "avfft.h"
#include "synth_filter.h"
-#define DCA_SUBBANDS 32
+#define DCA_SUBBANDS 64
typedef struct DCADSPContext {
void (*lfe_fir[2])(float *out, const float *in, const float *coefs);
diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c
new file mode 100644
index 0000000000..c8a215c200
--- /dev/null
+++ b/libavcodec/dcaenc.c
@@ -0,0 +1,974 @@
+/*
+ * DCA encoder
+ * Copyright (C) 2008-2012 Alexander E. Patrakov
+ * 2010 Benjamin Larsson
+ * 2011 Xiang 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
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/common.h"
+#include "avcodec.h"
+#include "dca.h"
+#include "dcadata.h"
+#include "dcaenc.h"
+#include "internal.h"
+#include "mathops.h"
+#include "put_bits.h"
+
+#define MAX_CHANNELS 6
+#define DCA_MAX_FRAME_SIZE 16384
+#define DCA_HEADER_SIZE 13
+#define DCA_LFE_SAMPLES 8
+
+#define DCAENC_SUBBANDS 32
+#define SUBFRAMES 1
+#define SUBSUBFRAMES 2
+#define SUBBAND_SAMPLES (SUBFRAMES * SUBSUBFRAMES * 8)
+#define AUBANDS 25
+
+typedef struct DCAEncContext {
+ PutBitContext pb;
+ int frame_size;
+ int frame_bits;
+ int fullband_channels;
+ int channels;
+ int lfe_channel;
+ int samplerate_index;
+ int bitrate_index;
+ int channel_config;
+ const int32_t *band_interpolation;
+ const int32_t *band_spectrum;
+ int lfe_scale_factor;
+ softfloat lfe_quant;
+ int32_t lfe_peak_cb;
+
+ int32_t history[512][MAX_CHANNELS]; /* This is a circular buffer */
+ int32_t subband[SUBBAND_SAMPLES][DCAENC_SUBBANDS][MAX_CHANNELS];
+ int32_t quantized[SUBBAND_SAMPLES][DCAENC_SUBBANDS][MAX_CHANNELS];
+ int32_t peak_cb[DCAENC_SUBBANDS][MAX_CHANNELS];
+ int32_t downsampled_lfe[DCA_LFE_SAMPLES];
+ int32_t masking_curve_cb[SUBSUBFRAMES][256];
+ int abits[DCAENC_SUBBANDS][MAX_CHANNELS];
+ int scale_factor[DCAENC_SUBBANDS][MAX_CHANNELS];
+ softfloat quant[DCAENC_SUBBANDS][MAX_CHANNELS];
+ int32_t eff_masking_curve_cb[256];
+ int32_t band_masking_cb[32];
+ int32_t worst_quantization_noise;
+ int32_t worst_noise_ever;
+ int consumed_bits;
+} DCAEncContext;
+
+static int32_t cos_table[2048];
+static int32_t band_interpolation[2][512];
+static int32_t band_spectrum[2][8];
+static int32_t auf[9][AUBANDS][256];
+static int32_t cb_to_add[256];
+static int32_t cb_to_level[2048];
+static int32_t lfe_fir_64i[512];
+
+/* Transfer function of outer and middle ear, Hz -> dB */
+static double hom(double f)
+{
+ double f1 = f / 1000;
+
+ return -3.64 * pow(f1, -0.8)
+ + 6.8 * exp(-0.6 * (f1 - 3.4) * (f1 - 3.4))
+ - 6.0 * exp(-0.15 * (f1 - 8.7) * (f1 - 8.7))
+ - 0.0006 * (f1 * f1) * (f1 * f1);
+}
+
+static double gammafilter(int i, double f)
+{
+ double h = (f - fc[i]) / erb[i];
+
+ h = 1 + h * h;
+ h = 1 / (h * h);
+ return 20 * log10(h);
+}
+
+static int encode_init(AVCodecContext *avctx)
+{
+ DCAEncContext *c = avctx->priv_data;
+ uint64_t layout = avctx->channel_layout;
+ int i, min_frame_bits;
+
+ c->fullband_channels = c->channels = avctx->channels;
+ c->lfe_channel = (avctx->channels == 3 || avctx->channels == 6);
+ c->band_interpolation = band_interpolation[1];
+ c->band_spectrum = band_spectrum[1];
+ c->worst_quantization_noise = -2047;
+ c->worst_noise_ever = -2047;
+
+ if (!layout) {
+ av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The "
+ "encoder will guess the layout, but it "
+ "might be incorrect.\n");
+ layout = av_get_default_channel_layout(avctx->channels);
+ }
+ switch (layout) {
+ case AV_CH_LAYOUT_MONO: c->channel_config = 0; break;
+ case AV_CH_LAYOUT_STEREO: c->channel_config = 2; break;
+ case AV_CH_LAYOUT_2_2: c->channel_config = 8; break;
+ case AV_CH_LAYOUT_5POINT0: c->channel_config = 9; break;
+ case AV_CH_LAYOUT_5POINT1: c->channel_config = 9; break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported channel layout!\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (c->lfe_channel)
+ c->fullband_channels--;
+
+ for (i = 0; i < 9; i++) {
+ if (sample_rates[i] == avctx->sample_rate)
+ break;
+ }
+ if (i == 9)
+ return AVERROR(EINVAL);
+ c->samplerate_index = i;
+
+ if (avctx->bit_rate < 32000 || avctx->bit_rate > 3840000) {
+ av_log(avctx, AV_LOG_ERROR, "Bit rate %i not supported.", avctx->bit_rate);
+ return AVERROR(EINVAL);
+ }
+ for (i = 0; ff_dca_bit_rates[i] < avctx->bit_rate; i++)
+ ;
+ c->bitrate_index = i;
+ avctx->bit_rate = ff_dca_bit_rates[i];
+ c->frame_bits = FFALIGN((avctx->bit_rate * 512 + avctx->sample_rate - 1) / avctx->sample_rate, 32);
+ min_frame_bits = 132 + (493 + 28 * 32) * c->fullband_channels + c->lfe_channel * 72;
+ if (c->frame_bits < min_frame_bits || c->frame_bits > (DCA_MAX_FRAME_SIZE << 3))
+ return AVERROR(EINVAL);
+
+ c->frame_size = (c->frame_bits + 7) / 8;
+
+ avctx->frame_size = 32 * SUBBAND_SAMPLES;
+
+ if (!cos_table[0]) {
+ int j, k;
+
+ for (i = 0; i < 2048; i++) {
+ cos_table[i] = (int32_t)(0x7fffffff * cos(M_PI * i / 1024));
+ cb_to_level[i] = (int32_t)(0x7fffffff * pow(10, -0.005 * i));
+ }
+
+ /* FIXME: probably incorrect */
+ for (i = 0; i < 256; i++) {
+ lfe_fir_64i[i] = (int32_t)(0x01ffffff * ff_dca_lfe_fir_64[i]);
+ lfe_fir_64i[511 - i] = (int32_t)(0x01ffffff * ff_dca_lfe_fir_64[i]);
+ }
+
+ for (i = 0; i < 512; i++) {
+ band_interpolation[0][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_perfect[i]);
+ band_interpolation[1][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_nonperfect[i]);
+ }
+
+ for (i = 0; i < 9; i++) {
+ for (j = 0; j < AUBANDS; j++) {
+ for (k = 0; k < 256; k++) {
+ double freq = sample_rates[i] * (k + 0.5) / 512;
+
+ auf[i][j][k] = (int32_t)(10 * (hom(freq) + gammafilter(j, freq)));
+ }
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ double add = 1 + pow(10, -0.01 * i);
+ cb_to_add[i] = (int32_t)(100 * log10(add));
+ }
+ for (j = 0; j < 8; j++) {
+ double accum = 0;
+ for (i = 0; i < 512; i++) {
+ double reconst = ff_dca_fir_32bands_perfect[i] * ((i & 64) ? (-1) : 1);
+ accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512);
+ }
+ band_spectrum[0][j] = (int32_t)(200 * log10(accum));
+ }
+ for (j = 0; j < 8; j++) {
+ double accum = 0;
+ for (i = 0; i < 512; i++) {
+ double reconst = ff_dca_fir_32bands_nonperfect[i] * ((i & 64) ? (-1) : 1);
+ accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512);
+ }
+ band_spectrum[1][j] = (int32_t)(200 * log10(accum));
+ }
+ }
+ return 0;
+}
+
+static inline int32_t cos_t(int x)
+{
+ return cos_table[x & 2047];
+}
+
+static inline int32_t sin_t(int x)
+{
+ return cos_t(x - 512);
+}
+
+static inline int32_t half32(int32_t a)
+{
+ return (a + 1) >> 1;
+}
+
+static inline int32_t mul32(int32_t a, int32_t b)
+{
+ int64_t r = (int64_t)a * b + 0x80000000ULL;
+ return r >> 32;
+}
+
+static void subband_transform(DCAEncContext *c, const int32_t *input)
+{
+ int ch, subs, i, k, j;
+
+ for (ch = 0; ch < c->fullband_channels; ch++) {
+ /* History is copied because it is also needed for PSY */
+ int32_t hist[512];
+ int hist_start = 0;
+
+ for (i = 0; i < 512; i++)
+ hist[i] = c->history[i][ch];
+
+ for (subs = 0; subs < SUBBAND_SAMPLES; subs++) {
+ int32_t accum[64];
+ int32_t resp;
+ int band;
+
+ /* Calculate the convolutions at once */
+ for (i = 0; i < 64; i++)
+ accum[i] = 0;
+
+ for (k = 0, i = hist_start, j = 0;
+ i < 512; k = (k + 1) & 63, i++, j++)
+ accum[k] += mul32(hist[i], c->band_interpolation[j]);
+ for (i = 0; i < hist_start; k = (k + 1) & 63, i++, j++)
+ accum[k] += mul32(hist[i], c->band_interpolation[j]);
+
+ for (k = 16; k < 32; k++)
+ accum[k] = accum[k] - accum[31 - k];
+ for (k = 32; k < 48; k++)
+ accum[k] = accum[k] + accum[95 - k];
+
+ for (band = 0; band < 32; band++) {
+ resp = 0;
+ for (i = 16; i < 48; i++) {
+ int s = (2 * band + 1) * (2 * (i + 16) + 1);
+ resp += mul32(accum[i], cos_t(s << 3)) >> 3;
+ }
+
+ c->subband[subs][band][ch] = ((band + 1) & 2) ? -resp : resp;
+ }
+
+ /* Copy in 32 new samples from input */
+ for (i = 0; i < 32; i++)
+ hist[i + hist_start] = input[(subs * 32 + i) * c->channels + ch];
+ hist_start = (hist_start + 32) & 511;
+ }
+ }
+}
+
+static void lfe_downsample(DCAEncContext *c, const int32_t *input)
+{
+ /* FIXME: make 128x LFE downsampling possible */
+ int i, j, lfes;
+ int32_t hist[512];
+ int32_t accum;
+ int hist_start = 0;
+
+ for (i = 0; i < 512; i++)
+ hist[i] = c->history[i][c->channels - 1];
+
+ for (lfes = 0; lfes < DCA_LFE_SAMPLES; lfes++) {
+ /* Calculate the convolution */
+ accum = 0;
+
+ for (i = hist_start, j = 0; i < 512; i++, j++)
+ accum += mul32(hist[i], lfe_fir_64i[j]);
+ for (i = 0; i < hist_start; i++, j++)
+ accum += mul32(hist[i], lfe_fir_64i[j]);
+
+ c->downsampled_lfe[lfes] = accum;
+
+ /* Copy in 64 new samples from input */
+ for (i = 0; i < 64; i++)
+ hist[i + hist_start] = input[(lfes * 64 + i) * c->channels + c->channels - 1];
+
+ hist_start = (hist_start + 64) & 511;
+ }
+}
+
+typedef struct {
+ int32_t re;
+ int32_t im;
+} cplx32;
+
+static void fft(const int32_t in[2 * 256], cplx32 out[256])
+{
+ cplx32 buf[256], rin[256], rout[256];
+ int i, j, k, l;
+
+ /* do two transforms in parallel */
+ for (i = 0; i < 256; i++) {
+ /* Apply the Hann window */
+ rin[i].re = mul32(in[2 * i], 0x3fffffff - (cos_t(8 * i + 2) >> 1));
+ rin[i].im = mul32(in[2 * i + 1], 0x3fffffff - (cos_t(8 * i + 6) >> 1));
+ }
+ /* pre-rotation */
+ for (i = 0; i < 256; i++) {
+ buf[i].re = mul32(cos_t(4 * i + 2), rin[i].re)
+ - mul32(sin_t(4 * i + 2), rin[i].im);
+ buf[i].im = mul32(cos_t(4 * i + 2), rin[i].im)
+ + mul32(sin_t(4 * i + 2), rin[i].re);
+ }
+
+ for (j = 256, l = 1; j != 1; j >>= 1, l <<= 1) {
+ for (k = 0; k < 256; k += j) {
+ for (i = k; i < k + j / 2; i++) {
+ cplx32 sum, diff;
+ int t = 8 * l * i;
+
+ sum.re = buf[i].re + buf[i + j / 2].re;
+ sum.im = buf[i].im + buf[i + j / 2].im;
+
+ diff.re = buf[i].re - buf[i + j / 2].re;
+ diff.im = buf[i].im - buf[i + j / 2].im;
+
+ buf[i].re = half32(sum.re);
+ buf[i].im = half32(sum.im);
+
+ buf[i + j / 2].re = mul32(diff.re, cos_t(t))
+ - mul32(diff.im, sin_t(t));
+ buf[i + j / 2].im = mul32(diff.im, cos_t(t))
+ + mul32(diff.re, sin_t(t));
+ }
+ }
+ }
+ /* post-rotation */
+ for (i = 0; i < 256; i++) {
+ int b = ff_reverse[i];
+ rout[i].re = mul32(buf[b].re, cos_t(4 * i))
+ - mul32(buf[b].im, sin_t(4 * i));
+ rout[i].im = mul32(buf[b].im, cos_t(4 * i))
+ + mul32(buf[b].re, sin_t(4 * i));
+ }
+ for (i = 0; i < 256; i++) {
+ /* separate the results of the two transforms */
+ cplx32 o1, o2;
+
+ o1.re = rout[i].re - rout[255 - i].re;
+ o1.im = rout[i].im + rout[255 - i].im;
+
+ o2.re = rout[i].im - rout[255 - i].im;
+ o2.im = -rout[i].re - rout[255 - i].re;
+
+ /* combine them into one long transform */
+ out[i].re = mul32( o1.re + o2.re, cos_t(2 * i + 1))
+ + mul32( o1.im - o2.im, sin_t(2 * i + 1));
+ out[i].im = mul32( o1.im + o2.im, cos_t(2 * i + 1))
+ + mul32(-o1.re + o2.re, sin_t(2 * i + 1));
+ }
+}
+
+static int32_t get_cb(int32_t in)
+{
+ int i, res;
+
+ res = 0;
+ if (in < 0)
+ in = -in;
+ for (i = 1024; i > 0; i >>= 1) {
+ if (cb_to_level[i + res] >= in)
+ res += i;
+ }
+ return -res;
+}
+
+static int32_t add_cb(int32_t a, int32_t b)
+{
+ if (a < b)
+ FFSWAP(int32_t, a, b);
+
+ if (a - b >= 256)
+ return a;
+ return a + cb_to_add[a - b];
+}
+
+static void adjust_jnd(int samplerate_index,
+ const int32_t in[512], int32_t out_cb[256])
+{
+ int32_t power[256];
+ cplx32 out[256];
+ int32_t out_cb_unnorm[256];
+ int32_t denom;
+ const int32_t ca_cb = -1114;
+ const int32_t cs_cb = 928;
+ int i, j;
+
+ fft(in, out);
+
+ for (j = 0; j < 256; j++) {
+ power[j] = add_cb(get_cb(out[j].re), get_cb(out[j].im));
+ out_cb_unnorm[j] = -2047; /* and can only grow */
+ }
+
+ for (i = 0; i < AUBANDS; i++) {
+ denom = ca_cb; /* and can only grow */
+ for (j = 0; j < 256; j++)
+ denom = add_cb(denom, power[j] + auf[samplerate_index][i][j]);
+ for (j = 0; j < 256; j++)
+ out_cb_unnorm[j] = add_cb(out_cb_unnorm[j],
+ -denom + auf[samplerate_index][i][j]);
+ }
+
+ for (j = 0; j < 256; j++)
+ out_cb[j] = add_cb(out_cb[j], -out_cb_unnorm[j] - ca_cb - cs_cb);
+}
+
+typedef void (*walk_band_t)(DCAEncContext *c, int band1, int band2, int f,
+ int32_t spectrum1, int32_t spectrum2, int channel,
+ int32_t * arg);
+
+static void walk_band_low(DCAEncContext *c, int band, int channel,
+ walk_band_t walk, int32_t *arg)
+{
+ int f;
+
+ if (band == 0) {
+ for (f = 0; f < 4; f++)
+ walk(c, 0, 0, f, 0, -2047, channel, arg);
+ } else {
+ for (f = 0; f < 8; f++)
+ walk(c, band, band - 1, 8 * band - 4 + f,
+ c->band_spectrum[7 - f], c->band_spectrum[f], channel, arg);
+ }
+}
+
+static void walk_band_high(DCAEncContext *c, int band, int channel,
+ walk_band_t walk, int32_t *arg)
+{
+ int f;
+
+ if (band == 31) {
+ for (f = 0; f < 4; f++)
+ walk(c, 31, 31, 256 - 4 + f, 0, -2047, channel, arg);
+ } else {
+ for (f = 0; f < 8; f++)
+ walk(c, band, band + 1, 8 * band + 4 + f,
+ c->band_spectrum[f], c->band_spectrum[7 - f], channel, arg);
+ }
+}
+
+static void update_band_masking(DCAEncContext *c, int band1, int band2,
+ int f, int32_t spectrum1, int32_t spectrum2,
+ int channel, int32_t * arg)
+{
+ int32_t value = c->eff_masking_curve_cb[f] - spectrum1;
+
+ if (value < c->band_masking_cb[band1])
+ c->band_masking_cb[band1] = value;
+}
+
+static void calc_masking(DCAEncContext *c, const int32_t *input)
+{
+ int i, k, band, ch, ssf;
+ int32_t data[512];
+
+ for (i = 0; i < 256; i++)
+ for (ssf = 0; ssf < SUBSUBFRAMES; ssf++)
+ c->masking_curve_cb[ssf][i] = -2047;
+
+ for (ssf = 0; ssf < SUBSUBFRAMES; ssf++)
+ for (ch = 0; ch < c->fullband_channels; ch++) {
+ for (i = 0, k = 128 + 256 * ssf; k < 512; i++, k++)
+ data[i] = c->history[k][ch];
+ for (k -= 512; i < 512; i++, k++)
+ data[i] = input[k * c->channels + ch];
+ adjust_jnd(c->samplerate_index, data, c->masking_curve_cb[ssf]);
+ }
+ for (i = 0; i < 256; i++) {
+ int32_t m = 2048;
+
+ for (ssf = 0; ssf < SUBSUBFRAMES; ssf++)
+ if (c->masking_curve_cb[ssf][i] < m)
+ m = c->masking_curve_cb[ssf][i];
+ c->eff_masking_curve_cb[i] = m;
+ }
+
+ for (band = 0; band < 32; band++) {
+ c->band_masking_cb[band] = 2048;
+ walk_band_low(c, band, 0, update_band_masking, NULL);
+ walk_band_high(c, band, 0, update_band_masking, NULL);
+ }
+}
+
+static void find_peaks(DCAEncContext *c)
+{
+ int band, ch;
+
+ for (band = 0; band < 32; band++)
+ for (ch = 0; ch < c->fullband_channels; ch++) {
+ int sample;
+ int32_t m = 0;
+
+ for (sample = 0; sample < SUBBAND_SAMPLES; sample++) {
+ int32_t s = abs(c->subband[sample][band][ch]);
+ if (m < s)
+ m = s;
+ }
+ c->peak_cb[band][ch] = get_cb(m);
+ }
+
+ if (c->lfe_channel) {
+ int sample;
+ int32_t m = 0;
+
+ for (sample = 0; sample < DCA_LFE_SAMPLES; sample++)
+ if (m < abs(c->downsampled_lfe[sample]))
+ m = abs(c->downsampled_lfe[sample]);
+ c->lfe_peak_cb = get_cb(m);
+ }
+}
+
+static const int snr_fudge = 128;
+#define USED_1ABITS 1
+#define USED_NABITS 2
+#define USED_26ABITS 4
+
+static int init_quantization_noise(DCAEncContext *c, int noise)
+{
+ int ch, band, ret = 0;
+
+ c->consumed_bits = 132 + 493 * c->fullband_channels;
+ if (c->lfe_channel)
+ c->consumed_bits += 72;
+
+ /* attempt to guess the bit distribution based on the prevoius frame */
+ for (ch = 0; ch < c->fullband_channels; ch++) {
+ for (band = 0; band < 32; band++) {
+ int snr_cb = c->peak_cb[band][ch] - c->band_masking_cb[band] - noise;
+
+ if (snr_cb >= 1312) {
+ c->abits[band][ch] = 26;
+ ret |= USED_26ABITS;
+ } else if (snr_cb >= 222) {
+ c->abits[band][ch] = 8 + mul32(snr_cb - 222, 69000000);
+ ret |= USED_NABITS;
+ } else if (snr_cb >= 0) {
+ c->abits[band][ch] = 2 + mul32(snr_cb, 106000000);
+ ret |= USED_NABITS;
+ } else {
+ c->abits[band][ch] = 1;
+ ret |= USED_1ABITS;
+ }
+ }
+ }
+
+ for (band = 0; band < 32; band++)
+ for (ch = 0; ch < c->fullband_channels; ch++) {
+ c->consumed_bits += bit_consumption[c->abits[band][ch]];
+ }
+
+ return ret;
+}
+
+static void assign_bits(DCAEncContext *c)
+{
+ /* Find the bounds where the binary search should work */
+ int low, high, down;
+ int used_abits = 0;
+
+ init_quantization_noise(c, c->worst_quantization_noise);
+ low = high = c->worst_quantization_noise;
+ if (c->consumed_bits > c->frame_bits) {
+ while (c->consumed_bits > c->frame_bits) {
+ av_assert0(used_abits != USED_1ABITS);
+ low = high;
+ high += snr_fudge;
+ used_abits = init_quantization_noise(c, high);
+ }
+ } else {
+ while (c->consumed_bits <= c->frame_bits) {
+ high = low;
+ if (used_abits == USED_26ABITS)
+ goto out; /* The requested bitrate is too high, pad with zeros */
+ low -= snr_fudge;
+ used_abits = init_quantization_noise(c, low);
+ }
+ }
+
+ /* Now do a binary search between low and high to see what fits */
+ for (down = snr_fudge >> 1; down; down >>= 1) {
+ init_quantization_noise(c, high - down);
+ if (c->consumed_bits <= c->frame_bits)
+ high -= down;
+ }
+ init_quantization_noise(c, high);
+out:
+ c->worst_quantization_noise = high;
+ if (high > c->worst_noise_ever)
+ c->worst_noise_ever = high;
+}
+
+static void shift_history(DCAEncContext *c, const int32_t *input)
+{
+ int k, ch;
+
+ for (k = 0; k < 512; k++)
+ for (ch = 0; ch < c->channels; ch++)
+ c->history[k][ch] = input[k * c->channels + ch];
+}
+
+static int32_t quantize_value(int32_t value, softfloat quant)
+{
+ int32_t offset = 1 << (quant.e - 1);
+
+ value = mul32(value, quant.m) + offset;
+ value = value >> quant.e;
+ return value;
+}
+
+static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant)
+{
+ int32_t peak;
+ int our_nscale, try_remove;
+ softfloat our_quant;
+
+ av_assert0(peak_cb <= 0);
+ av_assert0(peak_cb >= -2047);
+
+ our_nscale = 127;
+ peak = cb_to_level[-peak_cb];
+
+ for (try_remove = 64; try_remove > 0; try_remove >>= 1) {
+ if (scalefactor_inv[our_nscale - try_remove].e + stepsize_inv[abits].e <= 17)
+ continue;
+ our_quant.m = mul32(scalefactor_inv[our_nscale - try_remove].m, stepsize_inv[abits].m);
+ our_quant.e = scalefactor_inv[our_nscale - try_remove].e + stepsize_inv[abits].e - 17;
+ if ((quant_levels[abits] - 1) / 2 < quantize_value(peak, our_quant))
+ continue;
+ our_nscale -= try_remove;
+ }
+
+ if (our_nscale >= 125)
+ our_nscale = 124;
+
+ quant->m = mul32(scalefactor_inv[our_nscale].m, stepsize_inv[abits].m);
+ quant->e = scalefactor_inv[our_nscale].e + stepsize_inv[abits].e - 17;
+ av_assert0((quant_levels[abits] - 1) / 2 >= quantize_value(peak, *quant));
+
+ return our_nscale;
+}
+
+static void calc_scales(DCAEncContext *c)
+{
+ int band, ch;
+
+ for (band = 0; band < 32; band++)
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ c->scale_factor[band][ch] = calc_one_scale(c->peak_cb[band][ch],
+ c->abits[band][ch],
+ &c->quant[band][ch]);
+
+ if (c->lfe_channel)
+ c->lfe_scale_factor = calc_one_scale(c->lfe_peak_cb, 11, &c->lfe_quant);
+}
+
+static void quantize_all(DCAEncContext *c)
+{
+ int sample, band, ch;
+
+ for (sample = 0; sample < SUBBAND_SAMPLES; sample++)
+ for (band = 0; band < 32; band++)
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ c->quantized[sample][band][ch] = quantize_value(c->subband[sample][band][ch], c->quant[band][ch]);
+}
+
+static void put_frame_header(DCAEncContext *c)
+{
+ /* SYNC */
+ put_bits(&c->pb, 16, 0x7ffe);
+ put_bits(&c->pb, 16, 0x8001);
+
+ /* Frame type: normal */
+ put_bits(&c->pb, 1, 1);
+
+ /* Deficit sample count: none */
+ put_bits(&c->pb, 5, 31);
+
+ /* CRC is not present */
+ put_bits(&c->pb, 1, 0);
+
+ /* Number of PCM sample blocks */
+ put_bits(&c->pb, 7, SUBBAND_SAMPLES - 1);
+
+ /* Primary frame byte size */
+ put_bits(&c->pb, 14, c->frame_size - 1);
+
+ /* Audio channel arrangement */
+ put_bits(&c->pb, 6, c->channel_config);
+
+ /* Core audio sampling frequency */
+ put_bits(&c->pb, 4, bitstream_sfreq[c->samplerate_index]);
+
+ /* Transmission bit rate */
+ put_bits(&c->pb, 5, c->bitrate_index);
+
+ /* Embedded down mix: disabled */
+ put_bits(&c->pb, 1, 0);
+
+ /* Embedded dynamic range flag: not present */
+ put_bits(&c->pb, 1, 0);
+
+ /* Embedded time stamp flag: not present */
+ put_bits(&c->pb, 1, 0);
+
+ /* Auxiliary data flag: not present */
+ put_bits(&c->pb, 1, 0);
+
+ /* HDCD source: no */
+ put_bits(&c->pb, 1, 0);
+
+ /* Extension audio ID: N/A */
+ put_bits(&c->pb, 3, 0);
+
+ /* Extended audio data: not present */
+ put_bits(&c->pb, 1, 0);
+
+ /* Audio sync word insertion flag: after each sub-frame */
+ put_bits(&c->pb, 1, 0);
+
+ /* Low frequency effects flag: not present or 64x subsampling */
+ put_bits(&c->pb, 2, c->lfe_channel ? 2 : 0);
+
+ /* Predictor history switch flag: on */
+ put_bits(&c->pb, 1, 1);
+
+ /* No CRC */
+ /* Multirate interpolator switch: non-perfect reconstruction */
+ put_bits(&c->pb, 1, 0);
+
+ /* Encoder software revision: 7 */
+ put_bits(&c->pb, 4, 7);
+
+ /* Copy history: 0 */
+ put_bits(&c->pb, 2, 0);
+
+ /* Source PCM resolution: 16 bits, not DTS ES */
+ put_bits(&c->pb, 3, 0);
+
+ /* Front sum/difference coding: no */
+ put_bits(&c->pb, 1, 0);
+
+ /* Surrounds sum/difference coding: no */
+ put_bits(&c->pb, 1, 0);
+
+ /* Dialog normalization: 0 dB */
+ put_bits(&c->pb, 4, 0);
+}
+
+static void put_primary_audio_header(DCAEncContext *c)
+{
+ static const int bitlen[11] = { 0, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3 };
+ static const int thr[11] = { 0, 1, 3, 3, 3, 3, 7, 7, 7, 7, 7 };
+
+ int ch, i;
+ /* Number of subframes */
+ put_bits(&c->pb, 4, SUBFRAMES - 1);
+
+ /* Number of primary audio channels */
+ put_bits(&c->pb, 3, c->fullband_channels - 1);
+
+ /* Subband activity count */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 5, DCAENC_SUBBANDS - 2);
+
+ /* High frequency VQ start subband */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 5, DCAENC_SUBBANDS - 1);
+
+ /* Joint intensity coding index: 0, 0 */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 3, 0);
+
+ /* Transient mode codebook: A4, A4 (arbitrary) */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 2, 0);
+
+ /* Scale factor code book: 7 bit linear, 7-bit sqrt table (for each channel) */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 3, 6);
+
+ /* Bit allocation quantizer select: linear 5-bit */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, 3, 6);
+
+ /* Quantization index codebook select: dummy data
+ to avoid transmission of scale factor adjustment */
+ for (i = 1; i < 11; i++)
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ put_bits(&c->pb, bitlen[i], thr[i]);
+
+ /* Scale factor adjustment index: not transmitted */
+ /* Audio header CRC check word: not transmitted */
+}
+
+static void put_subframe_samples(DCAEncContext *c, int ss, int band, int ch)
+{
+ if (c->abits[band][ch] <= 7) {
+ int sum, i, j;
+ for (i = 0; i < 8; i += 4) {
+ sum = 0;
+ for (j = 3; j >= 0; j--) {
+ sum *= quant_levels[c->abits[band][ch]];
+ sum += c->quantized[ss * 8 + i + j][band][ch];
+ sum += (quant_levels[c->abits[band][ch]] - 1) / 2;
+ }
+ put_bits(&c->pb, bit_consumption[c->abits[band][ch]] / 4, sum);
+ }
+ } else {
+ int i;
+ for (i = 0; i < 8; i++) {
+ int bits = bit_consumption[c->abits[band][ch]] / 16;
+ put_sbits(&c->pb, bits, c->quantized[ss * 8 + i][band][ch]);
+ }
+ }
+}
+
+static void put_subframe(DCAEncContext *c, int subframe)
+{
+ int i, band, ss, ch;
+
+ /* Subsubframes count */
+ put_bits(&c->pb, 2, SUBSUBFRAMES -1);
+
+ /* Partial subsubframe sample count: dummy */
+ put_bits(&c->pb, 3, 0);
+
+ /* Prediction mode: no ADPCM, in each channel and subband */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ for (band = 0; band < DCAENC_SUBBANDS; band++)
+ put_bits(&c->pb, 1, 0);
+
+ /* Prediction VQ address: not transmitted */
+ /* Bit allocation index */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ for (band = 0; band < DCAENC_SUBBANDS; band++)
+ put_bits(&c->pb, 5, c->abits[band][ch]);
+
+ if (SUBSUBFRAMES > 1) {
+ /* Transition mode: none for each channel and subband */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ for (band = 0; band < DCAENC_SUBBANDS; band++)
+ put_bits(&c->pb, 1, 0); /* codebook A4 */
+ }
+
+ /* Scale factors */
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ for (band = 0; band < DCAENC_SUBBANDS; band++)
+ put_bits(&c->pb, 7, c->scale_factor[band][ch]);
+
+ /* Joint subband scale factor codebook select: not transmitted */
+ /* Scale factors for joint subband coding: not transmitted */
+ /* Stereo down-mix coefficients: not transmitted */
+ /* Dynamic range coefficient: not transmitted */
+ /* Stde information CRC check word: not transmitted */
+ /* VQ encoded high frequency subbands: not transmitted */
+
+ /* LFE data: 8 samples and scalefactor */
+ if (c->lfe_channel) {
+ for (i = 0; i < DCA_LFE_SAMPLES; i++)
+ put_bits(&c->pb, 8, quantize_value(c->downsampled_lfe[i], c->lfe_quant) & 0xff);
+ put_bits(&c->pb, 8, c->lfe_scale_factor);
+ }
+
+ /* Audio data (subsubframes) */
+ for (ss = 0; ss < SUBSUBFRAMES ; ss++)
+ for (ch = 0; ch < c->fullband_channels; ch++)
+ for (band = 0; band < DCAENC_SUBBANDS; band++)
+ put_subframe_samples(c, ss, band, ch);
+
+ /* DSYNC */
+ put_bits(&c->pb, 16, 0xffff);
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ DCAEncContext *c = avctx->priv_data;
+ const int32_t *samples;
+ int ret, i;
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, c->frame_size )) < 0)
+ return ret;
+
+ samples = (const int32_t *)frame->data[0];
+
+ subband_transform(c, samples);
+ if (c->lfe_channel)
+ lfe_downsample(c, samples);
+
+ calc_masking(c, samples);
+ find_peaks(c);
+ assign_bits(c);
+ calc_scales(c);
+ quantize_all(c);
+ shift_history(c, samples);
+
+ init_put_bits(&c->pb, avpkt->data, avpkt->size);
+ put_frame_header(c);
+ put_primary_audio_header(c);
+ for (i = 0; i < SUBFRAMES; i++)
+ put_subframe(c, i);
+
+ flush_put_bits(&c->pb);
+
+ avpkt->pts = frame->pts;
+ avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
+ avpkt->size = c->frame_size + 1;
+ *got_packet_ptr = 1;
+ return 0;
+}
+
+static const AVCodecDefault defaults[] = {
+ { "b", "1411200" },
+ { NULL },
+};
+
+AVCodec ff_dca_encoder = {
+ .name = "dca",
+ .long_name = NULL_IF_CONFIG_SMALL("DCA (DTS Coherent Acoustics)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_DTS,
+ .priv_data_size = sizeof(DCAEncContext),
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_NONE },
+ .supported_samplerates = sample_rates,
+ .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_2_2,
+ AV_CH_LAYOUT_5POINT0,
+ AV_CH_LAYOUT_5POINT1,
+ 0 },
+ .defaults = defaults,
+};
diff --git a/libavcodec/dcaenc.h b/libavcodec/dcaenc.h
new file mode 100644
index 0000000000..0443ca6511
--- /dev/null
+++ b/libavcodec/dcaenc.h
@@ -0,0 +1,113 @@
+/*
+ * DCA encoder tables
+ * Copyright (C) 2008-2012 Alexander E. Patrakov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_DCAENC_H
+#define AVCODEC_DCAENC_H
+
+#include <stdint.h>
+
+typedef struct {
+ int32_t m;
+ int32_t e;
+} softfloat;
+
+static const int sample_rates[] = {
+ 8000, 16000, 32000, 11025, 22050, 44100, 12000, 24000, 48000, 0,
+};
+
+static const uint8_t bitstream_sfreq[] = { 1, 2, 3, 6, 7, 8, 11, 12, 13 };
+
+/* Auditory filter center frequencies and bandwidths, in Hz.
+ * The last two are made up, because there is no scientific data.
+ */
+static const uint16_t fc[] = {
+ 50, 150, 250, 350, 450, 570, 700, 840, 1000, 1170, 1370, 1600, 1850, 2150,
+ 2500, 2900, 3400, 4000, 4800, 5800, 7000, 8500, 10500, 13500, 17000
+};
+
+static const uint16_t erb[] = {
+ 80, 100, 100, 100, 110, 120, 140, 150, 160, 190, 210, 240, 280,
+ 320, 380, 450, 550, 700, 900, 1100, 1300, 1800, 2500, 3500, 4500
+};
+
+static const softfloat stepsize_inv[27] = {
+ {0, 0}, {1342177360, 21}, {2147483647, 21}, {1342177360, 20},
+ {1819901661, 20}, {2147483647, 20}, {1278263843, 19}, {1579032492, 19},
+ {1412817763, 18}, {1220162327, 17}, {1118482133, 16}, {1917391412, 16},
+ {1766017772, 15}, {1525212826, 14}, {1290553940, 13}, {2097179000, 13},
+ {1677683200, 12}, {1497972244, 11}, {1310893147, 10}, {1165354136, 9},
+ {1748031204, 9}, {1542092044, 8}, {1636178017, 7}, {1636178017, 6},
+ {1636178017, 5}, {1636178017, 4}, {1636178017, 3},
+};
+
+static const softfloat scalefactor_inv[128] = {
+ {2147483647, 1}, {2147483647, 1}, {2147483647, 2}, {2147483647, 2},
+ {2147483647, 2}, {2147483647, 2}, {1431655765, 2}, {1431655765, 2},
+ {1431655765, 2}, {2147483647, 3}, {2147483647, 3}, {1717986918, 3},
+ {1431655765, 3}, {1227133513, 3}, {1227133513, 3}, {2147483647, 4},
+ {1717986918, 4}, {1561806289, 4}, {1431655765, 4}, {1227133513, 4},
+ {2147483647, 5}, {1908874353, 5}, {1717986918, 5}, {1493901668, 5},
+ {1321528398, 5}, {1145324612, 5}, {2021161080, 6}, {1808407282, 6},
+ {1561806289, 6}, {1374389534, 6}, {1227133513, 6}, {2147483647, 7},
+ {1908874353, 7}, {1676084798, 7}, {1477838209, 7}, {1296593900, 7},
+ {1145324612, 7}, {2021161080, 8}, {1773405851, 8}, {1561806289, 8},
+ {1374389534, 8}, {1216273924, 8}, {2139127680, 9}, {1882725390, 9},
+ {1660893697, 9}, {1462116526, 9}, {1287484341, 9}, {1135859119, 9},
+ {1999112050, 10}, {1762037865, 10}, {1552982525, 10}, {1367551775, 10},
+ {1205604855, 10}, {2124660150, 11}, {1871509153, 11}, {1648443220, 11},
+ {1452459217, 11}, {1279990253, 11}, {1127704233, 11}, {1987368509, 12},
+ {1750814693, 12}, {1542632939, 12}, {1359099663, 12}, {1197398995, 12},
+ {2109880792, 13}, {1858853132, 13}, {1638006149, 13}, {1443165385, 13},
+ {1271479187, 13}, {1120235993, 13}, {1973767086, 14}, {1739045674, 14},
+ {1532153461, 14}, {1349922194, 14}, {1189384493, 14}, {2095804865, 15},
+ {1846464029, 15}, {1626872524, 15}, {1433347133, 15}, {1262853884, 15},
+ {1112619678, 15}, {1960569045, 16}, {1727349015, 16}, {1521881227, 16},
+ {1340842289, 16}, {1181357555, 16}, {2081669156, 17}, {1834047752, 17},
+ {1615889229, 17}, {1423675973, 17}, {1254322457, 17}, {1105123583, 17},
+ {1947330755, 18}, {1715693602, 18}, {1511607799, 18}, {1331801790, 18},
+ {1173384427, 18}, {2067616532, 19}, {1821667648, 19}, {1604980024, 19},
+ {1414066955, 19}, {1245861410, 19}, {1097665748, 19}, {1934193616, 20},
+ {1704119624, 20}, {1501412075, 20}, {1322817107, 20}, {1165466323, 20},
+ {2053666205, 21}, {1809379407, 21}, {1594151671, 21}, {1404526328, 21},
+ {1237455941, 21}, {1090259329, 21}, {1921143210, 22}, {1692621231, 22},
+ {1491281857, 22}, {1313892269, 22}, {1157603482, 22}, {2039810470, 23},
+ {1797172644, 23}, {1583396912, 23}, {1395050052, 23}, {1229107276, 23},
+ {1082903494, 23}, {1082903494, 23}, {1082903494, 23}, {1082903494, 23},
+};
+
+/* manually derived from
+ * Table B.5: Selection of quantization levels and codebooks
+ * FIXME: will become invalid when Huffman codes are introduced.
+ */
+static const int bit_consumption[27] = {
+ -8, 28, 40, 48, 52, 60, 68, 76, 80, 96,
+ 112, 128, 144, 160, 176, 192, 208, 224, 240, 256,
+ 272, 288, 304, 320, 336, 352, 368,
+};
+
+/* Table B.5: Selection of quantization levels and codebooks */
+static const int quant_levels[27] = {
+ 1, 3, 5, 7, 9, 13, 17, 25, 32, 64,
+ 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
+ 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
+};
+
+#endif /* AVCODEC_DCAENC_H */
diff --git a/libavcodec/dcahuff.h b/libavcodec/dcahuff.h
index 79be4938e2..9388b636a7 100644
--- a/libavcodec/dcahuff.h
+++ b/libavcodec/dcahuff.h
@@ -3,20 +3,20 @@
* Copyright (C) 2004 Gildas Bazin
* Copyright (C) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dct-test.c b/libavcodec/dct-test.c
index d3233f310e..56e1a629a7 100644
--- a/libavcodec/dct-test.c
+++ b/libavcodec/dct-test.c
@@ -2,20 +2,20 @@
* (c) 2001 Fabrice Bellard
* 2007 Marc Hoffman <marc.hoffman@analog.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,10 +65,24 @@ static const struct algo fdct_tab[] = {
#endif /* CONFIG_FAANDCT */
};
+static void ff_prores_idct_wrap(int16_t *dst){
+ LOCAL_ALIGNED(16, int16_t, qmat, [64]);
+ int i;
+
+ for(i=0; i<64; i++){
+ qmat[i]=4;
+ }
+ ff_prores_idct(dst, qmat);
+ for(i=0; i<64; i++) {
+ dst[i] -= 512;
+ }
+}
+
static const struct algo idct_tab[] = {
{ "REF-DBL", ff_ref_idct, FF_IDCT_PERM_NONE },
{ "INT", ff_j_rev_dct, FF_IDCT_PERM_LIBMPEG2 },
{ "SIMPLE-C", ff_simple_idct_8, FF_IDCT_PERM_NONE },
+ { "PR-C", ff_prores_idct_wrap, FF_IDCT_PERM_NONE, 0, 1 },
#if CONFIG_FAANIDCT
{ "FAANI", ff_faanidct, FF_IDCT_PERM_NONE },
#endif /* CONFIG_FAANIDCT */
@@ -96,7 +110,7 @@ static const struct algo idct_tab_arch[] = { { 0 } };
DECLARE_ALIGNED(16, static int16_t, block)[64];
DECLARE_ALIGNED(8, static int16_t, block1)[64];
-static void init_block(int16_t block[64], int test, int is_idct, AVLFG *prng)
+static void init_block(int16_t block[64], int test, int is_idct, AVLFG *prng, int vals)
{
int i, j;
@@ -105,7 +119,7 @@ static void init_block(int16_t block[64], int test, int is_idct, AVLFG *prng)
switch (test) {
case 0:
for (i = 0; i < 64; i++)
- block[i] = (av_lfg_get(prng) % 512) - 256;
+ block[i] = (av_lfg_get(prng) % (2*vals)) -vals;
if (is_idct) {
ff_ref_fdct(block);
for (i = 0; i < 64; i++)
@@ -114,11 +128,13 @@ static void init_block(int16_t block[64], int test, int is_idct, AVLFG *prng)
break;
case 1:
j = av_lfg_get(prng) % 10 + 1;
- for (i = 0; i < j; i++)
- block[av_lfg_get(prng) % 64] = av_lfg_get(prng) % 512 - 256;
+ for (i = 0; i < j; i++) {
+ int idx = av_lfg_get(prng) % 64;
+ block[idx] = av_lfg_get(prng) % (2*vals) -vals;
+ }
break;
case 2:
- block[ 0] = av_lfg_get(prng) % 4096 - 2048;
+ block[ 0] = av_lfg_get(prng) % (16*vals) - (8*vals);
block[63] = (block[0] & 1) ^ 1;
break;
}
@@ -143,6 +159,10 @@ static void permute(int16_t dst[64], const int16_t src[64],
for (i = 0; i < 64; i++)
dst[(i & 0x24) | ((i & 3) << 3) | ((i >> 3) & 3)] = src[i];
break;
+ case FF_IDCT_PERM_TRANSPOSE:
+ for (i = 0; i < 64; i++)
+ dst[(i>>3) | ((i<<3)&0x38)] = src[i];
+ break;
default:
for (i = 0; i < 64; i++)
dst[i] = src[i];
@@ -150,7 +170,7 @@ static void permute(int16_t dst[64], const int16_t src[64],
}
}
-static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
+static int dct_error(const struct algo *dct, int test, int is_idct, int speed, const int bits)
{
void (*ref)(int16_t *block) = is_idct ? ff_ref_idct : ff_ref_fdct;
int it, i, scale;
@@ -160,6 +180,7 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
int maxout = 0;
int blockSumErrMax = 0, blockSumErr;
AVLFG prng;
+ const int vals=1<<bits;
double omse, ome;
int spec_err;
@@ -170,7 +191,7 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
for (i = 0; i < 64; i++)
sysErr[i] = 0;
for (it = 0; it < NB_ITS; it++) {
- init_block(block1, test, is_idct, &prng);
+ init_block(block1, test, is_idct, &prng, vals);
permute(block, block1, dct->perm_type);
dct->func(block);
@@ -184,6 +205,9 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
}
ref(block1);
+ if (!strcmp(dct->name, "PR-SSE2"))
+ for (i = 0; i < 64; i++)
+ block1[i] = av_clip(block1[i], 4-512, 1019-512);
blockSumErr = 0;
for (i = 0; i < 64; i++) {
@@ -216,7 +240,7 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
spec_err = is_idct && (err_inf > 1 || omse > 0.02 || fabs(ome) > 0.0015);
- printf("%s %s: ppe=%d omse=%0.8f ome=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
+ printf("%s %s: max_err=%d omse=%0.8f ome=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
is_idct ? "IDCT" : "DCT", dct->name, err_inf,
omse, ome, (double) sysErrMax / NB_ITS,
maxout, blockSumErrMax);
@@ -228,7 +252,8 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
return 0;
/* speed test */
- init_block(block, test, is_idct, &prng);
+
+ init_block(block, test, is_idct, &prng, vals);
permute(block1, block, dct->perm_type);
ti = av_gettime_relative();
@@ -238,10 +263,10 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
memcpy(block, block1, sizeof(block));
dct->func(block);
}
+ emms_c();
it1 += NB_ITS_SPEED;
ti1 = av_gettime_relative() - ti;
} while (ti1 < 1000000);
- emms_c();
printf("%s %s: %0.1f kdct/s\n", is_idct ? "IDCT" : "DCT", dct->name,
(double) it1 * 1000.0 / (double) ti1);
@@ -366,6 +391,25 @@ static void idct248_error(const char *name,
if (v > err_max)
err_max = v;
}
+#if 0
+ printf("ref=\n");
+ for(i=0;i<8;i++) {
+ int j;
+ for(j=0;j<8;j++) {
+ printf(" %3d", img_dest1[i*8+j]);
+ }
+ printf("\n");
+ }
+
+ printf("out=\n");
+ for(i=0;i<8;i++) {
+ int j;
+ for(j=0;j<8;j++) {
+ printf(" %3d", img_dest[i*8+j]);
+ }
+ printf("\n");
+ }
+#endif
}
printf("%s %s: err_inf=%d\n", 1 ? "IDCT248" : "DCT248", name, err_max);
@@ -380,10 +424,10 @@ static void idct248_error(const char *name,
block[i] = block1[i];
idct248_put(img_dest, 8, block);
}
+ emms_c();
it1 += NB_ITS_SPEED;
ti1 = av_gettime_relative() - ti;
} while (ti1 < 1000000);
- emms_c();
printf("%s %s: %0.1f kdct/s\n", 1 ? "IDCT248" : "DCT248", name,
(double) it1 * 1000.0 / (double) ti1);
@@ -391,10 +435,11 @@ static void idct248_error(const char *name,
static void help(void)
{
- printf("dct-test [-i] [<test-number>]\n"
+ printf("dct-test [-i] [<test-number>] [<bits>]\n"
"test-number 0 -> test with random matrixes\n"
" 1 -> test with random sparse matrixes\n"
" 2 -> do 3. test from mpeg4 std\n"
+ "bits Number of time domain bits to use, 8 is default\n"
"-i test IDCT implementations\n"
"-4 test IDCT248 implementations\n"
"-t speed test\n");
@@ -411,6 +456,7 @@ int main(int argc, char **argv)
int test = 1;
int speed = 0;
int err = 0;
+ int bits=8;
ff_ref_dct_init();
@@ -437,8 +483,9 @@ int main(int argc, char **argv)
if (optind < argc)
test = atoi(argv[optind]);
+ if(optind+1 < argc) bits= atoi(argv[optind+1]);
- printf("Libav DCT/IDCT test\n");
+ printf("ffmpeg DCT/IDCT test\n");
if (test_248_dct) {
idct248_error("SIMPLE-C", ff_simple_idct248_put, speed);
@@ -446,20 +493,20 @@ int main(int argc, char **argv)
const int cpu_flags = av_get_cpu_flags();
if (test_idct) {
for (i = 0; i < FF_ARRAY_ELEMS(idct_tab); i++)
- err |= dct_error(&idct_tab[i], test, test_idct, speed);
+ err |= dct_error(&idct_tab[i], test, test_idct, speed, bits);
for (i = 0; idct_tab_arch[i].name; i++)
if (!(~cpu_flags & idct_tab_arch[i].cpu_flag))
- err |= dct_error(&idct_tab_arch[i], test, test_idct, speed);
+ err |= dct_error(&idct_tab_arch[i], test, test_idct, speed, bits);
}
#if CONFIG_FDCTDSP
else {
for (i = 0; i < FF_ARRAY_ELEMS(fdct_tab); i++)
- err |= dct_error(&fdct_tab[i], test, test_idct, speed);
+ err |= dct_error(&fdct_tab[i], test, test_idct, speed, bits);
for (i = 0; fdct_tab_arch[i].name; i++)
if (!(~cpu_flags & fdct_tab_arch[i].cpu_flag))
- err |= dct_error(&fdct_tab_arch[i], test, test_idct, speed);
+ err |= dct_error(&fdct_tab_arch[i], test, test_idct, speed, bits);
}
#endif /* CONFIG_FDCTDSP */
}
diff --git a/libavcodec/dct.c b/libavcodec/dct.c
index 4dbbff867b..9cabc4f591 100644
--- a/libavcodec/dct.c
+++ b/libavcodec/dct.c
@@ -4,20 +4,20 @@
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
* Copyright (c) 2010 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -190,10 +190,10 @@ av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse)
ff_init_ff_cos_tabs(nbits + 2);
s->costab = ff_cos_tabs[nbits + 2];
- s->csc2 = av_malloc(n / 2 * sizeof(FFTSample));
+ s->csc2 = av_malloc_array(n / 2, sizeof(FFTSample));
if (ff_rdft_init(&s->rdft, nbits, inverse == DCT_III) < 0) {
- av_free(s->csc2);
+ av_freep(&s->csc2);
return -1;
}
@@ -218,5 +218,5 @@ av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse)
av_cold void ff_dct_end(DCTContext *s)
{
ff_rdft_end(&s->rdft);
- av_free(s->csc2);
+ av_freep(&s->csc2);
}
diff --git a/libavcodec/dct.h b/libavcodec/dct.h
index 4a31f54fcb..05297ba9db 100644
--- a/libavcodec/dct.h
+++ b/libavcodec/dct.h
@@ -4,24 +4,24 @@
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
* Copyright (c) 2010 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef AVCODEC_DCT_H
+#if !defined(AVCODEC_DCT_H) && (!defined(FFT_FLOAT) || FFT_FLOAT)
#define AVCODEC_DCT_H
#include <stdint.h>
@@ -59,6 +59,9 @@ void ff_fdct248_islow_8(int16_t *data);
void ff_fdct248_islow_10(int16_t *data);
void ff_j_rev_dct(int16_t *data);
+void ff_j_rev_dct4(int16_t *data);
+void ff_j_rev_dct2(int16_t *data);
+void ff_j_rev_dct1(int16_t *data);
void ff_jref_idct_put(uint8_t *dest, int line_size, int16_t *block);
void ff_jref_idct_add(uint8_t *dest, int line_size, int16_t *block);
diff --git a/libavcodec/dct32.h b/libavcodec/dct32.h
index 110338d25c..f4b2471de2 100644
--- a/libavcodec/dct32.h
+++ b/libavcodec/dct32.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dct32_fixed.c b/libavcodec/dct32_fixed.c
index 64efe8bf7a..9025d5efdd 100644
--- a/libavcodec/dct32_fixed.c
+++ b/libavcodec/dct32_fixed.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dct32_float.c b/libavcodec/dct32_float.c
index ef37ce9687..597c9bb639 100644
--- a/libavcodec/dct32_float.c
+++ b/libavcodec/dct32_float.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dct32_template.c b/libavcodec/dct32_template.c
index 272e0dbf95..fb53d53ab1 100644
--- a/libavcodec/dct32_template.c
+++ b/libavcodec/dct32_template.c
@@ -2,20 +2,20 @@
* Template for the Discrete Cosine Transform for 32 samples
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dctref.c b/libavcodec/dctref.c
index ae3dec51cd..851014b664 100644
--- a/libavcodec/dctref.c
+++ b/libavcodec/dctref.c
@@ -2,20 +2,20 @@
* reference discrete cosine transform (double precision)
* Copyright (C) 2009 Dylan Yudaken
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dctref.h b/libavcodec/dctref.h
index a93b70d9f2..f6fde8863a 100644
--- a/libavcodec/dctref.h
+++ b/libavcodec/dctref.h
@@ -2,20 +2,20 @@
* reference discrete cosine transform (double precision)
* Copyright (C) 2009 Dylan Yudaken
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c
index 6fa4edc400..f13291ef28 100644
--- a/libavcodec/dfa.c
+++ b/libavcodec/dfa.c
@@ -3,20 +3,20 @@
* Copyright (c) 2011 Konstantin Shishkov
* based on work by Vladimir "VAG" Gneushev
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "bytestream.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/mem.h"
@@ -37,12 +38,13 @@ typedef struct DfaContext {
static av_cold int dfa_decode_init(AVCodecContext *avctx)
{
DfaContext *s = avctx->priv_data;
- int ret;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
- if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
- return ret;
+ if (!avctx->width || !avctx->height)
+ return AVERROR_INVALIDDATA;
+
+ av_assert0(av_image_check_size(avctx->width, avctx->height, 0, avctx) >= 0);
s->frame_buf = av_mallocz(avctx->width * avctx->height);
if (!s->frame_buf)
@@ -70,6 +72,8 @@ static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height
segments = bytestream2_get_le32(gb);
offset = bytestream2_get_le32(gb);
+ if (segments == 0 && offset == frame_end - frame)
+ return 0; // skip frame
if (frame_end - frame <= offset)
return AVERROR_INVALIDDATA;
frame += offset;
@@ -252,6 +256,9 @@ static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height
y += skip_lines;
segments = bytestream2_get_le16(gb);
}
+
+ if (frame_end <= frame)
+ return AVERROR_INVALIDDATA;
if (segments & 0x8000) {
frame[width - 1] = segments & 0xFF;
segments = bytestream2_get_le16(gb);
@@ -289,7 +296,7 @@ static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height
static int decode_tdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
{
const uint8_t *frame_end = frame + width * height;
- int segments = bytestream2_get_le32(gb);
+ uint32_t segments = bytestream2_get_le32(gb);
int skip, copy;
while (segments--) {
@@ -338,11 +345,10 @@ static int dfa_decode_frame(AVCodecContext *avctx,
uint8_t *dst;
int ret;
int i, pal_elems;
+ int version = avctx->extradata_size==2 ? AV_RL16(avctx->extradata) : 0;
- if ((ret = ff_get_buffer(avctx, frame, 0))) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
bytestream2_init(&gb, avpkt->data, avpkt->size);
while (bytestream2_get_bytes_left(&gb) > 0) {
@@ -355,7 +361,7 @@ static int dfa_decode_frame(AVCodecContext *avctx,
pal_elems = FFMIN(chunk_size / 3, 256);
for (i = 0; i < pal_elems; i++) {
s->pal[i] = bytestream2_get_be24(&gb) << 2;
- s->pal[i] |= (s->pal[i] >> 6) & 0x333;
+ s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303;
}
frame->palette_has_changed = 1;
} else if (chunk_type <= 9) {
@@ -375,9 +381,17 @@ static int dfa_decode_frame(AVCodecContext *avctx,
buf = s->frame_buf;
dst = frame->data[0];
for (i = 0; i < avctx->height; i++) {
- memcpy(dst, buf, avctx->width);
+ if(version == 0x100) {
+ int j;
+ for(j = 0; j < avctx->width; j++) {
+ dst[j] = buf[ (i&3)*(avctx->width /4) + (j/4) +
+ ((j&3)*(avctx->height/4) + (i/4))*avctx->width];
+ }
+ } else {
+ memcpy(dst, buf, avctx->width);
+ buf += avctx->width;
+ }
dst += frame->linesize[0];
- buf += avctx->width;
}
memcpy(frame->data[1], s->pal, sizeof(s->pal));
diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c
index 5e13a849fc..07db919be4 100644
--- a/libavcodec/dirac.c
+++ b/libavcodec/dirac.c
@@ -1,28 +1,29 @@
/*
* Copyright (C) 2007 Marco Gerards <marco@gnu.org>
* Copyright (C) 2009 David Conrad
+ * Copyright (C) 2011 Jordi Ortiz
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Dirac Decoder
- * @author Marco Gerards <marco@gnu.org>
+ * @author Marco Gerards <marco@gnu.org>, David Conrad, Jordi Ortiz <nenjordi@gmail.com>
*/
#include "libavutil/imgutils.h"
@@ -33,7 +34,7 @@
#include "internal.h"
#include "mpeg12data.h"
-// defaults for source parameters
+/* defaults for source parameters */
static const dirac_source_params dirac_source_parameters_defaults[] = {
{ 640, 480, 2, 0, 0, 1, 1, 640, 480, 0, 0, 1, 0 },
{ 176, 120, 2, 0, 0, 9, 2, 176, 120, 0, 0, 1, 1 },
@@ -122,6 +123,7 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
AVRational frame_rate = { 0, 0 };
unsigned luma_depth = 8, luma_offset = 16;
int idx;
+ int chroma_x_shift, chroma_y_shift;
/* [DIRAC_STD] 10.3.2 Frame size. frame_size(video_params) */
/* [DIRAC_STD] custom_dimensions_flag */
@@ -136,7 +138,7 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
if (get_bits1(gb))
/* [DIRAC_STD] CHROMA_FORMAT_INDEX */
source->chroma_format = svq3_get_ue_golomb(gb);
- if (source->chroma_format > 2) {
+ if (source->chroma_format > 2U) {
av_log(avctx, AV_LOG_ERROR, "Unknown chroma format %d\n",
source->chroma_format);
return AVERROR_INVALIDDATA;
@@ -147,14 +149,14 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
if (get_bits1(gb))
/* [DIRAC_STD] SOURCE_SAMPLING */
source->interlaced = svq3_get_ue_golomb(gb);
- if (source->interlaced > 1)
+ if (source->interlaced > 1U)
return AVERROR_INVALIDDATA;
/* [DIRAC_STD] 10.3.5 Frame Rate. frame_rate(video_params) */
if (get_bits1(gb)) { /* [DIRAC_STD] custom_frame_rate_flag */
source->frame_rate_index = svq3_get_ue_golomb(gb);
- if (source->frame_rate_index > 10)
+ if (source->frame_rate_index > 10U)
return AVERROR_INVALIDDATA;
if (!source->frame_rate_index) {
@@ -180,7 +182,7 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
/* [DIRAC_STD] index */
source->aspect_ratio_index = svq3_get_ue_golomb(gb);
- if (source->aspect_ratio_index > 6)
+ if (source->aspect_ratio_index > 6U)
return AVERROR_INVALIDDATA;
if (!source->aspect_ratio_index) {
@@ -213,10 +215,10 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
/* [DIRAC_STD] index */
source->pixel_range_index = svq3_get_ue_golomb(gb);
- if (source->pixel_range_index > 4)
+ if (source->pixel_range_index > 4U)
return AVERROR_INVALIDDATA;
- // This assumes either fullrange or MPEG levels only
+ /* This assumes either fullrange or MPEG levels only */
if (!source->pixel_range_index) {
luma_offset = svq3_get_ue_golomb(gb);
luma_depth = av_log2(svq3_get_ue_golomb(gb)) + 1;
@@ -235,16 +237,22 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
}
if (luma_depth > 8)
- av_log(avctx, AV_LOG_WARNING, "Bitdepth greater than 8");
+ av_log(avctx, AV_LOG_WARNING, "Bitdepth greater than 8\n");
avctx->pix_fmt = dirac_pix_fmt[!luma_offset][source->chroma_format];
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &chroma_x_shift, &chroma_y_shift);
+ if ((source->width % (1<<chroma_x_shift)) || (source->height % (1<<chroma_y_shift))) {
+ av_log(avctx, AV_LOG_ERROR, "Dimensions must be an integer multiple of the chroma subsampling\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* [DIRAC_STD] 10.3.9 Colour specification. colour_spec(video_params) */
if (get_bits1(gb)) { /* [DIRAC_STD] custom_colour_spec_flag */
/* [DIRAC_STD] index */
idx = source->color_spec_index = svq3_get_ue_golomb(gb);
- if (source->color_spec_index > 4)
+ if (source->color_spec_index > 4U)
return AVERROR_INVALIDDATA;
avctx->color_primaries = dirac_color_presets[idx].color_primaries;
@@ -255,7 +263,7 @@ static int parse_source_parameters(AVCodecContext *avctx, GetBitContext *gb,
/* [DIRAC_STD] 10.3.9.1 Colour primaries */
if (get_bits1(gb)) {
idx = svq3_get_ue_golomb(gb);
- if (idx < 3)
+ if (idx < 3U)
avctx->color_primaries = dirac_primaries[idx];
}
/* [DIRAC_STD] 10.3.9.2 Colour matrix */
@@ -302,10 +310,10 @@ int avpriv_dirac_parse_sequence_header(AVCodecContext *avctx, GetBitContext *gb,
else if (version_major > 2)
av_log(avctx, AV_LOG_WARNING, "Stream may have unhandled features\n");
- if (video_format > 20)
+ if (video_format > 20U)
return AVERROR_INVALIDDATA;
- // Fill in defaults for the source parameters.
+ /* Fill in defaults for the source parameters. */
*source = dirac_source_parameters_defaults[video_format];
/* [DIRAC_STD] 10.3 Source Parameters
@@ -323,7 +331,7 @@ int avpriv_dirac_parse_sequence_header(AVCodecContext *avctx, GetBitContext *gb,
* currently only used to signal field coding */
picture_coding_mode = svq3_get_ue_golomb(gb);
if (picture_coding_mode != 0) {
- av_log(avctx, AV_LOG_ERROR, "Unsupported picture coding mode %d",
+ av_log(avctx, AV_LOG_ERROR, "Unsupported picture coding mode %d\n",
picture_coding_mode);
return AVERROR_INVALIDDATA;
}
diff --git a/libavcodec/dirac.h b/libavcodec/dirac.h
index e5b79b09d2..b0f955bf46 100644
--- a/libavcodec/dirac.h
+++ b/libavcodec/dirac.h
@@ -1,21 +1,22 @@
/*
* Copyright (C) 2007 Marco Gerards <marco@gnu.org>
* Copyright (C) 2009 David Conrad
+ * Copyright (C) 2011 Jordi Ortiz
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +27,8 @@
* @file
* Interface to Dirac Decoder/Encoder
* @author Marco Gerards <marco@gnu.org>
+ * @author David Conrad
+ * @author Jordi Ortiz
*/
#include "avcodec.h"
diff --git a/libavcodec/dirac_arith.c b/libavcodec/dirac_arith.c
new file mode 100644
index 0000000000..bf913928b3
--- /dev/null
+++ b/libavcodec/dirac_arith.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2009 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Arithmetic decoder for Dirac
+ * @author Marco Gerards <marco@gnu.org>
+ */
+
+#include "dirac_arith.h"
+
+
+const uint16_t ff_dirac_prob[256] = {
+ 0, 2, 5, 8, 11, 15, 20, 24,
+ 29, 35, 41, 47, 53, 60, 67, 74,
+ 82, 89, 97, 106, 114, 123, 132, 141,
+ 150, 160, 170, 180, 190, 201, 211, 222,
+ 233, 244, 256, 267, 279, 291, 303, 315,
+ 327, 340, 353, 366, 379, 392, 405, 419,
+ 433, 447, 461, 475, 489, 504, 518, 533,
+ 548, 563, 578, 593, 609, 624, 640, 656,
+ 672, 688, 705, 721, 738, 754, 771, 788,
+ 805, 822, 840, 857, 875, 892, 910, 928,
+ 946, 964, 983, 1001, 1020, 1038, 1057, 1076,
+ 1095, 1114, 1133, 1153, 1172, 1192, 1211, 1231,
+ 1251, 1271, 1291, 1311, 1332, 1352, 1373, 1393,
+ 1414, 1435, 1456, 1477, 1498, 1520, 1541, 1562,
+ 1584, 1606, 1628, 1649, 1671, 1694, 1716, 1738,
+ 1760, 1783, 1806, 1828, 1851, 1874, 1897, 1920,
+ 1935, 1942, 1949, 1955, 1961, 1968, 1974, 1980,
+ 1985, 1991, 1996, 2001, 2006, 2011, 2016, 2021,
+ 2025, 2029, 2033, 2037, 2040, 2044, 2047, 2050,
+ 2053, 2056, 2058, 2061, 2063, 2065, 2066, 2068,
+ 2069, 2070, 2071, 2072, 2072, 2072, 2072, 2072,
+ 2072, 2071, 2070, 2069, 2068, 2066, 2065, 2063,
+ 2060, 2058, 2055, 2052, 2049, 2045, 2042, 2038,
+ 2033, 2029, 2024, 2019, 2013, 2008, 2002, 1996,
+ 1989, 1982, 1975, 1968, 1960, 1952, 1943, 1934,
+ 1925, 1916, 1906, 1896, 1885, 1874, 1863, 1851,
+ 1839, 1827, 1814, 1800, 1786, 1772, 1757, 1742,
+ 1727, 1710, 1694, 1676, 1659, 1640, 1622, 1602,
+ 1582, 1561, 1540, 1518, 1495, 1471, 1447, 1422,
+ 1396, 1369, 1341, 1312, 1282, 1251, 1219, 1186,
+ 1151, 1114, 1077, 1037, 995, 952, 906, 857,
+ 805, 750, 690, 625, 553, 471, 376, 255
+};
+
+const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT] = {
+ [CTX_ZPZN_F1] = CTX_ZP_F2,
+ [CTX_ZPNN_F1] = CTX_ZP_F2,
+ [CTX_ZP_F2] = CTX_ZP_F3,
+ [CTX_ZP_F3] = CTX_ZP_F4,
+ [CTX_ZP_F4] = CTX_ZP_F5,
+ [CTX_ZP_F5] = CTX_ZP_F6,
+ [CTX_ZP_F6] = CTX_ZP_F6,
+ [CTX_NPZN_F1] = CTX_NP_F2,
+ [CTX_NPNN_F1] = CTX_NP_F2,
+ [CTX_NP_F2] = CTX_NP_F3,
+ [CTX_NP_F3] = CTX_NP_F4,
+ [CTX_NP_F4] = CTX_NP_F5,
+ [CTX_NP_F5] = CTX_NP_F6,
+ [CTX_NP_F6] = CTX_NP_F6,
+ [CTX_DELTA_Q_F] = CTX_DELTA_Q_F,
+};
+
+int16_t ff_dirac_prob_branchless[256][2];
+
+void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length)
+{
+ int i;
+ align_get_bits(gb);
+
+ length = FFMIN(length, get_bits_left(gb)/8);
+
+ c->bytestream = gb->buffer + get_bits_count(gb)/8;
+ c->bytestream_end = c->bytestream + length;
+ skip_bits_long(gb, length*8);
+
+ c->low = 0;
+ for (i = 0; i < 4; i++) {
+ c->low <<= 8;
+ if (c->bytestream < c->bytestream_end)
+ c->low |= *c->bytestream++;
+ else
+ c->low |= 0xff;
+ }
+
+ c->counter = -16;
+ c->range = 0xffff;
+
+ for (i = 0; i < 256; i++) {
+ ff_dirac_prob_branchless[i][0] = ff_dirac_prob[255-i];
+ ff_dirac_prob_branchless[i][1] = -ff_dirac_prob[i];
+ }
+
+ for (i = 0; i < DIRAC_CTX_COUNT; i++)
+ c->contexts[i] = 0x8000;
+}
diff --git a/libavcodec/dirac_arith.h b/libavcodec/dirac_arith.h
new file mode 100644
index 0000000000..003430a48d
--- /dev/null
+++ b/libavcodec/dirac_arith.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2009 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Arithmetic decoder for Dirac
+ * @author Marco Gerards <marco@gnu.org>
+ */
+
+#ifndef AVCODEC_DIRAC_ARITH_H
+#define AVCODEC_DIRAC_ARITH_H
+
+#include "libavutil/x86/asm.h"
+#include "bytestream.h"
+#include "get_bits.h"
+
+enum dirac_arith_contexts {
+ CTX_ZPZN_F1,
+ CTX_ZPNN_F1,
+ CTX_NPZN_F1,
+ CTX_NPNN_F1,
+ CTX_ZP_F2,
+ CTX_ZP_F3,
+ CTX_ZP_F4,
+ CTX_ZP_F5,
+ CTX_ZP_F6,
+ CTX_NP_F2,
+ CTX_NP_F3,
+ CTX_NP_F4,
+ CTX_NP_F5,
+ CTX_NP_F6,
+ CTX_COEFF_DATA,
+ CTX_SIGN_NEG,
+ CTX_SIGN_ZERO,
+ CTX_SIGN_POS,
+ CTX_ZERO_BLOCK,
+ CTX_DELTA_Q_F,
+ CTX_DELTA_Q_DATA,
+ CTX_DELTA_Q_SIGN,
+
+ DIRAC_CTX_COUNT
+};
+
+// Dirac resets the arith decoder between decoding various types of data,
+// so many contexts are never used simultaneously. Thus, we can reduce
+// the number of contexts needed by reusing them.
+#define CTX_SB_F1 CTX_ZP_F5
+#define CTX_SB_DATA 0
+#define CTX_PMODE_REF1 0
+#define CTX_PMODE_REF2 1
+#define CTX_GLOBAL_BLOCK 2
+#define CTX_MV_F1 CTX_ZP_F2
+#define CTX_MV_DATA 0
+#define CTX_DC_F1 CTX_ZP_F5
+#define CTX_DC_DATA 0
+
+typedef struct {
+ unsigned low;
+ uint16_t range;
+ int16_t counter;
+
+ const uint8_t *bytestream;
+ const uint8_t *bytestream_end;
+
+ uint16_t contexts[DIRAC_CTX_COUNT];
+} DiracArith;
+
+extern const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT];
+extern const uint16_t ff_dirac_prob[256];
+extern int16_t ff_dirac_prob_branchless[256][2];
+
+static inline void renorm(DiracArith *c)
+{
+#if HAVE_FAST_CLZ
+ int shift = 14 - av_log2_16bit(c->range-1) + ((c->range-1)>>15);
+
+ c->low <<= shift;
+ c->range <<= shift;
+ c->counter += shift;
+#else
+ while (c->range <= 0x4000) {
+ c->low <<= 1;
+ c->range <<= 1;
+ c->counter++;
+ }
+#endif
+}
+
+static inline void refill(DiracArith *c)
+{
+ int counter = c->counter;
+
+ if (counter >= 0) {
+ int new = bytestream_get_be16(&c->bytestream);
+
+ // the spec defines overread bits to be 1, and streams rely on this
+ if (c->bytestream > c->bytestream_end) {
+ new |= 0xff;
+ if (c->bytestream > c->bytestream_end+1)
+ new |= 0xff00;
+
+ c->bytestream = c->bytestream_end;
+ }
+
+ c->low += new << counter;
+ counter -= 16;
+ }
+ c->counter = counter;
+}
+
+static inline int dirac_get_arith_bit(DiracArith *c, int ctx)
+{
+ int prob_zero = c->contexts[ctx];
+ int range_times_prob, bit;
+ unsigned low = c->low;
+ int range = c->range;
+
+ range_times_prob = (c->range * prob_zero) >> 16;
+
+#if ARCH_X86 && HAVE_FAST_CMOV && HAVE_INLINE_ASM && HAVE_6REGS
+ low -= range_times_prob << 16;
+ range -= range_times_prob;
+ bit = 0;
+ __asm__(
+ "cmpl %5, %4 \n\t"
+ "setae %b0 \n\t"
+ "cmovb %3, %2 \n\t"
+ "cmovb %5, %1 \n\t"
+ : "+q"(bit), "+r"(range), "+r"(low)
+ : "r"(c->low), "r"(c->low>>16),
+ "r"(range_times_prob)
+ );
+#else
+ bit = (low >> 16) >= range_times_prob;
+ if (bit) {
+ low -= range_times_prob << 16;
+ range -= range_times_prob;
+ } else {
+ range = range_times_prob;
+ }
+#endif
+
+ c->contexts[ctx] += ff_dirac_prob_branchless[prob_zero>>8][bit];
+ c->low = low;
+ c->range = range;
+
+ renorm(c);
+ refill(c);
+ return bit;
+}
+
+static inline int dirac_get_arith_uint(DiracArith *c, int follow_ctx, int data_ctx)
+{
+ int ret = 1;
+ while (!dirac_get_arith_bit(c, follow_ctx)) {
+ if (ret >= 0x40000000) {
+ av_log(NULL, AV_LOG_ERROR, "dirac_get_arith_uint overflow\n");
+ return -1;
+ }
+ ret <<= 1;
+ ret += dirac_get_arith_bit(c, data_ctx);
+ follow_ctx = ff_dirac_next_ctx[follow_ctx];
+ }
+ return ret-1;
+}
+
+static inline int dirac_get_arith_int(DiracArith *c, int follow_ctx, int data_ctx)
+{
+ int ret = dirac_get_arith_uint(c, follow_ctx, data_ctx);
+ if (ret && dirac_get_arith_bit(c, data_ctx+1))
+ ret = -ret;
+ return ret;
+}
+
+void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length);
+
+#endif /* AVCODEC_DIRAC_ARITH_H */
diff --git a/libavcodec/dirac_dwt.c b/libavcodec/dirac_dwt.c
new file mode 100644
index 0000000000..ee3665e7ce
--- /dev/null
+++ b/libavcodec/dirac_dwt.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2008 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/avassert.h"
+#include "libavutil/common.h"
+#include "dirac_dwt.h"
+#include "libavcodec/x86/dirac_dwt.h"
+
+
+static void vertical_compose53iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] -= (b0[i] + b2[i] + 2) >> 2;
+}
+
+
+static av_always_inline
+void interleave(IDWTELEM *dst, IDWTELEM *src0, IDWTELEM *src1, int w2, int add, int shift)
+{
+ int i;
+ for (i = 0; i < w2; i++) {
+ dst[2*i ] = (src0[i] + add) >> shift;
+ dst[2*i+1] = (src1[i] + add) >> shift;
+ }
+}
+
+static void horizontal_compose_dirac53i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+ const int w2 = w >> 1;
+ int x;
+
+ temp[0] = COMPOSE_53iL0(b[w2], b[0], b[w2]);
+ for (x = 1; x < w2; x++) {
+ temp[x ] = COMPOSE_53iL0 (b[x+w2-1], b[x ], b[x+w2]);
+ temp[x+w2-1] = COMPOSE_DIRAC53iH0(temp[x-1], b[x+w2-1], temp[x]);
+ }
+ temp[w-1] = COMPOSE_DIRAC53iH0(temp[w2-1], b[w-1], temp[w2-1]);
+
+ interleave(b, temp, temp+w2, w2, 1, 1);
+}
+
+static void horizontal_compose_dd97i(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+ const int w2 = w >> 1;
+ int x;
+
+ tmp[0] = COMPOSE_53iL0(b[w2], b[0], b[w2]);
+ for (x = 1; x < w2; x++)
+ tmp[x] = COMPOSE_53iL0(b[x+w2-1], b[x], b[x+w2]);
+
+ // extend the edges
+ tmp[-1] = tmp[0];
+ tmp[w2+1] = tmp[w2] = tmp[w2-1];
+
+ for (x = 0; x < w2; x++) {
+ b[2*x ] = (tmp[x] + 1)>>1;
+ b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1;
+ }
+}
+
+static void horizontal_compose_dd137i(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+ const int w2 = w >> 1;
+ int x;
+
+ tmp[0] = COMPOSE_DD137iL0(b[w2], b[w2], b[0], b[w2 ], b[w2+1]);
+ tmp[1] = COMPOSE_DD137iL0(b[w2], b[w2], b[1], b[w2+1], b[w2+2]);
+ for (x = 2; x < w2-1; x++)
+ tmp[x] = COMPOSE_DD137iL0(b[x+w2-2], b[x+w2-1], b[x], b[x+w2], b[x+w2+1]);
+ tmp[w2-1] = COMPOSE_DD137iL0(b[w-3], b[w-2], b[w2-1], b[w-1], b[w-1]);
+
+ // extend the edges
+ tmp[-1] = tmp[0];
+ tmp[w2+1] = tmp[w2] = tmp[w2-1];
+
+ for (x = 0; x < w2; x++) {
+ b[2*x ] = (tmp[x] + 1)>>1;
+ b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1;
+ }
+}
+
+static av_always_inline
+void horizontal_compose_haari(IDWTELEM *b, IDWTELEM *temp, int w, int shift)
+{
+ const int w2 = w >> 1;
+ int x;
+
+ for (x = 0; x < w2; x++) {
+ temp[x ] = COMPOSE_HAARiL0(b[x ], b[x+w2]);
+ temp[x+w2] = COMPOSE_HAARiH0(b[x+w2], temp[x]);
+ }
+
+ interleave(b, temp, temp+w2, w2, shift, shift);
+}
+
+static void horizontal_compose_haar0i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+ horizontal_compose_haari(b, temp, w, 0);
+}
+
+static void horizontal_compose_haar1i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+ horizontal_compose_haari(b, temp, w, 1);
+}
+
+static void horizontal_compose_fidelityi(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+ const int w2 = w >> 1;
+ int i, x;
+ IDWTELEM v[8];
+
+ for (x = 0; x < w2; x++) {
+ for (i = 0; i < 8; i++)
+ v[i] = b[av_clip(x-3+i, 0, w2-1)];
+ tmp[x] = COMPOSE_FIDELITYiH0(v[0], v[1], v[2], v[3], b[x+w2], v[4], v[5], v[6], v[7]);
+ }
+
+ for (x = 0; x < w2; x++) {
+ for (i = 0; i < 8; i++)
+ v[i] = tmp[av_clip(x-4+i, 0, w2-1)];
+ tmp[x+w2] = COMPOSE_FIDELITYiL0(v[0], v[1], v[2], v[3], b[x], v[4], v[5], v[6], v[7]);
+ }
+
+ interleave(b, tmp+w2, tmp, w2, 0, 0);
+}
+
+static void horizontal_compose_daub97i(IDWTELEM *b, IDWTELEM *temp, int w)
+{
+ const int w2 = w >> 1;
+ int x, b0, b1, b2;
+
+ temp[0] = COMPOSE_DAUB97iL1(b[w2], b[0], b[w2]);
+ for (x = 1; x < w2; x++) {
+ temp[x ] = COMPOSE_DAUB97iL1(b[x+w2-1], b[x ], b[x+w2]);
+ temp[x+w2-1] = COMPOSE_DAUB97iH1(temp[x-1], b[x+w2-1], temp[x]);
+ }
+ temp[w-1] = COMPOSE_DAUB97iH1(temp[w2-1], b[w-1], temp[w2-1]);
+
+ // second stage combined with interleave and shift
+ b0 = b2 = COMPOSE_DAUB97iL0(temp[w2], temp[0], temp[w2]);
+ b[0] = (b0 + 1) >> 1;
+ for (x = 1; x < w2; x++) {
+ b2 = COMPOSE_DAUB97iL0(temp[x+w2-1], temp[x ], temp[x+w2]);
+ b1 = COMPOSE_DAUB97iH0( b0, temp[x+w2-1], b2 );
+ b[2*x-1] = (b1 + 1) >> 1;
+ b[2*x ] = (b2 + 1) >> 1;
+ b0 = b2;
+ }
+ b[w-1] = (COMPOSE_DAUB97iH0(b2, temp[w-1], b2) + 1) >> 1;
+}
+
+static void vertical_compose_dirac53iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b1[i] = COMPOSE_DIRAC53iH0(b0[i], b1[i], b2[i]);
+ }
+}
+
+static void vertical_compose_dd97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ IDWTELEM *b3, IDWTELEM *b4, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b2[i] = COMPOSE_DD97iH0(b0[i], b1[i], b2[i], b3[i], b4[i]);
+ }
+}
+
+static void vertical_compose_dd137iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ IDWTELEM *b3, IDWTELEM *b4, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b2[i] = COMPOSE_DD137iL0(b0[i], b1[i], b2[i], b3[i], b4[i]);
+ }
+}
+
+static void vertical_compose_haar(IDWTELEM *b0, IDWTELEM *b1, int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++) {
+ b0[i] = COMPOSE_HAARiL0(b0[i], b1[i]);
+ b1[i] = COMPOSE_HAARiH0(b1[i], b0[i]);
+ }
+}
+
+static void vertical_compose_fidelityiH0(IDWTELEM *dst, IDWTELEM *b[8], int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ dst[i] = COMPOSE_FIDELITYiH0(b[0][i], b[1][i], b[2][i], b[3][i], dst[i], b[4][i], b[5][i], b[6][i], b[7][i]);
+ }
+}
+
+static void vertical_compose_fidelityiL0(IDWTELEM *dst, IDWTELEM *b[8], int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ dst[i] = COMPOSE_FIDELITYiL0(b[0][i], b[1][i], b[2][i], b[3][i], dst[i], b[4][i], b[5][i], b[6][i], b[7][i]);
+ }
+}
+
+static void vertical_compose_daub97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b1[i] = COMPOSE_DAUB97iH0(b0[i], b1[i], b2[i]);
+ }
+}
+
+static void vertical_compose_daub97iH1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b1[i] = COMPOSE_DAUB97iH1(b0[i], b1[i], b2[i]);
+ }
+}
+
+static void vertical_compose_daub97iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b1[i] = COMPOSE_DAUB97iL0(b0[i], b1[i], b2[i]);
+ }
+}
+
+static void vertical_compose_daub97iL1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width)
+{
+ int i;
+
+ for(i=0; i<width; i++){
+ b1[i] = COMPOSE_DAUB97iL1(b0[i], b1[i], b2[i]);
+ }
+}
+
+
+static void spatial_compose_dd97i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+ vertical_compose_3tap vertical_compose_l0 = (void*)d->vertical_compose_l0;
+ vertical_compose_5tap vertical_compose_h0 = (void*)d->vertical_compose_h0;
+ DWTCompose *cs = d->cs + level;
+
+ int i, y = cs->y;
+ IDWTELEM *b[8];
+ for (i = 0; i < 6; i++)
+ b[i] = cs->b[i];
+ b[6] = d->buffer + av_clip(y+5, 0, height-2)*stride;
+ b[7] = d->buffer + av_clip(y+6, 1, height-1)*stride;
+
+ if(y+5<(unsigned)height) vertical_compose_l0( b[5], b[6], b[7], width);
+ if(y+1<(unsigned)height) vertical_compose_h0(b[0], b[2], b[3], b[4], b[6], width);
+
+ if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+ if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+ for (i = 0; i < 6; i++)
+ cs->b[i] = b[i+2];
+ cs->y += 2;
+}
+
+static void spatial_compose_dirac53i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+ vertical_compose_3tap vertical_compose_l0 = (void*)d->vertical_compose_l0;
+ vertical_compose_3tap vertical_compose_h0 = (void*)d->vertical_compose_h0;
+ DWTCompose *cs = d->cs + level;
+
+ int y= cs->y;
+ IDWTELEM *b[4] = { cs->b[0], cs->b[1] };
+ b[2] = d->buffer + avpriv_mirror(y+1, height-1)*stride;
+ b[3] = d->buffer + avpriv_mirror(y+2, height-1)*stride;
+
+ if(y+1<(unsigned)height) vertical_compose_l0(b[1], b[2], b[3], width);
+ if(y+0<(unsigned)height) vertical_compose_h0(b[0], b[1], b[2], width);
+
+ if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+ if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+ cs->b[0] = b[2];
+ cs->b[1] = b[3];
+ cs->y += 2;
+}
+
+
+static void spatial_compose_dd137i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+ vertical_compose_5tap vertical_compose_l0 = (void*)d->vertical_compose_l0;
+ vertical_compose_5tap vertical_compose_h0 = (void*)d->vertical_compose_h0;
+ DWTCompose *cs = d->cs + level;
+
+ int i, y = cs->y;
+ IDWTELEM *b[10];
+ for (i = 0; i < 8; i++)
+ b[i] = cs->b[i];
+ b[8] = d->buffer + av_clip(y+7, 0, height-2)*stride;
+ b[9] = d->buffer + av_clip(y+8, 1, height-1)*stride;
+
+ if(y+5<(unsigned)height) vertical_compose_l0(b[3], b[5], b[6], b[7], b[9], width);
+ if(y+1<(unsigned)height) vertical_compose_h0(b[0], b[2], b[3], b[4], b[6], width);
+
+ if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+ if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+ for (i = 0; i < 8; i++)
+ cs->b[i] = b[i+2];
+ cs->y += 2;
+}
+
+// haar makes the assumption that height is even (always true for dirac)
+static void spatial_compose_haari_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+ vertical_compose_2tap vertical_compose = (void*)d->vertical_compose;
+ int y = d->cs[level].y;
+ IDWTELEM *b0 = d->buffer + (y-1)*stride;
+ IDWTELEM *b1 = d->buffer + (y )*stride;
+
+ vertical_compose(b0, b1, width);
+ d->horizontal_compose(b0, d->temp, width);
+ d->horizontal_compose(b1, d->temp, width);
+
+ d->cs[level].y += 2;
+}
+
+// Don't do sliced idwt for fidelity; the 9 tap filter makes it a bit annoying
+// Fortunately, this filter isn't used in practice.
+static void spatial_compose_fidelity(DWTContext *d, int level, int width, int height, int stride)
+{
+ vertical_compose_9tap vertical_compose_l0 = (void*)d->vertical_compose_l0;
+ vertical_compose_9tap vertical_compose_h0 = (void*)d->vertical_compose_h0;
+ int i, y;
+ IDWTELEM *b[8];
+
+ for (y = 1; y < height; y += 2) {
+ for (i = 0; i < 8; i++)
+ b[i] = d->buffer + av_clip((y-7 + 2*i), 0, height-2)*stride;
+ vertical_compose_h0(d->buffer + y*stride, b, width);
+ }
+
+ for (y = 0; y < height; y += 2) {
+ for (i = 0; i < 8; i++)
+ b[i] = d->buffer + av_clip((y-7 + 2*i), 1, height-1)*stride;
+ vertical_compose_l0(d->buffer + y*stride, b, width);
+ }
+
+ for (y = 0; y < height; y++)
+ d->horizontal_compose(d->buffer + y*stride, d->temp, width);
+
+ d->cs[level].y = height+1;
+}
+
+static void spatial_compose_daub97i_dy(DWTContext *d, int level, int width, int height, int stride)
+{
+ vertical_compose_3tap vertical_compose_l0 = (void*)d->vertical_compose_l0;
+ vertical_compose_3tap vertical_compose_h0 = (void*)d->vertical_compose_h0;
+ vertical_compose_3tap vertical_compose_l1 = (void*)d->vertical_compose_l1;
+ vertical_compose_3tap vertical_compose_h1 = (void*)d->vertical_compose_h1;
+ DWTCompose *cs = d->cs + level;
+
+ int i, y = cs->y;
+ IDWTELEM *b[6];
+ for (i = 0; i < 4; i++)
+ b[i] = cs->b[i];
+ b[4] = d->buffer + avpriv_mirror(y+3, height-1)*stride;
+ b[5] = d->buffer + avpriv_mirror(y+4, height-1)*stride;
+
+ if(y+3<(unsigned)height) vertical_compose_l1(b[3], b[4], b[5], width);
+ if(y+2<(unsigned)height) vertical_compose_h1(b[2], b[3], b[4], width);
+ if(y+1<(unsigned)height) vertical_compose_l0(b[1], b[2], b[3], width);
+ if(y+0<(unsigned)height) vertical_compose_h0(b[0], b[1], b[2], width);
+
+ if(y-1<(unsigned)height) d->horizontal_compose(b[0], d->temp, width);
+ if(y+0<(unsigned)height) d->horizontal_compose(b[1], d->temp, width);
+
+ for (i = 0; i < 4; i++)
+ cs->b[i] = b[i+2];
+ cs->y += 2;
+}
+
+
+static void spatial_compose97i_init2(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+ cs->b[0] = buffer + avpriv_mirror(-3-1, height-1)*stride;
+ cs->b[1] = buffer + avpriv_mirror(-3 , height-1)*stride;
+ cs->b[2] = buffer + avpriv_mirror(-3+1, height-1)*stride;
+ cs->b[3] = buffer + avpriv_mirror(-3+2, height-1)*stride;
+ cs->y = -3;
+}
+
+static void spatial_compose53i_init2(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+ cs->b[0] = buffer + avpriv_mirror(-1-1, height-1)*stride;
+ cs->b[1] = buffer + avpriv_mirror(-1 , height-1)*stride;
+ cs->y = -1;
+}
+
+static void spatial_compose_dd97i_init(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+ cs->b[0] = buffer + av_clip(-5-1, 0, height-2)*stride;
+ cs->b[1] = buffer + av_clip(-5 , 1, height-1)*stride;
+ cs->b[2] = buffer + av_clip(-5+1, 0, height-2)*stride;
+ cs->b[3] = buffer + av_clip(-5+2, 1, height-1)*stride;
+ cs->b[4] = buffer + av_clip(-5+3, 0, height-2)*stride;
+ cs->b[5] = buffer + av_clip(-5+4, 1, height-1)*stride;
+ cs->y = -5;
+}
+
+static void spatial_compose_dd137i_init(DWTCompose *cs, IDWTELEM *buffer, int height, int stride)
+{
+ cs->b[0] = buffer + av_clip(-5-1, 0, height-2)*stride;
+ cs->b[1] = buffer + av_clip(-5 , 1, height-1)*stride;
+ cs->b[2] = buffer + av_clip(-5+1, 0, height-2)*stride;
+ cs->b[3] = buffer + av_clip(-5+2, 1, height-1)*stride;
+ cs->b[4] = buffer + av_clip(-5+3, 0, height-2)*stride;
+ cs->b[5] = buffer + av_clip(-5+4, 1, height-1)*stride;
+ cs->b[6] = buffer + av_clip(-5+5, 0, height-2)*stride;
+ cs->b[7] = buffer + av_clip(-5+6, 1, height-1)*stride;
+ cs->y = -5;
+}
+
+int ff_spatial_idwt_init2(DWTContext *d, IDWTELEM *buffer, int width, int height,
+ int stride, enum dwt_type type, int decomposition_count,
+ IDWTELEM *temp)
+{
+ int level;
+
+ d->buffer = buffer;
+ d->width = width;
+ d->height = height;
+ d->stride = stride;
+ d->decomposition_count = decomposition_count;
+ d->temp = temp + 8;
+
+ for(level=decomposition_count-1; level>=0; level--){
+ int hl = height >> level;
+ int stride_l = stride << level;
+
+ switch(type){
+ case DWT_DIRAC_DD9_7:
+ spatial_compose_dd97i_init(d->cs+level, buffer, hl, stride_l);
+ break;
+ case DWT_DIRAC_LEGALL5_3:
+ spatial_compose53i_init2(d->cs+level, buffer, hl, stride_l);
+ break;
+ case DWT_DIRAC_DD13_7:
+ spatial_compose_dd137i_init(d->cs+level, buffer, hl, stride_l);
+ break;
+ case DWT_DIRAC_HAAR0:
+ case DWT_DIRAC_HAAR1:
+ d->cs[level].y = 1;
+ break;
+ case DWT_DIRAC_DAUB9_7:
+ spatial_compose97i_init2(d->cs+level, buffer, hl, stride_l);
+ break;
+ default:
+ d->cs[level].y = 0;
+ break;
+ }
+ }
+
+ switch (type) {
+ case DWT_DIRAC_DD9_7:
+ d->spatial_compose = spatial_compose_dd97i_dy;
+ d->vertical_compose_l0 = (void*)vertical_compose53iL0;
+ d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0;
+ d->horizontal_compose = horizontal_compose_dd97i;
+ d->support = 7;
+ break;
+ case DWT_DIRAC_LEGALL5_3:
+ d->spatial_compose = spatial_compose_dirac53i_dy;
+ d->vertical_compose_l0 = (void*)vertical_compose53iL0;
+ d->vertical_compose_h0 = (void*)vertical_compose_dirac53iH0;
+ d->horizontal_compose = horizontal_compose_dirac53i;
+ d->support = 3;
+ break;
+ case DWT_DIRAC_DD13_7:
+ d->spatial_compose = spatial_compose_dd137i_dy;
+ d->vertical_compose_l0 = (void*)vertical_compose_dd137iL0;
+ d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0;
+ d->horizontal_compose = horizontal_compose_dd137i;
+ d->support = 7;
+ break;
+ case DWT_DIRAC_HAAR0:
+ case DWT_DIRAC_HAAR1:
+ d->spatial_compose = spatial_compose_haari_dy;
+ d->vertical_compose = (void*)vertical_compose_haar;
+ if (type == DWT_DIRAC_HAAR0)
+ d->horizontal_compose = horizontal_compose_haar0i;
+ else
+ d->horizontal_compose = horizontal_compose_haar1i;
+ d->support = 1;
+ break;
+ case DWT_DIRAC_FIDELITY:
+ d->spatial_compose = spatial_compose_fidelity;
+ d->vertical_compose_l0 = (void*)vertical_compose_fidelityiL0;
+ d->vertical_compose_h0 = (void*)vertical_compose_fidelityiH0;
+ d->horizontal_compose = horizontal_compose_fidelityi;
+ d->support = 0; // not really used
+ break;
+ case DWT_DIRAC_DAUB9_7:
+ d->spatial_compose = spatial_compose_daub97i_dy;
+ d->vertical_compose_l0 = (void*)vertical_compose_daub97iL0;
+ d->vertical_compose_h0 = (void*)vertical_compose_daub97iH0;
+ d->vertical_compose_l1 = (void*)vertical_compose_daub97iL1;
+ d->vertical_compose_h1 = (void*)vertical_compose_daub97iH1;
+ d->horizontal_compose = horizontal_compose_daub97i;
+ d->support = 5;
+ break;
+ default:
+ av_log(NULL, AV_LOG_ERROR, "Unknown wavelet type %d\n", type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (HAVE_MMX) ff_spatial_idwt_init_mmx(d, type);
+
+ return 0;
+}
+
+void ff_spatial_idwt_slice2(DWTContext *d, int y)
+{
+ int level, support = d->support;
+
+ for (level = d->decomposition_count-1; level >= 0; level--) {
+ int wl = d->width >> level;
+ int hl = d->height >> level;
+ int stride_l = d->stride << level;
+
+ while (d->cs[level].y <= FFMIN((y>>level)+support, hl))
+ d->spatial_compose(d, level, wl, hl, stride_l);
+ }
+}
+
diff --git a/libavcodec/dirac_dwt.h b/libavcodec/dirac_dwt.h
new file mode 100644
index 0000000000..e5e447b0ac
--- /dev/null
+++ b/libavcodec/dirac_dwt.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_DIRAC_DWT_H
+#define AVCODEC_DIRAC_DWT_H
+
+#include <stdint.h>
+
+typedef int DWTELEM;
+typedef short IDWTELEM;
+
+#define MAX_DWT_SUPPORT 8
+#define MAX_DECOMPOSITIONS 8
+
+typedef struct DWTCompose {
+ IDWTELEM *b[MAX_DWT_SUPPORT];
+ int y;
+} DWTCompose;
+
+struct DWTContext;
+
+// Possible prototypes for vertical_compose functions
+typedef void (*vertical_compose_2tap)(IDWTELEM *b0, IDWTELEM *b1, int width);
+typedef void (*vertical_compose_3tap)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width);
+typedef void (*vertical_compose_5tap)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, int width);
+typedef void (*vertical_compose_9tap)(IDWTELEM *dst, IDWTELEM *b[8], int width);
+
+typedef struct DWTContext {
+ IDWTELEM *buffer;
+ IDWTELEM *temp;
+ int width;
+ int height;
+ int stride;
+ int decomposition_count;
+ int support;
+
+ void (*spatial_compose)(struct DWTContext *cs, int level, int width, int height, int stride);
+ void (*vertical_compose_l0)(void);
+ void (*vertical_compose_h0)(void);
+ void (*vertical_compose_l1)(void);
+ void (*vertical_compose_h1)(void);
+ void (*vertical_compose)(void); ///< one set of lowpass and highpass combined
+ void (*horizontal_compose)(IDWTELEM *b, IDWTELEM *tmp, int width);
+
+ DWTCompose cs[MAX_DECOMPOSITIONS];
+} DWTContext;
+
+enum dwt_type {
+ DWT_SNOW_DAUB9_7,
+ DWT_SNOW_LEGALL5_3,
+ DWT_DIRAC_DD9_7,
+ DWT_DIRAC_LEGALL5_3,
+ DWT_DIRAC_DD13_7,
+ DWT_DIRAC_HAAR0,
+ DWT_DIRAC_HAAR1,
+ DWT_DIRAC_FIDELITY,
+ DWT_DIRAC_DAUB9_7,
+ DWT_NUM_TYPES
+};
+
+// -1 if an error occurred, e.g. the dwt_type isn't recognized
+int ff_spatial_idwt_init2(DWTContext *d, IDWTELEM *buffer, int width, int height,
+ int stride, enum dwt_type type, int decomposition_count,
+ IDWTELEM *temp);
+
+void ff_spatial_idwt_slice2(DWTContext *d, int y);
+
+// shared stuff for simd optimizations
+#define COMPOSE_53iL0(b0, b1, b2)\
+ (b1 - ((b0 + b2 + 2) >> 2))
+
+#define COMPOSE_DIRAC53iH0(b0, b1, b2)\
+ (b1 + ((b0 + b2 + 1) >> 1))
+
+#define COMPOSE_DD97iH0(b0, b1, b2, b3, b4)\
+ (b2 + ((-b0 + 9*b1 + 9*b3 - b4 + 8) >> 4))
+
+#define COMPOSE_DD137iL0(b0, b1, b2, b3, b4)\
+ (b2 - ((-b0 + 9*b1 + 9*b3 - b4 + 16) >> 5))
+
+#define COMPOSE_HAARiL0(b0, b1)\
+ (b0 - ((b1 + 1) >> 1))
+
+#define COMPOSE_HAARiH0(b0, b1)\
+ (b0 + b1)
+
+#define COMPOSE_FIDELITYiL0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\
+ (b4 - ((-8*(b0+b8) + 21*(b1+b7) - 46*(b2+b6) + 161*(b3+b5) + 128) >> 8))
+
+#define COMPOSE_FIDELITYiH0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\
+ (b4 + ((-2*(b0+b8) + 10*(b1+b7) - 25*(b2+b6) + 81*(b3+b5) + 128) >> 8))
+
+#define COMPOSE_DAUB97iL1(b0, b1, b2)\
+ (b1 - ((1817*(b0 + b2) + 2048) >> 12))
+
+#define COMPOSE_DAUB97iH1(b0, b1, b2)\
+ (b1 - (( 113*(b0 + b2) + 64) >> 7))
+
+#define COMPOSE_DAUB97iL0(b0, b1, b2)\
+ (b1 + (( 217*(b0 + b2) + 2048) >> 12))
+
+#define COMPOSE_DAUB97iH0(b0, b1, b2)\
+ (b1 + ((6497*(b0 + b2) + 2048) >> 12))
+
+
+#endif /* AVCODEC_DWT_H */
diff --git a/libavcodec/dirac_parser.c b/libavcodec/dirac_parser.c
index 5c9d266480..45ded5a779 100644
--- a/libavcodec/dirac_parser.c
+++ b/libavcodec/dirac_parser.c
@@ -4,20 +4,20 @@
* Copyright (c) 2007-2008 Marco Gerards <marco@gnu.org>
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -139,6 +139,8 @@ static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx,
void *new_buffer =
av_fast_realloc(pc->buffer, &pc->buffer_size,
pc->index + (*buf_size - pc->sync_offset));
+ if (!new_buffer)
+ return AVERROR(ENOMEM);
pc->buffer = new_buffer;
memcpy(pc->buffer + pc->index, (*buf + pc->sync_offset),
*buf_size - pc->sync_offset);
@@ -149,6 +151,8 @@ static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx,
DiracParseUnit pu1, pu;
void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size,
pc->index + next);
+ if (!new_buffer)
+ return AVERROR(ENOMEM);
pc->buffer = new_buffer;
memcpy(pc->buffer + pc->index, *buf, next);
pc->index += next;
@@ -161,7 +165,9 @@ static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx,
* we can be pretty sure that we have a valid parse unit */
if (!unpack_parse_unit(&pu1, pc, pc->index - 13) ||
!unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) ||
- pu.next_pu_offset != pu1.prev_pu_offset) {
+ pu.next_pu_offset != pu1.prev_pu_offset ||
+ pc->index < pc->dirac_unit_size + 13LL + pu1.prev_pu_offset
+ ) {
pc->index -= 9;
*buf_size = next - 9;
pc->header_bytes_needed = 9;
@@ -245,7 +251,7 @@ static void dirac_parse_close(AVCodecParserContext *s)
DiracParseContext *pc = s->priv_data;
if (pc->buffer_size > 0)
- av_free(pc->buffer);
+ av_freep(&pc->buffer);
}
AVCodecParser ff_dirac_parser = {
diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c
new file mode 100644
index 0000000000..0213048d3b
--- /dev/null
+++ b/libavcodec/diracdec.c
@@ -0,0 +1,2037 @@
+/*
+ * Copyright (C) 2007 Marco Gerards <marco@gnu.org>
+ * Copyright (C) 2009 David Conrad
+ * Copyright (C) 2011 Jordi Ortiz
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Dirac Decoder
+ * @author Marco Gerards <marco@gnu.org>, David Conrad, Jordi Ortiz <nenjordi@gmail.com>
+ */
+
+#include "avcodec.h"
+#include "get_bits.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "golomb.h"
+#include "dirac_arith.h"
+#include "mpeg12data.h"
+#include "libavcodec/mpegvideo.h"
+#include "mpegvideoencdsp.h"
+#include "dirac_dwt.h"
+#include "dirac.h"
+#include "diracdsp.h"
+#include "videodsp.h"
+
+/**
+ * The spec limits the number of wavelet decompositions to 4 for both
+ * level 1 (VC-2) and 128 (long-gop default).
+ * 5 decompositions is the maximum before >16-bit buffers are needed.
+ * Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting
+ * the others to 4 decompositions (or 3 for the fidelity filter).
+ *
+ * We use this instead of MAX_DECOMPOSITIONS to save some memory.
+ */
+#define MAX_DWT_LEVELS 5
+
+/**
+ * The spec limits this to 3 for frame coding, but in practice can be as high as 6
+ */
+#define MAX_REFERENCE_FRAMES 8
+#define MAX_DELAY 5 /* limit for main profile for frame coding (TODO: field coding) */
+#define MAX_FRAMES (MAX_REFERENCE_FRAMES + MAX_DELAY + 1)
+#define MAX_QUANT 68 /* max quant for VC-2 */
+#define MAX_BLOCKSIZE 32 /* maximum xblen/yblen we support */
+
+/**
+ * DiracBlock->ref flags, if set then the block does MC from the given ref
+ */
+#define DIRAC_REF_MASK_REF1 1
+#define DIRAC_REF_MASK_REF2 2
+#define DIRAC_REF_MASK_GLOBAL 4
+
+/**
+ * Value of Picture.reference when Picture is not a reference picture, but
+ * is held for delayed output.
+ */
+#define DELAYED_PIC_REF 4
+
+#define CALC_PADDING(size, depth) \
+ (((size + (1 << depth) - 1) >> depth) << depth)
+
+#define DIVRNDUP(a, b) (((a) + (b) - 1) / (b))
+
+typedef struct {
+ AVFrame *avframe;
+ int interpolated[3]; /* 1 if hpel[] is valid */
+ uint8_t *hpel[3][4];
+ uint8_t *hpel_base[3][4];
+} DiracFrame;
+
+typedef struct {
+ union {
+ int16_t mv[2][2];
+ int16_t dc[3];
+ } u; /* anonymous unions aren't in C99 :( */
+ uint8_t ref;
+} DiracBlock;
+
+typedef struct SubBand {
+ int level;
+ int orientation;
+ int stride;
+ int width;
+ int height;
+ int quant;
+ IDWTELEM *ibuf;
+ struct SubBand *parent;
+
+ /* for low delay */
+ unsigned length;
+ const uint8_t *coeff_data;
+} SubBand;
+
+typedef struct Plane {
+ int width;
+ int height;
+ ptrdiff_t stride;
+
+ int idwt_width;
+ int idwt_height;
+ int idwt_stride;
+ IDWTELEM *idwt_buf;
+ IDWTELEM *idwt_buf_base;
+ IDWTELEM *idwt_tmp;
+
+ /* block length */
+ uint8_t xblen;
+ uint8_t yblen;
+ /* block separation (block n+1 starts after this many pixels in block n) */
+ uint8_t xbsep;
+ uint8_t ybsep;
+ /* amount of overspill on each edge (half of the overlap between blocks) */
+ uint8_t xoffset;
+ uint8_t yoffset;
+
+ SubBand band[MAX_DWT_LEVELS][4];
+} Plane;
+
+typedef struct DiracContext {
+ AVCodecContext *avctx;
+ MpegvideoEncDSPContext mpvencdsp;
+ VideoDSPContext vdsp;
+ DiracDSPContext diracdsp;
+ GetBitContext gb;
+ dirac_source_params source;
+ int seen_sequence_header;
+ int frame_number; /* number of the next frame to display */
+ Plane plane[3];
+ int chroma_x_shift;
+ int chroma_y_shift;
+
+ int zero_res; /* zero residue flag */
+ int is_arith; /* whether coeffs use arith or golomb coding */
+ int low_delay; /* use the low delay syntax */
+ int globalmc_flag; /* use global motion compensation */
+ int num_refs; /* number of reference pictures */
+
+ /* wavelet decoding */
+ unsigned wavelet_depth; /* depth of the IDWT */
+ unsigned wavelet_idx;
+
+ /**
+ * schroedinger older than 1.0.8 doesn't store
+ * quant delta if only one codebook exists in a band
+ */
+ unsigned old_delta_quant;
+ unsigned codeblock_mode;
+
+ struct {
+ unsigned width;
+ unsigned height;
+ } codeblock[MAX_DWT_LEVELS+1];
+
+ struct {
+ unsigned num_x; /* number of horizontal slices */
+ unsigned num_y; /* number of vertical slices */
+ AVRational bytes; /* average bytes per slice */
+ uint8_t quant[MAX_DWT_LEVELS][4]; /* [DIRAC_STD] E.1 */
+ } lowdelay;
+
+ struct {
+ int pan_tilt[2]; /* pan/tilt vector */
+ int zrs[2][2]; /* zoom/rotate/shear matrix */
+ int perspective[2]; /* perspective vector */
+ unsigned zrs_exp;
+ unsigned perspective_exp;
+ } globalmc[2];
+
+ /* motion compensation */
+ uint8_t mv_precision; /* [DIRAC_STD] REFS_WT_PRECISION */
+ int16_t weight[2]; /* [DIRAC_STD] REF1_WT and REF2_WT */
+ unsigned weight_log2denom; /* [DIRAC_STD] REFS_WT_PRECISION */
+
+ int blwidth; /* number of blocks (horizontally) */
+ int blheight; /* number of blocks (vertically) */
+ int sbwidth; /* number of superblocks (horizontally) */
+ int sbheight; /* number of superblocks (vertically) */
+
+ uint8_t *sbsplit;
+ DiracBlock *blmotion;
+
+ uint8_t *edge_emu_buffer[4];
+ uint8_t *edge_emu_buffer_base;
+
+ uint16_t *mctmp; /* buffer holding the MC data multiplied by OBMC weights */
+ uint8_t *mcscratch;
+ int buffer_stride;
+
+ DECLARE_ALIGNED(16, uint8_t, obmc_weight)[3][MAX_BLOCKSIZE*MAX_BLOCKSIZE];
+
+ void (*put_pixels_tab[4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+ void (*avg_pixels_tab[4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+ void (*add_obmc)(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+ dirac_weight_func weight_func;
+ dirac_biweight_func biweight_func;
+
+ DiracFrame *current_picture;
+ DiracFrame *ref_pics[2];
+
+ DiracFrame *ref_frames[MAX_REFERENCE_FRAMES+1];
+ DiracFrame *delay_frames[MAX_DELAY+1];
+ DiracFrame all_frames[MAX_FRAMES];
+} DiracContext;
+
+/**
+ * Dirac Specification ->
+ * Parse code values. 9.6.1 Table 9.1
+ */
+enum dirac_parse_code {
+ pc_seq_header = 0x00,
+ pc_eos = 0x10,
+ pc_aux_data = 0x20,
+ pc_padding = 0x30,
+};
+
+enum dirac_subband {
+ subband_ll = 0,
+ subband_hl = 1,
+ subband_lh = 2,
+ subband_hh = 3,
+ subband_nb,
+};
+
+static const uint8_t default_qmat[][4][4] = {
+ { { 5, 3, 3, 0}, { 0, 4, 4, 1}, { 0, 5, 5, 2}, { 0, 6, 6, 3} },
+ { { 4, 2, 2, 0}, { 0, 4, 4, 2}, { 0, 5, 5, 3}, { 0, 7, 7, 5} },
+ { { 5, 3, 3, 0}, { 0, 4, 4, 1}, { 0, 5, 5, 2}, { 0, 6, 6, 3} },
+ { { 8, 4, 4, 0}, { 0, 4, 4, 0}, { 0, 4, 4, 0}, { 0, 4, 4, 0} },
+ { { 8, 4, 4, 0}, { 0, 4, 4, 0}, { 0, 4, 4, 0}, { 0, 4, 4, 0} },
+ { { 0, 4, 4, 8}, { 0, 8, 8, 12}, { 0, 13, 13, 17}, { 0, 17, 17, 21} },
+ { { 3, 1, 1, 0}, { 0, 4, 4, 2}, { 0, 6, 6, 5}, { 0, 9, 9, 7} },
+};
+
+static const int qscale_tab[MAX_QUANT+1] = {
+ 4, 5, 6, 7, 8, 10, 11, 13,
+ 16, 19, 23, 27, 32, 38, 45, 54,
+ 64, 76, 91, 108, 128, 152, 181, 215,
+ 256, 304, 362, 431, 512, 609, 724, 861,
+ 1024, 1218, 1448, 1722, 2048, 2435, 2896, 3444,
+ 4096, 4871, 5793, 6889, 8192, 9742, 11585, 13777,
+ 16384, 19484, 23170, 27554, 32768, 38968, 46341, 55109,
+ 65536, 77936
+};
+
+static const int qoffset_intra_tab[MAX_QUANT+1] = {
+ 1, 2, 3, 4, 4, 5, 6, 7,
+ 8, 10, 12, 14, 16, 19, 23, 27,
+ 32, 38, 46, 54, 64, 76, 91, 108,
+ 128, 152, 181, 216, 256, 305, 362, 431,
+ 512, 609, 724, 861, 1024, 1218, 1448, 1722,
+ 2048, 2436, 2897, 3445, 4096, 4871, 5793, 6889,
+ 8192, 9742, 11585, 13777, 16384, 19484, 23171, 27555,
+ 32768, 38968
+};
+
+static const int qoffset_inter_tab[MAX_QUANT+1] = {
+ 1, 2, 2, 3, 3, 4, 4, 5,
+ 6, 7, 9, 10, 12, 14, 17, 20,
+ 24, 29, 34, 41, 48, 57, 68, 81,
+ 96, 114, 136, 162, 192, 228, 272, 323,
+ 384, 457, 543, 646, 768, 913, 1086, 1292,
+ 1536, 1827, 2172, 2583, 3072, 3653, 4344, 5166,
+ 6144, 7307, 8689, 10333, 12288, 14613, 17378, 20666,
+ 24576, 29226
+};
+
+/* magic number division by 3 from schroedinger */
+static inline int divide3(int x)
+{
+ return ((x+1)*21845 + 10922) >> 16;
+}
+
+static DiracFrame *remove_frame(DiracFrame *framelist[], int picnum)
+{
+ DiracFrame *remove_pic = NULL;
+ int i, remove_idx = -1;
+
+ for (i = 0; framelist[i]; i++)
+ if (framelist[i]->avframe->display_picture_number == picnum) {
+ remove_pic = framelist[i];
+ remove_idx = i;
+ }
+
+ if (remove_pic)
+ for (i = remove_idx; framelist[i]; i++)
+ framelist[i] = framelist[i+1];
+
+ return remove_pic;
+}
+
+static int add_frame(DiracFrame *framelist[], int maxframes, DiracFrame *frame)
+{
+ int i;
+ for (i = 0; i < maxframes; i++)
+ if (!framelist[i]) {
+ framelist[i] = frame;
+ return 0;
+ }
+ return -1;
+}
+
+static int alloc_sequence_buffers(DiracContext *s)
+{
+ int sbwidth = DIVRNDUP(s->source.width, 4);
+ int sbheight = DIVRNDUP(s->source.height, 4);
+ int i, w, h, top_padding;
+
+ /* todo: think more about this / use or set Plane here */
+ for (i = 0; i < 3; i++) {
+ int max_xblen = MAX_BLOCKSIZE >> (i ? s->chroma_x_shift : 0);
+ int max_yblen = MAX_BLOCKSIZE >> (i ? s->chroma_y_shift : 0);
+ w = s->source.width >> (i ? s->chroma_x_shift : 0);
+ h = s->source.height >> (i ? s->chroma_y_shift : 0);
+
+ /* we allocate the max we support here since num decompositions can
+ * change from frame to frame. Stride is aligned to 16 for SIMD, and
+ * 1<<MAX_DWT_LEVELS top padding to avoid if(y>0) in arith decoding
+ * MAX_BLOCKSIZE padding for MC: blocks can spill up to half of that
+ * on each side */
+ top_padding = FFMAX(1<<MAX_DWT_LEVELS, max_yblen/2);
+ w = FFALIGN(CALC_PADDING(w, MAX_DWT_LEVELS), 8); /* FIXME: Should this be 16 for SSE??? */
+ h = top_padding + CALC_PADDING(h, MAX_DWT_LEVELS) + max_yblen/2;
+
+ s->plane[i].idwt_buf_base = av_mallocz_array((w+max_xblen), h * sizeof(IDWTELEM));
+ s->plane[i].idwt_tmp = av_malloc_array((w+16), sizeof(IDWTELEM));
+ s->plane[i].idwt_buf = s->plane[i].idwt_buf_base + top_padding*w;
+ if (!s->plane[i].idwt_buf_base || !s->plane[i].idwt_tmp)
+ return AVERROR(ENOMEM);
+ }
+
+ /* fixme: allocate using real stride here */
+ s->sbsplit = av_malloc_array(sbwidth, sbheight);
+ s->blmotion = av_malloc_array(sbwidth, sbheight * 16 * sizeof(*s->blmotion));
+
+ if (!s->sbsplit || !s->blmotion)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static int alloc_buffers(DiracContext *s, int stride)
+{
+ int w = s->source.width;
+ int h = s->source.height;
+
+ av_assert0(stride >= w);
+ stride += 64;
+
+ if (s->buffer_stride >= stride)
+ return 0;
+ s->buffer_stride = 0;
+
+ av_freep(&s->edge_emu_buffer_base);
+ memset(s->edge_emu_buffer, 0, sizeof(s->edge_emu_buffer));
+ av_freep(&s->mctmp);
+ av_freep(&s->mcscratch);
+
+ s->edge_emu_buffer_base = av_malloc_array(stride, MAX_BLOCKSIZE);
+
+ s->mctmp = av_malloc_array((stride+MAX_BLOCKSIZE), (h+MAX_BLOCKSIZE) * sizeof(*s->mctmp));
+ s->mcscratch = av_malloc_array(stride, MAX_BLOCKSIZE);
+
+ if (!s->edge_emu_buffer_base || !s->mctmp || !s->mcscratch)
+ return AVERROR(ENOMEM);
+
+ s->buffer_stride = stride;
+ return 0;
+}
+
+static void free_sequence_buffers(DiracContext *s)
+{
+ int i, j, k;
+
+ for (i = 0; i < MAX_FRAMES; i++) {
+ if (s->all_frames[i].avframe->data[0]) {
+ av_frame_unref(s->all_frames[i].avframe);
+ memset(s->all_frames[i].interpolated, 0, sizeof(s->all_frames[i].interpolated));
+ }
+
+ for (j = 0; j < 3; j++)
+ for (k = 1; k < 4; k++)
+ av_freep(&s->all_frames[i].hpel_base[j][k]);
+ }
+
+ memset(s->ref_frames, 0, sizeof(s->ref_frames));
+ memset(s->delay_frames, 0, sizeof(s->delay_frames));
+
+ for (i = 0; i < 3; i++) {
+ av_freep(&s->plane[i].idwt_buf_base);
+ av_freep(&s->plane[i].idwt_tmp);
+ }
+
+ s->buffer_stride = 0;
+ av_freep(&s->sbsplit);
+ av_freep(&s->blmotion);
+ av_freep(&s->edge_emu_buffer_base);
+
+ av_freep(&s->mctmp);
+ av_freep(&s->mcscratch);
+}
+
+static av_cold int dirac_decode_init(AVCodecContext *avctx)
+{
+ DiracContext *s = avctx->priv_data;
+ int i;
+
+ s->avctx = avctx;
+ s->frame_number = -1;
+
+ ff_diracdsp_init(&s->diracdsp);
+ ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx);
+ ff_videodsp_init(&s->vdsp, 8);
+
+ 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);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
+
+static void dirac_decode_flush(AVCodecContext *avctx)
+{
+ DiracContext *s = avctx->priv_data;
+ free_sequence_buffers(s);
+ s->seen_sequence_header = 0;
+ s->frame_number = -1;
+}
+
+static av_cold int dirac_decode_end(AVCodecContext *avctx)
+{
+ DiracContext *s = avctx->priv_data;
+ int i;
+
+ dirac_decode_flush(avctx);
+ for (i = 0; i < MAX_FRAMES; i++)
+ av_frame_free(&s->all_frames[i].avframe);
+
+ return 0;
+}
+
+#define SIGN_CTX(x) (CTX_SIGN_ZERO + ((x) > 0) - ((x) < 0))
+
+static inline void coeff_unpack_arith(DiracArith *c, int qfactor, int qoffset,
+ SubBand *b, IDWTELEM *buf, int x, int y)
+{
+ int coeff, sign;
+ int sign_pred = 0;
+ int pred_ctx = CTX_ZPZN_F1;
+
+ /* Check if the parent subband has a 0 in the corresponding position */
+ if (b->parent)
+ pred_ctx += !!b->parent->ibuf[b->parent->stride * (y>>1) + (x>>1)] << 1;
+
+ if (b->orientation == subband_hl)
+ sign_pred = buf[-b->stride];
+
+ /* Determine if the pixel has only zeros in its neighbourhood */
+ if (x) {
+ pred_ctx += !(buf[-1] | buf[-b->stride] | buf[-1-b->stride]);
+ if (b->orientation == subband_lh)
+ sign_pred = buf[-1];
+ } else {
+ pred_ctx += !buf[-b->stride];
+ }
+
+ coeff = dirac_get_arith_uint(c, pred_ctx, CTX_COEFF_DATA);
+ if (coeff) {
+ coeff = (coeff * qfactor + qoffset + 2) >> 2;
+ sign = dirac_get_arith_bit(c, SIGN_CTX(sign_pred));
+ coeff = (coeff ^ -sign) + sign;
+ }
+ *buf = coeff;
+}
+
+static inline int coeff_unpack_golomb(GetBitContext *gb, int qfactor, int qoffset)
+{
+ int sign, coeff;
+
+ coeff = svq3_get_ue_golomb(gb);
+ if (coeff) {
+ coeff = (coeff * qfactor + qoffset + 2) >> 2;
+ sign = get_bits1(gb);
+ coeff = (coeff ^ -sign) + sign;
+ }
+ return coeff;
+}
+
+/**
+ * Decode the coeffs in the rectangle defined by left, right, top, bottom
+ * [DIRAC_STD] 13.4.3.2 Codeblock unpacking loop. codeblock()
+ */
+static inline void codeblock(DiracContext *s, SubBand *b,
+ GetBitContext *gb, DiracArith *c,
+ int left, int right, int top, int bottom,
+ int blockcnt_one, int is_arith)
+{
+ int x, y, zero_block;
+ int qoffset, qfactor;
+ IDWTELEM *buf;
+
+ /* check for any coded coefficients in this codeblock */
+ if (!blockcnt_one) {
+ if (is_arith)
+ zero_block = dirac_get_arith_bit(c, CTX_ZERO_BLOCK);
+ else
+ zero_block = get_bits1(gb);
+
+ if (zero_block)
+ return;
+ }
+
+ if (s->codeblock_mode && !(s->old_delta_quant && blockcnt_one)) {
+ int quant = b->quant;
+ if (is_arith)
+ quant += dirac_get_arith_int(c, CTX_DELTA_Q_F, CTX_DELTA_Q_DATA);
+ else
+ quant += dirac_get_se_golomb(gb);
+ if (quant < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid quant\n");
+ return;
+ }
+ b->quant = quant;
+ }
+
+ b->quant = FFMIN(b->quant, MAX_QUANT);
+
+ qfactor = qscale_tab[b->quant];
+ /* TODO: context pointer? */
+ if (!s->num_refs)
+ qoffset = qoffset_intra_tab[b->quant];
+ else
+ qoffset = qoffset_inter_tab[b->quant];
+
+ buf = b->ibuf + top * b->stride;
+ for (y = top; y < bottom; y++) {
+ for (x = left; x < right; x++) {
+ /* [DIRAC_STD] 13.4.4 Subband coefficients. coeff_unpack() */
+ if (is_arith)
+ coeff_unpack_arith(c, qfactor, qoffset, b, buf+x, x, y);
+ else
+ buf[x] = coeff_unpack_golomb(gb, qfactor, qoffset);
+ }
+ buf += b->stride;
+ }
+}
+
+/**
+ * Dirac Specification ->
+ * 13.3 intra_dc_prediction(band)
+ */
+static inline void intra_dc_prediction(SubBand *b)
+{
+ IDWTELEM *buf = b->ibuf;
+ int x, y;
+
+ for (x = 1; x < b->width; x++)
+ buf[x] += buf[x-1];
+ buf += b->stride;
+
+ for (y = 1; y < b->height; y++) {
+ buf[0] += buf[-b->stride];
+
+ for (x = 1; x < b->width; x++) {
+ int pred = buf[x - 1] + buf[x - b->stride] + buf[x - b->stride-1];
+ buf[x] += divide3(pred);
+ }
+ buf += b->stride;
+ }
+}
+
+/**
+ * Dirac Specification ->
+ * 13.4.2 Non-skipped subbands. subband_coeffs()
+ */
+static av_always_inline void decode_subband_internal(DiracContext *s, SubBand *b, int is_arith)
+{
+ int cb_x, cb_y, left, right, top, bottom;
+ DiracArith c;
+ GetBitContext gb;
+ int cb_width = s->codeblock[b->level + (b->orientation != subband_ll)].width;
+ int cb_height = s->codeblock[b->level + (b->orientation != subband_ll)].height;
+ int blockcnt_one = (cb_width + cb_height) == 2;
+
+ if (!b->length)
+ return;
+
+ init_get_bits8(&gb, b->coeff_data, b->length);
+
+ if (is_arith)
+ ff_dirac_init_arith_decoder(&c, &gb, b->length);
+
+ top = 0;
+ for (cb_y = 0; cb_y < cb_height; cb_y++) {
+ bottom = (b->height * (cb_y+1LL)) / cb_height;
+ left = 0;
+ for (cb_x = 0; cb_x < cb_width; cb_x++) {
+ right = (b->width * (cb_x+1LL)) / cb_width;
+ codeblock(s, b, &gb, &c, left, right, top, bottom, blockcnt_one, is_arith);
+ left = right;
+ }
+ top = bottom;
+ }
+
+ if (b->orientation == subband_ll && s->num_refs == 0)
+ intra_dc_prediction(b);
+}
+
+static int decode_subband_arith(AVCodecContext *avctx, void *b)
+{
+ DiracContext *s = avctx->priv_data;
+ decode_subband_internal(s, b, 1);
+ return 0;
+}
+
+static int decode_subband_golomb(AVCodecContext *avctx, void *arg)
+{
+ DiracContext *s = avctx->priv_data;
+ SubBand **b = arg;
+ decode_subband_internal(s, *b, 0);
+ return 0;
+}
+
+/**
+ * Dirac Specification ->
+ * [DIRAC_STD] 13.4.1 core_transform_data()
+ */
+static void decode_component(DiracContext *s, int comp)
+{
+ AVCodecContext *avctx = s->avctx;
+ SubBand *bands[3*MAX_DWT_LEVELS+1];
+ enum dirac_subband orientation;
+ int level, num_bands = 0;
+
+ /* Unpack all subbands at all levels. */
+ for (level = 0; level < s->wavelet_depth; level++) {
+ for (orientation = !!level; orientation < 4; orientation++) {
+ SubBand *b = &s->plane[comp].band[level][orientation];
+ bands[num_bands++] = b;
+
+ align_get_bits(&s->gb);
+ /* [DIRAC_STD] 13.4.2 subband() */
+ b->length = svq3_get_ue_golomb(&s->gb);
+ if (b->length) {
+ b->quant = svq3_get_ue_golomb(&s->gb);
+ align_get_bits(&s->gb);
+ b->coeff_data = s->gb.buffer + get_bits_count(&s->gb)/8;
+ b->length = FFMIN(b->length, FFMAX(get_bits_left(&s->gb)/8, 0));
+ skip_bits_long(&s->gb, b->length*8);
+ }
+ }
+ /* arithmetic coding has inter-level dependencies, so we can only execute one level at a time */
+ if (s->is_arith)
+ avctx->execute(avctx, decode_subband_arith, &s->plane[comp].band[level][!!level],
+ NULL, 4-!!level, sizeof(SubBand));
+ }
+ /* golomb coding has no inter-level dependencies, so we can execute all subbands in parallel */
+ if (!s->is_arith)
+ avctx->execute(avctx, decode_subband_golomb, bands, NULL, num_bands, sizeof(SubBand*));
+}
+
+/* [DIRAC_STD] 13.5.5.2 Luma slice subband data. luma_slice_band(level,orient,sx,sy) --> if b2 == NULL */
+/* [DIRAC_STD] 13.5.5.3 Chroma slice subband data. chroma_slice_band(level,orient,sx,sy) --> if b2 != NULL */
+static void lowdelay_subband(DiracContext *s, GetBitContext *gb, int quant,
+ int slice_x, int slice_y, int bits_end,
+ SubBand *b1, SubBand *b2)
+{
+ int left = b1->width * slice_x / s->lowdelay.num_x;
+ int right = b1->width *(slice_x+1) / s->lowdelay.num_x;
+ int top = b1->height * slice_y / s->lowdelay.num_y;
+ int bottom = b1->height *(slice_y+1) / s->lowdelay.num_y;
+
+ int qfactor = qscale_tab[FFMIN(quant, MAX_QUANT)];
+ int qoffset = qoffset_intra_tab[FFMIN(quant, MAX_QUANT)];
+
+ IDWTELEM *buf1 = b1->ibuf + top * b1->stride;
+ IDWTELEM *buf2 = b2 ? b2->ibuf + top * b2->stride : NULL;
+ int x, y;
+ /* we have to constantly check for overread since the spec explicitly
+ requires this, with the meaning that all remaining coeffs are set to 0 */
+ if (get_bits_count(gb) >= bits_end)
+ return;
+
+ for (y = top; y < bottom; y++) {
+ for (x = left; x < right; x++) {
+ buf1[x] = coeff_unpack_golomb(gb, qfactor, qoffset);
+ if (get_bits_count(gb) >= bits_end)
+ return;
+ if (buf2) {
+ buf2[x] = coeff_unpack_golomb(gb, qfactor, qoffset);
+ if (get_bits_count(gb) >= bits_end)
+ return;
+ }
+ }
+ buf1 += b1->stride;
+ if (buf2)
+ buf2 += b2->stride;
+ }
+}
+
+struct lowdelay_slice {
+ GetBitContext gb;
+ int slice_x;
+ int slice_y;
+ int bytes;
+};
+
+
+/**
+ * Dirac Specification ->
+ * 13.5.2 Slices. slice(sx,sy)
+ */
+static int decode_lowdelay_slice(AVCodecContext *avctx, void *arg)
+{
+ DiracContext *s = avctx->priv_data;
+ struct lowdelay_slice *slice = arg;
+ GetBitContext *gb = &slice->gb;
+ enum dirac_subband orientation;
+ int level, quant, chroma_bits, chroma_end;
+
+ int quant_base = get_bits(gb, 7); /*[DIRAC_STD] qindex */
+ int length_bits = av_log2(8 * slice->bytes)+1;
+ int luma_bits = get_bits_long(gb, length_bits);
+ int luma_end = get_bits_count(gb) + FFMIN(luma_bits, get_bits_left(gb));
+
+ /* [DIRAC_STD] 13.5.5.2 luma_slice_band */
+ for (level = 0; level < s->wavelet_depth; level++)
+ for (orientation = !!level; orientation < 4; orientation++) {
+ quant = FFMAX(quant_base - s->lowdelay.quant[level][orientation], 0);
+ lowdelay_subband(s, gb, quant, slice->slice_x, slice->slice_y, luma_end,
+ &s->plane[0].band[level][orientation], NULL);
+ }
+
+ /* consume any unused bits from luma */
+ skip_bits_long(gb, get_bits_count(gb) - luma_end);
+
+ chroma_bits = 8*slice->bytes - 7 - length_bits - luma_bits;
+ chroma_end = get_bits_count(gb) + FFMIN(chroma_bits, get_bits_left(gb));
+ /* [DIRAC_STD] 13.5.5.3 chroma_slice_band */
+ for (level = 0; level < s->wavelet_depth; level++)
+ for (orientation = !!level; orientation < 4; orientation++) {
+ quant = FFMAX(quant_base - s->lowdelay.quant[level][orientation], 0);
+ lowdelay_subband(s, gb, quant, slice->slice_x, slice->slice_y, chroma_end,
+ &s->plane[1].band[level][orientation],
+ &s->plane[2].band[level][orientation]);
+ }
+
+ return 0;
+}
+
+/**
+ * Dirac Specification ->
+ * 13.5.1 low_delay_transform_data()
+ */
+static int decode_lowdelay(DiracContext *s)
+{
+ AVCodecContext *avctx = s->avctx;
+ int slice_x, slice_y, bytes, bufsize;
+ const uint8_t *buf;
+ struct lowdelay_slice *slices;
+ int slice_num = 0;
+
+ slices = av_mallocz_array(s->lowdelay.num_x, s->lowdelay.num_y * sizeof(struct lowdelay_slice));
+ if (!slices)
+ return AVERROR(ENOMEM);
+
+ align_get_bits(&s->gb);
+ /*[DIRAC_STD] 13.5.2 Slices. slice(sx,sy) */
+ buf = s->gb.buffer + get_bits_count(&s->gb)/8;
+ bufsize = get_bits_left(&s->gb);
+
+ for (slice_y = 0; bufsize > 0 && slice_y < s->lowdelay.num_y; slice_y++)
+ for (slice_x = 0; bufsize > 0 && slice_x < s->lowdelay.num_x; slice_x++) {
+ bytes = (slice_num+1) * s->lowdelay.bytes.num / s->lowdelay.bytes.den
+ - slice_num * s->lowdelay.bytes.num / s->lowdelay.bytes.den;
+
+ slices[slice_num].bytes = bytes;
+ slices[slice_num].slice_x = slice_x;
+ slices[slice_num].slice_y = slice_y;
+ init_get_bits(&slices[slice_num].gb, buf, bufsize);
+ slice_num++;
+
+ buf += bytes;
+ if (bufsize/8 >= bytes)
+ bufsize -= bytes*8;
+ else
+ bufsize = 0;
+ }
+
+ avctx->execute(avctx, decode_lowdelay_slice, slices, NULL, slice_num,
+ sizeof(struct lowdelay_slice)); /* [DIRAC_STD] 13.5.2 Slices */
+ intra_dc_prediction(&s->plane[0].band[0][0]); /* [DIRAC_STD] 13.3 intra_dc_prediction() */
+ intra_dc_prediction(&s->plane[1].band[0][0]); /* [DIRAC_STD] 13.3 intra_dc_prediction() */
+ intra_dc_prediction(&s->plane[2].band[0][0]); /* [DIRAC_STD] 13.3 intra_dc_prediction() */
+ av_free(slices);
+ return 0;
+}
+
+static void init_planes(DiracContext *s)
+{
+ int i, w, h, level, orientation;
+
+ for (i = 0; i < 3; i++) {
+ Plane *p = &s->plane[i];
+
+ p->width = s->source.width >> (i ? s->chroma_x_shift : 0);
+ p->height = s->source.height >> (i ? s->chroma_y_shift : 0);
+ p->idwt_width = w = CALC_PADDING(p->width , s->wavelet_depth);
+ p->idwt_height = h = CALC_PADDING(p->height, s->wavelet_depth);
+ p->idwt_stride = FFALIGN(p->idwt_width, 8);
+
+ for (level = s->wavelet_depth-1; level >= 0; level--) {
+ w = w>>1;
+ h = h>>1;
+ for (orientation = !!level; orientation < 4; orientation++) {
+ SubBand *b = &p->band[level][orientation];
+
+ b->ibuf = p->idwt_buf;
+ b->level = level;
+ b->stride = p->idwt_stride << (s->wavelet_depth - level);
+ b->width = w;
+ b->height = h;
+ b->orientation = orientation;
+
+ if (orientation & 1)
+ b->ibuf += w;
+ if (orientation > 1)
+ b->ibuf += b->stride>>1;
+
+ if (level)
+ b->parent = &p->band[level-1][orientation];
+ }
+ }
+
+ if (i > 0) {
+ p->xblen = s->plane[0].xblen >> s->chroma_x_shift;
+ p->yblen = s->plane[0].yblen >> s->chroma_y_shift;
+ p->xbsep = s->plane[0].xbsep >> s->chroma_x_shift;
+ p->ybsep = s->plane[0].ybsep >> s->chroma_y_shift;
+ }
+
+ p->xoffset = (p->xblen - p->xbsep)/2;
+ p->yoffset = (p->yblen - p->ybsep)/2;
+ }
+}
+
+/**
+ * Unpack the motion compensation parameters
+ * Dirac Specification ->
+ * 11.2 Picture prediction data. picture_prediction()
+ */
+static int dirac_unpack_prediction_parameters(DiracContext *s)
+{
+ static const uint8_t default_blen[] = { 4, 12, 16, 24 };
+
+ GetBitContext *gb = &s->gb;
+ unsigned idx, ref;
+
+ align_get_bits(gb);
+ /* [DIRAC_STD] 11.2.2 Block parameters. block_parameters() */
+ /* Luma and Chroma are equal. 11.2.3 */
+ idx = svq3_get_ue_golomb(gb); /* [DIRAC_STD] index */
+
+ if (idx > 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "Block prediction index too high\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (idx == 0) {
+ s->plane[0].xblen = svq3_get_ue_golomb(gb);
+ s->plane[0].yblen = svq3_get_ue_golomb(gb);
+ s->plane[0].xbsep = svq3_get_ue_golomb(gb);
+ s->plane[0].ybsep = svq3_get_ue_golomb(gb);
+ } else {
+ /*[DIRAC_STD] preset_block_params(index). Table 11.1 */
+ s->plane[0].xblen = default_blen[idx-1];
+ s->plane[0].yblen = default_blen[idx-1];
+ s->plane[0].xbsep = 4 * idx;
+ s->plane[0].ybsep = 4 * idx;
+ }
+ /*[DIRAC_STD] 11.2.4 motion_data_dimensions()
+ Calculated in function dirac_unpack_block_motion_data */
+
+ if (s->plane[0].xblen % (1 << s->chroma_x_shift) != 0 ||
+ s->plane[0].yblen % (1 << s->chroma_y_shift) != 0 ||
+ !s->plane[0].xblen || !s->plane[0].yblen) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "invalid x/y block length (%d/%d) for x/y chroma shift (%d/%d)\n",
+ s->plane[0].xblen, s->plane[0].yblen, s->chroma_x_shift, s->chroma_y_shift);
+ return AVERROR_INVALIDDATA;
+ }
+ if (!s->plane[0].xbsep || !s->plane[0].ybsep || s->plane[0].xbsep < s->plane[0].xblen/2 || s->plane[0].ybsep < s->plane[0].yblen/2) {
+ av_log(s->avctx, AV_LOG_ERROR, "Block separation too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (s->plane[0].xbsep > s->plane[0].xblen || s->plane[0].ybsep > s->plane[0].yblen) {
+ av_log(s->avctx, AV_LOG_ERROR, "Block separation greater than size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (FFMAX(s->plane[0].xblen, s->plane[0].yblen) > MAX_BLOCKSIZE) {
+ av_log(s->avctx, AV_LOG_ERROR, "Unsupported large block size\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ /*[DIRAC_STD] 11.2.5 Motion vector precision. motion_vector_precision()
+ Read motion vector precision */
+ s->mv_precision = svq3_get_ue_golomb(gb);
+ if (s->mv_precision > 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "MV precision finer than eighth-pel\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /*[DIRAC_STD] 11.2.6 Global motion. global_motion()
+ Read the global motion compensation parameters */
+ s->globalmc_flag = get_bits1(gb);
+ if (s->globalmc_flag) {
+ memset(s->globalmc, 0, sizeof(s->globalmc));
+ /* [DIRAC_STD] pan_tilt(gparams) */
+ for (ref = 0; ref < s->num_refs; ref++) {
+ if (get_bits1(gb)) {
+ s->globalmc[ref].pan_tilt[0] = dirac_get_se_golomb(gb);
+ s->globalmc[ref].pan_tilt[1] = dirac_get_se_golomb(gb);
+ }
+ /* [DIRAC_STD] zoom_rotate_shear(gparams)
+ zoom/rotation/shear parameters */
+ if (get_bits1(gb)) {
+ s->globalmc[ref].zrs_exp = svq3_get_ue_golomb(gb);
+ s->globalmc[ref].zrs[0][0] = dirac_get_se_golomb(gb);
+ s->globalmc[ref].zrs[0][1] = dirac_get_se_golomb(gb);
+ s->globalmc[ref].zrs[1][0] = dirac_get_se_golomb(gb);
+ s->globalmc[ref].zrs[1][1] = dirac_get_se_golomb(gb);
+ } else {
+ s->globalmc[ref].zrs[0][0] = 1;
+ s->globalmc[ref].zrs[1][1] = 1;
+ }
+ /* [DIRAC_STD] perspective(gparams) */
+ if (get_bits1(gb)) {
+ s->globalmc[ref].perspective_exp = svq3_get_ue_golomb(gb);
+ s->globalmc[ref].perspective[0] = dirac_get_se_golomb(gb);
+ s->globalmc[ref].perspective[1] = dirac_get_se_golomb(gb);
+ }
+ }
+ }
+
+ /*[DIRAC_STD] 11.2.7 Picture prediction mode. prediction_mode()
+ Picture prediction mode, not currently used. */
+ if (svq3_get_ue_golomb(gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Unknown picture prediction mode\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* [DIRAC_STD] 11.2.8 Reference picture weight. reference_picture_weights()
+ just data read, weight calculation will be done later on. */
+ s->weight_log2denom = 1;
+ s->weight[0] = 1;
+ s->weight[1] = 1;
+
+ if (get_bits1(gb)) {
+ s->weight_log2denom = svq3_get_ue_golomb(gb);
+ s->weight[0] = dirac_get_se_golomb(gb);
+ if (s->num_refs == 2)
+ s->weight[1] = dirac_get_se_golomb(gb);
+ }
+ return 0;
+}
+
+/**
+ * Dirac Specification ->
+ * 11.3 Wavelet transform data. wavelet_transform()
+ */
+static int dirac_unpack_idwt_params(DiracContext *s)
+{
+ GetBitContext *gb = &s->gb;
+ int i, level;
+ unsigned tmp;
+
+#define CHECKEDREAD(dst, cond, errmsg) \
+ tmp = svq3_get_ue_golomb(gb); \
+ if (cond) { \
+ av_log(s->avctx, AV_LOG_ERROR, errmsg); \
+ return AVERROR_INVALIDDATA; \
+ }\
+ dst = tmp;
+
+ align_get_bits(gb);
+
+ s->zero_res = s->num_refs ? get_bits1(gb) : 0;
+ if (s->zero_res)
+ return 0;
+
+ /*[DIRAC_STD] 11.3.1 Transform parameters. transform_parameters() */
+ CHECKEDREAD(s->wavelet_idx, tmp > 6, "wavelet_idx is too big\n")
+
+ CHECKEDREAD(s->wavelet_depth, tmp > MAX_DWT_LEVELS || tmp < 1, "invalid number of DWT decompositions\n")
+
+ if (!s->low_delay) {
+ /* Codeblock parameters (core syntax only) */
+ if (get_bits1(gb)) {
+ for (i = 0; i <= s->wavelet_depth; i++) {
+ CHECKEDREAD(s->codeblock[i].width , tmp < 1 || tmp > (s->avctx->width >>s->wavelet_depth-i), "codeblock width invalid\n")
+ CHECKEDREAD(s->codeblock[i].height, tmp < 1 || tmp > (s->avctx->height>>s->wavelet_depth-i), "codeblock height invalid\n")
+ }
+
+ CHECKEDREAD(s->codeblock_mode, tmp > 1, "unknown codeblock mode\n")
+ } else
+ for (i = 0; i <= s->wavelet_depth; i++)
+ s->codeblock[i].width = s->codeblock[i].height = 1;
+ } else {
+ /* Slice parameters + quantization matrix*/
+ /*[DIRAC_STD] 11.3.4 Slice coding Parameters (low delay syntax only). slice_parameters() */
+ s->lowdelay.num_x = svq3_get_ue_golomb(gb);
+ s->lowdelay.num_y = svq3_get_ue_golomb(gb);
+ s->lowdelay.bytes.num = svq3_get_ue_golomb(gb);
+ s->lowdelay.bytes.den = svq3_get_ue_golomb(gb);
+
+ if (s->lowdelay.bytes.den <= 0) {
+ av_log(s->avctx,AV_LOG_ERROR,"Invalid lowdelay.bytes.den\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* [DIRAC_STD] 11.3.5 Quantisation matrices (low-delay syntax). quant_matrix() */
+ if (get_bits1(gb)) {
+ av_log(s->avctx,AV_LOG_DEBUG,"Low Delay: Has Custom Quantization Matrix!\n");
+ /* custom quantization matrix */
+ s->lowdelay.quant[0][0] = svq3_get_ue_golomb(gb);
+ for (level = 0; level < s->wavelet_depth; level++) {
+ s->lowdelay.quant[level][1] = svq3_get_ue_golomb(gb);
+ s->lowdelay.quant[level][2] = svq3_get_ue_golomb(gb);
+ s->lowdelay.quant[level][3] = svq3_get_ue_golomb(gb);
+ }
+ } else {
+ if (s->wavelet_depth > 4) {
+ av_log(s->avctx,AV_LOG_ERROR,"Mandatory custom low delay matrix missing for depth %d\n", s->wavelet_depth);
+ return AVERROR_INVALIDDATA;
+ }
+ /* default quantization matrix */
+ for (level = 0; level < s->wavelet_depth; level++)
+ for (i = 0; i < 4; i++) {
+ s->lowdelay.quant[level][i] = default_qmat[s->wavelet_idx][level][i];
+ /* haar with no shift differs for different depths */
+ if (s->wavelet_idx == 3)
+ s->lowdelay.quant[level][i] += 4*(s->wavelet_depth-1 - level);
+ }
+ }
+ }
+ return 0;
+}
+
+static inline int pred_sbsplit(uint8_t *sbsplit, int stride, int x, int y)
+{
+ static const uint8_t avgsplit[7] = { 0, 0, 1, 1, 1, 2, 2 };
+
+ if (!(x|y))
+ return 0;
+ else if (!y)
+ return sbsplit[-1];
+ else if (!x)
+ return sbsplit[-stride];
+
+ return avgsplit[sbsplit[-1] + sbsplit[-stride] + sbsplit[-stride-1]];
+}
+
+static inline int pred_block_mode(DiracBlock *block, int stride, int x, int y, int refmask)
+{
+ int pred;
+
+ if (!(x|y))
+ return 0;
+ else if (!y)
+ return block[-1].ref & refmask;
+ else if (!x)
+ return block[-stride].ref & refmask;
+
+ /* return the majority */
+ pred = (block[-1].ref & refmask) + (block[-stride].ref & refmask) + (block[-stride-1].ref & refmask);
+ return (pred >> 1) & refmask;
+}
+
+static inline void pred_block_dc(DiracBlock *block, int stride, int x, int y)
+{
+ int i, n = 0;
+
+ memset(block->u.dc, 0, sizeof(block->u.dc));
+
+ if (x && !(block[-1].ref & 3)) {
+ for (i = 0; i < 3; i++)
+ block->u.dc[i] += block[-1].u.dc[i];
+ n++;
+ }
+
+ if (y && !(block[-stride].ref & 3)) {
+ for (i = 0; i < 3; i++)
+ block->u.dc[i] += block[-stride].u.dc[i];
+ n++;
+ }
+
+ if (x && y && !(block[-1-stride].ref & 3)) {
+ for (i = 0; i < 3; i++)
+ block->u.dc[i] += block[-1-stride].u.dc[i];
+ n++;
+ }
+
+ if (n == 2) {
+ for (i = 0; i < 3; i++)
+ block->u.dc[i] = (block->u.dc[i]+1)>>1;
+ } else if (n == 3) {
+ for (i = 0; i < 3; i++)
+ block->u.dc[i] = divide3(block->u.dc[i]);
+ }
+}
+
+static inline void pred_mv(DiracBlock *block, int stride, int x, int y, int ref)
+{
+ int16_t *pred[3];
+ int refmask = ref+1;
+ int mask = refmask | DIRAC_REF_MASK_GLOBAL; /* exclude gmc blocks */
+ int n = 0;
+
+ if (x && (block[-1].ref & mask) == refmask)
+ pred[n++] = block[-1].u.mv[ref];
+
+ if (y && (block[-stride].ref & mask) == refmask)
+ pred[n++] = block[-stride].u.mv[ref];
+
+ if (x && y && (block[-stride-1].ref & mask) == refmask)
+ pred[n++] = block[-stride-1].u.mv[ref];
+
+ switch (n) {
+ case 0:
+ block->u.mv[ref][0] = 0;
+ block->u.mv[ref][1] = 0;
+ break;
+ case 1:
+ block->u.mv[ref][0] = pred[0][0];
+ block->u.mv[ref][1] = pred[0][1];
+ break;
+ case 2:
+ block->u.mv[ref][0] = (pred[0][0] + pred[1][0] + 1) >> 1;
+ block->u.mv[ref][1] = (pred[0][1] + pred[1][1] + 1) >> 1;
+ break;
+ case 3:
+ block->u.mv[ref][0] = mid_pred(pred[0][0], pred[1][0], pred[2][0]);
+ block->u.mv[ref][1] = mid_pred(pred[0][1], pred[1][1], pred[2][1]);
+ break;
+ }
+}
+
+static void global_mv(DiracContext *s, DiracBlock *block, int x, int y, int ref)
+{
+ int ez = s->globalmc[ref].zrs_exp;
+ int ep = s->globalmc[ref].perspective_exp;
+ int (*A)[2] = s->globalmc[ref].zrs;
+ int *b = s->globalmc[ref].pan_tilt;
+ int *c = s->globalmc[ref].perspective;
+
+ int m = (1<<ep) - (c[0]*x + c[1]*y);
+ int mx = m * ((A[0][0] * x + A[0][1]*y) + (1<<ez) * b[0]);
+ int my = m * ((A[1][0] * x + A[1][1]*y) + (1<<ez) * b[1]);
+
+ block->u.mv[ref][0] = (mx + (1<<(ez+ep))) >> (ez+ep);
+ block->u.mv[ref][1] = (my + (1<<(ez+ep))) >> (ez+ep);
+}
+
+static void decode_block_params(DiracContext *s, DiracArith arith[8], DiracBlock *block,
+ int stride, int x, int y)
+{
+ int i;
+
+ block->ref = pred_block_mode(block, stride, x, y, DIRAC_REF_MASK_REF1);
+ block->ref ^= dirac_get_arith_bit(arith, CTX_PMODE_REF1);
+
+ if (s->num_refs == 2) {
+ block->ref |= pred_block_mode(block, stride, x, y, DIRAC_REF_MASK_REF2);
+ block->ref ^= dirac_get_arith_bit(arith, CTX_PMODE_REF2) << 1;
+ }
+
+ if (!block->ref) {
+ pred_block_dc(block, stride, x, y);
+ for (i = 0; i < 3; i++)
+ block->u.dc[i] += dirac_get_arith_int(arith+1+i, CTX_DC_F1, CTX_DC_DATA);
+ return;
+ }
+
+ if (s->globalmc_flag) {
+ block->ref |= pred_block_mode(block, stride, x, y, DIRAC_REF_MASK_GLOBAL);
+ block->ref ^= dirac_get_arith_bit(arith, CTX_GLOBAL_BLOCK) << 2;
+ }
+
+ for (i = 0; i < s->num_refs; i++)
+ if (block->ref & (i+1)) {
+ if (block->ref & DIRAC_REF_MASK_GLOBAL) {
+ global_mv(s, block, x, y, i);
+ } else {
+ pred_mv(block, stride, x, y, i);
+ block->u.mv[i][0] += dirac_get_arith_int(arith + 4 + 2 * i, CTX_MV_F1, CTX_MV_DATA);
+ block->u.mv[i][1] += dirac_get_arith_int(arith + 5 + 2 * i, CTX_MV_F1, CTX_MV_DATA);
+ }
+ }
+}
+
+/**
+ * Copies the current block to the other blocks covered by the current superblock split mode
+ */
+static void propagate_block_data(DiracBlock *block, int stride, int size)
+{
+ int x, y;
+ DiracBlock *dst = block;
+
+ for (x = 1; x < size; x++)
+ dst[x] = *block;
+
+ for (y = 1; y < size; y++) {
+ dst += stride;
+ for (x = 0; x < size; x++)
+ dst[x] = *block;
+ }
+}
+
+/**
+ * Dirac Specification ->
+ * 12. Block motion data syntax
+ */
+static int dirac_unpack_block_motion_data(DiracContext *s)
+{
+ GetBitContext *gb = &s->gb;
+ uint8_t *sbsplit = s->sbsplit;
+ int i, x, y, q, p;
+ DiracArith arith[8];
+
+ align_get_bits(gb);
+
+ /* [DIRAC_STD] 11.2.4 and 12.2.1 Number of blocks and superblocks */
+ s->sbwidth = DIVRNDUP(s->source.width, 4*s->plane[0].xbsep);
+ s->sbheight = DIVRNDUP(s->source.height, 4*s->plane[0].ybsep);
+ s->blwidth = 4 * s->sbwidth;
+ s->blheight = 4 * s->sbheight;
+
+ /* [DIRAC_STD] 12.3.1 Superblock splitting modes. superblock_split_modes()
+ decode superblock split modes */
+ ff_dirac_init_arith_decoder(arith, gb, svq3_get_ue_golomb(gb)); /* svq3_get_ue_golomb(gb) is the length */
+ for (y = 0; y < s->sbheight; y++) {
+ for (x = 0; x < s->sbwidth; x++) {
+ unsigned int split = dirac_get_arith_uint(arith, CTX_SB_F1, CTX_SB_DATA);
+ if (split > 2)
+ return AVERROR_INVALIDDATA;
+ sbsplit[x] = (split + pred_sbsplit(sbsplit+x, s->sbwidth, x, y)) % 3;
+ }
+ sbsplit += s->sbwidth;
+ }
+
+ /* setup arith decoding */
+ ff_dirac_init_arith_decoder(arith, gb, svq3_get_ue_golomb(gb));
+ for (i = 0; i < s->num_refs; i++) {
+ ff_dirac_init_arith_decoder(arith + 4 + 2 * i, gb, svq3_get_ue_golomb(gb));
+ ff_dirac_init_arith_decoder(arith + 5 + 2 * i, gb, svq3_get_ue_golomb(gb));
+ }
+ for (i = 0; i < 3; i++)
+ ff_dirac_init_arith_decoder(arith+1+i, gb, svq3_get_ue_golomb(gb));
+
+ for (y = 0; y < s->sbheight; y++)
+ for (x = 0; x < s->sbwidth; x++) {
+ int blkcnt = 1 << s->sbsplit[y * s->sbwidth + x];
+ int step = 4 >> s->sbsplit[y * s->sbwidth + x];
+
+ for (q = 0; q < blkcnt; q++)
+ for (p = 0; p < blkcnt; p++) {
+ int bx = 4 * x + p*step;
+ int by = 4 * y + q*step;
+ DiracBlock *block = &s->blmotion[by*s->blwidth + bx];
+ decode_block_params(s, arith, block, s->blwidth, bx, by);
+ propagate_block_data(block, s->blwidth, step);
+ }
+ }
+
+ return 0;
+}
+
+static int weight(int i, int blen, int offset)
+{
+#define ROLLOFF(i) offset == 1 ? ((i) ? 5 : 3) : \
+ (1 + (6*(i) + offset - 1) / (2*offset - 1))
+
+ if (i < 2*offset)
+ return ROLLOFF(i);
+ else if (i > blen-1 - 2*offset)
+ return ROLLOFF(blen-1 - i);
+ return 8;
+}
+
+static void init_obmc_weight_row(Plane *p, uint8_t *obmc_weight, int stride,
+ int left, int right, int wy)
+{
+ int x;
+ for (x = 0; left && x < p->xblen >> 1; x++)
+ obmc_weight[x] = wy*8;
+ for (; x < p->xblen >> right; x++)
+ obmc_weight[x] = wy*weight(x, p->xblen, p->xoffset);
+ for (; x < p->xblen; x++)
+ obmc_weight[x] = wy*8;
+ for (; x < stride; x++)
+ obmc_weight[x] = 0;
+}
+
+static void init_obmc_weight(Plane *p, uint8_t *obmc_weight, int stride,
+ int left, int right, int top, int bottom)
+{
+ int y;
+ for (y = 0; top && y < p->yblen >> 1; y++) {
+ init_obmc_weight_row(p, obmc_weight, stride, left, right, 8);
+ obmc_weight += stride;
+ }
+ for (; y < p->yblen >> bottom; y++) {
+ int wy = weight(y, p->yblen, p->yoffset);
+ init_obmc_weight_row(p, obmc_weight, stride, left, right, wy);
+ obmc_weight += stride;
+ }
+ for (; y < p->yblen; y++) {
+ init_obmc_weight_row(p, obmc_weight, stride, left, right, 8);
+ obmc_weight += stride;
+ }
+}
+
+static void init_obmc_weights(DiracContext *s, Plane *p, int by)
+{
+ int top = !by;
+ int bottom = by == s->blheight-1;
+
+ /* don't bother re-initing for rows 2 to blheight-2, the weights don't change */
+ if (top || bottom || by == 1) {
+ init_obmc_weight(p, s->obmc_weight[0], MAX_BLOCKSIZE, 1, 0, top, bottom);
+ init_obmc_weight(p, s->obmc_weight[1], MAX_BLOCKSIZE, 0, 0, top, bottom);
+ init_obmc_weight(p, s->obmc_weight[2], MAX_BLOCKSIZE, 0, 1, top, bottom);
+ }
+}
+
+static const uint8_t epel_weights[4][4][4] = {
+ {{ 16, 0, 0, 0 },
+ { 12, 4, 0, 0 },
+ { 8, 8, 0, 0 },
+ { 4, 12, 0, 0 }},
+ {{ 12, 0, 4, 0 },
+ { 9, 3, 3, 1 },
+ { 6, 6, 2, 2 },
+ { 3, 9, 1, 3 }},
+ {{ 8, 0, 8, 0 },
+ { 6, 2, 6, 2 },
+ { 4, 4, 4, 4 },
+ { 2, 6, 2, 6 }},
+ {{ 4, 0, 12, 0 },
+ { 3, 1, 9, 3 },
+ { 2, 2, 6, 6 },
+ { 1, 3, 3, 9 }}
+};
+
+/**
+ * For block x,y, determine which of the hpel planes to do bilinear
+ * interpolation from and set src[] to the location in each hpel plane
+ * to MC from.
+ *
+ * @return the index of the put_dirac_pixels_tab function to use
+ * 0 for 1 plane (fpel,hpel), 1 for 2 planes (qpel), 2 for 4 planes (qpel), and 3 for epel
+ */
+static int mc_subpel(DiracContext *s, DiracBlock *block, const uint8_t *src[5],
+ int x, int y, int ref, int plane)
+{
+ Plane *p = &s->plane[plane];
+ uint8_t **ref_hpel = s->ref_pics[ref]->hpel[plane];
+ int motion_x = block->u.mv[ref][0];
+ int motion_y = block->u.mv[ref][1];
+ int mx, my, i, epel, nplanes = 0;
+
+ if (plane) {
+ motion_x >>= s->chroma_x_shift;
+ motion_y >>= s->chroma_y_shift;
+ }
+
+ mx = motion_x & ~(-1U << s->mv_precision);
+ my = motion_y & ~(-1U << s->mv_precision);
+ motion_x >>= s->mv_precision;
+ motion_y >>= s->mv_precision;
+ /* normalize subpel coordinates to epel */
+ /* TODO: template this function? */
+ mx <<= 3 - s->mv_precision;
+ my <<= 3 - s->mv_precision;
+
+ x += motion_x;
+ y += motion_y;
+ epel = (mx|my)&1;
+
+ /* hpel position */
+ if (!((mx|my)&3)) {
+ nplanes = 1;
+ src[0] = ref_hpel[(my>>1)+(mx>>2)] + y*p->stride + x;
+ } else {
+ /* qpel or epel */
+ nplanes = 4;
+ for (i = 0; i < 4; i++)
+ src[i] = ref_hpel[i] + y*p->stride + x;
+
+ /* if we're interpolating in the right/bottom halves, adjust the planes as needed
+ we increment x/y because the edge changes for half of the pixels */
+ if (mx > 4) {
+ src[0] += 1;
+ src[2] += 1;
+ x++;
+ }
+ if (my > 4) {
+ src[0] += p->stride;
+ src[1] += p->stride;
+ y++;
+ }
+
+ /* hpel planes are:
+ [0]: F [1]: H
+ [2]: V [3]: C */
+ if (!epel) {
+ /* check if we really only need 2 planes since either mx or my is
+ a hpel position. (epel weights of 0 handle this there) */
+ if (!(mx&3)) {
+ /* mx == 0: average [0] and [2]
+ mx == 4: average [1] and [3] */
+ src[!mx] = src[2 + !!mx];
+ nplanes = 2;
+ } else if (!(my&3)) {
+ src[0] = src[(my>>1) ];
+ src[1] = src[(my>>1)+1];
+ nplanes = 2;
+ }
+ } else {
+ /* adjust the ordering if needed so the weights work */
+ if (mx > 4) {
+ FFSWAP(const uint8_t *, src[0], src[1]);
+ FFSWAP(const uint8_t *, src[2], src[3]);
+ }
+ if (my > 4) {
+ FFSWAP(const uint8_t *, src[0], src[2]);
+ FFSWAP(const uint8_t *, src[1], src[3]);
+ }
+ src[4] = epel_weights[my&3][mx&3];
+ }
+ }
+
+ /* fixme: v/h _edge_pos */
+ if (x + p->xblen > p->width +EDGE_WIDTH/2 ||
+ y + p->yblen > p->height+EDGE_WIDTH/2 ||
+ x < 0 || y < 0) {
+ for (i = 0; i < nplanes; i++) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer[i], src[i],
+ p->stride, p->stride,
+ p->xblen, p->yblen, x, y,
+ p->width+EDGE_WIDTH/2, p->height+EDGE_WIDTH/2);
+ src[i] = s->edge_emu_buffer[i];
+ }
+ }
+ return (nplanes>>1) + epel;
+}
+
+static void add_dc(uint16_t *dst, int dc, int stride,
+ uint8_t *obmc_weight, int xblen, int yblen)
+{
+ int x, y;
+ dc += 128;
+
+ for (y = 0; y < yblen; y++) {
+ for (x = 0; x < xblen; x += 2) {
+ dst[x ] += dc * obmc_weight[x ];
+ dst[x+1] += dc * obmc_weight[x+1];
+ }
+ dst += stride;
+ obmc_weight += MAX_BLOCKSIZE;
+ }
+}
+
+static void block_mc(DiracContext *s, DiracBlock *block,
+ uint16_t *mctmp, uint8_t *obmc_weight,
+ int plane, int dstx, int dsty)
+{
+ Plane *p = &s->plane[plane];
+ const uint8_t *src[5];
+ int idx;
+
+ switch (block->ref&3) {
+ case 0: /* DC */
+ add_dc(mctmp, block->u.dc[plane], p->stride, obmc_weight, p->xblen, p->yblen);
+ return;
+ case 1:
+ case 2:
+ idx = mc_subpel(s, block, src, dstx, dsty, (block->ref&3)-1, plane);
+ s->put_pixels_tab[idx](s->mcscratch, src, p->stride, p->yblen);
+ if (s->weight_func)
+ s->weight_func(s->mcscratch, p->stride, s->weight_log2denom,
+ s->weight[0] + s->weight[1], p->yblen);
+ break;
+ case 3:
+ idx = mc_subpel(s, block, src, dstx, dsty, 0, plane);
+ s->put_pixels_tab[idx](s->mcscratch, src, p->stride, p->yblen);
+ idx = mc_subpel(s, block, src, dstx, dsty, 1, plane);
+ if (s->biweight_func) {
+ /* fixme: +32 is a quick hack */
+ s->put_pixels_tab[idx](s->mcscratch + 32, src, p->stride, p->yblen);
+ s->biweight_func(s->mcscratch, s->mcscratch+32, p->stride, s->weight_log2denom,
+ s->weight[0], s->weight[1], p->yblen);
+ } else
+ s->avg_pixels_tab[idx](s->mcscratch, src, p->stride, p->yblen);
+ break;
+ }
+ s->add_obmc(mctmp, s->mcscratch, p->stride, obmc_weight, p->yblen);
+}
+
+static void mc_row(DiracContext *s, DiracBlock *block, uint16_t *mctmp, int plane, int dsty)
+{
+ Plane *p = &s->plane[plane];
+ int x, dstx = p->xbsep - p->xoffset;
+
+ block_mc(s, block, mctmp, s->obmc_weight[0], plane, -p->xoffset, dsty);
+ mctmp += p->xbsep;
+
+ for (x = 1; x < s->blwidth-1; x++) {
+ block_mc(s, block+x, mctmp, s->obmc_weight[1], plane, dstx, dsty);
+ dstx += p->xbsep;
+ mctmp += p->xbsep;
+ }
+ block_mc(s, block+x, mctmp, s->obmc_weight[2], plane, dstx, dsty);
+}
+
+static void select_dsp_funcs(DiracContext *s, int width, int height, int xblen, int yblen)
+{
+ int idx = 0;
+ if (xblen > 8)
+ idx = 1;
+ if (xblen > 16)
+ idx = 2;
+
+ memcpy(s->put_pixels_tab, s->diracdsp.put_dirac_pixels_tab[idx], sizeof(s->put_pixels_tab));
+ memcpy(s->avg_pixels_tab, s->diracdsp.avg_dirac_pixels_tab[idx], sizeof(s->avg_pixels_tab));
+ s->add_obmc = s->diracdsp.add_dirac_obmc[idx];
+ if (s->weight_log2denom > 1 || s->weight[0] != 1 || s->weight[1] != 1) {
+ s->weight_func = s->diracdsp.weight_dirac_pixels_tab[idx];
+ s->biweight_func = s->diracdsp.biweight_dirac_pixels_tab[idx];
+ } else {
+ s->weight_func = NULL;
+ s->biweight_func = NULL;
+ }
+}
+
+static void interpolate_refplane(DiracContext *s, DiracFrame *ref, int plane, int width, int height)
+{
+ /* chroma allocates an edge of 8 when subsampled
+ which for 4:2:2 means an h edge of 16 and v edge of 8
+ just use 8 for everything for the moment */
+ int i, edge = EDGE_WIDTH/2;
+
+ ref->hpel[plane][0] = ref->avframe->data[plane];
+ s->mpvencdsp.draw_edges(ref->hpel[plane][0], ref->avframe->linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM); /* EDGE_TOP | EDGE_BOTTOM values just copied to make it build, this needs to be ensured */
+
+ /* no need for hpel if we only have fpel vectors */
+ if (!s->mv_precision)
+ return;
+
+ for (i = 1; i < 4; i++) {
+ if (!ref->hpel_base[plane][i])
+ ref->hpel_base[plane][i] = av_malloc((height+2*edge) * ref->avframe->linesize[plane] + 32);
+ /* we need to be 16-byte aligned even for chroma */
+ ref->hpel[plane][i] = ref->hpel_base[plane][i] + edge*ref->avframe->linesize[plane] + 16;
+ }
+
+ if (!ref->interpolated[plane]) {
+ s->diracdsp.dirac_hpel_filter(ref->hpel[plane][1], ref->hpel[plane][2],
+ ref->hpel[plane][3], ref->hpel[plane][0],
+ ref->avframe->linesize[plane], width, height);
+ s->mpvencdsp.draw_edges(ref->hpel[plane][1], ref->avframe->linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+ s->mpvencdsp.draw_edges(ref->hpel[plane][2], ref->avframe->linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+ s->mpvencdsp.draw_edges(ref->hpel[plane][3], ref->avframe->linesize[plane], width, height, edge, edge, EDGE_TOP | EDGE_BOTTOM);
+ }
+ ref->interpolated[plane] = 1;
+}
+
+/**
+ * Dirac Specification ->
+ * 13.0 Transform data syntax. transform_data()
+ */
+static int dirac_decode_frame_internal(DiracContext *s)
+{
+ DWTContext d;
+ int y, i, comp, dsty;
+ int ret;
+
+ if (s->low_delay) {
+ /* [DIRAC_STD] 13.5.1 low_delay_transform_data() */
+ for (comp = 0; comp < 3; comp++) {
+ Plane *p = &s->plane[comp];
+ memset(p->idwt_buf, 0, p->idwt_stride * p->idwt_height * sizeof(IDWTELEM));
+ }
+ if (!s->zero_res) {
+ if ((ret = decode_lowdelay(s)) < 0)
+ return ret;
+ }
+ }
+
+ for (comp = 0; comp < 3; comp++) {
+ Plane *p = &s->plane[comp];
+ uint8_t *frame = s->current_picture->avframe->data[comp];
+
+ /* FIXME: small resolutions */
+ for (i = 0; i < 4; i++)
+ s->edge_emu_buffer[i] = s->edge_emu_buffer_base + i*FFALIGN(p->width, 16);
+
+ if (!s->zero_res && !s->low_delay)
+ {
+ memset(p->idwt_buf, 0, p->idwt_stride * p->idwt_height * sizeof(IDWTELEM));
+ decode_component(s, comp); /* [DIRAC_STD] 13.4.1 core_transform_data() */
+ }
+ ret = ff_spatial_idwt_init2(&d, p->idwt_buf, p->idwt_width, p->idwt_height, p->idwt_stride,
+ s->wavelet_idx+2, s->wavelet_depth, p->idwt_tmp);
+ if (ret < 0)
+ return ret;
+
+ if (!s->num_refs) { /* intra */
+ for (y = 0; y < p->height; y += 16) {
+ ff_spatial_idwt_slice2(&d, y+16); /* decode */
+ s->diracdsp.put_signed_rect_clamped(frame + y*p->stride, p->stride,
+ p->idwt_buf + y*p->idwt_stride, p->idwt_stride, p->width, 16);
+ }
+ } else { /* inter */
+ int rowheight = p->ybsep*p->stride;
+
+ select_dsp_funcs(s, p->width, p->height, p->xblen, p->yblen);
+
+ for (i = 0; i < s->num_refs; i++)
+ interpolate_refplane(s, s->ref_pics[i], comp, p->width, p->height);
+
+ memset(s->mctmp, 0, 4*p->yoffset*p->stride);
+
+ dsty = -p->yoffset;
+ for (y = 0; y < s->blheight; y++) {
+ int h = 0,
+ start = FFMAX(dsty, 0);
+ uint16_t *mctmp = s->mctmp + y*rowheight;
+ DiracBlock *blocks = s->blmotion + y*s->blwidth;
+
+ init_obmc_weights(s, p, y);
+
+ if (y == s->blheight-1 || start+p->ybsep > p->height)
+ h = p->height - start;
+ else
+ h = p->ybsep - (start - dsty);
+ if (h < 0)
+ break;
+
+ memset(mctmp+2*p->yoffset*p->stride, 0, 2*rowheight);
+ mc_row(s, blocks, mctmp, comp, dsty);
+
+ mctmp += (start - dsty)*p->stride + p->xoffset;
+ ff_spatial_idwt_slice2(&d, start + h); /* decode */
+ s->diracdsp.add_rect_clamped(frame + start*p->stride, mctmp, p->stride,
+ p->idwt_buf + start*p->idwt_stride, p->idwt_stride, p->width, h);
+
+ dsty += p->ybsep;
+ }
+ }
+ }
+
+
+ return 0;
+}
+
+static int get_buffer_with_edge(AVCodecContext *avctx, AVFrame *f, int flags)
+{
+ int ret, i;
+ int chroma_x_shift, chroma_y_shift;
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &chroma_x_shift, &chroma_y_shift);
+
+ f->width = avctx->width + 2 * EDGE_WIDTH;
+ f->height = avctx->height + 2 * EDGE_WIDTH + 2;
+ ret = ff_get_buffer(avctx, f, flags);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; f->data[i]; i++) {
+ int offset = (EDGE_WIDTH >> (i && i<3 ? chroma_y_shift : 0)) *
+ f->linesize[i] + 32;
+ f->data[i] += offset;
+ }
+ f->width = avctx->width;
+ f->height = avctx->height;
+
+ return 0;
+}
+
+/**
+ * Dirac Specification ->
+ * 11.1.1 Picture Header. picture_header()
+ */
+static int dirac_decode_picture_header(DiracContext *s)
+{
+ unsigned retire, picnum;
+ int i, j, ret;
+ int64_t refdist, refnum;
+ GetBitContext *gb = &s->gb;
+
+ /* [DIRAC_STD] 11.1.1 Picture Header. picture_header() PICTURE_NUM */
+ picnum = s->current_picture->avframe->display_picture_number = get_bits_long(gb, 32);
+
+
+ av_log(s->avctx,AV_LOG_DEBUG,"PICTURE_NUM: %d\n",picnum);
+
+ /* if this is the first keyframe after a sequence header, start our
+ reordering from here */
+ if (s->frame_number < 0)
+ s->frame_number = picnum;
+
+ s->ref_pics[0] = s->ref_pics[1] = NULL;
+ for (i = 0; i < s->num_refs; i++) {
+ refnum = (picnum + dirac_get_se_golomb(gb)) & 0xFFFFFFFF;
+ refdist = INT64_MAX;
+
+ /* find the closest reference to the one we want */
+ /* Jordi: this is needed if the referenced picture hasn't yet arrived */
+ for (j = 0; j < MAX_REFERENCE_FRAMES && refdist; j++)
+ if (s->ref_frames[j]
+ && FFABS(s->ref_frames[j]->avframe->display_picture_number - refnum) < refdist) {
+ s->ref_pics[i] = s->ref_frames[j];
+ refdist = FFABS(s->ref_frames[j]->avframe->display_picture_number - refnum);
+ }
+
+ if (!s->ref_pics[i] || refdist)
+ av_log(s->avctx, AV_LOG_DEBUG, "Reference not found\n");
+
+ /* if there were no references at all, allocate one */
+ if (!s->ref_pics[i])
+ for (j = 0; j < MAX_FRAMES; j++)
+ if (!s->all_frames[j].avframe->data[0]) {
+ s->ref_pics[i] = &s->all_frames[j];
+ get_buffer_with_edge(s->avctx, s->ref_pics[i]->avframe, AV_GET_BUFFER_FLAG_REF);
+ break;
+ }
+
+ if (!s->ref_pics[i]) {
+ av_log(s->avctx, AV_LOG_ERROR, "Reference could not be allocated\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ }
+
+ /* retire the reference frames that are not used anymore */
+ if (s->current_picture->avframe->reference) {
+ retire = (picnum + dirac_get_se_golomb(gb)) & 0xFFFFFFFF;
+ if (retire != picnum) {
+ DiracFrame *retire_pic = remove_frame(s->ref_frames, retire);
+
+ if (retire_pic)
+ retire_pic->avframe->reference &= DELAYED_PIC_REF;
+ else
+ av_log(s->avctx, AV_LOG_DEBUG, "Frame to retire not found\n");
+ }
+
+ /* if reference array is full, remove the oldest as per the spec */
+ while (add_frame(s->ref_frames, MAX_REFERENCE_FRAMES, s->current_picture)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Reference frame overflow\n");
+ remove_frame(s->ref_frames, s->ref_frames[0]->avframe->display_picture_number)->avframe->reference &= DELAYED_PIC_REF;
+ }
+ }
+
+ if (s->num_refs) {
+ ret = dirac_unpack_prediction_parameters(s); /* [DIRAC_STD] 11.2 Picture Prediction Data. picture_prediction() */
+ if (ret < 0)
+ return ret;
+ ret = dirac_unpack_block_motion_data(s); /* [DIRAC_STD] 12. Block motion data syntax */
+ if (ret < 0)
+ return ret;
+ }
+ ret = dirac_unpack_idwt_params(s); /* [DIRAC_STD] 11.3 Wavelet transform data */
+ if (ret < 0)
+ return ret;
+
+ init_planes(s);
+ return 0;
+}
+
+static int get_delayed_pic(DiracContext *s, AVFrame *picture, int *got_frame)
+{
+ DiracFrame *out = s->delay_frames[0];
+ int i, out_idx = 0;
+ int ret;
+
+ /* find frame with lowest picture number */
+ for (i = 1; s->delay_frames[i]; i++)
+ if (s->delay_frames[i]->avframe->display_picture_number < out->avframe->display_picture_number) {
+ out = s->delay_frames[i];
+ out_idx = i;
+ }
+
+ for (i = out_idx; s->delay_frames[i]; i++)
+ s->delay_frames[i] = s->delay_frames[i+1];
+
+ if (out) {
+ out->avframe->reference ^= DELAYED_PIC_REF;
+ *got_frame = 1;
+ if((ret = av_frame_ref(picture, out->avframe)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Dirac Specification ->
+ * 9.6 Parse Info Header Syntax. parse_info()
+ * 4 byte start code + byte parse code + 4 byte size + 4 byte previous size
+ */
+#define DATA_UNIT_HEADER_SIZE 13
+
+/* [DIRAC_STD] dirac_decode_data_unit makes reference to the while defined in 9.3
+ inside the function parse_sequence() */
+static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int size)
+{
+ DiracContext *s = avctx->priv_data;
+ DiracFrame *pic = NULL;
+ int ret, i, parse_code;
+ unsigned tmp;
+
+ if (size < DATA_UNIT_HEADER_SIZE)
+ return AVERROR_INVALIDDATA;
+
+ parse_code = buf[4];
+
+ init_get_bits(&s->gb, &buf[13], 8*(size - DATA_UNIT_HEADER_SIZE));
+
+ if (parse_code == pc_seq_header) {
+ if (s->seen_sequence_header)
+ return 0;
+
+ /* [DIRAC_STD] 10. Sequence header */
+ ret = avpriv_dirac_parse_sequence_header(avctx, &s->gb, &s->source);
+ if (ret < 0)
+ return ret;
+
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift);
+
+ ret = alloc_sequence_buffers(s);
+ if (ret < 0)
+ return ret;
+
+ s->seen_sequence_header = 1;
+ } else if (parse_code == pc_eos) { /* [DIRAC_STD] End of Sequence */
+ free_sequence_buffers(s);
+ s->seen_sequence_header = 0;
+ } else if (parse_code == pc_aux_data) {
+ if (buf[13] == 1) { /* encoder implementation/version */
+ int ver[3];
+ /* versions older than 1.0.8 don't store quant delta for
+ subbands with only one codeblock */
+ if (sscanf(buf+14, "Schroedinger %d.%d.%d", ver, ver+1, ver+2) == 3)
+ if (ver[0] == 1 && ver[1] == 0 && ver[2] <= 7)
+ s->old_delta_quant = 1;
+ }
+ } else if (parse_code & 0x8) { /* picture data unit */
+ if (!s->seen_sequence_header) {
+ av_log(avctx, AV_LOG_DEBUG, "Dropping frame without sequence header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* find an unused frame */
+ for (i = 0; i < MAX_FRAMES; i++)
+ if (s->all_frames[i].avframe->data[0] == NULL)
+ pic = &s->all_frames[i];
+ if (!pic) {
+ av_log(avctx, AV_LOG_ERROR, "framelist full\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ av_frame_unref(pic->avframe);
+
+ /* [DIRAC_STD] Defined in 9.6.1 ... */
+ tmp = parse_code & 0x03; /* [DIRAC_STD] num_refs() */
+ if (tmp > 2) {
+ av_log(avctx, AV_LOG_ERROR, "num_refs of 3\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->num_refs = tmp;
+ s->is_arith = (parse_code & 0x48) == 0x08; /* [DIRAC_STD] using_ac() */
+ s->low_delay = (parse_code & 0x88) == 0x88; /* [DIRAC_STD] is_low_delay() */
+ pic->avframe->reference = (parse_code & 0x0C) == 0x0C; /* [DIRAC_STD] is_reference() */
+ pic->avframe->key_frame = s->num_refs == 0; /* [DIRAC_STD] is_intra() */
+ pic->avframe->pict_type = s->num_refs + 1; /* Definition of AVPictureType in avutil.h */
+
+ if ((ret = get_buffer_with_edge(avctx, pic->avframe, (parse_code & 0x0C) == 0x0C ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
+ return ret;
+ s->current_picture = pic;
+ s->plane[0].stride = pic->avframe->linesize[0];
+ s->plane[1].stride = pic->avframe->linesize[1];
+ s->plane[2].stride = pic->avframe->linesize[2];
+
+ if (alloc_buffers(s, FFMAX3(FFABS(s->plane[0].stride), FFABS(s->plane[1].stride), FFABS(s->plane[2].stride))) < 0)
+ return AVERROR(ENOMEM);
+
+ /* [DIRAC_STD] 11.1 Picture parse. picture_parse() */
+ ret = dirac_decode_picture_header(s);
+ if (ret < 0)
+ return ret;
+
+ /* [DIRAC_STD] 13.0 Transform data syntax. transform_data() */
+ ret = dirac_decode_frame_internal(s);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int dirac_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *pkt)
+{
+ DiracContext *s = avctx->priv_data;
+ AVFrame *picture = data;
+ uint8_t *buf = pkt->data;
+ int buf_size = pkt->size;
+ int i, buf_idx = 0;
+ int ret;
+ unsigned data_unit_size;
+
+ /* release unused frames */
+ for (i = 0; i < MAX_FRAMES; i++)
+ if (s->all_frames[i].avframe->data[0] && !s->all_frames[i].avframe->reference) {
+ av_frame_unref(s->all_frames[i].avframe);
+ memset(s->all_frames[i].interpolated, 0, sizeof(s->all_frames[i].interpolated));
+ }
+
+ s->current_picture = NULL;
+ *got_frame = 0;
+
+ /* end of stream, so flush delayed pics */
+ if (buf_size == 0)
+ return get_delayed_pic(s, (AVFrame *)data, got_frame);
+
+ for (;;) {
+ /*[DIRAC_STD] Here starts the code from parse_info() defined in 9.6
+ [DIRAC_STD] PARSE_INFO_PREFIX = "BBCD" as defined in ISO/IEC 646
+ BBCD start code search */
+ for (; buf_idx + DATA_UNIT_HEADER_SIZE < buf_size; buf_idx++) {
+ if (buf[buf_idx ] == 'B' && buf[buf_idx+1] == 'B' &&
+ buf[buf_idx+2] == 'C' && buf[buf_idx+3] == 'D')
+ break;
+ }
+ /* BBCD found or end of data */
+ if (buf_idx + DATA_UNIT_HEADER_SIZE >= buf_size)
+ break;
+
+ data_unit_size = AV_RB32(buf+buf_idx+5);
+ if (data_unit_size > buf_size - buf_idx || !data_unit_size) {
+ if(data_unit_size > buf_size - buf_idx)
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Data unit with size %d is larger than input buffer, discarding\n",
+ data_unit_size);
+ buf_idx += 4;
+ continue;
+ }
+ /* [DIRAC_STD] dirac_decode_data_unit makes reference to the while defined in 9.3 inside the function parse_sequence() */
+ ret = dirac_decode_data_unit(avctx, buf+buf_idx, data_unit_size);
+ if (ret < 0)
+ {
+ av_log(s->avctx, AV_LOG_ERROR,"Error in dirac_decode_data_unit\n");
+ return ret;
+ }
+ buf_idx += data_unit_size;
+ }
+
+ if (!s->current_picture)
+ return buf_size;
+
+ if (s->current_picture->avframe->display_picture_number > s->frame_number) {
+ DiracFrame *delayed_frame = remove_frame(s->delay_frames, s->frame_number);
+
+ s->current_picture->avframe->reference |= DELAYED_PIC_REF;
+
+ if (add_frame(s->delay_frames, MAX_DELAY, s->current_picture)) {
+ int min_num = s->delay_frames[0]->avframe->display_picture_number;
+ /* Too many delayed frames, so we display the frame with the lowest pts */
+ av_log(avctx, AV_LOG_ERROR, "Delay frame overflow\n");
+
+ for (i = 1; s->delay_frames[i]; i++)
+ if (s->delay_frames[i]->avframe->display_picture_number < min_num)
+ min_num = s->delay_frames[i]->avframe->display_picture_number;
+
+ delayed_frame = remove_frame(s->delay_frames, min_num);
+ add_frame(s->delay_frames, MAX_DELAY, s->current_picture);
+ }
+
+ if (delayed_frame) {
+ delayed_frame->avframe->reference ^= DELAYED_PIC_REF;
+ if((ret=av_frame_ref(data, delayed_frame->avframe)) < 0)
+ return ret;
+ *got_frame = 1;
+ }
+ } else if (s->current_picture->avframe->display_picture_number == s->frame_number) {
+ /* The right frame at the right time :-) */
+ if((ret=av_frame_ref(data, s->current_picture->avframe)) < 0)
+ return ret;
+ *got_frame = 1;
+ }
+
+ if (*got_frame)
+ s->frame_number = picture->display_picture_number + 1;
+
+ return buf_idx;
+}
+
+AVCodec ff_dirac_decoder = {
+ .name = "dirac",
+ .long_name = NULL_IF_CONFIG_SMALL("BBC Dirac VC-2"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_DIRAC,
+ .priv_data_size = sizeof(DiracContext),
+ .init = dirac_decode_init,
+ .close = dirac_decode_end,
+ .decode = dirac_decode_frame,
+ .capabilities = CODEC_CAP_DELAY,
+ .flush = dirac_decode_flush,
+};
diff --git a/libavcodec/diracdsp.c b/libavcodec/diracdsp.c
new file mode 100644
index 0000000000..6b02779edb
--- /dev/null
+++ b/libavcodec/diracdsp.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2009 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "diracdsp.h"
+#include "libavcodec/x86/diracdsp_mmx.h"
+
+#define FILTER(src, stride) \
+ ((21*((src)[ 0*stride] + (src)[1*stride]) \
+ -7*((src)[-1*stride] + (src)[2*stride]) \
+ +3*((src)[-2*stride] + (src)[3*stride]) \
+ -1*((src)[-3*stride] + (src)[4*stride]) + 16) >> 5)
+
+static void dirac_hpel_filter(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, const uint8_t *src,
+ int stride, int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ for (x = -3; x < width+5; x++)
+ dstv[x] = av_clip_uint8(FILTER(src+x, stride));
+
+ for (x = 0; x < width; x++)
+ dstc[x] = av_clip_uint8(FILTER(dstv+x, 1));
+
+ for (x = 0; x < width; x++)
+ dsth[x] = av_clip_uint8(FILTER(src+x, 1));
+
+ src += stride;
+ dsth += stride;
+ dstv += stride;
+ dstc += stride;
+ }
+}
+
+#define PIXOP_BILINEAR(PFX, OP, WIDTH) \
+ static void ff_ ## PFX ## _dirac_pixels ## WIDTH ## _bilinear_c(uint8_t *dst, const uint8_t *src[5], int stride, int h) \
+ { \
+ int x; \
+ const uint8_t *s0 = src[0]; \
+ const uint8_t *s1 = src[1]; \
+ const uint8_t *s2 = src[2]; \
+ const uint8_t *s3 = src[3]; \
+ const uint8_t *w = src[4]; \
+ \
+ while (h--) { \
+ for (x = 0; x < WIDTH; x++) { \
+ OP(dst[x], (s0[x]*w[0] + s1[x]*w[1] + s2[x]*w[2] + s3[x]*w[3] + 8) >> 4); \
+ } \
+ \
+ dst += stride; \
+ s0 += stride; \
+ s1 += stride; \
+ s2 += stride; \
+ s3 += stride; \
+ } \
+ }
+
+#define OP_PUT(dst, val) (dst) = (val)
+#define OP_AVG(dst, val) (dst) = (((dst) + (val) + 1)>>1)
+
+PIXOP_BILINEAR(put, OP_PUT, 8)
+PIXOP_BILINEAR(put, OP_PUT, 16)
+PIXOP_BILINEAR(put, OP_PUT, 32)
+PIXOP_BILINEAR(avg, OP_AVG, 8)
+PIXOP_BILINEAR(avg, OP_AVG, 16)
+PIXOP_BILINEAR(avg, OP_AVG, 32)
+
+#define op_scale1(x) block[x] = av_clip_uint8( (block[x]*weight + (1<<(log2_denom-1))) >> log2_denom)
+#define op_scale2(x) dst[x] = av_clip_uint8( (src[x]*weights + dst[x]*weightd + (1<<(log2_denom-1))) >> log2_denom)
+
+#define DIRAC_WEIGHT(W) \
+ static void weight_dirac_pixels ## W ## _c(uint8_t *block, int stride, int log2_denom, \
+ int weight, int h) { \
+ int x; \
+ while (h--) { \
+ for (x = 0; x < W; x++) { \
+ op_scale1(x); \
+ op_scale1(x+1); \
+ } \
+ block += stride; \
+ } \
+ } \
+ static void biweight_dirac_pixels ## W ## _c(uint8_t *dst, const uint8_t *src, int stride, int log2_denom, \
+ int weightd, int weights, int h) { \
+ int x; \
+ while (h--) { \
+ for (x = 0; x < W; x++) { \
+ op_scale2(x); \
+ op_scale2(x+1); \
+ } \
+ dst += stride; \
+ src += stride; \
+ } \
+ }
+
+DIRAC_WEIGHT(8)
+DIRAC_WEIGHT(16)
+DIRAC_WEIGHT(32)
+
+#define ADD_OBMC(xblen) \
+ static void add_obmc ## xblen ## _c(uint16_t *dst, const uint8_t *src, int stride, \
+ const uint8_t *obmc_weight, int yblen) \
+ { \
+ int x; \
+ while (yblen--) { \
+ for (x = 0; x < xblen; x += 2) { \
+ dst[x ] += src[x ] * obmc_weight[x ]; \
+ dst[x+1] += src[x+1] * obmc_weight[x+1]; \
+ } \
+ dst += stride; \
+ src += stride; \
+ obmc_weight += 32; \
+ } \
+ }
+
+ADD_OBMC(8)
+ADD_OBMC(16)
+ADD_OBMC(32)
+
+static void put_signed_rect_clamped_c(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height)
+{
+ int x, y;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x+=4) {
+ dst[x ] = av_clip_uint8(src[x ] + 128);
+ dst[x+1] = av_clip_uint8(src[x+1] + 128);
+ dst[x+2] = av_clip_uint8(src[x+2] + 128);
+ dst[x+3] = av_clip_uint8(src[x+3] + 128);
+ }
+ dst += dst_stride;
+ src += src_stride;
+ }
+}
+
+static void add_rect_clamped_c(uint8_t *dst, const uint16_t *src, int stride,
+ const int16_t *idwt, int idwt_stride,
+ int width, int height)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x+=2) {
+ dst[x ] = av_clip_uint8(((src[x ]+32)>>6) + idwt[x ]);
+ dst[x+1] = av_clip_uint8(((src[x+1]+32)>>6) + idwt[x+1]);
+ }
+ dst += stride;
+ src += stride;
+ idwt += idwt_stride;
+ }
+}
+
+#define PIXFUNC(PFX, WIDTH) \
+ c->PFX ## _dirac_pixels_tab[WIDTH>>4][0] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _c; \
+ c->PFX ## _dirac_pixels_tab[WIDTH>>4][1] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _l2_c; \
+ c->PFX ## _dirac_pixels_tab[WIDTH>>4][2] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _l4_c; \
+ c->PFX ## _dirac_pixels_tab[WIDTH>>4][3] = ff_ ## PFX ## _dirac_pixels ## WIDTH ## _bilinear_c
+
+av_cold void ff_diracdsp_init(DiracDSPContext *c)
+{
+ c->dirac_hpel_filter = dirac_hpel_filter;
+ c->add_rect_clamped = add_rect_clamped_c;
+ c->put_signed_rect_clamped = put_signed_rect_clamped_c;
+
+ c->add_dirac_obmc[0] = add_obmc8_c;
+ c->add_dirac_obmc[1] = add_obmc16_c;
+ c->add_dirac_obmc[2] = add_obmc32_c;
+
+ c->weight_dirac_pixels_tab[0] = weight_dirac_pixels8_c;
+ c->weight_dirac_pixels_tab[1] = weight_dirac_pixels16_c;
+ c->weight_dirac_pixels_tab[2] = weight_dirac_pixels32_c;
+ c->biweight_dirac_pixels_tab[0] = biweight_dirac_pixels8_c;
+ c->biweight_dirac_pixels_tab[1] = biweight_dirac_pixels16_c;
+ c->biweight_dirac_pixels_tab[2] = biweight_dirac_pixels32_c;
+
+ PIXFUNC(put, 8);
+ PIXFUNC(put, 16);
+ PIXFUNC(put, 32);
+ PIXFUNC(avg, 8);
+ PIXFUNC(avg, 16);
+ PIXFUNC(avg, 32);
+
+ if (HAVE_MMX && HAVE_YASM) ff_diracdsp_init_mmx(c);
+}
diff --git a/libavcodec/diracdsp.h b/libavcodec/diracdsp.h
new file mode 100644
index 0000000000..613ca5bc83
--- /dev/null
+++ b/libavcodec/diracdsp.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_DIRACDSP_H
+#define AVCODEC_DIRACDSP_H
+
+#include <stdint.h>
+
+typedef void (*dirac_weight_func)(uint8_t *block, int stride, int log2_denom, int weight, int h);
+typedef void (*dirac_biweight_func)(uint8_t *dst, const uint8_t *src, int stride, int log2_denom, int weightd, int weights, int h);
+
+typedef struct {
+ void (*dirac_hpel_filter)(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, const uint8_t *src, int stride, int width, int height);
+ /**
+ * dirac_pixels_tab[width][subpel]
+ * width is 2 for 32, 1 for 16, 0 for 8
+ * subpel is 0 for fpel and hpel (only need to copy from the first plane in src)
+ * 1 if an average of the first 2 planes is needed (TODO: worth it?)
+ * 2 for general qpel (avg of 4)
+ * 3 for general epel (biweight of 4 using the weights in src[4])
+ * src[0-3] is each of the hpel planes
+ * src[4] is the 1/8 pel weights if needed
+ */
+ void (*put_dirac_pixels_tab[3][4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+ void (*avg_dirac_pixels_tab[3][4])(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+
+ void (*put_signed_rect_clamped)(uint8_t *dst/*align 16*/, int dst_stride, const int16_t *src/*align 16*/, int src_stride, int width, int height/*mod 2*/);
+ void (*put_rect_clamped)(uint8_t *dst/*align 16*/, int dst_stride, const int16_t *src/*align 16*/, int src_stride, int width, int height/*mod 2*/);
+ void (*add_rect_clamped)(uint8_t *dst/*align 16*/, const uint16_t *src/*align 16*/, int stride, const int16_t *idwt/*align 16*/, int idwt_stride, int width, int height/*mod 2*/);
+ void (*add_dirac_obmc[3])(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+
+ dirac_weight_func weight_dirac_pixels_tab[3];
+ dirac_biweight_func biweight_dirac_pixels_tab[3];
+} DiracDSPContext;
+
+#define DECL_DIRAC_PIXOP(PFX, EXT) \
+ void ff_ ## PFX ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h); \
+ void ff_ ## PFX ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h); \
+ void ff_ ## PFX ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+
+DECL_DIRAC_PIXOP(put, c);
+DECL_DIRAC_PIXOP(avg, c);
+DECL_DIRAC_PIXOP(put, l2_c);
+DECL_DIRAC_PIXOP(avg, l2_c);
+DECL_DIRAC_PIXOP(put, l4_c);
+DECL_DIRAC_PIXOP(avg, l4_c);
+
+void ff_diracdsp_init(DiracDSPContext *c);
+
+#endif /* AVCODEC_DIRACDSP_H */
diff --git a/libavcodec/dnxhd_parser.c b/libavcodec/dnxhd_parser.c
index 0de3561fc3..fffb98fa48 100644
--- a/libavcodec/dnxhd_parser.c
+++ b/libavcodec/dnxhd_parser.c
@@ -2,20 +2,20 @@
* DNxHD/VC-3 parser
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,21 +26,32 @@
#include "parser.h"
-#define DNXHD_HEADER_PREFIX 0x0000028001
+#define DNXHD_HEADER_PREFIX 0x000002800100
-static int dnxhd_find_frame_end(ParseContext *pc,
+typedef struct {
+ ParseContext pc;
+ int interlaced;
+ int cur_field; /* first field is 0, second is 1 */
+} DNXHDParserContext;
+
+static int dnxhd_find_frame_end(DNXHDParserContext *dctx,
const uint8_t *buf, int buf_size)
{
+ ParseContext *pc = &dctx->pc;
uint64_t state = pc->state64;
int pic_found = pc->frame_start_found;
int i = 0;
+ int interlaced = dctx->interlaced;
+ int cur_field = dctx->cur_field;
if (!pic_found) {
for (i = 0; i < buf_size; i++) {
state = (state << 8) | buf[i];
- if ((state & 0xffffffffffLL) == DNXHD_HEADER_PREFIX) {
+ if ((state & 0xffffffffff00LL) == DNXHD_HEADER_PREFIX) {
i++;
pic_found = 1;
+ interlaced = (state&2)>>1; /* byte following the 5-byte header prefix */
+ cur_field = state&1;
break;
}
}
@@ -51,15 +62,25 @@ static int dnxhd_find_frame_end(ParseContext *pc,
return 0;
for (; i < buf_size; i++) {
state = (state << 8) | buf[i];
- if ((state & 0xffffffffffLL) == DNXHD_HEADER_PREFIX) {
- pc->frame_start_found = 0;
- pc->state64 = -1;
- return i - 4;
+ if ((state & 0xffffffffff00LL) == DNXHD_HEADER_PREFIX) {
+ if (!interlaced || dctx->cur_field) {
+ pc->frame_start_found = 0;
+ pc->state64 = -1;
+ dctx->interlaced = interlaced;
+ dctx->cur_field = 0;
+ return i - 5;
+ } else {
+ /* continue, to get the second field */
+ dctx->interlaced = interlaced = (state&2)>>1;
+ dctx->cur_field = cur_field = state&1;
+ }
}
}
}
pc->frame_start_found = pic_found;
pc->state64 = state;
+ dctx->interlaced = interlaced;
+ dctx->cur_field = cur_field;
return END_NOT_FOUND;
}
@@ -68,13 +89,14 @@ static int dnxhd_parse(AVCodecParserContext *s,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
- ParseContext *pc = s->priv_data;
+ DNXHDParserContext *dctx = s->priv_data;
+ ParseContext *pc = &dctx->pc;
int next;
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
next = buf_size;
} else {
- next = dnxhd_find_frame_end(pc, buf, buf_size);
+ next = dnxhd_find_frame_end(dctx, buf, buf_size);
if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
*poutbuf = NULL;
*poutbuf_size = 0;
@@ -88,7 +110,7 @@ static int dnxhd_parse(AVCodecParserContext *s,
AVCodecParser ff_dnxhd_parser = {
.codec_ids = { AV_CODEC_ID_DNXHD },
- .priv_data_size = sizeof(ParseContext),
+ .priv_data_size = sizeof(DNXHDParserContext),
.parser_parse = dnxhd_parse,
.parser_close = ff_parse_close,
};
diff --git a/libavcodec/dnxhddata.c b/libavcodec/dnxhddata.c
index b23e337705..ef918b0214 100644
--- a/libavcodec/dnxhddata.c
+++ b/libavcodec/dnxhddata.c
@@ -2,20 +2,20 @@
* VC3/DNxHD data.
* Copyright (c) 2007 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,26 +23,28 @@
#include "dnxhddata.h"
#include "libavutil/common.h"
+/* The quantization tables below are in zigzag order! */
+
static const uint8_t dnxhd_1235_luma_weight[] = {
- 0, 32, 32, 32, 33, 35, 38, 39,
- 32, 33, 32, 33, 36, 36, 39, 42,
- 32, 32, 33, 36, 35, 37, 41, 43,
- 31, 33, 34, 36, 36, 40, 42, 48,
- 32, 34, 36, 37, 39, 42, 46, 51,
- 36, 37, 37, 39, 41, 46, 51, 55,
- 37, 39, 41, 41, 47, 50, 55, 56,
- 41, 42, 41, 44, 50, 53, 60, 60
+ 0, 32, 32, 32, 33, 32, 32, 32,
+ 32, 31, 32, 33, 33, 33, 33, 35,
+ 36, 36, 34, 34, 36, 37, 37, 36,
+ 36, 35, 36, 38, 39, 39, 37, 36,
+ 37, 37, 39, 41, 42, 41, 39, 39,
+ 40, 41, 42, 43, 42, 42, 41, 41,
+ 41, 44, 47, 46, 46, 48, 51, 51,
+ 50, 50, 53, 55, 55, 56, 60, 60,
};
static const uint8_t dnxhd_1235_chroma_weight[] = {
- 0, 32, 33, 34, 39, 41, 54, 59,
- 33, 34, 35, 38, 43, 49, 58, 84,
- 34, 37, 39, 44, 46, 55, 74, 87,
- 40, 42, 47, 48, 58, 70, 87, 86,
- 43, 50, 56, 63, 72, 94, 91, 82,
- 55, 63, 65, 75, 93, 89, 85, 73,
- 61, 67, 82, 81, 83, 90, 79, 73,
- 74, 84, 75, 78, 90, 85, 73, 73
+ 0, 32, 33, 34, 34, 33, 34, 35,
+ 37, 40, 43, 42, 39, 38, 39, 41,
+ 43, 44, 47, 50, 55, 61, 63, 56,
+ 48, 46, 49, 54, 59, 58, 55, 58,
+ 63, 65, 67, 74, 84, 82, 75, 72,
+ 70, 74, 84, 87, 87, 94, 93, 81,
+ 75, 78, 83, 89, 91, 86, 82, 85,
+ 90, 90, 85, 79, 73, 73, 73, 73,
};
static const uint8_t dnxhd_1237_luma_weight[] = {
@@ -156,25 +158,25 @@ static const uint8_t dnxhd_1243_chroma_weight[] = {
};
static const uint8_t dnxhd_1250_luma_weight[] = {
- 0, 32, 35, 35, 36, 36, 41, 43,
- 32, 34, 35, 36, 37, 39, 43, 47,
- 33, 34, 36, 38, 38, 42, 42, 50,
- 34, 36, 38, 38, 41, 40, 47, 54,
- 35, 38, 39, 40, 39, 45, 49, 58,
- 38, 39, 40, 39, 46, 47, 54, 60,
- 38, 39, 41, 46, 46, 48, 57, 62,
- 40, 41, 44, 45, 49, 54, 63, 63
+ 0, 32, 32, 33, 34, 35, 35, 35,
+ 34, 34, 35, 36, 36, 36, 36, 36,
+ 37, 38, 38, 38, 38, 38, 39, 39,
+ 38, 38, 39, 41, 43, 43, 42, 41,
+ 40, 40, 39, 40, 41, 41, 39, 39,
+ 40, 42, 47, 50, 47, 45, 46, 46,
+ 44, 45, 46, 47, 49, 54, 58, 54,
+ 48, 49, 54, 57, 60, 62, 63, 63,
};
static const uint8_t dnxhd_1250_chroma_weight[] = {
- 0, 32, 35, 36, 40, 42, 51, 51,
- 35, 36, 39, 39, 43, 51, 52, 55,
- 36, 41, 41, 43, 51, 53, 54, 56,
- 43, 44, 45, 50, 54, 54, 55, 57,
- 45, 48, 50, 51, 55, 58, 59, 58,
- 49, 52, 49, 57, 58, 62, 58, 60,
- 51, 51, 56, 58, 62, 61, 59, 62,
- 52, 52, 60, 61, 59, 59, 63, 63
+ 0, 32, 35, 36, 36, 35, 36, 39,
+ 41, 43, 45, 44, 41, 39, 40, 42,
+ 43, 43, 45, 48, 49, 51, 52, 50,
+ 50, 51, 51, 51, 51, 52, 53, 54,
+ 51, 49, 51, 52, 52, 56, 57, 55,
+ 54, 54, 55, 56, 55, 58, 58, 58,
+ 60, 61, 62, 62, 59, 57, 58, 58,
+ 61, 59, 59, 59, 60, 62, 63, 63,
};
static const uint8_t dnxhd_1251_luma_weight[] = {
@@ -318,63 +320,43 @@ static const uint8_t dnxhd_1237_ac_bits[257] = {
};
static const uint8_t dnxhd_1237_ac_level[257] = {
- 1, 1, 2, 0, 3, 4, 2, 5, 6, 7, 3, 8, 9, 10, 11, 12,
- 4, 5, 13, 14, 15, 16, 6, 17, 18, 19, 20, 21, 7, 22, 23, 24,
- 25, 26, 27, 8, 9, 28, 29, 30, 31, 32, 33, 34, 10, 11, 12, 35,
- 36, 37, 38, 39, 40, 41, 13, 14, 15, 16, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 17, 18, 19, 20, 21, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 64, 1, 22, 23, 24, 25, 26, 27, 62, 63, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
- 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64,
-};
-
-static const uint8_t dnxhd_1237_ac_run_flag[257] = {
- 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 5, 0, 7, 9, 5, 11, 13, 15, 7, 17, 19, 21, 23, 25,
+ 9, 11, 27, 29, 31, 33, 13, 35, 37, 39, 41, 43, 15, 45, 47, 49,
+ 51, 53, 55, 17, 19, 57, 59, 61, 63, 65, 67, 69, 21, 23, 25, 71,
+ 73, 75, 77, 79, 81, 83, 27, 29, 31, 33, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105, 35, 37, 39, 41, 43,107,109,111,113,115,117,
+ 119,121,123,129, 3, 45, 47, 49, 51, 53, 55,125,127, 5, 7, 9,
+ 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41,
+ 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73,
+ 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99,101,103,105,
+ 107,109,111,113,115,117,119,121,123,125,127,129, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
+ 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129,
+};
+
+static const uint8_t dnxhd_1237_ac_flags[257] = {
+ 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
-};
-
-static const uint8_t dnxhd_1237_ac_index_flag[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3,
};
static const uint16_t dnxhd_1237_run_codes[62] = {
@@ -467,63 +449,43 @@ static const uint8_t dnxhd_1238_ac_bits[257] = {
};
static const uint8_t dnxhd_1238_ac_level[257] = {
- 1, 1, 2, 3, 0, 4, 5, 2, 6, 7, 8, 3, 9, 10, 11, 4,
- 12, 13, 14, 15, 16, 5, 17, 18, 19, 20, 21, 22, 6, 7, 23, 24,
- 25, 26, 27, 28, 29, 8, 9, 30, 31, 32, 33, 34, 35, 36, 37, 10,
- 11, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 12, 13, 14, 49,
- 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 15, 16, 17, 18,
- 62, 63, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16, 19, 20, 21, 22, 23, 24, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 40, 25,
- 26, 27, 28, 29, 30, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49,
- 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64,
+ 3, 3, 5, 7, 0, 9, 11, 5, 13, 15, 17, 7, 19, 21, 23, 9,
+ 25, 27, 29, 31, 33, 11, 35, 37, 39, 41, 43, 45, 13, 15, 47, 49,
+ 51, 53, 55, 57, 59, 17, 19, 61, 63, 65, 67, 69, 71, 73, 75, 21,
+ 23, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 25, 27, 29, 99,
+ 101,103,105,107,109,111,113,115,117,119,121,123, 31, 33, 35, 37,
+ 125,127,129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27,
+ 29, 31, 33, 39, 41, 43, 45, 47, 49, 35, 37, 39, 41, 43, 45, 47,
+ 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 81, 51,
+ 53, 55, 57, 59, 61, 77, 79, 83, 85, 87, 89, 91, 93, 95, 97, 99,
+ 101,103,105,107,109,111,113,115,117,119,121,123,125,127,129, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
+ 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129,
}; /* 0 is EOB */
-static const uint8_t dnxhd_1238_ac_run_flag[257] = {
- 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
-};
-
-static const uint8_t dnxhd_1238_ac_index_flag[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+static const uint8_t dnxhd_1238_ac_flags[257] = {
+ 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
+ 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3,
};
static const uint16_t dnxhd_1235_1238_1241_run_codes[62] = {
@@ -616,63 +578,43 @@ static const uint8_t dnxhd_1235_1241_ac_bits[257] = {
};
static const uint8_t dnxhd_1235_1241_ac_level[257] = {
- 1, 1, 2, 3, 0, 4, 5, 2, 6, 7, 8, 3, 9, 10, 11, 4,
- 12, 13, 14, 15, 16, 5, 17, 18, 19, 20, 21, 6, 7, 22, 23, 24,
- 25, 26, 27, 28, 29, 8, 9, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- 10, 11, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 12, 13,
- 14, 15, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 1,
- 16, 17, 18, 19, 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
- 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 25, 26, 27, 28, 29, 30, 31, 32, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64,
-};
-
-static const uint8_t dnxhd_1235_1241_ac_run_flag[257] = {
- 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 5, 7, 0, 9, 11, 5, 13, 15, 17, 7, 19, 21, 23, 9,
+ 25, 27, 29, 31, 33, 11, 35, 37, 39, 41, 43, 13, 15, 45, 47, 49,
+ 51, 53, 55, 57, 59, 17, 19, 61, 63, 65, 67, 69, 71, 73, 75, 77,
+ 21, 23, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99,101, 25, 27,
+ 29, 31,103,105,107,109,111,113,115,117,119,121,123,125,127, 3,
+ 33, 35, 37, 39,129, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25,
+ 27, 29, 31, 33, 35, 41, 43, 45, 47, 49, 37, 39, 41, 43, 45, 47,
+ 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 83, 85, 51, 53, 55, 57, 59, 61, 63, 65, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
+ 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129,
+};
+
+static const uint8_t dnxhd_1235_1241_ac_flags[257] = {
+ 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
-};
-
-static const uint8_t dnxhd_1235_1241_ac_index_flag[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3,
};
static const uint8_t dnxhd_1235_1241_run[62] = {
@@ -743,61 +685,42 @@ static const uint8_t dnxhd_1250_ac_bits[257] = {
16
};
static const uint8_t dnxhd_1250_ac_level[257] = {
- 1, 1, 2, 3, 0, 4, 5, 2, 6, 7, 8, 3, 9, 10, 11, 4,
- 12, 13, 14, 15, 16, 5, 17, 18, 19, 20, 21, 22, 6, 23, 24, 25,
- 26, 27, 28, 29, 7, 8, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 9, 10, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 11,
- 12, 13, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 1, 2,
- 3, 4, 5, 14, 15, 16, 17, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 18, 19, 20, 21,
- 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 55, 56, 22, 23, 24,
- 25, 26, 27, 54, 57, 58, 59, 60, 61, 62, 63, 64, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64
-};
-static const uint8_t dnxhd_1250_ac_run_flag[257] = {
- 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 5, 7, 0, 9, 11, 5, 13, 15, 17, 7, 19, 21, 23, 9,
+ 25, 27, 29, 31, 33, 11, 35, 37, 39, 41, 43, 45, 13, 47, 49, 51,
+ 53, 55, 57, 59, 15, 17, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+ 19, 21, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99,101,103,105, 23,
+ 25, 27,107,109,111,113,115,117,119,121,123,125,127,129, 3, 5,
+ 7, 9, 11, 29, 31, 33, 35, 13, 15, 17, 19, 21, 23, 25, 27, 29,
+ 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 37, 39, 41, 43,
+ 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85,
+ 87, 89, 91, 93, 95, 97, 99,101,103,105,107,111,113, 45, 47, 49,
+ 51, 53, 55,109,115,117,119,121,123,125,127,129, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
+ 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129
+};
+static const uint8_t dnxhd_1250_ac_flags[257] = {
+ 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1
-};
-static const uint8_t dnxhd_1250_ac_index_flag[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
- 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3,
};
static const uint16_t dnxhd_1250_run_codes[62] = {
0, 4, 5, 12, 26, 27, 28, 58,
@@ -887,63 +810,43 @@ static const uint8_t dnxhd_1251_ac_bits[257] = {
};
static const uint8_t dnxhd_1251_ac_level[257] = {
- 1, 1, 2, 3, 0, 4, 5, 2, 6, 7, 8, 3, 9, 10, 11, 4,
- 12, 13, 14, 15, 16, 5, 17, 18, 19, 20, 21, 6, 22, 23, 24, 25,
- 26, 27, 28, 29, 7, 8, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 9, 10, 11, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
- 12, 13, 14, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 1,
- 2, 3, 4, 5, 6, 7, 8, 15, 16, 17, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 18,
- 19, 20, 21, 22, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
- 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
- 58, 23, 24, 25, 26, 27, 28, 59, 60, 61, 62, 63, 64, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64,
-};
-
-static const uint8_t dnxhd_1251_ac_run_flag[257] = {
- 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 5, 7, 0, 9, 11, 5, 13, 15, 17, 7, 19, 21, 23, 9,
+ 25, 27, 29, 31, 33, 11, 35, 37, 39, 41, 43, 13, 45, 47, 49, 51,
+ 53, 55, 57, 59, 15, 17, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 19, 21, 23, 83, 85, 87, 89, 91, 93, 95, 97, 99,101,103,105,
+ 25, 27, 29,107,109,111,113,115,117,119,121,123,125,127,129, 3,
+ 5, 7, 9, 11, 13, 15, 17, 31, 33, 35, 19, 21, 23, 25, 27, 29,
+ 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 37,
+ 39, 41, 43, 45, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83,
+ 85, 87, 89, 91, 93, 95, 97, 99,101,103,105,107,109,111,113,115,
+ 117, 47, 49, 51, 53, 55, 57,119,121,123,125,127,129, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
+ 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129,
+};
+
+static const uint8_t dnxhd_1251_ac_flags[257] = {
+ 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
-};
-
-static const uint8_t dnxhd_1251_ac_index_flag[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
+ 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3,
};
static const uint16_t dnxhd_1251_run_codes[62] = {
@@ -1036,63 +939,43 @@ static const uint8_t dnxhd_1252_ac_bits[257] = {
};
static const uint8_t dnxhd_1252_ac_level[257] = {
- 1, 1, 2, 3, 2, 0, 4, 5, 6, 7, 3, 8, 9, 10, 11, 12,
- 13, 14, 4, 5, 15, 16, 17, 18, 6, 19, 20, 21, 22, 23, 24, 7,
- 8, 25, 26, 27, 28, 29, 30, 31, 32, 9, 10, 33, 34, 35, 36, 37,
- 38, 39, 40, 41, 11, 12, 13, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, 14, 15, 16, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 17, 18, 19, 20, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21, 22, 23, 24, 25, 22,
- 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
- 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64,
-};
-
-static const uint8_t dnxhd_1252_ac_run_flag[257] = {
- 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
-};
-
-static const uint8_t dnxhd_1252_ac_index_flag[257] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 5, 7, 5, 0, 9, 11, 13, 15, 7, 17, 19, 21, 23, 25,
+ 27, 29, 9, 11, 31, 33, 35, 37, 13, 39, 41, 43, 45, 47, 49, 15,
+ 17, 51, 53, 55, 57, 59, 61, 63, 65, 19, 21, 67, 69, 71, 73, 75,
+ 77, 79, 81, 83, 23, 25, 27, 85, 87, 89, 91, 93, 95, 97, 99,101,
+ 103,105,107, 29, 31, 33,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 35, 37, 39, 41, 9, 11, 13, 15, 17, 19, 21, 23,
+ 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 43, 45, 47, 49, 51, 45,
+ 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77,
+ 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99,101,103,105,107,109,
+ 111,113,115,117,119,121,123,125,127,129, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31,
+ 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95,
+ 97, 99,101,103,105,107,109,111,113,115,117,119,121,123,125,127,
+ 129,
+};
+
+static const uint8_t dnxhd_1252_ac_flags[257] = {
+ 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2,
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3,
};
static const uint8_t dnxhd_1258_dc_codes[14] = {
@@ -1104,90 +987,102 @@ static const uint8_t dnxhd_1258_dc_bits[14] = {
};
const CIDEntry ff_dnxhd_cid_table[] = {
- { 1235, 1920, 1080, 0, 917504, 917504, 6, 10,
+ { 1235, 1920, 1080, 0, 917504, 917504, 6, 10, 4,
dnxhd_1235_luma_weight, dnxhd_1235_chroma_weight,
dnxhd_1235_1241_dc_codes, dnxhd_1235_1241_dc_bits,
dnxhd_1235_1241_ac_codes, dnxhd_1235_1241_ac_bits, dnxhd_1235_1241_ac_level,
- dnxhd_1235_1241_ac_run_flag, dnxhd_1235_1241_ac_index_flag,
+ dnxhd_1235_1241_ac_flags,
dnxhd_1235_1238_1241_run_codes, dnxhd_1235_1238_1241_run_bits, dnxhd_1235_1241_run,
- { 175, 185, 365, 440 } },
- { 1237, 1920, 1080, 0, 606208, 606208, 4, 8,
+ { 175, 185, 365, 440 },
+ { { 24000, 1001 }, { 25, 1 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1237, 1920, 1080, 0, 606208, 606208, 4, 8, 3,
dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight,
dnxhd_1237_dc_codes, dnxhd_1237_dc_bits,
dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_level,
- dnxhd_1237_ac_run_flag, dnxhd_1237_ac_index_flag,
+ dnxhd_1237_ac_flags,
dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run,
- { 115, 120, 145, 240, 290 } },
- { 1238, 1920, 1080, 0, 917504, 917504, 4, 8,
+ { 115, 120, 145, 240, 290 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1238, 1920, 1080, 0, 917504, 917504, 4, 8, 4,
dnxhd_1238_luma_weight, dnxhd_1238_chroma_weight,
dnxhd_1238_dc_codes, dnxhd_1238_dc_bits,
dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_level,
- dnxhd_1238_ac_run_flag, dnxhd_1238_ac_index_flag,
+ dnxhd_1238_ac_flags,
dnxhd_1235_1238_1241_run_codes, dnxhd_1235_1238_1241_run_bits, dnxhd_1238_run,
- { 175, 185, 220, 365, 440 } },
- { 1241, 1920, 1080, 1, 917504, 458752, 6, 10,
+ { 175, 185, 220, 365, 440 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1241, 1920, 1080, 1, 917504, 458752, 6, 10, 4,
dnxhd_1241_luma_weight, dnxhd_1241_chroma_weight,
dnxhd_1235_1241_dc_codes, dnxhd_1235_1241_dc_bits,
dnxhd_1235_1241_ac_codes, dnxhd_1235_1241_ac_bits, dnxhd_1235_1241_ac_level,
- dnxhd_1235_1241_ac_run_flag, dnxhd_1235_1241_ac_index_flag,
+ dnxhd_1235_1241_ac_flags,
dnxhd_1235_1238_1241_run_codes, dnxhd_1235_1238_1241_run_bits, dnxhd_1235_1241_run,
- { 185, 220 } },
- { 1242, 1920, 1080, 1, 606208, 303104, 4, 8,
+ { 185, 220 },
+ { { 25, 1 }, { 30000, 1001 } } },
+ { 1242, 1920, 1080, 1, 606208, 303104, 4, 8, 3,
dnxhd_1242_luma_weight, dnxhd_1242_chroma_weight,
dnxhd_1237_dc_codes, dnxhd_1237_dc_bits,
dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_level,
- dnxhd_1237_ac_run_flag, dnxhd_1237_ac_index_flag,
+ dnxhd_1237_ac_flags,
dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run,
- { 120, 145 } },
- { 1243, 1920, 1080, 1, 917504, 458752, 4, 8,
+ { 120, 145 },
+ { { 25, 1 }, { 30000, 1001 } } },
+ { 1243, 1920, 1080, 1, 917504, 458752, 4, 8, 4,
dnxhd_1243_luma_weight, dnxhd_1243_chroma_weight,
dnxhd_1238_dc_codes, dnxhd_1238_dc_bits,
dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_level,
- dnxhd_1238_ac_run_flag, dnxhd_1238_ac_index_flag,
+ dnxhd_1238_ac_flags,
dnxhd_1235_1238_1241_run_codes, dnxhd_1235_1238_1241_run_bits, dnxhd_1238_run,
- { 185, 220 } },
- { 1250, 1280, 720, 0, 458752, 458752, 6, 10,
+ { 185, 220 },
+ { { 25, 1 }, { 30000, 1001 } } },
+ { 1250, 1280, 720, 0, 458752, 458752, 6, 10, 4,
dnxhd_1250_luma_weight, dnxhd_1250_chroma_weight,
dnxhd_1250_dc_codes, dnxhd_1250_dc_bits,
dnxhd_1250_ac_codes, dnxhd_1250_ac_bits, dnxhd_1250_ac_level,
- dnxhd_1250_ac_run_flag, dnxhd_1250_ac_index_flag,
+ dnxhd_1250_ac_flags,
dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run,
- { 90, 180, 220 } },
- { 1251, 1280, 720, 0, 458752, 458752, 4, 8,
+ { 90, 90, 180, 220 },
+ { { 24000, 1001 }, { 25, 1 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1251, 1280, 720, 0, 458752, 458752, 4, 8, 4,
dnxhd_1251_luma_weight, dnxhd_1251_chroma_weight,
dnxhd_1251_dc_codes, dnxhd_1251_dc_bits,
dnxhd_1251_ac_codes, dnxhd_1251_ac_bits, dnxhd_1251_ac_level,
- dnxhd_1251_ac_run_flag, dnxhd_1251_ac_index_flag,
+ dnxhd_1251_ac_flags,
dnxhd_1251_run_codes, dnxhd_1251_run_bits, dnxhd_1251_run,
- { 90, 110, 175, 220 } },
- { 1252, 1280, 720, 0, 303104, 303104, 4, 8,
+ { 90, 90, 110, 180, 220 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1252, 1280, 720, 0, 303104, 303104, 4, 8, 5,
dnxhd_1252_luma_weight, dnxhd_1252_chroma_weight,
dnxhd_1252_dc_codes, dnxhd_1252_dc_bits,
dnxhd_1252_ac_codes, dnxhd_1252_ac_bits, dnxhd_1252_ac_level,
- dnxhd_1252_ac_run_flag, dnxhd_1252_ac_index_flag,
+ dnxhd_1252_ac_flags,
dnxhd_1251_run_codes, dnxhd_1251_run_bits, dnxhd_1251_run,
- { 60, 75, 115, 145 } },
- { 1253, 1920, 1080, 0, 188416, 188416, 4, 8,
+ { 60, 60, 75, 120, 145 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1253, 1920, 1080, 0, 188416, 188416, 4, 8, 3,
dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight,
dnxhd_1237_dc_codes, dnxhd_1237_dc_bits,
dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_level,
- dnxhd_1237_ac_run_flag, dnxhd_1237_ac_index_flag,
+ dnxhd_1237_ac_flags,
dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run,
- { 36, 45, 75, 90 } },
- { 1256, 1920, 1080, 0, 1835008, 1835008, 6, 10,
+ { 36, 36, 45, 75, 90 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1256, 1920, 1080, 0, 1835008, 1835008, 6, 10, 4,
dnxhd_1235_luma_weight, dnxhd_1256_chroma_weight,
dnxhd_1235_1241_dc_codes, dnxhd_1235_1241_dc_bits,
dnxhd_1235_1241_ac_codes, dnxhd_1235_1241_ac_bits, dnxhd_1235_1241_ac_level,
- dnxhd_1235_1241_ac_run_flag, dnxhd_1235_1241_ac_index_flag,
+ dnxhd_1235_1241_ac_flags,
dnxhd_1235_1238_1241_run_codes, dnxhd_1235_1238_1241_run_bits, dnxhd_1235_1241_run,
- { 350, 390, 440, 730, 880 } },
- { 1258, 960, 720, 0, 212992, 212992, 4, 8,
+ { 350, 390, 440, 730, 880 },
+ { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } },
+ { 1258, 960, 720, 0, 212992, 212992, 4, 8, 5,
dnxhd_1258_luma_weight, dnxhd_1258_chroma_weight,
dnxhd_1258_dc_codes, dnxhd_1258_dc_bits,
dnxhd_1252_ac_codes, dnxhd_1252_ac_bits, dnxhd_1252_ac_level,
- dnxhd_1252_ac_run_flag, dnxhd_1252_ac_index_flag,
+ dnxhd_1252_ac_flags,
dnxhd_1251_run_codes, dnxhd_1251_run_bits, dnxhd_1251_run,
{ 42, 60, 75, 115 } },
+
};
int ff_dnxhd_get_cid_table(int cid)
@@ -1199,6 +1094,22 @@ int ff_dnxhd_get_cid_table(int cid)
return -1;
}
+int avpriv_dnxhd_get_frame_size(int cid)
+{
+ int i = ff_dnxhd_get_cid_table(cid);
+ if (i<0)
+ return i;
+ return ff_dnxhd_cid_table[i].frame_size;
+}
+
+int avpriv_dnxhd_get_interlaced(int cid)
+{
+ int i = ff_dnxhd_get_cid_table(cid);
+ if (i < 0)
+ return i;
+ return ff_dnxhd_cid_table[i].interlaced;
+}
+
int ff_dnxhd_find_cid(AVCodecContext *avctx, int bit_depth)
{
int i, j;
@@ -1210,7 +1121,7 @@ int ff_dnxhd_find_cid(AVCodecContext *avctx, int bit_depth)
if (cid->width == avctx->width && cid->height == avctx->height &&
cid->interlaced == !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT) &&
cid->bit_depth == bit_depth) {
- for (j = 0; j < sizeof(cid->bit_rates); j++) {
+ for (j = 0; j < FF_ARRAY_ELEMS(cid->bit_rates); j++) {
if (cid->bit_rates[j] == mbs)
return cid->cid;
}
@@ -1218,3 +1129,19 @@ int ff_dnxhd_find_cid(AVCodecContext *avctx, int bit_depth)
}
return 0;
}
+
+void ff_dnxhd_print_profiles(AVCodecContext *avctx, int loglevel)
+{
+ int i, j;
+ for (i = 0; i < FF_ARRAY_ELEMS(ff_dnxhd_cid_table); i++) {
+ const CIDEntry *cid = &ff_dnxhd_cid_table[i];
+ for (j = 0; j < FF_ARRAY_ELEMS(cid->bit_rates); j++) {
+ if (!cid->bit_rates[j])
+ break;
+
+ av_log(avctx, loglevel, "Frame size: %dx%d%c; bitrate: %dMbps; pixel format: %s; framerate: %d/%d\n",
+ cid->width, cid->height, cid->interlaced ? 'i' : 'p', cid->bit_rates[j],
+ cid->bit_depth == 10 ? "yuv422p10" : "yuv422p", cid->frame_rates[j].num, cid->frame_rates[j].den);
+ }
+ }
+}
diff --git a/libavcodec/dnxhddata.h b/libavcodec/dnxhddata.h
index 66b03499d7..8cc27e88e7 100644
--- a/libavcodec/dnxhddata.h
+++ b/libavcodec/dnxhddata.h
@@ -2,20 +2,20 @@
* VC3/DNxHD decoder.
* Copyright (c) 2007 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include <stdint.h>
#include "avcodec.h"
+#include "libavutil/internal.h"
typedef struct CIDEntry {
int cid;
@@ -33,19 +34,25 @@ typedef struct CIDEntry {
unsigned int coding_unit_size;
int index_bits;
int bit_depth;
+ int eob_index;
const uint8_t *luma_weight, *chroma_weight;
const uint8_t *dc_codes, *dc_bits;
const uint16_t *ac_codes;
const uint8_t *ac_bits, *ac_level;
- const uint8_t *ac_run_flag, *ac_index_flag;
+ const uint8_t *ac_flags;
const uint16_t *run_codes;
const uint8_t *run_bits, *run;
- int bit_rates[5]; ///< Helpher to choose variants, rounded to nearest 5Mb/s
+ int bit_rates[5]; ///< Helper to choose variants, rounded to nearest 5Mb/s
+ AVRational frame_rates[5];
} CIDEntry;
extern const CIDEntry ff_dnxhd_cid_table[];
int ff_dnxhd_get_cid_table(int cid);
int ff_dnxhd_find_cid(AVCodecContext *avctx, int bit_depth);
+void ff_dnxhd_print_profiles(AVCodecContext *avctx, int loglevel);
+
+int avpriv_dnxhd_get_frame_size(int cid);
+int avpriv_dnxhd_get_interlaced(int cid);
#endif /* AVCODEC_DNXHDDATA_H */
diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c
index 559fc3ae6d..a1376d303c 100644
--- a/libavcodec/dnxhddec.c
+++ b/libavcodec/dnxhddec.c
@@ -5,20 +5,20 @@
*
* 10 bit support added by MirriAd Ltd, Joseph Artsimovich <joseph@mirriad.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,13 +30,15 @@
#include "dnxhddata.h"
#include "idctdsp.h"
#include "internal.h"
+#include "thread.h"
typedef struct DNXHDContext {
AVCodecContext *avctx;
GetBitContext gb;
BlockDSPContext bdsp;
- int cid; ///< compression id
+ int64_t cid; ///< compression id
unsigned int width, height;
+ enum AVPixelFormat pix_fmt;
unsigned int mb_width, mb_height;
uint32_t mb_scan_index[68]; /* max for 1080p */
int cur_field; ///< current interlaced field
@@ -50,6 +52,9 @@ typedef struct DNXHDContext {
int is_444;
void (*decode_dct_block)(struct DNXHDContext *ctx, int16_t *block,
int n, int qscale);
+ int last_qscale;
+ int luma_scale[64];
+ int chroma_scale[64];
} DNXHDContext;
#define DNXHD_VLC_BITS 9
@@ -67,10 +72,11 @@ static av_cold int dnxhd_decode_init(AVCodecContext *avctx)
DNXHDContext *ctx = avctx->priv_data;
ctx->avctx = avctx;
+ ctx->cid = -1;
return 0;
}
-static int dnxhd_init_vlc(DNXHDContext *ctx, int cid)
+static int dnxhd_init_vlc(DNXHDContext *ctx, uint32_t cid)
{
if (cid != ctx->cid) {
int index;
@@ -79,6 +85,10 @@ static int dnxhd_init_vlc(DNXHDContext *ctx, int cid)
av_log(ctx->avctx, AV_LOG_ERROR, "unsupported cid %d\n", cid);
return AVERROR(ENOSYS);
}
+ if (ff_dnxhd_cid_table[index].bit_depth != ctx->bit_depth) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "bit depth mismatches %d %d\n", ff_dnxhd_cid_table[index].bit_depth, ctx->bit_depth);
+ return AVERROR_INVALIDDATA;
+ }
ctx->cid_table = &ff_dnxhd_cid_table[index];
av_log(ctx->avctx, AV_LOG_VERBOSE, "Profile cid %d.\n", cid);
@@ -130,6 +140,8 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
frame->top_field_first = first_field ^ ctx->cur_field;
av_log(ctx->avctx, AV_LOG_DEBUG,
"interlaced %d, cur field %d\n", buf[5] & 3, ctx->cur_field);
+ } else {
+ ctx->cur_field = 0;
}
ctx->height = AV_RB16(buf + 0x18);
@@ -142,16 +154,18 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
if (buf[0x4] == 0x2) {
ctx->decode_dct_block = dnxhd_decode_dct_block_10_444;
- ctx->avctx->pix_fmt = AV_PIX_FMT_YUV444P10;
+ ctx->pix_fmt = AV_PIX_FMT_YUV444P10;
ctx->is_444 = 1;
} else {
ctx->decode_dct_block = dnxhd_decode_dct_block_10;
- ctx->avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+ ctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+ ctx->is_444 = 0;
}
} else if (buf[0x21] == 0x38) { /* 8 bit */
ctx->bit_depth = ctx->avctx->bits_per_raw_sample = 8;
- ctx->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ ctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ ctx->is_444 = 0;
ctx->decode_dct_block = dnxhd_decode_dct_block_8;
} else {
av_log(ctx->avctx, AV_LOG_ERROR, "invalid bit depth value (%d).\n",
@@ -203,7 +217,7 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame,
for (i = 0; i < ctx->mb_height; i++) {
ctx->mb_scan_index[i] = AV_RB32(buf + 0x170 + (i << 2));
ff_dlog(ctx->avctx, "mb scan index %d\n", ctx->mb_scan_index[i]);
- if (buf_size < ctx->mb_scan_index[i] + 0x280) {
+ if (buf_size < ctx->mb_scan_index[i] + 0x280LL) {
av_log(ctx->avctx, AV_LOG_ERROR,
"invalid mb scan index (%d < %d).\n",
buf_size, ctx->mb_scan_index[i] + 0x280);
@@ -221,24 +235,32 @@ static av_always_inline void dnxhd_decode_dct_block(DNXHDContext *ctx,
int level_bias,
int level_shift)
{
- int i, j, index1, index2, len;
+ int i, j, index1, index2, len, flags;
int level, component, sign;
+ const int *scale;
const uint8_t *weight_matrix;
+ const uint8_t *ac_level = ctx->cid_table->ac_level;
+ const uint8_t *ac_flags = ctx->cid_table->ac_flags;
+ const int eob_index = ctx->cid_table->eob_index;
OPEN_READER(bs, &ctx->gb);
if (!ctx->is_444) {
if (n & 2) {
component = 1 + (n & 1);
+ scale = ctx->chroma_scale;
weight_matrix = ctx->cid_table->chroma_weight;
} else {
component = 0;
+ scale = ctx->luma_scale;
weight_matrix = ctx->cid_table->luma_weight;
}
} else {
component = (n >> 1) % 3;
if (component) {
+ scale = ctx->chroma_scale;
weight_matrix = ctx->cid_table->chroma_weight;
} else {
+ scale = ctx->luma_scale;
weight_matrix = ctx->cid_table->luma_weight;
}
}
@@ -254,41 +276,47 @@ static av_always_inline void dnxhd_decode_dct_block(DNXHDContext *ctx,
}
block[0] = ctx->last_dc[component];
- for (i = 1; ; i++) {
- UPDATE_CACHE(bs, &ctx->gb);
- GET_VLC(index1, bs, &ctx->gb, ctx->ac_vlc.table,
- DNXHD_VLC_BITS, 2);
- level = ctx->cid_table->ac_level[index1];
- if (!level) /* EOB */
- break;
+ i = 0;
+
+ UPDATE_CACHE(bs, &ctx->gb);
+ GET_VLC(index1, bs, &ctx->gb, ctx->ac_vlc.table,
+ DNXHD_VLC_BITS, 2);
+
+ while (index1 != eob_index) {
+ level = ac_level[index1];
+ flags = ac_flags[index1];
sign = SHOW_SBITS(bs, &ctx->gb, 1);
SKIP_BITS(bs, &ctx->gb, 1);
- if (ctx->cid_table->ac_index_flag[index1]) {
- level += SHOW_UBITS(bs, &ctx->gb, index_bits) << 6;
+ if (flags & 1) {
+ level += SHOW_UBITS(bs, &ctx->gb, index_bits) << 7;
SKIP_BITS(bs, &ctx->gb, index_bits);
}
- if (ctx->cid_table->ac_run_flag[index1]) {
+ if (flags & 2) {
UPDATE_CACHE(bs, &ctx->gb);
GET_VLC(index2, bs, &ctx->gb, ctx->run_vlc.table,
DNXHD_VLC_BITS, 2);
i += ctx->cid_table->run[index2];
}
- if (i > 63) {
+ if (++i > 63) {
av_log(ctx->avctx, AV_LOG_ERROR, "ac tex damaged %d, %d\n", n, i);
break;
}
j = ctx->scantable.permutated[i];
- level = (2 * level + 1) * qscale * weight_matrix[i];
+ level *= scale[i];
if (level_bias < 32 || weight_matrix[i] != level_bias)
level += level_bias;
level >>= level_shift;
block[j] = (level ^ sign) - sign;
+
+ UPDATE_CACHE(bs, &ctx->gb);
+ GET_VLC(index1, bs, &ctx->gb, ctx->ac_vlc.table,
+ DNXHD_VLC_BITS, 2);
}
CLOSE_READER(bs, &ctx->gb);
@@ -325,6 +353,14 @@ static int dnxhd_decode_macroblock(DNXHDContext *ctx, AVFrame *frame,
qscale = get_bits(&ctx->gb, 11);
skip_bits1(&ctx->gb);
+ if (qscale != ctx->last_qscale) {
+ for (i = 0; i < 64; i++) {
+ ctx->luma_scale[i] = qscale * ctx->cid_table->luma_weight[i];
+ ctx->chroma_scale[i] = qscale * ctx->cid_table->chroma_weight[i];
+ }
+ ctx->last_qscale = qscale;
+ }
+
for (i = 0; i < 8; i++) {
ctx->bdsp.clear_block(ctx->blocks[i]);
ctx->decode_dct_block(ctx, ctx->blocks[i], i, qscale);
@@ -345,7 +381,7 @@ static int dnxhd_decode_macroblock(DNXHDContext *ctx, AVFrame *frame,
dest_u = frame->data[1] + ((y * dct_linesize_chroma) << 4) + (x << (3 + shift1 + ctx->is_444));
dest_v = frame->data[2] + ((y * dct_linesize_chroma) << 4) + (x << (3 + shift1 + ctx->is_444));
- if (ctx->cur_field) {
+ if (frame->interlaced_frame && ctx->cur_field) {
dest_y += frame->linesize[0];
dest_u += frame->linesize[1];
dest_v += frame->linesize[2];
@@ -412,6 +448,7 @@ static int dnxhd_decode_frame(AVCodecContext *avctx, void *data,
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
DNXHDContext *ctx = avctx->priv_data;
+ ThreadFrame frame = { .f = data };
AVFrame *picture = data;
int first_field = 1;
int ret;
@@ -428,16 +465,20 @@ decode_coding_unit:
avctx->width, avctx->height, ctx->width, ctx->height);
first_field = 1;
}
+ if (avctx->pix_fmt != AV_PIX_FMT_NONE && avctx->pix_fmt != ctx->pix_fmt) {
+ av_log(avctx, AV_LOG_WARNING, "pix_fmt changed: %s -> %s\n",
+ av_get_pix_fmt_name(avctx->pix_fmt), av_get_pix_fmt_name(ctx->pix_fmt));
+ first_field = 1;
+ }
+ avctx->pix_fmt = ctx->pix_fmt;
ret = ff_set_dimensions(avctx, ctx->width, ctx->height);
if (ret < 0)
return ret;
if (first_field) {
- if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
return ret;
- }
picture->pict_type = AV_PICTURE_TYPE_I;
picture->key_frame = 1;
}
@@ -452,7 +493,7 @@ decode_coding_unit:
}
*got_frame = 1;
- return buf_size;
+ return avpkt->size;
}
static av_cold int dnxhd_decode_close(AVCodecContext *avctx)
@@ -474,5 +515,5 @@ AVCodec ff_dnxhd_decoder = {
.init = dnxhd_decode_init,
.close = dnxhd_decode_close,
.decode = dnxhd_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
};
diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c
index dd7d8d1419..90d51ffbe5 100644
--- a/libavcodec/dnxhdenc.c
+++ b/libavcodec/dnxhdenc.c
@@ -6,20 +6,20 @@
* VC-3 encoder funded by the British Broadcasting Corporation
* 10 bit support added by MirriAd Ltd, Joseph Artsimovich <joseph@mirriad.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,6 +36,7 @@
#include "pixblockdsp.h"
#include "dnxhdenc.h"
+
// The largest value that will not lead to overflow for 10bit samples.
#define DNX10BIT_QMAT_SHIFT 18
#define RC_VARIANCE 1 // use variance or ssd for fast rc
@@ -48,14 +49,14 @@ static const AVOption options[] = {
{ NULL }
};
-static const AVClass class = {
- "dnxhd",
- av_default_item_name,
- options,
- LIBAVUTIL_VERSION_INT
+static const AVClass dnxhd_class = {
+ .class_name = "dnxhd",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
};
-static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *restrict block,
+static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *av_restrict block,
const uint8_t *pixels,
ptrdiff_t line_size)
{
@@ -79,25 +80,33 @@ static void dnxhd_8bit_get_pixels_8x4_sym(int16_t *restrict block,
}
static av_always_inline
-void dnxhd_10bit_get_pixels_8x4_sym(int16_t *restrict block,
+void dnxhd_10bit_get_pixels_8x4_sym(int16_t *av_restrict block,
const uint8_t *pixels,
ptrdiff_t line_size)
{
int i;
-
- block += 32;
+ const uint16_t* pixels16 = (const uint16_t*)pixels;
+ line_size >>= 1;
for (i = 0; i < 4; i++) {
- memcpy(block + i * 8, pixels + i * line_size, 8 * sizeof(*block));
- memcpy(block - (i + 1) * 8, pixels + i * line_size, 8 * sizeof(*block));
+ block[0] = pixels16[0]; block[1] = pixels16[1];
+ block[2] = pixels16[2]; block[3] = pixels16[3];
+ block[4] = pixels16[4]; block[5] = pixels16[5];
+ block[6] = pixels16[6]; block[7] = pixels16[7];
+ pixels16 += line_size;
+ block += 8;
}
+ memcpy(block, block - 8, sizeof(*block) * 8);
+ memcpy(block + 8, block - 16, sizeof(*block) * 8);
+ memcpy(block + 16, block - 24, sizeof(*block) * 8);
+ memcpy(block + 24, block - 32, sizeof(*block) * 8);
}
static int dnxhd_10bit_dct_quantize(MpegEncContext *ctx, int16_t *block,
int n, int qscale, int *overflow)
{
const uint8_t *scantable= ctx->intra_scantable.scantable;
- const int *qmat = ctx->q_intra_matrix[qscale];
+ const int *qmat = n<4 ? ctx->q_intra_matrix[qscale] : ctx->q_chroma_intra_matrix[qscale];
int last_non_zero = 0;
int i;
@@ -124,10 +133,10 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
int i, j, level, run;
int max_level = 1 << (ctx->cid_table->bit_depth + 2);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->vlc_codes,
- max_level * 4 * sizeof(*ctx->vlc_codes), fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->vlc_bits,
- max_level * 4 * sizeof(*ctx->vlc_bits), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_codes,
+ max_level, 4 * sizeof(*ctx->vlc_codes), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_bits,
+ max_level, 4 * sizeof(*ctx->vlc_bits), fail);
FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_codes,
63 * 2, fail);
FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_bits,
@@ -146,10 +155,10 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
alevel -= offset << 6;
}
for (j = 0; j < 257; j++) {
- if (ctx->cid_table->ac_level[j] == alevel &&
- (!offset || (ctx->cid_table->ac_index_flag[j] && offset)) &&
- (!run || (ctx->cid_table->ac_run_flag [j] && run))) {
- assert(!ctx->vlc_codes[index]);
+ if (ctx->cid_table->ac_level[j] >> 1 == alevel &&
+ (!offset || (ctx->cid_table->ac_flags[j] & 1) && offset) &&
+ (!run || (ctx->cid_table->ac_flags[j] & 2) && run)) {
+ av_assert1(!ctx->vlc_codes[index]);
if (alevel) {
ctx->vlc_codes[index] =
(ctx->cid_table->ac_codes[j] << 1) | (sign & 1);
@@ -161,7 +170,7 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
break;
}
}
- assert(!alevel || j < 257);
+ av_assert0(!alevel || j < 257);
if (offset) {
ctx->vlc_codes[index] =
(ctx->vlc_codes[index] << ctx->cid_table->index_bits) | offset;
@@ -171,7 +180,7 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx)
}
for (i = 0; i < 62; i++) {
int run = ctx->cid_table->run[i];
- assert(run < 63);
+ av_assert0(run < 63);
ctx->run_codes[run] = ctx->cid_table->run_codes[i];
ctx->run_bits[run] = ctx->cid_table->run_bits[i];
}
@@ -188,15 +197,15 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias)
const uint8_t *luma_weight_table = ctx->cid_table->luma_weight;
const uint8_t *chroma_weight_table = ctx->cid_table->chroma_weight;
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l,
- (ctx->m.avctx->qmax + 1) * 64 * sizeof(int), fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c,
- (ctx->m.avctx->qmax + 1) * 64 * sizeof(int), fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l16,
- (ctx->m.avctx->qmax + 1) * 64 * 2 * sizeof(uint16_t),
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l,
+ (ctx->m.avctx->qmax + 1), 64 * sizeof(int), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c,
+ (ctx->m.avctx->qmax + 1), 64 * sizeof(int), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_l16,
+ (ctx->m.avctx->qmax + 1), 64 * 2 * sizeof(uint16_t),
fail);
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c16,
- (ctx->m.avctx->qmax + 1) * 64 * 2 * sizeof(uint16_t),
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->qmatrix_c16,
+ (ctx->m.avctx->qmax + 1), 64 * 2 * sizeof(uint16_t),
fail);
if (ctx->cid_table->bit_depth == 8) {
@@ -250,6 +259,11 @@ static av_cold int dnxhd_init_qmat(DNXHDEncContext *ctx, int lbias, int cbias)
}
}
+ ctx->m.q_chroma_intra_matrix16 = ctx->qmatrix_c16;
+ ctx->m.q_chroma_intra_matrix = ctx->qmatrix_c;
+ ctx->m.q_intra_matrix16 = ctx->qmatrix_l16;
+ ctx->m.q_intra_matrix = ctx->qmatrix_l;
+
return 0;
fail:
return AVERROR(ENOMEM);
@@ -257,11 +271,10 @@ fail:
static av_cold int dnxhd_init_rc(DNXHDEncContext *ctx)
{
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_rc,
- 8160 * ctx->m.avctx->qmax * sizeof(RCEntry), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->mb_rc, (ctx->m.avctx->qmax + 1), 8160 * sizeof(RCEntry), fail);
if (ctx->m.avctx->mb_decision != FF_MB_DECISION_RD)
- FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->mb_cmp,
- ctx->m.mb_num * sizeof(RCCMPEntry), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->mb_cmp,
+ ctx->m.mb_num, sizeof(RCCMPEntry), fail);
ctx->frame_bits = (ctx->cid_table->coding_unit_size -
640 - 4 - ctx->min_padding) * 8;
@@ -293,14 +306,15 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
ctx->cid = ff_dnxhd_find_cid(avctx, bit_depth);
if (!ctx->cid) {
av_log(avctx, AV_LOG_ERROR,
- "video parameters incompatible with DNxHD\n");
+ "video parameters incompatible with DNxHD. Valid DNxHD profiles:\n");
+ ff_dnxhd_print_profiles(avctx, AV_LOG_ERROR);
return AVERROR(EINVAL);
}
av_log(avctx, AV_LOG_DEBUG, "cid %d\n", ctx->cid);
index = ff_dnxhd_get_cid_table(ctx->cid);
- if (index < 0)
- return index;
+ av_assert0(index >= 0);
+
ctx->cid_table = &ff_dnxhd_cid_table[index];
ctx->m.avctx = avctx;
@@ -314,6 +328,8 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
ff_mpv_idct_init(&ctx->m);
ff_mpegvideoencdsp_init(&ctx->m.mpvencdsp, avctx);
ff_pixblockdsp_init(&ctx->m.pdsp, avctx);
+ ff_dct_encode_init(&ctx->m);
+
if (!ctx->m.dct_quantize)
ctx->m.dct_quantize = ff_dct_quantize_c;
@@ -376,6 +392,11 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
+ if (avctx->qmax <= 1) {
+ av_log(avctx, AV_LOG_ERROR, "qmax must be at least 2\n");
+ return AVERROR(EINVAL);
+ }
+
ctx->thread[0] = ctx;
for (i = 1; i < avctx->thread_count; i++) {
ctx->thread[i] = av_malloc(sizeof(DNXHDEncContext));
@@ -390,7 +411,7 @@ fail: // for FF_ALLOCZ_OR_GOTO
static int dnxhd_write_header(AVCodecContext *avctx, uint8_t *buf)
{
DNXHDEncContext *ctx = avctx->priv_data;
- const uint8_t header_prefix[5] = { 0x00, 0x00, 0x02, 0x80, 0x01 };
+ static const uint8_t header_prefix[5] = { 0x00, 0x00, 0x02, 0x80, 0x01 };
memset(buf, 0, 640);
@@ -429,7 +450,7 @@ static av_always_inline void dnxhd_encode_dc(DNXHDEncContext *ctx, int diff)
}
put_bits(&ctx->m.pb, ctx->cid_table->dc_bits[nbits] + nbits,
(ctx->cid_table->dc_codes[nbits] << nbits) +
- (diff & ((1 << nbits) - 1)));
+ av_mod_uintp2(diff, nbits));
}
static av_always_inline
@@ -583,15 +604,8 @@ void dnxhd_get_blocks(DNXHDEncContext *ctx, int mb_x, int mb_y)
static av_always_inline
int dnxhd_switch_matrix(DNXHDEncContext *ctx, int i)
{
- if (i & 2) {
- ctx->m.q_intra_matrix16 = ctx->qmatrix_c16;
- ctx->m.q_intra_matrix = ctx->qmatrix_c;
- return 1 + (i & 1);
- } else {
- ctx->m.q_intra_matrix16 = ctx->qmatrix_l16;
- ctx->m.q_intra_matrix = ctx->qmatrix_l;
- return 0;
- }
+ const static uint8_t component[8]={0,0,1,2,0,0,1,2};
+ return component[i];
}
static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
@@ -622,7 +636,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
int n = dnxhd_switch_matrix(ctx, i);
memcpy(block, src_block, 64 * sizeof(*block));
- last_index = ctx->m.dct_quantize(&ctx->m, block, i,
+ last_index = ctx->m.dct_quantize(&ctx->m, block, 4 & (2*i),
qscale, &overflow);
ac_bits += dnxhd_calc_ac_bits(ctx, block, last_index);
@@ -632,7 +646,7 @@ static int dnxhd_calc_bits_thread(AVCodecContext *avctx, void *arg,
else
nbits = av_log2_16bit(2 * diff);
- assert(nbits < ctx->cid_table->bit_depth + 4);
+ av_assert1(nbits < ctx->cid_table->bit_depth + 4);
dc_bits += ctx->cid_table->dc_bits[nbits] + nbits;
ctx->m.last_dc[n] = block[0];
@@ -674,7 +688,7 @@ static int dnxhd_encode_thread(AVCodecContext *avctx, void *arg,
for (i = 0; i < 8; i++) {
int16_t *block = ctx->blocks[i];
int overflow, n = dnxhd_switch_matrix(ctx, i);
- int last_index = ctx->m.dct_quantize(&ctx->m, block, i,
+ int last_index = ctx->m.dct_quantize(&ctx->m, block, 4 & (2*i),
qscale, &overflow);
// START_TIMER;
dnxhd_encode_block(ctx, block, last_index, n);
@@ -933,13 +947,13 @@ static void radix_count(const RCCMPEntry *data, int size,
buckets[j][get_bucket(v, 0)]++;
v >>= BUCKET_BITS;
}
- assert(!v);
+ av_assert1(!v);
}
for (j = 0; j < RADIX_PASSES; j++) {
int offset = size;
for (i = NBUCKETS - 1; i >= 0; i--)
buckets[j][i] = offset -= buckets[j][i];
- assert(!buckets[j][0]);
+ av_assert1(!buckets[j][0]);
}
}
@@ -958,7 +972,7 @@ static void radix_sort_pass(RCCMPEntry *dst, const RCCMPEntry *data,
static void radix_sort(RCCMPEntry *data, int size)
{
int buckets[RADIX_PASSES][NBUCKETS];
- RCCMPEntry *tmp = av_malloc(sizeof(*tmp) * size);
+ RCCMPEntry *tmp = av_malloc_array(size, sizeof(*tmp));
radix_count(data, size, buckets);
radix_sort_pass(tmp, data, size, buckets[0], 0);
radix_sort_pass(data, tmp, size, buckets[1], 1);
@@ -1034,11 +1048,8 @@ static int dnxhd_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
int offset, i, ret;
uint8_t *buf;
- if ((ret = ff_alloc_packet(pkt, ctx->cid_table->frame_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "output buffer is too small to compress picture\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, ctx->cid_table->frame_size)) < 0)
return ret;
- }
buf = pkt->data;
dnxhd_load_picture(ctx, frame);
@@ -1068,12 +1079,12 @@ encode_coding_unit:
for (i = 0; i < ctx->m.mb_height; i++) {
AV_WB32(ctx->msip + i * 4, offset);
offset += ctx->slice_size[i];
- assert(!(ctx->slice_size[i] & 3));
+ av_assert1(!(ctx->slice_size[i] & 3));
}
avctx->execute2(avctx, dnxhd_encode_thread, buf, NULL, ctx->m.mb_height);
- assert(640 + offset + 4 <= ctx->cid_table->coding_unit_size);
+ av_assert1(640 + offset + 4 <= ctx->cid_table->coding_unit_size);
memset(buf + 640 + offset, 0,
ctx->cid_table->coding_unit_size - 4 - offset - 640);
@@ -1124,6 +1135,11 @@ static av_cold int dnxhd_encode_end(AVCodecContext *avctx)
return 0;
}
+static const AVCodecDefault dnxhd_defaults[] = {
+ { "qmax", "1024" }, /* Maximum quantization scale factor allowed for VC-3 */
+ { NULL },
+};
+
AVCodec ff_dnxhd_encoder = {
.name = "dnxhd",
.long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"),
@@ -1139,5 +1155,6 @@ AVCodec ff_dnxhd_encoder = {
AV_PIX_FMT_YUV422P10,
AV_PIX_FMT_NONE
},
- .priv_class = &class,
+ .priv_class = &dnxhd_class,
+ .defaults = dnxhd_defaults,
};
diff --git a/libavcodec/dnxhdenc.h b/libavcodec/dnxhdenc.h
index c3248a28d3..7ef0b96457 100644
--- a/libavcodec/dnxhdenc.h
+++ b/libavcodec/dnxhdenc.h
@@ -4,20 +4,20 @@
*
* VC-3 encoder funded by the British Broadcasting Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -84,8 +84,6 @@ typedef struct DNXHDEncContext {
unsigned qscale;
unsigned lambda;
- unsigned thread_size;
-
uint16_t *mb_bits;
uint8_t *mb_qscale;
diff --git a/libavcodec/dpcm.c b/libavcodec/dpcm.c
index 5ab2331601..ecc7a291ac 100644
--- a/libavcodec/dpcm.c
+++ b/libavcodec/dpcm.c
@@ -1,21 +1,21 @@
/*
* Assorted DPCM codecs
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -118,7 +118,7 @@ static av_cold int dpcm_decode_init(AVCodecContext *avctx)
int i;
if (avctx->channels < 1 || avctx->channels > 2) {
- av_log(avctx, AV_LOG_INFO, "invalid number of channels\n");
+ av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
return AVERROR(EINVAL);
}
@@ -205,13 +205,14 @@ static int dpcm_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
return AVERROR(EINVAL);
}
+ if (out % avctx->channels) {
+ av_log(avctx, AV_LOG_WARNING, "channels have differing number of samples\n");
+ }
/* get output buffer */
- frame->nb_samples = out / avctx->channels;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ frame->nb_samples = (out + avctx->channels - 1) / avctx->channels;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
output_samples = (int16_t *)frame->data[0];
samples_end = output_samples + out;
diff --git a/libavcodec/dpx.c b/libavcodec/dpx.c
index c796387681..66d8428951 100644
--- a/libavcodec/dpx.c
+++ b/libavcodec/dpx.c
@@ -2,29 +2,42 @@
* DPX (.dpx) image decoder
* Copyright (c) 2009 Jimmy Christensen
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/intfloat.h"
#include "libavutil/imgutils.h"
#include "bytestream.h"
#include "avcodec.h"
#include "internal.h"
+static unsigned int read16(const uint8_t **ptr, int is_big)
+{
+ unsigned int temp;
+ if (is_big) {
+ temp = AV_RB16(*ptr);
+ } else {
+ temp = AV_RL16(*ptr);
+ }
+ *ptr += 2;
+ return temp;
+}
+
static unsigned int read32(const uint8_t **ptr, int is_big)
{
unsigned int temp;
@@ -37,12 +50,19 @@ static unsigned int read32(const uint8_t **ptr, int is_big)
return temp;
}
-static inline unsigned make_16bit(unsigned value)
+static uint16_t read10in32(const uint8_t **ptr, uint32_t * lbuf,
+ int * n_datum, int is_big)
{
- // mask away invalid bits
- value &= 0xFFC0;
- // correctly expand to 16 bits
- return value + (value >> 10);
+ if (*n_datum)
+ (*n_datum)--;
+ else {
+ *lbuf = read32(ptr, is_big);
+ *n_datum = 2;
+ }
+
+ *lbuf = (*lbuf << 10) | (*lbuf >> 22);
+
+ return *lbuf & 0x3FF;
}
static int decode_frame(AVCodecContext *avctx,
@@ -51,17 +71,18 @@ static int decode_frame(AVCodecContext *avctx,
AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
- const uint8_t *buf_end = avpkt->data + avpkt->size;
int buf_size = avpkt->size;
AVFrame *const p = data;
- uint8_t *ptr;
+ uint8_t *ptr[AV_NUM_DATA_POINTERS];
unsigned int offset;
int magic_num, endian;
- int x, y, ret;
- int w, h, stride, bits_per_color, descriptor, elements, target_packet_size, source_packet_size;
+ int x, y, stride, i, ret;
+ int w, h, bits_per_color, descriptor, elements, packing;
+ int encoding, need_align = 0;
- unsigned int rgbBuffer;
+ unsigned int rgbBuffer = 0;
+ int n_datum = 0;
if (avpkt->size <= 1634) {
av_log(avctx, AV_LOG_ERROR, "Packet too small for DPX header\n");
@@ -87,11 +108,24 @@ static int decode_frame(AVCodecContext *avctx,
av_log(avctx, AV_LOG_ERROR, "Invalid data start offset\n");
return AVERROR_INVALIDDATA;
}
+
+ // Check encryption
+ buf = avpkt->data + 660;
+ ret = read32(&buf, endian);
+ if (ret != 0xFFFFFFFF) {
+ avpriv_report_missing_feature(avctx, "Encryption");
+ av_log(avctx, AV_LOG_WARNING, "The image is encrypted and may "
+ "not properly decode.\n");
+ }
+
// Need to end in 0x304 offset from start of file
buf = avpkt->data + 0x304;
w = read32(&buf, endian);
h = read32(&buf, endian);
+ if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
+ return ret;
+
// Need to end in 0x320 to read the descriptor
buf += 20;
descriptor = buf[0];
@@ -100,108 +134,251 @@ static int decode_frame(AVCodecContext *avctx,
buf += 3;
avctx->bits_per_raw_sample =
bits_per_color = buf[0];
+ buf++;
+ packing = read16(&buf, endian);
+ encoding = read16(&buf, endian);
+
+ if (packing > 1) {
+ avpriv_report_missing_feature(avctx, "Packing %d", packing);
+ return AVERROR_PATCHWELCOME;
+ }
+ if (encoding) {
+ avpriv_report_missing_feature(avctx, "Encoding %d", encoding);
+ return AVERROR_PATCHWELCOME;
+ }
- buf += 825;
+ buf += 820;
avctx->sample_aspect_ratio.num = read32(&buf, endian);
avctx->sample_aspect_ratio.den = read32(&buf, endian);
+ if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0)
+ av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
+ avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den,
+ 0x10000);
+ else
+ avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
+
+ if (offset >= 1724 + 4) {
+ buf = avpkt->data + 1724;
+ i = read32(&buf, endian);
+ if(i) {
+ AVRational q = av_d2q(av_int2float(i), 4096);
+ if (q.num > 0 && q.den > 0)
+ avctx->framerate = q;
+ }
+ }
switch (descriptor) {
- case 51: // RGBA
- elements = 4;
- break;
- case 50: // RGB
- elements = 3;
- break;
- default:
- av_log(avctx, AV_LOG_ERROR, "Unsupported descriptor %d\n", descriptor);
- return AVERROR_INVALIDDATA;
+ case 6: // Y
+ elements = 1;
+ break;
+ case 52: // ABGR
+ case 51: // RGBA
+ case 103: // UYVA4444
+ elements = 4;
+ break;
+ case 50: // RGB
+ case 102: // UYV444
+ elements = 3;
+ break;
+ case 100: // UYVY422
+ elements = 2;
+ break;
+ default:
+ avpriv_report_missing_feature(avctx, "Descriptor %d", descriptor);
+ return AVERROR_PATCHWELCOME;
}
switch (bits_per_color) {
- case 8:
- if (elements == 4) {
- avctx->pix_fmt = AV_PIX_FMT_RGBA;
- } else {
- avctx->pix_fmt = AV_PIX_FMT_RGB24;
- }
- source_packet_size = elements;
- target_packet_size = elements;
- break;
- case 10:
- avctx->pix_fmt = AV_PIX_FMT_RGB48;
- target_packet_size = 6;
- source_packet_size = 4;
- break;
- case 12:
- case 16:
- if (endian) {
- avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
- } else {
- avctx->pix_fmt = AV_PIX_FMT_RGB48LE;
- }
- target_packet_size = 6;
- source_packet_size = elements * 2;
- break;
- default:
- av_log(avctx, AV_LOG_ERROR, "Unsupported color depth : %d\n", bits_per_color);
+ case 8:
+ stride = avctx->width * elements;
+ break;
+ case 10:
+ if (!packing) {
+ av_log(avctx, AV_LOG_ERROR, "Packing to 32bit required\n");
+ return -1;
+ }
+ stride = (avctx->width * elements + 2) / 3 * 4;
+ break;
+ case 12:
+ if (!packing) {
+ av_log(avctx, AV_LOG_ERROR, "Packing to 16bit required\n");
+ return -1;
+ }
+ stride = 2 * avctx->width * elements;
+ break;
+ case 16:
+ stride = 2 * avctx->width * elements;
+ break;
+ case 1:
+ case 32:
+ case 64:
+ avpriv_report_missing_feature(avctx, "Depth %d", bits_per_color);
+ return AVERROR_PATCHWELCOME;
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+
+ // Table 3c: Runs will always break at scan line boundaries. Packing
+ // will always break to the next 32-bit word at scan-line boundaries.
+ // Unfortunately, the encoder produced invalid files, so attempt
+ // to detect it
+ need_align = FFALIGN(stride, 4);
+ if (need_align*avctx->height + (int64_t)offset > avpkt->size) {
+ // Alignment seems unappliable, try without
+ if (stride*avctx->height + (int64_t)offset > avpkt->size) {
+ av_log(avctx, AV_LOG_ERROR, "Overread buffer. Invalid header?\n");
return AVERROR_INVALIDDATA;
+ } else {
+ av_log(avctx, AV_LOG_INFO, "Decoding DPX without scanline "
+ "alignment.\n");
+ need_align = 0;
+ }
+ } else {
+ need_align -= stride;
+ stride = FFALIGN(stride, 4);
}
- if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
- return ret;
+ switch (1000 * descriptor + 10 * bits_per_color + endian) {
+ case 6081:
+ case 6080:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ break;
+ case 50081:
+ case 50080:
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ break;
+ case 52081:
+ case 52080:
+ avctx->pix_fmt = AV_PIX_FMT_ABGR;
+ break;
+ case 51081:
+ case 51080:
+ avctx->pix_fmt = AV_PIX_FMT_RGBA;
+ break;
+ case 50100:
+ case 51100:
+ case 50101:
+ case 51101:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP10;
+ break;
+ case 50120:
+ case 51120:
+ case 50121:
+ case 51121:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP12;
+ break;
+ case 6161:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
+ break;
+ case 6160:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16LE;
+ break;
+ case 50161:
+ avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
+ break;
+ case 50160:
+ avctx->pix_fmt = AV_PIX_FMT_RGB48LE;
+ break;
+ case 51161:
+ avctx->pix_fmt = AV_PIX_FMT_RGBA64BE;
+ break;
+ case 51160:
+ avctx->pix_fmt = AV_PIX_FMT_RGBA64LE;
+ break;
+ case 100081:
+ avctx->pix_fmt = AV_PIX_FMT_UYVY422;
+ break;
+ case 102081:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+ break;
+ case 103081:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported format\n");
+ return AVERROR_PATCHWELCOME;
+ }
ff_set_sar(avctx, avctx->sample_aspect_ratio);
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
// Move pointer to offset from start of file
buf = avpkt->data + offset;
- ptr = p->data[0];
- stride = p->linesize[0];
+ for (i=0; i<AV_NUM_DATA_POINTERS; i++)
+ ptr[i] = p->data[i];
- if (source_packet_size*avctx->width*avctx->height > buf_end - buf) {
- av_log(avctx, AV_LOG_ERROR, "Overread buffer. Invalid header?\n");
- return AVERROR_INVALIDDATA;
- }
switch (bits_per_color) {
- case 10:
- for (x = 0; x < avctx->height; x++) {
- uint16_t *dst = (uint16_t*)ptr;
- for (y = 0; y < avctx->width; y++) {
- rgbBuffer = read32(&buf, endian);
- // Read out the 10-bit colors and convert to 16-bit
- *dst++ = make_16bit(rgbBuffer >> 16);
- *dst++ = make_16bit(rgbBuffer >> 6);
- *dst++ = make_16bit(rgbBuffer << 4);
- }
- ptr += stride;
+ case 10:
+ for (x = 0; x < avctx->height; x++) {
+ uint16_t *dst[3] = {(uint16_t*)ptr[0],
+ (uint16_t*)ptr[1],
+ (uint16_t*)ptr[2]};
+ for (y = 0; y < avctx->width; y++) {
+ *dst[2]++ = read10in32(&buf, &rgbBuffer,
+ &n_datum, endian);
+ *dst[0]++ = read10in32(&buf, &rgbBuffer,
+ &n_datum, endian);
+ *dst[1]++ = read10in32(&buf, &rgbBuffer,
+ &n_datum, endian);
+ // For 10 bit, ignore alpha
+ if (elements == 4)
+ read10in32(&buf, &rgbBuffer,
+ &n_datum, endian);
}
- break;
- case 8:
- case 12: // Treat 12-bit as 16-bit
- case 16:
- if (source_packet_size == target_packet_size) {
- for (x = 0; x < avctx->height; x++) {
- memcpy(ptr, buf, target_packet_size*avctx->width);
- ptr += stride;
- buf += source_packet_size*avctx->width;
- }
- } else {
- for (x = 0; x < avctx->height; x++) {
- uint8_t *dst = ptr;
- for (y = 0; y < avctx->width; y++) {
- memcpy(dst, buf, target_packet_size);
- dst += target_packet_size;
- buf += source_packet_size;
- }
- ptr += stride;
+ n_datum = 0;
+ for (i = 0; i < 3; i++)
+ ptr[i] += p->linesize[i];
+ }
+ break;
+ case 12:
+ for (x = 0; x < avctx->height; x++) {
+ uint16_t *dst[3] = {(uint16_t*)ptr[0],
+ (uint16_t*)ptr[1],
+ (uint16_t*)ptr[2]};
+ for (y = 0; y < avctx->width; y++) {
+ *dst[2] = read16(&buf, endian) >> 4;
+ dst[2]++;
+ *dst[0] = read16(&buf, endian) >> 4;
+ dst[0]++;
+ *dst[1] = read16(&buf, endian) >> 4;
+ dst[1]++;
+ // For 12 bit, ignore alpha
+ if (elements == 4)
+ buf += 2;
+ // Jump to next aligned position
+ buf += need_align;
+ }
+ for (i = 0; i < 3; i++)
+ ptr[i] += p->linesize[i];
+ }
+ break;
+ case 16:
+ elements *= 2;
+ case 8:
+ if ( avctx->pix_fmt == AV_PIX_FMT_YUVA444P
+ || avctx->pix_fmt == AV_PIX_FMT_YUV444P) {
+ for (x = 0; x < avctx->height; x++) {
+ ptr[0] = p->data[0] + x * p->linesize[0];
+ ptr[1] = p->data[1] + x * p->linesize[1];
+ ptr[2] = p->data[2] + x * p->linesize[2];
+ ptr[3] = p->data[3] + x * p->linesize[3];
+ for (y = 0; y < avctx->width; y++) {
+ *ptr[1]++ = *buf++;
+ *ptr[0]++ = *buf++;
+ *ptr[2]++ = *buf++;
+ if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P)
+ *ptr[3]++ = *buf++;
}
}
- break;
+ } else {
+ av_image_copy_plane(ptr[0], p->linesize[0],
+ buf, stride,
+ elements * avctx->width, avctx->height);
+ }
+ break;
}
*got_frame = 1;
@@ -211,7 +388,7 @@ static int decode_frame(AVCodecContext *avctx,
AVCodec ff_dpx_decoder = {
.name = "dpx",
- .long_name = NULL_IF_CONFIG_SMALL("DPX image"),
+ .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_DPX,
.decode = decode_frame,
diff --git a/libavcodec/dpx_parser.c b/libavcodec/dpx_parser.c
index e3a7ac5c35..8e4a01e09d 100644
--- a/libavcodec/dpx_parser.c
+++ b/libavcodec/dpx_parser.c
@@ -2,20 +2,20 @@
* DPX parser
* Copyright (c) 2013 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dpxenc.c b/libavcodec/dpxenc.c
index 2b1ead391b..aca745bb58 100644
--- a/libavcodec/dpxenc.c
+++ b/libavcodec/dpxenc.c
@@ -2,20 +2,20 @@
* DPX (.dpx) image encoder
* Copyright (c) 2011 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,35 +28,44 @@
typedef struct DPXContext {
int big_endian;
int bits_per_component;
+ int num_components;
int descriptor;
+ int planar;
} DPXContext;
static av_cold int encode_init(AVCodecContext *avctx)
{
DPXContext *s = avctx->priv_data;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
-
- s->big_endian = 1;
- s->bits_per_component = 8;
- s->descriptor = 50; /* RGB */
+ s->big_endian = !!(desc->flags & AV_PIX_FMT_FLAG_BE);
+ s->bits_per_component = desc->comp[0].depth_minus1 + 1;
+ s->num_components = desc->nb_components;
+ s->descriptor = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? 51 : 50;
+ s->planar = !!(desc->flags & AV_PIX_FMT_FLAG_PLANAR);
switch (avctx->pix_fmt) {
- case AV_PIX_FMT_RGB24:
+ case AV_PIX_FMT_ABGR:
+ s->descriptor = 52;
break;
+ case AV_PIX_FMT_GRAY16BE:
+ case AV_PIX_FMT_GRAY16LE:
+ case AV_PIX_FMT_GRAY8:
+ s->descriptor = 6;
+ break;
+ case AV_PIX_FMT_GBRP10BE:
+ case AV_PIX_FMT_GBRP10LE:
+ case AV_PIX_FMT_GBRP12BE:
+ case AV_PIX_FMT_GBRP12LE:
+ case AV_PIX_FMT_RGB24:
+ case AV_PIX_FMT_RGBA64BE:
+ case AV_PIX_FMT_RGBA64LE:
case AV_PIX_FMT_RGBA:
- s->descriptor = 51; /* RGBA */
break;
case AV_PIX_FMT_RGB48LE:
- s->big_endian = 0;
- /* fall-through */
case AV_PIX_FMT_RGB48BE:
- s->bits_per_component = avctx->bits_per_raw_sample ? avctx->bits_per_raw_sample : 16;
+ if (avctx->bits_per_raw_sample)
+ s->bits_per_component = avctx->bits_per_raw_sample;
break;
default:
av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n");
@@ -78,8 +87,7 @@ do { \
else AV_WL32(p, value); \
} while(0)
-static void encode_rgb48_10bit(AVCodecContext *avctx, const AVPicture *pic,
- uint8_t *dst)
+static void encode_rgb48_10bit(AVCodecContext *avctx, const AVPicture *pic, uint8_t *dst)
{
DPXContext *s = avctx->priv_data;
const uint8_t *src = pic->data[0];
@@ -88,14 +96,14 @@ static void encode_rgb48_10bit(AVCodecContext *avctx, const AVPicture *pic,
for (y = 0; y < avctx->height; y++) {
for (x = 0; x < avctx->width; x++) {
int value;
- if ((avctx->pix_fmt & 1)) {
- value = ((AV_RB16(src + 6*x + 4) & 0xFFC0) >> 4)
- | ((AV_RB16(src + 6*x + 2) & 0xFFC0) << 6)
- | ((AV_RB16(src + 6*x + 0) & 0xFFC0) << 16);
+ if (s->big_endian) {
+ value = ((AV_RB16(src + 6*x + 4) & 0xFFC0U) >> 4)
+ | ((AV_RB16(src + 6*x + 2) & 0xFFC0U) << 6)
+ | ((AV_RB16(src + 6*x + 0) & 0xFFC0U) << 16);
} else {
- value = ((AV_RL16(src + 6*x + 4) & 0xFFC0) >> 4)
- | ((AV_RL16(src + 6*x + 2) & 0xFFC0) << 6)
- | ((AV_RL16(src + 6*x + 0) & 0xFFC0) << 16);
+ value = ((AV_RL16(src + 6*x + 4) & 0xFFC0U) >> 4)
+ | ((AV_RL16(src + 6*x + 2) & 0xFFC0U) << 6)
+ | ((AV_RL16(src + 6*x + 0) & 0xFFC0U) << 16);
}
write32(dst, value);
dst += 4;
@@ -104,22 +112,88 @@ static void encode_rgb48_10bit(AVCodecContext *avctx, const AVPicture *pic,
}
}
+static void encode_gbrp10(AVCodecContext *avctx, const AVPicture *pic, uint8_t *dst)
+{
+ DPXContext *s = avctx->priv_data;
+ const uint8_t *src[3] = {pic->data[0], pic->data[1], pic->data[2]};
+ int x, y, i;
+
+ for (y = 0; y < avctx->height; y++) {
+ for (x = 0; x < avctx->width; x++) {
+ int value;
+ if (s->big_endian) {
+ value = (AV_RB16(src[0] + 2*x) << 12)
+ | (AV_RB16(src[1] + 2*x) << 2)
+ | ((unsigned)AV_RB16(src[2] + 2*x) << 22);
+ } else {
+ value = (AV_RL16(src[0] + 2*x) << 12)
+ | (AV_RL16(src[1] + 2*x) << 2)
+ | ((unsigned)AV_RL16(src[2] + 2*x) << 22);
+ }
+ write32(dst, value);
+ dst += 4;
+ }
+ for (i = 0; i < 3; i++)
+ src[i] += pic->linesize[i];
+ }
+}
+
+static void encode_gbrp12(AVCodecContext *avctx, const AVPicture *pic, uint16_t *dst)
+{
+ DPXContext *s = avctx->priv_data;
+ const uint16_t *src[3] = {(uint16_t*)pic->data[0],
+ (uint16_t*)pic->data[1],
+ (uint16_t*)pic->data[2]};
+ int x, y, i, pad;
+ pad = avctx->width*6;
+ pad = (FFALIGN(pad, 4) - pad) >> 1;
+ for (y = 0; y < avctx->height; y++) {
+ for (x = 0; x < avctx->width; x++) {
+ uint16_t value[3];
+ if (s->big_endian) {
+ value[1] = AV_RB16(src[0] + x) << 4;
+ value[2] = AV_RB16(src[1] + x) << 4;
+ value[0] = AV_RB16(src[2] + x) << 4;
+ } else {
+ value[1] = AV_RL16(src[0] + x) << 4;
+ value[2] = AV_RL16(src[1] + x) << 4;
+ value[0] = AV_RL16(src[2] + x) << 4;
+ }
+ for (i = 0; i < 3; i++)
+ write16(dst++, value[i]);
+ }
+ for (i = 0; i < pad; i++)
+ *dst++ = 0;
+ for (i = 0; i < 3; i++)
+ src[i] += pic->linesize[i]/2;
+ }
+}
+
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
DPXContext *s = avctx->priv_data;
- int size, ret;
+ int size, ret, need_align, len;
uint8_t *buf;
#define HEADER_SIZE 1664 /* DPX Generic header */
if (s->bits_per_component == 10)
size = avctx->height * avctx->width * 4;
- else
- size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
- if ((ret = ff_alloc_packet(pkt, size + HEADER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
- return ret;
+ else if (s->bits_per_component == 12) {
+ // 3 components, 12 bits put on 16 bits
+ len = avctx->width*6;
+ size = FFALIGN(len, 4);
+ need_align = size - len;
+ size *= avctx->height;
+ } else {
+ // N components, M bits
+ len = avctx->width * s->num_components * s->bits_per_component >> 3;
+ size = FFALIGN(len, 4);
+ need_align = size - len;
+ size *= avctx->height;
}
+ if ((ret = ff_alloc_packet2(avctx, pkt, size + HEADER_SIZE)) < 0)
+ return ret;
buf = pkt->data;
memset(buf, 0, HEADER_SIZE);
@@ -143,24 +217,44 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
buf[801] = 2; /* linear transfer */
buf[802] = 2; /* linear colorimetric */
buf[803] = s->bits_per_component;
- write16(buf + 804, s->bits_per_component == 10 ? 1 : 0); /* packing method */
+ write16(buf + 804, (s->bits_per_component == 10 || s->bits_per_component == 12) ?
+ 1 : 0); /* packing method */
write32(buf + 808, HEADER_SIZE); /* data offset */
/* Image source information header */
write32(buf + 1628, avctx->sample_aspect_ratio.num);
write32(buf + 1632, avctx->sample_aspect_ratio.den);
- switch (s->bits_per_component) {
+ switch(s->bits_per_component) {
case 8:
case 16:
- size = avpicture_layout((const AVPicture*)frame, avctx->pix_fmt,
- avctx->width, avctx->height,
- buf + HEADER_SIZE, pkt->size - HEADER_SIZE);
+ if (need_align) {
+ int j;
+ const uint8_t *src = frame->data[0];
+ uint8_t *dst = pkt->data + HEADER_SIZE;
+ size = (len + need_align) * avctx->height;
+ for (j=0; j<avctx->height; j++) {
+ memcpy(dst, src, len);
+ memset(dst + len, 0, need_align);
+ dst += len + need_align;
+ src += frame->linesize[0];
+ }
+ } else {
+ size = avpicture_layout((const AVPicture*)frame, avctx->pix_fmt,
+ avctx->width, avctx->height,
+ buf + HEADER_SIZE, pkt->size - HEADER_SIZE);
+ }
if (size < 0)
return size;
break;
case 10:
- encode_rgb48_10bit(avctx, (const AVPicture*)frame, buf + HEADER_SIZE);
+ if (s->planar)
+ encode_gbrp10(avctx, (const AVPicture*)frame, buf + HEADER_SIZE);
+ else
+ encode_rgb48_10bit(avctx, (const AVPicture*)frame, buf + HEADER_SIZE);
+ break;
+ case 12:
+ encode_gbrp12(avctx, (const AVPicture*)frame, (uint16_t*)(buf + HEADER_SIZE));
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %d\n", s->bits_per_component);
@@ -177,25 +271,21 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
-static av_cold int encode_close(AVCodecContext *avctx)
-{
- av_frame_free(&avctx->coded_frame);
- return 0;
-}
-
AVCodec ff_dpx_encoder = {
- .name = "dpx",
- .long_name = NULL_IF_CONFIG_SMALL("DPX image"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_DPX,
+ .name = "dpx",
+ .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_DPX,
.priv_data_size = sizeof(DPXContext),
- .init = encode_init,
- .encode2 = encode_frame,
- .close = encode_close,
- .pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_RGB24,
- AV_PIX_FMT_RGBA,
- AV_PIX_FMT_RGB48LE,
- AV_PIX_FMT_RGB48BE,
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]){
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE,
+ AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE,
+ AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE,
+ AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRP10BE,
+ AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP12BE,
AV_PIX_FMT_NONE},
};
diff --git a/libavcodec/dsd_tablegen.c b/libavcodec/dsd_tablegen.c
new file mode 100644
index 0000000000..dbeb9fe205
--- /dev/null
+++ b/libavcodec/dsd_tablegen.c
@@ -0,0 +1,38 @@
+/*
+ * Generate a header file for hardcoded DSD tables
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdlib.h>
+#define CONFIG_HARDCODED_TABLES 0
+#include "dsd_tablegen.h"
+#include "tableprint.h"
+#include <inttypes.h>
+
+int main(void)
+{
+ dsd_ctables_tableinit();
+
+ write_fileheader();
+
+ printf("static const double ctables[CTABLES][256] = {\n");
+ write_float_2d_array(ctables, CTABLES, 256);
+ printf("};\n");
+
+ return 0;
+}
diff --git a/libavcodec/dsd_tablegen.h b/libavcodec/dsd_tablegen.h
new file mode 100644
index 0000000000..6afb4167da
--- /dev/null
+++ b/libavcodec/dsd_tablegen.h
@@ -0,0 +1,95 @@
+/*
+ * Header file for hardcoded DSD tables
+ * based on BSD licensed dsd2pcm by Sebastian Gesemann
+ * Copyright (c) 2009, 2011 Sebastian Gesemann. All rights reserved.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_DSD_TABLEGEN_H
+#define AVCODEC_DSD_TABLEGEN_H
+
+#include <stdint.h>
+#include "libavutil/attributes.h"
+
+#define HTAPS 48 /** number of FIR constants */
+#define CTABLES ((HTAPS + 7) / 8) /** number of "8 MACs" lookup tables */
+
+#if CONFIG_HARDCODED_TABLES
+#define dsd_ctables_tableinit()
+#include "libavcodec/dsd_tables.h"
+#else
+#include "libavutil/common.h"
+
+/*
+ * Properties of this 96-tap lowpass filter when applied on a signal
+ * with sampling rate of 44100*64 Hz:
+ *
+ * () has a delay of 17 microseconds.
+ *
+ * () flat response up to 48 kHz
+ *
+ * () if you downsample afterwards by a factor of 8, the
+ * spectrum below 70 kHz is practically alias-free.
+ *
+ * () stopband rejection is about 160 dB
+ *
+ * The coefficient tables ("ctables") take only 6 Kibi Bytes and
+ * should fit into a modern processor's fast cache.
+ */
+
+/**
+ * The 2nd half (48 coeffs) of a 96-tap symmetric lowpass filter
+ */
+static const double htaps[HTAPS] = {
+ 0.09950731974056658, 0.09562845727714668, 0.08819647126516944,
+ 0.07782552527068175, 0.06534876523171299, 0.05172629311427257,
+ 0.0379429484910187, 0.02490921351762261, 0.0133774746265897,
+ 0.003883043418804416, -0.003284703416210726, -0.008080250212687497,
+ -0.01067241812471033, -0.01139427235000863, -0.0106813877974587,
+ -0.009007905078766049, -0.006828859761015335, -0.004535184322001496,
+ -0.002425035959059578, -0.0006922187080790708, 0.0005700762133516592,
+ 0.001353838005269448, 0.001713709169690937, 0.001742046839472948,
+ 0.001545601648013235, 0.001226696225277855, 0.0008704322683580222,
+ 0.0005381636200535649, 0.000266446345425276, 7.002968738383528e-05,
+ -5.279407053811266e-05, -0.0001140625650874684, -0.0001304796361231895,
+ -0.0001189970287491285, -9.396247155265073e-05, -6.577634378272832e-05,
+ -4.07492895872535e-05, -2.17407957554587e-05, -9.163058931391722e-06,
+ -2.017460145032201e-06, 1.249721855219005e-06, 2.166655190537392e-06,
+ 1.930520892991082e-06, 1.319400334374195e-06, 7.410039764949091e-07,
+ 3.423230509967409e-07, 1.244182214744588e-07, 3.130441005359396e-08
+};
+
+static float ctables[CTABLES][256];
+
+static av_cold void dsd_ctables_tableinit(void)
+{
+ int t, e, m, k;
+ double acc;
+ for (t = 0; t < CTABLES; ++t) {
+ k = FFMIN(HTAPS - t * 8, 8);
+ for (e = 0; e < 256; ++e) {
+ acc = 0.0;
+ for (m = 0; m < k; ++m)
+ acc += (((e >> (7 - m)) & 1) * 2 - 1) * htaps[t * 8 + m];
+ ctables[CTABLES - 1 - t][e] = (float)acc;
+ }
+ }
+}
+#endif /* CONFIG_HARDCODED_TABLES */
+
+#endif /* AVCODEC_DSD_TABLEGEN_H */
diff --git a/libavcodec/dsddec.c b/libavcodec/dsddec.c
new file mode 100644
index 0000000000..f1dfd4b231
--- /dev/null
+++ b/libavcodec/dsddec.c
@@ -0,0 +1,167 @@
+/*
+ * Direct Stream Digital (DSD) decoder
+ * based on BSD licensed dsd2pcm by Sebastian Gesemann
+ * Copyright (c) 2009, 2011 Sebastian Gesemann. All rights reserved.
+ * Copyright (c) 2014 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Direct Stream Digital (DSD) decoder
+ */
+
+#include "libavcodec/internal.h"
+#include "libavcodec/mathops.h"
+#include "avcodec.h"
+#include "dsd_tablegen.h"
+
+#define FIFOSIZE 16 /** must be a power of two */
+#define FIFOMASK (FIFOSIZE - 1) /** bit mask for FIFO offsets */
+
+#if FIFOSIZE * 8 < HTAPS * 2
+#error "FIFOSIZE too small"
+#endif
+
+/**
+ * Per-channel buffer
+ */
+typedef struct {
+ unsigned char buf[FIFOSIZE];
+ unsigned pos;
+} DSDContext;
+
+static void dsd2pcm_translate(DSDContext* s, size_t samples, int lsbf,
+ const unsigned char *src, ptrdiff_t src_stride,
+ float *dst, ptrdiff_t dst_stride)
+{
+ unsigned pos, i;
+ unsigned char* p;
+ double sum;
+
+ pos = s->pos;
+
+ while (samples-- > 0) {
+ s->buf[pos] = lsbf ? ff_reverse[*src] : *src;
+ src += src_stride;
+
+ p = s->buf + ((pos - CTABLES) & FIFOMASK);
+ *p = ff_reverse[*p];
+
+ sum = 0.0;
+ for (i = 0; i < CTABLES; i++) {
+ unsigned char a = s->buf[(pos - i) & FIFOMASK];
+ unsigned char b = s->buf[(pos - (CTABLES*2 - 1) + i) & FIFOMASK];
+ sum += ctables[i][a] + ctables[i][b];
+ }
+
+ *dst = (float)sum;
+ dst += dst_stride;
+
+ pos = (pos + 1) & FIFOMASK;
+ }
+
+ s->pos = pos;
+}
+
+static av_cold void init_static_data(void)
+{
+ static int done = 0;
+ if (done)
+ return;
+ dsd_ctables_tableinit();
+ done = 1;
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ DSDContext * s;
+ int i;
+
+ init_static_data();
+
+ s = av_malloc_array(sizeof(DSDContext), avctx->channels);
+ if (!s)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < avctx->channels; i++) {
+ s[i].pos = 0;
+ memset(s[i].buf, 0x69, sizeof(s[i].buf));
+
+ /* 0x69 = 01101001
+ * This pattern "on repeat" makes a low energy 352.8 kHz tone
+ * and a high energy 1.0584 MHz tone which should be filtered
+ * out completely by any playback system --> silence
+ */
+ }
+
+ avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+ avctx->priv_data = s;
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *avpkt)
+{
+ DSDContext * s = avctx->priv_data;
+ AVFrame *frame = data;
+ int ret, i;
+ int lsbf = avctx->codec_id == AV_CODEC_ID_DSD_LSBF || avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR;
+ int src_next;
+ int src_stride;
+
+ frame->nb_samples = avpkt->size / avctx->channels;
+
+ if (avctx->codec_id == AV_CODEC_ID_DSD_LSBF_PLANAR || avctx->codec_id == AV_CODEC_ID_DSD_MSBF_PLANAR) {
+ src_next = frame->nb_samples;
+ src_stride = 1;
+ } else {
+ src_next = 1;
+ src_stride = avctx->channels;
+ }
+
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ for (i = 0; i < avctx->channels; i++) {
+ float * dst = ((float **)frame->extended_data)[i];
+ dsd2pcm_translate(&s[i], frame->nb_samples, lsbf,
+ avpkt->data + i * src_next, src_stride,
+ dst, 1);
+ }
+
+ *got_frame_ptr = 1;
+ return frame->nb_samples * avctx->channels;
+}
+
+#define DSD_DECODER(id_, name_, long_name_) \
+AVCodec ff_##name_##_decoder = { \
+ .name = #name_, \
+ .long_name = NULL_IF_CONFIG_SMALL(long_name_), \
+ .type = AVMEDIA_TYPE_AUDIO, \
+ .id = AV_CODEC_ID_##id_, \
+ .init = decode_init, \
+ .decode = decode_frame, \
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, \
+ AV_SAMPLE_FMT_NONE }, \
+};
+
+DSD_DECODER(DSD_LSBF, dsd_lsbf, "DSD (Direct Stream Digital), least significant bit first")
+DSD_DECODER(DSD_MSBF, dsd_msbf, "DSD (Direct Stream Digital), most significant bit first")
+DSD_DECODER(DSD_MSBF_PLANAR, dsd_msbf_planar, "DSD (Direct Stream Digital), most significant bit first, planar")
+DSD_DECODER(DSD_LSBF_PLANAR, dsd_lsbf_planar, "DSD (Direct Stream Digital), least significant bit first, planar")
diff --git a/libavcodec/dsicinaudio.c b/libavcodec/dsicinaudio.c
index 969e4ae195..b336d2c584 100644
--- a/libavcodec/dsicinaudio.c
+++ b/libavcodec/dsicinaudio.c
@@ -2,20 +2,20 @@
* Delphine Software International CIN audio decoder
* Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -98,10 +98,8 @@ static int cinaudio_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = avpkt->size - cin->initial_decode_frame;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t *)frame->data[0];
delta = cin->delta;
diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c
index b56a581ea3..48fb635c6b 100644
--- a/libavcodec/dsicinvideo.c
+++ b/libavcodec/dsicinvideo.c
@@ -2,20 +2,20 @@
* Delphine Software International CIN video decoder
* Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,10 +42,33 @@ typedef struct CinVideoContext {
uint8_t *bitmap_table[3];
} CinVideoContext;
+static av_cold void destroy_buffers(CinVideoContext *cin)
+{
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ av_freep(&cin->bitmap_table[i]);
+}
+
+static av_cold int allocate_buffers(CinVideoContext *cin)
+{
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ cin->bitmap_table[i] = av_mallocz(cin->bitmap_size);
+ if (!cin->bitmap_table[i]) {
+ av_log(cin->avctx, AV_LOG_ERROR, "Can't allocate bitmap buffers.\n");
+ destroy_buffers(cin);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
+
static av_cold int cinvideo_decode_init(AVCodecContext *avctx)
{
CinVideoContext *cin = avctx->priv_data;
- unsigned int i;
cin->avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
@@ -55,11 +78,8 @@ static av_cold int cinvideo_decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
cin->bitmap_size = avctx->width * avctx->height;
- for (i = 0; i < 3; ++i) {
- cin->bitmap_table[i] = av_mallocz(cin->bitmap_size);
- if (!cin->bitmap_table[i])
- av_log(avctx, AV_LOG_ERROR, "Can't allocate bitmap buffers.\n");
- }
+ if (allocate_buffers(cin))
+ return AVERROR(ENOMEM);
return 0;
}
@@ -141,27 +161,30 @@ static int cin_decode_lzss(const unsigned char *src, int src_size,
return 0;
}
-static void cin_decode_rle(const unsigned char *src, int src_size,
+static int cin_decode_rle(const unsigned char *src, int src_size,
unsigned char *dst, int dst_size)
{
int len, code;
unsigned char *dst_end = dst + dst_size;
const unsigned char *src_end = src + src_size;
- while (src < src_end && dst < dst_end) {
+ while (src + 1 < src_end && dst < dst_end) {
code = *src++;
if (code & 0x80) {
- if (src >= src_end)
- break;
len = code - 0x7F;
memset(dst, *src++, FFMIN(len, dst_end - dst));
} else {
len = code + 1;
+ if (len > src_end-src) {
+ av_log(NULL, AV_LOG_ERROR, "RLE overread\n");
+ return AVERROR_INVALIDDATA;
+ }
memcpy(dst, src, FFMIN3(len, dst_end - dst, src_end - src));
src += len;
}
dst += len;
}
+ return 0;
}
static int cinvideo_decode_frame(AVCodecContext *avctx,
@@ -188,19 +211,17 @@ static int cinvideo_decode_frame(AVCodecContext *avctx,
if (palette_colors_count > 256)
return AVERROR_INVALIDDATA;
for (i = 0; i < palette_colors_count; ++i) {
- cin->palette[i] = bytestream_get_le24(&buf);
+ cin->palette[i] = 0xFFU << 24 | bytestream_get_le24(&buf);
bitmap_frame_size -= 3;
}
} else {
for (i = 0; i < palette_colors_count; ++i) {
- cin->palette[buf[0]] = AV_RL24(buf + 1);
+ cin->palette[buf[0]] = 0xFFU << 24 | AV_RL24(buf + 1);
buf += 4;
bitmap_frame_size -= 4;
}
}
- bitmap_frame_size = FFMIN(cin->bitmap_size, bitmap_frame_size);
-
/* note: the decoding routines below assumes that
* surface.width = surface.pitch */
switch (bitmap_frame_type) {
@@ -215,7 +236,7 @@ static int cinvideo_decode_frame(AVCodecContext *avctx,
cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
break;
case 35:
- cin_decode_huffman(buf, bitmap_frame_size,
+ bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size,
cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size);
cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size,
cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size);
@@ -251,11 +272,8 @@ static int cinvideo_decode_frame(AVCodecContext *avctx,
break;
}
- if ((res = ff_reget_buffer(avctx, cin->frame)) < 0) {
- av_log(cin->avctx, AV_LOG_ERROR,
- "delphinecinvideo: reget_buffer() failed to allocate a frame\n");
+ if ((res = ff_reget_buffer(avctx, cin->frame)) < 0)
return res;
- }
memcpy(cin->frame->data[1], cin->palette, sizeof(cin->palette));
cin->frame->palette_has_changed = 1;
@@ -278,12 +296,10 @@ static int cinvideo_decode_frame(AVCodecContext *avctx,
static av_cold int cinvideo_decode_end(AVCodecContext *avctx)
{
CinVideoContext *cin = avctx->priv_data;
- int i;
av_frame_free(&cin->frame);
- for (i = 0; i < 3; ++i)
- av_free(cin->bitmap_table[i]);
+ destroy_buffers(cin);
return 0;
}
diff --git a/libavcodec/dss_sp.c b/libavcodec/dss_sp.c
index 5862fd4d15..909ad1f2e0 100644
--- a/libavcodec/dss_sp.c
+++ b/libavcodec/dss_sp.c
@@ -2,20 +2,20 @@
* Digital Speech Standard - Standard Play mode (DSS SP) audio decoder.
* Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,7 @@
#define DSS_SP_FRAME_SIZE 42
#define DSS_SP_SAMPLE_COUNT (66 * SUBFRAMES)
-#define DSS_SP_FORMULA(a, b, c) ((((a) << 15) + (b) * (c)) + 0x4000) >> 15
+#define DSS_SP_FORMULA(a, b, c) (((((a) << 15) + (b) * (c)) + 0x4000) >> 15)
typedef struct DssSpSubframe {
int16_t gain;
@@ -50,6 +50,7 @@ typedef struct DssSpFrame {
} DssSpFrame;
typedef struct DssSpContext {
+ AVCodecContext *avctx;
int32_t excitation[288 + 6];
int32_t history[187];
DssSpFrame fparam;
@@ -296,6 +297,7 @@ static av_cold int dss_sp_decode_init(AVCodecContext *avctx)
memset(p->history, 0, sizeof(p->history));
p->pulse_dec_mode = 1;
+ p->avctx = avctx;
return 0;
}
@@ -378,7 +380,7 @@ static void dss_sp_unpack_coeffs(DssSpContext *p, const uint8_t *src)
if (C72_binomials[index] <= combined_pulse_pos) {
combined_pulse_pos -= C72_binomials[index];
- fparam->sf[subframe_idx].pulse_pos[(index ^ 7) - 1] = i;
+ fparam->sf[subframe_idx].pulse_pos[6 - index] = i;
if (!index)
break;
@@ -400,10 +402,15 @@ static void dss_sp_unpack_coeffs(DssSpContext *p, const uint8_t *src)
combined_pitch /= 151;
- for (i = 1; i < SUBFRAMES; i++) {
+ for (i = 1; i < SUBFRAMES - 1; i++) {
fparam->pitch_lag[i] = combined_pitch % 48;
combined_pitch /= 48;
}
+ if (combined_pitch > 47) {
+ av_log (p->avctx, AV_LOG_WARNING, "combined_pitch was too large\n");
+ combined_pitch = 0;
+ }
+ fparam->pitch_lag[i] = combined_pitch;
pitch_lag = fparam->pitch_lag[0];
for (i = 1; i < SUBFRAMES; i++) {
diff --git a/libavcodec/dump_extradata_bsf.c b/libavcodec/dump_extradata_bsf.c
index 404fb59262..568f920979 100644
--- a/libavcodec/dump_extradata_bsf.c
+++ b/libavcodec/dump_extradata_bsf.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,6 @@ static int dump_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx,
}
AVBitStreamFilter ff_dump_extradata_bsf={
- "dump_extra",
- 0,
- dump_extradata,
+ .name = "dump_extra",
+ .filter = dump_extradata,
};
diff --git a/libavcodec/dv.c b/libavcodec/dv.c
index 81d28d1fb3..31d1315f38 100644
--- a/libavcodec/dv.c
+++ b/libavcodec/dv.c
@@ -16,20 +16,20 @@
* Many thanks to Dan Dennedy <dan@dennedy.org> for providing wealth
* of DV technical info.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,7 @@
#include "simple_idct.h"
/* XXX: also include quantization */
-RL_VLC_ELEM ff_dv_rl_vlc[1184];
+RL_VLC_ELEM ff_dv_rl_vlc[1664];
static inline void dv_calc_mb_coordinates(const AVDVProfile *d, int chan,
int seq, int slot, uint16_t *tbl)
@@ -173,20 +173,9 @@ static inline void dv_calc_mb_coordinates(const AVDVProfile *d, int chan,
}
}
-/* quantization quanta by QNO for DV100 */
-static const uint8_t dv100_qstep[16] = {
- 1, /* QNO = 0 and 1 both have no quantization */
- 1,
- 2, 3, 4, 5, 6, 7, 8, 16, 18, 20, 22, 24, 28, 52
-};
-
-static const uint8_t dv_quant_areas[4] = { 6, 21, 43, 64 };
-
int ff_dv_init_dynamic_tables(DVVideoContext *ctx, const AVDVProfile *d)
{
int j, i, c, s, p;
- uint32_t *factor1, *factor2;
- const int *iweight1, *iweight2;
p = i = 0;
for (c = 0; c < d->n_difchan; c++) {
@@ -204,38 +193,6 @@ int ff_dv_init_dynamic_tables(DVVideoContext *ctx, const AVDVProfile *d)
}
}
- factor1 = &ctx->idct_factor[0];
- factor2 = &ctx->idct_factor[DV_PROFILE_IS_HD(d) ? 4096 : 2816];
- if (d->height == 720) {
- iweight1 = &ff_dv_iweight_720_y[0];
- iweight2 = &ff_dv_iweight_720_c[0];
- } else {
- iweight1 = &ff_dv_iweight_1080_y[0];
- iweight2 = &ff_dv_iweight_1080_c[0];
- }
- if (DV_PROFILE_IS_HD(d)) {
- for (c = 0; c < 4; c++) {
- for (s = 0; s < 16; s++) {
- for (i = 0; i < 64; i++) {
- *factor1++ = (dv100_qstep[s] << (c + 9)) * iweight1[i];
- *factor2++ = (dv100_qstep[s] << (c + 9)) * iweight2[i];
- }
- }
- }
- } else {
- iweight1 = &ff_dv_iweight_88[0];
- for (j = 0; j < 2; j++, iweight1 = &ff_dv_iweight_248[0]) {
- for (s = 0; s < 22; s++) {
- for (i = c = 0; c < 4; c++) {
- for (; i < dv_quant_areas[c]; i++) {
- *factor1 = iweight1[i] << (ff_dv_quant_shifts[s][c] + 1);
- *factor2++ = (*factor1++) << 1;
- }
- }
- }
- }
- }
-
return 0;
}
@@ -277,7 +234,7 @@ av_cold int ff_dvvideo_init(AVCodecContext *avctx)
* to accelerate the parsing of partial codes */
init_vlc(&dv_vlc, TEX_VLC_BITS, j, new_dv_vlc_len,
1, 1, new_dv_vlc_bits, 2, 2, 0);
- assert(dv_vlc.table_size == 1184);
+ av_assert1(dv_vlc.table_size == 1664);
for (i = 0; i < dv_vlc.table_size; i++) {
int code = dv_vlc.table[i][0];
@@ -303,3 +260,4 @@ av_cold int ff_dvvideo_init(AVCodecContext *avctx)
return 0;
}
+
diff --git a/libavcodec/dv.h b/libavcodec/dv.h
index b458aeab29..5d282633dd 100644
--- a/libavcodec/dv.h
+++ b/libavcodec/dv.h
@@ -2,20 +2,20 @@
* Constants for DV codec
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,7 +45,7 @@ typedef struct DVVideoContext {
uint8_t dv_zigzag[2][64];
- void (*get_pixels)(int16_t *block, const uint8_t *pixels, int line_size);
+ void (*get_pixels)(int16_t *block, const uint8_t *pixels, ptrdiff_t line_size);
void (*fdct[2])(int16_t *block);
void (*idct_put[2])(uint8_t *dest, int line_size, int16_t *block);
me_cmp_func ildct_cmp;
@@ -80,10 +80,6 @@ enum dv_pack_type {
#define DV_PROFILE_IS_1080i50(p) (((p)->video_stype == 0x14) && ((p)->dsf == 1))
#define DV_PROFILE_IS_720p50(p) (((p)->video_stype == 0x18) && ((p)->dsf == 1))
-/* minimum number of bytes to read from a DV stream in order to
- * determine the profile */
-#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */
-
/**
* largest possible DV frame, in bytes (1080i50)
*/
@@ -94,11 +90,12 @@ enum dv_pack_type {
*/
#define DV_MAX_BPM 8
-#define TEX_VLC_BITS 9
+#define TEX_VLC_BITS 10
-extern RL_VLC_ELEM ff_dv_rl_vlc[1184];
+extern RL_VLC_ELEM ff_dv_rl_vlc[1664];
int ff_dv_init_dynamic_tables(DVVideoContext *s, const AVDVProfile *d);
+
int ff_dvvideo_init(AVCodecContext *avctx);
static inline int dv_work_pool_size(const AVDVProfile *d)
diff --git a/libavcodec/dv_profile.c b/libavcodec/dv_profile.c
index 74c529d727..e336e081ea 100644
--- a/libavcodec/dv_profile.c
+++ b/libavcodec/dv_profile.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,6 +21,7 @@
#include <stdint.h>
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/pixdesc.h"
@@ -256,22 +257,30 @@ void ff_dv_print_profiles(void *logctx, int loglevel)
#endif /* CONFIG_DVPROFILE */
-const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys,
+const AVDVProfile* ff_dv_frame_profile(AVCodecContext* codec, const AVDVProfile *sys,
const uint8_t *frame, unsigned buf_size)
{
#if CONFIG_DVPROFILE
int i, dsf, stype;
- if (buf_size < 80 * 5 + 48 + 4)
+ if(buf_size < DV_PROFILE_BYTES)
return NULL;
dsf = (frame[3] & 0x80) >> 7;
stype = frame[80 * 5 + 48 + 3] & 0x1f;
/* 576i50 25Mbps 4:1:1 is a special case */
- if (dsf == 1 && stype == 0 && frame[4] & 0x07 /* the APT field */)
+ if ((dsf == 1 && stype == 0 && frame[4] & 0x07 /* the APT field */) ||
+ (stype == 31 && codec && codec->codec_tag==AV_RL32("SL25") && codec->coded_width==720 && codec->coded_height==576))
return &dv_profiles[2];
+ if( stype == 0
+ && codec
+ && (codec->codec_tag==AV_RL32("dvsd") || codec->codec_tag==AV_RL32("CDVC"))
+ && codec->coded_width ==720
+ && codec->coded_height==576)
+ return &dv_profiles[1];
+
for (i = 0; i < FF_ARRAY_ELEMS(dv_profiles); i++)
if (dsf == dv_profiles[i].dsf && stype == dv_profiles[i].video_stype)
return &dv_profiles[i];
@@ -279,23 +288,62 @@ const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys,
/* check if old sys matches and assumes corrupted input */
if (sys && buf_size == sys->frame_size)
return sys;
+
+ /* hack for trac issue #217, dv files created with QuickTime 3 */
+ if ((frame[3] & 0x7f) == 0x3f && frame[80 * 5 + 48 + 3] == 0xff)
+ return &dv_profiles[dsf];
#endif
return NULL;
}
+#if FF_API_DV_FRAME_PROFILE
+const AVDVProfile* avpriv_dv_frame_profile2(AVCodecContext* codec, const AVDVProfile *sys,
+ const uint8_t *frame, unsigned buf_size)
+{
+ return ff_dv_frame_profile(codec, sys, frame, buf_size);
+}
+#endif
+
+const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys,
+ const uint8_t *frame, unsigned buf_size)
+{
+ return ff_dv_frame_profile(NULL, sys, frame, buf_size);
+}
+
const AVDVProfile *av_dv_codec_profile(int width, int height,
enum AVPixelFormat pix_fmt)
{
#if CONFIG_DVPROFILE
+ return av_dv_codec_profile2(width, height, pix_fmt, (AVRational){0, 0});
+#endif
+
+ return NULL;
+}
+
+const AVDVProfile *av_dv_codec_profile2(int width, int height,
+ enum AVPixelFormat pix_fmt,
+ AVRational frame_rate)
+{
+ const AVDVProfile *p = NULL;
+#if CONFIG_DVPROFILE
int i;
+ /* frame rate is necessary to select between 720p50 and 720p60 profiles */
+ int invalid_framerate = frame_rate.num == 0 || frame_rate.den == 0;
for (i = 0; i < FF_ARRAY_ELEMS(dv_profiles); i++)
if (height == dv_profiles[i].height &&
pix_fmt == dv_profiles[i].pix_fmt &&
width == dv_profiles[i].width)
- return &dv_profiles[i];
+ {
+ if( invalid_framerate || av_div_q(dv_profiles[i].time_base, frame_rate).num == 1 )
+ return &dv_profiles[i];
+
+ if(!p)
+ p = &dv_profiles[i];
+ }
#endif
- return NULL;
+ return p;
}
+
diff --git a/libavcodec/dv_profile.h b/libavcodec/dv_profile.h
index 5ad7b4f649..d22ad2663f 100644
--- a/libavcodec/dv_profile.h
+++ b/libavcodec/dv_profile.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,11 @@
#include "libavutil/rational.h"
#include "avcodec.h"
+/* minimum number of bytes to read from a DV stream in order to
+ * determine the profile */
+#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */
+
+
/*
* AVDVProfile is used to express the differences between various
* DV flavors. For now it's primarily used for differentiating
@@ -53,6 +58,15 @@ typedef struct AVDVProfile {
const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */
} AVDVProfile;
+#if FF_API_DV_FRAME_PROFILE
+/**
+ * @deprecated use av_dv_frame_profile()
+ */
+attribute_deprecated
+const AVDVProfile* avpriv_dv_frame_profile2(AVCodecContext* codec, const AVDVProfile *sys,
+ const uint8_t* frame, unsigned buf_size);
+#endif
+
/**
* Get a DV profile for the provided compressed frame.
*
@@ -69,4 +83,10 @@ const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys,
*/
const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt);
+/**
+ * Get a DV profile for the provided stream parameters.
+ * The frame rate is used as a best-effort parameter.
+ */
+const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate);
+
#endif /* AVCODEC_DV_PROFILE_H */
diff --git a/libavcodec/dv_profile_internal.h b/libavcodec/dv_profile_internal.h
index f93e7cad17..67d3a2b79a 100644
--- a/libavcodec/dv_profile_internal.h
+++ b/libavcodec/dv_profile_internal.h
@@ -1,27 +1,35 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_DV_PROFILE_INTERNAL_H
#define AVCODEC_DV_PROFILE_INTERNAL_H
+#include "dv_profile.h"
+
/**
* Print all allowed DV profiles into logctx at specified logging level.
*/
void ff_dv_print_profiles(void *logctx, int loglevel);
+/**
+ * Get a DV profile for the provided compressed frame.
+ */
+const AVDVProfile* ff_dv_frame_profile(AVCodecContext* codec, const AVDVProfile *sys,
+ const uint8_t *frame, unsigned buf_size);
+
#endif /* AVCODEC_DV_PROFILE_INTERNAL_H */
diff --git a/libavcodec/dv_tablegen.c b/libavcodec/dv_tablegen.c
index 9b2b9546d5..257934101a 100644
--- a/libavcodec/dv_tablegen.c
+++ b/libavcodec/dv_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dv_tablegen.h b/libavcodec/dv_tablegen.h
index b69721b591..941b5572be 100644
--- a/libavcodec/dv_tablegen.h
+++ b/libavcodec/dv_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#define AVCODEC_DV_TABLEGEN_H
#include <stdint.h>
+#include "libavutil/attributes.h"
#include "dvdata.h"
@@ -47,7 +48,7 @@ typedef struct dv_vlc_pair {
#else
static struct dv_vlc_pair dv_vlc_map[DV_VLC_MAP_RUN_SIZE][DV_VLC_MAP_LEV_SIZE];
-static void dv_vlc_map_tableinit(void)
+static av_cold void dv_vlc_map_tableinit(void)
{
int i, j;
for (i = 0; i < NB_DV_VLC - 1; i++) {
diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c
index 720e78669a..dd84a07664 100644
--- a/libavcodec/dvbsub.c
+++ b/libavcodec/dvbsub.c
@@ -2,20 +2,20 @@
* DVB subtitle encoding
* Copyright (c) 2005 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
@@ -23,7 +23,6 @@
#include "libavutil/colorspace.h"
typedef struct DVBSubtitleContext {
- int hide_state;
int object_version;
} DVBSubtitleContext;
@@ -194,6 +193,60 @@ static void dvb_encode_rle4(uint8_t **pq,
*pq = q;
}
+static void dvb_encode_rle8(uint8_t **pq,
+ const uint8_t *bitmap, int linesize,
+ int w, int h)
+{
+ uint8_t *q;
+ int x, y, len, x1, color;
+
+ q = *pq;
+
+ for (y = 0; y < h; y++) {
+ *q++ = 0x12;
+
+ x = 0;
+ while (x < w) {
+ x1 = x;
+ color = bitmap[x1++];
+ while (x1 < w && bitmap[x1] == color)
+ x1++;
+ len = x1 - x;
+ if (len == 1 && color) {
+ // 00000001 to 11111111 1 pixel in colour x
+ *q++ = color;
+ } else {
+ if (color == 0x00) {
+ // 00000000 0LLLLLLL L pixels (1-127) in colour 0 (L > 0)
+ len = FFMIN(len, 127);
+ *q++ = 0x00;
+ *q++ = len;
+ } else if (len > 2) {
+ // 00000000 1LLLLLLL CCCCCCCC L pixels (3-127) in colour C (L > 2)
+ len = FFMIN(len, 127);
+ *q++ = 0x00;
+ *q++ = 0x80+len;
+ *q++ = color;
+ }
+ else if (len == 2) {
+ *q++ = color;
+ *q++ = color;
+ } else {
+ *q++ = color;
+ len = 1;
+ }
+ }
+ x += len;
+ }
+ /* end of line */
+ // 00000000 00000000 end of 8-bit/pixel_code_string
+ *q++ = 0x00;
+ *q++ = 0x00;
+ bitmap += linesize;
+ }
+ *pq = q;
+}
+
static int encode_dvb_subtitles(DVBSubtitleContext *s,
uint8_t *outbuf, const AVSubtitle *h)
{
@@ -205,11 +258,9 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
page_id = 1;
- if (h->num_rects == 0 || !h->rects)
+ if (h->num_rects && !h->rects)
return -1;
- *q++ = 0x00; /* subtitle_stream_id */
-
/* page composition segment */
*q++ = 0x0f; /* sync_byte */
@@ -218,10 +269,7 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
pseg_len = q;
q += 2; /* segment length */
*q++ = 30; /* page_timeout (seconds) */
- if (s->hide_state)
- page_state = 0; /* normal case */
- else
- page_state = 2; /* mode change */
+ page_state = 2; /* mode change */
/* page_version = 0 + page_state */
*q++ = (s->object_version << 4) | (page_state << 2) | 3;
@@ -234,7 +282,7 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
bytestream_put_be16(&pseg_len, q - pseg_len - 2);
- if (!s->hide_state) {
+ if (h->num_rects) {
for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
/* CLUT segment */
@@ -245,10 +293,15 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
} else if (h->rects[clut_id]->nb_colors <= 16) {
/* 4 bpp, standard encoding */
bpp_index = 1;
+ } else if (h->rects[clut_id]->nb_colors <= 256) {
+ /* 8 bpp, standard encoding */
+ bpp_index = 2;
} else {
return -1;
}
+
+ /* CLUT segment */
*q++ = 0x0f; /* sync byte */
*q++ = 0x12; /* CLUT definition segment */
bytestream_put_be16(&q, page_id);
@@ -307,32 +360,37 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
*q++ = 0; /* 8 bit fill colors */
*q++ = 0x03; /* 4 bit and 2 bit fill colors */
- if (!s->hide_state) {
- bytestream_put_be16(&q, region_id); /* object_id == region_id */
- *q++ = (0 << 6) | (0 << 4);
- *q++ = 0;
- *q++ = 0xf0;
- *q++ = 0;
- }
+ bytestream_put_be16(&q, region_id); /* object_id == region_id */
+ *q++ = (0 << 6) | (0 << 4);
+ *q++ = 0;
+ *q++ = 0xf0;
+ *q++ = 0;
bytestream_put_be16(&pseg_len, q - pseg_len - 2);
}
- if (!s->hide_state) {
+ if (h->num_rects) {
for (object_id = 0; object_id < h->num_rects; object_id++) {
- /* Object Data segment */
+ void (*dvb_encode_rle)(uint8_t **pq,
+ const uint8_t *bitmap, int linesize,
+ int w, int h);
+ /* bpp_index maths */
if (h->rects[object_id]->nb_colors <= 4) {
/* 2 bpp, some decoders do not support it correctly */
- bpp_index = 0;
+ dvb_encode_rle = dvb_encode_rle2;
} else if (h->rects[object_id]->nb_colors <= 16) {
/* 4 bpp, standard encoding */
- bpp_index = 1;
+ dvb_encode_rle = dvb_encode_rle4;
+ } else if (h->rects[object_id]->nb_colors <= 256) {
+ /* 8 bpp, standard encoding */
+ dvb_encode_rle = dvb_encode_rle8;
} else {
return -1;
}
+ /* Object Data segment */
*q++ = 0x0f; /* sync byte */
*q++ = 0x13;
bytestream_put_be16(&q, page_id);
@@ -345,19 +403,12 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
non_modifying_color_flag */
{
uint8_t *ptop_field_len, *pbottom_field_len, *top_ptr, *bottom_ptr;
- void (*dvb_encode_rle)(uint8_t **pq,
- const uint8_t *bitmap, int linesize,
- int w, int h);
+
ptop_field_len = q;
q += 2;
pbottom_field_len = q;
q += 2;
- if (bpp_index == 0)
- dvb_encode_rle = dvb_encode_rle2;
- else
- dvb_encode_rle = dvb_encode_rle4;
-
top_ptr = q;
dvb_encode_rle(&q, h->rects[object_id]->pict.data[0], h->rects[object_id]->w * 2,
h->rects[object_id]->w, h->rects[object_id]->h >> 1);
@@ -384,10 +435,7 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
bytestream_put_be16(&pseg_len, q - pseg_len - 2);
- *q++ = 0xff; /* end of PES data */
-
s->object_version = (s->object_version + 1) & 0xf;
- s->hide_state = !s->hide_state;
return q - outbuf;
}
diff --git a/libavcodec/dvbsub_parser.c b/libavcodec/dvbsub_parser.c
index 2e7d8c2aee..af467f7b64 100644
--- a/libavcodec/dvbsub_parser.c
+++ b/libavcodec/dvbsub_parser.c
@@ -1,21 +1,21 @@
/*
- * DVB subtitle parser for Libav
+ * DVB subtitle parser for FFmpeg
* Copyright (c) 2005 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
@@ -123,11 +123,11 @@ static int dvbsub_parse(AVCodecParserContext *s,
{
if (*p == 0x0f)
{
- if (p + 6 <= p_end)
+ if (6 <= p_end - p)
{
len = AV_RB16(p + 4);
- if (p + len + 6 <= p_end)
+ if (len + 6 <= p_end - p)
{
*poutbuf_size += len + 6;
@@ -137,7 +137,7 @@ static int dvbsub_parse(AVCodecParserContext *s,
} else
break;
} else if (*p == 0xff) {
- if (p + 1 < p_end)
+ if (1 < p_end - p)
{
ff_dlog(avctx, "Junk at end of packet\n");
}
diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c
index d2b95bc53d..7c3dedf773 100644
--- a/libavcodec/dvbsubdec.c
+++ b/libavcodec/dvbsubdec.c
@@ -2,20 +2,20 @@
* DVB subtitle decoding
* Copyright (c) 2005 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include "bytestream.h"
#include "internal.h"
#include "libavutil/colorspace.h"
+#include "libavutil/opt.h"
#define DVBSUB_PAGE_SEGMENT 0x10
#define DVBSUB_REGION_SEGMENT 0x11
@@ -153,6 +154,7 @@ static void png_save2(const char *filename, uint32_t *bitmap, int w, int h)
typedef struct DVBSubCLUT {
int id;
+ int version;
uint32_t clut4[4];
uint32_t clut16[16];
@@ -179,6 +181,7 @@ typedef struct DVBSubObjectDisplay {
typedef struct DVBSubObject {
int id;
+ int version;
int type;
@@ -198,6 +201,7 @@ typedef struct DVBSubRegionDisplay {
typedef struct DVBSubRegion {
int id;
+ int version;
int width;
int height;
@@ -208,6 +212,7 @@ typedef struct DVBSubRegion {
uint8_t *pbuf;
int buf_size;
+ int dirty;
DVBSubObjectDisplay *display_list;
@@ -224,15 +229,19 @@ typedef struct DVBSubDisplayDefinition {
} DVBSubDisplayDefinition;
typedef struct DVBSubContext {
+ AVClass *class;
int composition_id;
int ancillary_id;
+ int version;
int time_out;
+ int compute_edt; /**< if 1 end display time calculated using pts
+ if 0 (Default) calculated using time out */
+ int64_t prev_start;
DVBSubRegion *region_list;
DVBSubCLUT *clut_list;
DVBSubObject *object_list;
- int display_list_size;
DVBSubRegionDisplay *display_list;
DVBSubDisplayDefinition *display_definition;
} DVBSubContext;
@@ -298,53 +307,59 @@ static void delete_region_display_list(DVBSubContext *ctx, DVBSubRegion *region)
obj2 = *obj2_ptr;
while (obj2 != object) {
- assert(obj2);
+ av_assert0(obj2);
obj2_ptr = &obj2->next;
obj2 = *obj2_ptr;
}
*obj2_ptr = obj2->next;
- av_free(obj2);
+ av_freep(&obj2);
}
}
}
region->display_list = display->region_list_next;
- av_free(display);
+ av_freep(&display);
}
}
-static void delete_state(DVBSubContext *ctx)
+static void delete_cluts(DVBSubContext *ctx)
{
- DVBSubRegion *region;
- DVBSubCLUT *clut;
-
- while (ctx->region_list) {
- region = ctx->region_list;
+ while (ctx->clut_list) {
+ DVBSubCLUT *clut = ctx->clut_list;
- ctx->region_list = region->next;
+ ctx->clut_list = clut->next;
- delete_region_display_list(ctx, region);
- av_free(region->pbuf);
- av_free(region);
+ av_freep(&clut);
}
+}
- while (ctx->clut_list) {
- clut = ctx->clut_list;
+static void delete_objects(DVBSubContext *ctx)
+{
+ while (ctx->object_list) {
+ DVBSubObject *object = ctx->object_list;
- ctx->clut_list = clut->next;
+ ctx->object_list = object->next;
- av_free(clut);
+ av_freep(&object);
}
+}
- av_freep(&ctx->display_definition);
+static void delete_regions(DVBSubContext *ctx)
+{
+ while (ctx->region_list) {
+ DVBSubRegion *region = ctx->region_list;
+
+ ctx->region_list = region->next;
+
+ delete_region_display_list(ctx, region);
- /* Should already be null */
- if (ctx->object_list)
- av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n");
+ av_freep(&region->pbuf);
+ av_freep(&region);
+ }
}
static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
@@ -352,15 +367,22 @@ static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
int i, r, g, b, a = 0;
DVBSubContext *ctx = avctx->priv_data;
- if (!avctx->extradata || avctx->extradata_size != 4) {
- av_log(avctx, AV_LOG_WARNING, "Invalid extradata, subtitle streams may be combined!\n");
+ if (!avctx->extradata || (avctx->extradata_size < 4) || ((avctx->extradata_size % 5 != 0) && (avctx->extradata_size != 4))) {
+ av_log(avctx, AV_LOG_WARNING, "Invalid DVB subtitles stream extradata!\n");
ctx->composition_id = -1;
ctx->ancillary_id = -1;
} else {
+ if (avctx->extradata_size > 5) {
+ av_log(avctx, AV_LOG_WARNING, "Decoding first DVB subtitles sub-stream\n");
+ }
+
ctx->composition_id = AV_RB16(avctx->extradata);
ctx->ancillary_id = AV_RB16(avctx->extradata + 2);
}
+ ctx->version = -1;
+ ctx->prev_start = AV_NOPTS_VALUE;
+
default_clut.id = -1;
default_clut.next = NULL;
@@ -429,30 +451,39 @@ static av_cold int dvbsub_close_decoder(AVCodecContext *avctx)
DVBSubContext *ctx = avctx->priv_data;
DVBSubRegionDisplay *display;
- delete_state(ctx);
+ delete_regions(ctx);
+
+ delete_objects(ctx);
+
+ delete_cluts(ctx);
+
+ av_freep(&ctx->display_definition);
while (ctx->display_list) {
display = ctx->display_list;
ctx->display_list = display->next;
- av_free(display);
+ av_freep(&display);
}
return 0;
}
-static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
+static int dvbsub_read_2bit_string(AVCodecContext *avctx,
+ uint8_t *destbuf, int dbuf_len,
const uint8_t **srcbuf, int buf_size,
- int non_mod, uint8_t *map_table)
+ int non_mod, uint8_t *map_table, int x_pos)
{
GetBitContext gb;
int bits;
int run_length;
- int pixels_read = 0;
+ int pixels_read = x_pos;
init_get_bits(&gb, *srcbuf, buf_size << 3);
+ destbuf += x_pos;
+
while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) {
bits = get_bits(&gb, 2);
@@ -513,14 +544,14 @@ static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
}
}
} else if (bits == 1) {
- pixels_read += 2;
if (map_table)
bits = map_table[0];
else
bits = 0;
- if (pixels_read <= dbuf_len) {
- *destbuf++ = bits;
+ run_length = 2;
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
*destbuf++ = bits;
+ pixels_read++;
}
} else {
(*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
@@ -539,25 +570,27 @@ static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
}
if (get_bits(&gb, 6))
- av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
+ av_log(avctx, AV_LOG_ERROR, "line overflow\n");
(*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
return pixels_read;
}
-static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
+static int dvbsub_read_4bit_string(AVCodecContext *avctx, uint8_t *destbuf, int dbuf_len,
const uint8_t **srcbuf, int buf_size,
- int non_mod, uint8_t *map_table)
+ int non_mod, uint8_t *map_table, int x_pos)
{
GetBitContext gb;
int bits;
int run_length;
- int pixels_read = 0;
+ int pixels_read = x_pos;
init_get_bits(&gb, *srcbuf, buf_size << 3);
+ destbuf += x_pos;
+
while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) {
bits = get_bits(&gb, 4);
@@ -637,14 +670,14 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
}
}
} else if (bits == 1) {
- pixels_read += 2;
if (map_table)
bits = map_table[0];
else
bits = 0;
- if (pixels_read <= dbuf_len) {
- *destbuf++ = bits;
+ run_length = 2;
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
*destbuf++ = bits;
+ pixels_read++;
}
} else {
if (map_table)
@@ -660,21 +693,24 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
}
if (get_bits(&gb, 8))
- av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
+ av_log(avctx, AV_LOG_ERROR, "line overflow\n");
(*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
return pixels_read;
}
-static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len,
+static int dvbsub_read_8bit_string(AVCodecContext *avctx,
+ uint8_t *destbuf, int dbuf_len,
const uint8_t **srcbuf, int buf_size,
- int non_mod, uint8_t *map_table)
+ int non_mod, uint8_t *map_table, int x_pos)
{
const uint8_t *sbuf_end = (*srcbuf) + buf_size;
int bits;
int run_length;
- int pixels_read = 0;
+ int pixels_read = x_pos;
+
+ destbuf += x_pos;
while (*srcbuf < sbuf_end && pixels_read < dbuf_len) {
bits = *(*srcbuf)++;
@@ -694,30 +730,151 @@ static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len,
if (run_length == 0) {
return pixels_read;
}
+
+ bits = 0;
} else {
bits = *(*srcbuf)++;
-
- if (non_mod == 1 && bits == 1)
- pixels_read += run_length;
}
- if (map_table)
- bits = map_table[0];
- else
- bits = 0;
- while (run_length-- > 0 && pixels_read < dbuf_len) {
- *destbuf++ = bits;
- pixels_read++;
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
}
}
}
if (*(*srcbuf)++)
- av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
+ av_log(avctx, AV_LOG_ERROR, "line overflow\n");
return pixels_read;
}
+static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_output)
+{
+ DVBSubContext *ctx = avctx->priv_data;
+ DVBSubRegionDisplay *display;
+ DVBSubDisplayDefinition *display_def = ctx->display_definition;
+ DVBSubRegion *region;
+ AVSubtitleRect *rect;
+ DVBSubCLUT *clut;
+ uint32_t *clut_table;
+ int i;
+ int offset_x=0, offset_y=0;
+ int ret = 0;
+
+
+ if (display_def) {
+ offset_x = display_def->x;
+ offset_y = display_def->y;
+ }
+
+ /* Not touching AVSubtitles again*/
+ if(sub->num_rects) {
+ avpriv_request_sample(ctx, "Different Version of Segment asked Twice\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ for (display = ctx->display_list; display; display = display->next) {
+ region = get_region(ctx, display->region_id);
+ if (region && region->dirty)
+ sub->num_rects++;
+ }
+
+ if(ctx->compute_edt == 0) {
+ sub->end_display_time = ctx->time_out * 1000;
+ *got_output = 1;
+ } else if (ctx->prev_start != AV_NOPTS_VALUE) {
+ sub->end_display_time = av_rescale_q((sub->pts - ctx->prev_start ), AV_TIME_BASE_Q, (AVRational){ 1, 1000 }) - 1;
+ *got_output = 1;
+ }
+ if (sub->num_rects > 0) {
+
+ sub->rects = av_mallocz_array(sizeof(*sub->rects), sub->num_rects);
+ if (!sub->rects) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ for(i=0; i<sub->num_rects; i++)
+ sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
+
+ i = 0;
+
+ for (display = ctx->display_list; display; display = display->next) {
+ region = get_region(ctx, display->region_id);
+
+ if (!region)
+ continue;
+
+ if (!region->dirty)
+ continue;
+
+ rect = sub->rects[i];
+ rect->x = display->x_pos + offset_x;
+ rect->y = display->y_pos + offset_y;
+ rect->w = region->width;
+ rect->h = region->height;
+ rect->nb_colors = (1 << region->depth);
+ rect->type = SUBTITLE_BITMAP;
+ rect->pict.linesize[0] = region->width;
+
+ clut = get_clut(ctx, region->clut);
+
+ if (!clut)
+ clut = &default_clut;
+
+ switch (region->depth) {
+ case 2:
+ clut_table = clut->clut4;
+ break;
+ case 8:
+ clut_table = clut->clut256;
+ break;
+ case 4:
+ default:
+ clut_table = clut->clut16;
+ break;
+ }
+
+ rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
+ if (!rect->pict.data[1]) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ memcpy(rect->pict.data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
+
+ rect->pict.data[0] = av_malloc(region->buf_size);
+ if (!rect->pict.data[0]) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ memcpy(rect->pict.data[0], region->pbuf, region->buf_size);
+
+ i++;
+ }
+ }
+
+ return 0;
+fail:
+ if (sub->rects) {
+ for(i=0; i<sub->num_rects; i++) {
+ rect = sub->rects[i];
+ if (rect) {
+ av_freep(&rect->pict.data[0]);
+ av_freep(&rect->pict.data[1]);
+ }
+ av_freep(&sub->rects[i]);
+ }
+ av_freep(&sub->rects);
+ }
+ sub->num_rects = 0;
+ return ret;
+}
static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDisplay *display,
const uint8_t *buf, int buf_size, int top_bottom, int non_mod)
@@ -736,6 +893,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
uint8_t *map_table;
+#if 0
ff_dlog(avctx, "DVB pixel block size %d, %s field:\n", buf_size,
top_bottom ? "bottom" : "top");
@@ -750,21 +908,22 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
if (i % 16)
ff_dlog(avctx, "\n");
+#endif
- if (region == 0)
+ if (!region)
return;
pbuf = region->pbuf;
+ region->dirty = 1;
x_pos = display->x_pos;
y_pos = display->y_pos;
- if ((y_pos & 1) != top_bottom)
- y_pos++;
+ y_pos += top_bottom;
while (buf < buf_end) {
- if (x_pos > region->width || y_pos > region->height) {
- av_log(avctx, AV_LOG_ERROR, "Invalid object location!\n");
+ if ((*buf!=0xf0 && x_pos >= region->width) || y_pos >= region->height) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid object location! %d-%d %d-%d %02x\n", x_pos, region->width, y_pos, region->height, *buf);
return;
}
@@ -777,9 +936,9 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
else
map_table = NULL;
- x_pos += dvbsub_read_2bit_string(pbuf + (y_pos * region->width) + x_pos,
- region->width - x_pos, &buf, buf_end - buf,
- non_mod, map_table);
+ x_pos = dvbsub_read_2bit_string(avctx, pbuf + (y_pos * region->width),
+ region->width, &buf, buf_end - buf,
+ non_mod, map_table, x_pos);
break;
case 0x11:
if (region->depth < 4) {
@@ -792,9 +951,9 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
else
map_table = NULL;
- x_pos += dvbsub_read_4bit_string(pbuf + (y_pos * region->width) + x_pos,
- region->width - x_pos, &buf, buf_end - buf,
- non_mod, map_table);
+ x_pos = dvbsub_read_4bit_string(avctx, pbuf + (y_pos * region->width),
+ region->width, &buf, buf_end - buf,
+ non_mod, map_table, x_pos);
break;
case 0x12:
if (region->depth < 8) {
@@ -802,9 +961,9 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
return;
}
- x_pos += dvbsub_read_8bit_string(pbuf + (y_pos * region->width) + x_pos,
- region->width - x_pos, &buf, buf_end - buf,
- non_mod, NULL);
+ x_pos = dvbsub_read_8bit_string(avctx, pbuf + (y_pos * region->width),
+ region->width, &buf, buf_end - buf,
+ non_mod, NULL, x_pos);
break;
case 0x20:
@@ -839,7 +998,6 @@ static int dvbsub_parse_object_segment(AVCodecContext *avctx,
DVBSubContext *ctx = avctx->priv_data;
const uint8_t *buf_end = buf + buf_size;
- const uint8_t *block;
int object_id;
DVBSubObject *object;
DVBSubObjectDisplay *display;
@@ -870,7 +1028,8 @@ static int dvbsub_parse_object_segment(AVCodecContext *avctx,
}
for (display = object->display_list; display; display = display->object_list_next) {
- block = buf;
+ const uint8_t *block = buf;
+ int bfl = bottom_field_len;
dvbsub_parse_pixel_data_block(avctx, display, block, top_field_len, 0,
non_modifying_color);
@@ -878,9 +1037,9 @@ static int dvbsub_parse_object_segment(AVCodecContext *avctx,
if (bottom_field_len > 0)
block = buf + top_field_len;
else
- bottom_field_len = top_field_len;
+ bfl = top_field_len;
- dvbsub_parse_pixel_data_block(avctx, display, block, bottom_field_len, 1,
+ dvbsub_parse_pixel_data_block(avctx, display, block, bfl, 1,
non_modifying_color);
}
@@ -900,6 +1059,7 @@ static int dvbsub_parse_clut_segment(AVCodecContext *avctx,
const uint8_t *buf_end = buf + buf_size;
int i, clut_id;
+ int version;
DVBSubCLUT *clut;
int entry_id, depth , full_range;
int y, cr, cb, alpha;
@@ -917,6 +1077,7 @@ static int dvbsub_parse_clut_segment(AVCodecContext *avctx,
ff_dlog(avctx, "\n");
clut_id = *buf++;
+ version = ((*buf)>>4)&15;
buf += 1;
clut = get_clut(ctx, clut_id);
@@ -929,11 +1090,16 @@ static int dvbsub_parse_clut_segment(AVCodecContext *avctx,
memcpy(clut, &default_clut, sizeof(DVBSubCLUT));
clut->id = clut_id;
+ clut->version = -1;
clut->next = ctx->clut_list;
ctx->clut_list = clut;
}
+ if (clut->version != version) {
+
+ clut->version = version;
+
while (buf + 4 < buf_end) {
entry_id = *buf++;
@@ -967,14 +1133,20 @@ static int dvbsub_parse_clut_segment(AVCodecContext *avctx,
YUV_TO_RGB2_CCIR(r, g, b, y);
ff_dlog(avctx, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha);
+ if (!!(depth & 0x80) + !!(depth & 0x40) + !!(depth & 0x20) > 1) {
+ ff_dlog(avctx, "More than one bit level marked: %x\n", depth);
+ if (avctx->strict_std_compliance > FF_COMPLIANCE_NORMAL)
+ return AVERROR_INVALIDDATA;
+ }
if (depth & 0x80)
clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha);
- if (depth & 0x40)
+ else if (depth & 0x40)
clut->clut16[entry_id] = RGBA(r,g,b,255 - alpha);
- if (depth & 0x20)
+ else if (depth & 0x20)
clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha);
}
+ }
return 0;
}
@@ -987,6 +1159,7 @@ static int dvbsub_parse_region_segment(AVCodecContext *avctx,
const uint8_t *buf_end = buf + buf_size;
int region_id, object_id;
+ int av_unused version;
DVBSubRegion *region;
DVBSubObject *object;
DVBSubObjectDisplay *display;
@@ -1005,11 +1178,13 @@ static int dvbsub_parse_region_segment(AVCodecContext *avctx,
return AVERROR(ENOMEM);
region->id = region_id;
+ region->version = -1;
region->next = ctx->region_list;
ctx->region_list = region;
}
+ version = ((*buf)>>4) & 15;
fill = ((*buf++) >> 3) & 1;
region->width = AV_RB16(buf);
@@ -1023,10 +1198,15 @@ static int dvbsub_parse_region_segment(AVCodecContext *avctx,
region->buf_size = region->width * region->height;
region->pbuf = av_malloc(region->buf_size);
- if (!region->pbuf)
+ if (!region->pbuf) {
+ region->buf_size =
+ region->width =
+ region->height = 0;
return AVERROR(ENOMEM);
+ }
fill = 1;
+ region->dirty = 0;
}
region->depth = 1 << (((*buf++) >> 2) & 7);
@@ -1036,9 +1216,10 @@ static int dvbsub_parse_region_segment(AVCodecContext *avctx,
}
region->clut = *buf++;
- if (region->depth == 8)
+ if (region->depth == 8) {
region->bgcolor = *buf++;
- else {
+ buf += 1;
+ } else {
buf += 1;
if (region->depth == 4)
@@ -1102,7 +1283,7 @@ static int dvbsub_parse_region_segment(AVCodecContext *avctx,
}
static int dvbsub_parse_page_segment(AVCodecContext *avctx,
- const uint8_t *buf, int buf_size)
+ const uint8_t *buf, int buf_size, AVSubtitle *sub, int *got_output)
{
DVBSubContext *ctx = avctx->priv_data;
DVBSubRegionDisplay *display;
@@ -1111,22 +1292,36 @@ static int dvbsub_parse_page_segment(AVCodecContext *avctx,
const uint8_t *buf_end = buf + buf_size;
int region_id;
int page_state;
+ int timeout;
+ int version;
if (buf_size < 1)
return AVERROR_INVALIDDATA;
- ctx->time_out = *buf++;
+ timeout = *buf++;
+ version = ((*buf)>>4) & 15;
page_state = ((*buf++) >> 2) & 3;
+ if (ctx->version == version) {
+ return 0;
+ }
+
+ ctx->time_out = timeout;
+ ctx->version = version;
+
ff_dlog(avctx, "Page time out %ds, state %d\n", ctx->time_out, page_state);
- if (page_state == 2) {
- delete_state(ctx);
+ if(ctx->compute_edt == 1)
+ save_subtitle_set(avctx, sub, got_output);
+
+ if (page_state == 1 || page_state == 2) {
+ delete_regions(ctx);
+ delete_objects(ctx);
+ delete_cluts(ctx);
}
tmp_display_list = ctx->display_list;
ctx->display_list = NULL;
- ctx->display_list_size = 0;
while (buf + 5 < buf_end) {
region_id = *buf++;
@@ -1157,7 +1352,6 @@ static int dvbsub_parse_page_segment(AVCodecContext *avctx,
display->next = ctx->display_list;
ctx->display_list = display;
- ctx->display_list_size++;
ff_dlog(avctx, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos);
}
@@ -1167,7 +1361,7 @@ static int dvbsub_parse_page_segment(AVCodecContext *avctx,
tmp_display_list = display->next;
- av_free(display);
+ av_freep(&display);
}
return 0;
@@ -1195,6 +1389,9 @@ static void save_display_set(DVBSubContext *ctx)
for (display = ctx->display_list; display; display = display->next) {
region = get_region(ctx, display->region_id);
+ if (!region)
+ return;
+
if (x_pos == -1) {
x_pos = display->x_pos;
y_pos = display->y_pos;
@@ -1225,17 +1422,20 @@ static void save_display_set(DVBSubContext *ctx)
pbuf = av_malloc(width * height * 4);
if (!pbuf)
- return AVERROR(ENOMEM);
+ return;
for (display = ctx->display_list; display; display = display->next) {
region = get_region(ctx, display->region_id);
+ if (!region)
+ return;
+
x_off = display->x_pos - x_pos;
y_off = display->y_pos - y_pos;
clut = get_clut(ctx, region->clut);
- if (clut == 0)
+ if (!clut)
clut = &default_clut;
switch (region->depth) {
@@ -1264,7 +1464,7 @@ static void save_display_set(DVBSubContext *ctx)
png_save2(filename, pbuf, width, height);
- av_free(pbuf);
+ av_freep(&pbuf);
}
fileno_index++;
@@ -1299,14 +1499,18 @@ static int dvbsub_parse_display_definition_segment(AVCodecContext *avctx,
display_def->y = 0;
display_def->width = bytestream_get_be16(&buf) + 1;
display_def->height = bytestream_get_be16(&buf) + 1;
+ if (!avctx->width || !avctx->height) {
+ avctx->width = display_def->width;
+ avctx->height = display_def->height;
+ }
if (buf_size < 13)
return AVERROR_INVALIDDATA;
if (info_byte & 1<<3) { // display_window_flag
display_def->x = bytestream_get_be16(&buf);
- display_def->y = bytestream_get_be16(&buf);
display_def->width = bytestream_get_be16(&buf) - display_def->x + 1;
+ display_def->y = bytestream_get_be16(&buf);
display_def->height = bytestream_get_be16(&buf) - display_def->y + 1;
}
@@ -1314,98 +1518,16 @@ static int dvbsub_parse_display_definition_segment(AVCodecContext *avctx,
}
static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
- int buf_size, AVSubtitle *sub)
+ int buf_size, AVSubtitle *sub,int *got_output)
{
DVBSubContext *ctx = avctx->priv_data;
- DVBSubDisplayDefinition *display_def = ctx->display_definition;
-
- DVBSubRegion *region;
- DVBSubRegionDisplay *display;
- AVSubtitleRect *rect;
- DVBSubCLUT *clut;
- uint32_t *clut_table;
- int i;
- int offset_x=0, offset_y=0;
-
- sub->rects = NULL;
- sub->start_display_time = 0;
- sub->end_display_time = ctx->time_out * 1000;
- sub->format = 0;
-
- if (display_def) {
- offset_x = display_def->x;
- offset_y = display_def->y;
- }
-
- sub->num_rects = ctx->display_list_size;
- if (sub->num_rects <= 0)
- return AVERROR_INVALIDDATA;
-
- sub->rects = av_mallocz_array(sub->num_rects * sub->num_rects,
- sizeof(*sub->rects));
- if (!sub->rects)
- return AVERROR(ENOMEM);
-
- i = 0;
-
- for (display = ctx->display_list; display; display = display->next) {
- region = get_region(ctx, display->region_id);
- rect = sub->rects[i];
-
- if (!region)
- continue;
-
- rect->x = display->x_pos + offset_x;
- rect->y = display->y_pos + offset_y;
- rect->w = region->width;
- rect->h = region->height;
- rect->nb_colors = 16;
- rect->type = SUBTITLE_BITMAP;
- rect->pict.linesize[0] = region->width;
-
- clut = get_clut(ctx, region->clut);
-
- if (!clut)
- clut = &default_clut;
-
- switch (region->depth) {
- case 2:
- clut_table = clut->clut4;
- break;
- case 8:
- clut_table = clut->clut256;
- break;
- case 4:
- default:
- clut_table = clut->clut16;
- break;
- }
-
- rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
- if (!rect->pict.data[1]) {
- av_free(sub->rects);
- return AVERROR(ENOMEM);
- }
- memcpy(rect->pict.data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
-
- rect->pict.data[0] = av_malloc(region->buf_size);
- if (!rect->pict.data[0]) {
- av_free(rect->pict.data[1]);
- av_free(sub->rects);
- return AVERROR(ENOMEM);
- }
- memcpy(rect->pict.data[0], region->pbuf, region->buf_size);
-
- i++;
- }
-
- sub->num_rects = i;
+ if(ctx->compute_edt == 0)
+ save_subtitle_set(avctx, sub, got_output);
#ifdef DEBUG
save_display_set(ctx);
#endif
-
- return 1;
+ return 0;
}
static int dvbsub_decode(AVCodecContext *avctx,
@@ -1421,6 +1543,8 @@ static int dvbsub_decode(AVCodecContext *avctx,
int page_id;
int segment_length;
int i;
+ int ret = 0;
+ int got_segment = 0;
ff_dlog(avctx, "DVB sub packet:\n");
@@ -1449,9 +1573,14 @@ static int dvbsub_decode(AVCodecContext *avctx,
segment_length = AV_RB16(p);
p += 2;
+ if (avctx->debug & FF_DEBUG_STARTCODE) {
+ av_log(avctx, AV_LOG_DEBUG, "segment_type:%d page_id:%d segment_length:%d\n", segment_type, page_id, segment_length);
+ }
+
if (p_end - p < segment_length) {
ff_dlog(avctx, "incomplete or broken packet");
- return -1;
+ ret = -1;
+ goto end;
}
if (page_id == ctx->composition_id || page_id == ctx->ancillary_id ||
@@ -1459,24 +1588,29 @@ static int dvbsub_decode(AVCodecContext *avctx,
int ret = 0;
switch (segment_type) {
case DVBSUB_PAGE_SEGMENT:
- ret = dvbsub_parse_page_segment(avctx, p, segment_length);
+ ret = dvbsub_parse_page_segment(avctx, p, segment_length, sub, data_size);
+ got_segment |= 1;
break;
case DVBSUB_REGION_SEGMENT:
ret = dvbsub_parse_region_segment(avctx, p, segment_length);
+ got_segment |= 2;
break;
case DVBSUB_CLUT_SEGMENT:
ret = dvbsub_parse_clut_segment(avctx, p, segment_length);
+ if (ret < 0) goto end;
+ got_segment |= 4;
break;
case DVBSUB_OBJECT_SEGMENT:
ret = dvbsub_parse_object_segment(avctx, p, segment_length);
+ got_segment |= 8;
break;
case DVBSUB_DISPLAYDEFINITION_SEGMENT:
ret = dvbsub_parse_display_definition_segment(avctx, p,
segment_length);
break;
case DVBSUB_DISPLAY_SEGMENT:
- ret = dvbsub_display_end_segment(avctx, p, segment_length, sub);
- *data_size = ret;
+ ret = dvbsub_display_end_segment(avctx, p, segment_length, sub, data_size);
+ got_segment |= 16;
break;
default:
ff_dlog(avctx, "Subtitling segment type 0x%x, page id %d, length %d\n",
@@ -1484,15 +1618,42 @@ static int dvbsub_decode(AVCodecContext *avctx,
break;
}
if (ret < 0)
- return ret;
+ goto end;
}
p += segment_length;
}
+ // Some streams do not send a display segment but if we have all the other
+ // segments then we need no further data.
+ if (got_segment == 15) {
+ av_log(avctx, AV_LOG_DEBUG, "Missing display_end_segment, emulating\n");
+ dvbsub_display_end_segment(avctx, p, 0, sub, data_size);
+ }
+
+end:
+ if(ret < 0) {
+ *data_size = 0;
+ avsubtitle_free(sub);
+ return ret;
+ } else {
+ if(ctx->compute_edt == 1 )
+ FFSWAP(int64_t, ctx->prev_start, sub->pts);
+ }
return p - buf;
}
+#define DS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_SUBTITLE_PARAM
+static const AVOption options[] = {
+ {"compute_edt", "compute end of time using pts or timeout", offsetof(DVBSubContext, compute_edt), FF_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DS},
+ {NULL}
+};
+static const AVClass dvbsubdec_class = {
+ .class_name = "DVB Sub Decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
AVCodec ff_dvbsub_decoder = {
.name = "dvbsub",
@@ -1503,4 +1664,5 @@ AVCodec ff_dvbsub_decoder = {
.init = dvbsub_init_decoder,
.close = dvbsub_close_decoder,
.decode = dvbsub_decode,
+ .priv_class = &dvbsubdec_class,
};
diff --git a/libavcodec/dvd_nav_parser.c b/libavcodec/dvd_nav_parser.c
new file mode 100644
index 0000000000..6e2352dc3c
--- /dev/null
+++ b/libavcodec/dvd_nav_parser.c
@@ -0,0 +1,115 @@
+/*
+ * DVD navigation block parser for FFmpeg
+ * Copyright (c) 2013 The FFmpeg Project
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "avcodec.h"
+#include "get_bits.h"
+#include "parser.h"
+
+#define PCI_SIZE 980
+#define DSI_SIZE 1018
+
+/* parser definition */
+typedef struct DVDNavParseContext {
+ uint32_t lba;
+ uint8_t buffer[PCI_SIZE+DSI_SIZE];
+ int copied;
+} DVDNavParseContext;
+
+static av_cold int dvd_nav_parse_init(AVCodecParserContext *s)
+{
+ DVDNavParseContext *pc = s->priv_data;
+
+ pc->lba = 0xFFFFFFFF;
+ pc->copied = 0;
+ return 0;
+}
+
+static int dvd_nav_parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
+ const uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ DVDNavParseContext *pc1 = s->priv_data;
+ int lastPacket = 0;
+ int valid = 0;
+
+ s->pict_type = AV_PICTURE_TYPE_NONE;
+
+ avctx->time_base.num = 1;
+ avctx->time_base.den = 90000;
+
+ if (buf && buf_size) {
+ switch(buf[0]) {
+ case 0x00:
+ if (buf_size == PCI_SIZE) {
+ /* PCI */
+ uint32_t lba = AV_RB32(&buf[0x01]);
+ uint32_t startpts = AV_RB32(&buf[0x0D]);
+ uint32_t endpts = AV_RB32(&buf[0x11]);
+
+ if (endpts > startpts) {
+ pc1->lba = lba;
+ s->pts = (int64_t)startpts;
+ s->duration = endpts - startpts;
+
+ memcpy(pc1->buffer, buf, PCI_SIZE);
+ pc1->copied = PCI_SIZE;
+ valid = 1;
+ }
+ }
+ break;
+
+ case 0x01:
+ if ((buf_size == DSI_SIZE) && (pc1->copied == PCI_SIZE)) {
+ /* DSI */
+ uint32_t lba = AV_RB32(&buf[0x05]);
+
+ if (lba == pc1->lba) {
+ memcpy(pc1->buffer + pc1->copied, buf, DSI_SIZE);
+ lastPacket = 1;
+ valid = 1;
+ }
+ }
+ break;
+ }
+ }
+
+ if (!valid || lastPacket) {
+ pc1->copied = 0;
+ pc1->lba = 0xFFFFFFFF;
+ }
+
+ if (lastPacket) {
+ *poutbuf = pc1->buffer;
+ *poutbuf_size = sizeof(pc1->buffer);
+ } else {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ }
+
+ return buf_size;
+}
+
+AVCodecParser ff_dvd_nav_parser = {
+ .codec_ids = { AV_CODEC_ID_DVD_NAV },
+ .priv_data_size = sizeof(DVDNavParseContext),
+ .parser_init = dvd_nav_parse_init,
+ .parser_parse = dvd_nav_parse,
+};
diff --git a/libavcodec/dvdata.c b/libavcodec/dvdata.c
index 985cda7ab5..231569a328 100644
--- a/libavcodec/dvdata.c
+++ b/libavcodec/dvdata.c
@@ -2,20 +2,20 @@
* Constants for DV codec
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,71 +69,6 @@ const uint8_t ff_dv_quant_shifts[22][4] = {
const uint8_t ff_dv_quant_offset[4] = { 6, 3, 0, 1 };
-const int ff_dv_iweight_88[64] = {
- 32768, 16710, 16710, 17735, 17015, 17735, 18197, 18079,
- 18079, 18197, 18725, 18559, 19196, 18559, 18725, 19284,
- 19108, 19692, 19692, 19108, 19284, 21400, 19645, 20262,
- 20214, 20262, 19645, 21400, 22733, 21845, 20867, 20815,
- 20815, 20867, 21845, 22733, 23173, 23173, 21400, 21400,
- 21400, 23173, 23173, 24600, 23764, 22017, 22017, 23764,
- 24600, 25267, 24457, 22672, 24457, 25267, 25971, 25191,
- 25191, 25971, 26715, 27962, 26715, 29642, 29642, 31536,
-};
-const int ff_dv_iweight_248[64] = {
- 32768, 17735, 16710, 18079, 18725, 21400, 17735, 19196,
- 19108, 21845, 16384, 17735, 18725, 21400, 16710, 18079,
- 20262, 23173, 18197, 19692, 18725, 20262, 20815, 23764,
- 17735, 19196, 19108, 21845, 20262, 23173, 18197, 19692,
- 21400, 24457, 19284, 20867, 21400, 23173, 22017, 25191,
- 18725, 20262, 20815, 23764, 21400, 24457, 19284, 20867,
- 24457, 27962, 22733, 24600, 25971, 29642, 21400, 23173,
- 22017, 25191, 24457, 27962, 22733, 24600, 25971, 29642,
-};
-
-/**
- * The "inverse" DV100 weights are actually just the spec weights (zig-zagged).
- */
-const int ff_dv_iweight_1080_y[64] = {
- 128, 16, 16, 17, 17, 17, 18, 18,
- 18, 18, 18, 18, 19, 18, 18, 19,
- 19, 19, 19, 19, 19, 42, 38, 40,
- 40, 40, 38, 42, 44, 43, 41, 41,
- 41, 41, 43, 44, 45, 45, 42, 42,
- 42, 45, 45, 48, 46, 43, 43, 46,
- 48, 49, 48, 44, 48, 49, 101, 98,
- 98, 101, 104, 109, 104, 116, 116, 123,
-};
-const int ff_dv_iweight_1080_c[64] = {
- 128, 16, 16, 17, 17, 17, 25, 25,
- 25, 25, 26, 25, 26, 25, 26, 26,
- 26, 27, 27, 26, 26, 42, 38, 40,
- 40, 40, 38, 42, 44, 43, 41, 41,
- 41, 41, 43, 44, 91, 91, 84, 84,
- 84, 91, 91, 96, 93, 86, 86, 93,
- 96, 197, 191, 177, 191, 197, 203, 197,
- 197, 203, 209, 219, 209, 232, 232, 246,
-};
-const int ff_dv_iweight_720_y[64] = {
- 128, 16, 16, 17, 17, 17, 18, 18,
- 18, 18, 18, 18, 19, 18, 18, 19,
- 19, 19, 19, 19, 19, 42, 38, 40,
- 40, 40, 38, 42, 44, 43, 41, 41,
- 41, 41, 43, 44, 68, 68, 63, 63,
- 63, 68, 68, 96, 92, 86, 86, 92,
- 96, 98, 96, 88, 96, 98, 202, 196,
- 196, 202, 208, 218, 208, 232, 232, 246,
-};
-const int ff_dv_iweight_720_c[64] = {
- 128, 24, 24, 26, 26, 26, 36, 36,
- 36, 36, 36, 36, 38, 36, 36, 38,
- 38, 38, 38, 38, 38, 84, 76, 80,
- 80, 80, 76, 84, 88, 86, 82, 82,
- 82, 82, 86, 88, 182, 182, 168, 168,
- 168, 182, 182, 192, 186, 192, 172, 186,
- 192, 394, 382, 354, 382, 394, 406, 394,
- 394, 406, 418, 438, 418, 464, 464, 492,
-};
-
/*
* There's a catch about the following three tables: the mapping they establish
* between (run, level) and vlc is not 1-1. So you have to watch out for that
diff --git a/libavcodec/dvdata.h b/libavcodec/dvdata.h
index 8e7c0fbcdf..e0ed043c47 100644
--- a/libavcodec/dvdata.h
+++ b/libavcodec/dvdata.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,13 +26,6 @@ extern const uint8_t ff_dv_zigzag248_direct[64];
extern const uint8_t ff_dv_quant_shifts[22][4];
extern const uint8_t ff_dv_quant_offset[4];
-extern const int ff_dv_iweight_88[64];
-extern const int ff_dv_iweight_248[64];
-extern const int ff_dv_iweight_1080_y[64];
-extern const int ff_dv_iweight_1080_c[64];
-extern const int ff_dv_iweight_720_y[64];
-extern const int ff_dv_iweight_720_c[64];
-
#define NB_DV_VLC 409
extern const uint16_t ff_dv_vlc_bits[NB_DV_VLC];
diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c
index 92f557fdb6..fbd6bf504b 100644
--- a/libavcodec/dvdec.c
+++ b/libavcodec/dvdec.c
@@ -13,20 +13,20 @@
* Many thanks to Dan Dennedy <dan@dennedy.org> for providing wealth
* of DV technical info.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,12 +35,14 @@
* DV decoder
*/
+#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "dv.h"
+#include "dv_profile_internal.h"
#include "dvdata.h"
#include "get_bits.h"
#include "idctdsp.h"
@@ -60,18 +62,136 @@ typedef struct BlockInfo {
static const int dv_iweight_bits = 14;
+static const uint16_t dv_iweight_88[64] = {
+ 32768, 16705, 16705, 17734, 17032, 17734, 18205, 18081,
+ 18081, 18205, 18725, 18562, 19195, 18562, 18725, 19266,
+ 19091, 19705, 19705, 19091, 19266, 21407, 19643, 20267,
+ 20228, 20267, 19643, 21407, 22725, 21826, 20853, 20806,
+ 20806, 20853, 21826, 22725, 23170, 23170, 21407, 21400,
+ 21407, 23170, 23170, 24598, 23786, 22018, 22018, 23786,
+ 24598, 25251, 24465, 22654, 24465, 25251, 25972, 25172,
+ 25172, 25972, 26722, 27969, 26722, 29692, 29692, 31521,
+};
+static const uint16_t dv_iweight_248[64] = {
+ 32768, 16384, 16705, 16705, 17734, 17734, 17734, 17734,
+ 18081, 18081, 18725, 18725, 21407, 21407, 19091, 19091,
+ 19195, 19195, 18205, 18205, 18725, 18725, 19705, 19705,
+ 20267, 20267, 21826, 21826, 23170, 23170, 20806, 20806,
+ 20267, 20267, 19266, 19266, 21407, 21407, 20853, 20853,
+ 21400, 21400, 23786, 23786, 24465, 24465, 22018, 22018,
+ 23170, 23170, 22725, 22725, 24598, 24598, 24465, 24465,
+ 25172, 25172, 27969, 27969, 25972, 25972, 29692, 29692
+};
+
+/**
+ * The "inverse" DV100 weights are actually just the spec weights (zig-zagged).
+ */
+static const uint16_t dv_iweight_1080_y[64] = {
+ 128, 16, 16, 17, 17, 17, 18, 18,
+ 18, 18, 18, 18, 19, 18, 18, 19,
+ 19, 19, 19, 19, 19, 42, 38, 40,
+ 40, 40, 38, 42, 44, 43, 41, 41,
+ 41, 41, 43, 44, 45, 45, 42, 42,
+ 42, 45, 45, 48, 46, 43, 43, 46,
+ 48, 49, 48, 44, 48, 49, 101, 98,
+ 98, 101, 104, 109, 104, 116, 116, 123,
+};
+static const uint16_t dv_iweight_1080_c[64] = {
+ 128, 16, 16, 17, 17, 17, 25, 25,
+ 25, 25, 26, 25, 26, 25, 26, 26,
+ 26, 27, 27, 26, 26, 42, 38, 40,
+ 40, 40, 38, 42, 44, 43, 41, 41,
+ 41, 41, 43, 44, 91, 91, 84, 84,
+ 84, 91, 91, 96, 93, 86, 86, 93,
+ 96, 197, 191, 177, 191, 197, 203, 197,
+ 197, 203, 209, 219, 209, 232, 232, 246,
+};
+static const uint16_t dv_iweight_720_y[64] = {
+ 128, 16, 16, 17, 17, 17, 18, 18,
+ 18, 18, 18, 18, 19, 18, 18, 19,
+ 19, 19, 19, 19, 19, 42, 38, 40,
+ 40, 40, 38, 42, 44, 43, 41, 41,
+ 41, 41, 43, 44, 68, 68, 63, 63,
+ 63, 68, 68, 96, 92, 86, 86, 92,
+ 96, 98, 96, 88, 96, 98, 202, 196,
+ 196, 202, 208, 218, 208, 232, 232, 246,
+};
+static const uint16_t dv_iweight_720_c[64] = {
+ 128, 24, 24, 26, 26, 26, 36, 36,
+ 36, 36, 36, 36, 38, 36, 36, 38,
+ 38, 38, 38, 38, 38, 84, 76, 80,
+ 80, 80, 76, 84, 88, 86, 82, 82,
+ 82, 82, 86, 88, 182, 182, 168, 168,
+ 168, 182, 182, 192, 186, 192, 172, 186,
+ 192, 394, 382, 354, 382, 394, 406, 394,
+ 394, 406, 418, 438, 418, 464, 464, 492,
+};
+
+static void dv_init_weight_tables(DVVideoContext *ctx, const AVDVProfile *d)
+{
+ int j, i, c, s;
+ uint32_t *factor1 = &ctx->idct_factor[0],
+ *factor2 = &ctx->idct_factor[DV_PROFILE_IS_HD(d) ? 4096 : 2816];
+
+ if (DV_PROFILE_IS_HD(d)) {
+ /* quantization quanta by QNO for DV100 */
+ static const uint8_t dv100_qstep[16] = {
+ 1, /* QNO = 0 and 1 both have no quantization */
+ 1,
+ 2, 3, 4, 5, 6, 7, 8, 16, 18, 20, 22, 24, 28, 52
+ };
+ const uint16_t *iweight1, *iweight2;
+
+ if (d->height == 720) {
+ iweight1 = &dv_iweight_720_y[0];
+ iweight2 = &dv_iweight_720_c[0];
+ } else {
+ iweight1 = &dv_iweight_1080_y[0];
+ iweight2 = &dv_iweight_1080_c[0];
+ }
+ for (c = 0; c < 4; c++) {
+ for (s = 0; s < 16; s++) {
+ for (i = 0; i < 64; i++) {
+ *factor1++ = (dv100_qstep[s] << (c + 9)) * iweight1[i];
+ *factor2++ = (dv100_qstep[s] << (c + 9)) * iweight2[i];
+ }
+ }
+ }
+ } else {
+ static const uint8_t dv_quant_areas[4] = { 6, 21, 43, 64 };
+ const uint16_t *iweight1 = &dv_iweight_88[0];
+ for (j = 0; j < 2; j++, iweight1 = &dv_iweight_248[0]) {
+ for (s = 0; s < 22; s++) {
+ for (i = c = 0; c < 4; c++) {
+ for (; i < dv_quant_areas[c]; i++) {
+ *factor1 = iweight1[i] << (ff_dv_quant_shifts[s][c] + 1);
+ *factor2++ = (*factor1++) << 1;
+ }
+ }
+ }
+ }
+ }
+}
+
static av_cold int dvvideo_decode_init(AVCodecContext *avctx)
{
DVVideoContext *s = avctx->priv_data;
IDCTDSPContext idsp;
int i;
+ memset(&idsp,0, sizeof(idsp));
ff_idctdsp_init(&idsp, avctx);
for (i = 0; i < 64; i++)
s->dv_zigzag[0][i] = idsp.idct_permutation[ff_zigzag_direct[i]];
- memcpy(s->dv_zigzag[1], ff_dv_zigzag248_direct, sizeof(s->dv_zigzag[1]));
+ if (avctx->lowres){
+ for (i = 0; i < 64; i++){
+ int j = ff_dv_zigzag248_direct[i];
+ s->dv_zigzag[1][i] = idsp.idct_permutation[(j & 7) + (j & 8) * 4 + (j & 48) / 2];
+ }
+ }else
+ memcpy(s->dv_zigzag[1], ff_dv_zigzag248_direct, sizeof(s->dv_zigzag[1]));
s->idct_put[0] = idsp.idct_put;
s->idct_put[1] = ff_simple_idct248_put;
@@ -169,11 +289,11 @@ static int dv_decode_video_segment(AVCodecContext *avctx, void *arg)
LOCAL_ALIGNED_16(int16_t, sblock, [5 * DV_MAX_BPM], [64]);
LOCAL_ALIGNED_16(uint8_t, mb_bit_buffer, [80 + FF_INPUT_BUFFER_PADDING_SIZE]); /* allow some slack */
LOCAL_ALIGNED_16(uint8_t, vs_bit_buffer, [80 * 5 + FF_INPUT_BUFFER_PADDING_SIZE]); /* allow some slack */
- const int log2_blocksize = 3;
+ const int log2_blocksize = 3-s->avctx->lowres;
int is_field_mode[5];
- assert((((int) mb_bit_buffer) & 7) == 0);
- assert((((int) vs_bit_buffer) & 7) == 0);
+ av_assert1((((int) mb_bit_buffer) & 7) == 0);
+ av_assert1((((int) vs_bit_buffer) & 7) == 0);
memset(sblock, 0, 5 * DV_MAX_BPM * sizeof(*sblock));
@@ -264,7 +384,7 @@ static int dv_decode_video_segment(AVCodecContext *avctx, void *arg)
flush_put_bits(&vs_pb);
for (mb_index = 0; mb_index < 5; mb_index++) {
for (j = 0; j < s->sys->bpm; j++) {
- if (mb->pos < 64) {
+ if (mb->pos < 64 && get_bits_left(&gb) > 0) {
ff_dlog(avctx, "start %d:%d\n", mb_index, j);
dv_decode_ac(&gb, mb, block);
}
@@ -317,9 +437,9 @@ static int dv_decode_video_segment(AVCodecContext *avctx, void *arg)
int x, y;
mb->idct_put(pixels, 8, block);
for (y = 0; y < (1 << log2_blocksize); y++, c_ptr += s->frame->linesize[j], pixels += 8) {
- ptr1 = pixels + (1 << (log2_blocksize - 1));
+ ptr1 = pixels + ((1 << (log2_blocksize))>>1);
c_ptr1 = c_ptr + (s->frame->linesize[j] << log2_blocksize);
- for (x = 0; x < (1 << (log2_blocksize - 1)); x++) {
+ for (x = 0; x < (1 << FFMAX(log2_blocksize - 1, 0)); x++) {
c_ptr[x] = pixels[x];
c_ptr1[x] = ptr1[x];
}
@@ -354,7 +474,7 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data,
int apt, is16_9, ret;
const AVDVProfile *sys;
- sys = av_dv_frame_profile(s->sys, buf, buf_size);
+ sys = ff_dv_frame_profile(avctx, s->sys, buf, buf_size);
if (!sys || buf_size < sys->frame_size) {
av_log(avctx, AV_LOG_ERROR, "could not find dv frame profile\n");
return -1; /* NOTE: we only accept several full frames */
@@ -366,6 +486,7 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "Error initializing the work tables.\n");
return ret;
}
+ dv_init_weight_tables(s, sys);
s->sys = sys;
}
@@ -388,13 +509,16 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data,
ff_set_sar(avctx, s->sys->sar[is16_9]);
}
- if (ff_get_buffer(avctx, s->frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0)
+ return ret;
s->frame->interlaced_frame = 1;
s->frame->top_field_first = 0;
+ /* Determine the codec's field order from the packet */
+ if ( *vsc_pack == dv_video_control ) {
+ s->frame->top_field_first = !(vsc_pack[3] & 0x40);
+ }
+
s->buf = buf;
avctx->execute(avctx, dv_decode_video_segment, s->work_chunks, NULL,
dv_work_pool_size(s->sys), sizeof(DVwork_chunk));
@@ -416,4 +540,5 @@ AVCodec ff_dvvideo_decoder = {
.init = dvvideo_decode_init,
.decode = dvvideo_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+ .max_lowres = 3,
};
diff --git a/libavcodec/dvdsub_parser.c b/libavcodec/dvdsub_parser.c
index 2ad3b33602..32a945ed65 100644
--- a/libavcodec/dvdsub_parser.c
+++ b/libavcodec/dvdsub_parser.c
@@ -2,20 +2,20 @@
* DVD subtitle decoding
* Copyright (c) 2005 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,8 +45,11 @@ static int dvdsub_parse(AVCodecParserContext *s,
DVDSubParseContext *pc = s->priv_data;
if (pc->packet_index == 0) {
- if (buf_size < 2)
- return 0;
+ if (buf_size < 2 || AV_RB16(buf) && buf_size < 6) {
+ if (buf_size)
+ av_log(avctx, AV_LOG_DEBUG, "Parser input %d too small\n", buf_size);
+ return buf_size;
+ }
pc->packet_len = AV_RB16(buf);
if (pc->packet_len == 0) /* HD-DVD subpicture packet */
pc->packet_len = AV_RB32(buf+2);
diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c
index a309e74346..673fc6051e 100644
--- a/libavcodec/dvdsubdec.c
+++ b/libavcodec/dvdsubdec.c
@@ -2,20 +2,20 @@
* DVD subtitle decoding
* Copyright (c) 2005 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,12 +25,26 @@
#include "libavutil/attributes.h"
#include "libavutil/colorspace.h"
+#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/avstring.h"
+#include "libavutil/bswap.h"
-typedef struct DVDSubContext {
- uint32_t palette[16];
- int has_palette;
+typedef struct DVDSubContext
+{
+ AVClass *class;
+ uint32_t palette[16];
+ char *palette_str;
+ char *ifo_str;
+ int has_palette;
+ uint8_t colormap[4];
+ uint8_t alpha[256];
+ uint8_t buf[0x10000];
+ int buf_size;
+ int forced_subs_only;
+#ifdef DEBUG
+ int sub_id;
+#endif
} DVDSubContext;
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
@@ -94,6 +108,12 @@ static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
int x, y, len, color;
uint8_t *d;
+ if (start >= buf_size)
+ return -1;
+
+ if (w <= 0 || h <= 0)
+ return -1;
+
bit_len = (buf_size - start) * 8;
init_get_bits(&gb, buf + start, bit_len);
@@ -125,17 +145,24 @@ static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
static void guess_palette(DVDSubContext* ctx,
uint32_t *rgba_palette,
- uint8_t *colormap,
- uint8_t *alpha,
uint32_t subtitle_color)
{
+ static const uint8_t level_map[4][4] = {
+ // this configuration (full range, lowest to highest) in tests
+ // seemed most common, so assume this
+ {0xff},
+ {0x00, 0xff},
+ {0x00, 0x80, 0xff},
+ {0x00, 0x55, 0xaa, 0xff},
+ };
uint8_t color_used[16] = { 0 };
int nb_opaque_colors, i, level, j, r, g, b;
+ uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
- if (ctx->has_palette) {
- for (i = 0; i < 4; i++)
+ if(ctx->has_palette) {
+ for(i = 0; i < 4; i++)
rgba_palette[i] = (ctx->palette[colormap[i]] & 0x00ffffff)
- | ((alpha[i] * 17) << 24);
+ | ((alpha[i] * 17U) << 24);
return;
}
@@ -153,18 +180,18 @@ static void guess_palette(DVDSubContext* ctx,
if (nb_opaque_colors == 0)
return;
- j = nb_opaque_colors;
+ j = 0;
memset(color_used, 0, 16);
for(i = 0; i < 4; i++) {
if (alpha[i] != 0) {
if (!color_used[colormap[i]]) {
- level = (0xff * j) / nb_opaque_colors;
+ level = level_map[nb_opaque_colors][j];
r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
color_used[colormap[i]] = (i + 1);
- j--;
+ j++;
} else {
rgba_palette[i] = (rgba_palette[color_used[colormap[i]] - 1] & 0x00ffffff) |
((alpha[i] * 17) << 24);
@@ -173,6 +200,21 @@ static void guess_palette(DVDSubContext* ctx,
}
}
+static void reset_rects(AVSubtitle *sub_header)
+{
+ int i;
+
+ if (sub_header->rects) {
+ for (i = 0; i < sub_header->num_rects; i++) {
+ av_freep(&sub_header->rects[i]->pict.data[0]);
+ av_freep(&sub_header->rects[i]->pict.data[1]);
+ av_freep(&sub_header->rects[i]);
+ }
+ av_freep(&sub_header->rects);
+ sub_header->num_rects = 0;
+ }
+}
+
#define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
@@ -180,15 +222,14 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
{
int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
int big_offsets, offset_size, is_8bit = 0;
- const uint8_t *yuv_palette = 0;
- uint8_t colormap[4] = { 0 }, alpha[256] = { 0 };
+ const uint8_t *yuv_palette = NULL;
+ uint8_t *colormap = ctx->colormap, *alpha = ctx->alpha;
int date;
int i;
int is_menu = 0;
if (buf_size < 10)
return -1;
- memset(sub_header, 0, sizeof(*sub_header));
if (AV_RB16(buf) == 0) { /* HD subpicture with 4-byte offsets */
big_offsets = 1;
@@ -202,6 +243,9 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
cmd_pos = READ_OFFSET(buf + cmd_pos);
+ if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size)
+ return AVERROR(EAGAIN);
+
while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
date = AV_RB16(buf + cmd_pos);
next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
@@ -310,19 +354,11 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
w = x2 - x1 + 1;
if (w < 0)
w = 0;
- h = y2 - y1;
+ h = y2 - y1 + 1;
if (h < 0)
h = 0;
if (w > 0 && h > 0) {
- if (sub_header->rects) {
- for (i = 0; i < sub_header->num_rects; i++) {
- av_freep(&sub_header->rects[i]->pict.data[0]);
- av_freep(&sub_header->rects[i]->pict.data[1]);
- av_freep(&sub_header->rects[i]);
- }
- av_freep(&sub_header->rects);
- sub_header->num_rects = 0;
- }
+ reset_rects(sub_header);
sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
if (!sub_header->rects)
@@ -334,23 +370,24 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
bitmap = sub_header->rects[0]->pict.data[0] = av_malloc(w * h);
if (!bitmap)
goto fail;
- decode_rle(bitmap, w * 2, w, (h + 1) / 2,
- buf, offset1, buf_size, is_8bit);
- decode_rle(bitmap + w, w * 2, w, h / 2,
- buf, offset2, buf_size, is_8bit);
+ if (decode_rle(bitmap, w * 2, w, (h + 1) / 2,
+ buf, offset1, buf_size, is_8bit) < 0)
+ goto fail;
+ if (decode_rle(bitmap + w, w * 2, w, h / 2,
+ buf, offset2, buf_size, is_8bit) < 0)
+ goto fail;
sub_header->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
if (!sub_header->rects[0]->pict.data[1])
goto fail;
if (is_8bit) {
- if (yuv_palette == 0)
+ if (!yuv_palette)
goto fail;
sub_header->rects[0]->nb_colors = 256;
yuv_a_to_rgba(yuv_palette, alpha, (uint32_t*)sub_header->rects[0]->pict.data[1], 256);
} else {
sub_header->rects[0]->nb_colors = 4;
- guess_palette(ctx,
- (uint32_t*)sub_header->rects[0]->pict.data[1],
- colormap, alpha, 0xffff00);
+ guess_palette(ctx, (uint32_t*)sub_header->rects[0]->pict.data[1],
+ 0xffff00);
}
sub_header->rects[0]->x = x1;
sub_header->rects[0]->y = y1;
@@ -358,8 +395,13 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
sub_header->rects[0]->h = h;
sub_header->rects[0]->type = SUBTITLE_BITMAP;
sub_header->rects[0]->pict.linesize[0] = w;
+ sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
}
}
+ if (next_cmd_pos < cmd_pos) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid command offset\n");
+ break;
+ }
if (next_cmd_pos == cmd_pos)
break;
cmd_pos = next_cmd_pos;
@@ -367,15 +409,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
if (sub_header->num_rects > 0)
return is_menu;
fail:
- if (!sub_header->rects) {
- for (i = 0; i < sub_header->num_rects; i++) {
- av_freep(&sub_header->rects[i]->pict.data[0]);
- av_freep(&sub_header->rects[i]->pict.data[1]);
- av_freep(&sub_header->rects[i]);
- }
- av_freep(&sub_header->rects);
- sub_header->num_rects = 0;
- }
+ reset_rects(sub_header);
return -1;
}
@@ -446,16 +480,19 @@ static int find_smallest_bounding_rectangle(AVSubtitle *s)
}
#ifdef DEBUG
+#define ALPHA_MIX(A,BACK,FORE) (((255-(A)) * (BACK) + (A) * (FORE)) / 255)
static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
uint32_t *rgba_palette)
{
- int x, y, v;
+ int x, y, alpha;
+ uint32_t v;
+ int back[3] = {0, 255, 0}; /* green background */
FILE *f;
f = fopen(filename, "w");
if (!f) {
perror(filename);
- exit(1);
+ return;
}
fprintf(f, "P6\n"
"%d %d\n"
@@ -464,15 +501,31 @@ static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
for(y = 0; y < h; y++) {
for(x = 0; x < w; x++) {
v = rgba_palette[bitmap[y * w + x]];
- putc((v >> 16) & 0xff, f);
- putc((v >> 8) & 0xff, f);
- putc((v >> 0) & 0xff, f);
+ alpha = v >> 24;
+ putc(ALPHA_MIX(alpha, back[0], (v >> 16) & 0xff), f);
+ putc(ALPHA_MIX(alpha, back[1], (v >> 8) & 0xff), f);
+ putc(ALPHA_MIX(alpha, back[2], (v >> 0) & 0xff), f);
}
}
fclose(f);
}
#endif
+static int append_to_cached_buf(AVCodecContext *avctx,
+ const uint8_t *buf, int buf_size)
+{
+ DVDSubContext *ctx = avctx->priv_data;
+
+ if (ctx->buf_size >= sizeof(ctx->buf) - buf_size) {
+ av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
+ "too large SPU packets aborted.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ memcpy(ctx->buf + ctx->buf_size, buf, buf_size);
+ ctx->buf_size += buf_size;
+ return 0;
+}
+
static int dvdsub_decode(AVCodecContext *avctx,
void *data, int *data_size,
AVPacket *avpkt)
@@ -483,10 +536,25 @@ static int dvdsub_decode(AVCodecContext *avctx,
AVSubtitle *sub = data;
int is_menu;
+ if (ctx->buf_size) {
+ int ret = append_to_cached_buf(avctx, buf, buf_size);
+ if (ret < 0) {
+ *data_size = 0;
+ return ret;
+ }
+ buf = ctx->buf;
+ buf_size = ctx->buf_size;
+ }
+
is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size);
+ if (is_menu == AVERROR(EAGAIN)) {
+ *data_size = 0;
+ return append_to_cached_buf(avctx, buf, buf_size);
+ }
if (is_menu < 0) {
no_subtitle:
+ reset_rects(sub);
*data_size = 0;
return buf_size;
@@ -494,61 +562,184 @@ static int dvdsub_decode(AVCodecContext *avctx,
if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
goto no_subtitle;
+ if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED))
+ goto no_subtitle;
+
#if defined(DEBUG)
+ {
+ char ppm_name[32];
+
+ snprintf(ppm_name, sizeof(ppm_name), "/tmp/%05d.ppm", ctx->sub_id++);
ff_dlog(NULL, "start=%d ms end =%d ms\n",
sub->start_display_time,
sub->end_display_time);
- ppm_save("/tmp/a.ppm", sub->rects[0]->pict.data[0],
- sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]);
+ ppm_save(ppm_name, sub->rects[0]->pict.data[0],
+ sub->rects[0]->w, sub->rects[0]->h, (uint32_t*) sub->rects[0]->pict.data[1]);
+ }
#endif
+ ctx->buf_size = 0;
*data_size = 1;
return buf_size;
}
-static av_cold int dvdsub_init(AVCodecContext *avctx)
+static void parse_palette(DVDSubContext *ctx, char *p)
{
- DVDSubContext *ctx = avctx->priv_data;
- char *data, *cur;
+ int i;
+
+ ctx->has_palette = 1;
+ for(i=0;i<16;i++) {
+ ctx->palette[i] = strtoul(p, &p, 16);
+ while(*p == ',' || av_isspace(*p))
+ p++;
+ }
+}
+
+static int parse_ifo_palette(DVDSubContext *ctx, char *p)
+{
+ FILE *ifo;
+ char ifostr[12];
+ uint32_t sp_pgci, pgci, off_pgc, pgc;
+ uint8_t r, g, b, yuv[65], *buf;
+ int i, y, cb, cr, r_add, g_add, b_add;
int ret = 0;
+ const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
+
+ ctx->has_palette = 0;
+ if ((ifo = fopen(p, "r")) == NULL) {
+ av_log(ctx, AV_LOG_WARNING, "Unable to open IFO file \"%s\": %s\n", p, av_err2str(AVERROR(errno)));
+ return AVERROR_EOF;
+ }
+ if (fread(ifostr, 12, 1, ifo) != 1 || memcmp(ifostr, "DVDVIDEO-VTS", 12)) {
+ av_log(ctx, AV_LOG_WARNING, "\"%s\" is not a proper IFO file\n", p);
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+ if (fseek(ifo, 0xCC, SEEK_SET) == -1) {
+ ret = AVERROR(errno);
+ goto end;
+ }
+ if (fread(&sp_pgci, 4, 1, ifo) == 1) {
+ pgci = av_be2ne32(sp_pgci) * 2048;
+ if (fseek(ifo, pgci + 0x0C, SEEK_SET) == -1) {
+ ret = AVERROR(errno);
+ goto end;
+ }
+ if (fread(&off_pgc, 4, 1, ifo) == 1) {
+ pgc = pgci + av_be2ne32(off_pgc);
+ if (fseek(ifo, pgc + 0xA4, SEEK_SET) == -1) {
+ ret = AVERROR(errno);
+ goto end;
+ }
+ if (fread(yuv, 64, 1, ifo) == 1) {
+ buf = yuv;
+ for(i=0; i<16; i++) {
+ y = *++buf;
+ cr = *++buf;
+ cb = *++buf;
+ YUV_TO_RGB1_CCIR(cb, cr);
+ YUV_TO_RGB2_CCIR(r, g, b, y);
+ ctx->palette[i] = (r << 16) + (g << 8) + b;
+ buf++;
+ }
+ ctx->has_palette = 1;
+ }
+ }
+ }
+ if (ctx->has_palette == 0) {
+ av_log(ctx, AV_LOG_WARNING, "Failed to read palette from IFO file \"%s\"\n", p);
+ ret = AVERROR_INVALIDDATA;
+ }
+end:
+ fclose(ifo);
+ return ret;
+}
+
+static int dvdsub_parse_extradata(AVCodecContext *avctx)
+{
+ DVDSubContext *ctx = (DVDSubContext*) avctx->priv_data;
+ char *dataorig, *data;
+ int ret = 1;
if (!avctx->extradata || !avctx->extradata_size)
- return 0;
+ return 1;
- data = av_malloc(avctx->extradata_size + 1);
+ dataorig = data = av_malloc(avctx->extradata_size+1);
if (!data)
return AVERROR(ENOMEM);
memcpy(data, avctx->extradata, avctx->extradata_size);
data[avctx->extradata_size] = '\0';
- cur = data;
-
- while (*cur) {
- if (strncmp("palette:", cur, 8) == 0) {
- int i;
- char *p = cur + 8;
- ctx->has_palette = 1;
- for (i = 0; i < 16; i++) {
- ctx->palette[i] = strtoul(p, &p, 16);
- while (*p == ',' || av_isspace(*p))
- p++;
- }
- } else if (!strncmp("size:", cur, 5)) {
+
+ for(;;) {
+ int pos = strcspn(data, "\n\r");
+ if (pos==0 && *data==0)
+ break;
+
+ if (strncmp("palette:", data, 8) == 0) {
+ parse_palette(ctx, data + 8);
+ } else if (strncmp("size:", data, 5) == 0) {
int w, h;
- if (sscanf(cur + 5, "%dx%d", &w, &h) == 2) {
+ if (sscanf(data + 5, "%dx%d", &w, &h) == 2) {
ret = ff_set_dimensions(avctx, w, h);
if (ret < 0)
goto fail;
}
}
- cur += strcspn(cur, "\n\r");
- cur += strspn(cur, "\n\r");
+
+ data += pos;
+ data += strspn(data, "\n\r");
}
fail:
- av_free(data);
+ av_free(dataorig);
return ret;
}
+static av_cold int dvdsub_init(AVCodecContext *avctx)
+{
+ DVDSubContext *ctx = avctx->priv_data;
+ int ret;
+
+ if ((ret = dvdsub_parse_extradata(avctx)) < 0)
+ return ret;
+
+ if (ctx->ifo_str)
+ parse_ifo_palette(ctx, ctx->ifo_str);
+ if (ctx->palette_str)
+ parse_palette(ctx, ctx->palette_str);
+ if (ctx->has_palette) {
+ int i;
+ av_log(avctx, AV_LOG_DEBUG, "palette:");
+ for(i=0;i<16;i++)
+ av_log(avctx, AV_LOG_DEBUG, " 0x%06x", ctx->palette[i]);
+ av_log(avctx, AV_LOG_DEBUG, "\n");
+ }
+
+ return 1;
+}
+
+static av_cold int dvdsub_close(AVCodecContext *avctx)
+{
+ DVDSubContext *ctx = avctx->priv_data;
+ ctx->buf_size = 0;
+ return 0;
+}
+
+#define OFFSET(field) offsetof(DVDSubContext, field)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
+ { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
+ { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD},
+ { NULL }
+};
+static const AVClass dvdsub_class = {
+ .class_name = "dvdsubdec",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_dvdsub_decoder = {
.name = "dvdsub",
.long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
@@ -557,4 +748,6 @@ AVCodec ff_dvdsub_decoder = {
.priv_data_size = sizeof(DVDSubContext),
.init = dvdsub_init,
.decode = dvdsub_decode,
+ .close = dvdsub_close,
+ .priv_class = &dvdsub_class,
};
diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c
index f62e943e7f..425f0af9ee 100644
--- a/libavcodec/dvdsubenc.c
+++ b/libavcodec/dvdsubenc.c
@@ -2,27 +2,35 @@
* DVD subtitle encoding
* Copyright (c) 2005 Wolfram Gloger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "bytestream.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/bprint.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
-#undef NDEBUG
-#include <assert.h>
+typedef struct {
+ AVClass *class;
+ uint32_t global_palette[16];
+ int even_rows_fix;
+} DVDSubtitleContext;
// ncnt is the nibble counter
#define PUTNIBBLE(val)\
@@ -53,7 +61,7 @@ static void dvd_encode_rle(uint8_t **pq,
if (bitmap[x+len] != color)
break;
color = cmap[color];
- assert(color < 4);
+ av_assert0(color < 4);
if (len < 0x04) {
PUTNIBBLE((len << 2)|color);
} else if (len < 0x10) {
@@ -86,72 +94,265 @@ static void dvd_encode_rle(uint8_t **pq,
*pq = q;
}
-static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,
+static int color_distance(uint32_t a, uint32_t b)
+{
+ int r = 0, d, i;
+ int alpha_a = 8, alpha_b = 8;
+
+ for (i = 24; i >= 0; i -= 8) {
+ d = alpha_a * (int)((a >> i) & 0xFF) -
+ alpha_b * (int)((b >> i) & 0xFF);
+ r += d * d;
+ alpha_a = a >> 28;
+ alpha_b = b >> 28;
+ }
+ return r;
+}
+
+/**
+ * Count colors used in a rectangle, quantizing alpha and grouping by
+ * nearest global palette entry.
+ */
+static void count_colors(AVCodecContext *avctx, unsigned hits[33],
+ const AVSubtitleRect *r)
+{
+ DVDSubtitleContext *dvdc = avctx->priv_data;
+ unsigned count[256] = { 0 };
+ uint32_t *palette = (uint32_t *)r->pict.data[1];
+ uint32_t color;
+ int x, y, i, j, match, d, best_d, av_uninit(best_j);
+ uint8_t *p = r->pict.data[0];
+
+ for (y = 0; y < r->h; y++) {
+ for (x = 0; x < r->w; x++)
+ count[*(p++)]++;
+ p += r->pict.linesize[0] - r->w;
+ }
+ for (i = 0; i < 256; i++) {
+ if (!count[i]) /* avoid useless search */
+ continue;
+ color = palette[i];
+ /* 0: transparent, 1-16: semi-transparent, 17-33 opaque */
+ match = color < 0x33000000 ? 0 : color < 0xCC000000 ? 1 : 17;
+ if (match) {
+ best_d = INT_MAX;
+ for (j = 0; j < 16; j++) {
+ d = color_distance(0xFF000000 | color,
+ 0xFF000000 | dvdc->global_palette[j]);
+ if (d < best_d) {
+ best_d = d;
+ best_j = j;
+ }
+ }
+ match += best_j;
+ }
+ hits[match] += count[i];
+ }
+}
+
+static void select_palette(AVCodecContext *avctx, int out_palette[4],
+ int out_alpha[4], unsigned hits[33])
+{
+ DVDSubtitleContext *dvdc = avctx->priv_data;
+ int i, j, bright, mult;
+ uint32_t color;
+ int selected[4] = { 0 };
+ uint32_t pseudopal[33] = { 0 };
+ uint32_t refcolor[3] = { 0x00000000, 0xFFFFFFFF, 0xFF000000 };
+
+ /* Bonus for transparent: if the rectangle fits tightly the text, the
+ background color can be quite rare, but it would be ugly without it */
+ hits[0] *= 16;
+ /* Bonus for bright colors */
+ for (i = 0; i < 16; i++) {
+ if (!(hits[1 + i] + hits[17 + i]))
+ continue; /* skip unused colors to gain time */
+ color = dvdc->global_palette[i];
+ bright = 0;
+ for (j = 0; j < 3; j++, color >>= 8)
+ bright += (color & 0xFF) < 0x40 || (color & 0xFF) >= 0xC0;
+ mult = 2 + FFMIN(bright, 2);
+ hits[ 1 + i] *= mult;
+ hits[17 + i] *= mult;
+ }
+
+ /* Select four most frequent colors */
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 33; j++)
+ if (hits[j] > hits[selected[i]])
+ selected[i] = j;
+ hits[selected[i]] = 0;
+ }
+
+ /* Order the colors like in most DVDs:
+ 0: background, 1: foreground, 2: outline */
+ for (i = 0; i < 16; i++) {
+ pseudopal[ 1 + i] = 0x80000000 | dvdc->global_palette[i];
+ pseudopal[17 + i] = 0xFF000000 | dvdc->global_palette[i];
+ }
+ for (i = 0; i < 3; i++) {
+ int best_d = color_distance(refcolor[i], pseudopal[selected[i]]);
+ for (j = i + 1; j < 4; j++) {
+ int d = color_distance(refcolor[i], pseudopal[selected[j]]);
+ if (d < best_d) {
+ FFSWAP(int, selected[i], selected[j]);
+ best_d = d;
+ }
+ }
+ }
+
+ /* Output */
+ for (i = 0; i < 4; i++) {
+ out_palette[i] = selected[i] ? (selected[i] - 1) & 0xF : 0;
+ out_alpha [i] = !selected[i] ? 0 : selected[i] < 17 ? 0x80 : 0xFF;
+ }
+}
+
+static void build_color_map(AVCodecContext *avctx, int cmap[],
+ const uint32_t palette[],
+ const int out_palette[], unsigned int const out_alpha[])
+{
+ DVDSubtitleContext *dvdc = avctx->priv_data;
+ int i, j, d, best_d;
+ uint32_t pseudopal[4];
+
+ for (i = 0; i < 4; i++)
+ pseudopal[i] = (out_alpha[i] << 24) |
+ dvdc->global_palette[out_palette[i]];
+ for (i = 0; i < 256; i++) {
+ best_d = INT_MAX;
+ for (j = 0; j < 4; j++) {
+ d = color_distance(pseudopal[j], palette[i]);
+ if (d < best_d) {
+ cmap[i] = j;
+ best_d = d;
+ }
+ }
+ }
+}
+
+static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[])
+{
+ int x, y;
+ uint8_t *p, *q;
+
+ p = src->pict.data[0];
+ q = dst->pict.data[0] + (src->x - dst->x) +
+ (src->y - dst->y) * dst->pict.linesize[0];
+ for (y = 0; y < src->h; y++) {
+ for (x = 0; x < src->w; x++)
+ *(q++) = cmap[*(p++)];
+ p += src->pict.linesize[0] - src->w;
+ q += dst->pict.linesize[0] - src->w;
+ }
+}
+
+static int encode_dvd_subtitles(AVCodecContext *avctx,
+ uint8_t *outbuf, int outbuf_size,
const AVSubtitle *h)
{
+ DVDSubtitleContext *dvdc = avctx->priv_data;
uint8_t *q, *qq;
- int object_id;
- int offset1[20], offset2[20];
- int i, imax, color, alpha, rects = h->num_rects;
- unsigned long hmax;
- unsigned long hist[256];
- int cmap[256];
+ int offset1, offset2;
+ int i, rects = h->num_rects, ret;
+ unsigned global_palette_hits[33] = { 0 };
+ int cmap[256];
+ int out_palette[4];
+ int out_alpha[4];
+ AVSubtitleRect vrect;
+ uint8_t *vrect_data = NULL;
+ int x2, y2;
+ int forced = 0;
if (rects == 0 || !h->rects)
- return -1;
- if (rects > 20)
- rects = 20;
-
- // analyze bitmaps, compress to 4 colors
- for (i=0; i<256; ++i) {
- hist[i] = 0;
- cmap[i] = 0;
- }
- for (object_id = 0; object_id < rects; object_id++)
- for (i=0; i<h->rects[object_id]->w*h->rects[object_id]->h; ++i) {
- color = h->rects[object_id]->pict.data[0][i];
- // only count non-transparent pixels
- alpha = ((uint32_t*)h->rects[object_id]->pict.data[1])[color] >> 24;
- hist[color] += alpha;
+ return AVERROR(EINVAL);
+ for (i = 0; i < rects; i++)
+ if (h->rects[i]->type != SUBTITLE_BITMAP) {
+ av_log(avctx, AV_LOG_ERROR, "Bitmap subtitle required\n");
+ return AVERROR(EINVAL);
}
- for (color=3;; --color) {
- hmax = 0;
- imax = 0;
- for (i=0; i<256; ++i)
- if (hist[i] > hmax) {
- imax = i;
- hmax = hist[i];
- }
- if (hmax == 0)
+ /* Mark this subtitle forced if any of the rectangles is forced. */
+ for (i = 0; i < rects; i++)
+ if ((h->rects[i]->flags & AV_SUBTITLE_FLAG_FORCED) != 0) {
+ forced = 1;
break;
- if (color == 0)
- color = 3;
- av_log(NULL, AV_LOG_DEBUG, "dvd_subtitle hist[%d]=%ld -> col %d\n",
- imax, hist[imax], color);
- cmap[imax] = color;
- hist[imax] = 0;
+ }
+ vrect = *h->rects[0];
+
+ if (rects > 1) {
+ /* DVD subtitles can have only one rectangle: build a virtual
+ rectangle containing all actual rectangles.
+ The data of the rectangles will be copied later, when the palette
+ is decided, because the rectangles may have different palettes. */
+ int xmin = h->rects[0]->x, xmax = xmin + h->rects[0]->w;
+ int ymin = h->rects[0]->y, ymax = ymin + h->rects[0]->h;
+ for (i = 1; i < rects; i++) {
+ xmin = FFMIN(xmin, h->rects[i]->x);
+ ymin = FFMIN(ymin, h->rects[i]->y);
+ xmax = FFMAX(xmax, h->rects[i]->x + h->rects[i]->w);
+ ymax = FFMAX(ymax, h->rects[i]->y + h->rects[i]->h);
+ }
+ vrect.x = xmin;
+ vrect.y = ymin;
+ vrect.w = xmax - xmin;
+ vrect.h = ymax - ymin;
+ if ((ret = av_image_check_size(vrect.w, vrect.h, 0, avctx)) < 0)
+ return ret;
+
+ /* Count pixels outside the virtual rectangle as transparent */
+ global_palette_hits[0] = vrect.w * vrect.h;
+ for (i = 0; i < rects; i++)
+ global_palette_hits[0] -= h->rects[i]->w * h->rects[i]->h;
}
+ for (i = 0; i < rects; i++)
+ count_colors(avctx, global_palette_hits, h->rects[i]);
+ select_palette(avctx, out_palette, out_alpha, global_palette_hits);
+
+ if (rects > 1) {
+ if (!(vrect_data = av_calloc(vrect.w, vrect.h)))
+ return AVERROR(ENOMEM);
+ vrect.pict.data [0] = vrect_data;
+ vrect.pict.linesize[0] = vrect.w;
+ for (i = 0; i < rects; i++) {
+ build_color_map(avctx, cmap, (uint32_t *)h->rects[i]->pict.data[1],
+ out_palette, out_alpha);
+ copy_rectangle(&vrect, h->rects[i], cmap);
+ }
+ for (i = 0; i < 4; i++)
+ cmap[i] = i;
+ } else {
+ build_color_map(avctx, cmap, (uint32_t *)h->rects[0]->pict.data[1],
+ out_palette, out_alpha);
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "Selected palette:");
+ for (i = 0; i < 4; i++)
+ av_log(avctx, AV_LOG_DEBUG, " 0x%06x@@%02x (0x%x,0x%x)",
+ dvdc->global_palette[out_palette[i]], out_alpha[i],
+ out_palette[i], out_alpha[i] >> 4);
+ av_log(avctx, AV_LOG_DEBUG, "\n");
// encode data block
q = outbuf + 4;
- for (object_id = 0; object_id < rects; object_id++) {
- offset1[object_id] = q - outbuf;
- // worst case memory requirement: 1 nibble per pixel..
- if ((q - outbuf) + h->rects[object_id]->w*h->rects[object_id]->h/2
- + 17*rects + 21 > outbuf_size) {
- av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n");
- return -1;
- }
- dvd_encode_rle(&q, h->rects[object_id]->pict.data[0],
- h->rects[object_id]->w*2,
- h->rects[object_id]->w, h->rects[object_id]->h >> 1,
- cmap);
- offset2[object_id] = q - outbuf;
- dvd_encode_rle(&q, h->rects[object_id]->pict.data[0] + h->rects[object_id]->w,
- h->rects[object_id]->w*2,
- h->rects[object_id]->w, h->rects[object_id]->h >> 1,
- cmap);
+ offset1 = q - outbuf;
+ // worst case memory requirement: 1 nibble per pixel..
+ if ((q - outbuf) + vrect.w * vrect.h / 2 + 17 + 21 > outbuf_size) {
+ av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n");
+ ret = AVERROR_BUFFER_TOO_SMALL;
+ goto fail;
+ }
+ dvd_encode_rle(&q, vrect.pict.data[0], vrect.w * 2,
+ vrect.w, (vrect.h + 1) >> 1, cmap);
+ offset2 = q - outbuf;
+ dvd_encode_rle(&q, vrect.pict.data[0] + vrect.w, vrect.w * 2,
+ vrect.w, vrect.h >> 1, cmap);
+
+ if (dvdc->even_rows_fix && (vrect.h & 1)) {
+ // Work-around for some players that want the height to be even.
+ vrect.h++;
+ *q++ = 0x00; // 0x00 0x00 == empty row, i.e. fully transparent
+ *q++ = 0x00;
}
// set data packet size
@@ -160,35 +361,34 @@ static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,
// send start display command
bytestream_put_be16(&q, (h->start_display_time*90) >> 10);
- bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12*rects + 2);
+ bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12 + 2);
*q++ = 0x03; // palette - 4 nibbles
- *q++ = 0x03; *q++ = 0x7f;
+ *q++ = (out_palette[3] << 4) | out_palette[2];
+ *q++ = (out_palette[1] << 4) | out_palette[0];
*q++ = 0x04; // alpha - 4 nibbles
- *q++ = 0xf0; *q++ = 0x00;
- //*q++ = 0x0f; *q++ = 0xff;
+ *q++ = (out_alpha[3] & 0xF0) | (out_alpha[2] >> 4);
+ *q++ = (out_alpha[1] & 0xF0) | (out_alpha[0] >> 4);
- // XXX not sure if more than one rect can really be encoded..
// 12 bytes per rect
- for (object_id = 0; object_id < rects; object_id++) {
- int x2 = h->rects[object_id]->x + h->rects[object_id]->w - 1;
- int y2 = h->rects[object_id]->y + h->rects[object_id]->h - 1;
-
- *q++ = 0x05;
- // x1 x2 -> 6 nibbles
- *q++ = h->rects[object_id]->x >> 4;
- *q++ = (h->rects[object_id]->x << 4) | ((x2 >> 8) & 0xf);
- *q++ = x2;
- // y1 y2 -> 6 nibbles
- *q++ = h->rects[object_id]->y >> 4;
- *q++ = (h->rects[object_id]->y << 4) | ((y2 >> 8) & 0xf);
- *q++ = y2;
-
- *q++ = 0x06;
- // offset1, offset2
- bytestream_put_be16(&q, offset1[object_id]);
- bytestream_put_be16(&q, offset2[object_id]);
- }
- *q++ = 0x01; // start command
+ x2 = vrect.x + vrect.w - 1;
+ y2 = vrect.y + vrect.h - 1;
+
+ *q++ = 0x05;
+ // x1 x2 -> 6 nibbles
+ *q++ = vrect.x >> 4;
+ *q++ = (vrect.x << 4) | ((x2 >> 8) & 0xf);
+ *q++ = x2;
+ // y1 y2 -> 6 nibbles
+ *q++ = vrect.y >> 4;
+ *q++ = (vrect.y << 4) | ((y2 >> 8) & 0xf);
+ *q++ = y2;
+
+ *q++ = 0x06;
+ // offset1, offset2
+ bytestream_put_be16(&q, offset1);
+ bytestream_put_be16(&q, offset2);
+
+ *q++ = forced ? 0x00 : 0x01; // start command
*q++ = 0xff; // terminating command
// send stop display command last
@@ -200,8 +400,42 @@ static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,
qq = outbuf;
bytestream_put_be16(&qq, q - outbuf);
- av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%td\n", q - outbuf);
- return q - outbuf;
+ av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%"PTRDIFF_SPECIFIER"\n", q - outbuf);
+ ret = q - outbuf;
+
+fail:
+ av_free(vrect_data);
+ return ret;
+}
+
+static int dvdsub_init(AVCodecContext *avctx)
+{
+ DVDSubtitleContext *dvdc = avctx->priv_data;
+ static const uint32_t default_palette[16] = {
+ 0x000000, 0x0000FF, 0x00FF00, 0xFF0000,
+ 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF,
+ 0x808000, 0x8080FF, 0x800080, 0x80FF80,
+ 0x008080, 0xFF8080, 0x555555, 0xAAAAAA,
+ };
+ AVBPrint extradata;
+ int i, ret;
+
+ av_assert0(sizeof(dvdc->global_palette) == sizeof(default_palette));
+ memcpy(dvdc->global_palette, default_palette, sizeof(dvdc->global_palette));
+
+ av_bprint_init(&extradata, 0, 1);
+ if (avctx->width && avctx->height)
+ av_bprintf(&extradata, "size: %dx%d\n", avctx->width, avctx->height);
+ av_bprintf(&extradata, "palette:");
+ for (i = 0; i < 16; i++)
+ av_bprintf(&extradata, " %06"PRIx32"%c",
+ dvdc->global_palette[i] & 0xFFFFFF, i < 15 ? ',' : '\n');
+
+ ret = avpriv_bprint_to_extradata(avctx, &extradata);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int dvdsub_encode(AVCodecContext *avctx,
@@ -211,14 +445,31 @@ static int dvdsub_encode(AVCodecContext *avctx,
//DVDSubtitleContext *s = avctx->priv_data;
int ret;
- ret = encode_dvd_subtitles(buf, buf_size, sub);
+ ret = encode_dvd_subtitles(avctx, buf, buf_size, sub);
return ret;
}
+#define OFFSET(x) offsetof(DVDSubtitleContext, x)
+#define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ {"even_rows_fix", "Make number of rows even (workaround for some players)", OFFSET(even_rows_fix), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SE},
+ { NULL },
+};
+
+static const AVClass dvdsubenc_class = {
+ .class_name = "VOBSUB subtitle encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_dvdsub_encoder = {
.name = "dvdsub",
.long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_DVD_SUBTITLE,
+ .init = dvdsub_init,
.encode_sub = dvdsub_encode,
+ .priv_class = &dvdsubenc_class,
+ .priv_data_size = sizeof(DVDSubtitleContext),
};
diff --git a/libavcodec/dvenc.c b/libavcodec/dvenc.c
index 6d98d499e1..9ce72732f3 100644
--- a/libavcodec/dvenc.c
+++ b/libavcodec/dvenc.c
@@ -2,20 +2,20 @@
* DV encoder
* Copyright (c) 2003 Roman Shaposhnik
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,7 +47,7 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx)
PixblockDSPContext pdsp;
int ret;
- s->sys = av_dv_codec_profile(avctx->width, avctx->height, avctx->pix_fmt);
+ s->sys = av_dv_codec_profile2(avctx->width, avctx->height, avctx->pix_fmt, avctx->time_base);
if (!s->sys) {
av_log(avctx, AV_LOG_ERROR, "Found no DV profile for %ix%i %s video. "
"Valid DV profiles are:\n",
@@ -55,6 +55,10 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx)
ff_dv_print_profiles(avctx, AV_LOG_ERROR);
return AVERROR(EINVAL);
}
+ if (avctx->height > 576) {
+ av_log(avctx, AV_LOG_ERROR, "DVCPRO HD encoding is not supported.\n");
+ return AVERROR_PATCHWELCOME;
+ }
ret = ff_dv_init_dynamic_tables(s, s->sys);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error initializing work tables.\n");
@@ -67,6 +71,9 @@ static av_cold int dvvideo_encode_init(AVCodecContext *avctx)
dv_vlc_map_tableinit();
+ 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);
@@ -169,7 +176,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 = vlc & ((1 << size) - 1);
+ vlc = av_mod_uintp2(vlc, size);
}
if (pb + 1 >= pb_end) {
bi->partial_bit_count = size;
@@ -225,14 +232,14 @@ static const int dv_weight_88[64] = {
170627, 165371, 160727, 153560, 160727, 144651, 144651, 136258,
};
static const int dv_weight_248[64] = {
- 131072, 242189, 257107, 237536, 229376, 200636, 242189, 223754,
- 224969, 196781, 262144, 242189, 229376, 200636, 257107, 237536,
- 211916, 185364, 235923, 217965, 229376, 211916, 206433, 180568,
- 242189, 223754, 224969, 196781, 211916, 185364, 235923, 217965,
- 200704, 175557, 222935, 205965, 200636, 185364, 195068, 170627,
- 229376, 211916, 206433, 180568, 200704, 175557, 222935, 205965,
- 175557, 153560, 188995, 174609, 165371, 144651, 200636, 185364,
- 195068, 170627, 175557, 153560, 188995, 174609, 165371, 144651,
+ 131072, 262144, 257107, 257107, 242189, 242189, 242189, 242189,
+ 237536, 237536, 229376, 229376, 200636, 200636, 224973, 224973,
+ 223754, 223754, 235923, 235923, 229376, 229376, 217965, 217965,
+ 211916, 211916, 196781, 196781, 185364, 185364, 206433, 206433,
+ 211916, 211916, 222935, 222935, 200636, 200636, 205964, 205964,
+ 200704, 200704, 180568, 180568, 175557, 175557, 195068, 195068,
+ 185364, 185364, 188995, 188995, 174606, 174606, 175557, 175557,
+ 170627, 170627, 153560, 153560, 165371, 165371, 144651, 144651,
};
static av_always_inline int dv_init_enc_block(EncBlockInfo *bi, uint8_t *data,
@@ -247,7 +254,7 @@ static av_always_inline int dv_init_enc_block(EncBlockInfo *bi, uint8_t *data,
* method suggested in SMPTE 314M Table 22, and an improved
* method. The SMPTE method is very conservative; it assigns class
* 3 (i.e. severe quantization) to any block where the largest AC
- * component is greater than 36. Libav's DV encoder tracks AC bit
+ * component is greater than 36. FFmpeg's DV encoder tracks AC bit
* consumption precisely, so there is no need to bias most blocks
* towards strongly lossy compression. Instead, we assign class 2
* to most blocks, and use class 3 only when strictly necessary
@@ -255,13 +262,13 @@ static av_always_inline int dv_init_enc_block(EncBlockInfo *bi, uint8_t *data,
#if 0 /* SMPTE spec method */
static const int classes[] = { 12, 24, 36, 0xffff };
-#else /* improved Libav method */
+#else /* improved FFmpeg method */
static const int classes[] = { -1, -1, 255, 0xffff };
#endif
int max = classes[0];
int prev = 0;
- assert((((int) blk) & 15) == 0);
+ av_assert2((((int) blk) & 15) == 0);
bi->area_q[0] =
bi->area_q[1] =
@@ -294,7 +301,7 @@ static av_always_inline int dv_init_enc_block(EncBlockInfo *bi, uint8_t *data,
if (level + 15 > 30U) {
bi->sign[i] = (level >> 31) & 1;
- /* Weight it and and shift down into range, adding for rounding.
+ /* Weight it and shift down into range, adding for rounding.
* The extra division by a factor of 2^4 reverses the 8x
* expansion of the DCT AND the 2x doubling of the weights. */
level = (FFABS(level) * weight[i] + (1 << (dv_weight_bits + 3))) >>
@@ -363,7 +370,7 @@ static inline void dv_guess_qnos(EncBlockInfo *blks, int *qnos)
b->bit_size[a] = 1; // 4 areas 4 bits for EOB :)
b->area_q[a]++;
prev = b->prev[a];
- assert(b->next[prev] >= mb_area_start[a + 1] || b->mb[prev]);
+ av_assert2(b->next[prev] >= mb_area_start[a + 1] || b->mb[prev]);
for (k = b->next[prev]; k < mb_area_start[a + 1]; k = b->next[k]) {
b->mb[k] >>= 1;
if (b->mb[k]) {
@@ -373,11 +380,11 @@ static inline void dv_guess_qnos(EncBlockInfo *blks, int *qnos)
if (b->next[k] >= mb_area_start[a + 1] && b->next[k] < 64) {
for (a2 = a + 1; b->next[k] >= mb_area_start[a2 + 1]; a2++)
b->prev[a2] = prev;
- assert(a2 < 4);
- assert(b->mb[b->next[k]]);
+ av_assert2(a2 < 4);
+ av_assert2(b->mb[b->next[k]]);
b->bit_size[a2] += dv_rl2vlc_size(b->next[k] - prev - 1, b->mb[b->next[k]]) -
dv_rl2vlc_size(b->next[k] - k - 1, b->mb[b->next[k]]);
- assert(b->prev[a2] == k && (a2 + 1 >= 4 || b->prev[a2 + 1] != k));
+ av_assert2(b->prev[a2] == k && (a2 + 1 >= 4 || b->prev[a2 + 1] != k));
b->prev[a2] = prev;
}
b->next[prev] = b->next[k];
@@ -571,6 +578,7 @@ static inline int dv_write_pack(enum dv_pack_type pack_id, DVVideoContext *c,
* compression scheme (if any).
*/
int apt = (c->sys->pix_fmt == AV_PIX_FMT_YUV420P ? 0 : 1);
+ int fs = c->frame->top_field_first ? 0x00 : 0x40;
uint8_t aspect = 0;
if ((int) (av_q2d(c->avctx->sample_aspect_ratio) *
@@ -610,7 +618,7 @@ static inline int dv_write_pack(enum dv_pack_type pack_id, DVVideoContext *c,
buf[2] = 0xc8 | /* reserved -- always b11001xxx */
aspect;
buf[3] = (1 << 7) | /* frame/field flag 1 -- frame, 0 -- field */
- (1 << 6) | /* first/second field flag 0 -- field 2, 1 -- field 1 */
+ fs | /* first/second field flag 0 -- field 2, 1 -- field 1 */
(1 << 5) | /* frame change flag 0 -- same picture as before, 1 -- different */
(1 << 4) | /* 1 - interlaced, 0 - noninterlaced */
0xc; /* reserved -- always b1100 */
@@ -713,10 +721,8 @@ static int dvvideo_encode_frame(AVCodecContext *c, AVPacket *pkt,
DVVideoContext *s = c->priv_data;
int ret;
- if ((ret = ff_alloc_packet(pkt, s->sys->frame_size)) < 0) {
- av_log(c, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(c, pkt, s->sys->frame_size)) < 0)
return ret;
- }
c->pix_fmt = s->sys->pix_fmt;
s->frame = frame;
@@ -752,7 +758,7 @@ AVCodec ff_dvvideo_encoder = {
.init = dvvideo_encode_init,
.encode2 = dvvideo_encode_frame,
.close = dvvideo_encode_close,
- .capabilities = CODEC_CAP_SLICE_THREADS,
+ .capabilities = CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV422P,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
diff --git a/libavcodec/dxa.c b/libavcodec/dxa.c
index 989fcb965b..c8e3f71399 100644
--- a/libavcodec/dxa.c
+++ b/libavcodec/dxa.c
@@ -2,20 +2,20 @@
* Feeble Files/ScummVM DXA decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
+#include "bytestream.h"
#include "avcodec.h"
#include "internal.h"
@@ -41,6 +42,7 @@ typedef struct DxaDecContext {
AVFrame *prev;
int dsize;
+#define DECOMP_BUF_PADDING 16
uint8_t *decomp_buf;
uint32_t pal[256];
} DxaDecContext;
@@ -49,13 +51,17 @@ static const int shift1[6] = { 0, 8, 8, 8, 4, 4 };
static const int shift2[6] = { 0, 0, 8, 4, 0, 4 };
static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
- int stride, uint8_t *src, uint8_t *ref)
+ int stride, uint8_t *src, int srcsize, uint8_t *ref)
{
uint8_t *code, *data, *mv, *msk, *tmp, *tmp2;
+ uint8_t *src_end = src + srcsize;
int i, j, k;
int type, x, y, d, d2;
uint32_t mask;
+ if (12ULL + ((avctx->width * avctx->height) >> 4) + AV_RB32(src + 0) + AV_RB32(src + 4) > srcsize)
+ return AVERROR_INVALIDDATA;
+
code = src + 12;
data = code + ((avctx->width * avctx->height) >> 4);
mv = data + AV_RB32(src + 0);
@@ -63,6 +69,8 @@ static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
for(j = 0; j < avctx->height; j += 4){
for(i = 0; i < avctx->width; i += 4){
+ if (data > src_end || mv > src_end || msk > src_end)
+ return AVERROR_INVALIDDATA;
tmp = dst + i;
tmp2 = ref + i;
type = *code++;
@@ -70,6 +78,11 @@ static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
case 4: // motion compensation
x = (*mv) >> 4; if(x & 8) x = 8 - x;
y = (*mv++) & 0xF; if(y & 8) y = 8 - y;
+ if (i < -x || avctx->width - i - 4 < x ||
+ j < -y || avctx->height - j - 4 < y) {
+ av_log(avctx, AV_LOG_ERROR, "MV %d %d out of bounds\n", x,y);
+ return AVERROR_INVALIDDATA;
+ }
tmp2 += x + y*stride;
case 0: // skip
case 5: // skip in method 12
@@ -127,6 +140,11 @@ static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
case 0x80: // motion compensation
x = (*mv) >> 4; if(x & 8) x = 8 - x;
y = (*mv++) & 0xF; if(y & 8) y = 8 - y;
+ if (i + 2*(k & 1) < -x || avctx->width - i - 2*(k & 1) - 2 < x ||
+ j + (k & 2) < -y || avctx->height - j - (k & 2) - 2 < y) {
+ av_log(avctx, AV_LOG_ERROR, "MV %d %d out of bounds\n", x,y);
+ return AVERROR_INVALIDDATA;
+ }
tmp2 += x + y*stride;
case 0x00: // skip
tmp[d + 0 ] = tmp2[0];
@@ -192,35 +210,27 @@ static int decode_13(AVCodecContext *avctx, DxaDecContext *c, uint8_t* dst,
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
{
AVFrame *frame = data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
DxaDecContext * const c = avctx->priv_data;
uint8_t *outptr, *srcptr, *tmpptr;
unsigned long dsize;
int i, j, compr, ret;
int stride;
- int orig_buf_size = buf_size;
int pc = 0;
+ GetByteContext gb;
- /* make the palette available on the way out */
- if(buf[0]=='C' && buf[1]=='M' && buf[2]=='A' && buf[3]=='P'){
- int r, g, b;
+ bytestream2_init(&gb, avpkt->data, avpkt->size);
- buf += 4;
+ /* make the palette available on the way out */
+ if (bytestream2_peek_le32(&gb) == MKTAG('C','M','A','P')) {
+ bytestream2_skip(&gb, 4);
for(i = 0; i < 256; i++){
- r = *buf++;
- g = *buf++;
- b = *buf++;
- c->pal[i] = (r << 16) | (g << 8) | b;
+ c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&gb);
}
pc = 1;
- buf_size -= 768+4;
}
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
frame->palette_has_changed = pc;
@@ -229,16 +239,25 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
tmpptr = c->prev->data[0];
stride = frame->linesize[0];
- if(buf[0]=='N' && buf[1]=='U' && buf[2]=='L' && buf[3]=='L')
+ if (bytestream2_get_le32(&gb) == MKTAG('N','U','L','L'))
compr = -1;
else
- compr = buf[4];
+ compr = bytestream2_get_byte(&gb);
dsize = c->dsize;
- if((compr != 4 && compr != -1) && uncompress(c->decomp_buf, &dsize, buf + 9, buf_size - 9) != Z_OK){
- av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n");
- return AVERROR_UNKNOWN;
+ if (compr != 4 && compr != -1) {
+ bytestream2_skip(&gb, 4);
+ if (uncompress(c->decomp_buf, &dsize, avpkt->data + bytestream2_tell(&gb),
+ bytestream2_get_bytes_left(&gb)) != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Uncompress failed!\n");
+ return AVERROR_UNKNOWN;
+ }
+ memset(c->decomp_buf + dsize, 0, DECOMP_BUF_PADDING);
}
+
+ if (avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(avctx, AV_LOG_DEBUG, "compr:%2d, dsize:%d\n", compr, (int)dsize);
+
switch(compr){
case -1:
frame->key_frame = 0;
@@ -265,14 +284,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
case 5:
if (!tmpptr) {
av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
- return AVERROR_INVALIDDATA;
+ if (!(avctx->flags2 & CODEC_FLAG2_SHOW_ALL))
+ return AVERROR_INVALIDDATA;
}
frame->key_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_P;
for (j = 0; j < avctx->height; j++) {
- for (i = 0; i < avctx->width; i++)
- outptr[i] = srcptr[i] ^ tmpptr[i];
- tmpptr += stride;
+ if(tmpptr){
+ for(i = 0; i < avctx->width; i++)
+ outptr[i] = srcptr[i] ^ tmpptr[i];
+ tmpptr += stride;
+ }else
+ memcpy(outptr, srcptr, avctx->width);
outptr += stride;
srcptr += avctx->width;
}
@@ -281,10 +304,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
case 13:
frame->key_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_P;
- decode_13(avctx, c, frame->data[0], frame->linesize[0], srcptr, c->prev->data[0]);
+ if (!c->prev->data[0]) {
+ av_log(avctx, AV_LOG_ERROR, "Missing reference frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+ decode_13(avctx, c, frame->data[0], frame->linesize[0], srcptr, dsize, c->prev->data[0]);
break;
default:
- av_log(avctx, AV_LOG_ERROR, "Unknown/unsupported compression type %d\n", buf[4]);
+ av_log(avctx, AV_LOG_ERROR, "Unknown/unsupported compression type %d\n", compr);
return AVERROR_INVALIDDATA;
}
@@ -295,13 +322,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
*got_frame = 1;
/* always report that the buffer was completely consumed */
- return orig_buf_size;
+ return avpkt->size;
}
static av_cold int decode_init(AVCodecContext *avctx)
{
DxaDecContext * const c = avctx->priv_data;
+ if (avctx->width%4 || avctx->height%4) {
+ avpriv_request_sample(avctx, "dimensions are not a multiple of 4");
+ return AVERROR_INVALIDDATA;
+ }
+
c->prev = av_frame_alloc();
if (!c->prev)
return AVERROR(ENOMEM);
@@ -309,7 +341,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_PAL8;
c->dsize = avctx->width * avctx->height * 2;
- if (!(c->decomp_buf = av_malloc(c->dsize))) {
+ c->decomp_buf = av_malloc(c->dsize + DECOMP_BUF_PADDING);
+ if (!c->decomp_buf) {
+ av_frame_free(&c->prev);
av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n");
return AVERROR(ENOMEM);
}
diff --git a/libavcodec/dxtory.c b/libavcodec/dxtory.c
index 662cd9f89d..22e7b2f4eb 100644
--- a/libavcodec/dxtory.c
+++ b/libavcodec/dxtory.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,7 +39,7 @@ static int dxtory_decode_v1_rgb(AVCodecContext *avctx, AVFrame *pic,
uint8_t *dst;
int ret;
- if (src_size < avctx->width * avctx->height * bpp) {
+ if (src_size < avctx->width * avctx->height * (int64_t)bpp) {
av_log(avctx, AV_LOG_ERROR, "packet too small\n");
return AVERROR_INVALIDDATA;
}
@@ -65,7 +65,7 @@ static int dxtory_decode_v1_410(AVCodecContext *avctx, AVFrame *pic,
uint8_t *Y1, *Y2, *Y3, *Y4, *U, *V;
int ret;
- if (src_size < avctx->width * avctx->height * 18 / 16) {
+ if (src_size < avctx->width * avctx->height * 9LL / 8) {
av_log(avctx, AV_LOG_ERROR, "packet too small\n");
return AVERROR_INVALIDDATA;
}
@@ -82,10 +82,10 @@ static int dxtory_decode_v1_410(AVCodecContext *avctx, AVFrame *pic,
V = pic->data[2];
for (h = 0; h < avctx->height; h += 4) {
for (w = 0; w < avctx->width; w += 4) {
- AV_COPY32(Y1 + w, src);
- AV_COPY32(Y2 + w, src + 4);
- AV_COPY32(Y3 + w, src + 8);
- AV_COPY32(Y4 + w, src + 12);
+ AV_COPY32U(Y1 + w, src);
+ AV_COPY32U(Y2 + w, src + 4);
+ AV_COPY32U(Y3 + w, src + 8);
+ AV_COPY32U(Y4 + w, src + 12);
U[w >> 2] = src[16] + 0x80;
V[w >> 2] = src[17] + 0x80;
src += 18;
@@ -108,7 +108,7 @@ static int dxtory_decode_v1_420(AVCodecContext *avctx, AVFrame *pic,
uint8_t *Y1, *Y2, *U, *V;
int ret;
- if (src_size < avctx->width * avctx->height * 3 / 2) {
+ if (src_size < avctx->width * avctx->height * 3LL / 2) {
av_log(avctx, AV_LOG_ERROR, "packet too small\n");
return AVERROR_INVALIDDATA;
}
@@ -145,7 +145,7 @@ static int dxtory_decode_v1_444(AVCodecContext *avctx, AVFrame *pic,
uint8_t *Y, *U, *V;
int ret;
- if (src_size < avctx->width * avctx->height * 3) {
+ if (src_size < avctx->width * avctx->height * 3LL) {
av_log(avctx, AV_LOG_ERROR, "packet too small\n");
return AVERROR_INVALIDDATA;
}
@@ -171,9 +171,9 @@ static int dxtory_decode_v1_444(AVCodecContext *avctx, AVFrame *pic,
return 0;
}
-const uint8_t def_lru[8] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xFF };
-const uint8_t def_lru_555[8] = { 0x00, 0x08, 0x10, 0x18, 0x1F };
-const uint8_t def_lru_565[8] = { 0x00, 0x08, 0x10, 0x20, 0x30, 0x3F };
+static const uint8_t def_lru[8] = { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xFF };
+static const uint8_t def_lru_555[8] = { 0x00, 0x08, 0x10, 0x18, 0x1F };
+static const uint8_t def_lru_565[8] = { 0x00, 0x08, 0x10, 0x20, 0x30, 0x3F };
static inline uint8_t decode_sym(GetBitContext *gb, uint8_t lru[8])
{
@@ -285,7 +285,8 @@ static int dxtory_decode_v2_565(AVCodecContext *avctx, AVFrame *pic,
"Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n",
AV_RL32(src + off), slice_size - 16);
}
- init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8);
+ if ((ret = init_get_bits8(&gb2, src + off + 16, slice_size - 16)) < 0)
+ return ret;
dx2_decode_slice_565(&gb2, avctx->width, slice_height, dst,
pic->linesize[0], is_565);
@@ -367,7 +368,8 @@ static int dxtory_decode_v2_rgb(AVCodecContext *avctx, AVFrame *pic,
"Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n",
AV_RL32(src + off), slice_size - 16);
}
- init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8);
+ if ((ret = init_get_bits8(&gb2, src + off + 16, slice_size - 16)) < 0)
+ return ret;
dx2_decode_slice_rgb(&gb2, avctx->width, slice_height, dst,
pic->linesize[0]);
@@ -410,7 +412,7 @@ static int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic,
{
GetByteContext gb;
GetBitContext gb2;
- int nslices, slice, slice_height, ref_slice_height;
+ int nslices, slice, slice_height;
int cur_y, next_y;
uint32_t off, slice_size;
uint8_t *Y, *U, *V;
@@ -424,13 +426,12 @@ static int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic,
return AVERROR_INVALIDDATA;
}
- if (!nslices || avctx->height % nslices) {
+ if (!nslices) {
avpriv_request_sample(avctx, "%d slices for %dx%d", nslices,
avctx->width, avctx->height);
return AVERROR_PATCHWELCOME;
}
- ref_slice_height = avctx->height / nslices;
if ((avctx->width & 3) || (avctx->height & 3)) {
avpriv_request_sample(avctx, "Frame dimensions %dx%d",
avctx->width, avctx->height);
@@ -445,9 +446,9 @@ static int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic,
V = pic->data[2];
cur_y = 0;
- next_y = ref_slice_height;
for (slice = 0; slice < nslices; slice++) {
slice_size = bytestream2_get_le32(&gb);
+ next_y = ((slice + 1) * avctx->height) / nslices;
slice_height = (next_y & ~3) - (cur_y & ~3);
if (slice_size > src_size - off) {
av_log(avctx, AV_LOG_ERROR,
@@ -465,7 +466,8 @@ static int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic,
"Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n",
AV_RL32(src + off), slice_size - 16);
}
- init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8);
+ if ((ret = init_get_bits8(&gb2, src + off + 16, slice_size - 16)) < 0)
+ return ret;
dx2_decode_slice_410(&gb2, avctx->width, slice_height, Y, U, V,
pic->linesize[0], pic->linesize[1],
pic->linesize[2]);
@@ -475,7 +477,6 @@ static int dxtory_decode_v2_410(AVCodecContext *avctx, AVFrame *pic,
V += pic->linesize[2] * (slice_height >> 2);
off += slice_size;
cur_y = next_y;
- next_y += ref_slice_height;
}
return 0;
@@ -514,7 +515,7 @@ static int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic,
{
GetByteContext gb;
GetBitContext gb2;
- int nslices, slice, slice_height, ref_slice_height;
+ int nslices, slice, slice_height;
int cur_y, next_y;
uint32_t off, slice_size;
uint8_t *Y, *U, *V;
@@ -528,13 +529,12 @@ static int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic,
return AVERROR_INVALIDDATA;
}
- if (!nslices || avctx->height % nslices) {
+ if (!nslices) {
avpriv_request_sample(avctx, "%d slices for %dx%d", nslices,
avctx->width, avctx->height);
return AVERROR_PATCHWELCOME;
}
- ref_slice_height = avctx->height / nslices;
if ((avctx->width & 1) || (avctx->height & 1)) {
avpriv_request_sample(avctx, "Frame dimensions %dx%d",
avctx->width, avctx->height);
@@ -549,9 +549,9 @@ static int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic,
V = pic->data[2];
cur_y = 0;
- next_y = ref_slice_height;
for (slice = 0; slice < nslices; slice++) {
slice_size = bytestream2_get_le32(&gb);
+ next_y = ((slice + 1) * avctx->height) / nslices;
slice_height = (next_y & ~1) - (cur_y & ~1);
if (slice_size > src_size - off) {
av_log(avctx, AV_LOG_ERROR,
@@ -569,7 +569,8 @@ static int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic,
"Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n",
AV_RL32(src + off), slice_size - 16);
}
- init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8);
+ if ((ret = init_get_bits8(&gb2, src + off + 16, slice_size - 16)) < 0)
+ return ret;
dx2_decode_slice_420(&gb2, avctx->width, slice_height, Y, U, V,
pic->linesize[0], pic->linesize[1],
pic->linesize[2]);
@@ -579,7 +580,6 @@ static int dxtory_decode_v2_420(AVCodecContext *avctx, AVFrame *pic,
V += pic->linesize[2] * (slice_height >> 1);
off += slice_size;
cur_y = next_y;
- next_y += ref_slice_height;
}
return 0;
@@ -662,7 +662,8 @@ static int dxtory_decode_v2_444(AVCodecContext *avctx, AVFrame *pic,
"Slice sizes mismatch: got %"PRIu32" instead of %"PRIu32"\n",
AV_RL32(src + off), slice_size - 16);
}
- init_get_bits(&gb2, src + off + 16, (slice_size - 16) * 8);
+ if ((ret = init_get_bits8(&gb2, src + off + 16, slice_size - 16)) < 0)
+ return ret;
dx2_decode_slice_444(&gb2, avctx->width, slice_height, Y, U, V,
pic->linesize[0], pic->linesize[1],
pic->linesize[2]);
diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
index 76a9d54a27..477607957c 100644
--- a/libavcodec/dxva2.c
+++ b/libavcodec/dxva2.c
@@ -3,20 +3,20 @@
*
* copyright (c) 2010 Laurent Aimar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dxva2.h b/libavcodec/dxva2.h
index d9017c6b8d..be246d7198 100644
--- a/libavcodec/dxva2.h
+++ b/libavcodec/dxva2.h
@@ -3,20 +3,20 @@
*
* copyright (c) 2009 Laurent Aimar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,7 @@
/**
* This structure is used to provides the necessary configurations and data
- * to the DXVA2 Libav HWAccel implementation.
+ * to the DXVA2 FFmpeg HWAccel implementation.
*
* The application must make it available as AVCodecContext.hwaccel_context.
*/
@@ -81,7 +81,7 @@ struct dxva_context {
uint64_t workaround;
/**
- * Private to the Libav AVHWAccel implementation
+ * Private to the FFmpeg AVHWAccel implementation
*/
unsigned report_id;
};
diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c
index a4a88ce61d..fe252bbae8 100644
--- a/libavcodec/dxva2_h264.c
+++ b/libavcodec/dxva2_h264.c
@@ -3,20 +3,20 @@
*
* copyright (c) 2009 Laurent Aimar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -96,7 +96,7 @@ static void fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *
((h->sps.mb_aff &&
(h->picture_structure == PICT_FRAME)) << 1) |
(h->sps.residual_color_transform_flag << 2) |
- /* sp_for_switch_flag (not implemented by Libav) */
+ /* sp_for_switch_flag (not implemented by FFmpeg) */
(0 << 3) |
(h->sps.chroma_format_idc << 4) |
((h->nal_ref_idc != 0) << 6) |
@@ -152,8 +152,8 @@ static void fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *
pp->deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present;
pp->redundant_pic_cnt_present_flag= h->pps.redundant_pic_cnt_present;
pp->Reserved8BitsB = 0;
- pp->slice_group_change_rate_minus1= 0; /* XXX not implemented by Libav */
- //pp->SliceGroupMap[810]; /* XXX not implemented by Libav */
+ pp->slice_group_change_rate_minus1= 0; /* XXX not implemented by FFmpeg */
+ //pp->SliceGroupMap[810]; /* XXX not implemented by FFmpeg */
}
static void fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, const H264Context *h, DXVA_Qmatrix_H264 *qm)
@@ -275,7 +275,7 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice,
}
}
}
- slice->slice_qs_delta = 0; /* XXX not implemented by Libav */
+ slice->slice_qs_delta = 0; /* XXX not implemented by FFmpeg */
slice->slice_qp_delta = sl->qscale - h->pps.init_qp;
slice->redundant_pic_cnt = sl->redundant_pic_count;
if (sl->slice_type == AV_PICTURE_TYPE_B)
diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c
index 9d130d93a7..dae990dd8f 100644
--- a/libavcodec/dxva2_hevc.c
+++ b/libavcodec/dxva2_hevc.c
@@ -3,20 +3,20 @@
*
* copyright (c) 2014 - 2015 Hendrik Leppkes
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h
index 23be2c36f3..5a30bc6aef 100644
--- a/libavcodec/dxva2_internal.h
+++ b/libavcodec/dxva2_internal.h
@@ -3,20 +3,20 @@
*
* copyright (c) 2010 Laurent Aimar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c
index 99a0787be6..89c43e7f9c 100644
--- a/libavcodec/dxva2_mpeg2.c
+++ b/libavcodec/dxva2_mpeg2.c
@@ -3,20 +3,20 @@
*
* copyright (c) 2010 Laurent Aimar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -111,10 +111,10 @@ static void fill_quantization_matrices(AVCodecContext *avctx,
qm->bNewQmatrix[i] = 1;
for (i = 0; i < 64; i++) {
int n = s->idsp.idct_permutation[ff_zigzag_direct[i]];
- qm->Qmatrix[0][i] = s->intra_matrix[n];;
- qm->Qmatrix[1][i] = s->inter_matrix[n];;
- qm->Qmatrix[2][i] = s->chroma_intra_matrix[n];;
- qm->Qmatrix[3][i] = s->chroma_inter_matrix[n];;
+ qm->Qmatrix[0][i] = s->intra_matrix[n];
+ qm->Qmatrix[1][i] = s->inter_matrix[n];
+ qm->Qmatrix[2][i] = s->chroma_intra_matrix[n];
+ qm->Qmatrix[3][i] = s->chroma_inter_matrix[n];
}
}
@@ -141,8 +141,7 @@ static void fill_slice(AVCodecContext *avctx,
init_get_bits(&gb, &buffer[4], 8 * (size - 4));
slice->wQuantizerScaleCode = get_bits(&gb, 5);
- while (get_bits1(&gb))
- skip_bits(&gb, 8);
+ skip_1stop_8data_bits(&gb);
slice->wMBbitOffset = 4 * 8 + get_bits_count(&gb);
}
diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c
index 73f9fb4109..1eb425383e 100644
--- a/libavcodec/dxva2_vc1.c
+++ b/libavcodec/dxva2_vc1.c
@@ -3,20 +3,20 @@
*
* copyright (c) 2010 Laurent Aimar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,6 +39,15 @@ static void fill_picture_parameters(AVCodecContext *avctx,
{
const MpegEncContext *s = &v->s;
const Picture *current_picture = s->current_picture_ptr;
+ int intcomp = 0;
+
+ // determine if intensity compensation is needed
+ if (s->pict_type == AV_PICTURE_TYPE_P) {
+ if ((v->fcm == ILACE_FRAME && v->intcomp) || (v->fcm != ILACE_FRAME && v->mv_mode == MV_PMODE_INTENSITY_COMP)) {
+ if (v->lumscale != 32 || v->lumshift != 0 || (s->picture_structure != PICT_FRAME && (v->lumscale2 != 32 || v->lumshift2 != 0)))
+ intcomp = 1;
+ }
+ }
memset(pp, 0, sizeof(*pp));
pp->wDecodedPictureIndex =
@@ -69,13 +78,13 @@ static void fill_picture_parameters(AVCodecContext *avctx,
pp->bPicStructure |= 0x01;
if (s->picture_structure & PICT_BOTTOM_FIELD)
pp->bPicStructure |= 0x02;
- pp->bSecondField = v->interlace && v->fcm != ILACE_FIELD && !s->first_field;
+ pp->bSecondField = v->interlace && v->fcm == ILACE_FIELD && v->second_field;
pp->bPicIntra = s->pict_type == AV_PICTURE_TYPE_I || v->bi_type;
pp->bPicBackwardPrediction = s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type;
pp->bBidirectionalAveragingMode = (1 << 7) |
((DXVA_CONTEXT_CFG_INTRARESID(avctx, ctx) != 0) << 6) |
((DXVA_CONTEXT_CFG_RESIDACCEL(avctx, ctx) != 0) << 5) |
- ((v->lumscale != 32 || v->lumshift != 0) << 4) |
+ (intcomp << 4) |
((v->profile == PROFILE_ADVANCED) << 3);
pp->bMVprecisionAndChromaRelation = ((v->mv_mode == MV_PMODE_1MV_HPEL_BILIN) << 3) |
(1 << 2) |
@@ -123,15 +132,25 @@ static void fill_picture_parameters(AVCodecContext *avctx,
(v->range_mapuv_flag << 3) |
(v->range_mapuv );
pp->bPicBinPB = 0;
- pp->bMV_RPS = 0;
- pp->bReservedBits = 0;
+ pp->bMV_RPS = (v->fcm == ILACE_FIELD && pp->bPicBackwardPrediction) ? v->refdist + 9 : 0;
+ pp->bReservedBits = v->pq;
if (s->picture_structure == PICT_FRAME) {
- pp->wBitstreamFcodes = v->lumscale;
- pp->wBitstreamPCEelements = v->lumshift;
+ if (intcomp) {
+ pp->wBitstreamFcodes = v->lumscale;
+ pp->wBitstreamPCEelements = v->lumshift;
+ } else {
+ pp->wBitstreamFcodes = 32;
+ pp->wBitstreamPCEelements = 0;
+ }
} else {
/* Syntax: (top_field_param << 8) | bottom_field_param */
- pp->wBitstreamFcodes = (v->lumscale << 8) | v->lumscale;
- pp->wBitstreamPCEelements = (v->lumshift << 8) | v->lumshift;
+ if (intcomp) {
+ pp->wBitstreamFcodes = (v->lumscale << 8) | v->lumscale2;
+ pp->wBitstreamPCEelements = (v->lumshift << 8) | v->lumshift2;
+ } else {
+ pp->wBitstreamFcodes = (32 << 8) | 32;
+ pp->wBitstreamPCEelements = 0;
+ }
}
pp->bBitstreamConcealmentNeed = 0;
pp->bBitstreamConcealmentMethod = 0;
@@ -149,8 +168,8 @@ static void fill_slice(AVCodecContext *avctx, DXVA_SliceInfo *slice,
slice->dwSliceBitsInBuffer = 8 * size;
slice->dwSliceDataLocation = position;
slice->bStartCodeBitOffset = 0;
- slice->bReservedBits = 0;
- slice->wMBbitOffset = get_bits_count(&s->gb);
+ slice->bReservedBits = (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type) ? v->bfraction_lut_index + 9 : 0;
+ slice->wMBbitOffset = v->p_frame_skipped ? 0xffff : get_bits_count(&s->gb) + (avctx->codec_id == AV_CODEC_ID_VC1 ? 32 : 0);
slice->wNumberMBsInSlice = s->mb_width * s->mb_height; /* XXX We assume 1 slice */
slice->wQuantizerScaleCode = v->pq;
slice->wBadSliceChopping = 0;
@@ -202,8 +221,11 @@ static int commit_bitstream_and_slice_buffer(AVCodecContext *avctx,
dxva_data = dxva_data_ptr;
result = data_size <= dxva_size ? 0 : -1;
if (!result) {
- if (start_code_size > 0)
+ if (start_code_size > 0) {
memcpy(dxva_data, start_code, start_code_size);
+ if (v->second_field)
+ dxva_data[3] = 0x0c;
+ }
memcpy(dxva_data + start_code_size,
ctx_pic->bitstream + slice->dwSliceDataLocation, slice_size);
if (padding > 0)
diff --git a/libavcodec/eac3_data.c b/libavcodec/eac3_data.c
index b0416f3ce7..b159e1682f 100644
--- a/libavcodec/eac3_data.c
+++ b/libavcodec/eac3_data.c
@@ -2,20 +2,20 @@
* E-AC-3 tables
* Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/eac3_data.h b/libavcodec/eac3_data.h
index 4d88ce0a53..10a67f16d2 100644
--- a/libavcodec/eac3_data.h
+++ b/libavcodec/eac3_data.h
@@ -2,20 +2,20 @@
* E-AC-3 tables
* Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c
index b9d079ce8d..ef815afb55 100644
--- a/libavcodec/eac3dec.c
+++ b/libavcodec/eac3dec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Bartlomiej Wolowiec <bartek.wolowiec@gmail.com>
* Copyright (c) 2008 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -63,7 +63,7 @@ typedef enum {
#define EAC3_SR_CODE_REDUCED 3
-void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
+static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
{
int bin, bnd, ch, i;
uint8_t wrapflag[SPX_MAX_BANDS]={1,0,}, num_copy_sections, copy_sizes[SPX_MAX_BANDS];
@@ -101,7 +101,7 @@ void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
for (i = 0; i < num_copy_sections; i++) {
memcpy(&s->transform_coeffs[ch][bin],
&s->transform_coeffs[ch][s->spx_dst_start_freq],
- copy_sizes[i]*sizeof(float));
+ copy_sizes[i]*sizeof(INTFLOAT));
bin += copy_sizes[i];
}
@@ -124,7 +124,7 @@ void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
bin = s->spx_src_start_freq - 2;
for (bnd = 0; bnd < s->num_spx_bands; bnd++) {
if (wrapflag[bnd]) {
- float *coeffs = &s->transform_coeffs[ch][bin];
+ INTFLOAT *coeffs = &s->transform_coeffs[ch][bin];
coeffs[0] *= atten_tab[0];
coeffs[1] *= atten_tab[1];
coeffs[2] *= atten_tab[2];
@@ -142,6 +142,11 @@ void ff_eac3_apply_spectral_extension(AC3DecodeContext *s)
for (bnd = 0; bnd < s->num_spx_bands; bnd++) {
float nscale = s->spx_noise_blend[ch][bnd] * rms_energy[bnd] * (1.0f / INT32_MIN);
float sscale = s->spx_signal_blend[ch][bnd];
+#if USE_FIXED
+ // spx_noise_blend and spx_signal_blend are both FP.23
+ nscale *= 1.0 / (1<<23);
+ sscale *= 1.0 / (1<<23);
+#endif
for (i = 0; i < s->spx_band_sizes[bnd]; i++) {
float noise = nscale * (int32_t)av_lfg_get(&s->dith_state);
s->transform_coeffs[ch][bin] *= sscale;
@@ -195,7 +200,7 @@ static void idct6(int pre_mant[6])
pre_mant[5] = even0 - odd0;
}
-void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch)
+static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch)
{
int bin, blk, gs;
int end_bap, gaq_mode;
@@ -288,7 +293,7 @@ void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch)
}
}
-int ff_eac3_parse_header(AC3DecodeContext *s)
+static int ff_eac3_parse_header(AC3DecodeContext *s)
{
int i, blk, ch;
int ac3_exponent_strategy, parse_aht_info, parse_spx_atten_data;
diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c
index 3aa2d54013..e1d61f68bf 100644
--- a/libavcodec/eac3enc.c
+++ b/libavcodec/eac3enc.c
@@ -2,20 +2,20 @@
* E-AC-3 encoder
* Copyright (c) 2011 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,9 +34,13 @@
#define AC3ENC_TYPE AC3ENC_TYPE_EAC3
#include "ac3enc_opts_template.c"
-static const AVClass eac3enc_class = { "E-AC-3 Encoder", av_default_item_name,
- ac3_options, LIBAVUTIL_VERSION_INT };
+static const AVClass eac3enc_class = {
+ .class_name = "E-AC-3 Encoder",
+ .item_name = av_default_item_name,
+ .option = ac3_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
/**
* LUT for finding a matching frame exponent strategy index from a set of
diff --git a/libavcodec/eac3enc.h b/libavcodec/eac3enc.h
index a92a24c2fa..7d6155975d 100644
--- a/libavcodec/eac3enc.h
+++ b/libavcodec/eac3enc.h
@@ -2,20 +2,20 @@
* E-AC-3 encoder
* Copyright (c) 2011 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/eacmv.c b/libavcodec/eacmv.c
index c5ce9a5a87..d1b7c68595 100644
--- a/libavcodec/eacmv.c
+++ b/libavcodec/eacmv.c
@@ -2,20 +2,20 @@
* Electronic Arts CMV Video Decoder
* Copyright (c) 2007-2008 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,6 +44,7 @@ typedef struct CmvContext {
static av_cold int cmv_decode_init(AVCodecContext *avctx){
CmvContext *s = avctx->priv_data;
+
s->avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
@@ -160,7 +161,7 @@ static int cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t *
buf += 16;
for (i=pal_start; i<pal_start+pal_count && i<AVPALETTE_COUNT && buf_end - buf >= 3; i++) {
- s->palette[i] = AV_RB24(buf);
+ s->palette[i] = 0xFFU << 24 | AV_RB24(buf);
buf += 3;
}
@@ -185,19 +186,20 @@ static int cmv_decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
if (AV_RL32(buf)==MVIh_TAG||AV_RB32(buf)==MVIh_TAG) {
+ unsigned size = AV_RL32(buf + 4);
ret = cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end);
if (ret < 0)
return ret;
- return buf_size;
+ if (size > buf_end - buf - EA_PREAMBLE_SIZE)
+ return -1;
+ buf += size;
}
if (av_image_check_size(s->width, s->height, 0, s->avctx))
return -1;
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
memcpy(frame->data[1], s->palette, AVPALETTE_SIZE);
diff --git a/libavcodec/eaidct.c b/libavcodec/eaidct.c
index 5b2db44aff..e4840f2653 100644
--- a/libavcodec/eaidct.c
+++ b/libavcodec/eaidct.c
@@ -2,20 +2,20 @@
* Electronic Arts TGQ/TQI/MAD IDCT algorithm
* Copyright (c) 2007-2008 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/eaidct.h b/libavcodec/eaidct.h
index e78de04178..6b9ec1c91c 100644
--- a/libavcodec/eaidct.h
+++ b/libavcodec/eaidct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/eamad.c b/libavcodec/eamad.c
index a76d93508d..6b7134a98d 100644
--- a/libavcodec/eamad.c
+++ b/libavcodec/eamad.c
@@ -2,20 +2,20 @@
* Electronic Arts Madcow Video Decoder
* Copyright (c) 2007-2009 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -94,15 +94,21 @@ static inline void comp_block(MadContext *t, AVFrame *frame,
int j, int mv_x, int mv_y, int add)
{
if (j < 4) {
+ unsigned offset = (mb_y*16 + ((j&2)<<2) + mv_y)*t->last_frame->linesize[0] + mb_x*16 + ((j&1)<<3) + mv_x;
+ if (offset >= (t->avctx->height - 7) * t->last_frame->linesize[0] - 7)
+ return;
comp(frame->data[0] + (mb_y*16 + ((j&2)<<2))*frame->linesize[0] + mb_x*16 + ((j&1)<<3),
frame->linesize[0],
- t->last_frame->data[0] + (mb_y*16 + ((j&2)<<2) + mv_y)*t->last_frame->linesize[0] + mb_x*16 + ((j&1)<<3) + mv_x,
+ t->last_frame->data[0] + offset,
t->last_frame->linesize[0], add);
} else if (!(t->avctx->flags & CODEC_FLAG_GRAY)) {
int index = j - 3;
+ unsigned offset = (mb_y * 8 + (mv_y/2))*t->last_frame->linesize[index] + mb_x * 8 + (mv_x/2);
+ if (offset >= (t->avctx->height/2 - 7) * t->last_frame->linesize[index] - 7)
+ return;
comp(frame->data[index] + (mb_y*8)*frame->linesize[index] + mb_x * 8,
frame->linesize[index],
- t->last_frame->data[index] + (mb_y * 8 + (mv_y/2))*t->last_frame->linesize[index] + mb_x * 8 + (mv_x/2),
+ t->last_frame->data[index] + offset,
t->last_frame->linesize[index], add);
}
}
@@ -122,7 +128,7 @@ static inline void idct_put(MadContext *t, AVFrame *frame, int16_t *block,
}
}
-static inline void decode_block_intra(MadContext *s, int16_t * block)
+static inline int decode_block_intra(MadContext *s, int16_t * block)
{
int level, i, j, run;
RLTable *rl = &ff_rl_mpeg1;
@@ -148,7 +154,7 @@ static inline void decode_block_intra(MadContext *s, int16_t * block)
if (i > 63) {
av_log(s->avctx, AV_LOG_ERROR,
"ac-tex damaged at %d %d\n", s->mb_x, s->mb_y);
- return;
+ return -1;
}
j = scantable[i];
level = (level*quant_matrix[j]) >> 4;
@@ -167,7 +173,7 @@ static inline void decode_block_intra(MadContext *s, int16_t * block)
if (i > 63) {
av_log(s->avctx, AV_LOG_ERROR,
"ac-tex damaged at %d %d\n", s->mb_x, s->mb_y);
- return;
+ return -1;
}
j = scantable[i];
if (level < 0) {
@@ -185,6 +191,7 @@ static inline void decode_block_intra(MadContext *s, int16_t * block)
}
CLOSE_READER(re, &s->gb);
}
+ return 0;
}
static int decode_motion(GetBitContext *gb)
@@ -198,10 +205,10 @@ static int decode_motion(GetBitContext *gb)
return value;
}
-static void decode_mb(MadContext *s, AVFrame *frame, int inter)
+static int decode_mb(MadContext *s, AVFrame *frame, int inter)
{
int mv_map = 0;
- int mv_x, mv_y;
+ int av_uninit(mv_x), av_uninit(mv_y);
int j;
if (inter) {
@@ -210,21 +217,22 @@ static void decode_mb(MadContext *s, AVFrame *frame, int inter)
mv_map = v ? get_bits(&s->gb, 6) : 63;
mv_x = decode_motion(&s->gb);
mv_y = decode_motion(&s->gb);
- } else {
- mv_map = 0;
}
}
for (j=0; j<6; j++) {
if (mv_map & (1<<j)) { // mv_x and mv_y are guarded by mv_map
int add = 2*decode_motion(&s->gb);
- comp_block(s, frame, s->mb_x, s->mb_y, j, mv_x, mv_y, add);
+ if (s->last_frame->data[0])
+ comp_block(s, frame, s->mb_x, s->mb_y, j, mv_x, mv_y, add);
} else {
s->bdsp.clear_block(s->block);
- decode_block_intra(s, s->block);
+ if(decode_block_intra(s, s->block) < 0)
+ return -1;
idct_put(s, frame, s->block, s->mb_x, s->mb_y, j);
}
}
+ return 0;
}
static void calc_quant_matrix(MadContext *s, int qscale)
@@ -269,16 +277,21 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
+ if (width < 16 || height < 16) {
+ av_log(avctx, AV_LOG_ERROR, "Dimensions too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
if (avctx->width != width || avctx->height != height) {
av_frame_unref(s->last_frame);
+ if((width * height)/2048*7 > bytestream2_get_bytes_left(&gb))
+ return AVERROR_INVALIDDATA;
if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
return ret;
}
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if (inter && !s->last_frame->data[0]) {
av_log(avctx, AV_LOG_WARNING, "Missing reference frame.\n");
@@ -299,11 +312,13 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR(ENOMEM);
s->bbdsp.bswap16_buf(s->bitstream_buf, (const uint16_t *)(buf + bytestream2_tell(&gb)),
bytestream2_get_bytes_left(&gb) / 2);
+ memset((uint8_t*)s->bitstream_buf + bytestream2_get_bytes_left(&gb), 0, FF_INPUT_BUFFER_PADDING_SIZE);
init_get_bits(&s->gb, s->bitstream_buf, 8*(bytestream2_get_bytes_left(&gb)));
for (s->mb_y=0; s->mb_y < (avctx->height+15)/16; s->mb_y++)
for (s->mb_x=0; s->mb_x < (avctx->width +15)/16; s->mb_x++)
- decode_mb(s, frame, inter);
+ if(decode_mb(s, frame, inter) < 0)
+ return AVERROR_INVALIDDATA;
*got_frame = 1;
@@ -320,7 +335,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
{
MadContext *t = avctx->priv_data;
av_frame_free(&t->last_frame);
- av_free(t->bitstream_buf);
+ av_freep(&t->bitstream_buf);
return 0;
}
diff --git a/libavcodec/eatgq.c b/libavcodec/eatgq.c
index 3d20c6c8ea..771dc2fb1a 100644
--- a/libavcodec/eatgq.c
+++ b/libavcodec/eatgq.c
@@ -2,20 +2,20 @@
* Electronic Arts TGQ Video Decoder
* Copyright (c) 2007-2008 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -148,7 +148,7 @@ static void tgq_idct_put_mb_dconly(TgqContext *s, AVFrame *frame,
}
}
-static void tgq_decode_mb(TgqContext *s, AVFrame *frame, int mb_y, int mb_x)
+static int tgq_decode_mb(TgqContext *s, AVFrame *frame, int mb_y, int mb_x)
{
int mode;
int i;
@@ -157,7 +157,7 @@ static void tgq_decode_mb(TgqContext *s, AVFrame *frame, int mb_y, int mb_x)
mode = bytestream2_get_byte(&s->gb);
if (mode > 12) {
GetBitContext gb;
- init_get_bits(&gb, s->gb.buffer, FFMIN(s->gb.buffer_end - s->gb.buffer, mode) * 8);
+ init_get_bits8(&gb, s->gb.buffer, FFMIN(bytestream2_get_bytes_left(&s->gb), mode));
for (i = 0; i < 6; i++)
tgq_decode_block(s, s->block[i], &gb);
tgq_idct_put_mb(s, s->block, frame, mb_x, mb_y);
@@ -176,9 +176,11 @@ static void tgq_decode_mb(TgqContext *s, AVFrame *frame, int mb_y, int mb_x)
}
} else {
av_log(s->avctx, AV_LOG_ERROR, "unsupported mb mode %i\n", mode);
+ return -1;
}
tgq_idct_put_mb_dconly(s, frame, mb_x, mb_y, dc);
}
+ return 0;
}
static void tgq_calculate_qtable(TgqContext *s, int quant)
@@ -201,12 +203,13 @@ static int tgq_decode_frame(AVCodecContext *avctx,
TgqContext *s = avctx->priv_data;
AVFrame *frame = data;
int x, y, ret;
- int big_endian = AV_RL32(&buf[4]) > 0x000FFFFF;
+ int big_endian;
if (buf_size < 16) {
av_log(avctx, AV_LOG_WARNING, "truncated header\n");
return AVERROR_INVALIDDATA;
}
+ big_endian = AV_RL32(&buf[4]) > 0x000FFFFF;
bytestream2_init(&s->gb, buf + 8, buf_size - 8);
if (big_endian) {
s->width = bytestream2_get_be16u(&s->gb);
@@ -223,16 +226,15 @@ static int tgq_decode_frame(AVCodecContext *avctx,
tgq_calculate_qtable(s, bytestream2_get_byteu(&s->gb));
bytestream2_skip(&s->gb, 3);
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
frame->key_frame = 1;
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++)
- tgq_decode_mb(s, frame, y, x);
+ if (tgq_decode_mb(s, frame, y, x) < 0)
+ return AVERROR_INVALIDDATA;
*got_frame = 1;
diff --git a/libavcodec/eatgv.c b/libavcodec/eatgv.c
index c400b56713..b4d3d1d27d 100644
--- a/libavcodec/eatgv.c
+++ b/libavcodec/eatgv.c
@@ -2,20 +2,20 @@
* Electronic Arts TGV Video Decoder
* Copyright (c) 2007-2008 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,7 +81,7 @@ static int unpack(const uint8_t *src, const uint8_t *src_end,
else
src += 2;
- if (src + 3 > src_end)
+ if (src_end - src < 3)
return AVERROR_INVALIDDATA;
size = AV_RB24(src);
src += 3;
@@ -156,7 +156,7 @@ static int tgv_decode_inter(TgvContext *s, AVFrame *frame,
int mvbits;
const uint8_t *blocks_raw;
- if (buf + 12 > buf_end)
+ if(buf_end - buf < 12)
return AVERROR_INVALIDDATA;
num_mvs = AV_RL16(&buf[0]);
@@ -173,7 +173,10 @@ static int tgv_decode_inter(TgvContext *s, AVFrame *frame,
/* allocate codebook buffers as necessary */
if (num_mvs > s->num_mvs) {
- s->mv_codebook = av_realloc(s->mv_codebook, num_mvs*2*sizeof(int));
+ if (av_reallocp_array(&s->mv_codebook, num_mvs, sizeof(*s->mv_codebook))) {
+ s->num_mvs = 0;
+ return AVERROR(ENOMEM);
+ }
s->num_mvs = num_mvs;
}
@@ -189,7 +192,7 @@ static int tgv_decode_inter(TgvContext *s, AVFrame *frame,
/* read motion vectors */
mvbits = (num_mvs * 2 * 10 + 31) & ~31;
- if (buf + (mvbits >> 3) + 16 * num_blocks_raw + 8 * num_blocks_packed > buf_end)
+ if (buf_end - buf < (mvbits>>3) + 16*num_blocks_raw + 8*num_blocks_packed)
return AVERROR_INVALIDDATA;
init_get_bits(&gb, buf, mvbits);
@@ -229,8 +232,10 @@ static int tgv_decode_inter(TgvContext *s, AVFrame *frame,
int my = y * 4 + s->mv_codebook[vector][1];
if (mx < 0 || mx + 4 > s->avctx->width ||
- my < 0 || my + 4 > s->avctx->height)
+ my < 0 || my + 4 > s->avctx->height) {
+ av_log(s->avctx, AV_LOG_ERROR, "MV %d %d out of picture\n", mx, my);
continue;
+ }
src = s->last_frame->data[0] + mx + my * s->last_frame->linesize[0];
src_stride = s->last_frame->linesize[0];
@@ -265,12 +270,15 @@ static int tgv_decode_frame(AVCodecContext *avctx,
AVFrame *frame = data;
int chunk_type, ret;
+ if (buf_end - buf < EA_PREAMBLE_SIZE)
+ return AVERROR_INVALIDDATA;
+
chunk_type = AV_RL32(&buf[0]);
buf += EA_PREAMBLE_SIZE;
if (chunk_type == kVGT_TAG) {
int pal_count, i;
- if (buf + 12 > buf_end) {
+ if(buf_end - buf < 12) {
av_log(avctx, AV_LOG_WARNING, "truncated header\n");
return AVERROR_INVALIDDATA;
}
@@ -286,8 +294,8 @@ static int tgv_decode_frame(AVCodecContext *avctx,
pal_count = AV_RL16(&buf[6]);
buf += 12;
- for (i = 0; i < pal_count && i < AVPALETTE_COUNT && buf + 2 < buf_end; i++) {
- s->palette[i] = AV_RB24(buf);
+ for(i = 0; i < pal_count && i < AVPALETTE_COUNT && buf_end - buf >= 3; i++) {
+ s->palette[i] = 0xFFU << 24 | AV_RB24(buf);
buf += 3;
}
}
@@ -303,7 +311,7 @@ static int tgv_decode_frame(AVCodecContext *avctx,
frame->pict_type = AV_PICTURE_TYPE_I;
if (!s->frame_buffer &&
- !(s->frame_buffer = av_malloc(s->width * s->height)))
+ !(s->frame_buffer = av_mallocz(s->width * s->height)))
return AVERROR(ENOMEM);
if (unpack(buf, buf_end, s->frame_buffer, s->avctx->width, s->avctx->height) < 0) {
@@ -341,8 +349,8 @@ static av_cold int tgv_decode_end(AVCodecContext *avctx)
TgvContext *s = avctx->priv_data;
av_frame_free(&s->last_frame);
av_freep(&s->frame_buffer);
- av_free(s->mv_codebook);
- av_free(s->block_codebook);
+ av_freep(&s->mv_codebook);
+ av_freep(&s->block_codebook);
return 0;
}
diff --git a/libavcodec/eatqi.c b/libavcodec/eatqi.c
index 256b6b4acb..34fc30dbba 100644
--- a/libavcodec/eatqi.c
+++ b/libavcodec/eatqi.c
@@ -2,20 +2,20 @@
* Electronic Arts TQI Video Decoder
* Copyright (c) 2007-2009 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -121,10 +121,8 @@ static int tqi_decode_frame(AVCodecContext *avctx,
if (ret < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
av_fast_padded_malloc(&t->bitstream_buf, &t->bitstream_buf_size,
buf_end - buf);
@@ -139,9 +137,10 @@ static int tqi_decode_frame(AVCodecContext *avctx,
for (s->mb_x=0; s->mb_x<(avctx->width+15)/16; s->mb_x++)
{
if (tqi_decode_mb(s, t->block) < 0)
- break;
+ goto end;
tqi_idct_put(t, frame, t->block);
}
+ end:
*got_frame = 1;
return buf_size;
@@ -150,7 +149,7 @@ static int tqi_decode_frame(AVCodecContext *avctx,
static av_cold int tqi_decode_end(AVCodecContext *avctx)
{
TqiContext *t = avctx->priv_data;
- av_free(t->bitstream_buf);
+ av_freep(&t->bitstream_buf);
return 0;
}
diff --git a/libavcodec/elbg.c b/libavcodec/elbg.c
index e2b03a6f9b..23ae9483f7 100644
--- a/libavcodec/elbg.c
+++ b/libavcodec/elbg.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/lfg.h"
#include "elbg.h"
@@ -50,7 +51,7 @@ typedef struct elbg_data {
int *codebook;
cell **cells;
int *utility;
- int *utility_inc;
+ int64_t *utility_inc;
int *nearest_cb;
int *points;
AVLFG *rand_state;
@@ -107,11 +108,20 @@ static int get_high_utility_cell(elbg_data *elbg)
{
int i=0;
/* Using linear search, do binary if it ever turns to be speed critical */
- int r = av_lfg_get(elbg->rand_state)%elbg->utility_inc[elbg->numCB-1] + 1;
- while (elbg->utility_inc[i] < r)
+ uint64_t r;
+
+ if (elbg->utility_inc[elbg->numCB-1] < INT_MAX) {
+ r = av_lfg_get(elbg->rand_state) % (unsigned int)elbg->utility_inc[elbg->numCB-1] + 1;
+ } else {
+ r = av_lfg_get(elbg->rand_state);
+ r = (av_lfg_get(elbg->rand_state) + (r<<32)) % elbg->utility_inc[elbg->numCB-1] + 1;
+ }
+
+ while (elbg->utility_inc[i] < r) {
i++;
+ }
- assert(elbg->cells[i]);
+ av_assert2(elbg->cells[i]);
return i;
}
@@ -189,7 +199,7 @@ static void get_new_centroids(elbg_data *elbg, int huc, int *newcentroid_i,
/**
* Add the points in the low utility cell to its closest cell. Split the high
- * utility cell, putting the separed points in the (now empty) low utility
+ * utility cell, putting the separate points in the (now empty) low utility
* cell.
*
* @param elbg Internal elbg data
@@ -226,7 +236,8 @@ static void shift_codebook(elbg_data *elbg, int *indexes,
static void evaluate_utility_inc(elbg_data *elbg)
{
- int i, inc=0;
+ int i;
+ int64_t inc=0;
for (i=0; i < elbg->numCB; i++) {
if (elbg->numCB*elbg->utility[i] > elbg->error)
@@ -323,7 +334,7 @@ static void do_shiftings(elbg_data *elbg)
#define BIG_PRIME 433494437LL
-int ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
+int avpriv_init_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int max_steps, int *closest_cb,
AVLFG *rand_state)
{
@@ -332,7 +343,7 @@ int ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
if (numpoints > 24*numCB) {
/* ELBG is very costly for a big number of points. So if we have a lot
of them, get a good initial codebook to save on iterations */
- int *temp_points = av_malloc(dim*(numpoints/8)*sizeof(int));
+ int *temp_points = av_malloc_array(dim, (numpoints/8)*sizeof(int));
if (!temp_points)
return AVERROR(ENOMEM);
for (i=0; i<numpoints/8; i++) {
@@ -340,14 +351,14 @@ int ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
memcpy(temp_points + i*dim, points + k*dim, dim*sizeof(int));
}
- ret = ff_init_elbg(temp_points, dim, numpoints / 8, codebook,
- numCB, 2 * max_steps, closest_cb, rand_state);
+ ret = avpriv_init_elbg(temp_points, dim, numpoints / 8, codebook,
+ numCB, 2 * max_steps, closest_cb, rand_state);
if (ret < 0) {
av_freep(&temp_points);
return ret;
}
- ret = ff_do_elbg(temp_points, dim, numpoints / 8, codebook,
- numCB, 2 * max_steps, closest_cb, rand_state);
+ ret = avpriv_do_elbg(temp_points, dim, numpoints / 8, codebook,
+ numCB, 2 * max_steps, closest_cb, rand_state);
av_free(temp_points);
} else // If not, initialize the codebook with random positions
@@ -357,7 +368,7 @@ int ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
return ret;
}
-int ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
+int avpriv_do_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int max_steps, int *closest_cb,
AVLFG *rand_state)
{
@@ -365,9 +376,9 @@ int ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
elbg_data elbg_d;
elbg_data *elbg = &elbg_d;
int i, j, k, last_error, steps = 0, ret = 0;
- int *dist_cb = av_malloc(numpoints*sizeof(int));
- int *size_part = av_malloc(numCB*sizeof(int));
- cell *list_buffer = av_malloc(numpoints*sizeof(cell));
+ int *dist_cb = av_malloc_array(numpoints, sizeof(int));
+ int *size_part = av_malloc_array(numCB, sizeof(int));
+ cell *list_buffer = av_malloc_array(numpoints, sizeof(cell));
cell *free_cells;
int best_dist, best_idx = 0;
@@ -375,12 +386,12 @@ int ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
elbg->dim = dim;
elbg->numCB = numCB;
elbg->codebook = codebook;
- elbg->cells = av_malloc(numCB*sizeof(cell *));
- elbg->utility = av_malloc(numCB*sizeof(int));
+ elbg->cells = av_malloc_array(numCB, sizeof(cell *));
+ elbg->utility = av_malloc_array(numCB, sizeof(int));
elbg->nearest_cb = closest_cb;
elbg->points = points;
- elbg->utility_inc = av_malloc(numCB*sizeof(int));
- elbg->scratchbuf = av_malloc(5*dim*sizeof(int));
+ elbg->utility_inc = av_malloc_array(numCB, sizeof(*elbg->utility_inc));
+ elbg->scratchbuf = av_malloc_array(5*dim, sizeof(int));
if (!dist_cb || !size_part || !list_buffer || !elbg->cells ||
!elbg->utility || !elbg->utility_inc || !elbg->scratchbuf) {
diff --git a/libavcodec/elbg.h b/libavcodec/elbg.h
index 3b1587a3ab..f48aa3b443 100644
--- a/libavcodec/elbg.h
+++ b/libavcodec/elbg.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@
* @param rand_state A random number generator state. Should be already initialized by av_lfg_init().
* @return < 0 in case of error, 0 otherwise
*/
-int ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
+int avpriv_do_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int num_steps, int *closest_cb,
AVLFG *rand_state);
@@ -46,11 +46,11 @@ int ff_do_elbg(int *points, int dim, int numpoints, int *codebook,
* Initialize the **codebook vector for the elbg algorithm. If you have already
* a codebook and you want to refine it, you shouldn't call this function.
* If numpoints < 8*numCB this function fills **codebook with random numbers.
- * If not, it calls ff_do_elbg for a (smaller) random sample of the points in
- * **points. Get the same parameters as ff_do_elbg.
+ * If not, it calls avpriv_do_elbg for a (smaller) random sample of the points in
+ * **points. Get the same parameters as avpriv_do_elbg.
* @return < 0 in case of error, 0 otherwise
*/
-int ff_init_elbg(int *points, int dim, int numpoints, int *codebook,
+int avpriv_init_elbg(int *points, int dim, int numpoints, int *codebook,
int numCB, int num_steps, int *closest_cb,
AVLFG *rand_state);
diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c
index 2c7836f23d..df4a64d17a 100644
--- a/libavcodec/error_resilience.c
+++ b/libavcodec/error_resilience.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include <limits.h>
+#include "libavutil/atomic.h"
#include "libavutil/internal.h"
#include "avcodec.h"
#include "error_resilience.h"
@@ -44,7 +45,7 @@
static void set_mv_strides(ERContext *s, int *mv_step, int *stride)
{
if (s->avctx->codec_id == AV_CODEC_ID_H264) {
- assert(s->quarter_sample);
+ av_assert0(s->quarter_sample);
*mv_step = 4;
*stride = s->mb_width * 4;
} else {
@@ -83,6 +84,8 @@ static void put_dc(ERContext *s, uint8_t *dest_y, uint8_t *dest_cb,
dcv = 0;
else if (dcv > 2040)
dcv = 2040;
+
+ if (dest_cr)
for (y = 0; y < 8; y++) {
int x;
for (x = 0; x < 8; x++) {
@@ -137,11 +140,73 @@ static void guess_dc(ERContext *s, int16_t *dc, int w,
int h, int stride, int is_luma)
{
int b_x, b_y;
+ int16_t (*col )[4] = av_malloc_array(stride, h*sizeof( int16_t)*4);
+ uint32_t (*dist)[4] = av_malloc_array(stride, h*sizeof(uint32_t)*4);
+
+ if(!col || !dist) {
+ av_log(s->avctx, AV_LOG_ERROR, "guess_dc() is out of memory\n");
+ goto fail;
+ }
+
+ for(b_y=0; b_y<h; b_y++){
+ int color= 1024;
+ int distance= -1;
+ for(b_x=0; b_x<w; b_x++){
+ int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
+ int error_j= s->error_status_table[mb_index_j];
+ int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
+ if(intra_j==0 || !(error_j&ER_DC_ERROR)){
+ color= dc[b_x + b_y*stride];
+ distance= b_x;
+ }
+ col [b_x + b_y*stride][1]= color;
+ dist[b_x + b_y*stride][1]= distance >= 0 ? b_x-distance : 9999;
+ }
+ color= 1024;
+ distance= -1;
+ for(b_x=w-1; b_x>=0; b_x--){
+ int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
+ int error_j= s->error_status_table[mb_index_j];
+ int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
+ if(intra_j==0 || !(error_j&ER_DC_ERROR)){
+ color= dc[b_x + b_y*stride];
+ distance= b_x;
+ }
+ col [b_x + b_y*stride][0]= color;
+ dist[b_x + b_y*stride][0]= distance >= 0 ? distance-b_x : 9999;
+ }
+ }
+ for(b_x=0; b_x<w; b_x++){
+ int color= 1024;
+ int distance= -1;
+ for(b_y=0; b_y<h; b_y++){
+ int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
+ int error_j= s->error_status_table[mb_index_j];
+ int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
+ if(intra_j==0 || !(error_j&ER_DC_ERROR)){
+ color= dc[b_x + b_y*stride];
+ distance= b_y;
+ }
+ col [b_x + b_y*stride][3]= color;
+ dist[b_x + b_y*stride][3]= distance >= 0 ? b_y-distance : 9999;
+ }
+ color= 1024;
+ distance= -1;
+ for(b_y=h-1; b_y>=0; b_y--){
+ int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride;
+ int error_j= s->error_status_table[mb_index_j];
+ int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
+ if(intra_j==0 || !(error_j&ER_DC_ERROR)){
+ color= dc[b_x + b_y*stride];
+ distance= b_y;
+ }
+ col [b_x + b_y*stride][2]= color;
+ dist[b_x + b_y*stride][2]= distance >= 0 ? distance-b_y : 9999;
+ }
+ }
for (b_y = 0; b_y < h; b_y++) {
for (b_x = 0; b_x < w; b_x++) {
- int color[4] = { 1024, 1024, 1024, 1024 };
- int distance[4] = { 9999, 9999, 9999, 9999 };
int mb_index, error, j;
int64_t guess, weight_sum;
mb_index = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride;
@@ -152,66 +217,21 @@ static void guess_dc(ERContext *s, int16_t *dc, int w,
if (!(error & ER_DC_ERROR))
continue; // dc-ok
- /* right block */
- for (j = b_x + 1; j < w; j++) {
- int mb_index_j = (j >> is_luma) + (b_y >> is_luma) * s->mb_stride;
- int error_j = s->error_status_table[mb_index_j];
- int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
- if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
- color[0] = dc[j + b_y * stride];
- distance[0] = j - b_x;
- break;
- }
- }
-
- /* left block */
- for (j = b_x - 1; j >= 0; j--) {
- int mb_index_j = (j >> is_luma) + (b_y >> is_luma) * s->mb_stride;
- int error_j = s->error_status_table[mb_index_j];
- int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
- if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
- color[1] = dc[j + b_y * stride];
- distance[1] = b_x - j;
- break;
- }
- }
-
- /* bottom block */
- for (j = b_y + 1; j < h; j++) {
- int mb_index_j = (b_x >> is_luma) + (j >> is_luma) * s->mb_stride;
- int error_j = s->error_status_table[mb_index_j];
- int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
-
- if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
- color[2] = dc[b_x + j * stride];
- distance[2] = j - b_y;
- break;
- }
- }
-
- /* top block */
- for (j = b_y - 1; j >= 0; j--) {
- int mb_index_j = (b_x >> is_luma) + (j >> is_luma) * s->mb_stride;
- int error_j = s->error_status_table[mb_index_j];
- int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]);
- if (intra_j == 0 || !(error_j & ER_DC_ERROR)) {
- color[3] = dc[b_x + j * stride];
- distance[3] = b_y - j;
- break;
- }
- }
-
weight_sum = 0;
guess = 0;
for (j = 0; j < 4; j++) {
- int64_t weight = 256 * 256 * 256 * 16 / distance[j];
- guess += weight * (int64_t) color[j];
+ int64_t weight = 256 * 256 * 256 * 16 / FFMAX(dist[b_x + b_y*stride][j], 1);
+ guess += weight*(int64_t)col[b_x + b_y*stride][j];
weight_sum += weight;
}
guess = (guess + weight_sum / 2) / weight_sum;
dc[b_x + b_y * stride] = guess;
}
}
+
+fail:
+ av_freep(&col);
+ av_freep(&dist);
}
/**
@@ -381,6 +401,14 @@ static void guess_mv(ERContext *s)
fixed[mb_xy] = f;
if (f == MV_FROZEN)
num_avail++;
+ else if(s->last_pic.f->data[0] && s->last_pic.motion_val[0]){
+ const int mb_y= mb_xy / s->mb_stride;
+ const int mb_x= mb_xy % s->mb_stride;
+ const int mot_index= (mb_x + mb_y*mot_stride) * mot_step;
+ s->cur_pic.motion_val[0][mot_index][0]= s->last_pic.motion_val[0][mot_index][0];
+ s->cur_pic.motion_val[0][mot_index][1]= s->last_pic.motion_val[0][mot_index][1];
+ s->cur_pic.ref_index[0][4*mb_xy] = s->last_pic.ref_index[0][4*mb_xy];
+ }
}
if ((!(s->avctx->error_concealment&FF_EC_GUESS_MVS)) ||
@@ -431,6 +459,8 @@ static void guess_mv(ERContext *s)
if (fixed[mb_xy] == MV_FROZEN)
continue;
+ av_assert1(!IS_INTRA(s->cur_pic.mb_type[mb_xy]));
+ av_assert1(s->last_pic.f && s->last_pic.f->data[0]);
j = 0;
if (mb_x > 0 && fixed[mb_xy - 1] == MV_FROZEN)
@@ -545,7 +575,7 @@ skip_mean_and_median:
/* zero MV */
pred_count++;
- if (!fixed[mb_xy]) {
+ if (!fixed[mb_xy] && 0) {
if (s->avctx->codec_id == AV_CODEC_ID_H264) {
// FIXME
} else {
@@ -660,6 +690,9 @@ static int is_intra_more_likely(ERContext *s)
if (!s->last_pic.f || !s->last_pic.f->data[0])
return 1; // no previous frame available -> use spatial prediction
+ if (s->avctx->error_concealment & FF_EC_FAVOR_INTER)
+ return 0;
+
undamaged_count = 0;
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
@@ -668,21 +701,14 @@ static int is_intra_more_likely(ERContext *s)
undamaged_count++;
}
- if (s->avctx->codec_id == AV_CODEC_ID_H264 && s->ref_count <= 0)
- return 1;
-
if (undamaged_count < 5)
return 0; // almost all MBs damaged -> use temporal prediction
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
// prevent dsp.sad() check, that requires access to the image
- if (CONFIG_MPEG_XVMC_DECODER &&
- s->avctx->xvmc_acceleration &&
+ if (CONFIG_XVMC &&
+ s->avctx->hwaccel && s->avctx->hwaccel->decode_mb &&
s->cur_pic.f->pict_type == AV_PICTURE_TYPE_I)
return 1;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
skip_amount = FFMAX(undamaged_count / 50, 1); // check only up to 50 MBs
is_intra_likely = 0;
@@ -716,6 +742,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
is_intra_likely += s->mecc.sad[0](NULL, last_mb_ptr, mb_ptr,
linesize[0], 16);
+ // FIXME need await_progress() here
is_intra_likely -= s->mecc.sad[0](NULL, last_mb_ptr,
last_mb_ptr + linesize[0] * 16,
linesize[0], 16);
@@ -727,6 +754,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
}
}
+// av_log(NULL, AV_LOG_ERROR, "is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type);
return is_intra_likely > 0;
}
@@ -746,6 +774,17 @@ void ff_er_frame_start(ERContext *s)
s->error_occurred = 0;
}
+static int er_supported(ERContext *s)
+{
+ if(s->avctx->hwaccel && s->avctx->hwaccel->decode_slice ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU ||
+ !s->cur_pic.f ||
+ s->cur_pic.field_picture
+ )
+ return 0;
+ return 1;
+}
+
/**
* Add a slice.
* @param endx x component of the last macroblock, can be -1
@@ -762,7 +801,7 @@ void ff_er_add_slice(ERContext *s, int startx, int starty,
const int end_xy = s->mb_index2xy[end_i];
int mask = -1;
- if (s->avctx->hwaccel)
+ if (s->avctx->hwaccel && s->avctx->hwaccel->decode_slice)
return;
if (start_i > end_i || start_xy > end_xy) {
@@ -777,20 +816,20 @@ void ff_er_add_slice(ERContext *s, int startx, int starty,
mask &= ~VP_START;
if (status & (ER_AC_ERROR | ER_AC_END)) {
mask &= ~(ER_AC_ERROR | ER_AC_END);
- s->error_count -= end_i - start_i + 1;
+ avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1);
}
if (status & (ER_DC_ERROR | ER_DC_END)) {
mask &= ~(ER_DC_ERROR | ER_DC_END);
- s->error_count -= end_i - start_i + 1;
+ avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1);
}
if (status & (ER_MV_ERROR | ER_MV_END)) {
mask &= ~(ER_MV_ERROR | ER_MV_END);
- s->error_count -= end_i - start_i + 1;
+ avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1);
}
if (status & ER_MB_ERROR) {
s->error_occurred = 1;
- s->error_count = INT_MAX;
+ avpriv_atomic_int_set(&s->error_count, INT_MAX);
}
if (mask == ~0x7F) {
@@ -803,7 +842,7 @@ void ff_er_add_slice(ERContext *s, int startx, int starty,
}
if (end_i == s->mb_num)
- s->error_count = INT_MAX;
+ avpriv_atomic_int_set(&s->error_count, INT_MAX);
else {
s->error_status_table[end_xy] &= mask;
s->error_status_table[end_xy] |= status;
@@ -811,41 +850,92 @@ void ff_er_add_slice(ERContext *s, int startx, int starty,
s->error_status_table[start_xy] |= VP_START;
- if (start_xy > 0 && s->avctx->thread_count <= 1 &&
- s->avctx->skip_top * s->mb_width < start_i) {
+ if (start_xy > 0 && !(s->avctx->active_thread_type & FF_THREAD_SLICE) &&
+ er_supported(s) && s->avctx->skip_top * s->mb_width < start_i) {
int prev_status = s->error_status_table[s->mb_index2xy[start_i - 1]];
prev_status &= ~ VP_START;
- if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END))
- s->error_count = INT_MAX;
+ if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) {
+ s->error_occurred = 1;
+ avpriv_atomic_int_set(&s->error_count, INT_MAX);
+ }
}
}
void ff_er_frame_end(ERContext *s)
{
- int *linesize = s->cur_pic.f->linesize;
+ int *linesize = NULL;
int i, mb_x, mb_y, error, error_type, dc_error, mv_error, ac_error;
int distance;
int threshold_part[4] = { 100, 100, 100 };
int threshold = 50;
int is_intra_likely;
+ int size = s->b8_stride * 2 * s->mb_height;
/* We do not support ER of field pictures yet,
* though it should not crash if enabled. */
if (!s->avctx->error_concealment || s->error_count == 0 ||
- s->avctx->hwaccel ||
- !s->cur_pic.f ||
- s->cur_pic.field_picture ||
+ s->avctx->lowres ||
+ !er_supported(s) ||
s->error_count == 3 * s->mb_width *
(s->avctx->skip_top + s->avctx->skip_bottom)) {
return;
- };
+ }
+ linesize = s->cur_pic.f->linesize;
+ for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
+ int status = s->error_status_table[mb_x + (s->mb_height - 1) * s->mb_stride];
+ if (status != 0x7F)
+ break;
+ }
- if (!s->cur_pic.motion_val[0] || !s->cur_pic.ref_index[0]) {
- av_log(s->avctx, AV_LOG_ERROR, "MVs not available, ER not possible.\n");
+ if ( mb_x == s->mb_width
+ && s->avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO
+ && (s->avctx->height&16)
+ && s->error_count == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom + 1)
+ ) {
+ av_log(s->avctx, AV_LOG_DEBUG, "ignoring last missing slice\n");
return;
}
+ if (s->last_pic.f) {
+ if (s->last_pic.f->width != s->cur_pic.f->width ||
+ s->last_pic.f->height != s->cur_pic.f->height ||
+ s->last_pic.f->format != s->cur_pic.f->format) {
+ av_log(s->avctx, AV_LOG_WARNING, "Cannot use previous picture in error concealment\n");
+ memset(&s->last_pic, 0, sizeof(s->last_pic));
+ }
+ }
+ if (s->next_pic.f) {
+ if (s->next_pic.f->width != s->cur_pic.f->width ||
+ s->next_pic.f->height != s->cur_pic.f->height ||
+ s->next_pic.f->format != s->cur_pic.f->format) {
+ av_log(s->avctx, AV_LOG_WARNING, "Cannot use next picture in error concealment\n");
+ memset(&s->next_pic, 0, sizeof(s->next_pic));
+ }
+ }
+
+ if (!s->cur_pic.motion_val[0] || !s->cur_pic.ref_index[0]) {
+ av_log(s->avctx, AV_LOG_ERROR, "Warning MVs not available\n");
+
+ for (i = 0; i < 2; i++) {
+ s->ref_index_buf[i] = av_buffer_allocz(s->mb_stride * s->mb_height * 4 * sizeof(uint8_t));
+ s->motion_val_buf[i] = av_buffer_allocz((size + 4) * 2 * sizeof(uint16_t));
+ if (!s->ref_index_buf[i] || !s->motion_val_buf[i])
+ break;
+ s->cur_pic.ref_index[i] = s->ref_index_buf[i]->data;
+ s->cur_pic.motion_val[i] = (int16_t (*)[2])s->motion_val_buf[i]->data + 4;
+ }
+ if (i < 2) {
+ for (i = 0; i < 2; i++) {
+ av_buffer_unref(&s->ref_index_buf[i]);
+ av_buffer_unref(&s->motion_val_buf[i]);
+ s->cur_pic.ref_index[i] = NULL;
+ s->cur_pic.motion_val[i] = NULL;
+ }
+ return;
+ }
+ }
+
if (s->avctx->debug & FF_DEBUG_ER) {
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
@@ -857,6 +947,7 @@ void ff_er_frame_end(ERContext *s)
}
}
+#if 1
/* handle overlapping slices */
for (error_type = 1; error_type <= 3; error_type++) {
int end_ok = 0;
@@ -877,7 +968,8 @@ void ff_er_frame_end(ERContext *s)
end_ok = 0;
}
}
-
+#endif
+#if 1
/* handle slices with partitions of different length */
if (s->partitioned_frame) {
int end_ok = 0;
@@ -900,7 +992,7 @@ void ff_er_frame_end(ERContext *s)
end_ok = 0;
}
}
-
+#endif
/* handle missing slices */
if (s->avctx->err_recognition & AV_EF_EXPLODE) {
int end_ok = 1;
@@ -927,6 +1019,7 @@ void ff_er_frame_end(ERContext *s)
}
}
+#if 1
/* backward mark errors */
distance = 9999999;
for (error_type = 1; error_type <= 3; error_type++) {
@@ -934,7 +1027,7 @@ void ff_er_frame_end(ERContext *s)
const int mb_xy = s->mb_index2xy[i];
int error = s->error_status_table[mb_xy];
- if (s->mbskip_table && !s->mbskip_table[mb_xy]) // FIXME partition specific
+ if (!s->mbskip_table || !s->mbskip_table[mb_xy]) // FIXME partition specific
distance++;
if (error & (1 << error_type))
distance = 0;
@@ -951,6 +1044,7 @@ void ff_er_frame_end(ERContext *s)
distance = 9999999;
}
}
+#endif
/* forward mark errors */
error = 0;
@@ -965,22 +1059,23 @@ void ff_er_frame_end(ERContext *s)
s->error_status_table[mb_xy] |= error;
}
}
-
+#if 1
/* handle not partitioned case */
if (!s->partitioned_frame) {
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
- error = s->error_status_table[mb_xy];
+ int error = s->error_status_table[mb_xy];
if (error & ER_MB_ERROR)
error |= ER_MB_ERROR;
s->error_status_table[mb_xy] = error;
}
}
+#endif
dc_error = ac_error = mv_error = 0;
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
- error = s->error_status_table[mb_xy];
+ int error = s->error_status_table[mb_xy];
if (error & ER_DC_ERROR)
dc_error++;
if (error & ER_AC_ERROR)
@@ -988,15 +1083,15 @@ void ff_er_frame_end(ERContext *s)
if (error & ER_MV_ERROR)
mv_error++;
}
- av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors\n",
- dc_error, ac_error, mv_error);
+ av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors in %c frame\n",
+ dc_error, ac_error, mv_error, av_get_picture_type_char(s->cur_pic.f->pict_type));
is_intra_likely = is_intra_more_likely(s);
/* set unknown mb-type to most likely */
for (i = 0; i < s->mb_num; i++) {
const int mb_xy = s->mb_index2xy[i];
- error = s->error_status_table[mb_xy];
+ int error = s->error_status_table[mb_xy];
if (!((error & ER_DC_ERROR) && (error & ER_MV_ERROR)))
continue;
@@ -1024,7 +1119,7 @@ void ff_er_frame_end(ERContext *s)
const int mv_dir = dir ? MV_DIR_BACKWARD : MV_DIR_FORWARD;
int mv_type;
- error = s->error_status_table[mb_xy];
+ int error = s->error_status_table[mb_xy];
if (IS_INTRA(mb_type))
continue; // intra
@@ -1061,7 +1156,7 @@ void ff_er_frame_end(ERContext *s)
const int mb_type = s->cur_pic.mb_type[mb_xy];
int mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD;
- error = s->error_status_table[mb_xy];
+ int error = s->error_status_table[mb_xy];
if (IS_INTRA(mb_type))
continue;
@@ -1079,6 +1174,7 @@ void ff_er_frame_end(ERContext *s)
int time_pp = s->pp_time;
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);
s->mv[0][0][0] = s->next_pic.motion_val[0][xy][0] * time_pb / time_pp;
@@ -1099,13 +1195,9 @@ void ff_er_frame_end(ERContext *s)
} else
guess_mv(s);
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- /* the filters below are not XvMC compatible, skip them */
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
+ /* the filters below manipulate raw image, skip them */
+ if (CONFIG_XVMC && s->avctx->hwaccel && s->avctx->hwaccel->decode_mb)
goto ec_clean;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
/* fill DC for inter blocks */
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
@@ -1115,7 +1207,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
const int mb_xy = mb_x + mb_y * s->mb_stride;
const int mb_type = s->cur_pic.mb_type[mb_xy];
- error = s->error_status_table[mb_xy];
+ // error = s->error_status_table[mb_xy];
if (IS_INTRA(mb_type) && s->partitioned_frame)
continue;
@@ -1138,6 +1230,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
dc_ptr[(n & 1) + (n >> 1) * s->b8_stride] = (dc + 4) >> 3;
}
+ if (!s->cur_pic.f->data[2])
+ continue;
+
dcu = dcv = 0;
for (y = 0; y < 8; y++) {
int x;
@@ -1150,15 +1245,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
s->dc_val[2][mb_x + mb_y * s->mb_stride] = (dcv + 4) >> 3;
}
}
-
+#if 1
/* guess DC for damaged blocks */
- guess_dc(s, s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride, 1);
- guess_dc(s, s->dc_val[1], s->mb_width, s->mb_height, s->mb_stride, 0);
- guess_dc(s, s->dc_val[2], s->mb_width, s->mb_height, s->mb_stride, 0);
+ guess_dc(s, s->dc_val[0], s->mb_width*2, s->mb_height*2, s->b8_stride, 1);
+ guess_dc(s, s->dc_val[1], s->mb_width , s->mb_height , s->mb_stride, 0);
+ guess_dc(s, s->dc_val[2], s->mb_width , s->mb_height , s->mb_stride, 0);
+#endif
/* filter luma DC */
filter181(s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride);
+#if 1
/* render DC only intra */
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
@@ -1166,7 +1263,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
const int mb_xy = mb_x + mb_y * s->mb_stride;
const int mb_type = s->cur_pic.mb_type[mb_xy];
- error = s->error_status_table[mb_xy];
+ int error = s->error_status_table[mb_xy];
if (IS_INTER(mb_type))
continue;
@@ -1176,27 +1273,33 @@ FF_ENABLE_DEPRECATION_WARNINGS
dest_y = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0];
dest_cb = s->cur_pic.f->data[1] + mb_x * 8 + mb_y * 8 * linesize[1];
dest_cr = s->cur_pic.f->data[2] + mb_x * 8 + mb_y * 8 * linesize[2];
+ if (!s->cur_pic.f->data[2])
+ dest_cb = dest_cr = NULL;
put_dc(s, dest_y, dest_cb, dest_cr, mb_x, mb_y);
}
}
+#endif
if (s->avctx->error_concealment & FF_EC_DEBLOCK) {
/* filter horizontal block boundaries */
h_block_filter(s, s->cur_pic.f->data[0], s->mb_width * 2,
s->mb_height * 2, linesize[0], 1);
- h_block_filter(s, s->cur_pic.f->data[1], s->mb_width,
- s->mb_height, linesize[1], 0);
- h_block_filter(s, s->cur_pic.f->data[2], s->mb_width,
- s->mb_height, linesize[2], 0);
/* filter vertical block boundaries */
v_block_filter(s, s->cur_pic.f->data[0], s->mb_width * 2,
s->mb_height * 2, linesize[0], 1);
- v_block_filter(s, s->cur_pic.f->data[1], s->mb_width,
- s->mb_height, linesize[1], 0);
- v_block_filter(s, s->cur_pic.f->data[2], s->mb_width,
- s->mb_height, linesize[2], 0);
+
+ if (s->cur_pic.f->data[2]) {
+ h_block_filter(s, s->cur_pic.f->data[1], s->mb_width,
+ s->mb_height, linesize[1], 0);
+ h_block_filter(s, s->cur_pic.f->data[2], s->mb_width,
+ s->mb_height, linesize[2], 0);
+ v_block_filter(s, s->cur_pic.f->data[1], s->mb_width,
+ s->mb_height, linesize[1], 0);
+ v_block_filter(s, s->cur_pic.f->data[2], s->mb_width,
+ s->mb_height, linesize[2], 0);
+ }
}
ec_clean:
@@ -1213,6 +1316,13 @@ ec_clean:
s->mbintra_table[mb_xy] = 1;
}
+ for (i = 0; i < 2; i++) {
+ av_buffer_unref(&s->ref_index_buf[i]);
+ av_buffer_unref(&s->motion_val_buf[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 611b529311..1f52f200f2 100644
--- a/libavcodec/error_resilience.h
+++ b/libavcodec/error_resilience.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,7 +42,7 @@ typedef struct ERPicture {
AVFrame *f;
ThreadFrame *tf;
- // it's the caller responsability to allocate these buffers
+ // it's the caller's responsibility to allocate these buffers
int16_t (*motion_val[2])[2];
int8_t *ref_index[2];
@@ -61,7 +61,8 @@ typedef struct ERContext {
int mb_stride;
int b8_stride;
- int error_count, error_occurred;
+ volatile int error_count;
+ int error_occurred;
uint8_t *error_status_table;
uint8_t *er_temp_buffer;
int16_t *dc_val[3];
@@ -73,6 +74,9 @@ typedef struct ERContext {
ERPicture last_pic;
ERPicture next_pic;
+ AVBufferRef *ref_index_buf[2];
+ AVBufferRef *motion_val_buf[2];
+
uint16_t pp_time;
uint16_t pb_time;
int quarter_sample;
diff --git a/libavcodec/escape124.c b/libavcodec/escape124.c
index 6c4654cd35..28167419bd 100644
--- a/libavcodec/escape124.c
+++ b/libavcodec/escape124.c
@@ -2,20 +2,20 @@
* Escape 124 Video Decoder
* Copyright (C) 2008 Eli Friedman (eli.friedman@gmail.com)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,10 +49,6 @@ typedef struct Escape124Context {
CodeBook codebooks[3];
} Escape124Context;
-static int can_safely_read(GetBitContext* gb, int bits) {
- return get_bits_left(gb) >= bits;
-}
-
/**
* Initialize the decoder
* @param avctx decoder context
@@ -80,7 +76,7 @@ static av_cold int escape124_decode_close(AVCodecContext *avctx)
Escape124Context *s = avctx->priv_data;
for (i = 0; i < 3; i++)
- av_free(s->codebooks[i].blocks);
+ av_freep(&s->codebooks[i].blocks);
av_frame_free(&s->frame);
@@ -93,7 +89,7 @@ static CodeBook unpack_codebook(GetBitContext* gb, unsigned depth,
unsigned i, j;
CodeBook cb = { 0 };
- if (!can_safely_read(gb, size * 34))
+ if (size >= INT_MAX / 34 || get_bits_left(gb) < size * 34)
return cb;
if (size >= INT_MAX / sizeof(MacroBlock))
@@ -124,7 +120,7 @@ static unsigned decode_skip_count(GetBitContext* gb)
unsigned value;
// This function reads a maximum of 23 bits,
// which is within the padding space
- if (!can_safely_read(gb, 1))
+ if (get_bits_left(gb) < 1)
return -1;
value = get_bits1(gb);
if (!value)
@@ -204,7 +200,6 @@ static int escape124_decode_frame(AVCodecContext *avctx,
void *data, int *got_frame,
AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
Escape124Context *s = avctx->priv_data;
AVFrame *frame = data;
@@ -219,13 +214,15 @@ static int escape124_decode_frame(AVCodecContext *avctx,
uint16_t* old_frame_data, *new_frame_data;
unsigned old_stride, new_stride;
+
int ret;
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
+ return ret;
// This call also guards the potential depth reads for the
// codebook unpacking.
- if (!can_safely_read(&gb, 64))
+ if (get_bits_left(&gb) < 64)
return -1;
frame_flags = get_bits_long(&gb, 32);
@@ -237,7 +234,7 @@ static int escape124_decode_frame(AVCodecContext *avctx,
if (!s->frame->data[0])
return AVERROR_INVALIDDATA;
- av_log(NULL, AV_LOG_DEBUG, "Skipping frame\n");
+ av_log(avctx, AV_LOG_DEBUG, "Skipping frame\n");
*got_frame = 1;
if ((ret = av_frame_ref(frame, s->frame)) < 0)
@@ -267,17 +264,15 @@ static int escape124_decode_frame(AVCodecContext *avctx,
cb_size = s->num_superblocks << cb_depth;
}
}
- av_free(s->codebooks[i].blocks);
+ av_freep(&s->codebooks[i].blocks);
s->codebooks[i] = unpack_codebook(&gb, cb_depth, cb_size);
if (!s->codebooks[i].blocks)
return -1;
}
}
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
new_frame_data = (uint16_t*)frame->data[0];
new_stride = frame->linesize[0] / 2;
@@ -303,7 +298,7 @@ static int escape124_decode_frame(AVCodecContext *avctx,
copy_superblock(sb.pixels, 8,
old_frame_data, old_stride);
- while (can_safely_read(&gb, 1) && !get_bits1(&gb)) {
+ while (get_bits_left(&gb) >= 1 && !get_bits1(&gb)) {
unsigned mask;
mb = decode_macroblock(s, &gb, &cb_index, superblock_index);
mask = get_bits(&gb, 16);
@@ -315,7 +310,7 @@ static int escape124_decode_frame(AVCodecContext *avctx,
}
}
- if (can_safely_read(&gb, 1) && !get_bits1(&gb)) {
+ if (!get_bits1(&gb)) {
unsigned inv_mask = get_bits(&gb, 4);
for (i = 0; i < 4; i++) {
if (inv_mask & (1 << i)) {
@@ -327,15 +322,13 @@ static int escape124_decode_frame(AVCodecContext *avctx,
for (i = 0; i < 16; i++) {
if (multi_mask & mask_matrix[i]) {
- if (!can_safely_read(&gb, 1))
- break;
mb = decode_macroblock(s, &gb, &cb_index,
superblock_index);
insert_mb_into_sb(&sb, mb, i);
}
}
} else if (frame_flags & (1 << 16)) {
- while (can_safely_read(&gb, 1) && !get_bits1(&gb)) {
+ while (get_bits_left(&gb) >= 1 && !get_bits1(&gb)) {
mb = decode_macroblock(s, &gb, &cb_index, superblock_index);
insert_mb_into_sb(&sb, mb, get_bits(&gb, 4));
}
@@ -357,7 +350,7 @@ static int escape124_decode_frame(AVCodecContext *avctx,
skip--;
}
- av_log(NULL, AV_LOG_DEBUG,
+ av_log(avctx, AV_LOG_DEBUG,
"Escape sizes: %i, %i, %i\n",
frame_size, buf_size, get_bits_count(&gb) / 8);
diff --git a/libavcodec/escape130.c b/libavcodec/escape130.c
index 22833d638b..129011b960 100644
--- a/libavcodec/escape130.c
+++ b/libavcodec/escape130.c
@@ -2,20 +2,20 @@
* Escape 130 video decoder
* Copyright (C) 2008 Eli Friedman (eli.friedman <at> gmail.com)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -105,7 +105,7 @@ static const int8_t chroma_adjust[2][8] = {
{ 0, 1, 1, 1, 0, -1, -1, -1 }
};
-const uint8_t chroma_vals[] = {
+static const uint8_t chroma_vals[] = {
20, 28, 36, 44, 52, 60, 68, 76,
84, 92, 100, 106, 112, 116, 120, 124,
128, 132, 136, 140, 144, 150, 156, 164,
@@ -166,6 +166,9 @@ static int decode_skip_count(GetBitContext* gb)
{
int value;
+ if (get_bits_left(gb) < 1+3)
+ return -1;
+
value = get_bits1(gb);
if (value)
return 0;
@@ -188,7 +191,6 @@ static int decode_skip_count(GetBitContext* gb)
static int escape130_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
Escape130Context *s = avctx->priv_data;
AVFrame *pic = data;
@@ -215,7 +217,9 @@ static int escape130_decode_frame(AVCodecContext *avctx, void *data,
if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
return ret;
- init_get_bits(&gb, buf + 16, (buf_size - 16) * 8);
+ if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
+ return ret;
+ skip_bits_long(&gb, 16 * 8);
new_y = s->new_y;
new_cb = s->new_u;
diff --git a/libavcodec/evrcdata.h b/libavcodec/evrcdata.h
new file mode 100644
index 0000000000..8cfc2028dd
--- /dev/null
+++ b/libavcodec/evrcdata.h
@@ -0,0 +1,1499 @@
+/*
+ * Enhanced Variable Rate Codec, Service Option 3 decoder
+ * Copyright (c) 2013 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 AVCODEC_EVRCDATA_H
+#define AVCODEC_EVRCDATA_H
+
+/**
+ * @file
+ * Data tables for the EVRC decoder
+ * @author Paul B Mahol
+ */
+
+#include "libavutil/common.h"
+
+/**
+ * Rate 1/8 frame energy quantization
+ *
+ * TIA/IS-127 table 8-18
+ */
+static const float evrc_energy_quant[][3] = {
+{-0.2464E-01,-0.4005E-02,-0.1107E+00 }, { 0.8734E+00, 0.1004E+01, 0.9930E+00 },
+{ 0.4222E+00, 0.3894E+00, 0.5020E+00 }, { 0.1450E+01, 0.1328E+01, 0.1278E+01 },
+{ 0.1957E+00, 0.2169E+00, 0.2735E+00 }, { 0.1142E+01, 0.1240E+01, 0.1157E+01 },
+{ 0.7881E+00, 0.6778E+00, 0.4185E+00 }, { 0.1504E+01, 0.1468E+01, 0.1534E+01 },
+{ 0.3173E+00, 0.2693E+00,-0.9526E-01 }, { 0.1141E+01, 0.1154E+01, 0.1044E+01 },
+{ 0.5147E+00, 0.5784E+00, 0.8802E+00 }, { 0.1502E+01, 0.1407E+01, 0.1409E+01 },
+{ 0.3163E+00, 0.3592E+00, 0.2830E+00 }, { 0.1217E+01, 0.1213E+01, 0.1216E+01 },
+{ 0.1023E+01, 0.1139E+01,-0.9526E-01 }, { 0.1619E+01, 0.1655E+01, 0.1642E+01 },
+{ 0.1437E+00, 0.1505E+00, 0.6838E-01 }, { 0.9794E+00, 0.1021E+01, 0.1117E+01 },
+{ 0.4701E+00, 0.6426E+00, 0.5519E+00 }, { 0.1366E+01, 0.1397E+01, 0.1406E+01 },
+{ 0.2918E+00, 0.3022E+00, 0.2420E+00 }, { 0.1309E+01, 0.1241E+01, 0.1220E+01 },
+{ 0.7989E+00, 0.7654E+00, 0.7391E+00 }, { 0.1612E+01, 0.1502E+01, 0.1447E+01 },
+{ 0.2594E+00, 0.1948E+00, 0.2555E+00 }, { 0.1091E+01, 0.1150E+01, 0.1272E+01 },
+{ 0.3423E+00, 0.4150E+00, 0.1294E+01 }, { 0.1729E+01, 0.1377E+01, 0.1065E+01 },
+{ 0.4103E+00, 0.3287E+00, 0.3228E+00 }, { 0.1144E+01, 0.1281E+01, 0.1416E+01 },
+{ 0.1047E+01, 0.1117E+01, 0.6188E+00 }, { 0.1914E+01, 0.1777E+01, 0.1516E+01 },
+{-0.2117E-01, 0.2159E+00, 0.2351E+00 }, { 0.1093E+01, 0.1088E+01, 0.1026E+01 },
+{ 0.5567E+00, 0.5092E+00, 0.4654E+00 }, { 0.1510E+01, 0.1449E+01, 0.1201E+01 },
+{ 0.2362E+00, 0.3426E+00, 0.2549E+00 }, { 0.1340E+01, 0.1225E+01, 0.1117E+01 },
+{ 0.1203E+01, 0.3819E+00, 0.2269E+00 }, { 0.1373E+01, 0.1404E+01, 0.1830E+01 },
+{ 0.2570E+00, 0.2668E+00, 0.1636E+00 }, { 0.1219E+01, 0.1098E+01, 0.1122E+01 },
+{ 0.6985E+00, 0.8456E+00, 0.1069E+01 }, { 0.1550E+01, 0.1501E+01, 0.1388E+01 },
+{ 0.2870E+00, 0.3060E+00, 0.3599E+00 }, { 0.1178E+01, 0.1345E+01, 0.1302E+01 },
+{ 0.1270E+01, 0.1215E+01, 0.1812E+00 }, { 0.1725E+01, 0.1777E+01, 0.1693E+01 },
+{ 0.2074E+00, 0.2104E+00, 0.1539E+00 }, { 0.1105E+01, 0.1034E+01, 0.1104E+01 },
+{ 0.6683E+00, 0.6646E+00, 0.6639E+00 }, { 0.1403E+01, 0.1462E+01, 0.1435E+01 },
+{ 0.3389E+00, 0.3754E+00, 0.2150E+00 }, { 0.1288E+01, 0.1325E+01, 0.1257E+01 },
+{ 0.8933E+00, 0.8253E+00, 0.8133E+00 }, { 0.1555E+01, 0.1579E+01, 0.1565E+01 },
+{ 0.3264E+00, 0.2434E+00, 0.2852E+00 }, { 0.1242E+01, 0.1180E+01, 0.1202E+01 },
+{ 0.1314E+00, 0.1698E+00, 0.1646E+01 }, { 0.1797E+01, 0.1597E+01, 0.1241E+01 },
+{ 0.4721E+00, 0.5346E+00, 0.3066E+00 }, { 0.1274E+01, 0.1401E+01, 0.1351E+01 },
+{ 0.1455E+01, 0.1386E+01, 0.6430E+00 }, { 0.1828E+01, 0.1867E+01, 0.1825E+01 },
+{-0.3265E+00,-0.2956E+00,-0.2462E+00 }, { 0.1035E+01, 0.1020E+01, 0.1003E+01 },
+{ 0.3702E+00, 0.4307E+00, 0.7072E+00 }, { 0.1424E+01, 0.1345E+01, 0.1352E+01 },
+{ 0.2267E+00, 0.2680E+00, 0.3037E+00 }, { 0.1235E+01, 0.1249E+01, 0.1146E+01 },
+{ 0.9944E+00, 0.6485E+00, 0.5248E+00 }, { 0.1539E+01, 0.1492E+01, 0.1612E+01 },
+{ 0.3815E+00, 0.3360E+00,-0.9526E-01 }, { 0.1163E+01, 0.1144E+01, 0.1117E+01 },
+{ 0.6734E+00, 0.7656E+00, 0.1014E+01 }, { 0.1568E+01, 0.1438E+01, 0.1455E+01 },
+{ 0.3409E+00, 0.3317E+00, 0.3856E+00 }, { 0.1180E+01, 0.1284E+01, 0.1284E+01 },
+{ 0.1244E+01, 0.1214E+01,-0.9526E-01 }, { 0.1753E+01, 0.1598E+01, 0.1744E+01 },
+{ 0.1548E+00, 0.1388E+00, 0.2020E+00 }, { 0.1027E+01, 0.1133E+01, 0.1093E+01 },
+{ 0.3906E+00, 0.7505E+00, 0.5705E+00 }, { 0.1420E+01, 0.1357E+01, 0.1543E+01 },
+{ 0.3252E+00, 0.3136E+00, 0.2804E+00 }, { 0.1351E+01, 0.1309E+01, 0.1224E+01 },
+{ 0.8781E+00, 0.8095E+00, 0.7109E+00 }, { 0.1614E+01, 0.1580E+01, 0.1433E+01 },
+{ 0.3222E+00, 0.2298E+00, 0.2157E+00 }, { 0.1216E+01, 0.1077E+01, 0.1247E+01 },
+{ 0.1363E+01, 0.1280E+01, 0.1317E+01 }, { 0.1751E+01, 0.1457E+01, 0.1182E+01 },
+{ 0.4428E+00, 0.4082E+00, 0.3181E+00 }, { 0.1157E+01, 0.1227E+01, 0.1604E+01 },
+{ 0.1286E+01, 0.1268E+01, 0.8167E+00 }, { 0.1994E+01, 0.2018E+01, 0.1307E+01 },
+{ 0.2671E-01, 0.2594E+00, 0.3397E+00 }, { 0.1164E+01, 0.1080E+01, 0.9321E+00 },
+{ 0.5998E+00, 0.6076E+00, 0.5081E+00 }, { 0.1442E+01, 0.1442E+01, 0.1375E+01 },
+{ 0.2390E+00, 0.3554E+00, 0.3426E+00 }, { 0.1287E+01, 0.1307E+01, 0.1144E+01 },
+{ 0.1200E+01, 0.7495E+00, 0.3967E+00 }, { 0.1561E+01, 0.1517E+01, 0.1898E+01 },
+{ 0.3598E+00, 0.3463E+00, 0.1200E+00 }, { 0.1298E+01, 0.1125E+01, 0.1062E+01 },
+{ 0.7577E+00, 0.1013E+01, 0.1194E+01 }, { 0.1537E+01, 0.1513E+01, 0.1464E+01 },
+{ 0.4041E+00, 0.4038E+00, 0.3897E+00 }, { 0.1293E+01, 0.1219E+01, 0.1378E+01 },
+{ 0.1250E+01, 0.1391E+01, 0.2451E+00 }, { 0.1558E+01, 0.1764E+01, 0.1728E+01 },
+{ 0.2700E+00, 0.1894E+00, 0.1924E+00 }, { 0.1111E+01, 0.1112E+01, 0.1173E+01 },
+{ 0.7579E+00, 0.8342E+00, 0.4781E+00 }, { 0.1464E+01, 0.1477E+01, 0.1469E+01 },
+{ 0.4001E+00, 0.3104E+00, 0.2217E+00 }, { 0.1346E+01, 0.1421E+01, 0.1312E+01 },
+{ 0.1071E+01, 0.8967E+00, 0.7511E+00 }, { 0.1616E+01, 0.1551E+01, 0.1574E+01 },
+{ 0.3329E+00, 0.2785E+00, 0.3140E+00 }, { 0.1281E+01, 0.1209E+01, 0.1239E+01 },
+{ 0.2805E+00, 0.2687E+00, 0.1646E+01 }, { 0.1814E+01, 0.1514E+01, 0.1510E+01 },
+{ 0.6231E+00, 0.4200E+00, 0.3701E+00 }, { 0.1255E+01, 0.1429E+01, 0.1454E+01 },
+{ 0.1642E+01, 0.1581E+01, 0.7112E+00 }, { 0.1844E+01, 0.1963E+01, 0.1895E+01 },
+{-0.4208E-01,-0.1491E+00,-0.7639E-01 }, { 0.1046E+01, 0.9598E+00, 0.9176E+00 },
+{ 0.4478E+00, 0.4605E+00, 0.5111E+00 }, { 0.1521E+01, 0.1292E+01, 0.1342E+01 },
+{ 0.2220E+00, 0.2549E+00, 0.2510E+00 }, { 0.1186E+01, 0.1254E+01, 0.1171E+01 },
+{ 0.8999E+00, 0.4960E+00, 0.4943E+00 }, { 0.1423E+01, 0.1484E+01, 0.1620E+01 },
+{ 0.2796E+00, 0.2778E+00,-0.2820E+00 }, { 0.1170E+01, 0.1181E+01, 0.1076E+01 },
+{ 0.4068E+00, 0.8541E+00, 0.9352E+00 }, { 0.1584E+01, 0.1416E+01, 0.1387E+01 },
+{ 0.3325E+00, 0.3655E+00, 0.3340E+00 }, { 0.1224E+01, 0.1257E+01, 0.1245E+01 },
+{ 0.1061E+01, 0.1138E+01,-0.9526E-01 }, { 0.1681E+01, 0.1704E+01, 0.1673E+01 },
+{ 0.1932E+00, 0.1489E+00, 0.1258E+00 }, { 0.1023E+01, 0.1088E+01, 0.1145E+01 },
+{ 0.5190E+00, 0.6873E+00, 0.5172E+00 }, { 0.1380E+01, 0.1405E+01, 0.1474E+01 },
+{ 0.3393E+00, 0.3100E+00, 0.2231E+00 }, { 0.1354E+01, 0.1249E+01, 0.1270E+01 },
+{ 0.7363E+00, 0.8508E+00, 0.8247E+00 }, { 0.1612E+01, 0.1537E+01, 0.1509E+01 },
+{ 0.2952E+00, 0.2053E+00, 0.2590E+00 }, { 0.1138E+01, 0.1219E+01, 0.1262E+01 },
+{ 0.1345E+01, 0.1289E+01, 0.1338E+01 }, { 0.1437E+01, 0.1360E+01, 0.1442E+01 },
+{ 0.4826E+00, 0.3298E+00, 0.3842E+00 }, { 0.1219E+01, 0.1311E+01, 0.1413E+01 },
+{ 0.1212E+01, 0.1186E+01, 0.6357E+00 }, { 0.1873E+01, 0.1939E+01, 0.1674E+01 },
+{ 0.1260E+01, 0.1306E+01, 0.1368E+01 }, { 0.1146E+01, 0.1077E+01, 0.1025E+01 },
+{ 0.6029E+00, 0.5039E+00, 0.5781E+00 }, { 0.1514E+01, 0.1420E+01, 0.1324E+01 },
+{ 0.2652E+00, 0.3192E+00, 0.3042E+00 }, { 0.1368E+01, 0.1198E+01, 0.1200E+01 },
+{ 0.1234E+01, 0.4910E+00, 0.3464E-01 }, { 0.1347E+01, 0.1560E+01, 0.1861E+01 },
+{ 0.2766E+00, 0.2887E+00, 0.2029E+00 }, { 0.1257E+01, 0.1105E+01, 0.1145E+01 },
+{ 0.1351E+01, 0.1353E+01, 0.1406E+01 }, { 0.1506E+01, 0.1580E+01, 0.1362E+01 },
+{ 0.2794E+00, 0.3868E+00, 0.4277E+00 }, { 0.1234E+01, 0.1334E+01, 0.1336E+01 },
+{ 0.1280E+01, 0.1252E+01, 0.1805E+00 }, { 0.1387E+01, 0.1396E+01, 0.1434E+01 },
+{ 0.2902E+00, 0.1170E+00, 0.1698E+00 }, { 0.1134E+01, 0.1077E+01, 0.1117E+01 },
+{ 0.6986E+00, 0.7177E+00, 0.7366E+00 }, { 0.1370E+01, 0.1491E+01, 0.1495E+01 },
+{ 0.4031E+00, 0.5144E+00, 0.1751E+00 }, { 0.1333E+01, 0.1377E+01, 0.1257E+01 },
+{ 0.9212E+00, 0.8934E+00, 0.8897E+00 }, { 0.1589E+01, 0.1614E+01, 0.1523E+01 },
+{ 0.3152E+00, 0.2164E+00, 0.3230E+00 }, { 0.1300E+01, 0.1145E+01, 0.1212E+01 },
+{ 0.1269E+01, 0.1245E+01, 0.1497E+01 }, { 0.1763E+01, 0.1716E+01, 0.1311E+01 },
+{ 0.4702E+00, 0.5422E+00, 0.4306E+00 }, { 0.1342E+01, 0.1433E+01, 0.1423E+01 },
+{ 0.1472E+01, 0.1404E+01, 0.8371E+00 }, { 0.1936E+01, 0.1883E+01, 0.1838E+01 },
+{ 0.1266E+01, 0.1295E+01, 0.1302E+01 }, { 0.1074E+01, 0.1002E+01, 0.1023E+01 },
+{ 0.5206E+00, 0.4045E+00, 0.6549E+00 }, { 0.1457E+01, 0.1378E+01, 0.1363E+01 },
+{ 0.2715E+00, 0.2629E+00, 0.2841E+00 }, { 0.1264E+01, 0.1271E+01, 0.1175E+01 },
+{ 0.1337E+01, 0.1305E+01, 0.1306E+01 }, { 0.1555E+01, 0.1571E+01, 0.1657E+01 },
+{ 0.3341E+00, 0.4147E+00,-0.3648E+00 }, { 0.1188E+01, 0.1185E+01, 0.1161E+01 },
+{ 0.6198E+00, 0.7208E+00, 0.1157E+01 }, { 0.1582E+01, 0.1465E+01, 0.1513E+01 },
+{ 0.3839E+00, 0.3651E+00, 0.3814E+00 }, { 0.1214E+01, 0.1256E+01, 0.1292E+01 },
+{ 0.1361E+01, 0.1363E+01, 0.1312E+01 }, { 0.1793E+01, 0.1693E+01, 0.1669E+01 },
+{ 0.1889E+00, 0.1275E+00, 0.2534E+00 }, { 0.1066E+01, 0.1174E+01, 0.1133E+01 },
+{ 0.4999E+00, 0.8207E+00, 0.5813E+00 }, { 0.1478E+01, 0.1416E+01, 0.1497E+01 },
+{ 0.3814E+00, 0.3138E+00, 0.2889E+00 }, { 0.1396E+01, 0.1265E+01, 0.1233E+01 },
+{ 0.9458E+00, 0.9161E+00, 0.5875E+00 }, { 0.1672E+01, 0.1632E+01, 0.1553E+01 },
+{ 0.3505E+00, 0.2525E+00, 0.2364E+00 }, { 0.1211E+01, 0.1138E+01, 0.1235E+01 },
+{ 0.1391E+01, 0.1231E+01, 0.1355E+01 }, { 0.1783E+01, 0.1510E+01, 0.1199E+01 },
+{ 0.4227E+00, 0.4548E+00, 0.3671E+00 }, { 0.1281E+01, 0.1254E+01, 0.1661E+01 },
+{ 0.1338E+01, 0.1379E+01, 0.9531E+00 }, { 0.2148E+01, 0.1965E+01, 0.1584E+01 },
+{ 0.9324E-01, 0.3575E+00, 0.3522E+00 }, { 0.1212E+01, 0.1086E+01, 0.1044E+01 },
+{ 0.6128E+00, 0.6136E+00, 0.6060E+00 }, { 0.1484E+01, 0.1507E+01, 0.1396E+01 },
+{ 0.2820E+00, 0.3848E+00, 0.3156E+00 }, { 0.1368E+01, 0.1287E+01, 0.1128E+01 },
+{ 0.1369E+01, 0.1352E+01, 0.1358E+01 }, { 0.1381E+01, 0.1765E+01, 0.2113E+01 },
+{ 0.1314E+01, 0.1345E+01, 0.1334E+01 }, { 0.1290E+01, 0.1172E+01, 0.1119E+01 },
+{ 0.1304E+01, 0.1377E+01, 0.1427E+01 }, { 0.1490E+01, 0.1540E+01, 0.1536E+01 },
+{ 0.3994E+00, 0.4402E+00, 0.4173E+00 }, { 0.1323E+01, 0.1307E+01, 0.1392E+01 },
+{ 0.1400E+01, 0.1388E+01, 0.1369E+01 }, { 0.1669E+01, 0.1818E+01, 0.1834E+01 },
+{ 0.2742E+00, 0.2235E+00, 0.1986E+00 }, { 0.1137E+01, 0.1139E+01, 0.1201E+01 },
+{ 0.1324E+01, 0.1385E+01, 0.1349E+01 }, { 0.1455E+01, 0.1574E+01, 0.1454E+01 },
+{ 0.5019E+00, 0.3255E+00, 0.2555E+00 }, { 0.1388E+01, 0.1438E+01, 0.1300E+01 },
+{ 0.1394E+01, 0.1349E+01, 0.1411E+01 }, { 0.1639E+01, 0.1580E+01, 0.1681E+01 },
+{ 0.3920E+00, 0.2498E+00, 0.3523E+00 }, { 0.1301E+01, 0.1221E+01, 0.1285E+01 },
+{ 0.1318E+01, 0.1342E+01, 0.1494E+01 }, { 0.1910E+01, 0.1680E+01, 0.1470E+01 },
+{ 0.6082E+00, 0.5270E+00, 0.4173E+00 }, { 0.1255E+01, 0.1477E+01, 0.1503E+01 },
+{ 0.1807E+01, 0.1742E+01, 0.6553E+00 }, { 0.2000E+01, 0.2072E+01, 0.2051E+01 }};
+
+/**
+ * LSP vector quantization tables
+ *
+ * TIA/IS-127 tables 8-1 through 8-9
+ */
+
+static const float evrc_lspq_full_codebook1[64][2] = {
+{1.42016308E-2, 1.93881616E-2}, {2.91667543E-2, 6.51749149E-2},
+{2.06693150E-2, 4.97564934E-2}, {3.94719802E-2, 9.55850929E-2},
+{2.27012448E-2, 3.96625809E-2}, {5.38789518E-2, 6.28347769E-2},
+{2.90525518E-2, 5.73435798E-2}, {4.48280610E-2, 1.15364626E-1},
+{1.94110647E-2, 3.46889682E-2}, {4.37502973E-2, 6.75228462E-2},
+{3.55497338E-2, 4.94086780E-2}, {6.99219853E-2, 8.67279768E-2},
+{2.77880151E-2, 4.65748496E-2}, {5.79111017E-2, 6.74542487E-2},
+{4.74664383E-2, 5.50271496E-2}, {7.88898915E-2, 1.22443043E-1},
+{2.21715886E-2, 3.02628800E-2}, {3.39134485E-2, 7.17703998E-2},
+{3.17989141E-2, 4.98996116E-2}, {6.11555986E-2, 8.73361230E-2},
+{2.67506503E-2, 3.96735854E-2}, {4.44100983E-2, 8.26731324E-2},
+{3.89172547E-2, 5.65788932E-2}, {6.04800619E-2, 1.04536951E-1},
+{2.69156620E-2, 3.57168876E-2}, {4.11117189E-2, 7.33322948E-2},
+{4.12660725E-2, 4.85165231E-2}, {7.18049556E-2, 1.06202349E-1},
+{3.38037871E-2, 4.24300395E-2}, {5.91818243E-2, 7.97467977E-2},
+{4.70107906E-2, 6.28563762E-2}, {9.42011923E-2, 1.30053163E-1},
+{1.94244273E-2, 2.72732340E-2}, {3.70831676E-2, 6.64898157E-2},
+{2.80136354E-2, 5.15984930E-2}, {5.34461029E-2, 9.25904214E-2},
+{2.54959203E-2, 4.32844795E-2}, {5.51860742E-2, 7.36182332E-2},
+{3.39851119E-2, 6.05329126E-2}, {6.18182123E-2, 1.34581268E-1},
+{2.35669166E-2, 3.55242006E-2}, {5.10804243E-2, 6.79562539E-2},
+{3.83464955E-2, 5.23469411E-2}, {7.44275749E-2, 9.66108292E-2},
+{3.18591148E-2, 4.62123118E-2}, {6.18909821E-2, 7.33231753E-2},
+{4.41718437E-2, 5.79240918E-2}, {7.93596208E-2, 1.41177371E-1},
+{2.47412287E-2, 3.23629379E-2}, {3.36563922E-2, 8.04650635E-2},
+{3.37943695E-2, 5.44977151E-2}, {6.53648973E-2, 9.52775925E-2},
+{2.93364152E-2, 4.28411029E-2}, {5.27870469E-2, 8.16159397E-2},
+{4.00724895E-2, 6.18144684E-2}, {6.75848573E-2, 1.17196076E-1},
+{3.03064957E-2, 3.86914052E-2}, {4.83106263E-2, 7.42383003E-2},
+{4.37548272E-2, 5.22842295E-2}, {8.32310021E-2, 1.09881967E-1},
+{3.75600643E-2, 4.53217216E-2}, {6.60113171E-2, 7.97580183E-2},
+{5.03225066E-2, 5.90176322E-2}, {8.77133310E-2, 1.63187444E-1}};
+
+static const float evrc_lspq_full_codebook2[64][2] = {
+{5.21959551E-2, 8.38445649E-2}, {1.05874076E-1, 1.28694162E-1},
+{5.48323877E-2, 1.33842856E-1}, {1.17768474E-1, 1.94037274E-1},
+{5.36086522E-2, 1.11398734E-1}, {1.19989693E-1, 1.47474691E-1},
+{8.00373554E-2, 1.42999724E-1}, {1.64086595E-1, 2.09821835E-1},
+{5.21059223E-2, 9.95229408E-2}, {8.67567956E-2, 1.85966507E-1},
+{7.77341127E-2, 1.31506845E-1}, {1.60545513E-1, 1.81930289E-1},
+{7.42243677E-2, 1.10437103E-1}, {1.18635088E-1, 1.75306752E-1},
+{6.61557764E-2, 1.64441928E-1}, {1.96810856E-1, 2.16682002E-1},
+{6.05317838E-2, 9.45408568E-2}, {1.06271386E-1, 1.48013934E-1},
+{5.87486550E-2, 1.47724584E-1}, {1.34816468E-1, 2.01517954E-1},
+{6.59698322E-2, 1.16447397E-1}, {1.32297173E-1, 1.53267249E-1},
+{9.26660746E-2, 1.46725491E-1}, {1.79285541E-1, 2.19705954E-1},
+{7.06458464E-2, 9.99924466E-2}, {1.06500491E-1, 1.79443434E-1},
+{8.79249722E-2, 1.25287697E-1}, {1.53640196E-1, 1.97852716E-1},
+{8.88430104E-2, 1.12465657E-1}, {1.48286715E-1, 1.67517021E-1},
+{8.16568136E-2, 1.69274017E-1}, {2.07810536E-1, 2.31033549E-1},
+{6.14927970E-2, 8.36263224E-2}, {1.14473253E-1, 1.36779979E-1},
+{6.87129870E-2, 1.38099059E-1}, {1.10511415E-1, 2.15352878E-1},
+{5.55652268E-2, 1.22242786E-1}, {1.20557591E-1, 1.61072448E-1},
+{8.32249671E-2, 1.55475482E-1}, {1.61638483E-1, 2.28268847E-1},
+{6.29152283E-2, 1.06229566E-1}, {8.29186887E-2, 2.06774518E-1},
+{8.84756893E-2, 1.35799959E-1}, {1.69772223E-1, 1.93773940E-1},
+{7.77297840E-2, 1.20287232E-1}, {1.30648017E-1, 1.84331819E-1},
+{6.91939592E-2, 1.84218004E-1}, {2.03904077E-1, 2.49715164E-1},
+{7.07671717E-2, 9.03186128E-2}, {1.08471557E-1, 1.61966518E-1},
+{7.16886371E-2, 1.51093170E-1}, {1.38779536E-1, 2.18801782E-1},
+{6.75907061E-2, 1.26740307E-1}, {1.33412346E-1, 1.68838874E-1},
+{9.61822569E-2, 1.58728704E-1}, {1.86485633E-1, 2.36560926E-1},
+{8.23447108E-2, 1.02126025E-1}, {1.00336641E-1, 1.94918498E-1},
+{9.95981991E-2, 1.36425093E-1}, {1.82448462E-1, 2.03655198E-1},
+{9.78890732E-2, 1.21145472E-1}, {1.45453140E-1, 1.83604524E-1},
+{9.58395451E-2, 1.72194853E-1}, {2.23295853E-1, 2.46418610E-1}};
+
+static const float evrc_lspq_full_codebook3[512][3] = {
+{1.36425778E-1, 1.68651849E-1, 2.04688221E-1},
+{1.85717627E-1, 2.28756160E-1, 2.51958042E-1},
+{1.22760192E-1, 1.85950696E-1, 2.79446691E-1},
+{1.96468458E-1, 2.64484435E-1, 2.89318889E-1},
+{1.25653744E-1, 1.50529265E-1, 2.76144296E-1},
+{1.96301565E-1, 2.41699994E-1, 2.88230687E-1},
+{1.40099391E-1, 2.22365588E-1, 2.74666578E-1},
+{2.59952307E-1, 2.75394946E-1, 3.10975939E-1},
+{1.58452198E-1, 1.88591003E-1, 2.07339197E-1},
+{1.95616230E-1, 2.21379519E-1, 2.87022918E-1},
+{1.69424579E-1, 2.01614648E-1, 2.75669187E-1},
+{2.12393746E-1, 2.64250666E-1, 3.17967504E-1},
+{1.82965085E-1, 1.99547559E-1, 2.29538843E-1},
+{2.15200707E-1, 2.62409419E-1, 2.82432705E-1},
+{1.46404549E-1, 2.36966729E-1, 2.90067106E-1},
+{2.45338634E-1, 3.03358108E-1, 3.42260152E-1},
+{1.37478963E-1, 1.58276558E-1, 2.39217222E-1},
+{2.01999024E-1, 2.20102608E-1, 2.69546896E-1},
+{1.18350029E-1, 2.30206400E-1, 2.83554822E-1},
+{2.25519255E-1, 2.72272140E-1, 3.06072980E-1},
+{1.35661438E-1, 1.91633970E-1, 2.65912026E-1},
+{1.95733085E-1, 2.31926173E-1, 3.14376086E-1},
+{1.67998984E-1, 2.27706313E-1, 2.76947826E-1},
+{2.50170559E-1, 3.01627070E-1, 3.21084231E-1},
+{1.33492306E-1, 2.01223105E-1, 2.33893991E-1},
+{2.06442133E-1, 2.38704175E-1, 2.77560145E-1},
+{1.79048792E-1, 1.95776582E-1, 2.80656606E-1},
+{2.06193641E-1, 2.64055401E-1, 3.33098441E-1},
+{1.75185278E-1, 1.91166341E-1, 2.57540315E-1},
+{2.28398636E-1, 2.45296657E-1, 3.08980793E-1},
+{1.80859819E-1, 2.43579060E-1, 2.96631068E-1},
+{2.76152968E-1, 3.08256060E-1, 3.46822590E-1},
+{1.37115732E-1, 1.80057764E-1, 2.20953465E-1},
+{1.81370094E-1, 2.26770103E-1, 2.70392686E-1},
+{1.25246510E-1, 1.79606944E-1, 3.10376436E-1},
+{1.90708354E-1, 2.87734240E-1, 3.13476235E-1},
+{1.30486086E-1, 1.60435289E-1, 3.00243706E-1},
+{1.97318628E-1, 2.56378502E-1, 2.78474301E-1},
+{1.58597067E-1, 2.37381399E-1, 2.62910336E-1},
+{2.61825919E-1, 2.77717203E-1, 3.31382245E-1},
+{1.64160743E-1, 1.85841531E-1, 2.35615849E-1},
+{2.09486142E-1, 2.21452802E-1, 2.92153865E-1},
+{1.66807845E-1, 2.13641763E-1, 2.70675927E-1},
+{2.29834273E-1, 2.88374633E-1, 3.06238323E-1},
+{1.82154253E-1, 2.00822473E-1, 2.40169376E-1},
+{2.24944726E-1, 2.69813925E-1, 2.91401237E-1},
+{1.63940564E-1, 2.50341147E-1, 2.78307766E-1},
+{2.56727993E-1, 2.95103759E-1, 3.53297085E-1},
+{1.40218839E-1, 1.76687688E-1, 2.46773273E-1},
+{2.15291306E-1, 2.29216009E-1, 2.64283627E-1},
+{1.21002659E-1, 2.18333840E-1, 3.22341293E-1},
+{2.54243195E-1, 2.73986191E-1, 2.96262473E-1},
+{1.60385415E-1, 1.83762908E-1, 2.81598717E-1},
+{1.87832162E-1, 2.37420350E-1, 3.29777509E-1},
+{1.77788362E-1, 2.26703495E-1, 3.02322537E-1},
+{2.75108218E-1, 2.93730587E-1, 3.12373787E-1},
+{1.70116410E-1, 1.85232103E-1, 2.46125028E-1},
+{2.21754774E-1, 2.39912242E-1, 2.86891907E-1},
+{1.95083722E-1, 2.08337873E-1, 2.88349718E-1},
+{2.37536535E-1, 2.75004476E-1, 3.39786023E-1},
+{1.88369319E-1, 2.04371840E-1, 2.57375032E-1},
+{2.47250155E-1, 2.60551840E-1, 3.02137524E-1},
+{1.66944191E-1, 2.46912360E-1, 3.18894416E-1},
+{2.78118610E-1, 3.13011140E-1, 3.65329295E-1},
+{1.45213529E-1, 1.63051456E-1, 2.24912614E-1},
+{2.05692515E-1, 2.20831484E-1, 2.52817810E-1},
+{1.21125661E-1, 1.96374118E-1, 3.00122708E-1},
+{2.15566799E-1, 2.65657336E-1, 2.99202889E-1},
+{1.09134212E-1, 1.78472102E-1, 2.88323194E-1},
+{2.03508541E-1, 2.40347922E-1, 2.96309739E-1},
+{1.53101787E-1, 2.25415319E-1, 2.84843713E-1},
+{2.50233442E-1, 2.77736932E-1, 3.24840695E-1},
+{1.66308925E-1, 1.94173396E-1, 2.11635381E-1},
+{2.01289460E-1, 2.26062179E-1, 2.93246478E-1},
+{1.49518773E-1, 2.14201719E-1, 2.83894747E-1},
+{2.21836135E-1, 2.85231501E-1, 3.20082635E-1},
+{1.89573213E-1, 2.06577629E-1, 2.30332345E-1},
+{2.31247649E-1, 2.46864259E-1, 2.89846569E-1},
+{1.39116928E-1, 2.59189934E-1, 2.98019558E-1},
+{2.44512573E-1, 2.82671362E-1, 3.61258298E-1},
+{1.22530967E-1, 1.68514788E-1, 2.70879298E-1},
+{2.04372838E-1, 2.30398357E-1, 2.71792918E-1},
+{1.42643943E-1, 2.22405583E-1, 2.92057186E-1},
+{2.42643669E-1, 2.77429372E-1, 2.97135502E-1},
+{1.52048603E-1, 1.96921080E-1, 2.61013240E-1},
+{2.17875019E-1, 2.45840371E-1, 3.08138579E-1},
+{1.90109268E-1, 2.31099129E-1, 2.80178159E-1},
+{2.54314184E-1, 2.94079810E-1, 3.39649171E-1},
+{1.56698599E-1, 2.08597451E-1, 2.28010774E-1},
+{2.25088730E-1, 2.50014484E-1, 2.76250154E-1},
+{1.78219035E-1, 1.98228240E-1, 3.04198891E-1},
+{2.08567217E-1, 2.92395383E-1, 3.46786886E-1},
+{1.71052113E-1, 2.03438759E-1, 2.62644321E-1},
+{2.30275467E-1, 2.58817524E-1, 3.11986536E-1},
+{1.85333565E-1, 2.45760202E-1, 3.10553998E-1},
+{2.89413869E-1, 3.11095625E-1, 3.46476167E-1},
+{1.50332406E-1, 1.67538226E-1, 2.40182847E-1},
+{1.79971650E-1, 2.37168610E-1, 2.60899693E-1},
+{1.49866179E-1, 1.97890073E-1, 3.07916552E-1},
+{2.10799649E-1, 2.88180083E-1, 3.29747230E-1},
+{1.31711140E-1, 1.65906459E-1, 3.22898000E-1},
+{2.14832023E-1, 2.52822131E-1, 2.97547072E-1},
+{1.83760419E-1, 2.37523615E-1, 2.74610013E-1},
+{2.55575180E-1, 2.75439233E-1, 3.46021861E-1},
+{1.82662204E-1, 1.99470907E-1, 2.16051653E-1},
+{2.09240332E-1, 2.22406715E-1, 3.02382857E-1},
+{1.84088245E-1, 2.11327791E-1, 2.82538086E-1},
+{2.41171077E-1, 2.97036022E-1, 3.15979272E-1},
+{1.96804658E-1, 2.11815894E-1, 2.41647676E-1},
+{2.42761984E-1, 2.58586556E-1, 2.93204397E-1},
+{1.58905461E-1, 2.65077025E-1, 2.89881319E-1},
+{2.58060575E-1, 3.18903178E-1, 3.47846836E-1},
+{1.48766384E-1, 1.66853935E-1, 2.66827434E-1},
+{2.15942249E-1, 2.29938298E-1, 2.76041597E-1},
+{1.38410494E-1, 2.39283442E-1, 3.27972382E-1},
+{2.43765280E-1, 2.88408488E-1, 3.06048721E-1},
+{1.70157120E-1, 1.89986289E-1, 2.81219155E-1},
+{2.19117031E-1, 2.58005291E-1, 3.26571971E-1},
+{1.92163572E-1, 2.23614186E-1, 2.98683077E-1},
+{2.73545444E-1, 3.12078089E-1, 3.30766588E-1},
+{1.62452087E-1, 2.04930902E-1, 2.53337711E-1},
+{2.23855302E-1, 2.37671077E-1, 3.03202003E-1},
+{1.93955287E-1, 2.12335557E-1, 3.07566851E-1},
+{2.29912683E-1, 2.97581047E-1, 3.37499231E-1},
+{1.89335391E-1, 2.04148144E-1, 2.78609782E-1},
+{2.42303565E-1, 2.73163110E-1, 3.15361649E-1},
+{1.55009672E-1, 2.88095146E-1, 3.35996419E-1},
+{2.73716152E-1, 3.31215471E-1, 3.62539083E-1},
+{1.52389362E-1, 1.72619134E-1, 1.90585673E-1},
+{1.96988270E-1, 2.26309747E-1, 2.46197492E-1},
+{1.20555148E-1, 2.06369758E-1, 2.81199783E-1},
+{1.93709418E-1, 2.71900505E-1, 3.01332921E-1},
+{1.36701152E-1, 1.54093146E-1, 2.82258362E-1},
+{1.97299168E-1, 2.53656298E-1, 2.90315062E-1},
+{1.43463776E-1, 2.43872911E-1, 2.75533706E-1},
+{2.58477271E-1, 2.73279876E-1, 3.21119100E-1},
+{1.54406175E-1, 1.93793535E-1, 2.15884149E-1},
+{2.05979452E-1, 2.24277020E-1, 2.85732359E-1},
+{1.74535319E-1, 2.08482355E-1, 2.79668540E-1},
+{2.18844578E-1, 2.72486299E-1, 3.27095598E-1},
+{1.77609727E-1, 2.12990195E-1, 2.39119649E-1},
+{2.29163751E-1, 2.59165913E-1, 2.83514649E-1},
+{1.57353148E-1, 2.39961296E-1, 3.04263145E-1},
+{2.45613828E-1, 3.16824526E-1, 3.42909366E-1},
+{1.42953232E-1, 1.61905348E-1, 2.53710240E-1},
+{2.10192814E-1, 2.22847700E-1, 2.71103770E-1},
+{1.26843944E-1, 2.16709048E-1, 2.97734648E-1},
+{2.31000140E-1, 2.80109137E-1, 2.99707443E-1},
+{1.52980462E-1, 1.93996876E-1, 2.72895664E-1},
+{2.12860718E-1, 2.41545349E-1, 3.16518754E-1},
+{1.71154693E-1, 2.22469687E-1, 2.93786496E-1},
+{2.51988232E-1, 3.04254979E-1, 3.31269950E-1},
+{1.33188918E-1, 2.07924992E-1, 2.55362093E-1},
+{2.12044910E-1, 2.42189646E-1, 2.88903743E-1},
+{1.84612468E-1, 2.01143622E-1, 2.86360770E-1},
+{2.18286708E-1, 2.76752442E-1, 3.44581515E-1},
+{1.83562174E-1, 1.99478507E-1, 2.62156576E-1},
+{2.33130530E-1, 2.49596909E-1, 3.15842837E-1},
+{1.89898983E-1, 2.46874869E-1, 2.97132462E-1},
+{2.75022447E-1, 3.22490305E-1, 3.46977681E-1},
+{1.42305329E-1, 1.92689180E-1, 2.16155857E-1},
+{1.95676163E-1, 2.22268641E-1, 2.76587397E-1},
+{1.33241490E-1, 1.97791785E-1, 3.22897941E-1},
+{1.84865132E-1, 2.97106177E-1, 3.26105148E-1},
+{1.50203660E-1, 1.76781267E-1, 2.91536182E-1},
+{2.03144446E-1, 2.59616166E-1, 2.99156040E-1},
+{1.65488973E-1, 2.38342047E-1, 2.87493914E-1},
+{2.71071255E-1, 2.89544493E-1, 3.19521040E-1},
+{1.68598369E-1, 1.98825568E-1, 2.30347604E-1},
+{2.13811651E-1, 2.34471768E-1, 2.90959626E-1},
+{1.74605444E-1, 2.17256010E-1, 2.85688072E-1},
+{2.28503481E-1, 2.96190292E-1, 3.16534668E-1},
+{1.87172607E-1, 2.20547438E-1, 2.39688724E-1},
+{2.28884771E-1, 2.63583153E-1, 3.01329464E-1},
+{1.77897051E-1, 2.58131474E-1, 2.81487674E-1},
+{2.59513617E-1, 3.07204396E-1, 3.48793596E-1},
+{1.45224437E-1, 1.78715974E-1, 2.59186983E-1},
+{2.19062313E-1, 2.38223523E-1, 2.60461539E-1},
+{1.43650874E-1, 2.09760785E-1, 3.15830201E-1},
+{2.50127465E-1, 2.79182345E-1, 3.05153579E-1},
+{1.48986444E-1, 2.01226771E-1, 2.82543689E-1},
+{2.08387777E-1, 2.35603899E-1, 3.45363885E-1},
+{1.85830340E-1, 2.21607298E-1, 3.10773641E-1},
+{2.80904710E-1, 2.95469791E-1, 3.25499445E-1},
+{1.72967300E-1, 1.97078109E-1, 2.45801106E-1},
+{2.19495699E-1, 2.44767100E-1, 2.93587774E-1},
+{1.83909580E-1, 2.15004295E-1, 3.00334543E-1},
+{2.45338634E-1, 2.68595248E-1, 3.48330349E-1},
+{1.92957386E-1, 2.06625074E-1, 2.67336398E-1},
+{2.54845560E-1, 2.68642277E-1, 3.03547889E-1},
+{1.76853105E-1, 2.59330958E-1, 3.16200763E-1},
+{2.90929139E-1, 3.15634757E-1, 3.68723541E-1},
+{1.57116994E-1, 1.73552901E-1, 2.28736520E-1},
+{2.12509260E-1, 2.30501205E-1, 2.52217978E-1},
+{1.42521843E-1, 2.01979935E-1, 2.93012232E-1},
+{2.14919671E-1, 2.78065056E-1, 3.14176053E-1},
+{1.35947272E-1, 1.81055903E-1, 2.75475413E-1},
+{1.98416695E-1, 2.41673797E-1, 3.05173427E-1},
+{1.59517333E-1, 2.31580108E-1, 2.95412451E-1},
+{2.58203626E-1, 2.87348121E-1, 3.20351988E-1},
+{1.74840674E-1, 1.92883253E-1, 2.11250007E-1},
+{2.02168509E-1, 2.27025688E-1, 3.04884046E-1},
+{1.69532105E-1, 2.11826235E-1, 2.97355384E-1},
+{2.30033740E-1, 2.91504353E-1, 3.26589435E-1},
+{1.95046112E-1, 2.11709172E-1, 2.27705747E-1},
+{2.37926885E-1, 2.52411634E-1, 2.97752172E-1},
+{1.53762922E-1, 2.46541560E-1, 3.14768940E-1},
+{2.36075714E-1, 3.03568929E-1, 3.70624453E-1},
+{1.38660327E-1, 1.67949975E-1, 2.73515254E-1},
+{2.13806167E-1, 2.27267206E-1, 2.86276251E-1},
+{1.25080630E-1, 2.44098395E-1, 3.02548796E-1},
+{2.35714868E-1, 2.81208843E-1, 3.08903724E-1},
+{1.51691392E-1, 2.10877746E-1, 2.63812989E-1},
+{2.20730439E-1, 2.52777904E-1, 3.16413730E-1},
+{1.84924737E-1, 2.39424765E-1, 2.85120815E-1},
+{2.59548545E-1, 3.09809893E-1, 3.26423734E-1},
+{1.62930742E-1, 2.19900876E-1, 2.36148626E-1},
+{2.34194234E-1, 2.49944329E-1, 2.77549058E-1},
+{1.70870200E-1, 1.98291600E-1, 3.21412593E-1},
+{2.31566861E-1, 2.75015086E-1, 3.69710356E-1},
+{1.80002406E-1, 2.06701040E-1, 2.71204919E-1},
+{2.38075271E-1, 2.54006237E-1, 3.23827595E-1},
+{1.99148253E-1, 2.54273921E-1, 3.07479709E-1},
+{2.87428617E-1, 3.25045079E-1, 3.48634571E-1},
+{1.45285025E-1, 1.91359162E-1, 2.49691397E-1},
+{1.94659308E-1, 2.40821242E-1, 2.77302653E-1},
+{1.53150991E-1, 1.94375664E-1, 3.27550441E-1},
+{2.04085842E-1, 2.98595697E-1, 3.21480066E-1},
+{1.56009689E-1, 1.81012720E-1, 3.00931662E-1},
+{2.10962430E-1, 2.55770296E-1, 3.08086127E-1},
+{1.85444072E-1, 2.49021322E-1, 2.74029821E-1},
+{2.74493456E-1, 2.89441973E-1, 3.38794917E-1},
+{1.76941887E-1, 1.94476932E-1, 2.22077265E-1},
+{2.16377512E-1, 2.30735779E-1, 3.03689271E-1},
+{1.89683452E-1, 2.14660764E-1, 2.88445383E-1},
+{2.40827337E-1, 2.98141748E-1, 3.27378422E-1},
+{2.01787844E-1, 2.19441772E-1, 2.39327446E-1},
+{2.48812512E-1, 2.65865892E-1, 2.93382376E-1},
+{1.82027832E-1, 2.68279046E-1, 2.93991417E-1},
+{2.56498635E-1, 3.19984466E-1, 3.62663239E-1},
+{1.58799276E-1, 1.75433666E-1, 2.67389864E-1},
+{2.24259302E-1, 2.36668259E-1, 2.77639121E-1},
+{1.49203405E-1, 2.26585329E-1, 3.45255584E-1},
+{2.50655770E-1, 2.92264849E-1, 3.13574284E-1},
+{1.58096299E-1, 2.02193201E-1, 2.98711687E-1},
+{2.28820905E-1, 2.48557344E-1, 3.44726473E-1},
+{1.87972054E-1, 2.34109432E-1, 3.04235607E-1},
+{2.85657108E-1, 3.14878136E-1, 3.36931497E-1},
+{1.62680015E-1, 2.17820048E-1, 2.57436782E-1},
+{2.24049792E-1, 2.46739820E-1, 3.00795883E-1},
+{2.01354548E-1, 2.18286663E-1, 3.13036293E-1},
+{2.38028511E-1, 2.98103482E-1, 3.53503793E-1},
+{1.98829994E-1, 2.12877125E-1, 2.72980839E-1},
+{2.50616491E-1, 2.67659992E-1, 3.20611864E-1},
+{1.70901820E-1, 2.69330353E-1, 3.34428221E-1},
+{3.04988861E-1, 3.36196691E-1, 3.65235358E-1},
+{1.47624031E-1, 1.81272805E-1, 2.04707921E-1},
+{1.93751350E-1, 2.20973969E-1, 2.61775166E-1},
+{1.32089809E-1, 1.94851607E-1, 2.83547610E-1},
+{2.07739428E-1, 2.70596832E-1, 2.92264789E-1},
+{1.27733424E-1, 1.66896015E-1, 2.83891350E-1},
+{2.05309406E-1, 2.47807533E-1, 2.83632785E-1},
+{1.54211894E-1, 2.25014091E-1, 2.70082027E-1},
+{2.67574131E-1, 2.84426898E-1, 3.09334785E-1},
+{1.68846920E-1, 1.87004536E-1, 2.02433169E-1},
+{2.02441111E-1, 2.16733068E-1, 2.93079227E-1},
+{1.63621262E-1, 2.15616465E-1, 2.82792896E-1},
+{2.25509301E-1, 2.66283005E-1, 3.17886561E-1},
+{1.89110294E-1, 2.05609441E-1, 2.22113580E-1},
+{2.21240178E-1, 2.60288864E-1, 2.92541057E-1},
+{1.55563369E-1, 2.46850818E-1, 2.89648801E-1},
+{2.48406157E-1, 3.05291861E-1, 3.55316669E-1},
+{1.27122149E-1, 1.58053726E-1, 2.54164368E-1},
+{2.04998836E-1, 2.19476849E-1, 2.78342038E-1},
+{1.33302316E-1, 2.29614019E-1, 2.86947161E-1},
+{2.36777052E-1, 2.67918199E-1, 3.08230907E-1},
+{1.40853569E-1, 2.03414679E-1, 2.73257107E-1},
+{2.07684264E-1, 2.34520018E-1, 3.24583262E-1},
+{1.77181646E-1, 2.29595393E-1, 2.83539146E-1},
+{2.61378348E-1, 3.01160187E-1, 3.21707100E-1},
+{1.48595735E-1, 2.07772017E-1, 2.46946126E-1},
+{2.14334831E-1, 2.48061299E-1, 2.72259146E-1},
+{1.76380262E-1, 1.96897894E-1, 2.92286903E-1},
+{1.98193476E-1, 2.75483340E-1, 3.49037558E-1},
+{1.76153168E-1, 1.93248957E-1, 2.69548506E-1},
+{2.36968622E-1, 2.50065804E-1, 3.06820840E-1},
+{1.76060721E-1, 2.54037619E-1, 3.03566784E-1},
+{2.82952905E-1, 3.01765054E-1, 3.53956312E-1},
+{1.45353720E-1, 1.83678836E-1, 2.34750062E-1},
+{1.93842635E-1, 2.30635554E-1, 2.67817765E-1},
+{1.38958976E-1, 1.86760783E-1, 3.13113242E-1},
+{1.99944481E-1, 2.77624756E-1, 3.25046331E-1},
+{1.42966077E-1, 1.71310842E-1, 3.03013414E-1},
+{2.07741663E-1, 2.58691758E-1, 2.88766950E-1},
+{1.71776935E-1, 2.40246087E-1, 2.73284525E-1},
+{2.71046638E-1, 2.85170943E-1, 3.27401131E-1},
+{1.69854626E-1, 1.87545776E-1, 2.24484712E-1},
+{2.15221986E-1, 2.27339745E-1, 2.95008808E-1},
+{1.75596640E-1, 2.17936546E-1, 2.74879605E-1},
+{2.34665439E-1, 2.89530903E-1, 3.16494375E-1},
+{1.89946994E-1, 2.04953820E-1, 2.46955171E-1},
+{2.37297818E-1, 2.68316716E-1, 2.90684313E-1},
+{1.69963166E-1, 2.53367484E-1, 2.92533010E-1},
+{2.70659864E-1, 2.97146112E-1, 3.56183976E-1},
+{1.52539685E-1, 1.70138955E-1, 2.52703935E-1},
+{2.19119206E-1, 2.35900700E-1, 2.69739121E-1},
+{1.42245665E-1, 2.18184620E-1, 3.28218073E-1},
+{2.61472821E-1, 2.78025657E-1, 3.02375883E-1},
+{1.53526023E-1, 1.90727741E-1, 2.92820841E-1},
+{2.09240988E-1, 2.49808684E-1, 3.24709088E-1},
+{1.75176397E-1, 2.38646746E-1, 3.06392699E-1},
+{2.73218870E-1, 3.03954989E-1, 3.20513874E-1},
+{1.63911596E-1, 1.89611584E-1, 2.56272525E-1},
+{2.26953760E-1, 2.40120232E-1, 2.92728513E-1},
+{1.95565715E-1, 2.11956203E-1, 2.97374696E-1},
+{2.41045550E-1, 2.88497001E-1, 3.36352319E-1},
+{1.94948331E-1, 2.09475279E-1, 2.56309658E-1},
+{2.47884631E-1, 2.63356417E-1, 3.11270863E-1},
+{1.69189706E-1, 2.35864580E-1, 3.36249381E-1},
+{2.86001563E-1, 3.25423747E-1, 3.59607369E-1},
+{1.56258598E-1, 1.76704943E-1, 2.14393437E-1},
+{2.08996847E-1, 2.23968685E-1, 2.60886759E-1},
+{1.35765389E-1, 2.03580052E-1, 3.05503219E-1},
+{2.18961373E-1, 2.79463500E-1, 2.99450845E-1},
+{1.34064749E-1, 1.78332120E-1, 2.90169626E-1},
+{2.13298395E-1, 2.40031511E-1, 3.00345927E-1},
+{1.64373413E-1, 2.26438701E-1, 2.87171155E-1},
+{2.50739604E-1, 2.80812472E-1, 3.35349351E-1},
+{1.63649514E-1, 1.97108001E-1, 2.21165180E-1},
+{2.08139613E-1, 2.30869800E-1, 2.96137065E-1},
+{1.59113124E-1, 2.18189180E-1, 2.95531958E-1},
+{2.39883497E-1, 2.81831235E-1, 3.26045603E-1},
+{1.89394727E-1, 2.08127141E-1, 2.38446414E-1},
+{2.32995704E-1, 2.59603471E-1, 2.93427974E-1},
+{1.60558835E-1, 2.55164832E-1, 3.02872926E-1},
+{2.53509283E-1, 2.96028465E-1, 3.67721587E-1},
+{1.30124375E-1, 1.74838990E-1, 2.60486037E-1},
+{2.10203990E-1, 2.33570784E-1, 2.83061892E-1},
+{1.52365491E-1, 2.25338757E-1, 3.03720981E-1},
+{2.40558609E-1, 2.77192205E-1, 3.05891901E-1},
+{1.63728818E-1, 1.94779396E-1, 2.69253582E-1},
+{2.25709423E-1, 2.40902692E-1, 3.18060607E-1},
+{1.92055091E-1, 2.29857832E-1, 2.89826721E-1},
+{2.62759686E-1, 3.04292172E-1, 3.35680574E-1},
+{1.66071162E-1, 2.06819177E-1, 2.39712462E-1},
+{2.23915562E-1, 2.50106871E-1, 2.85296232E-1},
+{1.88402340E-1, 2.03793734E-1, 3.03041130E-1},
+{2.30698988E-1, 2.87044138E-1, 3.49802762E-1},
+{1.82025358E-1, 2.14073509E-1, 2.63470024E-1},
+{2.37297758E-1, 2.65025407E-1, 3.17815512E-1},
+{1.89278707E-1, 2.58802205E-1, 3.04866165E-1},
+{2.97243059E-1, 3.17153066E-1, 3.56583923E-1},
+{1.58607468E-1, 1.78659767E-1, 2.41919369E-1},
+{1.94887385E-1, 2.41695851E-1, 2.62176663E-1},
+{1.58124432E-1, 2.11753070E-1, 3.11352164E-1},
+{2.16902718E-1, 2.98796803E-1, 3.20994049E-1},
+{1.49272785E-1, 1.74964130E-1, 3.15334409E-1},
+{2.21622273E-1, 2.56179065E-1, 3.03902954E-1},
+{1.75979599E-1, 2.43505448E-1, 2.85801739E-1},
+{2.64590383E-1, 2.85541564E-1, 3.45107764E-1},
+{1.80137083E-1, 2.05279350E-1, 2.22255990E-1},
+{2.10796222E-1, 2.26315439E-1, 3.14426929E-1},
+{1.79151163E-1, 2.09439725E-1, 2.93280870E-1},
+{2.49719024E-1, 2.91257650E-1, 3.27162296E-1},
+{1.98700234E-1, 2.15896755E-1, 2.49960214E-1},
+{2.40726396E-1, 2.64857739E-1, 2.99639553E-1},
+{1.71249732E-1, 2.68166155E-1, 3.03572744E-1},
+{2.69555569E-1, 3.16100627E-1, 3.56570691E-1},
+{1.50564745E-1, 1.84190869E-1, 2.68674821E-1},
+{2.16941193E-1, 2.40813971E-1, 2.78942198E-1},
+{1.35399476E-1, 2.60586530E-1, 3.32604855E-1},
+{2.56150961E-1, 2.87822872E-1, 3.06156367E-1},
+{1.66398838E-1, 1.88721806E-1, 2.93023735E-1},
+{2.29214087E-1, 2.61565417E-1, 3.27494055E-1},
+{1.98266640E-1, 2.32970506E-1, 2.99134284E-1},
+{2.87046254E-1, 3.07103783E-1, 3.27298075E-1},
+{1.75898686E-1, 2.11898595E-1, 2.51332909E-1},
+{2.32067421E-1, 2.44622201E-1, 2.99443692E-1},
+{1.90780059E-1, 2.12090015E-1, 3.25059265E-1},
+{2.31531218E-1, 3.14166099E-1, 3.42735857E-1},
+{1.95099846E-1, 2.09554315E-1, 2.79483467E-1},
+{2.40416065E-1, 2.69604772E-1, 3.28015476E-1},
+{1.71800867E-1, 2.82233089E-1, 3.14749271E-1},
+{2.69243777E-1, 3.38462502E-1, 3.79935652E-1},
+{1.59934625E-1, 1.77966774E-1, 2.00818628E-1},
+{2.01979712E-1, 2.30668545E-1, 2.56773323E-1},
+{1.34024277E-1, 2.10961610E-1, 2.84687728E-1},
+{2.03712896E-1, 2.83053070E-1, 3.03309411E-1},
+{1.44528881E-1, 1.64728075E-1, 2.85079390E-1},
+{2.06285611E-1, 2.48649031E-1, 2.96383053E-1},
+{1.58138171E-1, 2.34317720E-1, 2.79650003E-1},
+{2.64995635E-1, 2.79900700E-1, 3.18619400E-1},
+{1.66537479E-1, 1.84279412E-1, 2.14547485E-1},
+{2.03051880E-1, 2.35110492E-1, 2.88755983E-1},
+{1.68422714E-1, 2.03946173E-1, 2.87478894E-1},
+{2.31727019E-1, 2.74086386E-1, 3.24755162E-1},
+{1.85356215E-1, 2.14113116E-1, 2.29030401E-1},
+{2.42482558E-1, 2.60655493E-1, 2.83030301E-1},
+{1.67562261E-1, 2.42027491E-1, 2.99461991E-1},
+{2.38809898E-1, 3.19003850E-1, 3.58415872E-1},
+{1.37908265E-1, 1.54787809E-1, 2.65611202E-1},
+{2.11019263E-1, 2.24607319E-1, 2.79954702E-1},
+{1.37569889E-1, 2.25128531E-1, 3.09312850E-1},
+{2.29239866E-1, 2.76150972E-1, 3.15241843E-1},
+{1.60487458E-1, 1.95461214E-1, 2.83169478E-1},
+{2.18505666E-1, 2.38197207E-1, 3.30340117E-1},
+{1.81991324E-1, 2.33026952E-1, 2.93276042E-1},
+{2.54552305E-1, 3.14394146E-1, 3.36392254E-1},
+{1.44095764E-1, 2.26640165E-1, 2.50595063E-1},
+{2.15188012E-1, 2.51417249E-1, 2.85043985E-1},
+{1.87674388E-1, 2.04458863E-1, 2.94168979E-1},
+{2.30494842E-1, 2.68452436E-1, 3.52370054E-1},
+{1.85022101E-1, 1.99075252E-1, 2.71930546E-1},
+{2.42569372E-1, 2.55389154E-1, 3.11399311E-1},
+{1.95166096E-1, 2.49102056E-1, 2.98998445E-1},
+{2.83654153E-1, 3.14600259E-1, 3.55619401E-1},
+{1.51490018E-1, 1.97729796E-1, 2.32467473E-1},
+{2.00029895E-1, 2.30101258E-1, 2.81933933E-1},
+{1.38711318E-1, 1.91816628E-1, 3.45780402E-1},
+{1.96580395E-1, 3.04714769E-1, 3.40553433E-1},
+{1.38154253E-1, 1.88543141E-1, 2.99461216E-1},
+{2.05666468E-1, 2.68904895E-1, 3.05537194E-1},
+{1.72447845E-1, 2.33558387E-1, 2.93625206E-1},
+{2.70145416E-1, 2.98654765E-1, 3.28556389E-1},
+{1.75489411E-1, 1.91361547E-1, 2.35585332E-1},
+{2.20548794E-1, 2.34773993E-1, 2.95397669E-1},
+{1.85652360E-1, 2.22349137E-1, 2.79883891E-1},
+{2.29456946E-1, 3.04546326E-1, 3.24684292E-1},
+{1.86900780E-1, 2.15469390E-1, 2.51856804E-1},
+{2.34910533E-1, 2.71217376E-1, 2.99894661E-1},
+{1.85142443E-1, 2.56071001E-1, 2.93291301E-1},
+{2.63883710E-1, 3.07127446E-1, 3.62546653E-1},
+{1.60997644E-1, 1.78937852E-1, 2.55808324E-1},
+{2.25671068E-1, 2.43735075E-1, 2.68624991E-1},
+{1.55076161E-1, 2.30396181E-1, 3.21005553E-1},
+{2.51760483E-1, 2.79653400E-1, 3.14202160E-1},
+{1.56988814E-1, 2.07466930E-1, 2.89933950E-1},
+{2.17479482E-1, 2.59626418E-1, 3.40659052E-1},
+{1.76811531E-1, 2.31087089E-1, 3.17562491E-1},
+{2.82952607E-1, 2.99844354E-1, 3.36822897E-1},
+{1.82060316E-1, 1.98734730E-1, 2.51980305E-1},
+{2.25874200E-1, 2.52469152E-1, 2.93356389E-1},
+{2.00799957E-1, 2.17786849E-1, 3.02210063E-1},
+{2.47423753E-1, 2.86882848E-1, 3.47820610E-1},
+{2.01128140E-1, 2.14746892E-1, 2.62269646E-1},
+{2.53963351E-1, 2.69477993E-1, 3.12133819E-1},
+{1.91034868E-1, 2.55738169E-1, 3.32559615E-1},
+{2.91053712E-1, 3.31458420E-1, 3.68588477E-1},
+{1.57229915E-1, 1.85374141E-1, 2.25361317E-1},
+{2.08051339E-1, 2.38350868E-1, 2.64212936E-1},
+{1.46848336E-1, 2.13000089E-1, 3.00192565E-1},
+{2.18630567E-1, 2.90263802E-1, 3.09045762E-1},
+{1.43699184E-1, 1.87815160E-1, 2.83769876E-1},
+{2.07328036E-1, 2.45088696E-1, 3.08956414E-1},
+{1.64228097E-1, 2.27826655E-1, 3.08907896E-1},
+{2.61919737E-1, 2.91333705E-1, 3.31527978E-1},
+{1.70648888E-1, 2.02157527E-1, 2.17827827E-1},
+{2.07796112E-1, 2.34704822E-1, 3.06783766E-1},
+{1.72118798E-1, 2.14057386E-1, 3.10151786E-1},
+{2.29116157E-1, 2.80949861E-1, 3.33774298E-1},
+{1.96622208E-1, 2.16653049E-1, 2.33279720E-1},
+{2.37789229E-1, 2.58971304E-1, 3.04609209E-1},
+{1.55182019E-1, 2.63032585E-1, 3.18943053E-1},
+{2.49388829E-1, 3.16970855E-1, 3.77762467E-1},
+{1.51363596E-1, 1.75010651E-1, 2.78245836E-1},
+{2.19810233E-1, 2.32360214E-1, 2.85034925E-1},
+{1.42630622E-1, 2.40602851E-1, 3.04125100E-1},
+{2.42764875E-1, 2.83762127E-1, 3.15481216E-1},
+{1.57467470E-1, 2.07524061E-1, 2.75674909E-1},
+{2.28758618E-1, 2.49092206E-1, 3.28139395E-1},
+{1.90872714E-1, 2.38125205E-1, 2.94894546E-1},
+{2.66389251E-1, 3.14321429E-1, 3.38669509E-1},
+{1.70644209E-1, 2.25980043E-1, 2.47372389E-1},
+{2.36442789E-1, 2.53003448E-1, 2.88220435E-1},
+{1.85423777E-1, 2.04888850E-1, 3.14608842E-1},
+{2.17379019E-1, 2.94553548E-1, 3.67831022E-1},
+{1.88563988E-1, 2.15174288E-1, 2.72999734E-1},
+{2.45102122E-1, 2.59770364E-1, 3.21885556E-1},
+{1.98444173E-1, 2.61160702E-1, 3.17097872E-1},
+{2.99013853E-1, 3.28965336E-1, 3.56681198E-1},
+{1.58248767E-1, 1.92205697E-1, 2.46059090E-1},
+{2.02385351E-1, 2.47965842E-1, 2.71749645E-1},
+{1.61710784E-1, 2.13708103E-1, 3.27384740E-1},
+{2.14419708E-1, 3.05552453E-1, 3.33721548E-1},
+{1.61819980E-1, 1.89897299E-1, 3.10501546E-1},
+{2.19436333E-1, 2.65029579E-1, 3.09288830E-1},
+{1.88303933E-1, 2.49633163E-1, 2.85499543E-1},
+{2.69325376E-1, 2.99807042E-1, 3.41722459E-1},
+{1.72406003E-1, 2.10977256E-1, 2.27773219E-1},
+{2.20281526E-1, 2.34015763E-1, 3.12846094E-1},
+{1.83257267E-1, 2.22061962E-1, 2.91052371E-1},
+{2.42531225E-1, 3.09527606E-1, 3.30389649E-1},
+{2.07546696E-1, 2.24662632E-1, 2.44420141E-1},
+{2.45858207E-1, 2.70285994E-1, 3.05132121E-1},
+{1.84840545E-1, 2.72096783E-1, 3.12531084E-1},
+{2.74252594E-1, 3.21252435E-1, 3.74658197E-1},
+{1.66425839E-1, 1.84491634E-1, 2.68278092E-1},
+{2.28423670E-1, 2.43025422E-1, 2.81184882E-1},
+{1.60091296E-1, 2.52953321E-1, 3.35822314E-1},
+{2.62109995E-1, 2.95581907E-1, 3.13354105E-1},
+{1.67702749E-1, 2.01536924E-1, 3.01801592E-1},
+{2.37822965E-1, 2.59894758E-1, 3.38231117E-1},
+{1.97206214E-1, 2.45490909E-1, 3.17895442E-1},
+{2.98455298E-1, 3.19209784E-1, 3.40971738E-1},
+{1.71195343E-1, 2.24327832E-1, 2.62736112E-1},
+{2.30626896E-1, 2.53310233E-1, 3.01206797E-1},
+{2.04814211E-1, 2.21881568E-1, 3.25966567E-1},
+{2.22987518E-1, 3.06339115E-1, 3.50717157E-1},
+{2.00855389E-1, 2.15359926E-1, 2.84143478E-1},
+{2.50951648E-1, 2.66189247E-1, 3.33360583E-1},
+{1.75610259E-1, 2.93791324E-1, 3.40326935E-1},
+{2.91745067E-1, 3.40602487E-1, 3.81397158E-1}};
+
+static const float evrc_lspq_full_codebook4[128][3] = {
+{2.77461529E-1, 3.16972077E-1, 3.95498335E-1},
+{3.36560428E-1, 3.60156953E-1, 3.81473005E-1},
+{3.10509324E-1, 3.31732392E-1, 3.66864383E-1},
+{3.37470949E-1, 3.96795273E-1, 4.12356317E-1},
+{2.79660404E-1, 3.66520107E-1, 3.85313451E-1},
+{3.16038966E-1, 3.85609329E-1, 4.01304781E-1},
+{3.09960425E-1, 3.43410730E-1, 4.24745500E-1},
+{3.54243636E-1, 4.08699274E-1, 4.22167957E-1},
+{2.95587242E-1, 3.33741128E-1, 3.87421668E-1},
+{3.33446383E-1, 3.86974752E-1, 4.01353061E-1},
+{3.23412836E-1, 3.65269661E-1, 3.85193288E-1},
+{3.42731953E-1, 4.03192520E-1, 4.19920385E-1},
+{2.77681828E-1, 3.82494986E-1, 4.04274166E-1},
+{3.18247974E-1, 3.95985305E-1, 4.31353152E-1},
+{3.03711414E-1, 3.80319715E-1, 4.37173545E-1},
+{3.78288805E-1, 4.07077312E-1, 4.22679126E-1},
+{2.38116503E-1, 3.42454314E-1, 4.24624741E-1},
+{3.45615685E-1, 3.68681073E-1, 4.00817335E-1},
+{3.17688107E-1, 3.41902673E-1, 4.05601799E-1},
+{3.66368949E-1, 3.89039934E-1, 4.06154454E-1},
+{2.99398005E-1, 3.52021694E-1, 3.99955690E-1},
+{3.24991941E-1, 3.90028834E-1, 4.19478714E-1},
+{3.23025763E-1, 3.68114293E-1, 4.02087748E-1},
+{3.62326264E-1, 4.16927993E-1, 4.32773650E-1},
+{2.72696435E-1, 3.59205008E-1, 4.26880658E-1},
+{3.46539855E-1, 3.69616628E-1, 4.15621221E-1},
+{3.34109128E-1, 3.55736315E-1, 3.96749556E-1},
+{3.37468982E-1, 4.10392702E-1, 4.25986826E-1},
+{2.99468994E-1, 3.80648255E-1, 4.18284118E-1},
+{3.21378171E-1, 4.11198020E-1, 4.28792536E-1},
+{3.27841163E-1, 3.69345129E-1, 4.34395611E-1},
+{3.80669057E-1, 4.26086366E-1, 4.42754567E-1},
+{2.68943667E-1, 3.42942953E-1, 3.98681462E-1},
+{3.38102877E-1, 3.76338840E-1, 3.92043173E-1},
+{3.23593497E-1, 3.48742068E-1, 3.72551978E-1},
+{3.47550809E-1, 3.92885387E-1, 4.21169937E-1},
+{3.04182827E-1, 3.59816670E-1, 3.81633341E-1},
+{3.14221382E-1, 4.02108550E-1, 4.20085251E-1},
+{3.01306546E-1, 3.62662733E-1, 4.29262817E-1},
+{3.71770263E-1, 3.98696363E-1, 4.31438982E-1},
+{2.74591267E-1, 3.35595489E-1, 4.20079648E-1},
+{3.44540834E-1, 3.90451789E-1, 4.06412065E-1},
+{3.25239837E-1, 3.78344476E-1, 3.94673288E-1},
+{3.56683493E-1, 3.90574157E-1, 4.33851063E-1},
+{2.63501287E-1, 3.95260096E-1, 4.23116386E-1},
+{3.37520659E-1, 3.92563462E-1, 4.43415821E-1},
+{3.14522266E-1, 3.80968630E-1, 4.22676384E-1},
+{3.76235068E-1, 4.17298734E-1, 4.31451261E-1},
+{2.61855006E-1, 3.68646085E-1, 4.04260576E-1},
+{3.55580151E-1, 3.77994478E-1, 3.95868242E-1},
+{3.27742815E-1, 3.53872776E-1, 4.11040604E-1},
+{3.62960637E-1, 3.99466991E-1, 4.14690197E-1},
+{3.09410870E-1, 3.73796046E-1, 3.92672479E-1},
+{3.31016302E-1, 4.00801599E-1, 4.31759298E-1},
+{3.23573053E-1, 3.68619561E-1, 4.17455137E-1},
+{3.49115849E-1, 4.26840067E-1, 4.43913996E-1},
+{2.89738595E-1, 3.63759339E-1, 4.10511792E-1},
+{3.55286479E-1, 3.89331281E-1, 4.13432419E-1},
+{3.36565912E-1, 3.60222459E-1, 4.24179018E-1},
+{3.39932680E-1, 4.09228802E-1, 4.40184891E-1},
+{3.00889730E-1, 4.00081098E-1, 4.17955697E-1},
+{3.17052066E-1, 4.22288120E-1, 4.42229569E-1},
+{3.27336788E-1, 3.84311676E-1, 4.30288613E-1},
+{3.98990929E-1, 4.29498434E-1, 4.43475187E-1},
+{2.49110118E-1, 3.25696886E-1, 4.11728263E-1},
+{3.45929205E-1, 3.68577540E-1, 3.88473272E-1},
+{3.13219666E-1, 3.39229465E-1, 3.87597919E-1},
+{3.51453960E-1, 3.98730278E-1, 4.12656188E-1},
+{2.93487132E-1, 3.75763118E-1, 3.94488096E-1},
+{3.24470758E-1, 3.94202888E-1, 4.08882737E-1},
+{3.12710822E-1, 3.57720256E-1, 4.14061189E-1},
+{3.66507173E-1, 4.08171296E-1, 4.23891425E-1},
+{2.99965680E-1, 3.31993401E-1, 4.07860160E-1},
+{3.34925175E-1, 3.86143029E-1, 4.11538124E-1},
+{3.34788024E-1, 3.66196156E-1, 3.93347144E-1},
+{3.47847939E-1, 4.05926466E-1, 4.30507302E-1},
+{2.85952926E-1, 3.95283282E-1, 4.16119337E-1},
+{3.23867381E-1, 4.06476676E-1, 4.42482829E-1},
+{3.16716671E-1, 3.84451628E-1, 4.39411044E-1},
+{3.86772931E-1, 4.11824584E-1, 4.27831531E-1},
+{2.38072395E-1, 3.62342358E-1, 4.30931687E-1},
+{3.46450031E-1, 3.79082918E-1, 4.06567812E-1},
+{3.16576600E-1, 3.56468618E-1, 3.96218300E-1},
+{3.66539180E-1, 3.89590919E-1, 4.21055555E-1},
+{3.08291376E-1, 3.71324301E-1, 4.07867432E-1},
+{3.36435199E-1, 3.91514421E-1, 4.22977090E-1},
+{3.23035538E-1, 3.80447328E-1, 4.09550190E-1},
+{3.65228057E-1, 4.27910388E-1, 4.43691254E-1},
+{2.72038043E-1, 3.76596808E-1, 4.33685899E-1},
+{3.57665777E-1, 3.77761602E-1, 4.09178972E-1},
+{3.36498559E-1, 3.64215910E-1, 4.09255505E-1},
+{3.48082423E-1, 4.17631805E-1, 4.33284521E-1},
+{3.02754521E-1, 3.95974755E-1, 4.33717251E-1},
+{3.31676304E-1, 4.17587161E-1, 4.36239839E-1},
+{3.33287597E-1, 3.80799115E-1, 4.39620733E-1},
+{3.88112009E-1, 4.36933577E-1, 4.50829268E-1},
+{2.56026626E-1, 3.48015189E-1, 4.22922611E-1},
+{3.45773995E-1, 3.81725788E-1, 3.96794081E-1},
+{3.25623751E-1, 3.50391924E-1, 3.87330651E-1},
+{3.56868088E-1, 3.98574769E-1, 4.23177242E-1},
+{3.01226199E-1, 3.86906981E-1, 4.03335571E-1},
+{3.28178406E-1, 4.02090192E-1, 4.19389248E-1},
+{3.14385355E-1, 3.69043887E-1, 4.34375286E-1},
+{3.72321129E-1, 4.11672413E-1, 4.40518737E-1},
+{2.90479720E-1, 3.48121881E-1, 4.26216483E-1},
+{3.44438791E-1, 3.82666349E-1, 4.17321086E-1},
+{3.34866822E-1, 3.76235664E-1, 4.04475212E-1},
+{3.59025359E-1, 4.04721916E-1, 4.34838414E-1},
+{2.79127955E-1, 4.11106586E-1, 4.35360551E-1},
+{3.48125517E-1, 3.98732066E-1, 4.46927428E-1},
+{3.27018857E-1, 3.90107334E-1, 4.41707492E-1},
+{3.90858352E-1, 4.19813931E-1, 4.35153484E-1},
+{2.55319297E-1, 3.70405972E-1, 4.32188630E-1},
+{3.54651988E-1, 3.88332665E-1, 4.02956128E-1},
+{3.21608186E-1, 3.54489803E-1, 4.28299785E-1},
+{3.75163496E-1, 3.98833990E-1, 4.14177418E-1},
+{3.11953604E-1, 3.91430676E-1, 4.12552476E-1},
+{3.42528820E-1, 3.96365345E-1, 4.32497382E-1},
+{3.33744347E-1, 3.76422405E-1, 4.20536995E-1},
+{3.53529096E-1, 4.29231048E-1, 4.59699273E-1},
+{2.88017929E-1, 3.77999961E-1, 4.34011698E-1},
+{3.55683446E-1, 3.80780041E-1, 4.23145533E-1},
+{3.44358265E-1, 3.72184873E-1, 4.31265354E-1},
+{3.53966117E-1, 4.14166689E-1, 4.42941308E-1},
+{3.04770231E-1, 4.12517488E-1, 4.34183121E-1},
+{3.35913360E-1, 4.24590766E-1, 4.46378469E-1},
+{3.43738198E-1, 3.84766221E-1, 4.35271382E-1},
+{4.10941303E-1, 4.40662980E-1, 4.52113390E-1}};
+
+static const float evrc_lspq_half_codebook1[128][3] = {
+{1.35226343E-2, 1.82081293E-2, 3.93940695E-2},
+{2.29392890E-2, 3.57831158E-2, 1.05352886E-1},
+{2.09106486E-2, 3.04159056E-2, 8.93941075E-2},
+{1.88909005E-2, 3.82722206E-2, 1.37820408E-1},
+{2.05143820E-2, 2.85481159E-2, 7.39762187E-2},
+{4.69510332E-2, 6.84031919E-2, 1.09123811E-1},
+{3.15557197E-2, 5.69139980E-2, 8.57057571E-2},
+{3.81181911E-2, 7.77784660E-2, 1.92532852E-1},
+{2.16297153E-2, 2.92908940E-2, 6.25042021E-2},
+{3.11414022E-2, 5.99079318E-2, 1.02860682E-1},
+{3.02799307E-2, 5.35012372E-2, 7.80925751E-2},
+{6.50846213E-2, 9.06624720E-2, 1.42850950E-1},
+{3.27340364E-2, 5.04027791E-2, 6.26492277E-2},
+{5.27439862E-2, 6.22574277E-2, 1.22198336E-1},
+{3.48840356E-2, 6.42222390E-2, 9.16024595E-2},
+{4.88984436E-2, 1.05058022E-1, 1.68813452E-1},
+{2.35791076E-2, 3.21034677E-2, 5.60899563E-2},
+{2.77252812E-2, 4.87281792E-2, 1.01224191E-1},
+{2.74348017E-2, 4.04965915E-2, 9.34926122E-2},
+{4.38360050E-2, 6.03261292E-2, 1.52400866E-1},
+{2.68994924E-2, 4.52906378E-2, 6.49800375E-2},
+{5.16058952E-2, 6.08312152E-2, 1.08799636E-1},
+{4.20064926E-2, 6.11845106E-2, 8.54474008E-2},
+{7.13502690E-2, 1.01972111E-1, 1.74640998E-1},
+{2.88906675E-2, 4.13964354E-2, 5.25928028E-2},
+{3.16364467E-2, 6.63532093E-2, 1.24950245E-1},
+{4.30289507E-2, 5.14023267E-2, 7.96877742E-2},
+{5.70970774E-2, 1.08444504E-1, 1.44075617E-1},
+{3.38840261E-2, 5.04746847E-2, 7.29765445E-2},
+{6.54265657E-2, 7.90987685E-2, 1.15570590E-1},
+{3.85423526E-2, 7.33125433E-2, 1.02307513E-1},
+{6.57824501E-2, 1.02909811E-1, 2.11874440E-1},
+{1.54727865E-2, 2.04559695E-2, 5.46121262E-2},
+{2.27950197E-2, 3.90954204E-2, 1.19443826E-1},
+{3.06889173E-2, 4.54540215E-2, 8.20418894E-2},
+{2.25957241E-2, 4.79101725E-2, 1.71844408E-1},
+{2.71088015E-2, 4.01739590E-2, 7.01922849E-2},
+{4.95789349E-2, 7.92963281E-2, 1.04862511E-1},
+{3.06095853E-2, 5.64059429E-2, 9.49584097E-2},
+{6.34224564E-2, 9.11655501E-2, 1.84724405E-1},
+{2.43342388E-2, 3.91998328E-2, 6.31406233E-2},
+{3.38011980E-2, 6.60846457E-2, 1.11031540E-1},
+{3.51784080E-2, 5.79397269E-2, 7.20702857E-2},
+{6.49054050E-2, 8.65831897E-2, 1.54648736E-1},
+{2.91934665E-2, 5.16204573E-2, 6.94437325E-2},
+{5.94522804E-2, 7.19829276E-2, 1.27434507E-1},
+{5.31888530E-2, 6.38182089E-2, 9.88218486E-2},
+{8.68290961E-2, 1.41135350E-1, 1.91728458E-1},
+{2.49991138E-2, 3.62556018E-2, 5.03724031E-2},
+{2.82246377E-2, 5.44572286E-2, 1.12663500E-1},
+{3.62618119E-2, 4.59073223E-2, 9.43343639E-2},
+{5.70455343E-2, 7.46300444E-2, 1.59157172E-1},
+{2.72987466E-2, 4.56625856E-2, 7.52529651E-2},
+{5.12860194E-2, 8.51126984E-2, 1.23587973E-1},
+{4.91451994E-2, 5.93483113E-2, 9.22686011E-2},
+{7.06961900E-2, 1.05451979E-1, 1.92602143E-1},
+{2.80733760E-2, 4.18509208E-2, 5.87159805E-2},
+{4.64449003E-2, 7.06698820E-2, 1.26038432E-1},
+{4.18453738E-2, 6.30445331E-2, 7.66169876E-2},
+{8.42416435E-2, 1.13282882E-1, 1.43687114E-1},
+{4.17615622E-2, 5.59472926E-2, 7.09872842E-2},
+{5.55161387E-2, 9.50126722E-2, 1.27727196E-1},
+{5.90935498E-2, 7.36730024E-2, 9.65935886E-2},
+{7.84136653E-2, 1.41432360E-1, 2.17428640E-1},
+{2.10490543E-2, 2.91891042E-2, 4.60035764E-2},
+{3.64863276E-2, 4.62387018E-2, 1.07044168E-1},
+{2.68652122E-2, 3.92937548E-2, 8.41179937E-2},
+{2.72903945E-2, 5.53805046E-2, 1.41586170E-1},
+{2.48476695E-2, 3.63277681E-2, 7.62430876E-2},
+{5.25430813E-2, 7.75778666E-2, 1.14567965E-1},
+{4.07741442E-2, 5.39923795E-2, 9.07640457E-2},
+{5.73043302E-2, 7.65803084E-2, 1.79578975E-1},
+{2.46032421E-2, 3.41408364E-2, 6.78990781E-2},
+{4.08220068E-2, 6.29783794E-2, 9.95191261E-2},
+{3.83025035E-2, 5.52857481E-2, 7.90019333E-2},
+{7.24111274E-2, 1.01903863E-1, 1.46979645E-1},
+{3.73902172E-2, 4.70463894E-2, 6.54684529E-2},
+{5.27397543E-2, 6.72770366E-2, 1.39680430E-1},
+{4.05365378E-2, 7.05081299E-2, 9.25668627E-2},
+{4.43425253E-2, 1.10367171E-1, 1.99636266E-1},
+{2.54920740E-2, 3.47603969E-2, 6.05902039E-2},
+{4.35465500E-2, 5.32369502E-2, 1.08325966E-1},
+{2.79599819E-2, 4.91324775E-2, 8.84284526E-2},
+{4.98051867E-2, 8.81728902E-2, 1.52597323E-1},
+{3.19346264E-2, 4.62169312E-2, 6.85206428E-2},
+{5.80246300E-2, 6.84268698E-2, 1.15085281E-1},
+{4.33904678E-2, 6.90575615E-2, 8.44984353E-2},
+{7.39691556E-2, 1.19240515E-1, 1.77340195E-1},
+{3.18767503E-2, 4.59697433E-2, 5.72372638E-2},
+{4.50873822E-2, 5.66509366E-2, 1.32005826E-1},
+{4.59097028E-2, 5.45580424E-2, 8.61423314E-2},
+{7.44685754E-2, 1.13815404E-1, 1.61570594E-1},
+{3.97509560E-2, 4.95359488E-2, 7.22542256E-2},
+{6.76257759E-2, 8.31029043E-2, 1.27990112E-1},
+{5.76258078E-2, 6.95326403E-2, 1.05012968E-1},
+{6.85313493E-2, 1.21758826E-1, 2.20626548E-1},
+{2.18480472E-2, 2.99130920E-2, 5.16208000E-2},
+{3.64343151E-2, 4.91795056E-2, 1.23277210E-1},
+{3.89611274E-2, 4.76634987E-2, 8.61716568E-2},
+{4.14635167E-2, 6.88006952E-2, 1.69356152E-1},
+{3.35514620E-2, 4.17815186E-2, 7.37159401E-2},
+{5.80224693E-2, 8.70314166E-2, 1.12917498E-1},
+{4.80243117E-2, 5.69486506E-2, 1.00755706E-1},
+{5.98873124E-2, 8.57942328E-2, 2.01388851E-1},
+{2.99309995E-2, 3.94828431E-2, 6.46376088E-2},
+{3.88626605E-2, 8.07443634E-2, 1.15519784E-1},
+{3.49444002E-2, 6.28911033E-2, 8.04982036E-2},
+{6.88817874E-2, 9.92431119E-2, 1.60393253E-1},
+{3.64237651E-2, 5.34016453E-2, 6.70152009E-2},
+{5.83492741E-2, 7.85285756E-2, 1.41746715E-1},
+{4.86469641E-2, 7.26736858E-2, 9.48315859E-2},
+{5.85533604E-2, 1.36289746E-1, 1.98639736E-1},
+{2.60888506E-2, 3.73406820E-2, 5.57853170E-2},
+{4.58504409E-2, 5.60512505E-2, 1.17927872E-1},
+{4.28801328E-2, 5.14739119E-2, 9.75309014E-2},
+{6.37611598E-2, 8.73552933E-2, 1.68334916E-1},
+{3.76709923E-2, 4.58216034E-2, 7.86528140E-2},
+{6.75194561E-2, 8.98697898E-2, 1.19418114E-1},
+{5.46374246E-2, 6.66805878E-2, 8.93813819E-2},
+{7.73086548E-2, 1.21754415E-1, 1.99579224E-1},
+{3.15621309E-2, 4.51702215E-2, 6.25768527E-2},
+{3.78782675E-2, 8.03486481E-2, 1.38961688E-1},
+{5.08303270E-2, 6.18740581E-2, 8.31153840E-2},
+{8.96311402E-2, 1.28753766E-1, 1.64891586E-1},
+{4.73503470E-2, 5.75724356E-2, 7.65264630E-2},
+{7.16898590E-2, 9.89895687E-2, 1.30078360E-1},
+{6.29082546E-2, 7.90778771E-2, 1.05111063E-1},
+{8.80649835E-2, 1.65206164E-1, 2.13214174E-1}};
+
+static const float evrc_lspq_half_codebook2[128][3] = {
+{9.75915268E-2, 1.23701490E-1, 1.69437975E-1},
+{9.49536338E-2, 2.01081768E-1, 2.26855248E-1},
+{9.00496617E-2, 1.49164870E-1, 2.26532787E-1},
+{1.70302704E-1, 1.97222874E-1, 2.49974832E-1},
+{1.08773641E-1, 1.51972428E-1, 1.75123364E-1},
+{1.30278930E-1, 2.13229164E-1, 2.29646355E-1},
+{1.24917991E-1, 1.87347755E-1, 2.04712003E-1},
+{2.00670198E-1, 2.28963569E-1, 2.69420803E-1},
+{8.98375586E-2, 1.25332758E-1, 2.10539430E-1},
+{9.62376669E-2, 2.07185850E-1, 2.54174471E-1},
+{1.05694629E-1, 1.78856418E-1, 2.00121015E-1},
+{1.56048968E-1, 2.19573721E-1, 2.91079402E-1},
+{1.37392268E-1, 1.59993336E-1, 1.94698542E-1},
+{1.07262500E-1, 2.37790957E-1, 2.70740807E-1},
+{1.42976448E-1, 2.01550499E-1, 2.18468934E-1},
+{2.14270487E-1, 2.71881402E-1, 3.01200211E-1},
+{1.10729210E-1, 1.33688226E-1, 1.54877156E-1},
+{1.06667660E-1, 1.76678821E-1, 2.62798905E-1},
+{9.16352943E-2, 1.74592838E-1, 2.19329327E-1},
+{1.84038624E-1, 2.27964059E-1, 2.47762203E-1},
+{1.10572360E-1, 1.58207163E-1, 1.96013063E-1},
+{1.33543387E-1, 2.32269660E-1, 2.51828164E-1},
+{1.55922309E-1, 1.77941337E-1, 2.18096644E-1},
+{1.92260072E-1, 2.49512479E-1, 2.89911509E-1},
+{1.13708906E-1, 1.37872443E-1, 2.02929884E-1},
+{1.02557532E-1, 1.84820071E-1, 2.92164624E-1},
+{1.36595622E-1, 1.58687428E-1, 2.41399556E-1},
+{1.72813818E-1, 2.49303415E-1, 3.00458610E-1},
+{1.36871174E-1, 1.57249823E-1, 2.10913152E-1},
+{1.28974810E-1, 2.45167866E-1, 2.67653584E-1},
+{1.66812256E-1, 1.88998029E-1, 2.31345922E-1},
+{2.32248470E-1, 2.63196051E-1, 3.16754937E-1},
+{9.24560949E-2, 1.19977452E-1, 1.91262275E-1},
+{1.13085262E-1, 2.08461538E-1, 2.29368120E-1},
+{1.00716405E-1, 1.40670076E-1, 2.58062959E-1},
+{1.67010382E-1, 2.18105540E-1, 2.62592494E-1},
+{1.25487238E-1, 1.62686959E-1, 1.84409231E-1},
+{1.52406558E-1, 2.07131729E-1, 2.47582436E-1},
+{1.37441203E-1, 1.80262372E-1, 2.17698842E-1},
+{2.07853511E-1, 2.49209508E-1, 2.69830108E-1},
+{9.35257301E-2, 1.49197355E-1, 2.04652041E-1},
+{1.11997180E-1, 2.25233063E-1, 2.47003049E-1},
+{1.09315015E-1, 1.93811879E-1, 2.13802189E-1},
+{1.75118580E-1, 2.52520263E-1, 2.75082767E-1},
+{1.36918738E-1, 1.77440569E-1, 1.97931141E-1},
+{1.36811242E-1, 2.37426177E-1, 2.84737825E-1},
+{1.60759792E-1, 2.00833157E-1, 2.18084484E-1},
+{2.33710244E-1, 2.66372561E-1, 2.91802049E-1},
+{1.19171090E-1, 1.39703169E-1, 1.87723249E-1},
+{1.31049946E-1, 1.93696663E-1, 2.60426998E-1},
+{1.08267047E-1, 1.65194795E-1, 2.39523023E-1},
+{2.03195021E-1, 2.25942209E-1, 2.49403238E-1},
+{1.23842932E-1, 1.45794615E-1, 2.15635628E-1},
+{1.71226338E-1, 2.38054529E-1, 2.57975638E-1},
+{1.66923836E-1, 1.88604668E-1, 2.11124212E-1},
+{2.10620746E-1, 2.62442708E-1, 2.83127964E-1},
+{1.05748810E-1, 1.36286482E-1, 2.20050186E-1},
+{9.72945765E-2, 2.33471528E-1, 2.96113968E-1},
+{1.34298369E-1, 1.93955436E-1, 2.39148825E-1},
+{1.64229318E-1, 2.70067751E-1, 2.94142485E-1},
+{1.42760262E-1, 1.65033355E-1, 2.24100381E-1},
+{1.46414533E-1, 2.47942328E-1, 3.00708115E-1},
+{1.74778774E-1, 2.19349250E-1, 2.38162965E-1},
+{2.36311123E-1, 2.90669680E-1, 3.28010976E-1},
+{1.14076428E-1, 1.33071408E-1, 1.73181504E-1},
+{1.13575839E-1, 1.90307274E-1, 2.41681188E-1},
+{8.59165266E-2, 1.63920239E-1, 2.37934500E-1},
+{1.92916945E-1, 2.15082392E-1, 2.39128128E-1},
+{1.37291834E-1, 1.59423307E-1, 1.79722220E-1},
+{1.40435383E-1, 2.22092256E-1, 2.40960747E-1},
+{1.40387163E-1, 1.89601168E-1, 2.05635697E-1},
+{2.11695507E-1, 2.36578360E-1, 2.81248927E-1},
+{9.03010592E-2, 1.27157405E-1, 2.33567923E-1},
+{1.10118054E-1, 2.09328398E-1, 2.72836268E-1},
+{1.16710417E-1, 1.77853987E-1, 2.22808748E-1},
+{1.81691542E-1, 2.32265159E-1, 2.74991214E-1},
+{1.46553472E-1, 1.69474706E-1, 1.90245956E-1},
+{1.09213792E-1, 2.63291955E-1, 2.88490772E-1},
+{1.49815127E-1, 2.11342707E-1, 2.28899449E-1},
+{1.97645500E-1, 2.83229947E-1, 3.14882278E-1},
+{1.24495603E-1, 1.46097973E-1, 1.66125208E-1},
+{1.34878591E-1, 1.83030054E-1, 2.89288282E-1},
+{9.33032110E-2, 1.83962211E-1, 2.38543004E-1},
+{1.92844257E-1, 2.39588335E-1, 2.58421540E-1},
+{1.23796798E-1, 1.65556595E-1, 2.08408386E-1},
+{1.51144341E-1, 2.35801116E-1, 2.59280622E-1},
+{1.50657728E-1, 1.90052524E-1, 2.28362590E-1},
+{1.98180959E-1, 2.56794214E-1, 3.08975637E-1},
+{1.28490031E-1, 1.49084017E-1, 1.98376507E-1},
+{9.20595750E-2, 2.12231293E-1, 2.92948842E-1},
+{1.41698137E-1, 1.72356680E-1, 2.58454144E-1},
+{1.96733460E-1, 2.29709730E-1, 2.95780182E-1},
+{1.47062227E-1, 1.68918088E-1, 2.07363635E-1},
+{1.36309877E-1, 2.60373056E-1, 2.82607377E-1},
+{1.81041077E-1, 2.01826140E-1, 2.38867551E-1},
+{2.45326266E-1, 2.80183077E-1, 3.11954319E-1},
+{1.04131766E-1, 1.33040652E-1, 1.89834684E-1},
+{1.23298146E-1, 2.09621087E-1, 2.47813210E-1},
+{1.24040775E-1, 1.59827366E-1, 2.58856058E-1},
+{1.87048867E-1, 2.12488100E-1, 2.59629130E-1},
+{1.24255307E-1, 1.73768952E-1, 1.92850024E-1},
+{1.58917829E-1, 2.25389823E-1, 2.43284762E-1},
+{1.53421149E-1, 1.91807315E-1, 2.09249526E-1},
+{2.27154449E-1, 2.51181155E-1, 2.72600353E-1},
+{1.09922059E-1, 1.57100275E-1, 2.20024973E-1},
+{1.32782355E-1, 2.19485506E-1, 2.67028928E-1},
+{1.26857504E-1, 1.98836312E-1, 2.17928499E-1},
+{1.91415027E-1, 2.52424240E-1, 2.72652745E-1},
+{1.55277625E-1, 1.79573521E-1, 2.00773627E-1},
+{1.17547743E-1, 2.47869864E-1, 3.08279335E-1},
+{1.65706977E-1, 2.10339502E-1, 2.29199320E-1},
+{2.25694910E-1, 2.84438193E-1, 3.12106073E-1},
+{1.29503176E-1, 1.48420051E-1, 1.80180401E-1},
+{1.54752508E-1, 1.97748467E-1, 2.67275035E-1},
+{1.28590241E-1, 1.76178381E-1, 2.39905864E-1},
+{2.14926764E-1, 2.37634435E-1, 2.58794010E-1},
+{1.28322318E-1, 1.59338519E-1, 2.26626605E-1},
+{1.55747548E-1, 2.47740522E-1, 2.73726821E-1},
+{1.75741687E-1, 1.97952345E-1, 2.19115943E-1},
+{2.18626365E-1, 2.45809183E-1, 3.00479650E-1},
+{1.17709018E-1, 1.45512864E-1, 2.38044471E-1},
+{1.18006893E-1, 2.23775521E-1, 2.94175088E-1},
+{1.51349202E-1, 1.88157812E-1, 2.48743281E-1},
+{1.89312205E-1, 2.69580543E-1, 2.93785989E-1},
+{1.49895594E-1, 1.74537256E-1, 2.37430006E-1},
+{1.39775530E-1, 2.71709383E-1, 3.07839513E-1},
+{1.83945730E-1, 2.07717165E-1, 2.26722151E-1},
+{2.54552156E-1, 2.96640933E-1, 3.24801445E-1}};
+
+static const float evrc_lspq_half_codebook3[256][4] = {
+{2.36904725E-1, 2.56104350E-1, 3.16955745E-1, 4.07520533E-1},
+{2.97596931E-1, 3.23482454E-1, 3.47667515E-1, 3.74551237E-1},
+{2.73721159E-1, 2.98297524E-1, 3.29923928E-1, 3.83599102E-1},
+{3.07849586E-1, 3.32836270E-1, 3.89340341E-1, 4.05575991E-1},
+{2.33803615E-1, 2.60296524E-1, 3.67351949E-1, 4.04388249E-1},
+{2.97513664E-1, 3.15356553E-1, 3.85135233E-1, 4.02197123E-1},
+{2.85618782E-1, 3.10872793E-1, 3.65022361E-1, 3.84816766E-1},
+{3.35271597E-1, 3.55222225E-1, 3.81921113E-1, 3.98685753E-1},
+{2.00265601E-1, 2.50502288E-1, 3.70398223E-1, 4.32012677E-1},
+{3.07982087E-1, 3.33767712E-1, 3.58199060E-1, 3.78386796E-1},
+{2.60086119E-1, 3.25520277E-1, 3.56873333E-1, 3.84737790E-1},
+{3.01356375E-1, 3.41369390E-1, 4.00296748E-1, 4.17337179E-1},
+{2.67080963E-1, 2.97674358E-1, 3.69702041E-1, 3.89139235E-1},
+{2.72669852E-1, 3.49704087E-1, 3.91925275E-1, 4.06383276E-1},
+{2.52825916E-1, 3.49636555E-1, 3.84550989E-1, 4.05930996E-1},
+{3.42927098E-1, 3.74274015E-1, 4.05468166E-1, 4.20351923E-1},
+{2.52408743E-1, 2.80375838E-1, 3.21436584E-1, 3.88436913E-1},
+{2.96970189E-1, 3.17173600E-1, 3.65342557E-1, 4.02736843E-1},
+{2.81905174E-1, 3.01479161E-1, 3.34335625E-1, 4.07633483E-1},
+{3.26872945E-1, 3.47177684E-1, 3.75017703E-1, 4.05372381E-1},
+{2.36371145E-1, 3.16441059E-1, 3.48707020E-1, 3.82030427E-1},
+{2.87817597E-1, 3.13627005E-1, 4.05129731E-1, 4.23379660E-1},
+{2.77502477E-1, 3.01843822E-1, 3.72250855E-1, 4.19212818E-1},
+{3.28988850E-1, 3.61901104E-1, 4.02015507E-1, 4.19229805E-1},
+{2.24960461E-1, 2.74636388E-1, 3.77016127E-1, 3.94726515E-1},
+{3.01045477E-1, 3.40486169E-1, 3.74888122E-1, 4.02532160E-1},
+{2.59897947E-1, 3.30334961E-1, 3.57493818E-1, 4.08657968E-1},
+{3.00961852E-1, 3.56449068E-1, 4.04779494E-1, 4.22508955E-1},
+{2.20979586E-1, 3.16477656E-1, 4.01744068E-1, 4.20735776E-1},
+{2.79754996E-1, 3.30776095E-1, 4.11152899E-1, 4.32687044E-1},
+{2.64246881E-1, 3.16610634E-1, 3.83876741E-1, 4.36683774E-1},
+{3.44381154E-1, 3.85365665E-1, 4.24949467E-1, 4.41560209E-1},
+{2.19488308E-1, 2.36459881E-1, 3.42465997E-1, 4.24989998E-1},
+{2.91465104E-1, 3.22282016E-1, 3.72852802E-1, 3.91635895E-1},
+{2.74792433E-1, 3.16536307E-1, 3.45392585E-1, 3.74555230E-1},
+{3.10583472E-1, 3.35264921E-1, 3.87527227E-1, 4.23076212E-1},
+{2.23211512E-1, 2.98497617E-1, 3.68426204E-1, 3.90213728E-1},
+{2.89078832E-1, 3.26512754E-1, 3.76308680E-1, 4.09553707E-1},
+{2.63830125E-1, 3.08977246E-1, 3.81453037E-1, 4.04660761E-1},
+{3.47073615E-1, 3.64797831E-1, 3.86763453E-1, 4.04511690E-1},
+{2.18452707E-1, 2.75614083E-1, 3.62711072E-1, 4.18278992E-1},
+{3.15042794E-1, 3.40813220E-1, 3.78627181E-1, 3.96316767E-1},
+{2.79727697E-1, 3.31259727E-1, 3.60061288E-1, 3.81175518E-1},
+{3.18602443E-1, 3.38044286E-1, 4.09010768E-1, 4.30300415E-1},
+{2.64196932E-1, 2.90672481E-1, 3.68595004E-1, 4.31856751E-1},
+{2.72645593E-1, 3.63514841E-1, 3.96518826E-1, 4.20091212E-1},
+{2.26540968E-1, 3.50055099E-1, 3.93851519E-1, 4.12597001E-1},
+{3.53053868E-1, 3.69929552E-1, 4.09656048E-1, 4.26387310E-1},
+{2.60788381E-1, 2.85172462E-1, 3.45943332E-1, 3.97500694E-1},
+{3.01113129E-1, 3.28201890E-1, 3.56068015E-1, 4.10803795E-1},
+{2.88101614E-1, 3.09559643E-1, 3.43756795E-1, 4.24872875E-1},
+{3.10489357E-1, 3.51421893E-1, 3.93717408E-1, 4.15550530E-1},
+{2.22308263E-1, 3.26798201E-1, 3.77981663E-1, 3.98635030E-1},
+{3.02915514E-1, 3.22781920E-1, 3.98558855E-1, 4.25489604E-1},
+{2.77136803E-1, 3.19992602E-1, 3.77490878E-1, 4.29177463E-1},
+{3.38731766E-1, 3.58164370E-1, 4.08386350E-1, 4.25495386E-1},
+{2.18726233E-1, 2.84384966E-1, 3.94053698E-1, 4.16346967E-1},
+{3.01005960E-1, 3.44093680E-1, 3.69013667E-1, 4.15091276E-1},
+{2.80783713E-1, 3.33053648E-1, 3.76726151E-1, 3.97526860E-1},
+{3.14394057E-1, 3.62678826E-1, 4.23668981E-1, 4.41899240E-1},
+{2.66453624E-1, 3.08513761E-1, 3.97407174E-1, 4.17450190E-1},
+{2.94222653E-1, 3.41904402E-1, 4.12726879E-1, 4.34888899E-1},
+{2.87300706E-1, 3.32434595E-1, 3.78856659E-1, 4.38234031E-1},
+{3.57146621E-1, 3.98147047E-1, 4.29875731E-1, 4.44243908E-1},
+{2.29671344E-1, 2.51018614E-1, 3.41046572E-1, 4.04376328E-1},
+{2.94472575E-1, 3.34944606E-1, 3.60409737E-1, 3.83682847E-1},
+{2.88250983E-1, 3.11722696E-1, 3.31680059E-1, 3.65104675E-1},
+{3.24881613E-1, 3.45656693E-1, 3.88306379E-1, 4.05954897E-1},
+{2.50829220E-1, 2.77623534E-1, 3.70799541E-1, 3.90479207E-1},
+{2.93523371E-1, 3.28319192E-1, 3.92112255E-1, 4.09464061E-1},
+{2.83608794E-1, 3.03885639E-1, 3.78504395E-1, 3.97310555E-1},
+{3.34039807E-1, 3.52837384E-1, 3.97272944E-1, 4.14322019E-1},
+{2.21891895E-1, 2.51877457E-1, 3.71723533E-1, 4.31791008E-1},
+{3.13201427E-1, 3.41175437E-1, 3.65503550E-1, 3.88567209E-1},
+{2.71330535E-1, 3.39163721E-1, 3.62616420E-1, 3.95735979E-1},
+{3.07550132E-1, 3.47777665E-1, 4.01049614E-1, 4.32767451E-1},
+{2.59387434E-1, 2.87243843E-1, 3.86817336E-1, 4.06042695E-1},
+{2.85485208E-1, 3.44094992E-1, 4.02050495E-1, 4.19413745E-1},
+{2.65781403E-1, 3.40084374E-1, 3.69407654E-1, 4.27031696E-1},
+{3.53740931E-1, 3.84463251E-1, 4.11747813E-1, 4.26181793E-1},
+{2.43866488E-1, 2.68350184E-1, 3.42201948E-1, 3.98457229E-1},
+{2.93145239E-1, 3.34754169E-1, 3.61702800E-1, 3.98416638E-1},
+{2.91342974E-1, 3.13155174E-1, 3.36525917E-1, 3.87748599E-1},
+{3.05656791E-1, 3.62904549E-1, 3.88153434E-1, 4.05543149E-1},
+{2.17492327E-1, 3.11723530E-1, 3.75984788E-1, 4.28997755E-1},
+{2.91149259E-1, 3.29380929E-1, 4.03900385E-1, 4.22333181E-1},
+{2.90362060E-1, 3.09530973E-1, 3.78994226E-1, 4.13688362E-1},
+{3.29564869E-1, 3.77404690E-1, 4.06584859E-1, 4.24739718E-1},
+{2.46461585E-1, 2.71593273E-1, 3.66338253E-1, 4.30753767E-1},
+{3.14107716E-1, 3.37011874E-1, 3.80409718E-1, 4.11099434E-1},
+{2.76568413E-1, 3.27320695E-1, 3.58844280E-1, 4.28949475E-1},
+{3.17179084E-1, 3.58972430E-1, 4.04765844E-1, 4.40376341E-1},
+{2.42777750E-1, 3.34954798E-1, 3.96943450E-1, 4.13318396E-1},
+{2.88895488E-1, 3.25691164E-1, 4.22859550E-1, 4.43758667E-1},
+{2.77583301E-1, 3.25479031E-1, 3.89144659E-1, 4.41075861E-1},
+{3.59125674E-1, 3.90694141E-1, 4.21009541E-1, 4.35708523E-1},
+{2.20172390E-1, 2.47719273E-1, 3.54381859E-1, 4.25398111E-1},
+{3.06046784E-1, 3.27924728E-1, 3.66992772E-1, 3.93192589E-1},
+{2.70805597E-1, 3.16826642E-1, 3.45648706E-1, 4.11717594E-1},
+{3.23188901E-1, 3.45463097E-1, 3.89778793E-1, 4.21570778E-1},
+{2.46136114E-1, 3.12391996E-1, 3.72188628E-1, 3.95842731E-1},
+{3.03856730E-1, 3.24354768E-1, 3.85747254E-1, 4.14155006E-1},
+{2.81075418E-1, 3.18608463E-1, 3.85646880E-1, 4.02703643E-1},
+{3.53517115E-1, 3.72702539E-1, 3.96264613E-1, 4.13074911E-1},
+{2.09221140E-1, 2.95262218E-1, 3.80314291E-1, 4.31278229E-1},
+{3.25313628E-1, 3.46735477E-1, 3.70724022E-1, 3.91045630E-1},
+{2.86396503E-1, 3.43560040E-1, 3.69713604E-1, 3.89867842E-1},
+{3.27794671E-1, 3.47367823E-1, 4.05465066E-1, 4.24566150E-1},
+{2.53054976E-1, 3.02656293E-1, 3.82165134E-1, 4.29898322E-1},
+{2.94418454E-1, 3.70745420E-1, 3.95443261E-1, 4.19514775E-1},
+{2.62873113E-1, 3.45069230E-1, 4.04140890E-1, 4.21902061E-1},
+{3.65063488E-1, 3.82435143E-1, 4.13424790E-1, 4.31241691E-1},
+{2.48788506E-1, 2.82372773E-1, 3.65772307E-1, 4.10981059E-1},
+{3.07288766E-1, 3.27828944E-1, 3.77664983E-1, 4.36220944E-1},
+{2.98542321E-1, 3.20627332E-1, 3.50569665E-1, 4.27620232E-1},
+{3.16258013E-1, 3.62903833E-1, 3.88225138E-1, 4.25608873E-1},
+{2.39077866E-1, 3.31310451E-1, 3.70317876E-1, 4.15995896E-1},
+{3.03735793E-1, 3.32806051E-1, 4.10232842E-1, 4.27751064E-1},
+{2.96002507E-1, 3.19014788E-1, 3.81062448E-1, 4.26954985E-1},
+{3.32508922E-1, 3.62516999E-1, 4.23315108E-1, 4.40995157E-1},
+{2.35128701E-1, 2.74731100E-1, 4.12070572E-1, 4.35478806E-1},
+{2.98073769E-1, 3.55338752E-1, 3.79087746E-1, 4.15318787E-1},
+{2.83429801E-1, 3.45264912E-1, 3.70376289E-1, 4.09900844E-1},
+{3.23593080E-1, 3.65412831E-1, 4.12813127E-1, 4.31023479E-1},
+{2.76626348E-1, 3.00508440E-1, 4.02236879E-1, 4.26638782E-1},
+{2.94512928E-1, 3.61443222E-1, 4.19635236E-1, 4.36999202E-1},
+{2.90807247E-1, 3.41689348E-1, 3.92779291E-1, 4.43490267E-1},
+{3.59391451E-1, 4.03985143E-1, 4.40843761E-1, 4.53028619E-1},
+{2.23295465E-1, 2.39192486E-1, 3.23768020E-1, 4.21689451E-1},
+{2.94778049E-1, 3.18798721E-1, 3.53217840E-1, 3.91906381E-1},
+{2.59032130E-1, 3.10240507E-1, 3.43569040E-1, 3.95064235E-1},
+{3.16474676E-1, 3.38544369E-1, 3.93329024E-1, 4.12235558E-1},
+{2.40108207E-1, 2.84631193E-1, 3.60280991E-1, 3.79973769E-1},
+{2.96909094E-1, 3.15798342E-1, 3.94964337E-1, 4.15127575E-1},
+{2.85434067E-1, 3.04921508E-1, 3.61974716E-1, 4.05767262E-1},
+{3.37407053E-1, 3.56672168E-1, 3.85155082E-1, 4.11186695E-1},
+{2.24014923E-1, 2.60116160E-1, 3.94772530E-1, 4.19585884E-1},
+{3.00647914E-1, 3.41640651E-1, 3.70223522E-1, 3.89520049E-1},
+{2.65946031E-1, 3.25039148E-1, 3.74339938E-1, 3.92346144E-1},
+{3.16029310E-1, 3.40491295E-1, 4.02355313E-1, 4.20484245E-1},
+{2.69841492E-1, 2.94562399E-1, 3.62341762E-1, 4.06415462E-1},
+{2.78897285E-1, 3.59831035E-1, 3.82025838E-1, 4.10577476E-1},
+{2.60760844E-1, 3.31088543E-1, 3.88826251E-1, 4.05486643E-1},
+{3.43372285E-1, 3.82647038E-1, 4.14716601E-1, 4.31592941E-1},
+{2.47998103E-1, 2.73393154E-1, 3.31160426E-1, 4.18943226E-1},
+{3.03579569E-1, 3.25202465E-1, 3.70984435E-1, 4.14420485E-1},
+{2.76896894E-1, 3.00499499E-1, 3.54178190E-1, 4.28807020E-1},
+{3.23655546E-1, 3.59816968E-1, 3.89525414E-1, 4.09288704E-1},
+{2.38927796E-1, 3.09919238E-1, 3.53915572E-1, 4.16634321E-1},
+{2.81171739E-1, 3.07520270E-1, 4.16264892E-1, 4.38523829E-1},
+{2.88858652E-1, 3.09810817E-1, 3.67845178E-1, 4.36035573E-1},
+{3.38423491E-1, 3.70634377E-1, 4.15449977E-1, 4.31534529E-1},
+{2.41260394E-1, 2.73617864E-1, 3.89554620E-1, 4.12539542E-1},
+{2.98046708E-1, 3.40122104E-1, 3.86183739E-1, 4.13826346E-1},
+{2.82436430E-1, 3.31597507E-1, 3.57941389E-1, 4.12115216E-1},
+{3.03820193E-1, 3.70588601E-1, 4.05774951E-1, 4.31517065E-1},
+{2.39077732E-1, 3.11638474E-1, 4.13935781E-1, 4.35304046E-1},
+{2.67116845E-1, 3.41937900E-1, 4.17409420E-1, 4.39184844E-1},
+{2.67946839E-1, 3.33343923E-1, 3.86481404E-1, 4.37462509E-1},
+{3.40510964E-1, 3.90878022E-1, 4.35485125E-1, 4.49101925E-1},
+{2.10069850E-1, 2.32524484E-1, 3.61781418E-1, 4.31357861E-1},
+{2.94509888E-1, 3.33709776E-1, 3.82278621E-1, 3.98638904E-1},
+{2.80525148E-1, 3.25905204E-1, 3.50647032E-1, 3.92873943E-1},
+{3.19999635E-1, 3.43674660E-1, 3.91070545E-1, 4.37501073E-1},
+{2.20581010E-1, 3.03151906E-1, 3.81765544E-1, 4.04488146E-1},
+{2.86122739E-1, 3.29746544E-1, 3.88102829E-1, 4.24247742E-1},
+{2.69807100E-1, 3.25332284E-1, 3.79154503E-1, 4.15138245E-1},
+{3.34858894E-1, 3.69258404E-1, 3.94743145E-1, 4.11922157E-1},
+{2.07109794E-1, 2.72779524E-1, 3.78566444E-1, 4.34579968E-1},
+{3.06466222E-1, 3.46695721E-1, 3.87138307E-1, 4.03558314E-1},
+{2.70148575E-1, 3.46654534E-1, 3.77696693E-1, 3.96434486E-1},
+{3.18745911E-1, 3.40225697E-1, 4.14991558E-1, 4.41578746E-1},
+{2.58592844E-1, 3.14370096E-1, 3.65083754E-1, 4.21615183E-1},
+{2.82712996E-1, 3.54137123E-1, 4.06745970E-1, 4.29267883E-1},
+{2.52021760E-1, 3.59105110E-1, 3.95102918E-1, 4.18148398E-1},
+{3.54906201E-1, 3.74952912E-1, 4.18965995E-1, 4.36144412E-1},
+{2.64841139E-1, 2.92941809E-1, 3.27751458E-1, 4.08790469E-1},
+{3.07774246E-1, 3.35586190E-1, 3.62209618E-1, 4.25394237E-1},
+{2.88466334E-1, 3.16075742E-1, 3.60989630E-1, 4.19551432E-1},
+{3.17128420E-1, 3.55772197E-1, 4.05808747E-1, 4.23972964E-1},
+{2.47089684E-1, 3.38184595E-1, 3.71859610E-1, 3.95971477E-1},
+{3.07981730E-1, 3.32691789E-1, 4.00534213E-1, 4.38273668E-1},
+{2.79484808E-1, 3.16183507E-1, 3.97237718E-1, 4.34746623E-1},
+{3.44490469E-1, 3.66153181E-1, 4.10959423E-1, 4.41727102E-1},
+{2.35741779E-1, 2.94587255E-1, 3.98072541E-1, 4.16833401E-1},
+{3.14038455E-1, 3.52272034E-1, 3.79138887E-1, 4.10969079E-1},
+{2.83002496E-1, 3.38136256E-1, 3.88641894E-1, 4.06193316E-1},
+{3.23625326E-1, 3.50243390E-1, 4.28089559E-1, 4.46630359E-1},
+{2.61252105E-1, 3.24970961E-1, 4.00214493E-1, 4.25321758E-1},
+{3.05284500E-1, 3.42164159E-1, 4.24475133E-1, 4.43830967E-1},
+{2.87374794E-1, 3.32500637E-1, 3.94308269E-1, 4.42538500E-1},
+{3.74075353E-1, 4.02026355E-1, 4.30933535E-1, 4.44160044E-1},
+{2.34503999E-1, 2.56218612E-1, 3.41238797E-1, 4.23045278E-1},
+{3.05492580E-1, 3.29156995E-1, 3.52709830E-1, 3.92439067E-1},
+{2.81323552E-1, 3.03292334E-1, 3.48925412E-1, 3.93163860E-1},
+{3.21893454E-1, 3.50419939E-1, 3.97317469E-1, 4.14560318E-1},
+{2.39684582E-1, 2.92451501E-1, 3.78937423E-1, 3.96535456E-1},
+{3.07307243E-1, 3.29127908E-1, 3.98455560E-1, 4.16143298E-1},
+{2.85274565E-1, 3.08774531E-1, 3.92916501E-1, 4.14437652E-1},
+{3.44446361E-1, 3.62201869E-1, 3.97619784E-1, 4.17743623E-1},
+{2.32083067E-1, 2.67807961E-1, 3.78075659E-1, 4.34560895E-1},
+{3.04738700E-1, 3.51865292E-1, 3.75973165E-1, 3.95293653E-1},
+{2.61990905E-1, 3.46207321E-1, 3.71296942E-1, 4.12438929E-1},
+{3.11080933E-1, 3.51040900E-1, 4.16082799E-1, 4.34340119E-1},
+{2.74980426E-1, 2.96631455E-1, 3.87520492E-1, 4.09243762E-1},
+{2.90939093E-1, 3.54455590E-1, 3.93426955E-1, 4.08220291E-1},
+{2.71871865E-1, 3.45510781E-1, 3.87125313E-1, 4.22590613E-1},
+{3.63245904E-1, 3.81932199E-1, 4.04114902E-1, 4.18370664E-1},
+{2.45770738E-1, 2.72909343E-1, 3.48317921E-1, 4.25161839E-1},
+{3.14139009E-1, 3.37872326E-1, 3.65195215E-1, 4.04423416E-1},
+{2.94075787E-1, 3.16935539E-1, 3.43047202E-1, 4.06130373E-1},
+{3.14627469E-1, 3.72413397E-1, 4.00660694E-1, 4.17930841E-1},
+{2.34014243E-1, 3.14007223E-1, 3.83003533E-1, 4.34829175E-1},
+{2.93635666E-1, 3.20529997E-1, 4.10837352E-1, 4.36393142E-1},
+{2.89505839E-1, 3.11828852E-1, 3.86311471E-1, 4.38771248E-1},
+{3.26317430E-1, 3.80858183E-1, 4.19721425E-1, 4.38795507E-1},
+{2.50809520E-1, 2.83018053E-1, 3.82247388E-1, 4.34244394E-1},
+{3.18994045E-1, 3.44855130E-1, 3.72690141E-1, 4.23067033E-1},
+{2.88380086E-1, 3.36622238E-1, 3.69742334E-1, 4.25057590E-1},
+{3.06107700E-1, 3.81856918E-1, 4.18206155E-1, 4.32868361E-1},
+{2.33898312E-1, 3.44861805E-1, 4.12176549E-1, 4.29216206E-1},
+{2.85980880E-1, 3.42903793E-1, 4.25112903E-1, 4.44299698E-1},
+{2.79858828E-1, 3.38789344E-1, 3.92085373E-1, 4.40541029E-1},
+{3.64509344E-1, 3.82202744E-1, 4.29830611E-1, 4.45818365E-1},
+{2.34392300E-1, 2.57377386E-1, 3.59567046E-1, 4.30088580E-1},
+{3.05031896E-1, 3.27589393E-1, 3.78305554E-1, 4.01026130E-1},
+{2.77522624E-1, 3.18130314E-1, 3.67794275E-1, 4.01543021E-1},
+{3.33035767E-1, 3.55820954E-1, 3.87548923E-1, 4.24628675E-1},
+{2.45021001E-1, 3.12560678E-1, 3.91147614E-1, 4.08762813E-1},
+{2.97059119E-1, 3.40246916E-1, 3.92919302E-1, 4.28899705E-1},
+{2.77839303E-1, 3.25019777E-1, 3.97436380E-1, 4.15920913E-1},
+{3.49465251E-1, 3.70362461E-1, 3.95482540E-1, 4.31923389E-1},
+{2.31485590E-1, 2.91023374E-1, 3.77909541E-1, 4.32259738E-1},
+{3.19283485E-1, 3.53671074E-1, 3.80982876E-1, 3.97843361E-1},
+{2.89689243E-1, 3.50265682E-1, 3.80729675E-1, 3.97969365E-1},
+{3.28987300E-1, 3.52005422E-1, 4.12557244E-1, 4.37597930E-1},
+{2.76273251E-1, 3.02267194E-1, 3.81723404E-1, 4.34989095E-1},
+{2.79627264E-1, 3.73727322E-1, 4.12374616E-1, 4.30626333E-1},
+{2.53442764E-1, 3.65940034E-1, 4.14937019E-1, 4.32743609E-1},
+{3.76107216E-1, 3.95142019E-1, 4.16787744E-1, 4.33023572E-1},
+{2.62815833E-1, 2.88270533E-1, 3.47397208E-1, 4.24182594E-1},
+{3.01931322E-1, 3.43652546E-1, 3.77031326E-1, 4.34204459E-1},
+{2.97834277E-1, 3.23495388E-1, 3.64492416E-1, 4.33550835E-1},
+{3.31774473E-1, 3.64324927E-1, 3.98243546E-1, 4.35078323E-1},
+{2.49049723E-1, 3.27870786E-1, 3.83587003E-1, 4.35558081E-1},
+{3.04653406E-1, 3.27671230E-1, 4.18484688E-1, 4.41378772E-1},
+{2.96960890E-1, 3.23898911E-1, 3.90463710E-1, 4.39915955E-1},
+{3.43923748E-1, 3.67100477E-1, 4.29523230E-1, 4.45214987E-1},
+{2.59399652E-1, 2.91602671E-1, 4.04372454E-1, 4.31413233E-1},
+{2.97537506E-1, 3.57573807E-1, 3.88991833E-1, 4.30006981E-1},
+{2.84068942E-1, 3.49574566E-1, 3.81042838E-1, 4.29712772E-1},
+{3.25716257E-1, 3.74875903E-1, 4.31959271E-1, 4.47290838E-1},
+{2.65302956E-1, 3.14745963E-1, 4.16703463E-1, 4.37294722E-1},
+{3.00398588E-1, 3.54147255E-1, 4.28538084E-1, 4.60336387E-1},
+{2.98077166E-1, 3.49304914E-1, 4.00429249E-1, 4.48213518E-1},
+{3.75576198E-1, 4.16657329E-1, 4.42136765E-1, 4.52728629E-1}};
+
+static const float evrc_lspq_quant_codebook1[16][5] = {
+{0.42091064E-1, 0.69474973E-1, 0.11168948E+0, 0.14571965E+0, 0.20893581E+0},
+{0.54944664E-1, 0.98242261E-1, 0.11007882E+0, 0.15890779E+0, 0.20548241E+0},
+{0.45188572E-1, 0.75199433E-1, 0.11423391E+0, 0.15469728E+0, 0.19746706E+0},
+{0.49474996E-1, 0.79667501E-1, 0.12571351E+0, 0.16944779E+0, 0.20775315E+0},
+{0.41789379E-1, 0.63459560E-1, 0.12068028E+0, 0.15850765E+0, 0.20406815E+0},
+{0.47159236E-1, 0.79129547E-1, 0.12183110E+0, 0.15650047E+0, 0.22309226E+0},
+{0.54539919E-1, 0.80343045E-1, 0.12947764E+0, 0.15186153E+0, 0.20171718E+0},
+{0.55852082E-1, 0.94114847E-1, 0.14016025E+0, 0.17807084E+0, 0.22955489E+0},
+{0.45443531E-1, 0.73541410E-1, 0.11937657E+0, 0.15442030E+0, 0.21010752E+0},
+{0.63178010E-1, 0.95231488E-1, 0.12364983E+0, 0.17672543E+0, 0.21743731E+0},
+{0.52765369E-1, 0.84351443E-1, 0.11589085E+0, 0.15790924E+0, 0.20732352E+0},
+{0.51865745E-1, 0.81328541E-1, 0.13756232E+0, 0.18322878E+0, 0.21640070E+0},
+{0.44419531E-1, 0.68874463E-1, 0.13115251E+0, 0.16263582E+0, 0.21659100E+0},
+{0.49378436E-1, 0.81882551E-1, 0.13067168E+0, 0.16821896E+0, 0.23136081E+0},
+{0.55909779E-1, 0.90783298E-1, 0.13348848E+0, 0.16298474E+0, 0.20961523E+0},
+{0.61378211E-1, 0.98602772E-1, 0.14793332E+0, 0.19283190E+0, 0.23156509E+0}};
+
+static const float evrc_lspq_quant_codebook2[16][5] = {
+{0.26822963, 0.30585295, 0.31110349, 0.36823335, 0.40774474},
+{0.24418014, 0.28970167, 0.32573757, 0.39021483, 0.41345838},
+{0.23341830, 0.30078292, 0.32893899, 0.38557330, 0.41068462},
+{0.25905868, 0.29756859, 0.34196618, 0.38531172, 0.41295227},
+{0.24290450, 0.29223618, 0.32718554, 0.37788135, 0.40332928},
+{0.24674191, 0.29749370, 0.33631226, 0.39426059, 0.42258954},
+{0.21377595, 0.33140418, 0.34067687, 0.38222077, 0.40939021},
+{0.26673481, 0.30791649, 0.34419721, 0.39611506, 0.42387524},
+{0.26121426, 0.30492544, 0.32997236, 0.38486803, 0.42023736},
+{0.24954870, 0.29372856, 0.33382735, 0.37850669, 0.41714057},
+{0.24158891, 0.30173415, 0.34128246, 0.38428575, 0.41619650},
+{0.25818908, 0.31736413, 0.34904337, 0.38769925, 0.41551358},
+{0.24450587, 0.30673453, 0.33579323, 0.37844428, 0.40557048},
+{0.25164026, 0.31225079, 0.33847794, 0.39554194, 0.42396802},
+{0.22787990, 0.31779197, 0.33831909, 0.40044111, 0.41185561},
+{0.27896860, 0.32261974, 0.35658112, 0.40206763, 0.42370448}};
+
+static const float * const evrc_lspq_full_codebooks[] = {
+ evrc_lspq_full_codebook1[0], evrc_lspq_full_codebook2[0],
+ evrc_lspq_full_codebook3[0], evrc_lspq_full_codebook4[0],
+};
+
+static const float * const evrc_lspq_half_codebooks[] = {
+ evrc_lspq_half_codebook1[0], evrc_lspq_half_codebook2[0],
+ evrc_lspq_half_codebook3[0],
+};
+
+static const float * const evrc_lspq_quant_codebooks[] = {
+ evrc_lspq_quant_codebook1[0], evrc_lspq_quant_codebook2[0],
+};
+
+static const float * const * const evrc_lspq_codebooks[] = {
+ 0,
+ evrc_lspq_quant_codebooks,
+ 0,
+ evrc_lspq_half_codebooks,
+ evrc_lspq_full_codebooks,
+};
+
+static const uint8_t evrc_lspq_nb_codebooks[] = {
+ 0,
+ FF_ARRAY_ELEMS(evrc_lspq_quant_codebooks),
+ 0,
+ FF_ARRAY_ELEMS(evrc_lspq_half_codebooks),
+ FF_ARRAY_ELEMS(evrc_lspq_full_codebooks),
+};
+
+static const uint8_t evrc_lspq_full_codebooks_row_sizes[] = {
+ FF_ARRAY_ELEMS(evrc_lspq_full_codebook1[0]),
+ FF_ARRAY_ELEMS(evrc_lspq_full_codebook2[0]),
+ FF_ARRAY_ELEMS(evrc_lspq_full_codebook3[0]),
+ FF_ARRAY_ELEMS(evrc_lspq_full_codebook4[0]),
+};
+
+static const uint8_t evrc_lspq_half_codebooks_row_sizes[] = {
+ FF_ARRAY_ELEMS(evrc_lspq_half_codebook1[0]),
+ FF_ARRAY_ELEMS(evrc_lspq_half_codebook2[0]),
+ FF_ARRAY_ELEMS(evrc_lspq_half_codebook3[0]),
+};
+
+static const uint8_t evrc_lspq_quant_codebooks_row_sizes[] = {
+ FF_ARRAY_ELEMS(evrc_lspq_quant_codebook1[0]),
+ FF_ARRAY_ELEMS(evrc_lspq_quant_codebook2[0]),
+};
+
+static const uint8_t* const evrc_lspq_codebooks_row_sizes[] = {
+ NULL,
+ evrc_lspq_quant_codebooks_row_sizes,
+ NULL,
+ evrc_lspq_half_codebooks_row_sizes,
+ evrc_lspq_full_codebooks_row_sizes,
+};
+
+static const float pitch_gain_vq[] = { 0, 0.3, 0.55, 0.7, 0.8, 0.9, 1, 1.2 };
+static const float estimation_delay[] = { 55.0, 80.0, 39.0, 71.0, 33.0 }; // 5.2.3.4
+static const uint8_t subframe_sizes[] = { 53, 53, 54 };
+#endif /* AVCODEC_EVRCDATA_H */
diff --git a/libavcodec/evrcdec.c b/libavcodec/evrcdec.c
new file mode 100644
index 0000000000..c605a13d74
--- /dev/null
+++ b/libavcodec/evrcdec.c
@@ -0,0 +1,918 @@
+/*
+ * Enhanced Variable Rate Codec, Service Option 3 decoder
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Enhanced Variable Rate Codec, Service Option 3 decoder
+ * @author Paul B Mahol
+ */
+
+#include "libavutil/mathematics.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "get_bits.h"
+#include "evrcdata.h"
+#include "acelp_vectors.h"
+#include "lsp.h"
+
+#define MIN_LSP_SEP (0.05 / (2.0 * M_PI))
+#define MIN_DELAY 20
+#define MAX_DELAY 120
+#define NB_SUBFRAMES 3
+#define SUBFRAME_SIZE 54
+#define FILTER_ORDER 10
+#define ACB_SIZE 128
+
+typedef enum {
+ RATE_ERRS = -1,
+ SILENCE,
+ RATE_QUANT,
+ RATE_QUARTER,
+ RATE_HALF,
+ RATE_FULL,
+} evrc_packet_rate;
+
+/**
+ * EVRC-A unpacked data frame
+ */
+typedef struct EVRCAFrame {
+ uint8_t lpc_flag; ///< spectral change indicator
+ uint16_t lsp[4]; ///< index into LSP codebook
+ uint8_t pitch_delay; ///< pitch delay for entire frame
+ uint8_t delay_diff; ///< delay difference for entire frame
+ uint8_t acb_gain[3]; ///< adaptive codebook gain
+ uint16_t fcb_shape[3][4]; ///< fixed codebook shape
+ uint8_t fcb_gain[3]; ///< fixed codebook gain index
+ uint8_t energy_gain; ///< frame energy gain index
+ uint8_t tty; ///< tty baud rate bit
+} EVRCAFrame;
+
+typedef struct EVRCContext {
+ GetBitContext gb;
+ evrc_packet_rate bitrate;
+ evrc_packet_rate last_valid_bitrate;
+ EVRCAFrame frame;
+
+ float lspf[FILTER_ORDER];
+ float prev_lspf[FILTER_ORDER];
+ float synthesis[FILTER_ORDER];
+ float postfilter_fir[FILTER_ORDER];
+ float postfilter_iir[FILTER_ORDER];
+ float postfilter_residual[ACB_SIZE + SUBFRAME_SIZE];
+ float pitch_delay;
+ float prev_pitch_delay;
+ float avg_acb_gain; ///< average adaptive codebook gain
+ float avg_fcb_gain; ///< average fixed codebook gain
+ float pitch[ACB_SIZE + FILTER_ORDER + SUBFRAME_SIZE];
+ float pitch_back[ACB_SIZE];
+ float interpolation_coeffs[136];
+ float energy_vector[NB_SUBFRAMES];
+ float fade_scale;
+ float last;
+
+ uint8_t prev_energy_gain;
+ uint8_t prev_error_flag;
+ uint8_t warned_buf_mismatch_bitrate;
+} EVRCContext;
+
+/**
+ * Frame unpacking for RATE_FULL, RATE_HALF and RATE_QUANT
+ *
+ * @param e the context
+ *
+ * TIA/IS-127 Table 4.21-1
+ */
+static void unpack_frame(EVRCContext *e)
+{
+ EVRCAFrame *frame = &e->frame;
+ GetBitContext *gb = &e->gb;
+
+ switch (e->bitrate) {
+ case RATE_FULL:
+ frame->lpc_flag = get_bits1(gb);
+ frame->lsp[0] = get_bits(gb, 6);
+ frame->lsp[1] = get_bits(gb, 6);
+ frame->lsp[2] = get_bits(gb, 9);
+ frame->lsp[3] = get_bits(gb, 7);
+ frame->pitch_delay = get_bits(gb, 7);
+ frame->delay_diff = get_bits(gb, 5);
+ frame->acb_gain[0] = get_bits(gb, 3);
+ frame->fcb_shape[0][0] = get_bits(gb, 8);
+ frame->fcb_shape[0][1] = get_bits(gb, 8);
+ frame->fcb_shape[0][2] = get_bits(gb, 8);
+ frame->fcb_shape[0][3] = get_bits(gb, 11);
+ frame->fcb_gain[0] = get_bits(gb, 5);
+ frame->acb_gain[1] = get_bits(gb, 3);
+ frame->fcb_shape[1][0] = get_bits(gb, 8);
+ frame->fcb_shape[1][1] = get_bits(gb, 8);
+ frame->fcb_shape[1][2] = get_bits(gb, 8);
+ frame->fcb_shape[1][3] = get_bits(gb, 11);
+ frame->fcb_gain [1] = get_bits(gb, 5);
+ frame->acb_gain [2] = get_bits(gb, 3);
+ frame->fcb_shape[2][0] = get_bits(gb, 8);
+ frame->fcb_shape[2][1] = get_bits(gb, 8);
+ frame->fcb_shape[2][2] = get_bits(gb, 8);
+ frame->fcb_shape[2][3] = get_bits(gb, 11);
+ frame->fcb_gain [2] = get_bits(gb, 5);
+ frame->tty = get_bits1(gb);
+ break;
+ case RATE_HALF:
+ frame->lsp [0] = get_bits(gb, 7);
+ frame->lsp [1] = get_bits(gb, 7);
+ frame->lsp [2] = get_bits(gb, 8);
+ frame->pitch_delay = get_bits(gb, 7);
+ frame->acb_gain [0] = get_bits(gb, 3);
+ frame->fcb_shape[0][0] = get_bits(gb, 10);
+ frame->fcb_gain [0] = get_bits(gb, 4);
+ frame->acb_gain [1] = get_bits(gb, 3);
+ frame->fcb_shape[1][0] = get_bits(gb, 10);
+ frame->fcb_gain [1] = get_bits(gb, 4);
+ frame->acb_gain [2] = get_bits(gb, 3);
+ frame->fcb_shape[2][0] = get_bits(gb, 10);
+ frame->fcb_gain [2] = get_bits(gb, 4);
+ break;
+ case RATE_QUANT:
+ frame->lsp [0] = get_bits(gb, 4);
+ frame->lsp [1] = get_bits(gb, 4);
+ frame->energy_gain = get_bits(gb, 8);
+ break;
+ }
+}
+
+static evrc_packet_rate buf_size2bitrate(const int buf_size)
+{
+ switch (buf_size) {
+ case 23: return RATE_FULL;
+ case 11: return RATE_HALF;
+ case 6: return RATE_QUARTER;
+ case 3: return RATE_QUANT;
+ case 1: return SILENCE;
+ }
+
+ return RATE_ERRS;
+}
+
+/**
+ * Determine the bitrate from the frame size and/or the first byte of the frame.
+ *
+ * @param avctx the AV codec context
+ * @param buf_size length of the buffer
+ * @param buf the bufffer
+ *
+ * @return the bitrate on success,
+ * RATE_ERRS if the bitrate cannot be satisfactorily determined
+ */
+static evrc_packet_rate determine_bitrate(AVCodecContext *avctx,
+ int *buf_size,
+ const uint8_t **buf)
+{
+ evrc_packet_rate bitrate;
+
+ if ((bitrate = buf_size2bitrate(*buf_size)) >= 0) {
+ if (bitrate > **buf) {
+ EVRCContext *e = avctx->priv_data;
+ if (!e->warned_buf_mismatch_bitrate) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Claimed bitrate and buffer size mismatch.\n");
+ e->warned_buf_mismatch_bitrate = 1;
+ }
+ bitrate = **buf;
+ } else if (bitrate < **buf) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Buffer is too small for the claimed bitrate.\n");
+ return RATE_ERRS;
+ }
+ (*buf)++;
+ *buf_size -= 1;
+ } else if ((bitrate = buf_size2bitrate(*buf_size + 1)) >= 0) {
+ av_log(avctx, AV_LOG_DEBUG,
+ "Bitrate byte is missing, guessing the bitrate from packet size.\n");
+ } else
+ return RATE_ERRS;
+
+ return bitrate;
+}
+
+static void warn_insufficient_frame_quality(AVCodecContext *avctx,
+ const char *message)
+{
+ av_log(avctx, AV_LOG_WARNING, "Frame #%d, %s\n",
+ avctx->frame_number, message);
+}
+
+/**
+ * Initialize the speech codec according to the specification.
+ *
+ * TIA/IS-127 5.2
+ */
+static av_cold int evrc_decode_init(AVCodecContext *avctx)
+{
+ EVRCContext *e = avctx->priv_data;
+ int i, n, idx = 0;
+ float denom = 2.0 / (2.0 * 8.0 + 1.0);
+
+ avctx->channels = 1;
+ avctx->channel_layout = AV_CH_LAYOUT_MONO;
+ avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
+
+ for (i = 0; i < FILTER_ORDER; i++) {
+ e->prev_lspf[i] = (i + 1) * 0.048;
+ e->synthesis[i] = 0.0;
+ }
+
+ for (i = 0; i < ACB_SIZE; i++)
+ e->pitch[i] = e->pitch_back[i] = 0.0;
+
+ e->last_valid_bitrate = RATE_QUANT;
+ e->prev_pitch_delay = 40.0;
+ e->fade_scale = 1.0;
+ e->prev_error_flag = 0;
+ e->avg_acb_gain = e->avg_fcb_gain = 0.0;
+
+ for (i = 0; i < 8; i++) {
+ float tt = ((float)i - 8.0 / 2.0) / 8.0;
+
+ for (n = -8; n <= 8; n++, idx++) {
+ float arg1 = M_PI * 0.9 * (tt - n);
+ float arg2 = M_PI * (tt - n);
+
+ e->interpolation_coeffs[idx] = 0.9;
+ if (arg1)
+ e->interpolation_coeffs[idx] *= (0.54 + 0.46 * cos(arg2 * denom)) *
+ sin(arg1) / arg1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Decode the 10 vector quantized line spectral pair frequencies from the LSP
+ * transmission codes of any bitrate and check for badly received packets.
+ *
+ * @param e the context
+ *
+ * @return 0 on success, -1 if the packet is badly received
+ *
+ * TIA/IS-127 5.2.1, 5.7.1
+ */
+static int decode_lspf(EVRCContext *e)
+{
+ const float * const *codebooks = evrc_lspq_codebooks[e->bitrate];
+ int i, j, k = 0;
+
+ for (i = 0; i < evrc_lspq_nb_codebooks[e->bitrate]; i++) {
+ int row_size = evrc_lspq_codebooks_row_sizes[e->bitrate][i];
+ const float *codebook = codebooks[i];
+
+ for (j = 0; j < row_size; j++)
+ e->lspf[k++] = codebook[e->frame.lsp[i] * row_size + j];
+ }
+
+ // check for monotonic LSPs
+ for (i = 1; i < FILTER_ORDER; i++)
+ if (e->lspf[i] <= e->lspf[i - 1])
+ return -1;
+
+ // check for minimum separation of LSPs at the splits
+ for (i = 0, k = 0; i < evrc_lspq_nb_codebooks[e->bitrate] - 1; i++) {
+ k += evrc_lspq_codebooks_row_sizes[e->bitrate][i];
+ if (e->lspf[k] - e->lspf[k - 1] <= MIN_LSP_SEP)
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Interpolation of LSP parameters.
+ *
+ * TIA/IS-127 5.2.3.1, 5.7.3.2
+ */
+static void interpolate_lsp(float *ilsp, const float *lsp,
+ const float *prev, int index)
+{
+ static const float lsp_interpolation_factors[] = { 0.1667, 0.5, 0.8333 };
+ ff_weighted_vector_sumf(ilsp, prev, lsp,
+ 1.0 - lsp_interpolation_factors[index],
+ lsp_interpolation_factors[index], FILTER_ORDER);
+}
+
+/*
+ * Reconstruction of the delay contour.
+ *
+ * TIA/IS-127 5.2.2.3.2
+ */
+static void interpolate_delay(float *dst, float current, float prev, int index)
+{
+ static const float d_interpolation_factors[] = { 0, 0.3313, 0.6625, 1, 1 };
+ dst[0] = (1.0 - d_interpolation_factors[index ]) * prev
+ + d_interpolation_factors[index ] * current;
+ dst[1] = (1.0 - d_interpolation_factors[index + 1]) * prev
+ + d_interpolation_factors[index + 1] * current;
+ dst[2] = (1.0 - d_interpolation_factors[index + 2]) * prev
+ + d_interpolation_factors[index + 2] * current;
+}
+
+/*
+ * Convert the quantized, interpolated line spectral frequencies,
+ * to prediction coefficients.
+ *
+ * TIA/IS-127 5.2.3.2, 4.7.2.2
+ */
+static void decode_predictor_coeffs(const float *ilspf, float *ilpc)
+{
+ double lsp[FILTER_ORDER];
+ float a[FILTER_ORDER / 2 + 1], b[FILTER_ORDER / 2 + 1];
+ float a1[FILTER_ORDER / 2] = { 0 };
+ float a2[FILTER_ORDER / 2] = { 0 };
+ float b1[FILTER_ORDER / 2] = { 0 };
+ float b2[FILTER_ORDER / 2] = { 0 };
+ int i, k;
+
+ ff_acelp_lsf2lspd(lsp, ilspf, FILTER_ORDER);
+
+ for (k = 0; k <= FILTER_ORDER; k++) {
+ a[0] = k < 2 ? 0.25 : 0;
+ b[0] = k < 2 ? k < 1 ? 0.25 : -0.25 : 0;
+
+ for (i = 0; i < FILTER_ORDER / 2; i++) {
+ a[i + 1] = a[i] - 2 * lsp[i * 2 ] * a1[i] + a2[i];
+ b[i + 1] = b[i] - 2 * lsp[i * 2 + 1] * b1[i] + b2[i];
+ a2[i] = a1[i];
+ a1[i] = a[i];
+ b2[i] = b1[i];
+ b1[i] = b[i];
+ }
+
+ if (k)
+ ilpc[k - 1] = 2.0 * (a[FILTER_ORDER / 2] + b[FILTER_ORDER / 2]);
+ }
+}
+
+static void bl_intrp(EVRCContext *e, float *ex, float delay)
+{
+ float *f;
+ int offset, i, coef_idx;
+ int16_t t;
+
+ offset = lrintf(delay);
+
+ t = (offset - delay + 0.5) * 8.0 + 0.5;
+ if (t == 8) {
+ t = 0;
+ offset--;
+ }
+
+ f = ex - offset - 8;
+
+ coef_idx = t * (2 * 8 + 1);
+
+ ex[0] = 0.0;
+ for (i = 0; i < 2 * 8 + 1; i++)
+ ex[0] += e->interpolation_coeffs[coef_idx + i] * f[i];
+}
+
+/*
+ * Adaptive codebook excitation.
+ *
+ * TIA/IS-127 5.2.2.3.3, 4.12.5.2
+ */
+static void acb_excitation(EVRCContext *e, float *excitation, float gain,
+ const float delay[3], int length)
+{
+ float denom, locdelay, dpr, invl;
+ int i;
+
+ invl = 1.0 / ((float) length);
+ dpr = length;
+
+ /* first at-most extra samples */
+ denom = (delay[1] - delay[0]) * invl;
+ for (i = 0; i < dpr; i++) {
+ locdelay = delay[0] + i * denom;
+ bl_intrp(e, excitation + i, locdelay);
+ }
+
+ denom = (delay[2] - delay[1]) * invl;
+ /* interpolation */
+ for (i = dpr; i < dpr + 10; i++) {
+ locdelay = delay[1] + (i - dpr) * denom;
+ bl_intrp(e, excitation + i, locdelay);
+ }
+
+ for (i = 0; i < length; i++)
+ excitation[i] *= gain;
+}
+
+static void decode_8_pulses_35bits(const uint16_t *fixed_index, float *cod)
+{
+ int i, pos1, pos2, offset;
+
+ offset = (fixed_index[3] >> 9) & 3;
+
+ for (i = 0; i < 3; i++) {
+ pos1 = ((fixed_index[i] & 0x7f) / 11) * 5 + ((i + offset) % 5);
+ pos2 = ((fixed_index[i] & 0x7f) % 11) * 5 + ((i + offset) % 5);
+
+ cod[pos1] = (fixed_index[i] & 0x80) ? -1.0 : 1.0;
+
+ if (pos2 < pos1)
+ cod[pos2] = -cod[pos1];
+ else
+ cod[pos2] += cod[pos1];
+ }
+
+ pos1 = ((fixed_index[3] & 0x7f) / 11) * 5 + ((3 + offset) % 5);
+ pos2 = ((fixed_index[3] & 0x7f) % 11) * 5 + ((4 + offset) % 5);
+
+ cod[pos1] = (fixed_index[3] & 0x100) ? -1.0 : 1.0;
+ cod[pos2] = (fixed_index[3] & 0x80 ) ? -1.0 : 1.0;
+}
+
+static void decode_3_pulses_10bits(uint16_t fixed_index, float *cod)
+{
+ float sign;
+ int pos;
+
+ sign = (fixed_index & 0x200) ? -1.0 : 1.0;
+
+ pos = ((fixed_index & 0x7) * 7) + 4;
+ cod[pos] += sign;
+ pos = (((fixed_index >> 3) & 0x7) * 7) + 2;
+ cod[pos] -= sign;
+ pos = (((fixed_index >> 6) & 0x7) * 7);
+ cod[pos] += sign;
+}
+
+/*
+ * Reconstruction of ACELP fixed codebook excitation for full and half rate.
+ *
+ * TIA/IS-127 5.2.3.7
+ */
+static void fcb_excitation(EVRCContext *e, const uint16_t *codebook,
+ float *excitation, float pitch_gain,
+ int pitch_lag, int subframe_size)
+{
+ int i;
+
+ if (e->bitrate == RATE_FULL)
+ decode_8_pulses_35bits(codebook, excitation);
+ else
+ decode_3_pulses_10bits(*codebook, excitation);
+
+ pitch_gain = av_clipf(pitch_gain, 0.2, 0.9);
+
+ for (i = pitch_lag; i < subframe_size; i++)
+ excitation[i] += pitch_gain * excitation[i - pitch_lag];
+}
+
+/**
+ * Synthesis of the decoder output signal.
+ *
+ * param[in] in input signal
+ * param[in] filter_coeffs LPC coefficients
+ * param[in/out] memory synthesis filter memory
+ * param buffer_length amount of data to process
+ * param[out] samples output samples
+ *
+ * TIA/IS-127 5.2.3.15, 5.7.3.4
+ */
+static void synthesis_filter(const float *in, const float *filter_coeffs,
+ float *memory, int buffer_length, float *samples)
+{
+ int i, j;
+
+ for (i = 0; i < buffer_length; i++) {
+ samples[i] = in[i];
+ for (j = FILTER_ORDER - 1; j > 0; j--) {
+ samples[i] -= filter_coeffs[j] * memory[j];
+ memory[j] = memory[j - 1];
+ }
+ samples[i] -= filter_coeffs[0] * memory[0];
+ memory[0] = samples[i];
+ }
+}
+
+static void bandwidth_expansion(float *coeff, const float *inbuf, float gamma)
+{
+ double fac = gamma;
+ int i;
+
+ for (i = 0; i < FILTER_ORDER; i++) {
+ coeff[i] = inbuf[i] * fac;
+ fac *= gamma;
+ }
+}
+
+static void residual_filter(float *output, const float *input,
+ const float *coef, float *memory, int length)
+{
+ float sum;
+ int i, j;
+
+ for (i = 0; i < length; i++) {
+ sum = input[i];
+
+ for (j = FILTER_ORDER - 1; j > 0; j--) {
+ sum += coef[j] * memory[j];
+ memory[j] = memory[j - 1];
+ }
+ sum += coef[0] * memory[0];
+ memory[0] = input[i];
+ output[i] = sum;
+ }
+}
+
+/*
+ * TIA/IS-127 Table 5.9.1-1.
+ */
+static const struct PfCoeff {
+ float tilt;
+ float ltgain;
+ float p1;
+ float p2;
+} postfilter_coeffs[5] = {
+ { 0.0 , 0.0 , 0.0 , 0.0 },
+ { 0.0 , 0.0 , 0.57, 0.57 },
+ { 0.0 , 0.0 , 0.0 , 0.0 },
+ { 0.35, 0.50, 0.50, 0.75 },
+ { 0.20, 0.50, 0.57, 0.75 },
+};
+
+/*
+ * Adaptive postfilter.
+ *
+ * TIA/IS-127 5.9
+ */
+static void postfilter(EVRCContext *e, float *in, const float *coeff,
+ float *out, int idx, const struct PfCoeff *pfc,
+ int length)
+{
+ float wcoef1[FILTER_ORDER], wcoef2[FILTER_ORDER],
+ scratch[SUBFRAME_SIZE], temp[SUBFRAME_SIZE],
+ mem[SUBFRAME_SIZE];
+ float sum1 = 0.0, sum2 = 0.0, gamma, gain;
+ float tilt = pfc->tilt;
+ int i, n, best;
+
+ bandwidth_expansion(wcoef1, coeff, pfc->p1);
+ bandwidth_expansion(wcoef2, coeff, pfc->p2);
+
+ /* Tilt compensation filter, TIA/IS-127 5.9.1 */
+ for (i = 0; i < length - 1; i++)
+ sum2 += in[i] * in[i + 1];
+ if (sum2 < 0.0)
+ tilt = 0.0;
+
+ for (i = 0; i < length; i++) {
+ scratch[i] = in[i] - tilt * e->last;
+ e->last = in[i];
+ }
+
+ /* Short term residual filter, TIA/IS-127 5.9.2 */
+ residual_filter(&e->postfilter_residual[ACB_SIZE], scratch, wcoef1, e->postfilter_fir, length);
+
+ /* Long term postfilter */
+ best = idx;
+ for (i = FFMIN(MIN_DELAY, idx - 3); i <= FFMAX(MAX_DELAY, idx + 3); i++) {
+ for (n = ACB_SIZE, sum2 = 0; n < ACB_SIZE + length; n++)
+ sum2 += e->postfilter_residual[n] * e->postfilter_residual[n - i];
+ if (sum2 > sum1) {
+ sum1 = sum2;
+ best = i;
+ }
+ }
+
+ for (i = ACB_SIZE, sum1 = 0; i < ACB_SIZE + length; i++)
+ sum1 += e->postfilter_residual[i - best] * e->postfilter_residual[i - best];
+ for (i = ACB_SIZE, sum2 = 0; i < ACB_SIZE + length; i++)
+ sum2 += e->postfilter_residual[i] * e->postfilter_residual[i - best];
+
+ if (sum2 * sum1 == 0 || e->bitrate == RATE_QUANT) {
+ memcpy(temp, e->postfilter_residual + ACB_SIZE, length * sizeof(float));
+ } else {
+ gamma = sum2 / sum1;
+ if (gamma < 0.5)
+ memcpy(temp, e->postfilter_residual + ACB_SIZE, length * sizeof(float));
+ else {
+ gamma = FFMIN(gamma, 1.0);
+
+ for (i = 0; i < length; i++) {
+ temp[i] = e->postfilter_residual[ACB_SIZE + i] + gamma *
+ pfc->ltgain * e->postfilter_residual[ACB_SIZE + i - best];
+ }
+ }
+ }
+
+ memcpy(scratch, temp, length * sizeof(float));
+ memcpy(mem, e->postfilter_iir, FILTER_ORDER * sizeof(float));
+ synthesis_filter(scratch, wcoef2, mem, length, scratch);
+
+ /* Gain computation, TIA/IS-127 5.9.4-2 */
+ for (i = 0, sum1 = 0, sum2 = 0; i < length; i++) {
+ sum1 += in[i] * in[i];
+ sum2 += scratch[i] * scratch[i];
+ }
+ gain = sum2 ? sqrt(sum1 / sum2) : 1.0;
+
+ for (i = 0; i < length; i++)
+ temp[i] *= gain;
+
+ /* Short term postfilter */
+ synthesis_filter(temp, wcoef2, e->postfilter_iir, length, out);
+
+ memmove(e->postfilter_residual,
+ e->postfilter_residual + length, ACB_SIZE * sizeof(float));
+}
+
+static void frame_erasure(EVRCContext *e, float *samples)
+{
+ float ilspf[FILTER_ORDER], ilpc[FILTER_ORDER], idelay[NB_SUBFRAMES],
+ tmp[SUBFRAME_SIZE + 6], f;
+ int i, j;
+
+ for (i = 0; i < FILTER_ORDER; i++) {
+ if (e->bitrate != RATE_QUANT)
+ e->lspf[i] = e->prev_lspf[i] * 0.875 + 0.125 * (i + 1) * 0.048;
+ else
+ e->lspf[i] = e->prev_lspf[i];
+ }
+
+ if (e->prev_error_flag)
+ e->avg_acb_gain *= 0.75;
+ if (e->bitrate == RATE_FULL)
+ memcpy(e->pitch_back, e->pitch, ACB_SIZE * sizeof(float));
+ if (e->last_valid_bitrate == RATE_QUANT)
+ e->bitrate = RATE_QUANT;
+ else
+ e->bitrate = RATE_FULL;
+
+ if (e->bitrate == RATE_FULL || e->bitrate == RATE_HALF) {
+ e->pitch_delay = e->prev_pitch_delay;
+ } else {
+ float sum = 0;
+
+ idelay[0] = idelay[1] = idelay[2] = MIN_DELAY;
+
+ for (i = 0; i < NB_SUBFRAMES; i++)
+ sum += evrc_energy_quant[e->prev_energy_gain][i];
+ sum /= (float) NB_SUBFRAMES;
+ sum = pow(10, sum);
+ for (i = 0; i < NB_SUBFRAMES; i++)
+ e->energy_vector[i] = sum;
+ }
+
+ if (fabs(e->pitch_delay - e->prev_pitch_delay) > 15)
+ e->prev_pitch_delay = e->pitch_delay;
+
+ for (i = 0; i < NB_SUBFRAMES; i++) {
+ int subframe_size = subframe_sizes[i];
+ int pitch_lag;
+
+ interpolate_lsp(ilspf, e->lspf, e->prev_lspf, i);
+
+ if (e->bitrate != RATE_QUANT) {
+ if (e->avg_acb_gain < 0.3) {
+ idelay[0] = estimation_delay[i];
+ idelay[1] = estimation_delay[i + 1];
+ idelay[2] = estimation_delay[i + 2];
+ } else {
+ interpolate_delay(idelay, e->pitch_delay, e->prev_pitch_delay, i);
+ }
+ }
+
+ pitch_lag = lrintf((idelay[1] + idelay[0]) / 2.0);
+ decode_predictor_coeffs(ilspf, ilpc);
+
+ if (e->bitrate != RATE_QUANT) {
+ acb_excitation(e, e->pitch + ACB_SIZE,
+ e->avg_acb_gain, idelay, subframe_size);
+ for (j = 0; j < subframe_size; j++)
+ e->pitch[ACB_SIZE + j] *= e->fade_scale;
+ e->fade_scale = FFMAX(e->fade_scale - 0.05, 0.0);
+ } else {
+ for (j = 0; j < subframe_size; j++)
+ e->pitch[ACB_SIZE + j] = e->energy_vector[i];
+ }
+
+ memmove(e->pitch, e->pitch + subframe_size, ACB_SIZE * sizeof(float));
+
+ if (e->bitrate != RATE_QUANT && e->avg_acb_gain < 0.4) {
+ f = 0.1 * e->avg_fcb_gain;
+ for (j = 0; j < subframe_size; j++)
+ e->pitch[ACB_SIZE + j] += f;
+ } else if (e->bitrate == RATE_QUANT) {
+ for (j = 0; j < subframe_size; j++)
+ e->pitch[ACB_SIZE + j] = e->energy_vector[i];
+ }
+
+ synthesis_filter(e->pitch + ACB_SIZE, ilpc,
+ e->synthesis, subframe_size, tmp);
+ postfilter(e, tmp, ilpc, samples, pitch_lag,
+ &postfilter_coeffs[e->bitrate], subframe_size);
+
+ samples += subframe_size;
+ }
+}
+
+static int evrc_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame_ptr, AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ AVFrame *frame = data;
+ EVRCContext *e = avctx->priv_data;
+ int buf_size = avpkt->size;
+ float ilspf[FILTER_ORDER], ilpc[FILTER_ORDER], idelay[NB_SUBFRAMES];
+ float *samples;
+ int i, j, ret, error_flag = 0;
+
+ frame->nb_samples = 160;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+ samples = (float *)frame->data[0];
+
+ if ((e->bitrate = determine_bitrate(avctx, &buf_size, &buf)) == RATE_ERRS) {
+ warn_insufficient_frame_quality(avctx, "bitrate cannot be determined.");
+ goto erasure;
+ }
+ if (e->bitrate <= SILENCE || e->bitrate == RATE_QUARTER)
+ goto erasure;
+ if (e->bitrate == RATE_QUANT && e->last_valid_bitrate == RATE_FULL
+ && !e->prev_error_flag)
+ goto erasure;
+
+ if ((ret = init_get_bits8(&e->gb, buf, buf_size)) < 0)
+ return ret;
+ memset(&e->frame, 0, sizeof(EVRCAFrame));
+
+ unpack_frame(e);
+
+ if (e->bitrate != RATE_QUANT) {
+ uint8_t *p = (uint8_t *) &e->frame;
+ for (i = 0; i < sizeof(EVRCAFrame); i++) {
+ if (p[i])
+ break;
+ }
+ if (i == sizeof(EVRCAFrame))
+ goto erasure;
+ } else if (e->frame.lsp[0] == 0xf &&
+ e->frame.lsp[1] == 0xf &&
+ e->frame.energy_gain == 0xff) {
+ goto erasure;
+ }
+
+ if (decode_lspf(e) < 0)
+ goto erasure;
+
+ if (e->bitrate == RATE_FULL || e->bitrate == RATE_HALF) {
+ /* Pitch delay parameter checking as per TIA/IS-127 5.1.5.1 */
+ if (e->frame.pitch_delay > MAX_DELAY - MIN_DELAY)
+ goto erasure;
+
+ e->pitch_delay = e->frame.pitch_delay + MIN_DELAY;
+
+ /* Delay diff parameter checking as per TIA/IS-127 5.1.5.2 */
+ if (e->frame.delay_diff) {
+ int p = e->pitch_delay - e->frame.delay_diff + 16;
+ if (p < MIN_DELAY || p > MAX_DELAY)
+ goto erasure;
+ }
+
+ /* Delay contour reconstruction as per TIA/IS-127 5.2.2.2 */
+ if (e->frame.delay_diff &&
+ e->bitrate == RATE_FULL && e->prev_error_flag) {
+ float delay;
+
+ memcpy(e->pitch, e->pitch_back, ACB_SIZE * sizeof(float));
+
+ delay = e->prev_pitch_delay;
+ e->prev_pitch_delay = delay - e->frame.delay_diff + 16.0;
+
+ if (fabs(e->pitch_delay - delay) > 15)
+ delay = e->pitch_delay;
+
+ for (i = 0; i < NB_SUBFRAMES; i++) {
+ int subframe_size = subframe_sizes[i];
+
+ interpolate_delay(idelay, delay, e->prev_pitch_delay, i);
+ acb_excitation(e, e->pitch + ACB_SIZE, e->avg_acb_gain, idelay, subframe_size);
+ memmove(e->pitch, e->pitch + subframe_size, ACB_SIZE * sizeof(float));
+ }
+ }
+
+ /* Smoothing of the decoded delay as per TIA/IS-127 5.2.2.5 */
+ if (fabs(e->pitch_delay - e->prev_pitch_delay) > 15)
+ e->prev_pitch_delay = e->pitch_delay;
+
+ e->avg_acb_gain = e->avg_fcb_gain = 0.0;
+ } else {
+ idelay[0] = idelay[1] = idelay[2] = MIN_DELAY;
+
+ /* Decode frame energy vectors as per TIA/IS-127 5.7.2 */
+ for (i = 0; i < NB_SUBFRAMES; i++)
+ e->energy_vector[i] = pow(10, evrc_energy_quant[e->frame.energy_gain][i]);
+ e->prev_energy_gain = e->frame.energy_gain;
+ }
+
+ for (i = 0; i < NB_SUBFRAMES; i++) {
+ float tmp[SUBFRAME_SIZE + 6] = { 0 };
+ int subframe_size = subframe_sizes[i];
+ int pitch_lag;
+
+ interpolate_lsp(ilspf, e->lspf, e->prev_lspf, i);
+
+ if (e->bitrate != RATE_QUANT)
+ interpolate_delay(idelay, e->pitch_delay, e->prev_pitch_delay, i);
+
+ pitch_lag = lrintf((idelay[1] + idelay[0]) / 2.0);
+ decode_predictor_coeffs(ilspf, ilpc);
+
+ /* Bandwidth expansion as per TIA/IS-127 5.2.3.3 */
+ if (e->frame.lpc_flag && e->prev_error_flag)
+ bandwidth_expansion(ilpc, ilpc, 0.75);
+
+ if (e->bitrate != RATE_QUANT) {
+ float acb_sum, f;
+
+ f = exp((e->bitrate == RATE_HALF ? 0.5 : 0.25)
+ * (e->frame.fcb_gain[i] + 1));
+ acb_sum = pitch_gain_vq[e->frame.acb_gain[i]];
+ e->avg_acb_gain += acb_sum / NB_SUBFRAMES;
+ e->avg_fcb_gain += f / NB_SUBFRAMES;
+
+ acb_excitation(e, e->pitch + ACB_SIZE,
+ acb_sum, idelay, subframe_size);
+ fcb_excitation(e, e->frame.fcb_shape[i], tmp,
+ acb_sum, pitch_lag, subframe_size);
+
+ /* Total excitation generation as per TIA/IS-127 5.2.3.9 */
+ for (j = 0; j < subframe_size; j++)
+ e->pitch[ACB_SIZE + j] += f * tmp[j];
+ e->fade_scale = FFMIN(e->fade_scale + 0.2, 1.0);
+ } else {
+ for (j = 0; j < subframe_size; j++)
+ e->pitch[ACB_SIZE + j] = e->energy_vector[i];
+ }
+
+ memmove(e->pitch, e->pitch + subframe_size, ACB_SIZE * sizeof(float));
+
+ synthesis_filter(e->pitch + ACB_SIZE, ilpc,
+ e->synthesis, subframe_size, tmp);
+ postfilter(e, tmp, ilpc, samples, pitch_lag,
+ &postfilter_coeffs[e->bitrate], subframe_size);
+
+ samples += subframe_size;
+ }
+
+ if (error_flag) {
+erasure:
+ error_flag = 1;
+ av_log(avctx, AV_LOG_WARNING, "frame erasure\n");
+ frame_erasure(e, samples);
+ }
+
+ memcpy(e->prev_lspf, e->lspf, sizeof(e->prev_lspf));
+ e->prev_error_flag = error_flag;
+ e->last_valid_bitrate = e->bitrate;
+
+ if (e->bitrate != RATE_QUANT)
+ e->prev_pitch_delay = e->pitch_delay;
+
+ samples = (float *)frame->data[0];
+ for (i = 0; i < 160; i++)
+ samples[i] /= 32768;
+
+ *got_frame_ptr = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_evrc_decoder = {
+ .name = "evrc",
+ .long_name = NULL_IF_CONFIG_SMALL("EVRC (Enhanced Variable Rate Codec)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_EVRC,
+ .init = evrc_decode_init,
+ .decode = evrc_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+ .priv_data_size = sizeof(EVRCContext),
+};
diff --git a/libavcodec/exif.c b/libavcodec/exif.c
new file mode 100644
index 0000000000..fa30f0573f
--- /dev/null
+++ b/libavcodec/exif.c
@@ -0,0 +1,142 @@
+/*
+ * EXIF metadata parser
+ * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * EXIF metadata parser
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ */
+
+#include "exif.h"
+
+
+static const char *exif_get_tag_name(uint16_t id)
+{
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(tag_list); i++) {
+ if (tag_list[i].id == id)
+ return tag_list[i].name;
+ }
+
+ return NULL;
+}
+
+
+static int exif_add_metadata(AVCodecContext *avctx, int count, int type,
+ const char *name, const char *sep,
+ GetByteContext *gb, int le,
+ AVDictionary **metadata)
+{
+ switch(type) {
+ case 0:
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid TIFF tag type 0 found for %s with size %d\n",
+ name, count);
+ return 0;
+ case TIFF_DOUBLE : return ff_tadd_doubles_metadata(count, name, sep, gb, le, metadata);
+ case TIFF_SSHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 1, metadata);
+ case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, gb, le, 0, metadata);
+ case TIFF_SBYTE : return ff_tadd_bytes_metadata(count, name, sep, gb, le, 1, metadata);
+ case TIFF_BYTE :
+ case TIFF_UNDEFINED: return ff_tadd_bytes_metadata(count, name, sep, gb, le, 0, metadata);
+ case TIFF_STRING : return ff_tadd_string_metadata(count, name, gb, le, metadata);
+ case TIFF_SRATIONAL:
+ case TIFF_RATIONAL : return ff_tadd_rational_metadata(count, name, sep, gb, le, metadata);
+ case TIFF_SLONG :
+ case TIFF_LONG : return ff_tadd_long_metadata(count, name, sep, gb, le, metadata);
+ default:
+ avpriv_request_sample(avctx, "TIFF tag type (%u)", type);
+ return 0;
+ };
+}
+
+
+static int exif_decode_tag(AVCodecContext *avctx, GetByteContext *gbytes, int le,
+ int depth, AVDictionary **metadata)
+{
+ int ret, cur_pos;
+ unsigned id, count;
+ enum TiffTypes type;
+
+ if (depth > 2) {
+ return 0;
+ }
+
+ ff_tread_tag(gbytes, le, &id, &type, &count, &cur_pos);
+
+ if (!bytestream2_tell(gbytes)) {
+ bytestream2_seek(gbytes, cur_pos, SEEK_SET);
+ return 0;
+ }
+
+ // read count values and add it metadata
+ // store metadata or proceed with next IFD
+ ret = ff_tis_ifd(id);
+ if (ret) {
+ ret = avpriv_exif_decode_ifd(avctx, gbytes, le, depth + 1, metadata);
+ } else {
+ const char *name = exif_get_tag_name(id);
+ char *use_name = (char*) name;
+
+ if (!use_name) {
+ use_name = av_malloc(7);
+ if (!use_name) {
+ return AVERROR(ENOMEM);
+ }
+ snprintf(use_name, 7, "0x%04X", id);
+ }
+
+ ret = exif_add_metadata(avctx, count, type, use_name, NULL,
+ gbytes, le, metadata);
+
+ if (!name) {
+ av_freep(&use_name);
+ }
+ }
+
+ bytestream2_seek(gbytes, cur_pos, SEEK_SET);
+
+ return ret;
+}
+
+
+int avpriv_exif_decode_ifd(AVCodecContext *avctx, GetByteContext *gbytes, int le,
+ int depth, AVDictionary **metadata)
+{
+ int i, ret;
+ int entries;
+
+ entries = ff_tget_short(gbytes, le);
+
+ if (bytestream2_get_bytes_left(gbytes) < entries * 12) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (i = 0; i < entries; i++) {
+ if ((ret = exif_decode_tag(avctx, gbytes, le, depth, metadata)) < 0) {
+ return ret;
+ }
+ }
+
+ // return next IDF offset or 0x000000000 or a value < 0 for failure
+ return ff_tget_long(gbytes, le);
+}
diff --git a/libavcodec/exif.h b/libavcodec/exif.h
new file mode 100644
index 0000000000..2f509ba1e9
--- /dev/null
+++ b/libavcodec/exif.h
@@ -0,0 +1,170 @@
+/*
+ * EXIF metadata parser
+ * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * EXIF metadata parser
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ */
+
+#ifndef AVCODEC_EXIF_H
+#define AVCODEC_EXIF_H
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "tiff.h"
+
+#define EXIF_MAX_IFD_RECURSION 2
+#define EXIF_TAG_NAME_LENGTH 32
+
+struct exif_tag {
+ char name[EXIF_TAG_NAME_LENGTH];
+ uint16_t id;
+};
+
+static const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification:
+ {"GPSVersionID", 0x00}, // <- Table 12 GPS Attribute Information
+ {"GPSLatitudeRef", 0x01},
+ {"GPSLatitude", 0x02},
+ {"GPSLongitudeRef", 0x03},
+ {"GPSLongitude", 0x04},
+ {"GPSAltitudeRef", 0x05},
+ {"GPSAltitude", 0x06},
+ {"GPSTimeStamp", 0x07},
+ {"GPSSatellites", 0x08},
+ {"GPSStatus", 0x09},
+ {"GPSMeasureMode", 0x0A},
+ {"GPSDOP", 0x0B},
+ {"GPSSpeedRef", 0x0C},
+ {"GPSSpeed", 0x0D},
+ {"GPSTrackRef", 0x0E},
+ {"GPSTrack", 0x0F},
+ {"GPSImgDirectionRef", 0x10},
+ {"GPSImgDirection", 0x11},
+ {"GPSMapDatum", 0x12},
+ {"GPSDestLatitudeRef", 0x13},
+ {"GPSDestLatitude", 0x14},
+ {"GPSDestLongitudeRef", 0x15},
+ {"GPSDestLongitude", 0x16},
+ {"GPSDestBearingRef", 0x17},
+ {"GPSDestBearing", 0x18},
+ {"GPSDestDistanceRef", 0x19},
+ {"GPSDestDistance", 0x1A},
+ {"GPSProcessingMethod", 0x1B},
+ {"GPSAreaInformation", 0x1C},
+ {"GPSDateStamp", 0x1D},
+ {"GPSDifferential", 0x1E},
+ {"ImageWidth", 0x100}, // <- Table 3 TIFF Rev. 6.0 Attribute Information Used in Exif
+ {"ImageLength", 0x101},
+ {"BitsPerSample", 0x102},
+ {"Compression", 0x103},
+ {"PhotometricInterpretation", 0x106},
+ {"Orientation", 0x112},
+ {"SamplesPerPixel", 0x115},
+ {"PlanarConfiguration", 0x11C},
+ {"YCbCrSubSampling", 0x212},
+ {"YCbCrPositioning", 0x213},
+ {"XResolution", 0x11A},
+ {"YResolution", 0x11B},
+ {"ResolutionUnit", 0x128},
+ {"StripOffsets", 0x111},
+ {"RowsPerStrip", 0x116},
+ {"StripByteCounts", 0x117},
+ {"JPEGInterchangeFormat", 0x201},
+ {"JPEGInterchangeFormatLength",0x202},
+ {"TransferFunction", 0x12D},
+ {"WhitePoint", 0x13E},
+ {"PrimaryChromaticities", 0x13F},
+ {"YCbCrCoefficients", 0x211},
+ {"ReferenceBlackWhite", 0x214},
+ {"DateTime", 0x132},
+ {"ImageDescription", 0x10E},
+ {"Make", 0x10F},
+ {"Model", 0x110},
+ {"Software", 0x131},
+ {"Artist", 0x13B},
+ {"Copyright", 0x8298},
+ {"ExifVersion", 0x9000}, // <- Table 4 Exif IFD Attribute Information (1)
+ {"FlashpixVersion", 0xA000},
+ {"ColorSpace", 0xA001},
+ {"ComponentsConfiguration", 0x9101},
+ {"CompressedBitsPerPixel", 0x9102},
+ {"PixelXDimension", 0xA002},
+ {"PixelYDimension", 0xA003},
+ {"MakerNote", 0x927C},
+ {"UserComment", 0x9286},
+ {"RelatedSoundFile", 0xA004},
+ {"DateTimeOriginal", 0x9003},
+ {"DateTimeDigitized", 0x9004},
+ {"SubSecTime", 0x9290},
+ {"SubSecTimeOriginal", 0x9291},
+ {"SubSecTimeDigitized", 0x9292},
+ {"ImageUniqueID", 0xA420},
+ {"ExposureTime", 0x829A}, // <- Table 5 Exif IFD Attribute Information (2)
+ {"FNumber", 0x829D},
+ {"ExposureProgram", 0x8822},
+ {"SpectralSensitivity", 0x8824},
+ {"ISOSpeedRatings", 0x8827},
+ {"OECF", 0x8828},
+ {"ShutterSpeedValue", 0x9201},
+ {"ApertureValue", 0x9202},
+ {"BrightnessValue", 0x9203},
+ {"ExposureBiasValue", 0x9204},
+ {"MaxApertureValue", 0x9205},
+ {"SubjectDistance", 0x9206},
+ {"MeteringMode", 0x9207},
+ {"LightSource", 0x9208},
+ {"Flash", 0x9209},
+ {"FocalLength", 0x920A},
+ {"SubjectArea", 0x9214},
+ {"FlashEnergy", 0xA20B},
+ {"SpatialFrequencyResponse", 0xA20C},
+ {"FocalPlaneXResolution", 0xA20E},
+ {"FocalPlaneYResolution", 0xA20F},
+ {"FocalPlaneResolutionUnit", 0xA210},
+ {"SubjectLocation", 0xA214},
+ {"ExposureIndex", 0xA215},
+ {"SensingMethod", 0xA217},
+ {"FileSource", 0xA300},
+ {"SceneType", 0xA301},
+ {"CFAPattern", 0xA302},
+ {"CustomRendered", 0xA401},
+ {"ExposureMode", 0xA402},
+ {"WhiteBalance", 0xA403},
+ {"DigitalZoomRatio", 0xA404},
+ {"FocalLengthIn35mmFilm", 0xA405},
+ {"SceneCaptureType", 0xA406},
+ {"GainControl", 0xA407},
+ {"Contrast", 0xA408},
+ {"Saturation", 0xA409},
+ {"Sharpness", 0xA40A},
+ {"DeviceSettingDescription", 0xA40B},
+ {"SubjectDistanceRange", 0xA40C}
+// {"InteroperabilityIndex", 0x1}, // <- Table 13 Interoperability IFD Attribute Information
+// {"", 0x0}
+};
+
+/** Recursively decodes all IFD's and
+ * adds included TAGS into the metadata dictionary. */
+int avpriv_exif_decode_ifd(AVCodecContext *avctx, GetByteContext *gbytes, int le,
+ int depth, AVDictionary **metadata);
+
+#endif /* AVCODEC_EXIF_H */
diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index 327a60e335..f9525ecf02 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -2,20 +2,20 @@
* OpenEXR (.exr) image decoder
* Copyright (c) 2009 Jimmy Christensen
*
- * This file is part of Libav
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -722,8 +722,8 @@ static int piz_uncompress(EXRContext *s, const uint8_t *src, int ssize,
if (!td->lut)
td->lut = av_malloc(1 << 17);
if (!td->bitmap || !td->lut) {
- av_free(td->bitmap);
- av_free(td->lut);
+ av_freep(&td->bitmap);
+ av_freep(&td->lut);
return AVERROR(ENOMEM);
}
diff --git a/libavcodec/faandct.h b/libavcodec/faandct.h
index 59d5ff3534..c5ef96dcf1 100644
--- a/libavcodec/faandct.h
+++ b/libavcodec/faandct.h
@@ -2,20 +2,20 @@
* Floating point AAN DCT
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/faanidct.c b/libavcodec/faanidct.c
index 2e9ce9ce1e..ca82f778ba 100644
--- a/libavcodec/faanidct.c
+++ b/libavcodec/faanidct.c
@@ -2,20 +2,20 @@
* Floating point AAN IDCT
* Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "faanidct.h"
diff --git a/libavcodec/faanidct.h b/libavcodec/faanidct.h
index 0c015201cc..4cd2c7858f 100644
--- a/libavcodec/faanidct.h
+++ b/libavcodec/faanidct.h
@@ -2,20 +2,20 @@
* Floating point AAN IDCT
* Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/faxcompr.c b/libavcodec/faxcompr.c
index 4cbda3f126..eb39ae0b20 100644
--- a/libavcodec/faxcompr.c
+++ b/libavcodec/faxcompr.c
@@ -2,20 +2,20 @@
* CCITT Fax Group 3 and 4 decompression
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -165,8 +165,6 @@ static int decode_group3_2d_line(AVCodecContext *avctx, GetBitContext *gb,
int run_off = *ref++;
unsigned int offs = 0, run = 0;
- runend--; // for the last written 0
-
while (offs < width) {
int cmode = get_vlc2(gb, ccitt_group3_2d_vlc.table, 9, 1);
if (cmode == -1) {
@@ -174,10 +172,12 @@ static int decode_group3_2d_line(AVCodecContext *avctx, GetBitContext *gb,
return AVERROR_INVALIDDATA;
}
if (!cmode) { //pass mode
- run_off += *ref++;
+ if (run_off < width)
+ run_off += *ref++;
run = run_off - offs;
offs = run_off;
- run_off += *ref++;
+ if (run_off < width)
+ run_off += *ref++;
if (offs > width) {
av_log(avctx, AV_LOG_ERROR, "Run went out of bounds\n");
return AVERROR_INVALIDDATA;
@@ -230,13 +230,19 @@ static int decode_group3_2d_line(AVCodecContext *avctx, GetBitContext *gb,
mode = !mode;
}
//sync line pointers
- while (run_off <= offs) {
+ while (offs < width && run_off <= offs) {
run_off += *ref++;
run_off += *ref++;
}
}
*runs++ = saved_run;
- *runs++ = 0;
+ if (saved_run) {
+ if (runs >= runend) {
+ av_log(avctx, AV_LOG_ERROR, "Run overrun\n");
+ return -1;
+ }
+ *runs++ = 0;
+ }
return 0;
}
@@ -245,7 +251,7 @@ static void put_line(uint8_t *dst, int size, int width, const int *runs)
PutBitContext pb;
int run, mode = ~0, pix_left = width, run_idx = 0;
- init_put_bits(&pb, dst, size * 8);
+ init_put_bits(&pb, dst, size);
while (pix_left > 0) {
run = runs[run_idx++];
mode = ~mode;
@@ -279,9 +285,10 @@ int ff_ccitt_unpack(AVCodecContext *avctx, const uint8_t *src, int srcsize,
int *runs, *ref = NULL, *runend;
int ret;
int runsize = avctx->width + 2;
+ int has_eol;
- runs = av_malloc(runsize * sizeof(runs[0]));
- ref = av_malloc(runsize * sizeof(ref[0]));
+ runs = av_malloc_array(runsize, sizeof(runs[0]));
+ ref = av_malloc_array(runsize, sizeof(ref[0]));
if (!runs || !ref) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -289,7 +296,10 @@ int ff_ccitt_unpack(AVCodecContext *avctx, const uint8_t *src, int srcsize,
ref[0] = avctx->width;
ref[1] = 0;
ref[2] = 0;
- init_get_bits(&gb, src, srcsize * 8);
+ if ((ret = init_get_bits8(&gb, src, srcsize)) < 0)
+ goto fail;
+ has_eol = show_bits(&gb, 12) == 1 || show_bits(&gb, 16) == 1;
+
for (j = 0; j < height; j++) {
runend = runs + runsize;
if (compr == TIFF_G4) {
@@ -300,6 +310,7 @@ int ff_ccitt_unpack(AVCodecContext *avctx, const uint8_t *src, int srcsize,
} else {
int g3d1 = (compr == TIFF_G3) && !(opts & 1);
if (compr != TIFF_CCITT_RLE &&
+ has_eol &&
find_group3_syncmarker(&gb, srcsize * 8) < 0)
break;
if (compr == TIFF_CCITT_RLE || g3d1 || get_bits1(&gb))
diff --git a/libavcodec/faxcompr.h b/libavcodec/faxcompr.h
index 8157f1fc21..53d11681b2 100644
--- a/libavcodec/faxcompr.h
+++ b/libavcodec/faxcompr.h
@@ -2,20 +2,20 @@
* CCITT Fax Group 3 and 4 decompression
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/fdctdsp.c b/libavcodec/fdctdsp.c
index f299eae272..b9c2c86322 100644
--- a/libavcodec/fdctdsp.c
+++ b/libavcodec/fdctdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@ av_cold void ff_fdctdsp_init(FDCTDSPContext *c, AVCodecContext *avctx)
{
const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (avctx->bits_per_raw_sample == 10) {
+ if (avctx->bits_per_raw_sample == 10 || avctx->bits_per_raw_sample == 9) {
c->fdct = ff_jpeg_fdct_islow_10;
c->fdct248 = ff_fdct248_islow_10;
} else if (avctx->dct_algo == FF_DCT_FASTINT) {
diff --git a/libavcodec/fdctdsp.h b/libavcodec/fdctdsp.h
index 944dc6d1bf..3e1f683b9e 100644
--- a/libavcodec/fdctdsp.h
+++ b/libavcodec/fdctdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/fft-fixed-test.c b/libavcodec/fft-fixed-test.c
index d6ea987fa3..330211ebf6 100644
--- a/libavcodec/fft-fixed-test.c
+++ b/libavcodec/fft-fixed-test.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/fft-fixed32-test.c b/libavcodec/fft-fixed32-test.c
new file mode 100644
index 0000000000..4bd11cea61
--- /dev/null
+++ b/libavcodec/fft-fixed32-test.c
@@ -0,0 +1,21 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 FFT_FLOAT 0
+#define FFT_FIXED_32 1
+#include "fft-test.c"
diff --git a/libavcodec/fft-internal.h b/libavcodec/fft-internal.h
index a449ec058a..0a8f7d05cf 100644
--- a/libavcodec/fft-internal.h
+++ b/libavcodec/fft-internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,12 +36,29 @@
#else
+#define SCALE_FLOAT(a, bits) lrint((a) * (double)(1 << (bits)))
+
+#if FFT_FIXED_32
+
+#define CMUL(dre, dim, are, aim, bre, bim) do { \
+ int64_t accu; \
+ (accu) = (int64_t)(bre) * (are); \
+ (accu) -= (int64_t)(bim) * (aim); \
+ (dre) = (int)(((accu) + 0x40000000) >> 31); \
+ (accu) = (int64_t)(bre) * (aim); \
+ (accu) += (int64_t)(bim) * (are); \
+ (dim) = (int)(((accu) + 0x40000000) >> 31); \
+ } while (0)
+
+#define FIX15(a) av_clip(SCALE_FLOAT(a, 31), -2147483647, 2147483647)
+
+#else /* FFT_FIXED_32 */
+
#include "fft.h"
#include "mathops.h"
void ff_mdct_calcw_c(FFTContext *s, FFTDouble *output, const FFTSample *input);
-#define SCALE_FLOAT(a, bits) lrint((a) * (double)(1 << (bits)))
#define FIX15(a) av_clip(SCALE_FLOAT(a, 15), -32767, 32767)
#define sqrthalf ((int16_t)((1<<15)*M_SQRT1_2))
@@ -62,6 +79,8 @@ void ff_mdct_calcw_c(FFTContext *s, FFTDouble *output, const FFTSample *input);
#define CMULL(dre, dim, are, aim, bre, bim) \
CMULS(dre, dim, are, aim, bre, bim, 0)
+#endif /* FFT_FIXED_32 */
+
#endif /* FFT_FLOAT */
#define ff_imdct_calc_c FFT_NAME(ff_imdct_calc_c)
diff --git a/libavcodec/fft-test.c b/libavcodec/fft-test.c
index b7c83cf800..ba26f81f44 100644
--- a/libavcodec/fft-test.c
+++ b/libavcodec/fft-test.c
@@ -1,20 +1,20 @@
/*
* (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,6 +59,10 @@
#define RANGE 1.0
#define REF_SCALE(x, bits) (x)
#define FMT "%10.6f"
+#elif FFT_FIXED_32
+#define RANGE 8388608
+#define REF_SCALE(x, bits) (x)
+#define FMT "%6d"
#else
#define RANGE 16384
#define REF_SCALE(x, bits) ((x) / (1 << (bits)))
@@ -73,7 +77,7 @@ static int fft_ref_init(int nbits, int inverse)
{
int i, n = 1 << nbits;
- exptab = av_malloc((n / 2) * sizeof(*exptab));
+ exptab = av_malloc_array((n / 2), sizeof(*exptab));
if (!exptab)
return AVERROR(ENOMEM);
@@ -150,7 +154,7 @@ static void mdct_ref(FFTSample *output, FFTSample *input, int nbits)
#if FFT_FLOAT
#if CONFIG_DCT
-static void idct_ref(float *output, float *input, int nbits)
+static void idct_ref(FFTSample *output, FFTSample *input, int nbits)
{
int i, k, n = 1 << nbits;
@@ -165,7 +169,7 @@ static void idct_ref(float *output, float *input, int nbits)
}
}
-static void dct_ref(float *output, float *input, int nbits)
+static void dct_ref(FFTSample *output, FFTSample *input, int nbits)
{
int i, k, n = 1 << nbits;
@@ -203,7 +207,7 @@ static int check_diff(FFTSample *tab1, FFTSample *tab2, int n, double scale)
if (e > max)
max = e;
}
- av_log(NULL, AV_LOG_INFO, "max:%f e:%g\n", max, sqrt(error) / n);
+ av_log(NULL, AV_LOG_INFO, "max:%f e:%g\n", max, sqrt(error / n));
return err;
}
@@ -281,20 +285,22 @@ int main(int argc, char **argv)
break;
case 'c':
{
- int cpuflags = av_parse_cpu_flags(optarg);
- if (cpuflags < 0)
+ int cpuflags = av_get_cpu_flags();
+
+ if (av_parse_cpu_caps(&cpuflags, optarg) < 0)
return 1;
- av_set_cpu_flags_mask(cpuflags);
+
+ av_force_cpu_flags(cpuflags);
break;
}
}
}
fft_size = 1 << fft_nbits;
- tab = av_malloc(fft_size * sizeof(FFTComplex));
- tab1 = av_malloc(fft_size * sizeof(FFTComplex));
- tab_ref = av_malloc(fft_size * sizeof(FFTComplex));
- tab2 = av_malloc(fft_size * sizeof(FFTSample));
+ tab = av_malloc_array(fft_size, sizeof(FFTComplex));
+ tab1 = av_malloc_array(fft_size, sizeof(FFTComplex));
+ tab_ref = av_malloc_array(fft_size, sizeof(FFTComplex));
+ tab2 = av_malloc_array(fft_size, sizeof(FFTSample));
if (!(tab && tab1 && tab_ref && tab2))
goto cleanup;
@@ -316,22 +322,22 @@ int main(int argc, char **argv)
else
av_log(NULL, AV_LOG_INFO, "FFT");
ff_fft_init(&s, fft_nbits, do_inverse);
- if (err = fft_ref_init(fft_nbits, do_inverse) < 0)
+ if ((err = fft_ref_init(fft_nbits, do_inverse)) < 0)
goto cleanup;
break;
#if FFT_FLOAT
-#if CONFIG_RDFT
+# if CONFIG_RDFT
case TRANSFORM_RDFT:
if (do_inverse)
av_log(NULL, AV_LOG_INFO, "IDFT_C2R");
else
av_log(NULL, AV_LOG_INFO, "DFT_R2C");
ff_rdft_init(&r, fft_nbits, do_inverse ? IDFT_C2R : DFT_R2C);
- if (err = fft_ref_init(fft_nbits, do_inverse) < 0)
+ if ((err = fft_ref_init(fft_nbits, do_inverse)) < 0)
goto cleanup;
break;
-#endif /* CONFIG_RDFT */
-#if CONFIG_DCT
+# endif /* CONFIG_RDFT */
+# if CONFIG_DCT
case TRANSFORM_DCT:
if (do_inverse)
av_log(NULL, AV_LOG_INFO, "DCT_III");
@@ -339,7 +345,7 @@ int main(int argc, char **argv)
av_log(NULL, AV_LOG_INFO, "DCT_II");
ff_dct_init(&d, fft_nbits, do_inverse ? DCT_III : DCT_II);
break;
-#endif /* CONFIG_DCT */
+# endif /* CONFIG_DCT */
#endif /* FFT_FLOAT */
default:
av_log(NULL, AV_LOG_ERROR, "Requested transform not supported\n");
@@ -486,16 +492,16 @@ int main(int argc, char **argv)
ff_fft_end(&s);
break;
#if FFT_FLOAT
-#if CONFIG_RDFT
+# if CONFIG_RDFT
case TRANSFORM_RDFT:
ff_rdft_end(&r);
break;
-#endif /* CONFIG_RDFT */
-#if CONFIG_DCT
+# endif /* CONFIG_RDFT */
+# if CONFIG_DCT
case TRANSFORM_DCT:
ff_dct_end(&d);
break;
-#endif /* CONFIG_DCT */
+# endif /* CONFIG_DCT */
#endif /* FFT_FLOAT */
}
diff --git a/libavcodec/fft.h b/libavcodec/fft.h
index 7daae24ca3..64f0f6331e 100644
--- a/libavcodec/fft.h
+++ b/libavcodec/fft.h
@@ -2,20 +2,20 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,10 @@
#define FFT_FLOAT 1
#endif
+#ifndef FFT_FIXED_32
+#define FFT_FIXED_32 0
+#endif
+
#include <stdint.h>
#include "config.h"
#include "libavutil/mem.h"
@@ -40,15 +44,26 @@ typedef float FFTDouble;
#else
+#if FFT_FIXED_32
+
+#define Q31(x) (int)((x)*2147483648.0 + 0.5)
+#define FFT_NAME(x) x ## _fixed_32
+
+typedef int32_t FFTSample;
+
+#else /* FFT_FIXED_32 */
+
#define FFT_NAME(x) x ## _fixed
typedef int16_t FFTSample;
-typedef int FFTDouble;
+
+#endif /* FFT_FIXED_32 */
typedef struct FFTComplex {
- int16_t re, im;
+ FFTSample re, im;
} FFTComplex;
+typedef int FFTDouble;
typedef struct FFTContext FFTContext;
#endif /* FFT_FLOAT */
@@ -142,6 +157,7 @@ int ff_fft_init(FFTContext *s, int nbits, int inverse);
void ff_fft_init_aarch64(FFTContext *s);
void ff_fft_init_x86(FFTContext *s);
void ff_fft_init_arm(FFTContext *s);
+void ff_fft_init_mips(FFTContext *s);
void ff_fft_init_ppc(FFTContext *s);
void ff_fft_fixed_init_arm(FFTContext *s);
diff --git a/libavcodec/fft_fixed.c b/libavcodec/fft_fixed.c
index bad482148b..3d3bd2fca6 100644
--- a/libavcodec/fft_fixed.c
+++ b/libavcodec/fft_fixed.c
@@ -1,20 +1,21 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FFT_FLOAT 0
+#define FFT_FIXED_32 0
#include "fft_template.c"
diff --git a/libavcodec/fft_fixed_32.c b/libavcodec/fft_fixed_32.c
new file mode 100644
index 0000000000..fbdbf847e2
--- /dev/null
+++ b/libavcodec/fft_fixed_32.c
@@ -0,0 +1,52 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ * Goran Cordasic (goran@mips.com)
+ * Djordje Pesut (djordje@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
+ */
+
+#define FFT_FLOAT 0
+#define FFT_FIXED_32 1
+#include "fft_template.c"
diff --git a/libavcodec/fft_float.c b/libavcodec/fft_float.c
index ed4cffa11c..73cc98d0d4 100644
--- a/libavcodec/fft_float.c
+++ b/libavcodec/fft_float.c
@@ -1,20 +1,21 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FFT_FLOAT 1
+#define FFT_FIXED_32 0
#include "fft_template.c"
diff --git a/libavcodec/fft_init_table.c b/libavcodec/fft_init_table.c
new file mode 100644
index 0000000000..4d74f8a2a2
--- /dev/null
+++ b/libavcodec/fft_init_table.c
@@ -0,0 +1,200 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ * Goran Cordasic (goran@mips.com)
+ * Djordje Pesut (djordje@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
+ * definitions and initialization of LUT table for FFT
+ */
+#include "libavcodec/fft_table.h"
+
+const int32_t ff_w_tab_sr[MAX_FFT_SIZE/(4*16)] = {
+ 2147483647, 2147481121, 2147473542, 2147460908, 2147443222, 2147420483, 2147392690, 2147359845,
+ 2147321946, 2147278995, 2147230991, 2147177934, 2147119825, 2147056664, 2146988450, 2146915184,
+ 2146836866, 2146753497, 2146665076, 2146571603, 2146473080, 2146369505, 2146260881, 2146147205,
+ 2146028480, 2145904705, 2145775880, 2145642006, 2145503083, 2145359112, 2145210092, 2145056025,
+ 2144896910, 2144732748, 2144563539, 2144389283, 2144209982, 2144025635, 2143836244, 2143641807,
+ 2143442326, 2143237802, 2143028234, 2142813624, 2142593971, 2142369276, 2142139541, 2141904764,
+ 2141664948, 2141420092, 2141170197, 2140915264, 2140655293, 2140390284, 2140120240, 2139845159,
+ 2139565043, 2139279892, 2138989708, 2138694490, 2138394240, 2138088958, 2137778644, 2137463301,
+ 2137142927, 2136817525, 2136487095, 2136151637, 2135811153, 2135465642, 2135115107, 2134759548,
+ 2134398966, 2134033361, 2133662734, 2133287087, 2132906420, 2132520734, 2132130030, 2131734309,
+ 2131333572, 2130927819, 2130517052, 2130101272, 2129680480, 2129254676, 2128823862, 2128388038,
+ 2127947206, 2127501367, 2127050522, 2126594672, 2126133817, 2125667960, 2125197100, 2124721240,
+ 2124240380, 2123754522, 2123263666, 2122767814, 2122266967, 2121761126, 2121250292, 2120734467,
+ 2120213651, 2119687847, 2119157054, 2118621275, 2118080511, 2117534762, 2116984031, 2116428319,
+ 2115867626, 2115301954, 2114731305, 2114155680, 2113575080, 2112989506, 2112398960, 2111803444,
+ 2111202959, 2110597505, 2109987085, 2109371700, 2108751352, 2108126041, 2107495770, 2106860540,
+ 2106220352, 2105575208, 2104925109, 2104270057, 2103610054, 2102945101, 2102275199, 2101600350,
+ 2100920556, 2100235819, 2099546139, 2098851519, 2098151960, 2097447464, 2096738032, 2096023667,
+ 2095304370, 2094580142, 2093850985, 2093116901, 2092377892, 2091633960, 2090885105, 2090131331,
+ 2089372638, 2088609029, 2087840505, 2087067068, 2086288720, 2085505463, 2084717298, 2083924228,
+ 2083126254, 2082323379, 2081515603, 2080702930, 2079885360, 2079062896, 2078235540, 2077403294,
+ 2076566160, 2075724139, 2074877233, 2074025446, 2073168777, 2072307231, 2071440808, 2070569511,
+ 2069693342, 2068812302, 2067926394, 2067035621, 2066139983, 2065239484, 2064334124, 2063423908,
+ 2062508835, 2061588910, 2060664133, 2059734508, 2058800036, 2057860719, 2056916560, 2055967560,
+ 2055013723, 2054055050, 2053091544, 2052123207, 2051150040, 2050172048, 2049189231, 2048201592,
+ 2047209133, 2046211857, 2045209767, 2044202863, 2043191150, 2042174628, 2041153301, 2040127172,
+ 2039096241, 2038060512, 2037019988, 2035974670, 2034924562, 2033869665, 2032809982, 2031745516,
+ 2030676269, 2029602243, 2028523442, 2027439867, 2026351522, 2025258408, 2024160529, 2023057887,
+ 2021950484, 2020838323, 2019721407, 2018599739, 2017473321, 2016342155, 2015206245, 2014065592,
+ 2012920201, 2011770073, 2010615210, 2009455617, 2008291295, 2007122248, 2005948478, 2004769987,
+ 2003586779, 2002398857, 2001206222, 2000008879, 1998806829, 1997600076, 1996388622, 1995172471,
+ 1993951625, 1992726087, 1991495860, 1990260946, 1989021350, 1987777073, 1986528118, 1985274489,
+ 1984016189, 1982753220, 1981485585, 1980213288, 1978936331, 1977654717, 1976368450, 1975077532,
+ 1973781967, 1972481757, 1971176906, 1969867417, 1968553292, 1967234535, 1965911148, 1964583136,
+ 1963250501, 1961913246, 1960571375, 1959224890, 1957873796, 1956518093, 1955157788, 1953792881,
+ 1952423377, 1951049279, 1949670589, 1948287312, 1946899451, 1945507008, 1944109987, 1942708392,
+ 1941302225, 1939891490, 1938476190, 1937056329, 1935631910, 1934202936, 1932769411, 1931331338,
+ 1929888720, 1928441561, 1926989864, 1925533633, 1924072871, 1922607581, 1921137767, 1919663432,
+ 1918184581, 1916701216, 1915213340, 1913720958, 1912224073, 1910722688, 1909216806, 1907706433,
+ 1906191570, 1904672222, 1903148392, 1901620084, 1900087301, 1898550047, 1897008325, 1895462140,
+ 1893911494, 1892356392, 1890796837, 1889232832, 1887664383, 1886091491, 1884514161, 1882932397,
+ 1881346202, 1879755580, 1878160535, 1876561070, 1874957189, 1873348897, 1871736196, 1870119091,
+ 1868497586, 1866871683, 1865241388, 1863606704, 1861967634, 1860324183, 1858676355, 1857024153,
+ 1855367581, 1853706643, 1852041343, 1850371686, 1848697674, 1847019312, 1845336604, 1843649553,
+ 1841958164, 1840262441, 1838562388, 1836858008, 1835149306, 1833436286, 1831718951, 1829997307,
+ 1828271356, 1826541103, 1824806552, 1823067707, 1821324572, 1819577151, 1817825449, 1816069469,
+ 1814309216, 1812544694, 1810775906, 1809002858, 1807225553, 1805443995, 1803658189, 1801868139,
+ 1800073849, 1798275323, 1796472565, 1794665580, 1792854372, 1791038946, 1789219305, 1787395453,
+ 1785567396, 1783735137, 1781898681, 1780058032, 1778213194, 1776364172, 1774510970, 1772653593,
+ 1770792044, 1768926328, 1767056450, 1765182414, 1763304224, 1761421885, 1759535401, 1757644777,
+ 1755750017, 1753851126, 1751948107, 1750040966, 1748129707, 1746214334, 1744294853, 1742371267,
+ 1740443581, 1738511799, 1736575927, 1734635968, 1732691928, 1730743810, 1728791620, 1726835361,
+ 1724875040, 1722910659, 1720942225, 1718969740, 1716993211, 1715012642, 1713028037, 1711039401,
+ 1709046739, 1707050055, 1705049355, 1703044642, 1701035922, 1699023199, 1697006479, 1694985765,
+ 1692961062, 1690932376, 1688899711, 1686863072, 1684822463, 1682777890, 1680729357, 1678676870,
+ 1676620432, 1674560049, 1672495725, 1670427466, 1668355276, 1666279161, 1664199124, 1662115172,
+ 1660027308, 1657935539, 1655839867, 1653740300, 1651636841, 1649529496, 1647418269, 1645303166,
+ 1643184191, 1641061349, 1638934646, 1636804087, 1634669676, 1632531418, 1630389319, 1628243383,
+ 1626093616, 1623940023, 1621782608, 1619621377, 1617456335, 1615287487, 1613114838, 1610938393,
+ 1608758157, 1606574136, 1604386335, 1602194758, 1599999411, 1597800299, 1595597428, 1593390801,
+ 1591180426, 1588966306, 1586748447, 1584526854, 1582301533, 1580072489, 1577839726, 1575603251,
+ 1573363068, 1571119183, 1568871601, 1566620327, 1564365367, 1562106725, 1559844408, 1557578421,
+ 1555308768, 1553035455, 1550758488, 1548477872, 1546193612, 1543905714, 1541614183, 1539319024,
+ 1537020244, 1534717846, 1532411837, 1530102222, 1527789007, 1525472197, 1523151797, 1520827813,
+ 1518500250, 1516169114, 1513834411, 1511496145, 1509154322, 1506808949, 1504460029, 1502107570,
+ 1499751576, 1497392053, 1495029006, 1492662441, 1490292364, 1487918781, 1485541696, 1483161115,
+ 1480777044, 1478389489, 1475998456, 1473603949, 1471205974, 1468804538, 1466399645, 1463991302,
+ 1461579514, 1459164286, 1456745625, 1454323536, 1451898025, 1449469098, 1447036760, 1444601017,
+ 1442161874, 1439719338, 1437273414, 1434824109, 1432371426, 1429915374, 1427455956, 1424993180,
+ 1422527051, 1420057574, 1417584755, 1415108601, 1412629117, 1410146309, 1407660183, 1405170745,
+ 1402678000, 1400181954, 1397682613, 1395179984, 1392674072, 1390164882, 1387652422, 1385136696,
+ 1382617710, 1380095472, 1377569986, 1375041258, 1372509294, 1369974101, 1367435685, 1364894050,
+ 1362349204, 1359801152, 1357249901, 1354695455, 1352137822, 1349577007, 1347013017, 1344445857,
+ 1341875533, 1339302052, 1336725419, 1334145641, 1331562723, 1328976672, 1326387494, 1323795195,
+ 1321199781, 1318601257, 1315999631, 1313394909, 1310787095, 1308176198, 1305562222, 1302945174,
+ 1300325060, 1297701886, 1295075659, 1292446384, 1289814068, 1287178717, 1284540337, 1281898935,
+ 1279254516, 1276607086, 1273956653, 1271303222, 1268646800, 1265987392, 1263325005, 1260659646,
+ 1257991320, 1255320034, 1252645794, 1249968606, 1247288478, 1244605414, 1241919421, 1239230506,
+ 1236538675, 1233843935, 1231146291, 1228445750, 1225742318, 1223036002, 1220326809, 1217614743,
+ 1214899813, 1212182024, 1209461382, 1206737894, 1204011567, 1201282407, 1198550419, 1195815612,
+ 1193077991, 1190337562, 1187594332, 1184848308, 1182099496, 1179347902, 1176593533, 1173836395,
+ 1171076495, 1168313840, 1165548435, 1162780288, 1160009405, 1157235792, 1154459456, 1151680403,
+ 1148898640, 1146114174, 1143327011, 1140537158, 1137744621, 1134949406, 1132151521, 1129350972,
+ 1126547765, 1123741908, 1120933406, 1118122267, 1115308496, 1112492101, 1109673089, 1106851465,
+ 1104027237, 1101200410, 1098370993, 1095538991, 1092704411, 1089867259, 1087027544, 1084185270,
+ 1081340445, 1078493076, 1075643169, 1072790730, 1069935768, 1067078288, 1064218296, 1061355801,
+ 1058490808, 1055623324, 1052753357, 1049880912, 1047005996, 1044128617, 1041248781, 1038366495,
+ 1035481766, 1032594600, 1029705004, 1026812985, 1023918550, 1021021705, 1018122458, 1015220816,
+ 1012316784, 1009410370, 1006501581, 1003590424, 1000676905, 997761031, 994842810, 991922248,
+ 988999351, 986074127, 983146583, 980216726, 977284562, 974350098, 971413342, 968474300,
+ 965532978, 962589385, 959643527, 956695411, 953745043, 950792431, 947837582, 944880503,
+ 941921200, 938959681, 935995952, 933030021, 930061894, 927091579, 924119082, 921144411,
+ 918167572, 915188572, 912207419, 909224120, 906238681, 903251110, 900261413, 897269597,
+ 894275671, 891279640, 888281512, 885281293, 882278992, 879274614, 876268167, 873259659,
+ 870249095, 867236484, 864221832, 861205147, 858186435, 855165703, 852142959, 849118210,
+ 846091463, 843062726, 840032004, 836999305, 833964638, 830928007, 827889422, 824848888,
+ 821806413, 818762005, 815715670, 812667415, 809617249, 806565177, 803511207, 800455346,
+ 797397602, 794337982, 791276492, 788213141, 785147934, 782080880, 779011986, 775941259,
+ 772868706, 769794334, 766718151, 763640164, 760560380, 757478806, 754395449, 751310318,
+ 748223418, 745134758, 742044345, 738952186, 735858287, 732762657, 729665303, 726566232,
+ 723465451, 720362968, 717258790, 714152924, 711045377, 707936158, 704825272, 701712728,
+ 698598533, 695482694, 692365218, 689246113, 686125387, 683003045, 679879097, 676753549,
+ 673626408, 670497682, 667367379, 664235505, 661102068, 657967075, 654830535, 651692453,
+ 648552838, 645411696, 642269036, 639124865, 635979190, 632832018, 629683357, 626533215,
+ 623381598, 620228514, 617073971, 613917975, 610760536, 607601658, 604441352, 601279623,
+ 598116479, 594951927, 591785976, 588618632, 585449903, 582279796, 579108320, 575935480,
+ 572761285, 569585743, 566408860, 563230645, 560051104, 556870245, 553688076, 550504604,
+ 547319836, 544133781, 540946445, 537757837, 534567963, 531376831, 528184449, 524990824,
+ 521795963, 518599875, 515402566, 512204045, 509004318, 505803394, 502601279, 499397982,
+ 496193509, 492987869, 489781069, 486573117, 483364019, 480153784, 476942419, 473729932,
+ 470516330, 467301622, 464085813, 460868912, 457650927, 454431865, 451211734, 447990541,
+ 444768294, 441545000, 438320667, 435095303, 431868915, 428641511, 425413098, 422183684,
+ 418953276, 415721883, 412489512, 409256170, 406021865, 402786604, 399550396, 396313247,
+ 393075166, 389836160, 386596237, 383355404, 380113669, 376871039, 373627523, 370383128,
+ 367137861, 363891730, 360644742, 357396906, 354148230, 350898719, 347648383, 344397230,
+ 341145265, 337892498, 334638936, 331384586, 328129457, 324873555, 321616889, 318359466,
+ 315101295, 311842381, 308582734, 305322361, 302061269, 298799466, 295536961, 292273760,
+ 289009871, 285745302, 282480061, 279214155, 275947592, 272680379, 269412525, 266144038,
+ 262874923, 259605191, 256334847, 253063900, 249792358, 246520228, 243247518, 239974235,
+ 236700388, 233425984, 230151030, 226875535, 223599506, 220322951, 217045878, 213768293,
+ 210490206, 207211624, 203932553, 200653003, 197372981, 194092495, 190811551, 187530159,
+ 184248325, 180966058, 177683365, 174400254, 171116733, 167832808, 164548489, 161263783,
+ 157978697, 154693240, 151407418, 148121241, 144834714, 141547847, 138260647, 134973122,
+ 131685278, 128397125, 125108670, 121819921, 118530885, 115241570, 111951983, 108662134,
+ 105372028, 102081675, 98791081, 95500255, 92209205, 88917937, 85626460, 82334782,
+ 79042909, 75750851, 72458615, 69166208, 65873638, 62580914, 59288042, 55995030,
+ 52701887, 49408620, 46115236, 42821744, 39528151, 36234466, 32940695, 29646846,
+ 26352928, 23058947, 19764913, 16470832, 13176712, 9882561, 6588387, 3294197
+};
+
+uint16_t ff_fft_offsets_lut[0x2aab];
+
+void ff_fft_lut_init(uint16_t *table, int off, int size, int *index)
+{
+ if (size < 16) {
+ table[*index] = off >> 2;
+ (*index)++;
+ }
+ else {
+ ff_fft_lut_init(table, off, size>>1, index);
+ ff_fft_lut_init(table, off+(size>>1), size>>2, index);
+ ff_fft_lut_init(table, off+3*(size>>2), size>>2, index);
+ }
+}
diff --git a/libavcodec/fft_table.h b/libavcodec/fft_table.h
new file mode 100644
index 0000000000..e5e54b6efa
--- /dev/null
+++ b/libavcodec/fft_table.h
@@ -0,0 +1,66 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ * Goran Cordasic (goran@mips.com)
+ * Djordje Pesut (djordje@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
+ * definitions and tables for FFT
+ */
+#ifndef AVCODEC_FFT_TABLE_H
+#define AVCODEC_FFT_TABLE_H
+
+#include "libavcodec/fft.h"
+
+#define MAX_LOG2_NFFT 16 //!< Specifies maximum allowed fft size
+#define MAX_FFT_SIZE (1 << MAX_LOG2_NFFT)
+
+extern const int32_t ff_w_tab_sr[];
+extern uint16_t ff_fft_offsets_lut[];
+void ff_fft_lut_init(uint16_t *table, int off, int size, int *index);
+
+#endif /* AVCODEC_FFT_TABLE_H */
diff --git a/libavcodec/fft_template.c b/libavcodec/fft_template.c
index 808f317c17..23ea453938 100644
--- a/libavcodec/fft_template.c
+++ b/libavcodec/fft_template.c
@@ -4,20 +4,20 @@
* Copyright (c) 2002 Fabrice Bellard
* Partly based on libdjbfft by D. J. Bernstein
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,10 @@
#include "fft.h"
#include "fft-internal.h"
+#if FFT_FIXED_32
+#include "fft_table.h"
+#else /* FFT_FIXED_32 */
+
/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */
#if !CONFIG_HARDCODED_TABLES
COSTABLE(16);
@@ -65,6 +69,8 @@ COSTABLE_CONST FFTSample * const FFT_NAME(ff_cos_tabs)[] = {
FFT_NAME(ff_cos_65536),
};
+#endif /* FFT_FIXED_32 */
+
static void fft_permute_c(FFTContext *s, FFTComplex *z);
static void fft_calc_c(FFTContext *s, FFTComplex *z);
@@ -81,7 +87,7 @@ static int split_radix_permutation(int i, int n, int inverse)
av_cold void ff_init_ff_cos_tabs(int index)
{
-#if !CONFIG_HARDCODED_TABLES
+#if (!CONFIG_HARDCODED_TABLES) && (!FFT_FIXED_32)
int i;
int m = 1<<index;
double freq = 2*M_PI/m;
@@ -157,26 +163,34 @@ av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse)
s->mdct_calc = ff_mdct_calc_c;
#endif
+#if FFT_FIXED_32
+ {
+ int n=0;
+ ff_fft_lut_init(ff_fft_offsets_lut, 0, 1 << 16, &n);
+ }
+#else /* FFT_FIXED_32 */
#if FFT_FLOAT
if (ARCH_AARCH64) ff_fft_init_aarch64(s);
if (ARCH_ARM) ff_fft_init_arm(s);
if (ARCH_PPC) ff_fft_init_ppc(s);
if (ARCH_X86) ff_fft_init_x86(s);
if (CONFIG_MDCT) s->mdct_calcw = s->mdct_calc;
+ if (HAVE_MIPSFPU) ff_fft_init_mips(s);
#else
if (CONFIG_MDCT) s->mdct_calcw = ff_mdct_calcw_c;
if (ARCH_ARM) ff_fft_fixed_init_arm(s);
#endif
-
for(j=4; j<=nbits; j++) {
ff_init_ff_cos_tabs(j);
}
+#endif /* FFT_FIXED_32 */
+
if (s->fft_permutation == FF_FFT_PERM_AVX) {
fft_perm_avx(s);
} else {
for(i=0; i<n; i++) {
- int j = i;
+ j = i;
if (s->fft_permutation == FF_FFT_PERM_SWAP_LSBS)
j = (j&~3) | ((j>>1)&1) | ((j<<1)&2);
s->revtab[-split_radix_permutation(i, n, s->inverse) & (n-1)] = j;
@@ -206,6 +220,166 @@ av_cold void ff_fft_end(FFTContext *s)
av_freep(&s->tmp_buf);
}
+#if FFT_FIXED_32
+
+static void fft_calc_c(FFTContext *s, FFTComplex *z) {
+
+ int nbits, i, n, num_transforms, offset, step;
+ int n4, n2, n34;
+ FFTSample tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
+ FFTComplex *tmpz;
+ const int fft_size = (1 << s->nbits);
+ int64_t accu;
+
+ num_transforms = (0x2aab >> (16 - s->nbits)) | 1;
+
+ for (n=0; n<num_transforms; n++){
+ offset = ff_fft_offsets_lut[n] << 2;
+ tmpz = z + offset;
+
+ tmp1 = tmpz[0].re + tmpz[1].re;
+ tmp5 = tmpz[2].re + tmpz[3].re;
+ tmp2 = tmpz[0].im + tmpz[1].im;
+ tmp6 = tmpz[2].im + tmpz[3].im;
+ tmp3 = tmpz[0].re - tmpz[1].re;
+ tmp8 = tmpz[2].im - tmpz[3].im;
+ tmp4 = tmpz[0].im - tmpz[1].im;
+ tmp7 = tmpz[2].re - tmpz[3].re;
+
+ tmpz[0].re = tmp1 + tmp5;
+ tmpz[2].re = tmp1 - tmp5;
+ tmpz[0].im = tmp2 + tmp6;
+ tmpz[2].im = tmp2 - tmp6;
+ tmpz[1].re = tmp3 + tmp8;
+ tmpz[3].re = tmp3 - tmp8;
+ tmpz[1].im = tmp4 - tmp7;
+ tmpz[3].im = tmp4 + tmp7;
+ }
+
+ if (fft_size < 8)
+ return;
+
+ num_transforms = (num_transforms >> 1) | 1;
+
+ for (n=0; n<num_transforms; n++){
+ offset = ff_fft_offsets_lut[n] << 3;
+ tmpz = z + offset;
+
+ tmp1 = tmpz[4].re + tmpz[5].re;
+ tmp3 = tmpz[6].re + tmpz[7].re;
+ tmp2 = tmpz[4].im + tmpz[5].im;
+ tmp4 = tmpz[6].im + tmpz[7].im;
+ tmp5 = tmp1 + tmp3;
+ tmp7 = tmp1 - tmp3;
+ tmp6 = tmp2 + tmp4;
+ tmp8 = tmp2 - tmp4;
+
+ tmp1 = tmpz[4].re - tmpz[5].re;
+ tmp2 = tmpz[4].im - tmpz[5].im;
+ tmp3 = tmpz[6].re - tmpz[7].re;
+ tmp4 = tmpz[6].im - tmpz[7].im;
+
+ tmpz[4].re = tmpz[0].re - tmp5;
+ tmpz[0].re = tmpz[0].re + tmp5;
+ tmpz[4].im = tmpz[0].im - tmp6;
+ tmpz[0].im = tmpz[0].im + tmp6;
+ tmpz[6].re = tmpz[2].re - tmp8;
+ tmpz[2].re = tmpz[2].re + tmp8;
+ tmpz[6].im = tmpz[2].im + tmp7;
+ tmpz[2].im = tmpz[2].im - tmp7;
+
+ accu = (int64_t)Q31(M_SQRT1_2)*(tmp1 + tmp2);
+ tmp5 = (int32_t)((accu + 0x40000000) >> 31);
+ accu = (int64_t)Q31(M_SQRT1_2)*(tmp3 - tmp4);
+ tmp7 = (int32_t)((accu + 0x40000000) >> 31);
+ accu = (int64_t)Q31(M_SQRT1_2)*(tmp2 - tmp1);
+ tmp6 = (int32_t)((accu + 0x40000000) >> 31);
+ accu = (int64_t)Q31(M_SQRT1_2)*(tmp3 + tmp4);
+ tmp8 = (int32_t)((accu + 0x40000000) >> 31);
+ tmp1 = tmp5 + tmp7;
+ tmp3 = tmp5 - tmp7;
+ tmp2 = tmp6 + tmp8;
+ tmp4 = tmp6 - tmp8;
+
+ tmpz[5].re = tmpz[1].re - tmp1;
+ tmpz[1].re = tmpz[1].re + tmp1;
+ tmpz[5].im = tmpz[1].im - tmp2;
+ tmpz[1].im = tmpz[1].im + tmp2;
+ tmpz[7].re = tmpz[3].re - tmp4;
+ tmpz[3].re = tmpz[3].re + tmp4;
+ tmpz[7].im = tmpz[3].im + tmp3;
+ tmpz[3].im = tmpz[3].im - tmp3;
+ }
+
+ step = 1 << ((MAX_LOG2_NFFT-4) - 4);
+ n4 = 4;
+
+ for (nbits=4; nbits<=s->nbits; nbits++){
+ n2 = 2*n4;
+ n34 = 3*n4;
+ num_transforms = (num_transforms >> 1) | 1;
+
+ for (n=0; n<num_transforms; n++){
+ const FFTSample *w_re_ptr = ff_w_tab_sr + step;
+ const FFTSample *w_im_ptr = ff_w_tab_sr + MAX_FFT_SIZE/(4*16) - step;
+ offset = ff_fft_offsets_lut[n] << nbits;
+ tmpz = z + offset;
+
+ tmp5 = tmpz[ n2].re + tmpz[n34].re;
+ tmp1 = tmpz[ n2].re - tmpz[n34].re;
+ tmp6 = tmpz[ n2].im + tmpz[n34].im;
+ tmp2 = tmpz[ n2].im - tmpz[n34].im;
+
+ tmpz[ n2].re = tmpz[ 0].re - tmp5;
+ tmpz[ 0].re = tmpz[ 0].re + tmp5;
+ tmpz[ n2].im = tmpz[ 0].im - tmp6;
+ tmpz[ 0].im = tmpz[ 0].im + tmp6;
+ tmpz[n34].re = tmpz[n4].re - tmp2;
+ tmpz[ n4].re = tmpz[n4].re + tmp2;
+ tmpz[n34].im = tmpz[n4].im + tmp1;
+ tmpz[ n4].im = tmpz[n4].im - tmp1;
+
+ for (i=1; i<n4; i++){
+ FFTSample w_re = w_re_ptr[0];
+ FFTSample w_im = w_im_ptr[0];
+ accu = (int64_t)w_re*tmpz[ n2+i].re;
+ accu += (int64_t)w_im*tmpz[ n2+i].im;
+ tmp1 = (int32_t)((accu + 0x40000000) >> 31);
+ accu = (int64_t)w_re*tmpz[ n2+i].im;
+ accu -= (int64_t)w_im*tmpz[ n2+i].re;
+ tmp2 = (int32_t)((accu + 0x40000000) >> 31);
+ accu = (int64_t)w_re*tmpz[n34+i].re;
+ accu -= (int64_t)w_im*tmpz[n34+i].im;
+ tmp3 = (int32_t)((accu + 0x40000000) >> 31);
+ accu = (int64_t)w_re*tmpz[n34+i].im;
+ accu += (int64_t)w_im*tmpz[n34+i].re;
+ tmp4 = (int32_t)((accu + 0x40000000) >> 31);
+
+ tmp5 = tmp1 + tmp3;
+ tmp1 = tmp1 - tmp3;
+ tmp6 = tmp2 + tmp4;
+ tmp2 = tmp2 - tmp4;
+
+ tmpz[ n2+i].re = tmpz[ i].re - tmp5;
+ tmpz[ i].re = tmpz[ i].re + tmp5;
+ tmpz[ n2+i].im = tmpz[ i].im - tmp6;
+ tmpz[ i].im = tmpz[ i].im + tmp6;
+ tmpz[n34+i].re = tmpz[n4+i].re - tmp2;
+ tmpz[ n4+i].re = tmpz[n4+i].re + tmp2;
+ tmpz[n34+i].im = tmpz[n4+i].im + tmp1;
+ tmpz[ n4+i].im = tmpz[n4+i].im - tmp1;
+
+ w_re_ptr += step;
+ w_im_ptr -= step;
+ }
+ }
+ step >>= 1;
+ n4 <<= 1;
+ }
+}
+
+#else /* FFT_FIXED_32 */
+
#define BUTTERFLIES(a0,a1,a2,a3) {\
BF(t3, t5, t5, t1);\
BF(a2.re, a0.re, a0.re, t5);\
@@ -351,3 +525,4 @@ static void fft_calc_c(FFTContext *s, FFTComplex *z)
{
fft_dispatch[s->nbits-2](z);
}
+#endif /* FFT_FIXED_32 */
diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c
index 0836d42012..7a38bf9212 100644
--- a/libavcodec/ffv1.c
+++ b/libavcodec/ffv1.c
@@ -1,22 +1,22 @@
/*
* FFV1 codec for libavcodec
*
- * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2003-2013 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,119 +27,32 @@
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timer.h"
#include "avcodec.h"
-#include "get_bits.h"
-#include "put_bits.h"
+#include "internal.h"
#include "rangecoder.h"
#include "golomb.h"
#include "mathops.h"
#include "ffv1.h"
-const int8_t ffv1_quant5_10bit[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0,
-};
-
-const int8_t ffv1_quant5[256] = {
- 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1,
-};
-
-const int8_t ffv1_quant9_10bit[256] = {
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
- -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
- -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
- -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
- -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3,
- -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
- -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -0, -0, -0, -0,
-};
-
-const int8_t ffv1_quant11[256] = {
- 0, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
- -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
- -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
- -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
- -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
- -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -4, -4,
- -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
- -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1,
-};
-
-const uint8_t ffv1_ver2_state[256] = {
- 0, 10, 10, 10, 10, 16, 16, 16, 28, 16, 16, 29, 42, 49, 20, 49,
- 59, 25, 26, 26, 27, 31, 33, 33, 33, 34, 34, 37, 67, 38, 39, 39,
- 40, 40, 41, 79, 43, 44, 45, 45, 48, 48, 64, 50, 51, 52, 88, 52,
- 53, 74, 55, 57, 58, 58, 74, 60, 101, 61, 62, 84, 66, 66, 68, 69,
- 87, 82, 71, 97, 73, 73, 82, 75, 111, 77, 94, 78, 87, 81, 83, 97,
- 85, 83, 94, 86, 99, 89, 90, 99, 111, 92, 93, 134, 95, 98, 105, 98,
- 105, 110, 102, 108, 102, 118, 103, 106, 106, 113, 109, 112, 114, 112, 116, 125,
- 115, 116, 117, 117, 126, 119, 125, 121, 121, 123, 145, 124, 126, 131, 127, 129,
- 165, 130, 132, 138, 133, 135, 145, 136, 137, 139, 146, 141, 143, 142, 144, 148,
- 147, 155, 151, 149, 151, 150, 152, 157, 153, 154, 156, 168, 158, 162, 161, 160,
- 172, 163, 169, 164, 166, 184, 167, 170, 177, 174, 171, 173, 182, 176, 180, 178,
- 175, 189, 179, 181, 186, 183, 192, 185, 200, 187, 191, 188, 190, 197, 193, 196,
- 197, 194, 195, 196, 198, 202, 199, 201, 210, 203, 207, 204, 205, 206, 208, 214,
- 209, 211, 221, 212, 213, 215, 224, 216, 217, 218, 219, 220, 222, 228, 223, 225,
- 226, 224, 227, 229, 240, 230, 231, 232, 233, 234, 235, 236, 238, 239, 237, 242,
- 241, 243, 242, 244, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255,
-};
-
-
av_cold int ffv1_common_init(AVCodecContext *avctx)
{
FFV1Context *s = avctx->priv_data;
+ if (!avctx->width || !avctx->height)
+ return AVERROR_INVALIDDATA;
+
s->avctx = avctx;
s->flags = avctx->flags;
- if (!avctx->width || !avctx->height)
- return AVERROR_INVALIDDATA;
+ s->picture.f = av_frame_alloc();
+ s->last_picture.f = av_frame_alloc();
+ if (!s->picture.f || !s->last_picture.f)
+ return AVERROR(ENOMEM);
s->width = avctx->width;
s->height = avctx->height;
@@ -151,7 +64,7 @@ av_cold int ffv1_common_init(AVCodecContext *avctx)
return 0;
}
-int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs)
+av_cold int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs)
{
int j;
@@ -162,13 +75,13 @@ int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs)
if (fs->ac) {
if (!p->state)
- p->state = av_malloc(CONTEXT_SIZE * p->context_count *
+ p->state = av_malloc_array(p->context_count, CONTEXT_SIZE *
sizeof(uint8_t));
if (!p->state)
return AVERROR(ENOMEM);
} else {
if (!p->vlc_state)
- p->vlc_state = av_malloc(p->context_count * sizeof(VlcState));
+ p->vlc_state = av_malloc_array(p->context_count, sizeof(VlcState));
if (!p->vlc_state)
return AVERROR(ENOMEM);
}
@@ -177,7 +90,7 @@ int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs)
if (fs->ac > 1) {
//FIXME only redo if state_transition changed
for (j = 1; j < 256; j++) {
- fs->c.one_state[j] = f->state_transition[j];
+ fs->c. one_state[ j] = f->state_transition[j];
fs->c.zero_state[256 - j] = 256 - fs->c.one_state[j];
}
}
@@ -185,15 +98,23 @@ int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs)
return 0;
}
+av_cold int ffv1_init_slices_state(FFV1Context *f)
+{
+ int i, ret;
+ for (i = 0; i < f->slice_count; i++) {
+ FFV1Context *fs = f->slice_context[i];
+ if ((ret = ffv1_init_slice_state(f, fs)) < 0)
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+}
+
av_cold int ffv1_init_slice_contexts(FFV1Context *f)
{
- int i, j;
+ int i;
f->slice_count = f->num_h_slices * f->num_v_slices;
- if (f->slice_count <= 0) {
- av_log(f->avctx, AV_LOG_ERROR, "Invalid number of slices\n");
- return AVERROR(EINVAL);
- }
+ av_assert0(f->slice_count > 0);
for (i = 0; i < f->slice_count; i++) {
int sx = i % f->num_h_slices;
@@ -203,6 +124,7 @@ av_cold int ffv1_init_slice_contexts(FFV1Context *f)
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;
@@ -215,19 +137,19 @@ av_cold int ffv1_init_slice_contexts(FFV1Context *f)
fs->slice_x = sxs;
fs->slice_y = sys;
- fs->sample_buffer = av_malloc(3 * MAX_PLANES * (fs->width + 6) *
+ fs->sample_buffer = av_malloc_array((fs->width + 6), 3 * MAX_PLANES *
sizeof(*fs->sample_buffer));
if (!fs->sample_buffer) {
- av_free(fs);
+ av_freep(&f->slice_context[i]);
goto memfail;
}
}
return 0;
memfail:
- for (j = 0; j < i; j++) {
- av_free(f->slice_context[j]->sample_buffer);
- av_free(f->slice_context[j]);
+ while(--i >= 0) {
+ av_freep(&f->slice_context[i]->sample_buffer);
+ av_freep(&f->slice_context[i]);
}
return AVERROR(ENOMEM);
}
@@ -237,7 +159,7 @@ int ffv1_allocate_initial_states(FFV1Context *f)
int i;
for (i = 0; i < f->quant_table_count; i++) {
- f->initial_states[i] = av_malloc(f->context_count[i] *
+ f->initial_states[i] = av_malloc_array(f->context_count[i],
sizeof(*f->initial_states[i]));
if (!f->initial_states[i])
return AVERROR(ENOMEM);
@@ -274,11 +196,20 @@ void ffv1_clear_slice_state(FFV1Context *f, FFV1Context *fs)
}
}
+
av_cold int ffv1_close(AVCodecContext *avctx)
{
FFV1Context *s = avctx->priv_data;
int i, j;
+ if (s->picture.f)
+ ff_thread_release_buffer(avctx, &s->picture);
+ av_frame_free(&s->picture.f);
+
+ if (s->last_picture.f)
+ ff_thread_release_buffer(avctx, &s->last_picture);
+ av_frame_free(&s->last_picture.f);
+
for (j = 0; j < s->slice_count; j++) {
FFV1Context *fs = s->slice_context[j];
for (i = 0; i < s->plane_count; i++) {
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index bc433bceb5..bfc4d71e65 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -3,32 +3,49 @@
*
* Copyright (c) 2003-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_FFV1_H
#define AVCODEC_FFV1_H
-#include <stdint.h>
+/**
+ * @file
+ * FF Video Codec 1 (a lossless codec)
+ */
+#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timer.h"
#include "avcodec.h"
#include "get_bits.h"
+#include "internal.h"
+#include "mathops.h"
#include "put_bits.h"
#include "rangecoder.h"
+#include "thread.h"
+
+#ifdef __INTEL_COMPILER
+#undef av_flatten
+#define av_flatten
+#endif
#define MAX_PLANES 4
#define CONTEXT_SIZE 32
@@ -36,14 +53,6 @@
#define MAX_QUANT_TABLES 8
#define MAX_CONTEXT_INPUTS 5
-extern const uint8_t ff_log2_run[41];
-
-extern const int8_t ffv1_quant5_10bit[256];
-extern const int8_t ffv1_quant5[256];
-extern const int8_t ffv1_quant9_10bit[256];
-extern const int8_t ffv1_quant11[256];
-extern const uint8_t ffv1_ver2_state[256];
-
typedef struct VlcState {
int16_t drift;
uint16_t error_sum;
@@ -71,20 +80,20 @@ typedef struct FFV1Context {
uint64_t rc_stat[256][2];
uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2];
int version;
- int minor_version;
+ int micro_version;
int width, height;
int chroma_planes;
int chroma_h_shift, chroma_v_shift;
int transparency;
int flags;
int picture_number;
- const AVFrame *frame;
- AVFrame *last_picture;
+ ThreadFrame picture, last_picture;
+ struct FFV1Context *fsrc;
AVFrame *cur;
int plane_count;
- int ac; // 1 = range coder <-> 0 = golomb rice
- int ac_byte_count; // number of bytes used for AC coding
+ 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];
@@ -96,6 +105,7 @@ typedef struct FFV1Context {
int16_t *sample_buffer;
int ec;
+ int intra;
int slice_damaged;
int key_frame_ok;
@@ -113,15 +123,27 @@ typedef struct FFV1Context {
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;
} FFV1Context;
+int ffv1_common_init(AVCodecContext *avctx);
+int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs);
+int ffv1_init_slices_state(FFV1Context *f);
+int ffv1_init_slice_contexts(FFV1Context *f);
+int ffv1_allocate_initial_states(FFV1Context *f);
+void ffv1_clear_slice_state(FFV1Context *f, FFV1Context *fs);
+int ffv1_close(AVCodecContext *avctx);
+
static av_always_inline int fold(int diff, int bits)
{
if (bits == 8)
diff = (int8_t)diff;
else {
diff += 1 << (bits - 1);
- diff &= (1 << bits) - 1;
+ diff = av_mod_uintp2(diff, bits);
diff -= 1 << (bits - 1);
}
@@ -193,11 +215,4 @@ static inline void update_vlc_state(VlcState *const state, const int v)
state->count = count;
}
-int ffv1_common_init(AVCodecContext *avctx);
-int ffv1_init_slice_state(FFV1Context *f, FFV1Context *fs);
-int ffv1_init_slice_contexts(FFV1Context *f);
-int ffv1_allocate_initial_states(FFV1Context *f);
-void ffv1_clear_slice_state(FFV1Context *f, FFV1Context *fs);
-int ffv1_close(AVCodecContext *avctx);
-
#endif /* AVCODEC_FFV1_H */
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index c46bcf2681..d3927a25b7 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -1,22 +1,22 @@
/*
* FFV1 decoder
*
- * Copyright (c) 2003-2012 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2003-2013 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,15 +26,14 @@
*/
#include "libavutil/avassert.h"
-#include "libavutil/pixdesc.h"
#include "libavutil/crc.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
#include "libavutil/timer.h"
#include "avcodec.h"
#include "internal.h"
#include "get_bits.h"
-#include "put_bits.h"
#include "rangecoder.h"
#include "golomb.h"
#include "mathops.h"
@@ -77,8 +76,6 @@ static inline int get_vlc_symbol(GetBitContext *gb, VlcState *const state,
i += i;
}
- assert(k <= 8);
-
v = get_sr_golomb(gb, k, 12, bits);
ff_dlog(NULL, "v:%d bias:%d error:%d drift:%d count:%d k:%d",
v, state->bias, state->error_sum, state->drift, state->count, k);
@@ -108,6 +105,19 @@ static av_always_inline void decode_line(FFV1Context *s, int w,
int run_mode = 0;
int run_index = s->run_index;
+ if (s->slice_coding_mode == 1) {
+ int i;
+ for (x = 0; x < w; x++) {
+ int v = 0;
+ for (i=0; i<bits; i++) {
+ uint8_t state = 128;
+ v += v + get_rac(c, &state);
+ }
+ sample[1][x] = v;
+ }
+ return;
+ }
+
for (x = 0; x < w; x++) {
int diff, context, sign;
@@ -162,8 +172,7 @@ static av_always_inline void decode_line(FFV1Context *s, int w,
if (sign)
diff = -diff;
- sample[1][x] = (predict(sample[1] + x, sample[0] + x) + diff) &
- ((1 << bits) - 1);
+ sample[1][x] = av_mod_uintp2(predict(sample[1] + x, sample[0] + x) + diff, bits);
}
s->run_index = run_index;
}
@@ -195,29 +204,27 @@ static void decode_plane(FFV1Context *s, uint8_t *src,
for (x = 0; x < w; x++)
src[x + stride * y] = sample[1][x];
} else {
- decode_line(s, w, sample, plane_index,
- s->avctx->bits_per_raw_sample);
+ decode_line(s, w, sample, plane_index, s->avctx->bits_per_raw_sample);
if (s->packed_at_lsb) {
- for (x = 0; x < w; x++)
- ((uint16_t *)(src + stride * y))[x] = sample[1][x];
+ for (x = 0; x < w; x++) {
+ ((uint16_t*)(src + stride*y))[x] = sample[1][x];
+ }
} else {
- for (x = 0; x < w; x++)
- ((uint16_t *)(src + stride * y))[x] = sample[1][x] << (16 - s->avctx->bits_per_raw_sample);
+ for (x = 0; x < w; x++) {
+ ((uint16_t*)(src + stride*y))[x] = sample[1][x] << (16 - s->avctx->bits_per_raw_sample);
+ }
}
}
// STOP_TIMER("decode-line") }
}
}
-static void decode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
- int stride[3])
+static void decode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h, int stride[3])
{
int x, y, p;
int16_t *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 = s->avctx->bits_per_raw_sample <= 8;
+ int bits = s->avctx->bits_per_raw_sample > 0 ? s->avctx->bits_per_raw_sample : 8;
int offset = 1 << bits;
for (x = 0; x < 4; x++) {
@@ -231,17 +238,17 @@ static void decode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
for (y = 0; y < h; y++) {
for (p = 0; p < 3 + s->transparency; p++) {
- int16_t *temp = sample[p][0]; //FIXME try a normal buffer
+ int16_t *temp = sample[p][0]; // FIXME: try a normal buffer
sample[p][0] = sample[p][1];
sample[p][1] = temp;
- sample[p][1][-1] = sample[p][0][0];
- sample[p][0][w] = sample[p][0][w - 1];
- if (lbd)
- decode_line(s, w, sample[p], (p + 1) / 2, 9);
+ sample[p][1][-1]= sample[p][0][0 ];
+ sample[p][0][ w]= sample[p][0][w-1];
+ if (lbd && s->slice_coding_mode == 0)
+ decode_line(s, w, sample[p], (p + 1)/2, 9);
else
- decode_line(s, w, sample[p], (p + 1) / 2, bits + 1);
+ decode_line(s, w, sample[p], (p + 1)/2, bits + (s->slice_coding_mode != 1));
}
for (x = 0; x < w; x++) {
int g = sample[0][1][x];
@@ -249,19 +256,20 @@ static void decode_rgb_frame(FFV1Context *s, uint8_t *src[3], int w, int h,
int r = sample[2][1][x];
int a = sample[3][1][x];
- b -= offset;
- r -= offset;
- g -= (b + r) >> 2;
- b += g;
- r += g;
+ if (s->slice_coding_mode != 1) {
+ b -= offset;
+ r -= offset;
+ g -= (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2;
+ b += g;
+ r += g;
+ }
if (lbd)
- *((uint32_t *)(src[0] + x * 4 + stride[0] * y)) = b +
- (g << 8) + (r << 16) + (a << 24);
+ *((uint32_t*)(src[0] + x*4 + stride[0]*y)) = b + (g<<8) + (r<<16) + (a<<24);
else {
- *((uint16_t *)(src[0] + x * 2 + stride[0] * y)) = b;
- *((uint16_t *)(src[1] + x * 2 + stride[1] * y)) = g;
- *((uint16_t *)(src[2] + x * 2 + stride[2] * y)) = r;
+ *((uint16_t*)(src[0] + x*2 + stride[0]*y)) = b;
+ *((uint16_t*)(src[1] + x*2 + stride[1]*y)) = g;
+ *((uint16_t*)(src[2] + x*2 + stride[2]*y)) = r;
}
}
}
@@ -274,35 +282,29 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
unsigned ps, i, context_count;
memset(state, 128, sizeof(state));
- if (fs->ac > 1) {
- for (i = 1; i < 256; i++) {
- fs->c.one_state[i] = f->state_transition[i];
- fs->c.zero_state[256 - i] = 256 - fs->c.one_state[i];
- }
- }
+ av_assert0(f->version > 2);
- fs->slice_x = get_symbol(c, state, 0) * f->width;
- fs->slice_y = get_symbol(c, state, 0) * f->height;
- fs->slice_width = (get_symbol(c, state, 0) + 1) * f->width + fs->slice_x;
+ fs->slice_x = get_symbol(c, state, 0) * f->width ;
+ fs->slice_y = get_symbol(c, state, 0) * f->height;
+ fs->slice_width = (get_symbol(c, state, 0) + 1) * f->width + fs->slice_x;
fs->slice_height = (get_symbol(c, state, 0) + 1) * f->height + fs->slice_y;
- fs->slice_x /= f->num_h_slices;
- fs->slice_y /= f->num_v_slices;
- fs->slice_width = fs->slice_width / f->num_h_slices - fs->slice_x;
- fs->slice_height = fs->slice_height / f->num_v_slices - fs->slice_y;
- if ((unsigned)fs->slice_width > f->width ||
- (unsigned)fs->slice_height > f->height)
- return AVERROR_INVALIDDATA;
- if ((unsigned)fs->slice_x + (uint64_t)fs->slice_width > f->width ||
- (unsigned)fs->slice_y + (uint64_t)fs->slice_height > f->height)
- return AVERROR_INVALIDDATA;
+ fs->slice_x /= f->num_h_slices;
+ fs->slice_y /= f->num_v_slices;
+ fs->slice_width = fs->slice_width /f->num_h_slices - fs->slice_x;
+ fs->slice_height = fs->slice_height/f->num_v_slices - fs->slice_y;
+ if ((unsigned)fs->slice_width > f->width || (unsigned)fs->slice_height > f->height)
+ return -1;
+ if ( (unsigned)fs->slice_x + (uint64_t)fs->slice_width > f->width
+ || (unsigned)fs->slice_y + (uint64_t)fs->slice_height > f->height)
+ return -1;
for (i = 0; i < f->plane_count; i++) {
- PlaneContext *const p = &fs->plane[i];
- int idx = get_symbol(c, state, 0);
+ PlaneContext * const p = &fs->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 AVERROR_INVALIDDATA;
+ return -1;
}
p->quant_table_index = idx;
memcpy(p->quant_table, f->quant_tables[idx], sizeof(p->quant_table));
@@ -336,20 +338,72 @@ static int decode_slice_header(FFV1Context *f, FFV1Context *fs)
f->cur->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) {
+ av_log(f->avctx, AV_LOG_ERROR, "slice_rct_y_coef out of range\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+
return 0;
}
static int decode_slice(AVCodecContext *c, void *arg)
{
- FFV1Context *fs = *(void **)arg;
- FFV1Context *f = fs->avctx->priv_data;
+ FFV1Context *fs = *(void **)arg;
+ FFV1Context *f = fs->avctx->priv_data;
int width, height, x, y, ret;
- const int ps = (av_pix_fmt_desc_get(c->pix_fmt)->flags & AV_PIX_FMT_FLAG_PLANAR)
- ? (c->bits_per_raw_sample > 8) + 1
- : 4;
- AVFrame *const p = f->cur;
+ const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step_minus1 + 1;
+ AVFrame * const p = f->cur;
+ int i, si;
+
+ for( si=0; fs != f->slice_context[si]; si ++)
+ ;
+
+ if(f->fsrc && !p->key_frame)
+ ff_thread_await_progress(&f->last_picture, si, 0);
+
+ if(f->fsrc && !p->key_frame) {
+ 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->key_frame)
+ 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;
if (f->version > 2) {
+ if (ffv1_init_slice_state(f, fs) < 0)
+ return AVERROR(ENOMEM);
if (decode_slice_header(f, fs) < 0) {
fs->slice_damaged = 1;
return AVERROR_INVALIDDATA;
@@ -357,44 +411,37 @@ static int decode_slice(AVCodecContext *c, void *arg)
}
if ((ret = ffv1_init_slice_state(f, fs)) < 0)
return ret;
- if (f->cur->key_frame)
+ if (f->cur->key_frame || fs->slice_reset_contexts)
ffv1_clear_slice_state(f, fs);
+
width = fs->slice_width;
height = fs->slice_height;
x = fs->slice_x;
y = fs->slice_y;
if (!fs->ac) {
- if (f->version == 3 && f->minor_version > 1 || f->version > 3)
+ 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);
+ 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);
}
av_assert1(width && height);
if (f->colorspace == 0) {
- const int chroma_width = -((-width) >> f->chroma_h_shift);
- const int chroma_height = -((-height) >> f->chroma_v_shift);
+ const int chroma_width = FF_CEIL_RSHIFT(width, f->chroma_h_shift);
+ const int chroma_height = FF_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);
+ decode_plane(fs, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0);
if (f->chroma_planes) {
- decode_plane(fs, p->data[1] + ps * cx + cy * p->linesize[1],
- chroma_width, chroma_height, p->linesize[1],
- 1);
- decode_plane(fs, p->data[2] + ps * cx + cy * p->linesize[2],
- chroma_width, chroma_height, p->linesize[2],
- 1);
+ decode_plane(fs, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1);
+ decode_plane(fs, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1);
}
if (fs->transparency)
- decode_plane(fs, p->data[3] + ps * x + y * p->linesize[3], width,
- height, p->linesize[3],
- 2);
+ 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);
} else {
uint8_t *planes[3] = { p->data[0] + ps * x + y * p->linesize[0],
p->data[1] + ps * x + y * p->linesize[1],
@@ -404,16 +451,17 @@ static int decode_slice(AVCodecContext *c, void *arg)
if (fs->ac && f->version > 2) {
int v;
get_rac(&fs->c, (uint8_t[]) { 129 });
- v = fs->c.bytestream_end - fs->c.bytestream - 2 - 5 * f->ec;
+ v = fs->c.bytestream_end - fs->c.bytestream - 2 - 5*f->ec;
if (v) {
- av_log(f->avctx, AV_LOG_ERROR, "bytestream end mismatching by %d\n",
- v);
+ av_log(f->avctx, AV_LOG_ERROR, "bytestream end mismatching by %d\n", v);
fs->slice_damaged = 1;
}
}
emms_c();
+ ff_thread_report_progress(&f->picture, si, 0);
+
return 0;
}
@@ -428,8 +476,8 @@ static int read_quant_table(RangeCoder *c, int16_t *quant_table, int scale)
for (v = 0; i < 128; v++) {
unsigned len = get_symbol(c, state, 0) + 1;
- if (len > 128 - i)
- return -1;
+ if (len > 128 - i || !len)
+ return AVERROR_INVALIDDATA;
while (len--) {
quant_table[i] = scale * v;
@@ -453,7 +501,7 @@ static int read_quant_tables(RangeCoder *c,
for (i = 0; i < 5; i++) {
context_count *= read_quant_table(c, quant_table[i], context_count);
if (context_count > 32768U) {
- return -1;
+ return AVERROR_INVALIDDATA;
}
}
return (context_count + 1) / 2;
@@ -473,12 +521,17 @@ static int read_extra_header(FFV1Context *f)
ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
f->version = get_symbol(c, state, 0);
+ if (f->version < 2) {
+ av_log(f->avctx, AV_LOG_ERROR, "Invalid version in global header\n");
+ return AVERROR_INVALIDDATA;
+ }
if (f->version > 2) {
c->bytestream_end -= 4;
- f->minor_version = get_symbol(c, state, 0);
+ f->micro_version = get_symbol(c, state, 0);
+ if (f->micro_version < 0)
+ return AVERROR_INVALIDDATA;
}
f->ac = f->avctx->coder_type = get_symbol(c, state, 0);
-
if (f->ac > 1) {
for (i = 1; i < 256; i++)
f->state_transition[i] = get_symbol(c, state, 1) + c->one_state[i];
@@ -490,19 +543,27 @@ static int read_extra_header(FFV1Context *f)
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 = 2 + f->transparency;
+ f->plane_count = 1 + (f->chroma_planes || f->version<4) + f->transparency;
f->num_h_slices = 1 + get_symbol(c, state, 0);
f->num_v_slices = 1 + get_symbol(c, state, 0);
- if (f->num_h_slices > (unsigned)f->width ||
- f->num_v_slices > (unsigned)f->height) {
- av_log(f->avctx, AV_LOG_ERROR, "too many slices\n");
+ if (f->chroma_h_shift > 4U || f->chroma_v_shift > 4U) {
+ av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n",
+ f->chroma_h_shift, f->chroma_v_shift);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (f->num_h_slices > (unsigned)f->width || !f->num_h_slices ||
+ f->num_v_slices > (unsigned)f->height || !f->num_v_slices
+ ) {
+ av_log(f->avctx, AV_LOG_ERROR, "slice count invalid\n");
return AVERROR_INVALIDDATA;
}
f->quant_table_count = get_symbol(c, state, 0);
if (f->quant_table_count > (unsigned)MAX_QUANT_TABLES)
return AVERROR_INVALIDDATA;
+
for (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) {
@@ -525,6 +586,8 @@ static int read_extra_header(FFV1Context *f)
if (f->version > 2) {
f->ec = get_symbol(c, state, 0);
+ if (f->micro_version > 2)
+ f->intra = get_symbol(c, state, 0);
}
if (f->version > 2) {
@@ -537,34 +600,43 @@ static int read_extra_header(FFV1Context *f)
}
}
+ if (f->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(f->avctx, AV_LOG_DEBUG,
+ "global: ver:%d.%d, coder:%d, colorspace: %d bpr:%d chroma:%d(%d:%d), alpha:%d slices:%dx%d qtabs:%d ec:%d intra:%d\n",
+ f->version, f->micro_version,
+ f->ac,
+ f->colorspace,
+ f->avctx->bits_per_raw_sample,
+ f->chroma_planes, f->chroma_h_shift, f->chroma_v_shift,
+ f->transparency,
+ f->num_h_slices, f->num_v_slices,
+ f->quant_table_count,
+ f->ec,
+ f->intra
+ );
return 0;
}
-
static int read_header(FFV1Context *f)
{
uint8_t state[CONTEXT_SIZE];
- int i, j, context_count = -1;
+ int i, j, context_count = -1; //-1 to avoid warning
RangeCoder *const c = &f->slice_context[0]->c;
memset(state, 128, sizeof(state));
if (f->version < 2) {
int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample;
- unsigned v = get_symbol(c, state, 0);
- if (v > 1) {
- av_log(f->avctx, AV_LOG_ERROR,
- "invalid version %d in version 1 header\n", v);
+ unsigned v= get_symbol(c, state, 0);
+ if (v >= 2) {
+ av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v);
return AVERROR_INVALIDDATA;
}
f->version = v;
-
- f->ac = f->avctx->coder_type = get_symbol(c, state, 0);
-
+ f->ac = f->avctx->coder_type = get_symbol(c, state, 0);
if (f->ac > 1) {
for (i = 1; i < 256; i++)
- f->state_transition[i] =
- get_symbol(c, state, 1) + c->one_state[i];
+ f->state_transition[i] = get_symbol(c, state, 1) + c->one_state[i];
}
colorspace = get_symbol(c, state, 0); //YUV cs type
@@ -586,6 +658,12 @@ static int read_header(FFV1Context *f)
}
}
+ if (chroma_h_shift > 4U || chroma_v_shift > 4U) {
+ av_log(f->avctx, AV_LOG_ERROR, "chroma shift parameters %d %d are invalid\n",
+ chroma_h_shift, chroma_v_shift);
+ return AVERROR_INVALIDDATA;
+ }
+
f->colorspace = colorspace;
f->avctx->bits_per_raw_sample = bits_per_raw_sample;
f->chroma_planes = chroma_planes;
@@ -597,96 +675,66 @@ static int read_header(FFV1Context *f)
}
if (f->colorspace == 0) {
+ if (f->avctx->skip_alpha) f->transparency = 0;
if (!f->transparency && !f->chroma_planes) {
if (f->avctx->bits_per_raw_sample <= 8)
f->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
else
f->avctx->pix_fmt = AV_PIX_FMT_GRAY16;
- } else if (f->avctx->bits_per_raw_sample <= 8 && !f->transparency) {
- switch (16 * f->chroma_h_shift + f->chroma_v_shift) {
- case 0x00:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV444P;
- break;
- case 0x01:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV440P;
- break;
- case 0x10:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
- break;
- case 0x11:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
- break;
- case 0x20:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV411P;
- break;
- case 0x22:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV410P;
- break;
- default:
- av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
- return AVERROR(ENOSYS);
+ } else if (f->avctx->bits_per_raw_sample<=8 && !f->transparency) {
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P; break;
+ case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P; break;
+ case 0x20: f->avctx->pix_fmt = AV_PIX_FMT_YUV411P; break;
+ case 0x22: f->avctx->pix_fmt = AV_PIX_FMT_YUV410P; break;
}
} else if (f->avctx->bits_per_raw_sample <= 8 && f->transparency) {
- switch (16 * f->chroma_h_shift + f->chroma_v_shift) {
- case 0x00:
- f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
- break;
- case 0x10:
- f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P;
- break;
- case 0x11:
- f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
- break;
- default:
- av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
- return AVERROR(ENOSYS);
+ switch(16*f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; break;
}
- } else if (f->avctx->bits_per_raw_sample == 9) {
+ } else if (f->avctx->bits_per_raw_sample == 9 && !f->transparency) {
f->packed_at_lsb = 1;
- switch (16 * f->chroma_h_shift + f->chroma_v_shift) {
- case 0x00:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV444P9;
- break;
- case 0x10:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV422P9;
- break;
- case 0x11:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV420P9;
- break;
- default:
- av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
- return AVERROR(ENOSYS);
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P9; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P9; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P9; break;
}
- } else if (f->avctx->bits_per_raw_sample == 10) {
+ } else if (f->avctx->bits_per_raw_sample == 9 && f->transparency) {
f->packed_at_lsb = 1;
- switch (16 * f->chroma_h_shift + f->chroma_v_shift) {
- case 0x00:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV444P10;
- break;
- case 0x10:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
- break;
- case 0x11:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
- break;
- default:
- av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
- return AVERROR(ENOSYS);
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P9; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P9; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P9; break;
}
- } else {
- switch (16 * f->chroma_h_shift + f->chroma_v_shift) {
- case 0x00:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV444P16;
- break;
- case 0x10:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV422P16;
- break;
- case 0x11:
- f->avctx->pix_fmt = AV_PIX_FMT_YUV420P16;
- break;
- default:
- av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
- return AVERROR(ENOSYS);
+ } else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) {
+ f->packed_at_lsb = 1;
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P10; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P10; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P10; break;
+ }
+ } else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) {
+ f->packed_at_lsb = 1;
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P10; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P10; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P10; break;
+ }
+ } else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency){
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; break;
+ }
+ } else if (f->avctx->bits_per_raw_sample == 16 && f->transparency){
+ switch(16 * f->chroma_h_shift + f->chroma_v_shift) {
+ case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUVA444P16; break;
+ case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUVA422P16; break;
+ case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUVA420P16; break;
}
}
} else if (f->colorspace == 1) {
@@ -695,27 +743,25 @@ static int read_header(FFV1Context *f)
"chroma subsampling not supported in this colorspace\n");
return AVERROR(ENOSYS);
}
- switch (f->avctx->bits_per_raw_sample) {
- case 0:
- case 8:
- f->avctx->pix_fmt = AV_PIX_FMT_RGB32;
- break;
- case 9:
+ if ( f->avctx->bits_per_raw_sample == 9)
f->avctx->pix_fmt = AV_PIX_FMT_GBRP9;
- break;
- case 10:
+ else if (f->avctx->bits_per_raw_sample == 10)
f->avctx->pix_fmt = AV_PIX_FMT_GBRP10;
- break;
- default:
- av_log(f->avctx, AV_LOG_ERROR,
- "bit depth %d not supported\n",
- f->avctx->bits_per_raw_sample);
- return AVERROR(ENOSYS);
- }
+ else if (f->avctx->bits_per_raw_sample == 12)
+ f->avctx->pix_fmt = AV_PIX_FMT_GBRP12;
+ else if (f->avctx->bits_per_raw_sample == 14)
+ f->avctx->pix_fmt = AV_PIX_FMT_GBRP14;
+ else
+ if (f->transparency) f->avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ else f->avctx->pix_fmt = AV_PIX_FMT_0RGB32;
} else {
av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n");
return AVERROR(ENOSYS);
}
+ if (f->avctx->pix_fmt == AV_PIX_FMT_NONE) {
+ av_log(f->avctx, AV_LOG_ERROR, "format not supported\n");
+ return AVERROR(ENOSYS);
+ }
ff_dlog(f->avctx, "%d %d %d\n",
f->chroma_h_shift, f->chroma_v_shift, f->avctx->pix_fmt);
@@ -732,16 +778,15 @@ static int read_header(FFV1Context *f)
for (f->slice_count = 0;
f->slice_count < MAX_SLICES && 3 < p - c->bytestream_start;
f->slice_count++) {
- int trailer = 3 + 5 * !!f->ec;
- int size = AV_RB24(p - trailer);
+ int trailer = 3 + 5*!!f->ec;
+ int size = AV_RB24(p-trailer);
if (size + trailer > p - c->bytestream_start)
break;
p -= size + trailer;
}
}
if (f->slice_count > (unsigned)MAX_SLICES || f->slice_count <= 0) {
- av_log(f->avctx, AV_LOG_ERROR, "slice count %d is invalid\n",
- f->slice_count);
+ av_log(f->avctx, AV_LOG_ERROR, "slice count %d is invalid\n", f->slice_count);
return AVERROR_INVALIDDATA;
}
@@ -753,23 +798,20 @@ static int read_header(FFV1Context *f)
fs->slice_damaged = 0;
if (f->version == 2) {
- fs->slice_x = get_symbol(c, state, 0) * f->width;
- fs->slice_y = get_symbol(c, state, 0) * f->height;
- fs->slice_width =
- (get_symbol(c, state, 0) + 1) * f->width + fs->slice_x;
- fs->slice_height =
- (get_symbol(c, state, 0) + 1) * f->height + fs->slice_y;
-
- fs->slice_x /= f->num_h_slices;
- fs->slice_y /= f->num_v_slices;
+ fs->slice_x = get_symbol(c, state, 0) * f->width ;
+ fs->slice_y = get_symbol(c, state, 0) * f->height;
+ fs->slice_width = (get_symbol(c, state, 0) + 1) * f->width + fs->slice_x;
+ fs->slice_height = (get_symbol(c, state, 0) + 1) * f->height + fs->slice_y;
+
+ fs->slice_x /= f->num_h_slices;
+ fs->slice_y /= f->num_v_slices;
fs->slice_width = fs->slice_width / f->num_h_slices - fs->slice_x;
fs->slice_height = fs->slice_height / f->num_v_slices - fs->slice_y;
- if ((unsigned)fs->slice_width > f->width ||
+ if ((unsigned)fs->slice_width > f->width ||
(unsigned)fs->slice_height > f->height)
return AVERROR_INVALIDDATA;
- if ((unsigned)fs->slice_x + (uint64_t)fs->slice_width > f->width
- || (unsigned)fs->slice_y + (uint64_t)fs->slice_height >
- f->height)
+ if ( (unsigned)fs->slice_x + (uint64_t)fs->slice_width > f->width
+ || (unsigned)fs->slice_y + (uint64_t)fs->slice_height > f->height)
return AVERROR_INVALIDDATA;
}
@@ -804,16 +846,13 @@ static int read_header(FFV1Context *f)
return 0;
}
-static av_cold int ffv1_decode_init(AVCodecContext *avctx)
+static av_cold int decode_init(AVCodecContext *avctx)
{
FFV1Context *f = avctx->priv_data;
int ret;
- ffv1_common_init(avctx);
-
- f->last_picture = av_frame_alloc();
- if (!f->last_picture)
- return AVERROR(ENOMEM);
+ if ((ret = ffv1_common_init(avctx)) < 0)
+ return ret;
if (avctx->extradata && (ret = read_extra_header(f)) < 0)
return ret;
@@ -821,11 +860,12 @@ static av_cold int ffv1_decode_init(AVCodecContext *avctx)
if ((ret = ffv1_init_slice_contexts(f)) < 0)
return ret;
+ avctx->internal->allocate_progress = 1;
+
return 0;
}
-static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
- int *got_frame, AVPacket *avpkt)
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
{
uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
@@ -834,10 +874,22 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
int i, ret;
uint8_t keystate = 128;
uint8_t *buf_p;
- AVFrame *const p = data;
+ AVFrame *p;
+
+ if (f->last_picture.f)
+ ff_thread_release_buffer(avctx, &f->last_picture);
+ FFSWAP(ThreadFrame, f->picture, f->last_picture);
+
+ f->cur = p = f->picture.f;
- f->cur = p;
+ if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) {
+ /* we have interlaced material flagged in container */
+ p->interlaced_frame = 1;
+ if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB)
+ p->top_field_first = 1;
+ }
+ f->avctx = avctx;
ff_init_range_decoder(c, buf, buf_size);
ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
@@ -857,27 +909,23 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
p->key_frame = 0;
}
- if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &f->picture, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if (avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(avctx, AV_LOG_DEBUG,
- "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n",
- f->version, p->key_frame, f->ac, f->ec, f->slice_count,
- f->avctx->bits_per_raw_sample);
+ av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n",
+ f->version, p->key_frame, f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample);
+
+ 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];
- int trailer = 3 + 5 * !!f->ec;
+ int trailer = 3 + 5*!!f->ec;
int v;
- if (i || f->version > 2)
- v = AV_RB24(buf_p - trailer) + trailer;
- else
- v = buf_p - c->bytestream_start;
+ if (i || f->version > 2) 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");
return AVERROR_INVALIDDATA;
@@ -887,7 +935,15 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
if (f->ec) {
unsigned crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, buf_p, v);
if (crc) {
- av_log(f->avctx, AV_LOG_ERROR, "CRC mismatch %X!\n", crc);
+ int64_t ts = avpkt->pts != AV_NOPTS_VALUE ? avpkt->pts : avpkt->dts;
+ av_log(f->avctx, AV_LOG_ERROR, "CRC mismatch %X!", crc);
+ if (ts != AV_NOPTS_VALUE && avctx->pkt_timebase.num) {
+ av_log(f->avctx, AV_LOG_ERROR, "at %f seconds\n", ts*av_q2d(avctx->pkt_timebase));
+ } else if (ts != AV_NOPTS_VALUE) {
+ av_log(f->avctx, AV_LOG_ERROR, "at %"PRId64"\n", ts);
+ } else {
+ av_log(f->avctx, AV_LOG_ERROR, "\n");
+ }
fs->slice_damaged = 1;
}
}
@@ -897,54 +953,147 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void *data,
} else
fs->c.bytestream_end = buf_p + v;
+ fs->avctx = avctx;
fs->cur = p;
}
- avctx->execute(avctx, decode_slice, &f->slice_context[0], NULL,
+ avctx->execute(avctx,
+ decode_slice,
+ &f->slice_context[0],
+ NULL,
f->slice_count,
- sizeof(void *));
+ sizeof(void*));
for (i = f->slice_count - 1; i >= 0; i--) {
FFV1Context *fs = f->slice_context[i];
int j;
- if (fs->slice_damaged && f->last_picture->data[0]) {
+ if (fs->slice_damaged && f->last_picture.f->data[0]) {
const uint8_t *src[4];
uint8_t *dst[4];
+ ff_thread_await_progress(&f->last_picture, INT_MAX, 0);
for (j = 0; j < 4; j++) {
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);
- src[j] = f->last_picture->data[j] +
- f->last_picture->linesize[j] *
+ src[j] = f->last_picture.f->data[j] + f->last_picture.f->linesize[j] *
(fs->slice_y >> sv) + (fs->slice_x >> sh);
}
av_image_copy(dst, p->linesize, src,
- f->last_picture->linesize,
- avctx->pix_fmt, fs->slice_width,
+ f->last_picture.f->linesize,
+ avctx->pix_fmt,
+ fs->slice_width,
fs->slice_height);
}
}
+ ff_thread_report_progress(&f->picture, INT_MAX, 0);
f->picture_number++;
- av_frame_unref(f->last_picture);
- if ((ret = av_frame_ref(f->last_picture, p)) < 0)
- return ret;
+ if (f->last_picture.f)
+ ff_thread_release_buffer(avctx, &f->last_picture);
f->cur = NULL;
+ if ((ret = av_frame_ref(data, f->picture.f)) < 0)
+ return ret;
*got_frame = 1;
return buf_size;
}
-static av_cold int ffv1_decode_close(AVCodecContext *avctx)
+static int init_thread_copy(AVCodecContext *avctx)
+{
+ FFV1Context *f = avctx->priv_data;
+ int i, ret;
+
+ f->picture.f = NULL;
+ f->last_picture.f = NULL;
+ f->sample_buffer = NULL;
+ f->slice_count = 0;
+
+ for (i = 0; i < f->quant_table_count; i++) {
+ av_assert0(f->version > 1);
+ f->initial_states[i] = av_memdup(f->initial_states[i],
+ f->context_count[i] * sizeof(*f->initial_states[i]));
+ }
+
+ f->picture.f = av_frame_alloc();
+ f->last_picture.f = av_frame_alloc();
+
+ if ((ret = ffv1_init_slice_contexts(f)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static void copy_fields(FFV1Context *fsdst, FFV1Context *fssrc, 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->bits_per_raw_sample = fsrc->bits_per_raw_sample;
+ 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;
+ }
+}
+
+static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
{
- FFV1Context *s = avctx->priv_data;;
+ FFV1Context *fsrc = src->priv_data;
+ FFV1Context *fdst = dst->priv_data;
+ int i, ret;
+
+ if (dst == src)
+ return 0;
+
+ {
+ ThreadFrame picture = fdst->picture, last_picture = fdst->last_picture;
+ uint8_t (*initial_states[MAX_QUANT_TABLES])[32];
+ struct FFV1Context *slice_context[MAX_SLICES];
+ memcpy(initial_states, fdst->initial_states, sizeof(fdst->initial_states));
+ memcpy(slice_context, fdst->slice_context , sizeof(fdst->slice_context));
+
+ memcpy(fdst, fsrc, sizeof(*fdst));
+ memcpy(fdst->initial_states, initial_states, sizeof(fdst->initial_states));
+ memcpy(fdst->slice_context, slice_context , sizeof(fdst->slice_context));
+ fdst->picture = picture;
+ fdst->last_picture = last_picture;
+ 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);
+ }
+ av_assert0(!fdst->plane[0].state);
+ av_assert0(!fdst->sample_buffer);
+ }
- av_frame_free(&s->last_picture);
+ av_assert1(fdst->slice_count == fsrc->slice_count);
+
+
+ ff_thread_release_buffer(dst, &fdst->picture);
+ if (fsrc->picture.f->data[0]) {
+ if ((ret = ff_thread_ref_frame(&fdst->picture, &fsrc->picture)) < 0)
+ return ret;
+ }
- ffv1_close(avctx);
+ fdst->fsrc = fsrc;
return 0;
}
@@ -955,9 +1104,11 @@ AVCodec ff_ffv1_decoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_FFV1,
.priv_data_size = sizeof(FFV1Context),
- .init = ffv1_decode_init,
- .close = ffv1_decode_close,
- .decode = ffv1_decode_frame,
+ .init = decode_init,
+ .close = ffv1_close,
+ .decode = decode_frame,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+ .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
.capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/ |
- CODEC_CAP_SLICE_THREADS,
+ CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
};
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index f689bd98b4..af727a5cd5 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -1,22 +1,22 @@
/*
- * FFV1 encoder for libavcodec
+ * FFV1 encoder
*
- * Copyright (c) 2003-2012 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2003-2013 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,19 +27,114 @@
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
-#include "libavutil/pixdesc.h"
#include "libavutil/crc.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timer.h"
#include "avcodec.h"
#include "internal.h"
-#include "get_bits.h"
#include "put_bits.h"
#include "rangecoder.h"
#include "golomb.h"
#include "mathops.h"
#include "ffv1.h"
+static const int8_t quant5_10bit[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0,
+};
+
+static const int8_t quant5[256] = {
+ 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1,
+};
+
+static const int8_t quant9_10bit[256] = {
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+ -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+ -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+ -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+ -4, -4, -4, -4, -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3,
+ -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3,
+ -3, -3, -3, -3, -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -0, -0, -0, -0,
+};
+
+static const int8_t quant11[256] = {
+ 0, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
+ -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
+ -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
+ -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
+ -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5,
+ -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -4, -4,
+ -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4,
+ -4, -4, -4, -4, -4, -3, -3, -3, -3, -3, -3, -3, -2, -2, -2, -1,
+};
+
+static const uint8_t ver2_state[256] = {
+ 0, 10, 10, 10, 10, 16, 16, 16, 28, 16, 16, 29, 42, 49, 20, 49,
+ 59, 25, 26, 26, 27, 31, 33, 33, 33, 34, 34, 37, 67, 38, 39, 39,
+ 40, 40, 41, 79, 43, 44, 45, 45, 48, 48, 64, 50, 51, 52, 88, 52,
+ 53, 74, 55, 57, 58, 58, 74, 60, 101, 61, 62, 84, 66, 66, 68, 69,
+ 87, 82, 71, 97, 73, 73, 82, 75, 111, 77, 94, 78, 87, 81, 83, 97,
+ 85, 83, 94, 86, 99, 89, 90, 99, 111, 92, 93, 134, 95, 98, 105, 98,
+ 105, 110, 102, 108, 102, 118, 103, 106, 106, 113, 109, 112, 114, 112, 116, 125,
+ 115, 116, 117, 117, 126, 119, 125, 121, 121, 123, 145, 124, 126, 131, 127, 129,
+ 165, 130, 132, 138, 133, 135, 145, 136, 137, 139, 146, 141, 143, 142, 144, 148,
+ 147, 155, 151, 149, 151, 150, 152, 157, 153, 154, 156, 168, 158, 162, 161, 160,
+ 172, 163, 169, 164, 166, 184, 167, 170, 177, 174, 171, 173, 182, 176, 180, 178,
+ 175, 189, 179, 181, 186, 183, 192, 185, 200, 187, 191, 188, 190, 197, 193, 196,
+ 197, 194, 195, 196, 198, 202, 199, 201, 210, 203, 207, 204, 205, 206, 208, 214,
+ 209, 211, 221, 212, 213, 215, 224, 216, 217, 218, 219, 220, 222, 228, 223, 225,
+ 226, 224, 227, 229, 240, 230, 231, 232, 233, 234, 235, 236, 238, 239, 237, 242,
+ 241, 243, 242, 244, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255,
+};
+
static void find_best_state(uint8_t best_state[256][256],
const uint8_t one_state[256])
{
@@ -64,8 +159,8 @@ static void find_best_state(uint8_t best_state[256][256],
double newocc[256] = { 0 };
for (m = 1; m < 256; m++)
if (occ[m]) {
- len -= occ[m] * (p * l2tab[m] +
- (1 - p) * l2tab[256 - m]);
+ len -=occ[m]*( p *l2tab[ m]
+ + (1-p)*l2tab[256-m]);
}
if (len < best_len[k]) {
best_len[k] = len;
@@ -73,7 +168,7 @@ static void find_best_state(uint8_t best_state[256][256],
}
for (m = 1; m < 256; m++)
if (occ[m]) {
- newocc[one_state[m]] += occ[m] * p;
+ newocc[ one_state[ m]] += occ[m] * p;
newocc[256 - one_state[256 - m]] += occ[m] * (1 - p);
}
memcpy(occ, newocc, sizeof(occ));
@@ -136,6 +231,7 @@ static av_noinline void put_symbol(RangeCoder *c, uint8_t *state,
put_symbol_inline(c, state, v, is_signed, NULL, NULL);
}
+
static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state,
int v, int bits)
{
@@ -149,7 +245,7 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state,
i += i;
}
- assert(k <= 13);
+ av_assert2(k <= 13);
#if 0 // JPEG LS
if (k == 0 && 2 * state->drift <= -state->count)
@@ -179,7 +275,7 @@ static av_always_inline int encode_line(FFV1Context *s, int w,
int run_mode = 0;
if (s->ac) {
- if (c->bytestream_end - c->bytestream < w * 20) {
+ if (c->bytestream_end - c->bytestream < w * 35) {
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return AVERROR_INVALIDDATA;
}
@@ -190,6 +286,18 @@ static av_always_inline int encode_line(FFV1Context *s, int w,
}
}
+ if (s->slice_coding_mode == 1) {
+ for (x = 0; x < w; x++) {
+ int i;
+ int v = sample[0][x];
+ for (i = bits-1; i>=0; i--) {
+ uint8_t state = 128;
+ put_rac(c, &state, (v>>i) & 1);
+ }
+ }
+ return 0;
+ }
+
for (x = 0; x < w; x++) {
int diff, context;
@@ -257,10 +365,10 @@ static av_always_inline int encode_line(FFV1Context *s, int w,
return 0;
}
-static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h,
+static int encode_plane(FFV1Context *s, uint8_t *src, int w, int h,
int stride, int plane_index)
{
- int x, y, i;
+ int x, y, i, ret;
const int ring_size = s->avctx->context_model ? 3 : 2;
int16_t *sample[3];
s->run_index = 0;
@@ -271,38 +379,40 @@ static void encode_plane(FFV1Context *s, uint8_t *src, int w, int h,
for (i = 0; i < ring_size; i++)
sample[i] = s->sample_buffer + (w + 6) * ((h + i - y) % ring_size) + 3;
- sample[0][-1] = sample[1][0];
- sample[1][w] = sample[1][w - 1];
+ sample[0][-1]= sample[1][0 ];
+ sample[1][ w]= sample[1][w-1];
// { START_TIMER
if (s->bits_per_raw_sample <= 8) {
for (x = 0; x < w; x++)
sample[0][x] = src[x + stride * y];
- encode_line(s, w, sample, plane_index, 8);
+ if((ret = encode_line(s, w, sample, plane_index, 8)) < 0)
+ return ret;
} else {
if (s->packed_at_lsb) {
- for (x = 0; x < w; x++)
- sample[0][x] = ((uint16_t *)(src + stride * y))[x];
+ 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);
+ for (x = 0; x < w; x++) {
+ sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - s->bits_per_raw_sample);
+ }
}
- encode_line(s, w, sample, plane_index, s->bits_per_raw_sample);
+ if((ret = encode_line(s, w, sample, plane_index, s->bits_per_raw_sample)) < 0)
+ return ret;
}
// STOP_TIMER("encode line") }
}
+ return 0;
}
-static void encode_rgb_frame(FFV1Context *s, const uint8_t *src[3],
+static int encode_rgb_frame(FFV1Context *s, const uint8_t *src[3],
int w, int h, const int stride[3])
{
int x, y, p, i;
const int ring_size = s->avctx->context_model ? 3 : 2;
- int16_t *sample[MAX_PLANES][3];
- 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;
+ int16_t *sample[4][3];
+ int lbd = s->bits_per_raw_sample <= 8;
+ int bits = s->bits_per_raw_sample > 0 ? s->bits_per_raw_sample : 8;
int offset = 1 << bits;
s->run_index = 0;
@@ -313,29 +423,29 @@ static void encode_rgb_frame(FFV1Context *s, const uint8_t *src[3],
for (y = 0; y < h; y++) {
for (i = 0; i < ring_size; i++)
for (p = 0; p < MAX_PLANES; p++)
- sample[p][i] = s->sample_buffer + p * ring_size *
- (w + 6) +
- ((h + i - y) % ring_size) * (w + 6) + 3;
+ sample[p][i]= s->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);
if (lbd) {
- unsigned v = *((const uint32_t *)(src[0] + x * 4 + stride[0] * y));
- b = v & 0xFF;
- g = (v >> 8) & 0xFF;
+ unsigned v = *((const uint32_t*)(src[0] + x*4 + stride[0]*y));
+ b = v & 0xFF;
+ g = (v >> 8) & 0xFF;
r = (v >> 16) & 0xFF;
- a = v >> 24;
+ a = v >> 24;
} else {
- b = *((const uint16_t *)(src[0] + x * 2 + stride[0] * y));
- g = *((const uint16_t *)(src[1] + x * 2 + stride[1] * y));
- r = *((const uint16_t *)(src[2] + x * 2 + stride[2] * y));
+ b = *((const uint16_t *)(src[0] + x*2 + stride[0]*y));
+ g = *((const uint16_t *)(src[1] + x*2 + stride[1]*y));
+ r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y));
}
- b -= g;
- r -= g;
- g += (b + r) >> 2;
- b += offset;
- r += offset;
+ if (s->slice_coding_mode != 1) {
+ b -= g;
+ r -= g;
+ g += (b * s->slice_rct_by_coef + r * s->slice_rct_ry_coef) >> 2;
+ b += offset;
+ r += offset;
+ }
sample[0][0][x] = g;
sample[1][0][x] = b;
@@ -343,17 +453,20 @@ static void encode_rgb_frame(FFV1Context *s, const uint8_t *src[3],
sample[3][0][x] = a;
}
for (p = 0; p < 3 + s->transparency; p++) {
- sample[p][0][-1] = sample[p][1][0];
- sample[p][1][w] = sample[p][1][w - 1];
- if (lbd)
- encode_line(s, w, sample[p], (p + 1) / 2, 9);
+ 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 = encode_line(s, w, sample[p], (p + 1) / 2, 9);
else
- encode_line(s, w, sample[p], (p + 1) / 2, bits + 1);
+ ret = encode_line(s, w, sample[p], (p + 1) / 2, bits + (s->slice_coding_mode != 1));
+ if (ret < 0)
+ return ret;
}
}
+ return 0;
}
-
static void write_quant_table(RangeCoder *c, int16_t *quant_table)
{
int last = 0;
@@ -393,7 +506,7 @@ static void write_header(FFV1Context *f)
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->colorspace, 0); //YUV cs type
if (f->version > 0)
put_symbol(c, state, f->bits_per_raw_sample, 0);
put_rac(c, state, f->chroma_planes);
@@ -437,15 +550,19 @@ static int write_extradata(FFV1Context *f)
f->avctx->extradata_size = 10000 + 4 +
(11 * 11 * 5 * 5 * 5 + 11 * 11 * 11) * 32;
- f->avctx->extradata = av_malloc(f->avctx->extradata_size);
+ f->avctx->extradata = av_malloc(f->avctx->extradata_size + FF_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);
put_symbol(c, state, f->version, 0);
if (f->version > 2) {
- if (f->version == 3)
- f->minor_version = 2;
- put_symbol(c, state, f->minor_version, 0);
+ 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->ac, 0);
@@ -485,12 +602,11 @@ static int write_extradata(FFV1Context *f)
if (f->version > 2) {
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);
-
- v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0,
- f->avctx->extradata, f->avctx->extradata_size);
+ v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, f->avctx->extradata, f->avctx->extradata_size);
AV_WL32(f->avctx->extradata + f->avctx->extradata_size, v);
f->avctx->extradata_size += 4;
@@ -515,7 +631,7 @@ static int sort_stt(FFV1Context *s, uint8_t stt[256])
double size0 = COST2(i, i) + COST2(i2, i2);
double sizeX = COST2(i, i2) + COST2(i2, i);
- if (sizeX < size0 && i != 128 && i2 != 128) {
+ if (size0 - sizeX > size0*(1e-14) && i != 128 && i2 != 128) {
int j;
FFSWAP(int, stt[i], stt[i2]);
FFSWAP(int, s->rc_stat[i][0], s->rc_stat[i2][0]);
@@ -545,60 +661,57 @@ static int sort_stt(FFV1Context *s, uint8_t stt[256])
return print;
}
-static av_cold int init_slices_state(FFV1Context *f)
-{
- int i, ret;
- for (i = 0; i < f->slice_count; i++) {
- FFV1Context *fs = f->slice_context[i];
- if ((ret = ffv1_init_slice_state(f, fs)) < 0)
- return AVERROR(ENOMEM);
- }
- return 0;
-}
-
-static av_cold int ffv1_encode_init(AVCodecContext *avctx)
+static av_cold int encode_init(AVCodecContext *avctx)
{
FFV1Context *s = avctx->priv_data;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
int i, j, k, m, ret;
- ffv1_common_init(avctx);
+ if ((ret = ffv1_common_init(avctx)) < 0)
+ return ret;
s->version = 0;
- if ((avctx->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2)) ||
- avctx->slices > 1)
+ if ((avctx->flags & (CODEC_FLAG_PASS1|CODEC_FLAG_PASS2)) || avctx->slices>1)
s->version = FFMAX(s->version, 2);
- if (avctx->level == 3) {
+ // 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);
+
+ if (avctx->level <= 0 && s->version == 2) {
s->version = 3;
}
+ if (avctx->level >= 0 && avctx->level <= 4)
+ s->version = FFMAX(s->version, avctx->level);
if (s->ec < 0) {
s->ec = (s->version >= 3);
}
- if (s->version >= 2 &&
- avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
- av_log(avctx, AV_LOG_ERROR,
- "Version %d requested, please set -strict experimental in "
- "order to enable it\n",
- s->version);
- return AVERROR(ENOSYS);
+ 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");
+ return AVERROR_INVALIDDATA;
}
s->ac = avctx->coder_type > 0 ? 2 : 0;
s->plane_count = 3;
- switch (avctx->pix_fmt) {
+ switch(avctx->pix_fmt) {
case AV_PIX_FMT_YUV444P9:
case AV_PIX_FMT_YUV422P9:
case AV_PIX_FMT_YUV420P9:
+ case AV_PIX_FMT_YUVA444P9:
+ case AV_PIX_FMT_YUVA422P9:
+ case AV_PIX_FMT_YUVA420P9:
if (!avctx->bits_per_raw_sample)
s->bits_per_raw_sample = 9;
case AV_PIX_FMT_YUV444P10:
case AV_PIX_FMT_YUV420P10:
case AV_PIX_FMT_YUV422P10:
+ case AV_PIX_FMT_YUVA444P10:
+ case AV_PIX_FMT_YUVA422P10:
+ case AV_PIX_FMT_YUVA420P10:
s->packed_at_lsb = 1;
if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample)
s->bits_per_raw_sample = 10;
@@ -606,6 +719,9 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
case AV_PIX_FMT_YUV444P16:
case AV_PIX_FMT_YUV422P16:
case AV_PIX_FMT_YUV420P16:
+ case AV_PIX_FMT_YUVA444P16:
+ case AV_PIX_FMT_YUVA422P16:
+ case AV_PIX_FMT_YUVA420P16:
if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) {
s->bits_per_raw_sample = 16;
} else if (!s->bits_per_raw_sample) {
@@ -616,15 +732,12 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
if (!s->ac && avctx->coder_type == -1) {
- av_log(avctx, AV_LOG_INFO,
- "bits_per_raw_sample > 8, forcing coder 1\n");
+ av_log(avctx, AV_LOG_INFO, "bits_per_raw_sample > 8, forcing coder 1\n");
s->ac = 2;
}
if (!s->ac) {
- av_log(
- avctx, AV_LOG_ERROR,
- "bits_per_raw_sample of more than 8 needs -coder 1 currently\n");
- return AVERROR_INVALIDDATA;
+ av_log(avctx, AV_LOG_ERROR, "bits_per_raw_sample of more than 8 needs -coder 1 currently\n");
+ return AVERROR(ENOSYS);
}
s->version = FFMAX(s->version, 1);
case AV_PIX_FMT_GRAY8:
@@ -634,19 +747,27 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUV411P:
case AV_PIX_FMT_YUV410P:
- s->chroma_planes = desc->nb_components < 3 ? 0 : 1;
- s->colorspace = 0;
- break;
case AV_PIX_FMT_YUVA444P:
case AV_PIX_FMT_YUVA422P:
case AV_PIX_FMT_YUVA420P:
- s->chroma_planes = 1;
- s->colorspace = 0;
- s->transparency = 1;
+ s->chroma_planes = desc->nb_components < 3 ? 0 : 1;
+ s->colorspace = 0;
+ s->transparency = desc->nb_components == 4;
+ if (!avctx->bits_per_raw_sample)
+ s->bits_per_raw_sample = 8;
break;
case AV_PIX_FMT_RGB32:
- s->colorspace = 1;
+ s->colorspace = 1;
s->transparency = 1;
+ s->chroma_planes = 1;
+ if (!avctx->bits_per_raw_sample)
+ s->bits_per_raw_sample = 8;
+ break;
+ case AV_PIX_FMT_0RGB32:
+ s->colorspace = 1;
+ s->chroma_planes = 1;
+ if (!avctx->bits_per_raw_sample)
+ s->bits_per_raw_sample = 8;
break;
case AV_PIX_FMT_GBRP9:
if (!avctx->bits_per_raw_sample)
@@ -654,55 +775,64 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
case AV_PIX_FMT_GBRP10:
if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample)
s->bits_per_raw_sample = 10;
- case AV_PIX_FMT_GBRP16:
+ case AV_PIX_FMT_GBRP12:
if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample)
- s->bits_per_raw_sample = 16;
+ s->bits_per_raw_sample = 12;
+ case AV_PIX_FMT_GBRP14:
+ if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample)
+ s->bits_per_raw_sample = 14;
else if (!s->bits_per_raw_sample)
s->bits_per_raw_sample = avctx->bits_per_raw_sample;
- s->colorspace = 1;
+ s->colorspace = 1;
s->chroma_planes = 1;
- s->version = FFMAX(s->version, 1);
+ s->version = FFMAX(s->version, 1);
+ if (!s->ac && avctx->coder_type == -1) {
+ av_log(avctx, AV_LOG_INFO, "bits_per_raw_sample > 8, forcing coder 1\n");
+ s->ac = 2;
+ }
+ if (!s->ac) {
+ av_log(avctx, AV_LOG_ERROR, "bits_per_raw_sample of more than 8 needs -coder 1 currently\n");
+ return AVERROR(ENOSYS);
+ }
break;
default:
av_log(avctx, AV_LOG_ERROR, "format not supported\n");
- return AVERROR_INVALIDDATA;
+ return AVERROR(ENOSYS);
}
+ av_assert0(s->bits_per_raw_sample >= 8);
+
if (s->transparency) {
- av_log(
- avctx, AV_LOG_WARNING,
- "Storing alpha plane, this will require a recent FFV1 decoder to playback!\n");
+ av_log(avctx, AV_LOG_WARNING, "Storing alpha plane, this will require a recent FFV1 decoder to playback!\n");
}
if (avctx->context_model > 1U) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid context model %d, valid values are 0 and 1\n",
- avctx->context_model);
+ av_log(avctx, AV_LOG_ERROR, "Invalid context model %d, valid values are 0 and 1\n", avctx->context_model);
return AVERROR(EINVAL);
}
if (s->ac > 1)
for (i = 1; i < 256; i++)
- s->state_transition[i] = ffv1_ver2_state[i];
+ s->state_transition[i] = ver2_state[i];
for (i = 0; i < 256; i++) {
s->quant_table_count = 2;
if (s->bits_per_raw_sample <= 8) {
- s->quant_tables[0][0][i] = ffv1_quant11[i];
- s->quant_tables[0][1][i] = ffv1_quant11[i] * 11;
- s->quant_tables[0][2][i] = ffv1_quant11[i] * 11 * 11;
- s->quant_tables[1][0][i] = ffv1_quant11[i];
- s->quant_tables[1][1][i] = ffv1_quant11[i] * 11;
- s->quant_tables[1][2][i] = ffv1_quant5[i] * 11 * 11;
- s->quant_tables[1][3][i] = ffv1_quant5[i] * 5 * 11 * 11;
- s->quant_tables[1][4][i] = ffv1_quant5[i] * 5 * 5 * 11 * 11;
+ s->quant_tables[0][0][i]= quant11[i];
+ s->quant_tables[0][1][i]= 11*quant11[i];
+ s->quant_tables[0][2][i]= 11*11*quant11[i];
+ s->quant_tables[1][0][i]= quant11[i];
+ s->quant_tables[1][1][i]= 11*quant11[i];
+ 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];
} else {
- s->quant_tables[0][0][i] = ffv1_quant9_10bit[i];
- s->quant_tables[0][1][i] = ffv1_quant9_10bit[i] * 11;
- s->quant_tables[0][2][i] = ffv1_quant9_10bit[i] * 11 * 11;
- s->quant_tables[1][0][i] = ffv1_quant9_10bit[i];
- s->quant_tables[1][1][i] = ffv1_quant9_10bit[i] * 11;
- s->quant_tables[1][2][i] = ffv1_quant5_10bit[i] * 11 * 11;
- s->quant_tables[1][3][i] = ffv1_quant5_10bit[i] * 5 * 11 * 11;
- s->quant_tables[1][4][i] = ffv1_quant5_10bit[i] * 5 * 5 * 11 * 11;
+ 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[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->context_count[0] = (11 * 11 * 11 + 1) / 2;
@@ -729,10 +859,10 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
if (!s->transparency)
s->plane_count = 2;
+ if (!s->chroma_planes && s->version > 3)
+ s->plane_count--;
- av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift,
- &s->chroma_v_shift);
-
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift);
s->picture_number = 0;
if (avctx->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2)) {
@@ -745,19 +875,22 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
}
if (avctx->stats_in) {
char *p = avctx->stats_in;
- uint8_t best_state[256][256];
+ uint8_t (*best_state)[256] = av_malloc_array(256, 256);
int gob_count = 0;
char *next;
+ if (!best_state)
+ return AVERROR(ENOMEM);
av_assert0(s->version >= 2);
- for (;; ) {
+ for (;;) {
for (j = 0; j < 256; j++)
for (i = 0; i < 2; i++) {
s->rc_stat[j][i] = strtol(p, &next, 0);
if (next == p) {
av_log(avctx, AV_LOG_ERROR,
"2Pass file invalid at %d %d [%s]\n", j, i, p);
+ av_freep(&best_state);
return AVERROR_INVALIDDATA;
}
p = next;
@@ -771,6 +904,7 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR,
"2Pass file invalid at %d %d %d %d [%s]\n",
i, j, k, m, p);
+ av_freep(&best_state);
return AVERROR_INVALIDDATA;
}
p = next;
@@ -779,6 +913,7 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
gob_count = strtol(p, &next, 0);
if (next == p || gob_count <= 0) {
av_log(avctx, AV_LOG_ERROR, "2Pass file invalid\n");
+ av_freep(&best_state);
return AVERROR_INVALIDDATA;
}
p = next;
@@ -792,45 +927,61 @@ static av_cold int ffv1_encode_init(AVCodecContext *avctx)
find_best_state(best_state, s->state_transition);
for (i = 0; i < s->quant_table_count; i++) {
- for (j = 0; j < s->context_count[i]; j++)
- for (k = 0; k < 32; k++) {
+ for (k = 0; k < 32; k++) {
+ double a=0, b=0;
+ int jp = 0;
+ for (j = 0; j < s->context_count[i]; j++) {
double p = 128;
- if (s->rc_stat2[i][j][k][0] + s->rc_stat2[i][j][k][1]) {
- p = 256.0 * s->rc_stat2[i][j][k][1] /
- (s->rc_stat2[i][j][k][0] + s->rc_stat2[i][j][k][1]);
+ if (s->rc_stat2[i][j][k][0] + s->rc_stat2[i][j][k][1] > 200 && j || a+b > 200) {
+ if (a+b)
+ p = 256.0 * b / (a + b);
+ s->initial_states[i][jp][k] =
+ best_state[av_clip(round(p), 1, 255)][av_clip_uint8((a + b) / gob_count)];
+ for(jp++; jp<j; jp++)
+ s->initial_states[i][jp][k] = s->initial_states[i][jp-1][k];
+ a=b=0;
+ }
+ a += s->rc_stat2[i][j][k][0];
+ b += s->rc_stat2[i][j][k][1];
+ if (a+b) {
+ p = 256.0 * b / (a + b);
}
s->initial_states[i][j][k] =
- best_state[av_clip(round(p), 1, 255)][av_clip((s->rc_stat2[i][j][k][0] +
- s->rc_stat2[i][j][k][1]) /
- gob_count, 0, 255)];
+ best_state[av_clip(round(p), 1, 255)][av_clip_uint8((a + b) / gob_count)];
}
+ }
}
+ av_freep(&best_state);
}
if (s->version > 1) {
- for (s->num_v_slices = 2; s->num_v_slices < 9; s->num_v_slices++)
- for (s->num_h_slices = s->num_v_slices;
- s->num_h_slices < 2 * s->num_v_slices; s->num_h_slices++)
- if (avctx->slices == s->num_h_slices * s->num_v_slices &&
- avctx->slices <= 64 || !avctx->slices)
+ s->num_v_slices = (avctx->width > 352 || avctx->height > 288 || !avctx->slices) ? 2 : 1;
+ for (; s->num_v_slices < 9; s->num_v_slices++) {
+ for (s->num_h_slices = s->num_v_slices; s->num_h_slices < 2*s->num_v_slices; s->num_h_slices++) {
+ if (avctx->slices == s->num_h_slices * s->num_v_slices && avctx->slices <= 64 || !avctx->slices)
goto slices_ok;
+ }
+ }
av_log(avctx, AV_LOG_ERROR,
"Unsupported number %d of slices requested, please specify a "
"supported number with -slices (ex:4,6,9,12,16, ...)\n",
avctx->slices);
return AVERROR(ENOSYS);
slices_ok:
- write_extradata(s);
+ if ((ret = write_extradata(s)) < 0)
+ return ret;
}
if ((ret = ffv1_init_slice_contexts(s)) < 0)
return ret;
- if ((ret = init_slices_state(s)) < 0)
+ if ((ret = ffv1_init_slices_state(s)) < 0)
return ret;
#define STATS_OUT_SIZE 1024 * 1024 * 6
if (avctx->flags & CODEC_FLAG_PASS1) {
avctx->stats_out = av_mallocz(STATS_OUT_SIZE);
+ if (!avctx->stats_out)
+ return AVERROR(ENOMEM);
for (i = 0; i < s->quant_table_count; i++)
for (j = 0; j < s->slice_count; j++) {
FFV1Context *sf = s->slice_context[j];
@@ -852,23 +1003,112 @@ static void encode_slice_header(FFV1Context *f, FFV1Context *fs)
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);
- for (j = 0; j < f->plane_count; j++) {
+ 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);
+ 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->avctx->context_model);
}
- if (!f->avctx->coded_frame->interlaced_frame)
+ if (!f->picture.f->interlaced_frame)
put_symbol(c, state, 3, 0);
else
- put_symbol(c, state, 1 + !f->avctx->coded_frame->top_field_first, 0);
- put_symbol(c, state, f->avctx->coded_frame->sample_aspect_ratio.num, 0);
- put_symbol(c, state, f->avctx->coded_frame->sample_aspect_ratio.den, 0);
+ put_symbol(c, state, 1 + !f->picture.f->top_field_first, 0);
+ put_symbol(c, state, f->picture.f->sample_aspect_ratio.num, 0);
+ put_symbol(c, state, f->picture.f->sample_aspect_ratio.den, 0);
+ if (f->version > 3) {
+ put_rac(c, state, fs->slice_coding_mode == 1);
+ if (fs->slice_coding_mode == 1)
+ 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);
+ }
+ }
+}
+
+static void choose_rct_params(FFV1Context *fs, 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] = {
+ {0, 0}, // 4G
+ {1, 1}, // R + 2G + B
+ {2, 2}, // 2R + 2B
+ {0, 2}, // 2G + 2B
+ {2, 0}, // 2R + 2G
+ {4, 0}, // 4R
+ {0, 4}, // 4B
+
+ {0, 3}, // 1G + 3B
+ {3, 0}, // 3R + 1G
+ {3, 1}, // 3R + B
+ {1, 3}, // R + 3B
+ {1, 2}, // R + G + 2B
+ {2, 1}, // 2R + G + B
+ {0, 1}, // 3G + B
+ {1, 0}, // R + 3G
+ };
+
+ int stat[NB_Y_COEFF] = {0};
+ int x, y, i, p, best;
+ int16_t *sample[3];
+ int lbd = fs->bits_per_raw_sample <= 8;
+
+ 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;
+
+ for (x = 0; x < w; x++) {
+ int b, g, r;
+ int ab, ag, ar;
+ if (lbd) {
+ unsigned v = *((const uint32_t*)(src[0] + x*4 + stride[0]*y));
+ b = v & 0xFF;
+ g = (v >> 8) & 0xFF;
+ r = (v >> 16) & 0xFF;
+ } else {
+ b = *((const uint16_t*)(src[0] + x*2 + stride[0]*y));
+ g = *((const uint16_t*)(src[1] + x*2 + stride[1]*y));
+ r = *((const uint16_t*)(src[2] + x*2 + stride[2]*y));
+ }
+
+ ar = r - lastr;
+ ag = g - lastg;
+ ab = b - lastb;
+ if (x && y) {
+ int bg = ag - sample[0][x];
+ int bb = ab - sample[1][x];
+ int br = ar - sample[2][x];
+
+ br -= bg;
+ bb -= bg;
+
+ for (i = 0; i<NB_Y_COEFF; i++) {
+ stat[i] += FFABS(bg + ((br*rct_y_coeff[i][0] + bb*rct_y_coeff[i][1])>>2));
+ }
+
+ }
+ sample[0][x] = ag;
+ sample[1][x] = ab;
+ sample[2][x] = ar;
+
+ lastr = r;
+ lastg = g;
+ lastb = b;
+ }
+ }
+
+ best = 0;
+ for (i=1; i<NB_Y_COEFF; i++) {
+ if (stat[i] < stat[best])
+ best = i;
+ }
+
+ fs->slice_rct_by_coef = rct_y_coeff[best][1];
+ fs->slice_rct_ry_coef = rct_y_coeff[best][0];
}
static int encode_slice(AVCodecContext *c, void *arg)
@@ -879,11 +1119,23 @@ static int encode_slice(AVCodecContext *c, void *arg)
int height = fs->slice_height;
int x = fs->slice_x;
int y = fs->slice_y;
- const AVFrame *const p = f->frame;
- const int ps = (av_pix_fmt_desc_get(c->pix_fmt)->flags & AV_PIX_FMT_FLAG_PLANAR)
- ? (f->bits_per_raw_sample > 8) + 1
- : 4;
+ const AVFrame *const p = f->picture.f;
+ const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step_minus1 + 1;
+ int ret;
+ RangeCoder c_bak = fs->c;
+ const uint8_t *planes[3] = {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]};
+
+ fs->slice_coding_mode = 0;
+ if (f->version > 3) {
+ choose_rct_params(fs, planes, p->linesize, width, height);
+ } else {
+ fs->slice_rct_by_coef = 1;
+ fs->slice_rct_ry_coef = 1;
+ }
+retry:
if (c->coded_frame->key_frame)
ffv1_clear_slice_state(f, fs);
if (f->version > 2) {
@@ -892,71 +1144,126 @@ static int encode_slice(AVCodecContext *c, void *arg)
if (!fs->ac) {
if (f->version > 2)
put_rac(&fs->c, (uint8_t[]) { 129 }, 0);
- fs->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate( &fs->c) : 0;
- init_put_bits(&fs->pb, fs->c.bytestream_start + fs->ac_byte_count,
+ fs->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&fs->c) : 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->colorspace == 0) {
- const int chroma_width = -((-width) >> f->chroma_h_shift);
- const int chroma_height = -((-height) >> f->chroma_v_shift);
+ const int chroma_width = FF_CEIL_RSHIFT(width, f->chroma_h_shift);
+ const int chroma_height = FF_CEIL_RSHIFT(height, f->chroma_v_shift);
const int cx = x >> f->chroma_h_shift;
const int cy = y >> f->chroma_v_shift;
- encode_plane(fs, p->data[0] + ps * x + y * p->linesize[0],
- width, height, p->linesize[0], 0);
+ ret = encode_plane(fs, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0);
if (f->chroma_planes) {
- encode_plane(fs, p->data[1] + ps * cx + cy * p->linesize[1],
- chroma_width, chroma_height, p->linesize[1], 1);
- encode_plane(fs, p->data[2] + ps * cx + cy * p->linesize[2],
- chroma_width, chroma_height, p->linesize[2], 1);
+ ret |= encode_plane(fs, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1);
+ ret |= encode_plane(fs, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1);
}
if (fs->transparency)
- encode_plane(fs, p->data[3] + ps * x + y * p->linesize[3], width,
- height, p->linesize[3], 2);
+ ret |= encode_plane(fs, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2);
} else {
- const uint8_t *planes[3] = { 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] };
- encode_rgb_frame(fs, planes, width, height, p->linesize);
+ ret = encode_rgb_frame(fs, planes, width, height, p->linesize);
}
emms_c();
+ if (ret < 0) {
+ av_assert0(fs->slice_coding_mode == 0);
+ if (fs->version < 4 || !fs->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;
+ goto retry;
+ }
+
return 0;
}
-static int ffv1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+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;
- AVFrame *const p = avctx->coded_frame;
+ AVFrame *const p = f->picture.f;
int used_count = 0;
uint8_t keystate = 128;
uint8_t *buf_p;
int i, ret;
+ int64_t maxsize = FF_MIN_BUFFER_SIZE
+ + avctx->width*avctx->height*35LL*4;
+
+ if(!pict) {
+ if (avctx->flags & CODEC_FLAG_PASS1) {
+ int j, k, m;
+ char *p = avctx->stats_out;
+ char *end = p + STATS_OUT_SIZE;
+
+ memset(f->rc_stat, 0, sizeof(f->rc_stat));
+ for (i = 0; i < f->quant_table_count; i++)
+ memset(f->rc_stat2[i], 0, f->context_count[i] * sizeof(*f->rc_stat2[i]));
+
+ for (j = 0; j < f->slice_count; j++) {
+ FFV1Context *fs = f->slice_context[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];
+ }
+ 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->frame = pict;
+ for (j = 0; j < 256; j++) {
+ snprintf(p, end - p, "%" PRIu64 " %" PRIu64 " ",
+ f->rc_stat[j][0], f->rc_stat[j][1]);
+ p += strlen(p);
+ }
+ snprintf(p, end - p, "\n");
- if ((ret = ff_alloc_packet(pkt, avctx->width * avctx->height *
- ((8 * 2 + 1 + 1) * 4) / 8 +
- FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
- return ret;
+ for (i = 0; i < f->quant_table_count; i++) {
+ for (j = 0; j < f->context_count[i]; j++)
+ for (m = 0; m < 32; m++) {
+ snprintf(p, end - p, "%" PRIu64 " %" PRIu64 " ",
+ f->rc_stat2[i][j][m][0], f->rc_stat2[i][j][m][1]);
+ p += strlen(p);
+ }
+ }
+ snprintf(p, end - p, "%d\n", f->gob_count);
+ }
+ return 0;
}
+ if (f->version > 3)
+ maxsize = FF_MIN_BUFFER_SIZE + avctx->width*avctx->height*3LL*4;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, maxsize)) < 0)
+ return ret;
+
ff_init_range_encoder(c, pkt->data, pkt->size);
ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
+ av_frame_unref(p);
+ if ((ret = av_frame_ref(p, pict)) < 0)
+ return ret;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
if (avctx->gop_size == 0 || f->picture_number % avctx->gop_size == 0) {
put_rac(c, &keystate, 1);
- p->key_frame = 1;
+ avctx->coded_frame->key_frame = 1;
f->gob_count++;
write_header(f);
} else {
put_rac(c, &keystate, 0);
- p->key_frame = 0;
+ avctx->coded_frame->key_frame = 0;
}
if (f->ac > 1) {
@@ -969,9 +1276,8 @@ static int ffv1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
for (i = 1; i < f->slice_count; i++) {
FFV1Context *fs = f->slice_context[i];
- uint8_t *start = pkt->data +
- (pkt->size - used_count) * (int64_t)i / f->slice_count;
- int len = pkt->size / f->slice_count;
+ uint8_t *start = pkt->data + (pkt->size - used_count) * (int64_t)i / f->slice_count;
+ int len = pkt->size / f->slice_count;
ff_init_range_encoder(&fs->c, start, len);
}
avctx->execute(avctx, encode_slice, &f->slice_context[0], NULL,
@@ -1007,58 +1313,20 @@ static int ffv1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
buf_p += bytes;
}
- if ((avctx->flags & CODEC_FLAG_PASS1) && (f->picture_number & 31) == 0) {
- int j, k, m;
- char *p = avctx->stats_out;
- char *end = p + STATS_OUT_SIZE;
-
- memset(f->rc_stat, 0, sizeof(f->rc_stat));
- for (i = 0; i < f->quant_table_count; i++)
- memset(f->rc_stat2[i], 0, f->context_count[i] * sizeof(*f->rc_stat2[i]));
-
- for (j = 0; j < f->slice_count; j++) {
- FFV1Context *fs = f->slice_context[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];
- }
- 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];
- }
- }
- }
-
- for (j = 0; j < 256; j++) {
- snprintf(p, end - p, "%" PRIu64 " %" PRIu64 " ",
- f->rc_stat[j][0], f->rc_stat[j][1]);
- p += strlen(p);
- }
- snprintf(p, end - p, "\n");
-
- for (i = 0; i < f->quant_table_count; i++) {
- for (j = 0; j < f->context_count[i]; j++)
- for (m = 0; m < 32; m++) {
- snprintf(p, end - p, "%" PRIu64 " %" PRIu64 " ",
- f->rc_stat2[i][j][m][0], f->rc_stat2[i][j][m][1]);
- p += strlen(p);
- }
- }
- snprintf(p, end - p, "%d\n", f->gob_count);
- } else if (avctx->flags & CODEC_FLAG_PASS1)
+ if (avctx->flags & CODEC_FLAG_PASS1)
avctx->stats_out[0] = '\0';
f->picture_number++;
pkt->size = buf_p - pkt->data;
- pkt->flags |= AV_PKT_FLAG_KEY * p->key_frame;
+ pkt->pts =
+ pkt->dts = pict->pts;
+ pkt->flags |= AV_PKT_FLAG_KEY * avctx->coded_frame->key_frame;
*got_packet = 1;
return 0;
}
-static av_cold int ffv1_encode_close(AVCodecContext *avctx)
+static av_cold int encode_close(AVCodecContext *avctx)
{
av_frame_free(&avctx->coded_frame);
ffv1_close(avctx);
@@ -1068,12 +1336,11 @@ static av_cold int ffv1_encode_close(AVCodecContext *avctx)
#define OFFSET(x) offsetof(FFV1Context, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_INT,
- { .i64 = -1 }, -1, 1, VE },
+ { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE },
{ NULL }
};
-static const AVClass class = {
+static const AVClass ffv1_class = {
.class_name = "ffv1 encoder",
.item_name = av_default_item_name,
.option = options,
@@ -1091,23 +1358,24 @@ AVCodec ff_ffv1_encoder = {
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_FFV1,
.priv_data_size = sizeof(FFV1Context),
- .init = ffv1_encode_init,
- .encode2 = ffv1_encode_frame,
- .close = ffv1_encode_close,
- .capabilities = CODEC_CAP_SLICE_THREADS,
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_close,
+ .capabilities = CODEC_CAP_SLICE_THREADS | CODEC_CAP_DELAY,
.pix_fmts = (const enum AVPixelFormat[]) {
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
- AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
- AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
- AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
- AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
- AV_PIX_FMT_RGB32,
- AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
- AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
- AV_PIX_FMT_GRAY16, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_0RGB32, AV_PIX_FMT_RGB32, AV_PIX_FMT_YUV420P16,
+ AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9,
+ AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA420P16,
+ AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
+ AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
+ AV_PIX_FMT_GRAY16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
+ AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14,
AV_PIX_FMT_NONE
},
.defaults = ffv1_defaults,
- .priv_class = &class,
+ .priv_class = &ffv1_class,
};
diff --git a/libavcodec/ffwavesynth.c b/libavcodec/ffwavesynth.c
new file mode 100644
index 0000000000..e835934fa0
--- /dev/null
+++ b/libavcodec/ffwavesynth.c
@@ -0,0 +1,481 @@
+/*
+ * Wavesynth pseudo-codec
+ * Copyright (c) 2011 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+#include "avcodec.h"
+#include "internal.h"
+
+
+#define SIN_BITS 14
+#define WS_MAX_CHANNELS 32
+#define INF_TS 0x7FFFFFFFFFFFFFFF
+
+#define PINK_UNIT 128
+
+/*
+ Format of the extradata and packets
+
+ THIS INFORMATION IS NOT PART OF THE PUBLIC API OR ABI.
+ IT CAN CHANGE WITHOUT NOTIFICATION.
+
+ All numbers are in little endian.
+
+ The codec extradata define a set of intervals with uniform content.
+ Overlapping intervals are added together.
+
+ extradata:
+ uint32 number of intervals
+ ... intervals
+
+ interval:
+ int64 start timestamp; time_base must be 1/sample_rate;
+ start timestamps must be in ascending order
+ int64 end timestamp
+ uint32 type
+ uint32 channels mask
+ ... additional information, depends on type
+
+ sine interval (type fourcc "SINE"):
+ int32 start frequency, in 1/(1<<16) Hz
+ int32 end frequency
+ int32 start amplitude, 1<<16 is the full amplitude
+ int32 end amplitude
+ uint32 start phase, 0 is sin(0), 0x20000000 is sin(pi/2), etc.;
+ n | (1<<31) means to match the phase of previous channel #n
+
+ pink noise interval (type fourcc "NOIS"):
+ int32 start amplitude
+ int32 end amplitude
+
+ The input packets encode the time and duration of the requested segment.
+
+ packet:
+ int64 start timestamp
+ int32 duration
+
+*/
+
+enum ws_interval_type {
+ WS_SINE = MKTAG('S','I','N','E'),
+ WS_NOISE = MKTAG('N','O','I','S'),
+};
+
+struct ws_interval {
+ int64_t ts_start, ts_end;
+ uint64_t phi0, dphi0, ddphi;
+ uint64_t amp0, damp;
+ uint64_t phi, dphi, amp;
+ uint32_t channels;
+ enum ws_interval_type type;
+ int next;
+};
+
+struct wavesynth_context {
+ int64_t cur_ts;
+ int64_t next_ts;
+ int32_t *sin;
+ struct ws_interval *inter;
+ uint32_t dither_state;
+ uint32_t pink_state;
+ int32_t pink_pool[PINK_UNIT];
+ unsigned pink_need, pink_pos;
+ int nb_inter;
+ int cur_inter;
+ int next_inter;
+};
+
+#define LCG_A 1284865837
+#define LCG_C 4150755663
+#define LCG_AI 849225893 /* A*AI = 1 [mod 1<<32] */
+
+static uint32_t lcg_next(uint32_t *s)
+{
+ *s = *s * LCG_A + LCG_C;
+ return *s;
+}
+
+static void lcg_seek(uint32_t *s, int64_t dt)
+{
+ uint32_t a, c, t = *s;
+
+ if (dt >= 0) {
+ a = LCG_A;
+ c = LCG_C;
+ } else { /* coefficients for a step backward */
+ a = LCG_AI;
+ c = (uint32_t)(LCG_AI * LCG_C);
+ dt = -dt;
+ }
+ while (dt) {
+ if (dt & 1)
+ t = a * t + c;
+ c *= a + 1; /* coefficients for a double step */
+ a *= a;
+ dt >>= 1;
+ }
+ *s = t;
+}
+
+/* Emulate pink noise by summing white noise at the sampling frequency,
+ * white noise at half the sampling frequency (each value taken twice),
+ * etc., with a total of 8 octaves.
+ * This is known as the Voss-McCartney algorithm. */
+
+static void pink_fill(struct wavesynth_context *ws)
+{
+ int32_t vt[7] = { 0 }, v = 0;
+ int i, j;
+
+ ws->pink_pos = 0;
+ if (!ws->pink_need)
+ return;
+ for (i = 0; i < PINK_UNIT; i++) {
+ for (j = 0; j < 7; j++) {
+ if ((i >> j) & 1)
+ break;
+ v -= vt[j];
+ vt[j] = (int32_t)lcg_next(&ws->pink_state) >> 3;
+ v += vt[j];
+ }
+ ws->pink_pool[i] = v + ((int32_t)lcg_next(&ws->pink_state) >> 3);
+ }
+ lcg_next(&ws->pink_state); /* so we use exactly 256 steps */
+}
+
+/**
+ * @return (1<<64) * a / b, without overflow, if a < b
+ */
+static uint64_t frac64(uint64_t a, uint64_t b)
+{
+ uint64_t r = 0;
+ int i;
+
+ if (b < (uint64_t)1 << 32) { /* b small, use two 32-bits steps */
+ a <<= 32;
+ return ((a / b) << 32) | ((a % b) << 32) / b;
+ }
+ if (b < (uint64_t)1 << 48) { /* b medium, use four 16-bits steps */
+ for (i = 0; i < 4; i++) {
+ a <<= 16;
+ r = (r << 16) | (a / b);
+ a %= b;
+ }
+ return r;
+ }
+ for (i = 63; i >= 0; i--) {
+ if (a >= (uint64_t)1 << 63 || a << 1 >= b) {
+ r |= (uint64_t)1 << i;
+ a = (a << 1) - b;
+ } else {
+ a <<= 1;
+ }
+ }
+ return r;
+}
+
+static uint64_t phi_at(struct ws_interval *in, int64_t ts)
+{
+ uint64_t dt = ts - in->ts_start;
+ uint64_t dt2 = dt & 1 ? /* dt * (dt - 1) / 2 without overflow */
+ dt * ((dt - 1) >> 1) : (dt >> 1) * (dt - 1);
+ return in->phi0 + dt * in->dphi0 + dt2 * in->ddphi;
+}
+
+static void wavesynth_seek(struct wavesynth_context *ws, int64_t ts)
+{
+ int *last, i;
+ struct ws_interval *in;
+
+ last = &ws->cur_inter;
+ for (i = 0; i < ws->nb_inter; i++) {
+ in = &ws->inter[i];
+ if (ts < in->ts_start)
+ break;
+ if (ts >= in->ts_end)
+ continue;
+ *last = i;
+ last = &in->next;
+ in->phi = phi_at(in, ts);
+ in->dphi = in->dphi0 + (ts - in->ts_start) * in->ddphi;
+ in->amp = in->amp0 + (ts - in->ts_start) * in->damp;
+ }
+ ws->next_inter = i;
+ ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS;
+ *last = -1;
+ lcg_seek(&ws->dither_state, ts - ws->cur_ts);
+ if (ws->pink_need) {
+ int64_t pink_ts_cur = (ws->cur_ts + PINK_UNIT - 1) & ~(PINK_UNIT - 1);
+ int64_t pink_ts_next = ts & ~(PINK_UNIT - 1);
+ int pos = ts & (PINK_UNIT - 1);
+ lcg_seek(&ws->pink_state, (pink_ts_next - pink_ts_cur) << 1);
+ if (pos) {
+ pink_fill(ws);
+ ws->pink_pos = pos;
+ } else {
+ ws->pink_pos = PINK_UNIT;
+ }
+ }
+ ws->cur_ts = ts;
+}
+
+static int wavesynth_parse_extradata(AVCodecContext *avc)
+{
+ struct wavesynth_context *ws = avc->priv_data;
+ struct ws_interval *in;
+ uint8_t *edata, *edata_end;
+ int32_t f1, f2, a1, a2;
+ uint32_t phi;
+ int64_t dphi1, dphi2, dt, cur_ts = -0x8000000000000000;
+ int i;
+
+ if (avc->extradata_size < 4)
+ return AVERROR(EINVAL);
+ edata = avc->extradata;
+ edata_end = edata + avc->extradata_size;
+ ws->nb_inter = AV_RL32(edata);
+ edata += 4;
+ if (ws->nb_inter < 0)
+ return AVERROR(EINVAL);
+ ws->inter = av_calloc(ws->nb_inter, sizeof(*ws->inter));
+ if (!ws->inter)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < ws->nb_inter; i++) {
+ in = &ws->inter[i];
+ if (edata_end - edata < 24)
+ return AVERROR(EINVAL);
+ in->ts_start = AV_RL64(edata + 0);
+ in->ts_end = AV_RL64(edata + 8);
+ in->type = AV_RL32(edata + 16);
+ in->channels = AV_RL32(edata + 20);
+ edata += 24;
+ if (in->ts_start < cur_ts || in->ts_end <= in->ts_start)
+ return AVERROR(EINVAL);
+ cur_ts = in->ts_start;
+ dt = in->ts_end - in->ts_start;
+ switch (in->type) {
+ case WS_SINE:
+ if (edata_end - edata < 20)
+ return AVERROR(EINVAL);
+ f1 = AV_RL32(edata + 0);
+ f2 = AV_RL32(edata + 4);
+ a1 = AV_RL32(edata + 8);
+ a2 = AV_RL32(edata + 12);
+ phi = AV_RL32(edata + 16);
+ edata += 20;
+ dphi1 = frac64(f1, (int64_t)avc->sample_rate << 16);
+ dphi2 = frac64(f2, (int64_t)avc->sample_rate << 16);
+ in->dphi0 = dphi1;
+ in->ddphi = (dphi2 - dphi1) / dt;
+ if (phi & 0x80000000) {
+ phi &= ~0x80000000;
+ if (phi >= i)
+ return AVERROR(EINVAL);
+ in->phi0 = phi_at(&ws->inter[phi], in->ts_start);
+ } else {
+ in->phi0 = (uint64_t)phi << 33;
+ }
+ break;
+ case WS_NOISE:
+ if (edata_end - edata < 8)
+ return AVERROR(EINVAL);
+ a1 = AV_RL32(edata + 0);
+ a2 = AV_RL32(edata + 4);
+ edata += 8;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+ in->amp0 = (int64_t)a1 << 32;
+ in->damp = (((int64_t)a2 << 32) - ((int64_t)a1 << 32)) / dt;
+ }
+ if (edata != edata_end)
+ return AVERROR(EINVAL);
+ return 0;
+}
+
+static av_cold int wavesynth_init(AVCodecContext *avc)
+{
+ struct wavesynth_context *ws = avc->priv_data;
+ int i, r;
+
+ if (avc->channels > WS_MAX_CHANNELS) {
+ av_log(avc, AV_LOG_ERROR,
+ "This implementation is limited to %d channels.\n",
+ WS_MAX_CHANNELS);
+ return AVERROR(EINVAL);
+ }
+ r = wavesynth_parse_extradata(avc);
+ if (r < 0) {
+ av_log(avc, AV_LOG_ERROR, "Invalid intervals definitions.\n");
+ goto fail;
+ }
+ ws->sin = av_malloc(sizeof(*ws->sin) << SIN_BITS);
+ if (!ws->sin) {
+ r = AVERROR(ENOMEM);
+ goto fail;
+ }
+ for (i = 0; i < 1 << SIN_BITS; i++)
+ ws->sin[i] = floor(32767 * sin(2 * M_PI * i / (1 << SIN_BITS)));
+ ws->dither_state = MKTAG('D','I','T','H');
+ for (i = 0; i < ws->nb_inter; i++)
+ ws->pink_need += ws->inter[i].type == WS_NOISE;
+ ws->pink_state = MKTAG('P','I','N','K');
+ ws->pink_pos = PINK_UNIT;
+ wavesynth_seek(ws, 0);
+ avc->sample_fmt = AV_SAMPLE_FMT_S16;
+ return 0;
+
+fail:
+ av_freep(&ws->inter);
+ av_freep(&ws->sin);
+ return r;
+}
+
+static void wavesynth_synth_sample(struct wavesynth_context *ws, int64_t ts,
+ int32_t *channels)
+{
+ int32_t amp, val, *cv;
+ struct ws_interval *in;
+ int i, *last, pink;
+ uint32_t c, all_ch = 0;
+
+ i = ws->cur_inter;
+ last = &ws->cur_inter;
+ if (ws->pink_pos == PINK_UNIT)
+ pink_fill(ws);
+ pink = ws->pink_pool[ws->pink_pos++] >> 16;
+ while (i >= 0) {
+ in = &ws->inter[i];
+ i = in->next;
+ if (ts >= in->ts_end) {
+ *last = i;
+ continue;
+ }
+ last = &in->next;
+ amp = in->amp >> 32;
+ in->amp += in->damp;
+ switch (in->type) {
+ case WS_SINE:
+ val = amp * ws->sin[in->phi >> (64 - SIN_BITS)];
+ in->phi += in->dphi;
+ in->dphi += in->ddphi;
+ break;
+ case WS_NOISE:
+ val = amp * pink;
+ break;
+ default:
+ val = 0;
+ }
+ all_ch |= in->channels;
+ for (c = in->channels, cv = channels; c; c >>= 1, cv++)
+ if (c & 1)
+ *cv += val;
+ }
+ val = (int32_t)lcg_next(&ws->dither_state) >> 16;
+ for (c = all_ch, cv = channels; c; c >>= 1, cv++)
+ if (c & 1)
+ *cv += val;
+}
+
+static void wavesynth_enter_intervals(struct wavesynth_context *ws, int64_t ts)
+{
+ int *last, i;
+ struct ws_interval *in;
+
+ last = &ws->cur_inter;
+ for (i = ws->cur_inter; i >= 0; i = ws->inter[i].next)
+ last = &ws->inter[i].next;
+ for (i = ws->next_inter; i < ws->nb_inter; i++) {
+ in = &ws->inter[i];
+ if (ts < in->ts_start)
+ break;
+ if (ts >= in->ts_end)
+ continue;
+ *last = i;
+ last = &in->next;
+ in->phi = in->phi0;
+ in->dphi = in->dphi0;
+ in->amp = in->amp0;
+ }
+ ws->next_inter = i;
+ ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS;
+ *last = -1;
+}
+
+static int wavesynth_decode(AVCodecContext *avc, void *rframe, int *rgot_frame,
+ AVPacket *packet)
+{
+ struct wavesynth_context *ws = avc->priv_data;
+ AVFrame *frame = rframe;
+ int64_t ts;
+ int duration;
+ int s, c, r;
+ int16_t *pcm;
+ int32_t channels[WS_MAX_CHANNELS];
+
+ *rgot_frame = 0;
+ if (packet->size != 12)
+ return AVERROR_INVALIDDATA;
+ ts = AV_RL64(packet->data);
+ if (ts != ws->cur_ts)
+ wavesynth_seek(ws, ts);
+ duration = AV_RL32(packet->data + 8);
+ if (duration <= 0)
+ return AVERROR(EINVAL);
+ frame->nb_samples = duration;
+ r = ff_get_buffer(avc, frame, 0);
+ if (r < 0)
+ return r;
+ pcm = (int16_t *)frame->data[0];
+ for (s = 0; s < duration; s++, ts++) {
+ memset(channels, 0, avc->channels * sizeof(*channels));
+ if (ts >= ws->next_ts)
+ wavesynth_enter_intervals(ws, ts);
+ wavesynth_synth_sample(ws, ts, channels);
+ for (c = 0; c < avc->channels; c++)
+ *(pcm++) = channels[c] >> 16;
+ }
+ ws->cur_ts += duration;
+ *rgot_frame = 1;
+ return packet->size;
+}
+
+static av_cold int wavesynth_close(AVCodecContext *avc)
+{
+ struct wavesynth_context *ws = avc->priv_data;
+
+ av_freep(&ws->sin);
+ av_freep(&ws->inter);
+ return 0;
+}
+
+AVCodec ff_ffwavesynth_decoder = {
+ .name = "wavesynth",
+ .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_FFWAVESYNTH,
+ .priv_data_size = sizeof(struct wavesynth_context),
+ .init = wavesynth_init,
+ .close = wavesynth_close,
+ .decode = wavesynth_decode,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/fic.c b/libavcodec/fic.c
index 8512ef3400..48e7a6ea0a 100644
--- a/libavcodec/fic.c
+++ b/libavcodec/fic.c
@@ -4,20 +4,20 @@
* Copyright (c) 2014 Konstantin Shishkov
* Copyright (c) 2014 Derek Buitenhuis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -79,7 +79,7 @@ static const uint8_t fic_header[7] = { 0, 0, 1, 'F', 'I', 'C', 'V' };
#define FIC_HEADER_SIZE 27
-static av_always_inline void fic_idct(int16_t *blk, int step, int shift)
+static av_always_inline void fic_idct(int16_t *blk, int step, int shift, int rnd)
{
const int t0 = 27246 * blk[3 * step] + 18405 * blk[5 * step];
const int t1 = 27246 * blk[5 * step] - 18405 * blk[3 * step];
@@ -91,8 +91,8 @@ static av_always_inline void fic_idct(int16_t *blk, int step, int shift)
const int t7 = t3 - t1;
const int t8 = 17734 * blk[2 * step] - 42813 * blk[6 * step];
const int t9 = 17734 * blk[6 * step] + 42814 * blk[2 * step];
- const int tA = (blk[0 * step] - blk[4 * step] << 15) + (1 << shift - 1);
- const int tB = (blk[0 * step] + blk[4 * step] << 15) + (1 << shift - 1);
+ const int tA = (blk[0 * step] - blk[4 * step] << 15) + rnd;
+ const int tB = (blk[0 * step] + blk[4 * step] << 15) + rnd;
blk[0 * step] = ( t4 + t9 + tB) >> shift;
blk[1 * step] = ( t6 + t7 + t8 + tA) >> shift;
blk[2 * step] = ( t6 - t7 - t8 + tA) >> shift;
@@ -109,14 +109,15 @@ static void fic_idct_put(uint8_t *dst, int stride, int16_t *block)
int16_t *ptr;
ptr = block;
- for (i = 0; i < 8; i++) {
- fic_idct(ptr, 8, 13);
+ fic_idct(ptr++, 8, 13, (1 << 12) + (1 << 17));
+ for (i = 1; i < 8; i++) {
+ fic_idct(ptr, 8, 13, 1 << 12);
ptr++;
}
ptr = block;
for (i = 0; i < 8; i++) {
- fic_idct(ptr, 1, 20);
+ fic_idct(ptr, 1, 20, 0);
ptr += 8;
}
@@ -265,10 +266,8 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data,
int skip_cursor = 0;
uint8_t *sdata;
- if ((ret = ff_reget_buffer(avctx, ctx->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, ctx->frame)) < 0)
return ret;
- }
/* Header + at least one slice (4) */
if (avpkt->size < FIC_HEADER_SIZE + 4) {
@@ -281,8 +280,13 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_WARNING, "Invalid FIC Header.\n");
/* Is it a skip frame? */
- if (src[17])
+ if (src[17]) {
+ if (!ctx->final_frame) {
+ av_log(avctx, AV_LOG_WARNING, "Initial frame is skipped\n");
+ return AVERROR_INVALIDDATA;
+ }
goto skip;
+ }
nslices = src[13];
if (!nslices) {
@@ -302,7 +306,10 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
- if (tsize < 32) {
+ if (!tsize)
+ skip_cursor = 1;
+
+ if (!skip_cursor && tsize < 32) {
av_log(avctx, AV_LOG_WARNING,
"Cursor data too small. Skipping cursor.\n");
skip_cursor = 1;
@@ -311,14 +318,14 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data,
/* Cursor position. */
cur_x = AV_RL16(src + 33);
cur_y = AV_RL16(src + 35);
- if (cur_x > avctx->width || cur_y > avctx->height) {
+ if (!skip_cursor && (cur_x > avctx->width || cur_y > avctx->height)) {
av_log(avctx, AV_LOG_WARNING,
"Invalid cursor position: (%d,%d). Skipping cusor.\n",
cur_x, cur_y);
skip_cursor = 1;
}
- if (AV_RL16(src + 37) != 32 || AV_RL16(src + 39) != 32) {
+ if (!skip_cursor && (AV_RL16(src + 37) != 32 || AV_RL16(src + 39) != 32)) {
av_log(avctx, AV_LOG_WARNING,
"Invalid cursor size. Skipping cursor.\n");
skip_cursor = 1;
diff --git a/libavcodec/flac.c b/libavcodec/flac.c
index 3e51fdeb98..5ff004e01b 100644
--- a/libavcodec/flac.c
+++ b/libavcodec/flac.c
@@ -2,20 +2,20 @@
* FLAC common code
* Copyright (c) 2009 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -230,8 +230,7 @@ void ff_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s,
av_get_channel_layout_nb_channels(avctx->channel_layout) != avctx->channels)
ff_flac_set_channel_layout(avctx);
- s->samples = get_bits_long(&gb, 32) << 4;
- s->samples |= get_bits(&gb, 4);
+ s->samples = get_bits64(&gb, 36);
skip_bits_long(&gb, 64); /* md5 sum */
skip_bits_long(&gb, 64); /* md5 sum */
diff --git a/libavcodec/flac.h b/libavcodec/flac.h
index 3229682047..f1307c7f50 100644
--- a/libavcodec/flac.h
+++ b/libavcodec/flac.h
@@ -2,20 +2,20 @@
* FLAC (Free Lossless Audio Codec) decoder/demuxer common functions
* Copyright (c) 2008 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c
index 70b9a651e9..3723716441 100644
--- a/libavcodec/flac_parser.c
+++ b/libavcodec/flac_parser.c
@@ -2,20 +2,20 @@
* FLAC parser
* Copyright (c) 2010 Michael Chinen
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -87,6 +87,8 @@ typedef struct FLACParseContext {
int end_padded; /**< specifies if fifo_buf's end is padded */
uint8_t *wrap_buf; /**< general fifo read buffer when wrapped */
int wrap_buf_allocated_size; /**< actual allocated size of the buffer */
+ FLACFrameInfo last_fi; /**< last decoded frame header info */
+ int last_fi_valid; /**< set if last_fi is valid */
} FLACParseContext;
static int frame_header_is_valid(AVCodecContext *avctx, const uint8_t *buf,
@@ -180,7 +182,7 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset)
size++;
}
- *end_handle = av_mallocz(sizeof(FLACHeaderMarker));
+ *end_handle = av_mallocz(sizeof(**end_handle));
if (!*end_handle) {
av_log(fpc->avctx, AV_LOG_ERROR,
"couldn't allocate FLACHeaderMarker\n");
@@ -190,6 +192,13 @@ static int find_headers_search_validate(FLACParseContext *fpc, int offset)
(*end_handle)->offset = offset;
(*end_handle)->link_penalty = av_malloc(sizeof(int) *
FLAC_MAX_SEQUENTIAL_HEADERS);
+ if (!(*end_handle)->link_penalty) {
+ av_freep(end_handle);
+ av_log(fpc->avctx, AV_LOG_ERROR,
+ "couldn't allocate link_penalty\n");
+ return AVERROR(ENOMEM);
+ }
+
for (i = 0; i < FLAC_MAX_SEQUENTIAL_HEADERS; i++)
(*end_handle)->link_penalty[i] = FLAC_HEADER_NOT_PENALIZED_YET;
@@ -267,13 +276,12 @@ static int find_new_headers(FLACParseContext *fpc, int search_start)
return size;
}
-static int check_header_mismatch(FLACParseContext *fpc,
- FLACHeaderMarker *header,
- FLACHeaderMarker *child,
- int log_level_offset)
+static int check_header_fi_mismatch(FLACParseContext *fpc,
+ FLACFrameInfo *header_fi,
+ FLACFrameInfo *child_fi,
+ int log_level_offset)
{
- FLACFrameInfo *header_fi = &header->fi, *child_fi = &child->fi;
- int deduction = 0, deduction_expected = 0, i;
+ int deduction = 0;
if (child_fi->samplerate != header_fi->samplerate) {
deduction += FLAC_HEADER_CHANGED_PENALTY;
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
@@ -288,13 +296,25 @@ static int check_header_mismatch(FLACParseContext *fpc,
/* Changing blocking strategy not allowed per the spec */
deduction += FLAC_HEADER_BASE_SCORE;
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
- "blocking strategy change detected in adjacent frames\n");
+ "blocking strategy change detected in adjacent frames\n");
}
if (child_fi->channels != header_fi->channels) {
deduction += FLAC_HEADER_CHANGED_PENALTY;
av_log(fpc->avctx, AV_LOG_WARNING + log_level_offset,
- "number of channels change detected in adjacent frames\n");
+ "number of channels change detected in adjacent frames\n");
}
+ return deduction;
+}
+
+static int check_header_mismatch(FLACParseContext *fpc,
+ FLACHeaderMarker *header,
+ FLACHeaderMarker *child,
+ int log_level_offset)
+{
+ FLACFrameInfo *header_fi = &header->fi, *child_fi = &child->fi;
+ int deduction, deduction_expected = 0, i;
+ deduction = check_header_fi_mismatch(fpc, header_fi, child_fi,
+ log_level_offset);
/* Check sample and frame numbers. */
if ((child_fi->frame_or_sample_num - header_fi->frame_or_sample_num
!= header_fi->blocksize) &&
@@ -399,11 +419,18 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header)
FLACHeaderMarker *child;
int dist = 0;
int child_score;
-
+ int base_score = FLAC_HEADER_BASE_SCORE;
if (header->max_score != FLAC_HEADER_NOT_SCORED_YET)
return header->max_score;
- header->max_score = FLAC_HEADER_BASE_SCORE;
+ /* Modify the base score with changes from the last output header */
+ if (fpc->last_fi_valid) {
+ /* Silence the log since this will be repeated if selected */
+ base_score -= check_header_fi_mismatch(fpc, &fpc->last_fi, &header->fi,
+ AV_LOG_DEBUG);
+ }
+
+ header->max_score = base_score;
/* Check and compute the children's scores. */
child = header->next;
@@ -419,7 +446,7 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header)
if (FLAC_HEADER_BASE_SCORE + child_score > header->max_score) {
/* Keep the child because the frame scoring is dynamic. */
header->best_child = child;
- header->max_score = FLAC_HEADER_BASE_SCORE + child_score;
+ header->max_score = base_score + child_score;
}
child = child->next;
}
@@ -430,7 +457,7 @@ static int score_header(FLACParseContext *fpc, FLACHeaderMarker *header)
static void score_sequences(FLACParseContext *fpc)
{
FLACHeaderMarker *curr;
- int best_score = FLAC_HEADER_NOT_SCORED_YET;
+ int best_score = 0;//FLAC_HEADER_NOT_SCORED_YET;
/* First pass to clear all old scores. */
for (curr = fpc->headers; curr; curr = curr->next)
curr->max_score = FLAC_HEADER_NOT_SCORED_YET;
@@ -469,7 +496,18 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf,
&fpc->wrap_buf,
&fpc->wrap_buf_allocated_size);
+
+ if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){
+ if (header->fi.is_var_size)
+ fpc->pc->pts = header->fi.frame_or_sample_num;
+ else if (header->best_child)
+ fpc->pc->pts = header->fi.frame_or_sample_num * header->fi.blocksize;
+ }
+
fpc->best_header_valid = 0;
+ fpc->last_fi_valid = 1;
+ fpc->last_fi = header->fi;
+
/* Return the negative overread index so the client can compute pos.
This should be the amount overread to the beginning of the child */
if (child)
@@ -489,8 +527,16 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
FLACFrameInfo fi;
- if (frame_header_is_valid(avctx, buf, &fi))
+ if (frame_header_is_valid(avctx, buf, &fi)) {
s->duration = fi.blocksize;
+ if (!avctx->sample_rate)
+ avctx->sample_rate = fi.samplerate;
+ if (fpc->pc->flags & PARSER_FLAG_USE_CODEC_TS){
+ fpc->pc->pts = fi.frame_or_sample_num;
+ if (!fi.is_var_size)
+ fpc->pc->pts *= fi.blocksize;
+ }
+ }
*poutbuf = buf;
*poutbuf_size = buf_size;
return buf_size;
@@ -546,14 +592,18 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
av_freep(&fpc->best_header);
}
- /* Find and score new headers. */
- while ((buf && read_end < buf + buf_size &&
+ /* Find and score new headers. */
+ /* buf_size is to zero when padding, so check for this since we do */
+ /* not want to try to read more input once we have found the end. */
+ /* Note that as (non-modified) parameters, buf can be non-NULL, */
+ /* while buf_size is 0. */
+ while ((buf && buf_size && read_end < buf + buf_size &&
fpc->nb_headers_buffered < FLAC_MIN_HEADERS)
- || (!buf && !fpc->end_padded)) {
+ || ((!buf || !buf_size) && !fpc->end_padded)) {
int start_offset;
/* Pad the end once if EOF, to check the final region for headers. */
- if (!buf) {
+ if (!buf || !buf_size) {
fpc->end_padded = 1;
buf_size = MAX_FRAME_HEADER_SIZE;
read_end = read_start + MAX_FRAME_HEADER_SIZE;
@@ -575,15 +625,15 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
}
/* Fill the buffer. */
- if (av_fifo_realloc2(fpc->fifo_buf,
- (read_end - read_start) + av_fifo_size(fpc->fifo_buf)) < 0) {
+ if ( av_fifo_space(fpc->fifo_buf) < read_end - read_start
+ && av_fifo_realloc2(fpc->fifo_buf, (read_end - read_start) + 2*av_fifo_size(fpc->fifo_buf)) < 0) {
av_log(avctx, AV_LOG_ERROR,
- "couldn't reallocate buffer of size %td\n",
+ "couldn't reallocate buffer of size %"PTRDIFF_SPECIFIER"\n",
(read_end - read_start) + av_fifo_size(fpc->fifo_buf));
goto handle_error;
}
- if (buf) {
+ if (buf && buf_size) {
av_fifo_generic_write(fpc->fifo_buf, (void*) read_start,
read_end - read_start, NULL);
} else {
@@ -620,10 +670,11 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
/* restore the state pre-padding */
if (fpc->end_padded) {
+ int warp = fpc->fifo_buf->wptr - fpc->fifo_buf->buffer < MAX_FRAME_HEADER_SIZE;
/* HACK: drain the tail of the fifo */
fpc->fifo_buf->wptr -= MAX_FRAME_HEADER_SIZE;
fpc->fifo_buf->wndx -= MAX_FRAME_HEADER_SIZE;
- if (fpc->fifo_buf->wptr < 0) {
+ if (warp) {
fpc->fifo_buf->wptr += fpc->fifo_buf->end -
fpc->fifo_buf->buffer;
}
@@ -632,10 +683,12 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
}
}
- curr = fpc->headers;
- for (curr = fpc->headers; curr; curr = curr->next)
- if (!fpc->best_header || curr->max_score > fpc->best_header->max_score)
+ for (curr = fpc->headers; curr; curr = curr->next) {
+ if (curr->max_score > 0 &&
+ (!fpc->best_header || curr->max_score > fpc->best_header->max_score)) {
fpc->best_header = curr;
+ }
+ }
if (fpc->best_header) {
fpc->best_header_valid = 1;
@@ -660,7 +713,7 @@ static int flac_parse(AVCodecParserContext *s, AVCodecContext *avctx,
handle_error:
*poutbuf = NULL;
*poutbuf_size = 0;
- return read_end - buf;
+ return buf_size ? read_end - buf : 0;
}
static av_cold int flac_parse_init(AVCodecParserContext *c)
@@ -669,7 +722,12 @@ static av_cold int flac_parse_init(AVCodecParserContext *c)
fpc->pc = c;
/* There will generally be FLAC_MIN_HEADERS buffered in the fifo before
it drains. This is allocated early to avoid slow reallocation. */
- fpc->fifo_buf = av_fifo_alloc(FLAC_AVG_FRAME_SIZE * (FLAC_MIN_HEADERS + 3));
+ fpc->fifo_buf = av_fifo_alloc_array(FLAC_MIN_HEADERS + 3, FLAC_AVG_FRAME_SIZE);
+ if (!fpc->fifo_buf) {
+ av_log(fpc->avctx, AV_LOG_ERROR,
+ "couldn't allocate fifo_buf\n");
+ return AVERROR(ENOMEM);
+ }
return 0;
}
@@ -684,8 +742,8 @@ static void flac_parse_close(AVCodecParserContext *c)
av_free(curr);
curr = temp;
}
- av_fifo_free(fpc->fifo_buf);
- av_free(fpc->wrap_buf);
+ av_fifo_freep(&fpc->fifo_buf);
+ av_freep(&fpc->wrap_buf);
}
AVCodecParser ff_flac_parser = {
diff --git a/libavcodec/flacdata.c b/libavcodec/flacdata.c
index 820c3aa492..1954f32d32 100644
--- a/libavcodec/flacdata.c
+++ b/libavcodec/flacdata.c
@@ -2,20 +2,20 @@
* FLAC data
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@ const int ff_flac_sample_rate_table[16] =
8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
0, 0, 0, 0 };
-const int16_t ff_flac_blocksize_table[16] = {
+const int32_t ff_flac_blocksize_table[16] = {
0, 192, 576<<0, 576<<1, 576<<2, 576<<3, 0, 0,
256<<0, 256<<1, 256<<2, 256<<3, 256<<4, 256<<5, 256<<6, 256<<7
};
diff --git a/libavcodec/flacdata.h b/libavcodec/flacdata.h
index f56637773c..e2c1e5d7f2 100644
--- a/libavcodec/flacdata.h
+++ b/libavcodec/flacdata.h
@@ -2,20 +2,20 @@
* FLAC data header
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,6 @@
extern const int ff_flac_sample_rate_table[16];
-extern const int16_t ff_flac_blocksize_table[16];
+extern const int32_t ff_flac_blocksize_table[16];
#endif /* AVCODEC_FLACDATA_H */
diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c
index 6cce6923f3..30fe41618d 100644
--- a/libavcodec/flacdec.c
+++ b/libavcodec/flacdec.c
@@ -2,20 +2,20 @@
* FLAC (Free Lossless Audio Codec) decoder
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,9 @@
#include <limits.h>
+#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "internal.h"
#include "get_bits.h"
@@ -41,9 +44,13 @@
#include "flac.h"
#include "flacdata.h"
#include "flacdsp.h"
+#include "thread.h"
+#include "unary.h"
+
typedef struct FLACContext {
- FLACSTREAMINFO
+ AVClass *class;
+ struct FLACStreaminfo flac_stream_info;
AVCodecContext *avctx; ///< parent AVCodecContext
GetBitContext gb; ///< GetBitContext initialized to start at the current frame
@@ -56,6 +63,7 @@ typedef struct FLACContext {
int32_t *decoded[FLAC_MAX_CHANNELS]; ///< decoded samples
uint8_t *decoded_buffer;
unsigned int decoded_buffer_size;
+ int buggy_lpc; ///< use workaround for old lavc encoded files
FLACDSPContext dsp;
} FLACContext;
@@ -65,7 +73,7 @@ static int allocate_buffers(FLACContext *s);
static void flac_set_bps(FLACContext *s)
{
enum AVSampleFormat req = s->avctx->request_sample_fmt;
- int need32 = s->bps > 16;
+ int need32 = s->flac_stream_info.bps > 16;
int want32 = av_get_bytes_per_sample(req) > 2;
int planar = av_sample_fmt_is_planar(req);
@@ -74,13 +82,13 @@ static void flac_set_bps(FLACContext *s)
s->avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
else
s->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
- s->sample_shift = 32 - s->bps;
+ s->sample_shift = 32 - s->flac_stream_info.bps;
} else {
if (planar)
s->avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
else
s->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
- s->sample_shift = 16 - s->bps;
+ s->sample_shift = 16 - s->flac_stream_info.bps;
}
}
@@ -101,12 +109,13 @@ static av_cold int flac_decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
/* initialize based on the demuxer-supplied streamdata header */
- ff_flac_parse_streaminfo(avctx, (FLACStreaminfo *)s, streaminfo);
+ ff_flac_parse_streaminfo(avctx, &s->flac_stream_info, streaminfo);
ret = allocate_buffers(s);
if (ret < 0)
return ret;
flac_set_bps(s);
- ff_flacdsp_init(&s->dsp, avctx->sample_fmt, s->bps);
+ ff_flacdsp_init(&s->dsp, avctx->sample_fmt,
+ s->flac_stream_info.channels, s->flac_stream_info.bps);
s->got_streaminfo = 1;
return 0;
@@ -124,8 +133,12 @@ static void dump_headers(AVCodecContext *avctx, FLACStreaminfo *s)
static int allocate_buffers(FLACContext *s)
{
int buf_size;
+ int ret;
+
+ av_assert0(s->flac_stream_info.max_blocksize);
- buf_size = av_samples_get_buffer_size(NULL, s->channels, s->max_blocksize,
+ buf_size = av_samples_get_buffer_size(NULL, s->flac_stream_info.channels,
+ s->flac_stream_info.max_blocksize,
AV_SAMPLE_FMT_S32P, 0);
if (buf_size < 0)
return buf_size;
@@ -134,9 +147,12 @@ static int allocate_buffers(FLACContext *s)
if (!s->decoded_buffer)
return AVERROR(ENOMEM);
- return av_samples_fill_arrays((uint8_t **)s->decoded, NULL,
- s->decoded_buffer, s->channels,
- s->max_blocksize, AV_SAMPLE_FMT_S32P, 0);
+ ret = av_samples_fill_arrays((uint8_t **)s->decoded, NULL,
+ s->decoded_buffer,
+ s->flac_stream_info.channels,
+ s->flac_stream_info.max_blocksize,
+ AV_SAMPLE_FMT_S32P, 0);
+ return ret < 0 ? ret : 0;
}
/**
@@ -159,12 +175,13 @@ static int parse_streaminfo(FLACContext *s, const uint8_t *buf, int buf_size)
metadata_size != FLAC_STREAMINFO_SIZE) {
return AVERROR_INVALIDDATA;
}
- ff_flac_parse_streaminfo(s->avctx, (FLACStreaminfo *)s, &buf[8]);
+ ff_flac_parse_streaminfo(s->avctx, &s->flac_stream_info, &buf[8]);
ret = allocate_buffers(s);
if (ret < 0)
return ret;
flac_set_bps(s);
- ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps);
+ ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt,
+ s->flac_stream_info.channels, s->flac_stream_info.bps);
s->got_streaminfo = 1;
return 0;
@@ -213,6 +230,12 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order)
rice_order = get_bits(&s->gb, 4);
samples= s->blocksize >> rice_order;
+ if (samples << rice_order != s->blocksize) {
+ av_log(s->avctx, AV_LOG_ERROR, "invalid rice order: %i blocksize %i\n",
+ rice_order, s->blocksize);
+ return AVERROR_INVALIDDATA;
+ }
+
if (pred_order > samples) {
av_log(s->avctx, AV_LOG_ERROR, "invalid predictor order: %i > %i\n",
pred_order, samples);
@@ -245,7 +268,8 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
int pred_order, int bps)
{
const int blocksize = s->blocksize;
- int a, b, c, d, i, ret;
+ int av_uninit(a), av_uninit(b), av_uninit(c), av_uninit(d), i;
+ int ret;
/* warm up samples */
for (i = 0; i < pred_order; i++) {
@@ -291,6 +315,33 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded,
return 0;
}
+static void lpc_analyze_remodulate(int32_t *decoded, const int coeffs[32],
+ int order, int qlevel, int len, int bps)
+{
+ int i, j;
+ int ebps = 1 << (bps-1);
+ unsigned sigma = 0;
+
+ for (i = order; i < len; i++)
+ sigma |= decoded[i] + ebps;
+
+ if (sigma < 2*ebps)
+ return;
+
+ for (i = len - 1; i >= order; i--) {
+ int64_t p = 0;
+ for (j = 0; j < order; j++)
+ p += coeffs[j] * (int64_t)decoded[i-order+j];
+ decoded[i] -= p >> qlevel;
+ }
+ for (i = order; i < len; i++, decoded++) {
+ int32_t p = 0;
+ for (j = 0; j < order; j++)
+ p += coeffs[j] * (uint32_t)decoded[j];
+ decoded[j] += p >> qlevel;
+ }
+}
+
static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
int bps)
{
@@ -322,7 +373,15 @@ static int decode_subframe_lpc(FLACContext *s, int32_t *decoded, int pred_order,
if ((ret = decode_residuals(s, decoded, pred_order)) < 0)
return ret;
- s->dsp.lpc(decoded, coeffs, pred_order, qlevel, s->blocksize);
+ if ( ( s->buggy_lpc && s->flac_stream_info.bps <= 16)
+ || ( !s->buggy_lpc && bps <= 16
+ && bps + coeff_prec + av_log2(pred_order) <= 32)) {
+ s->dsp.lpc16(decoded, coeffs, pred_order, qlevel, s->blocksize);
+ } else {
+ s->dsp.lpc32(decoded, coeffs, pred_order, qlevel, s->blocksize);
+ if (s->flac_stream_info.bps <= 16)
+ lpc_analyze_remodulate(decoded, coeffs, pred_order, qlevel, s->blocksize, bps);
+ }
return 0;
}
@@ -331,7 +390,7 @@ static inline int decode_subframe(FLACContext *s, int channel)
{
int32_t *decoded = s->decoded[channel];
int type, wasted = 0;
- int bps = s->bps;
+ int bps = s->flac_stream_info.bps;
int i, tmp, ret;
if (channel == 0) {
@@ -350,8 +409,7 @@ static inline int decode_subframe(FLACContext *s, int channel)
if (get_bits1(&s->gb)) {
int left = get_bits_left(&s->gb);
- wasted = 1;
- if ( left < 0 ||
+ if ( left <= 0 ||
(left < bps && !show_bits_long(&s->gb, left)) ||
!show_bits_long(&s->gb, bps)) {
av_log(s->avctx, AV_LOG_ERROR,
@@ -359,8 +417,7 @@ static inline int decode_subframe(FLACContext *s, int channel)
bps, left);
return AVERROR_INVALIDDATA;
}
- while (!get_bits1(&s->gb))
- wasted++;
+ wasted = 1 + get_unary(&s->gb, 1, get_bits_left(&s->gb));
bps -= wasted;
}
if (bps > 32) {
@@ -407,66 +464,69 @@ static int decode_frame(FLACContext *s)
return ret;
}
- if (s->channels && fi.channels != s->channels && s->got_streaminfo) {
- s->channels = s->avctx->channels = fi.channels;
+ if ( s->flac_stream_info.channels
+ && fi.channels != s->flac_stream_info.channels
+ && s->got_streaminfo) {
+ s->flac_stream_info.channels = s->avctx->channels = fi.channels;
ff_flac_set_channel_layout(s->avctx);
ret = allocate_buffers(s);
if (ret < 0)
return ret;
}
- s->channels = s->avctx->channels = fi.channels;
+ s->flac_stream_info.channels = s->avctx->channels = fi.channels;
if (!s->avctx->channel_layout)
ff_flac_set_channel_layout(s->avctx);
s->ch_mode = fi.ch_mode;
- if (!s->bps && !fi.bps) {
+ if (!s->flac_stream_info.bps && !fi.bps) {
av_log(s->avctx, AV_LOG_ERROR, "bps not found in STREAMINFO or frame header\n");
return AVERROR_INVALIDDATA;
}
if (!fi.bps) {
- fi.bps = s->bps;
- } else if (s->bps && fi.bps != s->bps) {
+ fi.bps = s->flac_stream_info.bps;
+ } else if (s->flac_stream_info.bps && fi.bps != s->flac_stream_info.bps) {
av_log(s->avctx, AV_LOG_ERROR, "switching bps mid-stream is not "
"supported\n");
return AVERROR_INVALIDDATA;
}
- if (!s->bps) {
- s->bps = s->avctx->bits_per_raw_sample = fi.bps;
+ if (!s->flac_stream_info.bps) {
+ s->flac_stream_info.bps = s->avctx->bits_per_raw_sample = fi.bps;
flac_set_bps(s);
}
- if (!s->max_blocksize)
- s->max_blocksize = FLAC_MAX_BLOCKSIZE;
- if (fi.blocksize > s->max_blocksize) {
+ if (!s->flac_stream_info.max_blocksize)
+ s->flac_stream_info.max_blocksize = FLAC_MAX_BLOCKSIZE;
+ if (fi.blocksize > s->flac_stream_info.max_blocksize) {
av_log(s->avctx, AV_LOG_ERROR, "blocksize %d > %d\n", fi.blocksize,
- s->max_blocksize);
+ s->flac_stream_info.max_blocksize);
return AVERROR_INVALIDDATA;
}
s->blocksize = fi.blocksize;
- if (!s->samplerate && !fi.samplerate) {
+ if (!s->flac_stream_info.samplerate && !fi.samplerate) {
av_log(s->avctx, AV_LOG_ERROR, "sample rate not found in STREAMINFO"
" or frame header\n");
return AVERROR_INVALIDDATA;
}
if (fi.samplerate == 0)
- fi.samplerate = s->samplerate;
- s->samplerate = s->avctx->sample_rate = fi.samplerate;
+ fi.samplerate = s->flac_stream_info.samplerate;
+ s->flac_stream_info.samplerate = s->avctx->sample_rate = fi.samplerate;
if (!s->got_streaminfo) {
ret = allocate_buffers(s);
if (ret < 0)
return ret;
- ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps);
s->got_streaminfo = 1;
- dump_headers(s->avctx, (FLACStreaminfo *)s);
+ dump_headers(s->avctx, &s->flac_stream_info);
}
+ ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt,
+ s->flac_stream_info.channels, s->flac_stream_info.bps);
-// dump_headers(s->avctx, (FLACStreaminfo *)s);
+// dump_headers(s->avctx, &s->flac_stream_info);
/* subframes */
- for (i = 0; i < s->channels; i++) {
+ for (i = 0; i < s->flac_stream_info.channels; i++) {
if ((ret = decode_subframe(s, i)) < 0)
return ret;
}
@@ -483,6 +543,7 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
AVFrame *frame = data;
+ ThreadFrame tframe = { .f = data };
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
FLACContext *s = avctx->priv_data;
@@ -491,12 +552,22 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
*got_frame_ptr = 0;
- if (s->max_framesize == 0) {
- s->max_framesize =
- ff_flac_get_max_frame_size(s->max_blocksize ? s->max_blocksize : FLAC_MAX_BLOCKSIZE,
+ if (s->flac_stream_info.max_framesize == 0) {
+ s->flac_stream_info.max_framesize =
+ ff_flac_get_max_frame_size(s->flac_stream_info.max_blocksize ? s->flac_stream_info.max_blocksize : FLAC_MAX_BLOCKSIZE,
FLAC_MAX_CHANNELS, 32);
}
+ if (buf_size > 5 && !memcmp(buf, "\177FLAC", 5)) {
+ av_log(s->avctx, AV_LOG_DEBUG, "skipping flac header packet 1\n");
+ return buf_size;
+ }
+
+ if (buf_size > 0 && (*buf & 0x7F) == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
+ av_log(s->avctx, AV_LOG_DEBUG, "skipping vorbis comment\n");
+ return buf_size;
+ }
+
/* check that there is at least the smallest decodable amount of data.
this amount corresponds to the smallest valid FLAC frame possible.
FF F8 69 02 00 00 9A 00 00 34 46 */
@@ -513,21 +584,29 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
}
/* decode frame */
- init_get_bits(&s->gb, buf, buf_size*8);
+ if ((ret = init_get_bits8(&s->gb, buf, buf_size)) < 0)
+ return ret;
if ((ret = decode_frame(s)) < 0) {
av_log(s->avctx, AV_LOG_ERROR, "decode_frame() failed\n");
return ret;
}
- bytes_read = (get_bits_count(&s->gb)+7)/8;
+ bytes_read = get_bits_count(&s->gb)/8;
+
+ if ((s->avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_COMPLIANT)) &&
+ av_crc(av_crc_get_table(AV_CRC_16_ANSI),
+ 0, buf, bytes_read)) {
+ av_log(s->avctx, AV_LOG_ERROR, "CRC error at PTS %"PRId64"\n", avpkt->pts);
+ if (s->avctx->err_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
+ }
/* get output buffer */
frame->nb_samples = s->blocksize;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0)
return ret;
- }
- s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded, s->channels,
+ s->dsp.decorrelate[s->ch_mode](frame->data, s->decoded,
+ s->flac_stream_info.channels,
s->blocksize, s->sample_shift);
if (bytes_read > buf_size) {
@@ -544,6 +623,17 @@ static int flac_decode_frame(AVCodecContext *avctx, void *data,
return bytes_read;
}
+static int init_thread_copy(AVCodecContext *avctx)
+{
+ FLACContext *s = avctx->priv_data;
+ s->decoded_buffer = NULL;
+ s->decoded_buffer_size = 0;
+ s->avctx = avctx;
+ if (s->flac_stream_info.max_blocksize)
+ return allocate_buffers(s);
+ return 0;
+}
+
static av_cold int flac_decode_close(AVCodecContext *avctx)
{
FLACContext *s = avctx->priv_data;
@@ -553,6 +643,18 @@ static av_cold int flac_decode_close(AVCodecContext *avctx)
return 0;
}
+static const AVOption options[] = {
+{ "use_buggy_lpc", "emulate old buggy lavc behavior", offsetof(FLACContext, buggy_lpc), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM },
+{ NULL },
+};
+
+static const AVClass flac_decoder_class = {
+ "FLAC decoder",
+ av_default_item_name,
+ options,
+ LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_flac_decoder = {
.name = "flac",
.long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"),
@@ -562,10 +664,12 @@ AVCodec ff_flac_decoder = {
.init = flac_decode_init,
.close = flac_decode_close,
.decode = flac_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_S32,
AV_SAMPLE_FMT_S32P,
- -1 },
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &flac_decoder_class,
};
diff --git a/libavcodec/flacdsp.c b/libavcodec/flacdsp.c
index b916869321..30b66484e8 100644
--- a/libavcodec/flacdsp.c
+++ b/libavcodec/flacdsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -85,16 +85,13 @@ static void flac_lpc_32_c(int32_t *decoded, const int coeffs[32],
}
-av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt,
+av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels,
int bps)
{
- if (bps > 16) {
- c->lpc = flac_lpc_32_c;
- c->lpc_encode = flac_lpc_encode_c_32;
- } else {
- c->lpc = flac_lpc_16_c;
- c->lpc_encode = flac_lpc_encode_c_16;
- }
+ c->lpc16 = flac_lpc_16_c;
+ c->lpc32 = flac_lpc_32_c;
+ c->lpc16_encode = flac_lpc_encode_c_16;
+ c->lpc32_encode = flac_lpc_encode_c_32;
switch (fmt) {
case AV_SAMPLE_FMT_S32:
@@ -127,5 +124,7 @@ av_cold void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt,
}
if (ARCH_ARM)
- ff_flacdsp_init_arm(c, fmt, bps);
+ ff_flacdsp_init_arm(c, fmt, channels, bps);
+ if (ARCH_X86)
+ ff_flacdsp_init_x86(c, fmt, channels, bps);
}
diff --git a/libavcodec/flacdsp.h b/libavcodec/flacdsp.h
index 33184b589d..f5cbd94724 100644
--- a/libavcodec/flacdsp.h
+++ b/libavcodec/flacdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,13 +25,18 @@
typedef struct FLACDSPContext {
void (*decorrelate[4])(uint8_t **out, int32_t **in, int channels,
int len, int shift);
- void (*lpc)(int32_t *samples, const int coeffs[32], int order,
- int qlevel, int len);
- void (*lpc_encode)(int32_t *res, const int32_t *smp, int len, int order,
- const int32_t *coefs, int shift);
+ void (*lpc16)(int32_t *samples, const int coeffs[32], int order,
+ int qlevel, int len);
+ void (*lpc32)(int32_t *samples, const int coeffs[32], int order,
+ int qlevel, int len);
+ void (*lpc16_encode)(int32_t *res, const int32_t *smp, int len, int order,
+ const int32_t coefs[32], int shift);
+ void (*lpc32_encode)(int32_t *res, const int32_t *smp, int len, int order,
+ const int32_t coefs[32], int shift);
} FLACDSPContext;
-void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int bps);
-void ff_flacdsp_init_arm(FLACDSPContext *c, enum AVSampleFormat fmt, int bps);
+void ff_flacdsp_init(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps);
+void ff_flacdsp_init_arm(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps);
+void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, int bps);
#endif /* AVCODEC_FLACDSP_H */
diff --git a/libavcodec/flacdsp_lpc_template.c b/libavcodec/flacdsp_lpc_template.c
index 269e64b3a8..5d532e0673 100644
--- a/libavcodec/flacdsp_lpc_template.c
+++ b/libavcodec/flacdsp_lpc_template.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -139,3 +139,21 @@ static void FUNC(flac_lpc_encode_c)(int32_t *res, const int32_t *smp, int len,
}
#endif
}
+
+/* Comment for clarity/de-obfuscation.
+ *
+ * for (int i = order; i < len; i++) {
+ * int32_t p = 0;
+ * for (int j = 0; j < order; j++) {
+ * int c = coefs[j];
+ * int s = smp[(i-1)-j];
+ * p += c*s;
+ * }
+ * res[i] = smp[i] - (p >> shift);
+ * }
+ *
+ * The CONFIG_SMALL code above simplifies to this, in the case of SAMPLE_SIZE
+ * not being equal to 32 (at the present time that means for 16-bit audio). The
+ * code above does 2 samples per iteration. Commit bfdd5bc (made all the way
+ * back in 2007) says that way is faster.
+ */
diff --git a/libavcodec/flacdsp_template.c b/libavcodec/flacdsp_template.c
index 0affe22ddb..62c0a15ff6 100644
--- a/libavcodec/flacdsp_template.c
+++ b/libavcodec/flacdsp_template.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/flacenc.c b/libavcodec/flacenc.c
index 804333d5e9..935d55f32d 100644
--- a/libavcodec/flacenc.c
+++ b/libavcodec/flacenc.c
@@ -2,30 +2,31 @@
* FLAC audio encoder
* Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/intmath.h"
#include "libavutil/md5.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "bswapdsp.h"
-#include "get_bits.h"
+#include "put_bits.h"
#include "golomb.h"
#include "internal.h"
#include "lpc.h"
@@ -61,13 +62,14 @@ typedef struct CompressionOptions {
int min_partition_order;
int max_partition_order;
int ch_mode;
+ int exact_rice_parameters;
+ int multi_dim_quant;
} CompressionOptions;
typedef struct RiceContext {
enum CodingMode coding_mode;
int porder;
int params[MAX_PARTITIONS];
- uint32_t udata[FLAC_MAX_BLOCKSIZE];
} RiceContext;
typedef struct FlacSubframe {
@@ -78,9 +80,13 @@ typedef struct FlacSubframe {
int order;
int32_t coefs[MAX_LPC_ORDER];
int shift;
+
RiceContext rc;
+ uint32_t rc_udata[FLAC_MAX_BLOCKSIZE];
+ uint64_t rc_sums[32][MAX_PARTITIONS];
+
int32_t samples[FLAC_MAX_BLOCKSIZE];
- int32_t residual[FLAC_MAX_BLOCKSIZE+1];
+ int32_t residual[FLAC_MAX_BLOCKSIZE+11];
} FlacSubframe;
typedef struct FlacFrame {
@@ -157,7 +163,7 @@ static int select_blocksize(int samplerate, int block_time_ms)
int target;
int blocksize;
- assert(samplerate > 0);
+ av_assert0(samplerate > 0);
blocksize = ff_flac_blocksize_table[1];
target = (samplerate * block_time_ms) / 1000;
for (i = 0; i < 16; i++) {
@@ -251,8 +257,11 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
break;
}
- if (channels < 1 || channels > FLAC_MAX_CHANNELS)
- return -1;
+ if (channels < 1 || channels > FLAC_MAX_CHANNELS) {
+ av_log(avctx, AV_LOG_ERROR, "%d channels not supported (max %d)\n",
+ channels, FLAC_MAX_CHANNELS);
+ return AVERROR(EINVAL);
+ }
s->channels = channels;
/* find samplerate in table */
@@ -278,7 +287,8 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
s->sr_code[0] = 13;
s->sr_code[1] = freq;
} else {
- return -1;
+ av_log(avctx, AV_LOG_ERROR, "%d Hz not supported\n", freq);
+ return AVERROR(EINVAL);
}
s->samplerate = freq;
}
@@ -293,7 +303,7 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
if (level > 12) {
av_log(avctx, AV_LOG_ERROR, "invalid compression level: %d\n",
s->options.compression_level);
- return -1;
+ return AVERROR(EINVAL);
}
s->options.block_time_ms = ((int[]){ 27, 27, 27,105,105,105,105,105,105,105,105,105,105})[level];
@@ -332,13 +342,13 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
if (avctx->min_prediction_order > MAX_FIXED_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
avctx->min_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
} else if (avctx->min_prediction_order < MIN_LPC_ORDER ||
avctx->min_prediction_order > MAX_LPC_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid min prediction order: %d\n",
avctx->min_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
s->options.min_prediction_order = avctx->min_prediction_order;
}
@@ -349,20 +359,20 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
if (avctx->max_prediction_order > MAX_FIXED_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n",
avctx->max_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
} else if (avctx->max_prediction_order < MIN_LPC_ORDER ||
avctx->max_prediction_order > MAX_LPC_ORDER) {
av_log(avctx, AV_LOG_ERROR, "invalid max prediction order: %d\n",
avctx->max_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
s->options.max_prediction_order = avctx->max_prediction_order;
}
if (s->options.max_prediction_order < s->options.min_prediction_order) {
av_log(avctx, AV_LOG_ERROR, "invalid prediction orders: min=%d max=%d\n",
s->options.min_prediction_order, s->options.max_prediction_order);
- return -1;
+ return AVERROR(EINVAL);
}
if (avctx->frame_size > 0) {
@@ -370,7 +380,7 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
avctx->frame_size > FLAC_MAX_BLOCKSIZE) {
av_log(avctx, AV_LOG_ERROR, "invalid block size: %d\n",
avctx->frame_size);
- return -1;
+ return AVERROR(EINVAL);
}
} else {
s->avctx->frame_size = select_blocksize(s->samplerate, s->options.block_time_ms);
@@ -398,11 +408,33 @@ static av_cold int flac_encode_init(AVCodecContext *avctx)
s->frame_count = 0;
s->min_framesize = s->max_framesize;
+ if (channels == 3 &&
+ avctx->channel_layout != (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) ||
+ channels == 4 &&
+ avctx->channel_layout != AV_CH_LAYOUT_2_2 &&
+ avctx->channel_layout != AV_CH_LAYOUT_QUAD ||
+ channels == 5 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0_BACK ||
+ channels == 6 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1_BACK) {
+ if (avctx->channel_layout) {
+ av_log(avctx, AV_LOG_ERROR, "Channel layout not supported by Flac, "
+ "output stream will have incorrect "
+ "channel layout.\n");
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The encoder "
+ "will use Flac channel layout for "
+ "%d channels.\n", channels);
+ }
+ }
+
ret = ff_lpc_init(&s->lpc_ctx, avctx->frame_size,
s->options.max_prediction_order, FF_LPC_TYPE_LEVINSON);
ff_bswapdsp_init(&s->bdsp);
- ff_flacdsp_init(&s->flac_dsp, avctx->sample_fmt,
+ ff_flacdsp_init(&s->flac_dsp, avctx->sample_fmt, channels,
avctx->bits_per_raw_sample);
dprint_compression_options(s);
@@ -478,7 +510,7 @@ static void copy_samples(FlacEncodeContext *s, const void *samples)
}
-static uint64_t rice_count_exact(int32_t *res, int n, int k)
+static uint64_t rice_count_exact(const int32_t *res, int n, int k)
{
int i;
uint64_t count = 0;
@@ -502,6 +534,9 @@ static uint64_t subframe_count_exact(FlacEncodeContext *s, FlacSubframe *sub,
/* subframe header */
count += 8;
+ if (sub->wasted)
+ count += sub->wasted;
+
/* subframe */
if (sub->type == FLAC_SUBFRAME_CONSTANT) {
count += sub->obits;
@@ -556,24 +591,44 @@ static int find_optimal_param(uint64_t sum, int n, int max_param)
return FFMIN(k, max_param);
}
+static int find_optimal_param_exact(uint64_t sums[32][MAX_PARTITIONS], int i, int max_param)
+{
+ int bestk = 0;
+ int64_t bestbits = INT64_MAX;
+ int k;
+
+ for (k = 0; k <= max_param; k++) {
+ int64_t bits = sums[k][i];
+ if (bits < bestbits) {
+ bestbits = bits;
+ bestk = k;
+ }
+ }
+
+ return bestk;
+}
static uint64_t calc_optimal_rice_params(RiceContext *rc, int porder,
- uint64_t *sums, int n, int pred_order)
+ uint64_t sums[32][MAX_PARTITIONS],
+ int n, int pred_order, int max_param, int exact)
{
int i;
- int k, cnt, part, max_param;
+ int k, cnt, part;
uint64_t all_bits;
- max_param = (1 << rc->coding_mode) - 2;
-
part = (1 << porder);
all_bits = 4 * part;
cnt = (n >> porder) - pred_order;
for (i = 0; i < part; i++) {
- k = find_optimal_param(sums[i], cnt, max_param);
+ if (exact) {
+ k = find_optimal_param_exact(sums, i, max_param);
+ all_bits += sums[k][i];
+ } else {
+ k = find_optimal_param(sums[0][i], cnt, max_param);
+ all_bits += rice_encode_count(sums[0][i], cnt, k);
+ }
rc->params[i] = k;
- all_bits += rice_encode_count(sums[i], cnt, k);
cnt = n >> porder;
}
@@ -583,61 +638,80 @@ static uint64_t calc_optimal_rice_params(RiceContext *rc, int porder,
}
-static void calc_sums(int pmin, int pmax, uint32_t *data, int n, int pred_order,
- uint64_t sums[][MAX_PARTITIONS])
+static void calc_sum_top(int pmax, int kmax, const uint32_t *data, int n, int pred_order,
+ uint64_t sums[32][MAX_PARTITIONS])
{
- int i, j;
+ int i, k;
int parts;
- uint32_t *res, *res_end;
+ const uint32_t *res, *res_end;
/* sums for highest level */
parts = (1 << pmax);
- res = &data[pred_order];
- res_end = &data[n >> pmax];
- for (i = 0; i < parts; i++) {
- uint64_t sum = 0;
- while (res < res_end)
- sum += *(res++);
- sums[pmax][i] = sum;
- res_end += n >> pmax;
- }
- /* sums for lower levels */
- for (i = pmax - 1; i >= pmin; i--) {
- parts = (1 << i);
- for (j = 0; j < parts; j++)
- sums[i][j] = sums[i+1][2*j] + sums[i+1][2*j+1];
+
+ for (k = 0; k <= kmax; k++) {
+ res = &data[pred_order];
+ res_end = &data[n >> pmax];
+ for (i = 0; i < parts; i++) {
+ if (kmax) {
+ uint64_t sum = (1LL + k) * (res_end - res);
+ while (res < res_end)
+ sum += *(res++) >> k;
+ sums[k][i] = sum;
+ } else {
+ uint64_t sum = 0;
+ while (res < res_end)
+ sum += *(res++);
+ sums[k][i] = sum;
+ }
+ res_end += n >> pmax;
+ }
}
}
+static void calc_sum_next(int level, uint64_t sums[32][MAX_PARTITIONS], int kmax)
+{
+ int i, k;
+ int parts = (1 << level);
+ for (i = 0; i < parts; i++) {
+ for (k=0; k<=kmax; k++)
+ sums[k][i] = sums[k][2*i] + sums[k][2*i+1];
+ }
+}
-static uint64_t calc_rice_params(RiceContext *rc, int pmin, int pmax,
- int32_t *data, int n, int pred_order)
+static uint64_t calc_rice_params(RiceContext *rc,
+ uint32_t udata[FLAC_MAX_BLOCKSIZE],
+ uint64_t sums[32][MAX_PARTITIONS],
+ int pmin, int pmax,
+ const int32_t *data, int n, int pred_order, int exact)
{
int i;
uint64_t bits[MAX_PARTITION_ORDER+1];
int opt_porder;
RiceContext tmp_rc;
- uint64_t sums[MAX_PARTITION_ORDER + 1][MAX_PARTITIONS] = { { 0 } };
+ int kmax = (1 << rc->coding_mode) - 2;
- assert(pmin >= 0 && pmin <= MAX_PARTITION_ORDER);
- assert(pmax >= 0 && pmax <= MAX_PARTITION_ORDER);
- assert(pmin <= pmax);
+ av_assert1(pmin >= 0 && pmin <= MAX_PARTITION_ORDER);
+ av_assert1(pmax >= 0 && pmax <= MAX_PARTITION_ORDER);
+ av_assert1(pmin <= pmax);
tmp_rc.coding_mode = rc->coding_mode;
for (i = 0; i < n; i++)
- rc->udata[i] = (2 * data[i]) ^ (data[i] >> 31);
+ udata[i] = (2 * data[i]) ^ (data[i] >> 31);
- calc_sums(pmin, pmax, rc->udata, n, pred_order, sums);
+ calc_sum_top(pmax, exact ? kmax : 0, udata, n, pred_order, sums);
opt_porder = pmin;
bits[pmin] = UINT32_MAX;
- for (i = pmin; i <= pmax; i++) {
- bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums[i], n, pred_order);
- if (bits[i] <= bits[opt_porder]) {
+ for (i = pmax; ; ) {
+ bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums, n, pred_order, kmax, exact);
+ if (bits[i] < bits[opt_porder]) {
opt_porder = i;
*rc = tmp_rc;
}
+ if (i == pmin)
+ break;
+ calc_sum_next(--i, sums, exact ? kmax : 0);
}
return bits[opt_porder];
@@ -664,8 +738,8 @@ static uint64_t find_subframe_rice_params(FlacEncodeContext *s,
uint64_t bits = 8 + pred_order * sub->obits + 2 + sub->rc.coding_mode;
if (sub->type == FLAC_SUBFRAME_LPC)
bits += 4 + 5 + pred_order * s->options.lpc_coeff_precision;
- bits += calc_rice_params(&sub->rc, pmin, pmax, sub->residual,
- s->frame.blocksize, pred_order);
+ bits += calc_rice_params(&sub->rc, sub->rc_udata, sub->rc_sums, pmin, pmax, sub->residual,
+ s->frame.blocksize, pred_order, s->options.exact_rice_parameters);
return bits;
}
@@ -804,8 +878,13 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
order = av_clip(order, min_order - 1, max_order - 1);
if (order == last_order)
continue;
- s->flac_dsp.lpc_encode(res, smp, n, order+1, coefs[order],
- shift[order]);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(order) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, order+1, coefs[order],
+ shift[order]);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, order+1, coefs[order],
+ shift[order]);
+ }
bits[i] = find_subframe_rice_params(s, sub, order+1);
if (bits[i] < bits[opt_index]) {
opt_index = i;
@@ -819,7 +898,11 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
opt_order = 0;
bits[0] = UINT32_MAX;
for (i = min_order-1; i < max_order; i++) {
- s->flac_dsp.lpc_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(i) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ }
bits[i] = find_subframe_rice_params(s, sub, i+1);
if (bits[i] < bits[opt_order])
opt_order = i;
@@ -837,7 +920,11 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
for (i = last-step; i <= last+step; i += step) {
if (i < min_order-1 || i >= max_order || bits[i] < UINT32_MAX)
continue;
- s->flac_dsp.lpc_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(i) <= 32) {
+ s->flac_dsp.lpc32_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ } else {
+ s->flac_dsp.lpc16_encode(res, smp, n, i+1, coefs[i], shift[i]);
+ }
bits[i] = find_subframe_rice_params(s, sub, i+1);
if (bits[i] < bits[opt_order])
opt_order = i;
@@ -846,13 +933,60 @@ static int encode_residual_ch(FlacEncodeContext *s, int ch)
opt_order++;
}
+ if (s->options.multi_dim_quant) {
+ int allsteps = 1;
+ int i, step, improved;
+ int64_t best_score = INT64_MAX;
+ int32_t qmax;
+
+ qmax = (1 << (s->options.lpc_coeff_precision - 1)) - 1;
+
+ for (i=0; i<opt_order; i++)
+ allsteps *= 3;
+
+ do {
+ improved = 0;
+ for (step = 0; step < allsteps; step++) {
+ int tmp = step;
+ int32_t lpc_try[MAX_LPC_ORDER];
+ int64_t score = 0;
+ int diffsum = 0;
+
+ for (i=0; i<opt_order; i++) {
+ int diff = ((tmp + 1) % 3) - 1;
+ lpc_try[i] = av_clip(coefs[opt_order - 1][i] + diff, -qmax, qmax);
+ tmp /= 3;
+ diffsum += !!diff;
+ }
+ if (diffsum >8)
+ continue;
+
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(opt_order - 1) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, opt_order, lpc_try, shift[opt_order-1]);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, opt_order, lpc_try, shift[opt_order-1]);
+ }
+ score = find_subframe_rice_params(s, sub, opt_order);
+ if (score < best_score) {
+ best_score = score;
+ memcpy(coefs[opt_order-1], lpc_try, sizeof(coefs[opt_order-1]));
+ improved=1;
+ }
+ }
+ } while(improved);
+ }
+
sub->order = opt_order;
sub->type_code = sub->type | (sub->order-1);
sub->shift = shift[sub->order-1];
for (i = 0; i < sub->order; i++)
sub->coefs[i] = coefs[sub->order-1][i];
- s->flac_dsp.lpc_encode(res, smp, n, sub->order, sub->coefs, sub->shift);
+ if (s->bps_code * 4 + s->options.lpc_coeff_precision + av_log2(opt_order) <= 32) {
+ s->flac_dsp.lpc16_encode(res, smp, n, sub->order, sub->coefs, sub->shift);
+ } else {
+ s->flac_dsp.lpc32_encode(res, smp, n, sub->order, sub->coefs, sub->shift);
+ }
find_subframe_rice_params(s, sub, sub->order);
@@ -948,7 +1082,7 @@ static void remove_wasted_bits(FlacEncodeContext *s)
}
-static int estimate_stereo_mode(int32_t *left_ch, int32_t *right_ch, int n,
+static int estimate_stereo_mode(const int32_t *left_ch, const int32_t *right_ch, int n,
int max_rice_param)
{
int i, best;
@@ -1188,9 +1322,7 @@ static int update_md5_sum(FlacEncodeContext *s, const void *samples)
for (i = 0; i < s->frame.blocksize * s->channels; i++) {
int32_t v = samples0[i] >> 8;
- *tmp++ = (v ) & 0xFF;
- *tmp++ = (v >> 8) & 0xFF;
- *tmp++ = (v >> 16) & 0xFF;
+ AV_WL24(tmp + 3*i, v);
}
buf = s->md5_buffer;
}
@@ -1258,10 +1390,8 @@ static int flac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
}
- if ((ret = ff_alloc_packet(avpkt, frame_bytes))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, frame_bytes)) < 0)
return ret;
- }
out_bytes = write_frame(s, avpkt);
@@ -1308,7 +1438,7 @@ static const AVOption options[] = {
{ "fixed", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_FIXED }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
{ "levinson", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_LEVINSON }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
{ "cholesky", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LPC_TYPE_CHOLESKY }, INT_MIN, INT_MAX, FLAGS, "lpc_type" },
-{ "lpc_passes", "Number of passes to use for Cholesky factorization during LPC analysis", offsetof(FlacEncodeContext, options.lpc_passes), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, INT_MAX, FLAGS },
+{ "lpc_passes", "Number of passes to use for Cholesky factorization during LPC analysis", offsetof(FlacEncodeContext, options.lpc_passes), AV_OPT_TYPE_INT, {.i64 = 2 }, 1, INT_MAX, FLAGS },
{ "min_partition_order", NULL, offsetof(FlacEncodeContext, options.min_partition_order), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_PARTITION_ORDER, FLAGS },
{ "max_partition_order", NULL, offsetof(FlacEncodeContext, options.max_partition_order), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, MAX_PARTITION_ORDER, FLAGS },
{ "prediction_order_method", "Search method for selecting prediction order", offsetof(FlacEncodeContext, options.prediction_order_method), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, ORDER_METHOD_LOG, FLAGS, "predm" },
@@ -1324,6 +1454,8 @@ static const AVOption options[] = {
{ "left_side", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_LEFT_SIDE }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
{ "right_side", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_RIGHT_SIDE }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
{ "mid_side", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FLAC_CHMODE_MID_SIDE }, INT_MIN, INT_MAX, FLAGS, "ch_mode" },
+{ "exact_rice_parameters", "Calculate rice parameters exactly", offsetof(FlacEncodeContext, options.exact_rice_parameters), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+{ "multi_dim_quant", "Multi-dimensional quantization", offsetof(FlacEncodeContext, options.multi_dim_quant), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
{ NULL },
};
@@ -1343,7 +1475,7 @@ AVCodec ff_flac_encoder = {
.init = flac_encode_init,
.encode2 = flac_encode_frame,
.close = flac_encode_close,
- .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY,
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY | CODEC_CAP_LOSSLESS,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_S32,
AV_SAMPLE_FMT_NONE },
diff --git a/libavcodec/flashsv.c b/libavcodec/flashsv.c
index a5b1294165..f429167fe0 100644
--- a/libavcodec/flashsv.c
+++ b/libavcodec/flashsv.c
@@ -3,20 +3,20 @@
* Copyright (C) 2004 Alex Beregszaszi
* Copyright (C) 2006 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,7 +69,7 @@ typedef struct FlashSVContext {
int diff_start, diff_height;
} FlashSVContext;
-static int decode_hybrid(const uint8_t *sptr, uint8_t *dptr, int dx, int dy,
+static int decode_hybrid(const uint8_t *sptr, const uint8_t *sptr_end, uint8_t *dptr, int dx, int dy,
int h, int w, int stride, const uint32_t *pal)
{
int x, y;
@@ -78,6 +78,8 @@ static int decode_hybrid(const uint8_t *sptr, uint8_t *dptr, int dx, int dy,
for (y = dx + h; y > dx; y--) {
uint8_t *dst = dptr + (y * stride) + dy * 3;
for (x = 0; x < w; x++) {
+ if (sptr >= sptr_end)
+ return AVERROR_INVALIDDATA;
if (*sptr & 0x80) {
/* 15-bit color */
unsigned c = AV_RB16(sptr) & ~0x8000;
@@ -107,7 +109,7 @@ static av_cold int flashsv_decode_end(AVCodecContext *avctx)
av_frame_free(&s->frame);
/* free the tmpblock */
- av_free(s->tmpblock);
+ av_freep(&s->tmpblock);
return 0;
}
@@ -142,6 +144,9 @@ static int flashsv2_prime(FlashSVContext *s, uint8_t *src, int size)
z_stream zs;
int zret; // Zlib return code
+ if (!src)
+ return AVERROR_INVALIDDATA;
+
zs.zalloc = NULL;
zs.zfree = NULL;
zs.opaque = NULL;
@@ -152,7 +157,8 @@ static int flashsv2_prime(FlashSVContext *s, uint8_t *src, int size)
s->zstream.avail_out = s->block_size * 3;
inflate(&s->zstream, Z_SYNC_FLUSH);
- deflateInit(&zs, 0);
+ if (deflateInit(&zs, 0) != Z_OK)
+ return -1;
zs.next_in = s->tmpblock;
zs.avail_in = s->block_size * 3 - s->zstream.avail_out;
zs.next_out = s->deflate_block;
@@ -228,10 +234,15 @@ static int flashsv_decode_block(AVCodecContext *avctx, AVPacket *avpkt,
}
} else {
/* hybrid 15-bit/palette mode */
- decode_hybrid(s->tmpblock, s->frame->data[0],
+ ret = decode_hybrid(s->tmpblock, s->zstream.next_out,
+ s->frame->data[0],
s->image_height - (y_pos + 1 + s->diff_height),
x_pos, s->diff_height, width,
s->frame->linesize[0], s->pal);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "decode_hybrid failed\n");
+ return ret;
+ }
}
skip_bits_long(gb, 8 * block_size); /* skip the consumed bits */
return 0;
@@ -260,6 +271,8 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
FlashSVContext *s = avctx->priv_data;
int h_blocks, v_blocks, h_part, v_part, i, j, ret;
GetBitContext gb;
+ int last_blockwidth = s->block_width;
+ int last_blockheight= s->block_height;
/* no supplementary picture */
if (buf_size == 0)
@@ -267,7 +280,8 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
if (buf_size < 4)
return -1;
- init_get_bits(&gb, avpkt->data, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, avpkt->data, buf_size)) < 0)
+ return ret;
/* start to parse the bitstream */
s->block_width = 16 * (get_bits(&gb, 4) + 1);
@@ -275,6 +289,10 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
s->block_height = 16 * (get_bits(&gb, 4) + 1);
s->image_height = get_bits(&gb, 12);
+ if ( last_blockwidth != s->block_width
+ || last_blockheight!= s->block_height)
+ av_freep(&s->blocks);
+
if (s->ver == 2) {
skip_bits(&gb, 6);
if (get_bits1(&gb)) {
@@ -322,8 +340,8 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
/* initialize the image size once */
if (avctx->width == 0 && avctx->height == 0) {
- avctx->width = s->image_width;
- avctx->height = s->image_height;
+ if ((ret = ff_set_dimensions(avctx, s->image_width, s->image_height)) < 0)
+ return ret;
}
/* check for changes of image width and image height */
@@ -342,19 +360,17 @@ static int flashsv_decode_frame(AVCodecContext *avctx, void *data,
if ((err = av_reallocp(&s->keyframedata, avpkt->size)) < 0)
return err;
memcpy(s->keyframedata, avpkt->data, avpkt->size);
- if ((err = av_reallocp(&s->blocks, (v_blocks + !!v_part) *
- (h_blocks + !!h_part) * sizeof(s->blocks[0]))) < 0)
- return err;
}
+ if(s->ver == 2 && !s->blocks)
+ s->blocks = av_mallocz((v_blocks + !!v_part) * (h_blocks + !!h_part) *
+ sizeof(s->blocks[0]));
ff_dlog(avctx, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n",
s->image_width, s->image_height, s->block_width, s->block_height,
h_blocks, v_blocks, h_part, v_part);
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
/* loop over all block columns */
for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) {
diff --git a/libavcodec/flashsv2enc.c b/libavcodec/flashsv2enc.c
new file mode 100644
index 0000000000..a8bcaa2467
--- /dev/null
+++ b/libavcodec/flashsv2enc.c
@@ -0,0 +1,920 @@
+/*
+ * Flash Screen Video Version 2 encoder
+ * Copyright (C) 2009 Joshua Warner
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Flash Screen Video Version 2 encoder
+ * @author Joshua Warner
+ */
+
+/* Differences from version 1 stream:
+ * NOTE: Currently, the only player that supports version 2 streams is Adobe Flash Player itself.
+ * * Supports sending only a range of scanlines in a block,
+ * indicating a difference from the corresponding block in the last keyframe.
+ * * Supports initializing the zlib dictionary with data from the corresponding
+ * block in the last keyframe, to improve compression.
+ * * Supports a hybrid 15-bit rgb / 7-bit palette color space.
+ */
+
+/* TODO:
+ * Don't keep Block structures for both current frame and keyframe.
+ * Make better heuristics for deciding stream parameters (optimum_* functions). Currently these return constants.
+ * Figure out how to encode palette information in the stream, choose an optimum palette at each keyframe.
+ * Figure out how the zlibPrimeCompressCurrent flag works, implement support.
+ * Find other sample files (that weren't generated here), develop a decoder.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+#include "libavutil/imgutils.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "put_bits.h"
+#include "bytestream.h"
+
+#define HAS_IFRAME_IMAGE 0x02
+#define HAS_PALLET_INFO 0x01
+
+#define COLORSPACE_BGR 0x00
+#define COLORSPACE_15_7 0x10
+#define HAS_DIFF_BLOCKS 0x04
+#define ZLIB_PRIME_COMPRESS_CURRENT 0x02
+#define ZLIB_PRIME_COMPRESS_PREVIOUS 0x01
+
+// Disables experimental "smart" parameter-choosing code, as well as the statistics that it depends on.
+// At the moment, the "smart" code is a great example of how the parameters *shouldn't* be chosen.
+#define FLASHSV2_DUMB
+
+typedef struct Block {
+ uint8_t *enc;
+ uint8_t *sl_begin, *sl_end;
+ int enc_size;
+ uint8_t *data;
+ unsigned long data_size;
+
+ uint8_t start, len;
+ uint8_t dirty;
+ uint8_t col, row, width, height;
+ uint8_t flags;
+} Block;
+
+typedef struct Palette {
+ unsigned colors[128];
+ uint8_t index[1 << 15];
+} Palette;
+
+typedef struct FlashSV2Context {
+ AVCodecContext *avctx;
+ uint8_t *current_frame;
+ uint8_t *key_frame;
+ uint8_t *encbuffer;
+ uint8_t *keybuffer;
+ uint8_t *databuffer;
+
+ uint8_t *blockbuffer;
+ int blockbuffer_size;
+
+ Block *frame_blocks;
+ Block *key_blocks;
+ int frame_size;
+ int blocks_size;
+
+ int use15_7, dist, comp;
+
+ int rows, cols;
+
+ int last_key_frame;
+
+ int image_width, image_height;
+ int block_width, block_height;
+ uint8_t flags;
+ uint8_t use_custom_palette;
+ uint8_t palette_type; ///< 0=>default, 1=>custom - changed when palette regenerated.
+ Palette palette;
+#ifndef FLASHSV2_DUMB
+ double tot_blocks; ///< blocks encoded since last keyframe
+ double diff_blocks; ///< blocks that were different since last keyframe
+ double tot_lines; ///< total scanlines in image since last keyframe
+ double diff_lines; ///< scanlines that were different since last keyframe
+ double raw_size; ///< size of raw frames since last keyframe
+ double comp_size; ///< size of compressed data since last keyframe
+ double uncomp_size; ///< size of uncompressed data since last keyframe
+
+ double total_bits; ///< total bits written to stream so far
+#endif
+} FlashSV2Context;
+
+static av_cold void cleanup(FlashSV2Context * s)
+{
+ av_freep(&s->encbuffer);
+ av_freep(&s->keybuffer);
+ av_freep(&s->databuffer);
+ av_freep(&s->blockbuffer);
+ av_freep(&s->current_frame);
+ av_freep(&s->key_frame);
+
+ av_freep(&s->frame_blocks);
+ av_freep(&s->key_blocks);
+}
+
+static void init_blocks(FlashSV2Context * s, Block * blocks,
+ uint8_t * encbuf, uint8_t * databuf)
+{
+ int row, col;
+ Block *b;
+ for (col = 0; col < s->cols; col++) {
+ for (row = 0; row < s->rows; row++) {
+ b = blocks + (col + row * s->cols);
+ b->width = (col < s->cols - 1) ?
+ s->block_width :
+ s->image_width - col * s->block_width;
+
+ b->height = (row < s->rows - 1) ?
+ s->block_height :
+ s->image_height - row * s->block_height;
+
+ b->row = row;
+ b->col = col;
+ b->enc = encbuf;
+ b->data = databuf;
+ encbuf += b->width * b->height * 3;
+ databuf += !databuf ? 0 : b->width * b->height * 6;
+ }
+ }
+}
+
+static void reset_stats(FlashSV2Context * s)
+{
+#ifndef FLASHSV2_DUMB
+ s->diff_blocks = 0.1;
+ s->tot_blocks = 1;
+ s->diff_lines = 0.1;
+ s->tot_lines = 1;
+ s->raw_size = s->comp_size = s->uncomp_size = 10;
+#endif
+}
+
+static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
+{
+ FlashSV2Context *s = avctx->priv_data;
+
+ s->avctx = avctx;
+
+ s->comp = avctx->compression_level;
+ if (s->comp == -1)
+ s->comp = 9;
+ if (s->comp < 0 || s->comp > 9) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Compression level should be 0-9, not %d\n", s->comp);
+ return -1;
+ }
+
+
+ if ((avctx->width > 4095) || (avctx->height > 4095)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Input dimensions too large, input must be max 4095x4095 !\n");
+ return -1;
+ }
+ if ((avctx->width < 16) || (avctx->height < 16)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Input dimensions too small, input must be at least 16x16 !\n");
+ return -1;
+ }
+
+ if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0)
+ return -1;
+
+
+ s->last_key_frame = 0;
+
+ s->image_width = avctx->width;
+ s->image_height = avctx->height;
+
+ s->block_width = (s->image_width / 12) & ~15;
+ s->block_height = (s->image_height / 12) & ~15;
+
+ if(!s->block_width)
+ s->block_width = 1;
+ if(!s->block_height)
+ s->block_height = 1;
+
+ s->rows = (s->image_height + s->block_height - 1) / s->block_height;
+ s->cols = (s->image_width + s->block_width - 1) / s->block_width;
+
+ s->frame_size = s->image_width * s->image_height * 3;
+ s->blocks_size = s->rows * s->cols * sizeof(Block);
+
+ s->encbuffer = av_mallocz(s->frame_size);
+ s->keybuffer = av_mallocz(s->frame_size);
+ s->databuffer = av_mallocz(s->frame_size * 6);
+ s->current_frame = av_mallocz(s->frame_size);
+ s->key_frame = av_mallocz(s->frame_size);
+ s->frame_blocks = av_mallocz(s->blocks_size);
+ s->key_blocks = av_mallocz(s->blocks_size);
+
+ s->blockbuffer = NULL;
+ s->blockbuffer_size = 0;
+
+ init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
+ init_blocks(s, s->key_blocks, s->keybuffer, 0);
+ reset_stats(s);
+#ifndef FLASHSV2_DUMB
+ s->total_bits = 1;
+#endif
+
+ s->use_custom_palette = 0;
+ s->palette_type = -1; // so that the palette will be generated in reconfigure_at_keyframe
+
+ if (!s->encbuffer || !s->keybuffer || !s->databuffer
+ || !s->current_frame || !s->key_frame || !s->key_blocks
+ || !s->frame_blocks) {
+ av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
+ cleanup(s);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int new_key_frame(FlashSV2Context * s)
+{
+ int i;
+ memcpy(s->key_blocks, s->frame_blocks, s->blocks_size);
+ memcpy(s->key_frame, s->current_frame, s->frame_size);
+
+ for (i = 0; i < s->rows * s->cols; i++) {
+ s->key_blocks[i].enc += (s->keybuffer - s->encbuffer);
+ s->key_blocks[i].sl_begin = 0;
+ s->key_blocks[i].sl_end = 0;
+ s->key_blocks[i].data = 0;
+ }
+ memcpy(s->keybuffer, s->encbuffer, s->frame_size);
+
+ return 0;
+}
+
+static int write_palette(FlashSV2Context * s, uint8_t * buf, int buf_size)
+{
+ //this isn't implemented yet! Default palette only!
+ return -1;
+}
+
+static int write_header(FlashSV2Context * s, uint8_t * buf, int buf_size)
+{
+ PutBitContext pb;
+ int buf_pos, len;
+
+ if (buf_size < 5)
+ return -1;
+
+ init_put_bits(&pb, buf, buf_size);
+
+ put_bits(&pb, 4, (s->block_width >> 4) - 1);
+ put_bits(&pb, 12, s->image_width);
+ put_bits(&pb, 4, (s->block_height >> 4) - 1);
+ put_bits(&pb, 12, s->image_height);
+
+ flush_put_bits(&pb);
+ buf_pos = 4;
+
+ buf[buf_pos++] = s->flags;
+
+ if (s->flags & HAS_PALLET_INFO) {
+ len = write_palette(s, buf + buf_pos, buf_size - buf_pos);
+ if (len < 0)
+ return -1;
+ buf_pos += len;
+ }
+
+ return buf_pos;
+}
+
+static int write_block(Block * b, uint8_t * buf, int buf_size)
+{
+ int buf_pos = 0;
+ unsigned block_size = b->data_size;
+
+ if (b->flags & HAS_DIFF_BLOCKS)
+ block_size += 2;
+ if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT)
+ block_size += 2;
+ if (block_size > 0)
+ block_size += 1;
+ if (buf_size < block_size + 2)
+ return -1;
+
+ buf[buf_pos++] = block_size >> 8;
+ buf[buf_pos++] = block_size;
+
+ if (block_size == 0)
+ return buf_pos;
+
+ buf[buf_pos++] = b->flags;
+
+ if (b->flags & HAS_DIFF_BLOCKS) {
+ buf[buf_pos++] = (b->start);
+ buf[buf_pos++] = (b->len);
+ }
+
+ if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT) {
+ //This feature of the format is poorly understood, and as of now, unused.
+ buf[buf_pos++] = (b->col);
+ buf[buf_pos++] = (b->row);
+ }
+
+ memcpy(buf + buf_pos, b->data, b->data_size);
+
+ buf_pos += b->data_size;
+
+ return buf_pos;
+}
+
+static int encode_zlib(Block * b, uint8_t * buf, unsigned long *buf_size, int comp)
+{
+ int res = compress2(buf, buf_size, b->sl_begin, b->sl_end - b->sl_begin, comp);
+ return res == Z_OK ? 0 : -1;
+}
+
+static int encode_zlibprime(Block * b, Block * prime, uint8_t * buf,
+ int *buf_size, int comp)
+{
+ z_stream s;
+ int res;
+ s.zalloc = NULL;
+ s.zfree = NULL;
+ s.opaque = NULL;
+ res = deflateInit(&s, comp);
+ if (res < 0)
+ return -1;
+
+ s.next_in = prime->enc;
+ s.avail_in = prime->enc_size;
+ while (s.avail_in > 0) {
+ s.next_out = buf;
+ s.avail_out = *buf_size;
+ res = deflate(&s, Z_SYNC_FLUSH);
+ if (res < 0)
+ return -1;
+ }
+
+ s.next_in = b->sl_begin;
+ s.avail_in = b->sl_end - b->sl_begin;
+ s.next_out = buf;
+ s.avail_out = *buf_size;
+ res = deflate(&s, Z_FINISH);
+ deflateEnd(&s);
+ *buf_size -= s.avail_out;
+ if (res != Z_STREAM_END)
+ return -1;
+ return 0;
+}
+
+static int encode_bgr(Block * b, const uint8_t * src, int stride)
+{
+ int i;
+ uint8_t *ptr = b->enc;
+ for (i = 0; i < b->start; i++)
+ memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
+ b->sl_begin = ptr + i * b->width * 3;
+ for (; i < b->start + b->len; i++)
+ memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
+ b->sl_end = ptr + i * b->width * 3;
+ for (; i < b->height; i++)
+ memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
+ b->enc_size = ptr + i * b->width * 3 - b->enc;
+ return b->enc_size;
+}
+
+static inline unsigned pixel_color15(const uint8_t * src)
+{
+ return (src[0] >> 3) | ((src[1] & 0xf8) << 2) | ((src[2] & 0xf8) << 7);
+}
+
+static inline unsigned int chroma_diff(unsigned int c1, unsigned int c2)
+{
+ unsigned int t1 = (c1 & 0x000000ff) + ((c1 & 0x0000ff00) >> 8) + ((c1 & 0x00ff0000) >> 16);
+ unsigned int t2 = (c2 & 0x000000ff) + ((c2 & 0x0000ff00) >> 8) + ((c2 & 0x00ff0000) >> 16);
+
+ return abs(t1 - t2) + abs((c1 & 0x000000ff) - (c2 & 0x000000ff)) +
+ abs(((c1 & 0x0000ff00) >> 8) - ((c2 & 0x0000ff00) >> 8)) +
+ abs(((c1 & 0x00ff0000) >> 16) - ((c2 & 0x00ff0000) >> 16));
+}
+
+static inline int pixel_color7_fast(Palette * palette, unsigned c15)
+{
+ return palette->index[c15];
+}
+
+static int pixel_color7_slow(Palette * palette, unsigned color)
+{
+ int i, min = 0x7fffffff;
+ int minc = -1;
+ for (i = 0; i < 128; i++) {
+ int c1 = palette->colors[i];
+ int diff = chroma_diff(c1, color);
+ if (diff < min) {
+ min = diff;
+ minc = i;
+ }
+ }
+ return minc;
+}
+
+static inline unsigned pixel_bgr(const uint8_t * src)
+{
+ return (src[0]) | (src[1] << 8) | (src[2] << 16);
+}
+
+static int write_pixel_15_7(Palette * palette, uint8_t * dest, const uint8_t * src,
+ int dist)
+{
+ unsigned c15 = pixel_color15(src);
+ unsigned color = pixel_bgr(src);
+ int d15 = chroma_diff(color, color & 0x00f8f8f8);
+ int c7 = pixel_color7_fast(palette, c15);
+ int d7 = chroma_diff(color, palette->colors[c7]);
+ if (dist + d15 >= d7) {
+ dest[0] = c7;
+ return 1;
+ } else {
+ dest[0] = 0x80 | (c15 >> 8);
+ dest[1] = c15 & 0xff;
+ return 2;
+ }
+}
+
+static int update_palette_index(Palette * palette)
+{
+ int r, g, b;
+ unsigned int bgr, c15, index;
+ for (r = 4; r < 256; r += 8) {
+ for (g = 4; g < 256; g += 8) {
+ for (b = 4; b < 256; b += 8) {
+ bgr = b | (g << 8) | (r << 16);
+ c15 = (b >> 3) | ((g & 0xf8) << 2) | ((r & 0xf8) << 7);
+ index = pixel_color7_slow(palette, bgr);
+
+ palette->index[c15] = index;
+ }
+ }
+ }
+ return 0;
+}
+
+static const unsigned int default_screen_video_v2_palette[128] = {
+ 0x00000000, 0x00333333, 0x00666666, 0x00999999, 0x00CCCCCC, 0x00FFFFFF,
+ 0x00330000, 0x00660000, 0x00990000, 0x00CC0000, 0x00FF0000, 0x00003300,
+ 0x00006600, 0x00009900, 0x0000CC00, 0x0000FF00, 0x00000033, 0x00000066,
+ 0x00000099, 0x000000CC, 0x000000FF, 0x00333300, 0x00666600, 0x00999900,
+ 0x00CCCC00, 0x00FFFF00, 0x00003333, 0x00006666, 0x00009999, 0x0000CCCC,
+ 0x0000FFFF, 0x00330033, 0x00660066, 0x00990099, 0x00CC00CC, 0x00FF00FF,
+ 0x00FFFF33, 0x00FFFF66, 0x00FFFF99, 0x00FFFFCC, 0x00FF33FF, 0x00FF66FF,
+ 0x00FF99FF, 0x00FFCCFF, 0x0033FFFF, 0x0066FFFF, 0x0099FFFF, 0x00CCFFFF,
+ 0x00CCCC33, 0x00CCCC66, 0x00CCCC99, 0x00CCCCFF, 0x00CC33CC, 0x00CC66CC,
+ 0x00CC99CC, 0x00CCFFCC, 0x0033CCCC, 0x0066CCCC, 0x0099CCCC, 0x00FFCCCC,
+ 0x00999933, 0x00999966, 0x009999CC, 0x009999FF, 0x00993399, 0x00996699,
+ 0x0099CC99, 0x0099FF99, 0x00339999, 0x00669999, 0x00CC9999, 0x00FF9999,
+ 0x00666633, 0x00666699, 0x006666CC, 0x006666FF, 0x00663366, 0x00669966,
+ 0x0066CC66, 0x0066FF66, 0x00336666, 0x00996666, 0x00CC6666, 0x00FF6666,
+ 0x00333366, 0x00333399, 0x003333CC, 0x003333FF, 0x00336633, 0x00339933,
+ 0x0033CC33, 0x0033FF33, 0x00663333, 0x00993333, 0x00CC3333, 0x00FF3333,
+ 0x00003366, 0x00336600, 0x00660033, 0x00006633, 0x00330066, 0x00663300,
+ 0x00336699, 0x00669933, 0x00993366, 0x00339966, 0x00663399, 0x00996633,
+ 0x006699CC, 0x0099CC66, 0x00CC6699, 0x0066CC99, 0x009966CC, 0x00CC9966,
+ 0x0099CCFF, 0x00CCFF99, 0x00FF99CC, 0x0099FFCC, 0x00CC99FF, 0x00FFCC99,
+ 0x00111111, 0x00222222, 0x00444444, 0x00555555, 0x00AAAAAA, 0x00BBBBBB,
+ 0x00DDDDDD, 0x00EEEEEE
+};
+
+static int generate_default_palette(Palette * palette)
+{
+ memcpy(palette->colors, default_screen_video_v2_palette,
+ sizeof(default_screen_video_v2_palette));
+
+ return update_palette_index(palette);
+}
+
+static int generate_optimum_palette(Palette * palette, const uint8_t * image,
+ int width, int height, int stride)
+{
+ //this isn't implemented yet! Default palette only!
+ return -1;
+}
+
+static inline int encode_15_7_sl(Palette * palette, uint8_t * dest,
+ const uint8_t * src, int width, int dist)
+{
+ int len = 0, x;
+ for (x = 0; x < width; x++) {
+ len += write_pixel_15_7(palette, dest + len, src + 3 * x, dist);
+ }
+ return len;
+}
+
+static int encode_15_7(Palette * palette, Block * b, const uint8_t * src,
+ int stride, int dist)
+{
+ int i;
+ uint8_t *ptr = b->enc;
+ for (i = 0; i < b->start; i++)
+ ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
+ b->sl_begin = ptr;
+ for (; i < b->start + b->len; i++)
+ ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
+ b->sl_end = ptr;
+ for (; i < b->height; i++)
+ ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
+ b->enc_size = ptr - b->enc;
+ return b->enc_size;
+}
+
+static int encode_block(FlashSV2Context *s, Palette * palette, Block * b,
+ Block * prev, const uint8_t * src, int stride, int comp,
+ int dist, int keyframe)
+{
+ unsigned buf_size = b->width * b->height * 6;
+ uint8_t *buf = s->blockbuffer;
+ int res;
+
+ if (b->flags & COLORSPACE_15_7) {
+ encode_15_7(palette, b, src, stride, dist);
+ } else {
+ encode_bgr(b, src, stride);
+ }
+
+ if (b->len > 0) {
+ b->data_size = buf_size;
+ res = encode_zlib(b, b->data, &b->data_size, comp);
+ if (res)
+ return res;
+
+ if (!keyframe) {
+ res = encode_zlibprime(b, prev, buf, &buf_size, comp);
+ if (res)
+ return res;
+
+ if (buf_size < b->data_size) {
+ b->data_size = buf_size;
+ memcpy(b->data, buf, buf_size);
+ b->flags |= ZLIB_PRIME_COMPRESS_PREVIOUS;
+ }
+ }
+ } else {
+ b->data_size = 0;
+ }
+ return 0;
+}
+
+static int compare_sl(FlashSV2Context * s, Block * b, const uint8_t * src,
+ uint8_t * frame, uint8_t * key, int y, int keyframe)
+{
+ if (memcmp(src, frame, b->width * 3) != 0) {
+ b->dirty = 1;
+ memcpy(frame, src, b->width * 3);
+#ifndef FLASHSV2_DUMB
+ s->diff_lines++;
+#endif
+ }
+ if (memcmp(src, key, b->width * 3) != 0) {
+ if (b->len == 0)
+ b->start = y;
+ b->len = y + 1 - b->start;
+ }
+ return 0;
+}
+
+static int mark_all_blocks(FlashSV2Context * s, const uint8_t * src, int stride,
+ int keyframe)
+{
+ int sl, rsl, col, pos, possl;
+ Block *b;
+ for (sl = s->image_height - 1; sl >= 0; sl--) {
+ for (col = 0; col < s->cols; col++) {
+ rsl = s->image_height - sl - 1;
+ b = s->frame_blocks + col + rsl / s->block_height * s->cols;
+ possl = stride * sl + col * s->block_width * 3;
+ pos = s->image_width * rsl * 3 + col * s->block_width * 3;
+ compare_sl(s, b, src + possl, s->current_frame + pos,
+ s->key_frame + pos, rsl % s->block_height, keyframe);
+ }
+ }
+#ifndef FLASHSV2_DUMB
+ s->tot_lines += s->image_height * s->cols;
+#endif
+ return 0;
+}
+
+static int encode_all_blocks(FlashSV2Context * s, int keyframe)
+{
+ int row, col, res;
+ uint8_t *data;
+ Block *b, *prev;
+ for (row = 0; row < s->rows; row++) {
+ for (col = 0; col < s->cols; col++) {
+ b = s->frame_blocks + (row * s->cols + col);
+ prev = s->key_blocks + (row * s->cols + col);
+ b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
+ if (keyframe) {
+ b->start = 0;
+ b->len = b->height;
+ } else if (!b->dirty) {
+ b->start = 0;
+ b->len = 0;
+ b->data_size = 0;
+ continue;
+ } else if (b->start != 0 || b->len != b->height) {
+ b->flags |= HAS_DIFF_BLOCKS;
+ }
+ data = s->current_frame + s->image_width * 3 * s->block_height * row + s->block_width * col * 3;
+ res = encode_block(s, &s->palette, b, prev, data, s->image_width * 3, s->comp, s->dist, keyframe);
+#ifndef FLASHSV2_DUMB
+ if (b->dirty)
+ s->diff_blocks++;
+ s->comp_size += b->data_size;
+ s->uncomp_size += b->enc_size;
+#endif
+ if (res)
+ return res;
+ }
+ }
+#ifndef FLASHSV2_DUMB
+ s->raw_size += s->image_width * s->image_height * 3;
+ s->tot_blocks += s->rows * s->cols;
+#endif
+ return 0;
+}
+
+static int write_all_blocks(FlashSV2Context * s, uint8_t * buf,
+ int buf_size)
+{
+ int row, col, buf_pos = 0, len;
+ Block *b;
+ for (row = 0; row < s->rows; row++) {
+ for (col = 0; col < s->cols; col++) {
+ b = s->frame_blocks + row * s->cols + col;
+ len = write_block(b, buf + buf_pos, buf_size - buf_pos);
+ b->start = b->len = b->dirty = 0;
+ if (len < 0)
+ return len;
+ buf_pos += len;
+ }
+ }
+ return buf_pos;
+}
+
+static int write_bitstream(FlashSV2Context * s, const uint8_t * src, int stride,
+ uint8_t * buf, int buf_size, int keyframe)
+{
+ int buf_pos, res;
+
+ res = mark_all_blocks(s, src, stride, keyframe);
+ if (res)
+ return res;
+ res = encode_all_blocks(s, keyframe);
+ if (res)
+ return res;
+
+ res = write_header(s, buf, buf_size);
+ if (res < 0) {
+ return res;
+ } else {
+ buf_pos = res;
+ }
+ res = write_all_blocks(s, buf + buf_pos, buf_size - buf_pos);
+ if (res < 0)
+ return res;
+ buf_pos += res;
+#ifndef FLASHSV2_DUMB
+ s->total_bits += ((double) buf_pos) * 8.0;
+#endif
+
+ return buf_pos;
+}
+
+static void recommend_keyframe(FlashSV2Context * s, int *keyframe)
+{
+#ifndef FLASHSV2_DUMB
+ double block_ratio, line_ratio, enc_ratio, comp_ratio, data_ratio;
+ if (s->avctx->gop_size > 0) {
+ block_ratio = s->diff_blocks / s->tot_blocks;
+ line_ratio = s->diff_lines / s->tot_lines;
+ enc_ratio = s->uncomp_size / s->raw_size;
+ comp_ratio = s->comp_size / s->uncomp_size;
+ data_ratio = s->comp_size / s->raw_size;
+
+ if ((block_ratio >= 0.5 && line_ratio / block_ratio <= 0.5) || line_ratio >= 0.95) {
+ *keyframe = 1;
+ return;
+ }
+ }
+#else
+ return;
+#endif
+}
+
+#ifndef FLASHSV2_DUMB
+static const double block_size_fraction = 1.0 / 300;
+static const double use15_7_threshold = 8192;
+static const double color15_7_factor = 100;
+#endif
+static int optimum_block_width(FlashSV2Context * s)
+{
+#ifndef FLASHSV2_DUMB
+ double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
+ double width = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_width;
+ int pwidth = ((int) width);
+ return FFCLIP(pwidth & ~15, 256, 16);
+#else
+ return 64;
+#endif
+}
+
+static int optimum_block_height(FlashSV2Context * s)
+{
+#ifndef FLASHSV2_DUMB
+ double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
+ double height = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_height;
+ int pheight = ((int) height);
+ return FFCLIP(pheight & ~15, 256, 16);
+#else
+ return 64;
+#endif
+}
+
+static int optimum_use15_7(FlashSV2Context * s)
+{
+#ifndef FLASHSV2_DUMB
+ double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den * s->avctx->ticks_per_frame)) /
+ ((double) s->avctx->time_base.num) * s->avctx->frame_number;
+ if (ideal + use15_7_threshold < s->total_bits) {
+ return 1;
+ } else {
+ return 0;
+ }
+#else
+ return s->avctx->global_quality == 0;
+#endif
+}
+
+static int optimum_dist(FlashSV2Context * s)
+{
+#ifndef FLASHSV2_DUMB
+ double ideal =
+ s->avctx->bit_rate * s->avctx->time_base.den *
+ s->avctx->ticks_per_frame;
+ int dist = pow((s->total_bits / ideal) * color15_7_factor, 3);
+ av_log(s->avctx, AV_LOG_DEBUG, "dist: %d\n", dist);
+ return dist;
+#else
+ return 15;
+#endif
+}
+
+
+static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
+ int stride)
+{
+ int update_palette = 0;
+ int res;
+ int block_width = optimum_block_width (s);
+ int block_height = optimum_block_height(s);
+
+ s->rows = (s->image_height + block_height - 1) / block_height;
+ s->cols = (s->image_width + block_width - 1) / block_width;
+
+ if (block_width != s->block_width || block_height != s->block_height) {
+ s->block_width = block_width;
+ s->block_height = block_height;
+ if (s->rows * s->cols > s->blocks_size / sizeof(Block)) {
+ s->frame_blocks = av_realloc_array(s->frame_blocks, s->rows, s->cols * sizeof(Block));
+ s->key_blocks = av_realloc_array(s->key_blocks, s->cols, s->rows * sizeof(Block));
+ if (!s->frame_blocks || !s->key_blocks) {
+ av_log(s->avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
+ return -1;
+ }
+ s->blocks_size = s->rows * s->cols * sizeof(Block);
+ }
+ init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
+ init_blocks(s, s->key_blocks, s->keybuffer, 0);
+
+ av_fast_malloc(&s->blockbuffer, &s->blockbuffer_size, block_width * block_height * 6);
+ if (!s->blockbuffer) {
+ av_log(s->avctx, AV_LOG_ERROR, "Could not allocate block buffer.\n");
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ s->use15_7 = optimum_use15_7(s);
+ if (s->use15_7) {
+ if ((s->use_custom_palette && s->palette_type != 1) || update_palette) {
+ res = generate_optimum_palette(&s->palette, image, s->image_width, s->image_height, stride);
+ if (res)
+ return res;
+ s->palette_type = 1;
+ av_log(s->avctx, AV_LOG_DEBUG, "Generated optimum palette\n");
+ } else if (!s->use_custom_palette && s->palette_type != 0) {
+ res = generate_default_palette(&s->palette);
+ if (res)
+ return res;
+ s->palette_type = 0;
+ av_log(s->avctx, AV_LOG_DEBUG, "Generated default palette\n");
+ }
+ }
+
+
+ reset_stats(s);
+
+ return 0;
+}
+
+static int flashsv2_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *p, int *got_packet)
+{
+ FlashSV2Context *const s = avctx->priv_data;
+ int res;
+ int keyframe = 0;
+
+ if ((res = ff_alloc_packet2(avctx, pkt, s->frame_size + FF_MIN_BUFFER_SIZE)) < 0)
+ return res;
+
+ /* First frame needs to be a keyframe */
+ if (avctx->frame_number == 0)
+ keyframe = 1;
+
+ /* Check the placement of keyframes */
+ if (avctx->gop_size > 0) {
+ if (avctx->frame_number >= s->last_key_frame + avctx->gop_size)
+ keyframe = 1;
+ }
+
+ if (!keyframe
+ && avctx->frame_number > s->last_key_frame + avctx->keyint_min) {
+ recommend_keyframe(s, &keyframe);
+ if (keyframe)
+ av_log(avctx, AV_LOG_DEBUG, "Recommending key frame at frame %d\n", avctx->frame_number);
+ }
+
+ if (keyframe) {
+ res = reconfigure_at_keyframe(s, p->data[0], p->linesize[0]);
+ if (res)
+ return res;
+ }
+
+ if (s->use15_7)
+ s->dist = optimum_dist(s);
+
+ res = write_bitstream(s, p->data[0], p->linesize[0], pkt->data, pkt->size, keyframe);
+
+ if (keyframe) {
+ new_key_frame(s);
+ s->last_key_frame = avctx->frame_number;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ av_log(avctx, AV_LOG_DEBUG, "Inserting key frame at frame %d\n", avctx->frame_number);
+ }
+
+ pkt->size = res;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static av_cold int flashsv2_encode_end(AVCodecContext * avctx)
+{
+ FlashSV2Context *s = avctx->priv_data;
+
+ cleanup(s);
+
+ return 0;
+}
+
+AVCodec ff_flashsv2_encoder = {
+ .name = "flashsv2",
+ .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video Version 2"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_FLASHSV2,
+ .priv_data_size = sizeof(FlashSV2Context),
+ .init = flashsv2_encode_init,
+ .encode2 = flashsv2_encode_frame,
+ .close = flashsv2_encode_end,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/flashsvenc.c b/libavcodec/flashsvenc.c
index 971ce1be82..acbc13482a 100644
--- a/libavcodec/flashsvenc.c
+++ b/libavcodec/flashsvenc.c
@@ -3,20 +3,20 @@
* Copyright (C) 2004 Alex Beregszaszi
* Copyright (C) 2006 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -94,9 +94,9 @@ static av_cold int flashsv_encode_end(AVCodecContext *avctx)
deflateEnd(&s->zstream);
- av_free(s->encbuffer);
- av_free(s->previous_frame);
- av_free(s->tmpblock);
+ av_freep(&s->encbuffer);
+ av_freep(&s->previous_frame);
+ av_freep(&s->tmpblock);
av_frame_free(&avctx->coded_frame);
@@ -151,7 +151,7 @@ static int encode_bitstream(FlashSVContext *s, const AVFrame *p, uint8_t *buf,
int buf_pos, res;
int pred_blocks = 0;
- init_put_bits(&pb, buf, buf_size * 8);
+ init_put_bits(&pb, buf, buf_size);
put_bits(&pb, 4, block_width / 16 - 1);
put_bits(&pb, 12, s->image_width);
@@ -246,12 +246,8 @@ static int flashsv_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
I_frame = 1;
}
- if ((res = ff_alloc_packet(pkt, s->image_width * s->image_height * 3)) < 0) {
- //Conservative upper bound check for compressed data
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n",
- s->image_width * s->image_height * 3);
+ if ((res = ff_alloc_packet2(avctx, pkt, s->image_width * s->image_height * 3)) < 0)
return res;
- }
pkt->size = encode_bitstream(s, p, pkt->data, pkt->size, opt_w * 16, opt_h * 16,
pfptr, &I_frame);
diff --git a/libavcodec/flicvideo.c b/libavcodec/flicvideo.c
index 91bd7997b2..08dd98b597 100644
--- a/libavcodec/flicvideo.c
+++ b/libavcodec/flicvideo.c
@@ -1,21 +1,21 @@
/*
* FLI/FLC Animation Video Decoder
- * Copyright (C) 2003, 2004 the ffmpeg project
+ * Copyright (c) 2003, 2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,7 +64,7 @@
#define CHECK_PIXEL_PTR(n) \
if (pixel_ptr + n > pixel_limit) { \
- av_log (s->avctx, AV_LOG_INFO, "Problem: pixel_ptr >= pixel_limit (%d >= %d)\n", \
+ av_log (s->avctx, AV_LOG_ERROR, "Invalid pixel_ptr = %d > pixel_limit = %d\n", \
pixel_ptr + n, pixel_limit); \
return AVERROR_INVALIDDATA; \
} \
@@ -84,22 +84,40 @@ static av_cold int flic_decode_init(AVCodecContext *avctx)
unsigned char *fli_header = (unsigned char *)avctx->extradata;
int depth;
- if (avctx->extradata_size != 12 &&
- avctx->extradata_size != 128) {
- av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n");
+ if (avctx->extradata_size != 0 &&
+ avctx->extradata_size != 12 &&
+ avctx->extradata_size != 128 &&
+ avctx->extradata_size != 256 &&
+ avctx->extradata_size != 904 &&
+ avctx->extradata_size != 1024) {
+ av_log(avctx, AV_LOG_ERROR, "Unexpected extradata size %d\n", avctx->extradata_size);
return AVERROR_INVALIDDATA;
}
s->avctx = avctx;
- s->fli_type = AV_RL16(&fli_header[4]); /* Might be overridden if a Magic Carpet FLC */
-
- depth = 0;
if (s->avctx->extradata_size == 12) {
/* special case for magic carpet FLIs */
s->fli_type = FLC_MAGIC_CARPET_SYNTHETIC_TYPE_CODE;
depth = 8;
+ } else if (avctx->extradata_size == 1024) {
+ uint8_t *ptr = avctx->extradata;
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ s->palette[i] = AV_RL32(ptr);
+ ptr += 4;
+ }
+ depth = 8;
+ /* FLI in MOV, see e.g. FFmpeg trac issue #626 */
+ } else if (avctx->extradata_size == 0 ||
+ avctx->extradata_size == 256 ||
+ /* see FFmpeg ticket #1234 */
+ avctx->extradata_size == 904) {
+ s->fli_type = FLI_TYPE_CODE;
+ depth = 8;
} else {
+ s->fli_type = AV_RL16(&fli_header[4]);
depth = AV_RL16(&fli_header[12]);
}
@@ -116,7 +134,7 @@ static av_cold int flic_decode_init(AVCodecContext *avctx)
case 15 : avctx->pix_fmt = AV_PIX_FMT_RGB555; break;
case 16 : avctx->pix_fmt = AV_PIX_FMT_RGB565; break;
case 24 : avctx->pix_fmt = AV_PIX_FMT_BGR24; /* Supposedly BGR, but havent any files to test with */
- av_log(avctx, AV_LOG_ERROR, "24Bpp FLC/FLX is unsupported due to no test files.\n");
+ avpriv_request_sample(avctx, "24Bpp FLC/FLX");
return AVERROR_PATCHWELCOME;
default :
av_log(avctx, AV_LOG_ERROR, "Unknown FLC/FLX depth of %d Bpp is unsupported.\n",depth);
@@ -139,7 +157,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
FlicDecodeContext *s = avctx->priv_data;
GetByteContext g2;
- int stream_ptr_after_color_chunk;
int pixel_ptr;
int palette_ptr;
unsigned char palette_idx1;
@@ -171,14 +188,16 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
bytestream2_init(&g2, buf, buf_size);
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
pixels = s->frame->data[0];
pixel_limit = s->avctx->height * s->frame->linesize[0];
+ if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + FF_INPUT_BUFFER_PADDING_SIZE))
+ return AVERROR_INVALIDDATA;
frame_size = bytestream2_get_le32(&g2);
+ if (frame_size > buf_size)
+ frame_size = buf_size;
bytestream2_skip(&g2, 2); /* skip the magic number */
num_chunks = bytestream2_get_le16(&g2);
bytestream2_skip(&g2, 8); /* skip padding */
@@ -186,15 +205,22 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
frame_size -= 16;
/* iterate through the chunks */
- while ((frame_size > 0) && (num_chunks > 0)) {
+ while ((frame_size >= 6) && (num_chunks > 0) &&
+ bytestream2_get_bytes_left(&g2) >= 4) {
+ int stream_ptr_after_chunk;
chunk_size = bytestream2_get_le32(&g2);
+ if (chunk_size > frame_size) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size);
+ chunk_size = frame_size;
+ }
+ stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size;
+
chunk_type = bytestream2_get_le16(&g2);
switch (chunk_type) {
case FLI_256_COLOR:
case FLI_COLOR:
- stream_ptr_after_color_chunk = bytestream2_tell(&g2) + chunk_size - 6;
-
/* check special case: If this file is from the Magic Carpet
* game and uses 6-bit colors even though it reports 256-color
* chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during
@@ -217,6 +243,9 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
if (color_changes == 0)
color_changes = 256;
+ if (bytestream2_tell(&g2) + color_changes * 3 > stream_ptr_after_chunk)
+ break;
+
for (j = 0; j < color_changes; j++) {
unsigned int entry;
@@ -227,26 +256,22 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
r = bytestream2_get_byte(&g2) << color_shift;
g = bytestream2_get_byte(&g2) << color_shift;
b = bytestream2_get_byte(&g2) << color_shift;
- entry = (r << 16) | (g << 8) | b;
+ entry = 0xFFU << 24 | r << 16 | g << 8 | b;
+ if (color_shift == 2)
+ entry |= entry >> 6 & 0x30303;
if (s->palette[palette_ptr] != entry)
s->new_palette = 1;
s->palette[palette_ptr++] = entry;
}
}
-
- /* color chunks sometimes have weird 16-bit alignment issues;
- * therefore, take the hardline approach and skip
- * to the value calculated w.r.t. the size specified by the color
- * chunk header */
- if (stream_ptr_after_color_chunk - bytestream2_tell(&g2) > 0)
- bytestream2_skip(&g2, stream_ptr_after_color_chunk - bytestream2_tell(&g2));
-
break;
case FLI_DELTA:
y_ptr = 0;
compressed_lines = bytestream2_get_le16(&g2);
while (compressed_lines > 0) {
+ if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
+ break;
line_packets = bytestream2_get_le16(&g2);
if ((line_packets & 0xC000) == 0xC000) {
// line skip opcode
@@ -265,6 +290,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
CHECK_PIXEL_PTR(0);
pixel_countdown = s->avctx->width;
for (i = 0; i < line_packets; i++) {
+ if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
+ break;
/* account for the skip bytes */
pixel_skip = bytestream2_get_byte(&g2);
pixel_ptr += pixel_skip;
@@ -281,6 +308,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
}
} else {
CHECK_PIXEL_PTR(byte_run * 2);
+ if (bytestream2_tell(&g2) + byte_run * 2 > stream_ptr_after_chunk)
+ break;
for (j = 0; j < byte_run * 2; j++, pixel_countdown--) {
pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
}
@@ -303,16 +332,22 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
pixel_ptr = y_ptr;
CHECK_PIXEL_PTR(0);
pixel_countdown = s->avctx->width;
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
line_packets = bytestream2_get_byte(&g2);
if (line_packets > 0) {
for (i = 0; i < line_packets; i++) {
/* account for the skip bytes */
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
pixel_skip = bytestream2_get_byte(&g2);
pixel_ptr += pixel_skip;
pixel_countdown -= pixel_skip;
byte_run = sign_extend(bytestream2_get_byte(&g2),8);
if (byte_run > 0) {
CHECK_PIXEL_PTR(byte_run);
+ if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
+ break;
for (j = 0; j < byte_run; j++, pixel_countdown--) {
pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
}
@@ -349,6 +384,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
bytestream2_skip(&g2, 1);
pixel_countdown = s->avctx->width;
while (pixel_countdown > 0) {
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
if (!byte_run) {
av_log(avctx, AV_LOG_ERROR, "Invalid byte run value.\n");
@@ -368,6 +405,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
} else { /* copy bytes if byte_run < 0 */
byte_run = -byte_run;
CHECK_PIXEL_PTR(byte_run);
+ if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
+ break;
for (j = 0; j < byte_run; j++) {
pixels[pixel_ptr++] = bytestream2_get_byte(&g2);
pixel_countdown--;
@@ -384,9 +423,9 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
case FLI_COPY:
/* copy the chunk (uncompressed frame) */
- if (chunk_size - 6 > s->avctx->width * s->avctx->height) {
+ if (chunk_size - 6 != s->avctx->width * s->avctx->height) {
av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
- "bigger than image, skipping chunk\n", chunk_size - 6);
+ "has incorrect size, skipping chunk\n", chunk_size - 6);
bytestream2_skip(&g2, chunk_size - 6);
} else {
for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height;
@@ -399,7 +438,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
case FLI_MINI:
/* some sort of a thumbnail? disregard this chunk... */
- bytestream2_skip(&g2, chunk_size - 6);
break;
default:
@@ -407,14 +445,16 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx,
break;
}
+ if (stream_ptr_after_chunk - bytestream2_tell(&g2) > 0)
+ bytestream2_skip(&g2, stream_ptr_after_chunk - bytestream2_tell(&g2));
+
frame_size -= chunk_size;
num_chunks--;
}
/* by the end of the chunk, the stream ptr should equal the frame
- * size (minus 1, possibly); if it doesn't, issue a warning */
- if ((bytestream2_get_bytes_left(&g2) != 0) &&
- (bytestream2_get_bytes_left(&g2) != 1))
+ * size (minus 1 or 2, possibly); if it doesn't, issue a warning */
+ if (bytestream2_get_bytes_left(&g2) > 2)
av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \
"and final chunk ptr = %d\n", buf_size,
buf_size - bytestream2_get_bytes_left(&g2));
@@ -467,10 +507,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
bytestream2_init(&g2, buf, buf_size);
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
pixels = s->frame->data[0];
pixel_limit = s->avctx->height * s->frame->linesize[0];
@@ -479,14 +517,26 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
bytestream2_skip(&g2, 2); /* skip the magic number */
num_chunks = bytestream2_get_le16(&g2);
bytestream2_skip(&g2, 8); /* skip padding */
+ if (frame_size > buf_size)
+ frame_size = buf_size;
frame_size -= 16;
/* iterate through the chunks */
- while ((frame_size > 0) && (num_chunks > 0)) {
+ while ((frame_size > 0) && (num_chunks > 0) &&
+ bytestream2_get_bytes_left(&g2) >= 4) {
+ int stream_ptr_after_chunk;
chunk_size = bytestream2_get_le32(&g2);
+ if (chunk_size > frame_size) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size);
+ chunk_size = frame_size;
+ }
+ stream_ptr_after_chunk = bytestream2_tell(&g2) - 4 + chunk_size;
+
chunk_type = bytestream2_get_le16(&g2);
+
switch (chunk_type) {
case FLI_256_COLOR:
case FLI_COLOR:
@@ -504,6 +554,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
y_ptr = 0;
compressed_lines = bytestream2_get_le16(&g2);
while (compressed_lines > 0) {
+ if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
+ break;
line_packets = bytestream2_get_le16(&g2);
if (line_packets < 0) {
line_packets = -line_packets;
@@ -515,6 +567,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
pixel_countdown = s->avctx->width;
for (i = 0; i < line_packets; i++) {
/* account for the skip bytes */
+ if (bytestream2_tell(&g2) + 2 > stream_ptr_after_chunk)
+ break;
pixel_skip = bytestream2_get_byte(&g2);
pixel_ptr += (pixel_skip*2); /* Pixel is 2 bytes wide */
pixel_countdown -= pixel_skip;
@@ -528,6 +582,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
pixel_ptr += 2;
}
} else {
+ if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk)
+ break;
CHECK_PIXEL_PTR(2 * byte_run);
for (j = 0; j < byte_run; j++, pixel_countdown--) {
*((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2);
@@ -562,6 +618,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
pixel_countdown = (s->avctx->width * 2);
while (pixel_countdown > 0) {
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
if (byte_run > 0) {
palette_idx1 = bytestream2_get_byte(&g2);
@@ -575,6 +633,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
}
} else { /* copy bytes if byte_run < 0 */
byte_run = -byte_run;
+ if (bytestream2_tell(&g2) + byte_run > stream_ptr_after_chunk)
+ break;
CHECK_PIXEL_PTR(byte_run);
for (j = 0; j < byte_run; j++) {
palette_idx1 = bytestream2_get_byte(&g2);
@@ -614,6 +674,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
pixel_countdown = s->avctx->width; /* Width is in pixels, not bytes */
while (pixel_countdown > 0) {
+ if (bytestream2_tell(&g2) + 1 > stream_ptr_after_chunk)
+ break;
byte_run = sign_extend(bytestream2_get_byte(&g2), 8);
if (byte_run > 0) {
pixel = bytestream2_get_le16(&g2);
@@ -628,6 +690,8 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx,
}
} else { /* copy pixels if byte_run < 0 */
byte_run = -byte_run;
+ if (bytestream2_tell(&g2) + 2 * byte_run > stream_ptr_after_chunk)
+ break;
CHECK_PIXEL_PTR(2 * byte_run);
for (j = 0; j < byte_run; j++) {
*((signed short*)(&pixels[pixel_ptr])) = bytestream2_get_le16(&g2);
diff --git a/libavcodec/flv.h b/libavcodec/flv.h
index 801e357e7a..561cfe0baa 100644
--- a/libavcodec/flv.h
+++ b/libavcodec/flv.h
@@ -1,20 +1,20 @@
/*
* FLV specific private header.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,5 @@ void ff_flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, int run,
int last);
int ff_flv_decode_picture_header(MpegEncContext *s);
-void ff_flv2_decode_ac_esc(GetBitContext *gb, int *level, int *run, int *last);
#endif /* AVCODEC_FLV_H */
diff --git a/libavcodec/flvdec.c b/libavcodec/flvdec.c
index 0a6f268579..5b2bed5d94 100644
--- a/libavcodec/flvdec.c
+++ b/libavcodec/flvdec.c
@@ -1,20 +1,20 @@
/*
* FLV decoding.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,17 +24,6 @@
#include "h263.h"
#include "mpegvideo.h"
-void ff_flv2_decode_ac_esc(GetBitContext *gb, int *level, int *run, int *last)
-{
- int is11 = get_bits1(gb);
- *last = get_bits1(gb);
- *run = get_bits(gb, 6);
- if (is11)
- *level = get_sbits(gb, 11);
- else
- *level = get_sbits(gb, 7);
-}
-
int ff_flv_decode_picture_header(MpegEncContext *s)
{
int format, width, height;
@@ -42,12 +31,12 @@ int ff_flv_decode_picture_header(MpegEncContext *s)
/* picture header */
if (get_bits_long(&s->gb, 17) != 1) {
av_log(s->avctx, AV_LOG_ERROR, "Bad picture start code\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
format = get_bits(&s->gb, 5);
if (format != 0 && format != 1) {
av_log(s->avctx, AV_LOG_ERROR, "Bad picture format\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
s->h263_flv = format + 1;
s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */
@@ -86,7 +75,7 @@ int ff_flv_decode_picture_header(MpegEncContext *s)
break;
}
if (av_image_check_size(width, height, 0, s->avctx))
- return -1;
+ return AVERROR(EINVAL);
s->width = width;
s->height = height;
@@ -104,10 +93,14 @@ int ff_flv_decode_picture_header(MpegEncContext *s)
s->h263_long_vectors = 0;
/* PEI */
- while (get_bits1(&s->gb) != 0)
- skip_bits(&s->gb, 8);
+ if (skip_1stop_8data_bits(&s->gb) < 0)
+ return AVERROR_INVALIDDATA;
+
s->f_code = 1;
+ if (s->ehc_mode)
+ s->avctx->sample_aspect_ratio= (AVRational){1,2};
+
if (s->avctx->debug & FF_DEBUG_PICT_INFO) {
av_log(s->avctx, AV_LOG_DEBUG, "%c esc_type:%d, qp:%d num:%d\n",
s->droppable ? 'D' : av_get_picture_type_char(s->pict_type),
@@ -129,6 +122,7 @@ AVCodec ff_flv_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE },
};
diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c
index e14a1056e9..070b528df3 100644
--- a/libavcodec/flvenc.c
+++ b/libavcodec/flvenc.c
@@ -1,20 +1,20 @@
/*
* FLV Encoding specific code.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/fmtconvert.c b/libavcodec/fmtconvert.c
index 2dff704aa2..e6fc509a96 100644
--- a/libavcodec/fmtconvert.c
+++ b/libavcodec/fmtconvert.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,4 +49,36 @@ av_cold void ff_fmt_convert_init(FmtConvertContext *c, AVCodecContext *avctx)
if (ARCH_ARM) ff_fmt_convert_init_arm(c, avctx);
if (ARCH_PPC) ff_fmt_convert_init_ppc(c, avctx);
if (ARCH_X86) ff_fmt_convert_init_x86(c, avctx);
+ if (HAVE_MIPSFPU) ff_fmt_convert_init_mips(c);
+}
+
+/* ffdshow custom code */
+void float_interleave(float *dst, const float **src, long len, int channels)
+{
+ int i,j,c;
+ if(channels==2){
+ for(i=0; i<len; i++){
+ dst[2*i] = src[0][i] / 32768.0f;
+ dst[2*i+1] = src[1][i] / 32768.0f;
+ }
+ }else{
+ for(c=0; c<channels; c++)
+ for(i=0, j=c; i<len; i++, j+=channels)
+ dst[j] = src[c][i] / 32768.0f;
+ }
+}
+
+void float_interleave_noscale(float *dst, const float **src, long len, int channels)
+{
+ int i,j,c;
+ if(channels==2){
+ for(i=0; i<len; i++){
+ dst[2*i] = src[0][i];
+ dst[2*i+1] = src[1][i];
+ }
+ }else{
+ for(c=0; c<channels; c++)
+ for(i=0, j=c; i<len; i++, j+=channels)
+ dst[j] = src[c][i];
+ }
}
diff --git a/libavcodec/fmtconvert.h b/libavcodec/fmtconvert.h
index 7de890bd6a..401ac3a1fc 100644
--- a/libavcodec/fmtconvert.h
+++ b/libavcodec/fmtconvert.h
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,5 +61,10 @@ void ff_fmt_convert_init(FmtConvertContext *c, AVCodecContext *avctx);
void ff_fmt_convert_init_arm(FmtConvertContext *c, AVCodecContext *avctx);
void ff_fmt_convert_init_ppc(FmtConvertContext *c, AVCodecContext *avctx);
void ff_fmt_convert_init_x86(FmtConvertContext *c, AVCodecContext *avctx);
+void ff_fmt_convert_init_mips(FmtConvertContext *c);
+
+/* ffdshow custom code */
+void float_interleave(float *dst, const float **src, long len, int channels);
+void float_interleave_noscale(float *dst, const float **src, long len, int channels);
#endif /* AVCODEC_FMTCONVERT_H */
diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c
new file mode 100644
index 0000000000..9a49fea527
--- /dev/null
+++ b/libavcodec/frame_thread_encoder.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "frame_thread_encoder.h"
+
+#include "libavutil/fifo.h"
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "thread.h"
+
+#if HAVE_PTHREADS
+#include <pthread.h>
+#elif HAVE_W32THREADS
+#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
+#endif
+
+#define MAX_THREADS 64
+#define BUFFER_SIZE (2*MAX_THREADS)
+
+typedef struct{
+ void *indata;
+ void *outdata;
+ int64_t return_code;
+ unsigned index;
+} Task;
+
+typedef struct{
+ AVCodecContext *parent_avctx;
+ pthread_mutex_t buffer_mutex;
+
+ AVFifoBuffer *task_fifo;
+ pthread_mutex_t task_fifo_mutex;
+ pthread_cond_t task_fifo_cond;
+
+ Task finished_tasks[BUFFER_SIZE];
+ pthread_mutex_t finished_task_mutex;
+ pthread_cond_t finished_task_cond;
+
+ unsigned task_index;
+ unsigned finished_task_index;
+
+ pthread_t worker[MAX_THREADS];
+ int exit;
+} ThreadContext;
+
+static void * attribute_align_arg worker(void *v){
+ AVCodecContext *avctx = v;
+ ThreadContext *c = avctx->internal->frame_thread_encoder;
+ AVPacket *pkt = NULL;
+
+ while(!c->exit){
+ int got_packet, ret;
+ AVFrame *frame;
+ Task task;
+
+ if(!pkt) pkt= av_mallocz(sizeof(*pkt));
+ if(!pkt) continue;
+ av_init_packet(pkt);
+
+ pthread_mutex_lock(&c->task_fifo_mutex);
+ while (av_fifo_size(c->task_fifo) <= 0 || c->exit) {
+ if(c->exit){
+ pthread_mutex_unlock(&c->task_fifo_mutex);
+ goto end;
+ }
+ pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex);
+ }
+ av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL);
+ pthread_mutex_unlock(&c->task_fifo_mutex);
+ frame = task.indata;
+
+ ret = avcodec_encode_video2(avctx, pkt, frame, &got_packet);
+ pthread_mutex_lock(&c->buffer_mutex);
+ av_frame_unref(frame);
+ pthread_mutex_unlock(&c->buffer_mutex);
+ av_frame_free(&frame);
+ if(got_packet) {
+ av_dup_packet(pkt);
+ } else {
+ pkt->data = NULL;
+ pkt->size = 0;
+ }
+ pthread_mutex_lock(&c->finished_task_mutex);
+ c->finished_tasks[task.index].outdata = pkt; pkt = NULL;
+ c->finished_tasks[task.index].return_code = ret;
+ pthread_cond_signal(&c->finished_task_cond);
+ pthread_mutex_unlock(&c->finished_task_mutex);
+ }
+end:
+ av_free(pkt);
+ pthread_mutex_lock(&c->buffer_mutex);
+ avcodec_close(avctx);
+ pthread_mutex_unlock(&c->buffer_mutex);
+ av_freep(&avctx);
+ return NULL;
+}
+
+int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){
+ int i=0;
+ ThreadContext *c;
+
+
+ if( !(avctx->thread_type & FF_THREAD_FRAME)
+ || !(avctx->codec->capabilities & CODEC_CAP_INTRA_ONLY))
+ return 0;
+
+ if( !avctx->thread_count
+ && avctx->codec_id == AV_CODEC_ID_MJPEG
+ && !(avctx->flags & CODEC_FLAG_QSCALE)) {
+ av_log(avctx, AV_LOG_DEBUG,
+ "Forcing thread count to 1 for MJPEG encoding, use -thread_type slice "
+ "or a constant quantizer if you want to use multiple cpu cores\n");
+ avctx->thread_count = 1;
+ }
+ if( avctx->thread_count > 1
+ && avctx->codec_id == AV_CODEC_ID_MJPEG
+ && !(avctx->flags & CODEC_FLAG_QSCALE))
+ av_log(avctx, AV_LOG_WARNING,
+ "MJPEG CBR encoding works badly with frame multi-threading, consider "
+ "using -threads 1, -thread_type slice or a constant quantizer.\n");
+
+ if (avctx->codec_id == AV_CODEC_ID_HUFFYUV ||
+ avctx->codec_id == AV_CODEC_ID_FFVHUFF) {
+ int warn = 0;
+ if (avctx->flags & CODEC_FLAG_PASS1)
+ warn = 1;
+ else if(avctx->context_model > 0) {
+ AVDictionaryEntry *t = av_dict_get(options, "non_deterministic",
+ NULL, AV_DICT_MATCH_CASE);
+ warn = !t || !t->value || !atoi(t->value) ? 1 : 0;
+ }
+ // huffyuv does not support these with multiple frame threads currently
+ if (warn) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n");
+ avctx->thread_count = 1;
+ }
+ }
+
+ if(!avctx->thread_count) {
+ avctx->thread_count = av_cpu_count();
+ avctx->thread_count = FFMIN(avctx->thread_count, MAX_THREADS);
+ }
+
+ if(avctx->thread_count <= 1)
+ return 0;
+
+ if(avctx->thread_count > MAX_THREADS)
+ return AVERROR(EINVAL);
+
+ av_assert0(!avctx->internal->frame_thread_encoder);
+ c = avctx->internal->frame_thread_encoder = av_mallocz(sizeof(ThreadContext));
+ if(!c)
+ return AVERROR(ENOMEM);
+
+ c->parent_avctx = avctx;
+
+ c->task_fifo = av_fifo_alloc_array(BUFFER_SIZE, sizeof(Task));
+ if(!c->task_fifo)
+ goto fail;
+
+ pthread_mutex_init(&c->task_fifo_mutex, NULL);
+ pthread_mutex_init(&c->finished_task_mutex, NULL);
+ pthread_mutex_init(&c->buffer_mutex, NULL);
+ pthread_cond_init(&c->task_fifo_cond, NULL);
+ pthread_cond_init(&c->finished_task_cond, NULL);
+
+ for(i=0; i<avctx->thread_count ; i++){
+ AVDictionary *tmp = NULL;
+ void *tmpv;
+ AVCodecContext *thread_avctx = avcodec_alloc_context3(avctx->codec);
+ if(!thread_avctx)
+ goto fail;
+ tmpv = thread_avctx->priv_data;
+ *thread_avctx = *avctx;
+ thread_avctx->priv_data = tmpv;
+ thread_avctx->internal = NULL;
+ memcpy(thread_avctx->priv_data, avctx->priv_data, avctx->codec->priv_data_size);
+ thread_avctx->thread_count = 1;
+ thread_avctx->active_thread_type &= ~FF_THREAD_FRAME;
+
+ av_dict_copy(&tmp, options, 0);
+ av_dict_set(&tmp, "threads", "1", 0);
+ if(avcodec_open2(thread_avctx, avctx->codec, &tmp) < 0) {
+ av_dict_free(&tmp);
+ goto fail;
+ }
+ av_dict_free(&tmp);
+ av_assert0(!thread_avctx->internal->frame_thread_encoder);
+ thread_avctx->internal->frame_thread_encoder = c;
+ if(pthread_create(&c->worker[i], NULL, worker, thread_avctx)) {
+ goto fail;
+ }
+ }
+
+ avctx->active_thread_type = FF_THREAD_FRAME;
+
+ return 0;
+fail:
+ avctx->thread_count = i;
+ av_log(avctx, AV_LOG_ERROR, "ff_frame_thread_encoder_init failed\n");
+ ff_frame_thread_encoder_free(avctx);
+ return -1;
+}
+
+void ff_frame_thread_encoder_free(AVCodecContext *avctx){
+ int i;
+ ThreadContext *c= avctx->internal->frame_thread_encoder;
+
+ pthread_mutex_lock(&c->task_fifo_mutex);
+ c->exit = 1;
+ pthread_cond_broadcast(&c->task_fifo_cond);
+ pthread_mutex_unlock(&c->task_fifo_mutex);
+
+ for (i=0; i<avctx->thread_count; i++) {
+ pthread_join(c->worker[i], NULL);
+ }
+
+ pthread_mutex_destroy(&c->task_fifo_mutex);
+ pthread_mutex_destroy(&c->finished_task_mutex);
+ pthread_mutex_destroy(&c->buffer_mutex);
+ pthread_cond_destroy(&c->task_fifo_cond);
+ pthread_cond_destroy(&c->finished_task_cond);
+ av_fifo_freep(&c->task_fifo);
+ av_freep(&avctx->internal->frame_thread_encoder);
+}
+
+int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr){
+ ThreadContext *c = avctx->internal->frame_thread_encoder;
+ Task task;
+ int ret;
+
+ av_assert1(!*got_packet_ptr);
+
+ if(frame){
+ AVFrame *new = av_frame_alloc();
+ if(!new)
+ return AVERROR(ENOMEM);
+ ret = av_frame_ref(new, frame);
+ if(ret < 0) {
+ av_frame_free(&new);
+ return ret;
+ }
+
+ task.index = c->task_index;
+ task.indata = (void*)new;
+ pthread_mutex_lock(&c->task_fifo_mutex);
+ av_fifo_generic_write(c->task_fifo, &task, sizeof(task), NULL);
+ pthread_cond_signal(&c->task_fifo_cond);
+ pthread_mutex_unlock(&c->task_fifo_mutex);
+
+ c->task_index = (c->task_index+1) % BUFFER_SIZE;
+
+ if(!c->finished_tasks[c->finished_task_index].outdata && (c->task_index - c->finished_task_index) % BUFFER_SIZE <= avctx->thread_count)
+ return 0;
+ }
+
+ if(c->task_index == c->finished_task_index)
+ return 0;
+
+ pthread_mutex_lock(&c->finished_task_mutex);
+ while (!c->finished_tasks[c->finished_task_index].outdata) {
+ pthread_cond_wait(&c->finished_task_cond, &c->finished_task_mutex);
+ }
+ task = c->finished_tasks[c->finished_task_index];
+ *pkt = *(AVPacket*)(task.outdata);
+ if(pkt->data)
+ *got_packet_ptr = 1;
+ av_freep(&c->finished_tasks[c->finished_task_index].outdata);
+ c->finished_task_index = (c->finished_task_index+1) % BUFFER_SIZE;
+ pthread_mutex_unlock(&c->finished_task_mutex);
+
+ return task.return_code;
+}
diff --git a/libavcodec/frame_thread_encoder.h b/libavcodec/frame_thread_encoder.h
new file mode 100644
index 0000000000..1da0ce1808
--- /dev/null
+++ b/libavcodec/frame_thread_encoder.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+
+int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options);
+void ff_frame_thread_encoder_free(AVCodecContext *avctx);
+int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr);
+
diff --git a/libavcodec/fraps.c b/libavcodec/fraps.c
index 4b4b02cc51..c49866e7e2 100644
--- a/libavcodec/fraps.c
+++ b/libavcodec/fraps.c
@@ -3,20 +3,20 @@
* Copyright (c) 2005 Roine Gustafsson
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,8 +37,10 @@
#include "bytestream.h"
#include "bswapdsp.h"
#include "internal.h"
+#include "thread.h"
#define FPS_TAG MKTAG('F', 'P', 'S', 'x')
+#define VLC_BITS 11
/**
* local variable storage
@@ -46,7 +48,6 @@
typedef struct FrapsContext {
AVCodecContext *avctx;
BswapDSPContext bdsp;
- AVFrame *frame;
uint8_t *tmpbuf;
int tmpbuf_size;
} FrapsContext;
@@ -61,15 +62,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
{
FrapsContext * const s = avctx->priv_data;
- avctx->pix_fmt = AV_PIX_FMT_NONE; /* set in decode_frame */
-
s->avctx = avctx;
s->tmpbuf = NULL;
- s->frame = av_frame_alloc();
- if (!s->frame)
- return AVERROR(ENOMEM);
-
ff_bswapdsp_init(&s->bdsp);
return 0;
@@ -100,7 +95,8 @@ static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w,
for (i = 0; i < 256; i++)
nodes[i].count = bytestream_get_le32(&src);
size -= 1024;
- if ((ret = ff_huff_build_tree(s->avctx, &vlc, 256, nodes, huff_cmp,
+ if ((ret = ff_huff_build_tree(s->avctx, &vlc, 256, VLC_BITS,
+ nodes, huff_cmp,
FF_HUFFMAN_FLAG_ZERO_COUNT)) < 0)
return ret;
/* we have built Huffman table and are ready to decode plane */
@@ -112,7 +108,7 @@ static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w,
init_get_bits(&gb, s->tmpbuf, size * 8);
for (j = 0; j < h; j++) {
for (i = 0; i < w*step; i += step) {
- dst[i] = get_vlc2(&gb, vlc.table, 9, 3);
+ dst[i] = get_vlc2(&gb, vlc.table, VLC_BITS, 3);
/* lines are stored as deltas between previous lines
* and we need to add 0x80 to the first lines of chroma planes
*/
@@ -138,17 +134,17 @@ static int decode_frame(AVCodecContext *avctx,
FrapsContext * const s = avctx->priv_data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
- AVFrame *frame = data;
- AVFrame * const f = s->frame;
+ ThreadFrame frame = { .f = data };
+ AVFrame * const f = data;
uint32_t header;
unsigned int version,header_size;
unsigned int x, y;
const uint32_t *buf32;
uint32_t *luma1,*luma2,*cb,*cr;
uint32_t offs[4];
- int i, j, ret, is_chroma, planes;
- enum AVPixelFormat pix_fmt;
- int prev_pic_bit, expected_size;
+ int i, j, ret, is_chroma;
+ const int planes = 3;
+ uint8_t *out;
if (buf_size < 4) {
av_log(avctx, AV_LOG_ERROR, "Packet is too short\n");
@@ -158,7 +154,6 @@ static int decode_frame(AVCodecContext *avctx,
header = AV_RL32(buf);
version = header & 0xff;
header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */
- prev_pic_bit = header & (1U << 31); /* bit 31 means same as previous pic */
if (version > 5) {
av_log(avctx, AV_LOG_ERROR,
@@ -167,89 +162,92 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_PATCHWELCOME;
}
- buf += 4;
- if (header_size == 8)
- buf += 4;
+ buf += header_size;
- pix_fmt = version & 1 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P;
- if (avctx->pix_fmt != pix_fmt && f->data[0]) {
- av_frame_unref(f);
+ if (version < 2) {
+ unsigned needed_size = avctx->width * avctx->height * 3;
+ if (version == 0) needed_size /= 2;
+ needed_size += header_size;
+ /* bit 31 means same as previous pic */
+ if (header & (1U<<31)) {
+ *got_frame = 0;
+ return buf_size;
+ }
+ if (buf_size != needed_size) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid frame length %d (should be %d)\n",
+ buf_size, needed_size);
+ return AVERROR_INVALIDDATA;
+ }
+ } else {
+ /* skip frame */
+ if (buf_size == 8) {
+ *got_frame = 0;
+ return buf_size;
+ }
+ if (AV_RL32(buf) != FPS_TAG || buf_size < planes*1024 + 24) {
+ av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < planes; i++) {
+ offs[i] = AV_RL32(buf + 4 + i * 4);
+ if (offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) {
+ av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ offs[planes] = buf_size - header_size;
+ for (i = 0; i < planes; i++) {
+ av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024);
+ if (!s->tmpbuf)
+ return AVERROR(ENOMEM);
+ }
}
- avctx->pix_fmt = pix_fmt;
+
+ f->pict_type = AV_PICTURE_TYPE_I;
+ f->key_frame = 1;
+
+ avctx->pix_fmt = version & 1 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P;
avctx->color_range = version & 1 ? AVCOL_RANGE_UNSPECIFIED
: AVCOL_RANGE_JPEG;
+ avctx->colorspace = version & 1 ? AVCOL_SPC_UNSPECIFIED : AVCOL_SPC_BT709;
- expected_size = header_size;
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
switch (version) {
case 0:
default:
/* Fraps v0 is a reordered YUV420 */
- if (!prev_pic_bit)
- expected_size += avctx->width * avctx->height * 3 / 2;
- if (buf_size != expected_size) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid frame length %d (should be %d)\n",
- buf_size, expected_size);
- return AVERROR_INVALIDDATA;
- }
-
if (((avctx->width % 8) != 0) || ((avctx->height % 2) != 0)) {
av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n",
avctx->width, avctx->height);
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_reget_buffer(avctx, f)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
- return ret;
- }
- f->pict_type = prev_pic_bit ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
- f->key_frame = f->pict_type == AV_PICTURE_TYPE_I;
-
- if (f->pict_type == AV_PICTURE_TYPE_I) {
- buf32 = (const uint32_t*)buf;
- for (y = 0; y < avctx->height / 2; y++) {
- luma1 = (uint32_t*)&f->data[0][ y * 2 * f->linesize[0]];
- luma2 = (uint32_t*)&f->data[0][(y * 2 + 1) * f->linesize[0]];
- cr = (uint32_t*)&f->data[1][ y * f->linesize[1]];
- cb = (uint32_t*)&f->data[2][ y * f->linesize[2]];
- for (x = 0; x < avctx->width; x += 8) {
- *(luma1++) = *(buf32++);
- *(luma1++) = *(buf32++);
- *(luma2++) = *(buf32++);
- *(luma2++) = *(buf32++);
- *(cr++) = *(buf32++);
- *(cb++) = *(buf32++);
- }
+ buf32 = (const uint32_t*)buf;
+ for (y = 0; y < avctx->height / 2; y++) {
+ luma1 = (uint32_t*)&f->data[0][ y * 2 * f->linesize[0] ];
+ luma2 = (uint32_t*)&f->data[0][ (y * 2 + 1) * f->linesize[0] ];
+ cr = (uint32_t*)&f->data[1][ y * f->linesize[1] ];
+ cb = (uint32_t*)&f->data[2][ y * f->linesize[2] ];
+ for (x = 0; x < avctx->width; x += 8) {
+ *luma1++ = *buf32++;
+ *luma1++ = *buf32++;
+ *luma2++ = *buf32++;
+ *luma2++ = *buf32++;
+ *cr++ = *buf32++;
+ *cb++ = *buf32++;
}
}
break;
case 1:
/* Fraps v1 is an upside-down BGR24 */
- if (!prev_pic_bit)
- expected_size += avctx->width * avctx->height * 3;
- if (buf_size != expected_size) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid frame length %d (should be %d)\n",
- buf_size, expected_size);
- return AVERROR_INVALIDDATA;
- }
-
- if ((ret = ff_reget_buffer(avctx, f)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
- return ret;
- }
- f->pict_type = prev_pic_bit ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
- f->key_frame = f->pict_type == AV_PICTURE_TYPE_I;
-
- if (f->pict_type == AV_PICTURE_TYPE_I) {
for (y = 0; y<avctx->height; y++)
memcpy(&f->data[0][(avctx->height - y - 1) * f->linesize[0]],
&buf[y * avctx->width * 3],
3 * avctx->width);
- }
break;
case 2:
@@ -258,37 +256,8 @@ static int decode_frame(AVCodecContext *avctx,
* Fraps v2 is Huffman-coded YUV420 planes
* Fraps v4 is virtually the same
*/
- planes = 3;
- if ((ret = ff_reget_buffer(avctx, f)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
- return ret;
- }
- /* skip frame */
- if (buf_size == 8) {
- f->pict_type = AV_PICTURE_TYPE_P;
- f->key_frame = 0;
- break;
- }
- f->pict_type = AV_PICTURE_TYPE_I;
- f->key_frame = 1;
- if ((AV_RL32(buf) != FPS_TAG) || (buf_size < (planes * 1024 + 24))) {
- av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
- return AVERROR_INVALIDDATA;
- }
- for (i = 0; i < planes; i++) {
- offs[i] = AV_RL32(buf + 4 + i * 4);
- if (offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) {
- av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i);
- return AVERROR_INVALIDDATA;
- }
- }
- offs[planes] = buf_size;
for (i = 0; i < planes; i++) {
is_chroma = !!i;
- av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size,
- offs[i + 1] - offs[i] - 1024);
- if (!s->tmpbuf)
- return AVERROR(ENOMEM);
if ((ret = fraps2_decode_plane(s, f->data[i], f->linesize[i],
avctx->width >> is_chroma,
avctx->height >> is_chroma,
@@ -302,36 +271,7 @@ static int decode_frame(AVCodecContext *avctx,
case 3:
case 5:
/* Virtually the same as version 4, but is for RGB24 */
- planes = 3;
- if ((ret = ff_reget_buffer(avctx, f)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
- return ret;
- }
- /* skip frame */
- if (buf_size == 8) {
- f->pict_type = AV_PICTURE_TYPE_P;
- f->key_frame = 0;
- break;
- }
- f->pict_type = AV_PICTURE_TYPE_I;
- f->key_frame = 1;
- if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) {
- av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
- return AVERROR_INVALIDDATA;
- }
- for (i = 0; i < planes; i++) {
- offs[i] = AV_RL32(buf + 4 + i * 4);
- if (offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) {
- av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i);
- return AVERROR_INVALIDDATA;
- }
- }
- offs[planes] = buf_size;
for (i = 0; i < planes; i++) {
- av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size,
- offs[i + 1] - offs[i] - 1024);
- if (!s->tmpbuf)
- return AVERROR(ENOMEM);
if ((ret = fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)),
-f->linesize[0], avctx->width, avctx->height,
buf + offs[i], offs[i + 1] - offs[i], 0, 3)) < 0) {
@@ -339,18 +279,20 @@ static int decode_frame(AVCodecContext *avctx,
return ret;
}
}
+ out = f->data[0];
// convert pseudo-YUV into real RGB
for (j = 0; j < avctx->height; j++) {
- for (i = 0; i < avctx->width; i++) {
- f->data[0][0 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]];
- f->data[0][2 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]];
+ uint8_t *line_end = out + 3*avctx->width;
+ while (out < line_end) {
+ out[0] += out[1];
+ out[2] += out[1];
+ out += 3;
}
+ out += f->linesize[0] - 3*avctx->width;
}
break;
}
- if ((ret = av_frame_ref(frame, f)) < 0)
- return ret;
*got_frame = 1;
return buf_size;
@@ -366,8 +308,6 @@ static av_cold int decode_end(AVCodecContext *avctx)
{
FrapsContext *s = (FrapsContext*)avctx->priv_data;
- av_frame_free(&s->frame);
-
av_freep(&s->tmpbuf);
return 0;
}
@@ -382,5 +322,5 @@ AVCodec ff_fraps_decoder = {
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
};
diff --git a/libavcodec/frwu.c b/libavcodec/frwu.c
index 568b94f81b..c778dbde1a 100644
--- a/libavcodec/frwu.c
+++ b/libavcodec/frwu.c
@@ -3,26 +3,32 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
+#include "libavutil/opt.h"
+
+typedef struct {
+ AVClass *av_class;
+ int change_field_order;
+} FRWUContext;
static av_cold int decode_init(AVCodecContext *avctx)
{
@@ -38,6 +44,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
+ FRWUContext *s = avctx->priv_data;
int field, ret;
AVFrame *pic = data;
const uint8_t *buf = avpkt->data;
@@ -52,15 +59,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
return ret;
- }
pic->pict_type = AV_PICTURE_TYPE_I;
pic->key_frame = 1;
- pic->interlaced_frame = 1;
- pic->top_field_first = 1;
for (field = 0; field < 2; field++) {
int i;
@@ -79,9 +82,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_log(avctx, AV_LOG_ERROR, "Packet is too small, need %i, have %i\n", field_size, (int)(buf_end - buf));
return AVERROR_INVALIDDATA;
}
- if (field)
+ if (field ^ s->change_field_order) {
dst += pic->linesize[0];
+ } else if (s->change_field_order) {
+ dst += 2 * pic->linesize[0];
+ }
for (i = 0; i < field_h; i++) {
+ if (s->change_field_order && field && i == field_h - 1)
+ dst = pic->data[0];
memcpy(dst, buf, avctx->width * 2);
buf += avctx->width * 2;
dst += pic->linesize[0] << 1;
@@ -94,12 +102,27 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return avpkt->size;
}
+static const AVOption frwu_options[] = {
+ {"change_field_order", "Change field order", offsetof(FRWUContext, change_field_order), FF_OPT_TYPE_INT,
+ {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM},
+ {NULL}
+};
+
+static const AVClass frwu_class = {
+ .class_name = "frwu Decoder",
+ .item_name = av_default_item_name,
+ .option = frwu_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_frwu_decoder = {
.name = "frwu",
.long_name = NULL_IF_CONFIG_SMALL("Forward Uncompressed"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_FRWU,
+ .priv_data_size = sizeof(FRWUContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .priv_class = &frwu_class,
};
diff --git a/libavcodec/g2meet.c b/libavcodec/g2meet.c
index b3d2bc4aba..6482483444 100644
--- a/libavcodec/g2meet.c
+++ b/libavcodec/g2meet.c
@@ -2,20 +2,20 @@
* Go2Webinar decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -253,7 +253,8 @@ static int jpg_decode_data(JPGContext *c, int width, int height,
return ret;
jpg_unescape(src, src_size, c->buf, &unesc_size);
memset(c->buf + unesc_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- init_get_bits(&gb, c->buf, unesc_size * 8);
+ if((ret = init_get_bits8(&gb, c->buf, unesc_size)) < 0)
+ return ret;
width = FFALIGN(width, 16);
mb_w = width >> 4;
@@ -317,7 +318,7 @@ static int jpg_decode_data(JPGContext *c, int width, int height,
return 0;
}
-static void kempf_restore_buf(const uint8_t *src, int len,
+static int kempf_restore_buf(const uint8_t *src, int len,
uint8_t *dst, int stride,
const uint8_t *jpeg_tile, int tile_stride,
int width, int height,
@@ -325,8 +326,10 @@ static void kempf_restore_buf(const uint8_t *src, int len,
{
GetBitContext gb;
int i, j, nb, col;
+ int ret;
- init_get_bits(&gb, src, len * 8);
+ if ((ret = init_get_bits8(&gb, src, len)) < 0)
+ return ret;
if (npal <= 2) nb = 1;
else if (npal <= 4) nb = 2;
@@ -344,6 +347,8 @@ static void kempf_restore_buf(const uint8_t *src, int len,
memcpy(dst + i * 3, jpeg_tile + i * 3, 3);
}
}
+
+ return 0;
}
static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y,
@@ -387,6 +392,8 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y,
src += 3;
}
npal = *src++ + 1;
+ if (src_end - src < npal * 3)
+ return AVERROR_INVALIDDATA;
memcpy(pal, src, npal * 3);
src += npal * 3;
if (sub_type != 2) {
@@ -403,7 +410,7 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y,
zsize = (src[0] << 8) | src[1];
src += 2;
- if (src_end - src < zsize)
+ if (src_end - src < zsize + (sub_type != 2))
return AVERROR_INVALIDDATA;
ret = uncompress(c->kempf_buf, &dlen, src, zsize);
@@ -425,6 +432,8 @@ static int kempf_decode_tile(G2MContext *c, int tile_x, int tile_y,
for (i = 0; i < (FFALIGN(height, 16) >> 4); i++) {
for (j = 0; j < (FFALIGN(width, 16) >> 4); j++) {
if (!bits) {
+ if (src >= src_end)
+ return AVERROR_INVALIDDATA;
bitbuf = *src++;
bits = 8;
}
@@ -458,17 +467,17 @@ static int g2m_init_buffers(G2MContext *c)
int aligned_height;
if (!c->framebuf || c->old_width < c->width || c->old_height < c->height) {
- c->framebuf_stride = FFALIGN(c->width * 3, 16);
- aligned_height = FFALIGN(c->height, 16);
+ c->framebuf_stride = FFALIGN(c->width + 15, 16) * 3;
+ aligned_height = c->height + 15;
av_free(c->framebuf);
- c->framebuf = av_mallocz(c->framebuf_stride * aligned_height);
+ c->framebuf = av_mallocz_array(c->framebuf_stride, aligned_height);
if (!c->framebuf)
return AVERROR(ENOMEM);
}
if (!c->synth_tile || !c->jpeg_tile ||
c->old_tile_w < c->tile_width ||
c->old_tile_h < c->tile_height) {
- c->tile_stride = FFALIGN(c->tile_width * 3, 16);
+ c->tile_stride = FFALIGN(c->tile_width, 16) * 3;
aligned_height = FFALIGN(c->tile_height, 16);
av_free(c->synth_tile);
av_free(c->jpeg_tile);
@@ -504,7 +513,7 @@ static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
cursor_hot_y = bytestream2_get_byte(gb);
cursor_fmt = bytestream2_get_byte(gb);
- cursor_stride = FFALIGN(cursor_w, 32) * 4;
+ cursor_stride = FFALIGN(cursor_w, cursor_fmt==1 ? 32 : 1) * 4;
if (cursor_w < 1 || cursor_w > 256 ||
cursor_h < 1 || cursor_h > 256) {
@@ -554,7 +563,6 @@ static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
bits <<= 1;
}
}
- dst += c->cursor_stride - c->cursor_w * 4;
}
dst = c->cursor;
@@ -586,7 +594,6 @@ static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
bits <<= 1;
}
}
- dst += c->cursor_stride - c->cursor_w * 4;
}
break;
case 32: // full colour
@@ -600,7 +607,6 @@ static int g2m_load_cursor(AVCodecContext *avctx, G2MContext *c,
*dst++ = val >> 16;
*dst++ = val >> 24;
}
- dst += c->cursor_stride - c->cursor_w * 4;
}
break;
default:
@@ -706,6 +712,7 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
}
switch (chunk_type) {
case DISPLAY_INFO:
+ got_header =
c->got_header = 0;
if (chunk_size < 21) {
av_log(avctx, AV_LOG_ERROR, "Invalid display info size %"PRIu32"\n",
@@ -725,19 +732,22 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
if (c->width != avctx->width || c->height != avctx->height) {
ret = ff_set_dimensions(avctx, c->width, c->height);
if (ret < 0)
- return ret;
+ goto header_fail;
}
c->compression = bytestream2_get_be32(&bc);
if (c->compression != 2 && c->compression != 3) {
av_log(avctx, AV_LOG_ERROR,
"Unknown compression method %d\n",
c->compression);
- return AVERROR_PATCHWELCOME;
+ ret = AVERROR_PATCHWELCOME;
+ goto header_fail;
}
c->tile_width = bytestream2_get_be32(&bc);
c->tile_height = bytestream2_get_be32(&bc);
- if (!c->tile_width || !c->tile_height ||
- ((c->tile_width | c->tile_height) & 0xF)) {
+ if (c->tile_width <= 0 || c->tile_height <= 0 ||
+ ((c->tile_width | c->tile_height) & 0xF) ||
+ c->tile_width * 4LL * c->tile_height >= INT_MAX
+ ) {
av_log(avctx, AV_LOG_ERROR,
"Invalid tile dimensions %dx%d\n",
c->tile_width, c->tile_height);
@@ -752,7 +762,8 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
(chunk_size - 21) < 16) {
av_log(avctx, AV_LOG_ERROR,
"Display info: missing bitmasks!\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto header_fail;
}
r_mask = bytestream2_get_be32(&bc);
g_mask = bytestream2_get_be32(&bc);
@@ -761,11 +772,13 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR,
"Invalid or unsupported bitmasks: R=%"PRIX32", G=%"PRIX32", B=%"PRIX32"\n",
r_mask, g_mask, b_mask);
- return AVERROR_PATCHWELCOME;
+ ret = AVERROR_PATCHWELCOME;
+ goto header_fail;
}
} else {
avpriv_request_sample(avctx, "bpp=%d", c->bpp);
- return AVERROR_PATCHWELCOME;
+ ret = AVERROR_PATCHWELCOME;
+ goto header_fail;
}
if (g2m_init_buffers(c)) {
ret = AVERROR(ENOMEM);
@@ -841,11 +854,9 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data,
if (got_header)
c->got_header = 1;
- if (c->width && c->height) {
- if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if (c->width && c->height && c->framebuf) {
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
return ret;
- }
pic->key_frame = got_header;
pic->pict_type = got_header ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
diff --git a/libavcodec/g722.c b/libavcodec/g722.c
index 830877e336..ee3b85f845 100644
--- a/libavcodec/g722.c
+++ b/libavcodec/g722.c
@@ -7,20 +7,20 @@
* Copyright (c) 2009 Kenan Gillet
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/g722.h b/libavcodec/g722.h
index 483017018b..25676a326e 100644
--- a/libavcodec/g722.h
+++ b/libavcodec/g722.h
@@ -5,20 +5,20 @@
* Copyright (c) 2009 Kenan Gillet
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/g722dec.c b/libavcodec/g722dec.c
index a1b3aa78c9..22e90a3079 100644
--- a/libavcodec/g722dec.c
+++ b/libavcodec/g722dec.c
@@ -5,20 +5,20 @@
* Copyright (c) 2009 Kenan Gillet
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -79,7 +79,7 @@ static const int16_t low_inv_quant5[32] = {
587, 473, 370, 276, 190, 110, 35, -35
};
-static const int16_t *low_inv_quants[3] = { ff_g722_low_inv_quant6,
+static const int16_t * const low_inv_quants[3] = { ff_g722_low_inv_quant6,
low_inv_quant5,
ff_g722_low_inv_quant4 };
@@ -96,10 +96,8 @@ static int g722_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = avpkt->size * 2;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
out_buf = (int16_t *)frame->data[0];
init_get_bits(&gb, avpkt->data, avpkt->size * 8);
diff --git a/libavcodec/g722dsp.c b/libavcodec/g722dsp.c
index c7e41ff9c7..f1480536d0 100644
--- a/libavcodec/g722dsp.c
+++ b/libavcodec/g722dsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2015 Peter Meerwald <pmeerw@pmeerw.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,4 +71,6 @@ av_cold void ff_g722dsp_init(G722DSPContext *c)
if (ARCH_ARM)
ff_g722dsp_init_arm(c);
+ if (ARCH_X86)
+ ff_g722dsp_init_x86(c);
}
diff --git a/libavcodec/g722dsp.h b/libavcodec/g722dsp.h
index ecd6a47fcb..c956a1e161 100644
--- a/libavcodec/g722dsp.h
+++ b/libavcodec/g722dsp.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2015 Peter Meerwald <pmeerw@pmeerw.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,5 +29,6 @@ typedef struct G722DSPContext {
void ff_g722dsp_init(G722DSPContext *c);
void ff_g722dsp_init_arm(G722DSPContext *c);
+void ff_g722dsp_init_x86(G722DSPContext *c);
#endif /* AVCODEC_G722DSP_H */
diff --git a/libavcodec/g722enc.c b/libavcodec/g722enc.c
index 3943622137..38432f5006 100644
--- a/libavcodec/g722enc.c
+++ b/libavcodec/g722enc.c
@@ -5,20 +5,20 @@
* Copyright (c) 2009 Kenan Gillet
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
* G.722 ADPCM audio encoder
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "internal.h"
#include "g722.h"
@@ -74,9 +75,9 @@ static av_cold int g722_encode_init(AVCodecContext * avctx)
int max_paths = frontier * FREEZE_INTERVAL;
int i;
for (i = 0; i < 2; i++) {
- c->paths[i] = av_mallocz(max_paths * sizeof(**c->paths));
- c->node_buf[i] = av_mallocz(2 * frontier * sizeof(**c->node_buf));
- c->nodep_buf[i] = av_mallocz(2 * frontier * sizeof(**c->nodep_buf));
+ c->paths[i] = av_mallocz_array(max_paths, sizeof(**c->paths));
+ c->node_buf[i] = av_mallocz_array(frontier, 2 * sizeof(**c->node_buf));
+ c->nodep_buf[i] = av_mallocz_array(frontier, 2 * sizeof(**c->nodep_buf));
if (!c->paths[i] || !c->node_buf[i] || !c->nodep_buf[i]) {
ret = AVERROR(ENOMEM);
goto error;
@@ -238,7 +239,7 @@ static void g722_encode_trellis(G722Context *c, int trellis,
continue;\
if (heap_pos[index] < frontier) {\
pos = heap_pos[index]++;\
- assert(pathn[index] < FREEZE_INTERVAL * frontier);\
+ av_assert2(pathn[index] < FREEZE_INTERVAL * frontier);\
node = nodes_next[index][pos] = next[index]++;\
node->path = pathn[index]++;\
} else {\
@@ -357,10 +358,8 @@ static int g722_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
int nb_samples, out_size, ret;
out_size = (frame->nb_samples + 1) / 2;
- if ((ret = ff_alloc_packet(avpkt, out_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, out_size)) < 0)
return ret;
- }
nb_samples = frame->nb_samples - (frame->nb_samples & 1);
diff --git a/libavcodec/g723_1.c b/libavcodec/g723_1.c
index f3879bdbcd..66afd6af6a 100644
--- a/libavcodec/g723_1.c
+++ b/libavcodec/g723_1.c
@@ -3,20 +3,20 @@
* Copyright (c) 2006 Benjamin Larsson
* Copyright (c) 2010 Mohamed Naufal Basheer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,47 +33,12 @@
#include "get_bits.h"
#include "acelp_vectors.h"
#include "celp_filters.h"
+#include "celp_math.h"
#include "g723_1_data.h"
#include "internal.h"
#define CNG_RANDOM_SEED 12345
-/**
- * G723.1 frame types
- */
-enum FrameType {
- ACTIVE_FRAME, ///< Active speech
- SID_FRAME, ///< Silence Insertion Descriptor frame
- UNTRANSMITTED_FRAME
-};
-
-enum Rate {
- RATE_6300,
- RATE_5300
-};
-
-/**
- * G723.1 unpacked data subframe
- */
-typedef struct G723_1_Subframe {
- int ad_cb_lag; ///< adaptive codebook lag
- int ad_cb_gain;
- int dirac_train;
- int pulse_sign;
- int grid_index;
- int amp_index;
- int pulse_pos;
-} G723_1_Subframe;
-
-/**
- * Pitch postfilter parameters
- */
-typedef struct PPFParam {
- int index; ///< postfilter backward/forward lag
- int16_t opt_gain; ///< optimal gain
- int16_t sc_gain; ///< scaling gain
-} PPFParam;
-
typedef struct g723_1_context {
AVClass *class;
@@ -100,10 +65,21 @@ typedef struct g723_1_context {
int sid_gain;
int cur_gain;
int reflection_coef;
- int pf_gain;
+ int pf_gain; ///< formant postfilter
+ ///< gain scaling unit memory
int postfilter;
int16_t audio[FRAME_LEN + LPC_ORDER + PITCH_MAX + 4];
+ int16_t prev_data[HALF_FRAME_LEN];
+ int16_t prev_weight_sig[PITCH_MAX];
+
+
+ int16_t hpf_fir_mem; ///< highpass filter fir
+ int hpf_iir_mem; ///< and iir memories
+ int16_t perf_fir_mem[LPC_ORDER]; ///< perceptual filter fir
+ int16_t perf_iir_mem[LPC_ORDER]; ///< and iir memories
+
+ int16_t harmonic_mem[PITCH_MAX];
} G723_1_Context;
static av_cold int g723_1_decode_init(AVCodecContext *avctx)
@@ -113,7 +89,6 @@ static av_cold int g723_1_decode_init(AVCodecContext *avctx)
avctx->channel_layout = AV_CH_LAYOUT_MONO;
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
avctx->channels = 1;
- avctx->sample_rate = 8000;
p->pf_gain = 1 << 12;
memcpy(p->prev_lsp, dc_lsp, LPC_ORDER * sizeof(*p->prev_lsp));
@@ -197,13 +172,13 @@ static int unpack_bitstream(G723_1_Context *p, const uint8_t *buf,
}
}
- p->subframe[0].grid_index = get_bits(&gb, 1);
- p->subframe[1].grid_index = get_bits(&gb, 1);
- p->subframe[2].grid_index = get_bits(&gb, 1);
- p->subframe[3].grid_index = get_bits(&gb, 1);
+ p->subframe[0].grid_index = get_bits1(&gb);
+ p->subframe[1].grid_index = get_bits1(&gb);
+ p->subframe[2].grid_index = get_bits1(&gb);
+ p->subframe[3].grid_index = get_bits1(&gb);
if (p->cur_rate == RATE_6300) {
- skip_bits(&gb, 1); /* skip reserved bit */
+ skip_bits1(&gb); /* skip reserved bit */
/* Compute pulse_pos index using the 13-bit combined position index */
temp = get_bits(&gb, 13);
@@ -247,32 +222,27 @@ static int unpack_bitstream(G723_1_Context *p, const uint8_t *buf,
/**
* Bitexact implementation of sqrt(val/2).
*/
-static int16_t square_root(int val)
+static int16_t square_root(unsigned val)
{
- int16_t res = 0;
- int16_t exp = 0x4000;
- int i;
+ av_assert2(!(val & 0x80000000));
- for (i = 0; i < 14; i ++) {
- int res_exp = res + exp;
- if (val >= res_exp * res_exp << 1)
- res += exp;
- exp >>= 1;
- }
- return res;
+ return (ff_sqrt(val << 1) >> 1) & (~1);
}
/**
* Calculate the number of left-shifts required for normalizing the input.
*
* @param num input number
- * @param width width of the input, 16 bits(0) / 32 bits(1)
+ * @param width width of the input, 15 or 31 bits
*/
static int normalize_bits(int num, int width)
{
return width - av_log2(num) - 1;
}
+#define normalize_bits_int16(num) normalize_bits(num, 15)
+#define normalize_bits_int32(num) normalize_bits(num, 31)
+
/**
* Scale vector contents based on the largest of their absolutes.
*/
@@ -281,12 +251,11 @@ static int scale_vector(int16_t *dst, const int16_t *vector, int length)
int bits, max = 0;
int i;
-
for (i = 0; i < length; i++)
max |= FFABS(vector[i]);
- max = FFMIN(max, 0x7FFF);
- bits = normalize_bits(max, 15);
+ bits= 14 - av_log2_16bit(max);
+ bits= FFMAX(bits, 0);
for (i = 0; i < length; i++)
dst[i] = vector[i] << bits >> 3;
@@ -371,7 +340,7 @@ static void inverse_quant(int16_t *cur_lsp, int16_t *prev_lsp,
* @param b 16 bit multiplier
*/
#define MULL2(a, b) \
- ((((a) >> 16) * (b) << 1) + (((a) & 0xffff) * (b) >> 15))
+ MULL(a,b,15)
/**
* Convert LSP frequencies to LPC coefficients.
@@ -386,7 +355,7 @@ static void lsp2lpc(int16_t *lpc)
/* Calculate negative cosine */
for (j = 0; j < LPC_ORDER; j++) {
- int index = lpc[j] >> 7;
+ int index = (lpc[j] >> 7) & 0x1FF;
int offset = lpc[j] & 0x7f;
int temp1 = cos_tab[index] << 16;
int temp2 = (cos_tab[index + 1] - cos_tab[index]) *
@@ -567,13 +536,8 @@ static void get_residual(int16_t *residual, int16_t *prev_excitation, int lag)
static int dot_product(const int16_t *a, const int16_t *b, int length)
{
- int i, sum = 0;
-
- for (i = 0; i < length; i++) {
- int prod = a[i] * b[i];
- sum = av_sat_dadd32(sum, prod);
- }
- return sum;
+ int sum = ff_dot_product(a,b,length);
+ return av_sat_add32(sum, sum);
}
/**
@@ -593,16 +557,16 @@ static void gen_acb_excitation(int16_t *vector, int16_t *prev_excitation,
get_residual(residual, prev_excitation, lag);
/* Select quantization table */
- if (cur_rate == RATE_6300 && pitch_lag < SUBFRAME_LEN - 2)
+ if (cur_rate == RATE_6300 && pitch_lag < SUBFRAME_LEN - 2) {
cb_ptr = adaptive_cb_gain85;
- else
+ } else
cb_ptr = adaptive_cb_gain170;
/* Calculate adaptive vector */
cb_ptr += subfrm->ad_cb_gain * 20;
for (i = 0; i < SUBFRAME_LEN; i++) {
- sum = dot_product(residual + i, cb_ptr, PITCH_ORDER);
- vector[i] = av_sat_dadd32(1 << 15, sum) >> 16;
+ sum = ff_dot_product(residual + i, cb_ptr, PITCH_ORDER);
+ vector[i] = av_sat_dadd32(1 << 15, av_sat_add32(sum, sum)) >> 16;
}
}
@@ -810,9 +774,9 @@ static int comp_interp_index(G723_1_Context *p, int pitch_lag,
temp = best_eng * *exc_eng >> 3;
- if (temp < ccr * ccr)
+ if (temp < ccr * ccr) {
return index;
- else
+ } else
return 0;
}
@@ -852,21 +816,24 @@ static void residual_interp(int16_t *buf, int16_t *out, int lag,
* @param iir_coef IIR coefficients
* @param src source vector
* @param dest destination vector
+ * @param width width of the output, 16 bits(0) / 32 bits(1)
*/
-static inline void iir_filter(int16_t *fir_coef, int16_t *iir_coef,
- int16_t *src, int *dest)
-{
- int m, n;
-
- for (m = 0; m < SUBFRAME_LEN; m++) {
- int64_t filter = 0;
- for (n = 1; n <= LPC_ORDER; n++) {
- filter -= fir_coef[n - 1] * src[m - n] -
- iir_coef[n - 1] * (dest[m - n] >> 16);
- }
-
- dest[m] = av_clipl_int32((src[m] << 16) + (filter << 3) + (1 << 15));
- }
+#define iir_filter(fir_coef, iir_coef, src, dest, width)\
+{\
+ int m, n;\
+ int res_shift = 16 & ~-(width);\
+ int in_shift = 16 - res_shift;\
+\
+ for (m = 0; m < SUBFRAME_LEN; m++) {\
+ int64_t filter = 0;\
+ for (n = 1; n <= LPC_ORDER; n++) {\
+ filter -= (fir_coef)[n - 1] * (src)[m - n] -\
+ (iir_coef)[n - 1] * ((dest)[m - n] >> in_shift);\
+ }\
+\
+ (dest)[m] = av_clipl_int32(((src)[m] << 16) + (filter << 3) +\
+ (1 << 15)) >> res_shift;\
+ }\
}
/**
@@ -937,13 +904,12 @@ static void formant_postfilter(G723_1_Context *p, int16_t *lpc,
(1 << 14)) >> 15;
}
iir_filter(filter_coef[0], filter_coef[1], buf + i,
- filter_signal + i);
+ filter_signal + i, 1);
lpc += LPC_ORDER;
}
- memcpy(p->fir_mem, buf + FRAME_LEN, LPC_ORDER * sizeof(*p->fir_mem));
- memcpy(p->iir_mem, filter_signal + FRAME_LEN,
- LPC_ORDER * sizeof(*p->iir_mem));
+ memcpy(p->fir_mem, buf + FRAME_LEN, LPC_ORDER * sizeof(int16_t));
+ memcpy(p->iir_mem, filter_signal + FRAME_LEN, LPC_ORDER * sizeof(int));
buf += LPC_ORDER;
signal_ptr = filter_signal + LPC_ORDER;
@@ -1218,10 +1184,8 @@ static int g723_1_decode_frame(AVCodecContext *avctx, void *data,
}
frame->nb_samples = FRAME_LEN;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
- }
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
out = (int16_t *)frame->data[0];
@@ -1376,3 +1340,1145 @@ AVCodec ff_g723_1_decoder = {
.capabilities = CODEC_CAP_SUBFRAMES | CODEC_CAP_DR1,
.priv_class = &g723_1dec_class,
};
+
+#if CONFIG_G723_1_ENCODER
+#define BITSTREAM_WRITER_LE
+#include "put_bits.h"
+
+static av_cold int g723_1_encode_init(AVCodecContext *avctx)
+{
+ G723_1_Context *p = avctx->priv_data;
+
+ if (avctx->sample_rate != 8000) {
+ av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n");
+ return -1;
+ }
+
+ if (avctx->channels != 1) {
+ av_log(avctx, AV_LOG_ERROR, "Only mono supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (avctx->bit_rate == 6300) {
+ p->cur_rate = RATE_6300;
+ } else if (avctx->bit_rate == 5300) {
+ av_log(avctx, AV_LOG_ERROR, "Bitrate not supported yet, use 6.3k\n");
+ return AVERROR_PATCHWELCOME;
+ } else {
+ av_log(avctx, AV_LOG_ERROR,
+ "Bitrate not supported, use 6.3k\n");
+ return AVERROR(EINVAL);
+ }
+ avctx->frame_size = 240;
+ memcpy(p->prev_lsp, dc_lsp, LPC_ORDER * sizeof(int16_t));
+
+ return 0;
+}
+
+/**
+ * Remove DC component from the input signal.
+ *
+ * @param buf input signal
+ * @param fir zero memory
+ * @param iir pole memory
+ */
+static void highpass_filter(int16_t *buf, int16_t *fir, int *iir)
+{
+ int i;
+ for (i = 0; i < FRAME_LEN; i++) {
+ *iir = (buf[i] << 15) + ((-*fir) << 15) + MULL2(*iir, 0x7f00);
+ *fir = buf[i];
+ buf[i] = av_clipl_int32((int64_t)*iir + (1 << 15)) >> 16;
+ }
+}
+
+/**
+ * Estimate autocorrelation of the input vector.
+ *
+ * @param buf input buffer
+ * @param autocorr autocorrelation coefficients vector
+ */
+static void comp_autocorr(int16_t *buf, int16_t *autocorr)
+{
+ int i, scale, temp;
+ int16_t vector[LPC_FRAME];
+
+ scale_vector(vector, buf, LPC_FRAME);
+
+ /* Apply the Hamming window */
+ for (i = 0; i < LPC_FRAME; i++)
+ vector[i] = (vector[i] * hamming_window[i] + (1 << 14)) >> 15;
+
+ /* Compute the first autocorrelation coefficient */
+ temp = ff_dot_product(vector, vector, LPC_FRAME);
+
+ /* Apply a white noise correlation factor of (1025/1024) */
+ temp += temp >> 10;
+
+ /* Normalize */
+ scale = normalize_bits_int32(temp);
+ autocorr[0] = av_clipl_int32((int64_t)(temp << scale) +
+ (1 << 15)) >> 16;
+
+ /* Compute the remaining coefficients */
+ if (!autocorr[0]) {
+ memset(autocorr + 1, 0, LPC_ORDER * sizeof(int16_t));
+ } else {
+ for (i = 1; i <= LPC_ORDER; i++) {
+ temp = ff_dot_product(vector, vector + i, LPC_FRAME - i);
+ temp = MULL2((temp << scale), binomial_window[i - 1]);
+ autocorr[i] = av_clipl_int32((int64_t)temp + (1 << 15)) >> 16;
+ }
+ }
+}
+
+/**
+ * Use Levinson-Durbin recursion to compute LPC coefficients from
+ * autocorrelation values.
+ *
+ * @param lpc LPC coefficients vector
+ * @param autocorr autocorrelation coefficients vector
+ * @param error prediction error
+ */
+static void levinson_durbin(int16_t *lpc, int16_t *autocorr, int16_t error)
+{
+ int16_t vector[LPC_ORDER];
+ int16_t partial_corr;
+ int i, j, temp;
+
+ memset(lpc, 0, LPC_ORDER * sizeof(int16_t));
+
+ for (i = 0; i < LPC_ORDER; i++) {
+ /* Compute the partial correlation coefficient */
+ temp = 0;
+ for (j = 0; j < i; j++)
+ temp -= lpc[j] * autocorr[i - j - 1];
+ temp = ((autocorr[i] << 13) + temp) << 3;
+
+ if (FFABS(temp) >= (error << 16))
+ break;
+
+ partial_corr = temp / (error << 1);
+
+ lpc[i] = av_clipl_int32((int64_t)(partial_corr << 14) +
+ (1 << 15)) >> 16;
+
+ /* Update the prediction error */
+ temp = MULL2(temp, partial_corr);
+ error = av_clipl_int32((int64_t)(error << 16) - temp +
+ (1 << 15)) >> 16;
+
+ memcpy(vector, lpc, i * sizeof(int16_t));
+ for (j = 0; j < i; j++) {
+ temp = partial_corr * vector[i - j - 1] << 1;
+ lpc[j] = av_clipl_int32((int64_t)(lpc[j] << 16) - temp +
+ (1 << 15)) >> 16;
+ }
+ }
+}
+
+/**
+ * Calculate LPC coefficients for the current frame.
+ *
+ * @param buf current frame
+ * @param prev_data 2 trailing subframes of the previous frame
+ * @param lpc LPC coefficients vector
+ */
+static void comp_lpc_coeff(int16_t *buf, int16_t *lpc)
+{
+ int16_t autocorr[(LPC_ORDER + 1) * SUBFRAMES];
+ int16_t *autocorr_ptr = autocorr;
+ int16_t *lpc_ptr = lpc;
+ int i, j;
+
+ for (i = 0, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) {
+ comp_autocorr(buf + i, autocorr_ptr);
+ levinson_durbin(lpc_ptr, autocorr_ptr + 1, autocorr_ptr[0]);
+
+ lpc_ptr += LPC_ORDER;
+ autocorr_ptr += LPC_ORDER + 1;
+ }
+}
+
+static void lpc2lsp(int16_t *lpc, int16_t *prev_lsp, int16_t *lsp)
+{
+ int f[LPC_ORDER + 2]; ///< coefficients of the sum and difference
+ ///< polynomials (F1, F2) ordered as
+ ///< f1[0], f2[0], ...., f1[5], f2[5]
+
+ int max, shift, cur_val, prev_val, count, p;
+ int i, j;
+ int64_t temp;
+
+ /* Initialize f1[0] and f2[0] to 1 in Q25 */
+ for (i = 0; i < LPC_ORDER; i++)
+ lsp[i] = (lpc[i] * bandwidth_expand[i] + (1 << 14)) >> 15;
+
+ /* Apply bandwidth expansion on the LPC coefficients */
+ f[0] = f[1] = 1 << 25;
+
+ /* Compute the remaining coefficients */
+ for (i = 0; i < LPC_ORDER / 2; i++) {
+ /* f1 */
+ f[2 * i + 2] = -f[2 * i] - ((lsp[i] + lsp[LPC_ORDER - 1 - i]) << 12);
+ /* f2 */
+ f[2 * i + 3] = f[2 * i + 1] - ((lsp[i] - lsp[LPC_ORDER - 1 - i]) << 12);
+ }
+
+ /* Divide f1[5] and f2[5] by 2 for use in polynomial evaluation */
+ f[LPC_ORDER] >>= 1;
+ f[LPC_ORDER + 1] >>= 1;
+
+ /* Normalize and shorten */
+ max = FFABS(f[0]);
+ for (i = 1; i < LPC_ORDER + 2; i++)
+ max = FFMAX(max, FFABS(f[i]));
+
+ shift = normalize_bits_int32(max);
+
+ for (i = 0; i < LPC_ORDER + 2; i++)
+ f[i] = av_clipl_int32((int64_t)(f[i] << shift) + (1 << 15)) >> 16;
+
+ /**
+ * Evaluate F1 and F2 at uniform intervals of pi/256 along the
+ * unit circle and check for zero crossings.
+ */
+ p = 0;
+ temp = 0;
+ for (i = 0; i <= LPC_ORDER / 2; i++)
+ temp += f[2 * i] * cos_tab[0];
+ prev_val = av_clipl_int32(temp << 1);
+ count = 0;
+ for ( i = 1; i < COS_TBL_SIZE / 2; i++) {
+ /* Evaluate */
+ temp = 0;
+ for (j = 0; j <= LPC_ORDER / 2; j++)
+ temp += f[LPC_ORDER - 2 * j + p] * cos_tab[i * j % COS_TBL_SIZE];
+ cur_val = av_clipl_int32(temp << 1);
+
+ /* Check for sign change, indicating a zero crossing */
+ if ((cur_val ^ prev_val) < 0) {
+ int abs_cur = FFABS(cur_val);
+ int abs_prev = FFABS(prev_val);
+ int sum = abs_cur + abs_prev;
+
+ shift = normalize_bits_int32(sum);
+ sum <<= shift;
+ abs_prev = abs_prev << shift >> 8;
+ lsp[count++] = ((i - 1) << 7) + (abs_prev >> 1) / (sum >> 16);
+
+ if (count == LPC_ORDER)
+ break;
+
+ /* Switch between sum and difference polynomials */
+ p ^= 1;
+
+ /* Evaluate */
+ temp = 0;
+ for (j = 0; j <= LPC_ORDER / 2; j++){
+ temp += f[LPC_ORDER - 2 * j + p] *
+ cos_tab[i * j % COS_TBL_SIZE];
+ }
+ cur_val = av_clipl_int32(temp<<1);
+ }
+ prev_val = cur_val;
+ }
+
+ if (count != LPC_ORDER)
+ memcpy(lsp, prev_lsp, LPC_ORDER * sizeof(int16_t));
+}
+
+/**
+ * Quantize the current LSP subvector.
+ *
+ * @param num band number
+ * @param offset offset of the current subvector in an LPC_ORDER vector
+ * @param size size of the current subvector
+ */
+#define get_index(num, offset, size) \
+{\
+ int error, max = -1;\
+ int16_t temp[4];\
+ int i, j;\
+ for (i = 0; i < LSP_CB_SIZE; i++) {\
+ for (j = 0; j < size; j++){\
+ temp[j] = (weight[j + (offset)] * lsp_band##num[i][j] +\
+ (1 << 14)) >> 15;\
+ }\
+ error = dot_product(lsp + (offset), temp, size) << 1;\
+ error -= dot_product(lsp_band##num[i], temp, size);\
+ if (error > max) {\
+ max = error;\
+ lsp_index[num] = i;\
+ }\
+ }\
+}
+
+/**
+ * Vector quantize the LSP frequencies.
+ *
+ * @param lsp the current lsp vector
+ * @param prev_lsp the previous lsp vector
+ */
+static void lsp_quantize(uint8_t *lsp_index, int16_t *lsp, int16_t *prev_lsp)
+{
+ int16_t weight[LPC_ORDER];
+ int16_t min, max;
+ int shift, i;
+
+ /* Calculate the VQ weighting vector */
+ weight[0] = (1 << 20) / (lsp[1] - lsp[0]);
+ weight[LPC_ORDER - 1] = (1 << 20) /
+ (lsp[LPC_ORDER - 1] - lsp[LPC_ORDER - 2]);
+
+ for (i = 1; i < LPC_ORDER - 1; i++) {
+ min = FFMIN(lsp[i] - lsp[i - 1], lsp[i + 1] - lsp[i]);
+ if (min > 0x20)
+ weight[i] = (1 << 20) / min;
+ else
+ weight[i] = INT16_MAX;
+ }
+
+ /* Normalize */
+ max = 0;
+ for (i = 0; i < LPC_ORDER; i++)
+ max = FFMAX(weight[i], max);
+
+ shift = normalize_bits_int16(max);
+ for (i = 0; i < LPC_ORDER; i++) {
+ weight[i] <<= shift;
+ }
+
+ /* Compute the VQ target vector */
+ for (i = 0; i < LPC_ORDER; i++) {
+ lsp[i] -= dc_lsp[i] +
+ (((prev_lsp[i] - dc_lsp[i]) * 12288 + (1 << 14)) >> 15);
+ }
+
+ get_index(0, 0, 3);
+ get_index(1, 3, 3);
+ get_index(2, 6, 4);
+}
+
+/**
+ * Apply the formant perceptual weighting filter.
+ *
+ * @param flt_coef filter coefficients
+ * @param unq_lpc unquantized lpc vector
+ */
+static void perceptual_filter(G723_1_Context *p, int16_t *flt_coef,
+ int16_t *unq_lpc, int16_t *buf)
+{
+ int16_t vector[FRAME_LEN + LPC_ORDER];
+ int i, j, k, l = 0;
+
+ memcpy(buf, p->iir_mem, sizeof(int16_t) * LPC_ORDER);
+ memcpy(vector, p->fir_mem, sizeof(int16_t) * LPC_ORDER);
+ memcpy(vector + LPC_ORDER, buf + LPC_ORDER, sizeof(int16_t) * FRAME_LEN);
+
+ for (i = LPC_ORDER, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) {
+ for (k = 0; k < LPC_ORDER; k++) {
+ flt_coef[k + 2 * l] = (unq_lpc[k + l] * percept_flt_tbl[0][k] +
+ (1 << 14)) >> 15;
+ flt_coef[k + 2 * l + LPC_ORDER] = (unq_lpc[k + l] *
+ percept_flt_tbl[1][k] +
+ (1 << 14)) >> 15;
+ }
+ iir_filter(flt_coef + 2 * l, flt_coef + 2 * l + LPC_ORDER, vector + i,
+ buf + i, 0);
+ l += LPC_ORDER;
+ }
+ memcpy(p->iir_mem, buf + FRAME_LEN, sizeof(int16_t) * LPC_ORDER);
+ memcpy(p->fir_mem, vector + FRAME_LEN, sizeof(int16_t) * LPC_ORDER);
+}
+
+/**
+ * Estimate the open loop pitch period.
+ *
+ * @param buf perceptually weighted speech
+ * @param start estimation is carried out from this position
+ */
+static int estimate_pitch(int16_t *buf, int start)
+{
+ int max_exp = 32;
+ int max_ccr = 0x4000;
+ int max_eng = 0x7fff;
+ int index = PITCH_MIN;
+ int offset = start - PITCH_MIN + 1;
+
+ int ccr, eng, orig_eng, ccr_eng, exp;
+ int diff, temp;
+
+ int i;
+
+ orig_eng = ff_dot_product(buf + offset, buf + offset, HALF_FRAME_LEN);
+
+ for (i = PITCH_MIN; i <= PITCH_MAX - 3; i++) {
+ offset--;
+
+ /* Update energy and compute correlation */
+ orig_eng += buf[offset] * buf[offset] -
+ buf[offset + HALF_FRAME_LEN] * buf[offset + HALF_FRAME_LEN];
+ ccr = ff_dot_product(buf + start, buf + offset, HALF_FRAME_LEN);
+ if (ccr <= 0)
+ continue;
+
+ /* Split into mantissa and exponent to maintain precision */
+ exp = normalize_bits_int32(ccr);
+ ccr = av_clipl_int32((int64_t)(ccr << exp) + (1 << 15)) >> 16;
+ exp <<= 1;
+ ccr *= ccr;
+ temp = normalize_bits_int32(ccr);
+ ccr = ccr << temp >> 16;
+ exp += temp;
+
+ temp = normalize_bits_int32(orig_eng);
+ eng = av_clipl_int32((int64_t)(orig_eng << temp) + (1 << 15)) >> 16;
+ exp -= temp;
+
+ if (ccr >= eng) {
+ exp--;
+ ccr >>= 1;
+ }
+ if (exp > max_exp)
+ continue;
+
+ if (exp + 1 < max_exp)
+ goto update;
+
+ /* Equalize exponents before comparison */
+ if (exp + 1 == max_exp)
+ temp = max_ccr >> 1;
+ else
+ temp = max_ccr;
+ ccr_eng = ccr * max_eng;
+ diff = ccr_eng - eng * temp;
+ if (diff > 0 && (i - index < PITCH_MIN || diff > ccr_eng >> 2)) {
+update:
+ index = i;
+ max_exp = exp;
+ max_ccr = ccr;
+ max_eng = eng;
+ }
+ }
+ return index;
+}
+
+/**
+ * Compute harmonic noise filter parameters.
+ *
+ * @param buf perceptually weighted speech
+ * @param pitch_lag open loop pitch period
+ * @param hf harmonic filter parameters
+ */
+static void comp_harmonic_coeff(int16_t *buf, int16_t pitch_lag, HFParam *hf)
+{
+ int ccr, eng, max_ccr, max_eng;
+ int exp, max, diff;
+ int energy[15];
+ int i, j;
+
+ for (i = 0, j = pitch_lag - 3; j <= pitch_lag + 3; i++, j++) {
+ /* Compute residual energy */
+ energy[i << 1] = ff_dot_product(buf - j, buf - j, SUBFRAME_LEN);
+ /* Compute correlation */
+ energy[(i << 1) + 1] = ff_dot_product(buf, buf - j, SUBFRAME_LEN);
+ }
+
+ /* Compute target energy */
+ energy[14] = ff_dot_product(buf, buf, SUBFRAME_LEN);
+
+ /* Normalize */
+ max = 0;
+ for (i = 0; i < 15; i++)
+ max = FFMAX(max, FFABS(energy[i]));
+
+ exp = normalize_bits_int32(max);
+ for (i = 0; i < 15; i++) {
+ energy[i] = av_clipl_int32((int64_t)(energy[i] << exp) +
+ (1 << 15)) >> 16;
+ }
+
+ hf->index = -1;
+ hf->gain = 0;
+ max_ccr = 1;
+ max_eng = 0x7fff;
+
+ for (i = 0; i <= 6; i++) {
+ eng = energy[i << 1];
+ ccr = energy[(i << 1) + 1];
+
+ if (ccr <= 0)
+ continue;
+
+ ccr = (ccr * ccr + (1 << 14)) >> 15;
+ diff = ccr * max_eng - eng * max_ccr;
+ if (diff > 0) {
+ max_ccr = ccr;
+ max_eng = eng;
+ hf->index = i;
+ }
+ }
+
+ if (hf->index == -1) {
+ hf->index = pitch_lag;
+ return;
+ }
+
+ eng = energy[14] * max_eng;
+ eng = (eng >> 2) + (eng >> 3);
+ ccr = energy[(hf->index << 1) + 1] * energy[(hf->index << 1) + 1];
+ if (eng < ccr) {
+ eng = energy[(hf->index << 1) + 1];
+
+ if (eng >= max_eng)
+ hf->gain = 0x2800;
+ else
+ hf->gain = ((eng << 15) / max_eng * 0x2800 + (1 << 14)) >> 15;
+ }
+ hf->index += pitch_lag - 3;
+}
+
+/**
+ * Apply the harmonic noise shaping filter.
+ *
+ * @param hf filter parameters
+ */
+static void harmonic_filter(HFParam *hf, const int16_t *src, int16_t *dest)
+{
+ int i;
+
+ for (i = 0; i < SUBFRAME_LEN; i++) {
+ int64_t temp = hf->gain * src[i - hf->index] << 1;
+ dest[i] = av_clipl_int32((src[i] << 16) - temp + (1 << 15)) >> 16;
+ }
+}
+
+static void harmonic_noise_sub(HFParam *hf, const int16_t *src, int16_t *dest)
+{
+ int i;
+ for (i = 0; i < SUBFRAME_LEN; i++) {
+ int64_t temp = hf->gain * src[i - hf->index] << 1;
+ dest[i] = av_clipl_int32(((dest[i] - src[i]) << 16) + temp +
+ (1 << 15)) >> 16;
+
+ }
+}
+
+/**
+ * Combined synthesis and formant perceptual weighting filer.
+ *
+ * @param qnt_lpc quantized lpc coefficients
+ * @param perf_lpc perceptual filter coefficients
+ * @param perf_fir perceptual filter fir memory
+ * @param perf_iir perceptual filter iir memory
+ * @param scale the filter output will be scaled by 2^scale
+ */
+static void synth_percept_filter(int16_t *qnt_lpc, int16_t *perf_lpc,
+ int16_t *perf_fir, int16_t *perf_iir,
+ const int16_t *src, int16_t *dest, int scale)
+{
+ int i, j;
+ int16_t buf_16[SUBFRAME_LEN + LPC_ORDER];
+ int64_t buf[SUBFRAME_LEN];
+
+ int16_t *bptr_16 = buf_16 + LPC_ORDER;
+
+ memcpy(buf_16, perf_fir, sizeof(int16_t) * LPC_ORDER);
+ memcpy(dest - LPC_ORDER, perf_iir, sizeof(int16_t) * LPC_ORDER);
+
+ for (i = 0; i < SUBFRAME_LEN; i++) {
+ int64_t temp = 0;
+ for (j = 1; j <= LPC_ORDER; j++)
+ temp -= qnt_lpc[j - 1] * bptr_16[i - j];
+
+ buf[i] = (src[i] << 15) + (temp << 3);
+ bptr_16[i] = av_clipl_int32(buf[i] + (1 << 15)) >> 16;
+ }
+
+ for (i = 0; i < SUBFRAME_LEN; i++) {
+ int64_t fir = 0, iir = 0;
+ for (j = 1; j <= LPC_ORDER; j++) {
+ fir -= perf_lpc[j - 1] * bptr_16[i - j];
+ iir += perf_lpc[j + LPC_ORDER - 1] * dest[i - j];
+ }
+ dest[i] = av_clipl_int32(((buf[i] + (fir << 3)) << scale) + (iir << 3) +
+ (1 << 15)) >> 16;
+ }
+ memcpy(perf_fir, buf_16 + SUBFRAME_LEN, sizeof(int16_t) * LPC_ORDER);
+ memcpy(perf_iir, dest + SUBFRAME_LEN - LPC_ORDER,
+ sizeof(int16_t) * LPC_ORDER);
+}
+
+/**
+ * Compute the adaptive codebook contribution.
+ *
+ * @param buf input signal
+ * @param index the current subframe index
+ */
+static void acb_search(G723_1_Context *p, int16_t *residual,
+ int16_t *impulse_resp, const int16_t *buf,
+ int index)
+{
+
+ int16_t flt_buf[PITCH_ORDER][SUBFRAME_LEN];
+
+ const int16_t *cb_tbl = adaptive_cb_gain85;
+
+ int ccr_buf[PITCH_ORDER * SUBFRAMES << 2];
+
+ int pitch_lag = p->pitch_lag[index >> 1];
+ int acb_lag = 1;
+ int acb_gain = 0;
+ int odd_frame = index & 1;
+ int iter = 3 + odd_frame;
+ int count = 0;
+ int tbl_size = 85;
+
+ int i, j, k, l, max;
+ int64_t temp;
+
+ if (!odd_frame) {
+ if (pitch_lag == PITCH_MIN)
+ pitch_lag++;
+ else
+ pitch_lag = FFMIN(pitch_lag, PITCH_MAX - 5);
+ }
+
+ for (i = 0; i < iter; i++) {
+ get_residual(residual, p->prev_excitation, pitch_lag + i - 1);
+
+ for (j = 0; j < SUBFRAME_LEN; j++) {
+ temp = 0;
+ for (k = 0; k <= j; k++)
+ temp += residual[PITCH_ORDER - 1 + k] * impulse_resp[j - k];
+ flt_buf[PITCH_ORDER - 1][j] = av_clipl_int32((temp << 1) +
+ (1 << 15)) >> 16;
+ }
+
+ for (j = PITCH_ORDER - 2; j >= 0; j--) {
+ flt_buf[j][0] = ((residual[j] << 13) + (1 << 14)) >> 15;
+ for (k = 1; k < SUBFRAME_LEN; k++) {
+ temp = (flt_buf[j + 1][k - 1] << 15) +
+ residual[j] * impulse_resp[k];
+ flt_buf[j][k] = av_clipl_int32((temp << 1) + (1 << 15)) >> 16;
+ }
+ }
+
+ /* Compute crosscorrelation with the signal */
+ for (j = 0; j < PITCH_ORDER; j++) {
+ temp = ff_dot_product(buf, flt_buf[j], SUBFRAME_LEN);
+ ccr_buf[count++] = av_clipl_int32(temp << 1);
+ }
+
+ /* Compute energies */
+ for (j = 0; j < PITCH_ORDER; j++) {
+ ccr_buf[count++] = dot_product(flt_buf[j], flt_buf[j],
+ SUBFRAME_LEN);
+ }
+
+ for (j = 1; j < PITCH_ORDER; j++) {
+ for (k = 0; k < j; k++) {
+ temp = ff_dot_product(flt_buf[j], flt_buf[k], SUBFRAME_LEN);
+ ccr_buf[count++] = av_clipl_int32(temp<<2);
+ }
+ }
+ }
+
+ /* Normalize and shorten */
+ max = 0;
+ for (i = 0; i < 20 * iter; i++)
+ max = FFMAX(max, FFABS(ccr_buf[i]));
+
+ temp = normalize_bits_int32(max);
+
+ for (i = 0; i < 20 * iter; i++){
+ ccr_buf[i] = av_clipl_int32((int64_t)(ccr_buf[i] << temp) +
+ (1 << 15)) >> 16;
+ }
+
+ max = 0;
+ for (i = 0; i < iter; i++) {
+ /* Select quantization table */
+ if (!odd_frame && pitch_lag + i - 1 >= SUBFRAME_LEN - 2 ||
+ odd_frame && pitch_lag >= SUBFRAME_LEN - 2) {
+ cb_tbl = adaptive_cb_gain170;
+ tbl_size = 170;
+ }
+
+ for (j = 0, k = 0; j < tbl_size; j++, k += 20) {
+ temp = 0;
+ for (l = 0; l < 20; l++)
+ temp += ccr_buf[20 * i + l] * cb_tbl[k + l];
+ temp = av_clipl_int32(temp);
+
+ if (temp > max) {
+ max = temp;
+ acb_gain = j;
+ acb_lag = i;
+ }
+ }
+ }
+
+ if (!odd_frame) {
+ pitch_lag += acb_lag - 1;
+ acb_lag = 1;
+ }
+
+ p->pitch_lag[index >> 1] = pitch_lag;
+ p->subframe[index].ad_cb_lag = acb_lag;
+ p->subframe[index].ad_cb_gain = acb_gain;
+}
+
+/**
+ * Subtract the adaptive codebook contribution from the input
+ * to obtain the residual.
+ *
+ * @param buf target vector
+ */
+static void sub_acb_contrib(const int16_t *residual, const int16_t *impulse_resp,
+ int16_t *buf)
+{
+ int i, j;
+ /* Subtract adaptive CB contribution to obtain the residual */
+ for (i = 0; i < SUBFRAME_LEN; i++) {
+ int64_t temp = buf[i] << 14;
+ for (j = 0; j <= i; j++)
+ temp -= residual[j] * impulse_resp[i - j];
+
+ buf[i] = av_clipl_int32((temp << 2) + (1 << 15)) >> 16;
+ }
+}
+
+/**
+ * Quantize the residual signal using the fixed codebook (MP-MLQ).
+ *
+ * @param optim optimized fixed codebook parameters
+ * @param buf excitation vector
+ */
+static void get_fcb_param(FCBParam *optim, int16_t *impulse_resp,
+ int16_t *buf, int pulse_cnt, int pitch_lag)
+{
+ FCBParam param;
+ int16_t impulse_r[SUBFRAME_LEN];
+ int16_t temp_corr[SUBFRAME_LEN];
+ int16_t impulse_corr[SUBFRAME_LEN];
+
+ int ccr1[SUBFRAME_LEN];
+ int ccr2[SUBFRAME_LEN];
+ int amp, err, max, max_amp_index, min, scale, i, j, k, l;
+
+ int64_t temp;
+
+ /* Update impulse response */
+ memcpy(impulse_r, impulse_resp, sizeof(int16_t) * SUBFRAME_LEN);
+ param.dirac_train = 0;
+ if (pitch_lag < SUBFRAME_LEN - 2) {
+ param.dirac_train = 1;
+ gen_dirac_train(impulse_r, pitch_lag);
+ }
+
+ for (i = 0; i < SUBFRAME_LEN; i++)
+ temp_corr[i] = impulse_r[i] >> 1;
+
+ /* Compute impulse response autocorrelation */
+ temp = dot_product(temp_corr, temp_corr, SUBFRAME_LEN);
+
+ scale = normalize_bits_int32(temp);
+ impulse_corr[0] = av_clipl_int32((temp << scale) + (1 << 15)) >> 16;
+
+ for (i = 1; i < SUBFRAME_LEN; i++) {
+ temp = dot_product(temp_corr + i, temp_corr, SUBFRAME_LEN - i);
+ impulse_corr[i] = av_clipl_int32((temp << scale) + (1 << 15)) >> 16;
+ }
+
+ /* Compute crosscorrelation of impulse response with residual signal */
+ scale -= 4;
+ for (i = 0; i < SUBFRAME_LEN; i++){
+ temp = dot_product(buf + i, impulse_r, SUBFRAME_LEN - i);
+ if (scale < 0)
+ ccr1[i] = temp >> -scale;
+ else
+ ccr1[i] = av_clipl_int32(temp << scale);
+ }
+
+ /* Search loop */
+ for (i = 0; i < GRID_SIZE; i++) {
+ /* Maximize the crosscorrelation */
+ max = 0;
+ for (j = i; j < SUBFRAME_LEN; j += GRID_SIZE) {
+ temp = FFABS(ccr1[j]);
+ if (temp >= max) {
+ max = temp;
+ param.pulse_pos[0] = j;
+ }
+ }
+
+ /* Quantize the gain (max crosscorrelation/impulse_corr[0]) */
+ amp = max;
+ min = 1 << 30;
+ max_amp_index = GAIN_LEVELS - 2;
+ for (j = max_amp_index; j >= 2; j--) {
+ temp = av_clipl_int32((int64_t)fixed_cb_gain[j] *
+ impulse_corr[0] << 1);
+ temp = FFABS(temp - amp);
+ if (temp < min) {
+ min = temp;
+ max_amp_index = j;
+ }
+ }
+
+ max_amp_index--;
+ /* Select additional gain values */
+ for (j = 1; j < 5; j++) {
+ for (k = i; k < SUBFRAME_LEN; k += GRID_SIZE) {
+ temp_corr[k] = 0;
+ ccr2[k] = ccr1[k];
+ }
+ param.amp_index = max_amp_index + j - 2;
+ amp = fixed_cb_gain[param.amp_index];
+
+ param.pulse_sign[0] = (ccr2[param.pulse_pos[0]] < 0) ? -amp : amp;
+ temp_corr[param.pulse_pos[0]] = 1;
+
+ for (k = 1; k < pulse_cnt; k++) {
+ max = -1 << 30;
+ for (l = i; l < SUBFRAME_LEN; l += GRID_SIZE) {
+ if (temp_corr[l])
+ continue;
+ temp = impulse_corr[FFABS(l - param.pulse_pos[k - 1])];
+ temp = av_clipl_int32((int64_t)temp *
+ param.pulse_sign[k - 1] << 1);
+ ccr2[l] -= temp;
+ temp = FFABS(ccr2[l]);
+ if (temp > max) {
+ max = temp;
+ param.pulse_pos[k] = l;
+ }
+ }
+
+ param.pulse_sign[k] = (ccr2[param.pulse_pos[k]] < 0) ?
+ -amp : amp;
+ temp_corr[param.pulse_pos[k]] = 1;
+ }
+
+ /* Create the error vector */
+ memset(temp_corr, 0, sizeof(int16_t) * SUBFRAME_LEN);
+
+ for (k = 0; k < pulse_cnt; k++)
+ temp_corr[param.pulse_pos[k]] = param.pulse_sign[k];
+
+ for (k = SUBFRAME_LEN - 1; k >= 0; k--) {
+ temp = 0;
+ for (l = 0; l <= k; l++) {
+ int prod = av_clipl_int32((int64_t)temp_corr[l] *
+ impulse_r[k - l] << 1);
+ temp = av_clipl_int32(temp + prod);
+ }
+ temp_corr[k] = temp << 2 >> 16;
+ }
+
+ /* Compute square of error */
+ err = 0;
+ for (k = 0; k < SUBFRAME_LEN; k++) {
+ int64_t prod;
+ prod = av_clipl_int32((int64_t)buf[k] * temp_corr[k] << 1);
+ err = av_clipl_int32(err - prod);
+ prod = av_clipl_int32((int64_t)temp_corr[k] * temp_corr[k]);
+ err = av_clipl_int32(err + prod);
+ }
+
+ /* Minimize */
+ if (err < optim->min_err) {
+ optim->min_err = err;
+ optim->grid_index = i;
+ optim->amp_index = param.amp_index;
+ optim->dirac_train = param.dirac_train;
+
+ for (k = 0; k < pulse_cnt; k++) {
+ optim->pulse_sign[k] = param.pulse_sign[k];
+ optim->pulse_pos[k] = param.pulse_pos[k];
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Encode the pulse position and gain of the current subframe.
+ *
+ * @param optim optimized fixed CB parameters
+ * @param buf excitation vector
+ */
+static void pack_fcb_param(G723_1_Subframe *subfrm, FCBParam *optim,
+ int16_t *buf, int pulse_cnt)
+{
+ int i, j;
+
+ j = PULSE_MAX - pulse_cnt;
+
+ subfrm->pulse_sign = 0;
+ subfrm->pulse_pos = 0;
+
+ for (i = 0; i < SUBFRAME_LEN >> 1; i++) {
+ int val = buf[optim->grid_index + (i << 1)];
+ if (!val) {
+ subfrm->pulse_pos += combinatorial_table[j][i];
+ } else {
+ subfrm->pulse_sign <<= 1;
+ if (val < 0) subfrm->pulse_sign++;
+ j++;
+
+ if (j == PULSE_MAX) break;
+ }
+ }
+ subfrm->amp_index = optim->amp_index;
+ subfrm->grid_index = optim->grid_index;
+ subfrm->dirac_train = optim->dirac_train;
+}
+
+/**
+ * Compute the fixed codebook excitation.
+ *
+ * @param buf target vector
+ * @param impulse_resp impulse response of the combined filter
+ */
+static void fcb_search(G723_1_Context *p, int16_t *impulse_resp,
+ int16_t *buf, int index)
+{
+ FCBParam optim;
+ int pulse_cnt = pulses[index];
+ int i;
+
+ optim.min_err = 1 << 30;
+ get_fcb_param(&optim, impulse_resp, buf, pulse_cnt, SUBFRAME_LEN);
+
+ if (p->pitch_lag[index >> 1] < SUBFRAME_LEN - 2) {
+ get_fcb_param(&optim, impulse_resp, buf, pulse_cnt,
+ p->pitch_lag[index >> 1]);
+ }
+
+ /* Reconstruct the excitation */
+ memset(buf, 0, sizeof(int16_t) * SUBFRAME_LEN);
+ for (i = 0; i < pulse_cnt; i++)
+ buf[optim.pulse_pos[i]] = optim.pulse_sign[i];
+
+ pack_fcb_param(&p->subframe[index], &optim, buf, pulse_cnt);
+
+ if (optim.dirac_train)
+ gen_dirac_train(buf, p->pitch_lag[index >> 1]);
+}
+
+/**
+ * Pack the frame parameters into output bitstream.
+ *
+ * @param frame output buffer
+ * @param size size of the buffer
+ */
+static int pack_bitstream(G723_1_Context *p, unsigned char *frame, int size)
+{
+ PutBitContext pb;
+ int info_bits, i, temp;
+
+ init_put_bits(&pb, frame, size);
+
+ if (p->cur_rate == RATE_6300) {
+ info_bits = 0;
+ put_bits(&pb, 2, info_bits);
+ }else
+ av_assert0(0);
+
+ put_bits(&pb, 8, p->lsp_index[2]);
+ put_bits(&pb, 8, p->lsp_index[1]);
+ put_bits(&pb, 8, p->lsp_index[0]);
+
+ put_bits(&pb, 7, p->pitch_lag[0] - PITCH_MIN);
+ put_bits(&pb, 2, p->subframe[1].ad_cb_lag);
+ put_bits(&pb, 7, p->pitch_lag[1] - PITCH_MIN);
+ put_bits(&pb, 2, p->subframe[3].ad_cb_lag);
+
+ /* Write 12 bit combined gain */
+ for (i = 0; i < SUBFRAMES; i++) {
+ temp = p->subframe[i].ad_cb_gain * GAIN_LEVELS +
+ p->subframe[i].amp_index;
+ if (p->cur_rate == RATE_6300)
+ temp += p->subframe[i].dirac_train << 11;
+ put_bits(&pb, 12, temp);
+ }
+
+ put_bits(&pb, 1, p->subframe[0].grid_index);
+ put_bits(&pb, 1, p->subframe[1].grid_index);
+ put_bits(&pb, 1, p->subframe[2].grid_index);
+ put_bits(&pb, 1, p->subframe[3].grid_index);
+
+ if (p->cur_rate == RATE_6300) {
+ skip_put_bits(&pb, 1); /* reserved bit */
+
+ /* Write 13 bit combined position index */
+ temp = (p->subframe[0].pulse_pos >> 16) * 810 +
+ (p->subframe[1].pulse_pos >> 14) * 90 +
+ (p->subframe[2].pulse_pos >> 16) * 9 +
+ (p->subframe[3].pulse_pos >> 14);
+ put_bits(&pb, 13, temp);
+
+ put_bits(&pb, 16, p->subframe[0].pulse_pos & 0xffff);
+ put_bits(&pb, 14, p->subframe[1].pulse_pos & 0x3fff);
+ put_bits(&pb, 16, p->subframe[2].pulse_pos & 0xffff);
+ put_bits(&pb, 14, p->subframe[3].pulse_pos & 0x3fff);
+
+ put_bits(&pb, 6, p->subframe[0].pulse_sign);
+ put_bits(&pb, 5, p->subframe[1].pulse_sign);
+ put_bits(&pb, 6, p->subframe[2].pulse_sign);
+ put_bits(&pb, 5, p->subframe[3].pulse_sign);
+ }
+
+ flush_put_bits(&pb);
+ return frame_size[info_bits];
+}
+
+static int g723_1_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ G723_1_Context *p = avctx->priv_data;
+ int16_t unq_lpc[LPC_ORDER * SUBFRAMES];
+ int16_t qnt_lpc[LPC_ORDER * SUBFRAMES];
+ int16_t cur_lsp[LPC_ORDER];
+ int16_t weighted_lpc[LPC_ORDER * SUBFRAMES << 1];
+ int16_t vector[FRAME_LEN + PITCH_MAX];
+ int offset, ret;
+ int16_t *in_orig = av_memdup(frame->data[0], frame->nb_samples * sizeof(int16_t));
+ int16_t *in = in_orig;
+
+ HFParam hf[4];
+ int i, j;
+
+ if (!in)
+ return AVERROR(ENOMEM);
+
+ highpass_filter(in, &p->hpf_fir_mem, &p->hpf_iir_mem);
+
+ memcpy(vector, p->prev_data, HALF_FRAME_LEN * sizeof(int16_t));
+ memcpy(vector + HALF_FRAME_LEN, in, FRAME_LEN * sizeof(int16_t));
+
+ comp_lpc_coeff(vector, unq_lpc);
+ lpc2lsp(&unq_lpc[LPC_ORDER * 3], p->prev_lsp, cur_lsp);
+ lsp_quantize(p->lsp_index, cur_lsp, p->prev_lsp);
+
+ /* Update memory */
+ memcpy(vector + LPC_ORDER, p->prev_data + SUBFRAME_LEN,
+ sizeof(int16_t) * SUBFRAME_LEN);
+ memcpy(vector + LPC_ORDER + SUBFRAME_LEN, in,
+ sizeof(int16_t) * (HALF_FRAME_LEN + SUBFRAME_LEN));
+ memcpy(p->prev_data, in + HALF_FRAME_LEN,
+ sizeof(int16_t) * HALF_FRAME_LEN);
+ memcpy(in, vector + LPC_ORDER, sizeof(int16_t) * FRAME_LEN);
+
+ perceptual_filter(p, weighted_lpc, unq_lpc, vector);
+
+ memcpy(in, vector + LPC_ORDER, sizeof(int16_t) * FRAME_LEN);
+ memcpy(vector, p->prev_weight_sig, sizeof(int16_t) * PITCH_MAX);
+ memcpy(vector + PITCH_MAX, in, sizeof(int16_t) * FRAME_LEN);
+
+ scale_vector(vector, vector, FRAME_LEN + PITCH_MAX);
+
+ p->pitch_lag[0] = estimate_pitch(vector, PITCH_MAX);
+ p->pitch_lag[1] = estimate_pitch(vector, PITCH_MAX + HALF_FRAME_LEN);
+
+ for (i = PITCH_MAX, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++)
+ comp_harmonic_coeff(vector + i, p->pitch_lag[j >> 1], hf + j);
+
+ memcpy(vector, p->prev_weight_sig, sizeof(int16_t) * PITCH_MAX);
+ memcpy(vector + PITCH_MAX, in, sizeof(int16_t) * FRAME_LEN);
+ memcpy(p->prev_weight_sig, vector + FRAME_LEN, sizeof(int16_t) * PITCH_MAX);
+
+ for (i = 0, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++)
+ harmonic_filter(hf + j, vector + PITCH_MAX + i, in + i);
+
+ inverse_quant(cur_lsp, p->prev_lsp, p->lsp_index, 0);
+ lsp_interpolate(qnt_lpc, cur_lsp, p->prev_lsp);
+
+ memcpy(p->prev_lsp, cur_lsp, sizeof(int16_t) * LPC_ORDER);
+
+ offset = 0;
+ for (i = 0; i < SUBFRAMES; i++) {
+ int16_t impulse_resp[SUBFRAME_LEN];
+ int16_t residual[SUBFRAME_LEN + PITCH_ORDER - 1];
+ int16_t flt_in[SUBFRAME_LEN];
+ int16_t zero[LPC_ORDER], fir[LPC_ORDER], iir[LPC_ORDER];
+
+ /**
+ * Compute the combined impulse response of the synthesis filter,
+ * formant perceptual weighting filter and harmonic noise shaping filter
+ */
+ memset(zero, 0, sizeof(int16_t) * LPC_ORDER);
+ memset(vector, 0, sizeof(int16_t) * PITCH_MAX);
+ memset(flt_in, 0, sizeof(int16_t) * SUBFRAME_LEN);
+
+ flt_in[0] = 1 << 13; /* Unit impulse */
+ synth_percept_filter(qnt_lpc + offset, weighted_lpc + (offset << 1),
+ zero, zero, flt_in, vector + PITCH_MAX, 1);
+ harmonic_filter(hf + i, vector + PITCH_MAX, impulse_resp);
+
+ /* Compute the combined zero input response */
+ flt_in[0] = 0;
+ memcpy(fir, p->perf_fir_mem, sizeof(int16_t) * LPC_ORDER);
+ memcpy(iir, p->perf_iir_mem, sizeof(int16_t) * LPC_ORDER);
+
+ synth_percept_filter(qnt_lpc + offset, weighted_lpc + (offset << 1),
+ fir, iir, flt_in, vector + PITCH_MAX, 0);
+ memcpy(vector, p->harmonic_mem, sizeof(int16_t) * PITCH_MAX);
+ harmonic_noise_sub(hf + i, vector + PITCH_MAX, in);
+
+ acb_search(p, residual, impulse_resp, in, i);
+ gen_acb_excitation(residual, p->prev_excitation,p->pitch_lag[i >> 1],
+ &p->subframe[i], p->cur_rate);
+ sub_acb_contrib(residual, impulse_resp, in);
+
+ fcb_search(p, impulse_resp, in, i);
+
+ /* Reconstruct the excitation */
+ gen_acb_excitation(impulse_resp, p->prev_excitation, p->pitch_lag[i >> 1],
+ &p->subframe[i], RATE_6300);
+
+ memmove(p->prev_excitation, p->prev_excitation + SUBFRAME_LEN,
+ sizeof(int16_t) * (PITCH_MAX - SUBFRAME_LEN));
+ for (j = 0; j < SUBFRAME_LEN; j++)
+ in[j] = av_clip_int16((in[j] << 1) + impulse_resp[j]);
+ memcpy(p->prev_excitation + PITCH_MAX - SUBFRAME_LEN, in,
+ sizeof(int16_t) * SUBFRAME_LEN);
+
+ /* Update filter memories */
+ synth_percept_filter(qnt_lpc + offset, weighted_lpc + (offset << 1),
+ p->perf_fir_mem, p->perf_iir_mem,
+ in, vector + PITCH_MAX, 0);
+ memmove(p->harmonic_mem, p->harmonic_mem + SUBFRAME_LEN,
+ sizeof(int16_t) * (PITCH_MAX - SUBFRAME_LEN));
+ memcpy(p->harmonic_mem + PITCH_MAX - SUBFRAME_LEN, vector + PITCH_MAX,
+ sizeof(int16_t) * SUBFRAME_LEN);
+
+ in += SUBFRAME_LEN;
+ offset += LPC_ORDER;
+ }
+
+ av_freep(&in_orig); in = NULL;
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 24)) < 0)
+ return ret;
+
+ *got_packet_ptr = 1;
+ avpkt->size = pack_bitstream(p, avpkt->data, avpkt->size);
+ return 0;
+}
+
+AVCodec ff_g723_1_encoder = {
+ .name = "g723_1",
+ .long_name = NULL_IF_CONFIG_SMALL("G.723.1"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_G723_1,
+ .priv_data_size = sizeof(G723_1_Context),
+ .init = g723_1_encode_init,
+ .encode2 = g723_1_encode_frame,
+ .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE},
+};
+#endif
diff --git a/libavcodec/g723_1_data.h b/libavcodec/g723_1_data.h
index 04f8a06e37..db7f6e4d3c 100644
--- a/libavcodec/g723_1_data.h
+++ b/libavcodec/g723_1_data.h
@@ -1,28 +1,28 @@
/*
- * G.723.1 compatible decoder data tables.
+ * G723.1 compatible decoder data tables.
* Copyright (c) 2006 Benjamin Larsson
* Copyright (c) 2010 Mohamed Naufal Basheer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * G.723.1 compatible decoder data tables
+ * G723.1 compatible decoder data tables
*/
#ifndef AVCODEC_G723_1_DATA_H
@@ -33,6 +33,8 @@
#define SUBFRAMES 4
#define SUBFRAME_LEN 60
#define FRAME_LEN (SUBFRAME_LEN << 2)
+#define HALF_FRAME_LEN (FRAME_LEN / 2)
+#define LPC_FRAME (HALF_FRAME_LEN + SUBFRAME_LEN)
#define LPC_ORDER 10
#define LSP_BANDS 3
#define LSP_CB_SIZE 256
@@ -44,19 +46,89 @@
#define GAIN_LEVELS 24
#define COS_TBL_SIZE 512
+/**
+ * G723.1 frame types
+ */
+typedef enum FrameType {
+ ACTIVE_FRAME, ///< Active speech
+ SID_FRAME, ///< Silence Insertion Descriptor frame
+ UNTRANSMITTED_FRAME
+} FrameType;
+
static const uint8_t frame_size[4] = { 24, 20, 4, 1 };
-/* Postfilter gain weighting factors scaled by 2^15 */
-static const int16_t ppf_gain_weight[2] = { 0x1800, 0x2000 };
+typedef enum Rate {
+ RATE_6300,
+ RATE_5300
+} Rate;
+
+/**
+ * G723.1 unpacked data subframe
+ */
+typedef struct G723_1_Subframe {
+ int ad_cb_lag; ///< adaptive codebook lag
+ int ad_cb_gain;
+ int dirac_train;
+ int pulse_sign;
+ int grid_index;
+ int amp_index;
+ int pulse_pos;
+} G723_1_Subframe;
+
+/**
+ * Pitch postfilter parameters
+ */
+typedef struct PPFParam {
+ int index; ///< postfilter backward/forward lag
+ int16_t opt_gain; ///< optimal gain
+ int16_t sc_gain; ///< scaling gain
+} PPFParam;
+
+/**
+ * Harmonic filter parameters
+ */
+typedef struct HFParam {
+ int index;
+ int gain;
+} HFParam;
+
+/**
+ * Optimized fixed codebook excitation parameters
+ */
+typedef struct FCBParam {
+ int min_err;
+ int amp_index;
+ int grid_index;
+ int dirac_train;
+ int pulse_pos[PULSE_MAX];
+ int pulse_sign[PULSE_MAX];
+} FCBParam;
+
+/**
+ * Postfilter gain weighting factors scaled by 2^15
+ */
+static const int16_t ppf_gain_weight[2] = {0x1800, 0x2000};
-/* LSP DC component */
+/**
+ * LSP DC component
+ */
static const int16_t dc_lsp[LPC_ORDER] = {
- 0x0c3b, 0x1271, 0x1e0a, 0x2a36, 0x3630,
- 0x406f, 0x4d28, 0x56f4, 0x638c, 0x6c46
+ 0x0c3b,
+ 0x1271,
+ 0x1e0a,
+ 0x2a36,
+ 0x3630,
+ 0x406f,
+ 0x4d28,
+ 0x56f4,
+ 0x638c,
+ 0x6c46
};
-/* Cosine table scaled by 2^14 */
-static const int16_t cos_tab[COS_TBL_SIZE] = {
+/**
+ * Cosine table scaled by 2^14
+ */
+static const int16_t cos_tab[COS_TBL_SIZE+1] = {
16384, 16383, 16379, 16373, 16364, 16353, 16340, 16324,
16305, 16284, 16261, 16235, 16207, 16176, 16143, 16107,
16069, 16029, 15986, 15941, 15893, 15843, 15791, 15736,
@@ -121,9 +193,12 @@ static const int16_t cos_tab[COS_TBL_SIZE] = {
15679, 15736, 15791, 15843, 15893, 15941, 15986, 16029,
16069, 16107, 16143, 16176, 16207, 16235, 16261, 16284,
16305, 16324, 16340, 16353, 16364, 16373, 16379, 16383,
+ 16384
};
-/* LSP VQ tables */
+/**
+ * LSP VQ tables
+ */
static const int16_t lsp_band0[LSP_CB_SIZE][3] = {
{ 0, 0, 0}, { -270, -1372, -1032}, { -541, -1650, -1382},
{ -723, -2011, -2213}, { -941, -1122, -1942}, { -780, -1145, -2454},
@@ -433,12 +508,12 @@ static const int16_t lsp_band2[LSP_CB_SIZE][4] = {
{ 3633, 2336, 2408, 1453}, { 2923, 3517, 2567, 1318},
};
-/*
+/**
* Used for the coding/decoding of the pulses positions
* for the MP-MLQ codebook
*/
static const int32_t combinatorial_table[PULSE_MAX][SUBFRAME_LEN/GRID_SIZE] = {
- {118755, 98280, 80730, 65780L, 53130,
+ {118755, 98280, 80730, 65780, 53130,
42504, 33649, 26334, 20349, 15504,
11628, 8568, 6188, 4368, 3003,
2002, 1287, 792, 462, 252,
@@ -527,10 +602,14 @@ static const int16_t pitch_contrib[340] = {
-2, 25144, 0, 17998
};
-/* Number of non-zero pulses in the MP-MLQ excitation */
+/**
+ * Number of non-zero pulses in the MP-MLQ excitation
+ */
static const int8_t pulses[4] = {6, 5, 6, 5};
-/* Size of the MP-MLQ fixed excitation codebooks */
+/**
+ * Size of the MP-MLQ fixed excitation codebooks
+ */
static const int32_t max_pos[4] = {593775, 142506, 593775, 142506};
static const int16_t fixed_cb_gain[GAIN_LEVELS] = {
@@ -1183,12 +1262,62 @@ static const int16_t adaptive_cb_gain170[170 * 20] = {
-4534, -2487, -3932, -4166, -2113, -3341, -3540, -3070
};
-/* 0.65^i (Zero part) and 0.75^i (Pole part) scaled by 2^15 */
+/**
+ * 0.65^i (Zero part) and 0.75^i (Pole part) scaled by 2^15
+ */
static const int16_t postfilter_tbl[2][LPC_ORDER] = {
/* Zero */
- { 21299, 13844, 8999, 5849, 3802, 2471, 1606, 1044, 679, 441 },
+ {21299, 13844, 8999, 5849, 3802, 2471, 1606, 1044, 679, 441},
/* Pole */
- { 24576, 18432, 13824, 10368, 7776, 5832, 4374, 3281, 2460, 1845 }
+ {24576, 18432, 13824, 10368, 7776, 5832, 4374, 3281, 2460, 1845}
+};
+
+/**
+ * Hamming window coefficients scaled by 2^15
+ */
+static const int16_t hamming_window[LPC_FRAME] = {
+ 2621, 2631, 2659, 2705, 2770, 2853, 2955, 3074, 3212, 3367,
+ 3541, 3731, 3939, 4164, 4405, 4663, 4937, 5226, 5531, 5851,
+ 6186, 6534, 6897, 7273, 7661, 8062, 8475, 8899, 9334, 9780,
+ 10235, 10699, 11172, 11653, 12141, 12636, 13138, 13645, 14157, 14673,
+ 15193, 15716, 16242, 16769, 17298, 17827, 18356, 18884, 19411, 19935,
+ 20457, 20975, 21489, 21999, 22503, 23002, 23494, 23978, 24455, 24924,
+ 25384, 25834, 26274, 26704, 27122, 27529, 27924, 28306, 28675, 29031,
+ 29373, 29700, 30012, 30310, 30592, 30857, 31107, 31340, 31557, 31756,
+ 31938, 32102, 32249, 32377, 32488, 32580, 32654, 32710, 32747, 32766,
+ 32766, 32747, 32710, 32654, 32580, 32488, 32377, 32249, 32102, 31938,
+ 31756, 31557, 31340, 31107, 30857, 30592, 30310, 30012, 29700, 29373,
+ 29031, 28675, 28306, 27924, 27529, 27122, 26704, 26274, 25834, 25384,
+ 24924, 24455, 23978, 23494, 23002, 22503, 21999, 21489, 20975, 20457,
+ 19935, 19411, 18884, 18356, 17827, 17298, 16769, 16242, 15716, 15193,
+ 14673, 14157, 13645, 13138, 12636, 12141, 11653, 11172, 10699, 10235,
+ 9780, 9334, 8899, 8475, 8062, 7661, 7273, 6897, 6534, 6186,
+ 5851, 5531, 5226, 4937, 4663, 4405, 4164, 3939, 3731, 3541,
+ 3367, 3212, 3074, 2955, 2853, 2770, 2705, 2659, 2631, 2621
+};
+
+/**
+ * Binomial window coefficients scaled by 2^15
+ */
+static const int16_t binomial_window[LPC_ORDER] = {
+ 32749, 32695, 32604, 32477, 32315, 32118, 31887, 31622, 31324, 30995
+};
+
+/**
+ * 0.994^i scaled by 2^15
+ */
+static const int16_t bandwidth_expand[LPC_ORDER] = {
+ 32571, 32376, 32182, 31989, 31797, 31606, 31416, 31228, 31040, 30854
+};
+
+/**
+ * 0.5^i scaled by 2^15
+ */
+static const int16_t percept_flt_tbl[2][LPC_ORDER] = {
+ /* Zero part */
+ {29491, 26542, 23888, 21499, 19349, 17414, 15673, 14106, 12695, 11425},
+ /* Pole part */
+ {16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32}
};
static const int cng_adaptive_cb_lag[4] = { 1, 0, 1, 3 };
diff --git a/libavcodec/g726.c b/libavcodec/g726.c
index 9ad91f238e..5bbf897107 100644
--- a/libavcodec/g726.c
+++ b/libavcodec/g726.c
@@ -5,20 +5,20 @@
* This is a very straightforward rendition of the G.726
* Section 4 "Computational Details".
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <limits.h>
@@ -96,6 +96,7 @@ typedef struct G726Context {
int sez; /**< estimated second order prediction */
int y; /**< quantizer scaling factor for the next iteration */
int code_size;
+ int little_endian; /**< little-endian bitstream as used in aiff and Sun AU */
} G726Context;
static const int quant_tbl16[] = /**< 16kbit/s 2bits per sample */
@@ -297,7 +298,7 @@ static int16_t g726_encode(G726Context* c, int16_t sig)
{
uint8_t i;
- i = quant(c, sig/4 - c->se) & ((1<<c->code_size) - 1);
+ i = av_mod_uintp2(quant(c, sig/4 - c->se), c->code_size);
g726_decode(c, i);
return i;
}
@@ -347,10 +348,8 @@ static int g726_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
int i, ret, out_size;
out_size = (frame->nb_samples * c->code_size + 7) / 8;
- if ((ret = ff_alloc_packet(avpkt, out_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, out_size)) < 0)
return ret;
- }
init_put_bits(&pb, avpkt->data, avpkt->size);
for (i = 0; i < frame->nb_samples; i++)
@@ -370,7 +369,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass g726_class = {
.class_name = "g726",
.item_name = av_default_item_name,
.option = options,
@@ -393,19 +392,25 @@ AVCodec ff_adpcm_g726_encoder = {
.capabilities = CODEC_CAP_SMALL_LAST_FRAME,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
- .priv_class = &class,
+ .priv_class = &g726_class,
.defaults = defaults,
};
#endif
-#if CONFIG_ADPCM_G726_DECODER
+#if CONFIG_ADPCM_G726_DECODER || CONFIG_ADPCM_G726LE_DECODER
static av_cold int g726_decode_init(AVCodecContext *avctx)
{
G726Context* c = avctx->priv_data;
+ if(avctx->channels > 1){
+ avpriv_request_sample(avctx, "Decoding more than one channel");
+ return AVERROR_PATCHWELCOME;
+ }
avctx->channels = 1;
avctx->channel_layout = AV_CH_LAYOUT_MONO;
+ c->little_endian = !strcmp(avctx->codec->name, "g726le");
+
c->code_size = avctx->bits_per_coded_sample;
if (c->code_size < 2 || c->code_size > 5) {
av_log(avctx, AV_LOG_ERROR, "Invalid number of bits %d\n", c->code_size);
@@ -433,16 +438,16 @@ static int g726_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = out_samples;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t *)frame->data[0];
init_get_bits(&gb, buf, buf_size * 8);
while (out_samples--)
- *samples++ = g726_decode(c, get_bits(&gb, c->code_size));
+ *samples++ = g726_decode(c, c->little_endian ?
+ get_bits_le(&gb, c->code_size) :
+ get_bits(&gb, c->code_size));
if (get_bits_left(&gb) > 0)
av_log(avctx, AV_LOG_ERROR, "Frame invalidly split, missing parser?\n");
@@ -457,7 +462,9 @@ static void g726_decode_flush(AVCodecContext *avctx)
G726Context *c = avctx->priv_data;
g726_reset(c);
}
+#endif
+#if CONFIG_ADPCM_G726_DECODER
AVCodec ff_adpcm_g726_decoder = {
.name = "g726",
.long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM"),
@@ -470,3 +477,17 @@ AVCodec ff_adpcm_g726_decoder = {
.capabilities = CODEC_CAP_DR1,
};
#endif
+
+#if CONFIG_ADPCM_G726LE_DECODER
+AVCodec ff_adpcm_g726le_decoder = {
+ .name = "g726le",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_ADPCM_G726LE,
+ .priv_data_size = sizeof(G726Context),
+ .init = g726_decode_init,
+ .decode = g726_decode_frame,
+ .flush = g726_decode_flush,
+ .capabilities = CODEC_CAP_DR1,
+ .long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM little-endian"),
+};
+#endif
diff --git a/libavcodec/g729.h b/libavcodec/g729.h
new file mode 100644
index 0000000000..61683130a9
--- /dev/null
+++ b/libavcodec/g729.h
@@ -0,0 +1,29 @@
+/*
+ * G.729, G729 Annex D decoders
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_G729_H
+#define AVCODEC_G729_H
+
+/**
+ * subframe size
+ */
+#define SUBFRAME_SIZE 40
+
+#endif // AVCODEC_G729_H
diff --git a/libavcodec/g729data.h b/libavcodec/g729data.h
new file mode 100644
index 0000000000..365ca47ec6
--- /dev/null
+++ b/libavcodec/g729data.h
@@ -0,0 +1,382 @@
+/*
+ * data for G.729, G729 Annex D decoders
+ * Copyright (c) 2007 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_G729DATA_H
+#define AVCODEC_G729DATA_H
+
+#include <stdint.h>
+
+#define MA_NP 4 ///< Moving Average (MA) prediction order
+
+#define VQ_1ST_BITS 7 ///< first stage vector of quantizer (size in bits)
+#define VQ_2ND_BITS 5 ///< second stage vector of quantizer (size in bits)
+
+#define GC_1ST_IDX_BITS_8K 3 ///< gain codebook (first stage) index, 8k mode (size in bits)
+#define GC_2ND_IDX_BITS_8K 4 ///< gain codebook (second stage) index, 8k mode (size in bits)
+
+#define GC_1ST_IDX_BITS_6K4 3 ///< gain codebook (first stage) index, 6.4k mode (size in bits)
+#define GC_2ND_IDX_BITS_6K4 3 ///< gain codebook (second stage) index, 6.4k mode (size in bits)
+
+/**
+ * first stage LSP codebook
+ * (10-dimensional, with 128 entries (3.24 of G.729)
+ */
+static const int16_t cb_lsp_1st[1<<VQ_1ST_BITS][10] = { /* (2.13) */
+ { 1486, 2168, 3751, 9074, 12134, 13944, 17983, 19173, 21190, 21820},
+ { 1730, 2640, 3450, 4870, 6126, 7876, 15644, 17817, 20294, 21902},
+ { 1568, 2256, 3088, 4874, 11063, 13393, 18307, 19293, 21109, 21741},
+ { 1733, 2512, 3357, 4708, 6977, 10296, 17024, 17956, 19145, 20350},
+ { 1744, 2436, 3308, 8731, 10432, 12007, 15614, 16639, 21359, 21913},
+ { 1786, 2369, 3372, 4521, 6795, 12963, 17674, 18988, 20855, 21640},
+ { 1631, 2433, 3361, 6328, 10709, 12013, 13277, 13904, 19441, 21088},
+ { 1489, 2364, 3291, 6250, 9227, 10403, 13843, 15278, 17721, 21451},
+ { 1869, 2533, 3475, 4365, 9152, 14513, 15908, 17022, 20611, 21411},
+ { 2070, 3025, 4333, 5854, 7805, 9231, 10597, 16047, 20109, 21834},
+ { 1910, 2673, 3419, 4261, 11168, 15111, 16577, 17591, 19310, 20265},
+ { 1141, 1815, 2624, 4623, 6495, 9588, 13968, 16428, 19351, 21286},
+ { 2192, 3171, 4707, 5808, 10904, 12500, 14162, 15664, 21124, 21789},
+ { 1286, 1907, 2548, 3453, 9574, 11964, 15978, 17344, 19691, 22495},
+ { 1921, 2720, 4604, 6684, 11503, 12992, 14350, 15262, 16997, 20791},
+ { 2052, 2759, 3897, 5246, 6638, 10267, 15834, 16814, 18149, 21675},
+ { 1798, 2497, 5617, 11449, 13189, 14711, 17050, 18195, 20307, 21182},
+ { 1009, 1647, 2889, 5709, 9541, 12354, 15231, 18494, 20966, 22033},
+ { 3016, 3794, 5406, 7469, 12488, 13984, 15328, 16334, 19952, 20791},
+ { 2203, 3040, 3796, 5442, 11987, 13512, 14931, 16370, 17856, 18803},
+ { 2912, 4292, 7988, 9572, 11562, 13244, 14556, 16529, 20004, 21073},
+ { 2861, 3607, 5923, 7034, 9234, 12054, 13729, 18056, 20262, 20974},
+ { 3069, 4311, 5967, 7367, 11482, 12699, 14309, 16233, 18333, 19172},
+ { 2434, 3661, 4866, 5798, 10383, 11722, 13049, 15668, 18862, 19831},
+ { 2020, 2605, 3860, 9241, 13275, 14644, 16010, 17099, 19268, 20251},
+ { 1877, 2809, 3590, 4707, 11056, 12441, 15622, 17168, 18761, 19907},
+ { 2107, 2873, 3673, 5799, 13579, 14687, 15938, 17077, 18890, 19831},
+ { 1612, 2284, 2944, 3572, 8219, 13959, 15924, 17239, 18592, 20117},
+ { 2420, 3156, 6542, 10215, 12061, 13534, 15305, 16452, 18717, 19880},
+ { 1667, 2612, 3534, 5237, 10513, 11696, 12940, 16798, 18058, 19378},
+ { 2388, 3017, 4839, 9333, 11413, 12730, 15024, 16248, 17449, 18677},
+ { 1875, 2786, 4231, 6320, 8694, 10149, 11785, 17013, 18608, 19960},
+ { 679, 1411, 4654, 8006, 11446, 13249, 15763, 18127, 20361, 21567},
+ { 1838, 2596, 3578, 4608, 5650, 11274, 14355, 15886, 20579, 21754},
+ { 1303, 1955, 2395, 3322, 12023, 13764, 15883, 18077, 20180, 21232},
+ { 1438, 2102, 2663, 3462, 8328, 10362, 13763, 17248, 19732, 22344},
+ { 860, 1904, 6098, 7775, 9815, 12007, 14821, 16709, 19787, 21132},
+ { 1673, 2723, 3704, 6125, 7668, 9447, 13683, 14443, 20538, 21731},
+ { 1246, 1849, 2902, 4508, 7221, 12710, 14835, 16314, 19335, 22720},
+ { 1525, 2260, 3862, 5659, 7342, 11748, 13370, 14442, 18044, 21334},
+ { 1196, 1846, 3104, 7063, 10972, 12905, 14814, 17037, 19922, 22636},
+ { 2147, 3106, 4475, 6511, 8227, 9765, 10984, 12161, 18971, 21300},
+ { 1585, 2405, 2994, 4036, 11481, 13177, 14519, 15431, 19967, 21275},
+ { 1778, 2688, 3614, 4680, 9465, 11064, 12473, 16320, 19742, 20800},
+ { 1862, 2586, 3492, 6719, 11708, 13012, 14364, 16128, 19610, 20425},
+ { 1395, 2156, 2669, 3386, 10607, 12125, 13614, 16705, 18976, 21367},
+ { 1444, 2117, 3286, 6233, 9423, 12981, 14998, 15853, 17188, 21857},
+ { 2004, 2895, 3783, 4897, 6168, 7297, 12609, 16445, 19297, 21465},
+ { 1495, 2863, 6360, 8100, 11399, 14271, 15902, 17711, 20479, 22061},
+ { 2484, 3114, 5718, 7097, 8400, 12616, 14073, 14847, 20535, 21396},
+ { 2424, 3277, 5296, 6284, 11290, 12903, 16022, 17508, 19333, 20283},
+ { 2565, 3778, 5360, 6989, 8782, 10428, 14390, 15742, 17770, 21734},
+ { 2727, 3384, 6613, 9254, 10542, 12236, 14651, 15687, 20074, 21102},
+ { 1916, 2953, 6274, 8088, 9710, 10925, 12392, 16434, 20010, 21183},
+ { 3384, 4366, 5349, 7667, 11180, 12605, 13921, 15324, 19901, 20754},
+ { 3075, 4283, 5951, 7619, 9604, 11010, 12384, 14006, 20658, 21497},
+ { 1751, 2455, 5147, 9966, 11621, 13176, 14739, 16470, 20788, 21756},
+ { 1442, 2188, 3330, 6813, 8929, 12135, 14476, 15306, 19635, 20544},
+ { 2294, 2895, 4070, 8035, 12233, 13416, 14762, 17367, 18952, 19688},
+ { 1937, 2659, 4602, 6697, 9071, 12863, 14197, 15230, 16047, 18877},
+ { 2071, 2663, 4216, 9445, 10887, 12292, 13949, 14909, 19236, 20341},
+ { 1740, 2491, 3488, 8138, 9656, 11153, 13206, 14688, 20896, 21907},
+ { 2199, 2881, 4675, 8527, 10051, 11408, 14435, 15463, 17190, 20597},
+ { 1943, 2988, 4177, 6039, 7478, 8536, 14181, 15551, 17622, 21579},
+ { 1825, 3175, 7062, 9818, 12824, 15450, 18330, 19856, 21830, 22412},
+ { 2464, 3046, 4822, 5977, 7696, 15398, 16730, 17646, 20588, 21320},
+ { 2550, 3393, 5305, 6920, 10235, 14083, 18143, 19195, 20681, 21336},
+ { 3003, 3799, 5321, 6437, 7919, 11643, 15810, 16846, 18119, 18980},
+ { 3455, 4157, 6838, 8199, 9877, 12314, 15905, 16826, 19949, 20892},
+ { 3052, 3769, 4891, 5810, 6977, 10126, 14788, 15990, 19773, 20904},
+ { 3671, 4356, 5827, 6997, 8460, 12084, 14154, 14939, 19247, 20423},
+ { 2716, 3684, 5246, 6686, 8463, 10001, 12394, 14131, 16150, 19776},
+ { 1945, 2638, 4130, 7995, 14338, 15576, 17057, 18206, 20225, 20997},
+ { 2304, 2928, 4122, 4824, 5640, 13139, 15825, 16938, 20108, 21054},
+ { 1800, 2516, 3350, 5219, 13406, 15948, 17618, 18540, 20531, 21252},
+ { 1436, 2224, 2753, 4546, 9657, 11245, 15177, 16317, 17489, 19135},
+ { 2319, 2899, 4980, 6936, 8404, 13489, 15554, 16281, 20270, 20911},
+ { 2187, 2919, 4610, 5875, 7390, 12556, 14033, 16794, 20998, 21769},
+ { 2235, 2923, 5121, 6259, 8099, 13589, 15340, 16340, 17927, 20159},
+ { 1765, 2638, 3751, 5730, 7883, 10108, 13633, 15419, 16808, 18574},
+ { 3460, 5741, 9596, 11742, 14413, 16080, 18173, 19090, 20845, 21601},
+ { 3735, 4426, 6199, 7363, 9250, 14489, 16035, 17026, 19873, 20876},
+ { 3521, 4778, 6887, 8680, 12717, 14322, 15950, 18050, 20166, 21145},
+ { 2141, 2968, 6865, 8051, 10010, 13159, 14813, 15861, 17528, 18655},
+ { 4148, 6128, 9028, 10871, 12686, 14005, 15976, 17208, 19587, 20595},
+ { 4403, 5367, 6634, 8371, 10163, 11599, 14963, 16331, 17982, 18768},
+ { 4091, 5386, 6852, 8770, 11563, 13290, 15728, 16930, 19056, 20102},
+ { 2746, 3625, 5299, 7504, 10262, 11432, 13172, 15490, 16875, 17514},
+ { 2248, 3556, 8539, 10590, 12665, 14696, 16515, 17824, 20268, 21247},
+ { 1279, 1960, 3920, 7793, 10153, 14753, 16646, 18139, 20679, 21466},
+ { 2440, 3475, 6737, 8654, 12190, 14588, 17119, 17925, 19110, 19979},
+ { 1879, 2514, 4497, 7572, 10017, 14948, 16141, 16897, 18397, 19376},
+ { 2804, 3688, 7490, 10086, 11218, 12711, 16307, 17470, 20077, 21126},
+ { 2023, 2682, 3873, 8268, 10255, 11645, 15187, 17102, 18965, 19788},
+ { 2823, 3605, 5815, 8595, 10085, 11469, 16568, 17462, 18754, 19876},
+ { 2851, 3681, 5280, 7648, 9173, 10338, 14961, 16148, 17559, 18474},
+ { 1348, 2645, 5826, 8785, 10620, 12831, 16255, 18319, 21133, 22586},
+ { 2141, 3036, 4293, 6082, 7593, 10629, 17158, 18033, 21466, 22084},
+ { 1608, 2375, 3384, 6878, 9970, 11227, 16928, 17650, 20185, 21120},
+ { 2774, 3616, 5014, 6557, 7788, 8959, 17068, 18302, 19537, 20542},
+ { 1934, 4813, 6204, 7212, 8979, 11665, 15989, 17811, 20426, 21703},
+ { 2288, 3507, 5037, 6841, 8278, 9638, 15066, 16481, 21653, 22214},
+ { 2951, 3771, 4878, 7578, 9016, 10298, 14490, 15242, 20223, 20990},
+ { 3256, 4791, 6601, 7521, 8644, 9707, 13398, 16078, 19102, 20249},
+ { 1827, 2614, 3486, 6039, 12149, 13823, 16191, 17282, 21423, 22041},
+ { 1000, 1704, 3002, 6335, 8471, 10500, 14878, 16979, 20026, 22427},
+ { 1646, 2286, 3109, 7245, 11493, 12791, 16824, 17667, 18981, 20222},
+ { 1708, 2501, 3315, 6737, 8729, 9924, 16089, 17097, 18374, 19917},
+ { 2623, 3510, 4478, 5645, 9862, 11115, 15219, 18067, 19583, 20382},
+ { 2518, 3434, 4728, 6388, 8082, 9285, 13162, 18383, 19819, 20552},
+ { 1726, 2383, 4090, 6303, 7805, 12845, 14612, 17608, 19269, 20181},
+ { 2860, 3735, 4838, 6044, 7254, 8402, 14031, 16381, 18037, 19410},
+ { 4247, 5993, 7952, 9792, 12342, 14653, 17527, 18774, 20831, 21699},
+ { 3502, 4051, 5680, 6805, 8146, 11945, 16649, 17444, 20390, 21564},
+ { 3151, 4893, 5899, 7198, 11418, 13073, 15124, 17673, 20520, 21861},
+ { 3960, 4848, 5926, 7259, 8811, 10529, 15661, 16560, 18196, 20183},
+ { 4499, 6604, 8036, 9251, 10804, 12627, 15880, 17512, 20020, 21046},
+ { 4251, 5541, 6654, 8318, 9900, 11686, 15100, 17093, 20572, 21687},
+ { 3769, 5327, 7865, 9360, 10684, 11818, 13660, 15366, 18733, 19882},
+ { 3083, 3969, 6248, 8121, 9798, 10994, 12393, 13686, 17888, 19105},
+ { 2731, 4670, 7063, 9201, 11346, 13735, 16875, 18797, 20787, 22360},
+ { 1187, 2227, 4737, 7214, 9622, 12633, 15404, 17968, 20262, 23533},
+ { 1911, 2477, 3915, 10098, 11616, 12955, 16223, 17138, 19270, 20729},
+ { 1764, 2519, 3887, 6944, 9150, 12590, 16258, 16984, 17924, 18435},
+ { 1400, 3674, 7131, 8718, 10688, 12508, 15708, 17711, 19720, 21068},
+ { 2322, 3073, 4287, 8108, 9407, 10628, 15862, 16693, 19714, 21474},
+ { 2630, 3339, 4758, 8360, 10274, 11333, 12880, 17374, 19221, 19936},
+ { 1721, 2577, 5553, 7195, 8651, 10686, 15069, 16953, 18703, 19929}
+};
+
+/**
+ * second stage LSP codebook, high and low parts
+ (both 5-dimensional, with 32 entries (3.2.4 of G.729)
+ */
+static const int16_t cb_lsp_2nd[1<<VQ_2ND_BITS][10] = { /* (2.13) */
+ { -435, -815, -742, 1033, -518, 582, -1201, 829, 86, 385},
+ { -833, -891, 463, -8, -1251, 1450, 72, -231, 864, 661},
+ {-1021, 231, -306, 321, -220, -163, -526, -754, -1633, 267},
+ { 57, -198, -339, -33, -1468, 573, 796, -169, -631, 816},
+ { 171, -350, 294, 1660, 453, 519, 291, 159, -640, -1296},
+ { -701, -842, -58, 950, 892, 1549, 715, 527, -714, -193},
+ { 584, 31, -289, 356, -333, -457, 612, -283, -1381, -741},
+ { -109, -808, 231, 77, -87, -344, 1341, 1087, -654, -569},
+ { -859, 1236, 550, 854, 714, -543, -1752, -195, -98, -276},
+ { -877, -954, -1248, -299, 212, -235, -728, 949, 1517, 895},
+ { -77, 344, -620, 763, 413, 502, -362, -960, -483, 1386},
+ { -314, -307, -256, -1260, -429, 450, -466, -108, 1010, 2223},
+ { 711, 693, 521, 650, 1305, -28, -378, 744, -1005, 240},
+ { -112, -271, -500, 946, 1733, 271, -15, 909, -259, 1688},
+ { 575, -10, -468, -199, 1101, -1011, 581, -53, -747, 878},
+ { 145, -285, -1280, -398, 36, -498, -1377, 18, -444, 1483},
+ {-1133, -835, 1350, 1284, -95, 1015, -222, 443, 372, -354},
+ {-1459, -1237, 416, -213, 466, 669, 659, 1640, 932, 534},
+ { -15, 66, 468, 1019, -748, 1385, -182, -907, -721, -262},
+ { -338, 148, 1445, 75, -760, 569, 1247, 337, 416, -121},
+ { 389, 239, 1568, 981, 113, 369, -1003, -507, -587, -904},
+ { -312, -98, 949, 31, 1104, 72, -141, 1465, 63, -785},
+ { 1127, 584, 835, 277, -1159, 208, 301, -882, 117, -404},
+ { 539, -114, 856, -493, 223, -912, 623, -76, 276, -440},
+ { 2197, 2337, 1268, 670, 304, -267, -525, 140, 882, -139},
+ {-1596, 550, 801, -456, -56, -697, 865, 1060, 413, 446},
+ { 1154, 593, -77, 1237, -31, 581, -1037, -895, 669, 297},
+ { 397, 558, 203, -797, -919, 3, 692, -292, 1050, 782},
+ { 334, 1475, 632, -80, 48, -1061, -484, 362, -597, -852},
+ { -545, -330, -429, -680, 1133, -1182, -744, 1340, 262, 63},
+ { 1320, 827, -398, -576, 341, -774, -483, -1247, -70, 98},
+ { -163, 674, -11, -886, 531, -1125, -265, -242, 724, 934}
+};
+
+/**
+ * gain codebook (first stage), 8k mode (3.9.2 of G.729)
+ */
+static const int16_t cb_gain_1st_8k[1<<GC_1ST_IDX_BITS_8K][2] = { /*(0.14) (2.13) */
+ { 3242 , 9949 },
+ { 1551 , 2425 },
+ { 2678 , 27162 },
+ { 1921 , 9291 },
+ { 1831 , 5022 },
+ { 1 , 1516 },
+ { 356 , 14756 },
+ { 57 , 5404 },
+};
+
+/**
+ * gain codebook (second stage), 8k mode (3.9.2 of G.729)
+ */
+static const int16_t cb_gain_2nd_8k[1<<GC_2ND_IDX_BITS_8K][2] = { /*(1.14) (1.13) */
+ { 5142 , 592 },
+ { 17299 , 1861 },
+ { 6160 , 2395 },
+ { 16112 , 3392 },
+ { 826 , 2005 },
+ { 18973 , 5935 },
+ { 1994 , 0 },
+ { 15434 , 237 },
+ { 10573 , 2966 },
+ { 15132 , 4914 },
+ { 11569 , 1196 },
+ { 14194 , 1630 },
+ { 8091 , 4861 },
+ { 15161 , 14276 },
+ { 9120 , 525 },
+ { 13260 , 3256 },
+};
+
+/**
+ * gain codebook (first stage), 6.4k mode (D.3.9.2 of G.729)
+ */
+static const int16_t cb_gain_1st_6k4[1<<GC_1ST_IDX_BITS_6K4][2] =
+{ /*(0.14) (1.14)*/
+ { 5849, 0 },
+ { 3171, 9280 },
+ { 3617, 6747 },
+ { 4987, 22294 },
+ { 2929, 1078 },
+ { 6068, 6093 },
+ { 9425, 2731 },
+ { 3915, 12872 },
+};
+
+/**
+ * gain codebook (second stage), 6.4k mode (D.3.9.2 of G.729)
+ */
+static const int16_t cb_gain_2nd_6k4[1<<GC_2ND_IDX_BITS_6K4][2] =
+{ /*(1.14) (1.14)*/
+ { 0, 4175 },
+ {10828, 27602 },
+ {16423, 15724 },
+ { 4478, 7324 },
+ { 3988, 0 },
+ {10291, 11385 },
+ {11956, 10735 },
+ { 7876, 7821 },
+};
+
+/**
+ * 4th order Moving Average (MA) Predictor codebook (3.2.4 of G.729)
+ *
+ * float cb_ma_predictor_float[2][MA_NP][10] = {
+ * {
+ * {0.2570, 0.2780, 0.2800, 0.2736, 0.2757, 0.2764, 0.2675, 0.2678, 0.2779, 0.2647},
+ * {0.2142, 0.2194, 0.2331, 0.2230, 0.2272, 0.2252, 0.2148, 0.2123, 0.2115, 0.2096},
+ * {0.1670, 0.1523, 0.1567, 0.1580, 0.1601, 0.1569, 0.1589, 0.1555, 0.1474, 0.1571},
+ * {0.1238, 0.0925, 0.0798, 0.0923, 0.0890, 0.0828, 0.1010, 0.0988, 0.0872, 0.1060},
+ * },
+ * {
+ * {0.2360, 0.2405, 0.2499, 0.2495, 0.2517, 0.2591, 0.2636, 0.2625, 0.2551, 0.2310},
+ * {0.1285, 0.0925, 0.0779, 0.1060, 0.1183, 0.1176, 0.1277, 0.1268, 0.1193, 0.1211},
+ * {0.0981, 0.0589, 0.0401, 0.0654, 0.0761, 0.0728, 0.0841, 0.0826, 0.0776, 0.0891},
+ * {0.0923, 0.0486, 0.0287, 0.0498, 0.0526, 0.0482, 0.0621, 0.0636, 0.0584, 0.0794},
+ * },
+ * };
+ * 15
+ * cb_ma_predictor[j][k][i] = floor( 2 * cb_ma_predictor_float[j][k][i] )
+ *
+ * j=0..1, i=0..9, k=0..MA_NP-1
+ */
+static const int16_t cb_ma_predictor[2][MA_NP][10] = { /* (0.15) */
+ {
+ { 8421, 9109, 9175, 8965, 9034, 9057, 8765, 8775, 9106, 8673},
+ { 7018, 7189, 7638, 7307, 7444, 7379, 7038, 6956, 6930, 6868},
+ { 5472, 4990, 5134, 5177, 5246, 5141, 5206, 5095, 4830, 5147},
+ { 4056, 3031, 2614, 3024, 2916, 2713, 3309, 3237, 2857, 3473}
+ },
+ {
+ { 7733, 7880, 8188, 8175, 8247, 8490, 8637, 8601, 8359, 7569},
+ { 4210, 3031, 2552, 3473, 3876, 3853, 4184, 4154, 3909, 3968},
+ { 3214, 1930, 1313, 2143, 2493, 2385, 2755, 2706, 2542, 2919},
+ { 3024, 1592, 940, 1631, 1723, 1579, 2034, 2084, 1913, 2601}
+ }
+};
+
+/**
+ * 15 3
+ * cb_ma_predictor_sum[j][i] = floor( 2 * (1.0 - sum ( cb_ma_predictor_float[j][k][i] ) ) )
+ * k=0
+ * j=0..1, i=0..9
+ */
+static const int16_t cb_ma_predictor_sum[2][10] = { /* (0.15) */
+ { 7798, 8447, 8205, 8293, 8126, 8477, 8447, 8703, 9043, 8604},
+ {14585, 18333, 19772, 17344, 16426, 16459, 15155, 15220, 16043, 15708}
+};
+
+/**
+ * 12
+ * 2
+ * cb_ma_predictor_sum_inv[j][i] = floor(---------------------------------------------)
+ * 3
+ * 1.0 - sum ( cb_ma_predictor_float[j][k][i] )
+ * k=0
+ * j=0..1, i=0..9
+ */
+static const int16_t cb_ma_predictor_sum_inv[2][10] = { /* (3.12) */
+ {17210, 15888, 16357, 16183, 16516, 15833, 15888, 15421, 14840, 15597},
+ { 9202, 7320, 6788, 7738, 8170, 8154, 8856, 8818, 8366, 8544}
+};
+
+/**
+ * MA prediction coefficients (3.9.1 of G.729, near Equation 69)
+ */
+static const uint16_t ma_prediction_coeff[4] = { /* (0.13) */
+ 5571, 4751, 2785, 1556
+};
+
+/**
+ * initial LSP coefficients belongs to virtual frame preceding the
+ * first frame of the stream
+ */
+static const int16_t lsp_init[10]= { /* (0.15) */
+ 30000, 26000, 21000, 15000, 8000, 0, -8000,-15000,-21000,-26000
+};
+
+/**
+ * additional "phase" post-processing filter impulse response (D.6.2 of G.729)
+ *
+ * Table contains three impulse responses, correspond to
+ * different amounts of spreading.
+ */
+static const int16_t phase_filter[3][40] =
+{
+ { // maximum spreading (for noise-like segments)
+ 14690, 11518, 1268, -2762, -5672, 7514, -36, -2808, -3041, 4823,
+ 2952, -8425, 3785, 1455, 2179, -8638, 8051, -2104, -1455, 777,
+ 1108, -2386, 2254, -364, -675, -2104, 6046, -5682, 1072, 3123,
+ -5059, 5312, -2330, -3729, 6924, -3890, 675, -1776, 29, 10145,
+ },
+ { // medium spreading
+ 30274, 3831, -4037, 2972, -1049, -1003, 2477, -3044, 2815, -2232,
+ 1753, -1612, 1714, -1776, 1543, -1009, 429, -170, 472, -1265,
+ 2176, -2707, 2523, -1622, 344, 826, -1530, 1724, -1658, 1701,
+ -2064, 2644, -3061, 2897, -1979, 557, 780, -1370, 842, 655,
+ },
+ { // no spreading (for voiced speech)
+ 32767, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ }
+};
+#endif /* AVCODEC_G729DATA_H */
diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c
new file mode 100644
index 0000000000..ed717baf75
--- /dev/null
+++ b/libavcodec/g729dec.c
@@ -0,0 +1,726 @@
+/*
+ * G.729, G729 Annex D decoders
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <inttypes.h>
+#include <string.h>
+
+#include "avcodec.h"
+#include "libavutil/avutil.h"
+#include "get_bits.h"
+#include "audiodsp.h"
+#include "internal.h"
+
+
+#include "g729.h"
+#include "lsp.h"
+#include "celp_math.h"
+#include "celp_filters.h"
+#include "acelp_filters.h"
+#include "acelp_pitch_delay.h"
+#include "acelp_vectors.h"
+#include "g729data.h"
+#include "g729postfilter.h"
+
+/**
+ * minimum quantized LSF value (3.2.4)
+ * 0.005 in Q13
+ */
+#define LSFQ_MIN 40
+
+/**
+ * maximum quantized LSF value (3.2.4)
+ * 3.135 in Q13
+ */
+#define LSFQ_MAX 25681
+
+/**
+ * minimum LSF distance (3.2.4)
+ * 0.0391 in Q13
+ */
+#define LSFQ_DIFF_MIN 321
+
+/// interpolation filter length
+#define INTERPOL_LEN 11
+
+/**
+ * minimum gain pitch value (3.8, Equation 47)
+ * 0.2 in (1.14)
+ */
+#define SHARP_MIN 3277
+
+/**
+ * maximum gain pitch value (3.8, Equation 47)
+ * (EE) This does not comply with the specification.
+ * Specification says about 0.8, which should be
+ * 13107 in (1.14), but reference C code uses
+ * 13017 (equals to 0.7945) instead of it.
+ */
+#define SHARP_MAX 13017
+
+/**
+ * MR_ENERGY (mean removed energy) = mean_energy + 10 * log10(2^26 * subframe_size) in (7.13)
+ */
+#define MR_ENERGY 1018156
+
+#define DECISION_NOISE 0
+#define DECISION_INTERMEDIATE 1
+#define DECISION_VOICE 2
+
+typedef enum {
+ FORMAT_G729_8K = 0,
+ FORMAT_G729D_6K4,
+ FORMAT_COUNT,
+} G729Formats;
+
+typedef struct {
+ uint8_t ac_index_bits[2]; ///< adaptive codebook index for second subframe (size in bits)
+ uint8_t parity_bit; ///< parity bit for pitch delay
+ uint8_t gc_1st_index_bits; ///< gain codebook (first stage) index (size in bits)
+ uint8_t gc_2nd_index_bits; ///< gain codebook (second stage) index (size in bits)
+ uint8_t fc_signs_bits; ///< number of pulses in fixed-codebook vector
+ uint8_t fc_indexes_bits; ///< size (in bits) of fixed-codebook index entry
+} G729FormatDescription;
+
+typedef struct {
+ AudioDSPContext adsp;
+
+ /// past excitation signal buffer
+ int16_t exc_base[2*SUBFRAME_SIZE+PITCH_DELAY_MAX+INTERPOL_LEN];
+
+ int16_t* exc; ///< start of past excitation data in buffer
+ int pitch_delay_int_prev; ///< integer part of previous subframe's pitch delay (4.1.3)
+
+ /// (2.13) LSP quantizer outputs
+ int16_t past_quantizer_output_buf[MA_NP + 1][10];
+ int16_t* past_quantizer_outputs[MA_NP + 1];
+
+ int16_t lsfq[10]; ///< (2.13) quantized LSF coefficients from previous frame
+ int16_t lsp_buf[2][10]; ///< (0.15) LSP coefficients (previous and current frames) (3.2.5)
+ int16_t *lsp[2]; ///< pointers to lsp_buf
+
+ int16_t quant_energy[4]; ///< (5.10) past quantized energy
+
+ /// previous speech data for LP synthesis filter
+ int16_t syn_filter_data[10];
+
+
+ /// residual signal buffer (used in long-term postfilter)
+ int16_t residual[SUBFRAME_SIZE + RES_PREV_DATA_SIZE];
+
+ /// previous speech data for residual calculation filter
+ int16_t res_filter_data[SUBFRAME_SIZE+10];
+
+ /// previous speech data for short-term postfilter
+ int16_t pos_filter_data[SUBFRAME_SIZE+10];
+
+ /// (1.14) pitch gain of current and five previous subframes
+ int16_t past_gain_pitch[6];
+
+ /// (14.1) gain code from current and previous subframe
+ int16_t past_gain_code[2];
+
+ /// voice decision on previous subframe (0-noise, 1-intermediate, 2-voice), G.729D
+ int16_t voice_decision;
+
+ int16_t onset; ///< detected onset level (0-2)
+ int16_t was_periodic; ///< whether previous frame was declared as periodic or not (4.4)
+ int16_t ht_prev_data; ///< previous data for 4.2.3, equation 86
+ int gain_coeff; ///< (1.14) gain coefficient (4.2.4)
+ uint16_t rand_value; ///< random number generator value (4.4.4)
+ int ma_predictor_prev; ///< switched MA predictor of LSP quantizer from last good frame
+
+ /// (14.14) high-pass filter data (past input)
+ int hpf_f[2];
+
+ /// high-pass filter data (past output)
+ int16_t hpf_z[2];
+} G729Context;
+
+static const G729FormatDescription format_g729_8k = {
+ .ac_index_bits = {8,5},
+ .parity_bit = 1,
+ .gc_1st_index_bits = GC_1ST_IDX_BITS_8K,
+ .gc_2nd_index_bits = GC_2ND_IDX_BITS_8K,
+ .fc_signs_bits = 4,
+ .fc_indexes_bits = 13,
+};
+
+static const G729FormatDescription format_g729d_6k4 = {
+ .ac_index_bits = {8,4},
+ .parity_bit = 0,
+ .gc_1st_index_bits = GC_1ST_IDX_BITS_6K4,
+ .gc_2nd_index_bits = GC_2ND_IDX_BITS_6K4,
+ .fc_signs_bits = 2,
+ .fc_indexes_bits = 9,
+};
+
+/**
+ * @brief pseudo random number generator
+ */
+static inline uint16_t g729_prng(uint16_t value)
+{
+ return 31821 * value + 13849;
+}
+
+/**
+ * Get parity bit of bit 2..7
+ */
+static inline int get_parity(uint8_t value)
+{
+ return (0x6996966996696996ULL >> (value >> 2)) & 1;
+}
+
+/**
+ * Decodes LSF (Line Spectral Frequencies) from L0-L3 (3.2.4).
+ * @param[out] lsfq (2.13) quantized LSF coefficients
+ * @param[in,out] past_quantizer_outputs (2.13) quantizer outputs from previous frames
+ * @param ma_predictor switched MA predictor of LSP quantizer
+ * @param vq_1st first stage vector of quantizer
+ * @param vq_2nd_low second stage lower vector of LSP quantizer
+ * @param vq_2nd_high second stage higher vector of LSP quantizer
+ */
+static void lsf_decode(int16_t* lsfq, int16_t* past_quantizer_outputs[MA_NP + 1],
+ int16_t ma_predictor,
+ int16_t vq_1st, int16_t vq_2nd_low, int16_t vq_2nd_high)
+{
+ int i,j;
+ static const uint8_t min_distance[2]={10, 5}; //(2.13)
+ int16_t* quantizer_output = past_quantizer_outputs[MA_NP];
+
+ for (i = 0; i < 5; i++) {
+ quantizer_output[i] = cb_lsp_1st[vq_1st][i ] + cb_lsp_2nd[vq_2nd_low ][i ];
+ quantizer_output[i + 5] = cb_lsp_1st[vq_1st][i + 5] + cb_lsp_2nd[vq_2nd_high][i + 5];
+ }
+
+ for (j = 0; j < 2; j++) {
+ for (i = 1; i < 10; i++) {
+ int diff = (quantizer_output[i - 1] - quantizer_output[i] + min_distance[j]) >> 1;
+ if (diff > 0) {
+ quantizer_output[i - 1] -= diff;
+ quantizer_output[i ] += diff;
+ }
+ }
+ }
+
+ for (i = 0; i < 10; i++) {
+ int sum = quantizer_output[i] * cb_ma_predictor_sum[ma_predictor][i];
+ for (j = 0; j < MA_NP; j++)
+ sum += past_quantizer_outputs[j][i] * cb_ma_predictor[ma_predictor][j][i];
+
+ lsfq[i] = sum >> 15;
+ }
+
+ ff_acelp_reorder_lsf(lsfq, LSFQ_DIFF_MIN, LSFQ_MIN, LSFQ_MAX, 10);
+}
+
+/**
+ * Restores past LSP quantizer output using LSF from previous frame
+ * @param[in,out] lsfq (2.13) quantized LSF coefficients
+ * @param[in,out] past_quantizer_outputs (2.13) quantizer outputs from previous frames
+ * @param ma_predictor_prev MA predictor from previous frame
+ * @param lsfq_prev (2.13) quantized LSF coefficients from previous frame
+ */
+static void lsf_restore_from_previous(int16_t* lsfq,
+ int16_t* past_quantizer_outputs[MA_NP + 1],
+ int ma_predictor_prev)
+{
+ int16_t* quantizer_output = past_quantizer_outputs[MA_NP];
+ int i,k;
+
+ for (i = 0; i < 10; i++) {
+ int tmp = lsfq[i] << 15;
+
+ for (k = 0; k < MA_NP; k++)
+ tmp -= past_quantizer_outputs[k][i] * cb_ma_predictor[ma_predictor_prev][k][i];
+
+ quantizer_output[i] = ((tmp >> 15) * cb_ma_predictor_sum_inv[ma_predictor_prev][i]) >> 12;
+ }
+}
+
+/**
+ * Constructs new excitation signal and applies phase filter to it
+ * @param[out] out constructed speech signal
+ * @param in original excitation signal
+ * @param fc_cur (2.13) original fixed-codebook vector
+ * @param gain_code (14.1) gain code
+ * @param subframe_size length of the subframe
+ */
+static void g729d_get_new_exc(
+ int16_t* out,
+ const int16_t* in,
+ const int16_t* fc_cur,
+ int dstate,
+ int gain_code,
+ int subframe_size)
+{
+ int i;
+ int16_t fc_new[SUBFRAME_SIZE];
+
+ ff_celp_convolve_circ(fc_new, fc_cur, phase_filter[dstate], subframe_size);
+
+ for(i=0; i<subframe_size; i++)
+ {
+ out[i] = in[i];
+ out[i] -= (gain_code * fc_cur[i] + 0x2000) >> 14;
+ out[i] += (gain_code * fc_new[i] + 0x2000) >> 14;
+ }
+}
+
+/**
+ * Makes decision about onset in current subframe
+ * @param past_onset decision result of previous subframe
+ * @param past_gain_code gain code of current and previous subframe
+ *
+ * @return onset decision result for current subframe
+ */
+static int g729d_onset_decision(int past_onset, const int16_t* past_gain_code)
+{
+ if((past_gain_code[0] >> 1) > past_gain_code[1])
+ return 2;
+ else
+ return FFMAX(past_onset-1, 0);
+}
+
+/**
+ * Makes decision about voice presence in current subframe
+ * @param onset onset level
+ * @param prev_voice_decision voice decision result from previous subframe
+ * @param past_gain_pitch pitch gain of current and previous subframes
+ *
+ * @return voice decision result for current subframe
+ */
+static int16_t g729d_voice_decision(int onset, int prev_voice_decision, const int16_t* past_gain_pitch)
+{
+ int i, low_gain_pitch_cnt, voice_decision;
+
+ if(past_gain_pitch[0] >= 14745) // 0.9
+ voice_decision = DECISION_VOICE;
+ else if (past_gain_pitch[0] <= 9830) // 0.6
+ voice_decision = DECISION_NOISE;
+ else
+ voice_decision = DECISION_INTERMEDIATE;
+
+ for(i=0, low_gain_pitch_cnt=0; i<6; i++)
+ if(past_gain_pitch[i] < 9830)
+ low_gain_pitch_cnt++;
+
+ if(low_gain_pitch_cnt > 2 && !onset)
+ voice_decision = DECISION_NOISE;
+
+ if(!onset && voice_decision > prev_voice_decision + 1)
+ voice_decision--;
+
+ if(onset && voice_decision < DECISION_VOICE)
+ voice_decision++;
+
+ return voice_decision;
+}
+
+static int32_t scalarproduct_int16_c(const int16_t * v1, const int16_t * v2, int order)
+{
+ int res = 0;
+
+ while (order--)
+ res += *v1++ * *v2++;
+
+ return res;
+}
+
+static av_cold int decoder_init(AVCodecContext * avctx)
+{
+ G729Context* ctx = avctx->priv_data;
+ int i,k;
+
+ if (avctx->channels != 1) {
+ av_log(avctx, AV_LOG_ERROR, "Only mono sound is supported (requested channels: %d).\n", avctx->channels);
+ return AVERROR(EINVAL);
+ }
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+
+ /* Both 8kbit/s and 6.4kbit/s modes uses two subframes per frame. */
+ avctx->frame_size = SUBFRAME_SIZE << 1;
+
+ ctx->gain_coeff = 16384; // 1.0 in (1.14)
+
+ for (k = 0; k < MA_NP + 1; k++) {
+ ctx->past_quantizer_outputs[k] = ctx->past_quantizer_output_buf[k];
+ for (i = 1; i < 11; i++)
+ ctx->past_quantizer_outputs[k][i - 1] = (18717 * i) >> 3;
+ }
+
+ ctx->lsp[0] = ctx->lsp_buf[0];
+ ctx->lsp[1] = ctx->lsp_buf[1];
+ memcpy(ctx->lsp[0], lsp_init, 10 * sizeof(int16_t));
+
+ ctx->exc = &ctx->exc_base[PITCH_DELAY_MAX+INTERPOL_LEN];
+
+ ctx->pitch_delay_int_prev = PITCH_DELAY_MIN;
+
+ /* random seed initialization */
+ ctx->rand_value = 21845;
+
+ /* quantized prediction error */
+ for(i=0; i<4; i++)
+ ctx->quant_energy[i] = -14336; // -14 in (5.10)
+
+ ff_audiodsp_init(&ctx->adsp);
+ ctx->adsp.scalarproduct_int16 = scalarproduct_int16_c;
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr,
+ AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int16_t *out_frame;
+ GetBitContext gb;
+ const G729FormatDescription *format;
+ int frame_erasure = 0; ///< frame erasure detected during decoding
+ int bad_pitch = 0; ///< parity check failed
+ int i;
+ int16_t *tmp;
+ G729Formats packet_type;
+ G729Context *ctx = avctx->priv_data;
+ int16_t lp[2][11]; // (3.12)
+ uint8_t ma_predictor; ///< switched MA predictor of LSP quantizer
+ uint8_t quantizer_1st; ///< first stage vector of quantizer
+ uint8_t quantizer_2nd_lo; ///< second stage lower vector of quantizer (size in bits)
+ uint8_t quantizer_2nd_hi; ///< second stage higher vector of quantizer (size in bits)
+
+ int pitch_delay_int[2]; // pitch delay, integer part
+ int pitch_delay_3x; // pitch delay, multiplied by 3
+ int16_t fc[SUBFRAME_SIZE]; // fixed-codebook vector
+ int16_t synth[SUBFRAME_SIZE+10]; // fixed-codebook vector
+ int j, ret;
+ int gain_before, gain_after;
+ int is_periodic = 0; // whether one of the subframes is declared as periodic or not
+ AVFrame *frame = data;
+
+ frame->nb_samples = SUBFRAME_SIZE<<1;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+ out_frame = (int16_t*) frame->data[0];
+
+ if (buf_size % 10 == 0) {
+ packet_type = FORMAT_G729_8K;
+ format = &format_g729_8k;
+ //Reset voice decision
+ ctx->onset = 0;
+ ctx->voice_decision = DECISION_VOICE;
+ av_log(avctx, AV_LOG_DEBUG, "Packet type: %s\n", "G.729 @ 8kbit/s");
+ } else if (buf_size == 8) {
+ packet_type = FORMAT_G729D_6K4;
+ format = &format_g729d_6k4;
+ av_log(avctx, AV_LOG_DEBUG, "Packet type: %s\n", "G.729D @ 6.4kbit/s");
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Packet size %d is unknown.\n", buf_size);
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (i=0; i < buf_size; i++)
+ frame_erasure |= buf[i];
+ frame_erasure = !frame_erasure;
+
+ init_get_bits(&gb, buf, 8*buf_size);
+
+ ma_predictor = get_bits(&gb, 1);
+ quantizer_1st = get_bits(&gb, VQ_1ST_BITS);
+ quantizer_2nd_lo = get_bits(&gb, VQ_2ND_BITS);
+ quantizer_2nd_hi = get_bits(&gb, VQ_2ND_BITS);
+
+ if(frame_erasure)
+ lsf_restore_from_previous(ctx->lsfq, ctx->past_quantizer_outputs,
+ ctx->ma_predictor_prev);
+ else {
+ lsf_decode(ctx->lsfq, ctx->past_quantizer_outputs,
+ ma_predictor,
+ quantizer_1st, quantizer_2nd_lo, quantizer_2nd_hi);
+ ctx->ma_predictor_prev = ma_predictor;
+ }
+
+ tmp = ctx->past_quantizer_outputs[MA_NP];
+ memmove(ctx->past_quantizer_outputs + 1, ctx->past_quantizer_outputs,
+ MA_NP * sizeof(int16_t*));
+ ctx->past_quantizer_outputs[0] = tmp;
+
+ ff_acelp_lsf2lsp(ctx->lsp[1], ctx->lsfq, 10);
+
+ ff_acelp_lp_decode(&lp[0][0], &lp[1][0], ctx->lsp[1], ctx->lsp[0], 10);
+
+ FFSWAP(int16_t*, ctx->lsp[1], ctx->lsp[0]);
+
+ for (i = 0; i < 2; i++) {
+ int gain_corr_factor;
+
+ uint8_t ac_index; ///< adaptive codebook index
+ uint8_t pulses_signs; ///< fixed-codebook vector pulse signs
+ int fc_indexes; ///< fixed-codebook indexes
+ uint8_t gc_1st_index; ///< gain codebook (first stage) index
+ uint8_t gc_2nd_index; ///< gain codebook (second stage) index
+
+ ac_index = get_bits(&gb, format->ac_index_bits[i]);
+ if(!i && format->parity_bit)
+ bad_pitch = get_parity(ac_index) == get_bits1(&gb);
+ fc_indexes = get_bits(&gb, format->fc_indexes_bits);
+ pulses_signs = get_bits(&gb, format->fc_signs_bits);
+ gc_1st_index = get_bits(&gb, format->gc_1st_index_bits);
+ gc_2nd_index = get_bits(&gb, format->gc_2nd_index_bits);
+
+ if (frame_erasure)
+ pitch_delay_3x = 3 * ctx->pitch_delay_int_prev;
+ else if(!i) {
+ if (bad_pitch)
+ pitch_delay_3x = 3 * ctx->pitch_delay_int_prev;
+ else
+ pitch_delay_3x = ff_acelp_decode_8bit_to_1st_delay3(ac_index);
+ } else {
+ int pitch_delay_min = av_clip(ctx->pitch_delay_int_prev - 5,
+ PITCH_DELAY_MIN, PITCH_DELAY_MAX - 9);
+
+ if(packet_type == FORMAT_G729D_6K4)
+ pitch_delay_3x = ff_acelp_decode_4bit_to_2nd_delay3(ac_index, pitch_delay_min);
+ else
+ pitch_delay_3x = ff_acelp_decode_5_6_bit_to_2nd_delay3(ac_index, pitch_delay_min);
+ }
+
+ /* Round pitch delay to nearest (used everywhere except ff_acelp_interpolate). */
+ pitch_delay_int[i] = (pitch_delay_3x + 1) / 3;
+ if (pitch_delay_int[i] > PITCH_DELAY_MAX) {
+ av_log(avctx, AV_LOG_WARNING, "pitch_delay_int %d is too large\n", pitch_delay_int[i]);
+ pitch_delay_int[i] = PITCH_DELAY_MAX;
+ }
+
+ if (frame_erasure) {
+ ctx->rand_value = g729_prng(ctx->rand_value);
+ fc_indexes = av_mod_uintp2(ctx->rand_value, format->fc_indexes_bits);
+
+ ctx->rand_value = g729_prng(ctx->rand_value);
+ pulses_signs = ctx->rand_value;
+ }
+
+
+ memset(fc, 0, sizeof(int16_t) * SUBFRAME_SIZE);
+ switch (packet_type) {
+ case FORMAT_G729_8K:
+ ff_acelp_fc_pulse_per_track(fc, ff_fc_4pulses_8bits_tracks_13,
+ ff_fc_4pulses_8bits_track_4,
+ fc_indexes, pulses_signs, 3, 3);
+ break;
+ case FORMAT_G729D_6K4:
+ ff_acelp_fc_pulse_per_track(fc, ff_fc_2pulses_9bits_track1_gray,
+ ff_fc_2pulses_9bits_track2_gray,
+ fc_indexes, pulses_signs, 1, 4);
+ break;
+ }
+
+ /*
+ This filter enhances harmonic components of the fixed-codebook vector to
+ improve the quality of the reconstructed speech.
+
+ / fc_v[i], i < pitch_delay
+ fc_v[i] = <
+ \ fc_v[i] + gain_pitch * fc_v[i-pitch_delay], i >= pitch_delay
+ */
+ ff_acelp_weighted_vector_sum(fc + pitch_delay_int[i],
+ fc + pitch_delay_int[i],
+ fc, 1 << 14,
+ av_clip(ctx->past_gain_pitch[0], SHARP_MIN, SHARP_MAX),
+ 0, 14,
+ SUBFRAME_SIZE - pitch_delay_int[i]);
+
+ memmove(ctx->past_gain_pitch+1, ctx->past_gain_pitch, 5 * sizeof(int16_t));
+ ctx->past_gain_code[1] = ctx->past_gain_code[0];
+
+ if (frame_erasure) {
+ ctx->past_gain_pitch[0] = (29491 * ctx->past_gain_pitch[0]) >> 15; // 0.90 (0.15)
+ ctx->past_gain_code[0] = ( 2007 * ctx->past_gain_code[0] ) >> 11; // 0.98 (0.11)
+
+ gain_corr_factor = 0;
+ } else {
+ if (packet_type == FORMAT_G729D_6K4) {
+ ctx->past_gain_pitch[0] = cb_gain_1st_6k4[gc_1st_index][0] +
+ cb_gain_2nd_6k4[gc_2nd_index][0];
+ gain_corr_factor = cb_gain_1st_6k4[gc_1st_index][1] +
+ cb_gain_2nd_6k4[gc_2nd_index][1];
+
+ /* Without check below overflow can occur in ff_acelp_update_past_gain.
+ It is not issue for G.729, because gain_corr_factor in it's case is always
+ greater than 1024, while in G.729D it can be even zero. */
+ gain_corr_factor = FFMAX(gain_corr_factor, 1024);
+#ifndef G729_BITEXACT
+ gain_corr_factor >>= 1;
+#endif
+ } else {
+ ctx->past_gain_pitch[0] = cb_gain_1st_8k[gc_1st_index][0] +
+ cb_gain_2nd_8k[gc_2nd_index][0];
+ gain_corr_factor = cb_gain_1st_8k[gc_1st_index][1] +
+ cb_gain_2nd_8k[gc_2nd_index][1];
+ }
+
+ /* Decode the fixed-codebook gain. */
+ ctx->past_gain_code[0] = ff_acelp_decode_gain_code(&ctx->adsp, gain_corr_factor,
+ fc, MR_ENERGY,
+ ctx->quant_energy,
+ ma_prediction_coeff,
+ SUBFRAME_SIZE, 4);
+#ifdef G729_BITEXACT
+ /*
+ This correction required to get bit-exact result with
+ reference code, because gain_corr_factor in G.729D is
+ two times larger than in original G.729.
+
+ If bit-exact result is not issue then gain_corr_factor
+ can be simpler divided by 2 before call to g729_get_gain_code
+ instead of using correction below.
+ */
+ if (packet_type == FORMAT_G729D_6K4) {
+ gain_corr_factor >>= 1;
+ ctx->past_gain_code[0] >>= 1;
+ }
+#endif
+ }
+ ff_acelp_update_past_gain(ctx->quant_energy, gain_corr_factor, 2, frame_erasure);
+
+ /* Routine requires rounding to lowest. */
+ ff_acelp_interpolate(ctx->exc + i * SUBFRAME_SIZE,
+ ctx->exc + i * SUBFRAME_SIZE - pitch_delay_3x / 3,
+ ff_acelp_interp_filter, 6,
+ (pitch_delay_3x % 3) << 1,
+ 10, SUBFRAME_SIZE);
+
+ ff_acelp_weighted_vector_sum(ctx->exc + i * SUBFRAME_SIZE,
+ ctx->exc + i * SUBFRAME_SIZE, fc,
+ (!ctx->was_periodic && frame_erasure) ? 0 : ctx->past_gain_pitch[0],
+ ( ctx->was_periodic && frame_erasure) ? 0 : ctx->past_gain_code[0],
+ 1 << 13, 14, SUBFRAME_SIZE);
+
+ memcpy(synth, ctx->syn_filter_data, 10 * sizeof(int16_t));
+
+ if (ff_celp_lp_synthesis_filter(
+ synth+10,
+ &lp[i][1],
+ ctx->exc + i * SUBFRAME_SIZE,
+ SUBFRAME_SIZE,
+ 10,
+ 1,
+ 0,
+ 0x800))
+ /* Overflow occurred, downscale excitation signal... */
+ for (j = 0; j < 2 * SUBFRAME_SIZE + PITCH_DELAY_MAX + INTERPOL_LEN; j++)
+ ctx->exc_base[j] >>= 2;
+
+ /* ... and make synthesis again. */
+ if (packet_type == FORMAT_G729D_6K4) {
+ int16_t exc_new[SUBFRAME_SIZE];
+
+ ctx->onset = g729d_onset_decision(ctx->onset, ctx->past_gain_code);
+ ctx->voice_decision = g729d_voice_decision(ctx->onset, ctx->voice_decision, ctx->past_gain_pitch);
+
+ g729d_get_new_exc(exc_new, ctx->exc + i * SUBFRAME_SIZE, fc, ctx->voice_decision, ctx->past_gain_code[0], SUBFRAME_SIZE);
+
+ ff_celp_lp_synthesis_filter(
+ synth+10,
+ &lp[i][1],
+ exc_new,
+ SUBFRAME_SIZE,
+ 10,
+ 0,
+ 0,
+ 0x800);
+ } else {
+ ff_celp_lp_synthesis_filter(
+ synth+10,
+ &lp[i][1],
+ ctx->exc + i * SUBFRAME_SIZE,
+ SUBFRAME_SIZE,
+ 10,
+ 0,
+ 0,
+ 0x800);
+ }
+ /* Save data (without postfilter) for use in next subframe. */
+ memcpy(ctx->syn_filter_data, synth+SUBFRAME_SIZE, 10 * sizeof(int16_t));
+
+ /* Calculate gain of unfiltered signal for use in AGC. */
+ gain_before = 0;
+ for (j = 0; j < SUBFRAME_SIZE; j++)
+ gain_before += FFABS(synth[j+10]);
+
+ /* Call postfilter and also update voicing decision for use in next frame. */
+ ff_g729_postfilter(
+ &ctx->adsp,
+ &ctx->ht_prev_data,
+ &is_periodic,
+ &lp[i][0],
+ pitch_delay_int[0],
+ ctx->residual,
+ ctx->res_filter_data,
+ ctx->pos_filter_data,
+ synth+10,
+ SUBFRAME_SIZE);
+
+ /* Calculate gain of filtered signal for use in AGC. */
+ gain_after = 0;
+ for(j=0; j<SUBFRAME_SIZE; j++)
+ gain_after += FFABS(synth[j+10]);
+
+ ctx->gain_coeff = ff_g729_adaptive_gain_control(
+ gain_before,
+ gain_after,
+ synth+10,
+ SUBFRAME_SIZE,
+ ctx->gain_coeff);
+
+ if (frame_erasure)
+ ctx->pitch_delay_int_prev = FFMIN(ctx->pitch_delay_int_prev + 1, PITCH_DELAY_MAX);
+ else
+ ctx->pitch_delay_int_prev = pitch_delay_int[i];
+
+ memcpy(synth+8, ctx->hpf_z, 2*sizeof(int16_t));
+ ff_acelp_high_pass_filter(
+ out_frame + i*SUBFRAME_SIZE,
+ ctx->hpf_f,
+ synth+10,
+ SUBFRAME_SIZE);
+ memcpy(ctx->hpf_z, synth+8+SUBFRAME_SIZE, 2*sizeof(int16_t));
+ }
+
+ ctx->was_periodic = is_periodic;
+
+ /* Save signal for use in next frame. */
+ memmove(ctx->exc_base, ctx->exc_base + 2 * SUBFRAME_SIZE, (PITCH_DELAY_MAX+INTERPOL_LEN)*sizeof(int16_t));
+
+ *got_frame_ptr = 1;
+ return packet_type == FORMAT_G729_8K ? 10 : 8;
+}
+
+AVCodec ff_g729_decoder = {
+ .name = "g729",
+ .long_name = NULL_IF_CONFIG_SMALL("G.729"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_G729,
+ .priv_data_size = sizeof(G729Context),
+ .init = decoder_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_SUBFRAMES | CODEC_CAP_DR1,
+};
diff --git a/libavcodec/g729postfilter.c b/libavcodec/g729postfilter.c
new file mode 100644
index 0000000000..9a775c47b2
--- /dev/null
+++ b/libavcodec/g729postfilter.c
@@ -0,0 +1,610 @@
+/*
+ * G.729, G729 Annex D postfilter
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <inttypes.h>
+#include <limits.h>
+
+#include "avcodec.h"
+#include "g729.h"
+#include "acelp_pitch_delay.h"
+#include "g729postfilter.h"
+#include "celp_math.h"
+#include "acelp_filters.h"
+#include "acelp_vectors.h"
+#include "celp_filters.h"
+
+#define FRAC_BITS 15
+#include "mathops.h"
+
+/**
+ * short interpolation filter (of length 33, according to spec)
+ * for computing signal with non-integer delay
+ */
+static const int16_t ff_g729_interp_filt_short[(ANALYZED_FRAC_DELAYS+1)*SHORT_INT_FILT_LEN] = {
+ 0, 31650, 28469, 23705, 18050, 12266, 7041, 2873,
+ 0, -1597, -2147, -1992, -1492, -933, -484, -188,
+};
+
+/**
+ * long interpolation filter (of length 129, according to spec)
+ * for computing signal with non-integer delay
+ */
+static const int16_t ff_g729_interp_filt_long[(ANALYZED_FRAC_DELAYS+1)*LONG_INT_FILT_LEN] = {
+ 0, 31915, 29436, 25569, 20676, 15206, 9639, 4439,
+ 0, -3390, -5579, -6549, -6414, -5392, -3773, -1874,
+ 0, 1595, 2727, 3303, 3319, 2850, 2030, 1023,
+ 0, -887, -1527, -1860, -1876, -1614, -1150, -579,
+ 0, 501, 859, 1041, 1044, 892, 631, 315,
+ 0, -266, -453, -543, -538, -455, -317, -156,
+ 0, 130, 218, 258, 253, 212, 147, 72,
+ 0, -59, -101, -122, -123, -106, -77, -40,
+};
+
+/**
+ * formant_pp_factor_num_pow[i] = FORMANT_PP_FACTOR_NUM^(i+1)
+ */
+static const int16_t formant_pp_factor_num_pow[10]= {
+ /* (0.15) */
+ 18022, 9912, 5451, 2998, 1649, 907, 499, 274, 151, 83
+};
+
+/**
+ * formant_pp_factor_den_pow[i] = FORMANT_PP_FACTOR_DEN^(i+1)
+ */
+static const int16_t formant_pp_factor_den_pow[10] = {
+ /* (0.15) */
+ 22938, 16057, 11240, 7868, 5508, 3856, 2699, 1889, 1322, 925
+};
+
+/**
+ * \brief Residual signal calculation (4.2.1 if G.729)
+ * \param out [out] output data filtered through A(z/FORMANT_PP_FACTOR_NUM)
+ * \param filter_coeffs (3.12) A(z/FORMANT_PP_FACTOR_NUM) filter coefficients
+ * \param in input speech data to process
+ * \param subframe_size size of one subframe
+ *
+ * \note in buffer must contain 10 items of previous speech data before top of the buffer
+ * \remark It is safe to pass the same buffer for input and output.
+ */
+static void residual_filter(int16_t* out, const int16_t* filter_coeffs, const int16_t* in,
+ int subframe_size)
+{
+ int i, n;
+
+ for (n = subframe_size - 1; n >= 0; n--) {
+ int sum = 0x800;
+ for (i = 0; i < 10; i++)
+ sum += filter_coeffs[i] * in[n - i - 1];
+
+ out[n] = in[n] + (sum >> 12);
+ }
+}
+
+/**
+ * \brief long-term postfilter (4.2.1)
+ * \param dsp initialized DSP context
+ * \param pitch_delay_int integer part of the pitch delay in the first subframe
+ * \param residual filtering input data
+ * \param residual_filt [out] speech signal with applied A(z/FORMANT_PP_FACTOR_NUM) filter
+ * \param subframe_size size of subframe
+ *
+ * \return 0 if long-term prediction gain is less than 3dB, 1 - otherwise
+ */
+static int16_t long_term_filter(AudioDSPContext *adsp, int pitch_delay_int,
+ const int16_t* residual, int16_t *residual_filt,
+ int subframe_size)
+{
+ int i, k, tmp, tmp2;
+ int sum;
+ int L_temp0;
+ int L_temp1;
+ int64_t L64_temp0;
+ int64_t L64_temp1;
+ int16_t shift;
+ int corr_int_num, corr_int_den;
+
+ int ener;
+ int16_t sh_ener;
+
+ int16_t gain_num,gain_den; //selected signal's gain numerator and denominator
+ int16_t sh_gain_num, sh_gain_den;
+ int gain_num_square;
+
+ int16_t gain_long_num,gain_long_den; //filtered through long interpolation filter signal's gain numerator and denominator
+ int16_t sh_gain_long_num, sh_gain_long_den;
+
+ int16_t best_delay_int, best_delay_frac;
+
+ int16_t delayed_signal_offset;
+ int lt_filt_factor_a, lt_filt_factor_b;
+
+ int16_t * selected_signal;
+ const int16_t * selected_signal_const; //Necessary to avoid compiler warning
+
+ int16_t sig_scaled[SUBFRAME_SIZE + RES_PREV_DATA_SIZE];
+ int16_t delayed_signal[ANALYZED_FRAC_DELAYS][SUBFRAME_SIZE+1];
+ int corr_den[ANALYZED_FRAC_DELAYS][2];
+
+ tmp = 0;
+ for(i=0; i<subframe_size + RES_PREV_DATA_SIZE; i++)
+ tmp |= FFABS(residual[i]);
+
+ if(!tmp)
+ shift = 3;
+ else
+ shift = av_log2(tmp) - 11;
+
+ if (shift > 0)
+ for (i = 0; i < subframe_size + RES_PREV_DATA_SIZE; i++)
+ sig_scaled[i] = residual[i] >> shift;
+ else
+ for (i = 0; i < subframe_size + RES_PREV_DATA_SIZE; i++)
+ sig_scaled[i] = residual[i] << -shift;
+
+ /* Start of best delay searching code */
+ gain_num = 0;
+
+ ener = adsp->scalarproduct_int16(sig_scaled + RES_PREV_DATA_SIZE,
+ sig_scaled + RES_PREV_DATA_SIZE,
+ subframe_size);
+ if (ener) {
+ sh_ener = FFMAX(av_log2(ener) - 14, 0);
+ ener >>= sh_ener;
+ /* Search for best pitch delay.
+
+ sum{ r(n) * r(k,n) ] }^2
+ R'(k)^2 := -------------------------
+ sum{ r(k,n) * r(k,n) }
+
+
+ R(T) := sum{ r(n) * r(n-T) ] }
+
+
+ where
+ r(n-T) is integer delayed signal with delay T
+ r(k,n) is non-integer delayed signal with integer delay best_delay
+ and fractional delay k */
+
+ /* Find integer delay best_delay which maximizes correlation R(T).
+
+ This is also equals to numerator of R'(0),
+ since the fine search (second step) is done with 1/8
+ precision around best_delay. */
+ corr_int_num = 0;
+ best_delay_int = pitch_delay_int - 1;
+ for (i = pitch_delay_int - 1; i <= pitch_delay_int + 1; i++) {
+ sum = adsp->scalarproduct_int16(sig_scaled + RES_PREV_DATA_SIZE,
+ sig_scaled + RES_PREV_DATA_SIZE - i,
+ subframe_size);
+ if (sum > corr_int_num) {
+ corr_int_num = sum;
+ best_delay_int = i;
+ }
+ }
+ if (corr_int_num) {
+ /* Compute denominator of pseudo-normalized correlation R'(0). */
+ corr_int_den = adsp->scalarproduct_int16(sig_scaled - best_delay_int + RES_PREV_DATA_SIZE,
+ sig_scaled - best_delay_int + RES_PREV_DATA_SIZE,
+ subframe_size);
+
+ /* Compute signals with non-integer delay k (with 1/8 precision),
+ where k is in [0;6] range.
+ Entire delay is qual to best_delay+(k+1)/8
+ This is archieved by applying an interpolation filter of
+ legth 33 to source signal. */
+ for (k = 0; k < ANALYZED_FRAC_DELAYS; k++) {
+ ff_acelp_interpolate(&delayed_signal[k][0],
+ &sig_scaled[RES_PREV_DATA_SIZE - best_delay_int],
+ ff_g729_interp_filt_short,
+ ANALYZED_FRAC_DELAYS+1,
+ 8 - k - 1,
+ SHORT_INT_FILT_LEN,
+ subframe_size + 1);
+ }
+
+ /* Compute denominator of pseudo-normalized correlation R'(k).
+
+ corr_den[k][0] is square root of R'(k) denominator, for int(T) == int(T0)
+ corr_den[k][1] is square root of R'(k) denominator, for int(T) == int(T0)+1
+
+ Also compute maximum value of above denominators over all k. */
+ tmp = corr_int_den;
+ for (k = 0; k < ANALYZED_FRAC_DELAYS; k++) {
+ sum = adsp->scalarproduct_int16(&delayed_signal[k][1],
+ &delayed_signal[k][1],
+ subframe_size - 1);
+ corr_den[k][0] = sum + delayed_signal[k][0 ] * delayed_signal[k][0 ];
+ corr_den[k][1] = sum + delayed_signal[k][subframe_size] * delayed_signal[k][subframe_size];
+
+ tmp = FFMAX3(tmp, corr_den[k][0], corr_den[k][1]);
+ }
+
+ sh_gain_den = av_log2(tmp) - 14;
+ if (sh_gain_den >= 0) {
+
+ sh_gain_num = FFMAX(sh_gain_den, sh_ener);
+ /* Loop through all k and find delay that maximizes
+ R'(k) correlation.
+ Search is done in [int(T0)-1; intT(0)+1] range
+ with 1/8 precision. */
+ delayed_signal_offset = 1;
+ best_delay_frac = 0;
+ gain_den = corr_int_den >> sh_gain_den;
+ gain_num = corr_int_num >> sh_gain_num;
+ gain_num_square = gain_num * gain_num;
+ for (k = 0; k < ANALYZED_FRAC_DELAYS; k++) {
+ for (i = 0; i < 2; i++) {
+ int16_t gain_num_short, gain_den_short;
+ int gain_num_short_square;
+ /* Compute numerator of pseudo-normalized
+ correlation R'(k). */
+ sum = adsp->scalarproduct_int16(&delayed_signal[k][i],
+ sig_scaled + RES_PREV_DATA_SIZE,
+ subframe_size);
+ gain_num_short = FFMAX(sum >> sh_gain_num, 0);
+
+ /*
+ gain_num_short_square gain_num_square
+ R'(T)^2 = -----------------------, max R'(T)^2= --------------
+ den gain_den
+ */
+ gain_num_short_square = gain_num_short * gain_num_short;
+ gain_den_short = corr_den[k][i] >> sh_gain_den;
+
+ tmp = MULL(gain_num_short_square, gain_den, FRAC_BITS);
+ tmp2 = MULL(gain_num_square, gain_den_short, FRAC_BITS);
+
+ // R'(T)^2 > max R'(T)^2
+ if (tmp > tmp2) {
+ gain_num = gain_num_short;
+ gain_den = gain_den_short;
+ gain_num_square = gain_num_short_square;
+ delayed_signal_offset = i;
+ best_delay_frac = k + 1;
+ }
+ }
+ }
+
+ /*
+ R'(T)^2
+ 2 * --------- < 1
+ R(0)
+ */
+ L64_temp0 = (int64_t)gain_num_square << ((sh_gain_num << 1) + 1);
+ L64_temp1 = ((int64_t)gain_den * ener) << (sh_gain_den + sh_ener);
+ if (L64_temp0 < L64_temp1)
+ gain_num = 0;
+ } // if(sh_gain_den >= 0)
+ } // if(corr_int_num)
+ } // if(ener)
+ /* End of best delay searching code */
+
+ if (!gain_num) {
+ memcpy(residual_filt, residual + RES_PREV_DATA_SIZE, subframe_size * sizeof(int16_t));
+
+ /* Long-term prediction gain is less than 3dB. Long-term postfilter is disabled. */
+ return 0;
+ }
+ if (best_delay_frac) {
+ /* Recompute delayed signal with an interpolation filter of length 129. */
+ ff_acelp_interpolate(residual_filt,
+ &sig_scaled[RES_PREV_DATA_SIZE - best_delay_int + delayed_signal_offset],
+ ff_g729_interp_filt_long,
+ ANALYZED_FRAC_DELAYS + 1,
+ 8 - best_delay_frac,
+ LONG_INT_FILT_LEN,
+ subframe_size + 1);
+ /* Compute R'(k) correlation's numerator. */
+ sum = adsp->scalarproduct_int16(residual_filt,
+ sig_scaled + RES_PREV_DATA_SIZE,
+ subframe_size);
+
+ if (sum < 0) {
+ gain_long_num = 0;
+ sh_gain_long_num = 0;
+ } else {
+ tmp = FFMAX(av_log2(sum) - 14, 0);
+ sum >>= tmp;
+ gain_long_num = sum;
+ sh_gain_long_num = tmp;
+ }
+
+ /* Compute R'(k) correlation's denominator. */
+ sum = adsp->scalarproduct_int16(residual_filt, residual_filt, subframe_size);
+
+ tmp = FFMAX(av_log2(sum) - 14, 0);
+ sum >>= tmp;
+ gain_long_den = sum;
+ sh_gain_long_den = tmp;
+
+ /* Select between original and delayed signal.
+ Delayed signal will be selected if it increases R'(k)
+ correlation. */
+ L_temp0 = gain_num * gain_num;
+ L_temp0 = MULL(L_temp0, gain_long_den, FRAC_BITS);
+
+ L_temp1 = gain_long_num * gain_long_num;
+ L_temp1 = MULL(L_temp1, gain_den, FRAC_BITS);
+
+ tmp = ((sh_gain_long_num - sh_gain_num) << 1) - (sh_gain_long_den - sh_gain_den);
+ if (tmp > 0)
+ L_temp0 >>= tmp;
+ else
+ L_temp1 >>= -tmp;
+
+ /* Check if longer filter increases the values of R'(k). */
+ if (L_temp1 > L_temp0) {
+ /* Select long filter. */
+ selected_signal = residual_filt;
+ gain_num = gain_long_num;
+ gain_den = gain_long_den;
+ sh_gain_num = sh_gain_long_num;
+ sh_gain_den = sh_gain_long_den;
+ } else
+ /* Select short filter. */
+ selected_signal = &delayed_signal[best_delay_frac-1][delayed_signal_offset];
+
+ /* Rescale selected signal to original value. */
+ if (shift > 0)
+ for (i = 0; i < subframe_size; i++)
+ selected_signal[i] <<= shift;
+ else
+ for (i = 0; i < subframe_size; i++)
+ selected_signal[i] >>= -shift;
+
+ /* necessary to avoid compiler warning */
+ selected_signal_const = selected_signal;
+ } // if(best_delay_frac)
+ else
+ selected_signal_const = residual + RES_PREV_DATA_SIZE - (best_delay_int + 1 - delayed_signal_offset);
+#ifdef G729_BITEXACT
+ tmp = sh_gain_num - sh_gain_den;
+ if (tmp > 0)
+ gain_den >>= tmp;
+ else
+ gain_num >>= -tmp;
+
+ if (gain_num > gain_den)
+ lt_filt_factor_a = MIN_LT_FILT_FACTOR_A;
+ else {
+ gain_num >>= 2;
+ gain_den >>= 1;
+ lt_filt_factor_a = (gain_den << 15) / (gain_den + gain_num);
+ }
+#else
+ L64_temp0 = (((int64_t)gain_num) << sh_gain_num) >> 1;
+ L64_temp1 = ((int64_t)gain_den) << sh_gain_den;
+ lt_filt_factor_a = FFMAX((L64_temp1 << 15) / (L64_temp1 + L64_temp0), MIN_LT_FILT_FACTOR_A);
+#endif
+
+ /* Filter through selected filter. */
+ lt_filt_factor_b = 32767 - lt_filt_factor_a + 1;
+
+ ff_acelp_weighted_vector_sum(residual_filt, residual + RES_PREV_DATA_SIZE,
+ selected_signal_const,
+ lt_filt_factor_a, lt_filt_factor_b,
+ 1<<14, 15, subframe_size);
+
+ // Long-term prediction gain is larger than 3dB.
+ return 1;
+}
+
+/**
+ * \brief Calculate reflection coefficient for tilt compensation filter (4.2.3).
+ * \param dsp initialized DSP context
+ * \param lp_gn (3.12) coefficients of A(z/FORMANT_PP_FACTOR_NUM) filter
+ * \param lp_gd (3.12) coefficients of A(z/FORMANT_PP_FACTOR_DEN) filter
+ * \param speech speech to update
+ * \param subframe_size size of subframe
+ *
+ * \return (3.12) reflection coefficient
+ *
+ * \remark The routine also calculates the gain term for the short-term
+ * filter (gf) and multiplies the speech data by 1/gf.
+ *
+ * \note All members of lp_gn, except 10-19 must be equal to zero.
+ */
+static int16_t get_tilt_comp(AudioDSPContext *adsp, int16_t *lp_gn,
+ const int16_t *lp_gd, int16_t* speech,
+ int subframe_size)
+{
+ int rh1,rh0; // (3.12)
+ int temp;
+ int i;
+ int gain_term;
+
+ lp_gn[10] = 4096; //1.0 in (3.12)
+
+ /* Apply 1/A(z/FORMANT_PP_FACTOR_DEN) filter to hf. */
+ ff_celp_lp_synthesis_filter(lp_gn + 11, lp_gd + 1, lp_gn + 11, 22, 10, 0, 0, 0x800);
+ /* Now lp_gn (starting with 10) contains impulse response
+ of A(z/FORMANT_PP_FACTOR_NUM)/A(z/FORMANT_PP_FACTOR_DEN) filter. */
+
+ rh0 = adsp->scalarproduct_int16(lp_gn + 10, lp_gn + 10, 20);
+ rh1 = adsp->scalarproduct_int16(lp_gn + 10, lp_gn + 11, 20);
+
+ /* downscale to avoid overflow */
+ temp = av_log2(rh0) - 14;
+ if (temp > 0) {
+ rh0 >>= temp;
+ rh1 >>= temp;
+ }
+
+ if (FFABS(rh1) > rh0 || !rh0)
+ return 0;
+
+ gain_term = 0;
+ for (i = 0; i < 20; i++)
+ gain_term += FFABS(lp_gn[i + 10]);
+ gain_term >>= 2; // (3.12) -> (5.10)
+
+ if (gain_term > 0x400) { // 1.0 in (5.10)
+ temp = 0x2000000 / gain_term; // 1.0/gain_term in (0.15)
+ for (i = 0; i < subframe_size; i++)
+ speech[i] = (speech[i] * temp + 0x4000) >> 15;
+ }
+
+ return -(rh1 << 15) / rh0;
+}
+
+/**
+ * \brief Apply tilt compensation filter (4.2.3).
+ * \param res_pst [in/out] residual signal (partially filtered)
+ * \param k1 (3.12) reflection coefficient
+ * \param subframe_size size of subframe
+ * \param ht_prev_data previous data for 4.2.3, equation 86
+ *
+ * \return new value for ht_prev_data
+*/
+static int16_t apply_tilt_comp(int16_t* out, int16_t* res_pst, int refl_coeff,
+ int subframe_size, int16_t ht_prev_data)
+{
+ int tmp, tmp2;
+ int i;
+ int gt, ga;
+ int fact, sh_fact;
+
+ if (refl_coeff > 0) {
+ gt = (refl_coeff * G729_TILT_FACTOR_PLUS + 0x4000) >> 15;
+ fact = 0x4000; // 0.5 in (0.15)
+ sh_fact = 15;
+ } else {
+ gt = (refl_coeff * G729_TILT_FACTOR_MINUS + 0x4000) >> 15;
+ fact = 0x800; // 0.5 in (3.12)
+ sh_fact = 12;
+ }
+ ga = (fact << 15) / av_clip_int16(32768 - FFABS(gt));
+ gt >>= 1;
+
+ /* Apply tilt compensation filter to signal. */
+ tmp = res_pst[subframe_size - 1];
+
+ for (i = subframe_size - 1; i >= 1; i--) {
+ tmp2 = (res_pst[i] << 15) + ((gt * res_pst[i-1]) << 1);
+ tmp2 = (tmp2 + 0x4000) >> 15;
+
+ tmp2 = (tmp2 * ga * 2 + fact) >> sh_fact;
+ out[i] = tmp2;
+ }
+ tmp2 = (res_pst[0] << 15) + ((gt * ht_prev_data) << 1);
+ tmp2 = (tmp2 + 0x4000) >> 15;
+ tmp2 = (tmp2 * ga * 2 + fact) >> sh_fact;
+ out[0] = tmp2;
+
+ return tmp;
+}
+
+void ff_g729_postfilter(AudioDSPContext *adsp, int16_t* ht_prev_data, int* voicing,
+ const int16_t *lp_filter_coeffs, int pitch_delay_int,
+ int16_t* residual, int16_t* res_filter_data,
+ int16_t* pos_filter_data, int16_t *speech, int subframe_size)
+{
+ int16_t residual_filt_buf[SUBFRAME_SIZE+11];
+ int16_t lp_gn[33]; // (3.12)
+ int16_t lp_gd[11]; // (3.12)
+ int tilt_comp_coeff;
+ int i;
+
+ /* Zero-filling is necessary for tilt-compensation filter. */
+ memset(lp_gn, 0, 33 * sizeof(int16_t));
+
+ /* Calculate A(z/FORMANT_PP_FACTOR_NUM) filter coefficients. */
+ for (i = 0; i < 10; i++)
+ lp_gn[i + 11] = (lp_filter_coeffs[i + 1] * formant_pp_factor_num_pow[i] + 0x4000) >> 15;
+
+ /* Calculate A(z/FORMANT_PP_FACTOR_DEN) filter coefficients. */
+ for (i = 0; i < 10; i++)
+ lp_gd[i + 1] = (lp_filter_coeffs[i + 1] * formant_pp_factor_den_pow[i] + 0x4000) >> 15;
+
+ /* residual signal calculation (one-half of short-term postfilter) */
+ memcpy(speech - 10, res_filter_data, 10 * sizeof(int16_t));
+ residual_filter(residual + RES_PREV_DATA_SIZE, lp_gn + 11, speech, subframe_size);
+ /* Save data to use it in the next subframe. */
+ memcpy(res_filter_data, speech + subframe_size - 10, 10 * sizeof(int16_t));
+
+ /* long-term filter. If long-term prediction gain is larger than 3dB (returned value is
+ nonzero) then declare current subframe as periodic. */
+ *voicing = FFMAX(*voicing, long_term_filter(adsp, pitch_delay_int,
+ residual, residual_filt_buf + 10,
+ subframe_size));
+
+ /* shift residual for using in next subframe */
+ memmove(residual, residual + subframe_size, RES_PREV_DATA_SIZE * sizeof(int16_t));
+
+ /* short-term filter tilt compensation */
+ tilt_comp_coeff = get_tilt_comp(adsp, lp_gn, lp_gd, residual_filt_buf + 10, subframe_size);
+
+ /* Apply second half of short-term postfilter: 1/A(z/FORMANT_PP_FACTOR_DEN) */
+ ff_celp_lp_synthesis_filter(pos_filter_data + 10, lp_gd + 1,
+ residual_filt_buf + 10,
+ subframe_size, 10, 0, 0, 0x800);
+ memcpy(pos_filter_data, pos_filter_data + subframe_size, 10 * sizeof(int16_t));
+
+ *ht_prev_data = apply_tilt_comp(speech, pos_filter_data + 10, tilt_comp_coeff,
+ subframe_size, *ht_prev_data);
+}
+
+/**
+ * \brief Adaptive gain control (4.2.4)
+ * \param gain_before gain of speech before applying postfilters
+ * \param gain_after gain of speech after applying postfilters
+ * \param speech [in/out] signal buffer
+ * \param subframe_size length of subframe
+ * \param gain_prev (3.12) previous value of gain coefficient
+ *
+ * \return (3.12) last value of gain coefficient
+ */
+int16_t ff_g729_adaptive_gain_control(int gain_before, int gain_after, int16_t *speech,
+ int subframe_size, int16_t gain_prev)
+{
+ int gain; // (3.12)
+ int n;
+ int exp_before, exp_after;
+
+ if(!gain_after && gain_before)
+ return 0;
+
+ if (gain_before) {
+
+ exp_before = 14 - av_log2(gain_before);
+ gain_before = bidir_sal(gain_before, exp_before);
+
+ exp_after = 14 - av_log2(gain_after);
+ gain_after = bidir_sal(gain_after, exp_after);
+
+ if (gain_before < gain_after) {
+ gain = (gain_before << 15) / gain_after;
+ gain = bidir_sal(gain, exp_after - exp_before - 1);
+ } else {
+ gain = ((gain_before - gain_after) << 14) / gain_after + 0x4000;
+ gain = bidir_sal(gain, exp_after - exp_before);
+ }
+ gain = (gain * G729_AGC_FAC1 + 0x4000) >> 15; // gain * (1-0.9875)
+ } else
+ gain = 0;
+
+ for (n = 0; n < subframe_size; n++) {
+ // gain_prev = gain + 0.9875 * gain_prev
+ gain_prev = (G729_AGC_FACTOR * gain_prev + 0x4000) >> 15;
+ gain_prev = av_clip_int16(gain + gain_prev);
+ speech[n] = av_clip_int16((speech[n] * gain_prev + 0x2000) >> 14);
+ }
+ return gain_prev;
+}
diff --git a/libavcodec/g729postfilter.h b/libavcodec/g729postfilter.h
new file mode 100644
index 0000000000..89e3e40cea
--- /dev/null
+++ b/libavcodec/g729postfilter.h
@@ -0,0 +1,116 @@
+/*
+ * G.729, G729 Annex D postfilter
+ * Copyright (c) 2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 FFMPEG_G729POSTFILTER_H
+#define FFMPEG_G729POSTFILTER_H
+
+#include <stdint.h>
+#include "audiodsp.h"
+
+/**
+ * tilt compensation factor (G.729, k1>0)
+ * 0.2 in Q15
+ */
+#define G729_TILT_FACTOR_PLUS 6554
+
+/**
+ * tilt compensation factor (G.729, k1<0)
+ * 0.9 in Q15
+ */
+#define G729_TILT_FACTOR_MINUS 29491
+
+/* 4.2.2 */
+#define FORMANT_PP_FACTOR_NUM 18022 //0.55 in Q15
+#define FORMANT_PP_FACTOR_DEN 22938 //0.70 in Q15
+
+/**
+ * gain adjustment factor (G.729, 4.2.4)
+ * 0.9875 in Q15
+ */
+#define G729_AGC_FACTOR 32358
+#define G729_AGC_FAC1 (32768-G729_AGC_FACTOR)
+
+/**
+ * 1.0 / (1.0 + 0.5) in Q15
+ * where 0.5 is the minimum value of
+ * weight factor, controlling amount of long-term postfiltering
+ */
+#define MIN_LT_FILT_FACTOR_A 21845
+
+/**
+ * Short interpolation filter length
+ */
+#define SHORT_INT_FILT_LEN 2
+
+/**
+ * Long interpolation filter length
+ */
+#define LONG_INT_FILT_LEN 8
+
+/**
+ * Number of analyzed fractional pitch delays in second stage of long-term
+ * postfilter
+ */
+#define ANALYZED_FRAC_DELAYS 7
+
+/**
+ * Amount of past residual signal data stored in buffer
+ */
+#define RES_PREV_DATA_SIZE (PITCH_DELAY_MAX + LONG_INT_FILT_LEN + 1)
+
+/**
+ * \brief Signal postfiltering (4.2)
+ * \param dsp initialized DSP context
+ * \param ht_prev_data [in/out] (Q12) pointer to variable receiving tilt
+ * compensation filter data from previous subframe
+ * \param voicing [in/out] (Q0) pointer to variable receiving voicing decision
+ * \param lp_filter_coeffs (Q12) LP filter coefficients
+ * \param pitch_delay_int integer part of the pitch delay
+ * \param residual [in/out] (Q0) residual signal buffer (used in long-term postfilter)
+ * \param res_filter_data [in/out] (Q0) speech data of previous subframe
+ * \param pos_filter_data [in/out] (Q0) previous speech data for short-term postfilter
+ * \param speech [in/out] (Q0) signal buffer
+ * \param subframe_size size of subframe
+ *
+ * Filtering has the following stages:
+ * Long-term postfilter (4.2.1)
+ * Short-term postfilter (4.2.2).
+ * Tilt-compensation (4.2.3)
+ */
+void ff_g729_postfilter(AudioDSPContext *adsp, int16_t* ht_prev_data, int* voicing,
+ const int16_t *lp_filter_coeffs, int pitch_delay_int,
+ int16_t* residual, int16_t* res_filter_data,
+ int16_t* pos_filter_data, int16_t *speech,
+ int subframe_size);
+
+/**
+ * \brief Adaptive gain control (4.2.4)
+ * \param gain_before (Q0) gain of speech before applying postfilters
+ * \param gain_after (Q0) gain of speech after applying postfilters
+ * \param speech [in/out] (Q0) signal buffer
+ * \param subframe_size length of subframe
+ * \param gain_prev (Q12) previous value of gain coefficient
+ *
+ * \return (Q12) last value of gain coefficient
+ */
+int16_t ff_g729_adaptive_gain_control(int gain_before, int gain_after, int16_t *speech,
+ int subframe_size, int16_t gain_prev);
+
+#endif // FFMPEG_G729POSTFILTER_H
diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h
index ec4065370e..affaecb172 100644
--- a/libavcodec/get_bits.h
+++ b/libavcodec/get_bits.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
+#include "libavutil/avassert.h"
#include "mathops.h"
/*
@@ -54,9 +55,7 @@ typedef struct GetBitContext {
const uint8_t *buffer, *buffer_end;
int index;
int size_in_bits;
-#if !UNCHECKED_BITSTREAM_READER
int size_in_bits_plus8;
-#endif
} GetBitContext;
#define VLC_TYPE int16_t
@@ -114,6 +113,9 @@ typedef struct RL_VLC_ELEM {
* LAST_SKIP_BITS(name, gb, num)
* Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER.
*
+ * BITS_LEFT(name, gb)
+ * Return the number of bits left
+ *
* For examples see get_bits, show_bits, skip_bits, get_vlc.
*/
@@ -125,7 +127,7 @@ typedef struct RL_VLC_ELEM {
#define OPEN_READER_NOSIZE(name, gb) \
unsigned int name ## _index = (gb)->index; \
- unsigned int av_unused name ## _cache = 0
+ unsigned int av_unused name ## _cache
#if UNCHECKED_BITSTREAM_READER
#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb)
@@ -141,27 +143,34 @@ typedef struct RL_VLC_ELEM {
#define CLOSE_READER(name, gb) (gb)->index = name ## _index
+# ifdef LONG_BITSTREAM_READER
+
+# define UPDATE_CACHE_LE(name, gb) name ## _cache = \
+ AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)
+
+# define UPDATE_CACHE_BE(name, gb) name ## _cache = \
+ AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7))
+
+#else
+
+# define UPDATE_CACHE_LE(name, gb) name ## _cache = \
+ AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)
+
+# define UPDATE_CACHE_BE(name, gb) name ## _cache = \
+ AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7)
+
+#endif
+
+
#ifdef BITSTREAM_READER_LE
-# ifdef LONG_BITSTREAM_READER
-# define UPDATE_CACHE(name, gb) name ## _cache = \
- AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)
-# else
-# define UPDATE_CACHE(name, gb) name ## _cache = \
- AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)
-# endif
+# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb)
# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num)
#else
-# ifdef LONG_BITSTREAM_READER
-# define UPDATE_CACHE(name, gb) name ## _cache = \
- AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7))
-# else
-# define UPDATE_CACHE(name, gb) name ## _cache = \
- AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7)
-# endif
+# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb)
# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num)
@@ -174,6 +183,8 @@ typedef struct RL_VLC_ELEM {
name ## _index = FFMIN(name ## _size_plus8, name ## _index + (num))
#endif
+#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index))
+
#define SKIP_BITS(name, gb, num) \
do { \
SKIP_CACHE(name, gb, num); \
@@ -182,12 +193,18 @@ typedef struct RL_VLC_ELEM {
#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num)
+#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num)
+#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num)
+
+#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num)
+#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num)
+
#ifdef BITSTREAM_READER_LE
-# define SHOW_UBITS(name, gb, num) zero_extend(name ## _cache, num)
-# define SHOW_SBITS(name, gb, num) sign_extend(name ## _cache, num)
+# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num)
+# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num)
#else
-# define SHOW_UBITS(name, gb, num) NEG_USR32(name ## _cache, num)
-# define SHOW_SBITS(name, gb, num) NEG_SSR32(name ## _cache, num)
+# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num)
+# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num)
#endif
#define GET_CACHE(name, gb) ((uint32_t) name ## _cache)
@@ -207,7 +224,7 @@ static inline void skip_bits_long(GetBitContext *s, int n)
}
/**
- * read mpeg1 dc style vlc (sign bit + mantisse with no MSB).
+ * read mpeg1 dc style vlc (sign bit + mantissa with no MSB).
* if MSB not set it is negative
* @param n length in bits
*/
@@ -216,6 +233,7 @@ static inline int get_xbits(GetBitContext *s, int n)
register int sign;
register int32_t cache;
OPEN_READER(re, s);
+ av_assert2(n>0 && n<=25);
UPDATE_CACHE(re, s);
cache = GET_CACHE(re, s);
sign = ~cache >> 31;
@@ -228,6 +246,7 @@ static inline int get_sbits(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER(re, s);
+ av_assert2(n>0 && n<=25);
UPDATE_CACHE(re, s);
tmp = SHOW_SBITS(re, s, n);
LAST_SKIP_BITS(re, s, n);
@@ -242,6 +261,7 @@ static inline unsigned int get_bits(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER(re, s);
+ av_assert2(n>0 && n<=25);
UPDATE_CACHE(re, s);
tmp = SHOW_UBITS(re, s, n);
LAST_SKIP_BITS(re, s, n);
@@ -249,6 +269,18 @@ static inline unsigned int get_bits(GetBitContext *s, int n)
return tmp;
}
+static inline unsigned int get_bits_le(GetBitContext *s, int n)
+{
+ register int tmp;
+ OPEN_READER(re, s);
+ av_assert2(n>0 && n<=25);
+ UPDATE_CACHE_LE(re, s);
+ tmp = SHOW_UBITS_LE(re, s, n);
+ LAST_SKIP_BITS(re, s, n);
+ CLOSE_READER(re, s);
+ return tmp;
+}
+
/**
* Show 1-25 bits.
*/
@@ -256,6 +288,7 @@ static inline unsigned int show_bits(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER_NOSIZE(re, s);
+ av_assert2(n>0 && n<=25);
UPDATE_CACHE(re, s);
tmp = SHOW_UBITS(re, s, n);
return tmp;
@@ -264,7 +297,6 @@ static inline unsigned int show_bits(GetBitContext *s, int n)
static inline void skip_bits(GetBitContext *s, int n)
{
OPEN_READER(re, s);
- UPDATE_CACHE(re, s);
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
}
@@ -304,20 +336,22 @@ static inline void skip_bits1(GetBitContext *s)
*/
static inline unsigned int get_bits_long(GetBitContext *s, int n)
{
- if (n <= MIN_CACHE_BITS) {
+ if (!n) {
+ return 0;
+ } else if (n <= MIN_CACHE_BITS) {
return get_bits(s, n);
} else {
#ifdef BITSTREAM_READER_LE
- int ret = get_bits(s, 16);
+ unsigned ret = get_bits(s, 16);
return ret | (get_bits(s, n - 16) << 16);
#else
- int ret = get_bits(s, 16) << (n - 16);
+ unsigned ret = get_bits(s, 16) << (n - 16);
return ret | get_bits(s, n - 16);
#endif
}
}
-/*
+/**
* Read 0-64 bits.
*/
static inline uint64_t get_bits64(GetBitContext *s, int n)
@@ -360,7 +394,7 @@ static inline int check_marker(GetBitContext *s, const char *msg)
{
int bit = get_bits1(s);
if (!bit)
- av_log(NULL, AV_LOG_INFO, "Marker bit missing %s\n", msg);
+ av_log(NULL, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n", get_bits_count(s) - 1, s->size_in_bits, msg);
return bit;
}
@@ -379,7 +413,7 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer,
int buffer_size;
int ret = 0;
- if (bit_size > INT_MAX - 7 || bit_size < 0 || !buffer) {
+ if (bit_size >= INT_MAX - 7 || bit_size < 0 || !buffer) {
bit_size = 0;
buffer = NULL;
ret = AVERROR_INVALIDDATA;
@@ -389,9 +423,7 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer,
s->buffer = buffer;
s->size_in_bits = bit_size;
-#if !UNCHECKED_BITSTREAM_READER
s->size_in_bits_plus8 = bit_size + 8;
-#endif
s->buffer_end = buffer + buffer_size;
s->index = 0;
@@ -409,8 +441,8 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer,
static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer,
int byte_size)
{
- if (byte_size > INT_MAX / 8)
- return AVERROR_INVALIDDATA;
+ if (byte_size > INT_MAX / 8 || byte_size < 0)
+ byte_size = -1;
return init_get_bits(s, buffer, byte_size * 8);
}
@@ -486,7 +518,7 @@ void ff_free_vlc(VLC *vlc);
SKIP_BITS(name, gb, n); \
} while (0)
-#define GET_RL_VLC(level, run, name, gb, table, bits, \
+#define GET_RL_VLC_INTERNAL(level, run, name, gb, table, bits, \
max_depth, need_update) \
do { \
int n, nb_bits; \
@@ -558,6 +590,20 @@ static inline int get_bits_left(GetBitContext *gb)
return gb->size_in_bits - get_bits_count(gb);
}
+static inline int skip_1stop_8data_bits(GetBitContext *gb)
+{
+ if (get_bits_left(gb) <= 0)
+ return AVERROR_INVALIDDATA;
+
+ while (get_bits1(gb)) {
+ skip_bits(gb, 8);
+ if (get_bits_left(gb) <= 0)
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
//#define TRACE
#ifdef TRACE
@@ -601,6 +647,25 @@ static inline int get_vlc_trace(GetBitContext *s, VLC_TYPE (*table)[2],
return r;
}
+#define GET_RL_VLC(level, run, name, gb, table, bits, \
+ max_depth, need_update) \
+ do { \
+ int show = SHOW_UBITS(name, gb, 24); \
+ int len; \
+ int pos = name ## _index; \
+ \
+ GET_RL_VLC_INTERNAL(level, run, name, gb, table, bits,max_depth, need_update); \
+ \
+ len = name ## _index - pos + 1; \
+ show = show >> (24 - len); \
+ \
+ print_bin(show, len); \
+ \
+ av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d/%-3d rlv @%5d in %s %s:%d\n",\
+ show, len, run-1, level, pos, __FILE__, __PRETTY_FUNCTION__, __LINE__);\
+ } while (0) \
+
+
static inline int get_xbits_trace(GetBitContext *s, int n, const char *file,
const char *func, int line)
{
@@ -620,6 +685,8 @@ static inline int get_xbits_trace(GetBitContext *s, int n, const char *file,
#define get_vlc(s, vlc) get_vlc_trace(s, (vlc)->table, (vlc)->bits, 3, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define get_vlc2(s, tab, bits, max) get_vlc_trace(s, tab, bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#else //TRACE
+#define GET_RL_VLC GET_RL_VLC_INTERNAL
#endif
#endif /* AVCODEC_GET_BITS_H */
diff --git a/libavcodec/gif.c b/libavcodec/gif.c
index ae7fdfd818..cf5d438a72 100644
--- a/libavcodec/gif.c
+++ b/libavcodec/gif.c
@@ -1,113 +1,201 @@
/*
- * GIF encoder.
* Copyright (c) 2000 Fabrice Bellard
* Copyright (c) 2002 Francois Revol
* Copyright (c) 2006 Baptiste Coudurier
*
* first version by Francois Revol <revol@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/*
- * Features and limitations:
- * - currently no compression is performed,
- * in fact the size of the data is 9/8 the size of the image in 8bpp
- * - uses only a global standard palette
- * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
- *
- * Reference documents:
- * http://www.goice.co.jp/member/mo/formats/gif.html
- * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
- * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
- *
- * this url claims to have an LZW algorithm not covered by Unisys patent:
- * http://www.msg.net/utility/whirlgif/gifencod.html
- * could help reduce the size of the files _a lot_...
- * some sites mentions an RLE type compression also.
+/**
+ * @file
+ * GIF encoder
+ * @see http://www.w3.org/Graphics/GIF/spec-gif89a.txt
*/
+#define BITSTREAM_WRITER_LE
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
#include "lzw.h"
-
-/* The GIF format uses reversed order for bitstreams... */
-/* at least they don't use PDP_ENDIAN :) */
-#define BITSTREAM_WRITER_LE
+#include "gif.h"
#include "put_bits.h"
typedef struct GIFContext {
+ const AVClass *class;
LZWState *lzw;
uint8_t *buf;
+ AVFrame *last_frame;
+ int flags;
+ uint32_t palette[AVPALETTE_COUNT]; ///< local reference palette for !pal8
+ int palette_loaded;
+ int transparent_index;
+ uint8_t *pal_exdata;
+ uint8_t *tmpl; ///< temporary line buffer
} GIFContext;
-/* GIF header */
-static int gif_image_write_header(AVCodecContext *avctx,
- uint8_t **bytestream, uint32_t *palette)
+enum {
+ GF_OFFSETTING = 1<<0,
+ GF_TRANSDIFF = 1<<1,
+};
+
+static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int h)
{
- int i;
- unsigned int v;
-
- bytestream_put_buffer(bytestream, "GIF", 3);
- bytestream_put_buffer(bytestream, "89a", 3);
- bytestream_put_le16(bytestream, avctx->width);
- bytestream_put_le16(bytestream, avctx->height);
-
- bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */
- bytestream_put_byte(bytestream, 0x1f); /* background color index */
- bytestream_put_byte(bytestream, 0); /* aspect ratio */
-
- /* the global palette */
- for(i=0;i<256;i++) {
- v = palette[i];
- bytestream_put_be24(bytestream, v);
- }
+ int histogram[AVPALETTE_COUNT] = {0};
+ int x, y, i;
- return 0;
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++)
+ histogram[buf[x]]++;
+ buf += linesize;
+ }
+ for (i = 0; i < FF_ARRAY_ELEMS(histogram); i++)
+ if (!histogram[i])
+ return i;
+ return -1;
}
static int gif_image_write_image(AVCodecContext *avctx,
uint8_t **bytestream, uint8_t *end,
- const uint8_t *buf, int linesize)
+ const uint32_t *palette,
+ const uint8_t *buf, const int linesize,
+ AVPacket *pkt)
{
GIFContext *s = avctx->priv_data;
- int len = 0, height;
+ int len = 0, height = avctx->height, width = avctx->width, x, y;
+ int x_start = 0, y_start = 0, trans = s->transparent_index;
+ int honor_transparency = (s->flags & GF_TRANSDIFF) && s->last_frame;
const uint8_t *ptr;
+
+ /* Crop image */
+ if ((s->flags & GF_OFFSETTING) && s->last_frame && !palette) {
+ const uint8_t *ref = s->last_frame->data[0];
+ const int ref_linesize = s->last_frame->linesize[0];
+ int x_end = avctx->width - 1,
+ y_end = avctx->height - 1;
+
+ /* skip common lines */
+ while (y_start < y_end) {
+ if (memcmp(ref + y_start*ref_linesize, buf + y_start*linesize, width))
+ break;
+ y_start++;
+ }
+ while (y_end > y_start) {
+ if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, width))
+ break;
+ y_end--;
+ }
+ height = y_end + 1 - y_start;
+
+ /* skip common columns */
+ while (x_start < x_end) {
+ int same_column = 1;
+ for (y = y_start; y <= y_end; y++) {
+ if (ref[y*ref_linesize + x_start] != buf[y*linesize + x_start]) {
+ same_column = 0;
+ break;
+ }
+ }
+ if (!same_column)
+ break;
+ x_start++;
+ }
+ while (x_end > x_start) {
+ int same_column = 1;
+ for (y = y_start; y <= y_end; y++) {
+ if (ref[y*ref_linesize + x_end] != buf[y*linesize + x_end]) {
+ same_column = 0;
+ break;
+ }
+ }
+ if (!same_column)
+ break;
+ x_end--;
+ }
+ width = x_end + 1 - x_start;
+
+ av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n",
+ width, height, x_start, y_start, avctx->width, avctx->height);
+ }
+
/* image block */
+ bytestream_put_byte(bytestream, GIF_IMAGE_SEPARATOR);
+ bytestream_put_le16(bytestream, x_start);
+ bytestream_put_le16(bytestream, y_start);
+ bytestream_put_le16(bytestream, width);
+ bytestream_put_le16(bytestream, height);
- bytestream_put_byte(bytestream, 0x2c);
- bytestream_put_le16(bytestream, 0);
- bytestream_put_le16(bytestream, 0);
- bytestream_put_le16(bytestream, avctx->width);
- bytestream_put_le16(bytestream, avctx->height);
- bytestream_put_byte(bytestream, 0x00); /* flags */
- /* no local clut */
+ if (!palette) {
+ bytestream_put_byte(bytestream, 0x00); /* flags */
+ } else {
+ unsigned i;
+ bytestream_put_byte(bytestream, 1<<7 | 0x7); /* flags */
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t v = palette[i];
+ bytestream_put_be24(bytestream, v);
+ }
+ }
+
+ if (honor_transparency && trans < 0) {
+ trans = pick_palette_entry(buf + y_start*linesize + x_start,
+ linesize, width, height);
+ if (trans < 0) { // TODO, patch welcome
+ av_log(avctx, AV_LOG_DEBUG, "No available color, can not use transparency\n");
+ } else {
+ uint8_t *pal_exdata = s->pal_exdata;
+ if (!pal_exdata)
+ pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+ if (!pal_exdata)
+ return AVERROR(ENOMEM);
+ memcpy(pal_exdata, s->palette, AVPALETTE_SIZE);
+ pal_exdata[trans*4 + 3*!HAVE_BIGENDIAN] = 0x00;
+ }
+ }
+ if (trans < 0)
+ honor_transparency = 0;
bytestream_put_byte(bytestream, 0x08);
- ff_lzw_encode_init(s->lzw, s->buf, avctx->width*avctx->height,
+ ff_lzw_encode_init(s->lzw, s->buf, 2 * width * height,
12, FF_LZW_GIF, put_bits);
- ptr = buf;
- for (height = avctx->height; height--;) {
- len += ff_lzw_encode(s->lzw, ptr, avctx->width);
- ptr += linesize;
+ ptr = buf + y_start*linesize + x_start;
+ if (honor_transparency) {
+ const int ref_linesize = s->last_frame->linesize[0];
+ const uint8_t *ref = s->last_frame->data[0] + y_start*ref_linesize + x_start;
+
+ for (y = 0; y < height; y++) {
+ memcpy(s->tmpl, ptr, width);
+ for (x = 0; x < width; x++)
+ if (ref[x] == ptr[x])
+ s->tmpl[x] = trans;
+ len += ff_lzw_encode(s->lzw, s->tmpl, width);
+ ptr += linesize;
+ ref += ref_linesize;
+ }
+ } else {
+ for (y = 0; y < height; y++) {
+ len += ff_lzw_encode(s->lzw, ptr, width);
+ ptr += linesize;
+ }
}
len += ff_lzw_encode_flush(s->lzw, flush_put_bits);
@@ -122,7 +210,6 @@ static int gif_image_write_image(AVCodecContext *avctx,
len -= size;
}
bytestream_put_byte(bytestream, 0x00); /* end of image block */
- bytestream_put_byte(bytestream, 0x3b);
return 0;
}
@@ -130,6 +217,11 @@ static av_cold int gif_encode_init(AVCodecContext *avctx)
{
GIFContext *s = avctx->priv_data;
+ if (avctx->width > 65535 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n");
+ return AVERROR(EINVAL);
+ }
+
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame)
return AVERROR(ENOMEM);
@@ -137,31 +229,85 @@ static av_cold int gif_encode_init(AVCodecContext *avctx)
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
+ s->transparent_index = -1;
+
s->lzw = av_mallocz(ff_lzw_encode_state_size);
- if (!s->lzw)
- return AVERROR(ENOMEM);
s->buf = av_malloc(avctx->width*avctx->height*2);
- if (!s->buf)
- return AVERROR(ENOMEM);
+ s->tmpl = av_malloc(avctx->width);
+ if (!s->tmpl || !s->buf || !s->lzw)
+ return AVERROR(ENOMEM);
+
+ if (avpriv_set_systematic_pal2(s->palette, avctx->pix_fmt) < 0)
+ av_assert0(avctx->pix_fmt == AV_PIX_FMT_PAL8);
+
return 0;
}
-/* better than nothing gif encoder */
+/* FIXME: duplicated with lavc */
+static int get_palette_transparency_index(const uint32_t *palette)
+{
+ int transparent_color_index = -1;
+ unsigned i, smallest_alpha = 0xff;
+
+ if (!palette)
+ return -1;
+
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t v = palette[i];
+ if (v >> 24 < smallest_alpha) {
+ smallest_alpha = v >> 24;
+ transparent_color_index = i;
+ }
+ }
+ return smallest_alpha < 128 ? transparent_color_index : -1;
+}
+
static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
+ GIFContext *s = avctx->priv_data;
uint8_t *outbuf_ptr, *end;
+ const uint32_t *palette = NULL;
int ret;
- if ((ret = ff_alloc_packet(pkt, avctx->width*avctx->height*7/5 + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*7/5 + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
outbuf_ptr = pkt->data;
end = pkt->data + pkt->size;
- gif_image_write_header(avctx, &outbuf_ptr, (uint32_t *)pict->data[1]);
- gif_image_write_image(avctx, &outbuf_ptr, end, pict->data[0], pict->linesize[0]);
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ uint8_t *pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+ if (!pal_exdata)
+ return AVERROR(ENOMEM);
+ memcpy(pal_exdata, pict->data[1], AVPALETTE_SIZE);
+ palette = (uint32_t*)pict->data[1];
+
+ s->pal_exdata = pal_exdata;
+
+ /* The first palette with PAL8 will be used as generic palette by the
+ * muxer so we don't need to write it locally in the packet. We store
+ * it as a reference here in case it changes later. */
+ if (!s->palette_loaded) {
+ memcpy(s->palette, palette, AVPALETTE_SIZE);
+ s->transparent_index = get_palette_transparency_index(palette);
+ s->palette_loaded = 1;
+ palette = NULL;
+ } else if (!memcmp(s->palette, palette, AVPALETTE_SIZE)) {
+ palette = NULL;
+ }
+ }
+
+ gif_image_write_image(avctx, &outbuf_ptr, end, palette,
+ pict->data[0], pict->linesize[0], pkt);
+ if (!s->last_frame) {
+ s->last_frame = av_frame_alloc();
+ if (!s->last_frame)
+ return AVERROR(ENOMEM);
+ }
+ av_frame_unref(s->last_frame);
+ ret = av_frame_ref(s->last_frame, (AVFrame*)pict);
+ if (ret < 0)
+ return ret;
pkt->size = outbuf_ptr - pkt->data;
pkt->flags |= AV_PKT_FLAG_KEY;
@@ -178,9 +324,27 @@ static int gif_encode_close(AVCodecContext *avctx)
av_freep(&s->lzw);
av_freep(&s->buf);
+ av_frame_free(&s->last_frame);
+ av_freep(&s->tmpl);
return 0;
}
+#define OFFSET(x) offsetof(GIFContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption gif_options[] = {
+ { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = GF_OFFSETTING|GF_TRANSDIFF}, 0, INT_MAX, FLAGS, "flags" },
+ { "offsetting", "enable picture offsetting", 0, AV_OPT_TYPE_CONST, {.i64=GF_OFFSETTING}, INT_MIN, INT_MAX, FLAGS, "flags" },
+ { "transdiff", "enable transparency detection between frames", 0, AV_OPT_TYPE_CONST, {.i64=GF_TRANSDIFF}, INT_MIN, INT_MAX, FLAGS, "flags" },
+ { NULL }
+};
+
+static const AVClass gif_class = {
+ .class_name = "GIF encoder",
+ .item_name = av_default_item_name,
+ .option = gif_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_gif_encoder = {
.name = "gif",
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
@@ -194,4 +358,5 @@ AVCodec ff_gif_encoder = {
AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8, AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE
},
+ .priv_class = &gif_class,
};
diff --git a/libavcodec/gif.h b/libavcodec/gif.h
new file mode 100644
index 0000000000..b4cf66546c
--- /dev/null
+++ b/libavcodec/gif.h
@@ -0,0 +1,49 @@
+/*
+ * GIF format definitions
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Baptiste Coudurier
+ * Copyright (c) 2012 Vitaliy E Sugrobov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * GIF format definitions.
+ */
+
+#ifndef AVCODEC_GIFDEFS_H
+#define AVCODEC_GIFDEFS_H
+
+#include <stdint.h>
+
+static const uint8_t gif87a_sig[6] = "GIF87a";
+static const uint8_t gif89a_sig[6] = "GIF89a";
+
+#define GCE_DISPOSAL_NONE 0
+#define GCE_DISPOSAL_INPLACE 1
+#define GCE_DISPOSAL_BACKGROUND 2
+#define GCE_DISPOSAL_RESTORE 3
+
+#define GIF_TRAILER 0x3b
+#define GIF_EXTENSION_INTRODUCER 0x21
+#define GIF_IMAGE_SEPARATOR 0x2c
+#define GIF_GCE_EXT_LABEL 0xf9
+#define GIF_APP_EXT_LABEL 0xff
+#define NETSCAPE_EXT_STR "NETSCAPE2.0"
+
+#endif /* AVCODEC_GIFDEFS_H */
diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c
index d91f159dc1..c179f45c30 100644
--- a/libavcodec/gifdec.c
+++ b/libavcodec/gifdec.c
@@ -2,122 +2,268 @@
* GIF decoder
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2006 Baptiste Coudurier
+ * Copyright (c) 2012 Vitaliy E Sugrobov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
#include "lzw.h"
+#include "gif.h"
-#define GCE_DISPOSAL_NONE 0
-#define GCE_DISPOSAL_INPLACE 1
-#define GCE_DISPOSAL_BACKGROUND 2
-#define GCE_DISPOSAL_RESTORE 3
+/* This value is intentionally set to "transparent white" color.
+ * It is much better to have white background instead of black
+ * when gif image converted to format which not support transparency.
+ */
+#define GIF_TRANSPARENT_COLOR 0x00ffffff
typedef struct GifState {
+ const AVClass *class;
+ AVFrame *frame;
int screen_width;
int screen_height;
+ int has_global_palette;
int bits_per_pixel;
+ uint32_t bg_color;
int background_color_index;
int transparent_color_index;
int color_resolution;
- uint32_t *image_palette;
+ /* intermediate buffer for storing color indices
+ * obtained from lzw-encoded data stream */
+ uint8_t *idx_line;
+ int idx_line_size;
/* after the frame is displayed, the disposal method is used */
+ int gce_prev_disposal;
int gce_disposal;
- /* delay during which the frame is shown */
- int gce_delay;
+ /* rectangle describing area that must be disposed */
+ int gce_l, gce_t, gce_w, gce_h;
+ /* depending on disposal method we store either part of the image
+ * drawn on the canvas or background color that
+ * should be used upon disposal */
+ uint32_t * stored_img;
+ int stored_img_size;
+ int stored_bg_color;
- /* LZW compatible decoder */
GetByteContext gb;
LZWState *lzw;
/* aux buffers */
- uint8_t global_palette[256 * 3];
- uint8_t local_palette[256 * 3];
+ uint32_t global_palette[256];
+ uint32_t local_palette[256];
- AVCodecContext* avctx;
+ AVCodecContext *avctx;
+ int keyframe;
+ int keyframe_ok;
+ int trans_color; /**< color value that is used instead of transparent color */
} GifState;
-static const uint8_t gif87a_sig[6] = "GIF87a";
-static const uint8_t gif89a_sig[6] = "GIF89a";
+static void gif_read_palette(GifState *s, uint32_t *pal, int nb)
+{
+ int i;
+
+ for (i = 0; i < nb; i++, pal++)
+ *pal = (0xffu << 24) | bytestream2_get_be24u(&s->gb);
+}
+
+static void gif_fill(AVFrame *picture, uint32_t color)
+{
+ uint32_t *p = (uint32_t *)picture->data[0];
+ uint32_t *p_end = p + (picture->linesize[0] / sizeof(uint32_t)) * picture->height;
+
+ for (; p < p_end; p++)
+ *p = color;
+}
+
+static void gif_fill_rect(AVFrame *picture, uint32_t color, int l, int t, int w, int h)
+{
+ const int linesize = picture->linesize[0] / sizeof(uint32_t);
+ const uint32_t *py = (uint32_t *)picture->data[0] + t * linesize;
+ const uint32_t *pr, *pb = py + h * linesize;
+ uint32_t *px;
+
+ for (; py < pb; py += linesize) {
+ px = (uint32_t *)py + l;
+ pr = px + w;
+
+ for (; px < pr; px++)
+ *px = color;
+ }
+}
+
+static void gif_copy_img_rect(const uint32_t *src, uint32_t *dst,
+ int linesize, int l, int t, int w, int h)
+{
+ const int y_start = t * linesize;
+ const uint32_t *src_px,
+ *src_py = src + y_start,
+ *dst_py = dst + y_start;
+ const uint32_t *src_pb = src_py + h * linesize;
+ uint32_t *dst_px;
+
+ for (; src_py < src_pb; src_py += linesize, dst_py += linesize) {
+ src_px = src_py + l;
+ dst_px = (uint32_t *)dst_py + l;
+
+ memcpy(dst_px, src_px, w * sizeof(uint32_t));
+ }
+}
static int gif_read_image(GifState *s, AVFrame *frame)
{
- int left, top, width, height, bits_per_pixel, code_size, flags;
- int is_interleaved, has_local_palette, y, pass, y1, linesize, n, i;
- uint8_t *ptr, *spal, *palette, *ptr1;
-
- left = bytestream2_get_le16(&s->gb);
- top = bytestream2_get_le16(&s->gb);
- width = bytestream2_get_le16(&s->gb);
- height = bytestream2_get_le16(&s->gb);
- flags = bytestream2_get_byte(&s->gb);
+ int left, top, width, height, bits_per_pixel, code_size, flags, pw;
+ int is_interleaved, has_local_palette, y, pass, y1, linesize, pal_size;
+ uint32_t *ptr, *pal, *px, *pr, *ptr1;
+ int ret;
+ uint8_t *idx;
+
+ /* At least 9 bytes of Image Descriptor. */
+ if (bytestream2_get_bytes_left(&s->gb) < 9)
+ return AVERROR_INVALIDDATA;
+
+ left = bytestream2_get_le16u(&s->gb);
+ top = bytestream2_get_le16u(&s->gb);
+ width = bytestream2_get_le16u(&s->gb);
+ height = bytestream2_get_le16u(&s->gb);
+ flags = bytestream2_get_byteu(&s->gb);
is_interleaved = flags & 0x40;
has_local_palette = flags & 0x80;
bits_per_pixel = (flags & 0x07) + 1;
- ff_dlog(s->avctx, "gif: image x=%d y=%d w=%d h=%d\n", left, top, width, height);
+ ff_dlog(s->avctx, "image x=%d y=%d w=%d h=%d\n", left, top, width, height);
if (has_local_palette) {
- bytestream2_get_buffer(&s->gb, s->local_palette, 3 * (1 << bits_per_pixel));
- palette = s->local_palette;
+ pal_size = 1 << bits_per_pixel;
+
+ if (bytestream2_get_bytes_left(&s->gb) < pal_size * 3)
+ return AVERROR_INVALIDDATA;
+
+ gif_read_palette(s, s->local_palette, pal_size);
+ pal = s->local_palette;
} else {
- palette = s->global_palette;
- bits_per_pixel = s->bits_per_pixel;
+ if (!s->has_global_palette) {
+ av_log(s->avctx, AV_LOG_ERROR, "picture doesn't have either global or local palette.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ pal = s->global_palette;
+ }
+
+ if (s->keyframe) {
+ if (s->transparent_color_index == -1 && s->has_global_palette) {
+ /* transparency wasn't set before the first frame, fill with background color */
+ gif_fill(frame, s->bg_color);
+ } else {
+ /* otherwise fill with transparent color.
+ * this is necessary since by default picture filled with 0x80808080. */
+ gif_fill(frame, s->trans_color);
+ }
}
/* verify that all the image is inside the screen dimensions */
- if (left + width > s->screen_width ||
- top + height > s->screen_height ||
- !width || !height) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid image dimensions.\n");
+ if (!width || width > s->screen_width || left >= s->screen_width) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid image width.\n");
return AVERROR_INVALIDDATA;
}
+ if (!height || height > s->screen_height || top >= s->screen_height) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid image height.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (left + width > s->screen_width) {
+ /* width must be kept around to avoid lzw vs line desync */
+ pw = s->screen_width - left;
+ av_log(s->avctx, AV_LOG_WARNING, "Image too wide by %d, truncating.\n",
+ left + width - s->screen_width);
+ } else {
+ pw = width;
+ }
+ if (top + height > s->screen_height) {
+ /* we don't care about the extra invisible lines */
+ av_log(s->avctx, AV_LOG_WARNING, "Image too high by %d, truncating.\n",
+ top + height - s->screen_height);
+ height = s->screen_height - top;
+ }
+
+ /* process disposal method */
+ if (s->gce_prev_disposal == GCE_DISPOSAL_BACKGROUND) {
+ gif_fill_rect(frame, s->stored_bg_color, s->gce_l, s->gce_t, s->gce_w, s->gce_h);
+ } else if (s->gce_prev_disposal == GCE_DISPOSAL_RESTORE) {
+ gif_copy_img_rect(s->stored_img, (uint32_t *)frame->data[0],
+ frame->linesize[0] / sizeof(uint32_t), s->gce_l, s->gce_t, s->gce_w, s->gce_h);
+ }
+
+ s->gce_prev_disposal = s->gce_disposal;
+
+ if (s->gce_disposal != GCE_DISPOSAL_NONE) {
+ s->gce_l = left; s->gce_t = top;
+ s->gce_w = pw; s->gce_h = height;
- /* build the palette */
- n = (1 << bits_per_pixel);
- spal = palette;
- for(i = 0; i < n; i++) {
- s->image_palette[i] = (0xffu << 24) | AV_RB24(spal);
- spal += 3;
+ if (s->gce_disposal == GCE_DISPOSAL_BACKGROUND) {
+ if (s->transparent_color_index >= 0)
+ s->stored_bg_color = s->trans_color;
+ else
+ s->stored_bg_color = s->bg_color;
+ } else if (s->gce_disposal == GCE_DISPOSAL_RESTORE) {
+ av_fast_malloc(&s->stored_img, &s->stored_img_size, frame->linesize[0] * frame->height);
+ if (!s->stored_img)
+ return AVERROR(ENOMEM);
+
+ gif_copy_img_rect((uint32_t *)frame->data[0], s->stored_img,
+ frame->linesize[0] / sizeof(uint32_t), left, top, pw, height);
+ }
}
- for(; i < 256; i++)
- s->image_palette[i] = (0xffu << 24);
- /* handle transparency */
- if (s->transparent_color_index >= 0)
- s->image_palette[s->transparent_color_index] = 0;
+
+ /* Expect at least 2 bytes: 1 for lzw code size and 1 for block size. */
+ if (bytestream2_get_bytes_left(&s->gb) < 2)
+ return AVERROR_INVALIDDATA;
/* now get the image data */
- code_size = bytestream2_get_byte(&s->gb);
- ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer,
- bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF);
+ code_size = bytestream2_get_byteu(&s->gb);
+ if ((ret = ff_lzw_decode_init(s->lzw, code_size, s->gb.buffer,
+ bytestream2_get_bytes_left(&s->gb), FF_LZW_GIF)) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "LZW init failed\n");
+ return ret;
+ }
/* read all the image */
- linesize = frame->linesize[0];
- ptr1 = frame->data[0] + top * linesize + left;
+ linesize = frame->linesize[0] / sizeof(uint32_t);
+ ptr1 = (uint32_t *)frame->data[0] + top * linesize + left;
ptr = ptr1;
pass = 0;
y1 = 0;
for (y = 0; y < height; y++) {
- ff_lzw_decode(s->lzw, ptr, width);
+ int count = ff_lzw_decode(s->lzw, s->idx_line, width);
+ if (count != width) {
+ if (count)
+ av_log(s->avctx, AV_LOG_ERROR, "LZW decode failed\n");
+ goto decode_tail;
+ }
+
+ pr = ptr + pw;
+
+ for (px = ptr, idx = s->idx_line; px < pr; px++, idx++) {
+ if (*idx != s->transparent_color_index)
+ *px = pal[*idx];
+ }
+
if (is_interleaved) {
switch(pass) {
default:
@@ -144,53 +290,76 @@ static int gif_read_image(GifState *s, AVFrame *frame)
ptr += linesize;
}
}
+
+ decode_tail:
/* read the garbage data until end marker is found */
ff_lzw_decode_tail(s->lzw);
- bytestream2_skip(&s->gb, ff_lzw_size_read(s->lzw));
+ /* Graphic Control Extension's scope is single frame.
+ * Remove its influence. */
+ s->transparent_color_index = -1;
+ s->gce_disposal = GCE_DISPOSAL_NONE;
+
return 0;
}
static int gif_read_extension(GifState *s)
{
- int ext_code, ext_len, i, gce_flags, gce_transparent_index;
+ int ext_code, ext_len, gce_flags, gce_transparent_index;
+
+ /* There must be at least 2 bytes:
+ * 1 for extension label and 1 for extension length. */
+ if (bytestream2_get_bytes_left(&s->gb) < 2)
+ return AVERROR_INVALIDDATA;
- /* extension */
- ext_code = bytestream2_get_byte(&s->gb);
- ext_len = bytestream2_get_byte(&s->gb);
+ ext_code = bytestream2_get_byteu(&s->gb);
+ ext_len = bytestream2_get_byteu(&s->gb);
- ff_dlog(s->avctx, "gif: ext_code=0x%x len=%d\n", ext_code, ext_len);
+ ff_dlog(s->avctx, "ext_code=0x%x len=%d\n", ext_code, ext_len);
switch(ext_code) {
- case 0xf9:
+ case GIF_GCE_EXT_LABEL:
if (ext_len != 4)
goto discard_ext;
- s->transparent_color_index = -1;
- gce_flags = bytestream2_get_byte(&s->gb);
- s->gce_delay = bytestream2_get_le16(&s->gb);
- gce_transparent_index = bytestream2_get_byte(&s->gb);
+
+ /* We need at least 5 bytes more: 4 is for extension body
+ * and 1 for next block size. */
+ if (bytestream2_get_bytes_left(&s->gb) < 5)
+ return AVERROR_INVALIDDATA;
+
+ gce_flags = bytestream2_get_byteu(&s->gb);
+ bytestream2_skipu(&s->gb, 2); // delay during which the frame is shown
+ gce_transparent_index = bytestream2_get_byteu(&s->gb);
if (gce_flags & 0x01)
s->transparent_color_index = gce_transparent_index;
else
s->transparent_color_index = -1;
s->gce_disposal = (gce_flags >> 2) & 0x7;
- ff_dlog(s->avctx, "gif: gce_flags=%x delay=%d tcolor=%d disposal=%d\n",
- gce_flags, s->gce_delay,
+ ff_dlog(s->avctx, "gce_flags=%x tcolor=%d disposal=%d\n",
+ gce_flags,
s->transparent_color_index, s->gce_disposal);
- ext_len = bytestream2_get_byte(&s->gb);
+ if (s->gce_disposal > 3) {
+ s->gce_disposal = GCE_DISPOSAL_NONE;
+ ff_dlog(s->avctx, "invalid value in gce_disposal (%d). Using default value of 0.\n", ext_len);
+ }
+
+ ext_len = bytestream2_get_byteu(&s->gb);
break;
}
/* NOTE: many extension blocks can come after */
discard_ext:
- while (ext_len != 0) {
- for (i = 0; i < ext_len; i++)
- bytestream2_get_byte(&s->gb);
- ext_len = bytestream2_get_byte(&s->gb);
+ while (ext_len) {
+ /* There must be at least ext_len bytes and 1 for next block size byte. */
+ if (bytestream2_get_bytes_left(&s->gb) < ext_len + 1)
+ return AVERROR_INVALIDDATA;
+
+ bytestream2_skipu(&s->gb, ext_len);
+ ext_len = bytestream2_get_byteu(&s->gb);
- ff_dlog(s->avctx, "gif: ext_len1=%d\n", ext_len);
+ ff_dlog(s->avctx, "ext_len1=%d\n", ext_len);
}
return 0;
}
@@ -199,44 +368,48 @@ static int gif_read_header1(GifState *s)
{
uint8_t sig[6];
int v, n;
- int has_global_palette;
+ int background_color_index;
if (bytestream2_get_bytes_left(&s->gb) < 13)
return AVERROR_INVALIDDATA;
/* read gif signature */
- bytestream2_get_buffer(&s->gb, sig, 6);
- if (memcmp(sig, gif87a_sig, 6) != 0 &&
- memcmp(sig, gif89a_sig, 6) != 0)
+ bytestream2_get_bufferu(&s->gb, sig, 6);
+ if (memcmp(sig, gif87a_sig, 6) &&
+ memcmp(sig, gif89a_sig, 6))
return AVERROR_INVALIDDATA;
/* read screen header */
s->transparent_color_index = -1;
- s->screen_width = bytestream2_get_le16(&s->gb);
- s->screen_height = bytestream2_get_le16(&s->gb);
- if( (unsigned)s->screen_width > 32767
- || (unsigned)s->screen_height > 32767){
- av_log(NULL, AV_LOG_ERROR, "picture size too large\n");
- return AVERROR_INVALIDDATA;
- }
+ s->screen_width = bytestream2_get_le16u(&s->gb);
+ s->screen_height = bytestream2_get_le16u(&s->gb);
- v = bytestream2_get_byte(&s->gb);
+ v = bytestream2_get_byteu(&s->gb);
s->color_resolution = ((v & 0x70) >> 4) + 1;
- has_global_palette = (v & 0x80);
+ s->has_global_palette = (v & 0x80);
s->bits_per_pixel = (v & 0x07) + 1;
- s->background_color_index = bytestream2_get_byte(&s->gb);
- bytestream2_get_byte(&s->gb); /* ignored */
+ background_color_index = bytestream2_get_byteu(&s->gb);
+ n = bytestream2_get_byteu(&s->gb);
+ if (n) {
+ s->avctx->sample_aspect_ratio.num = n + 15;
+ s->avctx->sample_aspect_ratio.den = 64;
+ }
- ff_dlog(s->avctx, "gif: screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
+ ff_dlog(s->avctx, "screen_w=%d screen_h=%d bpp=%d global_palette=%d\n",
s->screen_width, s->screen_height, s->bits_per_pixel,
- has_global_palette);
+ s->has_global_palette);
- if (has_global_palette) {
+ if (s->has_global_palette) {
+ s->background_color_index = background_color_index;
n = 1 << s->bits_per_pixel;
if (bytestream2_get_bytes_left(&s->gb) < n * 3)
return AVERROR_INVALIDDATA;
- bytestream2_get_buffer(&s->gb, s->global_palette, n * 3);
- }
+
+ gif_read_palette(s, s->global_palette, n);
+ s->bg_color = s->global_palette[s->background_color_index];
+ } else
+ s->background_color_index = -1;
+
return 0;
}
@@ -246,23 +419,24 @@ static int gif_parse_next_image(GifState *s, AVFrame *frame)
int code = bytestream2_get_byte(&s->gb);
int ret;
- ff_dlog(s->avctx, "gif: code=%02x '%c'\n", code, code);
+ av_log(s->avctx, AV_LOG_DEBUG, "code=%02x '%c'\n", code, code);
switch (code) {
- case ',':
+ case GIF_IMAGE_SEPARATOR:
return gif_read_image(s, frame);
- case '!':
+ case GIF_EXTENSION_INTRODUCER:
if ((ret = gif_read_extension(s)) < 0)
return ret;
break;
- case ';':
+ case GIF_TRAILER:
/* end of image */
+ return AVERROR_EOF;
default:
- /* error or erroneous EOF */
+ /* erroneous block label */
return AVERROR_INVALIDDATA;
}
}
- return AVERROR_INVALIDDATA;
+ return AVERROR_EOF;
}
static av_cold int gif_decode_init(AVCodecContext *avctx)
@@ -271,38 +445,74 @@ static av_cold int gif_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
ff_lzw_decode_open(&s->lzw);
return 0;
}
-static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
- AVPacket *avpkt)
+static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
GifState *s = avctx->priv_data;
- AVFrame *picture = data;
int ret;
- bytestream2_init(&s->gb, buf, buf_size);
- if ((ret = gif_read_header1(s)) < 0)
- return ret;
+ bytestream2_init(&s->gb, avpkt->data, avpkt->size);
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ s->frame->pts = avpkt->pts;
+ s->frame->pkt_pts = avpkt->pts;
+ s->frame->pkt_dts = avpkt->dts;
+ av_frame_set_pkt_duration(s->frame, avpkt->duration);
- if ((ret = ff_set_dimensions(avctx, s->screen_width, s->screen_height)) < 0)
- return ret;
+ if (avpkt->size >= 6) {
+ s->keyframe = memcmp(avpkt->data, gif87a_sig, 6) == 0 ||
+ memcmp(avpkt->data, gif89a_sig, 6) == 0;
+ } else {
+ s->keyframe = 0;
+ }
- if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if (s->keyframe) {
+ s->keyframe_ok = 0;
+ s->gce_prev_disposal = GCE_DISPOSAL_NONE;
+ if ((ret = gif_read_header1(s)) < 0)
+ return ret;
+
+ if ((ret = ff_set_dimensions(avctx, s->screen_width, s->screen_height)) < 0)
+ return ret;
+
+ av_frame_unref(s->frame);
+ if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0)
+ return ret;
+
+ av_fast_malloc(&s->idx_line, &s->idx_line_size, s->screen_width);
+ if (!s->idx_line)
+ return AVERROR(ENOMEM);
+
+ s->frame->pict_type = AV_PICTURE_TYPE_I;
+ s->frame->key_frame = 1;
+ s->keyframe_ok = 1;
+ } else {
+ if (!s->keyframe_ok) {
+ av_log(avctx, AV_LOG_ERROR, "cannot decode frame without keyframe\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+ return ret;
+
+ s->frame->pict_type = AV_PICTURE_TYPE_P;
+ s->frame->key_frame = 0;
}
- s->image_palette = (uint32_t *)picture->data[1];
- ret = gif_parse_next_image(s, picture);
+
+ ret = gif_parse_next_image(s, s->frame);
if (ret < 0)
return ret;
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
+ return ret;
*got_frame = 1;
+
return bytestream2_tell(&s->gb);
}
@@ -311,9 +521,29 @@ static av_cold int gif_decode_close(AVCodecContext *avctx)
GifState *s = avctx->priv_data;
ff_lzw_decode_close(&s->lzw);
+ av_frame_free(&s->frame);
+ av_freep(&s->idx_line);
+ av_freep(&s->stored_img);
+
return 0;
}
+static const AVOption options[] = {
+ { "trans_color", "color value (ARGB) that is used instead of transparent color",
+ offsetof(GifState, trans_color), AV_OPT_TYPE_INT,
+ {.i64 = GIF_TRANSPARENT_COLOR}, 0, 0xffffffff,
+ AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_VIDEO_PARAM },
+ { NULL },
+};
+
+static const AVClass decoder_class = {
+ .class_name = "gif decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DECODER,
+};
+
AVCodec ff_gif_decoder = {
.name = "gif",
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
@@ -324,4 +554,5 @@ AVCodec ff_gif_decoder = {
.close = gif_decode_close,
.decode = gif_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .priv_class = &decoder_class,
};
diff --git a/libavcodec/golomb-test.c b/libavcodec/golomb-test.c
index e740a20aea..2dfe917144 100644
--- a/libavcodec/golomb-test.c
+++ b/libavcodec/golomb-test.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,7 +58,7 @@ int main(void)
}
}
-#define EXTEND(i) (i << 3 | i & 7)
+#define EXTEND(i) ((i) << 3 | (i) & 7)
init_put_bits(&pb, temp, SIZE);
for (i = 0; i < COUNT; i++)
set_ue_golomb(&pb, EXTEND(i));
diff --git a/libavcodec/golomb.c b/libavcodec/golomb.c
index 550c41ebfe..937ac22ce1 100644
--- a/libavcodec/golomb.c
+++ b/libavcodec/golomb.c
@@ -2,20 +2,20 @@
* exp golomb vlc stuff
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/golomb.h b/libavcodec/golomb.h
index 22a87c64e1..d30bb6bc86 100644
--- a/libavcodec/golomb.h
+++ b/libavcodec/golomb.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2004 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,10 +66,14 @@ static inline int get_ue_golomb(GetBitContext *gb)
return ff_ue_golomb_vlc_code[buf];
} else {
int log = 2 * av_log2(buf) - 31;
- buf >>= log;
- buf--;
LAST_SKIP_BITS(re, gb, 32 - log);
CLOSE_READER(re, gb);
+ if (CONFIG_FTRAPV && log < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid UE golomb code\n");
+ return AVERROR_INVALIDDATA;
+ }
+ buf >>= log;
+ buf--;
return buf;
}
@@ -138,7 +142,7 @@ static inline unsigned svq3_get_ue_golomb(GetBitContext *gb)
ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf];
UPDATE_CACHE(re, gb);
buf = GET_CACHE(re, gb);
- } while (BITS_AVAILABLE(re, gb));
+ } while (ret<0x8000000U && BITS_AVAILABLE(re, gb));
CLOSE_READER(re, gb);
return ret - 1;
@@ -150,7 +154,7 @@ static inline unsigned svq3_get_ue_golomb(GetBitContext *gb)
*/
static inline int get_te0_golomb(GetBitContext *gb, int range)
{
- assert(range >= 1);
+ av_assert2(range >= 1);
if (range == 1)
return 0;
@@ -165,7 +169,7 @@ static inline int get_te0_golomb(GetBitContext *gb, int range)
*/
static inline int get_te_golomb(GetBitContext *gb, int range)
{
- assert(range >= 1);
+ av_assert2(range >= 1);
if (range == 2)
return get_bits1(gb) ^ 1;
@@ -191,16 +195,18 @@ static inline int get_se_golomb(GetBitContext *gb)
return ff_se_golomb_vlc_code[buf];
} else {
- int log = 2 * av_log2(buf) - 31;
+ int log = av_log2(buf), sign;
+ LAST_SKIP_BITS(re, gb, 31 - log);
+ UPDATE_CACHE(re, gb);
+ buf = GET_CACHE(re, gb);
+
buf >>= log;
LAST_SKIP_BITS(re, gb, 32 - log);
CLOSE_READER(re, gb);
- if (buf & 1)
- buf = -(buf >> 1);
- else
- buf = (buf >> 1);
+ sign = -(buf & 1);
+ buf = ((buf >> 1) ^ sign) - sign;
return buf;
}
@@ -209,13 +215,8 @@ static inline int get_se_golomb(GetBitContext *gb)
static inline int get_se_golomb_long(GetBitContext *gb)
{
unsigned int buf = get_ue_golomb_long(gb);
-
- if (buf & 1)
- buf = (buf + 1) >> 1;
- else
- buf = -(buf >> 1);
-
- return buf;
+ int sign = (buf & 1) - 1;
+ return ((buf >> 1) ^ sign) + 1;
}
static inline int svq3_get_se_golomb(GetBitContext *gb)
@@ -256,13 +257,8 @@ static inline int dirac_get_se_golomb(GetBitContext *gb)
uint32_t ret = svq3_get_ue_golomb(gb);
if (ret) {
- uint32_t buf;
- OPEN_READER(re, gb);
- UPDATE_CACHE(re, gb);
- buf = SHOW_SBITS(re, gb, 1);
- LAST_SKIP_BITS(re, gb, 1);
- ret = (ret ^ buf) - buf;
- CLOSE_READER(re, gb);
+ int sign = -get_bits1(gb);
+ ret = (ret ^ sign) - sign;
}
return ret;
@@ -285,7 +281,7 @@ static inline int get_ur_golomb(GetBitContext *gb, int k, int limit,
if (log > 31 - limit) {
buf >>= log - k;
- buf += (30 - log) << k;
+ buf += (30U - log) << k;
LAST_SKIP_BITS(re, gb, 32 + k - log);
CLOSE_READER(re, gb);
@@ -321,14 +317,16 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit,
if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) &&
32 - log < limit) {
buf >>= log - k;
- buf += (30 - log) << k;
+ buf += (30U - log) << k;
LAST_SKIP_BITS(re, gb, 32 + k - log);
CLOSE_READER(re, gb);
return buf;
} else {
int i;
- for (i = 0; i < limit && SHOW_UBITS(re, gb, 1) == 0 && BITS_AVAILABLE(re, gb); i++) {
+ for (i = 0; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) {
+ if (gb->size_in_bits <= re_index)
+ return -1;
LAST_SKIP_BITS(re, gb, 1);
UPDATE_CACHE(re, gb);
}
@@ -336,8 +334,16 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit,
if (i < limit - 1) {
if (k) {
- buf = SHOW_UBITS(re, gb, k);
- LAST_SKIP_BITS(re, gb, k);
+ if (k > MIN_CACHE_BITS - 1) {
+ buf = SHOW_UBITS(re, gb, 16) << (k-16);
+ LAST_SKIP_BITS(re, gb, 16);
+ UPDATE_CACHE(re, gb);
+ buf |= SHOW_UBITS(re, gb, k-16);
+ LAST_SKIP_BITS(re, gb, k-16);
+ } else {
+ buf = SHOW_UBITS(re, gb, k);
+ LAST_SKIP_BITS(re, gb, k);
+ }
} else {
buf = 0;
}
@@ -361,15 +367,8 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit,
static inline int get_sr_golomb(GetBitContext *gb, int k, int limit,
int esc_len)
{
- int v = get_ur_golomb(gb, k, limit, esc_len);
-
- v++;
- if (v & 1)
- return v >> 1;
- else
- return -(v >> 1);
-
-// return (v>>1) ^ -(v&1);
+ unsigned v = get_ur_golomb(gb, k, limit, esc_len);
+ return (v >> 1) ^ -(v & 1);
}
/**
@@ -378,7 +377,7 @@ static inline int get_sr_golomb(GetBitContext *gb, int k, int limit,
static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit,
int esc_len)
{
- int v = get_ur_golomb_jpegls(gb, k, limit, esc_len);
+ unsigned v = get_ur_golomb_jpegls(gb, k, limit, esc_len);
return (v >> 1) ^ -(v & 1);
}
@@ -396,10 +395,7 @@ static inline unsigned int get_ur_golomb_shorten(GetBitContext *gb, int k)
static inline int get_sr_golomb_shorten(GetBitContext *gb, int k)
{
int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0);
- if (uvar & 1)
- return ~(uvar >> 1);
- else
- return uvar >> 1;
+ return (uvar >> 1) ^ -(uvar & 1);
}
#ifdef TRACE
@@ -467,14 +463,8 @@ static inline int get_te(GetBitContext *s, int r, char *file, const char *func,
*/
static inline void set_ue_golomb(PutBitContext *pb, int i)
{
- assert(i >= 0);
+ av_assert2(i >= 0);
-#if 0
- if (i = 0) {
- put_bits(pb, 1, 1);
- return;
- }
-#endif
if (i < 256)
put_bits(pb, ff_ue_golomb_len[i], i + 1);
else {
@@ -488,8 +478,8 @@ static inline void set_ue_golomb(PutBitContext *pb, int i)
*/
static inline void set_te_golomb(PutBitContext *pb, int i, int range)
{
- assert(range >= 1);
- assert(i <= range);
+ av_assert2(range >= 1);
+ av_assert2(i <= range);
if (range == 2)
put_bits(pb, 1, i ^ 1);
@@ -526,11 +516,11 @@ static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit,
{
int e;
- assert(i >= 0);
+ av_assert2(i >= 0);
e = i >> k;
if (e < limit)
- put_bits(pb, e + k + 1, (1 << k) + (i & ((1 << k) - 1)));
+ put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k));
else
put_bits(pb, limit + esc_len, i - limit + 1);
}
@@ -543,7 +533,7 @@ static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k,
{
int e;
- assert(i >= 0);
+ av_assert2(i >= 0);
e = (i >> k) + 1;
if (e < limit) {
diff --git a/libavcodec/gsm.h b/libavcodec/gsm.h
index 238cb7359d..53d65c4dc7 100644
--- a/libavcodec/gsm.h
+++ b/libavcodec/gsm.h
@@ -1,20 +1,20 @@
/*
* GSM common header
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/gsm_parser.c b/libavcodec/gsm_parser.c
index c0befc7796..9a3b94ef1d 100644
--- a/libavcodec/gsm_parser.c
+++ b/libavcodec/gsm_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,7 +55,10 @@ static int gsm_parse(AVCodecParserContext *s1, AVCodecContext *avctx,
s->duration = GSM_FRAME_SIZE * 2;
break;
default:
- return AVERROR(EINVAL);
+ *poutbuf = buf;
+ *poutbuf_size = buf_size;
+ av_log(avctx, AV_LOG_ERROR, "Invalid codec_id\n");
+ return buf_size;
}
}
diff --git a/libavcodec/gsmdec.c b/libavcodec/gsmdec.c
index b763ce8a58..c4cde9295a 100644
--- a/libavcodec/gsmdec.c
+++ b/libavcodec/gsmdec.c
@@ -2,20 +2,20 @@
* gsm 06.10 decoder
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -79,10 +79,8 @@ static int gsm_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = avctx->frame_size;
- if ((res = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
return res;
- }
samples = (int16_t *)frame->data[0];
switch (avctx->codec_id) {
@@ -112,6 +110,7 @@ static void gsm_flush(AVCodecContext *avctx)
memset(s, 0, sizeof(*s));
}
+#if CONFIG_GSM_DECODER
AVCodec ff_gsm_decoder = {
.name = "gsm",
.long_name = NULL_IF_CONFIG_SMALL("GSM"),
@@ -123,7 +122,8 @@ AVCodec ff_gsm_decoder = {
.flush = gsm_flush,
.capabilities = CODEC_CAP_DR1,
};
-
+#endif
+#if CONFIG_GSM_MS_DECODER
AVCodec ff_gsm_ms_decoder = {
.name = "gsm_ms",
.long_name = NULL_IF_CONFIG_SMALL("GSM Microsoft variant"),
@@ -135,3 +135,4 @@ AVCodec ff_gsm_ms_decoder = {
.flush = gsm_flush,
.capabilities = CODEC_CAP_DR1,
};
+#endif
diff --git a/libavcodec/gsmdec_data.c b/libavcodec/gsmdec_data.c
index c9b3183a55..d90c69b98f 100644
--- a/libavcodec/gsmdec_data.c
+++ b/libavcodec/gsmdec_data.c
@@ -2,20 +2,20 @@
* gsm 06.10 decoder data
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/gsmdec_data.h b/libavcodec/gsmdec_data.h
index f5581d53ba..b57194b8d1 100644
--- a/libavcodec/gsmdec_data.h
+++ b/libavcodec/gsmdec_data.h
@@ -2,20 +2,20 @@
* gsm 06.10 decoder data
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/gsmdec_template.c b/libavcodec/gsmdec_template.c
index 0b54dc54ce..0c60813a4a 100644
--- a/libavcodec/gsmdec_template.c
+++ b/libavcodec/gsmdec_template.c
@@ -2,20 +2,20 @@
* gsm 06.10 decoder
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h261.c b/libavcodec/h261.c
index b9783f1510..9836905d93 100644
--- a/libavcodec/h261.c
+++ b/libavcodec/h261.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2004 Maarten Daniels
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h261.h b/libavcodec/h261.h
index ad7e28bb64..5586462893 100644
--- a/libavcodec/h261.h
+++ b/libavcodec/h261.h
@@ -3,20 +3,20 @@
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2004 Maarten Daniels
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,6 @@ typedef struct H261Context {
MpegEncContext s;
int current_mba;
- int previous_mba;
int mba_diff;
int mtype;
int current_mv_x;
diff --git a/libavcodec/h261_parser.c b/libavcodec/h261_parser.c
index 2469424c1a..9c31557510 100644
--- a/libavcodec/h261_parser.c
+++ b/libavcodec/h261_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2004 Maarten Daniels
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,11 +71,15 @@ static int h261_parse(AVCodecParserContext *s,
ParseContext *pc = s->priv_data;
int next;
- next = h261_find_frame_end(pc, avctx, buf, buf_size);
- if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
- *poutbuf = NULL;
- *poutbuf_size = 0;
- return buf_size;
+ if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+ next = buf_size;
+ } else {
+ next = h261_find_frame_end(pc, avctx, buf, buf_size);
+ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ return buf_size;
+ }
}
*poutbuf = buf;
*poutbuf_size = buf_size;
diff --git a/libavcodec/h261data.c b/libavcodec/h261data.c
index a81ccdfef9..a9891edd0a 100644
--- a/libavcodec/h261data.c
+++ b/libavcodec/h261data.c
@@ -2,20 +2,20 @@
* copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* copyright (c) 2004 Maarten Daniels
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h261dec.c b/libavcodec/h261dec.c
index 8e97309c72..4f5994a659 100644
--- a/libavcodec/h261dec.c
+++ b/libavcodec/h261dec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2004 Maarten Daniels
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
* H.261 decoder.
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "mpeg_er.h"
#include "mpegutils.h"
@@ -75,14 +76,11 @@ static av_cold int h261_decode_init(AVCodecContext *avctx)
// set defaults
ff_mpv_decode_defaults(s);
- s->avctx = avctx;
- s->width = s->avctx->coded_width;
- s->height = s->avctx->coded_height;
- s->codec_id = s->avctx->codec->id;
+ ff_mpv_decode_init(s, avctx);
+
s->out_format = FMT_H261;
s->low_delay = 1;
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
- s->codec_id = avctx->codec->id;
ff_h261_common_init();
h261_decode_init_vlc(h);
@@ -127,12 +125,12 @@ static int h261_decode_gob_header(H261Context *h)
}
/* GEI */
- while (get_bits1(&s->gb) != 0)
- skip_bits(&s->gb, 8);
+ if (skip_1stop_8data_bits(&s->gb) < 0)
+ return AVERROR_INVALIDDATA;
if (s->qscale == 0) {
av_log(s->avctx, AV_LOG_ERROR, "qscale has forbidden 0 value\n");
- if (s->avctx->err_recognition & AV_EF_BITSTREAM)
+ if (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT))
return -1;
}
@@ -218,6 +216,13 @@ static int h261_decode_mb_skipped(H261Context *h, int mba1, int mba2)
s->mb_skipped = 1;
h->mtype &= ~MB_TYPE_H261_FIL;
+ if (s->current_picture.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];
+ }
+
ff_mpv_decode_mb(s, s->block);
}
@@ -257,7 +262,7 @@ static int decode_mv_component(GetBitContext *gb, int v)
static int h261_decode_block(H261Context *h, int16_t *block, int n, int coded)
{
MpegEncContext *const s = &h->s;
- int code, level, i, j, run;
+ int level, i, j, run;
RLTable *rl = &ff_h261_rl_tcoeff;
const uint8_t *scan_table;
@@ -302,39 +307,47 @@ static int h261_decode_block(H261Context *h, int16_t *block, int n, int coded)
s->block_last_index[n] = i - 1;
return 0;
}
+ {
+ OPEN_READER(re, &s->gb);
+ i--; // offset by -1 to allow direct indexing of scan_table
for (;;) {
- code = get_vlc2(&s->gb, rl->vlc.table, TCOEFF_VLC_BITS, 2);
- if (code < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n",
- s->mb_x, s->mb_y);
- return -1;
- }
- if (code == rl->n) {
+ UPDATE_CACHE(re, &s->gb);
+ GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TCOEFF_VLC_BITS, 2, 0);
+ if (run == 66) {
+ if (level) {
+ CLOSE_READER(re, &s->gb);
+ av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n",
+ s->mb_x, s->mb_y);
+ return -1;
+ }
/* escape */
/* The remaining combinations of (run, level) are encoded with a
* 20-bit word consisting of 6 bits escape, 6 bits run and 8 bits
* level. */
- run = get_bits(&s->gb, 6);
- level = get_sbits(&s->gb, 8);
- } else if (code == 0) {
+ run = SHOW_UBITS(re, &s->gb, 6) + 1;
+ SKIP_CACHE(re, &s->gb, 6);
+ level = SHOW_SBITS(re, &s->gb, 8);
+ SKIP_COUNTER(re, &s->gb, 6 + 8);
+ } else if (level == 0) {
break;
} else {
- run = rl->table_run[code];
- level = rl->table_level[code];
- if (get_bits1(&s->gb))
+ if (SHOW_UBITS(re, &s->gb, 1))
level = -level;
+ SKIP_COUNTER(re, &s->gb, 1);
}
i += run;
if (i >= 64) {
+ CLOSE_READER(re, &s->gb);
av_log(s->avctx, AV_LOG_ERROR, "run overflow at %dx%d\n",
s->mb_x, s->mb_y);
return -1;
}
j = scan_table[i];
block[j] = level;
- i++;
}
- s->block_last_index[n] = i - 1;
+ CLOSE_READER(re, &s->gb);
+ }
+ s->block_last_index[n] = i;
return 0;
}
@@ -379,11 +392,12 @@ static int h261_decode_mb(H261Context *h)
// Read mtype
h->mtype = get_vlc2(&s->gb, h261_mtype_vlc.table, H261_MTYPE_VLC_BITS, 2);
- if (h->mtype < 0 || h->mtype >= FF_ARRAY_ELEMS(ff_h261_mtype_map)) {
+ if (h->mtype < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid mtype index %d\n",
h->mtype);
return SLICE_ERROR;
}
+ av_assert0(h->mtype < FF_ARRAY_ELEMS(ff_h261_mtype_map));
h->mtype = ff_h261_mtype_map[h->mtype];
// Read mquant
@@ -431,6 +445,13 @@ static int h261_decode_mb(H261Context *h)
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]) {
+ 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];
+ }
+
intra:
/* decode each block */
if (s->mb_intra || HAS_CBP(h->mtype)) {
@@ -506,8 +527,8 @@ static int h261_decode_picture_header(H261Context *h)
skip_bits1(&s->gb); /* Reserved */
/* PEI */
- while (get_bits1(&s->gb) != 0)
- skip_bits(&s->gb, 8);
+ if (skip_1stop_8data_bits(&s->gb) < 0)
+ return AVERROR_INVALIDDATA;
/* H.261 has no I-frames, but if we pass AV_PICTURE_TYPE_I for the first
* frame, the codec crashes if it does not contain all I-blocks
@@ -634,12 +655,12 @@ retry:
}
ff_mpv_frame_end(s);
- assert(s->current_picture.f->pict_type == s->current_picture_ptr->f->pict_type);
- assert(s->current_picture.f->pict_type == s->pict_type);
+ 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);
if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->current_picture_ptr);
+ ff_print_debug_info(s, s->current_picture_ptr, pict);
*got_frame = 1;
@@ -665,4 +686,5 @@ AVCodec ff_h261_decoder = {
.close = h261_decode_end,
.decode = h261_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
};
diff --git a/libavcodec/h261enc.c b/libavcodec/h261enc.c
index f24e590f92..1c3f2ecf5a 100644
--- a/libavcodec/h261enc.c
+++ b/libavcodec/h261enc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2004 Maarten Daniels
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,12 +26,16 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "mpegutils.h"
#include "mpegvideo.h"
#include "h263.h"
#include "h261.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))
+
int ff_h261_get_picture_format(int width, int height)
{
// QCIF
@@ -42,7 +46,7 @@ int ff_h261_get_picture_format(int width, int height)
return 1;
// ERROR
else
- return -1;
+ return AVERROR(EINVAL);
}
void ff_h261_encode_picture_header(MpegEncContext *s, int picture_number)
@@ -57,8 +61,8 @@ void ff_h261_encode_picture_header(MpegEncContext *s, int picture_number)
put_bits(&s->pb, 20, 0x10); /* PSC */
- temp_ref = s->picture_number * (int64_t)30000 * s->avctx->time_base.num /
- (1001 * (int64_t)s->avctx->time_base.den); // FIXME maybe this should use a timestamp
+ temp_ref = s->picture_number * 30000LL * s->avctx->time_base.num /
+ (1001LL * s->avctx->time_base.den); // FIXME maybe this should use a timestamp
put_sbits(&s->pb, 5, temp_ref); /* TemporalReference */
put_bits(&s->pb, 1, 0); /* split screen off */
@@ -77,7 +81,7 @@ void ff_h261_encode_picture_header(MpegEncContext *s, int picture_number)
h->gob_number = -1;
else
h->gob_number = 0;
- h->current_mba = 0;
+ s->mb_skip_run = 0;
}
/**
@@ -95,18 +99,21 @@ static void h261_encode_gob_header(MpegEncContext *s, int mb_line)
put_bits(&s->pb, 4, h->gob_number); /* GN */
put_bits(&s->pb, 5, s->qscale); /* GQUANT */
put_bits(&s->pb, 1, 0); /* no GEI */
- h->current_mba = 0;
- h->previous_mba = 0;
- h->current_mv_x = 0;
- h->current_mv_y = 0;
+ s->mb_skip_run = 0;
+ s->last_mv[0][0][0] = 0;
+ s->last_mv[0][0][1] = 0;
}
void ff_h261_reorder_mb_index(MpegEncContext *s)
{
int index = s->mb_x + s->mb_y * s->mb_width;
- if (index % 33 == 0)
- h261_encode_gob_header(s, 0);
+ if (index % 11 == 0) {
+ if (index % 33 == 0)
+ h261_encode_gob_header(s, 0);
+ s->last_mv[0][0][0] = 0;
+ s->last_mv[0][0][1] = 0;
+ }
/* for CIF the GOB's are fragmented in the middle of a scanline
* that's why we need to adjust the x and y index of the macroblocks */
@@ -213,8 +220,8 @@ static void h261_encode_block(H261Context *h, int16_t *block, int n)
put_bits(&s->pb, rl->table_vlc[code][1], rl->table_vlc[code][0]);
if (code == rl->n) {
put_bits(&s->pb, 6, run);
- assert(slevel != 0);
- assert(level <= 127);
+ av_assert1(slevel != 0);
+ av_assert1(level <= 127);
put_sbits(&s->pb, 8, slevel);
} else {
put_bits(&s->pb, 1, sign);
@@ -234,7 +241,6 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
cbp = 63; // avoid warning
mvd = 0;
- h->current_mba++;
h->mtype = 0;
if (!s->mb_intra) {
@@ -244,19 +250,22 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
/* mvd indicates if this block is motion compensated */
mvd = motion_x | motion_y;
- if ((cbp | mvd | s->dquant) == 0) {
+ if ((cbp | mvd) == 0) {
/* skip macroblock */
s->skip_count++;
- h->current_mv_x = 0;
- h->current_mv_y = 0;
+ s->mb_skip_run++;
+ s->last_mv[0][0][0] = 0;
+ s->last_mv[0][0][1] = 0;
+ s->qscale -= s->dquant;
return;
}
}
/* MB is not skipped, encode MBA */
put_bits(&s->pb,
- ff_h261_mba_bits[(h->current_mba - h->previous_mba) - 1],
- ff_h261_mba_code[(h->current_mba - h->previous_mba) - 1]);
+ ff_h261_mba_bits[s->mb_skip_run],
+ ff_h261_mba_code[s->mb_skip_run]);
+ s->mb_skip_run = 0;
/* calculate MTYPE */
if (!s->mb_intra) {
@@ -266,13 +275,15 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
h->mtype += 3;
if (s->loop_filter)
h->mtype += 3;
- if (cbp || s->dquant)
+ if (cbp)
h->mtype++;
- assert(h->mtype > 1);
+ av_assert1(h->mtype > 1);
}
- if (s->dquant)
+ if (s->dquant && cbp) {
h->mtype++;
+ } else
+ s->qscale -= s->dquant;
put_bits(&s->pb,
ff_h261_mtype_bits[h->mtype],
@@ -286,18 +297,16 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
}
if (IS_16X16(h->mtype)) {
- mv_diff_x = (motion_x >> 1) - h->current_mv_x;
- mv_diff_y = (motion_y >> 1) - h->current_mv_y;
- h->current_mv_x = (motion_x >> 1);
- h->current_mv_y = (motion_y >> 1);
+ mv_diff_x = (motion_x >> 1) - s->last_mv[0][0][0];
+ mv_diff_y = (motion_y >> 1) - s->last_mv[0][0][1];
+ s->last_mv[0][0][0] = (motion_x >> 1);
+ s->last_mv[0][0][1] = (motion_y >> 1);
h261_encode_motion(h, mv_diff_x);
h261_encode_motion(h, mv_diff_y);
}
- h->previous_mba = h->current_mba;
-
if (HAS_CBP(h->mtype)) {
- assert(cbp > 0);
+ av_assert1(cbp > 0);
put_bits(&s->pb,
ff_h261_cbp_tab[cbp - 1][1],
ff_h261_cbp_tab[cbp - 1][0]);
@@ -306,10 +315,49 @@ void ff_h261_encode_mb(MpegEncContext *s, int16_t block[6][64],
/* encode each block */
h261_encode_block(h, block[i], i);
- if ((h->current_mba == 11) || (h->current_mba == 22) ||
- (h->current_mba == 33) || (!IS_16X16(h->mtype))) {
- h->current_mv_x = 0;
- h->current_mv_y = 0;
+ if (!IS_16X16(h->mtype)) {
+ s->last_mv[0][0][0] = 0;
+ s->last_mv[0][0][1] = 0;
+ }
+}
+
+static av_cold void init_uni_h261_rl_tab(RLTable *rl, uint32_t *bits_tab,
+ 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;
+ }
+ }
+ }
}
}
@@ -321,6 +369,12 @@ av_cold void ff_h261_encode_init(MpegEncContext *s)
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;
+
+ init_uni_h261_rl_tab(&ff_h261_rl_tcoeff, NULL, uni_h261_rl_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;
}
FF_MPV_GENERIC_CLASS(h261)
diff --git a/libavcodec/h263.c b/libavcodec/h263.c
index 6eaab41394..41836a809e 100644
--- a/libavcodec/h263.c
+++ b/libavcodec/h263.c
@@ -5,20 +5,20 @@
* Copyright (c) 2001 Juan J. Sierralta P
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h263.h b/libavcodec/h263.h
index 91fc57ef3c..1f954cdf6f 100644
--- a/libavcodec/h263.h
+++ b/libavcodec/h263.h
@@ -1,20 +1,20 @@
/*
* H263 internal header
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_H263_H
@@ -70,8 +70,8 @@ extern RLTable ff_rl_intra_aic;
extern const uint16_t ff_h263_format[8][2];
extern const uint8_t ff_modified_quant_tab[2][32];
-extern uint16_t ff_mba_max[6];
-extern uint8_t ff_mba_length[7];
+extern const uint16_t ff_mba_max[6];
+extern const uint8_t ff_mba_length[7];
extern uint8_t ff_h263_static_rl_table_store[2][2][2*MAX_RUN + MAX_LEVEL + 3];
@@ -123,11 +123,10 @@ int av_const h263_get_picture_format(int width, int height);
void ff_clean_h263_qscales(MpegEncContext *s);
int ff_h263_resync(MpegEncContext *s);
-const uint8_t *ff_h263_find_resync_marker(const uint8_t *p, const uint8_t *end);
-void ff_h263_encode_motion(MpegEncContext * s, int val, int f_code);
+void ff_h263_encode_motion(PutBitContext *pb, int val, int f_code);
-static inline int h263_get_motion_length(MpegEncContext * s, int val, int f_code){
+static inline int h263_get_motion_length(int val, int f_code){
int l, bit_size, code;
if (val == 0) {
@@ -147,11 +146,11 @@ static inline int h263_get_motion_length(MpegEncContext * s, int val, int f_code
static inline void ff_h263_encode_motion_vector(MpegEncContext * s, int x, int y, int f_code){
if (s->avctx->flags2 & CODEC_FLAG2_NO_OUTPUT) {
skip_put_bits(&s->pb,
- h263_get_motion_length(s, x, f_code)
- +h263_get_motion_length(s, y, f_code));
+ h263_get_motion_length(x, f_code)
+ +h263_get_motion_length(y, f_code));
}else{
- ff_h263_encode_motion(s, x, f_code);
- ff_h263_encode_motion(s, y, f_code);
+ ff_h263_encode_motion(&s->pb, x, f_code);
+ ff_h263_encode_motion(&s->pb, y, f_code);
}
}
diff --git a/libavcodec/h263_parser.c b/libavcodec/h263_parser.c
index 71e047a77e..2e7d4930c3 100644
--- a/libavcodec/h263_parser.c
+++ b/libavcodec/h263_parser.c
@@ -2,20 +2,20 @@
* H.263 parser
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -70,12 +70,16 @@ static int h263_parse(AVCodecParserContext *s,
ParseContext *pc = s->priv_data;
int next;
- next= ff_h263_find_frame_end(pc, buf, buf_size);
+ if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+ next = buf_size;
+ } else {
+ next= ff_h263_find_frame_end(pc, buf, buf_size);
- if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
- *poutbuf = NULL;
- *poutbuf_size = 0;
- return buf_size;
+ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+ return buf_size;
+ }
}
*poutbuf = buf;
diff --git a/libavcodec/h263_parser.h b/libavcodec/h263_parser.h
index 5bd715f49d..565a222bc1 100644
--- a/libavcodec/h263_parser.h
+++ b/libavcodec/h263_parser.h
@@ -2,20 +2,20 @@
* H.263 parser
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h263data.h b/libavcodec/h263data.h
index c966aab6d0..1cd965f19a 100644
--- a/libavcodec/h263data.h
+++ b/libavcodec/h263data.h
@@ -4,20 +4,20 @@
* copyright (c) 2001 Juan J. Sierralta P
* copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -264,11 +264,11 @@ const uint8_t ff_h263_chroma_qscale_table[32]={
0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 9,10,10,11,11,12,12,12,13,13,13,14,14,14,14,14,15,15,15,15,15
};
-uint16_t ff_mba_max[6]={
+const uint16_t ff_mba_max[6]={
47, 98, 395,1583,6335,9215
};
-uint8_t ff_mba_length[7]={
+const uint8_t ff_mba_length[7]={
6, 7, 9, 11, 13, 14, 14
};
diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
index 0e08a8df70..89362d209b 100644
--- a/libavcodec/h263dec.c
+++ b/libavcodec/h263dec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,8 @@
* H.263 decoder.
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/cpu.h"
#include "avcodec.h"
#include "error_resilience.h"
@@ -38,6 +40,7 @@
#include "mpegvideo.h"
#include "msmpeg4.h"
#include "qpeldsp.h"
+#include "vdpau_internal.h"
#include "thread.h"
static enum AVPixelFormat h263_get_format(AVCodecContext *avctx)
@@ -45,6 +48,12 @@ static enum AVPixelFormat h263_get_format(AVCodecContext *avctx)
if (avctx->codec->id == AV_CODEC_ID_MSS2)
return AV_PIX_FMT_YUV420P;
+ if (CONFIG_GRAY && (avctx->flags & CODEC_FLAG_GRAY)) {
+ if (avctx->color_range == AVCOL_RANGE_UNSPECIFIED)
+ avctx->color_range = AVCOL_RANGE_MPEG;
+ return AV_PIX_FMT_GRAY8;
+ }
+
return avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);
}
@@ -53,14 +62,12 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
MpegEncContext *s = avctx->priv_data;
int ret;
- s->avctx = avctx;
s->out_format = FMT_H263;
- s->width = avctx->coded_width;
- s->height = avctx->coded_height;
- s->workaround_bugs = avctx->workaround_bugs;
// set defaults
ff_mpv_decode_defaults(s);
+ ff_mpv_decode_init(s, avctx);
+
s->quant_precision = 5;
s->decode_mb = ff_h263_decode_mb;
s->low_delay = 1;
@@ -69,6 +76,7 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
/* select sub codec */
switch (avctx->codec->id) {
case AV_CODEC_ID_H263:
+ case AV_CODEC_ID_H263P:
s->unrestricted_mv = 0;
avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
break;
@@ -115,8 +123,13 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
}
s->codec_id = avctx->codec->id;
+ if (avctx->codec_tag == AV_RL32("L263") || avctx->codec_tag == AV_RL32("S263"))
+ if (avctx->extradata_size == 56 && avctx->extradata[0] == 1)
+ s->ehc_mode = 1;
+
/* for h263, we allocate the images after having read the header */
if (avctx->codec->id != AV_CODEC_ID_H263 &&
+ avctx->codec->id != AV_CODEC_ID_H263P &&
avctx->codec->id != AV_CODEC_ID_MPEG4) {
avctx->pix_fmt = h263_get_format(avctx);
ff_mpv_idct_init(s);
@@ -172,7 +185,7 @@ static int decode_slice(MpegEncContext *s)
{
const int part_mask = s->partitioned_frame
? (ER_AC_END | ER_AC_ERROR) : 0x7F;
- const int mb_size = 16;
+ const int mb_size = 16 >> s->avctx->lowres;
int ret;
s->last_resync_gb = s->gb;
@@ -184,10 +197,10 @@ static int decode_slice(MpegEncContext *s)
if (s->avctx->hwaccel) {
const uint8_t *start = s->gb.buffer + get_bits_count(&s->gb) / 8;
- const uint8_t *end = ff_h263_find_resync_marker(start + 1,
- s->gb.buffer_end);
- skip_bits_long(&s->gb, 8 * (end - start));
- return s->avctx->hwaccel->decode_slice(s->avctx, start, end - start);
+ ret = s->avctx->hwaccel->decode_slice(s->avctx, start, s->gb.buffer_end - start);
+ // ensure we exit decode loop
+ s->mb_y = s->mb_height;
+ return ret;
}
if (s->partitioned_frame) {
@@ -236,6 +249,8 @@ static int decode_slice(MpegEncContext *s)
s->mv_type = MV_TYPE_16X16;
ff_dlog(s, "%d %d %06X\n",
ret, get_bits_count(&s->gb), show_bits(&s->gb, 24));
+
+ ff_tlog(NULL, "Decoding MB at %dx%d\n", s->mb_x, s->mb_y);
ret = s->decode_mb(s, s->block);
if (s->pict_type != AV_PICTURE_TYPE_B)
@@ -272,6 +287,8 @@ static int decode_slice(MpegEncContext *s)
ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y,
s->mb_x, s->mb_y, ER_MB_ERROR & part_mask);
+ if (s->avctx->err_recognition & AV_EF_IGNORE_ERR)
+ continue;
return AVERROR_INVALIDDATA;
}
@@ -286,7 +303,7 @@ static int decode_slice(MpegEncContext *s)
s->mb_x = 0;
}
- assert(s->mb_x == 0 && s->mb_y == s->mb_height);
+ av_assert1(s->mb_x == 0 && s->mb_y == s->mb_height);
if (s->codec_id == AV_CODEC_ID_MPEG4 &&
(s->workaround_bugs & FF_BUG_AUTODETECT) &&
@@ -299,7 +316,7 @@ static int decode_slice(MpegEncContext *s)
if (s->codec_id == AV_CODEC_ID_MPEG4 &&
(s->workaround_bugs & FF_BUG_AUTODETECT) &&
get_bits_left(&s->gb) >= 0 &&
- get_bits_left(&s->gb) < 48 &&
+ get_bits_left(&s->gb) < 137 &&
!s->data_partitioning) {
const int bits_count = get_bits_count(&s->gb);
const int bits_left = s->gb.size_in_bits - bits_count;
@@ -320,8 +337,27 @@ static int decode_slice(MpegEncContext *s)
}
}
+ if (s->codec_id == AV_CODEC_ID_H263 &&
+ (s->workaround_bugs & FF_BUG_AUTODETECT) &&
+ get_bits_left(&s->gb) >= 8 &&
+ get_bits_left(&s->gb) < 300 &&
+ s->pict_type == AV_PICTURE_TYPE_I &&
+ show_bits(&s->gb, 8) == 0 &&
+ !s->data_partitioning) {
+
+ s->padding_bug_score += 32;
+ }
+
+ if (s->codec_id == AV_CODEC_ID_H263 &&
+ (s->workaround_bugs & FF_BUG_AUTODETECT) &&
+ get_bits_left(&s->gb) >= 64 &&
+ AV_RB64(s->gb.buffer_end - 8) == 0xCDCDCDCDFC7F0000) {
+
+ s->padding_bug_score += 32;
+ }
+
if (s->workaround_bugs & FF_BUG_AUTODETECT) {
- if (s->codec_id == AV_CODEC_ID_H263 ||
+ if (
(s->padding_bug_score > -2 && !s->data_partitioning))
s->workaround_bugs |= FF_BUG_NO_PADDING;
else
@@ -340,7 +376,7 @@ static int decode_slice(MpegEncContext *s)
/* buggy padding but the frame should still end approximately at
* the bitstream end */
if ((s->workaround_bugs & FF_BUG_NO_PADDING) &&
- (s->avctx->err_recognition & AV_EF_BUFFER))
+ (s->avctx->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE)))
max_extra += 48;
else if ((s->workaround_bugs & FF_BUG_NO_PADDING))
max_extra += 256 * 256 * 256 * 64;
@@ -375,6 +411,7 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int buf_size = avpkt->size;
MpegEncContext *s = avctx->priv_data;
int ret;
+ int slice_ret = 0;
AVFrame *pict = data;
/* no supplementary picture */
@@ -398,6 +435,8 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
next = ff_mpeg4_find_frame_end(&s->parse_context, buf, buf_size);
} else if (CONFIG_H263_DECODER && s->codec_id == AV_CODEC_ID_H263) {
next = ff_h263_find_frame_end(&s->parse_context, buf, buf_size);
+ } else if (CONFIG_H263P_DECODER && s->codec_id == AV_CODEC_ID_H263P) {
+ next = ff_h263_find_frame_end(&s->parse_context, buf, buf_size);
} else {
av_log(s->avctx, AV_LOG_ERROR,
"this codec does not support truncated bitstreams\n");
@@ -409,13 +448,27 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return buf_size;
}
- if (s->bitstream_buffer_size && (s->divx_packed || buf_size < 20)) // divx 5.01+/xvid frame reorder
+retry:
+ if (s->divx_packed && s->bitstream_buffer_size) {
+ int i;
+ for(i=0; i < buf_size-3; i++) {
+ if (buf[i]==0 && buf[i+1]==0 && buf[i+2]==1) {
+ if (buf[i+3]==0xB0) {
+ av_log(s->avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n");
+ s->bitstream_buffer_size = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ if (s->bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) // divx 5.01+/xvid frame reorder
ret = init_get_bits8(&s->gb, s->bitstream_buffer,
s->bitstream_buffer_size);
else
ret = init_get_bits8(&s->gb, buf, buf_size);
- s->bitstream_buffer_size = 0;
+ s->bitstream_buffer_size = 0;
if (ret < 0)
return ret;
@@ -432,11 +485,8 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (s->avctx->extradata_size && s->picture_number == 0) {
GetBitContext gb;
- ret = init_get_bits8(&gb, s->avctx->extradata,
- s->avctx->extradata_size);
- if (ret < 0)
- return ret;
- ff_mpeg4_decode_picture_header(avctx->priv_data, &gb);
+ if (init_get_bits8(&gb, s->avctx->extradata, s->avctx->extradata_size) >= 0 )
+ ff_mpeg4_decode_picture_header(avctx->priv_data, &gb);
}
ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb);
} else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) {
@@ -447,6 +497,14 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ret = ff_h263_decode_picture_header(s);
}
+ if (ret < 0 || ret == FRAME_SKIPPED) {
+ if ( s->width != avctx->coded_width
+ || s->height != avctx->coded_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;
+ }
+ }
if (ret == FRAME_SKIPPED)
return get_consumed_bytes(s, buf_size);
@@ -471,25 +529,9 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
avctx->has_b_frames = !s->low_delay;
-#define SET_QPEL_FUNC(postfix1, postfix2) \
- s->qdsp.put_ ## postfix1 = ff_put_ ## postfix2; \
- s->qdsp.put_no_rnd_ ## postfix1 = ff_put_no_rnd_ ## postfix2; \
- s->qdsp.avg_ ## postfix1 = ff_avg_ ## postfix2;
-
- if (s->workaround_bugs & FF_BUG_STD_QPEL) {
- SET_QPEL_FUNC(qpel_pixels_tab[0][5], qpel16_mc11_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[0][7], qpel16_mc31_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[0][9], qpel16_mc12_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[0][11], qpel16_mc32_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[0][13], qpel16_mc13_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[0][15], qpel16_mc33_old_c)
-
- SET_QPEL_FUNC(qpel_pixels_tab[1][5], qpel8_mc11_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[1][7], qpel8_mc31_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[1][9], qpel8_mc12_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[1][11], qpel8_mc32_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[1][13], qpel8_mc13_old_c)
- SET_QPEL_FUNC(qpel_pixels_tab[1][15], qpel8_mc33_old_c)
+ if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) {
+ if (ff_mpeg4_workaround_bugs(avctx) == 1)
+ goto retry;
}
/* After H263 & mpeg4 header decode we have the height, width,
@@ -559,6 +601,11 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (!s->divx_packed && !avctx->hwaccel)
ff_thread_finish_setup(avctx);
+ if (CONFIG_MPEG4_VDPAU_DECODER && (s->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)) {
+ ff_vdpau_mpeg4_decode_picture(avctx->priv_data, s->gb.buffer, s->gb.buffer_end - s->gb.buffer);
+ goto frame_end;
+ }
+
if (avctx->hwaccel) {
ret = avctx->hwaccel->start_frame(avctx, s->gb.buffer,
s->gb.buffer_end - s->gb.buffer);
@@ -576,14 +623,14 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (ret < 0)
return ret;
if (ret == 1)
- goto intrax8_decoded;
+ goto frame_end;
}
/* decode each macroblock */
s->mb_x = 0;
s->mb_y = 0;
- ret = decode_slice(s);
+ slice_ret = decode_slice(s);
while (s->mb_y < s->mb_height) {
if (s->msmpeg4_version) {
if (s->slice_height == 0 || s->mb_x != 0 ||
@@ -601,7 +648,7 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ff_mpeg4_clean_buffers(s);
if (decode_slice(s) < 0)
- ret = AVERROR_INVALIDDATA;
+ slice_ret = AVERROR_INVALIDDATA;
}
if (s->msmpeg4_version && s->msmpeg4_version < 4 &&
@@ -610,12 +657,8 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ff_msmpeg4_decode_ext_header(s, buf_size) < 0)
s->er.error_status_table[s->mb_num - 1] = ER_MB_ERROR;
- assert(s->bitstream_buffer_size == 0);
-
- if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4)
- ff_mpeg4_frame_end(avctx, buf, buf_size);
-
-intrax8_decoded:
+ av_assert1(s->bitstream_buffer_size == 0);
+frame_end:
ff_er_frame_end(&s->er);
if (avctx->hwaccel) {
@@ -626,26 +669,46 @@ intrax8_decoded:
ff_mpv_frame_end(s);
+ if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4)
+ ff_mpeg4_frame_end(avctx, buf, buf_size);
+
if (!s->divx_packed && avctx->hwaccel)
ff_thread_finish_setup(avctx);
- assert(s->current_picture.f->pict_type ==
- s->current_picture_ptr->f->pict_type);
- assert(s->current_picture.f->pict_type == s->pict_type);
+ 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);
if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->current_picture_ptr);
+ ff_print_debug_info(s, s->current_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_QSCALE_TYPE_MPEG1);
} else if (s->last_picture_ptr) {
if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->last_picture_ptr);
+ ff_print_debug_info(s, s->last_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_QSCALE_TYPE_MPEG1);
}
- if (s->last_picture_ptr || s->low_delay)
+ if (s->last_picture_ptr || s->low_delay) {
+ if ( pict->format == AV_PIX_FMT_YUV420P
+ && (s->codec_tag == AV_RL32("GEOV") || s->codec_tag == AV_RL32("GEOX"))) {
+ int x, y, p;
+ av_frame_make_writable(pict);
+ for (p=0; p<3; p++) {
+ int w = FF_CEIL_RSHIFT(pict-> width, !!p);
+ int h = FF_CEIL_RSHIFT(pict->height, !!p);
+ int linesize = pict->linesize[p];
+ for (y=0; y<(h>>1); y++)
+ for (x=0; x<w; x++)
+ FFSWAP(int,
+ pict->data[p][x + y*linesize],
+ pict->data[p][x + (h-1-y)*linesize]);
+ }
+ }
*got_frame = 1;
+ }
- if (ret && (avctx->err_recognition & AV_EF_EXPLODE))
+ if (slice_ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
return ret;
else
return get_consumed_bytes(s, buf_size);
@@ -674,5 +737,22 @@ AVCodec ff_h263_decoder = {
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 |
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY,
.flush = ff_mpeg_flush,
+ .max_lowres = 3,
+ .pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
+};
+
+AVCodec ff_h263p_decoder = {
+ .name = "h263p",
+ .long_name = NULL_IF_CONFIG_SMALL("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H263P,
+ .priv_data_size = sizeof(MpegEncContext),
+ .init = ff_h263_decode_init,
+ .close = ff_h263_decode_end,
+ .decode = ff_h263_decode_frame,
+ .capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 |
+ CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY,
+ .flush = ff_mpeg_flush,
+ .max_lowres = 3,
.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
};
diff --git a/libavcodec/h263dsp.c b/libavcodec/h263dsp.c
index 70ecdb9a89..a70ff24fdf 100644
--- a/libavcodec/h263dsp.c
+++ b/libavcodec/h263dsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h263dsp.h b/libavcodec/h263dsp.h
index 40f041cd0d..d2cc2ffe70 100644
--- a/libavcodec/h263dsp.h
+++ b/libavcodec/h263dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index e39a119364..1ba0e95924 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,8 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/avassert.h"
#include "libavutil/display.h"
#include "libavutil/imgutils.h"
@@ -47,11 +49,16 @@
#include "rectangle.h"
#include "svq3.h"
#include "thread.h"
-
-#include <assert.h>
+#include "vdpau_internal.h"
const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 };
+int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx)
+{
+ H264Context *h = avctx->priv_data;
+ return h ? h->sps.num_reorder_frames : 0;
+}
+
static void h264_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type,
int (*mv)[2][4][2],
int mb_x, int mb_y, int mb_intra, int mb_skipped)
@@ -63,19 +70,28 @@ static void h264_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type,
sl->mb_y = mb_y;
sl->mb_xy = mb_x + mb_y * h->mb_stride;
memset(sl->non_zero_count_cache, 0, sizeof(sl->non_zero_count_cache));
- assert(ref >= 0);
+ av_assert1(ref >= 0);
/* FIXME: It is possible albeit uncommon that slice references
* differ between slices. We take the easy approach and ignore
* it for now. If this turns out to have any relevance in
* practice then correct remapping should be added. */
if (ref >= sl->ref_count[0])
ref = 0;
+ if (!sl->ref_list[0][ref].data[0]) {
+ av_log(h->avctx, AV_LOG_DEBUG, "Reference not available for error concealing\n");
+ ref = 0;
+ }
+ if ((sl->ref_list[0][ref].reference&3) != 3) {
+ av_log(h->avctx, AV_LOG_DEBUG, "Reference invalid\n");
+ return;
+ }
fill_rectangle(&h->cur_pic.ref_index[0][4 * sl->mb_xy],
2, 2, 2, ref, 1);
fill_rectangle(&sl->ref_cache[0][scan8[0]], 4, 4, 8, ref, 1);
fill_rectangle(sl->mv_cache[0][scan8[0]], 4, 4, 8,
pack16to32((*mv)[0][0][0], (*mv)[0][0][1]), 4);
- assert(!FRAME_MBAFF(h));
+ sl->mb_mbaff =
+ sl->mb_field_decoding_flag = 0;
ff_h264_hl_decode_mb(h, &h->slice_ctx[0]);
}
@@ -190,18 +206,18 @@ int ff_h264_check_intra_pred_mode(const H264Context *h, H264SliceContext *sl,
if ((sl->left_samples_available & 0x8080) != 0x8080) {
mode = left[mode];
- if (is_chroma && (sl->left_samples_available & 0x8080)) {
- // mad cow disease mode, aka MBAFF + constrained_intra_pred
- mode = ALZHEIMER_DC_L0T_PRED8x8 +
- (!(sl->left_samples_available & 0x8000)) +
- 2 * (mode == DC_128_PRED8x8);
- }
if (mode < 0) {
av_log(h->avctx, AV_LOG_ERROR,
"left block unavailable for requested intra mode at %d %d\n",
sl->mb_x, sl->mb_y);
return AVERROR_INVALIDDATA;
}
+ if (is_chroma && (sl->left_samples_available & 0x8080)) {
+ // mad cow disease mode, aka MBAFF + constrained_intra_pred
+ mode = ALZHEIMER_DC_L0T_PRED8x8 +
+ (!(sl->left_samples_available & 0x8000)) +
+ 2 * (mode == DC_128_PRED8x8);
+ }
}
return mode;
@@ -223,7 +239,7 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, H264SliceContext *sl,
#define STARTCODE_TEST \
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \
- if (src[i + 2] != 3) { \
+ if (src[i + 2] != 3 && src[i + 2] != 0) { \
/* startcode, so we must be past the end */ \
length = i; \
} \
@@ -268,19 +284,23 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, H264SliceContext *sl,
}
#endif
- if (i >= length - 1) { // no escaped 0
- *dst_length = length;
- *consumed = length + 1; // +1 for the header
- return src;
- }
-
- av_fast_malloc(&sl->rbsp_buffer, &sl->rbsp_buffer_size,
- length + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_fast_padded_malloc(&sl->rbsp_buffer, &sl->rbsp_buffer_size, length+MAX_MBPAIR_SIZE);
dst = sl->rbsp_buffer;
if (!dst)
return NULL;
+ if(i>=length-1){ //no escaped 0
+ *dst_length= length;
+ *consumed= length+1; //+1 for the header
+ if(h->avctx->flags2 & CODEC_FLAG2_FAST){
+ return src;
+ }else{
+ memcpy(dst, src, length);
+ return dst;
+ }
+ }
+
memcpy(dst, src, i);
si = di = i;
while (si + 2 < length) {
@@ -288,7 +308,7 @@ const uint8_t *ff_h264_decode_nal(H264Context *h, H264SliceContext *sl,
if (src[si + 2] > 3) {
dst[di++] = src[si++];
dst[di++] = src[si++];
- } else if (src[si] == 0 && src[si + 1] == 0) {
+ } else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] != 0) {
if (src[si + 2] == 3) { // escape
dst[di++] = 0;
dst[di++] = 0;
@@ -378,11 +398,11 @@ void ff_h264_free_tables(H264Context *h)
int ff_h264_alloc_tables(H264Context *h)
{
const int big_mb_num = h->mb_stride * (h->mb_height + 1);
- const int row_mb_num = h->mb_stride * 2 * h->avctx->thread_count;
+ const int row_mb_num = 2*h->mb_stride*FFMAX(h->avctx->thread_count, 1);
int x, y;
- FF_ALLOCZ_OR_GOTO(h->avctx, h->intra4x4_pred_mode,
- row_mb_num * 8 * sizeof(uint8_t), fail)
+ FF_ALLOCZ_ARRAY_OR_GOTO(h->avctx, h->intra4x4_pred_mode,
+ row_mb_num, 8 * sizeof(uint8_t), fail)
h->slice_ctx[0].intra4x4_pred_mode = h->intra4x4_pred_mode;
FF_ALLOCZ_OR_GOTO(h->avctx, h->non_zero_count,
@@ -393,10 +413,10 @@ int ff_h264_alloc_tables(H264Context *h)
big_mb_num * sizeof(uint16_t), fail)
FF_ALLOCZ_OR_GOTO(h->avctx, h->chroma_pred_mode_table,
big_mb_num * sizeof(uint8_t), fail)
- FF_ALLOCZ_OR_GOTO(h->avctx, h->mvd_table[0],
- 16 * row_mb_num * sizeof(uint8_t), fail);
- FF_ALLOCZ_OR_GOTO(h->avctx, h->mvd_table[1],
- 16 * row_mb_num * sizeof(uint8_t), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(h->avctx, h->mvd_table[0],
+ row_mb_num, 16 * sizeof(uint8_t), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(h->avctx, h->mvd_table[1],
+ row_mb_num, 16 * sizeof(uint8_t), fail);
h->slice_ctx[0].mvd_table[0] = h->mvd_table[0];
h->slice_ctx[0].mvd_table[1] = h->mvd_table[1];
@@ -423,7 +443,7 @@ int ff_h264_alloc_tables(H264Context *h)
}
if (!h->dequant4_coeff[0])
- h264_init_dequant_tables(h);
+ ff_h264_init_dequant_tables(h);
return 0;
@@ -452,7 +472,11 @@ int ff_h264_slice_context_init(H264Context *h, H264SliceContext *sl)
sl->ref_cache[1][scan8[7] + 1] =
sl->ref_cache[1][scan8[13] + 1] = PART_NOT_AVAILABLE;
+ if (sl != h->slice_ctx) {
+ memset(er, 0, sizeof(*er));
+ } else
if (CONFIG_ERROR_RESILIENCE) {
+
/* init ER */
er->avctx = h->avctx;
er->decode_mb = h264_er_decode_mb;
@@ -500,20 +524,23 @@ fail:
static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
int parse_extradata);
-int ff_h264_decode_extradata(H264Context *h)
+int ff_h264_decode_extradata(H264Context *h, const uint8_t *buf, int size)
{
AVCodecContext *avctx = h->avctx;
int ret;
- if (avctx->extradata[0] == 1) {
+ if (!buf || size <= 0)
+ return -1;
+
+ if (buf[0] == 1) {
int i, cnt, nalsize;
- unsigned char *p = avctx->extradata;
+ const unsigned char *p = buf;
h->is_avc = 1;
- if (avctx->extradata_size < 7) {
+ if (size < 7) {
av_log(avctx, AV_LOG_ERROR,
- "avcC %d too short\n", avctx->extradata_size);
+ "avcC %d too short\n", size);
return AVERROR_INVALIDDATA;
}
/* sps and pps in the avcC always have length coded with 2 bytes,
@@ -524,7 +551,7 @@ int ff_h264_decode_extradata(H264Context *h)
p += 6;
for (i = 0; i < cnt; i++) {
nalsize = AV_RB16(p) + 2;
- if (p - avctx->extradata + nalsize > avctx->extradata_size)
+ if(nalsize > size - (p-buf))
return AVERROR_INVALIDDATA;
ret = decode_nal_units(h, p, nalsize, 1);
if (ret < 0) {
@@ -538,7 +565,7 @@ int ff_h264_decode_extradata(H264Context *h)
cnt = *(p++); // Number of pps
for (i = 0; i < cnt; i++) {
nalsize = AV_RB16(p) + 2;
- if (p - avctx->extradata + nalsize > avctx->extradata_size)
+ if(nalsize > size - (p-buf))
return AVERROR_INVALIDDATA;
ret = decode_nal_units(h, p, nalsize, 1);
if (ret < 0) {
@@ -549,14 +576,14 @@ int ff_h264_decode_extradata(H264Context *h)
p += nalsize;
}
// Store right nal length size that will be used to parse all other nals
- h->nal_length_size = (avctx->extradata[4] & 0x03) + 1;
+ h->nal_length_size = (buf[4] & 0x03) + 1;
} else {
h->is_avc = 0;
- ret = decode_nal_units(h, avctx->extradata, avctx->extradata_size, 1);
+ ret = decode_nal_units(h, buf, size, 1);
if (ret < 0)
return ret;
}
- return 0;
+ return size;
}
static int h264_init_context(AVCodecContext *avctx, H264Context *h)
@@ -565,6 +592,8 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
h->avctx = avctx;
h->dequant_coeff_pps = -1;
+ h->current_sps_id = -1;
+ h->cur_chroma_format_idc = -1;
h->picture_structure = PICT_FRAME;
h->slice_context_count = 1;
@@ -574,6 +603,8 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
h->x264_build = -1;
h->recovery_frame = -1;
h->frame_recovered = 0;
+ h->prev_frame_num = -1;
+ h->sei_fpa.frame_packing_arrangement_cancel_flag = -1;
h->next_outputed_poc = INT_MIN;
for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
@@ -600,6 +631,10 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
if (!h->cur_pic.f)
return AVERROR(ENOMEM);
+ h->last_pic_for_ec.f = av_frame_alloc();
+ if (!h->last_pic_for_ec.f)
+ return AVERROR(ENOMEM);
+
for (i = 0; i < h->nb_slice_ctx; i++)
h->slice_ctx[i].h264 = h;
@@ -624,17 +659,21 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
ff_init_cabac_states();
if (avctx->codec_id == AV_CODEC_ID_H264) {
- if (avctx->ticks_per_frame == 1)
- h->avctx->framerate.num *= 2;
+ if (avctx->ticks_per_frame == 1) {
+ if(h->avctx->time_base.den < INT_MAX/2) {
+ h->avctx->time_base.den *= 2;
+ } else
+ h->avctx->time_base.num /= 2;
+ }
avctx->ticks_per_frame = 2;
}
if (avctx->extradata_size > 0 && avctx->extradata) {
- ret = ff_h264_decode_extradata(h);
- if (ret < 0) {
- ff_h264_free_context(h);
- return ret;
- }
+ ret = ff_h264_decode_extradata(h, avctx->extradata, avctx->extradata_size);
+ if (ret < 0) {
+ ff_h264_free_context(h);
+ return ret;
+ }
}
if (h->sps.bitstream_restriction_flag &&
@@ -645,9 +684,14 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
avctx->internal->allocate_progress = 1;
- if (h->enable_er) {
+ ff_h264_flush_change(h);
+
+ if (h->enable_er < 0 && (avctx->active_thread_type & FF_THREAD_SLICE))
+ h->enable_er = 0;
+
+ if (h->enable_er && (avctx->active_thread_type & FF_THREAD_SLICE)) {
av_log(avctx, AV_LOG_WARNING,
- "Error resilience is enabled. It is unsafe and unsupported and may crash. "
+ "Error resilience with slice threads is enabled. It is unsafe and unsupported and may crash. "
"Use it at your own risk\n");
}
@@ -686,7 +730,6 @@ static void decode_postinit(H264Context *h, int setup_finished)
H264Picture *out = h->cur_pic_ptr;
H264Picture *cur = h->cur_pic_ptr;
int i, pics, out_of_order, out_idx;
- int invalid = 0, cnt = 0;
h->cur_pic_ptr->f->pict_type = h->pict_type;
@@ -700,7 +743,10 @@ static void decode_postinit(H264Context *h, int setup_finished)
* yet, so we assume the worst for now. */
// if (setup_finished)
// ff_thread_finish_setup(h->avctx);
- return;
+ if (cur->field_poc[0] == INT_MAX && cur->field_poc[1] == INT_MAX)
+ return;
+ if (h->avctx->hwaccel || h->missing_fields <=1)
+ return;
}
cur->f->interlaced_frame = 0;
@@ -774,9 +820,7 @@ static void decode_postinit(H264Context *h, int setup_finished)
h->content_interpretation_type > 0 &&
h->content_interpretation_type < 3) {
AVStereo3D *stereo = av_stereo3d_create_side_data(cur->f);
- if (!stereo)
- return;
-
+ if (stereo) {
switch (h->frame_packing_arrangement_type) {
case 0:
stereo->type = AV_STEREO3D_CHECKERBOARD;
@@ -806,6 +850,7 @@ static void decode_postinit(H264Context *h, int setup_finished)
if (h->content_interpretation_type == 2)
stereo->flags = AV_STEREO3D_FLAG_INVERT;
+ }
}
if (h->sei_display_orientation_present &&
@@ -814,14 +859,16 @@ static void decode_postinit(H264Context *h, int setup_finished)
AVFrameSideData *rotation = av_frame_new_side_data(cur->f,
AV_FRAME_DATA_DISPLAYMATRIX,
sizeof(int32_t) * 9);
- if (!rotation)
- return;
-
- av_display_rotation_set((int32_t *)rotation->data, angle);
- av_display_matrix_flip((int32_t *)rotation->data,
- h->sei_hflip, h->sei_vflip);
+ if (rotation) {
+ av_display_rotation_set((int32_t *)rotation->data, angle);
+ av_display_matrix_flip((int32_t *)rotation->data,
+ h->sei_hflip, h->sei_vflip);
+ }
}
+ cur->mmco_reset = h->mmco_reset;
+ h->mmco_reset = 0;
+
// FIXME do something with unavailable reference frames
/* Sort B-frames into display order */
@@ -838,107 +885,71 @@ static void decode_postinit(H264Context *h, int setup_finished)
h->low_delay = 0;
}
+ for (i = 0; 1; i++) {
+ if(i == MAX_DELAYED_PIC_COUNT || cur->poc < h->last_pocs[i]){
+ if(i)
+ h->last_pocs[i-1] = cur->poc;
+ break;
+ } else if(i) {
+ h->last_pocs[i-1]= h->last_pocs[i];
+ }
+ }
+ out_of_order = MAX_DELAYED_PIC_COUNT - i;
+ if( cur->f->pict_type == AV_PICTURE_TYPE_B
+ || (h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && h->last_pocs[MAX_DELAYED_PIC_COUNT-1] - h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2))
+ out_of_order = FFMAX(out_of_order, 1);
+ if (out_of_order == MAX_DELAYED_PIC_COUNT) {
+ av_log(h->avctx, AV_LOG_VERBOSE, "Invalid POC %d<%d\n", cur->poc, h->last_pocs[0]);
+ for (i = 1; i < MAX_DELAYED_PIC_COUNT; i++)
+ h->last_pocs[i] = INT_MIN;
+ h->last_pocs[0] = cur->poc;
+ cur->mmco_reset = 1;
+ } else if(h->avctx->has_b_frames < out_of_order && !h->sps.bitstream_restriction_flag){
+ av_log(h->avctx, AV_LOG_VERBOSE, "Increasing reorder buffer to %d\n", out_of_order);
+ h->avctx->has_b_frames = out_of_order;
+ h->low_delay = 0;
+ }
+
pics = 0;
while (h->delayed_pic[pics])
pics++;
- assert(pics <= MAX_DELAYED_PIC_COUNT);
+ av_assert0(pics <= MAX_DELAYED_PIC_COUNT);
h->delayed_pic[pics++] = cur;
if (cur->reference == 0)
cur->reference = DELAYED_PIC_REF;
- /* Frame reordering. This code takes pictures from coding order and sorts
- * them by their incremental POC value into display order. It supports POC
- * gaps, MMCO reset codes and random resets.
- * A "display group" can start either with a IDR frame (f.key_frame = 1),
- * and/or can be closed down with a MMCO reset code. In sequences where
- * there is no delay, we can't detect that (since the frame was already
- * output to the user), so we also set h->mmco_reset to detect the MMCO
- * reset code.
- * FIXME: if we detect insufficient delays (as per h->avctx->has_b_frames),
- * we increase the delay between input and output. All frames affected by
- * the lag (e.g. those that should have been output before another frame
- * that we already returned to the user) will be dropped. This is a bug
- * that we will fix later. */
- for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++) {
- cnt += out->poc < h->last_pocs[i];
- invalid += out->poc == INT_MIN;
- }
- if (!h->mmco_reset && !cur->f->key_frame &&
- cnt + invalid == MAX_DELAYED_PIC_COUNT && cnt > 0) {
- h->mmco_reset = 2;
- if (pics > 1)
- h->delayed_pic[pics - 2]->mmco_reset = 2;
- }
- if (h->mmco_reset || cur->f->key_frame) {
- for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
- h->last_pocs[i] = INT_MIN;
- cnt = 0;
- invalid = MAX_DELAYED_PIC_COUNT;
- }
out = h->delayed_pic[0];
out_idx = 0;
- for (i = 1; i < MAX_DELAYED_PIC_COUNT &&
- h->delayed_pic[i] &&
- !h->delayed_pic[i - 1]->mmco_reset &&
- !h->delayed_pic[i]->f->key_frame;
+ for (i = 1; h->delayed_pic[i] &&
+ !h->delayed_pic[i]->f->key_frame &&
+ !h->delayed_pic[i]->mmco_reset;
i++)
if (h->delayed_pic[i]->poc < out->poc) {
out = h->delayed_pic[i];
out_idx = i;
}
if (h->avctx->has_b_frames == 0 &&
- (h->delayed_pic[0]->f->key_frame || h->mmco_reset))
+ (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset))
h->next_outputed_poc = INT_MIN;
- out_of_order = !out->f->key_frame && !h->mmco_reset &&
- (out->poc < h->next_outputed_poc);
+ out_of_order = out->poc < h->next_outputed_poc;
- if (h->sps.bitstream_restriction_flag &&
- h->avctx->has_b_frames >= h->sps.num_reorder_frames) {
- } else if (out_of_order && pics - 1 == h->avctx->has_b_frames &&
- h->avctx->has_b_frames < MAX_DELAYED_PIC_COUNT) {
- if (invalid + cnt < MAX_DELAYED_PIC_COUNT) {
- h->avctx->has_b_frames = FFMAX(h->avctx->has_b_frames, cnt);
- }
- h->low_delay = 0;
- } else if (h->low_delay &&
- ((h->next_outputed_poc != INT_MIN &&
- out->poc > h->next_outputed_poc + 2) ||
- cur->f->pict_type == AV_PICTURE_TYPE_B)) {
- h->low_delay = 0;
- h->avctx->has_b_frames++;
- }
-
- if (pics > h->avctx->has_b_frames) {
+ if (out_of_order || pics > h->avctx->has_b_frames) {
out->reference &= ~DELAYED_PIC_REF;
// for frame threading, the owner must be the second field's thread or
// else the first thread can release the picture and reuse it unsafely
for (i = out_idx; h->delayed_pic[i]; i++)
h->delayed_pic[i] = h->delayed_pic[i + 1];
}
- memmove(h->last_pocs, &h->last_pocs[1],
- sizeof(*h->last_pocs) * (MAX_DELAYED_PIC_COUNT - 1));
- h->last_pocs[MAX_DELAYED_PIC_COUNT - 1] = cur->poc;
if (!out_of_order && pics > h->avctx->has_b_frames) {
h->next_output_pic = out;
- if (out->mmco_reset) {
- if (out_idx > 0) {
- h->next_outputed_poc = out->poc;
- h->delayed_pic[out_idx - 1]->mmco_reset = out->mmco_reset;
- } else {
- h->next_outputed_poc = INT_MIN;
- }
- } else {
- if (out_idx == 0 && pics > 1 && h->delayed_pic[0]->f->key_frame) {
- h->next_outputed_poc = INT_MIN;
- } else {
- h->next_outputed_poc = out->poc;
- }
- }
- h->mmco_reset = 0;
+ if (out_idx == 0 && h->delayed_pic[0] && (h->delayed_pic[0]->f->key_frame || h->delayed_pic[0]->mmco_reset)) {
+ h->next_outputed_poc = INT_MIN;
+ } else
+ h->next_outputed_poc = out->poc;
} else {
- av_log(h->avctx, AV_LOG_DEBUG, "no picture\n");
+ av_log(h->avctx, AV_LOG_DEBUG, "no picture %s\n", out_of_order ? "ooo" : "");
}
if (h->next_output_pic) {
@@ -964,6 +975,16 @@ int ff_pred_weight_table(H264Context *h, H264SliceContext *sl)
sl->luma_log2_weight_denom = get_ue_golomb(&sl->gb);
if (h->sps.chroma_format_idc)
sl->chroma_log2_weight_denom = get_ue_golomb(&sl->gb);
+
+ if (sl->luma_log2_weight_denom > 7U) {
+ av_log(h->avctx, AV_LOG_ERROR, "luma_log2_weight_denom %d is out of range\n", sl->luma_log2_weight_denom);
+ sl->luma_log2_weight_denom = 0;
+ }
+ if (sl->chroma_log2_weight_denom > 7U) {
+ av_log(h->avctx, AV_LOG_ERROR, "chroma_log2_weight_denom %d is out of range\n", sl->chroma_log2_weight_denom);
+ sl->chroma_log2_weight_denom = 0;
+ }
+
luma_def = 1 << sl->luma_log2_weight_denom;
chroma_def = 1 << sl->chroma_log2_weight_denom;
@@ -1021,28 +1042,43 @@ int ff_pred_weight_table(H264Context *h, H264SliceContext *sl)
*/
static void idr(H264Context *h)
{
+ int i;
ff_h264_remove_all_refs(h);
h->prev_frame_num =
- h->prev_frame_num_offset =
- h->prev_poc_msb =
+ h->prev_frame_num_offset = 0;
+ h->prev_poc_msb = 1<<16;
h->prev_poc_lsb = 0;
+ for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
+ h->last_pocs[i] = INT_MIN;
}
/* forget old pics after a seek */
void ff_h264_flush_change(H264Context *h)
{
- int i;
- for (i = 0; i < MAX_DELAYED_PIC_COUNT; i++)
- h->last_pocs[i] = INT_MIN;
+ int i, j;
+
h->next_outputed_poc = INT_MIN;
h->prev_interlaced_frame = 1;
idr(h);
- if (h->cur_pic_ptr)
+
+ h->prev_frame_num = -1;
+ if (h->cur_pic_ptr) {
h->cur_pic_ptr->reference = 0;
+ for (j=i=0; h->delayed_pic[i]; i++)
+ if (h->delayed_pic[i] != h->cur_pic_ptr)
+ h->delayed_pic[j++] = h->delayed_pic[i];
+ h->delayed_pic[j] = NULL;
+ }
+ ff_h264_unref_picture(h, &h->last_pic_for_ec);
+
h->first_field = 0;
ff_h264_reset_sei(h);
h->recovery_frame = -1;
h->frame_recovered = 0;
+ h->current_slice = 0;
+ h->mmco_reset = 1;
+ for (i = 0; i < h->nb_slice_ctx; i++)
+ h->slice_ctx[i].list_count = 0;
}
/* forget old pics after a seek */
@@ -1174,26 +1210,34 @@ int ff_h264_get_profile(SPS *sps)
int ff_set_ref_count(H264Context *h, H264SliceContext *sl)
{
int ref_count[2], list_count;
- int num_ref_idx_active_override_flag, max_refs;
+ int num_ref_idx_active_override_flag;
// set defaults, might be overridden a few lines later
ref_count[0] = h->pps.ref_count[0];
ref_count[1] = h->pps.ref_count[1];
if (sl->slice_type_nos != AV_PICTURE_TYPE_I) {
+ unsigned max[2];
+ max[0] = max[1] = h->picture_structure == PICT_FRAME ? 15 : 31;
+
if (sl->slice_type_nos == AV_PICTURE_TYPE_B)
sl->direct_spatial_mv_pred = get_bits1(&sl->gb);
num_ref_idx_active_override_flag = get_bits1(&sl->gb);
if (num_ref_idx_active_override_flag) {
ref_count[0] = get_ue_golomb(&sl->gb) + 1;
- if (ref_count[0] < 1)
- return AVERROR_INVALIDDATA;
if (sl->slice_type_nos == AV_PICTURE_TYPE_B) {
ref_count[1] = get_ue_golomb(&sl->gb) + 1;
- if (ref_count[1] < 1)
- return AVERROR_INVALIDDATA;
- }
+ } else
+ // full range is spec-ok in this case, even for frames
+ ref_count[1] = 1;
+ }
+
+ if (ref_count[0]-1 > max[0] || ref_count[1]-1 > max[1]){
+ av_log(h->avctx, AV_LOG_ERROR, "reference overflow %u > %u or %u > %u\n", ref_count[0]-1, max[0], ref_count[1]-1, max[1]);
+ sl->ref_count[0] = sl->ref_count[1] = 0;
+ sl->list_count = 0;
+ return AVERROR_INVALIDDATA;
}
if (sl->slice_type_nos == AV_PICTURE_TYPE_B)
@@ -1205,14 +1249,6 @@ int ff_set_ref_count(H264Context *h, H264SliceContext *sl)
ref_count[0] = ref_count[1] = 0;
}
- max_refs = h->picture_structure == PICT_FRAME ? 16 : 32;
-
- if (ref_count[0] > max_refs || ref_count[1] > max_refs) {
- av_log(h->avctx, AV_LOG_ERROR, "reference overflow\n");
- sl->ref_count[0] = sl->ref_count[1] = 0;
- return AVERROR_INVALIDDATA;
- }
-
if (list_count != sl->list_count ||
ref_count[0] != sl->ref_count[0] ||
ref_count[1] != sl->ref_count[1]) {
@@ -1225,40 +1261,7 @@ int ff_set_ref_count(H264Context *h, H264SliceContext *sl)
return 0;
}
-static int find_start_code(const uint8_t *buf, int buf_size,
- int buf_index, int next_avc)
-{
- // start code prefix search
- for (; buf_index + 3 < next_avc; buf_index++)
- // This should always succeed in the first iteration.
- if (buf[buf_index] == 0 &&
- buf[buf_index + 1] == 0 &&
- buf[buf_index + 2] == 1)
- break;
-
- if (buf_index + 3 >= buf_size)
- return buf_size;
-
- return buf_index + 3;
-}
-
-static int get_avc_nalsize(H264Context *h, const uint8_t *buf,
- int buf_size, int *buf_index)
-{
- int i, nalsize = 0;
-
- if (*buf_index >= buf_size - h->nal_length_size)
- return -1;
-
- for (i = 0; i < h->nal_length_size; i++)
- nalsize = (nalsize << 8) | buf[(*buf_index)++];
- if (nalsize <= 0 || nalsize > buf_size - *buf_index) {
- av_log(h->avctx, AV_LOG_ERROR,
- "AVC: nal size %d\n", nalsize);
- return -1;
- }
- return nalsize;
-}
+static const uint8_t start_code[] = { 0x00, 0x00, 0x01 };
static int get_bit_length(H264Context *h, const uint8_t *buf,
const uint8_t *ptr, int dst_length,
@@ -1285,6 +1288,7 @@ static int get_last_needed_nal(H264Context *h, const uint8_t *buf, int buf_size)
int nal_index = 0;
int buf_index = 0;
int nals_needed = 0;
+ int first_slice = 0;
while(1) {
GetBitContext gb;
@@ -1301,6 +1305,8 @@ static int get_last_needed_nal(H264Context *h, const uint8_t *buf, int buf_size)
buf_index = find_start_code(buf, buf_size, buf_index, next_avc);
if (buf_index >= buf_size)
break;
+ if (buf_index >= next_avc)
+ continue;
}
ptr = ff_h264_decode_nal(h, &h->slice_ctx[0], buf + buf_index, &dst_length, &consumed,
@@ -1328,8 +1334,12 @@ static int get_last_needed_nal(H264Context *h, const uint8_t *buf, int buf_size)
case NAL_IDR_SLICE:
case NAL_SLICE:
init_get_bits(&gb, ptr, bit_length);
- if (!get_ue_golomb(&gb))
+ if (!get_ue_golomb(&gb) ||
+ !first_slice ||
+ first_slice != h->nal_unit_type)
nals_needed = nal_index;
+ if (!first_slice)
+ first_slice = h->nal_unit_type;
}
}
@@ -1346,8 +1356,13 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
int next_avc;
int nals_needed = 0; ///< number of NALs that need decoding before the next frame thread starts
int nal_index;
+ int idr_cleared=0;
int ret = 0;
+ h->nal_unit_type= 0;
+
+ if(!h->slice_context_count)
+ h->slice_context_count= 1;
h->max_contexts = h->slice_context_count;
if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS)) {
h->current_slice = 0;
@@ -1356,6 +1371,13 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
ff_h264_reset_sei(h);
}
+ if (h->nal_length_size == 4) {
+ if (buf_size > 8 && AV_RB32(buf) == 1 && AV_RB32(buf+5) > (unsigned)buf_size) {
+ h->is_avc = 0;
+ }else if(buf_size > 3 && AV_RB32(buf) > 1 && AV_RB32(buf) <= (unsigned)buf_size)
+ h->is_avc = 1;
+ }
+
if (avctx->active_thread_type & FF_THREAD_FRAME)
nals_needed = get_last_needed_nal(h, buf, buf_size);
@@ -1399,8 +1421,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
if (h->avctx->debug & FF_DEBUG_STARTCODE)
av_log(h->avctx, AV_LOG_DEBUG,
- "NAL %d at %d/%d length %d\n",
- h->nal_unit_type, buf_index, buf_size, dst_length);
+ "NAL %d/%d at %d/%d length %d\n",
+ h->nal_unit_type, h->nal_ref_idc, buf_index, buf_size, dst_length);
if (h->is_avc && (nalsize != consumed) && nalsize)
av_log(h->avctx, AV_LOG_DEBUG,
@@ -1416,44 +1438,76 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,
continue;
again:
- /* Ignore every NAL unit type except PPS and SPS during extradata
+ /* Ignore per frame NAL unit type during extradata
* parsing. Decoding slices is not possible in codec init
* with frame-mt */
- if (parse_extradata && HAVE_THREADS &&
- (h->avctx->active_thread_type & FF_THREAD_FRAME) &&
- (h->nal_unit_type != NAL_PPS &&
- h->nal_unit_type != NAL_SPS)) {
- if (h->nal_unit_type < NAL_AUD ||
- h->nal_unit_type > NAL_AUXILIARY_SLICE)
- av_log(avctx, AV_LOG_INFO,
- "Ignoring NAL unit %d during extradata parsing\n",
+ if (parse_extradata) {
+ switch (h->nal_unit_type) {
+ case NAL_IDR_SLICE:
+ case NAL_SLICE:
+ case NAL_DPA:
+ case NAL_DPB:
+ case NAL_DPC:
+ av_log(h->avctx, AV_LOG_WARNING,
+ "Ignoring NAL %d in global header/extradata\n",
h->nal_unit_type);
- h->nal_unit_type = NAL_FF_IGNORE;
+ // fall through to next case
+ case NAL_AUXILIARY_SLICE:
+ h->nal_unit_type = NAL_FF_IGNORE;
+ }
}
+
err = 0;
+
switch (h->nal_unit_type) {
case NAL_IDR_SLICE:
+ if ((ptr[0] & 0xFC) == 0x98) {
+ av_log(h->avctx, AV_LOG_ERROR, "Invalid inter IDR frame\n");
+ h->next_outputed_poc = INT_MIN;
+ ret = -1;
+ goto end;
+ }
if (h->nal_unit_type != NAL_IDR_SLICE) {
av_log(h->avctx, AV_LOG_ERROR,
"Invalid mix of idr and non-idr slices\n");
ret = -1;
goto end;
}
- idr(h); // FIXME ensure we don't lose some frames if there is reordering
+ if(!idr_cleared) {
+ if (h->current_slice && (avctx->active_thread_type & FF_THREAD_SLICE)) {
+ av_log(h, AV_LOG_ERROR, "invalid mixed IDR / non IDR frames cannot be decoded in slice multithreading mode\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+ idr(h); // FIXME ensure we don't lose some frames if there is reordering
+ }
+ idr_cleared = 1;
+ h->has_recovery_point = 1;
case NAL_SLICE:
init_get_bits(&sl->gb, ptr, bit_length);
+ if ( nals_needed >= nal_index
+ || (!(avctx->active_thread_type & FF_THREAD_FRAME) && !context_count))
+ h->au_pps_id = -1;
+
if ((err = ff_h264_decode_slice_header(h, sl)))
break;
- if (h->sei_recovery_frame_cnt >= 0 && h->recovery_frame < 0) {
- h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) &
- ((1 << h->sps.log2_max_frame_num) - 1);
+ if (h->sei_recovery_frame_cnt >= 0) {
+ if (h->frame_num != h->sei_recovery_frame_cnt || sl->slice_type_nos != AV_PICTURE_TYPE_I)
+ h->valid_recovery_point = 1;
+
+ if ( h->recovery_frame < 0
+ || av_mod_uintp2(h->recovery_frame - h->frame_num, h->sps.log2_max_frame_num) > h->sei_recovery_frame_cnt) {
+ h->recovery_frame = av_mod_uintp2(h->frame_num + h->sei_recovery_frame_cnt, h->sps.log2_max_frame_num);
+
+ if (!h->valid_recovery_point)
+ h->recovery_frame = h->frame_num;
+ }
}
h->cur_pic_ptr->f->key_frame |=
- (h->nal_unit_type == NAL_IDR_SLICE) ||
- (h->sei_recovery_frame_cnt >= 0);
+ (h->nal_unit_type == NAL_IDR_SLICE);
if (h->nal_unit_type == NAL_IDR_SLICE ||
h->recovery_frame == h->frame_num) {
@@ -1464,31 +1518,41 @@ again:
// "recovered".
if (h->nal_unit_type == NAL_IDR_SLICE)
h->frame_recovered |= FRAME_RECOVERED_IDR;
+ h->frame_recovered |= 3*!!(avctx->flags2 & CODEC_FLAG2_SHOW_ALL);
+ h->frame_recovered |= 3*!!(avctx->flags & CODEC_FLAG_OUTPUT_CORRUPT);
+#if 1
+ h->cur_pic_ptr->recovered |= h->frame_recovered;
+#else
h->cur_pic_ptr->recovered |= !!(h->frame_recovered & FRAME_RECOVERED_IDR);
+#endif
if (h->current_slice == 1) {
if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS))
decode_postinit(h, nal_index >= nals_needed);
if (h->avctx->hwaccel &&
- (ret = h->avctx->hwaccel->start_frame(h->avctx, NULL, 0)) < 0)
- return ret;
+ (ret = h->avctx->hwaccel->start_frame(h->avctx, buf, buf_size)) < 0)
+ goto end;
+ if (CONFIG_H264_VDPAU_DECODER &&
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+ ff_vdpau_h264_picture_start(h);
}
- if (sl->redundant_pic_count == 0 &&
- (avctx->skip_frame < AVDISCARD_NONREF ||
- h->nal_ref_idc) &&
- (avctx->skip_frame < AVDISCARD_BIDIR ||
- sl->slice_type_nos != AV_PICTURE_TYPE_B) &&
- (avctx->skip_frame < AVDISCARD_NONKEY ||
- sl->slice_type_nos == AV_PICTURE_TYPE_I) &&
- avctx->skip_frame < AVDISCARD_ALL) {
+ if (sl->redundant_pic_count == 0) {
if (avctx->hwaccel) {
ret = avctx->hwaccel->decode_slice(avctx,
&buf[buf_index - consumed],
consumed);
if (ret < 0)
- return ret;
+ goto end;
+ } else if (CONFIG_H264_VDPAU_DECODER &&
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) {
+ ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0],
+ start_code,
+ sizeof(start_code));
+ ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0],
+ &buf[buf_index - consumed],
+ consumed);
} else
context_count++;
}
@@ -1497,8 +1561,6 @@ again:
case NAL_DPB:
case NAL_DPC:
avpriv_request_sample(avctx, "data partitioning");
- ret = AVERROR(ENOSYS);
- goto end;
break;
case NAL_SEI:
init_get_bits(&h->gb, ptr, bit_length);
@@ -1508,14 +1570,22 @@ again:
break;
case NAL_SPS:
init_get_bits(&h->gb, ptr, bit_length);
- ret = ff_h264_decode_seq_parameter_set(h);
- if (ret < 0 && h->is_avc && (nalsize != consumed) && nalsize) {
+ if (ff_h264_decode_seq_parameter_set(h, 0) >= 0)
+ break;
+ if (h->is_avc ? nalsize : 1) {
av_log(h->avctx, AV_LOG_DEBUG,
"SPS decoding failure, trying again with the complete NAL\n");
- init_get_bits(&h->gb, buf + buf_index + 1 - consumed,
- 8 * (nalsize - 1));
- ff_h264_decode_seq_parameter_set(h);
+ if (h->is_avc)
+ av_assert0(next_avc - buf_index + consumed == nalsize);
+ if ((next_avc - buf_index + consumed - 1) >= INT_MAX/8)
+ break;
+ init_get_bits(&h->gb, &buf[buf_index + 1 - consumed],
+ 8*(next_avc - buf_index + consumed - 1));
+ if (ff_h264_decode_seq_parameter_set(h, 0) >= 0)
+ break;
}
+ init_get_bits(&h->gb, ptr, bit_length);
+ ff_h264_decode_seq_parameter_set(h, 1);
break;
case NAL_PPS:
@@ -1545,10 +1615,17 @@ again:
context_count = 0;
}
- if (err < 0) {
- av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n");
+ if (err < 0 || err == SLICE_SKIPED) {
+ if (err < 0)
+ av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n");
sl->ref_count[0] = sl->ref_count[1] = sl->list_count = 0;
- } else if (err == 1) {
+ } else if (err == SLICE_SINGLETHREAD) {
+ if (context_count > 1) {
+ ret = ff_h264_execute_decode_slices(h, context_count - 1);
+ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))
+ goto end;
+ context_count = 0;
+ }
/* Slice could not be decoded in parallel mode, restart. Note
* that rbsp_buffer is not transferred, but since we no longer
* run in parallel mode this should not be an issue. */
@@ -1587,26 +1664,54 @@ static int get_consumed_bytes(int pos, int buf_size)
return pos;
}
-static int output_frame(H264Context *h, AVFrame *dst, AVFrame *src)
+static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
{
+ AVFrame *src = srcp->f;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src->format);
int i;
int ret = av_frame_ref(dst, src);
if (ret < 0)
return ret;
- if (!h->sps.crop)
+ av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0);
+
+ if (srcp->sei_recovery_frame_cnt == 0)
+ dst->key_frame = 1;
+ if (!srcp->crop)
return 0;
- for (i = 0; i < 3; i++) {
- int hshift = (i > 0) ? h->chroma_x_shift : 0;
- int vshift = (i > 0) ? h->chroma_y_shift : 0;
- int off = ((h->sps.crop_left >> hshift) << h->pixel_shift) +
- (h->sps.crop_top >> vshift) * dst->linesize[i];
+ for (i = 0; i < desc->nb_components; i++) {
+ int hshift = (i > 0) ? desc->log2_chroma_w : 0;
+ int vshift = (i > 0) ? desc->log2_chroma_h : 0;
+ int off = ((srcp->crop_left >> hshift) << h->pixel_shift) +
+ (srcp->crop_top >> vshift) * dst->linesize[i];
dst->data[i] += off;
}
return 0;
}
+static int is_extra(const uint8_t *buf, int buf_size)
+{
+ int cnt= buf[5]&0x1f;
+ const uint8_t *p= buf+6;
+ while(cnt--){
+ int nalsize= AV_RB16(p) + 2;
+ if(nalsize > buf_size - (p-buf) || p[2]!=0x67)
+ return 0;
+ p += nalsize;
+ }
+ cnt = *(p++);
+ if(!cnt)
+ return 0;
+ while(cnt--){
+ int nalsize= AV_RB16(p) + 2;
+ if(nalsize > buf_size - (p-buf) || p[2]!=0x68)
+ return 0;
+ p += nalsize;
+ }
+ return 1;
+}
+
static int h264_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
@@ -1615,17 +1720,20 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data,
H264Context *h = avctx->priv_data;
AVFrame *pict = data;
int buf_index = 0;
+ H264Picture *out;
+ int i, out_idx;
int ret;
h->flags = avctx->flags;
+ ff_h264_unref_picture(h, &h->last_pic_for_ec);
+
/* end of stream, output what is still in the buffers */
-out:
if (buf_size == 0) {
- H264Picture *out;
- int i, out_idx;
+ out:
h->cur_pic_ptr = NULL;
+ h->first_field = 0;
// FIXME factorize this with the output code below
out = h->delayed_pic[0];
@@ -1644,7 +1752,8 @@ out:
h->delayed_pic[i] = h->delayed_pic[i + 1];
if (out) {
- ret = output_frame(h, pict, out->f);
+ out->reference &= ~DELAYED_PIC_REF;
+ ret = output_frame(h, pict, out);
if (ret < 0)
return ret;
*got_frame = 1;
@@ -1652,19 +1761,30 @@ out:
return buf_index;
}
+ if (h->is_avc && av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, NULL)) {
+ int side_size;
+ uint8_t *side = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
+ if (is_extra(side, side_size))
+ ff_h264_decode_extradata(h, side, side_size);
+ }
+ if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){
+ if (is_extra(buf, buf_size))
+ return ff_h264_decode_extradata(h, buf, buf_size);
+ }
buf_index = decode_nal_units(h, buf, buf_size, 0);
if (buf_index < 0)
return AVERROR_INVALIDDATA;
if (!h->cur_pic_ptr && h->nal_unit_type == NAL_END_SEQUENCE) {
- buf_size = 0;
+ av_assert0(buf_index <= buf_size);
goto out;
}
if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS) && !h->cur_pic_ptr) {
- if (avctx->skip_frame >= AVDISCARD_NONREF)
- return 0;
+ if (avctx->skip_frame >= AVDISCARD_NONREF ||
+ buf_size >= 4 && !memcmp("Q264", buf, 4))
+ return buf_size;
av_log(avctx, AV_LOG_ERROR, "no frame!\n");
return AVERROR_INVALIDDATA;
}
@@ -1676,20 +1796,54 @@ out:
ff_h264_field_end(h, &h->slice_ctx[0], 0);
+ /* Wait for second field. */
*got_frame = 0;
- if (h->next_output_pic && ((avctx->flags & CODEC_FLAG_OUTPUT_CORRUPT) ||
+ if (h->next_output_pic && (
h->next_output_pic->recovered)) {
if (!h->next_output_pic->recovered)
h->next_output_pic->f->flags |= AV_FRAME_FLAG_CORRUPT;
- ret = output_frame(h, pict, h->next_output_pic->f);
+ if (!h->avctx->hwaccel &&
+ (h->next_output_pic->field_poc[0] == INT_MAX ||
+ h->next_output_pic->field_poc[1] == INT_MAX)
+ ) {
+ int p;
+ AVFrame *f = h->next_output_pic->f;
+ int field = h->next_output_pic->field_poc[0] == INT_MAX;
+ uint8_t *dst_data[4];
+ int linesizes[4];
+ const uint8_t *src_data[4];
+
+ av_log(h->avctx, AV_LOG_DEBUG, "Duplicating field %d to fill missing\n", field);
+
+ for (p = 0; p<4; p++) {
+ dst_data[p] = f->data[p] + (field^1)*f->linesize[p];
+ src_data[p] = f->data[p] + field *f->linesize[p];
+ linesizes[p] = 2*f->linesize[p];
+ }
+
+ av_image_copy(dst_data, linesizes, src_data, linesizes,
+ f->format, f->width, f->height>>1);
+ }
+
+ ret = output_frame(h, pict, h->next_output_pic);
if (ret < 0)
return ret;
*got_frame = 1;
+ if (CONFIG_MPEGVIDEO) {
+ ff_print_debug_info2(h->avctx, pict, NULL,
+ h->next_output_pic->mb_type,
+ h->next_output_pic->qscale_table,
+ h->next_output_pic->motion_val,
+ &h->low_delay,
+ h->mb_width, h->mb_height, h->mb_stride, 1);
+ }
}
}
- assert(pict->buf[0] || !*got_frame);
+ av_assert0(pict->buf[0] || !*got_frame);
+
+ ff_h264_unref_picture(h, &h->last_pic_for_ec);
return get_consumed_bytes(buf_index, buf_size);
}
@@ -1704,6 +1858,7 @@ av_cold void ff_h264_free_context(H264Context *h)
ff_h264_unref_picture(h, &h->DPB[i]);
av_frame_free(&h->DPB[i].f);
}
+ memset(h->delayed_pic, 0, sizeof(h->delayed_pic));
h->cur_pic_ptr = NULL;
@@ -1723,10 +1878,13 @@ static av_cold int h264_decode_end(AVCodecContext *avctx)
{
H264Context *h = avctx->priv_data;
+ ff_h264_remove_all_refs(h);
ff_h264_free_context(h);
ff_h264_unref_picture(h, &h->cur_pic);
av_frame_free(&h->cur_pic.f);
+ ff_h264_unref_picture(h, &h->last_pic_for_ec);
+ av_frame_free(&h->last_pic_for_ec.f);
return 0;
}
@@ -1734,12 +1892,14 @@ static av_cold int h264_decode_end(AVCodecContext *avctx)
#define OFFSET(x) offsetof(H264Context, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption h264_options[] = {
- { "enable_er", "Enable error resilience on damaged frames (unsafe)", OFFSET(enable_er), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VD },
+ {"is_avc", "is avc", offsetof(H264Context, is_avc), FF_OPT_TYPE_INT, {.i64 = 0}, 0, 1, 0},
+ {"nal_length_size", "nal_length_size", offsetof(H264Context, nal_length_size), FF_OPT_TYPE_INT, {.i64 = 0}, 0, 4, 0},
+ { "enable_er", "Enable error resilience on damaged frames (unsafe)", OFFSET(enable_er), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VD },
{ NULL },
};
static const AVClass h264_class = {
- .class_name = "h264",
+ .class_name = "H264 Decoder",
.item_name = av_default_item_name,
.option = h264_options,
.version = LIBAVUTIL_VERSION_INT,
@@ -1780,3 +1940,29 @@ AVCodec ff_h264_decoder = {
.profiles = NULL_IF_CONFIG_SMALL(profiles),
.priv_class = &h264_class,
};
+
+#if CONFIG_H264_VDPAU_DECODER
+static const AVClass h264_vdpau_class = {
+ .class_name = "H264 VDPAU Decoder",
+ .item_name = av_default_item_name,
+ .option = h264_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_h264_vdpau_decoder = {
+ .name = "h264_vdpau",
+ .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (VDPAU acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(H264Context),
+ .init = ff_h264_decode_init,
+ .close = h264_decode_end,
+ .decode = h264_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
+ .flush = flush_dpb,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VDPAU_H264,
+ AV_PIX_FMT_NONE},
+ .profiles = NULL_IF_CONFIG_SMALL(profiles),
+ .priv_class = &h264_vdpau_class,
+};
+#endif
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index 12172ac7bc..95db912465 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,8 +43,8 @@
#include "rectangle.h"
#include "videodsp.h"
-#define H264_MAX_PICTURE_COUNT 32
-#define H264_MAX_THREADS 16
+#define H264_MAX_PICTURE_COUNT 36
+#define H264_MAX_THREADS 32
#define MAX_SPS_COUNT 32
#define MAX_PPS_COUNT 256
@@ -53,6 +53,8 @@
#define MAX_DELAYED_PIC_COUNT 16
+#define MAX_MBPAIR_SIZE (256*1024) // a tighter bound could be calculated if someone cares about a few bytes
+
/* Compiling in interlaced support reduces the speed
* of progressive decoding by about 2%. */
#define ALLOW_INTERLACE
@@ -66,17 +68,17 @@
#define MAX_SLICES 32
#ifdef ALLOW_INTERLACE
-#define MB_MBAFF(h) h->mb_mbaff
-#define MB_FIELD(h) h->mb_field_decoding_flag
-#define FRAME_MBAFF(h) h->mb_aff_frame
-#define FIELD_PICTURE(h) (h->picture_structure != PICT_FRAME)
+#define MB_MBAFF(h) (h)->mb_mbaff
+#define MB_FIELD(sl) (sl)->mb_field_decoding_flag
+#define FRAME_MBAFF(h) (h)->mb_aff_frame
+#define FIELD_PICTURE(h) ((h)->picture_structure != PICT_FRAME)
#define LEFT_MBS 2
#define LTOP 0
#define LBOT 1
#define LEFT(i) (i)
#else
#define MB_MBAFF(h) 0
-#define MB_FIELD(h) 0
+#define MB_FIELD(sl) 0
#define FRAME_MBAFF(h) 0
#define FIELD_PICTURE(h) 0
#undef IS_INTERLACED
@@ -89,11 +91,12 @@
#define FIELD_OR_MBAFF_PICTURE(h) (FRAME_MBAFF(h) || FIELD_PICTURE(h))
#ifndef CABAC
-#define CABAC(h) h->pps.cabac
+#define CABAC(h) (h)->pps.cabac
#endif
-#define CHROMA422(h) (h->sps.chroma_format_idc == 2)
-#define CHROMA444(h) (h->sps.chroma_format_idc == 3)
+#define CHROMA(h) ((h)->sps.chroma_format_idc)
+#define CHROMA422(h) ((h)->sps.chroma_format_idc == 2)
+#define CHROMA444(h) ((h)->sps.chroma_format_idc == 3)
#define EXTENDED_SAR 255
@@ -102,7 +105,7 @@
#define IS_REF0(a) ((a) & MB_TYPE_REF0)
#define IS_8x8DCT(a) ((a) & MB_TYPE_8x8DCT)
-#define QP_MAX_NUM (51 + 2 * 6) // The maximum supported qp
+#define QP_MAX_NUM (51 + 6*6) // The maximum supported qp
/* NAL unit types */
enum {
@@ -129,6 +132,7 @@ enum {
typedef enum {
SEI_TYPE_BUFFERING_PERIOD = 0, ///< buffering period (H.264, D.1.1)
SEI_TYPE_PIC_TIMING = 1, ///< picture timing
+ SEI_TYPE_USER_DATA_ITU_T_T35 = 4, ///< user data registered by ITU-T Recommendation T.35
SEI_TYPE_USER_DATA_UNREGISTERED = 5, ///< unregistered user data
SEI_TYPE_RECOVERY_POINT = 6, ///< recovery point (frame # to decoder sync)
SEI_TYPE_FRAME_PACKING = 45, ///< frame packing arrangement
@@ -151,6 +155,19 @@ typedef enum {
} SEI_PicStructType;
/**
+ * frame_packing_arrangement types
+ */
+typedef enum {
+ SEI_FPA_TYPE_CHECKERBOARD = 0,
+ SEI_FPA_TYPE_INTERLEAVE_COLUMN = 1,
+ SEI_FPA_TYPE_INTERLEAVE_ROW = 2,
+ SEI_FPA_TYPE_SIDE_BY_SIDE = 3,
+ SEI_FPA_TYPE_TOP_BOTTOM = 4,
+ SEI_FPA_TYPE_INTERLEAVE_TEMPORAL = 5,
+ SEI_FPA_TYPE_2D = 6,
+} SEI_FpaType;
+
+/**
* Sequence parameter set
*/
typedef struct SPS {
@@ -234,11 +251,23 @@ typedef struct PPS {
int transform_8x8_mode; ///< transform_8x8_mode_flag
uint8_t scaling_matrix4[6][16];
uint8_t scaling_matrix8[6][64];
- uint8_t chroma_qp_table[2][64]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table
+ uint8_t chroma_qp_table[2][QP_MAX_NUM+1]; ///< pre-scaled (with chroma_qp_index_offset) version of qp_table
int chroma_qp_diff;
} PPS;
/**
+ * Frame Packing Arrangement Type
+ */
+typedef struct FPA {
+ int frame_packing_arrangement_id;
+ int frame_packing_arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received
+ SEI_FpaType frame_packing_arrangement_type;
+ int frame_packing_arrangement_repetition_period;
+ int content_interpretation_type;
+ int quincunx_sampling_flag;
+} FPA;
+
+/**
* Memory management control operation opcode.
*/
typedef enum MMCOOpcode {
@@ -287,13 +316,19 @@ typedef struct H264Picture {
int pic_id; /**< pic_num (short -> no wrap version of pic_num,
pic_num & max_pic_num; long -> long_pic_num) */
int long_ref; ///< 1->long term reference 0->short term reference
- int ref_poc[2][2][32]; ///< POCs of the frames used as reference (FIXME need per slice)
+ int ref_poc[2][2][32]; ///< POCs of the frames/fields used as reference (FIXME need per slice)
int ref_count[2][2]; ///< number of entries in ref_poc (FIXME need per slice)
int mbaff; ///< 1 -> MBAFF frame 0-> not MBAFF
int field_picture; ///< whether or not picture was encoded in separate fields
int reference;
int recovered; ///< picture at IDR or recovery point + recovery count
+ int invalid_gap;
+ int sei_recovery_frame_cnt;
+
+ int crop;
+ int crop_left;
+ int crop_top;
} H264Picture;
typedef struct H264Ref {
@@ -374,6 +409,7 @@ typedef struct H264SliceContext {
int mb_xy;
int resync_mb_x;
int resync_mb_y;
+ int mb_index_end;
int mb_skip_run;
int is_complex;
@@ -436,7 +472,7 @@ typedef struct H264SliceContext {
DECLARE_ALIGNED(8, uint16_t, sub_mb_type)[4];
- ///< as a dct coeffecient is int32_t in high depth, we need to reserve twice the space.
+ ///< as a dct coefficient is int32_t in high depth, we need to reserve twice the space.
DECLARE_ALIGNED(16, int16_t, mb)[16 * 48 * 2];
DECLARE_ALIGNED(16, int16_t, mb_luma_dc)[3][16 * 2];
///< as mb is addressed by scantable[i] and scantable is uint8_t we can either
@@ -461,6 +497,7 @@ typedef struct H264SliceContext {
* H264Context
*/
typedef struct H264Context {
+ AVClass *av_class;
AVCodecContext *avctx;
VideoDSPContext vdsp;
H264DSPContext h264dsp;
@@ -471,6 +508,7 @@ typedef struct H264Context {
H264Picture DPB[H264_MAX_PICTURE_COUNT];
H264Picture *cur_pic_ptr;
H264Picture cur_pic;
+ H264Picture last_pic_for_ec;
H264SliceContext *slice_ctx;
int nb_slice_ctx;
@@ -507,9 +545,13 @@ typedef struct H264Context {
uint32_t *mb2br_xy;
int b_stride; // FIXME use s->b4_stride
+
+ unsigned current_sps_id; ///< id of the current SPS
SPS sps; ///< current sps
PPS pps; ///< current pps
+ int au_pps_id; ///< pps_id of current access unit
+
uint32_t dequant4_buffer[6][QP_MAX_NUM + 1][16]; // FIXME should these be moved down?
uint32_t dequant8_buffer[6][QP_MAX_NUM + 1][64];
uint32_t(*dequant4_coeff[6])[16];
@@ -538,12 +580,12 @@ typedef struct H264Context {
uint8_t field_scan[16];
uint8_t field_scan8x8[64];
uint8_t field_scan8x8_cavlc[64];
- const uint8_t *zigzag_scan_q0;
- const uint8_t *zigzag_scan8x8_q0;
- const uint8_t *zigzag_scan8x8_cavlc_q0;
- const uint8_t *field_scan_q0;
- const uint8_t *field_scan8x8_q0;
- const uint8_t *field_scan8x8_cavlc_q0;
+ uint8_t zigzag_scan_q0[16];
+ uint8_t zigzag_scan8x8_q0[64];
+ uint8_t zigzag_scan8x8_cavlc_q0[64];
+ uint8_t field_scan_q0[16];
+ uint8_t field_scan8x8_q0[64];
+ uint8_t field_scan8x8_cavlc_q0[64];
int x264_build;
@@ -619,7 +661,7 @@ typedef struct H264Context {
* @{
*/
/**
- * current slice number, used to initalize slice_num of each thread/context
+ * current slice number, used to initialize slice_num of each thread/context
*/
int current_slice;
@@ -642,6 +684,7 @@ typedef struct H264Context {
enum AVPictureType pict_type;
int last_slice_type;
+ unsigned int last_ref_count[2];
/** @} */
/**
@@ -699,6 +742,13 @@ typedef struct H264Context {
int sei_recovery_frame_cnt;
/**
+ * Are the SEI recovery points looking valid.
+ */
+ int valid_recovery_point;
+
+ FPA sei_fpa;
+
+ /**
* recovery_frame is the frame_num at which the next frame should
* be fully constructed.
*
@@ -719,11 +769,23 @@ typedef struct H264Context {
int frame_recovered; ///< Initial frame has been completely recovered
+ int has_recovery_point;
+
+ int missing_fields;
+
// Timestamp stuff
int sei_buffering_period_present; ///< Buffering period SEI flag
int initial_cpb_removal_delay[32]; ///< Initial timestamps for CPBs
+ int cur_chroma_format_idc;
+ int cur_bit_depth_luma;
+ int16_t slice_row[MAX_SLICES]; ///< to detect when MAX_SLICES is too low
+
+ uint8_t parse_history[6];
+ int parse_history_count;
+ int parse_last_mb;
+
int enable_er;
AVBufferPool *qscale_table_pool;
@@ -736,7 +798,7 @@ typedef struct H264Context {
qpel_mc_func (*qpel_avg)[16];
} H264Context;
-extern const uint8_t ff_h264_chroma_qp[3][QP_MAX_NUM + 1]; ///< One chroma qp table for each supported bit depth (8, 9, 10).
+extern const uint8_t ff_h264_chroma_qp[7][QP_MAX_NUM + 1]; ///< One chroma qp table for each possible bit depth (8-14).
extern const uint16_t ff_h264_mb_sizes[4];
/**
@@ -747,7 +809,7 @@ int ff_h264_decode_sei(H264Context *h);
/**
* Decode SPS
*/
-int ff_h264_decode_seq_parameter_set(H264Context *h);
+int ff_h264_decode_seq_parameter_set(H264Context *h, int ignore_truncation);
/**
* compute profile from sps
@@ -820,7 +882,7 @@ int ff_h264_check_intra_pred_mode(const H264Context *h, H264SliceContext *sl,
int mode, int is_chroma);
void ff_h264_hl_decode_mb(const H264Context *h, H264SliceContext *sl);
-int ff_h264_decode_extradata(H264Context *h);
+int ff_h264_decode_extradata(H264Context *h, const uint8_t *buf, int size);
int ff_h264_decode_init(AVCodecContext *avctx);
void ff_h264_decode_init_vlc(void);
@@ -838,7 +900,7 @@ int ff_h264_decode_mb_cabac(const H264Context *h, H264SliceContext *sl);
void ff_h264_init_cabac_states(const H264Context *h, H264SliceContext *sl);
-void h264_init_dequant_tables(H264Context *h);
+void ff_h264_init_dequant_tables(H264Context *h);
void ff_h264_direct_dist_scale_factor(const H264Context *const h, H264SliceContext *sl);
void ff_h264_direct_ref_list_init(const H264Context *const h, H264SliceContext *sl);
@@ -859,6 +921,12 @@ void ff_h264_filter_mb(const H264Context *h, H264SliceContext *sl, int mb_x, int
*/
void ff_h264_reset_sei(H264Context *h);
+/**
+ * Get stereo_mode string from the h264 frame_packing_arrangement
+ * @param h H.264 context.
+ */
+const char* ff_h264_sei_stereo_mode(H264Context *h);
+
/*
* o-o o-o
* / / /
@@ -909,7 +977,7 @@ static const uint8_t scan8[16 * 3 + 3] = {
0 + 0 * 8, 0 + 5 * 8, 0 + 10 * 8
};
-static av_always_inline uint32_t pack16to32(int a, int b)
+static av_always_inline uint32_t pack16to32(unsigned a, unsigned b)
{
#if HAVE_BIGENDIAN
return (b & 0xFFFF) + (a << 16);
@@ -918,7 +986,7 @@ static av_always_inline uint32_t pack16to32(int a, int b)
#endif
}
-static av_always_inline uint16_t pack8to16(int a, int b)
+static av_always_inline uint16_t pack8to16(unsigned a, unsigned b)
{
#if HAVE_BIGENDIAN
return (b & 0xFF) + (a << 8);
@@ -1065,6 +1133,34 @@ static av_always_inline int get_dct8x8_allowed(const H264Context *h, H264SliceCo
0x0001000100010001ULL));
}
+static inline int find_start_code(const uint8_t *buf, int buf_size,
+ int buf_index, int next_avc)
+{
+ uint32_t state = -1;
+
+ buf_index = avpriv_find_start_code(buf + buf_index, buf + next_avc + 1, &state) - buf - 1;
+
+ return FFMIN(buf_index, buf_size);
+}
+
+static inline int get_avc_nalsize(H264Context *h, const uint8_t *buf,
+ int buf_size, int *buf_index)
+{
+ int i, nalsize = 0;
+
+ if (*buf_index >= buf_size - h->nal_length_size)
+ return -1;
+
+ for (i = 0; i < h->nal_length_size; i++)
+ nalsize = ((unsigned)nalsize << 8) | buf[(*buf_index)++];
+ if (nalsize <= 0 || nalsize > buf_size - *buf_index) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "AVC: nal size %d\n", nalsize);
+ return -1;
+ }
+ return nalsize;
+}
+
int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup);
int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src);
@@ -1078,6 +1174,9 @@ int ff_pred_weight_table(H264Context *h, H264SliceContext *sl);
int ff_set_ref_count(H264Context *h, H264SliceContext *sl);
int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl);
+#define SLICE_SINGLETHREAD 1
+#define SLICE_SKIPED 2
+
int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count);
int ff_h264_update_thread_context(AVCodecContext *dst,
const AVCodecContext *src);
@@ -1086,4 +1185,6 @@ void ff_h264_flush_change(H264Context *h);
void ff_h264_free_tables(H264Context *h);
+void ff_h264_set_erpic(ERPicture *dst, H264Picture *src);
+
#endif /* AVCODEC_H264_H */
diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c
index f4e451d79b..c1c8b80855 100644
--- a/libavcodec/h264_cabac.c
+++ b/libavcodec/h264_cabac.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... cabac decoding
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,9 +26,11 @@
*/
#define CABAC(h) 1
+#define UNCHECKED_BITSTREAM_READER 1
#define INT_BIT (CHAR_BIT * sizeof(int))
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/timer.h"
#include "config.h"
#include "cabac.h"
@@ -45,8 +47,6 @@
#include "x86/h264_i386.h"
#endif
-#include <assert.h>
-
/* Cabac pre state table */
static const int8_t cabac_context_init_I[1024][2] =
@@ -1284,7 +1284,7 @@ void ff_h264_init_cabac_states(const H264Context *h, H264SliceContext *sl)
static int decode_cabac_field_decoding_flag(const H264Context *h, H264SliceContext *sl)
{
- const long mbb_xy = sl->mb_xy - 2L*h->mb_stride;
+ const int mbb_xy = sl->mb_xy - 2*h->mb_stride;
unsigned long ctx = 0;
@@ -1501,7 +1501,7 @@ static int decode_cabac_mb_mvd(H264SliceContext *sl, int ctxbase, int amvd, int
int mvd;
if(!get_cabac(&sl->cabac, &sl->cabac_state[ctxbase+((amvd-3)>>(INT_BIT-1))+((amvd-33)>>(INT_BIT-1))+2])){
-// if(!get_cabac(&h->cabac, &h->cabac_state[ctxbase+(amvd>2)+(amvd>32)])){
+// if(!get_cabac(&sl->cabac, &sl->cabac_state[ctxbase+(amvd>2)+(amvd>32)])){
*mvda= 0;
return 0;
}
@@ -1640,7 +1640,9 @@ decode_cabac_residual_internal(const H264Context *h, H264SliceContext *sl,
cc.range = sl->cabac.range;
cc.low = sl->cabac.low;
cc.bytestream= sl->cabac.bytestream;
+#if !UNCHECKED_BITSTREAM_READER || ARCH_AARCH64
cc.bytestream_end = sl->cabac.bytestream_end;
+#endif
#else
#define CC &sl->cabac
#endif
@@ -1689,7 +1691,7 @@ decode_cabac_residual_internal(const H264Context *h, H264SliceContext *sl,
}
#endif
}
- assert(coeff_count > 0);
+ av_assert2(coeff_count > 0);
if( is_dc ) {
if( cat == 3 )
@@ -1701,7 +1703,7 @@ decode_cabac_residual_internal(const H264Context *h, H264SliceContext *sl,
if( max_coeff == 64 )
fill_rectangle(&sl->non_zero_count_cache[scan8[n]], 2, 2, 8, coeff_count, 1);
else {
- assert( cat == 1 || cat == 2 || cat == 4 || cat == 7 || cat == 8 || cat == 11 || cat == 12 );
+ av_assert2( cat == 1 || cat == 2 || cat == 4 || cat == 7 || cat == 8 || cat == 11 || cat == 12 );
sl->non_zero_count_cache[scan8[n]] = coeff_count;
}
}
@@ -1955,7 +1957,7 @@ int ff_h264_decode_mb_cabac(const H264Context *h, H264SliceContext *sl)
if (sl->slice_type_nos == AV_PICTURE_TYPE_B) {
int ctx = 0;
- assert(sl->slice_type_nos == AV_PICTURE_TYPE_B);
+ av_assert2(sl->slice_type_nos == AV_PICTURE_TYPE_B);
if (!IS_DIRECT(sl->left_type[LTOP] - 1))
ctx++;
@@ -2008,7 +2010,7 @@ int ff_h264_decode_mb_cabac(const H264Context *h, H264SliceContext *sl)
mb_type = decode_cabac_intra_mb_type(sl, 3, 1);
if (sl->slice_type == AV_PICTURE_TYPE_SI && mb_type)
mb_type--;
- assert(sl->slice_type_nos == AV_PICTURE_TYPE_I);
+ av_assert2(sl->slice_type_nos == AV_PICTURE_TYPE_I);
decode_intra_mb:
partition_count = 0;
cbp= i_mb_type_info[mb_type].cbp;
@@ -2071,8 +2073,8 @@ decode_intra_mb:
int pred = pred_intra_mode(h, sl, i);
sl->intra4x4_pred_mode_cache[scan8[i]] = decode_cabac_mb_intra4x4_pred_mode(sl, pred);
- ff_dlog(h->avctx, "i4x4 pred=%d mode=%d\n", pred,
- h->intra4x4_pred_mode_cache[scan8[i]]);
+ ff_tlog(h->avctx, "i4x4 pred=%d mode=%d\n", pred,
+ sl->intra4x4_pred_mode_cache[scan8[i]]);
}
}
write_back_intra_pred_mode(h, sl);
@@ -2122,10 +2124,10 @@ decode_intra_mb:
for( i = 0; i < 4; i++ ) {
if(IS_DIRECT(sl->sub_mb_type[i])) continue;
if(IS_DIR(sl->sub_mb_type[i], 0, list)){
- int rc = sl->ref_count[list] << MB_MBAFF(sl);
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc > 1) {
ref[list][i] = decode_cabac_mb_ref(sl, list, 4 * i);
- if (ref[list][i] >= (unsigned) rc) {
+ if (ref[list][i] >= rc) {
av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref[list][i], rc);
return -1;
}
@@ -2208,10 +2210,11 @@ decode_intra_mb:
if(IS_16X16(mb_type)){
for (list = 0; list < sl->list_count; list++) {
if(IS_DIR(mb_type, 0, list)){
- int ref, rc = sl->ref_count[list] << MB_MBAFF(sl);
+ int ref;
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc > 1) {
ref= decode_cabac_mb_ref(sl, list, 0);
- if (ref >= (unsigned) rc) {
+ if (ref >= rc) {
av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, rc);
return -1;
}
@@ -2236,10 +2239,11 @@ decode_intra_mb:
for (list = 0; list < sl->list_count; list++) {
for(i=0; i<2; i++){
if(IS_DIR(mb_type, i, list)){
- int ref, rc = sl->ref_count[list] << MB_MBAFF(sl);
+ int ref;
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc > 1) {
ref= decode_cabac_mb_ref(sl, list, 8 * i);
- if (ref >= (unsigned) rc) {
+ if (ref >= rc) {
av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, rc);
return -1;
}
@@ -2267,14 +2271,15 @@ decode_intra_mb:
}
}
}else{
- assert(IS_8X16(mb_type));
+ av_assert2(IS_8X16(mb_type));
for (list = 0; list < sl->list_count; list++) {
for(i=0; i<2; i++){
if(IS_DIR(mb_type, i, list)){ //FIXME optimize
- int ref, rc = sl->ref_count[list] << MB_MBAFF(sl);
+ int ref;
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc > 1) {
ref = decode_cabac_mb_ref(sl, list, 4 * i);
- if (ref >= (unsigned) rc) {
+ if (ref >= rc) {
av_log(h->avctx, AV_LOG_ERROR, "Reference %d >= %d\n", ref, rc);
return -1;
}
@@ -2313,6 +2318,11 @@ decode_intra_mb:
cbp = decode_cabac_mb_cbp_luma(sl);
if(decode_chroma)
cbp |= decode_cabac_mb_cbp_chroma(sl) << 4;
+ } else {
+ if (!decode_chroma && cbp>15) {
+ av_log(h->avctx, AV_LOG_ERROR, "gray chroma\n");
+ return AVERROR_INVALIDDATA;
+ }
}
h->cbp_table[mb_xy] = sl->cbp = cbp;
diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c
index 7445788e56..b0251f405c 100644
--- a/libavcodec/h264_cavlc.c
+++ b/libavcodec/h264_cavlc.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... cavlc bitstream decoding
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
*/
#define CABAC(h) 0
+#define UNCHECKED_BITSTREAM_READER 1
#include "internal.h"
#include "avcodec.h"
@@ -34,8 +35,8 @@
#include "h264_mvpred.h"
#include "golomb.h"
#include "mpegutils.h"
+#include "libavutil/avassert.h"
-#include <assert.h>
static const uint8_t golomb_to_inter_cbp_gray[16]={
0, 1, 2, 4, 8, 3, 5,10,12,15, 7,11,13,14, 6, 9,
@@ -360,7 +361,7 @@ av_cold void ff_h264_decode_init_vlc(void){
* the packed static coeff_token_vlc table sizes
* were initialized correctly.
*/
- assert(offset == FF_ARRAY_ELEMS(coeff_token_vlc_tables));
+ av_assert0(offset == FF_ARRAY_ELEMS(coeff_token_vlc_tables));
for(i=0; i<3; i++){
chroma_dc_total_zeros_vlc[i].table = chroma_dc_total_zeros_vlc_tables[i];
@@ -483,7 +484,7 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
trailing_ones= coeff_token&3;
ff_tlog(h->avctx, "trailing:%d, total:%d\n", trailing_ones, total_coeff);
- assert(total_coeff<=16);
+ av_assert2(total_coeff<=16);
i = show_bits(gb, 3);
skip_bits(gb, trailing_ones);
@@ -515,7 +516,7 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
else
level_code= prefix + get_bits(gb, 4); //part
}else{
- level_code= 30 + get_bits(gb, prefix-3); //part
+ level_code= 30;
if(prefix>=16){
if(prefix > 25+3){
av_log(h->avctx, AV_LOG_ERROR, "Invalid level prefix\n");
@@ -523,6 +524,7 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
}
level_code += (1<<(prefix-3))-4096;
}
+ level_code += get_bits(gb, prefix-3); //part
}
if(trailing_ones < 3) level_code += 2;
@@ -552,9 +554,15 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
if(prefix<15){
level_code = (prefix<<suffix_length) + get_bits(gb, suffix_length);
}else{
- level_code = (15<<suffix_length) + get_bits(gb, prefix-3);
- if(prefix>=16)
+ level_code = 15<<suffix_length;
+ if (prefix>=16) {
+ if(prefix > 25+3){
+ av_log(h->avctx, AV_LOG_ERROR, "Invalid level prefix\n");
+ return AVERROR_INVALIDDATA;
+ }
level_code += (1<<(prefix-3))-4096;
+ }
+ level_code += get_bits(gb, prefix-3);
}
mask= -(level_code&1);
level_code= (((2+level_code)>>1) ^ mask) - mask;
@@ -569,13 +577,13 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
else{
if (max_coeff <= 8) {
if (max_coeff == 4)
- zeros_left = get_vlc2(gb, chroma_dc_total_zeros_vlc[total_coeff - 1].table,
+ zeros_left = get_vlc2(gb, (chroma_dc_total_zeros_vlc-1)[total_coeff].table,
CHROMA_DC_TOTAL_ZEROS_VLC_BITS, 1);
else
- zeros_left = get_vlc2(gb, chroma422_dc_total_zeros_vlc[total_coeff - 1].table,
+ zeros_left = get_vlc2(gb, (chroma422_dc_total_zeros_vlc-1)[total_coeff].table,
CHROMA422_DC_TOTAL_ZEROS_VLC_BITS, 1);
} else {
- zeros_left= get_vlc2(gb, total_zeros_vlc[total_coeff - 1].table, TOTAL_ZEROS_VLC_BITS, 1);
+ zeros_left= get_vlc2(gb, (total_zeros_vlc-1)[ total_coeff ].table, TOTAL_ZEROS_VLC_BITS, 1);
}
}
@@ -585,7 +593,7 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
((type*)block)[*scantable] = level[0]; \
for(i=1;i<total_coeff && zeros_left > 0;i++) { \
if(zeros_left < 7) \
- run_before= get_vlc2(gb, run_vlc[zeros_left - 1].table, RUN_VLC_BITS, 1); \
+ run_before= get_vlc2(gb, (run_vlc-1)[zeros_left].table, RUN_VLC_BITS, 1); \
else \
run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \
zeros_left -= run_before; \
@@ -600,7 +608,7 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
((type*)block)[*scantable] = ((int)(level[0] * qmul[*scantable] + 32))>>6; \
for(i=1;i<total_coeff && zeros_left > 0;i++) { \
if(zeros_left < 7) \
- run_before= get_vlc2(gb, run_vlc[zeros_left - 1].table, RUN_VLC_BITS, 1); \
+ run_before= get_vlc2(gb, (run_vlc-1)[zeros_left].table, RUN_VLC_BITS, 1); \
else \
run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \
zeros_left -= run_before; \
@@ -613,18 +621,17 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
} \
}
- if (zeros_left < 0) {
- av_log(h->avctx, AV_LOG_ERROR,
- "negative number of zero coeffs at %d %d\n", sl->mb_x, sl->mb_y);
- return AVERROR_INVALIDDATA;
- }
-
if (h->pixel_shift) {
STORE_BLOCK(int32_t)
} else {
STORE_BLOCK(int16_t)
}
+ if(zeros_left<0){
+ av_log(h->avctx, AV_LOG_ERROR, "negative number of zero coeffs at %d %d\n", sl->mb_x, sl->mb_y);
+ return -1;
+ }
+
return 0;
}
@@ -645,7 +652,7 @@ int decode_luma_residual(const H264Context *h, H264SliceContext *sl,
return -1; //FIXME continue if partitioned and other return -1 too
}
- assert((cbp&15) == 0 || (cbp&15) == 15);
+ av_assert2((cbp&15) == 0 || (cbp&15) == 15);
if(cbp&15){
for(i8x8=0; i8x8<4; i8x8++){
@@ -715,7 +722,7 @@ int ff_h264_decode_mb_cavlc(const H264Context *h, H264SliceContext *sl)
down the code */
if (sl->slice_type_nos != AV_PICTURE_TYPE_I) {
if (sl->mb_skip_run == -1)
- sl->mb_skip_run = get_ue_golomb(&sl->gb);
+ sl->mb_skip_run = get_ue_golomb_long(&sl->gb);
if (sl->mb_skip_run--) {
if (FRAME_MBAFF(h) && (sl->mb_y & 1) == 0) {
@@ -751,7 +758,7 @@ int ff_h264_decode_mb_cavlc(const H264Context *h, H264SliceContext *sl)
goto decode_intra_mb;
}
}else{
- assert(sl->slice_type_nos == AV_PICTURE_TYPE_I);
+ av_assert2(sl->slice_type_nos == AV_PICTURE_TYPE_I);
if (sl->slice_type == AV_PICTURE_TYPE_SI && mb_type)
mb_type--;
decode_intra_mb:
@@ -857,7 +864,7 @@ decode_intra_mb:
sl->ref_cache[1][scan8[12]] = PART_NOT_AVAILABLE;
}
}else{
- assert(sl->slice_type_nos == AV_PICTURE_TYPE_P); //FIXME SP correct ?
+ av_assert2(sl->slice_type_nos == AV_PICTURE_TYPE_P); //FIXME SP correct ?
for(i=0; i<4; i++){
sl->sub_mb_type[i]= get_ue_golomb_31(&sl->gb);
if(sl->sub_mb_type[i] >=4){
@@ -950,7 +957,7 @@ decode_intra_mb:
for (list = 0; list < sl->list_count; list++) {
unsigned int val;
if(IS_DIR(mb_type, 0, list)){
- int rc = sl->ref_count[list] << MB_MBAFF(sl);
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc == 1) {
val= 0;
} else if (rc == 2) {
@@ -981,7 +988,7 @@ decode_intra_mb:
for(i=0; i<2; i++){
unsigned int val;
if(IS_DIR(mb_type, i, list)){
- int rc = sl->ref_count[list] << MB_MBAFF(sl);
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc == 1) {
val= 0;
} else if (rc == 2) {
@@ -1014,12 +1021,12 @@ decode_intra_mb:
}
}
}else{
- assert(IS_8X16(mb_type));
+ av_assert2(IS_8X16(mb_type));
for (list = 0; list < sl->list_count; list++) {
for(i=0; i<2; i++){
unsigned int val;
if(IS_DIR(mb_type, i, list)){ //FIXME optimize
- int rc = sl->ref_count[list] << MB_MBAFF(sl);
+ unsigned rc = sl->ref_count[list] << MB_MBAFF(sl);
if (rc == 1) {
val= 0;
} else if (rc == 2) {
@@ -1075,6 +1082,11 @@ decode_intra_mb:
if(IS_INTRA4x4(mb_type)) cbp= golomb_to_intra4x4_cbp_gray[cbp];
else cbp= golomb_to_inter_cbp_gray[cbp];
}
+ } else {
+ if (!decode_chroma && cbp>15) {
+ av_log(h->avctx, AV_LOG_ERROR, "gray chroma\n");
+ return AVERROR_INVALIDDATA;
+ }
}
if(dct8x8_allowed && (cbp&15) && !IS_INTRA(mb_type)){
@@ -1127,12 +1139,15 @@ decode_intra_mb:
if (decode_luma_residual(h, sl, gb, scan, scan8x8, pixel_shift, mb_type, cbp, 2) < 0 ) {
return -1;
}
- } else if (CHROMA422(h)) {
+ } else {
+ const int num_c8x8 = h->sps.chroma_format_idc;
+
if(cbp&0x30){
for(chroma_idx=0; chroma_idx<2; chroma_idx++)
if (decode_residual(h, sl, gb, sl->mb + ((256 + 16*16*chroma_idx) << pixel_shift),
- CHROMA_DC_BLOCK_INDEX+chroma_idx, chroma422_dc_scan,
- NULL, 8) < 0) {
+ CHROMA_DC_BLOCK_INDEX+chroma_idx,
+ CHROMA422(h) ? chroma422_dc_scan : chroma_dc_scan,
+ NULL, 4*num_c8x8) < 0) {
return -1;
}
}
@@ -1141,7 +1156,7 @@ decode_intra_mb:
for(chroma_idx=0; chroma_idx<2; chroma_idx++){
const uint32_t *qmul = h->dequant4_coeff[chroma_idx+1+(IS_INTRA( mb_type ) ? 0:3)][sl->chroma_qp[chroma_idx]];
int16_t *mb = sl->mb + (16*(16 + 16*chroma_idx) << pixel_shift);
- for (i8x8 = 0; i8x8 < 2; i8x8++) {
+ for (i8x8 = 0; i8x8<num_c8x8; i8x8++) {
for (i4x4 = 0; i4x4 < 4; i4x4++) {
const int index = 16 + 16*chroma_idx + 8*i8x8 + i4x4;
if (decode_residual(h, sl, gb, mb, index, scan + 1, qmul, 15) < 0)
@@ -1154,28 +1169,6 @@ decode_intra_mb:
fill_rectangle(&sl->non_zero_count_cache[scan8[16]], 4, 4, 8, 0, 1);
fill_rectangle(&sl->non_zero_count_cache[scan8[32]], 4, 4, 8, 0, 1);
}
- } else /* yuv420 */ {
- if(cbp&0x30){
- for(chroma_idx=0; chroma_idx<2; chroma_idx++)
- if( decode_residual(h, sl, gb, sl->mb + ((256 + 16*16*chroma_idx) << pixel_shift), CHROMA_DC_BLOCK_INDEX+chroma_idx, chroma_dc_scan, NULL, 4) < 0){
- return -1;
- }
- }
-
- if(cbp&0x20){
- for(chroma_idx=0; chroma_idx<2; chroma_idx++){
- const uint32_t *qmul = h->dequant4_coeff[chroma_idx+1+(IS_INTRA( mb_type ) ? 0:3)][sl->chroma_qp[chroma_idx]];
- for(i4x4=0; i4x4<4; i4x4++){
- const int index= 16 + 16*chroma_idx + i4x4;
- if( decode_residual(h, sl, gb, sl->mb + (16*index << pixel_shift), index, scan + 1, qmul, 15) < 0){
- return -1;
- }
- }
- }
- }else{
- fill_rectangle(&sl->non_zero_count_cache[scan8[16]], 4, 4, 8, 0, 1);
- fill_rectangle(&sl->non_zero_count_cache[scan8[32]], 4, 4, 8, 0, 1);
- }
}
}else{
fill_rectangle(&sl->non_zero_count_cache[scan8[ 0]], 4, 4, 8, 0, 1);
diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c
index a7966e15e9..5756a7ba66 100644
--- a/libavcodec/h264_direct.c
+++ b/libavcodec/h264_direct.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... direct mb/block decoding
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -159,11 +159,11 @@ void ff_h264_direct_ref_list_init(const H264Context *const h, H264SliceContext *
}
}
-static void await_reference_mb_row(const H264Context *const h, H264Picture *ref,
+static void await_reference_mb_row(const H264Context *const h, H264Ref *ref,
int mb_y)
{
int ref_field = ref->reference - 1;
- int ref_field_picture = ref->field_picture;
+ int ref_field_picture = ref->parent->field_picture;
int ref_height = 16 * h->mb_height >> ref_field_picture;
if (!HAVE_THREADS || !(h->avctx->active_thread_type & FF_THREAD_FRAME))
@@ -172,7 +172,7 @@ static void await_reference_mb_row(const H264Context *const h, H264Picture *ref,
/* FIXME: It can be safe to access mb stuff
* even if pixels aren't deblocked yet. */
- ff_thread_await_progress(&ref->tf,
+ ff_thread_await_progress(&ref->parent->tf,
FFMIN(16 * mb_y >> ref_field_picture,
ref_height - 1),
ref_field_picture && ref_field);
@@ -196,7 +196,7 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont
assert(sl->ref_list[1][0].reference & 3);
- await_reference_mb_row(h, sl->ref_list[1][0].parent,
+ await_reference_mb_row(h, &sl->ref_list[1][0],
sl->mb_y + !!IS_INTERLACED(*mb_type));
#define MB_TYPE_16x16_OR_INTRA (MB_TYPE_16x16 | MB_TYPE_INTRA4x4 | \
@@ -237,6 +237,7 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont
else
mv[list] = AV_RN32A(C);
}
+ av_assert2(ref[list] < (sl->ref_count[list] << !!FRAME_MBAFF(h)));
} else {
int mask = ~(MB_TYPE_L0 << (2 * list));
mv[list] = 0;
@@ -320,10 +321,10 @@ single_col:
}
}
- await_reference_mb_row(h, sl->ref_list[1][0].parent, mb_y);
+ await_reference_mb_row(h, &sl->ref_list[1][0], mb_y);
- l1mv0 = &sl->ref_list[1][0].parent->motion_val[0][h->mb2b_xy[mb_xy]];
- l1mv1 = &sl->ref_list[1][0].parent->motion_val[1][h->mb2b_xy[mb_xy]];
+ l1mv0 = (void*)&sl->ref_list[1][0].parent->motion_val[0][h->mb2b_xy[mb_xy]];
+ l1mv1 = (void*)&sl->ref_list[1][0].parent->motion_val[1][h->mb2b_xy[mb_xy]];
l1ref0 = &sl->ref_list[1][0].parent->ref_index[0][4 * mb_xy];
l1ref1 = &sl->ref_list[1][0].parent->ref_index[1][4 * mb_xy];
if (!b8_stride) {
@@ -479,7 +480,7 @@ static void pred_temp_direct_motion(const H264Context *const h, H264SliceContext
assert(sl->ref_list[1][0].reference & 3);
- await_reference_mb_row(h, sl->ref_list[1][0].parent,
+ await_reference_mb_row(h, &sl->ref_list[1][0],
sl->mb_y + !!IS_INTERLACED(*mb_type));
if (IS_INTERLACED(sl->ref_list[1][0].parent->mb_type[mb_xy])) { // AFL/AFR/FR/FL -> AFL/FL
@@ -544,10 +545,10 @@ single_col:
}
}
- await_reference_mb_row(h, sl->ref_list[1][0].parent, mb_y);
+ await_reference_mb_row(h, &sl->ref_list[1][0], mb_y);
- l1mv0 = &sl->ref_list[1][0].parent->motion_val[0][h->mb2b_xy[mb_xy]];
- l1mv1 = &sl->ref_list[1][0].parent->motion_val[1][h->mb2b_xy[mb_xy]];
+ l1mv0 = (void*)&sl->ref_list[1][0].parent->motion_val[0][h->mb2b_xy[mb_xy]];
+ l1mv1 = (void*)&sl->ref_list[1][0].parent->motion_val[1][h->mb2b_xy[mb_xy]];
l1ref0 = &sl->ref_list[1][0].parent->ref_index[0][4 * mb_xy];
l1ref1 = &sl->ref_list[1][0].parent->ref_index[1][4 * mb_xy];
if (!b8_stride) {
diff --git a/libavcodec/h264_loopfilter.c b/libavcodec/h264_loopfilter.c
index fa40ba4ba2..cb91134185 100644
--- a/libavcodec/h264_loopfilter.c
+++ b/libavcodec/h264_loopfilter.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... loop filter
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,8 +34,6 @@
#include "mpegutils.h"
#include "rectangle.h"
-#include <assert.h>
-
/* Deblocking filter (p153) */
static const uint8_t alpha_table[52*3] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -244,7 +242,7 @@ static av_always_inline void h264_filter_mb_fast_internal(const H264Context *h,
unsigned int uvlinesize,
int pixel_shift)
{
- int chroma = !(CONFIG_GRAY && (h->flags&CODEC_FLAG_GRAY));
+ int chroma = CHROMA(h) && !(CONFIG_GRAY && (h->flags&CODEC_FLAG_GRAY));
int chroma444 = CHROMA444(h);
int chroma422 = CHROMA422(h);
@@ -358,7 +356,7 @@ static av_always_inline void h264_filter_mb_fast_internal(const H264Context *h,
}
return;
} else {
- LOCAL_ALIGNED_8(int16_t, bS, [2], [4][4]);
+ LOCAL_ALIGNED(8, int16_t, bS, [2], [4][4]);
int edges;
if( IS_8x8DCT(mb_type) && (sl->cbp&7) == 7 && !chroma444 ) {
edges = 4;
@@ -421,7 +419,7 @@ void ff_h264_filter_mb_fast(const H264Context *h, H264SliceContext *sl,
uint8_t *img_cb, uint8_t *img_cr,
unsigned int linesize, unsigned int uvlinesize)
{
- assert(!FRAME_MBAFF(h));
+ av_assert2(!FRAME_MBAFF(h));
if(!h->h264dsp.h264_loop_filter_strength || h->pps.chroma_qp_diff) {
ff_h264_filter_mb(h, sl, mb_x, mb_y, img_y, img_cb, img_cr, linesize, uvlinesize);
return;
@@ -507,7 +505,7 @@ static av_always_inline void filter_mb_dir(const H264Context *h, H264SliceContex
int j;
for(j=0; j<2; j++, mbn_xy += h->mb_stride){
- DECLARE_ALIGNED(8, int16_t, bS)[4];
+ LOCAL_ALIGNED(8, int16_t, bS, [4]);
int qp;
if (IS_INTRA(mb_type | h->cur_pic.mb_type[mbn_xy])) {
AV_WN64A(bS, 0x0003000300030003ULL);
@@ -544,7 +542,7 @@ static av_always_inline void filter_mb_dir(const H264Context *h, H264SliceContex
}
}
}else{
- DECLARE_ALIGNED(8, int16_t, bS)[4];
+ LOCAL_ALIGNED(8, int16_t, bS, [4]);
int qp;
if( IS_INTRA(mb_type|mbm_type)) {
@@ -593,7 +591,9 @@ static av_always_inline void filter_mb_dir(const H264Context *h, H264SliceContex
// value in IPCM macroblocks.
if(bS[0]+bS[1]+bS[2]+bS[3]){
qp = (h->cur_pic.qscale_table[mb_xy] + h->cur_pic.qscale_table[mbm_xy] + 1) >> 1;
+ //ff_tlog(h->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d, QPc:%d, QPcn:%d\n", mb_x, mb_y, dir, edge, qp, h->chroma_qp[0], h->cur_pic.qscale_table[mbn_xy]);
ff_tlog(h->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d ls:%d uvls:%d", mb_x, mb_y, dir, edge, qp, linesize, uvlinesize);
+ //{ int i; for (i = 0; i < 4; i++) ff_tlog(h->avctx, " bS[%d]:%d", i, bS[i]); ff_tlog(h->avctx, "\n"); }
chroma_qp_avg[0] = (sl->chroma_qp[0] + get_chroma_qp(h, 0, h->cur_pic.qscale_table[mbm_xy]) + 1) >> 1;
chroma_qp_avg[1] = (sl->chroma_qp[1] + get_chroma_qp(h, 1, h->cur_pic.qscale_table[mbm_xy]) + 1) >> 1;
if( dir == 0 ) {
@@ -625,7 +625,7 @@ static av_always_inline void filter_mb_dir(const H264Context *h, H264SliceContex
/* Calculate bS */
for( edge = 1; edge < edges; edge++ ) {
- DECLARE_ALIGNED(8, int16_t, bS)[4];
+ LOCAL_ALIGNED(8, int16_t, bS, [4]);
int qp;
const int deblock_edge = !IS_8x8DCT(mb_type & (edge<<24)); // (edge&1) && IS_8x8DCT(mb_type)
@@ -676,7 +676,9 @@ static av_always_inline void filter_mb_dir(const H264Context *h, H264SliceContex
// Do not use s->qscale as luma quantizer because it has not the same
// value in IPCM macroblocks.
qp = h->cur_pic.qscale_table[mb_xy];
+ //ff_tlog(h->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d, QPc:%d, QPcn:%d\n", mb_x, mb_y, dir, edge, qp, h->chroma_qp[0], h->cur_pic.qscale_table[mbn_xy]);
ff_tlog(h->avctx, "filter mb:%d/%d dir:%d edge:%d, QPy:%d ls:%d uvls:%d", mb_x, mb_y, dir, edge, qp, linesize, uvlinesize);
+ //{ int i; for (i = 0; i < 4; i++) ff_tlog(h->avctx, " bS[%d]:%d", i, bS[i]); ff_tlog(h->avctx, "\n"); }
if( dir == 0 ) {
filter_mb_edgev( &img_y[4*edge << h->pixel_shift], linesize, bS, qp, a, b, h, 0 );
if (chroma) {
@@ -721,7 +723,7 @@ void ff_h264_filter_mb(const H264Context *h, H264SliceContext *sl,
const int mb_type = h->cur_pic.mb_type[mb_xy];
const int mvy_limit = IS_INTERLACED(mb_type) ? 2 : 4;
int first_vertical_edge_done = 0;
- int chroma = !(CONFIG_GRAY && (h->flags&CODEC_FLAG_GRAY));
+ int chroma = CHROMA(h) && !(CONFIG_GRAY && (h->flags&CODEC_FLAG_GRAY));
int qp_bd_offset = 6 * (h->sps.bit_depth_luma - 8);
int a = 52 + sl->slice_alpha_c0_offset - qp_bd_offset;
int b = 52 + sl->slice_beta_offset - qp_bd_offset;
@@ -734,7 +736,7 @@ void ff_h264_filter_mb(const H264Context *h, H264SliceContext *sl,
/* First vertical edge is different in MBAFF frames
* There are 8 different bS to compute and 2 different Qp
*/
- DECLARE_ALIGNED(8, int16_t, bS)[8];
+ LOCAL_ALIGNED(8, int16_t, bS, [8]);
int qp[2];
int bqp[2];
int rqp[2];
diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c
index fea733a9c3..634d814493 100644
--- a/libavcodec/h264_mb.c
+++ b/libavcodec/h264_mb.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,17 +40,17 @@ static inline int get_lowest_part_list_y(H264SliceContext *sl,
int n, int height, int y_offset, int list)
{
int raw_my = sl->mv_cache[list][scan8[n]][1];
- int filter_height_up = (raw_my & 3) ? 2 : 0;
int filter_height_down = (raw_my & 3) ? 3 : 0;
int full_my = (raw_my >> 2) + y_offset;
- int top = full_my - filter_height_up;
int bottom = full_my + filter_height_down + height;
- return FFMAX(abs(top), bottom);
+ av_assert2(height >= 0);
+
+ return FFMAX(0, bottom);
}
static inline void get_lowest_part_y(const H264Context *h, H264SliceContext *sl,
- int refs[2][48], int n,
+ int16_t refs[2][48], int n,
int height, int y_offset, int list0,
int list1, int *nrefs)
{
@@ -97,7 +97,7 @@ static void await_references(const H264Context *h, H264SliceContext *sl)
{
const int mb_xy = sl->mb_xy;
const int mb_type = h->cur_pic.mb_type[mb_xy];
- int refs[2][48];
+ int16_t refs[2][48];
int nrefs[2] = { 0 };
int ref, list;
@@ -119,7 +119,7 @@ static void await_references(const H264Context *h, H264SliceContext *sl)
} else {
int i;
- assert(IS_8X8(mb_type));
+ av_assert2(IS_8X8(mb_type));
for (i = 0; i < 4; i++) {
const int sub_mb_type = sl->sub_mb_type[i];
@@ -151,7 +151,7 @@ static void await_references(const H264Context *h, H264SliceContext *sl)
nrefs);
} else {
int j;
- assert(IS_SUB_4X4(sub_mb_type));
+ av_assert2(IS_SUB_4X4(sub_mb_type));
for (j = 0; j < 4; j++) {
int sub_y_offset = y_offset + 2 * (j & 2);
get_lowest_part_y(h, sl, refs, n + j, 4, sub_y_offset,
@@ -176,6 +176,7 @@ static void await_references(const H264Context *h, H264SliceContext *sl)
nrefs[list]--;
if (!FIELD_PICTURE(h) && ref_field_picture) { // frame referencing two fields
+ av_assert2((ref_pic->parent->reference & 3) == 3);
ff_thread_await_progress(&ref_pic->parent->tf,
FFMIN((row >> 1) - !(row & 1),
pic_height - 1),
@@ -215,7 +216,7 @@ static av_always_inline void mc_dir_part(const H264Context *h, H264SliceContext
const int mx = sl->mv_cache[list][scan8[n]][0] + src_x_offset * 8;
int my = sl->mv_cache[list][scan8[n]][1] + src_y_offset * 8;
const int luma_xy = (mx & 3) + ((my & 3) << 2);
- ptrdiff_t offset = ((mx >> 2) << pixel_shift) + (my >> 2) * sl->mb_linesize;
+ ptrdiff_t offset = (mx >> 2) * (1 << pixel_shift) + (my >> 2) * sl->mb_linesize;
uint8_t *src_y = pic->data[0] + offset;
uint8_t *src_cb, *src_cr;
int extra_width = 0;
@@ -290,9 +291,9 @@ static av_always_inline void mc_dir_part(const H264Context *h, H264SliceContext
emu |= (my >> 3) < 0 || (my >> 3) + 8 >= (pic_height >> 1);
}
- src_cb = pic->data[1] + ((mx >> 3) << pixel_shift) +
+ src_cb = pic->data[1] + ((mx >> 3) * (1 << pixel_shift)) +
(my >> ysh) * sl->mb_uvlinesize;
- src_cr = pic->data[2] + ((mx >> 3) << pixel_shift) +
+ src_cr = pic->data[2] + ((mx >> 3) * (1 << pixel_shift)) +
(my >> ysh) * sl->mb_uvlinesize;
if (emu) {
@@ -304,7 +305,7 @@ static av_always_inline void mc_dir_part(const H264Context *h, H264SliceContext
}
chroma_op(dest_cb, src_cb, sl->mb_uvlinesize,
height >> (chroma_idc == 1 /* yuv420 */),
- mx & 7, (my << (chroma_idc == 2 /* yuv422 */)) & 7);
+ mx & 7, ((unsigned)my << (chroma_idc == 2 /* yuv422 */)) & 7);
if (emu) {
h->vdsp.emulated_edge_mc(sl->edge_emu_buffer, src_cr,
@@ -314,7 +315,7 @@ static av_always_inline void mc_dir_part(const H264Context *h, H264SliceContext
src_cr = sl->edge_emu_buffer;
}
chroma_op(dest_cr, src_cr, sl->mb_uvlinesize, height >> (chroma_idc == 1 /* yuv420 */),
- mx & 7, (my << (chroma_idc == 2 /* yuv422 */)) & 7);
+ mx & 7, ((unsigned)my << (chroma_idc == 2 /* yuv422 */)) & 7);
}
static av_always_inline void mc_part_std(const H264Context *h, H264SliceContext *sl,
@@ -424,10 +425,12 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon
int weight1 = 64 - weight0;
luma_weight_avg(dest_y, tmp_y, sl->mb_linesize,
height, 5, weight0, weight1, 0);
- chroma_weight_avg(dest_cb, tmp_cb, sl->mb_uvlinesize,
- chroma_height, 5, weight0, weight1, 0);
- chroma_weight_avg(dest_cr, tmp_cr, sl->mb_uvlinesize,
- chroma_height, 5, weight0, weight1, 0);
+ if (!CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ chroma_weight_avg(dest_cb, tmp_cb, sl->mb_uvlinesize,
+ chroma_height, 5, weight0, weight1, 0);
+ chroma_weight_avg(dest_cr, tmp_cr, sl->mb_uvlinesize,
+ chroma_height, 5, weight0, weight1, 0);
+ }
} else {
luma_weight_avg(dest_y, tmp_y, sl->mb_linesize, height,
sl->luma_log2_weight_denom,
@@ -435,18 +438,20 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon
sl->luma_weight[refn1][1][0],
sl->luma_weight[refn0][0][1] +
sl->luma_weight[refn1][1][1]);
- chroma_weight_avg(dest_cb, tmp_cb, sl->mb_uvlinesize, chroma_height,
- sl->chroma_log2_weight_denom,
- sl->chroma_weight[refn0][0][0][0],
- sl->chroma_weight[refn1][1][0][0],
- sl->chroma_weight[refn0][0][0][1] +
- sl->chroma_weight[refn1][1][0][1]);
- chroma_weight_avg(dest_cr, tmp_cr, sl->mb_uvlinesize, chroma_height,
- sl->chroma_log2_weight_denom,
- sl->chroma_weight[refn0][0][1][0],
- sl->chroma_weight[refn1][1][1][0],
- sl->chroma_weight[refn0][0][1][1] +
- sl->chroma_weight[refn1][1][1][1]);
+ if (!CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ chroma_weight_avg(dest_cb, tmp_cb, sl->mb_uvlinesize, chroma_height,
+ sl->chroma_log2_weight_denom,
+ sl->chroma_weight[refn0][0][0][0],
+ sl->chroma_weight[refn1][1][0][0],
+ sl->chroma_weight[refn0][0][0][1] +
+ sl->chroma_weight[refn1][1][0][1]);
+ chroma_weight_avg(dest_cr, tmp_cr, sl->mb_uvlinesize, chroma_height,
+ sl->chroma_log2_weight_denom,
+ sl->chroma_weight[refn0][0][1][0],
+ sl->chroma_weight[refn1][1][1][0],
+ sl->chroma_weight[refn0][0][1][1] +
+ sl->chroma_weight[refn1][1][1][1]);
+ }
}
} else {
int list = list1 ? 1 : 0;
@@ -460,15 +465,17 @@ static av_always_inline void mc_part_weighted(const H264Context *h, H264SliceCon
sl->luma_log2_weight_denom,
sl->luma_weight[refn][list][0],
sl->luma_weight[refn][list][1]);
- if (sl->use_weight_chroma) {
- chroma_weight_op(dest_cb, sl->mb_uvlinesize, chroma_height,
- sl->chroma_log2_weight_denom,
- sl->chroma_weight[refn][list][0][0],
- sl->chroma_weight[refn][list][0][1]);
- chroma_weight_op(dest_cr, sl->mb_uvlinesize, chroma_height,
- sl->chroma_log2_weight_denom,
- sl->chroma_weight[refn][list][1][0],
- sl->chroma_weight[refn][list][1][1]);
+ if (!CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ if (sl->use_weight_chroma) {
+ chroma_weight_op(dest_cb, sl->mb_uvlinesize, chroma_height,
+ sl->chroma_log2_weight_denom,
+ sl->chroma_weight[refn][list][0][0],
+ sl->chroma_weight[refn][list][0][1]);
+ chroma_weight_op(dest_cr, sl->mb_uvlinesize, chroma_height,
+ sl->chroma_log2_weight_denom,
+ sl->chroma_weight[refn][list][1][0],
+ sl->chroma_weight[refn][list][1][1]);
+ }
}
}
}
@@ -484,7 +491,7 @@ static av_always_inline void prefetch_motion(const H264Context *h, H264SliceCont
const int mx = (sl->mv_cache[list][scan8[0]][0] >> 2) + 16 * sl->mb_x + 8;
const int my = (sl->mv_cache[list][scan8[0]][1] >> 2) + 16 * sl->mb_y;
uint8_t **src = sl->ref_list[list][refn].data;
- int off = (mx << pixel_shift) +
+ int off = mx * (1<< pixel_shift) +
(my + (sl->mb_x & 3) * 4) * sl->mb_linesize +
(64 << pixel_shift);
h->vdsp.prefetch(src[0] + off, sl->linesize, 4);
@@ -492,9 +499,7 @@ static av_always_inline void prefetch_motion(const H264Context *h, H264SliceCont
h->vdsp.prefetch(src[1] + off, sl->linesize, 4);
h->vdsp.prefetch(src[2] + off, sl->linesize, 4);
} else {
- off = ((mx >> 1) << pixel_shift) +
- ((my >> 1) + (sl->mb_x & 7)) * sl->uvlinesize +
- (64 << pixel_shift);
+ off= ((mx>>1)+64) * (1<<pixel_shift) + ((my>>1) + (sl->mb_x&7))*sl->uvlinesize;
h->vdsp.prefetch(src[1] + off, src[2] - src[1], 2);
}
}
@@ -561,10 +566,8 @@ static av_always_inline void xchg_mb_border(const H264Context *h, H264SliceConte
XCHG(sl->top_borders[top_idx][sl->mb_x + 1],
src_y + (17 << pixel_shift), 1);
}
- }
- if (simple || !CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
- if (chroma444) {
- if (deblock_top) {
+ if (simple || !CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
+ if (chroma444) {
if (deblock_topleft) {
XCHG(top_border_m1 + (24 << pixel_shift), src_cb - (7 << pixel_shift), 1);
XCHG(top_border_m1 + (40 << pixel_shift), src_cr - (7 << pixel_shift), 1);
@@ -577,9 +580,7 @@ static av_always_inline void xchg_mb_border(const H264Context *h, H264SliceConte
XCHG(sl->top_borders[top_idx][sl->mb_x + 1] + (16 << pixel_shift), src_cb + (17 << pixel_shift), 1);
XCHG(sl->top_borders[top_idx][sl->mb_x + 1] + (32 << pixel_shift), src_cr + (17 << pixel_shift), 1);
}
- }
- } else {
- if (deblock_top) {
+ } else {
if (deblock_topleft) {
XCHG(top_border_m1 + (16 << pixel_shift), src_cb - (7 << pixel_shift), 1);
XCHG(top_border_m1 + (24 << pixel_shift), src_cr - (7 << pixel_shift), 1);
@@ -637,7 +638,12 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h,
uint8_t *const ptr = dest_y + block_offset[i];
const int dir = sl->intra4x4_pred_mode_cache[scan8[i]];
if (transform_bypass && h->sps.profile_idc == 244 && dir <= 1) {
- h->hpc.pred8x8l_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift), linesize);
+ if (h->x264_build != -1) {
+ h->hpc.pred8x8l_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift), linesize);
+ } else
+ h->hpc.pred8x8l_filter_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift),
+ (sl-> topleft_samples_available << i) & 0x8000,
+ (sl->topright_samples_available << i) & 0x4000, linesize);
} else {
const int nnz = sl->non_zero_count_cache[scan8[i + p * 16]];
h->hpc.pred8x8l[dir](ptr, (sl->topleft_samples_available << i) & 0x8000,
@@ -670,7 +676,7 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h,
uint64_t tr_high;
if (dir == DIAG_DOWN_LEFT_PRED || dir == VERT_LEFT_PRED) {
const int topright_avail = (sl->topright_samples_available << i) & 0x8000;
- assert(sl->mb_y || linesize <= block_offset[i]);
+ av_assert2(sl->mb_y || linesize <= block_offset[i]);
if (!topright_avail) {
if (pixel_shift) {
tr_high = ((uint16_t *)ptr)[3 - linesize / 2] * 0x0001000100010001ULL;
diff --git a/libavcodec/h264_mb_template.c b/libavcodec/h264_mb_template.c
index 968c55e43e..bc68a738b8 100644
--- a/libavcodec/h264_mb_template.c
+++ b/libavcodec/h264_mb_template.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -100,8 +100,8 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
}
if (!SIMPLE && IS_INTRA_PCM(mb_type)) {
+ const int bit_depth = h->sps.bit_depth_luma;
if (PIXEL_SHIFT) {
- const int bit_depth = h->sps.bit_depth_luma;
int j;
GetBitContext gb;
init_get_bits(&gb, sl->intra_pcm_ptr,
@@ -116,13 +116,10 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
if (!h->sps.chroma_format_idc) {
for (i = 0; i < block_h; i++) {
uint16_t *tmp_cb = (uint16_t *)(dest_cb + i * uvlinesize);
- for (j = 0; j < 8; j++)
- tmp_cb[j] = 1 << (bit_depth - 1);
- }
- for (i = 0; i < block_h; i++) {
uint16_t *tmp_cr = (uint16_t *)(dest_cr + i * uvlinesize);
- for (j = 0; j < 8; j++)
- tmp_cr[j] = 1 << (bit_depth - 1);
+ for (j = 0; j < 8; j++) {
+ tmp_cb[j] = tmp_cr[j] = 1 << (bit_depth - 1);
+ }
}
} else {
for (i = 0; i < block_h; i++) {
@@ -142,9 +139,9 @@ static av_noinline void FUNC(hl_decode_mb)(const H264Context *h, H264SliceContex
memcpy(dest_y + i * linesize, sl->intra_pcm_ptr + i * 16, 16);
if (SIMPLE || !CONFIG_GRAY || !(h->flags & CODEC_FLAG_GRAY)) {
if (!h->sps.chroma_format_idc) {
- for (i = 0; i < block_h; i++) {
- memset(dest_cb + i * uvlinesize, 128, 8);
- memset(dest_cr + i * uvlinesize, 128, 8);
+ for (i = 0; i < 8; i++) {
+ memset(dest_cb + i * uvlinesize, 1 << (bit_depth - 1), 8);
+ memset(dest_cr + i * uvlinesize, 1 << (bit_depth - 1), 8);
}
} else {
const uint8_t *src_cb = sl->intra_pcm_ptr + 256;
diff --git a/libavcodec/h264_mc_template.c b/libavcodec/h264_mc_template.c
index a2958598ab..eaead35bb2 100644
--- a/libavcodec/h264_mc_template.c
+++ b/libavcodec/h264_mc_template.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -74,7 +74,7 @@ static void MCFUNC(hl_motion)(const H264Context *h, H264SliceContext *sl,
const int mb_xy = sl->mb_xy;
const int mb_type = h->cur_pic.mb_type[mb_xy];
- assert(IS_INTER(mb_type));
+ av_assert2(IS_INTER(mb_type));
if (HAVE_THREADS && (h->avctx->active_thread_type & FF_THREAD_FRAME))
await_references(h, sl);
@@ -106,7 +106,7 @@ static void MCFUNC(hl_motion)(const H264Context *h, H264SliceContext *sl,
} else {
int i;
- assert(IS_8X8(mb_type));
+ av_assert2(IS_8X8(mb_type));
for (i = 0; i < 4; i++) {
const int sub_mb_type = sl->sub_mb_type[i];
@@ -144,7 +144,7 @@ static void MCFUNC(hl_motion)(const H264Context *h, H264SliceContext *sl,
IS_DIR(sub_mb_type, 0, 0), IS_DIR(sub_mb_type, 0, 1));
} else {
int j;
- assert(IS_SUB_4X4(sub_mb_type));
+ av_assert2(IS_SUB_4X4(sub_mb_type));
for (j = 0; j < 4; j++) {
int sub_x_offset = x_offset + 2 * (j & 1);
int sub_y_offset = y_offset + (j & 2);
diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c
index 3b212e5a55..ae96ee953d 100644
--- a/libavcodec/h264_mp4toannexb_bsf.c
+++ b/libavcodec/h264_mp4toannexb_bsf.c
@@ -2,20 +2,20 @@
* H.264 MP4 to Annex B byte stream format filter
* Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,12 @@
#include "avcodec.h"
typedef struct H264BSFContext {
+ int32_t sps_offset;
+ int32_t pps_offset;
uint8_t length_size;
- uint8_t first_idr;
+ uint8_t new_idr;
+ uint8_t idr_sps_seen;
+ uint8_t idr_pps_seen;
int extradata_parsed;
} H264BSFContext;
@@ -59,7 +63,7 @@ static int alloc_and_copy(uint8_t **poutbuf, int *poutbuf_size,
return 0;
}
-static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding)
+static int h264_extradata_to_annexb(H264BSFContext *ctx, AVCodecContext *avctx, const int padding)
{
uint16_t unit_size;
uint64_t total_size = 0;
@@ -69,18 +73,14 @@ static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding)
static const uint8_t nalu_header[4] = { 0, 0, 0, 1 };
int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size
- if (length_size == 3)
- return AVERROR(EINVAL);
+ ctx->sps_offset = ctx->pps_offset = -1;
/* retrieve sps and pps unit(s) */
unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */
if (!unit_nb) {
- unit_nb = *extradata++; /* number of pps unit(s) */
- sps_done++;
-
- if (unit_nb)
- pps_seen = 1;
+ goto pps;
} else {
+ ctx->sps_offset = 0;
sps_seen = 1;
}
@@ -89,9 +89,15 @@ static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding)
unit_size = AV_RB16(extradata);
total_size += unit_size + 4;
- if (total_size > INT_MAX - padding ||
- extradata + 2 + unit_size > avctx->extradata +
- avctx->extradata_size) {
+ if (total_size > INT_MAX - padding) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n");
+ av_free(out);
+ return AVERROR(EINVAL);
+ }
+ if (extradata + 2 + unit_size > avctx->extradata + avctx->extradata_size) {
+ av_log(avctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, "
+ "corrupted stream or invalid MP4/AVCC bitstream\n");
av_free(out);
return AVERROR(EINVAL);
}
@@ -100,16 +106,18 @@ static int h264_extradata_to_annexb(AVCodecContext *avctx, const int padding)
memcpy(out + total_size - unit_size - 4, nalu_header, 4);
memcpy(out + total_size - unit_size, extradata + 2, unit_size);
extradata += 2 + unit_size;
-
+pps:
if (!unit_nb && !sps_done++) {
unit_nb = *extradata++; /* number of pps unit(s) */
- if (unit_nb)
+ if (unit_nb) {
+ ctx->pps_offset = (extradata - 1) - (avctx->extradata + 4);
pps_seen = 1;
+ }
}
}
if (out)
- memset(out + total_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ memset(out + total_size, 0, padding);
if (!sps_seen)
av_log(avctx, AV_LOG_WARNING,
@@ -135,6 +143,7 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
int keyframe)
{
H264BSFContext *ctx = bsfc->priv_data;
+ int i;
uint8_t unit_type;
int32_t nal_size;
uint32_t cumul_size = 0;
@@ -150,26 +159,25 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
/* retrieve sps and pps NAL units from extradata */
if (!ctx->extradata_parsed) {
- ret = h264_extradata_to_annexb(avctx, FF_INPUT_BUFFER_PADDING_SIZE);
+ ret = h264_extradata_to_annexb(ctx, avctx, FF_INPUT_BUFFER_PADDING_SIZE);
if (ret < 0)
return ret;
ctx->length_size = ret;
- ctx->first_idr = 1;
+ ctx->new_idr = 1;
+ ctx->idr_sps_seen = 0;
+ ctx->idr_pps_seen = 0;
ctx->extradata_parsed = 1;
}
*poutbuf_size = 0;
*poutbuf = NULL;
do {
+ ret= AVERROR(EINVAL);
if (buf + ctx->length_size > buf_end)
goto fail;
- if (ctx->length_size == 1) {
- nal_size = buf[0];
- } else if (ctx->length_size == 2) {
- nal_size = AV_RB16(buf);
- } else
- nal_size = AV_RB32(buf);
+ for (nal_size = 0, i = 0; i<ctx->length_size; i++)
+ nal_size = (nal_size << 8) | buf[i];
buf += ctx->length_size;
unit_type = *buf & 0x1f;
@@ -177,21 +185,62 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
if (buf + nal_size > buf_end || nal_size < 0)
goto fail;
- /* prepend only to the first type 5 NAL unit of an IDR picture */
- if (ctx->first_idr && unit_type == 5) {
- if (alloc_and_copy(poutbuf, poutbuf_size,
+ if (unit_type == 7)
+ ctx->idr_sps_seen = ctx->new_idr = 1;
+ else if (unit_type == 8) {
+ ctx->idr_pps_seen = ctx->new_idr = 1;
+ /* if SPS has not been seen yet, prepend the AVCC one to PPS */
+ if (!ctx->idr_sps_seen) {
+ if (ctx->sps_offset == -1)
+ av_log(avctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n");
+ else {
+ if ((ret = alloc_and_copy(poutbuf, poutbuf_size,
+ avctx->extradata + ctx->sps_offset,
+ ctx->pps_offset != -1 ? ctx->pps_offset : avctx->extradata_size - ctx->sps_offset,
+ buf, nal_size)) < 0)
+ goto fail;
+ ctx->idr_sps_seen = 1;
+ goto next_nal;
+ }
+ }
+ }
+
+ /* if this is a new IDR picture following an IDR picture, reset the idr flag.
+ * Just check first_mb_in_slice to be 0 as this is the simplest solution.
+ * This could be checking idr_pic_id instead, but would complexify the parsing. */
+ if (!ctx->new_idr && unit_type == 5 && (buf[1] & 0x80))
+ ctx->new_idr = 1;
+
+ /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */
+ if (ctx->new_idr && unit_type == 5 && !ctx->idr_sps_seen && !ctx->idr_pps_seen) {
+ if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
avctx->extradata, avctx->extradata_size,
- buf, nal_size) < 0)
+ buf, nal_size)) < 0)
+ goto fail;
+ ctx->new_idr = 0;
+ /* if only SPS has been seen, also insert PPS */
+ } else if (ctx->new_idr && unit_type == 5 && ctx->idr_sps_seen && !ctx->idr_pps_seen) {
+ if (ctx->pps_offset == -1) {
+ av_log(avctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n");
+ if ((ret = alloc_and_copy(poutbuf, poutbuf_size,
+ NULL, 0, buf, nal_size)) < 0)
+ goto fail;
+ } else if ((ret = alloc_and_copy(poutbuf, poutbuf_size,
+ avctx->extradata + ctx->pps_offset, avctx->extradata_size - ctx->pps_offset,
+ buf, nal_size)) < 0)
goto fail;
- ctx->first_idr = 0;
} else {
- if (alloc_and_copy(poutbuf, poutbuf_size,
- NULL, 0, buf, nal_size) < 0)
+ if ((ret=alloc_and_copy(poutbuf, poutbuf_size,
+ NULL, 0, buf, nal_size)) < 0)
goto fail;
- if (!ctx->first_idr && unit_type == 1)
- ctx->first_idr = 1;
+ if (!ctx->new_idr && unit_type == 1) {
+ ctx->new_idr = 1;
+ ctx->idr_sps_seen = 0;
+ ctx->idr_pps_seen = 0;
+ }
}
+next_nal:
buf += nal_size;
cumul_size += nal_size + ctx->length_size;
} while (cumul_size < buf_size);
@@ -201,11 +250,11 @@ static int h264_mp4toannexb_filter(AVBitStreamFilterContext *bsfc,
fail:
av_freep(poutbuf);
*poutbuf_size = 0;
- return AVERROR(EINVAL);
+ return ret;
}
AVBitStreamFilter ff_h264_mp4toannexb_bsf = {
- "h264_mp4toannexb",
- sizeof(H264BSFContext),
- h264_mp4toannexb_filter,
+ .name = "h264_mp4toannexb",
+ .priv_data_size = sizeof(H264BSFContext),
+ .filter = h264_mp4toannexb_filter,
};
diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h
index 5e8f237f63..57fa9b90ef 100644
--- a/libavcodec/h264_mvpred.h
+++ b/libavcodec/h264_mvpred.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... motion vector predicion
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,8 +32,8 @@
#include "avcodec.h"
#include "h264.h"
#include "mpegutils.h"
+#include "libavutil/avassert.h"
-#include <assert.h>
static av_always_inline int fetch_diagonal_mv(const H264Context *h, H264SliceContext *sl,
const int16_t **C,
@@ -106,7 +106,7 @@ static av_always_inline void pred_motion(const H264Context *const h,
const int16_t *C;
int diagonal_ref, match_count;
- assert(part_width == 1 || part_width == 2 || part_width == 4);
+ av_assert2(part_width == 1 || part_width == 2 || part_width == 4);
/* mv_cache
* B . . A T T T T
@@ -488,7 +488,7 @@ static void fill_decode_caches(const H264Context *h, H264SliceContext *sl, int m
} else {
int left_typei = h->cur_pic.mb_type[left_xy[LTOP] + h->mb_stride];
- assert(left_xy[LTOP] == left_xy[LBOT]);
+ av_assert2(left_xy[LTOP] == left_xy[LBOT]);
if (!((left_typei & type_mask) && (left_type[LTOP] & type_mask))) {
sl->topleft_samples_available &= 0xDF5F;
sl->left_samples_available &= 0x5F5F;
@@ -613,7 +613,7 @@ static void fill_decode_caches(const H264Context *h, H264SliceContext *sl, int m
int16_t(*mv)[2] = h->cur_pic.motion_val[list];
if (!USES_LIST(mb_type, list))
continue;
- assert(!(IS_DIRECT(mb_type) && !sl->direct_spatial_mv_pred));
+ av_assert2(!(IS_DIRECT(mb_type) && !sl->direct_spatial_mv_pred));
if (USES_LIST(top_type, list)) {
const int b_xy = h->mb2b_xy[top_xy] + 3 * b_stride;
@@ -670,7 +670,7 @@ static void fill_decode_caches(const H264Context *h, H264SliceContext *sl, int m
ref_cache[4 - 1 * 8] = topright_type ? LIST_NOT_USED
: PART_NOT_AVAILABLE;
}
- if (ref_cache[4 - 1 * 8] < 0) {
+ if(ref_cache[2 - 1*8] < 0 || ref_cache[4 - 1 * 8] < 0) {
if (USES_LIST(topleft_type, list)) {
const int b_xy = h->mb2b_xy[topleft_xy] + 3 + b_stride +
(sl->topleft_partition & 2 * b_stride);
diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index f44435532e..19d1aa3f21 100644
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... parser
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,8 @@
* @author Michael Niedermayer <michaelni@gmx.at>
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/attributes.h"
#include "parser.h"
#include "h264data.h"
@@ -32,8 +34,6 @@
#include "internal.h"
#include "mpegutils.h"
-#include <assert.h>
-
typedef struct H264ParseContext {
H264Context h;
ParseContext pc;
@@ -45,18 +45,36 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf,
int buf_size)
{
H264Context *h = &p->h;
- int i;
+ int i, j;
uint32_t state;
ParseContext *pc = &p->pc;
+
+ int next_avc= h->is_avc ? 0 : buf_size;
// mb_addr= pc->mb_addr - 1;
state = pc->state;
if (state > 13)
state = 7;
+ if (h->is_avc && !h->nal_length_size)
+ av_log(h->avctx, AV_LOG_ERROR, "AVC-parser: nal length size invalid\n");
+
for (i = 0; i < buf_size; i++) {
+ if (i >= next_avc) {
+ int nalsize = 0;
+ i = next_avc;
+ for (j = 0; j < h->nal_length_size; j++)
+ nalsize = (nalsize << 8) | buf[i++];
+ if (nalsize <= 0 || nalsize > buf_size - i) {
+ av_log(h->avctx, AV_LOG_ERROR, "AVC-parser: nal size %d remaining %d\n", nalsize, buf_size - i);
+ return buf_size;
+ }
+ next_avc = i + nalsize;
+ state = 5;
+ }
+
if (state == 7) {
- i += h->h264dsp.startcode_find_candidate(buf + i, buf_size - i);
- if (i < buf_size)
+ i += h->h264dsp.startcode_find_candidate(buf + i, next_avc - i);
+ if (i < next_avc)
state = 2;
} else if (state <= 2) {
if (buf[i] == 1)
@@ -75,27 +93,40 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf,
}
} else if (nalu_type == NAL_SLICE || nalu_type == NAL_DPA ||
nalu_type == NAL_IDR_SLICE) {
+ state += 8;
+ continue;
+ }
+ state = 7;
+ } else {
+ h->parse_history[h->parse_history_count++]= buf[i];
+ if (h->parse_history_count>5) {
+ unsigned int mb, last_mb= h->parse_last_mb;
+ GetBitContext gb;
+
+ init_get_bits(&gb, h->parse_history, 8*h->parse_history_count);
+ h->parse_history_count=0;
+ mb= get_ue_golomb_long(&gb);
+ h->parse_last_mb= mb;
if (pc->frame_start_found) {
- state += 8;
- continue;
+ if (mb <= last_mb)
+ goto found;
} else
pc->frame_start_found = 1;
+ state = 7;
}
- state = 7;
- } else {
- // first_mb_in_slice is 0, probably the first nal of a new slice
- if (buf[i] & 0x80)
- goto found;
- state = 7;
}
}
pc->state = state;
+ if (h->is_avc)
+ return next_avc;
return END_NOT_FOUND;
found:
pc->state = 7;
pc->frame_start_found = 0;
- return i - (state & 5);
+ if (h->is_avc)
+ return next_avc;
+ return i - (state & 5) - 5 * (state > 7);
}
static int scan_mmco_reset(AVCodecParserContext *s)
@@ -180,16 +211,17 @@ static int scan_mmco_reset(AVCodecParserContext *s)
*/
static inline int parse_nal_units(AVCodecParserContext *s,
AVCodecContext *avctx,
- const uint8_t *buf, int buf_size)
+ const uint8_t * const buf, int buf_size)
{
H264ParseContext *p = s->priv_data;
H264Context *h = &p->h;
H264SliceContext *sl = &h->slice_ctx[0];
- const uint8_t *buf_end = buf + buf_size;
+ int buf_index, next_avc;
unsigned int pps_id;
unsigned int slice_type;
int state = -1, got_reset = 0;
const uint8_t *ptr;
+ int q264 = buf_size >=4 && !memcmp("Q264", buf, 4);
int field_poc[2];
/* set some sane default values */
@@ -199,17 +231,31 @@ static inline int parse_nal_units(AVCodecParserContext *s,
h->avctx = avctx;
ff_h264_reset_sei(h);
+ h->sei_fpa.frame_packing_arrangement_cancel_flag = -1;
if (!buf_size)
return 0;
+ buf_index = 0;
+ next_avc = h->is_avc ? 0 : buf_size;
for (;;) {
- int src_length, dst_length, consumed;
- buf = avpriv_find_start_code(buf, buf_end, &state);
- if (buf >= buf_end)
- break;
- --buf;
- src_length = buf_end - buf;
+ int src_length, dst_length, consumed, nalsize = 0;
+
+ if (buf_index >= next_avc) {
+ nalsize = get_avc_nalsize(h, buf, buf_size, &buf_index);
+ if (nalsize < 0)
+ break;
+ next_avc = buf_index + nalsize;
+ } else {
+ buf_index = find_start_code(buf, buf_size, buf_index, next_avc);
+ if (buf_index >= buf_size)
+ break;
+ if (buf_index >= next_avc)
+ continue;
+ }
+ src_length = next_avc - buf_index;
+
+ state = buf[buf_index];
switch (state & 0x1f) {
case NAL_SLICE:
case NAL_IDR_SLICE:
@@ -226,14 +272,17 @@ static inline int parse_nal_units(AVCodecParserContext *s,
}
break;
}
- ptr = ff_h264_decode_nal(h, sl, buf, &dst_length, &consumed, src_length);
+ ptr = ff_h264_decode_nal(h, sl, buf + buf_index, &dst_length,
+ &consumed, src_length);
if (!ptr || dst_length < 0)
break;
+ buf_index += consumed;
+
init_get_bits(&h->gb, ptr, 8 * dst_length);
switch (h->nal_unit_type) {
case NAL_SPS:
- ff_h264_decode_seq_parameter_set(h);
+ ff_h264_decode_seq_parameter_set(h, 0);
break;
case NAL_PPS:
ff_h264_decode_picture_parameter_set(h, h->gb.size_in_bits);
@@ -251,7 +300,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
/* fall through */
case NAL_SLICE:
init_get_bits(&sl->gb, ptr, 8 * dst_length);
- get_ue_golomb(&sl->gb); // skip first_mb_in_slice
+ get_ue_golomb_long(&sl->gb); // skip first_mb_in_slice
slice_type = get_ue_golomb_31(&sl->gb);
s->pict_type = golomb_to_pict_type[slice_type % 5];
if (h->sei_recovery_frame_cnt >= 0) {
@@ -278,6 +327,9 @@ static inline int parse_nal_units(AVCodecParserContext *s,
h->sps = *h->sps_buffers[h->pps.sps_id];
h->frame_num = get_bits(&sl->gb, h->sps.log2_max_frame_num);
+ if(h->sps.ref_frame_count <= 1 && h->pps.ref_count[0] <= 1 && s->pict_type == AV_PICTURE_TYPE_I)
+ s->key_frame = 1;
+
s->coded_width = 16 * h->sps.mb_width;
s->coded_height = 16 * h->sps.mb_height;
s->width = s->coded_width - (h->sps.crop_right + h->sps.crop_left);
@@ -431,10 +483,11 @@ static inline int parse_nal_units(AVCodecParserContext *s,
return 0; /* no need to evaluate the rest */
}
- buf += consumed;
}
+ if (q264)
+ return 0;
/* didn't find a picture! */
- av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit\n");
+ av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size);
return -1;
}
@@ -452,14 +505,13 @@ static int h264_parse(AVCodecParserContext *s,
p->got_first = 1;
if (avctx->extradata_size) {
h->avctx = avctx;
- // must be done like in the decoder.
- // otherwise opening the parser, creating extradata,
- // and then closing and opening again
+ // must be done like in decoder, otherwise opening the parser,
+ // letting it create extradata and then closing and opening again
// will cause has_b_frames to be always set.
- // NB: estimate_timings_from_pts behaves exactly like this.
+ // Note that estimate_timings_from_pts does exactly this.
if (!avctx->has_b_frames)
h->low_delay = 1;
- ff_h264_decode_extradata(h);
+ ff_h264_decode_extradata(h, avctx->extradata, avctx->extradata_size);
}
}
@@ -475,13 +527,15 @@ static int h264_parse(AVCodecParserContext *s,
}
if (next < 0 && next != END_NOT_FOUND) {
- assert(pc->last_index + next >= 0);
+ av_assert1(pc->last_index + next >= 0);
h264_find_frame_end(p, &pc->buffer[pc->last_index + next], -next); // update state
}
}
parse_nal_units(s, avctx, buf, buf_size);
+ if (avctx->framerate.num)
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
if (h->sei_cpb_removal_delay >= 0) {
s->dts_sync_point = h->sei_buffering_period_present;
s->dts_ref_dts_delta = h->sei_cpb_removal_delay;
@@ -504,41 +558,47 @@ static int h264_parse(AVCodecParserContext *s,
static int h264_split(AVCodecContext *avctx,
const uint8_t *buf, int buf_size)
{
- int i;
uint32_t state = -1;
int has_sps = 0;
+ int has_pps = 0;
+ const uint8_t *ptr = buf, *end = buf + buf_size;
+ int nalu_type;
- for (i = 0; i <= buf_size; i++) {
- if ((state & 0xFFFFFF1F) == 0x107)
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &state);
+ if ((state & 0xFFFFFF00) != 0x100)
+ break;
+ nalu_type = state & 0x1F;
+ if (nalu_type == NAL_SPS) {
has_sps = 1;
- /* if((state&0xFFFFFF1F) == 0x101 ||
- * (state&0xFFFFFF1F) == 0x102 ||
- * (state&0xFFFFFF1F) == 0x105) {
+ } else if (nalu_type == NAL_PPS)
+ has_pps = 1;
+ /* else if (nalu_type == 0x01 ||
+ * nalu_type == 0x02 ||
+ * nalu_type == 0x05) {
* }
*/
- if ((state & 0xFFFFFF00) == 0x100 && (state & 0xFFFFFF1F) != 0x106 &&
- (state & 0xFFFFFF1F) != 0x107 && (state & 0xFFFFFF1F) != 0x108 &&
- (state & 0xFFFFFF1F) != 0x109 && (state & 0xFFFFFF1F) != 0x10d &&
- (state & 0xFFFFFF1F) != 0x10f) {
+ else if ((nalu_type != NAL_SEI || has_pps) &&
+ nalu_type != NAL_AUD && nalu_type != NAL_SPS_EXT &&
+ nalu_type != 0x0f) {
if (has_sps) {
- while (i > 4 && buf[i - 5] == 0)
- i--;
- return i - 4;
+ while (ptr - 4 > buf && ptr[-5] == 0)
+ ptr--;
+ return ptr - 4 - buf;
}
}
- if (i < buf_size)
- state = (state << 8) | buf[i];
}
+
return 0;
}
-static void close(AVCodecParserContext *s)
+static void h264_close(AVCodecParserContext *s)
{
H264ParseContext *p = s->priv_data;
H264Context *h = &p->h;
ParseContext *pc = &p->pc;
- av_free(pc->buffer);
+ av_freep(&pc->buffer);
ff_h264_free_context(h);
}
@@ -562,6 +622,6 @@ AVCodecParser ff_h264_parser = {
.priv_data_size = sizeof(H264ParseContext),
.parser_init = init,
.parser_parse = h264_parse,
- .parser_close = close,
+ .parser_close = h264_close,
.split = h264_split,
};
diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index 3e2c84e566..14d8f19ef8 100644
--- a/libavcodec/h264_picture.c
+++ b/libavcodec/h264_picture.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,6 +42,7 @@
#include "mpegutils.h"
#include "rectangle.h"
#include "thread.h"
+#include "vdpau_internal.h"
void ff_h264_unref_picture(H264Context *h, H264Picture *pic)
{
@@ -114,7 +115,12 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src)
dst->mbaff = src->mbaff;
dst->field_picture = src->field_picture;
dst->reference = src->reference;
+ dst->crop = src->crop;
+ dst->crop_left = src->crop_left;
+ dst->crop_top = src->crop_top;
dst->recovered = src->recovered;
+ dst->invalid_gap = src->invalid_gap;
+ dst->sei_recovery_frame_cnt = src->sei_recovery_frame_cnt;
return 0;
fail:
@@ -122,11 +128,13 @@ fail:
return ret;
}
-#if CONFIG_ERROR_RESILIENCE
-static void h264_set_erpic(ERPicture *dst, H264Picture *src)
+void ff_h264_set_erpic(ERPicture *dst, H264Picture *src)
{
+#if CONFIG_ERROR_RESILIENCE
int i;
+ memset(dst, 0, sizeof(*dst));
+
if (!src)
return;
@@ -140,8 +148,8 @@ static void h264_set_erpic(ERPicture *dst, H264Picture *src)
dst->mb_type = src->mb_type;
dst->field_picture = src->field_picture;
-}
#endif /* CONFIG_ERROR_RESILIENCE */
+}
int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup)
{
@@ -149,9 +157,9 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup)
int err = 0;
h->mb_y = 0;
- if (!in_setup && !h->droppable)
- ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
- h->picture_structure == PICT_BOTTOM_FIELD);
+ if (CONFIG_H264_VDPAU_DECODER &&
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+ ff_vdpau_h264_set_reference_frames(h);
if (in_setup || !(avctx->active_thread_type & FF_THREAD_FRAME)) {
if (!h->droppable) {
@@ -169,7 +177,12 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup)
"hardware accelerator failed to decode picture\n");
}
+ if (CONFIG_H264_VDPAU_DECODER &&
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+ ff_vdpau_h264_picture_complete(h);
+
#if CONFIG_ERROR_RESILIENCE
+ av_assert0(sl == h->slice_ctx);
/*
* FIXME: Error handling code does not seem to support interlaced
* when slices span multiple rows
@@ -182,16 +195,36 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup)
* past end by one (callers fault) and resync_mb_y != 0
* causes problems for the first MB line, too.
*/
- if (!FIELD_PICTURE(h) && h->enable_er) {
- h264_set_erpic(&sl->er.cur_pic, h->cur_pic_ptr);
- h264_set_erpic(&sl->er.last_pic,
- sl->ref_count[0] ? sl->ref_list[0][0].parent : NULL);
- h264_set_erpic(&sl->er.next_pic,
- sl->ref_count[1] ? sl->ref_list[1][0].parent : NULL);
+ if (!FIELD_PICTURE(h) && h->current_slice && !h->sps.new && h->enable_er) {
+ int use_last_pic = h->last_pic_for_ec.f->buf[0] && !sl->ref_count[0];
+
+ ff_h264_set_erpic(&sl->er.cur_pic, h->cur_pic_ptr);
+
+ if (use_last_pic) {
+ ff_h264_set_erpic(&sl->er.last_pic, &h->last_pic_for_ec);
+ sl->ref_list[0][0].parent = &h->last_pic_for_ec;
+ memcpy(sl->ref_list[0][0].data, h->last_pic_for_ec.f->data, sizeof(sl->ref_list[0][0].data));
+ memcpy(sl->ref_list[0][0].linesize, h->last_pic_for_ec.f->linesize, sizeof(sl->ref_list[0][0].linesize));
+ sl->ref_list[0][0].reference = h->last_pic_for_ec.reference;
+ } else if (sl->ref_count[0]) {
+ ff_h264_set_erpic(&sl->er.last_pic, sl->ref_list[0][0].parent);
+ } else
+ ff_h264_set_erpic(&sl->er.last_pic, NULL);
+
+ if (sl->ref_count[1])
+ ff_h264_set_erpic(&sl->er.next_pic, sl->ref_list[1][0].parent);
+
+ sl->er.ref_count = sl->ref_count[0];
+
ff_er_frame_end(&sl->er);
+ if (use_last_pic)
+ memset(&sl->ref_list[0][0], 0, sizeof(sl->ref_list[0][0]));
}
#endif /* CONFIG_ERROR_RESILIENCE */
+ if (!in_setup && !h->droppable)
+ ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
+ h->picture_structure == PICT_BOTTOM_FIELD);
emms_c();
h->current_slice = 0;
diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c
index 23615d527b..ae1b60a45b 100644
--- a/libavcodec/h264_ps.c
+++ b/libavcodec/h264_ps.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... parameter set decoding
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,32 +31,12 @@
#include "internal.h"
#include "avcodec.h"
#include "h264.h"
-#include "h264data.h" //FIXME FIXME FIXME (just for zigzag_scan)
+#include "h264data.h"
#include "golomb.h"
#define MAX_LOG2_MAX_FRAME_NUM (12 + 4)
#define MIN_LOG2_MAX_FRAME_NUM 4
-static const AVRational pixel_aspect[17] = {
- { 0, 1 },
- { 1, 1 },
- { 12, 11 },
- { 10, 11 },
- { 16, 11 },
- { 40, 33 },
- { 24, 11 },
- { 20, 11 },
- { 32, 11 },
- { 80, 33 },
- { 18, 11 },
- { 15, 11 },
- { 64, 33 },
- { 160, 99 },
- { 4, 3 },
- { 3, 2 },
- { 2, 1 },
-};
-
#define QP(qP, depth) ((qP) + 6 * ((depth) - 8))
#define CHROMA_QP_TABLE_END(d) \
@@ -70,13 +50,35 @@ static const AVRational pixel_aspect[17] = {
QP(37, d), QP(37, d), QP(37, d), QP(38, d), QP(38, d), QP(38, d), \
QP(39, d), QP(39, d), QP(39, d), QP(39, d)
-const uint8_t ff_h264_chroma_qp[3][QP_MAX_NUM + 1] = {
+const uint8_t ff_h264_chroma_qp[7][QP_MAX_NUM + 1] = {
{ CHROMA_QP_TABLE_END(8) },
{ 0, 1, 2, 3, 4, 5,
CHROMA_QP_TABLE_END(9) },
- { 0, 1, 2, 3, 4, 5,
+ { 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11,
CHROMA_QP_TABLE_END(10) },
+ { 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11,
+ 12,13,14,15, 16, 17,
+ CHROMA_QP_TABLE_END(11) },
+ { 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11,
+ 12,13,14,15, 16, 17,
+ 18,19,20,21, 22, 23,
+ CHROMA_QP_TABLE_END(12) },
+ { 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11,
+ 12,13,14,15, 16, 17,
+ 18,19,20,21, 22, 23,
+ 24,25,26,27, 28, 29,
+ CHROMA_QP_TABLE_END(13) },
+ { 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11,
+ 12,13,14,15, 16, 17,
+ 18,19,20,21, 22, 23,
+ 24,25,26,27, 28, 29,
+ 30,31,32,33, 34, 35,
+ CHROMA_QP_TABLE_END(14) },
};
static const uint8_t default_scaling4[2][16] = {
@@ -142,8 +144,8 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps)
if (aspect_ratio_idc == EXTENDED_SAR) {
sps->sar.num = get_bits(&h->gb, 16);
sps->sar.den = get_bits(&h->gb, 16);
- } else if (aspect_ratio_idc < FF_ARRAY_ELEMS(pixel_aspect)) {
- sps->sar = pixel_aspect[aspect_ratio_idc];
+ } else if (aspect_ratio_idc < FF_ARRAY_ELEMS(ff_h264_pixel_aspect)) {
+ sps->sar = ff_h264_pixel_aspect[aspect_ratio_idc];
} else {
av_log(h->avctx, AV_LOG_ERROR, "illegal aspect ratio\n");
return AVERROR_INVALIDDATA;
@@ -182,15 +184,23 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps)
get_ue_golomb(&h->gb); /* chroma_sample_location_type_bottom_field */
}
+ if (show_bits1(&h->gb) && get_bits_left(&h->gb) < 10) {
+ av_log(h->avctx, AV_LOG_WARNING, "Truncated VUI\n");
+ return 0;
+ }
+
sps->timing_info_present_flag = get_bits1(&h->gb);
if (sps->timing_info_present_flag) {
- sps->num_units_in_tick = get_bits_long(&h->gb, 32);
- sps->time_scale = get_bits_long(&h->gb, 32);
- if (!sps->num_units_in_tick || !sps->time_scale) {
+ unsigned num_units_in_tick = get_bits_long(&h->gb, 32);
+ unsigned time_scale = get_bits_long(&h->gb, 32);
+ if (!num_units_in_tick || !time_scale) {
av_log(h->avctx, AV_LOG_ERROR,
- "time_scale/num_units_in_tick invalid or unsupported (%"PRIu32"/%"PRIu32")\n",
- sps->time_scale, sps->num_units_in_tick);
- return AVERROR_INVALIDDATA;
+ "time_scale/num_units_in_tick invalid or unsupported (%u/%u)\n",
+ time_scale, num_units_in_tick);
+ sps->timing_info_present_flag = 0;
+ } else {
+ sps->num_units_in_tick = num_units_in_tick;
+ sps->time_scale = time_scale;
}
sps->fixed_frame_rate_flag = get_bits1(&h->gb);
}
@@ -207,7 +217,8 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps)
sps->vcl_hrd_parameters_present_flag)
get_bits1(&h->gb); /* low_delay_hrd_flag */
sps->pic_struct_present_flag = get_bits1(&h->gb);
-
+ if (!get_bits_left(&h->gb))
+ return 0;
sps->bitstream_restriction_flag = get_bits1(&h->gb);
if (sps->bitstream_restriction_flag) {
get_bits1(&h->gb); /* motion_vectors_over_pic_boundaries_flag */
@@ -232,11 +243,6 @@ static inline int decode_vui_parameters(H264Context *h, SPS *sps)
return AVERROR_INVALIDDATA;
}
}
- if (get_bits_left(&h->gb) < 0) {
- av_log(h->avctx, AV_LOG_ERROR,
- "Overread VUI by %d bits\n", -get_bits_left(&h->gb));
- return AVERROR_INVALIDDATA;
- }
return 0;
}
@@ -283,20 +289,18 @@ static void decode_scaling_matrices(H264Context *h, SPS *sps,
decode_scaling_list(h, scaling_matrix4[5], 16, default_scaling4[1], scaling_matrix4[4]); // Inter, Cb
if (is_sps || pps->transform_8x8_mode) {
decode_scaling_list(h, scaling_matrix8[0], 64, default_scaling8[0], fallback[2]); // Intra, Y
- if (sps->chroma_format_idc == 3) {
- decode_scaling_list(h, scaling_matrix8[1], 64, default_scaling8[0], scaling_matrix8[0]); // Intra, Cr
- decode_scaling_list(h, scaling_matrix8[2], 64, default_scaling8[0], scaling_matrix8[1]); // Intra, Cb
- }
decode_scaling_list(h, scaling_matrix8[3], 64, default_scaling8[1], fallback[3]); // Inter, Y
if (sps->chroma_format_idc == 3) {
+ decode_scaling_list(h, scaling_matrix8[1], 64, default_scaling8[0], scaling_matrix8[0]); // Intra, Cr
decode_scaling_list(h, scaling_matrix8[4], 64, default_scaling8[1], scaling_matrix8[3]); // Inter, Cr
+ decode_scaling_list(h, scaling_matrix8[2], 64, default_scaling8[0], scaling_matrix8[1]); // Intra, Cb
decode_scaling_list(h, scaling_matrix8[5], 64, default_scaling8[1], scaling_matrix8[4]); // Inter, Cb
}
}
}
}
-int ff_h264_decode_seq_parameter_set(H264Context *h)
+int ff_h264_decode_seq_parameter_set(H264Context *h, int ignore_truncation)
{
int profile_idc, level_idc, constraint_set_flags = 0;
unsigned int sps_id;
@@ -327,10 +331,12 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->profile_idc = profile_idc;
sps->constraint_set_flags = constraint_set_flags;
sps->level_idc = level_idc;
+ sps->full_range = -1;
memset(sps->scaling_matrix4, 16, sizeof(sps->scaling_matrix4));
memset(sps->scaling_matrix8, 16, sizeof(sps->scaling_matrix8));
sps->scaling_matrix_present = 0;
+ sps->colorspace = 2; //AVCOL_SPC_UNSPECIFIED
if (sps->profile_idc == 100 || // High profile
sps->profile_idc == 110 || // High10 profile
@@ -344,12 +350,16 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->profile_idc == 138 || // Multiview Depth High profile (MVCD)
sps->profile_idc == 144) { // old High444 profile
sps->chroma_format_idc = get_ue_golomb_31(&h->gb);
- if (sps->chroma_format_idc > 3) {
+ if (sps->chroma_format_idc > 3U) {
avpriv_request_sample(h->avctx, "chroma_format_idc %u",
sps->chroma_format_idc);
goto fail;
} else if (sps->chroma_format_idc == 3) {
sps->residual_color_transform_flag = get_bits1(&h->gb);
+ if (sps->residual_color_transform_flag) {
+ av_log(h->avctx, AV_LOG_ERROR, "separate color planes are not supported\n");
+ goto fail;
+ }
}
sps->bit_depth_luma = get_ue_golomb(&h->gb) + 8;
sps->bit_depth_chroma = get_ue_golomb(&h->gb) + 8;
@@ -358,6 +368,12 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
"Different chroma and luma bit depth");
goto fail;
}
+ if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 14 ||
+ sps->bit_depth_chroma < 8 || sps->bit_depth_chroma > 14) {
+ av_log(h->avctx, AV_LOG_ERROR, "illegal bit depth value (%d, %d)\n",
+ sps->bit_depth_luma, sps->bit_depth_chroma);
+ goto fail;
+ }
sps->transform_bypass = get_bits1(&h->gb);
decode_scaling_matrices(h, sps, NULL, 1,
sps->scaling_matrix4, sps->scaling_matrix8);
@@ -380,7 +396,12 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->poc_type = get_ue_golomb_31(&h->gb);
if (sps->poc_type == 0) { // FIXME #define
- sps->log2_max_poc_lsb = get_ue_golomb(&h->gb) + 4;
+ unsigned t = get_ue_golomb(&h->gb);
+ if (t>12) {
+ av_log(h->avctx, AV_LOG_ERROR, "log2_max_poc_lsb (%d) is out of range\n", t);
+ goto fail;
+ }
+ sps->log2_max_poc_lsb = t + 4;
} else if (sps->poc_type == 1) { // FIXME #define
sps->delta_pic_order_always_zero_flag = get_bits1(&h->gb);
sps->offset_for_non_ref_pic = get_se_golomb(&h->gb);
@@ -402,8 +423,10 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
}
sps->ref_frame_count = get_ue_golomb_31(&h->gb);
+ if (h->avctx->codec_tag == MKTAG('S', 'M', 'V', '2'))
+ sps->ref_frame_count = FFMAX(2, sps->ref_frame_count);
if (sps->ref_frame_count > H264_MAX_PICTURE_COUNT - 2 ||
- sps->ref_frame_count >= 32U) {
+ sps->ref_frame_count > 16U) {
av_log(h->avctx, AV_LOG_ERROR,
"too many reference frames %d\n", sps->ref_frame_count);
goto fail;
@@ -426,11 +449,6 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->mb_aff = 0;
sps->direct_8x8_inference_flag = get_bits1(&h->gb);
- if (!sps->frame_mbs_only_flag && !sps->direct_8x8_inference_flag) {
- av_log(h->avctx, AV_LOG_ERROR,
- "This stream was generated by a broken encoder, invalid 8x8 inference\n");
- goto fail;
- }
#ifndef ALLOW_INTERLACE
if (sps->mb_aff)
@@ -443,6 +461,8 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
unsigned int crop_right = get_ue_golomb(&h->gb);
unsigned int crop_top = get_ue_golomb(&h->gb);
unsigned int crop_bottom = get_ue_golomb(&h->gb);
+ int width = 16 * sps->mb_width;
+ int height = 16 * sps->mb_height * (2 - sps->frame_mbs_only_flag);
if (h->avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) {
av_log(h->avctx, AV_LOG_DEBUG, "discarding sps cropping, original "
@@ -469,16 +489,15 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
crop_left);
}
- if (INT_MAX / step_x <= crop_left ||
- INT_MAX / step_x - crop_left <= crop_right ||
- 16 * sps->mb_width <= step_x * (crop_left + crop_right) ||
- INT_MAX / step_y <= crop_top ||
- INT_MAX / step_y - crop_top <= crop_bottom ||
- 16 * sps->mb_height <= step_y * (crop_top + crop_bottom)) {
- av_log(h->avctx, AV_LOG_WARNING, "Invalid crop parameters\n");
- if (h->avctx->err_recognition & AV_EF_EXPLODE)
- goto fail;
- crop_left = crop_right = crop_top = crop_bottom = 0;
+ if (crop_left > (unsigned)INT_MAX / 4 / step_x ||
+ crop_right > (unsigned)INT_MAX / 4 / step_x ||
+ crop_top > (unsigned)INT_MAX / 4 / step_y ||
+ crop_bottom> (unsigned)INT_MAX / 4 / step_y ||
+ (crop_left + crop_right ) * step_x >= width ||
+ (crop_top + crop_bottom) * step_y >= height
+ ) {
+ av_log(h->avctx, AV_LOG_ERROR, "crop values invalid %d %d %d %d / %d %d\n", crop_left, crop_right, crop_top, crop_bottom, width, height);
+ goto fail;
}
sps->crop_left = crop_left * step_x;
@@ -497,7 +516,14 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->vui_parameters_present_flag = get_bits1(&h->gb);
if (sps->vui_parameters_present_flag) {
int ret = decode_vui_parameters(h, sps);
- if (ret < 0 && h->avctx->err_recognition & AV_EF_EXPLODE)
+ if (ret < 0)
+ goto fail;
+ }
+
+ if (get_bits_left(&h->gb) < 0) {
+ av_log(h->avctx, ignore_truncation ? AV_LOG_WARNING : AV_LOG_ERROR,
+ "Overread %s by %d bits\n", sps->vui_parameters_present_flag ? "VUI" : "SPS", -get_bits_left(&h->gb));
+ if (!ignore_truncation)
goto fail;
}
@@ -507,7 +533,7 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
if (h->avctx->debug & FF_DEBUG_PICT_INFO) {
static const char csp[4][5] = { "Gray", "420", "422", "444" };
av_log(h->avctx, AV_LOG_DEBUG,
- "sps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %"PRId32"/%"PRId32"\n",
+ "sps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %"PRId32"/%"PRId32" b%d reo:%d\n",
sps_id, sps->profile_idc, sps->level_idc,
sps->poc_type,
sps->ref_frame_count,
@@ -519,13 +545,15 @@ int ff_h264_decode_seq_parameter_set(H264Context *h)
sps->vui_parameters_present_flag ? "VUI" : "",
csp[sps->chroma_format_idc],
sps->timing_info_present_flag ? sps->num_units_in_tick : 0,
- sps->timing_info_present_flag ? sps->time_scale : 0);
+ sps->timing_info_present_flag ? sps->time_scale : 0,
+ sps->bit_depth_luma,
+ sps->bitstream_restriction_flag ? sps->num_reorder_frames : -1
+ );
}
sps->new = 1;
av_free(h->sps_buffers[sps_id]);
h->sps_buffers[sps_id] = sps;
- h->sps = *sps;
return 0;
@@ -543,6 +571,21 @@ static void build_qp_table(PPS *pps, int t, int index, const int depth)
ff_h264_chroma_qp[depth - 8][av_clip(i + index, 0, max_qp)];
}
+static int more_rbsp_data_in_pps(H264Context *h, PPS *pps)
+{
+ const SPS *sps = h->sps_buffers[pps->sps_id];
+ int profile_idc = sps->profile_idc;
+
+ if ((profile_idc == 66 || profile_idc == 77 ||
+ profile_idc == 88) && (sps->constraint_set_flags & 7)) {
+ av_log(h->avctx, AV_LOG_VERBOSE,
+ "Current profile doesn't provide more RBSP data in PPS, skipping\n");
+ return 0;
+ }
+
+ return 1;
+}
+
int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length)
{
const SPS *sps;
@@ -568,10 +611,15 @@ int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length)
goto fail;
}
sps = h->sps_buffers[pps->sps_id];
-
- if (sps->bit_depth_luma > 10) {
+ if (sps->bit_depth_luma > 14) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "Invalid luma bit depth=%d\n",
+ sps->bit_depth_luma);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ } else if (sps->bit_depth_luma == 11 || sps->bit_depth_luma == 13) {
av_log(h->avctx, AV_LOG_ERROR,
- "Unimplemented luma bit depth=%d (max=10)\n",
+ "Unimplemented luma bit depth=%d\n",
sps->bit_depth_luma);
ret = AVERROR_PATCHWELCOME;
goto fail;
@@ -643,8 +691,7 @@ int ff_h264_decode_picture_parameter_set(H264Context *h, int bit_length)
sizeof(pps->scaling_matrix8));
bits_left = bit_length - get_bits_count(&h->gb);
- if (bits_left && (bits_left > 8 ||
- show_bits(&h->gb, bits_left) != 1 << (bits_left - 1))) {
+ if (bits_left > 0 && more_rbsp_data_in_pps(h, pps)) {
pps->transform_8x8_mode = get_bits1(&h->gb);
decode_scaling_matrices(h, h->sps_buffers[pps->sps_id], pps, 0,
pps->scaling_matrix4, pps->scaling_matrix8);
diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index 2ddbdb7052..379fb26a1a 100644
--- a/libavcodec/h264_refs.c
+++ b/libavcodec/h264_refs.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... reference picture handling
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "internal.h"
#include "avcodec.h"
#include "h264.h"
@@ -79,16 +80,18 @@ static int build_def_list(H264Ref *def, int def_len,
int i[2] = { 0 };
int index = 0;
- while ((i[0] < len || i[1] < len) && index < def_len) {
+ while (i[0] < len || i[1] < len) {
while (i[0] < len && !(in[i[0]] && (in[i[0]]->reference & sel)))
i[0]++;
while (i[1] < len && !(in[i[1]] && (in[i[1]]->reference & (sel ^ 3))))
i[1]++;
- if (i[0] < len && index < def_len) {
+ if (i[0] < len) {
+ av_assert0(index < def_len);
in[i[0]]->pic_id = is_long ? i[0] : in[i[0]]->frame_num;
split_field_copy(&def[index++], in[i[0]++], sel, 1);
}
- if (i[1] < len && index < def_len) {
+ if (i[1] < len) {
+ av_assert0(index < def_len);
in[i[1]]->pic_id = is_long ? i[1] : in[i[1]]->frame_num;
split_field_copy(&def[index++], in[i[1]++], sel ^ 3, 0);
}
@@ -136,13 +139,14 @@ int ff_h264_fill_default_ref_list(H264Context *h, H264SliceContext *sl)
for (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);
- assert(len <= 32);
+ av_assert0(len <= 32);
len = build_def_list(h->default_ref_list[list], FF_ARRAY_ELEMS(h->default_ref_list[0]),
sorted, len, 0, h->picture_structure);
len += build_def_list(h->default_ref_list[list] + len,
FF_ARRAY_ELEMS(h->default_ref_list[0]) - len,
h->long_ref, 16, 1, h->picture_structure);
+ av_assert0(len <= 32);
if (len < sl->ref_count[list])
memset(&h->default_ref_list[list][len], 0, sizeof(H264Ref) * (sl->ref_count[list] - len));
@@ -163,6 +167,7 @@ int ff_h264_fill_default_ref_list(H264Context *h, H264SliceContext *sl)
len += build_def_list(h->default_ref_list[0] + len,
FF_ARRAY_ELEMS(h->default_ref_list[0]) - len,
h-> long_ref, 16, 1, h->picture_structure);
+ av_assert0(len <= 32);
if (len < sl->ref_count[0])
memset(&h->default_ref_list[0][len], 0, sizeof(H264Ref) * (sl->ref_count[0] - len));
@@ -170,16 +175,16 @@ int ff_h264_fill_default_ref_list(H264Context *h, H264SliceContext *sl)
#ifdef TRACE
for (i = 0; i < sl->ref_count[0]; i++) {
ff_tlog(h->avctx, "List0: %s fn:%d 0x%p\n",
- (h->default_ref_list[0][i].long_ref ? "LT" : "ST"),
+ h->default_ref_list[0][i].parent ? (h->default_ref_list[0][i].parent->long_ref ? "LT" : "ST") : "NULL",
h->default_ref_list[0][i].pic_id,
- h->default_ref_list[0][i].f->data[0]);
+ h->default_ref_list[0][i].parent ? h->default_ref_list[0][i].parent->f->data[0] : 0);
}
if (sl->slice_type_nos == AV_PICTURE_TYPE_B) {
for (i = 0; i < sl->ref_count[1]; i++) {
ff_tlog(h->avctx, "List1: %s fn:%d 0x%p\n",
- (h->default_ref_list[1][i].long_ref ? "LT" : "ST"),
+ h->default_ref_list[1][i].parent ? (h->default_ref_list[1][i].parent->long_ref ? "LT" : "ST") : "NULL",
h->default_ref_list[1][i].pic_id,
- h->default_ref_list[1][i].f->data[0]);
+ h->default_ref_list[1][i].parent ? h->default_ref_list[1][i].parent->f->data[0] : 0);
}
}
#endif
@@ -324,13 +329,19 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h, H264SliceContext *sl)
}
for (list = 0; list < sl->list_count; list++) {
for (index = 0; index < sl->ref_count[list]; index++) {
- if (!sl->ref_list[list][index].parent) {
- av_log(h->avctx, AV_LOG_ERROR, "Missing reference picture\n");
- if (h->default_ref_list[list][0].parent)
+ 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[list][0].poc);
+ for (i = 0; i < FF_ARRAY_ELEMS(h->last_pocs); i++)
+ h->last_pocs[i] = INT_MIN;
+ if (h->default_ref_list[list][0].parent
+ && !(!FIELD_PICTURE(h) && (h->default_ref_list[list][0].reference&3) != 3))
sl->ref_list[list][index] = h->default_ref_list[list][0];
else
return -1;
}
+ av_assert0(av_buffer_get_ref_count(sl->ref_list[list][index].parent->f->buf[0]) > 0);
}
}
@@ -340,7 +351,7 @@ int ff_h264_decode_ref_pic_list_reordering(H264Context *h, H264SliceContext *sl)
void ff_h264_fill_mbaff_ref_list(H264Context *h, H264SliceContext *sl)
{
int list, i, j;
- for (list = 0; list < sl->list_count; list++) { //FIXME try list_count
+ for (list = 0; list < sl->list_count; list++) {
for (i = 0; i < sl->ref_count[list]; i++) {
H264Ref *frame = &sl->ref_list[list][i];
H264Ref *field = &sl->ref_list[list][16 + 2 * i];
@@ -486,11 +497,23 @@ void ff_h264_remove_all_refs(H264Context *h)
}
assert(h->long_ref_count == 0);
+ if (h->short_ref_count && !h->last_pic_for_ec.f->data[0]) {
+ ff_h264_unref_picture(h, &h->last_pic_for_ec);
+ ff_h264_ref_picture(h, &h->last_pic_for_ec, h->short_ref[0]);
+ }
+
for (i = 0; i < h->short_ref_count; i++) {
unreference_pic(h, h->short_ref[i], 0);
h->short_ref[i] = NULL;
}
h->short_ref_count = 0;
+
+ memset(h->default_ref_list, 0, sizeof(h->default_ref_list));
+ for (i = 0; i < h->nb_slice_ctx; i++) {
+ H264SliceContext *sl = &h->slice_ctx[i];
+ sl->list_count = sl->ref_count[0] = sl->ref_count[1] = 0;
+ memset(sl->ref_list, 0, sizeof(sl->ref_list));
+ }
}
/**
@@ -532,8 +555,11 @@ static int check_opcodes(MMCO *mmco1, MMCO *mmco2, int n_mmcos)
int i;
for (i = 0; i < n_mmcos; i++) {
- if (mmco1[i].opcode != mmco2[i].opcode)
+ if (mmco1[i].opcode != mmco2[i].opcode) {
+ av_log(NULL, AV_LOG_ERROR, "MMCO opcode [%d, %d] at %d mismatches between slices\n",
+ mmco1[i].opcode, mmco2[i].opcode, i);
return -1;
+ }
}
return 0;
@@ -544,10 +570,8 @@ int ff_generate_sliding_window_mmcos(H264Context *h, int first_slice)
MMCO mmco_temp[MAX_MMCO_COUNT], *mmco = first_slice ? h->mmco : mmco_temp;
int mmco_index = 0, i = 0;
- assert(h->long_ref_count + h->short_ref_count <= h->sps.ref_frame_count);
-
if (h->short_ref_count &&
- h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count &&
+ h->long_ref_count + h->short_ref_count >= h->sps.ref_frame_count &&
!(FIELD_PICTURE(h) && !h->first_field && h->cur_pic_ptr->reference)) {
mmco[0].opcode = MMCO_SHORT2UNUSED;
mmco[0].short_pic_num = h->short_ref[h->short_ref_count - 1]->frame_num;
@@ -566,8 +590,8 @@ int ff_generate_sliding_window_mmcos(H264Context *h, int first_slice)
(mmco_index != h->mmco_index ||
(i = check_opcodes(h->mmco, mmco_temp, mmco_index)))) {
av_log(h->avctx, AV_LOG_ERROR,
- "Inconsistent MMCO state between slices [%d, %d, %d]\n",
- mmco_index, h->mmco_index, i);
+ "Inconsistent MMCO state between slices [%d, %d]\n",
+ mmco_index, h->mmco_index);
return AVERROR_INVALIDDATA;
}
return 0;
@@ -576,6 +600,7 @@ int ff_generate_sliding_window_mmcos(H264Context *h, int first_slice)
int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
{
int i, av_uninit(j);
+ int pps_count;
int current_ref_assigned = 0, err = 0;
H264Picture *av_uninit(pic);
@@ -596,7 +621,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
if (mmco[i].opcode != MMCO_SHORT2LONG ||
!h->long_ref[mmco[i].long_arg] ||
h->long_ref[mmco[i].long_arg]->frame_num != frame_num) {
- av_log(h->avctx, AV_LOG_ERROR, "mmco: unref short failure\n");
+ av_log(h->avctx, h->short_ref_count ? AV_LOG_ERROR : AV_LOG_DEBUG, "mmco: unref short failure\n");
err = AVERROR_INVALIDDATA;
}
continue;
@@ -637,10 +662,21 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
* Report the problem and keep the pair where it is,
* and mark this field valid.
*/
- if (h->short_ref[0] == h->cur_pic_ptr)
+ if (h->short_ref[0] == h->cur_pic_ptr) {
+ av_log(h->avctx, AV_LOG_ERROR, "mmco: cannot assign current picture to short and long at the same time\n");
remove_short_at_index(h, 0);
+ }
if (h->long_ref[mmco[i].long_arg] != h->cur_pic_ptr) {
+ if (h->cur_pic_ptr->long_ref) {
+ for(j=0; j<16; j++) {
+ if(h->long_ref[j] == h->cur_pic_ptr) {
+ remove_long(h, j, 0);
+ av_log(h->avctx, AV_LOG_ERROR, "mmco: cannot assign current picture to 2 long term references\n");
+ }
+ }
+ }
+ av_assert0(!h->cur_pic_ptr->long_ref);
remove_long(h, mmco[i].long_arg, 0);
h->long_ref[mmco[i].long_arg] = h->cur_pic_ptr;
@@ -668,6 +704,8 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
h->frame_num = h->cur_pic_ptr->frame_num = 0;
h->mmco_reset = 1;
h->cur_pic_ptr->mmco_reset = 1;
+ for (j = 0; j < MAX_DELAYED_PIC_COUNT; j++)
+ h->last_pocs[j] = INT_MIN;
break;
default: assert(0);
}
@@ -682,7 +720,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
*/
if (h->short_ref_count && h->short_ref[0] == h->cur_pic_ptr) {
/* Just mark the second field valid */
- h->cur_pic_ptr->reference = PICT_FRAME;
+ h->cur_pic_ptr->reference |= h->picture_structure;
} else if (h->cur_pic_ptr->long_ref) {
av_log(h->avctx, AV_LOG_ERROR, "illegal short term reference "
"assignment for second field "
@@ -706,8 +744,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
}
}
- if (h->long_ref_count + h->short_ref_count -
- (h->short_ref[0] == h->cur_pic_ptr) > h->sps.ref_frame_count) {
+ if (h->long_ref_count + h->short_ref_count > FFMAX(h->sps.ref_frame_count, 1)) {
/* We have too many reference frames, probably due to corrupted
* stream. Need to discard one frame. Prevents overrun of the
@@ -732,8 +769,32 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count)
}
}
+ for (i = 0; i<h->short_ref_count; i++) {
+ pic = h->short_ref[i];
+ if (pic->invalid_gap) {
+ int d = av_mod_uintp2(h->cur_pic_ptr->frame_num - pic->frame_num, h->sps.log2_max_frame_num);
+ if (d > h->sps.ref_frame_count)
+ remove_short(h, pic->frame_num, 0);
+ }
+ }
+
print_short_term(h);
print_long_term(h);
+
+ pps_count = 0;
+ for (i = 0; i < FF_ARRAY_ELEMS(h->pps_buffers); i++)
+ pps_count += !!h->pps_buffers[i];
+
+ if ( err >= 0
+ && h->long_ref_count==0
+ && (h->short_ref_count<=2 || h->pps.ref_count[0] <= 1 && h->pps.ref_count[1] <= 1 && pps_count == 1)
+ && h->pps.ref_count[0]<=2 + (h->picture_structure != PICT_FRAME) + (2*!h->has_recovery_point)
+ && h->cur_pic_ptr->f->pict_type == AV_PICTURE_TYPE_I){
+ h->cur_pic_ptr->recovered |= 1;
+ if(!h->avctx->has_b_frames)
+ h->frame_recovered |= FRAME_RECOVERED_SEI;
+ }
+
return (h->avctx->err_recognition & AV_EF_EXPLODE) ? err : 0;
}
@@ -741,7 +802,7 @@ int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb,
int first_slice)
{
int i, ret;
- MMCO mmco_temp[MAX_MMCO_COUNT], *mmco = first_slice ? h->mmco : mmco_temp;
+ MMCO mmco_temp[MAX_MMCO_COUNT], *mmco = mmco_temp;
int mmco_index = 0;
if (h->nal_unit_type == NAL_IDR_SLICE) { // FIXME fields
@@ -807,6 +868,7 @@ int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb,
}
if (first_slice && mmco_index != -1) {
+ memcpy(h->mmco, mmco_temp, sizeof(h->mmco));
h->mmco_index = mmco_index;
} else if (!first_slice && mmco_index >= 0 &&
(mmco_index != h->mmco_index ||
diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index 52ff2ff4bb..8e1697a31e 100644
--- a/libavcodec/h264_sei.c
+++ b/libavcodec/h264_sei.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... sei decoding
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,14 +46,20 @@ void ff_h264_reset_sei(H264Context *h)
static int decode_picture_timing(H264Context *h)
{
- if (h->sps.nal_hrd_parameters_present_flag ||
- h->sps.vcl_hrd_parameters_present_flag) {
- h->sei_cpb_removal_delay = get_bits(&h->gb,
- h->sps.cpb_removal_delay_length);
- h->sei_dpb_output_delay = get_bits(&h->gb,
- h->sps.dpb_output_delay_length);
+ SPS *sps = &h->sps;
+ int i;
+
+ for (i = 0; i<MAX_SPS_COUNT; i++)
+ if (!sps->log2_max_frame_num && h->sps_buffers[i])
+ sps = h->sps_buffers[i];
+
+ if (sps->nal_hrd_parameters_present_flag || sps->vcl_hrd_parameters_present_flag) {
+ h->sei_cpb_removal_delay = get_bits_long(&h->gb,
+ sps->cpb_removal_delay_length);
+ h->sei_dpb_output_delay = get_bits_long(&h->gb,
+ sps->dpb_output_delay_length);
}
- if (h->sps.pic_struct_present_flag) {
+ if (sps->pic_struct_present_flag) {
unsigned int i, num_clock_ts;
h->sei_pic_struct = get_bits(&h->gb, 4);
@@ -89,9 +95,9 @@ static int decode_picture_timing(H264Context *h)
}
}
}
- if (h->sps.time_offset_length > 0)
+ if (sps->time_offset_length > 0)
skip_bits(&h->gb,
- h->sps.time_offset_length); /* time_offset */
+ sps->time_offset_length); /* time_offset */
}
}
@@ -102,6 +108,43 @@ static int decode_picture_timing(H264Context *h)
return 0;
}
+static int decode_user_data_itu_t_t35(H264Context *h, int size)
+{
+ uint32_t user_identifier;
+ int dtg_active_format;
+
+ if (size < 7)
+ return -1;
+ size -= 7;
+
+ skip_bits(&h->gb, 8); // country_code
+ skip_bits(&h->gb, 16); // provider_code
+ user_identifier = get_bits_long(&h->gb, 32);
+
+ switch (user_identifier) {
+ case 0x44544731: // "DTG1" - AFD_data
+ if (size < 1)
+ return -1;
+ skip_bits(&h->gb, 1);
+ if (get_bits(&h->gb, 1)) {
+ skip_bits(&h->gb, 6);
+ if (size < 2)
+ return -1;
+ skip_bits(&h->gb, 4);
+ dtg_active_format = get_bits(&h->gb, 4);
+ h->avctx->dtg_active_format = dtg_active_format;
+ } else {
+ skip_bits(&h->gb, 6);
+ }
+ break;
+ default:
+ skip_bits(&h->gb, size * 8);
+ break;
+ }
+
+ return 0;
+}
+
static int decode_unregistered_user_data(H264Context *h, int size)
{
uint8_t user_data[16 + 256];
@@ -117,6 +160,8 @@ static int decode_unregistered_user_data(H264Context *h, int size)
e = sscanf(user_data + 16, "x264 - core %d", &build);
if (e == 1 && build > 0)
h->x264_build = build;
+ if (e == 1 && build == 1 && !strncmp(user_data+16, "x264 - core 0000", 16))
+ h->x264_build = 67;
if (h->avctx->debug & FF_DEBUG_BUGS)
av_log(h->avctx, AV_LOG_DEBUG, "user data:\"%s\"\n", user_data + 16);
@@ -136,6 +181,11 @@ static int decode_recovery_point(H264Context *h)
* 2b changing_slice_group_idc */
skip_bits(&h->gb, 4);
+ if (h->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(h->avctx, AV_LOG_DEBUG, "sei_recovery_frame_cnt: %d\n", h->sei_recovery_frame_cnt);
+
+ h->has_recovery_point = 1;
+
return 0;
}
@@ -157,7 +207,7 @@ static int decode_buffering_period(H264Context *h)
if (sps->nal_hrd_parameters_present_flag) {
for (sched_sel_idx = 0; sched_sel_idx < sps->cpb_cnt; sched_sel_idx++) {
h->initial_cpb_removal_delay[sched_sel_idx] =
- get_bits(&h->gb, sps->initial_cpb_removal_delay_length);
+ get_bits_long(&h->gb, sps->initial_cpb_removal_delay_length);
// initial_cpb_removal_delay_offset
skip_bits(&h->gb, sps->initial_cpb_removal_delay_length);
}
@@ -165,7 +215,7 @@ static int decode_buffering_period(H264Context *h)
if (sps->vcl_hrd_parameters_present_flag) {
for (sched_sel_idx = 0; sched_sel_idx < sps->cpb_cnt; sched_sel_idx++) {
h->initial_cpb_removal_delay[sched_sel_idx] =
- get_bits(&h->gb, sps->initial_cpb_removal_delay_length);
+ get_bits_long(&h->gb, sps->initial_cpb_removal_delay_length);
// initial_cpb_removal_delay_offset
skip_bits(&h->gb, sps->initial_cpb_removal_delay_length);
}
@@ -177,12 +227,16 @@ static int decode_buffering_period(H264Context *h)
static int decode_frame_packing_arrangement(H264Context *h)
{
- get_ue_golomb(&h->gb); // frame_packing_arrangement_id
- h->sei_frame_packing_present = !get_bits1(&h->gb);
+ h->sei_fpa.frame_packing_arrangement_id = get_ue_golomb(&h->gb);
+ h->sei_fpa.frame_packing_arrangement_cancel_flag = get_bits1(&h->gb);
+ h->sei_frame_packing_present = !h->sei_fpa.frame_packing_arrangement_cancel_flag;
if (h->sei_frame_packing_present) {
+ h->sei_fpa.frame_packing_arrangement_type =
h->frame_packing_arrangement_type = get_bits(&h->gb, 7);
+ h->sei_fpa.quincunx_sampling_flag =
h->quincunx_subsampling = get_bits1(&h->gb);
+ h->sei_fpa.content_interpretation_type =
h->content_interpretation_type = get_bits(&h->gb, 6);
// the following skips: spatial_flipping_flag, frame0_flipped_flag,
@@ -193,10 +247,19 @@ static int decode_frame_packing_arrangement(H264Context *h)
if (!h->quincunx_subsampling && h->frame_packing_arrangement_type != 5)
skip_bits(&h->gb, 16); // frame[01]_grid_position_[xy]
skip_bits(&h->gb, 8); // frame_packing_arrangement_reserved_byte
- get_ue_golomb(&h->gb); // frame_packing_arrangement_repetition_period
+ h->sei_fpa.frame_packing_arrangement_repetition_period = get_ue_golomb(&h->gb) /* frame_packing_arrangement_repetition_period */;
}
skip_bits1(&h->gb); // frame_packing_arrangement_extension_flag
+ if (h->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(h->avctx, AV_LOG_DEBUG, "SEI FPA %d %d %d %d %d %d\n",
+ h->sei_fpa.frame_packing_arrangement_id,
+ h->sei_fpa.frame_packing_arrangement_cancel_flag,
+ h->sei_fpa.frame_packing_arrangement_type,
+ h->sei_fpa.quincunx_sampling_flag,
+ h->sei_fpa.content_interpretation_type,
+ h->sei_fpa.frame_packing_arrangement_repetition_period);
+
return 0;
}
@@ -218,30 +281,33 @@ static int decode_display_orientation(H264Context *h)
int ff_h264_decode_sei(H264Context *h)
{
- while (get_bits_left(&h->gb) > 16) {
- int size = 0;
+ while (get_bits_left(&h->gb) > 16 && show_bits(&h->gb, 16)) {
int type = 0;
+ unsigned size = 0;
+ unsigned next;
int ret = 0;
- int last = 0;
- while (get_bits_left(&h->gb) >= 8 &&
- (last = get_bits(&h->gb, 8)) == 255) {
- type += 255;
- }
- type += last;
+ do {
+ if (get_bits_left(&h->gb) < 8)
+ return AVERROR_INVALIDDATA;
+ type += show_bits(&h->gb, 8);
+ } while (get_bits(&h->gb, 8) == 255);
- last = 0;
- while (get_bits_left(&h->gb) >= 8 &&
- (last = get_bits(&h->gb, 8)) == 255) {
- size += 255;
- }
- size += last;
+ do {
+ if (get_bits_left(&h->gb) < 8)
+ return AVERROR_INVALIDDATA;
+ size += show_bits(&h->gb, 8);
+ } while (get_bits(&h->gb, 8) == 255);
+
+ if (h->avctx->debug&FF_DEBUG_STARTCODE)
+ av_log(h->avctx, AV_LOG_DEBUG, "SEI %d len:%d\n", type, size);
if (size > get_bits_left(&h->gb) / 8) {
- av_log(h->avctx, AV_LOG_ERROR, "SEI type %d truncated at %d\n",
- type, get_bits_left(&h->gb));
+ av_log(h->avctx, AV_LOG_ERROR, "SEI type %d size %d truncated at %d\n",
+ type, 8*size, get_bits_left(&h->gb));
return AVERROR_INVALIDDATA;
}
+ next = get_bits_count(&h->gb) + 8 * size;
switch (type) {
case SEI_TYPE_PIC_TIMING: // Picture timing SEI
@@ -249,6 +315,10 @@ int ff_h264_decode_sei(H264Context *h)
if (ret < 0)
return ret;
break;
+ case SEI_TYPE_USER_DATA_ITU_T_T35:
+ if (decode_user_data_itu_t_t35(h, size) < 0)
+ return -1;
+ break;
case SEI_TYPE_USER_DATA_UNREGISTERED:
ret = decode_unregistered_user_data(h, size);
if (ret < 0)
@@ -276,8 +346,8 @@ int ff_h264_decode_sei(H264Context *h)
break;
default:
av_log(h->avctx, AV_LOG_DEBUG, "unknown SEI type %d\n", type);
- skip_bits(&h->gb, 8 * size);
}
+ skip_bits_long(&h->gb, next - get_bits_count(&h->gb));
// FIXME check bits here
align_get_bits(&h->gb);
@@ -285,3 +355,48 @@ int ff_h264_decode_sei(H264Context *h)
return 0;
}
+
+const char* ff_h264_sei_stereo_mode(H264Context *h)
+{
+ if (h->sei_fpa.frame_packing_arrangement_cancel_flag == 0) {
+ switch (h->sei_fpa.frame_packing_arrangement_type) {
+ case SEI_FPA_TYPE_CHECKERBOARD:
+ if (h->sei_fpa.content_interpretation_type == 2)
+ return "checkerboard_rl";
+ else
+ return "checkerboard_lr";
+ case SEI_FPA_TYPE_INTERLEAVE_COLUMN:
+ if (h->sei_fpa.content_interpretation_type == 2)
+ return "col_interleaved_rl";
+ else
+ return "col_interleaved_lr";
+ case SEI_FPA_TYPE_INTERLEAVE_ROW:
+ if (h->sei_fpa.content_interpretation_type == 2)
+ return "row_interleaved_rl";
+ else
+ return "row_interleaved_lr";
+ case SEI_FPA_TYPE_SIDE_BY_SIDE:
+ if (h->sei_fpa.content_interpretation_type == 2)
+ return "right_left";
+ else
+ return "left_right";
+ case SEI_FPA_TYPE_TOP_BOTTOM:
+ if (h->sei_fpa.content_interpretation_type == 2)
+ return "bottom_top";
+ else
+ return "top_bottom";
+ case SEI_FPA_TYPE_INTERLEAVE_TEMPORAL:
+ if (h->sei_fpa.content_interpretation_type == 2)
+ return "block_rl";
+ else
+ return "block_lr";
+ case SEI_FPA_TYPE_2D:
+ default:
+ return "mono";
+ }
+ } else if (h->sei_fpa.frame_packing_arrangement_cancel_flag == 1) {
+ return "mono";
+ } else {
+ return NULL;
+ }
+}
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 1cee6346de..738c359701 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,23 +47,27 @@
static const uint8_t rem6[QP_MAX_NUM + 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,
+ 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[QP_MAX_NUM + 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,
+ 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,
};
-static const uint8_t field_scan[16] = {
+static const uint8_t field_scan[16+1] = {
0 + 0 * 4, 0 + 1 * 4, 1 + 0 * 4, 0 + 2 * 4,
0 + 3 * 4, 1 + 1 * 4, 1 + 2 * 4, 1 + 3 * 4,
2 + 0 * 4, 2 + 1 * 4, 2 + 2 * 4, 2 + 3 * 4,
3 + 0 * 4, 3 + 1 * 4, 3 + 2 * 4, 3 + 3 * 4,
};
-static const uint8_t field_scan8x8[64] = {
+static const uint8_t field_scan8x8[64+1] = {
0 + 0 * 8, 0 + 1 * 8, 0 + 2 * 8, 1 + 0 * 8,
1 + 1 * 8, 0 + 3 * 8, 0 + 4 * 8, 1 + 2 * 8,
2 + 0 * 8, 1 + 3 * 8, 0 + 5 * 8, 0 + 6 * 8,
@@ -82,7 +86,7 @@ static const uint8_t field_scan8x8[64] = {
7 + 4 * 8, 7 + 5 * 8, 7 + 6 * 8, 7 + 7 * 8,
};
-static const uint8_t field_scan8x8_cavlc[64] = {
+static const uint8_t field_scan8x8_cavlc[64+1] = {
0 + 0 * 8, 1 + 1 * 8, 2 + 0 * 8, 0 + 7 * 8,
2 + 2 * 8, 2 + 3 * 8, 2 + 4 * 8, 3 + 3 * 8,
3 + 4 * 8, 4 + 3 * 8, 4 + 4 * 8, 5 + 3 * 8,
@@ -102,7 +106,7 @@ static const uint8_t field_scan8x8_cavlc[64] = {
};
// zigzag_scan8x8_cavlc[i] = zigzag_scan8x8[(i/4) + 16*(i%4)]
-static const uint8_t zigzag_scan8x8_cavlc[64] = {
+static const uint8_t zigzag_scan8x8_cavlc[64+1] = {
0 + 0 * 8, 1 + 1 * 8, 1 + 2 * 8, 2 + 2 * 8,
4 + 1 * 8, 0 + 5 * 8, 3 + 3 * 8, 7 + 0 * 8,
3 + 4 * 8, 1 + 7 * 8, 5 + 3 * 8, 6 + 3 * 8,
@@ -228,6 +232,10 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
if (ret < 0)
goto fail;
+ pic->crop = h->sps.crop;
+ pic->crop_top = h->sps.crop_top;
+ pic->crop_left= h->sps.crop_left;
+
if (h->avctx->hwaccel) {
const AVHWAccel *hwaccel = h->avctx->hwaccel;
av_assert0(!pic->hwaccel_picture_private);
@@ -238,6 +246,18 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
pic->hwaccel_picture_private = pic->hwaccel_priv_buf->data;
}
}
+ if (CONFIG_GRAY && !h->avctx->hwaccel && h->flags & CODEC_FLAG_GRAY && pic->f->data[2]) {
+ int h_chroma_shift, v_chroma_shift;
+ av_pix_fmt_get_chroma_sub_sample(pic->f->format,
+ &h_chroma_shift, &v_chroma_shift);
+
+ for(i=0; i<FF_CEIL_RSHIFT(h->avctx->height, v_chroma_shift); i++) {
+ memset(pic->f->data[1] + pic->f->linesize[1]*i,
+ 0x80, FF_CEIL_RSHIFT(h->avctx->width, h_chroma_shift));
+ memset(pic->f->data[2] + pic->f->linesize[2]*i,
+ 0x80, FF_CEIL_RSHIFT(h->avctx->width, h_chroma_shift));
+ }
+ }
if (!h->qscale_table_pool) {
ret = init_table_pools(h);
@@ -344,10 +364,12 @@ static void init_dequant4_coeff_table(H264Context *h)
}
}
-void h264_init_dequant_tables(H264Context *h)
+void ff_h264_init_dequant_tables(H264Context *h)
{
int i, x;
init_dequant4_coeff_table(h);
+ memset(h->dequant8_coeff, 0, sizeof(h->dequant8_coeff));
+
if (h->pps.transform_8x8_mode)
init_dequant8_coeff_table(h);
if (h->sps.transform_bypass) {
@@ -364,9 +386,9 @@ void h264_init_dequant_tables(H264Context *h)
#define IN_RANGE(a, b, size) (((a) >= (b)) && ((a) < ((b) + (size))))
#define REBASE_PICTURE(pic, new_ctx, old_ctx) \
- ((pic && pic >= old_ctx->DPB && \
- pic < old_ctx->DPB + H264_MAX_PICTURE_COUNT) ? \
- &new_ctx->DPB[pic - old_ctx->DPB] : NULL)
+ (((pic) && (pic) >= (old_ctx)->DPB && \
+ (pic) < (old_ctx)->DPB + H264_MAX_PICTURE_COUNT) ? \
+ &(new_ctx)->DPB[(pic) - (old_ctx)->DPB] : NULL)
static void copy_picture_range(H264Picture **to, H264Picture **from, int count,
H264Context *new_base,
@@ -375,9 +397,9 @@ static void copy_picture_range(H264Picture **to, H264Picture **from, int count,
int i;
for (i = 0; i < count; i++) {
- assert((IN_RANGE(from[i], old_base, sizeof(*old_base)) ||
+ av_assert1((IN_RANGE(from[i], old_base, 1) ||
IN_RANGE(from[i], old_base->DPB,
- sizeof(H264Picture) * H264_MAX_PICTURE_COUNT) ||
+ H264_MAX_PICTURE_COUNT) ||
!from[i]));
to[i] = REBASE_PICTURE(from[i], new_base, old_base);
}
@@ -404,8 +426,8 @@ static int copy_parameter_set(void **to, void **from, int count, int size)
}
#define copy_fields(to, from, start_field, end_field) \
- memcpy(&to->start_field, &from->start_field, \
- (char *)&to->end_field - (char *)&to->start_field)
+ memcpy(&(to)->start_field, &(from)->start_field, \
+ (char *)&(to)->end_field - (char *)&(to)->start_field)
static int h264_slice_header_init(H264Context *h);
@@ -417,7 +439,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
int need_reinit = 0;
int i, ret;
- if (dst == src || !h1->context_initialized)
+ if (dst == src)
return 0;
if (inited &&
@@ -428,9 +450,13 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->sps.bit_depth_luma != h1->sps.bit_depth_luma ||
h->sps.chroma_format_idc != h1->sps.chroma_format_idc ||
h->sps.colorspace != h1->sps.colorspace)) {
+
need_reinit = 1;
}
+ /* copy block_offset since frame_start may not be called */
+ memcpy(h->block_offset, h1->block_offset, sizeof(h->block_offset));
+
// SPS/PPS
if ((ret = copy_parameter_set((void **)h->sps_buffers,
(void **)h1->sps_buffers,
@@ -452,11 +478,12 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->mb_stride = h1->mb_stride;
h->b_stride = h1->b_stride;
- if ((err = h264_slice_header_init(h)) < 0) {
- av_log(h->avctx, AV_LOG_ERROR, "h264_slice_header_init() failed");
- return err;
+ if (h->context_initialized || h1->context_initialized) {
+ if ((err = h264_slice_header_init(h)) < 0) {
+ av_log(h->avctx, AV_LOG_ERROR, "h264_slice_header_init() failed");
+ return err;
+ }
}
-
/* copy block_offset since frame_start may not be called */
memcpy(h->block_offset, h1->block_offset, sizeof(h->block_offset));
}
@@ -494,6 +521,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
// extradata/NAL handling
h->is_avc = h1->is_avc;
h->nal_length_size = h1->nal_length_size;
+ h->x264_build = h1->x264_build;
// Dequantization matrices
// FIXME these are big - can they be only copied when PPS changes?
@@ -520,7 +548,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
copy_picture_range(h->delayed_pic, h1->delayed_pic,
MAX_DELAYED_PIC_COUNT + 2, h, h1);
- h->last_slice_type = h1->last_slice_type;
+ h->frame_recovered = h1->frame_recovered;
if (!h->cur_pic_ptr)
return 0;
@@ -534,7 +562,6 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
h->prev_frame_num = h->frame_num;
h->recovery_frame = h1->recovery_frame;
- h->frame_recovered = h1->frame_recovered;
return err;
}
@@ -544,6 +571,17 @@ static int h264_frame_start(H264Context *h)
H264Picture *pic;
int i, ret;
const int pixel_shift = h->pixel_shift;
+ int c[4] = {
+ 1<<(h->sps.bit_depth_luma-1),
+ 1<<(h->sps.bit_depth_chroma-1),
+ 1<<(h->sps.bit_depth_chroma-1),
+ -1
+ };
+
+ 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;
+ }
release_unused_pictures(h, 1);
h->cur_pic_ptr = NULL;
@@ -558,6 +596,7 @@ static int h264_frame_start(H264Context *h)
pic->reference = h->droppable ? 0 : h->picture_structure;
pic->f->coded_picture_number = h->coded_picture_number++;
pic->field_picture = h->picture_structure != PICT_FRAME;
+
/*
* Zero key_frame here; IDR markings per slice in frame or fields are ORed
* in later.
@@ -566,17 +605,34 @@ static int h264_frame_start(H264Context *h)
pic->f->key_frame = 0;
pic->mmco_reset = 0;
pic->recovered = 0;
+ pic->invalid_gap = 0;
+ pic->sei_recovery_frame_cnt = h->sei_recovery_frame_cnt;
if ((ret = alloc_picture(h, pic)) < 0)
return ret;
+ if(!h->frame_recovered && !h->avctx->hwaccel &&
+ !(h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU))
+ avpriv_color_frame(pic->f, c);
h->cur_pic_ptr = pic;
ff_h264_unref_picture(h, &h->cur_pic);
+ if (CONFIG_ERROR_RESILIENCE) {
+ ff_h264_set_erpic(&h->slice_ctx[0].er.cur_pic, NULL);
+ }
+
if ((ret = ff_h264_ref_picture(h, &h->cur_pic, h->cur_pic_ptr)) < 0)
return ret;
- if (CONFIG_ERROR_RESILIENCE && h->enable_er)
+ for (i = 0; i < h->nb_slice_ctx; i++) {
+ h->slice_ctx[i].linesize = h->cur_pic_ptr->f->linesize[0];
+ h->slice_ctx[i].uvlinesize = h->cur_pic_ptr->f->linesize[1];
+ }
+
+ if (CONFIG_ERROR_RESILIENCE && h->enable_er) {
ff_er_frame_start(&h->slice_ctx[0].er);
+ ff_h264_set_erpic(&h->slice_ctx[0].er.last_pic, NULL);
+ ff_h264_set_erpic(&h->slice_ctx[0].er.next_pic, NULL);
+ }
for (i = 0; i < 16; i++) {
h->block_offset[i] = (4 * ((scan8[i] - scan8[0]) & 7) << pixel_shift) + 4 * pic->f->linesize[0] * ((scan8[i] - scan8[0]) >> 3);
@@ -589,11 +645,6 @@ static int h264_frame_start(H264Context *h)
h->block_offset[48 + 32 + i] = (4 * ((scan8[i] - scan8[0]) & 7) << pixel_shift) + 8 * pic->f->linesize[1] * ((scan8[i] - scan8[0]) >> 3);
}
- /* Some macroblocks can be accessed before they're available in case
- * of lost slices, MBAFF or threading. */
- memset(h->slice_table, -1,
- (h->mb_height * h->mb_stride - 1) * sizeof(*h->slice_table));
-
/* We mark the current picture as non-reference after allocating it, so
* that if we break out due to an error it can be released automatically
* in the next ff_mpv_frame_start().
@@ -779,13 +830,13 @@ static void init_scan_tables(H264Context *h)
{
int i;
for (i = 0; i < 16; i++) {
-#define TRANSPOSE(x) (x >> 2) | ((x << 2) & 0xF)
+#define TRANSPOSE(x) ((x) >> 2) | (((x) << 2) & 0xF)
h->zigzag_scan[i] = TRANSPOSE(zigzag_scan[i]);
h->field_scan[i] = TRANSPOSE(field_scan[i]);
#undef TRANSPOSE
}
for (i = 0; i < 64; i++) {
-#define TRANSPOSE(x) (x >> 3) | ((x & 7) << 3)
+#define TRANSPOSE(x) ((x) >> 3) | (((x) & 7) << 3)
h->zigzag_scan8x8[i] = TRANSPOSE(ff_zigzag_direct[i]);
h->zigzag_scan8x8_cavlc[i] = TRANSPOSE(zigzag_scan8x8_cavlc[i]);
h->field_scan8x8[i] = TRANSPOSE(field_scan8x8[i]);
@@ -793,23 +844,23 @@ static void init_scan_tables(H264Context *h)
#undef TRANSPOSE
}
if (h->sps.transform_bypass) { // FIXME same ugly
- h->zigzag_scan_q0 = zigzag_scan;
- h->zigzag_scan8x8_q0 = ff_zigzag_direct;
- h->zigzag_scan8x8_cavlc_q0 = zigzag_scan8x8_cavlc;
- h->field_scan_q0 = field_scan;
- h->field_scan8x8_q0 = field_scan8x8;
- h->field_scan8x8_cavlc_q0 = field_scan8x8_cavlc;
+ memcpy(h->zigzag_scan_q0 , zigzag_scan , sizeof(h->zigzag_scan_q0 ));
+ memcpy(h->zigzag_scan8x8_q0 , ff_zigzag_direct , sizeof(h->zigzag_scan8x8_q0 ));
+ memcpy(h->zigzag_scan8x8_cavlc_q0 , zigzag_scan8x8_cavlc , sizeof(h->zigzag_scan8x8_cavlc_q0));
+ memcpy(h->field_scan_q0 , field_scan , sizeof(h->field_scan_q0 ));
+ memcpy(h->field_scan8x8_q0 , field_scan8x8 , sizeof(h->field_scan8x8_q0 ));
+ memcpy(h->field_scan8x8_cavlc_q0 , field_scan8x8_cavlc , sizeof(h->field_scan8x8_cavlc_q0 ));
} else {
- h->zigzag_scan_q0 = h->zigzag_scan;
- h->zigzag_scan8x8_q0 = h->zigzag_scan8x8;
- h->zigzag_scan8x8_cavlc_q0 = h->zigzag_scan8x8_cavlc;
- h->field_scan_q0 = h->field_scan;
- h->field_scan8x8_q0 = h->field_scan8x8;
- h->field_scan8x8_cavlc_q0 = h->field_scan8x8_cavlc;
+ memcpy(h->zigzag_scan_q0 , h->zigzag_scan , sizeof(h->zigzag_scan_q0 ));
+ memcpy(h->zigzag_scan8x8_q0 , h->zigzag_scan8x8 , sizeof(h->zigzag_scan8x8_q0 ));
+ memcpy(h->zigzag_scan8x8_cavlc_q0 , h->zigzag_scan8x8_cavlc , sizeof(h->zigzag_scan8x8_cavlc_q0));
+ memcpy(h->field_scan_q0 , h->field_scan , sizeof(h->field_scan_q0 ));
+ memcpy(h->field_scan8x8_q0 , h->field_scan8x8 , sizeof(h->field_scan8x8_q0 ));
+ memcpy(h->field_scan8x8_cavlc_q0 , h->field_scan8x8_cavlc , sizeof(h->field_scan8x8_cavlc_q0 ));
}
}
-static enum AVPixelFormat get_pixel_format(H264Context *h)
+static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
{
#define HWACCEL_MAX (CONFIG_H264_DXVA2_HWACCEL + \
CONFIG_H264_VAAPI_HWACCEL + \
@@ -817,6 +868,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
CONFIG_H264_VDPAU_HWACCEL)
enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
const enum AVPixelFormat *choices = pix_fmts;
+ int i;
switch (h->sps.bit_depth_luma) {
case 9:
@@ -841,6 +893,28 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
else
*fmt++ = AV_PIX_FMT_YUV420P10;
break;
+ case 12:
+ if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_RGB) {
+ *fmt++ = AV_PIX_FMT_GBRP12;
+ } else
+ *fmt++ = AV_PIX_FMT_YUV444P12;
+ } else if (CHROMA422(h))
+ *fmt++ = AV_PIX_FMT_YUV422P12;
+ else
+ *fmt++ = AV_PIX_FMT_YUV420P12;
+ break;
+ case 14:
+ if (CHROMA444(h)) {
+ if (h->avctx->colorspace == AVCOL_SPC_RGB) {
+ *fmt++ = AV_PIX_FMT_GBRP14;
+ } else
+ *fmt++ = AV_PIX_FMT_YUV444P14;
+ } else if (CHROMA422(h))
+ *fmt++ = AV_PIX_FMT_YUV422P14;
+ else
+ *fmt++ = AV_PIX_FMT_YUV420P14;
+ break;
case 8:
#if CONFIG_H264_VDPAU_HWACCEL
*fmt++ = AV_PIX_FMT_VDPAU;
@@ -887,7 +961,10 @@ static enum AVPixelFormat get_pixel_format(H264Context *h)
*fmt = AV_PIX_FMT_NONE;
- return ff_get_format(h->avctx, choices);
+ for (i=0; choices[i] != AV_PIX_FMT_NONE; i++)
+ if (choices[i] == h->avctx->pix_fmt && !force_callback)
+ return choices[i];
+ return ff_thread_get_format(h->avctx, choices);
}
/* export coded and cropped frame dimensions to AVCodecContext */
@@ -897,6 +974,8 @@ static int init_dimensions(H264Context *h)
int height = h->height - (h->sps.crop_top + h->sps.crop_bottom);
int crop_present = h->sps.crop_left || h->sps.crop_top ||
h->sps.crop_right || h->sps.crop_bottom;
+ av_assert0(h->sps.crop_right + h->sps.crop_left < (unsigned)h->width);
+ av_assert0(h->sps.crop_top + h->sps.crop_bottom < (unsigned)h->height);
/* handle container cropping */
if (!crop_present &&
@@ -947,7 +1026,7 @@ static int h264_slice_header_init(H264Context *h)
if (h->x264_build < 44U)
den *= 2;
av_reduce(&h->avctx->framerate.den, &h->avctx->framerate.num,
- h->sps.num_units_in_tick, den, 1 << 30);
+ h->sps.num_units_in_tick * h->avctx->ticks_per_frame, den, 1 << 30);
}
ff_h264_free_tables(h);
@@ -959,16 +1038,30 @@ static int h264_slice_header_init(H264Context *h)
ret = ff_h264_alloc_tables(h);
if (ret < 0) {
av_log(h->avctx, AV_LOG_ERROR, "Could not allocate memory\n");
- return ret;
+ goto fail;
}
- if (h->sps.bit_depth_luma < 8 || h->sps.bit_depth_luma > 10) {
+ if (h->avctx->codec &&
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU &&
+ (h->sps.bit_depth_luma != 8 || h->sps.chroma_format_idc > 1)) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "VDPAU decoding does not support video colorspace.\n");
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ if (h->sps.bit_depth_luma < 8 || h->sps.bit_depth_luma > 14 ||
+ h->sps.bit_depth_luma == 11 || h->sps.bit_depth_luma == 13
+ ) {
av_log(h->avctx, AV_LOG_ERROR, "Unsupported bit depth %d\n",
h->sps.bit_depth_luma);
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
+ h->cur_bit_depth_luma =
h->avctx->bits_per_raw_sample = h->sps.bit_depth_luma;
+ h->cur_chroma_format_idc = h->sps.chroma_format_idc;
h->pixel_shift = h->sps.bit_depth_luma > 8;
h->chroma_format_idc = h->sps.chroma_format_idc;
h->bit_depth_luma = h->sps.bit_depth_luma;
@@ -997,7 +1090,7 @@ static int h264_slice_header_init(H264Context *h)
ret = ff_h264_slice_context_init(h, &h->slice_ctx[0]);
if (ret < 0) {
av_log(h->avctx, AV_LOG_ERROR, "context_init() failed.\n");
- return ret;
+ goto fail;
}
} else {
for (i = 0; i < h->slice_context_count; i++) {
@@ -1010,7 +1103,7 @@ static int h264_slice_header_init(H264Context *h)
if ((ret = ff_h264_slice_context_init(h, sl)) < 0) {
av_log(h->avctx, AV_LOG_ERROR, "context_init() failed.\n");
- return ret;
+ goto fail;
}
}
}
@@ -1018,6 +1111,21 @@ static int h264_slice_header_init(H264Context *h)
h->context_initialized = 1;
return 0;
+fail:
+ ff_h264_free_tables(h);
+ h->context_initialized = 0;
+ return ret;
+}
+
+static enum AVPixelFormat non_j_pixfmt(enum AVPixelFormat a)
+{
+ switch (a) {
+ case AV_PIX_FMT_YUVJ420P: return AV_PIX_FMT_YUV420P;
+ case AV_PIX_FMT_YUVJ422P: return AV_PIX_FMT_YUV422P;
+ case AV_PIX_FMT_YUVJ444P: return AV_PIX_FMT_YUV444P;
+ default:
+ return a;
+ }
}
/**
@@ -1034,22 +1142,36 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
unsigned int pps_id;
int ret;
unsigned int slice_type, tmp, i, j;
- int default_ref_list_done = 0;
int last_pic_structure, last_pic_droppable;
+ int must_reinit;
int needs_reinit = 0;
int field_pic_flag, bottom_field_flag;
+ int first_slice = sl == h->slice_ctx && !h->current_slice;
+ int frame_num, picture_structure, droppable;
+ int mb_aff_frame, last_mb_aff_frame;
+ PPS *pps;
h->qpel_put = h->h264qpel.put_h264_qpel_pixels_tab;
h->qpel_avg = h->h264qpel.avg_h264_qpel_pixels_tab;
- first_mb_in_slice = get_ue_golomb(&sl->gb);
+ first_mb_in_slice = get_ue_golomb_long(&sl->gb);
if (first_mb_in_slice == 0) { // FIXME better field boundary detection
- if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) {
- ff_h264_field_end(h, sl, 1);
+ if (h->current_slice) {
+ if (h->cur_pic_ptr && FIELD_PICTURE(h) && h->first_field) {
+ ff_h264_field_end(h, h->slice_ctx, 1);
+ h->current_slice = 0;
+ } else if (h->cur_pic_ptr && !FIELD_PICTURE(h) && !h->first_field && h->nal_unit_type == NAL_IDR_SLICE) {
+ av_log(h, AV_LOG_WARNING, "Broken frame packetizing\n");
+ ff_h264_field_end(h, h->slice_ctx, 1);
+ h->current_slice = 0;
+ ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0);
+ ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1);
+ h->cur_pic_ptr = NULL;
+ } else
+ return AVERROR_INVALIDDATA;
}
- h->current_slice = 0;
if (!h->first_field) {
if (h->cur_pic_ptr && !h->droppable) {
ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
@@ -1073,10 +1195,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
sl->slice_type_fixed = 0;
slice_type = golomb_to_pict_type[slice_type];
- if (slice_type == AV_PICTURE_TYPE_I ||
- (h->current_slice != 0 && slice_type == h->last_slice_type)) {
- default_ref_list_done = 1;
- }
+
sl->slice_type = slice_type;
sl->slice_type_nos = slice_type & 3;
@@ -1086,6 +1205,15 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
return AVERROR_INVALIDDATA;
}
+ if (
+ (h->avctx->skip_frame >= AVDISCARD_NONREF && !h->nal_ref_idc) ||
+ (h->avctx->skip_frame >= AVDISCARD_BIDIR && sl->slice_type_nos == AV_PICTURE_TYPE_B) ||
+ (h->avctx->skip_frame >= AVDISCARD_NONINTRA && sl->slice_type_nos != AV_PICTURE_TYPE_I) ||
+ (h->avctx->skip_frame >= AVDISCARD_NONKEY && h->nal_unit_type != NAL_IDR_SLICE) ||
+ h->avctx->skip_frame >= AVDISCARD_ALL) {
+ return SLICE_SKIPED;
+ }
+
// to make a few old functions happy, it's wrong though
h->pict_type = sl->slice_type;
@@ -1100,21 +1228,43 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
pps_id);
return AVERROR_INVALIDDATA;
}
- h->pps = *h->pps_buffers[pps_id];
+ if (h->au_pps_id >= 0 && pps_id != h->au_pps_id) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "PPS change from %d to %d forbidden\n",
+ h->au_pps_id, pps_id);
+ return AVERROR_INVALIDDATA;
+ }
- if (!h->sps_buffers[h->pps.sps_id]) {
+ pps = h->pps_buffers[pps_id];
+
+ if (!h->sps_buffers[pps->sps_id]) {
av_log(h->avctx, AV_LOG_ERROR,
"non-existing SPS %u referenced\n",
h->pps.sps_id);
return AVERROR_INVALIDDATA;
}
+ if (first_slice)
+ h->pps = *h->pps_buffers[pps_id];
+
+ if (pps->sps_id != h->sps.sps_id ||
+ pps->sps_id != h->current_sps_id ||
+ h->sps_buffers[pps->sps_id]->new) {
- if (h->pps.sps_id != h->sps.sps_id ||
- h->sps_buffers[h->pps.sps_id]->new) {
- h->sps_buffers[h->pps.sps_id]->new = 0;
+ if (!first_slice) {
+ av_log(h->avctx, AV_LOG_ERROR,
+ "SPS changed in the middle of the frame\n");
+ return AVERROR_INVALIDDATA;
+ }
h->sps = *h->sps_buffers[h->pps.sps_id];
+ if (h->mb_width != h->sps.mb_width ||
+ h->mb_height != h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag) ||
+ h->cur_bit_depth_luma != h->sps.bit_depth_luma ||
+ h->cur_chroma_format_idc != h->sps.chroma_format_idc
+ )
+ needs_reinit = 1;
+
if (h->bit_depth_luma != h->sps.bit_depth_luma ||
h->chroma_format_idc != h->sps.chroma_format_idc)
needs_reinit = 1;
@@ -1138,9 +1288,20 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
h->avctx->level = h->sps.level_idc;
h->avctx->refs = h->sps.ref_frame_count;
- if (h->mb_width != h->sps.mb_width ||
- h->mb_height != h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag))
- needs_reinit = 1;
+ must_reinit = (h->context_initialized &&
+ ( 16*h->sps.mb_width != h->avctx->coded_width
+ || 16*h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag) != h->avctx->coded_height
+ || h->cur_bit_depth_luma != h->sps.bit_depth_luma
+ || h->cur_chroma_format_idc != h->sps.chroma_format_idc
+ || h->mb_width != h->sps.mb_width
+ || h->mb_height != h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag)
+ ));
+ if (h->avctx->pix_fmt == AV_PIX_FMT_NONE
+ || (non_j_pixfmt(h->avctx->pix_fmt) != non_j_pixfmt(get_pixel_format(h, 0))))
+ must_reinit = 1;
+
+ if (first_slice && av_cmp_q(h->sps.sar, h->avctx->sample_aspect_ratio))
+ must_reinit = 1;
h->mb_width = h->sps.mb_width;
h->mb_height = h->sps.mb_height * (2 - h->sps.frame_mbs_only_flag);
@@ -1159,8 +1320,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
return ret;
if (h->sps.video_signal_type_present_flag) {
- h->avctx->color_range = h->sps.full_range ? AVCOL_RANGE_JPEG
- : AVCOL_RANGE_MPEG;
+ h->avctx->color_range = h->sps.full_range>0 ? AVCOL_RANGE_JPEG
+ : AVCOL_RANGE_MPEG;
if (h->sps.colour_description_present_flag) {
if (h->avctx->colorspace != h->sps.colorspace)
needs_reinit = 1;
@@ -1170,7 +1331,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
}
}
- if (h->context_initialized && needs_reinit) {
+ if (h->context_initialized &&
+ (must_reinit || needs_reinit)) {
if (sl != h->slice_ctx) {
av_log(h->avctx, AV_LOG_ERROR,
"changing width %d -> %d / height %d -> %d on "
@@ -1181,14 +1343,16 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
return AVERROR_INVALIDDATA;
}
+ av_assert1(first_slice);
+
ff_h264_flush_change(h);
- if ((ret = get_pixel_format(h)) < 0)
+ if ((ret = get_pixel_format(h, 1)) < 0)
return ret;
h->avctx->pix_fmt = ret;
av_log(h->avctx, AV_LOG_INFO, "Reinit context to %dx%d, "
- "pix_fmt: %d\n", h->width, h->height, h->avctx->pix_fmt);
+ "pix_fmt: %s\n", h->width, h->height, av_get_pix_fmt_name(h->avctx->pix_fmt));
if ((ret = h264_slice_header_init(h)) < 0) {
av_log(h->avctx, AV_LOG_ERROR,
@@ -1203,7 +1367,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
return AVERROR_PATCHWELCOME;
}
- if ((ret = get_pixel_format(h)) < 0)
+ if ((ret = get_pixel_format(h, 1)) < 0)
return ret;
h->avctx->pix_fmt = ret;
@@ -1214,40 +1378,50 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
}
}
- if (sl == h->slice_ctx && h->dequant_coeff_pps != pps_id) {
+ if (first_slice && h->dequant_coeff_pps != pps_id) {
h->dequant_coeff_pps = pps_id;
- h264_init_dequant_tables(h);
+ ff_h264_init_dequant_tables(h);
}
- h->frame_num = get_bits(&sl->gb, h->sps.log2_max_frame_num);
+ frame_num = get_bits(&sl->gb, h->sps.log2_max_frame_num);
+ if (!first_slice) {
+ if (h->frame_num != frame_num) {
+ av_log(h->avctx, AV_LOG_ERROR, "Frame num change from %d to %d\n",
+ h->frame_num, frame_num);
+ return AVERROR_INVALIDDATA;
+ }
+ }
sl->mb_mbaff = 0;
- h->mb_aff_frame = 0;
+ mb_aff_frame = 0;
+ last_mb_aff_frame = h->mb_aff_frame;
last_pic_structure = h->picture_structure;
last_pic_droppable = h->droppable;
- h->droppable = h->nal_ref_idc == 0;
+ droppable = h->nal_ref_idc == 0;
if (h->sps.frame_mbs_only_flag) {
- h->picture_structure = PICT_FRAME;
+ picture_structure = PICT_FRAME;
} else {
+ if (!h->sps.direct_8x8_inference_flag && slice_type == AV_PICTURE_TYPE_B) {
+ av_log(h->avctx, AV_LOG_ERROR, "This stream was generated by a broken encoder, invalid 8x8 inference\n");
+ return -1;
+ }
field_pic_flag = get_bits1(&sl->gb);
+
if (field_pic_flag) {
bottom_field_flag = get_bits1(&sl->gb);
- h->picture_structure = PICT_TOP_FIELD + bottom_field_flag;
+ picture_structure = PICT_TOP_FIELD + bottom_field_flag;
} else {
- h->picture_structure = PICT_FRAME;
- h->mb_aff_frame = h->sps.mb_aff;
+ picture_structure = PICT_FRAME;
+ mb_aff_frame = h->sps.mb_aff;
}
}
- sl->mb_field_decoding_flag = h->picture_structure != PICT_FRAME;
-
- if (h->current_slice != 0) {
- if (last_pic_structure != h->picture_structure ||
- last_pic_droppable != h->droppable) {
+ if (h->current_slice) {
+ if (last_pic_structure != picture_structure ||
+ last_pic_droppable != droppable ||
+ last_mb_aff_frame != mb_aff_frame) {
av_log(h->avctx, AV_LOG_ERROR,
"Changing field mode (%d -> %d) between slices is not allowed\n",
last_pic_structure, h->picture_structure);
- h->picture_structure = last_pic_structure;
- h->droppable = last_pic_droppable;
return AVERROR_INVALIDDATA;
} else if (!h->cur_pic_ptr) {
av_log(h->avctx, AV_LOG_ERROR,
@@ -1255,7 +1429,15 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
h->current_slice + 1);
return AVERROR_INVALIDDATA;
}
- } else {
+ }
+
+ h->picture_structure = picture_structure;
+ h->droppable = droppable;
+ h->frame_num = frame_num;
+ h->mb_aff_frame = mb_aff_frame;
+ sl->mb_field_decoding_flag = picture_structure != PICT_FRAME;
+
+ if (h->current_slice == 0) {
/* Shorten frame num gaps so we don't have to allocate reference
* frames just to throw them away */
if (h->frame_num != h->prev_frame_num) {
@@ -1278,17 +1460,23 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
* Here, we're using that to see if we should mark previously
* decode frames as "finished".
* We have to do that before the "dummy" in-between frame allocation,
- * since that can modify s->current_picture_ptr. */
+ * since that can modify h->cur_pic_ptr. */
if (h->first_field) {
- assert(h->cur_pic_ptr);
- assert(h->cur_pic_ptr->f->buf[0]);
+ av_assert0(h->cur_pic_ptr);
+ av_assert0(h->cur_pic_ptr->f->buf[0]);
assert(h->cur_pic_ptr->reference != DELAYED_PIC_REF);
+ /* Mark old field/frame as completed */
+ if (h->cur_pic_ptr->tf.owner == h->avctx) {
+ ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
+ last_pic_structure == PICT_BOTTOM_FIELD);
+ }
+
/* figure out if we have a complementary field pair */
if (!FIELD_PICTURE(h) || h->picture_structure == last_pic_structure) {
/* Previous field is unmatched. Don't display it, but let it
* remain for reference if marked as such. */
- if (!last_pic_droppable && last_pic_structure != PICT_FRAME) {
+ if (last_pic_structure != PICT_FRAME) {
ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
last_pic_structure == PICT_TOP_FIELD);
}
@@ -1298,7 +1486,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
* different frame_nums. Consider this field first in
* pair. Throw away previous field except for reference
* purposes. */
- if (!last_pic_droppable && last_pic_structure != PICT_FRAME) {
+ if (last_pic_structure != PICT_FRAME) {
ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
last_pic_structure == PICT_TOP_FIELD);
}
@@ -1325,11 +1513,14 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
}
}
- while (h->frame_num != h->prev_frame_num &&
+ while (h->frame_num != h->prev_frame_num && !h->first_field &&
h->frame_num != (h->prev_frame_num + 1) % (1 << h->sps.log2_max_frame_num)) {
H264Picture *prev = h->short_ref_count ? h->short_ref[0] : NULL;
av_log(h->avctx, AV_LOG_DEBUG, "Frame num gap %d %d\n",
h->frame_num, h->prev_frame_num);
+ if (!h->sps.gaps_in_frame_num_allowed_flag)
+ for(i=0; i<FF_ARRAY_ELEMS(h->last_pocs); i++)
+ h->last_pocs[i] = INT_MIN;
ret = h264_frame_start(h);
if (ret < 0) {
h->first_field = 0;
@@ -1339,6 +1530,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
h->prev_frame_num++;
h->prev_frame_num %= 1 << h->sps.log2_max_frame_num;
h->cur_pic_ptr->frame_num = h->prev_frame_num;
+ h->cur_pic_ptr->invalid_gap = !h->sps.gaps_in_frame_num_allowed_flag;
ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 0);
ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, 1);
ret = ff_generate_sliding_window_mmcos(h, 1);
@@ -1373,18 +1565,22 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
* We're using that to see whether to continue decoding in that
* frame, or to allocate a new one. */
if (h->first_field) {
- assert(h->cur_pic_ptr);
- assert(h->cur_pic_ptr->f->buf[0]);
+ av_assert0(h->cur_pic_ptr);
+ av_assert0(h->cur_pic_ptr->f->buf[0]);
assert(h->cur_pic_ptr->reference != DELAYED_PIC_REF);
/* figure out if we have a complementary field pair */
if (!FIELD_PICTURE(h) || h->picture_structure == last_pic_structure) {
/* Previous field is unmatched. Don't display it, but let it
* remain for reference if marked as such. */
+ h->missing_fields ++;
h->cur_pic_ptr = NULL;
h->first_field = FIELD_PICTURE(h);
} else {
+ h->missing_fields = 0;
if (h->cur_pic_ptr->frame_num != h->frame_num) {
+ ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,
+ h->picture_structure==PICT_BOTTOM_FIELD);
/* This and the previous field had different frame_nums.
* Consider this field first in pair. Throw away previous
* one except for reference purposes. */
@@ -1408,11 +1604,22 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
} else {
release_unused_pictures(h, 0);
}
+ /* Some macroblocks can be accessed before they're available in case
+ * of lost slices, MBAFF or threading. */
+ if (FIELD_PICTURE(h)) {
+ for(i = (h->picture_structure == PICT_BOTTOM_FIELD); i<h->mb_height; i++)
+ memset(h->slice_table + i*h->mb_stride, -1, (h->mb_stride - (i+1==h->mb_height)) * sizeof(*h->slice_table));
+ } else {
+ memset(h->slice_table, -1,
+ (h->mb_height * h->mb_stride - 1) * sizeof(*h->slice_table));
+ }
+ h->last_slice_type = -1;
}
+
h->cur_pic_ptr->frame_num = h->frame_num; // FIXME frame_num cleanup
- assert(h->mb_num == h->mb_width * h->mb_height);
+ av_assert1(h->mb_num == h->mb_width * h->mb_height);
if (first_mb_in_slice << FIELD_OR_MBAFF_PICTURE(h) >= h->mb_num ||
first_mb_in_slice >= h->mb_num) {
av_log(h->avctx, AV_LOG_ERROR, "first_mb_in_slice overflow\n");
@@ -1423,7 +1630,7 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
FIELD_OR_MBAFF_PICTURE(h);
if (h->picture_structure == PICT_BOTTOM_FIELD)
sl->resync_mb_y = sl->mb_y = sl->mb_y + 1;
- assert(sl->mb_y < h->mb_height);
+ av_assert1(sl->mb_y < h->mb_height);
if (h->picture_structure == PICT_FRAME) {
h->curr_pic_num = h->frame_num;
@@ -1458,11 +1665,14 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
ret = ff_set_ref_count(h, sl);
if (ret < 0)
return ret;
- else if (ret == 1)
- default_ref_list_done = 0;
- if (!default_ref_list_done)
+ if (slice_type != AV_PICTURE_TYPE_I &&
+ (h->current_slice == 0 ||
+ slice_type != h->last_slice_type ||
+ memcmp(h->last_ref_count, sl->ref_count, sizeof(sl->ref_count)))) {
+
ff_h264_fill_default_ref_list(h, sl);
+ }
if (sl->slice_type_nos != AV_PICTURE_TYPE_I) {
ret = ff_h264_decode_ref_pic_list_reordering(h, sl);
@@ -1569,6 +1779,8 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
if (h->avctx->skip_loop_filter >= AVDISCARD_ALL ||
(h->avctx->skip_loop_filter >= AVDISCARD_NONKEY &&
+ h->nal_unit_type != NAL_IDR_SLICE) ||
+ (h->avctx->skip_loop_filter >= AVDISCARD_NONINTRA &&
sl->slice_type_nos != AV_PICTURE_TYPE_I) ||
(h->avctx->skip_loop_filter >= AVDISCARD_BIDIR &&
sl->slice_type_nos == AV_PICTURE_TYPE_B) ||
@@ -1585,13 +1797,16 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
h->max_contexts = 1;
if (!h->single_decode_warning) {
av_log(h->avctx, AV_LOG_INFO,
- "Cannot parallelize deblocking type 1, decoding such frames in sequential order\n");
+ "Cannot parallelize slice decoding with deblocking filter type 1, decoding such frames in sequential order\n"
+ "To parallelize slice decoding you need video encoded with disable_deblocking_filter_idc set to 2 (deblock only edges that do not cross slices).\n"
+ "Setting the flags2 libavcodec option to +fast (-flags2 +fast) will disable deblocking across slices and enable parallel slice decoding "
+ "but will generate non-standard-compliant output.\n");
h->single_decode_warning = 1;
}
if (sl != h->slice_ctx) {
av_log(h->avctx, AV_LOG_ERROR,
"Deblocking switched inside frame.\n");
- return 1;
+ return SLICE_SINGLETHREAD;
}
}
}
@@ -1603,10 +1818,16 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
6 * (h->sps.bit_depth_luma - 8);
h->last_slice_type = slice_type;
+ memcpy(h->last_ref_count, sl->ref_count, sizeof(h->last_ref_count));
sl->slice_num = ++h->current_slice;
- if (sl->slice_num >= MAX_SLICES) {
- av_log(h->avctx, AV_LOG_ERROR,
- "Too many slices, increase MAX_SLICES and recompile\n");
+
+ if (sl->slice_num)
+ h->slice_row[(sl->slice_num-1)&(MAX_SLICES-1)]= sl->resync_mb_y;
+ if ( h->slice_row[sl->slice_num&(MAX_SLICES-1)] + 3 >= sl->resync_mb_y
+ && h->slice_row[sl->slice_num&(MAX_SLICES-1)] <= sl->resync_mb_y
+ && sl->slice_num >= MAX_SLICES) {
+ //in case of ASO this check needs to be updated depending on how we decide to assign slice numbers in this case
+ av_log(h->avctx, AV_LOG_WARNING, "Possibly too many slices (%d >= %d), increase MAX_SLICES and recompile if there are artifacts\n", sl->slice_num, MAX_SLICES);
}
for (j = 0; j < 2; j++) {
@@ -1642,6 +1863,11 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl)
(sl->ref_list[j][i].reference & 3);
}
+ h->au_pps_id = pps_id;
+ h->sps.new =
+ h->sps_buffers[h->pps.sps_id]->new = 0;
+ h->current_sps_id = h->pps.sps_id;
+
if (h->avctx->debug & FF_DEBUG_PICT_INFO) {
av_log(h->avctx, AV_LOG_DEBUG,
"slice:%d %s mb:%d %c%s%s pps:%u frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d:%d:%d weight:%d%s %s\n",
@@ -1699,7 +1925,7 @@ static av_always_inline void fill_filter_caches_inter(const H264Context *h,
if (USES_LIST(top_type, list)) {
const int b_xy = h->mb2b_xy[top_xy] + 3 * b_stride;
const int b8_xy = 4 * top_xy + 2;
- int (*ref2frm)[64] = sl->ref2frm[h->slice_table[top_xy] & (MAX_SLICES - 1)][0] + (MB_MBAFF(sl) ? 20 : 2);
+ int (*ref2frm)[64] = (void*)(sl->ref2frm[h->slice_table[top_xy] & (MAX_SLICES - 1)][0] + (MB_MBAFF(sl) ? 20 : 2));
AV_COPY128(mv_dst - 1 * 8, h->cur_pic.motion_val[list][b_xy + 0]);
ref_cache[0 - 1 * 8] =
ref_cache[1 - 1 * 8] = ref2frm[list][h->cur_pic.ref_index[list][b8_xy + 0]];
@@ -1714,7 +1940,7 @@ static av_always_inline void fill_filter_caches_inter(const H264Context *h,
if (USES_LIST(left_type[LTOP], list)) {
const int b_xy = h->mb2b_xy[left_xy[LTOP]] + 3;
const int b8_xy = 4 * left_xy[LTOP] + 1;
- int (*ref2frm)[64] = sl->ref2frm[h->slice_table[left_xy[LTOP]] & (MAX_SLICES - 1)][0] + (MB_MBAFF(sl) ? 20 : 2);
+ int (*ref2frm)[64] =(void*)( sl->ref2frm[h->slice_table[left_xy[LTOP]] & (MAX_SLICES - 1)][0] + (MB_MBAFF(sl) ? 20 : 2));
AV_COPY32(mv_dst - 1 + 0, h->cur_pic.motion_val[list][b_xy + b_stride * 0]);
AV_COPY32(mv_dst - 1 + 8, h->cur_pic.motion_val[list][b_xy + b_stride * 1]);
AV_COPY32(mv_dst - 1 + 16, h->cur_pic.motion_val[list][b_xy + b_stride * 2]);
@@ -1747,7 +1973,7 @@ static av_always_inline void fill_filter_caches_inter(const H264Context *h,
{
int8_t *ref = &h->cur_pic.ref_index[list][4 * mb_xy];
- int (*ref2frm)[64] = sl->ref2frm[sl->slice_num & (MAX_SLICES - 1)][0] + (MB_MBAFF(sl) ? 20 : 2);
+ int (*ref2frm)[64] = (void*)(sl->ref2frm[sl->slice_num & (MAX_SLICES - 1)][0] + (MB_MBAFF(sl) ? 20 : 2));
uint32_t ref01 = (pack16to32(ref2frm[list][ref[0]], ref2frm[list][ref[1]]) & 0x00FF00FF) * 0x0101;
uint32_t ref23 = (pack16to32(ref2frm[list][ref[2]], ref2frm[list][ref[3]]) & 0x00FF00FF) * 0x0101;
AV_WN32A(&ref_cache[0 * 8], ref01);
@@ -2020,7 +2246,7 @@ static void decode_finish_row(const H264Context *h, H264SliceContext *sl)
ff_h264_draw_horiz_band(h, sl, top, height);
- if (h->droppable)
+ if (h->droppable || sl->h264->slice_ctx[0].er.error_occurred)
return;
ff_thread_report_progress(&h->cur_pic_ptr->tf, top + height - 1,
@@ -2031,15 +2257,14 @@ static void er_add_slice(H264SliceContext *sl,
int startx, int starty,
int endx, int endy, int status)
{
-#if CONFIG_ERROR_RESILIENCE
- ERContext *er = &sl->er;
-
if (!sl->h264->enable_er)
return;
- er->ref_count = sl->ref_count[0];
- ff_er_add_slice(er, startx, starty, endx, endy, status);
-#endif
+ if (CONFIG_ERROR_RESILIENCE) {
+ ERContext *er = &sl->h264->slice_ctx[0].er;
+
+ ff_er_add_slice(er, startx, starty, endx, endy, status);
+ }
}
static int decode_slice(struct AVCodecContext *avctx, void *arg)
@@ -2058,10 +2283,22 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
sl->mb_skip_run = -1;
+ av_assert0(h->block_offset[15] == (4 * ((scan8[15] - scan8[0]) & 7) << h->pixel_shift) + 4 * sl->linesize * ((scan8[15] - scan8[0]) >> 3));
+
sl->is_complex = FRAME_MBAFF(h) || h->picture_structure != PICT_FRAME ||
avctx->codec_id != AV_CODEC_ID_H264 ||
(CONFIG_GRAY && (h->flags & CODEC_FLAG_GRAY));
+ if (!(h->avctx->active_thread_type & FF_THREAD_SLICE) && h->picture_structure == PICT_FRAME && h->slice_ctx[0].er.error_status_table) {
+ const int start_i = av_clip(sl->resync_mb_x + sl->resync_mb_y * h->mb_width, 0, h->mb_num - 1);
+ if (start_i) {
+ int prev_status = h->slice_ctx[0].er.error_status_table[h->slice_ctx[0].er.mb_index2xy[start_i - 1]];
+ prev_status &= ~ VP_START;
+ if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END))
+ h->slice_ctx[0].er.error_occurred = 1;
+ }
+ }
+
if (h->pps.cabac) {
/* realign */
align_get_bits(&sl->gb);
@@ -2075,8 +2312,17 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
for (;;) {
// START_TIMER
- int ret = ff_h264_decode_mb_cabac(h, sl);
- int eos;
+ int ret, eos;
+
+ if (sl->mb_x + sl->mb_y * h->mb_width >= sl->mb_index_end) {
+ av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps next at %d\n",
+ sl->mb_index_end);
+ er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y, sl->mb_x,
+ sl->mb_y, ER_MB_ERROR);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = ff_h264_decode_mb_cabac(h, sl);
// STOP_TIMER("decode_mb_cabac")
if (ret >= 0)
@@ -2102,9 +2348,11 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
loop_filter(h, sl, lf_x_start, sl->mb_x + 1);
return 0;
}
- if (ret < 0 || sl->cabac.bytestream > sl->cabac.bytestream_end + 2) {
+ if (sl->cabac.bytestream > sl->cabac.bytestream_end + 2 )
+ av_log(h->avctx, AV_LOG_DEBUG, "bytestream overread %"PTRDIFF_SPECIFIER"\n", sl->cabac.bytestream_end - sl->cabac.bytestream);
+ if (ret < 0 || sl->cabac.bytestream > sl->cabac.bytestream_end + 4) {
av_log(h->avctx, AV_LOG_ERROR,
- "error while decoding MB %d %d, bytestream %td\n",
+ "error while decoding MB %d %d, bytestream %"PTRDIFF_SPECIFIER"\n",
sl->mb_x, sl->mb_y,
sl->cabac.bytestream_end - sl->cabac.bytestream);
er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y, sl->mb_x,
@@ -2136,7 +2384,17 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
}
} else {
for (;;) {
- int ret = ff_h264_decode_mb_cavlc(h, sl);
+ int ret;
+
+ if (sl->mb_x + sl->mb_y * h->mb_width >= sl->mb_index_end) {
+ av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps next at %d\n",
+ sl->mb_index_end);
+ er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y, sl->mb_x,
+ sl->mb_y, ER_MB_ERROR);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = ff_h264_decode_mb_cavlc(h, sl);
if (ret >= 0)
ff_h264_hl_decode_mb(h, sl);
@@ -2173,14 +2431,15 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg)
ff_tlog(h->avctx, "slice end %d %d\n",
get_bits_count(&sl->gb), sl->gb.size_in_bits);
- if (get_bits_left(&sl->gb) == 0) {
+ if ( get_bits_left(&sl->gb) == 0
+ || get_bits_left(&sl->gb) > 0 && !(h->avctx->err_recognition & AV_EF_AGGRESSIVE)) {
er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y,
sl->mb_x - 1, sl->mb_y, ER_MB_END);
return 0;
} else {
er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y,
- sl->mb_x - 1, sl->mb_y, ER_MB_END);
+ sl->mb_x, sl->mb_y, ER_MB_END);
return AVERROR_INVALIDDATA;
}
@@ -2221,16 +2480,36 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)
H264SliceContext *sl;
int i;
- if (h->avctx->hwaccel)
+ av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height);
+
+ h->slice_ctx[0].mb_index_end = INT_MAX;
+
+ if (h->avctx->hwaccel ||
+ h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
return 0;
if (context_count == 1) {
int ret = decode_slice(avctx, &h->slice_ctx[0]);
h->mb_y = h->slice_ctx[0].mb_y;
return ret;
} else {
- for (i = 1; i < context_count; i++) {
+ int j, mb_index;
+ av_assert0(context_count > 0);
+ for (i = 0; i < context_count; i++) {
+ int mb_index_end = h->mb_width * h->mb_height;
sl = &h->slice_ctx[i];
- sl->er.error_count = 0;
+ mb_index = sl->resync_mb_x + sl->resync_mb_y * h->mb_width;
+ if (CONFIG_ERROR_RESILIENCE) {
+ sl->er.error_count = 0;
+ }
+ for (j = 0; j < context_count; j++) {
+ H264SliceContext *sl2 = &h->slice_ctx[j];
+ int mb_index2 = sl2->resync_mb_x + sl2->resync_mb_y * h->mb_width;
+
+ if (i==j || mb_index > mb_index2)
+ continue;
+ mb_index_end = FFMIN(mb_index_end, mb_index2);
+ }
+ sl->mb_index_end = mb_index_end;
}
avctx->execute(avctx, decode_slice, h->slice_ctx,
@@ -2239,8 +2518,10 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)
/* pull back stuff from slices to master context */
sl = &h->slice_ctx[context_count - 1];
h->mb_y = sl->mb_y;
- for (i = 1; i < context_count; i++)
- h->slice_ctx[0].er.error_count += h->slice_ctx[i].er.error_count;
+ if (CONFIG_ERROR_RESILIENCE) {
+ for (i = 1; i < context_count; i++)
+ h->slice_ctx[0].er.error_count += h->slice_ctx[i].er.error_count;
+ }
}
return 0;
diff --git a/libavcodec/h264addpx_template.c b/libavcodec/h264addpx_template.c
index cdbfc67dfe..046b6c2e19 100644
--- a/libavcodec/h264addpx_template.c
+++ b/libavcodec/h264addpx_template.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h264chroma.c b/libavcodec/h264chroma.c
index d5146de7b1..5b3e13bdac 100644
--- a/libavcodec/h264chroma.c
+++ b/libavcodec/h264chroma.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,9 +32,11 @@
c->put_h264_chroma_pixels_tab[0] = put_h264_chroma_mc8_ ## depth ## _c; \
c->put_h264_chroma_pixels_tab[1] = put_h264_chroma_mc4_ ## depth ## _c; \
c->put_h264_chroma_pixels_tab[2] = put_h264_chroma_mc2_ ## depth ## _c; \
+ c->put_h264_chroma_pixels_tab[3] = put_h264_chroma_mc1_ ## depth ## _c; \
c->avg_h264_chroma_pixels_tab[0] = avg_h264_chroma_mc8_ ## depth ## _c; \
c->avg_h264_chroma_pixels_tab[1] = avg_h264_chroma_mc4_ ## depth ## _c; \
c->avg_h264_chroma_pixels_tab[2] = avg_h264_chroma_mc2_ ## depth ## _c; \
+ c->avg_h264_chroma_pixels_tab[3] = avg_h264_chroma_mc1_ ## depth ## _c; \
av_cold void ff_h264chroma_init(H264ChromaContext *c, int bit_depth)
{
diff --git a/libavcodec/h264chroma.h b/libavcodec/h264chroma.h
index 93064fe06b..d4b8a0eb0e 100644
--- a/libavcodec/h264chroma.h
+++ b/libavcodec/h264chroma.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,8 +24,8 @@
typedef void (*h264_chroma_mc_func)(uint8_t *dst/*align 8*/, uint8_t *src/*align 1*/, int srcStride, int h, int x, int y);
typedef struct H264ChromaContext {
- h264_chroma_mc_func put_h264_chroma_pixels_tab[3];
- h264_chroma_mc_func avg_h264_chroma_pixels_tab[3];
+ h264_chroma_mc_func put_h264_chroma_pixels_tab[4];
+ h264_chroma_mc_func avg_h264_chroma_pixels_tab[4];
} H264ChromaContext;
void ff_h264chroma_init(H264ChromaContext *c, int bit_depth);
diff --git a/libavcodec/h264chroma_template.c b/libavcodec/h264chroma_template.c
index 028ed132cf..072b5e03f7 100644
--- a/libavcodec/h264chroma_template.c
+++ b/libavcodec/h264chroma_template.c
@@ -2,28 +2,62 @@
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
+#include "libavutil/avassert.h"
#include "bit_depth_template.c"
#define H264_CHROMA_MC(OPNAME, OP)\
+static void FUNCC(OPNAME ## h264_chroma_mc1)(uint8_t *_dst/*align 8*/, uint8_t *_src/*align 1*/, int stride, int h, int x, int y){\
+ pixel *dst = (pixel*)_dst;\
+ pixel *src = (pixel*)_src;\
+ const int A=(8-x)*(8-y);\
+ const int B=( x)*(8-y);\
+ const int C=(8-x)*( y);\
+ const int D=( x)*( y);\
+ int i;\
+ stride >>= sizeof(pixel)-1;\
+ \
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);\
+\
+ if(D){\
+ for(i=0; i<h; i++){\
+ OP(dst[0], (A*src[0] + B*src[1] + C*src[stride+0] + D*src[stride+1]));\
+ dst+= stride;\
+ src+= stride;\
+ }\
+ } else if (B + C) {\
+ const int E= B+C;\
+ const int step= C ? stride : 1;\
+ for(i=0; i<h; i++){\
+ OP(dst[0], (A*src[0] + E*src[step+0]));\
+ dst+= stride;\
+ src+= stride;\
+ }\
+ } else {\
+ for(i=0; i<h; i++){\
+ OP(dst[0], (A*src[0]));\
+ dst+= stride;\
+ src+= stride;\
+ }\
+ }\
+}\
static void FUNCC(OPNAME ## h264_chroma_mc2)(uint8_t *_dst/*align 8*/, uint8_t *_src/*align 1*/, int stride, int h, int x, int y){\
pixel *dst = (pixel*)_dst;\
pixel *src = (pixel*)_src;\
@@ -32,9 +66,9 @@ static void FUNCC(OPNAME ## h264_chroma_mc2)(uint8_t *_dst/*align 8*/, uint8_t *
const int C=(8-x)*( y);\
const int D=( x)*( y);\
int i;\
- stride /= sizeof(pixel);\
+ stride >>= sizeof(pixel)-1;\
\
- assert(x<8 && y<8 && x>=0 && y>=0);\
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);\
\
if(D){\
for(i=0; i<h; i++){\
@@ -70,9 +104,9 @@ static void FUNCC(OPNAME ## h264_chroma_mc4)(uint8_t *_dst/*align 8*/, uint8_t *
const int C=(8-x)*( y);\
const int D=( x)*( y);\
int i;\
- stride /= sizeof(pixel);\
+ stride >>= sizeof(pixel)-1;\
\
- assert(x<8 && y<8 && x>=0 && y>=0);\
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);\
\
if(D){\
for(i=0; i<h; i++){\
@@ -114,9 +148,9 @@ static void FUNCC(OPNAME ## h264_chroma_mc8)(uint8_t *_dst/*align 8*/, uint8_t *
const int C=(8-x)*( y);\
const int D=( x)*( y);\
int i;\
- stride /= sizeof(pixel);\
+ stride >>= sizeof(pixel)-1;\
\
- assert(x<8 && y<8 && x>=0 && y>=0);\
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);\
\
if(D){\
for(i=0; i<h; i++){\
diff --git a/libavcodec/h264data.h b/libavcodec/h264data.h
index 6b40b39f0a..95ea385deb 100644
--- a/libavcodec/h264data.h
+++ b/libavcodec/h264data.h
@@ -2,20 +2,20 @@
* H26L/H264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,7 +51,7 @@ static const uint8_t golomb_to_inter_cbp[48] = {
17, 18, 20, 24, 19, 21, 26, 28, 23, 27, 29, 30, 22, 25, 38, 41
};
-static const uint8_t zigzag_scan[16] = {
+static const uint8_t zigzag_scan[16+1] = {
0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4,
1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4,
1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4,
@@ -167,4 +167,23 @@ static const PMbInfo b_sub_mb_type_info[13] = {
{ MB_TYPE_8x8 | MB_TYPE_P0L0 | MB_TYPE_P0L1 | MB_TYPE_P1L0 | MB_TYPE_P1L1, 4, },
};
+static const AVRational ff_h264_pixel_aspect[17] = {
+ { 0, 1 },
+ { 1, 1 },
+ { 12, 11 },
+ { 10, 11 },
+ { 16, 11 },
+ { 40, 33 },
+ { 24, 11 },
+ { 20, 11 },
+ { 32, 11 },
+ { 80, 33 },
+ { 18, 11 },
+ { 15, 11 },
+ { 64, 33 },
+ { 160, 99 },
+ { 4, 3 },
+ { 3, 2 },
+ { 2, 1 },
+};
#endif /* AVCODEC_H264DATA_H */
diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c
index c8edbd08eb..bfb6f1ef6c 100644
--- a/libavcodec/h264dsp.c
+++ b/libavcodec/h264dsp.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,8 @@
#include <stdint.h>
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
+
#include "avcodec.h"
#include "h264dsp.h"
#include "h264idct.h"
@@ -46,6 +48,14 @@
#include "h264dsp_template.c"
#undef BIT_DEPTH
+#define BIT_DEPTH 12
+#include "h264dsp_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 14
+#include "h264dsp_template.c"
+#undef BIT_DEPTH
+
#define BIT_DEPTH 8
#include "h264addpx_template.c"
#undef BIT_DEPTH
@@ -130,7 +140,14 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
case 10:
H264_DSP(10);
break;
+ case 12:
+ H264_DSP(12);
+ break;
+ case 14:
+ H264_DSP(14);
+ break;
default:
+ av_assert0(bit_depth<=8);
H264_DSP(8);
break;
}
@@ -140,4 +157,5 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
if (ARCH_PPC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
if (ARCH_X86) ff_h264dsp_init_x86(c, bit_depth, chroma_format_idc);
+ if (ARCH_MIPS) ff_h264dsp_init_mips(c, bit_depth, chroma_format_idc);
}
diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h
index c4be235519..c232193054 100644
--- a/libavcodec/h264dsp.h
+++ b/libavcodec/h264dsp.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -126,5 +126,7 @@ void ff_h264dsp_init_ppc(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,
+ const int chroma_format_idc);
#endif /* AVCODEC_H264DSP_H */
diff --git a/libavcodec/h264dsp_template.c b/libavcodec/h264dsp_template.c
index 3d99cfcfec..fa110196b2 100644
--- a/libavcodec/h264dsp_template.c
+++ b/libavcodec/h264dsp_template.c
@@ -1,21 +1,21 @@
/*
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
- * Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,8 +35,8 @@ static void FUNCC(weight_h264_pixels ## W)(uint8_t *_block, int stride, int heig
{ \
int y; \
pixel *block = (pixel*)_block; \
- stride /= sizeof(pixel); \
- offset <<= (log2_denom + (BIT_DEPTH-8)); \
+ stride >>= sizeof(pixel)-1; \
+ offset = (unsigned)offset << (log2_denom + (BIT_DEPTH-8)); \
if(log2_denom) offset += 1<<(log2_denom-1); \
for (y = 0; y < height; y++, block += stride) { \
op_scale1(0); \
@@ -66,9 +66,9 @@ static void FUNCC(biweight_h264_pixels ## W)(uint8_t *_dst, uint8_t *_src, int s
int y; \
pixel *dst = (pixel*)_dst; \
pixel *src = (pixel*)_src; \
- stride /= sizeof(pixel); \
- offset <<= (BIT_DEPTH-8); \
- offset = ((offset + 1) | 1) << log2_denom; \
+ stride >>= sizeof(pixel)-1; \
+ offset = (unsigned)offset << (BIT_DEPTH-8); \
+ offset = (unsigned)((offset + 1) | 1) << log2_denom; \
for (y = 0; y < height; y++, dst += stride, src += stride) { \
op_scale2(0); \
op_scale2(1); \
@@ -101,12 +101,12 @@ H264_WEIGHT(2)
#undef op_scale2
#undef H264_WEIGHT
-static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma)(uint8_t *_pix, int xstride, int ystride, int inner_iters, int alpha, int beta, int8_t *tc0)
+static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta, int8_t *tc0)
{
- pixel *pix = (pixel*)_pix;
+ pixel *pix = (pixel*)p_pix;
int i, d;
- xstride /= sizeof(pixel);
- ystride /= sizeof(pixel);
+ xstride >>= sizeof(pixel)-1;
+ ystride >>= sizeof(pixel)-1;
alpha <<= BIT_DEPTH - 8;
beta <<= BIT_DEPTH - 8;
for( i = 0; i < 4; i++ ) {
@@ -162,12 +162,12 @@ static void FUNCC(h264_h_loop_filter_luma_mbaff)(uint8_t *pix, int stride, int a
FUNCC(h264_loop_filter_luma)(pix, sizeof(pixel), stride, 2, alpha, beta, tc0);
}
-static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma_intra)(uint8_t *_pix, int xstride, int ystride, int inner_iters, int alpha, int beta)
+static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma_intra)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta)
{
- pixel *pix = (pixel*)_pix;
+ pixel *pix = (pixel*)p_pix;
int d;
- xstride /= sizeof(pixel);
- ystride /= sizeof(pixel);
+ xstride >>= sizeof(pixel)-1;
+ ystride >>= sizeof(pixel)-1;
alpha <<= BIT_DEPTH - 8;
beta <<= BIT_DEPTH - 8;
for( d = 0; d < 4 * inner_iters; d++ ) {
@@ -228,16 +228,16 @@ static void FUNCC(h264_h_loop_filter_luma_mbaff_intra)(uint8_t *pix, int stride,
FUNCC(h264_loop_filter_luma_intra)(pix, sizeof(pixel), stride, 2, alpha, beta);
}
-static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma)(uint8_t *_pix, int xstride, int ystride, int inner_iters, int alpha, int beta, int8_t *tc0)
+static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta, int8_t *tc0)
{
- pixel *pix = (pixel*)_pix;
+ pixel *pix = (pixel*)p_pix;
int i, d;
- xstride /= sizeof(pixel);
- ystride /= sizeof(pixel);
alpha <<= BIT_DEPTH - 8;
beta <<= BIT_DEPTH - 8;
+ xstride >>= sizeof(pixel)-1;
+ ystride >>= sizeof(pixel)-1;
for( i = 0; i < 4; i++ ) {
- const int tc = ((tc0[i] - 1) << (BIT_DEPTH - 8)) + 1;
+ const int tc = ((tc0[i] - 1U) << (BIT_DEPTH - 8)) + 1;
if( tc <= 0 ) {
pix += inner_iters*ystride;
continue;
@@ -252,7 +252,7 @@ static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma)(uint8_t *
FFABS( p1 - p0 ) < beta &&
FFABS( q1 - q0 ) < beta ) {
- int delta = av_clip( (((q0 - p0 ) << 2) + (p1 - q1) + 4) >> 3, -tc, tc );
+ int delta = av_clip( ((q0 - p0) * 4 + (p1 - q1) + 4) >> 3, -tc, tc );
pix[-xstride] = av_clip_pixel( p0 + delta ); /* p0' */
pix[0] = av_clip_pixel( q0 - delta ); /* q0' */
@@ -282,12 +282,12 @@ static void FUNCC(h264_h_loop_filter_chroma422_mbaff)(uint8_t *pix, int stride,
FUNCC(h264_loop_filter_chroma)(pix, sizeof(pixel), stride, 2, alpha, beta, tc0);
}
-static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma_intra)(uint8_t *_pix, int xstride, int ystride, int inner_iters, int alpha, int beta)
+static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma_intra)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta)
{
- pixel *pix = (pixel*)_pix;
+ pixel *pix = (pixel*)p_pix;
int d;
- xstride /= sizeof(pixel);
- ystride /= sizeof(pixel);
+ xstride >>= sizeof(pixel)-1;
+ ystride >>= sizeof(pixel)-1;
alpha <<= BIT_DEPTH - 8;
beta <<= BIT_DEPTH - 8;
for( d = 0; d < 4 * inner_iters; d++ ) {
diff --git a/libavcodec/h264idct.c b/libavcodec/h264idct.c
index ea08d03b07..6a771affe1 100644
--- a/libavcodec/h264idct.c
+++ b/libavcodec/h264idct.c
@@ -2,20 +2,20 @@
* H.264 IDCT
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,3 +38,11 @@
#define BIT_DEPTH 10
#include "h264idct_template.c"
#undef BIT_DEPTH
+
+#define BIT_DEPTH 12
+#include "h264idct_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 14
+#include "h264idct_template.c"
+#undef BIT_DEPTH
diff --git a/libavcodec/h264idct.h b/libavcodec/h264idct.h
index 816a8251ba..17e0051497 100644
--- a/libavcodec/h264idct.h
+++ b/libavcodec/h264idct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,5 +38,7 @@ void ff_h264_chroma_dc_dequant_idct_ ## depth ## _c(int16_t *block, int qmul);
H264_IDCT( 8)
H264_IDCT( 9)
H264_IDCT(10)
+H264_IDCT(12)
+H264_IDCT(14)
#endif /* AVCODEC_H264IDCT_H */
diff --git a/libavcodec/h264idct_template.c b/libavcodec/h264idct_template.c
index 83c2a959b2..abf888ed96 100644
--- a/libavcodec/h264idct_template.c
+++ b/libavcodec/h264idct_template.c
@@ -2,20 +2,20 @@
* H.264 IDCT
* Copyright (c) 2004-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,7 +35,7 @@ void FUNCC(ff_h264_idct_add)(uint8_t *_dst, int16_t *_block, int stride)
int i;
pixel *dst = (pixel*)_dst;
dctcoef *block = (dctcoef*)_block;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
block[0] += 1 << 5;
@@ -70,7 +70,7 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){
int i;
pixel *dst = (pixel*)_dst;
dctcoef *block = (dctcoef*)_block;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
block[0] += 32;
diff --git a/libavcodec/h264pred.c b/libavcodec/h264pred.c
index b782a25586..044fc90c4e 100644
--- a/libavcodec/h264pred.c
+++ b/libavcodec/h264pred.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "avcodec.h"
#include "h264pred.h"
@@ -42,6 +43,14 @@
#include "h264pred_template.c"
#undef BIT_DEPTH
+#define BIT_DEPTH 12
+#include "h264pred_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 14
+#include "h264pred_template.c"
+#undef BIT_DEPTH
+
static void pred4x4_vertical_vp8_c(uint8_t *src, const uint8_t *topright,
ptrdiff_t stride)
{
@@ -401,7 +410,7 @@ static void pred8x8_tm_vp8_c(uint8_t *src, ptrdiff_t stride)
*/
av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id,
const int bit_depth,
- const int chroma_format_idc)
+ int chroma_format_idc)
{
#undef FUNC
#undef FUNCC
@@ -552,6 +561,8 @@ av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id,
h->pred4x4_add [ HOR_PRED ]= FUNCC(pred4x4_horizontal_add , depth);\
h->pred8x8l_add [VERT_PRED ]= FUNCC(pred8x8l_vertical_add , depth);\
h->pred8x8l_add [ HOR_PRED ]= FUNCC(pred8x8l_horizontal_add , depth);\
+ h->pred8x8l_filter_add [VERT_PRED ]= FUNCC(pred8x8l_vertical_filter_add , depth);\
+ h->pred8x8l_filter_add [ HOR_PRED ]= FUNCC(pred8x8l_horizontal_filter_add , depth);\
if (chroma_format_idc <= 1) {\
h->pred8x8_add [VERT_PRED8x8]= FUNCC(pred8x8_vertical_add , depth);\
h->pred8x8_add [ HOR_PRED8x8]= FUNCC(pred8x8_horizontal_add , depth);\
@@ -569,7 +580,14 @@ av_cold void ff_h264_pred_init(H264PredContext *h, int codec_id,
case 10:
H264_PRED(10)
break;
+ case 12:
+ H264_PRED(12)
+ break;
+ case 14:
+ H264_PRED(14)
+ break;
default:
+ av_assert0(bit_depth<=8);
H264_PRED(8)
break;
}
diff --git a/libavcodec/h264pred.h b/libavcodec/h264pred.h
index 5c4ef17c2a..6708292048 100644
--- a/libavcodec/h264pred.h
+++ b/libavcodec/h264pred.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -101,6 +101,8 @@ typedef struct H264PredContext {
int16_t *block /*align 16*/, ptrdiff_t stride);
void(*pred8x8l_add[2])(uint8_t *pix /*align 8*/,
int16_t *block /*align 16*/, ptrdiff_t stride);
+ void(*pred8x8l_filter_add[2])(uint8_t *pix /*align 8*/,
+ int16_t *block /*align 16*/, int topleft, int topright, ptrdiff_t stride);
void(*pred8x8_add[3])(uint8_t *pix /*align 8*/,
const int *block_offset,
int16_t *block /*align 16*/, ptrdiff_t stride);
diff --git a/libavcodec/h264pred_template.c b/libavcodec/h264pred_template.c
index 48baec8f85..f684433abe 100644
--- a/libavcodec/h264pred_template.c
+++ b/libavcodec/h264pred_template.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,7 +35,7 @@ static void FUNCC(pred4x4_vertical)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel4 a= AV_RN4PA(src-stride);
AV_WN4PA(src+0*stride, a);
@@ -48,7 +48,7 @@ static void FUNCC(pred4x4_horizontal)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
AV_WN4PA(src+0*stride, PIXEL_SPLAT_X4(src[-1+0*stride]));
AV_WN4PA(src+1*stride, PIXEL_SPLAT_X4(src[-1+1*stride]));
AV_WN4PA(src+2*stride, PIXEL_SPLAT_X4(src[-1+2*stride]));
@@ -59,7 +59,7 @@ static void FUNCC(pred4x4_dc)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const int dc= ( src[-stride] + src[1-stride] + src[2-stride] + src[3-stride]
+ src[-1+0*stride] + src[-1+1*stride] + src[-1+2*stride] + src[-1+3*stride] + 4) >>3;
const pixel4 a = PIXEL_SPLAT_X4(dc);
@@ -74,7 +74,7 @@ static void FUNCC(pred4x4_left_dc)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const int dc= ( src[-1+0*stride] + src[-1+1*stride] + src[-1+2*stride] + src[-1+3*stride] + 2) >>2;
const pixel4 a = PIXEL_SPLAT_X4(dc);
@@ -88,7 +88,7 @@ static void FUNCC(pred4x4_top_dc)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const int dc= ( src[-stride] + src[1-stride] + src[2-stride] + src[3-stride] + 2) >>2;
const pixel4 a = PIXEL_SPLAT_X4(dc);
@@ -102,7 +102,7 @@ static void FUNCC(pred4x4_128_dc)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel4 a = PIXEL_SPLAT_X4(1<<(BIT_DEPTH-1));
AV_WN4PA(src+0*stride, a);
@@ -115,7 +115,7 @@ static void FUNCC(pred4x4_127_dc)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel4 a = PIXEL_SPLAT_X4((1<<(BIT_DEPTH-1))-1);
AV_WN4PA(src+0*stride, a);
@@ -128,7 +128,7 @@ static void FUNCC(pred4x4_129_dc)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel4 a = PIXEL_SPLAT_X4((1<<(BIT_DEPTH-1))+1);
AV_WN4PA(src+0*stride, a);
@@ -166,7 +166,7 @@ static void FUNCC(pred4x4_down_right)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const int lt= src[-1-1*stride];
LOAD_TOP_EDGE
LOAD_LEFT_EDGE
@@ -194,7 +194,7 @@ static void FUNCC(pred4x4_down_left)(uint8_t *_src, const uint8_t *_topright,
{
pixel *src = (pixel*)_src;
const pixel *topright = (const pixel*)_topright;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
LOAD_TOP_EDGE
LOAD_TOP_RIGHT_EDGE
// LOAD_LEFT_EDGE
@@ -222,7 +222,7 @@ static void FUNCC(pred4x4_vertical_right)(uint8_t *_src,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const int lt= src[-1-1*stride];
LOAD_TOP_EDGE
LOAD_LEFT_EDGE
@@ -251,7 +251,7 @@ static void FUNCC(pred4x4_vertical_left)(uint8_t *_src,
{
pixel *src = (pixel*)_src;
const pixel *topright = (const pixel*)_topright;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
LOAD_TOP_EDGE
LOAD_TOP_RIGHT_EDGE
@@ -277,7 +277,7 @@ static void FUNCC(pred4x4_horizontal_up)(uint8_t *_src, const uint8_t *topright,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
LOAD_LEFT_EDGE
src[0+0*stride]=(l0 + l1 + 1)>>1;
@@ -303,7 +303,7 @@ static void FUNCC(pred4x4_horizontal_down)(uint8_t *_src,
ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const int lt= src[-1-1*stride];
LOAD_TOP_EDGE
LOAD_LEFT_EDGE
@@ -330,7 +330,7 @@ static void FUNCC(pred16x16_vertical)(uint8_t *_src, ptrdiff_t _stride)
{
int i;
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel4 a = AV_RN4PA(((pixel4*)(src-stride))+0);
const pixel4 b = AV_RN4PA(((pixel4*)(src-stride))+1);
const pixel4 c = AV_RN4PA(((pixel4*)(src-stride))+2);
@@ -348,7 +348,7 @@ static void FUNCC(pred16x16_horizontal)(uint8_t *_src, ptrdiff_t stride)
{
int i;
pixel *src = (pixel*)_src;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0; i<16; i++){
const pixel4 a = PIXEL_SPLAT_X4(src[-1+i*stride]);
@@ -374,7 +374,7 @@ static void FUNCC(pred16x16_dc)(uint8_t *_src, ptrdiff_t stride)
int i, dc=0;
pixel *src = (pixel*)_src;
pixel4 dcsplat;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0;i<16; i++){
dc+= src[-1+i*stride];
@@ -393,7 +393,7 @@ static void FUNCC(pred16x16_left_dc)(uint8_t *_src, ptrdiff_t stride)
int i, dc=0;
pixel *src = (pixel*)_src;
pixel4 dcsplat;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0;i<16; i++){
dc+= src[-1+i*stride];
@@ -408,7 +408,7 @@ static void FUNCC(pred16x16_top_dc)(uint8_t *_src, ptrdiff_t stride)
int i, dc=0;
pixel *src = (pixel*)_src;
pixel4 dcsplat;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0;i<16; i++){
dc+= src[i-stride];
@@ -423,7 +423,7 @@ static void FUNCC(pred16x16_##n##_dc)(uint8_t *_src, ptrdiff_t stride)\
{\
int i;\
pixel *src = (pixel*)_src;\
- stride /= sizeof(pixel);\
+ stride >>= sizeof(pixel)-1;\
PREDICT_16x16_DC(PIXEL_SPLAT_X4(v));\
}
@@ -440,7 +440,7 @@ static inline void FUNCC(pred16x16_plane_compat)(uint8_t *_src,
int a;
INIT_CLIP
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel * const src0 = src +7-stride;
const pixel * src1 = src +8*stride-1;
const pixel * src2 = src1-2*stride; // == src+6*stride-1;
@@ -489,7 +489,7 @@ static void FUNCC(pred8x8_vertical)(uint8_t *_src, ptrdiff_t _stride)
{
int i;
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel4 a= AV_RN4PA(((pixel4*)(src-stride))+0);
const pixel4 b= AV_RN4PA(((pixel4*)(src-stride))+1);
@@ -517,7 +517,7 @@ static void FUNCC(pred8x8_horizontal)(uint8_t *_src, ptrdiff_t stride)
{
int i;
pixel *src = (pixel*)_src;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0; i<8; i++){
const pixel4 a = PIXEL_SPLAT_X4(src[-1+i*stride]);
@@ -544,7 +544,7 @@ static void FUNCC(pred8x8_##n##_dc)(uint8_t *_src, ptrdiff_t stride)\
int i;\
const pixel4 a = PIXEL_SPLAT_X4(v);\
pixel *src = (pixel*)_src;\
- stride /= sizeof(pixel);\
+ stride >>= sizeof(pixel)-1;\
for(i=0; i<8; i++){\
AV_WN4PA(((pixel4*)(src+i*stride))+0, a);\
AV_WN4PA(((pixel4*)(src+i*stride))+1, a);\
@@ -567,7 +567,7 @@ static void FUNCC(pred8x8_left_dc)(uint8_t *_src, ptrdiff_t stride)
int dc0, dc2;
pixel4 dc0splat, dc2splat;
pixel *src = (pixel*)_src;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
dc0=dc2=0;
for(i=0;i<4; i++){
@@ -599,7 +599,7 @@ static void FUNCC(pred8x8_top_dc)(uint8_t *_src, ptrdiff_t stride)
int dc0, dc1;
pixel4 dc0splat, dc1splat;
pixel *src = (pixel*)_src;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
dc0=dc1=0;
for(i=0;i<4; i++){
@@ -647,7 +647,7 @@ static void FUNCC(pred8x8_dc)(uint8_t *_src, ptrdiff_t stride)
int dc0, dc1, dc2;
pixel4 dc0splat, dc1splat, dc2splat, dc3splat;
pixel *src = (pixel*)_src;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
dc0=dc1=dc2=0;
for(i=0;i<4; i++){
@@ -713,6 +713,7 @@ static void FUNCC(pred8x16_dc)(uint8_t *_src, ptrdiff_t stride)
}
}
+//the following 4 function should not be optimized!
static void FUNC(pred8x8_mad_cow_dc_l0t)(uint8_t *src, ptrdiff_t stride)
{
FUNCC(pred8x8_top_dc)(src, stride);
@@ -771,7 +772,7 @@ static void FUNCC(pred8x8_plane)(uint8_t *_src, ptrdiff_t _stride)
int a;
INIT_CLIP
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
const pixel * const src0 = src +3-stride;
const pixel * src1 = src +4*stride-1;
const pixel * src2 = src1-2*stride; // == src+2*stride-1;
@@ -885,7 +886,7 @@ static void FUNCC(pred8x8l_128_dc)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_DC(PIXEL_SPLAT_X4(1<<(BIT_DEPTH-1)));
}
@@ -893,7 +894,7 @@ static void FUNCC(pred8x8l_left_dc)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_LEFT;
const pixel4 dc = PIXEL_SPLAT_X4((l0+l1+l2+l3+l4+l5+l6+l7+4) >> 3);
@@ -903,7 +904,7 @@ static void FUNCC(pred8x8l_top_dc)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_TOP;
const pixel4 dc = PIXEL_SPLAT_X4((t0+t1+t2+t3+t4+t5+t6+t7+4) >> 3);
@@ -913,7 +914,7 @@ static void FUNCC(pred8x8l_dc)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_LEFT;
PREDICT_8x8_LOAD_TOP;
@@ -925,7 +926,7 @@ static void FUNCC(pred8x8l_horizontal)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
pixel4 a;
PREDICT_8x8_LOAD_LEFT;
@@ -940,7 +941,7 @@ static void FUNCC(pred8x8l_vertical)(uint8_t *_src, int has_topleft,
{
int y;
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
pixel4 a, b;
PREDICT_8x8_LOAD_TOP;
@@ -963,7 +964,7 @@ static void FUNCC(pred8x8l_down_left)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_TOP;
PREDICT_8x8_LOAD_TOPRIGHT;
SRC(0,0)= (t0 + 2*t1 + t2 + 2) >> 2;
@@ -986,7 +987,7 @@ static void FUNCC(pred8x8l_down_right)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_TOP;
PREDICT_8x8_LOAD_LEFT;
PREDICT_8x8_LOAD_TOPLEFT;
@@ -1010,7 +1011,7 @@ static void FUNCC(pred8x8l_vertical_right)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_TOP;
PREDICT_8x8_LOAD_LEFT;
PREDICT_8x8_LOAD_TOPLEFT;
@@ -1041,7 +1042,7 @@ static void FUNCC(pred8x8l_horizontal_down)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_TOP;
PREDICT_8x8_LOAD_LEFT;
PREDICT_8x8_LOAD_TOPLEFT;
@@ -1072,7 +1073,7 @@ static void FUNCC(pred8x8l_vertical_left)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_TOP;
PREDICT_8x8_LOAD_TOPRIGHT;
SRC(0,0)= (t0 + t1 + 1) >> 1;
@@ -1102,7 +1103,7 @@ static void FUNCC(pred8x8l_horizontal_up)(uint8_t *_src, int has_topleft,
int has_topright, ptrdiff_t _stride)
{
pixel *src = (pixel*)_src;
- int stride = _stride/sizeof(pixel);
+ int stride = _stride>>(sizeof(pixel)-1);
PREDICT_8x8_LOAD_LEFT;
SRC(0,0)= (l0 + l1 + 1) >> 1;
SRC(1,0)= (l0 + 2*l1 + l2 + 2) >> 2;
@@ -1123,6 +1124,79 @@ static void FUNCC(pred8x8l_horizontal_up)(uint8_t *_src, int has_topleft,
SRC(5,6)=SRC(5,7)=SRC(6,4)=SRC(6,5)=SRC(6,6)=
SRC(6,7)=SRC(7,4)=SRC(7,5)=SRC(7,6)=SRC(7,7)= l7;
}
+
+static void FUNCC(pred8x8l_vertical_filter_add)(uint8_t *_src, int16_t *_block, int has_topleft,
+ int has_topright, ptrdiff_t _stride)
+{
+ int i;
+ pixel *src = (pixel*)_src;
+ const dctcoef *block = (const dctcoef*)_block;
+ pixel pix[8];
+ int stride = _stride>>(sizeof(pixel)-1);
+ PREDICT_8x8_LOAD_TOP;
+
+ pix[0] = t0;
+ pix[1] = t1;
+ pix[2] = t2;
+ pix[3] = t3;
+ pix[4] = t4;
+ pix[5] = t5;
+ pix[6] = t6;
+ pix[7] = t7;
+
+ for(i=0; i<8; i++){
+ pixel v = pix[i];
+ src[0*stride]= v += block[0];
+ src[1*stride]= v += block[8];
+ src[2*stride]= v += block[16];
+ src[3*stride]= v += block[24];
+ src[4*stride]= v += block[32];
+ src[5*stride]= v += block[40];
+ src[6*stride]= v += block[48];
+ src[7*stride]= v + block[56];
+ src++;
+ block++;
+ }
+
+ memset(_block, 0, sizeof(dctcoef) * 64);
+}
+
+static void FUNCC(pred8x8l_horizontal_filter_add)(uint8_t *_src, int16_t *_block, int has_topleft,
+ int has_topright, ptrdiff_t _stride)
+{
+ int i;
+ pixel *src = (pixel*)_src;
+ const dctcoef *block = (const dctcoef*)_block;
+ pixel pix[8];
+ int stride = _stride>>(sizeof(pixel)-1);
+ PREDICT_8x8_LOAD_LEFT;
+
+ pix[0] = l0;
+ pix[1] = l1;
+ pix[2] = l2;
+ pix[3] = l3;
+ pix[4] = l4;
+ pix[5] = l5;
+ pix[6] = l6;
+ pix[7] = l7;
+
+ for(i=0; i<8; i++){
+ pixel v = pix[i];
+ src[0]= v += block[0];
+ src[1]= v += block[1];
+ src[2]= v += block[2];
+ src[3]= v += block[3];
+ src[4]= v += block[4];
+ src[5]= v += block[5];
+ src[6]= v += block[6];
+ src[7]= v + block[7];
+ src+= stride;
+ block+= 8;
+ }
+
+ memset(_block, 0, sizeof(dctcoef) * 64);
+}
+
#undef PREDICT_8x8_LOAD_LEFT
#undef PREDICT_8x8_LOAD_TOP
#undef PREDICT_8x8_LOAD_TOPLEFT
@@ -1139,7 +1213,7 @@ static void FUNCC(pred4x4_vertical_add)(uint8_t *_pix, int16_t *_block,
int i;
pixel *pix = (pixel*)_pix;
const dctcoef *block = (const dctcoef*)_block;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
pix -= stride;
for(i=0; i<4; i++){
pixel v = pix[0];
@@ -1160,7 +1234,7 @@ static void FUNCC(pred4x4_horizontal_add)(uint8_t *_pix, int16_t *_block,
int i;
pixel *pix = (pixel*)_pix;
const dctcoef *block = (const dctcoef*)_block;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0; i<4; i++){
pixel v = pix[-1];
pix[0]= v += block[0];
@@ -1180,7 +1254,7 @@ static void FUNCC(pred8x8l_vertical_add)(uint8_t *_pix, int16_t *_block,
int i;
pixel *pix = (pixel*)_pix;
const dctcoef *block = (const dctcoef*)_block;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
pix -= stride;
for(i=0; i<8; i++){
pixel v = pix[0];
@@ -1205,7 +1279,7 @@ static void FUNCC(pred8x8l_horizontal_add)(uint8_t *_pix, int16_t *_block,
int i;
pixel *pix = (pixel*)_pix;
const dctcoef *block = (const dctcoef*)_block;
- stride /= sizeof(pixel);
+ stride >>= sizeof(pixel)-1;
for(i=0; i<8; i++){
pixel v = pix[-1];
pix[0]= v += block[0];
diff --git a/libavcodec/h264qpel.c b/libavcodec/h264qpel.c
index ec46da244f..5f1bfa3176 100644
--- a/libavcodec/h264qpel.c
+++ b/libavcodec/h264qpel.c
@@ -2,26 +2,27 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "h264qpel.h"
+#define pixeltmp int16_t
#define BIT_DEPTH 8
#include "h264qpel_template.c"
#undef BIT_DEPTH
@@ -33,6 +34,17 @@
#define BIT_DEPTH 10
#include "h264qpel_template.c"
#undef BIT_DEPTH
+#undef pixeltmp
+
+#define pixeltmp int32_t
+#define BIT_DEPTH 12
+#include "h264qpel_template.c"
+#undef BIT_DEPTH
+
+#define BIT_DEPTH 14
+#include "h264qpel_template.c"
+#undef BIT_DEPTH
+
av_cold void ff_h264qpel_init(H264QpelContext *c, int bit_depth)
{
@@ -76,6 +88,12 @@ av_cold void ff_h264qpel_init(H264QpelContext *c, int bit_depth)
case 10:
SET_QPEL(10);
break;
+ case 12:
+ SET_QPEL(12);
+ break;
+ case 14:
+ SET_QPEL(14);
+ break;
}
if (ARCH_AARCH64)
diff --git a/libavcodec/h264qpel.h b/libavcodec/h264qpel.h
index 97ce195d6a..d71130d1e3 100644
--- a/libavcodec/h264qpel.h
+++ b/libavcodec/h264qpel.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/h264qpel_template.c b/libavcodec/h264qpel_template.c
index e846ac9e91..27c5b8f17f 100644
--- a/libavcodec/h264qpel_template.c
+++ b/libavcodec/h264qpel_template.c
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -75,14 +75,14 @@ static inline void FUNC(copy_block16)(uint8_t *dst, const uint8_t *src, int dstS
}
#define H264_LOWPASS(OPNAME, OP, OP2) \
-static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *_dst, const uint8_t *_src, int dstStride, int srcStride){\
+static av_unused void FUNC(OPNAME ## h264_qpel2_h_lowpass)(uint8_t *p_dst, const uint8_t *p_src, int dstStride, int srcStride){\
const int h=2;\
INIT_CLIP\
int i;\
- pixel *dst = (pixel*)_dst;\
- const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ pixel *dst = (pixel*)p_dst;\
+ const pixel *src = (const pixel*)p_src;\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<h; i++)\
{\
OP(dst[0], (src[0]+src[1])*20 - (src[-1]+src[2])*5 + (src[-2]+src[3]));\
@@ -98,8 +98,8 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_v_lowpass)(uint8_t *_dst, const
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<w; i++)\
{\
const int srcB= src[-2*srcStride];\
@@ -116,16 +116,16 @@ static av_unused void FUNC(OPNAME ## h264_qpel2_v_lowpass)(uint8_t *_dst, const
}\
}\
\
-static av_unused void FUNC(OPNAME ## h264_qpel2_hv_lowpass)(uint8_t *_dst, int16_t *tmp, const uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
+static av_unused void FUNC(OPNAME ## h264_qpel2_hv_lowpass)(uint8_t *_dst, pixeltmp *tmp, const uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
const int h=2;\
const int w=2;\
- const int pad = (BIT_DEPTH > 9) ? (-10 * ((1<<BIT_DEPTH)-1)) : 0;\
+ const int pad = (BIT_DEPTH == 10) ? (-10 * ((1<<BIT_DEPTH)-1)) : 0;\
INIT_CLIP\
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
src -= 2*srcStride;\
for(i=0; i<h+5; i++)\
{\
@@ -156,8 +156,8 @@ static void FUNC(OPNAME ## h264_qpel4_h_lowpass)(uint8_t *_dst, const uint8_t *_
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<h; i++)\
{\
OP(dst[0], (src[0]+src[1])*20 - (src[-1]+src[2])*5 + (src[-2]+src[3]));\
@@ -175,8 +175,8 @@ static void FUNC(OPNAME ## h264_qpel4_v_lowpass)(uint8_t *_dst, const uint8_t *_
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<w; i++)\
{\
const int srcB= src[-2*srcStride];\
@@ -197,16 +197,16 @@ static void FUNC(OPNAME ## h264_qpel4_v_lowpass)(uint8_t *_dst, const uint8_t *_
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel4_hv_lowpass)(uint8_t *_dst, int16_t *tmp, const uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel4_hv_lowpass)(uint8_t *_dst, pixeltmp *tmp, const uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
const int h=4;\
const int w=4;\
- const int pad = (BIT_DEPTH > 9) ? (-10 * ((1<<BIT_DEPTH)-1)) : 0;\
+ const int pad = (BIT_DEPTH == 10) ? (-10 * ((1<<BIT_DEPTH)-1)) : 0;\
INIT_CLIP\
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
src -= 2*srcStride;\
for(i=0; i<h+5; i++)\
{\
@@ -244,8 +244,8 @@ static void FUNC(OPNAME ## h264_qpel8_h_lowpass)(uint8_t *_dst, const uint8_t *_
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<h; i++)\
{\
OP(dst[0], (src[0]+src[1])*20 - (src[-1]+src[2])*5 + (src[-2]+src[3 ]));\
@@ -267,8 +267,8 @@ static void FUNC(OPNAME ## h264_qpel8_v_lowpass)(uint8_t *_dst, const uint8_t *_
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
for(i=0; i<w; i++)\
{\
const int srcB= src[-2*srcStride];\
@@ -297,16 +297,16 @@ static void FUNC(OPNAME ## h264_qpel8_v_lowpass)(uint8_t *_dst, const uint8_t *_
}\
}\
\
-static void FUNC(OPNAME ## h264_qpel8_hv_lowpass)(uint8_t *_dst, int16_t *tmp, const uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel8_hv_lowpass)(uint8_t *_dst, pixeltmp *tmp, const uint8_t *_src, int dstStride, int tmpStride, int srcStride){\
const int h=8;\
const int w=8;\
- const int pad = (BIT_DEPTH > 9) ? (-10 * ((1<<BIT_DEPTH)-1)) : 0;\
+ const int pad = (BIT_DEPTH == 10) ? (-10 * ((1<<BIT_DEPTH)-1)) : 0;\
INIT_CLIP\
int i;\
pixel *dst = (pixel*)_dst;\
const pixel *src = (const pixel*)_src;\
- dstStride /= sizeof(pixel);\
- srcStride /= sizeof(pixel);\
+ dstStride >>= sizeof(pixel)-1;\
+ srcStride >>= sizeof(pixel)-1;\
src -= 2*srcStride;\
for(i=0; i<h+5; i++)\
{\
@@ -368,7 +368,7 @@ static void FUNC(OPNAME ## h264_qpel16_h_lowpass)(uint8_t *dst, const uint8_t *s
FUNC(OPNAME ## h264_qpel8_h_lowpass)(dst+8*sizeof(pixel), src+8*sizeof(pixel), dstStride, srcStride);\
}\
\
-static void FUNC(OPNAME ## h264_qpel16_hv_lowpass)(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\
+static void FUNC(OPNAME ## h264_qpel16_hv_lowpass)(uint8_t *dst, pixeltmp *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\
FUNC(OPNAME ## h264_qpel8_hv_lowpass)(dst , tmp , src , dstStride, tmpStride, srcStride);\
FUNC(OPNAME ## h264_qpel8_hv_lowpass)(dst+8*sizeof(pixel), tmp+8, src+8*sizeof(pixel), dstStride, tmpStride, srcStride);\
src += 8*srcStride;\
@@ -480,13 +480,13 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc33)(uint8_t *dst, const uint
\
static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc22)(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- int16_t tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
+ pixeltmp tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
FUNC(OPNAME ## h264_qpel ## SIZE ## _hv_lowpass)(dst, tmp, src, stride, SIZE*sizeof(pixel), stride);\
}\
\
static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc21)(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- int16_t tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
+ pixeltmp tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
uint8_t halfH[SIZE*SIZE*sizeof(pixel)];\
uint8_t halfHV[SIZE*SIZE*sizeof(pixel)];\
FUNC(put_h264_qpel ## SIZE ## _h_lowpass)(halfH, src, SIZE*sizeof(pixel), stride);\
@@ -496,7 +496,7 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc21)(uint8_t *dst, const uint
\
static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc23)(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- int16_t tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
+ pixeltmp tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
uint8_t halfH[SIZE*SIZE*sizeof(pixel)];\
uint8_t halfHV[SIZE*SIZE*sizeof(pixel)];\
FUNC(put_h264_qpel ## SIZE ## _h_lowpass)(halfH, src + stride, SIZE*sizeof(pixel), stride);\
@@ -508,7 +508,7 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc12)(uint8_t *dst, const uint
{\
uint8_t full[SIZE*(SIZE+5)*sizeof(pixel)];\
uint8_t * const full_mid= full + SIZE*2*sizeof(pixel);\
- int16_t tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
+ pixeltmp tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
uint8_t halfV[SIZE*SIZE*sizeof(pixel)];\
uint8_t halfHV[SIZE*SIZE*sizeof(pixel)];\
FUNC(copy_block ## SIZE )(full, src - stride*2, SIZE*sizeof(pixel), stride, SIZE + 5);\
@@ -521,7 +521,7 @@ static void FUNCC(OPNAME ## h264_qpel ## SIZE ## _mc32)(uint8_t *dst, const uint
{\
uint8_t full[SIZE*(SIZE+5)*sizeof(pixel)];\
uint8_t * const full_mid= full + SIZE*2*sizeof(pixel);\
- int16_t tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
+ pixeltmp tmp[SIZE*(SIZE+5)*sizeof(pixel)];\
uint8_t halfV[SIZE*SIZE*sizeof(pixel)];\
uint8_t halfHV[SIZE*SIZE*sizeof(pixel)];\
FUNC(copy_block ## SIZE )(full, src - stride*2 + sizeof(pixel), SIZE*sizeof(pixel), stride, SIZE + 5);\
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
index 62768aa1e5..028ece82f9 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
@@ -1,28 +1,29 @@
/*
- * HEVC video decoder
+ * HEVC video Decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Mickael Raulet
* Copyright (C) 2012 - 2013 Gildas Cocherel
* Copyright (C) 2012 - 2013 Wassim Hamidouche
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/atomic.h"
#include "libavutil/attributes.h"
#include "libavutil/common.h"
#include "libavutil/display.h"
@@ -38,119 +39,7 @@
#include "golomb.h"
#include "hevc.h"
-const uint8_t ff_hevc_qpel_extra_before[4] = { 0, 3, 3, 2 };
-const uint8_t ff_hevc_qpel_extra_after[4] = { 0, 3, 4, 4 };
-const uint8_t ff_hevc_qpel_extra[4] = { 0, 6, 7, 6 };
-
-static const uint8_t scan_1x1[1] = { 0 };
-
-static const uint8_t horiz_scan2x2_x[4] = { 0, 1, 0, 1 };
-
-static const uint8_t horiz_scan2x2_y[4] = { 0, 0, 1, 1 };
-
-static const uint8_t horiz_scan4x4_x[16] = {
- 0, 1, 2, 3,
- 0, 1, 2, 3,
- 0, 1, 2, 3,
- 0, 1, 2, 3,
-};
-
-static const uint8_t horiz_scan4x4_y[16] = {
- 0, 0, 0, 0,
- 1, 1, 1, 1,
- 2, 2, 2, 2,
- 3, 3, 3, 3,
-};
-
-static const uint8_t horiz_scan8x8_inv[8][8] = {
- { 0, 1, 2, 3, 16, 17, 18, 19, },
- { 4, 5, 6, 7, 20, 21, 22, 23, },
- { 8, 9, 10, 11, 24, 25, 26, 27, },
- { 12, 13, 14, 15, 28, 29, 30, 31, },
- { 32, 33, 34, 35, 48, 49, 50, 51, },
- { 36, 37, 38, 39, 52, 53, 54, 55, },
- { 40, 41, 42, 43, 56, 57, 58, 59, },
- { 44, 45, 46, 47, 60, 61, 62, 63, },
-};
-
-static const uint8_t diag_scan2x2_x[4] = { 0, 0, 1, 1 };
-
-static const uint8_t diag_scan2x2_y[4] = { 0, 1, 0, 1 };
-
-static const uint8_t diag_scan2x2_inv[2][2] = {
- { 0, 2, },
- { 1, 3, },
-};
-
-const uint8_t ff_hevc_diag_scan4x4_x[16] = {
- 0, 0, 1, 0,
- 1, 2, 0, 1,
- 2, 3, 1, 2,
- 3, 2, 3, 3,
-};
-
-const uint8_t ff_hevc_diag_scan4x4_y[16] = {
- 0, 1, 0, 2,
- 1, 0, 3, 2,
- 1, 0, 3, 2,
- 1, 3, 2, 3,
-};
-
-static const uint8_t diag_scan4x4_inv[4][4] = {
- { 0, 2, 5, 9, },
- { 1, 4, 8, 12, },
- { 3, 7, 11, 14, },
- { 6, 10, 13, 15, },
-};
-
-const uint8_t ff_hevc_diag_scan8x8_x[64] = {
- 0, 0, 1, 0,
- 1, 2, 0, 1,
- 2, 3, 0, 1,
- 2, 3, 4, 0,
- 1, 2, 3, 4,
- 5, 0, 1, 2,
- 3, 4, 5, 6,
- 0, 1, 2, 3,
- 4, 5, 6, 7,
- 1, 2, 3, 4,
- 5, 6, 7, 2,
- 3, 4, 5, 6,
- 7, 3, 4, 5,
- 6, 7, 4, 5,
- 6, 7, 5, 6,
- 7, 6, 7, 7,
-};
-
-const uint8_t ff_hevc_diag_scan8x8_y[64] = {
- 0, 1, 0, 2,
- 1, 0, 3, 2,
- 1, 0, 4, 3,
- 2, 1, 0, 5,
- 4, 3, 2, 1,
- 0, 6, 5, 4,
- 3, 2, 1, 0,
- 7, 6, 5, 4,
- 3, 2, 1, 0,
- 7, 6, 5, 4,
- 3, 2, 1, 7,
- 6, 5, 4, 3,
- 2, 7, 6, 5,
- 4, 3, 7, 6,
- 5, 4, 7, 6,
- 5, 7, 6, 7,
-};
-
-static const uint8_t diag_scan8x8_inv[8][8] = {
- { 0, 2, 5, 9, 14, 20, 27, 35, },
- { 1, 4, 8, 13, 19, 26, 34, 42, },
- { 3, 7, 12, 18, 25, 33, 41, 48, },
- { 6, 11, 17, 24, 32, 40, 47, 53, },
- { 10, 16, 23, 31, 39, 46, 52, 57, },
- { 15, 22, 30, 38, 45, 51, 56, 60, },
- { 21, 29, 37, 44, 50, 55, 59, 62, },
- { 28, 36, 43, 49, 54, 58, 61, 63, },
-};
+const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 };
/**
* NOTE: Each function hls_foo correspond to the function foo in the
@@ -181,6 +70,10 @@ static void pic_arrays_free(HEVCContext *s)
av_freep(&s->horizontal_bs);
av_freep(&s->vertical_bs);
+ av_freep(&s->sh.entry_point_offset);
+ av_freep(&s->sh.size);
+ av_freep(&s->sh.offset);
+
av_buffer_pool_uninit(&s->tab_mvf_pool);
av_buffer_pool_uninit(&s->rpl_tab_pool);
}
@@ -196,40 +89,40 @@ 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 >> 3;
- s->bs_height = height >> 3;
+ s->bs_width = (width >> 2) + 1;
+ s->bs_height = (height >> 2) + 1;
s->sao = av_mallocz_array(ctb_count, sizeof(*s->sao));
s->deblock = av_mallocz_array(ctb_count, sizeof(*s->deblock));
if (!s->sao || !s->deblock)
goto fail;
- s->skip_flag = av_malloc(pic_size_in_ctb);
- s->tab_ct_depth = av_malloc(sps->min_cb_height * sps->min_cb_width);
+ 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)
goto fail;
- s->cbf_luma = av_malloc(sps->min_tb_width * sps->min_tb_height);
+ 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(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)
goto fail;
- s->filter_slice_edges = av_malloc(ctb_count);
- s->tab_slice_address = av_malloc(pic_size_in_ctb *
+ 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(pic_size_in_ctb *
+ s->qp_y_tab = av_malloc_array(pic_size_in_ctb,
sizeof(*s->qp_y_tab));
if (!s->qp_y_tab || !s->filter_slice_edges || !s->tab_slice_address)
goto fail;
- s->horizontal_bs = av_mallocz(2 * s->bs_width * (s->bs_height + 1));
- s->vertical_bs = av_mallocz(2 * s->bs_width * (s->bs_height + 1));
+ s->horizontal_bs = av_mallocz_array(s->bs_width, s->bs_height);
+ s->vertical_bs = av_mallocz_array(s->bs_width, s->bs_height);
if (!s->horizontal_bs || !s->vertical_bs)
goto fail;
s->tab_mvf_pool = av_buffer_pool_init(min_pu_size * sizeof(MvField),
- av_buffer_alloc);
+ av_buffer_allocz);
s->rpl_tab_pool = av_buffer_pool_init(ctb_count * sizeof(RefPicListTab),
av_buffer_allocz);
if (!s->tab_mvf_pool || !s->rpl_tab_pool)
@@ -250,11 +143,15 @@ static void pred_weight_table(HEVCContext *s, GetBitContext *gb)
uint8_t chroma_weight_l0_flag[16];
uint8_t luma_weight_l1_flag[16];
uint8_t chroma_weight_l1_flag[16];
+ int luma_log2_weight_denom;
- s->sh.luma_log2_weight_denom = av_clip(get_ue_golomb_long(gb), 0, 7);
+ 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);
+ s->sh.luma_log2_weight_denom = av_clip_uintp2(luma_log2_weight_denom, 3);
if (s->sps->chroma_format_idc != 0) {
int delta = get_se_golomb(gb);
- s->sh.chroma_log2_weight_denom = av_clip(s->sh.luma_log2_weight_denom + delta, 0, 7);
+ s->sh.chroma_log2_weight_denom = av_clip_uintp2(s->sh.luma_log2_weight_denom + delta, 3);
}
for (i = 0; i < s->sh.nb_refs[L0]; i++) {
@@ -264,7 +161,7 @@ static void pred_weight_table(HEVCContext *s, GetBitContext *gb)
s->sh.luma_offset_l0[i] = 0;
}
}
- if (s->sps->chroma_format_idc != 0) { // FIXME: invert "if" and "for"
+ if (s->sps->chroma_format_idc != 0) {
for (i = 0; i < s->sh.nb_refs[L0]; i++)
chroma_weight_l0_flag[i] = get_bits1(gb);
} else {
@@ -347,7 +244,7 @@ static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb)
nb_sps = get_ue_golomb_long(gb);
nb_sh = get_ue_golomb_long(gb);
- if (nb_sh + nb_sps > FF_ARRAY_ELEMS(rps->poc))
+ if (nb_sh + (uint64_t)nb_sps > FF_ARRAY_ELEMS(rps->poc))
return AVERROR_INVALIDDATA;
rps->nb_refs = nb_sh + nb_sps;
@@ -429,11 +326,11 @@ static void export_stream_params(AVCodecContext *avctx,
num, den, 1 << 30);
}
-static int set_sps(HEVCContext *s, const HEVCSPS *sps)
+static int set_sps(HEVCContext *s, const HEVCSPS *sps, enum AVPixelFormat pix_fmt)
{
#define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL)
enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts;
- int ret;
+ int ret, i;
export_stream_params(s->avctx, s, sps);
@@ -451,24 +348,42 @@ static int set_sps(HEVCContext *s, const HEVCSPS *sps)
#endif
}
- *fmt++ = sps->pix_fmt;
- *fmt = AV_PIX_FMT_NONE;
+ if (pix_fmt == AV_PIX_FMT_NONE) {
+ *fmt++ = sps->pix_fmt;
+ *fmt = AV_PIX_FMT_NONE;
- ret = ff_get_format(s->avctx, pix_fmts);
- if (ret < 0)
- goto fail;
- s->avctx->pix_fmt = ret;
+ ret = ff_thread_get_format(s->avctx, pix_fmts);
+ if (ret < 0)
+ goto fail;
+ s->avctx->pix_fmt = ret;
+ }
+ else {
+ 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) {
- av_frame_unref(s->tmp_frame);
- ret = ff_get_buffer(s->avctx, s->tmp_frame, AV_GET_BUFFER_FLAG_REF);
- if (ret < 0)
- goto fail;
- s->frame = s->tmp_frame;
+ 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);
+ }
}
s->sps = sps;
@@ -484,7 +399,7 @@ fail:
static int hls_slice_header(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
SliceHeader *sh = &s->sh;
int i, ret;
@@ -496,6 +411,7 @@ static int hls_slice_header(HEVCContext *s)
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);
@@ -510,12 +426,20 @@ static int hls_slice_header(HEVCContext *s)
return AVERROR_INVALIDDATA;
}
s->pps = (HEVCPPS*)s->pps_list[sh->pps_id]->data;
+ if (s->nal_unit_type == NAL_CRA_NUT && s->last_eos == 1)
+ sh->no_output_of_prior_pics_flag = 1;
if (s->sps != (HEVCSPS*)s->sps_list[s->pps->sps_id]->data) {
+ const HEVCSPS* last_sps = s->sps;
s->sps = (HEVCSPS*)s->sps_list[s->pps->sps_id]->data;
-
+ if (last_sps && IS_IRAP(s) && s->nal_unit_type != NAL_CRA_NUT) {
+ if (s->sps->width != last_sps->width || s->sps->height != last_sps->height ||
+ s->sps->temporal_layer[s->sps->max_sub_layers - 1].max_dec_pic_buffering !=
+ last_sps->temporal_layer[last_sps->max_sub_layers - 1].max_dec_pic_buffering)
+ sh->no_output_of_prior_pics_flag = 0;
+ }
ff_hevc_clear_refs(s);
- ret = set_sps(s, s->sps);
+ ret = set_sps(s, s->sps, AV_PIX_FMT_NONE);
if (ret < 0)
return ret;
@@ -642,8 +566,10 @@ static int hls_slice_header(HEVCContext *s)
if (s->sps->sao_enabled) {
sh->slice_sample_adaptive_offset_flag[0] = get_bits1(gb);
- sh->slice_sample_adaptive_offset_flag[1] =
- sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb);
+ if (s->sps->chroma_format_idc) {
+ sh->slice_sample_adaptive_offset_flag[1] =
+ sh->slice_sample_adaptive_offset_flag[2] = get_bits1(gb);
+ }
} else {
sh->slice_sample_adaptive_offset_flag[0] = 0;
sh->slice_sample_adaptive_offset_flag[1] = 0;
@@ -741,6 +667,11 @@ static int hls_slice_header(HEVCContext *s)
sh->slice_cr_qp_offset = 0;
}
+ if (s->pps->chroma_qp_offset_list_enabled_flag)
+ sh->cu_chroma_qp_offset_enabled_flag = get_bits1(gb);
+ else
+ sh->cu_chroma_qp_offset_enabled_flag = 0;
+
if (s->pps->deblocking_filter_control_present_flag) {
int deblocking_filter_override_flag = 0;
@@ -779,23 +710,59 @@ static int hls_slice_header(HEVCContext *s)
sh->num_entry_point_offsets = 0;
if (s->pps->tiles_enabled_flag || s->pps->entropy_coding_sync_enabled_flag) {
- sh->num_entry_point_offsets = get_ue_golomb_long(gb);
+ 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)) {
+ av_log(s->avctx, AV_LOG_ERROR, "num_entry_point_offsets %d is invalid\n", num_entry_point_offsets);
+ return AVERROR_INVALIDDATA;
+ }
+
+ sh->num_entry_point_offsets = num_entry_point_offsets;
if (sh->num_entry_point_offsets > 0) {
int offset_len = get_ue_golomb_long(gb) + 1;
- for (i = 0; i < sh->num_entry_point_offsets; i++)
- skip_bits(gb, offset_len);
- }
+ if (offset_len < 1 || offset_len > 32) {
+ sh->num_entry_point_offsets = 0;
+ av_log(s->avctx, AV_LOG_ERROR, "offset_len %d is invalid\n", offset_len);
+ return AVERROR_INVALIDDATA;
+ }
+
+ av_freep(&sh->entry_point_offset);
+ av_freep(&sh->offset);
+ av_freep(&sh->size);
+ sh->entry_point_offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
+ sh->offset = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
+ sh->size = av_malloc_array(sh->num_entry_point_offsets, sizeof(int));
+ if (!sh->entry_point_offset || !sh->offset || !sh->size) {
+ sh->num_entry_point_offsets = 0;
+ av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate memory\n");
+ return AVERROR(ENOMEM);
+ }
+ for (i = 0; i < sh->num_entry_point_offsets; i++) {
+ 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->pps->num_tile_rows > 1 || s->pps->num_tile_columns > 1)) {
+ s->enable_parallel_tiles = 0; // TODO: you can enable tiles in parallel here
+ s->threads_number = 1;
+ } else
+ s->enable_parallel_tiles = 0;
+ } else
+ s->enable_parallel_tiles = 0;
}
if (s->pps->slice_header_extension_present_flag) {
unsigned int length = get_ue_golomb_long(gb);
+ if (length*8LL > get_bits_left(gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "too many slice_header_extension_data_bytes\n");
+ return AVERROR_INVALIDDATA;
+ }
for (i = 0; i < length; i++)
skip_bits(gb, 8); // slice_header_extension_data_byte
}
// Inferred parameters
- sh->slice_qp = 26 + s->pps->pic_init_qp_minus26 + sh->slice_qp_delta;
+ sh->slice_qp = 26U + s->pps->pic_init_qp_minus26 + sh->slice_qp_delta;
if (sh->slice_qp > 51 ||
sh->slice_qp < -s->sps->qp_bd_offset) {
av_log(s->avctx, AV_LOG_ERROR,
@@ -813,13 +780,20 @@ static int hls_slice_header(HEVCContext *s)
return AVERROR_INVALIDDATA;
}
- s->HEVClc.first_qp_group = !s->sh.dependent_slice_segment_flag;
+ if (get_bits_left(gb) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Overread slice header by %d bits\n", -get_bits_left(gb));
+ return AVERROR_INVALIDDATA;
+ }
+
+ s->HEVClc->first_qp_group = !s->sh.dependent_slice_segment_flag;
if (!s->pps->cu_qp_delta_enabled_flag)
- s->HEVClc.qp_y = FFUMOD(s->sh.slice_qp + 52 + 2 * s->sps->qp_bd_offset,
- 52 + s->sps->qp_bd_offset) - s->sps->qp_bd_offset;
+ 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;
}
@@ -840,10 +814,9 @@ do { \
static void hls_sao_param(HEVCContext *s, int rx, int ry)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int sao_merge_left_flag = 0;
int sao_merge_up_flag = 0;
- int shift = s->sps->bit_depth - FFMIN(s->sps->bit_depth, 10);
SAOParams *sao = &CTB(s->sao, rx, ry);
int c_idx, i;
@@ -859,7 +832,10 @@ static void hls_sao_param(HEVCContext *s, int rx, int ry)
}
}
- for (c_idx = 0; c_idx < 3; c_idx++) {
+ for (c_idx = 0; c_idx < (s->sps->chroma_format_idc ? 3 : 1); c_idx++) {
+ int log2_sao_offset_scale = c_idx == 0 ? s->pps->log2_sao_offset_scale_luma :
+ s->pps->log2_sao_offset_scale_chroma;
+
if (!s->sh.slice_sample_adaptive_offset_flag[c_idx]) {
sao->type_idx[c_idx] = SAO_NOT_APPLIED;
continue;
@@ -895,13 +871,14 @@ static void hls_sao_param(HEVCContext *s, int rx, int ry)
// Inferred parameters
sao->offset_val[c_idx][0] = 0;
for (i = 0; i < 4; i++) {
- sao->offset_val[c_idx][i + 1] = sao->offset_abs[c_idx][i] << shift;
+ sao->offset_val[c_idx][i + 1] = sao->offset_abs[c_idx][i];
if (sao->type_idx[c_idx] == SAO_EDGE) {
if (i > 1)
sao->offset_val[c_idx][i + 1] = -sao->offset_val[c_idx][i + 1];
} else if (sao->offset_sign[c_idx][i]) {
sao->offset_val[c_idx][i + 1] = -sao->offset_val[c_idx][i + 1];
}
+ sao->offset_val[c_idx][i + 1] *= 1 << log2_sao_offset_scale;
}
}
}
@@ -909,384 +886,45 @@ static void hls_sao_param(HEVCContext *s, int rx, int ry)
#undef SET_SAO
#undef CTB
-static void hls_residual_coding(HEVCContext *s, int x0, int y0,
- int log2_trafo_size, enum ScanType scan_idx,
- int c_idx)
-{
-#define GET_COORD(offset, n) \
- do { \
- x_c = (scan_x_cg[offset >> 4] << 2) + scan_x_off[n]; \
- y_c = (scan_y_cg[offset >> 4] << 2) + scan_y_off[n]; \
- } while (0)
- HEVCLocalContext *lc = &s->HEVClc;
- int transform_skip_flag = 0;
-
- int last_significant_coeff_x, last_significant_coeff_y;
- int last_scan_pos;
- int n_end;
- int num_coeff = 0;
- int greater1_ctx = 1;
-
- int num_last_subset;
- int x_cg_last_sig, y_cg_last_sig;
-
- const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off;
-
- ptrdiff_t stride = s->frame->linesize[c_idx];
- int hshift = s->sps->hshift[c_idx];
- int vshift = s->sps->vshift[c_idx];
- uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride +
- ((x0 >> hshift) << s->sps->pixel_shift)];
- DECLARE_ALIGNED(16, int16_t, coeffs[MAX_TB_SIZE * MAX_TB_SIZE]) = { 0 };
- DECLARE_ALIGNED(8, uint8_t, significant_coeff_group_flag[8][8]) = { { 0 } };
-
- int trafo_size = 1 << log2_trafo_size;
- int i, qp, shift, add, scale, scale_m;
- const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
- const uint8_t *scale_matrix;
- uint8_t dc_scale;
-
- // Derive QP for dequant
- if (!lc->cu.cu_transquant_bypass_flag) {
- static const int qp_c[] = {
- 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37
- };
-
- static const uint8_t rem6[51 + 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,
- };
-
- static const uint8_t div6[51 + 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,
- };
- int qp_y = lc->qp_y;
-
- if (c_idx == 0) {
- qp = qp_y + s->sps->qp_bd_offset;
- } else {
- int qp_i, offset;
-
- if (c_idx == 1)
- offset = s->pps->cb_qp_offset + s->sh.slice_cb_qp_offset;
- else
- offset = s->pps->cr_qp_offset + s->sh.slice_cr_qp_offset;
-
- qp_i = av_clip(qp_y + offset, -s->sps->qp_bd_offset, 57);
- if (qp_i < 30)
- qp = qp_i;
- else if (qp_i > 43)
- qp = qp_i - 6;
- else
- qp = qp_c[qp_i - 30];
-
- qp += s->sps->qp_bd_offset;
- }
-
- shift = s->sps->bit_depth + log2_trafo_size - 5;
- add = 1 << (shift - 1);
- scale = level_scale[rem6[qp]] << (div6[qp]);
- scale_m = 16; // default when no custom scaling lists.
- dc_scale = 16;
-
- if (s->sps->scaling_list_enable_flag) {
- const ScalingList *sl = s->pps->scaling_list_data_present_flag ?
- &s->pps->scaling_list : &s->sps->scaling_list;
- int matrix_id = lc->cu.pred_mode != MODE_INTRA;
-
- if (log2_trafo_size != 5)
- matrix_id = 3 * matrix_id + c_idx;
-
- scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id];
- if (log2_trafo_size >= 4)
- dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id];
- }
- }
-
- if (s->pps->transform_skip_enabled_flag &&
- !lc->cu.cu_transquant_bypass_flag &&
- log2_trafo_size == 2) {
- transform_skip_flag = ff_hevc_transform_skip_flag_decode(s, c_idx);
- }
-
- last_significant_coeff_x =
- ff_hevc_last_significant_coeff_x_prefix_decode(s, c_idx, log2_trafo_size);
- last_significant_coeff_y =
- ff_hevc_last_significant_coeff_y_prefix_decode(s, c_idx, log2_trafo_size);
-
- if (last_significant_coeff_x > 3) {
- int suffix = ff_hevc_last_significant_coeff_suffix_decode(s, last_significant_coeff_x);
- last_significant_coeff_x = (1 << ((last_significant_coeff_x >> 1) - 1)) *
- (2 + (last_significant_coeff_x & 1)) +
- suffix;
- }
+static int hls_cross_component_pred(HEVCContext *s, int idx) {
+ HEVCLocalContext *lc = s->HEVClc;
+ int log2_res_scale_abs_plus1 = ff_hevc_log2_res_scale_abs(s, idx);
- if (last_significant_coeff_y > 3) {
- int suffix = ff_hevc_last_significant_coeff_suffix_decode(s, last_significant_coeff_y);
- last_significant_coeff_y = (1 << ((last_significant_coeff_y >> 1) - 1)) *
- (2 + (last_significant_coeff_y & 1)) +
- suffix;
- }
-
- if (scan_idx == SCAN_VERT)
- FFSWAP(int, last_significant_coeff_x, last_significant_coeff_y);
-
- x_cg_last_sig = last_significant_coeff_x >> 2;
- y_cg_last_sig = last_significant_coeff_y >> 2;
-
- switch (scan_idx) {
- case SCAN_DIAG: {
- int last_x_c = last_significant_coeff_x & 3;
- int last_y_c = last_significant_coeff_y & 3;
-
- scan_x_off = ff_hevc_diag_scan4x4_x;
- scan_y_off = ff_hevc_diag_scan4x4_y;
- num_coeff = diag_scan4x4_inv[last_y_c][last_x_c];
- if (trafo_size == 4) {
- scan_x_cg = scan_1x1;
- scan_y_cg = scan_1x1;
- } else if (trafo_size == 8) {
- num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4;
- scan_x_cg = diag_scan2x2_x;
- scan_y_cg = diag_scan2x2_y;
- } else if (trafo_size == 16) {
- num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4;
- scan_x_cg = ff_hevc_diag_scan4x4_x;
- scan_y_cg = ff_hevc_diag_scan4x4_y;
- } else { // trafo_size == 32
- num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4;
- scan_x_cg = ff_hevc_diag_scan8x8_x;
- scan_y_cg = ff_hevc_diag_scan8x8_y;
- }
- break;
- }
- case SCAN_HORIZ:
- scan_x_cg = horiz_scan2x2_x;
- scan_y_cg = horiz_scan2x2_y;
- scan_x_off = horiz_scan4x4_x;
- scan_y_off = horiz_scan4x4_y;
- num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x];
- break;
- default: //SCAN_VERT
- scan_x_cg = horiz_scan2x2_y;
- scan_y_cg = horiz_scan2x2_x;
- scan_x_off = horiz_scan4x4_y;
- scan_y_off = horiz_scan4x4_x;
- num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y];
- break;
+ if (log2_res_scale_abs_plus1 != 0) {
+ int res_scale_sign_flag = ff_hevc_res_scale_sign_flag(s, idx);
+ lc->tu.res_scale_val = (1 << (log2_res_scale_abs_plus1 - 1)) *
+ (1 - 2 * res_scale_sign_flag);
+ } else {
+ lc->tu.res_scale_val = 0;
}
- num_coeff++;
- num_last_subset = (num_coeff - 1) >> 4;
-
- for (i = num_last_subset; i >= 0; i--) {
- int n, m;
- int x_cg, y_cg, x_c, y_c;
- int implicit_non_zero_coeff = 0;
- int64_t trans_coeff_level;
- int prev_sig = 0;
- int offset = i << 4;
-
- uint8_t significant_coeff_flag_idx[16];
- uint8_t nb_significant_coeff_flag = 0;
-
- x_cg = scan_x_cg[i];
- y_cg = scan_y_cg[i];
-
- if (i < num_last_subset && i > 0) {
- int ctx_cg = 0;
- if (x_cg < (1 << (log2_trafo_size - 2)) - 1)
- ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg];
- if (y_cg < (1 << (log2_trafo_size - 2)) - 1)
- ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1];
-
- significant_coeff_group_flag[x_cg][y_cg] =
- ff_hevc_significant_coeff_group_flag_decode(s, c_idx, ctx_cg);
- implicit_non_zero_coeff = 1;
- } else {
- significant_coeff_group_flag[x_cg][y_cg] =
- ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) ||
- (x_cg == 0 && y_cg == 0));
- }
-
- last_scan_pos = num_coeff - offset - 1;
-
- if (i == num_last_subset) {
- n_end = last_scan_pos - 1;
- significant_coeff_flag_idx[0] = last_scan_pos;
- nb_significant_coeff_flag = 1;
- } else {
- n_end = 15;
- }
-
- if (x_cg < ((1 << log2_trafo_size) - 1) >> 2)
- prev_sig = significant_coeff_group_flag[x_cg + 1][y_cg];
- if (y_cg < ((1 << log2_trafo_size) - 1) >> 2)
- prev_sig += significant_coeff_group_flag[x_cg][y_cg + 1] << 1;
-
- for (n = n_end; n >= 0; n--) {
- GET_COORD(offset, n);
-
- if (significant_coeff_group_flag[x_cg][y_cg] &&
- (n > 0 || implicit_non_zero_coeff == 0)) {
- if (ff_hevc_significant_coeff_flag_decode(s, c_idx, x_c, y_c,
- log2_trafo_size,
- scan_idx,
- prev_sig) == 1) {
- significant_coeff_flag_idx[nb_significant_coeff_flag] = n;
- nb_significant_coeff_flag++;
- implicit_non_zero_coeff = 0;
- }
- } else {
- int last_cg = (x_c == (x_cg << 2) && y_c == (y_cg << 2));
- if (last_cg && implicit_non_zero_coeff && significant_coeff_group_flag[x_cg][y_cg]) {
- significant_coeff_flag_idx[nb_significant_coeff_flag] = n;
- nb_significant_coeff_flag++;
- }
- }
- }
-
- n_end = nb_significant_coeff_flag;
-
- if (n_end) {
- int first_nz_pos_in_cg = 16;
- int last_nz_pos_in_cg = -1;
- int c_rice_param = 0;
- int first_greater1_coeff_idx = -1;
- uint8_t coeff_abs_level_greater1_flag[16] = { 0 };
- uint16_t coeff_sign_flag;
- int sum_abs = 0;
- int sign_hidden = 0;
-
- // initialize first elem of coeff_bas_level_greater1_flag
- int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0;
-
- if (!(i == num_last_subset) && greater1_ctx == 0)
- ctx_set++;
- greater1_ctx = 1;
- last_nz_pos_in_cg = significant_coeff_flag_idx[0];
-
- for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) {
- int n_idx = significant_coeff_flag_idx[m];
- int inc = (ctx_set << 2) + greater1_ctx;
- coeff_abs_level_greater1_flag[n_idx] =
- ff_hevc_coeff_abs_level_greater1_flag_decode(s, c_idx, inc);
- if (coeff_abs_level_greater1_flag[n_idx]) {
- greater1_ctx = 0;
- } else if (greater1_ctx > 0 && greater1_ctx < 3) {
- greater1_ctx++;
- }
-
- if (coeff_abs_level_greater1_flag[n_idx] &&
- first_greater1_coeff_idx == -1)
- first_greater1_coeff_idx = n_idx;
- }
- first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1];
- sign_hidden = last_nz_pos_in_cg - first_nz_pos_in_cg >= 4 &&
- !lc->cu.cu_transquant_bypass_flag;
-
- if (first_greater1_coeff_idx != -1) {
- coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += ff_hevc_coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set);
- }
- if (!s->pps->sign_data_hiding_flag || !sign_hidden) {
- coeff_sign_flag = ff_hevc_coeff_sign_flag(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag);
- } else {
- coeff_sign_flag = ff_hevc_coeff_sign_flag(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1));
- }
- for (m = 0; m < n_end; m++) {
- n = significant_coeff_flag_idx[m];
- GET_COORD(offset, n);
- trans_coeff_level = 1 + coeff_abs_level_greater1_flag[n];
- if (trans_coeff_level == ((m < 8) ?
- ((n == first_greater1_coeff_idx) ? 3 : 2) : 1)) {
- int last_coeff_abs_level_remaining = ff_hevc_coeff_abs_level_remaining(s, trans_coeff_level, c_rice_param);
-
- trans_coeff_level += last_coeff_abs_level_remaining;
- if ((trans_coeff_level) > (3 * (1 << c_rice_param)))
- c_rice_param = FFMIN(c_rice_param + 1, 4);
- }
- if (s->pps->sign_data_hiding_flag && sign_hidden) {
- sum_abs += trans_coeff_level;
- if (n == first_nz_pos_in_cg && ((sum_abs & 1) == 1))
- trans_coeff_level = -trans_coeff_level;
- }
- if (coeff_sign_flag >> 15)
- trans_coeff_level = -trans_coeff_level;
- coeff_sign_flag <<= 1;
- if (!lc->cu.cu_transquant_bypass_flag) {
- if (s->sps->scaling_list_enable_flag) {
- if (y_c || x_c || log2_trafo_size < 4) {
- int pos;
- switch (log2_trafo_size) {
- case 3: pos = (y_c << 3) + x_c; break;
- case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break;
- case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break;
- default: pos = (y_c << 2) + x_c;
- }
- scale_m = scale_matrix[pos];
- } else {
- scale_m = dc_scale;
- }
- }
- trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift;
- if(trans_coeff_level < 0) {
- if((~trans_coeff_level) & 0xFffffffffff8000)
- trans_coeff_level = -32768;
- } else {
- if (trans_coeff_level & 0xffffffffffff8000)
- trans_coeff_level = 32767;
- }
- }
- coeffs[y_c * trafo_size + x_c] = trans_coeff_level;
- }
- }
- }
- if (lc->cu.cu_transquant_bypass_flag) {
- s->hevcdsp.transquant_bypass[log2_trafo_size - 2](dst, coeffs, stride);
- } else {
- if (transform_skip_flag)
- s->hevcdsp.transform_skip(dst, coeffs, stride);
- else if (lc->cu.pred_mode == MODE_INTRA && c_idx == 0 &&
- log2_trafo_size == 2)
- s->hevcdsp.transform_4x4_luma_add(dst, coeffs, stride);
- else
- s->hevcdsp.transform_add[log2_trafo_size - 2](dst, coeffs, stride);
- }
+ return 0;
}
static int hls_transform_unit(HEVCContext *s, int x0, int y0,
int xBase, int yBase, int cb_xBase, int cb_yBase,
int log2_cb_size, int log2_trafo_size,
- int blk_idx, int cbf_luma, int cbf_cb, int cbf_cr)
+ int blk_idx, int cbf_luma, int *cbf_cb, int *cbf_cr)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
+ const int log2_trafo_size_c = log2_trafo_size - s->sps->hshift[1];
+ int i;
if (lc->cu.pred_mode == MODE_INTRA) {
int trafo_size = 1 << log2_trafo_size;
ff_hevc_set_neighbour_available(s, x0, y0, trafo_size, trafo_size);
s->hpc.intra_pred[log2_trafo_size - 2](s, x0, y0, 0);
- if (log2_trafo_size > 2) {
- trafo_size = trafo_size << (s->sps->hshift[1] - 1);
- ff_hevc_set_neighbour_available(s, x0, y0, trafo_size, trafo_size);
- s->hpc.intra_pred[log2_trafo_size - 3](s, x0, y0, 1);
- s->hpc.intra_pred[log2_trafo_size - 3](s, x0, y0, 2);
- } else if (blk_idx == 3) {
- trafo_size = trafo_size << s->sps->hshift[1];
- ff_hevc_set_neighbour_available(s, xBase, yBase,
- trafo_size, trafo_size);
- s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 1);
- s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 2);
- }
}
- if (cbf_luma || cbf_cb || cbf_cr) {
+ if (cbf_luma || cbf_cb[0] || cbf_cr[0] ||
+ (s->sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) {
int scan_idx = SCAN_DIAG;
int scan_idx_c = SCAN_DIAG;
+ int cbf_chroma = cbf_cb[0] || cbf_cr[0] ||
+ (s->sps->chroma_format_idc == 2 &&
+ (cbf_cb[1] || cbf_cr[1]));
if (s->pps->cu_qp_delta_enabled_flag && !lc->tu.is_cu_qp_delta_coded) {
lc->tu.cu_qp_delta = ff_hevc_cu_qp_delta_abs(s);
@@ -1306,41 +944,167 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
return AVERROR_INVALIDDATA;
}
- ff_hevc_set_qPy(s, x0, y0, cb_xBase, cb_yBase, log2_cb_size);
+ ff_hevc_set_qPy(s, cb_xBase, cb_yBase, log2_cb_size);
+ }
+
+ if (s->sh.cu_chroma_qp_offset_enabled_flag && cbf_chroma &&
+ !lc->cu.cu_transquant_bypass_flag && !lc->tu.is_cu_chroma_qp_offset_coded) {
+ int cu_chroma_qp_offset_flag = ff_hevc_cu_chroma_qp_offset_flag(s);
+ if (cu_chroma_qp_offset_flag) {
+ int cu_chroma_qp_offset_idx = 0;
+ if (s->pps->chroma_qp_offset_list_len_minus1 > 0) {
+ cu_chroma_qp_offset_idx = ff_hevc_cu_chroma_qp_offset_idx(s);
+ av_log(s->avctx, AV_LOG_ERROR,
+ "cu_chroma_qp_offset_idx not yet tested.\n");
+ }
+ lc->tu.cu_qp_offset_cb = s->pps->cb_qp_offset_list[cu_chroma_qp_offset_idx];
+ lc->tu.cu_qp_offset_cr = s->pps->cr_qp_offset_list[cu_chroma_qp_offset_idx];
+ } else {
+ lc->tu.cu_qp_offset_cb = 0;
+ lc->tu.cu_qp_offset_cr = 0;
+ }
+ lc->tu.is_cu_chroma_qp_offset_coded = 1;
}
if (lc->cu.pred_mode == MODE_INTRA && log2_trafo_size < 4) {
- if (lc->tu.cur_intra_pred_mode >= 6 &&
- lc->tu.cur_intra_pred_mode <= 14) {
+ if (lc->tu.intra_pred_mode >= 6 &&
+ lc->tu.intra_pred_mode <= 14) {
scan_idx = SCAN_VERT;
- } else if (lc->tu.cur_intra_pred_mode >= 22 &&
- lc->tu.cur_intra_pred_mode <= 30) {
+ } else if (lc->tu.intra_pred_mode >= 22 &&
+ lc->tu.intra_pred_mode <= 30) {
scan_idx = SCAN_HORIZ;
}
- if (lc->pu.intra_pred_mode_c >= 6 &&
- lc->pu.intra_pred_mode_c <= 14) {
+ if (lc->tu.intra_pred_mode_c >= 6 &&
+ lc->tu.intra_pred_mode_c <= 14) {
scan_idx_c = SCAN_VERT;
- } else if (lc->pu.intra_pred_mode_c >= 22 &&
- lc->pu.intra_pred_mode_c <= 30) {
+ } else if (lc->tu.intra_pred_mode_c >= 22 &&
+ lc->tu.intra_pred_mode_c <= 30) {
scan_idx_c = SCAN_HORIZ;
}
}
+ lc->tu.cross_pf = 0;
+
if (cbf_luma)
- hls_residual_coding(s, x0, y0, log2_trafo_size, scan_idx, 0);
- if (log2_trafo_size > 2) {
- if (cbf_cb)
- hls_residual_coding(s, x0, y0, log2_trafo_size - 1, scan_idx_c, 1);
- if (cbf_cr)
- hls_residual_coding(s, x0, y0, log2_trafo_size - 1, scan_idx_c, 2);
+ ff_hevc_hls_residual_coding(s, x0, y0, log2_trafo_size, scan_idx, 0);
+ if (s->sps->chroma_format_idc && (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3)) {
+ int trafo_size_h = 1 << (log2_trafo_size_c + s->sps->hshift[1]);
+ int trafo_size_v = 1 << (log2_trafo_size_c + s->sps->vshift[1]);
+ lc->tu.cross_pf = (s->pps->cross_component_prediction_enabled_flag && cbf_luma &&
+ (lc->cu.pred_mode == MODE_INTER ||
+ (lc->tu.chroma_mode_c == 4)));
+
+ if (lc->tu.cross_pf) {
+ hls_cross_component_pred(s, 0);
+ }
+ for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
+ if (lc->cu.pred_mode == MODE_INTRA) {
+ ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (i << log2_trafo_size_c), 1);
+ }
+ if (cbf_cb[i])
+ ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c),
+ log2_trafo_size_c, scan_idx_c, 1);
+ else
+ if (lc->tu.cross_pf) {
+ ptrdiff_t stride = s->frame->linesize[1];
+ int hshift = s->sps->hshift[1];
+ int vshift = s->sps->vshift[1];
+ int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer;
+ int16_t *coeffs = (int16_t*)lc->edge_emu_buffer2;
+ int size = 1 << log2_trafo_size_c;
+
+ uint8_t *dst = &s->frame->data[1][(y0 >> vshift) * stride +
+ ((x0 >> hshift) << s->sps->pixel_shift)];
+ for (i = 0; i < (size * size); i++) {
+ coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
+ }
+ s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride);
+ }
+ }
+
+ if (lc->tu.cross_pf) {
+ hls_cross_component_pred(s, 1);
+ }
+ for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
+ if (lc->cu.pred_mode == MODE_INTRA) {
+ ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (i << log2_trafo_size_c), 2);
+ }
+ if (cbf_cr[i])
+ ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c),
+ log2_trafo_size_c, scan_idx_c, 2);
+ else
+ if (lc->tu.cross_pf) {
+ ptrdiff_t stride = s->frame->linesize[2];
+ int hshift = s->sps->hshift[2];
+ int vshift = s->sps->vshift[2];
+ int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer;
+ int16_t *coeffs = (int16_t*)lc->edge_emu_buffer2;
+ int size = 1 << log2_trafo_size_c;
+
+ uint8_t *dst = &s->frame->data[2][(y0 >> vshift) * stride +
+ ((x0 >> hshift) << s->sps->pixel_shift)];
+ for (i = 0; i < (size * size); i++) {
+ coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
+ }
+ s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride);
+ }
+ }
+ } else if (s->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->sps->vshift[1]);
+ for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
+ if (lc->cu.pred_mode == MODE_INTRA) {
+ ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size),
+ trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (i << log2_trafo_size), 1);
+ }
+ if (cbf_cb[i])
+ ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size),
+ log2_trafo_size, scan_idx_c, 1);
+ }
+ for (i = 0; i < (s->sps->chroma_format_idc == 2 ? 2 : 1); i++) {
+ if (lc->cu.pred_mode == MODE_INTRA) {
+ ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size),
+ trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (i << log2_trafo_size), 2);
+ }
+ if (cbf_cr[i])
+ ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size),
+ log2_trafo_size, scan_idx_c, 2);
+ }
+ }
+ } else if (s->sps->chroma_format_idc && lc->cu.pred_mode == MODE_INTRA) {
+ if (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3) {
+ int trafo_size_h = 1 << (log2_trafo_size_c + s->sps->hshift[1]);
+ int trafo_size_v = 1 << (log2_trafo_size_c + s->sps->vshift[1]);
+ ff_hevc_set_neighbour_available(s, x0, y0, trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0, 1);
+ s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0, 2);
+ if (s->sps->chroma_format_idc == 2) {
+ ff_hevc_set_neighbour_available(s, x0, y0 + (1 << log2_trafo_size_c),
+ trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (1 << log2_trafo_size_c), 1);
+ s->hpc.intra_pred[log2_trafo_size_c - 2](s, x0, y0 + (1 << log2_trafo_size_c), 2);
+ }
} else if (blk_idx == 3) {
- if (cbf_cb)
- hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 1);
- if (cbf_cr)
- hls_residual_coding(s, xBase, yBase, log2_trafo_size, scan_idx_c, 2);
+ int trafo_size_h = 1 << (log2_trafo_size + 1);
+ int trafo_size_v = 1 << (log2_trafo_size + s->sps->vshift[1]);
+ ff_hevc_set_neighbour_available(s, xBase, yBase,
+ trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 1);
+ s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase, 2);
+ if (s->sps->chroma_format_idc == 2) {
+ ff_hevc_set_neighbour_available(s, xBase, yBase + (1 << (log2_trafo_size)),
+ trafo_size_h, trafo_size_v);
+ s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (1 << (log2_trafo_size)), 1);
+ s->hpc.intra_pred[log2_trafo_size - 2](s, xBase, yBase + (1 << (log2_trafo_size)), 2);
+ }
}
}
+
return 0;
}
@@ -1363,17 +1127,34 @@ static int hls_transform_tree(HEVCContext *s, int x0, int y0,
int xBase, int yBase, int cb_xBase, int cb_yBase,
int log2_cb_size, int log2_trafo_size,
int trafo_depth, int blk_idx,
- int cbf_cb, int cbf_cr)
+ const int *base_cbf_cb, const int *base_cbf_cr)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
uint8_t split_transform_flag;
+ int cbf_cb[2];
+ int cbf_cr[2];
int ret;
+ cbf_cb[0] = base_cbf_cb[0];
+ cbf_cb[1] = base_cbf_cb[1];
+ cbf_cr[0] = base_cbf_cr[0];
+ cbf_cr[1] = base_cbf_cr[1];
+
if (lc->cu.intra_split_flag) {
- if (trafo_depth == 1)
- lc->tu.cur_intra_pred_mode = lc->pu.intra_pred_mode[blk_idx];
+ if (trafo_depth == 1) {
+ lc->tu.intra_pred_mode = lc->pu.intra_pred_mode[blk_idx];
+ if (s->sps->chroma_format_idc == 3) {
+ lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[blk_idx];
+ lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[blk_idx];
+ } else {
+ lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[0];
+ lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[0];
+ }
+ }
} else {
- lc->tu.cur_intra_pred_mode = lc->pu.intra_pred_mode[0];
+ lc->tu.intra_pred_mode = lc->pu.intra_pred_mode[0];
+ lc->tu.intra_pred_mode_c = lc->pu.intra_pred_mode_c[0];
+ lc->tu.chroma_mode_c = lc->pu.chroma_mode_c[0];
}
if (log2_trafo_size <= s->sps->log2_max_trafo_size &&
@@ -1392,14 +1173,21 @@ static int hls_transform_tree(HEVCContext *s, int x0, int y0,
inter_split;
}
- if (log2_trafo_size > 2 && (trafo_depth == 0 || cbf_cb))
- cbf_cb = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
- else if (log2_trafo_size > 2 || trafo_depth == 0)
- cbf_cb = 0;
- if (log2_trafo_size > 2 && (trafo_depth == 0 || cbf_cr))
- cbf_cr = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
- else if (log2_trafo_size > 2 || trafo_depth == 0)
- cbf_cr = 0;
+ if (s->sps->chroma_format_idc && (log2_trafo_size > 2 || s->sps->chroma_format_idc == 3)) {
+ if (trafo_depth == 0 || cbf_cb[0]) {
+ cbf_cb[0] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
+ if (s->sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) {
+ cbf_cb[1] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
+ }
+ }
+
+ if (trafo_depth == 0 || cbf_cr[0]) {
+ cbf_cr[0] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
+ if (s->sps->chroma_format_idc == 2 && (!split_transform_flag || log2_trafo_size == 3)) {
+ cbf_cr[1] = ff_hevc_cbf_cb_cr_decode(s, trafo_depth);
+ }
+ }
+ }
if (split_transform_flag) {
const int trafo_size_split = 1 << (log2_trafo_size - 1);
@@ -1428,8 +1216,10 @@ do {
int cbf_luma = 1;
if (lc->cu.pred_mode == MODE_INTRA || trafo_depth != 0 ||
- cbf_cb || cbf_cr)
+ cbf_cb[0] || cbf_cr[0] ||
+ (s->sps->chroma_format_idc == 2 && (cbf_cb[1] || cbf_cr[1]))) {
cbf_luma = ff_hevc_cbf_luma_decode(s, trafo_depth);
+ }
ret = hls_transform_unit(s, x0, y0, xBase, yBase, cb_xBase, cb_yBase,
log2_cb_size, log2_trafo_size,
@@ -1458,8 +1248,7 @@ do {
static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
{
- //TODO: non-4:2:0 support
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
GetBitContext gb;
int cb_size = 1 << log2_cb_size;
int stride0 = s->frame->linesize[0];
@@ -1469,7 +1258,10 @@ static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
int stride2 = s->frame->linesize[2];
uint8_t *dst2 = &s->frame->data[2][(y0 >> s->sps->vshift[2]) * stride2 + ((x0 >> s->sps->hshift[2]) << s->sps->pixel_shift)];
- int length = cb_size * cb_size * s->sps->pcm.bit_depth + ((cb_size * cb_size) >> 1) * s->sps->pcm.bit_depth_chroma;
+ int length = cb_size * cb_size * s->sps->pcm.bit_depth +
+ (((cb_size >> s->sps->hshift[1]) * (cb_size >> s->sps->vshift[1])) +
+ ((cb_size >> s->sps->hshift[2]) * (cb_size >> s->sps->vshift[2]))) *
+ s->sps->pcm.bit_depth_chroma;
const uint8_t *pcm = skip_bytes(&lc->cc, (length + 7) >> 3);
int ret;
@@ -1480,38 +1272,23 @@ static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
if (ret < 0)
return ret;
- s->hevcdsp.put_pcm(dst0, stride0, cb_size, &gb, s->sps->pcm.bit_depth);
- s->hevcdsp.put_pcm(dst1, stride1, cb_size / 2, &gb, s->sps->pcm.bit_depth_chroma);
- s->hevcdsp.put_pcm(dst2, stride2, cb_size / 2, &gb, s->sps->pcm.bit_depth_chroma);
- return 0;
-}
-
-static void hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size)
-{
- HEVCLocalContext *lc = &s->HEVClc;
- int x = ff_hevc_abs_mvd_greater0_flag_decode(s);
- int y = ff_hevc_abs_mvd_greater0_flag_decode(s);
-
- if (x)
- x += ff_hevc_abs_mvd_greater1_flag_decode(s);
- if (y)
- y += ff_hevc_abs_mvd_greater1_flag_decode(s);
-
- switch (x) {
- case 2: lc->pu.mvd.x = ff_hevc_mvd_decode(s); break;
- case 1: lc->pu.mvd.x = ff_hevc_mvd_sign_flag_decode(s); break;
- case 0: lc->pu.mvd.x = 0; break;
+ s->hevcdsp.put_pcm(dst0, stride0, cb_size, cb_size, &gb, s->sps->pcm.bit_depth);
+ if (s->sps->chroma_format_idc) {
+ s->hevcdsp.put_pcm(dst1, stride1,
+ cb_size >> s->sps->hshift[1],
+ cb_size >> s->sps->vshift[1],
+ &gb, s->sps->pcm.bit_depth_chroma);
+ s->hevcdsp.put_pcm(dst2, stride2,
+ cb_size >> s->sps->hshift[2],
+ cb_size >> s->sps->vshift[2],
+ &gb, s->sps->pcm.bit_depth_chroma);
}
- switch (y) {
- case 2: lc->pu.mvd.y = ff_hevc_mvd_decode(s); break;
- case 1: lc->pu.mvd.y = ff_hevc_mvd_sign_flag_decode(s); break;
- case 0: lc->pu.mvd.y = 0; break;
- }
+ return 0;
}
/**
- * 8.5.3.2.2.1 Luma sample interpolation process
+ * 8.5.3.2.2.1 Luma sample unidirectional interpolation process
*
* @param s HEVC decoding context
* @param dst target buffer for block data at block position
@@ -1522,49 +1299,147 @@ static void hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size)
* @param y_off vertical position of block from origin (0, 0)
* @param block_w width of block
* @param block_h height of block
+ * @param luma_weight weighting factor applied to the luma prediction
+ * @param luma_offset additive offset applied to the luma prediction value
*/
-static void luma_mc(HEVCContext *s, int16_t *dst, ptrdiff_t dststride,
- AVFrame *ref, const Mv *mv, int x_off, int y_off,
- int block_w, int block_h)
+
+static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+ AVFrame *ref, const Mv *mv, int x_off, int y_off,
+ int block_w, int block_h, int luma_weight, int luma_offset)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
uint8_t *src = ref->data[0];
ptrdiff_t srcstride = ref->linesize[0];
int pic_width = s->sps->width;
int pic_height = s->sps->height;
-
- int mx = mv->x & 3;
- int my = mv->y & 3;
- int extra_left = ff_hevc_qpel_extra_before[mx];
- int extra_top = ff_hevc_qpel_extra_before[my];
+ int mx = mv->x & 3;
+ int my = mv->y & 3;
+ int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
+ (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
+ int idx = ff_hevc_pel_weight[block_w];
x_off += mv->x >> 2;
y_off += mv->y >> 2;
- src += y_off * srcstride + (x_off << s->sps->pixel_shift);
+ src += y_off * srcstride + x_off * (1 << s->sps->pixel_shift);
- if (x_off < extra_left || y_off < extra_top ||
- x_off >= pic_width - block_w - ff_hevc_qpel_extra_after[mx] ||
- y_off >= pic_height - block_h - ff_hevc_qpel_extra_after[my]) {
+ if (x_off < QPEL_EXTRA_BEFORE || y_off < QPEL_EXTRA_AFTER ||
+ x_off >= pic_width - block_w - QPEL_EXTRA_AFTER ||
+ y_off >= pic_height - block_h - QPEL_EXTRA_AFTER) {
const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
- int offset = extra_top * srcstride + (extra_left << s->sps->pixel_shift);
- int buf_offset = extra_top *
- edge_emu_stride + (extra_left << s->sps->pixel_shift);
+ int offset = QPEL_EXTRA_BEFORE * srcstride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
+ int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src - offset,
edge_emu_stride, srcstride,
- block_w + ff_hevc_qpel_extra[mx],
- block_h + ff_hevc_qpel_extra[my],
- x_off - extra_left, y_off - extra_top,
+ block_w + QPEL_EXTRA,
+ block_h + QPEL_EXTRA,
+ x_off - QPEL_EXTRA_BEFORE, y_off - QPEL_EXTRA_BEFORE,
pic_width, pic_height);
src = lc->edge_emu_buffer + buf_offset;
srcstride = edge_emu_stride;
}
- s->hevcdsp.put_hevc_qpel[my][mx](dst, dststride, src, srcstride, block_w,
- block_h, lc->mc_buffer);
+
+ if (!weight_flag)
+ s->hevcdsp.put_hevc_qpel_uni[idx][!!my][!!mx](dst, dststride, src, srcstride,
+ block_h, mx, my, block_w);
+ else
+ s->hevcdsp.put_hevc_qpel_uni_w[idx][!!my][!!mx](dst, dststride, src, srcstride,
+ block_h, s->sh.luma_log2_weight_denom,
+ luma_weight, luma_offset, mx, my, block_w);
}
/**
- * 8.5.3.2.2.2 Chroma sample interpolation process
+ * 8.5.3.2.2.1 Luma sample bidirectional interpolation process
+ *
+ * @param s HEVC decoding context
+ * @param dst target buffer for block data at block position
+ * @param dststride stride of the dst buffer
+ * @param ref0 reference picture0 buffer at origin (0, 0)
+ * @param mv0 motion vector0 (relative to block position) to get pixel data from
+ * @param x_off horizontal position of block from origin (0, 0)
+ * @param y_off vertical position of block from origin (0, 0)
+ * @param block_w width of block
+ * @param block_h height of block
+ * @param ref1 reference picture1 buffer at origin (0, 0)
+ * @param mv1 motion vector1 (relative to block position) to get pixel data from
+ * @param current_mv current motion vector structure
+ */
+ static void luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+ AVFrame *ref0, const Mv *mv0, int x_off, int y_off,
+ int block_w, int block_h, AVFrame *ref1, const Mv *mv1, struct MvField *current_mv)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ ptrdiff_t src0stride = ref0->linesize[0];
+ ptrdiff_t src1stride = ref1->linesize[0];
+ int pic_width = s->sps->width;
+ int pic_height = s->sps->height;
+ int mx0 = mv0->x & 3;
+ int my0 = mv0->y & 3;
+ int mx1 = mv1->x & 3;
+ int my1 = mv1->y & 3;
+ int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
+ (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
+ int x_off0 = x_off + (mv0->x >> 2);
+ int y_off0 = y_off + (mv0->y >> 2);
+ int x_off1 = x_off + (mv1->x >> 2);
+ int y_off1 = y_off + (mv1->y >> 2);
+ int idx = ff_hevc_pel_weight[block_w];
+
+ uint8_t *src0 = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << s->sps->pixel_shift);
+ uint8_t *src1 = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << s->sps->pixel_shift);
+
+ if (x_off0 < QPEL_EXTRA_BEFORE || y_off0 < QPEL_EXTRA_AFTER ||
+ x_off0 >= pic_width - block_w - QPEL_EXTRA_AFTER ||
+ y_off0 >= pic_height - block_h - QPEL_EXTRA_AFTER) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
+ int offset = QPEL_EXTRA_BEFORE * src0stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
+ int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
+
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset,
+ edge_emu_stride, src0stride,
+ block_w + QPEL_EXTRA,
+ block_h + QPEL_EXTRA,
+ x_off0 - QPEL_EXTRA_BEFORE, y_off0 - QPEL_EXTRA_BEFORE,
+ pic_width, pic_height);
+ src0 = lc->edge_emu_buffer + buf_offset;
+ src0stride = edge_emu_stride;
+ }
+
+ if (x_off1 < QPEL_EXTRA_BEFORE || y_off1 < QPEL_EXTRA_AFTER ||
+ x_off1 >= pic_width - block_w - QPEL_EXTRA_AFTER ||
+ y_off1 >= pic_height - block_h - QPEL_EXTRA_AFTER) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
+ int offset = QPEL_EXTRA_BEFORE * src1stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
+ int buf_offset = QPEL_EXTRA_BEFORE * edge_emu_stride + (QPEL_EXTRA_BEFORE << s->sps->pixel_shift);
+
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src1 - offset,
+ edge_emu_stride, src1stride,
+ block_w + QPEL_EXTRA,
+ block_h + QPEL_EXTRA,
+ x_off1 - QPEL_EXTRA_BEFORE, y_off1 - QPEL_EXTRA_BEFORE,
+ pic_width, pic_height);
+ src1 = lc->edge_emu_buffer2 + buf_offset;
+ src1stride = edge_emu_stride;
+ }
+
+ s->hevcdsp.put_hevc_qpel[idx][!!my0][!!mx0](lc->tmp, src0, src0stride,
+ block_h, mx0, my0, block_w);
+ if (!weight_flag)
+ s->hevcdsp.put_hevc_qpel_bi[idx][!!my1][!!mx1](dst, dststride, src1, src1stride, lc->tmp,
+ block_h, mx1, my1, block_w);
+ else
+ s->hevcdsp.put_hevc_qpel_bi_w[idx][!!my1][!!mx1](dst, dststride, src1, src1stride, lc->tmp,
+ block_h, s->sh.luma_log2_weight_denom,
+ s->sh.luma_weight_l0[current_mv->ref_idx[0]],
+ s->sh.luma_weight_l1[current_mv->ref_idx[1]],
+ s->sh.luma_offset_l0[current_mv->ref_idx[0]],
+ s->sh.luma_offset_l1[current_mv->ref_idx[1]],
+ mx1, my1, block_w);
+
+}
+
+/**
+ * 8.5.3.2.2.2 Chroma sample uniprediction interpolation process
*
* @param s HEVC decoding context
* @param dst1 target buffer for block data at block position (U plane)
@@ -1576,88 +1451,184 @@ static void luma_mc(HEVCContext *s, int16_t *dst, ptrdiff_t dststride,
* @param y_off vertical position of block from origin (0, 0)
* @param block_w width of block
* @param block_h height of block
+ * @param chroma_weight weighting factor applied to the chroma prediction
+ * @param chroma_offset additive offset applied to the chroma prediction value
*/
-static void chroma_mc(HEVCContext *s, int16_t *dst1, int16_t *dst2,
- ptrdiff_t dststride, AVFrame *ref, const Mv *mv,
- int x_off, int y_off, int block_w, int block_h)
+
+static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
+ ptrdiff_t dststride, uint8_t *src0, ptrdiff_t srcstride, int reflist,
+ int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int chroma_weight, int chroma_offset)
{
- HEVCLocalContext *lc = &s->HEVClc;
- uint8_t *src1 = ref->data[1];
- uint8_t *src2 = ref->data[2];
- ptrdiff_t src1stride = ref->linesize[1];
- ptrdiff_t src2stride = ref->linesize[2];
- int pic_width = s->sps->width >> 1;
- int pic_height = s->sps->height >> 1;
-
- int mx = mv->x & 7;
- int my = mv->y & 7;
-
- x_off += mv->x >> 3;
- y_off += mv->y >> 3;
- src1 += y_off * src1stride + (x_off << s->sps->pixel_shift);
- src2 += y_off * src2stride + (x_off << s->sps->pixel_shift);
+ HEVCLocalContext *lc = s->HEVClc;
+ int pic_width = s->sps->width >> s->sps->hshift[1];
+ int pic_height = s->sps->height >> s->sps->vshift[1];
+ const Mv *mv = &current_mv->mv[reflist];
+ int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
+ (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
+ int idx = ff_hevc_pel_weight[block_w];
+ int hshift = s->sps->hshift[1];
+ int vshift = s->sps->vshift[1];
+ intptr_t mx = av_mod_uintp2(mv->x, 2 + hshift);
+ intptr_t my = av_mod_uintp2(mv->y, 2 + vshift);
+ intptr_t _mx = mx << (1 - hshift);
+ intptr_t _my = my << (1 - vshift);
+
+ x_off += mv->x >> (2 + hshift);
+ y_off += mv->y >> (2 + vshift);
+ src0 += y_off * srcstride + x_off * (1 << s->sps->pixel_shift);
if (x_off < EPEL_EXTRA_BEFORE || y_off < EPEL_EXTRA_AFTER ||
x_off >= pic_width - block_w - EPEL_EXTRA_AFTER ||
y_off >= pic_height - block_h - EPEL_EXTRA_AFTER) {
const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
+ int offset0 = EPEL_EXTRA_BEFORE * (srcstride + (1 << s->sps->pixel_shift));
+ int buf_offset0 = EPEL_EXTRA_BEFORE *
+ (edge_emu_stride + (1 << s->sps->pixel_shift));
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src0 - offset0,
+ edge_emu_stride, srcstride,
+ block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
+ x_off - EPEL_EXTRA_BEFORE,
+ y_off - EPEL_EXTRA_BEFORE,
+ pic_width, pic_height);
+
+ src0 = lc->edge_emu_buffer + buf_offset0;
+ srcstride = edge_emu_stride;
+ }
+ if (!weight_flag)
+ s->hevcdsp.put_hevc_epel_uni[idx][!!my][!!mx](dst0, dststride, src0, srcstride,
+ block_h, _mx, _my, block_w);
+ else
+ s->hevcdsp.put_hevc_epel_uni_w[idx][!!my][!!mx](dst0, dststride, src0, srcstride,
+ block_h, s->sh.chroma_log2_weight_denom,
+ chroma_weight, chroma_offset, _mx, _my, block_w);
+}
+
+/**
+ * 8.5.3.2.2.2 Chroma sample bidirectional interpolation process
+ *
+ * @param s HEVC decoding context
+ * @param dst target buffer for block data at block position
+ * @param dststride stride of the dst buffer
+ * @param ref0 reference picture0 buffer at origin (0, 0)
+ * @param mv0 motion vector0 (relative to block position) to get pixel data from
+ * @param x_off horizontal position of block from origin (0, 0)
+ * @param y_off vertical position of block from origin (0, 0)
+ * @param block_w width of block
+ * @param block_h height of block
+ * @param ref1 reference picture1 buffer at origin (0, 0)
+ * @param mv1 motion vector1 (relative to block position) to get pixel data from
+ * @param current_mv current motion vector structure
+ * @param cidx chroma component(cb, cr)
+ */
+static void chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVFrame *ref0, AVFrame *ref1,
+ int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int cidx)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ uint8_t *src1 = ref0->data[cidx+1];
+ uint8_t *src2 = ref1->data[cidx+1];
+ ptrdiff_t src1stride = ref0->linesize[cidx+1];
+ ptrdiff_t src2stride = ref1->linesize[cidx+1];
+ int weight_flag = (s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
+ (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag);
+ int pic_width = s->sps->width >> s->sps->hshift[1];
+ int pic_height = s->sps->height >> s->sps->vshift[1];
+ Mv *mv0 = &current_mv->mv[0];
+ Mv *mv1 = &current_mv->mv[1];
+ int hshift = s->sps->hshift[1];
+ int vshift = s->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 = mx0 << (1 - hshift);
+ intptr_t _my0 = my0 << (1 - vshift);
+ intptr_t _mx1 = mx1 << (1 - hshift);
+ intptr_t _my1 = my1 << (1 - vshift);
+
+ int x_off0 = x_off + (mv0->x >> (2 + hshift));
+ int y_off0 = y_off + (mv0->y >> (2 + vshift));
+ int x_off1 = x_off + (mv1->x >> (2 + hshift));
+ int y_off1 = y_off + (mv1->y >> (2 + vshift));
+ int idx = ff_hevc_pel_weight[block_w];
+ src1 += y_off0 * src1stride + (int)((unsigned)x_off0 << s->sps->pixel_shift);
+ src2 += y_off1 * src2stride + (int)((unsigned)x_off1 << s->sps->pixel_shift);
+
+ if (x_off0 < EPEL_EXTRA_BEFORE || y_off0 < EPEL_EXTRA_AFTER ||
+ x_off0 >= pic_width - block_w - EPEL_EXTRA_AFTER ||
+ y_off0 >= pic_height - block_h - EPEL_EXTRA_AFTER) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
int offset1 = EPEL_EXTRA_BEFORE * (src1stride + (1 << s->sps->pixel_shift));
int buf_offset1 = EPEL_EXTRA_BEFORE *
(edge_emu_stride + (1 << s->sps->pixel_shift));
- int offset2 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->sps->pixel_shift));
- int buf_offset2 = EPEL_EXTRA_BEFORE *
- (edge_emu_stride + (1 << s->sps->pixel_shift));
s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src1 - offset1,
edge_emu_stride, src1stride,
block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
- x_off - EPEL_EXTRA_BEFORE,
- y_off - EPEL_EXTRA_BEFORE,
+ x_off0 - EPEL_EXTRA_BEFORE,
+ y_off0 - EPEL_EXTRA_BEFORE,
pic_width, pic_height);
src1 = lc->edge_emu_buffer + buf_offset1;
src1stride = edge_emu_stride;
- s->hevcdsp.put_hevc_epel[!!my][!!mx](dst1, dststride, src1, src1stride,
- block_w, block_h, mx, my, lc->mc_buffer);
+ }
+
+ if (x_off1 < EPEL_EXTRA_BEFORE || y_off1 < EPEL_EXTRA_AFTER ||
+ x_off1 >= pic_width - block_w - EPEL_EXTRA_AFTER ||
+ y_off1 >= pic_height - block_h - EPEL_EXTRA_AFTER) {
+ const int edge_emu_stride = EDGE_EMU_BUFFER_STRIDE << s->sps->pixel_shift;
+ int offset1 = EPEL_EXTRA_BEFORE * (src2stride + (1 << s->sps->pixel_shift));
+ int buf_offset1 = EPEL_EXTRA_BEFORE *
+ (edge_emu_stride + (1 << s->sps->pixel_shift));
- s->vdsp.emulated_edge_mc(lc->edge_emu_buffer, src2 - offset2,
+ s->vdsp.emulated_edge_mc(lc->edge_emu_buffer2, src2 - offset1,
edge_emu_stride, src2stride,
block_w + EPEL_EXTRA, block_h + EPEL_EXTRA,
- x_off - EPEL_EXTRA_BEFORE,
- y_off - EPEL_EXTRA_BEFORE,
+ x_off1 - EPEL_EXTRA_BEFORE,
+ y_off1 - EPEL_EXTRA_BEFORE,
pic_width, pic_height);
- src2 = lc->edge_emu_buffer + buf_offset2;
- src2stride = edge_emu_stride;
- s->hevcdsp.put_hevc_epel[!!my][!!mx](dst2, dststride, src2, src2stride,
- block_w, block_h, mx, my,
- lc->mc_buffer);
- } else {
- s->hevcdsp.put_hevc_epel[!!my][!!mx](dst1, dststride, src1, src1stride,
- block_w, block_h, mx, my,
- lc->mc_buffer);
- s->hevcdsp.put_hevc_epel[!!my][!!mx](dst2, dststride, src2, src2stride,
- block_w, block_h, mx, my,
- lc->mc_buffer);
+ src2 = lc->edge_emu_buffer2 + buf_offset1;
+ src2stride = edge_emu_stride;
}
+
+ s->hevcdsp.put_hevc_epel[idx][!!my0][!!mx0](lc->tmp, src1, src1stride,
+ block_h, _mx0, _my0, block_w);
+ if (!weight_flag)
+ s->hevcdsp.put_hevc_epel_bi[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1],
+ src2, src2stride, lc->tmp,
+ block_h, _mx1, _my1, block_w);
+ else
+ s->hevcdsp.put_hevc_epel_bi_w[idx][!!my1][!!mx1](dst0, s->frame->linesize[cidx+1],
+ src2, src2stride, lc->tmp,
+ block_h,
+ s->sh.chroma_log2_weight_denom,
+ s->sh.chroma_weight_l0[current_mv->ref_idx[0]][cidx],
+ s->sh.chroma_weight_l1[current_mv->ref_idx[1]][cidx],
+ s->sh.chroma_offset_l0[current_mv->ref_idx[0]][cidx],
+ s->sh.chroma_offset_l1[current_mv->ref_idx[1]][cidx],
+ _mx1, _my1, block_w);
}
static void hevc_await_progress(HEVCContext *s, HEVCFrame *ref,
const Mv *mv, int y0, int height)
{
- int y = (mv->y >> 2) + y0 + height + 9;
- ff_thread_await_progress(&ref->tf, y, 0);
+ int y = FFMAX(0, (mv->y >> 2) + y0 + height + 9);
+
+ if (s->threads_type == FF_THREAD_FRAME )
+ ff_thread_await_progress(&ref->tf, y, 0);
}
static void hevc_luma_mv_mpv_mode(HEVCContext *s, int x0, int y0, int nPbW,
int nPbH, int log2_cb_size, int part_idx,
int merge_idx, MvField *mv)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
enum InterPredIdc inter_pred_idc = PRED_L0;
int mvp_flag;
ff_hevc_set_neighbour_available(s, x0, y0, nPbW, nPbH);
+ mv->pred_flag = 0;
if (s->sh.slice_type == B_SLICE)
inter_pred_idc = ff_hevc_inter_pred_idc_decode(s, nPbW, nPbH);
@@ -1665,8 +1636,8 @@ static void hevc_luma_mv_mpv_mode(HEVCContext *s, int x0, int y0, int nPbW,
if (s->sh.nb_refs[L0])
mv->ref_idx[0]= ff_hevc_ref_idx_lx_decode(s, s->sh.nb_refs[L0]);
- mv->pred_flag[0] = 1;
- hls_mvd_coding(s, x0, y0, 0);
+ mv->pred_flag = PF_L0;
+ ff_hevc_hls_mvd_coding(s, x0, y0, 0);
mvp_flag = ff_hevc_mvp_lx_flag_decode(s);
ff_hevc_luma_mv_mvp_mode(s, x0, y0, nPbW, nPbH, log2_cb_size,
part_idx, merge_idx, mv, mvp_flag, 0);
@@ -1681,10 +1652,10 @@ static void hevc_luma_mv_mpv_mode(HEVCContext *s, int x0, int y0, int nPbW,
if (s->sh.mvd_l1_zero_flag == 1 && inter_pred_idc == PRED_BI) {
AV_ZERO32(&lc->pu.mvd);
} else {
- hls_mvd_coding(s, x0, y0, 1);
+ ff_hevc_hls_mvd_coding(s, x0, y0, 1);
}
- mv->pred_flag[1] = 1;
+ mv->pred_flag += PF_L1;
mvp_flag = ff_hevc_mvp_lx_flag_decode(s);
ff_hevc_luma_mv_mvp_mode(s, x0, y0, nPbW, nPbH, log2_cb_size,
part_idx, merge_idx, mv, mvp_flag, 1);
@@ -1695,12 +1666,12 @@ static void hevc_luma_mv_mpv_mode(HEVCContext *s, int x0, int y0, int nPbW,
static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW, int nPbH,
- int log2_cb_size, int partIdx)
+ int log2_cb_size, int partIdx, int idx)
{
#define POS(c_idx, x, y) \
&s->frame->data[c_idx][((y) >> s->sps->vshift[c_idx]) * s->frame->linesize[c_idx] + \
(((x) >> s->sps->hshift[c_idx]) << s->sps->pixel_shift)]
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int merge_idx = 0;
struct MvField current_mv = {{{ 0 }}};
@@ -1708,10 +1679,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
MvField *tab_mvf = s->ref->tab_mvf;
RefPicList *refPicList = s->ref->refPicList;
- HEVCFrame *ref0, *ref1;
-
- int tmpstride = MAX_PB_SIZE;
-
+ HEVCFrame *ref0 = NULL, *ref1 = NULL;
uint8_t *dst0 = POS(0, x0, y0);
uint8_t *dst1 = POS(1, x0, y0);
uint8_t *dst2 = POS(2, x0, y0);
@@ -1747,139 +1715,74 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < nPbW >> s->sps->log2_min_pu_size; i++)
tab_mvf[(y_pu + j) * min_pu_width + x_pu + i] = current_mv;
- if (current_mv.pred_flag[0]) {
+ if (current_mv.pred_flag & PF_L0) {
ref0 = refPicList[0].ref[current_mv.ref_idx[0]];
if (!ref0)
return;
hevc_await_progress(s, ref0, &current_mv.mv[0], y0, nPbH);
}
- if (current_mv.pred_flag[1]) {
+ if (current_mv.pred_flag & PF_L1) {
ref1 = refPicList[1].ref[current_mv.ref_idx[1]];
if (!ref1)
return;
hevc_await_progress(s, ref1, &current_mv.mv[1], y0, nPbH);
}
- if (current_mv.pred_flag[0] && !current_mv.pred_flag[1]) {
- DECLARE_ALIGNED(16, int16_t, tmp[MAX_PB_SIZE * MAX_PB_SIZE]);
- DECLARE_ALIGNED(16, int16_t, tmp2[MAX_PB_SIZE * MAX_PB_SIZE]);
+ if (current_mv.pred_flag == PF_L0) {
+ int x0_c = x0 >> s->sps->hshift[1];
+ int y0_c = y0 >> s->sps->vshift[1];
+ int nPbW_c = nPbW >> s->sps->hshift[1];
+ int nPbH_c = nPbH >> s->sps->vshift[1];
- luma_mc(s, tmp, tmpstride, ref0->frame,
- &current_mv.mv[0], x0, y0, nPbW, nPbH);
+ luma_mc_uni(s, dst0, s->frame->linesize[0], ref0->frame,
+ &current_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->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
- (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag)) {
- s->hevcdsp.weighted_pred(s->sh.luma_log2_weight_denom,
- s->sh.luma_weight_l0[current_mv.ref_idx[0]],
- s->sh.luma_offset_l0[current_mv.ref_idx[0]],
- dst0, s->frame->linesize[0], tmp,
- tmpstride, nPbW, nPbH);
- } else {
- s->hevcdsp.put_unweighted_pred(dst0, s->frame->linesize[0], tmp, tmpstride, nPbW, nPbH);
- }
- chroma_mc(s, tmp, tmp2, tmpstride, ref0->frame,
- &current_mv.mv[0], x0 / 2, y0 / 2, nPbW / 2, nPbH / 2);
-
- if ((s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
- (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag)) {
- s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
- s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0],
- s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0],
- dst1, s->frame->linesize[1], tmp, tmpstride,
- nPbW / 2, nPbH / 2);
- s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
- s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1],
- s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1],
- dst2, s->frame->linesize[2], tmp2, tmpstride,
- nPbW / 2, nPbH / 2);
- } else {
- s->hevcdsp.put_unweighted_pred(dst1, s->frame->linesize[1], tmp, tmpstride, nPbW/2, nPbH/2);
- s->hevcdsp.put_unweighted_pred(dst2, s->frame->linesize[2], tmp2, tmpstride, nPbW/2, nPbH/2);
- }
- } else if (!current_mv.pred_flag[0] && current_mv.pred_flag[1]) {
- DECLARE_ALIGNED(16, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]);
- DECLARE_ALIGNED(16, int16_t, tmp2[MAX_PB_SIZE * MAX_PB_SIZE]);
-
- luma_mc(s, tmp, tmpstride, ref1->frame,
- &current_mv.mv[1], x0, y0, nPbW, nPbH);
-
- if ((s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
- (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag)) {
- s->hevcdsp.weighted_pred(s->sh.luma_log2_weight_denom,
- s->sh.luma_weight_l1[current_mv.ref_idx[1]],
- s->sh.luma_offset_l1[current_mv.ref_idx[1]],
- dst0, s->frame->linesize[0], tmp, tmpstride,
- nPbW, nPbH);
- } else {
- s->hevcdsp.put_unweighted_pred(dst0, s->frame->linesize[0], tmp, tmpstride, nPbW, nPbH);
- }
-
- chroma_mc(s, tmp, tmp2, tmpstride, ref1->frame,
- &current_mv.mv[1], x0/2, y0/2, nPbW/2, nPbH/2);
-
- if ((s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
- (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag)) {
- s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
- s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0],
- s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0],
- dst1, s->frame->linesize[1], tmp, tmpstride, nPbW/2, nPbH/2);
- s->hevcdsp.weighted_pred(s->sh.chroma_log2_weight_denom,
- s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1],
- s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1],
- dst2, s->frame->linesize[2], tmp2, tmpstride, nPbW/2, nPbH/2);
- } else {
- s->hevcdsp.put_unweighted_pred(dst1, s->frame->linesize[1], tmp, tmpstride, nPbW/2, nPbH/2);
- s->hevcdsp.put_unweighted_pred(dst2, s->frame->linesize[2], tmp2, tmpstride, nPbW/2, nPbH/2);
- }
- } else if (current_mv.pred_flag[0] && current_mv.pred_flag[1]) {
- DECLARE_ALIGNED(16, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]);
- DECLARE_ALIGNED(16, int16_t, tmp2[MAX_PB_SIZE * MAX_PB_SIZE]);
- DECLARE_ALIGNED(16, int16_t, tmp3[MAX_PB_SIZE * MAX_PB_SIZE]);
- DECLARE_ALIGNED(16, int16_t, tmp4[MAX_PB_SIZE * MAX_PB_SIZE]);
-
- luma_mc(s, tmp, tmpstride, ref0->frame,
- &current_mv.mv[0], x0, y0, nPbW, nPbH);
- luma_mc(s, tmp2, tmpstride, ref1->frame,
- &current_mv.mv[1], x0, y0, nPbW, nPbH);
-
- if ((s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
- (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag)) {
- s->hevcdsp.weighted_pred_avg(s->sh.luma_log2_weight_denom,
- s->sh.luma_weight_l0[current_mv.ref_idx[0]],
- s->sh.luma_weight_l1[current_mv.ref_idx[1]],
- s->sh.luma_offset_l0[current_mv.ref_idx[0]],
- s->sh.luma_offset_l1[current_mv.ref_idx[1]],
- dst0, s->frame->linesize[0],
- tmp, tmp2, tmpstride, nPbW, nPbH);
- } else {
- s->hevcdsp.put_weighted_pred_avg(dst0, s->frame->linesize[0],
- tmp, tmp2, tmpstride, nPbW, nPbH);
- }
-
- chroma_mc(s, tmp, tmp2, tmpstride, ref0->frame,
- &current_mv.mv[0], x0 / 2, y0 / 2, nPbW / 2, nPbH / 2);
- chroma_mc(s, tmp3, tmp4, tmpstride, ref1->frame,
- &current_mv.mv[1], x0 / 2, y0 / 2, nPbW / 2, nPbH / 2);
-
- if ((s->sh.slice_type == P_SLICE && s->pps->weighted_pred_flag) ||
- (s->sh.slice_type == B_SLICE && s->pps->weighted_bipred_flag)) {
- s->hevcdsp.weighted_pred_avg(s->sh.chroma_log2_weight_denom,
- s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0],
- s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0],
- s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0],
- s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0],
- dst1, s->frame->linesize[1], tmp, tmp3,
- tmpstride, nPbW / 2, nPbH / 2);
- s->hevcdsp.weighted_pred_avg(s->sh.chroma_log2_weight_denom,
- s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1],
- s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1],
- s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1],
- s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1],
- dst2, s->frame->linesize[2], tmp2, tmp4,
- tmpstride, nPbW / 2, nPbH / 2);
- } else {
- s->hevcdsp.put_weighted_pred_avg(dst1, s->frame->linesize[1], tmp, tmp3, tmpstride, nPbW/2, nPbH/2);
- s->hevcdsp.put_weighted_pred_avg(dst2, s->frame->linesize[2], tmp2, tmp4, tmpstride, nPbW/2, nPbH/2);
+ if (s->sps->chroma_format_idc) {
+ chroma_mc_uni(s, dst1, s->frame->linesize[1], ref0->frame->data[1], ref0->frame->linesize[1],
+ 0, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
+ s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]);
+ chroma_mc_uni(s, dst2, s->frame->linesize[2], ref0->frame->data[2], ref0->frame->linesize[2],
+ 0, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
+ s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1]);
+ }
+ } else if (current_mv.pred_flag == PF_L1) {
+ int x0_c = x0 >> s->sps->hshift[1];
+ int y0_c = y0 >> s->sps->vshift[1];
+ int nPbW_c = nPbW >> s->sps->hshift[1];
+ int nPbH_c = nPbH >> s->sps->vshift[1];
+
+ luma_mc_uni(s, dst0, s->frame->linesize[0], ref1->frame,
+ &current_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->sps->chroma_format_idc) {
+ chroma_mc_uni(s, dst1, s->frame->linesize[1], ref1->frame->data[1], ref1->frame->linesize[1],
+ 1, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
+ s->sh.chroma_weight_l1[current_mv.ref_idx[1]][0], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][0]);
+
+ chroma_mc_uni(s, dst2, s->frame->linesize[2], ref1->frame->data[2], ref1->frame->linesize[2],
+ 1, x0_c, y0_c, nPbW_c, nPbH_c, &current_mv,
+ s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1]);
+ }
+ } else if (current_mv.pred_flag == PF_BI) {
+ int x0_c = x0 >> s->sps->hshift[1];
+ int y0_c = y0 >> s->sps->vshift[1];
+ int nPbW_c = nPbW >> s->sps->hshift[1];
+ int nPbH_c = nPbH >> s->sps->vshift[1];
+
+ luma_mc_bi(s, dst0, s->frame->linesize[0], ref0->frame,
+ &current_mv.mv[0], x0, y0, nPbW, nPbH,
+ ref1->frame, &current_mv.mv[1], &current_mv);
+
+ if (s->sps->chroma_format_idc) {
+ chroma_mc_bi(s, dst1, s->frame->linesize[1], ref0->frame, ref1->frame,
+ x0_c, y0_c, nPbW_c, nPbH_c, &current_mv, 0);
+
+ chroma_mc_bi(s, dst2, s->frame->linesize[2], ref0->frame, ref1->frame,
+ x0_c, y0_c, nPbW_c, nPbH_c, &current_mv, 1);
}
}
}
@@ -1890,13 +1793,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
static int luma_intra_pred_mode(HEVCContext *s, int x0, int y0, int pu_size,
int prev_intra_luma_pred_flag)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int x_pu = x0 >> s->sps->log2_min_pu_size;
int y_pu = y0 >> s->sps->log2_min_pu_size;
int min_pu_width = s->sps->min_pu_width;
int size_in_pus = pu_size >> s->sps->log2_min_pu_size;
- int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
- int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int x0b = av_mod_uintp2(x0, s->sps->log2_ctb_size);
+ int y0b = av_mod_uintp2(y0, s->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;
@@ -1960,15 +1863,7 @@ static int luma_intra_pred_mode(HEVCContext *s, int x0, int y0, int pu_size,
intra_pred_mode, size_in_pus);
for (j = 0; j < size_in_pus; j++) {
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].is_intra = 1;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].pred_flag[0] = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].pred_flag[1] = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].ref_idx[0] = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].ref_idx[1] = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].mv[0].x = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].mv[0].y = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].mv[1].x = 0;
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].mv[1].y = 0;
+ tab_mvf[(y_pu + j) * min_pu_width + x_pu + i].pred_flag = PF_INTRA;
}
}
@@ -1988,10 +1883,14 @@ static av_always_inline void set_ct_depth(HEVCContext *s, int x0, int y0,
ct_depth, length);
}
+static const uint8_t tab_mode_idx[] = {
+ 0, 1, 2, 2, 2, 2, 3, 5, 7, 8, 10, 12, 13, 15, 17, 18, 19, 20,
+ 21, 22, 23, 23, 24, 24, 25, 25, 26, 27, 27, 28, 28, 29, 29, 30, 31};
+
static void intra_prediction_unit(HEVCContext *s, int x0, int y0,
int log2_cb_size)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
static const uint8_t intra_chroma_table[4] = { 0, 26, 10, 1 };
uint8_t prev_intra_luma_pred_flag[4];
int split = lc->cu.part_mode == PART_NxN;
@@ -2017,14 +1916,42 @@ static void intra_prediction_unit(HEVCContext *s, int x0, int y0,
}
}
- chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
- if (chroma_mode != 4) {
- if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode])
- lc->pu.intra_pred_mode_c = 34;
- else
- lc->pu.intra_pred_mode_c = intra_chroma_table[chroma_mode];
- } else {
- lc->pu.intra_pred_mode_c = lc->pu.intra_pred_mode[0];
+ if (s->sps->chroma_format_idc == 3) {
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ lc->pu.chroma_mode_c[2 * i + j] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
+ if (chroma_mode != 4) {
+ if (lc->pu.intra_pred_mode[2 * i + j] == intra_chroma_table[chroma_mode])
+ lc->pu.intra_pred_mode_c[2 * i + j] = 34;
+ else
+ lc->pu.intra_pred_mode_c[2 * i + j] = intra_chroma_table[chroma_mode];
+ } else {
+ lc->pu.intra_pred_mode_c[2 * i + j] = lc->pu.intra_pred_mode[2 * i + j];
+ }
+ }
+ }
+ } else if (s->sps->chroma_format_idc == 2) {
+ int mode_idx;
+ lc->pu.chroma_mode_c[0] = chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
+ if (chroma_mode != 4) {
+ if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode])
+ mode_idx = 34;
+ else
+ mode_idx = intra_chroma_table[chroma_mode];
+ } else {
+ mode_idx = lc->pu.intra_pred_mode[0];
+ }
+ lc->pu.intra_pred_mode_c[0] = tab_mode_idx[mode_idx];
+ } else if (s->sps->chroma_format_idc != 0) {
+ chroma_mode = ff_hevc_intra_chroma_pred_mode_decode(s);
+ if (chroma_mode != 4) {
+ if (lc->pu.intra_pred_mode[0] == intra_chroma_table[chroma_mode])
+ lc->pu.intra_pred_mode_c[0] = 34;
+ else
+ lc->pu.intra_pred_mode_c[0] = intra_chroma_table[chroma_mode];
+ } else {
+ lc->pu.intra_pred_mode_c[0] = lc->pu.intra_pred_mode[0];
+ }
}
}
@@ -2032,7 +1959,7 @@ static void intra_prediction_unit_default_value(HEVCContext *s,
int x0, int y0,
int log2_cb_size)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int pb_size = 1 << log2_cb_size;
int size_in_pus = pb_size >> s->sps->log2_min_pu_size;
int min_pu_width = s->sps->min_pu_width;
@@ -2043,22 +1970,25 @@ static void intra_prediction_unit_default_value(HEVCContext *s,
if (size_in_pus == 0)
size_in_pus = 1;
- for (j = 0; j < size_in_pus; j++) {
+ 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);
- for (k = 0; k < size_in_pus; k++)
- tab_mvf[(y_pu + j) * min_pu_width + x_pu + k].is_intra = lc->cu.pred_mode == MODE_INTRA;
- }
+ 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(HEVCContext *s, int x0, int y0, int log2_cb_size)
{
int cb_size = 1 << log2_cb_size;
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int log2_min_cb_size = s->sps->log2_min_cb_size;
int length = cb_size >> log2_min_cb_size;
int min_cb_width = s->sps->min_cb_width;
int x_cb = x0 >> log2_min_cb_size;
int y_cb = y0 >> log2_min_cb_size;
+ int idx = log2_cb_size - 2;
+ int qp_block_mask = (1<<(s->sps->log2_ctb_size - s->pps->diff_cu_qp_delta_depth)) - 1;
int x, y, ret;
lc->cu.x = x0;
@@ -2086,10 +2016,16 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
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);
+ x += min_cb_width;
+ }
}
if (SAMPLE_CTB(s->skip_flag, x_cb, y_cb)) {
- hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0);
+ hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0, idx);
intra_prediction_unit_default_value(s, x0, y0, log2_cb_size);
if (!s->sh.disable_deblocking_filter_flag)
@@ -2127,37 +2063,37 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
intra_prediction_unit_default_value(s, x0, y0, log2_cb_size);
switch (lc->cu.part_mode) {
case PART_2Nx2N:
- hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0);
+ hls_prediction_unit(s, x0, y0, cb_size, cb_size, log2_cb_size, 0, idx);
break;
case PART_2NxN:
- hls_prediction_unit(s, x0, y0, cb_size, cb_size / 2, log2_cb_size, 0);
- hls_prediction_unit(s, x0, y0 + cb_size / 2, cb_size, cb_size / 2, log2_cb_size, 1);
+ hls_prediction_unit(s, x0, y0, cb_size, cb_size / 2, log2_cb_size, 0, idx);
+ hls_prediction_unit(s, x0, y0 + cb_size / 2, cb_size, cb_size / 2, log2_cb_size, 1, idx);
break;
case PART_Nx2N:
- hls_prediction_unit(s, x0, y0, cb_size / 2, cb_size, log2_cb_size, 0);
- hls_prediction_unit(s, x0 + cb_size / 2, y0, cb_size / 2, cb_size, log2_cb_size, 1);
+ hls_prediction_unit(s, x0, y0, cb_size / 2, cb_size, log2_cb_size, 0, idx - 1);
+ hls_prediction_unit(s, x0 + cb_size / 2, y0, cb_size / 2, cb_size, log2_cb_size, 1, idx - 1);
break;
case PART_2NxnU:
- hls_prediction_unit(s, x0, y0, cb_size, cb_size / 4, log2_cb_size, 0);
- hls_prediction_unit(s, x0, y0 + cb_size / 4, cb_size, cb_size * 3 / 4, log2_cb_size, 1);
+ hls_prediction_unit(s, x0, y0, cb_size, cb_size / 4, log2_cb_size, 0, idx);
+ hls_prediction_unit(s, x0, y0 + cb_size / 4, cb_size, cb_size * 3 / 4, log2_cb_size, 1, idx);
break;
case PART_2NxnD:
- hls_prediction_unit(s, x0, y0, cb_size, cb_size * 3 / 4, log2_cb_size, 0);
- hls_prediction_unit(s, x0, y0 + cb_size * 3 / 4, cb_size, cb_size / 4, log2_cb_size, 1);
+ hls_prediction_unit(s, x0, y0, cb_size, cb_size * 3 / 4, log2_cb_size, 0, idx);
+ hls_prediction_unit(s, x0, y0 + cb_size * 3 / 4, cb_size, cb_size / 4, log2_cb_size, 1, idx);
break;
case PART_nLx2N:
- hls_prediction_unit(s, x0, y0, cb_size / 4, cb_size, log2_cb_size, 0);
- hls_prediction_unit(s, x0 + cb_size / 4, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 1);
+ hls_prediction_unit(s, x0, y0, cb_size / 4, cb_size, log2_cb_size, 0, idx - 2);
+ hls_prediction_unit(s, x0 + cb_size / 4, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 1, idx - 2);
break;
case PART_nRx2N:
- hls_prediction_unit(s, x0, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 0);
- hls_prediction_unit(s, x0 + cb_size * 3 / 4, y0, cb_size / 4, cb_size, log2_cb_size, 1);
+ hls_prediction_unit(s, x0, y0, cb_size * 3 / 4, cb_size, log2_cb_size, 0, idx - 2);
+ hls_prediction_unit(s, x0 + cb_size * 3 / 4, y0, cb_size / 4, cb_size, log2_cb_size, 1, idx - 2);
break;
case PART_NxN:
- hls_prediction_unit(s, x0, y0, cb_size / 2, cb_size / 2, log2_cb_size, 0);
- hls_prediction_unit(s, x0 + cb_size / 2, y0, cb_size / 2, cb_size / 2, log2_cb_size, 1);
- hls_prediction_unit(s, x0, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 2);
- hls_prediction_unit(s, x0 + cb_size / 2, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 3);
+ hls_prediction_unit(s, x0, y0, cb_size / 2, cb_size / 2, log2_cb_size, 0, idx - 1);
+ hls_prediction_unit(s, x0 + cb_size / 2, y0, cb_size / 2, cb_size / 2, log2_cb_size, 1, idx - 1);
+ hls_prediction_unit(s, x0, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 2, idx - 1);
+ hls_prediction_unit(s, x0 + cb_size / 2, y0 + cb_size / 2, cb_size / 2, cb_size / 2, log2_cb_size, 3, idx - 1);
break;
}
}
@@ -2170,12 +2106,13 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
rqt_root_cbf = ff_hevc_no_residual_syntax_flag_decode(s);
}
if (rqt_root_cbf) {
+ const static int cbf[2] = { 0 };
lc->cu.max_trafo_depth = lc->cu.pred_mode == MODE_INTRA ?
s->sps->max_transform_hierarchy_depth_intra + lc->cu.intra_split_flag :
s->sps->max_transform_hierarchy_depth_inter;
ret = hls_transform_tree(s, x0, y0, x0, y0, x0, y0,
log2_cb_size,
- log2_cb_size, 0, 0, 0, 0);
+ log2_cb_size, 0, 0, cbf, cbf);
if (ret < 0)
return ret;
} else {
@@ -2186,7 +2123,7 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
}
if (s->pps->cu_qp_delta_enabled_flag && lc->tu.is_cu_qp_delta_coded == 0)
- ff_hevc_set_qPy(s, x0, y0, x0, y0, log2_cb_size);
+ ff_hevc_set_qPy(s, x0, y0, log2_cb_size);
x = y_cb * min_cb_width + x_cb;
for (y = 0; y < length; y++) {
@@ -2194,7 +2131,12 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
x += min_cb_width;
}
- set_ct_depth(s, x0, y0, log2_cb_size, lc->ct.depth);
+ if(((x0 + (1<<log2_cb_size)) & qp_block_mask) == 0 &&
+ ((y0 + (1<<log2_cb_size)) & qp_block_mask) == 0) {
+ lc->qPy_pred = lc->qp_y;
+ }
+
+ set_ct_depth(s, x0, y0, log2_cb_size, lc->ct_depth);
return 0;
}
@@ -2202,11 +2144,12 @@ static int hls_coding_unit(HEVCContext *s, int x0, int y0, int log2_cb_size)
static int hls_coding_quadtree(HEVCContext *s, int x0, int y0,
int log2_cb_size, int cb_depth)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
const int cb_size = 1 << log2_cb_size;
+ int ret;
int split_cu;
- lc->ct.depth = cb_depth;
+ lc->ct_depth = cb_depth;
if (x0 + cb_size <= s->sps->width &&
y0 + cb_size <= s->sps->height &&
log2_cb_size > s->sps->log2_min_cb_size) {
@@ -2220,31 +2163,64 @@ static int hls_coding_quadtree(HEVCContext *s, int x0, int y0,
lc->tu.cu_qp_delta = 0;
}
+ if (s->sh.cu_chroma_qp_offset_enabled_flag &&
+ log2_cb_size >= s->sps->log2_ctb_size - s->pps->diff_cu_chroma_qp_offset_depth) {
+ lc->tu.is_cu_chroma_qp_offset_coded = 0;
+ }
+
if (split_cu) {
+ int qp_block_mask = (1<<(s->sps->log2_ctb_size - s->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;
- log2_cb_size--;
- cb_depth++;
+ int more_data = 0;
-#define SUBDIVIDE(x, y) \
-do { \
- if (x < s->sps->width && y < s->sps->height) { \
- int ret = hls_coding_quadtree(s, x, y, log2_cb_size, cb_depth);\
- if (ret < 0) \
- return ret; \
- } \
-} while (0)
+ more_data = hls_coding_quadtree(s, x0, y0, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+
+ if (more_data && x1 < s->sps->width) {
+ more_data = hls_coding_quadtree(s, x1, y0, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+ }
+ if (more_data && y1 < s->sps->height) {
+ more_data = hls_coding_quadtree(s, x0, y1, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+ }
+ if (more_data && x1 < s->sps->width &&
+ y1 < s->sps->height) {
+ more_data = hls_coding_quadtree(s, x1, y1, log2_cb_size - 1, cb_depth + 1);
+ if (more_data < 0)
+ return more_data;
+ }
- SUBDIVIDE(x0, y0);
- SUBDIVIDE(x1, y0);
- SUBDIVIDE(x0, y1);
- SUBDIVIDE(x1, y1);
+ if(((x0 + (1<<log2_cb_size)) & qp_block_mask) == 0 &&
+ ((y0 + (1<<log2_cb_size)) & qp_block_mask) == 0)
+ lc->qPy_pred = lc->qp_y;
+
+ if (more_data)
+ return ((x1 + cb_size_split) < s->sps->width ||
+ (y1 + cb_size_split) < s->sps->height);
+ else
+ return 0;
} else {
- int ret = hls_coding_unit(s, x0, y0, log2_cb_size);
+ ret = hls_coding_unit(s, x0, y0, log2_cb_size);
if (ret < 0)
return ret;
+ if ((!((x0 + cb_size) %
+ (1 << (s->sps->log2_ctb_size))) ||
+ (x0 + cb_size >= s->sps->width)) &&
+ (!((y0 + cb_size) %
+ (1 << (s->sps->log2_ctb_size))) ||
+ (y0 + cb_size >= s->sps->height))) {
+ int end_of_slice_flag = ff_hevc_end_of_slice_flag_decode(s);
+ return !end_of_slice_flag;
+ } else {
+ return 1;
+ }
}
return 0;
@@ -2253,7 +2229,7 @@ do { \
static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
int ctb_addr_ts)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int ctb_size = 1 << s->sps->log2_ctb_size;
int ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
int ctb_addr_in_slice = ctb_addr_rs - s->sh.slice_addr;
@@ -2267,7 +2243,6 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
} else if (s->pps->tiles_enabled_flag) {
if (ctb_addr_ts && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) {
int idxX = s->pps->col_idxX[x_ctb >> s->sps->log2_ctb_size];
- lc->start_of_tiles_x = x_ctb;
lc->end_of_tiles_x = x_ctb + (s->pps->column_width[idxX] << s->sps->log2_ctb_size);
lc->first_qp_group = 1;
}
@@ -2288,7 +2263,7 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
if (y_ctb > 0 && s->tab_slice_address[ctb_addr_rs] != s->tab_slice_address[ctb_addr_rs - s->sps->ctb_width])
lc->boundary_flags |= BOUNDARY_UPPER_SLICE;
} else {
- if (!ctb_addr_in_slice > 0)
+ if (ctb_addr_in_slice <= 0)
lc->boundary_flags |= BOUNDARY_LEFT_SLICE;
if (ctb_addr_in_slice < s->sps->ctb_width)
lc->boundary_flags |= BOUNDARY_UPPER_SLICE;
@@ -2300,14 +2275,27 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0) && (ctb_addr_in_slice-1 >= s->sps->ctb_width) && (s->pps->tile_id[ctb_addr_ts] == s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1 - s->sps->ctb_width]]));
}
-static int hls_slice_data(HEVCContext *s)
+static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
{
+ HEVCContext *s = avctxt->priv_data;
int ctb_size = 1 << s->sps->log2_ctb_size;
int more_data = 1;
int x_ctb = 0;
int y_ctb = 0;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
- 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;
+ }
+
+ if (s->sh.dependent_slice_segment_flag) {
+ int prev_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts - 1];
+ if (s->tab_slice_address[prev_rs] != s->sh.slice_addr) {
+ av_log(s->avctx, AV_LOG_ERROR, "Previous slice segment missing\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
while (more_data && ctb_addr_ts < s->sps->ctb_size) {
int ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
@@ -2324,10 +2312,12 @@ static int hls_slice_data(HEVCContext *s)
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;
- ret = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0);
- if (ret < 0)
- return ret;
- more_data = !ff_hevc_end_of_slice_flag_decode(s);
+ more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0);
+ if (more_data < 0) {
+ s->tab_slice_address[ctb_addr_rs] = -1;
+ return more_data;
+ }
+
ctb_addr_ts++;
ff_hevc_save_states(s, ctb_addr_ts);
@@ -2336,18 +2326,187 @@ static int hls_slice_data(HEVCContext *s)
if (x_ctb + ctb_size >= s->sps->width &&
y_ctb + ctb_size >= s->sps->height)
- ff_hevc_hls_filter(s, x_ctb, y_ctb);
+ ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size);
return ctb_addr_ts;
}
+static int hls_slice_data(HEVCContext *s)
+{
+ int arg[2];
+ int ret[2];
+
+ arg[0] = 0;
+ arg[1] = 1;
+
+ s->avctx->execute(s->avctx, hls_decode_entry, arg, ret , 1, sizeof(int));
+ return ret[0];
+}
+static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int job, int self_id)
+{
+ HEVCContext *s1 = avctxt->priv_data, *s;
+ HEVCLocalContext *lc;
+ int ctb_size = 1<< s1->sps->log2_ctb_size;
+ int more_data = 1;
+ int *ctb_row_p = input_ctb_row;
+ int ctb_row = ctb_row_p[job];
+ int ctb_addr_rs = s1->sh.slice_ctb_addr_rs + ctb_row * ((s1->sps->width + ctb_size - 1) >> s1->sps->log2_ctb_size);
+ int ctb_addr_ts = s1->pps->ctb_addr_rs_to_ts[ctb_addr_rs];
+ int thread = ctb_row % s1->threads_number;
+ int ret;
+
+ s = s1->sList[self_id];
+ lc = s->HEVClc;
+
+ if(ctb_row) {
+ ret = init_get_bits8(&lc->gb, s->data + s->sh.offset[ctb_row - 1], s->sh.size[ctb_row - 1]);
+
+ if (ret < 0)
+ return ret;
+ ff_init_cabac_decoder(&lc->cc, s->data + s->sh.offset[(ctb_row)-1], s->sh.size[ctb_row - 1]);
+ }
+
+ while(more_data && ctb_addr_ts < s->sps->ctb_size) {
+ int x_ctb = (ctb_addr_rs % s->sps->ctb_width) << s->sps->log2_ctb_size;
+ int y_ctb = (ctb_addr_rs / s->sps->ctb_width) << s->sps->log2_ctb_size;
+
+ hls_decode_neighbour(s, x_ctb, y_ctb, ctb_addr_ts);
+
+ ff_thread_await_progress2(s->avctx, ctb_row, thread, SHIFT_CTB_WPP);
+
+ if (avpriv_atomic_int_get(&s1->wpp_err)){
+ ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP);
+ return 0;
+ }
+
+ ff_hevc_cabac_init(s, ctb_addr_ts);
+ hls_sao_param(s, x_ctb >> s->sps->log2_ctb_size, y_ctb >> s->sps->log2_ctb_size);
+ more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->sps->log2_ctb_size, 0);
+
+ if (more_data < 0) {
+ s->tab_slice_address[ctb_addr_rs] = -1;
+ return more_data;
+ }
+
+ ctb_addr_ts++;
+
+ ff_hevc_save_states(s, ctb_addr_ts);
+ ff_thread_report_progress2(s->avctx, ctb_row, thread, 1);
+ ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size);
+
+ if (!more_data && (x_ctb+ctb_size) < s->sps->width && ctb_row != s->sh.num_entry_point_offsets) {
+ avpriv_atomic_int_set(&s1->wpp_err, 1);
+ ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
+ return 0;
+ }
+
+ if ((x_ctb+ctb_size) >= s->sps->width && (y_ctb+ctb_size) >= s->sps->height ) {
+ ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size);
+ ff_thread_report_progress2(s->avctx, ctb_row , thread, SHIFT_CTB_WPP);
+ return ctb_addr_ts;
+ }
+ ctb_addr_rs = s->pps->ctb_addr_ts_to_rs[ctb_addr_ts];
+ x_ctb+=ctb_size;
+
+ if(x_ctb >= s->sps->width) {
+ break;
+ }
+ }
+ ff_thread_report_progress2(s->avctx, ctb_row ,thread, SHIFT_CTB_WPP);
+
+ return 0;
+}
+
+static int hls_slice_data_wpp(HEVCContext *s, const uint8_t *nal, int length)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ int *ret = av_malloc_array(s->sh.num_entry_point_offsets + 1, sizeof(int));
+ int *arg = av_malloc_array(s->sh.num_entry_point_offsets + 1, sizeof(int));
+ int offset;
+ int startheader, cmpt = 0;
+ int i, j, res = 0;
+
+ if (!ret || !arg) {
+ av_free(ret);
+ av_free(arg);
+ return AVERROR(ENOMEM);
+ }
+
+
+ if (!s->sList[1]) {
+ ff_alloc_entries(s->avctx, s->sh.num_entry_point_offsets + 1);
+
+
+ for (i = 1; i < s->threads_number; i++) {
+ s->sList[i] = av_malloc(sizeof(HEVCContext));
+ memcpy(s->sList[i], s, sizeof(HEVCContext));
+ s->HEVClcList[i] = av_mallocz(sizeof(HEVCLocalContext));
+ s->sList[i]->HEVClc = s->HEVClcList[i];
+ }
+ }
+
+ offset = (lc->gb.index >> 3);
+
+ for (j = 0, cmpt = 0, startheader = offset + s->sh.entry_point_offset[0]; j < s->skipped_bytes; j++) {
+ if (s->skipped_bytes_pos[j] >= offset && s->skipped_bytes_pos[j] < startheader) {
+ startheader--;
+ cmpt++;
+ }
+ }
+
+ for (i = 1; i < s->sh.num_entry_point_offsets; i++) {
+ offset += (s->sh.entry_point_offset[i - 1] - cmpt);
+ for (j = 0, cmpt = 0, startheader = offset
+ + s->sh.entry_point_offset[i]; j < s->skipped_bytes; j++) {
+ if (s->skipped_bytes_pos[j] >= offset && s->skipped_bytes_pos[j] < startheader) {
+ startheader--;
+ cmpt++;
+ }
+ }
+ s->sh.size[i - 1] = s->sh.entry_point_offset[i] - cmpt;
+ s->sh.offset[i - 1] = offset;
+
+ }
+ if (s->sh.num_entry_point_offsets != 0) {
+ offset += s->sh.entry_point_offset[s->sh.num_entry_point_offsets - 1] - cmpt;
+ s->sh.size[s->sh.num_entry_point_offsets - 1] = length - offset;
+ s->sh.offset[s->sh.num_entry_point_offsets - 1] = offset;
+
+ }
+ s->data = nal;
+
+ for (i = 1; i < s->threads_number; i++) {
+ s->sList[i]->HEVClc->first_qp_group = 1;
+ s->sList[i]->HEVClc->qp_y = s->sList[0]->HEVClc->qp_y;
+ memcpy(s->sList[i], s, sizeof(HEVCContext));
+ s->sList[i]->HEVClc = s->HEVClcList[i];
+ }
+
+ avpriv_atomic_int_set(&s->wpp_err, 0);
+ ff_reset_entries(s->avctx);
+
+ for (i = 0; i <= s->sh.num_entry_point_offsets; i++) {
+ arg[i] = i;
+ ret[i] = 0;
+ }
+
+ if (s->pps->entropy_coding_sync_enabled_flag)
+ s->avctx->execute2(s->avctx, (void *) hls_decode_entry_wpp, arg, ret, s->sh.num_entry_point_offsets + 1);
+
+ for (i = 0; i <= s->sh.num_entry_point_offsets; i++)
+ res += ret[i];
+ av_free(ret);
+ av_free(arg);
+ return res;
+}
+
/**
* @return AVERROR_INVALIDDATA if the packet is not a valid NAL unit,
* 0 if the unit should be skipped, 1 otherwise
*/
static int hls_nal_unit(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
int nuh_layer_id;
if (get_bits1(gb) != 0)
@@ -2361,39 +2520,12 @@ static int hls_nal_unit(HEVCContext *s)
return AVERROR_INVALIDDATA;
av_log(s->avctx, AV_LOG_DEBUG,
- "nal_unit_type: %d, nuh_layer_id: %dtemporal_id: %d\n",
+ "nal_unit_type: %d, nuh_layer_id: %d, temporal_id: %d\n",
s->nal_unit_type, nuh_layer_id, s->temporal_id);
return nuh_layer_id == 0;
}
-static void restore_tqb_pixels(HEVCContext *s)
-{
- int min_pu_size = 1 << s->sps->log2_min_pu_size;
- int x, y, c_idx;
-
- for (c_idx = 0; c_idx < 3; c_idx++) {
- ptrdiff_t stride = s->frame->linesize[c_idx];
- int hshift = s->sps->hshift[c_idx];
- int vshift = s->sps->vshift[c_idx];
- for (y = 0; y < s->sps->min_pu_height; y++) {
- for (x = 0; x < s->sps->min_pu_width; x++) {
- if (s->is_pcm[y * s->sps->min_pu_width + x]) {
- int n;
- int len = min_pu_size >> hshift;
- uint8_t *src = &s->frame->data[c_idx][((y << s->sps->log2_min_pu_size) >> vshift) * stride + (((x << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift)];
- uint8_t *dst = &s->sao_frame->data[c_idx][((y << s->sps->log2_min_pu_size) >> vshift) * stride + (((x << s->sps->log2_min_pu_size) >> hshift) << s->sps->pixel_shift)];
- for (n = 0; n < (min_pu_size >> vshift); n++) {
- memcpy(dst, src, len);
- src += stride;
- dst += stride;
- }
- }
- }
- }
- }
-}
-
static int set_side_data(HEVCContext *s)
{
AVFrame *out = s->ref->frame;
@@ -2445,23 +2577,24 @@ static int set_side_data(HEVCContext *s)
static int hevc_frame_start(HEVCContext *s)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
+ int pic_size_in_ctb = ((s->sps->width >> s->sps->log2_min_cb_size) + 1) *
+ ((s->sps->height >> s->sps->log2_min_cb_size) + 1);
int ret;
- memset(s->horizontal_bs, 0, 2 * s->bs_width * (s->bs_height + 1));
- memset(s->vertical_bs, 0, 2 * s->bs_width * (s->bs_height + 1));
+ memset(s->horizontal_bs, 0, s->bs_width * s->bs_height);
+ memset(s->vertical_bs, 0, s->bs_width * s->bs_height);
memset(s->cbf_luma, 0, s->sps->min_tb_width * s->sps->min_tb_height);
- memset(s->is_pcm, 0, s->sps->min_pu_width * s->sps->min_pu_height);
+ memset(s->is_pcm, 0, (s->sps->min_pu_width + 1) * (s->sps->min_pu_height + 1));
+ memset(s->tab_slice_address, -1, pic_size_in_ctb * sizeof(*s->tab_slice_address));
- lc->start_of_tiles_x = 0;
s->is_decoded = 0;
s->first_nal_type = s->nal_unit_type;
if (s->pps->tiles_enabled_flag)
lc->end_of_tiles_x = s->pps->column_width[0] << s->sps->log2_ctb_size;
- ret = ff_hevc_set_new_ref(s, s->sps->sao_enabled ? &s->sao_frame : &s->frame,
- s->poc);
+ ret = ff_hevc_set_new_ref(s, &s->frame, s->poc);
if (ret < 0)
goto fail;
@@ -2477,12 +2610,18 @@ static int hevc_frame_start(HEVCContext *s)
if (ret < 0)
goto fail;
+ s->frame->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);
if (ret < 0)
goto fail;
- ff_thread_finish_setup(s->avctx);
+ if (!s->avctx->hwaccel)
+ ff_thread_finish_setup(s->avctx);
return 0;
@@ -2495,7 +2634,7 @@ fail:
static int decode_nal_unit(HEVCContext *s, const HEVCNAL *nal)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
GetBitContext *gb = &lc->gb;
int ctb_addr_ts, ret;
@@ -2608,13 +2747,12 @@ static int decode_nal_unit(HEVCContext *s, const HEVCNAL *nal)
if (ret < 0)
goto fail;
} else {
- ctb_addr_ts = hls_slice_data(s);
+ if (s->threads_number > 1 && s->sh.num_entry_point_offsets > 0)
+ ctb_addr_ts = hls_slice_data_wpp(s, nal->data, nal->size);
+ else
+ ctb_addr_ts = hls_slice_data(s);
if (ctb_addr_ts >= (s->sps->ctb_width * s->sps->ctb_height)) {
s->is_decoded = 1;
- if ((s->pps->transquant_bypass_enable_flag ||
- (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) &&
- s->sps->sao_enabled)
- restore_tqb_pixels(s);
}
if (ctb_addr_ts < 0) {
@@ -2645,12 +2783,13 @@ fail:
/* FIXME: This is adapted from ff_h264_decode_nal, avoiding duplication
* between these functions would be nice. */
-static int extract_rbsp(const uint8_t *src, int length,
- HEVCNAL *nal)
+int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length,
+ HEVCNAL *nal)
{
int i, si, di;
uint8_t *dst;
+ s->skipped_bytes = 0;
#define STARTCODE_TEST \
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3) { \
if (src[i + 2] != 3) { \
@@ -2724,6 +2863,17 @@ static int extract_rbsp(const uint8_t *src, int length,
dst[di++] = 0;
si += 3;
+ s->skipped_bytes++;
+ if (s->skipped_bytes_pos_size < s->skipped_bytes) {
+ s->skipped_bytes_pos_size *= 2;
+ av_reallocp_array(&s->skipped_bytes_pos,
+ s->skipped_bytes_pos_size,
+ sizeof(*s->skipped_bytes_pos));
+ if (!s->skipped_bytes_pos)
+ return AVERROR(ENOMEM);
+ }
+ if (s->skipped_bytes_pos)
+ s->skipped_bytes_pos[s->skipped_bytes-1] = di - 1;
continue;
} else // next start code
goto nsc;
@@ -2749,6 +2899,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
int i, consumed, ret = 0;
s->ref = NULL;
+ s->last_eos = s->eos;
s->eos = 0;
/* split the input packet into NAL units, so we know the upper bound on the
@@ -2771,42 +2922,73 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
goto fail;
}
} else {
- if (buf[2] == 0) {
- length--;
- buf++;
- continue;
- }
- if (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) {
- ret = AVERROR_INVALIDDATA;
- goto fail;
+ /* search start code */
+ while (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) {
+ ++buf;
+ --length;
+ if (length < 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "No start code is found.\n");
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
}
buf += 3;
length -= 3;
- extract_length = length;
}
+ if (!s->is_nalff)
+ extract_length = length;
+
if (s->nals_allocated < s->nb_nals + 1) {
int new_size = s->nals_allocated + 1;
- HEVCNAL *tmp = av_realloc_array(s->nals, new_size, sizeof(*tmp));
+ void *tmp = av_realloc_array(s->nals, new_size, sizeof(*s->nals));
+ ret = AVERROR(ENOMEM);
if (!tmp) {
- ret = AVERROR(ENOMEM);
goto fail;
}
s->nals = tmp;
memset(s->nals + s->nals_allocated, 0,
- (new_size - s->nals_allocated) * sizeof(*tmp));
+ (new_size - s->nals_allocated) * sizeof(*s->nals));
+
+ tmp = av_realloc_array(s->skipped_bytes_nal, new_size, sizeof(*s->skipped_bytes_nal));
+ if (!tmp)
+ goto fail;
+ s->skipped_bytes_nal = tmp;
+
+ tmp = av_realloc_array(s->skipped_bytes_pos_size_nal, new_size, sizeof(*s->skipped_bytes_pos_size_nal));
+ if (!tmp)
+ goto fail;
+ s->skipped_bytes_pos_size_nal = tmp;
+
+ tmp = av_realloc_array(s->skipped_bytes_pos_nal, new_size, sizeof(*s->skipped_bytes_pos_nal));
+ if (!tmp)
+ goto fail;
+ s->skipped_bytes_pos_nal = tmp;
+
+ s->skipped_bytes_pos_size_nal[s->nals_allocated] = 1024; // initial buffer size
+ s->skipped_bytes_pos_nal[s->nals_allocated] = av_malloc_array(s->skipped_bytes_pos_size_nal[s->nals_allocated], sizeof(*s->skipped_bytes_pos));
+ if (!s->skipped_bytes_pos_nal[s->nals_allocated])
+ goto fail;
s->nals_allocated = new_size;
}
- nal = &s->nals[s->nb_nals++];
+ s->skipped_bytes_pos_size = s->skipped_bytes_pos_size_nal[s->nb_nals];
+ s->skipped_bytes_pos = s->skipped_bytes_pos_nal[s->nb_nals];
+ nal = &s->nals[s->nb_nals];
+
+ consumed = ff_hevc_extract_rbsp(s, buf, extract_length, nal);
+
+ s->skipped_bytes_nal[s->nb_nals] = s->skipped_bytes;
+ s->skipped_bytes_pos_size_nal[s->nb_nals] = s->skipped_bytes_pos_size;
+ s->skipped_bytes_pos_nal[s->nb_nals++] = s->skipped_bytes_pos;
+
- consumed = extract_rbsp(buf, extract_length, nal);
if (consumed < 0) {
ret = consumed;
goto fail;
}
- ret = init_get_bits8(&s->HEVClc.gb, nal->data, nal->size);
+ ret = init_get_bits8(&s->HEVClc->gb, nal->data, nal->size);
if (ret < 0)
goto fail;
hls_nal_unit(s);
@@ -2821,6 +3003,9 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
/* parse the NAL units */
for (i = 0; i < s->nb_nals; i++) {
+ s->skipped_bytes = s->skipped_bytes_nal[i];
+ s->skipped_bytes_pos = s->skipped_bytes_pos_nal[i];
+
ret = decode_nal_unit(s, &s->nals[i]);
if (ret < 0) {
av_log(s->avctx, AV_LOG_WARNING,
@@ -2830,7 +3015,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
}
fail:
- if (s->ref)
+ if (s->ref && s->threads_type == FF_THREAD_FRAME)
ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
return ret;
@@ -2961,7 +3146,9 @@ static int hevc_decode_frame(AVCodecContext *avctx, void *data, int *got_output,
static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
{
- int ret = ff_thread_ref_frame(&dst->tf, &src->tf);
+ int ret;
+
+ ret = ff_thread_ref_frame(&dst->tf, &src->tf);
if (ret < 0)
return ret;
@@ -3007,7 +3194,19 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->md5_ctx);
- av_frame_free(&s->tmp_frame);
+ for(i=0; i < s->nals_allocated; i++) {
+ av_freep(&s->skipped_bytes_pos_nal[i]);
+ }
+ av_freep(&s->skipped_bytes_pos_size_nal);
+ av_freep(&s->skipped_bytes_nal);
+ av_freep(&s->skipped_bytes_pos_nal);
+
+ av_freep(&s->cabac_state);
+
+ 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);
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
@@ -3021,6 +3220,24 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_buffer_unref(&s->sps_list[i]);
for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++)
av_buffer_unref(&s->pps_list[i]);
+ s->sps = NULL;
+ s->pps = NULL;
+ s->vps = NULL;
+
+ av_freep(&s->sh.entry_point_offset);
+ av_freep(&s->sh.offset);
+ av_freep(&s->sh.size);
+
+ for (i = 1; i < s->threads_number; i++) {
+ HEVCLocalContext *lc = s->HEVClcList[i];
+ if (lc) {
+ av_freep(&s->HEVClcList[i]);
+ av_freep(&s->sList[i]);
+ }
+ }
+ if (s->HEVClc == s->HEVClcList[0])
+ s->HEVClc = NULL;
+ av_freep(&s->HEVClcList[0]);
for (i = 0; i < s->nals_allocated; i++)
av_freep(&s->nals[i].rbsp_buffer);
@@ -3037,8 +3254,14 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->avctx = avctx;
- s->tmp_frame = av_frame_alloc();
- if (!s->tmp_frame)
+ s->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
+ if (!s->HEVClc)
+ goto fail;
+ s->HEVClcList[0] = s->HEVClc;
+ s->sList[0] = s;
+
+ s->cabac_state = av_malloc(HEVC_CONTEXTS);
+ if (!s->cabac_state)
goto fail;
s->output_frame = av_frame_alloc();
@@ -3061,6 +3284,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
ff_bswapdsp_init(&s->bdsp);
s->context_initialized = 1;
+ s->eos = 0;
return 0;
@@ -3091,6 +3315,8 @@ static int hevc_update_thread_context(AVCodecContext *dst,
}
}
+ if (s->sps != s0->sps)
+ s->sps = NULL;
for (i = 0; i < FF_ARRAY_ELEMS(s->vps_list); i++) {
av_buffer_unref(&s->vps_list[i]);
if (s0->vps_list[i]) {
@@ -3119,16 +3345,21 @@ static int hevc_update_thread_context(AVCodecContext *dst,
}
if (s->sps != s0->sps)
- ret = set_sps(s, s0->sps);
+ if ((ret = set_sps(s, s0->sps, src->pix_fmt)) < 0)
+ return ret;
s->seq_decode = s0->seq_decode;
s->seq_output = s0->seq_output;
s->pocTid0 = s0->pocTid0;
s->max_ra = s0->max_ra;
+ s->eos = s0->eos;
s->is_nalff = s0->is_nalff;
s->nal_length_size = s0->nal_length_size;
+ s->threads_number = s0->threads_number;
+ s->threads_type = s0->threads_type;
+
if (s0->eos) {
s->seq_decode = (s->seq_decode + 1) & 0xff;
s->max_ra = INT_MAX;
@@ -3224,6 +3455,14 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx)
if (ret < 0)
return ret;
+ s->enable_parallel_tiles = 0;
+ s->picture_struct = 0;
+
+ if(avctx->active_thread_type & FF_THREAD_SLICE)
+ s->threads_number = avctx->thread_count;
+ else
+ s->threads_number = 1;
+
if (avctx->extradata_size > 0 && avctx->extradata) {
ret = hevc_decode_extradata(s);
if (ret < 0) {
@@ -3232,6 +3471,11 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx)
}
}
+ if((avctx->active_thread_type & FF_THREAD_FRAME) && avctx->thread_count > 1)
+ s->threads_type = FF_THREAD_FRAME;
+ else
+ s->threads_type = FF_THREAD_SLICE;
+
return 0;
}
@@ -3263,12 +3507,15 @@ static const AVProfile profiles[] = {
{ FF_PROFILE_HEVC_MAIN, "Main" },
{ FF_PROFILE_HEVC_MAIN_10, "Main 10" },
{ FF_PROFILE_HEVC_MAIN_STILL_PICTURE, "Main Still Picture" },
+ { FF_PROFILE_HEVC_REXT, "Rext" },
{ FF_PROFILE_UNKNOWN },
};
static const AVOption options[] = {
{ "apply_defdispwin", "Apply default display window from VUI", OFFSET(apply_defdispwin),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, PAR },
+ { "strict-displaywin", "stricly apply default display window size", OFFSET(apply_defdispwin),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, PAR },
{ NULL },
};
@@ -3293,6 +3540,6 @@ AVCodec ff_hevc_decoder = {
.update_thread_context = hevc_update_thread_context,
.init_thread_copy = hevc_init_thread_copy,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY |
- CODEC_CAP_FRAME_THREADS,
+ CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,
.profiles = NULL_IF_CONFIG_SMALL(profiles),
};
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
index 068c10a8ff..eecccb7f16 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -3,29 +3,26 @@
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_HEVC_H
#define AVCODEC_HEVC_H
-#include <stddef.h>
-#include <stdint.h>
-
#include "libavutil/buffer.h"
#include "libavutil/md5.h"
@@ -33,6 +30,7 @@
#include "bswapdsp.h"
#include "cabac.h"
#include "get_bits.h"
+#include "hevcpred.h"
#include "hevcdsp.h"
#include "internal.h"
#include "thread.h"
@@ -41,6 +39,9 @@
#define MAX_DPB_SIZE 16 // A.4.1
#define MAX_REFS 16
+#define MAX_NB_THREADS 16
+#define SHIFT_CTB_WPP 2
+
/**
* 7.4.2.1
*/
@@ -55,12 +56,11 @@
#define MAX_TRANSFORM_DEPTH 5
#define MAX_TB_SIZE 32
-#define MAX_PB_SIZE 64
#define MAX_LOG2_CTB_SIZE 6
#define MAX_QP 51
#define DEFAULT_INTRA_TC_OFFSET 2
-#define HEVC_CONTEXTS 183
+#define HEVC_CONTEXTS 199
#define MRG_MAX_NUM_CANDS 5
@@ -70,6 +70,9 @@
#define EPEL_EXTRA_BEFORE 1
#define EPEL_EXTRA_AFTER 2
#define EPEL_EXTRA 3
+#define QPEL_EXTRA_BEFORE 3
+#define QPEL_EXTRA_AFTER 4
+#define QPEL_EXTRA 7
#define EDGE_EMU_BUFFER_STRIDE 80
@@ -79,13 +82,10 @@
#define SAMPLE(tab, x, y) ((tab)[(y) * s->sps->width + (x)])
#define SAMPLE_CTB(tab, x, y) ((tab)[(y) * min_cb_width + (x)])
-#define IS_IDR(s) (s->nal_unit_type == NAL_IDR_W_RADL || s->nal_unit_type == NAL_IDR_N_LP)
-#define IS_BLA(s) (s->nal_unit_type == NAL_BLA_W_RADL || s->nal_unit_type == NAL_BLA_W_LP || \
- s->nal_unit_type == NAL_BLA_N_LP)
-#define IS_IRAP(s) (s->nal_unit_type >= 16 && s->nal_unit_type <= 23)
-
-#define FFUDIV(a,b) (((a) > 0 ? (a) : (a) - (b) + 1) / (b))
-#define FFUMOD(a,b) ((a) - (b) * FFUDIV(a,b))
+#define IS_IDR(s) ((s)->nal_unit_type == NAL_IDR_W_RADL || (s)->nal_unit_type == NAL_IDR_N_LP)
+#define IS_BLA(s) ((s)->nal_unit_type == NAL_BLA_W_RADL || (s)->nal_unit_type == NAL_BLA_W_LP || \
+ (s)->nal_unit_type == NAL_BLA_N_LP)
+#define IS_IRAP(s) ((s)->nal_unit_type >= 16 && (s)->nal_unit_type <= 23)
/**
* Table 7-3: NAL unit type codes
@@ -167,6 +167,8 @@ enum SyntaxElement {
CBF_LUMA,
CBF_CB_CR,
TRANSFORM_SKIP_FLAG,
+ EXPLICIT_RDPCM_FLAG,
+ EXPLICIT_RDPCM_DIR_FLAG,
LAST_SIGNIFICANT_COEFF_X_PREFIX,
LAST_SIGNIFICANT_COEFF_Y_PREFIX,
LAST_SIGNIFICANT_COEFF_X_SUFFIX,
@@ -177,6 +179,10 @@ enum SyntaxElement {
COEFF_ABS_LEVEL_GREATER2_FLAG,
COEFF_ABS_LEVEL_REMAINING,
COEFF_SIGN_FLAG,
+ LOG2_RES_SCALE_ABS,
+ RES_SCALE_SIGN_FLAG,
+ CU_CHROMA_QP_OFFSET_FLAG,
+ CU_CHROMA_QP_OFFSET_IDX,
};
enum PartMode {
@@ -202,6 +208,13 @@ enum InterPredIdc {
PRED_BI,
};
+enum PredFlag {
+ PF_INTRA = 0,
+ PF_L0,
+ PF_L1,
+ PF_BI,
+};
+
enum IntraPredMode {
INTRA_PLANAR = 0,
INTRA_DC,
@@ -244,6 +257,7 @@ enum SAOType {
SAO_NOT_APPLIED = 0,
SAO_BAND,
SAO_EDGE,
+ SAO_APPLIED
};
enum SAOEOClass {
@@ -381,7 +395,7 @@ typedef struct ScalingList {
} ScalingList;
typedef struct HEVCSPS {
- int vps_id;
+ unsigned vps_id;
int chroma_format_idc;
uint8_t separate_colour_plane_flag;
@@ -442,6 +456,13 @@ typedef struct HEVCSPS {
int max_transform_hierarchy_depth_inter;
int max_transform_hierarchy_depth_intra;
+ int transform_skip_rotation_enabled_flag;
+ int transform_skip_context_enabled_flag;
+ int implicit_rdpcm_enabled_flag;
+ int explicit_rdpcm_enabled_flag;
+ int intra_smoothing_disabled_flag;
+ int persistent_rice_adaptation_enabled_flag;
+
///< coded frame dimension in various units
int width;
int height;
@@ -454,6 +475,7 @@ typedef struct HEVCSPS {
int min_tb_height;
int min_pu_width;
int min_pu_height;
+ int tb_mask;
int hshift[3];
int vshift[3];
@@ -510,6 +532,15 @@ typedef struct HEVCPPS {
int log2_parallel_merge_level; ///< log2_parallel_merge_level_minus2 + 2
int num_extra_slice_header_bits;
uint8_t slice_header_extension_present_flag;
+ uint8_t log2_max_transform_skip_block_size;
+ uint8_t cross_component_prediction_enabled_flag;
+ uint8_t chroma_qp_offset_list_enabled_flag;
+ uint8_t diff_cu_chroma_qp_offset_depth;
+ uint8_t chroma_qp_offset_list_len_minus1;
+ int8_t cb_qp_offset_list[5];
+ int8_t cr_qp_offset_list[5];
+ uint8_t log2_sao_offset_scale_luma;
+ uint8_t log2_sao_offset_scale_chroma;
// Inferred parameters
unsigned int *column_width; ///< ColumnWidth
@@ -523,6 +554,7 @@ typedef struct HEVCPPS {
int *tile_id; ///< TileId
int *tile_pos_rs; ///< TilePosRS
int *min_tb_addr_zs; ///< MinTbAddrZS
+ int *min_tb_addr_zs_tab;///< MinTbAddrZS
} HEVCPPS;
typedef struct SliceHeader {
@@ -570,11 +602,16 @@ typedef struct SliceHeader {
int slice_cb_qp_offset;
int slice_cr_qp_offset;
+ uint8_t cu_chroma_qp_offset_enabled_flag;
+
int beta_offset; ///< beta_offset_div2 * 2
int tc_offset; ///< tc_offset_div2 * 2
unsigned int max_num_merge_cand; ///< 5 - 5_minus_max_num_merge_cand
+ int *entry_point_offset;
+ int * offset;
+ int * size;
int num_entry_point_offsets;
int8_t slice_qp;
@@ -596,10 +633,6 @@ typedef struct SliceHeader {
int slice_ctb_addr_rs;
} SliceHeader;
-typedef struct CodingTree {
- int depth; ///< ctDepth
-} CodingTree;
-
typedef struct CodingUnit {
int x;
int y;
@@ -621,8 +654,7 @@ typedef struct Mv {
typedef struct MvField {
DECLARE_ALIGNED(4, Mv, mv)[2];
int8_t ref_idx[2];
- int8_t pred_flag[2];
- uint8_t is_intra;
+ int8_t pred_flag;
} MvField;
typedef struct NeighbourAvailable {
@@ -640,15 +672,24 @@ typedef struct PredictionUnit {
uint8_t intra_pred_mode[4];
Mv mvd;
uint8_t merge_flag;
- uint8_t intra_pred_mode_c;
+ uint8_t intra_pred_mode_c[4];
+ uint8_t chroma_mode_c[4];
} PredictionUnit;
typedef struct TransformUnit {
int cu_qp_delta;
+ int res_scale_val;
+
// Inferred parameters;
- int cur_intra_pred_mode;
+ int intra_pred_mode;
+ int intra_pred_mode_c;
+ int chroma_mode_c;
uint8_t is_cu_qp_delta_coded;
+ uint8_t is_cu_chroma_qp_offset_coded;
+ int8_t cu_qp_offset_cb;
+ int8_t cu_qp_offset_cr;
+ uint8_t cross_pf;
} TransformUnit;
typedef struct DBParams {
@@ -659,6 +700,7 @@ 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)
typedef struct HEVCFrame {
AVFrame *frame;
@@ -702,24 +744,11 @@ typedef struct HEVCNAL {
const uint8_t *raw_data;
} HEVCNAL;
-struct HEVCContext;
-
-typedef struct HEVCPredContext {
- void (*intra_pred[4])(struct HEVCContext *s, int x0, int y0, int c_idx);
-
- void (*pred_planar[4])(uint8_t *src, const uint8_t *top,
- const uint8_t *left, ptrdiff_t stride);
- void (*pred_dc)(uint8_t *src, const uint8_t *top, const uint8_t *left,
- ptrdiff_t stride, int log2_size, int c_idx);
- void (*pred_angular[4])(uint8_t *src, const uint8_t *top,
- const uint8_t *left, ptrdiff_t stride,
- int c_idx, int mode);
-} HEVCPredContext;
-
typedef struct HEVCLocalContext {
- DECLARE_ALIGNED(16, int16_t, mc_buffer[(MAX_PB_SIZE + 7) * MAX_PB_SIZE]);
uint8_t cabac_state[HEVC_CONTEXTS];
+ uint8_t stat_coeff[4];
+
uint8_t first_qp_group;
GetBitContext gb;
@@ -728,18 +757,23 @@ typedef struct HEVCLocalContext {
int8_t qp_y;
int8_t curr_qp_y;
+ int qPy_pred;
+
TransformUnit tu;
uint8_t ctb_left_flag;
uint8_t ctb_up_flag;
uint8_t ctb_up_right_flag;
uint8_t ctb_up_left_flag;
- int start_of_tiles_x;
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];
- CodingTree ct;
+ /* 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];
+ DECLARE_ALIGNED(32, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]);
+
+ int ct_depth;
CodingUnit cu;
PredictionUnit pu;
NeighbourAvailable na;
@@ -757,17 +791,26 @@ typedef struct HEVCContext {
const AVClass *c; // needed by private avoptions
AVCodecContext *avctx;
- HEVCLocalContext HEVClc;
+ struct HEVCContext *sList[MAX_NB_THREADS];
- uint8_t cabac_state[HEVC_CONTEXTS];
+ HEVCLocalContext *HEVClcList[MAX_NB_THREADS];
+ HEVCLocalContext *HEVClc;
+
+ uint8_t threads_type;
+ uint8_t threads_number;
+
+ int width;
+ int height;
+
+ uint8_t *cabac_state;
/** 1 if the independent slice segment header was successfully parsed */
uint8_t slice_initialized;
AVFrame *frame;
- AVFrame *sao_frame;
- AVFrame *tmp_frame;
AVFrame *output_frame;
+ uint8_t *sao_pixel_buffer_h[3];
+ uint8_t *sao_pixel_buffer_v[3];
const HEVCVPS *vps;
const HEVCSPS *sps;
@@ -793,6 +836,7 @@ typedef struct HEVCContext {
int pocTid0;
int slice_idx; ///< number of the slice being currently decoded
int eos; ///< current packet contains an EOS/EOB NAL
+ int last_eos; ///< last packet contains an EOS/EOB NAL
int max_ra;
int bs_width;
int bs_height;
@@ -832,6 +876,18 @@ typedef struct HEVCContext {
uint16_t seq_decode;
uint16_t seq_output;
+ int enable_parallel_tiles;
+ int wpp_err;
+ int skipped_bytes;
+ int *skipped_bytes_pos;
+ int skipped_bytes_pos_size;
+
+ int *skipped_bytes_nal;
+ int **skipped_bytes_pos_nal;
+ int *skipped_bytes_pos_size_nal;
+
+ const uint8_t *data;
+
HEVCNAL *nals;
int nb_nals;
int nals_allocated;
@@ -848,6 +904,8 @@ typedef struct HEVCContext {
///< as a format defined in 14496-15
int apply_defdispwin;
+ int active_seq_parameter_set_id;
+
int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4)
int nuh_layer_id;
@@ -861,6 +919,8 @@ typedef struct HEVCContext {
int sei_display_orientation_present;
int sei_anticlockwise_rotation;
int sei_hflip, sei_vflip;
+
+ int picture_struct;
} HEVCContext;
int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
@@ -870,6 +930,9 @@ int ff_hevc_decode_nal_sps(HEVCContext *s);
int ff_hevc_decode_nal_pps(HEVCContext *s);
int ff_hevc_decode_nal_sei(HEVCContext *s);
+int ff_hevc_extract_rbsp(HEVCContext *s, const uint8_t *src, int length,
+ HEVCNAL *nal);
+
/**
* Mark all frames in DPB as unused for reference.
*/
@@ -925,32 +988,11 @@ int ff_hevc_inter_pred_idc_decode(HEVCContext *s, int nPbW, int nPbH);
int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx);
int ff_hevc_mvp_lx_flag_decode(HEVCContext *s);
int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s);
-int ff_hevc_abs_mvd_greater0_flag_decode(HEVCContext *s);
-int ff_hevc_abs_mvd_greater1_flag_decode(HEVCContext *s);
-int ff_hevc_mvd_decode(HEVCContext *s);
-int ff_hevc_mvd_sign_flag_decode(HEVCContext *s);
int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size);
int ff_hevc_cbf_cb_cr_decode(HEVCContext *s, int trafo_depth);
int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth);
-int ff_hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx);
-int ff_hevc_last_significant_coeff_x_prefix_decode(HEVCContext *s, int c_idx,
- int log2_size);
-int ff_hevc_last_significant_coeff_y_prefix_decode(HEVCContext *s, int c_idx,
- int log2_size);
-int ff_hevc_last_significant_coeff_suffix_decode(HEVCContext *s,
- int last_significant_coeff_prefix);
-int ff_hevc_significant_coeff_group_flag_decode(HEVCContext *s, int c_idx,
- int ctx_cg);
-int ff_hevc_significant_coeff_flag_decode(HEVCContext *s, int c_idx, int x_c,
- int y_c, int log2_trafo_size,
- int scan_idx, int prev_sig);
-int ff_hevc_coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx,
- int ctx_set);
-int ff_hevc_coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx,
- int inc);
-int ff_hevc_coeff_abs_level_remaining(HEVCContext *s, int base_level,
- int rc_rice_param);
-int ff_hevc_coeff_sign_flag(HEVCContext *s, uint8_t nb);
+int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx);
+int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx);
/**
* Get the number of candidate references for the current frame.
@@ -965,6 +1007,8 @@ int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc);
*/
int ff_hevc_output_frame(HEVCContext *s, AVFrame *frame, int flush);
+void ff_hevc_bump_frame(HEVCContext *s);
+
void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags);
void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0,
@@ -976,18 +1020,22 @@ void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0,
int nPbW, int nPbH, int log2_cb_size,
int part_idx, int merge_idx,
MvField *mv, int mvp_lx_flag, int LX);
-void ff_hevc_set_qPy(HEVCContext *s, int xC, int yC, int xBase, int yBase,
+void ff_hevc_set_qPy(HEVCContext *s, int xBase, int yBase,
int log2_cb_size);
void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
int log2_trafo_size);
int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s);
int ff_hevc_cu_qp_delta_abs(HEVCContext *s);
-void ff_hevc_hls_filter(HEVCContext *s, int x, int y);
+int ff_hevc_cu_chroma_qp_offset_flag(HEVCContext *s);
+int ff_hevc_cu_chroma_qp_offset_idx(HEVCContext *s);
+void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size);
void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size);
+void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ int log2_trafo_size, enum ScanType scan_idx,
+ int c_idx);
-void ff_hevc_pps_free(HEVCPPS **ppps);
+void ff_hevc_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size);
-void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth);
extern const uint8_t ff_hevc_qpel_extra_before[4];
extern const uint8_t ff_hevc_qpel_extra_after[4];
diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c
index efcaa860c7..3d16896b3c 100644
--- a/libavcodec/hevc_cabac.c
+++ b/libavcodec/hevc_cabac.c
@@ -4,20 +4,20 @@
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Gildas Cocherel
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,65 +66,77 @@ av_unused static const int8_t num_bins_in_se[] = {
2, // cbf_luma
4, // cbf_cb, cbf_cr
2, // transform_skip_flag[][]
+ 2, // explicit_rdpcm_flag[][]
+ 2, // explicit_rdpcm_dir_flag[][]
18, // last_significant_coeff_x_prefix
18, // last_significant_coeff_y_prefix
0, // last_significant_coeff_x_suffix
0, // last_significant_coeff_y_suffix
4, // significant_coeff_group_flag
- 42, // significant_coeff_flag
+ 44, // significant_coeff_flag
24, // coeff_abs_level_greater1_flag
6, // coeff_abs_level_greater2_flag
0, // coeff_abs_level_remaining
0, // coeff_sign_flag
+ 8, // log2_res_scale_abs
+ 2, // res_scale_sign_flag
+ 1, // cu_chroma_qp_offset_flag
+ 1, // cu_chroma_qp_offset_idx
};
/**
* Offset to ctxIdx 0 in init_values and states, indexed by SyntaxElement.
*/
static const int elem_offset[sizeof(num_bins_in_se)] = {
- 0,
- 1,
- 2,
- 2,
- 2,
- 2,
- 2,
- 2,
- 5,
- 6,
- 9,
- 12,
- 13,
- 17,
- 17,
- 18,
- 18,
- 18,
- 20,
- 21,
- 22,
- 27,
- 29,
- 31,
- 33,
- 35,
- 35,
- 35,
- 36,
- 37,
- 40,
- 42,
- 46,
- 48,
- 66,
- 84,
- 84,
- 84,
- 88,
- 130,
- 154,
- 160,
- 160,
+ 0, // sao_merge_flag
+ 1, // sao_type_idx
+ 2, // sao_eo_class
+ 2, // sao_band_position
+ 2, // sao_offset_abs
+ 2, // sao_offset_sign
+ 2, // end_of_slice_flag
+ 2, // split_coding_unit_flag
+ 5, // cu_transquant_bypass_flag
+ 6, // skip_flag
+ 9, // cu_qp_delta
+ 12, // pred_mode
+ 13, // part_mode
+ 17, // pcm_flag
+ 17, // prev_intra_luma_pred_mode
+ 18, // mpm_idx
+ 18, // rem_intra_luma_pred_mode
+ 18, // intra_chroma_pred_mode
+ 20, // merge_flag
+ 21, // merge_idx
+ 22, // inter_pred_idc
+ 27, // ref_idx_l0
+ 29, // ref_idx_l1
+ 31, // abs_mvd_greater0_flag
+ 33, // abs_mvd_greater1_flag
+ 35, // abs_mvd_minus2
+ 35, // mvd_sign_flag
+ 35, // mvp_lx_flag
+ 36, // no_residual_data_flag
+ 37, // split_transform_flag
+ 40, // cbf_luma
+ 42, // cbf_cb, cbf_cr
+ 46, // transform_skip_flag[][]
+ 48, // explicit_rdpcm_flag[][]
+ 50, // explicit_rdpcm_dir_flag[][]
+ 52, // last_significant_coeff_x_prefix
+ 70, // last_significant_coeff_y_prefix
+ 88, // last_significant_coeff_x_suffix
+ 88, // last_significant_coeff_y_suffix
+ 88, // significant_coeff_group_flag
+ 92, // significant_coeff_flag
+ 136, // coeff_abs_level_greater1_flag
+ 160, // coeff_abs_level_greater2_flag
+ 166, // coeff_abs_level_remaining
+ 166, // coeff_sign_flag
+ 166, // log2_res_scale_abs
+ 174, // res_scale_sign_flag
+ 176, // cu_chroma_qp_offset_flag
+ 177, // cu_chroma_qp_offset_idx
};
#define CNU 154
@@ -178,6 +190,10 @@ static const uint8_t init_values[3][HEVC_CONTEXTS] = {
94, 138, 182, 154,
// transform_skip_flag
139, 139,
+ // explicit_rdpcm_flag
+ 139, 139,
+ // explicit_rdpcm_dir_flag
+ 139, 139,
// last_significant_coeff_x_prefix
110, 110, 124, 125, 140, 153, 125, 127, 140, 109, 111, 143, 127, 111,
79, 108, 123, 63,
@@ -190,11 +206,21 @@ static const uint8_t init_values[3][HEVC_CONTEXTS] = {
111, 111, 125, 110, 110, 94, 124, 108, 124, 107, 125, 141, 179, 153,
125, 107, 125, 141, 179, 153, 125, 107, 125, 141, 179, 153, 125, 140,
139, 182, 182, 152, 136, 152, 136, 153, 136, 139, 111, 136, 139, 111,
+ 141, 111,
// coeff_abs_level_greater1_flag
140, 92, 137, 138, 140, 152, 138, 139, 153, 74, 149, 92, 139, 107,
122, 152, 140, 179, 166, 182, 140, 227, 122, 197,
// coeff_abs_level_greater2_flag
- 138, 153, 136, 167, 152, 152, },
+ 138, 153, 136, 167, 152, 152,
+ // log2_res_scale_abs
+ 154, 154, 154, 154, 154, 154, 154, 154,
+ // res_scale_sign_flag
+ 154, 154,
+ // cu_chroma_qp_offset_flag
+ 154,
+ // cu_chroma_qp_offset_idx
+ 154,
+ },
{ // sao_merge_flag
153,
// sao_type_idx
@@ -241,6 +267,10 @@ static const uint8_t init_values[3][HEVC_CONTEXTS] = {
149, 107, 167, 154,
// transform_skip_flag
139, 139,
+ // explicit_rdpcm_flag
+ 139, 139,
+ // explicit_rdpcm_dir_flag
+ 139, 139,
// last_significant_coeff_x_prefix
125, 110, 94, 110, 95, 79, 125, 111, 110, 78, 110, 111, 111, 95,
94, 108, 123, 108,
@@ -253,11 +283,21 @@ static const uint8_t init_values[3][HEVC_CONTEXTS] = {
155, 154, 139, 153, 139, 123, 123, 63, 153, 166, 183, 140, 136, 153,
154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 170,
153, 123, 123, 107, 121, 107, 121, 167, 151, 183, 140, 151, 183, 140,
+ 140, 140,
// coeff_abs_level_greater1_flag
154, 196, 196, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121,
136, 137, 169, 194, 166, 167, 154, 167, 137, 182,
// coeff_abs_level_greater2_flag
- 107, 167, 91, 122, 107, 167, },
+ 107, 167, 91, 122, 107, 167,
+ // log2_res_scale_abs
+ 154, 154, 154, 154, 154, 154, 154, 154,
+ // res_scale_sign_flag
+ 154, 154,
+ // cu_chroma_qp_offset_flag
+ 154,
+ // cu_chroma_qp_offset_idx
+ 154,
+ },
{ // sao_merge_flag
153,
// sao_type_idx
@@ -304,6 +344,10 @@ static const uint8_t init_values[3][HEVC_CONTEXTS] = {
149, 92, 167, 154,
// transform_skip_flag
139, 139,
+ // explicit_rdpcm_flag
+ 139, 139,
+ // explicit_rdpcm_dir_flag
+ 139, 139,
// last_significant_coeff_x_prefix
125, 110, 124, 110, 95, 94, 125, 111, 111, 79, 125, 126, 111, 111,
79, 108, 123, 93,
@@ -316,11 +360,141 @@ static const uint8_t init_values[3][HEVC_CONTEXTS] = {
170, 154, 139, 153, 139, 123, 123, 63, 124, 166, 183, 140, 136, 153,
154, 166, 183, 140, 136, 153, 154, 166, 183, 140, 136, 153, 154, 170,
153, 138, 138, 122, 121, 122, 121, 167, 151, 183, 140, 151, 183, 140,
+ 140, 140,
// coeff_abs_level_greater1_flag
154, 196, 167, 167, 154, 152, 167, 182, 182, 134, 149, 136, 153, 121,
136, 122, 169, 208, 166, 167, 154, 152, 167, 182,
// coeff_abs_level_greater2_flag
- 107, 167, 91, 107, 107, 167, },
+ 107, 167, 91, 107, 107, 167,
+ // log2_res_scale_abs
+ 154, 154, 154, 154, 154, 154, 154, 154,
+ // res_scale_sign_flag
+ 154, 154,
+ // cu_chroma_qp_offset_flag
+ 154,
+ // cu_chroma_qp_offset_idx
+ 154,
+ },
+};
+
+static const uint8_t scan_1x1[1] = {
+ 0,
+};
+
+static const uint8_t horiz_scan2x2_x[4] = {
+ 0, 1, 0, 1,
+};
+
+static const uint8_t horiz_scan2x2_y[4] = {
+ 0, 0, 1, 1
+};
+
+static const uint8_t horiz_scan4x4_x[16] = {
+ 0, 1, 2, 3,
+ 0, 1, 2, 3,
+ 0, 1, 2, 3,
+ 0, 1, 2, 3,
+};
+
+static const uint8_t horiz_scan4x4_y[16] = {
+ 0, 0, 0, 0,
+ 1, 1, 1, 1,
+ 2, 2, 2, 2,
+ 3, 3, 3, 3,
+};
+
+static const uint8_t horiz_scan8x8_inv[8][8] = {
+ { 0, 1, 2, 3, 16, 17, 18, 19, },
+ { 4, 5, 6, 7, 20, 21, 22, 23, },
+ { 8, 9, 10, 11, 24, 25, 26, 27, },
+ { 12, 13, 14, 15, 28, 29, 30, 31, },
+ { 32, 33, 34, 35, 48, 49, 50, 51, },
+ { 36, 37, 38, 39, 52, 53, 54, 55, },
+ { 40, 41, 42, 43, 56, 57, 58, 59, },
+ { 44, 45, 46, 47, 60, 61, 62, 63, },
+};
+
+static const uint8_t diag_scan2x2_x[4] = {
+ 0, 0, 1, 1,
+};
+
+static const uint8_t diag_scan2x2_y[4] = {
+ 0, 1, 0, 1,
+};
+
+static const uint8_t diag_scan2x2_inv[2][2] = {
+ { 0, 2, },
+ { 1, 3, },
+};
+
+const uint8_t ff_hevc_diag_scan4x4_x[16] = {
+ 0, 0, 1, 0,
+ 1, 2, 0, 1,
+ 2, 3, 1, 2,
+ 3, 2, 3, 3,
+};
+
+const uint8_t ff_hevc_diag_scan4x4_y[16] = {
+ 0, 1, 0, 2,
+ 1, 0, 3, 2,
+ 1, 0, 3, 2,
+ 1, 3, 2, 3,
+};
+
+static const uint8_t diag_scan4x4_inv[4][4] = {
+ { 0, 2, 5, 9, },
+ { 1, 4, 8, 12, },
+ { 3, 7, 11, 14, },
+ { 6, 10, 13, 15, },
+};
+
+const uint8_t ff_hevc_diag_scan8x8_x[64] = {
+ 0, 0, 1, 0,
+ 1, 2, 0, 1,
+ 2, 3, 0, 1,
+ 2, 3, 4, 0,
+ 1, 2, 3, 4,
+ 5, 0, 1, 2,
+ 3, 4, 5, 6,
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 1, 2, 3, 4,
+ 5, 6, 7, 2,
+ 3, 4, 5, 6,
+ 7, 3, 4, 5,
+ 6, 7, 4, 5,
+ 6, 7, 5, 6,
+ 7, 6, 7, 7,
+};
+
+const uint8_t ff_hevc_diag_scan8x8_y[64] = {
+ 0, 1, 0, 2,
+ 1, 0, 3, 2,
+ 1, 0, 4, 3,
+ 2, 1, 0, 5,
+ 4, 3, 2, 1,
+ 0, 6, 5, 4,
+ 3, 2, 1, 0,
+ 7, 6, 5, 4,
+ 3, 2, 1, 0,
+ 7, 6, 5, 4,
+ 3, 2, 1, 7,
+ 6, 5, 4, 3,
+ 2, 7, 6, 5,
+ 4, 3, 7, 6,
+ 5, 4, 7, 6,
+ 5, 7, 6, 7,
+};
+
+static const uint8_t diag_scan8x8_inv[8][8] = {
+ { 0, 2, 5, 9, 14, 20, 27, 35, },
+ { 1, 4, 8, 13, 19, 26, 34, 42, },
+ { 3, 7, 12, 18, 25, 33, 41, 48, },
+ { 6, 11, 17, 24, 32, 40, 47, 53, },
+ { 10, 16, 23, 31, 39, 46, 52, 57, },
+ { 15, 22, 30, 38, 45, 51, 56, 60, },
+ { 21, 29, 37, 44, 50, 55, 59, 62, },
+ { 28, 36, 43, 49, 54, 58, 61, 63, },
};
void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts)
@@ -329,13 +503,13 @@ void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts)
(ctb_addr_ts % s->sps->ctb_width == 2 ||
(s->sps->ctb_width == 2 &&
ctb_addr_ts % s->sps->ctb_width == 0))) {
- memcpy(s->cabac_state, s->HEVClc.cabac_state, HEVC_CONTEXTS);
+ memcpy(s->cabac_state, s->HEVClc->cabac_state, HEVC_CONTEXTS);
}
}
static void load_states(HEVCContext *s)
{
- memcpy(s->HEVClc.cabac_state, s->cabac_state, HEVC_CONTEXTS);
+ memcpy(s->HEVClc->cabac_state, s->cabac_state, HEVC_CONTEXTS);
}
static void cabac_reinit(HEVCLocalContext *lc)
@@ -345,10 +519,10 @@ static void cabac_reinit(HEVCLocalContext *lc)
static void cabac_init_decoder(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
skip_bits(gb, 1);
align_get_bits(gb);
- ff_init_cabac_decoder(&s->HEVClc.cc,
+ ff_init_cabac_decoder(&s->HEVClc->cc,
gb->buffer + get_bits_count(gb) / 8,
(get_bits_left(gb) + 7) / 8);
}
@@ -370,8 +544,11 @@ static void cabac_init_state(HEVCContext *s)
pre ^= pre >> 31;
if (pre > 124)
pre = 124 + (pre & 1);
- s->HEVClc.cabac_state[i] = pre;
+ s->HEVClc->cabac_state[i] = pre;
}
+
+ for (i = 0; i < 4; i++)
+ s->HEVClc->stat_coeff[i] = 0;
}
void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts)
@@ -395,13 +572,19 @@ void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts)
} else {
if (s->pps->tiles_enabled_flag &&
s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[ctb_addr_ts - 1]) {
- cabac_reinit(&s->HEVClc);
+ if (s->threads_number == 1)
+ cabac_reinit(s->HEVClc);
+ else
+ cabac_init_decoder(s);
cabac_init_state(s);
}
if (s->pps->entropy_coding_sync_enabled_flag) {
if (ctb_addr_ts % s->sps->ctb_width == 0) {
- get_cabac_terminate(&s->HEVClc.cc);
- cabac_reinit(&s->HEVClc);
+ get_cabac_terminate(&s->HEVClc->cc);
+ if (s->threads_number == 1)
+ cabac_reinit(s->HEVClc);
+ else
+ cabac_init_decoder(s);
if (s->sps->ctb_width == 1)
cabac_init_state(s);
@@ -412,7 +595,7 @@ void ff_hevc_cabac_init(HEVCContext *s, int ctb_addr_ts)
}
}
-#define GET_CABAC(ctx) get_cabac(&s->HEVClc.cc, &s->HEVClc.cabac_state[ctx])
+#define GET_CABAC(ctx) get_cabac(&s->HEVClc->cc, &s->HEVClc->cabac_state[ctx])
int ff_hevc_sao_merge_flag_decode(HEVCContext *s)
{
@@ -424,7 +607,7 @@ int ff_hevc_sao_type_idx_decode(HEVCContext *s)
if (!GET_CABAC(elem_offset[SAO_TYPE_IDX]))
return 0;
- if (!get_cabac_bypass(&s->HEVClc.cc))
+ if (!get_cabac_bypass(&s->HEVClc->cc))
return SAO_BAND;
return SAO_EDGE;
}
@@ -432,10 +615,10 @@ int ff_hevc_sao_type_idx_decode(HEVCContext *s)
int ff_hevc_sao_band_position_decode(HEVCContext *s)
{
int i;
- int value = get_cabac_bypass(&s->HEVClc.cc);
+ int value = get_cabac_bypass(&s->HEVClc->cc);
for (i = 0; i < 4; i++)
- value = (value << 1) | get_cabac_bypass(&s->HEVClc.cc);
+ value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc);
return value;
}
@@ -444,26 +627,26 @@ int ff_hevc_sao_offset_abs_decode(HEVCContext *s)
int i = 0;
int length = (1 << (FFMIN(s->sps->bit_depth, 10) - 5)) - 1;
- while (i < length && get_cabac_bypass(&s->HEVClc.cc))
+ while (i < length && get_cabac_bypass(&s->HEVClc->cc))
i++;
return i;
}
int ff_hevc_sao_offset_sign_decode(HEVCContext *s)
{
- return get_cabac_bypass(&s->HEVClc.cc);
+ return get_cabac_bypass(&s->HEVClc->cc);
}
int ff_hevc_sao_eo_class_decode(HEVCContext *s)
{
- int ret = get_cabac_bypass(&s->HEVClc.cc) << 1;
- ret |= get_cabac_bypass(&s->HEVClc.cc);
+ int ret = get_cabac_bypass(&s->HEVClc->cc) << 1;
+ ret |= get_cabac_bypass(&s->HEVClc->cc);
return ret;
}
int ff_hevc_end_of_slice_flag_decode(HEVCContext *s)
{
- return get_cabac_terminate(&s->HEVClc.cc);
+ return get_cabac_terminate(&s->HEVClc->cc);
}
int ff_hevc_cu_transquant_bypass_flag_decode(HEVCContext *s)
@@ -475,12 +658,12 @@ int ff_hevc_skip_flag_decode(HEVCContext *s, int x0, int y0, int x_cb, int y_cb)
{
int min_cb_width = s->sps->min_cb_width;
int inc = 0;
- int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
- int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int x0b = av_mod_uintp2(x0, s->sps->log2_ctb_size);
+ int y0b = av_mod_uintp2(y0, s->sps->log2_ctb_size);
- if (s->HEVClc.ctb_left_flag || x0b)
+ if (s->HEVClc->ctb_left_flag || x0b)
inc = !!SAMPLE_CTB(s->skip_flag, x_cb - 1, y_cb);
- if (s->HEVClc.ctb_up_flag || y0b)
+ if (s->HEVClc->ctb_up_flag || y0b)
inc += !!SAMPLE_CTB(s->skip_flag, x_cb, y_cb - 1);
return GET_CABAC(elem_offset[SKIP_FLAG] + inc);
@@ -498,7 +681,7 @@ int ff_hevc_cu_qp_delta_abs(HEVCContext *s)
}
if (prefix_val >= 5) {
int k = 0;
- while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc.cc)) {
+ while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) {
suffix_val += 1 << k;
k++;
}
@@ -506,14 +689,30 @@ int ff_hevc_cu_qp_delta_abs(HEVCContext *s)
av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k);
while (k--)
- suffix_val += get_cabac_bypass(&s->HEVClc.cc) << k;
+ suffix_val += get_cabac_bypass(&s->HEVClc->cc) << k;
}
return prefix_val + suffix_val;
}
int ff_hevc_cu_qp_delta_sign_flag(HEVCContext *s)
{
- return get_cabac_bypass(&s->HEVClc.cc);
+ return get_cabac_bypass(&s->HEVClc->cc);
+}
+
+int ff_hevc_cu_chroma_qp_offset_flag(HEVCContext *s)
+{
+ return GET_CABAC(elem_offset[CU_CHROMA_QP_OFFSET_FLAG]);
+}
+
+int ff_hevc_cu_chroma_qp_offset_idx(HEVCContext *s)
+{
+ int c_max= FFMAX(5, s->pps->chroma_qp_offset_list_len_minus1);
+ int i = 0;
+
+ while (i < c_max && GET_CABAC(elem_offset[CU_CHROMA_QP_OFFSET_IDX]))
+ i++;
+
+ return i;
}
int ff_hevc_pred_mode_decode(HEVCContext *s)
@@ -524,14 +723,14 @@ int ff_hevc_pred_mode_decode(HEVCContext *s)
int ff_hevc_split_coding_unit_flag_decode(HEVCContext *s, int ct_depth, int x0, int y0)
{
int inc = 0, depth_left = 0, depth_top = 0;
- int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
- int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+ int x0b = av_mod_uintp2(x0, s->sps->log2_ctb_size);
+ int y0b = av_mod_uintp2(y0, s->sps->log2_ctb_size);
int x_cb = x0 >> s->sps->log2_min_cb_size;
int y_cb = y0 >> s->sps->log2_min_cb_size;
- if (s->HEVClc.ctb_left_flag || x0b)
+ if (s->HEVClc->ctb_left_flag || x0b)
depth_left = s->tab_ct_depth[(y_cb) * s->sps->min_cb_width + x_cb - 1];
- if (s->HEVClc.ctb_up_flag || y0b)
+ if (s->HEVClc->ctb_up_flag || y0b)
depth_top = s->tab_ct_depth[(y_cb - 1) * s->sps->min_cb_width + x_cb];
inc += (depth_left > ct_depth);
@@ -545,7 +744,7 @@ int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size)
if (GET_CABAC(elem_offset[PART_MODE])) // 1
return PART_2Nx2N;
if (log2_cb_size == s->sps->log2_min_cb_size) {
- if (s->HEVClc.cu.pred_mode == MODE_INTRA) // 0
+ if (s->HEVClc->cu.pred_mode == MODE_INTRA) // 0
return PART_NxN;
if (GET_CABAC(elem_offset[PART_MODE] + 1)) // 01
return PART_2NxN;
@@ -565,21 +764,21 @@ int ff_hevc_part_mode_decode(HEVCContext *s, int log2_cb_size)
if (GET_CABAC(elem_offset[PART_MODE] + 1)) { // 01X, 01XX
if (GET_CABAC(elem_offset[PART_MODE] + 3)) // 011
return PART_2NxN;
- if (get_cabac_bypass(&s->HEVClc.cc)) // 0101
+ if (get_cabac_bypass(&s->HEVClc->cc)) // 0101
return PART_2NxnD;
return PART_2NxnU; // 0100
}
if (GET_CABAC(elem_offset[PART_MODE] + 3)) // 001
return PART_Nx2N;
- if (get_cabac_bypass(&s->HEVClc.cc)) // 0001
+ if (get_cabac_bypass(&s->HEVClc->cc)) // 0001
return PART_nRx2N;
return PART_nLx2N; // 0000
}
int ff_hevc_pcm_flag_decode(HEVCContext *s)
{
- return get_cabac_terminate(&s->HEVClc.cc);
+ return get_cabac_terminate(&s->HEVClc->cc);
}
int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s)
@@ -590,7 +789,7 @@ int ff_hevc_prev_intra_luma_pred_flag_decode(HEVCContext *s)
int ff_hevc_mpm_idx_decode(HEVCContext *s)
{
int i = 0;
- while (i < 2 && get_cabac_bypass(&s->HEVClc.cc))
+ while (i < 2 && get_cabac_bypass(&s->HEVClc->cc))
i++;
return i;
}
@@ -598,10 +797,10 @@ int ff_hevc_mpm_idx_decode(HEVCContext *s)
int ff_hevc_rem_intra_luma_pred_mode_decode(HEVCContext *s)
{
int i;
- int value = get_cabac_bypass(&s->HEVClc.cc);
+ int value = get_cabac_bypass(&s->HEVClc->cc);
for (i = 0; i < 4; i++)
- value = (value << 1) | get_cabac_bypass(&s->HEVClc.cc);
+ value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc);
return value;
}
@@ -611,8 +810,8 @@ int ff_hevc_intra_chroma_pred_mode_decode(HEVCContext *s)
if (!GET_CABAC(elem_offset[INTRA_CHROMA_PRED_MODE]))
return 4;
- ret = get_cabac_bypass(&s->HEVClc.cc) << 1;
- ret |= get_cabac_bypass(&s->HEVClc.cc);
+ ret = get_cabac_bypass(&s->HEVClc->cc) << 1;
+ ret |= get_cabac_bypass(&s->HEVClc->cc);
return ret;
}
@@ -621,7 +820,7 @@ int ff_hevc_merge_idx_decode(HEVCContext *s)
int i = GET_CABAC(elem_offset[MERGE_IDX]);
if (i != 0) {
- while (i < s->sh.max_num_merge_cand-1 && get_cabac_bypass(&s->HEVClc.cc))
+ while (i < s->sh.max_num_merge_cand-1 && get_cabac_bypass(&s->HEVClc->cc))
i++;
}
return i;
@@ -636,7 +835,7 @@ int ff_hevc_inter_pred_idc_decode(HEVCContext *s, int nPbW, int nPbH)
{
if (nPbW + nPbH == 12)
return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4);
- if (GET_CABAC(elem_offset[INTER_PRED_IDC] + s->HEVClc.ct.depth))
+ if (GET_CABAC(elem_offset[INTER_PRED_IDC] + s->HEVClc->ct_depth))
return PRED_BI;
return GET_CABAC(elem_offset[INTER_PRED_IDC] + 4);
@@ -651,7 +850,7 @@ int ff_hevc_ref_idx_lx_decode(HEVCContext *s, int num_ref_idx_lx)
while (i < max_ctx && GET_CABAC(elem_offset[REF_IDX_L0] + i))
i++;
if (i == 2) {
- while (i < max && get_cabac_bypass(&s->HEVClc.cc))
+ while (i < max && get_cabac_bypass(&s->HEVClc->cc))
i++;
}
@@ -668,35 +867,35 @@ int ff_hevc_no_residual_syntax_flag_decode(HEVCContext *s)
return GET_CABAC(elem_offset[NO_RESIDUAL_DATA_FLAG]);
}
-int ff_hevc_abs_mvd_greater0_flag_decode(HEVCContext *s)
+static av_always_inline int abs_mvd_greater0_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[ABS_MVD_GREATER0_FLAG]);
}
-int ff_hevc_abs_mvd_greater1_flag_decode(HEVCContext *s)
+static av_always_inline int abs_mvd_greater1_flag_decode(HEVCContext *s)
{
return GET_CABAC(elem_offset[ABS_MVD_GREATER1_FLAG] + 1);
}
-int ff_hevc_mvd_decode(HEVCContext *s)
+static av_always_inline int mvd_decode(HEVCContext *s)
{
int ret = 2;
int k = 1;
- while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc.cc)) {
+ while (k < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) {
ret += 1 << k;
k++;
}
if (k == CABAC_MAX_BIN)
av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k);
while (k--)
- ret += get_cabac_bypass(&s->HEVClc.cc) << k;
- return get_cabac_bypass_sign(&s->HEVClc.cc, -ret);
+ ret += get_cabac_bypass(&s->HEVClc->cc) << k;
+ return get_cabac_bypass_sign(&s->HEVClc->cc, -ret);
}
-int ff_hevc_mvd_sign_flag_decode(HEVCContext *s)
+static av_always_inline int mvd_sign_flag_decode(HEVCContext *s)
{
- return get_cabac_bypass_sign(&s->HEVClc.cc, -1);
+ return get_cabac_bypass_sign(&s->HEVClc->cc, -1);
}
int ff_hevc_split_transform_flag_decode(HEVCContext *s, int log2_trafo_size)
@@ -714,53 +913,73 @@ int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth)
return GET_CABAC(elem_offset[CBF_LUMA] + !trafo_depth);
}
-int ff_hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx)
+static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx)
{
return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + !!c_idx);
}
-#define LAST_SIG_COEFF(elem) \
- int i = 0; \
- int max = (log2_size << 1) - 1; \
- int ctx_offset, ctx_shift; \
- \
- if (c_idx == 0) { \
- ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2); \
- ctx_shift = (log2_size + 1) >> 2; \
- } else { \
- ctx_offset = 15; \
- ctx_shift = log2_size - 2; \
- } \
- while (i < max && \
- GET_CABAC(elem_offset[elem] + (i >> ctx_shift) + ctx_offset)) \
- i++; \
- return i;
+static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx)
+{
+ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + !!c_idx);
+}
-int ff_hevc_last_significant_coeff_x_prefix_decode(HEVCContext *s, int c_idx,
- int log2_size)
+static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx)
{
- LAST_SIG_COEFF(LAST_SIGNIFICANT_COEFF_X_PREFIX)
+ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + !!c_idx);
+}
+
+int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx) {
+ int i =0;
+
+ while (i < 4 && GET_CABAC(elem_offset[LOG2_RES_SCALE_ABS] + 4 * idx + i))
+ i++;
+
+ return i;
+}
+
+int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx) {
+ return GET_CABAC(elem_offset[RES_SCALE_SIGN_FLAG] + idx);
}
-int ff_hevc_last_significant_coeff_y_prefix_decode(HEVCContext *s, int c_idx,
- int log2_size)
+static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx,
+ int log2_size, int *last_scx_prefix, int *last_scy_prefix)
{
- LAST_SIG_COEFF(LAST_SIGNIFICANT_COEFF_Y_PREFIX)
+ int i = 0;
+ int max = (log2_size << 1) - 1;
+ int ctx_offset, ctx_shift;
+
+ if (!c_idx) {
+ ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2);
+ ctx_shift = (log2_size + 1) >> 2;
+ } else {
+ ctx_offset = 15;
+ ctx_shift = log2_size - 2;
+ }
+ while (i < max &&
+ GET_CABAC(elem_offset[LAST_SIGNIFICANT_COEFF_X_PREFIX] + (i >> ctx_shift) + ctx_offset))
+ i++;
+ *last_scx_prefix = i;
+
+ i = 0;
+ while (i < max &&
+ GET_CABAC(elem_offset[LAST_SIGNIFICANT_COEFF_Y_PREFIX] + (i >> ctx_shift) + ctx_offset))
+ i++;
+ *last_scy_prefix = i;
}
-int ff_hevc_last_significant_coeff_suffix_decode(HEVCContext *s,
+static av_always_inline int last_significant_coeff_suffix_decode(HEVCContext *s,
int last_significant_coeff_prefix)
{
int i;
int length = (last_significant_coeff_prefix >> 1) - 1;
- int value = get_cabac_bypass(&s->HEVClc.cc);
+ int value = get_cabac_bypass(&s->HEVClc->cc);
for (i = 1; i < length; i++)
- value = (value << 1) | get_cabac_bypass(&s->HEVClc.cc);
+ value = (value << 1) | get_cabac_bypass(&s->HEVClc->cc);
return value;
}
-int ff_hevc_significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg)
+static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg)
{
int inc;
@@ -768,58 +987,19 @@ int ff_hevc_significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int c
return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc);
}
-
-int ff_hevc_significant_coeff_flag_decode(HEVCContext *s, int c_idx, int x_c, int y_c,
- int log2_trafo_size, int scan_idx, int prev_sig)
+static av_always_inline int significant_coeff_flag_decode(HEVCContext *s, int x_c, int y_c,
+ int offset, const uint8_t *ctx_idx_map)
{
- static const uint8_t ctx_idx_map[] = {
- 0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8
- };
- int x_cg = x_c >> 2;
- int y_cg = y_c >> 2;
- int sig_ctx, inc;
-
- if (x_c + y_c == 0) {
- sig_ctx = 0;
- } else if (log2_trafo_size == 2) {
- sig_ctx = ctx_idx_map[(y_c << 2) + x_c];
- } else {
- switch (prev_sig) {
- case 0: {
- int x_off = x_c & 3;
- int y_off = y_c & 3;
- sig_ctx = ((x_off + y_off) == 0) ? 2 : ((x_off + y_off) <= 2) ? 1 : 0;
- }
- break;
- case 1:
- sig_ctx = 2 - FFMIN(y_c & 3, 2);
- break;
- case 2:
- sig_ctx = 2 - FFMIN(x_c & 3, 2);
- break;
- default:
- sig_ctx = 2;
- }
-
- if (c_idx == 0 && (x_cg > 0 || y_cg > 0))
- sig_ctx += 3;
-
- if (log2_trafo_size == 3) {
- sig_ctx += (scan_idx == SCAN_DIAG) ? 9 : 15;
- } else {
- sig_ctx += c_idx ? 12 : 21;
- }
- }
-
- if (c_idx == 0)
- inc = sig_ctx;
- else
- inc = sig_ctx + 27;
-
+ int inc = ctx_idx_map[(y_c << 2) + x_c] + offset;
return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc);
}
-int ff_hevc_coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx, int inc)
+static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int c_idx, int offset)
+{
+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + offset);
+}
+
+static av_always_inline int coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx, int inc)
{
if (c_idx > 0)
@@ -828,7 +1008,7 @@ int ff_hevc_coeff_abs_level_greater1_flag_decode(HEVCContext *s, int c_idx, int
return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] + inc);
}
-int ff_hevc_coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx, int inc)
+static av_always_inline int coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx, int inc)
{
if (c_idx > 0)
inc += 4;
@@ -836,37 +1016,572 @@ int ff_hevc_coeff_abs_level_greater2_flag_decode(HEVCContext *s, int c_idx, int
return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc);
}
-int ff_hevc_coeff_abs_level_remaining(HEVCContext *s, int base_level, int rc_rice_param)
+static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int rc_rice_param)
{
int prefix = 0;
int suffix = 0;
int last_coeff_abs_level_remaining;
int i;
- while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc.cc))
+ while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc))
prefix++;
if (prefix == CABAC_MAX_BIN)
av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix);
if (prefix < 3) {
for (i = 0; i < rc_rice_param; i++)
- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc.cc);
+ suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc);
last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix;
} else {
int prefix_minus3 = prefix - 3;
for (i = 0; i < prefix_minus3 + rc_rice_param; i++)
- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc.cc);
+ suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc);
last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1)
<< rc_rice_param) + suffix;
}
return last_coeff_abs_level_remaining;
}
-int ff_hevc_coeff_sign_flag(HEVCContext *s, uint8_t nb)
+static av_always_inline int coeff_sign_flag_decode(HEVCContext *s, uint8_t nb)
{
int i;
int ret = 0;
for (i = 0; i < nb; i++)
- ret = (ret << 1) | get_cabac_bypass(&s->HEVClc.cc);
+ ret = (ret << 1) | get_cabac_bypass(&s->HEVClc->cc);
return ret;
}
+
+void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ int log2_trafo_size, enum ScanType scan_idx,
+ int c_idx)
+{
+#define GET_COORD(offset, n) \
+ do { \
+ x_c = (x_cg << 2) + scan_x_off[n]; \
+ y_c = (y_cg << 2) + scan_y_off[n]; \
+ } while (0)
+ HEVCLocalContext *lc = s->HEVClc;
+ int transform_skip_flag = 0;
+
+ int last_significant_coeff_x, last_significant_coeff_y;
+ int last_scan_pos;
+ int n_end;
+ int num_coeff = 0;
+ int greater1_ctx = 1;
+
+ int num_last_subset;
+ int x_cg_last_sig, y_cg_last_sig;
+
+ const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off;
+
+ ptrdiff_t stride = s->frame->linesize[c_idx];
+ int hshift = s->sps->hshift[c_idx];
+ int vshift = s->sps->vshift[c_idx];
+ uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride +
+ ((x0 >> hshift) << s->sps->pixel_shift)];
+ int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer);
+ uint8_t significant_coeff_group_flag[8][8] = {{0}};
+ int explicit_rdpcm_flag = 0;
+ int explicit_rdpcm_dir_flag;
+
+ int trafo_size = 1 << log2_trafo_size;
+ int i;
+ int qp,shift,add,scale,scale_m;
+ const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
+ const uint8_t *scale_matrix = NULL;
+ uint8_t dc_scale;
+ int pred_mode_intra = (c_idx == 0) ? lc->tu.intra_pred_mode :
+ lc->tu.intra_pred_mode_c;
+
+ memset(coeffs, 0, trafo_size * trafo_size * sizeof(int16_t));
+
+ // Derive QP for dequant
+ if (!lc->cu.cu_transquant_bypass_flag) {
+ static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
+ static const uint8_t rem6[51 + 4 * 6 + 1] = {
+ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2,
+ 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
+ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
+ 4, 5, 0, 1, 2, 3, 4, 5, 0, 1
+ };
+
+ static const uint8_t div6[51 + 4 * 6 + 1] = {
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10,
+ 10, 10, 11, 11, 11, 11, 11, 11, 12, 12
+ };
+ int qp_y = lc->qp_y;
+
+ if (s->pps->transform_skip_enabled_flag &&
+ log2_trafo_size <= s->pps->log2_max_transform_skip_block_size) {
+ transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx);
+ }
+
+ if (c_idx == 0) {
+ qp = qp_y + s->sps->qp_bd_offset;
+ } else {
+ int qp_i, offset;
+
+ if (c_idx == 1)
+ offset = s->pps->cb_qp_offset + s->sh.slice_cb_qp_offset +
+ lc->tu.cu_qp_offset_cb;
+ else
+ offset = s->pps->cr_qp_offset + s->sh.slice_cr_qp_offset +
+ lc->tu.cu_qp_offset_cr;
+
+ qp_i = av_clip(qp_y + offset, - s->sps->qp_bd_offset, 57);
+ if (s->sps->chroma_format_idc == 1) {
+ if (qp_i < 30)
+ qp = qp_i;
+ else if (qp_i > 43)
+ qp = qp_i - 6;
+ else
+ qp = qp_c[qp_i - 30];
+ } else {
+ if (qp_i > 51)
+ qp = 51;
+ else
+ qp = qp_i;
+ }
+
+ qp += s->sps->qp_bd_offset;
+ }
+
+ shift = s->sps->bit_depth + log2_trafo_size - 5;
+ add = 1 << (shift-1);
+ scale = level_scale[rem6[qp]] << (div6[qp]);
+ scale_m = 16; // default when no custom scaling lists.
+ dc_scale = 16;
+
+ if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
+ const ScalingList *sl = s->pps->scaling_list_data_present_flag ?
+ &s->pps->scaling_list : &s->sps->scaling_list;
+ int matrix_id = lc->cu.pred_mode != MODE_INTRA;
+
+ matrix_id = 3 * matrix_id + c_idx;
+
+ scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id];
+ if (log2_trafo_size >= 4)
+ dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id];
+ }
+ } else {
+ shift = 0;
+ add = 0;
+ scale = 0;
+ dc_scale = 0;
+ }
+
+ if (lc->cu.pred_mode == MODE_INTER && s->sps->explicit_rdpcm_enabled_flag &&
+ (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
+ explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx);
+ if (explicit_rdpcm_flag) {
+ explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx);
+ }
+ }
+
+ last_significant_coeff_xy_prefix_decode(s, c_idx, log2_trafo_size,
+ &last_significant_coeff_x, &last_significant_coeff_y);
+
+ if (last_significant_coeff_x > 3) {
+ int suffix = last_significant_coeff_suffix_decode(s, last_significant_coeff_x);
+ last_significant_coeff_x = (1 << ((last_significant_coeff_x >> 1) - 1)) *
+ (2 + (last_significant_coeff_x & 1)) +
+ suffix;
+ }
+
+ if (last_significant_coeff_y > 3) {
+ int suffix = last_significant_coeff_suffix_decode(s, last_significant_coeff_y);
+ last_significant_coeff_y = (1 << ((last_significant_coeff_y >> 1) - 1)) *
+ (2 + (last_significant_coeff_y & 1)) +
+ suffix;
+ }
+
+ if (scan_idx == SCAN_VERT)
+ FFSWAP(int, last_significant_coeff_x, last_significant_coeff_y);
+
+ x_cg_last_sig = last_significant_coeff_x >> 2;
+ y_cg_last_sig = last_significant_coeff_y >> 2;
+
+ switch (scan_idx) {
+ case SCAN_DIAG: {
+ int last_x_c = last_significant_coeff_x & 3;
+ int last_y_c = last_significant_coeff_y & 3;
+
+ scan_x_off = ff_hevc_diag_scan4x4_x;
+ scan_y_off = ff_hevc_diag_scan4x4_y;
+ num_coeff = diag_scan4x4_inv[last_y_c][last_x_c];
+ if (trafo_size == 4) {
+ scan_x_cg = scan_1x1;
+ scan_y_cg = scan_1x1;
+ } else if (trafo_size == 8) {
+ num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4;
+ scan_x_cg = diag_scan2x2_x;
+ scan_y_cg = diag_scan2x2_y;
+ } else if (trafo_size == 16) {
+ num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4;
+ scan_x_cg = ff_hevc_diag_scan4x4_x;
+ scan_y_cg = ff_hevc_diag_scan4x4_y;
+ } else { // trafo_size == 32
+ num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4;
+ scan_x_cg = ff_hevc_diag_scan8x8_x;
+ scan_y_cg = ff_hevc_diag_scan8x8_y;
+ }
+ break;
+ }
+ case SCAN_HORIZ:
+ scan_x_cg = horiz_scan2x2_x;
+ scan_y_cg = horiz_scan2x2_y;
+ scan_x_off = horiz_scan4x4_x;
+ scan_y_off = horiz_scan4x4_y;
+ num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x];
+ break;
+ default: //SCAN_VERT
+ scan_x_cg = horiz_scan2x2_y;
+ scan_y_cg = horiz_scan2x2_x;
+ scan_x_off = horiz_scan4x4_y;
+ scan_y_off = horiz_scan4x4_x;
+ num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y];
+ break;
+ }
+ num_coeff++;
+ num_last_subset = (num_coeff - 1) >> 4;
+
+ for (i = num_last_subset; i >= 0; i--) {
+ int n, m;
+ int x_cg, y_cg, x_c, y_c, pos;
+ int implicit_non_zero_coeff = 0;
+ int64_t trans_coeff_level;
+ int prev_sig = 0;
+ int offset = i << 4;
+ int rice_init = 0;
+
+ uint8_t significant_coeff_flag_idx[16];
+ uint8_t nb_significant_coeff_flag = 0;
+
+ x_cg = scan_x_cg[i];
+ y_cg = scan_y_cg[i];
+
+ if ((i < num_last_subset) && (i > 0)) {
+ int ctx_cg = 0;
+ if (x_cg < (1 << (log2_trafo_size - 2)) - 1)
+ ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg];
+ if (y_cg < (1 << (log2_trafo_size - 2)) - 1)
+ ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1];
+
+ significant_coeff_group_flag[x_cg][y_cg] =
+ significant_coeff_group_flag_decode(s, c_idx, ctx_cg);
+ implicit_non_zero_coeff = 1;
+ } else {
+ significant_coeff_group_flag[x_cg][y_cg] =
+ ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) ||
+ (x_cg == 0 && y_cg == 0));
+ }
+
+ last_scan_pos = num_coeff - offset - 1;
+
+ if (i == num_last_subset) {
+ n_end = last_scan_pos - 1;
+ significant_coeff_flag_idx[0] = last_scan_pos;
+ nb_significant_coeff_flag = 1;
+ } else {
+ n_end = 15;
+ }
+
+ if (x_cg < ((1 << log2_trafo_size) - 1) >> 2)
+ prev_sig = !!significant_coeff_group_flag[x_cg + 1][y_cg];
+ if (y_cg < ((1 << log2_trafo_size) - 1) >> 2)
+ prev_sig += (!!significant_coeff_group_flag[x_cg][y_cg + 1] << 1);
+
+ if (significant_coeff_group_flag[x_cg][y_cg] && n_end >= 0) {
+ static const uint8_t ctx_idx_map[] = {
+ 0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8, // log2_trafo_size == 2
+ 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 0
+ 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 1
+ 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, // prev_sig == 2
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // default
+ };
+ const uint8_t *ctx_idx_map_p;
+ int scf_offset = 0;
+ if (s->sps->transform_skip_context_enabled_flag &&
+ (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
+ ctx_idx_map_p = (uint8_t*) &ctx_idx_map[4 * 16];
+ if (c_idx == 0) {
+ scf_offset = 40;
+ } else {
+ scf_offset = 14 + 27;
+ }
+ } else {
+ if (c_idx != 0)
+ scf_offset = 27;
+ if (log2_trafo_size == 2) {
+ ctx_idx_map_p = (uint8_t*) &ctx_idx_map[0];
+ } else {
+ ctx_idx_map_p = (uint8_t*) &ctx_idx_map[(prev_sig + 1) << 4];
+ if (c_idx == 0) {
+ if ((x_cg > 0 || y_cg > 0))
+ scf_offset += 3;
+ if (log2_trafo_size == 3) {
+ scf_offset += (scan_idx == SCAN_DIAG) ? 9 : 15;
+ } else {
+ scf_offset += 21;
+ }
+ } else {
+ if (log2_trafo_size == 3)
+ scf_offset += 9;
+ else
+ scf_offset += 12;
+ }
+ }
+ }
+ for (n = n_end; n > 0; n--) {
+ x_c = scan_x_off[n];
+ y_c = scan_y_off[n];
+ if (significant_coeff_flag_decode(s, x_c, y_c, scf_offset, ctx_idx_map_p)) {
+ significant_coeff_flag_idx[nb_significant_coeff_flag] = n;
+ nb_significant_coeff_flag++;
+ implicit_non_zero_coeff = 0;
+ }
+ }
+ if (implicit_non_zero_coeff == 0) {
+ if (s->sps->transform_skip_context_enabled_flag &&
+ (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
+ if (c_idx == 0) {
+ scf_offset = 42;
+ } else {
+ scf_offset = 16 + 27;
+ }
+ } else {
+ if (i == 0) {
+ if (c_idx == 0)
+ scf_offset = 0;
+ else
+ scf_offset = 27;
+ } else {
+ scf_offset = 2 + scf_offset;
+ }
+ }
+ if (significant_coeff_flag_decode_0(s, c_idx, scf_offset) == 1) {
+ significant_coeff_flag_idx[nb_significant_coeff_flag] = 0;
+ nb_significant_coeff_flag++;
+ }
+ } else {
+ significant_coeff_flag_idx[nb_significant_coeff_flag] = 0;
+ nb_significant_coeff_flag++;
+ }
+ }
+
+ n_end = nb_significant_coeff_flag;
+
+
+ if (n_end) {
+ int first_nz_pos_in_cg;
+ int last_nz_pos_in_cg;
+ int c_rice_param = 0;
+ int first_greater1_coeff_idx = -1;
+ uint8_t coeff_abs_level_greater1_flag[8];
+ uint16_t coeff_sign_flag;
+ int sum_abs = 0;
+ int sign_hidden;
+ int sb_type;
+
+
+ // initialize first elem of coeff_bas_level_greater1_flag
+ int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0;
+
+ if (s->sps->persistent_rice_adaptation_enabled_flag) {
+ if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag)
+ sb_type = 2 * (c_idx == 0 ? 1 : 0);
+ else
+ sb_type = 2 * (c_idx == 0 ? 1 : 0) + 1;
+ c_rice_param = lc->stat_coeff[sb_type] / 4;
+ }
+
+ if (!(i == num_last_subset) && greater1_ctx == 0)
+ ctx_set++;
+ greater1_ctx = 1;
+ last_nz_pos_in_cg = significant_coeff_flag_idx[0];
+
+ for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) {
+ int inc = (ctx_set << 2) + greater1_ctx;
+ coeff_abs_level_greater1_flag[m] =
+ coeff_abs_level_greater1_flag_decode(s, c_idx, inc);
+ if (coeff_abs_level_greater1_flag[m]) {
+ greater1_ctx = 0;
+ if (first_greater1_coeff_idx == -1)
+ first_greater1_coeff_idx = m;
+ } else if (greater1_ctx > 0 && greater1_ctx < 3) {
+ greater1_ctx++;
+ }
+ }
+ first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1];
+
+ if (lc->cu.cu_transquant_bypass_flag ||
+ (lc->cu.pred_mode == MODE_INTRA &&
+ s->sps->implicit_rdpcm_enabled_flag && transform_skip_flag &&
+ (pred_mode_intra == 10 || pred_mode_intra == 26 )) ||
+ explicit_rdpcm_flag)
+ sign_hidden = 0;
+ else
+ sign_hidden = (last_nz_pos_in_cg - first_nz_pos_in_cg >= 4);
+
+ if (first_greater1_coeff_idx != -1) {
+ coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set);
+ }
+ if (!s->pps->sign_data_hiding_flag || !sign_hidden ) {
+ coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag);
+ } else {
+ coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1));
+ }
+
+ for (m = 0; m < n_end; m++) {
+ n = significant_coeff_flag_idx[m];
+ GET_COORD(offset, n);
+ if (m < 8) {
+ trans_coeff_level = 1 + coeff_abs_level_greater1_flag[m];
+ if (trans_coeff_level == ((m == first_greater1_coeff_idx) ? 3 : 2)) {
+ int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
+
+ trans_coeff_level += last_coeff_abs_level_remaining;
+ if (trans_coeff_level > (3 << c_rice_param))
+ c_rice_param = s->sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
+ if (s->sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
+ int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
+ if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
+ lc->stat_coeff[sb_type]++;
+ else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
+ if (lc->stat_coeff[sb_type] > 0)
+ lc->stat_coeff[sb_type]--;
+ rice_init = 1;
+ }
+ }
+ } else {
+ int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
+
+ trans_coeff_level = 1 + last_coeff_abs_level_remaining;
+ if (trans_coeff_level > (3 << c_rice_param))
+ c_rice_param = s->sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
+ if (s->sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
+ int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
+ if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
+ lc->stat_coeff[sb_type]++;
+ else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
+ if (lc->stat_coeff[sb_type] > 0)
+ lc->stat_coeff[sb_type]--;
+ rice_init = 1;
+ }
+ }
+ if (s->pps->sign_data_hiding_flag && sign_hidden) {
+ sum_abs += trans_coeff_level;
+ if (n == first_nz_pos_in_cg && (sum_abs&1))
+ trans_coeff_level = -trans_coeff_level;
+ }
+ if (coeff_sign_flag >> 15)
+ trans_coeff_level = -trans_coeff_level;
+ coeff_sign_flag <<= 1;
+ if(!lc->cu.cu_transquant_bypass_flag) {
+ if (s->sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
+ if(y_c || x_c || log2_trafo_size < 4) {
+ switch(log2_trafo_size) {
+ case 3: pos = (y_c << 3) + x_c; break;
+ case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break;
+ case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break;
+ default: pos = (y_c << 2) + x_c; break;
+ }
+ scale_m = scale_matrix[pos];
+ } else {
+ scale_m = dc_scale;
+ }
+ }
+ trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift;
+ if(trans_coeff_level < 0) {
+ if((~trans_coeff_level) & 0xFffffffffff8000)
+ trans_coeff_level = -32768;
+ } else {
+ if(trans_coeff_level & 0xffffffffffff8000)
+ trans_coeff_level = 32767;
+ }
+ }
+ coeffs[y_c * trafo_size + x_c] = trans_coeff_level;
+ }
+ }
+ }
+
+ if (lc->cu.cu_transquant_bypass_flag) {
+ if (explicit_rdpcm_flag || (s->sps->implicit_rdpcm_enabled_flag &&
+ (pred_mode_intra == 10 || pred_mode_intra == 26))) {
+ int mode = s->sps->implicit_rdpcm_enabled_flag ? (pred_mode_intra == 26) : explicit_rdpcm_dir_flag;
+
+ s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode);
+ }
+ } else {
+ if (transform_skip_flag) {
+ int rot = s->sps->transform_skip_rotation_enabled_flag &&
+ log2_trafo_size == 2 &&
+ lc->cu.pred_mode == MODE_INTRA;
+ if (rot) {
+ for (i = 0; i < 8; i++)
+ FFSWAP(int16_t, coeffs[i], coeffs[16 - i - 1]);
+ }
+
+ s->hevcdsp.transform_skip(coeffs, log2_trafo_size);
+
+ if (explicit_rdpcm_flag || (s->sps->implicit_rdpcm_enabled_flag &&
+ lc->cu.pred_mode == MODE_INTRA &&
+ (pred_mode_intra == 10 || pred_mode_intra == 26))) {
+ int mode = explicit_rdpcm_flag ? explicit_rdpcm_dir_flag : (pred_mode_intra == 26);
+
+ s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode);
+ }
+ } else if (lc->cu.pred_mode == MODE_INTRA && c_idx == 0 && log2_trafo_size == 2) {
+ s->hevcdsp.idct_4x4_luma(coeffs);
+ } else {
+ int max_xy = FFMAX(last_significant_coeff_x, last_significant_coeff_y);
+ if (max_xy == 0)
+ s->hevcdsp.idct_dc[log2_trafo_size-2](coeffs);
+ else {
+ int col_limit = last_significant_coeff_x + last_significant_coeff_y + 4;
+ if (max_xy < 4)
+ col_limit = FFMIN(4, col_limit);
+ else if (max_xy < 8)
+ col_limit = FFMIN(8, col_limit);
+ else if (max_xy < 12)
+ col_limit = FFMIN(24, col_limit);
+ s->hevcdsp.idct[log2_trafo_size-2](coeffs, col_limit);
+ }
+ }
+ }
+ if (lc->tu.cross_pf) {
+ int16_t *coeffs_y = (int16_t*)lc->edge_emu_buffer;
+
+ for (i = 0; i < (trafo_size * trafo_size); i++) {
+ coeffs[i] = coeffs[i] + ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
+ }
+ }
+ s->hevcdsp.transform_add[log2_trafo_size-2](dst, coeffs, stride);
+}
+
+void ff_hevc_hls_mvd_coding(HEVCContext *s, int x0, int y0, int log2_cb_size)
+{
+ HEVCLocalContext *lc = s->HEVClc;
+ int x = abs_mvd_greater0_flag_decode(s);
+ int y = abs_mvd_greater0_flag_decode(s);
+
+ if (x)
+ x += abs_mvd_greater1_flag_decode(s);
+ if (y)
+ y += abs_mvd_greater1_flag_decode(s);
+
+ switch (x) {
+ case 2: lc->pu.mvd.x = mvd_decode(s); break;
+ case 1: lc->pu.mvd.x = mvd_sign_flag_decode(s); break;
+ case 0: lc->pu.mvd.x = 0; break;
+ }
+
+ switch (y) {
+ case 2: lc->pu.mvd.y = mvd_decode(s); break;
+ case 1: lc->pu.mvd.y = mvd_sign_flag_decode(s); break;
+ case 0: lc->pu.mvd.y = 0; break;
+ }
+}
+
diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c
index 2f3a3c413a..f50a640eab 100644
--- a/libavcodec/hevc_filter.c
+++ b/libavcodec/hevc_filter.c
@@ -5,20 +5,20 @@
* Copyright (C) 2013 Seppo Tomperi
* Copyright (C) 2013 Wassim Hamidouche
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,8 @@
#include "golomb.h"
#include "hevc.h"
+#include "bit_depth_template.c"
+
#define LUMA 0
#define CB 1
#define CR 2
@@ -59,28 +61,30 @@ static int chroma_tc(HEVCContext *s, int qp_y, int c_idx, int tc_offset)
offset = s->pps->cr_qp_offset;
qp_i = av_clip(qp_y + offset, 0, 57);
- if (qp_i < 30)
- qp = qp_i;
- else if (qp_i > 43)
- qp = qp_i - 6;
- else
- qp = qp_c[qp_i - 30];
+ if (s->sps->chroma_format_idc == 1) {
+ if (qp_i < 30)
+ qp = qp_i;
+ else if (qp_i > 43)
+ qp = qp_i - 6;
+ else
+ qp = qp_c[qp_i - 30];
+ } else {
+ qp = av_clip(qp_i, 0, 51);
+ }
idxt = av_clip(qp + DEFAULT_INTRA_TC_OFFSET + tc_offset, 0, 53);
return tctable[idxt];
}
-static int get_qPy_pred(HEVCContext *s, int xC, int yC,
- int xBase, int yBase, int log2_cb_size)
+static int get_qPy_pred(HEVCContext *s, int xBase, int yBase, int log2_cb_size)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
int ctb_size_mask = (1 << s->sps->log2_ctb_size) - 1;
int MinCuQpDeltaSizeMask = (1 << (s->sps->log2_ctb_size -
s->pps->diff_cu_qp_delta_depth)) - 1;
int xQgBase = xBase - (xBase & MinCuQpDeltaSizeMask);
int yQgBase = yBase - (yBase & MinCuQpDeltaSizeMask);
int min_cb_width = s->sps->min_cb_width;
- int min_cb_height = s->sps->min_cb_height;
int x_cb = xQgBase >> s->sps->log2_min_cb_size;
int y_cb = yQgBase >> s->sps->log2_min_cb_size;
int availableA = (xBase & ctb_size_mask) &&
@@ -94,46 +98,7 @@ static int get_qPy_pred(HEVCContext *s, int xC, int yC,
lc->first_qp_group = !lc->tu.is_cu_qp_delta_coded;
qPy_pred = s->sh.slice_qp;
} else {
- qPy_pred = lc->qp_y;
- if (log2_cb_size < s->sps->log2_ctb_size -
- s->pps->diff_cu_qp_delta_depth) {
- static const int offsetX[8][8] = {
- { -1, 1, 3, 1, 7, 1, 3, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 1, 3, 1, 3, 1, 3, 1, 3 },
- { 2, 2, 2, 2, 2, 2, 2, 2 },
- { 3, 5, 7, 5, 3, 5, 7, 5 },
- { 4, 4, 4, 4, 4, 4, 4, 4 },
- { 5, 7, 5, 7, 5, 7, 5, 7 },
- { 6, 6, 6, 6, 6, 6, 6, 6 }
- };
- static const int offsetY[8][8] = {
- { 7, 0, 1, 2, 3, 4, 5, 6 },
- { 0, 1, 2, 3, 4, 5, 6, 7 },
- { 1, 0, 3, 2, 5, 4, 7, 6 },
- { 0, 1, 2, 3, 4, 5, 6, 7 },
- { 3, 0, 1, 2, 7, 4, 5, 6 },
- { 0, 1, 2, 3, 4, 5, 6, 7 },
- { 1, 0, 3, 2, 5, 4, 7, 6 },
- { 0, 1, 2, 3, 4, 5, 6, 7 }
- };
- int xC0b = (xC - (xC & ctb_size_mask)) >> s->sps->log2_min_cb_size;
- int yC0b = (yC - (yC & ctb_size_mask)) >> s->sps->log2_min_cb_size;
- int idxX = (xQgBase & ctb_size_mask) >> s->sps->log2_min_cb_size;
- int idxY = (yQgBase & ctb_size_mask) >> s->sps->log2_min_cb_size;
- int idx_mask = ctb_size_mask >> s->sps->log2_min_cb_size;
- int x, y;
-
- x = FFMIN(xC0b + offsetX[idxX][idxY], min_cb_width - 1);
- y = FFMIN(yC0b + (offsetY[idxX][idxY] & idx_mask), min_cb_height - 1);
-
- if (xC0b == (lc->start_of_tiles_x >> s->sps->log2_min_cb_size) &&
- offsetX[idxX][idxY] == -1) {
- x = (lc->end_of_tiles_x >> s->sps->log2_min_cb_size) - 1;
- y = yC0b - 1;
- }
- qPy_pred = s->qp_y_tab[y * min_cb_width + x];
- }
+ qPy_pred = lc->qPy_pred;
}
// qPy_a
@@ -148,20 +113,22 @@ static int get_qPy_pred(HEVCContext *s, int xC, int yC,
else
qPy_b = s->qp_y_tab[x_cb + (y_cb - 1) * min_cb_width];
+ av_assert2(qPy_a >= -s->sps->qp_bd_offset && qPy_a < 52);
+ av_assert2(qPy_b >= -s->sps->qp_bd_offset && qPy_b < 52);
+
return (qPy_a + qPy_b + 1) >> 1;
}
-void ff_hevc_set_qPy(HEVCContext *s, int xC, int yC,
- int xBase, int yBase, int log2_cb_size)
+void ff_hevc_set_qPy(HEVCContext *s, int xBase, int yBase, int log2_cb_size)
{
- int qp_y = get_qPy_pred(s, xC, yC, xBase, yBase, log2_cb_size);
+ int qp_y = get_qPy_pred(s, xBase, yBase, log2_cb_size);
- if (s->HEVClc.tu.cu_qp_delta != 0) {
+ if (s->HEVClc->tu.cu_qp_delta != 0) {
int off = s->sps->qp_bd_offset;
- s->HEVClc.qp_y = FFUMOD(qp_y + s->HEVClc.tu.cu_qp_delta + 52 + 2 * off,
- 52 + off) - off;
+ s->HEVClc->qp_y = FFUMOD(qp_y + s->HEVClc->tu.cu_qp_delta + 52 + 2 * off,
+ 52 + off) - off;
} else
- s->HEVClc.qp_y = qp_y;
+ s->HEVClc->qp_y = qp_y;
}
static int get_qPy(HEVCContext *s, int xC, int yC)
@@ -172,15 +139,106 @@ static int get_qPy(HEVCContext *s, int xC, int yC)
return s->qp_y_tab[x + y * s->sps->min_cb_width];
}
-static void copy_CTB(uint8_t *dst, uint8_t *src,
- int width, int height, int stride)
+static void copy_CTB(uint8_t *dst, const uint8_t *src, int width, int height,
+ intptr_t stride_dst, intptr_t stride_src)
+{
+int i, j;
+
+ if (((intptr_t)dst | (intptr_t)src | stride_dst | stride_src) & 15) {
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j+=8)
+ AV_COPY64U(dst+j, src+j);
+ dst += stride_dst;
+ src += stride_src;
+ }
+ } else {
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j+=16)
+ AV_COPY128(dst+j, src+j);
+ dst += stride_dst;
+ src += stride_src;
+ }
+ }
+}
+
+static void copy_pixel(uint8_t *dst, const uint8_t *src, int pixel_shift)
+{
+ if (pixel_shift)
+ *(uint16_t *)dst = *(uint16_t *)src;
+ else
+ *dst = *src;
+}
+
+static void copy_vert(uint8_t *dst, const uint8_t *src,
+ int pixel_shift, int height,
+ int stride_dst, int stride_src)
{
int i;
+ if (pixel_shift == 0) {
+ for (i = 0; i < height; i++) {
+ *dst = *src;
+ dst += stride_dst;
+ src += stride_src;
+ }
+ } else {
+ for (i = 0; i < height; i++) {
+ *(uint16_t *)dst = *(uint16_t *)src;
+ dst += stride_dst;
+ src += stride_src;
+ }
+ }
+}
+
+static void copy_CTB_to_hv(HEVCContext *s, const uint8_t *src,
+ int stride_src, int x, int y, int width, int height,
+ int c_idx, int x_ctb, int y_ctb)
+{
+ int sh = s->sps->pixel_shift;
+ int w = s->sps->width >> s->sps->hshift[c_idx];
+ int h = s->sps->height >> s->sps->vshift[c_idx];
- for (i = 0; i < height; i++) {
- memcpy(dst, src, width);
- dst += stride;
- src += stride;
+ /* copy horizontal edges */
+ memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb) * w + x) << sh),
+ src, width << sh);
+ memcpy(s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 1) * w + x) << sh),
+ src + stride_src * (height - 1), width << sh);
+
+ /* copy vertical edges */
+ copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb) * h + y) << sh), src, sh, height, 1 << sh, stride_src);
+
+ copy_vert(s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 1) * h + y) << sh), src + ((width - 1) << sh), sh, height, 1 << sh, stride_src);
+}
+
+static void restore_tqb_pixels(HEVCContext *s,
+ uint8_t *src1, const uint8_t *dst1,
+ ptrdiff_t stride_src, ptrdiff_t stride_dst,
+ int x0, int y0, int width, int height, int c_idx)
+{
+ if ( s->pps->transquant_bypass_enable_flag ||
+ (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) {
+ int x, y;
+ int min_pu_size = 1 << s->sps->log2_min_pu_size;
+ int hshift = s->sps->hshift[c_idx];
+ int vshift = s->sps->vshift[c_idx];
+ int x_min = ((x0 ) >> s->sps->log2_min_pu_size);
+ int y_min = ((y0 ) >> s->sps->log2_min_pu_size);
+ int x_max = ((x0 + width ) >> s->sps->log2_min_pu_size);
+ int y_max = ((y0 + height) >> s->sps->log2_min_pu_size);
+ int len = (min_pu_size >> hshift) << s->sps->pixel_shift;
+ for (y = y_min; y < y_max; y++) {
+ for (x = x_min; x < x_max; x++) {
+ if (s->is_pcm[y * s->sps->min_pu_width + x]) {
+ int n;
+ uint8_t *src = src1 + (((y << s->sps->log2_min_pu_size) - y0) >> vshift) * stride_src + ((((x << s->sps->log2_min_pu_size) - x0) >> hshift) << s->sps->pixel_shift);
+ const uint8_t *dst = dst1 + (((y << s->sps->log2_min_pu_size) - y0) >> vshift) * stride_dst + ((((x << s->sps->log2_min_pu_size) - x0) >> hshift) << s->sps->pixel_shift);
+ for (n = 0; n < (min_pu_size >> vshift); n++) {
+ memcpy(src, dst, len);
+ src += stride_src;
+ dst += stride_dst;
+ }
+ }
+ }
+ }
}
}
@@ -188,128 +246,209 @@ static void copy_CTB(uint8_t *dst, uint8_t *src,
static void sao_filter_CTB(HEVCContext *s, int x, int y)
{
- // TODO: This should be easily parallelizable
- // TODO: skip CBs when (cu_transquant_bypass_flag || (pcm_loop_filter_disable_flag && pcm_flag))
- int c_idx = 0;
- int class = 1, class_index;
+ static const uint8_t sao_tab[8] = { 0, 1, 2, 2, 3, 3, 4, 4 };
+ HEVCLocalContext *lc = s->HEVClc;
+ int c_idx;
int edges[4]; // 0 left 1 top 2 right 3 bottom
- SAOParams *sao[4];
- int classes[4];
- int x_shift = 0, y_shift = 0;
- int x_ctb = x >> s->sps->log2_ctb_size;
- int y_ctb = y >> s->sps->log2_ctb_size;
- int ctb_addr_rs = y_ctb * s->sps->ctb_width + x_ctb;
- int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[ctb_addr_rs];
-
+ int x_ctb = x >> s->sps->log2_ctb_size;
+ int y_ctb = y >> s->sps->log2_ctb_size;
+ int ctb_addr_rs = y_ctb * s->sps->ctb_width + x_ctb;
+ int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[ctb_addr_rs];
+ SAOParams *sao = &CTB(s->sao, x_ctb, y_ctb);
// flags indicating unfilterable edges
- uint8_t vert_edge[] = { 0, 0, 0, 0 };
- uint8_t horiz_edge[] = { 0, 0, 0, 0 };
- uint8_t diag_edge[] = { 0, 0, 0, 0 };
- uint8_t lfase[3]; // current, above, left
- uint8_t no_tile_filter = s->pps->tiles_enabled_flag &&
- !s->pps->loop_filter_across_tiles_enabled_flag;
- uint8_t left_tile_edge = 0, up_tile_edge = 0;
-
- sao[0] = &CTB(s->sao, x_ctb, y_ctb);
+ uint8_t vert_edge[] = { 0, 0 };
+ uint8_t horiz_edge[] = { 0, 0 };
+ uint8_t diag_edge[] = { 0, 0, 0, 0 };
+ uint8_t lfase = CTB(s->filter_slice_edges, x_ctb, y_ctb);
+ uint8_t no_tile_filter = s->pps->tiles_enabled_flag &&
+ !s->pps->loop_filter_across_tiles_enabled_flag;
+ uint8_t restore = no_tile_filter || !lfase;
+ uint8_t left_tile_edge = 0;
+ uint8_t right_tile_edge = 0;
+ uint8_t up_tile_edge = 0;
+ uint8_t bottom_tile_edge = 0;
+
edges[0] = x_ctb == 0;
edges[1] = y_ctb == 0;
edges[2] = x_ctb == s->sps->ctb_width - 1;
edges[3] = y_ctb == s->sps->ctb_height - 1;
- lfase[0] = CTB(s->filter_slice_edges, x_ctb, y_ctb);
- classes[0] = 0;
-
- if (!edges[0]) {
- left_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]];
- sao[class] = &CTB(s->sao, x_ctb - 1, y_ctb);
- vert_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge;
- vert_edge[2] = vert_edge[0];
- lfase[2] = CTB(s->filter_slice_edges, x_ctb - 1, y_ctb);
- classes[class] = 2;
- class++;
- x_shift = 8;
- }
-
- if (!edges[1]) {
- up_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]];
- sao[class] = &CTB(s->sao, x_ctb, y_ctb - 1);
- horiz_edge[0] = (!lfase[0] && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge;
- horiz_edge[1] = horiz_edge[0];
- lfase[1] = CTB(s->filter_slice_edges, x_ctb, y_ctb - 1);
- classes[class] = 1;
- class++;
- y_shift = 4;
+ if (restore) {
if (!edges[0]) {
- classes[class] = 3;
- sao[class] = &CTB(s->sao, x_ctb - 1, y_ctb - 1);
- class++;
-
- // Tile check here is done current CTB row/col, not above/left like you'd expect,
- //but that is because the tile boundary always extends through the whole pic
- vert_edge[1] = (!lfase[1] && CTB(s->tab_slice_address, x_ctb, y_ctb - 1) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge;
- vert_edge[3] = vert_edge[1];
- horiz_edge[2] = (!lfase[2] && CTB(s->tab_slice_address, x_ctb - 1, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || up_tile_edge;
- horiz_edge[3] = horiz_edge[2];
- diag_edge[0] = (!lfase[0] && 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[3] = diag_edge[0];
-
- // Does left CTB comes after above CTB?
- if (CTB(s->tab_slice_address, x_ctb - 1, y_ctb) >
- CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) {
- diag_edge[2] = !lfase[2] || left_tile_edge || up_tile_edge;
- diag_edge[1] = diag_edge[2];
- } else if (CTB(s->tab_slice_address, x_ctb - 1, y_ctb) <
- CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) {
- diag_edge[1] = !lfase[1] || left_tile_edge || up_tile_edge;
- diag_edge[2] = diag_edge[1];
- } else {
- // Same slice, only consider tiles
- diag_edge[2] = left_tile_edge || up_tile_edge;
- diag_edge[1] = diag_edge[2];
- }
+ left_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs-1]];
+ vert_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb)) || left_tile_edge;
+ }
+ if (!edges[2]) {
+ right_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs+1]];
+ vert_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb)) || right_tile_edge;
+ }
+ if (!edges[1]) {
+ up_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs - s->sps->ctb_width]];
+ horiz_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb - 1)) || up_tile_edge;
+ }
+ if (!edges[3]) {
+ bottom_tile_edge = no_tile_filter && s->pps->tile_id[ctb_addr_ts] != s->pps->tile_id[s->pps->ctb_addr_rs_to_ts[ctb_addr_rs + s->sps->ctb_width]];
+ horiz_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb, y_ctb + 1)) || bottom_tile_edge;
+ }
+ if (!edges[0] && !edges[1]) {
+ diag_edge[0] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb - 1)) || left_tile_edge || up_tile_edge;
+ }
+ if (!edges[1] && !edges[2]) {
+ diag_edge[1] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb - 1)) || right_tile_edge || up_tile_edge;
+ }
+ if (!edges[2] && !edges[3]) {
+ diag_edge[2] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb + 1, y_ctb + 1)) || right_tile_edge || bottom_tile_edge;
+ }
+ if (!edges[0] && !edges[3]) {
+ diag_edge[3] = (!lfase && CTB(s->tab_slice_address, x_ctb, y_ctb) != CTB(s->tab_slice_address, x_ctb - 1, y_ctb + 1)) || left_tile_edge || bottom_tile_edge;
}
}
- for (c_idx = 0; c_idx < 3; c_idx++) {
- int chroma = c_idx ? 1 : 0;
- int x0 = x >> chroma;
- int y0 = y >> chroma;
- int stride = s->frame->linesize[c_idx];
- int ctb_size = (1 << (s->sps->log2_ctb_size)) >> s->sps->hshift[c_idx];
- int width = FFMIN(ctb_size,
- (s->sps->width >> s->sps->hshift[c_idx]) - x0);
- int height = FFMIN(ctb_size,
- (s->sps->height >> s->sps->vshift[c_idx]) - y0);
-
- uint8_t *src = &s->frame->data[c_idx][y0 * stride + (x0 << s->sps->pixel_shift)];
- uint8_t *dst = &s->sao_frame->data[c_idx][y0 * stride + (x0 << s->sps->pixel_shift)];
- int offset = (y_shift >> chroma) * stride + ((x_shift >> chroma) << s->sps->pixel_shift);
-
- copy_CTB(dst - offset, src - offset,
- (edges[2] ? width + (x_shift >> chroma) : width) << s->sps->pixel_shift,
- (edges[3] ? height + (y_shift >> chroma) : height), stride);
-
- for (class_index = 0; class_index < class; class_index++) {
-
- switch (sao[class_index]->type_idx[c_idx]) {
- case SAO_BAND:
- s->hevcdsp.sao_band_filter[classes[class_index]](dst, src,
- stride,
- sao[class_index],
- edges, width,
- height, c_idx);
- break;
- case SAO_EDGE:
- s->hevcdsp.sao_edge_filter[classes[class_index]](dst, src,
- stride,
- sao[class_index],
- edges, width,
- height, c_idx,
- vert_edge[classes[class_index]],
- horiz_edge[classes[class_index]],
- diag_edge[classes[class_index]]);
- break;
+ for (c_idx = 0; c_idx < (s->sps->chroma_format_idc ? 3 : 1); c_idx++) {
+ int x0 = x >> s->sps->hshift[c_idx];
+ int y0 = y >> s->sps->vshift[c_idx];
+ int stride_src = s->frame->linesize[c_idx];
+ int ctb_size_h = (1 << (s->sps->log2_ctb_size)) >> s->sps->hshift[c_idx];
+ int ctb_size_v = (1 << (s->sps->log2_ctb_size)) >> s->sps->vshift[c_idx];
+ int width = FFMIN(ctb_size_h, (s->sps->width >> s->sps->hshift[c_idx]) - x0);
+ int height = FFMIN(ctb_size_v, (s->sps->height >> s->sps->vshift[c_idx]) - y0);
+ int tab = sao_tab[(FFALIGN(width, 8) >> 3) - 1];
+ uint8_t *src = &s->frame->data[c_idx][y0 * stride_src + (x0 << s->sps->pixel_shift)];
+ int 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,
+ x_ctb, y_ctb);
+ if (s->pps->transquant_bypass_enable_flag ||
+ (s->sps->pcm.loop_filter_disable_flag && s->sps->pcm_enabled_flag)) {
+ dst = lc->edge_emu_buffer;
+ stride_dst = 2*MAX_PB_SIZE;
+ copy_CTB(dst, src, width << s->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,
+ x, y, width, height, c_idx);
+ } else {
+ s->hevcdsp.sao_band_filter[tab](src, src, stride_src, stride_src,
+ sao->offset_val[c_idx], sao->band_position[c_idx],
+ width, height);
+ }
+ sao->type_idx[c_idx] = SAO_APPLIED;
+ break;
+ case SAO_EDGE:
+ {
+ int w = s->sps->width >> s->sps->hshift[c_idx];
+ int h = s->sps->height >> s->sps->vshift[c_idx];
+ int left_edge = edges[0];
+ int top_edge = edges[1];
+ int right_edge = edges[2];
+ int bottom_edge = edges[3];
+ int sh = s->sps->pixel_shift;
+ int left_pixels, right_pixels;
+
+ stride_dst = 2*MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE;
+ dst = lc->edge_emu_buffer + stride_dst + FF_INPUT_BUFFER_PADDING_SIZE;
+
+ if (!top_edge) {
+ int left = 1 - left_edge;
+ int right = 1 - right_edge;
+ const uint8_t *src1[2];
+ uint8_t *dst1;
+ int src_idx, pos;
+
+ dst1 = dst - stride_dst - (left << sh);
+ src1[0] = src - stride_src - (left << sh);
+ src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb - 1) * w + x0 - left) << sh);
+ pos = 0;
+ if (left) {
+ src_idx = (CTB(s->sao, x_ctb-1, y_ctb-1).type_idx[c_idx] ==
+ SAO_APPLIED);
+ copy_pixel(dst1, src1[src_idx], sh);
+ pos += (1 << sh);
+ }
+ src_idx = (CTB(s->sao, x_ctb, y_ctb-1).type_idx[c_idx] ==
+ SAO_APPLIED);
+ memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
+ if (right) {
+ pos += width << sh;
+ src_idx = (CTB(s->sao, x_ctb+1, y_ctb-1).type_idx[c_idx] ==
+ SAO_APPLIED);
+ copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
+ }
}
+ if (!bottom_edge) {
+ int left = 1 - left_edge;
+ int right = 1 - right_edge;
+ const uint8_t *src1[2];
+ uint8_t *dst1;
+ int src_idx, pos;
+
+ dst1 = dst + height * stride_dst - (left << sh);
+ src1[0] = src + height * stride_src - (left << sh);
+ src1[1] = s->sao_pixel_buffer_h[c_idx] + (((2 * y_ctb + 2) * w + x0 - left) << sh);
+ pos = 0;
+ if (left) {
+ src_idx = (CTB(s->sao, x_ctb-1, y_ctb+1).type_idx[c_idx] ==
+ SAO_APPLIED);
+ copy_pixel(dst1, src1[src_idx], sh);
+ pos += (1 << sh);
+ }
+ src_idx = (CTB(s->sao, x_ctb, y_ctb+1).type_idx[c_idx] ==
+ SAO_APPLIED);
+ memcpy(dst1 + pos, src1[src_idx] + pos, width << sh);
+ if (right) {
+ pos += width << sh;
+ src_idx = (CTB(s->sao, x_ctb+1, y_ctb+1).type_idx[c_idx] ==
+ SAO_APPLIED);
+ copy_pixel(dst1 + pos, src1[src_idx] + pos, sh);
+ }
+ }
+ left_pixels = 0;
+ if (!left_edge) {
+ if (CTB(s->sao, x_ctb-1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
+ copy_vert(dst - (1 << sh),
+ s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb - 1) * h + y0) << sh),
+ sh, height, stride_dst, 1 << sh);
+ } else {
+ left_pixels = 1;
+ }
+ }
+ right_pixels = 0;
+ if (!right_edge) {
+ if (CTB(s->sao, x_ctb+1, y_ctb).type_idx[c_idx] == SAO_APPLIED) {
+ copy_vert(dst + (width << sh),
+ s->sao_pixel_buffer_v[c_idx] + (((2 * x_ctb + 2) * h + y0) << sh),
+ sh, height, stride_dst, 1 << sh);
+ } else {
+ right_pixels = 1;
+ }
+ }
+
+ copy_CTB(dst - (left_pixels << sh),
+ src - (left_pixels << sh),
+ (width + left_pixels + right_pixels) << sh,
+ height, stride_dst, stride_src);
+
+ copy_CTB_to_hv(s, src, stride_src, x0, y0, width, height, c_idx,
+ x_ctb, y_ctb);
+ s->hevcdsp.sao_edge_filter[tab](src, dst, stride_src, sao->offset_val[c_idx],
+ sao->eo_class[c_idx], width, height);
+ s->hevcdsp.sao_edge_restore[restore](src, dst,
+ stride_src, stride_dst,
+ sao,
+ edges, width,
+ height, c_idx,
+ vert_edge,
+ horiz_edge,
+ diag_edge);
+ restore_tqb_pixels(s, src, dst, stride_src, stride_dst,
+ x, y, width, height, c_idx);
+ sao->type_idx[c_idx] = SAO_APPLIED;
+ break;
+ }
}
}
}
@@ -338,18 +477,21 @@ static int get_pcm(HEVCContext *s, int x, int y)
static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
{
uint8_t *src;
- int x, y, x_end, y_end, chroma;
- int c_tc[2], tc[2], beta;
+ int x, y;
+ int chroma, beta;
+ int32_t c_tc[2], tc[2];
uint8_t no_p[2] = { 0 };
uint8_t no_q[2] = { 0 };
int log2_ctb_size = s->sps->log2_ctb_size;
+ int x_end, x_end2, y_end;
int ctb_size = 1 << log2_ctb_size;
int ctb = (x0 >> log2_ctb_size) +
(y0 >> log2_ctb_size) * s->sps->ctb_width;
int cur_tc_offset = s->deblock[ctb].tc_offset;
int cur_beta_offset = s->deblock[ctb].beta_offset;
- int tc_offset, left_tc_offset, beta_offset, left_beta_offset;
+ int left_tc_offset, left_beta_offset;
+ int tc_offset, beta_offset;
int pcmf = (s->sps->pcm_enabled_flag &&
s->sps->pcm.loop_filter_disable_flag) ||
s->pps->transquant_bypass_enable_flag;
@@ -357,6 +499,9 @@ static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
if (x0) {
left_tc_offset = s->deblock[ctb - 1].tc_offset;
left_beta_offset = s->deblock[ctb - 1].beta_offset;
+ } else {
+ left_tc_offset = 0;
+ left_beta_offset = 0;
}
x_end = x0 + ctb_size;
@@ -369,11 +514,14 @@ static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
tc_offset = cur_tc_offset;
beta_offset = cur_beta_offset;
- // vertical filtering luma
+ x_end2 = x_end;
+ if (x_end2 != s->sps->width)
+ x_end2 -= 8;
for (y = y0; y < y_end; y += 8) {
+ // vertical filtering luma
for (x = x0 ? x0 : 8; x < x_end; x += 8) {
- const int bs0 = s->vertical_bs[(x >> 3) + (y >> 2) * s->bs_width];
- const int bs1 = s->vertical_bs[(x >> 3) + ((y + 4) >> 2) * s->bs_width];
+ const int bs0 = s->vertical_bs[(x + y * s->bs_width) >> 2];
+ const int bs1 = s->vertical_bs[(x + (y + 4) * s->bs_width) >> 2];
if (bs0 || bs1) {
const int qp = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1;
@@ -396,45 +544,14 @@ static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
beta, tc, no_p, no_q);
}
}
- }
- // vertical filtering chroma
- for (chroma = 1; chroma <= 2; chroma++) {
- for (y = y0; y < y_end; y += 16) {
- for (x = x0 ? x0 : 16; x < x_end; x += 16) {
- const int bs0 = s->vertical_bs[(x >> 3) + (y >> 2) * s->bs_width];
- const int bs1 = s->vertical_bs[(x >> 3) + ((y + 8) >> 2) * s->bs_width];
- 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 + 8) + get_qPy(s, x, y + 8) + 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 / 2 * s->frame->linesize[chroma] + ((x / 2) << s->sps->pixel_shift)];
- if (pcmf) {
- no_p[0] = get_pcm(s, x - 1, y);
- no_p[1] = get_pcm(s, x - 1, y + 8);
- no_q[0] = get_pcm(s, x, y);
- no_q[1] = get_pcm(s, x, y + 8);
- s->hevcdsp.hevc_v_loop_filter_chroma_c(src,
- s->frame->linesize[chroma],
- c_tc, no_p, no_q);
- } else
- s->hevcdsp.hevc_v_loop_filter_chroma(src,
- s->frame->linesize[chroma],
- c_tc, no_p, no_q);
- }
- }
- }
- }
+ if(!y)
+ continue;
- // horizontal filtering luma
- if (x_end != s->sps->width)
- x_end -= 8;
- for (y = y0 ? y0 : 8; y < y_end; y += 8) {
- for (x = x0 ? x0 - 8 : 0; x < x_end; 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];
+ // horizontal filtering luma
+ for (x = x0 ? x0 - 8 : 0; x < x_end2; x += 8) {
+ const int bs0 = s->horizontal_bs[( x + y * s->bs_width) >> 2];
+ const int bs1 = s->horizontal_bs[((x + 4) + y * s->bs_width) >> 2];
if (bs0 || bs1) {
const int qp = (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1;
@@ -461,123 +578,135 @@ static void deblocking_filter_CTB(HEVCContext *s, int x0, int y0)
}
}
- // horizontal filtering chroma
- for (chroma = 1; chroma <= 2; chroma++) {
- for (y = y0 ? y0 : 16; y < y_end; y += 16) {
- for (x = x0 - 8; x < x_end; x += 16) {
- int bs0, bs1;
- // to make sure no memory access over boundary when x = -8
- // TODO: simplify with row based deblocking
- if (x < 0) {
- bs0 = 0;
- bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
- } else if (x >= x_end - 8) {
- bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
- bs1 = 0;
- } else {
- bs0 = s->horizontal_bs[(x + y * s->bs_width) >> 2];
- bs1 = s->horizontal_bs[(x + 8 + y * s->bs_width) >> 2];
+ if (s->sps->chroma_format_idc) {
+ for (chroma = 1; chroma <= 2; chroma++) {
+ int h = 1 << s->sps->hshift[chroma];
+ int v = 1 << s->sps->vshift[chroma];
+
+ // vertical filtering chroma
+ for (y = y0; y < y_end; y += (8 * v)) {
+ for (x = x0 ? x0 : 8 * h; x < x_end; x += (8 * h)) {
+ const int bs0 = s->vertical_bs[(x + y * s->bs_width) >> 2];
+ const int bs1 = s->vertical_bs[(x + (y + (4 * v)) * s->bs_width) >> 2];
+
+ if ((bs0 == 2) || (bs1 == 2)) {
+ const int qp0 = (get_qPy(s, x - 1, y) + get_qPy(s, x, y) + 1) >> 1;
+ const int qp1 = (get_qPy(s, x - 1, y + (4 * v)) + get_qPy(s, x, y + (4 * v)) + 1) >> 1;
+
+ c_tc[0] = (bs0 == 2) ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
+ c_tc[1] = (bs1 == 2) ? chroma_tc(s, qp1, chroma, tc_offset) : 0;
+ src = &s->frame->data[chroma][(y >> s->sps->vshift[chroma]) * s->frame->linesize[chroma] + ((x >> s->sps->hshift[chroma]) << s->sps->pixel_shift)];
+ if (pcmf) {
+ no_p[0] = get_pcm(s, x - 1, y);
+ no_p[1] = get_pcm(s, x - 1, y + (4 * v));
+ no_q[0] = get_pcm(s, x, y);
+ no_q[1] = get_pcm(s, x, y + (4 * v));
+ s->hevcdsp.hevc_v_loop_filter_chroma_c(src,
+ s->frame->linesize[chroma],
+ c_tc, no_p, no_q);
+ } else
+ s->hevcdsp.hevc_v_loop_filter_chroma(src,
+ s->frame->linesize[chroma],
+ c_tc, no_p, no_q);
+ }
}
- 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 + 8, y - 1) + get_qPy(s, x + 8, y) + 1) >> 1 : 0;
-
- tc_offset = x >= x0 ? cur_tc_offset : left_tc_offset;
- 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 / 2 * s->frame->linesize[chroma] + ((x / 2) << s->sps->pixel_shift)];
- if (pcmf) {
- no_p[0] = get_pcm(s, x, y - 1);
- no_p[1] = get_pcm(s, x + 8, y - 1);
- no_q[0] = get_pcm(s, x, y);
- no_q[1] = get_pcm(s, x + 8, y);
- s->hevcdsp.hevc_h_loop_filter_chroma_c(src,
- s->frame->linesize[chroma],
- c_tc, no_p, no_q);
- } else
- s->hevcdsp.hevc_h_loop_filter_chroma(src,
- s->frame->linesize[chroma],
- c_tc, no_p, no_q);
+ if(!y)
+ continue;
+
+ // horizontal filtering chroma
+ tc_offset = x0 ? left_tc_offset : cur_tc_offset;
+ x_end2 = x_end;
+ if (x_end != s->sps->width)
+ x_end2 = x_end - 8 * h;
+ for (x = x0 ? x0 - 8 * h : 0; x < x_end2; x += (8 * h)) {
+ const int bs0 = s->horizontal_bs[( x + y * s->bs_width) >> 2];
+ const int bs1 = s->horizontal_bs[((x + 4 * h) + y * s->bs_width) >> 2];
+ if ((bs0 == 2) || (bs1 == 2)) {
+ const int qp0 = bs0 == 2 ? (get_qPy(s, x, y - 1) + get_qPy(s, x, y) + 1) >> 1 : 0;
+ const int qp1 = bs1 == 2 ? (get_qPy(s, x + (4 * h), y - 1) + get_qPy(s, x + (4 * h), y) + 1) >> 1 : 0;
+
+ c_tc[0] = bs0 == 2 ? chroma_tc(s, qp0, chroma, tc_offset) : 0;
+ c_tc[1] = bs1 == 2 ? chroma_tc(s, qp1, chroma, cur_tc_offset) : 0;
+ src = &s->frame->data[chroma][(y >> s->sps->vshift[1]) * s->frame->linesize[chroma] + ((x >> s->sps->hshift[1]) << s->sps->pixel_shift)];
+ if (pcmf) {
+ no_p[0] = get_pcm(s, x, y - 1);
+ no_p[1] = get_pcm(s, x + (4 * h), y - 1);
+ no_q[0] = get_pcm(s, x, y);
+ no_q[1] = get_pcm(s, x + (4 * h), y);
+ s->hevcdsp.hevc_h_loop_filter_chroma_c(src,
+ s->frame->linesize[chroma],
+ c_tc, no_p, no_q);
+ } else
+ s->hevcdsp.hevc_h_loop_filter_chroma(src,
+ s->frame->linesize[chroma],
+ c_tc, no_p, no_q);
+ }
}
}
}
}
}
-static int boundary_strength(HEVCContext *s, MvField *curr,
- uint8_t curr_cbf_luma, MvField *neigh,
- uint8_t neigh_cbf_luma,
- RefPicList *neigh_refPicList,
- int tu_border)
+static int boundary_strength(HEVCContext *s, MvField *curr, MvField *neigh,
+ RefPicList *neigh_refPicList)
{
- int mvs = curr->pred_flag[0] + curr->pred_flag[1];
-
- if (tu_border) {
- if (curr->is_intra || neigh->is_intra)
- return 2;
- if (curr_cbf_luma || neigh_cbf_luma)
- return 1;
- }
-
- if (mvs == neigh->pred_flag[0] + neigh->pred_flag[1]) {
- if (mvs == 2) {
- // same L0 and L1
- if (s->ref->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] &&
- s->ref->refPicList[0].list[curr->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]] &&
- neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) {
- if ((abs(neigh->mv[0].x - curr->mv[0].x) >= 4 || abs(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
- abs(neigh->mv[1].x - curr->mv[1].x) >= 4 || abs(neigh->mv[1].y - curr->mv[1].y) >= 4) &&
- (abs(neigh->mv[1].x - curr->mv[0].x) >= 4 || abs(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
- abs(neigh->mv[0].x - curr->mv[1].x) >= 4 || abs(neigh->mv[0].y - curr->mv[1].y) >= 4))
- return 1;
- else
- return 0;
- } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
- neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
- if (abs(neigh->mv[0].x - curr->mv[0].x) >= 4 || abs(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
- abs(neigh->mv[1].x - curr->mv[1].x) >= 4 || abs(neigh->mv[1].y - curr->mv[1].y) >= 4)
- return 1;
- else
- return 0;
- } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
- neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
- if (abs(neigh->mv[1].x - curr->mv[0].x) >= 4 || abs(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
- abs(neigh->mv[0].x - curr->mv[1].x) >= 4 || abs(neigh->mv[0].y - curr->mv[1].y) >= 4)
- return 1;
- else
- return 0;
- } else {
+ if (curr->pred_flag == PF_BI && neigh->pred_flag == PF_BI) {
+ // same L0 and L1
+ if (s->ref->refPicList[0].list[curr->ref_idx[0]] == neigh_refPicList[0].list[neigh->ref_idx[0]] &&
+ s->ref->refPicList[0].list[curr->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]] &&
+ neigh_refPicList[0].list[neigh->ref_idx[0]] == neigh_refPicList[1].list[neigh->ref_idx[1]]) {
+ if ((FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
+ FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4) &&
+ (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
+ FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4))
return 1;
- }
- } else { // 1 MV
- Mv A, B;
- int ref_A, ref_B;
-
- if (curr->pred_flag[0]) {
- A = curr->mv[0];
- ref_A = s->ref->refPicList[0].list[curr->ref_idx[0]];
- } else {
- A = curr->mv[1];
- ref_A = s->ref->refPicList[1].list[curr->ref_idx[1]];
- }
+ else
+ return 0;
+ } else if (neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
+ neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
+ if (FFABS(neigh->mv[0].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[0].y) >= 4 ||
+ FFABS(neigh->mv[1].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[1].y) >= 4)
+ return 1;
+ else
+ return 0;
+ } else if (neigh_refPicList[1].list[neigh->ref_idx[1]] == s->ref->refPicList[0].list[curr->ref_idx[0]] &&
+ neigh_refPicList[0].list[neigh->ref_idx[0]] == s->ref->refPicList[1].list[curr->ref_idx[1]]) {
+ if (FFABS(neigh->mv[1].x - curr->mv[0].x) >= 4 || FFABS(neigh->mv[1].y - curr->mv[0].y) >= 4 ||
+ FFABS(neigh->mv[0].x - curr->mv[1].x) >= 4 || FFABS(neigh->mv[0].y - curr->mv[1].y) >= 4)
+ return 1;
+ else
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if ((curr->pred_flag != PF_BI) && (neigh->pred_flag != PF_BI)){ // 1 MV
+ Mv A, B;
+ int ref_A, ref_B;
+
+ if (curr->pred_flag & 1) {
+ A = curr->mv[0];
+ ref_A = s->ref->refPicList[0].list[curr->ref_idx[0]];
+ } else {
+ A = curr->mv[1];
+ ref_A = s->ref->refPicList[1].list[curr->ref_idx[1]];
+ }
- if (neigh->pred_flag[0]) {
- B = neigh->mv[0];
- ref_B = neigh_refPicList[0].list[neigh->ref_idx[0]];
- } else {
- B = neigh->mv[1];
- ref_B = neigh_refPicList[1].list[neigh->ref_idx[1]];
- }
+ if (neigh->pred_flag & 1) {
+ B = neigh->mv[0];
+ ref_B = neigh_refPicList[0].list[neigh->ref_idx[0]];
+ } else {
+ B = neigh->mv[1];
+ ref_B = neigh_refPicList[1].list[neigh->ref_idx[1]];
+ }
- if (ref_A == ref_B) {
- if (abs(A.x - B.x) >= 4 || abs(A.y - B.y) >= 4)
- return 1;
- else
- return 0;
- } else
+ if (ref_A == ref_B) {
+ if (FFABS(A.x - B.x) >= 4 || FFABS(A.y - B.y) >= 4)
return 1;
- }
+ else
+ return 0;
+ } else
+ return 1;
}
return 1;
@@ -586,14 +715,14 @@ static int boundary_strength(HEVCContext *s, MvField *curr,
void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
int log2_trafo_size)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
MvField *tab_mvf = s->ref->tab_mvf;
int log2_min_pu_size = s->sps->log2_min_pu_size;
int log2_min_tu_size = s->sps->log2_min_tb_size;
int min_pu_width = s->sps->min_pu_width;
int min_tu_width = s->sps->min_tb_width;
int is_intra = tab_mvf[(y0 >> log2_min_pu_size) * min_pu_width +
- (x0 >> log2_min_pu_size)].is_intra;
+ (x0 >> log2_min_pu_size)].pred_flag == PF_INTRA;
int boundary_upper, boundary_left;
int i, j, bs;
@@ -611,37 +740,11 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
RefPicList *rpl_top = (lc->boundary_flags & BOUNDARY_UPPER_SLICE) ?
ff_hevc_get_ref_list(s, s->ref, x0, y0 - 1) :
s->ref->refPicList;
-
int yp_pu = (y0 - 1) >> log2_min_pu_size;
int yq_pu = y0 >> log2_min_pu_size;
int yp_tu = (y0 - 1) >> log2_min_tu_size;
int yq_tu = y0 >> log2_min_tu_size;
- for (i = 0; i < (1 << log2_trafo_size); i += 4) {
- int x_pu = (x0 + i) >> log2_min_pu_size;
- int x_tu = (x0 + i) >> log2_min_tu_size;
- MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu];
- MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
- uint8_t top_cbf_luma = s->cbf_luma[yp_tu * min_tu_width + x_tu];
- uint8_t curr_cbf_luma = s->cbf_luma[yq_tu * min_tu_width + x_tu];
-
- bs = boundary_strength(s, curr, curr_cbf_luma,
- top, top_cbf_luma, rpl_top, 1);
- if (bs)
- s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = bs;
- }
- }
-
- // bs for TU internal horizontal PU boundaries
- if (log2_trafo_size > s->sps->log2_min_pu_size && !is_intra) {
- RefPicList *rpl = s->ref->refPicList;
-
- for (j = 8; j < (1 << log2_trafo_size); j += 8) {
- int yp_pu = (y0 + j - 1) >> log2_min_pu_size;
- int yq_pu = (y0 + j) >> log2_min_pu_size;
- int yp_tu = (y0 + j - 1) >> log2_min_tu_size;
- int yq_tu = (y0 + j) >> log2_min_tu_size;
-
for (i = 0; i < (1 << log2_trafo_size); i += 4) {
int x_pu = (x0 + i) >> log2_min_pu_size;
int x_tu = (x0 + i) >> log2_min_tu_size;
@@ -650,12 +753,14 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
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];
- bs = boundary_strength(s, curr, curr_cbf_luma,
- top, top_cbf_luma, rpl, 0);
- if (bs)
- s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
+ if (curr->pred_flag == PF_INTRA || top->pred_flag == PF_INTRA)
+ bs = 2;
+ else if (curr_cbf_luma || top_cbf_luma)
+ bs = 1;
+ else
+ bs = boundary_strength(s, curr, top, rpl_top);
+ s->horizontal_bs[((x0 + i) + y0 * s->bs_width) >> 2] = bs;
}
- }
}
// bs for vertical TU boundaries
@@ -673,50 +778,59 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
RefPicList *rpl_left = (lc->boundary_flags & BOUNDARY_LEFT_SLICE) ?
ff_hevc_get_ref_list(s, s->ref, x0 - 1, y0) :
s->ref->refPicList;
-
int xp_pu = (x0 - 1) >> log2_min_pu_size;
int xq_pu = x0 >> log2_min_pu_size;
int xp_tu = (x0 - 1) >> log2_min_tu_size;
int xq_tu = x0 >> log2_min_tu_size;
- for (i = 0; i < (1 << log2_trafo_size); i += 4) {
- int y_pu = (y0 + i) >> log2_min_pu_size;
- int y_tu = (y0 + i) >> log2_min_tu_size;
- MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
- MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
-
- uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu];
- uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu];
+ for (i = 0; i < (1 << log2_trafo_size); i += 4) {
+ int y_pu = (y0 + i) >> log2_min_pu_size;
+ int y_tu = (y0 + i) >> log2_min_tu_size;
+ MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
+ MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
+ uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu];
+ uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu];
- bs = boundary_strength(s, curr, curr_cbf_luma,
- left, left_cbf_luma, rpl_left, 1);
- if (bs)
- s->vertical_bs[(x0 >> 3) + ((y0 + i) >> 2) * s->bs_width] = bs;
- }
+ if (curr->pred_flag == PF_INTRA || left->pred_flag == PF_INTRA)
+ bs = 2;
+ else if (curr_cbf_luma || left_cbf_luma)
+ bs = 1;
+ else
+ bs = boundary_strength(s, curr, left, rpl_left);
+ s->vertical_bs[(x0 + (y0 + i) * s->bs_width) >> 2] = bs;
+ }
}
- // bs for TU internal vertical PU boundaries
if (log2_trafo_size > log2_min_pu_size && !is_intra) {
RefPicList *rpl = s->ref->refPicList;
+ // bs for TU internal horizontal PU boundaries
+ for (j = 8; j < (1 << log2_trafo_size); j += 8) {
+ int yp_pu = (y0 + j - 1) >> log2_min_pu_size;
+ int yq_pu = (y0 + j) >> log2_min_pu_size;
+
+ for (i = 0; i < (1 << log2_trafo_size); i += 4) {
+ int x_pu = (x0 + i) >> log2_min_pu_size;
+ MvField *top = &tab_mvf[yp_pu * min_pu_width + x_pu];
+ MvField *curr = &tab_mvf[yq_pu * min_pu_width + x_pu];
+
+ bs = boundary_strength(s, curr, top, rpl);
+ s->horizontal_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
+ }
+ }
+
+ // bs for TU internal vertical PU boundaries
for (j = 0; j < (1 << log2_trafo_size); j += 4) {
int y_pu = (y0 + j) >> log2_min_pu_size;
- int y_tu = (y0 + j) >> log2_min_tu_size;
for (i = 8; i < (1 << log2_trafo_size); i += 8) {
int xp_pu = (x0 + i - 1) >> log2_min_pu_size;
int xq_pu = (x0 + i) >> log2_min_pu_size;
- int xp_tu = (x0 + i - 1) >> log2_min_tu_size;
- int xq_tu = (x0 + i) >> log2_min_tu_size;
MvField *left = &tab_mvf[y_pu * min_pu_width + xp_pu];
MvField *curr = &tab_mvf[y_pu * min_pu_width + xq_pu];
- uint8_t left_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xp_tu];
- uint8_t curr_cbf_luma = s->cbf_luma[y_tu * min_tu_width + xq_tu];
- bs = boundary_strength(s, curr, curr_cbf_luma,
- left, left_cbf_luma, rpl, 0);
- if (bs)
- s->vertical_bs[((x0 + i) >> 3) + ((y0 + j) >> 2) * s->bs_width] = bs;
+ bs = boundary_strength(s, curr, left, rpl);
+ s->vertical_bs[((x0 + i) + (y0 + j) * s->bs_width) >> 2] = bs;
}
}
}
@@ -726,21 +840,38 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
#undef CB
#undef CR
-void ff_hevc_hls_filter(HEVCContext *s, int x, int y)
+void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size)
{
+ int x_end = x >= s->sps->width - ctb_size;
deblocking_filter_CTB(s, x, y);
- if (s->sps->sao_enabled)
- sao_filter_CTB(s, x, y);
+ if (s->sps->sao_enabled) {
+ int y_end = y >= s->sps->height - ctb_size;
+ if (y && x)
+ sao_filter_CTB(s, x - ctb_size, y - ctb_size);
+ if (x && y_end)
+ sao_filter_CTB(s, x - ctb_size, y);
+ if (y && x_end) {
+ sao_filter_CTB(s, x, y - ctb_size);
+ if (s->threads_type & FF_THREAD_FRAME )
+ ff_thread_report_progress(&s->ref->tf, y, 0);
+ }
+ if (x_end && y_end) {
+ sao_filter_CTB(s, x , y);
+ if (s->threads_type & FF_THREAD_FRAME )
+ ff_thread_report_progress(&s->ref->tf, y + ctb_size, 0);
+ }
+ } else if (s->threads_type & FF_THREAD_FRAME && x_end)
+ ff_thread_report_progress(&s->ref->tf, y + ctb_size - 4, 0);
}
void ff_hevc_hls_filters(HEVCContext *s, int x_ctb, int y_ctb, int ctb_size)
{
+ int x_end = x_ctb >= s->sps->width - ctb_size;
+ int y_end = y_ctb >= s->sps->height - ctb_size;
if (y_ctb && x_ctb)
- ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size);
- if (y_ctb && x_ctb >= s->sps->width - ctb_size) {
- ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size);
- ff_thread_report_progress(&s->ref->tf, y_ctb - ctb_size, 0);
- }
- if (x_ctb && y_ctb >= s->sps->height - ctb_size)
- ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb);
+ ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb - ctb_size, ctb_size);
+ if (y_ctb && x_end)
+ ff_hevc_hls_filter(s, x_ctb, y_ctb - ctb_size, ctb_size);
+ if (x_ctb && y_end)
+ ff_hevc_hls_filter(s, x_ctb - ctb_size, y_ctb, ctb_size);
}
diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c
index 23ea2ec2ee..e504257c47 100644
--- a/libavcodec/hevc_mvs.c
+++ b/libavcodec/hevc_mvs.c
@@ -4,20 +4,20 @@
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2013 Anand Meher Kotra
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,9 +41,9 @@ static const uint8_t l0_l1_cand_idx[12][2] = {
void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0,
int nPbW, int nPbH)
{
- HEVCLocalContext *lc = &s->HEVClc;
- int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
- int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
+ HEVCLocalContext *lc = s->HEVClc;
+ int x0b = av_mod_uintp2(x0, s->sps->log2_ctb_size);
+ int y0b = av_mod_uintp2(y0, s->sps->log2_ctb_size);
lc->na.cand_up = (lc->ctb_up_flag || y0b);
lc->na.cand_left = (lc->ctb_left_flag || x0b);
@@ -52,8 +52,7 @@ void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0,
((x0b + nPbW) == (1 << s->sps->log2_ctb_size)) ?
lc->ctb_up_right_flag && !y0b : lc->na.cand_up;
lc->na.cand_up_right =
- ((x0b + nPbW) == (1 << s->sps->log2_ctb_size) ?
- lc->ctb_up_right_flag && !y0b : lc->na.cand_up )
+ lc->na.cand_up_right_sap
&& (x0 + nPbW) < lc->end_of_tiles_x;
lc->na.cand_bottom_left = ((y0 + nPbH) >= lc->end_of_tiles_y) ? 0 : lc->na.cand_left;
}
@@ -61,56 +60,29 @@ void ff_hevc_set_neighbour_available(HEVCContext *s, int x0, int y0,
/*
* 6.4.1 Derivation process for z-scan order block availability
*/
-static int z_scan_block_avail(HEVCContext *s, int xCurr, int yCurr,
+static av_always_inline int z_scan_block_avail(HEVCContext *s, int xCurr, int yCurr,
int xN, int yN)
{
#define MIN_TB_ADDR_ZS(x, y) \
- s->pps->min_tb_addr_zs[(y) * s->sps->min_tb_width + (x)]
- int Curr = MIN_TB_ADDR_ZS(xCurr >> s->sps->log2_min_tb_size,
- yCurr >> s->sps->log2_min_tb_size);
- int N;
-
- if (xN < 0 || yN < 0 ||
- xN >= s->sps->width ||
- yN >= s->sps->height)
- return 0;
-
- N = MIN_TB_ADDR_ZS(xN >> s->sps->log2_min_tb_size,
- yN >> s->sps->log2_min_tb_size);
-
- return N <= Curr;
-}
-
-static int same_prediction_block(HEVCLocalContext *lc, int log2_cb_size,
- int x0, int y0, int nPbW, int nPbH,
- int xA1, int yA1, int partIdx)
-{
- return !(nPbW << 1 == 1 << log2_cb_size &&
- nPbH << 1 == 1 << log2_cb_size && partIdx == 1 &&
- lc->cu.x + nPbW > xA1 &&
- lc->cu.y + nPbH <= yA1);
-}
+ s->pps->min_tb_addr_zs[(y) * (s->sps->tb_mask+2) + (x)]
-/*
- * 6.4.2 Derivation process for prediction block availability
- */
-static int check_prediction_block_available(HEVCContext *s, int log2_cb_size,
- int x0, int y0, int nPbW, int nPbH,
- int xA1, int yA1, int partIdx)
-{
- HEVCLocalContext *lc = &s->HEVClc;
-
- if (lc->cu.x < xA1 && lc->cu.y < yA1 &&
- (lc->cu.x + (1 << log2_cb_size)) > xA1 &&
- (lc->cu.y + (1 << log2_cb_size)) > yA1)
- return same_prediction_block(lc, log2_cb_size, x0, y0,
- nPbW, nPbH, xA1, yA1, partIdx);
- else
- return z_scan_block_avail(s, x0, y0, xA1, yA1);
+ int xCurr_ctb = xCurr >> s->sps->log2_ctb_size;
+ int yCurr_ctb = yCurr >> s->sps->log2_ctb_size;
+ int xN_ctb = xN >> s->sps->log2_ctb_size;
+ int yN_ctb = yN >> s->sps->log2_ctb_size;
+ if( yN_ctb < yCurr_ctb || xN_ctb < xCurr_ctb )
+ return 1;
+ else {
+ int Curr = MIN_TB_ADDR_ZS((xCurr >> s->sps->log2_min_tb_size) & s->sps->tb_mask,
+ (yCurr >> s->sps->log2_min_tb_size) & s->sps->tb_mask);
+ int N = MIN_TB_ADDR_ZS((xN >> s->sps->log2_min_tb_size) & s->sps->tb_mask,
+ (yN >> s->sps->log2_min_tb_size) & s->sps->tb_mask);
+ return N <= Curr;
+ }
}
//check if the two luma locations belong to the same mostion estimation region
-static int isDiffMER(HEVCContext *s, int xN, int yN, int xP, int yP)
+static av_always_inline int is_diff_mer(HEVCContext *s, int xN, int yN, int xP, int yP)
{
uint8_t plevel = s->pps->log2_parallel_merge_level;
@@ -122,18 +94,20 @@ static int isDiffMER(HEVCContext *s, int xN, int yN, int xP, int yP)
#define MATCH(x) (A.x == B.x)
// check if the mv's and refidx are the same between A and B
-static int compareMVrefidx(struct MvField A, struct MvField B)
+static av_always_inline int compare_mv_ref_idx(struct MvField A, struct MvField B)
{
- if (A.pred_flag[0] && A.pred_flag[1] && B.pred_flag[0] && B.pred_flag[1])
- return MATCH(ref_idx[0]) && MATCH_MV(mv[0]) &&
- MATCH(ref_idx[1]) && MATCH_MV(mv[1]);
-
- if (A.pred_flag[0] && !A.pred_flag[1] && B.pred_flag[0] && !B.pred_flag[1])
- return MATCH(ref_idx[0]) && MATCH_MV(mv[0]);
-
- if (!A.pred_flag[0] && A.pred_flag[1] && !B.pred_flag[0] && B.pred_flag[1])
- return MATCH(ref_idx[1]) && MATCH_MV(mv[1]);
-
+ int a_pf = A.pred_flag;
+ int b_pf = B.pred_flag;
+ if (a_pf == b_pf) {
+ if (a_pf == PF_BI) {
+ return MATCH(ref_idx[0]) && MATCH_MV(mv[0]) &&
+ MATCH(ref_idx[1]) && MATCH_MV(mv[1]);
+ } else if (a_pf == PF_L0) {
+ return MATCH(ref_idx[0]) && MATCH_MV(mv[0]);
+ } else if (a_pf == PF_L1) {
+ return MATCH(ref_idx[1]) && MATCH_MV(mv[1]);
+ }
+ }
return 0;
}
@@ -144,11 +118,11 @@ static av_always_inline void mv_scale(Mv *dst, Mv *src, int td, int tb)
td = av_clip_int8(td);
tb = av_clip_int8(tb);
tx = (0x4000 + abs(td / 2)) / td;
- scale_factor = av_clip((tb * tx + 32) >> 6, -4096, 4095);
+ scale_factor = av_clip_intp2((tb * tx + 32) >> 6, 12);
dst->x = av_clip_int16((scale_factor * src->x + 127 +
- (scale_factor * src->x < 0)) >> 8);
+ (scale_factor * src->x < 0)) >> 8);
dst->y = av_clip_int16((scale_factor * src->y + 127 +
- (scale_factor * src->y < 0)) >> 8);
+ (scale_factor * src->y < 0)) >> 8);
}
static int check_mvset(Mv *mvLXCol, Mv *mvCol,
@@ -169,10 +143,7 @@ static int check_mvset(Mv *mvLXCol, Mv *mvCol,
col_poc_diff = colPic - refPicList_col[listCol].list[refidxCol];
cur_poc_diff = poc - refPicList[X].list[refIdxLx];
- if (!col_poc_diff)
- col_poc_diff = 1; // error resilience
-
- if (cur_lt || col_poc_diff == cur_poc_diff) {
+ if (cur_lt || col_poc_diff == cur_poc_diff || !col_poc_diff) {
mvLXCol->x = mvCol->x;
mvLXCol->y = mvCol->y;
} else {
@@ -194,32 +165,30 @@ static int derive_temporal_colocated_mvs(HEVCContext *s, MvField temp_col,
{
RefPicList *refPicList = s->ref->refPicList;
- if (temp_col.is_intra) {
- mvLXCol->x = 0;
- mvLXCol->y = 0;
+ if (temp_col.pred_flag == PF_INTRA)
return 0;
- }
- if (temp_col.pred_flag[0] == 0)
+ if (!(temp_col.pred_flag & PF_L0))
return CHECK_MVSET(1);
- else if (temp_col.pred_flag[0] == 1 && temp_col.pred_flag[1] == 0)
+ else if (temp_col.pred_flag == PF_L0)
return CHECK_MVSET(0);
- else if (temp_col.pred_flag[0] == 1 && temp_col.pred_flag[1] == 1) {
+ else if (temp_col.pred_flag == PF_BI) {
int check_diffpicount = 0;
- int i = 0;
- for (i = 0; i < refPicList[0].nb_refs; i++) {
- if (refPicList[0].list[i] > s->poc)
- check_diffpicount++;
- }
- for (i = 0; i < refPicList[1].nb_refs; i++) {
- if (refPicList[1].list[i] > s->poc)
- check_diffpicount++;
+ int i, j;
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < refPicList[j].nb_refs; i++) {
+ if (refPicList[j].list[i] > s->poc) {
+ check_diffpicount++;
+ break;
+ }
+ }
}
- if (check_diffpicount == 0 && X == 0)
- return CHECK_MVSET(0);
- else if (check_diffpicount == 0 && X == 1)
- return CHECK_MVSET(1);
- else {
+ if (!check_diffpicount) {
+ if (X==0)
+ return CHECK_MVSET(0);
+ else
+ return CHECK_MVSET(1);
+ } else {
if (s->sh.collocated_list == L1)
return CHECK_MVSET(0);
else
@@ -234,7 +203,8 @@ static int derive_temporal_colocated_mvs(HEVCContext *s, MvField temp_col,
tab_mvf[(y) * min_pu_width + x]
#define TAB_MVF_PU(v) \
- TAB_MVF(x ## v ## _pu, y ## v ## _pu)
+ TAB_MVF(((x ## v) >> s->sps->log2_min_pu_size), \
+ ((y ## v) >> s->sps->log2_min_pu_size))
#define DERIVE_TEMPORAL_COLOCATED_MVS \
derive_temporal_colocated_mvs(s, temp_col, \
@@ -275,7 +245,8 @@ static int temporal_luma_motion_vector(HEVCContext *s, int x0, int y0,
x < s->sps->width) {
x &= ~15;
y &= ~15;
- ff_thread_await_progress(&ref->tf, y, 0);
+ if (s->threads_type == FF_THREAD_FRAME)
+ ff_thread_await_progress(&ref->tf, y, 0);
x_pu = x >> s->sps->log2_min_pu_size;
y_pu = y >> s->sps->log2_min_pu_size;
temp_col = TAB_MVF(x_pu, y_pu);
@@ -288,7 +259,8 @@ static int temporal_luma_motion_vector(HEVCContext *s, int x0, int y0,
y = y0 + (nPbH >> 1);
x &= ~15;
y &= ~15;
- ff_thread_await_progress(&ref->tf, y, 0);
+ if (s->threads_type == FF_THREAD_FRAME)
+ ff_thread_await_progress(&ref->tf, y, 0);
x_pu = x >> s->sps->log2_min_pu_size;
y_pu = y >> s->sps->log2_min_pu_size;
temp_col = TAB_MVF(x_pu, y_pu);
@@ -298,15 +270,13 @@ static int temporal_luma_motion_vector(HEVCContext *s, int x0, int y0,
}
#define AVAILABLE(cand, v) \
- (cand && !TAB_MVF_PU(v).is_intra)
+ (cand && !(TAB_MVF_PU(v).pred_flag == PF_INTRA))
#define PRED_BLOCK_AVAILABLE(v) \
- check_prediction_block_available(s, log2_cb_size, \
- x0, y0, nPbW, nPbH, \
- x ## v, y ## v, part_idx)
+ z_scan_block_avail(s, x0, y0, x ## v, y ## v)
#define COMPARE_MV_REFIDX(a, b) \
- compareMVrefidx(TAB_MVF_PU(a), TAB_MVF_PU(b))
+ compare_mv_ref_idx(TAB_MVF_PU(a), TAB_MVF_PU(b))
/*
* 8.5.3.1.2 Derivation process for spatial merging candidates
@@ -318,7 +288,7 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
int merge_idx,
struct MvField mergecandlist[])
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
RefPicList *refPicList = s->ref->refPicList;
MvField *tab_mvf = s->ref->tab_mvf;
@@ -332,33 +302,21 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
const int xA1 = x0 - 1;
const int yA1 = y0 + nPbH - 1;
- const int xA1_pu = xA1 >> s->sps->log2_min_pu_size;
- const int yA1_pu = yA1 >> s->sps->log2_min_pu_size;
const int xB1 = x0 + nPbW - 1;
const int yB1 = y0 - 1;
- const int xB1_pu = xB1 >> s->sps->log2_min_pu_size;
- const int yB1_pu = yB1 >> s->sps->log2_min_pu_size;
const int xB0 = x0 + nPbW;
const int yB0 = y0 - 1;
- const int xB0_pu = xB0 >> s->sps->log2_min_pu_size;
- const int yB0_pu = yB0 >> s->sps->log2_min_pu_size;
const int xA0 = x0 - 1;
const int yA0 = y0 + nPbH;
- const int xA0_pu = xA0 >> s->sps->log2_min_pu_size;
- const int yA0_pu = yA0 >> s->sps->log2_min_pu_size;
const int xB2 = x0 - 1;
const int yB2 = y0 - 1;
- const int xB2_pu = xB2 >> s->sps->log2_min_pu_size;
- const int yB2_pu = yB2 >> s->sps->log2_min_pu_size;
const int nb_refs = (s->sh.slice_type == P_SLICE) ?
s->sh.nb_refs[0] : FFMIN(s->sh.nb_refs[0], s->sh.nb_refs[1]);
- int check_MER = 1;
- int check_MER_1 = 1;
int zero_idx = 0;
@@ -370,57 +328,49 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
int is_available_b0;
int is_available_b1;
int is_available_b2;
- int check_B0;
- int check_A0;
- //first left spatial merge candidate
- is_available_a1 = AVAILABLE(cand_left, A1);
if (!singleMCLFlag && part_idx == 1 &&
(lc->cu.part_mode == PART_Nx2N ||
lc->cu.part_mode == PART_nLx2N ||
lc->cu.part_mode == PART_nRx2N) ||
- isDiffMER(s, xA1, yA1, x0, y0)) {
+ is_diff_mer(s, xA1, yA1, x0, y0)) {
is_available_a1 = 0;
+ } else {
+ is_available_a1 = AVAILABLE(cand_left, A1);
+ if (is_available_a1) {
+ mergecandlist[nb_merge_cand] = TAB_MVF_PU(A1);
+ if (merge_idx == 0)
+ return;
+ nb_merge_cand++;
+ }
}
- if (is_available_a1) {
- mergecandlist[0] = TAB_MVF_PU(A1);
- if (merge_idx == 0)
- return;
- nb_merge_cand++;
- }
-
- // above spatial merge candidate
- is_available_b1 = AVAILABLE(cand_up, B1);
-
if (!singleMCLFlag && part_idx == 1 &&
(lc->cu.part_mode == PART_2NxN ||
lc->cu.part_mode == PART_2NxnU ||
lc->cu.part_mode == PART_2NxnD) ||
- isDiffMER(s, xB1, yB1, x0, y0)) {
+ is_diff_mer(s, xB1, yB1, x0, y0)) {
is_available_b1 = 0;
+ } else {
+ is_available_b1 = AVAILABLE(cand_up, B1);
+ if (is_available_b1 &&
+ !(is_available_a1 && COMPARE_MV_REFIDX(B1, A1))) {
+ mergecandlist[nb_merge_cand] = TAB_MVF_PU(B1);
+ if (merge_idx == nb_merge_cand)
+ return;
+ nb_merge_cand++;
+ }
}
- if (is_available_a1 && is_available_b1)
- check_MER = !COMPARE_MV_REFIDX(B1, A1);
-
- if (is_available_b1 && check_MER)
- mergecandlist[nb_merge_cand++] = TAB_MVF_PU(B1);
-
// above right spatial merge candidate
- check_MER = 1;
- check_B0 = PRED_BLOCK_AVAILABLE(B0);
-
- is_available_b0 = check_B0 && AVAILABLE(cand_up_right, B0);
+ is_available_b0 = AVAILABLE(cand_up_right, B0) &&
+ xB0 < s->sps->width &&
+ PRED_BLOCK_AVAILABLE(B0) &&
+ !is_diff_mer(s, xB0, yB0, x0, y0);
- if (isDiffMER(s, xB0, yB0, x0, y0))
- is_available_b0 = 0;
-
- if (is_available_b1 && is_available_b0)
- check_MER = !COMPARE_MV_REFIDX(B0, B1);
-
- if (is_available_b0 && check_MER) {
+ if (is_available_b0 &&
+ !(is_available_b1 && COMPARE_MV_REFIDX(B0, B1))) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(B0);
if (merge_idx == nb_merge_cand)
return;
@@ -428,18 +378,13 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
}
// left bottom spatial merge candidate
- check_MER = 1;
- check_A0 = PRED_BLOCK_AVAILABLE(A0);
-
- is_available_a0 = check_A0 && AVAILABLE(cand_bottom_left, A0);
+ is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
+ yA0 < s->sps->height &&
+ PRED_BLOCK_AVAILABLE(A0) &&
+ !is_diff_mer(s, xA0, yA0, x0, y0);
- if (isDiffMER(s, xA0, yA0, x0, y0))
- is_available_a0 = 0;
-
- if (is_available_a1 && is_available_a0)
- check_MER = !COMPARE_MV_REFIDX(A0, A1);
-
- if (is_available_a0 && check_MER) {
+ if (is_available_a0 &&
+ !(is_available_a1 && COMPARE_MV_REFIDX(A0, A1))) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(A0);
if (merge_idx == nb_merge_cand)
return;
@@ -447,20 +392,13 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
}
// above left spatial merge candidate
- check_MER = 1;
+ is_available_b2 = AVAILABLE(cand_up_left, B2) &&
+ !is_diff_mer(s, xB2, yB2, x0, y0);
- is_available_b2 = AVAILABLE(cand_up_left, B2);
-
- if (isDiffMER(s, xB2, yB2, x0, y0))
- is_available_b2 = 0;
-
- if (is_available_a1 && is_available_b2)
- check_MER = !COMPARE_MV_REFIDX(B2, A1);
-
- if (is_available_b1 && is_available_b2)
- check_MER_1 = !COMPARE_MV_REFIDX(B2, B1);
-
- if (is_available_b2 && check_MER && check_MER_1 && nb_merge_cand != 4) {
+ if (is_available_b2 &&
+ !(is_available_a1 && COMPARE_MV_REFIDX(B2, A1)) &&
+ !(is_available_b1 && COMPARE_MV_REFIDX(B2, B1)) &&
+ nb_merge_cand != 4) {
mergecandlist[nb_merge_cand] = TAB_MVF_PU(B2);
if (merge_idx == nb_merge_cand)
return;
@@ -478,9 +416,7 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
0, &mv_l1_col, 1) : 0;
if (available_l0 || available_l1) {
- mergecandlist[nb_merge_cand].is_intra = 0;
- mergecandlist[nb_merge_cand].pred_flag[0] = available_l0;
- mergecandlist[nb_merge_cand].pred_flag[1] = available_l1;
+ mergecandlist[nb_merge_cand].pred_flag = available_l0 + (available_l1 << 1);
AV_ZERO16(mergecandlist[nb_merge_cand].ref_idx);
mergecandlist[nb_merge_cand].mv[0] = mv_l0_col;
mergecandlist[nb_merge_cand].mv[1] = mv_l1_col;
@@ -496,7 +432,7 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
// combined bi-predictive merge candidates (applies for B slices)
if (s->sh.slice_type == B_SLICE && nb_orig_merge_cand > 1 &&
nb_orig_merge_cand < s->sh.max_num_merge_cand) {
- int comb_idx;
+ int comb_idx = 0;
for (comb_idx = 0; nb_merge_cand < s->sh.max_num_merge_cand &&
comb_idx < nb_orig_merge_cand * (nb_orig_merge_cand - 1); comb_idx++) {
@@ -505,17 +441,15 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
MvField l0_cand = mergecandlist[l0_cand_idx];
MvField l1_cand = mergecandlist[l1_cand_idx];
- if (l0_cand.pred_flag[0] && l1_cand.pred_flag[1] &&
+ if ((l0_cand.pred_flag & PF_L0) && (l1_cand.pred_flag & PF_L1) &&
(refPicList[0].list[l0_cand.ref_idx[0]] !=
refPicList[1].list[l1_cand.ref_idx[1]] ||
AV_RN32A(&l0_cand.mv[0]) != AV_RN32A(&l1_cand.mv[1]))) {
mergecandlist[nb_merge_cand].ref_idx[0] = l0_cand.ref_idx[0];
mergecandlist[nb_merge_cand].ref_idx[1] = l1_cand.ref_idx[1];
- mergecandlist[nb_merge_cand].pred_flag[0] = 1;
- mergecandlist[nb_merge_cand].pred_flag[1] = 1;
+ mergecandlist[nb_merge_cand].pred_flag = PF_BI;
AV_COPY32(&mergecandlist[nb_merge_cand].mv[0], &l0_cand.mv[0]);
AV_COPY32(&mergecandlist[nb_merge_cand].mv[1], &l1_cand.mv[1]);
- mergecandlist[nb_merge_cand].is_intra = 0;
if (merge_idx == nb_merge_cand)
return;
nb_merge_cand++;
@@ -525,11 +459,9 @@ static void derive_spatial_merge_candidates(HEVCContext *s, int x0, int y0,
// append Zero motion vector candidates
while (nb_merge_cand < s->sh.max_num_merge_cand) {
- mergecandlist[nb_merge_cand].pred_flag[0] = 1;
- mergecandlist[nb_merge_cand].pred_flag[1] = s->sh.slice_type == B_SLICE;
+ mergecandlist[nb_merge_cand].pred_flag = PF_L0 + ((s->sh.slice_type == B_SLICE) << 1);
AV_ZERO32(mergecandlist[nb_merge_cand].mv + 0);
AV_ZERO32(mergecandlist[nb_merge_cand].mv + 1);
- mergecandlist[nb_merge_cand].is_intra = 0;
mergecandlist[nb_merge_cand].ref_idx[0] = zero_idx < nb_refs ? zero_idx : 0;
mergecandlist[nb_merge_cand].ref_idx[1] = zero_idx < nb_refs ? zero_idx : 0;
@@ -552,7 +484,7 @@ void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW,
LOCAL_ALIGNED(4, MvField, mergecand_list, [MRG_MAX_NUM_CANDS]);
int nPbW2 = nPbW;
int nPbH2 = nPbH;
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
if (s->pps->log2_parallel_merge_level > 2 && nCS == 8) {
singleMCLFlag = 1;
@@ -568,11 +500,9 @@ void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW,
singleMCLFlag, part_idx,
merge_idx, mergecand_list);
- if (mergecand_list[merge_idx].pred_flag[0] == 1 &&
- mergecand_list[merge_idx].pred_flag[1] == 1 &&
+ if (mergecand_list[merge_idx].pred_flag == PF_BI &&
(nPbW2 + nPbH2) == 12) {
- mergecand_list[merge_idx].ref_idx[1] = -1;
- mergecand_list[merge_idx].pred_flag[1] = 0;
+ mergecand_list[merge_idx].pred_flag = PF_L0;
}
*mv = mergecand_list[merge_idx];
@@ -603,7 +533,7 @@ static int mv_mp_mode_mx(HEVCContext *s, int x, int y, int pred_flag_index,
RefPicList *refPicList = s->ref->refPicList;
- if (TAB_MVF(x, y).pred_flag[pred_flag_index] == 1 &&
+ if (((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) &&
refPicList[pred_flag_index].list[TAB_MVF(x, y).ref_idx[pred_flag_index]] == refPicList[ref_idx_curr].list[ref_idx]) {
*mv = TAB_MVF(x, y).mv[pred_flag_index];
return 1;
@@ -618,82 +548,73 @@ static int mv_mp_mode_mx_lt(HEVCContext *s, int x, int y, int pred_flag_index,
int min_pu_width = s->sps->min_pu_width;
RefPicList *refPicList = s->ref->refPicList;
- int currIsLongTerm = refPicList[ref_idx_curr].isLongTerm[ref_idx];
- int colIsLongTerm =
- refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])];
+ if ((TAB_MVF(x, y).pred_flag) & (1 << pred_flag_index)) {
+ int currIsLongTerm = refPicList[ref_idx_curr].isLongTerm[ref_idx];
- if (TAB_MVF(x, y).pred_flag[pred_flag_index] &&
- colIsLongTerm == currIsLongTerm) {
- *mv = TAB_MVF(x, y).mv[pred_flag_index];
- if (!currIsLongTerm)
- dist_scale(s, mv, min_pu_width, x, y,
- pred_flag_index, ref_idx_curr, ref_idx);
- return 1;
+ int colIsLongTerm =
+ refPicList[pred_flag_index].isLongTerm[(TAB_MVF(x, y).ref_idx[pred_flag_index])];
+
+ if (colIsLongTerm == currIsLongTerm) {
+ *mv = TAB_MVF(x, y).mv[pred_flag_index];
+ if (!currIsLongTerm)
+ dist_scale(s, mv, min_pu_width, x, y,
+ pred_flag_index, ref_idx_curr, ref_idx);
+ return 1;
+ }
}
return 0;
}
#define MP_MX(v, pred, mx) \
- mv_mp_mode_mx(s, x ## v ## _pu, y ## v ## _pu, pred, \
- &mx, ref_idx_curr, ref_idx)
+ mv_mp_mode_mx(s, \
+ (x ## v) >> s->sps->log2_min_pu_size, \
+ (y ## v) >> s->sps->log2_min_pu_size, \
+ pred, &mx, ref_idx_curr, ref_idx)
#define MP_MX_LT(v, pred, mx) \
- mv_mp_mode_mx_lt(s, x ## v ## _pu, y ## v ## _pu, pred, \
- &mx, ref_idx_curr, ref_idx)
+ mv_mp_mode_mx_lt(s, \
+ (x ## v) >> s->sps->log2_min_pu_size, \
+ (y ## v) >> s->sps->log2_min_pu_size, \
+ pred, &mx, ref_idx_curr, ref_idx)
void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, int nPbW,
int nPbH, int log2_cb_size, int part_idx,
int merge_idx, MvField *mv,
int mvp_lx_flag, int LX)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
MvField *tab_mvf = s->ref->tab_mvf;
int isScaledFlag_L0 = 0;
- int availableFlagLXA0 = 0;
- int availableFlagLXB0 = 0;
+ int availableFlagLXA0 = 1;
+ int availableFlagLXB0 = 1;
int numMVPCandLX = 0;
int min_pu_width = s->sps->min_pu_width;
int xA0, yA0;
- int xA0_pu, yA0_pu;
int is_available_a0;
-
int xA1, yA1;
- int xA1_pu, yA1_pu;
int is_available_a1;
-
int xB0, yB0;
- int xB0_pu, yB0_pu;
int is_available_b0;
-
int xB1, yB1;
- int xB1_pu = 0, yB1_pu = 0;
- int is_available_b1 = 0;
-
+ int is_available_b1;
int xB2, yB2;
- int xB2_pu = 0, yB2_pu = 0;
- int is_available_b2 = 0;
+ int is_available_b2;
+
Mv mvpcand_list[2] = { { 0 } };
- Mv mxA = { 0 };
- Mv mxB = { 0 };
- int ref_idx_curr = 0;
+ Mv mxA;
+ Mv mxB;
+ int ref_idx_curr;
int ref_idx = 0;
int pred_flag_index_l0;
int pred_flag_index_l1;
- int x0b = x0 & ((1 << s->sps->log2_ctb_size) - 1);
- int y0b = y0 & ((1 << s->sps->log2_ctb_size) - 1);
-
- int cand_up = (lc->ctb_up_flag || y0b);
- int cand_left = (lc->ctb_left_flag || x0b);
- int cand_up_left =
- (!x0b && !y0b) ? lc->ctb_up_left_flag : cand_left && cand_up;
- int cand_up_right =
- (x0b + nPbW == (1 << s->sps->log2_ctb_size) ||
- x0 + nPbW >= lc->end_of_tiles_x) ? lc->ctb_up_right_flag && !y0b
- : cand_up;
- int cand_bottom_left = (y0 + nPbH >= lc->end_of_tiles_y) ? 0 : cand_left;
+ const int cand_bottom_left = lc->na.cand_bottom_left;
+ const int cand_left = lc->na.cand_left;
+ const int cand_up_left = lc->na.cand_up_left;
+ const int cand_up = lc->na.cand_up;
+ const int cand_up_right = lc->na.cand_up_right_sap;
ref_idx_curr = LX;
ref_idx = mv->ref_idx[LX];
pred_flag_index_l0 = LX;
@@ -702,97 +623,109 @@ void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, int nPbW,
// left bottom spatial candidate
xA0 = x0 - 1;
yA0 = y0 + nPbH;
- xA0_pu = xA0 >> s->sps->log2_min_pu_size;
- yA0_pu = yA0 >> s->sps->log2_min_pu_size;
- is_available_a0 = PRED_BLOCK_AVAILABLE(A0) && AVAILABLE(cand_bottom_left, A0);
+ is_available_a0 = AVAILABLE(cand_bottom_left, A0) &&
+ yA0 < s->sps->height &&
+ PRED_BLOCK_AVAILABLE(A0);
//left spatial merge candidate
xA1 = x0 - 1;
yA1 = y0 + nPbH - 1;
- xA1_pu = xA1 >> s->sps->log2_min_pu_size;
- yA1_pu = yA1 >> s->sps->log2_min_pu_size;
is_available_a1 = AVAILABLE(cand_left, A1);
if (is_available_a0 || is_available_a1)
isScaledFlag_L0 = 1;
if (is_available_a0) {
- availableFlagLXA0 = MP_MX(A0, pred_flag_index_l0, mxA);
- if (!availableFlagLXA0)
- availableFlagLXA0 = MP_MX(A0, pred_flag_index_l1, mxA);
- }
-
- if (is_available_a1 && !availableFlagLXA0) {
- availableFlagLXA0 = MP_MX(A1, pred_flag_index_l0, mxA);
- if (!availableFlagLXA0)
- availableFlagLXA0 = MP_MX(A1, pred_flag_index_l1, mxA);
+ if (MP_MX(A0, pred_flag_index_l0, mxA)) {
+ goto b_candidates;
+ }
+ if (MP_MX(A0, pred_flag_index_l1, mxA)) {
+ goto b_candidates;
+ }
}
- if (is_available_a0 && !availableFlagLXA0) {
- availableFlagLXA0 = MP_MX_LT(A0, pred_flag_index_l0, mxA);
- if (!availableFlagLXA0)
- availableFlagLXA0 = MP_MX_LT(A0, pred_flag_index_l1, mxA);
+ if (is_available_a1) {
+ if (MP_MX(A1, pred_flag_index_l0, mxA)) {
+ goto b_candidates;
+ }
+ if (MP_MX(A1, pred_flag_index_l1, mxA)) {
+ goto b_candidates;
+ }
}
- if (is_available_a1 && !availableFlagLXA0) {
- availableFlagLXA0 = MP_MX_LT(A1, pred_flag_index_l0, mxA);
- if (!availableFlagLXA0)
- availableFlagLXA0 = MP_MX_LT(A1, pred_flag_index_l1, mxA);
+ if (is_available_a0) {
+ if (MP_MX_LT(A0, pred_flag_index_l0, mxA)) {
+ goto b_candidates;
+ }
+ if (MP_MX_LT(A0, pred_flag_index_l1, mxA)) {
+ goto b_candidates;
+ }
}
- if (availableFlagLXA0 && !mvp_lx_flag) {
- mv->mv[LX] = mxA;
- return;
+ if (is_available_a1) {
+ if (MP_MX_LT(A1, pred_flag_index_l0, mxA)) {
+ goto b_candidates;
+ }
+ if (MP_MX_LT(A1, pred_flag_index_l1, mxA)) {
+ goto b_candidates;
+ }
}
+ availableFlagLXA0 = 0;
+b_candidates:
// B candidates
// above right spatial merge candidate
xB0 = x0 + nPbW;
yB0 = y0 - 1;
- xB0_pu = xB0 >> s->sps->log2_min_pu_size;
- yB0_pu = yB0 >> s->sps->log2_min_pu_size;
- is_available_b0 = PRED_BLOCK_AVAILABLE(B0) && AVAILABLE(cand_up_right, B0);
+ is_available_b0 = AVAILABLE(cand_up_right, B0) &&
+ xB0 < s->sps->width &&
+ PRED_BLOCK_AVAILABLE(B0);
- if (is_available_b0) {
- availableFlagLXB0 = MP_MX(B0, pred_flag_index_l0, mxB);
- if (!availableFlagLXB0)
- availableFlagLXB0 = MP_MX(B0, pred_flag_index_l1, mxB);
- }
-
- if (!availableFlagLXB0) {
- // above spatial merge candidate
- xB1 = x0 + nPbW - 1;
- yB1 = y0 - 1;
- xB1_pu = xB1 >> s->sps->log2_min_pu_size;
- yB1_pu = yB1 >> s->sps->log2_min_pu_size;
+ // above spatial merge candidate
+ xB1 = x0 + nPbW - 1;
+ yB1 = y0 - 1;
+ is_available_b1 = AVAILABLE(cand_up, B1);
- is_available_b1 = AVAILABLE(cand_up, B1);
+ // above left spatial merge candidate
+ xB2 = x0 - 1;
+ yB2 = y0 - 1;
+ is_available_b2 = AVAILABLE(cand_up_left, B2);
- if (is_available_b1) {
- availableFlagLXB0 = MP_MX(B1, pred_flag_index_l0, mxB);
- if (!availableFlagLXB0)
- availableFlagLXB0 = MP_MX(B1, pred_flag_index_l1, mxB);
+ // above right spatial merge candidate
+ if (is_available_b0) {
+ if (MP_MX(B0, pred_flag_index_l0, mxB)) {
+ goto scalef;
+ }
+ if (MP_MX(B0, pred_flag_index_l1, mxB)) {
+ goto scalef;
}
}
- if (!availableFlagLXB0) {
- // above left spatial merge candidate
- xB2 = x0 - 1;
- yB2 = y0 - 1;
- xB2_pu = xB2 >> s->sps->log2_min_pu_size;
- yB2_pu = yB2 >> s->sps->log2_min_pu_size;
- is_available_b2 = AVAILABLE(cand_up_left, B2);
+ // above spatial merge candidate
+ if (is_available_b1) {
+ if (MP_MX(B1, pred_flag_index_l0, mxB)) {
+ goto scalef;
+ }
+ if (MP_MX(B1, pred_flag_index_l1, mxB)) {
+ goto scalef;
+ }
+ }
- if (is_available_b2) {
- availableFlagLXB0 = MP_MX(B2, pred_flag_index_l0, mxB);
- if (!availableFlagLXB0)
- availableFlagLXB0 = MP_MX(B2, pred_flag_index_l1, mxB);
+ // above left spatial merge candidate
+ if (is_available_b2) {
+ if (MP_MX(B2, pred_flag_index_l0, mxB)) {
+ goto scalef;
+ }
+ if (MP_MX(B2, pred_flag_index_l1, mxB)) {
+ goto scalef;
}
}
+ availableFlagLXB0 = 0;
- if (isScaledFlag_L0 == 0) {
+scalef:
+ if (!isScaledFlag_L0) {
if (availableFlagLXB0) {
availableFlagLXA0 = 1;
mxA = mxB;
@@ -836,10 +769,5 @@ void ff_hevc_luma_mv_mvp_mode(HEVCContext *s, int x0, int y0, int nPbW,
mvpcand_list[numMVPCandLX++] = mv_col;
}
- // insert zero motion vectors when the number of available candidates are less than 2
- while (numMVPCandLX < 2)
- mvpcand_list[numMVPCandLX++] = (Mv){ 0, 0 };
-
- mv->mv[LX].x = mvpcand_list[mvp_lx_flag].x;
- mv->mv[LX].y = mvpcand_list[mvp_lx_flag].y;
+ mv->mv[LX] = mvpcand_list[mvp_lx_flag];
}
diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c
index ac2c6f52d9..3c7c3c377d 100644
--- a/libavcodec/hevc_parser.c
+++ b/libavcodec/hevc_parser.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,9 +24,15 @@
#include "parser.h"
#include "hevc.h"
+#include "golomb.h"
#define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
+typedef struct HEVCParseContext {
+ HEVCContext h;
+ ParseContext pc;
+} HEVCParseContext;
+
/**
* Find the end of the current frame in the bitstream.
* @return the position of the first byte of the next frame, or END_NOT_FOUND
@@ -35,7 +41,7 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
int buf_size)
{
int i;
- ParseContext *pc = s->priv_data;
+ ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
for (i = 0; i < buf_size; i++) {
int nut;
@@ -59,7 +65,6 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
if (first_slice_segment_in_pic_flag) {
if (!pc->frame_start_found) {
pc->frame_start_found = 1;
- s->key_frame = nut >= NAL_BLA_W_LP && nut <= NAL_CRA_NUT;
} else { // First slice of next frame found
pc->frame_start_found = 0;
return i - 5;
@@ -71,12 +76,194 @@ static int hevc_find_frame_end(AVCodecParserContext *s, const uint8_t *buf,
return END_NOT_FOUND;
}
-static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
+/**
+ * Parse NAL units of found picture and decode some basic information.
+ *
+ * @param s parser context.
+ * @param avctx codec context.
+ * @param buf buffer with field/frame data.
+ * @param buf_size size of the buffer.
+ */
+static inline int parse_nal_units(AVCodecParserContext *s, AVCodecContext *avctx,
+ const uint8_t *buf, int buf_size)
+{
+ HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h;
+ GetBitContext *gb = &h->HEVClc->gb;
+ SliceHeader *sh = &h->sh;
+ const uint8_t *buf_end = buf + buf_size;
+ int state = -1, i;
+ HEVCNAL *nal;
+
+ /* set some sane default values */
+ s->pict_type = AV_PICTURE_TYPE_I;
+ s->key_frame = 0;
+ s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN;
+
+ h->avctx = avctx;
+
+ if (!buf_size)
+ return 0;
+
+ if (h->nals_allocated < 1) {
+ HEVCNAL *tmp = av_realloc_array(h->nals, 1, sizeof(*tmp));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ h->nals = tmp;
+ memset(h->nals, 0, sizeof(*tmp));
+ h->nals_allocated = 1;
+ }
+
+ nal = &h->nals[0];
+
+ for (;;) {
+ int src_length, consumed;
+ buf = avpriv_find_start_code(buf, buf_end, &state);
+ if (--buf + 2 >= buf_end)
+ break;
+ src_length = buf_end - buf;
+
+ h->nal_unit_type = (*buf >> 1) & 0x3f;
+ h->temporal_id = (*(buf + 1) & 0x07) - 1;
+ if (h->nal_unit_type <= NAL_CRA_NUT) {
+ // Do not walk the whole buffer just to decode slice segment header
+ if (src_length > 20)
+ src_length = 20;
+ }
+
+ consumed = ff_hevc_extract_rbsp(h, buf, src_length, nal);
+ if (consumed < 0)
+ return consumed;
+
+ init_get_bits8(gb, nal->data + 2, nal->size);
+ switch (h->nal_unit_type) {
+ case NAL_VPS:
+ ff_hevc_decode_nal_vps(h);
+ break;
+ case NAL_SPS:
+ ff_hevc_decode_nal_sps(h);
+ break;
+ case NAL_PPS:
+ ff_hevc_decode_nal_pps(h);
+ break;
+ case NAL_SEI_PREFIX:
+ case NAL_SEI_SUFFIX:
+ ff_hevc_decode_nal_sei(h);
+ break;
+ case NAL_TRAIL_N:
+ case NAL_TRAIL_R:
+ case NAL_TSA_N:
+ case NAL_TSA_R:
+ case NAL_STSA_N:
+ case NAL_STSA_R:
+ case NAL_RADL_N:
+ case NAL_RADL_R:
+ case NAL_RASL_N:
+ case NAL_RASL_R:
+ case NAL_BLA_W_LP:
+ case NAL_BLA_W_RADL:
+ case NAL_BLA_N_LP:
+ case NAL_IDR_W_RADL:
+ case NAL_IDR_N_LP:
+ case NAL_CRA_NUT:
+ sh->first_slice_in_pic_flag = get_bits1(gb);
+ s->picture_structure = h->picture_struct;
+ s->field_order = h->picture_struct;
+
+ if (IS_IRAP(h)) {
+ s->key_frame = 1;
+ sh->no_output_of_prior_pics_flag = get_bits1(gb);
+ }
+
+ sh->pps_id = get_ue_golomb(gb);
+ if (sh->pps_id >= MAX_PPS_COUNT || !h->pps_list[sh->pps_id]) {
+ av_log(h->avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", sh->pps_id);
+ return AVERROR_INVALIDDATA;
+ }
+ h->pps = (HEVCPPS*)h->pps_list[sh->pps_id]->data;
+
+ if (h->pps->sps_id >= MAX_SPS_COUNT || !h->sps_list[h->pps->sps_id]) {
+ av_log(h->avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", h->pps->sps_id);
+ return AVERROR_INVALIDDATA;
+ }
+ if (h->sps != (HEVCSPS*)h->sps_list[h->pps->sps_id]->data) {
+ h->sps = (HEVCSPS*)h->sps_list[h->pps->sps_id]->data;
+ h->vps = (HEVCVPS*)h->vps_list[h->sps->vps_id]->data;
+ }
+
+ if (!sh->first_slice_in_pic_flag) {
+ int slice_address_length;
+
+ if (h->pps->dependent_slice_segments_enabled_flag)
+ sh->dependent_slice_segment_flag = get_bits1(gb);
+ else
+ sh->dependent_slice_segment_flag = 0;
+
+ slice_address_length = av_ceil_log2_c(h->sps->ctb_width *
+ h->sps->ctb_height);
+ sh->slice_segment_addr = get_bits(gb, slice_address_length);
+ if (sh->slice_segment_addr >= h->sps->ctb_width * h->sps->ctb_height) {
+ av_log(h->avctx, AV_LOG_ERROR, "Invalid slice segment address: %u.\n",
+ sh->slice_segment_addr);
+ return AVERROR_INVALIDDATA;
+ }
+ } else
+ sh->dependent_slice_segment_flag = 0;
+
+ if (sh->dependent_slice_segment_flag)
+ break;
+
+ for (i = 0; i < h->pps->num_extra_slice_header_bits; i++)
+ skip_bits(gb, 1); // slice_reserved_undetermined_flag[]
+
+ sh->slice_type = get_ue_golomb(gb);
+ if (!(sh->slice_type == I_SLICE || sh->slice_type == P_SLICE ||
+ sh->slice_type == B_SLICE)) {
+ av_log(h->avctx, AV_LOG_ERROR, "Unknown slice type: %d.\n",
+ sh->slice_type);
+ return AVERROR_INVALIDDATA;
+ }
+ s->pict_type = sh->slice_type == B_SLICE ? AV_PICTURE_TYPE_B :
+ sh->slice_type == P_SLICE ? AV_PICTURE_TYPE_P :
+ AV_PICTURE_TYPE_I;
+
+ if (h->pps->output_flag_present_flag)
+ sh->pic_output_flag = get_bits1(gb);
+
+ if (h->sps->separate_colour_plane_flag)
+ sh->colour_plane_id = get_bits(gb, 2);
+
+ if (!IS_IDR(h)) {
+ sh->pic_order_cnt_lsb = get_bits(gb, h->sps->log2_max_poc_lsb);
+ s->output_picture_number = h->poc = ff_hevc_compute_poc(h, sh->pic_order_cnt_lsb);
+ } else
+ s->output_picture_number = h->poc = 0;
+
+ if (h->temporal_id == 0 &&
+ h->nal_unit_type != NAL_TRAIL_N &&
+ h->nal_unit_type != NAL_TSA_N &&
+ h->nal_unit_type != NAL_STSA_N &&
+ h->nal_unit_type != NAL_RADL_N &&
+ h->nal_unit_type != NAL_RASL_N &&
+ h->nal_unit_type != NAL_RADL_R &&
+ h->nal_unit_type != NAL_RASL_R)
+ h->pocTid0 = h->poc;
+
+ return 0; /* no need to evaluate the rest */
+ }
+ buf += consumed;
+ }
+ /* didn't find a picture! */
+ av_log(h->avctx, AV_LOG_ERROR, "missing picture in access unit\n");
+ return -1;
+}
+
+static int hevc_parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
int next;
- ParseContext *pc = s->priv_data;
+ ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
next = buf_size;
@@ -89,6 +276,8 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
}
}
+ parse_nal_units(s, avctx, buf, buf_size);
+
*poutbuf = buf;
*poutbuf_size = buf_size;
return next;
@@ -97,29 +286,66 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx,
// Split after the parameter sets at the beginning of the stream if they exist.
static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
{
- int i;
+ const uint8_t *ptr = buf, *end = buf + buf_size;
uint32_t state = -1;
- int has_ps = 0;
+ int has_ps = 0, nut;
- for (i = 0; i < buf_size; i++) {
- state = (state << 8) | buf[i];
- if (((state >> 8) & 0xFFFFFF) == START_CODE) {
- int nut = (state >> 1) & 0x3F;
- if (nut >= NAL_VPS && nut <= NAL_PPS)
- has_ps = 1;
- else if (has_ps)
- return i - 3;
- else // no parameter set at the beginning of the stream
- return 0;
- }
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &state);
+ if ((state >> 8) != START_CODE)
+ break;
+ nut = (state >> 1) & 0x3F;
+ if (nut >= NAL_VPS && nut <= NAL_PPS)
+ has_ps = 1;
+ else if (has_ps)
+ return ptr - 4 - buf;
+ else // no parameter set at the beginning of the stream
+ return 0;
}
return 0;
}
+static int hevc_init(AVCodecParserContext *s)
+{
+ HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h;
+ h->HEVClc = av_mallocz(sizeof(HEVCLocalContext));
+ if (!h->HEVClc)
+ return AVERROR(ENOMEM);
+ h->skipped_bytes_pos_size = INT_MAX;
+
+ return 0;
+}
+
+static void hevc_close(AVCodecParserContext *s)
+{
+ int i;
+ HEVCContext *h = &((HEVCParseContext *)s->priv_data)->h;
+ ParseContext *pc = &((HEVCParseContext *)s->priv_data)->pc;
+
+ av_freep(&h->skipped_bytes_pos);
+ av_freep(&h->HEVClc);
+ av_freep(&pc->buffer);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(h->vps_list); i++)
+ av_buffer_unref(&h->vps_list[i]);
+ for (i = 0; i < FF_ARRAY_ELEMS(h->sps_list); i++)
+ av_buffer_unref(&h->sps_list[i]);
+ for (i = 0; i < FF_ARRAY_ELEMS(h->pps_list); i++)
+ av_buffer_unref(&h->pps_list[i]);
+
+ h->sps = NULL;
+
+ for (i = 0; i < h->nals_allocated; i++)
+ av_freep(&h->nals[i].rbsp_buffer);
+ av_freep(&h->nals);
+ h->nals_allocated = 0;
+}
+
AVCodecParser ff_hevc_parser = {
.codec_ids = { AV_CODEC_ID_HEVC },
- .priv_data_size = sizeof(ParseContext),
+ .priv_data_size = sizeof(HEVCParseContext),
+ .parser_init = hevc_init,
.parser_parse = hevc_parse,
- .parser_close = ff_parse_close,
+ .parser_close = hevc_close,
.split = hevc_split,
};
diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c
index 83adc172c1..ced0600e32 100644
--- a/libavcodec/hevc_ps.c
+++ b/libavcodec/hevc_ps.c
@@ -6,25 +6,24 @@
* Copyright (C) 2012 - 2013 Gildas Cocherel
* Copyright (C) 2013 Vittorio Giovara
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/imgutils.h"
-
#include "golomb.h"
#include "hevc.h"
@@ -88,6 +87,8 @@ static void remove_sps(HEVCContext *s, int id)
for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++)
if (s->pps_list[i] && ((HEVCPPS*)s->pps_list[i]->data)->sps_id == id)
remove_pps(s, i);
+
+ av_assert0(!(s->sps_list[id] && s->sps == (HEVCSPS*)s->sps_list[id]->data));
}
av_buffer_unref(&s->sps_list[id]);
}
@@ -109,7 +110,7 @@ static void remove_vps(HEVCContext *s, int id)
int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
const HEVCSPS *sps, int is_slice_header)
{
- HEVCLocalContext *lc = &s->HEVClc;
+ HEVCLocalContext *lc = s->HEVClc;
uint8_t rps_predict = 0;
int delta_poc;
int k0 = 0;
@@ -124,7 +125,8 @@ int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
if (rps_predict) {
const ShortTermRPS *rps_ridx;
- int delta_rps, abs_delta_rps;
+ int delta_rps;
+ unsigned abs_delta_rps;
uint8_t use_delta_flag = 0;
uint8_t delta_rps_sign;
@@ -142,6 +144,12 @@ int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
delta_rps_sign = get_bits1(gb);
abs_delta_rps = get_ue_golomb_long(gb) + 1;
+ if (abs_delta_rps < 1 || abs_delta_rps > 32768) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Invalid value of abs_delta_rps: %d\n",
+ abs_delta_rps);
+ return AVERROR_INVALIDDATA;
+ }
delta_rps = (1 - (delta_rps_sign << 1)) * abs_delta_rps;
for (i = 0; i <= rps_ridx->num_delta_pocs; i++) {
int used = rps->used[k] = get_bits1(gb);
@@ -229,10 +237,14 @@ int ff_hevc_decode_short_term_rps(HEVCContext *s, ShortTermRPS *rps,
}
-static void decode_profile_tier_level(HEVCContext *s, PTLCommon *ptl)
+static int decode_profile_tier_level(HEVCContext *s, PTLCommon *ptl)
{
int i;
- GetBitContext *gb = &s->HEVClc.gb;
+ HEVCLocalContext *lc = s->HEVClc;
+ GetBitContext *gb = &lc->gb;
+
+ if (get_bits_left(gb) < 2+1+5 + 32 + 4 + 16 + 16 + 12)
+ return -1;
ptl->profile_space = get_bits(gb, 2);
ptl->tier_flag = get_bits1(gb);
@@ -243,6 +255,8 @@ static void decode_profile_tier_level(HEVCContext *s, PTLCommon *ptl)
av_log(s->avctx, AV_LOG_DEBUG, "Main 10 profile bitstream\n");
else if (ptl->profile_idc == FF_PROFILE_HEVC_MAIN_STILL_PICTURE)
av_log(s->avctx, AV_LOG_DEBUG, "Main Still Picture profile bitstream\n");
+ else if (ptl->profile_idc == FF_PROFILE_HEVC_REXT)
+ av_log(s->avctx, AV_LOG_DEBUG, "Range Extension profile bitstream\n");
else
av_log(s->avctx, AV_LOG_WARNING, "Unknown HEVC profile: %d\n", ptl->profile_idc);
@@ -256,34 +270,55 @@ static void decode_profile_tier_level(HEVCContext *s, PTLCommon *ptl)
skip_bits(gb, 16); // XXX_reserved_zero_44bits[0..15]
skip_bits(gb, 16); // XXX_reserved_zero_44bits[16..31]
skip_bits(gb, 12); // XXX_reserved_zero_44bits[32..43]
+
+ return 0;
}
-static void parse_ptl(HEVCContext *s, PTL *ptl, int max_num_sub_layers)
+static int parse_ptl(HEVCContext *s, PTL *ptl, int max_num_sub_layers)
{
int i;
- GetBitContext *gb = &s->HEVClc.gb;
- decode_profile_tier_level(s, &ptl->general_ptl);
+ HEVCLocalContext *lc = s->HEVClc;
+ GetBitContext *gb = &lc->gb;
+ if (decode_profile_tier_level(s, &ptl->general_ptl) < 0 ||
+ get_bits_left(gb) < 8 + 8*2) {
+ av_log(s->avctx, AV_LOG_ERROR, "PTL information too short\n");
+ return -1;
+ }
+
ptl->general_ptl.level_idc = get_bits(gb, 8);
for (i = 0; i < max_num_sub_layers - 1; i++) {
ptl->sub_layer_profile_present_flag[i] = get_bits1(gb);
ptl->sub_layer_level_present_flag[i] = get_bits1(gb);
}
- if (max_num_sub_layers - 1 > 0)
+
+ if (max_num_sub_layers - 1> 0)
for (i = max_num_sub_layers - 1; i < 8; i++)
skip_bits(gb, 2); // reserved_zero_2bits[i]
for (i = 0; i < max_num_sub_layers - 1; i++) {
- if (ptl->sub_layer_profile_present_flag[i])
- decode_profile_tier_level(s, &ptl->sub_layer_ptl[i]);
- if (ptl->sub_layer_level_present_flag[i])
- ptl->sub_layer_ptl[i].level_idc = get_bits(gb, 8);
+ if (ptl->sub_layer_profile_present_flag[i] &&
+ decode_profile_tier_level(s, &ptl->sub_layer_ptl[i]) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "PTL information for sublayer %i too short\n", i);
+ return -1;
+ }
+ if (ptl->sub_layer_level_present_flag[i]) {
+ if (get_bits_left(gb) < 8) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Not enough data for sublayer %i level_idc\n", i);
+ return -1;
+ } else
+ ptl->sub_layer_ptl[i].level_idc = get_bits(gb, 8);
+ }
}
+
+ return 0;
}
static void decode_sublayer_hrd(HEVCContext *s, unsigned int nb_cpb,
int subpic_params_present)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
int i;
for (i = 0; i < nb_cpb; i++) {
@@ -298,10 +333,10 @@ static void decode_sublayer_hrd(HEVCContext *s, unsigned int nb_cpb,
}
}
-static void decode_hrd(HEVCContext *s, int common_inf_present,
+static int decode_hrd(HEVCContext *s, int common_inf_present,
int max_sublayers)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
int nal_params_present = 0, vcl_params_present = 0;
int subpic_params_present = 0;
int i;
@@ -345,20 +380,26 @@ static void decode_hrd(HEVCContext *s, int common_inf_present,
else
low_delay = get_bits1(gb);
- if (!low_delay)
+ if (!low_delay) {
nb_cpb = get_ue_golomb_long(gb) + 1;
+ if (nb_cpb < 1 || nb_cpb > 32) {
+ av_log(s->avctx, AV_LOG_ERROR, "nb_cpb %d invalid\n", nb_cpb);
+ return AVERROR_INVALIDDATA;
+ }
+ }
if (nal_params_present)
decode_sublayer_hrd(s, nb_cpb, subpic_params_present);
if (vcl_params_present)
decode_sublayer_hrd(s, nb_cpb, subpic_params_present);
}
+ return 0;
}
int ff_hevc_decode_nal_vps(HEVCContext *s)
{
int i,j;
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
int vps_id = 0;
HEVCVPS *vps;
AVBufferRef *vps_buf = av_buffer_allocz(sizeof(*vps));
@@ -395,7 +436,8 @@ int ff_hevc_decode_nal_vps(HEVCContext *s)
goto err;
}
- parse_ptl(s, &vps->ptl, vps->vps_max_sub_layers);
+ if (parse_ptl(s, &vps->ptl, vps->vps_max_sub_layers) < 0)
+ goto err;
vps->vps_sub_layer_ordering_info_present_flag = get_bits1(gb);
@@ -405,7 +447,7 @@ int ff_hevc_decode_nal_vps(HEVCContext *s)
vps->vps_num_reorder_pics[i] = get_ue_golomb_long(gb);
vps->vps_max_latency_increase[i] = get_ue_golomb_long(gb) - 1;
- if (vps->vps_max_dec_pic_buffering[i] > MAX_DPB_SIZE) {
+ if (vps->vps_max_dec_pic_buffering[i] > MAX_DPB_SIZE || !vps->vps_max_dec_pic_buffering[i]) {
av_log(s->avctx, AV_LOG_ERROR, "vps_max_dec_pic_buffering_minus1 out of range: %d\n",
vps->vps_max_dec_pic_buffering[i] - 1);
goto err;
@@ -420,6 +462,12 @@ int ff_hevc_decode_nal_vps(HEVCContext *s)
vps->vps_max_layer_id = get_bits(gb, 6);
vps->vps_num_layer_sets = get_ue_golomb_long(gb) + 1;
+ if (vps->vps_num_layer_sets < 1 || vps->vps_num_layer_sets > 1024 ||
+ (vps->vps_num_layer_sets - 1LL) * (vps->vps_max_layer_id + 1LL) > get_bits_left(gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "too many layer_id_included_flags\n");
+ goto err;
+ }
+
for (i = 1; i < vps->vps_num_layer_sets; i++)
for (j = 0; j <= vps->vps_max_layer_id; j++)
skip_bits(gb, 1); // layer_id_included_flag[i][j]
@@ -432,6 +480,11 @@ int ff_hevc_decode_nal_vps(HEVCContext *s)
if (vps->vps_poc_proportional_to_timing_flag)
vps->vps_num_ticks_poc_diff_one = get_ue_golomb_long(gb) + 1;
vps->vps_num_hrd_parameters = get_ue_golomb_long(gb);
+ if (vps->vps_num_hrd_parameters > (unsigned)vps->vps_num_layer_sets) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "vps_num_hrd_parameters %d is invalid\n", vps->vps_num_hrd_parameters);
+ goto err;
+ }
for (i = 0; i < vps->vps_num_hrd_parameters; i++) {
int common_inf_present = 1;
@@ -443,6 +496,12 @@ int ff_hevc_decode_nal_vps(HEVCContext *s)
}
get_bits1(gb); /* vps_extension_flag */
+ if (get_bits_left(gb) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Overread VPS by %d bits\n", -get_bits_left(gb));
+ goto err;
+ }
+
if (s->vps_list[vps_id] &&
!memcmp(s->vps_list[vps_id]->data, vps_buf->data, vps_buf->size)) {
av_buffer_unref(&vps_buf);
@@ -461,8 +520,9 @@ err:
static void decode_vui(HEVCContext *s, HEVCSPS *sps)
{
VUI *vui = &sps->vui;
- GetBitContext *gb = &s->HEVClc.gb;
- int sar_present;
+ GetBitContext *gb = &s->HEVClc->gb;
+ GetBitContext backup;
+ int sar_present, alt = 0;
av_log(s->avctx, AV_LOG_DEBUG, "Decoding VUI\n");
@@ -515,7 +575,14 @@ static void decode_vui(HEVCContext *s, HEVCSPS *sps)
vui->field_seq_flag = get_bits1(gb);
vui->frame_field_info_present_flag = get_bits1(gb);
- vui->default_display_window_flag = get_bits1(gb);
+ if (get_bits_left(gb) >= 68 && show_bits_long(gb, 21) == 0x100000) {
+ vui->default_display_window_flag = 0;
+ av_log(s->avctx, AV_LOG_WARNING, "Invalid default display window\n");
+ } else
+ vui->default_display_window_flag = get_bits1(gb);
+ // Backup context in case an alternate header is detected
+ memcpy(&backup, gb, sizeof(backup));
+
if (vui->default_display_window_flag) {
//TODO: * 2 is only valid for 420
vui->def_disp_win.left_offset = get_ue_golomb_long(gb) * 2;
@@ -541,9 +608,24 @@ static void decode_vui(HEVCContext *s, HEVCSPS *sps)
}
vui->vui_timing_info_present_flag = get_bits1(gb);
+
if (vui->vui_timing_info_present_flag) {
+ if( get_bits_left(gb) < 66) {
+ // The alternate syntax seem to have timing info located
+ // at where def_disp_win is normally located
+ av_log(s->avctx, AV_LOG_WARNING,
+ "Strange VUI timing information, retrying...\n");
+ vui->default_display_window_flag = 0;
+ memset(&vui->def_disp_win, 0, sizeof(vui->def_disp_win));
+ memcpy(gb, &backup, sizeof(backup));
+ alt = 1;
+ }
vui->vui_num_units_in_tick = get_bits_long(gb, 32);
vui->vui_time_scale = get_bits_long(gb, 32);
+ if (alt) {
+ av_log(s->avctx, AV_LOG_INFO, "Retry got %i/%i fps\n",
+ vui->vui_time_scale, vui->vui_num_units_in_tick);
+ }
vui->vui_poc_proportional_to_timing_flag = get_bits1(gb);
if (vui->vui_poc_proportional_to_timing_flag)
vui->vui_num_ticks_poc_diff_one_minus1 = get_ue_golomb_long(gb);
@@ -588,20 +670,25 @@ static void set_default_scaling_list_data(ScalingList *sl)
memcpy(sl->sl[2][4], default_scaling_list_inter, 64);
memcpy(sl->sl[2][5], default_scaling_list_inter, 64);
memcpy(sl->sl[3][0], default_scaling_list_intra, 64);
- memcpy(sl->sl[3][1], default_scaling_list_inter, 64);
+ memcpy(sl->sl[3][1], default_scaling_list_intra, 64);
+ memcpy(sl->sl[3][2], default_scaling_list_intra, 64);
+ memcpy(sl->sl[3][3], default_scaling_list_inter, 64);
+ memcpy(sl->sl[3][4], default_scaling_list_inter, 64);
+ memcpy(sl->sl[3][5], default_scaling_list_inter, 64);
}
-static int scaling_list_data(HEVCContext *s, ScalingList *sl)
+static int scaling_list_data(HEVCContext *s, ScalingList *sl, HEVCSPS *sps)
{
- GetBitContext *gb = &s->HEVClc.gb;
- uint8_t scaling_list_pred_mode_flag[4][6];
+ GetBitContext *gb = &s->HEVClc->gb;
+ uint8_t scaling_list_pred_mode_flag;
int32_t scaling_list_dc_coef[2][6];
- int size_id, matrix_id, i, pos;
+ int size_id, matrix_id, pos;
+ int i;
for (size_id = 0; size_id < 4; size_id++)
- for (matrix_id = 0; matrix_id < (size_id == 3 ? 2 : 6); matrix_id++) {
- scaling_list_pred_mode_flag[size_id][matrix_id] = get_bits1(gb);
- if (!scaling_list_pred_mode_flag[size_id][matrix_id]) {
+ for (matrix_id = 0; matrix_id < 6; matrix_id += ((size_id == 3) ? 3 : 1)) {
+ scaling_list_pred_mode_flag = get_bits1(gb);
+ if (!scaling_list_pred_mode_flag) {
unsigned int delta = get_ue_golomb_long(gb);
/* Only need to handle non-zero delta. Zero means default,
* which should already be in the arrays. */
@@ -645,13 +732,27 @@ static int scaling_list_data(HEVCContext *s, ScalingList *sl)
}
}
+ if (sps->chroma_format_idc == 3) {
+ for (i = 0; i < 64; i++) {
+ sl->sl[3][1][i] = sl->sl[2][1][i];
+ sl->sl[3][2][i] = sl->sl[2][2][i];
+ sl->sl[3][4][i] = sl->sl[2][4][i];
+ sl->sl[3][5][i] = sl->sl[2][5][i];
+ }
+ sl->sl_dc[1][1] = sl->sl_dc[0][1];
+ sl->sl_dc[1][2] = sl->sl_dc[0][2];
+ sl->sl_dc[1][4] = sl->sl_dc[0][4];
+ sl->sl_dc[1][5] = sl->sl_dc[0][5];
+ }
+
+
return 0;
}
int ff_hevc_decode_nal_sps(HEVCContext *s)
{
const AVPixFmtDescriptor *desc;
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
int ret = 0;
unsigned int sps_id = 0;
int log2_diff_max_min_transform_block_size;
@@ -693,7 +794,8 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
skip_bits1(gb); // temporal_id_nesting_flag
- parse_ptl(s, &sps->ptl, sps->max_sub_layers);
+ if (parse_ptl(s, &sps->ptl, sps->max_sub_layers) < 0)
+ goto err;
sps_id = get_ue_golomb_long(gb);
if (sps_id >= MAX_SPS_COUNT) {
@@ -703,15 +805,13 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
}
sps->chroma_format_idc = get_ue_golomb_long(gb);
- if (sps->chroma_format_idc != 1) {
- avpriv_report_missing_feature(s->avctx, "chroma_format_idc != 1\n");
- ret = AVERROR_PATCHWELCOME;
- goto err;
- }
if (sps->chroma_format_idc == 3)
sps->separate_colour_plane_flag = get_bits1(gb);
+ if (sps->separate_colour_plane_flag)
+ sps->chroma_format_idc = 0;
+
sps->width = get_ue_golomb_long(gb);
sps->height = get_ue_golomb_long(gb);
if ((ret = av_image_check_size(sps->width,
@@ -744,7 +844,7 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
sps->bit_depth = get_ue_golomb_long(gb) + 8;
bit_depth_chroma = get_ue_golomb_long(gb) + 8;
- if (bit_depth_chroma != sps->bit_depth) {
+ if (sps->chroma_format_idc && bit_depth_chroma != sps->bit_depth) {
av_log(s->avctx, AV_LOG_ERROR,
"Luma bit depth (%d) is different from chroma bit depth (%d), "
"this is unsupported.\n",
@@ -753,21 +853,36 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
goto err;
}
- if (sps->chroma_format_idc == 1) {
- switch (sps->bit_depth) {
- case 8: sps->pix_fmt = AV_PIX_FMT_YUV420P; break;
- case 9: sps->pix_fmt = AV_PIX_FMT_YUV420P9; break;
- case 10: sps->pix_fmt = AV_PIX_FMT_YUV420P10; break;
- default:
- av_log(s->avctx, AV_LOG_ERROR, "Unsupported bit depth: %d\n",
- sps->bit_depth);
- ret = AVERROR_PATCHWELCOME;
- goto err;
- }
- } else {
+ switch (sps->bit_depth) {
+ case 8:
+ if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY8;
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P;
+ break;
+ case 9:
+ if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY16;
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P9;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P9;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P9;
+ break;
+ case 10:
+ if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY16;
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P10;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P10;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P10;
+ break;
+ case 12:
+ if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY16;
+ if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P12;
+ if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P12;
+ if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P12;
+ break;
+ default:
av_log(s->avctx, AV_LOG_ERROR,
- "non-4:2:0 support is currently unspecified.\n");
- return AVERROR_PATCHWELCOME;
+ "4:2:0, 4:2:2, 4:4:4 supports are currently specified for 8, 10 and 12 bits.\n");
+ ret = AVERROR_PATCHWELCOME;
+ goto err;
}
desc = av_pix_fmt_desc_get(sps->pix_fmt);
@@ -829,11 +944,30 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
sps->log2_max_trafo_size = log2_diff_max_min_transform_block_size +
sps->log2_min_tb_size;
- if (sps->log2_min_tb_size >= sps->log2_min_cb_size) {
+ if (sps->log2_min_cb_size < 3 || sps->log2_min_cb_size > 30) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid value %d for log2_min_cb_size", sps->log2_min_cb_size);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ if (sps->log2_diff_max_min_coding_block_size > 30) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid value %d for log2_diff_max_min_coding_block_size", sps->log2_diff_max_min_coding_block_size);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
+ if (sps->log2_min_tb_size >= sps->log2_min_cb_size || sps->log2_min_tb_size < 2) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid value for log2_min_tb_size");
ret = AVERROR_INVALIDDATA;
goto err;
}
+
+ if (log2_diff_max_min_transform_block_size < 0 || log2_diff_max_min_transform_block_size > 30) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid value %d for log2_diff_max_min_transform_block_size", log2_diff_max_min_transform_block_size);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
sps->max_transform_hierarchy_depth_inter = get_ue_golomb_long(gb);
sps->max_transform_hierarchy_depth_intra = get_ue_golomb_long(gb);
@@ -842,7 +976,7 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
set_default_scaling_list_data(&sps->scaling_list);
if (get_bits1(gb)) {
- ret = scaling_list_data(s, &sps->scaling_list);
+ ret = scaling_list_data(s, &sps->scaling_list, sps);
if (ret < 0)
goto err;
}
@@ -885,6 +1019,11 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
sps->long_term_ref_pics_present_flag = get_bits1(gb);
if (sps->long_term_ref_pics_present_flag) {
sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb);
+ if (sps->num_long_term_ref_pics_sps > 31U) {
+ av_log(s->avctx, AV_LOG_ERROR, "num_long_term_ref_pics_sps %d is out of range.\n",
+ sps->num_long_term_ref_pics_sps);
+ goto err;
+ }
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);
@@ -897,8 +1036,42 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
vui_present = get_bits1(gb);
if (vui_present)
decode_vui(s, sps);
- skip_bits1(gb); // sps_extension_flag
+ if (get_bits1(gb)) { // sps_extension_flag
+ int sps_extension_flag[1];
+ for (i = 0; i < 1; i++)
+ sps_extension_flag[i] = get_bits1(gb);
+ skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7);
+ if (sps_extension_flag[0]) {
+ int extended_precision_processing_flag;
+ int high_precision_offsets_enabled_flag;
+ int cabac_bypass_alignment_enabled_flag;
+
+ sps->transform_skip_rotation_enabled_flag = get_bits1(gb);
+ sps->transform_skip_context_enabled_flag = get_bits1(gb);
+ sps->implicit_rdpcm_enabled_flag = get_bits1(gb);
+
+ sps->explicit_rdpcm_enabled_flag = get_bits1(gb);
+
+ extended_precision_processing_flag = get_bits1(gb);
+ if (extended_precision_processing_flag)
+ av_log(s->avctx, AV_LOG_WARNING,
+ "extended_precision_processing_flag not yet implemented\n");
+
+ sps->intra_smoothing_disabled_flag = get_bits1(gb);
+ high_precision_offsets_enabled_flag = get_bits1(gb);
+ if (high_precision_offsets_enabled_flag)
+ av_log(s->avctx, AV_LOG_WARNING,
+ "high_precision_offsets_enabled_flag not yet implemented\n");
+
+ sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb);
+
+ cabac_bypass_alignment_enabled_flag = get_bits1(gb);
+ if (cabac_bypass_alignment_enabled_flag)
+ av_log(s->avctx, AV_LOG_WARNING,
+ "cabac_bypass_alignment_enabled_flag not yet implemented\n");
+ }
+ }
if (s->apply_defdispwin) {
sps->output_window.left_offset += sps->vui.def_disp_win.left_offset;
sps->output_window.right_offset += sps->vui.def_disp_win.right_offset;
@@ -916,7 +1089,8 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
(sps->output_window.left_offset + sps->output_window.right_offset);
sps->output_height = sps->height -
(sps->output_window.top_offset + sps->output_window.bottom_offset);
- if (sps->output_width <= 0 || sps->output_height <= 0) {
+ if (sps->width <= sps->output_window.left_offset + (int64_t)sps->output_window.right_offset ||
+ sps->height <= sps->output_window.top_offset + (int64_t)sps->output_window.bottom_offset) {
av_log(s->avctx, AV_LOG_WARNING, "Invalid visible frame dimensions: %dx%d.\n",
sps->output_width, sps->output_height);
if (s->avctx->err_recognition & AV_EF_EXPLODE) {
@@ -925,10 +1099,8 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
}
av_log(s->avctx, AV_LOG_WARNING,
"Displaying the whole video surface.\n");
- sps->output_window.left_offset =
- sps->output_window.right_offset =
- sps->output_window.top_offset =
- sps->output_window.bottom_offset = 0;
+ memset(&sps->pic_conf_win, 0, sizeof(sps->pic_conf_win));
+ memset(&sps->output_window, 0, sizeof(sps->output_window));
sps->output_width = sps->width;
sps->output_height = sps->height;
}
@@ -938,6 +1110,19 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
sps->log2_diff_max_min_coding_block_size;
sps->log2_min_pu_size = sps->log2_min_cb_size - 1;
+ if (sps->log2_ctb_size > MAX_LOG2_CTB_SIZE) {
+ av_log(s->avctx, AV_LOG_ERROR, "CTB size out of range: 2^%d\n", sps->log2_ctb_size);
+ goto err;
+ }
+ if (sps->log2_ctb_size < 4) {
+ av_log(s->avctx,
+ AV_LOG_ERROR,
+ "log2_ctb_size %d differs from the bounds of any known profile\n",
+ sps->log2_ctb_size);
+ avpriv_request_sample(s->avctx, "log2_ctb_size %d", sps->log2_ctb_size);
+ goto err;
+ }
+
sps->ctb_width = (sps->width + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size;
sps->ctb_height = (sps->height + (1 << sps->log2_ctb_size) - 1) >> sps->log2_ctb_size;
sps->ctb_size = sps->ctb_width * sps->ctb_height;
@@ -948,19 +1133,16 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
sps->min_tb_height = sps->height >> sps->log2_min_tb_size;
sps->min_pu_width = sps->width >> sps->log2_min_pu_size;
sps->min_pu_height = sps->height >> sps->log2_min_pu_size;
+ sps->tb_mask = (1 << (sps->log2_ctb_size - sps->log2_min_tb_size)) - 1;
sps->qp_bd_offset = 6 * (sps->bit_depth - 8);
- if (sps->width & ((1 << sps->log2_min_cb_size) - 1) ||
- sps->height & ((1 << sps->log2_min_cb_size) - 1)) {
+ if (av_mod_uintp2(sps->width, sps->log2_min_cb_size) ||
+ av_mod_uintp2(sps->height, sps->log2_min_cb_size)) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid coded frame dimensions.\n");
goto err;
}
- if (sps->log2_ctb_size > MAX_LOG2_CTB_SIZE) {
- av_log(s->avctx, AV_LOG_ERROR, "CTB size out of range: 2^%d\n", sps->log2_ctb_size);
- goto err;
- }
if (sps->max_transform_hierarchy_depth_inter > sps->log2_ctb_size - sps->log2_min_tb_size) {
av_log(s->avctx, AV_LOG_ERROR, "max_transform_hierarchy_depth_inter out of range: %d\n",
sps->max_transform_hierarchy_depth_inter);
@@ -978,6 +1160,12 @@ int ff_hevc_decode_nal_sps(HEVCContext *s)
goto err;
}
+ if (get_bits_left(gb) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Overread SPS by %d bits\n", -get_bits_left(gb));
+ goto err;
+ }
+
if (s->avctx->debug & FF_DEBUG_BITSTREAM) {
av_log(s->avctx, AV_LOG_DEBUG,
"Parsed SPS: id %d; coded wxh: %dx%d; "
@@ -1018,16 +1206,52 @@ static void hevc_pps_free(void *opaque, uint8_t *data)
av_freep(&pps->ctb_addr_ts_to_rs);
av_freep(&pps->tile_pos_rs);
av_freep(&pps->tile_id);
- av_freep(&pps->min_tb_addr_zs);
+ av_freep(&pps->min_tb_addr_zs_tab);
av_freep(&pps);
}
+static int pps_range_extensions(HEVCContext *s, HEVCPPS *pps, HEVCSPS *sps) {
+ GetBitContext *gb = &s->HEVClc->gb;
+ int i;
+
+ if (pps->transform_skip_enabled_flag) {
+ pps->log2_max_transform_skip_block_size = get_ue_golomb_long(gb) + 2;
+ }
+ pps->cross_component_prediction_enabled_flag = get_bits1(gb);
+ pps->chroma_qp_offset_list_enabled_flag = get_bits1(gb);
+ if (pps->chroma_qp_offset_list_enabled_flag) {
+ pps->diff_cu_chroma_qp_offset_depth = get_ue_golomb_long(gb);
+ pps->chroma_qp_offset_list_len_minus1 = get_ue_golomb_long(gb);
+ if (pps->chroma_qp_offset_list_len_minus1 && pps->chroma_qp_offset_list_len_minus1 >= 5) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "chroma_qp_offset_list_len_minus1 shall be in the range [0, 5].\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) {
+ pps->cb_qp_offset_list[i] = get_se_golomb_long(gb);
+ if (pps->cb_qp_offset_list[i]) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "cb_qp_offset_list not tested yet.\n");
+ }
+ pps->cr_qp_offset_list[i] = get_se_golomb_long(gb);
+ if (pps->cr_qp_offset_list[i]) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "cb_qp_offset_list not tested yet.\n");
+ }
+ }
+ }
+ pps->log2_sao_offset_scale_luma = get_ue_golomb_long(gb);
+ pps->log2_sao_offset_scale_chroma = get_ue_golomb_long(gb);
+
+ return(0);
+}
+
int ff_hevc_decode_nal_pps(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
HEVCSPS *sps = NULL;
- int pic_area_in_ctbs, pic_area_in_min_tbs;
+ int pic_area_in_ctbs;
int log2_diff_ctb_min_tb_size;
int i, j, x, y, ctb_addr_rs, tile_id;
int ret = 0;
@@ -1056,6 +1280,7 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
pps->disable_dbf = 0;
pps->beta_offset = 0;
pps->tc_offset = 0;
+ pps->log2_max_transform_skip_block_size = 2;
// Coded parameters
pps_id = get_ue_golomb_long(gb);
@@ -1098,6 +1323,14 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
if (pps->cu_qp_delta_enabled_flag)
pps->diff_cu_qp_delta_depth = get_ue_golomb_long(gb);
+ if (pps->diff_cu_qp_delta_depth < 0 ||
+ pps->diff_cu_qp_delta_depth > sps->log2_diff_max_min_coding_block_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "diff_cu_qp_delta_depth %d is invalid\n",
+ pps->diff_cu_qp_delta_depth);
+ ret = AVERROR_INVALIDDATA;
+ goto err;
+ }
+
pps->cb_qp_offset = get_se_golomb(gb);
if (pps->cb_qp_offset < -12 || pps->cb_qp_offset > 12) {
av_log(s->avctx, AV_LOG_ERROR, "pps_cb_qp_offset out of range: %d\n",
@@ -1124,14 +1357,14 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
if (pps->tiles_enabled_flag) {
pps->num_tile_columns = get_ue_golomb_long(gb) + 1;
pps->num_tile_rows = get_ue_golomb_long(gb) + 1;
- if (pps->num_tile_columns == 0 ||
+ if (pps->num_tile_columns <= 0 ||
pps->num_tile_columns >= sps->width) {
av_log(s->avctx, AV_LOG_ERROR, "num_tile_columns_minus1 out of range: %d\n",
pps->num_tile_columns - 1);
ret = AVERROR_INVALIDDATA;
goto err;
}
- if (pps->num_tile_rows == 0 ||
+ if (pps->num_tile_rows <= 0 ||
pps->num_tile_rows >= sps->height) {
av_log(s->avctx, AV_LOG_ERROR, "num_tile_rows_minus1 out of range: %d\n",
pps->num_tile_rows - 1);
@@ -1202,7 +1435,7 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
pps->scaling_list_data_present_flag = get_bits1(gb);
if (pps->scaling_list_data_present_flag) {
set_default_scaling_list_data(&pps->scaling_list);
- ret = scaling_list_data(s, &pps->scaling_list);
+ ret = scaling_list_data(s, &pps->scaling_list, sps);
if (ret < 0)
goto err;
}
@@ -1216,7 +1449,15 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
}
pps->slice_header_extension_present_flag = get_bits1(gb);
- skip_bits1(gb); // pps_extension_flag
+
+ if (get_bits1(gb)) { // pps_extension_present_flag
+ int pps_range_extensions_flag = get_bits1(gb);
+ /* int pps_extension_7bits = */ get_bits(gb, 7);
+ if (sps->ptl.general_ptl.profile_idc == FF_PROFILE_HEVC_REXT && pps_range_extensions_flag) {
+ if ((ret = pps_range_extensions(s, pps, sps)) < 0)
+ goto err;
+ }
+ }
// Inferred parameters
pps->col_bd = av_malloc_array(pps->num_tile_columns + 1, sizeof(*pps->col_bd));
@@ -1266,14 +1507,13 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
* 6.5
*/
pic_area_in_ctbs = sps->ctb_width * sps->ctb_height;
- pic_area_in_min_tbs = sps->min_tb_width * sps->min_tb_height;
pps->ctb_addr_rs_to_ts = av_malloc_array(pic_area_in_ctbs, sizeof(*pps->ctb_addr_rs_to_ts));
pps->ctb_addr_ts_to_rs = av_malloc_array(pic_area_in_ctbs, sizeof(*pps->ctb_addr_ts_to_rs));
pps->tile_id = av_malloc_array(pic_area_in_ctbs, sizeof(*pps->tile_id));
- pps->min_tb_addr_zs = av_malloc_array(pic_area_in_min_tbs, sizeof(*pps->min_tb_addr_zs));
+ pps->min_tb_addr_zs_tab = av_malloc_array((sps->tb_mask+2) * (sps->tb_mask+2), sizeof(*pps->min_tb_addr_zs_tab));
if (!pps->ctb_addr_rs_to_ts || !pps->ctb_addr_ts_to_rs ||
- !pps->tile_id || !pps->min_tb_addr_zs) {
+ !pps->tile_id || !pps->min_tb_addr_zs_tab) {
ret = AVERROR(ENOMEM);
goto err;
}
@@ -1328,8 +1568,13 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
pps->tile_pos_rs[j * pps->num_tile_columns + i] = pps->row_bd[j] * sps->ctb_width + pps->col_bd[i];
log2_diff_ctb_min_tb_size = sps->log2_ctb_size - sps->log2_min_tb_size;
- for (y = 0; y < sps->min_tb_height; y++) {
- for (x = 0; x < sps->min_tb_width; x++) {
+ pps->min_tb_addr_zs = &pps->min_tb_addr_zs_tab[1*(sps->tb_mask+2)+1];
+ for (y = 0; y < sps->tb_mask+2; y++) {
+ pps->min_tb_addr_zs_tab[y*(sps->tb_mask+2)] = -1;
+ pps->min_tb_addr_zs_tab[y] = -1;
+ }
+ for (y = 0; y < sps->tb_mask+1; y++) {
+ for (x = 0; x < sps->tb_mask+1; x++) {
int tb_x = x >> log2_diff_ctb_min_tb_size;
int tb_y = y >> log2_diff_ctb_min_tb_size;
int ctb_addr_rs = sps->ctb_width * tb_y + tb_x;
@@ -1339,10 +1584,16 @@ int ff_hevc_decode_nal_pps(HEVCContext *s)
int m = 1 << i;
val += (m & x ? m * m : 0) + (m & y ? 2 * m * m : 0);
}
- pps->min_tb_addr_zs[y * sps->min_tb_width + x] = val;
+ pps->min_tb_addr_zs[y * (sps->tb_mask+2) + x] = val;
}
}
+ if (get_bits_left(gb) < 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Overread PPS by %d bits\n", -get_bits_left(gb));
+ goto err;
+ }
+
remove_pps(s, pps_id);
s->pps_list[pps_id] = pps_buf;
diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index f232d03020..fea3d125ba 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -4,20 +4,20 @@
* Copyright (C) 2012 - 2013 Guillaume Martres
* Copyright (C) 2012 - 2013 Gildas Cocherel
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,8 +57,7 @@ RefPicList *ff_hevc_get_ref_list(HEVCContext *s, HEVCFrame *ref, int x0, int y0)
{
int x_cb = x0 >> s->sps->log2_ctb_size;
int y_cb = y0 >> s->sps->log2_ctb_size;
- int pic_width_cb = (s->sps->width + (1 << s->sps->log2_ctb_size) - 1) >>
- s->sps->log2_ctb_size;
+ int pic_width_cb = s->sps->ctb_width;
int ctb_addr_ts = s->pps->ctb_addr_rs_to_ts[y_cb * pic_width_cb + x_cb];
return (RefPicList *)ref->rpl_tab[ctb_addr_ts];
}
@@ -109,6 +108,9 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
for (j = 0; j < frame->ctb_count; j++)
frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data;
+ frame->frame->top_field_first = s->picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD;
+ frame->frame->interlaced_frame = (s->picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD) || (s->picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD);
+
if (s->avctx->hwaccel) {
const AVHWAccel *hwaccel = s->avctx->hwaccel;
av_assert0(!frame->hwaccel_picture_private);
@@ -121,7 +123,6 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
}
return frame;
-
fail:
ff_hevc_unref_frame(s, frame, ~0);
return NULL;
@@ -173,12 +174,22 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
int min_poc = INT_MAX;
int i, min_idx, ret;
+ if (s->sh.no_output_of_prior_pics_flag == 1) {
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+ if (!(frame->flags & HEVC_FRAME_FLAG_BUMPING) && frame->poc != s->poc &&
+ frame->sequence == s->seq_output) {
+ ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
+ }
+ }
+ }
+
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *frame = &s->DPB[i];
if ((frame->flags & HEVC_FRAME_FLAG_OUTPUT) &&
frame->sequence == s->seq_output) {
nb_output++;
- if (frame->poc < min_poc) {
+ if (frame->poc < min_poc || nb_output == 1) {
min_poc = frame->poc;
min_idx = i;
}
@@ -192,16 +203,16 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
if (nb_output) {
HEVCFrame *frame = &s->DPB[min_idx];
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->frame->format);
- int pixel_shift;
-
- if (!desc)
- return AVERROR_BUG;
-
- pixel_shift = desc->comp[0].depth_minus1 > 7;
-
- ret = av_frame_ref(out, frame->frame);
- ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
+ AVFrame *dst = out;
+ AVFrame *src = frame->frame;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src->format);
+ int pixel_shift = !!(desc->comp[0].depth_minus1 > 7);
+
+ ret = av_frame_ref(out, src);
+ if (frame->flags & HEVC_FRAME_FLAG_BUMPING)
+ ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_BUMPING);
+ else
+ ff_hevc_unref_frame(s, frame, HEVC_FRAME_FLAG_OUTPUT);
if (ret < 0)
return ret;
@@ -209,8 +220,8 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
int hshift = (i > 0) ? desc->log2_chroma_w : 0;
int vshift = (i > 0) ? desc->log2_chroma_h : 0;
int off = ((frame->window.left_offset >> hshift) << pixel_shift) +
- (frame->window.top_offset >> vshift) * out->linesize[i];
- out->data[i] += off;
+ (frame->window.top_offset >> vshift) * dst->linesize[i];
+ dst->data[i] += off;
}
av_log(s->avctx, AV_LOG_DEBUG,
"Output frame with POC %d.\n", frame->poc);
@@ -226,6 +237,46 @@ int ff_hevc_output_frame(HEVCContext *s, AVFrame *out, int flush)
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->sps && dpb >= s->sps->temporal_layer[s->sps->max_sub_layers - 1].max_dec_pic_buffering) {
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+ if ((frame->flags) &&
+ frame->sequence == s->seq_output &&
+ frame->poc != s->poc) {
+ if (frame->flags == HEVC_FRAME_FLAG_OUTPUT && frame->poc < min_poc) {
+ min_poc = frame->poc;
+ }
+ }
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
+ HEVCFrame *frame = &s->DPB[i];
+ if (frame->flags & HEVC_FRAME_FLAG_OUTPUT &&
+ frame->sequence == s->seq_output &&
+ frame->poc <= min_poc) {
+ frame->flags |= HEVC_FRAME_FLAG_BUMPING;
+ }
+ }
+
+ dpb--;
+ }
+}
+
static int init_slice_rpl(HEVCContext *s)
{
HEVCFrame *frame = s->ref;
@@ -335,8 +386,9 @@ static HEVCFrame *find_ref_idx(HEVCContext *s, int poc)
}
}
- av_log(s->avctx, AV_LOG_ERROR,
- "Could not find ref with POC %d\n", poc);
+ if (s->nal_unit_type != NAL_CRA_NUT && !IS_BLA(s))
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Could not find ref with POC %d\n", poc);
return NULL;
}
@@ -374,7 +426,8 @@ static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc)
frame->sequence = s->seq_decode;
frame->flags = 0;
- ff_thread_report_progress(&frame->tf, INT_MAX, 0);
+ if (s->threads_type == FF_THREAD_FRAME)
+ ff_thread_report_progress(&frame->tf, INT_MAX, 0);
return frame;
}
diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c
index 978a0e3878..13ebcd3ede 100644
--- a/libavcodec/hevc_sei.c
+++ b/libavcodec/hevc_sei.c
@@ -5,20 +5,20 @@
* Copyright (C) 2012 - 2013 Gildas Cocherel
* Copyright (C) 2013 Vittorio Giovara
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,10 +28,13 @@
static void decode_nal_sei_decoded_picture_hash(HEVCContext *s)
{
int cIdx, i;
- GetBitContext *gb = &s->HEVClc.gb;
- uint8_t hash_type = get_bits(gb, 8);
+ uint8_t hash_type;
+ //uint16_t picture_crc;
+ //uint32_t picture_checksum;
+ GetBitContext *gb = &s->HEVClc->gb;
+ hash_type = get_bits(gb, 8);
- for (cIdx = 0; cIdx < 3; cIdx++) {
+ for (cIdx = 0; cIdx < 3/*((s->sps->chroma_format_idc == 0) ? 1 : 3)*/; cIdx++) {
if (hash_type == 0) {
s->is_md5 = 1;
for (i = 0; i < 16; i++)
@@ -40,7 +43,7 @@ static void decode_nal_sei_decoded_picture_hash(HEVCContext *s)
// picture_crc = get_bits(gb, 16);
skip_bits(gb, 16);
} else if (hash_type == 2) {
- // picture_checksum = get_bits(gb, 32);
+ // picture_checksum = get_bits_long(gb, 32);
skip_bits(gb, 32);
}
}
@@ -48,7 +51,7 @@ static void decode_nal_sei_decoded_picture_hash(HEVCContext *s)
static void decode_nal_sei_frame_packing_arrangement(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
get_ue_golomb(gb); // frame_packing_arrangement_id
s->sei_frame_packing_present = !get_bits1(gb);
@@ -73,7 +76,7 @@ static void decode_nal_sei_frame_packing_arrangement(HEVCContext *s)
static void decode_nal_sei_display_orientation(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
s->sei_display_orientation_present = !get_bits1(gb);
@@ -86,9 +89,64 @@ static void decode_nal_sei_display_orientation(HEVCContext *s)
}
}
+static int decode_pic_timing(HEVCContext *s)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ HEVCSPS *sps;
+
+ if (!s->sps_list[s->active_seq_parameter_set_id])
+ return(AVERROR(ENOMEM));
+ sps = (HEVCSPS*)s->sps_list[s->active_seq_parameter_set_id]->data;
+
+ if (sps->vui.frame_field_info_present_flag) {
+ int pic_struct = get_bits(gb, 4);
+ s->picture_struct = AV_PICTURE_STRUCTURE_UNKNOWN;
+ if (pic_struct == 2) {
+ av_log(s->avctx, AV_LOG_DEBUG, "BOTTOM Field\n");
+ s->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD;
+ } else if (pic_struct == 1) {
+ av_log(s->avctx, AV_LOG_DEBUG, "TOP Field\n");
+ s->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD;
+ }
+ get_bits(gb, 2); // source_scan_type
+ get_bits(gb, 1); // duplicate_flag
+ }
+ return 1;
+}
+
+static int active_parameter_sets(HEVCContext *s)
+{
+ GetBitContext *gb = &s->HEVClc->gb;
+ int num_sps_ids_minus1;
+ int i;
+ unsigned active_seq_parameter_set_id;
+
+ get_bits(gb, 4); // active_video_parameter_set_id
+ get_bits(gb, 1); // self_contained_cvs_flag
+ get_bits(gb, 1); // num_sps_ids_minus1
+ num_sps_ids_minus1 = get_ue_golomb_long(gb); // num_sps_ids_minus1
+
+ if (num_sps_ids_minus1 < 0 || num_sps_ids_minus1 > 15) {
+ av_log(s->avctx, AV_LOG_ERROR, "num_sps_ids_minus1 %d invalid\n", num_sps_ids_minus1);
+ return AVERROR_INVALIDDATA;
+ }
+
+ active_seq_parameter_set_id = get_ue_golomb_long(gb);
+ if (active_seq_parameter_set_id >= MAX_SPS_COUNT) {
+ av_log(s->avctx, AV_LOG_ERROR, "active_parameter_set_id %d invalid\n", active_seq_parameter_set_id);
+ return AVERROR_INVALIDDATA;
+ }
+ s->active_seq_parameter_set_id = active_seq_parameter_set_id;
+
+ for (i = 1; i <= num_sps_ids_minus1; i++)
+ get_ue_golomb_long(gb); // active_seq_parameter_set_id[i]
+
+ return 0;
+}
+
static int decode_nal_sei_message(HEVCContext *s)
{
- GetBitContext *gb = &s->HEVClc.gb;
+ GetBitContext *gb = &s->HEVClc->gb;
int payload_type = 0;
int payload_size = 0;
@@ -105,25 +163,33 @@ static int decode_nal_sei_message(HEVCContext *s)
payload_size += byte;
}
if (s->nal_unit_type == NAL_SEI_PREFIX) {
- if (payload_type == 256)
+ if (payload_type == 256 /*&& s->decode_checksum_sei*/) {
decode_nal_sei_decoded_picture_hash(s);
- else if (payload_type == 45)
+ } else if (payload_type == 45) {
decode_nal_sei_frame_packing_arrangement(s);
- else if (payload_type == 47)
+ } else if (payload_type == 47) {
decode_nal_sei_display_orientation(s);
- else {
+ } else if (payload_type == 1){
+ int ret = decode_pic_timing(s);
av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type);
skip_bits(gb, 8 * payload_size);
+ return ret;
+ } else if (payload_type == 129){
+ active_parameter_sets(s);
+ av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type);
+ } else {
+ av_log(s->avctx, AV_LOG_DEBUG, "Skipped PREFIX SEI %d\n", payload_type);
+ skip_bits(gb, 8*payload_size);
}
} else { /* nal_unit_type == NAL_SEI_SUFFIX */
- if (payload_type == 132)
+ if (payload_type == 132 /* && s->decode_checksum_sei */)
decode_nal_sei_decoded_picture_hash(s);
else {
av_log(s->avctx, AV_LOG_DEBUG, "Skipped SUFFIX SEI %d\n", payload_type);
skip_bits(gb, 8 * payload_size);
}
}
- return 0;
+ return 1;
}
static int more_rbsp_data(GetBitContext *gb)
@@ -133,8 +199,12 @@ static int more_rbsp_data(GetBitContext *gb)
int ff_hevc_decode_nal_sei(HEVCContext *s)
{
+ int ret;
+
do {
- decode_nal_sei_message(s);
- } while (more_rbsp_data(&s->HEVClc.gb));
- return 0;
+ ret = decode_nal_sei_message(s);
+ if (ret < 0)
+ return(AVERROR(ENOMEM));
+ } while (more_rbsp_data(&s->HEVClc->gb));
+ return 1;
}
diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevcdsp.c
index 0abee9b1d8..be01e927f1 100644
--- a/libavcodec/hevcdsp.c
+++ b/libavcodec/hevcdsp.c
@@ -2,21 +2,23 @@
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere
*
- * This file is part of Libav.
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -89,14 +91,20 @@ static const int8_t transform[32][32] = {
90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 },
};
-DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][16]) = {
- { -2, 58, 10, -2, -2, 58, 10, -2, -2, 58, 10, -2, -2, 58, 10, -2 },
- { -4, 54, 16, -2, -4, 54, 16, -2, -4, 54, 16, -2, -4, 54, 16, -2 },
- { -6, 46, 28, -4, -6, 46, 28, -4, -6, 46, 28, -4, -6, 46, 28, -4 },
- { -4, 36, 36, -4, -4, 36, 36, -4, -4, 36, 36, -4, -4, 36, 36, -4 },
- { -4, 28, 46, -6, -4, 28, 46, -6, -4, 28, 46, -6, -4, 28, 46, -6 },
- { -2, 16, 54, -4, -2, 16, 54, -4, -2, 16, 54, -4, -2, 16, 54, -4 },
- { -2, 10, 58, -2, -2, 10, 58, -2, -2, 10, 58, -2, -2, 10, 58, -2 },
+DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][4]) = {
+ { -2, 58, 10, -2},
+ { -4, 54, 16, -2},
+ { -6, 46, 28, -4},
+ { -4, 36, 36, -4},
+ { -4, 28, 46, -6},
+ { -2, 16, 54, -4},
+ { -2, 10, 58, -2},
+};
+
+DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters[3][16]) = {
+ { -1, 4,-10, 58, 17, -5, 1, 0, -1, 4,-10, 58, 17, -5, 1, 0},
+ { -1, 4,-11, 40, 40,-11, 4, -1, -1, 4,-11, 40, 40,-11, 4, -1},
+ { 0, 1, -5, 17, 58,-10, 4, -1, 0, 1, -5, 17, 58,-10, 4, -1}
};
#define BIT_DEPTH 8
@@ -111,62 +119,119 @@ DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][16]) = {
#include "hevcdsp_template.c"
#undef BIT_DEPTH
+#define BIT_DEPTH 12
+#include "hevcdsp_template.c"
+#undef BIT_DEPTH
+
void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
{
#undef FUNC
#define FUNC(a, depth) a ## _ ## depth
+#undef PEL_FUNC
+#define PEL_FUNC(dst1, idx1, idx2, a, depth) \
+ for(i = 0 ; i < 10 ; i++) \
+{ \
+ hevcdsp->dst1[i][idx1][idx2] = a ## _ ## depth; \
+}
+
+#undef EPEL_FUNCS
+#define EPEL_FUNCS(depth) \
+ PEL_FUNC(put_hevc_epel, 0, 0, put_hevc_pel_pixels, depth); \
+ PEL_FUNC(put_hevc_epel, 0, 1, put_hevc_epel_h, depth); \
+ PEL_FUNC(put_hevc_epel, 1, 0, put_hevc_epel_v, depth); \
+ PEL_FUNC(put_hevc_epel, 1, 1, put_hevc_epel_hv, depth)
+
+#undef EPEL_UNI_FUNCS
+#define EPEL_UNI_FUNCS(depth) \
+ PEL_FUNC(put_hevc_epel_uni, 0, 0, put_hevc_pel_uni_pixels, depth); \
+ PEL_FUNC(put_hevc_epel_uni, 0, 1, put_hevc_epel_uni_h, depth); \
+ PEL_FUNC(put_hevc_epel_uni, 1, 0, put_hevc_epel_uni_v, depth); \
+ PEL_FUNC(put_hevc_epel_uni, 1, 1, put_hevc_epel_uni_hv, depth); \
+ PEL_FUNC(put_hevc_epel_uni_w, 0, 0, put_hevc_pel_uni_w_pixels, depth); \
+ PEL_FUNC(put_hevc_epel_uni_w, 0, 1, put_hevc_epel_uni_w_h, depth); \
+ PEL_FUNC(put_hevc_epel_uni_w, 1, 0, put_hevc_epel_uni_w_v, depth); \
+ PEL_FUNC(put_hevc_epel_uni_w, 1, 1, put_hevc_epel_uni_w_hv, depth)
+
+#undef EPEL_BI_FUNCS
+#define EPEL_BI_FUNCS(depth) \
+ PEL_FUNC(put_hevc_epel_bi, 0, 0, put_hevc_pel_bi_pixels, depth); \
+ PEL_FUNC(put_hevc_epel_bi, 0, 1, put_hevc_epel_bi_h, depth); \
+ PEL_FUNC(put_hevc_epel_bi, 1, 0, put_hevc_epel_bi_v, depth); \
+ PEL_FUNC(put_hevc_epel_bi, 1, 1, put_hevc_epel_bi_hv, depth); \
+ PEL_FUNC(put_hevc_epel_bi_w, 0, 0, put_hevc_pel_bi_w_pixels, depth); \
+ PEL_FUNC(put_hevc_epel_bi_w, 0, 1, put_hevc_epel_bi_w_h, depth); \
+ PEL_FUNC(put_hevc_epel_bi_w, 1, 0, put_hevc_epel_bi_w_v, depth); \
+ PEL_FUNC(put_hevc_epel_bi_w, 1, 1, put_hevc_epel_bi_w_hv, depth)
+
+#undef QPEL_FUNCS
+#define QPEL_FUNCS(depth) \
+ PEL_FUNC(put_hevc_qpel, 0, 0, put_hevc_pel_pixels, depth); \
+ PEL_FUNC(put_hevc_qpel, 0, 1, put_hevc_qpel_h, depth); \
+ PEL_FUNC(put_hevc_qpel, 1, 0, put_hevc_qpel_v, depth); \
+ PEL_FUNC(put_hevc_qpel, 1, 1, put_hevc_qpel_hv, depth)
+
+#undef QPEL_UNI_FUNCS
+#define QPEL_UNI_FUNCS(depth) \
+ PEL_FUNC(put_hevc_qpel_uni, 0, 0, put_hevc_pel_uni_pixels, depth); \
+ PEL_FUNC(put_hevc_qpel_uni, 0, 1, put_hevc_qpel_uni_h, depth); \
+ PEL_FUNC(put_hevc_qpel_uni, 1, 0, put_hevc_qpel_uni_v, depth); \
+ PEL_FUNC(put_hevc_qpel_uni, 1, 1, put_hevc_qpel_uni_hv, depth); \
+ PEL_FUNC(put_hevc_qpel_uni_w, 0, 0, put_hevc_pel_uni_w_pixels, depth); \
+ PEL_FUNC(put_hevc_qpel_uni_w, 0, 1, put_hevc_qpel_uni_w_h, depth); \
+ PEL_FUNC(put_hevc_qpel_uni_w, 1, 0, put_hevc_qpel_uni_w_v, depth); \
+ PEL_FUNC(put_hevc_qpel_uni_w, 1, 1, put_hevc_qpel_uni_w_hv, depth)
+
+#undef QPEL_BI_FUNCS
+#define QPEL_BI_FUNCS(depth) \
+ PEL_FUNC(put_hevc_qpel_bi, 0, 0, put_hevc_pel_bi_pixels, depth); \
+ PEL_FUNC(put_hevc_qpel_bi, 0, 1, put_hevc_qpel_bi_h, depth); \
+ PEL_FUNC(put_hevc_qpel_bi, 1, 0, put_hevc_qpel_bi_v, depth); \
+ PEL_FUNC(put_hevc_qpel_bi, 1, 1, put_hevc_qpel_bi_hv, depth); \
+ PEL_FUNC(put_hevc_qpel_bi_w, 0, 0, put_hevc_pel_bi_w_pixels, depth); \
+ PEL_FUNC(put_hevc_qpel_bi_w, 0, 1, put_hevc_qpel_bi_w_h, depth); \
+ PEL_FUNC(put_hevc_qpel_bi_w, 1, 0, put_hevc_qpel_bi_w_v, depth); \
+ PEL_FUNC(put_hevc_qpel_bi_w, 1, 1, put_hevc_qpel_bi_w_hv, depth)
+
#define HEVC_DSP(depth) \
hevcdsp->put_pcm = FUNC(put_pcm, depth); \
- hevcdsp->transquant_bypass[0] = FUNC(transquant_bypass4x4, depth); \
- hevcdsp->transquant_bypass[1] = FUNC(transquant_bypass8x8, depth); \
- hevcdsp->transquant_bypass[2] = FUNC(transquant_bypass16x16, depth); \
- hevcdsp->transquant_bypass[3] = FUNC(transquant_bypass32x32, depth); \
+ hevcdsp->transform_add[0] = FUNC(transform_add4x4, depth); \
+ hevcdsp->transform_add[1] = FUNC(transform_add8x8, depth); \
+ hevcdsp->transform_add[2] = FUNC(transform_add16x16, depth); \
+ hevcdsp->transform_add[3] = FUNC(transform_add32x32, depth); \
hevcdsp->transform_skip = FUNC(transform_skip, depth); \
- hevcdsp->transform_4x4_luma_add = FUNC(transform_4x4_luma_add, depth); \
- hevcdsp->transform_add[0] = FUNC(transform_4x4_add, depth); \
- hevcdsp->transform_add[1] = FUNC(transform_8x8_add, depth); \
- hevcdsp->transform_add[2] = FUNC(transform_16x16_add, depth); \
- hevcdsp->transform_add[3] = FUNC(transform_32x32_add, depth); \
- \
- hevcdsp->sao_band_filter[0] = FUNC(sao_band_filter_0, depth); \
- hevcdsp->sao_band_filter[1] = FUNC(sao_band_filter_1, depth); \
- hevcdsp->sao_band_filter[2] = FUNC(sao_band_filter_2, depth); \
- hevcdsp->sao_band_filter[3] = FUNC(sao_band_filter_3, depth); \
+ hevcdsp->transform_rdpcm = FUNC(transform_rdpcm, depth); \
+ hevcdsp->idct_4x4_luma = FUNC(transform_4x4_luma, depth); \
+ hevcdsp->idct[0] = FUNC(idct_4x4, depth); \
+ hevcdsp->idct[1] = FUNC(idct_8x8, depth); \
+ hevcdsp->idct[2] = FUNC(idct_16x16, depth); \
+ hevcdsp->idct[3] = FUNC(idct_32x32, depth); \
\
- hevcdsp->sao_edge_filter[0] = FUNC(sao_edge_filter_0, depth); \
- hevcdsp->sao_edge_filter[1] = FUNC(sao_edge_filter_1, depth); \
- hevcdsp->sao_edge_filter[2] = FUNC(sao_edge_filter_2, depth); \
- hevcdsp->sao_edge_filter[3] = FUNC(sao_edge_filter_3, depth); \
- \
- hevcdsp->put_hevc_qpel[0][0] = FUNC(put_hevc_qpel_pixels, depth); \
- hevcdsp->put_hevc_qpel[0][1] = FUNC(put_hevc_qpel_h1, depth); \
- hevcdsp->put_hevc_qpel[0][2] = FUNC(put_hevc_qpel_h2, depth); \
- hevcdsp->put_hevc_qpel[0][3] = FUNC(put_hevc_qpel_h3, depth); \
- hevcdsp->put_hevc_qpel[1][0] = FUNC(put_hevc_qpel_v1, depth); \
- hevcdsp->put_hevc_qpel[1][1] = FUNC(put_hevc_qpel_h1v1, depth); \
- hevcdsp->put_hevc_qpel[1][2] = FUNC(put_hevc_qpel_h2v1, depth); \
- hevcdsp->put_hevc_qpel[1][3] = FUNC(put_hevc_qpel_h3v1, depth); \
- hevcdsp->put_hevc_qpel[2][0] = FUNC(put_hevc_qpel_v2, depth); \
- hevcdsp->put_hevc_qpel[2][1] = FUNC(put_hevc_qpel_h1v2, depth); \
- hevcdsp->put_hevc_qpel[2][2] = FUNC(put_hevc_qpel_h2v2, depth); \
- hevcdsp->put_hevc_qpel[2][3] = FUNC(put_hevc_qpel_h3v2, depth); \
- hevcdsp->put_hevc_qpel[3][0] = FUNC(put_hevc_qpel_v3, depth); \
- hevcdsp->put_hevc_qpel[3][1] = FUNC(put_hevc_qpel_h1v3, depth); \
- hevcdsp->put_hevc_qpel[3][2] = FUNC(put_hevc_qpel_h2v3, depth); \
- hevcdsp->put_hevc_qpel[3][3] = FUNC(put_hevc_qpel_h3v3, depth); \
- \
- hevcdsp->put_hevc_epel[0][0] = FUNC(put_hevc_epel_pixels, depth); \
- hevcdsp->put_hevc_epel[0][1] = FUNC(put_hevc_epel_h, depth); \
- hevcdsp->put_hevc_epel[1][0] = FUNC(put_hevc_epel_v, depth); \
- hevcdsp->put_hevc_epel[1][1] = FUNC(put_hevc_epel_hv, depth); \
- \
- hevcdsp->put_unweighted_pred = FUNC(put_unweighted_pred, depth); \
- hevcdsp->put_weighted_pred_avg = FUNC(put_weighted_pred_avg, depth); \
- \
- hevcdsp->weighted_pred = FUNC(weighted_pred, depth); \
- hevcdsp->weighted_pred_avg = FUNC(weighted_pred_avg, depth); \
+ hevcdsp->idct_dc[0] = FUNC(idct_4x4_dc, depth); \
+ hevcdsp->idct_dc[1] = FUNC(idct_8x8_dc, depth); \
+ hevcdsp->idct_dc[2] = FUNC(idct_16x16_dc, depth); \
+ hevcdsp->idct_dc[3] = FUNC(idct_32x32_dc, depth); \
\
+ hevcdsp->sao_band_filter[0] = \
+ hevcdsp->sao_band_filter[1] = \
+ hevcdsp->sao_band_filter[2] = \
+ hevcdsp->sao_band_filter[3] = \
+ hevcdsp->sao_band_filter[4] = FUNC(sao_band_filter_0, depth); \
+ hevcdsp->sao_edge_filter[0] = \
+ hevcdsp->sao_edge_filter[1] = \
+ hevcdsp->sao_edge_filter[2] = \
+ hevcdsp->sao_edge_filter[3] = \
+ hevcdsp->sao_edge_filter[4] = FUNC(sao_edge_filter, depth); \
+ hevcdsp->sao_edge_restore[0] = FUNC(sao_edge_restore_0, depth); \
+ hevcdsp->sao_edge_restore[1] = FUNC(sao_edge_restore_1, depth); \
+ \
+ QPEL_FUNCS(depth); \
+ QPEL_UNI_FUNCS(depth); \
+ QPEL_BI_FUNCS(depth); \
+ EPEL_FUNCS(depth); \
+ EPEL_UNI_FUNCS(depth); \
+ EPEL_BI_FUNCS(depth); \
+ \
hevcdsp->hevc_h_loop_filter_luma = FUNC(hevc_h_loop_filter_luma, depth); \
hevcdsp->hevc_v_loop_filter_luma = FUNC(hevc_v_loop_filter_luma, depth); \
hevcdsp->hevc_h_loop_filter_chroma = FUNC(hevc_h_loop_filter_chroma, depth); \
@@ -174,7 +239,8 @@ void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
hevcdsp->hevc_h_loop_filter_luma_c = FUNC(hevc_h_loop_filter_luma, depth); \
hevcdsp->hevc_v_loop_filter_luma_c = FUNC(hevc_v_loop_filter_luma, depth); \
hevcdsp->hevc_h_loop_filter_chroma_c = FUNC(hevc_h_loop_filter_chroma, depth); \
- hevcdsp->hevc_v_loop_filter_chroma_c = FUNC(hevc_v_loop_filter_chroma, depth);
+ hevcdsp->hevc_v_loop_filter_chroma_c = FUNC(hevc_v_loop_filter_chroma, depth)
+int i = 0;
switch (bit_depth) {
case 9:
@@ -183,6 +249,9 @@ void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
case 10:
HEVC_DSP(10);
break;
+ case 12:
+ HEVC_DSP(12);
+ break;
default:
HEVC_DSP(8);
break;
@@ -190,4 +259,8 @@ void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
if (ARCH_X86)
ff_hevc_dsp_init_x86(hevcdsp, bit_depth);
+ if (ARCH_ARM)
+ ff_hevcdsp_init_arm(hevcdsp, bit_depth);
+ if (ARCH_MIPS)
+ ff_hevc_dsp_init_mips(hevcdsp, bit_depth);
}
diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h
index aad96db3ad..d2ea8672b1 100644
--- a/libavcodec/hevcdsp.h
+++ b/libavcodec/hevcdsp.h
@@ -2,21 +2,23 @@
* HEVC video decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere
*
- * This file is part of Libav.
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,87 +27,107 @@
#include "get_bits.h"
+#define MAX_PB_SIZE 64
+
typedef struct SAOParams {
int offset_abs[3][4]; ///< sao_offset_abs
int offset_sign[3][4]; ///< sao_offset_sign
- int band_position[3]; ///< sao_band_position
+ uint8_t band_position[3]; ///< sao_band_position
int eo_class[3]; ///< sao_eo_class
- int offset_val[3][5]; ///<SaoOffsetVal
+ int16_t offset_val[3][5]; ///<SaoOffsetVal
uint8_t type_idx[3]; ///< sao_type_idx
} SAOParams;
typedef struct HEVCDSPContext {
- void (*put_pcm)(uint8_t *dst, ptrdiff_t stride, int size,
- GetBitContext *gb, int pcm_bit_depth);
-
- void (*transquant_bypass[4])(uint8_t *dst, int16_t *coeffs,
- ptrdiff_t stride);
-
- void (*transform_skip)(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
- void (*transform_4x4_luma_add)(uint8_t *dst, int16_t *coeffs,
- ptrdiff_t stride);
- void (*transform_add[4])(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
-
- void (*sao_band_filter[4])(uint8_t *dst, uint8_t *src, ptrdiff_t stride,
- struct SAOParams *sao, int *borders,
- int width, int height, int c_idx);
- void (*sao_edge_filter[4])(uint8_t *dst, uint8_t *src, ptrdiff_t stride,
- struct SAOParams *sao, int *borders, int width,
- int height, int c_idx, uint8_t vert_edge,
- uint8_t horiz_edge, uint8_t diag_edge);
-
- void (*put_hevc_qpel[4][4])(int16_t *dst, ptrdiff_t dststride, uint8_t *src,
- ptrdiff_t srcstride, int width, int height,
- int16_t *mcbuffer);
- void (*put_hevc_epel[2][2])(int16_t *dst, ptrdiff_t dststride, uint8_t *src,
- ptrdiff_t srcstride, int width, int height,
- int mx, int my, int16_t *mcbuffer);
-
- void (*put_unweighted_pred)(uint8_t *dst, ptrdiff_t dststride, int16_t *src,
- ptrdiff_t srcstride, int width, int height);
- void (*put_weighted_pred_avg)(uint8_t *dst, ptrdiff_t dststride,
- int16_t *src1, int16_t *src2,
- ptrdiff_t srcstride, int width, int height);
- void (*weighted_pred)(uint8_t denom, int16_t wlxFlag, int16_t olxFlag,
- uint8_t *dst, ptrdiff_t dststride, int16_t *src,
- ptrdiff_t srcstride, int width, int height);
- void (*weighted_pred_avg)(uint8_t denom, int16_t wl0Flag, int16_t wl1Flag,
- int16_t ol0Flag, int16_t ol1Flag, uint8_t *dst,
- ptrdiff_t dststride, int16_t *src1, int16_t *src2,
- ptrdiff_t srcstride, int width, int height);
+ void (*put_pcm)(uint8_t *_dst, ptrdiff_t _stride, int width, int height,
+ struct GetBitContext *gb, int pcm_bit_depth);
+
+ void (*transform_add[4])(uint8_t *_dst, int16_t *coeffs, ptrdiff_t _stride);
+
+ void (*transform_skip)(int16_t *coeffs, int16_t log2_size);
+
+ void (*transform_rdpcm)(int16_t *coeffs, int16_t log2_size, int mode);
+
+ void (*idct_4x4_luma)(int16_t *coeffs);
+
+ void (*idct[4])(int16_t *coeffs, int col_limit);
+
+ void (*idct_dc[4])(int16_t *coeffs);
+
+ void (*sao_band_filter[5])(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);
+
+ /* implicit stride_src parameter has value of 2 * MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE */
+ void (*sao_edge_filter[5])(uint8_t *_dst /* align 16 */, uint8_t *_src /* align 32 */, ptrdiff_t stride_dst,
+ int16_t *sao_offset_val, int sao_eo_class, int width, int height);
+
+ void (*sao_edge_restore[2])(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src,
+ struct SAOParams *sao, int *borders, int _width, int _height, int c_idx,
+ uint8_t *vert_edge, uint8_t *horiz_edge, uint8_t *diag_edge);
+
+ void (*put_hevc_qpel[10][2][2])(int16_t *dst, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_qpel_uni[10][2][2])(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_qpel_uni_w[10][2][2])(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width);
+
+ void (*put_hevc_qpel_bi[10][2][2])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_qpel_bi_w[10][2][2])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_epel[10][2][2])(int16_t *dst, uint8_t *src, ptrdiff_t srcstride,
+ int height, intptr_t mx, intptr_t my, int width);
+
+ void (*put_hevc_epel_uni[10][2][2])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_epel_uni_w[10][2][2])(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_epel_bi[10][2][2])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width);
+ void (*put_hevc_epel_bi_w[10][2][2])(uint8_t *dst, ptrdiff_t dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int ox0, int wx1,
+ int ox1, intptr_t mx, intptr_t my, int width);
void (*hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
- int beta, int *tc,
+ int beta, int32_t *tc,
uint8_t *no_p, uint8_t *no_q);
void (*hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
- int beta, int *tc,
+ int beta, int32_t *tc,
uint8_t *no_p, uint8_t *no_q);
void (*hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
- int *tc, uint8_t *no_p, uint8_t *no_q);
+ int32_t *tc, uint8_t *no_p, uint8_t *no_q);
void (*hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
- int *tc, uint8_t *no_p, uint8_t *no_q);
+ int32_t *tc, uint8_t *no_p, uint8_t *no_q);
void (*hevc_h_loop_filter_luma_c)(uint8_t *pix, ptrdiff_t stride,
- int beta, int *tc,
+ int beta, int32_t *tc,
uint8_t *no_p, uint8_t *no_q);
void (*hevc_v_loop_filter_luma_c)(uint8_t *pix, ptrdiff_t stride,
- int beta, int *tc,
+ int beta, int32_t *tc,
uint8_t *no_p, uint8_t *no_q);
void (*hevc_h_loop_filter_chroma_c)(uint8_t *pix, ptrdiff_t stride,
- int *tc, uint8_t *no_p,
+ int32_t *tc, uint8_t *no_p,
uint8_t *no_q);
void (*hevc_v_loop_filter_chroma_c)(uint8_t *pix, ptrdiff_t stride,
- int *tc, uint8_t *no_p,
+ int32_t *tc, uint8_t *no_p,
uint8_t *no_q);
} HEVCDSPContext;
void ff_hevc_dsp_init(HEVCDSPContext *hpc, int bit_depth);
-void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth);
-
-extern const int8_t ff_hevc_epel_filters[7][16];
+extern const int8_t ff_hevc_epel_filters[7][4];
+extern const int8_t ff_hevc_qpel_filters[3][16];
+void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth);
+void ff_hevcdsp_init_arm(HEVCDSPContext *c, const int bit_depth);
+void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth);
#endif /* AVCODEC_HEVCDSP_H */
diff --git a/libavcodec/hevcdsp_template.c b/libavcodec/hevcdsp_template.c
index ae7e0217cc..cec28e4550 100644
--- a/libavcodec/hevcdsp_template.c
+++ b/libavcodec/hevcdsp_template.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,8 +24,10 @@
#include "hevc.h"
#include "bit_depth_template.c"
+#include "hevcdsp.h"
-static void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int size,
+
+static void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int width, int height,
GetBitContext *gb, int pcm_bit_depth)
{
int x, y;
@@ -33,8 +35,8 @@ static void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int size,
stride /= sizeof(pixel);
- for (y = 0; y < size; y++) {
- for (x = 0; x < size; x++)
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
dst[x] = get_bits(gb, pcm_bit_depth) << (BIT_DEPTH - pcm_bit_depth);
dst += stride;
}
@@ -57,48 +59,76 @@ static av_always_inline void FUNC(transquant_bypass)(uint8_t *_dst, int16_t *coe
}
}
-static void FUNC(transquant_bypass4x4)(uint8_t *_dst, int16_t *coeffs,
+static void FUNC(transform_add4x4)(uint8_t *_dst, int16_t *coeffs,
ptrdiff_t stride)
{
FUNC(transquant_bypass)(_dst, coeffs, stride, 4);
}
-static void FUNC(transquant_bypass8x8)(uint8_t *_dst, int16_t *coeffs,
+static void FUNC(transform_add8x8)(uint8_t *_dst, int16_t *coeffs,
ptrdiff_t stride)
{
FUNC(transquant_bypass)(_dst, coeffs, stride, 8);
}
-static void FUNC(transquant_bypass16x16)(uint8_t *_dst, int16_t *coeffs,
+static void FUNC(transform_add16x16)(uint8_t *_dst, int16_t *coeffs,
ptrdiff_t stride)
{
FUNC(transquant_bypass)(_dst, coeffs, stride, 16);
}
-static void FUNC(transquant_bypass32x32)(uint8_t *_dst, int16_t *coeffs,
+static void FUNC(transform_add32x32)(uint8_t *_dst, int16_t *coeffs,
ptrdiff_t stride)
{
FUNC(transquant_bypass)(_dst, coeffs, stride, 32);
}
-static void FUNC(transform_skip)(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride)
+
+static void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode)
{
- pixel *dst = (pixel *)_dst;
- int shift = 13 - BIT_DEPTH;
-#if BIT_DEPTH <= 13
- int offset = 1 << (shift - 1);
-#else
- int offset = 0;
-#endif
+ int16_t *coeffs = (int16_t *) _coeffs;
+ int x, y;
+ int size = 1 << log2_size;
+
+ if (mode) {
+ coeffs += size;
+ for (y = 0; y < size - 1; y++) {
+ for (x = 0; x < size; x++)
+ coeffs[x] += coeffs[x - size];
+ coeffs += size;
+ }
+ } else {
+ for (y = 0; y < size; y++) {
+ for (x = 1; x < size; x++)
+ coeffs[x] += coeffs[x - 1];
+ coeffs += size;
+ }
+ }
+}
+
+static void FUNC(transform_skip)(int16_t *_coeffs, int16_t log2_size)
+{
+ int shift = 15 - BIT_DEPTH - log2_size;
int x, y;
+ int size = 1 << log2_size;
+ int16_t *coeffs = _coeffs;
- stride /= sizeof(pixel);
- for (y = 0; y < 4 * 4; y += 4) {
- for (x = 0; x < 4; x++)
- dst[x] = av_clip_pixel(dst[x] + ((coeffs[y + x] + offset) >> shift));
- dst += stride;
+ if (shift > 0) {
+ int offset = 1 << (shift - 1);
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; x++) {
+ *coeffs = (*coeffs + offset) >> shift;
+ coeffs++;
+ }
+ }
+ } else {
+ for (y = 0; y < size; y++) {
+ for (x = 0; x < size; x++) {
+ *coeffs = *coeffs << -shift;
+ coeffs++;
+ }
+ }
}
}
@@ -122,17 +152,13 @@ static void FUNC(transform_skip)(uint8_t *_dst, int16_t *coeffs,
assign(dst[3 * step], 55 * c0 + 29 * c2 - c3); \
} while (0)
-static void FUNC(transform_4x4_luma_add)(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride)
+static void FUNC(transform_4x4_luma)(int16_t *coeffs)
{
int i;
- pixel *dst = (pixel *)_dst;
int shift = 7;
int add = 1 << (shift - 1);
int16_t *src = coeffs;
- stride /= sizeof(pixel);
-
for (i = 0; i < 4; i++) {
TR_4x4_LUMA(src, src, 4, SCALE);
src++;
@@ -141,323 +167,226 @@ static void FUNC(transform_4x4_luma_add)(uint8_t *_dst, int16_t *coeffs,
shift = 20 - BIT_DEPTH;
add = 1 << (shift - 1);
for (i = 0; i < 4; i++) {
- TR_4x4_LUMA(dst, coeffs, 1, ADD_AND_SCALE);
+ TR_4x4_LUMA(coeffs, coeffs, 1, SCALE);
coeffs += 4;
- dst += stride;
}
}
#undef TR_4x4_LUMA
-#define TR_4(dst, src, dstep, sstep, assign) \
- do { \
- const int e0 = transform[8 * 0][0] * src[0 * sstep] + \
- transform[8 * 2][0] * src[2 * sstep]; \
- const int e1 = transform[8 * 0][1] * src[0 * sstep] + \
- transform[8 * 2][1] * src[2 * sstep]; \
- const int o0 = transform[8 * 1][0] * src[1 * sstep] + \
- transform[8 * 3][0] * src[3 * sstep]; \
- const int o1 = transform[8 * 1][1] * src[1 * sstep] + \
- transform[8 * 3][1] * src[3 * sstep]; \
- \
- assign(dst[0 * dstep], e0 + o0); \
- assign(dst[1 * dstep], e1 + o1); \
- assign(dst[2 * dstep], e1 - o1); \
- assign(dst[3 * dstep], e0 - o0); \
+#define TR_4(dst, src, dstep, sstep, assign, end) \
+ do { \
+ const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \
+ const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \
+ const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \
+ const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \
+ \
+ assign(dst[0 * dstep], e0 + o0); \
+ assign(dst[1 * dstep], e1 + o1); \
+ assign(dst[2 * dstep], e1 - o1); \
+ assign(dst[3 * dstep], e0 - o0); \
} while (0)
-static void FUNC(transform_4x4_add)(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride)
-{
- int i;
- pixel *dst = (pixel *)_dst;
- int shift = 7;
- int add = 1 << (shift - 1);
- int16_t *src = coeffs;
-
- stride /= sizeof(pixel);
-
- for (i = 0; i < 4; i++) {
- TR_4(src, src, 4, 4, SCALE);
- src++;
- }
-
- shift = 20 - BIT_DEPTH;
- add = 1 << (shift - 1);
- for (i = 0; i < 4; i++) {
- TR_4(dst, coeffs, 1, 1, ADD_AND_SCALE);
- coeffs += 4;
- dst += stride;
- }
-}
-
-#define TR_8(dst, src, dstep, sstep, assign) \
- do { \
- int i, j; \
- int e_8[4]; \
- int o_8[4] = { 0 }; \
- for (i = 0; i < 4; i++) \
- for (j = 1; j < 8; j += 2) \
- o_8[i] += transform[4 * j][i] * src[j * sstep]; \
- TR_4(e_8, src, 1, 2 * sstep, SET); \
- \
- for (i = 0; i < 4; i++) { \
- assign(dst[i * dstep], e_8[i] + o_8[i]); \
- assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]); \
- } \
+#define TR_8(dst, src, dstep, sstep, assign, end) \
+ do { \
+ int i, j; \
+ int e_8[4]; \
+ int o_8[4] = { 0 }; \
+ for (i = 0; i < 4; i++) \
+ for (j = 1; j < end; j += 2) \
+ o_8[i] += transform[4 * j][i] * src[j * sstep]; \
+ TR_4(e_8, src, 1, 2 * sstep, SET, 4); \
+ \
+ for (i = 0; i < 4; i++) { \
+ assign(dst[i * dstep], e_8[i] + o_8[i]); \
+ assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]); \
+ } \
} while (0)
-#define TR_16(dst, src, dstep, sstep, assign) \
- do { \
- int i, j; \
- int e_16[8]; \
- int o_16[8] = { 0 }; \
- for (i = 0; i < 8; i++) \
- for (j = 1; j < 16; j += 2) \
- o_16[i] += transform[2 * j][i] * src[j * sstep]; \
- TR_8(e_16, src, 1, 2 * sstep, SET); \
- \
- for (i = 0; i < 8; i++) { \
- assign(dst[i * dstep], e_16[i] + o_16[i]); \
- assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]); \
- } \
+#define TR_16(dst, src, dstep, sstep, assign, end) \
+ do { \
+ int i, j; \
+ int e_16[8]; \
+ int o_16[8] = { 0 }; \
+ for (i = 0; i < 8; i++) \
+ for (j = 1; j < end; j += 2) \
+ o_16[i] += transform[2 * j][i] * src[j * sstep]; \
+ TR_8(e_16, src, 1, 2 * sstep, SET, 8); \
+ \
+ for (i = 0; i < 8; i++) { \
+ assign(dst[i * dstep], e_16[i] + o_16[i]); \
+ assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]); \
+ } \
} while (0)
-#define TR_32(dst, src, dstep, sstep, assign) \
- do { \
- int i, j; \
- int e_32[16]; \
- int o_32[16] = { 0 }; \
- for (i = 0; i < 16; i++) \
- for (j = 1; j < 32; j += 2) \
- o_32[i] += transform[j][i] * src[j * sstep]; \
- TR_16(e_32, src, 1, 2 * sstep, SET); \
- \
- for (i = 0; i < 16; i++) { \
- assign(dst[i * dstep], e_32[i] + o_32[i]); \
- assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]); \
- } \
+#define TR_32(dst, src, dstep, sstep, assign, end) \
+ do { \
+ int i, j; \
+ int e_32[16]; \
+ int o_32[16] = { 0 }; \
+ for (i = 0; i < 16; i++) \
+ for (j = 1; j < end; j += 2) \
+ o_32[i] += transform[j][i] * src[j * sstep]; \
+ TR_16(e_32, src, 1, 2 * sstep, SET, end/2); \
+ \
+ for (i = 0; i < 16; i++) { \
+ assign(dst[i * dstep], e_32[i] + o_32[i]); \
+ assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]); \
+ } \
} while (0)
-
-
-static void FUNC(transform_8x8_add)(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride)
-{
- int i;
- pixel *dst = (pixel *)_dst;
- int shift = 7;
- int add = 1 << (shift - 1);
- int16_t *src = coeffs;
-
- stride /= sizeof(pixel);
-
- for (i = 0; i < 8; i++) {
- TR_8(src, src, 8, 8, SCALE);
- src++;
- }
-
- shift = 20 - BIT_DEPTH;
- add = 1 << (shift - 1);
- for (i = 0; i < 8; i++) {
- TR_8(dst, coeffs, 1, 1, ADD_AND_SCALE);
- coeffs += 8;
- dst += stride;
- }
+#define IDCT_VAR4(H) \
+ int limit2 = FFMIN(col_limit + 4, H)
+#define IDCT_VAR8(H) \
+ int limit = FFMIN(col_limit, H); \
+ int limit2 = FFMIN(col_limit + 4, H)
+#define IDCT_VAR16(H) IDCT_VAR8(H)
+#define IDCT_VAR32(H) IDCT_VAR8(H)
+
+#define IDCT(H) \
+static void FUNC(idct_##H ##x ##H )( \
+ int16_t *coeffs, int col_limit) { \
+ int i; \
+ int shift = 7; \
+ int add = 1 << (shift - 1); \
+ int16_t *src = coeffs; \
+ IDCT_VAR ##H(H); \
+ \
+ for (i = 0; i < H; i++) { \
+ TR_ ## H(src, src, H, H, SCALE, limit2); \
+ if (limit2 < H && i%4 == 0 && !!i) \
+ limit2 -= 4; \
+ src++; \
+ } \
+ \
+ shift = 20 - BIT_DEPTH; \
+ add = 1 << (shift - 1); \
+ for (i = 0; i < H; i++) { \
+ TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit); \
+ coeffs += H; \
+ } \
}
-static void FUNC(transform_16x16_add)(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride)
-{
- int i;
- pixel *dst = (pixel *)_dst;
- int shift = 7;
- int add = 1 << (shift - 1);
- int16_t *src = coeffs;
-
- stride /= sizeof(pixel);
-
- for (i = 0; i < 16; i++) {
- TR_16(src, src, 16, 16, SCALE);
- src++;
- }
-
- shift = 20 - BIT_DEPTH;
- add = 1 << (shift - 1);
- for (i = 0; i < 16; i++) {
- TR_16(dst, coeffs, 1, 1, ADD_AND_SCALE);
- coeffs += 16;
- dst += stride;
- }
+#define IDCT_DC(H) \
+static void FUNC(idct_##H ##x ##H ##_dc)( \
+ int16_t *coeffs) { \
+ int i, j; \
+ int shift = 14 - BIT_DEPTH; \
+ int add = 1 << (shift - 1); \
+ int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift; \
+ \
+ for (j = 0; j < H; j++) { \
+ for (i = 0; i < H; i++) { \
+ coeffs[i+j*H] = coeff; \
+ } \
+ } \
}
-static void FUNC(transform_32x32_add)(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride)
-{
- int i;
- pixel *dst = (pixel *)_dst;
- int shift = 7;
- int add = 1 << (shift - 1);
- int16_t *src = coeffs;
+IDCT( 4)
+IDCT( 8)
+IDCT(16)
+IDCT(32)
- stride /= sizeof(pixel);
+IDCT_DC( 4)
+IDCT_DC( 8)
+IDCT_DC(16)
+IDCT_DC(32)
- for (i = 0; i < 32; i++) {
- TR_32(src, src, 32, 32, SCALE);
- src++;
- }
- src = coeffs;
- shift = 20 - BIT_DEPTH;
- add = 1 << (shift - 1);
- for (i = 0; i < 32; i++) {
- TR_32(dst, coeffs, 1, 1, ADD_AND_SCALE);
- coeffs += 32;
- dst += stride;
- }
-}
+#undef TR_4
+#undef TR_8
+#undef TR_16
+#undef TR_32
+
+#undef SET
+#undef SCALE
+#undef ADD_AND_SCALE
-static void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int width, int height,
- int c_idx, int class)
+static void FUNC(sao_band_filter_0)(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)
{
pixel *dst = (pixel *)_dst;
pixel *src = (pixel *)_src;
int offset_table[32] = { 0 };
int k, y, x;
- int chroma = !!c_idx;
int shift = BIT_DEPTH - 5;
- int *sao_offset_val = sao->offset_val[c_idx];
- int sao_left_class = sao->band_position[c_idx];
- int init_y = 0, init_x = 0;
- stride /= sizeof(pixel);
-
- switch (class) {
- case 0:
- if (!borders[2])
- width -= (8 >> chroma) + 2;
- if (!borders[3])
- height -= (4 >> chroma) + 2;
- break;
- case 1:
- init_y = -(4 >> chroma) - 2;
- if (!borders[2])
- width -= (8 >> chroma) + 2;
- height = (4 >> chroma) + 2;
- break;
- case 2:
- init_x = -(8 >> chroma) - 2;
- width = (8 >> chroma) + 2;
- if (!borders[3])
- height -= (4 >> chroma) + 2;
- break;
- case 3:
- init_y = -(4 >> chroma) - 2;
- init_x = -(8 >> chroma) - 2;
- width = (8 >> chroma) + 2;
- height = (4 >> chroma) + 2;
- break;
- }
+ stride_dst /= sizeof(pixel);
+ stride_src /= sizeof(pixel);
- dst = dst + (init_y * stride + init_x);
- src = src + (init_y * stride + init_x);
for (k = 0; k < 4; k++)
offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);
- dst += stride;
- src += stride;
+ dst += stride_dst;
+ src += stride_src;
}
}
-static void FUNC(sao_band_filter_0)(uint8_t *dst, uint8_t *src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int width, int height,
- int c_idx)
-{
- FUNC(sao_band_filter)(dst, src, stride, sao, borders,
- width, height, c_idx, 0);
-}
+#define CMP(a, b) (((a) > (b)) - ((a) < (b)))
-static void FUNC(sao_band_filter_1)(uint8_t *dst, uint8_t *src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int width, int height,
- int c_idx)
-{
- FUNC(sao_band_filter)(dst, src, stride, sao, borders,
- width, height, c_idx, 1);
-}
+static void FUNC(sao_edge_filter)(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,
+ int eo, int width, int height) {
-static void FUNC(sao_band_filter_2)(uint8_t *dst, uint8_t *src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int width, int height,
- int c_idx)
-{
- FUNC(sao_band_filter)(dst, src, stride, sao, borders,
- width, height, c_idx, 2);
-}
+ static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
+ static const int8_t pos[4][2][2] = {
+ { { -1, 0 }, { 1, 0 } }, // horizontal
+ { { 0, -1 }, { 0, 1 } }, // vertical
+ { { -1, -1 }, { 1, 1 } }, // 45 degree
+ { { 1, -1 }, { -1, 1 } }, // 135 degree
+ };
+ pixel *dst = (pixel *)_dst;
+ pixel *src = (pixel *)_src;
+ int a_stride, b_stride;
+ int x, y;
+ ptrdiff_t stride_src = (2*MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE) / sizeof(pixel);
+ stride_dst /= sizeof(pixel);
-static void FUNC(sao_band_filter_3)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int width, int height,
- int c_idx)
-{
- FUNC(sao_band_filter)(_dst, _src, stride, sao, borders,
- width, height, c_idx, 3);
+ a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;
+ b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ int diff0 = CMP(src[x], src[x + a_stride]);
+ int diff1 = CMP(src[x], src[x + b_stride]);
+ int offset_val = edge_idx[2 + diff0 + diff1];
+ dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);
+ }
+ src += stride_src;
+ dst += stride_dst;
+ }
}
-static void FUNC(sao_edge_filter_0)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
+static void FUNC(sao_edge_restore_0)(uint8_t *_dst, uint8_t *_src,
+ ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,
int *borders, int _width, int _height,
- int c_idx, uint8_t vert_edge,
- uint8_t horiz_edge, uint8_t diag_edge)
+ int c_idx, uint8_t *vert_edge,
+ uint8_t *horiz_edge, uint8_t *diag_edge)
{
int x, y;
pixel *dst = (pixel *)_dst;
pixel *src = (pixel *)_src;
- int chroma = !!c_idx;
- int *sao_offset_val = sao->offset_val[c_idx];
+ int16_t *sao_offset_val = sao->offset_val[c_idx];
int sao_eo_class = sao->eo_class[c_idx];
- int init_x = 0, init_y = 0, width = _width, height = _height;
-
- static const int8_t pos[4][2][2] = {
- { { -1, 0 }, { 1, 0 } }, // horizontal
- { { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
- };
- static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
-
-#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
-
- stride /= sizeof(pixel);
+ int init_x = 0, width = _width, height = _height;
- if (!borders[2])
- width -= (8 >> chroma) + 2;
- if (!borders[3])
- height -= (4 >> chroma) + 2;
+ stride_dst /= sizeof(pixel);
+ stride_src /= sizeof(pixel);
- dst = dst + (init_y * stride + init_x);
- src = src + (init_y * stride + init_x);
- init_y = init_x = 0;
if (sao_eo_class != SAO_EO_VERT) {
if (borders[0]) {
int offset_val = sao_offset_val[0];
- int y_stride = 0;
for (y = 0; y < height; y++) {
- dst[y_stride] = av_clip_pixel(src[y_stride] + offset_val);
- y_stride += stride;
+ dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);
}
init_x = 1;
}
if (borders[2]) {
int offset_val = sao_offset_val[0];
- int x_stride = width - 1;
+ int offset = width - 1;
for (x = 0; x < height; x++) {
- dst[x_stride] = av_clip_pixel(src[x_stride] + offset_val);
- x_stride += stride;
+ dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);
}
width--;
}
@@ -467,526 +396,725 @@ static void FUNC(sao_edge_filter_0)(uint8_t *_dst, uint8_t *_src,
int offset_val = sao_offset_val[0];
for (x = init_x; x < width; x++)
dst[x] = av_clip_pixel(src[x] + offset_val);
- init_y = 1;
}
if (borders[3]) {
- int offset_val = sao_offset_val[0];
- int y_stride = stride * (height - 1);
+ int offset_val = sao_offset_val[0];
+ int y_stride_dst = stride_dst * (height - 1);
+ int y_stride_src = stride_src * (height - 1);
for (x = init_x; x < width; x++)
- dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + offset_val);
+ dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);
height--;
}
}
- {
- int y_stride = init_y * stride;
- int pos_0_0 = pos[sao_eo_class][0][0];
- int pos_0_1 = pos[sao_eo_class][0][1];
- int pos_1_0 = pos[sao_eo_class][1][0];
- int pos_1_1 = pos[sao_eo_class][1][1];
-
- int y_stride_0_1 = (init_y + pos_0_1) * stride;
- int y_stride_1_1 = (init_y + pos_1_1) * stride;
- for (y = init_y; y < height; y++) {
- for (x = init_x; x < width; x++) {
- int diff0 = CMP(src[x + y_stride], src[x + pos_0_0 + y_stride_0_1]);
- int diff1 = CMP(src[x + y_stride], src[x + pos_1_0 + y_stride_1_1]);
- int offset_val = edge_idx[2 + diff0 + diff1];
- dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + sao_offset_val[offset_val]);
- }
- y_stride += stride;
- y_stride_0_1 += stride;
- y_stride_1_1 += stride;
- }
- }
-
- {
- // Restore pixels that can't be modified
- int save_upper_left = !diag_edge && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];
- if (vert_edge && sao_eo_class != SAO_EO_VERT)
- for (y = init_y+save_upper_left; y< height; y++)
- dst[y*stride] = src[y*stride];
- if(horiz_edge && sao_eo_class != SAO_EO_HORIZ)
- for(x = init_x+save_upper_left; x<width; x++)
- dst[x] = src[x];
- if(diag_edge && sao_eo_class == SAO_EO_135D)
- dst[0] = src[0];
- }
-
-#undef CMP
}
-static void FUNC(sao_edge_filter_1)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
+static void FUNC(sao_edge_restore_1)(uint8_t *_dst, uint8_t *_src,
+ ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,
int *borders, int _width, int _height,
- int c_idx, uint8_t vert_edge,
- uint8_t horiz_edge, uint8_t diag_edge)
+ int c_idx, uint8_t *vert_edge,
+ uint8_t *horiz_edge, uint8_t *diag_edge)
{
int x, y;
pixel *dst = (pixel *)_dst;
pixel *src = (pixel *)_src;
- int chroma = !!c_idx;
- int *sao_offset_val = sao->offset_val[c_idx];
+ int16_t *sao_offset_val = sao->offset_val[c_idx];
int sao_eo_class = sao->eo_class[c_idx];
int init_x = 0, init_y = 0, width = _width, height = _height;
- static const int8_t pos[4][2][2] = {
- { { -1, 0 }, { 1, 0 } }, // horizontal
- { { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
- };
- static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
-
-#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
-
- stride /= sizeof(pixel);
-
- init_y = -(4 >> chroma) - 2;
- if (!borders[2])
- width -= (8 >> chroma) + 2;
- height = (4 >> chroma) + 2;
+ stride_dst /= sizeof(pixel);
+ stride_src /= sizeof(pixel);
- dst = dst + (init_y * stride + init_x);
- src = src + (init_y * stride + init_x);
- init_y = init_x = 0;
if (sao_eo_class != SAO_EO_VERT) {
if (borders[0]) {
int offset_val = sao_offset_val[0];
- int y_stride = 0;
for (y = 0; y < height; y++) {
- dst[y_stride] = av_clip_pixel(src[y_stride] + offset_val);
- y_stride += stride;
+ dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);
}
init_x = 1;
}
if (borders[2]) {
int offset_val = sao_offset_val[0];
- int x_stride = width - 1;
+ int offset = width - 1;
for (x = 0; x < height; x++) {
- dst[x_stride] = av_clip_pixel(src[x_stride] + offset_val);
- x_stride += stride;
+ dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);
}
width--;
}
}
- {
- int y_stride = init_y * stride;
- int pos_0_0 = pos[sao_eo_class][0][0];
- int pos_0_1 = pos[sao_eo_class][0][1];
- int pos_1_0 = pos[sao_eo_class][1][0];
- int pos_1_1 = pos[sao_eo_class][1][1];
-
- int y_stride_0_1 = (init_y + pos_0_1) * stride;
- int y_stride_1_1 = (init_y + pos_1_1) * stride;
- for (y = init_y; y < height; y++) {
- for (x = init_x; x < width; x++) {
- int diff0 = CMP(src[x + y_stride], src[x + pos_0_0 + y_stride_0_1]);
- int diff1 = CMP(src[x + y_stride], src[x + pos_1_0 + y_stride_1_1]);
- int offset_val = edge_idx[2 + diff0 + diff1];
- dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + sao_offset_val[offset_val]);
- }
- y_stride += stride;
- y_stride_0_1 += stride;
- y_stride_1_1 += stride;
+ if (sao_eo_class != SAO_EO_HORIZ) {
+ if (borders[1]) {
+ int offset_val = sao_offset_val[0];
+ for (x = init_x; x < width; x++)
+ dst[x] = av_clip_pixel(src[x] + offset_val);
+ init_y = 1;
+ }
+ if (borders[3]) {
+ int offset_val = sao_offset_val[0];
+ int y_stride_dst = stride_dst * (height - 1);
+ int y_stride_src = stride_src * (height - 1);
+ for (x = init_x; x < width; x++)
+ dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);
+ height--;
}
}
{
+ int save_upper_left = !diag_edge[0] && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];
+ int save_upper_right = !diag_edge[1] && sao_eo_class == SAO_EO_45D && !borders[1] && !borders[2];
+ int save_lower_right = !diag_edge[2] && sao_eo_class == SAO_EO_135D && !borders[2] && !borders[3];
+ int save_lower_left = !diag_edge[3] && sao_eo_class == SAO_EO_45D && !borders[0] && !borders[3];
+
// Restore pixels that can't be modified
- int save_lower_left = !diag_edge && sao_eo_class == SAO_EO_45D && !borders[0];
- if(vert_edge && sao_eo_class != SAO_EO_VERT)
- for(y = init_y; y< height-save_lower_left; y++)
- dst[y*stride] = src[y*stride];
- if(horiz_edge && sao_eo_class != SAO_EO_HORIZ)
- for(x = init_x+save_lower_left; x<width; x++)
- dst[(height-1)*stride+x] = src[(height-1)*stride+x];
- if(diag_edge && sao_eo_class == SAO_EO_45D)
- dst[stride*(height-1)] = src[stride*(height-1)];
+ if(vert_edge[0] && sao_eo_class != SAO_EO_VERT) {
+ for(y = init_y+save_upper_left; y< height-save_lower_left; y++)
+ dst[y*stride_dst] = src[y*stride_src];
+ }
+ if(vert_edge[1] && sao_eo_class != SAO_EO_VERT) {
+ for(y = init_y+save_upper_right; y< height-save_lower_right; y++)
+ dst[y*stride_dst+width-1] = src[y*stride_src+width-1];
+ }
+
+ if(horiz_edge[0] && sao_eo_class != SAO_EO_HORIZ) {
+ for(x = init_x+save_upper_left; x < width-save_upper_right; x++)
+ dst[x] = src[x];
+ }
+ if(horiz_edge[1] && sao_eo_class != SAO_EO_HORIZ) {
+ for(x = init_x+save_lower_left; x < width-save_lower_right; x++)
+ dst[(height-1)*stride_dst+x] = src[(height-1)*stride_src+x];
+ }
+ if(diag_edge[0] && sao_eo_class == SAO_EO_135D)
+ dst[0] = src[0];
+ if(diag_edge[1] && sao_eo_class == SAO_EO_45D)
+ dst[width-1] = src[width-1];
+ if(diag_edge[2] && sao_eo_class == SAO_EO_135D)
+ dst[stride_dst*(height-1)+width-1] = src[stride_src*(height-1)+width-1];
+ if(diag_edge[3] && sao_eo_class == SAO_EO_45D)
+ dst[stride_dst*(height-1)] = src[stride_src*(height-1)];
+
}
+}
#undef CMP
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+static void FUNC(put_hevc_pel_pixels)(int16_t *dst,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = src[x] << (14 - BIT_DEPTH);
+ src += srcstride;
+ dst += MAX_PB_SIZE;
+ }
}
-static void FUNC(sao_edge_filter_2)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int _width, int _height,
- int c_idx, uint8_t vert_edge,
- uint8_t horiz_edge, uint8_t diag_edge)
+static void FUNC(put_hevc_pel_uni_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ for (y = 0; y < height; y++) {
+ memcpy(dst, src, width * sizeof(pixel));
+ src += srcstride;
+ dst += dststride;
+ }
+}
+
+static void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
- pixel *dst = (pixel *)_dst;
- pixel *src = (pixel *)_src;
- int chroma = !!c_idx;
- int *sao_offset_val = sao->offset_val[c_idx];
- int sao_eo_class = sao->eo_class[c_idx];
- int init_x = 0, init_y = 0, width = _width, height = _height;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
- static const int8_t pos[4][2][2] = {
- { { -1, 0 }, { 1, 0 } }, // horizontal
- { { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
- };
- static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
+ int shift = 14 + 1 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
-#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift);
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
- stride /= sizeof(pixel);
+static void FUNC(put_hevc_pel_uni_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
- init_x = -(8 >> chroma) - 2;
- width = (8 >> chroma) + 2;
- if (!borders[3])
- height -= (4 >> chroma) + 2;
+ ox = ox * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel((((src[x] << (14 - BIT_DEPTH)) * wx + offset) >> shift) + ox);
+ src += srcstride;
+ dst += dststride;
+ }
+}
- dst = dst + (init_y * stride + init_x);
- src = src + (init_y * stride + init_x);
- init_y = init_x = 0;
- if (sao_eo_class != SAO_EO_HORIZ) {
- if (borders[1]) {
- int offset_val = sao_offset_val[0];
- for (x = init_x; x < width; x++)
- dst[x] = av_clip_pixel(src[x] + offset_val);
- init_y = 1;
- }
- if (borders[3]) {
- int offset_val = sao_offset_val[0];
- int y_stride = stride * (height - 1);
- for (x = init_x; x < width; x++)
- dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + offset_val);
- height--;
+static void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ dst[x] = av_clip_pixel(( (src[x] << (14 - BIT_DEPTH)) * wx1 + src2[x] * wx0 + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
}
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
}
- {
- int y_stride = init_y * stride;
- int pos_0_0 = pos[sao_eo_class][0][0];
- int pos_0_1 = pos[sao_eo_class][0][1];
- int pos_1_0 = pos[sao_eo_class][1][0];
- int pos_1_1 = pos[sao_eo_class][1][1];
-
- int y_stride_0_1 = (init_y + pos_0_1) * stride;
- int y_stride_1_1 = (init_y + pos_1_1) * stride;
- for (y = init_y; y < height; y++) {
- for (x = init_x; x < width; x++) {
- int diff0 = CMP(src[x + y_stride], src[x + pos_0_0 + y_stride_0_1]);
- int diff1 = CMP(src[x + y_stride], src[x + pos_1_0 + y_stride_1_1]);
- int offset_val = edge_idx[2 + diff0 + diff1];
- dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + sao_offset_val[offset_val]);
- }
- y_stride += stride;
- y_stride_0_1 += stride;
- y_stride_1_1 += stride;
- }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+#define QPEL_FILTER(src, stride) \
+ (filter[0] * src[x - 3 * stride] + \
+ filter[1] * src[x - 2 * stride] + \
+ filter[2] * src[x - stride] + \
+ filter[3] * src[x ] + \
+ filter[4] * src[x + stride] + \
+ filter[5] * src[x + 2 * stride] + \
+ filter[6] * src[x + 3 * stride] + \
+ filter[7] * src[x + 4 * stride])
+
+static void FUNC(put_hevc_qpel_h)(int16_t *dst,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[mx - 1];
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ dst += MAX_PB_SIZE;
}
+}
- {
- // Restore pixels that can't be modified
- int save_upper_right = !diag_edge && sao_eo_class == SAO_EO_45D && !borders[1];
- if(vert_edge && sao_eo_class != SAO_EO_VERT)
- for(y = init_y+save_upper_right; y< height; y++)
- dst[y*stride+width-1] = src[y*stride+width-1];
- if(horiz_edge && sao_eo_class != SAO_EO_HORIZ)
- for(x = init_x; x<width-save_upper_right; x++)
- dst[x] = src[x];
- if(diag_edge && sao_eo_class == SAO_EO_45D)
- dst[width-1] = src[width-1];
+static void FUNC(put_hevc_qpel_v)(int16_t *dst,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[my - 1];
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ dst += MAX_PB_SIZE;
}
-#undef CMP
}
-static void FUNC(sao_edge_filter_3)(uint8_t *_dst, uint8_t *_src,
- ptrdiff_t stride, SAOParams *sao,
- int *borders, int _width, int _height,
- int c_idx, uint8_t vert_edge,
- uint8_t horiz_edge, uint8_t diag_edge)
+static void FUNC(put_hevc_qpel_hv)(int16_t *dst,
+ uint8_t *_src,
+ ptrdiff_t _srcstride,
+ int height, intptr_t mx,
+ intptr_t my, int width)
{
int x, y;
- pixel *dst = (pixel *)_dst;
- pixel *src = (pixel *)_src;
- int chroma = !!c_idx;
- int *sao_offset_val = sao->offset_val[c_idx];
- int sao_eo_class = sao->eo_class[c_idx];
- int init_x = 0, init_y = 0, width = _width, height = _height;
+ const int8_t *filter;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
- static const int8_t pos[4][2][2] = {
- { { -1, 0 }, { 1, 0 } }, // horizontal
- { { 0, -1 }, { 0, 1 } }, // vertical
- { { -1, -1 }, { 1, 1 } }, // 45 degree
- { { 1, -1 }, { -1, 1 } }, // 135 degree
- };
- static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
+ src -= QPEL_EXTRA_BEFORE * srcstride;
+ filter = ff_hevc_qpel_filters[mx - 1];
+ for (y = 0; y < height + QPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
-#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
+ tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_qpel_filters[my - 1];
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;
+ tmp += MAX_PB_SIZE;
+ dst += MAX_PB_SIZE;
+ }
+}
- stride /= sizeof(pixel);
+static void FUNC(put_hevc_qpel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[mx - 1];
+ int shift = 14 - BIT_DEPTH;
+
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);
+ src += srcstride;
+ dst += dststride;
+ }
+}
- init_y = -(4 >> chroma) - 2;
- init_x = -(8 >> chroma) - 2;
- width = (8 >> chroma) + 2;
- height = (4 >> chroma) + 2;
+static void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[mx - 1];
- dst = dst + (init_y * stride + init_x);
- src = src + (init_y * stride + init_x);
- init_y = init_x = 0;
+ int shift = 14 + 1 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
- {
- int y_stride = init_y * stride;
- int pos_0_0 = pos[sao_eo_class][0][0];
- int pos_0_1 = pos[sao_eo_class][0][1];
- int pos_1_0 = pos[sao_eo_class][1][0];
- int pos_1_1 = pos[sao_eo_class][1][1];
-
- int y_stride_0_1 = (init_y + pos_0_1) * stride;
- int y_stride_1_1 = (init_y + pos_1_1) * stride;
-
- for (y = init_y; y < height; y++) {
- for (x = init_x; x < width; x++) {
- int diff0 = CMP(src[x + y_stride], src[x + pos_0_0 + y_stride_0_1]);
- int diff1 = CMP(src[x + y_stride], src[x + pos_1_0 + y_stride_1_1]);
- int offset_val = edge_idx[2 + diff0 + diff1];
- dst[x + y_stride] = av_clip_pixel(src[x + y_stride] + sao_offset_val[offset_val]);
- }
- y_stride += stride;
- y_stride_0_1 += stride;
- y_stride_1_1 += stride;
- }
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
}
+}
- {
- // Restore pixels that can't be modified
- int save_lower_right = !diag_edge && sao_eo_class == SAO_EO_135D;
- if(vert_edge && sao_eo_class != SAO_EO_VERT)
- for(y = init_y; y< height-save_lower_right; y++)
- dst[y*stride+width-1] = src[y*stride+width-1];
- if(horiz_edge && sao_eo_class != SAO_EO_HORIZ)
- for(x = init_x; x<width-save_lower_right; x++)
- dst[(height-1)*stride+x] = src[(height-1)*stride+x];
- if(diag_edge && sao_eo_class == SAO_EO_135D)
- dst[stride*(height-1)+width-1] = src[stride*(height-1)+width-1];
+static void FUNC(put_hevc_qpel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[my - 1];
+ int shift = 14 - BIT_DEPTH;
+
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);
+ src += srcstride;
+ dst += dststride;
}
-#undef CMP
}
-#undef SET
-#undef SCALE
-#undef ADD_AND_SCALE
-#undef TR_4
-#undef TR_8
-#undef TR_16
-#undef TR_32
-static void FUNC(put_hevc_qpel_pixels)(int16_t *dst, ptrdiff_t dststride,
+static void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ const int8_t *filter = ff_hevc_qpel_filters[my - 1];
+
+ int shift = 14 + 1 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_qpel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride,
uint8_t *_src, ptrdiff_t _srcstride,
- int width, int height, int16_t* mcbuffer)
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
- pixel *src = (pixel *)_src;
+ const int8_t *filter;
+ pixel *src = (pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = 14 - BIT_DEPTH;
+
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ src -= QPEL_EXTRA_BEFORE * srcstride;
+ filter = ff_hevc_qpel_filters[mx - 1];
+ for (y = 0; y < height + QPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_qpel_filters[my - 1];
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
- dst[x] = src[x] << (14 - BIT_DEPTH);
+ dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
+ }
+}
+
+static void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ const int8_t *filter;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = 14 + 1 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ src -= QPEL_EXTRA_BEFORE * srcstride;
+ filter = ff_hevc_qpel_filters[mx - 1];
+ for (y = 0; y < height + QPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_qpel_filters[my - 1];
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_qpel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox,
+ intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[mx - 1];
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ ox = ox * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel((((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);
src += srcstride;
dst += dststride;
}
}
-#define QPEL_FILTER_1(src, stride) \
- (1 * -src[x - 3 * stride] + \
- 4 * src[x - 2 * stride] - \
- 10 * src[x - stride] + \
- 58 * src[x] + \
- 17 * src[x + stride] - \
- 5 * src[x + 2 * stride] + \
- 1 * src[x + 3 * stride])
-
-#define QPEL_FILTER_2(src, stride) \
- (1 * -src[x - 3 * stride] + \
- 4 * src[x - 2 * stride] - \
- 11 * src[x - stride] + \
- 40 * src[x] + \
- 40 * src[x + stride] - \
- 11 * src[x + 2 * stride] + \
- 4 * src[x + 3 * stride] - \
- 1 * src[x + 4 * stride])
-
-#define QPEL_FILTER_3(src, stride) \
- (1 * src[x - 2 * stride] - \
- 5 * src[x - stride] + \
- 17 * src[x] + \
- 58 * src[x + stride] - \
- 10 * src[x + 2 * stride] + \
- 4 * src[x + 3 * stride] - \
- 1 * src[x + 4 * stride])
-
-
-#define PUT_HEVC_QPEL_H(H) \
-static void FUNC(put_hevc_qpel_h ## H)(int16_t *dst, ptrdiff_t dststride, \
- uint8_t *_src, ptrdiff_t _srcstride, \
- int width, int height, \
- int16_t* mcbuffer) \
-{ \
- int x, y; \
- pixel *src = (pixel*)_src; \
- ptrdiff_t srcstride = _srcstride / sizeof(pixel); \
- \
- for (y = 0; y < height; y++) { \
- for (x = 0; x < width; x++) \
- dst[x] = QPEL_FILTER_ ## H(src, 1) >> (BIT_DEPTH - 8); \
- src += srcstride; \
- dst += dststride; \
- } \
+static void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ const int8_t *filter = ff_hevc_qpel_filters[mx - 1];
+
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
+ ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
}
-#define PUT_HEVC_QPEL_V(V) \
-static void FUNC(put_hevc_qpel_v ## V)(int16_t *dst, ptrdiff_t dststride, \
- uint8_t *_src, ptrdiff_t _srcstride, \
- int width, int height, \
- int16_t* mcbuffer) \
-{ \
- int x, y; \
- pixel *src = (pixel*)_src; \
- ptrdiff_t srcstride = _srcstride / sizeof(pixel); \
- \
- for (y = 0; y < height; y++) { \
- for (x = 0; x < width; x++) \
- dst[x] = QPEL_FILTER_ ## V(src, srcstride) >> (BIT_DEPTH - 8); \
- src += srcstride; \
- dst += dststride; \
- } \
+static void FUNC(put_hevc_qpel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox,
+ intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_qpel_filters[my - 1];
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ ox = ox * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel((((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);
+ src += srcstride;
+ dst += dststride;
+ }
}
-#define PUT_HEVC_QPEL_HV(H, V) \
-static void FUNC(put_hevc_qpel_h ## H ## v ## V)(int16_t *dst, \
- ptrdiff_t dststride, \
- uint8_t *_src, \
- ptrdiff_t _srcstride, \
- int width, int height, \
- int16_t* mcbuffer) \
-{ \
- int x, y; \
- pixel *src = (pixel*)_src; \
- ptrdiff_t srcstride = _srcstride / sizeof(pixel); \
- \
- int16_t tmp_array[(MAX_PB_SIZE + 7) * MAX_PB_SIZE]; \
- int16_t *tmp = tmp_array; \
- \
- src -= ff_hevc_qpel_extra_before[V] * srcstride; \
- \
- for (y = 0; y < height + ff_hevc_qpel_extra[V]; y++) { \
- for (x = 0; x < width; x++) \
- tmp[x] = QPEL_FILTER_ ## H(src, 1) >> (BIT_DEPTH - 8); \
- src += srcstride; \
- tmp += MAX_PB_SIZE; \
- } \
- \
- tmp = tmp_array + ff_hevc_qpel_extra_before[V] * MAX_PB_SIZE; \
- \
- for (y = 0; y < height; y++) { \
- for (x = 0; x < width; x++) \
- dst[x] = QPEL_FILTER_ ## V(tmp, MAX_PB_SIZE) >> 6; \
- tmp += MAX_PB_SIZE; \
- dst += dststride; \
- } \
+static void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+
+ const int8_t *filter = ff_hevc_qpel_filters[my - 1];
+
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
+ ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
}
-PUT_HEVC_QPEL_H(1)
-PUT_HEVC_QPEL_H(2)
-PUT_HEVC_QPEL_H(3)
-PUT_HEVC_QPEL_V(1)
-PUT_HEVC_QPEL_V(2)
-PUT_HEVC_QPEL_V(3)
-PUT_HEVC_QPEL_HV(1, 1)
-PUT_HEVC_QPEL_HV(1, 2)
-PUT_HEVC_QPEL_HV(1, 3)
-PUT_HEVC_QPEL_HV(2, 1)
-PUT_HEVC_QPEL_HV(2, 2)
-PUT_HEVC_QPEL_HV(2, 3)
-PUT_HEVC_QPEL_HV(3, 1)
-PUT_HEVC_QPEL_HV(3, 2)
-PUT_HEVC_QPEL_HV(3, 3)
-
-static void FUNC(put_hevc_epel_pixels)(int16_t *dst, ptrdiff_t dststride,
- uint8_t *_src, ptrdiff_t _srcstride,
- int width, int height, int mx, int my,
- int16_t* mcbuffer)
+static void FUNC(put_hevc_qpel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride,
+ uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox,
+ intptr_t mx, intptr_t my, int width)
{
int x, y;
- pixel *src = (pixel *)_src;
+ const int8_t *filter;
+ pixel *src = (pixel*)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
- for (y = 0; y < height; y++) {
+ src -= QPEL_EXTRA_BEFORE * srcstride;
+ filter = ff_hevc_qpel_filters[mx - 1];
+ for (y = 0; y < height + QPEL_EXTRA; y++) {
for (x = 0; x < width; x++)
- dst[x] = src[x] << (14 - BIT_DEPTH);
+ tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_qpel_filters[my - 1];
+
+ ox = ox * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel((((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);
+ tmp += MAX_PB_SIZE;
dst += dststride;
}
}
-#define EPEL_FILTER(src, stride) \
- (filter_0 * src[x - stride] + \
- filter_1 * src[x] + \
- filter_2 * src[x + stride] + \
- filter_3 * src[x + 2 * stride])
+static void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ const int8_t *filter;
+ pixel *src = (pixel*)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+
+ src -= QPEL_EXTRA_BEFORE * srcstride;
+ filter = ff_hevc_qpel_filters[mx - 1];
+ for (y = 0; y < height + QPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_qpel_filters[my - 1];
+
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +
+ ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+#define EPEL_FILTER(src, stride) \
+ (filter[0] * src[x - stride] + \
+ filter[1] * src[x] + \
+ filter[2] * src[x + stride] + \
+ filter[3] * src[x + 2 * stride])
-static void FUNC(put_hevc_epel_h)(int16_t *dst, ptrdiff_t dststride,
+static void FUNC(put_hevc_epel_h)(int16_t *dst,
uint8_t *_src, ptrdiff_t _srcstride,
- int width, int height, int mx, int my,
- int16_t* mcbuffer)
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
pixel *src = (pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[mx - 1];
- int8_t filter_0 = filter[0];
- int8_t filter_1 = filter[1];
- int8_t filter_2 = filter[2];
- int8_t filter_3 = filter[3];
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
src += srcstride;
- dst += dststride;
+ dst += MAX_PB_SIZE;
}
}
-static void FUNC(put_hevc_epel_v)(int16_t *dst, ptrdiff_t dststride,
+static void FUNC(put_hevc_epel_v)(int16_t *dst,
uint8_t *_src, ptrdiff_t _srcstride,
- int width, int height, int mx, int my,
- int16_t* mcbuffer)
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
pixel *src = (pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
const int8_t *filter = ff_hevc_epel_filters[my - 1];
- int8_t filter_0 = filter[0];
- int8_t filter_1 = filter[1];
- int8_t filter_2 = filter[2];
- int8_t filter_3 = filter[3];
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);
src += srcstride;
- dst += dststride;
+ dst += MAX_PB_SIZE;
}
}
-static void FUNC(put_hevc_epel_hv)(int16_t *dst, ptrdiff_t dststride,
+static void FUNC(put_hevc_epel_hv)(int16_t *dst,
uint8_t *_src, ptrdiff_t _srcstride,
- int width, int height, int mx, int my,
- int16_t* mcbuffer)
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
pixel *src = (pixel *)_src;
ptrdiff_t srcstride = _srcstride / sizeof(pixel);
- const int8_t *filter_h = ff_hevc_epel_filters[mx - 1];
- const int8_t *filter_v = ff_hevc_epel_filters[my - 1];
- int8_t filter_0 = filter_h[0];
- int8_t filter_1 = filter_h[1];
- int8_t filter_2 = filter_h[2];
- int8_t filter_3 = filter_h[3];
- int16_t tmp_array[(MAX_PB_SIZE + 3) * MAX_PB_SIZE];
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
int16_t *tmp = tmp_array;
src -= EPEL_EXTRA_BEFORE * srcstride;
@@ -999,49 +1127,101 @@ static void FUNC(put_hevc_epel_hv)(int16_t *dst, ptrdiff_t dststride,
}
tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
- filter_0 = filter_v[0];
- filter_1 = filter_v[1];
- filter_2 = filter_v[2];
- filter_3 = filter_v[3];
+ filter = ff_hevc_epel_filters[my - 1];
+
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
dst[x] = EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;
tmp += MAX_PB_SIZE;
+ dst += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_epel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int shift = 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);
+ src += srcstride;
dst += dststride;
}
}
-static void FUNC(put_unweighted_pred)(uint8_t *_dst, ptrdiff_t _dststride,
- int16_t *src, ptrdiff_t srcstride,
- int width, int height)
+static void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int shift = 14 + 1 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
+ }
+ dst += dststride;
+ src += srcstride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+static void FUNC(put_hevc_epel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[my - 1];
int shift = 14 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
#else
int offset = 0;
#endif
+
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
- dst[x] = av_clip_pixel((src[x] + offset) >> shift);
- dst += dststride;
+ dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);
src += srcstride;
+ dst += dststride;
}
}
-static void FUNC(put_weighted_pred_avg)(uint8_t *_dst, ptrdiff_t _dststride,
- int16_t *src1, int16_t *src2,
- ptrdiff_t srcstride,
- int width, int height)
+static void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
{
int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[my - 1];
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
-
int shift = 14 + 1 - BIT_DEPTH;
#if BIT_DEPTH < 14
int offset = 1 << (shift - 1);
@@ -1051,71 +1231,273 @@ static void FUNC(put_weighted_pred_avg)(uint8_t *_dst, ptrdiff_t _dststride,
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
- dst[x] = av_clip_pixel((src1[x] + src2[x] + offset) >> shift);
+ dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);
dst += dststride;
- src1 += srcstride;
- src2 += srcstride;
+ src += srcstride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_epel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ src -= EPEL_EXTRA_BEFORE * srcstride;
+
+ for (y = 0; y < height + EPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_epel_filters[my - 1];
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
}
}
-static void FUNC(weighted_pred)(uint8_t denom, int16_t wlxFlag, int16_t olxFlag,
- uint8_t *_dst, ptrdiff_t _dststride,
- int16_t *src, ptrdiff_t srcstride,
- int width, int height)
+static void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, intptr_t mx, intptr_t my, int width)
{
- int shift, log2Wd, wx, ox, x, y, offset;
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = 14 + 1 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ src -= EPEL_EXTRA_BEFORE * srcstride;
+
+ for (y = 0; y < height + EPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_epel_filters[my - 1];
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
- shift = 14 - BIT_DEPTH;
- log2Wd = denom + shift;
- offset = 1 << (log2Wd - 1);
- wx = wlxFlag;
- ox = olxFlag * (1 << (BIT_DEPTH - 8));
+static void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+ ox = ox * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
- if (log2Wd >= 1) {
- dst[x] = av_clip_pixel(((src[x] * wx + offset) >> log2Wd) + ox);
- } else {
- dst[x] = av_clip_pixel(src[x] * wx + ox);
- }
+ dst[x] = av_clip_pixel((((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);
}
dst += dststride;
src += srcstride;
}
}
-static void FUNC(weighted_pred_avg)(uint8_t denom,
- int16_t wl0Flag, int16_t wl1Flag,
- int16_t ol0Flag, int16_t ol1Flag,
- uint8_t *_dst, ptrdiff_t _dststride,
- int16_t *src1, int16_t *src2,
- ptrdiff_t srcstride,
- int width, int height)
+static void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
{
- int shift, log2Wd, w0, w1, o0, o1, x, y;
- pixel *dst = (pixel *)_dst;
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
+ ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
+ src += srcstride;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_epel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[my - 1];
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ ox = ox * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ dst[x] = av_clip_pixel((((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);
+ }
+ dst += dststride;
+ src += srcstride;
+ }
+}
- shift = 14 - BIT_DEPTH;
- log2Wd = denom + shift;
- w0 = wl0Flag;
- w1 = wl1Flag;
- o0 = ol0Flag * (1 << (BIT_DEPTH - 8));
- o1 = ol1Flag * (1 << (BIT_DEPTH - 8));
+static void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[my - 1];
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
- dst[x] = av_clip_pixel((src1[x] * w0 + src2[x] * w1 +
- ((o0 + o1 + 1) << log2Wd)) >> (log2Wd + 1));
+ dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +
+ ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
+ src += srcstride;
dst += dststride;
- src1 += srcstride;
- src2 += srcstride;
+ src2 += MAX_PB_SIZE;
+ }
+}
+
+static void FUNC(put_hevc_epel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = denom + 14 - BIT_DEPTH;
+#if BIT_DEPTH < 14
+ int offset = 1 << (shift - 1);
+#else
+ int offset = 0;
+#endif
+
+ src -= EPEL_EXTRA_BEFORE * srcstride;
+
+ for (y = 0; y < height + EPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_epel_filters[my - 1];
+
+ ox = ox * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel((((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
}
}
-// line zero
+static void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,
+ int16_t *src2,
+ int height, int denom, int wx0, int wx1,
+ int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+{
+ int x, y;
+ pixel *src = (pixel *)_src;
+ ptrdiff_t srcstride = _srcstride / sizeof(pixel);
+ pixel *dst = (pixel *)_dst;
+ ptrdiff_t dststride = _dststride / sizeof(pixel);
+ const int8_t *filter = ff_hevc_epel_filters[mx - 1];
+ int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];
+ int16_t *tmp = tmp_array;
+ int shift = 14 + 1 - BIT_DEPTH;
+ int log2Wd = denom + shift - 1;
+
+ src -= EPEL_EXTRA_BEFORE * srcstride;
+
+ for (y = 0; y < height + EPEL_EXTRA; y++) {
+ for (x = 0; x < width; x++)
+ tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);
+ src += srcstride;
+ tmp += MAX_PB_SIZE;
+ }
+
+ tmp = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;
+ filter = ff_hevc_epel_filters[my - 1];
+
+ ox0 = ox0 * (1 << (BIT_DEPTH - 8));
+ ox1 = ox1 * (1 << (BIT_DEPTH - 8));
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +
+ ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));
+ tmp += MAX_PB_SIZE;
+ dst += dststride;
+ src2 += MAX_PB_SIZE;
+ }
+}// line zero
#define P3 pix[-4 * xstride]
#define P2 pix[-3 * xstride]
#define P1 pix[-2 * xstride]
@@ -1266,21 +1648,21 @@ static void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,
}
static void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
- int *tc, uint8_t *no_p,
+ int32_t *tc, uint8_t *no_p,
uint8_t *no_q)
{
FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q);
}
static void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
- int *tc, uint8_t *no_p,
+ int32_t *tc, uint8_t *no_p,
uint8_t *no_q)
{
FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q);
}
static void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
- int beta, int *tc, uint8_t *no_p,
+ int beta, int32_t *tc, uint8_t *no_p,
uint8_t *no_q)
{
FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel),
@@ -1288,7 +1670,7 @@ static void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
}
static void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
- int beta, int *tc, uint8_t *no_p,
+ int beta, int32_t *tc, uint8_t *no_p,
uint8_t *no_q)
{
FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride,
diff --git a/libavcodec/hevcpred.c b/libavcodec/hevcpred.c
index 1ba2487a62..4598229b36 100644
--- a/libavcodec/hevcpred.c
+++ b/libavcodec/hevcpred.c
@@ -1,27 +1,29 @@
/*
- * HEVC video decoder
+ * HEVC video Decoder
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "hevc.h"
+#include "hevcpred.h"
+
#define BIT_DEPTH 8
#include "hevcpred_template.c"
#undef BIT_DEPTH
@@ -34,6 +36,10 @@
#include "hevcpred_template.c"
#undef BIT_DEPTH
+#define BIT_DEPTH 12
+#include "hevcpred_template.c"
+#undef BIT_DEPTH
+
void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth)
{
#undef FUNC
@@ -61,6 +67,9 @@ void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth)
case 10:
HEVC_PRED(10);
break;
+ case 12:
+ HEVC_PRED(12);
+ break;
default:
HEVC_PRED(8);
break;
diff --git a/libavcodec/hevcpred.h b/libavcodec/hevcpred.h
new file mode 100644
index 0000000000..7f14a76da1
--- /dev/null
+++ b/libavcodec/hevcpred.h
@@ -0,0 +1,45 @@
+/*
+ * HEVC video Decoder
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_HEVCPRED_H
+#define AVCODEC_HEVCPRED_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct HEVCContext;
+
+typedef struct HEVCPredContext {
+ void (*intra_pred[4])(struct HEVCContext *s, int x0, int y0, int c_idx);
+
+ void (*pred_planar[4])(uint8_t *src, const uint8_t *top,
+ const uint8_t *left, ptrdiff_t stride);
+ void (*pred_dc)(uint8_t *src, const uint8_t *top, const uint8_t *left,
+ ptrdiff_t stride, int log2_size, int c_idx);
+ void (*pred_angular[4])(uint8_t *src, const uint8_t *top,
+ const uint8_t *left, ptrdiff_t stride,
+ int c_idx, int mode);
+} HEVCPredContext;
+
+void ff_hevc_pred_init(HEVCPredContext *hpc, int bit_depth);
+
+#endif /* AVCODEC_HEVCPRED_H */
diff --git a/libavcodec/hevcpred_template.c b/libavcodec/hevcpred_template.c
index 53b9c590b6..6b763b3a73 100644
--- a/libavcodec/hevcpred_template.c
+++ b/libavcodec/hevcpred_template.c
@@ -3,28 +3,27 @@
*
* Copyright (C) 2012 - 2013 Guillaume Martres
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/pixdesc.h"
-#include "hevc.h"
-
#include "bit_depth_template.c"
+#include "hevcpred.h"
#define POS(x, y) src[(x) + stride * (y)]
@@ -38,10 +37,9 @@ static av_always_inline void FUNC(intra_pred)(HEVCContext *s, int x0, int y0,
#define MVF_PU(x, y) \
MVF(PU(x0 + ((x) << hshift)), PU(y0 + ((y) << vshift)))
#define IS_INTRA(x, y) \
- MVF_PU(x, y).is_intra
+ (MVF_PU(x, y).pred_flag == PF_INTRA)
#define MIN_TB_ADDR_ZS(x, y) \
- s->pps->min_tb_addr_zs[(y) * s->sps->min_tb_width + (x)]
-
+ s->pps->min_tb_addr_zs[(y) * (s->sps->tb_mask+2) + (x)]
#define EXTEND(ptr, val, len) \
do { \
pixel4 pix = PIXEL_SPLAT_X4(val); \
@@ -49,36 +47,43 @@ do { \
AV_WN4P(ptr + i, pix); \
} while (0)
+#define EXTEND_RIGHT_CIP(ptr, start, length) \
+ for (i = start; i < (start) + (length); i += 4) \
+ if (!IS_INTRA(i, -1)) \
+ AV_WN4P(&ptr[i], a); \
+ else \
+ a = PIXEL_SPLAT_X4(ptr[i+3])
#define EXTEND_LEFT_CIP(ptr, start, length) \
- for (i = (start); i > (start) - (length); i--) \
+ for (i = start; i > (start) - (length); i--) \
if (!IS_INTRA(i - 1, -1)) \
ptr[i - 1] = ptr[i]
-#define EXTEND_RIGHT_CIP(ptr, start, length) \
- for (i = (start); i < (start) + (length); i++) \
- if (!IS_INTRA(i, -1)) \
- ptr[i] = ptr[i - 1]
-#define EXTEND_UP_CIP(ptr, start, length) \
- for (i = (start); i > (start) - (length); i--) \
- if (!IS_INTRA(-1, i - 1)) \
- ptr[i - 1] = ptr[i]
-#define EXTEND_UP_CIP_0(ptr, start, length) \
- for (i = (start); i > (start) - (length); i--) \
- ptr[i - 1] = ptr[i]
-#define EXTEND_DOWN_CIP(ptr, start, length) \
- for (i = (start); i < (start) + (length); i++) \
- if (!IS_INTRA(-1, i)) \
- ptr[i] = ptr[i - 1]
- HEVCLocalContext *lc = &s->HEVClc;
+#define EXTEND_UP_CIP(ptr, start, length) \
+ for (i = (start); i > (start) - (length); i -= 4) \
+ if (!IS_INTRA(-1, i - 3)) \
+ AV_WN4P(&ptr[i - 3], a); \
+ else \
+ a = PIXEL_SPLAT_X4(ptr[i - 3])
+#define EXTEND_DOWN_CIP(ptr, start, length) \
+ for (i = start; i < (start) + (length); i += 4) \
+ if (!IS_INTRA(-1, i)) \
+ AV_WN4P(&ptr[i], a); \
+ else \
+ a = PIXEL_SPLAT_X4(ptr[i + 3])
+
+ HEVCLocalContext *lc = s->HEVClc;
int i;
int hshift = s->sps->hshift[c_idx];
int vshift = s->sps->vshift[c_idx];
int size = (1 << log2_size);
- int size_in_luma = size << hshift;
- int size_in_tbs = size_in_luma >> s->sps->log2_min_tb_size;
+ int size_in_luma_h = size << hshift;
+ int size_in_tbs_h = size_in_luma_h >> s->sps->log2_min_tb_size;
+ int size_in_luma_v = size << vshift;
+ int size_in_tbs_v = size_in_luma_v >> s->sps->log2_min_tb_size;
int x = x0 >> hshift;
int y = y0 >> vshift;
- int x_tb = x0 >> s->sps->log2_min_tb_size;
- int y_tb = y0 >> s->sps->log2_min_tb_size;
+ int x_tb = (x0 >> s->sps->log2_min_tb_size) & s->sps->tb_mask;
+ int y_tb = (y0 >> s->sps->log2_min_tb_size) & s->sps->tb_mask;
+
int cur_tb_addr = MIN_TB_ADDR_ZS(x_tb, y_tb);
ptrdiff_t stride = s->frame->linesize[c_idx] / sizeof(pixel);
@@ -86,87 +91,77 @@ do { \
int min_pu_width = s->sps->min_pu_width;
- enum IntraPredMode mode = c_idx ? lc->pu.intra_pred_mode_c :
- lc->tu.cur_intra_pred_mode;
-
- pixel left_array[2 * MAX_TB_SIZE + 1];
- pixel filtered_left_array[2 * MAX_TB_SIZE + 1];
- pixel top_array[2 * MAX_TB_SIZE + 1];
- pixel filtered_top_array[2 * MAX_TB_SIZE + 1];
-
- pixel *left = left_array + 1;
- pixel *top = top_array + 1;
- pixel *filtered_left = filtered_left_array + 1;
- pixel *filtered_top = filtered_top_array + 1;
-
- int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS(x_tb - 1, y_tb + size_in_tbs);
+ enum IntraPredMode mode = c_idx ? lc->tu.intra_pred_mode_c :
+ lc->tu.intra_pred_mode;
+ pixel4 a;
+ pixel left_array[2 * MAX_TB_SIZE + 1];
+ pixel filtered_left_array[2 * MAX_TB_SIZE + 1];
+ pixel top_array[2 * MAX_TB_SIZE + 1];
+ pixel filtered_top_array[2 * MAX_TB_SIZE + 1];
+
+ pixel *left = left_array + 1;
+ pixel *top = top_array + 1;
+ pixel *filtered_left = filtered_left_array + 1;
+ pixel *filtered_top = filtered_top_array + 1;
+ int cand_bottom_left = lc->na.cand_bottom_left && cur_tb_addr > MIN_TB_ADDR_ZS( x_tb - 1, (y_tb + size_in_tbs_v) & s->sps->tb_mask);
int cand_left = lc->na.cand_left;
int cand_up_left = lc->na.cand_up_left;
int cand_up = lc->na.cand_up;
- int cand_up_right = lc->na.cand_up_right && cur_tb_addr > MIN_TB_ADDR_ZS(x_tb + size_in_tbs, y_tb - 1);
+ int cand_up_right = lc->na.cand_up_right && cur_tb_addr > MIN_TB_ADDR_ZS((x_tb + size_in_tbs_h) & s->sps->tb_mask, y_tb - 1);
- int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma, s->sps->height) -
- (y0 + size_in_luma)) >> vshift;
- int top_right_size = (FFMIN(x0 + 2 * size_in_luma, s->sps->width) -
- (x0 + size_in_luma)) >> hshift;
+ int bottom_left_size = (FFMIN(y0 + 2 * size_in_luma_v, s->sps->height) -
+ (y0 + size_in_luma_v)) >> vshift;
+ int top_right_size = (FFMIN(x0 + 2 * size_in_luma_h, s->sps->width) -
+ (x0 + size_in_luma_h)) >> hshift;
if (s->pps->constrained_intra_pred_flag == 1) {
- int size_in_luma_pu = PU(size_in_luma);
- int on_pu_edge_x = !(x0 & ((1 << s->sps->log2_min_pu_size) - 1));
- int on_pu_edge_y = !(y0 & ((1 << s->sps->log2_min_pu_size) - 1));
- if (!size_in_luma_pu)
- size_in_luma_pu++;
+ 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->sps->log2_min_pu_size);
+ int on_pu_edge_y = !av_mod_uintp2(y0, s->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);
- int max = FFMIN(size_in_luma_pu, s->sps->min_pu_height - y_bottom_pu);
+ int y_bottom_pu = PU(y0 + size_in_luma_v);
+ int max = FFMIN(size_in_luma_pu_v, s->sps->min_pu_height - y_bottom_pu);
cand_bottom_left = 0;
- for (i = 0; i < max; i++)
- cand_bottom_left |= MVF(x_left_pu, y_bottom_pu + i).is_intra;
+ for (i = 0; i < max; i += 2)
+ cand_bottom_left |= (MVF(x_left_pu, y_bottom_pu + i).pred_flag == PF_INTRA);
}
if (cand_left == 1 && on_pu_edge_x) {
int x_left_pu = PU(x0 - 1);
int y_left_pu = PU(y0);
- int max = FFMIN(size_in_luma_pu, s->sps->min_pu_height - y_left_pu);
+ int max = FFMIN(size_in_luma_pu_v, s->sps->min_pu_height - y_left_pu);
cand_left = 0;
- for (i = 0; i < max; i++)
- cand_left |= MVF(x_left_pu, y_left_pu + i).is_intra;
+ for (i = 0; i < max; i += 2)
+ cand_left |= (MVF(x_left_pu, y_left_pu + i).pred_flag == PF_INTRA);
}
if (cand_up_left == 1) {
int x_left_pu = PU(x0 - 1);
int y_top_pu = PU(y0 - 1);
- cand_up_left = MVF(x_left_pu, y_top_pu).is_intra;
+ cand_up_left = MVF(x_left_pu, y_top_pu).pred_flag == PF_INTRA;
}
if (cand_up == 1 && on_pu_edge_y) {
int x_top_pu = PU(x0);
int y_top_pu = PU(y0 - 1);
- int max = FFMIN(size_in_luma_pu, s->sps->min_pu_width - x_top_pu);
+ int max = FFMIN(size_in_luma_pu_h, s->sps->min_pu_width - x_top_pu);
cand_up = 0;
- for (i = 0; i < max; i++)
- cand_up |= MVF(x_top_pu + i, y_top_pu).is_intra;
+ for (i = 0; i < max; i += 2)
+ cand_up |= (MVF(x_top_pu + i, y_top_pu).pred_flag == PF_INTRA);
}
if (cand_up_right == 1 && on_pu_edge_y) {
int y_top_pu = PU(y0 - 1);
- int x_right_pu = PU(x0 + size_in_luma);
- int max = FFMIN(size_in_luma_pu, s->sps->min_pu_width - x_right_pu);
+ int x_right_pu = PU(x0 + size_in_luma_h);
+ int max = FFMIN(size_in_luma_pu_h, s->sps->min_pu_width - x_right_pu);
cand_up_right = 0;
- for (i = 0; i < max; i++)
- cand_up_right |= MVF(x_right_pu + i, y_top_pu).is_intra;
+ for (i = 0; i < max; i += 2)
+ cand_up_right |= (MVF(x_right_pu + i, y_top_pu).pred_flag == PF_INTRA);
}
- for (i = 0; i < 2 * MAX_TB_SIZE; i++) {
- left[i] = 128;
- top[i] = 128;
- }
- }
- if (cand_bottom_left) {
- for (i = size; i < size + bottom_left_size; i++)
- left[i] = POS(-1, i);
- EXTEND(left + size + bottom_left_size, POS(-1, size + bottom_left_size - 1),
- size - bottom_left_size);
+ memset(left, 128, 2 * MAX_TB_SIZE*sizeof(pixel));
+ memset(top , 128, 2 * MAX_TB_SIZE*sizeof(pixel));
+ top[-1] = 128;
}
- if (cand_left)
- for (i = size - 1; i >= 0; i--)
- left[i] = POS(-1, i);
if (cand_up_left) {
left[-1] = POS(-1, -1);
top[-1] = left[-1];
@@ -178,6 +173,15 @@ do { \
EXTEND(top + size + top_right_size, POS(size + top_right_size - 1, -1),
size - top_right_size);
}
+ if (cand_left)
+ for (i = 0; i < size; i++)
+ left[i] = POS(-1, i);
+ if (cand_bottom_left) {
+ for (i = size; i < size + bottom_left_size; i++)
+ left[i] = POS(-1, i);
+ EXTEND(left + size + bottom_left_size, POS(-1, size + bottom_left_size - 1),
+ size - bottom_left_size);
+ }
if (s->pps->constrained_intra_pred_flag == 1) {
if (cand_bottom_left || cand_left || cand_up_left || cand_up || cand_up_right) {
@@ -203,7 +207,6 @@ do { \
j++;
EXTEND_LEFT_CIP(top, j, j + 1);
left[-1] = top[-1];
- j = 0;
}
} else {
j = 0;
@@ -217,24 +220,30 @@ do { \
top[-1] = top[0];
}
left[-1] = top[-1];
- j = 0;
}
+ left[-1] = top[-1];
if (cand_bottom_left || cand_left) {
- EXTEND_DOWN_CIP(left, j, size_max_y - j);
+ a = PIXEL_SPLAT_X4(left[-1]);
+ EXTEND_DOWN_CIP(left, 0, size_max_y);
}
if (!cand_left)
EXTEND(left, left[-1], size);
if (!cand_bottom_left)
EXTEND(left + size, left[size - 1], size);
if (x0 != 0 && y0 != 0) {
+ a = PIXEL_SPLAT_X4(left[size_max_y - 1]);
EXTEND_UP_CIP(left, size_max_y - 1, size_max_y);
+ if (!IS_INTRA(-1, - 1))
+ left[-1] = left[0];
} else if (x0 == 0) {
- EXTEND_UP_CIP_0(left, size_max_y - 1, size_max_y);
+ EXTEND(left, 0, size_max_y);
} else {
- EXTEND_UP_CIP(left, size_max_y - 1, size_max_y - 1);
+ a = PIXEL_SPLAT_X4(left[size_max_y - 1]);
+ EXTEND_UP_CIP(left, size_max_y - 1, size_max_y);
}
top[-1] = left[-1];
if (y0 != 0) {
+ a = PIXEL_SPLAT_X4(left[-1]);
EXTEND_RIGHT_CIP(top, 0, size_max_x);
}
}
@@ -278,40 +287,42 @@ do { \
top[-1] = left[-1];
// Filtering process
- if (c_idx == 0 && mode != INTRA_DC && size != 4) {
- int intra_hor_ver_dist_thresh[] = { 7, 1, 0 };
- int min_dist_vert_hor = FFMIN(FFABS((int)mode - 26),
- FFABS((int)mode - 10));
- if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) {
- int threshold = 1 << (BIT_DEPTH - 5);
- if (s->sps->sps_strong_intra_smoothing_enable_flag &&
- log2_size == 5 &&
- FFABS(top[-1] + top[63] - 2 * top[31]) < threshold &&
- FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) {
- // We can't just overwrite values in top because it could be
- // a pointer into src
- filtered_top[-1] = top[-1];
- filtered_top[63] = top[63];
- for (i = 0; i < 63; i++)
- filtered_top[i] = ((64 - (i + 1)) * top[-1] +
- (i + 1) * top[63] + 32) >> 6;
- for (i = 0; i < 63; i++)
- left[i] = ((64 - (i + 1)) * left[-1] +
- (i + 1) * left[63] + 32) >> 6;
- top = filtered_top;
- } else {
- filtered_left[2 * size - 1] = left[2 * size - 1];
- filtered_top[2 * size - 1] = top[2 * size - 1];
- for (i = 2 * size - 2; i >= 0; i--)
- filtered_left[i] = (left[i + 1] + 2 * left[i] +
- left[i - 1] + 2) >> 2;
- filtered_top[-1] =
- filtered_left[-1] = (left[0] + 2 * left[-1] + top[0] + 2) >> 2;
- for (i = 2 * size - 2; i >= 0; i--)
- filtered_top[i] = (top[i + 1] + 2 * top[i] +
- top[i - 1] + 2) >> 2;
- left = filtered_left;
- top = filtered_top;
+ if (!s->sps->intra_smoothing_disabled_flag && (c_idx == 0 || s->sps->chroma_format_idc == 3)) {
+ if (mode != INTRA_DC && size != 4){
+ int intra_hor_ver_dist_thresh[] = { 7, 1, 0 };
+ int min_dist_vert_hor = FFMIN(FFABS((int)(mode - 26U)),
+ FFABS((int)(mode - 10U)));
+ if (min_dist_vert_hor > intra_hor_ver_dist_thresh[log2_size - 3]) {
+ int threshold = 1 << (BIT_DEPTH - 5);
+ if (s->sps->sps_strong_intra_smoothing_enable_flag && c_idx == 0 &&
+ log2_size == 5 &&
+ FFABS(top[-1] + top[63] - 2 * top[31]) < threshold &&
+ FFABS(left[-1] + left[63] - 2 * left[31]) < threshold) {
+ // We can't just overwrite values in top because it could be
+ // a pointer into src
+ filtered_top[-1] = top[-1];
+ filtered_top[63] = top[63];
+ for (i = 0; i < 63; i++)
+ filtered_top[i] = ((64 - (i + 1)) * top[-1] +
+ (i + 1) * top[63] + 32) >> 6;
+ for (i = 0; i < 63; i++)
+ left[i] = ((64 - (i + 1)) * left[-1] +
+ (i + 1) * left[63] + 32) >> 6;
+ top = filtered_top;
+ } else {
+ filtered_left[2 * size - 1] = left[2 * size - 1];
+ filtered_top[2 * size - 1] = top[2 * size - 1];
+ for (i = 2 * size - 2; i >= 0; i--)
+ filtered_left[i] = (left[i + 1] + 2 * left[i] +
+ left[i - 1] + 2) >> 2;
+ filtered_top[-1] =
+ filtered_left[-1] = (left[0] + 2 * left[-1] + top[0] + 2) >> 2;
+ for (i = 2 * size - 2; i >= 0; i--)
+ filtered_top[i] = (top[i + 1] + 2 * top[i] +
+ top[i - 1] + 2) >> 2;
+ left = filtered_left;
+ top = filtered_top;
+ }
}
}
}
@@ -394,8 +405,8 @@ static void FUNC(pred_dc)(uint8_t *_src, const uint8_t *_top,
a = PIXEL_SPLAT_X4(dc);
for (i = 0; i < size; i++)
- for (j = 0; j < size / 4; j++)
- AV_WN4PA(&POS(j * 4, i), a);
+ for (j = 0; j < size; j+=4)
+ AV_WN4P(&POS(j, i), a);
if (c_idx == 0 && size < 32) {
POS(0, 0) = (left[0] + 2 * dc + top[0] + 2) >> 2;
@@ -427,7 +438,7 @@ static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
};
int angle = intra_pred_angle[mode - 2];
- pixel ref_array[3 * MAX_TB_SIZE + 1];
+ pixel ref_array[3 * MAX_TB_SIZE + 4];
pixel *ref_tmp = ref_array + size;
const pixel *ref;
int last = (size * angle) >> 5;
@@ -435,8 +446,8 @@ static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
if (mode >= 18) {
ref = top - 1;
if (angle < 0 && last < -1) {
- for (x = 0; x <= size; x++)
- ref_tmp[x] = top[x - 1];
+ for (x = 0; x <= size; x += 4)
+ AV_WN4P(&ref_tmp[x], AV_RN4P(&top[x - 1]));
for (x = last; x <= -1; x++)
ref_tmp[x] = left[-1 + ((x * inv_angle[mode - 11] + 128) >> 8)];
ref = ref_tmp;
@@ -446,13 +457,19 @@ static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
int idx = ((y + 1) * angle) >> 5;
int fact = ((y + 1) * angle) & 31;
if (fact) {
- for (x = 0; x < size; x++) {
- POS(x, y) = ((32 - fact) * ref[x + idx + 1] +
- fact * ref[x + idx + 2] + 16) >> 5;
+ for (x = 0; x < size; x += 4) {
+ POS(x , y) = ((32 - fact) * ref[x + idx + 1] +
+ fact * ref[x + idx + 2] + 16) >> 5;
+ POS(x + 1, y) = ((32 - fact) * ref[x + 1 + idx + 1] +
+ fact * ref[x + 1 + idx + 2] + 16) >> 5;
+ POS(x + 2, y) = ((32 - fact) * ref[x + 2 + idx + 1] +
+ fact * ref[x + 2 + idx + 2] + 16) >> 5;
+ POS(x + 3, y) = ((32 - fact) * ref[x + 3 + idx + 1] +
+ fact * ref[x + 3 + idx + 2] + 16) >> 5;
}
} else {
- for (x = 0; x < size; x++)
- POS(x, y) = ref[x + idx + 1];
+ for (x = 0; x < size; x += 4)
+ AV_WN4P(&POS(x, y), AV_RN4P(&ref[x + idx + 1]));
}
}
if (mode == 26 && c_idx == 0 && size < 32) {
@@ -462,8 +479,8 @@ static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
} else {
ref = left - 1;
if (angle < 0 && last < -1) {
- for (x = 0; x <= size; x++)
- ref_tmp[x] = left[x - 1];
+ for (x = 0; x <= size; x += 4)
+ AV_WN4P(&ref_tmp[x], AV_RN4P(&left[x - 1]));
for (x = last; x <= -1; x++)
ref_tmp[x] = top[-1 + ((x * inv_angle[mode - 11] + 128) >> 8)];
ref = ref_tmp;
@@ -483,8 +500,12 @@ static av_always_inline void FUNC(pred_angular)(uint8_t *_src,
}
}
if (mode == 10 && c_idx == 0 && size < 32) {
- for (x = 0; x < size; x++)
- POS(x, 0) = av_clip_pixel(left[0] + ((top[x] - top[-1]) >> 1));
+ for (x = 0; x < size; x += 4) {
+ POS(x, 0) = av_clip_pixel(left[0] + ((top[x ] - top[-1]) >> 1));
+ POS(x + 1, 0) = av_clip_pixel(left[0] + ((top[x + 1] - top[-1]) >> 1));
+ POS(x + 2, 0) = av_clip_pixel(left[0] + ((top[x + 2] - top[-1]) >> 1));
+ POS(x + 3, 0) = av_clip_pixel(left[0] + ((top[x + 3] - top[-1]) >> 1));
+ }
}
}
}
diff --git a/libavcodec/hnm4video.c b/libavcodec/hnm4video.c
index 700504d87c..31995bc75c 100644
--- a/libavcodec/hnm4video.c
+++ b/libavcodec/hnm4video.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 David Kment
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -79,7 +79,7 @@ static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src,
if (getbit(&gb, &bitbuf, &bits)) {
if (writeoffset >= hnm->width * hnm->height) {
av_log(avctx, AV_LOG_ERROR,
- "Attempting to write out of bounds");
+ "Attempting to write out of bounds\n");
break;
}
hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
@@ -100,11 +100,11 @@ static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src,
count += 2;
offset += writeoffset;
if (offset < 0 || offset + count >= hnm->width * hnm->height) {
- av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
break;
} else if (writeoffset + count >= hnm->width * hnm->height) {
av_log(avctx, AV_LOG_ERROR,
- "Attempting to write out of bounds");
+ "Attempting to write out of bounds\n");
break;
}
while (count--) {
@@ -147,7 +147,8 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s
{
Hnm4VideoContext *hnm = avctx->priv_data;
GetByteContext gb;
- uint32_t writeoffset = 0, count, left, offset;
+ uint32_t writeoffset = 0;
+ int count, left, offset;
uint8_t tag, previous, backline, backward, swap;
bytestream2_init(&gb, src, size);
@@ -157,7 +158,12 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s
if (count == 0) {
tag = bytestream2_get_byte(&gb) & 0xE0;
tag = tag >> 5;
+
if (tag == 0) {
+ if (writeoffset + 2 > hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
+ break;
+ }
hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
} else if (tag == 1) {
@@ -168,6 +174,10 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s
writeoffset += count;
} else if (tag == 3) {
count = bytestream2_get_byte(&gb) * 2;
+ if (writeoffset + count > hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
+ break;
+ }
while (count > 0) {
hnm->current[writeoffset++] = bytestream2_peek_byte(&gb);
count--;
@@ -176,6 +186,10 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s
} else {
break;
}
+ if (writeoffset > hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
+ break;
+ }
} else {
previous = bytestream2_peek_byte(&gb) & 0x20;
backline = bytestream2_peek_byte(&gb) & 0x40;
@@ -188,17 +202,28 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s
left = count;
- if (!backward && offset + count >= hnm->width * hnm->height) {
- av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
+ if (!backward && offset + 2*count > hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
break;
- } else if (backward && offset >= hnm->width * hnm->height) {
- av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
+ } else if (backward && offset + 1 >= hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
break;
- } else if (writeoffset + count >= hnm->width * hnm->height) {
+ } else if (writeoffset + 2*count > hnm->width * hnm->height) {
av_log(avctx, AV_LOG_ERROR,
- "Attempting to write out of bounds");
+ "Attempting to write out of bounds\n");
break;
}
+ if(backward) {
+ if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) {
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
+ break;
+ }
+ } else {
+ if (offset < (!!backline)*(2 * hnm->width - 1)) {
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
+ break;
+ }
+ }
if (previous) {
while (left > 0) {
@@ -263,6 +288,10 @@ static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src,
if (tag == 0) {
writeoffset += bytestream2_get_byte(&gb);
} else if (tag == 1) {
+ if (writeoffset + hnm->width >= hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
+ break;
+ }
hnm->current[writeoffset] = bytestream2_get_byte(&gb);
hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb);
writeoffset++;
@@ -271,6 +300,10 @@ static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src,
} else if (tag == 3) {
break;
}
+ if (writeoffset > hnm->width * hnm->height) {
+ av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
+ break;
+ }
} else {
delta = bytestream2_peek_byte(&gb) & 0x80;
previous = bytestream2_peek_byte(&gb) & 0x40;
@@ -279,14 +312,19 @@ static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src,
offset = writeoffset;
offset += bytestream2_get_le16(&gb);
- if (delta)
+ if (delta) {
+ if (offset < 0x10000) {
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
+ break;
+ }
offset -= 0x10000;
+ }
if (offset + hnm->width + count >= hnm->width * hnm->height) {
- av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
+ av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
break;
} else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) {
- av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds");
+ av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n");
break;
}
@@ -360,17 +398,23 @@ static int hnm_decode_frame(AVCodecContext *avctx, void *data,
int ret;
uint16_t chunk_id;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if (avpkt->size < 8) {
+ av_log(avctx, AV_LOG_ERROR, "packet too small\n");
+ return AVERROR_INVALIDDATA;
}
chunk_id = AV_RL16(avpkt->data + 4);
if (chunk_id == HNM4_CHUNK_ID_PL) {
hnm_update_palette(avctx, avpkt->data, avpkt->size);
- frame->palette_has_changed = 1;
} else if (chunk_id == HNM4_CHUNK_ID_IZ) {
+ if (avpkt->size < 12) {
+ av_log(avctx, AV_LOG_ERROR, "packet too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
if (hnm->version == 0x4a)
@@ -383,6 +427,9 @@ static int hnm_decode_frame(AVCodecContext *avctx, void *data,
memcpy(frame->data[1], hnm->palette, 256 * 4);
*got_frame = 1;
} else if (chunk_id == HNM4_CHUNK_ID_IU) {
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
if (hnm->version == 0x4a) {
decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
@@ -427,7 +474,9 @@ static av_cold int hnm_decode_init(AVCodecContext *avctx)
hnm->buffer2 = av_mallocz(avctx->width * avctx->height);
hnm->processed = av_mallocz(avctx->width * avctx->height);
- if (!hnm->buffer1 || !hnm->buffer2 || !hnm->processed) {
+ if ( !hnm->buffer1 || !hnm->buffer2 || !hnm->processed
+ || avctx->width * avctx->height == 0
+ || avctx->height % 2) {
av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
av_freep(&hnm->buffer1);
av_freep(&hnm->buffer2);
diff --git a/libavcodec/hpel_template.c b/libavcodec/hpel_template.c
index 81d3892e56..fccfe7610f 100644
--- a/libavcodec/hpel_template.c
+++ b/libavcodec/hpel_template.c
@@ -2,20 +2,20 @@
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hpeldsp.c b/libavcodec/hpeldsp.c
index 25694c5940..7763760eb3 100644
--- a/libavcodec/hpeldsp.c
+++ b/libavcodec/hpeldsp.c
@@ -5,20 +5,20 @@
*
* gmc & q-pel & 32/64 bit based MC by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -357,6 +357,8 @@ av_cold void ff_hpeldsp_init(HpelDSPContext *c, int flags)
if (ARCH_AARCH64)
ff_hpeldsp_init_aarch64(c, flags);
+ if (ARCH_ALPHA)
+ ff_hpeldsp_init_alpha(c, flags);
if (ARCH_ARM)
ff_hpeldsp_init_arm(c, flags);
if (ARCH_PPC)
diff --git a/libavcodec/hpeldsp.h b/libavcodec/hpeldsp.h
index d037cba14e..07c293ae78 100644
--- a/libavcodec/hpeldsp.h
+++ b/libavcodec/hpeldsp.h
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -95,6 +95,7 @@ typedef struct HpelDSPContext {
void ff_hpeldsp_init(HpelDSPContext *c, int flags);
void ff_hpeldsp_init_aarch64(HpelDSPContext *c, int flags);
+void ff_hpeldsp_init_alpha(HpelDSPContext *c, int flags);
void ff_hpeldsp_init_arm(HpelDSPContext *c, int flags);
void ff_hpeldsp_init_ppc(HpelDSPContext *c, int flags);
void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags);
diff --git a/libavcodec/hq_hqa.c b/libavcodec/hq_hqa.c
index ae378e6524..7d14e2755b 100644
--- a/libavcodec/hq_hqa.c
+++ b/libavcodec/hq_hqa.c
@@ -1,20 +1,20 @@
/*
* Canopus HQ/HQA decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -137,10 +137,8 @@ static int hq_decode_frame(HQContext *ctx, AVFrame *pic,
ctx->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
ret = ff_get_buffer(ctx->avctx, pic, 0);
- if (ret < 0) {
- av_log(ctx->avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+ if (ret < 0)
return ret;
- }
/* Offsets are stored from CUV position, so adjust them accordingly. */
for (i = 0; i < profile->num_slices + 1; i++)
@@ -267,10 +265,8 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, size_t data_size)
}
ret = ff_get_buffer(ctx->avctx, pic, 0);
- if (ret < 0) {
- av_log(ctx->avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+ if (ret < 0)
return ret;
- }
/* Offsets are stored from HQA1 position, so adjust them accordingly. */
for (i = 0; i < num_slices + 1; i++)
diff --git a/libavcodec/hq_hqa.h b/libavcodec/hq_hqa.h
index 6bd858ddf2..4286dd0752 100644
--- a/libavcodec/hq_hqa.h
+++ b/libavcodec/hq_hqa.h
@@ -1,20 +1,20 @@
/*
* Canopus HQ/HQA decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hq_hqadata.c b/libavcodec/hq_hqadata.c
index 23fefc11b0..ae9231aa02 100644
--- a/libavcodec/hq_hqadata.c
+++ b/libavcodec/hq_hqadata.c
@@ -1,20 +1,20 @@
/*
* Canopus HQ/HQA decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hq_hqadsp.c b/libavcodec/hq_hqadsp.c
index 93fc06709b..db1ea2e246 100644
--- a/libavcodec/hq_hqadsp.c
+++ b/libavcodec/hq_hqadsp.c
@@ -1,20 +1,20 @@
/*
* Canopus HQ/HQA decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hq_hqadsp.h b/libavcodec/hq_hqadsp.h
index 22b1e6145c..420ed92f76 100644
--- a/libavcodec/hq_hqadsp.h
+++ b/libavcodec/hq_hqadsp.h
@@ -1,20 +1,20 @@
/*
* Canopus HQ/HQA decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hqx.c b/libavcodec/hqx.c
index 11b872cbb3..44016ac34a 100644
--- a/libavcodec/hqx.c
+++ b/libavcodec/hqx.c
@@ -1,20 +1,20 @@
/*
* Canopus HQX decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -458,7 +458,7 @@ static int hqx_decode_frame(AVCodecContext *avctx, void *data,
}
ret = av_image_check_size(ctx->width, ctx->height, 0, avctx);
if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Invalid stored dimenstions %dx%d.\n",
+ av_log(avctx, AV_LOG_ERROR, "Invalid stored dimensions %dx%d.\n",
ctx->width, ctx->height);
return AVERROR_INVALIDDATA;
}
@@ -492,10 +492,8 @@ static int hqx_decode_frame(AVCodecContext *avctx, void *data,
}
ret = ff_get_buffer(avctx, ctx->pic, 0);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
+ if (ret < 0)
return ret;
- }
avctx->execute2(avctx, decode_slice_thread, NULL, NULL, 16);
diff --git a/libavcodec/hqx.h b/libavcodec/hqx.h
index 7f329712fd..42d382de1f 100644
--- a/libavcodec/hqx.h
+++ b/libavcodec/hqx.h
@@ -1,20 +1,20 @@
/*
* Canopus HQX decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hqxdsp.c b/libavcodec/hqxdsp.c
index 2a02299a29..feff9c0b68 100644
--- a/libavcodec/hqxdsp.c
+++ b/libavcodec/hqxdsp.c
@@ -1,20 +1,20 @@
/*
* HQX DSP routines
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -118,7 +118,7 @@ static void hqx_idct_put(uint16_t *dst, ptrdiff_t stride,
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
- int v = av_clip(block[j + i * 8] + 0x800, 0, 0xFFF);
+ int v = av_clip_uintp2(block[j + i * 8] + 0x800, 12);
dst[j] = (v << 4) | (v >> 8);
}
dst += stride >> 1;
diff --git a/libavcodec/hqxdsp.h b/libavcodec/hqxdsp.h
index 163c1f8ab2..16a42cc2b5 100644
--- a/libavcodec/hqxdsp.h
+++ b/libavcodec/hqxdsp.h
@@ -1,20 +1,20 @@
/*
* HQX DSP routines
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/hqxvlc.c b/libavcodec/hqxvlc.c
index d185e861da..06a8073661 100644
--- a/libavcodec/hqxvlc.c
+++ b/libavcodec/hqxvlc.c
@@ -1,20 +1,20 @@
/*
* Canopus HQX decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/huffman.c b/libavcodec/huffman.c
index eb5f01fcf9..c771bcfe08 100644
--- a/libavcodec/huffman.c
+++ b/libavcodec/huffman.c
@@ -2,20 +2,20 @@
* Copyright (c) 2006 Konstantin Shishkov
* Copyright (c) 2007 Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,18 +52,31 @@ static void heap_sift(HeapElem *h, int root, int size)
}
}
-void ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats)
+int ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats, int stats_size, int skip0)
{
- HeapElem h[256];
- int up[2*256];
- int len[2*256];
+ HeapElem *h = av_malloc_array(sizeof(*h), stats_size);
+ int *up = av_malloc_array(sizeof(*up) * 2, stats_size);
+ uint8_t *len = av_malloc_array(sizeof(*len) * 2, stats_size);
+ uint16_t *map= av_malloc_array(sizeof(*map), stats_size);
int offset, i, next;
- int size = 256;
+ int size = 0;
+ int ret = 0;
+
+ if (!h || !up || !len || !map) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ for (i = 0; i<stats_size; i++) {
+ dst[i] = 255;
+ if (stats[i] || !skip0)
+ map[size++] = i;
+ }
for (offset = 1; ; offset <<= 1) {
for (i=0; i < size; i++) {
h[i].name = i;
- h[i].val = (stats[i] << 8) + offset;
+ h[i].val = (stats[map[i]] << 14) + offset;
}
for (i = size / 2 - 1; i >= 0; i--)
heap_sift(h, i, size);
@@ -84,11 +97,17 @@ void ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats)
for (i = 2 * size - 3; i >= size; i--)
len[i] = len[up[i]] + 1;
for (i = 0; i < size; i++) {
- dst[i] = len[up[i]] + 1;
- if (dst[i] >= 32) break;
+ dst[map[i]] = len[up[i]] + 1;
+ if (dst[map[i]] >= 32) break;
}
if (i==size) break;
}
+end:
+ av_free(h);
+ av_free(up);
+ av_free(len);
+ av_free(map);
+ return ret;
}
static void get_tree_codes(uint32_t *bits, int16_t *lens, uint8_t *xlat,
@@ -114,7 +133,7 @@ static void get_tree_codes(uint32_t *bits, int16_t *lens, uint8_t *xlat,
}
}
-static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags)
+static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags, int nb_bits)
{
int no_zero_count = !(flags & FF_HUFFMAN_FLAG_ZERO_COUNT);
uint32_t bits[256];
@@ -124,7 +143,7 @@ static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags)
get_tree_codes(bits, lens, xlat, nodes, head, 0, 0,
&pos, no_zero_count);
- return ff_init_vlc_sparse(vlc, 9, pos, lens, 2, 2, bits, 4, 4, xlat, 1, 1, 0);
+ return ff_init_vlc_sparse(vlc, nb_bits, pos, lens, 2, 2, bits, 4, 4, xlat, 1, 1, 0);
}
@@ -132,7 +151,7 @@ static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags)
* nodes size must be 2*nb_codes
* first nb_codes nodes.count must be set
*/
-int ff_huff_build_tree(AVCodecContext *avctx, VLC *vlc, int nb_codes,
+int ff_huff_build_tree(AVCodecContext *avctx, VLC *vlc, int nb_codes, int nb_bits,
Node *nodes, HuffCmp cmp, int flags)
{
int i, j;
@@ -155,21 +174,22 @@ int ff_huff_build_tree(AVCodecContext *avctx, VLC *vlc, int nb_codes,
cur_node = nb_codes;
nodes[nb_codes*2-1].count = 0;
for (i = 0; i < nb_codes * 2 - 1; i += 2) {
- nodes[cur_node].sym = HNODE;
- nodes[cur_node].count = nodes[i].count + nodes[i + 1].count;
- nodes[cur_node].n0 = i;
- for (j = cur_node; j > 0; j--) {
- if (nodes[j].count > nodes[j - 1].count ||
- (nodes[j].count == nodes[j - 1].count &&
- (!(flags & FF_HUFFMAN_FLAG_HNODE_FIRST) ||
- nodes[j].n0 == j - 1 || nodes[j].n0 == j - 2 ||
- (nodes[j].sym!=HNODE && nodes[j-1].sym!=HNODE))))
+ uint32_t cur_count = nodes[i].count + nodes[i+1].count;
+ // find correct place to insert new node, and
+ // make space for the new node while at it
+ for(j = cur_node; j > i + 2; j--){
+ if(cur_count > nodes[j-1].count ||
+ (cur_count == nodes[j-1].count &&
+ !(flags & FF_HUFFMAN_FLAG_HNODE_FIRST)))
break;
- FFSWAP(Node, nodes[j], nodes[j - 1]);
+ nodes[j] = nodes[j - 1];
}
+ nodes[j].sym = HNODE;
+ nodes[j].count = cur_count;
+ nodes[j].n0 = i;
cur_node++;
}
- if (build_huff_tree(vlc, nodes, nb_codes * 2 - 2, flags) < 0) {
+ if (build_huff_tree(vlc, nodes, nb_codes * 2 - 2, flags, nb_bits) < 0) {
av_log(avctx, AV_LOG_ERROR, "Error building tree\n");
return -1;
}
diff --git a/libavcodec/huffman.h b/libavcodec/huffman.h
index 043e6e3991..6ab23ae216 100644
--- a/libavcodec/huffman.h
+++ b/libavcodec/huffman.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,11 +37,12 @@ typedef struct Node {
#define FF_HUFFMAN_FLAG_HNODE_FIRST 0x01
#define FF_HUFFMAN_FLAG_ZERO_COUNT 0x02
+#define FF_HUFFMAN_BITS 10
typedef int (*HuffCmp)(const void *va, const void *vb);
-int ff_huff_build_tree(AVCodecContext *avctx, VLC *vlc, int nb_codes,
+int ff_huff_build_tree(AVCodecContext *avctx, VLC *vlc, int nb_codes, int nb_bits,
Node *nodes, HuffCmp cmp, int flags);
-void ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats);
+int ff_huff_gen_len_table(uint8_t *dst, const uint64_t *stats, int n, int skip0);
#endif /* AVCODEC_HUFFMAN_H */
diff --git a/libavcodec/huffyuv.c b/libavcodec/huffyuv.c
index da5c52f9a6..492155550f 100644
--- a/libavcodec/huffyuv.c
+++ b/libavcodec/huffyuv.c
@@ -1,25 +1,25 @@
/*
* huffyuv codec for libavcodec
*
- * Copyright (c) 2002-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2002-2014 Michael Niedermayer <michaelni@gmx.at>
*
* see http://www.pcisys.net/~melanson/codecs/huffyuv.txt for a description of
* the algorithm used
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,13 +36,13 @@
#include "bswapdsp.h"
#include "huffyuv.h"
-int ff_huffyuv_generate_bits_table(uint32_t *dst, const uint8_t *len_table)
+int ff_huffyuv_generate_bits_table(uint32_t *dst, const uint8_t *len_table, int n)
{
int len, index;
uint32_t bits = 0;
for (len = 32; len > 0; len--) {
- for (index = 0; index < 256; index++) {
+ for (index = 0; index < n; index++) {
if (len_table[index] == len)
dst[index] = bits++;
}
@@ -59,16 +59,11 @@ av_cold int ff_huffyuv_alloc_temp(HYuvContext *s)
{
int i;
- if (s->bitstream_bpp<24) {
- for (i=0; i<3; i++) {
- s->temp[i]= av_malloc(s->width + 16);
- if (!s->temp[i])
- return AVERROR(ENOMEM);
- }
- } else {
- s->temp[0]= av_mallocz(4*s->width + 16);
- if (!s->temp[0])
+ for (i=0; i<3; i++) {
+ s->temp[i]= av_malloc(4*s->width + 16);
+ if (!s->temp[i])
return AVERROR(ENOMEM);
+ s->temp16[i] = (uint16_t*)s->temp[i];
}
return 0;
}
@@ -81,17 +76,20 @@ av_cold void ff_huffyuv_common_init(AVCodecContext *avctx)
s->flags = avctx->flags;
ff_bswapdsp_init(&s->bdsp);
+ ff_llviddsp_init(&s->llviddsp, avctx);
s->width = avctx->width;
s->height = avctx->height;
- assert(s->width>0 && s->height>0);
+
+ av_assert1(s->width > 0 && s->height > 0);
}
-void ff_huffyuv_common_end(HYuvContext *s)
+av_cold void ff_huffyuv_common_end(HYuvContext *s)
{
int i;
for(i = 0; i < 3; i++) {
av_freep(&s->temp[i]);
+ s->temp16[i] = NULL;
}
}
diff --git a/libavcodec/huffyuv.h b/libavcodec/huffyuv.h
index aed153769a..c18247ed0f 100644
--- a/libavcodec/huffyuv.h
+++ b/libavcodec/huffyuv.h
@@ -1,23 +1,23 @@
/*
- * Copyright (c) 2002-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2002-2014 Michael Niedermayer <michaelni@gmx.at>
*
* see http://www.pcisys.net/~melanson/codecs/huffyuv.txt for a description of
* the algorithm used
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,20 +37,13 @@
#include "huffyuvdsp.h"
#include "huffyuvencdsp.h"
#include "put_bits.h"
+#include "lossless_videodsp.h"
-#define VLC_BITS 11
+#define VLC_BITS 12
-#if HAVE_BIGENDIAN
-#define B 3
-#define G 2
-#define R 1
-#define A 0
-#else
-#define B 0
-#define G 1
-#define R 2
-#define A 3
-#endif
+#define MAX_BITS 16
+#define MAX_N (1<<MAX_BITS)
+#define MAX_VLC_N 16384
typedef enum Predictor {
LEFT = 0,
@@ -59,6 +52,7 @@ typedef enum Predictor {
} Predictor;
typedef struct HYuvContext {
+ AVClass *class;
AVCodecContext *avctx;
Predictor predictor;
GetBitContext gb;
@@ -69,27 +63,38 @@ typedef struct HYuvContext {
int version;
int yuy2; //use yuy2 instead of 422P
int bgr32; //use bgr32 instead of bgr24
+ int bps;
+ int n; // 1<<bps
+ int vlc_n; // number of vlc codes (FFMIN(1<<bps, MAX_VLC_N))
+ int alpha;
+ int chroma;
+ int yuv;
+ int chroma_h_shift;
+ int chroma_v_shift;
int width, height;
int flags;
int context;
int picture_number;
int last_slice_end;
uint8_t *temp[3];
- uint64_t stats[3][256];
- uint8_t len[3][256];
- uint32_t bits[3][256];
+ uint16_t *temp16[3]; ///< identical to temp but 16bit type
+ uint64_t stats[4][MAX_VLC_N];
+ uint8_t len[4][MAX_VLC_N];
+ uint32_t bits[4][MAX_VLC_N];
uint32_t pix_bgr_map[1<<VLC_BITS];
- VLC vlc[6]; //Y,U,V,YY,YU,YV
+ VLC vlc[8]; //Y,U,V,A,YY,YU,YV,AA
uint8_t *bitstream_buffer;
unsigned int bitstream_buffer_size;
BswapDSPContext bdsp;
HuffYUVDSPContext hdsp;
HuffYUVEncDSPContext hencdsp;
+ LLVidDSPContext llviddsp;
+ int non_determ; // non-deterministic, multi-threaded encoder allowed
} HYuvContext;
void ff_huffyuv_common_init(AVCodecContext *s);
void ff_huffyuv_common_end(HYuvContext *s);
int ff_huffyuv_alloc_temp(HYuvContext *s);
-int ff_huffyuv_generate_bits_table(uint32_t *dst, const uint8_t *len_table);
+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 1ad81f7dd7..98c6128470 100644
--- a/libavcodec/huffyuvdec.c
+++ b/libavcodec/huffyuvdec.c
@@ -1,26 +1,28 @@
/*
* huffyuv decoder
*
- * Copyright (c) 2002-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2002-2014 Michael Niedermayer <michaelni@gmx.at>
*
* see http://www.pcisys.net/~melanson/codecs/huffyuv.txt for a description of
* the algorithm used
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * yuva, gray, 4:4:4, 4:1:1, 4:1:0 and >8 bit per sample support sponsored by NOA
*/
/**
@@ -28,17 +30,21 @@
* huffyuv decoder
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "avcodec.h"
#include "get_bits.h"
#include "huffyuv.h"
#include "huffyuvdsp.h"
#include "thread.h"
+#include "libavutil/pixdesc.h"
#define classic_shift_luma_table_size 42
static const unsigned char classic_shift_luma[classic_shift_luma_table_size + FF_INPUT_BUFFER_PADDING_SIZE] = {
34, 36, 35, 69, 135, 232, 9, 16, 10, 24, 11, 23, 12, 16, 13, 10,
14, 8, 15, 8, 16, 8, 17, 20, 16, 10, 207, 206, 205, 236, 11, 8,
- 10, 21, 9, 23, 8, 8, 199, 70, 69, 68, 0
+ 10, 21, 9, 23, 8, 8, 199, 70, 69, 68, 0,
+ 0,0,0,0,0,0,0,0,
};
#define classic_shift_chroma_table_size 59
@@ -46,7 +52,8 @@ static const unsigned char classic_shift_chroma[classic_shift_chroma_table_size
66, 36, 37, 38, 39, 40, 41, 75, 76, 77, 110, 239, 144, 81, 82, 83,
84, 85, 118, 183, 56, 57, 88, 89, 56, 89, 154, 57, 58, 57, 26, 141,
57, 56, 58, 57, 58, 57, 184, 119, 214, 245, 116, 83, 82, 49, 80, 79,
- 78, 77, 44, 75, 41, 40, 39, 38, 37, 36, 34, 0
+ 78, 77, 44, 75, 41, 40, 39, 38, 37, 36, 34, 0,
+ 0,0,0,0,0,0,0,0,
};
static const unsigned char classic_add_luma[256] = {
@@ -87,16 +94,16 @@ static const unsigned char classic_add_chroma[256] = {
6, 12, 8, 10, 7, 9, 6, 4, 6, 2, 2, 3, 3, 3, 3, 2,
};
-static int read_len_table(uint8_t *dst, GetBitContext *gb)
+static int read_len_table(uint8_t *dst, GetBitContext *gb, int n)
{
int i, val, repeat;
- for (i = 0; i < 256;) {
+ for (i = 0; i < n;) {
repeat = get_bits(gb, 3);
val = get_bits(gb, 5);
if (repeat == 0)
repeat = get_bits(gb, 8);
- if (i + repeat > 256 || get_bits_left(gb) < 0) {
+ if (i + repeat > n || get_bits_left(gb) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error reading huffman table\n");
return AVERROR_INVALIDDATA;
}
@@ -108,34 +115,43 @@ static int read_len_table(uint8_t *dst, GetBitContext *gb)
static int generate_joint_tables(HYuvContext *s)
{
- uint16_t symbols[1 << VLC_BITS];
- uint16_t bits[1 << VLC_BITS];
- uint8_t len[1 << VLC_BITS];
int ret;
+ uint16_t *symbols = av_mallocz(5 << VLC_BITS);
+ uint16_t *bits;
+ uint8_t *len;
+ if (!symbols)
+ return AVERROR(ENOMEM);
+ bits = symbols + (1 << VLC_BITS);
+ len = (uint8_t *)(bits + (1 << VLC_BITS));
- if (s->bitstream_bpp < 24) {
+ if (s->bitstream_bpp < 24 || s->version > 2) {
int p, i, y, u;
- for (p = 0; p < 3; p++) {
- for (i = y = 0; y < 256; y++) {
- int len0 = s->len[0][y];
+ for (p = 0; p < 4; p++) {
+ int p0 = s->version > 2 ? p : 0;
+ for (i = y = 0; y < s->vlc_n; y++) {
+ int len0 = s->len[p0][y];
int limit = VLC_BITS - len0;
- if (limit <= 0)
+ if (limit <= 0 || !len0)
+ continue;
+ if ((sign_extend(y, 8) & (s->vlc_n-1)) != y)
continue;
- for (u = 0; u < 256; u++) {
+ for (u = 0; u < s->vlc_n; u++) {
int len1 = s->len[p][u];
- if (len1 > limit)
+ if (len1 > limit || !len1)
continue;
+ if ((sign_extend(u, 8) & (s->vlc_n-1)) != u)
+ continue;
+ av_assert0(i < (1 << VLC_BITS));
len[i] = len0 + len1;
- bits[i] = (s->bits[0][y] << len1) + s->bits[p][u];
- symbols[i] = (y << 8) + u;
- if (symbols[i] != 0xffff) // reserved to mean "invalid"
+ bits[i] = (s->bits[p0][y] << len1) + s->bits[p][u];
+ symbols[i] = (y << 8) + (u & 0xFF);
i++;
}
}
- ff_free_vlc(&s->vlc[3 + p]);
- if ((ret = ff_init_vlc_sparse(&s->vlc[3 + p], VLC_BITS, i, len, 1, 1,
+ ff_free_vlc(&s->vlc[4 + p]);
+ if ((ret = ff_init_vlc_sparse(&s->vlc[4 + p], VLC_BITS, i, len, 1, 1,
bits, 2, 2, symbols, 2, 2, 0)) < 0)
- return ret;
+ goto out;
}
} else {
uint8_t (*map)[4] = (uint8_t(*)[4]) s->pix_bgr_map;
@@ -148,18 +164,19 @@ static int generate_joint_tables(HYuvContext *s)
for (i = 0, g = -16; g < 16; g++) {
int len0 = s->len[p0][g & 255];
int limit0 = VLC_BITS - len0;
- if (limit0 < 2)
+ if (limit0 < 2 || !len0)
continue;
for (b = -16; b < 16; b++) {
int len1 = s->len[p1][b & 255];
int limit1 = limit0 - len1;
- if (limit1 < 1)
+ if (limit1 < 1 || !len1)
continue;
code = (s->bits[p0][g & 255] << len1) + s->bits[p1][b & 255];
for (r = -16; r < 16; r++) {
int len2 = s->len[2][r & 255];
- if (len2 > limit1)
+ if (len2 > limit1 || !len2)
continue;
+ av_assert0(i < (1 << VLC_BITS));
len[i] = len0 + len1 + len2;
bits[i] = (code << len2) + s->bits[2][r & 255];
if (s->decorrelate) {
@@ -175,30 +192,37 @@ static int generate_joint_tables(HYuvContext *s)
}
}
}
- ff_free_vlc(&s->vlc[3]);
- if ((ret = init_vlc(&s->vlc[3], VLC_BITS, i, len, 1, 1,
+ ff_free_vlc(&s->vlc[4]);
+ if ((ret = init_vlc(&s->vlc[4], VLC_BITS, i, len, 1, 1,
bits, 2, 2, 0)) < 0)
- return ret;
+ goto out;
}
- return 0;
+ ret = 0;
+out:
+ av_freep(&symbols);
+ return ret;
}
static int read_huffman_tables(HYuvContext *s, const uint8_t *src, int length)
{
GetBitContext gb;
int i, ret;
+ int count = 3;
if ((ret = init_get_bits(&gb, src, length * 8)) < 0)
return ret;
- for (i = 0; i < 3; i++) {
- if ((ret = read_len_table(s->len[i], &gb)) < 0)
+ if (s->version > 2)
+ count = 1 + s->alpha + 2*s->chroma;
+
+ for (i = 0; i < count; i++) {
+ if ((ret = read_len_table(s->len[i], &gb, s->vlc_n)) < 0)
return ret;
- if ((ret = ff_huffyuv_generate_bits_table(s->bits[i], s->len[i])) < 0)
+ if ((ret = ff_huffyuv_generate_bits_table(s->bits[i], s->len[i], s->vlc_n)) < 0)
return ret;
ff_free_vlc(&s->vlc[i]);
- if ((ret = init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1,
- s->bits[i], 4, 4, 0)) < 0)
+ if ((ret = init_vlc(&s->vlc[i], VLC_BITS, s->vlc_n, s->len[i], 1, 1,
+ s->bits[i], 4, 4, 0)) < 0)
return ret;
}
@@ -213,16 +237,14 @@ static int read_old_huffman_tables(HYuvContext *s)
GetBitContext gb;
int i, ret;
- if ((ret = init_get_bits(&gb, classic_shift_luma,
- classic_shift_luma_table_size * 8)) < 0)
- return ret;
- if ((ret = read_len_table(s->len[0], &gb)) < 0)
+ 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;
- if ((ret = init_get_bits(&gb, classic_shift_chroma,
- classic_shift_chroma_table_size * 8)) < 0)
- return ret;
- if ((ret = read_len_table(s->len[1], &gb)) < 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;
for (i = 0; i < 256; i++)
@@ -237,7 +259,7 @@ static int read_old_huffman_tables(HYuvContext *s)
memcpy(s->bits[2], s->bits[1], 256 * sizeof(uint32_t));
memcpy(s->len[2], s->len[1], 256 * sizeof(uint8_t));
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
ff_free_vlc(&s->vlc[i]);
if ((ret = init_vlc(&s->vlc[i], VLC_BITS, 256, s->len[i], 1, 1,
s->bits[i], 4, 4, 0)) < 0)
@@ -250,28 +272,47 @@ static int read_old_huffman_tables(HYuvContext *s)
return 0;
}
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+ HYuvContext *s = avctx->priv_data;
+ int i;
+
+ ff_huffyuv_common_end(s);
+ av_freep(&s->bitstream_buffer);
+
+ for (i = 0; i < 8; i++)
+ ff_free_vlc(&s->vlc[i]);
+
+ return 0;
+}
+
static av_cold int decode_init(AVCodecContext *avctx)
{
HYuvContext *s = avctx->priv_data;
int ret;
- ff_huffyuv_common_init(avctx);
ff_huffyuvdsp_init(&s->hdsp);
- memset(s->vlc, 0, 3 * sizeof(VLC));
+ memset(s->vlc, 0, 4 * sizeof(VLC));
- s->interlaced = s->height > 288;
+ s->interlaced = avctx->height > 288;
s->bgr32 = 1;
if (avctx->extradata_size) {
if ((avctx->bits_per_coded_sample & 7) &&
avctx->bits_per_coded_sample != 12)
s->version = 1; // do such files exist at all?
- else
+ else if (avctx->extradata_size > 3 && avctx->extradata[3] == 0)
s->version = 2;
+ else
+ s->version = 3;
} else
s->version = 0;
- if (s->version == 2) {
+ s->bps = 8;
+ s->n = 1<<s->bps;
+ s->vlc_n = FFMIN(s->n, MAX_VLC_N);
+ s->chroma = 1;
+ if (s->version >= 2) {
int method, interlace;
if (avctx->extradata_size < 4)
@@ -280,16 +321,27 @@ static av_cold int decode_init(AVCodecContext *avctx)
method = avctx->extradata[0];
s->decorrelate = method & 64 ? 1 : 0;
s->predictor = method & 63;
- s->bitstream_bpp = avctx->extradata[1];
- if (s->bitstream_bpp == 0)
- s->bitstream_bpp = avctx->bits_per_coded_sample & ~7;
+ if (s->version == 2) {
+ s->bitstream_bpp = avctx->extradata[1];
+ if (s->bitstream_bpp == 0)
+ s->bitstream_bpp = avctx->bits_per_coded_sample & ~7;
+ } else {
+ s->bps = (avctx->extradata[1] >> 4) + 1;
+ s->n = 1<<s->bps;
+ s->vlc_n = FFMIN(s->n, MAX_VLC_N);
+ s->chroma_h_shift = avctx->extradata[1] & 3;
+ s->chroma_v_shift = (avctx->extradata[1] >> 2) & 3;
+ s->yuv = !!(avctx->extradata[2] & 1);
+ s->chroma= !!(avctx->extradata[2] & 3);
+ s->alpha = !!(avctx->extradata[2] & 4);
+ }
interlace = (avctx->extradata[2] & 0x30) >> 4;
s->interlaced = (interlace == 1) ? 1 : (interlace == 2) ? 0 : s->interlaced;
s->context = avctx->extradata[2] & 0x40 ? 1 : 0;
if ((ret = read_huffman_tables(s, avctx->extradata + 4,
avctx->extradata_size - 4)) < 0)
- return ret;
+ goto error;
} else {
switch (avctx->bits_per_coded_sample & 7) {
case 1:
@@ -317,41 +369,201 @@ static av_cold int decode_init(AVCodecContext *avctx)
s->context = 0;
if ((ret = read_old_huffman_tables(s)) < 0)
- return ret;
+ goto error;
}
- switch (s->bitstream_bpp) {
- case 12:
- avctx->pix_fmt = AV_PIX_FMT_YUV420P;
- break;
- case 16:
- if (s->yuy2)
- avctx->pix_fmt = AV_PIX_FMT_YUYV422;
- else
- avctx->pix_fmt = AV_PIX_FMT_YUV422P;
- break;
- case 24:
- case 32:
- if (s->bgr32)
+ if (s->version <= 2) {
+ switch (s->bitstream_bpp) {
+ case 12:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ s->yuv = 1;
+ break;
+ case 16:
+ if (s->yuy2)
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ s->yuv = 1;
+ break;
+ case 24:
+ if (s->bgr32)
+ avctx->pix_fmt = AV_PIX_FMT_0RGB32;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_BGR24;
+ break;
+ case 32:
+ av_assert0(s->bgr32);
avctx->pix_fmt = AV_PIX_FMT_RGB32;
- else
- avctx->pix_fmt = AV_PIX_FMT_BGR24;
- break;
- default:
- return AVERROR_INVALIDDATA;
+ s->alpha = 1;
+ break;
+ default:
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
+ av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt,
+ &s->chroma_h_shift,
+ &s->chroma_v_shift);
+ } else {
+ switch ( (s->chroma<<10) | (s->yuv<<9) | (s->alpha<<8) | ((s->bps-1)<<4) | s->chroma_h_shift | (s->chroma_v_shift<<2)) {
+ case 0x070:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ break;
+ case 0x0F0:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16;
+ break;
+ case 0x170:
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
+ break;
+ case 0x470:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP;
+ break;
+ case 0x480:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP9;
+ break;
+ case 0x490:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP10;
+ break;
+ case 0x4B0:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP12;
+ break;
+ case 0x4D0:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP14;
+ break;
+ case 0x4F0:
+ avctx->pix_fmt = AV_PIX_FMT_GBRP16;
+ break;
+ case 0x570:
+ avctx->pix_fmt = AV_PIX_FMT_GBRAP;
+ break;
+ case 0x670:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+ break;
+ case 0x680:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P9;
+ break;
+ case 0x690:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P10;
+ break;
+ case 0x6B0:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P12;
+ break;
+ case 0x6D0:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P14;
+ break;
+ case 0x6F0:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P16;
+ break;
+ case 0x671:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ break;
+ case 0x681:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P9;
+ break;
+ case 0x691:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+ break;
+ case 0x6B1:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P12;
+ break;
+ case 0x6D1:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P14;
+ break;
+ case 0x6F1:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P16;
+ break;
+ case 0x672:
+ avctx->pix_fmt = AV_PIX_FMT_YUV411P;
+ break;
+ case 0x674:
+ avctx->pix_fmt = AV_PIX_FMT_YUV440P;
+ break;
+ case 0x675:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ break;
+ case 0x685:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P9;
+ break;
+ case 0x695:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
+ break;
+ case 0x6B5:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P12;
+ break;
+ case 0x6D5:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P14;
+ break;
+ case 0x6F5:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P16;
+ break;
+ case 0x67A:
+ avctx->pix_fmt = AV_PIX_FMT_YUV410P;
+ break;
+ case 0x770:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+ break;
+ case 0x780:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA444P9;
+ break;
+ case 0x790:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA444P10;
+ break;
+ case 0x7F0:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA444P16;
+ break;
+ case 0x771:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA422P;
+ break;
+ case 0x781:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA422P9;
+ break;
+ case 0x791:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA422P10;
+ break;
+ case 0x7F1:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA422P16;
+ break;
+ case 0x775:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
+ break;
+ case 0x785:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA420P9;
+ break;
+ case 0x795:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA420P10;
+ break;
+ case 0x7F5:
+ avctx->pix_fmt = AV_PIX_FMT_YUVA420P16;
+ break;
+ default:
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
}
+ ff_huffyuv_common_init(avctx);
+
+ if ((avctx->pix_fmt == AV_PIX_FMT_YUV422P || avctx->pix_fmt == AV_PIX_FMT_YUV420P) && avctx->width & 1) {
+ av_log(avctx, AV_LOG_ERROR, "width must be even for this colorspace\n");
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
if (s->predictor == MEDIAN && avctx->pix_fmt == AV_PIX_FMT_YUV422P &&
avctx->width % 4) {
- av_log(avctx, AV_LOG_ERROR, "width must be multiple of 4 "
+ av_log(avctx, AV_LOG_ERROR, "width must be a multiple of 4 "
"for this combination of colorspace and predictor type.\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto error;
}
- if ((ret = ff_huffyuv_alloc_temp(s)) < 0)
- return ret;
+ if ((ret = ff_huffyuv_alloc_temp(s)) < 0) {
+ ff_huffyuv_common_end(s);
+ goto error;
+ }
return 0;
+ error:
+ decode_end(avctx);
+ return ret;
}
static av_cold int decode_init_thread_copy(AVCodecContext *avctx)
@@ -359,13 +571,15 @@ static av_cold int decode_init_thread_copy(AVCodecContext *avctx)
HYuvContext *s = avctx->priv_data;
int i, ret;
- if ((ret = ff_huffyuv_alloc_temp(s)) < 0)
+ if ((ret = ff_huffyuv_alloc_temp(s)) < 0) {
+ ff_huffyuv_common_end(s);
return ret;
+ }
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 8; i++)
s->vlc[i].table = NULL;
- if (s->version == 2) {
+ if (s->version >= 2) {
if ((ret = read_huffman_tables(s, avctx->extradata + 4,
avctx->extradata_size)) < 0)
return ret;
@@ -377,48 +591,172 @@ static av_cold int decode_init_thread_copy(AVCodecContext *avctx)
return 0;
}
-/* TODO instead of restarting the read when the code isn't in the first level
- * of the joint table, jump into the 2nd level of the individual table. */
+/** Subset of GET_VLC for use in hand-roller VLC code */
+#define VLC_INTERN(dst, table, gb, name, bits, max_depth) \
+ code = table[index][0]; \
+ n = table[index][1]; \
+ if (max_depth > 1 && n < 0) { \
+ LAST_SKIP_BITS(name, gb, bits); \
+ UPDATE_CACHE(name, gb); \
+ \
+ nb_bits = -n; \
+ index = SHOW_UBITS(name, gb, nb_bits) + code; \
+ code = table[index][0]; \
+ n = table[index][1]; \
+ if (max_depth > 2 && n < 0) { \
+ LAST_SKIP_BITS(name, gb, nb_bits); \
+ UPDATE_CACHE(name, gb); \
+ \
+ nb_bits = -n; \
+ index = SHOW_UBITS(name, gb, nb_bits) + code; \
+ code = table[index][0]; \
+ n = table[index][1]; \
+ } \
+ } \
+ dst = code; \
+ LAST_SKIP_BITS(name, gb, n)
+
+
+#define GET_VLC_DUAL(dst0, dst1, name, gb, dtable, table1, table2, \
+ bits, max_depth, OP) \
+ do { \
+ unsigned int index = SHOW_UBITS(name, gb, bits); \
+ int code, n = dtable[index][1]; \
+ \
+ if (n<=0) { \
+ int nb_bits; \
+ VLC_INTERN(dst0, table1, gb, name, bits, max_depth); \
+ \
+ UPDATE_CACHE(re, gb); \
+ index = SHOW_UBITS(name, gb, bits); \
+ VLC_INTERN(dst1, table2, gb, name, bits, max_depth); \
+ } else { \
+ code = dtable[index][0]; \
+ OP(dst0, dst1, code); \
+ LAST_SKIP_BITS(name, gb, n); \
+ } \
+ } while (0)
+
+#define OP8bits(dst0, dst1, code) dst0 = code>>8; dst1 = code
+
#define READ_2PIX(dst0, dst1, plane1) \
- { \
- uint16_t code = get_vlc2(&s->gb, s->vlc[3 + plane1].table, \
- VLC_BITS, 1); \
- if (code != 0xffff) { \
- dst0 = code >> 8; \
- dst1 = code; \
- } else { \
- dst0 = get_vlc2(&s->gb, s->vlc[0].table, VLC_BITS, 3); \
- dst1 = get_vlc2(&s->gb, s->vlc[plane1].table, VLC_BITS, 3); \
- } \
- }
+ UPDATE_CACHE(re, &s->gb); \
+ GET_VLC_DUAL(dst0, dst1, re, &s->gb, s->vlc[4+plane1].table, \
+ s->vlc[0].table, s->vlc[plane1].table, VLC_BITS, 3, OP8bits)
static void decode_422_bitstream(HYuvContext *s, int count)
{
- int i;
-
+ int i, icount;
+ OPEN_READER(re, &s->gb);
count /= 2;
- if (count >= (get_bits_left(&s->gb)) / (31 * 4)) {
- for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) {
+ icount = get_bits_left(&s->gb) / (32 * 4);
+ if (count >= icount) {
+ for (i = 0; i < icount; i++) {
READ_2PIX(s->temp[0][2 * i], s->temp[1][i], 1);
READ_2PIX(s->temp[0][2 * i + 1], s->temp[2][i], 2);
}
+ for (; i < count && BITS_LEFT(re, &s->gb) > 0; i++) {
+ READ_2PIX(s->temp[0][2 * i ], s->temp[1][i], 1);
+ if (BITS_LEFT(re, &s->gb) <= 0) break;
+ READ_2PIX(s->temp[0][2 * i + 1], s->temp[2][i], 2);
+ }
+ for (; i < count; i++)
+ s->temp[0][2 * i ] = s->temp[1][i] =
+ s->temp[0][2 * i + 1] = s->temp[2][i] = 0;
} else {
for (i = 0; i < count; i++) {
READ_2PIX(s->temp[0][2 * i], s->temp[1][i], 1);
READ_2PIX(s->temp[0][2 * i + 1], s->temp[2][i], 2);
}
}
+ CLOSE_READER(re, &s->gb);
+}
+
+#define READ_2PIX_PLANE(dst0, dst1, plane, OP) \
+ UPDATE_CACHE(re, &s->gb); \
+ GET_VLC_DUAL(dst0, dst1, re, &s->gb, s->vlc[4+plane].table, \
+ s->vlc[plane].table, s->vlc[plane].table, VLC_BITS, 3, OP)
+
+#define OP14bits(dst0, dst1, code) dst0 = code>>8; dst1 = sign_extend(code, 8)
+
+/* TODO instead of restarting the read when the code isn't in the first level
+ * of the joint table, jump into the 2nd level of the individual table. */
+#define READ_2PIX_PLANE16(dst0, dst1, plane){\
+ dst0 = get_vlc2(&s->gb, s->vlc[plane].table, VLC_BITS, 3)<<2;\
+ dst0 += get_bits(&s->gb, 2);\
+ dst1 = get_vlc2(&s->gb, s->vlc[plane].table, VLC_BITS, 3)<<2;\
+ dst1 += get_bits(&s->gb, 2);\
+}
+static void decode_plane_bitstream(HYuvContext *s, int width, int plane)
+{
+ int i, count = width/2;
+
+ if (s->bps <= 8) {
+ OPEN_READER(re, &s->gb);
+ if (count >= (get_bits_left(&s->gb)) / (32 * 2)) {
+ for (i = 0; i < count && BITS_LEFT(re, &s->gb) > 0; i++) {
+ READ_2PIX_PLANE(s->temp[0][2 * i], s->temp[0][2 * i + 1], plane, OP8bits);
+ }
+ } else {
+ for(i=0; i<count; i++){
+ READ_2PIX_PLANE(s->temp[0][2 * i], s->temp[0][2 * i + 1], plane, OP8bits);
+ }
+ }
+ if( width&1 && BITS_LEFT(re, &s->gb)>0 ) {
+ unsigned int index;
+ int nb_bits, code, n;
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(s->temp[0][width-1], s->vlc[plane].table,
+ &s->gb, re, VLC_BITS, 3);
+ }
+ CLOSE_READER(re, &s->gb);
+ } else if (s->bps <= 14) {
+ OPEN_READER(re, &s->gb);
+ if (count >= (get_bits_left(&s->gb)) / (32 * 2)) {
+ for (i = 0; i < count && BITS_LEFT(re, &s->gb) > 0; i++) {
+ READ_2PIX_PLANE(s->temp16[0][2 * i], s->temp16[0][2 * i + 1], plane, OP14bits);
+ }
+ } else {
+ for(i=0; i<count; i++){
+ READ_2PIX_PLANE(s->temp16[0][2 * i], s->temp16[0][2 * i + 1], plane, OP14bits);
+ }
+ }
+ if( width&1 && BITS_LEFT(re, &s->gb)>0 ) {
+ unsigned int index;
+ int nb_bits, code, n;
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(s->temp16[0][width-1], s->vlc[plane].table,
+ &s->gb, re, VLC_BITS, 3);
+ }
+ CLOSE_READER(re, &s->gb);
+ } else {
+ if (count >= (get_bits_left(&s->gb)) / (32 * 2)) {
+ for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) {
+ READ_2PIX_PLANE16(s->temp16[0][2 * i], s->temp16[0][2 * i + 1], plane);
+ }
+ } else {
+ for(i=0; i<count; i++){
+ READ_2PIX_PLANE16(s->temp16[0][2 * i], s->temp16[0][2 * i + 1], plane);
+ }
+ }
+ if( width&1 && get_bits_left(&s->gb)>0 ) {
+ int dst = get_vlc2(&s->gb, s->vlc[plane].table, VLC_BITS, 3)<<2;
+ s->temp16[0][width-1] = dst + get_bits(&s->gb, 2);
+ }
+ }
}
static void decode_gray_bitstream(HYuvContext *s, int count)
{
int i;
-
+ OPEN_READER(re, &s->gb);
count /= 2;
- if (count >= (get_bits_left(&s->gb)) / (31 * 2)) {
- for (i = 0; i < count && get_bits_left(&s->gb) > 0; i++) {
+ if (count >= (get_bits_left(&s->gb)) / (32 * 2)) {
+ 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);
}
} else {
@@ -426,30 +764,65 @@ static void decode_gray_bitstream(HYuvContext *s, int count)
READ_2PIX(s->temp[0][2 * i], s->temp[0][2 * i + 1], 0);
}
}
+ CLOSE_READER(re, &s->gb);
}
static av_always_inline void decode_bgr_1(HYuvContext *s, int count,
int decorrelate, int alpha)
{
int i;
- for (i = 0; i < count; i++) {
- int code = get_vlc2(&s->gb, s->vlc[3].table, VLC_BITS, 1);
- if (code != -1) {
+ OPEN_READER(re, &s->gb);
+
+ for (i = 0; i < count && BITS_LEFT(re, &s->gb) > 0; i++) {
+ unsigned int index;
+ int code, n, nb_bits;
+
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ n = s->vlc[4].table[index][1];
+
+ if (n>0) {
+ code = s->vlc[4].table[index][0];
*(uint32_t *) &s->temp[0][4 * i] = s->pix_bgr_map[code];
- } else if (decorrelate) {
- s->temp[0][4 * i + G] = get_vlc2(&s->gb, s->vlc[1].table, VLC_BITS, 3);
- s->temp[0][4 * i + B] = get_vlc2(&s->gb, s->vlc[0].table, VLC_BITS, 3) +
- s->temp[0][4 * i + G];
- s->temp[0][4 * i + R] = get_vlc2(&s->gb, s->vlc[2].table, VLC_BITS, 3) +
- s->temp[0][4 * i + G];
+ LAST_SKIP_BITS(re, &s->gb, n);
} else {
- s->temp[0][4 * i + B] = get_vlc2(&s->gb, s->vlc[0].table, VLC_BITS, 3);
- s->temp[0][4 * i + G] = get_vlc2(&s->gb, s->vlc[1].table, VLC_BITS, 3);
- s->temp[0][4 * i + R] = get_vlc2(&s->gb, s->vlc[2].table, VLC_BITS, 3);
+ if (decorrelate) {
+ VLC_INTERN(s->temp[0][4 * i + G], s->vlc[1].table,
+ &s->gb, re, VLC_BITS, 3);
+
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(code, s->vlc[0].table, &s->gb, re, VLC_BITS, 3);
+ s->temp[0][4 * i + B] = code + s->temp[0][4 * i + G];
+
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(code, s->vlc[2].table, &s->gb, re, VLC_BITS, 3);
+ s->temp[0][4 * i + R] = code + s->temp[0][4 * i + G];
+ } else {
+ VLC_INTERN(s->temp[0][4 * i + B], s->vlc[0].table,
+ &s->gb, re, VLC_BITS, 3);
+
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(s->temp[0][4 * i + G], s->vlc[1].table,
+ &s->gb, re, VLC_BITS, 3);
+
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(s->temp[0][4 * i + R], s->vlc[2].table,
+ &s->gb, re, VLC_BITS, 3);
+ }
}
- if (alpha)
- s->temp[0][4 * i + A] = get_vlc2(&s->gb, s->vlc[2].table, VLC_BITS, 3);
+ if (alpha) {
+ UPDATE_CACHE(re, &s->gb);
+ index = SHOW_UBITS(re, &s->gb, VLC_BITS);
+ VLC_INTERN(s->temp[0][4 * i + A], s->vlc[2].table,
+ &s->gb, re, VLC_BITS, 3);
+ } else
+ s->temp[0][4 * i + A] = 0;
}
+ CLOSE_READER(re, &s->gb);
}
static void decode_bgr_bitstream(HYuvContext *s, int count)
@@ -495,6 +868,32 @@ static void draw_slice(HYuvContext *s, AVFrame *frame, int y)
s->last_slice_end = y + h;
}
+static int left_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *src, int w, int acc)
+{
+ if (s->bps <= 8) {
+ return s->hdsp.add_hfyu_left_pred(dst, src, w, acc);
+ } else {
+ return s->llviddsp.add_hfyu_left_pred_int16(( uint16_t *)dst, (const uint16_t *)src, s->n-1, w, acc);
+ }
+}
+
+static void add_bytes(HYuvContext *s, uint8_t *dst, uint8_t *src, int w)
+{
+ if (s->bps <= 8) {
+ s->hdsp.add_bytes(dst, src, w);
+ } else {
+ s->llviddsp.add_int16((uint16_t*)dst, (const uint16_t*)src, s->n - 1, w);
+ }
+}
+
+static void add_median_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *src, const uint8_t *diff, int w, int *left, int *left_top)
+{
+ if (s->bps <= 8) {
+ s->hdsp.add_hfyu_median_pred(dst, src, diff, w, left, left_top);
+ } else {
+ s->llviddsp.add_hfyu_median_pred_int16((uint16_t *)dst, (const uint16_t *)src, (const uint16_t *)diff, s->n-1, w, left, left_top);
+ }
+}
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
@@ -509,20 +908,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVFrame *const p = data;
int table_size = 0, ret;
- av_fast_malloc(&s->bitstream_buffer,
+ av_fast_padded_malloc(&s->bitstream_buffer,
&s->bitstream_buffer_size,
- buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ buf_size);
if (!s->bitstream_buffer)
return AVERROR(ENOMEM);
- memset(s->bitstream_buffer + buf_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
s->bdsp.bswap_buf((uint32_t *) s->bitstream_buffer,
(const uint32_t *) buf, buf_size / 4);
- if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
return ret;
- }
if (s->context) {
table_size = read_huffman_tables(s, s->bitstream_buffer, buf_size);
@@ -543,7 +939,72 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->last_slice_end = 0;
- if (s->bitstream_bpp < 24) {
+ if (s->version > 2) {
+ int plane;
+ for(plane = 0; plane < 1 + 2*s->chroma + s->alpha; plane++) {
+ int left, lefttop, y;
+ int w = width;
+ int h = height;
+ int fake_stride = fake_ystride;
+
+ if (s->chroma && (plane == 1 || plane == 2)) {
+ w >>= s->chroma_h_shift;
+ h >>= s->chroma_v_shift;
+ fake_stride = plane == 1 ? fake_ustride : fake_vstride;
+ }
+
+ switch (s->predictor) {
+ case LEFT:
+ case PLANE:
+ decode_plane_bitstream(s, w, plane);
+ left = left_prediction(s, p->data[plane], s->temp[0], w, 0);
+
+ for (y = 1; y < h; y++) {
+ uint8_t *dst = p->data[plane] + p->linesize[plane]*y;
+
+ decode_plane_bitstream(s, w, plane);
+ left = left_prediction(s, dst, s->temp[0], w, left);
+ if (s->predictor == PLANE) {
+ if (y > s->interlaced) {
+ add_bytes(s, dst, dst - fake_stride, w);
+ }
+ }
+ }
+
+ break;
+ case MEDIAN:
+ decode_plane_bitstream(s, w, plane);
+ left= left_prediction(s, p->data[plane], s->temp[0], w, 0);
+
+ y = 1;
+
+ /* second line is left predicted for interlaced case */
+ if (s->interlaced) {
+ decode_plane_bitstream(s, w, plane);
+ left = left_prediction(s, p->data[plane] + p->linesize[plane], s->temp[0], w, left);
+ y++;
+ }
+
+ lefttop = p->data[plane][0];
+ decode_plane_bitstream(s, w, plane);
+ add_median_prediction(s, p->data[plane] + fake_stride, p->data[plane], s->temp[0], w, &left, &lefttop);
+ y++;
+
+ for (; y<h; y++) {
+ uint8_t *dst;
+
+ decode_plane_bitstream(s, w, plane);
+
+ dst = p->data[plane] + p->linesize[plane] * y;
+
+ add_median_prediction(s, dst, dst - fake_stride, s->temp[0], w, &left, &lefttop);
+ }
+
+ break;
+ }
+ }
+ draw_slice(s, p, height);
+ } else if (s->bitstream_bpp < 24) {
int y, cy;
int lefty, leftu, leftv;
int lefttopy, lefttopu, lefttopv;
@@ -554,7 +1015,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
p->data[0][1] = get_bits(&s->gb, 8);
p->data[0][0] = get_bits(&s->gb, 8);
- avpriv_report_missing_feature(avctx, "YUY2 output");
+ av_log(avctx, AV_LOG_ERROR,
+ "YUY2 output is not implemented yet\n");
return AVERROR_PATCHWELCOME;
} else {
leftv =
@@ -708,19 +1170,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
} else {
int y;
- int leftr, leftg, leftb, lefta;
+ uint8_t left[4];
const int last_line = (height - 1) * p->linesize[0];
if (s->bitstream_bpp == 32) {
- lefta = p->data[0][last_line + A] = get_bits(&s->gb, 8);
- leftr = p->data[0][last_line + R] = get_bits(&s->gb, 8);
- leftg = p->data[0][last_line + G] = get_bits(&s->gb, 8);
- leftb = p->data[0][last_line + B] = get_bits(&s->gb, 8);
+ left[A] = p->data[0][last_line + A] = get_bits(&s->gb, 8);
+ left[R] = p->data[0][last_line + R] = get_bits(&s->gb, 8);
+ left[G] = p->data[0][last_line + G] = get_bits(&s->gb, 8);
+ left[B] = p->data[0][last_line + B] = get_bits(&s->gb, 8);
} else {
- leftr = p->data[0][last_line + R] = get_bits(&s->gb, 8);
- leftg = p->data[0][last_line + G] = get_bits(&s->gb, 8);
- leftb = p->data[0][last_line + B] = get_bits(&s->gb, 8);
- lefta = p->data[0][last_line + A] = 255;
+ left[R] = p->data[0][last_line + R] = get_bits(&s->gb, 8);
+ left[G] = p->data[0][last_line + G] = get_bits(&s->gb, 8);
+ left[B] = p->data[0][last_line + B] = get_bits(&s->gb, 8);
+ left[A] = p->data[0][last_line + A] = 255;
skip_bits(&s->gb, 8);
}
@@ -730,23 +1192,20 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
case PLANE:
decode_bgr_bitstream(s, width - 1);
s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + last_line + 4,
- s->temp[0], width - 1, &leftr,
- &leftg, &leftb, &lefta);
+ s->temp[0], width - 1, left);
for (y = s->height - 2; y >= 0; y--) { // Yes it is stored upside down.
decode_bgr_bitstream(s, width);
s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + p->linesize[0] * y,
- s->temp[0], width, &leftr,
- &leftg, &leftb, &lefta);
+ s->temp[0], width, left);
if (s->predictor == PLANE) {
if (s->bitstream_bpp != 32)
- lefta = 0;
- if ((y & s->interlaced) == 0 &&
- y < s->height - 1 - s->interlaced) {
+ left[A] = 0;
+ if (y < s->height - 1 - s->interlaced) {
s->hdsp.add_bytes(p->data[0] + p->linesize[0] * y,
p->data[0] + p->linesize[0] * y +
- fake_ystride, fake_ystride);
+ fake_ystride, 4 * width);
}
}
}
@@ -758,7 +1217,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
"prediction type not supported!\n");
}
} else {
- avpriv_report_missing_feature(avctx, "BGR24 output");
+ av_log(avctx, AV_LOG_ERROR,
+ "BGR24 output is not implemented yet\n");
return AVERROR_PATCHWELCOME;
}
}
@@ -769,20 +1229,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return (get_bits_count(&s->gb) + 31) / 32 * 4 + table_size;
}
-static av_cold int decode_end(AVCodecContext *avctx)
-{
- HYuvContext *s = avctx->priv_data;
- int i;
-
- ff_huffyuv_common_end(s);
- av_freep(&s->bitstream_buffer);
-
- for (i = 0; i < 6; i++)
- ff_free_vlc(&s->vlc[i]);
-
- return 0;
-}
-
AVCodec ff_huffyuv_decoder = {
.name = "huffyuv",
.long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
diff --git a/libavcodec/huffyuvdsp.c b/libavcodec/huffyuvdsp.c
index b5a714d072..e8a05f6592 100644
--- a/libavcodec/huffyuvdsp.c
+++ b/libavcodec/huffyuvdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
#define pb_7f (~0UL / 255 * 0x7f)
#define pb_80 (~0UL / 255 * 0x80)
-static void add_bytes_c(uint8_t *dst, uint8_t *src, int w)
+static void add_bytes_c(uint8_t *dst, uint8_t *src, intptr_t w)
{
long i;
@@ -41,7 +41,7 @@ static void add_bytes_c(uint8_t *dst, uint8_t *src, int w)
}
static void add_hfyu_median_pred_c(uint8_t *dst, const uint8_t *src1,
- const uint8_t *diff, int w,
+ const uint8_t *diff, intptr_t w,
int *left, int *left_top)
{
int i;
@@ -60,7 +60,7 @@ static void add_hfyu_median_pred_c(uint8_t *dst, const uint8_t *src1,
*left_top = lt;
}
-static int add_hfyu_left_pred_c(uint8_t *dst, const uint8_t *src, int w,
+static int add_hfyu_left_pred_c(uint8_t *dst, const uint8_t *src, intptr_t w,
int acc)
{
int i;
@@ -81,22 +81,11 @@ static int add_hfyu_left_pred_c(uint8_t *dst, const uint8_t *src, int w,
return acc;
}
-#if HAVE_BIGENDIAN
-#define B 3
-#define G 2
-#define R 1
-#define A 0
-#else
-#define B 0
-#define G 1
-#define R 2
-#define A 3
-#endif
static void add_hfyu_left_pred_bgr32_c(uint8_t *dst, const uint8_t *src,
- int w, int *red, int *green,
- int *blue, int *alpha)
+ intptr_t w, uint8_t *left)
{
- int i, r = *red, g = *green, b = *blue, a = *alpha;
+ int i;
+ uint8_t r = left[R], g = left[G], b = left[B], a = left[A];
for (i = 0; i < w; i++) {
b += src[4 * i + B];
@@ -110,15 +99,11 @@ static void add_hfyu_left_pred_bgr32_c(uint8_t *dst, const uint8_t *src,
dst[4 * i + A] = a;
}
- *red = r;
- *green = g;
- *blue = b;
- *alpha = a;
+ left[B] = b;
+ left[G] = g;
+ left[R] = r;
+ left[A] = a;
}
-#undef B
-#undef G
-#undef R
-#undef A
av_cold void ff_huffyuvdsp_init(HuffYUVDSPContext *c)
{
diff --git a/libavcodec/huffyuvdsp.h b/libavcodec/huffyuvdsp.h
index 5e84e3aecb..db377289ee 100644
--- a/libavcodec/huffyuvdsp.h
+++ b/libavcodec/huffyuvdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -20,18 +20,30 @@
#define AVCODEC_HUFFYUVDSP_H
#include <stdint.h>
+#include "config.h"
+
+#if HAVE_BIGENDIAN
+#define B 3
+#define G 2
+#define R 1
+#define A 0
+#else
+#define B 0
+#define G 1
+#define R 2
+#define A 3
+#endif
typedef struct HuffYUVDSPContext {
void (*add_bytes)(uint8_t *dst /* align 16 */, uint8_t *src /* align 16 */,
- int w);
+ intptr_t w);
void (*add_hfyu_median_pred)(uint8_t *dst, const uint8_t *top,
- const uint8_t *diff, int w,
+ const uint8_t *diff, intptr_t w,
int *left, int *left_top);
int (*add_hfyu_left_pred)(uint8_t *dst, const uint8_t *src,
- int w, int left);
+ intptr_t w, int left);
void (*add_hfyu_left_pred_bgr32)(uint8_t *dst, const uint8_t *src,
- int w, int *red, int *green,
- int *blue, int *alpha);
+ intptr_t w, uint8_t *left);
} HuffYUVDSPContext;
void ff_huffyuvdsp_init(HuffYUVDSPContext *c);
diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c
index 6b3ff76505..f0179dfa5b 100644
--- a/libavcodec/huffyuvenc.c
+++ b/libavcodec/huffyuvenc.c
@@ -1,24 +1,26 @@
/*
- * Copyright (c) 2002-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2002-2014 Michael Niedermayer <michaelni@gmx.at>
*
* see http://www.pcisys.net/~melanson/codecs/huffyuv.txt for a description of
* the algorithm used
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * yuva, gray, 4:4:4, 4:1:1, 4:1:0 and >8 bit per sample support sponsored by NOA
*/
/**
@@ -32,31 +34,64 @@
#include "huffyuvencdsp.h"
#include "internal.h"
#include "put_bits.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+static inline void diff_bytes(HYuvContext *s, uint8_t *dst,
+ const uint8_t *src0, const uint8_t *src1, int w)
+{
+ if (s->bps <= 8) {
+ s->hencdsp.diff_bytes(dst, src0, src1, w);
+ } else {
+ s->llviddsp.diff_int16((uint16_t *)dst, (const uint16_t *)src0, (const uint16_t *)src1, s->n - 1, w);
+ }
+}
static inline int sub_left_prediction(HYuvContext *s, uint8_t *dst,
- uint8_t *src, int w, int left)
+ const uint8_t *src, int w, int left)
{
int i;
- if (w < 32) {
- for (i = 0; i < w; i++) {
- const int temp = src[i];
- dst[i] = temp - left;
- left = temp;
+ if (s->bps <= 8) {
+ if (w < 32) {
+ for (i = 0; i < w; i++) {
+ const int temp = src[i];
+ dst[i] = temp - left;
+ left = temp;
+ }
+ return left;
+ } else {
+ for (i = 0; i < 16; i++) {
+ const int temp = src[i];
+ dst[i] = temp - left;
+ left = temp;
+ }
+ s->hencdsp.diff_bytes(dst + 16, src + 16, src + 15, w - 16);
+ return src[w-1];
}
- return left;
} else {
- for (i = 0; i < 16; i++) {
- const int temp = src[i];
- dst[i] = temp - left;
- left = temp;
+ const uint16_t *src16 = (const uint16_t *)src;
+ uint16_t *dst16 = ( uint16_t *)dst;
+ if (w < 32) {
+ for (i = 0; i < w; i++) {
+ const int temp = src16[i];
+ dst16[i] = temp - left;
+ left = temp;
+ }
+ return left;
+ } else {
+ for (i = 0; i < 16; i++) {
+ const int temp = src16[i];
+ dst16[i] = temp - left;
+ left = temp;
+ }
+ s->llviddsp.diff_int16(dst16 + 16, src16 + 16, src16 + 15, s->n - 1, w - 16);
+ return src16[w-1];
}
- s->hencdsp.diff_bytes(dst + 16, src + 16, src + 15, w - 16);
- return src[w-1];
}
}
static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst,
- uint8_t *src, int w,
+ const uint8_t *src, int w,
int *red, int *green, int *blue,
int *alpha)
{
@@ -118,20 +153,30 @@ static inline void sub_left_prediction_rgb24(HYuvContext *s, uint8_t *dst,
*blue = src[(w - 1) * 3 + 2];
}
+static void sub_median_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *src1, const uint8_t *src2, int w, int *left, int *left_top)
+{
+ if (s->bps <= 8) {
+ s->hencdsp.sub_hfyu_median_pred(dst, src1, src2, w , left, left_top);
+ } else {
+ s->llviddsp.sub_hfyu_median_pred_int16((uint16_t *)dst, (const uint16_t *)src1, (const uint16_t *)src2, s->n - 1, w , left, left_top);
+ }
+}
+
static int store_table(HYuvContext *s, const uint8_t *len, uint8_t *buf)
{
int i;
int index = 0;
+ int n = s->vlc_n;
- for (i = 0; i < 256;) {
+ for (i = 0; i < n;) {
int val = len[i];
int repeat = 0;
- for (; i < 256 && len[i] == val && repeat < 255; i++)
+ for (; i < n && len[i] == val && repeat < 255; i++)
repeat++;
- assert(val < 32 && val >0 && repeat<256 && repeat>0);
- if ( repeat > 7) {
+ av_assert0(val < 32 && val >0 && repeat < 256 && repeat>0);
+ if (repeat > 7) {
buf[index++] = val;
buf[index++] = repeat;
} else {
@@ -142,16 +187,47 @@ static int store_table(HYuvContext *s, const uint8_t *len, uint8_t *buf)
return index;
}
+static int store_huffman_tables(HYuvContext *s, uint8_t *buf)
+{
+ int i, ret;
+ int size = 0;
+ int count = 3;
+
+ if (s->version > 2)
+ count = 1 + s->alpha + 2*s->chroma;
+
+ for (i = 0; i < count; i++) {
+ 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;
+ }
+
+ size += store_table(s, s->len[i], buf + size);
+ }
+ return size;
+}
+
static av_cold int encode_init(AVCodecContext *avctx)
{
HYuvContext *s = avctx->priv_data;
int i, j;
+ int ret;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
ff_huffyuv_common_init(avctx);
ff_huffyuvencdsp_init(&s->hencdsp);
- avctx->extradata = av_mallocz(1024*30); // 256*3+4 == 772
- avctx->stats_out = av_mallocz(1024*30); // 21*256*3(%llu ) + 3(\n) + 1(0) = 16132
+ avctx->extradata = av_mallocz(3*MAX_N + 4);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
+ if (s->flags&CODEC_FLAG_PASS1) {
+#define STATS_OUT_SIZE 21*MAX_N*3 + 4
+ avctx->stats_out = av_mallocz(STATS_OUT_SIZE); // 21*256*3(%llu ) + 3(\n) + 1(0) = 16132
+ if (!avctx->stats_out)
+ return AVERROR(ENOMEM);
+ }
s->version = 2;
avctx->coded_frame = av_frame_alloc();
@@ -161,15 +237,66 @@ static av_cold int encode_init(AVCodecContext *avctx)
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
+ s->bps = desc->comp[0].depth_minus1 + 1;
+ s->yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB) && desc->nb_components >= 2;
+ s->chroma = desc->nb_components > 2;
+ s->alpha = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA);
+ av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt,
+ &s->chroma_h_shift,
+ &s->chroma_v_shift);
+
switch (avctx->pix_fmt) {
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUV422P:
if (s->width & 1) {
av_log(avctx, AV_LOG_ERROR, "Width must be even for this colorspace.\n");
- return -1;
+ return AVERROR(EINVAL);
}
s->bitstream_bpp = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? 12 : 16;
break;
+ case AV_PIX_FMT_YUV444P:
+ case AV_PIX_FMT_YUV410P:
+ case AV_PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUV440P:
+ case AV_PIX_FMT_GBRP:
+ case AV_PIX_FMT_GBRP9:
+ case AV_PIX_FMT_GBRP10:
+ case AV_PIX_FMT_GBRP12:
+ case AV_PIX_FMT_GBRP14:
+ case AV_PIX_FMT_GBRP16:
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_GRAY16:
+ case AV_PIX_FMT_YUVA444P:
+ case AV_PIX_FMT_YUVA420P:
+ case AV_PIX_FMT_YUVA422P:
+ case AV_PIX_FMT_GBRAP:
+ case AV_PIX_FMT_GRAY8A:
+ case AV_PIX_FMT_YUV420P9:
+ case AV_PIX_FMT_YUV420P10:
+ case AV_PIX_FMT_YUV420P12:
+ case AV_PIX_FMT_YUV420P14:
+ case AV_PIX_FMT_YUV420P16:
+ case AV_PIX_FMT_YUV422P9:
+ case AV_PIX_FMT_YUV422P10:
+ case AV_PIX_FMT_YUV422P12:
+ case AV_PIX_FMT_YUV422P14:
+ case AV_PIX_FMT_YUV422P16:
+ case AV_PIX_FMT_YUV444P9:
+ case AV_PIX_FMT_YUV444P10:
+ case AV_PIX_FMT_YUV444P12:
+ case AV_PIX_FMT_YUV444P14:
+ case AV_PIX_FMT_YUV444P16:
+ case AV_PIX_FMT_YUVA420P9:
+ case AV_PIX_FMT_YUVA420P10:
+ case AV_PIX_FMT_YUVA420P16:
+ case AV_PIX_FMT_YUVA422P9:
+ case AV_PIX_FMT_YUVA422P10:
+ case AV_PIX_FMT_YUVA422P16:
+ case AV_PIX_FMT_YUVA444P9:
+ case AV_PIX_FMT_YUVA444P10:
+ case AV_PIX_FMT_YUVA444P16:
+ s->version = 3;
+ break;
case AV_PIX_FMT_RGB32:
s->bitstream_bpp = 32;
break;
@@ -178,10 +305,13 @@ static av_cold int encode_init(AVCodecContext *avctx)
break;
default:
av_log(avctx, AV_LOG_ERROR, "format not supported\n");
- return -1;
+ return AVERROR(EINVAL);
}
+ s->n = 1<<s->bps;
+ s->vlc_n = FFMIN(s->n, MAX_VLC_N);
+
avctx->bits_per_coded_sample = s->bitstream_bpp;
- s->decorrelate = s->bitstream_bpp >= 24;
+ s->decorrelate = s->bitstream_bpp >= 24 && !s->yuv && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR);
s->predictor = avctx->prediction_method;
s->interlaced = avctx->flags&CODEC_FLAG_INTERLACED_ME ? 1 : 0;
if (avctx->context_model == 1) {
@@ -190,7 +320,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR,
"context=1 is not compatible with "
"2 pass huffyuv encoding\n");
- return -1;
+ return AVERROR(EINVAL);
}
}else s->context= 0;
@@ -199,45 +329,66 @@ static av_cold int encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR,
"Error: YV12 is not supported by huffyuv; use "
"vcodec=ffvhuff or format=422p\n");
- return -1;
+ return AVERROR(EINVAL);
}
if (avctx->context_model) {
av_log(avctx, AV_LOG_ERROR,
"Error: per-frame huffman tables are not supported "
"by huffyuv; use vcodec=ffvhuff\n");
- return -1;
+ return AVERROR(EINVAL);
+ }
+ if (s->version > 2) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Error: ver>2 is not supported "
+ "by huffyuv; use vcodec=ffvhuff\n");
+ return AVERROR(EINVAL);
}
if (s->interlaced != ( s->height > 288 ))
av_log(avctx, AV_LOG_INFO,
"using huffyuv 2.2.0 or newer interlacing flag\n");
}
- if (s->bitstream_bpp >= 24 && s->predictor == MEDIAN) {
+ if (s->version > 3 && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+ av_log(avctx, AV_LOG_ERROR, "Ver > 3 is under development, files encoded with it may not be decodable with future versions!!!\n"
+ "Use vstrict=-2 / -strict -2 to use it anyway.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (s->bitstream_bpp >= 24 && s->predictor == MEDIAN && s->version <= 2) {
av_log(avctx, AV_LOG_ERROR,
"Error: RGB is incompatible with median predictor\n");
- return -1;
+ return AVERROR(EINVAL);
}
((uint8_t*)avctx->extradata)[0] = s->predictor | (s->decorrelate << 6);
- ((uint8_t*)avctx->extradata)[1] = s->bitstream_bpp;
((uint8_t*)avctx->extradata)[2] = s->interlaced ? 0x10 : 0x20;
if (s->context)
((uint8_t*)avctx->extradata)[2] |= 0x40;
- ((uint8_t*)avctx->extradata)[3] = 0;
+ if (s->version < 3) {
+ ((uint8_t*)avctx->extradata)[1] = s->bitstream_bpp;
+ ((uint8_t*)avctx->extradata)[3] = 0;
+ } else {
+ ((uint8_t*)avctx->extradata)[1] = ((s->bps-1)<<4) | s->chroma_h_shift | (s->chroma_v_shift<<2);
+ if (s->chroma)
+ ((uint8_t*)avctx->extradata)[2] |= s->yuv ? 1 : 2;
+ if (s->alpha)
+ ((uint8_t*)avctx->extradata)[2] |= 4;
+ ((uint8_t*)avctx->extradata)[3] = 1;
+ }
s->avctx->extradata_size = 4;
if (avctx->stats_in) {
char *p = avctx->stats_in;
- for (i = 0; i < 3; i++)
- for (j = 0; j < 256; j++)
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < s->vlc_n; j++)
s->stats[i][j] = 1;
for (;;) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
char *next;
- for (j = 0; j < 256; j++) {
+ for (j = 0; j < s->vlc_n; j++) {
s->stats[i][j] += strtol(p, &next, 0);
if (next == p) return -1;
p = next;
@@ -246,40 +397,37 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (p[0] == 0 || p[1] == 0 || p[2] == 0) break;
}
} else {
- for (i = 0; i < 3; i++)
- for (j = 0; j < 256; j++) {
- int d = FFMIN(j, 256 - j);
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < s->vlc_n; j++) {
+ int d = FFMIN(j, s->vlc_n - j);
- s->stats[i][j] = 100000000 / (d + 1);
+ s->stats[i][j] = 100000000 / (d*d + 1);
}
}
- for (i = 0; i < 3; i++) {
- ff_huff_gen_len_table(s->len[i], s->stats[i]);
-
- if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i]) < 0) {
- return -1;
- }
-
- s->avctx->extradata_size +=
- store_table(s, s->len[i], &((uint8_t*)s->avctx->extradata)[s->avctx->extradata_size]);
- }
+ ret = store_huffman_tables(s, s->avctx->extradata + s->avctx->extradata_size);
+ if (ret < 0)
+ return ret;
+ s->avctx->extradata_size += ret;
if (s->context) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
int pels = s->width * s->height / (i ? 40 : 10);
- for (j = 0; j < 256; j++) {
- int d = FFMIN(j, 256 - j);
- s->stats[i][j] = pels/(d + 1);
+ for (j = 0; j < s->vlc_n; j++) {
+ int d = FFMIN(j, s->vlc_n - j);
+ s->stats[i][j] = pels/(d*d + 1);
}
}
} else {
- for (i = 0; i < 3; i++)
- for (j = 0; j < 256; j++)
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < s->vlc_n; j++)
s->stats[i][j]= 0;
}
- ff_huffyuv_alloc_temp(s);
+ if (ff_huffyuv_alloc_temp(s)) {
+ ff_huffyuv_common_end(s);
+ return AVERROR(ENOMEM);
+ }
s->picture_number=0;
@@ -340,6 +488,168 @@ static int encode_422_bitstream(HYuvContext *s, int offset, int count)
return 0;
}
+static int encode_plane_bitstream(HYuvContext *s, int width, int plane)
+{
+ int i, count = width/2;
+
+ if (s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb) >> 3) < count * s->bps / 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ return -1;
+ }
+
+#define LOADEND\
+ int y0 = s->temp[0][width-1];
+#define LOADEND_14\
+ int y0 = s->temp16[0][width-1] & mask;
+#define LOADEND_16\
+ int y0 = s->temp16[0][width-1];
+#define STATEND\
+ s->stats[plane][y0]++;
+#define STATEND_16\
+ s->stats[plane][y0>>2]++;
+#define WRITEEND\
+ put_bits(&s->pb, s->len[plane][y0], s->bits[plane][y0]);
+#define WRITEEND_16\
+ put_bits(&s->pb, s->len[plane][y0>>2], s->bits[plane][y0>>2]);\
+ put_bits(&s->pb, 2, y0&3);
+
+#define LOAD2\
+ int y0 = s->temp[0][2 * i];\
+ int y1 = s->temp[0][2 * i + 1];
+#define LOAD2_14\
+ int y0 = s->temp16[0][2 * i] & mask;\
+ int y1 = s->temp16[0][2 * i + 1] & mask;
+#define LOAD2_16\
+ int y0 = s->temp16[0][2 * i];\
+ int y1 = s->temp16[0][2 * i + 1];
+#define STAT2\
+ s->stats[plane][y0]++;\
+ s->stats[plane][y1]++;
+#define STAT2_16\
+ s->stats[plane][y0>>2]++;\
+ s->stats[plane][y1>>2]++;
+#define WRITE2\
+ put_bits(&s->pb, s->len[plane][y0], s->bits[plane][y0]);\
+ put_bits(&s->pb, s->len[plane][y1], s->bits[plane][y1]);
+#define WRITE2_16\
+ put_bits(&s->pb, s->len[plane][y0>>2], s->bits[plane][y0>>2]);\
+ put_bits(&s->pb, 2, y0&3);\
+ 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 & CODEC_FLAG_PASS1) {
+ for (i = 0; i < count; i++) {
+ LOAD2;
+ STAT2;
+ }
+ if (width&1) {
+ LOADEND;
+ STATEND;
+ }
+ }
+ if (s->avctx->flags2 & CODEC_FLAG2_NO_OUTPUT)
+ return 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;
+ }
+ }
+ } else if (s->bps <= 14) {
+ int mask = s->n - 1;
+ if (s->flags & CODEC_FLAG_PASS1) {
+ for (i = 0; i < count; i++) {
+ LOAD2_14;
+ STAT2;
+ }
+ if (width&1) {
+ LOADEND_14;
+ STATEND;
+ }
+ }
+ if (s->avctx->flags2 & 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;
+ }
+ }
+ } else {
+ if (s->flags & CODEC_FLAG_PASS1) {
+ for (i = 0; i < count; i++) {
+ LOAD2_16;
+ STAT2_16;
+ }
+ if (width&1) {
+ LOADEND_16;
+ STATEND_16;
+ }
+ }
+ if (s->avctx->flags2 & 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;
+ }
+ }
+ }
+#undef LOAD2
+#undef STAT2
+#undef WRITE2
+ return 0;
+}
+
static int encode_gray_bitstream(HYuvContext *s, int count)
{
int i;
@@ -397,8 +707,8 @@ static inline int encode_bgra_bitstream(HYuvContext *s, int count, int planes)
#define LOAD_GBRA \
int g = s->temp[0][planes == 3 ? 3 * i + 1 : 4 * i + G]; \
- int b = s->temp[0][planes == 3 ? 3 * i + 2 : 4 * i + B] - g & 0xFF; \
- int r = s->temp[0][planes == 3 ? 3 * i + 0 : 4 * i + R] - g & 0xFF; \
+ int b =(s->temp[0][planes == 3 ? 3 * i + 2 : 4 * i + B] - g) & 0xFF;\
+ int r =(s->temp[0][planes == 3 ? 3 * i + 0 : 4 * i + R] - g) & 0xFF;\
int a = s->temp[0][planes * i + A];
#define STAT_BGRA \
@@ -449,22 +759,16 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame * const p = pict;
int i, j, size = 0, ret;
- if (!pkt->data &&
- (ret = av_new_packet(pkt, width * height * 3 * 4 + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error allocating output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, width * height * 3 * 4 + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
if (s->context) {
- for (i = 0; i < 3; i++) {
- ff_huff_gen_len_table(s->len[i], s->stats[i]);
- if (ff_huffyuv_generate_bits_table(s->bits[i], s->len[i]) < 0)
- return -1;
- size += store_table(s, s->len[i], &pkt->data[size]);
- }
+ size = store_huffman_tables(s, pkt->data);
+ if (size < 0)
+ return size;
- for (i = 0; i < 3; i++)
- for (j = 0; j < 256; j++)
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < s->vlc_n; j++)
s->stats[i][j] >>= 1;
}
@@ -632,6 +936,59 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
encode_bgra_bitstream(s, width, 3);
}
+ } else if (s->version > 2) {
+ int plane;
+ for (plane = 0; plane < 1 + 2*s->chroma + s->alpha; plane++) {
+ int left, y;
+ int w = width;
+ int h = height;
+ int fake_stride = fake_ystride;
+
+ if (s->chroma && (plane == 1 || plane == 2)) {
+ w >>= s->chroma_h_shift;
+ h >>= s->chroma_v_shift;
+ fake_stride = plane == 1 ? fake_ustride : fake_vstride;
+ }
+
+ left = sub_left_prediction(s, s->temp[0], p->data[plane], w , 0);
+
+ encode_plane_bitstream(s, w, plane);
+
+ if (s->predictor==MEDIAN) {
+ int lefttop;
+ y = 1;
+ if (s->interlaced) {
+ left = sub_left_prediction(s, s->temp[0], p->data[plane] + p->linesize[plane], w , left);
+
+ encode_plane_bitstream(s, w, plane);
+ y++;
+ }
+
+ lefttop = p->data[plane][0];
+
+ for (; y < h; y++) {
+ uint8_t *dst = p->data[plane] + p->linesize[plane] * y;
+
+ sub_median_prediction(s, s->temp[0], dst - fake_stride, dst, w , &left, &lefttop);
+
+ encode_plane_bitstream(s, w, plane);
+ }
+ } else {
+ for (y = 1; y < h; y++) {
+ uint8_t *dst = p->data[plane] + p->linesize[plane] * y;
+
+ if (s->predictor == PLANE && s->interlaced < y) {
+ diff_bytes(s, s->temp[1], dst, dst - fake_stride, w);
+
+ left = sub_left_prediction(s, s->temp[0], s->temp[1], w , left);
+ } else {
+ left = sub_left_prediction(s, s->temp[0], dst, w , left);
+ }
+
+ encode_plane_bitstream(s, w, plane);
+ }
+ }
+ }
} else {
av_log(avctx, AV_LOG_ERROR, "Format not supported!\n");
}
@@ -645,17 +1002,19 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if ((s->flags&CODEC_FLAG_PASS1) && (s->picture_number & 31) == 0) {
int j;
char *p = avctx->stats_out;
- char *end = p + 1024*30;
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 256; j++) {
+ char *end = p + STATS_OUT_SIZE;
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < s->vlc_n; j++) {
snprintf(p, end-p, "%"PRIu64" ", s->stats[i][j]);
p += strlen(p);
s->stats[i][j]= 0;
}
snprintf(p, end-p, "\n");
p++;
+ if (end <= p)
+ return AVERROR(ENOMEM);
}
- } else
+ } else if (avctx->stats_out)
avctx->stats_out[0] = '\0';
if (!(s->avctx->flags2 & CODEC_FLAG2_NO_OUTPUT)) {
flush_put_bits(&s->pb);
@@ -685,6 +1044,27 @@ static av_cold int encode_end(AVCodecContext *avctx)
return 0;
}
+static const AVOption options[] = {
+ { "non_deterministic", "Allow multithreading for e.g. context=1 at the expense of determinism",
+ offsetof(HYuvContext, non_determ), AV_OPT_TYPE_INT, { .i64 = 1 },
+ 0, 1, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+static const AVClass normal_class = {
+ .class_name = "huffyuv",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVClass ff_class = {
+ .class_name = "ffvhuff",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_huffyuv_encoder = {
.name = "huffyuv",
.long_name = NULL_IF_CONFIG_SMALL("Huffyuv / HuffYUV"),
@@ -694,6 +1074,8 @@ AVCodec ff_huffyuv_encoder = {
.init = encode_init,
.encode2 = encode_frame,
.close = encode_end,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .priv_class = &normal_class,
.pix_fmts = (const enum AVPixelFormat[]){
AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24,
AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
@@ -712,8 +1094,24 @@ AVCodec ff_ffvhuff_encoder = {
.init = encode_init,
.encode2 = encode_frame,
.close = encode_end,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .priv_class = &ff_class,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_RGB24,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_GBRP,
+ AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16,
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_GRAY8A,
+ AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV420P16,
+ AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV422P16,
+ AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV444P16,
+ AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
+ AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P16,
+ AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P16,
+ AV_PIX_FMT_RGB24,
AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
},
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
diff --git a/libavcodec/huffyuvencdsp.c b/libavcodec/huffyuvencdsp.c
index 6c30877737..95fcc19582 100644
--- a/libavcodec/huffyuvencdsp.c
+++ b/libavcodec/huffyuvencdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,12 +25,12 @@
#define pb_7f (~0UL / 255 * 0x7f)
#define pb_80 (~0UL / 255 * 0x80)
-static void diff_bytes_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w)
+static void diff_bytes_c(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, int w)
{
long i;
#if !HAVE_FAST_UNALIGNED
- if ((long) src2 & (sizeof(long) - 1)) {
+ if (((long)src1 | (long)src2) & (sizeof(long) - 1)) {
for (i = 0; i + 7 < w; i += 8) {
dst[i + 0] = src1[i + 0] - src2[i + 0];
dst[i + 1] = src1[i + 1] - src2[i + 1];
diff --git a/libavcodec/huffyuvencdsp.h b/libavcodec/huffyuvencdsp.h
index 603c36f7af..3a49b4a7ef 100644
--- a/libavcodec/huffyuvencdsp.h
+++ b/libavcodec/huffyuvencdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,8 +23,8 @@
typedef struct HuffYUVEncDSPContext {
void (*diff_bytes)(uint8_t *dst /* align 16 */,
- uint8_t *src1 /* align 16 */,
- uint8_t *src2 /* align 1 */,
+ const uint8_t *src1 /* align 16 */,
+ const uint8_t *src2 /* align 1 */,
int w);
/**
* Subtract HuffYUV's variant of median prediction.
diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c
index 87a1013966..55319e51eb 100644
--- a/libavcodec/idcinvideo.c
+++ b/libavcodec/idcinvideo.c
@@ -1,21 +1,21 @@
/*
* id Quake II CIN Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -75,7 +75,7 @@ typedef struct IdcinContext {
uint32_t pal[256];
} IdcinContext;
-/*
+/**
* Find the lowest probability node in a Huffman table, and mark it as
* being assigned to a higher probability.
* @return the node index of the lowest unused node, or -1 if all nodes
@@ -169,7 +169,7 @@ static av_cold int idcin_decode_init(AVCodecContext *avctx)
return 0;
}
-static void idcin_decode_vlcs(IdcinContext *s, AVFrame *frame)
+static int idcin_decode_vlcs(IdcinContext *s, AVFrame *frame)
{
hnode *hnodes;
long x, y;
@@ -188,7 +188,7 @@ static void idcin_decode_vlcs(IdcinContext *s, AVFrame *frame)
if(!bit_pos) {
if(dat_pos >= s->size) {
av_log(s->avctx, AV_LOG_ERROR, "Huffman decode error.\n");
- return;
+ return -1;
}
bit_pos = 8;
v = s->buf[dat_pos++];
@@ -203,6 +203,8 @@ static void idcin_decode_vlcs(IdcinContext *s, AVFrame *frame)
prev = node_num;
}
}
+
+ return 0;
}
static int idcin_decode_frame(AVCodecContext *avctx,
@@ -219,12 +221,11 @@ static int idcin_decode_frame(AVCodecContext *avctx,
s->buf = buf;
s->size = buf_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, " id CIN Video: get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
- idcin_decode_vlcs(s, frame);
+ if (idcin_decode_vlcs(s, frame))
+ return AVERROR_INVALIDDATA;
if (pal) {
frame->palette_has_changed = 1;
diff --git a/libavcodec/idctdsp.c b/libavcodec/idctdsp.c
index a9b8727468..ae804d999a 100644
--- a/libavcodec/idctdsp.c
+++ b/libavcodec/idctdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include "faanidct.h"
#include "idctdsp.h"
#include "simple_idct.h"
+#include "xvididct.h"
av_cold void ff_init_scantable(uint8_t *permutation, ScanTable *st,
const uint8_t *src_scantable)
@@ -79,11 +80,11 @@ av_cold void ff_init_scantable_permutation(uint8_t *idct_permutation,
}
}
-void (*ff_put_pixels_clamped)(const int16_t *block, uint8_t *pixels, int line_size);
-void (*ff_add_pixels_clamped)(const int16_t *block, uint8_t *pixels, int line_size);
+void (*ff_put_pixels_clamped)(const int16_t *block, uint8_t *pixels, ptrdiff_t line_size);
+void (*ff_add_pixels_clamped)(const int16_t *block, uint8_t *pixels, ptrdiff_t line_size);
-static void put_pixels_clamped_c(const int16_t *block, uint8_t *restrict pixels,
- int line_size)
+static void put_pixels_clamped_c(const int16_t *block, uint8_t *av_restrict pixels,
+ ptrdiff_t line_size)
{
int i;
@@ -103,9 +104,41 @@ static void put_pixels_clamped_c(const int16_t *block, uint8_t *restrict pixels,
}
}
+static void put_pixels_clamped4_c(const int16_t *block, uint8_t *av_restrict pixels,
+ int line_size)
+{
+ int i;
+
+ /* read the pixels */
+ for(i=0;i<4;i++) {
+ pixels[0] = av_clip_uint8(block[0]);
+ pixels[1] = av_clip_uint8(block[1]);
+ pixels[2] = av_clip_uint8(block[2]);
+ pixels[3] = av_clip_uint8(block[3]);
+
+ pixels += line_size;
+ block += 8;
+ }
+}
+
+static void put_pixels_clamped2_c(const int16_t *block, uint8_t *av_restrict pixels,
+ int line_size)
+{
+ int i;
+
+ /* read the pixels */
+ for(i=0;i<2;i++) {
+ pixels[0] = av_clip_uint8(block[0]);
+ pixels[1] = av_clip_uint8(block[1]);
+
+ pixels += line_size;
+ block += 8;
+ }
+}
+
static void put_signed_pixels_clamped_c(const int16_t *block,
- uint8_t *restrict pixels,
- int line_size)
+ uint8_t *av_restrict pixels,
+ ptrdiff_t line_size)
{
int i, j;
@@ -124,8 +157,8 @@ static void put_signed_pixels_clamped_c(const int16_t *block,
}
}
-static void add_pixels_clamped_c(const int16_t *block, uint8_t *restrict pixels,
- int line_size)
+static void add_pixels_clamped_c(const int16_t *block, uint8_t *av_restrict pixels,
+ ptrdiff_t line_size)
{
int i;
@@ -144,41 +177,128 @@ static void add_pixels_clamped_c(const int16_t *block, uint8_t *restrict pixels,
}
}
+static void add_pixels_clamped4_c(const int16_t *block, uint8_t *av_restrict pixels,
+ int line_size)
+{
+ int i;
+
+ /* read the pixels */
+ for(i=0;i<4;i++) {
+ pixels[0] = av_clip_uint8(pixels[0] + block[0]);
+ pixels[1] = av_clip_uint8(pixels[1] + block[1]);
+ pixels[2] = av_clip_uint8(pixels[2] + block[2]);
+ pixels[3] = av_clip_uint8(pixels[3] + block[3]);
+ pixels += line_size;
+ block += 8;
+ }
+}
+
+static void add_pixels_clamped2_c(const int16_t *block, uint8_t *av_restrict pixels,
+ int line_size)
+{
+ int i;
+
+ /* read the pixels */
+ for(i=0;i<2;i++) {
+ pixels[0] = av_clip_uint8(pixels[0] + block[0]);
+ pixels[1] = av_clip_uint8(pixels[1] + block[1]);
+ pixels += line_size;
+ block += 8;
+ }
+}
+
+static void ff_jref_idct4_put(uint8_t *dest, int line_size, int16_t *block)
+{
+ ff_j_rev_dct4 (block);
+ put_pixels_clamped4_c(block, dest, line_size);
+}
+static void ff_jref_idct4_add(uint8_t *dest, int line_size, int16_t *block)
+{
+ ff_j_rev_dct4 (block);
+ add_pixels_clamped4_c(block, dest, line_size);
+}
+
+static void ff_jref_idct2_put(uint8_t *dest, int line_size, int16_t *block)
+{
+ ff_j_rev_dct2 (block);
+ put_pixels_clamped2_c(block, dest, line_size);
+}
+static void ff_jref_idct2_add(uint8_t *dest, int line_size, int16_t *block)
+{
+ ff_j_rev_dct2 (block);
+ add_pixels_clamped2_c(block, dest, line_size);
+}
+
+static void ff_jref_idct1_put(uint8_t *dest, int line_size, int16_t *block)
+{
+ dest[0] = av_clip_uint8((block[0] + 4)>>3);
+}
+static void ff_jref_idct1_add(uint8_t *dest, int line_size, int16_t *block)
+{
+ dest[0] = av_clip_uint8(dest[0] + ((block[0] + 4)>>3));
+}
+
av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx)
{
const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (avctx->bits_per_raw_sample == 10) {
- c->idct_put = ff_simple_idct_put_10;
- c->idct_add = ff_simple_idct_add_10;
- c->idct = ff_simple_idct_10;
+ if (avctx->lowres==1) {
+ c->idct_put = ff_jref_idct4_put;
+ c->idct_add = ff_jref_idct4_add;
+ c->idct = ff_j_rev_dct4;
c->perm_type = FF_IDCT_PERM_NONE;
- } else if (avctx->idct_algo == FF_IDCT_INT) {
- c->idct_put = ff_jref_idct_put;
- c->idct_add = ff_jref_idct_add;
- c->idct = ff_j_rev_dct;
- c->perm_type = FF_IDCT_PERM_LIBMPEG2;
-#if CONFIG_FAANIDCT
- } else if (avctx->idct_algo == FF_IDCT_FAAN) {
- c->idct_put = ff_faanidct_put;
- c->idct_add = ff_faanidct_add;
- c->idct = ff_faanidct;
+ } else if (avctx->lowres==2) {
+ c->idct_put = ff_jref_idct2_put;
+ c->idct_add = ff_jref_idct2_add;
+ c->idct = ff_j_rev_dct2;
c->perm_type = FF_IDCT_PERM_NONE;
-#endif /* CONFIG_FAANIDCT */
- } else { // accurate/default
- c->idct_put = ff_simple_idct_put_8;
- c->idct_add = ff_simple_idct_add_8;
- c->idct = ff_simple_idct_8;
+ } else if (avctx->lowres==3) {
+ c->idct_put = ff_jref_idct1_put;
+ c->idct_add = ff_jref_idct1_add;
+ c->idct = ff_j_rev_dct1;
c->perm_type = FF_IDCT_PERM_NONE;
+ } else {
+ if (avctx->bits_per_raw_sample == 10 || avctx->bits_per_raw_sample == 9) {
+ c->idct_put = ff_simple_idct_put_10;
+ c->idct_add = ff_simple_idct_add_10;
+ c->idct = ff_simple_idct_10;
+ c->perm_type = FF_IDCT_PERM_NONE;
+ } else if (avctx->bits_per_raw_sample == 12) {
+ c->idct_put = ff_simple_idct_put_12;
+ c->idct_add = ff_simple_idct_add_12;
+ c->idct = ff_simple_idct_12;
+ c->perm_type = FF_IDCT_PERM_NONE;
+ } else {
+ if (avctx->idct_algo == FF_IDCT_INT) {
+ c->idct_put = ff_jref_idct_put;
+ c->idct_add = ff_jref_idct_add;
+ c->idct = ff_j_rev_dct;
+ c->perm_type = FF_IDCT_PERM_LIBMPEG2;
+#if CONFIG_FAANIDCT
+ } else if (avctx->idct_algo == FF_IDCT_FAAN) {
+ c->idct_put = ff_faanidct_put;
+ c->idct_add = ff_faanidct_add;
+ c->idct = ff_faanidct;
+ c->perm_type = FF_IDCT_PERM_NONE;
+#endif /* CONFIG_FAANIDCT */
+ } else { // accurate/default
+ c->idct_put = ff_simple_idct_put_8;
+ c->idct_add = ff_simple_idct_add_8;
+ c->idct = ff_simple_idct_8;
+ c->perm_type = FF_IDCT_PERM_NONE;
+ }
+ }
}
c->put_pixels_clamped = put_pixels_clamped_c;
c->put_signed_pixels_clamped = put_signed_pixels_clamped_c;
c->add_pixels_clamped = add_pixels_clamped_c;
- ff_put_pixels_clamped = c->put_pixels_clamped;
- ff_add_pixels_clamped = c->add_pixels_clamped;
+ if (CONFIG_MPEG4_DECODER && avctx->idct_algo == FF_IDCT_XVID)
+ ff_xvid_idct_init(c, avctx);
+ if (ARCH_ALPHA)
+ ff_idctdsp_init_alpha(c, avctx, high_bit_depth);
if (ARCH_ARM)
ff_idctdsp_init_arm(c, avctx, high_bit_depth);
if (ARCH_PPC)
@@ -186,6 +306,9 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx)
if (ARCH_X86)
ff_idctdsp_init_x86(c, avctx, high_bit_depth);
+ ff_put_pixels_clamped = c->put_pixels_clamped;
+ ff_add_pixels_clamped = c->add_pixels_clamped;
+
ff_init_scantable_permutation(c->idct_permutation,
c->perm_type);
}
diff --git a/libavcodec/idctdsp.h b/libavcodec/idctdsp.h
index c49a4ca15a..538b71669c 100644
--- a/libavcodec/idctdsp.h
+++ b/libavcodec/idctdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,13 +52,13 @@ typedef struct IDCTDSPContext {
/* pixel ops : interface with DCT */
void (*put_pixels_clamped)(const int16_t *block /* align 16 */,
uint8_t *pixels /* align 8 */,
- int line_size);
+ ptrdiff_t line_size);
void (*put_signed_pixels_clamped)(const int16_t *block /* align 16 */,
uint8_t *pixels /* align 8 */,
- int line_size);
+ ptrdiff_t line_size);
void (*add_pixels_clamped)(const int16_t *block /* align 16 */,
uint8_t *pixels /* align 8 */,
- int line_size);
+ ptrdiff_t line_size);
void (*idct)(int16_t *block /* align 16 */);
@@ -95,11 +95,13 @@ typedef struct IDCTDSPContext {
enum idct_permutation_type perm_type;
} IDCTDSPContext;
-extern void (*ff_put_pixels_clamped)(const int16_t *block, uint8_t *pixels, int line_size);
-extern void (*ff_add_pixels_clamped)(const int16_t *block, uint8_t *pixels, int line_size);
+extern void (*ff_put_pixels_clamped)(const int16_t *block, uint8_t *pixels, ptrdiff_t line_size);
+extern void (*ff_add_pixels_clamped)(const int16_t *block, uint8_t *pixels, ptrdiff_t line_size);
void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx);
+void ff_idctdsp_init_alpha(IDCTDSPContext *c, AVCodecContext *avctx,
+ unsigned high_bit_depth);
void ff_idctdsp_init_arm(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth);
void ff_idctdsp_init_ppc(IDCTDSPContext *c, AVCodecContext *avctx,
diff --git a/libavcodec/iff.c b/libavcodec/iff.c
index 92c3764462..03bb3f5bed 100644
--- a/libavcodec/iff.c
+++ b/libavcodec/iff.c
@@ -1,28 +1,28 @@
/*
- * IFF PBM/ILBM bitmap decoder
+ * IFF ACBM/DEEP/ILBM/PBM bitmap decoder
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
* Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * IFF PBM/ILBM bitmap decoder
+ * IFF ACBM/DEEP/ILBM/PBM bitmap decoder
*/
#include <stdint.h>
@@ -33,11 +33,30 @@
#include "get_bits.h"
#include "internal.h"
+// TODO: masking bits
+typedef enum {
+ MASK_NONE,
+ MASK_HAS_MASK,
+ MASK_HAS_TRANSPARENT_COLOR,
+ MASK_LASSO
+} mask_type;
+
typedef struct IffContext {
AVFrame *frame;
int planesize;
uint8_t * planebuf;
+ uint8_t * ham_buf; ///< temporary buffer for planar to chunky conversation
+ uint32_t *ham_palbuf; ///< HAM decode table
+ uint32_t *mask_buf; ///< temporary buffer for palette indices
+ uint32_t *mask_palbuf; ///< masking palette table
+ unsigned compression; ///< delta compression method used
+ unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM)
+ unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise)
+ unsigned flags; ///< 1 for EHB, 0 is no extra half darkening
+ unsigned transparency; ///< TODO: transparency color index in palette
+ unsigned masking; ///< TODO: masking method used
int init; // 1 if buffer and palette data already initialized, 0 otherwise
+ int16_t tvdc[16]; ///< TVDC lookup table
} IffContext;
#define LUT8_PART(plane, v) \
@@ -124,25 +143,180 @@ static av_always_inline uint32_t gray2rgb(const uint32_t x) {
*/
static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal)
{
+ IffContext *s = avctx->priv_data;
int count, i;
+ const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
+ int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
if (avctx->bits_per_coded_sample > 8) {
- av_log(avctx, AV_LOG_ERROR, "bit_per_coded_sample > 8 not supported\n");
+ av_log(avctx, AV_LOG_ERROR, "bits_per_coded_sample > 8 not supported\n");
return AVERROR_INVALIDDATA;
}
count = 1 << avctx->bits_per_coded_sample;
// If extradata is smaller than actually needed, fill the remaining with black.
- count = FFMIN(avctx->extradata_size / 3, count);
+ count = FFMIN(palette_size / 3, count);
if (count) {
for (i = 0; i < count; i++)
- pal[i] = 0xFF000000 | AV_RB24(avctx->extradata + i * 3);
+ pal[i] = 0xFF000000 | AV_RB24(palette + i*3);
+ if (s->flags && count >= 32) { // EHB
+ for (i = 0; i < 32; i++)
+ pal[i + 32] = 0xFF000000 | (AV_RB24(palette + i*3) & 0xFEFEFE) >> 1;
+ count = FFMAX(count, 64);
+ }
} else { // Create gray-scale color palette for bps < 8
count = 1 << avctx->bits_per_coded_sample;
for (i = 0; i < count; i++)
pal[i] = 0xFF000000 | gray2rgb((i * 255) >> avctx->bits_per_coded_sample);
}
+ if (s->masking == MASK_HAS_MASK) {
+ memcpy(pal + (1 << avctx->bits_per_coded_sample), pal, count * 4);
+ for (i = 0; i < count; i++)
+ pal[i] &= 0xFFFFFF;
+ } else if (s->masking == MASK_HAS_TRANSPARENT_COLOR &&
+ s->transparency < 1 << avctx->bits_per_coded_sample)
+ pal[s->transparency] &= 0xFFFFFF;
+ return 0;
+}
+
+/**
+ * Extracts the IFF extra context and updates internal
+ * decoder structures.
+ *
+ * @param avctx the AVCodecContext where to extract extra context to
+ * @param avpkt the AVPacket to extract extra context from or NULL to use avctx
+ * @return >= 0 in case of success, a negative error code otherwise
+ */
+static int extract_header(AVCodecContext *const avctx,
+ const AVPacket *const avpkt) {
+ const uint8_t *buf;
+ unsigned buf_size;
+ IffContext *s = avctx->priv_data;
+ int i, palette_size;
+
+ if (avctx->extradata_size < 2) {
+ av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
+
+ if (avpkt) {
+ int image_size;
+ if (avpkt->size < 2)
+ return AVERROR_INVALIDDATA;
+ image_size = avpkt->size - AV_RB16(avpkt->data);
+ buf = avpkt->data;
+ buf_size = bytestream_get_be16(&buf);
+ if (buf_size <= 1 || image_size <= 1) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid image size received: %u -> image data offset: %d\n",
+ buf_size, image_size);
+ return AVERROR_INVALIDDATA;
+ }
+ } else {
+ buf = avctx->extradata;
+ buf_size = bytestream_get_be16(&buf);
+ if (buf_size <= 1 || palette_size < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid palette size received: %u -> palette data offset: %d\n",
+ buf_size, palette_size);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (buf_size >= 41) {
+ s->compression = bytestream_get_byte(&buf);
+ s->bpp = bytestream_get_byte(&buf);
+ s->ham = bytestream_get_byte(&buf);
+ s->flags = bytestream_get_byte(&buf);
+ s->transparency = bytestream_get_be16(&buf);
+ s->masking = bytestream_get_byte(&buf);
+ for (i = 0; i < 16; i++)
+ s->tvdc[i] = bytestream_get_be16(&buf);
+
+ if (s->masking == MASK_HAS_MASK) {
+ if (s->bpp >= 8 && !s->ham) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ av_freep(&s->mask_buf);
+ av_freep(&s->mask_palbuf);
+ s->mask_buf = av_malloc((s->planesize * 32) + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->mask_buf)
+ return AVERROR(ENOMEM);
+ if (s->bpp > 16) {
+ av_log(avctx, AV_LOG_ERROR, "bpp %d too large for palette\n", s->bpp);
+ av_freep(&s->mask_buf);
+ return AVERROR(ENOMEM);
+ }
+ s->mask_palbuf = av_malloc((2 << s->bpp) * sizeof(uint32_t) + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->mask_palbuf) {
+ av_freep(&s->mask_buf);
+ return AVERROR(ENOMEM);
+ }
+ }
+ s->bpp++;
+ } else if (s->masking != MASK_NONE && s->masking != MASK_HAS_TRANSPARENT_COLOR) {
+ av_log(avctx, AV_LOG_ERROR, "Masking not supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (!s->bpp || s->bpp > 32) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of bitplanes: %u\n", s->bpp);
+ return AVERROR_INVALIDDATA;
+ } else if (s->ham >= 8) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham);
+ return AVERROR_INVALIDDATA;
+ }
+
+ av_freep(&s->ham_buf);
+ av_freep(&s->ham_palbuf);
+
+ if (s->ham) {
+ int i, count = FFMIN(palette_size / 3, 1 << s->ham);
+ int ham_count;
+ const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
+
+ s->ham_buf = av_malloc((s->planesize * 8) + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->ham_buf)
+ return AVERROR(ENOMEM);
+
+ ham_count = 8 * (1 << s->ham);
+ s->ham_palbuf = av_malloc((ham_count << !!(s->masking == MASK_HAS_MASK)) * sizeof (uint32_t) + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->ham_palbuf) {
+ av_freep(&s->ham_buf);
+ return AVERROR(ENOMEM);
+ }
+
+ if (count) { // HAM with color palette attached
+ // prefill with black and palette and set HAM take direct value mask to zero
+ memset(s->ham_palbuf, 0, (1 << s->ham) * 2 * sizeof (uint32_t));
+ for (i=0; i < count; i++) {
+ s->ham_palbuf[i*2+1] = 0xFF000000 | AV_RL24(palette + i*3);
+ }
+ count = 1 << s->ham;
+ } else { // HAM with grayscale color palette
+ count = 1 << s->ham;
+ for (i=0; i < count; i++) {
+ s->ham_palbuf[i*2] = 0xFF000000; // take direct color value from palette
+ s->ham_palbuf[i*2+1] = 0xFF000000 | av_le2ne32(gray2rgb((i * 255) >> s->ham));
+ }
+ }
+ for (i=0; i < count; i++) {
+ uint32_t tmp = i << (8 - s->ham);
+ tmp |= tmp >> s->ham;
+ s->ham_palbuf[(i+count)*2] = 0xFF00FFFF; // just modify blue color component
+ s->ham_palbuf[(i+count*2)*2] = 0xFFFFFF00; // just modify red color component
+ s->ham_palbuf[(i+count*3)*2] = 0xFFFF00FF; // just modify green color component
+ s->ham_palbuf[(i+count)*2+1] = 0xFF000000 | tmp << 16;
+ s->ham_palbuf[(i+count*2)*2+1] = 0xFF000000 | tmp;
+ s->ham_palbuf[(i+count*3)*2+1] = 0xFF000000 | tmp << 8;
+ }
+ if (s->masking == MASK_HAS_MASK) {
+ for (i = 0; i < ham_count; i++)
+ s->ham_palbuf[(1 << s->bpp) + i] = s->ham_palbuf[i] | 0xFF000000;
+ }
+ }
+ }
+
return 0;
}
@@ -151,6 +325,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
IffContext *s = avctx->priv_data;
av_frame_free(&s->frame);
av_freep(&s->planebuf);
+ av_freep(&s->ham_buf);
+ av_freep(&s->ham_palbuf);
return 0;
}
@@ -160,11 +336,29 @@ static av_cold int decode_init(AVCodecContext *avctx)
int err;
if (avctx->bits_per_coded_sample <= 8) {
- avctx->pix_fmt = (avctx->bits_per_coded_sample < 8 ||
- avctx->extradata_size) ? AV_PIX_FMT_PAL8
- : AV_PIX_FMT_GRAY8;
+ int palette_size;
+
+ if (avctx->extradata_size >= 2)
+ palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
+ else
+ palette_size = 0;
+ avctx->pix_fmt = (avctx->bits_per_coded_sample < 8) ||
+ (avctx->extradata_size >= 2 && palette_size) ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8;
} else if (avctx->bits_per_coded_sample <= 32) {
- avctx->pix_fmt = AV_PIX_FMT_BGR32;
+ if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8')) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ } else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N')) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB444;
+ } else if (avctx->codec_tag != MKTAG('D', 'E', 'E', 'P')) {
+ if (avctx->bits_per_coded_sample == 24) {
+ avctx->pix_fmt = AV_PIX_FMT_0BGR32;
+ } else if (avctx->bits_per_coded_sample == 32) {
+ avctx->pix_fmt = AV_PIX_FMT_BGR32;
+ } else {
+ avpriv_request_sample(avctx, "unknown bits_per_coded_sample");
+ return AVERROR_PATCHWELCOME;
+ }
+ }
} else {
return AVERROR_INVALIDDATA;
}
@@ -176,12 +370,16 @@ static av_cold int decode_init(AVCodecContext *avctx)
if (!s->planebuf)
return AVERROR(ENOMEM);
+ s->bpp = avctx->bits_per_coded_sample;
s->frame = av_frame_alloc();
if (!s->frame) {
decode_end(avctx);
return AVERROR(ENOMEM);
}
+ if ((err = extract_header(avctx, NULL)) < 0)
+ return err;
+
return 0;
}
@@ -195,6 +393,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
static void decodeplane8(uint8_t *dst, const uint8_t *buf, int buf_size, int plane)
{
const uint64_t *lut = plane8_lut[plane];
+ if (plane >= 8) {
+ av_log(NULL, AV_LOG_WARNING, "Ignoring extra planes beyond 8\n");
+ return;
+ }
do {
uint64_t v = AV_RN64A(dst) | lut[*buf++];
AV_WN64A(dst, v);
@@ -227,6 +429,47 @@ static void decodeplane32(uint32_t *dst, const uint8_t *buf, int buf_size, int p
} while (--buf_size);
}
+#define DECODE_HAM_PLANE32(x) \
+ first = buf[x] << 1; \
+ second = buf[(x)+1] << 1; \
+ delta &= pal[first++]; \
+ delta |= pal[first]; \
+ dst[x] = delta; \
+ delta &= pal[second++]; \
+ delta |= pal[second]; \
+ dst[(x)+1] = delta
+
+/**
+ * Converts one line of HAM6/8-encoded chunky buffer to 24bpp.
+ *
+ * @param dst the destination 24bpp buffer
+ * @param buf the source 8bpp chunky buffer
+ * @param pal the HAM decode table
+ * @param buf_size the plane size in bytes
+ */
+static void decode_ham_plane32(uint32_t *dst, const uint8_t *buf,
+ const uint32_t *const pal, unsigned buf_size)
+{
+ uint32_t delta = pal[1]; /* first palette entry */
+ do {
+ uint32_t first, second;
+ DECODE_HAM_PLANE32(0);
+ DECODE_HAM_PLANE32(2);
+ DECODE_HAM_PLANE32(4);
+ DECODE_HAM_PLANE32(6);
+ buf += 8;
+ dst += 8;
+ } while (--buf_size);
+}
+
+static void lookup_pal_indicies(uint32_t *dst, const uint32_t *buf,
+ const uint32_t *const pal, unsigned width)
+{
+ do {
+ *dst++ = pal[*buf++];
+ } while (--width);
+}
+
/**
* Decode one complete byterun1 encoded line.
*
@@ -245,124 +488,385 @@ static int decode_byterun(uint8_t *dst, int dst_size,
unsigned length;
const int8_t value = *buf++;
if (value >= 0) {
- length = value + 1;
- memcpy(dst + x, buf, FFMIN3(length, dst_size - x, buf_end - buf));
+ length = FFMIN3(value + 1, dst_size - x, buf_end - buf);
+ memcpy(dst + x, buf, length);
buf += length;
} else if (value > -128) {
- length = -value + 1;
- memset(dst + x, *buf++, FFMIN(length, dst_size - x));
+ length = FFMIN(-value + 1, dst_size - x);
+ memset(dst + x, *buf++, length);
} else { // noop
continue;
}
x += length;
}
+ if (x < dst_size) {
+ av_log(NULL, AV_LOG_WARNING, "decode_byterun ended before plane size\n");
+ memset(dst+x, 0, dst_size - x);
+ }
return buf - buf_start;
}
-static int decode_frame_ilbm(AVCodecContext *avctx,
- void *data, int *got_frame,
- AVPacket *avpkt)
-{
- IffContext *s = avctx->priv_data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
- const uint8_t *buf_end = buf + buf_size;
- int y, plane, res;
+#define DECODE_RGBX_COMMON(type) \
+ if (!length) { \
+ length = bytestream2_get_byte(gb); \
+ if (!length) { \
+ length = bytestream2_get_be16(gb); \
+ if (!length) \
+ return; \
+ } \
+ } \
+ for (i = 0; i < length; i++) { \
+ *(type *)(dst + y*linesize + x * sizeof(type)) = pixel; \
+ x += 1; \
+ if (x >= width) { \
+ y += 1; \
+ if (y >= height) \
+ return; \
+ x = 0; \
+ } \
+ }
- if ((res = ff_reget_buffer(avctx, s->frame)) < 0)
- return res;
+/**
+ * Decode RGB8 buffer
+ * @param[out] dst Destination buffer
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ */
+static void decode_rgb8(GetByteContext *gb, uint8_t *dst, int width, int height, int linesize)
+{
+ int x = 0, y = 0, i, length;
+ while (bytestream2_get_bytes_left(gb) >= 4) {
+ uint32_t pixel = 0xFF000000 | bytestream2_get_be24(gb);
+ length = bytestream2_get_byte(gb) & 0x7F;
+ DECODE_RGBX_COMMON(uint32_t)
+ }
+}
- if (!s->init && avctx->bits_per_coded_sample <= 8 &&
- avctx->pix_fmt != AV_PIX_FMT_GRAY8) {
- if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0)
- return res;
+/**
+ * Decode RGBN buffer
+ * @param[out] dst Destination buffer
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ */
+static void decode_rgbn(GetByteContext *gb, uint8_t *dst, int width, int height, int linesize)
+{
+ int x = 0, y = 0, i, length;
+ while (bytestream2_get_bytes_left(gb) >= 2) {
+ uint32_t pixel = bytestream2_get_be16u(gb);
+ length = pixel & 0x7;
+ pixel >>= 4;
+ DECODE_RGBX_COMMON(uint16_t)
}
- s->init = 1;
+}
- if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved
- 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 = &s->frame->data[0][y * s->frame->linesize[0]];
- memset(row, 0, avctx->width);
- for (plane = 0; plane < avctx->bits_per_coded_sample && buf < buf_end;
- plane++) {
- decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
- buf += s->planesize;
+/**
+ * Decode DEEP RLE 32-bit buffer
+ * @param[out] dst Destination buffer
+ * @param[in] src Source buffer
+ * @param src_size Source buffer size (bytes)
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ */
+static void decode_deep_rle32(uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize)
+{
+ const uint8_t *src_end = src + src_size;
+ int x = 0, y = 0, i;
+ while (src + 5 <= src_end) {
+ int opcode;
+ opcode = *(int8_t *)src++;
+ if (opcode >= 0) {
+ int size = opcode + 1;
+ for (i = 0; i < size; i++) {
+ int length = FFMIN(size - i, width);
+ memcpy(dst + y*linesize + x * 4, src, length * 4);
+ src += length * 4;
+ x += length;
+ i += length;
+ if (x >= width) {
+ x = 0;
+ y += 1;
+ if (y >= height)
+ return;
}
}
- } else { // AV_PIX_FMT_BGR32
- for (y = 0; y < avctx->height; y++) {
- uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- memset(row, 0, avctx->width << 2);
- for (plane = 0; plane < avctx->bits_per_coded_sample && buf < buf_end;
- plane++) {
- decodeplane32((uint32_t *)row, buf,
- FFMIN(s->planesize, buf_end - buf), plane);
- buf += s->planesize;
+ } else {
+ int size = -opcode + 1;
+ uint32_t pixel = AV_RN32(src);
+ for (i = 0; i < size; i++) {
+ *(uint32_t *)(dst + y*linesize + x * 4) = pixel;
+ x += 1;
+ if (x >= width) {
+ x = 0;
+ y += 1;
+ if (y >= height)
+ return;
}
}
- }
- } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) { // IFF-PBM
- for (y = 0; y < avctx->height && buf < buf_end; y++) {
- uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- memcpy(row, buf, FFMIN(avctx->width, buf_end - buf));
- buf += avctx->width + (avctx->width % 2); // padding if odd
+ src += 4;
}
}
+}
- if ((res = av_frame_ref(data, s->frame)) < 0)
- return res;
-
- *got_frame = 1;
+/**
+ * Decode DEEP TVDC 32-bit buffer
+ * @param[out] dst Destination buffer
+ * @param[in] src Source buffer
+ * @param src_size Source buffer size (bytes)
+ * @param width Width of destination buffer (pixels)
+ * @param height Height of destination buffer (pixels)
+ * @param linesize Line size of destination buffer (bytes)
+ * @param[int] tvdc TVDC lookup table
+ */
+static void decode_deep_tvdc32(uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize, const int16_t *tvdc)
+{
+ int x = 0, y = 0, plane = 0;
+ int8_t pixel = 0;
+ int i, j;
+
+ for (i = 0; i < src_size * 2;) {
+#define GETNIBBLE ((i & 1) ? (src[i>>1] & 0xF) : (src[i>>1] >> 4))
+ int d = tvdc[GETNIBBLE];
+ i++;
+ if (d) {
+ pixel += d;
+ dst[y * linesize + x*4 + plane] = pixel;
+ x++;
+ } else {
+ if (i >= src_size * 2)
+ return;
+ d = GETNIBBLE + 1;
+ i++;
+ d = FFMIN(d, width - x);
+ for (j = 0; j < d; j++) {
+ dst[y * linesize + x*4 + plane] = pixel;
+ x++;
+ }
+ }
+ if (x >= width) {
+ plane++;
+ if (plane >= 4) {
+ y++;
+ if (y >= height)
+ return;
+ plane = 0;
+ }
+ x = 0;
+ pixel = 0;
+ i = (i + 1) & ~1;
+ }
+ }
+}
- return buf_size;
+static int unsupported(AVCodecContext *avctx)
+{
+ IffContext *s = avctx->priv_data;
+ avpriv_request_sample(avctx, "bitmap (compression %i, bpp %i, ham %i)", s->compression, s->bpp, s->ham);
+ return AVERROR_INVALIDDATA;
}
-static int decode_frame_byterun1(AVCodecContext *avctx,
- void *data, int *got_frame,
- AVPacket *avpkt)
+static int decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
{
IffContext *s = avctx->priv_data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
+ const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL;
+ const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0;
const uint8_t *buf_end = buf + buf_size;
int y, plane, res;
+ GetByteContext gb;
+ const AVPixFmtDescriptor *desc;
+ if ((res = extract_header(avctx, avpkt)) < 0)
+ return res;
if ((res = ff_reget_buffer(avctx, s->frame)) < 0)
return res;
+ desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+
if (!s->init && avctx->bits_per_coded_sample <= 8 &&
- avctx->pix_fmt != AV_PIX_FMT_GRAY8) {
+ avctx->pix_fmt == AV_PIX_FMT_PAL8) {
if ((res = cmap_read_palette(avctx, (uint32_t *)s->frame->data[1])) < 0)
return res;
+ } else if (!s->init && avctx->bits_per_coded_sample <= 8 &&
+ avctx->pix_fmt == AV_PIX_FMT_RGB32) {
+ if ((res = cmap_read_palette(avctx, s->mask_palbuf)) < 0)
+ return res;
}
s->init = 1;
- if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved
- if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
- for (y = 0; y < avctx->height; y++) {
+ switch (s->compression) {
+ case 0:
+ if (avctx->codec_tag == MKTAG('A', 'C', 'B', 'M')) {
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
+ memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]);
+ for (plane = 0; plane < s->bpp; plane++) {
+ for (y = 0; y < avctx->height && buf < buf_end; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
+ buf += s->planesize;
+ }
+ }
+ } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32
+ memset(s->frame->data[0], 0, avctx->height * s->frame->linesize[0]);
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ memset(s->ham_buf, 0, s->planesize * 8);
+ for (plane = 0; plane < s->bpp; plane++) {
+ const uint8_t * start = buf + (plane * avctx->height + y) * s->planesize;
+ if (start >= buf_end)
+ break;
+ decodeplane8(s->ham_buf, start, FFMIN(s->planesize, buf_end - start), plane);
+ }
+ decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
+ }
+ } else
+ return unsupported(avctx);
+ } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) {
+ int raw_width = avctx->width * (av_get_bits_per_pixel(desc) >> 3);
+ int x;
+ for (y = 0; y < avctx->height && buf < buf_end; y++) {
uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- memset(row, 0, avctx->width);
- for (plane = 0; plane < avctx->bits_per_coded_sample; plane++) {
- buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
- decodeplane8(row, s->planebuf, s->planesize, plane);
+ memcpy(row, buf, FFMIN(raw_width, buf_end - buf));
+ buf += raw_width;
+ if (avctx->pix_fmt == AV_PIX_FMT_BGR32) {
+ for (x = 0; x < avctx->width; x++)
+ row[4 * x + 3] = row[4 * x + 3] & 0xF0 | (row[4 * x + 3] >> 4);
}
}
- } else { // AV_PIX_FMT_BGR32
- for (y = 0; y < avctx->height; y++) {
- uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- memset(row, 0, avctx->width << 2);
- for (plane = 0; plane < avctx->bits_per_coded_sample; plane++) {
- buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
- decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane);
+ } else if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved
+ 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 = &s->frame->data[0][y * s->frame->linesize[0]];
+ memset(row, 0, avctx->width);
+ for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
+ decodeplane8(row, buf, FFMIN(s->planesize, buf_end - buf), plane);
+ buf += s->planesize;
+ }
+ }
+ } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ memset(s->ham_buf, 0, s->planesize * 8);
+ for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
+ decodeplane8(s->ham_buf, buf, FFMIN(s->planesize, buf_end - buf), plane);
+ buf += s->planesize;
+ }
+ decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
+ }
+ } else { // AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ memset(row, 0, avctx->width << 2);
+ for (plane = 0; plane < s->bpp && buf < buf_end; plane++) {
+ decodeplane32((uint32_t *)row, buf,
+ FFMIN(s->planesize, buf_end - buf), plane);
+ buf += s->planesize;
+ }
}
}
+ } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8 || avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
+ for (y = 0; y < avctx->height && buf_end > buf; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ memcpy(row, buf, FFMIN(avctx->width, buf_end - buf));
+ buf += avctx->width + (avctx->width % 2); // padding if odd
+ }
+ } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height && buf_end > buf; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ memcpy(s->ham_buf, buf, FFMIN(avctx->width, buf_end - buf));
+ buf += avctx->width + (avctx->width & 1); // padding if odd
+ decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
+ }
+ } else
+ return unsupported(avctx);
}
- } else {
- for (y = 0; y < avctx->height; y++) {
- uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
- buf += decode_byterun(row, avctx->width, buf, buf_end);
+ break;
+ case 1:
+ if (avctx->codec_tag == MKTAG('I', 'L', 'B', 'M')) { // interleaved
+ 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 = &s->frame->data[0][y * s->frame->linesize[0]];
+ memset(row, 0, avctx->width);
+ for (plane = 0; plane < s->bpp; plane++) {
+ buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
+ decodeplane8(row, s->planebuf, s->planesize, plane);
+ }
+ }
+ } else if (avctx->bits_per_coded_sample <= 8) { //8-bit (+ mask) to AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->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, buf, buf_end);
+ decodeplane32(s->mask_buf, s->planebuf, s->planesize, plane);
+ }
+ lookup_pal_indicies((uint32_t *)row, s->mask_buf, s->mask_palbuf, avctx->width);
+ }
+ } else if (s->ham) { // HAM to AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->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, buf, buf_end);
+ decodeplane8(s->ham_buf, s->planebuf, s->planesize, plane);
+ }
+ decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
+ }
+ } else { // AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ memset(row, 0, avctx->width << 2);
+ for (plane = 0; plane < s->bpp; plane++) {
+ buf += decode_byterun(s->planebuf, s->planesize, buf, buf_end);
+ decodeplane32((uint32_t *)row, s->planebuf, s->planesize, plane);
+ }
+ }
+ }
+ } else if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ')) { // IFF-PBM
+ 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 = &s->frame->data[0][y * s->frame->linesize[0]];
+ buf += decode_byterun(row, avctx->width, buf, buf_end);
+ }
+ } else if (s->ham) { // IFF-PBM: HAM to AV_PIX_FMT_BGR32
+ for (y = 0; y < avctx->height; y++) {
+ uint8_t *row = &s->frame->data[0][y * s->frame->linesize[0]];
+ buf += decode_byterun(s->ham_buf, avctx->width, buf, buf_end);
+ decode_ham_plane32((uint32_t *)row, s->ham_buf, s->ham_palbuf, s->planesize);
+ }
+ } else
+ return unsupported(avctx);
+ } else if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) { // IFF-DEEP
+ if (av_get_bits_per_pixel(desc) == 32)
+ decode_deep_rle32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0]);
+ else
+ return unsupported(avctx);
}
+ break;
+ case 4:
+ bytestream2_init(&gb, buf, buf_size);
+ if (avctx->codec_tag == MKTAG('R', 'G', 'B', '8') && avctx->pix_fmt == AV_PIX_FMT_RGB32)
+ decode_rgb8(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]);
+ else if (avctx->codec_tag == MKTAG('R', 'G', 'B', 'N') && avctx->pix_fmt == AV_PIX_FMT_RGB444)
+ decode_rgbn(&gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]);
+ else
+ return unsupported(avctx);
+ break;
+ case 5:
+ if (avctx->codec_tag == MKTAG('D', 'E', 'E', 'P')) {
+ if (av_get_bits_per_pixel(desc) == 32)
+ decode_deep_tvdc32(s->frame->data[0], buf, buf_size, avctx->width, avctx->height, s->frame->linesize[0], s->tvdc);
+ else
+ return unsupported(avctx);
+ } else
+ return unsupported(avctx);
+ break;
+ default:
+ return unsupported(avctx);
}
if ((res = av_frame_ref(data, s->frame)) < 0)
@@ -373,26 +877,29 @@ static int decode_frame_byterun1(AVCodecContext *avctx,
return buf_size;
}
+#if CONFIG_IFF_ILBM_DECODER
AVCodec ff_iff_ilbm_decoder = {
- .name = "iff_ilbm",
- .long_name = NULL_IF_CONFIG_SMALL("IFF ILBM"),
+ .name = "iff",
+ .long_name = NULL_IF_CONFIG_SMALL("IFF"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_IFF_ILBM,
.priv_data_size = sizeof(IffContext),
.init = decode_init,
.close = decode_end,
- .decode = decode_frame_ilbm,
+ .decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
-
+#endif
+#if CONFIG_IFF_BYTERUN1_DECODER
AVCodec ff_iff_byterun1_decoder = {
- .name = "iff_byterun1",
- .long_name = NULL_IF_CONFIG_SMALL("IFF ByteRun1"),
+ .name = "iff",
+ .long_name = NULL_IF_CONFIG_SMALL("IFF"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_IFF_BYTERUN1,
.priv_data_size = sizeof(IffContext),
.init = decode_init,
.close = decode_end,
- .decode = decode_frame_byterun1,
+ .decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+#endif
diff --git a/libavcodec/iirfilter.c b/libavcodec/iirfilter.c
index 40a543da4c..cb5871cb29 100644
--- a/libavcodec/iirfilter.c
+++ b/libavcodec/iirfilter.c
@@ -2,20 +2,20 @@
* IIR filter
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -196,7 +196,7 @@ av_cold struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc,
return c;
init_fail:
- ff_iir_filter_free_coeffs(c);
+ ff_iir_filter_free_coeffsp(&c);
return NULL;
}
@@ -299,18 +299,26 @@ void ff_iir_filter_flt(const struct FFIIRFilterCoeffs *c,
}
}
-av_cold void ff_iir_filter_free_state(struct FFIIRFilterState *state)
+av_cold void ff_iir_filter_free_statep(struct FFIIRFilterState **state)
{
- av_free(state);
+ av_freep(state);
}
-av_cold void ff_iir_filter_free_coeffs(struct FFIIRFilterCoeffs *coeffs)
+av_cold void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffsp)
{
+ struct FFIIRFilterCoeffs *coeffs = *coeffsp;
if(coeffs){
- av_free(coeffs->cx);
- av_free(coeffs->cy);
+ av_freep(&coeffs->cx);
+ av_freep(&coeffs->cy);
}
- av_free(coeffs);
+ av_freep(coeffsp);
+}
+
+void ff_iir_filter_init(FFIIRFilterContext *f) {
+ f->filter_flt = ff_iir_filter_flt;
+
+ if (HAVE_MIPSFPU)
+ ff_iir_filter_init_mips(f);
}
#ifdef TEST
@@ -340,8 +348,8 @@ int main(void)
for (i = 0; i < SIZE; i++)
printf("%6d %6d\n", x[i], y[i]);
- ff_iir_filter_free_coeffs(fcoeffs);
- ff_iir_filter_free_state(fstate);
+ ff_iir_filter_free_coeffsp(&fcoeffs);
+ ff_iir_filter_free_statep(&fstate);
return 0;
}
#endif /* TEST */
diff --git a/libavcodec/iirfilter.h b/libavcodec/iirfilter.h
index bc65a96b59..6f7bba67ac 100644
--- a/libavcodec/iirfilter.h
+++ b/libavcodec/iirfilter.h
@@ -2,20 +2,20 @@
* IIR filter
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,6 +47,29 @@ enum IIRFilterMode{
FF_FILTER_MODE_BANDSTOP,
};
+typedef struct FFIIRFilterContext {
+ /**
+ * Perform IIR filtering on floating-point input samples.
+ *
+ * @param coeffs pointer to filter coefficients
+ * @param state pointer to filter state
+ * @param size input length
+ * @param src source samples
+ * @param sstep source stride
+ * @param dst filtered samples (destination may be the same as input)
+ * @param dstep destination stride
+ */
+ void (*filter_flt)(const struct FFIIRFilterCoeffs *coeffs,
+ struct FFIIRFilterState *state, int size,
+ const float *src, int sstep, float *dst, int dstep);
+} FFIIRFilterContext;
+
+/**
+ * Initialize FFIIRFilterContext
+ */
+void ff_iir_filter_init(FFIIRFilterContext *f);
+void ff_iir_filter_init_mips(FFIIRFilterContext *f);
+
/**
* Initialize filter coefficients.
*
@@ -81,14 +104,14 @@ struct FFIIRFilterState* ff_iir_filter_init_state(int order);
*
* @param coeffs pointer allocated with ff_iir_filter_init_coeffs()
*/
-void ff_iir_filter_free_coeffs(struct FFIIRFilterCoeffs *coeffs);
+void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffs);
/**
- * Free filter state.
+ * Free and zero filter state.
*
- * @param state pointer allocated with ff_iir_filter_init_state()
+ * @param state pointer to pointer allocated with ff_iir_filter_init_state()
*/
-void ff_iir_filter_free_state(struct FFIIRFilterState *state);
+void ff_iir_filter_free_statep(struct FFIIRFilterState **state);
/**
* Perform IIR filtering on signed 16-bit input samples.
diff --git a/libavcodec/imc.c b/libavcodec/imc.c
index 411bc85b74..2fa910a5e5 100644
--- a/libavcodec/imc.c
+++ b/libavcodec/imc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006 Benjamin Larsson
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,6 +38,7 @@
#include "libavutil/channel_layout.h"
#include "libavutil/float_dsp.h"
#include "libavutil/internal.h"
+#include "libavutil/libm.h"
#include "avcodec.h"
#include "bswapdsp.h"
#include "get_bits.h"
@@ -95,7 +96,7 @@ typedef struct IMCContext {
GetBitContext gb;
BswapDSPContext bdsp;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext fft;
DECLARE_ALIGNED(32, FFTComplex, samples)[COEFFS / 2];
float *out_samples;
@@ -179,6 +180,14 @@ static av_cold int imc_decode_init(AVCodecContext *avctx)
IMCContext *q = avctx->priv_data;
double r1, r2;
+ if (avctx->codec_id == AV_CODEC_ID_IAC && avctx->sample_rate > 96000) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Strange sample rate of %i, file likely corrupt or "
+ "needing a new table derivation method.\n",
+ avctx->sample_rate);
+ return AVERROR_PATCHWELCOME;
+ }
+
if (avctx->codec_id == AV_CODEC_ID_IMC)
avctx->channels = 1;
@@ -247,7 +256,13 @@ static av_cold int imc_decode_init(AVCodecContext *avctx)
return ret;
}
ff_bswapdsp_init(&q->bdsp);
- avpriv_float_dsp_init(&q->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ q->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!q->fdsp) {
+ ff_fft_end(&q->fft);
+
+ return AVERROR(ENOMEM);
+ }
+
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
avctx->channel_layout = avctx->channels == 1 ? AV_CH_LAYOUT_MONO
: AV_CH_LAYOUT_STEREO;
@@ -356,7 +371,7 @@ static void imc_decode_level_coefficients(IMCContext *q, int *levlCoeffBuf,
float tmp, tmp2;
// maybe some frequency division thingy
- flcoeffs1[0] = 20000.0 / pow (2, levlCoeffBuf[0] * 0.18945); // 0.18945 = log2(10) * 0.05703125
+ flcoeffs1[0] = 20000.0 / exp2 (levlCoeffBuf[0] * 0.18945); // 0.18945 = log2(10) * 0.05703125
flcoeffs2[0] = log2f(flcoeffs1[0]);
tmp = flcoeffs1[0];
tmp2 = flcoeffs2[0];
@@ -450,8 +465,13 @@ static int bit_allocation(IMCContext *q, IMCChannel *chctx,
for (i = 0; i < BANDS; i++)
highest = FFMAX(highest, chctx->flcoeffs1[i]);
- for (i = 0; i < BANDS - 1; i++)
+ for (i = 0; i < BANDS - 1; i++) {
+ if (chctx->flcoeffs5[i] <= 0) {
+ av_log(NULL, AV_LOG_ERROR, "flcoeffs5 %f invalid\n", chctx->flcoeffs5[i]);
+ return AVERROR_INVALIDDATA;
+ }
chctx->flcoeffs4[i] = chctx->flcoeffs3[i] - log2f(chctx->flcoeffs5[i]);
+ }
chctx->flcoeffs4[BANDS - 1] = limit;
highest = highest * 0.25;
@@ -770,7 +790,8 @@ static int inverse_quant_coeff(IMCContext *q, IMCChannel *chctx,
}
-static int imc_get_coeffs(IMCContext *q, IMCChannel *chctx)
+static void imc_get_coeffs(AVCodecContext *avctx,
+ IMCContext *q, IMCChannel *chctx)
{
int i, j, cw_len, cw;
@@ -782,19 +803,19 @@ static int imc_get_coeffs(IMCContext *q, IMCChannel *chctx)
cw_len = chctx->CWlengthT[j];
cw = 0;
- if (get_bits_count(&q->gb) + cw_len > 512) {
- ff_dlog(NULL, "Band %i coeff %i cw_len %i\n", i, j, cw_len);
- return AVERROR_INVALIDDATA;
+ if (cw_len && (!chctx->bandFlagsBuf[i] || !chctx->skipFlags[j])) {
+ if (get_bits_count(&q->gb) + cw_len > 512) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Potential problem on band %i, coefficient %i"
+ ": cw_len=%i\n", i, j, cw_len);
+ } else
+ cw = get_bits(&q->gb, cw_len);
}
- if (cw_len && (!chctx->bandFlagsBuf[i] || !chctx->skipFlags[j]))
- cw = get_bits(&q->gb, cw_len);
-
chctx->codewords[j] = cw;
}
}
}
- return 0;
}
static void imc_refine_bit_allocation(IMCContext *q, IMCChannel *chctx)
@@ -887,6 +908,13 @@ static int imc_decode_block(AVCodecContext *avctx, IMCContext *q, int ch)
imc_decode_level_coefficients2(q, chctx->levlCoeffBuf, chctx->old_floor,
chctx->flcoeffs1, chctx->flcoeffs2);
+ for(i=0; i<BANDS; i++) {
+ if(chctx->flcoeffs1[i] > INT_MAX) {
+ av_log(avctx, AV_LOG_ERROR, "scalefactor out of range\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
memcpy(chctx->old_floor, chctx->flcoeffs1, 32 * sizeof(float));
counter = 0;
@@ -968,11 +996,7 @@ static int imc_decode_block(AVCodecContext *avctx, IMCContext *q, int ch)
memset(chctx->codewords, 0, sizeof(chctx->codewords));
- if (imc_get_coeffs(q, chctx) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Read coefficients failed\n");
- chctx->decoder_reset = 1;
- return AVERROR_INVALIDDATA;
- }
+ imc_get_coeffs(avctx, q, chctx);
if (inverse_quant_coeff(q, chctx, stream_format_code) < 0) {
av_log(avctx, AV_LOG_ERROR, "Inverse quantization of coefficients failed\n");
@@ -997,7 +1021,7 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data,
IMCContext *q = avctx->priv_data;
- LOCAL_ALIGNED_16(uint16_t, buf16, [IMC_BLOCK_SIZE / 2]);
+ LOCAL_ALIGNED_16(uint16_t, buf16, [IMC_BLOCK_SIZE / 2 + FF_INPUT_BUFFER_PADDING_SIZE/2]);
if (buf_size < IMC_BLOCK_SIZE * avctx->channels) {
av_log(avctx, AV_LOG_ERROR, "frame too small!\n");
@@ -1006,10 +1030,8 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = COEFFS;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
for (i = 0; i < avctx->channels; i++) {
q->out_samples = (float *)frame->extended_data[i];
@@ -1025,7 +1047,7 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data,
}
if (avctx->channels == 2) {
- q->fdsp.butterflies_float((float *)frame->extended_data[0],
+ q->fdsp->butterflies_float((float *)frame->extended_data[0],
(float *)frame->extended_data[1], COEFFS);
}
@@ -1034,17 +1056,25 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data,
return IMC_BLOCK_SIZE * avctx->channels;
}
-
static av_cold int imc_decode_close(AVCodecContext * avctx)
{
IMCContext *q = avctx->priv_data;
ff_fft_end(&q->fft);
+ av_freep(&q->fdsp);
return 0;
}
+static av_cold void flush(AVCodecContext *avctx)
+{
+ IMCContext *q = avctx->priv_data;
+
+ q->chctx[0].decoder_reset =
+ q->chctx[1].decoder_reset = 1;
+}
+#if CONFIG_IMC_DECODER
AVCodec ff_imc_decoder = {
.name = "imc",
.long_name = NULL_IF_CONFIG_SMALL("IMC (Intel Music Coder)"),
@@ -1054,11 +1084,13 @@ AVCodec ff_imc_decoder = {
.init = imc_decode_init,
.close = imc_decode_close,
.decode = imc_decode_frame,
+ .flush = flush,
.capabilities = CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
-
+#endif
+#if CONFIG_IAC_DECODER
AVCodec ff_iac_decoder = {
.name = "iac",
.long_name = NULL_IF_CONFIG_SMALL("IAC (Indeo Audio Coder)"),
@@ -1068,7 +1100,9 @@ AVCodec ff_iac_decoder = {
.init = imc_decode_init,
.close = imc_decode_close,
.decode = imc_decode_frame,
+ .flush = flush,
.capabilities = CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
+#endif
diff --git a/libavcodec/imcdata.h b/libavcodec/imcdata.h
index 8e99391d61..64e7c7185e 100644
--- a/libavcodec/imcdata.h
+++ b/libavcodec/imcdata.h
@@ -4,20 +4,20 @@
* Copyright (c) 2006 Benjamin Larsson
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/imdct15.c b/libavcodec/imdct15.c
index e02e9cedf6..e91aa11085 100644
--- a/libavcodec/imdct15.c
+++ b/libavcodec/imdct15.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -105,11 +105,11 @@ av_cold int ff_imdct15_init(IMDCT15Context **ps, int N)
s->len4 = len2 / 2;
s->len2 = len2;
- s->tmp = av_malloc(len * 2 * sizeof(*s->tmp));
+ s->tmp = av_malloc_array(len, 2 * sizeof(*s->tmp));
if (!s->tmp)
goto fail;
- s->twiddle_exptab = av_malloc(s->len4 * sizeof(*s->twiddle_exptab));
+ s->twiddle_exptab = av_malloc_array(s->len4, sizeof(*s->twiddle_exptab));
if (!s->twiddle_exptab)
goto fail;
diff --git a/libavcodec/imdct15.h b/libavcodec/imdct15.h
index ed3f0039e8..1979aa76af 100644
--- a/libavcodec/imdct15.h
+++ b/libavcodec/imdct15.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/imgconvert.c b/libavcodec/imgconvert.c
index 2d32602385..8cb609946a 100644
--- a/libavcodec/imgconvert.c
+++ b/libavcodec/imgconvert.c
@@ -2,20 +2,20 @@
* Misc image conversion routines
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@
#include "imgconvert.h"
#include "internal.h"
#include "mathops.h"
+#include "libavutil/avassert.h"
#include "libavutil/colorspace.h"
#include "libavutil/common.h"
#include "libavutil/pixdesc.h"
@@ -42,121 +43,49 @@
void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ av_assert0(desc);
*h_shift = desc->log2_chroma_w;
*v_shift = desc->log2_chroma_h;
}
-static int is_gray(const AVPixFmtDescriptor *desc)
-{
- return desc->nb_components - (desc->flags & AV_PIX_FMT_FLAG_ALPHA) == 1;
-}
-
int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
enum AVPixelFormat src_pix_fmt,
int has_alpha)
{
- const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
- const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
- int loss, i, nb_components = FFMIN(src_desc->nb_components,
- dst_desc->nb_components);
-
- /* compute loss */
- loss = 0;
-
- if (dst_pix_fmt == src_pix_fmt)
- return 0;
-
- for (i = 0; i < nb_components; i++)
- if (src_desc->comp[i].depth_minus1 > dst_desc->comp[i].depth_minus1)
- loss |= FF_LOSS_DEPTH;
-
- if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w ||
- dst_desc->log2_chroma_h > src_desc->log2_chroma_h)
- loss |= FF_LOSS_RESOLUTION;
-
- if ((src_desc->flags & AV_PIX_FMT_FLAG_RGB) != (dst_desc->flags & AV_PIX_FMT_FLAG_RGB))
- loss |= FF_LOSS_COLORSPACE;
-
- if (has_alpha && !(dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA) &&
- (dst_desc->flags & AV_PIX_FMT_FLAG_ALPHA))
- loss |= FF_LOSS_ALPHA;
-
- if (dst_pix_fmt == AV_PIX_FMT_PAL8 && !is_gray(src_desc))
- return loss | FF_LOSS_COLORQUANT;
-
- if (src_desc->nb_components > dst_desc->nb_components)
- if (is_gray(dst_desc))
- loss |= FF_LOSS_CHROMA;
-
- return loss;
+ return av_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
}
-static enum AVPixelFormat avcodec_find_best_pix_fmt1(enum AVPixelFormat *pix_fmt_list,
- enum AVPixelFormat src_pix_fmt,
- int has_alpha,
- int loss_mask)
+enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
+ enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr)
{
- int dist, i, loss, min_dist;
- enum AVPixelFormat dst_pix_fmt;
-
- /* find exact color match with smallest size */
- dst_pix_fmt = AV_PIX_FMT_NONE;
- min_dist = 0x7fffffff;
- i = 0;
- while (pix_fmt_list[i] != AV_PIX_FMT_NONE) {
- enum AVPixelFormat pix_fmt = pix_fmt_list[i];
-
- if (i > AV_PIX_FMT_NB) {
- av_log(NULL, AV_LOG_ERROR, "Pixel format list longer than expected, "
- "it is either not properly terminated or contains duplicates\n");
- return AV_PIX_FMT_NONE;
- }
-
- loss = avcodec_get_pix_fmt_loss(pix_fmt, src_pix_fmt, has_alpha) & loss_mask;
- if (loss == 0) {
- dist = av_get_bits_per_pixel(av_pix_fmt_desc_get(pix_fmt));
- if (dist < min_dist) {
- min_dist = dist;
- dst_pix_fmt = pix_fmt;
- }
- }
- i++;
- }
- return dst_pix_fmt;
+ return av_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr);
}
-enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat *pix_fmt_list,
+#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
+enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list,
enum AVPixelFormat src_pix_fmt,
- int has_alpha, int *loss_ptr)
+ int has_alpha, int *loss_ptr){
+ return avcodec_find_best_pix_fmt_of_list(pix_fmt_list, src_pix_fmt, has_alpha, loss_ptr);
+}
+#else
+enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
+ enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr)
{
- enum AVPixelFormat dst_pix_fmt;
- int loss_mask, i;
- static const int loss_mask_order[] = {
- ~0, /* no loss first */
- ~FF_LOSS_ALPHA,
- ~FF_LOSS_RESOLUTION,
- ~(FF_LOSS_COLORSPACE | FF_LOSS_RESOLUTION),
- ~FF_LOSS_COLORQUANT,
- ~FF_LOSS_DEPTH,
- 0,
- };
-
- /* try with successive loss */
- i = 0;
- for(;;) {
- loss_mask = loss_mask_order[i++];
- dst_pix_fmt = avcodec_find_best_pix_fmt1(pix_fmt_list, src_pix_fmt,
- has_alpha, loss_mask);
- if (dst_pix_fmt >= 0)
- goto found;
- if (loss_mask == 0)
- break;
- }
- return AV_PIX_FMT_NONE;
- found:
- if (loss_ptr)
- *loss_ptr = avcodec_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
- return dst_pix_fmt;
+ return avcodec_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr);
+}
+#endif
+
+enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list,
+ enum AVPixelFormat src_pix_fmt,
+ int has_alpha, int *loss_ptr){
+ int i;
+
+ enum AVPixelFormat best = AV_PIX_FMT_NONE;
+
+ for(i=0; pix_fmt_list[i] != AV_PIX_FMT_NONE; i++)
+ best = avcodec_find_best_pix_fmt_of_2(best, pix_fmt_list[i], src_pix_fmt, has_alpha, loss_ptr);
+
+ return best;
}
/* 2x2 -> 1x1 */
@@ -248,8 +177,22 @@ void ff_shrink88(uint8_t *dst, int dst_wrap,
/* return true if yuv planar */
static inline int is_yuv_planar(const AVPixFmtDescriptor *desc)
{
- return (!(desc->flags & AV_PIX_FMT_FLAG_RGB) &&
- (desc->flags & AV_PIX_FMT_FLAG_PLANAR));
+ int i;
+ int planes[4] = { 0 };
+
+ if ( desc->flags & AV_PIX_FMT_FLAG_RGB
+ || !(desc->flags & AV_PIX_FMT_FLAG_PLANAR))
+ return 0;
+
+ /* set the used planes */
+ for (i = 0; i < desc->nb_components; i++)
+ planes[desc->comp[i].plane] = 1;
+
+ /* if there is an unused plane, the format is not planar */
+ for (i = 0; i < desc->nb_components; i++)
+ if (!planes[i])
+ return 0;
+ return 1;
}
int av_picture_crop(AVPicture *dst, const AVPicture *src,
@@ -259,15 +202,23 @@ int av_picture_crop(AVPicture *dst, const AVPicture *src,
int y_shift;
int x_shift;
- if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB || !is_yuv_planar(desc))
+ if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB)
return -1;
y_shift = desc->log2_chroma_h;
x_shift = desc->log2_chroma_w;
+ if (is_yuv_planar(desc)) {
dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift);
dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift);
+ } else{
+ if(top_band % (1<<y_shift) || left_band % (1<<x_shift))
+ return -1;
+ if(left_band) //FIXME add support for this too
+ return -1;
+ dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band;
+ }
dst->linesize[0] = src->linesize[0];
dst->linesize[1] = src->linesize[1];
@@ -510,3 +461,31 @@ int avpicture_deinterlace(AVPicture *dst, const AVPicture *src,
}
#endif /* FF_API_DEINTERLACE */
+
+#ifdef TEST
+
+int main(void){
+ int i;
+ int err=0;
+ int skip = 0;
+
+ for (i=0; i<AV_PIX_FMT_NB*2; i++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
+ if(!desc || !desc->name) {
+ skip ++;
+ continue;
+ }
+ if (skip) {
+ av_log(NULL, AV_LOG_INFO, "%3d unused pixel format values\n", skip);
+ skip = 0;
+ }
+ av_log(NULL, AV_LOG_INFO, "pix fmt %s yuv_plan:%d avg_bpp:%d\n", desc->name, is_yuv_planar(desc), av_get_padded_bits_per_pixel(desc));
+ if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) != (desc->nb_components != 2 && desc->nb_components != 4)) {
+ av_log(NULL, AV_LOG_ERROR, "Alpha flag mismatch\n");
+ err = 1;
+ }
+ }
+ return err;
+}
+
+#endif
diff --git a/libavcodec/imgconvert.h b/libavcodec/imgconvert.h
index 56d89b2df0..0ce626d7a2 100644
--- a/libavcodec/imgconvert.h
+++ b/libavcodec/imgconvert.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/imx_dump_header_bsf.c b/libavcodec/imx_dump_header_bsf.c
index 5c647c4d68..d53f338a4f 100644
--- a/libavcodec/imx_dump_header_bsf.c
+++ b/libavcodec/imx_dump_header_bsf.c
@@ -2,20 +2,20 @@
* imx dump header bitstream filter
* Copyright (c) 2007 Baptiste Coudurier
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,7 +55,6 @@ static int imx_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx
}
AVBitStreamFilter ff_imx_dump_header_bsf = {
- "imxdump",
- 0,
- imx_dump_header,
+ .name = "imxdump",
+ .filter = imx_dump_header,
};
diff --git a/libavcodec/indeo2.c b/libavcodec/indeo2.c
index 4221e9e9e4..39735c2e4b 100644
--- a/libavcodec/indeo2.c
+++ b/libavcodec/indeo2.c
@@ -2,20 +2,20 @@
* Intel Indeo 2 codec
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,15 +54,13 @@ static int ir2_decode_plane(Ir2Context *ctx, int width, int height, uint8_t *dst
int i;
int j;
int out = 0;
- int c;
- int t;
if (width & 1)
return AVERROR_INVALIDDATA;
/* first line contain absolute values, other lines contain deltas */
while (out < width) {
- c = ir2_get_code(&ctx->gb);
+ int c = ir2_get_code(&ctx->gb);
if (c >= 0x80) { /* we have a run */
c -= 0x7F;
if (out + c*2 > width)
@@ -79,7 +77,7 @@ static int ir2_decode_plane(Ir2Context *ctx, int width, int height, uint8_t *dst
for (j = 1; j < height; j++) {
out = 0;
while (out < width) {
- c = ir2_get_code(&ctx->gb);
+ int c = ir2_get_code(&ctx->gb);
if (c >= 0x80) { /* we have a skip */
c -= 0x7F;
if (out + c*2 > width)
@@ -89,7 +87,7 @@ static int ir2_decode_plane(Ir2Context *ctx, int width, int height, uint8_t *dst
out++;
}
} else { /* add two deltas from table */
- t = dst[out - pitch] + (table[c * 2] - 128);
+ int t = dst[out - pitch] + (table[c * 2] - 128);
t = av_clip_uint8(t);
dst[out] = t;
out++;
@@ -149,10 +147,8 @@ static int ir2_decode_frame(AVCodecContext *avctx,
AVFrame * const p = s->picture;
int start, ret;
- if ((ret = ff_reget_buffer(avctx, p)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, p)) < 0)
return ret;
- }
start = 48; /* hardcoded for now */
diff --git a/libavcodec/indeo2data.h b/libavcodec/indeo2data.h
index ed8d83c83b..0d6d82f22c 100644
--- a/libavcodec/indeo2data.h
+++ b/libavcodec/indeo2data.h
@@ -2,20 +2,20 @@
* Intel Indeo 2 codec
* copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/indeo3.c b/libavcodec/indeo3.c
index 33239eb9f8..3d0f906e0f 100644
--- a/libavcodec/indeo3.c
+++ b/libavcodec/indeo3.c
@@ -2,20 +2,20 @@
* Indeo Video v3 compatible decoder
* Copyright (c) 2009 - 2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,7 @@
#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "avcodec.h"
+#include "copy_block.h"
#include "bytestream.h"
#include "get_bits.h"
#include "hpeldsp.h"
@@ -93,7 +94,7 @@ typedef struct Indeo3DecodeContext {
int16_t width, height;
uint32_t frame_num; ///< current frame number (zero-based)
- uint32_t data_size; ///< size of the frame data in bytes
+ int data_size; ///< size of the frame data in bytes
uint16_t frame_flags; ///< frame properties
uint8_t cb_offset; ///< needed for selecting VQ tables
uint8_t buf_sel; ///< active frame buffer: 0 - primary, 1 -secondary
@@ -117,8 +118,8 @@ static uint8_t requant_tab[8][128];
*/
static av_cold void build_requant_tab(void)
{
- static int8_t offsets[8] = { 1, 1, 2, -3, -3, 3, 4, 4 };
- static int8_t deltas [8] = { 0, 1, 0, 4, 4, 1, 0, 1 };
+ static const int8_t offsets[8] = { 1, 1, 2, -3, -3, 3, 4, 4 };
+ static const int8_t deltas [8] = { 0, 1, 0, 4, 4, 1, 0, 1 };
int i, j, step;
@@ -147,15 +148,26 @@ static av_cold void build_requant_tab(void)
}
+static av_cold void free_frame_buffers(Indeo3DecodeContext *ctx)
+{
+ int p;
+
+ ctx->width = ctx->height = 0;
+
+ for (p = 0; p < 3; p++) {
+ av_freep(&ctx->planes[p].buffers[0]);
+ av_freep(&ctx->planes[p].buffers[1]);
+ ctx->planes[p].pixels[0] = ctx->planes[p].pixels[1] = 0;
+ }
+}
+
+
static av_cold int allocate_frame_buffers(Indeo3DecodeContext *ctx,
- AVCodecContext *avctx)
+ AVCodecContext *avctx, int luma_width, int luma_height)
{
- int p, luma_width, luma_height, chroma_width, chroma_height;
+ int p, chroma_width, chroma_height;
int luma_pitch, chroma_pitch, luma_size, chroma_size;
- luma_width = ctx->width;
- luma_height = ctx->height;
-
if (luma_width < 16 || luma_width > 640 ||
luma_height < 16 || luma_height > 480 ||
luma_width & 3 || luma_height & 3) {
@@ -164,6 +176,9 @@ static av_cold int allocate_frame_buffers(Indeo3DecodeContext *ctx,
return AVERROR_INVALIDDATA;
}
+ ctx->width = luma_width ;
+ ctx->height = luma_height;
+
chroma_width = FFALIGN(luma_width >> 2, 4);
chroma_height = FFALIGN(luma_height >> 2, 4);
@@ -187,6 +202,11 @@ static av_cold int allocate_frame_buffers(Indeo3DecodeContext *ctx,
ctx->planes[p].buffers[0] = av_malloc(!p ? luma_size : chroma_size);
ctx->planes[p].buffers[1] = av_malloc(!p ? luma_size : chroma_size);
+ if (!ctx->planes[p].buffers[0] || !ctx->planes[p].buffers[1]) {
+ free_frame_buffers(ctx);
+ return AVERROR(ENOMEM);
+ }
+
/* fill the INTRA prediction lines with the middle pixel value = 64 */
memset(ctx->planes[p].buffers[0], 0x40, ctx->planes[p].pitch);
memset(ctx->planes[p].buffers[1], 0x40, ctx->planes[p].pitch);
@@ -201,19 +221,6 @@ static av_cold int allocate_frame_buffers(Indeo3DecodeContext *ctx,
return 0;
}
-
-static av_cold void free_frame_buffers(Indeo3DecodeContext *ctx)
-{
- int p;
-
- for (p = 0; p < 3; p++) {
- av_freep(&ctx->planes[p].buffers[0]);
- av_freep(&ctx->planes[p].buffers[1]);
- ctx->planes[p].pixels[0] = ctx->planes[p].pixels[1] = 0;
- }
-}
-
-
/**
* Copy pixels of the cell(x + mv_x, y + mv_y) from the previous frame into
* the cell(x, y) in the current frame.
@@ -230,8 +237,11 @@ static int copy_cell(Indeo3DecodeContext *ctx, Plane *plane, Cell *cell)
/* setup output and reference pointers */
offset_dst = (cell->ypos << 2) * plane->pitch + (cell->xpos << 2);
dst = plane->pixels[ctx->buf_sel] + offset_dst;
+ if(cell->mv_ptr){
mv_y = cell->mv_ptr[0];
mv_x = cell->mv_ptr[1];
+ }else
+ mv_x= mv_y= 0;
/* -1 because there is an extra line on top for prediction */
if ((cell->ypos << 2) + mv_y < -1 || (cell->xpos << 2) + mv_x < 0 ||
@@ -333,7 +343,7 @@ if (*data_ptr >= last_ptr) \
#define RLE_BLOCK_COPY \
if (cell->mv_ptr || !skip_flag) \
- ctx->hdsp.put_pixels_tab[2][0](dst, ref, row_offset, 4 << v_zoom)
+ copy_block4(dst, ref, row_offset, row_offset, 4 << v_zoom)
#define RLE_BLOCK_COPY_8 \
pix64 = AV_RN64(ref);\
@@ -345,7 +355,7 @@ if (*data_ptr >= last_ptr) \
fill_64(dst, pix64, 8, row_offset)
#define RLE_LINES_COPY \
- ctx->hdsp.put_pixels_tab[2][0](dst, ref, row_offset, num_lines << v_zoom)
+ copy_block4(dst, ref, row_offset, row_offset, num_lines << v_zoom)
#define RLE_LINES_COPY_M10 \
pix64 = AV_RN64(ref);\
@@ -589,6 +599,7 @@ static int decode_cell(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
/* setup output and reference pointers */
offset = (cell->ypos << 2) * plane->pitch + (cell->xpos << 2);
block = plane->pixels[ctx->buf_sel] + offset;
+
if (!cell->mv_ptr) {
/* use previous line as reference for INTRA cells */
ref_block = block - plane->pitch;
@@ -643,7 +654,7 @@ static int decode_cell(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
/* of the predicted cell in order to avoid overflows. */
if (vq_index >= 8 && ref_block) {
for (x = 0; x < cell->width << 2; x++)
- ref_block[x] = requant_tab[vq_index & 7][ref_block[x]];
+ ref_block[x] = requant_tab[vq_index & 7][ref_block[x] & 127];
}
error = IV3_NOERR;
@@ -771,7 +782,7 @@ static int parse_bintree(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
- while (1) { /* loop until return */
+ while (get_bits_left(&ctx->gb) >= 2) { /* loop until return */
RESYNC_BITSTREAM;
switch (code = get_bits(&ctx->gb, 2)) {
case H_SPLIT:
@@ -796,6 +807,7 @@ static int parse_bintree(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
CHECK_CELL
if (!curr_cell.mv_ptr)
return AVERROR_INVALIDDATA;
+
ret = copy_cell(ctx, plane, &curr_cell);
return ret;
}
@@ -806,6 +818,10 @@ static int parse_bintree(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
/* get motion vector index and setup the pointer to the mv set */
if (!ctx->need_resync)
ctx->next_cell_data = &ctx->gb.buffer[(get_bits_count(&ctx->gb) + 7) >> 3];
+ if (ctx->next_cell_data >= ctx->last_byte) {
+ av_log(avctx, AV_LOG_ERROR, "motion vector out of array\n");
+ return AVERROR_INVALIDDATA;
+ }
mv_idx = *(ctx->next_cell_data++);
if (mv_idx >= ctx->num_vectors) {
av_log(avctx, AV_LOG_ERROR, "motion vector index out of range\n");
@@ -832,7 +848,7 @@ static int parse_bintree(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
}
}//while
- return 0;
+ return AVERROR_INVALIDDATA;
}
@@ -845,13 +861,13 @@ static int decode_plane(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
/* each plane data starts with mc_vector_count field, */
/* an optional array of motion vectors followed by the vq data */
- num_vectors = bytestream_get_le32(&data);
+ num_vectors = bytestream_get_le32(&data); data_size -= 4;
if (num_vectors > 256) {
av_log(ctx->avctx, AV_LOG_ERROR,
"Read invalid number of motion vectors %d\n", num_vectors);
return AVERROR_INVALIDDATA;
}
- if (num_vectors * 2 >= data_size)
+ if (num_vectors * 2 > data_size)
return AVERROR_INVALIDDATA;
ctx->num_vectors = num_vectors;
@@ -862,7 +878,7 @@ static int decode_plane(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
ctx->skip_bits = 0;
ctx->need_resync = 0;
- ctx->last_byte = data + data_size - 1;
+ ctx->last_byte = data + data_size;
/* initialize the 1st cell and set its dimensions to whole plane */
curr_cell.xpos = curr_cell.ypos = 0;
@@ -883,7 +899,8 @@ static int decode_frame_headers(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
GetByteContext gb;
const uint8_t *bs_hdr;
uint32_t frame_num, word2, check_sum, data_size;
- uint32_t y_offset, u_offset, v_offset, starts[3], ends[3];
+ int y_offset, u_offset, v_offset;
+ uint32_t starts[3], ends[3];
uint16_t height, width;
int i, j;
@@ -937,12 +954,8 @@ static int decode_frame_headers(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
"Invalid picture dimensions: %d x %d!\n", width, height);
return AVERROR_INVALIDDATA;
}
-
- ctx->width = width;
- ctx->height = height;
-
free_frame_buffers(ctx);
- if ((res = allocate_frame_buffers(ctx, avctx)) < 0)
+ if ((res = allocate_frame_buffers(ctx, avctx, width, height)) < 0)
return res;
if ((res = ff_set_dimensions(avctx, width, height)) < 0)
return res;
@@ -969,7 +982,8 @@ static int decode_frame_headers(Indeo3DecodeContext *ctx, AVCodecContext *avctx,
ctx->y_data_size = ends[0] - starts[0];
ctx->v_data_size = ends[1] - starts[1];
ctx->u_data_size = ends[2] - starts[2];
- if (FFMAX3(y_offset, v_offset, u_offset) >= ctx->data_size - 16 ||
+ if (FFMIN3(y_offset, v_offset, u_offset) < 0 ||
+ FFMAX3(y_offset, v_offset, u_offset) >= ctx->data_size - 16 ||
FFMIN3(y_offset, v_offset, u_offset) < gb.buffer - bs_hdr + 16 ||
FFMIN3(ctx->y_data_size, ctx->v_data_size, ctx->u_data_size) <= 0) {
av_log(avctx, AV_LOG_ERROR, "One of the y/u/v offsets is invalid\n");
@@ -1040,17 +1054,13 @@ static av_cold int decode_init(AVCodecContext *avctx)
Indeo3DecodeContext *ctx = avctx->priv_data;
ctx->avctx = avctx;
- ctx->width = avctx->width;
- ctx->height = avctx->height;
avctx->pix_fmt = AV_PIX_FMT_YUV410P;
build_requant_tab();
ff_hpeldsp_init(&ctx->hdsp, avctx->flags);
- allocate_frame_buffers(ctx, avctx);
-
- return 0;
+ return allocate_frame_buffers(ctx, avctx, avctx->width, avctx->height);
}
@@ -1086,6 +1096,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
/* use BS_BUFFER flag for buffer switching */
ctx->buf_sel = (ctx->frame_flags >> BS_BUFFER) & 1;
+ if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
+ return res;
+
/* decode luma plane */
if ((res = decode_plane(ctx, avctx, ctx->planes, ctx->y_data_ptr, ctx->y_data_size, 40)))
return res;
@@ -1097,11 +1110,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if ((res = decode_plane(ctx, avctx, &ctx->planes[2], ctx->v_data_ptr, ctx->v_data_size, 10)))
return res;
- if ((res = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(ctx->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return res;
- }
-
output_plane(&ctx->planes[0], ctx->buf_sel,
frame->data[0], frame->linesize[0],
avctx->height);
diff --git a/libavcodec/indeo3data.h b/libavcodec/indeo3data.h
index 28c9bb6061..e7e28a3b45 100644
--- a/libavcodec/indeo3data.h
+++ b/libavcodec/indeo3data.h
@@ -2,20 +2,20 @@
* Indeo Video v3 compatible decoder
* Copyright (c) 2009 - 2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/indeo4.c b/libavcodec/indeo4.c
index 1fd45f0790..1c2491d6c1 100644
--- a/libavcodec/indeo4.c
+++ b/libavcodec/indeo4.c
@@ -2,20 +2,20 @@
* Indeo Video Interactive v4 compatible decoder
* Copyright (c) 2009-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -184,6 +184,7 @@ static int decode_pic_hdr(IVI45DecContext *ctx, AVCodecContext *avctx)
/* decode subdivision of the planes */
pic_conf.luma_bands = decode_plane_subdivision(&ctx->gb);
+ pic_conf.chroma_bands = 0;
if (pic_conf.luma_bands)
pic_conf.chroma_bands = decode_plane_subdivision(&ctx->gb);
ctx->is_scalable = pic_conf.luma_bands != 1 || pic_conf.chroma_bands != 1;
@@ -271,6 +272,7 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
{
int plane, band_num, indx, transform_id, scan_indx;
int i;
+ int quant_mat;
plane = get_bits(&ctx->gb, 2);
band_num = get_bits(&ctx->gb, 4);
@@ -328,6 +330,10 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
return AVERROR_PATCHWELCOME;
}
+ if (transform_id < 10 && band->blk_size < 8) {
+ av_log(avctx, AV_LOG_ERROR, "wrong transform size!\n");
+ return AVERROR_INVALIDDATA;
+ }
#if IVI4_STREAM_ANALYSER
if ((transform_id >= 0 && transform_id <= 2) || transform_id == 10)
ctx->uses_haar = 1;
@@ -336,13 +342,16 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
band->inv_transform = transforms[transform_id].inv_trans;
band->dc_transform = transforms[transform_id].dc_trans;
band->is_2d_trans = transforms[transform_id].is_2d_trans;
+
if (transform_id < 10)
band->transform_size = 8;
else
band->transform_size = 4;
- if (band->blk_size != band->transform_size)
+ if (band->blk_size != band->transform_size) {
+ av_log(avctx, AV_LOG_ERROR, "transform and block size mismatch (%d != %d)\n", band->transform_size, band->blk_size);
return AVERROR_INVALIDDATA;
+ }
scan_indx = get_bits(&ctx->gb, 4);
if (scan_indx == 15) {
@@ -350,25 +359,29 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
return AVERROR_INVALIDDATA;
}
if (scan_indx > 4 && scan_indx < 10) {
- if (band->blk_size != 4)
+ if (band->blk_size != 4) {
+ av_log(avctx, AV_LOG_ERROR, "mismatching scan table!\n");
return AVERROR_INVALIDDATA;
- } else if (band->blk_size != 8)
+ }
+ } else if (band->blk_size != 8) {
+ av_log(avctx, AV_LOG_ERROR, "mismatching scan table!\n");
return AVERROR_INVALIDDATA;
+ }
band->scan = scan_index_to_tab[scan_indx];
+ band->scan_size = band->blk_size;
- band->quant_mat = get_bits(&ctx->gb, 5);
- if (band->quant_mat >= FF_ARRAY_ELEMS(quant_index_to_tab)) {
-
- if (band->quant_mat == 31)
- av_log(avctx, AV_LOG_ERROR,
- "Custom quant matrix encountered!\n");
- else
- avpriv_request_sample(avctx, "Quantization matrix %d",
- band->quant_mat);
- band->quant_mat = -1;
+ quant_mat = get_bits(&ctx->gb, 5);
+ if (quant_mat == 31) {
+ av_log(avctx, AV_LOG_ERROR, "Custom quant matrix encountered!\n");
return AVERROR_INVALIDDATA;
}
+ if (quant_mat >= FF_ARRAY_ELEMS(quant_index_to_tab)) {
+ avpriv_request_sample(avctx, "Quantization matrix %d",
+ quant_mat);
+ return AVERROR_INVALIDDATA;
+ }
+ band->quant_mat = quant_mat;
} else {
if (old_blk_size != band->blk_size) {
av_log(avctx, AV_LOG_ERROR,
@@ -376,10 +389,19 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
"inherited\n");
return AVERROR_INVALIDDATA;
}
- if (band->quant_mat < 0) {
- av_log(avctx, AV_LOG_ERROR, "Invalid quant_mat inherited\n");
- return AVERROR_INVALIDDATA;
- }
+ }
+ if (quant_index_to_tab[band->quant_mat] > 4 && band->blk_size == 4) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid quant matrix for 4x4 block encountered!\n");
+ band->quant_mat = 0;
+ return AVERROR_INVALIDDATA;
+ }
+ if (band->scan_size != band->blk_size) {
+ av_log(avctx, AV_LOG_ERROR, "mismatching scan table!\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (band->transform_size == 8 && band->blk_size < 8) {
+ av_log(avctx, AV_LOG_ERROR, "mismatching transform_size!\n");
+ return AVERROR_INVALIDDATA;
}
/* decode block huffman codebook */
@@ -423,6 +445,11 @@ static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band,
align_get_bits(&ctx->gb);
+ if (!band->scan) {
+ av_log(avctx, AV_LOG_ERROR, "band->scan not set\n");
+ return AVERROR_INVALIDDATA;
+ }
+
return 0;
}
@@ -441,7 +468,7 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
IVITile *tile, AVCodecContext *avctx)
{
int x, y, mv_x, mv_y, mv_delta, offs, mb_offset, blks_per_mb,
- mv_scale, mb_type_bits;
+ mv_scale, mb_type_bits, s;
IVIMbInfo *mb, *ref_mb;
int row_offset = band->mb_size * band->pitch;
@@ -456,6 +483,11 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
mv_scale = (ctx->planes[0].bands[0].mb_size >> 3) - (band->mb_size >> 3);
mv_x = mv_y = 0;
+ if (((tile->width + band->mb_size-1)/band->mb_size) * ((tile->height + band->mb_size-1)/band->mb_size) != tile->num_MBs) {
+ av_log(avctx, AV_LOG_ERROR, "num_MBs mismatch %d %d %d %d\n", tile->width, tile->height, band->mb_size, tile->num_MBs);
+ return -1;
+ }
+
for (y = tile->ypos; y < tile->ypos + tile->height; y += band->mb_size) {
mb_offset = offs;
@@ -495,8 +527,10 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
} else {
if (band->inherit_mv) {
/* copy mb_type from corresponding reference mb */
- if (!ref_mb)
+ if (!ref_mb) {
+ av_log(avctx, AV_LOG_ERROR, "ref_mb unavailable\n");
return AVERROR_INVALIDDATA;
+ }
mb->type = ref_mb->type;
} else if (ctx->frame_type == IVI4_FRAMETYPE_INTRA ||
ctx->frame_type == IVI4_FRAMETYPE_INTRA1) {
@@ -562,6 +596,15 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
}
}
+ s= band->is_halfpel;
+ if (mb->type)
+ if ( x + (mb->mv_x >>s) + (y+ (mb->mv_y >>s))*band->pitch < 0 ||
+ x + ((mb->mv_x+s)>>s) + band->mb_size - 1
+ + (y+band->mb_size - 1 +((mb->mv_y+s)>>s))*band->pitch > band->bufsize -1) {
+ av_log(avctx, AV_LOG_ERROR, "motion vector %d %d outside reference\n", x*s + mb->mv_x, y*s + mb->mv_y);
+ return AVERROR_INVALIDDATA;
+ }
+
mb++;
if (ref_mb)
ref_mb++;
diff --git a/libavcodec/indeo4data.h b/libavcodec/indeo4data.h
index be7c41356b..cc497c2391 100644
--- a/libavcodec/indeo4data.h
+++ b/libavcodec/indeo4data.h
@@ -2,20 +2,20 @@
* Indeo Video Interactive 4 compatible decoder
* Copyright (c) 2009-2010 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -60,7 +60,7 @@ static const uint8_t ivi4_horizontal_scan_4x4[16] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
-static const uint8_t *scan_index_to_tab[15] = {
+static const uint8_t * const scan_index_to_tab[15] = {
// for 8x8 transforms
ff_zigzag_direct,
ivi4_alternate_scan_8x8,
diff --git a/libavcodec/indeo5.c b/libavcodec/indeo5.c
index 2d00c23604..7474863334 100644
--- a/libavcodec/indeo5.c
+++ b/libavcodec/indeo5.c
@@ -2,20 +2,20 @@
* Indeo Video Interactive v5 compatible decoder
* Copyright (c) 2009 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,7 +58,7 @@ enum {
*/
static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
{
- int result, i, p, tile_size, pic_size_indx, mb_size, blk_size;
+ int result, i, p, tile_size, pic_size_indx, mb_size, blk_size, is_scalable;
int quant_mat, blk_size_changed = 0;
IVIBandDesc *band, *band1, *band2;
IVIPicConfig pic_conf;
@@ -80,8 +80,8 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
/* num_levels * 3 + 1 */
pic_conf.luma_bands = get_bits(&ctx->gb, 2) * 3 + 1;
pic_conf.chroma_bands = get_bits1(&ctx->gb) * 3 + 1;
- ctx->is_scalable = pic_conf.luma_bands != 1 || pic_conf.chroma_bands != 1;
- if (ctx->is_scalable && (pic_conf.luma_bands != 4 || pic_conf.chroma_bands != 1)) {
+ is_scalable = pic_conf.luma_bands != 1 || pic_conf.chroma_bands != 1;
+ if (is_scalable && (pic_conf.luma_bands != 4 || pic_conf.chroma_bands != 1)) {
av_log(avctx, AV_LOG_ERROR, "Scalability: unsupported subdivision! Luma bands: %d, chroma bands: %d\n",
pic_conf.luma_bands, pic_conf.chroma_bands);
return AVERROR_INVALIDDATA;
@@ -119,6 +119,7 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
return result;
}
ctx->pic_conf = pic_conf;
+ ctx->is_scalable = is_scalable;
blk_size_changed = 1; /* force reallocation of the internal structures */
}
@@ -132,6 +133,11 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
blk_size = 8 >> get_bits1(&ctx->gb);
mb_size = blk_size << !mb_size;
+ if (p==0 && blk_size==4) {
+ av_log(avctx, AV_LOG_ERROR, "4x4 luma blocks are unsupported!\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
blk_size_changed = mb_size != band->mb_size || blk_size != band->blk_size;
if (blk_size_changed) {
band->mb_size = mb_size;
@@ -184,8 +190,10 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
band->is_2d_trans = band->inv_transform == ff_ivi_inverse_slant_8x8 ||
band->inv_transform == ff_ivi_inverse_slant_4x4;
- if (band->transform_size != band->blk_size)
+ if (band->transform_size != band->blk_size) {
+ av_log(avctx, AV_LOG_ERROR, "transform and block size mismatch (%d != %d)\n", band->transform_size, band->blk_size);
return AVERROR_INVALIDDATA;
+ }
/* select dequant matrix according to plane and band number */
if (!p) {
@@ -195,6 +203,10 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
}
if (band->blk_size == 8) {
+ if(quant_mat >= 5){
+ av_log(avctx, AV_LOG_ERROR, "quant_mat %d too large!\n", quant_mat);
+ return -1;
+ }
band->intra_base = &ivi5_base_quant_8x8_intra[quant_mat][0];
band->inter_base = &ivi5_base_quant_8x8_inter[quant_mat][0];
band->intra_scale = &ivi5_scale_quant_8x8_intra[quant_mat][0];
@@ -231,6 +243,7 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
band2->inv_transform = band1->inv_transform;
band2->dc_transform = band1->dc_transform;
band2->is_2d_trans = band1->is_2d_trans;
+ band2->transform_size= band1->transform_size;
}
/* reallocate internal structures if needed */
@@ -276,14 +289,18 @@ static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx)
*
* @param[in,out] gb the GetBit context
*/
-static inline void skip_hdr_extension(GetBitContext *gb)
+static inline int skip_hdr_extension(GetBitContext *gb)
{
int i, len;
do {
len = get_bits(gb, 8);
+ if (8*len > get_bits_left(gb))
+ return AVERROR_INVALIDDATA;
for (i = 0; i < len; i++) skip_bits(gb, 8);
} while(len);
+
+ return 0;
}
@@ -321,6 +338,12 @@ static int decode_pic_hdr(IVI45DecContext *ctx, AVCodecContext *avctx)
ctx->gop_invalid = 0;
}
+ if (ctx->frame_type == FRAMETYPE_INTER_SCAL && !ctx->is_scalable) {
+ av_log(avctx, AV_LOG_ERROR, "Scalable inter frame in non scalable stream\n");
+ ctx->frame_type = FRAMETYPE_INTER;
+ return AVERROR_INVALIDDATA;
+ }
+
if (ctx->frame_type != FRAMETYPE_NULL) {
ctx->frame_flags = get_bits(&ctx->gb, 8);
@@ -431,7 +454,7 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
IVITile *tile, AVCodecContext *avctx)
{
int x, y, mv_x, mv_y, mv_delta, offs, mb_offset,
- mv_scale, blks_per_mb;
+ mv_scale, blks_per_mb, s;
IVIMbInfo *mb, *ref_mb;
int row_offset = band->mb_size * band->pitch;
@@ -477,7 +500,7 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
}
mb->mv_x = mb->mv_y = 0; /* no motion vector coded */
- if (band->inherit_mv){
+ if (band->inherit_mv && ref_mb){
/* motion vector inheritance */
if (mv_scale) {
mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale);
@@ -488,7 +511,7 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
}
}
} else {
- if (band->inherit_mv) {
+ if (band->inherit_mv && ref_mb) {
mb->type = ref_mb->type; /* copy mb_type from corresponding reference mb */
} else if (ctx->frame_type == FRAMETYPE_INTRA) {
mb->type = 0; /* mb_type is always INTRA for intra-frames */
@@ -514,7 +537,7 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
if (!mb->type) {
mb->mv_x = mb->mv_y = 0; /* there is no motion vector in intra-macroblocks */
} else {
- if (band->inherit_mv){
+ if (band->inherit_mv && ref_mb){
/* motion vector inheritance */
if (mv_scale) {
mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale);
@@ -537,6 +560,15 @@ static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band,
}
}
+ s= band->is_halfpel;
+ if (mb->type)
+ if ( x + (mb->mv_x >>s) + (y+ (mb->mv_y >>s))*band->pitch < 0 ||
+ x + ((mb->mv_x+s)>>s) + band->mb_size - 1
+ + (y+band->mb_size - 1 +((mb->mv_y+s)>>s))*band->pitch > band->bufsize - 1) {
+ av_log(avctx, AV_LOG_ERROR, "motion vector %d %d outside reference\n", x*s + mb->mv_x, y*s + mb->mv_y);
+ return AVERROR_INVALIDDATA;
+ }
+
mb++;
if (ref_mb)
ref_mb++;
@@ -647,7 +679,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
return 0;
}
-
AVCodec ff_indeo5_decoder = {
.name = "indeo5",
.long_name = NULL_IF_CONFIG_SMALL("Intel Indeo Video Interactive 5"),
diff --git a/libavcodec/indeo5data.h b/libavcodec/indeo5data.h
index f4252b59f6..a6217d0bf8 100644
--- a/libavcodec/indeo5data.h
+++ b/libavcodec/indeo5data.h
@@ -2,20 +2,20 @@
* Indeo Video Interactive 5 compatible decoder
* Copyright (c) 2009 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/intelh263dec.c b/libavcodec/intelh263dec.c
index e34da5c6f5..1a0dd59d6a 100644
--- a/libavcodec/intelh263dec.c
+++ b/libavcodec/intelh263dec.c
@@ -1,20 +1,20 @@
/*
* H.263i decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,8 +37,7 @@ int ff_intel_h263_decode_picture_header(MpegEncContext *s)
}
s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */
- if (get_bits1(&s->gb) != 1) {
- av_log(s->avctx, AV_LOG_ERROR, "Bad marker\n");
+ if (check_marker(&s->gb, "after picture_number") != 1) {
return -1; /* marker */
}
if (get_bits1(&s->gb) != 0) {
@@ -58,14 +57,14 @@ int ff_intel_h263_decode_picture_header(MpegEncContext *s)
s->pict_type = AV_PICTURE_TYPE_I + get_bits1(&s->gb);
- s->unrestricted_mv = get_bits1(&s->gb);
- s->h263_long_vectors = s->unrestricted_mv;
+ s->h263_long_vectors = get_bits1(&s->gb);
if (get_bits1(&s->gb) != 0) {
av_log(s->avctx, AV_LOG_ERROR, "SAC not supported\n");
return -1; /* SAC: off */
}
s->obmc= get_bits1(&s->gb);
+ s->unrestricted_mv = s->obmc || s->h263_long_vectors;
s->pb_frame = get_bits1(&s->gb);
if (format < 6) {
@@ -81,7 +80,7 @@ int ff_intel_h263_decode_picture_header(MpegEncContext *s)
}
if(get_bits(&s->gb, 2))
av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n");
- s->loop_filter = get_bits1(&s->gb);
+ s->loop_filter = get_bits1(&s->gb) * !s->avctx->lowres;
if(get_bits1(&s->gb))
av_log(s->avctx, AV_LOG_ERROR, "Bad value for reserved field\n");
if(get_bits1(&s->gb))
@@ -94,7 +93,7 @@ int ff_intel_h263_decode_picture_header(MpegEncContext *s)
if(format == 6){
int ar = get_bits(&s->gb, 4);
skip_bits(&s->gb, 9); // display width
- skip_bits1(&s->gb);
+ check_marker(&s->gb, "in dimensions");
skip_bits(&s->gb, 9); // display height
if(ar == 15){
s->avctx->sample_aspect_ratio.num = get_bits(&s->gb, 8); // aspect ratio - width
@@ -115,9 +114,8 @@ int ff_intel_h263_decode_picture_header(MpegEncContext *s)
}
/* PEI */
- while (get_bits1(&s->gb) != 0) {
- skip_bits(&s->gb, 8);
- }
+ if (skip_1stop_8data_bits(&s->gb) < 0)
+ return AVERROR_INVALIDDATA;
s->f_code = 1;
s->y_dc_scale_table=
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 634400f384..a49bf34a26 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,7 +51,7 @@
#ifdef DEBUG
# define ff_dlog(ctx, ...) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__)
#else
-# define ff_dlog(ctx, ...) while(0)
+# define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0)
#endif
#ifdef TRACE
@@ -63,7 +63,15 @@
#define FF_SANE_NB_CHANNELS 63U
-#define FF_SIGNBIT(x) (x >> CHAR_BIT * sizeof(x) - 1)
+#define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1)
+
+#if HAVE_AVX
+# define STRIDE_ALIGN 32
+#elif HAVE_SIMD_ALIGN_16
+# define STRIDE_ALIGN 16
+#else
+# define STRIDE_ALIGN 8
+#endif
typedef struct FramePool {
/**
@@ -108,6 +116,14 @@ typedef struct AVCodecInternal {
*/
int allocate_progress;
+#if FF_API_OLD_ENCODE_AUDIO
+ /**
+ * Internal sample count used by avcodec_encode_audio() to fabricate pts.
+ * Can be removed along with avcodec_encode_audio().
+ */
+ int64_t sample_count;
+#endif
+
/**
* An audio frame with less than required samples has been submitted and
* padded with silence. Reject all subsequent frames.
@@ -127,6 +143,19 @@ typedef struct AVCodecInternal {
AVPacket *pkt;
/**
+ * temporary buffer used for encoders to store their bitstream
+ */
+ uint8_t *byte_buffer;
+ unsigned int byte_buffer_size;
+
+ void *frame_thread_encoder;
+
+ /**
+ * Number of audio samples to skip at the start of the next decoded frame
+ */
+ int skip_samples;
+
+ /**
* hwaccel-specific private data
*/
void *hwaccel_priv_data;
@@ -137,6 +166,8 @@ struct AVCodecDefault {
const uint8_t *value;
};
+extern const uint8_t ff_log2_run[41];
+
/**
* Return the index into tab at which {a,b} match elements {[0],[1]} of tab.
* If there is no such matching pair then size is returned.
@@ -145,6 +176,18 @@ int ff_match_2uint16(const uint16_t (*tab)[2], int size, int a, int b);
unsigned int avpriv_toupper4(unsigned int x);
+/**
+ * does needed setup of pkt_pts/pos and such for (re)get_buffer();
+ */
+int ff_init_buffer_info(AVCodecContext *s, AVFrame *frame);
+
+
+void avpriv_color_frame(AVFrame *frame, const int color[4]);
+
+extern volatile int ff_avcodec_locked;
+int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec);
+int ff_unlock_avcodec(void);
+
int avpriv_lock_avformat(void);
int avpriv_unlock_avformat(void);
@@ -162,6 +205,7 @@ int avpriv_unlock_avformat(void);
* ensure the output packet data is large enough, whether provided by the user
* or allocated in this function.
*
+ * @param avctx the AVCodecContext of the encoder
* @param avpkt the AVPacket
* If avpkt->data is already set, avpkt->size is checked
* to ensure it is large enough.
@@ -169,8 +213,10 @@ int avpriv_unlock_avformat(void);
* avpkt->size is set to the specified size.
* All other AVPacket fields will be reset with av_init_packet().
* @param size the minimum required packet size
- * @return 0 on success, negative error code on failure
+ * @return non negative on success, negative error code on failure
*/
+int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size);
+
int ff_alloc_packet(AVPacket *avpkt, int size);
/**
@@ -179,6 +225,8 @@ int ff_alloc_packet(AVPacket *avpkt, int size);
static av_always_inline int64_t ff_samples_to_time_base(AVCodecContext *avctx,
int64_t samples)
{
+ if(samples == AV_NOPTS_VALUE)
+ return AV_NOPTS_VALUE;
return av_rescale_q(samples, (AVRational){ 1, avctx->sample_rate },
avctx->time_base);
}
@@ -196,9 +244,25 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags);
*/
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame);
-const uint8_t *avpriv_find_start_code(const uint8_t *restrict p,
+int ff_thread_can_start_frame(AVCodecContext *avctx);
+
+int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx);
+
+/**
+ * Call avcodec_open2 recursively by decrementing counter, unlocking mutex,
+ * calling the function and then restoring again. Assumes the mutex is
+ * already locked
+ */
+int ff_codec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
+
+/**
+ * Finalize buf into extradata and set its size appropriately.
+ */
+int avpriv_bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf);
+
+const uint8_t *avpriv_find_start_code(const uint8_t *p,
const uint8_t *end,
- uint32_t *restrict state);
+ uint32_t *state);
/**
* Check that the provided frame dimensions are valid and set them on the codec
diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c
index d681fdf72e..2106419da3 100644
--- a/libavcodec/interplayvideo.c
+++ b/libavcodec/interplayvideo.c
@@ -1,21 +1,21 @@
/*
* Interplay MVE Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,10 +72,10 @@ static int copy_from(IpvideoContext *s, AVFrame *src, AVFrame *dst, int delta_x,
int motion_offset = current_offset + delta_y * dst->linesize[0]
+ delta_x * (1 + s->is_16bpp);
if (motion_offset < 0) {
- av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset);
+ av_log(s->avctx, AV_LOG_ERROR, "motion offset < 0 (%d)\n", motion_offset);
return AVERROR_INVALIDDATA;
} else if (motion_offset > s->upper_motion_limit_offset) {
- av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "motion offset above limit (%d >= %d)\n",
motion_offset, s->upper_motion_limit_offset);
return AVERROR_INVALIDDATA;
}
@@ -118,7 +118,7 @@ static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s, AVFrame *frame)
y = 8 + ((B - 56) / 29);
}
- ff_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
+ ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
return copy_from(s, s->second_last_frame, frame, x, y);
}
@@ -144,7 +144,7 @@ static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s, AVFrame *frame)
y = -( 8 + ((B - 56) / 29));
}
- ff_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
+ ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
return copy_from(s, frame, frame, x, y);
}
@@ -165,7 +165,7 @@ static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s, AVFrame *frame)
x = -8 + BL;
y = -8 + BH;
- ff_dlog(NULL, " motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
+ ff_tlog(s->avctx, "motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
return copy_from(s, s->last_frame, frame, x, y);
}
@@ -178,14 +178,14 @@ static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s, AVFrame *frame)
x = bytestream2_get_byte(&s->stream_ptr);
y = bytestream2_get_byte(&s->stream_ptr);
- ff_dlog(NULL, " motion bytes = %d, %d\n", x, y);
+ ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y);
return copy_from(s, s->last_frame, frame, x, y);
}
static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s, AVFrame *frame)
{
/* mystery opcode? skip multiple blocks? */
- av_log(s->avctx, AV_LOG_ERROR, " Interplay video: Help! Mystery opcode 0x6 seen\n");
+ av_log(s->avctx, AV_LOG_ERROR, "Help! Mystery opcode 0x6 seen\n");
/* report success */
return 0;
@@ -197,6 +197,11 @@ static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s, AVFrame *frame)
unsigned char P[2];
unsigned int flags;
+ if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x7\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* 2-color encoding */
P[0] = bytestream2_get_byte(&s->stream_ptr);
P[1] = bytestream2_get_byte(&s->stream_ptr);
@@ -236,6 +241,11 @@ static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s, AVFrame *frame)
unsigned char P[4];
unsigned int flags = 0;
+ if (bytestream2_get_bytes_left(&s->stream_ptr) < 12) {
+ av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x8\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
* either top and bottom or left and right halves */
P[0] = bytestream2_get_byte(&s->stream_ptr);
@@ -308,6 +318,11 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s, AVFrame *frame)
int x, y;
unsigned char P[4];
+ if (bytestream2_get_bytes_left(&s->stream_ptr) < 8) {
+ av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0x9\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* 4-color encoding */
bytestream2_get_buffer(&s->stream_ptr, P, 4);
@@ -374,6 +389,11 @@ static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s, AVFrame *frame)
unsigned char P[8];
int flags = 0;
+ if (bytestream2_get_bytes_left(&s->stream_ptr) < 16) {
+ av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xA\n");
+ return AVERROR_INVALIDDATA;
+ }
+
bytestream2_get_buffer(&s->stream_ptr, P, 4);
/* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
@@ -467,6 +487,11 @@ static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s, AVFrame *frame)
int y;
unsigned char P[2];
+ if (bytestream2_get_bytes_left(&s->stream_ptr) < 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "too little data for opcode 0xD\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* 4-color block encoding: each 4x4 block is a different color */
for (y = 0; y < 8; y++) {
if (!(y & 3)) {
@@ -528,7 +553,7 @@ static int ipvideo_decode_block_opcode_0x6_16(IpvideoContext *s, AVFrame *frame)
x = bytestream2_get_byte(&s->stream_ptr);
y = bytestream2_get_byte(&s->stream_ptr);
- ff_dlog(NULL, " motion bytes = %d, %d\n", x, y);
+ ff_tlog(s->avctx, "motion bytes = %d, %d\n", x, y);
return copy_from(s, s->second_last_frame, frame, x, y);
}
@@ -903,7 +928,7 @@ static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame)
for (x = 0; x < s->avctx->width; x += 8) {
opcode = get_bits(&gb, 4);
- ff_dlog(s->avctx,
+ ff_tlog(s->avctx,
" block @ (%3d, %3d): encoding 0x%X, data ptr offset %d\n",
x, y, opcode, bytestream2_tell(&s->stream_ptr));
@@ -917,7 +942,7 @@ static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame)
ret = ipvideo_decode_block16[opcode](s, frame);
}
if (ret != 0) {
- av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "decode problem on frame %d, @ block (%d, %d)\n",
s->avctx->frame_number, x, y);
return;
}
@@ -925,7 +950,7 @@ static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame)
}
if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) {
av_log(s->avctx, AV_LOG_ERROR,
- "Interplay video: decode finished with %d bytes left over\n",
+ "decode finished with %d bytes left over\n",
bytestream2_get_bytes_left(&s->stream_ptr));
}
}
@@ -970,14 +995,17 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
if (buf_size < s->decoding_map_size)
return buf_size;
+ if (av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, NULL)) {
+ av_frame_unref(s->last_frame);
+ av_frame_unref(s->second_last_frame);
+ }
+
s->decoding_map = buf;
bytestream2_init(&s->stream_ptr, buf + s->decoding_map_size,
buf_size - s->decoding_map_size);
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, " Interplay Video: get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if (!s->is_16bpp) {
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
diff --git a/libavcodec/intrax8.c b/libavcodec/intrax8.c
index 303b9263be..017536d644 100644
--- a/libavcodec/intrax8.c
+++ b/libavcodec/intrax8.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,6 +21,7 @@
* @brief IntraX8 (J-Frame) subdecoder, used by WMV2 and VC-1
*/
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "error_resilience.h"
#include "get_bits.h"
@@ -127,13 +128,13 @@ static inline void x8_select_ac_table(IntraX8Context * const w , int mode){
MpegEncContext * const s= w->s;
int table_index;
- assert(mode<4);
+ av_assert2(mode<4);
if( w->j_ac_vlc[mode] ) return;
table_index = get_bits(&s->gb, 3);
w->j_ac_vlc[mode] = &j_ac_vlc[w->quant<13][mode>>1][table_index];//2 modes use same tables
- assert(w->j_ac_vlc[mode]);
+ av_assert2(w->j_ac_vlc[mode]);
}
static inline int x8_get_orient_vlc(IntraX8Context * w){
@@ -144,8 +145,6 @@ static inline int x8_get_orient_vlc(IntraX8Context * w){
table_index = get_bits(&s->gb, 1+(w->quant<13) );
w->j_orient_vlc = &j_orient_vlc[w->quant<13][table_index];
}
- assert(w->j_orient_vlc);
- assert(w->j_orient_vlc->table);
return get_vlc2(&s->gb, w->j_orient_vlc->table, OR_VLC_BITS, OR_VLC_MTD);
}
@@ -267,15 +266,13 @@ static int x8_get_dc_rlf(IntraX8Context * const w,int const mode, int * const le
MpegEncContext * const s= w->s;
int i,e,c;
- assert(mode<3);
+ av_assert2(mode<3);
if( !w->j_dc_vlc[mode] ) {
int table_index;
table_index = get_bits(&s->gb, 3);
//4 modes, same table
w->j_dc_vlc[mode]= &j_dc_vlc[w->quant<13][table_index];
}
- assert(w->j_dc_vlc);
- assert(w->j_dc_vlc[mode]->table);
i=get_vlc2(&s->gb, w->j_dc_vlc[mode]->table, DC_VLC_BITS, DC_VLC_MTD);
@@ -328,7 +325,7 @@ static int x8_setup_spatial_predictor(IntraX8Context * const w, const int chroma
if(chroma)
return 0;
- assert(w->orient < 3);
+ av_assert2(w->orient < 3);
if(range < 2*w->quant){
if( (w->edges&3) == 0){
if(w->orient==1) w->orient=11;
@@ -345,8 +342,8 @@ static int x8_setup_spatial_predictor(IntraX8Context * const w, const int chroma
};
w->raw_orient=x8_get_orient_vlc(w);
if(w->raw_orient<0) return -1;
- assert(w->raw_orient < 12 );
- assert(w->orient<3);
+ av_assert2(w->raw_orient < 12 );
+ av_assert2(w->orient<3);
w->orient=prediction_table[w->orient][w->raw_orient];
}
return 0;
@@ -441,7 +438,7 @@ lut2[q>12][c]={
static void x8_ac_compensation(IntraX8Context * const w, int const direction, int const dc_level){
MpegEncContext * const s= w->s;
int t;
-#define B(x, y) s->block[0][s->idsp.idct_permutation[(x) + (y) * 8]]
+#define B(x,y) s->block[0][w->idct_permutation[(x)+(y)*8]]
#define T(x) ((x) * dc_level + 0x8000) >> 16;
switch(direction){
case 0:
@@ -538,7 +535,7 @@ static int x8_decode_intra_mb(IntraX8Context* const w, const int chroma){
int use_quant_matrix;
int sign;
- assert(w->orient<12);
+ av_assert2(w->orient<12);
s->bdsp.clear_block(s->block[0]);
if(chroma){
@@ -647,7 +644,7 @@ static int x8_decode_intra_mb(IntraX8Context* const w, const int chroma){
s->current_picture.f->linesize[!!chroma] );
}
if(!zeros_only)
- s->idsp.idct_add(s->dest[chroma],
+ w->wdsp.idct_add(s->dest[chroma],
s->current_picture.f->linesize[!!chroma],
s->block[0]);
@@ -696,12 +693,16 @@ av_cold void ff_intrax8_common_init(IntraX8Context * w, MpegEncContext * const s
w->s=s;
x8_vlc_init();
- assert(s->mb_width>0);
+ av_assert0(s->mb_width>0);
w->prediction_table=av_mallocz(s->mb_width*2*2);//two rows, 2 blocks per cannon mb
- ff_init_scantable(s->idsp.idct_permutation, &w->scantable[0], ff_wmv1_scantable[0]);
- ff_init_scantable(s->idsp.idct_permutation, &w->scantable[1], ff_wmv1_scantable[2]);
- ff_init_scantable(s->idsp.idct_permutation, &w->scantable[2], ff_wmv1_scantable[3]);
+ ff_wmv2dsp_init(&w->wdsp);
+ ff_init_scantable_permutation(w->idct_permutation,
+ w->wdsp.idct_perm);
+
+ ff_init_scantable(w->idct_permutation, &w->scantable[0], ff_wmv1_scantable[0]);
+ ff_init_scantable(w->idct_permutation, &w->scantable[1], ff_wmv1_scantable[2]);
+ ff_init_scantable(w->idct_permutation, &w->scantable[2], ff_wmv1_scantable[3]);
ff_intrax8dsp_init(&w->dsp);
}
@@ -721,6 +722,7 @@ av_cold void ff_intrax8_common_end(IntraX8Context * w)
* The parent codec must call ff_mpv_frame_start(), ff_er_frame_start() before calling this function.
* The parent codec must call ff_er_frame_end(), ff_mpv_frame_end() after calling this function.
* This function does not use ff_mpv_decode_mb().
+ * lowres decoding is theoretically impossible.
* @param w pointer to IntraX8Context
* @param dquant doubled quantizer, it would be odd in case of VC-1 halfpq==1.
* @param quant_offset offset away from zero
@@ -728,7 +730,6 @@ av_cold void ff_intrax8_common_end(IntraX8Context * w)
int ff_intrax8_decode_picture(IntraX8Context * const w, int dquant, int quant_offset){
MpegEncContext * const s= w->s;
int mb_xy;
- assert(s);
w->use_quant_matrix = get_bits1(&s->gb);
w->dquant = dquant;
diff --git a/libavcodec/intrax8.h b/libavcodec/intrax8.h
index 69673171a8..9981785403 100644
--- a/libavcodec/intrax8.h
+++ b/libavcodec/intrax8.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,6 +22,7 @@
#include "get_bits.h"
#include "mpegvideo.h"
#include "intrax8dsp.h"
+#include "wmv2dsp.h"
typedef struct IntraX8Context {
VLC * j_ac_vlc[4];//they point to the static j_mb_vlc
@@ -32,6 +33,8 @@ typedef struct IntraX8Context {
//set by ff_intrax8_common_init
uint8_t * prediction_table;//2*(mb_w*2)
ScanTable scantable[3];
+ WMV2DSPContext wdsp;
+ uint8_t idct_permutation[64];
//set by the caller codec
MpegEncContext * s;
IntraX8DSPContext dsp;
diff --git a/libavcodec/intrax8dsp.c b/libavcodec/intrax8dsp.c
index 1115945eba..1b34f899d6 100644
--- a/libavcodec/intrax8dsp.c
+++ b/libavcodec/intrax8dsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/intrax8dsp.h b/libavcodec/intrax8dsp.h
index 5c3cc4aa74..1e4a3af881 100644
--- a/libavcodec/intrax8dsp.h
+++ b/libavcodec/intrax8dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/intrax8huf.h b/libavcodec/intrax8huf.h
index 6bf01f388a..375906bab2 100644
--- a/libavcodec/intrax8huf.h
+++ b/libavcodec/intrax8huf.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c
index a89e5d0a37..c41e600809 100644
--- a/libavcodec/ituh263dec.c
+++ b/libavcodec/ituh263dec.c
@@ -5,20 +5,20 @@
* Copyright (c) 2001 Juan J. Sierralta P
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
* h263 decoder.
*/
+#define UNCHECKED_BITSTREAM_READER 1
#include <limits.h>
#include "libavutil/attributes.h"
@@ -102,11 +103,9 @@ static VLC cbpc_b_vlc;
/* XXX: find a better solution to handle static init */
av_cold void ff_h263_decode_init_vlc(void)
{
- static int done = 0;
+ static volatile int done = 0;
if (!done) {
- done = 1;
-
INIT_VLC_STATIC(&ff_h263_intra_MCBPC_vlc, INTRA_MCBPC_VLC_BITS, 9,
ff_h263_intra_MCBPC_bits, 1, 1,
ff_h263_intra_MCBPC_code, 1, 1, 72);
@@ -129,6 +128,7 @@ av_cold void ff_h263_decode_init_vlc(void)
INIT_VLC_STATIC(&cbpc_b_vlc, CBPC_B_VLC_BITS, 4,
&ff_cbpc_b_tab[0][1], 2, 1,
&ff_cbpc_b_tab[0][0], 2, 1, 8);
+ done = 1;
}
}
@@ -171,17 +171,17 @@ static int h263_decode_gob_header(MpegEncContext *s)
return -1;
if(s->h263_slice_structured){
- if(get_bits1(&s->gb)==0)
+ if(check_marker(&s->gb, "before MBA")==0)
return -1;
ff_h263_decode_mba(s);
if(s->mb_num > 1583)
- if(get_bits1(&s->gb)==0)
+ if(check_marker(&s->gb, "after MBA")==0)
return -1;
s->qscale = get_bits(&s->gb, 5); /* SQUANT */
- if(get_bits1(&s->gb)==0)
+ if(check_marker(&s->gb, "after SQUANT")==0)
return -1;
skip_bits(&s->gb, 2); /* GFID */
}else{
@@ -202,27 +202,6 @@ static int h263_decode_gob_header(MpegEncContext *s)
}
/**
- * Find the next resync_marker.
- * @param p pointer to buffer to scan
- * @param end pointer to the end of the buffer
- * @return pointer to the next resync_marker, or end if none was found
- */
-const uint8_t *ff_h263_find_resync_marker(const uint8_t *restrict p, const uint8_t * restrict end)
-{
- assert(p < end);
-
- end-=2;
- p++;
- for(;p<end; p+=2){
- if(!*p){
- if (!p[-1] && p[1]) return p - 1;
- else if(!p[ 1] && p[2]) return p;
- }
- }
- return end+2;
-}
-
-/**
* Decode the group of blocks / video packet header.
* @return bit position of the resync_marker, or <0 if none was found
*/
@@ -324,7 +303,7 @@ static int h263p_decode_umotion(MpegEncContext * s, int pred)
code >>= 1;
code = (sign) ? (pred - code) : (pred + code);
- ff_dlog(s->avctx,"H.263+ UMV Motion = %d\n", code);
+ ff_tlog(s->avctx,"H.263+ UMV Motion = %d\n", code);
return code;
}
@@ -346,7 +325,7 @@ static void preview_obmc(MpegEncContext *s){
s->block_index[i]+= 1;
s->mb_x++;
- assert(s->pict_type == AV_PICTURE_TYPE_P);
+ av_assert2(s->pict_type == AV_PICTURE_TYPE_P);
do{
if (get_bits1(&s->gb)) {
@@ -440,7 +419,7 @@ static void h263_decode_dquant(MpegEncContext *s){
static int h263_decode_block(MpegEncContext * s, int16_t * block,
int n, int coded)
{
- int code, level, i, j, last, run;
+ int level, i, j, run;
RLTable *rl = &ff_h263_rl_inter;
const uint8_t *scan_table;
GetBitContext gb= s->gb;
@@ -481,7 +460,7 @@ static int h263_decode_block(MpegEncContext * s, int16_t * block,
level = get_bits(&s->gb, 8);
if((level&0x7F) == 0){
av_log(s->avctx, AV_LOG_ERROR, "illegal dc %d at %d %d\n", level, s->mb_x, s->mb_y);
- if (s->avctx->err_recognition & AV_EF_BITSTREAM)
+ if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))
return -1;
}
if (level == 255)
@@ -499,39 +478,67 @@ static int h263_decode_block(MpegEncContext * s, int16_t * block,
return 0;
}
retry:
+ {
+ OPEN_READER(re, &s->gb);
+ i--; // offset by -1 to allow direct indexing of scan_table
for(;;) {
- code = get_vlc2(&s->gb, rl->vlc.table, TEX_VLC_BITS, 2);
- if (code < 0){
- av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", s->mb_x, s->mb_y);
- return -1;
- }
- if (code == rl->n) {
+ UPDATE_CACHE(re, &s->gb);
+ GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0);
+ if (run == 66) {
+ if (level){
+ CLOSE_READER(re, &s->gb);
+ av_log(s->avctx, AV_LOG_ERROR, "illegal ac vlc code at %dx%d\n", s->mb_x, s->mb_y);
+ return -1;
+ }
/* escape */
if (CONFIG_FLV_DECODER && s->h263_flv > 1) {
- ff_flv2_decode_ac_esc(&s->gb, &level, &run, &last);
+ int is11 = SHOW_UBITS(re, &s->gb, 1);
+ SKIP_CACHE(re, &s->gb, 1);
+ run = SHOW_UBITS(re, &s->gb, 7) + 1;
+ if (is11) {
+ SKIP_COUNTER(re, &s->gb, 1 + 7);
+ UPDATE_CACHE(re, &s->gb);
+ level = SHOW_SBITS(re, &s->gb, 11);
+ SKIP_COUNTER(re, &s->gb, 11);
+ } else {
+ SKIP_CACHE(re, &s->gb, 7);
+ level = SHOW_SBITS(re, &s->gb, 7);
+ SKIP_COUNTER(re, &s->gb, 1 + 7 + 7);
+ }
} else {
- last = get_bits1(&s->gb);
- run = get_bits(&s->gb, 6);
- level = (int8_t)get_bits(&s->gb, 8);
+ run = SHOW_UBITS(re, &s->gb, 7) + 1;
+ SKIP_CACHE(re, &s->gb, 7);
+ level = (int8_t)SHOW_UBITS(re, &s->gb, 8);
+ SKIP_COUNTER(re, &s->gb, 7 + 8);
if(level == -128){
+ UPDATE_CACHE(re, &s->gb);
if (s->codec_id == AV_CODEC_ID_RV10) {
/* XXX: should patch encoder too */
- level = get_sbits(&s->gb, 12);
+ level = SHOW_SBITS(re, &s->gb, 12);
+ SKIP_COUNTER(re, &s->gb, 12);
}else{
- level = get_bits(&s->gb, 5);
- level |= get_sbits(&s->gb, 6)<<5;
+ level = SHOW_UBITS(re, &s->gb, 5);
+ SKIP_CACHE(re, &s->gb, 5);
+ level |= SHOW_SBITS(re, &s->gb, 6)<<5;
+ SKIP_COUNTER(re, &s->gb, 5 + 6);
}
}
}
} else {
- run = rl->table_run[code];
- level = rl->table_level[code];
- last = code >= rl->last;
- if (get_bits1(&s->gb))
+ if (SHOW_UBITS(re, &s->gb, 1))
level = -level;
+ SKIP_COUNTER(re, &s->gb, 1);
}
i += run;
if (i >= 64){
+ CLOSE_READER(re, &s->gb);
+ // redo update without last flag, revert -1 offset
+ i = i - run + ((run-1)&63) + 1;
+ if (i < 64) {
+ // only last marker, no overrun
+ block[scan_table[i]] = level;
+ break;
+ }
if(s->alt_inter_vlc && rl == &ff_h263_rl_inter && !s->mb_intra){
//Looks like a hack but no, it's the way it is supposed to work ...
rl = &ff_rl_intra_aic;
@@ -545,9 +552,7 @@ retry:
}
j = scan_table[i];
block[j] = level;
- if (last)
- break;
- i++;
+ }
}
not_coded:
if (s->mb_intra && s->h263_aic) {
@@ -562,11 +567,13 @@ static int h263_skip_b_part(MpegEncContext *s, int cbp)
{
LOCAL_ALIGNED_16(int16_t, dblock, [64]);
int i, mbi;
+ int bli[6];
/* we have to set s->mb_intra to zero to decode B-part of PB-frame correctly
* but real value should be restored in order to be used later (in OBMC condition)
*/
mbi = s->mb_intra;
+ memcpy(bli, s->block_last_index, sizeof(bli));
s->mb_intra = 0;
for (i = 0; i < 6; i++) {
if (h263_decode_block(s, dblock, i, cbp&32) < 0)
@@ -574,6 +581,7 @@ static int h263_skip_b_part(MpegEncContext *s, int cbp)
cbp+=cbp;
}
s->mb_intra = mbi;
+ memcpy(s->block_last_index, bli, sizeof(bli));
return 0;
}
@@ -603,7 +611,7 @@ int ff_h263_decode_mb(MpegEncContext *s,
const int xy= s->mb_x + s->mb_y * s->mb_stride;
int cbpb = 0, pb_mv_count = 0;
- assert(!s->h263_pred);
+ av_assert2(!s->h263_pred);
if (s->pict_type == AV_PICTURE_TYPE_P) {
do{
@@ -743,15 +751,13 @@ int ff_h263_decode_mb(MpegEncContext *s,
}else
cbp=0;
- assert(!s->mb_intra);
+ av_assert2(!s->mb_intra);
if(IS_QUANT(mb_type)){
h263_decode_dquant(s);
}
if(IS_DIRECT(mb_type)){
- if (!s->pp_time)
- return AVERROR_INVALIDDATA;
s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT;
mb_type |= ff_mpeg4_set_direct_mv(s, 0, 0);
}else{
@@ -870,6 +876,10 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
align_get_bits(&s->gb);
+ if (show_bits(&s->gb, 2) == 2 && s->avctx->frame_number == 0) {
+ av_log(s->avctx, AV_LOG_WARNING, "Header looks like RTP instead of H.263\n");
+ }
+
startcode= get_bits(&s->gb, 22-8);
for(i= get_bits_left(&s->gb); i>24; i-=8) {
@@ -890,9 +900,7 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
s->picture_number= (s->picture_number&~0xFF) + i;
/* PTYPE starts here */
- if (get_bits1(&s->gb) != 1) {
- /* marker */
- av_log(s->avctx, AV_LOG_ERROR, "Bad marker\n");
+ if (check_marker(&s->gb, "in PTYPE") != 1) {
return -1;
}
if (get_bits1(&s->gb) != 0) {
@@ -959,6 +967,8 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
s->h263_aic = get_bits1(&s->gb); /* Advanced Intra Coding (AIC) */
s->loop_filter= get_bits1(&s->gb);
s->unrestricted_mv = s->umvplus || s->obmc || s->loop_filter;
+ if(s->avctx->lowres)
+ s->loop_filter = 0;
s->h263_slice_structured= get_bits1(&s->gb);
if (get_bits1(&s->gb) != 0) {
@@ -1011,7 +1021,7 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
6-14 - reserved
*/
width = (get_bits(&s->gb, 9) + 1) * 4;
- skip_bits1(&s->gb);
+ check_marker(&s->gb, "in dimensions");
height = get_bits(&s->gb, 9) * 4;
ff_dlog(s->avctx, "\nH.263+ Custom picture: %dx%d\n",width,height);
if (s->aspect_ratio_info == FF_ASPECT_EXTENDED) {
@@ -1026,6 +1036,7 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
height = ff_h263_format[format][1];
s->avctx->sample_aspect_ratio= (AVRational){12,11};
}
+ s->avctx->sample_aspect_ratio.den <<= s->ehc_mode;
if ((width == 0) || (height == 0))
return -1;
s->width = width;
@@ -1070,6 +1081,10 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
s->qscale = get_bits(&s->gb, 5);
}
+ if (s->width == 0 || s->height == 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "dimensions 0\n");
+ return -1;
+ }
s->mb_width = (s->width + 15) / 16;
s->mb_height = (s->height + 15) / 16;
s->mb_num = s->mb_width * s->mb_height;
@@ -1098,20 +1113,17 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
}
/* PEI */
- while (get_bits1(&s->gb) != 0) {
- skip_bits(&s->gb, 8);
- }
+ if (skip_1stop_8data_bits(&s->gb) < 0)
+ return AVERROR_INVALIDDATA;
if(s->h263_slice_structured){
- if (get_bits1(&s->gb) != 1) {
- av_log(s->avctx, AV_LOG_ERROR, "SEPB1 marker missing\n");
+ if (check_marker(&s->gb, "SEPB1") != 1) {
return -1;
}
ff_h263_decode_mba(s);
- if (get_bits1(&s->gb) != 1) {
- av_log(s->avctx, AV_LOG_ERROR, "SEPB2 marker missing\n");
+ if (check_marker(&s->gb, "SEPB2") != 1) {
return -1;
}
}
@@ -1126,7 +1138,7 @@ int ff_h263_decode_picture_header(MpegEncContext *s)
}
ff_h263_show_pict_info(s);
- if (s->pict_type == AV_PICTURE_TYPE_I && s->codec_tag == AV_RL32("ZYGO")){
+ if (s->pict_type == AV_PICTURE_TYPE_I && s->codec_tag == AV_RL32("ZYGO") && get_bits_left(&s->gb) >= 85 + 13*3*16 + 50){
int i,j;
for(i=0; i<85; i++) av_log(s->avctx, AV_LOG_DEBUG, "%d", get_bits1(&s->gb));
av_log(s->avctx, AV_LOG_DEBUG, "\n");
diff --git a/libavcodec/ituh263enc.c b/libavcodec/ituh263enc.c
index 87a37a056b..15b2ef183d 100644
--- a/libavcodec/ituh263enc.c
+++ b/libavcodec/ituh263enc.c
@@ -5,20 +5,20 @@
* Copyright (c) 2001 Juan J. Sierralta P
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -88,7 +88,7 @@ static const uint8_t wrong_run[102] = {
av_const int ff_h263_aspect_to_info(AVRational aspect){
int i;
- if(aspect.num==0) aspect= (AVRational){1,1};
+ if(aspect.num==0 || aspect.den==0) aspect= (AVRational){1,1};
for(i=1; i<6; i++){
if(av_cmp_q(ff_h263_pixel_aspect[i], aspect) == 0){
@@ -226,19 +226,11 @@ void ff_h263_encode_picture_header(MpegEncContext * s, int picture_number)
if(s->h263_slice_structured){
put_bits(&s->pb, 1, 1);
- assert(s->mb_x == 0 && s->mb_y == 0);
+ av_assert1(s->mb_x == 0 && s->mb_y == 0);
ff_h263_encode_mba(s);
put_bits(&s->pb, 1, 1);
}
-
- if(s->h263_aic){
- s->y_dc_scale_table=
- s->c_dc_scale_table= ff_aic_dc_scale_table;
- }else{
- s->y_dc_scale_table=
- s->c_dc_scale_table= ff_mpeg1_dc_scale_table;
- }
}
/**
@@ -268,7 +260,7 @@ void ff_h263_encode_gob_header(MpegEncContext * s, int mb_line)
}
/**
- * modify qscale so that encoding is acually possible in h263 (limit difference to -2..2)
+ * modify qscale so that encoding is actually possible in h263 (limit difference to -2..2)
*/
void ff_clean_h263_qscales(MpegEncContext *s){
int i;
@@ -393,7 +385,7 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n)
put_bits(&s->pb, 1, last);
put_bits(&s->pb, 6, run);
- assert(slevel != 0);
+ av_assert2(slevel != 0);
if(level < 128)
put_sbits(&s->pb, 8, slevel);
@@ -414,7 +406,7 @@ static void h263_encode_block(MpegEncContext * s, int16_t * block, int n)
}
/* Encode MV differences on H.263+ with Unrestricted MV mode */
-static void h263p_encode_umotion(MpegEncContext * s, int val)
+static void h263p_encode_umotion(PutBitContext *pb, int val)
{
short sval = 0;
short i = 0;
@@ -424,11 +416,11 @@ static void h263p_encode_umotion(MpegEncContext * s, int val)
int tcode;
if ( val == 0)
- put_bits(&s->pb, 1, 1);
+ put_bits(pb, 1, 1);
else if (val == 1)
- put_bits(&s->pb, 3, 0);
+ put_bits(pb, 3, 0);
else if (val == -1)
- put_bits(&s->pb, 3, 2);
+ put_bits(pb, 3, 2);
else {
sval = ((val < 0) ? (short)(-val):(short)val);
@@ -447,7 +439,7 @@ static void h263p_encode_umotion(MpegEncContext * s, int val)
i--;
}
code = ((code << 1) | (val < 0)) << 1;
- put_bits(&s->pb, (2*n_bits)+1, code);
+ put_bits(pb, (2*n_bits)+1, code);
}
}
@@ -504,8 +496,8 @@ void ff_h263_encode_mb(MpegEncContext * s,
motion_y - pred_y, 1);
}
else {
- h263p_encode_umotion(s, motion_x - pred_x);
- h263p_encode_umotion(s, motion_y - pred_y);
+ h263p_encode_umotion(&s->pb, motion_x - pred_x);
+ h263p_encode_umotion(&s->pb, motion_y - pred_y);
if (((motion_x - pred_x) == 1) && ((motion_y - pred_y) == 1))
/* To prevent Start Code emulation */
put_bits(&s->pb,1,1);
@@ -533,8 +525,8 @@ void ff_h263_encode_mb(MpegEncContext * s,
motion_y - pred_y, 1);
}
else {
- h263p_encode_umotion(s, motion_x - pred_x);
- h263p_encode_umotion(s, motion_y - pred_y);
+ h263p_encode_umotion(&s->pb, motion_x - pred_x);
+ h263p_encode_umotion(&s->pb, motion_y - pred_y);
if (((motion_x - pred_x) == 1) && ((motion_y - pred_y) == 1))
/* To prevent Start Code emulation */
put_bits(&s->pb,1,1);
@@ -546,7 +538,7 @@ void ff_h263_encode_mb(MpegEncContext * s,
s->mv_bits+= get_bits_diff(s);
}
} else {
- assert(s->mb_intra);
+ av_assert2(s->mb_intra);
cbp = 0;
if (s->h263_aic) {
@@ -650,14 +642,14 @@ void ff_h263_encode_mb(MpegEncContext * s,
}
}
-void ff_h263_encode_motion(MpegEncContext * s, int val, int f_code)
+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(&s->pb, ff_mvtab[code][1], ff_mvtab[code][0]);
+ put_bits(pb, ff_mvtab[code][1], ff_mvtab[code][0]);
} else {
bit_size = f_code - 1;
range = 1 << bit_size;
@@ -671,9 +663,9 @@ void ff_h263_encode_motion(MpegEncContext * s, int val, int f_code)
code = (val >> bit_size) + 1;
bits = val & (range - 1);
- put_bits(&s->pb, ff_mvtab[code][1] + 1, (ff_mvtab[code][0] << 1) | sign);
+ put_bits(pb, ff_mvtab[code][1] + 1, (ff_mvtab[code][0] << 1) | sign);
if (bit_size > 0) {
- put_bits(&s->pb, bit_size, bits);
+ put_bits(pb, bit_size, bits);
}
}
}
@@ -725,8 +717,8 @@ static av_cold void init_uni_h263_rl_tab(RLTable *rl, uint32_t *bits_tab,
{
int slevel, run, last;
- assert(MAX_LEVEL >= 64);
- assert(MAX_RUN >= 63);
+ av_assert0(MAX_LEVEL >= 64);
+ av_assert0(MAX_RUN >= 63);
for(slevel=-64; slevel<64; slevel++){
if(slevel==0) continue;
@@ -815,12 +807,15 @@ av_cold void ff_h263_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;
break;
default: //nothing needed - default table already set in mpegvideo.c
s->min_qcoeff= -127;
s->max_qcoeff= 127;
+ }
+ if(s->h263_aic){
+ s->y_dc_scale_table=
+ s->c_dc_scale_table= ff_aic_dc_scale_table;
+ }else{
s->y_dc_scale_table=
s->c_dc_scale_table= ff_mpeg1_dc_scale_table;
}
diff --git a/libavcodec/ivi.c b/libavcodec/ivi.c
index 6086e2e681..4525ff494c 100644
--- a/libavcodec/ivi.c
+++ b/libavcodec/ivi.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -87,12 +87,9 @@ static int ivi_mc(IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg,
int ref_size = (mc_type > 1) * band->pitch + (mc_type & 1);
if (mc_type != -1) {
- if (offs < 0 || ref_offs < 0 || !band->ref_buf)
- return AVERROR_INVALIDDATA;
- if (buf_size - min_size < offs)
- return AVERROR_INVALIDDATA;
- if (buf_size - min_size - ref_size < ref_offs)
- return AVERROR_INVALIDDATA;
+ av_assert0(offs >= 0 && ref_offs >= 0 && band->ref_buf);
+ av_assert0(buf_size - min_size >= offs);
+ av_assert0(buf_size - min_size - ref_size >= ref_offs);
}
if (mc_type2 == -1) {
@@ -136,7 +133,7 @@ static uint16_t inv_bits(uint16_t val, int nbits)
/*
* Generate a huffman codebook from the given descriptor
- * and convert it into the Libav VLC table.
+ * and convert it into the FFmpeg VLC table.
*
* @param[in] cb pointer to codebook descriptor
* @param[out] vlc where to place the generated VLC table
@@ -250,7 +247,7 @@ int ff_ivi_dec_huff_desc(GetBitContext *gb, int desc_coded, int which_tab,
new_huff.xbits[i] = get_bits(gb, 4);
/* Have we got the same custom table? Rebuild if not. */
- if (ivi_huff_desc_cmp(&new_huff, &huff_tab->cust_desc)) {
+ if (ivi_huff_desc_cmp(&new_huff, &huff_tab->cust_desc) || !huff_tab->cust_tab.table) {
ivi_huff_desc_copy(&huff_tab->cust_desc, &new_huff);
if (huff_tab->cust_tab.table)
@@ -285,6 +282,7 @@ static av_cold void ivi_free_buffers(IVIPlaneDesc *planes)
int p, b, t;
for (p = 0; p < 3; p++) {
+ if (planes[p].bands)
for (b = 0; b < planes[p].num_bands; b++) {
av_freep(&planes[p].bands[b].bufs[0]);
av_freep(&planes[p].bands[b].bufs[1]);
@@ -327,7 +325,7 @@ av_cold int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg,
planes[1].num_bands = planes[2].num_bands = cfg->chroma_bands;
for (p = 0; p < 3; p++) {
- planes[p].bands = av_mallocz(planes[p].num_bands * sizeof(IVIBandDesc));
+ planes[p].bands = av_mallocz_array(planes[p].num_bands, sizeof(IVIBandDesc));
if (!planes[p].bands)
return AVERROR(ENOMEM);
@@ -356,6 +354,7 @@ av_cold int ff_ivi_init_planes(IVIPlaneDesc *planes, const IVIPicConfig *cfg,
band->aheight = height_aligned;
band->bufs[0] = av_mallocz(buf_size);
band->bufs[1] = av_mallocz(buf_size);
+ band->bufsize = buf_size/2;
if (!band->bufs[0] || !band->bufs[1])
return AVERROR(ENOMEM);
@@ -397,14 +396,16 @@ static int ivi_init_tiles(IVIBandDesc *band, IVITile *ref_tile,
band->mb_size);
av_freep(&tile->mbs);
- tile->mbs = av_malloc(tile->num_MBs * sizeof(IVIMbInfo));
+ tile->mbs = av_mallocz_array(tile->num_MBs, sizeof(IVIMbInfo));
if (!tile->mbs)
return AVERROR(ENOMEM);
tile->ref_mbs = 0;
if (p || b) {
- if (tile->num_MBs != ref_tile->num_MBs)
+ if (tile->num_MBs != ref_tile->num_MBs) {
+ av_log(NULL, AV_LOG_DEBUG, "ref_tile mismatch\n");
return AVERROR_INVALIDDATA;
+ }
tile->ref_mbs = ref_tile->mbs;
ref_tile++;
}
@@ -429,6 +430,8 @@ av_cold int ff_ivi_init_tiles(IVIPlaneDesc *planes,
t_width >>= 1;
t_height >>= 1;
}
+ if(t_width<=0 || t_height<=0)
+ return AVERROR(EINVAL);
for (b = 0; b < planes[p].num_bands; b++) {
band = &planes[p].bands[b];
@@ -437,7 +440,7 @@ av_cold int ff_ivi_init_tiles(IVIPlaneDesc *planes,
band->num_tiles = x_tiles * y_tiles;
av_freep(&band->tiles);
- band->tiles = av_mallocz(band->num_tiles * sizeof(IVITile));
+ band->tiles = av_mallocz_array(band->num_tiles, sizeof(IVITile));
if (!band->tiles)
return AVERROR(ENOMEM);
@@ -486,10 +489,6 @@ static int ivi_dc_transform(IVIBandDesc *band, int *prev_dc, int buf_offs,
int buf_size = band->pitch * band->aheight - buf_offs;
int min_size = (blk_size - 1) * band->pitch + blk_size;
- if (!band->dc_transform)
- return 0;
-
-
if (min_size > buf_size)
return AVERROR_INVALIDDATA;
@@ -583,6 +582,11 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band,
col_flags[0] |= !!*prev_dc;
}
+ if(band->transform_size > band->blk_size){
+ av_log(NULL, AV_LOG_ERROR, "Too large transform\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* apply inverse transform */
band->inv_transform(trvec, band->buf + offs,
band->pitch, col_flags);
@@ -642,7 +646,7 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band,
quant = band->glob_quant + mb->q_delta;
if (avctx->codec_id == AV_CODEC_ID_INDEO4)
- quant = av_clip(quant, 0, 31);
+ quant = av_clip_uintp2(quant, 5);
else
quant = av_clip(quant, 0, 23);
@@ -805,6 +809,22 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band,
mb->mv_y = ref_mb->mv_y;
}
need_mc |= mb->mv_x || mb->mv_y; /* tracking non-zero motion vectors */
+ {
+ int dmv_x, dmv_y, cx, cy;
+
+ dmv_x = mb->mv_x >> band->is_halfpel;
+ dmv_y = mb->mv_y >> band->is_halfpel;
+ cx = mb->mv_x & band->is_halfpel;
+ cy = mb->mv_y & band->is_halfpel;
+
+ if ( mb->xpos + dmv_x < 0
+ || mb->xpos + dmv_x + band->mb_size + cx > band->pitch
+ || mb->ypos + dmv_y < 0
+ || mb->ypos + dmv_y + band->mb_size + cy > band->aheight) {
+ av_log(avctx, AV_LOG_ERROR, "MV out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
}
mb++;
@@ -946,6 +966,10 @@ static int decode_band(IVI45DecContext *ctx,
idx2 = band->corr[i * 2 + 1];
FFSWAP(uint8_t, band->rv_map->runtab[idx1], band->rv_map->runtab[idx2]);
FFSWAP(int16_t, band->rv_map->valtab[idx1], band->rv_map->valtab[idx2]);
+ if (idx1 == band->rv_map->eob_sym || idx2 == band->rv_map->eob_sym)
+ band->rv_map->eob_sym ^= idx1 ^ idx2;
+ if (idx1 == band->rv_map->esc_sym || idx2 == band->rv_map->esc_sym)
+ band->rv_map->esc_sym ^= idx1 ^ idx2;
}
pos = get_bits_count(&ctx->gb);
@@ -969,7 +993,8 @@ static int decode_band(IVI45DecContext *ctx,
tile->data_size = ivi_dec_tile_data_size(&ctx->gb);
if (!tile->data_size) {
av_log(avctx, AV_LOG_ERROR, "Tile data size is zero!\n");
- return AVERROR_INVALIDDATA;
+ result = AVERROR_INVALIDDATA;
+ break;
}
result = ctx->decode_mb_info(ctx, band, tile, avctx);
@@ -1001,6 +1026,10 @@ static int decode_band(IVI45DecContext *ctx,
idx2 = band->corr[i*2+1];
FFSWAP(uint8_t, band->rv_map->runtab[idx1], band->rv_map->runtab[idx2]);
FFSWAP(int16_t, band->rv_map->valtab[idx1], band->rv_map->valtab[idx2]);
+ if (idx1 == band->rv_map->eob_sym || idx2 == band->rv_map->eob_sym)
+ band->rv_map->eob_sym ^= idx1 ^ idx2;
+ if (idx1 == band->rv_map->esc_sym || idx2 == band->rv_map->esc_sym)
+ band->rv_map->esc_sym ^= idx1 ^ idx2;
}
#ifdef DEBUG
@@ -1068,6 +1097,7 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
//{ START_TIMER;
if (ctx->is_nonnull_frame(ctx)) {
+ ctx->buf_invalid[ctx->dst_buf] = 1;
for (p = 0; p < 3; p++) {
for (b = 0; b < ctx->planes[p].num_bands; b++) {
result = decode_band(ctx, &ctx->planes[p].bands[b], avctx);
@@ -1078,6 +1108,7 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
}
}
+ ctx->buf_invalid[ctx->dst_buf] = 0;
} else {
if (ctx->is_scalable)
return AVERROR_INVALIDDATA;
@@ -1087,17 +1118,20 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
}
+ if (ctx->buf_invalid[ctx->dst_buf])
+ return -1;
//STOP_TIMER("decode_planes"); }
+ if (!ctx->is_nonnull_frame(ctx))
+ return buf_size;
+
result = ff_set_dimensions(avctx, ctx->planes[0].width, ctx->planes[0].height);
if (result < 0)
return result;
- if ((result = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((result = ff_get_buffer(avctx, frame, 0)) < 0)
return result;
- }
if (ctx->is_scalable) {
if (ctx->is_indeo4)
@@ -1121,7 +1155,11 @@ int ff_ivi_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (ctx->is_indeo4 && ctx->frame_type == IVI4_FRAMETYPE_INTRA) {
int left;
- while (get_bits(&ctx->gb, 8)); // skip version string
+ // skip version string
+ while (get_bits(&ctx->gb, 8)) {
+ if (get_bits_left(&ctx->gb) < 8)
+ return AVERROR_INVALIDDATA;
+ }
left = get_bits_count(&ctx->gb) & 0x18;
skip_bits_long(&ctx->gb, 64 - left);
if (get_bits_left(&ctx->gb) > 18 &&
diff --git a/libavcodec/ivi.h b/libavcodec/ivi.h
index 5dadd9f4a5..abe43462a1 100644
--- a/libavcodec/ivi.h
+++ b/libavcodec/ivi.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -165,6 +165,7 @@ typedef struct IVIBandDesc {
int quant_mat; ///< dequant matrix index
int glob_quant; ///< quant base for this band
const uint8_t *scan; ///< ptr to the scan pattern
+ int scan_size; ///< size of the scantable
IVIHuffTab blk_vlc; ///< vlc table for decoding block data
@@ -264,6 +265,7 @@ typedef struct IVI45DecContext {
int (*is_nonnull_frame)(struct IVI45DecContext *ctx);
int gop_invalid;
+ int buf_invalid[4];
int is_indeo4;
diff --git a/libavcodec/ivi_dsp.c b/libavcodec/ivi_dsp.c
index 7d1278431b..4b973992e0 100644
--- a/libavcodec/ivi_dsp.c
+++ b/libavcodec/ivi_dsp.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@ void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst,
int32_t b0_1, b0_2, b1_1, b1_2, b1_3, b2_1, b2_2, b2_3, b2_4, b2_5, b2_6;
int32_t b3_1, b3_2, b3_3, b3_4, b3_5, b3_6, b3_7, b3_8, b3_9;
int32_t pitch, back_pitch;
- const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
+ const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
const int num_bands = 4;
/* all bands should have the same pitch */
@@ -54,6 +54,9 @@ void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst,
b3_ptr = plane->bands[3].buf;
for (y = 0; y < plane->height; y += 2) {
+
+ if (y+2 >= plane->height)
+ pitch= 0;
/* load storage variables with values */
if (num_bands > 0) {
b0_1 = b0_ptr[0];
@@ -83,6 +86,13 @@ void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst,
}
for (x = 0, indx = 0; x < plane->width; x+=2, indx++) {
+ if (x+2 >= plane->width) {
+ b0_ptr --;
+ b1_ptr --;
+ b2_ptr --;
+ b3_ptr --;
+ }
+
/* some values calculated in the previous iterations can */
/* be reused in the next ones, so do appropriate copying */
b2_1 = b2_2; // b2[x-1,y ] = b2[x, y ]
@@ -170,10 +180,10 @@ void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst,
back_pitch = -pitch;
- b0_ptr += pitch;
- b1_ptr += pitch;
- b2_ptr += pitch;
- b3_ptr += pitch;
+ b0_ptr += pitch + 1;
+ b1_ptr += pitch + 1;
+ b2_ptr += pitch + 1;
+ b3_ptr += pitch + 1;
}
}
@@ -181,7 +191,7 @@ void ff_ivi_recompose_haar(const IVIPlaneDesc *plane, uint8_t *dst,
const int dst_pitch)
{
int x, y, indx, b0, b1, b2, b3, p0, p1, p2, p3;
- const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
+ const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr;
int32_t pitch;
/* all bands should have the same pitch */
@@ -225,15 +235,15 @@ void ff_ivi_recompose_haar(const IVIPlaneDesc *plane, uint8_t *dst,
/** butterfly operation for the inverse Haar transform */
#define IVI_HAAR_BFLY(s1, s2, o1, o2, t) \
- t = (s1 - s2) >> 1;\
- o1 = (s1 + s2) >> 1;\
- o2 = t;\
+ t = ((s1) - (s2)) >> 1;\
+ o1 = ((s1) + (s2)) >> 1;\
+ o2 = (t);\
/** inverse 8-point Haar transform */
#define INV_HAAR8(s1, s5, s3, s7, s2, s4, s6, s8,\
d1, d2, d3, d4, d5, d6, d7, d8,\
t0, t1, t2, t3, t4, t5, t6, t7, t8) {\
- t1 = s1 << 1; t5 = s5 << 1;\
+ t1 = (s1) << 1; t5 = (s5) << 1;\
IVI_HAAR_BFLY(t1, t5, t1, t5, t0); IVI_HAAR_BFLY(t1, s3, t1, t3, t0);\
IVI_HAAR_BFLY(t5, s7, t5, t7, t0); IVI_HAAR_BFLY(t1, s2, t1, t2, t0);\
IVI_HAAR_BFLY(t3, s4, t3, t4, t0); IVI_HAAR_BFLY(t5, s6, t5, t6, t0);\
@@ -475,21 +485,21 @@ void ff_ivi_dc_haar_2d(const int32_t *in, int16_t *out, uint32_t pitch,
/** butterfly operation for the inverse slant transform */
#define IVI_SLANT_BFLY(s1, s2, o1, o2, t) \
- t = s1 - s2;\
- o1 = s1 + s2;\
- o2 = t;\
+ t = (s1) - (s2);\
+ o1 = (s1) + (s2);\
+ o2 = (t);\
/** This is a reflection a,b = 1/2, 5/4 for the inverse slant transform */
#define IVI_IREFLECT(s1, s2, o1, o2, t) \
- t = ((s1 + s2*2 + 2) >> 2) + s1;\
- o2 = ((s1*2 - s2 + 2) >> 2) - s2;\
- o1 = t;\
+ t = (((s1) + (s2)*2 + 2) >> 2) + (s1);\
+ o2 = (((s1)*2 - (s2) + 2) >> 2) - (s2);\
+ o1 = (t);\
/** This is a reflection a,b = 1/2, 7/8 for the inverse slant transform */
#define IVI_SLANT_PART4(s1, s2, o1, o2, t) \
- t = s2 + ((s1*4 - s2 + 4) >> 3);\
- o2 = s1 + ((-s1 - s2*4 + 4) >> 3);\
- o1 = t;\
+ t = (s2) + (((s1)*4 - (s2) + 4) >> 3);\
+ o2 = (s1) + ((-(s1) - (s2)*4 + 4) >> 3);\
+ o1 = (t);\
/** inverse slant8 transform */
#define IVI_INV_SLANT8(s1, s4, s8, s5, s2, s6, s3, s7,\
@@ -547,7 +557,7 @@ void ff_ivi_inverse_slant_8x8(const int32_t *in, int16_t *out, uint32_t pitch, c
}
#undef COMPENSATE
-#define COMPENSATE(x) ((x + 1)>>1)
+#define COMPENSATE(x) (((x) + 1)>>1)
src = tmp;
for (i = 0; i < 8; i++) {
if (!src[0] && !src[1] && !src[2] && !src[3] && !src[4] && !src[5] && !src[6] && !src[7]) {
@@ -587,7 +597,7 @@ void ff_ivi_inverse_slant_4x4(const int32_t *in, int16_t *out, uint32_t pitch, c
}
#undef COMPENSATE
-#define COMPENSATE(x) ((x + 1)>>1)
+#define COMPENSATE(x) (((x) + 1)>>1)
src = tmp;
for (i = 0; i < 4; i++) {
if (!src[0] && !src[1] && !src[2] && !src[3]) {
@@ -621,7 +631,7 @@ void ff_ivi_row_slant8(const int32_t *in, int16_t *out, uint32_t pitch, const ui
int i;
int t0, t1, t2, t3, t4, t5, t6, t7, t8;
-#define COMPENSATE(x) ((x + 1)>>1)
+#define COMPENSATE(x) (((x) + 1)>>1)
for (i = 0; i < 8; i++) {
if (!in[0] && !in[1] && !in[2] && !in[3] && !in[4] && !in[5] && !in[6] && !in[7]) {
memset(out, 0, 8*sizeof(out[0]));
@@ -663,7 +673,7 @@ void ff_ivi_col_slant8(const int32_t *in, int16_t *out, uint32_t pitch, const ui
row4 = pitch << 2;
row8 = pitch << 3;
-#define COMPENSATE(x) ((x + 1)>>1)
+#define COMPENSATE(x) (((x) + 1)>>1)
for (i = 0; i < 8; i++) {
if (flags[i]) {
IVI_INV_SLANT8(in[0], in[8], in[16], in[24], in[32], in[40], in[48], in[56],
@@ -700,7 +710,7 @@ void ff_ivi_row_slant4(const int32_t *in, int16_t *out, uint32_t pitch, const ui
int i;
int t0, t1, t2, t3, t4;
-#define COMPENSATE(x) ((x + 1)>>1)
+#define COMPENSATE(x) (((x) + 1)>>1)
for (i = 0; i < 4; i++) {
if (!in[0] && !in[1] && !in[2] && !in[3]) {
memset(out, 0, 4*sizeof(out[0]));
@@ -722,7 +732,7 @@ void ff_ivi_col_slant4(const int32_t *in, int16_t *out, uint32_t pitch, const ui
row2 = pitch << 1;
-#define COMPENSATE(x) ((x + 1)>>1)
+#define COMPENSATE(x) (((x) + 1)>>1)
for (i = 0; i < 4; i++) {
if (flags[i]) {
IVI_INV_SLANT4(in[0], in[4], in[8], in[12],
diff --git a/libavcodec/ivi_dsp.h b/libavcodec/ivi_dsp.h
index 45c8a18086..f64c718e72 100644
--- a/libavcodec/ivi_dsp.h
+++ b/libavcodec/ivi_dsp.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,6 +65,10 @@ void ff_ivi_recompose_haar(const IVIPlaneDesc *plane, uint8_t *dst,
*/
void ff_ivi_inverse_haar_8x8(const int32_t *in, int16_t *out, uint32_t pitch,
const uint8_t *flags);
+void ff_ivi_inverse_haar_8x1(const int32_t *in, int16_t *out, uint32_t pitch,
+ const uint8_t *flags);
+void ff_ivi_inverse_haar_1x8(const int32_t *in, int16_t *out, uint32_t pitch,
+ const uint8_t *flags);
/**
* one-dimensional inverse 8-point Haar transform on rows for Indeo 4
diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c
new file mode 100644
index 0000000000..593ceb40e5
--- /dev/null
+++ b/libavcodec/j2kenc.c
@@ -0,0 +1,1055 @@
+/*
+ * JPEG2000 image encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * JPEG2000 image encoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include <float.h>
+#include "avcodec.h"
+#include "internal.h"
+#include "bytestream.h"
+#include "jpeg2000.h"
+#include "libavutil/common.h"
+
+#define NMSEDEC_BITS 7
+#define NMSEDEC_FRACBITS (NMSEDEC_BITS-1)
+#define WMSEDEC_SHIFT 13 ///< must be >= 13
+#define LAMBDA_SCALE (100000000LL << (WMSEDEC_SHIFT - 13))
+
+static int lut_nmsedec_ref [1<<NMSEDEC_BITS],
+ lut_nmsedec_ref0[1<<NMSEDEC_BITS],
+ lut_nmsedec_sig [1<<NMSEDEC_BITS],
+ lut_nmsedec_sig0[1<<NMSEDEC_BITS];
+
+static const int dwt_norms[2][4][10] = { // [dwt_type][band][rlevel] (multiplied by 10000)
+ {{10000, 19650, 41770, 84030, 169000, 338400, 676900, 1353000, 2706000, 5409000},
+ {20220, 39890, 83550, 170400, 342700, 686300, 1373000, 2746000, 5490000},
+ {20220, 39890, 83550, 170400, 342700, 686300, 1373000, 2746000, 5490000},
+ {20800, 38650, 83070, 171800, 347100, 695900, 1393000, 2786000, 5572000}},
+
+ {{10000, 15000, 27500, 53750, 106800, 213400, 426700, 853300, 1707000, 3413000},
+ {10380, 15920, 29190, 57030, 113300, 226400, 452500, 904800, 1809000},
+ {10380, 15920, 29190, 57030, 113300, 226400, 452500, 904800, 1809000},
+ { 7186, 9218, 15860, 30430, 60190, 120100, 240000, 479700, 959300}}
+};
+
+typedef struct {
+ Jpeg2000Component *comp;
+} Jpeg2000Tile;
+
+typedef struct {
+ AVCodecContext *avctx;
+ const AVFrame *picture;
+
+ int width, height; ///< image width and height
+ uint8_t cbps[4]; ///< bits per sample in particular components
+ int chroma_shift[2];
+ uint8_t planar;
+ int ncomponents;
+ int tile_width, tile_height; ///< tile size
+ int numXtiles, numYtiles;
+
+ uint8_t *buf_start;
+ uint8_t *buf;
+ uint8_t *buf_end;
+ int bit_index;
+
+ int64_t lambda;
+
+ Jpeg2000CodingStyle codsty;
+ Jpeg2000QuantStyle qntsty;
+
+ Jpeg2000Tile *tile;
+} Jpeg2000EncoderContext;
+
+
+/* debug */
+#if 0
+#undef ifprintf
+#undef printf
+
+static void nspaces(FILE *fd, int n)
+{
+ while(n--) putc(' ', fd);
+}
+
+static void printcomp(Jpeg2000Component *comp)
+{
+ int i;
+ for (i = 0; i < comp->y1 - comp->y0; i++)
+ ff_jpeg2000_printv(comp->i_data + i * (comp->x1 - comp->x0), comp->x1 - comp->x0);
+}
+
+static void dump(Jpeg2000EncoderContext *s, FILE *fd)
+{
+ int tileno, compno, reslevelno, bandno, precno;
+ fprintf(fd, "XSiz = %d, YSiz = %d, tile_width = %d, tile_height = %d\n"
+ "numXtiles = %d, numYtiles = %d, ncomponents = %d\n"
+ "tiles:\n",
+ s->width, s->height, s->tile_width, s->tile_height,
+ s->numXtiles, s->numYtiles, s->ncomponents);
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ Jpeg2000Tile *tile = s->tile + tileno;
+ nspaces(fd, 2);
+ fprintf(fd, "tile %d:\n", tileno);
+ for(compno = 0; compno < s->ncomponents; compno++){
+ Jpeg2000Component *comp = tile->comp + compno;
+ nspaces(fd, 4);
+ fprintf(fd, "component %d:\n", compno);
+ nspaces(fd, 4);
+ fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d\n",
+ comp->x0, comp->x1, comp->y0, comp->y1);
+ for(reslevelno = 0; reslevelno < s->nreslevels; reslevelno++){
+ Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno;
+ nspaces(fd, 6);
+ fprintf(fd, "reslevel %d:\n", reslevelno);
+ nspaces(fd, 6);
+ fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d, nbands = %d\n",
+ reslevel->x0, reslevel->x1, reslevel->y0,
+ reslevel->y1, reslevel->nbands);
+ for(bandno = 0; bandno < reslevel->nbands; bandno++){
+ Jpeg2000Band *band = reslevel->band + bandno;
+ nspaces(fd, 8);
+ fprintf(fd, "band %d:\n", bandno);
+ nspaces(fd, 8);
+ fprintf(fd, "x0 = %d, x1 = %d, y0 = %d, y1 = %d,"
+ "codeblock_width = %d, codeblock_height = %d cblknx = %d cblkny = %d\n",
+ band->x0, band->x1,
+ band->y0, band->y1,
+ band->codeblock_width, band->codeblock_height,
+ band->cblknx, band->cblkny);
+ for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+ Jpeg2000Prec *prec = band->prec + precno;
+ nspaces(fd, 10);
+ fprintf(fd, "prec %d:\n", precno);
+ nspaces(fd, 10);
+ fprintf(fd, "xi0 = %d, xi1 = %d, yi0 = %d, yi1 = %d\n",
+ prec->xi0, prec->xi1, prec->yi0, prec->yi1);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+/* bitstream routines */
+
+/** put n times val bit */
+static void put_bits(Jpeg2000EncoderContext *s, int val, int n) // TODO: optimize
+{
+ while (n-- > 0){
+ if (s->bit_index == 8)
+ {
+ s->bit_index = *s->buf == 0xff;
+ *(++s->buf) = 0;
+ }
+ *s->buf |= val << (7 - s->bit_index++);
+ }
+}
+
+/** put n least significant bits of a number num */
+static void put_num(Jpeg2000EncoderContext *s, int num, int n)
+{
+ while(--n >= 0)
+ put_bits(s, (num >> n) & 1, 1);
+}
+
+/** flush the bitstream */
+static void j2k_flush(Jpeg2000EncoderContext *s)
+{
+ if (s->bit_index){
+ s->bit_index = 0;
+ s->buf++;
+ }
+}
+
+/* tag tree routines */
+
+/** code the value stored in node */
+static void tag_tree_code(Jpeg2000EncoderContext *s, Jpeg2000TgtNode *node, int threshold)
+{
+ Jpeg2000TgtNode *stack[30];
+ int sp = 1, curval = 0;
+ stack[0] = node;
+
+ node = node->parent;
+ while(node){
+ if (node->vis){
+ curval = node->val;
+ break;
+ }
+ node->vis++;
+ stack[sp++] = node;
+ node = node->parent;
+ }
+ while(--sp >= 0){
+ if (stack[sp]->val >= threshold){
+ put_bits(s, 0, threshold - curval);
+ break;
+ }
+ put_bits(s, 0, stack[sp]->val - curval);
+ put_bits(s, 1, 1);
+ curval = stack[sp]->val;
+ }
+}
+
+/** update the value in node */
+static void tag_tree_update(Jpeg2000TgtNode *node)
+{
+ int lev = 0;
+ while (node->parent){
+ if (node->parent->val <= node->val)
+ break;
+ node->parent->val = node->val;
+ node = node->parent;
+ lev++;
+ }
+}
+
+static int put_siz(Jpeg2000EncoderContext *s)
+{
+ int i;
+
+ if (s->buf_end - s->buf < 40 + 3 * s->ncomponents)
+ return -1;
+
+ bytestream_put_be16(&s->buf, JPEG2000_SIZ);
+ bytestream_put_be16(&s->buf, 38 + 3 * s->ncomponents); // Lsiz
+ bytestream_put_be16(&s->buf, 0); // Rsiz
+ bytestream_put_be32(&s->buf, s->width); // width
+ bytestream_put_be32(&s->buf, s->height); // height
+ bytestream_put_be32(&s->buf, 0); // X0Siz
+ bytestream_put_be32(&s->buf, 0); // Y0Siz
+
+ bytestream_put_be32(&s->buf, s->tile_width); // XTSiz
+ bytestream_put_be32(&s->buf, s->tile_height); // YTSiz
+ bytestream_put_be32(&s->buf, 0); // XT0Siz
+ bytestream_put_be32(&s->buf, 0); // YT0Siz
+ bytestream_put_be16(&s->buf, s->ncomponents); // CSiz
+
+ for (i = 0; i < s->ncomponents; i++){ // Ssiz_i XRsiz_i, YRsiz_i
+ bytestream_put_byte(&s->buf, 7);
+ bytestream_put_byte(&s->buf, i?1<<s->chroma_shift[0]:1);
+ bytestream_put_byte(&s->buf, i?1<<s->chroma_shift[1]:1);
+ }
+ return 0;
+}
+
+static int put_cod(Jpeg2000EncoderContext *s)
+{
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+
+ if (s->buf_end - s->buf < 14)
+ return -1;
+
+ bytestream_put_be16(&s->buf, JPEG2000_COD);
+ bytestream_put_be16(&s->buf, 12); // Lcod
+ bytestream_put_byte(&s->buf, 0); // Scod
+ // SGcod
+ bytestream_put_byte(&s->buf, 0); // progression level
+ bytestream_put_be16(&s->buf, 1); // num of layers
+ if(s->avctx->pix_fmt == AV_PIX_FMT_YUV444P){
+ bytestream_put_byte(&s->buf, 2); // ICT
+ }else{
+ bytestream_put_byte(&s->buf, 0); // unspecified
+ }
+ // SPcod
+ bytestream_put_byte(&s->buf, codsty->nreslevels - 1); // num of decomp. levels
+ bytestream_put_byte(&s->buf, codsty->log2_cblk_width-2); // cblk width
+ bytestream_put_byte(&s->buf, codsty->log2_cblk_height-2); // cblk height
+ bytestream_put_byte(&s->buf, 0); // cblk style
+ bytestream_put_byte(&s->buf, codsty->transform == FF_DWT53); // transformation
+ return 0;
+}
+
+static int put_qcd(Jpeg2000EncoderContext *s, int compno)
+{
+ int i, size;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+ Jpeg2000QuantStyle *qntsty = &s->qntsty;
+
+ if (qntsty->quantsty == JPEG2000_QSTY_NONE)
+ size = 4 + 3 * (codsty->nreslevels-1);
+ else // QSTY_SE
+ size = 5 + 6 * (codsty->nreslevels-1);
+
+ if (s->buf_end - s->buf < size + 2)
+ return -1;
+
+ bytestream_put_be16(&s->buf, JPEG2000_QCD);
+ bytestream_put_be16(&s->buf, size); // LQcd
+ bytestream_put_byte(&s->buf, (qntsty->nguardbits << 5) | qntsty->quantsty); // Sqcd
+ if (qntsty->quantsty == JPEG2000_QSTY_NONE)
+ for (i = 0; i < codsty->nreslevels * 3 - 2; i++)
+ bytestream_put_byte(&s->buf, qntsty->expn[i] << 3);
+ else // QSTY_SE
+ for (i = 0; i < codsty->nreslevels * 3 - 2; i++)
+ bytestream_put_be16(&s->buf, (qntsty->expn[i] << 11) | qntsty->mant[i]);
+ return 0;
+}
+
+static uint8_t *put_sot(Jpeg2000EncoderContext *s, int tileno)
+{
+ uint8_t *psotptr;
+
+ if (s->buf_end - s->buf < 12)
+ return NULL;
+
+ bytestream_put_be16(&s->buf, JPEG2000_SOT);
+ bytestream_put_be16(&s->buf, 10); // Lsot
+ bytestream_put_be16(&s->buf, tileno); // Isot
+
+ psotptr = s->buf;
+ bytestream_put_be32(&s->buf, 0); // Psot (filled in later)
+
+ bytestream_put_byte(&s->buf, 0); // TPsot
+ bytestream_put_byte(&s->buf, 1); // TNsot
+ return psotptr;
+}
+
+/**
+ * compute the sizes of tiles, resolution levels, bands, etc.
+ * allocate memory for them
+ * divide the input image into tile-components
+ */
+static int init_tiles(Jpeg2000EncoderContext *s)
+{
+ int tileno, tilex, tiley, compno;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+ Jpeg2000QuantStyle *qntsty = &s->qntsty;
+
+ s->numXtiles = ff_jpeg2000_ceildiv(s->width, s->tile_width);
+ s->numYtiles = ff_jpeg2000_ceildiv(s->height, s->tile_height);
+
+ s->tile = av_malloc_array(s->numXtiles, s->numYtiles * sizeof(Jpeg2000Tile));
+ if (!s->tile)
+ return AVERROR(ENOMEM);
+ for (tileno = 0, tiley = 0; tiley < s->numYtiles; tiley++)
+ for (tilex = 0; tilex < s->numXtiles; tilex++, tileno++){
+ Jpeg2000Tile *tile = s->tile + tileno;
+
+ tile->comp = av_mallocz_array(s->ncomponents, sizeof(Jpeg2000Component));
+ if (!tile->comp)
+ return AVERROR(ENOMEM);
+ for (compno = 0; compno < s->ncomponents; compno++){
+ Jpeg2000Component *comp = tile->comp + compno;
+ int ret, i, j;
+
+ comp->coord[0][0] = comp->coord_o[0][0] = tilex * s->tile_width;
+ comp->coord[0][1] = comp->coord_o[0][1] = FFMIN((tilex+1)*s->tile_width, s->width);
+ comp->coord[1][0] = comp->coord_o[1][0] = tiley * s->tile_height;
+ comp->coord[1][1] = comp->coord_o[1][1] = FFMIN((tiley+1)*s->tile_height, s->height);
+ if (compno > 0)
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
+ comp->coord[i][j] = comp->coord_o[i][j] = ff_jpeg2000_ceildivpow2(comp->coord[i][j], s->chroma_shift[i]);
+
+ if ((ret = ff_jpeg2000_init_component(comp,
+ codsty,
+ qntsty,
+ s->cbps[compno],
+ compno?1<<s->chroma_shift[0]:1,
+ compno?1<<s->chroma_shift[1]:1,
+ s->avctx
+ )) < 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void copy_frame(Jpeg2000EncoderContext *s)
+{
+ int tileno, compno, i, y, x;
+ uint8_t *line;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ Jpeg2000Tile *tile = s->tile + tileno;
+ if (s->planar){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ Jpeg2000Component *comp = tile->comp + compno;
+ int *dst = comp->i_data;
+ line = s->picture->data[compno]
+ + comp->coord[1][0] * s->picture->linesize[compno]
+ + comp->coord[0][0];
+ for (y = comp->coord[1][0]; y < comp->coord[1][1]; y++){
+ uint8_t *ptr = line;
+ for (x = comp->coord[0][0]; x < comp->coord[0][1]; x++)
+ *dst++ = *ptr++ - (1 << 7);
+ line += s->picture->linesize[compno];
+ }
+ }
+ } else{
+ line = s->picture->data[0] + tile->comp[0].coord[1][0] * s->picture->linesize[0]
+ + tile->comp[0].coord[0][0] * s->ncomponents;
+
+ i = 0;
+ for (y = tile->comp[0].coord[1][0]; y < tile->comp[0].coord[1][1]; y++){
+ uint8_t *ptr = line;
+ for (x = tile->comp[0].coord[0][0]; x < tile->comp[0].coord[0][1]; x++, i++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ tile->comp[compno].i_data[i] = *ptr++ - (1 << 7);
+ }
+ }
+ line += s->picture->linesize[0];
+ }
+ }
+ }
+}
+
+static void init_quantization(Jpeg2000EncoderContext *s)
+{
+ int compno, reslevelno, bandno;
+ Jpeg2000QuantStyle *qntsty = &s->qntsty;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+
+ for (compno = 0; compno < s->ncomponents; compno++){
+ int gbandno = 0;
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ int nbands, lev = codsty->nreslevels - reslevelno - 1;
+ nbands = reslevelno ? 3 : 1;
+ for (bandno = 0; bandno < nbands; bandno++, gbandno++){
+ int expn, mant = 0;
+
+ if (codsty->transform == FF_DWT97_INT){
+ int bandpos = bandno + (reslevelno>0),
+ ss = 81920000 / dwt_norms[0][bandpos][lev],
+ log = av_log2(ss);
+ mant = (11 - log < 0 ? ss >> log - 11 : ss << 11 - log) & 0x7ff;
+ expn = s->cbps[compno] - log + 13;
+ } else
+ expn = ((bandno&2)>>1) + (reslevelno>0) + s->cbps[compno];
+
+ qntsty->expn[gbandno] = expn;
+ qntsty->mant[gbandno] = mant;
+ }
+ }
+ }
+}
+
+static void init_luts(void)
+{
+ int i, a,
+ mask = ~((1<<NMSEDEC_FRACBITS)-1);
+
+ for (i = 0; i < (1 << NMSEDEC_BITS); i++){
+ lut_nmsedec_sig[i] = FFMAX(6*i - (9<<NMSEDEC_FRACBITS-1) << 12-NMSEDEC_FRACBITS, 0);
+ lut_nmsedec_sig0[i] = FFMAX((i*i + (1<<NMSEDEC_FRACBITS-1) & mask) << 1, 0);
+
+ a = (i >> (NMSEDEC_BITS-2)&2) + 1;
+ lut_nmsedec_ref[i] = FFMAX((-2*i + (1<<NMSEDEC_FRACBITS) + a*i - (a*a<<NMSEDEC_FRACBITS-2))
+ << 13-NMSEDEC_FRACBITS, 0);
+ lut_nmsedec_ref0[i] = FFMAX(((i*i + (1-4*i << NMSEDEC_FRACBITS-1) + (1<<2*NMSEDEC_FRACBITS)) & mask)
+ << 1, 0);
+ }
+}
+
+/* tier-1 routines */
+static int getnmsedec_sig(int x, int bpno)
+{
+ if (bpno > NMSEDEC_FRACBITS)
+ return lut_nmsedec_sig[(x >> (bpno - NMSEDEC_FRACBITS)) & ((1 << NMSEDEC_BITS) - 1)];
+ return lut_nmsedec_sig0[x & ((1 << NMSEDEC_BITS) - 1)];
+}
+
+static int getnmsedec_ref(int x, int bpno)
+{
+ if (bpno > NMSEDEC_FRACBITS)
+ return lut_nmsedec_ref[(x >> (bpno - NMSEDEC_FRACBITS)) & ((1 << NMSEDEC_BITS) - 1)];
+ return lut_nmsedec_ref0[x & ((1 << NMSEDEC_BITS) - 1)];
+}
+
+static void encode_sigpass(Jpeg2000T1Context *t1, int width, int height, int bandno, int *nmsedec, int bpno)
+{
+ int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+ for (y0 = 0; y0 < height; y0 += 4)
+ for (x = 0; x < width; x++)
+ for (y = y0; y < height && y < y0+4; y++){
+ if (!(t1->flags[y+1][x+1] & JPEG2000_T1_SIG) && (t1->flags[y+1][x+1] & JPEG2000_T1_SIG_NB)){
+ int ctxno = ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1], bandno),
+ bit = t1->data[y][x] & mask ? 1 : 0;
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, bit);
+ if (bit){
+ int xorbit;
+ int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit);
+ *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+ ff_jpeg2000_set_significance(t1, x, y, t1->flags[y+1][x+1] >> 15);
+ }
+ t1->flags[y+1][x+1] |= JPEG2000_T1_VIS;
+ }
+ }
+}
+
+static void encode_refpass(Jpeg2000T1Context *t1, int width, int height, int *nmsedec, int bpno)
+{
+ int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+ for (y0 = 0; y0 < height; y0 += 4)
+ for (x = 0; x < width; x++)
+ for (y = y0; y < height && y < y0+4; y++)
+ if ((t1->flags[y+1][x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS)) == JPEG2000_T1_SIG){
+ int ctxno = ff_jpeg2000_getrefctxno(t1->flags[y+1][x+1]);
+ *nmsedec += getnmsedec_ref(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0);
+ t1->flags[y+1][x+1] |= JPEG2000_T1_REF;
+ }
+}
+
+static void encode_clnpass(Jpeg2000T1Context *t1, int width, int height, int bandno, int *nmsedec, int bpno)
+{
+ int y0, x, y, mask = 1 << (bpno + NMSEDEC_FRACBITS);
+ for (y0 = 0; y0 < height; y0 += 4)
+ for (x = 0; x < width; x++){
+ if (y0 + 3 < height && !(
+ (t1->flags[y0+1][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) ||
+ (t1->flags[y0+2][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) ||
+ (t1->flags[y0+3][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG)) ||
+ (t1->flags[y0+4][x+1] & (JPEG2000_T1_SIG_NB | JPEG2000_T1_VIS | JPEG2000_T1_SIG))))
+ {
+ // aggregation mode
+ int rlen;
+ for (rlen = 0; rlen < 4; rlen++)
+ if (t1->data[y0+rlen][x] & mask)
+ break;
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_RL, rlen != 4);
+ if (rlen == 4)
+ continue;
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI, rlen >> 1);
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + MQC_CX_UNI, rlen & 1);
+ for (y = y0 + rlen; y < y0 + 4; y++){
+ if (!(t1->flags[y+1][x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))){
+ int ctxno = ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1], bandno);
+ if (y > y0 + rlen)
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0);
+ if (t1->data[y][x] & mask){ // newly significant
+ int xorbit;
+ int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+ *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit);
+ ff_jpeg2000_set_significance(t1, x, y, t1->flags[y+1][x+1] >> 15);
+ }
+ }
+ t1->flags[y+1][x+1] &= ~JPEG2000_T1_VIS;
+ }
+ } else{
+ for (y = y0; y < y0 + 4 && y < height; y++){
+ if (!(t1->flags[y+1][x+1] & (JPEG2000_T1_SIG | JPEG2000_T1_VIS))){
+ int ctxno = ff_jpeg2000_getsigctxno(t1->flags[y+1][x+1], bandno);
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, t1->data[y][x] & mask ? 1:0);
+ if (t1->data[y][x] & mask){ // newly significant
+ int xorbit;
+ int ctxno = ff_jpeg2000_getsgnctxno(t1->flags[y+1][x+1], &xorbit);
+ *nmsedec += getnmsedec_sig(t1->data[y][x], bpno + NMSEDEC_FRACBITS);
+ ff_mqc_encode(&t1->mqc, t1->mqc.cx_states + ctxno, (t1->flags[y+1][x+1] >> 15) ^ xorbit);
+ ff_jpeg2000_set_significance(t1, x, y, t1->flags[y+1][x+1] >> 15);
+ }
+ }
+ t1->flags[y+1][x+1] &= ~JPEG2000_T1_VIS;
+ }
+ }
+ }
+}
+
+static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, Jpeg2000Tile *tile,
+ int width, int height, int bandpos, int lev)
+{
+ int pass_t = 2, passno, x, y, max=0, nmsedec, bpno;
+ int64_t wmsedec = 0;
+
+ for (y = 0; y < height+2; y++)
+ memset(t1->flags[y], 0, (width+2)*sizeof(int));
+
+ for (y = 0; y < height; y++){
+ for (x = 0; x < width; x++){
+ if (t1->data[y][x] < 0){
+ t1->flags[y+1][x+1] |= JPEG2000_T1_SGN;
+ t1->data[y][x] = -t1->data[y][x];
+ }
+ max = FFMAX(max, t1->data[y][x]);
+ }
+ }
+
+ if (max == 0){
+ cblk->nonzerobits = 0;
+ bpno = 0;
+ } else{
+ cblk->nonzerobits = av_log2(max) + 1 - NMSEDEC_FRACBITS;
+ bpno = cblk->nonzerobits - 1;
+ }
+
+ ff_mqc_initenc(&t1->mqc, cblk->data);
+
+ for (passno = 0; bpno >= 0; passno++){
+ nmsedec=0;
+
+ switch(pass_t){
+ case 0: encode_sigpass(t1, width, height, bandpos, &nmsedec, bpno);
+ break;
+ case 1: encode_refpass(t1, width, height, &nmsedec, bpno);
+ break;
+ case 2: encode_clnpass(t1, width, height, bandpos, &nmsedec, bpno);
+ break;
+ }
+
+ cblk->passes[passno].rate = 3 + ff_mqc_length(&t1->mqc);
+ wmsedec += (int64_t)nmsedec << (2*bpno);
+ cblk->passes[passno].disto = wmsedec;
+
+ if (++pass_t == 3){
+ pass_t = 0;
+ bpno--;
+ }
+ }
+ cblk->npasses = passno;
+ cblk->ninclpasses = passno;
+
+ // TODO: optional flush on each pass
+ cblk->passes[passno-1].rate = ff_mqc_flush(&t1->mqc);
+}
+
+/* tier-2 routines: */
+
+static void putnumpasses(Jpeg2000EncoderContext *s, int n)
+{
+ if (n == 1)
+ put_num(s, 0, 1);
+ else if (n == 2)
+ put_num(s, 2, 2);
+ else if (n <= 5)
+ put_num(s, 0xc | (n-3), 4);
+ else if (n <= 36)
+ put_num(s, 0x1e0 | (n-6), 9);
+ else
+ put_num(s, 0xff80 | (n-37), 16);
+}
+
+
+static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, int precno,
+ uint8_t *expn, int numgbits)
+{
+ int bandno, empty = 1;
+
+ // init bitstream
+ *s->buf = 0;
+ s->bit_index = 0;
+
+ // header
+
+ // is the packet empty?
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ if (rlevel->band[bandno].coord[0][0] < rlevel->band[bandno].coord[0][1]
+ && rlevel->band[bandno].coord[1][0] < rlevel->band[bandno].coord[1][1]){
+ empty = 0;
+ break;
+ }
+ }
+
+ put_bits(s, !empty, 1);
+ if (empty){
+ j2k_flush(s);
+ return 0;
+ }
+
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ Jpeg2000Band *band = rlevel->band + bandno;
+ Jpeg2000Prec *prec = band->prec + precno;
+ int yi, xi, pos;
+ int cblknw = prec->nb_codeblocks_width;
+
+ if (band->coord[0][0] == band->coord[0][1]
+ || band->coord[1][0] == band->coord[1][1])
+ continue;
+
+ for (pos=0, yi = 0; yi < prec->nb_codeblocks_height; yi++){
+ for (xi = 0; xi < cblknw; xi++, pos++){
+ prec->cblkincl[pos].val = prec->cblk[yi * cblknw + xi].ninclpasses == 0;
+ tag_tree_update(prec->cblkincl + pos);
+ prec->zerobits[pos].val = expn[bandno] + numgbits - 1 - prec->cblk[yi * cblknw + xi].nonzerobits;
+ tag_tree_update(prec->zerobits + pos);
+ }
+ }
+
+ for (pos=0, yi = 0; yi < prec->nb_codeblocks_height; yi++){
+ for (xi = 0; xi < cblknw; xi++, pos++){
+ int pad = 0, llen, length;
+ Jpeg2000Cblk *cblk = prec->cblk + yi * cblknw + xi;
+
+ if (s->buf_end - s->buf < 20) // approximately
+ return -1;
+
+ // inclusion information
+ tag_tree_code(s, prec->cblkincl + pos, 1);
+ if (!cblk->ninclpasses)
+ continue;
+ // zerobits information
+ tag_tree_code(s, prec->zerobits + pos, 100);
+ // number of passes
+ putnumpasses(s, cblk->ninclpasses);
+
+ length = cblk->passes[cblk->ninclpasses-1].rate;
+ llen = av_log2(length) - av_log2(cblk->ninclpasses) - 2;
+ if (llen < 0){
+ pad = -llen;
+ llen = 0;
+ }
+ // length of code block
+ put_bits(s, 1, llen);
+ put_bits(s, 0, 1);
+ put_num(s, length, av_log2(length)+1+pad);
+ }
+ }
+ }
+ j2k_flush(s);
+ for (bandno = 0; bandno < rlevel->nbands; bandno++){
+ Jpeg2000Band *band = rlevel->band + bandno;
+ Jpeg2000Prec *prec = band->prec + precno;
+ int yi, cblknw = prec->nb_codeblocks_width;
+ for (yi =0; yi < prec->nb_codeblocks_height; yi++){
+ int xi;
+ for (xi = 0; xi < cblknw; xi++){
+ Jpeg2000Cblk *cblk = prec->cblk + yi * cblknw + xi;
+ if (cblk->ninclpasses){
+ if (s->buf_end - s->buf < cblk->passes[cblk->ninclpasses-1].rate)
+ return -1;
+ bytestream_put_buffer(&s->buf, cblk->data, cblk->passes[cblk->ninclpasses-1].rate);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int encode_packets(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno)
+{
+ int compno, reslevelno, ret;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+ Jpeg2000QuantStyle *qntsty = &s->qntsty;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "tier2\n");
+ // lay-rlevel-comp-pos progression
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ int precno;
+ Jpeg2000ResLevel *reslevel = s->tile[tileno].comp[compno].reslevel + reslevelno;
+ for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+ if ((ret = encode_packet(s, reslevel, precno, qntsty->expn + (reslevelno ? 3*reslevelno-2 : 0),
+ qntsty->nguardbits)) < 0)
+ return ret;
+ }
+ }
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "after tier2\n");
+ return 0;
+}
+
+static int getcut(Jpeg2000Cblk *cblk, int64_t lambda, int dwt_norm)
+{
+ int passno, res = 0;
+ for (passno = 0; passno < cblk->npasses; passno++){
+ int dr;
+ int64_t dd;
+
+ dr = cblk->passes[passno].rate
+ - (res ? cblk->passes[res-1].rate:0);
+ dd = cblk->passes[passno].disto
+ - (res ? cblk->passes[res-1].disto:0);
+
+ if (((dd * dwt_norm) >> WMSEDEC_SHIFT) * dwt_norm >= dr * lambda)
+ res = passno+1;
+ }
+ return res;
+}
+
+static void truncpasses(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile)
+{
+ int precno, compno, reslevelno, bandno, cblkno, lev;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+
+ for (compno = 0; compno < s->ncomponents; compno++){
+ Jpeg2000Component *comp = tile->comp + compno;
+
+ for (reslevelno = 0, lev = codsty->nreslevels-1; reslevelno < codsty->nreslevels; reslevelno++, lev--){
+ Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++){
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ int bandpos = bandno + (reslevelno > 0);
+ Jpeg2000Band *band = reslevel->band + bandno;
+ Jpeg2000Prec *prec = band->prec + precno;
+
+ for (cblkno = 0; cblkno < prec->nb_codeblocks_height * prec->nb_codeblocks_width; cblkno++){
+ Jpeg2000Cblk *cblk = prec->cblk + cblkno;
+
+ cblk->ninclpasses = getcut(cblk, s->lambda,
+ (int64_t)dwt_norms[codsty->transform == FF_DWT53][bandpos][lev] * (int64_t)band->i_stepsize >> 15);
+ }
+ }
+ }
+ }
+ }
+}
+
+static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno)
+{
+ int compno, reslevelno, bandno, ret;
+ Jpeg2000T1Context t1;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+ for (compno = 0; compno < s->ncomponents; compno++){
+ Jpeg2000Component *comp = s->tile[tileno].comp + compno;
+
+ av_log(s->avctx, AV_LOG_DEBUG,"dwt\n");
+ if ((ret = ff_dwt_encode(&comp->dwt, comp->i_data)) < 0)
+ return ret;
+ av_log(s->avctx, AV_LOG_DEBUG,"after dwt -> tier1\n");
+
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++){
+ Jpeg2000ResLevel *reslevel = comp->reslevel + reslevelno;
+
+ for (bandno = 0; bandno < reslevel->nbands ; bandno++){
+ Jpeg2000Band *band = reslevel->band + bandno;
+ Jpeg2000Prec *prec = band->prec; // we support only 1 precinct per band ATM in the encoder
+ int cblkx, cblky, cblkno=0, xx0, x0, xx1, y0, yy0, yy1, bandpos;
+ yy0 = bandno == 0 ? 0 : comp->reslevel[reslevelno-1].coord[1][1] - comp->reslevel[reslevelno-1].coord[1][0];
+ y0 = yy0;
+ yy1 = FFMIN(ff_jpeg2000_ceildivpow2(band->coord[1][0] + 1, band->log2_cblk_height) << band->log2_cblk_height,
+ band->coord[1][1]) - band->coord[1][0] + yy0;
+
+ if (band->coord[0][0] == band->coord[0][1] || band->coord[1][0] == band->coord[1][1])
+ continue;
+
+ bandpos = bandno + (reslevelno > 0);
+
+ for (cblky = 0; cblky < prec->nb_codeblocks_height; cblky++){
+ if (reslevelno == 0 || bandno == 1)
+ xx0 = 0;
+ else
+ xx0 = comp->reslevel[reslevelno-1].coord[0][1] - comp->reslevel[reslevelno-1].coord[0][0];
+ x0 = xx0;
+ xx1 = FFMIN(ff_jpeg2000_ceildivpow2(band->coord[0][0] + 1, band->log2_cblk_width) << band->log2_cblk_width,
+ band->coord[0][1]) - band->coord[0][0] + xx0;
+
+ for (cblkx = 0; cblkx < prec->nb_codeblocks_width; cblkx++, cblkno++){
+ int y, x;
+ if (codsty->transform == FF_DWT53){
+ for (y = yy0; y < yy1; y++){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x++){
+ *ptr++ = comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * y + x] << NMSEDEC_FRACBITS;
+ }
+ }
+ } else{
+ for (y = yy0; y < yy1; y++){
+ int *ptr = t1.data[y-yy0];
+ for (x = xx0; x < xx1; x++){
+ *ptr = (comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * y + x]);
+ *ptr = (int64_t)*ptr * (int64_t)(16384 * 65536 / band->i_stepsize) >> 15 - NMSEDEC_FRACBITS;
+ ptr++;
+ }
+ }
+ }
+ encode_cblk(s, &t1, prec->cblk + cblkno, tile, xx1 - xx0, yy1 - yy0,
+ bandpos, codsty->nreslevels - reslevelno - 1);
+ xx0 = xx1;
+ xx1 = FFMIN(xx1 + (1 << band->log2_cblk_width), band->coord[0][1] - band->coord[0][0] + x0);
+ }
+ yy0 = yy1;
+ yy1 = FFMIN(yy1 + (1 << band->log2_cblk_height), band->coord[1][1] - band->coord[1][0] + y0);
+ }
+ }
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "after tier1\n");
+ }
+
+ av_log(s->avctx, AV_LOG_DEBUG, "rate control\n");
+ truncpasses(s, tile);
+ if ((ret = encode_packets(s, tile, tileno)) < 0)
+ return ret;
+ av_log(s->avctx, AV_LOG_DEBUG, "after rate control\n");
+ return 0;
+}
+
+static void cleanup(Jpeg2000EncoderContext *s)
+{
+ int tileno, compno;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ for (compno = 0; compno < s->ncomponents; compno++){
+ Jpeg2000Component *comp = s->tile[tileno].comp + compno;
+ ff_jpeg2000_cleanup(comp, codsty);
+ }
+ av_freep(&s->tile[tileno].comp);
+ }
+ av_freep(&s->tile);
+}
+
+static void reinit(Jpeg2000EncoderContext *s)
+{
+ int tileno, compno;
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ Jpeg2000Tile *tile = s->tile + tileno;
+ for (compno = 0; compno < s->ncomponents; compno++)
+ ff_jpeg2000_reinit(tile->comp + compno, &s->codsty);
+ }
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ int tileno, ret;
+ Jpeg2000EncoderContext *s = avctx->priv_data;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*9 + FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+
+ // init:
+ s->buf = s->buf_start = pkt->data;
+ s->buf_end = pkt->data + pkt->size;
+
+ s->picture = pict;
+
+ s->lambda = s->picture->quality * LAMBDA_SCALE;
+
+ copy_frame(s);
+ reinit(s);
+
+ if (s->buf_end - s->buf < 2)
+ return -1;
+ bytestream_put_be16(&s->buf, JPEG2000_SOC);
+ if ((ret = put_siz(s)) < 0)
+ return ret;
+ if ((ret = put_cod(s)) < 0)
+ return ret;
+ if ((ret = put_qcd(s, 0)) < 0)
+ return ret;
+
+ for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++){
+ uint8_t *psotptr;
+ if (!(psotptr = put_sot(s, tileno)))
+ return -1;
+ if (s->buf_end - s->buf < 2)
+ return -1;
+ bytestream_put_be16(&s->buf, JPEG2000_SOD);
+ if ((ret = encode_tile(s, s->tile + tileno, tileno)) < 0)
+ return ret;
+ bytestream_put_be32(&psotptr, s->buf - psotptr + 6);
+ }
+ if (s->buf_end - s->buf < 2)
+ return -1;
+ bytestream_put_be16(&s->buf, JPEG2000_EOC);
+
+ av_log(s->avctx, AV_LOG_DEBUG, "end\n");
+ pkt->size = s->buf - s->buf_start;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static av_cold int j2kenc_init(AVCodecContext *avctx)
+{
+ int i, ret;
+ Jpeg2000EncoderContext *s = avctx->priv_data;
+ Jpeg2000CodingStyle *codsty = &s->codsty;
+ Jpeg2000QuantStyle *qntsty = &s->qntsty;
+
+ s->avctx = avctx;
+ av_log(s->avctx, AV_LOG_DEBUG, "init\n");
+
+ // defaults:
+ // TODO: implement setting non-standard precinct size
+ memset(codsty->log2_prec_widths , 15, sizeof(codsty->log2_prec_widths ));
+ memset(codsty->log2_prec_heights, 15, sizeof(codsty->log2_prec_heights));
+ codsty->nreslevels2decode=
+ codsty->nreslevels = 7;
+ codsty->log2_cblk_width = 4;
+ codsty->log2_cblk_height = 4;
+ codsty->transform = avctx->prediction_method ? FF_DWT53 : FF_DWT97_INT;
+
+ qntsty->nguardbits = 1;
+
+ s->tile_width = 256;
+ s->tile_height = 256;
+
+ if (codsty->transform == FF_DWT53)
+ qntsty->quantsty = JPEG2000_QSTY_NONE;
+ else
+ qntsty->quantsty = JPEG2000_QSTY_SE;
+
+ s->width = avctx->width;
+ s->height = avctx->height;
+
+ for (i = 0; i < 3; i++)
+ s->cbps[i] = 8;
+
+ if (avctx->pix_fmt == AV_PIX_FMT_RGB24){
+ s->ncomponents = 3;
+ } else if (avctx->pix_fmt == AV_PIX_FMT_GRAY8){
+ s->ncomponents = 1;
+ } else{ // planar YUV
+ s->planar = 1;
+ s->ncomponents = 3;
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt,
+ s->chroma_shift, s->chroma_shift + 1);
+ }
+
+ ff_jpeg2000_init_tier1_luts();
+ ff_mqc_init_context_tables();
+ init_luts();
+
+ init_quantization(s);
+ if ((ret=init_tiles(s)) < 0)
+ return ret;
+
+ av_log(s->avctx, AV_LOG_DEBUG, "after init\n");
+
+ return 0;
+}
+
+static int j2kenc_destroy(AVCodecContext *avctx)
+{
+ Jpeg2000EncoderContext *s = avctx->priv_data;
+
+ cleanup(s);
+ return 0;
+}
+
+AVCodec ff_jpeg2000_encoder = {
+ .name = "jpeg2000",
+ .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_JPEG2000,
+ .priv_data_size = sizeof(Jpeg2000EncoderContext),
+ .init = j2kenc_init,
+ .encode2 = encode_frame,
+ .close = j2kenc_destroy,
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GRAY8,
+/* AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,*/
+ AV_PIX_FMT_NONE
+ }
+};
diff --git a/libavcodec/jacosub.h b/libavcodec/jacosub.h
new file mode 100644
index 0000000000..c3665ae3fc
--- /dev/null
+++ b/libavcodec/jacosub.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * JACOsub shared utils
+ */
+
+#ifndef AVCODEC_JACOSUB_H
+#define AVCODEC_JACOSUB_H
+
+#include "libavutil/common.h"
+
+#define JSS_MAX_LINESIZE 512
+
+static av_always_inline int jss_whitespace(char c)
+{
+ return c == ' ' || (c >= '\t' && c <= '\r');
+}
+
+static av_always_inline const char *jss_skip_whitespace(const char *p)
+{
+ while (jss_whitespace(*p))
+ p++;
+ return p;
+}
+
+#endif /* AVCODEC_JACOSUB_H */
diff --git a/libavcodec/jacosubdec.c b/libavcodec/jacosubdec.c
new file mode 100644
index 0000000000..0c97eb86c0
--- /dev/null
+++ b/libavcodec/jacosubdec.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * JACOsub subtitle decoder
+ * @see http://unicorn.us.com/jacosub/jscripts.html
+ */
+
+#include <time.h>
+#include "ass.h"
+#include "jacosub.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/time_internal.h"
+
+#undef time
+
+static int insert_text(AVBPrint *dst, const char *in, const char *arg)
+{
+ av_bprintf(dst, "%s", arg);
+ return 0;
+}
+
+static int insert_datetime(AVBPrint *dst, const char *in, const char *arg)
+{
+ char buf[16] = {0};
+ time_t now = time(0);
+ struct tm ltime;
+
+ localtime_r(&now, &ltime);
+ if (strftime(buf, sizeof(buf), arg, &ltime))
+ av_bprintf(dst, "%s", buf);
+ return 0;
+}
+
+static int insert_color(AVBPrint *dst, const char *in, const char *arg)
+{
+ return 1; // skip id
+}
+
+static int insert_font(AVBPrint *dst, const char *in, const char *arg)
+{
+ return 1; // skip id
+}
+
+static const struct {
+ const char *from;
+ const char *arg;
+ int (*func)(AVBPrint *dst, const char *in, const char *arg);
+} ass_codes_map[] = {
+ {"\\~", "~", insert_text}, // tilde doesn't need escaping
+ {"~", "{\\h}", insert_text}, // hard space
+ {"\\n", "\\N", insert_text}, // newline
+ {"\\D", "%d %b %Y", insert_datetime}, // current date
+ {"\\T", "%H:%M", insert_datetime}, // current time
+ {"\\N", "{\\r}", insert_text}, // reset to default style
+ {"\\I", "{\\i1}", insert_text}, // italic on
+ {"\\i", "{\\i0}", insert_text}, // italic off
+ {"\\B", "{\\b1}", insert_text}, // bold on
+ {"\\b", "{\\b0}", insert_text}, // bold off
+ {"\\U", "{\\u1}", insert_text}, // underline on
+ {"\\u", "{\\u0}", insert_text}, // underline off
+ {"\\C", "", insert_color}, // TODO: color
+ {"\\F", "", insert_font}, // TODO: font
+};
+
+enum {
+ ALIGN_VB = 1<<0, // vertical bottom, default
+ ALIGN_VM = 1<<1, // vertical middle
+ ALIGN_VT = 1<<2, // vertical top
+ ALIGN_JC = 1<<3, // justify center, default
+ ALIGN_JL = 1<<4, // justify left
+ ALIGN_JR = 1<<5, // justify right
+};
+
+static void jacosub_to_ass(AVCodecContext *avctx, AVBPrint *dst, const char *src)
+{
+ int i, valign = 0, halign = 0;
+ char c = av_toupper(*src);
+ char directives[128] = {0};
+
+ /* extract the optional directives */
+ if ((c >= 'A' && c <= 'Z') || c == '[') {
+ char *p = directives;
+ char *pend = directives + sizeof(directives) - 1;
+
+ do *p++ = av_toupper(*src++);
+ while (*src && !jss_whitespace(*src) && p < pend);
+ *p = 0;
+ src = jss_skip_whitespace(src);
+ }
+
+ /* handle directives (TODO: handle more of them, and more reliably) */
+ if (strstr(directives, "VB")) valign = ALIGN_VB;
+ else if (strstr(directives, "VM")) valign = ALIGN_VM;
+ else if (strstr(directives, "VT")) valign = ALIGN_VT;
+ if (strstr(directives, "JC")) halign = ALIGN_JC;
+ else if (strstr(directives, "JL")) halign = ALIGN_JL;
+ else if (strstr(directives, "JR")) halign = ALIGN_JR;
+ if (valign || halign) {
+ if (!valign) valign = ALIGN_VB;
+ if (!halign) halign = ALIGN_JC;
+ switch (valign | halign) {
+ case ALIGN_VB | ALIGN_JL: av_bprintf(dst, "{\\an1}"); break; // bottom left
+ case ALIGN_VB | ALIGN_JC: av_bprintf(dst, "{\\an2}"); break; // bottom center
+ case ALIGN_VB | ALIGN_JR: av_bprintf(dst, "{\\an3}"); break; // bottom right
+ case ALIGN_VM | ALIGN_JL: av_bprintf(dst, "{\\an4}"); break; // middle left
+ case ALIGN_VM | ALIGN_JC: av_bprintf(dst, "{\\an5}"); break; // middle center
+ case ALIGN_VM | ALIGN_JR: av_bprintf(dst, "{\\an6}"); break; // middle right
+ case ALIGN_VT | ALIGN_JL: av_bprintf(dst, "{\\an7}"); break; // top left
+ case ALIGN_VT | ALIGN_JC: av_bprintf(dst, "{\\an8}"); break; // top center
+ case ALIGN_VT | ALIGN_JR: av_bprintf(dst, "{\\an9}"); break; // top right
+ }
+ }
+
+ /* process timed line */
+ while (*src && *src != '\n') {
+
+ /* text continue on the next line */
+ if (src[0] == '\\' && src[1] == '\n') {
+ src += 2;
+ while (jss_whitespace(*src))
+ src++;
+ continue;
+ }
+
+ /* special character codes */
+ for (i = 0; i < FF_ARRAY_ELEMS(ass_codes_map); i++) {
+ const char *from = ass_codes_map[i].from;
+ const char *arg = ass_codes_map[i].arg;
+ size_t codemap_len = strlen(from);
+
+ if (!strncmp(src, from, codemap_len)) {
+ src += codemap_len;
+ src += ass_codes_map[i].func(dst, src, arg);
+ break;
+ }
+ }
+
+ /* simple char copy */
+ if (i == FF_ARRAY_ELEMS(ass_codes_map))
+ av_bprintf(dst, "%c", *src++);
+ }
+}
+
+static int jacosub_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ int ret;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+
+ if (avpkt->size <= 0)
+ goto end;
+
+ if (*ptr) {
+ AVBPrint buffer;
+
+ // skip timers
+ ptr = jss_skip_whitespace(ptr);
+ ptr = strchr(ptr, ' '); if (!ptr) goto end; ptr++;
+ ptr = strchr(ptr, ' '); if (!ptr) goto end; ptr++;
+
+ av_bprint_init(&buffer, JSS_MAX_LINESIZE, JSS_MAX_LINESIZE);
+ jacosub_to_ass(avctx, &buffer, ptr);
+ ret = ff_ass_add_rect_bprint(sub, &buffer, avpkt->pts, avpkt->duration);
+ av_bprint_finalize(&buffer, NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+end:
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_jacosub_decoder = {
+ .name = "jacosub",
+ .long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_JACOSUB,
+ .init = ff_ass_subtitle_header_default,
+ .decode = jacosub_decode_frame,
+};
diff --git a/libavcodec/jfdctint.c b/libavcodec/jfdctint.c
index ed6b7ffca2..6a39578f88 100644
--- a/libavcodec/jfdctint.c
+++ b/libavcodec/jfdctint.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/jfdctint_template.c b/libavcodec/jfdctint_template.c
index c6a1638107..3ea2f5dadc 100644
--- a/libavcodec/jfdctint_template.c
+++ b/libavcodec/jfdctint_template.c
@@ -216,8 +216,8 @@ static av_always_inline void FUNC(row_fdct)(int16_t *data)
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
- dataptr[0] = (int16_t) ((tmp10 + tmp11) << PASS1_BITS);
- dataptr[4] = (int16_t) ((tmp10 - tmp11) << PASS1_BITS);
+ dataptr[0] = (int16_t) ((tmp10 + tmp11) * (1 << PASS1_BITS));
+ dataptr[4] = (int16_t) ((tmp10 - tmp11) * (1 << PASS1_BITS));
z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
dataptr[2] = (int16_t) DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865),
diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c
index 2ccd0789e4..644e25d399 100644
--- a/libavcodec/jpeg2000.c
+++ b/libavcodec/jpeg2000.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Kamil Nowosad
* Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/mem.h"
#include "avcodec.h"
@@ -41,8 +42,7 @@ static int32_t tag_tree_size(uint16_t w, uint16_t h)
uint32_t res = 0;
while (w > 1 || h > 1) {
res += w * h;
- if (res + 1 >= INT32_MAX)
- return -1;
+ av_assert0(res + 1 < INT32_MAX);
w = (w + 1) >> 1;
h = (h + 1) >> 1;
}
@@ -56,8 +56,6 @@ static Jpeg2000TgtNode *ff_jpeg2000_tag_tree_init(int w, int h)
int32_t tt_size;
tt_size = tag_tree_size(w, h);
- if (tt_size == -1)
- return NULL;
t = res = av_mallocz_array(tt_size, sizeof(*t));
if (!res)
@@ -82,6 +80,16 @@ static Jpeg2000TgtNode *ff_jpeg2000_tag_tree_init(int w, int h)
return res;
}
+static void tag_tree_zero(Jpeg2000TgtNode *t, int w, int h)
+{
+ int i, siz = tag_tree_size(w, h);
+
+ for (i = 0; i < siz; i++) {
+ t[i].val = 0;
+ t[i].vis = 0;
+ }
+}
+
uint8_t ff_jpeg2000_sigctxno_lut[256][4];
static int getsigctxno(int flag, int bandno)
@@ -96,45 +104,33 @@ static int getsigctxno(int flag, int bandno)
((flag & JPEG2000_T1_SIG_NW) ? 1 : 0) +
((flag & JPEG2000_T1_SIG_SE) ? 1 : 0) +
((flag & JPEG2000_T1_SIG_SW) ? 1 : 0);
+
if (bandno < 3) {
if (bandno == 1)
FFSWAP(int, h, v);
- if (h == 2)
- return 8;
+ if (h == 2) return 8;
if (h == 1) {
- if (v >= 1)
- return 7;
- if (d >= 1)
- return 6;
+ if (v >= 1) return 7;
+ if (d >= 1) return 6;
return 5;
}
- if (v == 2)
- return 4;
- if (v == 1)
- return 3;
- if (d >= 2)
- return 2;
- if (d == 1)
- return 1;
+ if (v == 2) return 4;
+ if (v == 1) return 3;
+ if (d >= 2) return 2;
+ if (d == 1) return 1;
} else {
- if (d >= 3)
- return 8;
+ if (d >= 3) return 8;
if (d == 2) {
- if (h + v >= 1)
- return 7;
+ if (h+v >= 1) return 7;
return 6;
}
if (d == 1) {
- if (h + v >= 2)
- return 5;
- if (h + v == 1)
- return 4;
+ if (h+v >= 2) return 5;
+ if (h+v == 1) return 4;
return 3;
}
- if (h + v >= 2)
- return 2;
- if (h + v == 1)
- return 1;
+ if (h+v >= 2) return 2;
+ if (h+v == 1) return 1;
}
return 0;
}
@@ -205,8 +201,8 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
int reslevelno, bandno, gbandno = 0, ret, i, j;
uint32_t csize;
- if (!codsty->nreslevels2decode) {
- av_log(avctx, AV_LOG_ERROR, "nreslevels2decode uninitialized\n");
+ if (codsty->nreslevels2decode <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "nreslevels2decode %d invalid or uninitialized\n", codsty->nreslevels2decode);
return AVERROR_INVALIDDATA;
}
@@ -220,12 +216,12 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
if (codsty->transform == FF_DWT97) {
comp->i_data = NULL;
- comp->f_data = av_malloc_array(csize, sizeof(*comp->f_data));
+ comp->f_data = av_mallocz_array(csize, sizeof(*comp->f_data));
if (!comp->f_data)
return AVERROR(ENOMEM);
} else {
comp->f_data = NULL;
- comp->i_data = av_malloc_array(csize, sizeof(*comp->i_data));
+ comp->i_data = av_mallocz_array(csize, sizeof(*comp->i_data));
if (!comp->i_data)
return AVERROR(ENOMEM);
}
@@ -254,7 +250,7 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
else
reslevel->nbands = 3;
- /* Number of precincts wich span the tile for resolution level reslevelno
+ /* Number of precincts which span the tile for resolution level reslevelno
* see B.6 in ISO/IEC 15444-1:2002 eq. B-16
* num_precincts_x = |- trx_1 / 2 ^ log2_prec_width) -| - (trx_0 / 2 ^ log2_prec_width)
* num_precincts_y = |- try_1 / 2 ^ log2_prec_width) -| - (try_0 / 2 ^ log2_prec_width)
@@ -325,7 +321,7 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
if (!av_codec_is_encoder(avctx->codec))
band->f_stepsize *= 0.5;
- band->i_stepsize = band->f_stepsize * (1 << 16);
+ band->i_stepsize = band->f_stepsize * (1 << 15);
/* computation of tbx_0, tbx_1, tby_0, tby_1
* see ISO/IEC 15444-1:2002 B.5 eq. B-15 and tbl B.1
@@ -373,6 +369,10 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
for (j = 0; j < 2; j++)
band->coord[1][j] = ff_jpeg2000_ceildiv(band->coord[1][j], dy);
+ if (reslevel->num_precincts_x * (uint64_t)reslevel->num_precincts_y > INT_MAX) {
+ band->prec = NULL;
+ return AVERROR(ENOMEM);
+ }
nb_precincts = reslevel->num_precincts_x * reslevel->num_precincts_y;
band->prec = av_mallocz_array(nb_precincts, sizeof(*band->prec));
if (!band->prec)
@@ -427,6 +427,10 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
if (!prec->zerobits)
return AVERROR(ENOMEM);
+ if (prec->nb_codeblocks_width * (uint64_t)prec->nb_codeblocks_height > INT_MAX) {
+ prec->cblk = NULL;
+ return AVERROR(ENOMEM);
+ }
nb_codeblocks = prec->nb_codeblocks_width * prec->nb_codeblocks_height;
prec->cblk = av_mallocz_array(nb_codeblocks, sizeof(*prec->cblk));
if (!prec->cblk)
@@ -479,6 +483,27 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
return 0;
}
+void ff_jpeg2000_reinit(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty)
+{
+ int reslevelno, bandno, cblkno, precno;
+ for (reslevelno = 0; reslevelno < codsty->nreslevels; reslevelno++) {
+ Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno;
+ for (bandno = 0; bandno < rlevel->nbands; bandno++) {
+ Jpeg2000Band *band = rlevel->band + bandno;
+ for(precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++) {
+ Jpeg2000Prec *prec = band->prec + precno;
+ tag_tree_zero(prec->zerobits, prec->nb_codeblocks_width, prec->nb_codeblocks_height);
+ tag_tree_zero(prec->cblkincl, prec->nb_codeblocks_width, prec->nb_codeblocks_height);
+ for (cblkno = 0; cblkno < prec->nb_codeblocks_width * prec->nb_codeblocks_height; cblkno++) {
+ Jpeg2000Cblk *cblk = prec->cblk + cblkno;
+ cblk->length = 0;
+ cblk->lblock = 3;
+ }
+ }
+ }
+ }
+}
+
void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty)
{
int reslevelno, bandno, precno;
@@ -499,16 +524,12 @@ void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty)
band = reslevel->band + bandno;
for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++) {
- Jpeg2000Prec *prec;
-
- if (!band->prec)
- continue;
-
- prec = band->prec + precno;
- av_freep(&prec->zerobits);
- av_freep(&prec->cblkincl);
- av_freep(&prec->cblk);
-
+ if (band->prec) {
+ Jpeg2000Prec *prec = band->prec + precno;
+ av_freep(&prec->zerobits);
+ av_freep(&prec->cblkincl);
+ av_freep(&prec->cblk);
+ }
}
av_freep(&band->prec);
diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h
index b96b7e2291..acdba62a07 100644
--- a/libavcodec/jpeg2000.h
+++ b/libavcodec/jpeg2000.h
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Kamil Nowosad
* Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -130,8 +130,8 @@ typedef struct Jpeg2000TgtNode {
} Jpeg2000TgtNode;
typedef struct Jpeg2000CodingStyle {
- uint8_t nreslevels; // number of resolution levels
- uint8_t nreslevels2decode; // number of resolution levels to decode
+ int nreslevels; // number of resolution levels
+ int nreslevels2decode; // number of resolution levels to decode
uint8_t log2_cblk_width,
log2_cblk_height; // exponent of codeblock size
uint8_t transform; // DWT type
@@ -146,11 +146,16 @@ typedef struct Jpeg2000CodingStyle {
typedef struct Jpeg2000QuantStyle {
uint8_t expn[JPEG2000_MAX_DECLEVELS * 3]; // quantization exponent
- uint32_t mant[JPEG2000_MAX_DECLEVELS * 3]; // quantization mantissa
+ uint16_t mant[JPEG2000_MAX_DECLEVELS * 3]; // quantization mantissa
uint8_t quantsty; // quantization style
uint8_t nguardbits; // number of guard bits
} Jpeg2000QuantStyle;
+typedef struct Jpeg2000Pass {
+ uint16_t rate;
+ int64_t disto;
+} Jpeg2000Pass;
+
typedef struct Jpeg2000Cblk {
uint8_t npasses;
uint8_t ninclpasses; // number coding of passes included in codestream
@@ -160,6 +165,7 @@ typedef struct Jpeg2000Cblk {
uint8_t lblock;
uint8_t zero;
uint8_t data[8192];
+ Jpeg2000Pass passes[100];
uint16_t coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}}
} Jpeg2000Cblk; // code block
@@ -252,6 +258,8 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp,
int cbps, int dx, int dy,
AVCodecContext *ctx);
+void ff_jpeg2000_reinit(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty);
+
void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty);
#endif /* AVCODEC_JPEG2000_H */
diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c
index 51352979e7..1b441a5b0c 100644
--- a/libavcodec/jpeg2000dec.c
+++ b/libavcodec/jpeg2000dec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Kamil Nowosad
* Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,8 +28,10 @@
#include <inttypes.h>
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
@@ -40,6 +42,7 @@
#define JP2_SIG_TYPE 0x6A502020
#define JP2_SIG_VALUE 0x0D0A870A
#define JP2_CODESTREAM 0x6A703263
+#define JP2_HEADER 0x6A703268
#define HAD_COC 0x01
#define HAD_QCC 0x02
@@ -57,14 +60,14 @@ typedef struct Jpeg2000Tile {
uint8_t properties[4];
Jpeg2000CodingStyle codsty[4];
Jpeg2000QuantStyle qntsty[4];
- Jpeg2000TilePart tile_part[3];
+ Jpeg2000TilePart tile_part[4];
uint16_t tp_idx; // Tile-part index
} Jpeg2000Tile;
typedef struct Jpeg2000DecoderContext {
AVClass *class;
AVCodecContext *avctx;
- GetByteContext g;
+ GetByteContext g;
int width, height;
int image_offset_x, image_offset_y;
@@ -75,6 +78,10 @@ typedef struct Jpeg2000DecoderContext {
int cdx[4], cdy[4];
int precision;
int ncomponents;
+ int colour_space;
+ uint32_t palette[256];
+ int8_t pal8;
+ int cdef[4];
int tile_width, tile_height;
unsigned numXtiles, numYtiles;
int maxtilelen;
@@ -84,7 +91,8 @@ typedef struct Jpeg2000DecoderContext {
int bit_index;
- int16_t curtileno;
+ int curtileno;
+
Jpeg2000Tile *tile;
Jpeg2000DSPContext dsp;
@@ -99,6 +107,7 @@ typedef struct Jpeg2000DecoderContext {
static int get_bits(Jpeg2000DecoderContext *s, int n)
{
int res = 0;
+
while (--n >= 0) {
res <<= 1;
if (s->bit_index == 0) {
@@ -156,12 +165,74 @@ static int tag_tree_decode(Jpeg2000DecoderContext *s, Jpeg2000TgtNode *node,
return curval;
}
+static int pix_fmt_match(enum AVPixelFormat pix_fmt, int components,
+ int bpc, uint32_t log2_chroma_wh, int pal8)
+{
+ int match = 1;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+
+ if (desc->nb_components != components) {
+ return 0;
+ }
+
+ switch (components) {
+ case 4:
+ match = match && desc->comp[3].depth_minus1 + 1 >= bpc &&
+ (log2_chroma_wh >> 14 & 3) == 0 &&
+ (log2_chroma_wh >> 12 & 3) == 0;
+ case 3:
+ match = match && desc->comp[2].depth_minus1 + 1 >= bpc &&
+ (log2_chroma_wh >> 10 & 3) == desc->log2_chroma_w &&
+ (log2_chroma_wh >> 8 & 3) == desc->log2_chroma_h;
+ case 2:
+ match = match && desc->comp[1].depth_minus1 + 1 >= bpc &&
+ (log2_chroma_wh >> 6 & 3) == desc->log2_chroma_w &&
+ (log2_chroma_wh >> 4 & 3) == desc->log2_chroma_h;
+
+ case 1:
+ match = match && desc->comp[0].depth_minus1 + 1 >= bpc &&
+ (log2_chroma_wh >> 2 & 3) == 0 &&
+ (log2_chroma_wh & 3) == 0 &&
+ (desc->flags & AV_PIX_FMT_FLAG_PAL) == pal8 * AV_PIX_FMT_FLAG_PAL;
+ }
+ return match;
+}
+
+// pix_fmts with lower bpp have to be listed before
+// similar pix_fmts with higher bpp.
+#define RGB_PIXEL_FORMATS AV_PIX_FMT_PAL8,AV_PIX_FMT_RGB24,AV_PIX_FMT_RGBA,AV_PIX_FMT_RGB48,AV_PIX_FMT_RGBA64
+#define GRAY_PIXEL_FORMATS AV_PIX_FMT_GRAY8,AV_PIX_FMT_GRAY8A,AV_PIX_FMT_GRAY16,AV_PIX_FMT_YA16
+#define YUV_PIXEL_FORMATS AV_PIX_FMT_YUV410P,AV_PIX_FMT_YUV411P,AV_PIX_FMT_YUVA420P, \
+ AV_PIX_FMT_YUV420P,AV_PIX_FMT_YUV422P,AV_PIX_FMT_YUVA422P, \
+ AV_PIX_FMT_YUV440P,AV_PIX_FMT_YUV444P,AV_PIX_FMT_YUVA444P, \
+ AV_PIX_FMT_YUV420P9,AV_PIX_FMT_YUV422P9,AV_PIX_FMT_YUV444P9, \
+ AV_PIX_FMT_YUVA420P9,AV_PIX_FMT_YUVA422P9,AV_PIX_FMT_YUVA444P9, \
+ AV_PIX_FMT_YUV420P10,AV_PIX_FMT_YUV422P10,AV_PIX_FMT_YUV444P10, \
+ AV_PIX_FMT_YUVA420P10,AV_PIX_FMT_YUVA422P10,AV_PIX_FMT_YUVA444P10, \
+ AV_PIX_FMT_YUV420P12,AV_PIX_FMT_YUV422P12,AV_PIX_FMT_YUV444P12, \
+ AV_PIX_FMT_YUV420P14,AV_PIX_FMT_YUV422P14,AV_PIX_FMT_YUV444P14, \
+ AV_PIX_FMT_YUV420P16,AV_PIX_FMT_YUV422P16,AV_PIX_FMT_YUV444P16, \
+ AV_PIX_FMT_YUVA420P16,AV_PIX_FMT_YUVA422P16,AV_PIX_FMT_YUVA444P16
+#define XYZ_PIXEL_FORMATS AV_PIX_FMT_XYZ12
+
+static const enum AVPixelFormat rgb_pix_fmts[] = {RGB_PIXEL_FORMATS};
+static const enum AVPixelFormat gray_pix_fmts[] = {GRAY_PIXEL_FORMATS};
+static const enum AVPixelFormat yuv_pix_fmts[] = {YUV_PIXEL_FORMATS};
+static const enum AVPixelFormat xyz_pix_fmts[] = {XYZ_PIXEL_FORMATS};
+static const enum AVPixelFormat all_pix_fmts[] = {RGB_PIXEL_FORMATS,
+ GRAY_PIXEL_FORMATS,
+ YUV_PIXEL_FORMATS,
+ XYZ_PIXEL_FORMATS};
+
/* marker segments */
/* get sizes and offsets of image, tiles; number of components */
static int get_siz(Jpeg2000DecoderContext *s)
{
int i;
int ncomponents;
+ uint32_t log2_chroma_wh = 0;
+ const enum AVPixelFormat *possible_fmts = NULL;
+ int possible_fmts_nb = 0;
if (bytestream2_get_bytes_left(&s->g) < 36)
return AVERROR_INVALIDDATA;
@@ -177,6 +248,11 @@ static int get_siz(Jpeg2000DecoderContext *s)
s->tile_offset_y = bytestream2_get_be32u(&s->g); // YT0Siz
ncomponents = bytestream2_get_be16u(&s->g); // CSiz
+ if (s->image_offset_x || s->image_offset_y) {
+ avpriv_request_sample(s->avctx, "Support for image offsets");
+ return AVERROR_PATCHWELCOME;
+ }
+
if (ncomponents <= 0) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid number of components: %d\n",
s->ncomponents);
@@ -191,8 +267,7 @@ static int get_siz(Jpeg2000DecoderContext *s)
s->ncomponents = ncomponents;
- if (s->tile_width <= 0 || s->tile_height <= 0 ||
- s->tile_width > s->width || s->tile_height > s->height) {
+ if (s->tile_width <= 0 || s->tile_height <= 0) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid tile dimension %dx%d.\n",
s->tile_width, s->tile_height);
return AVERROR_INVALIDDATA;
@@ -208,21 +283,22 @@ static int get_siz(Jpeg2000DecoderContext *s)
s->sgnd[i] = !!(x & 0x80);
s->cdx[i] = bytestream2_get_byteu(&s->g);
s->cdy[i] = bytestream2_get_byteu(&s->g);
-
- if (s->cdx[i] != 1 || s->cdy[i] != 1) {
- avpriv_request_sample(s->avctx,
- "CDxy values %d %d for component %d",
- s->cdx[i], s->cdy[i], i);
- if (!s->cdx[i] || !s->cdy[i])
- return AVERROR_INVALIDDATA;
- else
- return AVERROR_PATCHWELCOME;
+ if ( !s->cdx[i] || s->cdx[i] == 3 || s->cdx[i] > 4
+ || !s->cdy[i] || s->cdy[i] == 3 || s->cdy[i] > 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid sample separation %d/%d\n", s->cdx[i], s->cdy[i]);
+ return AVERROR_INVALIDDATA;
}
+ log2_chroma_wh |= s->cdy[i] >> 1 << i * 4 | s->cdx[i] >> 1 << i * 4 + 2;
}
s->numXtiles = ff_jpeg2000_ceildiv(s->width - s->tile_offset_x, s->tile_width);
s->numYtiles = ff_jpeg2000_ceildiv(s->height - s->tile_offset_y, s->tile_height);
+ if (s->numXtiles * (uint64_t)s->numYtiles > INT_MAX/sizeof(*s->tile)) {
+ s->numXtiles = s->numYtiles = 0;
+ return AVERROR(EINVAL);
+ }
+
s->tile = av_mallocz_array(s->numXtiles * s->numYtiles, sizeof(*s->tile));
if (!s->tile) {
s->numXtiles = s->numYtiles = 0;
@@ -243,36 +319,49 @@ static int get_siz(Jpeg2000DecoderContext *s)
s->avctx->height = ff_jpeg2000_ceildivpow2(s->height - s->image_offset_y,
s->reduction_factor);
- switch (s->ncomponents) {
- case 1:
- if (s->precision > 8)
- s->avctx->pix_fmt = AV_PIX_FMT_GRAY16;
- else
- s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
- break;
- case 3:
- switch (s->avctx->profile) {
- case FF_PROFILE_JPEG2000_DCINEMA_2K:
- case FF_PROFILE_JPEG2000_DCINEMA_4K:
- /* XYZ color-space for digital cinema profiles */
- s->avctx->pix_fmt = AV_PIX_FMT_XYZ12;
+ if (s->avctx->profile == FF_PROFILE_JPEG2000_DCINEMA_2K ||
+ s->avctx->profile == FF_PROFILE_JPEG2000_DCINEMA_4K) {
+ possible_fmts = xyz_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(xyz_pix_fmts);
+ } else {
+ switch (s->colour_space) {
+ case 16:
+ possible_fmts = rgb_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(rgb_pix_fmts);
+ break;
+ case 17:
+ possible_fmts = gray_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(gray_pix_fmts);
+ break;
+ case 18:
+ possible_fmts = yuv_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(yuv_pix_fmts);
break;
default:
- if (s->precision > 8)
- s->avctx->pix_fmt = AV_PIX_FMT_RGB48;
- else
- s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ possible_fmts = all_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(all_pix_fmts);
break;
}
- break;
- case 4:
- s->avctx->pix_fmt = AV_PIX_FMT_RGBA;
- break;
- default:
- /* pixel format can not be identified */
- s->avctx->pix_fmt = AV_PIX_FMT_NONE;
- break;
}
+ for (i = 0; i < possible_fmts_nb; ++i) {
+ if (pix_fmt_match(possible_fmts[i], ncomponents, s->precision, log2_chroma_wh, s->pal8)) {
+ s->avctx->pix_fmt = possible_fmts[i];
+ break;
+ }
+ }
+ if (i == possible_fmts_nb) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Unknown pix_fmt, profile: %d, colour_space: %d, "
+ "components: %d, precision: %d, "
+ "cdx[1]: %d, cdy[1]: %d, cdx[2]: %d, cdy[2]: %d\n",
+ s->avctx->profile, s->colour_space, ncomponents, s->precision,
+ ncomponents > 2 ? s->cdx[1] : 0,
+ ncomponents > 2 ? s->cdy[1] : 0,
+ ncomponents > 2 ? s->cdx[2] : 0,
+ ncomponents > 2 ? s->cdy[2] : 0);
+ return AVERROR_PATCHWELCOME;
+ }
+ s->avctx->bits_per_raw_sample = s->precision;
return 0;
}
@@ -287,18 +376,26 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
/* nreslevels = number of resolution levels
= number of decomposition level +1 */
c->nreslevels = bytestream2_get_byteu(&s->g) + 1;
-
- if (c->nreslevels > JPEG2000_MAX_RESLEVELS)
+ if (c->nreslevels >= JPEG2000_MAX_RESLEVELS) {
+ av_log(s->avctx, AV_LOG_ERROR, "nreslevels %d is invalid\n", c->nreslevels);
return AVERROR_INVALIDDATA;
+ }
+
+ if (c->nreslevels <= s->reduction_factor) {
+ /* we are forced to update reduction_factor as its requested value is
+ not compatible with this bitstream, and as we might have used it
+ already in setup earlier we have to fail this frame until
+ reinitialization is implemented */
+ av_log(s->avctx, AV_LOG_ERROR, "reduction_factor too large for this bitstream, max is %d\n", c->nreslevels - 1);
+ s->reduction_factor = c->nreslevels - 1;
+ return AVERROR(EINVAL);
+ }
/* compute number of resolution levels to decode */
- if (c->nreslevels < s->reduction_factor)
- c->nreslevels2decode = 1;
- else
- c->nreslevels2decode = c->nreslevels - s->reduction_factor;
+ c->nreslevels2decode = c->nreslevels - s->reduction_factor;
- c->log2_cblk_width = bytestream2_get_byteu(&s->g) + 2; // cblk width
- c->log2_cblk_height = bytestream2_get_byteu(&s->g) + 2; // cblk height
+ c->log2_cblk_width = (bytestream2_get_byteu(&s->g) & 15) + 2; // cblk width
+ c->log2_cblk_height = (bytestream2_get_byteu(&s->g) & 15) + 2; // cblk height
if (c->log2_cblk_width > 10 || c->log2_cblk_height > 10 ||
c->log2_cblk_width + c->log2_cblk_height > 12) {
@@ -306,10 +403,14 @@ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c)
return AVERROR_INVALIDDATA;
}
+ if (c->log2_cblk_width > 6 || c->log2_cblk_height > 6) {
+ avpriv_request_sample(s->avctx, "cblk size > 64");
+ return AVERROR_PATCHWELCOME;
+ }
+
c->cblk_style = bytestream2_get_byteu(&s->g);
if (c->cblk_style != 0) { // cblk style
- avpriv_request_sample(s->avctx, "Support for extra cblk styles");
- return AVERROR_PATCHWELCOME;
+ av_log(s->avctx, AV_LOG_WARNING, "extra cblk styles %X\n", c->cblk_style);
}
c->transform = bytestream2_get_byteu(&s->g); // DWT transformation type
/* set integer 9/7 DWT in case of BITEXACT flag */
@@ -409,7 +510,7 @@ static int get_qcx(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q)
if (q->quantsty == JPEG2000_QSTY_NONE) {
n -= 3;
if (bytestream2_get_bytes_left(&s->g) < n ||
- n > JPEG2000_MAX_DECLEVELS)
+ n > JPEG2000_MAX_DECLEVELS*3)
return AVERROR_INVALIDDATA;
for (i = 0; i < n; i++)
q->expn[i] = bytestream2_get_byteu(&s->g) >> 3;
@@ -427,7 +528,7 @@ static int get_qcx(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q)
} else {
n = (n - 3) >> 1;
if (bytestream2_get_bytes_left(&s->g) < 2 * n ||
- n > JPEG2000_MAX_DECLEVELS)
+ n > JPEG2000_MAX_DECLEVELS*3)
return AVERROR_INVALIDDATA;
for (i = 0; i < n; i++) {
x = bytestream2_get_be16u(&s->g);
@@ -445,6 +546,8 @@ static int get_qcd(Jpeg2000DecoderContext *s, int n, Jpeg2000QuantStyle *q,
Jpeg2000QuantStyle tmp;
int compno, ret;
+ memset(&tmp, 0, sizeof(tmp));
+
if ((ret = get_qcx(s, n, &tmp)) < 0)
return ret;
for (compno = 0; compno < s->ncomponents; compno++)
@@ -487,14 +590,12 @@ static int get_sot(Jpeg2000DecoderContext *s, int n)
if (bytestream2_get_bytes_left(&s->g) < 8)
return AVERROR_INVALIDDATA;
+ s->curtileno = 0;
Isot = bytestream2_get_be16u(&s->g); // Isot
if (Isot >= s->numXtiles * s->numYtiles)
return AVERROR_INVALIDDATA;
- if (Isot) {
- avpriv_request_sample(s->avctx, "Support for more than one tile");
- return AVERROR_PATCHWELCOME;
- }
+ s->curtileno = Isot;
Psot = bytestream2_get_be32u(&s->g); // Psot
TPsot = bytestream2_get_byteu(&s->g); // TPsot
@@ -684,7 +785,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s,
return ret;
if (ret > sizeof(cblk->data)) {
avpriv_request_sample(s->avctx,
- "Block with lengthinc greater than %zu",
+ "Block with lengthinc greater than %"SIZE_SPECIFIER"",
sizeof(cblk->data));
return AVERROR_PATCHWELCOME;
}
@@ -708,25 +809,18 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s,
nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width;
for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) {
Jpeg2000Cblk *cblk = prec->cblk + cblkno;
- if (bytestream2_get_bytes_left(&s->g) < cblk->lengthinc)
+ if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc
+ || sizeof(cblk->data) < cblk->length + cblk->lengthinc + 2
+ ) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Block length %"PRIu16" or lengthinc %d is too large\n",
+ cblk->length, cblk->lengthinc);
return AVERROR_INVALIDDATA;
- /* Code-block data can be empty. In that case initialize data
- * with 0xFFFF. */
- if (cblk->lengthinc > 0) {
- bytestream2_get_bufferu(&s->g, cblk->data, cblk->lengthinc);
- } else {
- cblk->data[0] = 0xFF;
- cblk->data[1] = 0xFF;
}
+
+ bytestream2_get_bufferu(&s->g, cblk->data + cblk->length, cblk->lengthinc);
cblk->length += cblk->lengthinc;
cblk->lengthinc = 0;
-
- if (cblk->length > sizeof(cblk->data)) {
- av_log(s->avctx, AV_LOG_ERROR,
- "Block length %"PRIu16" > data size %zd\n",
- cblk->length, sizeof(cblk->data));
- return AVERROR_INVALIDDATA;
- }
}
}
return 0;
@@ -740,6 +834,9 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile
s->bit_index = 8;
switch (tile->codsty[0].prog_order) {
+ case JPEG2000_PGOD_RLCP:
+ avpriv_request_sample(s->avctx, "Progression order RLCP");
+
case JPEG2000_PGOD_LRCP:
for (layno = 0; layno < tile->codsty[0].nlayers; layno++) {
ok_reslevel = 1;
@@ -750,7 +847,7 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile
Jpeg2000QuantStyle *qntsty = tile->qntsty + compno;
if (reslevelno < codsty->nreslevels) {
Jpeg2000ResLevel *rlevel = tile->comp[compno].reslevel +
- reslevelno;
+ reslevelno;
ok_reslevel = 1;
for (precno = 0; precno < rlevel->num_precincts_x * rlevel->num_precincts_y; precno++)
if ((ret = jpeg2000_decode_packet(s,
@@ -800,6 +897,10 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile
prcx = ff_jpeg2000_ceildivpow2(x, reducedresno) >> rlevel->log2_prec_width;
prcy = ff_jpeg2000_ceildivpow2(y, reducedresno) >> rlevel->log2_prec_height;
precno = prcx + rlevel->num_precincts_x * prcy;
+
+ if (prcx >= rlevel->num_precincts_x || prcy >= rlevel->num_precincts_y)
+ return AVERROR_PATCHWELCOME;
+
for (layno = 0; layno < tile->codsty[0].nlayers; layno++) {
if ((ret = jpeg2000_decode_packet(s, codsty, rlevel,
precno, layno,
@@ -813,11 +914,6 @@ static int jpeg2000_decode_packets(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile
}
break;
- case JPEG2000_PGOD_RLCP:
- avpriv_request_sample(s->avctx, "Progression order RLCP");
- ret = AVERROR_PATCHWELCOME;
- break;
-
case JPEG2000_PGOD_RPCL:
avpriv_request_sample(s->avctx, "Progression order RPCL");
ret = AVERROR_PATCHWELCOME;
@@ -963,21 +1059,25 @@ static int decode_cblk(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty,
int bpass_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_BYPASS;
int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC;
+ av_assert0(width <= JPEG2000_MAX_CBLKW);
+ av_assert0(height <= JPEG2000_MAX_CBLKH);
+
for (y = 0; y < height; y++)
memset(t1->data[y], 0, width * sizeof(**t1->data));
/* If code-block contains no compressed data: nothing to do. */
if (!cblk->length)
return 0;
+
for (y = 0; y < height + 2; y++)
memset(t1->flags[y], 0, (width + 2) * sizeof(**t1->flags));
+ cblk->data[cblk->length] = 0xff;
+ cblk->data[cblk->length+1] = 0xff;
ff_mqc_initdec(&t1->mqc, cblk->data);
- cblk->data[cblk->length] = 0xff;
- cblk->data[cblk->length + 1] = 0xff;
while (passno--) {
- switch (pass_t) {
+ switch(pass_t) {
case 0:
decode_sigpass(t1, width, height, bpno + 1, bandpos,
bpass_csty_symbol && (clnpass_cnt >= 4),
@@ -1039,7 +1139,7 @@ static void dequantization_int(int x, int y, Jpeg2000Cblk *cblk,
int32_t *datap = &comp->i_data[(comp->coord[0][1] - comp->coord[0][0]) * (y + j) + x];
int *src = t1->data[j];
for (i = 0; i < w; ++i)
- datap[i] = (src[i] * band->i_stepsize + (1 << 15)) >> 16;
+ datap[i] = (src[i] * band->i_stepsize + (1 << 14)) >> 15;
}
}
@@ -1048,6 +1148,12 @@ static inline void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile)
int i, csize = 1;
void *src[3];
+ for (i = 1; i < 3; i++)
+ if (tile->codsty[0].transform != tile->codsty[i].transform) {
+ av_log(s->avctx, AV_LOG_ERROR, "Transforms mismatch, MCT not supported\n");
+ return;
+ }
+
for (i = 0; i < 3; i++)
if (tile->codsty[0].transform == FF_DWT97)
src[i] = tile->comp[i].f_data;
@@ -1063,24 +1169,29 @@ static inline void mct_decode(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile)
static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
AVFrame *picture)
{
+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
int compno, reslevelno, bandno;
int x, y;
+ int planar = !!(pixdesc->flags & AV_PIX_FMT_FLAG_PLANAR);
+ int pixelsize = planar ? 1 : pixdesc->nb_components;
uint8_t *line;
Jpeg2000T1Context t1;
- /* Loop on tile components */
+ /* Loop on tile components */
for (compno = 0; compno < s->ncomponents; compno++) {
Jpeg2000Component *comp = tile->comp + compno;
Jpeg2000CodingStyle *codsty = tile->codsty + compno;
+
/* Loop on resolution levels */
for (reslevelno = 0; reslevelno < codsty->nreslevels2decode; reslevelno++) {
Jpeg2000ResLevel *rlevel = comp->reslevel + reslevelno;
/* Loop on bands */
for (bandno = 0; bandno < rlevel->nbands; bandno++) {
- uint16_t nb_precincts, precno;
+ int nb_precincts, precno;
Jpeg2000Band *band = rlevel->band + bandno;
int cblkno = 0, bandpos;
+
bandpos = bandno + (reslevelno > 0);
if (band->coord[0][0] == band->coord[0][1] ||
@@ -1121,6 +1232,13 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
if (tile->codsty[0].mct)
mct_decode(s, tile);
+ if (s->cdef[0] < 0) {
+ for (x = 0; x < s->ncomponents; x++)
+ s->cdef[x] = x + 1;
+ if ((s->ncomponents & 1) == 0)
+ s->cdef[s->ncomponents-1] = 0;
+ }
+
if (s->precision <= 8) {
for (compno = 0; compno < s->ncomponents; compno++) {
Jpeg2000Component *comp = tile->comp + compno;
@@ -1129,14 +1247,19 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
int32_t *i_datap = comp->i_data;
int cbps = s->cbps[compno];
int w = tile->comp[compno].coord[0][1] - s->image_offset_x;
+ int plane = 0;
+
+ if (planar)
+ plane = s->cdef[compno] ? s->cdef[compno]-1 : (s->ncomponents-1);
+
y = tile->comp[compno].coord[1][0] - s->image_offset_y;
- line = picture->data[0] + y * picture->linesize[0];
+ line = picture->data[plane] + y / s->cdy[compno] * picture->linesize[plane];
for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y += s->cdy[compno]) {
uint8_t *dst;
x = tile->comp[compno].coord[0][0] - s->image_offset_x;
- dst = line + x * s->ncomponents + compno;
+ dst = line + x / s->cdx[compno] * pixelsize + compno*!planar;
if (codsty->transform == FF_DWT97) {
for (; x < w; x += s->cdx[compno]) {
@@ -1145,7 +1268,7 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
val = av_clip(val, 0, (1 << cbps) - 1);
*dst = val << (8 - cbps);
datap++;
- dst += s->ncomponents;
+ dst += pixelsize;
}
} else {
for (; x < w; x += s->cdx[compno]) {
@@ -1154,10 +1277,10 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
val = av_clip(val, 0, (1 << cbps) - 1);
*dst = val << (8 - cbps);
i_datap++;
- dst += s->ncomponents;
+ dst += pixelsize;
}
}
- line += picture->linesize[0];
+ line += picture->linesize[plane];
}
}
} else {
@@ -1169,13 +1292,18 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
uint16_t *linel;
int cbps = s->cbps[compno];
int w = tile->comp[compno].coord[0][1] - s->image_offset_x;
+ int plane = 0;
+
+ if (planar)
+ plane = s->cdef[compno] ? s->cdef[compno]-1 : (s->ncomponents-1);
y = tile->comp[compno].coord[1][0] - s->image_offset_y;
- linel = (uint16_t *)picture->data[0] + y * (picture->linesize[0] >> 1);
+ linel = (uint16_t *)picture->data[plane] + y / s->cdy[compno] * (picture->linesize[plane] >> 1);
for (; y < tile->comp[compno].coord[1][1] - s->image_offset_y; y += s->cdy[compno]) {
uint16_t *dst;
+
x = tile->comp[compno].coord[0][0] - s->image_offset_x;
- dst = linel + (x * s->ncomponents + compno);
+ dst = linel + (x / s->cdx[compno] * pixelsize + compno*!planar);
if (codsty->transform == FF_DWT97) {
for (; x < w; x += s-> cdx[compno]) {
int val = lrintf(*datap) + (1 << (cbps - 1));
@@ -1184,7 +1312,7 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
/* align 12 bit values in little-endian mode */
*dst = val << (16 - cbps);
datap++;
- dst += s->ncomponents;
+ dst += pixelsize;
}
} else {
for (; x < w; x += s-> cdx[compno]) {
@@ -1194,10 +1322,10 @@ static int jpeg2000_decode_tile(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile,
/* align 12 bit values in little-endian mode */
*dst = val << (16 - cbps);
i_datap++;
- dst += s->ncomponents;
+ dst += pixelsize;
}
}
- linel += picture->linesize[0] >> 1;
+ linel += picture->linesize[plane] >> 1;
}
}
}
@@ -1209,15 +1337,19 @@ static void jpeg2000_dec_cleanup(Jpeg2000DecoderContext *s)
{
int tileno, compno;
for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++) {
- for (compno = 0; compno < s->ncomponents; compno++) {
- Jpeg2000Component *comp = s->tile[tileno].comp + compno;
- Jpeg2000CodingStyle *codsty = s->tile[tileno].codsty + compno;
+ if (s->tile[tileno].comp) {
+ for (compno = 0; compno < s->ncomponents; compno++) {
+ Jpeg2000Component *comp = s->tile[tileno].comp + compno;
+ Jpeg2000CodingStyle *codsty = s->tile[tileno].codsty + compno;
- ff_jpeg2000_cleanup(comp, codsty);
+ ff_jpeg2000_cleanup(comp, codsty);
+ }
+ av_freep(&s->tile[tileno].comp);
}
- av_freep(&s->tile[tileno].comp);
}
av_freep(&s->tile);
+ memset(s->codsty, 0, sizeof(s->codsty));
+ memset(s->qntsty, 0, sizeof(s->qntsty));
s->numXtiles = s->numYtiles = 0;
}
@@ -1244,17 +1376,21 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
Jpeg2000Tile *tile;
Jpeg2000TilePart *tp;
- if (s->curtileno < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "Missing SOT\n");
- return AVERROR_INVALIDDATA;
- }
if (!s->tile) {
av_log(s->avctx, AV_LOG_ERROR, "Missing SIZ\n");
return AVERROR_INVALIDDATA;
}
+ if (s->curtileno < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "Missing SOT\n");
+ return AVERROR_INVALIDDATA;
+ }
tile = s->tile + s->curtileno;
tp = tile->tile_part + tile->tp_idx;
+ if (tp->tp_end < s->g.buffer) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid tpend\n");
+ return AVERROR_INVALIDDATA;
+ }
bytestream2_init(&tp->tpg, s->g.buffer, tp->tp_end - s->g.buffer);
bytestream2_skip(&s->g, tp->tp_end - s->g.buffer);
@@ -1263,13 +1399,15 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
if (marker == JPEG2000_EOC)
break;
- len = bytestream2_get_be16u(&s->g);
+ len = bytestream2_get_be16(&s->g);
if (len < 2 || bytestream2_get_bytes_left(&s->g) < len - 2)
return AVERROR_INVALIDDATA;
switch (marker) {
case JPEG2000_SIZ:
ret = get_siz(s);
+ if (!s->tile)
+ s->numXtiles = s->numYtiles = 0;
break;
case JPEG2000_COC:
ret = get_coc(s, codsty, properties);
@@ -1285,6 +1423,7 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s)
break;
case JPEG2000_SOT:
if (!(ret = get_sot(s, len))) {
+ av_assert1(s->curtileno >= 0);
codsty = s->tile[s->curtileno].codsty;
qntsty = s->tile[s->curtileno].qntsty;
properties = s->tile[s->curtileno].properties;
@@ -1337,26 +1476,101 @@ static int jpeg2000_read_bitstream_packets(Jpeg2000DecoderContext *s)
static int jp2_find_codestream(Jpeg2000DecoderContext *s)
{
- uint32_t atom_size, atom;
- int found_codestream = 0, search_range = 10;
+ uint32_t atom_size, atom, atom_end;
+ int search_range = 10;
- while(!found_codestream && search_range
- &&
- bytestream2_get_bytes_left(&s->g) >= 8) {
+ while (search_range
+ &&
+ bytestream2_get_bytes_left(&s->g) >= 8) {
atom_size = bytestream2_get_be32u(&s->g);
atom = bytestream2_get_be32u(&s->g);
- if (atom == JP2_CODESTREAM) {
- found_codestream = 1;
+ atom_end = bytestream2_tell(&s->g) + atom_size - 8;
+
+ if (atom == JP2_CODESTREAM)
+ return 1;
+
+ if (bytestream2_get_bytes_left(&s->g) < atom_size || atom_end < atom_size)
+ return 0;
+
+ if (atom == JP2_HEADER &&
+ atom_size >= 16) {
+ uint32_t atom2_size, atom2, atom2_end;
+ do {
+ atom2_size = bytestream2_get_be32u(&s->g);
+ atom2 = bytestream2_get_be32u(&s->g);
+ atom2_end = bytestream2_tell(&s->g) + atom2_size - 8;
+ if (atom2_size < 8 || atom2_end > atom_end || atom2_end < atom2_size)
+ break;
+ if (atom2 == JP2_CODESTREAM) {
+ return 1;
+ } else if (atom2 == MKBETAG('c','o','l','r') && atom2_size >= 7) {
+ int method = bytestream2_get_byteu(&s->g);
+ bytestream2_skipu(&s->g, 2);
+ if (method == 1) {
+ s->colour_space = bytestream2_get_be32u(&s->g);
+ }
+ } else if (atom2 == MKBETAG('p','c','l','r') && atom2_size >= 6) {
+ int i, size, colour_count, colour_channels, colour_depth[3];
+ uint32_t r, g, b;
+ colour_count = bytestream2_get_be16u(&s->g);
+ colour_channels = bytestream2_get_byteu(&s->g);
+ // FIXME: Do not ignore channel_sign
+ colour_depth[0] = (bytestream2_get_byteu(&s->g) & 0x7f) + 1;
+ colour_depth[1] = (bytestream2_get_byteu(&s->g) & 0x7f) + 1;
+ colour_depth[2] = (bytestream2_get_byteu(&s->g) & 0x7f) + 1;
+ size = (colour_depth[0] + 7 >> 3) * colour_count +
+ (colour_depth[1] + 7 >> 3) * colour_count +
+ (colour_depth[2] + 7 >> 3) * colour_count;
+ if (colour_count > 256 ||
+ colour_channels != 3 ||
+ colour_depth[0] > 16 ||
+ colour_depth[1] > 16 ||
+ colour_depth[2] > 16 ||
+ atom2_size < size) {
+ avpriv_request_sample(s->avctx, "Unknown palette");
+ bytestream2_seek(&s->g, atom2_end, SEEK_SET);
+ continue;
+ }
+ s->pal8 = 1;
+ for (i = 0; i < colour_count; i++) {
+ if (colour_depth[0] <= 8) {
+ r = bytestream2_get_byteu(&s->g) << 8 - colour_depth[0];
+ r |= r >> colour_depth[0];
+ } else {
+ r = bytestream2_get_be16u(&s->g) >> colour_depth[0] - 8;
+ }
+ if (colour_depth[1] <= 8) {
+ g = bytestream2_get_byteu(&s->g) << 8 - colour_depth[1];
+ r |= r >> colour_depth[1];
+ } else {
+ g = bytestream2_get_be16u(&s->g) >> colour_depth[1] - 8;
+ }
+ if (colour_depth[2] <= 8) {
+ b = bytestream2_get_byteu(&s->g) << 8 - colour_depth[2];
+ r |= r >> colour_depth[2];
+ } else {
+ b = bytestream2_get_be16u(&s->g) >> colour_depth[2] - 8;
+ }
+ s->palette[i] = 0xffu << 24 | r << 16 | g << 8 | b;
+ }
+ } else if (atom2 == MKBETAG('c','d','e','f') && atom2_size >= 2) {
+ int n = bytestream2_get_be16u(&s->g);
+ for (; n>0; n--) {
+ int cn = bytestream2_get_be16(&s->g);
+ int av_unused typ = bytestream2_get_be16(&s->g);
+ int asoc = bytestream2_get_be16(&s->g);
+ if (cn < 4 && asoc < 4)
+ s->cdef[cn] = asoc;
+ }
+ }
+ bytestream2_seek(&s->g, atom2_end, SEEK_SET);
+ } while (atom_end - atom2_end >= 8);
} else {
- if (bytestream2_get_bytes_left(&s->g) < atom_size - 8)
- return 0;
- bytestream2_skipu(&s->g, atom_size - 8);
search_range--;
}
+ bytestream2_seek(&s->g, atom_end, SEEK_SET);
}
- if (found_codestream)
- return 1;
return 0;
}
@@ -1379,7 +1593,8 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data,
s->avctx = avctx;
bytestream2_init(&s->g, avpkt->data, avpkt->size);
- s->curtileno = 0; // TODO: only one tile in DCI JP2K. to implement for more tiles
+ s->curtileno = -1;
+ memset(s->cdef, -1, sizeof(s->cdef));
if (bytestream2_get_bytes_left(&s->g) < 2) {
ret = AVERROR_INVALIDDATA;
@@ -1401,6 +1616,9 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data,
bytestream2_seek(&s->g, 0, SEEK_SET);
}
+ while (bytestream2_get_bytes_left(&s->g) >= 3 && bytestream2_peek_be16(&s->g) != JPEG2000_SOC)
+ bytestream2_skip(&s->g, 1);
+
if (bytestream2_get_be16u(&s->g) != JPEG2000_SOC) {
av_log(avctx, AV_LOG_ERROR, "SOC marker not present\n");
ret = AVERROR_INVALIDDATA;
@@ -1410,15 +1628,14 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data,
goto end;
/* get picture buffer */
- if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "ff_thread_get_buffer() failed.\n");
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
goto end;
- }
picture->pict_type = AV_PICTURE_TYPE_I;
picture->key_frame = 1;
if (ret = jpeg2000_read_bitstream_packets(s))
goto end;
+
for (tileno = 0; tileno < s->numXtiles * s->numYtiles; tileno++)
if (ret = jpeg2000_decode_tile(s, s->tile + tileno, picture))
goto end;
@@ -1427,6 +1644,9 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data,
*got_frame = 1;
+ if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
+ memcpy(picture->data[1], s->palette, 256 * sizeof(uint32_t));
+
return bytestream2_tell(&s->g);
end:
@@ -1458,7 +1678,7 @@ static const AVProfile profiles[] = {
{ FF_PROFILE_UNKNOWN },
};
-static const AVClass class = {
+static const AVClass jpeg2000_class = {
.class_name = "jpeg2000",
.item_name = av_default_item_name,
.option = options,
@@ -1475,6 +1695,7 @@ AVCodec ff_jpeg2000_decoder = {
.init_static_data = jpeg2000_init_static_data,
.init = jpeg2000_decode_init,
.decode = jpeg2000_decode_frame,
- .priv_class = &class,
+ .priv_class = &jpeg2000_class,
+ .max_lowres = 5,
.profiles = NULL_IF_CONFIG_SMALL(profiles)
};
diff --git a/libavcodec/jpeg2000dsp.c b/libavcodec/jpeg2000dsp.c
index 6e04c3a37d..a7c7f53b7a 100644
--- a/libavcodec/jpeg2000dsp.c
+++ b/libavcodec/jpeg2000dsp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Kamil Nowosad
* Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/jpeg2000dsp.h b/libavcodec/jpeg2000dsp.h
index 45a32c0dd8..de1ddb94cd 100644
--- a/libavcodec/jpeg2000dsp.h
+++ b/libavcodec/jpeg2000dsp.h
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Kamil Nowosad
* Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/jpeg2000dwt.c b/libavcodec/jpeg2000dwt.c
index 6642a53ac8..ceceda36dc 100644
--- a/libavcodec/jpeg2000dwt.c
+++ b/libavcodec/jpeg2000dwt.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Kamil Nowosad
* Copyright (c) 2013 Nicolas Bertrand <nicoinattendu@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,7 +51,6 @@
#define I_LFTG_K 80621
#define I_LFTG_X 106544
-
static inline void extend53(int *p, int i0, int i1)
{
p[i0 - 1] = p[i0 + 1];
@@ -80,6 +79,213 @@ static inline void extend97_int(int32_t *p, int i0, int i1)
}
}
+static void sd_1d53(int *p, int i0, int i1)
+{
+ int i;
+
+ if (i1 == i0 + 1)
+ return;
+
+ extend53(p, i0, i1);
+
+ for (i = (i0+1)/2 - 1; i < (i1+1)/2; i++)
+ p[2*i+1] -= (p[2*i] + p[2*i+2]) >> 1;
+ for (i = (i0+1)/2; i < (i1+1)/2; i++)
+ p[2*i] += (p[2*i-1] + p[2*i+1] + 2) >> 2;
+}
+
+static void dwt_encode53(DWTContext *s, int *t)
+{
+ int lev,
+ w = s->linelen[s->ndeclevels-1][0];
+ int *line = s->i_linebuf;
+ line += 3;
+
+ for (lev = s->ndeclevels-1; lev >= 0; lev--){
+ int lh = s->linelen[lev][0],
+ lv = s->linelen[lev][1],
+ mh = s->mod[lev][0],
+ mv = s->mod[lev][1],
+ lp;
+ int *l;
+
+ // HOR_SD
+ l = line + mh;
+ for (lp = 0; lp < lv; lp++){
+ int i, j = 0;
+
+ for (i = 0; i < lh; i++)
+ l[i] = t[w*lp + i];
+
+ sd_1d53(line, mh, mh + lh);
+
+ // copy back and deinterleave
+ for (i = mh; i < lh; i+=2, j++)
+ t[w*lp + j] = l[i];
+ for (i = 1-mh; i < lh; i+=2, j++)
+ t[w*lp + j] = l[i];
+ }
+
+ // VER_SD
+ l = line + mv;
+ for (lp = 0; lp < lh; lp++) {
+ int i, j = 0;
+
+ for (i = 0; i < lv; i++)
+ l[i] = t[w*i + lp];
+
+ sd_1d53(line, mv, mv + lv);
+
+ // copy back and deinterleave
+ for (i = mv; i < lv; i+=2, j++)
+ t[w*j + lp] = l[i];
+ for (i = 1-mv; i < lv; i+=2, j++)
+ t[w*j + lp] = l[i];
+ }
+ }
+}
+static void sd_1d97_float(float *p, int i0, int i1)
+{
+ int i;
+
+ if (i1 == i0 + 1)
+ return;
+
+ extend97_float(p, i0, i1);
+ i0++; i1++;
+
+ for (i = i0/2 - 2; i < i1/2 + 1; i++)
+ p[2*i+1] -= 1.586134 * (p[2*i] + p[2*i+2]);
+ for (i = i0/2 - 1; i < i1/2 + 1; i++)
+ p[2*i] -= 0.052980 * (p[2*i-1] + p[2*i+1]);
+ for (i = i0/2 - 1; i < i1/2; i++)
+ p[2*i+1] += 0.882911 * (p[2*i] + p[2*i+2]);
+ for (i = i0/2; i < i1/2; i++)
+ p[2*i] += 0.443506 * (p[2*i-1] + p[2*i+1]);
+}
+
+static void dwt_encode97_float(DWTContext *s, float *t)
+{
+ int lev,
+ w = s->linelen[s->ndeclevels-1][0];
+ float *line = s->f_linebuf;
+ line += 5;
+
+ for (lev = s->ndeclevels-1; lev >= 0; lev--){
+ int lh = s->linelen[lev][0],
+ lv = s->linelen[lev][1],
+ mh = s->mod[lev][0],
+ mv = s->mod[lev][1],
+ lp;
+ float *l;
+
+ // HOR_SD
+ l = line + mh;
+ for (lp = 0; lp < lv; lp++){
+ int i, j = 0;
+
+ for (i = 0; i < lh; i++)
+ l[i] = t[w*lp + i];
+
+ sd_1d97_float(line, mh, mh + lh);
+
+ // copy back and deinterleave
+ for (i = mh; i < lh; i+=2, j++)
+ t[w*lp + j] = F_LFTG_X * l[i] / 2;
+ for (i = 1-mh; i < lh; i+=2, j++)
+ t[w*lp + j] = F_LFTG_K * l[i] / 2;
+ }
+
+ // VER_SD
+ l = line + mv;
+ for (lp = 0; lp < lh; lp++) {
+ int i, j = 0;
+
+ for (i = 0; i < lv; i++)
+ l[i] = t[w*i + lp];
+
+ sd_1d97_float(line, mv, mv + lv);
+
+ // copy back and deinterleave
+ for (i = mv; i < lv; i+=2, j++)
+ t[w*j + lp] = F_LFTG_X * l[i] / 2;
+ for (i = 1-mv; i < lv; i+=2, j++)
+ t[w*j + lp] = F_LFTG_K * l[i] / 2;
+ }
+ }
+}
+
+static void sd_1d97_int(int *p, int i0, int i1)
+{
+ int i;
+
+ if (i1 == i0 + 1)
+ return;
+
+ extend97_int(p, i0, i1);
+ i0++; i1++;
+
+ for (i = i0/2 - 2; i < i1/2 + 1; i++)
+ p[2 * i + 1] -= (I_LFTG_ALPHA * (p[2 * i] + p[2 * i + 2]) + (1 << 15)) >> 16;
+ for (i = i0/2 - 1; i < i1/2 + 1; i++)
+ p[2 * i] -= (I_LFTG_BETA * (p[2 * i - 1] + p[2 * i + 1]) + (1 << 15)) >> 16;
+ for (i = i0/2 - 1; i < i1/2; i++)
+ p[2 * i + 1] += (I_LFTG_GAMMA * (p[2 * i] + p[2 * i + 2]) + (1 << 15)) >> 16;
+ for (i = i0/2; i < i1/2; i++)
+ p[2 * i] += (I_LFTG_DELTA * (p[2 * i - 1] + p[2 * i + 1]) + (1 << 15)) >> 16;
+}
+
+static void dwt_encode97_int(DWTContext *s, int *t)
+{
+ int lev,
+ w = s->linelen[s->ndeclevels-1][0];
+ int *line = s->i_linebuf;
+ line += 5;
+
+ for (lev = s->ndeclevels-1; lev >= 0; lev--){
+ int lh = s->linelen[lev][0],
+ lv = s->linelen[lev][1],
+ mh = s->mod[lev][0],
+ mv = s->mod[lev][1],
+ lp;
+ int *l;
+
+ // HOR_SD
+ l = line + mh;
+ for (lp = 0; lp < lv; lp++){
+ int i, j = 0;
+
+ for (i = 0; i < lh; i++)
+ l[i] = t[w*lp + i];
+
+ sd_1d97_int(line, mh, mh + lh);
+
+ // copy back and deinterleave
+ for (i = mh; i < lh; i+=2, j++)
+ t[w*lp + j] = ((l[i] * I_LFTG_X) + (1 << 16)) >> 17;
+ for (i = 1-mh; i < lh; i+=2, j++)
+ t[w*lp + j] = ((l[i] * I_LFTG_K) + (1 << 16)) >> 17;
+ }
+
+ // VER_SD
+ l = line + mv;
+ for (lp = 0; lp < lh; lp++) {
+ int i, j = 0;
+
+ for (i = 0; i < lv; i++)
+ l[i] = t[w*i + lp];
+
+ sd_1d97_int(line, mv, mv + lv);
+
+ // copy back and deinterleave
+ for (i = mv; i < lv; i+=2, j++)
+ t[w*j + lp] = ((l[i] * I_LFTG_X) + (1 << 16)) >> 17;
+ for (i = 1-mv; i < lv; i+=2, j++)
+ t[w*j + lp] = ((l[i] * I_LFTG_K) + (1 << 16)) >> 17;
+ }
+ }
+}
+
static void sr_1d53(int *p, int i0, int i1)
{
int i;
@@ -312,17 +518,17 @@ int ff_jpeg2000_dwt_init(DWTContext *s, uint16_t border[2][2],
}
switch (type) {
case FF_DWT97:
- s->f_linebuf = av_malloc((maxlen + 12) * sizeof(*s->f_linebuf));
+ s->f_linebuf = av_malloc_array((maxlen + 12), sizeof(*s->f_linebuf));
if (!s->f_linebuf)
return AVERROR(ENOMEM);
break;
case FF_DWT97_INT:
- s->i_linebuf = av_malloc((maxlen + 12) * sizeof(*s->i_linebuf));
+ s->i_linebuf = av_malloc_array((maxlen + 12), sizeof(*s->i_linebuf));
if (!s->i_linebuf)
return AVERROR(ENOMEM);
break;
case FF_DWT53:
- s->i_linebuf = av_malloc((maxlen + 6) * sizeof(*s->i_linebuf));
+ s->i_linebuf = av_malloc_array((maxlen + 6), sizeof(*s->i_linebuf));
if (!s->i_linebuf)
return AVERROR(ENOMEM);
break;
@@ -332,6 +538,21 @@ int ff_jpeg2000_dwt_init(DWTContext *s, uint16_t border[2][2],
return 0;
}
+int ff_dwt_encode(DWTContext *s, void *t)
+{
+ switch(s->type){
+ case FF_DWT97:
+ dwt_encode97_float(s, t); break;
+ case FF_DWT97_INT:
+ dwt_encode97_int(s, t); break;
+ case FF_DWT53:
+ dwt_encode53(s, t); break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
int ff_dwt_decode(DWTContext *s, void *t)
{
switch (s->type) {
diff --git a/libavcodec/jpeg2000dwt.h b/libavcodec/jpeg2000dwt.h
index f08340dbc9..b6d296d8a8 100644
--- a/libavcodec/jpeg2000dwt.h
+++ b/libavcodec/jpeg2000dwt.h
@@ -2,20 +2,20 @@
* Discrete wavelet transform
* Copyright (c) 2007 Kamil Nowosad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,6 +58,7 @@ typedef struct DWTContext {
int ff_jpeg2000_dwt_init(DWTContext *s, uint16_t border[2][2],
int decomp_levels, int type);
+int ff_dwt_encode(DWTContext *s, void *t);
int ff_dwt_decode(DWTContext *s, void *t);
void ff_dwt_destroy(DWTContext *s);
diff --git a/libavcodec/jpegls.c b/libavcodec/jpegls.c
index 19d461fa09..7f9fa8d60c 100644
--- a/libavcodec/jpegls.c
+++ b/libavcodec/jpegls.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Michael Niedermayer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,10 +39,8 @@ void ff_jpegls_init_state(JLSState *state)
for (state->qbpp = 0; (1 << state->qbpp) < state->range; state->qbpp++)
;
- if (state->bpp < 8)
- state->limit = 2 * state->bpp - state->qbpp + 16;
- else
- state->limit = 4 * state->bpp - state->qbpp;
+ state->bpp = FFMAX(av_log2(state->maxval) + 1, 2);
+ state->limit = 2*(state->bpp + FFMAX(state->bpp, 8)) - state->qbpp;
for (i = 0; i < 367; i++) {
state->A[i] = FFMAX(state->range + 32 >> 6, 2);
diff --git a/libavcodec/jpegls.h b/libavcodec/jpegls.h
index eae3943c30..c8997c7861 100644
--- a/libavcodec/jpegls.h
+++ b/libavcodec/jpegls.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Michael Niedermayer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,7 @@
#include "libavutil/common.h"
#include "avcodec.h"
+#include "internal.h"
typedef struct JpeglsContext {
AVCodecContext *avctx;
@@ -40,11 +41,9 @@ typedef struct JLSState {
int A[367], B[367], C[365], N[367];
int limit, reset, bpp, qbpp, maxval, range;
int near, twonear;
- int run_index[3];
+ int run_index[4];
} JLSState;
-extern const uint8_t ff_log2_run[32];
-
/**
* Calculate initial JPEG-LS parameters
*/
@@ -98,6 +97,8 @@ static inline void ff_jpegls_downscale_state(JLSState *state, int Q)
static inline int ff_jpegls_update_state_regular(JLSState *state,
int Q, int err)
{
+ if(FFABS(err) > 0xFFFF)
+ return -0x10000;
state->A[Q] += FFABS(err);
err *= state->twonear;
state->B[Q] += err;
diff --git a/libavcodec/jpeglsdec.c b/libavcodec/jpeglsdec.c
index d9b08fbb76..97fc600721 100644
--- a/libavcodec/jpeglsdec.c
+++ b/libavcodec/jpeglsdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Michael Niedermayer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,7 +40,7 @@
* (or test broken JPEG-LS decoder) and slow down ordinary decoding a bit.
*
* There is no Golomb code with length >= 32 bits possible, so check and
- * avoid situation of 32 zeros, Libav Golomb decoder is painfully slow
+ * avoid situation of 32 zeros, FFmpeg Golomb decoder is painfully slow
* on this errors.
*/
//#define JLS_BROKEN
@@ -51,27 +51,87 @@
int ff_jpegls_decode_lse(MJpegDecodeContext *s)
{
int id;
+ int tid, wt, maxtab, i, j;
- skip_bits(&s->gb, 16); /* length: FIXME: verify field validity */
+ int len = get_bits(&s->gb, 16);
id = get_bits(&s->gb, 8);
switch (id) {
case 1:
+ if (len < 13)
+ return AVERROR_INVALIDDATA;
+
s->maxval = get_bits(&s->gb, 16);
s->t1 = get_bits(&s->gb, 16);
s->t2 = get_bits(&s->gb, 16);
s->t3 = get_bits(&s->gb, 16);
s->reset = get_bits(&s->gb, 16);
+ if(s->avctx->debug & FF_DEBUG_PICT_INFO) {
+ av_log(s->avctx, AV_LOG_DEBUG, "Coding parameters maxval:%d T1:%d T2:%d T3:%d reset:%d\n",
+ s->maxval, s->t1, s->t2, s->t3, s->reset);
+ }
+
// ff_jpegls_reset_coding_parameters(s, 0);
//FIXME quant table?
break;
case 2:
+ s->palette_index = 0;
case 3:
- av_log(s->avctx, AV_LOG_ERROR, "palette not supported\n");
- return AVERROR(ENOSYS);
+ tid= get_bits(&s->gb, 8);
+ wt = get_bits(&s->gb, 8);
+
+ if (len < 5)
+ return AVERROR_INVALIDDATA;
+
+ if (wt < 1 || wt > MAX_COMPONENTS) {
+ avpriv_request_sample(s->avctx, "wt %d", wt);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (!s->maxval)
+ maxtab = 255;
+ else if ((5 + wt*(s->maxval+1)) < 65535)
+ maxtab = s->maxval;
+ else
+ maxtab = 65530/wt - 1;
+
+ if(s->avctx->debug & FF_DEBUG_PICT_INFO) {
+ av_log(s->avctx, AV_LOG_DEBUG, "LSE palette %d tid:%d wt:%d maxtab:%d\n", id, tid, wt, maxtab);
+ }
+ if (maxtab >= 256) {
+ avpriv_request_sample(s->avctx, ">8bit palette");
+ return AVERROR_PATCHWELCOME;
+ }
+ maxtab = FFMIN(maxtab, (len - 5) / wt + s->palette_index);
+
+ if (s->palette_index > maxtab)
+ return AVERROR_INVALIDDATA;
+
+ if ((s->avctx->pix_fmt == AV_PIX_FMT_GRAY8 || s->avctx->pix_fmt == AV_PIX_FMT_PAL8) &&
+ (s->picture_ptr->format == AV_PIX_FMT_GRAY8 || s->picture_ptr->format == AV_PIX_FMT_PAL8)) {
+ uint32_t *pal = (uint32_t *)s->picture_ptr->data[1];
+ int shift = 0;
+
+ if (s->avctx->bits_per_raw_sample > 0 && s->avctx->bits_per_raw_sample < 8) {
+ maxtab = FFMIN(maxtab, (1<<s->avctx->bits_per_raw_sample)-1);
+ shift = 8 - s->avctx->bits_per_raw_sample;
+ }
+
+ s->picture_ptr->format =
+ s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ for (i=s->palette_index; i<=maxtab; i++) {
+ uint8_t k = i << shift;
+ pal[k] = 0;
+ for (j=0; j<wt; j++) {
+ pal[k] |= get_bits(&s->gb, 8) << (8*(wt-j-1));
+ }
+ }
+ s->palette_index = i;
+ }
+ break;
case 4:
- av_log(s->avctx, AV_LOG_ERROR, "oversize image not supported\n");
+ avpriv_request_sample(s->avctx, "oversize image");
return AVERROR(ENOSYS);
default:
av_log(s->avctx, AV_LOG_ERROR, "invalid id %d\n", id);
@@ -149,6 +209,8 @@ static inline int ls_get_code_runterm(GetBitContext *gb, JLSState *state,
ret = ret >> 1;
}
+ if(FFABS(ret) > 0xFFFF)
+ return -0x10000;
/* update state */
state->A[Q] += FFABS(ret) - RItype;
ret *= state->twonear;
@@ -208,11 +270,20 @@ static inline void ls_decode_line(JLSState *state, MJpegDecodeContext *s,
r = ff_log2_run[state->run_index[comp]];
if (r)
r = get_bits_long(&s->gb, r);
+ if (x + r * stride > w) {
+ r = (w - x) / stride;
+ }
for (i = 0; i < r; i++) {
W(dst, x, Ra);
x += stride;
}
+ if (x >= w) {
+ av_log(NULL, AV_LOG_ERROR, "run overflow\n");
+ av_assert0(x <= w);
+ return;
+ }
+
/* decode run termination value */
Rb = R(last, x);
RItype = (FFABS(Ra - Rb) <= state->near) ? 1 : 0;
@@ -298,21 +369,23 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
else
shift = point_transform + (16 - s->bits);
- ff_dlog(s->avctx,
- "JPEG-LS params: %ix%i NEAR=%i MV=%i T(%i,%i,%i) "
- "RESET=%i, LIMIT=%i, qbpp=%i, RANGE=%i\n",
- s->width, s->height, state->near, state->maxval,
- state->T1, state->T2, state->T3,
- state->reset, state->limit, state->qbpp, state->range);
- ff_dlog(s->avctx, "JPEG params: ILV=%i Pt=%i BPP=%i, scan = %i\n",
- ilv, point_transform, s->bits, s->cur_scan);
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO) {
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "JPEG-LS params: %ix%i NEAR=%i MV=%i T(%i,%i,%i) "
+ "RESET=%i, LIMIT=%i, qbpp=%i, RANGE=%i\n",
+ s->width, s->height, state->near, state->maxval,
+ state->T1, state->T2, state->T3,
+ state->reset, state->limit, state->qbpp, state->range);
+ av_log(s->avctx, AV_LOG_DEBUG, "JPEG params: ILV=%i Pt=%i BPP=%i, scan = %i\n",
+ ilv, point_transform, s->bits, s->cur_scan);
+ }
if (ilv == 0) { /* separate planes */
if (s->cur_scan > s->nb_components) {
ret = AVERROR_INVALIDDATA;
goto end;
}
- off = s->cur_scan - 1;
stride = (s->nb_components > 1) ? 3 : 1;
+ off = av_clip(s->cur_scan - 1, 0, stride - 1);
width = s->width * stride;
cur += off;
for (i = 0; i < s->height; i++) {
@@ -334,12 +407,13 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
} else if (ilv == 1) { /* line interleaving */
int j;
int Rc[3] = { 0, 0, 0 };
+ stride = (s->nb_components > 1) ? 3 : 1;
memset(cur, 0, s->picture_ptr->linesize[0]);
- width = s->width * 3;
+ width = s->width * stride;
for (i = 0; i < s->height; i++) {
- for (j = 0; j < 3; j++) {
+ for (j = 0; j < stride; j++) {
ls_decode_line(state, s, last + j, cur + j,
- Rc[j], width, 3, j, 8);
+ Rc[j], width, stride, j, 8);
Rc[j] = last[j];
if (s->restart_interval && !--s->restart_count) {
@@ -356,6 +430,53 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near,
goto end;
}
+ if (s->xfrm && s->nb_components == 3) {
+ int x, w;
+
+ w = s->width * s->nb_components;
+
+ if (s->bits <= 8) {
+ uint8_t *src = s->picture_ptr->data[0];
+
+ for (i = 0; i < s->height; i++) {
+ switch(s->xfrm) {
+ case 1:
+ for (x = off; x < w; x += 3) {
+ src[x ] += src[x+1] + 128;
+ src[x+2] += src[x+1] + 128;
+ }
+ break;
+ case 2:
+ for (x = off; x < w; x += 3) {
+ src[x ] += src[x+1] + 128;
+ src[x+2] += ((src[x ] + src[x+1])>>1) + 128;
+ }
+ break;
+ case 3:
+ for (x = off; x < w; x += 3) {
+ int g = src[x+0] - ((src[x+2]+src[x+1])>>2) + 64;
+ src[x+0] = src[x+2] + g + 128;
+ src[x+2] = src[x+1] + g + 128;
+ src[x+1] = g;
+ }
+ break;
+ case 4:
+ for (x = off; x < w; x += 3) {
+ int r = src[x+0] - (( 359 * (src[x+2]-128) + 490) >> 8);
+ int g = src[x+0] - (( 88 * (src[x+1]-128) - 183 * (src[x+2]-128) + 30) >> 8);
+ int b = src[x+0] + ((454 * (src[x+1]-128) + 574) >> 8);
+ src[x+0] = av_clip_uint8(r);
+ src[x+1] = av_clip_uint8(g);
+ src[x+2] = av_clip_uint8(b);
+ }
+ break;
+ }
+ src += s->picture_ptr->linesize[0];
+ }
+ }else
+ avpriv_report_missing_feature(s->avctx, "16bit xfrm");
+ }
+
if (shift) { /* we need to do point transform or normalize samples */
int x, w;
diff --git a/libavcodec/jpeglsdec.h b/libavcodec/jpeglsdec.h
index d60a87bdd5..0cafaba7a4 100644
--- a/libavcodec/jpeglsdec.h
+++ b/libavcodec/jpeglsdec.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Michael Niedermayer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/jpeglsenc.c b/libavcodec/jpeglsenc.c
index 839b540ee7..d2749101ed 100644
--- a/libavcodec/jpeglsenc.c
+++ b/libavcodec/jpeglsenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Michael Niedermayer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "avcodec.h"
#include "get_bits.h"
+#include "put_bits.h"
#include "golomb.h"
#include "internal.h"
#include "mathops.h"
@@ -257,7 +258,7 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt,
uint8_t *zero = NULL;
uint8_t *cur = NULL;
uint8_t *last = NULL;
- JLSState *state;
+ JLSState *state = NULL;
int i, size, ret;
int comps;
@@ -267,11 +268,9 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt,
else
comps = 3;
- if ((ret = ff_alloc_packet(pkt, avctx->width * avctx->height * comps * 4 +
- FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width *avctx->height * comps * 4 +
+ FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
buf2 = av_malloc(pkt->size);
if (!buf2)
@@ -317,7 +316,7 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt,
ls_store_lse(state, &pb);
- zero = last = av_mallocz(p->linesize[0]);
+ zero = last = av_mallocz(FFABS(p->linesize[0]));
if (!zero)
goto memfail;
@@ -446,6 +445,7 @@ AVCodec ff_jpegls_encoder = {
.id = AV_CODEC_ID_JPEGLS,
.init = encode_init_ls,
.close = encode_close,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.encode2 = encode_picture_ls,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24,
diff --git a/libavcodec/jpegtables.c b/libavcodec/jpegtables.c
index ce2bae2454..cbe5523cb4 100644
--- a/libavcodec/jpegtables.c
+++ b/libavcodec/jpegtables.c
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@
* The spec says that the values given produce "good" quality, and
* when divided by 2, "very good" quality.
*/
-const unsigned char std_luminance_quant_tbl[64] = {
+static const unsigned char std_luminance_quant_tbl[64] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
@@ -48,7 +48,7 @@ const unsigned char std_luminance_quant_tbl[64] = {
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
};
-const unsigned char std_chrominance_quant_tbl[64] = {
+static const unsigned char std_chrominance_quant_tbl[64] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
diff --git a/libavcodec/jpegtables.h b/libavcodec/jpegtables.h
index 1a909bef7a..6833b4b166 100644
--- a/libavcodec/jpegtables.h
+++ b/libavcodec/jpegtables.h
@@ -1,20 +1,20 @@
/*
* JPEG-related tables
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/jrevdct.c b/libavcodec/jrevdct.c
index 8261269b25..55a7392e98 100644
--- a/libavcodec/jrevdct.c
+++ b/libavcodec/jrevdct.c
@@ -251,8 +251,8 @@ void ff_j_rev_dct(DCTBLOCK data)
/* AC terms all zero */
if (d0) {
/* Compute a 32 bit value to assign. */
- int16_t dcval = (int16_t) (d0 << PASS1_BITS);
- register int v = (dcval & 0xffff) | ((dcval << 16) & 0xffff0000);
+ int16_t dcval = (int16_t) (d0 * (1 << PASS1_BITS));
+ register int v = (dcval & 0xffff) | ((dcval * (1 << 16)) & 0xffff0000);
idataptr[0] = v;
idataptr[1] = v;
@@ -274,8 +274,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
- tmp0 = (d0 + d4) << CONST_BITS;
- tmp1 = (d0 - d4) << CONST_BITS;
+ tmp0 = (d0 + d4) * CONST_SCALE;
+ tmp1 = (d0 - d4) * CONST_SCALE;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
@@ -286,8 +286,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp2 = MULTIPLY(-d6, FIX_1_306562965);
tmp3 = MULTIPLY(d6, FIX_0_541196100);
- tmp0 = (d0 + d4) << CONST_BITS;
- tmp1 = (d0 - d4) << CONST_BITS;
+ tmp0 = (d0 + d4) * CONST_SCALE;
+ tmp1 = (d0 - d4) * CONST_SCALE;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
@@ -300,8 +300,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp2 = MULTIPLY(d2, FIX_0_541196100);
tmp3 = MULTIPLY(d2, FIX_1_306562965);
- tmp0 = (d0 + d4) << CONST_BITS;
- tmp1 = (d0 - d4) << CONST_BITS;
+ tmp0 = (d0 + d4) * CONST_SCALE;
+ tmp1 = (d0 - d4) * CONST_SCALE;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
@@ -309,8 +309,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp12 = tmp1 - tmp2;
} else {
/* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
- tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
- tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
+ tmp10 = tmp13 = (d0 + d4) * CONST_SCALE;
+ tmp11 = tmp12 = (d0 - d4) * CONST_SCALE;
}
}
@@ -620,8 +620,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
- tmp0 = (d0 + d4) << CONST_BITS;
- tmp1 = (d0 - d4) << CONST_BITS;
+ tmp0 = (d0 + d4) * CONST_SCALE;
+ tmp1 = (d0 - d4) * CONST_SCALE;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
@@ -632,8 +632,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp2 = MULTIPLY(-d6, FIX_1_306562965);
tmp3 = MULTIPLY(d6, FIX_0_541196100);
- tmp0 = (d0 + d4) << CONST_BITS;
- tmp1 = (d0 - d4) << CONST_BITS;
+ tmp0 = (d0 + d4) * CONST_SCALE;
+ tmp1 = (d0 - d4) * CONST_SCALE;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
@@ -646,8 +646,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp2 = MULTIPLY(d2, FIX_0_541196100);
tmp3 = MULTIPLY(d2, FIX_1_306562965);
- tmp0 = (d0 + d4) << CONST_BITS;
- tmp1 = (d0 - d4) << CONST_BITS;
+ tmp0 = (d0 + d4) * CONST_SCALE;
+ tmp1 = (d0 - d4) * CONST_SCALE;
tmp10 = tmp0 + tmp3;
tmp13 = tmp0 - tmp3;
@@ -655,8 +655,8 @@ void ff_j_rev_dct(DCTBLOCK data)
tmp12 = tmp1 - tmp2;
} else {
/* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
- tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
- tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
+ tmp10 = tmp13 = (d0 + d4) * CONST_SCALE;
+ tmp11 = tmp12 = (d0 - d4) * CONST_SCALE;
}
}
@@ -943,6 +943,219 @@ void ff_j_rev_dct(DCTBLOCK data)
}
}
+#undef DCTSIZE
+#define DCTSIZE 4
+#define DCTSTRIDE 8
+
+void ff_j_rev_dct4(DCTBLOCK data)
+{
+ int32_t tmp0, tmp1, tmp2, tmp3;
+ int32_t tmp10, tmp11, tmp12, tmp13;
+ int32_t z1;
+ int32_t d0, d2, d4, d6;
+ register int16_t *dataptr;
+ int rowctr;
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ data[0] += 4;
+
+ dataptr = data;
+
+ for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any row in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * row DCT calculations can be simplified this way.
+ */
+
+ register int *idataptr = (int*)dataptr;
+
+ d0 = dataptr[0];
+ d2 = dataptr[1];
+ d4 = dataptr[2];
+ d6 = dataptr[3];
+
+ if ((d2 | d4 | d6) == 0) {
+ /* AC terms all zero */
+ if (d0) {
+ /* Compute a 32 bit value to assign. */
+ int16_t dcval = (int16_t) (d0 << PASS1_BITS);
+ register int v = (dcval & 0xffff) | ((dcval << 16) & 0xffff0000);
+
+ idataptr[0] = v;
+ idataptr[1] = v;
+ }
+
+ dataptr += DCTSTRIDE; /* advance pointer to next row */
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+ if (d6) {
+ if (d2) {
+ /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */
+ z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+ tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+ tmp0 = (d0 + d4) << CONST_BITS;
+ tmp1 = (d0 - d4) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ } else {
+ /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */
+ tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+ tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+ tmp0 = (d0 + d4) << CONST_BITS;
+ tmp1 = (d0 - d4) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ }
+ } else {
+ if (d2) {
+ /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */
+ tmp2 = MULTIPLY(d2, FIX_0_541196100);
+ tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+ tmp0 = (d0 + d4) << CONST_BITS;
+ tmp1 = (d0 - d4) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ } else {
+ /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
+ tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
+ tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
+ }
+ }
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ dataptr[0] = (int16_t) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[1] = (int16_t) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[2] = (int16_t) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (int16_t) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSTRIDE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ dataptr = data;
+ for (rowctr = DCTSIZE-1; rowctr >= 0; rowctr--) {
+ /* Columns of zeroes can be exploited in the same way as we did with rows.
+ * However, the row calculation has created many nonzero AC terms, so the
+ * simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+ d0 = dataptr[DCTSTRIDE*0];
+ d2 = dataptr[DCTSTRIDE*1];
+ d4 = dataptr[DCTSTRIDE*2];
+ d6 = dataptr[DCTSTRIDE*3];
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+ if (d6) {
+ if (d2) {
+ /* d0 != 0, d2 != 0, d4 != 0, d6 != 0 */
+ z1 = MULTIPLY(d2 + d6, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(-d6, FIX_1_847759065);
+ tmp3 = z1 + MULTIPLY(d2, FIX_0_765366865);
+
+ tmp0 = (d0 + d4) << CONST_BITS;
+ tmp1 = (d0 - d4) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ } else {
+ /* d0 != 0, d2 == 0, d4 != 0, d6 != 0 */
+ tmp2 = MULTIPLY(-d6, FIX_1_306562965);
+ tmp3 = MULTIPLY(d6, FIX_0_541196100);
+
+ tmp0 = (d0 + d4) << CONST_BITS;
+ tmp1 = (d0 - d4) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ }
+ } else {
+ if (d2) {
+ /* d0 != 0, d2 != 0, d4 != 0, d6 == 0 */
+ tmp2 = MULTIPLY(d2, FIX_0_541196100);
+ tmp3 = MULTIPLY(d2, FIX_1_306562965);
+
+ tmp0 = (d0 + d4) << CONST_BITS;
+ tmp1 = (d0 - d4) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ } else {
+ /* d0 != 0, d2 == 0, d4 != 0, d6 == 0 */
+ tmp10 = tmp13 = (d0 + d4) << CONST_BITS;
+ tmp11 = tmp12 = (d0 - d4) << CONST_BITS;
+ }
+ }
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ dataptr[DCTSTRIDE*0] = tmp10 >> (CONST_BITS+PASS1_BITS+3);
+ dataptr[DCTSTRIDE*1] = tmp11 >> (CONST_BITS+PASS1_BITS+3);
+ dataptr[DCTSTRIDE*2] = tmp12 >> (CONST_BITS+PASS1_BITS+3);
+ dataptr[DCTSTRIDE*3] = tmp13 >> (CONST_BITS+PASS1_BITS+3);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+void ff_j_rev_dct2(DCTBLOCK data){
+ int d00, d01, d10, d11;
+
+ data[0] += 4;
+ d00 = data[0+0*DCTSTRIDE] + data[1+0*DCTSTRIDE];
+ d01 = data[0+0*DCTSTRIDE] - data[1+0*DCTSTRIDE];
+ d10 = data[0+1*DCTSTRIDE] + data[1+1*DCTSTRIDE];
+ d11 = data[0+1*DCTSTRIDE] - data[1+1*DCTSTRIDE];
+
+ data[0+0*DCTSTRIDE]= (d00 + d10)>>3;
+ data[1+0*DCTSTRIDE]= (d01 + d11)>>3;
+ data[0+1*DCTSTRIDE]= (d00 - d10)>>3;
+ data[1+1*DCTSTRIDE]= (d01 - d11)>>3;
+}
+
+void ff_j_rev_dct1(DCTBLOCK data){
+ data[0] = (data[0] + 4)>>3;
+}
+
+#undef FIX
+#undef CONST_BITS
+
void ff_jref_idct_put(uint8_t *dest, int line_size, int16_t *block)
{
ff_j_rev_dct(block);
diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c
index 2a7aa10254..9c4a8d4ca3 100644
--- a/libavcodec/jvdec.c
+++ b/libavcodec/jvdec.c
@@ -2,20 +2,20 @@
* Bitmap Brothers JV video decoder
* Copyright (c) 2011 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -147,24 +147,28 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
JvContext *s = avctx->priv_data;
- int buf_size = avpkt->size;
const uint8_t *buf = avpkt->data;
- const uint8_t *buf_end = buf + buf_size;
+ const uint8_t *buf_end = buf + avpkt->size;
int video_size, video_type, i, j, ret;
+ if (avpkt->size < 6)
+ return AVERROR_INVALIDDATA;
+
video_size = AV_RL32(buf);
video_type = buf[4];
buf += 5;
if (video_size) {
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if (video_size < 0 || video_size > avpkt->size - 5) {
+ av_log(avctx, AV_LOG_ERROR, "video size %d invalid\n", video_size);
+ return AVERROR_INVALIDDATA;
}
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
+ return ret;
if (video_type == 0 || video_type == 1) {
GetBitContext gb;
- init_get_bits(&gb, buf, 8 * FFMIN(video_size, buf_end - buf));
+ init_get_bits(&gb, buf, 8 * video_size);
for (j = 0; j < avctx->height; j += 8)
for (i = 0; i < avctx->width; i += 8)
@@ -174,12 +178,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
buf += video_size;
} else if (video_type == 2) {
- if (buf + 1 <= buf_end) {
- int v = *buf++;
- for (j = 0; j < avctx->height; j++)
- memset(s->frame->data[0] + j * s->frame->linesize[0],
- v, avctx->width);
- }
+ int v = *buf++;
+ for (j = 0; j < avctx->height; j++)
+ memset(s->frame->data[0] + j * s->frame->linesize[0],
+ v, avctx->width);
} else {
av_log(avctx, AV_LOG_WARNING,
"unsupported frame type %i\n", video_type);
@@ -187,9 +189,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
}
- if (buf < buf_end) {
- for (i = 0; i < AVPALETTE_COUNT && buf + 3 <= buf_end; i++) {
- s->palette[i] = AV_RB24(buf) << 2;
+ if (buf_end - buf >= AVPALETTE_COUNT * 3) {
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ uint32_t pal = AV_RB24(buf);
+ s->palette[i] = 0xFFU << 24 | pal << 2 | ((pal >> 4) & 0x30303);
buf += 3;
}
s->palette_has_changed = 1;
@@ -207,7 +210,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
*got_frame = 1;
}
- return buf_size;
+ return avpkt->size;
}
static av_cold int decode_close(AVCodecContext *avctx)
diff --git a/libavcodec/kbdwin.c b/libavcodec/kbdwin.c
index 1b7313d1dc..bf32aeb317 100644
--- a/libavcodec/kbdwin.c
+++ b/libavcodec/kbdwin.c
@@ -1,22 +1,22 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
+#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "libavutil/attributes.h"
#include "kbdwin.h"
@@ -30,7 +30,7 @@ av_cold void ff_kbd_window_init(float *window, float alpha, int n)
double local_window[FF_KBD_WINDOW_MAX];
double alpha2 = (alpha * M_PI / n) * (alpha * M_PI / n);
- assert(n <= FF_KBD_WINDOW_MAX);
+ av_assert0(n <= FF_KBD_WINDOW_MAX);
for (i = 0; i < n; i++) {
tmp = i * (n - i) * alpha2;
@@ -45,3 +45,13 @@ av_cold void ff_kbd_window_init(float *window, float alpha, int n)
for (i = 0; i < n; i++)
window[i] = sqrt(local_window[i] / sum);
}
+
+av_cold void ff_kbd_window_init_fixed(int32_t *window, float alpha, int n)
+{
+ int i;
+ float local_window[FF_KBD_WINDOW_MAX];
+
+ ff_kbd_window_init(local_window, alpha, n);
+ for (i = 0; i < n; i++)
+ window[i] = (int)floor(2147483647.0 * local_window[i] + 0.5);
+}
diff --git a/libavcodec/kbdwin.h b/libavcodec/kbdwin.h
index 89b569aa7c..4185c4206f 100644
--- a/libavcodec/kbdwin.h
+++ b/libavcodec/kbdwin.h
@@ -1,24 +1,26 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_KBDWIN_H
#define AVCODEC_KBDWIN_H
+#include <stdint.h>
+
/**
* Maximum window size for ff_kbd_window_init.
*/
@@ -31,5 +33,6 @@
* @param n size of half window, max FF_KBD_WINDOW_MAX
*/
void ff_kbd_window_init(float *window, float alpha, int n);
+void ff_kbd_window_init_fixed(int32_t *window, float alpha, int n);
#endif /* AVCODEC_KBDWIN_H */
diff --git a/libavcodec/kgv1dec.c b/libavcodec/kgv1dec.c
index 4035e472f3..4f9329f9b7 100644
--- a/libavcodec/kgv1dec.c
+++ b/libavcodec/kgv1dec.c
@@ -2,20 +2,20 @@
* Kega Game Video (KGV1) decoder
* Copyright (c) 2010 Daniel Verkamp
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,6 @@
#include "internal.h"
typedef struct KgvContext {
- AVCodecContext *avctx;
uint16_t *frame_buffer;
uint16_t *last_frame_buffer;
} KgvContext;
@@ -52,7 +51,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
const uint8_t *buf_end = buf + avpkt->size;
KgvContext * const c = avctx->priv_data;
int offsets[8];
- uint16_t *out, *prev;
+ uint8_t *out, *prev;
int outcnt = 0, maxcnt;
int w, h, i, res;
@@ -83,22 +82,21 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
return res;
- out = c->frame_buffer;
- prev = c->last_frame_buffer;
+ out = (uint8_t*)c->frame_buffer;
+ prev = (uint8_t*)c->last_frame_buffer;
for (i = 0; i < 8; i++)
offsets[i] = -1;
- while (outcnt < maxcnt && buf_end - 2 > buf) {
+ while (outcnt < maxcnt && buf_end - 2 >= buf) {
int code = AV_RL16(buf);
buf += 2;
if (!(code & 0x8000)) {
- out[outcnt++] = code; // rgb555 pixel coded directly
+ AV_WN16A(&out[2 * outcnt], code); // rgb555 pixel coded directly
+ outcnt++;
} else {
int count;
- int inp_off;
- uint16_t *inp;
if ((code & 0x6000) == 0x6000) {
// copy from previous frame
@@ -116,7 +114,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
start = (outcnt + offsets[oidx]) % maxcnt;
- if (maxcnt - start < count)
+ if (maxcnt - start < count || maxcnt - outcnt < count)
break;
if (!prev) {
@@ -125,8 +123,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
break;
}
- inp = prev;
- inp_off = start;
+ memcpy(out + 2 * outcnt, prev + 2 * start, 2 * count);
} else {
// copy from earlier in this frame
int offset = (code & 0x1FFF) + 1;
@@ -141,19 +138,12 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
count = 4 + *buf++;
}
- if (outcnt < offset)
+ if (outcnt < offset || maxcnt - outcnt < count)
break;
- inp = out;
- inp_off = outcnt - offset;
- }
-
- if (maxcnt - outcnt < count)
- break;
-
- for (i = inp_off; i < count + inp_off; i++) {
- out[outcnt++] = inp[i];
+ av_memcpy_backptr(out + 2 * outcnt, 2 * offset, 2 * count);
}
+ outcnt += count;
}
}
@@ -172,9 +162,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
static av_cold int decode_init(AVCodecContext *avctx)
{
- KgvContext * const c = avctx->priv_data;
-
- c->avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_RGB555;
return 0;
diff --git a/libavcodec/kmvc.c b/libavcodec/kmvc.c
index 5da8bb27cc..f879c353e7 100644
--- a/libavcodec/kmvc.c
+++ b/libavcodec/kmvc.c
@@ -2,20 +2,20 @@
* KMVC decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -107,6 +107,10 @@ static int kmvc_decode_intra_8x8(KmvcContext * ctx, int w, int h)
val = bytestream2_get_byte(&ctx->g);
mx = val & 0xF;
my = val >> 4;
+ if ((l0x-mx) + 320*(l0y-my) < 0 || (l0x-mx) + 320*(l0y-my) > 320*197 - 4) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
+ return AVERROR_INVALIDDATA;
+ }
for (j = 0; j < 16; j++)
BLK(ctx->cur, l0x + (j & 3), l0y + (j >> 2)) =
BLK(ctx->cur, l0x + (j & 3) - mx, l0y + (j >> 2) - my);
@@ -128,6 +132,10 @@ static int kmvc_decode_intra_8x8(KmvcContext * ctx, int w, int h)
val = bytestream2_get_byte(&ctx->g);
mx = val & 0xF;
my = val >> 4;
+ if ((l1x-mx) + 320*(l1y-my) < 0 || (l1x-mx) + 320*(l1y-my) > 320*199 - 2) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
+ return AVERROR_INVALIDDATA;
+ }
BLK(ctx->cur, l1x, l1y) = BLK(ctx->cur, l1x - mx, l1y - my);
BLK(ctx->cur, l1x + 1, l1y) =
BLK(ctx->cur, l1x + 1 - mx, l1y - my);
@@ -199,6 +207,10 @@ static int kmvc_decode_inter_8x8(KmvcContext * ctx, int w, int h)
val = bytestream2_get_byte(&ctx->g);
mx = (val & 0xF) - 8;
my = (val >> 4) - 8;
+ if ((l0x+mx) + 320*(l0y+my) < 0 || (l0x+mx) + 320*(l0y+my) > 320*197 - 4) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
+ return AVERROR_INVALIDDATA;
+ }
for (j = 0; j < 16; j++)
BLK(ctx->cur, l0x + (j & 3), l0y + (j >> 2)) =
BLK(ctx->prev, l0x + (j & 3) + mx, l0y + (j >> 2) + my);
@@ -220,6 +232,10 @@ static int kmvc_decode_inter_8x8(KmvcContext * ctx, int w, int h)
val = bytestream2_get_byte(&ctx->g);
mx = (val & 0xF) - 8;
my = (val >> 4) - 8;
+ if ((l1x+mx) + 320*(l1y+my) < 0 || (l1x+mx) + 320*(l1y+my) > 320*199 - 2) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
+ return AVERROR_INVALIDDATA;
+ }
BLK(ctx->cur, l1x, l1y) = BLK(ctx->prev, l1x + mx, l1y + my);
BLK(ctx->cur, l1x + 1, l1y) =
BLK(ctx->prev, l1x + 1 + mx, l1y + my);
@@ -256,10 +272,8 @@ static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame,
bytestream2_init(&ctx->g, avpkt->data, avpkt->size);
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
header = bytestream2_get_byte(&ctx->g);
@@ -267,7 +281,7 @@ static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame,
if (bytestream2_peek_byte(&ctx->g) == 127) {
bytestream2_skip(&ctx->g, 3);
for (i = 0; i < 127; i++) {
- ctx->pal[i + (header & 0x81)] = bytestream2_get_be24(&ctx->g);
+ ctx->pal[i + (header & 0x81)] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g);
bytestream2_skip(&ctx->g, 1);
}
bytestream2_seek(&ctx->g, -127 * 4 - 3, SEEK_CUR);
@@ -285,7 +299,7 @@ static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame,
frame->palette_has_changed = 1;
// palette starts from index 1 and has 127 entries
for (i = 1; i <= ctx->palsize; i++) {
- ctx->pal[i] = bytestream2_get_be24(&ctx->g);
+ ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g);
}
}
@@ -369,7 +383,7 @@ static av_cold int decode_init(AVCodecContext * avctx)
c->prev = c->frm1;
for (i = 0; i < 256; i++) {
- c->pal[i] = i * 0x10101;
+ c->pal[i] = 0xFFU << 24 | i * 0x10101;
}
if (avctx->extradata_size < 12) {
@@ -378,7 +392,8 @@ static av_cold int decode_init(AVCodecContext * avctx)
c->palsize = 127;
} else {
c->palsize = AV_RL16(avctx->extradata + 10);
- if (c->palsize >= MAX_PALSIZE) {
+ if (c->palsize >= (unsigned)MAX_PALSIZE) {
+ c->palsize = 127;
av_log(avctx, AV_LOG_ERROR, "KMVC palette too large\n");
return AVERROR_INVALIDDATA;
}
diff --git a/libavcodec/lagarith.c b/libavcodec/lagarith.c
index e9b00982d3..2c6d70c065 100644
--- a/libavcodec/lagarith.c
+++ b/libavcodec/lagarith.c
@@ -2,20 +2,20 @@
* Lagarith lossless decoder
* Copyright (c) 2009 Nathan Caldwell <saintdev (at) gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -128,7 +128,7 @@ static int lag_decode_prob(GetBitContext *gb, uint32_t *value)
}
val = get_bits_long(gb, bits);
- val |= 1 << bits;
+ val |= 1U << bits;
*value = val - 1;
@@ -160,8 +160,8 @@ static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb)
av_log(rac->avctx, AV_LOG_ERROR, "Invalid probability run encountered.\n");
return -1;
}
- if (prob > 257 - i)
- prob = 257 - i;
+ if (prob > 256 - i)
+ prob = 256 - i;
for (j = 0; j < prob; j++)
rac->prob[++i] = 0;
}
@@ -177,7 +177,15 @@ static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb)
if (cumul_prob & (cumul_prob - 1)) {
uint64_t mul = softfloat_reciprocal(cumul_prob);
- for (i = 1; i < 257; i++) {
+ for (i = 1; i <= 128; i++) {
+ rac->prob[i] = softfloat_mul(rac->prob[i], mul);
+ scaled_cumul_prob += rac->prob[i];
+ }
+ if (scaled_cumul_prob <= 0) {
+ av_log(rac->avctx, AV_LOG_ERROR, "Scaled probabilities invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (; i < 257; i++) {
rac->prob[i] = softfloat_mul(rac->prob[i], mul);
scaled_cumul_prob += rac->prob[i];
}
@@ -251,11 +259,8 @@ static void lag_pred_line(LagarithContext *l, uint8_t *buf,
int L, TL;
if (!line) {
- int i, align_width = (width - 1) & ~31;
/* Left prediction only for first line */
- L = l->hdsp.add_hfyu_left_pred(buf + 1, buf + 1, align_width, buf[0]);
- for (i = align_width + 1; i < width; i++)
- buf[i] += buf[i - 1];
+ L = l->hdsp.add_hfyu_left_pred(buf, buf, width, 0);
} else {
/* Left pixel is actually prev_row[width] */
L = buf[width - stride - 1];
@@ -281,18 +286,12 @@ static void lag_pred_line_yuy2(LagarithContext *l, uint8_t *buf,
int L, TL;
if (!line) {
- int i, align_width;
- if (is_luma) {
- buf++;
- width--;
- }
-
- align_width = (width - 1) & ~31;
- l->hdsp.add_hfyu_left_pred(buf + 1, buf + 1, align_width, buf[0]);
-
- for (i = align_width + 1; i < width; i++)
- buf[i] += buf[i - 1];
-
+ L= buf[0];
+ if (is_luma)
+ buf[0] = 0;
+ l->hdsp.add_hfyu_left_pred(buf, buf, width, 0);
+ if (is_luma)
+ buf[0] = L;
return;
}
if (line == 1) {
@@ -371,6 +370,10 @@ static int lag_decode_zero_run_line(LagarithContext *l, uint8_t *dst,
uint8_t mask2 = -(esc_count < 3);
uint8_t *end = dst + (width - 2);
+ avpriv_request_sample(l->avctx, "zero_run_line");
+
+ memset(dst, 0, width);
+
output_zeros:
if (l->zeros_rem) {
count = FFMIN(l->zeros_rem, width - i);
@@ -388,7 +391,7 @@ output_zeros:
i = 0;
while (!zero_run && dst + i < end) {
i++;
- if (src + i >= src_end)
+ if (i+2 >= src_end - src)
return AVERROR_INVALIDDATA;
zero_run =
!(src[i] | (src[i + 1] & mask1) | (src[i + 2] & mask2));
@@ -408,7 +411,7 @@ output_zeros:
dst += i;
}
}
- return src_start - src;
+ return src - src_start;
}
@@ -421,22 +424,30 @@ static int lag_decode_arith_plane(LagarithContext *l, uint8_t *dst,
int read = 0;
uint32_t length;
uint32_t offset = 1;
- int esc_count = src[0];
+ int esc_count;
GetBitContext gb;
lag_rac rac;
const uint8_t *src_end = src + src_size;
+ int ret;
rac.avctx = l->avctx;
l->zeros = 0;
+ if(src_size < 2)
+ return AVERROR_INVALIDDATA;
+
+ esc_count = src[0];
if (esc_count < 4) {
length = width * height;
+ if(src_size < 5)
+ return AVERROR_INVALIDDATA;
if (esc_count && AV_RL32(src + 1) < length) {
length = AV_RL32(src + 1);
offset += 4;
}
- init_get_bits(&gb, src + offset, src_size * 8);
+ if ((ret = init_get_bits8(&gb, src + offset, src_size - offset)) < 0)
+ return ret;
if (lag_read_prob_header(&rac, &gb) < 0)
return -1;
@@ -453,6 +464,8 @@ static int lag_decode_arith_plane(LagarithContext *l, uint8_t *dst,
length);
} else if (esc_count < 8) {
esc_count -= 4;
+ src ++;
+ src_size --;
if (esc_count > 0) {
/* Zero run coding only, no range coding. */
for (i = 0; i < height; i++) {
@@ -513,7 +526,7 @@ static int lag_decode_frame(AVCodecContext *avctx,
void *data, int *got_frame, AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
+ unsigned int buf_size = avpkt->size;
LagarithContext *l = avctx->priv_data;
ThreadFrame frame = { .f = data };
AVFrame *const p = data;
@@ -522,6 +535,7 @@ static int lag_decode_frame(AVCodecContext *avctx,
uint32_t offs[4];
uint8_t *srcs[4], *dst;
int i, j, planes = 3;
+ int ret;
p->key_frame = 1;
@@ -533,18 +547,53 @@ static int lag_decode_frame(AVCodecContext *avctx,
switch (frametype) {
case FRAME_SOLID_RGBA:
avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ case FRAME_SOLID_GRAY:
+ if (frametype == FRAME_SOLID_GRAY)
+ if (avctx->bits_per_coded_sample == 24) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_0RGB32;
+ planes = 4;
+ }
- if (ff_thread_get_buffer(avctx, &frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
dst = p->data[0];
+ if (frametype == FRAME_SOLID_RGBA) {
for (j = 0; j < avctx->height; j++) {
for (i = 0; i < avctx->width; i++)
AV_WN32(dst + i * 4, offset_gu);
dst += p->linesize[0];
}
+ } else {
+ for (j = 0; j < avctx->height; j++) {
+ memset(dst, buf[1], avctx->width * planes);
+ dst += p->linesize[0];
+ }
+ }
+ break;
+ case FRAME_SOLID_COLOR:
+ if (avctx->bits_per_coded_sample == 24) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ offset_gu |= 0xFFU << 24;
+ }
+
+ if ((ret = ff_thread_get_buffer(avctx, &frame,0)) < 0)
+ return ret;
+
+ dst = p->data[0];
+ for (j = 0; j < avctx->height; j++) {
+ for (i = 0; i < avctx->width; i++)
+ if (avctx->bits_per_coded_sample == 24) {
+ AV_WB24(dst + i * 3, offset_gu);
+ } else {
+ AV_WN32(dst + i * 4, offset_gu);
+ }
+ dst += p->linesize[0];
+ }
break;
case FRAME_ARITH_RGBA:
avctx->pix_fmt = AV_PIX_FMT_RGB32;
@@ -556,10 +605,8 @@ static int lag_decode_frame(AVCodecContext *avctx,
if (frametype == FRAME_ARITH_RGB24 || frametype == FRAME_U_RGB24)
avctx->pix_fmt = AV_PIX_FMT_RGB24;
- if (ff_thread_get_buffer(avctx, &frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
offs[0] = offset_bv;
offs[1] = offset_gu;
@@ -574,14 +621,13 @@ static int lag_decode_frame(AVCodecContext *avctx,
}
for (i = 0; i < planes; i++)
srcs[i] = l->rgb_planes + (i + 1) * l->rgb_stride * avctx->height - l->rgb_stride;
- if (offset_ry >= buf_size ||
- offset_gu >= buf_size ||
- offset_bv >= buf_size ||
- (planes == 4 && offs[3] >= buf_size)) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid frame offsets\n");
- return AVERROR_INVALIDDATA;
- }
+ for (i = 0; i < planes; i++)
+ if (buf_size <= offs[i]) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid frame offsets\n");
+ return AVERROR_INVALIDDATA;
+ }
+
for (i = 0; i < planes; i++)
lag_decode_arith_plane(l, srcs[i],
avctx->width, avctx->height,
@@ -615,10 +661,8 @@ static int lag_decode_frame(AVCodecContext *avctx,
case FRAME_ARITH_YUY2:
avctx->pix_fmt = AV_PIX_FMT_YUV422P;
- if (ff_thread_get_buffer(avctx, &frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
if (offset_ry >= buf_size ||
offset_gu >= buf_size ||
@@ -631,19 +675,20 @@ static int lag_decode_frame(AVCodecContext *avctx,
lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf + offset_ry,
buf_size - offset_ry);
- lag_decode_arith_plane(l, p->data[1], avctx->width / 2,
+ lag_decode_arith_plane(l, p->data[1], (avctx->width + 1) / 2,
avctx->height, p->linesize[1],
buf + offset_gu, buf_size - offset_gu);
- lag_decode_arith_plane(l, p->data[2], avctx->width / 2,
+ lag_decode_arith_plane(l, p->data[2], (avctx->width + 1) / 2,
avctx->height, p->linesize[2],
buf + offset_bv, buf_size - offset_bv);
break;
case FRAME_ARITH_YV12:
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
- if (ff_thread_get_buffer(avctx, &frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
+ return ret;
+ if (buf_size <= offset_ry || buf_size <= offset_gu || buf_size <= offset_bv) {
+ return AVERROR_INVALIDDATA;
}
if (offset_ry >= buf_size ||
@@ -657,17 +702,17 @@ static int lag_decode_frame(AVCodecContext *avctx,
lag_decode_arith_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf + offset_ry,
buf_size - offset_ry);
- lag_decode_arith_plane(l, p->data[2], avctx->width / 2,
- avctx->height / 2, p->linesize[2],
+ lag_decode_arith_plane(l, p->data[2], (avctx->width + 1) / 2,
+ (avctx->height + 1) / 2, p->linesize[2],
buf + offset_gu, buf_size - offset_gu);
- lag_decode_arith_plane(l, p->data[1], avctx->width / 2,
- avctx->height / 2, p->linesize[1],
+ lag_decode_arith_plane(l, p->data[1], (avctx->width + 1) / 2,
+ (avctx->height + 1) / 2, p->linesize[1],
buf + offset_bv, buf_size - offset_bv);
break;
default:
av_log(avctx, AV_LOG_ERROR,
"Unsupported Lagarith frame type: %#"PRIx8"\n", frametype);
- return -1;
+ return AVERROR_PATCHWELCOME;
}
*got_frame = 1;
diff --git a/libavcodec/lagarithrac.c b/libavcodec/lagarithrac.c
index edfb18fb74..37ac2cf570 100644
--- a/libavcodec/lagarithrac.c
+++ b/libavcodec/lagarithrac.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Nathan Caldwell <saintdev (at) gmail.com>
* Copyright (c) 2009 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,19 +41,16 @@ void ff_lag_rac_init(lag_rac *l, GetBitContext *gb, int length)
left = get_bits_left(gb) >> 3;
l->bytestream_start =
l->bytestream = gb->buffer + get_bits_count(gb) / 8;
- l->bytestream_end = l->bytestream_start + FFMIN(length, left);
+ l->bytestream_end = l->bytestream_start + left;
l->range = 0x80;
l->low = *l->bytestream >> 1;
- l->hash_shift = FFMAX(l->scale - 8, 0);
+ l->hash_shift = FFMAX((int)l->scale - 10, 0);
- for (i = j = 0; i < 256; i++) {
+ for (i = j = 0; i < 1024; i++) {
unsigned r = i << l->hash_shift;
while (l->prob[j + 1] <= r)
j++;
l->range_hash[i] = j;
}
-
- /* Add conversion factor to hash_shift so we don't have to in lag_get_rac. */
- l->hash_shift += 23;
}
diff --git a/libavcodec/lagarithrac.h b/libavcodec/lagarithrac.h
index e4f066e445..dfdfea0db3 100644
--- a/libavcodec/lagarithrac.h
+++ b/libavcodec/lagarithrac.h
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Nathan Caldwell <saintdev (at) gmail.com>
* Copyright (c) 2009 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,7 +48,7 @@ typedef struct lag_rac {
const uint8_t *bytestream_end; /**< End position of input bytestream. */
uint32_t prob[258]; /**< Table of cumulative probability for each symbol. */
- uint8_t range_hash[256]; /**< Hash table mapping upper byte to approximate symbol. */
+ uint8_t range_hash[1024]; /**< Hash table mapping upper byte to approximate symbol. */
} lag_rac;
void ff_lag_rac_init(lag_rac *l, GetBitContext *gb, int length);
@@ -72,9 +72,8 @@ static inline void lag_rac_refill(lag_rac *l)
*/
static inline uint8_t lag_get_rac(lag_rac *l)
{
- unsigned range_scaled, low_scaled, div;
+ unsigned range_scaled, low_scaled;
int val;
- uint8_t shift;
lag_rac_refill(l);
@@ -85,18 +84,9 @@ static inline uint8_t lag_get_rac(lag_rac *l)
if (l->low < range_scaled * l->prob[1]) {
val = 0;
} else {
- /* FIXME __builtin_clz is ~20% faster here, but not allowed in generic code. */
- shift = 30 - av_log2(range_scaled);
- div = ((range_scaled << shift) + (1 << 23) - 1) >> 23;
- /* low>>24 ensures that any cases too big for exact FASTDIV are
- * under- rather than over-estimated
- */
- low_scaled = FASTDIV(l->low - (l->low >> 24), div);
- shift -= l->hash_shift;
- shift &= 31;
- low_scaled = (low_scaled << shift) | (low_scaled >> (32 - shift));
- /* low_scaled is now a lower bound of low/range_scaled */
- val = l->range_hash[(uint8_t) low_scaled];
+ low_scaled = l->low / (range_scaled<<(l->hash_shift));
+
+ val = l->range_hash[low_scaled];
while (l->low >= range_scaled * l->prob[val + 1])
val++;
}
diff --git a/libavcodec/latm_parser.c b/libavcodec/latm_parser.c
index 6fdb897375..3820f58d69 100644
--- a/libavcodec/latm_parser.c
+++ b/libavcodec/latm_parser.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2008 Paul Kendall <paul@kcbbs.gen.nz>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,6 @@ static int latm_find_frame_end(AVCodecParserContext *s1, const uint8_t *buf,
pic_found = pc->frame_start_found;
state = pc->state;
- i = 0;
if (!pic_found) {
for (i = 0; i < buf_size; i++) {
state = (state<<8) | buf[i];
diff --git a/libavcodec/lcl.h b/libavcodec/lcl.h
index 4e7e170138..b60c0e901a 100644
--- a/libavcodec/lcl.h
+++ b/libavcodec/lcl.h
@@ -2,20 +2,20 @@
* LCL (LossLess Codec Library) Codec
* Copyright (c) 2002-2004 Roberto Togni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/lcldec.c b/libavcodec/lcldec.c
index 9c606976e7..1d94041fa5 100644
--- a/libavcodec/lcldec.c
+++ b/libavcodec/lcldec.c
@@ -2,20 +2,20 @@
* LCL (LossLess Codec Library) Codec
* Copyright (c) 2002-2004 Roberto Togni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,6 +42,7 @@
#include <stdlib.h>
#include "libavutil/mem.h"
+#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
@@ -95,7 +96,13 @@ static unsigned int mszh_decomp(const unsigned char * srcptr, int srclen, unsign
ofs = FFMIN(ofs, destptr - destptr_bak);
cnt *= 4;
cnt = FFMIN(cnt, destptr_end - destptr);
- av_memcpy_backptr(destptr, ofs, cnt);
+ if (ofs) {
+ av_memcpy_backptr(destptr, ofs, cnt);
+ } else {
+ // Not known what the correct behaviour is, but
+ // this at least avoids uninitialized data.
+ memset(destptr, 0, cnt);
+ }
destptr += cnt;
}
maskbit >>= 1;
@@ -132,7 +139,7 @@ static int zlib_decomp(AVCodecContext *avctx, const uint8_t *src, int src_len, i
av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
return AVERROR_UNKNOWN;
}
- c->zstream.next_in = src;
+ c->zstream.next_in = (uint8_t *)src;
c->zstream.avail_in = src_len;
c->zstream.next_out = c->decomp_buf + offset;
c->zstream.avail_out = c->decomp_size - offset;
@@ -164,7 +171,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
LclDecContext * const c = avctx->priv_data;
unsigned int pixel_ptr;
int row, col;
- unsigned char *encoded, *outptr;
+ unsigned char *encoded = avpkt->data, *outptr;
uint8_t *y_out, *u_out, *v_out;
unsigned int width = avctx->width; // Real image width
unsigned int height = avctx->height; // Real image height
@@ -173,11 +180,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
int uqvq, ret;
unsigned int mthread_inlen, mthread_outlen;
unsigned int len = buf_size;
+ int linesize;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
outptr = frame->data[0]; // Output image pointer
@@ -186,8 +192,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
case AV_CODEC_ID_MSZH:
switch (c->compression) {
case COMP_MSZH:
- if (c->flags & FLAG_MULTITHREAD) {
+ if (c->imgtype == IMGTYPE_RGB24 && len == FFALIGN(width * 3, 4) * height ||
+ c->imgtype == IMGTYPE_YUV111 && len == width * height * 3) {
+ ;
+ } else if (c->flags & FLAG_MULTITHREAD) {
mthread_inlen = AV_RL32(buf);
+ if (len < 8) {
+ av_log(avctx, AV_LOG_ERROR, "len %d is too small\n", len);
+ return AVERROR_INVALIDDATA;
+ }
mthread_inlen = FFMIN(mthread_inlen, len - 8);
mthread_outlen = AV_RL32(buf + 4);
mthread_outlen = FFMIN(mthread_outlen, c->decomp_size);
@@ -399,10 +412,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
}
break;
case IMGTYPE_RGB24:
+ linesize = len < FFALIGN(3 * width, 4) * height ? 3 * width : FFALIGN(3 * width, 4);
for (row = height - 1; row >= 0; row--) {
pixel_ptr = row * frame->linesize[0];
memcpy(outptr + pixel_ptr, encoded, 3 * width);
- encoded += 3 * width;
+ encoded += linesize;
}
break;
case IMGTYPE_YUV411:
@@ -471,6 +485,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
unsigned int max_basesize = FFALIGN(avctx->width, 4) *
FFALIGN(avctx->height, 4);
unsigned int max_decomp_size;
+ int subsample_h, subsample_v;
if (avctx->extradata_size < 8) {
av_log(avctx, AV_LOG_ERROR, "Extradata size too small.\n");
@@ -496,6 +511,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
max_decomp_size = max_basesize * 2;
avctx->pix_fmt = AV_PIX_FMT_YUV422P;
av_log(avctx, AV_LOG_DEBUG, "Image type is YUV 4:2:2.\n");
+ if (avctx->width % 4) {
+ avpriv_request_sample(avctx, "Unsupported dimensions\n");
+ return AVERROR_INVALIDDATA;
+ }
break;
case IMGTYPE_RGB24:
c->decomp_size = basesize * 3;
@@ -526,6 +545,12 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
+ av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &subsample_h, &subsample_v);
+ if (avctx->width % (1<<subsample_h) || avctx->height % (1<<subsample_v)) {
+ avpriv_request_sample(avctx, "Unsupported dimensions\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* Detect compression method */
c->compression = (int8_t)avctx->extradata[5];
switch (avctx->codec_id) {
diff --git a/libavcodec/lclenc.c b/libavcodec/lclenc.c
index 20841bcf58..bce1d537a2 100644
--- a/libavcodec/lclenc.c
+++ b/libavcodec/lclenc.c
@@ -2,20 +2,20 @@
* LCL (LossLess Codec Library) Codec
* Copyright (c) 2002-2004 Roberto Togni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,6 +41,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "internal.h"
#include "lcl.h"
@@ -71,19 +72,15 @@ typedef struct LclEncContext {
*
*/
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+ const AVFrame *p, int *got_packet)
{
LclEncContext *c = avctx->priv_data;
- const AVFrame * const p = pict;
int i, ret;
int zret; // Zlib return code
int max_size = deflateBound(&c->zstream, avctx->width * avctx->height * 3);
- if (!pkt->data &&
- (ret = av_new_packet(pkt, max_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error allocating packet of size %d.\n", max_size);
- return ret;
- }
+ if ((ret = ff_alloc_packet2(avctx, pkt, max_size)) < 0)
+ return ret;
if(avctx->pix_fmt != AV_PIX_FMT_BGR24){
av_log(avctx, AV_LOG_ERROR, "Format not supported!\n");
@@ -132,9 +129,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
c->avctx= avctx;
- assert(avctx->width && avctx->height);
+ av_assert0(avctx->width && avctx->height);
- avctx->extradata= av_mallocz(8);
+ avctx->extradata = av_mallocz(8 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame)
@@ -143,8 +142,9 @@ static av_cold int encode_init(AVCodecContext *avctx)
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
- // Will be user settable someday
- c->compression = 6;
+ c->compression = avctx->compression_level == FF_COMPRESSION_DEFAULT ?
+ COMP_ZLIB_NORMAL :
+ av_clip(avctx->compression_level, 0, 9);
c->flags = 0;
c->imgtype = IMGTYPE_RGB24;
avctx->bits_per_coded_sample= 24;
@@ -197,6 +197,7 @@ AVCodec ff_zlib_encoder = {
.init = encode_init,
.encode2 = encode_frame,
.close = encode_end,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
FF_CODEC_CAP_INIT_CLEANUP,
diff --git a/libavcodec/libaacplus.c b/libavcodec/libaacplus.c
new file mode 100644
index 0000000000..9087d00635
--- /dev/null
+++ b/libavcodec/libaacplus.c
@@ -0,0 +1,145 @@
+/*
+ * Interface to libaacplus for aac+ (sbr+ps) encoding
+ * Copyright (c) 2010 tipok <piratfm@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
+ * Interface to libaacplus for aac+ (sbr+ps) encoding.
+ */
+
+#include <aacplus.h>
+
+#include "avcodec.h"
+#include "internal.h"
+
+typedef struct aacPlusAudioContext {
+ aacplusEncHandle aacplus_handle;
+ unsigned long max_output_bytes;
+ unsigned long samples_input;
+} aacPlusAudioContext;
+
+static av_cold int aacPlus_encode_init(AVCodecContext *avctx)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+ aacplusEncConfiguration *aacplus_cfg;
+
+ /* number of channels */
+ if (avctx->channels < 1 || avctx->channels > 2) {
+ av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->channels);
+ return AVERROR(EINVAL);
+ }
+
+ if (avctx->profile != FF_PROFILE_AAC_LOW && avctx->profile != FF_PROFILE_UNKNOWN) {
+ av_log(avctx, AV_LOG_ERROR, "invalid AAC profile: %d, only LC supported\n", avctx->profile);
+ return AVERROR(EINVAL);
+ }
+
+ s->aacplus_handle = aacplusEncOpen(avctx->sample_rate, avctx->channels,
+ &s->samples_input, &s->max_output_bytes);
+ if (!s->aacplus_handle) {
+ av_log(avctx, AV_LOG_ERROR, "can't open encoder\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* check aacplus version */
+ aacplus_cfg = aacplusEncGetCurrentConfiguration(s->aacplus_handle);
+
+ aacplus_cfg->bitRate = avctx->bit_rate;
+ aacplus_cfg->bandWidth = avctx->cutoff;
+ aacplus_cfg->outputFormat = !(avctx->flags & CODEC_FLAG_GLOBAL_HEADER);
+ aacplus_cfg->inputFormat = avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? AACPLUS_INPUT_FLOAT : AACPLUS_INPUT_16BIT;
+ if (!aacplusEncSetConfiguration(s->aacplus_handle, aacplus_cfg)) {
+ av_log(avctx, AV_LOG_ERROR, "libaacplus doesn't support this output format!\n");
+ return AVERROR(EINVAL);
+ }
+
+ avctx->frame_size = s->samples_input / avctx->channels;
+
+ /* Set decoder specific info */
+ avctx->extradata_size = 0;
+ if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+
+ unsigned char *buffer = NULL;
+ unsigned long decoder_specific_info_size;
+
+ if (aacplusEncGetDecoderSpecificInfo(s->aacplus_handle, &buffer,
+ &decoder_specific_info_size) == 1) {
+ avctx->extradata = av_malloc(decoder_specific_info_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!avctx->extradata) {
+ free(buffer);
+ return AVERROR(ENOMEM);
+ }
+ avctx->extradata_size = decoder_specific_info_size;
+ memcpy(avctx->extradata, buffer, avctx->extradata_size);
+ }
+ free(buffer);
+ }
+ return 0;
+}
+
+static int aacPlus_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+ int32_t *input_buffer = (int32_t *)frame->data[0];
+ int ret;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, s->max_output_bytes)) < 0)
+ return ret;
+
+ pkt->size = aacplusEncEncode(s->aacplus_handle, input_buffer,
+ s->samples_input, pkt->data, pkt->size);
+ *got_packet = 1;
+ pkt->pts = frame->pts;
+ return 0;
+}
+
+static av_cold int aacPlus_encode_close(AVCodecContext *avctx)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+
+ av_freep(&avctx->extradata);
+ aacplusEncClose(s->aacplus_handle);
+
+ return 0;
+}
+
+static const AVProfile profiles[] = {
+ { FF_PROFILE_AAC_LOW, "LC" },
+ { FF_PROFILE_UNKNOWN },
+};
+
+AVCodec ff_libaacplus_encoder = {
+ .name = "libaacplus",
+ .long_name = NULL_IF_CONFIG_SMALL("libaacplus AAC+ (Advanced Audio Codec with SBR+PS)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_AAC,
+ .priv_data_size = sizeof(aacPlusAudioContext),
+ .init = aacPlus_encode_init,
+ .encode2 = aacPlus_encode_frame,
+ .close = aacPlus_encode_close,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_NONE },
+ .profiles = profiles,
+ .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ 0 },
+};
diff --git a/libavcodec/libavcodec.v b/libavcodec/libavcodec.v
index bf148075c7..c923cd378f 100644
--- a/libavcodec/libavcodec.v
+++ b/libavcodec/libavcodec.v
@@ -1,4 +1,7 @@
LIBAVCODEC_$MAJOR {
global: av*;
+ #deprecated, remove after next bump
+ audio_resample;
+ audio_resample_close;
local: *;
};
diff --git a/libavcodec/libcelt_dec.c b/libavcodec/libcelt_dec.c
new file mode 100644
index 0000000000..4e62fe53a6
--- /dev/null
+++ b/libavcodec/libcelt_dec.c
@@ -0,0 +1,140 @@
+/*
+ * Xiph CELT decoder using libcelt
+ * Copyright (c) 2011 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <celt/celt.h>
+#include <celt/celt_header.h>
+#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+struct libcelt_context {
+ CELTMode *mode;
+ CELTDecoder *dec;
+ int discard;
+};
+
+static int ff_celt_error_to_averror(int err)
+{
+ switch (err) {
+ case CELT_BAD_ARG: return AVERROR(EINVAL);
+#ifdef CELT_BUFFER_TOO_SMALL
+ case CELT_BUFFER_TOO_SMALL: return AVERROR(ENOBUFS);
+#endif
+ case CELT_INTERNAL_ERROR: return AVERROR(EFAULT);
+ case CELT_CORRUPTED_DATA: return AVERROR_INVALIDDATA;
+ case CELT_UNIMPLEMENTED: return AVERROR(ENOSYS);
+#ifdef ENOTRECOVERABLE
+ case CELT_INVALID_STATE: return AVERROR(ENOTRECOVERABLE);
+#endif
+ case CELT_ALLOC_FAIL: return AVERROR(ENOMEM);
+ default: return AVERROR(EINVAL);
+ }
+}
+
+static int ff_celt_bitstream_version_hack(CELTMode *mode)
+{
+ CELTHeader header = { .version_id = 0 };
+ celt_header_init(&header, mode, 960, 2);
+ return header.version_id;
+}
+
+static av_cold int libcelt_dec_init(AVCodecContext *c)
+{
+ struct libcelt_context *celt = c->priv_data;
+ int err;
+
+ if (!c->channels || !c->frame_size ||
+ c->frame_size > INT_MAX / sizeof(int16_t) / c->channels)
+ return AVERROR(EINVAL);
+ celt->mode = celt_mode_create(c->sample_rate, c->frame_size, &err);
+ if (!celt->mode)
+ return ff_celt_error_to_averror(err);
+ celt->dec = celt_decoder_create_custom(celt->mode, c->channels, &err);
+ if (!celt->dec) {
+ celt_mode_destroy(celt->mode);
+ return ff_celt_error_to_averror(err);
+ }
+ if (c->extradata_size >= 4) {
+ celt->discard = AV_RL32(c->extradata);
+ if (celt->discard < 0 || celt->discard >= c->frame_size) {
+ av_log(c, AV_LOG_WARNING,
+ "Invalid overlap (%d), ignored.\n", celt->discard);
+ celt->discard = 0;
+ }
+ }
+ if (c->extradata_size >= 8) {
+ unsigned version = AV_RL32(c->extradata + 4);
+ unsigned lib_version = ff_celt_bitstream_version_hack(celt->mode);
+ if (version != lib_version)
+ av_log(c, AV_LOG_WARNING,
+ "CELT bitstream version 0x%x may be "
+ "improperly decoded by libcelt for version 0x%x.\n",
+ version, lib_version);
+ }
+ c->sample_fmt = AV_SAMPLE_FMT_S16;
+ return 0;
+}
+
+static av_cold int libcelt_dec_close(AVCodecContext *c)
+{
+ struct libcelt_context *celt = c->priv_data;
+
+ celt_decoder_destroy(celt->dec);
+ celt_mode_destroy(celt->mode);
+ return 0;
+}
+
+static int libcelt_dec_decode(AVCodecContext *c, void *data,
+ int *got_frame_ptr, AVPacket *pkt)
+{
+ struct libcelt_context *celt = c->priv_data;
+ AVFrame *frame = data;
+ int err;
+ int16_t *pcm;
+
+ frame->nb_samples = c->frame_size;
+ if ((err = ff_get_buffer(c, frame, 0)) < 0)
+ return err;
+ pcm = (int16_t *)frame->data[0];
+ err = celt_decode(celt->dec, pkt->data, pkt->size, pcm, c->frame_size);
+ if (err < 0)
+ return ff_celt_error_to_averror(err);
+ if (celt->discard) {
+ frame->nb_samples -= celt->discard;
+ memmove(pcm, pcm + celt->discard * c->channels,
+ frame->nb_samples * c->channels * sizeof(int16_t));
+ celt->discard = 0;
+ }
+ *got_frame_ptr = 1;
+ return pkt->size;
+}
+
+AVCodec ff_libcelt_decoder = {
+ .name = "libcelt",
+ .long_name = NULL_IF_CONFIG_SMALL("Xiph CELT decoder using libcelt"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_CELT,
+ .priv_data_size = sizeof(struct libcelt_context),
+ .init = libcelt_dec_init,
+ .close = libcelt_dec_close,
+ .decode = libcelt_dec_decode,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/libdcadec.c b/libavcodec/libdcadec.c
index 3ab3b1a652..890d27091d 100644
--- a/libavcodec/libdcadec.c
+++ b/libavcodec/libdcadec.c
@@ -2,20 +2,20 @@
* libdcadec decoder wrapper
* Copyright (C) 2015 Hendrik Leppkes
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,7 +58,10 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
if (!s->buffer)
return AVERROR(ENOMEM);
- if ((ret = ff_dca_convert_bitstream(avpkt->data, avpkt->size, s->buffer, s->buffer_size)) < 0)
+ for (i = 0, ret = AVERROR_INVALIDDATA; i < input_size - 3 && ret < 0; i++)
+ ret = avpriv_dca_convert_bitstream(input + i, input_size - i, s->buffer, s->buffer_size);
+
+ if (ret < 0)
return ret;
input = s->buffer;
@@ -67,12 +70,12 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
if ((ret = dcadec_context_parse(s->ctx, input, input_size)) < 0) {
av_log(avctx, AV_LOG_ERROR, "dcadec_context_parse() failed: %d (%s)\n", -ret, dcadec_strerror(ret));
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
}
if ((ret = dcadec_context_filter(s->ctx, &samples, &nsamples, &channel_mask,
&sample_rate, &bits_per_sample, &profile)) < 0) {
av_log(avctx, AV_LOG_ERROR, "dcadec_context_filter() failed: %d (%s)\n", -ret, dcadec_strerror(ret));
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
}
avctx->channels = av_get_channel_layout_nb_channels(channel_mask);
@@ -81,7 +84,7 @@ static int dcadec_decode_frame(AVCodecContext *avctx, void *data,
if (bits_per_sample == 16)
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
- else if (bits_per_sample <= 24)
+ else if (bits_per_sample > 16 && bits_per_sample <= 24)
avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
else {
av_log(avctx, AV_LOG_ERROR, "Unsupported number of bits per sample: %d\n",
@@ -167,8 +170,13 @@ static av_cold int dcadec_close(AVCodecContext *avctx)
static av_cold int dcadec_init(AVCodecContext *avctx)
{
DCADecContext *s = avctx->priv_data;
+ int flags = 0;
+
+ /* Affects only lossy DTS profiles. DTS-HD MA is always bitexact */
+ if (avctx->flags & CODEC_FLAG_BITEXACT)
+ flags |= DCADEC_FLAG_CORE_BIT_EXACT;
- s->ctx = dcadec_context_create(0);
+ s->ctx = dcadec_context_create(flags);
if (!s->ctx)
return AVERROR(ENOMEM);
diff --git a/libavcodec/libfaac.c b/libavcodec/libfaac.c
index ad51a03181..69c186b11a 100644
--- a/libavcodec/libfaac.c
+++ b/libavcodec/libfaac.c
@@ -2,20 +2,20 @@
* Interface to libfaac for aac encoding
* Copyright (c) 2002 Gildas Bazin <gbazin@netcourrier.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,7 +41,6 @@ typedef struct FaacAudioContext {
AudioFrameQueue afq;
} FaacAudioContext;
-
static av_cold int Faac_encode_close(AVCodecContext *avctx)
{
FaacAudioContext *s = avctx->priv_data;
@@ -152,9 +151,20 @@ static av_cold int Faac_encode_init(AVCodecContext *avctx)
}
if (!faacEncSetConfiguration(s->faac_handle, faac_cfg)) {
- av_log(avctx, AV_LOG_ERROR, "libfaac doesn't support this output format!\n");
- ret = AVERROR(EINVAL);
- goto error;
+ int i;
+ for (i = avctx->bit_rate/1000; i ; i--) {
+ faac_cfg->bitRate = 1000*i / avctx->channels;
+ if (faacEncSetConfiguration(s->faac_handle, faac_cfg))
+ break;
+ }
+ if (!i) {
+ av_log(avctx, AV_LOG_ERROR, "libfaac doesn't support this output format!\n");
+ ret = AVERROR(EINVAL);
+ goto error;
+ } else {
+ avctx->bit_rate = 1000*i;
+ av_log(avctx, AV_LOG_WARNING, "libfaac doesn't support the specified bitrate, using %dkbit/s instead\n", i);
+ }
}
avctx->initial_padding = FAAC_DELAY_SAMPLES;
@@ -174,10 +184,8 @@ static int Faac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
int num_samples = frame ? frame->nb_samples : 0;
void *samples = frame ? frame->data[0] : NULL;
- if ((ret = ff_alloc_packet(avpkt, (7 + 768) * avctx->channels))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, (7 + 768) * avctx->channels)) < 0)
return ret;
- }
bytes_written = faacEncEncode(s->faac_handle, samples,
num_samples * avctx->channels,
diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c
index f789b75bfe..f7fc8119c2 100644
--- a/libavcodec/libfdk-aacdec.c
+++ b/libavcodec/libfdk-aacdec.c
@@ -2,7 +2,7 @@
* AAC decoder wrapper
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * 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
@@ -44,7 +44,7 @@ typedef struct FDKAACDecContext {
int initialized;
uint8_t *decoder_buffer;
uint8_t *anc_buffer;
- enum ConcealMethod conceal_method;
+ int conceal_method;
int drc_level;
int drc_boost;
int drc_heavy;
@@ -199,8 +199,8 @@ static av_cold int fdk_aac_decode_close(AVCodecContext *avctx)
if (s->handle)
aacDecoder_Close(s->handle);
- av_free(s->decoder_buffer);
- av_free(s->anc_buffer);
+ av_freep(&s->decoder_buffer);
+ av_freep(&s->anc_buffer);
return 0;
}
@@ -330,10 +330,8 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, void *data,
if (s->initialized) {
frame->nb_samples = avctx->frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "ff_get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if (s->anc_buffer) {
buf_size = DECODER_BUFFSIZE * DECODER_MAX_CHANNELS;
@@ -375,10 +373,8 @@ static int fdk_aac_decode_frame(AVCodecContext *avctx, void *data,
if (tmpptr) {
frame->nb_samples = avctx->frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "ff_get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
goto end;
- }
}
if (s->decoder_buffer) {
memcpy(frame->extended_data[0], buf,
diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c
index d45fad2676..3eadb36b83 100644
--- a/libavcodec/libfdk-aacenc.c
+++ b/libavcodec/libfdk-aacenc.c
@@ -2,7 +2,7 @@
* AAC encoder wrapper
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * 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
@@ -342,10 +342,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
/* The maximum packet size is 6144 bits aka 768 bytes per channel. */
- if ((ret = ff_alloc_packet(avpkt, FFMAX(8192, 768 * avctx->channels)))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, FFMAX(8192, 768 * avctx->channels))) < 0)
return ret;
- }
out_ptr = avpkt->data;
out_buffer_size = avpkt->size;
diff --git a/libavcodec/libgsmdec.c b/libavcodec/libgsmdec.c
index da95cc7185..8740108d78 100644
--- a/libavcodec/libgsmdec.c
+++ b/libavcodec/libgsmdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2005 Alban Bedel <albeu@free.fr>
* Copyright (c) 2006, 2007 Michel Bardiaux <mbardiaux@mediaxim.be>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,8 @@ static av_cold int libgsm_decode_init(AVCodecContext *avctx) {
avctx->channels = 1;
avctx->channel_layout = AV_CH_LAYOUT_MONO;
- avctx->sample_rate = 8000;
+ if (!avctx->sample_rate)
+ avctx->sample_rate = 8000;
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
s->state = gsm_create();
@@ -96,10 +97,8 @@ static int libgsm_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = avctx->frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t *)frame->data[0];
for (i = 0; i < avctx->frame_size / GSM_FRAME_SIZE; i++) {
@@ -124,6 +123,7 @@ static void libgsm_flush(AVCodecContext *avctx) {
gsm_option(s->state, GSM_OPT_WAV49, &one);
}
+#if CONFIG_LIBGSM_DECODER
AVCodec ff_libgsm_decoder = {
.name = "libgsm",
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"),
@@ -136,7 +136,8 @@ AVCodec ff_libgsm_decoder = {
.flush = libgsm_flush,
.capabilities = CODEC_CAP_DR1,
};
-
+#endif
+#if CONFIG_LIBGSM_MS_DECODER
AVCodec ff_libgsm_ms_decoder = {
.name = "libgsm_ms",
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
@@ -149,3 +150,4 @@ AVCodec ff_libgsm_ms_decoder = {
.flush = libgsm_flush,
.capabilities = CODEC_CAP_DR1,
};
+#endif
diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c
index 8f51321d46..b06ec6498b 100644
--- a/libavcodec/libgsmenc.c
+++ b/libavcodec/libgsmenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2005 Alban Bedel <albeu@free.fr>
* Copyright (c) 2006, 2007 Michel Bardiaux <mbardiaux@mediaxim.be>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,6 +40,12 @@
#include "internal.h"
#include "gsm.h"
+static av_cold int libgsm_encode_close(AVCodecContext *avctx) {
+ gsm_destroy(avctx->priv_data);
+ avctx->priv_data = NULL;
+ return 0;
+}
+
static av_cold int libgsm_encode_init(AVCodecContext *avctx) {
if (avctx->channels > 1) {
av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n",
@@ -63,6 +69,8 @@ static av_cold int libgsm_encode_init(AVCodecContext *avctx) {
}
avctx->priv_data = gsm_create();
+ if (!avctx->priv_data)
+ goto error;
switch(avctx->codec_id) {
case AV_CODEC_ID_GSM:
@@ -78,12 +86,9 @@ static av_cold int libgsm_encode_init(AVCodecContext *avctx) {
}
return 0;
-}
-
-static av_cold int libgsm_encode_close(AVCodecContext *avctx) {
- gsm_destroy(avctx->priv_data);
- avctx->priv_data = NULL;
- return 0;
+error:
+ libgsm_encode_close(avctx);
+ return -1;
}
static int libgsm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
@@ -93,10 +98,8 @@ static int libgsm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
gsm_signal *samples = (gsm_signal *)frame->data[0];
struct gsm_state *state = avctx->priv_data;
- if ((ret = ff_alloc_packet(avpkt, avctx->block_align))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, avctx->block_align)) < 0)
return ret;
- }
switch(avctx->codec_id) {
case AV_CODEC_ID_GSM:
@@ -112,6 +115,7 @@ static int libgsm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
+#if CONFIG_LIBGSM_ENCODER
AVCodec ff_libgsm_encoder = {
.name = "libgsm",
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"),
@@ -123,7 +127,8 @@ AVCodec ff_libgsm_encoder = {
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
-
+#endif
+#if CONFIG_LIBGSM_MS_ENCODER
AVCodec ff_libgsm_ms_encoder = {
.name = "libgsm_ms",
.long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
@@ -135,3 +140,4 @@ AVCodec ff_libgsm_ms_encoder = {
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
};
+#endif
diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c
index af693bd728..9fdd3c83f5 100644
--- a/libavcodec/libilbc.c
+++ b/libavcodec/libilbc.c
@@ -2,20 +2,20 @@
* iLBC decoder/encoder stub
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,7 +51,10 @@ static const AVOption ilbc_dec_options[] = {
};
static const AVClass ilbc_dec_class = {
- "libilbc", av_default_item_name, ilbc_dec_options, LIBAVUTIL_VERSION_INT
+ .class_name = "libilbc",
+ .item_name = av_default_item_name,
+ .option = ilbc_dec_options,
+ .version = LIBAVUTIL_VERSION_INT,
};
static av_cold int ilbc_decode_init(AVCodecContext *avctx)
@@ -90,13 +93,10 @@ static int ilbc_decode_frame(AVCodecContext *avctx, void *data,
}
frame->nb_samples = s->decoder.blockl;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
- WebRtcIlbcfix_DecodeImpl((WebRtc_Word16*) frame->data[0],
- (const WebRtc_UWord16*) buf, &s->decoder, 1);
+ WebRtcIlbcfix_DecodeImpl((int16_t *) frame->data[0], (const uint16_t *) buf, &s->decoder, 1);
*got_frame_ptr = 1;
@@ -127,7 +127,10 @@ static const AVOption ilbc_enc_options[] = {
};
static const AVClass ilbc_enc_class = {
- "libilbc", av_default_item_name, ilbc_enc_options, LIBAVUTIL_VERSION_INT
+ .class_name = "libilbc",
+ .item_name = av_default_item_name,
+ .option = ilbc_enc_options,
+ .version = LIBAVUTIL_VERSION_INT,
};
static av_cold int ilbc_encode_init(AVCodecContext *avctx)
@@ -163,12 +166,10 @@ static int ilbc_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
ILBCEncContext *s = avctx->priv_data;
int ret;
- if ((ret = ff_alloc_packet(avpkt, 50))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 50)) < 0)
return ret;
- }
- WebRtcIlbcfix_EncodeImpl((WebRtc_UWord16*) avpkt->data, (const WebRtc_Word16*) frame->data[0], &s->encoder);
+ WebRtcIlbcfix_EncodeImpl((uint16_t *) avpkt->data, (const int16_t *) frame->data[0], &s->encoder);
avpkt->size = s->encoder.no_of_bytes;
*got_packet_ptr = 1;
diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c
index 067a17fdcd..b5d50048aa 100644
--- a/libavcodec/libmp3lame.c
+++ b/libavcodec/libmp3lame.c
@@ -2,20 +2,20 @@
* Interface to libmp3lame for mp3 encoding
* Copyright (c) 2002 Lennert Buytenhek <buytenh@gnu.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@
#include "mpegaudio.h"
#include "mpegaudiodecheader.h"
-#define BUFFER_SIZE (7200 + 2 * MPA_FRAME_SIZE + MPA_FRAME_SIZE / 4)
+#define BUFFER_SIZE (7200 + 2 * MPA_FRAME_SIZE + MPA_FRAME_SIZE / 4+1000) // FIXME: Buffer size to small? Adding 1000 to make up for it.
typedef struct LAMEContext {
AVClass *class;
@@ -52,7 +52,7 @@ typedef struct LAMEContext {
int abr;
float *samples_flt[2];
AudioFrameQueue afq;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
} LAMEContext;
@@ -79,6 +79,7 @@ static av_cold int mp3lame_encode_close(AVCodecContext *avctx)
av_freep(&s->samples_flt[0]);
av_freep(&s->samples_flt[1]);
av_freep(&s->buffer);
+ av_freep(&s->fdsp);
ff_af_queue_close(&s->afq);
@@ -97,6 +98,7 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
if (!(s->gfp = lame_init()))
return AVERROR(ENOMEM);
+
lame_set_num_channels(s->gfp, avctx->channels);
lame_set_mode(s->gfp, avctx->channels > 1 ? s->joint_stereo ? JOINT_STEREO : STEREO : MONO);
@@ -105,9 +107,7 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
lame_set_out_samplerate(s->gfp, avctx->sample_rate);
/* algorithmic quality */
- if (avctx->compression_level == FF_COMPRESSION_DEFAULT)
- lame_set_quality(s->gfp, 5);
- else
+ if (avctx->compression_level != FF_COMPRESSION_DEFAULT)
lame_set_quality(s->gfp, avctx->compression_level);
/* rate control */
@@ -146,7 +146,7 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
if (avctx->sample_fmt == AV_SAMPLE_FMT_FLTP) {
int ch;
for (ch = 0; ch < avctx->channels; ch++) {
- s->samples_flt[ch] = av_malloc(avctx->frame_size *
+ s->samples_flt[ch] = av_malloc_array(avctx->frame_size,
sizeof(*s->samples_flt[ch]));
if (!s->samples_flt[ch]) {
ret = AVERROR(ENOMEM);
@@ -159,7 +159,12 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
if (ret < 0)
goto error;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
return 0;
error:
@@ -198,7 +203,7 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
return AVERROR(EINVAL);
}
for (ch = 0; ch < avctx->channels; ch++) {
- s->fdsp.vector_fmul_scalar(s->samples_flt[ch],
+ s->fdsp->vector_fmul_scalar(s->samples_flt[ch],
(const float *)frame->data[ch],
32768.0f,
FFALIGN(frame->nb_samples, 8));
@@ -208,6 +213,8 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
default:
return AVERROR_BUG;
}
+ } else if (!s->afq.frame_alloc) {
+ lame_result = 0;
} else {
lame_result = lame_encode_flush(s->gfp, s->buffer + s->buffer_index,
s->buffer_size - s->buffer_index);
@@ -251,10 +258,8 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
ff_dlog(avctx, "in:%d packet-len:%d index:%d\n", avctx->frame_size, len,
s->buffer_index);
if (len <= s->buffer_index) {
- if ((ret = ff_alloc_packet(avpkt, len))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, len)) < 0)
return ret;
- }
memcpy(avpkt->data, s->buffer, len);
s->buffer_index -= len;
memmove(s->buffer, s->buffer + len, s->buffer_index);
@@ -272,9 +277,9 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
#define OFFSET(x) offsetof(LAMEContext, x)
#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "reservoir", "Use bit reservoir.", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
- { "joint_stereo", "Use joint stereo.", OFFSET(joint_stereo), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
- { "abr", "Use ABR", OFFSET(abr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
+ { "reservoir", "use bit reservoir", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+ { "joint_stereo", "use joint stereo", OFFSET(joint_stereo), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+ { "abr", "use ABR", OFFSET(abr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
{ NULL },
};
diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c
index 72e0bbbbf5..556792ad77 100644
--- a/libavcodec/libopencore-amr.c
+++ b/libavcodec/libopencore-amr.c
@@ -1,21 +1,21 @@
/*
* AMR Audio decoder stub
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,8 @@ static int amr_decode_fix_avctx(AVCodecContext *avctx)
{
const int is_amr_wb = 1 + (avctx->codec_id == AV_CODEC_ID_AMR_WB);
- avctx->sample_rate = 8000 * is_amr_wb;
+ if (!avctx->sample_rate)
+ avctx->sample_rate = 8000 * is_amr_wb;
if (avctx->channels > 1) {
avpriv_report_missing_feature(avctx, "multi-channel AMR");
@@ -103,10 +104,8 @@ static int amr_nb_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = 160;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
dec_mode = (buf[0] >> 3) & 0x000F;
packet_size = block_size[dec_mode] + 1;
@@ -181,7 +180,7 @@ static const AVOption options[] = {
{ NULL }
};
-static const AVClass class = {
+static const AVClass amrnb_class = {
"libopencore_amrnb", av_default_item_name, options, LIBAVUTIL_VERSION_INT
};
@@ -189,7 +188,7 @@ static av_cold int amr_nb_encode_init(AVCodecContext *avctx)
{
AMRContext *s = avctx->priv_data;
- if (avctx->sample_rate != 8000) {
+ if (avctx->sample_rate != 8000 && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n");
return AVERROR(ENOSYS);
}
@@ -206,7 +205,6 @@ static av_cold int amr_nb_encode_init(AVCodecContext *avctx)
s->enc_state = Encoder_Interface_init(s->enc_dtx);
if (!s->enc_state) {
av_log(avctx, AV_LOG_ERROR, "Encoder_Interface_init error\n");
- av_freep(&avctx->coded_frame);
return -1;
}
@@ -238,14 +236,12 @@ static int amr_nb_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
s->enc_bitrate = avctx->bit_rate;
}
- if ((ret = ff_alloc_packet(avpkt, 32))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 32)) < 0)
return ret;
- }
if (frame) {
if (frame->nb_samples < avctx->frame_size) {
- flush_buf = av_mallocz(avctx->frame_size * sizeof(*flush_buf));
+ flush_buf = av_mallocz_array(avctx->frame_size, sizeof(*flush_buf));
if (!flush_buf)
return AVERROR(ENOMEM);
memcpy(flush_buf, samples, frame->nb_samples * sizeof(*flush_buf));
@@ -260,7 +256,7 @@ static int amr_nb_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
} else {
if (s->enc_last_frame < 0)
return 0;
- flush_buf = av_mallocz(avctx->frame_size * sizeof(*flush_buf));
+ flush_buf = av_mallocz_array(avctx->frame_size, sizeof(*flush_buf));
if (!flush_buf)
return AVERROR(ENOMEM);
samples = flush_buf;
@@ -270,7 +266,7 @@ static int amr_nb_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
written = Encoder_Interface_Encode(s->enc_state, s->enc_mode, samples,
avpkt->data, 0);
ff_dlog(avctx, "amr_nb_encode_frame encoded %u bytes, bitrate %u, first byte was %#02x\n",
- written, s->enc_mode, frame[0]);
+ written, s->enc_mode, avpkt->data[0]);
/* Get the next frame pts/duration */
ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts,
@@ -294,7 +290,7 @@ AVCodec ff_libopencore_amrnb_encoder = {
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_SMALL_LAST_FRAME,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
- .priv_class = &class,
+ .priv_class = &amrnb_class,
};
#endif /* CONFIG_LIBOPENCORE_AMRNB_ENCODER */
@@ -336,10 +332,8 @@ static int amr_wb_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = 320;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
mode = (buf[0] >> 3) & 0x000F;
packet_size = block_size[mode];
@@ -349,6 +343,10 @@ static int amr_wb_decode_frame(AVCodecContext *avctx, void *data,
buf_size, packet_size + 1);
return AVERROR_INVALIDDATA;
}
+ if (!packet_size) {
+ av_log(avctx, AV_LOG_ERROR, "amr packet_size invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
D_IF_decode(s->state, buf, (short *)frame->data[0], _good_frame);
diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c
index 35431fa361..2b7bad3a08 100644
--- a/libavcodec/libopenh264enc.c
+++ b/libavcodec/libopenh264enc.c
@@ -2,20 +2,20 @@
* OpenH264 video encoder
* Copyright (C) 2014 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c
index 73b1b9f71e..1cd1b9b009 100644
--- a/libavcodec/libopenjpegdec.c
+++ b/libavcodec/libopenjpegdec.c
@@ -2,20 +2,20 @@
* JPEG 2000 decoding support via OpenJPEG
* Copyright (c) 2009 Jaikrishnan Menon <realityman@gmx.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,6 @@
*/
#define OPJ_STATIC
-#include <openjpeg.h>
#include "libavutil/common.h"
#include "libavutil/imgutils.h"
@@ -37,6 +36,12 @@
#include "internal.h"
#include "thread.h"
+#if HAVE_OPENJPEG_1_5_OPENJPEG_H
+# include <openjpeg-1.5/openjpeg.h>
+#else
+# include <openjpeg.h>
+#endif
+
#define JP2_SIG_TYPE 0x6A502020
#define JP2_SIG_VALUE 0x0D0A870A
@@ -46,72 +51,71 @@
AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64
#define GRAY_PIXEL_FORMATS AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, \
- AV_PIX_FMT_GRAY16
-
-#define YUV_PIXEL_FORMATS AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, \
- AV_PIX_FMT_YUVA420P, \
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, \
- AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, \
- AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, \
- AV_PIX_FMT_YUV444P9, \
- AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, \
- AV_PIX_FMT_YUV444P10, \
- AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, \
- AV_PIX_FMT_YUV444P16
+ AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16
+
+#define YUV_PIXEL_FORMATS AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUVA420P, \
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, \
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, \
+ AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, \
+ AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, \
+ AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, \
+ AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, \
+ AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, \
+ AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, \
+ AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, \
+ AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16
#define XYZ_PIXEL_FORMATS AV_PIX_FMT_XYZ12
-static const enum AVPixelFormat rgb_pix_fmts[] = {
+static const enum AVPixelFormat libopenjpeg_rgb_pix_fmts[] = {
RGB_PIXEL_FORMATS
};
-static const enum AVPixelFormat gray_pix_fmts[] = {
+static const enum AVPixelFormat libopenjpeg_gray_pix_fmts[] = {
GRAY_PIXEL_FORMATS
};
-static const enum AVPixelFormat yuv_pix_fmts[] = {
+static const enum AVPixelFormat libopenjpeg_yuv_pix_fmts[] = {
YUV_PIXEL_FORMATS
};
-static const enum AVPixelFormat any_pix_fmts[] = {
+static const enum AVPixelFormat libopenjpeg_all_pix_fmts[] = {
RGB_PIXEL_FORMATS, GRAY_PIXEL_FORMATS, YUV_PIXEL_FORMATS, XYZ_PIXEL_FORMATS
};
typedef struct LibOpenJPEGContext {
AVClass *class;
opj_dparameters_t dec_params;
- int lowres;
int lowqual;
} LibOpenJPEGContext;
-static int libopenjpeg_matches_pix_fmt(const opj_image_t *img,
- enum AVPixelFormat pix_fmt)
+static inline int libopenjpeg_matches_pix_fmt(const opj_image_t *image, enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
int match = 1;
- if (desc->nb_components != img->numcomps) {
+ if (desc->nb_components != image->numcomps) {
return 0;
}
switch (desc->nb_components) {
case 4:
match = match &&
- desc->comp[3].depth_minus1 + 1 >= img->comps[3].prec &&
- 1 == img->comps[3].dx &&
- 1 == img->comps[3].dy;
+ desc->comp[3].depth_minus1 + 1 >= image->comps[3].prec &&
+ 1 == image->comps[3].dx &&
+ 1 == image->comps[3].dy;
case 3:
match = match &&
- desc->comp[2].depth_minus1 + 1 >= img->comps[2].prec &&
- 1 << desc->log2_chroma_w == img->comps[2].dx &&
- 1 << desc->log2_chroma_h == img->comps[2].dy;
+ desc->comp[2].depth_minus1 + 1 >= image->comps[2].prec &&
+ 1 << desc->log2_chroma_w == image->comps[2].dx &&
+ 1 << desc->log2_chroma_h == image->comps[2].dy;
case 2:
match = match &&
- desc->comp[1].depth_minus1 + 1 >= img->comps[1].prec &&
- 1 << desc->log2_chroma_w == img->comps[1].dx &&
- 1 << desc->log2_chroma_h == img->comps[1].dy;
+ desc->comp[1].depth_minus1 + 1 >= image->comps[1].prec &&
+ 1 << desc->log2_chroma_w == image->comps[1].dx &&
+ 1 << desc->log2_chroma_h == image->comps[1].dy;
case 1:
match = match &&
- desc->comp[0].depth_minus1 + 1 >= img->comps[0].prec &&
- 1 == img->comps[0].dx &&
- 1 == img->comps[0].dy;
+ desc->comp[0].depth_minus1 + 1 >= image->comps[0].prec &&
+ 1 == image->comps[0].dx &&
+ 1 == image->comps[0].dy;
default:
break;
}
@@ -119,28 +123,27 @@ static int libopenjpeg_matches_pix_fmt(const opj_image_t *img,
return match;
}
-static enum AVPixelFormat libopenjpeg_guess_pix_fmt(const opj_image_t *image)
-{
+static inline enum AVPixelFormat libopenjpeg_guess_pix_fmt(const opj_image_t *image) {
int index;
const enum AVPixelFormat *possible_fmts = NULL;
int possible_fmts_nb = 0;
switch (image->color_space) {
case CLRSPC_SRGB:
- possible_fmts = rgb_pix_fmts;
- possible_fmts_nb = FF_ARRAY_ELEMS(rgb_pix_fmts);
+ possible_fmts = libopenjpeg_rgb_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_rgb_pix_fmts);
break;
case CLRSPC_GRAY:
- possible_fmts = gray_pix_fmts;
- possible_fmts_nb = FF_ARRAY_ELEMS(gray_pix_fmts);
+ possible_fmts = libopenjpeg_gray_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_gray_pix_fmts);
break;
case CLRSPC_SYCC:
- possible_fmts = yuv_pix_fmts;
- possible_fmts_nb = FF_ARRAY_ELEMS(yuv_pix_fmts);
+ possible_fmts = libopenjpeg_yuv_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_yuv_pix_fmts);
break;
default:
- possible_fmts = any_pix_fmts;
- possible_fmts_nb = FF_ARRAY_ELEMS(any_pix_fmts);
+ possible_fmts = libopenjpeg_all_pix_fmts;
+ possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_all_pix_fmts);
break;
}
@@ -167,40 +170,37 @@ static inline int libopenjpeg_ispacked(enum AVPixelFormat pix_fmt)
return 1;
}
-static void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image)
-{
+static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image) {
uint8_t *img_ptr;
int index, x, y, c;
-
for (y = 0; y < picture->height; y++) {
index = y * picture->width;
img_ptr = picture->data[0] + y * picture->linesize[0];
for (x = 0; x < picture->width; x++, index++)
for (c = 0; c < image->numcomps; c++)
- *img_ptr++ = image->comps[c].data[index];
+ *img_ptr++ = 0x80 * image->comps[c].sgnd + image->comps[c].data[index];
}
}
-static void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image)
-{
+static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image) {
uint16_t *img_ptr;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(picture->format);
int index, x, y, c;
int adjust[4];
-
for (x = 0; x < image->numcomps; x++)
- adjust[x] = FFMAX(FFMIN(16 - image->comps[x].prec, 8), 0);
+ adjust[x] = FFMAX(FFMIN(desc->comp[x].depth_minus1 + 1 - image->comps[x].prec, 8), 0) + desc->comp[x].shift;
for (y = 0; y < picture->height; y++) {
index = y * picture->width;
img_ptr = (uint16_t *) (picture->data[0] + y * picture->linesize[0]);
for (x = 0; x < picture->width; x++, index++)
for (c = 0; c < image->numcomps; c++)
- *img_ptr++ = image->comps[c].data[index] << adjust[c];
+ *img_ptr++ = (1 << image->comps[c].prec - 1) * image->comps[c].sgnd +
+ (unsigned)image->comps[c].data[index] << adjust[c];
}
}
-static void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image)
-{
+static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) {
int *comp_data;
uint8_t *img_ptr;
int index, x, y;
@@ -210,7 +210,7 @@ static void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image)
for (y = 0; y < image->comps[index].h; y++) {
img_ptr = picture->data[index] + y * picture->linesize[index];
for (x = 0; x < image->comps[index].w; x++) {
- *img_ptr = (uint8_t) *comp_data;
+ *img_ptr = 0x80 * image->comps[index].sgnd + *comp_data;
img_ptr++;
comp_data++;
}
@@ -218,18 +218,22 @@ static void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image)
}
}
-static void libopenjpeg_copyto16(AVFrame *p, opj_image_t *image)
-{
+static inline void libopenjpeg_copyto16(AVFrame *picture, opj_image_t *image) {
int *comp_data;
uint16_t *img_ptr;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(picture->format);
int index, x, y;
+ int adjust[4];
+ for (x = 0; x < image->numcomps; x++)
+ adjust[x] = FFMAX(FFMIN(desc->comp[x].depth_minus1 + 1 - image->comps[x].prec, 8), 0) + desc->comp[x].shift;
for (index = 0; index < image->numcomps; index++) {
comp_data = image->comps[index].data;
for (y = 0; y < image->comps[index].h; y++) {
- img_ptr = (uint16_t *)(p->data[index] + y * p->linesize[index]);
+ img_ptr = (uint16_t *)(picture->data[index] + y * picture->linesize[index]);
for (x = 0; x < image->comps[index].w; x++) {
- *img_ptr = *comp_data;
+ *img_ptr = (1 << image->comps[index].prec - 1) * image->comps[index].sgnd +
+ (unsigned)*comp_data << adjust[index];
img_ptr++;
comp_data++;
}
@@ -283,9 +287,7 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx,
return AVERROR_UNKNOWN;
}
opj_set_event_mgr((opj_common_ptr) dec, NULL, NULL);
-
ctx->dec_params.cp_limit_decoding = LIMIT_TO_MAIN_HEADER;
- ctx->dec_params.cp_reduce = ctx->lowres;
ctx->dec_params.cp_layer = ctx->lowqual;
// Tie decoder with decoding parameters
opj_setup_decoder(dec, &ctx->dec_params);
@@ -311,11 +313,6 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx,
width = image->x1 - image->x0;
height = image->y1 - image->y0;
- if (ctx->lowres) {
- width = (width + (1 << ctx->lowres) - 1) >> ctx->lowres;
- height = (height + (1 << ctx->lowres) - 1) >> ctx->lowres;
- }
-
ret = ff_set_dimensions(avctx, width, height);
if (ret < 0)
goto done;
@@ -329,20 +326,17 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx,
if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "Unable to determine pixel format\n");
- ret = AVERROR_INVALIDDATA;
goto done;
}
-
for (i = 0; i < image->numcomps; i++)
if (image->comps[i].prec > avctx->bits_per_raw_sample)
avctx->bits_per_raw_sample = image->comps[i].prec;
- if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "ff_thread_get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
goto done;
- }
ctx->dec_params.cp_limit_decoding = NO_LIMITATION;
+ ctx->dec_params.cp_reduce = avctx->lowres;
// Tie decoder with decoding parameters.
opj_setup_decoder(dec, &ctx->dec_params);
stream = opj_cio_open((opj_common_ptr) dec, buf, buf_size);
@@ -416,12 +410,10 @@ done:
static const AVOption options[] = {
{ "lowqual", "Limit the number of layers used for decoding",
OFFSET(lowqual), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VD },
- { "lowres", "Lower the decoding resolution by a power of two",
- OFFSET(lowres), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VD },
{ NULL },
};
-static const AVClass class = {
+static const AVClass openjpeg_class = {
.class_name = "libopenjpeg",
.item_name = av_default_item_name,
.option = options,
@@ -437,5 +429,6 @@ AVCodec ff_libopenjpeg_decoder = {
.init = libopenjpeg_decode_init,
.decode = libopenjpeg_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
- .priv_class = &class,
+ .max_lowres = 31,
+ .priv_class = &openjpeg_class,
};
diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c
index 00c0ed6d0d..95b0987e14 100644
--- a/libavcodec/libopenjpegenc.c
+++ b/libavcodec/libopenjpegenc.c
@@ -1,21 +1,21 @@
/*
* JPEG 2000 encoding support via OpenJPEG
- * Copyright (c) 2011 Michael Bradshaw <mbradshaw@sorensonmedia.com>
+ * Copyright (c) 2011 Michael Bradshaw <mjbshaw gmail com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,8 +25,8 @@
*/
#define OPJ_STATIC
-#include <openjpeg.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
@@ -34,11 +34,16 @@
#include "avcodec.h"
#include "internal.h"
+#if HAVE_OPENJPEG_1_5_OPENJPEG_H
+# include <openjpeg-1.5/openjpeg.h>
+#else
+# include <openjpeg.h>
+#endif
+
typedef struct LibOpenJPEGContext {
AVClass *avclass;
opj_image_t *image;
opj_cparameters_t enc_params;
- opj_cinfo_t *compress;
opj_event_mgr_t event_mgr;
int format;
int profile;
@@ -66,37 +71,79 @@ static void info_callback(const char *msg, void *data)
av_log(data, AV_LOG_DEBUG, "%s\n", msg);
}
-static opj_image_t *libopenjpeg_create_image(AVCodecContext *avctx,
- opj_cparameters_t *parameters)
+static void cinema_parameters(opj_cparameters_t *p)
+{
+ p->tile_size_on = 0;
+ p->cp_tdx = 1;
+ p->cp_tdy = 1;
+
+ /* Tile part */
+ p->tp_flag = 'C';
+ p->tp_on = 1;
+
+ /* Tile and Image shall be at (0, 0) */
+ p->cp_tx0 = 0;
+ p->cp_ty0 = 0;
+ p->image_offset_x0 = 0;
+ p->image_offset_y0 = 0;
+
+ /* Codeblock size= 32 * 32 */
+ p->cblockw_init = 32;
+ p->cblockh_init = 32;
+ p->csty |= 0x01;
+
+ /* The progression order shall be CPRL */
+ p->prog_order = CPRL;
+
+ /* No ROI */
+ p->roi_compno = -1;
+
+ /* No subsampling */
+ p->subsampling_dx = 1;
+ p->subsampling_dy = 1;
+
+ /* 9-7 transform */
+ p->irreversible = 1;
+
+ p->tcp_mct = 1;
+}
+
+static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *parameters)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
- opj_image_cmptparm_t *cmptparm;
- OPJ_COLOR_SPACE color_space;
+ opj_image_cmptparm_t cmptparm[4] = {{0}};
opj_image_t *img;
int i;
int sub_dx[4];
int sub_dy[4];
- int numcomps = desc->nb_components;
+ int numcomps;
+ OPJ_COLOR_SPACE color_space = CLRSPC_UNKNOWN;
- sub_dx[0] =
- sub_dx[3] = 1;
- sub_dy[0] =
- sub_dy[3] = 1;
- sub_dx[1] =
- sub_dx[2] = 1 << desc->log2_chroma_w;
- sub_dy[1] =
- sub_dy[2] = 1 << desc->log2_chroma_h;
+ sub_dx[0] = sub_dx[3] = 1;
+ sub_dy[0] = sub_dy[3] = 1;
+ sub_dx[1] = sub_dx[2] = 1 << desc->log2_chroma_w;
+ sub_dy[1] = sub_dy[2] = 1 << desc->log2_chroma_h;
+
+ numcomps = desc->nb_components;
switch (avctx->pix_fmt) {
case AV_PIX_FMT_GRAY8:
- case AV_PIX_FMT_GRAY16:
case AV_PIX_FMT_YA8:
+ case AV_PIX_FMT_GRAY16:
+ case AV_PIX_FMT_YA16:
color_space = CLRSPC_GRAY;
break;
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_RGB48:
case AV_PIX_FMT_RGBA64:
+ case AV_PIX_FMT_GBR24P:
+ case AV_PIX_FMT_GBRP9:
+ case AV_PIX_FMT_GBRP10:
+ case AV_PIX_FMT_GBRP12:
+ case AV_PIX_FMT_GBRP14:
+ case AV_PIX_FMT_GBRP16:
+ case AV_PIX_FMT_XYZ12:
color_space = CLRSPC_SRGB;
break;
case AV_PIX_FMT_YUV410P:
@@ -106,15 +153,32 @@ static opj_image_t *libopenjpeg_create_image(AVCodecContext *avctx,
case AV_PIX_FMT_YUV440P:
case AV_PIX_FMT_YUV444P:
case AV_PIX_FMT_YUVA420P:
+ case AV_PIX_FMT_YUVA422P:
+ case AV_PIX_FMT_YUVA444P:
case AV_PIX_FMT_YUV420P9:
case AV_PIX_FMT_YUV422P9:
case AV_PIX_FMT_YUV444P9:
+ case AV_PIX_FMT_YUVA420P9:
+ case AV_PIX_FMT_YUVA422P9:
+ case AV_PIX_FMT_YUVA444P9:
case AV_PIX_FMT_YUV420P10:
case AV_PIX_FMT_YUV422P10:
case AV_PIX_FMT_YUV444P10:
+ case AV_PIX_FMT_YUVA420P10:
+ case AV_PIX_FMT_YUVA422P10:
+ case AV_PIX_FMT_YUVA444P10:
+ case AV_PIX_FMT_YUV420P12:
+ case AV_PIX_FMT_YUV422P12:
+ case AV_PIX_FMT_YUV444P12:
+ case AV_PIX_FMT_YUV420P14:
+ case AV_PIX_FMT_YUV422P14:
+ case AV_PIX_FMT_YUV444P14:
case AV_PIX_FMT_YUV420P16:
case AV_PIX_FMT_YUV422P16:
case AV_PIX_FMT_YUV444P16:
+ case AV_PIX_FMT_YUVA420P16:
+ case AV_PIX_FMT_YUVA422P16:
+ case AV_PIX_FMT_YUVA444P16:
color_space = CLRSPC_SYCC;
break;
default:
@@ -124,24 +188,25 @@ static opj_image_t *libopenjpeg_create_image(AVCodecContext *avctx,
return NULL;
}
- cmptparm = av_mallocz(numcomps * sizeof(*cmptparm));
- if (!cmptparm) {
- av_log(avctx, AV_LOG_ERROR, "Not enough memory");
- return NULL;
- }
-
for (i = 0; i < numcomps; i++) {
cmptparm[i].prec = desc->comp[i].depth_minus1 + 1;
cmptparm[i].bpp = desc->comp[i].depth_minus1 + 1;
cmptparm[i].sgnd = 0;
- cmptparm[i].dx = sub_dx[i];
- cmptparm[i].dy = sub_dy[i];
- cmptparm[i].w = avctx->width / sub_dx[i];
- cmptparm[i].h = avctx->height / sub_dy[i];
+ cmptparm[i].dx = sub_dx[i];
+ cmptparm[i].dy = sub_dy[i];
+ cmptparm[i].w = (avctx->width + sub_dx[i] - 1) / sub_dx[i];
+ cmptparm[i].h = (avctx->height + sub_dy[i] - 1) / sub_dy[i];
}
img = opj_image_create(numcomps, cmptparm, color_space);
- av_freep(&cmptparm);
+
+ // x0, y0 is the top left corner of the image
+ // x1, y1 is the width, height of the reference grid
+ img->x0 = 0;
+ img->y0 = 0;
+ img->x1 = (avctx->width - 1) * parameters->subsampling_dx + 1;
+ img->y1 = (avctx->height - 1) * parameters->subsampling_dy + 1;
+
return img;
}
@@ -152,162 +217,292 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx)
opj_set_default_encoder_parameters(&ctx->enc_params);
- ctx->enc_params.cp_rsiz = ctx->profile;
- ctx->enc_params.mode = !!avctx->global_quality;
- ctx->enc_params.cp_cinema = ctx->cinema_mode;
- ctx->enc_params.prog_order = ctx->prog_order;
- ctx->enc_params.numresolution = ctx->numresolution;
- ctx->enc_params.cp_disto_alloc = ctx->disto_alloc;
- ctx->enc_params.cp_fixed_alloc = ctx->fixed_alloc;
+ ctx->enc_params.cp_rsiz = ctx->profile;
+ ctx->enc_params.mode = !!avctx->global_quality;
+ ctx->enc_params.cp_cinema = ctx->cinema_mode;
+ ctx->enc_params.prog_order = ctx->prog_order;
+ ctx->enc_params.numresolution = ctx->numresolution;
+ ctx->enc_params.cp_disto_alloc = ctx->disto_alloc;
+ ctx->enc_params.cp_fixed_alloc = ctx->fixed_alloc;
ctx->enc_params.cp_fixed_quality = ctx->fixed_quality;
- ctx->enc_params.tcp_numlayers = ctx->numlayers;
- ctx->enc_params.tcp_rates[0] = FFMAX(avctx->compression_level, 0) * 2;
+ ctx->enc_params.tcp_numlayers = ctx->numlayers;
+ ctx->enc_params.tcp_rates[0] = FFMAX(avctx->compression_level, 0) * 2;
- ctx->compress = opj_create_compress(ctx->format);
- if (!ctx->compress) {
- av_log(avctx, AV_LOG_ERROR, "Error creating the compressor\n");
- return AVERROR(ENOMEM);
+ if (ctx->cinema_mode > 0) {
+ cinema_parameters(&ctx->enc_params);
}
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame) {
- av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
- goto fail;
- }
-
- ctx->image = libopenjpeg_create_image(avctx, &ctx->enc_params);
+ ctx->image = mj2_create_image(avctx, &ctx->enc_params);
if (!ctx->image) {
av_log(avctx, AV_LOG_ERROR, "Error creating the mj2 image\n");
err = AVERROR(EINVAL);
goto fail;
}
- ctx->event_mgr.info_handler = info_callback;
- ctx->event_mgr.error_handler = error_callback;
- ctx->event_mgr.warning_handler = warning_callback;
- opj_set_event_mgr((opj_common_ptr) ctx->compress, &ctx->event_mgr, avctx);
+ avctx->coded_frame = av_frame_alloc();
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Error allocating coded frame\n");
+ goto fail;
+ }
return 0;
fail:
- av_freep(&ctx->compress);
- av_freep(&avctx->coded_frame);
+ opj_image_destroy(ctx->image);
+ ctx->image = NULL;
+ av_frame_free(&avctx->coded_frame);
return err;
}
-static void libopenjpeg_copy_packed8(AVCodecContext *avctx,
- const AVFrame *frame, opj_image_t *image)
+static int libopenjpeg_copy_packed8(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
{
int compno;
- int x, y;
- int image_index, frame_index;
+ int x;
+ int y;
+ int *image_line;
+ int frame_index;
const int numcomps = image->numcomps;
- for (compno = 0; compno < numcomps; ++compno)
+ for (compno = 0; compno < numcomps; ++compno) {
+ if (image->comps[compno].w > frame->linesize[0] / numcomps) {
+ av_log(avctx, AV_LOG_ERROR, "Error: frame's linesize is too small for the image\n");
+ return 0;
+ }
+ }
+
+ for (compno = 0; compno < numcomps; ++compno) {
for (y = 0; y < avctx->height; ++y) {
- image_index = y * avctx->width;
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
frame_index = y * frame->linesize[0] + compno;
for (x = 0; x < avctx->width; ++x) {
- image->comps[compno].data[image_index++] =
- frame->data[0][frame_index];
+ image_line[x] = frame->data[0][frame_index];
frame_index += numcomps;
}
+ for (; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - 1];
+ }
}
+ for (; y < image->comps[compno].h; ++y) {
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
+ for (x = 0; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - image->comps[compno].w];
+ }
+ }
+ }
+
+ return 1;
}
-static void libopenjpeg_copy_packed16(AVCodecContext *avctx,
- const AVFrame *frame, opj_image_t *image)
+// for XYZ 12 bit
+static int libopenjpeg_copy_packed12(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
{
int compno;
int x, y;
- int image_index, frame_index;
+ int *image_line;
+ int frame_index;
const int numcomps = image->numcomps;
uint16_t *frame_ptr = (uint16_t *)frame->data[0];
- for (compno = 0; compno < numcomps; ++compno)
+ for (compno = 0; compno < numcomps; ++compno) {
+ if (image->comps[compno].w > frame->linesize[0] / numcomps) {
+ av_log(avctx, AV_LOG_ERROR, "Error: frame's linesize is too small for the image\n");
+ return 0;
+ }
+ }
+
+ for (compno = 0; compno < numcomps; ++compno) {
for (y = 0; y < avctx->height; ++y) {
- image_index = y * avctx->width;
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
frame_index = y * (frame->linesize[0] / 2) + compno;
for (x = 0; x < avctx->width; ++x) {
- image->comps[compno].data[image_index++] =
- frame_ptr[frame_index];
+ image_line[x] = frame_ptr[frame_index] >> 4;
frame_index += numcomps;
}
+ for (; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - 1];
+ }
+ }
+ for (; y < image->comps[compno].h; ++y) {
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
+ for (x = 0; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - image->comps[compno].w];
+ }
}
+ }
+
+ return 1;
}
-static void libopenjpeg_copy_unpacked8(AVCodecContext *avctx,
- const AVFrame *frame, opj_image_t *image)
+static int libopenjpeg_copy_packed16(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
{
int compno;
- int x, y;
- int width, height;
- int image_index, frame_index;
+ int x;
+ int y;
+ int *image_line;
+ int frame_index;
const int numcomps = image->numcomps;
+ uint16_t *frame_ptr = (uint16_t*)frame->data[0];
+
+ for (compno = 0; compno < numcomps; ++compno) {
+ if (image->comps[compno].w > frame->linesize[0] / numcomps) {
+ av_log(avctx, AV_LOG_ERROR, "Error: frame's linesize is too small for the image\n");
+ return 0;
+ }
+ }
+
+ for (compno = 0; compno < numcomps; ++compno) {
+ for (y = 0; y < avctx->height; ++y) {
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
+ frame_index = y * (frame->linesize[0] / 2) + compno;
+ for (x = 0; x < avctx->width; ++x) {
+ image_line[x] = frame_ptr[frame_index];
+ frame_index += numcomps;
+ }
+ for (; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - 1];
+ }
+ }
+ for (; y < image->comps[compno].h; ++y) {
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
+ for (x = 0; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - image->comps[compno].w];
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int libopenjpeg_copy_unpacked8(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
+{
+ int compno;
+ int x;
+ int y;
+ int width;
+ int height;
+ int *image_line;
+ int frame_index;
+ const int numcomps = image->numcomps;
+
+ for (compno = 0; compno < numcomps; ++compno) {
+ if (image->comps[compno].w > frame->linesize[compno]) {
+ av_log(avctx, AV_LOG_ERROR, "Error: frame's linesize is too small for the image\n");
+ return 0;
+ }
+ }
for (compno = 0; compno < numcomps; ++compno) {
width = avctx->width / image->comps[compno].dx;
height = avctx->height / image->comps[compno].dy;
for (y = 0; y < height; ++y) {
- image_index = y * width;
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
frame_index = y * frame->linesize[compno];
for (x = 0; x < width; ++x)
- image->comps[compno].data[image_index++] =
- frame->data[compno][frame_index++];
+ image_line[x] = frame->data[compno][frame_index++];
+ for (; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - 1];
+ }
+ }
+ for (; y < image->comps[compno].h; ++y) {
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
+ for (x = 0; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - image->comps[compno].w];
+ }
}
}
+
+ return 1;
}
-static void libopenjpeg_copy_unpacked16(AVCodecContext *avctx,
- const AVFrame *frame,
- opj_image_t *image)
+static int libopenjpeg_copy_unpacked16(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image)
{
int compno;
- int x, y;
- int width, height;
- int image_index, frame_index;
+ int x;
+ int y;
+ int width;
+ int height;
+ int *image_line;
+ int frame_index;
const int numcomps = image->numcomps;
uint16_t *frame_ptr;
for (compno = 0; compno < numcomps; ++compno) {
+ if (image->comps[compno].w > frame->linesize[compno]) {
+ av_log(avctx, AV_LOG_ERROR, "Error: frame's linesize is too small for the image\n");
+ return 0;
+ }
+ }
+
+ for (compno = 0; compno < numcomps; ++compno) {
width = avctx->width / image->comps[compno].dx;
height = avctx->height / image->comps[compno].dy;
frame_ptr = (uint16_t *)frame->data[compno];
for (y = 0; y < height; ++y) {
- image_index = y * width;
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
frame_index = y * (frame->linesize[compno] / 2);
for (x = 0; x < width; ++x)
- image->comps[compno].data[image_index++] =
- frame_ptr[frame_index++];
+ image_line[x] = frame_ptr[frame_index++];
+ for (; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - 1];
+ }
+ }
+ for (; y < image->comps[compno].h; ++y) {
+ image_line = image->comps[compno].data + y * image->comps[compno].w;
+ for (x = 0; x < image->comps[compno].w; ++x) {
+ image_line[x] = image_line[x - image->comps[compno].w];
+ }
}
}
+
+ return 1;
}
static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
LibOpenJPEGContext *ctx = avctx->priv_data;
- opj_cinfo_t *compress = ctx->compress;
opj_image_t *image = ctx->image;
- opj_cio_t *stream;
+ opj_cinfo_t *compress = NULL;
+ opj_cio_t *stream = NULL;
+ int cpyresult = 0;
int ret, len;
-
- // x0, y0 is the top left corner of the image
- // x1, y1 is the width, height of the reference grid
- image->x0 = 0;
- image->y0 = 0;
- image->x1 = (avctx->width - 1) * ctx->enc_params.subsampling_dx + 1;
- image->y1 = (avctx->height - 1) * ctx->enc_params.subsampling_dy + 1;
+ AVFrame *gbrframe;
switch (avctx->pix_fmt) {
case AV_PIX_FMT_RGB24:
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_YA8:
- libopenjpeg_copy_packed8(avctx, frame, image);
+ cpyresult = libopenjpeg_copy_packed8(avctx, frame, image);
+ break;
+ case AV_PIX_FMT_XYZ12:
+ cpyresult = libopenjpeg_copy_packed12(avctx, frame, image);
break;
case AV_PIX_FMT_RGB48:
case AV_PIX_FMT_RGBA64:
- libopenjpeg_copy_packed16(avctx, frame, image);
+ case AV_PIX_FMT_YA16:
+ cpyresult = libopenjpeg_copy_packed16(avctx, frame, image);
+ break;
+ case AV_PIX_FMT_GBR24P:
+ case AV_PIX_FMT_GBRP9:
+ case AV_PIX_FMT_GBRP10:
+ case AV_PIX_FMT_GBRP12:
+ case AV_PIX_FMT_GBRP14:
+ case AV_PIX_FMT_GBRP16:
+ gbrframe = av_frame_clone(frame);
+ if (!gbrframe)
+ return AVERROR(ENOMEM);
+ gbrframe->data[0] = frame->data[2]; // swap to be rgb
+ gbrframe->data[1] = frame->data[0];
+ gbrframe->data[2] = frame->data[1];
+ gbrframe->linesize[0] = frame->linesize[2];
+ gbrframe->linesize[1] = frame->linesize[0];
+ gbrframe->linesize[2] = frame->linesize[1];
+ if (avctx->pix_fmt == AV_PIX_FMT_GBR24P) {
+ cpyresult = libopenjpeg_copy_unpacked8(avctx, gbrframe, image);
+ } else {
+ cpyresult = libopenjpeg_copy_unpacked16(avctx, gbrframe, image);
+ }
+ av_frame_free(&gbrframe);
break;
case AV_PIX_FMT_GRAY8:
case AV_PIX_FMT_YUV410P:
@@ -317,19 +512,36 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case AV_PIX_FMT_YUV440P:
case AV_PIX_FMT_YUV444P:
case AV_PIX_FMT_YUVA420P:
- libopenjpeg_copy_unpacked8(avctx, frame, image);
+ case AV_PIX_FMT_YUVA422P:
+ case AV_PIX_FMT_YUVA444P:
+ cpyresult = libopenjpeg_copy_unpacked8(avctx, frame, image);
break;
case AV_PIX_FMT_GRAY16:
case AV_PIX_FMT_YUV420P9:
case AV_PIX_FMT_YUV422P9:
case AV_PIX_FMT_YUV444P9:
+ case AV_PIX_FMT_YUVA420P9:
+ case AV_PIX_FMT_YUVA422P9:
+ case AV_PIX_FMT_YUVA444P9:
case AV_PIX_FMT_YUV444P10:
case AV_PIX_FMT_YUV422P10:
case AV_PIX_FMT_YUV420P10:
+ case AV_PIX_FMT_YUVA444P10:
+ case AV_PIX_FMT_YUVA422P10:
+ case AV_PIX_FMT_YUVA420P10:
+ case AV_PIX_FMT_YUV420P12:
+ case AV_PIX_FMT_YUV422P12:
+ case AV_PIX_FMT_YUV444P12:
+ case AV_PIX_FMT_YUV420P14:
+ case AV_PIX_FMT_YUV422P14:
+ case AV_PIX_FMT_YUV444P14:
case AV_PIX_FMT_YUV444P16:
case AV_PIX_FMT_YUV422P16:
case AV_PIX_FMT_YUV420P16:
- libopenjpeg_copy_unpacked16(avctx, frame, image);
+ case AV_PIX_FMT_YUVA444P16:
+ case AV_PIX_FMT_YUVA422P16:
+ case AV_PIX_FMT_YUVA420P16:
+ cpyresult = libopenjpeg_copy_unpacked16(avctx, frame, image);
break;
default:
av_log(avctx, AV_LOG_ERROR,
@@ -339,29 +551,51 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
break;
}
+ if (!cpyresult) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not copy the frame data to the internal image buffer\n");
+ return -1;
+ }
+
+ compress = opj_create_compress(ctx->format);
+ if (!compress) {
+ av_log(avctx, AV_LOG_ERROR, "Error creating the compressor\n");
+ return AVERROR(ENOMEM);
+ }
+
opj_setup_encoder(compress, &ctx->enc_params, image);
+
stream = opj_cio_open((opj_common_ptr) compress, NULL, 0);
if (!stream) {
av_log(avctx, AV_LOG_ERROR, "Error creating the cio stream\n");
return AVERROR(ENOMEM);
}
+ memset(&ctx->event_mgr, 0, sizeof(opj_event_mgr_t));
+ ctx->event_mgr.info_handler = info_callback;
+ ctx->event_mgr.error_handler = error_callback;
+ ctx->event_mgr.warning_handler = warning_callback;
+ opj_set_event_mgr((opj_common_ptr) compress, &ctx->event_mgr, avctx);
+
if (!opj_encode(compress, stream, image, NULL)) {
- opj_cio_close(stream);
av_log(avctx, AV_LOG_ERROR, "Error during the opj encode\n");
return -1;
}
len = cio_tell(stream);
- if ((ret = ff_alloc_packet(pkt, len)) < 0) {
- opj_cio_close(stream);
+ if ((ret = ff_alloc_packet2(avctx, pkt, len)) < 0) {
return ret;
}
memcpy(pkt->data, stream->buffer, len);
pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = 1;
+
opj_cio_close(stream);
+ stream = NULL;
+ opj_destroy_compress(compress);
+ compress = NULL;
+
return 0;
}
@@ -369,9 +603,9 @@ static av_cold int libopenjpeg_encode_close(AVCodecContext *avctx)
{
LibOpenJPEGContext *ctx = avctx->priv_data;
- opj_destroy_compress(ctx->compress);
opj_image_destroy(ctx->image);
- av_freep(&avctx->coded_frame);
+ ctx->image = NULL;
+ av_frame_free(&avctx->coded_frame);
return 0;
}
@@ -396,15 +630,15 @@ static const AVOption options[] = {
{ "rpcl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = RPCL }, 0, 0, VE, "prog_order" },
{ "pcrl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PCRL }, 0, 0, VE, "prog_order" },
{ "cprl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPRL }, 0, 0, VE, "prog_order" },
- { "numresolution", NULL, OFFSET(numresolution), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, 10, VE },
- { "numlayers", NULL, OFFSET(numlayers), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 10, VE },
- { "disto_alloc", NULL, OFFSET(disto_alloc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
- { "fixed_alloc", NULL, OFFSET(fixed_alloc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
- { "fixed_quality", NULL, OFFSET(fixed_quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "numresolution", NULL, OFFSET(numresolution), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, INT_MAX, VE },
+ { "numlayers", NULL, OFFSET(numlayers), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 10, VE },
+ { "disto_alloc", NULL, OFFSET(disto_alloc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
+ { "fixed_alloc", NULL, OFFSET(fixed_alloc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "fixed_quality", NULL, OFFSET(fixed_quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
{ NULL },
};
-static const AVClass class = {
+static const AVClass openjpeg_class = {
.class_name = "libopenjpeg",
.item_name = av_default_item_name,
.option = options,
@@ -420,18 +654,25 @@ AVCodec ff_libopenjpeg_encoder = {
.init = libopenjpeg_encode_init,
.encode2 = libopenjpeg_encode_frame,
.close = libopenjpeg_encode_close,
- .capabilities = 0,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48,
- AV_PIX_FMT_RGBA64,
- AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA8,
+ AV_PIX_FMT_RGBA64, AV_PIX_FMT_GBR24P,
+ AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P,
- AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
- AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA444P,
AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
+ AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
+ AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12,
+ AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
+ AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
+ AV_PIX_FMT_XYZ12,
AV_PIX_FMT_NONE
},
- .priv_class = &class,
+ .priv_class = &openjpeg_class,
};
diff --git a/libavcodec/libopus.c b/libavcodec/libopus.c
index b511415962..16395c73df 100644
--- a/libavcodec/libopus.c
+++ b/libavcodec/libopus.c
@@ -2,20 +2,20 @@
* libopus encoder/decoder common code
* Copyright (c) 2012 Nicolas George
*
- * This file is part of libav.
+ * This file is part of FFmpeg.
*
- * libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/libopus.h b/libavcodec/libopus.h
index b08257df4a..a8223d1d6f 100644
--- a/libavcodec/libopus.h
+++ b/libavcodec/libopus.h
@@ -2,20 +2,20 @@
* libopus encoder/decoder common code
* Copyright (c) 2012 Nicolas George
*
- * This file is part of libav.
+ * This file is part of FFmpeg.
*
- * libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c
index 398450f4d4..8436302a9b 100644
--- a/libavcodec/libopusdec.c
+++ b/libavcodec/libopusdec.c
@@ -2,20 +2,20 @@
* Opus decoder using libopus
* Copyright (c) 2012 Nicolas George
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,10 @@
struct libopus_context {
OpusMSDecoder *dec;
+ int pre_skip;
+#ifndef OPUS_SET_GAIN
+ union { int i; double d; } gain;
+#endif
};
#define OPUS_HEAD_SIZE 19
@@ -49,6 +53,7 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
ff_vorbis_channel_layouts[avc->channels - 1];
if (avc->extradata_size >= OPUS_HEAD_SIZE) {
+ opus->pre_skip = AV_RL16(avc->extradata + 10);
gain_db = sign_extend(AV_RL16(avc->extradata + 16), 16);
channel_map = AV_RL8 (avc->extradata + 18);
}
@@ -73,7 +78,7 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1];
int ch;
- /* Remap channels from vorbis order to libav order */
+ /* Remap channels from vorbis order to ffmpeg order */
for (ch = 0; ch < avc->channels; ch++)
mapping_arr[ch] = mapping[vorbis_offset[ch]];
mapping = mapping_arr;
@@ -88,12 +93,23 @@ static av_cold int libopus_decode_init(AVCodecContext *avc)
return ff_opus_error_to_averror(ret);
}
+#ifdef OPUS_SET_GAIN
ret = opus_multistream_decoder_ctl(opus->dec, OPUS_SET_GAIN(gain_db));
if (ret != OPUS_OK)
av_log(avc, AV_LOG_WARNING, "Failed to set gain: %s\n",
opus_strerror(ret));
+#else
+ {
+ double gain_lin = pow(10, gain_db / (20.0 * 256));
+ if (avc->sample_fmt == AV_SAMPLE_FMT_FLT)
+ opus->gain.d = gain_lin;
+ else
+ opus->gain.i = FFMIN(gain_lin * 65536, INT_MAX);
+ }
+#endif
- avc->delay = 3840; /* Decoder delay (in samples) at 48kHz */
+ /* Decoder delay (in samples) at 48kHz */
+ avc->delay = avc->internal->skip_samples = opus->pre_skip;
return 0;
}
@@ -116,11 +132,8 @@ static int libopus_decode(AVCodecContext *avc, void *data,
int ret, nb_samples;
frame->nb_samples = MAX_FRAME_SIZE;
- ret = ff_get_buffer(avc, frame, 0);
- if (ret < 0) {
- av_log(avc, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avc, frame, 0)) < 0)
return ret;
- }
if (avc->sample_fmt == AV_SAMPLE_FMT_S16)
nb_samples = opus_multistream_decode(opus->dec, pkt->data, pkt->size,
@@ -137,6 +150,21 @@ static int libopus_decode(AVCodecContext *avc, void *data,
return ff_opus_error_to_averror(nb_samples);
}
+#ifndef OPUS_SET_GAIN
+ {
+ int i = avc->channels * nb_samples;
+ if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) {
+ float *pcm = (float *)frame->data[0];
+ for (; i > 0; i--, pcm++)
+ *pcm = av_clipf(*pcm * opus->gain.d, -1, 1);
+ } else {
+ int16_t *pcm = (int16_t *)frame->data[0];
+ for (; i > 0; i--, pcm++)
+ *pcm = av_clip_int16(((int64_t)opus->gain.i * *pcm) >> 16);
+ }
+ }
+#endif
+
frame->nb_samples = nb_samples;
*got_frame_ptr = 1;
@@ -148,6 +176,9 @@ static void libopus_flush(AVCodecContext *avc)
struct libopus_context *opus = avc->priv_data;
opus_multistream_decoder_ctl(opus->dec, OPUS_RESET_STATE);
+ /* The stream can have been extracted by a tool that is not Opus-aware.
+ Therefore, any packet can become the first of the stream. */
+ avc->internal->skip_samples = opus->pre_skip;
}
AVCodec ff_libopus_decoder = {
diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c
index da6194acac..785460972d 100644
--- a/libavcodec/libopusenc.c
+++ b/libavcodec/libopusenc.c
@@ -2,20 +2,20 @@
* Opus encoder using libopus
* Copyright (c) 2012 Nathan Caldwell
*
- * This file is part of libav.
+ * This file is part of FFmpeg.
*
- * libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,8 +65,8 @@ static const uint8_t opus_vorbis_channel_map[8][8] = {
{ 0, 6, 1, 2, 3, 4, 5, 7 },
};
-/* libav to libopus channel order mapping, passed to libopus */
-static const uint8_t libav_libopus_channel_map[8][8] = {
+/* libavcodec to libopus channel order mapping, passed to libopus */
+static const uint8_t libavcodec_libopus_channel_map[8][8] = {
{ 0 },
{ 0, 1 },
{ 0, 1, 2 },
@@ -107,6 +107,13 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
{
int ret;
+ if (avctx->global_quality) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Quality-based encoding not supported, "
+ "please specify a bitrate and VBR setting.\n");
+ return AVERROR(EINVAL);
+ }
+
ret = opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(avctx->bit_rate));
if (ret != OPUS_OK) {
av_log(avctx, AV_LOG_ERROR,
@@ -149,7 +156,7 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
return OPUS_OK;
}
-static int av_cold libopus_encode_init(AVCodecContext *avctx)
+static av_cold int libopus_encode_init(AVCodecContext *avctx)
{
LibopusEncContext *opus = avctx->priv_data;
const uint8_t *channel_mapping;
@@ -159,7 +166,7 @@ static int av_cold libopus_encode_init(AVCodecContext *avctx)
coupled_stream_count = opus_coupled_streams[avctx->channels - 1];
opus->stream_count = avctx->channels - coupled_stream_count;
- channel_mapping = libav_libopus_channel_map[avctx->channels - 1];
+ channel_mapping = libavcodec_libopus_channel_map[avctx->channels - 1];
/* FIXME: Opus can handle up to 255 channels. However, the mapping for
* anything greater than 8 is undefined. */
@@ -270,7 +277,7 @@ static int av_cold libopus_encode_init(AVCodecContext *avctx)
}
avctx->extradata_size = header_size;
- opus->samples = av_mallocz(frame_size * avctx->channels *
+ opus->samples = av_mallocz_array(frame_size, avctx->channels *
av_get_bytes_per_sample(avctx->sample_fmt));
if (!opus->samples) {
av_log(avctx, AV_LOG_ERROR, "Failed to allocate samples buffer.\n");
@@ -307,6 +314,7 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
av_get_bytes_per_sample(avctx->sample_fmt);
uint8_t *audio;
int ret;
+ int discard_padding;
if (frame) {
ret = ff_af_queue_add(&opus->afq, frame);
@@ -327,10 +335,8 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
/* Maximum packet size taken from opusenc in opus-tools. 60ms packets
* consist of 3 frames in one packet. The maximum frame size is 1275
* bytes along with the largest possible packet header of 7 bytes. */
- if (ret = ff_alloc_packet(avpkt, (1275 * 3 + 7) * opus->stream_count)) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, (1275 * 3 + 7) * opus->stream_count)) < 0)
return ret;
- }
if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT)
ret = opus_multistream_encode_float(opus->enc, (float *)audio,
@@ -352,12 +358,31 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
ff_af_queue_remove(&opus->afq, opus->opts.packet_size,
&avpkt->pts, &avpkt->duration);
+ discard_padding = opus->opts.packet_size - avpkt->duration;
+ // Check if subtraction resulted in an overflow
+ if ((discard_padding < opus->opts.packet_size) != (avpkt->duration > 0)) {
+ av_free_packet(avpkt);
+ av_free(avpkt);
+ return AVERROR(EINVAL);
+ }
+ if (discard_padding > 0) {
+ uint8_t* side_data = av_packet_new_side_data(avpkt,
+ AV_PKT_DATA_SKIP_SAMPLES,
+ 10);
+ if(!side_data) {
+ av_free_packet(avpkt);
+ av_free(avpkt);
+ return AVERROR(ENOMEM);
+ }
+ AV_WL32(side_data + 4, discard_padding);
+ }
+
*got_packet_ptr = 1;
return 0;
}
-static int av_cold libopus_encode_close(AVCodecContext *avctx)
+static av_cold int libopus_encode_close(AVCodecContext *avctx)
{
LibopusEncContext *opus = avctx->priv_data;
diff --git a/libavcodec/libschroedinger.c b/libavcodec/libschroedinger.c
index 157433ea95..9f0b25c02b 100644
--- a/libavcodec/libschroedinger.c
+++ b/libavcodec/libschroedinger.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com >
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -191,9 +191,10 @@ SchroFrame *ff_create_schro_frame(AVCodecContext *avctx,
uv_height = y_height >> (SCHRO_FRAME_FORMAT_V_SHIFT(schro_frame_fmt));
p_pic = av_mallocz(sizeof(AVPicture));
- if (!p_pic)
+ if (!p_pic || avpicture_alloc(p_pic, avctx->pix_fmt, y_width, y_height) < 0) {
+ av_free(p_pic);
return NULL;
- avpicture_alloc(p_pic, avctx->pix_fmt, y_width, y_height);
+ }
p_frame = schro_frame_new();
p_frame->format = schro_frame_fmt;
diff --git a/libavcodec/libschroedinger.h b/libavcodec/libschroedinger.h
index 5481f92ce0..12fe57c7f1 100644
--- a/libavcodec/libschroedinger.h
+++ b/libavcodec/libschroedinger.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com >
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/libschroedingerdec.c b/libavcodec/libschroedingerdec.c
index c61aaefafe..8778869af8 100644
--- a/libavcodec/libschroedingerdec.c
+++ b/libavcodec/libschroedingerdec.c
@@ -2,20 +2,20 @@
* Dirac decoder support via Schroedinger libraries
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com >
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,10 +37,6 @@
#include "internal.h"
#include "libschroedinger.h"
-#undef NDEBUG
-#include <assert.h>
-
-
#include <schroedinger/schro.h>
#include <schroedinger/schrodebug.h>
#include <schroedinger/schrovideoformat.h>
@@ -134,7 +130,7 @@ static SchroBuffer *find_next_parse_unit(SchroParseUnitContext *parse_ctx)
}
/**
-* Returns Libav chroma format.
+* Returns FFmpeg chroma format.
*/
static enum AVPixelFormat get_chroma_format(SchroChromaFormat schro_pix_fmt)
{
@@ -179,7 +175,7 @@ static void libschroedinger_handle_first_access_unit(AVCodecContext *avctx)
p_schro_params->format = schro_decoder_get_video_format(decoder);
- /* Tell Libav about sequence details. */
+ /* Tell FFmpeg about sequence details. */
if (av_image_check_size(p_schro_params->format->width,
p_schro_params->format->height, 0, avctx) < 0) {
av_log(avctx, AV_LOG_ERROR, "invalid dimensions (%dx%d)\n",
@@ -312,10 +308,10 @@ static int libschroedinger_decode_frame(AVCodecContext *avctx,
framewithpts = ff_schro_queue_pop(&p_schro_params->dec_frame_queue);
if (framewithpts && framewithpts->frame) {
- if (ff_get_buffer(avctx, avframe, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Unable to allocate buffer\n");
- return AVERROR(ENOMEM);
- }
+ int ret;
+
+ if ((ret = ff_get_buffer(avctx, avframe, 0)) < 0)
+ return ret;
memcpy(avframe->data[0],
framewithpts->frame->components[0].data,
diff --git a/libavcodec/libschroedingerenc.c b/libavcodec/libschroedingerenc.c
index b2c492b990..f7a32353e2 100644
--- a/libavcodec/libschroedingerenc.c
+++ b/libavcodec/libschroedingerenc.c
@@ -2,20 +2,20 @@
* Dirac encoder support via Schroedinger libraries
* Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju at gmail dot com >
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,7 @@
#include <schroedinger/schrovideoformat.h>
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "internal.h"
#include "libschroedinger.h"
@@ -382,10 +383,8 @@ static int libschroedinger_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
pkt_size = p_frame_output->size;
if (last_frame_in_sequence && p_schro_params->enc_buf_size > 0)
pkt_size += p_schro_params->enc_buf_size;
- if ((ret = ff_alloc_packet(pkt, pkt_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", pkt_size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size)) < 0)
goto error;
- }
memcpy(pkt->data, p_frame_output->p_encbuf, p_frame_output->size);
avctx->coded_frame->key_frame = p_frame_output->key_frame;
diff --git a/libavcodec/libshine.c b/libavcodec/libshine.c
new file mode 100644
index 0000000000..27c1a5f43f
--- /dev/null
+++ b/libavcodec/libshine.c
@@ -0,0 +1,149 @@
+/*
+ * Interface to libshine for mp3 encoding
+ * Copyright (c) 2012 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
+ */
+
+#include <shine/layer3.h>
+
+#include "libavutil/intreadwrite.h"
+#include "audio_frame_queue.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "mpegaudio.h"
+#include "mpegaudiodecheader.h"
+
+#define BUFFER_SIZE (4096 * 20)
+
+typedef struct SHINEContext {
+ shine_config_t config;
+ shine_t shine;
+ uint8_t buffer[BUFFER_SIZE];
+ int buffer_index;
+ AudioFrameQueue afq;
+} SHINEContext;
+
+static av_cold int libshine_encode_init(AVCodecContext *avctx)
+{
+ SHINEContext *s = avctx->priv_data;
+
+ if (avctx->channels <= 0 || avctx->channels > 2){
+ av_log(avctx, AV_LOG_ERROR, "only mono or stereo is supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ shine_set_config_mpeg_defaults(&s->config.mpeg);
+ if (avctx->bit_rate)
+ s->config.mpeg.bitr = avctx->bit_rate / 1000;
+ s->config.mpeg.mode = avctx->channels == 2 ? STEREO : MONO;
+ s->config.wave.samplerate = avctx->sample_rate;
+ s->config.wave.channels = avctx->channels == 2 ? PCM_STEREO : PCM_MONO;
+ if (shine_check_config(s->config.wave.samplerate, s->config.mpeg.bitr) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid configuration\n");
+ return AVERROR(EINVAL);
+ }
+ s->shine = shine_initialise(&s->config);
+ if (!s->shine)
+ return AVERROR(ENOMEM);
+ avctx->frame_size = shine_samples_per_pass(s->shine);
+ ff_af_queue_init(avctx, &s->afq);
+ return 0;
+}
+
+static int libshine_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ SHINEContext *s = avctx->priv_data;
+ MPADecodeHeader hdr;
+ unsigned char *data;
+ int written;
+ int ret, len;
+
+ if (frame)
+ data = shine_encode_buffer(s->shine, (int16_t **)frame->data, &written);
+ else
+ data = shine_flush(s->shine, &written);
+ if (written < 0)
+ return -1;
+ if (written > 0) {
+ if (s->buffer_index + written > BUFFER_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "internal buffer too small\n");
+ return AVERROR_BUG;
+ }
+ memcpy(s->buffer + s->buffer_index, data, written);
+ s->buffer_index += written;
+ }
+ if (frame) {
+ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
+ return ret;
+ }
+
+ if (s->buffer_index < 4 || !s->afq.frame_count)
+ return 0;
+ if (avpriv_mpegaudio_decode_header(&hdr, AV_RB32(s->buffer))) {
+ av_log(avctx, AV_LOG_ERROR, "free format output not supported\n");
+ return -1;
+ }
+
+ len = hdr.frame_size;
+ if (len <= s->buffer_index) {
+ if ((ret = ff_alloc_packet2(avctx, avpkt, len)))
+ return ret;
+ memcpy(avpkt->data, s->buffer, len);
+ s->buffer_index -= len;
+ memmove(s->buffer, s->buffer + len, s->buffer_index);
+
+ ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts,
+ &avpkt->duration);
+
+ avpkt->size = len;
+ *got_packet_ptr = 1;
+ }
+ return 0;
+}
+
+static av_cold int libshine_encode_close(AVCodecContext *avctx)
+{
+ SHINEContext *s = avctx->priv_data;
+
+ ff_af_queue_close(&s->afq);
+ shine_close(s->shine);
+ return 0;
+}
+
+static const int libshine_sample_rates[] = {
+ 44100, 48000, 32000, 0
+};
+
+AVCodec ff_libshine_encoder = {
+ .name = "libshine",
+ .long_name = NULL_IF_CONFIG_SMALL("libshine MP3 (MPEG audio layer 3)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_MP3,
+ .priv_data_size = sizeof(SHINEContext),
+ .init = libshine_encode_init,
+ .encode2 = libshine_encode_frame,
+ .close = libshine_encode_close,
+ .capabilities = CODEC_CAP_DELAY,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_NONE },
+ .supported_samplerates = libshine_sample_rates,
+ .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ 0 },
+};
diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c
index a26b763688..6ca592aec8 100644
--- a/libavcodec/libspeexdec.c
+++ b/libavcodec/libspeexdec.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2008 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,7 @@ typedef struct LibSpeexContext {
SpeexStereoState stereo;
void *dec_state;
int frame_size;
+ int pktsize;
} LibSpeexContext;
@@ -43,14 +44,30 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx)
SpeexHeader *header = NULL;
int spx_mode;
- avctx->sample_fmt = AV_SAMPLE_FMT_S16;
if (avctx->extradata && avctx->extradata_size >= 80) {
header = speex_packet_to_header(avctx->extradata,
avctx->extradata_size);
if (!header)
av_log(avctx, AV_LOG_WARNING, "Invalid Speex header\n");
}
- if (header) {
+ if (avctx->codec_tag == MKTAG('S', 'P', 'X', 'N')) {
+ int quality;
+ if (!avctx->extradata || avctx->extradata && avctx->extradata_size < 47) {
+ av_log(avctx, AV_LOG_ERROR, "Missing or invalid extradata.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ quality = avctx->extradata[37];
+ if (quality > 10) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported quality mode %d.\n", quality);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ s->pktsize = ((const int[]){5,10,15,20,20,28,28,38,38,46,62})[quality];
+
+ spx_mode = 0;
+ } else if (header) {
+ avctx->sample_rate = header->rate;
avctx->channels = header->nb_channels;
spx_mode = header->mode;
speex_header_free(header);
@@ -73,8 +90,9 @@ static av_cold int libspeex_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", spx_mode);
return AVERROR_INVALIDDATA;
}
- avctx->sample_rate = 8000 << spx_mode;
s->frame_size = 160 << spx_mode;
+ if (!avctx->sample_rate)
+ avctx->sample_rate = 8000 << spx_mode;
if (avctx->channels < 1 || avctx->channels > 2) {
/* libspeex can handle mono or stereo if initialized as stereo */
@@ -113,13 +131,12 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
AVFrame *frame = data;
int16_t *output;
int ret, consumed = 0;
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
/* get output buffer */
frame->nb_samples = s->frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
output = (int16_t *)frame->data[0];
/* if there is not enough data left for the smallest possible frame or the
@@ -133,9 +150,11 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
*got_frame_ptr = 0;
return buf_size;
}
+ if (s->pktsize && buf_size == 62)
+ buf_size = s->pktsize;
/* set new buffer */
speex_bits_read_from(&s->bits, buf, buf_size);
- consumed = buf_size;
+ consumed = avpkt->size;
}
/* decode a single frame */
@@ -149,6 +168,8 @@ static int libspeex_decode_frame(AVCodecContext *avctx, void *data,
*got_frame_ptr = 1;
+ if (!avctx->bit_rate)
+ speex_decoder_ctl(s->dec_state, SPEEX_GET_BITRATE, &avctx->bit_rate);
return consumed;
}
diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c
index ec8882f936..22d0d6ef3d 100644
--- a/libavcodec/libspeexenc.c
+++ b/libavcodec/libspeexenc.c
@@ -2,20 +2,20 @@
* Copyright (C) 2009 Justin Ruggles
* Copyright (c) 2009 Xuggle Incorporated
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -92,6 +92,7 @@
#include "internal.h"
#include "audio_frame_queue.h"
+/* TODO: Think about converting abr, vad, dtx and such flags to a bit field */
typedef struct LibSpeexEncContext {
AVClass *class; ///< AVClass for private options
SpeexBits bits; ///< libspeex bitwriter context
@@ -293,10 +294,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
/* write output if all frames for the packet have been encoded */
if (s->pkt_frame_count == s->frames_per_packet) {
s->pkt_frame_count = 0;
- if ((ret = ff_alloc_packet(avpkt, speex_bits_nbytes(&s->bits)))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, speex_bits_nbytes(&s->bits))) < 0)
return ret;
- }
ret = speex_bits_write(&s->bits, avpkt->data, avpkt->size);
speex_bits_reset(&s->bits);
@@ -335,7 +334,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass speex_class = {
.class_name = "libspeex",
.item_name = av_default_item_name,
.option = options,
@@ -364,6 +363,6 @@ AVCodec ff_libspeex_encoder = {
AV_CH_LAYOUT_STEREO,
0 },
.supported_samplerates = (const int[]){ 8000, 16000, 32000, 0 },
- .priv_class = &class,
+ .priv_class = &speex_class,
.defaults = defaults,
};
diff --git a/libavcodec/libstagefright.cpp b/libavcodec/libstagefright.cpp
new file mode 100644
index 0000000000..44d7ea1492
--- /dev/null
+++ b/libavcodec/libstagefright.cpp
@@ -0,0 +1,590 @@
+/*
+ * Interface to the Android Stagefright library for
+ * H/W accelerated H.264 decoding
+ *
+ * Copyright (C) 2011 Mohamed Naufal
+ * Copyright (C) 2011 Martin Storsjö
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <utils/List.h>
+#include <new>
+#include <map>
+
+extern "C" {
+#include "avcodec.h"
+#include "libavutil/imgutils.h"
+#include "internal.h"
+}
+
+#define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00
+
+using namespace android;
+
+struct Frame {
+ status_t status;
+ size_t size;
+ int64_t time;
+ int key;
+ uint8_t *buffer;
+ AVFrame *vframe;
+};
+
+struct TimeStamp {
+ int64_t pts;
+ int64_t reordered_opaque;
+};
+
+class CustomSource;
+
+struct StagefrightContext {
+ AVCodecContext *avctx;
+ AVBitStreamFilterContext *bsfc;
+ uint8_t* orig_extradata;
+ int orig_extradata_size;
+ sp<MediaSource> *source;
+ List<Frame*> *in_queue, *out_queue;
+ pthread_mutex_t in_mutex, out_mutex;
+ pthread_cond_t condition;
+ pthread_t decode_thread_id;
+
+ Frame *end_frame;
+ bool source_done;
+ volatile sig_atomic_t thread_started, thread_exited, stop_decode;
+
+ AVFrame *prev_frame;
+ std::map<int64_t, TimeStamp> *ts_map;
+ int64_t frame_index;
+
+ uint8_t *dummy_buf;
+ int dummy_bufsize;
+
+ OMXClient *client;
+ sp<MediaSource> *decoder;
+ const char *decoder_component;
+};
+
+class CustomSource : public MediaSource {
+public:
+ CustomSource(AVCodecContext *avctx, sp<MetaData> meta) {
+ s = (StagefrightContext*)avctx->priv_data;
+ source_meta = meta;
+ frame_size = (avctx->width * avctx->height * 3) / 2;
+ buf_group.add_buffer(new MediaBuffer(frame_size));
+ }
+
+ virtual sp<MetaData> getFormat() {
+ return source_meta;
+ }
+
+ virtual status_t start(MetaData *params) {
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
+ }
+
+ virtual status_t read(MediaBuffer **buffer,
+ const MediaSource::ReadOptions *options) {
+ Frame *frame;
+ status_t ret;
+
+ if (s->thread_exited)
+ return ERROR_END_OF_STREAM;
+ pthread_mutex_lock(&s->in_mutex);
+
+ while (s->in_queue->empty())
+ pthread_cond_wait(&s->condition, &s->in_mutex);
+
+ frame = *s->in_queue->begin();
+ ret = frame->status;
+
+ if (ret == OK) {
+ ret = buf_group.acquire_buffer(buffer);
+ if (ret == OK) {
+ memcpy((*buffer)->data(), frame->buffer, frame->size);
+ (*buffer)->set_range(0, frame->size);
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame,frame->key);
+ (*buffer)->meta_data()->setInt64(kKeyTime, frame->time);
+ } else {
+ av_log(s->avctx, AV_LOG_ERROR, "Failed to acquire MediaBuffer\n");
+ }
+ av_freep(&frame->buffer);
+ }
+
+ s->in_queue->erase(s->in_queue->begin());
+ pthread_mutex_unlock(&s->in_mutex);
+
+ av_freep(&frame);
+ return ret;
+ }
+
+private:
+ MediaBufferGroup buf_group;
+ sp<MetaData> source_meta;
+ StagefrightContext *s;
+ int frame_size;
+};
+
+void* decode_thread(void *arg)
+{
+ AVCodecContext *avctx = (AVCodecContext*)arg;
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ Frame* frame;
+ MediaBuffer *buffer;
+ int32_t w, h;
+ int decode_done = 0;
+ int ret;
+ int src_linesize[3];
+ const uint8_t *src_data[3];
+ int64_t out_frame_index = 0;
+
+ do {
+ buffer = NULL;
+ frame = (Frame*)av_mallocz(sizeof(Frame));
+ if (!frame) {
+ frame = s->end_frame;
+ frame->status = AVERROR(ENOMEM);
+ decode_done = 1;
+ s->end_frame = NULL;
+ goto push_frame;
+ }
+ frame->status = (*s->decoder)->read(&buffer);
+ if (frame->status == OK) {
+ sp<MetaData> outFormat = (*s->decoder)->getFormat();
+ outFormat->findInt32(kKeyWidth , &w);
+ outFormat->findInt32(kKeyHeight, &h);
+ frame->vframe = av_frame_alloc();
+ if (!frame->vframe) {
+ frame->status = AVERROR(ENOMEM);
+ decode_done = 1;
+ buffer->release();
+ goto push_frame;
+ }
+ ret = ff_get_buffer(avctx, frame->vframe, AV_GET_BUFFER_FLAG_REF);
+ if (ret < 0) {
+ frame->status = ret;
+ decode_done = 1;
+ buffer->release();
+ goto push_frame;
+ }
+
+ // The OMX.SEC decoder doesn't signal the modified width/height
+ if (s->decoder_component && !strncmp(s->decoder_component, "OMX.SEC", 7) &&
+ (w & 15 || h & 15)) {
+ if (((w + 15)&~15) * ((h + 15)&~15) * 3/2 == buffer->range_length()) {
+ w = (w + 15)&~15;
+ h = (h + 15)&~15;
+ }
+ }
+
+ if (!avctx->width || !avctx->height || avctx->width > w || avctx->height > h) {
+ avctx->width = w;
+ avctx->height = h;
+ }
+
+ src_linesize[0] = av_image_get_linesize(avctx->pix_fmt, w, 0);
+ src_linesize[1] = av_image_get_linesize(avctx->pix_fmt, w, 1);
+ src_linesize[2] = av_image_get_linesize(avctx->pix_fmt, w, 2);
+
+ src_data[0] = (uint8_t*)buffer->data();
+ src_data[1] = src_data[0] + src_linesize[0] * h;
+ src_data[2] = src_data[1] + src_linesize[1] * -(-h>>pix_desc->log2_chroma_h);
+ av_image_copy(frame->vframe->data, frame->vframe->linesize,
+ src_data, src_linesize,
+ avctx->pix_fmt, avctx->width, avctx->height);
+
+ buffer->meta_data()->findInt64(kKeyTime, &out_frame_index);
+ if (out_frame_index && s->ts_map->count(out_frame_index) > 0) {
+ frame->vframe->pts = (*s->ts_map)[out_frame_index].pts;
+ frame->vframe->reordered_opaque = (*s->ts_map)[out_frame_index].reordered_opaque;
+ s->ts_map->erase(out_frame_index);
+ }
+ buffer->release();
+ } else if (frame->status == INFO_FORMAT_CHANGED) {
+ if (buffer)
+ buffer->release();
+ av_free(frame);
+ continue;
+ } else {
+ decode_done = 1;
+ }
+push_frame:
+ while (true) {
+ pthread_mutex_lock(&s->out_mutex);
+ if (s->out_queue->size() >= 10) {
+ pthread_mutex_unlock(&s->out_mutex);
+ usleep(10000);
+ continue;
+ }
+ break;
+ }
+ s->out_queue->push_back(frame);
+ pthread_mutex_unlock(&s->out_mutex);
+ } while (!decode_done && !s->stop_decode);
+
+ s->thread_exited = true;
+
+ return 0;
+}
+
+static av_cold int Stagefright_init(AVCodecContext *avctx)
+{
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ sp<MetaData> meta, outFormat;
+ int32_t colorFormat = 0;
+ int ret;
+
+ if (!avctx->extradata || !avctx->extradata_size || avctx->extradata[0] != 1)
+ return -1;
+
+ s->avctx = avctx;
+ s->bsfc = av_bitstream_filter_init("h264_mp4toannexb");
+ if (!s->bsfc) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot open the h264_mp4toannexb BSF!\n");
+ return -1;
+ }
+
+ s->orig_extradata_size = avctx->extradata_size;
+ s->orig_extradata = (uint8_t*) av_mallocz(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!s->orig_extradata) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ memcpy(s->orig_extradata, avctx->extradata, avctx->extradata_size);
+
+ meta = new MetaData;
+ if (!meta) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ meta->setInt32(kKeyWidth, avctx->width);
+ meta->setInt32(kKeyHeight, avctx->height);
+ meta->setData(kKeyAVCC, kTypeAVCC, avctx->extradata, avctx->extradata_size);
+
+ android::ProcessState::self()->startThreadPool();
+
+ s->source = new sp<MediaSource>();
+ *s->source = new CustomSource(avctx, meta);
+ s->in_queue = new List<Frame*>;
+ s->out_queue = new List<Frame*>;
+ s->ts_map = new std::map<int64_t, TimeStamp>;
+ s->client = new OMXClient;
+ s->end_frame = (Frame*)av_mallocz(sizeof(Frame));
+ if (s->source == NULL || !s->in_queue || !s->out_queue || !s->client ||
+ !s->ts_map || !s->end_frame) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (s->client->connect() != OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot connect OMX client\n");
+ ret = -1;
+ goto fail;
+ }
+
+ s->decoder = new sp<MediaSource>();
+ *s->decoder = OMXCodec::Create(s->client->interface(), meta,
+ false, *s->source, NULL,
+ OMXCodec::kClientNeedsFramebuffer);
+ if ((*s->decoder)->start() != OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot start decoder\n");
+ ret = -1;
+ s->client->disconnect();
+ goto fail;
+ }
+
+ outFormat = (*s->decoder)->getFormat();
+ outFormat->findInt32(kKeyColorFormat, &colorFormat);
+ if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar ||
+ colorFormat == OMX_COLOR_FormatYUV420SemiPlanar)
+ avctx->pix_fmt = AV_PIX_FMT_NV21;
+ else if (colorFormat == OMX_COLOR_FormatYCbYCr)
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+ else if (colorFormat == OMX_COLOR_FormatCbYCrY)
+ avctx->pix_fmt = AV_PIX_FMT_UYVY422;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
+ outFormat->findCString(kKeyDecoderComponent, &s->decoder_component);
+ if (s->decoder_component)
+ s->decoder_component = av_strdup(s->decoder_component);
+
+ pthread_mutex_init(&s->in_mutex, NULL);
+ pthread_mutex_init(&s->out_mutex, NULL);
+ pthread_cond_init(&s->condition, NULL);
+ return 0;
+
+fail:
+ av_bitstream_filter_close(s->bsfc);
+ av_freep(&s->orig_extradata);
+ av_freep(&s->end_frame);
+ delete s->in_queue;
+ delete s->out_queue;
+ delete s->ts_map;
+ delete s->client;
+ return ret;
+}
+
+static int Stagefright_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ Frame *frame;
+ status_t status;
+ int orig_size = avpkt->size;
+ AVPacket pkt = *avpkt;
+ AVFrame *ret_frame;
+
+ if (!s->thread_started) {
+ pthread_create(&s->decode_thread_id, NULL, &decode_thread, avctx);
+ s->thread_started = true;
+ }
+
+ if (avpkt && avpkt->data) {
+ av_bitstream_filter_filter(s->bsfc, avctx, NULL, &pkt.data, &pkt.size,
+ avpkt->data, avpkt->size, avpkt->flags & AV_PKT_FLAG_KEY);
+ avpkt = &pkt;
+ }
+
+ if (!s->source_done) {
+ if(!s->dummy_buf) {
+ s->dummy_buf = (uint8_t*)av_malloc(avpkt->size);
+ if (!s->dummy_buf)
+ return AVERROR(ENOMEM);
+ s->dummy_bufsize = avpkt->size;
+ memcpy(s->dummy_buf, avpkt->data, avpkt->size);
+ }
+
+ frame = (Frame*)av_mallocz(sizeof(Frame));
+ if (avpkt->data) {
+ frame->status = OK;
+ frame->size = avpkt->size;
+ frame->key = avpkt->flags & AV_PKT_FLAG_KEY ? 1 : 0;
+ frame->buffer = (uint8_t*)av_malloc(avpkt->size);
+ if (!frame->buffer) {
+ av_freep(&frame);
+ return AVERROR(ENOMEM);
+ }
+ uint8_t *ptr = avpkt->data;
+ // The OMX.SEC decoder fails without this.
+ if (avpkt->size == orig_size + avctx->extradata_size) {
+ ptr += avctx->extradata_size;
+ frame->size = orig_size;
+ }
+ memcpy(frame->buffer, ptr, orig_size);
+ if (avpkt == &pkt)
+ av_free(avpkt->data);
+
+ frame->time = ++s->frame_index;
+ (*s->ts_map)[s->frame_index].pts = avpkt->pts;
+ (*s->ts_map)[s->frame_index].reordered_opaque = avctx->reordered_opaque;
+ } else {
+ frame->status = ERROR_END_OF_STREAM;
+ s->source_done = true;
+ }
+
+ while (true) {
+ if (s->thread_exited) {
+ s->source_done = true;
+ break;
+ }
+ pthread_mutex_lock(&s->in_mutex);
+ if (s->in_queue->size() >= 10) {
+ pthread_mutex_unlock(&s->in_mutex);
+ usleep(10000);
+ continue;
+ }
+ s->in_queue->push_back(frame);
+ pthread_cond_signal(&s->condition);
+ pthread_mutex_unlock(&s->in_mutex);
+ break;
+ }
+ }
+ while (true) {
+ pthread_mutex_lock(&s->out_mutex);
+ if (!s->out_queue->empty()) break;
+ pthread_mutex_unlock(&s->out_mutex);
+ if (s->source_done) {
+ usleep(10000);
+ continue;
+ } else {
+ return orig_size;
+ }
+ }
+
+ frame = *s->out_queue->begin();
+ s->out_queue->erase(s->out_queue->begin());
+ pthread_mutex_unlock(&s->out_mutex);
+
+ ret_frame = frame->vframe;
+ status = frame->status;
+ av_freep(&frame);
+
+ if (status == ERROR_END_OF_STREAM)
+ return 0;
+ if (status != OK) {
+ if (status == AVERROR(ENOMEM))
+ return status;
+ av_log(avctx, AV_LOG_ERROR, "Decode failed: %x\n", status);
+ return -1;
+ }
+
+ if (s->prev_frame)
+ av_frame_free(&s->prev_frame);
+ s->prev_frame = ret_frame;
+
+ *got_frame = 1;
+ *(AVFrame*)data = *ret_frame;
+ return orig_size;
+}
+
+static av_cold int Stagefright_close(AVCodecContext *avctx)
+{
+ StagefrightContext *s = (StagefrightContext*)avctx->priv_data;
+ Frame *frame;
+
+ if (s->thread_started) {
+ if (!s->thread_exited) {
+ s->stop_decode = 1;
+
+ // Make sure decode_thread() doesn't get stuck
+ pthread_mutex_lock(&s->out_mutex);
+ while (!s->out_queue->empty()) {
+ frame = *s->out_queue->begin();
+ s->out_queue->erase(s->out_queue->begin());
+ if (frame->vframe)
+ av_frame_free(&frame->vframe);
+ av_freep(&frame);
+ }
+ pthread_mutex_unlock(&s->out_mutex);
+
+ // Feed a dummy frame prior to signalling EOF.
+ // This is required to terminate the decoder(OMX.SEC)
+ // when only one frame is read during stream info detection.
+ if (s->dummy_buf && (frame = (Frame*)av_mallocz(sizeof(Frame)))) {
+ frame->status = OK;
+ frame->size = s->dummy_bufsize;
+ frame->key = 1;
+ frame->buffer = s->dummy_buf;
+ pthread_mutex_lock(&s->in_mutex);
+ s->in_queue->push_back(frame);
+ pthread_cond_signal(&s->condition);
+ pthread_mutex_unlock(&s->in_mutex);
+ s->dummy_buf = NULL;
+ }
+
+ pthread_mutex_lock(&s->in_mutex);
+ s->end_frame->status = ERROR_END_OF_STREAM;
+ s->in_queue->push_back(s->end_frame);
+ pthread_cond_signal(&s->condition);
+ pthread_mutex_unlock(&s->in_mutex);
+ s->end_frame = NULL;
+ }
+
+ pthread_join(s->decode_thread_id, NULL);
+
+ if (s->prev_frame)
+ av_frame_free(&s->prev_frame);
+
+ s->thread_started = false;
+ }
+
+ while (!s->in_queue->empty()) {
+ frame = *s->in_queue->begin();
+ s->in_queue->erase(s->in_queue->begin());
+ if (frame->size)
+ av_freep(&frame->buffer);
+ av_freep(&frame);
+ }
+
+ while (!s->out_queue->empty()) {
+ frame = *s->out_queue->begin();
+ s->out_queue->erase(s->out_queue->begin());
+ if (frame->vframe)
+ av_frame_free(&frame->vframe);
+ av_freep(&frame);
+ }
+
+ (*s->decoder)->stop();
+ s->client->disconnect();
+
+ if (s->decoder_component)
+ av_freep(&s->decoder_component);
+ av_freep(&s->dummy_buf);
+ av_freep(&s->end_frame);
+
+ // Reset the extradata back to the original mp4 format, so that
+ // the next invocation (both when decoding and when called from
+ // av_find_stream_info) get the original mp4 format extradata.
+ av_freep(&avctx->extradata);
+ avctx->extradata = s->orig_extradata;
+ avctx->extradata_size = s->orig_extradata_size;
+
+ delete s->in_queue;
+ delete s->out_queue;
+ delete s->ts_map;
+ delete s->client;
+ delete s->decoder;
+ delete s->source;
+
+ pthread_mutex_destroy(&s->in_mutex);
+ pthread_mutex_destroy(&s->out_mutex);
+ pthread_cond_destroy(&s->condition);
+ av_bitstream_filter_close(s->bsfc);
+ return 0;
+}
+
+AVCodec ff_libstagefright_h264_decoder = {
+ "libstagefright_h264",
+ NULL_IF_CONFIG_SMALL("libstagefright H.264"),
+ AVMEDIA_TYPE_VIDEO,
+ AV_CODEC_ID_H264,
+ CODEC_CAP_DELAY,
+ NULL, //supported_framerates
+ NULL, //pix_fmts
+ NULL, //supported_samplerates
+ NULL, //sample_fmts
+ NULL, //channel_layouts
+ 0, //max_lowres
+ NULL, //priv_class
+ NULL, //profiles
+ sizeof(StagefrightContext),
+ NULL, //next
+ NULL, //init_thread_copy
+ NULL, //update_thread_context
+ NULL, //defaults
+ NULL, //init_static_data
+ Stagefright_init,
+ NULL, //encode
+ NULL, //encode2
+ Stagefright_decode_frame,
+ Stagefright_close,
+};
diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c
index 462bc942ce..e6b1cbd2ed 100644
--- a/libavcodec/libtheoraenc.c
+++ b/libavcodec/libtheoraenc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Paul Richards <paul.richards@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,7 @@
* and o_ prefixes on variables which are libogg types.
*/
-/* Libav includes */
+/* FFmpeg includes */
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/pixdesc.h"
@@ -96,11 +96,14 @@ static int get_stats(AVCodecContext *avctx, int eos)
bytes = th_encode_ctl(h->t_state, TH_ENCCTL_2PASS_OUT, &buf, sizeof(buf));
if (bytes < 0) {
av_log(avctx, AV_LOG_ERROR, "Error getting first pass stats\n");
- return -1;
+ return AVERROR_EXTERNAL;
}
if (!eos) {
- h->stats = av_fast_realloc(h->stats, &h->stats_size,
+ void *tmp = av_fast_realloc(h->stats, &h->stats_size,
h->stats_offset + bytes);
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ h->stats = tmp;
memcpy(h->stats + h->stats_offset, buf, bytes);
h->stats_offset += bytes;
} else {
@@ -108,12 +111,14 @@ static int get_stats(AVCodecContext *avctx, int eos)
// libtheora generates a summary header at the end
memcpy(h->stats, buf, bytes);
avctx->stats_out = av_malloc(b64_size);
+ if (!avctx->stats_out)
+ return AVERROR(ENOMEM);
av_base64_encode(avctx->stats_out, b64_size, h->stats, h->stats_offset);
}
return 0;
#else
av_log(avctx, AV_LOG_ERROR, "libtheora too old to support 2pass\n");
- return -1;
+ return AVERROR(ENOSUP);
#endif
}
@@ -127,10 +132,14 @@ static int submit_stats(AVCodecContext *avctx)
if (!h->stats) {
if (!avctx->stats_in) {
av_log(avctx, AV_LOG_ERROR, "No statsfile for second pass\n");
- return -1;
+ return AVERROR(EINVAL);
}
h->stats_size = strlen(avctx->stats_in) * 3/4;
h->stats = av_malloc(h->stats_size);
+ if (!h->stats) {
+ h->stats_size = 0;
+ return AVERROR(ENOMEM);
+ }
h->stats_size = av_base64_decode(h->stats, avctx->stats_in, h->stats_size);
}
while (h->stats_size - h->stats_offset > 0) {
@@ -139,7 +148,7 @@ static int submit_stats(AVCodecContext *avctx)
h->stats_size - h->stats_offset);
if (bytes < 0) {
av_log(avctx, AV_LOG_ERROR, "Error submitting stats\n");
- return -1;
+ return AVERROR_EXTERNAL;
}
if (!bytes)
return 0;
@@ -148,7 +157,7 @@ static int submit_stats(AVCodecContext *avctx)
return 0;
#else
av_log(avctx, AV_LOG_ERROR, "libtheora too old to support 2pass\n");
- return -1;
+ return AVERROR(ENOSUP);
#endif
}
@@ -160,6 +169,7 @@ static av_cold int encode_init(AVCodecContext* avc_context)
unsigned int offset;
TheoraContext *h = avc_context->priv_data;
uint32_t gop_size = avc_context->gop_size;
+ int ret;
/* Set up the theora_info struct */
th_info_init(&t_info);
@@ -196,17 +206,16 @@ static av_cold int encode_init(AVCodecContext* avc_context)
t_info.pixel_fmt = TH_PF_444;
else {
av_log(avc_context, AV_LOG_ERROR, "Unsupported pix_fmt\n");
- return -1;
+ return AVERROR(EINVAL);
}
- av_pix_fmt_get_chroma_sub_sample(avc_context->pix_fmt,
- &h->uv_hshift, &h->uv_vshift);
+ avcodec_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift);
if (avc_context->flags & CODEC_FLAG_QSCALE) {
- /* to be constant with the libvorbis implementation, clip global_quality to 0 - 10
- Theora accepts a quality parameter p, which is:
- * 0 <= p <=63
- * an int value
- */
+ /* Clip global_quality in QP units to the [0 - 10] range
+ to be consistent with the libvorbis implementation.
+ Theora accepts a quality parameter which is an int value in
+ the [0 - 63] range.
+ */
t_info.quality = av_clipf(avc_context->global_quality / (float)FF_QP2LAMBDA, 0, 10) * 6.3;
t_info.target_bitrate = 0;
} else {
@@ -218,7 +227,7 @@ static av_cold int encode_init(AVCodecContext* avc_context)
h->t_state = th_encode_alloc(&t_info);
if (!h->t_state) {
av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n");
- return -1;
+ return AVERROR_EXTERNAL;
}
h->keyframe_mask = (1 << t_info.keyframe_granule_shift) - 1;
@@ -228,16 +237,16 @@ static av_cold int encode_init(AVCodecContext* avc_context)
if (th_encode_ctl(h->t_state, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
&gop_size, sizeof(gop_size))) {
av_log(avc_context, AV_LOG_ERROR, "Error setting GOP size\n");
- return -1;
+ return AVERROR_EXTERNAL;
}
// need to enable 2 pass (via TH_ENCCTL_2PASS_) before encoding headers
if (avc_context->flags & CODEC_FLAG_PASS1) {
- if (get_stats(avc_context, 0))
- return -1;
+ if ((ret = get_stats(avc_context, 0)) < 0)
+ return ret;
} else if (avc_context->flags & CODEC_FLAG_PASS2) {
- if (submit_stats(avc_context))
- return -1;
+ if ((ret = submit_stats(avc_context)) < 0)
+ return ret;
}
/*
@@ -253,8 +262,8 @@ static av_cold int encode_init(AVCodecContext* avc_context)
th_comment_init(&t_comment);
while (th_encode_flushheader(h->t_state, &t_comment, &o_packet))
- if (concatenate_packet(&offset, avc_context, &o_packet))
- return -1;
+ if ((ret = concatenate_packet(&offset, avc_context, &o_packet)) < 0)
+ return ret;
th_comment_clear(&t_comment);
@@ -278,8 +287,8 @@ static int encode_frame(AVCodecContext* avc_context, AVPacket *pkt,
if (!frame) {
th_encode_packetout(h->t_state, 1, &o_packet);
if (avc_context->flags & CODEC_FLAG_PASS1)
- if (get_stats(avc_context, 1))
- return -1;
+ if ((ret = get_stats(avc_context, 1)) < 0)
+ return ret;
return 0;
}
@@ -292,8 +301,8 @@ static int encode_frame(AVCodecContext* avc_context, AVPacket *pkt,
}
if (avc_context->flags & CODEC_FLAG_PASS2)
- if (submit_stats(avc_context))
- return -1;
+ if ((ret = submit_stats(avc_context)) < 0)
+ return ret;
/* Now call into theora_encode_YUVin */
result = th_encode_ycbcr_in(h->t_state, t_yuv_buffer);
@@ -311,12 +320,12 @@ static int encode_frame(AVCodecContext* avc_context, AVPacket *pkt,
break;
}
av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result);
- return -1;
+ return AVERROR_EXTERNAL;
}
if (avc_context->flags & CODEC_FLAG_PASS1)
- if (get_stats(avc_context, 0))
- return -1;
+ if ((ret = get_stats(avc_context, 0)) < 0)
+ return ret;
/* Pick up returned ogg_packet */
result = th_encode_packetout(h->t_state, 0, &o_packet);
@@ -329,14 +338,12 @@ static int encode_frame(AVCodecContext* avc_context, AVPacket *pkt,
break;
default:
av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed [%d]\n", result);
- return -1;
+ return AVERROR_EXTERNAL;
}
/* Copy ogg_packet content out to buffer */
- if ((ret = ff_alloc_packet(pkt, o_packet.bytes)) < 0) {
- av_log(avc_context, AV_LOG_ERROR, "Error getting output packet of size %ld.\n", o_packet.bytes);
+ if ((ret = ff_alloc_packet2(avc_context, pkt, o_packet.bytes)) < 0)
return ret;
- }
memcpy(pkt->data, o_packet.packet, o_packet.bytes);
// HACK: assumes no encoder delay, this is true until libtheora becomes
@@ -356,7 +363,7 @@ static av_cold int encode_close(AVCodecContext* avc_context)
th_encode_free(h->t_state);
av_freep(&h->stats);
- av_freep(&avc_context->coded_frame);
+ av_frame_free(&avc_context->coded_frame);
av_freep(&avc_context->stats_out);
av_freep(&avc_context->extradata);
avc_context->extradata_size = 0;
diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c
index ce3294126a..dc188575b5 100644
--- a/libavcodec/libtwolame.c
+++ b/libavcodec/libtwolame.c
@@ -2,20 +2,20 @@
* Interface to libtwolame for mp2 encoding
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -77,6 +77,10 @@ static av_cold int twolame_encode_init(AVCodecContext *avctx)
twolame_set_num_channels(s->glopts, avctx->channels);
twolame_set_in_samplerate(s->glopts, avctx->sample_rate);
twolame_set_out_samplerate(s->glopts, avctx->sample_rate);
+
+ if (!avctx->bit_rate)
+ avctx->bit_rate = avctx->sample_rate < 28000 ? 160000 : 384000;
+
if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) {
twolame_set_VBR(s->glopts, TRUE);
twolame_set_VBR_level(s->glopts,
@@ -102,7 +106,7 @@ static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
TWOLAMEContext *s = avctx->priv_data;
int ret;
- if ((ret = ff_alloc_packet(avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0)
+ if ((ret = ff_alloc_packet2(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0)
return ret;
if (frame) {
@@ -190,7 +194,7 @@ static const AVClass twolame_class = {
};
static const AVCodecDefault twolame_defaults[] = {
- { "b", "384000" },
+ { "b", "0" },
{ NULL },
};
diff --git a/libavcodec/libutvideo.h b/libavcodec/libutvideo.h
new file mode 100644
index 0000000000..5fb1174c84
--- /dev/null
+++ b/libavcodec/libutvideo.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2011-2012 Derek Buitenhuis
+ *
+ * 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;
+ * version 2 of the License.
+ *
+ * FFmpeg is distributed in the hope that 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
+ * Known FOURCCs:
+ * 'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA),
+ * 'ULH0' (YCbCr 4:2:0 BT.709), 'ULH2' (YCbCr 4:2:2 BT.709)
+ */
+
+#ifndef AVCODEC_LIBUTVIDEO_H
+#define AVCODEC_LIBUTVIDEO_H
+
+#include <stdlib.h>
+#include <utvideo/utvideo.h>
+#include <utvideo/Codec.h>
+
+/*
+ * Ut Video version 12.0.0 changed the RGB format names and removed
+ * the _WIN names, so if the new names are absent, define them
+ * against the old names so compatibility with pre-v12 versions
+ * is maintained.
+ */
+#if !defined(UTVF_NFCC_BGR_BU)
+#define UTVF_NFCC_BGR_BU UTVF_RGB24_WIN
+#endif
+
+#if !defined(UTVF_NFCC_BGRA_BU)
+#define UTVF_NFCC_BGRA_BU UTVF_RGB32_WIN
+#endif
+
+/*
+ * Ut Video version 13.0.1 introduced new BT.709 variants.
+ * Special-case these and only use them if v13 is detected.
+ */
+#if defined(UTVF_HDYC)
+#define UTV_BT709
+#endif
+
+typedef struct {
+ uint32_t version;
+ uint32_t original_format;
+ uint32_t frameinfo_size;
+ uint32_t flags;
+} UtVideoExtra;
+
+typedef struct {
+ CCodec *codec;
+ unsigned int buf_size;
+ uint8_t *buffer;
+} UtVideoContext;
+
+#endif /* AVCODEC_LIBUTVIDEO_H */
diff --git a/libavcodec/libutvideodec.cpp b/libavcodec/libutvideodec.cpp
new file mode 100644
index 0000000000..e4b87a8bbc
--- /dev/null
+++ b/libavcodec/libutvideodec.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2011 Derek Buitenhuis
+ *
+ * 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;
+ * version 2 of the License.
+ *
+ * FFmpeg is distributed in the hope that 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
+ * Known FOURCCs:
+ * 'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA),
+ * 'ULH0' (YCbCr 4:2:0 BT.709), 'ULH2' (YCbCr 4:2:2 BT.709)
+ */
+
+extern "C" {
+#include "avcodec.h"
+}
+
+#include "libutvideo.h"
+#include "get_bits.h"
+
+static av_cold int utvideo_decode_init(AVCodecContext *avctx)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+ UtVideoExtra info;
+ int format;
+ int begin_ret;
+
+ if (avctx->extradata_size != 16 && avctx->extradata_size != 8 ) {
+ av_log(avctx, AV_LOG_ERROR, "Extradata size (%d) mismatch.\n", avctx->extradata_size);
+ return -1;
+ }
+
+ /* Read extradata */
+ info.version = AV_RL32(avctx->extradata);
+ info.original_format = AV_RL32(avctx->extradata + 4);
+ info.frameinfo_size = AV_RL32(avctx->extradata + 8);
+ info.flags = AV_RL32(avctx->extradata + 12);
+
+ /* Pick format based on FOURCC */
+ switch (avctx->codec_tag) {
+#ifdef UTV_BT709
+ case MKTAG('U', 'L', 'H', '0'):
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ avctx->colorspace = AVCOL_SPC_BT709;
+ format = UTVF_YV12;
+ break;
+ case MKTAG('U', 'L', 'H', '2'):
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+ avctx->colorspace = AVCOL_SPC_BT709;
+ format = UTVF_YUY2;
+ break;
+#endif
+ case MKTAG('U', 'L', 'Y', '0'):
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ format = UTVF_YV12;
+ break;
+ case MKTAG('U', 'L', 'Y', '2'):
+ avctx->pix_fmt = AV_PIX_FMT_YUYV422;
+ format = UTVF_YUY2;
+ break;
+ case MKTAG('U', 'L', 'R', 'G'):
+ avctx->pix_fmt = AV_PIX_FMT_BGR24;
+ format = UTVF_NFCC_BGR_BU;
+ break;
+ case MKTAG('U', 'L', 'R', 'A'):
+ avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ format = UTVF_NFCC_BGRA_BU;
+ break;
+#ifdef UTVF_UQY2
+ case MKTAG('U', 'Q', 'Y', '2'):
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
+ format = UTVF_v210;
+ break;
+#endif
+ default:
+ av_log(avctx, AV_LOG_ERROR,
+ "Not a Ut Video FOURCC: %X\n", avctx->codec_tag);
+ return -1;
+ }
+
+ /* Only allocate the buffer once */
+ utv->buf_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
+#ifdef UTVF_UQY2
+ if (format == UTVF_v210)
+ utv->buf_size += avctx->height * ((avctx->width + 47) / 48) * 128; // the linesize used by the decoder, this does not seem to be exported
+#endif
+ utv->buffer = (uint8_t *)av_malloc(utv->buf_size * sizeof(uint8_t));
+
+ if (utv->buffer == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to allocate output buffer.\n");
+ return -1;
+ }
+
+ /* Allocate the output frame */
+ avctx->coded_frame = av_frame_alloc();
+
+ /* Ut Video only supports 8-bit */
+ avctx->bits_per_raw_sample = 8;
+
+ /* Is it interlaced? */
+ avctx->coded_frame->interlaced_frame = info.flags & 0x800 ? 1 : 0;
+
+ /* Apparently Ut Video doesn't store this info... */
+ avctx->coded_frame->top_field_first = 1;
+
+ /*
+ * Create a Ut Video instance. Since the function wants
+ * an "interface name" string, pass it the name of the lib.
+ */
+ utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec");
+
+ /* Initialize Decoding */
+ begin_ret = utv->codec->DecodeBegin(format, avctx->width, avctx->height,
+ CBGROSSWIDTH_WINDOWS, &info, sizeof(UtVideoExtra));
+
+ /* Check to see if the decoder initlized properly */
+ if (begin_ret != 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not initialize decoder: %d\n", begin_ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int utvideo_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+ AVFrame *pic = avctx->coded_frame;
+ int w = avctx->width, h = avctx->height;
+
+ /* Set flags */
+ pic->reference = 0;
+ pic->pict_type = AV_PICTURE_TYPE_I;
+ pic->key_frame = 1;
+
+ /* Decode the frame */
+ utv->codec->DecodeFrame(utv->buffer, avpkt->data, true);
+
+ /* Set the output data depending on the colorspace */
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUV420P:
+ pic->linesize[0] = w;
+ pic->linesize[1] = pic->linesize[2] = w / 2;
+ pic->data[0] = utv->buffer;
+ pic->data[2] = utv->buffer + (w * h);
+ pic->data[1] = pic->data[2] + (w * h / 4);
+ break;
+ case AV_PIX_FMT_YUYV422:
+ pic->linesize[0] = w * 2;
+ pic->data[0] = utv->buffer;
+ break;
+ case AV_PIX_FMT_YUV422P10: {
+ uint16_t *y, *u, *v;
+ int i,j;
+ int linesize = ((w + 47) / 48) * 128;
+
+ pic->linesize[0] = w * 2;
+ pic->linesize[1] =
+ pic->linesize[2] = w;
+ pic->data[0] = utv->buffer + linesize * h;
+ pic->data[1] = pic->data[0] + h*pic->linesize[0];
+ pic->data[2] = pic->data[1] + h*pic->linesize[1];
+ y = (uint16_t*)pic->data[0];
+ u = (uint16_t*)pic->data[1];
+ v = (uint16_t*)pic->data[2];
+ for (j = 0; j < h; j++) {
+ const uint8_t *in = utv->buffer + j * linesize;
+
+ for (i = 0; i + 1 < w; i += 6, in += 4) {
+ unsigned a,b;
+ a = AV_RL32(in);
+ in += 4;
+ b = AV_RL32(in);
+ *u++ = (a ) & 0x3FF;
+ *y++ = (a>>10) & 0x3FF;
+ *v++ = (a>>20) & 0x3FF;
+ *y++ = (b ) & 0x3FF;
+
+ if (i + 3 >= w)
+ break;
+
+ in += 4;
+ a = AV_RL32(in);
+ *u++ = (b>>10) & 0x3FF;
+ *y++ = (b>>20) & 0x3FF;
+ *v++ = (a ) & 0x3FF;
+ *y++ = (a>>10) & 0x3FF;
+
+ if (i + 5 >= w)
+ break;
+
+ in += 4;
+ b = AV_RL32(in);
+ *u++ = (a>>20) & 0x3FF;
+ *y++ = (b ) & 0x3FF;
+ *v++ = (b>>10) & 0x3FF;
+ *y++ = (b>>20) & 0x3FF;
+ }
+ }
+ break;
+ }
+ case AV_PIX_FMT_BGR24:
+ case AV_PIX_FMT_RGB32:
+ /* Make the linesize negative, since Ut Video uses bottom-up BGR */
+ pic->linesize[0] = -1 * w * (avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4);
+ pic->data[0] = utv->buffer + utv->buf_size + pic->linesize[0];
+ break;
+ }
+
+ *got_frame = 1;
+ av_frame_move_ref((AVFrame*)data, pic);
+
+ return avpkt->size;
+}
+
+static av_cold int utvideo_decode_close(AVCodecContext *avctx)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+
+ /* Free output */
+ av_frame_free(&avctx->coded_frame);
+ av_freep(&utv->buffer);
+
+ /* Finish decoding and clean up the instance */
+ utv->codec->DecodeEnd();
+ CCodec::DeleteInstance(utv->codec);
+
+ return 0;
+}
+
+AVCodec ff_libutvideo_decoder = {
+ "libutvideo",
+ NULL_IF_CONFIG_SMALL("Ut Video"),
+ AVMEDIA_TYPE_VIDEO,
+ AV_CODEC_ID_UTVIDEO,
+ 0, //capabilities
+ NULL, //supported_framerates
+ NULL, //pix_fmts
+ NULL, //supported_samplerates
+ NULL, //sample_fmts
+ NULL, //channel_layouts
+ 0, //max_lowres
+ NULL, //priv_class
+ NULL, //profiles
+ sizeof(UtVideoContext),
+ NULL, //next
+ NULL, //init_thread_copy
+ NULL, //update_thread_context
+ NULL, //defaults
+ NULL, //init_static_data
+ utvideo_decode_init,
+ NULL, //encode
+ NULL, //encode2
+ utvideo_decode_frame,
+ utvideo_decode_close,
+};
diff --git a/libavcodec/libutvideoenc.cpp b/libavcodec/libutvideoenc.cpp
new file mode 100644
index 0000000000..cf669d28a0
--- /dev/null
+++ b/libavcodec/libutvideoenc.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2012 Derek Buitenhuis
+ *
+ * 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;
+ * version 2 of the License.
+ *
+ * FFmpeg is distributed in the hope that 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
+ * Known FOURCCs:
+ * 'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA),
+ * 'ULH0' (YCbCr 4:2:0 BT.709), 'ULH2' (YCbCr 4:2:2 BT.709)
+ */
+
+extern "C" {
+#include "libavutil/avassert.h"
+#include "avcodec.h"
+#include "internal.h"
+}
+
+#include "libutvideo.h"
+#include "put_bits.h"
+
+static av_cold int utvideo_encode_init(AVCodecContext *avctx)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+ UtVideoExtra *info;
+ uint32_t flags, in_format;
+ int ret;
+
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUV420P:
+ in_format = UTVF_YV12;
+ avctx->bits_per_coded_sample = 12;
+ if (avctx->colorspace == AVCOL_SPC_BT709)
+ avctx->codec_tag = MKTAG('U', 'L', 'H', '0');
+ else
+ avctx->codec_tag = MKTAG('U', 'L', 'Y', '0');
+ break;
+ case AV_PIX_FMT_YUYV422:
+ in_format = UTVF_YUYV;
+ avctx->bits_per_coded_sample = 16;
+ if (avctx->colorspace == AVCOL_SPC_BT709)
+ avctx->codec_tag = MKTAG('U', 'L', 'H', '2');
+ else
+ avctx->codec_tag = MKTAG('U', 'L', 'Y', '2');
+ break;
+ case AV_PIX_FMT_BGR24:
+ in_format = UTVF_NFCC_BGR_BU;
+ avctx->bits_per_coded_sample = 24;
+ avctx->codec_tag = MKTAG('U', 'L', 'R', 'G');
+ break;
+ case AV_PIX_FMT_RGB32:
+ in_format = UTVF_NFCC_BGRA_BU;
+ avctx->bits_per_coded_sample = 32;
+ avctx->codec_tag = MKTAG('U', 'L', 'R', 'A');
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ /* Check before we alloc anything */
+ if (avctx->prediction_method != 0 && avctx->prediction_method != 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid prediction method.\n");
+ return AVERROR(EINVAL);
+ }
+
+ flags = ((avctx->prediction_method + 1) << 8) | (avctx->thread_count - 1);
+
+ avctx->priv_data = utv;
+ avctx->coded_frame = av_frame_alloc();
+
+ /* Alloc extradata buffer */
+ info = (UtVideoExtra *)av_malloc(sizeof(*info));
+
+ if (!info) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata buffer.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ /*
+ * We use this buffer to hold the data that Ut Video returns,
+ * since we cannot decode planes separately with it.
+ */
+ ret = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
+ if (ret < 0) {
+ av_free(info);
+ return ret;
+ }
+ utv->buf_size = ret;
+
+ utv->buffer = (uint8_t *)av_malloc(utv->buf_size);
+
+ if (utv->buffer == NULL) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate output buffer.\n");
+ av_free(info);
+ return AVERROR(ENOMEM);
+ }
+
+ /*
+ * Create a Ut Video instance. Since the function wants
+ * an "interface name" string, pass it the name of the lib.
+ */
+ utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec");
+
+ /* Initialize encoder */
+ utv->codec->EncodeBegin(in_format, avctx->width, avctx->height,
+ CBGROSSWIDTH_WINDOWS);
+
+ /* Get extradata from encoder */
+ avctx->extradata_size = utv->codec->EncodeGetExtraDataSize();
+ utv->codec->EncodeGetExtraData(info, avctx->extradata_size, in_format,
+ avctx->width, avctx->height,
+ CBGROSSWIDTH_WINDOWS);
+ avctx->extradata = (uint8_t *)info;
+
+ /* Set flags */
+ utv->codec->SetState(&flags, sizeof(flags));
+
+ return 0;
+}
+
+static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+ int w = avctx->width, h = avctx->height;
+ int ret, rgb_size, i;
+ bool keyframe;
+ uint8_t *y, *u, *v;
+ uint8_t *dst;
+
+ /* Alloc buffer */
+ if ((ret = ff_alloc_packet2(avctx, pkt, utv->buf_size)) < 0)
+ return ret;
+
+ dst = pkt->data;
+
+ /* Move input if needed data into Ut Video friendly buffer */
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUV420P:
+ y = utv->buffer;
+ u = y + w * h;
+ v = u + w * h / 4;
+ for (i = 0; i < h; i++) {
+ memcpy(y, pic->data[0] + i * pic->linesize[0], w);
+ y += w;
+ }
+ for (i = 0; i < h / 2; i++) {
+ memcpy(u, pic->data[2] + i * pic->linesize[2], w >> 1);
+ memcpy(v, pic->data[1] + i * pic->linesize[1], w >> 1);
+ u += w >> 1;
+ v += w >> 1;
+ }
+ break;
+ case AV_PIX_FMT_YUYV422:
+ for (i = 0; i < h; i++)
+ memcpy(utv->buffer + i * (w << 1),
+ pic->data[0] + i * pic->linesize[0], w << 1);
+ break;
+ case AV_PIX_FMT_BGR24:
+ case AV_PIX_FMT_RGB32:
+ /* Ut Video takes bottom-up BGR */
+ rgb_size = avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4;
+ for (i = 0; i < h; i++)
+ memcpy(utv->buffer + (h - i - 1) * w * rgb_size,
+ pic->data[0] + i * pic->linesize[0],
+ w * rgb_size);
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ /* Encode frame */
+ pkt->size = utv->codec->EncodeFrame(dst, &keyframe, utv->buffer);
+
+ if (!pkt->size) {
+ av_log(avctx, AV_LOG_ERROR, "EncodeFrame failed!\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /*
+ * Ut Video is intra-only and every frame is a keyframe,
+ * and the API always returns true. In case something
+ * durastic changes in the future, such as inter support,
+ * assert that this is true.
+ */
+ av_assert2(keyframe == true);
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int utvideo_encode_close(AVCodecContext *avctx)
+{
+ UtVideoContext *utv = (UtVideoContext *)avctx->priv_data;
+
+ av_frame_free(&avctx->coded_frame);
+ av_freep(&avctx->extradata);
+ av_freep(&utv->buffer);
+
+ utv->codec->EncodeEnd();
+ CCodec::DeleteInstance(utv->codec);
+
+ return 0;
+}
+
+AVCodec ff_libutvideo_encoder = {
+ "libutvideo",
+ NULL_IF_CONFIG_SMALL("Ut Video"),
+ AVMEDIA_TYPE_VIDEO,
+ AV_CODEC_ID_UTVIDEO,
+ CODEC_CAP_AUTO_THREADS | CODEC_CAP_LOSSLESS,
+ NULL, /* supported_framerates */
+ (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE
+ },
+ NULL, /* supported_samplerates */
+ NULL, /* sample_fmts */
+ NULL, /* channel_layouts */
+ 0, /* max_lowres */
+ NULL, /* priv_class */
+ NULL, /* profiles */
+ sizeof(UtVideoContext),
+ NULL, /* next */
+ NULL, /* init_thread_copy */
+ NULL, /* update_thread_context */
+ NULL, /* defaults */
+ NULL, /* init_static_data */
+ utvideo_encode_init,
+ NULL, /* encode */
+ utvideo_encode_frame,
+ NULL, /* decode */
+ utvideo_encode_close,
+ NULL, /* flush */
+};
diff --git a/libavcodec/libvo-aacenc.c b/libavcodec/libvo-aacenc.c
index 6dd71174d3..2c4a424252 100644
--- a/libavcodec/libvo-aacenc.c
+++ b/libavcodec/libvo-aacenc.c
@@ -2,20 +2,20 @@
* AAC encoder wrapper
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,7 +65,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
s->last_frame = 2;
ff_af_queue_init(avctx, &s->afq);
- s->end_buffer = av_mallocz(avctx->frame_size * avctx->channels * 2);
+ s->end_buffer = av_mallocz_array(avctx->channels, avctx->frame_size * 2);
if (!s->end_buffer) {
ret = AVERROR(ENOMEM);
goto error;
@@ -153,10 +153,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
return ret;
}
- if ((ret = ff_alloc_packet(avpkt, FFMAX(8192, 768 * avctx->channels)))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, FFMAX(8192, 768 * avctx->channels))) < 0)
return ret;
- }
input.Buffer = samples;
input.Length = 2 * avctx->channels * avctx->frame_size;
@@ -179,6 +177,13 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
return 0;
}
+/* duplicated from avpriv_mpeg4audio_sample_rates to avoid shared build
+ * failures */
+static const int mpeg4audio_sample_rates[16] = {
+ 96000, 88200, 64000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000, 11025, 8000, 7350
+};
+
AVCodec ff_libvo_aacenc_encoder = {
.name = "libvo_aacenc",
.long_name = NULL_IF_CONFIG_SMALL("Android VisualOn AAC (Advanced Audio Coding)"),
@@ -188,6 +193,7 @@ AVCodec ff_libvo_aacenc_encoder = {
.init = aac_encode_init,
.encode2 = aac_encode_frame,
.close = aac_encode_close,
+ .supported_samplerates = mpeg4audio_sample_rates,
.capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
diff --git a/libavcodec/libvo-amrwbenc.c b/libavcodec/libvo-amrwbenc.c
index da3941b312..fe19e71156 100644
--- a/libavcodec/libvo-amrwbenc.c
+++ b/libavcodec/libvo-amrwbenc.c
@@ -1,21 +1,21 @@
/*
* AMR Audio encoder stub
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,7 +45,7 @@ static const AVOption options[] = {
{ NULL }
};
-static const AVClass class = {
+static const AVClass amrwb_class = {
"libvo_amrwbenc", av_default_item_name, options, LIBAVUTIL_VERSION_INT
};
@@ -79,7 +79,7 @@ static av_cold int amr_wb_encode_init(AVCodecContext *avctx)
{
AMRWBContext *s = avctx->priv_data;
- if (avctx->sample_rate != 16000) {
+ if (avctx->sample_rate != 16000 && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
av_log(avctx, AV_LOG_ERROR, "Only 16000Hz sample rate supported\n");
return AVERROR(ENOSYS);
}
@@ -115,10 +115,8 @@ static int amr_wb_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const int16_t *samples = (const int16_t *)frame->data[0];
int size, ret;
- if ((ret = ff_alloc_packet(avpkt, MAX_PACKET_SIZE))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, MAX_PACKET_SIZE)) < 0)
return ret;
- }
if (s->last_bitrate != avctx->bit_rate) {
s->mode = get_wb_bitrate_mode(avctx->bit_rate, avctx);
@@ -150,5 +148,5 @@ AVCodec ff_libvo_amrwbenc_encoder = {
.close = amr_wb_encode_close,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
- .priv_class = &class,
+ .priv_class = &amrwb_class,
};
diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c
deleted file mode 100644
index f7ea253c4f..0000000000
--- a/libavcodec/libvorbis.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * Vorbis encoding support via libvorbisenc.
- * @author Mark Hills <mark@pogo.org.uk>
- */
-
-#include <vorbis/vorbisenc.h>
-
-#include "libavutil/fifo.h"
-#include "libavutil/opt.h"
-#include "avcodec.h"
-#include "audio_frame_queue.h"
-#include "bytestream.h"
-#include "internal.h"
-#include "vorbis.h"
-#include "vorbis_parser.h"
-
-#undef NDEBUG
-#include <assert.h>
-
-/* Number of samples the user should send in each call.
- * This value is used because it is the LCD of all possible frame sizes, so
- * an output packet will always start at the same point as one of the input
- * packets.
- */
-#define LIBVORBIS_FRAME_SIZE 64
-
-#define BUFFER_SIZE (1024 * 64)
-
-typedef struct LibvorbisContext {
- AVClass *av_class; /**< class for AVOptions */
- vorbis_info vi; /**< vorbis_info used during init */
- vorbis_dsp_state vd; /**< DSP state used for analysis */
- vorbis_block vb; /**< vorbis_block used for analysis */
- AVFifoBuffer *pkt_fifo; /**< output packet buffer */
- int eof; /**< end-of-file flag */
- int dsp_initialized; /**< vd has been initialized */
- vorbis_comment vc; /**< VorbisComment info */
- ogg_packet op; /**< ogg packet */
- double iblock; /**< impulse block bias option */
- AVVorbisParseContext *vp; /**< parse context to get durations */
- AudioFrameQueue afq; /**< frame queue for timestamps */
-} LibvorbisContext;
-
-static const AVOption options[] = {
- { "iblock", "Sets the impulse block bias", offsetof(LibvorbisContext, iblock), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -15, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
- { NULL }
-};
-
-static const AVCodecDefault defaults[] = {
- { "b", "0" },
- { NULL },
-};
-
-static const AVClass class = { "libvorbis", av_default_item_name, options, LIBAVUTIL_VERSION_INT };
-
-
-static int vorbis_error_to_averror(int ov_err)
-{
- switch (ov_err) {
- case OV_EFAULT: return AVERROR_BUG;
- case OV_EINVAL: return AVERROR(EINVAL);
- case OV_EIMPL: return AVERROR(EINVAL);
- default: return AVERROR_UNKNOWN;
- }
-}
-
-static av_cold int libvorbis_setup(vorbis_info *vi, AVCodecContext *avctx)
-{
- LibvorbisContext *s = avctx->priv_data;
- double cfreq;
- int ret;
-
- if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) {
- /* variable bitrate
- * NOTE: we use the oggenc range of -1 to 10 for global_quality for
- * user convenience, but libvorbis uses -0.1 to 1.0.
- */
- float q = avctx->global_quality / (float)FF_QP2LAMBDA;
- /* default to 3 if the user did not set quality or bitrate */
- if (!(avctx->flags & CODEC_FLAG_QSCALE))
- q = 3.0;
- if ((ret = vorbis_encode_setup_vbr(vi, avctx->channels,
- avctx->sample_rate,
- q / 10.0)))
- goto error;
- } else {
- int minrate = avctx->rc_min_rate > 0 ? avctx->rc_min_rate : -1;
- int maxrate = avctx->rc_max_rate > 0 ? avctx->rc_max_rate : -1;
-
- /* average bitrate */
- if ((ret = vorbis_encode_setup_managed(vi, avctx->channels,
- avctx->sample_rate, maxrate,
- avctx->bit_rate, minrate)))
- goto error;
-
- /* variable bitrate by estimate, disable slow rate management */
- if (minrate == -1 && maxrate == -1)
- if ((ret = vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, NULL)))
- goto error;
- }
-
- /* cutoff frequency */
- if (avctx->cutoff > 0) {
- cfreq = avctx->cutoff / 1000.0;
- if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)))
- goto error;
- }
-
- /* impulse block bias */
- if (s->iblock) {
- if ((ret = vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &s->iblock)))
- goto error;
- }
-
- if ((ret = vorbis_encode_setup_init(vi)))
- goto error;
-
- return 0;
-error:
- return vorbis_error_to_averror(ret);
-}
-
-/* How many bytes are needed for a buffer of length 'l' */
-static int xiph_len(int l)
-{
- return 1 + l / 255 + l;
-}
-
-static av_cold int libvorbis_encode_close(AVCodecContext *avctx)
-{
- LibvorbisContext *s = avctx->priv_data;
-
- /* notify vorbisenc this is EOF */
- if (s->dsp_initialized)
- vorbis_analysis_wrote(&s->vd, 0);
-
- vorbis_block_clear(&s->vb);
- vorbis_dsp_clear(&s->vd);
- vorbis_info_clear(&s->vi);
-
- av_fifo_free(s->pkt_fifo);
- ff_af_queue_close(&s->afq);
- av_freep(&avctx->extradata);
-
- av_vorbis_parse_free(&s->vp);
-
- return 0;
-}
-
-static av_cold int libvorbis_encode_init(AVCodecContext *avctx)
-{
- LibvorbisContext *s = avctx->priv_data;
- ogg_packet header, header_comm, header_code;
- uint8_t *p;
- unsigned int offset;
- int ret;
-
- vorbis_info_init(&s->vi);
- if ((ret = libvorbis_setup(&s->vi, avctx))) {
- av_log(avctx, AV_LOG_ERROR, "encoder setup failed\n");
- goto error;
- }
- if ((ret = vorbis_analysis_init(&s->vd, &s->vi))) {
- av_log(avctx, AV_LOG_ERROR, "analysis init failed\n");
- ret = vorbis_error_to_averror(ret);
- goto error;
- }
- s->dsp_initialized = 1;
- if ((ret = vorbis_block_init(&s->vd, &s->vb))) {
- av_log(avctx, AV_LOG_ERROR, "dsp init failed\n");
- ret = vorbis_error_to_averror(ret);
- goto error;
- }
-
- vorbis_comment_init(&s->vc);
- vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
-
- if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
- &header_code))) {
- ret = vorbis_error_to_averror(ret);
- goto error;
- }
-
- avctx->extradata_size = 1 + xiph_len(header.bytes) +
- xiph_len(header_comm.bytes) +
- header_code.bytes;
- p = avctx->extradata = av_malloc(avctx->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!p) {
- ret = AVERROR(ENOMEM);
- goto error;
- }
- p[0] = 2;
- offset = 1;
- offset += av_xiphlacing(&p[offset], header.bytes);
- offset += av_xiphlacing(&p[offset], header_comm.bytes);
- memcpy(&p[offset], header.packet, header.bytes);
- offset += header.bytes;
- memcpy(&p[offset], header_comm.packet, header_comm.bytes);
- offset += header_comm.bytes;
- memcpy(&p[offset], header_code.packet, header_code.bytes);
- offset += header_code.bytes;
- assert(offset == avctx->extradata_size);
-
- s->vp = av_vorbis_parse_init(avctx->extradata, avctx->extradata_size);
- if (!s->vp) {
- av_log(avctx, AV_LOG_ERROR, "invalid extradata\n");
- return ret;
- }
-
- vorbis_comment_clear(&s->vc);
-
- avctx->frame_size = LIBVORBIS_FRAME_SIZE;
- ff_af_queue_init(avctx, &s->afq);
-
- s->pkt_fifo = av_fifo_alloc(BUFFER_SIZE);
- if (!s->pkt_fifo) {
- ret = AVERROR(ENOMEM);
- goto error;
- }
-
- return 0;
-error:
- libvorbis_encode_close(avctx);
- return ret;
-}
-
-static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
- const AVFrame *frame, int *got_packet_ptr)
-{
- LibvorbisContext *s = avctx->priv_data;
- ogg_packet op;
- int ret, duration;
-
- /* send samples to libvorbis */
- if (frame) {
- const int samples = frame->nb_samples;
- float **buffer;
- int c, channels = s->vi.channels;
-
- buffer = vorbis_analysis_buffer(&s->vd, samples);
- for (c = 0; c < channels; c++) {
- int co = (channels > 8) ? c :
- ff_vorbis_encoding_channel_layout_offsets[channels - 1][c];
- memcpy(buffer[c], frame->extended_data[co],
- samples * sizeof(*buffer[c]));
- }
- if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
- return vorbis_error_to_averror(ret);
- }
- if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
- return ret;
- } else {
- if (!s->eof)
- if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
- return vorbis_error_to_averror(ret);
- }
- s->eof = 1;
- }
-
- /* retrieve available packets from libvorbis */
- while ((ret = vorbis_analysis_blockout(&s->vd, &s->vb)) == 1) {
- if ((ret = vorbis_analysis(&s->vb, NULL)) < 0)
- break;
- if ((ret = vorbis_bitrate_addblock(&s->vb)) < 0)
- break;
-
- /* add any available packets to the output packet buffer */
- while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) {
- if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) {
- av_log(avctx, AV_LOG_ERROR, "packet buffer is too small");
- return AVERROR_BUG;
- }
- av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
- av_fifo_generic_write(s->pkt_fifo, op.packet, op.bytes, NULL);
- }
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
- break;
- }
- }
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
- return vorbis_error_to_averror(ret);
- }
-
- /* check for available packets */
- if (av_fifo_size(s->pkt_fifo) < sizeof(ogg_packet))
- return 0;
-
- av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
-
- if ((ret = ff_alloc_packet(avpkt, op.bytes))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
- return ret;
- }
- av_fifo_generic_read(s->pkt_fifo, avpkt->data, op.bytes, NULL);
-
- avpkt->pts = ff_samples_to_time_base(avctx, op.granulepos);
-
- duration = av_vorbis_parse_frame(s->vp, avpkt->data, avpkt->size);
- if (duration > 0) {
- /* we do not know encoder delay until we get the first packet from
- * libvorbis, so we have to update the AudioFrameQueue counts */
- if (!avctx->initial_padding) {
- avctx->initial_padding = duration;
- s->afq.remaining_delay += duration;
- s->afq.remaining_samples += duration;
- }
- ff_af_queue_remove(&s->afq, duration, &avpkt->pts, &avpkt->duration);
- }
-
- *got_packet_ptr = 1;
- return 0;
-}
-
-AVCodec ff_libvorbis_encoder = {
- .name = "libvorbis",
- .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_VORBIS,
- .priv_data_size = sizeof(LibvorbisContext),
- .init = libvorbis_encode_init,
- .encode2 = libvorbis_encode_frame,
- .close = libvorbis_encode_close,
- .capabilities = CODEC_CAP_DELAY,
- .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
- AV_SAMPLE_FMT_NONE },
- .priv_class = &class,
- .defaults = defaults,
-};
diff --git a/libavcodec/libvorbisdec.c b/libavcodec/libvorbisdec.c
new file mode 100644
index 0000000000..db005725fc
--- /dev/null
+++ b/libavcodec/libvorbisdec.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <vorbis/vorbisenc.h>
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+
+typedef struct OggVorbisDecContext {
+ vorbis_info vi; /**< vorbis_info used during init */
+ vorbis_dsp_state vd; /**< DSP state used for analysis */
+ vorbis_block vb; /**< vorbis_block used for analysis */
+ vorbis_comment vc; /**< VorbisComment info */
+ ogg_packet op; /**< ogg packet */
+} OggVorbisDecContext;
+
+static int oggvorbis_decode_init(AVCodecContext *avccontext) {
+ OggVorbisDecContext *context = avccontext->priv_data ;
+ uint8_t *p= avccontext->extradata;
+ int i, hsizes[3], ret;
+ unsigned char *headers[3], *extradata = avccontext->extradata;
+
+ if(! avccontext->extradata_size || ! p) {
+ av_log(avccontext, AV_LOG_ERROR, "vorbis extradata absent\n");
+ return AVERROR(EINVAL);
+ }
+
+ vorbis_info_init(&context->vi) ;
+ vorbis_comment_init(&context->vc) ;
+
+ if(p[0] == 0 && p[1] == 30) {
+ for(i = 0; i < 3; i++){
+ hsizes[i] = bytestream_get_be16((const uint8_t **)&p);
+ headers[i] = p;
+ p += hsizes[i];
+ }
+ } else if(*p == 2) {
+ unsigned int offset = 1;
+ p++;
+ for(i=0; i<2; i++) {
+ hsizes[i] = 0;
+ while((*p == 0xFF) && (offset < avccontext->extradata_size)) {
+ hsizes[i] += 0xFF;
+ offset++;
+ p++;
+ }
+ if(offset >= avccontext->extradata_size - 1) {
+ av_log(avccontext, AV_LOG_ERROR,
+ "vorbis header sizes damaged\n");
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
+ hsizes[i] += *p;
+ offset++;
+ p++;
+ }
+ hsizes[2] = avccontext->extradata_size - hsizes[0]-hsizes[1]-offset;
+#if 0
+ av_log(avccontext, AV_LOG_DEBUG,
+ "vorbis header sizes: %d, %d, %d, / extradata_len is %d \n",
+ hsizes[0], hsizes[1], hsizes[2], avccontext->extradata_size);
+#endif
+ headers[0] = extradata + offset;
+ headers[1] = extradata + offset + hsizes[0];
+ headers[2] = extradata + offset + hsizes[0] + hsizes[1];
+ } else {
+ av_log(avccontext, AV_LOG_ERROR,
+ "vorbis initial header len is wrong: %d\n", *p);
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
+
+ for(i=0; i<3; i++){
+ context->op.b_o_s= i==0;
+ context->op.bytes = hsizes[i];
+ context->op.packet = headers[i];
+ if(vorbis_synthesis_headerin(&context->vi, &context->vc, &context->op)<0){
+ av_log(avccontext, AV_LOG_ERROR, "%d. vorbis header damaged\n", i+1);
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
+ }
+
+ avccontext->channels = context->vi.channels;
+ avccontext->sample_rate = context->vi.rate;
+ avccontext->sample_fmt = AV_SAMPLE_FMT_S16;
+ avccontext->time_base= (AVRational){1, avccontext->sample_rate};
+
+ vorbis_synthesis_init(&context->vd, &context->vi);
+ vorbis_block_init(&context->vd, &context->vb);
+
+ return 0 ;
+
+ error:
+ vorbis_info_clear(&context->vi);
+ vorbis_comment_clear(&context->vc) ;
+ return ret;
+}
+
+
+static inline int conv(int samples, float **pcm, char *buf, int channels) {
+ int i, j;
+ ogg_int16_t *ptr, *data = (ogg_int16_t*)buf ;
+ float *mono ;
+
+ for(i = 0 ; i < channels ; i++){
+ ptr = &data[i];
+ mono = pcm[i] ;
+
+ for(j = 0 ; j < samples ; j++) {
+ *ptr = av_clip_int16(mono[j] * 32767.f);
+ ptr += channels;
+ }
+ }
+
+ return 0 ;
+}
+
+static int oggvorbis_decode_frame(AVCodecContext *avccontext, void *data,
+ int *got_frame_ptr, AVPacket *avpkt)
+{
+ OggVorbisDecContext *context = avccontext->priv_data ;
+ AVFrame *frame = data;
+ float **pcm ;
+ ogg_packet *op= &context->op;
+ int samples, total_samples, total_bytes;
+ int ret;
+ int16_t *output;
+
+ if(!avpkt->size){
+ //FIXME flush
+ return 0;
+ }
+
+ frame->nb_samples = 8192*4;
+ if ((ret = ff_get_buffer(avccontext, frame, 0)) < 0)
+ return ret;
+ output = (int16_t *)frame->data[0];
+
+
+ op->packet = avpkt->data;
+ op->bytes = avpkt->size;
+
+// av_log(avccontext, AV_LOG_DEBUG, "%d %d %d %"PRId64" %"PRId64" %d %d\n", op->bytes, op->b_o_s, op->e_o_s, op->granulepos, op->packetno, buf_size, context->vi.rate);
+
+/* for(i=0; i<op->bytes; i++)
+ av_log(avccontext, AV_LOG_DEBUG, "%02X ", op->packet[i]);
+ av_log(avccontext, AV_LOG_DEBUG, "\n");*/
+
+ if(vorbis_synthesis(&context->vb, op) == 0)
+ vorbis_synthesis_blockin(&context->vd, &context->vb) ;
+
+ total_samples = 0 ;
+ total_bytes = 0 ;
+
+ while((samples = vorbis_synthesis_pcmout(&context->vd, &pcm)) > 0) {
+ conv(samples, pcm, (char*)output + total_bytes, context->vi.channels) ;
+ total_bytes += samples * 2 * context->vi.channels ;
+ total_samples += samples ;
+ vorbis_synthesis_read(&context->vd, samples) ;
+ }
+
+ frame->nb_samples = total_samples;
+ *got_frame_ptr = total_samples > 0;
+ return avpkt->size;
+}
+
+
+static int oggvorbis_decode_close(AVCodecContext *avccontext) {
+ OggVorbisDecContext *context = avccontext->priv_data ;
+
+ vorbis_info_clear(&context->vi) ;
+ vorbis_comment_clear(&context->vc) ;
+
+ return 0 ;
+}
+
+
+AVCodec ff_libvorbis_decoder = {
+ .name = "libvorbis",
+ .long_name = NULL_IF_CONFIG_SMALL("libvorbis"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_VORBIS,
+ .priv_data_size = sizeof(OggVorbisDecContext),
+ .init = oggvorbis_decode_init,
+ .decode = oggvorbis_decode_frame,
+ .close = oggvorbis_decode_close,
+ .capabilities = CODEC_CAP_DELAY,
+};
diff --git a/libavcodec/libvorbisenc.c b/libavcodec/libvorbisenc.c
new file mode 100644
index 0000000000..231d1be252
--- /dev/null
+++ b/libavcodec/libvorbisenc.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2002 Mark Hills <mark@pogo.org.uk>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <vorbis/vorbisenc.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/fifo.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "audio_frame_queue.h"
+#include "internal.h"
+#include "vorbis.h"
+#include "vorbis_parser.h"
+
+
+/* Number of samples the user should send in each call.
+ * This value is used because it is the LCD of all possible frame sizes, so
+ * an output packet will always start at the same point as one of the input
+ * packets.
+ */
+#define LIBVORBIS_FRAME_SIZE 64
+
+#define BUFFER_SIZE (1024 * 64)
+
+typedef struct LibvorbisEncContext {
+ AVClass *av_class; /**< class for AVOptions */
+ vorbis_info vi; /**< vorbis_info used during init */
+ vorbis_dsp_state vd; /**< DSP state used for analysis */
+ vorbis_block vb; /**< vorbis_block used for analysis */
+ AVFifoBuffer *pkt_fifo; /**< output packet buffer */
+ int eof; /**< end-of-file flag */
+ int dsp_initialized; /**< vd has been initialized */
+ vorbis_comment vc; /**< VorbisComment info */
+ double iblock; /**< impulse block bias option */
+ AVVorbisParseContext *vp; /**< parse context to get durations */
+ AudioFrameQueue afq; /**< frame queue for timestamps */
+} LibvorbisEncContext;
+
+static const AVOption options[] = {
+ { "iblock", "Sets the impulse block bias", offsetof(LibvorbisEncContext, iblock), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -15, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL }
+};
+
+static const AVCodecDefault defaults[] = {
+ { "b", "0" },
+ { NULL },
+};
+
+static const AVClass vorbis_class = {
+ .class_name = "libvorbis",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int vorbis_error_to_averror(int ov_err)
+{
+ switch (ov_err) {
+ case OV_EFAULT: return AVERROR_BUG;
+ case OV_EINVAL: return AVERROR(EINVAL);
+ case OV_EIMPL: return AVERROR(EINVAL);
+ default: return AVERROR_UNKNOWN;
+ }
+}
+
+static av_cold int libvorbis_setup(vorbis_info *vi, AVCodecContext *avctx)
+{
+ LibvorbisEncContext *s = avctx->priv_data;
+ double cfreq;
+ int ret;
+
+ if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) {
+ /* variable bitrate
+ * NOTE: we use the oggenc range of -1 to 10 for global_quality for
+ * user convenience, but libvorbis uses -0.1 to 1.0.
+ */
+ float q = avctx->global_quality / (float)FF_QP2LAMBDA;
+ /* default to 3 if the user did not set quality or bitrate */
+ if (!(avctx->flags & CODEC_FLAG_QSCALE))
+ q = 3.0;
+ if ((ret = vorbis_encode_setup_vbr(vi, avctx->channels,
+ avctx->sample_rate,
+ q / 10.0)))
+ goto error;
+ } else {
+ int minrate = avctx->rc_min_rate > 0 ? avctx->rc_min_rate : -1;
+ int maxrate = avctx->rc_max_rate > 0 ? avctx->rc_max_rate : -1;
+
+ /* average bitrate */
+ if ((ret = vorbis_encode_setup_managed(vi, avctx->channels,
+ avctx->sample_rate, maxrate,
+ avctx->bit_rate, minrate)))
+ goto error;
+
+ /* variable bitrate by estimate, disable slow rate management */
+ if (minrate == -1 && maxrate == -1)
+ if ((ret = vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, NULL)))
+ goto error; /* should not happen */
+ }
+
+ /* cutoff frequency */
+ if (avctx->cutoff > 0) {
+ cfreq = avctx->cutoff / 1000.0;
+ if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)))
+ goto error; /* should not happen */
+ }
+
+ /* impulse block bias */
+ if (s->iblock) {
+ if ((ret = vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &s->iblock)))
+ goto error;
+ }
+
+ if (avctx->channels == 3 &&
+ avctx->channel_layout != (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) ||
+ avctx->channels == 4 &&
+ avctx->channel_layout != AV_CH_LAYOUT_2_2 &&
+ avctx->channel_layout != AV_CH_LAYOUT_QUAD ||
+ avctx->channels == 5 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT0_BACK ||
+ avctx->channels == 6 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1 &&
+ avctx->channel_layout != AV_CH_LAYOUT_5POINT1_BACK ||
+ avctx->channels == 7 &&
+ avctx->channel_layout != (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) ||
+ avctx->channels == 8 &&
+ avctx->channel_layout != AV_CH_LAYOUT_7POINT1) {
+ if (avctx->channel_layout) {
+ char name[32];
+ av_get_channel_layout_string(name, sizeof(name), avctx->channels,
+ avctx->channel_layout);
+ av_log(avctx, AV_LOG_ERROR, "%s not supported by Vorbis: "
+ "output stream will have incorrect "
+ "channel layout.\n", name);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The encoder "
+ "will use Vorbis channel layout for "
+ "%d channels.\n", avctx->channels);
+ }
+ }
+
+ if ((ret = vorbis_encode_setup_init(vi)))
+ goto error;
+
+ return 0;
+error:
+ return vorbis_error_to_averror(ret);
+}
+
+/* How many bytes are needed for a buffer of length 'l' */
+static int xiph_len(int l)
+{
+ return 1 + l / 255 + l;
+}
+
+static av_cold int libvorbis_encode_close(AVCodecContext *avctx)
+{
+ LibvorbisEncContext *s = avctx->priv_data;
+
+ /* notify vorbisenc this is EOF */
+ if (s->dsp_initialized)
+ vorbis_analysis_wrote(&s->vd, 0);
+
+ vorbis_block_clear(&s->vb);
+ vorbis_dsp_clear(&s->vd);
+ vorbis_info_clear(&s->vi);
+
+ av_fifo_freep(&s->pkt_fifo);
+ ff_af_queue_close(&s->afq);
+ av_freep(&avctx->extradata);
+
+ av_vorbis_parse_free(&s->vp);
+
+ return 0;
+}
+
+static av_cold int libvorbis_encode_init(AVCodecContext *avctx)
+{
+ LibvorbisEncContext *s = avctx->priv_data;
+ ogg_packet header, header_comm, header_code;
+ uint8_t *p;
+ unsigned int offset;
+ int ret;
+
+ vorbis_info_init(&s->vi);
+ if ((ret = libvorbis_setup(&s->vi, avctx))) {
+ av_log(avctx, AV_LOG_ERROR, "encoder setup failed\n");
+ goto error;
+ }
+ if ((ret = vorbis_analysis_init(&s->vd, &s->vi))) {
+ av_log(avctx, AV_LOG_ERROR, "analysis init failed\n");
+ ret = vorbis_error_to_averror(ret);
+ goto error;
+ }
+ s->dsp_initialized = 1;
+ if ((ret = vorbis_block_init(&s->vd, &s->vb))) {
+ av_log(avctx, AV_LOG_ERROR, "dsp init failed\n");
+ ret = vorbis_error_to_averror(ret);
+ goto error;
+ }
+
+ vorbis_comment_init(&s->vc);
+ if (!(avctx->flags & CODEC_FLAG_BITEXACT))
+ vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT);
+
+ if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm,
+ &header_code))) {
+ ret = vorbis_error_to_averror(ret);
+ goto error;
+ }
+
+ avctx->extradata_size = 1 + xiph_len(header.bytes) +
+ xiph_len(header_comm.bytes) +
+ header_code.bytes;
+ p = avctx->extradata = av_malloc(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!p) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ p[0] = 2;
+ offset = 1;
+ offset += av_xiphlacing(&p[offset], header.bytes);
+ offset += av_xiphlacing(&p[offset], header_comm.bytes);
+ memcpy(&p[offset], header.packet, header.bytes);
+ offset += header.bytes;
+ memcpy(&p[offset], header_comm.packet, header_comm.bytes);
+ offset += header_comm.bytes;
+ memcpy(&p[offset], header_code.packet, header_code.bytes);
+ offset += header_code.bytes;
+ av_assert0(offset == avctx->extradata_size);
+
+ s->vp = av_vorbis_parse_init(avctx->extradata, avctx->extradata_size);
+ if (!s->vp) {
+ av_log(avctx, AV_LOG_ERROR, "invalid extradata\n");
+ return ret;
+ }
+
+ vorbis_comment_clear(&s->vc);
+
+ avctx->frame_size = LIBVORBIS_FRAME_SIZE;
+ ff_af_queue_init(avctx, &s->afq);
+
+ s->pkt_fifo = av_fifo_alloc(BUFFER_SIZE);
+ if (!s->pkt_fifo) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ return 0;
+error:
+ libvorbis_encode_close(avctx);
+ return ret;
+}
+
+static int libvorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ LibvorbisEncContext *s = avctx->priv_data;
+ ogg_packet op;
+ int ret, duration;
+
+ /* send samples to libvorbis */
+ if (frame) {
+ const int samples = frame->nb_samples;
+ float **buffer;
+ int c, channels = s->vi.channels;
+
+ buffer = vorbis_analysis_buffer(&s->vd, samples);
+ for (c = 0; c < channels; c++) {
+ int co = (channels > 8) ? c :
+ ff_vorbis_encoding_channel_layout_offsets[channels - 1][c];
+ memcpy(buffer[c], frame->extended_data[co],
+ samples * sizeof(*buffer[c]));
+ }
+ if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
+ return vorbis_error_to_averror(ret);
+ }
+ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
+ return ret;
+ } else {
+ if (!s->eof && s->afq.frame_alloc)
+ if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n");
+ return vorbis_error_to_averror(ret);
+ }
+ s->eof = 1;
+ }
+
+ /* retrieve available packets from libvorbis */
+ while ((ret = vorbis_analysis_blockout(&s->vd, &s->vb)) == 1) {
+ if ((ret = vorbis_analysis(&s->vb, NULL)) < 0)
+ break;
+ if ((ret = vorbis_bitrate_addblock(&s->vb)) < 0)
+ break;
+
+ /* add any available packets to the output packet buffer */
+ while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) {
+ if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) {
+ av_log(avctx, AV_LOG_ERROR, "packet buffer is too small\n");
+ return AVERROR_BUG;
+ }
+ av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
+ av_fifo_generic_write(s->pkt_fifo, op.packet, op.bytes, NULL);
+ }
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
+ break;
+ }
+ }
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error getting available packets\n");
+ return vorbis_error_to_averror(ret);
+ }
+
+ /* check for available packets */
+ if (av_fifo_size(s->pkt_fifo) < sizeof(ogg_packet))
+ return 0;
+
+ av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL);
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, op.bytes)) < 0)
+ return ret;
+ av_fifo_generic_read(s->pkt_fifo, avpkt->data, op.bytes, NULL);
+
+ avpkt->pts = ff_samples_to_time_base(avctx, op.granulepos);
+
+ duration = av_vorbis_parse_frame(s->vp, avpkt->data, avpkt->size);
+ if (duration > 0) {
+ /* we do not know encoder delay until we get the first packet from
+ * libvorbis, so we have to update the AudioFrameQueue counts */
+ if (!avctx->initial_padding && s->afq.frames) {
+ avctx->initial_padding = duration;
+ av_assert0(!s->afq.remaining_delay);
+ s->afq.frames->duration += duration;
+ if (s->afq.frames->pts != AV_NOPTS_VALUE)
+ s->afq.frames->pts -= duration;
+ s->afq.remaining_samples += duration;
+ }
+ ff_af_queue_remove(&s->afq, duration, &avpkt->pts, &avpkt->duration);
+ }
+
+ *got_packet_ptr = 1;
+ return 0;
+}
+
+AVCodec ff_libvorbis_encoder = {
+ .name = "libvorbis",
+ .long_name = NULL_IF_CONFIG_SMALL("libvorbis"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_VORBIS,
+ .priv_data_size = sizeof(LibvorbisEncContext),
+ .init = libvorbis_encode_init,
+ .encode2 = libvorbis_encode_frame,
+ .close = libvorbis_encode_close,
+ .capabilities = CODEC_CAP_DELAY | CODEC_CAP_SMALL_LAST_FRAME,
+ .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_NONE },
+ .priv_class = &vorbis_class,
+ .defaults = defaults,
+};
diff --git a/libavcodec/libvpx.c b/libavcodec/libvpx.c
index 20f44841f2..e0f9df3caa 100644
--- a/libavcodec/libvpx.c
+++ b/libavcodec/libvpx.c
@@ -1,35 +1,79 @@
/*
* Copyright (c) 2013 Guillaume Martres <smarter@ubuntu.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <vpx/vpx_codec.h>
-
#include "libvpx.h"
+#include "config.h"
+
+#if CONFIG_LIBVPX_VP9_ENCODER
+#include <vpx/vpx_encoder.h>
+#include <vpx/vp8cx.h>
+#endif
+
+static const enum AVPixelFormat vp9_pix_fmts_def[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_NONE
+};
+
+#if CONFIG_LIBVPX_VP9_ENCODER
+static const enum AVPixelFormat vp9_pix_fmts_highcol[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_NONE
+};
+
+static const enum AVPixelFormat vp9_pix_fmts_highbd[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV420P10LE,
+ AV_PIX_FMT_YUV422P10LE,
+ AV_PIX_FMT_YUV440P10LE,
+ AV_PIX_FMT_YUV444P10LE,
+ AV_PIX_FMT_YUV420P12LE,
+ AV_PIX_FMT_YUV422P12LE,
+ AV_PIX_FMT_YUV440P12LE,
+ AV_PIX_FMT_YUV444P12LE,
+ AV_PIX_FMT_NONE
+};
+#endif
-int ff_vp9_check_experimental(AVCodecContext *avctx)
+av_cold void ff_vp9_init_static(AVCodec *codec)
{
- if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL &&
- (vpx_codec_version_major() < 1 ||
- (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3))) {
- av_log(avctx, AV_LOG_ERROR,
- "Non-experimental support of VP9 requires libvpx >= 1.3.0\n");
- return AVERROR_EXPERIMENTAL;
+ if ( vpx_codec_version_major() < 1
+ || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3))
+ codec->capabilities |= CODEC_CAP_EXPERIMENTAL;
+ codec->pix_fmts = vp9_pix_fmts_def;
+#if CONFIG_LIBVPX_VP9_ENCODER
+ if ( vpx_codec_version_major() > 1
+ || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() >= 4)) {
+#ifdef VPX_CODEC_CAP_HIGHBITDEPTH
+ vpx_codec_caps_t codec_caps = vpx_codec_get_caps(vpx_codec_vp9_cx());
+ if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH)
+ codec->pix_fmts = vp9_pix_fmts_highbd;
+ else
+#endif
+ codec->pix_fmts = vp9_pix_fmts_highcol;
}
- return 0;
+#endif
}
diff --git a/libavcodec/libvpx.h b/libavcodec/libvpx.h
index cb1ed0959f..36a275c5d2 100644
--- a/libavcodec/libvpx.h
+++ b/libavcodec/libvpx.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 Guillaume Martres <smarter@ubuntu.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,6 @@
#include "avcodec.h"
-int ff_vp9_check_experimental(AVCodecContext *avctx);
+void ff_vp9_init_static(AVCodec *codec);
#endif /* AVCODEC_LIBVPX_H */
diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c
index 6052207b76..c69e88899e 100644
--- a/libavcodec/libvpxdec.c
+++ b/libavcodec/libvpxdec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010, Google, Inc.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,10 +56,80 @@ static av_cold int vpx_init(AVCodecContext *avctx,
return AVERROR(EINVAL);
}
- avctx->pix_fmt = AV_PIX_FMT_YUV420P;
return 0;
}
+// returns 0 on success, AVERROR_INVALIDDATA otherwise
+static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img)
+{
+ if (avctx->codec_id == AV_CODEC_ID_VP8 && img->fmt != VPX_IMG_FMT_I420)
+ return AVERROR_INVALIDDATA;
+ switch (img->fmt) {
+ case VPX_IMG_FMT_I420:
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ return 0;
+#if CONFIG_LIBVPX_VP9_DECODER
+ case VPX_IMG_FMT_I422:
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ return 0;
+#if VPX_IMAGE_ABI_VERSION >= 3
+ case VPX_IMG_FMT_I440:
+ avctx->pix_fmt = AV_PIX_FMT_YUV440P;
+ return 0;
+#endif
+ case VPX_IMG_FMT_I444:
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+ return 0;
+#ifdef VPX_IMG_FMT_HIGHBITDEPTH
+ case VPX_IMG_FMT_I42016:
+ if (img->bit_depth == 10) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P10LE;
+ return 0;
+ } else if (img->bit_depth == 12) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P12LE;
+ return 0;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+ case VPX_IMG_FMT_I42216:
+ if (img->bit_depth == 10) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
+ return 0;
+ } else if (img->bit_depth == 12) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P12LE;
+ return 0;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+#if VPX_IMAGE_ABI_VERSION >= 3
+ case VPX_IMG_FMT_I44016:
+ if (img->bit_depth == 10) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV440P10LE;
+ return 0;
+ } else if (img->bit_depth == 12) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV440P12LE;
+ return 0;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+#endif
+ case VPX_IMG_FMT_I44416:
+ if (img->bit_depth == 10) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P10LE;
+ return 0;
+ } else if (img->bit_depth == 12) {
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P12LE;
+ return 0;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+#endif
+#endif
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+}
+
static int vp8_decode(AVCodecContext *avctx,
void *data, int *got_frame, AVPacket *avpkt)
{
@@ -82,10 +152,15 @@ static int vp8_decode(AVCodecContext *avctx,
}
if ((img = vpx_codec_get_frame(&ctx->decoder, &iter))) {
- if (img->fmt != VPX_IMG_FMT_I420) {
- av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d)\n",
- img->fmt);
- return AVERROR_INVALIDDATA;
+ if ((ret = set_pix_fmt(avctx, img)) < 0) {
+#ifdef VPX_IMG_FMT_HIGHBITDEPTH
+ av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n",
+ img->fmt, img->bit_depth);
+#else
+ av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n",
+ img->fmt, 8);
+#endif
+ return ret;
}
if ((int) img->d_w != avctx->width || (int) img->d_h != avctx->height) {
@@ -97,7 +172,7 @@ static int vp8_decode(AVCodecContext *avctx,
}
if ((ret = ff_get_buffer(avctx, picture, 0)) < 0)
return ret;
- av_image_copy(picture->data, picture->linesize, img->planes,
+ av_image_copy(picture->data, picture->linesize, (const uint8_t **)img->planes,
img->stride, avctx->pix_fmt, img->d_w, img->d_h);
*got_frame = 1;
}
@@ -133,9 +208,6 @@ AVCodec ff_libvpx_vp8_decoder = {
#if CONFIG_LIBVPX_VP9_DECODER
static av_cold int vp9_init(AVCodecContext *avctx)
{
- int ret;
- if ((ret = ff_vp9_check_experimental(avctx)))
- return ret;
return vpx_init(avctx, &vpx_codec_vp9_dx_algo);
}
@@ -148,6 +220,7 @@ AVCodec ff_libvpx_vp9_decoder = {
.init = vp9_init,
.close = vp8_free,
.decode = vp8_decode,
- .capabilities = CODEC_CAP_AUTO_THREADS,
+ .capabilities = CODEC_CAP_AUTO_THREADS | CODEC_CAP_DR1,
+ .init_static_data = ff_vp9_init_static,
};
#endif /* CONFIG_LIBVPX_VP9_DECODER */
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index 4164769ad6..adf4b2e2f6 100644
--- a/libavcodec/libvpxenc.c
+++ b/libavcodec/libvpxenc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010, Google, Inc.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,9 +30,11 @@
#include "avcodec.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libvpx.h"
#include "libavutil/base64.h"
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -43,11 +45,16 @@
struct FrameListData {
void *buf; /**< compressed data buffer */
size_t sz; /**< length of compressed data */
+ void *buf_alpha;
+ size_t sz_alpha;
int64_t pts; /**< time stamp to show frame
(in timebase units) */
unsigned long duration; /**< duration to show frame
(in timebase units) */
uint32_t flags; /**< flags for this frame */
+ uint64_t sse[4];
+ int have_sse; /**< true if we have pending sse[] */
+ uint64_t frame_number;
struct FrameListData *next;
};
@@ -55,18 +62,42 @@ typedef struct VP8EncoderContext {
AVClass *class;
struct vpx_codec_ctx encoder;
struct vpx_image rawimg;
+ struct vpx_codec_ctx encoder_alpha;
+ struct vpx_image rawimg_alpha;
+ uint8_t is_alpha;
struct vpx_fixed_buf twopass_stats;
- unsigned long deadline; //i.e., RT/GOOD/BEST
+ int deadline; //i.e., RT/GOOD/BEST
+ uint64_t sse[4];
+ int have_sse; /**< true if we have pending sse[] */
+ uint64_t frame_number;
struct FrameListData *coded_frame_list;
+
int cpu_used;
+ /**
+ * VP8 specific flags, see VP8F_* below.
+ */
+ int flags;
+#define VP8F_ERROR_RESILIENT 0x00000001 ///< Enable measures appropriate for streaming over lossy links
+#define VP8F_AUTO_ALT_REF 0x00000002 ///< Enable automatic alternate reference frame generation
+
int auto_alt_ref;
+
int arnr_max_frames;
int arnr_strength;
int arnr_type;
+
int lag_in_frames;
int error_resilient;
int crf;
int static_thresh;
+ int max_intra_rate;
+
+ // VP9-only
+ int lossless;
+ int tile_columns;
+ int tile_rows;
+ int frame_parallel;
+ int aq_mode;
} VP8Context;
/** String mappings for enum vp8e_enc_control_id */
@@ -88,6 +119,14 @@ static const char *const ctlidstr[] = {
[VP8E_SET_ARNR_STRENGTH] = "VP8E_SET_ARNR_STRENGTH",
[VP8E_SET_ARNR_TYPE] = "VP8E_SET_ARNR_TYPE",
[VP8E_SET_CQ_LEVEL] = "VP8E_SET_CQ_LEVEL",
+ [VP8E_SET_MAX_INTRA_BITRATE_PCT] = "VP8E_SET_MAX_INTRA_BITRATE_PCT",
+#if CONFIG_LIBVPX_VP9_ENCODER
+ [VP9E_SET_LOSSLESS] = "VP9E_SET_LOSSLESS",
+ [VP9E_SET_TILE_COLUMNS] = "VP9E_SET_TILE_COLUMNS",
+ [VP9E_SET_TILE_ROWS] = "VP9E_SET_TILE_ROWS",
+ [VP9E_SET_FRAME_PARALLEL_DECODING] = "VP9E_SET_FRAME_PARALLEL_DECODING",
+ [VP9E_SET_AQ_MODE] = "VP9E_SET_AQ_MODE",
+#endif
};
static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc)
@@ -110,19 +149,26 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx,
av_log(avctx, level, "vpx_codec_enc_cfg\n");
av_log(avctx, level, "generic settings\n"
" %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n"
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ " %*s%u\n %*s%u\n"
+#endif
" %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n",
width, "g_usage:", cfg->g_usage,
width, "g_threads:", cfg->g_threads,
width, "g_profile:", cfg->g_profile,
width, "g_w:", cfg->g_w,
width, "g_h:", cfg->g_h,
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ width, "g_bit_depth:", cfg->g_bit_depth,
+ width, "g_input_bit_depth:", cfg->g_input_bit_depth,
+#endif
width, "g_timebase:", cfg->g_timebase.num, cfg->g_timebase.den,
width, "g_error_resilient:", cfg->g_error_resilient,
width, "g_pass:", cfg->g_pass,
width, "g_lag_in_frames:", cfg->g_lag_in_frames);
av_log(avctx, level, "rate control settings\n"
" %*s%u\n %*s%u\n %*s%u\n %*s%u\n"
- " %*s%d\n %*s%p(%zu)\n %*s%u\n",
+ " %*s%d\n %*s%p(%"SIZE_SPECIFIER")\n %*s%u\n",
width, "rc_dropframe_thresh:", cfg->rc_dropframe_thresh,
width, "rc_resize_allowed:", cfg->rc_resize_allowed,
width, "rc_resize_up_thresh:", cfg->rc_resize_up_thresh,
@@ -169,6 +215,8 @@ static void coded_frame_add(void *list, struct FrameListData *cx_frame)
static av_cold void free_coded_frame(struct FrameListData *cx_frame)
{
av_freep(&cx_frame->buf);
+ if (cx_frame->buf_alpha)
+ av_freep(&cx_frame->buf_alpha);
av_freep(&cx_frame);
}
@@ -209,28 +257,136 @@ static av_cold int vp8_free(AVCodecContext *avctx)
VP8Context *ctx = avctx->priv_data;
vpx_codec_destroy(&ctx->encoder);
+ if (ctx->is_alpha)
+ vpx_codec_destroy(&ctx->encoder_alpha);
av_freep(&ctx->twopass_stats.buf);
- av_freep(&avctx->coded_frame);
+ av_frame_free(&avctx->coded_frame);
av_freep(&avctx->stats_out);
free_frame_list(ctx->coded_frame_list);
return 0;
}
+#if CONFIG_LIBVPX_VP9_ENCODER
+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)
+{
+#ifdef VPX_IMG_FMT_HIGHBITDEPTH
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8;
+#endif
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUV420P:
+ enccfg->g_profile = 0;
+ *img_fmt = VPX_IMG_FMT_I420;
+ return 0;
+ case AV_PIX_FMT_YUV422P:
+ enccfg->g_profile = 1;
+ *img_fmt = VPX_IMG_FMT_I422;
+ return 0;
+#if VPX_IMAGE_ABI_VERSION >= 3
+ case AV_PIX_FMT_YUV440P:
+ enccfg->g_profile = 1;
+ *img_fmt = VPX_IMG_FMT_I440;
+ return 0;
+#endif
+ case AV_PIX_FMT_YUV444P:
+ enccfg->g_profile = 1;
+ *img_fmt = VPX_IMG_FMT_I444;
+ return 0;
+#ifdef VPX_IMG_FMT_HIGHBITDEPTH
+ case AV_PIX_FMT_YUV420P10LE:
+ case AV_PIX_FMT_YUV420P12LE:
+ if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV420P10LE ? 10 : 12;
+ enccfg->g_profile = 2;
+ *img_fmt = VPX_IMG_FMT_I42016;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ }
+ break;
+ case AV_PIX_FMT_YUV422P10LE:
+ case AV_PIX_FMT_YUV422P12LE:
+ if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV422P10LE ? 10 : 12;
+ enccfg->g_profile = 3;
+ *img_fmt = VPX_IMG_FMT_I42216;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ }
+ break;
+#if VPX_IMAGE_ABI_VERSION >= 3
+ case AV_PIX_FMT_YUV440P10LE:
+ case AV_PIX_FMT_YUV440P12LE:
+ if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV440P10LE ? 10 : 12;
+ enccfg->g_profile = 3;
+ *img_fmt = VPX_IMG_FMT_I44016;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ }
+ break;
+#endif
+ case AV_PIX_FMT_YUV444P10LE:
+ case AV_PIX_FMT_YUV444P12LE:
+ if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) {
+ enccfg->g_bit_depth = enccfg->g_input_bit_depth =
+ avctx->pix_fmt == AV_PIX_FMT_YUV444P10LE ? 10 : 12;
+ enccfg->g_profile = 3;
+ *img_fmt = VPX_IMG_FMT_I44416;
+ *flags |= VPX_CODEC_USE_HIGHBITDEPTH;
+ return 0;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
+ return AVERROR_INVALIDDATA;
+}
+#endif
+
static av_cold int vpx_init(AVCodecContext *avctx,
const struct vpx_codec_iface *iface)
{
VP8Context *ctx = avctx->priv_data;
struct vpx_codec_enc_cfg enccfg;
+ struct vpx_codec_enc_cfg enccfg_alpha;
+ vpx_codec_flags_t flags = (avctx->flags & CODEC_FLAG_PSNR) ? VPX_CODEC_USE_PSNR : 0;
int res;
+ vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420;
+#if CONFIG_LIBVPX_VP9_ENCODER
+ vpx_codec_caps_t codec_caps = vpx_codec_get_caps(iface);
+#endif
av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str());
av_log(avctx, AV_LOG_VERBOSE, "%s\n", vpx_codec_build_config());
+ if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P)
+ ctx->is_alpha = 1;
+
if ((res = vpx_codec_enc_config_default(iface, &enccfg, 0)) != VPX_CODEC_OK) {
av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n",
vpx_codec_err_to_string(res));
return AVERROR(EINVAL);
}
+
+#if CONFIG_LIBVPX_VP9_ENCODER
+ if (avctx->codec_id == AV_CODEC_ID_VP9) {
+ if (set_pix_fmt(avctx, codec_caps, &enccfg, &flags, &img_fmt))
+ return AVERROR(EINVAL);
+ }
+#endif
+
+ if(!avctx->bit_rate)
+ if(avctx->rc_max_rate || avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) {
+ av_log( avctx, AV_LOG_ERROR, "Rate control parameters set without a bitrate\n");
+ return AVERROR(EINVAL);
+ }
+
dump_enc_cfg(avctx, &enccfg);
enccfg.g_w = avctx->width;
@@ -238,9 +394,7 @@ static av_cold int vpx_init(AVCodecContext *avctx,
enccfg.g_timebase.num = avctx->time_base.num;
enccfg.g_timebase.den = avctx->time_base.den;
enccfg.g_threads = avctx->thread_count;
-
- if (ctx->lag_in_frames >= 0)
- enccfg.g_lag_in_frames = ctx->lag_in_frames;
+ enccfg.g_lag_in_frames= ctx->lag_in_frames;
if (avctx->flags & CODEC_FLAG_PASS1)
enccfg.g_pass = VPX_RC_FIRST_PASS;
@@ -249,28 +403,64 @@ static av_cold int vpx_init(AVCodecContext *avctx,
else
enccfg.g_pass = VPX_RC_ONE_PASS;
- if (!avctx->bit_rate)
- avctx->bit_rate = enccfg.rc_target_bitrate * 1000;
- else
+ if (avctx->rc_min_rate == avctx->rc_max_rate &&
+ avctx->rc_min_rate == avctx->bit_rate && avctx->bit_rate) {
+ enccfg.rc_end_usage = VPX_CBR;
+ } else if (ctx->crf >= 0) {
+ enccfg.rc_end_usage = VPX_CQ;
+#if CONFIG_LIBVPX_VP9_ENCODER
+ if (!avctx->bit_rate && avctx->codec_id == AV_CODEC_ID_VP9)
+ enccfg.rc_end_usage = VPX_Q;
+#endif
+ }
+
+ if (avctx->bit_rate) {
enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000,
- AV_ROUND_NEAR_INF);
+ AV_ROUND_NEAR_INF);
+#if CONFIG_LIBVPX_VP9_ENCODER
+ } else if (enccfg.rc_end_usage == VPX_Q) {
+#endif
+ } else {
+ if (enccfg.rc_end_usage == VPX_CQ) {
+ enccfg.rc_target_bitrate = 1000000;
+ } else {
+ avctx->bit_rate = enccfg.rc_target_bitrate * 1000;
+ av_log(avctx, AV_LOG_WARNING,
+ "Neither bitrate nor constrained quality specified, using default bitrate of %dkbit/sec\n",
+ enccfg.rc_target_bitrate);
+ }
+ }
- if (ctx->crf)
- enccfg.rc_end_usage = VPX_CQ;
- else if (avctx->rc_min_rate == avctx->rc_max_rate &&
- avctx->rc_min_rate == avctx->bit_rate)
- enccfg.rc_end_usage = VPX_CBR;
+ if (avctx->codec_id == AV_CODEC_ID_VP9 && ctx->lossless == 1) {
+ enccfg.rc_min_quantizer =
+ enccfg.rc_max_quantizer = 0;
+ } else {
+ if (avctx->qmin >= 0)
+ enccfg.rc_min_quantizer = avctx->qmin;
+ if (avctx->qmax >= 0)
+ enccfg.rc_max_quantizer = avctx->qmax;
+ }
+
+ if (enccfg.rc_end_usage == VPX_CQ
+#if CONFIG_LIBVPX_VP9_ENCODER
+ || enccfg.rc_end_usage == VPX_Q
+#endif
+ ) {
+ if (ctx->crf < enccfg.rc_min_quantizer || ctx->crf > enccfg.rc_max_quantizer) {
+ av_log(avctx, AV_LOG_ERROR,
+ "CQ level %d must be between minimum and maximum quantizer value (%d-%d)\n",
+ ctx->crf, enccfg.rc_min_quantizer, enccfg.rc_max_quantizer);
+ return AVERROR(EINVAL);
+ }
+ }
- if (avctx->qmin > 0)
- enccfg.rc_min_quantizer = avctx->qmin;
- if (avctx->qmax > 0)
- enccfg.rc_max_quantizer = avctx->qmax;
enccfg.rc_dropframe_thresh = avctx->frame_skip_threshold;
//0-100 (0 => CBR, 100 => VBR)
enccfg.rc_2pass_vbr_bias_pct = round(avctx->qcompress * 100);
- enccfg.rc_2pass_vbr_minsection_pct =
- avctx->rc_min_rate * 100LL / avctx->bit_rate;
+ if (avctx->bit_rate)
+ enccfg.rc_2pass_vbr_minsection_pct =
+ avctx->rc_min_rate * 100LL / avctx->bit_rate;
if (avctx->rc_max_rate)
enccfg.rc_2pass_vbr_maxsection_pct =
avctx->rc_max_rate * 100LL / avctx->bit_rate;
@@ -282,6 +472,7 @@ static av_cold int vpx_init(AVCodecContext *avctx,
enccfg.rc_buf_initial_sz =
avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate;
enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6;
+ enccfg.rc_undershoot_pct = round(avctx->rc_buffer_aggressivity * 100);
//_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO
if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size)
@@ -303,8 +494,9 @@ static av_cold int vpx_init(AVCodecContext *avctx,
ret = av_reallocp(&ctx->twopass_stats.buf, ctx->twopass_stats.sz);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR,
- "Stat buffer alloc (%zu bytes) failed\n",
+ "Stat buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n",
ctx->twopass_stats.sz);
+ ctx->twopass_stats.sz = 0;
return ret;
}
decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in,
@@ -321,23 +513,33 @@ static av_cold int vpx_init(AVCodecContext *avctx,
/* 0-3: For non-zero values the encoder increasingly optimizes for reduced
complexity playback on low powered devices at the expense of encode
quality. */
- if (avctx->profile != FF_PROFILE_UNKNOWN)
- enccfg.g_profile = avctx->profile;
+ if (avctx->profile != FF_PROFILE_UNKNOWN)
+ enccfg.g_profile = avctx->profile;
- enccfg.g_error_resilient = ctx->error_resilient;
+ enccfg.g_error_resilient = ctx->error_resilient || ctx->flags & VP8F_ERROR_RESILIENT;
dump_enc_cfg(avctx, &enccfg);
/* Construct Encoder Context */
- res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, 0);
+ res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, flags);
if (res != VPX_CODEC_OK) {
log_encoder_error(avctx, "Failed to initialize encoder");
return AVERROR(EINVAL);
}
+ if (ctx->is_alpha) {
+ enccfg_alpha = enccfg;
+ res = vpx_codec_enc_init(&ctx->encoder_alpha, iface, &enccfg_alpha, flags);
+ if (res != VPX_CODEC_OK) {
+ log_encoder_error(avctx, "Failed to initialize alpha encoder");
+ return AVERROR(EINVAL);
+ }
+ }
+
//codec control failures are currently treated only as warnings
av_log(avctx, AV_LOG_DEBUG, "vpx_codec_control\n");
- if (ctx->cpu_used != INT_MIN)
- codecctl_int(avctx, VP8E_SET_CPUUSED, ctx->cpu_used);
+ codecctl_int(avctx, VP8E_SET_CPUUSED, ctx->cpu_used);
+ if (ctx->flags & VP8F_AUTO_ALT_REF)
+ ctx->auto_alt_ref = 1;
if (ctx->auto_alt_ref >= 0)
codecctl_int(avctx, VP8E_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref);
if (ctx->arnr_max_frames >= 0)
@@ -346,8 +548,10 @@ static av_cold int vpx_init(AVCodecContext *avctx,
codecctl_int(avctx, VP8E_SET_ARNR_STRENGTH, ctx->arnr_strength);
if (ctx->arnr_type >= 0)
codecctl_int(avctx, VP8E_SET_ARNR_TYPE, ctx->arnr_type);
- codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction);
- codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices));
+ if (avctx->codec_id == AV_CODEC_ID_VP8) {
+ codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction);
+ codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices));
+ }
#if FF_API_MPV_OPT
FF_DISABLE_DEPRECATION_WARNINGS
if (avctx->mb_threshold) {
@@ -358,11 +562,39 @@ static av_cold int vpx_init(AVCodecContext *avctx,
FF_ENABLE_DEPRECATION_WARNINGS
#endif
codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, ctx->static_thresh);
- codecctl_int(avctx, VP8E_SET_CQ_LEVEL, ctx->crf);
+ if (ctx->crf >= 0)
+ codecctl_int(avctx, VP8E_SET_CQ_LEVEL, ctx->crf);
+ if (ctx->max_intra_rate >= 0)
+ codecctl_int(avctx, VP8E_SET_MAX_INTRA_BITRATE_PCT, ctx->max_intra_rate);
+
+#if CONFIG_LIBVPX_VP9_ENCODER
+ if (avctx->codec_id == AV_CODEC_ID_VP9) {
+ if (ctx->lossless >= 0)
+ codecctl_int(avctx, VP9E_SET_LOSSLESS, ctx->lossless);
+ if (ctx->tile_columns >= 0)
+ codecctl_int(avctx, VP9E_SET_TILE_COLUMNS, ctx->tile_columns);
+ if (ctx->tile_rows >= 0)
+ codecctl_int(avctx, VP9E_SET_TILE_ROWS, ctx->tile_rows);
+ if (ctx->frame_parallel >= 0)
+ codecctl_int(avctx, VP9E_SET_FRAME_PARALLEL_DECODING, ctx->frame_parallel);
+ if (ctx->aq_mode >= 0)
+ codecctl_int(avctx, VP9E_SET_AQ_MODE, ctx->aq_mode);
+ }
+#endif
+
+ av_log(avctx, AV_LOG_DEBUG, "Using deadline: %d\n", ctx->deadline);
//provide dummy value to initialize wrapper, values will be updated each _encode()
- vpx_img_wrap(&ctx->rawimg, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
+ vpx_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1,
(unsigned char*)1);
+#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH)
+ if (avctx->codec_id == AV_CODEC_ID_VP9 && (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH))
+ ctx->rawimg.bit_depth = enccfg.g_bit_depth;
+#endif
+
+ if (ctx->is_alpha)
+ vpx_img_wrap(&ctx->rawimg_alpha, VPX_IMG_FMT_I420, avctx->width, avctx->height, 1,
+ (unsigned char*)1);
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame) {
@@ -374,13 +606,38 @@ static av_cold int vpx_init(AVCodecContext *avctx,
}
static inline void cx_pktcpy(struct FrameListData *dst,
- const struct vpx_codec_cx_pkt *src)
+ const struct vpx_codec_cx_pkt *src,
+ const struct vpx_codec_cx_pkt *src_alpha,
+ VP8Context *ctx)
{
dst->pts = src->data.frame.pts;
dst->duration = src->data.frame.duration;
dst->flags = src->data.frame.flags;
dst->sz = src->data.frame.sz;
dst->buf = src->data.frame.buf;
+ dst->have_sse = 0;
+ /* For alt-ref frame, don't store PSNR or increment frame_number */
+ if (!(dst->flags & VPX_FRAME_IS_INVISIBLE)) {
+ dst->frame_number = ++ctx->frame_number;
+ dst->have_sse = ctx->have_sse;
+ if (ctx->have_sse) {
+ /* associate last-seen SSE to the frame. */
+ /* Transfers ownership from ctx to dst. */
+ /* WARNING! This makes the assumption that PSNR_PKT comes
+ just before the frame it refers to! */
+ memcpy(dst->sse, ctx->sse, sizeof(dst->sse));
+ ctx->have_sse = 0;
+ }
+ } else {
+ dst->frame_number = -1; /* sanity marker */
+ }
+ if (src_alpha) {
+ dst->buf_alpha = src_alpha->data.frame.buf;
+ dst->sz_alpha = src_alpha->data.frame.sz;
+ } else {
+ dst->buf_alpha = NULL;
+ dst->sz_alpha = 0;
+ }
}
/**
@@ -393,7 +650,8 @@ static inline void cx_pktcpy(struct FrameListData *dst,
static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame,
AVPacket *pkt, AVFrame *coded_frame)
{
- int ret = ff_alloc_packet(pkt, cx_frame->sz);
+ int ret = ff_alloc_packet2(avctx, pkt, cx_frame->sz);
+ uint8_t *side_data;
if (ret >= 0) {
memcpy(pkt->data, cx_frame->buf, pkt->size);
pkt->pts = pkt->dts = cx_frame->pts;
@@ -405,9 +663,32 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame,
pkt->flags |= AV_PKT_FLAG_KEY;
} else
coded_frame->pict_type = AV_PICTURE_TYPE_P;
+
+ if (cx_frame->have_sse) {
+ int i;
+ /* Beware of the Y/U/V/all order! */
+ coded_frame->error[0] = cx_frame->sse[1];
+ coded_frame->error[1] = cx_frame->sse[2];
+ coded_frame->error[2] = cx_frame->sse[3];
+ coded_frame->error[3] = 0; // alpha
+ for (i = 0; i < 4; ++i) {
+ avctx->error[i] += coded_frame->error[i];
+ }
+ cx_frame->have_sse = 0;
+ }
+ if (cx_frame->sz_alpha > 0) {
+ side_data = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
+ cx_frame->sz_alpha + 8);
+ if(!side_data) {
+ av_free_packet(pkt);
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ AV_WB64(side_data, 1);
+ memcpy(side_data + 8, cx_frame->buf_alpha, cx_frame->sz_alpha);
+ }
} else {
- av_log(avctx, AV_LOG_ERROR,
- "Error getting output packet of size %zu.\n", cx_frame->sz);
return ret;
}
return pkt->size;
@@ -426,7 +707,9 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out,
{
VP8Context *ctx = avctx->priv_data;
const struct vpx_codec_cx_pkt *pkt;
+ const struct vpx_codec_cx_pkt *pkt_alpha = NULL;
const void *iter = NULL;
+ const void *iter_alpha = NULL;
int size = 0;
if (ctx->coded_frame_list) {
@@ -441,7 +724,9 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out,
/* consume all available output from the encoder before returning. buffers
are only good through the next vpx_codec call */
- while ((pkt = vpx_codec_get_cx_data(&ctx->encoder, &iter))) {
+ while ((pkt = vpx_codec_get_cx_data(&ctx->encoder, &iter)) &&
+ (!ctx->is_alpha ||
+ (ctx->is_alpha && (pkt_alpha = vpx_codec_get_cx_data(&ctx->encoder_alpha, &iter_alpha))))) {
switch (pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT:
if (!size) {
@@ -449,8 +734,8 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out,
/* avoid storing the frame when the list is empty and we haven't yet
provided a frame for output */
- assert(!ctx->coded_frame_list);
- cx_pktcpy(&cx_frame, pkt);
+ av_assert0(!ctx->coded_frame_list);
+ cx_pktcpy(&cx_frame, pkt, pkt_alpha, ctx);
size = storeframe(avctx, &cx_frame, pkt_out, coded_frame);
if (size < 0)
return size;
@@ -463,17 +748,28 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out,
"Frame queue element alloc failed\n");
return AVERROR(ENOMEM);
}
- cx_pktcpy(cx_frame, pkt);
+ cx_pktcpy(cx_frame, pkt, pkt_alpha, ctx);
cx_frame->buf = av_malloc(cx_frame->sz);
if (!cx_frame->buf) {
av_log(avctx, AV_LOG_ERROR,
- "Data buffer alloc (%zu bytes) failed\n",
+ "Data buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n",
cx_frame->sz);
av_freep(&cx_frame);
return AVERROR(ENOMEM);
}
memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz);
+ if (ctx->is_alpha) {
+ cx_frame->buf_alpha = av_malloc(cx_frame->sz_alpha);
+ if (!cx_frame->buf_alpha) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Data buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n",
+ cx_frame->sz_alpha);
+ av_free(cx_frame);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(cx_frame->buf_alpha, pkt_alpha->data.frame.buf, pkt_alpha->data.frame.sz);
+ }
coded_frame_add(&ctx->coded_frame_list, cx_frame);
}
break;
@@ -492,7 +788,14 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out,
stats->sz += pkt->data.twopass_stats.sz;
break;
}
- case VPX_CODEC_PSNR_PKT: //FIXME add support for CODEC_FLAG_PSNR
+ case VPX_CODEC_PSNR_PKT:
+ av_assert0(!ctx->have_sse);
+ ctx->sse[0] = pkt->data.psnr.sse[0];
+ ctx->sse[1] = pkt->data.psnr.sse[1];
+ ctx->sse[2] = pkt->data.psnr.sse[2];
+ ctx->sse[3] = pkt->data.psnr.sse[3];
+ ctx->have_sse = 1;
+ break;
case VPX_CODEC_CUSTOM_PKT:
//ignore unsupported/unrecognized packet types
break;
@@ -507,6 +810,7 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
{
VP8Context *ctx = avctx->priv_data;
struct vpx_image *rawimg = NULL;
+ struct vpx_image *rawimg_alpha = NULL;
int64_t timestamp = 0;
int res, coded_size;
vpx_enc_frame_flags_t flags = 0;
@@ -519,6 +823,25 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
rawimg->stride[VPX_PLANE_Y] = frame->linesize[0];
rawimg->stride[VPX_PLANE_U] = frame->linesize[1];
rawimg->stride[VPX_PLANE_V] = frame->linesize[2];
+ if (ctx->is_alpha) {
+ uint8_t *u_plane, *v_plane;
+ rawimg_alpha = &ctx->rawimg_alpha;
+ rawimg_alpha->planes[VPX_PLANE_Y] = frame->data[3];
+ u_plane = av_malloc(frame->linesize[1] * frame->height);
+ v_plane = av_malloc(frame->linesize[2] * frame->height);
+ if (!u_plane || !v_plane) {
+ av_free(u_plane);
+ av_free(v_plane);
+ return AVERROR(ENOMEM);
+ }
+ memset(u_plane, 0x80, frame->linesize[1] * frame->height);
+ rawimg_alpha->planes[VPX_PLANE_U] = u_plane;
+ memset(v_plane, 0x80, frame->linesize[2] * frame->height);
+ rawimg_alpha->planes[VPX_PLANE_V] = v_plane;
+ rawimg_alpha->stride[VPX_PLANE_Y] = frame->linesize[0];
+ rawimg_alpha->stride[VPX_PLANE_U] = frame->linesize[1];
+ rawimg_alpha->stride[VPX_PLANE_V] = frame->linesize[2];
+ }
timestamp = frame->pts;
if (frame->pict_type == AV_PICTURE_TYPE_I)
flags |= VPX_EFLAG_FORCE_KF;
@@ -530,6 +853,16 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
log_encoder_error(avctx, "Error encoding frame");
return AVERROR_INVALIDDATA;
}
+
+ if (ctx->is_alpha) {
+ res = vpx_codec_encode(&ctx->encoder_alpha, rawimg_alpha, timestamp,
+ avctx->ticks_per_frame, flags, ctx->deadline);
+ if (res != VPX_CODEC_OK) {
+ log_encoder_error(avctx, "Error encoding alpha frame");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
coded_size = queue_frames(avctx, pkt, avctx->coded_frame);
if (!frame && avctx->flags & CODEC_FLAG_PASS1) {
@@ -545,40 +878,87 @@ static int vp8_encode(AVCodecContext *avctx, AVPacket *pkt,
ctx->twopass_stats.sz);
}
+ if (rawimg_alpha) {
+ av_freep(&rawimg_alpha->planes[VPX_PLANE_U]);
+ av_freep(&rawimg_alpha->planes[VPX_PLANE_V]);
+ }
+
*got_packet = !!coded_size;
return 0;
}
#define OFFSET(x) offsetof(VP8Context, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
-static const AVOption options[] = {
- { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, INT_MIN, INT_MAX, VE},
- { "auto-alt-ref", "Enable use of alternate reference "
- "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE},
- { "lag-in-frames", "Number of frames to look ahead for "
- "alternate reference frame selection", OFFSET(lag_in_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE},
- { "arnr-maxframes", "altref noise reduction max frame count", OFFSET(arnr_max_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE},
- { "arnr-strength", "altref noise reduction filter strength", OFFSET(arnr_strength), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE},
- { "arnr-type", "altref noise reduction filter type", OFFSET(arnr_type), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, "arnr_type"},
- { "backward", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "arnr_type" },
- { "forward", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "arnr_type" },
- { "centered", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 3}, 0, 0, VE, "arnr_type" },
- { "deadline", "Time to spend encoding, in microseconds.", OFFSET(deadline), AV_OPT_TYPE_INT, {.i64 = VPX_DL_GOOD_QUALITY}, INT_MIN, INT_MAX, VE, "quality"},
- { "best", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VPX_DL_BEST_QUALITY}, 0, 0, VE, "quality"},
- { "good", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VPX_DL_GOOD_QUALITY}, 0, 0, VE, "quality"},
- { "realtime", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VPX_DL_REALTIME}, 0, 0, VE, "quality"},
- { "error-resilient", "Error resilience configuration", OFFSET(error_resilient), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, VE, "er"},
-#ifdef VPX_ERROR_RESILIENT_DEFAULT
- { "default", "Improve resiliency against losses of whole frames", 0, AV_OPT_TYPE_CONST, {.i64 = VPX_ERROR_RESILIENT_DEFAULT}, 0, 0, VE, "er"},
- { "partitions", "The frame partitions are independently decodable "
- "by the bool decoder, meaning that partitions can be decoded even "
- "though earlier partitions have been lost. Note that intra predicition"
- " is still done over the partition boundary.", 0, AV_OPT_TYPE_CONST, {.i64 = VPX_ERROR_RESILIENT_PARTITIONS}, 0, 0, VE, "er"},
+
+#ifndef VPX_ERROR_RESILIENT_DEFAULT
+#define VPX_ERROR_RESILIENT_DEFAULT 1
+#define VPX_ERROR_RESILIENT_PARTITIONS 2
+#endif
+
+#define COMMON_OPTIONS \
+ { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -16, 16, VE}, \
+ { "auto-alt-ref", "Enable use of alternate reference " \
+ "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE}, \
+ { "lag-in-frames", "Number of frames to look ahead for " \
+ "alternate reference frame selection", OFFSET(lag_in_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, \
+ { "arnr-maxframes", "altref noise reduction max frame count", OFFSET(arnr_max_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, \
+ { "arnr-strength", "altref noise reduction filter strength", OFFSET(arnr_strength), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, \
+ { "arnr-type", "altref noise reduction filter type", OFFSET(arnr_type), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE, "arnr_type"}, \
+ { "backward", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "arnr_type" }, \
+ { "forward", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "arnr_type" }, \
+ { "centered", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 3}, 0, 0, VE, "arnr_type" }, \
+ { "deadline", "Time to spend encoding, in microseconds.", OFFSET(deadline), AV_OPT_TYPE_INT, {.i64 = VPX_DL_GOOD_QUALITY}, INT_MIN, INT_MAX, VE, "quality"}, \
+ { "best", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VPX_DL_BEST_QUALITY}, 0, 0, VE, "quality"}, \
+ { "good", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VPX_DL_GOOD_QUALITY}, 0, 0, VE, "quality"}, \
+ { "realtime", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VPX_DL_REALTIME}, 0, 0, VE, "quality"}, \
+ { "error-resilient", "Error resilience configuration", OFFSET(error_resilient), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, VE, "er"}, \
+ { "max-intra-rate", "Maximum I-frame bitrate (pct) 0=unlimited", OFFSET(max_intra_rate), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, \
+ { "default", "Improve resiliency against losses of whole frames", 0, AV_OPT_TYPE_CONST, {.i64 = VPX_ERROR_RESILIENT_DEFAULT}, 0, 0, VE, "er"}, \
+ { "partitions", "The frame partitions are independently decodable " \
+ "by the bool decoder, meaning that partitions can be decoded even " \
+ "though earlier partitions have been lost. Note that intra predicition" \
+ " is still done over the partition boundary.", 0, AV_OPT_TYPE_CONST, {.i64 = VPX_ERROR_RESILIENT_PARTITIONS}, 0, 0, VE, "er"}, \
+ { "crf", "Select the quality for constant quality mode", offsetof(VP8Context, crf), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 63, VE }, \
+ { "static-thresh", "A change threshold on blocks below which they will be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, \
+
+#define LEGACY_OPTIONS \
+ {"speed", "", offsetof(VP8Context, cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -16, 16, VE}, \
+ {"quality", "", offsetof(VP8Context, deadline), AV_OPT_TYPE_INT, {.i64 = VPX_DL_GOOD_QUALITY}, INT_MIN, INT_MAX, VE, "quality"}, \
+ {"vp8flags", "", offsetof(VP8Context, flags), FF_OPT_TYPE_FLAGS, {.i64 = 0}, 0, UINT_MAX, VE, "flags"}, \
+ {"error_resilient", "enable error resilience", 0, FF_OPT_TYPE_CONST, {.dbl = VP8F_ERROR_RESILIENT}, INT_MIN, INT_MAX, VE, "flags"}, \
+ {"altref", "enable use of alternate reference frames (VP8/2-pass only)", 0, FF_OPT_TYPE_CONST, {.dbl = VP8F_AUTO_ALT_REF}, INT_MIN, INT_MAX, VE, "flags"}, \
+ {"arnr_max_frames", "altref noise reduction max frame count", offsetof(VP8Context, arnr_max_frames), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 15, VE}, \
+ {"arnr_strength", "altref noise reduction filter strength", offsetof(VP8Context, arnr_strength), AV_OPT_TYPE_INT, {.i64 = 3}, 0, 6, VE}, \
+ {"arnr_type", "altref noise reduction filter type", offsetof(VP8Context, arnr_type), AV_OPT_TYPE_INT, {.i64 = 3}, 1, 3, VE}, \
+ {"rc_lookahead", "Number of frames to look ahead for alternate reference frame selection", offsetof(VP8Context, lag_in_frames), AV_OPT_TYPE_INT, {.i64 = 25}, 0, 25, VE}, \
+
+#if CONFIG_LIBVPX_VP8_ENCODER
+static const AVOption vp8_options[] = {
+ COMMON_OPTIONS
+ LEGACY_OPTIONS
+ { NULL }
+};
#endif
- { "crf", "Select the quality for constant quality mode", offsetof(VP8Context, crf), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 63, VE },
- { "static-thresh", "A change threshold on blocks below which they will be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
+
+#if CONFIG_LIBVPX_VP9_ENCODER
+static const AVOption vp9_options[] = {
+ COMMON_OPTIONS
+ { "lossless", "Lossless mode", OFFSET(lossless), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE},
+ { "tile-columns", "Number of tile columns to use, log2", OFFSET(tile_columns), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE},
+ { "tile-rows", "Number of tile rows to use, log2", OFFSET(tile_rows), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE},
+ { "frame-parallel", "Enable frame parallel decodability features", OFFSET(frame_parallel), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE},
+ { "aq-mode", "adaptive quantization mode", OFFSET(aq_mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 3, VE, "aq_mode"},
+ { "none", "Aq not used", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, VE, "aq_mode" }, \
+ { "variance", "Variance based Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "aq_mode" }, \
+ { "complexity", "Complexity based Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "aq_mode" }, \
+ { "cyclic", "Cyclic Refresh Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 3}, 0, 0, VE, "aq_mode" }, \
+ LEGACY_OPTIONS
{ NULL }
};
+#endif
+
+#undef COMMON_OPTIONS
+#undef LEGACY_OPTIONS
static const AVCodecDefault defaults[] = {
{ "qmin", "-1" },
@@ -591,13 +971,13 @@ static const AVCodecDefault defaults[] = {
#if CONFIG_LIBVPX_VP8_ENCODER
static av_cold int vp8_init(AVCodecContext *avctx)
{
- return vpx_init(avctx, &vpx_codec_vp8_cx_algo);
+ return vpx_init(avctx, vpx_codec_vp8_cx());
}
static const AVClass class_vp8 = {
- .class_name = "libvpx encoder",
+ .class_name = "libvpx-vp8 encoder",
.item_name = av_default_item_name,
- .option = options,
+ .option = vp8_options,
.version = LIBAVUTIL_VERSION_INT,
};
@@ -611,7 +991,7 @@ AVCodec ff_libvpx_vp8_encoder = {
.encode2 = vp8_encode,
.close = vp8_free,
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
- .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE },
.priv_class = &class_vp8,
.defaults = defaults,
};
@@ -620,16 +1000,13 @@ AVCodec ff_libvpx_vp8_encoder = {
#if CONFIG_LIBVPX_VP9_ENCODER
static av_cold int vp9_init(AVCodecContext *avctx)
{
- int ret;
- if ((ret = ff_vp9_check_experimental(avctx)))
- return ret;
- return vpx_init(avctx, &vpx_codec_vp9_cx_algo);
+ return vpx_init(avctx, vpx_codec_vp9_cx());
}
static const AVClass class_vp9 = {
- .class_name = "libvpx encoder",
+ .class_name = "libvpx-vp9 encoder",
.item_name = av_default_item_name,
- .option = options,
+ .option = vp9_options,
.version = LIBAVUTIL_VERSION_INT,
};
@@ -643,8 +1020,8 @@ AVCodec ff_libvpx_vp9_encoder = {
.encode2 = vp8_encode,
.close = vp8_free,
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
- .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
.priv_class = &class_vp9,
.defaults = defaults,
+ .init_static_data = ff_vp9_init_static,
};
#endif /* CONFIG_LIBVPX_VP9_ENCODER */
diff --git a/libavcodec/libwavpackenc.c b/libavcodec/libwavpackenc.c
index 34ec013943..77d98a214f 100644
--- a/libavcodec/libwavpackenc.c
+++ b/libavcodec/libwavpackenc.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c
index b981f48245..db96e1637b 100644
--- a/libavcodec/libwebpenc.c
+++ b/libavcodec/libwebpenc.c
@@ -2,213 +2,48 @@
* WebP encoding support via libwebp
* Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * WebP encoder using libwebp
+ * WebP encoder using libwebp (WebPEncode API)
*/
-#include <webp/encode.h>
+#include "libwebpenc_common.h"
-#include "libavutil/common.h"
-#include "libavutil/frame.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/opt.h"
-#include "avcodec.h"
-#include "internal.h"
-
-typedef struct LibWebPContext {
- AVClass *class; // class for AVOptions
- float quality; // lossy quality 0 - 100
- int lossless; // use lossless encoding
- int preset; // configuration preset
- int chroma_warning; // chroma linesize mismatch warning has been printed
- int conversion_warning; // pixel format conversion warning has been printed
- WebPConfig config; // libwebp configuration
-} LibWebPContext;
-
-static int libwebp_error_to_averror(int err)
-{
- switch (err) {
- case VP8_ENC_ERROR_OUT_OF_MEMORY:
- case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
- return AVERROR(ENOMEM);
- case VP8_ENC_ERROR_NULL_PARAMETER:
- case VP8_ENC_ERROR_INVALID_CONFIGURATION:
- case VP8_ENC_ERROR_BAD_DIMENSION:
- return AVERROR(EINVAL);
- }
- return AVERROR_UNKNOWN;
-}
+typedef LibWebPContextCommon LibWebPContext;
static av_cold int libwebp_encode_init(AVCodecContext *avctx)
{
- LibWebPContext *s = avctx->priv_data;
- int ret;
-
- if (avctx->global_quality < 0)
- avctx->global_quality = 75 * FF_QP2LAMBDA;
- s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
- 0.0f, 100.0f);
-
- if (avctx->compression_level < 0 || avctx->compression_level > 6) {
- av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
- avctx->compression_level);
- avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
- }
-
- if (s->preset >= WEBP_PRESET_DEFAULT) {
- ret = WebPConfigPreset(&s->config, s->preset, s->quality);
- if (!ret)
- return AVERROR_UNKNOWN;
- s->lossless = s->config.lossless;
- s->quality = s->config.quality;
- avctx->compression_level = s->config.method;
- } else {
- ret = WebPConfigInit(&s->config);
- if (!ret)
- return AVERROR_UNKNOWN;
-
- s->config.lossless = s->lossless;
- s->config.quality = s->quality;
- s->config.method = avctx->compression_level;
-
- ret = WebPValidateConfig(&s->config);
- if (!ret)
- return AVERROR(EINVAL);
- }
-
- av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
- s->lossless ? "Lossless" : "Lossy", s->quality,
- avctx->compression_level);
-
- return 0;
+ return ff_libwebp_encode_init_common(avctx);
}
static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
LibWebPContext *s = avctx->priv_data;
- AVFrame *alt_frame = NULL;
WebPPicture *pic = NULL;
+ AVFrame *alt_frame = NULL;
WebPMemoryWriter mw = { 0 };
- int ret;
-
- if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
- av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
- WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
- return AVERROR(EINVAL);
- }
-
- pic = av_malloc(sizeof(*pic));
- if (!pic)
- return AVERROR(ENOMEM);
- ret = WebPPictureInit(pic);
- if (!ret) {
- ret = AVERROR_UNKNOWN;
+ int ret = ff_libwebp_get_frame(avctx, s, frame, &alt_frame, &pic);
+ if (ret < 0)
goto end;
- }
- pic->width = avctx->width;
- pic->height = avctx->height;
-
- if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
- if (!s->lossless) {
- /* libwebp will automatically convert RGB input to YUV when
- encoding lossy. */
- if (!s->conversion_warning) {
- av_log(avctx, AV_LOG_WARNING,
- "Using libwebp for RGB-to-YUV conversion. You may want "
- "to consider passing in YUV instead for lossy "
- "encoding.\n");
- s->conversion_warning = 1;
- }
- }
- pic->use_argb = 1;
- pic->argb = (uint32_t *)frame->data[0];
- pic->argb_stride = frame->linesize[0] / 4;
- } else {
- if (frame->linesize[1] != frame->linesize[2]) {
- if (!s->chroma_warning) {
- av_log(avctx, AV_LOG_WARNING,
- "Copying frame due to differing chroma linesizes.\n");
- s->chroma_warning = 1;
- }
- alt_frame = av_frame_alloc();
- if (!alt_frame) {
- ret = AVERROR(ENOMEM);
- goto end;
- }
- alt_frame->width = frame->width;
- alt_frame->height = frame->height;
- alt_frame->format = frame->format;
- ret = av_frame_get_buffer(alt_frame, 32);
- if (ret < 0)
- goto end;
- av_frame_copy(alt_frame, frame);
- frame = alt_frame;
- }
- pic->use_argb = 0;
- pic->y = frame->data[0];
- pic->u = frame->data[1];
- pic->v = frame->data[2];
- pic->y_stride = frame->linesize[0];
- pic->uv_stride = frame->linesize[1];
- if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
- pic->colorspace = WEBP_YUV420A;
- pic->a = frame->data[3];
- pic->a_stride = frame->linesize[3];
- } else {
- pic->colorspace = WEBP_YUV420;
- }
-
- if (s->lossless) {
- /* We do not have a way to automatically prioritize RGB over YUV
- in automatic pixel format conversion based on whether we're
- encoding lossless or lossy, so we do conversion with libwebp as
- a convenience. */
- if (!s->conversion_warning) {
- av_log(avctx, AV_LOG_WARNING,
- "Using libwebp for YUV-to-RGB conversion. You may want "
- "to consider passing in RGB instead for lossless "
- "encoding.\n");
- s->conversion_warning = 1;
- }
-
-#if (WEBP_ENCODER_ABI_VERSION <= 0x201)
- /* libwebp should do the conversion automatically, but there is a
- bug that causes it to return an error instead, so a work-around
- is required.
- See https://code.google.com/p/webp/issues/detail?id=178 */
- pic->memory_ = (void*)1; /* something non-null */
- ret = WebPPictureYUVAToARGB(pic);
- if (!ret) {
- av_log(avctx, AV_LOG_ERROR,
- "WebPPictureYUVAToARGB() failed with error: %d\n",
- pic->error_code);
- ret = libwebp_error_to_averror(pic->error_code);
- goto end;
- }
- pic->memory_ = NULL; /* restore pointer */
-#endif
- }
- }
WebPMemoryWriterInit(&mw);
pic->custom_ptr = &mw;
@@ -218,7 +53,7 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (!ret) {
av_log(avctx, AV_LOG_ERROR, "WebPEncode() failed with error: %d\n",
pic->error_code);
- ret = libwebp_error_to_averror(pic->error_code);
+ ret = ff_libwebp_error_to_averror(pic->error_code);
goto end;
}
@@ -231,7 +66,11 @@ static int libwebp_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
*got_packet = 1;
end:
+#if (WEBP_ENCODER_ABI_VERSION > 0x0203)
+ WebPMemoryWriterClear(&mw);
+#else
free(mw.mem); /* must use free() according to libwebp documentation */
+#endif
WebPPictureFree(pic);
av_freep(&pic);
av_frame_free(&alt_frame);
@@ -239,20 +78,13 @@ end:
return ret;
}
-#define OFFSET(x) offsetof(LibWebPContext, x)
-#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
-static const AVOption options[] = {
- { "lossless", "Use lossless mode", OFFSET(lossless), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
- { "preset", "Configuration preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, WEBP_PRESET_TEXT, VE, "preset" },
- { "none", "do not use a preset", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "preset" },
- { "default", "default preset", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0, VE, "preset" },
- { "picture", "digital picture, like portrait, inner shot", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0, VE, "preset" },
- { "photo", "outdoor photograph, with natural lighting", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO }, 0, 0, VE, "preset" },
- { "drawing", "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" },
- { "icon", "small-sized colorful images", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON }, 0, 0, VE, "preset" },
- { "text", "text-like", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT }, 0, 0, VE, "preset" },
- { NULL },
-};
+static int libwebp_encode_close(AVCodecContext *avctx)
+{
+ LibWebPContextCommon *s = avctx->priv_data;
+ av_frame_free(&s->ref);
+
+ return 0;
+}
static const AVClass class = {
.class_name = "libwebp",
@@ -261,12 +93,6 @@ static const AVClass class = {
.version = LIBAVUTIL_VERSION_INT,
};
-static const AVCodecDefault libwebp_defaults[] = {
- { "compression_level", "4" },
- { "global_quality", "-1" },
- { NULL },
-};
-
AVCodec ff_libwebp_encoder = {
.name = "libwebp",
.long_name = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
@@ -275,6 +101,7 @@ AVCodec ff_libwebp_encoder = {
.priv_data_size = sizeof(LibWebPContext),
.init = libwebp_encode_init,
.encode2 = libwebp_encode_frame,
+ .close = libwebp_encode_close,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_RGB32,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c
new file mode 100644
index 0000000000..e9582016d3
--- /dev/null
+++ b/libavcodec/libwebpenc_animencoder.c
@@ -0,0 +1,150 @@
+/*
+ * WebP encoding support via libwebp
+ * Copyright (c) 2015 Urvang Joshi
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * WebP encoder using libwebp (WebPAnimEncoder API)
+ */
+
+#include "config.h"
+#include "libwebpenc_common.h"
+
+#include <webp/mux.h>
+
+typedef struct LibWebPAnimContext {
+ LibWebPContextCommon cc;
+ WebPAnimEncoder *enc; // the main AnimEncoder object
+ int64_t prev_frame_pts; // pts of the previously encoded frame.
+ int done; // If true, we have assembled the bitstream already
+} LibWebPAnimContext;
+
+static av_cold int libwebp_anim_encode_init(AVCodecContext *avctx)
+{
+ int ret = ff_libwebp_encode_init_common(avctx);
+ if (!ret) {
+ LibWebPAnimContext *s = avctx->priv_data;
+ WebPAnimEncoderOptions enc_options;
+ WebPAnimEncoderOptionsInit(&enc_options);
+ // TODO(urvang): Expose some options on command-line perhaps.
+ s->enc = WebPAnimEncoderNew(avctx->width, avctx->height, &enc_options);
+ if (!s->enc)
+ return AVERROR(EINVAL);
+ s->prev_frame_pts = -1;
+ s->done = 0;
+ }
+ return ret;
+}
+
+static int libwebp_anim_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet) {
+ LibWebPAnimContext *s = avctx->priv_data;
+ int ret;
+
+ if (!frame) {
+ if (s->done) { // Second flush: return empty package to denote finish.
+ *got_packet = 0;
+ return 0;
+ } else { // First flush: assemble bitstream and return it.
+ WebPData assembled_data = { 0 };
+ ret = WebPAnimEncoderAssemble(s->enc, &assembled_data);
+ if (ret) {
+ ret = ff_alloc_packet(pkt, assembled_data.size);
+ if (ret < 0)
+ return ret;
+ memcpy(pkt->data, assembled_data.bytes, assembled_data.size);
+ s->done = 1;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->pts = pkt->dts = s->prev_frame_pts + 1;
+ *got_packet = 1;
+ return 0;
+ } else {
+ av_log(s, AV_LOG_ERROR,
+ "WebPAnimEncoderAssemble() failed with error: %d\n",
+ VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return AVERROR(ENOMEM);
+ }
+ }
+ } else {
+ int timestamp_ms;
+ WebPPicture *pic = NULL;
+ AVFrame *alt_frame = NULL;
+ ret = ff_libwebp_get_frame(avctx, &s->cc, frame, &alt_frame, &pic);
+ if (ret < 0)
+ goto end;
+
+ timestamp_ms =
+ avctx->time_base.num * frame->pts * 1000 / avctx->time_base.den;
+ ret = WebPAnimEncoderAdd(s->enc, pic, timestamp_ms, &s->cc.config);
+ if (!ret) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Encoding WebP frame failed with error: %d\n",
+ pic->error_code);
+ ret = ff_libwebp_error_to_averror(pic->error_code);
+ goto end;
+ }
+
+ pkt->pts = pkt->dts = frame->pts;
+ s->prev_frame_pts = frame->pts; // Save for next frame.
+ ret = 0;
+ *got_packet = 1;
+
+end:
+ WebPPictureFree(pic);
+ av_freep(&pic);
+ av_frame_free(&alt_frame);
+ return ret;
+ }
+}
+
+static int libwebp_anim_encode_close(AVCodecContext *avctx)
+{
+ LibWebPAnimContext *s = avctx->priv_data;
+ av_frame_free(&s->cc.ref);
+ WebPAnimEncoderDelete(s->enc);
+
+ return 0;
+}
+
+static const AVClass class = {
+ .class_name = "libwebp_anim",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_libwebp_anim_encoder = {
+ .name = "libwebp_anim",
+ .long_name = NULL_IF_CONFIG_SMALL("libwebp WebP image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_WEBP,
+ .priv_data_size = sizeof(LibWebPAnimContext),
+ .init = libwebp_anim_encode_init,
+ .encode2 = libwebp_anim_encode_frame,
+ .close = libwebp_anim_encode_close,
+ .capabilities = CODEC_CAP_DELAY,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_RGB32,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ },
+ .priv_class = &class,
+ .defaults = libwebp_defaults,
+};
diff --git a/libavcodec/libwebpenc_common.c b/libavcodec/libwebpenc_common.c
new file mode 100644
index 0000000000..a76b6da5d6
--- /dev/null
+++ b/libavcodec/libwebpenc_common.c
@@ -0,0 +1,254 @@
+/*
+ * WebP encoding support via libwebp
+ * Copyright (c) 2013 Justin Ruggles <justin.ruggles@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
+ * WebP encoder using libwebp: common structs and methods.
+ */
+
+#include "libwebpenc_common.h"
+
+int ff_libwebp_error_to_averror(int err)
+{
+ switch (err) {
+ case VP8_ENC_ERROR_OUT_OF_MEMORY:
+ case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
+ return AVERROR(ENOMEM);
+ case VP8_ENC_ERROR_NULL_PARAMETER:
+ case VP8_ENC_ERROR_INVALID_CONFIGURATION:
+ case VP8_ENC_ERROR_BAD_DIMENSION:
+ return AVERROR(EINVAL);
+ }
+ return AVERROR_UNKNOWN;
+}
+
+av_cold int ff_libwebp_encode_init_common(AVCodecContext *avctx)
+{
+ LibWebPContextCommon *s = avctx->priv_data;
+ int ret;
+
+ if (avctx->global_quality >= 0)
+ s->quality = av_clipf(avctx->global_quality / (float)FF_QP2LAMBDA,
+ 0.0f, 100.0f);
+
+ if (avctx->compression_level < 0 || avctx->compression_level > 6) {
+ av_log(avctx, AV_LOG_WARNING, "invalid compression level: %d\n",
+ avctx->compression_level);
+ avctx->compression_level = av_clip(avctx->compression_level, 0, 6);
+ }
+
+ if (s->preset >= WEBP_PRESET_DEFAULT) {
+ ret = WebPConfigPreset(&s->config, s->preset, s->quality);
+ if (!ret)
+ return AVERROR_UNKNOWN;
+ s->lossless = s->config.lossless;
+ s->quality = s->config.quality;
+ avctx->compression_level = s->config.method;
+ } else {
+ ret = WebPConfigInit(&s->config);
+ if (!ret)
+ return AVERROR_UNKNOWN;
+
+ s->config.lossless = s->lossless;
+ s->config.quality = s->quality;
+ s->config.method = avctx->compression_level;
+
+ ret = WebPValidateConfig(&s->config);
+ if (!ret)
+ return AVERROR(EINVAL);
+ }
+
+ av_log(avctx, AV_LOG_DEBUG, "%s - quality=%.1f method=%d\n",
+ s->lossless ? "Lossless" : "Lossy", s->quality,
+ avctx->compression_level);
+
+ return 0;
+}
+
+int ff_libwebp_get_frame(AVCodecContext *avctx, LibWebPContextCommon *s,
+ const AVFrame *frame, AVFrame **alt_frame_ptr,
+ WebPPicture **pic_ptr) {
+ int ret;
+ WebPPicture *pic = NULL;
+ AVFrame *alt_frame = NULL;
+
+ if (avctx->width > WEBP_MAX_DIMENSION || avctx->height > WEBP_MAX_DIMENSION) {
+ av_log(avctx, AV_LOG_ERROR, "Picture size is too large. Max is %dx%d.\n",
+ WEBP_MAX_DIMENSION, WEBP_MAX_DIMENSION);
+ return AVERROR(EINVAL);
+ }
+
+ *pic_ptr = av_malloc(sizeof(*pic));
+ pic = *pic_ptr;
+ if (!pic)
+ return AVERROR(ENOMEM);
+
+ ret = WebPPictureInit(pic);
+ if (!ret) {
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+ pic->width = avctx->width;
+ pic->height = avctx->height;
+
+ if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
+ if (!s->lossless) {
+ /* libwebp will automatically convert RGB input to YUV when
+ encoding lossy. */
+ if (!s->conversion_warning) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Using libwebp for RGB-to-YUV conversion. You may want "
+ "to consider passing in YUV instead for lossy "
+ "encoding.\n");
+ s->conversion_warning = 1;
+ }
+ }
+ pic->use_argb = 1;
+ pic->argb = (uint32_t *)frame->data[0];
+ pic->argb_stride = frame->linesize[0] / 4;
+ } else {
+ if (frame->linesize[1] != frame->linesize[2] || s->cr_threshold) {
+ if (!s->chroma_warning && !s->cr_threshold) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Copying frame due to differing chroma linesizes.\n");
+ s->chroma_warning = 1;
+ }
+ *alt_frame_ptr = av_frame_alloc();
+ alt_frame = *alt_frame_ptr;
+ if (!alt_frame) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ alt_frame->width = frame->width;
+ alt_frame->height = frame->height;
+ alt_frame->format = frame->format;
+ if (s->cr_threshold)
+ alt_frame->format = AV_PIX_FMT_YUVA420P;
+ ret = av_frame_get_buffer(alt_frame, 32);
+ if (ret < 0)
+ goto end;
+ alt_frame->format = frame->format;
+ av_frame_copy(alt_frame, frame);
+ frame = alt_frame;
+ if (s->cr_threshold) {
+ int x,y, x2, y2, p;
+ int bs = s->cr_size;
+
+ if (!s->ref) {
+ s->ref = av_frame_clone(frame);
+ if (!s->ref) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ }
+
+ alt_frame->format = AV_PIX_FMT_YUVA420P;
+ for (y = 0; y < frame->height; y+= bs) {
+ for (x = 0; x < frame->width; x+= bs) {
+ int skip;
+ int sse = 0;
+ for (p = 0; p < 3; p++) {
+ int bs2 = bs >> !!p;
+ int w = FF_CEIL_RSHIFT(frame->width , !!p);
+ int h = FF_CEIL_RSHIFT(frame->height, !!p);
+ int xs = x >> !!p;
+ int ys = y >> !!p;
+ for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
+ for (x2 = xs; x2 < FFMIN(xs + bs2, w); x2++) {
+ int diff = frame->data[p][frame->linesize[p] * y2 + x2]
+ -s->ref->data[p][frame->linesize[p] * y2 + x2];
+ sse += diff*diff;
+ }
+ }
+ }
+ skip = sse < s->cr_threshold && frame->data[3] != s->ref->data[3];
+ if (!skip)
+ for (p = 0; p < 3; p++) {
+ int bs2 = bs >> !!p;
+ int w = FF_CEIL_RSHIFT(frame->width , !!p);
+ int h = FF_CEIL_RSHIFT(frame->height, !!p);
+ int xs = x >> !!p;
+ int ys = y >> !!p;
+ for (y2 = ys; y2 < FFMIN(ys + bs2, h); y2++) {
+ memcpy(&s->ref->data[p][frame->linesize[p] * y2 + xs],
+ & frame->data[p][frame->linesize[p] * y2 + xs], FFMIN(bs2, w-xs));
+ }
+ }
+ for (y2 = y; y2 < FFMIN(y+bs, frame->height); y2++) {
+ memset(&frame->data[3][frame->linesize[3] * y2 + x],
+ skip ? 0 : 255,
+ FFMIN(bs, frame->width-x));
+ }
+ }
+ }
+ }
+ }
+
+ pic->use_argb = 0;
+ pic->y = frame->data[0];
+ pic->u = frame->data[1];
+ pic->v = frame->data[2];
+ pic->y_stride = frame->linesize[0];
+ pic->uv_stride = frame->linesize[1];
+ if (frame->format == AV_PIX_FMT_YUVA420P) {
+ pic->colorspace = WEBP_YUV420A;
+ pic->a = frame->data[3];
+ pic->a_stride = frame->linesize[3];
+ if (alt_frame)
+ WebPCleanupTransparentArea(pic);
+ } else {
+ pic->colorspace = WEBP_YUV420;
+ }
+
+ if (s->lossless) {
+ /* We do not have a way to automatically prioritize RGB over YUV
+ in automatic pixel format conversion based on whether we're
+ encoding lossless or lossy, so we do conversion with libwebp as
+ a convenience. */
+ if (!s->conversion_warning) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Using libwebp for YUV-to-RGB conversion. You may want "
+ "to consider passing in RGB instead for lossless "
+ "encoding.\n");
+ s->conversion_warning = 1;
+ }
+
+#if (WEBP_ENCODER_ABI_VERSION <= 0x201)
+ /* libwebp should do the conversion automatically, but there is a
+ bug that causes it to return an error instead, so a work-around
+ is required.
+ See https://code.google.com/p/webp/issues/detail?id=178 */
+ pic->memory_ = (void*)1; /* something non-null */
+ ret = WebPPictureYUVAToARGB(pic);
+ if (!ret) {
+ av_log(avctx, AV_LOG_ERROR,
+ "WebPPictureYUVAToARGB() failed with error: %d\n",
+ pic->error_code);
+ ret = libwebp_error_to_averror(pic->error_code);
+ goto end;
+ }
+ pic->memory_ = NULL; /* restore pointer */
+#endif
+ }
+ }
+end:
+ return ret;
+}
diff --git a/libavcodec/libwebpenc_common.h b/libavcodec/libwebpenc_common.h
new file mode 100644
index 0000000000..e74e57939e
--- /dev/null
+++ b/libavcodec/libwebpenc_common.h
@@ -0,0 +1,84 @@
+/*
+ * WebP encoding support via libwebp
+ * Copyright (c) 2013 Justin Ruggles <justin.ruggles@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
+ * WebP encoder using libwebp: common structs and methods.
+ */
+
+#ifndef AVCODEC_LIBWEBPENC_COMMON_H
+#define AVCODEC_LIBWEBPENC_COMMON_H
+
+#include <webp/encode.h>
+
+#include "libavutil/common.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+
+typedef struct LibWebPContextCommon {
+ AVClass *class; // class for AVOptions
+ float quality; // lossy quality 0 - 100
+ int lossless; // use lossless encoding
+ int preset; // configuration preset
+ int chroma_warning; // chroma linesize mismatch warning has been printed
+ int conversion_warning; // pixel format conversion warning has been printed
+ WebPConfig config; // libwebp configuration
+ AVFrame *ref;
+ int cr_size;
+ int cr_threshold;
+} LibWebPContextCommon;
+
+int ff_libwebp_error_to_averror(int err);
+
+av_cold int ff_libwebp_encode_init_common(AVCodecContext *avctx);
+
+int ff_libwebp_get_frame(AVCodecContext *avctx, LibWebPContextCommon *s,
+ const AVFrame *frame, AVFrame **alt_frame_ptr,
+ WebPPicture **pic_ptr);
+
+#define OFFSET(x) offsetof(LibWebPContextCommon, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "lossless", "Use lossless mode", OFFSET(lossless), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "preset", "Configuration preset", OFFSET(preset), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, WEBP_PRESET_TEXT, VE, "preset" },
+ { "none", "do not use a preset", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "preset" },
+ { "default", "default preset", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DEFAULT }, 0, 0, VE, "preset" },
+ { "picture", "digital picture, like portrait, inner shot", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PICTURE }, 0, 0, VE, "preset" },
+ { "photo", "outdoor photograph, with natural lighting", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_PHOTO }, 0, 0, VE, "preset" },
+ { "drawing", "hand or line drawing, with high-contrast details", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_DRAWING }, 0, 0, VE, "preset" },
+ { "icon", "small-sized colorful images", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_ICON }, 0, 0, VE, "preset" },
+ { "text", "text-like", 0, AV_OPT_TYPE_CONST, { .i64 = WEBP_PRESET_TEXT }, 0, 0, VE, "preset" },
+ { "cr_threshold","Conditional replenishment threshold", OFFSET(cr_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
+ { "cr_size" ,"Conditional replenishment block size", OFFSET(cr_size) , AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 256, VE },
+ { "quality" ,"Quality", OFFSET(quality), AV_OPT_TYPE_FLOAT, { .dbl = 75 }, 0, 100, VE },
+ { NULL },
+};
+
+static const AVCodecDefault libwebp_defaults[] = {
+ { "compression_level", "4" },
+ { "global_quality", "-1" },
+ { NULL },
+};
+
+#endif /* AVCODEC_LIBWEBPENC_COMMON_H */
diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 841b824c8a..82c4f2e2f8 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -2,23 +2,24 @@
* H.264 encoding using the x264 library
* Copyright (C) 2005 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/eval.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
#include "libavutil/mem.h"
@@ -48,7 +49,10 @@ typedef struct X264Context {
char *preset;
char *tune;
char *profile;
+ char *level;
int fastfirstpass;
+ char *wpredp;
+ char *x264opts;
float crf;
float crf_max;
int cqp;
@@ -76,6 +80,7 @@ typedef struct X264Context {
int slice_max_size;
char *stats;
int nal_hrd;
+ int avcintra_class;
char *x264_params;
} X264Context;
@@ -96,7 +101,7 @@ static void X264_log(void *p, int level, const char *fmt, va_list args)
static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,
- x264_nal_t *nals, int nnal)
+ const x264_nal_t *nals, int nnal)
{
X264Context *x4 = ctx->priv_data;
uint8_t *p;
@@ -108,16 +113,21 @@ static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,
for (i = 0; i < nnal; i++)
size += nals[i].i_payload;
- if ((ret = ff_alloc_packet(pkt, size)) < 0)
+ if ((ret = ff_alloc_packet2(ctx, pkt, size)) < 0)
return ret;
p = pkt->data;
/* Write the SEI as part of the first frame. */
if (x4->sei_size > 0 && nnal > 0) {
+ if (x4->sei_size > size) {
+ av_log(ctx, AV_LOG_ERROR, "Error: nal buffer is too small\n");
+ return -1;
+ }
memcpy(p, x4->sei, x4->sei_size);
p += x4->sei_size;
x4->sei_size = 0;
+ av_freep(&x4->sei);
}
for (i = 0; i < nnal; i++){
@@ -128,23 +138,42 @@ static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,
return 1;
}
+static int avfmt2_num_planes(int avfmt)
+{
+ switch (avfmt) {
+ case AV_PIX_FMT_YUV420P:
+ case AV_PIX_FMT_YUVJ420P:
+ case AV_PIX_FMT_YUV420P9:
+ case AV_PIX_FMT_YUV420P10:
+ case AV_PIX_FMT_YUV444P:
+ return 3;
+
+ case AV_PIX_FMT_BGR24:
+ case AV_PIX_FMT_RGB24:
+ return 1;
+
+ default:
+ return 3;
+ }
+}
+
static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
int *got_packet)
{
X264Context *x4 = ctx->priv_data;
x264_nal_t *nal;
int nnal, i, ret;
- x264_picture_t pic_out;
+ x264_picture_t pic_out = {0};
AVFrameSideData *side_data;
x264_picture_init( &x4->pic );
x4->pic.img.i_csp = x4->params.i_csp;
if (x264_bit_depth > 8)
x4->pic.img.i_csp |= X264_CSP_HIGH_DEPTH;
- x4->pic.img.i_plane = 3;
+ x4->pic.img.i_plane = avfmt2_num_planes(ctx->pix_fmt);
if (frame) {
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < x4->pic.img.i_plane; i++) {
x4->pic.img.plane[i] = frame->data[i];
x4->pic.img.i_stride[i] = frame->linesize[i];
}
@@ -155,7 +184,9 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
frame->pict_type == AV_PICTURE_TYPE_P ? X264_TYPE_P :
frame->pict_type == AV_PICTURE_TYPE_B ? X264_TYPE_B :
X264_TYPE_AUTO;
- if (x4->params.b_tff != frame->top_field_first) {
+
+ if (x4->avcintra_class < 0) {
+ if (x4->params.b_interlaced && x4->params.b_tff != frame->top_field_first) {
x4->params.b_tff = frame->top_field_first;
x264_encoder_reconfig(x4->enc, &x4->params);
}
@@ -187,6 +218,7 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
}
if (x4->params.rc.i_rc_method == X264_RC_CQP &&
+ x4->cqp >= 0 &&
x4->params.rc.i_qp_constant != x4->cqp) {
x4->params.rc.i_qp_constant = x4->cqp;
x264_encoder_reconfig(x4->enc, &x4->params);
@@ -197,6 +229,7 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
x4->params.rc.f_rf_constant_max = x4->crf_max;
x264_encoder_reconfig(x4->enc, &x4->params);
}
+ }
side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_STEREO3D);
if (side_data) {
@@ -235,7 +268,7 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
}
do {
if (x264_encoder_encode(x4->enc, &nal, &nnal, frame? &x4->pic: NULL, &pic_out) < 0)
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
ret = encode_nals(ctx, pkt, nal, nnal);
if (ret < 0)
@@ -284,6 +317,20 @@ static av_cold int X264_close(AVCodecContext *avctx)
return 0;
}
+#define OPT_STR(opt, param) \
+ do { \
+ int ret; \
+ if (param && (ret = x264_param_parse(&x4->params, opt, param)) < 0) { \
+ if(ret == X264_PARAM_BAD_NAME) \
+ av_log(avctx, AV_LOG_ERROR, \
+ "bad option '%s': '%s'\n", opt, param); \
+ else \
+ av_log(avctx, AV_LOG_ERROR, \
+ "bad value for '%s': '%s'\n", opt, param); \
+ return -1; \
+ } \
+ } while (0)
+
static int convert_pix_fmt(enum AVPixelFormat pix_fmt)
{
switch (pix_fmt) {
@@ -298,6 +345,13 @@ static int convert_pix_fmt(enum AVPixelFormat pix_fmt)
case AV_PIX_FMT_YUVJ444P:
case AV_PIX_FMT_YUV444P9:
case AV_PIX_FMT_YUV444P10: return X264_CSP_I444;
+#ifdef X264_CSP_BGR
+ case AV_PIX_FMT_BGR24:
+ return X264_CSP_BGR;
+
+ case AV_PIX_FMT_RGB24:
+ return X264_CSP_RGB;
+#endif
case AV_PIX_FMT_NV12: return X264_CSP_NV12;
case AV_PIX_FMT_NV16:
case AV_PIX_FMT_NV20: return X264_CSP_NV16;
@@ -314,6 +368,10 @@ static int convert_pix_fmt(enum AVPixelFormat pix_fmt)
static av_cold int X264_init(AVCodecContext *avctx)
{
X264Context *x4 = avctx->priv_data;
+ int sw,sh;
+
+ if (avctx->global_quality > 0)
+ av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is recommended.\n");
x264_param_default(&x4->params);
@@ -321,7 +379,16 @@ static av_cold int X264_init(AVCodecContext *avctx)
if (x4->preset || x4->tune)
if (x264_param_default_preset(&x4->params, x4->preset, x4->tune) < 0) {
+ int i;
av_log(avctx, AV_LOG_ERROR, "Error setting preset/tune %s/%s.\n", x4->preset, x4->tune);
+ av_log(avctx, AV_LOG_INFO, "Possible presets:");
+ for (i = 0; x264_preset_names[i]; i++)
+ av_log(avctx, AV_LOG_INFO, " %s", x264_preset_names[i]);
+ av_log(avctx, AV_LOG_INFO, "\n");
+ av_log(avctx, AV_LOG_INFO, "Possible tunes:");
+ for (i = 0; x264_tune_names[i]; i++)
+ av_log(avctx, AV_LOG_INFO, " %s", x264_tune_names[i]);
+ av_log(avctx, AV_LOG_INFO, "\n");
return AVERROR(EINVAL);
}
@@ -333,6 +400,8 @@ static av_cold int X264_init(AVCodecContext *avctx)
x4->params.i_log_level = X264_LOG_DEBUG;
x4->params.i_csp = convert_pix_fmt(avctx->pix_fmt);
+ OPT_STR("weightp", x4->wpredp);
+
if (avctx->bit_rate) {
x4->params.rc.i_bitrate = avctx->bit_rate / 1000;
x4->params.rc.i_rc_method = X264_RC_ABR;
@@ -361,10 +430,14 @@ static av_cold int X264_init(AVCodecContext *avctx)
(float)avctx->rc_initial_buffer_occupancy / avctx->rc_buffer_size;
}
+ OPT_STR("level", x4->level);
+
if (avctx->i_quant_factor > 0)
x4->params.rc.f_ip_factor = 1 / fabs(avctx->i_quant_factor);
- x4->params.rc.f_pb_factor = avctx->b_quant_factor;
- x4->params.analyse.i_chroma_qp_offset = avctx->chromaoffset;
+ if (avctx->b_quant_factor > 0)
+ x4->params.rc.f_pb_factor = avctx->b_quant_factor;
+ if (avctx->chromaoffset)
+ x4->params.analyse.i_chroma_qp_offset = avctx->chromaoffset;
if (avctx->me_method == ME_EPZS)
x4->params.analyse.i_me_method = X264_ME_DIA;
@@ -395,6 +468,28 @@ static av_cold int X264_init(AVCodecContext *avctx)
x4->params.rc.f_qcompress = avctx->qcompress; /* 0.0 => cbr, 1.0 => constant qp */
if (avctx->refs >= 0)
x4->params.i_frame_reference = avctx->refs;
+ else if (x4->level) {
+ int i;
+ int mbn = FF_CEIL_RSHIFT(avctx->width, 4) * FF_CEIL_RSHIFT(avctx->height, 4);
+ int level_id = -1;
+ char *tail;
+ int scale = X264_BUILD < 129 ? 384 : 1;
+
+ if (!strcmp(x4->level, "1b")) {
+ level_id = 9;
+ } else if (strlen(x4->level) <= 3){
+ level_id = av_strtod(x4->level, &tail) * 10 + 0.5;
+ if (*tail)
+ level_id = -1;
+ }
+ if (level_id <= 0)
+ av_log(avctx, AV_LOG_WARNING, "Failed to parse level\n");
+
+ for (i = 0; i<x264_levels[i].level_idc; i++)
+ if (x264_levels[i].level_idc == level_id)
+ x4->params.i_frame_reference = av_clip(x264_levels[i].dpb / mbn / scale, 1, x4->params.i_frame_reference);
+ }
+
if (avctx->trellis >= 0)
x4->params.analyse.i_trellis = avctx->trellis;
if (avctx->me_range >= 0)
@@ -439,6 +534,13 @@ static av_cold int X264_init(AVCodecContext *avctx)
x4->params.b_bluray_compat = x4->bluray_compat;
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->b_bias != INT_MIN)
x4->params.i_bframe_bias = x4->b_bias;
if (x4->b_pyramid >= 0)
@@ -458,25 +560,68 @@ static av_cold int X264_init(AVCodecContext *avctx)
if (x4->slice_max_size >= 0)
x4->params.i_slice_max_size = x4->slice_max_size;
+ else {
+ /*
+ * Allow x264 to be instructed through AVCodecContext about the maximum
+ * size of the RTP payload. For example, this enables the production of
+ * payload suitable for the H.264 RTP packetization-mode 0 i.e. single
+ * NAL unit per RTP packet.
+ */
+ if (avctx->rtp_payload_size)
+ x4->params.i_slice_max_size = avctx->rtp_payload_size;
+ }
if (x4->fastfirstpass)
x264_param_apply_fastfirstpass(&x4->params);
+ /* Allow specifying the x264 profile through AVCodecContext. */
+ if (!x4->profile)
+ switch (avctx->profile) {
+ case FF_PROFILE_H264_BASELINE:
+ x4->profile = av_strdup("baseline");
+ break;
+ case FF_PROFILE_H264_HIGH:
+ x4->profile = av_strdup("high");
+ break;
+ case FF_PROFILE_H264_HIGH_10:
+ x4->profile = av_strdup("high10");
+ break;
+ case FF_PROFILE_H264_HIGH_422:
+ x4->profile = av_strdup("high422");
+ break;
+ case FF_PROFILE_H264_HIGH_444:
+ x4->profile = av_strdup("high444");
+ break;
+ case FF_PROFILE_H264_MAIN:
+ x4->profile = av_strdup("main");
+ break;
+ default:
+ break;
+ }
+
if (x4->nal_hrd >= 0)
x4->params.i_nal_hrd = x4->nal_hrd;
if (x4->profile)
if (x264_param_apply_profile(&x4->params, x4->profile) < 0) {
+ int i;
av_log(avctx, AV_LOG_ERROR, "Error setting profile %s.\n", x4->profile);
+ av_log(avctx, AV_LOG_INFO, "Possible profiles:");
+ for (i = 0; x264_profile_names[i]; i++)
+ av_log(avctx, AV_LOG_INFO, " %s", x264_profile_names[i]);
+ av_log(avctx, AV_LOG_INFO, "\n");
return AVERROR(EINVAL);
}
x4->params.i_width = avctx->width;
x4->params.i_height = avctx->height;
- x4->params.vui.i_sar_width = avctx->sample_aspect_ratio.num;
- x4->params.vui.i_sar_height = avctx->sample_aspect_ratio.den;
- x4->params.i_fps_num = x4->params.i_timebase_den = avctx->time_base.den;
- x4->params.i_fps_den = x4->params.i_timebase_num = avctx->time_base.num;
+ av_reduce(&sw, &sh, avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 4096);
+ x4->params.vui.i_sar_width = sw;
+ x4->params.vui.i_sar_height = sh;
+ x4->params.i_timebase_den = avctx->time_base.den;
+ x4->params.i_timebase_num = avctx->time_base.num;
+ x4->params.i_fps_num = avctx->time_base.den;
+ x4->params.i_fps_den = avctx->time_base.num * avctx->ticks_per_frame;
x4->params.analyse.b_psnr = avctx->flags & CODEC_FLAG_PSNR;
@@ -495,14 +640,29 @@ static av_cold int X264_init(AVCodecContext *avctx)
avctx->pix_fmt == AV_PIX_FMT_YUVJ444P ||
avctx->color_range == AVCOL_RANGE_JPEG;
- // x264 validates the values internally
- x4->params.vui.i_colorprim = avctx->color_primaries;
- x4->params.vui.i_transfer = avctx->color_trc;
- x4->params.vui.i_colmatrix = avctx->colorspace;
+ if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED)
+ x4->params.vui.i_colmatrix = avctx->colorspace;
+ if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED)
+ x4->params.vui.i_colorprim = avctx->color_primaries;
+ if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED)
+ x4->params.vui.i_transfer = avctx->color_trc;
if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER)
x4->params.b_repeat_headers = 0;
+ if(x4->x264opts){
+ const char *p= x4->x264opts;
+ while(p){
+ char param[256]={0}, val[256]={0};
+ if(sscanf(p, "%255[^:=]=%255[^:]", param, val) == 1){
+ OPT_STR(param, "1");
+ }else
+ OPT_STR(param, val);
+ p= strchr(p, ':');
+ p+=!!p;
+ }
+ }
+
if (x4->x264_params) {
AVDictionary *dict = NULL;
AVDictionaryEntry *en = NULL;
@@ -529,7 +689,7 @@ static av_cold int X264_init(AVCodecContext *avctx)
x4->enc = x264_encoder_open(&x4->params);
if (!x4->enc)
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame)
@@ -542,6 +702,8 @@ static av_cold int X264_init(AVCodecContext *avctx)
s = x264_encoder_headers(x4->enc, &nal, &nnal);
avctx->extradata = p = av_malloc(s);
+ if (!p)
+ return AVERROR(ENOMEM);
for (i = 0; i < nnal; i++) {
/* Don't put the SEI in extradata. */
@@ -549,6 +711,8 @@ static av_cold int X264_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_INFO, "%s\n", nal[i].p_payload+25);
x4->sei_size = nal[i].i_payload;
x4->sei = av_malloc(x4->sei_size);
+ if (!x4->sei)
+ return AVERROR(ENOMEM);
memcpy(x4->sei, nal[i].p_payload, nal[i].i_payload);
continue;
}
@@ -584,6 +748,13 @@ static const enum AVPixelFormat pix_fmts_10bit[] = {
AV_PIX_FMT_NV20,
AV_PIX_FMT_NONE
};
+static const enum AVPixelFormat pix_fmts_8bit_rgb[] = {
+#ifdef X264_CSP_BGR
+ AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGB24,
+#endif
+ AV_PIX_FMT_NONE
+};
static av_cold void X264_init_static(AVCodec *codec)
{
@@ -602,13 +773,20 @@ static const AVOption options[] = {
{ "tune", "Tune the encoding params (cf. x264 --fullhelp)", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE},
{ "profile", "Set profile restrictions (cf. x264 --fullhelp) ", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE},
{ "fastfirstpass", "Use fast settings when encoding first pass", OFFSET(fastfirstpass), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE},
+ {"level", "Specify level (as defined by Annex A)", OFFSET(level), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
+ {"passlogfile", "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
+ {"wpredp", "Weighted prediction for P-frames", OFFSET(wpredp), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
+ {"x264opts", "x264 options", OFFSET(x264opts), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE},
{ "crf", "Select the quality for constant quality mode", OFFSET(crf), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE },
{ "crf_max", "In CRF mode, prevents VBV from lowering quality beyond this point.",OFFSET(crf_max), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE },
{ "qp", "Constant quantization parameter rate control method",OFFSET(cqp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE },
{ "aq-mode", "AQ method", OFFSET(aq_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE, "aq_mode"},
{ "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_NONE}, INT_MIN, INT_MAX, VE, "aq_mode" },
{ "variance", "Variance AQ (complexity mask)", 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_VARIANCE}, INT_MIN, INT_MAX, VE, "aq_mode" },
- { "autovariance", "Auto-variance AQ (experimental)", 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_AUTOVARIANCE}, INT_MIN, INT_MAX, VE, "aq_mode" },
+ { "autovariance", "Auto-variance AQ", 0, AV_OPT_TYPE_CONST, {.i64 = X264_AQ_AUTOVARIANCE}, INT_MIN, INT_MAX, VE, "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, "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_INT, { .i64 = -1 }, -1, 1, VE },
{ "psy-rd", "Strength of psychovisual optimization, in <psy-rd>:<psy-trellis> format.", OFFSET(psy_rd), AV_OPT_TYPE_STRING, {0 }, 0, 0, VE},
@@ -647,27 +825,38 @@ static const AVOption options[] = {
{ "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_NONE}, INT_MIN, INT_MAX, VE, "nal-hrd" },
{ "vbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_VBR}, INT_MIN, INT_MAX, VE, "nal-hrd" },
{ "cbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_CBR}, INT_MIN, INT_MAX, VE, "nal-hrd" },
+ { "avcintra-class","AVC-Intra class 50/100/200", OFFSET(avcintra_class),AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 200 , VE},
{ "x264-params", "Override the x264 configuration using a :-separated list of key=value parameters", OFFSET(x264_params), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ NULL },
};
-static const AVClass class = {
+static const AVClass x264_class = {
.class_name = "libx264",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
+static const AVClass rgbclass = {
+ .class_name = "libx264rgb",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
static const AVCodecDefault x264_defaults[] = {
{ "b", "0" },
{ "bf", "-1" },
+ { "flags2", "0" },
{ "g", "-1" },
{ "i_qfactor", "-1" },
+ { "b_qfactor", "-1" },
{ "qmin", "-1" },
{ "qmax", "-1" },
{ "qdiff", "-1" },
{ "qblur", "-1" },
{ "qcomp", "-1" },
+// { "rc_lookahead", "-1" },
{ "refs", "-1" },
{ "sc_threshold", "-1" },
{ "trellis", "-1" },
@@ -696,9 +885,24 @@ AVCodec ff_libx264_encoder = {
.encode2 = X264_frame,
.close = X264_close,
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
- .priv_class = &class,
+ .priv_class = &x264_class,
.defaults = x264_defaults,
.init_static_data = X264_init_static,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
FF_CODEC_CAP_INIT_CLEANUP,
};
+
+AVCodec ff_libx264rgb_encoder = {
+ .name = "libx264rgb",
+ .long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 RGB"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(X264Context),
+ .init = X264_init,
+ .encode2 = X264_frame,
+ .close = X264_close,
+ .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
+ .priv_class = &rgbclass,
+ .defaults = x264_defaults,
+ .pix_fmts = pix_fmts_8bit_rgb,
+};
diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c
index f5687f6a09..e9240f9491 100644
--- a/libavcodec/libx265.c
+++ b/libavcodec/libx265.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2013-2014 Derek Buitenhuis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -280,7 +280,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
pic ? &x265pic : NULL, &x265pic_out);
if (ret < 0)
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
if (!nnal)
return 0;
@@ -342,10 +342,10 @@ static const enum AVPixelFormat x265_csp_twelve[] = {
static av_cold void libx265_encode_init_csp(AVCodec *codec)
{
- if (x265_max_bit_depth == 8)
- codec->pix_fmts = x265_csp_eight;
- else if (x265_max_bit_depth == 12)
+ if (x265_api_get(10))
codec->pix_fmts = x265_csp_twelve;
+ else if (x265_api_get(8))
+ codec->pix_fmts = x265_csp_eight;
}
#define OFFSET(x) offsetof(libx265Context, x)
diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c
index 7a74e361c1..30d1479836 100644
--- a/libavcodec/libxavs.c
+++ b/libavcodec/libxavs.c
@@ -2,20 +2,20 @@
* AVS encoding using the xavs library
* Copyright (C) 2010 Amanda, Y.N. Wu <amanda11192003@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -88,10 +88,8 @@ static int encode_nals(AVCodecContext *ctx, AVPacket *pkt,
for (i = 0; i < nnal; i++)
size += nals[i].i_payload;
- if ((ret = ff_alloc_packet(pkt, size)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", size);
+ if ((ret = ff_alloc_packet2(ctx, pkt, size)) < 0)
return ret;
- }
p = pkt->data;
/* Write the SEI as part of the first frame. */
@@ -145,7 +143,7 @@ static int XAVS_frame(AVCodecContext *avctx, AVPacket *pkt,
if (!ret) {
if (!frame && !(x4->end_of_stream)) {
- if ((ret = ff_alloc_packet(pkt, 4)) < 0)
+ if ((ret = ff_alloc_packet2(avctx, pkt, 4)) < 0)
return ret;
pkt->data[0] = 0x0;
@@ -153,7 +151,7 @@ static int XAVS_frame(AVCodecContext *avctx, AVPacket *pkt,
pkt->data[2] = 0x01;
pkt->data[3] = 0xb1;
pkt->dts = 2*x4->pts_buffer[(x4->out_frame_count-1)%(avctx->max_b_frames+1)] -
- x4->pts_buffer[(x4->out_frame_count-2)%(avctx->max_b_frames+1)];
+ x4->pts_buffer[(x4->out_frame_count-2)%(avctx->max_b_frames+1)];
x4->end_of_stream = END_OF_STREAM;
*got_packet = 1;
}
@@ -203,7 +201,7 @@ static av_cold int XAVS_close(AVCodecContext *avctx)
XavsContext *x4 = avctx->priv_data;
av_freep(&avctx->extradata);
- av_free(x4->sei);
+ av_freep(&x4->sei);
av_freep(&x4->pts_buffer);
if (x4->enc)
@@ -327,8 +325,9 @@ static av_cold int XAVS_init(AVCodecContext *avctx)
if (avctx->level > 0)
x4->params.i_level_idc = avctx->level;
- x4->params.rc.f_rate_tolerance =
- (float)avctx->bit_rate_tolerance/avctx->bit_rate;
+ if (avctx->bit_rate > 0)
+ x4->params.rc.f_rate_tolerance =
+ (float)avctx->bit_rate_tolerance/avctx->bit_rate;
if ((avctx->rc_buffer_size) &&
(avctx->rc_initial_buffer_occupancy <= avctx->rc_buffer_size)) {
@@ -355,7 +354,7 @@ static av_cold int XAVS_init(AVCodecContext *avctx)
if (!x4->enc)
return -1;
- if (!(x4->pts_buffer = av_mallocz((avctx->max_b_frames+1) * sizeof(*x4->pts_buffer))))
+ if (!(x4->pts_buffer = av_mallocz_array((avctx->max_b_frames+1), sizeof(*x4->pts_buffer))))
return AVERROR(ENOMEM);
avctx->coded_frame = av_frame_alloc();
@@ -364,7 +363,7 @@ static av_cold int XAVS_init(AVCodecContext *avctx)
/* TAG: Do we have GLOBAL HEADER in AVS */
/* We Have PPS and SPS in AVS */
- if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+ if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER && 0) {
xavs_nal_t *nal;
int nnal, s, i, size;
uint8_t *p;
@@ -394,10 +393,10 @@ static av_cold int XAVS_init(AVCodecContext *avctx)
#define OFFSET(x) offsetof(XavsContext, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "crf", "Select the quality for constant quality mode", OFFSET(crf), AV_OPT_TYPE_FLOAT, {-1 }, -1, FLT_MAX, VE },
+ { "crf", "Select the quality for constant quality mode", OFFSET(crf), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE },
{ "qp", "Constant quantization parameter rate control method",OFFSET(cqp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE },
{ "b-bias", "Influences how often B-frames are used", OFFSET(b_bias), AV_OPT_TYPE_INT, {.i64 = INT_MIN}, INT_MIN, INT_MAX, VE },
- { "cplxblur", "Reduce fluctuations in QP (before curve compression)", OFFSET(cplxblur), AV_OPT_TYPE_FLOAT, {-1 }, -1, FLT_MAX, VE},
+ { "cplxblur", "Reduce fluctuations in QP (before curve compression)", OFFSET(cplxblur), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE},
{ "direct-pred", "Direct MV prediction mode", OFFSET(direct_pred), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE, "direct-pred" },
{ "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_DIRECT_PRED_NONE }, 0, 0, VE, "direct-pred" },
{ "spatial", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_DIRECT_PRED_SPATIAL }, 0, 0, VE, "direct-pred" },
@@ -410,7 +409,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass xavs_class = {
.class_name = "libxavs",
.item_name = av_default_item_name,
.option = options,
@@ -433,6 +432,6 @@ AVCodec ff_libxavs_encoder = {
.close = XAVS_close,
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
- .priv_class = &class,
+ .priv_class = &xavs_class,
.defaults = xavs_defaults,
};
diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c
index 46da773052..bd88326c06 100644
--- a/libavcodec/libxvid.c
+++ b/libavcodec/libxvid.c
@@ -2,20 +2,20 @@
* Interface to xvidcore for mpeg4 encoding
* Copyright (c) 2004 Adam Thayer <krevnik@comcast.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,10 +25,10 @@
* @author Adam Thayer (krevnik@comcast.net)
*/
-#include <unistd.h>
#include <xvid.h>
#include "libavutil/cpu.h"
+#include "libavutil/file.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
@@ -37,6 +37,14 @@
#include "libxvid.h"
#include "mpegvideo.h"
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_IO_H
+#include <io.h>
+#endif
+
/**
* Buffer management macros.
*/
@@ -49,7 +57,7 @@
* This stores all the private context for the codec.
*/
struct xvid_context {
- AVClass *class; /**< Handle for Xvid encoder */
+ AVClass *class;
void *encoder_handle; /**< Handle for Xvid encoder */
int xsize; /**< Frame x size */
int ysize; /**< Frame y size */
@@ -61,6 +69,7 @@ struct xvid_context {
char *twopassbuffer; /**< Character buffer for two-pass */
char *old_twopassbuffer; /**< Old character buffer (two-pass) */
char *twopassfile; /**< second pass temp file name */
+ int twopassfd;
unsigned char *intra_matrix; /**< P-Frame Quant Matrix */
unsigned char *inter_matrix; /**< I-Frame Quant Matrix */
int lumi_aq; /**< Lumi masking as an aq method */
@@ -78,6 +87,8 @@ struct xvid_ff_pass1 {
struct xvid_context *context; /**< Pointer to private context */
};
+static int xvid_encode_close(AVCodecContext *avctx);
+
/*
* Xvid 2-Pass Kludge Section
*
@@ -108,7 +119,7 @@ static int xvid_ff_2pass_create(xvid_plg_create_t *param, void **handle)
/* This is because we can safely prevent a buffer overflow */
log[0] = 0;
snprintf(log, BUFFER_REMAINING(log),
- "# avconv 2-pass log file, using xvid codec\n");
+ "# ffmpeg 2-pass log file, using xvid codec\n");
snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log),
"# Do not modify. libxvidcore version: %d.%d.%d\n\n",
XVID_VERSION_MAJOR(XVID_VERSION),
@@ -276,6 +287,8 @@ static int xvid_strip_vol_header(AVCodecContext *avctx, AVPacket *pkt,
/* We need to store the header, so extract it */
if (!avctx->extradata) {
avctx->extradata = av_malloc(vo_len);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
memcpy(avctx->extradata, pkt->data, vo_len);
avctx->extradata_size = vo_len;
}
@@ -348,32 +361,34 @@ static void xvid_correct_framerate(AVCodecContext *avctx)
static av_cold int xvid_encode_init(AVCodecContext *avctx)
{
- int xerr, i;
+ int xerr, i, ret = -1;
int xvid_flags = avctx->flags;
struct xvid_context *x = avctx->priv_data;
uint16_t *intra, *inter;
int fd;
- xvid_plugin_single_t single = { 0 };
- struct xvid_ff_pass1 rc2pass1 = { 0 };
- xvid_plugin_2pass2_t rc2pass2 = { 0 };
- xvid_plugin_lumimasking_t masking_l = { 0 }; /* For lumi masking */
- xvid_plugin_lumimasking_t masking_v = { 0 }; /* For variance AQ */
- xvid_plugin_ssim_t ssim = { 0 };
- xvid_gbl_init_t xvid_gbl_init = { 0 };
- xvid_enc_create_t xvid_enc_create = { 0 };
- xvid_enc_plugin_t plugins[7];
-
- /* Bring in VOP flags from avconv command-line */
- x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */
+ xvid_plugin_single_t single = { 0 };
+ struct xvid_ff_pass1 rc2pass1 = { 0 };
+ xvid_plugin_2pass2_t rc2pass2 = { 0 };
+ xvid_plugin_lumimasking_t masking_l = { 0 }; /* For lumi masking */
+ xvid_plugin_lumimasking_t masking_v = { 0 }; /* For variance AQ */
+ xvid_plugin_ssim_t ssim = { 0 };
+ xvid_gbl_init_t xvid_gbl_init = { 0 };
+ xvid_enc_create_t xvid_enc_create = { 0 };
+ xvid_enc_plugin_t plugins[4];
+
+ x->twopassfd = -1;
+
+ /* Bring in VOP flags from ffmpeg command-line */
+ x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */
if (xvid_flags & CODEC_FLAG_4MV)
- x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */
+ x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */
if (avctx->trellis)
- x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */
+ x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */
if (xvid_flags & CODEC_FLAG_AC_PRED)
- x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */
+ x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */
if (xvid_flags & CODEC_FLAG_GRAY)
- x->vop_flags |= XVID_VOP_GREYSCALE;
+ x->vop_flags |= XVID_VOP_GREYSCALE;
/* Decide which ME quality setting to use */
x->me_flags = 0;
@@ -416,7 +431,7 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
break;
}
- /* Bring in VOL flags from avconv command-line */
+ /* Bring in VOL flags from ffmpeg command-line */
#if FF_API_GMC
if (avctx->flags & CODEC_FLAG_GMC)
x->gmc = 1;
@@ -458,6 +473,18 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
xvid_enc_create.num_zones = 0;
xvid_enc_create.num_threads = avctx->thread_count;
+#if (XVID_VERSION <= 0x010303) && (XVID_VERSION >= 0x010300)
+ /* workaround for a bug in libxvidcore */
+ if (avctx->height <= 16) {
+ if (avctx->thread_count < 2) {
+ xvid_enc_create.num_threads = 0;
+ } else {
+ av_log(avctx, AV_LOG_ERROR,
+ "Too small height for threads > 1.");
+ return AVERROR(EINVAL);
+ }
+ }
+#endif
xvid_enc_create.plugins = plugins;
xvid_enc_create.num_plugins = 0;
@@ -487,26 +514,29 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
rc2pass2.version = XVID_VERSION;
rc2pass2.bitrate = avctx->bit_rate;
- fd = ff_tempfile("xvidff.", &x->twopassfile);
+ fd = av_tempfile("xvidff.", &x->twopassfile, 0, avctx);
if (fd < 0) {
av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write 2-pass pipe\n");
return fd;
}
+ x->twopassfd = fd;
if (!avctx->stats_in) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: No 2-pass information loaded for second pass\n");
- return AVERROR_INVALIDDATA;
+ return AVERROR(EINVAL);
}
- if (strlen(avctx->stats_in) >
- write(fd, avctx->stats_in, strlen(avctx->stats_in))) {
- close(fd);
+ ret = write(fd, avctx->stats_in, strlen(avctx->stats_in));
+ if (ret == -1)
+ ret = AVERROR(errno);
+ else if (strlen(avctx->stats_in) > ret) {
av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write to 2-pass pipe\n");
- return AVERROR(EIO);
+ ret = AVERROR(EIO);
}
+ if (ret < 0)
+ return ret;
- close(fd);
rc2pass2.filename = x->twopassfile;
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2;
plugins[xvid_enc_create.num_plugins].param = &rc2pass2;
@@ -524,12 +554,6 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
if (avctx->lumi_masking != 0.0)
x->lumi_aq = 1;
- if (x->lumi_aq && x->variance_aq) {
- x->variance_aq = 0;
- av_log(avctx, AV_LOG_WARNING,
- "variance_aq is ignored when lumi_aq is set.\n");
- }
-
/* Luminance Masking */
if (x->lumi_aq) {
masking_l.method = 0;
@@ -550,6 +574,11 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
xvid_enc_create.num_plugins++;
}
+ if (x->lumi_aq && x->variance_aq )
+ av_log(avctx, AV_LOG_INFO,
+ "Both lumi_aq and variance_aq are enabled. The resulting quality"
+ "will be the worse one of the two effects made by the AQ.\n");
+
/* SSIM */
if (x->ssim) {
plugins[xvid_enc_create.num_plugins].func = xvid_plugin_ssim;
@@ -594,11 +623,15 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
if (avctx->intra_matrix) {
intra = avctx->intra_matrix;
x->intra_matrix = av_malloc(sizeof(unsigned char) * 64);
+ if (!x->intra_matrix)
+ return AVERROR(ENOMEM);
} else
intra = NULL;
if (avctx->inter_matrix) {
inter = avctx->inter_matrix;
x->inter_matrix = av_malloc(sizeof(unsigned char) * 64);
+ if (!x->inter_matrix)
+ return AVERROR(ENOMEM);
} else
inter = NULL;
@@ -637,11 +670,13 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
if (avctx->max_b_frames > 0 && !x->quicktime_format)
xvid_enc_create.global |= XVID_GLOBAL_PACKED;
+ av_assert0(xvid_enc_create.num_plugins + (!!x->ssim) + (!!x->variance_aq) + (!!x->lumi_aq) <= FF_ARRAY_ELEMS(plugins));
+
/* Create encoder context */
xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL);
if (xerr) {
av_log(avctx, AV_LOG_ERROR, "Xvid: Could not create encoder reference\n");
- return -1;
+ return AVERROR_EXTERNAL;
}
x->encoder_handle = xvid_enc_create.handle;
@@ -665,11 +700,8 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
xvid_enc_frame_t xvid_enc_frame = { 0 };
xvid_enc_stats_t xvid_enc_stats = { 0 };
- if (!user_packet &&
- (ret = av_new_packet(pkt, mb_width * mb_height * MAX_MB_BYTES + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, mb_width*(int64_t)mb_height*MAX_MB_BYTES + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
/* Start setting up the frame */
xvid_enc_frame.version = XVID_VERSION;
@@ -683,7 +715,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (avctx->pix_fmt != AV_PIX_FMT_YUV420P) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: Color spaces other than 420P not supported\n");
- return -1;
+ return AVERROR(EINVAL);
}
xvid_enc_frame.input.csp = XVID_CSP_PLANAR; /* YUV420P */
@@ -704,11 +736,13 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
XVID_TYPE_AUTO;
/* Pixel aspect ratio setting */
- if (avctx->sample_aspect_ratio.num < 1 || avctx->sample_aspect_ratio.num > 255 ||
- avctx->sample_aspect_ratio.den < 1 || avctx->sample_aspect_ratio.den > 255) {
- av_log(avctx, AV_LOG_ERROR, "Invalid pixel aspect ratio %i/%i\n",
+ if (avctx->sample_aspect_ratio.num < 0 || avctx->sample_aspect_ratio.num > 255 ||
+ avctx->sample_aspect_ratio.den < 0 || avctx->sample_aspect_ratio.den > 255) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid pixel aspect ratio %i/%i, limit is 255/255 reducing\n",
avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
- return -1;
+ av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
+ avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 255);
}
xvid_enc_frame.par = XVID_PAR_EXT;
xvid_enc_frame.par_width = avctx->sample_aspect_ratio.num;
@@ -771,7 +805,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
av_log(avctx, AV_LOG_ERROR,
"Xvid: Encoding Error Occurred: %i\n", xerr);
- return xerr;
+ return AVERROR_EXTERNAL;
}
}
@@ -787,12 +821,18 @@ static av_cold int xvid_encode_close(AVCodecContext *avctx)
av_frame_free(&avctx->coded_frame);
av_freep(&avctx->extradata);
if (x->twopassbuffer) {
- av_free(x->twopassbuffer);
- av_free(x->old_twopassbuffer);
+ av_freep(&x->twopassbuffer);
+ av_freep(&x->old_twopassbuffer);
+ avctx->stats_out = NULL;
+ }
+ if (x->twopassfd>=0) {
+ unlink(x->twopassfile);
+ close(x->twopassfd);
+ x->twopassfd = -1;
}
- av_free(x->twopassfile);
- av_free(x->intra_matrix);
- av_free(x->inter_matrix);
+ av_freep(&x->twopassfile);
+ av_freep(&x->intra_matrix);
+ av_freep(&x->inter_matrix);
return 0;
}
diff --git a/libavcodec/libxvid.h b/libavcodec/libxvid.h
index 15f908f6f5..bffe07d808 100644
--- a/libavcodec/libxvid.h
+++ b/libavcodec/libxvid.h
@@ -1,20 +1,20 @@
/*
* copyright (C) 2006 Corey Hickey
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/libxvid_rc.c b/libavcodec/libxvid_rc.c
index 26f3c495c1..0fd030c706 100644
--- a/libavcodec/libxvid_rc.c
+++ b/libavcodec/libxvid_rc.c
@@ -3,75 +3,42 @@
*
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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"
-#if !HAVE_MKSTEMP
-#include <fcntl.h>
+#if HAVE_IO_H
+#include <io.h>
#endif
+
+#if HAVE_UNISTD_H
#include <unistd.h>
+#endif
+
#include <xvid.h>
#include "libavutil/attributes.h"
-#include "libavutil/internal.h"
+#include "libavutil/file.h"
#include "avcodec.h"
#include "libxvid.h"
#include "mpegvideo.h"
-/* Wrapper to work around the lack of mkstemp() on mingw.
- * Also, tries to create file in /tmp first, if possible.
- * *prefix can be a character constant; *filename will be allocated internally.
- * @return file descriptor of opened file (or -1 on error)
- * and opened file name in **filename. */
-int ff_tempfile(const char *prefix, char **filename)
-{
- int fd = -1;
-#if !HAVE_MKSTEMP
- *filename = tempnam(".", prefix);
-#else
- size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */
- *filename = av_malloc(len);
-#endif
- /* -----common section-----*/
- if (!(*filename)) {
- av_log(NULL, AV_LOG_ERROR, "ff_tempfile: Cannot allocate file name\n");
- return AVERROR(ENOMEM);
- }
-#if !HAVE_MKSTEMP
- fd = avpriv_open(*filename, O_RDWR | O_BINARY | O_CREAT, 0444);
-#else
- snprintf(*filename, len, "/tmp/%sXXXXXX", prefix);
- fd = mkstemp(*filename);
- if (fd < 0) {
- snprintf(*filename, len, "./%sXXXXXX", prefix);
- fd = mkstemp(*filename);
- }
-#endif
- /* -----common section-----*/
- if (fd < 0) {
- av_log(NULL, AV_LOG_ERROR, "ff_tempfile: Cannot open temporary file %s\n", *filename);
- return AVERROR(EIO);
- }
- return fd; /* success */
-}
-
av_cold int ff_xvid_rate_control_init(MpegEncContext *s)
{
char *tmp_name;
@@ -79,7 +46,7 @@ av_cold int ff_xvid_rate_control_init(MpegEncContext *s)
xvid_plg_create_t xvid_plg_create = { 0 };
xvid_plugin_2pass2_t xvid_2pass2 = { 0 };
- fd = ff_tempfile("xvidrc.", &tmp_name);
+ fd = av_tempfile("xvidrc.", &tmp_name, 0, s->avctx);
if (fd < 0) {
av_log(NULL, AV_LOG_ERROR, "Can't create temporary pass2 file.\n");
return fd;
@@ -100,7 +67,13 @@ av_cold int ff_xvid_rate_control_init(MpegEncContext *s)
(rce->i_tex_bits + rce->p_tex_bits + rce->misc_bits + 7) / 8,
(rce->header_bits + rce->mv_bits + 7) / 8);
- write(fd, tmp, strlen(tmp));
+ if (write(fd, tmp, strlen(tmp)) < 0) {
+ int ret = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR, "Error %s writing 2pass logfile\n", av_err2str(ret));
+ av_free(tmp_name);
+ close(fd);
+ return ret;
+ }
}
close(fd);
diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c
new file mode 100644
index 0000000000..15c1a5de7b
--- /dev/null
+++ b/libavcodec/libzvbi-teletextdec.c
@@ -0,0 +1,571 @@
+/*
+ * Teletext decoding for ffmpeg
+ * Copyright (c) 2005-2010, 2012 Wolfram Gloger
+ * Copyright (c) 2013 Marton Balint
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "libavcodec/ass.h"
+#include "libavutil/opt.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+
+#include <libzvbi.h>
+
+#define TEXT_MAXSZ (25 * (56 + 1) * 4 + 2)
+#define VBI_NB_COLORS 40
+#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define VBI_R(rgba) (((rgba) >> 0) & 0xFF)
+#define VBI_G(rgba) (((rgba) >> 8) & 0xFF)
+#define VBI_B(rgba) (((rgba) >> 16) & 0xFF)
+#define VBI_A(rgba) (((rgba) >> 24) & 0xFF)
+#define MAX_BUFFERED_PAGES 25
+#define BITMAP_CHAR_WIDTH 12
+#define BITMAP_CHAR_HEIGHT 10
+#define MAX_SLICES 64
+
+typedef struct TeletextPage
+{
+ AVSubtitleRect *sub_rect;
+ int pgno;
+ int subno;
+ int64_t pts;
+} TeletextPage;
+
+typedef struct TeletextContext
+{
+ AVClass *class;
+ char *pgno;
+ int x_offset;
+ int y_offset;
+ int format_id; /* 0 = bitmap, 1 = text/ass */
+ int chop_top;
+ int sub_duration; /* in msec */
+ int transparent_bg;
+ int chop_spaces;
+
+ int lines_processed;
+ TeletextPage *pages;
+ int nb_pages;
+ int64_t pts;
+ int handler_ret;
+
+ vbi_decoder * vbi;
+#ifdef DEBUG
+ vbi_export * ex;
+#endif
+ vbi_sliced sliced[MAX_SLICES];
+} TeletextContext;
+
+static int chop_spaces_utf8(const unsigned char* t, int len)
+{
+ t += len;
+ while (len > 0) {
+ if (*--t != ' ' || (len-1 > 0 && *(t-1) & 0x80))
+ break;
+ --len;
+ }
+ return len;
+}
+
+static void subtitle_rect_free(AVSubtitleRect **sub_rect)
+{
+ av_freep(&(*sub_rect)->pict.data[0]);
+ av_freep(&(*sub_rect)->pict.data[1]);
+ av_freep(&(*sub_rect)->ass);
+ av_freep(sub_rect);
+}
+
+static int create_ass_text(TeletextContext *ctx, const char *text, char **ass)
+{
+ int ret;
+ AVBPrint buf, buf2;
+ const int ts_start = av_rescale_q(ctx->pts, AV_TIME_BASE_Q, (AVRational){1, 100});
+ const int ts_duration = av_rescale_q(ctx->sub_duration, (AVRational){1, 1000}, (AVRational){1, 100});
+
+ /* First we escape the plain text into buf. */
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ ff_ass_bprint_text_event(&buf, text, strlen(text), "", 0);
+ av_bprintf(&buf, "\r\n");
+
+ if (!av_bprint_is_complete(&buf)) {
+ av_bprint_finalize(&buf, NULL);
+ return AVERROR(ENOMEM);
+ }
+
+ /* Then we create the ass dialog line in buf2 from the escaped text in buf. */
+ av_bprint_init(&buf2, 0, AV_BPRINT_SIZE_UNLIMITED);
+ ff_ass_bprint_dialog(&buf2, buf.str, ts_start, ts_duration, 0);
+ av_bprint_finalize(&buf, NULL);
+
+ if (!av_bprint_is_complete(&buf2)) {
+ av_bprint_finalize(&buf2, NULL);
+ return AVERROR(ENOMEM);
+ }
+
+ if ((ret = av_bprint_finalize(&buf2, ass)) < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Draw a page as text */
+static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
+{
+ const char *in;
+ AVBPrint buf;
+ char *vbi_text = av_malloc(TEXT_MAXSZ);
+ int sz;
+
+ if (!vbi_text)
+ return AVERROR(ENOMEM);
+
+ sz = vbi_print_page_region(page, vbi_text, TEXT_MAXSZ-1, "UTF-8",
+ /*table mode*/ TRUE, FALSE,
+ 0, chop_top,
+ page->columns, page->rows-chop_top);
+ if (sz <= 0) {
+ av_log(ctx, AV_LOG_ERROR, "vbi_print error\n");
+ av_free(vbi_text);
+ return AVERROR_EXTERNAL;
+ }
+ vbi_text[sz] = '\0';
+ in = vbi_text;
+ av_bprint_init(&buf, 0, TEXT_MAXSZ);
+
+ if (ctx->chop_spaces) {
+ for (;;) {
+ int nl, sz;
+
+ // skip leading spaces and newlines
+ in += strspn(in, " \n");
+ // compute end of row
+ for (nl = 0; in[nl]; ++nl)
+ if (in[nl] == '\n' && (nl==0 || !(in[nl-1] & 0x80)))
+ break;
+ if (!in[nl])
+ break;
+ // skip trailing spaces
+ sz = chop_spaces_utf8(in, nl);
+ av_bprint_append_data(&buf, in, sz);
+ av_bprintf(&buf, "\n");
+ in += nl;
+ }
+ } else {
+ av_bprintf(&buf, "%s\n", vbi_text);
+ }
+ av_free(vbi_text);
+
+ if (!av_bprint_is_complete(&buf)) {
+ av_bprint_finalize(&buf, NULL);
+ return AVERROR(ENOMEM);
+ }
+
+ if (buf.len) {
+ int ret;
+ sub_rect->type = SUBTITLE_ASS;
+ if ((ret = create_ass_text(ctx, buf.str, &sub_rect->ass)) < 0) {
+ av_bprint_finalize(&buf, NULL);
+ return ret;
+ }
+ av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
+ } else {
+ sub_rect->type = SUBTITLE_NONE;
+ }
+ av_bprint_finalize(&buf, NULL);
+ return 0;
+}
+
+static void fix_transparency(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page,
+ int chop_top, uint8_t transparent_color, int resx, int resy)
+{
+ int iy;
+
+ // Hack for transparency, inspired by VLC code...
+ for (iy = 0; iy < resy; iy++) {
+ uint8_t *pixel = sub_rect->pict.data[0] + iy * sub_rect->pict.linesize[0];
+ vbi_char *vc = page->text + (iy / BITMAP_CHAR_HEIGHT + chop_top) * page->columns;
+ vbi_char *vcnext = vc + page->columns;
+ for (; vc < vcnext; vc++) {
+ uint8_t *pixelnext = pixel + BITMAP_CHAR_WIDTH;
+ switch (vc->opacity) {
+ case VBI_TRANSPARENT_SPACE:
+ memset(pixel, transparent_color, BITMAP_CHAR_WIDTH);
+ break;
+ case VBI_OPAQUE:
+ case VBI_SEMI_TRANSPARENT:
+ if (!ctx->transparent_bg)
+ break;
+ case VBI_TRANSPARENT_FULL:
+ for(; pixel < pixelnext; pixel++)
+ if (*pixel == vc->background)
+ *pixel = transparent_color;
+ break;
+ }
+ pixel = pixelnext;
+ }
+ }
+}
+
+/* Draw a page as bitmap */
+static int gen_sub_bitmap(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
+{
+ int resx = page->columns * BITMAP_CHAR_WIDTH;
+ int resy = (page->rows - chop_top) * BITMAP_CHAR_HEIGHT;
+ uint8_t ci, cmax = 0;
+ int ret;
+ vbi_char *vc = page->text + (chop_top * page->columns);
+ vbi_char *vcend = page->text + (page->rows * page->columns);
+
+ for (; vc < vcend; vc++) {
+ if (vc->opacity != VBI_TRANSPARENT_SPACE) {
+ cmax = VBI_NB_COLORS;
+ break;
+ }
+ }
+
+ if (cmax == 0) {
+ av_log(ctx, AV_LOG_DEBUG, "dropping empty page %3x\n", page->pgno);
+ sub_rect->type = SUBTITLE_NONE;
+ return 0;
+ }
+
+ if ((ret = avpicture_alloc(&sub_rect->pict, AV_PIX_FMT_PAL8, resx, resy)) < 0)
+ return ret;
+ // Yes, we want to allocate the palette on our own because AVSubtitle works this way
+ sub_rect->pict.data[1] = NULL;
+
+ vbi_draw_vt_page_region(page, VBI_PIXFMT_PAL8,
+ sub_rect->pict.data[0], sub_rect->pict.linesize[0],
+ 0, chop_top, page->columns, page->rows - chop_top,
+ /*reveal*/ 1, /*flash*/ 1);
+
+ fix_transparency(ctx, sub_rect, page, chop_top, cmax, resx, resy);
+ sub_rect->x = ctx->x_offset;
+ sub_rect->y = ctx->y_offset + chop_top * BITMAP_CHAR_HEIGHT;
+ sub_rect->w = resx;
+ sub_rect->h = resy;
+ sub_rect->nb_colors = (int)cmax + 1;
+ sub_rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
+ if (!sub_rect->pict.data[1]) {
+ av_freep(&sub_rect->pict.data[0]);
+ return AVERROR(ENOMEM);
+ }
+ for (ci = 0; ci < cmax; ci++) {
+ int r, g, b, a;
+
+ r = VBI_R(page->color_map[ci]);
+ g = VBI_G(page->color_map[ci]);
+ b = VBI_B(page->color_map[ci]);
+ a = VBI_A(page->color_map[ci]);
+ ((uint32_t *)sub_rect->pict.data[1])[ci] = RGBA(r, g, b, a);
+ av_dlog(ctx, "palette %0x\n", ((uint32_t *)sub_rect->pict.data[1])[ci]);
+ }
+ ((uint32_t *)sub_rect->pict.data[1])[cmax] = RGBA(0, 0, 0, 0);
+ sub_rect->type = SUBTITLE_BITMAP;
+ return 0;
+}
+
+static void handler(vbi_event *ev, void *user_data)
+{
+ TeletextContext *ctx = user_data;
+ TeletextPage *new_pages;
+ vbi_page page;
+ int res;
+ char pgno_str[12];
+ vbi_subno subno;
+ vbi_page_type vpt;
+ int chop_top;
+ char *lang;
+
+ snprintf(pgno_str, sizeof pgno_str, "%03x", ev->ev.ttx_page.pgno);
+ av_log(ctx, AV_LOG_DEBUG, "decoded page %s.%02x\n",
+ pgno_str, ev->ev.ttx_page.subno & 0xFF);
+
+ if (strcmp(ctx->pgno, "*") && !strstr(ctx->pgno, pgno_str))
+ return;
+ if (ctx->handler_ret < 0)
+ return;
+
+ res = vbi_fetch_vt_page(ctx->vbi, &page,
+ ev->ev.ttx_page.pgno,
+ ev->ev.ttx_page.subno,
+ VBI_WST_LEVEL_3p5, 25, TRUE);
+
+ if (!res)
+ return;
+
+#ifdef DEBUG
+ fprintf(stderr, "\nSaving res=%d dy0=%d dy1=%d...\n",
+ res, page.dirty.y0, page.dirty.y1);
+ fflush(stderr);
+
+ if (!vbi_export_stdio(ctx->ex, stderr, &page))
+ fprintf(stderr, "failed: %s\n", vbi_export_errstr(ctx->ex));
+#endif
+
+ vpt = vbi_classify_page(ctx->vbi, ev->ev.ttx_page.pgno, &subno, &lang);
+ chop_top = ctx->chop_top ||
+ ((page.rows > 1) && (vpt == VBI_SUBTITLE_PAGE));
+
+ av_log(ctx, AV_LOG_DEBUG, "%d x %d page chop:%d\n",
+ page.columns, page.rows, chop_top);
+
+ if (ctx->nb_pages < MAX_BUFFERED_PAGES) {
+ if ((new_pages = av_realloc_array(ctx->pages, ctx->nb_pages + 1, sizeof(TeletextPage)))) {
+ TeletextPage *cur_page = new_pages + ctx->nb_pages;
+ ctx->pages = new_pages;
+ cur_page->sub_rect = av_mallocz(sizeof(*cur_page->sub_rect));
+ cur_page->pts = ctx->pts;
+ cur_page->pgno = ev->ev.ttx_page.pgno;
+ cur_page->subno = ev->ev.ttx_page.subno;
+ if (cur_page->sub_rect) {
+ res = (ctx->format_id == 0) ?
+ gen_sub_bitmap(ctx, cur_page->sub_rect, &page, chop_top) :
+ gen_sub_text (ctx, cur_page->sub_rect, &page, chop_top);
+ if (res < 0) {
+ av_freep(&cur_page->sub_rect);
+ ctx->handler_ret = res;
+ } else {
+ ctx->pages[ctx->nb_pages++] = *cur_page;
+ }
+ } else {
+ ctx->handler_ret = AVERROR(ENOMEM);
+ }
+ } else {
+ ctx->handler_ret = AVERROR(ENOMEM);
+ }
+ } else {
+ //TODO: If multiple packets contain more than one page, pages may got queued up, and this may happen...
+ av_log(ctx, AV_LOG_ERROR, "Buffered too many pages, dropping page %s.\n", pgno_str);
+ ctx->handler_ret = AVERROR(ENOSYS);
+ }
+
+ vbi_unref_page(&page);
+}
+
+static inline int data_identifier_is_teletext(int data_identifier) {
+ /* See EN 301 775 section 4.4.2. */
+ return (data_identifier >= 0x10 && data_identifier <= 0x1F ||
+ data_identifier >= 0x99 && data_identifier <= 0x9B);
+}
+
+static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size)
+{
+ int lines = 0;
+ while (size >= 2 && lines < MAX_SLICES) {
+ int data_unit_id = buf[0];
+ int data_unit_length = buf[1];
+ if (data_unit_length + 2 > size)
+ return AVERROR_INVALIDDATA;
+ if (data_unit_id == 0x02 || data_unit_id == 0x03) {
+ if (data_unit_length != 0x2c)
+ return AVERROR_INVALIDDATA;
+ else {
+ int line_offset = buf[2] & 0x1f;
+ int field_parity = buf[2] & 0x20;
+ int i;
+ ctx->sliced[lines].id = VBI_SLICED_TELETEXT_B;
+ ctx->sliced[lines].line = (line_offset > 0 ? (line_offset + (field_parity ? 0 : 313)) : 0);
+ for (i = 0; i < 42; i++)
+ ctx->sliced[lines].data[i] = vbi_rev8(buf[4 + i]);
+ lines++;
+ }
+ }
+ size -= data_unit_length + 2;
+ buf += data_unit_length + 2;
+ }
+ if (size)
+ av_log(ctx, AV_LOG_WARNING, "%d bytes remained after slicing data\n", size);
+ return lines;
+}
+
+static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
+{
+ TeletextContext *ctx = avctx->priv_data;
+ AVSubtitle *sub = data;
+ int ret = 0;
+
+ if (!ctx->vbi) {
+ if (!(ctx->vbi = vbi_decoder_new()))
+ return AVERROR(ENOMEM);
+ if (!vbi_event_handler_add(ctx->vbi, VBI_EVENT_TTX_PAGE, handler, ctx)) {
+ vbi_decoder_delete(ctx->vbi);
+ ctx->vbi = NULL;
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (avctx->pkt_timebase.den && pkt->pts != AV_NOPTS_VALUE)
+ ctx->pts = av_rescale_q(pkt->pts, avctx->pkt_timebase, AV_TIME_BASE_Q);
+
+ if (pkt->size) {
+ int lines;
+ const int full_pes_size = pkt->size + 45; /* PES header is 45 bytes */
+
+ // We allow unreasonably big packets, even if the standard only allows a max size of 1472
+ if (full_pes_size < 184 || full_pes_size > 65504 || full_pes_size % 184 != 0)
+ return AVERROR_INVALIDDATA;
+
+ ctx->handler_ret = pkt->size;
+
+ if (data_identifier_is_teletext(*pkt->data)) {
+ if ((lines = slice_to_vbi_lines(ctx, pkt->data + 1, pkt->size - 1)) < 0)
+ return lines;
+ av_dlog(avctx, "ctx=%p buf_size=%d lines=%u pkt_pts=%7.3f\n",
+ ctx, pkt->size, lines, (double)pkt->pts/90000.0);
+ if (lines > 0) {
+#ifdef DEBUG
+ int i;
+ av_log(avctx, AV_LOG_DEBUG, "line numbers:");
+ for(i = 0; i < lines; i++)
+ av_log(avctx, AV_LOG_DEBUG, " %d", ctx->sliced[i].line);
+ av_log(avctx, AV_LOG_DEBUG, "\n");
+#endif
+ vbi_decode(ctx->vbi, ctx->sliced, lines, 0.0);
+ ctx->lines_processed += lines;
+ }
+ }
+ ctx->pts = AV_NOPTS_VALUE;
+ ret = ctx->handler_ret;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ // is there a subtitle to pass?
+ if (ctx->nb_pages) {
+ int i;
+ sub->format = ctx->format_id;
+ sub->start_display_time = 0;
+ sub->end_display_time = ctx->sub_duration;
+ sub->num_rects = 0;
+ sub->pts = ctx->pages->pts;
+
+ if (ctx->pages->sub_rect->type != SUBTITLE_NONE) {
+ sub->rects = av_malloc(sizeof(*sub->rects));
+ if (sub->rects) {
+ sub->num_rects = 1;
+ sub->rects[0] = ctx->pages->sub_rect;
+ } else {
+ ret = AVERROR(ENOMEM);
+ }
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "sending empty sub\n");
+ sub->rects = NULL;
+ }
+ if (!sub->rects) // no rect was passed
+ subtitle_rect_free(&ctx->pages->sub_rect);
+
+ for (i = 0; i < ctx->nb_pages - 1; i++)
+ ctx->pages[i] = ctx->pages[i + 1];
+ ctx->nb_pages--;
+
+ if (ret >= 0)
+ *data_size = 1;
+ } else
+ *data_size = 0;
+
+ return ret;
+}
+
+static int teletext_init_decoder(AVCodecContext *avctx)
+{
+ TeletextContext *ctx = avctx->priv_data;
+ unsigned int maj, min, rev;
+
+ vbi_version(&maj, &min, &rev);
+ if (!(maj > 0 || min > 2 || min == 2 && rev >= 26)) {
+ av_log(avctx, AV_LOG_ERROR, "decoder needs zvbi version >= 0.2.26.\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if (ctx->format_id == 0) {
+ avctx->width = 41 * BITMAP_CHAR_WIDTH;
+ avctx->height = 25 * BITMAP_CHAR_HEIGHT;
+ }
+
+ ctx->vbi = NULL;
+ ctx->pts = AV_NOPTS_VALUE;
+
+#ifdef DEBUG
+ {
+ char *t;
+ ctx->ex = vbi_export_new("text", &t);
+ }
+#endif
+ av_log(avctx, AV_LOG_VERBOSE, "page filter: %s\n", ctx->pgno);
+ return (ctx->format_id == 1) ? ff_ass_subtitle_header_default(avctx) : 0;
+}
+
+static int teletext_close_decoder(AVCodecContext *avctx)
+{
+ TeletextContext *ctx = avctx->priv_data;
+
+ av_dlog(avctx, "lines_total=%u\n", ctx->lines_processed);
+ while (ctx->nb_pages)
+ subtitle_rect_free(&ctx->pages[--ctx->nb_pages].sub_rect);
+ av_freep(&ctx->pages);
+
+ vbi_decoder_delete(ctx->vbi);
+ ctx->vbi = NULL;
+ ctx->pts = AV_NOPTS_VALUE;
+ return 0;
+}
+
+static void teletext_flush(AVCodecContext *avctx)
+{
+ teletext_close_decoder(avctx);
+}
+
+#define OFFSET(x) offsetof(TeletextContext, x)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ {"txt_page", "list of teletext page numbers to decode, * is all", OFFSET(pgno), AV_OPT_TYPE_STRING, {.str = "*"}, 0, 0, SD},
+ {"txt_chop_top", "discards the top teletext line", OFFSET(chop_top), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, SD},
+ {"txt_format", "format of the subtitles (bitmap or text)", OFFSET(format_id), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD, "txt_format"},
+ {"bitmap", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, SD, "txt_format"},
+ {"text", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, SD, "txt_format"},
+ {"txt_left", "x offset of generated bitmaps", OFFSET(x_offset), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 65535, SD},
+ {"txt_top", "y offset of generated bitmaps", OFFSET(y_offset), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 65535, SD},
+ {"txt_chop_spaces", "chops leading and trailing spaces from text", OFFSET(chop_spaces), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, SD},
+ {"txt_duration", "display duration of teletext pages in msecs", OFFSET(sub_duration), AV_OPT_TYPE_INT, {.i64 = 30000}, 0, 86400000, SD},
+ {"txt_transparent", "force transparent background of the teletext", OFFSET(transparent_bg), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD},
+ { NULL },
+};
+
+static const AVClass teletext_class = {
+ .class_name = "libzvbi_teletextdec",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_libzvbi_teletext_decoder = {
+ .name = "libzvbi_teletextdec",
+ .long_name = NULL_IF_CONFIG_SMALL("Libzvbi DVB teletext decoder"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_DVB_TELETEXT,
+ .priv_data_size = sizeof(TeletextContext),
+ .init = teletext_init_decoder,
+ .close = teletext_close_decoder,
+ .decode = teletext_decode_frame,
+ .capabilities = CODEC_CAP_DELAY,
+ .flush = teletext_flush,
+ .priv_class= &teletext_class,
+};
diff --git a/libavcodec/ljpegenc.c b/libavcodec/ljpegenc.c
index fc2ade6ba7..8c0ebf5e08 100644
--- a/libavcodec/ljpegenc.c
+++ b/libavcodec/ljpegenc.c
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -78,7 +78,7 @@ static int ljpeg_encode_bgr(AVCodecContext *avctx, PutBitContext *pb,
const int modified_predictor = y ? predictor : 1;
uint8_t *ptr = frame->data[0] + (linesize * y);
- if (pb->buf_end - pb->buf - (put_bits_count(pb) >> 3) < width * 3 * 3) {
+ if (pb->buf_end - pb->buf - (put_bits_count(pb) >> 3) < width * 3 * 4) {
av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
}
@@ -87,9 +87,15 @@ static int ljpeg_encode_bgr(AVCodecContext *avctx, PutBitContext *pb,
top[i]= left[i]= topleft[i]= buffer[0][i];
for (x = 0; x < width; x++) {
- buffer[x][1] = ptr[3 * x + 0] - ptr[3 * x + 1] + 0x100;
- buffer[x][2] = ptr[3 * x + 2] - ptr[3 * x + 1] + 0x100;
- buffer[x][0] = (ptr[3 * x + 0] + 2 * ptr[3 * x + 1] + ptr[3 * x + 2]) >> 2;
+ if(avctx->pix_fmt == AV_PIX_FMT_BGR24){
+ buffer[x][1] = ptr[3 * x + 0] - ptr[3 * x + 1] + 0x100;
+ buffer[x][2] = ptr[3 * x + 2] - ptr[3 * x + 1] + 0x100;
+ buffer[x][0] = (ptr[3 * x + 0] + 2 * ptr[3 * x + 1] + ptr[3 * x + 2]) >> 2;
+ }else{
+ buffer[x][1] = ptr[4 * x + 0] - ptr[4 * x + 1] + 0x100;
+ buffer[x][2] = ptr[4 * x + 2] - ptr[4 * x + 1] + 0x100;
+ buffer[x][0] = (ptr[4 * x + 0] + 2 * ptr[4 * x + 1] + ptr[4 * x + 2]) >> 2;
+ }
for (i = 0; i < 3; i++) {
int pred, diff;
@@ -214,25 +220,28 @@ static int ljpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
int max_pkt_size = FF_MIN_BUFFER_SIZE;
int ret, header_bits;
- if (avctx->pix_fmt == AV_PIX_FMT_BGR24)
- max_pkt_size += width * height * 3 * 3;
+ if( avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || avctx->pix_fmt == AV_PIX_FMT_BGR24)
+ max_pkt_size += width * height * 3 * 4;
else {
max_pkt_size += mb_width * mb_height * 3 * 4
* s->hsample[0] * s->vsample[0];
}
- if ((ret = ff_alloc_packet(pkt, max_pkt_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", max_pkt_size);
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, max_pkt_size)) < 0)
return ret;
- }
init_put_bits(&pb, pkt->data, pkt->size);
ff_mjpeg_encode_picture_header(avctx, &pb, &s->scantable,
- s->matrix);
+ s->matrix, s->matrix);
header_bits = put_bits_count(&pb);
- if (avctx->pix_fmt == AV_PIX_FMT_BGR24)
+ if( avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || avctx->pix_fmt == AV_PIX_FMT_BGR24)
ret = ljpeg_encode_bgr(avctx, &pb, pict);
else
ret = ljpeg_encode_yuv(avctx, &pb, pict);
@@ -241,6 +250,7 @@ static int ljpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
emms_c();
+ ff_mjpeg_escape_FF(&pb, header_bits >> 3);
ff_mjpeg_encode_picture_trailer(&pb, header_bits);
flush_put_bits(&pb);
@@ -264,7 +274,6 @@ static av_cold int ljpeg_encode_close(AVCodecContext *avctx)
static av_cold int ljpeg_encode_init(AVCodecContext *avctx)
{
LJpegEncContext *s = avctx->priv_data;
- int chroma_v_shift, chroma_h_shift;
if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
avctx->pix_fmt == AV_PIX_FMT_YUV422P ||
@@ -285,26 +294,14 @@ static av_cold int ljpeg_encode_init(AVCodecContext *avctx)
avctx->coded_frame->key_frame = 1;
s->scratch = av_malloc_array(avctx->width + 1, sizeof(*s->scratch));
+ if (!s->scratch)
+ goto fail;
ff_idctdsp_init(&s->idsp, avctx);
ff_init_scantable(s->idsp.idct_permutation, &s->scantable,
ff_zigzag_direct);
- av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift,
- &chroma_v_shift);
-
- if (avctx->pix_fmt == AV_PIX_FMT_BGR24) {
- s->vsample[0] = s->hsample[0] =
- s->vsample[1] = s->hsample[1] =
- s->vsample[2] = s->hsample[2] = 1;
- } else {
- s->vsample[0] = 2;
- s->vsample[1] = 2 >> chroma_v_shift;
- s->vsample[2] = 2 >> chroma_v_shift;
- s->hsample[0] = 2;
- s->hsample[1] = 2 >> chroma_h_shift;
- s->hsample[2] = 2 >> chroma_h_shift;
- }
+ ff_mjpeg_init_hvsample(avctx, s->hsample, s->vsample);
ff_mjpeg_build_huffman_codes(s->huff_size_dc_luminance,
s->huff_code_dc_luminance,
@@ -316,6 +313,9 @@ static av_cold int ljpeg_encode_init(AVCodecContext *avctx)
avpriv_mjpeg_val_dc);
return 0;
+fail:
+ ljpeg_encode_close(avctx);
+ return AVERROR(ENOMEM);
}
AVCodec ff_ljpeg_encoder = {
@@ -327,12 +327,10 @@ AVCodec ff_ljpeg_encoder = {
.init = ljpeg_encode_init,
.encode2 = ljpeg_encode_frame,
.close = ljpeg_encode_close,
- .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVJ420P,
- AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUVJ444P,
- AV_PIX_FMT_BGR24,
- AV_PIX_FMT_YUV420P,
- AV_PIX_FMT_YUV422P,
- AV_PIX_FMT_YUV444P,
- AV_PIX_FMT_NONE },
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .pix_fmts = (const enum AVPixelFormat[]){
+ AV_PIX_FMT_BGR24 , AV_PIX_FMT_BGRA , AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUV420P , AV_PIX_FMT_YUV444P , AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_NONE},
};
diff --git a/libavcodec/loco.c b/libavcodec/loco.c
index 6be081d8ad..aea478d563 100644
--- a/libavcodec/loco.c
+++ b/libavcodec/loco.c
@@ -2,20 +2,20 @@
* LOCO codec
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,7 +46,7 @@ enum LOCO_MODE {
typedef struct LOCOContext {
AVCodecContext *avctx;
int lossy;
- int mode;
+ enum LOCO_MODE mode;
} LOCOContext;
typedef struct RICEContext {
@@ -130,9 +130,15 @@ static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int heigh
{
RICEContext rc;
int val;
+ int ret;
int i, j;
- init_get_bits(&rc.gb, buf, buf_size*8);
+ if(buf_size<=0)
+ return -1;
+
+ if ((ret = init_get_bits8(&rc.gb, buf, buf_size)) < 0)
+ return ret;
+
rc.save = 0;
rc.run = 0;
rc.run2 = 0;
@@ -165,6 +171,23 @@ static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int heigh
return (get_bits_count(&rc.gb) + 7) >> 3;
}
+static void rotate_faulty_loco(uint8_t *data, int width, int height, int stride, int step)
+{
+ int y;
+
+ for (y=1; y<height; y++) {
+ if (width>=y) {
+ memmove(data + y*stride,
+ data + y*(stride + step),
+ step*(width-y));
+ if (y+1 < height)
+ memmove(data + y*stride + step*(width-y),
+ data + (y+1)*stride,
+ step*y);
+ }
+ }
+}
+
static int decode_frame(AVCodecContext *avctx,
void *data, int *got_frame,
AVPacket *avpkt)
@@ -175,88 +198,72 @@ static int decode_frame(AVCodecContext *avctx,
AVFrame * const p = data;
int decoded, ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->key_frame = 1;
+#define ADVANCE_BY_DECODED do { \
+ if (decoded < 0 || decoded >= buf_size) goto buf_too_small; \
+ buf += decoded; buf_size -= decoded; \
+} while(0)
switch(l->mode) {
case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY:
decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 1);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
+ ADVANCE_BY_DECODED;
decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height,
p->linesize[1], buf, buf_size, 1);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
+ ADVANCE_BY_DECODED;
decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height,
p->linesize[2], buf, buf_size, 1);
break;
case LOCO_CYV12: case LOCO_YV12:
decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
p->linesize[0], buf, buf_size, 1);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
+ ADVANCE_BY_DECODED;
decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2,
p->linesize[2], buf, buf_size, 1);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
+ ADVANCE_BY_DECODED;
decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2,
p->linesize[1], buf, buf_size, 1);
break;
case LOCO_CRGB: case LOCO_RGB:
decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height,
-p->linesize[0], buf, buf_size, 3);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
+ ADVANCE_BY_DECODED;
decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height,
-p->linesize[0], buf, buf_size, 3);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
+ ADVANCE_BY_DECODED;
decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height,
-p->linesize[0], buf, buf_size, 3);
+ if (avctx->width & 1)
+ rotate_faulty_loco(p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, -p->linesize[0], 3);
break;
+ case LOCO_CRGBA:
case LOCO_RGBA:
- decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height,
- p->linesize[0], buf, buf_size, 4);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
- decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height,
- p->linesize[0], buf, buf_size, 4);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
- decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height,
- p->linesize[0], buf, buf_size, 4);
- if (decoded >= buf_size)
- goto buf_too_small;
- buf += decoded; buf_size -= decoded;
-
- decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height,
- p->linesize[0], buf, buf_size, 4);
+ decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height,
+ -p->linesize[0], buf, buf_size, 4);
+ ADVANCE_BY_DECODED;
+ decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height,
+ -p->linesize[0], buf, buf_size, 4);
+ ADVANCE_BY_DECODED;
+ decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height,
+ -p->linesize[0], buf, buf_size, 4);
+ ADVANCE_BY_DECODED;
+ decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 3, avctx->width, avctx->height,
+ -p->linesize[0], buf, buf_size, 4);
break;
+ default:
+ av_assert0(0);
}
+ if (decoded < 0 || decoded > buf_size)
+ goto buf_too_small;
+ buf_size -= decoded;
+
*got_frame = 1;
- return buf_size;
+ return avpkt->size - buf_size;
buf_too_small:
av_log(avctx, AV_LOG_ERROR, "Input data too small.\n");
return AVERROR(EINVAL);
@@ -303,7 +310,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
break;
case LOCO_CRGBA:
case LOCO_RGBA:
- avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ avctx->pix_fmt = AV_PIX_FMT_BGRA;
break;
default:
av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode);
diff --git a/libavcodec/lossless_audiodsp.c b/libavcodec/lossless_audiodsp.c
new file mode 100644
index 0000000000..32f4c9e856
--- /dev/null
+++ b/libavcodec/lossless_audiodsp.c
@@ -0,0 +1,49 @@
+/*
+ * Monkey's Audio lossless audio decoder
+ * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
+ * based upon libdemac from Dave Chapman.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "lossless_audiodsp.h"
+
+static int32_t scalarproduct_and_madd_int16_c(int16_t *v1, const int16_t *v2,
+ const int16_t *v3,
+ int order, int mul)
+{
+ int res = 0;
+
+ while (order--) {
+ res += *v1 * *v2++;
+ *v1++ += mul * *v3++;
+ }
+ return res;
+}
+
+av_cold void ff_llauddsp_init(LLAudDSPContext *c)
+{
+ c->scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_c;
+
+ if (ARCH_ARM)
+ ff_llauddsp_init_arm(c);
+ if (ARCH_PPC)
+ ff_llauddsp_init_ppc(c);
+ if (ARCH_X86)
+ ff_llauddsp_init_x86(c);
+}
diff --git a/libavcodec/lossless_audiodsp.h b/libavcodec/lossless_audiodsp.h
new file mode 100644
index 0000000000..9ce2e63d45
--- /dev/null
+++ b/libavcodec/lossless_audiodsp.h
@@ -0,0 +1,46 @@
+/*
+ * Monkey's Audio lossless audio decoder
+ * Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
+ * based upon libdemac from Dave Chapman.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_LLAUDDSP_H
+#define AVCODEC_LLAUDDSP_H
+
+#include <stdint.h>
+
+typedef struct LLAudDSPContext {
+ /**
+ * Calculate scalar product of v1 and v2,
+ * and v1[i] += v3[i] * mul
+ * @param len length of vectors, should be multiple of 16,
+ * or padd v3 and v1 or v2 with zeros.
+ */
+ int32_t (*scalarproduct_and_madd_int16)(int16_t *v1 /* align 16 */,
+ const int16_t *v2,
+ const int16_t *v3,
+ int len, int mul);
+} LLAudDSPContext;
+
+void ff_llauddsp_init(LLAudDSPContext *c);
+void ff_llauddsp_init_arm(LLAudDSPContext *c);
+void ff_llauddsp_init_ppc(LLAudDSPContext *c);
+void ff_llauddsp_init_x86(LLAudDSPContext *c);
+
+#endif /* AVCODEC_LLAUDDSP_H */
diff --git a/libavcodec/lossless_videodsp.c b/libavcodec/lossless_videodsp.c
new file mode 100644
index 0000000000..3491621dc4
--- /dev/null
+++ b/libavcodec/lossless_videodsp.c
@@ -0,0 +1,128 @@
+/*
+ * Lossless video DSP utils
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "avcodec.h"
+#include "lossless_videodsp.h"
+#include "libavcodec/mathops.h"
+
+static void add_int16_c(uint16_t *dst, const uint16_t *src, unsigned mask, int w){
+ long i;
+ unsigned long pw_lsb = (mask >> 1) * 0x0001000100010001ULL;
+ unsigned long pw_msb = pw_lsb + 0x0001000100010001ULL;
+ for (i = 0; i <= w - (int)sizeof(long)/2; i += sizeof(long)/2) {
+ long a = *(long*)(src+i);
+ long b = *(long*)(dst+i);
+ *(long*)(dst+i) = ((a&pw_lsb) + (b&pw_lsb)) ^ ((a^b)&pw_msb);
+ }
+ for(; i<w; i++)
+ dst[i] = (dst[i] + src[i]) & mask;
+}
+
+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)){
+ for(i=0; i+3<w; i+=4){
+ dst[i+0] = (src1[i+0]-src2[i+0]) & mask;
+ dst[i+1] = (src1[i+1]-src2[i+1]) & mask;
+ dst[i+2] = (src1[i+2]-src2[i+2]) & mask;
+ dst[i+3] = (src1[i+3]-src2[i+3]) & mask;
+ }
+ }else
+#endif
+ {
+ unsigned long pw_lsb = (mask >> 1) * 0x0001000100010001ULL;
+ unsigned long pw_msb = pw_lsb + 0x0001000100010001ULL;
+
+ 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<w; i++)
+ dst[i] = (src1[i] - src2[i]) & mask;
+}
+
+static void add_hfyu_median_pred_int16_c(uint16_t *dst, const uint16_t *src, const uint16_t *diff, unsigned mask, int w, int *left, int *left_top){
+ int i;
+ uint16_t l, lt;
+
+ l = *left;
+ lt = *left_top;
+
+ for(i=0; i<w; i++){
+ l = (mid_pred(l, src[i], (l + src[i] - lt) & mask) + diff[i]) & mask;
+ lt = src[i];
+ dst[i] = l;
+ }
+
+ *left = l;
+ *left_top = lt;
+}
+
+static void sub_hfyu_median_pred_int16_c(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w, int *left, int *left_top){
+ int i;
+ uint16_t l, lt;
+
+ l = *left;
+ lt = *left_top;
+
+ for(i=0; i<w; i++){
+ const int pred = mid_pred(l, src1[i], (l + src1[i] - lt) & mask);
+ lt = src1[i];
+ l = src2[i];
+ dst[i] = (l - pred) & mask;
+ }
+
+ *left = l;
+ *left_top = lt;
+}
+
+static int add_hfyu_left_pred_int16_c(uint16_t *dst, const uint16_t *src, unsigned mask, int w, unsigned acc){
+ int i;
+
+ for(i=0; i<w-1; i++){
+ acc+= src[i];
+ dst[i]= acc & mask;
+ i++;
+ acc+= src[i];
+ dst[i]= acc & mask;
+ }
+
+ for(; i<w; i++){
+ acc+= src[i];
+ dst[i]= acc & mask;
+ }
+
+ return acc;
+}
+
+
+void ff_llviddsp_init(LLVidDSPContext *c, AVCodecContext *avctx)
+{
+ c->add_int16 = add_int16_c;
+ c->diff_int16= diff_int16_c;
+ c->add_hfyu_left_pred_int16 = add_hfyu_left_pred_int16_c;
+ c->add_hfyu_median_pred_int16 = add_hfyu_median_pred_int16_c;
+ c->sub_hfyu_median_pred_int16 = sub_hfyu_median_pred_int16_c;
+
+ if (ARCH_X86)
+ ff_llviddsp_init_x86(c, avctx);
+}
diff --git a/libavcodec/lossless_videodsp.h b/libavcodec/lossless_videodsp.h
new file mode 100644
index 0000000000..040902e7ba
--- /dev/null
+++ b/libavcodec/lossless_videodsp.h
@@ -0,0 +1,40 @@
+/*
+ * Lossless video DSP utils
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_LOSSLESS_VIDEODSP_H
+#define AVCODEC_LOSSLESS_VIDEODSP_H
+
+#include "avcodec.h"
+#include "libavutil/cpu.h"
+
+typedef struct LLVidDSPContext {
+ void (*add_int16)(uint16_t *dst/*align 16*/, const uint16_t *src/*align 16*/, unsigned mask, int w);
+ void (*diff_int16)(uint16_t *dst/*align 16*/, const uint16_t *src1/*align 16*/, const uint16_t *src2/*align 1*/, unsigned mask, int w);
+
+ void (*sub_hfyu_median_pred_int16)(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w, int *left, int *left_top);
+ void (*add_hfyu_median_pred_int16)(uint16_t *dst, const uint16_t *top, const uint16_t *diff, unsigned mask, int w, int *left, int *left_top);
+ int (*add_hfyu_left_pred_int16)(uint16_t *dst, const uint16_t *src, unsigned mask, int w, unsigned left);
+} LLVidDSPContext;
+
+void ff_llviddsp_init(LLVidDSPContext *llviddsp, AVCodecContext *avctx);
+void ff_llviddsp_init_x86(LLVidDSPContext *llviddsp, AVCodecContext *avctx);
+
+#endif //AVCODEC_LOSSLESS_VIDEODSP_H
diff --git a/libavcodec/lpc.c b/libavcodec/lpc.c
index 1482e57615..deb02e7f58 100644
--- a/libavcodec/lpc.c
+++ b/libavcodec/lpc.c
@@ -2,20 +2,20 @@
* LPC utility code
* Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#define LPC_USE_DOUBLE
#include "lpc.h"
+#include "libavutil/avassert.h"
/**
@@ -38,7 +39,7 @@ static void lpc_apply_welch_window_c(const int32_t *data, int len,
/* The optimization in commit fa4ed8c does not support odd len.
* If someone wants odd len extend that change. */
- assert(!(len & 1));
+ av_assert2(!(len & 1));
n2 = (len >> 1);
c = 2.0 / (len - 1.0);
@@ -179,8 +180,9 @@ int ff_lpc_calc_coefs(LPCContext *s,
int i, j, pass = 0;
int opt_order;
- assert(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER &&
+ av_assert2(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER &&
lpc_type > FF_LPC_TYPE_FIXED);
+ av_assert0(lpc_type == FF_LPC_TYPE_CHOLESKY || lpc_type == FF_LPC_TYPE_LEVINSON);
/* reinit LPC context if parameters have changed */
if (blocksize != s->blocksize || max_order != s->max_order ||
@@ -189,6 +191,9 @@ int ff_lpc_calc_coefs(LPCContext *s,
ff_lpc_init(s, blocksize, max_order, lpc_type);
}
+ if(lpc_passes <= 0)
+ lpc_passes = 2;
+
if (lpc_type == FF_LPC_TYPE_LEVINSON || (lpc_type == FF_LPC_TYPE_CHOLESKY && lpc_passes > 1)) {
s->lpc_apply_welch_window(samples, blocksize, s->windowed_samples);
@@ -203,7 +208,7 @@ int ff_lpc_calc_coefs(LPCContext *s,
}
if (lpc_type == FF_LPC_TYPE_CHOLESKY) {
- LLSModel m[2];
+ LLSModel *m = s->lls_models;
LOCAL_ALIGNED(32, double, var, [FFALIGN(MAX_LPC_ORDER+1,4)]);
double av_uninit(weight);
memset(var, 0, FFALIGN(MAX_LPC_ORDER+1,4)*sizeof(*var));
@@ -244,6 +249,7 @@ int ff_lpc_calc_coefs(LPCContext *s,
for(i=max_order-1; i>0; i--)
ref[i] = ref[i-1] - ref[i];
}
+
opt_order = max_order;
if(omethod == ORDER_METHOD_EST) {
diff --git a/libavcodec/lpc.h b/libavcodec/lpc.h
index 642854c59a..96acb37146 100644
--- a/libavcodec/lpc.h
+++ b/libavcodec/lpc.h
@@ -2,20 +2,20 @@
* LPC utility code
* Copyright (c) 2006 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,8 @@
#define AVCODEC_LPC_H
#include <stdint.h>
+#include "libavutil/avassert.h"
+#include "libavutil/lls.h"
#define ORDER_METHOD_EST 0
#define ORDER_METHOD_2LEVEL 1
@@ -66,7 +68,7 @@ typedef struct LPCContext {
/**
* Perform autocorrelation on input samples with delay of 0 to lag.
* @param data input samples.
- * constraints: no alignment needed, but must have have at
+ * constraints: no alignment needed, but must have at
* least lag*sizeof(double) valid bytes preceding it, and
* size must be at least (len+1)*sizeof(double) if data is
* 16-byte aligned or (len+2)*sizeof(double) if data is
@@ -78,6 +80,9 @@ typedef struct LPCContext {
*/
void (*lpc_compute_autocorr)(const double *data, int len, int lag,
double *autoc);
+
+ // TODO: these should be allocated to reduce ABI compatibility issues
+ LLSModel lls_models[2];
} LPCContext;
@@ -155,6 +160,8 @@ static inline int compute_lpc_coefs(const LPC_TYPE *autoc, int max_order,
LPC_TYPE err = 0;
LPC_TYPE *lpc_last = lpc;
+ av_assert2(normalize || !fail);
+
if (normalize)
err = *autoc++;
diff --git a/libavcodec/lsp.c b/libavcodec/lsp.c
index 8a05aede62..17f59ea77d 100644
--- a/libavcodec/lsp.c
+++ b/libavcodec/lsp.c
@@ -4,20 +4,20 @@
* Copyright (c) 2007 Reynaldo H. Verdejo Pinochet (QCELP decoder)
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,8 @@
#define FRAC_BITS 14
#include "mathops.h"
#include "lsp.h"
+#include "libavcodec/mips/lsp_mips.h"
+#include "libavutil/avassert.h"
void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsfq_min, int lsfq_max, int lp_order)
{
@@ -73,7 +75,7 @@ static int16_t ff_cos(uint16_t arg)
uint8_t offset= arg;
uint8_t ind = arg >> 8;
- assert(arg <= 0x3fff);
+ av_assert2(arg <= 0x3fff);
return tab_cos[ind] + (offset * (tab_cos[ind+1] - tab_cos[ind]) >> 8);
}
@@ -173,7 +175,11 @@ void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd
/* LSP values for first subframe (3.2.5 of G.729, Equation 24)*/
for(i=0; i<lp_order; i++)
+#ifdef G729_BITEXACT
+ lsp_1st[i] = (lsp_2nd[i] >> 1) + (lsp_prev[i] >> 1);
+#else
lsp_1st[i] = (lsp_2nd[i] + lsp_prev[i]) >> 1;
+#endif
ff_acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1);
@@ -181,6 +187,7 @@ void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd
ff_acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1);
}
+#ifndef ff_lsp2polyf
void ff_lsp2polyf(const double *lsp, double *f, int lp_half_order)
{
int i, j;
@@ -197,13 +204,14 @@ void ff_lsp2polyf(const double *lsp, double *f, int lp_half_order)
f[1] += val;
}
}
+#endif /* ff_lsp2polyf */
void ff_acelp_lspd2lpc(const double *lsp, float *lpc, int lp_half_order)
{
double pa[MAX_LP_HALF_ORDER+1], qa[MAX_LP_HALF_ORDER+1];
float *lpc2 = lpc + (lp_half_order << 1) - 1;
- assert(lp_half_order <= MAX_LP_HALF_ORDER);
+ av_assert2(lp_half_order <= MAX_LP_HALF_ORDER);
ff_lsp2polyf(lsp, pa, lp_half_order);
ff_lsp2polyf(lsp + 1, qa, lp_half_order);
diff --git a/libavcodec/lsp.h b/libavcodec/lsp.h
index 4b955678ee..46a2d47beb 100644
--- a/libavcodec/lsp.h
+++ b/libavcodec/lsp.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2008 Vladimir Voroshilov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/lzw.c b/libavcodec/lzw.c
index fae5687ab7..6832c122a2 100644
--- a/libavcodec/lzw.c
+++ b/libavcodec/lzw.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -93,12 +93,6 @@ static int lzw_get_code(struct LZWState * s)
return c & s->curmask;
}
-int ff_lzw_size_read(LZWState *p)
-{
- struct LZWState *s = p;
- return bytestream2_tell(&s->gb);
-}
-
void ff_lzw_decode_tail(LZWState *p)
{
struct LZWState *s = (struct LZWState *)p;
diff --git a/libavcodec/lzw.h b/libavcodec/lzw.h
index d925d35e27..4653c1c74f 100644
--- a/libavcodec/lzw.h
+++ b/libavcodec/lzw.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,7 +47,6 @@ void ff_lzw_decode_open(LZWState **p);
void ff_lzw_decode_close(LZWState **p);
int ff_lzw_decode_init(LZWState *s, int csize, const uint8_t *buf, int buf_size, int mode);
int ff_lzw_decode(LZWState *s, uint8_t *buf, int len);
-int ff_lzw_size_read(LZWState *lzw);
void ff_lzw_decode_tail(LZWState *lzw);
/** LZW encode state */
diff --git a/libavcodec/lzwenc.c b/libavcodec/lzwenc.c
index 7c37bf2094..03080ee587 100644
--- a/libavcodec/lzwenc.c
+++ b/libavcodec/lzwenc.c
@@ -2,20 +2,20 @@
* LZW encoder
* Copyright (c) 2007 Bartlomiej Wolowiec
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -77,7 +77,7 @@ static inline int hash(int head, const int add)
head ^= (add << LZW_HASH_SHIFT);
if (head >= LZW_HASH_SIZE)
head -= LZW_HASH_SIZE;
- assert(head >= 0 && head < LZW_HASH_SIZE);
+ av_assert2(head >= 0 && head < LZW_HASH_SIZE);
return head;
}
@@ -112,7 +112,7 @@ static inline int hashOffset(const int head)
*/
static inline void writeCode(LZWEncodeState * s, int c)
{
- assert(0 <= c && c < 1 << s->bits);
+ av_assert2(0 <= c && c < 1 << s->bits);
s->put_bits(&s->pb, s->bits, c);
}
@@ -208,7 +208,7 @@ void ff_lzw_encode_init(LZWEncodeState *s, uint8_t *outbuf, int outsize,
s->maxbits = maxbits;
init_put_bits(&s->pb, outbuf, outsize);
s->bufsize = outsize;
- assert(s->maxbits >= 9 && s->maxbits <= LZW_MAXBITS);
+ av_assert0(s->maxbits >= 9 && s->maxbits <= LZW_MAXBITS);
s->maxcode = 1 << s->maxbits;
s->output_bytes = 0;
s->last_code = LZW_PREFIX_EMPTY;
@@ -263,6 +263,9 @@ int ff_lzw_encode_flush(LZWEncodeState *s,
if (s->last_code != -1)
writeCode(s, s->last_code);
writeCode(s, s->end_code);
+ if (s->mode == FF_LZW_GIF)
+ s->put_bits(&s->pb, 1, 0);
+
lzw_flush_put_bits(&s->pb);
s->last_code = -1;
diff --git a/libavcodec/mace.c b/libavcodec/mace.c
index 25c6b703ac..6eaa296688 100644
--- a/libavcodec/mace.c
+++ b/libavcodec/mace.c
@@ -2,20 +2,20 @@
* MACE decoder
* Copyright (c) 2002 Laszlo Torok <torokl@alpha.dfmk.hu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -244,12 +244,17 @@ static int mace_decode_frame(AVCodecContext *avctx, void *data,
int i, j, k, l, ret;
int is_mace3 = (avctx->codec_id == AV_CODEC_ID_MACE3);
+ if (buf_size % (avctx->channels << is_mace3)) {
+ av_log(avctx, AV_LOG_ERROR, "buffer size %d is odd\n", buf_size);
+ buf_size -= buf_size % (avctx->channels << is_mace3);
+ if (!buf_size)
+ return AVERROR_INVALIDDATA;
+ }
+
/* get output buffer */
frame->nb_samples = 3 * (buf_size << (1 - is_mace3)) / avctx->channels;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t **)frame->extended_data;
for(i = 0; i < avctx->channels; i++) {
diff --git a/libavcodec/mathops.c b/libavcodec/mathops.c
new file mode 100644
index 0000000000..31c8e69e61
--- /dev/null
+++ b/libavcodec/mathops.c
@@ -0,0 +1,26 @@
+#include "mathops.h"
+
+#ifdef TEST
+
+#include <stdlib.h>
+
+int main(void)
+{
+ unsigned u;
+
+ for(u=0; u<65536; u++) {
+ unsigned s = u*u;
+ unsigned root = ff_sqrt(s);
+ unsigned root_m1 = ff_sqrt(s-1);
+ if (s && root != u) {
+ fprintf(stderr, "ff_sqrt failed at %u with %u\n", s, root);
+ return 1;
+ }
+ if (u && root_m1 != u - 1) {
+ fprintf(stderr, "ff_sqrt failed at %u with %u\n", s, root);
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif /* TEST */
diff --git a/libavcodec/mathops.h b/libavcodec/mathops.h
index 7af13e19e0..46283ca444 100644
--- a/libavcodec/mathops.h
+++ b/libavcodec/mathops.h
@@ -3,20 +3,20 @@
* Copyright (c) 2001, 2002 Fabrice Bellard
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MATHOPS_H
@@ -39,8 +39,6 @@ extern const uint8_t ff_zigzag_direct[64];
# include "arm/mathops.h"
#elif ARCH_AVR32
# include "avr32/mathops.h"
-#elif ARCH_BFIN
-# include "bfin/mathops.h"
#elif ARCH_MIPS
# include "mips/mathops.h"
#elif ARCH_PPC
@@ -123,6 +121,20 @@ static inline av_const int mid_pred(int a, int b, int c)
}
#endif
+#ifndef median4
+#define median4 median4
+static inline av_const int median4(int a, int b, int c, int d)
+{
+ if (a < b) {
+ if (c < d) return (FFMIN(b, d) + FFMAX(a, c)) / 2;
+ else return (FFMIN(b, c) + FFMAX(a, d)) / 2;
+ } else {
+ if (c < d) return (FFMIN(a, d) + FFMAX(b, c)) / 2;
+ else return (FFMIN(a, c) + FFMAX(b, d)) / 2;
+ }
+}
+#endif
+
#ifndef sign_extend
static inline av_const int sign_extend(int val, unsigned bits)
{
@@ -199,6 +211,8 @@ if ((y) < (x)) {\
# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a) * ff_inverse[b]) >> 32))
#endif /* FASTDIV */
+#ifndef ff_sqrt
+#define ff_sqrt ff_sqrt
static inline av_const unsigned int ff_sqrt(unsigned int a)
{
unsigned int b;
@@ -218,6 +232,7 @@ static inline av_const unsigned int ff_sqrt(unsigned int a)
return b - (a < b * b);
}
+#endif
static inline int8_t ff_u8_to_s8(uint8_t a)
{
diff --git a/libavcodec/mathtables.c b/libavcodec/mathtables.c
index 47695bc343..a07ac50c08 100644
--- a/libavcodec/mathtables.c
+++ b/libavcodec/mathtables.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mdct_fixed.c b/libavcodec/mdct_fixed.c
index 9e06861dba..a32cb00ca0 100644
--- a/libavcodec/mdct_fixed.c
+++ b/libavcodec/mdct_fixed.c
@@ -1,22 +1,23 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FFT_FLOAT 0
+#define FFT_FIXED_32 0
#include "mdct_template.c"
/* same as ff_mdct_calcw_c with double-width unscaled output */
diff --git a/libavcodec/mdct_fixed_32.c b/libavcodec/mdct_fixed_32.c
new file mode 100644
index 0000000000..5a34dfe760
--- /dev/null
+++ b/libavcodec/mdct_fixed_32.c
@@ -0,0 +1,52 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ * Goran Cordasic (goran@mips.com)
+ * Djordje Pesut (djordje@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
+ */
+
+#define FFT_FLOAT 0
+#define FFT_FIXED_32 1
+#include "mdct_template.c"
diff --git a/libavcodec/mdct_float.c b/libavcodec/mdct_float.c
index a0a62b3001..cff2d211c4 100644
--- a/libavcodec/mdct_float.c
+++ b/libavcodec/mdct_float.c
@@ -1,20 +1,21 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FFT_FLOAT 1
+#define FFT_FIXED_32 0
#include "mdct_template.c"
diff --git a/libavcodec/mdct_template.c b/libavcodec/mdct_template.c
index bad890ef7f..7fa8bcce56 100644
--- a/libavcodec/mdct_template.c
+++ b/libavcodec/mdct_template.c
@@ -2,20 +2,20 @@
* MDCT/IMDCT transforms
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,7 +34,11 @@
#if FFT_FLOAT
# define RSCALE(x) (x)
#else
+#if FFT_FIXED_32
+# define RSCALE(x) (((x) + 32) >> 6)
+#else /* FFT_FIXED_32 */
# define RSCALE(x) ((x) >> 1)
+#endif /* FFT_FIXED_32 */
#endif
/**
@@ -56,7 +60,7 @@ av_cold int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale)
if (ff_fft_init(s, s->mdct_bits - 2, inverse) < 0)
goto fail;
- s->tcos = av_malloc(n/2 * sizeof(FFTSample));
+ s->tcos = av_malloc_array(n/2, sizeof(FFTSample));
if (!s->tcos)
goto fail;
diff --git a/libavcodec/mdec.c b/libavcodec/mdec.c
index 2a779c1176..5fd06f4aa6 100644
--- a/libavcodec/mdec.c
+++ b/libavcodec/mdec.c
@@ -4,20 +4,20 @@
*
* based upon code from Sebastian Jedruszkiewicz <elf@frogger.rules.pl>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@
#include "avcodec.h"
#include "blockdsp.h"
+#include "bswapdsp.h"
#include "idctdsp.h"
#include "mpegvideo.h"
#include "mpeg12.h"
@@ -37,6 +38,7 @@
typedef struct MDECContext {
AVCodecContext *avctx;
BlockDSPContext bdsp;
+ BswapDSPContext bbdsp;
IDCTDSPContext idsp;
ThreadFrame frame;
GetBitContext gb;
@@ -130,7 +132,7 @@ static inline int mdec_decode_block_intra(MDECContext *a, int16_t *block, int n)
static inline int decode_mb(MDECContext *a, int16_t block[6][64])
{
int i, ret;
- const int block_index[6] = { 5, 4, 0, 1, 2, 3 };
+ static const int block_index[6] = { 5, 4, 0, 1, 2, 3 };
a->bdsp.clear_blocks(block[0]);
@@ -172,23 +174,19 @@ static int decode_frame(AVCodecContext *avctx,
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
ThreadFrame frame = { .f = data };
- int i, ret;
+ int ret;
- if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
return ret;
- }
frame.f->pict_type = AV_PICTURE_TYPE_I;
frame.f->key_frame = 1;
- av_fast_malloc(&a->bitstream_buffer, &a->bitstream_buffer_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_fast_padded_malloc(&a->bitstream_buffer, &a->bitstream_buffer_size, buf_size);
if (!a->bitstream_buffer)
return AVERROR(ENOMEM);
- for (i = 0; i < buf_size; i += 2) {
- a->bitstream_buffer[i] = buf[i + 1];
- a->bitstream_buffer[i + 1] = buf[i];
- }
- init_get_bits(&a->gb, a->bitstream_buffer, buf_size * 8);
+ a->bbdsp.bswap16_buf((uint16_t *)a->bitstream_buffer, (uint16_t *)buf, (buf_size + 1) / 2);
+ if ((ret = init_get_bits8(&a->gb, a->bitstream_buffer, buf_size)) < 0)
+ return ret;
/* skip over 4 preamble bytes in stream (typically 0xXX 0xXX 0x00 0x38) */
skip_bits(&a->gb, 32);
@@ -222,6 +220,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
a->avctx = avctx;
ff_blockdsp_init(&a->bdsp, avctx);
+ ff_bswapdsp_init(&a->bbdsp);
ff_idctdsp_init(&a->idsp, avctx);
ff_mpeg12_init_vlcs();
ff_init_scantable(a->idsp.idct_permutation, &a->scantable,
diff --git a/libavcodec/me_cmp.c b/libavcodec/me_cmp.c
index eb98a72f1b..d4213d2759 100644
--- a/libavcodec/me_cmp.c
+++ b/libavcodec/me_cmp.c
@@ -1,22 +1,27 @@
/*
- * This file is part of Libav.
+ * DSP utils
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/internal.h"
#include "avcodec.h"
#include "copy_block.h"
#include "simple_idct.h"
@@ -103,8 +108,8 @@ static int sum_abs_dctelem_c(int16_t *block)
return sum;
}
-#define avg2(a, b) ((a + b + 1) >> 1)
-#define avg4(a, b, c, d) ((a + b + c + d + 2) >> 2)
+#define avg2(a, b) (((a) + (b) + 1) >> 1)
+#define avg4(a, b, c, d) (((a) + (b) + (c) + (d) + 2) >> 2)
static inline int pix_abs16_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
@@ -409,6 +414,14 @@ void ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type)
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,
"internal error in cmp function selection\n");
@@ -436,7 +449,7 @@ static int hadamard8_diff8x8_c(MpegEncContext *s, uint8_t *dst,
{
int i, temp[64], sum = 0;
- assert(h == 8);
+ av_assert2(h == 8);
for (i = 0; i < 8; i++) {
// FIXME: try pointer walks
@@ -488,7 +501,7 @@ static int hadamard8_intra8x8_c(MpegEncContext *s, uint8_t *src,
{
int i, temp[64], sum = 0;
- assert(h == 8);
+ av_assert2(h == 8);
for (i = 0; i < 8; i++) {
// FIXME: try pointer walks
@@ -540,7 +553,7 @@ static int dct_sad8x8_c(MpegEncContext *s, uint8_t *src1,
{
LOCAL_ALIGNED_16(int16_t, temp, [64]);
- assert(h == 8);
+ av_assert2(h == 8);
s->pdsp.diff_pixels(temp, src1, src2, stride);
s->fdsp.fdct(temp);
@@ -607,7 +620,7 @@ static int dct_max8x8_c(MpegEncContext *s, uint8_t *src1,
LOCAL_ALIGNED_16(int16_t, temp, [64]);
int sum = 0, i;
- assert(h == 8);
+ av_assert2(h == 8);
s->pdsp.diff_pixels(temp, src1, src2, stride);
s->fdsp.fdct(temp);
@@ -625,7 +638,7 @@ static int quant_psnr8x8_c(MpegEncContext *s, uint8_t *src1,
int16_t *const bak = temp + 64;
int sum = 0, i;
- assert(h == 8);
+ av_assert2(h == 8);
s->mb_intra = 0;
s->pdsp.diff_pixels(temp, src1, src2, stride);
@@ -654,7 +667,7 @@ static int rd8x8_c(MpegEncContext *s, uint8_t *src1, uint8_t *src2,
const int esc_length = s->ac_esc_length;
uint8_t *length, *last_length;
- assert(h == 8);
+ av_assert2(h == 8);
copy_block8(lsrc1, src1, 8, stride, 8);
copy_block8(lsrc2, src2, 8, stride, 8);
@@ -698,7 +711,7 @@ static int rd8x8_c(MpegEncContext *s, uint8_t *src1, uint8_t *src2,
level = temp[i] + 64;
- assert(level - 64);
+ av_assert2(level - 64);
if ((level & (~127)) == 0) {
bits += last_length[UNI_AC_ENC_INDEX(run, level)];
@@ -729,7 +742,7 @@ static int bit8x8_c(MpegEncContext *s, uint8_t *src1, uint8_t *src2,
const int esc_length = s->ac_esc_length;
uint8_t *length, *last_length;
- assert(h == 8);
+ av_assert2(h == 8);
s->pdsp.diff_pixels(temp, src1, src2, stride);
@@ -770,7 +783,7 @@ static int bit8x8_c(MpegEncContext *s, uint8_t *src1, uint8_t *src2,
level = temp[i] + 64;
- assert(level - 64);
+ av_assert2(level - 64);
if ((level & (~127)) == 0)
bits += last_length[UNI_AC_ENC_INDEX(run, level)];
@@ -803,20 +816,24 @@ static int vsad_intra ## size ## _c(MpegEncContext *c, \
VSAD_INTRA(8)
VSAD_INTRA(16)
-static int vsad16_c(MpegEncContext *c, uint8_t *s1, uint8_t *s2,
- ptrdiff_t stride, int h)
-{
- int score = 0, x, y;
-
- for (y = 1; y < h; y++) {
- for (x = 0; x < 16; x++)
- score += FFABS(s1[x] - s2[x] - s1[x + stride] + s2[x + stride]);
- s1 += stride;
- s2 += stride;
- }
-
- return score;
+#define VSAD(size) \
+static int vsad ## size ## _c(MpegEncContext *c, \
+ uint8_t *s1, uint8_t *s2, \
+ ptrdiff_t stride, int h) \
+{ \
+ int score = 0, x, y; \
+ \
+ for (y = 1; y < h; y++) { \
+ for (x = 0; x < size; x++) \
+ score += FFABS(s1[x] - s2[x] - s1[x + stride] + s2[x + stride]); \
+ s1 += stride; \
+ s2 += stride; \
+ } \
+ \
+ return score; \
}
+VSAD(8)
+VSAD(16)
#define SQ(a) ((a) * (a))
#define VSSE_INTRA(size) \
@@ -841,20 +858,23 @@ static int vsse_intra ## size ## _c(MpegEncContext *c, \
VSSE_INTRA(8)
VSSE_INTRA(16)
-static int vsse16_c(MpegEncContext *c, uint8_t *s1, uint8_t *s2,
- ptrdiff_t stride, int h)
-{
- int score = 0, x, y;
-
- for (y = 1; y < h; y++) {
- for (x = 0; x < 16; x++)
- score += SQ(s1[x] - s2[x] - s1[x + stride] + s2[x + stride]);
- s1 += stride;
- s2 += stride;
- }
-
- return score;
+#define VSSE(size) \
+static int vsse ## size ## _c(MpegEncContext *c, uint8_t *s1, uint8_t *s2, \
+ ptrdiff_t stride, int h) \
+{ \
+ int score = 0, x, y; \
+ \
+ for (y = 1; y < h; y++) { \
+ for (x = 0; x < size; x++) \
+ score += SQ(s1[x] - s2[x] - s1[x + stride] + s2[x + stride]); \
+ s1 += stride; \
+ s2 += stride; \
+ } \
+ \
+ return score; \
}
+VSSE(8)
+VSSE(16)
#define WRAPPER8_16_SQ(name8, name16) \
static int name16(MpegEncContext *s, uint8_t *dst, uint8_t *src, \
@@ -892,8 +912,31 @@ av_cold void ff_me_cmp_init_static(void)
ff_square_tab[i] = (i - 256) * (i - 256);
}
+int ff_check_alignment(void)
+{
+ static int did_fail = 0;
+ LOCAL_ALIGNED_16(int, aligned, [4]);
+
+ if ((intptr_t)aligned & 15) {
+ if (!did_fail) {
+#if HAVE_MMX || HAVE_ALTIVEC
+ av_log(NULL, AV_LOG_ERROR,
+ "Compiler did not align stack variables. Libavcodec has been miscompiled\n"
+ "and may be very slow or crash. This is not a bug in libavcodec,\n"
+ "but in the compiler. You may try recompiling using gcc >= 4.2.\n"
+ "Do not report crashes to FFmpeg developers.\n");
+#endif
+ did_fail=1;
+ }
+ return -1;
+ }
+ return 0;
+}
+
av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx)
{
+ ff_check_alignment();
+
c->sum_abs_dctelem = sum_abs_dctelem_c;
/* TODO [0] 16 [1] 8 */
@@ -927,14 +970,21 @@ av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx)
SET_CMP_FUNC(rd)
SET_CMP_FUNC(bit)
c->vsad[0] = vsad16_c;
+ c->vsad[1] = vsad8_c;
c->vsad[4] = vsad_intra16_c;
c->vsad[5] = vsad_intra8_c;
c->vsse[0] = vsse16_c;
+ c->vsse[1] = vsse8_c;
c->vsse[4] = vsse_intra16_c;
c->vsse[5] = vsse_intra8_c;
c->nsse[0] = nsse16_c;
c->nsse[1] = nsse8_c;
+#if CONFIG_SNOW_DECODER || CONFIG_SNOW_ENCODER
+ ff_dsputil_init_dwt(c);
+#endif
+ if (ARCH_ALPHA)
+ ff_me_cmp_init_alpha(c, avctx);
if (ARCH_ARM)
ff_me_cmp_init_arm(c, avctx);
if (ARCH_PPC)
diff --git a/libavcodec/me_cmp.h b/libavcodec/me_cmp.h
index 725f9b25ee..98ee53ce2a 100644
--- a/libavcodec/me_cmp.h
+++ b/libavcodec/me_cmp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,20 @@
extern uint32_t ff_square_tab[512];
+
+/* minimum alignment rules ;)
+ * If you notice errors in the align stuff, need more alignment for some ASM code
+ * for some CPU or need to use a function with less aligned data then send a mail
+ * to the ffmpeg-devel mailing list, ...
+ *
+ * !warning These alignments might not match reality, (missing attribute((align))
+ * stuff somewhere possible).
+ * I (Michael) did not check them, these are just the alignments which I think
+ * could be reached easily ...
+ *
+ * !future video codecs might need functions with less strict alignment
+ */
+
struct MpegEncContext;
/* Motion estimation:
* h is limited to { width / 2, width, 2 * width },
@@ -49,6 +63,8 @@ typedef struct MECmpContext {
me_cmp_func vsad[6];
me_cmp_func vsse[6];
me_cmp_func nsse[6];
+ me_cmp_func w53[6];
+ me_cmp_func w97[6];
me_cmp_func dct_max[6];
me_cmp_func dct264_sad[6];
@@ -64,11 +80,16 @@ typedef struct MECmpContext {
void ff_me_cmp_init_static(void);
+int ff_check_alignment(void);
+
void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx);
+void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx);
void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx);
void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx);
void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx);
void ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type);
+void ff_dsputil_init_dwt(MECmpContext *c);
+
#endif /* AVCODEC_ME_CMP_H */
diff --git a/libavcodec/metasound.c b/libavcodec/metasound.c
index dd9ffe03b0..2dab135bda 100644
--- a/libavcodec/metasound.c
+++ b/libavcodec/metasound.c
@@ -4,20 +4,20 @@
* based on TwinVQ decoder
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -236,7 +236,7 @@ static int metasound_read_bitstream(AVCodecContext *avctx, TwinVQContext *tctx,
skip_bits(&gb, 4 - (get_bits_count(&gb) & 3));
}
- return 0;
+ return (get_bits_count(&gb) + 7) / 8;
}
typedef struct MetasoundProps {
diff --git a/libavcodec/metasound_data.c b/libavcodec/metasound_data.c
index 8aa53e556c..e439b3d837 100644
--- a/libavcodec/metasound_data.c
+++ b/libavcodec/metasound_data.c
@@ -2,20 +2,20 @@
* MetaSound decoder
* Copyright (c) 2013 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -11208,6 +11208,14 @@ static const int16_t fcb16m[] = {
-688, -209, 915, 622, -1038, -474, -343, -91,
-173, -104, 255, 96, 1547, 773, -625, 2272,
-90, -509, -527, -247, -147, -234, -45, 166,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
static const int16_t fcb16sl[] = {
@@ -12739,185 +12747,6 @@ static const float lsp16[] = {
-0.0429, -0.0615, -0.0893, -0.0618, -0.0384, -0.0134, -0.0232, -0.0238,
};
-static const float lsp16s[] = {
- 0.1813, 0.3911, 0.6301, 0.8012, 1.0057, 1.2041, 1.4271, 1.6943,
- 1.9402, 2.1733, 2.3521, 2.4989, 2.5839, 2.6846, 2.7634, 2.8950,
- 0.1311, 0.3183, 0.4659, 0.5601, 0.6658, 0.7828, 1.0065, 1.2717,
- 1.5185, 1.7339, 1.9530, 2.2189, 2.3739, 2.4991, 2.6984, 2.9256,
- 0.1627, 0.4519, 0.6323, 0.7012, 0.7848, 0.9801, 1.1810, 1.3222,
- 1.5413, 1.8129, 1.9338, 2.0809, 2.3180, 2.5189, 2.7066, 2.9514,
- 0.1475, 0.2447, 0.4240, 0.5669, 0.7872, 0.9838, 1.1823, 1.3814,
- 1.5358, 1.6820, 1.8794, 2.1419, 2.4132, 2.6112, 2.7911, 2.9511,
- 0.1224, 0.2876, 0.5013, 0.6985, 0.8902, 1.0901, 1.2835, 1.4768,
- 1.6596, 1.8538, 2.0467, 2.2304, 2.4124, 2.5942, 2.7729, 2.9531,
- 0.1741, 0.3034, 0.4677, 0.5879, 0.7258, 0.9648, 1.1417, 1.3220,
- 1.5081, 1.7151, 1.9212, 2.1286, 2.3208, 2.4938, 2.6765, 2.8891,
- 0.1657, 0.3174, 0.4907, 0.6559, 0.8295, 1.0254, 1.2071, 1.3880,
- 1.5737, 1.7845, 1.9027, 2.1139, 2.3323, 2.5157, 2.7323, 2.9015,
- 0.1592, 0.2758, 0.4417, 0.6315, 0.8257, 0.9873, 1.1277, 1.2830,
- 1.4337, 1.6315, 1.8899, 2.1356, 2.3572, 2.5632, 2.7468, 2.9420,
- 0.1524, 0.4325, 0.5931, 0.7036, 0.7696, 0.8923, 1.1739, 1.4773,
- 1.6609, 1.7911, 1.9666, 2.1972, 2.3754, 2.5045, 2.6613, 2.8882,
- 0.2130, 0.3013, 0.3721, 0.4257, 0.5079, 0.7015, 0.9815, 1.2554,
- 1.4648, 1.6966, 1.9138, 2.1075, 2.3318, 2.5292, 2.7453, 2.9347,
- 0.1142, 0.3748, 0.6205, 0.7642, 0.8121, 0.9022, 0.9843, 1.1558,
- 1.4467, 1.7422, 1.9574, 2.1302, 2.3812, 2.5898, 2.7720, 2.9583,
- 0.1255, 0.2339, 0.3570, 0.5323, 0.7458, 1.0003, 1.1729, 1.3567,
- 1.5217, 1.6977, 1.8924, 2.0942, 2.3145, 2.5408, 2.7553, 2.9337,
- 0.1316, 0.2289, 0.4327, 0.6663, 0.8509, 0.9994, 1.1697, 1.3804,
- 1.5609, 1.6903, 1.8572, 2.1019, 2.3687, 2.5789, 2.7715, 2.9472,
- 0.1502, 0.2546, 0.3883, 0.5333, 0.6976, 0.9163, 1.1071, 1.3364,
- 1.5420, 1.7525, 1.8948, 2.0839, 2.2819, 2.4651, 2.6875, 2.8987,
- 0.1593, 0.3014, 0.4573, 0.6354, 0.8157, 0.9805, 1.1783, 1.3747,
- 1.5678, 1.7326, 1.9286, 2.1340, 2.3253, 2.5280, 2.7180, 2.9298,
- 0.1811, 0.3167, 0.4655, 0.6507, 0.8198, 1.0075, 1.1892, 1.3743,
- 1.5227, 1.7090, 1.8849, 2.0743, 2.2750, 2.4830, 2.6896, 2.8953,
- 0.1846, 0.3577, 0.5315, 0.7290, 0.9176, 1.1016, 1.2654, 1.4525,
- 1.6315, 1.8268, 2.0238, 2.1934, 2.3868, 2.5753, 2.7682, 2.9469,
- 0.0876, 0.1439, 0.2048, 0.3654, 0.6281, 0.8853, 1.0907, 1.2992,
- 1.5227, 1.7373, 1.9395, 2.1419, 2.3488, 2.5486, 2.7466, 2.9348,
- 0.1391, 0.4170, 0.6561, 0.7953, 0.8734, 0.9986, 1.1870, 1.4520,
- 1.6042, 1.7910, 2.0135, 2.1870, 2.3358, 2.5066, 2.7409, 2.9955,
- 0.0804, 0.1355, 0.2599, 0.4998, 0.7408, 0.9474, 1.1276, 1.3428,
- 1.5556, 1.7712, 1.9699, 2.1535, 2.3605, 2.5548, 2.7489, 2.9325,
- 0.1304, 0.3087, 0.4979, 0.6584, 0.8414, 1.0329, 1.2244, 1.4189,
- 1.6118, 1.8200, 1.9985, 2.1893, 2.3915, 2.5794, 2.7647, 2.9344,
- 0.1895, 0.2849, 0.3705, 0.4126, 0.6265, 0.9207, 1.1774, 1.3762,
- 1.5757, 1.7728, 1.9568, 2.1662, 2.3615, 2.5575, 2.7561, 2.9416,
- 0.1800, 0.3078, 0.4805, 0.6796, 0.8503, 1.0046, 1.1703, 1.3269,
- 1.4862, 1.6502, 1.8454, 2.0873, 2.3175, 2.5356, 2.7516, 2.9469,
- 0.1950, 0.3233, 0.4568, 0.5940, 0.7589, 0.9978, 1.1701, 1.3383,
- 1.5017, 1.6565, 1.8243, 2.0605, 2.2938, 2.5147, 2.7419, 2.9396,
- 0.2531, 0.4391, 0.5790, 0.7170, 0.8998, 1.1430, 1.3577, 1.5326,
- 1.6328, 1.7627, 1.9726, 2.1762, 2.3563, 2.5478, 2.7385, 2.9067,
- 0.1805, 0.2788, 0.3591, 0.3881, 0.5441, 0.8055, 1.0766, 1.3165,
- 1.5316, 1.7508, 1.9477, 2.1374, 2.3438, 2.5484, 2.7501, 2.9410,
- 0.2044, 0.3671, 0.5396, 0.7042, 0.8582, 0.9831, 1.1261, 1.3194,
- 1.4769, 1.6979, 1.8717, 2.0463, 2.2620, 2.4739, 2.7054, 2.9208,
- 0.1048, 0.2175, 0.4206, 0.5923, 0.7483, 0.9400, 1.1356, 1.3799,
- 1.5958, 1.7320, 1.8984, 2.1296, 2.3594, 2.5492, 2.7387, 2.9305,
- 0.0842, 0.1729, 0.3951, 0.6447, 0.8688, 1.0605, 1.2472, 1.4330,
- 1.6232, 1.8144, 2.0216, 2.1915, 2.3878, 2.5763, 2.7685, 2.9464,
- 0.1461, 0.2593, 0.4105, 0.5677, 0.7328, 0.8919, 1.0484, 1.2302,
- 1.4386, 1.6635, 1.8873, 2.1024, 2.3116, 2.5268, 2.7273, 2.9269,
- 0.1503, 0.3108, 0.4756, 0.6731, 0.8600, 1.0233, 1.2115, 1.3971,
- 1.5915, 1.7892, 1.9517, 2.1603, 2.3487, 2.5460, 2.7308, 2.8998,
- 0.2163, 0.3669, 0.5125, 0.6709, 0.8143, 0.9930, 1.2095, 1.4205,
- 1.6176, 1.7112, 1.8398, 2.0896, 2.3513, 2.5290, 2.6667, 2.8960,
- 0.2133, 0.4382, 0.6287, 0.8702, 1.1088, 1.3749, 1.6062, 1.7446,
- 1.8333, 1.9122, 1.9614, 2.0669, 2.1789, 2.3449, 2.6038, 2.8849,
- 0.1598, 0.2719, 0.3877, 0.4815, 0.5926, 0.7795, 1.0449, 1.3045,
- 1.5210, 1.7391, 1.9462, 2.1397, 2.3553, 2.5458, 2.7540, 2.9392,
- 0.2918, 0.5607, 0.6801, 0.7404, 0.8285, 0.9431, 1.1579, 1.4080,
- 1.6332, 1.8472, 1.9738, 2.0771, 2.2890, 2.5178, 2.7445, 2.9830,
- 0.1664, 0.2842, 0.3965, 0.5463, 0.8162, 1.0346, 1.1849, 1.3446,
- 1.5122, 1.7563, 1.9960, 2.2002, 2.3796, 2.5689, 2.7712, 2.9550,
- 0.0911, 0.2397, 0.5052, 0.7868, 1.0299, 1.1311, 1.2244, 1.3333,
- 1.4395, 1.6790, 1.9369, 2.1717, 2.3689, 2.5538, 2.7340, 2.9326,
- 0.1647, 0.2931, 0.3836, 0.4978, 0.6255, 0.9243, 1.1339, 1.3001,
- 1.5269, 1.8010, 1.9715, 2.1419, 2.3784, 2.5503, 2.6719, 2.8745,
- 0.2440, 0.3802, 0.4756, 0.6613, 0.8627, 1.0292, 1.2291, 1.4060,
- 1.5198, 1.7354, 1.9044, 2.1010, 2.3147, 2.4996, 2.7171, 2.9041,
- 0.1590, 0.2876, 0.4572, 0.5996, 0.7713, 0.9490, 1.1205, 1.2815,
- 1.4516, 1.6385, 1.8179, 2.0457, 2.2759, 2.4785, 2.6861, 2.9080,
- 0.2297, 0.4309, 0.5712, 0.6717, 0.8138, 1.0463, 1.2492, 1.4560,
- 1.6796, 1.8458, 1.9642, 2.1452, 2.3636, 2.5395, 2.7456, 2.9495,
- 0.2975, 0.4678, 0.4996, 0.5809, 0.6279, 0.6884, 0.8606, 1.1386,
- 1.4412, 1.6876, 1.8760, 2.0932, 2.3178, 2.5166, 2.7345, 2.9280,
- 0.1278, 0.3737, 0.6004, 0.7069, 0.8147, 1.0180, 1.2581, 1.3812,
- 1.4855, 1.7268, 1.9970, 2.1258, 2.2936, 2.5702, 2.7563, 2.8983,
- 0.1314, 0.2508, 0.3999, 0.5680, 0.7424, 0.9367, 1.1286, 1.3175,
- 1.5336, 1.7404, 1.9317, 2.1404, 2.3514, 2.5562, 2.7510, 2.9402,
- 0.1043, 0.2367, 0.4293, 0.6376, 0.8160, 0.9836, 1.1779, 1.3850,
- 1.5835, 1.7875, 1.9765, 2.1593, 2.3654, 2.5577, 2.7465, 2.9398,
- 0.1529, 0.2515, 0.3454, 0.4374, 0.7011, 0.9015, 1.0744, 1.3532,
- 1.5699, 1.7545, 2.0021, 2.1259, 2.2278, 2.4546, 2.7264, 2.9425,
- 0.1429, 0.2808, 0.4395, 0.6334, 0.8069, 0.9705, 1.1520, 1.3250,
- 1.5109, 1.7285, 1.9356, 2.1469, 2.3479, 2.5554, 2.7512, 2.9348,
- 0.1625, 0.3022, 0.4756, 0.6315, 0.8032, 0.9924, 1.1596, 1.3204,
- 1.4994, 1.6929, 1.8955, 2.1090, 2.3025, 2.5018, 2.6908, 2.8980,
- 0.1692, 0.3427, 0.5228, 0.7756, 0.9688, 1.0950, 1.3056, 1.4360,
- 1.5675, 1.8049, 1.9376, 2.1151, 2.3407, 2.5012, 2.7192, 2.9258,
- 0.0474, 0.1251, 0.1939, 0.3841, 0.6501, 0.9231, 1.1153, 1.3240,
- 1.5478, 1.7599, 1.9651, 2.1510, 2.3645, 2.5552, 2.7542, 2.9393,
- 0.2196, 0.4656, 0.7492, 0.9922, 1.1678, 1.2489, 1.3112, 1.3657,
- 1.4223, 1.5302, 1.7212, 1.9996, 2.2523, 2.4844, 2.7036, 2.9145,
- 0.1128, 0.2368, 0.3704, 0.5476, 0.7723, 0.9968, 1.1930, 1.3992,
- 1.6013, 1.7957, 1.9888, 2.1857, 2.3825, 2.5705, 2.7616, 2.9434,
- 0.1341, 0.2768, 0.4510, 0.6359, 0.8332, 1.0335, 1.2004, 1.3952,
- 1.5762, 1.7681, 1.9815, 2.1735, 2.3657, 2.5552, 2.7514, 2.9498,
- 0.1247, 0.2559, 0.3516, 0.4726, 0.6861, 0.9483, 1.1852, 1.3858,
- 1.5851, 1.7815, 1.9778, 2.1737, 2.3729, 2.5664, 2.7620, 2.9429,
- 0.1988, 0.3320, 0.4777, 0.6737, 0.8425, 1.0265, 1.1694, 1.3655,
- 1.5463, 1.7135, 1.9385, 2.1650, 2.3529, 2.5367, 2.7545, 2.9585,
- 0.1376, 0.2620, 0.4273, 0.6169, 0.7755, 0.9441, 1.1169, 1.3157,
- 1.5179, 1.7020, 1.8931, 2.1059, 2.3112, 2.5136, 2.7169, 2.9198,
- 0.2112, 0.4385, 0.6091, 0.7618, 0.9553, 1.1543, 1.3445, 1.5396,
- 1.7153, 1.9192, 2.1263, 2.3593, 2.5958, 2.8171, 2.9394, 3.0409,
- 0.1347, 0.2099, 0.2646, 0.3453, 0.5266, 0.7869, 1.0513, 1.2795,
- 1.4880, 1.7181, 1.9294, 2.1332, 2.3362, 2.5442, 2.7433, 2.9362,
- 0.3141, 0.5935, 0.7517, 0.8313, 0.8568, 0.9570, 1.0250, 1.1275,
- 1.3422, 1.6303, 1.8577, 2.0705, 2.2957, 2.5095, 2.7244, 2.9262,
- 0.0962, 0.2116, 0.3961, 0.5641, 0.7122, 0.8883, 1.1023, 1.3481,
- 1.5623, 1.7554, 1.9618, 2.1675, 2.3706, 2.5556, 2.7430, 2.9337,
- 0.0898, 0.1510, 0.3060, 0.5820, 0.8221, 1.0388, 1.2261, 1.4289,
- 1.6054, 1.8103, 1.9941, 2.1844, 2.3742, 2.5711, 2.7632, 2.9474,
- 0.1326, 0.2316, 0.3761, 0.5177, 0.6782, 0.8761, 1.0952, 1.3175,
- 1.5078, 1.7034, 1.9051, 2.1245, 2.3424, 2.5484, 2.7444, 2.9389,
- 0.1740, 0.3293, 0.5174, 0.6824, 0.8394, 1.0372, 1.2046, 1.3723,
- 1.5656, 1.7444, 1.9442, 2.1386, 2.3139, 2.4960, 2.7071, 2.9297,
- 0.2304, 0.3775, 0.4865, 0.6182, 0.7842, 0.9208, 1.1151, 1.2843,
- 1.4641, 1.6988, 1.9209, 2.1260, 2.3099, 2.5229, 2.7414, 2.9276,
- 0.0094, 0.0261, -0.0037, 0.0041, -0.0092, -0.0044, -0.0232, -0.0073,
- -0.0047, -0.0021, 0.0250, -0.0580, -0.0140, -0.0342, -0.0586, 0.0020,
- 0.0449, 0.0155, -0.0523, -0.0279, 0.0299, -0.0183, -0.0736, -0.0639,
- -0.0017, 0.0336, 0.0209, 0.0046, 0.0077, -0.0148, -0.0114, -0.0120,
- 0.0115, -0.0050, 0.0445, 0.0048, 0.0188, -0.0137, -0.0080, 0.0239,
- -0.0184, -0.0524, -0.0195, -0.0126, 0.0284, 0.0632, 0.0141, -0.0093,
- -0.0096, 0.0196, 0.0230, 0.0379, 0.0308, 0.0237, -0.0224, -0.0600,
- -0.0755, -0.1074, -0.0988, -0.0606, -0.1038, -0.1552, -0.1480, -0.0672,
- 0.0504, 0.0676, 0.0336, -0.0042, 0.0729, 0.1013, 0.0868, 0.0846,
- 0.0954, 0.0515, -0.0066, -0.0851, -0.0485, 0.0294, 0.0395, 0.0087,
- 0.0078, 0.0446, 0.0881, 0.0672, -0.0384, -0.0025, 0.0415, 0.0353,
- 0.0080, 0.0052, 0.0190, 0.0182, 0.0069, 0.0168, 0.0374, 0.0037,
- -0.0292, -0.0429, 0.0302, 0.0681, -0.0233, -0.0238, -0.0003, -0.0043,
- 0.0054, -0.0029, -0.0149, 0.0642, 0.0622, 0.0341, -0.0232, -0.0461,
- -0.0082, -0.0469, -0.0618, -0.0326, -0.0452, -0.0649, -0.0597, -0.0398,
- -0.0318, -0.0116, 0.0011, 0.0009, -0.0384, -0.0384, -0.0156, -0.0260,
- -0.0007, 0.0473, 0.0111, -0.0358, -0.0484, -0.0204, -0.0029, -0.0090,
- -0.0285, -0.0495, -0.0376, 0.0917, 0.1192, 0.1026, 0.0745, 0.0397,
- 0.0463, 0.0253, 0.0025, 0.0465, 0.0100, 0.0488, 0.0416, 0.0223,
- 0.0263, 0.0072, -0.0053, 0.0595, 0.0060, -0.0518, -0.0316, -0.0043,
- -0.0133, -0.0233, -0.0075, -0.0251, 0.0277, -0.0067, -0.0136, -0.0004,
- 0.0235, 0.0112, -0.0182, -0.0324, -0.0210, -0.0035, -0.0395, -0.0384,
- 0.0005, -0.0150, -0.0356, 0.0127, -0.0033, -0.0034, 0.0205, 0.0747,
- 0.1138, 0.1015, 0.0995, -0.0161, -0.0045, 0.0129, 0.0472, 0.0575,
- 0.0222, 0.0091, 0.0037, -0.0471, 0.0371, 0.0132, 0.0208, 0.0247,
- 0.0117, 0.0164, 0.0225, 0.0124, -0.0023, 0.0088, -0.0046, 0.0047,
- -0.0393, 0.0018, 0.0148, 0.0020, 0.0044, 0.0165, 0.0229, -0.0208,
- -0.0477, -0.0310, -0.0164, -0.0390, -0.0764, -0.0525, -0.0094, 0.0075,
- -0.0102, -0.0045, -0.0504, -0.0709, 0.0822, 0.0710, 0.0426, 0.0014,
- -0.0371, -0.0400, -0.0157, -0.0155, -0.0173, -0.0138, -0.0015, 0.0134,
- -0.0418, -0.0682, -0.0256, 0.0050, 0.0360, 0.0354, 0.0074, -0.0396,
- -0.0235, 0.0284, 0.0494, 0.0153, 0.0448, 0.0025, -0.0061, 0.0252,
- 0.1000, 0.2260, 0.2158, 0.2116, 0.2198, 0.2055, 0.2110, 0.1873,
- 0.1907, 0.2071, 0.2164, 0.2009, 0.2059, 0.2124, 0.2141, 0.2093,
- 0.0875, 0.0981, 0.1177, 0.1071, 0.1033, 0.1248, 0.1048, 0.1238,
- 0.1166, 0.1008, 0.1062, 0.0992, 0.0994, 0.1067, 0.0999, 0.1187,
- 0.0750, 0.0794, 0.0828, 0.0854, 0.0859, 0.0801, 0.0891, 0.0933,
- 0.0969, 0.0920, 0.0915, 0.0862, 0.0868, 0.0891, 0.0842, 0.0824,
- 0.0625, 0.0930, 0.0815, 0.0853, 0.0898, 0.0828, 0.0822, 0.0910,
- 0.0873, 0.0906, 0.0856, 0.0840, 0.0774, 0.0785, 0.0684, 0.0711,
- 0.3319, 0.4219, 0.4588, 0.4090, 0.4092, 0.4014, 0.3548, 0.3353,
- 0.3708, 0.3352, 0.3720, 0.3538, 0.4084, 0.4289, 0.4060, 0.4210,
- 0.0588, 0.0209, -0.0082, -0.0115, -0.0343, -0.0621, -0.0541, -0.0346,
- -0.0346, -0.0366, -0.0220, -0.0265, -0.0102, 0.0374, 0.0306, 0.0404,
- 0.0306, 0.0090, -0.0054, 0.0333, 0.0047, 0.0238, 0.0141, 0.0165,
- 0.0306, 0.0420, 0.0159, 0.0124, 0.0414, 0.0158, -0.0237, 0.0141,
- 0.0765, 0.0057, -0.0260, -0.0426, -0.0395, -0.0126, -0.0579, -0.0417,
- -0.0429, -0.0615, -0.0893, -0.0618, -0.0384, -0.0134, -0.0232, -0.0238,
-};
-
static const float lsp22[] = {
0.0664, 0.1875, 0.4300, 0.6730, 0.8793, 1.0640, 1.2563, 1.4433,
1.6394, 1.8176, 2.0029, 2.1921, 2.3796, 2.5671, 2.7595, 2.9536,
diff --git a/libavcodec/metasound_data.h b/libavcodec/metasound_data.h
index 4925516e21..5c334113cc 100644
--- a/libavcodec/metasound_data.h
+++ b/libavcodec/metasound_data.h
@@ -2,20 +2,20 @@
* MetaSound decoder
* Copyright (c) 2013 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/microdvddec.c b/libavcodec/microdvddec.c
new file mode 100644
index 0000000000..96034a042a
--- /dev/null
+++ b/libavcodec/microdvddec.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * MicroDVD subtitle decoder
+ *
+ * Based on the specifications found here:
+ * https://trac.videolan.org/vlc/ticket/1825#comment:6
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/bprint.h"
+#include "avcodec.h"
+#include "ass.h"
+
+static int indexof(const char *s, int c)
+{
+ char *f = strchr(s, c);
+ return f ? (f - s) : -1;
+}
+
+struct microdvd_tag {
+ char key;
+ int persistent;
+ uint32_t data1;
+ uint32_t data2;
+ char *data_string;
+ int data_string_len;
+};
+
+#define MICRODVD_PERSISTENT_OFF 0
+#define MICRODVD_PERSISTENT_ON 1
+#define MICRODVD_PERSISTENT_OPENED 2
+
+// Color, Font, Size, cHarset, stYle, Position, cOordinate
+#define MICRODVD_TAGS "cfshyYpo"
+
+static void microdvd_set_tag(struct microdvd_tag *tags, struct microdvd_tag tag)
+{
+ int tag_index = indexof(MICRODVD_TAGS, tag.key);
+
+ if (tag_index < 0)
+ return;
+ memcpy(&tags[tag_index], &tag, sizeof(tag));
+}
+
+// italic, bold, underline, strike-through
+#define MICRODVD_STYLES "ibus"
+
+/* some samples have lines that start with a / indicating non persistent italic
+ * marker */
+static char *check_for_italic_slash_marker(struct microdvd_tag *tags, char *s)
+{
+ if (*s == '/') {
+ struct microdvd_tag tag = tags[indexof(MICRODVD_TAGS, 'y')];
+ tag.key = 'y';
+ tag.data1 |= 1 << 0 /* 'i' position in MICRODVD_STYLES */;
+ microdvd_set_tag(tags, tag);
+ s++;
+ }
+ return s;
+}
+
+static char *microdvd_load_tags(struct microdvd_tag *tags, char *s)
+{
+ s = check_for_italic_slash_marker(tags, s);
+
+ while (*s == '{') {
+ char *start = s;
+ char tag_char = *(s + 1);
+ struct microdvd_tag tag = {0};
+
+ if (!tag_char || *(s + 2) != ':')
+ break;
+ s += 3;
+
+ switch (tag_char) {
+
+ /* Style */
+ case 'Y':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'y':
+ while (*s && *s != '}') {
+ int style_index = indexof(MICRODVD_STYLES, *s);
+
+ if (style_index >= 0)
+ tag.data1 |= (1 << style_index);
+ s++;
+ }
+ if (*s != '}')
+ break;
+ /* We must distinguish persistent and non-persistent styles
+ * to handle this kind of style tags: {y:ib}{Y:us} */
+ tag.key = tag_char;
+ break;
+
+ /* Color */
+ case 'C':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'c':
+ while (*s == '$' || *s == '#')
+ s++;
+ tag.data1 = strtol(s, &s, 16) & 0x00ffffff;
+ if (*s != '}')
+ break;
+ tag.key = 'c';
+ break;
+
+ /* Font name */
+ case 'F':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'f': {
+ int len = indexof(s, '}');
+ if (len < 0)
+ break;
+ tag.data_string = s;
+ tag.data_string_len = len;
+ s += len;
+ tag.key = 'f';
+ break;
+ }
+
+ /* Font size */
+ case 'S':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 's':
+ tag.data1 = strtol(s, &s, 10);
+ if (*s != '}')
+ break;
+ tag.key = 's';
+ break;
+
+ /* Charset */
+ case 'H': {
+ //TODO: not yet handled, just parsed.
+ int len = indexof(s, '}');
+ if (len < 0)
+ break;
+ tag.data_string = s;
+ tag.data_string_len = len;
+ s += len;
+ tag.key = 'h';
+ break;
+ }
+
+ /* Position */
+ case 'P':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ tag.data1 = (*s++ == '1');
+ if (*s != '}')
+ break;
+ tag.key = 'p';
+ break;
+
+ /* Coordinates */
+ case 'o':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ tag.data1 = strtol(s, &s, 10);
+ if (*s != ',')
+ break;
+ s++;
+ tag.data2 = strtol(s, &s, 10);
+ if (*s != '}')
+ break;
+ tag.key = 'o';
+ break;
+
+ default: /* Unknown tag, we consider it's text */
+ break;
+ }
+
+ if (tag.key == 0)
+ return start;
+
+ microdvd_set_tag(tags, tag);
+ s++;
+ }
+ return check_for_italic_slash_marker(tags, s);
+}
+
+static void microdvd_open_tags(AVBPrint *new_line, struct microdvd_tag *tags)
+{
+ int i, sidx;
+ for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) {
+ if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED)
+ continue;
+ switch (tags[i].key) {
+ case 'Y':
+ case 'y':
+ for (sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++)
+ if (tags[i].data1 & (1 << sidx))
+ av_bprintf(new_line, "{\\%c1}", MICRODVD_STYLES[sidx]);
+ break;
+
+ case 'c':
+ av_bprintf(new_line, "{\\c&H%06X&}", tags[i].data1);
+ break;
+
+ case 'f':
+ av_bprintf(new_line, "{\\fn%.*s}",
+ tags[i].data_string_len, tags[i].data_string);
+ break;
+
+ case 's':
+ av_bprintf(new_line, "{\\fs%d}", tags[i].data1);
+ break;
+
+ case 'p':
+ if (tags[i].data1 == 0)
+ av_bprintf(new_line, "{\\an8}");
+ break;
+
+ case 'o':
+ av_bprintf(new_line, "{\\pos(%d,%d)}",
+ tags[i].data1, tags[i].data2);
+ break;
+ }
+ if (tags[i].persistent == MICRODVD_PERSISTENT_ON)
+ tags[i].persistent = MICRODVD_PERSISTENT_OPENED;
+ }
+}
+
+static void microdvd_close_no_persistent_tags(AVBPrint *new_line,
+ struct microdvd_tag *tags)
+{
+ int i, sidx;
+
+ for (i = sizeof(MICRODVD_TAGS) - 2; i >= 0; i--) {
+ if (tags[i].persistent != MICRODVD_PERSISTENT_OFF)
+ continue;
+ switch (tags[i].key) {
+
+ case 'y':
+ for (sidx = sizeof(MICRODVD_STYLES) - 2; sidx >= 0; sidx--)
+ if (tags[i].data1 & (1 << sidx))
+ av_bprintf(new_line, "{\\%c0}", MICRODVD_STYLES[sidx]);
+ break;
+
+ case 'c':
+ av_bprintf(new_line, "{\\c}");
+ break;
+
+ case 'f':
+ av_bprintf(new_line, "{\\fn}");
+ break;
+
+ case 's':
+ av_bprintf(new_line, "{\\fs}");
+ break;
+ }
+ tags[i].key = 0;
+ }
+}
+
+static int microdvd_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ AVSubtitle *sub = data;
+ AVBPrint new_line;
+ char *line = avpkt->data;
+ char *end = avpkt->data + avpkt->size;
+ struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}};
+
+ if (avpkt->size <= 0)
+ return avpkt->size;
+
+ av_bprint_init(&new_line, 0, 2048);
+
+ // subtitle content
+ while (line < end && *line) {
+
+ // parse MicroDVD tags, and open them in ASS
+ line = microdvd_load_tags(tags, line);
+ microdvd_open_tags(&new_line, tags);
+
+ // simple copy until EOL or forced carriage return
+ while (line < end && *line && *line != '|') {
+ av_bprint_chars(&new_line, *line, 1);
+ line++;
+ }
+
+ // line split
+ if (line < end && *line == '|') {
+ microdvd_close_no_persistent_tags(&new_line, tags);
+ av_bprintf(&new_line, "\\N");
+ line++;
+ }
+ }
+ if (new_line.len) {
+ int ret;
+ int64_t start = avpkt->pts;
+ int64_t duration = avpkt->duration;
+ int ts_start = av_rescale_q(start, avctx->time_base, (AVRational){1,100});
+ int ts_duration = duration != -1 ?
+ av_rescale_q(duration, avctx->time_base, (AVRational){1,100}) : -1;
+
+ ret = ff_ass_add_rect_bprint(sub, &new_line, ts_start, ts_duration);
+ av_bprint_finalize(&new_line, NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+static int microdvd_init(AVCodecContext *avctx)
+{
+ int i, sidx;
+ AVBPrint font_buf;
+ int font_size = ASS_DEFAULT_FONT_SIZE;
+ int color = ASS_DEFAULT_COLOR;
+ int bold = ASS_DEFAULT_BOLD;
+ int italic = ASS_DEFAULT_ITALIC;
+ int underline = ASS_DEFAULT_UNDERLINE;
+ int alignment = ASS_DEFAULT_ALIGNMENT;
+ struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}};
+
+ av_bprint_init(&font_buf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ av_bprintf(&font_buf, "%s", ASS_DEFAULT_FONT);
+
+ if (avctx->extradata) {
+ microdvd_load_tags(tags, avctx->extradata);
+ for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) {
+ switch (av_tolower(tags[i].key)) {
+ case 'y':
+ for (sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++) {
+ if (tags[i].data1 & (1 << sidx)) {
+ switch (MICRODVD_STYLES[sidx]) {
+ case 'i': italic = 1; break;
+ case 'b': bold = 1; break;
+ case 'u': underline = 1; break;
+ }
+ }
+ }
+ break;
+
+ case 'c': color = tags[i].data1; break;
+ case 's': font_size = tags[i].data1; break;
+ case 'p': alignment = 8; break;
+
+ case 'f':
+ av_bprint_clear(&font_buf);
+ av_bprintf(&font_buf, "%.*s",
+ tags[i].data_string_len, tags[i].data_string);
+ break;
+ }
+ }
+ }
+ return ff_ass_subtitle_header(avctx, font_buf.str, font_size, color,
+ ASS_DEFAULT_BACK_COLOR, bold, italic,
+ underline, alignment);
+}
+
+AVCodec ff_microdvd_decoder = {
+ .name = "microdvd",
+ .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_MICRODVD,
+ .init = microdvd_init,
+ .decode = microdvd_decode_frame,
+};
diff --git a/libavcodec/mimic.c b/libavcodec/mimic.c
index 7f97366de4..73f2a13de8 100644
--- a/libavcodec/mimic.c
+++ b/libavcodec/mimic.c
@@ -2,20 +2,20 @@
* Copyright (C) 2005 Ole AndrĂ© Vadla RavnĂ¥s <oleavr@gmail.com>
* Copyright (C) 2008 Ramiro Polla
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -120,7 +120,8 @@ static av_cold int mimic_decode_end(AVCodecContext *avctx)
MimicContext *ctx = avctx->priv_data;
int i;
- av_free(ctx->swap_buf);
+ 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)
@@ -181,7 +182,7 @@ static int mimic_decode_update_thread_context(AVCodecContext *avctx, const AVCod
for (i = 0; i < FF_ARRAY_ELEMS(dst->frames); i++) {
ff_thread_release_buffer(avctx, &dst->frames[i]);
- if (src->frames[i].f->data[0]) {
+ 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;
@@ -257,7 +258,7 @@ static int vlc_decode_block(MimicContext *ctx, int num_coeffs, int qscale)
value = get_bits(&ctx->gb, num_bits);
- /* Libav's IDCT behaves somewhat different from the original code, so
+ /* FFmpeg's IDCT behaves somewhat different from the original code, so
* a factor of 4 was added to the input */
coeff = vlcdec_lookup[num_bits][value];
@@ -394,8 +395,8 @@ static int mimic_decode_frame(AVCodecContext *avctx, void *data,
avctx->height = height;
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
for (i = 0; i < 3; i++) {
- ctx->num_vblocks[i] = -((-height) >> (3 + !!i));
- ctx->num_hblocks[i] = width >> (3 + !!i);
+ ctx->num_vblocks[i] = FF_CEIL_RSHIFT(height, 3 + !!i);
+ ctx->num_hblocks[i] = width >> (3 + !!i);
}
} else if (width != ctx->avctx->width || height != ctx->avctx->height) {
avpriv_request_sample(avctx, "Resolution changing");
@@ -411,10 +412,8 @@ static int mimic_decode_frame(AVCodecContext *avctx, void *data,
ctx->frames[ctx->cur_index].f->pict_type = is_pframe ? AV_PICTURE_TYPE_P :
AV_PICTURE_TYPE_I;
if ((res = ff_thread_get_buffer(avctx, &ctx->frames[ctx->cur_index],
- AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ AV_GET_BUFFER_FLAG_REF)) < 0)
return res;
- }
ctx->next_prev_index = ctx->cur_index;
ctx->next_cur_index = (ctx->cur_index - 1) & 15;
diff --git a/libavcodec/mips/Makefile b/libavcodec/mips/Makefile
new file mode 100644
index 0000000000..eaedd7f8f5
--- /dev/null
+++ b/libavcodec/mips/Makefile
@@ -0,0 +1,24 @@
+MIPSFPU-OBJS-$(CONFIG_AMRNB_DECODER) += mips/acelp_filters_mips.o \
+ mips/celp_filters_mips.o \
+ mips/celp_math_mips.o \
+ mips/acelp_vectors_mips.o
+MIPSFPU-OBJS-$(CONFIG_AMRWB_DECODER) += mips/acelp_filters_mips.o \
+ mips/celp_filters_mips.o \
+ mips/amrwbdec_mips.o \
+ mips/celp_math_mips.o \
+ mips/acelp_vectors_mips.o
+MIPSFPU-OBJS-$(CONFIG_MPEGAUDIODSP) += mips/mpegaudiodsp_mips_float.o
+MIPSDSPR1-OBJS-$(CONFIG_MPEGAUDIODSP) += mips/mpegaudiodsp_mips_fixed.o
+MIPSFPU-OBJS-$(CONFIG_FFT) += mips/fft_mips.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
+MIPSDSPR1-OBJS-$(CONFIG_AAC_ENCODER) += mips/aaccoder_mips.o
+MIPSFPU-OBJS-$(CONFIG_AAC_ENCODER) += mips/iirfilter_mips.o
+OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_init_mips.o
+OBJS-$(CONFIG_H264DSP) += mips/h264dsp_init_mips.o
+MSA-OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_msa.o
+MSA-OBJS-$(CONFIG_H264DSP) += mips/h264dsp_msa.o
diff --git a/libavcodec/mips/aaccoder_mips.c b/libavcodec/mips/aaccoder_mips.c
new file mode 100644
index 0000000000..ea0bf3159b
--- /dev/null
+++ b/libavcodec/mips/aaccoder_mips.c
@@ -0,0 +1,2523 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ * Szabolcs Pal (sabolc@mips.com)
+ *
+ * AAC coefficients encoder 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/aaccoder.c
+ */
+
+#include "libavutil/libm.h"
+
+#include <float.h>
+#include "libavutil/mathematics.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/put_bits.h"
+#include "libavcodec/aac.h"
+#include "libavcodec/aacenc.h"
+#include "libavcodec/aactab.h"
+
+#if HAVE_INLINE_ASM
+typedef struct BandCodingPath {
+ int prev_idx;
+ float cost;
+ int run;
+} BandCodingPath;
+
+static const uint8_t run_value_bits_long[64] = {
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 15
+};
+
+static const uint8_t run_value_bits_short[16] = {
+ 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 9
+};
+
+static const uint8_t * const run_value_bits[2] = {
+ run_value_bits_long, run_value_bits_short
+};
+
+static const uint8_t uquad_sign_bits[81] = {
+ 0, 1, 1, 1, 2, 2, 1, 2, 2,
+ 1, 2, 2, 2, 3, 3, 2, 3, 3,
+ 1, 2, 2, 2, 3, 3, 2, 3, 3,
+ 1, 2, 2, 2, 3, 3, 2, 3, 3,
+ 2, 3, 3, 3, 4, 4, 3, 4, 4,
+ 2, 3, 3, 3, 4, 4, 3, 4, 4,
+ 1, 2, 2, 2, 3, 3, 2, 3, 3,
+ 2, 3, 3, 3, 4, 4, 3, 4, 4,
+ 2, 3, 3, 3, 4, 4, 3, 4, 4
+};
+
+static const uint8_t upair7_sign_bits[64] = {
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+};
+
+static const uint8_t upair12_sign_bits[169] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+static const uint8_t esc_sign_bits[289] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
+};
+
+static void abs_pow34_v(float *out, const float *in, const int size) {
+#ifndef USE_REALLY_FULL_SEARCH
+ int i;
+ float a, b, c, d;
+ float ax, bx, cx, dx;
+
+ for (i = 0; i < size; i += 4) {
+ a = fabsf(in[i ]);
+ b = fabsf(in[i+1]);
+ c = fabsf(in[i+2]);
+ d = fabsf(in[i+3]);
+
+ ax = sqrtf(a);
+ bx = sqrtf(b);
+ cx = sqrtf(c);
+ dx = sqrtf(d);
+
+ a = a * ax;
+ b = b * bx;
+ c = c * cx;
+ d = d * dx;
+
+ out[i ] = sqrtf(a);
+ out[i+1] = sqrtf(b);
+ out[i+2] = sqrtf(c);
+ out[i+3] = sqrtf(d);
+ }
+#endif /* USE_REALLY_FULL_SEARCH */
+}
+
+static float find_max_val(int group_len, int swb_size, const float *scaled) {
+ float maxval = 0.0f;
+ int w2, i;
+ for (w2 = 0; w2 < group_len; w2++) {
+ for (i = 0; i < swb_size; i++) {
+ maxval = FFMAX(maxval, scaled[w2*128+i]);
+ }
+ }
+ return maxval;
+}
+
+static int find_min_book(float maxval, int sf) {
+ float Q = ff_aac_pow2sf_tab[POW_SF2_ZERO - sf + SCALE_ONE_POS - SCALE_DIV_512];
+ float Q34 = sqrtf(Q * sqrtf(Q));
+ int qmaxval, cb;
+ qmaxval = maxval * Q34 + 0.4054f;
+ if (qmaxval == 0) cb = 0;
+ else if (qmaxval == 1) cb = 1;
+ else if (qmaxval == 2) cb = 3;
+ else if (qmaxval <= 4) cb = 5;
+ else if (qmaxval <= 7) cb = 7;
+ else if (qmaxval <= 12) cb = 9;
+ else cb = 11;
+ return cb;
+}
+
+/**
+ * Functions developed from template function and optimized for quantizing and encoding band
+ */
+static void quantize_and_encode_band_cost_SQUAD_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ uint16_t *p_codes = (uint16_t *)ff_aac_spectral_codes[cb-1];
+
+ abs_pow34_v(s->scoefs, in, size);
+ scaled = s->scoefs;
+ for (i = 0; i < size; i += 4) {
+ int curidx;
+ int *in_int = (int *)&in[i];
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "slt %[qc1], $zero, %[qc1] \n\t"
+ "slt %[qc2], $zero, %[qc2] \n\t"
+ "slt %[qc3], $zero, %[qc3] \n\t"
+ "slt %[qc4], $zero, %[qc4] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "srl %[t0], %[t0], 31 \n\t"
+ "srl %[t1], %[t1], 31 \n\t"
+ "srl %[t2], %[t2], 31 \n\t"
+ "srl %[t3], %[t3], 31 \n\t"
+ "subu %[t4], $zero, %[qc1] \n\t"
+ "subu %[t5], $zero, %[qc2] \n\t"
+ "subu %[t6], $zero, %[qc3] \n\t"
+ "subu %[t7], $zero, %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t5], %[t1] \n\t"
+ "movn %[qc3], %[t6], %[t2] \n\t"
+ "movn %[qc4], %[t7], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = qc1;
+ curidx *= 3;
+ curidx += qc2;
+ curidx *= 3;
+ curidx += qc3;
+ curidx *= 3;
+ curidx += qc4;
+ curidx += 40;
+
+ put_bits(pb, p_bits[curidx], p_codes[curidx]);
+ }
+}
+
+static void quantize_and_encode_band_cost_UQUAD_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ uint16_t *p_codes = (uint16_t *)ff_aac_spectral_codes[cb-1];
+
+ abs_pow34_v(s->scoefs, in, size);
+ scaled = s->scoefs;
+ for (i = 0; i < size; i += 4) {
+ int curidx, sign, count;
+ int *in_int = (int *)&in[i];
+ uint8_t v_bits;
+ unsigned int v_codes;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 2 \n\t"
+ "ori %[sign], $zero, 0 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign], %[t0], %[qc1] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign], %[t0], %[qc2] \n\t"
+ "slt %[t4], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count], $zero, %[qc3] \n\t"
+ "sll %[t0], %[sign], 1 \n\t"
+ "or %[t0], %[t0], %[t2] \n\t"
+ "movn %[sign], %[t0], %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count], %[count], %[t4] \n\t"
+ "addu %[count], %[count], %[t1] \n\t"
+ "sll %[t0], %[sign], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign], %[t0], %[qc4] \n\t"
+ "addu %[count], %[count], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign]"=&r"(sign), [count]"=&r"(count),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = qc1;
+ curidx *= 3;
+ curidx += qc2;
+ curidx *= 3;
+ curidx += qc3;
+ curidx *= 3;
+ curidx += qc4;
+
+ v_codes = (p_codes[curidx] << count) | (sign & ((1 << count) - 1));
+ v_bits = p_bits[curidx] + count;
+ put_bits(pb, v_bits, v_codes);
+ }
+}
+
+static void quantize_and_encode_band_cost_SPAIR_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ uint16_t *p_codes = (uint16_t *)ff_aac_spectral_codes[cb-1];
+
+ abs_pow34_v(s->scoefs, in, size);
+ scaled = s->scoefs;
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2;
+ int *in_int = (int *)&in[i];
+ uint8_t v_bits;
+ unsigned int v_codes;
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 4 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "srl %[t0], %[t0], 31 \n\t"
+ "srl %[t1], %[t1], 31 \n\t"
+ "srl %[t2], %[t2], 31 \n\t"
+ "srl %[t3], %[t3], 31 \n\t"
+ "subu %[t4], $zero, %[qc1] \n\t"
+ "subu %[t5], $zero, %[qc2] \n\t"
+ "subu %[t6], $zero, %[qc3] \n\t"
+ "subu %[t7], $zero, %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t5], %[t1] \n\t"
+ "movn %[qc3], %[t6], %[t2] \n\t"
+ "movn %[qc4], %[t7], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 9 * qc1;
+ curidx += qc2 + 40;
+
+ curidx2 = 9 * qc3;
+ curidx2 += qc4 + 40;
+
+ v_codes = (p_codes[curidx] << p_bits[curidx2]) | (p_codes[curidx2]);
+ v_bits = p_bits[curidx] + p_bits[curidx2];
+ put_bits(pb, v_bits, v_codes);
+ }
+}
+
+static void quantize_and_encode_band_cost_UPAIR7_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t*) ff_aac_spectral_bits[cb-1];
+ uint16_t *p_codes = (uint16_t*)ff_aac_spectral_codes[cb-1];
+
+ abs_pow34_v(s->scoefs, in, size);
+ scaled = s->scoefs;
+ for (i = 0; i < size; i += 4) {
+ int curidx, sign1, count1, sign2, count2;
+ int *in_int = (int *)&in[i];
+ uint8_t v_bits;
+ unsigned int v_codes;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 7 \n\t"
+ "ori %[sign1], $zero, 0 \n\t"
+ "ori %[sign2], $zero, 0 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign1], %[t0], %[qc1] \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "movn %[sign2], %[t2], %[qc3] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "sll %[t0], %[sign1], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign1], %[t0], %[qc2] \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign2], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign2], %[t0], %[qc4] \n\t"
+ "slt %[count1], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count2], $zero, %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count1], %[count1], %[t1] \n\t"
+ "addu %[count2], %[count2], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign1]"=&r"(sign1), [count1]"=&r"(count1),
+ [sign2]"=&r"(sign2), [count2]"=&r"(count2),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "t0", "t1", "t2", "t3", "t4",
+ "memory"
+ );
+
+ curidx = 8 * qc1;
+ curidx += qc2;
+
+ v_codes = (p_codes[curidx] << count1) | sign1;
+ v_bits = p_bits[curidx] + count1;
+ put_bits(pb, v_bits, v_codes);
+
+ curidx = 8 * qc3;
+ curidx += qc4;
+
+ v_codes = (p_codes[curidx] << count2) | sign2;
+ v_bits = p_bits[curidx] + count2;
+ put_bits(pb, v_bits, v_codes);
+ }
+}
+
+static void quantize_and_encode_band_cost_UPAIR12_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t*) ff_aac_spectral_bits[cb-1];
+ uint16_t *p_codes = (uint16_t*)ff_aac_spectral_codes[cb-1];
+
+ abs_pow34_v(s->scoefs, in, size);
+ scaled = s->scoefs;
+ for (i = 0; i < size; i += 4) {
+ int curidx, sign1, count1, sign2, count2;
+ int *in_int = (int *)&in[i];
+ uint8_t v_bits;
+ unsigned int v_codes;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 12 \n\t"
+ "ori %[sign1], $zero, 0 \n\t"
+ "ori %[sign2], $zero, 0 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign1], %[t0], %[qc1] \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "movn %[sign2], %[t2], %[qc3] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "sll %[t0], %[sign1], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign1], %[t0], %[qc2] \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign2], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign2], %[t0], %[qc4] \n\t"
+ "slt %[count1], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count2], $zero, %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count1], %[count1], %[t1] \n\t"
+ "addu %[count2], %[count2], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign1]"=&r"(sign1), [count1]"=&r"(count1),
+ [sign2]"=&r"(sign2), [count2]"=&r"(count2),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 13 * qc1;
+ curidx += qc2;
+
+ v_codes = (p_codes[curidx] << count1) | sign1;
+ v_bits = p_bits[curidx] + count1;
+ put_bits(pb, v_bits, v_codes);
+
+ curidx = 13 * qc3;
+ curidx += qc4;
+
+ v_codes = (p_codes[curidx] << count2) | sign2;
+ v_bits = p_bits[curidx] + count2;
+ put_bits(pb, v_bits, v_codes);
+ }
+}
+
+static void quantize_and_encode_band_cost_ESC_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t* )ff_aac_spectral_bits[cb-1];
+ uint16_t *p_codes = (uint16_t*)ff_aac_spectral_codes[cb-1];
+ float *p_vectors = (float* )ff_aac_codebook_vectors[cb-1];
+
+ abs_pow34_v(s->scoefs, in, size);
+ scaled = s->scoefs;
+
+ if (cb < 11) {
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2, sign1, count1, sign2, count2;
+ int *in_int = (int *)&in[i];
+ uint8_t v_bits;
+ unsigned int v_codes;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 16 \n\t"
+ "ori %[sign1], $zero, 0 \n\t"
+ "ori %[sign2], $zero, 0 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign1], %[t0], %[qc1] \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "movn %[sign2], %[t2], %[qc3] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "sll %[t0], %[sign1], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign1], %[t0], %[qc2] \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign2], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign2], %[t0], %[qc4] \n\t"
+ "slt %[count1], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count2], $zero, %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count1], %[count1], %[t1] \n\t"
+ "addu %[count2], %[count2], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign1]"=&r"(sign1), [count1]"=&r"(count1),
+ [sign2]"=&r"(sign2), [count2]"=&r"(count2),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 17 * qc1;
+ curidx += qc2;
+ curidx2 = 17 * qc3;
+ curidx2 += qc4;
+
+ v_codes = (p_codes[curidx] << count1) | sign1;
+ v_bits = p_bits[curidx] + count1;
+ put_bits(pb, v_bits, v_codes);
+
+ v_codes = (p_codes[curidx2] << count2) | sign2;
+ v_bits = p_bits[curidx2] + count2;
+ put_bits(pb, v_bits, v_codes);
+ }
+ } else {
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2, sign1, count1, sign2, count2;
+ int *in_int = (int *)&in[i];
+ uint8_t v_bits;
+ unsigned int v_codes;
+ int c1, c2, c3, c4;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 16 \n\t"
+ "ori %[sign1], $zero, 0 \n\t"
+ "ori %[sign2], $zero, 0 \n\t"
+ "shll_s.w %[c1], %[qc1], 18 \n\t"
+ "shll_s.w %[c2], %[qc2], 18 \n\t"
+ "shll_s.w %[c3], %[qc3], 18 \n\t"
+ "shll_s.w %[c4], %[qc4], 18 \n\t"
+ "srl %[c1], %[c1], 18 \n\t"
+ "srl %[c2], %[c2], 18 \n\t"
+ "srl %[c3], %[c3], 18 \n\t"
+ "srl %[c4], %[c4], 18 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign1], %[t0], %[qc1] \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "movn %[sign2], %[t2], %[qc3] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "sll %[t0], %[sign1], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign1], %[t0], %[qc2] \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign2], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign2], %[t0], %[qc4] \n\t"
+ "slt %[count1], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count2], $zero, %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count1], %[count1], %[t1] \n\t"
+ "addu %[count2], %[count2], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign1]"=&r"(sign1), [count1]"=&r"(count1),
+ [sign2]"=&r"(sign2), [count2]"=&r"(count2),
+ [c1]"=&r"(c1), [c2]"=&r"(c2),
+ [c3]"=&r"(c3), [c4]"=&r"(c4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 17 * qc1;
+ curidx += qc2;
+
+ curidx2 = 17 * qc3;
+ curidx2 += qc4;
+
+ v_codes = (p_codes[curidx] << count1) | sign1;
+ v_bits = p_bits[curidx] + count1;
+ put_bits(pb, v_bits, v_codes);
+
+ if (p_vectors[curidx*2 ] == 64.0f) {
+ int len = av_log2(c1);
+ v_codes = (((1 << (len - 3)) - 2) << len) | (c1 & ((1 << len) - 1));
+ put_bits(pb, len * 2 - 3, v_codes);
+ }
+ if (p_vectors[curidx*2+1] == 64.0f) {
+ int len = av_log2(c2);
+ v_codes = (((1 << (len - 3)) - 2) << len) | (c2 & ((1 << len) - 1));
+ put_bits(pb, len*2-3, v_codes);
+ }
+
+ v_codes = (p_codes[curidx2] << count2) | sign2;
+ v_bits = p_bits[curidx2] + count2;
+ put_bits(pb, v_bits, v_codes);
+
+ if (p_vectors[curidx2*2 ] == 64.0f) {
+ int len = av_log2(c3);
+ v_codes = (((1 << (len - 3)) - 2) << len) | (c3 & ((1 << len) - 1));
+ put_bits(pb, len* 2 - 3, v_codes);
+ }
+ if (p_vectors[curidx2*2+1] == 64.0f) {
+ int len = av_log2(c4);
+ v_codes = (((1 << (len - 3)) - 2) << len) | (c4 & ((1 << len) - 1));
+ put_bits(pb, len * 2 - 3, v_codes);
+ }
+ }
+ }
+}
+
+static void (*const quantize_and_encode_band_cost_arr[])(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits) = {
+ NULL,
+ quantize_and_encode_band_cost_SQUAD_mips,
+ quantize_and_encode_band_cost_SQUAD_mips,
+ quantize_and_encode_band_cost_UQUAD_mips,
+ quantize_and_encode_band_cost_UQUAD_mips,
+ quantize_and_encode_band_cost_SPAIR_mips,
+ quantize_and_encode_band_cost_SPAIR_mips,
+ quantize_and_encode_band_cost_UPAIR7_mips,
+ quantize_and_encode_band_cost_UPAIR7_mips,
+ quantize_and_encode_band_cost_UPAIR12_mips,
+ quantize_and_encode_band_cost_UPAIR12_mips,
+ quantize_and_encode_band_cost_ESC_mips,
+};
+
+#define quantize_and_encode_band_cost( \
+ s, pb, in, scaled, size, scale_idx, cb, \
+ lambda, uplim, bits) \
+ quantize_and_encode_band_cost_arr[cb]( \
+ s, pb, in, scaled, size, scale_idx, cb, \
+ lambda, uplim, bits)
+
+static void quantize_and_encode_band_mips(struct AACEncContext *s, PutBitContext *pb,
+ const float *in, int size, int scale_idx,
+ int cb, const float lambda)
+{
+ quantize_and_encode_band_cost(s, pb, in, NULL, size, scale_idx, cb, lambda,
+ INFINITY, NULL);
+}
+
+/**
+ * Functions developed from template function and optimized for getting the number of bits
+ */
+static float get_band_numbits_ZERO_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ return 0;
+}
+
+static float get_band_numbits_SQUAD_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ int curidx;
+ int *in_int = (int *)&in[i];
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "slt %[qc1], $zero, %[qc1] \n\t"
+ "slt %[qc2], $zero, %[qc2] \n\t"
+ "slt %[qc3], $zero, %[qc3] \n\t"
+ "slt %[qc4], $zero, %[qc4] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "srl %[t0], %[t0], 31 \n\t"
+ "srl %[t1], %[t1], 31 \n\t"
+ "srl %[t2], %[t2], 31 \n\t"
+ "srl %[t3], %[t3], 31 \n\t"
+ "subu %[t4], $zero, %[qc1] \n\t"
+ "subu %[t5], $zero, %[qc2] \n\t"
+ "subu %[t6], $zero, %[qc3] \n\t"
+ "subu %[t7], $zero, %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t5], %[t1] \n\t"
+ "movn %[qc3], %[t6], %[t2] \n\t"
+ "movn %[qc4], %[t7], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = qc1;
+ curidx *= 3;
+ curidx += qc2;
+ curidx *= 3;
+ curidx += qc3;
+ curidx *= 3;
+ curidx += qc4;
+ curidx += 40;
+
+ curbits += p_bits[curidx];
+ }
+ return curbits;
+}
+
+static float get_band_numbits_UQUAD_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int curbits = 0;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ int curidx;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 2 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ );
+
+ curidx = qc1;
+ curidx *= 3;
+ curidx += qc2;
+ curidx *= 3;
+ curidx += qc3;
+ curidx *= 3;
+ curidx += qc4;
+
+ curbits += p_bits[curidx];
+ curbits += uquad_sign_bits[curidx];
+ }
+ return curbits;
+}
+
+static float get_band_numbits_SPAIR_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t*)ff_aac_spectral_bits[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2;
+ int *in_int = (int *)&in[i];
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 4 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "srl %[t0], %[t0], 31 \n\t"
+ "srl %[t1], %[t1], 31 \n\t"
+ "srl %[t2], %[t2], 31 \n\t"
+ "srl %[t3], %[t3], 31 \n\t"
+ "subu %[t4], $zero, %[qc1] \n\t"
+ "subu %[t5], $zero, %[qc2] \n\t"
+ "subu %[t6], $zero, %[qc3] \n\t"
+ "subu %[t7], $zero, %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t5], %[t1] \n\t"
+ "movn %[qc3], %[t6], %[t2] \n\t"
+ "movn %[qc4], %[t7], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 9 * qc1;
+ curidx += qc2 + 40;
+
+ curidx2 = 9 * qc3;
+ curidx2 += qc4 + 40;
+
+ curbits += p_bits[curidx] + p_bits[curidx2];
+ }
+ return curbits;
+}
+
+static float get_band_numbits_UPAIR7_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 7 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ );
+
+ curidx = 8 * qc1;
+ curidx += qc2;
+
+ curidx2 = 8 * qc3;
+ curidx2 += qc4;
+
+ curbits += p_bits[curidx] +
+ upair7_sign_bits[curidx] +
+ p_bits[curidx2] +
+ upair7_sign_bits[curidx2];
+ }
+ return curbits;
+}
+
+static float get_band_numbits_UPAIR12_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 12 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ );
+
+ curidx = 13 * qc1;
+ curidx += qc2;
+
+ curidx2 = 13 * qc3;
+ curidx2 += qc4;
+
+ curbits += p_bits[curidx] +
+ p_bits[curidx2] +
+ upair12_sign_bits[curidx] +
+ upair12_sign_bits[curidx2];
+ }
+ return curbits;
+}
+
+static float get_band_numbits_ESC_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ int i;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t*)ff_aac_spectral_bits[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ int curidx, curidx2;
+ int cond0, cond1, cond2, cond3;
+ int c1, c2, c3, c4;
+ int t4, t5;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 15 \n\t"
+ "ori %[t5], $zero, 16 \n\t"
+ "shll_s.w %[c1], %[qc1], 18 \n\t"
+ "shll_s.w %[c2], %[qc2], 18 \n\t"
+ "shll_s.w %[c3], %[qc3], 18 \n\t"
+ "shll_s.w %[c4], %[qc4], 18 \n\t"
+ "srl %[c1], %[c1], 18 \n\t"
+ "srl %[c2], %[c2], 18 \n\t"
+ "srl %[c3], %[c3], 18 \n\t"
+ "srl %[c4], %[c4], 18 \n\t"
+ "slt %[cond0], %[t4], %[qc1] \n\t"
+ "slt %[cond1], %[t4], %[qc2] \n\t"
+ "slt %[cond2], %[t4], %[qc3] \n\t"
+ "slt %[cond3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t5], %[cond0] \n\t"
+ "movn %[qc2], %[t5], %[cond1] \n\t"
+ "movn %[qc3], %[t5], %[cond2] \n\t"
+ "movn %[qc4], %[t5], %[cond3] \n\t"
+ "ori %[t5], $zero, 31 \n\t"
+ "clz %[c1], %[c1] \n\t"
+ "clz %[c2], %[c2] \n\t"
+ "clz %[c3], %[c3] \n\t"
+ "clz %[c4], %[c4] \n\t"
+ "subu %[c1], %[t5], %[c1] \n\t"
+ "subu %[c2], %[t5], %[c2] \n\t"
+ "subu %[c3], %[t5], %[c3] \n\t"
+ "subu %[c4], %[t5], %[c4] \n\t"
+ "sll %[c1], %[c1], 1 \n\t"
+ "sll %[c2], %[c2], 1 \n\t"
+ "sll %[c3], %[c3], 1 \n\t"
+ "sll %[c4], %[c4], 1 \n\t"
+ "addiu %[c1], %[c1], -3 \n\t"
+ "addiu %[c2], %[c2], -3 \n\t"
+ "addiu %[c3], %[c3], -3 \n\t"
+ "addiu %[c4], %[c4], -3 \n\t"
+ "subu %[cond0], $zero, %[cond0] \n\t"
+ "subu %[cond1], $zero, %[cond1] \n\t"
+ "subu %[cond2], $zero, %[cond2] \n\t"
+ "subu %[cond3], $zero, %[cond3] \n\t"
+ "and %[c1], %[c1], %[cond0] \n\t"
+ "and %[c2], %[c2], %[cond1] \n\t"
+ "and %[c3], %[c3], %[cond2] \n\t"
+ "and %[c4], %[c4], %[cond3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [cond0]"=&r"(cond0), [cond1]"=&r"(cond1),
+ [cond2]"=&r"(cond2), [cond3]"=&r"(cond3),
+ [c1]"=&r"(c1), [c2]"=&r"(c2),
+ [c3]"=&r"(c3), [c4]"=&r"(c4),
+ [t4]"=&r"(t4), [t5]"=&r"(t5)
+ );
+
+ curidx = 17 * qc1;
+ curidx += qc2;
+
+ curidx2 = 17 * qc3;
+ curidx2 += qc4;
+
+ curbits += p_bits[curidx];
+ curbits += esc_sign_bits[curidx];
+ curbits += p_bits[curidx2];
+ curbits += esc_sign_bits[curidx2];
+
+ curbits += c1;
+ curbits += c2;
+ curbits += c3;
+ curbits += c4;
+ }
+ return curbits;
+}
+
+static float (*const get_band_numbits_arr[])(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits) = {
+ get_band_numbits_ZERO_mips,
+ get_band_numbits_SQUAD_mips,
+ get_band_numbits_SQUAD_mips,
+ get_band_numbits_UQUAD_mips,
+ get_band_numbits_UQUAD_mips,
+ get_band_numbits_SPAIR_mips,
+ get_band_numbits_SPAIR_mips,
+ get_band_numbits_UPAIR7_mips,
+ get_band_numbits_UPAIR7_mips,
+ get_band_numbits_UPAIR12_mips,
+ get_band_numbits_UPAIR12_mips,
+ get_band_numbits_ESC_mips,
+};
+
+#define get_band_numbits( \
+ s, pb, in, scaled, size, scale_idx, cb, \
+ lambda, uplim, bits) \
+ get_band_numbits_arr[cb]( \
+ s, pb, in, scaled, size, scale_idx, cb, \
+ lambda, uplim, bits)
+
+static float quantize_band_cost_bits(struct AACEncContext *s, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ return get_band_numbits(s, NULL, in, scaled, size, scale_idx, cb, lambda, uplim, bits);
+}
+
+/**
+ * Functions developed from template function and optimized for getting the band cost
+ */
+#if HAVE_MIPSFPU
+static float get_band_cost_ZERO_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ int i;
+ float cost = 0;
+
+ for (i = 0; i < size; i += 4) {
+ cost += in[i ] * in[i ];
+ cost += in[i+1] * in[i+1];
+ cost += in[i+2] * in[i+2];
+ cost += in[i+3] * in[i+3];
+ }
+ if (bits)
+ *bits = 0;
+ return cost * lambda;
+}
+
+static float get_band_cost_SQUAD_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];
+ int i;
+ float cost = 0;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ float *p_codes = (float *)ff_aac_codebook_vectors[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ const float *vec;
+ int curidx;
+ int *in_int = (int *)&in[i];
+ float *in_pos = (float *)&in[i];
+ float di0, di1, di2, di3;
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "slt %[qc1], $zero, %[qc1] \n\t"
+ "slt %[qc2], $zero, %[qc2] \n\t"
+ "slt %[qc3], $zero, %[qc3] \n\t"
+ "slt %[qc4], $zero, %[qc4] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "srl %[t0], %[t0], 31 \n\t"
+ "srl %[t1], %[t1], 31 \n\t"
+ "srl %[t2], %[t2], 31 \n\t"
+ "srl %[t3], %[t3], 31 \n\t"
+ "subu %[t4], $zero, %[qc1] \n\t"
+ "subu %[t5], $zero, %[qc2] \n\t"
+ "subu %[t6], $zero, %[qc3] \n\t"
+ "subu %[t7], $zero, %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t5], %[t1] \n\t"
+ "movn %[qc3], %[t6], %[t2] \n\t"
+ "movn %[qc4], %[t7], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = qc1;
+ curidx *= 3;
+ curidx += qc2;
+ curidx *= 3;
+ curidx += qc3;
+ curidx *= 3;
+ curidx += qc4;
+ curidx += 40;
+
+ curbits += p_bits[curidx];
+ vec = &p_codes[curidx*4];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "lwc1 $f0, 0(%[in_pos]) \n\t"
+ "lwc1 $f1, 0(%[vec]) \n\t"
+ "lwc1 $f2, 4(%[in_pos]) \n\t"
+ "lwc1 $f3, 4(%[vec]) \n\t"
+ "lwc1 $f4, 8(%[in_pos]) \n\t"
+ "lwc1 $f5, 8(%[vec]) \n\t"
+ "lwc1 $f6, 12(%[in_pos]) \n\t"
+ "lwc1 $f7, 12(%[vec]) \n\t"
+ "nmsub.s %[di0], $f0, $f1, %[IQ] \n\t"
+ "nmsub.s %[di1], $f2, $f3, %[IQ] \n\t"
+ "nmsub.s %[di2], $f4, $f5, %[IQ] \n\t"
+ "nmsub.s %[di3], $f6, $f7, %[IQ] \n\t"
+
+ ".set pop \n\t"
+
+ : [di0]"=&f"(di0), [di1]"=&f"(di1),
+ [di2]"=&f"(di2), [di3]"=&f"(di3)
+ : [in_pos]"r"(in_pos), [vec]"r"(vec),
+ [IQ]"f"(IQ)
+ : "$f0", "$f1", "$f2", "$f3",
+ "$f4", "$f5", "$f6", "$f7",
+ "memory"
+ );
+
+ cost += di0 * di0 + di1 * di1
+ + di2 * di2 + di3 * di3;
+ }
+
+ if (bits)
+ *bits = curbits;
+ return cost * lambda + curbits;
+}
+
+static float get_band_cost_UQUAD_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];
+ int i;
+ float cost = 0;
+ int curbits = 0;
+ int qc1, qc2, qc3, qc4;
+
+ uint8_t *p_bits = (uint8_t*)ff_aac_spectral_bits[cb-1];
+ float *p_codes = (float *)ff_aac_codebook_vectors[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ const float *vec;
+ int curidx;
+ float *in_pos = (float *)&in[i];
+ float di0, di1, di2, di3;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 2 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ );
+
+ curidx = qc1;
+ curidx *= 3;
+ curidx += qc2;
+ curidx *= 3;
+ curidx += qc3;
+ curidx *= 3;
+ curidx += qc4;
+
+ curbits += p_bits[curidx];
+ curbits += uquad_sign_bits[curidx];
+ vec = &p_codes[curidx*4];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "lwc1 %[di0], 0(%[in_pos]) \n\t"
+ "lwc1 %[di1], 4(%[in_pos]) \n\t"
+ "lwc1 %[di2], 8(%[in_pos]) \n\t"
+ "lwc1 %[di3], 12(%[in_pos]) \n\t"
+ "abs.s %[di0], %[di0] \n\t"
+ "abs.s %[di1], %[di1] \n\t"
+ "abs.s %[di2], %[di2] \n\t"
+ "abs.s %[di3], %[di3] \n\t"
+ "lwc1 $f0, 0(%[vec]) \n\t"
+ "lwc1 $f1, 4(%[vec]) \n\t"
+ "lwc1 $f2, 8(%[vec]) \n\t"
+ "lwc1 $f3, 12(%[vec]) \n\t"
+ "nmsub.s %[di0], %[di0], $f0, %[IQ] \n\t"
+ "nmsub.s %[di1], %[di1], $f1, %[IQ] \n\t"
+ "nmsub.s %[di2], %[di2], $f2, %[IQ] \n\t"
+ "nmsub.s %[di3], %[di3], $f3, %[IQ] \n\t"
+
+ ".set pop \n\t"
+
+ : [di0]"=&f"(di0), [di1]"=&f"(di1),
+ [di2]"=&f"(di2), [di3]"=&f"(di3)
+ : [in_pos]"r"(in_pos), [vec]"r"(vec),
+ [IQ]"f"(IQ)
+ : "$f0", "$f1", "$f2", "$f3",
+ "memory"
+ );
+
+ cost += di0 * di0 + di1 * di1
+ + di2 * di2 + di3 * di3;
+ }
+
+ if (bits)
+ *bits = curbits;
+ return cost * lambda + curbits;
+}
+
+static float get_band_cost_SPAIR_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];
+ int i;
+ float cost = 0;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ float *p_codes = (float *)ff_aac_codebook_vectors[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ const float *vec, *vec2;
+ int curidx, curidx2;
+ int *in_int = (int *)&in[i];
+ float *in_pos = (float *)&in[i];
+ float di0, di1, di2, di3;
+ int t0, t1, t2, t3, t4, t5, t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 4 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "srl %[t0], %[t0], 31 \n\t"
+ "srl %[t1], %[t1], 31 \n\t"
+ "srl %[t2], %[t2], 31 \n\t"
+ "srl %[t3], %[t3], 31 \n\t"
+ "subu %[t4], $zero, %[qc1] \n\t"
+ "subu %[t5], $zero, %[qc2] \n\t"
+ "subu %[t6], $zero, %[qc3] \n\t"
+ "subu %[t7], $zero, %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t5], %[t1] \n\t"
+ "movn %[qc3], %[t6], %[t2] \n\t"
+ "movn %[qc4], %[t7], %[t3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4), [t5]"=&r"(t5), [t6]"=&r"(t6), [t7]"=&r"(t7)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 9 * qc1;
+ curidx += qc2 + 40;
+
+ curidx2 = 9 * qc3;
+ curidx2 += qc4 + 40;
+
+ curbits += p_bits[curidx];
+ curbits += p_bits[curidx2];
+
+ vec = &p_codes[curidx*2];
+ vec2 = &p_codes[curidx2*2];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "lwc1 $f0, 0(%[in_pos]) \n\t"
+ "lwc1 $f1, 0(%[vec]) \n\t"
+ "lwc1 $f2, 4(%[in_pos]) \n\t"
+ "lwc1 $f3, 4(%[vec]) \n\t"
+ "lwc1 $f4, 8(%[in_pos]) \n\t"
+ "lwc1 $f5, 0(%[vec2]) \n\t"
+ "lwc1 $f6, 12(%[in_pos]) \n\t"
+ "lwc1 $f7, 4(%[vec2]) \n\t"
+ "nmsub.s %[di0], $f0, $f1, %[IQ] \n\t"
+ "nmsub.s %[di1], $f2, $f3, %[IQ] \n\t"
+ "nmsub.s %[di2], $f4, $f5, %[IQ] \n\t"
+ "nmsub.s %[di3], $f6, $f7, %[IQ] \n\t"
+
+ ".set pop \n\t"
+
+ : [di0]"=&f"(di0), [di1]"=&f"(di1),
+ [di2]"=&f"(di2), [di3]"=&f"(di3)
+ : [in_pos]"r"(in_pos), [vec]"r"(vec),
+ [vec2]"r"(vec2), [IQ]"f"(IQ)
+ : "$f0", "$f1", "$f2", "$f3",
+ "$f4", "$f5", "$f6", "$f7",
+ "memory"
+ );
+
+ cost += di0 * di0 + di1 * di1
+ + di2 * di2 + di3 * di3;
+ }
+
+ if (bits)
+ *bits = curbits;
+ return cost * lambda + curbits;
+}
+
+static float get_band_cost_UPAIR7_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];
+ int i;
+ float cost = 0;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ float *p_codes = (float *)ff_aac_codebook_vectors[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ const float *vec, *vec2;
+ int curidx, curidx2, sign1, count1, sign2, count2;
+ int *in_int = (int *)&in[i];
+ float *in_pos = (float *)&in[i];
+ float di0, di1, di2, di3;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 7 \n\t"
+ "ori %[sign1], $zero, 0 \n\t"
+ "ori %[sign2], $zero, 0 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign1], %[t0], %[qc1] \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "movn %[sign2], %[t2], %[qc3] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "sll %[t0], %[sign1], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign1], %[t0], %[qc2] \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign2], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign2], %[t0], %[qc4] \n\t"
+ "slt %[count1], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count2], $zero, %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count1], %[count1], %[t1] \n\t"
+ "addu %[count2], %[count2], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign1]"=&r"(sign1), [count1]"=&r"(count1),
+ [sign2]"=&r"(sign2), [count2]"=&r"(count2),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 8 * qc1;
+ curidx += qc2;
+
+ curidx2 = 8 * qc3;
+ curidx2 += qc4;
+
+ curbits += p_bits[curidx];
+ curbits += upair7_sign_bits[curidx];
+ vec = &p_codes[curidx*2];
+
+ curbits += p_bits[curidx2];
+ curbits += upair7_sign_bits[curidx2];
+ vec2 = &p_codes[curidx2*2];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "lwc1 %[di0], 0(%[in_pos]) \n\t"
+ "lwc1 %[di1], 4(%[in_pos]) \n\t"
+ "lwc1 %[di2], 8(%[in_pos]) \n\t"
+ "lwc1 %[di3], 12(%[in_pos]) \n\t"
+ "abs.s %[di0], %[di0] \n\t"
+ "abs.s %[di1], %[di1] \n\t"
+ "abs.s %[di2], %[di2] \n\t"
+ "abs.s %[di3], %[di3] \n\t"
+ "lwc1 $f0, 0(%[vec]) \n\t"
+ "lwc1 $f1, 4(%[vec]) \n\t"
+ "lwc1 $f2, 0(%[vec2]) \n\t"
+ "lwc1 $f3, 4(%[vec2]) \n\t"
+ "nmsub.s %[di0], %[di0], $f0, %[IQ] \n\t"
+ "nmsub.s %[di1], %[di1], $f1, %[IQ] \n\t"
+ "nmsub.s %[di2], %[di2], $f2, %[IQ] \n\t"
+ "nmsub.s %[di3], %[di3], $f3, %[IQ] \n\t"
+
+ ".set pop \n\t"
+
+ : [di0]"=&f"(di0), [di1]"=&f"(di1),
+ [di2]"=&f"(di2), [di3]"=&f"(di3)
+ : [in_pos]"r"(in_pos), [vec]"r"(vec),
+ [vec2]"r"(vec2), [IQ]"f"(IQ)
+ : "$f0", "$f1", "$f2", "$f3",
+ "memory"
+ );
+
+ cost += di0 * di0 + di1 * di1
+ + di2 * di2 + di3 * di3;
+ }
+
+ if (bits)
+ *bits = curbits;
+ return cost * lambda + curbits;
+}
+
+static float get_band_cost_UPAIR12_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];
+ int i;
+ float cost = 0;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t *)ff_aac_spectral_bits[cb-1];
+ float *p_codes = (float *)ff_aac_codebook_vectors[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ const float *vec, *vec2;
+ int curidx, curidx2;
+ int sign1, count1, sign2, count2;
+ int *in_int = (int *)&in[i];
+ float *in_pos = (float *)&in[i];
+ float di0, di1, di2, di3;
+ int t0, t1, t2, t3, t4;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t4], $zero, 12 \n\t"
+ "ori %[sign1], $zero, 0 \n\t"
+ "ori %[sign2], $zero, 0 \n\t"
+ "slt %[t0], %[t4], %[qc1] \n\t"
+ "slt %[t1], %[t4], %[qc2] \n\t"
+ "slt %[t2], %[t4], %[qc3] \n\t"
+ "slt %[t3], %[t4], %[qc4] \n\t"
+ "movn %[qc1], %[t4], %[t0] \n\t"
+ "movn %[qc2], %[t4], %[t1] \n\t"
+ "movn %[qc3], %[t4], %[t2] \n\t"
+ "movn %[qc4], %[t4], %[t3] \n\t"
+ "lw %[t0], 0(%[in_int]) \n\t"
+ "lw %[t1], 4(%[in_int]) \n\t"
+ "lw %[t2], 8(%[in_int]) \n\t"
+ "lw %[t3], 12(%[in_int]) \n\t"
+ "slt %[t0], %[t0], $zero \n\t"
+ "movn %[sign1], %[t0], %[qc1] \n\t"
+ "slt %[t2], %[t2], $zero \n\t"
+ "movn %[sign2], %[t2], %[qc3] \n\t"
+ "slt %[t1], %[t1], $zero \n\t"
+ "sll %[t0], %[sign1], 1 \n\t"
+ "or %[t0], %[t0], %[t1] \n\t"
+ "movn %[sign1], %[t0], %[qc2] \n\t"
+ "slt %[t3], %[t3], $zero \n\t"
+ "sll %[t0], %[sign2], 1 \n\t"
+ "or %[t0], %[t0], %[t3] \n\t"
+ "movn %[sign2], %[t0], %[qc4] \n\t"
+ "slt %[count1], $zero, %[qc1] \n\t"
+ "slt %[t1], $zero, %[qc2] \n\t"
+ "slt %[count2], $zero, %[qc3] \n\t"
+ "slt %[t2], $zero, %[qc4] \n\t"
+ "addu %[count1], %[count1], %[t1] \n\t"
+ "addu %[count2], %[count2], %[t2] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [sign1]"=&r"(sign1), [count1]"=&r"(count1),
+ [sign2]"=&r"(sign2), [count2]"=&r"(count2),
+ [t0]"=&r"(t0), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3),
+ [t4]"=&r"(t4)
+ : [in_int]"r"(in_int)
+ : "memory"
+ );
+
+ curidx = 13 * qc1;
+ curidx += qc2;
+
+ curidx2 = 13 * qc3;
+ curidx2 += qc4;
+
+ curbits += p_bits[curidx];
+ curbits += p_bits[curidx2];
+ curbits += upair12_sign_bits[curidx];
+ curbits += upair12_sign_bits[curidx2];
+ vec = &p_codes[curidx*2];
+ vec2 = &p_codes[curidx2*2];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "lwc1 %[di0], 0(%[in_pos]) \n\t"
+ "lwc1 %[di1], 4(%[in_pos]) \n\t"
+ "lwc1 %[di2], 8(%[in_pos]) \n\t"
+ "lwc1 %[di3], 12(%[in_pos]) \n\t"
+ "abs.s %[di0], %[di0] \n\t"
+ "abs.s %[di1], %[di1] \n\t"
+ "abs.s %[di2], %[di2] \n\t"
+ "abs.s %[di3], %[di3] \n\t"
+ "lwc1 $f0, 0(%[vec]) \n\t"
+ "lwc1 $f1, 4(%[vec]) \n\t"
+ "lwc1 $f2, 0(%[vec2]) \n\t"
+ "lwc1 $f3, 4(%[vec2]) \n\t"
+ "nmsub.s %[di0], %[di0], $f0, %[IQ] \n\t"
+ "nmsub.s %[di1], %[di1], $f1, %[IQ] \n\t"
+ "nmsub.s %[di2], %[di2], $f2, %[IQ] \n\t"
+ "nmsub.s %[di3], %[di3], $f3, %[IQ] \n\t"
+
+ ".set pop \n\t"
+
+ : [di0]"=&f"(di0), [di1]"=&f"(di1),
+ [di2]"=&f"(di2), [di3]"=&f"(di3)
+ : [in_pos]"r"(in_pos), [vec]"r"(vec),
+ [vec2]"r"(vec2), [IQ]"f"(IQ)
+ : "$f0", "$f1", "$f2", "$f3",
+ "memory"
+ );
+
+ cost += di0 * di0 + di1 * di1
+ + di2 * di2 + di3 * di3;
+ }
+
+ if (bits)
+ *bits = curbits;
+ return cost * lambda + curbits;
+}
+
+static float get_band_cost_ESC_mips(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ const float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512];
+ const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512];
+ const float CLIPPED_ESCAPE = 165140.0f * IQ;
+ int i;
+ float cost = 0;
+ int qc1, qc2, qc3, qc4;
+ int curbits = 0;
+
+ uint8_t *p_bits = (uint8_t*)ff_aac_spectral_bits[cb-1];
+ float *p_codes = (float* )ff_aac_codebook_vectors[cb-1];
+
+ for (i = 0; i < size; i += 4) {
+ const float *vec, *vec2;
+ int curidx, curidx2;
+ float t1, t2, t3, t4;
+ float di1, di2, di3, di4;
+ int cond0, cond1, cond2, cond3;
+ int c1, c2, c3, c4;
+ int t6, t7;
+
+ qc1 = scaled[i ] * Q34 + 0.4054f;
+ qc2 = scaled[i+1] * Q34 + 0.4054f;
+ qc3 = scaled[i+2] * Q34 + 0.4054f;
+ qc4 = scaled[i+3] * Q34 + 0.4054f;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "ori %[t6], $zero, 15 \n\t"
+ "ori %[t7], $zero, 16 \n\t"
+ "shll_s.w %[c1], %[qc1], 18 \n\t"
+ "shll_s.w %[c2], %[qc2], 18 \n\t"
+ "shll_s.w %[c3], %[qc3], 18 \n\t"
+ "shll_s.w %[c4], %[qc4], 18 \n\t"
+ "srl %[c1], %[c1], 18 \n\t"
+ "srl %[c2], %[c2], 18 \n\t"
+ "srl %[c3], %[c3], 18 \n\t"
+ "srl %[c4], %[c4], 18 \n\t"
+ "slt %[cond0], %[t6], %[qc1] \n\t"
+ "slt %[cond1], %[t6], %[qc2] \n\t"
+ "slt %[cond2], %[t6], %[qc3] \n\t"
+ "slt %[cond3], %[t6], %[qc4] \n\t"
+ "movn %[qc1], %[t7], %[cond0] \n\t"
+ "movn %[qc2], %[t7], %[cond1] \n\t"
+ "movn %[qc3], %[t7], %[cond2] \n\t"
+ "movn %[qc4], %[t7], %[cond3] \n\t"
+
+ ".set pop \n\t"
+
+ : [qc1]"+r"(qc1), [qc2]"+r"(qc2),
+ [qc3]"+r"(qc3), [qc4]"+r"(qc4),
+ [cond0]"=&r"(cond0), [cond1]"=&r"(cond1),
+ [cond2]"=&r"(cond2), [cond3]"=&r"(cond3),
+ [c1]"=&r"(c1), [c2]"=&r"(c2),
+ [c3]"=&r"(c3), [c4]"=&r"(c4),
+ [t6]"=&r"(t6), [t7]"=&r"(t7)
+ );
+
+ curidx = 17 * qc1;
+ curidx += qc2;
+
+ curidx2 = 17 * qc3;
+ curidx2 += qc4;
+
+ curbits += p_bits[curidx];
+ curbits += esc_sign_bits[curidx];
+ vec = &p_codes[curidx*2];
+
+ curbits += p_bits[curidx2];
+ curbits += esc_sign_bits[curidx2];
+ vec2 = &p_codes[curidx2*2];
+
+ curbits += (av_log2(c1) * 2 - 3) & (-cond0);
+ curbits += (av_log2(c2) * 2 - 3) & (-cond1);
+ curbits += (av_log2(c3) * 2 - 3) & (-cond2);
+ curbits += (av_log2(c4) * 2 - 3) & (-cond3);
+
+ t1 = fabsf(in[i ]);
+ t2 = fabsf(in[i+1]);
+ t3 = fabsf(in[i+2]);
+ t4 = fabsf(in[i+3]);
+
+ if (cond0) {
+ if (t1 >= CLIPPED_ESCAPE) {
+ di1 = t1 - CLIPPED_ESCAPE;
+ } else {
+ di1 = t1 - c1 * cbrtf(c1) * IQ;
+ }
+ } else
+ di1 = t1 - vec[0] * IQ;
+
+ if (cond1) {
+ if (t2 >= CLIPPED_ESCAPE) {
+ di2 = t2 - CLIPPED_ESCAPE;
+ } else {
+ di2 = t2 - c2 * cbrtf(c2) * IQ;
+ }
+ } else
+ di2 = t2 - vec[1] * IQ;
+
+ if (cond2) {
+ if (t3 >= CLIPPED_ESCAPE) {
+ di3 = t3 - CLIPPED_ESCAPE;
+ } else {
+ di3 = t3 - c3 * cbrtf(c3) * IQ;
+ }
+ } else
+ di3 = t3 - vec2[0] * IQ;
+
+ if (cond3) {
+ if (t4 >= CLIPPED_ESCAPE) {
+ di4 = t4 - CLIPPED_ESCAPE;
+ } else {
+ di4 = t4 - c4 * cbrtf(c4) * IQ;
+ }
+ } else
+ di4 = t4 - vec2[1]*IQ;
+
+ cost += di1 * di1 + di2 * di2
+ + di3 * di3 + di4 * di4;
+ }
+
+ if (bits)
+ *bits = curbits;
+ return cost * lambda + curbits;
+}
+
+static float (*const get_band_cost_arr[])(struct AACEncContext *s,
+ PutBitContext *pb, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits) = {
+ get_band_cost_ZERO_mips,
+ get_band_cost_SQUAD_mips,
+ get_band_cost_SQUAD_mips,
+ get_band_cost_UQUAD_mips,
+ get_band_cost_UQUAD_mips,
+ get_band_cost_SPAIR_mips,
+ get_band_cost_SPAIR_mips,
+ get_band_cost_UPAIR7_mips,
+ get_band_cost_UPAIR7_mips,
+ get_band_cost_UPAIR12_mips,
+ get_band_cost_UPAIR12_mips,
+ get_band_cost_ESC_mips,
+};
+
+#define get_band_cost( \
+ s, pb, in, scaled, size, scale_idx, cb, \
+ lambda, uplim, bits) \
+ get_band_cost_arr[cb]( \
+ s, pb, in, scaled, size, scale_idx, cb, \
+ lambda, uplim, bits)
+
+static float quantize_band_cost(struct AACEncContext *s, const float *in,
+ const float *scaled, int size, int scale_idx,
+ int cb, const float lambda, const float uplim,
+ int *bits)
+{
+ return get_band_cost(s, NULL, in, scaled, size, scale_idx, cb, lambda, uplim, bits);
+}
+
+static void search_for_quantizers_twoloop_mips(AVCodecContext *avctx,
+ AACEncContext *s,
+ SingleChannelElement *sce,
+ const float lambda)
+{
+ int start = 0, i, w, w2, g;
+ int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels;
+ float dists[128] = { 0 }, uplims[128];
+ float maxvals[128];
+ int fflag, minscaler;
+ int its = 0;
+ int allz = 0;
+ float minthr = INFINITY;
+
+ destbits = FFMIN(destbits, 5800);
+ for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+ for (g = 0; g < sce->ics.num_swb; g++) {
+ int nz = 0;
+ float uplim = 0.0f;
+ for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
+ FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
+ uplim += band->threshold;
+ if (band->energy <= band->threshold || band->threshold == 0.0f) {
+ sce->zeroes[(w+w2)*16+g] = 1;
+ continue;
+ }
+ nz = 1;
+ }
+ uplims[w*16+g] = uplim *512;
+ sce->zeroes[w*16+g] = !nz;
+ if (nz)
+ minthr = FFMIN(minthr, uplim);
+ allz |= nz;
+ }
+ }
+ 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]) {
+ sce->sf_idx[w*16+g] = SCALE_ONE_POS;
+ continue;
+ }
+ sce->sf_idx[w*16+g] = SCALE_ONE_POS + FFMIN(log2f(uplims[w*16+g]/minthr)*4,59);
+ }
+ }
+
+ if (!allz)
+ return;
+ abs_pow34_v(s->scoefs, sce->coeffs, 1024);
+
+ for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+ start = w*128;
+ for (g = 0; g < sce->ics.num_swb; g++) {
+ const float *scaled = s->scoefs + start;
+ maxvals[w*16+g] = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], scaled);
+ start += sce->ics.swb_sizes[g];
+ }
+ }
+
+ do {
+ int tbits, qstep;
+ minscaler = sce->sf_idx[0];
+ qstep = its ? 1 : 32;
+ do {
+ int prev = -1;
+ tbits = 0;
+ fflag = 0;
+
+ if (qstep > 1) {
+ for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+ start = w*128;
+ for (g = 0; g < sce->ics.num_swb; g++) {
+ const float *coefs = sce->coeffs + start;
+ const float *scaled = s->scoefs + start;
+ int bits = 0;
+ int cb;
+
+ if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) {
+ start += sce->ics.swb_sizes[g];
+ continue;
+ }
+ minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]);
+ cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
+ for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
+ int b;
+ bits += quantize_band_cost_bits(s, coefs + w2*128,
+ scaled + w2*128,
+ sce->ics.swb_sizes[g],
+ sce->sf_idx[w*16+g],
+ cb,
+ 1.0f,
+ INFINITY,
+ &b);
+ }
+ if (prev != -1) {
+ bits += ff_aac_scalefactor_bits[sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO];
+ }
+ tbits += bits;
+ start += sce->ics.swb_sizes[g];
+ prev = sce->sf_idx[w*16+g];
+ }
+ }
+ }
+ else {
+ for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+ start = w*128;
+ for (g = 0; g < sce->ics.num_swb; g++) {
+ const float *coefs = sce->coeffs + start;
+ const float *scaled = s->scoefs + start;
+ int bits = 0;
+ int cb;
+ float dist = 0.0f;
+
+ if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) {
+ start += sce->ics.swb_sizes[g];
+ continue;
+ }
+ minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]);
+ cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
+ for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
+ int b;
+ dist += quantize_band_cost(s, coefs + w2*128,
+ scaled + w2*128,
+ sce->ics.swb_sizes[g],
+ sce->sf_idx[w*16+g],
+ cb,
+ 1.0f,
+ INFINITY,
+ &b);
+ bits += b;
+ }
+ dists[w*16+g] = dist - bits;
+ if (prev != -1) {
+ bits += ff_aac_scalefactor_bits[sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO];
+ }
+ tbits += bits;
+ start += sce->ics.swb_sizes[g];
+ prev = sce->sf_idx[w*16+g];
+ }
+ }
+ }
+ if (tbits > destbits) {
+ for (i = 0; i < 128; i++)
+ if (sce->sf_idx[i] < 218 - qstep)
+ sce->sf_idx[i] += qstep;
+ } else {
+ for (i = 0; i < 128; i++)
+ if (sce->sf_idx[i] > 60 - qstep)
+ sce->sf_idx[i] -= qstep;
+ }
+ qstep >>= 1;
+ if (!qstep && tbits > destbits*1.02 && sce->sf_idx[0] < 217)
+ qstep = 1;
+ } while (qstep);
+
+ fflag = 0;
+ minscaler = av_clip(minscaler, 60, 255 - SCALE_MAX_DIFF);
+ for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
+ for (g = 0; g < sce->ics.num_swb; g++) {
+ int prevsc = sce->sf_idx[w*16+g];
+ if (dists[w*16+g] > uplims[w*16+g] && sce->sf_idx[w*16+g] > 60) {
+ if (find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]-1))
+ sce->sf_idx[w*16+g]--;
+ else
+ sce->sf_idx[w*16+g]-=2;
+ }
+ sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], minscaler, minscaler + SCALE_MAX_DIFF);
+ sce->sf_idx[w*16+g] = FFMIN(sce->sf_idx[w*16+g], 219);
+ if (sce->sf_idx[w*16+g] != prevsc)
+ fflag = 1;
+ sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
+ }
+ }
+ its++;
+ } while (fflag && its < 10);
+}
+
+static void search_for_ms_mips(AACEncContext *s, ChannelElement *cpe,
+ const float lambda)
+{
+ int start = 0, i, w, w2, g;
+ float M[128], S[128];
+ float *L34 = s->scoefs, *R34 = s->scoefs + 128, *M34 = s->scoefs + 128*2, *S34 = s->scoefs + 128*3;
+ SingleChannelElement *sce0 = &cpe->ch[0];
+ SingleChannelElement *sce1 = &cpe->ch[1];
+ if (!cpe->common_window)
+ return;
+ for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) {
+ for (g = 0; g < sce0->ics.num_swb; g++) {
+ if (!cpe->ch[0].zeroes[w*16+g] && !cpe->ch[1].zeroes[w*16+g]) {
+ float dist1 = 0.0f, dist2 = 0.0f;
+ for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) {
+ FFPsyBand *band0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
+ FFPsyBand *band1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
+ float minthr = FFMIN(band0->threshold, band1->threshold);
+ float maxthr = FFMAX(band0->threshold, band1->threshold);
+ for (i = 0; i < sce0->ics.swb_sizes[g]; i+=4) {
+ M[i ] = (sce0->coeffs[start+w2*128+i ]
+ + sce1->coeffs[start+w2*128+i ]) * 0.5;
+ M[i+1] = (sce0->coeffs[start+w2*128+i+1]
+ + sce1->coeffs[start+w2*128+i+1]) * 0.5;
+ M[i+2] = (sce0->coeffs[start+w2*128+i+2]
+ + sce1->coeffs[start+w2*128+i+2]) * 0.5;
+ M[i+3] = (sce0->coeffs[start+w2*128+i+3]
+ + sce1->coeffs[start+w2*128+i+3]) * 0.5;
+
+ S[i ] = M[i ]
+ - sce1->coeffs[start+w2*128+i ];
+ S[i+1] = M[i+1]
+ - sce1->coeffs[start+w2*128+i+1];
+ S[i+2] = M[i+2]
+ - sce1->coeffs[start+w2*128+i+2];
+ S[i+3] = M[i+3]
+ - sce1->coeffs[start+w2*128+i+3];
+ }
+ abs_pow34_v(L34, sce0->coeffs+start+w2*128, sce0->ics.swb_sizes[g]);
+ abs_pow34_v(R34, sce1->coeffs+start+w2*128, sce0->ics.swb_sizes[g]);
+ abs_pow34_v(M34, M, sce0->ics.swb_sizes[g]);
+ abs_pow34_v(S34, S, sce0->ics.swb_sizes[g]);
+ dist1 += quantize_band_cost(s, sce0->coeffs + start + w2*128,
+ L34,
+ sce0->ics.swb_sizes[g],
+ sce0->sf_idx[(w+w2)*16+g],
+ sce0->band_type[(w+w2)*16+g],
+ lambda / band0->threshold, INFINITY, NULL);
+ dist1 += quantize_band_cost(s, sce1->coeffs + start + w2*128,
+ R34,
+ sce1->ics.swb_sizes[g],
+ sce1->sf_idx[(w+w2)*16+g],
+ sce1->band_type[(w+w2)*16+g],
+ lambda / band1->threshold, INFINITY, NULL);
+ dist2 += quantize_band_cost(s, M,
+ M34,
+ sce0->ics.swb_sizes[g],
+ sce0->sf_idx[(w+w2)*16+g],
+ sce0->band_type[(w+w2)*16+g],
+ lambda / maxthr, INFINITY, NULL);
+ dist2 += quantize_band_cost(s, S,
+ S34,
+ sce1->ics.swb_sizes[g],
+ sce1->sf_idx[(w+w2)*16+g],
+ sce1->band_type[(w+w2)*16+g],
+ lambda / minthr, INFINITY, NULL);
+ }
+ cpe->ms_mask[w*16+g] = dist2 < dist1;
+ }
+ start += sce0->ics.swb_sizes[g];
+ }
+ }
+}
+#endif /*HAVE_MIPSFPU */
+
+static void codebook_trellis_rate_mips(AACEncContext *s, SingleChannelElement *sce,
+ int win, int group_len, const float lambda)
+{
+ BandCodingPath path[120][12];
+ int w, swb, cb, start, size;
+ int i, j;
+ const int max_sfb = sce->ics.max_sfb;
+ const int run_bits = sce->ics.num_windows == 1 ? 5 : 3;
+ const int run_esc = (1 << run_bits) - 1;
+ int idx, ppos, count;
+ int stackrun[120], stackcb[120], stack_len;
+ float next_minbits = INFINITY;
+ int next_mincb = 0;
+
+ abs_pow34_v(s->scoefs, sce->coeffs, 1024);
+ start = win*128;
+ for (cb = 0; cb < 12; cb++) {
+ path[0][cb].cost = run_bits+4;
+ path[0][cb].prev_idx = -1;
+ path[0][cb].run = 0;
+ }
+ for (swb = 0; swb < max_sfb; swb++) {
+ size = sce->ics.swb_sizes[swb];
+ if (sce->zeroes[win*16 + swb]) {
+ float cost_stay_here = path[swb][0].cost;
+ float cost_get_here = next_minbits + run_bits + 4;
+ if ( run_value_bits[sce->ics.num_windows == 8][path[swb][0].run]
+ != run_value_bits[sce->ics.num_windows == 8][path[swb][0].run+1])
+ cost_stay_here += run_bits;
+ if (cost_get_here < cost_stay_here) {
+ path[swb+1][0].prev_idx = next_mincb;
+ path[swb+1][0].cost = cost_get_here;
+ path[swb+1][0].run = 1;
+ } else {
+ path[swb+1][0].prev_idx = 0;
+ path[swb+1][0].cost = cost_stay_here;
+ path[swb+1][0].run = path[swb][0].run + 1;
+ }
+ next_minbits = path[swb+1][0].cost;
+ next_mincb = 0;
+ for (cb = 1; cb < 12; cb++) {
+ path[swb+1][cb].cost = 61450;
+ path[swb+1][cb].prev_idx = -1;
+ path[swb+1][cb].run = 0;
+ }
+ } else {
+ float minbits = next_minbits;
+ int mincb = next_mincb;
+ int startcb = sce->band_type[win*16+swb];
+ next_minbits = INFINITY;
+ next_mincb = 0;
+ for (cb = 0; cb < startcb; cb++) {
+ path[swb+1][cb].cost = 61450;
+ path[swb+1][cb].prev_idx = -1;
+ path[swb+1][cb].run = 0;
+ }
+ for (cb = startcb; cb < 12; cb++) {
+ float cost_stay_here, cost_get_here;
+ float bits = 0.0f;
+ for (w = 0; w < group_len; w++) {
+ bits += quantize_band_cost_bits(s, sce->coeffs + start + w*128,
+ s->scoefs + start + w*128, size,
+ sce->sf_idx[(win+w)*16+swb], cb,
+ 0, INFINITY, NULL);
+ }
+ cost_stay_here = path[swb][cb].cost + bits;
+ cost_get_here = minbits + bits + run_bits + 4;
+ if ( run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run]
+ != run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run+1])
+ cost_stay_here += run_bits;
+ if (cost_get_here < cost_stay_here) {
+ path[swb+1][cb].prev_idx = mincb;
+ path[swb+1][cb].cost = cost_get_here;
+ path[swb+1][cb].run = 1;
+ } else {
+ path[swb+1][cb].prev_idx = cb;
+ path[swb+1][cb].cost = cost_stay_here;
+ path[swb+1][cb].run = path[swb][cb].run + 1;
+ }
+ if (path[swb+1][cb].cost < next_minbits) {
+ next_minbits = path[swb+1][cb].cost;
+ next_mincb = cb;
+ }
+ }
+ }
+ start += sce->ics.swb_sizes[swb];
+ }
+
+ stack_len = 0;
+ idx = 0;
+ for (cb = 1; cb < 12; cb++)
+ if (path[max_sfb][cb].cost < path[max_sfb][idx].cost)
+ idx = cb;
+ ppos = max_sfb;
+ while (ppos > 0) {
+ av_assert1(idx >= 0);
+ cb = idx;
+ stackrun[stack_len] = path[ppos][cb].run;
+ stackcb [stack_len] = cb;
+ idx = path[ppos-path[ppos][cb].run+1][cb].prev_idx;
+ ppos -= path[ppos][cb].run;
+ stack_len++;
+ }
+
+ start = 0;
+ for (i = stack_len - 1; i >= 0; i--) {
+ put_bits(&s->pb, 4, stackcb[i]);
+ count = stackrun[i];
+ memset(sce->zeroes + win*16 + start, !stackcb[i], count);
+ for (j = 0; j < count; j++) {
+ sce->band_type[win*16 + start] = stackcb[i];
+ start++;
+ }
+ while (count >= run_esc) {
+ put_bits(&s->pb, run_bits, run_esc);
+ count -= run_esc;
+ }
+ put_bits(&s->pb, run_bits, count);
+ }
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_aac_coder_init_mips(AACEncContext *c) {
+#if HAVE_INLINE_ASM
+ AACCoefficientsEncoder *e = c->coder;
+ int option = c->options.aac_coder;
+
+ if (option == 2) {
+ e->quantize_and_encode_band = quantize_and_encode_band_mips;
+ e->encode_window_bands_info = codebook_trellis_rate_mips;
+#if HAVE_MIPSFPU
+ e->search_for_quantizers = search_for_quantizers_twoloop_mips;
+ e->search_for_ms = search_for_ms_mips;
+#endif /* HAVE_MIPSFPU */
+ }
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/aacdec_mips.c b/libavcodec/mips/aacdec_mips.c
new file mode 100644
index 0000000000..253cdeb80b
--- /dev/null
+++ b/libavcodec/mips/aacdec_mips.c
@@ -0,0 +1,442 @@
+/*
+ * 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 "libavcodec/aac.h"
+#include "aacdec_mips.h"
+#include "libavcodec/aactab.h"
+#include "libavcodec/sinewin.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+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(AACContext *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->mdct_small.imdct_half(&ac->mdct_small, buf + i, in + i);
+ } else
+ ac->mdct.imdct_half(&ac->mdct, buf, in);
+
+ /* 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(AACContext *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];
+ }
+}
+
+#if HAVE_MIPSFPU
+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(AACContext *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;
+ float 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(AACContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->imdct_and_windowing = imdct_and_windowing_mips;
+ c->apply_ltp = apply_ltp_mips;
+#if HAVE_MIPSFPU
+ 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
new file mode 100644
index 0000000000..054a9fba62
--- /dev/null
+++ b/libavcodec/mips/aacdec_mips.h
@@ -0,0 +1,251 @@
+/*
+ * 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_FLOAT_H
+#define AVCODEC_MIPS_AACDEC_FLOAT_H
+
+#include "libavcodec/aac.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+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_INLINE_ASM && HAVE_MIPSFPU */
+
+#endif /* AVCODEC_MIPS_AACDEC_FLOAT_H */
diff --git a/libavcodec/mips/aacpsdsp_mips.c b/libavcodec/mips/aacpsdsp_mips.c
new file mode 100644
index 0000000000..695f9ef3c6
--- /dev/null
+++ b/libavcodec/mips/aacpsdsp_mips.c
@@ -0,0 +1,460 @@
+/*
+ * 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
+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_MIPSFPU
+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 *p_delay_end = (p_delay + (len << 1));
+
+ /* merged 2 loops */
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "li.s %[ag0], 0.65143905753106 \n\t"
+ "li.s %[ag1], 0.56471812200776 \n\t"
+ "li.s %[ag2], 0.48954165955695 \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),
+ [ag0]"=&f"(ag0), [ag1]"=&f"(ag1), [ag2]"=&f"(ag2)
+ : [phi_fract0]"f"(phi_fract0), [phi_fract1]"f"(phi_fract1),
+ [p_delay_end]"r"(p_delay_end), [g_decay_slope]"f"(g_decay_slope)
+ : "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_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_psdsp_init_mips(PSDSPContext *s)
+{
+#if HAVE_INLINE_ASM
+ s->hybrid_analysis_ileave = ps_hybrid_analysis_ileave_mips;
+ s->hybrid_synthesis_deint = ps_hybrid_synthesis_deint_mips;
+#if HAVE_MIPSFPU
+ 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_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/aacpsy_mips.h b/libavcodec/mips/aacpsy_mips.h
new file mode 100644
index 0000000000..596dcaddd0
--- /dev/null
+++ b/libavcodec/mips/aacpsy_mips.h
@@ -0,0 +1,232 @@
+/*
+ * 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 )
+static void calc_thr_3gpp_mips(const FFPsyWindowInfo *wi, const int num_bands,
+ AacPsyChannel *pch, const uint8_t *band_sizes,
+ const float *coefs)
+{
+ int i, w, g;
+ int start = 0;
+ for (w = 0; w < wi->num_windows*16; w += 16) {
+ for (g = 0; g < num_bands; g++) {
+ AacPsyBand *band = &pch->band[w+g];
+
+ float form_factor = 0.0f;
+ float Temp;
+ band->energy = 0.0f;
+ 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];
+ }
+ }
+}
+
+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];
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "li.s $f12, 32768 \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], $f12 \n\t"
+ "mul.s %[sum2], %[sum2], $f12 \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], $f12 \n\t"
+ "mul.s %[sum3], %[sum3], $f12 \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)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6",
+ "$f7", "$f8", "$f9", "$f10", "$f11", "$f12",
+ "memory"
+ );
+}
+
+#define calc_thr_3gpp calc_thr_3gpp_mips
+#define psy_hp_filter psy_hp_filter_mips
+
+#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
new file mode 100644
index 0000000000..e478290e47
--- /dev/null
+++ b/libavcodec/mips/aacsbr_mips.c
@@ -0,0 +1,619 @@
+/*
+ * 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/aac.h"
+#include "libavcodec/aacsbr.h"
+#include "libavutil/mips/asmdefs.h"
+
+#define ENVELOPE_ADJUSTMENT_OFFSET 2
+
+#if HAVE_INLINE_ASM
+static int sbr_lf_gen_mips(AACContext *ac, 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_MIPSFPU
+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;
+ float 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_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_aacsbr_func_ptr_init_mips(AACSBRContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->sbr_lf_gen = sbr_lf_gen_mips;
+ c->sbr_x_gen = sbr_x_gen_mips;
+#if HAVE_MIPSFPU
+ c->sbr_hf_inverse_filter = sbr_hf_inverse_filter_mips;
+ c->sbr_hf_assemble = sbr_hf_assemble_mips;
+#endif /* HAVE_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/aacsbr_mips.h b/libavcodec/mips/aacsbr_mips.h
new file mode 100644
index 0000000000..e525197a40
--- /dev/null
+++ b/libavcodec/mips/aacsbr_mips.h
@@ -0,0 +1,494 @@
+/*
+ * 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_FLOAT_H
+#define AVCODEC_MIPS_AACSBR_FLOAT_H
+
+#include "libavcodec/aac.h"
+#include "libavcodec/sbr.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static void sbr_qmf_analysis_mips(AVFloatDSPContext *fdsp, FFTContext *mdct,
+ 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->imdct_half(mdct, z, z+64);
+ sbrdsp->qmf_post_shuffle(W[buf_idx][i], z);
+ x += 32;
+ }
+}
+
+#if (HAVE_MIPSFPU && !HAVE_LOONGSON3)
+static void sbr_qmf_synthesis_mips(FFTContext *mdct,
+ 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->imdct_half(mdct, mdct_buf[0], X[0][i]);
+ sbrdsp->qmf_deint_neg(v, mdct_buf[0]);
+ } else {
+ sbrdsp->neg_odd_64(X[1][i]);
+ mdct->imdct_half(mdct, mdct_buf[0], X[0][i]);
+ mdct->imdct_half(mdct, mdct_buf[1], X[1][i]);
+ 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_MIPSFPU && !HAVE_LOONGSON3) */
+#endif /* HAVE_INLINE_ASM */
+
+#endif /* AVCODEC_MIPS_AACSBR_FLOAT_H */
diff --git a/libavcodec/mips/ac3dsp_mips.c b/libavcodec/mips/ac3dsp_mips.c
new file mode 100644
index 0000000000..01c7de57a0
--- /dev/null
+++ b/libavcodec/mips/ac3dsp_mips.c
@@ -0,0 +1,413 @@
+/*
+ * 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: Branimir Vasic (bvasic@mips.com)
+ * Nedeljko Babic (nbabic@mips.com)
+ *
+ * Various AC-3 DSP Utils 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/ac3dsp.c
+ */
+
+#include "config.h"
+#include "libavcodec/ac3dsp.h"
+#include "libavcodec/ac3.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+static void ac3_bit_alloc_calc_bap_mips(int16_t *mask, int16_t *psd,
+ int start, int end,
+ int snr_offset, int floor,
+ const uint8_t *bap_tab, uint8_t *bap)
+{
+ int band, band_end, cond;
+ int m, address1, address2;
+ int16_t *psd1, *psd_end;
+ uint8_t *bap1;
+
+ if (snr_offset == -960) {
+ memset(bap, 0, AC3_MAX_COEFS);
+ return;
+ }
+
+ psd1 = &psd[start];
+ bap1 = &bap[start];
+ band = ff_ac3_bin_to_band_tab[start];
+
+ do {
+ m = (FFMAX(mask[band] - snr_offset - floor, 0) & 0x1FE0) + floor;
+ band_end = ff_ac3_band_start_tab[++band];
+ band_end = FFMIN(band_end, end);
+ psd_end = psd + band_end - 1;
+
+ __asm__ volatile (
+ "slt %[cond], %[psd1], %[psd_end] \n\t"
+ "beqz %[cond], 1f \n\t"
+ "2: \n\t"
+ "lh %[address1], 0(%[psd1]) \n\t"
+ "lh %[address2], 2(%[psd1]) \n\t"
+ PTR_ADDIU " %[psd1], %[psd1], 4 \n\t"
+ "subu %[address1], %[address1], %[m] \n\t"
+ "sra %[address1], %[address1], 5 \n\t"
+ "addiu %[address1], %[address1], -32 \n\t"
+ "shll_s.w %[address1], %[address1], 26 \n\t"
+ "subu %[address2], %[address2], %[m] \n\t"
+ "sra %[address2], %[address2], 5 \n\t"
+ "sra %[address1], %[address1], 26 \n\t"
+ "addiu %[address1], %[address1], 32 \n\t"
+ "lbux %[address1], %[address1](%[bap_tab]) \n\t"
+ "addiu %[address2], %[address2], -32 \n\t"
+ "shll_s.w %[address2], %[address2], 26 \n\t"
+ "sb %[address1], 0(%[bap1]) \n\t"
+ "slt %[cond], %[psd1], %[psd_end] \n\t"
+ "sra %[address2], %[address2], 26 \n\t"
+ "addiu %[address2], %[address2], 32 \n\t"
+ "lbux %[address2], %[address2](%[bap_tab]) \n\t"
+ "sb %[address2], 1(%[bap1]) \n\t"
+ PTR_ADDIU " %[bap1], %[bap1], 2 \n\t"
+ "bnez %[cond], 2b \n\t"
+ PTR_ADDIU " %[psd_end], %[psd_end], 2 \n\t"
+ "slt %[cond], %[psd1], %[psd_end] \n\t"
+ "beqz %[cond], 3f \n\t"
+ "1: \n\t"
+ "lh %[address1], 0(%[psd1]) \n\t"
+ PTR_ADDIU " %[psd1], %[psd1], 2 \n\t"
+ "subu %[address1], %[address1], %[m] \n\t"
+ "sra %[address1], %[address1], 5 \n\t"
+ "addiu %[address1], %[address1], -32 \n\t"
+ "shll_s.w %[address1], %[address1], 26 \n\t"
+ "sra %[address1], %[address1], 26 \n\t"
+ "addiu %[address1], %[address1], 32 \n\t"
+ "lbux %[address1], %[address1](%[bap_tab]) \n\t"
+ "sb %[address1], 0(%[bap1]) \n\t"
+ PTR_ADDIU " %[bap1], %[bap1], 1 \n\t"
+ "3: \n\t"
+
+ : [address1]"=&r"(address1), [address2]"=&r"(address2),
+ [cond]"=&r"(cond), [bap1]"+r"(bap1),
+ [psd1]"+r"(psd1), [psd_end]"+r"(psd_end)
+ : [m]"r"(m), [bap_tab]"r"(bap_tab)
+ : "memory"
+ );
+ } while (end > band_end);
+}
+
+static void ac3_update_bap_counts_mips(uint16_t mant_cnt[16], uint8_t *bap,
+ int len)
+{
+ void *temp0, *temp2, *temp4, *temp5, *temp6, *temp7;
+ int temp1, temp3;
+
+ __asm__ volatile (
+ "andi %[temp3], %[len], 3 \n\t"
+ PTR_ADDU "%[temp2], %[bap], %[len] \n\t"
+ PTR_ADDU "%[temp4], %[bap], %[temp3] \n\t"
+ "beq %[temp2], %[temp4], 4f \n\t"
+ "1: \n\t"
+ "lbu %[temp0], -1(%[temp2]) \n\t"
+ "lbu %[temp5], -2(%[temp2]) \n\t"
+ "lbu %[temp6], -3(%[temp2]) \n\t"
+ "sll %[temp0], %[temp0], 1 \n\t"
+ PTR_ADDU "%[temp0], %[mant_cnt], %[temp0] \n\t"
+ "sll %[temp5], %[temp5], 1 \n\t"
+ PTR_ADDU "%[temp5], %[mant_cnt], %[temp5] \n\t"
+ "lhu %[temp1], 0(%[temp0]) \n\t"
+ "sll %[temp6], %[temp6], 1 \n\t"
+ PTR_ADDU "%[temp6], %[mant_cnt], %[temp6] \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp0]) \n\t"
+ "lhu %[temp1], 0(%[temp5]) \n\t"
+ "lbu %[temp7], -4(%[temp2]) \n\t"
+ PTR_ADDIU "%[temp2],%[temp2], -4 \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp5]) \n\t"
+ "lhu %[temp1], 0(%[temp6]) \n\t"
+ "sll %[temp7], %[temp7], 1 \n\t"
+ PTR_ADDU "%[temp7], %[mant_cnt], %[temp7] \n\t"
+ "addiu %[temp1], %[temp1],1 \n\t"
+ "sh %[temp1], 0(%[temp6]) \n\t"
+ "lhu %[temp1], 0(%[temp7]) \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp7]) \n\t"
+ "bne %[temp2], %[temp4], 1b \n\t"
+ "4: \n\t"
+ "beqz %[temp3], 2f \n\t"
+ "3: \n\t"
+ "addiu %[temp3], %[temp3], -1 \n\t"
+ "lbu %[temp0], -1(%[temp2]) \n\t"
+ PTR_ADDIU "%[temp2],%[temp2], -1 \n\t"
+ "sll %[temp0], %[temp0], 1 \n\t"
+ PTR_ADDU "%[temp0], %[mant_cnt], %[temp0] \n\t"
+ "lhu %[temp1], 0(%[temp0]) \n\t"
+ "addiu %[temp1], %[temp1], 1 \n\t"
+ "sh %[temp1], 0(%[temp0]) \n\t"
+ "bgtz %[temp3], 3b \n\t"
+ "2: \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)
+ : [len] "r" (len), [bap] "r" (bap),
+ [mant_cnt] "r" (mant_cnt)
+ : "memory"
+ );
+}
+#endif
+
+#if HAVE_MIPSFPU
+static void float_to_fixed24_mips(int32_t *dst, const float *src, unsigned int len)
+{
+ const float scale = 1 << 24;
+ float src0, src1, src2, src3, src4, src5, src6, src7;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ do {
+ __asm__ volatile (
+ "lwc1 %[src0], 0(%[src]) \n\t"
+ "lwc1 %[src1], 4(%[src]) \n\t"
+ "lwc1 %[src2], 8(%[src]) \n\t"
+ "lwc1 %[src3], 12(%[src]) \n\t"
+ "lwc1 %[src4], 16(%[src]) \n\t"
+ "lwc1 %[src5], 20(%[src]) \n\t"
+ "lwc1 %[src6], 24(%[src]) \n\t"
+ "lwc1 %[src7], 28(%[src]) \n\t"
+ "mul.s %[src0], %[src0], %[scale] \n\t"
+ "mul.s %[src1], %[src1], %[scale] \n\t"
+ "mul.s %[src2], %[src2], %[scale] \n\t"
+ "mul.s %[src3], %[src3], %[scale] \n\t"
+ "mul.s %[src4], %[src4], %[scale] \n\t"
+ "mul.s %[src5], %[src5], %[scale] \n\t"
+ "mul.s %[src6], %[src6], %[scale] \n\t"
+ "mul.s %[src7], %[src7], %[scale] \n\t"
+ "cvt.w.s %[src0], %[src0] \n\t"
+ "cvt.w.s %[src1], %[src1] \n\t"
+ "cvt.w.s %[src2], %[src2] \n\t"
+ "cvt.w.s %[src3], %[src3] \n\t"
+ "cvt.w.s %[src4], %[src4] \n\t"
+ "cvt.w.s %[src5], %[src5] \n\t"
+ "cvt.w.s %[src6], %[src6] \n\t"
+ "cvt.w.s %[src7], %[src7] \n\t"
+ "mfc1 %[temp0], %[src0] \n\t"
+ "mfc1 %[temp1], %[src1] \n\t"
+ "mfc1 %[temp2], %[src2] \n\t"
+ "mfc1 %[temp3], %[src3] \n\t"
+ "mfc1 %[temp4], %[src4] \n\t"
+ "mfc1 %[temp5], %[src5] \n\t"
+ "mfc1 %[temp6], %[src6] \n\t"
+ "mfc1 %[temp7], %[src7] \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"
+
+ : [dst] "+r" (dst), [src] "+r" (src),
+ [src0] "=&f" (src0), [src1] "=&f" (src1),
+ [src2] "=&f" (src2), [src3] "=&f" (src3),
+ [src4] "=&f" (src4), [src5] "=&f" (src5),
+ [src6] "=&f" (src6), [src7] "=&f" (src7),
+ [temp0] "=r" (temp0), [temp1] "=r" (temp1),
+ [temp2] "=r" (temp2), [temp3] "=r" (temp3),
+ [temp4] "=r" (temp4), [temp5] "=r" (temp5),
+ [temp6] "=r" (temp6), [temp7] "=r" (temp7)
+ : [scale] "f" (scale)
+ : "memory"
+ );
+ src = src + 8;
+ dst = dst + 8;
+ len -= 8;
+ } while (len > 0);
+}
+
+static void ac3_downmix_mips(float **samples, float (*matrix)[2],
+ int out_ch, int in_ch, int len)
+{
+ int i, j, i1, i2, i3;
+ float v0, v1, v2, v3;
+ float v4, v5, v6, v7;
+ float samples0, samples1, samples2, samples3, matrix_j, matrix_j2;
+ float *samples_p, *samples_sw, *matrix_p, **samples_x, **samples_end;
+
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "li %[i1], 2 \n\t"
+ "sll %[len], 2 \n\t"
+ "move %[i], $zero \n\t"
+ "sll %[j], %[in_ch], " PTRLOG " \n\t"
+
+ "bne %[out_ch], %[i1], 3f \n\t" // if (out_ch == 2)
+ " li %[i2], 1 \n\t"
+
+ "2: \n\t" // start of the for loop (for (i = 0; i < len; i+=4))
+ "move %[matrix_p], %[matrix] \n\t"
+ "move %[samples_x], %[samples] \n\t"
+ "mtc1 $zero, %[v0] \n\t"
+ "mtc1 $zero, %[v1] \n\t"
+ "mtc1 $zero, %[v2] \n\t"
+ "mtc1 $zero, %[v3] \n\t"
+ "mtc1 $zero, %[v4] \n\t"
+ "mtc1 $zero, %[v5] \n\t"
+ "mtc1 $zero, %[v6] \n\t"
+ "mtc1 $zero, %[v7] \n\t"
+ "addiu %[i1], %[i], 4 \n\t"
+ "addiu %[i2], %[i], 8 \n\t"
+ PTR_L " %[samples_p], 0(%[samples_x]) \n\t"
+ "addiu %[i3], %[i], 12 \n\t"
+ PTR_ADDU "%[samples_end],%[samples_x], %[j] \n\t"
+ "move %[samples_sw], %[samples_p] \n\t"
+
+ "1: \n\t" // start of the inner for loop (for (j = 0; j < in_ch; j++))
+ "lwc1 %[matrix_j], 0(%[matrix_p]) \n\t"
+ "lwc1 %[matrix_j2], 4(%[matrix_p]) \n\t"
+ "lwxc1 %[samples0], %[i](%[samples_p]) \n\t"
+ "lwxc1 %[samples1], %[i1](%[samples_p]) \n\t"
+ "lwxc1 %[samples2], %[i2](%[samples_p]) \n\t"
+ "lwxc1 %[samples3], %[i3](%[samples_p]) \n\t"
+ PTR_ADDIU "%[matrix_p], 8 \n\t"
+ PTR_ADDIU "%[samples_x]," PTRSIZE " \n\t"
+ "madd.s %[v0], %[v0], %[samples0], %[matrix_j] \n\t"
+ "madd.s %[v1], %[v1], %[samples1], %[matrix_j] \n\t"
+ "madd.s %[v2], %[v2], %[samples2], %[matrix_j] \n\t"
+ "madd.s %[v3], %[v3], %[samples3], %[matrix_j] \n\t"
+ "madd.s %[v4], %[v4], %[samples0], %[matrix_j2]\n\t"
+ "madd.s %[v5], %[v5], %[samples1], %[matrix_j2]\n\t"
+ "madd.s %[v6], %[v6], %[samples2], %[matrix_j2]\n\t"
+ "madd.s %[v7], %[v7], %[samples3], %[matrix_j2]\n\t"
+ "bne %[samples_x], %[samples_end], 1b \n\t"
+ PTR_L " %[samples_p], 0(%[samples_x]) \n\t"
+
+ PTR_L " %[samples_p], " PTRSIZE "(%[samples]) \n\t"
+ "swxc1 %[v0], %[i](%[samples_sw]) \n\t"
+ "swxc1 %[v1], %[i1](%[samples_sw]) \n\t"
+ "swxc1 %[v2], %[i2](%[samples_sw]) \n\t"
+ "swxc1 %[v3], %[i3](%[samples_sw]) \n\t"
+ "swxc1 %[v4], %[i](%[samples_p]) \n\t"
+ "addiu %[i], 16 \n\t"
+ "swxc1 %[v5], %[i1](%[samples_p]) \n\t"
+ "swxc1 %[v6], %[i2](%[samples_p]) \n\t"
+ "bne %[i], %[len], 2b \n\t"
+ " swxc1 %[v7], %[i3](%[samples_p]) \n\t"
+
+ "3: \n\t"
+ "bne %[out_ch], %[i2], 6f \n\t" // if (out_ch == 1)
+ " nop \n\t"
+
+ "5: \n\t" // start of the outer for loop (for (i = 0; i < len; i+=4))
+ "move %[matrix_p], %[matrix] \n\t"
+ "move %[samples_x], %[samples] \n\t"
+ "mtc1 $zero, %[v0] \n\t"
+ "mtc1 $zero, %[v1] \n\t"
+ "mtc1 $zero, %[v2] \n\t"
+ "mtc1 $zero, %[v3] \n\t"
+ "addiu %[i1], %[i], 4 \n\t"
+ "addiu %[i2], %[i], 8 \n\t"
+ PTR_L " %[samples_p], 0(%[samples_x]) \n\t"
+ "addiu %[i3], %[i], 12 \n\t"
+ PTR_ADDU "%[samples_end],%[samples_x], %[j] \n\t"
+ "move %[samples_sw], %[samples_p] \n\t"
+
+ "4: \n\t" // start of the inner for loop (for (j = 0; j < in_ch; j++))
+ "lwc1 %[matrix_j], 0(%[matrix_p]) \n\t"
+ "lwxc1 %[samples0], %[i](%[samples_p]) \n\t"
+ "lwxc1 %[samples1], %[i1](%[samples_p]) \n\t"
+ "lwxc1 %[samples2], %[i2](%[samples_p]) \n\t"
+ "lwxc1 %[samples3], %[i3](%[samples_p]) \n\t"
+ PTR_ADDIU "%[matrix_p], 8 \n\t"
+ PTR_ADDIU "%[samples_x]," PTRSIZE " \n\t"
+ "madd.s %[v0], %[v0], %[samples0], %[matrix_j] \n\t"
+ "madd.s %[v1], %[v1], %[samples1], %[matrix_j] \n\t"
+ "madd.s %[v2], %[v2], %[samples2], %[matrix_j] \n\t"
+ "madd.s %[v3], %[v3], %[samples3], %[matrix_j] \n\t"
+ "bne %[samples_x], %[samples_end], 4b \n\t"
+ PTR_L " %[samples_p], 0(%[samples_x]) \n\t"
+
+ "swxc1 %[v0], %[i](%[samples_sw]) \n\t"
+ "addiu %[i], 16 \n\t"
+ "swxc1 %[v1], %[i1](%[samples_sw]) \n\t"
+ "swxc1 %[v2], %[i2](%[samples_sw]) \n\t"
+ "bne %[i], %[len], 5b \n\t"
+ " swxc1 %[v3], %[i3](%[samples_sw]) \n\t"
+ "6: \n\t"
+
+ ".set pop"
+ :[samples_p]"=&r"(samples_p), [matrix_j]"=&f"(matrix_j), [matrix_j2]"=&f"(matrix_j2),
+ [samples0]"=&f"(samples0), [samples1]"=&f"(samples1),
+ [samples2]"=&f"(samples2), [samples3]"=&f"(samples3),
+ [v0]"=&f"(v0), [v1]"=&f"(v1), [v2]"=&f"(v2), [v3]"=&f"(v3),
+ [v4]"=&f"(v4), [v5]"=&f"(v5), [v6]"=&f"(v6), [v7]"=&f"(v7),
+ [samples_x]"=&r"(samples_x), [matrix_p]"=&r"(matrix_p),
+ [samples_end]"=&r"(samples_end), [samples_sw]"=&r"(samples_sw),
+ [i1]"=&r"(i1), [i2]"=&r"(i2), [i3]"=&r"(i3), [i]"=&r"(i),
+ [j]"=&r"(j), [len]"+r"(len)
+ :[samples]"r"(samples), [matrix]"r"(matrix),
+ [in_ch]"r"(in_ch), [out_ch]"r"(out_ch)
+ :"memory"
+ );
+}
+#endif
+#endif /* HAVE_INLINE_ASM */
+
+void ff_ac3dsp_init_mips(AC3DSPContext *c, int bit_exact) {
+#if HAVE_INLINE_ASM
+#if HAVE_MIPSDSPR1
+ c->bit_alloc_calc_bap = ac3_bit_alloc_calc_bap_mips;
+ c->update_bap_counts = ac3_update_bap_counts_mips;
+#endif
+#if HAVE_MIPSFPU
+ c->float_to_fixed24 = float_to_fixed24_mips;
+ c->downmix = ac3_downmix_mips;
+#endif
+#endif
+
+}
diff --git a/libavcodec/mips/acelp_filters_mips.c b/libavcodec/mips/acelp_filters_mips.c
new file mode 100644
index 0000000000..ba789abe3f
--- /dev/null
+++ b/libavcodec/mips/acelp_filters_mips.c
@@ -0,0 +1,217 @@
+ /*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * various filters for ACELP-based codecs 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/acelp_filters.c
+ */
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavcodec/acelp_filters.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static void ff_acelp_interpolatef_mips(float *out, const float *in,
+ const float *filter_coeffs, int precision,
+ int frac_pos, int filter_length, int length)
+{
+ int n, i;
+ int prec = precision * 4;
+ int fc_offset = precision - frac_pos;
+ float in_val_p, in_val_m, fc_val_p, fc_val_m;
+
+ for (n = 0; n < length; n++) {
+ /**
+ * four pointers are defined in order to minimize number of
+ * computations done in inner loop
+ */
+ const float *p_in_p = &in[n];
+ const float *p_in_m = &in[n-1];
+ const float *p_filter_coeffs_p = &filter_coeffs[frac_pos];
+ const float *p_filter_coeffs_m = filter_coeffs + fc_offset;
+ float v = 0;
+
+ for (i = 0; i < filter_length;i++) {
+ __asm__ volatile (
+ "lwc1 %[in_val_p], 0(%[p_in_p]) \n\t"
+ "lwc1 %[fc_val_p], 0(%[p_filter_coeffs_p]) \n\t"
+ "lwc1 %[in_val_m], 0(%[p_in_m]) \n\t"
+ "lwc1 %[fc_val_m], 0(%[p_filter_coeffs_m]) \n\t"
+ PTR_ADDIU "%[p_in_p], %[p_in_p], 4 \n\t"
+ "madd.s %[v],%[v], %[in_val_p],%[fc_val_p] \n\t"
+ PTR_ADDIU "%[p_in_m], %[p_in_m], -4 \n\t"
+ PTR_ADDU "%[p_filter_coeffs_p],%[p_filter_coeffs_p], %[prec] \n\t"
+ PTR_ADDU "%[p_filter_coeffs_m],%[p_filter_coeffs_m], %[prec] \n\t"
+ "madd.s %[v],%[v],%[in_val_m], %[fc_val_m] \n\t"
+
+ : [v] "+&f" (v),[p_in_p] "+r" (p_in_p), [p_in_m] "+r" (p_in_m),
+ [p_filter_coeffs_p] "+r" (p_filter_coeffs_p),
+ [in_val_p] "=&f" (in_val_p), [in_val_m] "=&f" (in_val_m),
+ [fc_val_p] "=&f" (fc_val_p), [fc_val_m] "=&f" (fc_val_m),
+ [p_filter_coeffs_m] "+r" (p_filter_coeffs_m)
+ : [prec] "r" (prec)
+ : "memory"
+ );
+ }
+ out[n] = v;
+ }
+}
+
+static void ff_acelp_apply_order_2_transfer_function_mips(float *out, const float *in,
+ const float zero_coeffs[2],
+ const float pole_coeffs[2],
+ float gain, float mem[2], int n)
+{
+ /**
+ * loop is unrolled eight times
+ */
+
+ __asm__ volatile (
+ "lwc1 $f0, 0(%[mem]) \n\t"
+ "blez %[n], ff_acelp_apply_order_2_transfer_function_end%= \n\t"
+ "lwc1 $f1, 4(%[mem]) \n\t"
+ "lwc1 $f2, 0(%[pole_coeffs]) \n\t"
+ "lwc1 $f3, 4(%[pole_coeffs]) \n\t"
+ "lwc1 $f4, 0(%[zero_coeffs]) \n\t"
+ "lwc1 $f5, 4(%[zero_coeffs]) \n\t"
+
+ "ff_acelp_apply_order_2_transfer_function_madd%=: \n\t"
+
+ "lwc1 $f6, 0(%[in]) \n\t"
+ "mul.s $f9, $f3, $f1 \n\t"
+ "mul.s $f7, $f2, $f0 \n\t"
+ "msub.s $f7, $f7, %[gain], $f6 \n\t"
+ "sub.s $f7, $f7, $f9 \n\t"
+ "madd.s $f8, $f7, $f4, $f0 \n\t"
+ "madd.s $f8, $f8, $f5, $f1 \n\t"
+ "lwc1 $f11, 4(%[in]) \n\t"
+ "mul.s $f12, $f3, $f0 \n\t"
+ "mul.s $f13, $f2, $f7 \n\t"
+ "msub.s $f13, $f13, %[gain], $f11 \n\t"
+ "sub.s $f13, $f13, $f12 \n\t"
+ "madd.s $f14, $f13, $f4, $f7 \n\t"
+ "madd.s $f14, $f14, $f5, $f0 \n\t"
+ "swc1 $f8, 0(%[out]) \n\t"
+ "lwc1 $f6, 8(%[in]) \n\t"
+ "mul.s $f9, $f3, $f7 \n\t"
+ "mul.s $f15, $f2, $f13 \n\t"
+ "msub.s $f15, $f15, %[gain], $f6 \n\t"
+ "sub.s $f15, $f15, $f9 \n\t"
+ "madd.s $f8, $f15, $f4, $f13 \n\t"
+ "madd.s $f8, $f8, $f5, $f7 \n\t"
+ "swc1 $f14, 4(%[out]) \n\t"
+ "lwc1 $f11, 12(%[in]) \n\t"
+ "mul.s $f12, $f3, $f13 \n\t"
+ "mul.s $f16, $f2, $f15 \n\t"
+ "msub.s $f16, $f16, %[gain], $f11 \n\t"
+ "sub.s $f16, $f16, $f12 \n\t"
+ "madd.s $f14, $f16, $f4, $f15 \n\t"
+ "madd.s $f14, $f14, $f5, $f13 \n\t"
+ "swc1 $f8, 8(%[out]) \n\t"
+ "lwc1 $f6, 16(%[in]) \n\t"
+ "mul.s $f9, $f3, $f15 \n\t"
+ "mul.s $f7, $f2, $f16 \n\t"
+ "msub.s $f7, $f7, %[gain], $f6 \n\t"
+ "sub.s $f7, $f7, $f9 \n\t"
+ "madd.s $f8, $f7, $f4, $f16 \n\t"
+ "madd.s $f8, $f8, $f5, $f15 \n\t"
+ "swc1 $f14, 12(%[out]) \n\t"
+ "lwc1 $f11, 20(%[in]) \n\t"
+ "mul.s $f12, $f3, $f16 \n\t"
+ "mul.s $f13, $f2, $f7 \n\t"
+ "msub.s $f13, $f13, %[gain], $f11 \n\t"
+ "sub.s $f13, $f13, $f12 \n\t"
+ "madd.s $f14, $f13, $f4, $f7 \n\t"
+ "madd.s $f14, $f14, $f5, $f16 \n\t"
+ "swc1 $f8, 16(%[out]) \n\t"
+ "lwc1 $f6, 24(%[in]) \n\t"
+ "mul.s $f9, $f3, $f7 \n\t"
+ "mul.s $f15, $f2, $f13 \n\t"
+ "msub.s $f15, $f15, %[gain], $f6 \n\t"
+ "sub.s $f1, $f15, $f9 \n\t"
+ "madd.s $f8, $f1, $f4, $f13 \n\t"
+ "madd.s $f8, $f8, $f5, $f7 \n\t"
+ "swc1 $f14, 20(%[out]) \n\t"
+ "lwc1 $f11, 28(%[in]) \n\t"
+ "mul.s $f12, $f3, $f13 \n\t"
+ "mul.s $f16, $f2, $f1 \n\t"
+ "msub.s $f16, $f16, %[gain], $f11 \n\t"
+ "sub.s $f0, $f16, $f12 \n\t"
+ "madd.s $f14, $f0, $f4, $f1 \n\t"
+ "madd.s $f14, $f14, $f5, $f13 \n\t"
+ "swc1 $f8, 24(%[out]) \n\t"
+ PTR_ADDIU "%[out], 32 \n\t"
+ PTR_ADDIU "%[in], 32 \n\t"
+ "addiu %[n], -8 \n\t"
+ "swc1 $f14, -4(%[out]) \n\t"
+ "bnez %[n], ff_acelp_apply_order_2_transfer_function_madd%= \n\t"
+ "swc1 $f1, 4(%[mem]) \n\t"
+ "swc1 $f0, 0(%[mem]) \n\t"
+
+ "ff_acelp_apply_order_2_transfer_function_end%=: \n\t"
+
+ : [out] "+r" (out),
+ [in] "+r" (in), [gain] "+f" (gain),
+ [n] "+r" (n), [mem] "+r" (mem)
+ : [zero_coeffs] "r" (zero_coeffs),
+ [pole_coeffs] "r" (pole_coeffs)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5",
+ "$f6", "$f7", "$f8", "$f9", "$f10", "$f11",
+ "$f12", "$f13", "$f14", "$f15", "$f16", "memory"
+ );
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_acelp_filter_init_mips(ACELPFContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->acelp_interpolatef = ff_acelp_interpolatef_mips;
+ c->acelp_apply_order_2_transfer_function = ff_acelp_apply_order_2_transfer_function_mips;
+#endif
+}
diff --git a/libavcodec/mips/acelp_vectors_mips.c b/libavcodec/mips/acelp_vectors_mips.c
new file mode 100644
index 0000000000..ad9434866e
--- /dev/null
+++ b/libavcodec/mips/acelp_vectors_mips.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * adaptive and fixed codebook vector operations for ACELP-based codecs
+ * 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/acelp_vectors.c
+ */
+#include "config.h"
+#include "libavcodec/acelp_vectors.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static void ff_weighted_vector_sumf_mips(
+ float *out, const float *in_a, const float *in_b,
+ float weight_coeff_a, float weight_coeff_b, int length)
+{
+ const float *a_end = in_a + length;
+
+ /* loop unrolled two times */
+ __asm__ volatile (
+ "blez %[length], ff_weighted_vector_sumf_end%= \n\t"
+
+ "ff_weighted_vector_sumf_madd%=: \n\t"
+ "lwc1 $f0, 0(%[in_a]) \n\t"
+ "lwc1 $f3, 4(%[in_a]) \n\t"
+ "lwc1 $f1, 0(%[in_b]) \n\t"
+ "lwc1 $f4, 4(%[in_b]) \n\t"
+ "mul.s $f2, %[weight_coeff_a], $f0 \n\t"
+ "mul.s $f5, %[weight_coeff_a], $f3 \n\t"
+ "madd.s $f2, $f2, %[weight_coeff_b], $f1 \n\t"
+ "madd.s $f5, $f5, %[weight_coeff_b], $f4 \n\t"
+ PTR_ADDIU "%[in_a],8 \n\t"
+ PTR_ADDIU "%[in_b],8 \n\t"
+ "swc1 $f2, 0(%[out]) \n\t"
+ "swc1 $f5, 4(%[out]) \n\t"
+ PTR_ADDIU "%[out], 8 \n\t"
+ "bne %[in_a], %[a_end], ff_weighted_vector_sumf_madd%= \n\t"
+
+ "ff_weighted_vector_sumf_end%=: \n\t"
+
+ : [out] "+r" (out), [in_a] "+r" (in_a), [in_b] "+r" (in_b)
+ : [weight_coeff_a] "f" (weight_coeff_a),
+ [weight_coeff_b] "f" (weight_coeff_b),
+ [length] "r" (length), [a_end]"r"(a_end)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "memory"
+ );
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_acelp_vectors_init_mips(ACELPVContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->weighted_vector_sumf = ff_weighted_vector_sumf_mips;
+#endif
+}
diff --git a/libavcodec/mips/amrwbdec_mips.c b/libavcodec/mips/amrwbdec_mips.c
new file mode 100644
index 0000000000..1d6ed2dfca
--- /dev/null
+++ b/libavcodec/mips/amrwbdec_mips.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/amrwbdec.c
+ */
+#include "libavutil/avutil.h"
+#include "libavcodec/amrwbdata.h"
+#include "amrwbdec_mips.h"
+
+#if HAVE_INLINE_ASM
+void hb_fir_filter_mips(float *out, const float fir_coef[HB_FIR_SIZE + 1],
+ float mem[HB_FIR_SIZE], const float *in)
+{
+ int i;
+ float data[AMRWB_SFR_SIZE_16k + HB_FIR_SIZE]; // past and current samples
+
+ memcpy(data, mem, HB_FIR_SIZE * sizeof(float));
+ memcpy(data + HB_FIR_SIZE, in, AMRWB_SFR_SIZE_16k * sizeof(float));
+
+ for (i = 0; i < AMRWB_SFR_SIZE_16k; i++) {
+ float output;
+ float * p_data = (data+i);
+
+ /**
+ * inner loop is entirely unrolled and instructions are scheduled
+ * to minimize pipeline stall
+ */
+ __asm__ volatile(
+ "mtc1 $zero, %[output] \n\t"
+ "lwc1 $f0, 0(%[p_data]) \n\t"
+ "lwc1 $f1, 0(%[fir_coef]) \n\t"
+ "lwc1 $f2, 4(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f3, 4(%[fir_coef]) \n\t"
+ "lwc1 $f4, 8(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f5, 8(%[fir_coef]) \n\t"
+
+ "lwc1 $f0, 12(%[p_data]) \n\t"
+ "lwc1 $f1, 12(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f2, 16(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f3, 16(%[fir_coef]) \n\t"
+ "lwc1 $f4, 20(%[p_data]) \n\t"
+ "lwc1 $f5, 20(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 24(%[p_data]) \n\t"
+ "lwc1 $f1, 24(%[fir_coef]) \n\t"
+ "lwc1 $f2, 28(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 28(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 32(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f5, 32(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+
+ "lwc1 $f0, 36(%[p_data]) \n\t"
+ "lwc1 $f1, 36(%[fir_coef]) \n\t"
+ "lwc1 $f2, 40(%[p_data]) \n\t"
+ "lwc1 $f3, 40(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 44(%[p_data]) \n\t"
+ "lwc1 $f5, 44(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 48(%[p_data]) \n\t"
+ "lwc1 $f1, 48(%[fir_coef]) \n\t"
+ "lwc1 $f2, 52(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 52(%[fir_coef]) \n\t"
+ "lwc1 $f4, 56(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f5, 56(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 60(%[p_data]) \n\t"
+ "lwc1 $f1, 60(%[fir_coef]) \n\t"
+ "lwc1 $f2, 64(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 64(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 68(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f5, 68(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+
+ "lwc1 $f0, 72(%[p_data]) \n\t"
+ "lwc1 $f1, 72(%[fir_coef]) \n\t"
+ "lwc1 $f2, 76(%[p_data]) \n\t"
+ "lwc1 $f3, 76(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 80(%[p_data]) \n\t"
+ "lwc1 $f5, 80(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 84(%[p_data]) \n\t"
+ "lwc1 $f1, 84(%[fir_coef]) \n\t"
+ "lwc1 $f2, 88(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 88(%[fir_coef]) \n\t"
+ "lwc1 $f4, 92(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f5, 92(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 96(%[p_data]) \n\t"
+ "lwc1 $f1, 96(%[fir_coef]) \n\t"
+ "lwc1 $f2, 100(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f3, 100(%[fir_coef]) \n\t"
+ "lwc1 $f4, 104(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f5, 104(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+
+ "lwc1 $f0, 108(%[p_data]) \n\t"
+ "lwc1 $f1, 108(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "lwc1 $f2, 112(%[p_data]) \n\t"
+ "lwc1 $f3, 112(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+ "lwc1 $f4, 116(%[p_data]) \n\t"
+ "lwc1 $f5, 116(%[fir_coef]) \n\t"
+ "lwc1 $f0, 120(%[p_data]) \n\t"
+ "madd.s %[output], %[output], $f2, $f3 \n\t"
+ "lwc1 $f1, 120(%[fir_coef]) \n\t"
+ "madd.s %[output], %[output], $f4, $f5 \n\t"
+ "madd.s %[output], %[output], $f0, $f1 \n\t"
+
+ : [output]"=&f"(output)
+ : [fir_coef]"r"(fir_coef), [p_data]"r"(p_data)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "memory"
+ );
+ out[i] = output;
+ }
+ memcpy(mem, data + AMRWB_SFR_SIZE_16k, HB_FIR_SIZE * sizeof(float));
+}
+#endif /* HAVE_INLINE_ASM */
diff --git a/libavcodec/mips/amrwbdec_mips.h b/libavcodec/mips/amrwbdec_mips.h
new file mode 100644
index 0000000000..a469918d2c
--- /dev/null
+++ b/libavcodec/mips/amrwbdec_mips.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Reference: libavcodec/amrwbdec.c
+ */
+#ifndef AVCODEC_AMRWBDEC_MIPS_H
+#define AVCODEC_AMRWBDEC_MIPS_H
+#include "config.h"
+
+#if HAVE_MIPSFPU && HAVE_INLINE_ASM
+void hb_fir_filter_mips(float *out, const float fir_coef[],
+ float mem[], const float *in);
+#define hb_fir_filter hb_fir_filter_mips
+#endif
+
+#endif /* AVCODEC_AMRWBDEC_MIPS_H */
diff --git a/libavcodec/mips/celp_filters_mips.c b/libavcodec/mips/celp_filters_mips.c
new file mode 100644
index 0000000000..88ac45841d
--- /dev/null
+++ b/libavcodec/mips/celp_filters_mips.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * various filters for CELP-based codecs 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/celp_filters.c
+ */
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/common.h"
+#include "libavcodec/celp_filters.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static void ff_celp_lp_synthesis_filterf_mips(float *out,
+ const float *filter_coeffs,
+ const float* in, int buffer_length,
+ int filter_length)
+{
+ int i,n;
+
+ float out0, out1, out2, out3;
+ float old_out0, old_out1, old_out2, old_out3;
+ float a,b,c;
+ const float *p_filter_coeffs;
+ float *p_out;
+
+ a = filter_coeffs[0];
+ b = filter_coeffs[1];
+ c = filter_coeffs[2];
+ b -= filter_coeffs[0] * filter_coeffs[0];
+ c -= filter_coeffs[1] * filter_coeffs[0];
+ c -= filter_coeffs[0] * b;
+
+ old_out0 = out[-4];
+ old_out1 = out[-3];
+ old_out2 = out[-2];
+ old_out3 = out[-1];
+ for (n = 0; n <= buffer_length - 4; n+=4) {
+ p_filter_coeffs = filter_coeffs;
+ p_out = out;
+
+ out0 = in[0];
+ out1 = in[1];
+ out2 = in[2];
+ out3 = in[3];
+
+ __asm__ volatile(
+ "lwc1 $f2, 8(%[filter_coeffs]) \n\t"
+ "lwc1 $f1, 4(%[filter_coeffs]) \n\t"
+ "lwc1 $f0, 0(%[filter_coeffs]) \n\t"
+ "nmsub.s %[out0], %[out0], $f2, %[old_out1] \n\t"
+ "nmsub.s %[out1], %[out1], $f2, %[old_out2] \n\t"
+ "nmsub.s %[out2], %[out2], $f2, %[old_out3] \n\t"
+ "lwc1 $f3, 12(%[filter_coeffs]) \n\t"
+ "nmsub.s %[out0], %[out0], $f1, %[old_out2] \n\t"
+ "nmsub.s %[out1], %[out1], $f1, %[old_out3] \n\t"
+ "nmsub.s %[out2], %[out2], $f3, %[old_out2] \n\t"
+ "nmsub.s %[out0], %[out0], $f0, %[old_out3] \n\t"
+ "nmsub.s %[out3], %[out3], $f3, %[old_out3] \n\t"
+ "nmsub.s %[out1], %[out1], $f3, %[old_out1] \n\t"
+ "nmsub.s %[out0], %[out0], $f3, %[old_out0] \n\t"
+
+ : [out0]"+f"(out0), [out1]"+f"(out1),
+ [out2]"+f"(out2), [out3]"+f"(out3)
+ : [old_out0]"f"(old_out0), [old_out1]"f"(old_out1),
+ [old_out2]"f"(old_out2), [old_out3]"f"(old_out3),
+ [filter_coeffs]"r"(filter_coeffs)
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "memory"
+ );
+
+ for (i = 5; i <= filter_length; i += 2) {
+ __asm__ volatile(
+ "lwc1 %[old_out3], -20(%[p_out]) \n\t"
+ "lwc1 $f5, 16(%[p_filter_coeffs]) \n\t"
+ PTR_ADDIU "%[p_out], -8 \n\t"
+ PTR_ADDIU "%[p_filter_coeffs], 8 \n\t"
+ "nmsub.s %[out1], %[out1], $f5, %[old_out0] \n\t"
+ "nmsub.s %[out3], %[out3], $f5, %[old_out2] \n\t"
+ "lwc1 $f4, 12(%[p_filter_coeffs]) \n\t"
+ "lwc1 %[old_out2], -16(%[p_out]) \n\t"
+ "nmsub.s %[out0], %[out0], $f5, %[old_out3] \n\t"
+ "nmsub.s %[out2], %[out2], $f5, %[old_out1] \n\t"
+ "nmsub.s %[out1], %[out1], $f4, %[old_out3] \n\t"
+ "nmsub.s %[out3], %[out3], $f4, %[old_out1] \n\t"
+ "mov.s %[old_out1], %[old_out3] \n\t"
+ "nmsub.s %[out0], %[out0], $f4, %[old_out2] \n\t"
+ "nmsub.s %[out2], %[out2], $f4, %[old_out0] \n\t"
+
+ : [out0]"+f"(out0), [out1]"+f"(out1),
+ [out2]"+f"(out2), [out3]"+f"(out3), [old_out0]"+f"(old_out0),
+ [old_out1]"+f"(old_out1), [old_out2]"+f"(old_out2),
+ [old_out3]"+f"(old_out3),[p_filter_coeffs]"+r"(p_filter_coeffs),
+ [p_out]"+r"(p_out)
+ :
+ : "$f4", "$f5", "memory"
+ );
+ FFSWAP(float, old_out0, old_out2);
+ }
+
+ __asm__ volatile(
+ "nmsub.s %[out3], %[out3], %[a], %[out2] \n\t"
+ "nmsub.s %[out2], %[out2], %[a], %[out1] \n\t"
+ "nmsub.s %[out3], %[out3], %[b], %[out1] \n\t"
+ "nmsub.s %[out1], %[out1], %[a], %[out0] \n\t"
+ "nmsub.s %[out2], %[out2], %[b], %[out0] \n\t"
+ "nmsub.s %[out3], %[out3], %[c], %[out0] \n\t"
+
+ : [out0]"+f"(out0), [out1]"+f"(out1),
+ [out2]"+f"(out2), [out3]"+f"(out3)
+ : [a]"f"(a), [b]"f"(b), [c]"f"(c)
+ );
+
+ out[0] = out0;
+ out[1] = out1;
+ out[2] = out2;
+ out[3] = out3;
+
+ old_out0 = out0;
+ old_out1 = out1;
+ old_out2 = out2;
+ old_out3 = out3;
+
+ out += 4;
+ in += 4;
+ }
+
+ out -= n;
+ in -= n;
+ for (; n < buffer_length; n++) {
+ float out_val, out_val_i, fc_val;
+ p_filter_coeffs = filter_coeffs;
+ p_out = &out[n];
+ out_val = in[n];
+ for (i = 1; i <= filter_length; i++) {
+ __asm__ volatile(
+ "lwc1 %[fc_val], 0(%[p_filter_coeffs]) \n\t"
+ "lwc1 %[out_val_i], -4(%[p_out]) \n\t"
+ PTR_ADDIU "%[p_filter_coeffs], 4 \n\t"
+ PTR_ADDIU "%[p_out], -4 \n\t"
+ "nmsub.s %[out_val], %[out_val], %[fc_val], %[out_val_i] \n\t"
+
+ : [fc_val]"=&f"(fc_val), [out_val]"+f"(out_val),
+ [out_val_i]"=&f"(out_val_i), [p_out]"+r"(p_out),
+ [p_filter_coeffs]"+r"(p_filter_coeffs)
+ :
+ : "memory"
+ );
+ }
+ out[n] = out_val;
+ }
+}
+
+static void ff_celp_lp_zero_synthesis_filterf_mips(float *out,
+ const float *filter_coeffs,
+ const float *in, int buffer_length,
+ int filter_length)
+{
+ int i,n;
+ float sum_out8, sum_out7, sum_out6, sum_out5, sum_out4, fc_val;
+ float sum_out3, sum_out2, sum_out1;
+ const float *p_filter_coeffs, *p_in;
+
+ for (n = 0; n < buffer_length; n+=8) {
+ p_in = &in[n];
+ p_filter_coeffs = filter_coeffs;
+ sum_out8 = in[n+7];
+ sum_out7 = in[n+6];
+ sum_out6 = in[n+5];
+ sum_out5 = in[n+4];
+ sum_out4 = in[n+3];
+ sum_out3 = in[n+2];
+ sum_out2 = in[n+1];
+ sum_out1 = in[n];
+ i = filter_length;
+
+ /* i is always greater than 0
+ * outer loop is unrolled eight times so there is less memory access
+ * inner loop is unrolled two times
+ */
+ __asm__ volatile(
+ "filt_lp_inner%=: \n\t"
+ "lwc1 %[fc_val], 0(%[p_filter_coeffs]) \n\t"
+ "lwc1 $f7, 6*4(%[p_in]) \n\t"
+ "lwc1 $f6, 5*4(%[p_in]) \n\t"
+ "lwc1 $f5, 4*4(%[p_in]) \n\t"
+ "lwc1 $f4, 3*4(%[p_in]) \n\t"
+ "lwc1 $f3, 2*4(%[p_in]) \n\t"
+ "lwc1 $f2, 4(%[p_in]) \n\t"
+ "lwc1 $f1, 0(%[p_in]) \n\t"
+ "lwc1 $f0, -4(%[p_in]) \n\t"
+ "addiu %[i], -2 \n\t"
+ "madd.s %[sum_out8], %[sum_out8], %[fc_val], $f7 \n\t"
+ "madd.s %[sum_out7], %[sum_out7], %[fc_val], $f6 \n\t"
+ "madd.s %[sum_out6], %[sum_out6], %[fc_val], $f5 \n\t"
+ "madd.s %[sum_out5], %[sum_out5], %[fc_val], $f4 \n\t"
+ "madd.s %[sum_out4], %[sum_out4], %[fc_val], $f3 \n\t"
+ "madd.s %[sum_out3], %[sum_out3], %[fc_val], $f2 \n\t"
+ "madd.s %[sum_out2], %[sum_out2], %[fc_val], $f1 \n\t"
+ "madd.s %[sum_out1], %[sum_out1], %[fc_val], $f0 \n\t"
+ "lwc1 %[fc_val], 4(%[p_filter_coeffs]) \n\t"
+ "lwc1 $f7, -8(%[p_in]) \n\t"
+ PTR_ADDIU "%[p_filter_coeffs], 8 \n\t"
+ PTR_ADDIU "%[p_in], -8 \n\t"
+ "madd.s %[sum_out8], %[sum_out8], %[fc_val], $f6 \n\t"
+ "madd.s %[sum_out7], %[sum_out7], %[fc_val], $f5 \n\t"
+ "madd.s %[sum_out6], %[sum_out6], %[fc_val], $f4 \n\t"
+ "madd.s %[sum_out5], %[sum_out5], %[fc_val], $f3 \n\t"
+ "madd.s %[sum_out4], %[sum_out4], %[fc_val], $f2 \n\t"
+ "madd.s %[sum_out3], %[sum_out3], %[fc_val], $f1 \n\t"
+ "madd.s %[sum_out2], %[sum_out2], %[fc_val], $f0 \n\t"
+ "madd.s %[sum_out1], %[sum_out1], %[fc_val], $f7 \n\t"
+ "bgtz %[i], filt_lp_inner%= \n\t"
+
+ : [sum_out8]"+f"(sum_out8), [sum_out7]"+f"(sum_out7),
+ [sum_out6]"+f"(sum_out6), [sum_out5]"+f"(sum_out5),
+ [sum_out4]"+f"(sum_out4), [sum_out3]"+f"(sum_out3),
+ [sum_out2]"+f"(sum_out2), [sum_out1]"+f"(sum_out1),
+ [fc_val]"=&f"(fc_val), [p_filter_coeffs]"+r"(p_filter_coeffs),
+ [p_in]"+r"(p_in), [i]"+r"(i)
+ :
+ : "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "memory"
+ );
+
+ out[n+7] = sum_out8;
+ out[n+6] = sum_out7;
+ out[n+5] = sum_out6;
+ out[n+4] = sum_out5;
+ out[n+3] = sum_out4;
+ out[n+2] = sum_out3;
+ out[n+1] = sum_out2;
+ out[n] = sum_out1;
+ }
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_celp_filter_init_mips(CELPFContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->celp_lp_synthesis_filterf = ff_celp_lp_synthesis_filterf_mips;
+ c->celp_lp_zero_synthesis_filterf = ff_celp_lp_zero_synthesis_filterf_mips;
+#endif
+}
diff --git a/libavcodec/mips/celp_math_mips.c b/libavcodec/mips/celp_math_mips.c
new file mode 100644
index 0000000000..008dd80308
--- /dev/null
+++ b/libavcodec/mips/celp_math_mips.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * Math operations 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/celp_math.c
+ */
+#include "config.h"
+#include "libavcodec/celp_math.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static float ff_dot_productf_mips(const float* a, const float* b,
+ int length)
+{
+ float sum;
+ const float* a_end = a + length;
+
+ __asm__ volatile (
+ "mtc1 $zero, %[sum] \n\t"
+ "blez %[length], ff_dot_productf_end%= \n\t"
+ "ff_dot_productf_madd%=: \n\t"
+ "lwc1 $f2, 0(%[a]) \n\t"
+ "lwc1 $f1, 0(%[b]) \n\t"
+ PTR_ADDIU "%[a], %[a], 4 \n\t"
+ PTR_ADDIU "%[b], %[b], 4 \n\t"
+ "madd.s %[sum], %[sum], $f1, $f2 \n\t"
+ "bne %[a], %[a_end], ff_dot_productf_madd%= \n\t"
+ "ff_dot_productf_end%=: \n\t"
+
+ : [sum] "=&f" (sum), [a] "+r" (a), [b] "+r" (b)
+ : [a_end]"r"(a_end), [length] "r" (length)
+ : "$f1", "$f2", "memory"
+ );
+ return sum;
+}
+#endif /* HAVE_INLINE_ASM */
+
+void ff_celp_math_init_mips(CELPMContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->dot_productf = ff_dot_productf_mips;
+#endif
+}
diff --git a/libavcodec/mips/compute_antialias_fixed.h b/libavcodec/mips/compute_antialias_fixed.h
new file mode 100644
index 0000000000..a967f67de7
--- /dev/null
+++ b/libavcodec/mips/compute_antialias_fixed.h
@@ -0,0 +1,250 @@
+/*
+ * 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)
+ *
+ * Compute antialias function optimised for MIPS fixed-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/mpegaudiodec.c
+ */
+
+#ifndef AVCODEC_MIPS_COMPUTE_ANTIALIAS_FIXED_H
+#define AVCODEC_MIPS_COMPUTE_ANTIALIAS_FIXED_H
+
+#if HAVE_INLINE_ASM
+static void compute_antialias_mips_fixed(MPADecodeContext *s,
+ GranuleDef *g)
+{
+ int32_t *ptr, *csa;
+ int n, i;
+ int MAX_lo = 0xffffffff;
+
+ /* we antialias only "long" bands */
+ if (g->block_type == 2) {
+ if (!g->switch_point)
+ return;
+ /* XXX: check this for 8000Hz case */
+ n = 1;
+ } else {
+ n = SBLIMIT - 1;
+ }
+
+
+ ptr = g->sb_hybrid + 18;
+
+ for(i = n;i > 0;i--) {
+ int tmp0, tmp1, tmp2, tmp00, tmp11;
+ int temp_reg1, temp_reg2, temp_reg3, temp_reg4, temp_reg5, temp_reg6;
+ csa = &csa_table[0][0];
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ */
+ __asm__ volatile (
+ "lw %[tmp0], -1*4(%[ptr]) \n\t"
+ "lw %[tmp1], 0*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 0*4(%[csa]) \n\t"
+ "lw %[temp_reg2], 2*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "lw %[temp_reg3], 3*4(%[csa]) \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "lw %[tmp00], -2*4(%[ptr]) \n\t"
+ "lw %[tmp11], 1*4(%[ptr]) \n\t"
+ "lw %[temp_reg4], 4*4(%[csa]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "lw %[temp_reg5], 6*4(%[csa]) \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[temp_reg6], 7*4(%[csa]) \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "sw %[temp_reg1], -1*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "sw %[temp_reg2], 0*4(%[ptr]) \n\t"
+ "lw %[tmp0], -3*4(%[ptr]) \n\t"
+ "lw %[tmp1], 2*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 8*4(%[csa]) \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "sw %[temp_reg4], -2*4(%[ptr]) \n\t"
+ "sw %[temp_reg5], 1*4(%[ptr]) \n\t"
+ "lw %[temp_reg2], 10*4(%[csa]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "lw %[temp_reg3], 11*4(%[csa]) \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "lw %[tmp00], -4*4(%[ptr]) \n\t"
+ "lw %[tmp11], 3*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "lw %[temp_reg4], 12*4(%[csa]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "lw %[temp_reg5], 14*4(%[csa]) \n\t"
+ "lw %[temp_reg6], 15*4(%[csa]) \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "sw %[temp_reg1], -3*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "sw %[temp_reg2], 2*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "lw %[tmp0], -5*4(%[ptr]) \n\t"
+ "lw %[tmp1], 4*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 16*4(%[csa]) \n\t"
+ "lw %[temp_reg2], 18*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "lw %[temp_reg3], 19*4(%[csa]) \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "sw %[temp_reg4], -4*4(%[ptr]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "sw %[temp_reg5], 3*4(%[ptr]) \n\t"
+ "lw %[tmp00], -6*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "lw %[tmp11], 5*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[temp_reg4], 20*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "lw %[temp_reg5], 22*4(%[csa]) \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "lw %[temp_reg6], 23*4(%[csa]) \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sw %[temp_reg1], -5*4(%[ptr]) \n\t"
+ "sw %[temp_reg2], 4*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "lw %[tmp0], -7*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "lw %[tmp1], 6*4(%[ptr]) \n\t"
+ "lw %[temp_reg1], 24*4(%[csa]) \n\t"
+ "lw %[temp_reg2], 26*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp0], %[tmp1] \n\t"
+ "lw %[temp_reg3], 27*4(%[csa]) \n\t"
+ "mult $ac0, %[tmp2], %[temp_reg1] \n\t"
+ "mult $ac1, %[tmp2], %[temp_reg1] \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "sw %[temp_reg4], -6*4(%[ptr]) \n\t"
+ "mtlo %[MAX_lo], $ac0 \n\t"
+ "msub $ac0, %[tmp1], %[temp_reg2] \n\t"
+ "mtlo $zero, $ac1 \n\t"
+ "madd $ac1, %[tmp0], %[temp_reg3] \n\t"
+ "sw %[temp_reg5], 5*4(%[ptr]) \n\t"
+ "lw %[tmp00], -8*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg1], $ac0 \n\t"
+ "lw %[tmp11], 7*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[temp_reg4], 28*4(%[csa]) \n\t"
+ "add %[tmp2], %[tmp00], %[tmp11] \n\t"
+ "lw %[temp_reg5], 30*4(%[csa]) \n\t"
+ "mult $ac2, %[tmp2], %[temp_reg4] \n\t"
+ "mult $ac3, %[tmp2], %[temp_reg4] \n\t"
+ "lw %[temp_reg6], 31*4(%[csa]) \n\t"
+ "sll %[temp_reg1], %[temp_reg1], 2 \n\t"
+ "sll %[temp_reg2], %[temp_reg2], 2 \n\t"
+ "mtlo %[MAX_lo], $ac2 \n\t"
+ "msub $ac2, %[tmp11], %[temp_reg5] \n\t"
+ "mtlo $zero, $ac3 \n\t"
+ "madd $ac3, %[tmp00], %[temp_reg6] \n\t"
+ "sw %[temp_reg1], -7*4(%[ptr]) \n\t"
+ "sw %[temp_reg2], 6*4(%[ptr]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "sll %[temp_reg4], %[temp_reg4], 2 \n\t"
+ "sll %[temp_reg5], %[temp_reg5], 2 \n\t"
+ "sw %[temp_reg4], -8*4(%[ptr]) \n\t"
+ "sw %[temp_reg5], 7*4(%[ptr]) \n\t"
+
+ : [tmp0] "=&r" (tmp0), [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2),
+ [tmp00] "=&r" (tmp00), [tmp11] "=&r" (tmp11),
+ [temp_reg1] "=&r" (temp_reg1), [temp_reg2] "=&r" (temp_reg2),
+ [temp_reg3] "=&r" (temp_reg3), [temp_reg4] "=&r" (temp_reg4),
+ [temp_reg5] "=&r" (temp_reg5), [temp_reg6] "=&r" (temp_reg6)
+ : [csa] "r" (csa), [ptr] "r" (ptr),
+ [MAX_lo] "r" (MAX_lo)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo"
+ );
+
+ ptr += 18;
+ }
+}
+#define compute_antialias compute_antialias_mips_fixed
+#endif /* HAVE_INLINE_ASM */
+
+#endif /* AVCODEC_MIPS_COMPUTE_ANTIALIAS_FIXED_H */
diff --git a/libavcodec/mips/compute_antialias_float.h b/libavcodec/mips/compute_antialias_float.h
new file mode 100644
index 0000000000..f6cf46508b
--- /dev/null
+++ b/libavcodec/mips/compute_antialias_float.h
@@ -0,0 +1,184 @@
+/*
+ * 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)
+ *
+ * Compute antialias function optimised 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/mpegaudiodec.c
+ */
+
+#ifndef AVCODEC_MIPS_COMPUTE_ANTIALIAS_FLOAT_H
+#define AVCODEC_MIPS_COMPUTE_ANTIALIAS_FLOAT_H
+
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static void compute_antialias_mips_float(MPADecodeContext *s,
+ GranuleDef *g)
+{
+ float *ptr, *ptr_end;
+ float *csa = &csa_table[0][0];
+ /* temporary variables */
+ float in1, in2, in3, in4, in5, in6, in7, in8;
+ float out1, out2, out3, out4;
+
+ ptr = g->sb_hybrid + 18;
+ /* we antialias only "long" bands */
+ if (g->block_type == 2) {
+ if (!g->switch_point)
+ return;
+ /* XXX: check this for 8000Hz case */
+ ptr_end = ptr + 18;
+ } else {
+ ptr_end = ptr + 558;
+ }
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ */
+
+ __asm__ volatile (
+ "compute_antialias_float_loop%=: \t\n"
+ "lwc1 %[in1], -1*4(%[ptr]) \t\n"
+ "lwc1 %[in2], 0(%[csa]) \t\n"
+ "lwc1 %[in3], 1*4(%[csa]) \t\n"
+ "lwc1 %[in4], 0(%[ptr]) \t\n"
+ "lwc1 %[in5], -2*4(%[ptr]) \t\n"
+ "lwc1 %[in6], 4*4(%[csa]) \t\n"
+ "mul.s %[out1], %[in1], %[in2] \t\n"
+ "mul.s %[out2], %[in1], %[in3] \t\n"
+ "lwc1 %[in7], 5*4(%[csa]) \t\n"
+ "lwc1 %[in8], 1*4(%[ptr]) \t\n"
+ "nmsub.s %[out1], %[out1], %[in3], %[in4] \t\n"
+ "madd.s %[out2], %[out2], %[in2], %[in4] \t\n"
+ "mul.s %[out3], %[in5], %[in6] \t\n"
+ "mul.s %[out4], %[in5], %[in7] \t\n"
+ "lwc1 %[in1], -3*4(%[ptr]) \t\n"
+ "swc1 %[out1], -1*4(%[ptr]) \t\n"
+ "swc1 %[out2], 0(%[ptr]) \t\n"
+ "nmsub.s %[out3], %[out3], %[in7], %[in8] \t\n"
+ "madd.s %[out4], %[out4], %[in6], %[in8] \t\n"
+ "lwc1 %[in2], 8*4(%[csa]) \t\n"
+ "swc1 %[out3], -2*4(%[ptr]) \t\n"
+ "swc1 %[out4], 1*4(%[ptr]) \t\n"
+ "lwc1 %[in3], 9*4(%[csa]) \t\n"
+ "lwc1 %[in4], 2*4(%[ptr]) \t\n"
+ "mul.s %[out1], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], -4*4(%[ptr]) \t\n"
+ "lwc1 %[in6], 12*4(%[csa]) \t\n"
+ "mul.s %[out2], %[in1], %[in3] \t\n"
+ "lwc1 %[in7], 13*4(%[csa]) \t\n"
+ "nmsub.s %[out1], %[out1], %[in3], %[in4] \t\n"
+ "lwc1 %[in8], 3*4(%[ptr]) \t\n"
+ "mul.s %[out3], %[in5], %[in6] \t\n"
+ "madd.s %[out2], %[out2], %[in2], %[in4] \t\n"
+ "mul.s %[out4], %[in5], %[in7] \t\n"
+ "swc1 %[out1], -3*4(%[ptr]) \t\n"
+ "lwc1 %[in1], -5*4(%[ptr]) \t\n"
+ "nmsub.s %[out3], %[out3], %[in7], %[in8] \t\n"
+ "swc1 %[out2], 2*4(%[ptr]) \t\n"
+ "madd.s %[out4], %[out4], %[in6], %[in8] \t\n"
+ "lwc1 %[in2], 16*4(%[csa]) \t\n"
+ "lwc1 %[in3], 17*4(%[csa]) \t\n"
+ "swc1 %[out3], -4*4(%[ptr]) \t\n"
+ "lwc1 %[in4], 4*4(%[ptr]) \t\n"
+ "swc1 %[out4], 3*4(%[ptr]) \t\n"
+ "mul.s %[out1], %[in1], %[in2] \t\n"
+ "mul.s %[out2], %[in1], %[in3] \t\n"
+ "lwc1 %[in5], -6*4(%[ptr]) \t\n"
+ "lwc1 %[in6], 20*4(%[csa]) \t\n"
+ "lwc1 %[in7], 21*4(%[csa]) \t\n"
+ "nmsub.s %[out1], %[out1], %[in3], %[in4] \t\n"
+ "madd.s %[out2], %[out2], %[in2], %[in4] \t\n"
+ "lwc1 %[in8], 5*4(%[ptr]) \t\n"
+ "mul.s %[out3], %[in5], %[in6] \t\n"
+ "mul.s %[out4], %[in5], %[in7] \t\n"
+ "swc1 %[out1], -5*4(%[ptr]) \t\n"
+ "swc1 %[out2], 4*4(%[ptr]) \t\n"
+ "lwc1 %[in1], -7*4(%[ptr]) \t\n"
+ "nmsub.s %[out3], %[out3], %[in7], %[in8] \t\n"
+ "madd.s %[out4], %[out4], %[in6], %[in8] \t\n"
+ "lwc1 %[in2], 24*4(%[csa]) \t\n"
+ "lwc1 %[in3], 25*4(%[csa]) \t\n"
+ "lwc1 %[in4], 6*4(%[ptr]) \t\n"
+ "swc1 %[out3], -6*4(%[ptr]) \t\n"
+ "swc1 %[out4], 5*4(%[ptr]) \t\n"
+ "mul.s %[out1], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], -8*4(%[ptr]) \t\n"
+ "mul.s %[out2], %[in1], %[in3] \t\n"
+ "lwc1 %[in6], 28*4(%[csa]) \t\n"
+ "lwc1 %[in7], 29*4(%[csa]) \t\n"
+ "nmsub.s %[out1], %[out1], %[in3], %[in4] \t\n"
+ "lwc1 %[in8], 7*4(%[ptr]) \t\n"
+ "madd.s %[out2], %[out2], %[in2], %[in4] \t\n"
+ "mul.s %[out3], %[in5], %[in6] \t\n"
+ "mul.s %[out4], %[in5], %[in7] \t\n"
+ "swc1 %[out1], -7*4(%[ptr]) \t\n"
+ "swc1 %[out2], 6*4(%[ptr]) \t\n"
+ PTR_ADDIU "%[ptr],%[ptr], 72 \t\n"
+ "nmsub.s %[out3], %[out3], %[in7], %[in8] \t\n"
+ "madd.s %[out4], %[out4], %[in6], %[in8] \t\n"
+ "swc1 %[out3], -26*4(%[ptr]) \t\n"
+ "swc1 %[out4], -11*4(%[ptr]) \t\n"
+ "bne %[ptr], %[ptr_end], compute_antialias_float_loop%= \t\n"
+
+ : [ptr] "+r" (ptr),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [in7] "=&f" (in7), [in8] "=&f" (in8),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3), [out4] "=&f" (out4)
+ : [csa] "r" (csa), [ptr_end] "r" (ptr_end)
+ : "memory"
+ );
+}
+#define compute_antialias compute_antialias_mips_float
+#endif /* HAVE_INLINE_ASM */
+
+#endif /* AVCODEC_MIPS_COMPUTE_ANTIALIAS_FLOAT_H */
diff --git a/libavcodec/mips/fft_mips.c b/libavcodec/mips/fft_mips.c
new file mode 100644
index 0000000000..cf008c6561
--- /dev/null
+++ b/libavcodec/mips/fft_mips.c
@@ -0,0 +1,513 @@
+/*
+ * 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: Stanislav Ocovaj (socovaj@mips.com)
+ * Author: Zoran Lukic (zoranl@mips.com)
+ *
+ * Optimized MDCT/IMDCT and FFT transforms
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "libavcodec/fft.h"
+#include "libavcodec/fft_table.h"
+#include "libavutil/mips/asmdefs.h"
+
+/**
+ * FFT transform
+ */
+
+#if HAVE_INLINE_ASM
+static void ff_fft_calc_mips(FFTContext *s, FFTComplex *z)
+{
+ int nbits, i, n, num_transforms, offset, step;
+ int n4, n2, n34;
+ FFTSample tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8;
+ FFTComplex *tmpz;
+ float w_re, w_im;
+ float *w_re_ptr, *w_im_ptr;
+ const int fft_size = (1 << s->nbits);
+ float pom, pom1, pom2, pom3;
+ float temp, temp1, temp3, temp4;
+ FFTComplex * tmpz_n2, * tmpz_n34, * tmpz_n4;
+ FFTComplex * tmpz_n2_i, * tmpz_n34_i, * tmpz_n4_i, * tmpz_i;
+
+ num_transforms = (0x2aab >> (16 - s->nbits)) | 1;
+
+ for (n=0; n<num_transforms; n++) {
+ offset = ff_fft_offsets_lut[n] << 2;
+ tmpz = z + offset;
+
+ tmp1 = tmpz[0].re + tmpz[1].re;
+ tmp5 = tmpz[2].re + tmpz[3].re;
+ tmp2 = tmpz[0].im + tmpz[1].im;
+ tmp6 = tmpz[2].im + tmpz[3].im;
+ tmp3 = tmpz[0].re - tmpz[1].re;
+ tmp8 = tmpz[2].im - tmpz[3].im;
+ tmp4 = tmpz[0].im - tmpz[1].im;
+ tmp7 = tmpz[2].re - tmpz[3].re;
+
+ tmpz[0].re = tmp1 + tmp5;
+ tmpz[2].re = tmp1 - tmp5;
+ tmpz[0].im = tmp2 + tmp6;
+ tmpz[2].im = tmp2 - tmp6;
+ tmpz[1].re = tmp3 + tmp8;
+ tmpz[3].re = tmp3 - tmp8;
+ tmpz[1].im = tmp4 - tmp7;
+ tmpz[3].im = tmp4 + tmp7;
+
+ }
+
+ if (fft_size < 8)
+ return;
+
+ num_transforms = (num_transforms >> 1) | 1;
+
+ for (n=0; n<num_transforms; n++) {
+ offset = ff_fft_offsets_lut[n] << 3;
+ tmpz = z + offset;
+
+ __asm__ volatile (
+ "lwc1 %[tmp1], 32(%[tmpz]) \n\t"
+ "lwc1 %[pom], 40(%[tmpz]) \n\t"
+ "lwc1 %[tmp3], 48(%[tmpz]) \n\t"
+ "lwc1 %[pom1], 56(%[tmpz]) \n\t"
+ "lwc1 %[tmp2], 36(%[tmpz]) \n\t"
+ "lwc1 %[pom2], 44(%[tmpz]) \n\t"
+ "lwc1 %[pom3], 60(%[tmpz]) \n\t"
+ "lwc1 %[tmp4], 52(%[tmpz]) \n\t"
+ "add.s %[tmp1], %[tmp1], %[pom] \n\t" // tmp1 = tmpz[4].re + tmpz[5].re;
+ "add.s %[tmp3], %[tmp3], %[pom1] \n\t" // tmp3 = tmpz[6].re + tmpz[7].re;
+ "add.s %[tmp2], %[tmp2], %[pom2] \n\t" // tmp2 = tmpz[4].im + tmpz[5].im;
+ "lwc1 %[pom], 40(%[tmpz]) \n\t"
+ "add.s %[tmp4], %[tmp4], %[pom3] \n\t" // tmp4 = tmpz[6].im + tmpz[7].im;
+ "add.s %[tmp5], %[tmp1], %[tmp3] \n\t" // tmp5 = tmp1 + tmp3;
+ "sub.s %[tmp7], %[tmp1], %[tmp3] \n\t" // tmp7 = tmp1 - tmp3;
+ "lwc1 %[tmp1], 32(%[tmpz]) \n\t"
+ "lwc1 %[pom1], 44(%[tmpz]) \n\t"
+ "add.s %[tmp6], %[tmp2], %[tmp4] \n\t" // tmp6 = tmp2 + tmp4;
+ "sub.s %[tmp8], %[tmp2], %[tmp4] \n\t" // tmp8 = tmp2 - tmp4;
+ "lwc1 %[tmp2], 36(%[tmpz]) \n\t"
+ "lwc1 %[pom2], 56(%[tmpz]) \n\t"
+ "lwc1 %[pom3], 60(%[tmpz]) \n\t"
+ "lwc1 %[tmp3], 48(%[tmpz]) \n\t"
+ "lwc1 %[tmp4], 52(%[tmpz]) \n\t"
+ "sub.s %[tmp1], %[tmp1], %[pom] \n\t" // tmp1 = tmpz[4].re - tmpz[5].re;
+ "lwc1 %[pom], 0(%[tmpz]) \n\t"
+ "sub.s %[tmp2], %[tmp2], %[pom1] \n\t" // tmp2 = tmpz[4].im - tmpz[5].im;
+ "sub.s %[tmp3], %[tmp3], %[pom2] \n\t" // tmp3 = tmpz[6].re - tmpz[7].re;
+ "lwc1 %[pom2], 4(%[tmpz]) \n\t"
+ "sub.s %[pom1], %[pom], %[tmp5] \n\t"
+ "sub.s %[tmp4], %[tmp4], %[pom3] \n\t" // tmp4 = tmpz[6].im - tmpz[7].im;
+ "add.s %[pom3], %[pom], %[tmp5] \n\t"
+ "sub.s %[pom], %[pom2], %[tmp6] \n\t"
+ "add.s %[pom2], %[pom2], %[tmp6] \n\t"
+ "swc1 %[pom1], 32(%[tmpz]) \n\t" // tmpz[4].re = tmpz[0].re - tmp5;
+ "swc1 %[pom3], 0(%[tmpz]) \n\t" // tmpz[0].re = tmpz[0].re + tmp5;
+ "swc1 %[pom], 36(%[tmpz]) \n\t" // tmpz[4].im = tmpz[0].im - tmp6;
+ "swc1 %[pom2], 4(%[tmpz]) \n\t" // tmpz[0].im = tmpz[0].im + tmp6;
+ "lwc1 %[pom1], 16(%[tmpz]) \n\t"
+ "lwc1 %[pom3], 20(%[tmpz]) \n\t"
+ "li.s %[pom], 0.7071067812 \n\t" // float pom = 0.7071067812f;
+ "add.s %[temp1],%[tmp1], %[tmp2] \n\t"
+ "sub.s %[temp], %[pom1], %[tmp8] \n\t"
+ "add.s %[pom2], %[pom3], %[tmp7] \n\t"
+ "sub.s %[temp3],%[tmp3], %[tmp4] \n\t"
+ "sub.s %[temp4],%[tmp2], %[tmp1] \n\t"
+ "swc1 %[temp], 48(%[tmpz]) \n\t" // tmpz[6].re = tmpz[2].re - tmp8;
+ "swc1 %[pom2], 52(%[tmpz]) \n\t" // tmpz[6].im = tmpz[2].im + tmp7;
+ "add.s %[pom1], %[pom1], %[tmp8] \n\t"
+ "sub.s %[pom3], %[pom3], %[tmp7] \n\t"
+ "add.s %[tmp3], %[tmp3], %[tmp4] \n\t"
+ "mul.s %[tmp5], %[pom], %[temp1] \n\t" // tmp5 = pom * (tmp1 + tmp2);
+ "mul.s %[tmp7], %[pom], %[temp3] \n\t" // tmp7 = pom * (tmp3 - tmp4);
+ "mul.s %[tmp6], %[pom], %[temp4] \n\t" // tmp6 = pom * (tmp2 - tmp1);
+ "mul.s %[tmp8], %[pom], %[tmp3] \n\t" // tmp8 = pom * (tmp3 + tmp4);
+ "swc1 %[pom1], 16(%[tmpz]) \n\t" // tmpz[2].re = tmpz[2].re + tmp8;
+ "swc1 %[pom3], 20(%[tmpz]) \n\t" // tmpz[2].im = tmpz[2].im - tmp7;
+ "add.s %[tmp1], %[tmp5], %[tmp7] \n\t" // tmp1 = tmp5 + tmp7;
+ "sub.s %[tmp3], %[tmp5], %[tmp7] \n\t" // tmp3 = tmp5 - tmp7;
+ "add.s %[tmp2], %[tmp6], %[tmp8] \n\t" // tmp2 = tmp6 + tmp8;
+ "sub.s %[tmp4], %[tmp6], %[tmp8] \n\t" // tmp4 = tmp6 - tmp8;
+ "lwc1 %[temp], 8(%[tmpz]) \n\t"
+ "lwc1 %[temp1],12(%[tmpz]) \n\t"
+ "lwc1 %[pom], 24(%[tmpz]) \n\t"
+ "lwc1 %[pom2], 28(%[tmpz]) \n\t"
+ "sub.s %[temp4],%[temp], %[tmp1] \n\t"
+ "sub.s %[temp3],%[temp1], %[tmp2] \n\t"
+ "add.s %[temp], %[temp], %[tmp1] \n\t"
+ "add.s %[temp1],%[temp1], %[tmp2] \n\t"
+ "sub.s %[pom1], %[pom], %[tmp4] \n\t"
+ "add.s %[pom3], %[pom2], %[tmp3] \n\t"
+ "add.s %[pom], %[pom], %[tmp4] \n\t"
+ "sub.s %[pom2], %[pom2], %[tmp3] \n\t"
+ "swc1 %[temp4],40(%[tmpz]) \n\t" // tmpz[5].re = tmpz[1].re - tmp1;
+ "swc1 %[temp3],44(%[tmpz]) \n\t" // tmpz[5].im = tmpz[1].im - tmp2;
+ "swc1 %[temp], 8(%[tmpz]) \n\t" // tmpz[1].re = tmpz[1].re + tmp1;
+ "swc1 %[temp1],12(%[tmpz]) \n\t" // tmpz[1].im = tmpz[1].im + tmp2;
+ "swc1 %[pom1], 56(%[tmpz]) \n\t" // tmpz[7].re = tmpz[3].re - tmp4;
+ "swc1 %[pom3], 60(%[tmpz]) \n\t" // tmpz[7].im = tmpz[3].im + tmp3;
+ "swc1 %[pom], 24(%[tmpz]) \n\t" // tmpz[3].re = tmpz[3].re + tmp4;
+ "swc1 %[pom2], 28(%[tmpz]) \n\t" // tmpz[3].im = tmpz[3].im - tmp3;
+ : [tmp1]"=&f"(tmp1), [pom]"=&f"(pom), [pom1]"=&f"(pom1), [pom2]"=&f"(pom2),
+ [tmp3]"=&f"(tmp3), [tmp2]"=&f"(tmp2), [tmp4]"=&f"(tmp4), [tmp5]"=&f"(tmp5), [tmp7]"=&f"(tmp7),
+ [tmp6]"=&f"(tmp6), [tmp8]"=&f"(tmp8), [pom3]"=&f"(pom3),[temp]"=&f"(temp), [temp1]"=&f"(temp1),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4)
+ : [tmpz]"r"(tmpz)
+ : "memory"
+ );
+ }
+
+ step = 1 << (MAX_LOG2_NFFT - 4);
+ n4 = 4;
+
+ for (nbits=4; nbits<=s->nbits; nbits++) {
+ num_transforms = (num_transforms >> 1) | 1;
+ n2 = 2 * n4;
+ n34 = 3 * n4;
+
+ for (n=0; n<num_transforms; n++) {
+ offset = ff_fft_offsets_lut[n] << nbits;
+ tmpz = z + offset;
+
+ tmpz_n2 = tmpz + n2;
+ tmpz_n4 = tmpz + n4;
+ tmpz_n34 = tmpz + n34;
+
+ __asm__ volatile (
+ "lwc1 %[pom1], 0(%[tmpz_n2]) \n\t"
+ "lwc1 %[pom], 0(%[tmpz_n34]) \n\t"
+ "lwc1 %[pom2], 4(%[tmpz_n2]) \n\t"
+ "lwc1 %[pom3], 4(%[tmpz_n34]) \n\t"
+ "lwc1 %[temp1],0(%[tmpz]) \n\t"
+ "lwc1 %[temp3],4(%[tmpz]) \n\t"
+ "add.s %[tmp5], %[pom1], %[pom] \n\t" // tmp5 = tmpz[ n2].re + tmpz[n34].re;
+ "sub.s %[tmp1], %[pom1], %[pom] \n\t" // tmp1 = tmpz[ n2].re - tmpz[n34].re;
+ "add.s %[tmp6], %[pom2], %[pom3] \n\t" // tmp6 = tmpz[ n2].im + tmpz[n34].im;
+ "sub.s %[tmp2], %[pom2], %[pom3] \n\t" // tmp2 = tmpz[ n2].im - tmpz[n34].im;
+ "sub.s %[temp], %[temp1], %[tmp5] \n\t"
+ "add.s %[temp1],%[temp1], %[tmp5] \n\t"
+ "sub.s %[temp4],%[temp3], %[tmp6] \n\t"
+ "add.s %[temp3],%[temp3], %[tmp6] \n\t"
+ "swc1 %[temp], 0(%[tmpz_n2]) \n\t" // tmpz[ n2].re = tmpz[ 0].re - tmp5;
+ "swc1 %[temp1],0(%[tmpz]) \n\t" // tmpz[ 0].re = tmpz[ 0].re + tmp5;
+ "lwc1 %[pom1], 0(%[tmpz_n4]) \n\t"
+ "swc1 %[temp4],4(%[tmpz_n2]) \n\t" // tmpz[ n2].im = tmpz[ 0].im - tmp6;
+ "lwc1 %[temp], 4(%[tmpz_n4]) \n\t"
+ "swc1 %[temp3],4(%[tmpz]) \n\t" // tmpz[ 0].im = tmpz[ 0].im + tmp6;
+ "sub.s %[pom], %[pom1], %[tmp2] \n\t"
+ "add.s %[pom1], %[pom1], %[tmp2] \n\t"
+ "add.s %[temp1],%[temp], %[tmp1] \n\t"
+ "sub.s %[temp], %[temp], %[tmp1] \n\t"
+ "swc1 %[pom], 0(%[tmpz_n34]) \n\t" // tmpz[n34].re = tmpz[n4].re - tmp2;
+ "swc1 %[pom1], 0(%[tmpz_n4]) \n\t" // tmpz[ n4].re = tmpz[n4].re + tmp2;
+ "swc1 %[temp1],4(%[tmpz_n34]) \n\t" // tmpz[n34].im = tmpz[n4].im + tmp1;
+ "swc1 %[temp], 4(%[tmpz_n4]) \n\t" // tmpz[ n4].im = tmpz[n4].im - tmp1;
+ : [tmp5]"=&f"(tmp5),
+ [tmp1]"=&f"(tmp1), [pom]"=&f"(pom), [pom1]"=&f"(pom1), [pom2]"=&f"(pom2),
+ [tmp2]"=&f"(tmp2), [tmp6]"=&f"(tmp6), [pom3]"=&f"(pom3),
+ [temp]"=&f"(temp), [temp1]"=&f"(temp1), [temp3]"=&f"(temp3), [temp4]"=&f"(temp4)
+ : [tmpz]"r"(tmpz), [tmpz_n2]"r"(tmpz_n2), [tmpz_n34]"r"(tmpz_n34), [tmpz_n4]"r"(tmpz_n4)
+ : "memory"
+ );
+
+ w_re_ptr = (float*)(ff_cos_65536 + step);
+ w_im_ptr = (float*)(ff_cos_65536 + MAX_FFT_SIZE/4 - step);
+
+ for (i=1; i<n4; i++) {
+ w_re = w_re_ptr[0];
+ w_im = w_im_ptr[0];
+ tmpz_n2_i = tmpz_n2 + i;
+ tmpz_n4_i = tmpz_n4 + i;
+ tmpz_n34_i= tmpz_n34 + i;
+ tmpz_i = tmpz + i;
+
+ __asm__ volatile (
+ "lwc1 %[temp], 0(%[tmpz_n2_i]) \n\t"
+ "lwc1 %[temp1], 4(%[tmpz_n2_i]) \n\t"
+ "lwc1 %[pom], 0(%[tmpz_n34_i]) \n\t"
+ "lwc1 %[pom1], 4(%[tmpz_n34_i]) \n\t"
+ "mul.s %[temp3], %[w_im], %[temp] \n\t"
+ "mul.s %[temp4], %[w_im], %[temp1] \n\t"
+ "mul.s %[pom2], %[w_im], %[pom1] \n\t"
+ "mul.s %[pom3], %[w_im], %[pom] \n\t"
+ "msub.s %[tmp2], %[temp3], %[w_re], %[temp1] \n\t" // tmp2 = w_re * tmpz[ n2+i].im - w_im * tmpz[ n2+i].re;
+ "madd.s %[tmp1], %[temp4], %[w_re], %[temp] \n\t" // tmp1 = w_re * tmpz[ n2+i].re + w_im * tmpz[ n2+i].im;
+ "msub.s %[tmp3], %[pom2], %[w_re], %[pom] \n\t" // tmp3 = w_re * tmpz[n34+i].re - w_im * tmpz[n34+i].im;
+ "madd.s %[tmp4], %[pom3], %[w_re], %[pom1] \n\t" // tmp4 = w_re * tmpz[n34+i].im + w_im * tmpz[n34+i].re;
+ "lwc1 %[temp], 0(%[tmpz_i]) \n\t"
+ "lwc1 %[pom], 4(%[tmpz_i]) \n\t"
+ "add.s %[tmp5], %[tmp1], %[tmp3] \n\t" // tmp5 = tmp1 + tmp3;
+ "sub.s %[tmp1], %[tmp1], %[tmp3] \n\t" // tmp1 = tmp1 - tmp3;
+ "add.s %[tmp6], %[tmp2], %[tmp4] \n\t" // tmp6 = tmp2 + tmp4;
+ "sub.s %[tmp2], %[tmp2], %[tmp4] \n\t" // tmp2 = tmp2 - tmp4;
+ "sub.s %[temp1], %[temp], %[tmp5] \n\t"
+ "add.s %[temp], %[temp], %[tmp5] \n\t"
+ "sub.s %[pom1], %[pom], %[tmp6] \n\t"
+ "add.s %[pom], %[pom], %[tmp6] \n\t"
+ "lwc1 %[temp3], 0(%[tmpz_n4_i]) \n\t"
+ "lwc1 %[pom2], 4(%[tmpz_n4_i]) \n\t"
+ "swc1 %[temp1], 0(%[tmpz_n2_i]) \n\t" // tmpz[ n2+i].re = tmpz[ i].re - tmp5;
+ "swc1 %[temp], 0(%[tmpz_i]) \n\t" // tmpz[ i].re = tmpz[ i].re + tmp5;
+ "swc1 %[pom1], 4(%[tmpz_n2_i]) \n\t" // tmpz[ n2+i].im = tmpz[ i].im - tmp6;
+ "swc1 %[pom] , 4(%[tmpz_i]) \n\t" // tmpz[ i].im = tmpz[ i].im + tmp6;
+ "sub.s %[temp4], %[temp3], %[tmp2] \n\t"
+ "add.s %[pom3], %[pom2], %[tmp1] \n\t"
+ "add.s %[temp3], %[temp3], %[tmp2] \n\t"
+ "sub.s %[pom2], %[pom2], %[tmp1] \n\t"
+ "swc1 %[temp4], 0(%[tmpz_n34_i]) \n\t" // tmpz[n34+i].re = tmpz[n4+i].re - tmp2;
+ "swc1 %[pom3], 4(%[tmpz_n34_i]) \n\t" // tmpz[n34+i].im = tmpz[n4+i].im + tmp1;
+ "swc1 %[temp3], 0(%[tmpz_n4_i]) \n\t" // tmpz[ n4+i].re = tmpz[n4+i].re + tmp2;
+ "swc1 %[pom2], 4(%[tmpz_n4_i]) \n\t" // tmpz[ n4+i].im = tmpz[n4+i].im - tmp1;
+ : [tmp1]"=&f"(tmp1), [tmp2]"=&f" (tmp2), [temp]"=&f"(temp), [tmp3]"=&f"(tmp3),
+ [tmp4]"=&f"(tmp4), [tmp5]"=&f"(tmp5), [tmp6]"=&f"(tmp6),
+ [temp1]"=&f"(temp1), [temp3]"=&f"(temp3), [temp4]"=&f"(temp4),
+ [pom]"=&f"(pom), [pom1]"=&f"(pom1), [pom2]"=&f"(pom2), [pom3]"=&f"(pom3)
+ : [w_re]"f"(w_re), [w_im]"f"(w_im),
+ [tmpz_i]"r"(tmpz_i),[tmpz_n2_i]"r"(tmpz_n2_i),
+ [tmpz_n34_i]"r"(tmpz_n34_i), [tmpz_n4_i]"r"(tmpz_n4_i)
+ : "memory"
+ );
+ w_re_ptr += step;
+ w_im_ptr -= step;
+ }
+ }
+ step >>= 1;
+ n4 <<= 1;
+ }
+}
+
+/**
+ * MDCT/IMDCT transforms.
+ */
+
+static void ff_imdct_half_mips(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ int k, n8, n4, n2, n, j;
+ const uint16_t *revtab = s->revtab;
+ const FFTSample *tcos = s->tcos;
+ const FFTSample *tsin = s->tsin;
+ const FFTSample *in1, *in2, *in3, *in4;
+ FFTComplex *z = (FFTComplex *)output;
+
+ int j1;
+ const float *tcos1, *tsin1, *tcos2, *tsin2;
+ float temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8,
+ temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16;
+ FFTComplex *z1, *z2;
+
+ n = 1 << s->mdct_bits;
+ n2 = n >> 1;
+ n4 = n >> 2;
+ n8 = n >> 3;
+
+ /* pre rotation */
+ in1 = input;
+ in2 = input + n2 - 1;
+ in3 = input + 2;
+ in4 = input + n2 - 3;
+
+ tcos1 = tcos;
+ tsin1 = tsin;
+
+ /* n4 = 64 or 128 */
+ for(k = 0; k < n4; k += 2) {
+ j = revtab[k ];
+ j1 = revtab[k + 1];
+
+ __asm__ volatile (
+ "lwc1 %[temp1], 0(%[in2]) \t\n"
+ "lwc1 %[temp2], 0(%[tcos1]) \t\n"
+ "lwc1 %[temp3], 0(%[tsin1]) \t\n"
+ "lwc1 %[temp4], 0(%[in1]) \t\n"
+ "lwc1 %[temp5], 0(%[in4]) \t\n"
+ "mul.s %[temp9], %[temp1], %[temp2] \t\n"
+ "mul.s %[temp10], %[temp1], %[temp3] \t\n"
+ "lwc1 %[temp6], 4(%[tcos1]) \t\n"
+ "lwc1 %[temp7], 4(%[tsin1]) \t\n"
+ "nmsub.s %[temp9], %[temp9], %[temp4], %[temp3] \t\n"
+ "madd.s %[temp10], %[temp10], %[temp4], %[temp2] \t\n"
+ "mul.s %[temp11], %[temp5], %[temp6] \t\n"
+ "mul.s %[temp12], %[temp5], %[temp7] \t\n"
+ "lwc1 %[temp8], 0(%[in3]) \t\n"
+ PTR_ADDIU " %[tcos1], %[tcos1], 8 \t\n"
+ PTR_ADDIU " %[tsin1], %[tsin1], 8 \t\n"
+ PTR_ADDIU " %[in1], %[in1], 16 \t\n"
+ "nmsub.s %[temp11], %[temp11], %[temp8], %[temp7] \t\n"
+ "madd.s %[temp12], %[temp12], %[temp8], %[temp6] \t\n"
+ PTR_ADDIU " %[in2], %[in2], -16 \t\n"
+ PTR_ADDIU " %[in3], %[in3], 16 \t\n"
+ PTR_ADDIU " %[in4], %[in4], -16 \t\n"
+
+ : [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),
+ [tsin1]"+r"(tsin1), [tcos1]"+r"(tcos1),
+ [in1]"+r"(in1), [in2]"+r"(in2),
+ [in3]"+r"(in3), [in4]"+r"(in4)
+ :
+ : "memory"
+ );
+
+ z[j ].re = temp9;
+ z[j ].im = temp10;
+ z[j1].re = temp11;
+ z[j1].im = temp12;
+ }
+
+ s->fft_calc(s, z);
+
+ /* post rotation + reordering */
+ /* n8 = 32 or 64 */
+ for(k = 0; k < n8; k += 2) {
+ tcos1 = &tcos[n8 - k - 2];
+ tsin1 = &tsin[n8 - k - 2];
+ tcos2 = &tcos[n8 + k];
+ tsin2 = &tsin[n8 + k];
+ z1 = &z[n8 - k - 2];
+ z2 = &z[n8 + k ];
+
+ __asm__ volatile (
+ "lwc1 %[temp1], 12(%[z1]) \t\n"
+ "lwc1 %[temp2], 4(%[tsin1]) \t\n"
+ "lwc1 %[temp3], 4(%[tcos1]) \t\n"
+ "lwc1 %[temp4], 8(%[z1]) \t\n"
+ "lwc1 %[temp5], 4(%[z1]) \t\n"
+ "mul.s %[temp9], %[temp1], %[temp2] \t\n"
+ "mul.s %[temp10], %[temp1], %[temp3] \t\n"
+ "lwc1 %[temp6], 0(%[tsin1]) \t\n"
+ "lwc1 %[temp7], 0(%[tcos1]) \t\n"
+ "nmsub.s %[temp9], %[temp9], %[temp4], %[temp3] \t\n"
+ "madd.s %[temp10], %[temp10], %[temp4], %[temp2] \t\n"
+ "mul.s %[temp11], %[temp5], %[temp6] \t\n"
+ "mul.s %[temp12], %[temp5], %[temp7] \t\n"
+ "lwc1 %[temp8], 0(%[z1]) \t\n"
+ "lwc1 %[temp1], 4(%[z2]) \t\n"
+ "lwc1 %[temp2], 0(%[tsin2]) \t\n"
+ "lwc1 %[temp3], 0(%[tcos2]) \t\n"
+ "nmsub.s %[temp11], %[temp11], %[temp8], %[temp7] \t\n"
+ "madd.s %[temp12], %[temp12], %[temp8], %[temp6] \t\n"
+ "mul.s %[temp13], %[temp1], %[temp2] \t\n"
+ "mul.s %[temp14], %[temp1], %[temp3] \t\n"
+ "lwc1 %[temp4], 0(%[z2]) \t\n"
+ "lwc1 %[temp5], 12(%[z2]) \t\n"
+ "lwc1 %[temp6], 4(%[tsin2]) \t\n"
+ "lwc1 %[temp7], 4(%[tcos2]) \t\n"
+ "nmsub.s %[temp13], %[temp13], %[temp4], %[temp3] \t\n"
+ "madd.s %[temp14], %[temp14], %[temp4], %[temp2] \t\n"
+ "mul.s %[temp15], %[temp5], %[temp6] \t\n"
+ "mul.s %[temp16], %[temp5], %[temp7] \t\n"
+ "lwc1 %[temp8], 8(%[z2]) \t\n"
+ "nmsub.s %[temp15], %[temp15], %[temp8], %[temp7] \t\n"
+ "madd.s %[temp16], %[temp16], %[temp8], %[temp6] \t\n"
+ : [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)
+ : [z1]"r"(z1), [z2]"r"(z2),
+ [tsin1]"r"(tsin1), [tcos1]"r"(tcos1),
+ [tsin2]"r"(tsin2), [tcos2]"r"(tcos2)
+ : "memory"
+ );
+
+ z1[1].re = temp9;
+ z1[1].im = temp14;
+ z2[0].re = temp13;
+ z2[0].im = temp10;
+
+ z1[0].re = temp11;
+ z1[0].im = temp16;
+ z2[1].re = temp15;
+ z2[1].im = temp12;
+ }
+}
+
+/**
+ * Compute inverse MDCT of size N = 2^nbits
+ * @param output N samples
+ * @param input N/2 samples
+ */
+static void ff_imdct_calc_mips(FFTContext *s, FFTSample *output, const FFTSample *input)
+{
+ int k;
+ int n = 1 << s->mdct_bits;
+ int n2 = n >> 1;
+ int n4 = n >> 2;
+
+ ff_imdct_half_mips(s, output+n4, input);
+
+ for(k = 0; k < n4; k+=4) {
+ output[k] = -output[n2-k-1];
+ output[k+1] = -output[n2-k-2];
+ output[k+2] = -output[n2-k-3];
+ output[k+3] = -output[n2-k-4];
+
+ output[n-k-1] = output[n2+k];
+ output[n-k-2] = output[n2+k+1];
+ output[n-k-3] = output[n2+k+2];
+ output[n-k-4] = output[n2+k+3];
+ }
+}
+#endif /* HAVE_INLINE_ASM */
+
+av_cold void ff_fft_init_mips(FFTContext *s)
+{
+ int n=0;
+
+ ff_fft_lut_init(ff_fft_offsets_lut, 0, 1 << 16, &n);
+ ff_init_ff_cos_tabs(16);
+
+#if HAVE_INLINE_ASM
+ s->fft_calc = ff_fft_calc_mips;
+#if CONFIG_MDCT
+ s->imdct_calc = ff_imdct_calc_mips;
+ s->imdct_half = ff_imdct_half_mips;
+#endif
+#endif
+}
diff --git a/libavcodec/mips/fmtconvert_mips.c b/libavcodec/mips/fmtconvert_mips.c
new file mode 100644
index 0000000000..990958402c
--- /dev/null
+++ b/libavcodec/mips/fmtconvert_mips.c
@@ -0,0 +1,141 @@
+/*
+ * Format Conversion Utils for MIPS
+ *
+ * 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 is
+ * 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: Zoran Lukic (zoranl@mips.com)
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/fmtconvert.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM
+static void int32_to_float_fmul_scalar_mips(float *dst, const int *src,
+ float mul, int len)
+{
+ /*
+ * variables used in inline assembler
+ */
+ float temp1, temp3, temp5, temp7, temp9, temp11, temp13, temp15;
+
+ int rpom1, rpom2, rpom11, rpom21, rpom12, rpom22, rpom13, rpom23;
+ const int *src_end = src + len;
+ /*
+ * loop is 8 times unrolled in assembler in order to achieve better performance
+ */
+ __asm__ volatile (
+ "i32tf_lp%=: \n\t"
+ "lw %[rpom11], 0(%[src]) \n\t"
+ "lw %[rpom21], 4(%[src]) \n\t"
+ "lw %[rpom1], 8(%[src]) \n\t"
+ "lw %[rpom2], 12(%[src]) \n\t"
+ "mtc1 %[rpom11], %[temp1] \n\t"
+ "mtc1 %[rpom21], %[temp3] \n\t"
+ "mtc1 %[rpom1], %[temp5] \n\t"
+ "mtc1 %[rpom2], %[temp7] \n\t"
+
+ "lw %[rpom13], 16(%[src]) \n\t"
+ "lw %[rpom23], 20(%[src]) \n\t"
+ "lw %[rpom12], 24(%[src]) \n\t"
+ "lw %[rpom22], 28(%[src]) \n\t"
+ "mtc1 %[rpom13], %[temp9] \n\t"
+ "mtc1 %[rpom23], %[temp11] \n\t"
+ "mtc1 %[rpom12], %[temp13] \n\t"
+ "mtc1 %[rpom22], %[temp15] \n\t"
+
+ PTR_ADDIU "%[src], 32 \n\t"
+ "cvt.s.w %[temp1], %[temp1] \n\t"
+ "cvt.s.w %[temp3], %[temp3] \n\t"
+ "cvt.s.w %[temp5], %[temp5] \n\t"
+ "cvt.s.w %[temp7], %[temp7] \n\t"
+
+ "cvt.s.w %[temp9], %[temp9] \n\t"
+ "cvt.s.w %[temp11], %[temp11] \n\t"
+ "cvt.s.w %[temp13], %[temp13] \n\t"
+ "cvt.s.w %[temp15], %[temp15] \n\t"
+
+ "mul.s %[temp1], %[temp1], %[mul] \n\t"
+ "mul.s %[temp3], %[temp3], %[mul] \n\t"
+ "mul.s %[temp5], %[temp5], %[mul] \n\t"
+ "mul.s %[temp7], %[temp7], %[mul] \n\t"
+
+ "mul.s %[temp9], %[temp9], %[mul] \n\t"
+ "mul.s %[temp11], %[temp11], %[mul] \n\t"
+ "mul.s %[temp13], %[temp13], %[mul] \n\t"
+ "mul.s %[temp15], %[temp15], %[mul] \n\t"
+
+ "swc1 %[temp1], 0(%[dst]) \n\t" /*dst[i] = src[i] * mul; */
+ "swc1 %[temp3], 4(%[dst]) \n\t" /*dst[i+1] = src[i+1] * mul;*/
+ "swc1 %[temp5], 8(%[dst]) \n\t" /*dst[i+2] = src[i+2] * mul;*/
+ "swc1 %[temp7], 12(%[dst]) \n\t" /*dst[i+3] = src[i+3] * mul;*/
+
+ "swc1 %[temp9], 16(%[dst]) \n\t" /*dst[i+4] = src[i+4] * mul;*/
+ "swc1 %[temp11], 20(%[dst]) \n\t" /*dst[i+5] = src[i+5] * mul;*/
+ "swc1 %[temp13], 24(%[dst]) \n\t" /*dst[i+6] = src[i+6] * mul;*/
+ "swc1 %[temp15], 28(%[dst]) \n\t" /*dst[i+7] = src[i+7] * mul;*/
+ PTR_ADDIU "%[dst], 32 \n\t"
+ "bne %[src], %[src_end], i32tf_lp%= \n\t"
+ : [temp1]"=&f"(temp1), [temp11]"=&f"(temp11),
+ [temp13]"=&f"(temp13), [temp15]"=&f"(temp15),
+ [temp3]"=&f"(temp3), [temp5]"=&f"(temp5),
+ [temp7]"=&f"(temp7), [temp9]"=&f"(temp9),
+ [rpom1]"=&r"(rpom1), [rpom2]"=&r"(rpom2),
+ [rpom11]"=&r"(rpom11), [rpom21]"=&r"(rpom21),
+ [rpom12]"=&r"(rpom12), [rpom22]"=&r"(rpom22),
+ [rpom13]"=&r"(rpom13), [rpom23]"=&r"(rpom23),
+ [dst]"+r"(dst), [src]"+r"(src)
+ : [mul]"f"(mul), [src_end]"r"(src_end)
+ : "memory"
+ );
+}
+#endif /* HAVE_INLINE_ASM */
+
+av_cold void ff_fmt_convert_init_mips(FmtConvertContext *c)
+{
+#if HAVE_INLINE_ASM
+ c->int32_to_float_fmul_scalar = int32_to_float_fmul_scalar_mips;
+#endif
+}
diff --git a/libavcodec/mips/h264dsp_init_mips.c b/libavcodec/mips/h264dsp_init_mips.c
new file mode 100644
index 0000000000..8d3d76085f
--- /dev/null
+++ b/libavcodec/mips/h264dsp_init_mips.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015 Parag Salasakar (Parag.Salasakar@imgtec.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
+ */
+
+#include "h264dsp_mips.h"
+
+#if HAVE_MSA
+static av_cold void h264dsp_init_msa(H264DSPContext *c,
+ const int bit_depth,
+ const int chroma_format_idc)
+{
+ if (8 == bit_depth) {
+ c->h264_v_loop_filter_luma = ff_h264_v_lpf_luma_inter_msa;
+ c->h264_h_loop_filter_luma = ff_h264_h_lpf_luma_inter_msa;
+ c->h264_h_loop_filter_luma_mbaff =
+ ff_h264_h_loop_filter_luma_mbaff_msa;
+ c->h264_v_loop_filter_luma_intra = ff_h264_v_lpf_luma_intra_msa;
+ c->h264_h_loop_filter_luma_intra = ff_h264_h_lpf_luma_intra_msa;
+ c->h264_h_loop_filter_luma_mbaff_intra =
+ ff_h264_h_loop_filter_luma_mbaff_intra_msa;
+ c->h264_v_loop_filter_chroma = ff_h264_v_lpf_chroma_inter_msa;
+
+ if (chroma_format_idc <= 1)
+ c->h264_h_loop_filter_chroma = ff_h264_h_lpf_chroma_inter_msa;
+ else
+ c->h264_h_loop_filter_chroma =
+ ff_h264_h_loop_filter_chroma422_msa;
+
+ if (chroma_format_idc > 1)
+ c->h264_h_loop_filter_chroma_mbaff =
+ ff_h264_h_loop_filter_chroma422_mbaff_msa;
+
+ c->h264_v_loop_filter_chroma_intra =
+ ff_h264_v_lpf_chroma_intra_msa;
+
+ if (chroma_format_idc <= 1)
+ c->h264_h_loop_filter_chroma_intra =
+ ff_h264_h_lpf_chroma_intra_msa;
+
+ /* Weighted MC */
+ c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels16_8_msa;
+ c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels8_8_msa;
+ c->weight_h264_pixels_tab[2] = ff_weight_h264_pixels4_8_msa;
+
+ c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels16_8_msa;
+ c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels8_8_msa;
+ c->biweight_h264_pixels_tab[2] = ff_biweight_h264_pixels4_8_msa;
+ } // if (8 == bit_depth)
+}
+#endif // #if HAVE_MSA
+
+av_cold void ff_h264dsp_init_mips(H264DSPContext *c, const int bit_depth,
+ const int chroma_format_idc)
+{
+#if HAVE_MSA
+ h264dsp_init_msa(c, bit_depth, chroma_format_idc);
+#endif // #if HAVE_MSA
+}
diff --git a/libavcodec/mips/h264dsp_mips.h b/libavcodec/mips/h264dsp_mips.h
new file mode 100644
index 0000000000..df9b0b29d7
--- /dev/null
+++ b/libavcodec/mips/h264dsp_mips.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 Parag Salasakar (Parag.Salasakar@imgtec.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef H264_DSP_MIPS_H
+#define H264_DSP_MIPS_H
+
+#include "libavcodec/h264.h"
+
+void ff_h264_h_lpf_luma_inter_msa(uint8_t *src, int stride,
+ int alpha, int beta, int8_t *tc0);
+void ff_h264_v_lpf_luma_inter_msa(uint8_t *src, int stride,
+ int alpha, int beta, int8_t *tc0);
+void ff_h264_h_lpf_chroma_inter_msa(uint8_t *src, int stride,
+ int alpha, int beta, int8_t *tc0);
+void ff_h264_v_lpf_chroma_inter_msa(uint8_t *src, int stride,
+ int alpha, int beta, int8_t *tc0);
+void ff_h264_h_loop_filter_chroma422_msa(uint8_t *src, int32_t stride,
+ int32_t alpha, int32_t beta,
+ int8_t *tc0);
+void ff_h264_h_loop_filter_chroma422_mbaff_msa(uint8_t *src, int32_t stride,
+ int32_t alpha, int32_t beta,
+ int8_t *tc0);
+void ff_h264_h_loop_filter_luma_mbaff_msa(uint8_t *src, int32_t stride,
+ int32_t alpha, int32_t beta,
+ int8_t *tc0);
+
+void ff_h264_h_lpf_luma_intra_msa(uint8_t *src, int stride,
+ int alpha, int beta);
+void ff_h264_v_lpf_luma_intra_msa(uint8_t *src, int stride,
+ int alpha, int beta);
+void ff_h264_h_lpf_chroma_intra_msa(uint8_t *src, int stride,
+ int alpha, int beta);
+void ff_h264_v_lpf_chroma_intra_msa(uint8_t *src, int stride,
+ int alpha, int beta);
+void ff_h264_h_loop_filter_luma_mbaff_intra_msa(uint8_t *src, int stride,
+ int alpha, int beta);
+
+void ff_biweight_h264_pixels16_8_msa(uint8_t *dst, uint8_t *src,
+ int stride, int height, int log2_denom,
+ int weightd, int weights, int offset);
+void ff_biweight_h264_pixels8_8_msa(uint8_t *dst, uint8_t *src,
+ int stride, int height, int log2_denom,
+ int weightd, int weights, int offset);
+void ff_biweight_h264_pixels4_8_msa(uint8_t *dst, uint8_t *src,
+ int stride, int height, int log2_denom,
+ int weightd, int weights, int offset);
+void ff_weight_h264_pixels16_8_msa(uint8_t *src, int stride, int height,
+ int log2_denom, int weight, int offset);
+void ff_weight_h264_pixels8_8_msa(uint8_t *src, int stride, int height,
+ int log2_denom, int weight, int offset);
+void ff_weight_h264_pixels4_8_msa(uint8_t *src, int stride, int height,
+ int log2_denom, int weight, int offset);
+
+#endif // #ifndef H264_DSP_MIPS_H
diff --git a/libavcodec/mips/h264dsp_msa.c b/libavcodec/mips/h264dsp_msa.c
new file mode 100644
index 0000000000..f728fcc147
--- /dev/null
+++ b/libavcodec/mips/h264dsp_msa.c
@@ -0,0 +1,3034 @@
+/*
+ * Copyright (c) 2015 Parag Salasakar (Parag.Salasakar@imgtec.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
+ */
+
+#include "libavutil/mips/generic_macros_msa.h"
+#include "h264dsp_mips.h"
+
+static void avc_wgt_4x2_msa(uint8_t *data,
+ int32_t stride,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t offset_in)
+{
+ uint32_t data0, data1;
+ v16u8 zero = { 0 };
+ v16u8 src0, src1;
+ v4i32 res0, res1;
+ v8i16 temp0, temp1;
+ v16u8 vec0, vec1;
+ v8i16 wgt, denom, offset;
+
+ offset_in <<= (log2_denom);
+
+ if (log2_denom) {
+ offset_in += (1 << (log2_denom - 1));
+ }
+
+ wgt = __msa_fill_h(src_weight);
+ offset = __msa_fill_h(offset_in);
+ denom = __msa_fill_h(log2_denom);
+
+ data0 = LOAD_WORD(data);
+ data1 = LOAD_WORD(data + stride);
+
+ src0 = (v16u8) __msa_fill_w(data0);
+ src1 = (v16u8) __msa_fill_w(data1);
+
+ ILVR_B_2VECS_UB(src0, src1, zero, zero, vec0, vec1);
+
+ temp0 = wgt * (v8i16) vec0;
+ temp1 = wgt * (v8i16) vec1;
+
+ temp0 = __msa_adds_s_h(temp0, offset);
+ temp1 = __msa_adds_s_h(temp1, offset);
+
+ temp0 = __msa_maxi_s_h(temp0, 0);
+ temp1 = __msa_maxi_s_h(temp1, 0);
+
+ temp0 = __msa_srl_h(temp0, denom);
+ temp1 = __msa_srl_h(temp1, denom);
+
+ temp0 = (v8i16) __msa_sat_u_h((v8u16) temp0, 7);
+ temp1 = (v8i16) __msa_sat_u_h((v8u16) temp1, 7);
+
+ res0 = (v4i32) __msa_pckev_b((v16i8) temp0, (v16i8) temp0);
+ res1 = (v4i32) __msa_pckev_b((v16i8) temp1, (v16i8) temp1);
+
+ data0 = __msa_copy_u_w(res0, 0);
+ data1 = __msa_copy_u_w(res1, 0);
+
+ STORE_WORD(data, data0);
+ data += stride;
+ STORE_WORD(data, data1);
+}
+
+static void avc_wgt_4x4multiple_msa(uint8_t *data,
+ int32_t stride,
+ int32_t height,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t offset_in)
+{
+ uint8_t cnt;
+ uint32_t data0, data1, data2, data3;
+ v16u8 zero = { 0 };
+ v16u8 src0, src1, src2, src3;
+ v8u16 temp0, temp1, temp2, temp3;
+ v8i16 wgt, denom, offset;
+
+ offset_in <<= (log2_denom);
+
+ if (log2_denom) {
+ offset_in += (1 << (log2_denom - 1));
+ }
+
+ wgt = __msa_fill_h(src_weight);
+ offset = __msa_fill_h(offset_in);
+ denom = __msa_fill_h(log2_denom);
+
+ for (cnt = height / 4; cnt--;) {
+ LOAD_4WORDS_WITH_STRIDE(data, stride, data0, data1, data2, data3);
+
+ src0 = (v16u8) __msa_fill_w(data0);
+ src1 = (v16u8) __msa_fill_w(data1);
+ src2 = (v16u8) __msa_fill_w(data2);
+ src3 = (v16u8) __msa_fill_w(data3);
+
+ ILVR_B_4VECS_UH(src0, src1, src2, src3, zero, zero, zero, zero,
+ temp0, temp1, temp2, temp3);
+
+ temp0 *= wgt;
+ temp1 *= wgt;
+ temp2 *= wgt;
+ temp3 *= wgt;
+
+ ADDS_S_H_4VECS_UH(temp0, offset, temp1, offset,
+ temp2, offset, temp3, offset,
+ temp0, temp1, temp2, temp3);
+
+ MAXI_S_H_4VECS_UH(temp0, temp1, temp2, temp3, 0);
+
+ SRL_H_4VECS_UH(temp0, temp1, temp2, temp3,
+ temp0, temp1, temp2, temp3, denom);
+
+ SAT_U_H_4VECS_UH(temp0, temp1, temp2, temp3, 7);
+
+ PCKEV_B_STORE_4_BYTES_4(temp0, temp1, temp2, temp3, data, stride);
+ data += (4 * stride);
+ }
+}
+
+static void avc_wgt_4width_msa(uint8_t *data,
+ int32_t stride,
+ int32_t height,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t offset_in)
+{
+ if (2 == height) {
+ avc_wgt_4x2_msa(data, stride, log2_denom, src_weight, offset_in);
+ } else {
+ avc_wgt_4x4multiple_msa(data, stride, height, log2_denom,
+ src_weight, offset_in);
+ }
+}
+
+static void avc_wgt_8width_msa(uint8_t *data,
+ int32_t stride,
+ int32_t height,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t offset_in)
+{
+ uint8_t cnt;
+ v16u8 zero = { 0 };
+ v16u8 src0, src1, src2, src3;
+ v8u16 src0_r, src1_r, src2_r, src3_r;
+ v8u16 temp0, temp1, temp2, temp3;
+ v8u16 wgt, denom, offset;
+
+ offset_in <<= (log2_denom);
+
+ if (log2_denom) {
+ offset_in += (1 << (log2_denom - 1));
+ }
+
+ wgt = (v8u16) __msa_fill_h(src_weight);
+ offset = (v8u16) __msa_fill_h(offset_in);
+ denom = (v8u16) __msa_fill_h(log2_denom);
+
+ for (cnt = height / 4; cnt--;) {
+ LOAD_4VECS_UB(data, stride, src0, src1, src2, src3);
+
+ ILVR_B_4VECS_UH(src0, src1, src2, src3, zero, zero, zero, zero,
+ src0_r, src1_r, src2_r, src3_r);
+
+ temp0 = wgt * src0_r;
+ temp1 = wgt * src1_r;
+ temp2 = wgt * src2_r;
+ temp3 = wgt * src3_r;
+
+ ADDS_S_H_4VECS_UH(temp0, offset, temp1, offset,
+ temp2, offset, temp3, offset,
+ temp0, temp1, temp2, temp3);
+
+ MAXI_S_H_4VECS_UH(temp0, temp1, temp2, temp3, 0);
+
+ SRL_H_4VECS_UH(temp0, temp1, temp2, temp3,
+ temp0, temp1, temp2, temp3, denom);
+
+ SAT_U_H_4VECS_UH(temp0, temp1, temp2, temp3, 7);
+
+ PCKEV_B_STORE_8_BYTES_4(temp0, temp1, temp2, temp3, data, stride);
+ data += (4 * stride);
+ }
+}
+
+static void avc_wgt_16width_msa(uint8_t *data,
+ int32_t stride,
+ int32_t height,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t offset_in)
+{
+ uint8_t cnt;
+ v16u8 zero = { 0 };
+ v16u8 src0, src1, src2, src3;
+ v16u8 dst0, dst1, dst2, dst3;
+ v8u16 src0_l, src1_l, src2_l, src3_l;
+ v8u16 src0_r, src1_r, src2_r, src3_r;
+ v8u16 temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ v8u16 wgt, denom, offset;
+
+ offset_in <<= (log2_denom);
+
+ if (log2_denom) {
+ offset_in += (1 << (log2_denom - 1));
+ }
+
+ wgt = (v8u16) __msa_fill_h(src_weight);
+ offset = (v8u16) __msa_fill_h(offset_in);
+ denom = (v8u16) __msa_fill_h(log2_denom);
+
+ for (cnt = height / 4; cnt--;) {
+ LOAD_4VECS_UB(data, stride, src0, src1, src2, src3);
+
+ ILV_B_LRLR_UH(src0, zero, src1, zero, src0_l, src0_r, src1_l, src1_r);
+ ILV_B_LRLR_UH(src2, zero, src3, zero, src2_l, src2_r, src3_l, src3_r);
+
+ temp0 = wgt * src0_r;
+ temp1 = wgt * src0_l;
+ temp2 = wgt * src1_r;
+ temp3 = wgt * src1_l;
+ temp4 = wgt * src2_r;
+ temp5 = wgt * src2_l;
+ temp6 = wgt * src3_r;
+ temp7 = wgt * src3_l;
+
+ ADDS_S_H_4VECS_UH(temp0, offset, temp1, offset,
+ temp2, offset, temp3, offset,
+ temp0, temp1, temp2, temp3);
+
+ ADDS_S_H_4VECS_UH(temp4, offset, temp5, offset,
+ temp6, offset, temp7, offset,
+ temp4, temp5, temp6, temp7);
+
+ MAXI_S_H_4VECS_UH(temp0, temp1, temp2, temp3, 0);
+ MAXI_S_H_4VECS_UH(temp4, temp5, temp6, temp7, 0);
+
+ SRL_H_4VECS_UH(temp0, temp1, temp2, temp3,
+ temp0, temp1, temp2, temp3, denom);
+
+ SRL_H_4VECS_UH(temp4, temp5, temp6, temp7,
+ temp4, temp5, temp6, temp7, denom);
+
+ SAT_U_H_4VECS_UH(temp0, temp1, temp2, temp3, 7);
+ SAT_U_H_4VECS_UH(temp4, temp5, temp6, temp7, 7);
+
+ PCKEV_B_4VECS_UB(temp1, temp3, temp5, temp7, temp0, temp2, temp4, temp6,
+ dst0, dst1, dst2, dst3);
+
+ STORE_4VECS_UB(data, stride, dst0, dst1, dst2, dst3);
+ data += 4 * stride;
+ }
+}
+
+static void avc_biwgt_4x2_msa(uint8_t *src,
+ int32_t src_stride,
+ uint8_t *dst,
+ int32_t dst_stride,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t dst_weight,
+ int32_t offset_in)
+{
+ uint32_t load0, load1, out0, out1;
+ v16i8 src_wgt, dst_wgt, wgt;
+ v16i8 src0, src1, dst0, dst1;
+ v8i16 temp0, temp1, denom, offset, add_val;
+ int32_t val = 128 * (src_weight + dst_weight);
+
+ offset_in = ((offset_in + 1) | 1) << log2_denom;
+
+ src_wgt = __msa_fill_b(src_weight);
+ dst_wgt = __msa_fill_b(dst_weight);
+ offset = __msa_fill_h(offset_in);
+ denom = __msa_fill_h(log2_denom + 1);
+ add_val = __msa_fill_h(val);
+ offset += add_val;
+
+ wgt = __msa_ilvev_b(dst_wgt, src_wgt);
+
+ load0 = LOAD_WORD(src);
+ src += src_stride;
+ load1 = LOAD_WORD(src);
+
+ src0 = (v16i8) __msa_fill_w(load0);
+ src1 = (v16i8) __msa_fill_w(load1);
+
+ load0 = LOAD_WORD(dst);
+ load1 = LOAD_WORD(dst + dst_stride);
+
+ dst0 = (v16i8) __msa_fill_w(load0);
+ dst1 = (v16i8) __msa_fill_w(load1);
+
+ XORI_B_4VECS_SB(src0, src1, dst0, dst1, src0, src1, dst0, dst1, 128);
+
+ ILVR_B_2VECS_SH(src0, src1, dst0, dst1, temp0, temp1);
+
+ temp0 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp0);
+ temp1 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp1);
+
+ temp0 >>= denom;
+ temp1 >>= denom;
+
+ temp0 = CLIP_UNSIGNED_CHAR_H(temp0);
+ temp1 = CLIP_UNSIGNED_CHAR_H(temp1);
+
+ dst0 = __msa_pckev_b((v16i8) temp0, (v16i8) temp0);
+ dst1 = __msa_pckev_b((v16i8) temp1, (v16i8) temp1);
+
+ out0 = __msa_copy_u_w((v4i32) dst0, 0);
+ out1 = __msa_copy_u_w((v4i32) dst1, 0);
+
+ STORE_WORD(dst, out0);
+ dst += dst_stride;
+ STORE_WORD(dst, out1);
+}
+
+static void avc_biwgt_4x4multiple_msa(uint8_t *src,
+ int32_t src_stride,
+ uint8_t *dst,
+ int32_t dst_stride,
+ int32_t height,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t dst_weight,
+ int32_t offset_in)
+{
+ uint8_t cnt;
+ uint32_t load0, load1, load2, load3;
+ v16i8 src_wgt, dst_wgt, wgt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 dst0, dst1, dst2, dst3;
+ v8i16 temp0, temp1, temp2, temp3;
+ v8i16 denom, offset, add_val;
+ int32_t val = 128 * (src_weight + dst_weight);
+
+ offset_in = ((offset_in + 1) | 1) << log2_denom;
+
+ src_wgt = __msa_fill_b(src_weight);
+ dst_wgt = __msa_fill_b(dst_weight);
+ offset = __msa_fill_h(offset_in);
+ denom = __msa_fill_h(log2_denom + 1);
+ add_val = __msa_fill_h(val);
+ offset += add_val;
+
+ wgt = __msa_ilvev_b(dst_wgt, src_wgt);
+
+ for (cnt = height / 4; cnt--;) {
+ LOAD_4WORDS_WITH_STRIDE(src, src_stride, load0, load1, load2, load3);
+ src += (4 * src_stride);
+
+ src0 = (v16i8) __msa_fill_w(load0);
+ src1 = (v16i8) __msa_fill_w(load1);
+ src2 = (v16i8) __msa_fill_w(load2);
+ src3 = (v16i8) __msa_fill_w(load3);
+
+ LOAD_4WORDS_WITH_STRIDE(dst, dst_stride, load0, load1, load2, load3);
+
+ dst0 = (v16i8) __msa_fill_w(load0);
+ dst1 = (v16i8) __msa_fill_w(load1);
+ dst2 = (v16i8) __msa_fill_w(load2);
+ dst3 = (v16i8) __msa_fill_w(load3);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ XORI_B_4VECS_SB(dst0, dst1, dst2, dst3, dst0, dst1, dst2, dst3, 128);
+
+ ILVR_B_4VECS_SH(src0, src1, src2, src3, dst0, dst1, dst2, dst3,
+ temp0, temp1, temp2, temp3);
+
+ temp0 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp0);
+ temp1 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp1);
+ temp2 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp2);
+ temp3 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp3);
+
+ SRA_4VECS(temp0, temp1, temp2, temp3,
+ temp0, temp1, temp2, temp3, denom);
+
+ temp0 = CLIP_UNSIGNED_CHAR_H(temp0);
+ temp1 = CLIP_UNSIGNED_CHAR_H(temp1);
+ temp2 = CLIP_UNSIGNED_CHAR_H(temp2);
+ temp3 = CLIP_UNSIGNED_CHAR_H(temp3);
+
+ PCKEV_B_STORE_4_BYTES_4(temp0, temp1, temp2, temp3, dst, dst_stride);
+ dst += (4 * dst_stride);
+ }
+}
+
+static void avc_biwgt_4width_msa(uint8_t *src,
+ int32_t src_stride,
+ uint8_t *dst,
+ int32_t dst_stride,
+ int32_t height,
+ int32_t log2_denom,
+ int32_t src_weight,
+ int32_t dst_weight,
+ int32_t offset_in)
+{
+ if (2 == height) {
+ avc_biwgt_4x2_msa(src, src_stride, dst, dst_stride,
+ log2_denom, src_weight, dst_weight,
+ offset_in);
+ } else {
+ avc_biwgt_4x4multiple_msa(src, src_stride, dst, dst_stride,
+ height, log2_denom, src_weight,
+ dst_weight, offset_in);
+ }
+}
+
+static void avc_biwgt_8width_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height, int32_t log2_denom,
+ int32_t src_weight, int32_t dst_weight,
+ int32_t offset_in)
+{
+ uint8_t cnt;
+ v16i8 src_wgt, dst_wgt, wgt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 dst0, dst1, dst2, dst3;
+ v8i16 temp0, temp1, temp2, temp3;
+ v8i16 denom, offset, add_val;
+ int32_t val = 128 * (src_weight + dst_weight);
+
+ offset_in = ((offset_in + 1) | 1) << log2_denom;
+
+ src_wgt = __msa_fill_b(src_weight);
+ dst_wgt = __msa_fill_b(dst_weight);
+ offset = __msa_fill_h(offset_in);
+ denom = __msa_fill_h(log2_denom + 1);
+ add_val = __msa_fill_h(val);
+ offset += add_val;
+
+ wgt = __msa_ilvev_b(dst_wgt, src_wgt);
+
+ for (cnt = height / 4; cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ LOAD_4VECS_SB(dst, dst_stride, dst0, dst1, dst2, dst3);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ XORI_B_4VECS_SB(dst0, dst1, dst2, dst3, dst0, dst1, dst2, dst3, 128);
+
+ ILVR_B_4VECS_SH(src0, src1, src2, src3, dst0, dst1, dst2, dst3,
+ temp0, temp1, temp2, temp3);
+
+ temp0 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp0);
+ temp1 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp1);
+ temp2 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp2);
+ temp3 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp3);
+
+ SRA_4VECS(temp0, temp1, temp2, temp3,
+ temp0, temp1, temp2, temp3, denom);
+
+ temp0 = CLIP_UNSIGNED_CHAR_H(temp0);
+ temp1 = CLIP_UNSIGNED_CHAR_H(temp1);
+ temp2 = CLIP_UNSIGNED_CHAR_H(temp2);
+ temp3 = CLIP_UNSIGNED_CHAR_H(temp3);
+
+ PCKEV_B_STORE_8_BYTES_4(temp0, temp1, temp2, temp3, dst, dst_stride);
+ dst += 4 * dst_stride;
+ }
+}
+
+static void avc_biwgt_16width_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height, int32_t log2_denom,
+ int32_t src_weight, int32_t dst_weight,
+ int32_t offset_in)
+{
+ uint8_t cnt;
+ v16i8 src_wgt, dst_wgt, wgt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 dst0, dst1, dst2, dst3;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7;
+ v8i16 temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ v8i16 denom, offset, add_val;
+ int32_t val = 128 * (src_weight + dst_weight);
+
+ offset_in = ((offset_in + 1) | 1) << log2_denom;
+
+ src_wgt = __msa_fill_b(src_weight);
+ dst_wgt = __msa_fill_b(dst_weight);
+ offset = __msa_fill_h(offset_in);
+ denom = __msa_fill_h(log2_denom + 1);
+ add_val = __msa_fill_h(val);
+ offset += add_val;
+
+ wgt = __msa_ilvev_b(dst_wgt, src_wgt);
+
+ for (cnt = height / 4; cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ LOAD_4VECS_SB(dst, dst_stride, dst0, dst1, dst2, dst3);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ XORI_B_4VECS_SB(dst0, dst1, dst2, dst3, dst0, dst1, dst2, dst3, 128);
+
+ ILV_B_LRLR_SB(src0, dst0, src1, dst1, vec1, vec0, vec3, vec2);
+ ILV_B_LRLR_SB(src2, dst2, src3, dst3, vec5, vec4, vec7, vec6);
+
+ temp0 = __msa_dpadd_s_h(offset, wgt, vec0);
+ temp1 = __msa_dpadd_s_h(offset, wgt, vec1);
+ temp2 = __msa_dpadd_s_h(offset, wgt, vec2);
+ temp3 = __msa_dpadd_s_h(offset, wgt, vec3);
+ temp4 = __msa_dpadd_s_h(offset, wgt, vec4);
+ temp5 = __msa_dpadd_s_h(offset, wgt, vec5);
+ temp6 = __msa_dpadd_s_h(offset, wgt, vec6);
+ temp7 = __msa_dpadd_s_h(offset, wgt, vec7);
+
+ SRA_4VECS(temp0, temp1, temp2, temp3,
+ temp0, temp1, temp2, temp3, denom);
+ SRA_4VECS(temp4, temp5, temp6, temp7,
+ temp4, temp5, temp6, temp7, denom);
+
+ temp0 = CLIP_UNSIGNED_CHAR_H(temp0);
+ temp1 = CLIP_UNSIGNED_CHAR_H(temp1);
+ temp2 = CLIP_UNSIGNED_CHAR_H(temp2);
+ temp3 = CLIP_UNSIGNED_CHAR_H(temp3);
+ temp4 = CLIP_UNSIGNED_CHAR_H(temp4);
+ temp5 = CLIP_UNSIGNED_CHAR_H(temp5);
+ temp6 = CLIP_UNSIGNED_CHAR_H(temp6);
+ temp7 = CLIP_UNSIGNED_CHAR_H(temp7);
+
+ PCKEV_B_4VECS_SB(temp1, temp3, temp5, temp7, temp0, temp2, temp4, temp6,
+ dst0, dst1, dst2, dst3);
+
+ STORE_4VECS_SB(dst, dst_stride, dst0, dst1, dst2, dst3);
+ dst += 4 * dst_stride;
+ }
+}
+
+#define AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(p3_or_q3_org_in, p0_or_q0_org_in, \
+ q3_or_p3_org_in, p1_or_q1_org_in, \
+ p2_or_q2_org_in, q1_or_p1_org_in, \
+ p0_or_q0_out, \
+ p1_or_q1_out, p2_or_q2_out) \
+{ \
+ v8i16 threshold; \
+ v8i16 const3 = __msa_ldi_h(3); \
+ \
+ threshold = (p0_or_q0_org_in) + (q3_or_p3_org_in); \
+ threshold += (p1_or_q1_org_in); \
+ \
+ (p0_or_q0_out) = threshold << 1; \
+ (p0_or_q0_out) += (p2_or_q2_org_in); \
+ (p0_or_q0_out) += (q1_or_p1_org_in); \
+ (p0_or_q0_out) = __msa_srari_h((p0_or_q0_out), 3); \
+ \
+ (p1_or_q1_out) = (p2_or_q2_org_in) + threshold; \
+ (p1_or_q1_out) = __msa_srari_h((p1_or_q1_out), 2); \
+ \
+ (p2_or_q2_out) = (p2_or_q2_org_in) * const3; \
+ (p2_or_q2_out) += (p3_or_q3_org_in); \
+ (p2_or_q2_out) += (p3_or_q3_org_in); \
+ (p2_or_q2_out) += threshold; \
+ (p2_or_q2_out) = __msa_srari_h((p2_or_q2_out), 3); \
+}
+
+/* data[-u32_img_width] = (uint8_t)((2 * p1 + p0 + q1 + 2) >> 2); */
+#define AVC_LOOP_FILTER_P0_OR_Q0(p0_or_q0_org_in, q1_or_p1_org_in, \
+ p1_or_q1_org_in, p0_or_q0_out) \
+{ \
+ (p0_or_q0_out) = (p0_or_q0_org_in) + (q1_or_p1_org_in); \
+ (p0_or_q0_out) += (p1_or_q1_org_in); \
+ (p0_or_q0_out) += (p1_or_q1_org_in); \
+ (p0_or_q0_out) = __msa_srari_h((p0_or_q0_out), 2); \
+}
+
+#define AVC_LOOP_FILTER_P1_OR_Q1(p0_or_q0_org_in, q0_or_p0_org_in, \
+ p1_or_q1_org_in, p2_or_q2_org_in, \
+ negate_tc_in, tc_in, p1_or_q1_out) \
+{ \
+ v8i16 clip3, temp; \
+ \
+ clip3 = (v8i16) __msa_aver_u_h((v8u16) (p0_or_q0_org_in), \
+ (v8u16) (q0_or_p0_org_in)); \
+ temp = (p1_or_q1_org_in) << 1; \
+ clip3 = clip3 - temp; \
+ clip3 = __msa_ave_s_h((p2_or_q2_org_in), clip3); \
+ clip3 = CLIP_MIN_TO_MAX_H(clip3, negate_tc_in, tc_in); \
+ (p1_or_q1_out) = (p1_or_q1_org_in) + clip3; \
+}
+
+#define AVC_LOOP_FILTER_P0Q0(q0_or_p0_org_in, p0_or_q0_org_in, \
+ p1_or_q1_org_in, q1_or_p1_org_in, \
+ negate_threshold_in, threshold_in, \
+ p0_or_q0_out, q0_or_p0_out) \
+{ \
+ v8i16 q0_sub_p0, p1_sub_q1, delta; \
+ \
+ q0_sub_p0 = (q0_or_p0_org_in) - (p0_or_q0_org_in); \
+ p1_sub_q1 = (p1_or_q1_org_in) - (q1_or_p1_org_in); \
+ q0_sub_p0 <<= 2; \
+ p1_sub_q1 += 4; \
+ delta = q0_sub_p0 + p1_sub_q1; \
+ delta >>= 3; \
+ \
+ delta = CLIP_MIN_TO_MAX_H(delta, negate_threshold_in, \
+ threshold_in); \
+ \
+ (p0_or_q0_out) = (p0_or_q0_org_in) + delta; \
+ p0_or_q0_out = CLIP_UNSIGNED_CHAR_H(p0_or_q0_out); \
+ \
+ (q0_or_p0_out) = (q0_or_p0_org_in) - delta; \
+ q0_or_p0_out = CLIP_UNSIGNED_CHAR_H(q0_or_p0_out); \
+}
+
+#define AVC_LPF_H_CHROMA_422(src, stride, tc_val, alpha, beta, res) \
+{ \
+ uint32_t load0, load1, load2, load3; \
+ v16u8 src0 = { 0 }; \
+ v16u8 src1 = { 0 }; \
+ v16u8 src2 = { 0 }; \
+ v16u8 src3 = { 0 }; \
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0; \
+ v16u8 is_less_than, is_less_than_alpha, is_less_than_beta; \
+ v8i16 tc, q0_sub_p0, p1_sub_q1, delta; \
+ v8i16 res0_r, res1_r; \
+ v16i8 zeros = { 0 }; \
+ v16u8 res0, res1; \
+ \
+ LOAD_4WORDS_WITH_STRIDE((src - 2), stride, \
+ load0, load1, load2, load3); \
+ \
+ src0 = (v16u8) __msa_insert_w((v4i32) src0, 0, load0); \
+ src1 = (v16u8) __msa_insert_w((v4i32) src1, 0, load1); \
+ src2 = (v16u8) __msa_insert_w((v4i32) src2, 0, load2); \
+ src3 = (v16u8) __msa_insert_w((v4i32) src3, 0, load3); \
+ \
+ TRANSPOSE4x4_B_UB(src0, src1, src2, src3, \
+ src0, src1, src2, src3); \
+ \
+ p0_asub_q0 = __msa_asub_u_b(src2, src1); \
+ p1_asub_p0 = __msa_asub_u_b(src1, src0); \
+ q1_asub_q0 = __msa_asub_u_b(src2, src3); \
+ \
+ tc = __msa_fill_h(tc_val); \
+ \
+ is_less_than_alpha = (p0_asub_q0 < alpha); \
+ is_less_than_beta = (p1_asub_p0 < beta); \
+ is_less_than = is_less_than_alpha & is_less_than_beta; \
+ is_less_than_beta = (q1_asub_q0 < beta); \
+ is_less_than = is_less_than_beta & is_less_than; \
+ \
+ q0_sub_p0 = (v8i16) __msa_ilvr_b((v16i8) src2, (v16i8) src1); \
+ p1_sub_q1 = (v8i16) __msa_ilvr_b((v16i8) src0, (v16i8) src3); \
+ \
+ q0_sub_p0 = __msa_hsub_u_h((v16u8) q0_sub_p0, (v16u8) q0_sub_p0); \
+ p1_sub_q1 = __msa_hsub_u_h((v16u8) p1_sub_q1, (v16u8) p1_sub_q1); \
+ \
+ q0_sub_p0 <<= 2; \
+ delta = q0_sub_p0 + p1_sub_q1; \
+ delta = __msa_srari_h(delta, 3); \
+ \
+ delta = CLIP_MIN_TO_MAX_H(delta, -tc, tc); \
+ \
+ res0_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) src1); \
+ res1_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) src2); \
+ \
+ res0_r += delta; \
+ res1_r -= delta; \
+ \
+ res0_r = CLIP_UNSIGNED_CHAR_H(res0_r); \
+ res1_r = CLIP_UNSIGNED_CHAR_H(res1_r); \
+ \
+ res0 = (v16u8) __msa_pckev_b((v16i8) res0_r, (v16i8) res0_r); \
+ res1 = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res1_r); \
+ \
+ res0 = __msa_bmnz_v(src1, res0, is_less_than); \
+ res1 = __msa_bmnz_v(src2, res1, is_less_than); \
+ \
+ res = (v16u8) __msa_ilvr_b((v16i8) res1, (v16i8) res0); \
+}
+
+#define TRANSPOSE2x4_B_UB(in0, in1, \
+ out0, out1, out2, out3) \
+{ \
+ v16i8 zero_m = { 0 }; \
+ \
+ out0 = (v16u8) __msa_ilvr_b((v16i8) in1, (v16i8) in0); \
+ \
+ out1 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out0, 2); \
+ out2 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out1, 2); \
+ out3 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out2, 2); \
+}
+
+#define AVC_LPF_H_2BYTE_CHROMA_422(src, stride, \
+ tc_val, alpha, beta, res) \
+{ \
+ uint32_t load0, load1; \
+ v16u8 src0 = { 0 }; \
+ v16u8 src1 = { 0 }; \
+ v16u8 src2 = { 0 }; \
+ v16u8 src3 = { 0 }; \
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0; \
+ v16u8 is_less_than, is_less_than_alpha, is_less_than_beta; \
+ v8i16 tc, q0_sub_p0, p1_sub_q1, delta; \
+ v8i16 res0_r, res1_r; \
+ v16i8 zeros = { 0 }; \
+ v16u8 res0, res1; \
+ \
+ load0 = LOAD_WORD(src - 2); \
+ load1 = LOAD_WORD(src - 2 + stride); \
+ \
+ src0 = (v16u8) __msa_insert_w((v4i32) src0, 0, load0); \
+ src1 = (v16u8) __msa_insert_w((v4i32) src1, 0, load1); \
+ \
+ TRANSPOSE2x4_B_UB(src0, src1, \
+ src0, src1, src2, src3); \
+ \
+ p0_asub_q0 = __msa_asub_u_b(src2, src1); \
+ p1_asub_p0 = __msa_asub_u_b(src1, src0); \
+ q1_asub_q0 = __msa_asub_u_b(src2, src3); \
+ \
+ tc = __msa_fill_h(tc_val); \
+ \
+ is_less_than_alpha = (p0_asub_q0 < alpha); \
+ is_less_than_beta = (p1_asub_p0 < beta); \
+ is_less_than = is_less_than_alpha & is_less_than_beta; \
+ is_less_than_beta = (q1_asub_q0 < beta); \
+ is_less_than = is_less_than_beta & is_less_than; \
+ \
+ q0_sub_p0 = (v8i16) __msa_ilvr_b((v16i8) src2, (v16i8) src1); \
+ p1_sub_q1 = (v8i16) __msa_ilvr_b((v16i8) src0, (v16i8) src3); \
+ \
+ q0_sub_p0 = __msa_hsub_u_h((v16u8) q0_sub_p0, (v16u8) q0_sub_p0); \
+ p1_sub_q1 = __msa_hsub_u_h((v16u8) p1_sub_q1, (v16u8) p1_sub_q1); \
+ \
+ q0_sub_p0 <<= 2; \
+ delta = q0_sub_p0 + p1_sub_q1; \
+ delta = __msa_srari_h(delta, 3); \
+ \
+ delta = CLIP_MIN_TO_MAX_H(delta, -tc, tc); \
+ \
+ res0_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) src1); \
+ res1_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) src2); \
+ \
+ res0_r += delta; \
+ res1_r -= delta; \
+ \
+ res0_r = CLIP_UNSIGNED_CHAR_H(res0_r); \
+ res1_r = CLIP_UNSIGNED_CHAR_H(res1_r); \
+ \
+ res0 = (v16u8) __msa_pckev_b((v16i8) res0_r, (v16i8) res0_r); \
+ res1 = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res1_r); \
+ \
+ res0 = __msa_bmnz_v(src1, res0, is_less_than); \
+ res1 = __msa_bmnz_v(src2, res1, is_less_than); \
+ \
+ res = (v16u8) __msa_ilvr_b((v16i8) res1, (v16i8) res0); \
+}
+
+static void avc_loopfilter_luma_intra_edge_hor_msa(uint8_t *data,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ v16u8 p2_asub_p0, q2_asub_q0, p0_asub_q0;
+ v16u8 alpha, beta;
+ v16u8 is_less_than, is_less_than_beta, negate_is_less_than_beta;
+ v16u8 p2, p1, p0, q0, q1, q2;
+ v16u8 p3_org, p2_org, p1_org, p0_org, q0_org, q1_org, q2_org, q3_org;
+ v8i16 p1_org_r, p0_org_r, q0_org_r, q1_org_r;
+ v8i16 p1_org_l, p0_org_l, q0_org_l, q1_org_l;
+ v8i16 p2_r = { 0 };
+ v8i16 p1_r = { 0 };
+ v8i16 p0_r = { 0 };
+ v8i16 q0_r = { 0 };
+ v8i16 q1_r = { 0 };
+ v8i16 q2_r = { 0 };
+ v8i16 p2_l = { 0 };
+ v8i16 p1_l = { 0 };
+ v8i16 p0_l = { 0 };
+ v8i16 q0_l = { 0 };
+ v8i16 q1_l = { 0 };
+ v8i16 q2_l = { 0 };
+ v16u8 tmp_flag;
+ v16i8 zero = { 0 };
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ p1_org = LOAD_UB(data - (img_width << 1));
+ p0_org = LOAD_UB(data - img_width);
+ q0_org = LOAD_UB(data);
+ q1_org = LOAD_UB(data + img_width);
+
+ {
+ v16u8 p1_asub_p0, q1_asub_q0, is_less_than_alpha;
+
+ p0_asub_q0 = __msa_asub_u_b(p0_org, q0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_org, p0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_org, q0_org);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+ }
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ q2_org = LOAD_UB(data + (2 * img_width));
+ p3_org = LOAD_UB(data - (img_width << 2));
+ p2_org = LOAD_UB(data - (3 * img_width));
+
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_org);
+
+ p1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p1_org);
+ p0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p0_org);
+ q0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q0_org);
+
+ tmp_flag = alpha >> 2;
+ tmp_flag = tmp_flag + 2;
+ tmp_flag = (p0_asub_q0 < tmp_flag);
+
+ p2_asub_p0 = __msa_asub_u_b(p2_org, p0_org);
+ is_less_than_beta = (p2_asub_p0 < beta);
+ is_less_than_beta = is_less_than_beta & tmp_flag;
+
+ negate_is_less_than_beta = __msa_xori_b(is_less_than_beta, 0xff);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+ negate_is_less_than_beta = negate_is_less_than_beta & is_less_than;
+
+ {
+ v8u16 is_less_than_beta_l, is_less_than_beta_r;
+
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_org);
+
+ is_less_than_beta_r =
+ (v8u16) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_r)) {
+ v8i16 p3_org_r;
+
+ p3_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p3_org);
+ p2_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(p3_org_r, p0_org_r,
+ q0_org_r, p1_org_r,
+ p2_r, q1_org_r,
+ p0_r, p1_r, p2_r);
+ }
+
+ q1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q1_org);
+
+ is_less_than_beta_l =
+ (v8u16) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_l)) {
+ v8i16 p3_org_l;
+
+ p3_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p3_org);
+ p2_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(p3_org_l, p0_org_l,
+ q0_org_l, p1_org_l,
+ p2_l, q1_org_l,
+ p0_l, p1_l, p2_l);
+ }
+ }
+
+ /* combine and store */
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ p0 = (v16u8) __msa_pckev_b((v16i8) p0_l, (v16i8) p0_r);
+ p1 = (v16u8) __msa_pckev_b((v16i8) p1_l, (v16i8) p1_r);
+ p2 = (v16u8) __msa_pckev_b((v16i8) p2_l, (v16i8) p2_r);
+
+ p0_org = __msa_bmnz_v(p0_org, p0, is_less_than_beta);
+ p1_org = __msa_bmnz_v(p1_org, p1, is_less_than_beta);
+ p2_org = __msa_bmnz_v(p2_org, p2, is_less_than_beta);
+
+ STORE_UB(p1_org, data - (2 * img_width));
+ STORE_UB(p2_org, data - (3 * img_width));
+ }
+
+ {
+ v8u16 negate_is_less_than_beta_r, negate_is_less_than_beta_l;
+
+ negate_is_less_than_beta_r =
+ (v8u16) __msa_sldi_b((v16i8) negate_is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v((v16u8) negate_is_less_than_beta_r)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(p0_org_r, q1_org_r, p1_org_r, p0_r);
+ }
+
+ negate_is_less_than_beta_l =
+ (v8u16) __msa_sldi_b(zero, (v16i8) negate_is_less_than_beta, 8);
+ if (!__msa_test_bz_v((v16u8) negate_is_less_than_beta_l)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(p0_org_l, q1_org_l, p1_org_l, p0_l);
+ }
+ }
+
+ /* combine */
+ if (!__msa_test_bz_v(negate_is_less_than_beta)) {
+ p0 = (v16u8) __msa_pckev_b((v16i8) p0_l, (v16i8) p0_r);
+ p0_org = __msa_bmnz_v(p0_org, p0, negate_is_less_than_beta);
+ }
+
+ STORE_UB(p0_org, data - img_width);
+
+ /* if (tmpFlag && (unsigned)ABS(q2-q0) < thresholds->beta_in) */
+
+ q3_org = LOAD_UB(data + (3 * img_width));
+
+ q2_asub_q0 = __msa_asub_u_b(q2_org, q0_org);
+ is_less_than_beta = (q2_asub_q0 < beta);
+ is_less_than_beta = is_less_than_beta & tmp_flag;
+ negate_is_less_than_beta = __msa_xori_b(is_less_than_beta, 0xff);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+ negate_is_less_than_beta = negate_is_less_than_beta & is_less_than;
+
+ {
+ v8u16 is_less_than_beta_l, is_less_than_beta_r;
+
+ is_less_than_beta_r =
+ (v8u16) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_r)) {
+ v8i16 q3_org_r;
+
+ q3_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q3_org);
+ q2_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(q3_org_r, q0_org_r,
+ p0_org_r, q1_org_r,
+ q2_r, p1_org_r,
+ q0_r, q1_r, q2_r);
+ }
+
+ is_less_than_beta_l =
+ (v8u16) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_l)) {
+ v8i16 q3_org_l;
+
+ q3_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q3_org);
+ q2_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(q3_org_l, q0_org_l,
+ p0_org_l, q1_org_l,
+ q2_l, p1_org_l,
+ q0_l, q1_l, q2_l);
+ }
+ }
+
+ /* combine and store */
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ q0 = (v16u8) __msa_pckev_b((v16i8) q0_l, (v16i8) q0_r);
+ q1 = (v16u8) __msa_pckev_b((v16i8) q1_l, (v16i8) q1_r);
+ q2 = (v16u8) __msa_pckev_b((v16i8) q2_l, (v16i8) q2_r);
+
+ q0_org = __msa_bmnz_v(q0_org, q0, is_less_than_beta);
+ q1_org = __msa_bmnz_v(q1_org, q1, is_less_than_beta);
+ q2_org = __msa_bmnz_v(q2_org, q2, is_less_than_beta);
+
+ STORE_UB(q1_org, data + img_width);
+ STORE_UB(q2_org, data + 2 * img_width);
+ }
+
+ {
+ v8u16 negate_is_less_than_beta_r, negate_is_less_than_beta_l;
+
+ negate_is_less_than_beta_r =
+ (v8u16) __msa_sldi_b((v16i8) negate_is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v((v16u8) negate_is_less_than_beta_r)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(q0_org_r, p1_org_r, q1_org_r, q0_r);
+ }
+
+ negate_is_less_than_beta_l =
+ (v8u16) __msa_sldi_b(zero, (v16i8) negate_is_less_than_beta, 8);
+ if (!__msa_test_bz_v((v16u8) negate_is_less_than_beta_l)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(q0_org_l, p1_org_l, q1_org_l, q0_l);
+ }
+ }
+
+ /* combine */
+ if (!__msa_test_bz_v(negate_is_less_than_beta)) {
+ q0 = (v16u8) __msa_pckev_b((v16i8) q0_l, (v16i8) q0_r);
+ q0_org = __msa_bmnz_v(q0_org, q0, negate_is_less_than_beta);
+ }
+
+ STORE_UB(q0_org, data);
+ }
+}
+
+static void avc_loopfilter_luma_intra_edge_ver_msa(uint8_t *data,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ uint8_t *src;
+ v16u8 alpha, beta, p0_asub_q0;
+ v16u8 is_less_than_alpha, is_less_than;
+ v16u8 is_less_than_beta, negate_is_less_than_beta;
+ v8i16 p2_r = { 0 };
+ v8i16 p1_r = { 0 };
+ v8i16 p0_r = { 0 };
+ v8i16 q0_r = { 0 };
+ v8i16 q1_r = { 0 };
+ v8i16 q2_r = { 0 };
+ v8i16 p2_l = { 0 };
+ v8i16 p1_l = { 0 };
+ v8i16 p0_l = { 0 };
+ v8i16 q0_l = { 0 };
+ v8i16 q1_l = { 0 };
+ v8i16 q2_l = { 0 };
+ v16u8 p3_org, p2_org, p1_org, p0_org, q0_org, q1_org, q2_org, q3_org;
+ v8i16 p1_org_r, p0_org_r, q0_org_r, q1_org_r;
+ v8i16 p1_org_l, p0_org_l, q0_org_l, q1_org_l;
+ v16i8 zero = { 0 };
+ v16u8 tmp_flag;
+
+ src = data - 4;
+
+ {
+ v16u8 row0, row1, row2, row3, row4, row5, row6, row7;
+ v16u8 row8, row9, row10, row11, row12, row13, row14, row15;
+
+ LOAD_8VECS_UB(src, img_width,
+ row0, row1, row2, row3, row4, row5, row6, row7);
+ LOAD_8VECS_UB(src + (8 * img_width), img_width,
+ row8, row9, row10, row11, row12, row13, row14, row15);
+
+ TRANSPOSE16x8_B_UB(row0, row1, row2, row3, row4, row5, row6, row7,
+ row8, row9, row10, row11, row12, row13, row14, row15,
+ p3_org, p2_org, p1_org, p0_org,
+ q0_org, q1_org, q2_org, q3_org);
+ }
+
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_org);
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_org);
+
+ p1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p1_org);
+ p0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p0_org);
+ q0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q0_org);
+ q1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q1_org);
+
+ /* if ( ((unsigned)ABS(p0-q0) < thresholds->alpha_in) &&
+ ((unsigned)ABS(p1-p0) < thresholds->beta_in) &&
+ ((unsigned)ABS(q1-q0) < thresholds->beta_in) ) */
+ {
+ v16u8 p1_asub_p0, q1_asub_q0;
+
+ p0_asub_q0 = __msa_asub_u_b(p0_org, q0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_org, p0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_org, q0_org);
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+ }
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ tmp_flag = alpha >> 2;
+ tmp_flag = tmp_flag + 2;
+ tmp_flag = (p0_asub_q0 < tmp_flag);
+
+ {
+ v16u8 p2_asub_p0;
+
+ p2_asub_p0 = __msa_asub_u_b(p2_org, p0_org);
+ is_less_than_beta = (p2_asub_p0 < beta);
+ }
+
+ is_less_than_beta = tmp_flag & is_less_than_beta;
+
+ negate_is_less_than_beta = __msa_xori_b(is_less_than_beta, 0xff);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+ negate_is_less_than_beta = negate_is_less_than_beta & is_less_than;
+
+ /* right */
+ {
+ v16u8 is_less_than_beta_r;
+
+ is_less_than_beta_r =
+ (v16u8) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_r)) {
+ v8i16 p3_org_r;
+
+ p3_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p3_org);
+ p2_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(p3_org_r, p0_org_r,
+ q0_org_r, p1_org_r,
+ p2_r, q1_org_r,
+ p0_r, p1_r, p2_r);
+ }
+ }
+ /* left */
+ {
+ v16u8 is_less_than_beta_l;
+
+ is_less_than_beta_l =
+ (v16u8) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_l)) {
+ v8i16 p3_org_l;
+
+ p3_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p3_org);
+ p2_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(p3_org_l, p0_org_l,
+ q0_org_l, p1_org_l,
+ p2_l, q1_org_l,
+ p0_l, p1_l, p2_l);
+ }
+ }
+
+ /* combine and store */
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ v16u8 p0, p2, p1;
+
+ p0 = (v16u8) __msa_pckev_b((v16i8) p0_l, (v16i8) p0_r);
+ p1 = (v16u8) __msa_pckev_b((v16i8) p1_l, (v16i8) p1_r);
+ p2 = (v16u8) __msa_pckev_b((v16i8) p2_l, (v16i8) p2_r);
+
+ p0_org = __msa_bmnz_v(p0_org, p0, is_less_than_beta);
+ p1_org = __msa_bmnz_v(p1_org, p1, is_less_than_beta);
+ p2_org = __msa_bmnz_v(p2_org, p2, is_less_than_beta);
+ }
+
+ /* right */
+ {
+ v16u8 negate_is_less_than_beta_r;
+
+ negate_is_less_than_beta_r =
+ (v16u8) __msa_sldi_b((v16i8) negate_is_less_than_beta, zero, 8);
+
+ if (!__msa_test_bz_v(negate_is_less_than_beta_r)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(p0_org_r, q1_org_r, p1_org_r, p0_r);
+ }
+ }
+
+ /* left */
+ {
+ v16u8 negate_is_less_than_beta_l;
+
+ negate_is_less_than_beta_l =
+ (v16u8) __msa_sldi_b(zero, (v16i8) negate_is_less_than_beta, 8);
+ if (!__msa_test_bz_v(negate_is_less_than_beta_l)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(p0_org_l, q1_org_l, p1_org_l, p0_l);
+ }
+ }
+
+ if (!__msa_test_bz_v(negate_is_less_than_beta)) {
+ v16u8 p0;
+
+ p0 = (v16u8) __msa_pckev_b((v16i8) p0_l, (v16i8) p0_r);
+ p0_org = __msa_bmnz_v(p0_org, p0, negate_is_less_than_beta);
+ }
+
+ {
+ v16u8 q2_asub_q0;
+
+ q2_asub_q0 = __msa_asub_u_b(q2_org, q0_org);
+ is_less_than_beta = (q2_asub_q0 < beta);
+ }
+
+ is_less_than_beta = is_less_than_beta & tmp_flag;
+ negate_is_less_than_beta = __msa_xori_b(is_less_than_beta, 0xff);
+
+ is_less_than_beta = is_less_than_beta & is_less_than;
+ negate_is_less_than_beta = negate_is_less_than_beta & is_less_than;
+
+ /* right */
+ {
+ v16u8 is_less_than_beta_r;
+
+ is_less_than_beta_r =
+ (v16u8) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_r)) {
+ v8i16 q3_org_r;
+
+ q3_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q3_org);
+ q2_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(q3_org_r, q0_org_r,
+ p0_org_r, q1_org_r,
+ q2_r, p1_org_r,
+ q0_r, q1_r, q2_r);
+ }
+ }
+
+ /* left */
+ {
+ v16u8 is_less_than_beta_l;
+
+ is_less_than_beta_l =
+ (v16u8) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_l)) {
+ v8i16 q3_org_l;
+
+ q3_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q3_org);
+ q2_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P0P1P2_OR_Q0Q1Q2(q3_org_l, q0_org_l,
+ p0_org_l, q1_org_l,
+ q2_l, p1_org_l,
+ q0_l, q1_l, q2_l);
+ }
+ }
+
+ /* combine and store */
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ v16u8 q0, q1, q2;
+
+ q0 = (v16u8) __msa_pckev_b((v16i8) q0_l, (v16i8) q0_r);
+ q1 = (v16u8) __msa_pckev_b((v16i8) q1_l, (v16i8) q1_r);
+ q2 = (v16u8) __msa_pckev_b((v16i8) q2_l, (v16i8) q2_r);
+
+ q0_org = __msa_bmnz_v(q0_org, q0, is_less_than_beta);
+ q1_org = __msa_bmnz_v(q1_org, q1, is_less_than_beta);
+ q2_org = __msa_bmnz_v(q2_org, q2, is_less_than_beta);
+ }
+
+ /* right */
+ {
+ v16u8 negate_is_less_than_beta_r;
+
+ negate_is_less_than_beta_r =
+ (v16u8) __msa_sldi_b((v16i8) negate_is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v(negate_is_less_than_beta_r)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(q0_org_r, p1_org_r, q1_org_r, q0_r);
+ }
+ }
+ /* left */
+ {
+ v16u8 negate_is_less_than_beta_l;
+
+ negate_is_less_than_beta_l =
+ (v16u8) __msa_sldi_b(zero, (v16i8) negate_is_less_than_beta, 8);
+ if (!__msa_test_bz_v(negate_is_less_than_beta_l)) {
+ AVC_LOOP_FILTER_P0_OR_Q0(q0_org_l, p1_org_l, q1_org_l, q0_l);
+ }
+ }
+
+ if (!__msa_test_bz_v(negate_is_less_than_beta)) {
+ v16u8 q0;
+
+ q0 = (v16u8) __msa_pckev_b((v16i8) q0_l, (v16i8) q0_r);
+ q0_org = __msa_bmnz_v(q0_org, q0, negate_is_less_than_beta);
+ }
+ }
+
+ {
+ v16u8 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ uint32_t out0, out2;
+ uint16_t out1, out3;
+
+ tmp0 = (v16u8) __msa_ilvr_b((v16i8) p1_org, (v16i8) p2_org);
+ tmp1 = (v16u8) __msa_ilvr_b((v16i8) q0_org, (v16i8) p0_org);
+ tmp2 = (v16u8) __msa_ilvr_b((v16i8) q2_org, (v16i8) q1_org);
+ tmp3 = (v16u8) __msa_ilvr_h((v8i16) tmp1, (v8i16) tmp0);
+ tmp4 = (v16u8) __msa_ilvl_h((v8i16) tmp1, (v8i16) tmp0);
+
+ tmp0 = (v16u8) __msa_ilvl_b((v16i8) p1_org, (v16i8) p2_org);
+ tmp1 = (v16u8) __msa_ilvl_b((v16i8) q0_org, (v16i8) p0_org);
+ tmp5 = (v16u8) __msa_ilvl_b((v16i8) q2_org, (v16i8) q1_org);
+ tmp6 = (v16u8) __msa_ilvr_h((v8i16) tmp1, (v8i16) tmp0);
+ tmp7 = (v16u8) __msa_ilvl_h((v8i16) tmp1, (v8i16) tmp0);
+
+ src = data - 3;
+
+ out0 = __msa_copy_u_w((v4i32) tmp3, 0);
+ out1 = __msa_copy_u_h((v8i16) tmp2, 0);
+ out2 = __msa_copy_u_w((v4i32) tmp3, 1);
+ out3 = __msa_copy_u_h((v8i16) tmp2, 1);
+
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp3, 2);
+ out1 = __msa_copy_u_h((v8i16) tmp2, 2);
+ out2 = __msa_copy_u_w((v4i32) tmp3, 3);
+ out3 = __msa_copy_u_h((v8i16) tmp2, 3);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp4, 0);
+ out1 = __msa_copy_u_h((v8i16) tmp2, 4);
+ out2 = __msa_copy_u_w((v4i32) tmp4, 1);
+ out3 = __msa_copy_u_h((v8i16) tmp2, 5);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp4, 2);
+ out1 = __msa_copy_u_h((v8i16) tmp2, 6);
+ out2 = __msa_copy_u_w((v4i32) tmp4, 3);
+ out3 = __msa_copy_u_h((v8i16) tmp2, 7);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp6, 0);
+ out1 = __msa_copy_u_h((v8i16) tmp5, 0);
+ out2 = __msa_copy_u_w((v4i32) tmp6, 1);
+ out3 = __msa_copy_u_h((v8i16) tmp5, 1);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp6, 2);
+ out1 = __msa_copy_u_h((v8i16) tmp5, 2);
+ out2 = __msa_copy_u_w((v4i32) tmp6, 3);
+ out3 = __msa_copy_u_h((v8i16) tmp5, 3);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp7, 0);
+ out1 = __msa_copy_u_h((v8i16) tmp5, 4);
+ out2 = __msa_copy_u_w((v4i32) tmp7, 1);
+ out3 = __msa_copy_u_h((v8i16) tmp5, 5);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w((v4i32) tmp7, 2);
+ out1 = __msa_copy_u_h((v8i16) tmp5, 6);
+ out2 = __msa_copy_u_w((v4i32) tmp7, 3);
+ out3 = __msa_copy_u_h((v8i16) tmp5, 7);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+ }
+}
+
+static void avc_h_loop_filter_luma_mbaff_intra_msa(uint8_t *src,
+ int32_t stride,
+ int32_t alpha_in,
+ int32_t beta_in)
+{
+ uint64_t load0, load1;
+ uint32_t out0, out2;
+ uint16_t out1, out3;
+ v8u16 src0_r, src1_r, src2_r, src3_r, src4_r, src5_r, src6_r, src7_r;
+ v8u16 dst0_r, dst1_r, dst4_r, dst5_r;
+ v8u16 dst2_x_r, dst2_y_r, dst3_x_r, dst3_y_r;
+ v16u8 dst0, dst1, dst4, dst5, dst2_x, dst2_y, dst3_x, dst3_y;
+ v8i16 tmp0, tmp1, tmp2, tmp3;
+ v16u8 alpha, beta;
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0, p2_asub_p0, q2_asub_q0;
+ v16u8 is_less_than, is_less_than_alpha, is_less_than_beta;
+ v16u8 is_less_than_beta1, is_less_than_beta2;
+ v16i8 src0 = { 0 };
+ v16i8 src1 = { 0 };
+ v16i8 src2 = { 0 };
+ v16i8 src3 = { 0 };
+ v16i8 src4 = { 0 };
+ v16i8 src5 = { 0 };
+ v16i8 src6 = { 0 };
+ v16i8 src7 = { 0 };
+ v16i8 zeros = { 0 };
+
+ load0 = LOAD_DWORD(src - 4);
+ load1 = LOAD_DWORD(src + stride - 4);
+ src0 = (v16i8) __msa_insert_d((v2i64) src0, 0, load0);
+ src1 = (v16i8) __msa_insert_d((v2i64) src1, 0, load1);
+
+ load0 = LOAD_DWORD(src + (2 * stride) - 4);
+ load1 = LOAD_DWORD(src + (3 * stride) - 4);
+ src2 = (v16i8) __msa_insert_d((v2i64) src2, 0, load0);
+ src3 = (v16i8) __msa_insert_d((v2i64) src3, 0, load1);
+
+ load0 = LOAD_DWORD(src + (4 * stride) - 4);
+ load1 = LOAD_DWORD(src + (5 * stride) - 4);
+ src4 = (v16i8) __msa_insert_d((v2i64) src4, 0, load0);
+ src5 = (v16i8) __msa_insert_d((v2i64) src5, 0, load1);
+
+ load0 = LOAD_DWORD(src + (6 * stride) - 4);
+ load1 = LOAD_DWORD(src + (7 * stride) - 4);
+ src6 = (v16i8) __msa_insert_d((v2i64) src6, 0, load0);
+ src7 = (v16i8) __msa_insert_d((v2i64) src7, 0, load1);
+
+ src0 = __msa_ilvr_b(src1, src0);
+ src1 = __msa_ilvr_b(src3, src2);
+ src2 = __msa_ilvr_b(src5, src4);
+ src3 = __msa_ilvr_b(src7, src6);
+ tmp0 = __msa_ilvr_h((v8i16) src1, (v8i16) src0);
+ tmp1 = __msa_ilvl_h((v8i16) src1, (v8i16) src0);
+ tmp2 = __msa_ilvr_h((v8i16) src3, (v8i16) src2);
+ tmp3 = __msa_ilvl_h((v8i16) src3, (v8i16) src2);
+ src6 = (v16i8) __msa_ilvr_w((v4i32) tmp2, (v4i32) tmp0);
+ src0 = __msa_sldi_b(zeros, src6, 8);
+ src1 = (v16i8) __msa_ilvl_w((v4i32) tmp2, (v4i32) tmp0);
+ src2 = __msa_sldi_b(zeros, src1, 8);
+ src3 = (v16i8) __msa_ilvr_w((v4i32) tmp3, (v4i32) tmp1);
+ src4 = __msa_sldi_b(zeros, src3, 8);
+ src5 = (v16i8) __msa_ilvl_w((v4i32) tmp3, (v4i32) tmp1);
+ src7 = __msa_sldi_b(zeros, src5, 8);
+
+ p0_asub_q0 = __msa_asub_u_b((v16u8) src2, (v16u8) src3);
+ p1_asub_p0 = __msa_asub_u_b((v16u8) src1, (v16u8) src2);
+ q1_asub_q0 = __msa_asub_u_b((v16u8) src4, (v16u8) src3);
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_alpha & is_less_than_beta;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than & is_less_than_beta;
+
+ alpha >>= 2;
+ alpha += 2;
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+
+ p2_asub_p0 = __msa_asub_u_b((v16u8) src0, (v16u8) src2);
+ is_less_than_beta1 = (p2_asub_p0 < beta);
+ q2_asub_q0 = __msa_asub_u_b((v16u8) src5, (v16u8) src3);
+ is_less_than_beta2 = (q2_asub_q0 < beta);
+
+ src0_r = (v8u16) __msa_ilvr_b(zeros, src0);
+ src1_r = (v8u16) __msa_ilvr_b(zeros, src1);
+ src2_r = (v8u16) __msa_ilvr_b(zeros, src2);
+ src3_r = (v8u16) __msa_ilvr_b(zeros, src3);
+ src4_r = (v8u16) __msa_ilvr_b(zeros, src4);
+ src5_r = (v8u16) __msa_ilvr_b(zeros, src5);
+ src6_r = (v8u16) __msa_ilvr_b(zeros, src6);
+ src7_r = (v8u16) __msa_ilvr_b(zeros, src7);
+
+ dst2_x_r = src1_r + src2_r + src3_r;
+ dst2_x_r = src0_r + (2 * (dst2_x_r)) + src4_r;
+ dst2_x_r = (v8u16) __msa_srari_h((v8i16) dst2_x_r, 3);
+
+ dst1_r = src0_r + src1_r + src2_r + src3_r;
+ dst1_r = (v8u16) __msa_srari_h((v8i16) dst1_r, 2);
+
+ dst0_r = (2 * src6_r) + (3 * src0_r);
+ dst0_r += src1_r + src2_r + src3_r;
+ dst0_r = (v8u16) __msa_srari_h((v8i16) dst0_r, 3);
+
+ dst2_y_r = (2 * src1_r) + src2_r + src4_r;
+ dst2_y_r = (v8u16) __msa_srari_h((v8i16) dst2_y_r, 2);
+
+ dst2_x = (v16u8) __msa_pckev_b((v16i8) dst2_x_r, (v16i8) dst2_x_r);
+ dst2_y = (v16u8) __msa_pckev_b((v16i8) dst2_y_r, (v16i8) dst2_y_r);
+ dst2_x = __msa_bmnz_v(dst2_y, dst2_x, is_less_than_beta1);
+
+ dst3_x_r = src2_r + src3_r + src4_r;
+ dst3_x_r = src1_r + (2 * dst3_x_r) + src5_r;
+ dst3_x_r = (v8u16) __msa_srari_h((v8i16) dst3_x_r, 3);
+
+ dst4_r = src2_r + src3_r + src4_r + src5_r;
+ dst4_r = (v8u16) __msa_srari_h((v8i16) dst4_r, 2);
+
+ dst5_r = (2 * src7_r) + (3 * src5_r);
+ dst5_r += src4_r + src3_r + src2_r;
+ dst5_r = (v8u16) __msa_srari_h((v8i16) dst5_r, 3);
+
+ dst3_y_r = (2 * src4_r) + src3_r + src1_r;
+ dst3_y_r = (v8u16) __msa_srari_h((v8i16) dst3_y_r, 2);
+ dst3_x = (v16u8) __msa_pckev_b((v16i8) dst3_x_r, (v16i8) dst3_x_r);
+ dst3_y = (v16u8) __msa_pckev_b((v16i8) dst3_y_r, (v16i8) dst3_y_r);
+ dst3_x = __msa_bmnz_v(dst3_y, dst3_x, is_less_than_beta2);
+
+ dst2_y_r = (2 * src1_r) + src2_r + src4_r;
+ dst2_y_r = (v8u16) __msa_srari_h((v8i16) dst2_y_r, 2);
+
+ dst3_y_r = (2 * src4_r) + src3_r + src1_r;
+ dst3_y_r = (v8u16) __msa_srari_h((v8i16) dst3_y_r, 2);
+
+ dst2_y = (v16u8) __msa_pckev_b((v16i8) dst2_y_r, (v16i8) dst2_y_r);
+ dst3_y = (v16u8) __msa_pckev_b((v16i8) dst3_y_r, (v16i8) dst3_y_r);
+ dst2_x = __msa_bmnz_v(dst2_y, dst2_x, is_less_than_alpha);
+ dst3_x = __msa_bmnz_v(dst3_y, dst3_x, is_less_than_alpha);
+ dst2_x = __msa_bmnz_v((v16u8) src2, dst2_x, is_less_than);
+ dst3_x = __msa_bmnz_v((v16u8) src3, dst3_x, is_less_than);
+
+ is_less_than = is_less_than_alpha & is_less_than;
+ dst1 = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst1_r);
+ is_less_than_beta1 = is_less_than_beta1 & is_less_than;
+ dst1 = __msa_bmnz_v((v16u8) src1, dst1, is_less_than_beta1);
+
+ dst0 = (v16u8) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r);
+ dst0 = __msa_bmnz_v((v16u8) src0, dst0, is_less_than_beta1);
+
+ dst4 = (v16u8) __msa_pckev_b((v16i8) dst4_r, (v16i8) dst4_r);
+ is_less_than_beta2 = is_less_than_beta2 & is_less_than;
+ dst4 = __msa_bmnz_v((v16u8) src4, dst4, is_less_than_beta2);
+
+ dst5 = (v16u8) __msa_pckev_b((v16i8) dst5_r, (v16i8) dst5_r);
+ dst5 = __msa_bmnz_v((v16u8) src5, dst5, is_less_than_beta2);
+
+ dst0 = (v16u8) __msa_ilvr_b((v16i8) dst1, (v16i8) dst0);
+ dst1 = (v16u8) __msa_ilvr_b((v16i8) dst3_x, (v16i8) dst2_x);
+ dst2_x = (v16u8) __msa_ilvr_b((v16i8) dst5, (v16i8) dst4);
+ tmp0 = __msa_ilvr_h((v8i16) dst1, (v8i16) dst0);
+ tmp1 = __msa_ilvl_h((v8i16) dst1, (v8i16) dst0);
+ tmp2 = __msa_ilvr_h((v8i16) zeros, (v8i16) dst2_x);
+ tmp3 = __msa_ilvl_h((v8i16) zeros, (v8i16) dst2_x);
+ dst0 = (v16u8) __msa_ilvr_w((v4i32) tmp2, (v4i32) tmp0);
+ dst1 = (v16u8) __msa_sldi_b(zeros, (v16i8) dst0, 8);
+ dst2_x = (v16u8) __msa_ilvl_w((v4i32) tmp2, (v4i32) tmp0);
+ dst3_x = (v16u8) __msa_sldi_b(zeros, (v16i8) dst2_x, 8);
+ dst4 = (v16u8) __msa_ilvr_w((v4i32) tmp3, (v4i32) tmp1);
+ dst5 = (v16u8) __msa_sldi_b(zeros, (v16i8) dst4, 8);
+ dst2_y = (v16u8) __msa_ilvl_w((v4i32) tmp3, (v4i32) tmp1);
+ dst3_y = (v16u8) __msa_sldi_b(zeros, (v16i8) dst2_y, 8);
+
+ out0 = __msa_copy_u_w((v4i32) dst0, 0);
+ out1 = __msa_copy_u_h((v8i16) dst0, 2);
+ out2 = __msa_copy_u_w((v4i32) dst1, 0);
+ out3 = __msa_copy_u_h((v8i16) dst1, 2);
+
+ STORE_WORD((src - 3), out0);
+ STORE_HWORD((src + 1), out1);
+ src += stride;
+ STORE_WORD((src - 3), out2);
+ STORE_HWORD((src + 1), out3);
+ src += stride;
+
+ out0 = __msa_copy_u_w((v4i32) dst2_x, 0);
+ out1 = __msa_copy_u_h((v8i16) dst2_x, 2);
+ out2 = __msa_copy_u_w((v4i32) dst3_x, 0);
+ out3 = __msa_copy_u_h((v8i16) dst3_x, 2);
+
+ STORE_WORD((src - 3), out0);
+ STORE_HWORD((src + 1), out1);
+ src += stride;
+ STORE_WORD((src - 3), out2);
+ STORE_HWORD((src + 1), out3);
+ src += stride;
+
+ out0 = __msa_copy_u_w((v4i32) dst4, 0);
+ out1 = __msa_copy_u_h((v8i16) dst4, 2);
+ out2 = __msa_copy_u_w((v4i32) dst5, 0);
+ out3 = __msa_copy_u_h((v8i16) dst5, 2);
+
+ STORE_WORD((src - 3), out0);
+ STORE_HWORD((src + 1), out1);
+ src += stride;
+ STORE_WORD((src - 3), out2);
+ STORE_HWORD((src + 1), out3);
+ src += stride;
+
+ out0 = __msa_copy_u_w((v4i32) dst2_y, 0);
+ out1 = __msa_copy_u_h((v8i16) dst2_y, 2);
+ out2 = __msa_copy_u_w((v4i32) dst3_y, 0);
+ out3 = __msa_copy_u_h((v8i16) dst3_y, 2);
+
+ STORE_WORD((src - 3), out0);
+ STORE_HWORD((src + 1), out1);
+ src += stride;
+ STORE_WORD((src - 3), out2);
+ STORE_HWORD((src + 1), out3);
+}
+
+static void avc_loopfilter_cb_or_cr_intra_edge_hor_msa(uint8_t *data_cb_or_cr,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ v16u8 alpha, beta;
+ v16u8 is_less_than;
+ v8i16 p0_or_q0, q0_or_p0;
+ v16u8 p1_or_q1_org, p0_or_q0_org, q0_or_p0_org, q1_or_p1_org;
+ v16i8 zero = { 0 };
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0;
+ v16u8 is_less_than_alpha, is_less_than_beta;
+ v8i16 p1_org_r, p0_org_r, q0_org_r, q1_org_r;
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ p1_or_q1_org = LOAD_UB(data_cb_or_cr - (img_width << 1));
+ p0_or_q0_org = LOAD_UB(data_cb_or_cr - img_width);
+ q0_or_p0_org = LOAD_UB(data_cb_or_cr);
+ q1_or_p1_org = LOAD_UB(data_cb_or_cr + img_width);
+
+ p0_asub_q0 = __msa_asub_u_b(p0_or_q0_org, q0_or_p0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_or_q1_org, p0_or_q0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_or_p1_org, q0_or_p0_org);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+
+ is_less_than = (v16u8) __msa_ilvr_d((v2i64) zero, (v2i64) is_less_than);
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_or_q1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_or_q0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_or_p0_org);
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_or_p1_org);
+
+ AVC_LOOP_FILTER_P0_OR_Q0(p0_org_r, q1_org_r, p1_org_r, p0_or_q0);
+ AVC_LOOP_FILTER_P0_OR_Q0(q0_org_r, p1_org_r, q1_org_r, q0_or_p0);
+
+ p0_or_q0 = (v8i16) __msa_pckev_b(zero, (v16i8) p0_or_q0);
+ q0_or_p0 = (v8i16) __msa_pckev_b(zero, (v16i8) q0_or_p0);
+
+ p0_or_q0_org =
+ __msa_bmnz_v(p0_or_q0_org, (v16u8) p0_or_q0, is_less_than);
+ q0_or_p0_org =
+ __msa_bmnz_v(q0_or_p0_org, (v16u8) q0_or_p0, is_less_than);
+
+ STORE_UB(q0_or_p0_org, data_cb_or_cr);
+ STORE_UB(p0_or_q0_org, data_cb_or_cr - img_width);
+ }
+}
+
+static void avc_loopfilter_cb_or_cr_intra_edge_ver_msa(uint8_t *data_cb_or_cr,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ uint16_t out0, out1, out2, out3;
+ v8i16 tmp1;
+ v16u8 alpha, beta, is_less_than;
+ v8i16 p0_or_q0, q0_or_p0;
+ v16u8 p1_or_q1_org, p0_or_q0_org, q0_or_p0_org, q1_or_p1_org;
+ v16i8 zero = { 0 };
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0;
+ v16u8 is_less_than_alpha, is_less_than_beta;
+ v8i16 p1_org_r, p0_org_r, q0_org_r, q1_org_r;
+
+ {
+ v16u8 row0, row1, row2, row3, row4, row5, row6, row7;
+
+ LOAD_8VECS_UB((data_cb_or_cr - 2), img_width,
+ row0, row1, row2, row3, row4, row5, row6, row7);
+
+ TRANSPOSE8x4_B_UB(row0, row1, row2, row3, row4, row5, row6, row7,
+ p1_or_q1_org, p0_or_q0_org,
+ q0_or_p0_org, q1_or_p1_org);
+ }
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ p0_asub_q0 = __msa_asub_u_b(p0_or_q0_org, q0_or_p0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_or_q1_org, p0_or_q0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_or_p1_org, q0_or_p0_org);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+
+ is_less_than = (v16u8) __msa_ilvr_d((v2i64) zero, (v2i64) is_less_than);
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_or_q1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_or_q0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_or_p0_org);
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_or_p1_org);
+
+ AVC_LOOP_FILTER_P0_OR_Q0(p0_org_r, q1_org_r, p1_org_r, p0_or_q0);
+ AVC_LOOP_FILTER_P0_OR_Q0(q0_org_r, p1_org_r, q1_org_r, q0_or_p0);
+
+ /* convert 16 bit output into 8 bit output */
+ p0_or_q0 = (v8i16) __msa_pckev_b(zero, (v16i8) p0_or_q0);
+ q0_or_p0 = (v8i16) __msa_pckev_b(zero, (v16i8) q0_or_p0);
+
+ p0_or_q0_org =
+ __msa_bmnz_v(p0_or_q0_org, (v16u8) p0_or_q0, is_less_than);
+ q0_or_p0_org =
+ __msa_bmnz_v(q0_or_p0_org, (v16u8) q0_or_p0, is_less_than);
+
+ tmp1 = (v8i16) __msa_ilvr_b((v16i8) q0_or_p0_org, (v16i8) p0_or_q0_org);
+
+ data_cb_or_cr -= 1;
+
+ out0 = __msa_copy_u_h(tmp1, 0);
+ out1 = __msa_copy_u_h(tmp1, 1);
+ out2 = __msa_copy_u_h(tmp1, 2);
+ out3 = __msa_copy_u_h(tmp1, 3);
+
+ STORE_HWORD(data_cb_or_cr, out0);
+ data_cb_or_cr += img_width;
+ STORE_HWORD(data_cb_or_cr, out1);
+ data_cb_or_cr += img_width;
+ STORE_HWORD(data_cb_or_cr, out2);
+ data_cb_or_cr += img_width;
+ STORE_HWORD(data_cb_or_cr, out3);
+ data_cb_or_cr += img_width;
+
+ out0 = __msa_copy_u_h(tmp1, 4);
+ out1 = __msa_copy_u_h(tmp1, 5);
+ out2 = __msa_copy_u_h(tmp1, 6);
+ out3 = __msa_copy_u_h(tmp1, 7);
+
+ STORE_HWORD(data_cb_or_cr, out0);
+ data_cb_or_cr += img_width;
+ STORE_HWORD(data_cb_or_cr, out1);
+ data_cb_or_cr += img_width;
+ STORE_HWORD(data_cb_or_cr, out2);
+ data_cb_or_cr += img_width;
+ STORE_HWORD(data_cb_or_cr, out3);
+ }
+}
+
+static void avc_loopfilter_luma_inter_edge_ver_msa(uint8_t *data,
+ uint8_t bs0, uint8_t bs1,
+ uint8_t bs2, uint8_t bs3,
+ uint8_t tc0, uint8_t tc1,
+ uint8_t tc2, uint8_t tc3,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ uint8_t *src;
+ v16u8 beta, tmp_vec, bs = { 0 };
+ v16u8 tc = { 0 };
+ v16u8 is_less_than, is_less_than_beta;
+ v16u8 p1, p0, q0, q1;
+ v8i16 p0_r, q0_r, p1_r = { 0 };
+ v8i16 q1_r = { 0 };
+ v8i16 p0_l, q0_l, p1_l = { 0 };
+ v8i16 q1_l = { 0 };
+ v16u8 p3_org, p2_org, p1_org, p0_org, q0_org, q1_org, q2_org, q3_org;
+ v8i16 p2_org_r, p1_org_r, p0_org_r, q0_org_r, q1_org_r, q2_org_r;
+ v8i16 p2_org_l, p1_org_l, p0_org_l, q0_org_l, q1_org_l, q2_org_l;
+ v8i16 tc_r, tc_l;
+ v16i8 zero = { 0 };
+ v16u8 is_bs_greater_than0;
+
+ tmp_vec = (v16u8) __msa_fill_b(bs0);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 0, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(bs1);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 1, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(bs2);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 2, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(bs3);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 3, (v4i32) tmp_vec);
+
+ if (!__msa_test_bz_v(bs)) {
+ tmp_vec = (v16u8) __msa_fill_b(tc0);
+ tc = (v16u8) __msa_insve_w((v4i32) tc, 0, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(tc1);
+ tc = (v16u8) __msa_insve_w((v4i32) tc, 1, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(tc2);
+ tc = (v16u8) __msa_insve_w((v4i32) tc, 2, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(tc3);
+ tc = (v16u8) __msa_insve_w((v4i32) tc, 3, (v4i32) tmp_vec);
+
+ is_bs_greater_than0 = (zero < bs);
+
+ {
+ v16u8 row0, row1, row2, row3, row4, row5, row6, row7;
+ v16u8 row8, row9, row10, row11, row12, row13, row14, row15;
+
+ src = data;
+ src -= 4;
+
+ LOAD_8VECS_UB(src, img_width,
+ row0, row1, row2, row3, row4, row5, row6, row7);
+ src += (8 * img_width);
+ LOAD_8VECS_UB(src, img_width,
+ row8, row9, row10, row11, row12, row13, row14, row15);
+
+ TRANSPOSE16x8_B_UB(row0, row1, row2, row3, row4, row5, row6, row7,
+ row8, row9, row10, row11,
+ row12, row13, row14, row15,
+ p3_org, p2_org, p1_org, p0_org,
+ q0_org, q1_org, q2_org, q3_org);
+ }
+
+ {
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0, alpha;
+ v16u8 is_less_than_alpha;
+
+ p0_asub_q0 = __msa_asub_u_b(p0_org, q0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_org, p0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_org, q0_org);
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+ is_less_than = is_less_than & is_bs_greater_than0;
+ }
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ v16i8 negate_tc, sign_negate_tc;
+ v8i16 negate_tc_r, i16_negatetc_l;
+
+ negate_tc = zero - (v16i8) tc;
+ sign_negate_tc = __msa_clti_s_b(negate_tc, 0);
+
+ negate_tc_r = (v8i16) __msa_ilvr_b(sign_negate_tc, negate_tc);
+ i16_negatetc_l = (v8i16) __msa_ilvl_b(sign_negate_tc, negate_tc);
+
+ tc_r = (v8i16) __msa_ilvr_b(zero, (v16i8) tc);
+ tc_l = (v8i16) __msa_ilvl_b(zero, (v16i8) tc);
+
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_org);
+
+ p1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p1_org);
+ p0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p0_org);
+ q0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q0_org);
+
+ {
+ v16u8 p2_asub_p0;
+ v16u8 is_less_than_beta_r, is_less_than_beta_l;
+
+ p2_asub_p0 = __msa_asub_u_b(p2_org, p0_org);
+ is_less_than_beta = (p2_asub_p0 < beta);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+
+ is_less_than_beta_r =
+ (v16u8) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_r)) {
+ p2_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_r, q0_org_r,
+ p1_org_r, p2_org_r,
+ negate_tc_r, tc_r, p1_r);
+ }
+
+ is_less_than_beta_l =
+ (v16u8) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_l)) {
+ p2_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_l, q0_org_l,
+ p1_org_l, p2_org_l,
+ i16_negatetc_l, tc_l, p1_l);
+ }
+ }
+
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ p1 = (v16u8) __msa_pckev_b((v16i8) p1_l, (v16i8) p1_r);
+ p1_org = __msa_bmnz_v(p1_org, p1, is_less_than_beta);
+
+ is_less_than_beta = __msa_andi_b(is_less_than_beta, 1);
+ tc = tc + is_less_than_beta;
+ }
+
+ {
+ v16u8 u8_q2asub_q0;
+ v16u8 is_less_than_beta_l, is_less_than_beta_r;
+
+ u8_q2asub_q0 = __msa_asub_u_b(q2_org, q0_org);
+ is_less_than_beta = (u8_q2asub_q0 < beta);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_org);
+
+ is_less_than_beta_r =
+ (v16u8) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_r)) {
+ q2_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_r, q0_org_r,
+ q1_org_r, q2_org_r,
+ negate_tc_r, tc_r, q1_r);
+ }
+
+ q1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q1_org);
+
+ is_less_than_beta_l =
+ (v16u8) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+ if (!__msa_test_bz_v(is_less_than_beta_l)) {
+ q2_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_l, q0_org_l,
+ q1_org_l, q2_org_l,
+ i16_negatetc_l, tc_l, q1_l);
+ }
+ }
+
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ q1 = (v16u8) __msa_pckev_b((v16i8) q1_l, (v16i8) q1_r);
+ q1_org = __msa_bmnz_v(q1_org, q1, is_less_than_beta);
+
+ is_less_than_beta = __msa_andi_b(is_less_than_beta, 1);
+ tc = tc + is_less_than_beta;
+ }
+
+ {
+ v8i16 threshold_r, negate_thresh_r;
+ v8i16 threshold_l, negate_thresh_l;
+ v16i8 negate_thresh, sign_negate_thresh;
+
+ negate_thresh = zero - (v16i8) tc;
+ sign_negate_thresh = __msa_clti_s_b(negate_thresh, 0);
+
+ threshold_r = (v8i16) __msa_ilvr_b(zero, (v16i8) tc);
+ negate_thresh_r = (v8i16) __msa_ilvr_b(sign_negate_thresh,
+ negate_thresh);
+
+ AVC_LOOP_FILTER_P0Q0(q0_org_r, p0_org_r, p1_org_r, q1_org_r,
+ negate_thresh_r, threshold_r, p0_r, q0_r);
+
+ threshold_l = (v8i16) __msa_ilvl_b(zero, (v16i8) tc);
+ negate_thresh_l = (v8i16) __msa_ilvl_b(sign_negate_thresh,
+ negate_thresh);
+
+ AVC_LOOP_FILTER_P0Q0(q0_org_l, p0_org_l, p1_org_l, q1_org_l,
+ negate_thresh_l, threshold_l, p0_l, q0_l);
+ }
+
+ p0 = (v16u8) __msa_pckev_b((v16i8) p0_l, (v16i8) p0_r);
+ q0 = (v16u8) __msa_pckev_b((v16i8) q0_l, (v16i8) q0_r);
+
+ p0_org = __msa_bmnz_v(p0_org, p0, is_less_than);
+ q0_org = __msa_bmnz_v(q0_org, q0, is_less_than);
+ }
+
+ {
+ v16i8 tmp0, tmp1;
+ v8i16 tmp2, tmp5;
+ v4i32 tmp3, tmp4, tmp6, tmp7;
+ uint32_t out0, out2;
+ uint16_t out1, out3;
+
+ src = data - 3;
+
+ tmp0 = __msa_ilvr_b((v16i8) p1_org, (v16i8) p2_org);
+ tmp1 = __msa_ilvr_b((v16i8) q0_org, (v16i8) p0_org);
+ tmp2 = (v8i16) __msa_ilvr_b((v16i8) q2_org, (v16i8) q1_org);
+ tmp3 = (v4i32) __msa_ilvr_h((v8i16) tmp1, (v8i16) tmp0);
+ tmp4 = (v4i32) __msa_ilvl_h((v8i16) tmp1, (v8i16) tmp0);
+
+ tmp0 = __msa_ilvl_b((v16i8) p1_org, (v16i8) p2_org);
+ tmp1 = __msa_ilvl_b((v16i8) q0_org, (v16i8) p0_org);
+ tmp5 = (v8i16) __msa_ilvl_b((v16i8) q2_org, (v16i8) q1_org);
+ tmp6 = (v4i32) __msa_ilvr_h((v8i16) tmp1, (v8i16) tmp0);
+ tmp7 = (v4i32) __msa_ilvl_h((v8i16) tmp1, (v8i16) tmp0);
+
+ out0 = __msa_copy_u_w(tmp3, 0);
+ out1 = __msa_copy_u_h(tmp2, 0);
+ out2 = __msa_copy_u_w(tmp3, 1);
+ out3 = __msa_copy_u_h(tmp2, 1);
+
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp3, 2);
+ out1 = __msa_copy_u_h(tmp2, 2);
+ out2 = __msa_copy_u_w(tmp3, 3);
+ out3 = __msa_copy_u_h(tmp2, 3);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp4, 0);
+ out1 = __msa_copy_u_h(tmp2, 4);
+ out2 = __msa_copy_u_w(tmp4, 1);
+ out3 = __msa_copy_u_h(tmp2, 5);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp4, 2);
+ out1 = __msa_copy_u_h(tmp2, 6);
+ out2 = __msa_copy_u_w(tmp4, 3);
+ out3 = __msa_copy_u_h(tmp2, 7);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp6, 0);
+ out1 = __msa_copy_u_h(tmp5, 0);
+ out2 = __msa_copy_u_w(tmp6, 1);
+ out3 = __msa_copy_u_h(tmp5, 1);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp6, 2);
+ out1 = __msa_copy_u_h(tmp5, 2);
+ out2 = __msa_copy_u_w(tmp6, 3);
+ out3 = __msa_copy_u_h(tmp5, 3);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp7, 0);
+ out1 = __msa_copy_u_h(tmp5, 4);
+ out2 = __msa_copy_u_w(tmp7, 1);
+ out3 = __msa_copy_u_h(tmp5, 5);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+
+ out0 = __msa_copy_u_w(tmp7, 2);
+ out1 = __msa_copy_u_h(tmp5, 6);
+ out2 = __msa_copy_u_w(tmp7, 3);
+ out3 = __msa_copy_u_h(tmp5, 7);
+
+ src += img_width;
+ STORE_WORD(src, out0);
+ STORE_HWORD((src + 4), out1);
+ src += img_width;
+ STORE_WORD(src, out2);
+ STORE_HWORD((src + 4), out3);
+ }
+ }
+}
+
+static void avc_loopfilter_luma_inter_edge_hor_msa(uint8_t *data,
+ uint8_t bs0, uint8_t bs1,
+ uint8_t bs2, uint8_t bs3,
+ uint8_t tc0, uint8_t tc1,
+ uint8_t tc2, uint8_t tc3,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t image_width)
+{
+ v16u8 p2_asub_p0, u8_q2asub_q0;
+ v16u8 alpha, beta, is_less_than, is_less_than_beta;
+ v16u8 p1, p0, q0, q1;
+ v8i16 p1_r = { 0 };
+ v8i16 p0_r, q0_r, q1_r = { 0 };
+ v8i16 p1_l = { 0 };
+ v8i16 p0_l, q0_l, q1_l = { 0 };
+ v16u8 p2_org, p1_org, p0_org, q0_org, q1_org, q2_org;
+ v8i16 p2_org_r, p1_org_r, p0_org_r, q0_org_r, q1_org_r, q2_org_r;
+ v8i16 p2_org_l, p1_org_l, p0_org_l, q0_org_l, q1_org_l, q2_org_l;
+ v16i8 zero = { 0 };
+ v16u8 tmp_vec;
+ v16u8 bs = { 0 };
+ v16i8 tc = { 0 };
+
+ tmp_vec = (v16u8) __msa_fill_b(bs0);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 0, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(bs1);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 1, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(bs2);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 2, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(bs3);
+ bs = (v16u8) __msa_insve_w((v4i32) bs, 3, (v4i32) tmp_vec);
+
+ if (!__msa_test_bz_v(bs)) {
+ tmp_vec = (v16u8) __msa_fill_b(tc0);
+ tc = (v16i8) __msa_insve_w((v4i32) tc, 0, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(tc1);
+ tc = (v16i8) __msa_insve_w((v4i32) tc, 1, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(tc2);
+ tc = (v16i8) __msa_insve_w((v4i32) tc, 2, (v4i32) tmp_vec);
+ tmp_vec = (v16u8) __msa_fill_b(tc3);
+ tc = (v16i8) __msa_insve_w((v4i32) tc, 3, (v4i32) tmp_vec);
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ p2_org = LOAD_UB(data - (3 * image_width));
+ p1_org = LOAD_UB(data - (image_width << 1));
+ p0_org = LOAD_UB(data - image_width);
+ q0_org = LOAD_UB(data);
+ q1_org = LOAD_UB(data + image_width);
+
+ {
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0;
+ v16u8 is_less_than_alpha, is_bs_greater_than0;
+
+ is_bs_greater_than0 = ((v16u8) zero < bs);
+ p0_asub_q0 = __msa_asub_u_b(p0_org, q0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_org, p0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_org, q0_org);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+ is_less_than = is_less_than & is_bs_greater_than0;
+ }
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ v16i8 sign_negate_tc, negate_tc;
+ v8i16 negate_tc_r, i16_negatetc_l, tc_l, tc_r;
+
+ q2_org = LOAD_UB(data + (2 * image_width));
+
+ negate_tc = zero - tc;
+ sign_negate_tc = __msa_clti_s_b(negate_tc, 0);
+
+ negate_tc_r = (v8i16) __msa_ilvr_b(sign_negate_tc, negate_tc);
+ i16_negatetc_l = (v8i16) __msa_ilvl_b(sign_negate_tc, negate_tc);
+
+ tc_r = (v8i16) __msa_ilvr_b(zero, tc);
+ tc_l = (v8i16) __msa_ilvl_b(zero, tc);
+
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_org);
+
+ p1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p1_org);
+ p0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p0_org);
+ q0_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q0_org);
+
+ p2_asub_p0 = __msa_asub_u_b(p2_org, p0_org);
+ is_less_than_beta = (p2_asub_p0 < beta);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+
+ {
+ v8u16 is_less_than_beta_r, is_less_than_beta_l;
+
+ is_less_than_beta_r =
+ (v8u16) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_r)) {
+ p2_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_r, q0_org_r,
+ p1_org_r, p2_org_r,
+ negate_tc_r, tc_r, p1_r);
+ }
+
+ is_less_than_beta_l =
+ (v8u16) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_l)) {
+ p2_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) p2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_l, q0_org_l,
+ p1_org_l, p2_org_l,
+ i16_negatetc_l, tc_l, p1_l);
+ }
+ }
+
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ p1 = (v16u8) __msa_pckev_b((v16i8) p1_l, (v16i8) p1_r);
+ p1_org = __msa_bmnz_v(p1_org, p1, is_less_than_beta);
+ STORE_UB(p1_org, data - (2 * image_width));
+
+ is_less_than_beta = __msa_andi_b(is_less_than_beta, 1);
+ tc = tc + (v16i8) is_less_than_beta;
+ }
+
+ u8_q2asub_q0 = __msa_asub_u_b(q2_org, q0_org);
+ is_less_than_beta = (u8_q2asub_q0 < beta);
+ is_less_than_beta = is_less_than_beta & is_less_than;
+
+ {
+ v8u16 is_less_than_beta_r, is_less_than_beta_l;
+
+ is_less_than_beta_r =
+ (v8u16) __msa_sldi_b((v16i8) is_less_than_beta, zero, 8);
+
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_org);
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_r)) {
+ q2_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_r, q0_org_r,
+ q1_org_r, q2_org_r,
+ negate_tc_r, tc_r, q1_r);
+ }
+
+ is_less_than_beta_l =
+ (v8u16) __msa_sldi_b(zero, (v16i8) is_less_than_beta, 8);
+
+ q1_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q1_org);
+ if (!__msa_test_bz_v((v16u8) is_less_than_beta_l)) {
+ q2_org_l = (v8i16) __msa_ilvl_b(zero, (v16i8) q2_org);
+
+ AVC_LOOP_FILTER_P1_OR_Q1(p0_org_l, q0_org_l,
+ q1_org_l, q2_org_l,
+ i16_negatetc_l, tc_l, q1_l);
+ }
+ }
+
+ if (!__msa_test_bz_v(is_less_than_beta)) {
+ q1 = (v16u8) __msa_pckev_b((v16i8) q1_l, (v16i8) q1_r);
+ q1_org = __msa_bmnz_v(q1_org, q1, is_less_than_beta);
+ STORE_UB(q1_org, data + image_width);
+
+ is_less_than_beta = __msa_andi_b(is_less_than_beta, 1);
+ tc = tc + (v16i8) is_less_than_beta;
+ }
+
+ {
+ v16i8 negate_thresh, sign_negate_thresh;
+ v8i16 threshold_r, threshold_l;
+ v8i16 negate_thresh_l, negate_thresh_r;
+
+ negate_thresh = zero - tc;
+ sign_negate_thresh = __msa_clti_s_b(negate_thresh, 0);
+
+ threshold_r = (v8i16) __msa_ilvr_b(zero, tc);
+ negate_thresh_r = (v8i16) __msa_ilvr_b(sign_negate_thresh,
+ negate_thresh);
+
+ AVC_LOOP_FILTER_P0Q0(q0_org_r, p0_org_r, p1_org_r, q1_org_r,
+ negate_thresh_r, threshold_r, p0_r, q0_r);
+
+ threshold_l = (v8i16) __msa_ilvl_b(zero, tc);
+ negate_thresh_l = (v8i16) __msa_ilvl_b(sign_negate_thresh,
+ negate_thresh);
+
+ AVC_LOOP_FILTER_P0Q0(q0_org_l, p0_org_l, p1_org_l, q1_org_l,
+ negate_thresh_l, threshold_l, p0_l, q0_l);
+ }
+
+ p0 = (v16u8) __msa_pckev_b((v16i8) p0_l, (v16i8) p0_r);
+ q0 = (v16u8) __msa_pckev_b((v16i8) q0_l, (v16i8) q0_r);
+
+ p0_org = __msa_bmnz_v(p0_org, p0, is_less_than);
+ q0_org = __msa_bmnz_v(q0_org, q0, is_less_than);
+
+ STORE_UB(p0_org, (data - image_width));
+ STORE_UB(q0_org, data);
+ }
+ }
+}
+
+static void avc_h_loop_filter_luma_mbaff_msa(uint8_t *in, int32_t stride,
+ int32_t alpha_in, int32_t beta_in,
+ int8_t *tc0)
+{
+ uint8_t *data = in;
+ uint32_t out0, out1, out2, out3;
+ uint64_t load;
+ uint32_t tc_val;
+ v16u8 alpha, beta;
+ v16i8 inp0 = { 0 };
+ v16i8 inp1 = { 0 };
+ v16i8 inp2 = { 0 };
+ v16i8 inp3 = { 0 };
+ v16i8 inp4 = { 0 };
+ v16i8 inp5 = { 0 };
+ v16i8 inp6 = { 0 };
+ v16i8 inp7 = { 0 };
+ v16i8 src0, src1, src2, src3;
+ v8i16 src4, src5, src6, src7;
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0, p2_asub_p0, q2_asub_q0;
+ v16u8 is_less_than, is_less_than_alpha, is_less_than_beta;
+ v16u8 is_less_than_beta1, is_less_than_beta2;
+ v8i16 tc, tc_orig_r, tc_plus1;
+ v16u8 is_tc_orig1, is_tc_orig2, tc_orig = { 0 };
+ v8i16 p0_ilvr_q0, p0_add_q0, q0_sub_p0, p1_sub_q1;
+ v8u16 src2_r, src3_r;
+ v8i16 p2_r, p1_r, q2_r, q1_r;
+ v16u8 p2, q2, p0, q0;
+ v4i32 dst0, dst1;
+ v16i8 zeros = { 0 };
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ if (tc0[0] < 0) {
+ data += (2 * stride);
+ } else {
+ load = LOAD_DWORD(data - 3);
+ inp0 = (v16i8) __msa_insert_d((v2i64) inp0, 0, load);
+ load = LOAD_DWORD(data - 3 + stride);
+ inp1 = (v16i8) __msa_insert_d((v2i64) inp1, 0, load);
+ data += (2 * stride);
+ }
+
+ if (tc0[1] < 0) {
+ data += (2 * stride);
+ } else {
+ load = LOAD_DWORD(data - 3);
+ inp2 = (v16i8) __msa_insert_d((v2i64) inp2, 0, load);
+ load = LOAD_DWORD(data - 3 + stride);
+ inp3 = (v16i8) __msa_insert_d((v2i64) inp3, 0, load);
+ data += (2 * stride);
+ }
+
+ if (tc0[2] < 0) {
+ data += (2 * stride);
+ } else {
+ load = LOAD_DWORD(data - 3);
+ inp4 = (v16i8) __msa_insert_d((v2i64) inp4, 0, load);
+ load = LOAD_DWORD(data - 3 + stride);
+ inp5 = (v16i8) __msa_insert_d((v2i64) inp5, 0, load);
+ data += (2 * stride);
+ }
+
+ if (tc0[3] < 0) {
+ data += (2 * stride);
+ } else {
+ load = LOAD_DWORD(data - 3);
+ inp6 = (v16i8) __msa_insert_d((v2i64) inp6, 0, load);
+ load = LOAD_DWORD(data - 3 + stride);
+ inp7 = (v16i8) __msa_insert_d((v2i64) inp7, 0, load);
+ data += (2 * stride);
+ }
+
+ src0 = __msa_ilvr_b(inp1, inp0);
+ src1 = __msa_ilvr_b(inp3, inp2);
+ src2 = __msa_ilvr_b(inp5, inp4);
+ src3 = __msa_ilvr_b(inp7, inp6);
+ src4 = __msa_ilvr_h((v8i16) src1, (v8i16) src0);
+ src5 = __msa_ilvl_h((v8i16) src1, (v8i16) src0);
+ src6 = __msa_ilvr_h((v8i16) src3, (v8i16) src2);
+ src7 = __msa_ilvl_h((v8i16) src3, (v8i16) src2);
+ src0 = (v16i8) __msa_ilvr_w((v4i32) src6, (v4i32) src4);
+ src1 = __msa_sldi_b(zeros, (v16i8) src0, 8);
+ src2 = (v16i8) __msa_ilvl_w((v4i32) src6, (v4i32) src4);
+ src3 = __msa_sldi_b(zeros, (v16i8) src2, 8);
+ src4 = (v8i16) __msa_ilvr_w((v4i32) src7, (v4i32) src5);
+ src5 = (v8i16) __msa_sldi_b(zeros, (v16i8) src4, 8);
+
+ p0_asub_q0 = __msa_asub_u_b((v16u8) src2, (v16u8) src3);
+ p1_asub_p0 = __msa_asub_u_b((v16u8) src1, (v16u8) src2);
+ q1_asub_q0 = __msa_asub_u_b((v16u8) src4, (v16u8) src3);
+ p2_asub_p0 = __msa_asub_u_b((v16u8) src0, (v16u8) src2);
+ q2_asub_q0 = __msa_asub_u_b((v16u8) src5, (v16u8) src3);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_alpha & is_less_than_beta;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+
+ is_less_than_beta1 = (p2_asub_p0 < beta);
+ is_less_than_beta2 = (q2_asub_q0 < beta);
+
+ p0_ilvr_q0 = (v8i16) __msa_ilvr_b((v16i8) src3, (v16i8) src2);
+ p0_add_q0 = (v8i16) __msa_hadd_u_h((v16u8) p0_ilvr_q0, (v16u8) p0_ilvr_q0);
+ p0_add_q0 = __msa_srari_h(p0_add_q0, 1);
+
+ p2_r = (v8i16) __msa_ilvr_b(zeros, src0);
+ p1_r = (v8i16) __msa_ilvr_b(zeros, src1);
+ p2_r += p0_add_q0;
+ p2_r >>= 1;
+ p2_r -= p1_r;
+ q2_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) src5);
+ q1_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) src4);
+ q2_r += p0_add_q0;
+ q2_r >>= 1;
+ q2_r -= q1_r;
+
+ tc_val = LOAD_WORD(tc0);
+ tc_orig = (v16u8) __msa_insert_w((v4i32) tc_orig, 0, tc_val);
+ tc_orig = (v16u8) __msa_ilvr_b((v16i8) tc_orig, (v16i8) tc_orig);
+ is_tc_orig1 = tc_orig;
+ is_tc_orig2 = tc_orig;
+ tc_orig_r = (v8i16) __msa_ilvr_b(zeros, (v16i8) tc_orig);
+ tc = tc_orig_r;
+
+ p2_r = CLIP_MIN_TO_MAX_H(p2_r, -tc_orig_r, tc_orig_r);
+ q2_r = CLIP_MIN_TO_MAX_H(q2_r, -tc_orig_r, tc_orig_r);
+
+ p2_r += p1_r;
+ q2_r += q1_r;
+
+ p2 = (v16u8) __msa_pckev_b((v16i8) p2_r, (v16i8) p2_r);
+ q2 = (v16u8) __msa_pckev_b((v16i8) q2_r, (v16i8) q2_r);
+
+ is_tc_orig1 = (zeros < is_tc_orig1);
+ is_tc_orig2 = is_tc_orig1;
+ is_tc_orig1 = is_less_than_beta1 & is_tc_orig1;
+ is_tc_orig2 = is_less_than_beta2 & is_tc_orig2;
+ is_tc_orig1 = is_less_than & is_tc_orig1;
+ is_tc_orig2 = is_less_than & is_tc_orig2;
+
+ p2 = __msa_bmnz_v((v16u8) src1, p2, is_tc_orig1);
+ q2 = __msa_bmnz_v((v16u8) src4, q2, is_tc_orig2);
+
+ q0_sub_p0 = __msa_hsub_u_h((v16u8) p0_ilvr_q0, (v16u8) p0_ilvr_q0);
+ q0_sub_p0 <<= 2;
+ p1_sub_q1 = p1_r - q1_r;
+ q0_sub_p0 += p1_sub_q1;
+ q0_sub_p0 = __msa_srari_h(q0_sub_p0, 3);
+
+ tc_plus1 = tc + 1;
+ is_less_than_beta1 = (v16u8) __msa_ilvr_b((v16i8) is_less_than_beta1,
+ (v16i8) is_less_than_beta1);
+ tc = (v8i16) __msa_bmnz_v((v16u8) tc, (v16u8) tc_plus1, is_less_than_beta1);
+ tc_plus1 = tc + 1;
+ is_less_than_beta2 = (v16u8) __msa_ilvr_b((v16i8) is_less_than_beta2,
+ (v16i8) is_less_than_beta2);
+ tc = (v8i16) __msa_bmnz_v((v16u8) tc, (v16u8) tc_plus1, is_less_than_beta2);
+
+ q0_sub_p0 = CLIP_MIN_TO_MAX_H(q0_sub_p0, -tc, tc);
+
+ src2_r = (v8u16) __msa_ilvr_b(zeros, src2);
+ src3_r = (v8u16) __msa_ilvr_b(zeros, src3);
+ src2_r += q0_sub_p0;
+ src3_r -= q0_sub_p0;
+
+ src2_r = (v8u16) CLIP_UNSIGNED_CHAR_H(src2_r);
+ src3_r = (v8u16) CLIP_UNSIGNED_CHAR_H(src3_r);
+
+ p0 = (v16u8) __msa_pckev_b((v16i8) src2_r, (v16i8) src2_r);
+ q0 = (v16u8) __msa_pckev_b((v16i8) src3_r, (v16i8) src3_r);
+
+ p0 = __msa_bmnz_v((v16u8) src2, p0, is_less_than);
+ q0 = __msa_bmnz_v((v16u8) src3, q0, is_less_than);
+
+ p2 = (v16u8) __msa_ilvr_b((v16i8) p0, (v16i8) p2);
+ q2 = (v16u8) __msa_ilvr_b((v16i8) q2, (v16i8) q0);
+ dst0 = (v4i32) __msa_ilvr_h((v8i16) q2, (v8i16) p2);
+ dst1 = (v4i32) __msa_ilvl_h((v8i16) q2, (v8i16) p2);
+
+ data = in;
+
+ out0 = __msa_copy_u_w(dst0, 0);
+ out1 = __msa_copy_u_w(dst0, 1);
+ out2 = __msa_copy_u_w(dst0, 2);
+ out3 = __msa_copy_u_w(dst0, 3);
+
+ if (tc0[0] < 0) {
+ data += (2 * stride);
+ } else {
+ STORE_WORD((data - 2), out0);
+ data += stride;
+ STORE_WORD((data - 2), out1);
+ data += stride;
+ }
+
+ if (tc0[1] < 0) {
+ data += (2 * stride);
+ } else {
+ STORE_WORD((data - 2), out2);
+ data += stride;
+ STORE_WORD((data - 2), out3);
+ data += stride;
+ }
+
+ out0 = __msa_copy_u_w(dst1, 0);
+ out1 = __msa_copy_u_w(dst1, 1);
+ out2 = __msa_copy_u_w(dst1, 2);
+ out3 = __msa_copy_u_w(dst1, 3);
+
+ if (tc0[2] < 0) {
+ data += (2 * stride);
+ } else {
+ STORE_WORD((data - 2), out0);
+ data += stride;
+ STORE_WORD((data - 2), out1);
+ data += stride;
+ }
+
+ if (tc0[3] >= 0) {
+ STORE_WORD((data - 2), out2);
+ data += stride;
+ STORE_WORD((data - 2), out3);
+ }
+}
+
+static void avc_loopfilter_cb_or_cr_inter_edge_hor_msa(uint8_t *data,
+ uint8_t bs0, uint8_t bs1,
+ uint8_t bs2, uint8_t bs3,
+ uint8_t tc0, uint8_t tc1,
+ uint8_t tc2, uint8_t tc3,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ v16u8 alpha, beta;
+ v8i16 tmp_vec;
+ v8i16 bs = { 0 };
+ v8i16 tc = { 0 };
+ v16u8 p0, q0, p0_asub_q0, p1_asub_p0, q1_asub_q0;
+ v16u8 is_less_than;
+ v16u8 is_less_than_beta, is_less_than_alpha, is_bs_greater_than0;
+ v8i16 p0_r, q0_r;
+ v16u8 p1_org, p0_org, q0_org, q1_org;
+ v8i16 p1_org_r, p0_org_r, q0_org_r, q1_org_r;
+ v16i8 negate_tc, sign_negate_tc;
+ v8i16 tc_r, negate_tc_r;
+ v16i8 zero = { 0 };
+
+ tmp_vec = (v8i16) __msa_fill_b(bs0);
+ bs = __msa_insve_h(bs, 0, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(bs1);
+ bs = __msa_insve_h(bs, 1, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(bs2);
+ bs = __msa_insve_h(bs, 2, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(bs3);
+ bs = __msa_insve_h(bs, 3, tmp_vec);
+
+ if (!__msa_test_bz_v((v16u8) bs)) {
+ tmp_vec = (v8i16) __msa_fill_b(tc0);
+ tc = __msa_insve_h(tc, 0, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(tc1);
+ tc = __msa_insve_h(tc, 1, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(tc2);
+ tc = __msa_insve_h(tc, 2, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(tc3);
+ tc = __msa_insve_h(tc, 3, tmp_vec);
+
+ is_bs_greater_than0 = (v16u8) (zero < (v16i8) bs);
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ p1_org = LOAD_UB(data - (img_width << 1));
+ p0_org = LOAD_UB(data - img_width);
+ q0_org = LOAD_UB(data);
+ q1_org = LOAD_UB(data + img_width);
+
+ p0_asub_q0 = __msa_asub_u_b(p0_org, q0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_org, p0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_org, q0_org);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+ is_less_than = is_less_than & is_bs_greater_than0;
+
+ is_less_than = (v16u8) __msa_ilvr_d((v2i64) zero, (v2i64) is_less_than);
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ negate_tc = zero - (v16i8) tc;
+ sign_negate_tc = __msa_clti_s_b(negate_tc, 0);
+
+ negate_tc_r = (v8i16) __msa_ilvr_b(sign_negate_tc, negate_tc);
+
+ tc_r = (v8i16) __msa_ilvr_b(zero, (v16i8) tc);
+
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_org);
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_org);
+
+ AVC_LOOP_FILTER_P0Q0(q0_org_r, p0_org_r, p1_org_r, q1_org_r,
+ negate_tc_r, tc_r, p0_r, q0_r);
+
+ p0 = (v16u8) __msa_pckev_b(zero, (v16i8) p0_r);
+ q0 = (v16u8) __msa_pckev_b(zero, (v16i8) q0_r);
+
+ p0_org = __msa_bmnz_v(p0_org, p0, is_less_than);
+ q0_org = __msa_bmnz_v(q0_org, q0, is_less_than);
+
+ STORE_UB(q0_org, data);
+ STORE_UB(p0_org, (data - img_width));
+ }
+ }
+}
+
+static void avc_loopfilter_cb_or_cr_inter_edge_ver_msa(uint8_t *data,
+ uint8_t bs0, uint8_t bs1,
+ uint8_t bs2, uint8_t bs3,
+ uint8_t tc0, uint8_t tc1,
+ uint8_t tc2, uint8_t tc3,
+ uint8_t alpha_in,
+ uint8_t beta_in,
+ uint32_t img_width)
+{
+ uint8_t *src;
+ uint16_t out0, out1, out2, out3;
+ v16u8 alpha, beta;
+ v16u8 p0_asub_q0, p1_asub_p0, q1_asub_q0;
+ v16u8 is_less_than, is_less_than_beta, is_less_than_alpha;
+ v16u8 p0, q0;
+ v8i16 p0_r = { 0 };
+ v8i16 q0_r = { 0 };
+ v16u8 p1_org, p0_org, q0_org, q1_org;
+ v8i16 p1_org_r, p0_org_r, q0_org_r, q1_org_r;
+ v16u8 is_bs_greater_than0;
+ v8i16 tc_r, negate_tc_r;
+ v16i8 negate_tc, sign_negate_tc;
+ v16i8 zero = { 0 };
+ v16u8 row0, row1, row2, row3, row4, row5, row6, row7;
+ v8i16 tmp1, tmp_vec, bs = { 0 };
+ v8i16 tc = { 0 };
+
+ tmp_vec = (v8i16) __msa_fill_b(bs0);
+ bs = __msa_insve_h(bs, 0, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(bs1);
+ bs = __msa_insve_h(bs, 1, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(bs2);
+ bs = __msa_insve_h(bs, 2, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(bs3);
+ bs = __msa_insve_h(bs, 3, tmp_vec);
+
+ if (!__msa_test_bz_v((v16u8) bs)) {
+ tmp_vec = (v8i16) __msa_fill_b(tc0);
+ tc = __msa_insve_h(tc, 0, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(tc1);
+ tc = __msa_insve_h(tc, 1, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(tc2);
+ tc = __msa_insve_h(tc, 2, tmp_vec);
+ tmp_vec = (v8i16) __msa_fill_b(tc3);
+ tc = __msa_insve_h(tc, 3, tmp_vec);
+
+ is_bs_greater_than0 = (v16u8) (zero < (v16i8) bs);
+
+ LOAD_8VECS_UB((data - 2), img_width,
+ row0, row1, row2, row3, row4, row5, row6, row7);
+
+ TRANSPOSE8x4_B_UB(row0, row1, row2, row3,
+ row4, row5, row6, row7,
+ p1_org, p0_org, q0_org, q1_org);
+
+ p0_asub_q0 = __msa_asub_u_b(p0_org, q0_org);
+ p1_asub_p0 = __msa_asub_u_b(p1_org, p0_org);
+ q1_asub_q0 = __msa_asub_u_b(q1_org, q0_org);
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ is_less_than_alpha = (p0_asub_q0 < alpha);
+ is_less_than_beta = (p1_asub_p0 < beta);
+ is_less_than = is_less_than_beta & is_less_than_alpha;
+ is_less_than_beta = (q1_asub_q0 < beta);
+ is_less_than = is_less_than_beta & is_less_than;
+ is_less_than = is_bs_greater_than0 & is_less_than;
+
+ is_less_than = (v16u8) __msa_ilvr_d((v2i64) zero, (v2i64) is_less_than);
+
+ if (!__msa_test_bz_v(is_less_than)) {
+ p1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p1_org);
+ p0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) p0_org);
+ q0_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q0_org);
+ q1_org_r = (v8i16) __msa_ilvr_b(zero, (v16i8) q1_org);
+
+ negate_tc = zero - (v16i8) tc;
+ sign_negate_tc = __msa_clti_s_b(negate_tc, 0);
+
+ negate_tc_r = (v8i16) __msa_ilvr_b(sign_negate_tc, negate_tc);
+
+ tc_r = (v8i16) __msa_ilvr_b(zero, (v16i8) tc);
+
+ AVC_LOOP_FILTER_P0Q0(q0_org_r, p0_org_r, p1_org_r, q1_org_r,
+ negate_tc_r, tc_r, p0_r, q0_r);
+
+ p0 = (v16u8) __msa_pckev_b(zero, (v16i8) p0_r);
+ q0 = (v16u8) __msa_pckev_b(zero, (v16i8) q0_r);
+
+ p0_org = __msa_bmnz_v(p0_org, p0, is_less_than);
+ q0_org = __msa_bmnz_v(q0_org, q0, is_less_than);
+
+ tmp1 = (v8i16) __msa_ilvr_b((v16i8) q0_org, (v16i8) p0_org);
+
+ src = data - 1;
+
+ out0 = __msa_copy_u_h(tmp1, 0);
+ out1 = __msa_copy_u_h(tmp1, 1);
+ out2 = __msa_copy_u_h(tmp1, 2);
+ out3 = __msa_copy_u_h(tmp1, 3);
+
+ STORE_HWORD(src, out0);
+ src += img_width;
+ STORE_HWORD(src, out1);
+ src += img_width;
+ STORE_HWORD(src, out2);
+ src += img_width;
+ STORE_HWORD(src, out3);
+
+ out0 = __msa_copy_u_h(tmp1, 4);
+ out1 = __msa_copy_u_h(tmp1, 5);
+ out2 = __msa_copy_u_h(tmp1, 6);
+ out3 = __msa_copy_u_h(tmp1, 7);
+
+ src += img_width;
+ STORE_HWORD(src, out0);
+ src += img_width;
+ STORE_HWORD(src, out1);
+ src += img_width;
+ STORE_HWORD(src, out2);
+ src += img_width;
+ STORE_HWORD(src, out3);
+ }
+ }
+}
+
+static void avc_h_loop_filter_chroma422_msa(uint8_t *src,
+ int32_t stride,
+ int32_t alpha_in,
+ int32_t beta_in,
+ int8_t *tc0)
+{
+ int32_t col, tc_val;
+ int16_t out0, out1, out2, out3;
+ v16u8 alpha, beta, res;
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ for (col = 0; col < 4; col++) {
+ tc_val = (tc0[col] - 1) + 1;
+
+ if (tc_val <= 0) {
+ src += (4 * stride);
+ continue;
+ }
+
+ AVC_LPF_H_CHROMA_422(src, stride, tc_val, alpha, beta, res);
+
+ out0 = __msa_copy_s_h((v8i16) res, 0);
+ out1 = __msa_copy_s_h((v8i16) res, 1);
+ out2 = __msa_copy_s_h((v8i16) res, 2);
+ out3 = __msa_copy_s_h((v8i16) res, 3);
+
+ STORE_HWORD((src - 1), out0);
+ src += stride;
+ STORE_HWORD((src - 1), out1);
+ src += stride;
+ STORE_HWORD((src - 1), out2);
+ src += stride;
+ STORE_HWORD((src - 1), out3);
+ src += stride;
+ }
+}
+
+static void avc_h_loop_filter_chroma422_mbaff_msa(uint8_t *src,
+ int32_t stride,
+ int32_t alpha_in,
+ int32_t beta_in,
+ int8_t *tc0)
+{
+ int32_t col, tc_val;
+ int16_t out0, out1;
+ v16u8 alpha, beta, res;
+
+ alpha = (v16u8) __msa_fill_b(alpha_in);
+ beta = (v16u8) __msa_fill_b(beta_in);
+
+ for (col = 0; col < 4; col++) {
+ tc_val = (tc0[col] - 1) + 1;
+
+ if (tc_val <= 0) {
+ src += 4 * stride;
+ continue;
+ }
+
+ AVC_LPF_H_2BYTE_CHROMA_422(src, stride, tc_val, alpha, beta, res);
+
+ out0 = __msa_copy_s_h((v8i16) res, 0);
+ out1 = __msa_copy_s_h((v8i16) res, 1);
+
+ STORE_HWORD((src - 1), out0);
+ src += stride;
+ STORE_HWORD((src - 1), out1);
+ src += stride;
+ }
+}
+
+void ff_h264_h_lpf_luma_inter_msa(uint8_t *data, int img_width,
+ int alpha, int beta, int8_t *tc)
+{
+ uint8_t bs0 = 1;
+ uint8_t bs1 = 1;
+ uint8_t bs2 = 1;
+ uint8_t bs3 = 1;
+
+ if (tc[0] < 0)
+ bs0 = 0;
+ if (tc[1] < 0)
+ bs1 = 0;
+ if (tc[2] < 0)
+ bs2 = 0;
+ if (tc[3] < 0)
+ bs3 = 0;
+
+ avc_loopfilter_luma_inter_edge_ver_msa(data,
+ bs0, bs1, bs2, bs3,
+ tc[0], tc[1], tc[2], tc[3],
+ alpha, beta, img_width);
+}
+
+void ff_h264_v_lpf_luma_inter_msa(uint8_t *data, int img_width,
+ int alpha, int beta, int8_t *tc)
+{
+
+ uint8_t bs0 = 1;
+ uint8_t bs1 = 1;
+ uint8_t bs2 = 1;
+ uint8_t bs3 = 1;
+
+ if (tc[0] < 0)
+ bs0 = 0;
+ if (tc[1] < 0)
+ bs1 = 0;
+ if (tc[2] < 0)
+ bs2 = 0;
+ if (tc[3] < 0)
+ bs3 = 0;
+
+ avc_loopfilter_luma_inter_edge_hor_msa(data,
+ bs0, bs1, bs2, bs3,
+ tc[0], tc[1], tc[2], tc[3],
+ alpha, beta, img_width);
+}
+
+void ff_h264_h_lpf_chroma_inter_msa(uint8_t *data, int img_width,
+ int alpha, int beta, int8_t *tc)
+{
+ uint8_t bs0 = 1;
+ uint8_t bs1 = 1;
+ uint8_t bs2 = 1;
+ uint8_t bs3 = 1;
+
+ if (tc[0] < 0)
+ bs0 = 0;
+ if (tc[1] < 0)
+ bs1 = 0;
+ if (tc[2] < 0)
+ bs2 = 0;
+ if (tc[3] < 0)
+ bs3 = 0;
+
+ avc_loopfilter_cb_or_cr_inter_edge_ver_msa(data,
+ bs0, bs1, bs2, bs3,
+ tc[0], tc[1], tc[2], tc[3],
+ alpha, beta,
+ img_width);
+}
+
+void ff_h264_v_lpf_chroma_inter_msa(uint8_t *data, int img_width,
+ int alpha, int beta, int8_t *tc)
+{
+ uint8_t bs0 = 1;
+ uint8_t bs1 = 1;
+ uint8_t bs2 = 1;
+ uint8_t bs3 = 1;
+
+ if (tc[0] < 0)
+ bs0 = 0;
+ if (tc[1] < 0)
+ bs1 = 0;
+ if (tc[2] < 0)
+ bs2 = 0;
+ if (tc[3] < 0)
+ bs3 = 0;
+
+ avc_loopfilter_cb_or_cr_inter_edge_hor_msa(data,
+ bs0, bs1, bs2, bs3,
+ tc[0], tc[1], tc[2], tc[3],
+ alpha, beta,
+ img_width);
+}
+
+void ff_h264_h_lpf_luma_intra_msa(uint8_t *data, int img_width,
+ int alpha, int beta)
+{
+ avc_loopfilter_luma_intra_edge_ver_msa(data, (uint8_t) alpha,
+ (uint8_t) beta,
+ (unsigned int) img_width);
+}
+
+void ff_h264_v_lpf_luma_intra_msa(uint8_t *data, int img_width,
+ int alpha, int beta)
+{
+ avc_loopfilter_luma_intra_edge_hor_msa(data, (uint8_t) alpha,
+ (uint8_t) beta,
+ (unsigned int) img_width);
+}
+
+void ff_h264_h_lpf_chroma_intra_msa(uint8_t *data, int img_width,
+ int alpha, int beta)
+{
+ avc_loopfilter_cb_or_cr_intra_edge_ver_msa(data, (uint8_t) alpha,
+ (uint8_t) beta,
+ (unsigned int) img_width);
+}
+
+void ff_h264_v_lpf_chroma_intra_msa(uint8_t *data, int img_width,
+ int alpha, int beta)
+{
+ avc_loopfilter_cb_or_cr_intra_edge_hor_msa(data, (uint8_t) alpha,
+ (uint8_t) beta,
+ (unsigned int) img_width);
+}
+
+void ff_h264_h_loop_filter_chroma422_msa(uint8_t *src,
+ int32_t ystride,
+ int32_t alpha, int32_t beta,
+ int8_t *tc0)
+{
+ avc_h_loop_filter_chroma422_msa(src, ystride, alpha, beta, tc0);
+}
+
+void ff_h264_h_loop_filter_chroma422_mbaff_msa(uint8_t *src,
+ int32_t ystride,
+ int32_t alpha,
+ int32_t beta,
+ int8_t *tc0)
+{
+ avc_h_loop_filter_chroma422_mbaff_msa(src, ystride, alpha, beta, tc0);
+}
+
+void ff_h264_h_loop_filter_luma_mbaff_msa(uint8_t *src,
+ int32_t ystride,
+ int32_t alpha,
+ int32_t beta,
+ int8_t *tc0)
+{
+ avc_h_loop_filter_luma_mbaff_msa(src, ystride, alpha, beta, tc0);
+}
+
+void ff_h264_h_loop_filter_luma_mbaff_intra_msa(uint8_t *src,
+ int32_t ystride,
+ int32_t alpha,
+ int32_t beta)
+{
+ avc_h_loop_filter_luma_mbaff_intra_msa(src, ystride, alpha, beta);
+}
+
+void ff_weight_h264_pixels16_8_msa(uint8_t *src, int stride,
+ int height, int log2_denom,
+ int weight_src, int offset)
+{
+ avc_wgt_16width_msa(src, stride,
+ height, log2_denom, weight_src, offset);
+}
+
+void ff_weight_h264_pixels8_8_msa(uint8_t *src, int stride,
+ int height, int log2_denom,
+ int weight_src, int offset)
+{
+ avc_wgt_8width_msa(src, stride,
+ height, log2_denom, weight_src, offset);
+}
+
+void ff_weight_h264_pixels4_8_msa(uint8_t *src, int stride,
+ int height, int log2_denom,
+ int weight_src, int offset)
+{
+ avc_wgt_4width_msa(src, stride,
+ height, log2_denom, weight_src, offset);
+}
+
+void ff_biweight_h264_pixels16_8_msa(uint8_t *dst, uint8_t *src,
+ int stride, int height,
+ int log2_denom, int weight_dst,
+ int weight_src, int offset)
+{
+ avc_biwgt_16width_msa(src, stride,
+ dst, stride,
+ height, log2_denom,
+ weight_src, weight_dst, offset);
+}
+
+void ff_biweight_h264_pixels8_8_msa(uint8_t *dst, uint8_t *src,
+ int stride, int height,
+ int log2_denom, int weight_dst,
+ int weight_src, int offset)
+{
+ avc_biwgt_8width_msa(src, stride,
+ dst, stride,
+ height, log2_denom,
+ weight_src, weight_dst, offset);
+}
+
+void ff_biweight_h264_pixels4_8_msa(uint8_t *dst, uint8_t *src,
+ int stride, int height,
+ int log2_denom, int weight_dst,
+ int weight_src, int offset)
+{
+ avc_biwgt_4width_msa(src, stride,
+ dst, stride,
+ height, log2_denom,
+ weight_src, weight_dst, offset);
+}
diff --git a/libavcodec/mips/hevcdsp_init_mips.c b/libavcodec/mips/hevcdsp_init_mips.c
new file mode 100644
index 0000000000..d2e3c60546
--- /dev/null
+++ b/libavcodec/mips/hevcdsp_init_mips.c
@@ -0,0 +1,108 @@
+/*
+ * 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
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/mips/hevcdsp_mips.h"
+
+#if HAVE_MSA
+static av_cold void hevc_dsp_init_msa(HEVCDSPContext *c,
+ const int bit_depth)
+{
+ if (8 == bit_depth) {
+ c->put_hevc_qpel[1][0][0] = ff_hevc_put_hevc_pel_pixels4_8_msa;
+ c->put_hevc_qpel[2][0][0] = ff_hevc_put_hevc_pel_pixels6_8_msa;
+ c->put_hevc_qpel[3][0][0] = ff_hevc_put_hevc_pel_pixels8_8_msa;
+ c->put_hevc_qpel[4][0][0] = ff_hevc_put_hevc_pel_pixels12_8_msa;
+ c->put_hevc_qpel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_8_msa;
+ c->put_hevc_qpel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_8_msa;
+ c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_msa;
+ c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_msa;
+ c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_msa;
+
+ c->put_hevc_qpel[1][0][1] = ff_hevc_put_hevc_qpel_h4_8_msa;
+ c->put_hevc_qpel[3][0][1] = ff_hevc_put_hevc_qpel_h8_8_msa;
+ c->put_hevc_qpel[4][0][1] = ff_hevc_put_hevc_qpel_h12_8_msa;
+ c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_8_msa;
+ c->put_hevc_qpel[6][0][1] = ff_hevc_put_hevc_qpel_h24_8_msa;
+ c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_msa;
+ c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_8_msa;
+ c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_msa;
+
+ c->put_hevc_qpel[1][1][0] = ff_hevc_put_hevc_qpel_v4_8_msa;
+ c->put_hevc_qpel[3][1][0] = ff_hevc_put_hevc_qpel_v8_8_msa;
+ c->put_hevc_qpel[4][1][0] = ff_hevc_put_hevc_qpel_v12_8_msa;
+ c->put_hevc_qpel[5][1][0] = ff_hevc_put_hevc_qpel_v16_8_msa;
+ c->put_hevc_qpel[6][1][0] = ff_hevc_put_hevc_qpel_v24_8_msa;
+ c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_8_msa;
+ c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_8_msa;
+ c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_8_msa;
+
+ c->put_hevc_qpel[1][1][1] = ff_hevc_put_hevc_qpel_hv4_8_msa;
+ c->put_hevc_qpel[3][1][1] = ff_hevc_put_hevc_qpel_hv8_8_msa;
+ c->put_hevc_qpel[4][1][1] = ff_hevc_put_hevc_qpel_hv12_8_msa;
+ c->put_hevc_qpel[5][1][1] = ff_hevc_put_hevc_qpel_hv16_8_msa;
+ c->put_hevc_qpel[6][1][1] = ff_hevc_put_hevc_qpel_hv24_8_msa;
+ c->put_hevc_qpel[7][1][1] = ff_hevc_put_hevc_qpel_hv32_8_msa;
+ c->put_hevc_qpel[8][1][1] = ff_hevc_put_hevc_qpel_hv48_8_msa;
+ c->put_hevc_qpel[9][1][1] = ff_hevc_put_hevc_qpel_hv64_8_msa;
+
+ c->put_hevc_qpel_uni[3][0][0] = ff_hevc_put_hevc_uni_pel_pixels8_8_msa;
+ c->put_hevc_qpel_uni[4][0][0] = ff_hevc_put_hevc_uni_pel_pixels12_8_msa;
+ c->put_hevc_qpel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels16_8_msa;
+ c->put_hevc_qpel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels24_8_msa;
+ c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_msa;
+ c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_msa;
+ c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_msa;
+
+ c->put_hevc_qpel_uni[1][0][1] = ff_hevc_put_hevc_uni_qpel_h4_8_msa;
+ c->put_hevc_qpel_uni[3][0][1] = ff_hevc_put_hevc_uni_qpel_h8_8_msa;
+ c->put_hevc_qpel_uni[4][0][1] = ff_hevc_put_hevc_uni_qpel_h12_8_msa;
+ c->put_hevc_qpel_uni[5][0][1] = ff_hevc_put_hevc_uni_qpel_h16_8_msa;
+ c->put_hevc_qpel_uni[6][0][1] = ff_hevc_put_hevc_uni_qpel_h24_8_msa;
+ c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_8_msa;
+ c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_8_msa;
+ c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_8_msa;
+
+ c->put_hevc_qpel_uni[1][1][0] = ff_hevc_put_hevc_uni_qpel_v4_8_msa;
+ c->put_hevc_qpel_uni[3][1][0] = ff_hevc_put_hevc_uni_qpel_v8_8_msa;
+ c->put_hevc_qpel_uni[4][1][0] = ff_hevc_put_hevc_uni_qpel_v12_8_msa;
+ c->put_hevc_qpel_uni[5][1][0] = ff_hevc_put_hevc_uni_qpel_v16_8_msa;
+ c->put_hevc_qpel_uni[6][1][0] = ff_hevc_put_hevc_uni_qpel_v24_8_msa;
+ c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_8_msa;
+ c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_8_msa;
+ c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_8_msa;
+
+ c->put_hevc_qpel_uni[1][1][1] = ff_hevc_put_hevc_uni_qpel_hv4_8_msa;
+ c->put_hevc_qpel_uni[3][1][1] = ff_hevc_put_hevc_uni_qpel_hv8_8_msa;
+ c->put_hevc_qpel_uni[4][1][1] = ff_hevc_put_hevc_uni_qpel_hv12_8_msa;
+ c->put_hevc_qpel_uni[5][1][1] = ff_hevc_put_hevc_uni_qpel_hv16_8_msa;
+ c->put_hevc_qpel_uni[6][1][1] = ff_hevc_put_hevc_uni_qpel_hv24_8_msa;
+ c->put_hevc_qpel_uni[7][1][1] = ff_hevc_put_hevc_uni_qpel_hv32_8_msa;
+ c->put_hevc_qpel_uni[8][1][1] = ff_hevc_put_hevc_uni_qpel_hv48_8_msa;
+ c->put_hevc_qpel_uni[9][1][1] = ff_hevc_put_hevc_uni_qpel_hv64_8_msa;
+ }
+}
+#endif // #if HAVE_MSA
+
+void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth)
+{
+#if HAVE_MSA
+ hevc_dsp_init_msa(c, bit_depth);
+#endif // #if HAVE_MSA
+}
diff --git a/libavcodec/mips/hevcdsp_mips.h b/libavcodec/mips/hevcdsp_mips.h
new file mode 100644
index 0000000000..a8c8848b30
--- /dev/null
+++ b/libavcodec/mips/hevcdsp_mips.h
@@ -0,0 +1,118 @@
+/*
+ * 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
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/hevcdsp.h"
+
+#define MC(PEL, DIR, WIDTH) \
+void ff_hevc_put_hevc_##PEL##_##DIR####WIDTH##_8_msa(int16_t *dst, \
+ uint8_t *src, \
+ ptrdiff_t src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width)
+
+MC(pel, pixels, 4);
+MC(pel, pixels, 6);
+MC(pel, pixels, 8);
+MC(pel, pixels, 12);
+MC(pel, pixels, 16);
+MC(pel, pixels, 24);
+MC(pel, pixels, 32);
+MC(pel, pixels, 48);
+MC(pel, pixels, 64);
+
+MC(qpel, h, 4);
+MC(qpel, h, 8);
+MC(qpel, h, 12);
+MC(qpel, h, 16);
+MC(qpel, h, 24);
+MC(qpel, h, 32);
+MC(qpel, h, 48);
+MC(qpel, h, 64);
+
+MC(qpel, v, 4);
+MC(qpel, v, 8);
+MC(qpel, v, 12);
+MC(qpel, v, 16);
+MC(qpel, v, 24);
+MC(qpel, v, 32);
+MC(qpel, v, 48);
+MC(qpel, v, 64);
+
+MC(qpel, hv, 4);
+MC(qpel, hv, 8);
+MC(qpel, hv, 12);
+MC(qpel, hv, 16);
+MC(qpel, hv, 24);
+MC(qpel, hv, 32);
+MC(qpel, hv, 48);
+MC(qpel, hv, 64);
+
+#undef MC
+
+#define UNI_MC(PEL, DIR, WIDTH) \
+void ff_hevc_put_hevc_uni_##PEL##_##DIR####WIDTH##_8_msa(uint8_t *dst, \
+ ptrdiff_t dst_stride, \
+ uint8_t *src, \
+ ptrdiff_t src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width)
+
+UNI_MC(pel, pixels, 4);
+UNI_MC(pel, pixels, 6);
+UNI_MC(pel, pixels, 8);
+UNI_MC(pel, pixels, 12);
+UNI_MC(pel, pixels, 16);
+UNI_MC(pel, pixels, 24);
+UNI_MC(pel, pixels, 32);
+UNI_MC(pel, pixels, 48);
+UNI_MC(pel, pixels, 64);
+
+UNI_MC(qpel, h, 4);
+UNI_MC(qpel, h, 8);
+UNI_MC(qpel, h, 12);
+UNI_MC(qpel, h, 16);
+UNI_MC(qpel, h, 24);
+UNI_MC(qpel, h, 32);
+UNI_MC(qpel, h, 48);
+UNI_MC(qpel, h, 64);
+
+UNI_MC(qpel, v, 4);
+UNI_MC(qpel, v, 8);
+UNI_MC(qpel, v, 12);
+UNI_MC(qpel, v, 16);
+UNI_MC(qpel, v, 24);
+UNI_MC(qpel, v, 32);
+UNI_MC(qpel, v, 48);
+UNI_MC(qpel, v, 64);
+
+UNI_MC(qpel, hv, 4);
+UNI_MC(qpel, hv, 8);
+UNI_MC(qpel, hv, 12);
+UNI_MC(qpel, hv, 16);
+UNI_MC(qpel, hv, 24);
+UNI_MC(qpel, hv, 32);
+UNI_MC(qpel, hv, 48);
+UNI_MC(qpel, hv, 64);
+
+#undef UNI_MC
diff --git a/libavcodec/mips/hevcdsp_msa.c b/libavcodec/mips/hevcdsp_msa.c
new file mode 100644
index 0000000000..781264d1f4
--- /dev/null
+++ b/libavcodec/mips/hevcdsp_msa.c
@@ -0,0 +1,4691 @@
+/*
+ * 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
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/mips/generic_macros_msa.h"
+#include "libavcodec/mips/hevcdsp_mips.h"
+
+#define HEVC_FILT_8TAP_DPADD_W(vec0, vec1, vec2, vec3, \
+ filt0, filt1, filt2, filt3) \
+( { \
+ v4i32 out; \
+ \
+ out = __msa_dotp_s_w((v8i16) (vec0), (v8i16) (filt0)); \
+ out = __msa_dpadd_s_w(out, (v8i16) (vec1), (v8i16) (filt1)); \
+ out = __msa_dpadd_s_w(out, (v8i16) (vec2), (v8i16) (filt2)); \
+ out = __msa_dpadd_s_w(out, (v8i16) (vec3), (v8i16) (filt3)); \
+ out; \
+} )
+
+#define HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3, \
+ filt0, filt1, filt2, filt3, \
+ var_in) \
+( { \
+ v8i16 out; \
+ \
+ out = __msa_dpadd_s_h((v8i16) (var_in), (v16i8) (vec0), (v16i8) (filt0)); \
+ out = __msa_dpadd_s_h(out, (v16i8) (vec1), (v16i8) (filt1)); \
+ out = __msa_dpadd_s_h(out, (v16i8) (vec2), (v16i8) (filt2)); \
+ out = __msa_dpadd_s_h(out, (v16i8) (vec3), (v16i8) (filt3)); \
+ out; \
+} )
+
+#define HEVC_RND_W_CLIP_UNSIGNED_CHAR_W_VEC2(vec0_r, vec0_l, \
+ vec1_r, vec1_l, \
+ out0, out1) \
+{ \
+ (vec0_r) = __msa_srari_w((vec0_r), 6); \
+ (vec0_l) = __msa_srari_w((vec0_l), 6); \
+ (vec1_r) = __msa_srari_w((vec1_r), 6); \
+ (vec1_l) = __msa_srari_w((vec1_l), 6); \
+ \
+ (vec0_r) = CLIP_UNSIGNED_CHAR_W((vec0_r)); \
+ (vec0_l) = CLIP_UNSIGNED_CHAR_W((vec0_l)); \
+ (vec1_r) = CLIP_UNSIGNED_CHAR_W((vec1_r)); \
+ (vec1_l) = CLIP_UNSIGNED_CHAR_W((vec1_l)); \
+ \
+ out0 = (v4i32) __msa_pckev_h((v8i16) (vec0_l), (v8i16) (vec0_r)); \
+ out1 = (v4i32) __msa_pckev_h((v8i16) (vec1_l), (v8i16) (vec1_r)); \
+}
+
+static void hevc_copy_4w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ v16i8 zero = { 0 };
+
+ if (2 == height) {
+ uint64_t out0, out1;
+ v16i8 src0, src1;
+ v8i16 input0;
+
+ LOAD_2VECS_SB(src, src_stride, src0, src1);
+
+ src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+
+ input0 <<= 6;
+
+ out0 = __msa_copy_u_d((v2i64) input0, 0);
+ out1 = __msa_copy_u_d((v2i64) input0, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ } else if (4 == height) {
+ uint64_t out0, out1, out2, out3;
+ v16i8 src0, src1, src2, src3;
+ v8i16 input0, input1;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+
+ src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0);
+ src1 = (v16i8) __msa_ilvr_w((v4i32) src3, (v4i32) src2);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+
+ input0 <<= 6;
+ input1 <<= 6;
+
+ out0 = __msa_copy_u_d((v2i64) input0, 0);
+ out1 = __msa_copy_u_d((v2i64) input0, 1);
+ out2 = __msa_copy_u_d((v2i64) input1, 0);
+ out3 = __msa_copy_u_d((v2i64) input1, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ } else if (0 == height % 8) {
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ uint64_t out0, out1, out2, out3, out4, out5, out6, out7;
+ v8i16 input0, input1, input2, input3;
+ uint32_t loop_cnt;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0);
+ src1 = (v16i8) __msa_ilvr_w((v4i32) src3, (v4i32) src2);
+ src2 = (v16i8) __msa_ilvr_w((v4i32) src5, (v4i32) src4);
+ src3 = (v16i8) __msa_ilvr_w((v4i32) src7, (v4i32) src6);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+ input2 = (v8i16) __msa_ilvr_b(zero, src2);
+ input3 = (v8i16) __msa_ilvr_b(zero, src3);
+
+ input0 <<= 6;
+ input1 <<= 6;
+ input2 <<= 6;
+ input3 <<= 6;
+
+ out0 = __msa_copy_u_d((v2i64) input0, 0);
+ out1 = __msa_copy_u_d((v2i64) input0, 1);
+ out2 = __msa_copy_u_d((v2i64) input1, 0);
+ out3 = __msa_copy_u_d((v2i64) input1, 1);
+ out4 = __msa_copy_u_d((v2i64) input2, 0);
+ out5 = __msa_copy_u_d((v2i64) input2, 1);
+ out6 = __msa_copy_u_d((v2i64) input3, 0);
+ out7 = __msa_copy_u_d((v2i64) input3, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+ STORE_DWORD(dst, out4);
+ dst += dst_stride;
+ STORE_DWORD(dst, out5);
+ dst += dst_stride;
+ STORE_DWORD(dst, out6);
+ dst += dst_stride;
+ STORE_DWORD(dst, out7);
+ dst += dst_stride;
+ }
+ }
+}
+
+static void hevc_copy_6w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ uint32_t loop_cnt;
+ uint64_t out0, out1, out2, out3, out4, out5, out6, out7;
+ uint32_t out8, out9, out10, out11, out12, out13, out14, out15;
+ v16i8 zero = { 0 };
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v8i16 input0, input1, input2, input3, input4, input5, input6, input7;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+ input2 = (v8i16) __msa_ilvr_b(zero, src2);
+ input3 = (v8i16) __msa_ilvr_b(zero, src3);
+ input4 = (v8i16) __msa_ilvr_b(zero, src4);
+ input5 = (v8i16) __msa_ilvr_b(zero, src5);
+ input6 = (v8i16) __msa_ilvr_b(zero, src6);
+ input7 = (v8i16) __msa_ilvr_b(zero, src7);
+
+ input0 <<= 6;
+ input1 <<= 6;
+ input2 <<= 6;
+ input3 <<= 6;
+ input4 <<= 6;
+ input5 <<= 6;
+ input6 <<= 6;
+ input7 <<= 6;
+
+ out0 = __msa_copy_u_d((v2i64) input0, 0);
+ out1 = __msa_copy_u_d((v2i64) input1, 0);
+ out2 = __msa_copy_u_d((v2i64) input2, 0);
+ out3 = __msa_copy_u_d((v2i64) input3, 0);
+ out4 = __msa_copy_u_d((v2i64) input4, 0);
+ out5 = __msa_copy_u_d((v2i64) input5, 0);
+ out6 = __msa_copy_u_d((v2i64) input6, 0);
+ out7 = __msa_copy_u_d((v2i64) input7, 0);
+
+ out8 = __msa_copy_u_w((v4i32) input0, 2);
+ out9 = __msa_copy_u_w((v4i32) input1, 2);
+ out10 = __msa_copy_u_w((v4i32) input2, 2);
+ out11 = __msa_copy_u_w((v4i32) input3, 2);
+ out12 = __msa_copy_u_w((v4i32) input4, 2);
+ out13 = __msa_copy_u_w((v4i32) input5, 2);
+ out14 = __msa_copy_u_w((v4i32) input6, 2);
+ out15 = __msa_copy_u_w((v4i32) input7, 2);
+
+ STORE_DWORD(dst, out0);
+ STORE_WORD(dst + 4, out8);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ STORE_WORD(dst + 4, out9);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ STORE_WORD(dst + 4, out10);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ STORE_WORD(dst + 4, out11);
+ dst += dst_stride;
+ STORE_DWORD(dst, out4);
+ STORE_WORD(dst + 4, out12);
+ dst += dst_stride;
+ STORE_DWORD(dst, out5);
+ STORE_WORD(dst + 4, out13);
+ dst += dst_stride;
+ STORE_DWORD(dst, out6);
+ STORE_WORD(dst + 4, out14);
+ dst += dst_stride;
+ STORE_DWORD(dst, out7);
+ STORE_WORD(dst + 4, out15);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_copy_8w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ v16i8 zero = { 0 };
+
+ if (2 == height) {
+ v16i8 src0, src1;
+ v8i16 input0, input1;
+
+ LOAD_2VECS_SB(src, src_stride, src0, src1);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+
+ input0 <<= 6;
+ input1 <<= 6;
+
+ STORE_2VECS_SH(dst, dst_stride, input0, input1);
+ } else if (4 == height) {
+ v16i8 src0, src1, src2, src3;
+ v8i16 input0, input1, input2, input3;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+ input2 = (v8i16) __msa_ilvr_b(zero, src2);
+ input3 = (v8i16) __msa_ilvr_b(zero, src3);
+
+ input0 <<= 6;
+ input1 <<= 6;
+ input2 <<= 6;
+ input3 <<= 6;
+
+ STORE_4VECS_SH(dst, dst_stride, input0, input1, input2, input3);
+ } else if (6 == height) {
+ v16i8 src0, src1, src2, src3, src4, src5;
+ v8i16 input0, input1, input2, input3, input4, input5;
+
+ LOAD_6VECS_SB(src, src_stride, src0, src1, src2, src3, src4, src5);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+ input2 = (v8i16) __msa_ilvr_b(zero, src2);
+ input3 = (v8i16) __msa_ilvr_b(zero, src3);
+ input4 = (v8i16) __msa_ilvr_b(zero, src4);
+ input5 = (v8i16) __msa_ilvr_b(zero, src5);
+
+ input0 <<= 6;
+ input1 <<= 6;
+ input2 <<= 6;
+ input3 <<= 6;
+ input4 <<= 6;
+ input5 <<= 6;
+
+ STORE_6VECS_SH(dst, dst_stride,
+ input0, input1, input2, input3, input4, input5);
+ } else if (0 == height % 8) {
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v8i16 input0, input1, input2, input3;
+ v8i16 input4, input5, input6, input7;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+ input2 = (v8i16) __msa_ilvr_b(zero, src2);
+ input3 = (v8i16) __msa_ilvr_b(zero, src3);
+ input4 = (v8i16) __msa_ilvr_b(zero, src4);
+ input5 = (v8i16) __msa_ilvr_b(zero, src5);
+ input6 = (v8i16) __msa_ilvr_b(zero, src6);
+ input7 = (v8i16) __msa_ilvr_b(zero, src7);
+
+ input0 <<= 6;
+ input1 <<= 6;
+ input2 <<= 6;
+ input3 <<= 6;
+ input4 <<= 6;
+ input5 <<= 6;
+ input6 <<= 6;
+ input7 <<= 6;
+
+ STORE_8VECS_SH(dst, dst_stride,
+ input0, input1, input2, input3,
+ input4, input5, input6, input7);
+ dst += (8 * dst_stride);
+ }
+ }
+}
+
+static void hevc_copy_12w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ uint32_t loop_cnt;
+ uint64_t dst_val0, dst_val1, dst_val2, dst_val3;
+ v16i8 zero = { 0 };
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v8i16 input0, input1;
+ v8i16 input0_r, input1_r, input2_r, input3_r;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src0);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src1);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src2);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src3);
+
+ input0_r <<= 6;
+ input1_r <<= 6;
+ input2_r <<= 6;
+ input3_r <<= 6;
+
+ src0 = (v16i8) __msa_ilvl_w((v4i32) src1, (v4i32) src0);
+ src1 = (v16i8) __msa_ilvl_w((v4i32) src3, (v4i32) src2);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+
+ input0 <<= 6;
+ input1 <<= 6;
+
+ dst_val0 = __msa_copy_u_d((v2i64) input0, 0);
+ dst_val1 = __msa_copy_u_d((v2i64) input0, 1);
+ dst_val2 = __msa_copy_u_d((v2i64) input1, 0);
+ dst_val3 = __msa_copy_u_d((v2i64) input1, 1);
+
+ STORE_4VECS_SH(dst, dst_stride, input0_r, input1_r, input2_r, input3_r);
+
+ STORE_DWORD(dst + 8, dst_val0);
+ dst += dst_stride;
+ STORE_DWORD(dst + 8, dst_val1);
+ dst += dst_stride;
+ STORE_DWORD(dst + 8, dst_val2);
+ dst += dst_stride;
+ STORE_DWORD(dst + 8, dst_val3);
+ dst += dst_stride;
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src4);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src5);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src6);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src7);
+
+ input0_r <<= 6;
+ input1_r <<= 6;
+ input2_r <<= 6;
+ input3_r <<= 6;
+
+ src0 = (v16i8) __msa_ilvl_w((v4i32) src5, (v4i32) src4);
+ src1 = (v16i8) __msa_ilvl_w((v4i32) src7, (v4i32) src6);
+
+ input0 = (v8i16) __msa_ilvr_b(zero, src0);
+ input1 = (v8i16) __msa_ilvr_b(zero, src1);
+
+ input0 <<= 6;
+ input1 <<= 6;
+
+ dst_val0 = __msa_copy_u_d((v2i64) input0, 0);
+ dst_val1 = __msa_copy_u_d((v2i64) input0, 1);
+ dst_val2 = __msa_copy_u_d((v2i64) input1, 0);
+ dst_val3 = __msa_copy_u_d((v2i64) input1, 1);
+
+ STORE_4VECS_SH(dst, dst_stride, input0_r, input1_r, input2_r, input3_r);
+
+ STORE_DWORD(dst + 8, dst_val0);
+ dst += dst_stride;
+ STORE_DWORD(dst + 8, dst_val1);
+ dst += dst_stride;
+ STORE_DWORD(dst + 8, dst_val2);
+ dst += dst_stride;
+ STORE_DWORD(dst + 8, dst_val3);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_copy_16multx8mult_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ int16_t * __restrict dst,
+ int32_t dst_stride,
+ int32_t height,
+ int32_t width)
+{
+ uint8_t *src_tmp;
+ int16_t *dst_tmp;
+ uint32_t loop_cnt, cnt;
+ v16i8 zero = { 0 };
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v8i16 input0_r, input1_r, input2_r, input3_r;
+ v8i16 input0_l, input1_l, input2_l, input3_l;
+
+ for (cnt = (width >> 4); cnt--;) {
+ src_tmp = src;
+ dst_tmp = dst;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src_tmp, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src_tmp += (8 * src_stride);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src0);
+ input0_l = (v8i16) __msa_ilvl_b(zero, src0);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src1);
+ input1_l = (v8i16) __msa_ilvl_b(zero, src1);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src2);
+ input2_l = (v8i16) __msa_ilvl_b(zero, src2);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src3);
+ input3_l = (v8i16) __msa_ilvl_b(zero, src3);
+
+ input0_r <<= 6;
+ input0_l <<= 6;
+ input1_r <<= 6;
+ input1_l <<= 6;
+ input2_r <<= 6;
+ input2_l <<= 6;
+ input3_r <<= 6;
+ input3_l <<= 6;
+
+ STORE_4VECS_SH(dst_tmp, dst_stride,
+ input0_r, input1_r, input2_r, input3_r);
+ STORE_4VECS_SH((dst_tmp + 8), dst_stride,
+ input0_l, input1_l, input2_l, input3_l);
+ dst_tmp += (4 * dst_stride);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src4);
+ input0_l = (v8i16) __msa_ilvl_b(zero, src4);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src5);
+ input1_l = (v8i16) __msa_ilvl_b(zero, src5);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src6);
+ input2_l = (v8i16) __msa_ilvl_b(zero, src6);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src7);
+ input3_l = (v8i16) __msa_ilvl_b(zero, src7);
+
+ input0_r <<= 6;
+ input0_l <<= 6;
+ input1_r <<= 6;
+ input1_l <<= 6;
+ input2_r <<= 6;
+ input2_l <<= 6;
+ input3_r <<= 6;
+ input3_l <<= 6;
+
+ STORE_4VECS_SH(dst_tmp, dst_stride,
+ input0_r, input1_r, input2_r, input3_r);
+ STORE_4VECS_SH((dst_tmp + 8), dst_stride,
+ input0_l, input1_l, input2_l, input3_l);
+ dst_tmp += (4 * dst_stride);
+ }
+
+ src += 16;
+ dst += 16;
+ }
+}
+
+static void hevc_copy_16w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ v16i8 zero = { 0 };
+
+ if (4 == height) {
+ v16i8 src0, src1, src2, src3;
+ v8i16 input0_r, input1_r, input2_r, input3_r;
+ v8i16 input0_l, input1_l, input2_l, input3_l;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src0);
+ input0_l = (v8i16) __msa_ilvl_b(zero, src0);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src1);
+ input1_l = (v8i16) __msa_ilvl_b(zero, src1);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src2);
+ input2_l = (v8i16) __msa_ilvl_b(zero, src2);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src3);
+ input3_l = (v8i16) __msa_ilvl_b(zero, src3);
+
+ input0_r <<= 6;
+ input0_l <<= 6;
+ input1_r <<= 6;
+ input1_l <<= 6;
+ input2_r <<= 6;
+ input2_l <<= 6;
+ input3_r <<= 6;
+ input3_l <<= 6;
+
+ STORE_4VECS_SH(dst, dst_stride, input0_r, input1_r, input2_r, input3_r);
+ STORE_4VECS_SH((dst + 8), dst_stride,
+ input0_l, input1_l, input2_l, input3_l);
+ } else if (12 == height) {
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v16i8 src8, src9, src10, src11;
+ v8i16 input0_r, input1_r, input2_r, input3_r;
+ v8i16 input0_l, input1_l, input2_l, input3_l;
+
+ LOAD_8VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ LOAD_4VECS_SB(src, src_stride, src8, src9, src10, src11);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src0);
+ input0_l = (v8i16) __msa_ilvl_b(zero, src0);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src1);
+ input1_l = (v8i16) __msa_ilvl_b(zero, src1);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src2);
+ input2_l = (v8i16) __msa_ilvl_b(zero, src2);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src3);
+ input3_l = (v8i16) __msa_ilvl_b(zero, src3);
+
+ input0_r <<= 6;
+ input0_l <<= 6;
+ input1_r <<= 6;
+ input1_l <<= 6;
+ input2_r <<= 6;
+ input2_l <<= 6;
+ input3_r <<= 6;
+ input3_l <<= 6;
+
+ STORE_4VECS_SH(dst, dst_stride, input0_r, input1_r, input2_r, input3_r);
+ STORE_4VECS_SH((dst + 8), dst_stride,
+ input0_l, input1_l, input2_l, input3_l);
+ dst += (4 * dst_stride);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src4);
+ input0_l = (v8i16) __msa_ilvl_b(zero, src4);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src5);
+ input1_l = (v8i16) __msa_ilvl_b(zero, src5);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src6);
+ input2_l = (v8i16) __msa_ilvl_b(zero, src6);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src7);
+ input3_l = (v8i16) __msa_ilvl_b(zero, src7);
+
+ input0_r <<= 6;
+ input0_l <<= 6;
+ input1_r <<= 6;
+ input1_l <<= 6;
+ input2_r <<= 6;
+ input2_l <<= 6;
+ input3_r <<= 6;
+ input3_l <<= 6;
+
+ STORE_4VECS_SH(dst, dst_stride, input0_r, input1_r, input2_r, input3_r);
+ STORE_4VECS_SH((dst + 8), dst_stride,
+ input0_l, input1_l, input2_l, input3_l);
+ dst += (4 * dst_stride);
+
+ input0_r = (v8i16) __msa_ilvr_b(zero, src8);
+ input0_l = (v8i16) __msa_ilvl_b(zero, src8);
+ input1_r = (v8i16) __msa_ilvr_b(zero, src9);
+ input1_l = (v8i16) __msa_ilvl_b(zero, src9);
+ input2_r = (v8i16) __msa_ilvr_b(zero, src10);
+ input2_l = (v8i16) __msa_ilvl_b(zero, src10);
+ input3_r = (v8i16) __msa_ilvr_b(zero, src11);
+ input3_l = (v8i16) __msa_ilvl_b(zero, src11);
+
+ input0_r <<= 6;
+ input0_l <<= 6;
+ input1_r <<= 6;
+ input1_l <<= 6;
+ input2_r <<= 6;
+ input2_l <<= 6;
+ input3_r <<= 6;
+ input3_l <<= 6;
+
+ STORE_4VECS_SH(dst, dst_stride, input0_r, input1_r, input2_r, input3_r);
+ STORE_4VECS_SH((dst + 8), dst_stride,
+ input0_l, input1_l, input2_l, input3_l);
+ } else if (0 == (height % 8)) {
+ hevc_copy_16multx8mult_msa(src, src_stride, dst, dst_stride,
+ height, 16);
+ }
+}
+
+static void hevc_copy_24w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ hevc_copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 16);
+
+ hevc_copy_8w_msa(src + 16, src_stride, dst + 16, dst_stride, height);
+}
+
+static void hevc_copy_32w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ hevc_copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 32);
+}
+
+static void hevc_copy_48w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ hevc_copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 48);
+}
+
+static void hevc_copy_64w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ int32_t height)
+{
+ hevc_copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 64);
+}
+
+static void hevc_hz_8t_4w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ uint64_t out0, out1, out2, out3, out4, out5, out6, out7;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3;
+ v8i16 filter_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 };
+
+ src -= 3;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ XORI_B_8VECS_SB(src0, src1, src2, src3, src4, src5, src6, src7,
+ src0, src1, src2, src3, src4, src5, src6, src7, 128);
+
+ vec0 = __msa_vshf_b(mask0, src1, src0);
+ vec1 = __msa_vshf_b(mask1, src1, src0);
+ vec2 = __msa_vshf_b(mask2, src1, src0);
+ vec3 = __msa_vshf_b(mask3, src1, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src3, src2);
+ vec1 = __msa_vshf_b(mask1, src3, src2);
+ vec2 = __msa_vshf_b(mask2, src3, src2);
+ vec3 = __msa_vshf_b(mask3, src3, src2);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src5, src4);
+ vec1 = __msa_vshf_b(mask1, src5, src4);
+ vec2 = __msa_vshf_b(mask2, src5, src4);
+ vec3 = __msa_vshf_b(mask3, src5, src4);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src7, src6);
+ vec1 = __msa_vshf_b(mask1, src7, src6);
+ vec2 = __msa_vshf_b(mask2, src7, src6);
+ vec3 = __msa_vshf_b(mask3, src7, src6);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ out0 = __msa_copy_u_d((v2i64) dst0, 0);
+ out1 = __msa_copy_u_d((v2i64) dst0, 1);
+ out2 = __msa_copy_u_d((v2i64) dst1, 0);
+ out3 = __msa_copy_u_d((v2i64) dst1, 1);
+ out4 = __msa_copy_u_d((v2i64) dst2, 0);
+ out5 = __msa_copy_u_d((v2i64) dst2, 1);
+ out6 = __msa_copy_u_d((v2i64) dst3, 0);
+ out7 = __msa_copy_u_d((v2i64) dst3, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+ STORE_DWORD(dst, out4);
+ dst += dst_stride;
+ STORE_DWORD(dst, out5);
+ dst += dst_stride;
+ STORE_DWORD(dst, out6);
+ dst += dst_stride;
+ STORE_DWORD(dst, out7);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_hz_8t_8w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3;
+ v8i16 filter_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= 3;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src1, src1);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ vec3 = __msa_vshf_b(mask3, src1, src1);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src2, src2);
+ vec1 = __msa_vshf_b(mask1, src2, src2);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec3 = __msa_vshf_b(mask3, src2, src2);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src3, src3);
+ vec1 = __msa_vshf_b(mask1, src3, src3);
+ vec2 = __msa_vshf_b(mask2, src3, src3);
+ vec3 = __msa_vshf_b(mask3, src3, src3);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0, dst);
+ dst += dst_stride;
+ STORE_SH(dst1, dst);
+ dst += dst_stride;
+ STORE_SH(dst2, dst);
+ dst += dst_stride;
+ STORE_SH(dst3, dst);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_hz_8t_12w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ hevc_hz_8t_8w_msa(src, src_stride, dst, dst_stride, filter, height);
+
+ hevc_hz_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, filter, height);
+}
+
+static void hevc_hz_8t_16w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7;
+ v8i16 filter_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= 3;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src0, src2, src4, src6);
+ LOAD_4VECS_SB(src + 8, src_stride, src1, src3, src5, src7);
+ src += (4 * src_stride);
+
+ XORI_B_8VECS_SB(src0, src1, src2, src3, src4, src5, src6, src7,
+ src0, src1, src2, src3, src4, src5, src6, src7, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src1, src1);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ vec3 = __msa_vshf_b(mask3, src1, src1);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src2, src2);
+ vec1 = __msa_vshf_b(mask1, src2, src2);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec3 = __msa_vshf_b(mask3, src2, src2);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src3, src3);
+ vec1 = __msa_vshf_b(mask1, src3, src3);
+ vec2 = __msa_vshf_b(mask2, src3, src3);
+ vec3 = __msa_vshf_b(mask3, src3, src3);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src4, src4);
+ vec1 = __msa_vshf_b(mask1, src4, src4);
+ vec2 = __msa_vshf_b(mask2, src4, src4);
+ vec3 = __msa_vshf_b(mask3, src4, src4);
+
+ dst4 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src5, src5);
+ vec1 = __msa_vshf_b(mask1, src5, src5);
+ vec2 = __msa_vshf_b(mask2, src5, src5);
+ vec3 = __msa_vshf_b(mask3, src5, src5);
+
+ dst5 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src6, src6);
+ vec1 = __msa_vshf_b(mask1, src6, src6);
+ vec2 = __msa_vshf_b(mask2, src6, src6);
+ vec3 = __msa_vshf_b(mask3, src6, src6);
+
+ dst6 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src7, src7);
+ vec1 = __msa_vshf_b(mask1, src7, src7);
+ vec2 = __msa_vshf_b(mask2, src7, src7);
+ vec3 = __msa_vshf_b(mask3, src7, src7);
+
+ dst7 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0, dst);
+ STORE_SH(dst1, dst + 8);
+ dst += dst_stride;
+ STORE_SH(dst2, dst);
+ STORE_SH(dst3, dst + 8);
+ dst += dst_stride;
+ STORE_SH(dst4, dst);
+ STORE_SH(dst5, dst + 8);
+ dst += dst_stride;
+ STORE_SH(dst6, dst);
+ STORE_SH(dst7, dst + 8);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_hz_8t_24w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3, dst4, dst5;
+ v8i16 filter_vec;
+ v8u16 const_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= 3;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+ mask4 = mask0 + 8;
+ mask5 = mask0 + 10;
+ mask6 = mask0 + 12;
+ mask7 = mask0 + 14;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ for (loop_cnt = (height >> 1); loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src1 = LOAD_SB(src + 16);
+ src += src_stride;
+ src2 = LOAD_SB(src);
+ src3 = LOAD_SB(src + 16);
+ src += src_stride;
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask4, src1, src0);
+ vec1 = __msa_vshf_b(mask5, src1, src0);
+ vec2 = __msa_vshf_b(mask6, src1, src0);
+ vec3 = __msa_vshf_b(mask7, src1, src0);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src1, src1);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ vec3 = __msa_vshf_b(mask3, src1, src1);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src2, src2);
+ vec1 = __msa_vshf_b(mask1, src2, src2);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec3 = __msa_vshf_b(mask3, src2, src2);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask4, src3, src2);
+ vec1 = __msa_vshf_b(mask5, src3, src2);
+ vec2 = __msa_vshf_b(mask6, src3, src2);
+ vec3 = __msa_vshf_b(mask7, src3, src2);
+
+ dst4 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src3, src3);
+ vec1 = __msa_vshf_b(mask1, src3, src3);
+ vec2 = __msa_vshf_b(mask2, src3, src3);
+ vec3 = __msa_vshf_b(mask3, src3, src3);
+
+ dst5 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0, dst);
+ STORE_SH(dst1, dst + 8);
+ STORE_SH(dst2, dst + 16);
+ dst += dst_stride;
+ STORE_SH(dst3, dst);
+ STORE_SH(dst4, dst + 8);
+ STORE_SH(dst5, dst + 16);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_hz_8t_32w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3;
+ v8i16 filter_vec;
+ v8u16 const_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= 3;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+ mask4 = mask0 + 8;
+ mask5 = mask0 + 10;
+ mask6 = mask0 + 12;
+ mask7 = mask0 + 14;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ for (loop_cnt = height; loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src1 = LOAD_SB(src + 16);
+ src2 = LOAD_SB(src + 24);
+ src += src_stride;
+
+ XORI_B_3VECS_SB(src0, src1, src2, src0, src1, src2, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask4, src1, src0);
+ vec1 = __msa_vshf_b(mask5, src1, src0);
+ vec2 = __msa_vshf_b(mask6, src1, src0);
+ vec3 = __msa_vshf_b(mask7, src1, src0);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src1, src1);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ vec3 = __msa_vshf_b(mask3, src1, src1);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src2, src2);
+ vec1 = __msa_vshf_b(mask1, src2, src2);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec3 = __msa_vshf_b(mask3, src2, src2);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0, dst);
+ STORE_SH(dst1, dst + 8);
+ STORE_SH(dst2, dst + 16);
+ STORE_SH(dst3, dst + 24);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_hz_8t_48w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3, dst4, dst5;
+ v8i16 filter_vec;
+ v8u16 const_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= 3;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+ mask4 = mask0 + 8;
+ mask5 = mask0 + 10;
+ mask6 = mask0 + 12;
+ mask7 = mask0 + 14;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ for (loop_cnt = height; loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src1 = LOAD_SB(src + 16);
+ src2 = LOAD_SB(src + 32);
+ src3 = LOAD_SB(src + 40);
+ src += src_stride;
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask4, src1, src0);
+ vec1 = __msa_vshf_b(mask5, src1, src0);
+ vec2 = __msa_vshf_b(mask6, src1, src0);
+ vec3 = __msa_vshf_b(mask7, src1, src0);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src1, src1);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ vec3 = __msa_vshf_b(mask3, src1, src1);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask4, src2, src1);
+ vec1 = __msa_vshf_b(mask5, src2, src1);
+ vec2 = __msa_vshf_b(mask6, src2, src1);
+ vec3 = __msa_vshf_b(mask7, src2, src1);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src2, src2);
+ vec1 = __msa_vshf_b(mask1, src2, src2);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec3 = __msa_vshf_b(mask3, src2, src2);
+
+ dst4 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src3, src3);
+ vec1 = __msa_vshf_b(mask1, src3, src3);
+ vec2 = __msa_vshf_b(mask2, src3, src3);
+ vec3 = __msa_vshf_b(mask3, src3, src3);
+
+ dst5 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0, dst);
+ STORE_SH(dst1, dst + 8);
+ STORE_SH(dst2, dst + 16);
+ STORE_SH(dst3, dst + 24);
+ STORE_SH(dst4, dst + 32);
+ STORE_SH(dst5, dst + 40);
+ dst += dst_stride;
+ }
+}
+
+static void hevc_hz_8t_64w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4;
+ v8i16 filt0, filt1, filt2, filt3;
+ v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7;
+ v16i8 vec0, vec1, vec2, vec3;
+ v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7;
+ v8i16 filter_vec;
+ v8u16 const_vec;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= 3;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+ mask4 = mask0 + 8;
+ mask5 = mask0 + 10;
+ mask6 = mask0 + 12;
+ mask7 = mask0 + 14;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ for (loop_cnt = height; loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src1 = LOAD_SB(src + 16);
+ src2 = LOAD_SB(src + 32);
+ src3 = LOAD_SB(src + 48);
+ src4 = LOAD_SB(src + 56);
+ src += src_stride;
+
+ XORI_B_5VECS_SB(src0, src1, src2, src3, src4,
+ src0, src1, src2, src3, src4, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0, dst);
+
+ vec0 = __msa_vshf_b(mask4, src1, src0);
+ vec1 = __msa_vshf_b(mask5, src1, src0);
+ vec2 = __msa_vshf_b(mask6, src1, src0);
+ vec3 = __msa_vshf_b(mask7, src1, src0);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst1, dst + 8);
+
+ vec0 = __msa_vshf_b(mask0, src1, src1);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ vec3 = __msa_vshf_b(mask3, src1, src1);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst2, dst + 16);
+
+ vec0 = __msa_vshf_b(mask4, src2, src1);
+ vec1 = __msa_vshf_b(mask5, src2, src1);
+ vec2 = __msa_vshf_b(mask6, src2, src1);
+ vec3 = __msa_vshf_b(mask7, src2, src1);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst3, dst + 24);
+
+ vec0 = __msa_vshf_b(mask0, src2, src2);
+ vec1 = __msa_vshf_b(mask1, src2, src2);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec3 = __msa_vshf_b(mask3, src2, src2);
+
+ dst4 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst4, dst + 32);
+
+ vec0 = __msa_vshf_b(mask4, src3, src2);
+ vec1 = __msa_vshf_b(mask5, src3, src2);
+ vec2 = __msa_vshf_b(mask6, src3, src2);
+ vec3 = __msa_vshf_b(mask7, src3, src2);
+
+ dst5 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst5, dst + 40);
+
+ vec0 = __msa_vshf_b(mask0, src3, src3);
+ vec1 = __msa_vshf_b(mask1, src3, src3);
+ vec2 = __msa_vshf_b(mask2, src3, src3);
+ vec3 = __msa_vshf_b(mask3, src3, src3);
+
+ dst6 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst6, dst + 48);
+
+ vec0 = __msa_vshf_b(mask0, src4, src4);
+ vec1 = __msa_vshf_b(mask1, src4, src4);
+ vec2 = __msa_vshf_b(mask2, src4, src4);
+ vec3 = __msa_vshf_b(mask3, src4, src4);
+
+ dst7 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst7, dst + 56);
+
+ dst += dst_stride;
+ }
+}
+
+static void hevc_vt_8t_4w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ int32_t loop_cnt;
+ uint64_t out0, out1, out2, out3;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8;
+ v16i8 src9, src10, src11, src12, src13, src14;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v16i8 src1110_r, src1211_r, src1312_r, src1413_r;
+ v16i8 src2110, src4332, src6554, src8776, src10998;
+ v16i8 src12111110, src14131312;
+ v8i16 dst10, dst32, dst54, dst76;
+ v8i16 filter_vec;
+ v8i16 filt0, filt1, filt2, filt3;
+ v8u16 const_vec;
+
+ src -= (3 * src_stride);
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ LOAD_7VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ ILVR_D_3VECS_SB(src2110, src21_r, src10_r, src4332, src43_r, src32_r,
+ src6554, src65_r, src54_r);
+
+ XORI_B_3VECS_SB(src2110, src4332, src6554, src2110, src4332, src6554, 128);
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_SB(src, src_stride,
+ src7, src8, src9, src10, src11, src12, src13, src14);
+ src += (8 * src_stride);
+
+ ILVR_B_8VECS_SB(src6, src7, src8, src9, src10, src11, src12, src13,
+ src7, src8, src9, src10, src11, src12, src13, src14,
+ src76_r, src87_r, src98_r, src109_r,
+ src1110_r, src1211_r, src1312_r, src1413_r);
+
+ ILVR_D_4VECS_SB(src8776, src87_r, src76_r, src10998, src109_r, src98_r,
+ src12111110, src1211_r, src1110_r,
+ src14131312, src1413_r, src1312_r);
+
+ XORI_B_4VECS_SB(src8776, src10998, src12111110, src14131312,
+ src8776, src10998, src12111110, src14131312, 128);
+
+ dst10 = HEVC_FILT_8TAP_DPADD_H(src2110, src4332, src6554, src8776,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst32 = HEVC_FILT_8TAP_DPADD_H(src4332, src6554, src8776, src10998,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst54 = HEVC_FILT_8TAP_DPADD_H(src6554, src8776, src10998, src12111110,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst76 = HEVC_FILT_8TAP_DPADD_H(src8776, src10998,
+ src12111110, src14131312,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ out0 = __msa_copy_u_d((v2i64) dst10, 0);
+ out1 = __msa_copy_u_d((v2i64) dst10, 1);
+ out2 = __msa_copy_u_d((v2i64) dst32, 0);
+ out3 = __msa_copy_u_d((v2i64) dst32, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+
+ out0 = __msa_copy_u_d((v2i64) dst54, 0);
+ out1 = __msa_copy_u_d((v2i64) dst54, 1);
+ out2 = __msa_copy_u_d((v2i64) dst76, 0);
+ out3 = __msa_copy_u_d((v2i64) dst76, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+
+ src2110 = src10998;
+ src4332 = src12111110;
+ src6554 = src14131312;
+
+ src6 = src14;
+ }
+}
+
+static void hevc_vt_8t_8w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ int32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v8i16 dst0_r, dst1_r, dst2_r, dst3_r;
+ v8i16 filter_vec;
+ v8i16 filt0, filt1, filt2, filt3;
+ v8u16 const_vec;
+
+ src -= (3 * src_stride);
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ LOAD_7VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src7, src8, src9, src10);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src7, src8, src9, src10, src7, src8, src9, src10, 128);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_H(src10_r, src32_r, src54_r, src76_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst1_r = HEVC_FILT_8TAP_DPADD_H(src21_r, src43_r, src65_r, src87_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst2_r = HEVC_FILT_8TAP_DPADD_H(src32_r, src54_r, src76_r, src98_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst3_r = HEVC_FILT_8TAP_DPADD_H(src43_r, src65_r, src87_r, src109_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ STORE_SH(dst0_r, dst);
+ dst += dst_stride;
+ STORE_SH(dst1_r, dst);
+ dst += dst_stride;
+ STORE_SH(dst2_r, dst);
+ dst += dst_stride;
+ STORE_SH(dst3_r, dst);
+ dst += dst_stride;
+
+ src10_r = src54_r;
+ src32_r = src76_r;
+ src54_r = src98_r;
+
+ src21_r = src65_r;
+ src43_r = src87_r;
+ src65_r = src109_r;
+
+ src6 = src10;
+ }
+}
+
+static void hevc_vt_8t_12w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ int32_t loop_cnt;
+ uint64_t out0, out1, out2, out3;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v8i16 dst0_r, dst1_r, dst2_r, dst3_r;
+ v16i8 src10_l, src32_l, src54_l, src76_l, src98_l;
+ v16i8 src21_l, src43_l, src65_l, src87_l, src109_l;
+ v16i8 src2110, src4332, src6554, src8776, src10998;
+ v8i16 dst0_l, dst1_l;
+ v8i16 filter_vec;
+ v8i16 filt0, filt1, filt2, filt3;
+ v8u16 const_vec;
+
+ src -= (3 * src_stride);
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ LOAD_7VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ ILVL_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_l, src32_l, src54_l, src21_l, src43_l, src65_l);
+
+ ILVR_D_3VECS_SB(src2110, src21_l, src10_l, src4332, src43_l, src32_l,
+ src6554, src65_l, src54_l);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src7, src8, src9, src10);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src7, src8, src9, src10, src7, src8, src9, src10, 128);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ ILVL_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_l, src87_l, src98_l, src109_l);
+
+ ILVR_D_2VECS_SB(src8776, src87_l, src76_l, src10998, src109_l, src98_l);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_H(src10_r, src32_r, src54_r, src76_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst1_r = HEVC_FILT_8TAP_DPADD_H(src21_r, src43_r, src65_r, src87_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst2_r = HEVC_FILT_8TAP_DPADD_H(src32_r, src54_r, src76_r, src98_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst3_r = HEVC_FILT_8TAP_DPADD_H(src43_r, src65_r, src87_r, src109_r,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst0_l = HEVC_FILT_8TAP_DPADD_H(src2110, src4332, src6554, src8776,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst1_l = HEVC_FILT_8TAP_DPADD_H(src4332, src6554, src8776, src10998,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ out0 = __msa_copy_u_d((v2i64) dst0_l, 0);
+ out1 = __msa_copy_u_d((v2i64) dst0_l, 1);
+ out2 = __msa_copy_u_d((v2i64) dst1_l, 0);
+ out3 = __msa_copy_u_d((v2i64) dst1_l, 1);
+
+ STORE_SH(dst0_r, dst);
+ STORE_DWORD(dst + 8, out0);
+ dst += dst_stride;
+ STORE_SH(dst1_r, dst);
+ STORE_DWORD(dst + 8, out1);
+ dst += dst_stride;
+
+ STORE_SH(dst2_r, dst);
+ STORE_DWORD(dst + 8, out2);
+ dst += dst_stride;
+ STORE_SH(dst3_r, dst);
+ STORE_DWORD(dst + 8, out3);
+ dst += dst_stride;
+
+ src10_r = src54_r;
+ src32_r = src76_r;
+ src54_r = src98_r;
+
+ src21_r = src65_r;
+ src43_r = src87_r;
+ src65_r = src109_r;
+
+ src2110 = src6554;
+ src4332 = src8776;
+ src6554 = src10998;
+
+ src6 = src10;
+ }
+}
+
+static void hevc_vt_8t_16multx4mult_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ int16_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter,
+ int32_t height,
+ int32_t width)
+{
+ uint8_t *src_tmp;
+ int16_t *dst_tmp;
+ int32_t loop_cnt, cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v8i16 dst0_r, dst1_r, dst2_r, dst3_r;
+ v16i8 src10_l, src32_l, src54_l, src76_l, src98_l;
+ v16i8 src21_l, src43_l, src65_l, src87_l, src109_l;
+ v8i16 dst0_l, dst1_l, dst2_l, dst3_l;
+ v8i16 filter_vec;
+ v8i16 filt0, filt1, filt2, filt3;
+ v8u16 const_vec;
+
+ src -= (3 * src_stride);
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ for (cnt = width >> 4; cnt--;) {
+ src_tmp = src;
+ dst_tmp = dst;
+
+ LOAD_7VECS_SB(src_tmp, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src_tmp += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ ILVL_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_l, src32_l, src54_l, src21_l, src43_l, src65_l);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src_tmp, src_stride, src7, src8, src9, src10);
+ src_tmp += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src7, src8, src9, src10,
+ src7, src8, src9, src10, 128);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ ILVL_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_l, src87_l, src98_l, src109_l);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_H(src10_r, src32_r, src54_r, src76_r,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst1_r = HEVC_FILT_8TAP_DPADD_H(src21_r, src43_r, src65_r, src87_r,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst2_r = HEVC_FILT_8TAP_DPADD_H(src32_r, src54_r, src76_r, src98_r,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst3_r = HEVC_FILT_8TAP_DPADD_H(src43_r, src65_r, src87_r, src109_r,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst0_l = HEVC_FILT_8TAP_DPADD_H(src10_l, src32_l, src54_l, src76_l,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst1_l = HEVC_FILT_8TAP_DPADD_H(src21_l, src43_l, src65_l, src87_l,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst2_l = HEVC_FILT_8TAP_DPADD_H(src32_l, src54_l, src76_l, src98_l,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst3_l = HEVC_FILT_8TAP_DPADD_H(src43_l, src65_l, src87_l, src109_l,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ STORE_SH(dst0_r, dst_tmp);
+ STORE_SH(dst0_l, dst_tmp + 8);
+ dst_tmp += dst_stride;
+ STORE_SH(dst1_r, dst_tmp);
+ STORE_SH(dst1_l, dst_tmp + 8);
+ dst_tmp += dst_stride;
+
+ STORE_SH(dst2_r, dst_tmp);
+ STORE_SH(dst2_l, dst_tmp + 8);
+ dst_tmp += dst_stride;
+ STORE_SH(dst3_r, dst_tmp);
+ STORE_SH(dst3_l, dst_tmp + 8);
+ dst_tmp += dst_stride;
+
+ src10_r = src54_r;
+ src32_r = src76_r;
+ src54_r = src98_r;
+
+ src21_r = src65_r;
+ src43_r = src87_r;
+ src65_r = src109_r;
+
+ src10_l = src54_l;
+ src32_l = src76_l;
+ src54_l = src98_l;
+
+ src21_l = src65_l;
+ src43_l = src87_l;
+ src65_l = src109_l;
+
+ src6 = src10;
+ }
+
+ src += 16;
+ dst += 16;
+ }
+}
+
+static void hevc_vt_8t_16w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ hevc_vt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, 16);
+}
+
+static void hevc_vt_8t_24w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ hevc_vt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, 16);
+
+ hevc_vt_8t_8w_msa(src + 16, src_stride, dst + 16, dst_stride,
+ filter, height);
+}
+
+static void hevc_vt_8t_32w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ hevc_vt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, 32);
+}
+
+static void hevc_vt_8t_48w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ hevc_vt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, 48);
+}
+
+static void hevc_vt_8t_64w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter, int32_t height)
+{
+ hevc_vt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, 64);
+}
+
+static void hevc_hv_8t_4w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ uint32_t loop_cnt;
+ uint64_t out0, out1;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8;
+ v8i16 filt0, filt1, filt2, filt3, filter_vec;
+ v4i32 filt_h0, filt_h1, filt_h2, filt_h3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7;
+ v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15;
+ v8i16 dst30, dst41, dst52, dst63, dst66, dst87;
+ v4i32 dst0_r, dst1_r;
+ v8i16 dst10_r, dst32_r, dst54_r, dst76_r;
+ v8i16 dst21_r, dst43_r, dst65_r, dst87_r;
+ v16i8 tmp;
+ v16i8 mask0 = {
+ 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20
+ };
+ v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 };
+
+ src -= ((3 * src_stride) + 3);
+
+ filter_vec = LOAD_SH(filter_x);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ filter_vec = LOAD_SH(filter_y);
+ tmp = __msa_clti_s_b((v16i8) filter_vec, 0);
+ filter_vec = (v8i16) __msa_ilvr_b(tmp, (v16i8) filter_vec);
+
+ filt_h0 = __msa_splati_w((v4i32) filter_vec, 0);
+ filt_h1 = __msa_splati_w((v4i32) filter_vec, 1);
+ filt_h2 = __msa_splati_w((v4i32) filter_vec, 2);
+ filt_h3 = __msa_splati_w((v4i32) filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ LOAD_7VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ /* Row 0 Row 1 Row 2 Row 3 */
+ vec0 = __msa_vshf_b(mask0, src3, src0);
+ vec1 = __msa_vshf_b(mask1, src3, src0);
+ vec2 = __msa_vshf_b(mask2, src3, src0);
+ vec3 = __msa_vshf_b(mask3, src3, src0);
+
+ vec4 = __msa_vshf_b(mask0, src4, src1);
+ vec5 = __msa_vshf_b(mask1, src4, src1);
+ vec6 = __msa_vshf_b(mask2, src4, src1);
+ vec7 = __msa_vshf_b(mask3, src4, src1);
+
+ vec8 = __msa_vshf_b(mask0, src5, src2);
+ vec9 = __msa_vshf_b(mask1, src5, src2);
+ vec10 = __msa_vshf_b(mask2, src5, src2);
+ vec11 = __msa_vshf_b(mask3, src5, src2);
+
+ vec12 = __msa_vshf_b(mask0, src6, src3);
+ vec13 = __msa_vshf_b(mask1, src6, src3);
+ vec14 = __msa_vshf_b(mask2, src6, src3);
+ vec15 = __msa_vshf_b(mask3, src6, src3);
+
+ dst30 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst41 = HEVC_FILT_8TAP_DPADD_H(vec4, vec5, vec6, vec7,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst52 = HEVC_FILT_8TAP_DPADD_H(vec8, vec9, vec10, vec11,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst63 = HEVC_FILT_8TAP_DPADD_H(vec12, vec13, vec14, vec15,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst10_r = __msa_ilvr_h(dst41, dst30);
+ dst21_r = __msa_ilvr_h(dst52, dst41);
+ dst32_r = __msa_ilvr_h(dst63, dst52);
+
+ dst43_r = __msa_ilvl_h(dst41, dst30);
+ dst54_r = __msa_ilvl_h(dst52, dst41);
+ dst65_r = __msa_ilvl_h(dst63, dst52);
+
+ dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1);
+
+ for (loop_cnt = height >> 1; loop_cnt--;) {
+ LOAD_2VECS_SB(src, src_stride, src7, src8);
+ src += (2 * src_stride);
+
+ src7 = (v16i8) __msa_xori_b((v16u8) src7, 128);
+ src8 = (v16i8) __msa_xori_b((v16u8) src8, 128);
+
+ vec0 = __msa_vshf_b(mask0, src8, src7);
+ vec1 = __msa_vshf_b(mask1, src8, src7);
+ vec2 = __msa_vshf_b(mask2, src8, src7);
+ vec3 = __msa_vshf_b(mask3, src8, src7);
+
+ dst87 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst76_r = __msa_ilvr_h(dst87, dst66);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_W(dst10_r, dst32_r, dst54_r, dst76_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87);
+
+ dst1_r = HEVC_FILT_8TAP_DPADD_W(dst21_r, dst43_r, dst65_r, dst87_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_r >>= 6;
+ dst1_r >>= 6;
+
+ dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r);
+
+ out0 = __msa_copy_u_d((v2i64) dst0_r, 0);
+ out1 = __msa_copy_u_d((v2i64) dst0_r, 1);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+
+ dst10_r = dst32_r;
+ dst32_r = dst54_r;
+ dst54_r = dst76_r;
+
+ dst21_r = dst43_r;
+ dst43_r = dst65_r;
+ dst65_r = dst87_r;
+
+ dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1);
+ }
+}
+
+static void hevc_hv_8t_8multx2mult_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ int16_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height, int32_t width)
+{
+ uint32_t loop_cnt, cnt;
+ uint8_t *src_tmp;
+ int16_t *dst_tmp;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8;
+ v8i16 filt0, filt1, filt2, filt3, filter_vec;
+ v4i32 filt_h0, filt_h1, filt_h2, filt_h3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7;
+ v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15;
+ v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8;
+ v4i32 dst0_r, dst0_l;
+ v8i16 dst10_r, dst32_r, dst54_r, dst76_r;
+ v8i16 dst10_l, dst32_l, dst54_l, dst76_l;
+ v8i16 dst21_r, dst43_r, dst65_r, dst87_r;
+ v8i16 dst21_l, dst43_l, dst65_l, dst87_l;
+ v16i8 tmp;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= ((3 * src_stride) + 3);
+
+ filter_vec = LOAD_SH(filter_x);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ filter_vec = LOAD_SH(filter_y);
+ tmp = __msa_clti_s_b((v16i8) filter_vec, 0);
+ filter_vec = (v8i16) __msa_ilvr_b(tmp, (v16i8) filter_vec);
+
+ filt_h0 = __msa_splati_w((v4i32) filter_vec, 0);
+ filt_h1 = __msa_splati_w((v4i32) filter_vec, 1);
+ filt_h2 = __msa_splati_w((v4i32) filter_vec, 2);
+ filt_h3 = __msa_splati_w((v4i32) filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ for (cnt = width >> 3; cnt--;) {
+ src_tmp = src;
+ dst_tmp = dst;
+
+ LOAD_7VECS_SB(src_tmp, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src_tmp += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ /* Row 0 Row 1 Row 2 Row 3 */
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ vec4 = __msa_vshf_b(mask0, src1, src1);
+ vec5 = __msa_vshf_b(mask1, src1, src1);
+ vec6 = __msa_vshf_b(mask2, src1, src1);
+ vec7 = __msa_vshf_b(mask3, src1, src1);
+
+ vec8 = __msa_vshf_b(mask0, src2, src2);
+ vec9 = __msa_vshf_b(mask1, src2, src2);
+ vec10 = __msa_vshf_b(mask2, src2, src2);
+ vec11 = __msa_vshf_b(mask3, src2, src2);
+
+ vec12 = __msa_vshf_b(mask0, src3, src3);
+ vec13 = __msa_vshf_b(mask1, src3, src3);
+ vec14 = __msa_vshf_b(mask2, src3, src3);
+ vec15 = __msa_vshf_b(mask3, src3, src3);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec4, vec5, vec6, vec7,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec8, vec9, vec10, vec11,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec12, vec13, vec14, vec15,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ /* Row 4 Row 5 Row 6 */
+ vec0 = __msa_vshf_b(mask0, src4, src4);
+ vec1 = __msa_vshf_b(mask1, src4, src4);
+ vec2 = __msa_vshf_b(mask2, src4, src4);
+ vec3 = __msa_vshf_b(mask3, src4, src4);
+
+ vec4 = __msa_vshf_b(mask0, src5, src5);
+ vec5 = __msa_vshf_b(mask1, src5, src5);
+ vec6 = __msa_vshf_b(mask2, src5, src5);
+ vec7 = __msa_vshf_b(mask3, src5, src5);
+
+ vec8 = __msa_vshf_b(mask0, src6, src6);
+ vec9 = __msa_vshf_b(mask1, src6, src6);
+ vec10 = __msa_vshf_b(mask2, src6, src6);
+ vec11 = __msa_vshf_b(mask3, src6, src6);
+
+ dst4 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst5 = HEVC_FILT_8TAP_DPADD_H(vec4, vec5, vec6, vec7,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst6 = HEVC_FILT_8TAP_DPADD_H(vec8, vec9, vec10, vec11,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ ILVR_H_6VECS_SH(dst0, dst2, dst4, dst1, dst3, dst5,
+ dst1, dst3, dst5, dst2, dst4, dst6,
+ dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r);
+
+ ILVL_H_6VECS_SH(dst0, dst2, dst4, dst1, dst3, dst5,
+ dst1, dst3, dst5, dst2, dst4, dst6,
+ dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l);
+
+ for (loop_cnt = height >> 1; loop_cnt--;) {
+ src7 = LOAD_SB(src_tmp);
+ src_tmp += src_stride;
+
+ src7 = (v16i8) __msa_xori_b((v16u8) src7, 128);
+
+ vec0 = __msa_vshf_b(mask0, src7, src7);
+ vec1 = __msa_vshf_b(mask1, src7, src7);
+ vec2 = __msa_vshf_b(mask2, src7, src7);
+ vec3 = __msa_vshf_b(mask3, src7, src7);
+
+ dst7 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst76_r = __msa_ilvr_h(dst7, dst6);
+ dst76_l = __msa_ilvl_h(dst7, dst6);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_W(dst10_r, dst32_r, dst54_r, dst76_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_l = HEVC_FILT_8TAP_DPADD_W(dst10_l, dst32_l, dst54_l, dst76_l,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_r >>= 6;
+ dst0_l >>= 6;
+
+ dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r);
+
+ STORE_SW(dst0_r, dst_tmp);
+ dst_tmp += dst_stride;
+
+ /* Next row */
+ src8 = LOAD_SB(src_tmp);
+ src_tmp += src_stride;
+
+ src8 = (v16i8) __msa_xori_b((v16u8) src8, 128);
+
+ vec0 = __msa_vshf_b(mask0, src8, src8);
+ vec1 = __msa_vshf_b(mask1, src8, src8);
+ vec2 = __msa_vshf_b(mask2, src8, src8);
+ vec3 = __msa_vshf_b(mask3, src8, src8);
+
+ dst8 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst87_r = __msa_ilvr_h(dst8, dst7);
+ dst87_l = __msa_ilvl_h(dst8, dst7);
+
+ dst6 = dst8;
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_W(dst21_r, dst43_r, dst65_r, dst87_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_l = HEVC_FILT_8TAP_DPADD_W(dst21_l, dst43_l, dst65_l, dst87_l,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_r >>= 6;
+ dst0_l >>= 6;
+
+ dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r);
+
+ STORE_SW(dst0_r, dst_tmp);
+ dst_tmp += dst_stride;
+
+ dst10_r = dst32_r;
+ dst32_r = dst54_r;
+ dst54_r = dst76_r;
+
+ dst10_l = dst32_l;
+ dst32_l = dst54_l;
+ dst54_l = dst76_l;
+
+ dst21_r = dst43_r;
+ dst43_r = dst65_r;
+ dst65_r = dst87_r;
+
+ dst21_l = dst43_l;
+ dst43_l = dst65_l;
+ dst65_l = dst87_l;
+ }
+
+ src += 8;
+ dst += 8;
+ }
+}
+
+static void hevc_hv_8t_8w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 8);
+}
+
+static void hevc_hv_8t_12w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 8);
+
+ hevc_hv_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride,
+ filter_x, filter_y, height);
+}
+
+static void hevc_hv_8t_16w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 16);
+}
+
+static void hevc_hv_8t_24w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 24);
+}
+
+static void hevc_hv_8t_32w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 32);
+}
+
+static void hevc_hv_8t_48w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 48);
+}
+
+static void hevc_hv_8t_64w_msa(uint8_t * __restrict src, int32_t src_stride,
+ int16_t * __restrict dst, int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 64);
+}
+
+static void hevc_hv_uni_8t_4w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ uint32_t loop_cnt;
+ uint32_t out0, out1;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8;
+ v8i16 filt0, filt1, filt2, filt3, filter_vec;
+ v4i32 filt_h0, filt_h1, filt_h2, filt_h3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7;
+ v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15;
+ v8i16 dst30, dst41, dst52, dst63, dst66, dst87;
+ v4i32 dst0_r, dst1_r;
+ v8i16 dst10_r, dst32_r, dst54_r, dst76_r;
+ v8i16 dst21_r, dst43_r, dst65_r, dst87_r;
+ v16i8 tmp;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 };
+ v8i16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 };
+
+ src -= ((3 * src_stride) + 3);
+
+ filter_vec = LOAD_SH(filter_x);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ filter_vec = LOAD_SH(filter_y);
+ tmp = __msa_clti_s_b((v16i8) filter_vec, 0);
+ filter_vec = (v8i16) __msa_ilvr_b(tmp, (v16i8) filter_vec);
+
+ filt_h0 = __msa_splati_w((v4i32) filter_vec, 0);
+ filt_h1 = __msa_splati_w((v4i32) filter_vec, 1);
+ filt_h2 = __msa_splati_w((v4i32) filter_vec, 2);
+ filt_h3 = __msa_splati_w((v4i32) filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ LOAD_7VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ /* Row 0 Row 1 Row 2 Row 3 */
+ vec0 = __msa_vshf_b(mask0, src3, src0);
+ vec1 = __msa_vshf_b(mask1, src3, src0);
+ vec2 = __msa_vshf_b(mask2, src3, src0);
+ vec3 = __msa_vshf_b(mask3, src3, src0);
+
+ vec4 = __msa_vshf_b(mask0, src4, src1);
+ vec5 = __msa_vshf_b(mask1, src4, src1);
+ vec6 = __msa_vshf_b(mask2, src4, src1);
+ vec7 = __msa_vshf_b(mask3, src4, src1);
+
+ vec8 = __msa_vshf_b(mask0, src5, src2);
+ vec9 = __msa_vshf_b(mask1, src5, src2);
+ vec10 = __msa_vshf_b(mask2, src5, src2);
+ vec11 = __msa_vshf_b(mask3, src5, src2);
+
+ vec12 = __msa_vshf_b(mask0, src6, src3);
+ vec13 = __msa_vshf_b(mask1, src6, src3);
+ vec14 = __msa_vshf_b(mask2, src6, src3);
+ vec15 = __msa_vshf_b(mask3, src6, src3);
+
+ dst30 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst41 = HEVC_FILT_8TAP_DPADD_H(vec4, vec5, vec6, vec7,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst52 = HEVC_FILT_8TAP_DPADD_H(vec8, vec9, vec10, vec11,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst63 = HEVC_FILT_8TAP_DPADD_H(vec12, vec13, vec14, vec15,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst10_r = __msa_ilvr_h(dst41, dst30);
+ dst21_r = __msa_ilvr_h(dst52, dst41);
+ dst32_r = __msa_ilvr_h(dst63, dst52);
+
+ dst43_r = __msa_ilvl_h(dst41, dst30);
+ dst54_r = __msa_ilvl_h(dst52, dst41);
+ dst65_r = __msa_ilvl_h(dst63, dst52);
+
+ dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1);
+
+ for (loop_cnt = height >> 1; loop_cnt--;) {
+ src7 = LOAD_SB(src);
+ src += src_stride;
+ src8 = LOAD_SB(src);
+ src += src_stride;
+
+ XORI_B_2VECS_SB(src7, src8, src7, src8, 128);
+
+ vec0 = __msa_vshf_b(mask0, src8, src7);
+ vec1 = __msa_vshf_b(mask1, src8, src7);
+ vec2 = __msa_vshf_b(mask2, src8, src7);
+ vec3 = __msa_vshf_b(mask3, src8, src7);
+
+ dst87 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst76_r = __msa_ilvr_h(dst87, dst66);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_W(dst10_r, dst32_r, dst54_r, dst76_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst87_r = __msa_vshf_h(mask4, dst87, dst87);
+
+ dst1_r = HEVC_FILT_8TAP_DPADD_W(dst21_r, dst43_r, dst65_r, dst87_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_r >>= 6;
+ dst1_r >>= 6;
+
+ dst0_r = __msa_srari_w(dst0_r, 6);
+ dst1_r = __msa_srari_w(dst1_r, 6);
+
+ dst0_r = CLIP_UNSIGNED_CHAR_W(dst0_r);
+ dst1_r = CLIP_UNSIGNED_CHAR_W(dst1_r);
+
+ dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r);
+ dst0_r = (v4i32) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r);
+
+ out0 = __msa_copy_u_w(dst0_r, 0);
+ out1 = __msa_copy_u_w(dst0_r, 1);
+
+ STORE_WORD(dst, out0);
+ dst += dst_stride;
+ STORE_WORD(dst, out1);
+ dst += dst_stride;
+
+ dst10_r = dst32_r;
+ dst32_r = dst54_r;
+ dst54_r = dst76_r;
+
+ dst21_r = dst43_r;
+ dst43_r = dst65_r;
+ dst65_r = dst87_r;
+
+ dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1);
+ }
+}
+
+static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height, int32_t width)
+{
+ uint32_t loop_cnt, cnt;
+ uint64_t out0, out1;
+ uint8_t *src_tmp;
+ uint8_t *dst_tmp;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8;
+ v8i16 filt0, filt1, filt2, filt3, filter_vec;
+ v4i32 filt_h0, filt_h1, filt_h2, filt_h3;
+ v16i8 mask1, mask2, mask3;
+ v8u16 const_vec;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7;
+ v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15;
+ v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8;
+ v4i32 dst0_r, dst0_l, dst1_r, dst1_l;
+ v8i16 dst10_r, dst32_r, dst54_r, dst76_r;
+ v8i16 dst10_l, dst32_l, dst54_l, dst76_l;
+ v8i16 dst21_r, dst43_r, dst65_r, dst87_r;
+ v8i16 dst21_l, dst43_l, dst65_l, dst87_l;
+ v16i8 tmp;
+ v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
+
+ src -= ((3 * src_stride) + 3);
+
+ const_vec = (v8u16) __msa_ldi_h(128);
+ const_vec <<= 6;
+
+ filter_vec = LOAD_SH(filter_x);
+ filt0 = __msa_splati_h(filter_vec, 0);
+ filt1 = __msa_splati_h(filter_vec, 1);
+ filt2 = __msa_splati_h(filter_vec, 2);
+ filt3 = __msa_splati_h(filter_vec, 3);
+
+ filter_vec = LOAD_SH(filter_y);
+ tmp = __msa_clti_s_b((v16i8) filter_vec, 0);
+ filter_vec = (v8i16) __msa_ilvr_b(tmp, (v16i8) filter_vec);
+
+ filt_h0 = __msa_splati_w((v4i32) filter_vec, 0);
+ filt_h1 = __msa_splati_w((v4i32) filter_vec, 1);
+ filt_h2 = __msa_splati_w((v4i32) filter_vec, 2);
+ filt_h3 = __msa_splati_w((v4i32) filter_vec, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ for (cnt = width >> 3; cnt--;) {
+ src_tmp = src;
+ dst_tmp = dst;
+
+ LOAD_7VECS_SB(src_tmp, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src_tmp += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ /* Row 0 Row 1 Row 2 Row 3 */
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src0, src0);
+ vec2 = __msa_vshf_b(mask2, src0, src0);
+ vec3 = __msa_vshf_b(mask3, src0, src0);
+
+ vec4 = __msa_vshf_b(mask0, src1, src1);
+ vec5 = __msa_vshf_b(mask1, src1, src1);
+ vec6 = __msa_vshf_b(mask2, src1, src1);
+ vec7 = __msa_vshf_b(mask3, src1, src1);
+
+ vec8 = __msa_vshf_b(mask0, src2, src2);
+ vec9 = __msa_vshf_b(mask1, src2, src2);
+ vec10 = __msa_vshf_b(mask2, src2, src2);
+ vec11 = __msa_vshf_b(mask3, src2, src2);
+
+ vec12 = __msa_vshf_b(mask0, src3, src3);
+ vec13 = __msa_vshf_b(mask1, src3, src3);
+ vec14 = __msa_vshf_b(mask2, src3, src3);
+ vec15 = __msa_vshf_b(mask3, src3, src3);
+
+ dst0 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst1 = HEVC_FILT_8TAP_DPADD_H(vec4, vec5, vec6, vec7,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst2 = HEVC_FILT_8TAP_DPADD_H(vec8, vec9, vec10, vec11,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst3 = HEVC_FILT_8TAP_DPADD_H(vec12, vec13, vec14, vec15,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ vec0 = __msa_vshf_b(mask0, src4, src4);
+ vec1 = __msa_vshf_b(mask1, src4, src4);
+ vec2 = __msa_vshf_b(mask2, src4, src4);
+ vec3 = __msa_vshf_b(mask3, src4, src4);
+
+ vec4 = __msa_vshf_b(mask0, src5, src5);
+ vec5 = __msa_vshf_b(mask1, src5, src5);
+ vec6 = __msa_vshf_b(mask2, src5, src5);
+ vec7 = __msa_vshf_b(mask3, src5, src5);
+
+ vec8 = __msa_vshf_b(mask0, src6, src6);
+ vec9 = __msa_vshf_b(mask1, src6, src6);
+ vec10 = __msa_vshf_b(mask2, src6, src6);
+ vec11 = __msa_vshf_b(mask3, src6, src6);
+
+ dst4 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst5 = HEVC_FILT_8TAP_DPADD_H(vec4, vec5, vec6, vec7,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ dst6 = HEVC_FILT_8TAP_DPADD_H(vec8, vec9, vec10, vec11,
+ filt0, filt1, filt2, filt3, const_vec);
+
+ ILVR_H_6VECS_SH(dst0, dst2, dst4, dst1, dst3, dst5,
+ dst1, dst3, dst5, dst2, dst4, dst6,
+ dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r);
+
+ ILVL_H_6VECS_SH(dst0, dst2, dst4, dst1, dst3, dst5,
+ dst1, dst3, dst5, dst2, dst4, dst6,
+ dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l);
+
+ for (loop_cnt = height >> 1; loop_cnt--;) {
+ src7 = LOAD_SB(src_tmp);
+ src_tmp += src_stride;
+
+ src7 = (v16i8) __msa_xori_b((v16u8) src7, 128);
+
+ vec0 = __msa_vshf_b(mask0, src7, src7);
+ vec1 = __msa_vshf_b(mask1, src7, src7);
+ vec2 = __msa_vshf_b(mask2, src7, src7);
+ vec3 = __msa_vshf_b(mask3, src7, src7);
+
+ dst7 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst76_r = __msa_ilvr_h(dst7, dst6);
+ dst76_l = __msa_ilvl_h(dst7, dst6);
+
+ dst0_r = HEVC_FILT_8TAP_DPADD_W(dst10_r, dst32_r, dst54_r, dst76_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_l = HEVC_FILT_8TAP_DPADD_W(dst10_l, dst32_l, dst54_l, dst76_l,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst0_r >>= 6;
+ dst0_l >>= 6;
+
+ /* Row 8 */
+ src8 = LOAD_SB(src_tmp);
+ src_tmp += src_stride;
+
+ src8 = (v16i8) __msa_xori_b((v16u8) src8, 128);
+
+ vec0 = __msa_vshf_b(mask0, src8, src8);
+ vec1 = __msa_vshf_b(mask1, src8, src8);
+ vec2 = __msa_vshf_b(mask2, src8, src8);
+ vec3 = __msa_vshf_b(mask3, src8, src8);
+
+ dst8 = HEVC_FILT_8TAP_DPADD_H(vec0, vec1, vec2, vec3,
+ filt0, filt1, filt2, filt3,
+ const_vec);
+
+ dst87_r = __msa_ilvr_h(dst8, dst7);
+ dst87_l = __msa_ilvl_h(dst8, dst7);
+
+ dst1_r = HEVC_FILT_8TAP_DPADD_W(dst21_r, dst43_r, dst65_r, dst87_r,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst1_l = HEVC_FILT_8TAP_DPADD_W(dst21_l, dst43_l, dst65_l, dst87_l,
+ filt_h0, filt_h1, filt_h2, filt_h3);
+
+ dst1_r >>= 6;
+ dst1_l >>= 6;
+
+ HEVC_RND_W_CLIP_UNSIGNED_CHAR_W_VEC2(dst0_r, dst0_l, dst1_r, dst1_l,
+ dst0_r, dst1_r);
+
+ dst0_r = (v4i32) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r);
+
+ out0 = __msa_copy_u_d((v2i64) dst0_r, 0);
+ out1 = __msa_copy_u_d((v2i64) dst0_r, 1);
+
+ STORE_DWORD(dst_tmp, out0);
+ dst_tmp += dst_stride;
+ STORE_DWORD(dst_tmp, out1);
+ dst_tmp += dst_stride;
+
+ dst10_r = dst32_r;
+ dst32_r = dst54_r;
+ dst54_r = dst76_r;
+
+ dst10_l = dst32_l;
+ dst32_l = dst54_l;
+ dst54_l = dst76_l;
+
+ dst21_r = dst43_r;
+ dst43_r = dst65_r;
+ dst65_r = dst87_r;
+
+ dst21_l = dst43_l;
+ dst43_l = dst65_l;
+ dst65_l = dst87_l;
+
+ dst6 = dst8;
+ }
+
+ src += 8;
+ dst += 8;
+ }
+}
+
+static void hevc_hv_uni_8t_8w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 8);
+}
+
+static void hevc_hv_uni_8t_12w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 8);
+
+ hevc_hv_uni_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride,
+ filter_x, filter_y, height);
+}
+
+static void hevc_hv_uni_8t_16w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 16);
+}
+
+static void hevc_hv_uni_8t_24w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 24);
+}
+
+static void hevc_hv_uni_8t_32w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 32);
+}
+
+static void hevc_hv_uni_8t_48w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 48);
+}
+
+static void hevc_hv_uni_8t_64w_msa(uint8_t * __restrict src,
+ int32_t src_stride,
+ uint8_t * __restrict dst,
+ int32_t dst_stride,
+ const int8_t * __restrict filter_x,
+ const int8_t * __restrict filter_y,
+ int32_t height)
+{
+ hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride,
+ filter_x, filter_y, height, 64);
+}
+
+static uint8_t mc_filt_mask_arr[16 * 3] = {
+ /* 8 width cases */
+ 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+ /* 4 width cases */
+ 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20,
+ /* 4 width cases */
+ 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28
+};
+
+#define FILT_8TAP_DPADD_S_H(vec0, vec1, vec2, vec3, \
+ filt0, filt1, filt2, filt3) \
+( { \
+ v8i16 tmp0, tmp1; \
+ \
+ tmp0 = __msa_dotp_s_h((v16i8) (vec0), (v16i8) (filt0)); \
+ tmp0 = __msa_dpadd_s_h(tmp0, (v16i8) (vec1), (v16i8) (filt1)); \
+ tmp1 = __msa_dotp_s_h((v16i8) (vec2), (v16i8) (filt2)); \
+ tmp1 = __msa_dpadd_s_h(tmp1, (v16i8) (vec3), (v16i8) (filt3)); \
+ tmp0 = __msa_adds_s_h(tmp0, tmp1); \
+ \
+ tmp0; \
+} )
+
+#define HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \
+ mask0, mask1, mask2, mask3, \
+ filt0, filt1, filt2, filt3, \
+ out0, out1) \
+{ \
+ v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \
+ v8i16 res0_m, res1_m, res2_m, res3_m; \
+ \
+ vec0_m = __msa_vshf_b((v16i8) (mask0), (v16i8) (src1), (v16i8) (src0)); \
+ vec1_m = __msa_vshf_b((v16i8) (mask0), (v16i8) (src3), (v16i8) (src2)); \
+ \
+ res0_m = __msa_dotp_s_h(vec0_m, (v16i8) (filt0)); \
+ res1_m = __msa_dotp_s_h(vec1_m, (v16i8) (filt0)); \
+ \
+ vec2_m = __msa_vshf_b((v16i8) (mask1), (v16i8) (src1), (v16i8) (src0)); \
+ vec3_m = __msa_vshf_b((v16i8) (mask1), (v16i8) (src3), (v16i8) (src2)); \
+ \
+ res0_m = __msa_dpadd_s_h(res0_m, (filt1), vec2_m); \
+ res1_m = __msa_dpadd_s_h(res1_m, (filt1), vec3_m); \
+ \
+ vec4_m = __msa_vshf_b((v16i8) (mask2), (v16i8) (src1), (v16i8) (src0)); \
+ vec5_m = __msa_vshf_b((v16i8) (mask2), (v16i8) (src3), (v16i8) (src2)); \
+ \
+ res2_m = __msa_dotp_s_h((v16i8) (filt2), vec4_m); \
+ res3_m = __msa_dotp_s_h((v16i8) (filt2), vec5_m); \
+ \
+ vec6_m = __msa_vshf_b((v16i8) (mask3), (v16i8) (src1), (v16i8) (src0)); \
+ vec7_m = __msa_vshf_b((v16i8) (mask3), (v16i8) (src3), (v16i8) (src2)); \
+ \
+ res2_m = __msa_dpadd_s_h(res2_m, (v16i8) (filt3), vec6_m); \
+ res3_m = __msa_dpadd_s_h(res3_m, (v16i8) (filt3), vec7_m); \
+ \
+ out0 = __msa_adds_s_h(res0_m, res2_m); \
+ out1 = __msa_adds_s_h(res1_m, res3_m); \
+}
+
+#define HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \
+ mask0, mask1, mask2, mask3, \
+ filt0, filt1, filt2, filt3, \
+ out0, out1, out2, out3) \
+{ \
+ v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \
+ v8i16 res0_m, res1_m, res2_m, res3_m, res4_m, res5_m, res6_m, res7_m; \
+ \
+ vec0_m = __msa_vshf_b((v16i8) (mask0), (v16i8) (src0), (v16i8) (src0)); \
+ vec1_m = __msa_vshf_b((v16i8) (mask0), (v16i8) (src1), (v16i8) (src1)); \
+ vec2_m = __msa_vshf_b((v16i8) (mask0), (v16i8) (src2), (v16i8) (src2)); \
+ vec3_m = __msa_vshf_b((v16i8) (mask0), (v16i8) (src3), (v16i8) (src3)); \
+ \
+ res0_m = __msa_dotp_s_h(vec0_m, (v16i8) (filt0)); \
+ res1_m = __msa_dotp_s_h(vec1_m, (v16i8) (filt0)); \
+ res2_m = __msa_dotp_s_h(vec2_m, (v16i8) (filt0)); \
+ res3_m = __msa_dotp_s_h(vec3_m, (v16i8) (filt0)); \
+ \
+ vec0_m = __msa_vshf_b((v16i8) (mask2), (v16i8) (src0), (v16i8) (src0)); \
+ vec1_m = __msa_vshf_b((v16i8) (mask2), (v16i8) (src1), (v16i8) (src1)); \
+ vec2_m = __msa_vshf_b((v16i8) (mask2), (v16i8) (src2), (v16i8) (src2)); \
+ vec3_m = __msa_vshf_b((v16i8) (mask2), (v16i8) (src3), (v16i8) (src3)); \
+ \
+ res4_m = __msa_dotp_s_h(vec0_m, (v16i8) (filt2)); \
+ res5_m = __msa_dotp_s_h(vec1_m, (v16i8) (filt2)); \
+ res6_m = __msa_dotp_s_h(vec2_m, (v16i8) (filt2)); \
+ res7_m = __msa_dotp_s_h(vec3_m, (v16i8) (filt2)); \
+ \
+ vec4_m = __msa_vshf_b((v16i8) (mask1), (v16i8) (src0), (v16i8) (src0)); \
+ vec5_m = __msa_vshf_b((v16i8) (mask1), (v16i8) (src1), (v16i8) (src1)); \
+ vec6_m = __msa_vshf_b((v16i8) (mask1), (v16i8) (src2), (v16i8) (src2)); \
+ vec7_m = __msa_vshf_b((v16i8) (mask1), (v16i8) (src3), (v16i8) (src3)); \
+ \
+ res0_m = __msa_dpadd_s_h(res0_m, (v16i8) (filt1), vec4_m); \
+ res1_m = __msa_dpadd_s_h(res1_m, (v16i8) (filt1), vec5_m); \
+ res2_m = __msa_dpadd_s_h(res2_m, (v16i8) (filt1), vec6_m); \
+ res3_m = __msa_dpadd_s_h(res3_m, (v16i8) (filt1), vec7_m); \
+ \
+ vec4_m = __msa_vshf_b((v16i8) (mask3), (v16i8) (src0), (v16i8) (src0)); \
+ vec5_m = __msa_vshf_b((v16i8) (mask3), (v16i8) (src1), (v16i8) (src1)); \
+ vec6_m = __msa_vshf_b((v16i8) (mask3), (v16i8) (src2), (v16i8) (src2)); \
+ vec7_m = __msa_vshf_b((v16i8) (mask3), (v16i8) (src3), (v16i8) (src3)); \
+ \
+ res4_m = __msa_dpadd_s_h(res4_m, (v16i8) (filt3), vec4_m); \
+ res5_m = __msa_dpadd_s_h(res5_m, (v16i8) (filt3), vec5_m); \
+ res6_m = __msa_dpadd_s_h(res6_m, (v16i8) (filt3), vec6_m); \
+ res7_m = __msa_dpadd_s_h(res7_m, (v16i8) (filt3), vec7_m); \
+ \
+ out0 = __msa_adds_s_h(res0_m, res4_m); \
+ out1 = __msa_adds_s_h(res1_m, res5_m); \
+ out2 = __msa_adds_s_h(res2_m, res6_m); \
+ out3 = __msa_adds_s_h(res3_m, res7_m); \
+}
+
+static void common_hz_8t_4x4_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, uint8_t rnd_val)
+{
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src0, src1, src2, src3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[16]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0, out1);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out0, out1, dst, dst_stride);
+}
+
+static void common_hz_8t_4x8_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, uint8_t rnd_val)
+{
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src0, src1, src2, src3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[16]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0, out1);
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out2, out3);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out0, out1, dst, dst_stride);
+ dst += (4 * dst_stride);
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out2, out3, dst, dst_stride);
+}
+
+static void common_hz_8t_4x16_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, uint8_t rnd_val)
+{
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src0, src1, src2, src3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[16]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0, out1);
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out2, out3);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out0, out1, dst, dst_stride);
+ dst += (4 * dst_stride);
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out2, out3, dst, dst_stride);
+ dst += (4 * dst_stride);
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0, out1);
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out2, out3);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out0, out1, dst, dst_stride);
+ dst += (4 * dst_stride);
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out2, out3, dst, dst_stride);
+}
+
+static void common_hz_8t_4w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ if (4 == height) {
+ common_hz_8t_4x4_msa(src, src_stride, dst, dst_stride, filter, rnd_val);
+ } else if (8 == height) {
+ common_hz_8t_4x8_msa(src, src_stride, dst, dst_stride, filter, rnd_val);
+ } else if (16 == height) {
+ common_hz_8t_4x16_msa(src, src_stride, dst, dst_stride, filter,
+ rnd_val);
+ }
+}
+
+static void common_hz_8t_8x4_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, uint8_t rnd_val)
+{
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src0, src1, src2, src3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[0]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0, out1,
+ out2, out3);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_4_XORI128_STORE_8_BYTES_4(out0, out1, out2, out3, dst, dst_stride);
+}
+
+static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src0, src1, src2, src3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[0]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0,
+ out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_4_XORI128_STORE_8_BYTES_4(out0, out1, out2, out3,
+ dst, dst_stride);
+ dst += (4 * dst_stride);
+ }
+}
+
+static void common_hz_8t_8w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ if (4 == height) {
+ common_hz_8t_8x4_msa(src, src_stride, dst, dst_stride, filter, rnd_val);
+ } else {
+ common_hz_8t_8x8mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, rnd_val);
+ }
+}
+
+static void common_hz_8t_12w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint8_t *src1_ptr, *dst1;
+ uint32_t loop_cnt;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src0, src1, src2, src3;
+ v8u16 rnd_vec;
+ v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask00;
+ v8i16 filt, out0, out1, out2, out3;
+
+ mask00 = LOAD_UB(&mc_filt_mask_arr[0]);
+ mask0 = LOAD_UB(&mc_filt_mask_arr[16]);
+
+ src1_ptr = src - 3;
+ dst1 = dst;
+
+ dst = dst1 + 8;
+ src = src1_ptr + 8;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask00 + 2;
+ mask2 = mask00 + 4;
+ mask3 = mask00 + 6;
+ mask4 = mask0 + 2;
+ mask5 = mask0 + 4;
+ mask6 = mask0 + 6;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ /* 8 width */
+ LOAD_4VECS_SB(src1_ptr, src_stride, src0, src1, src2, src3);
+ src1_ptr += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask00, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0,
+ out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_4_XORI128_STORE_8_BYTES_4(out0, out1, out2, out3,
+ dst1, dst_stride);
+ dst1 += (4 * dst_stride);
+
+ /* 4 width */
+ LOAD_4VECS_SB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask4, mask5,
+ mask6, filt0, filt1, filt2, filt3, out0,
+ out1);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out0, out1, dst, dst_stride);
+ dst += (4 * dst_stride);
+ }
+}
+
+static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[0]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = (height >> 1); loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src1 = LOAD_SB(src + 8);
+ src += src_stride;
+ src2 = LOAD_SB(src);
+ src3 = LOAD_SB(src + 8);
+ src += src_stride;
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0,
+ out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst);
+ dst += dst_stride;
+ PCKEV_B_XORI128_STORE_VEC(out3, out2, dst);
+ dst += dst_stride;
+ }
+}
+
+static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5;
+ v16i8 vec6, vec7, vec8, vec9, vec10, vec11;
+ v8i16 out0, out1, out2, out3, out4, out5;
+ v8i16 out6, out7, out8, out9, out10, out11;
+ v8i16 filt;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_SB(&mc_filt_mask_arr[0]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+ mask4 = mask0 + 8;
+ mask5 = mask0 + 10;
+ mask6 = mask0 + 12;
+ mask7 = mask0 + 14;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = (height >> 1); loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src1 = LOAD_SB(src + 16);
+ src += src_stride;
+ src2 = LOAD_SB(src);
+ src3 = LOAD_SB(src + 16);
+ src += src_stride;
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec8 = __msa_vshf_b(mask0, src1, src1);
+ vec2 = __msa_vshf_b(mask0, src2, src2);
+ vec9 = __msa_vshf_b(mask0, src3, src3);
+ vec1 = __msa_vshf_b(mask4, src1, src0);
+ vec3 = __msa_vshf_b(mask4, src3, src2);
+
+ out0 = __msa_dotp_s_h(vec0, filt0);
+ out8 = __msa_dotp_s_h(vec8, filt0);
+ out2 = __msa_dotp_s_h(vec2, filt0);
+ out9 = __msa_dotp_s_h(vec9, filt0);
+ out1 = __msa_dotp_s_h(vec1, filt0);
+ out3 = __msa_dotp_s_h(vec3, filt0);
+
+ vec0 = __msa_vshf_b(mask2, src0, src0);
+ vec8 = __msa_vshf_b(mask2, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ vec9 = __msa_vshf_b(mask2, src3, src3);
+ vec1 = __msa_vshf_b(mask6, src1, src0);
+ vec3 = __msa_vshf_b(mask6, src3, src2);
+
+ out4 = __msa_dotp_s_h(vec0, filt2);
+ out10 = __msa_dotp_s_h(vec8, filt2);
+ out6 = __msa_dotp_s_h(vec2, filt2);
+ out11 = __msa_dotp_s_h(vec9, filt2);
+ out5 = __msa_dotp_s_h(vec1, filt2);
+ out7 = __msa_dotp_s_h(vec3, filt2);
+
+ vec4 = __msa_vshf_b(mask1, src0, src0);
+ vec10 = __msa_vshf_b(mask1, src1, src1);
+ vec6 = __msa_vshf_b(mask1, src2, src2);
+ vec11 = __msa_vshf_b(mask1, src3, src3);
+ vec5 = __msa_vshf_b(mask5, src1, src0);
+ vec7 = __msa_vshf_b(mask5, src3, src2);
+
+ out0 = __msa_dpadd_s_h(out0, vec4, filt1);
+ out8 = __msa_dpadd_s_h(out8, vec10, filt1);
+ out2 = __msa_dpadd_s_h(out2, vec6, filt1);
+ out9 = __msa_dpadd_s_h(out9, vec11, filt1);
+ out1 = __msa_dpadd_s_h(out1, vec5, filt1);
+ out3 = __msa_dpadd_s_h(out3, vec7, filt1);
+
+ vec4 = __msa_vshf_b(mask3, src0, src0);
+ vec10 = __msa_vshf_b(mask3, src1, src1);
+ vec6 = __msa_vshf_b(mask3, src2, src2);
+ vec11 = __msa_vshf_b(mask3, src3, src3);
+ vec5 = __msa_vshf_b(mask7, src1, src0);
+ vec7 = __msa_vshf_b(mask7, src3, src2);
+
+ out4 = __msa_dpadd_s_h(out4, vec4, filt3);
+ out10 = __msa_dpadd_s_h(out10, vec10, filt3);
+ out6 = __msa_dpadd_s_h(out6, vec6, filt3);
+ out11 = __msa_dpadd_s_h(out11, vec11, filt3);
+ out5 = __msa_dpadd_s_h(out5, vec5, filt3);
+ out7 = __msa_dpadd_s_h(out7, vec7, filt3);
+
+ out0 = __msa_adds_s_h(out0, out4);
+ out8 = __msa_adds_s_h(out8, out10);
+ out2 = __msa_adds_s_h(out2, out6);
+ out9 = __msa_adds_s_h(out9, out11);
+ out1 = __msa_adds_s_h(out1, out5);
+ out3 = __msa_adds_s_h(out3, out7);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out8 = SRAR_SATURATE_SIGNED_H(out8, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out9 = SRAR_SATURATE_SIGNED_H(out9, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_8_BYTES_2(out8, out9, dst + 16, dst_stride);
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst);
+ dst += dst_stride;
+ PCKEV_B_XORI128_STORE_VEC(out3, out2, dst);
+ dst += dst_stride;
+ }
+}
+
+static void common_hz_8t_32w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[0]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = (height >> 1); loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src2 = LOAD_SB(src + 16);
+ src3 = LOAD_SB(src + 24);
+ src1 = __msa_sld_b(src2, src0, 8);
+ src += src_stride;
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0,
+ out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ src0 = LOAD_SB(src);
+ src2 = LOAD_SB(src + 16);
+ src3 = LOAD_SB(src + 24);
+ src1 = __msa_sld_b(src2, src0, 8);
+ src += src_stride;
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst);
+ PCKEV_B_XORI128_STORE_VEC(out3, out2, (dst + 16));
+ dst += dst_stride;
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2,
+ mask3, filt0, filt1, filt2, filt3, out0,
+ out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst);
+ PCKEV_B_XORI128_STORE_VEC(out3, out2, (dst + 16));
+ dst += dst_stride;
+ }
+}
+
+static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 vec0, vec1, vec2;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7;
+ v8i16 filt, out0, out1, out2, out3, out4, out5, out6;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_SB(&mc_filt_mask_arr[0]);
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+ mask4 = mask0 + 8;
+ mask5 = mask0 + 10;
+ mask6 = mask0 + 12;
+ mask7 = mask0 + 14;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ src -= 3;
+
+ for (loop_cnt = height; loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src2 = LOAD_SB(src + 16);
+ src3 = LOAD_SB(src + 32);
+ src1 = __msa_sld_b(src2, src0, 8);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ vec0 = __msa_vshf_b(mask0, src0, src0);
+ vec1 = __msa_vshf_b(mask0, src1, src1);
+ vec2 = __msa_vshf_b(mask0, src2, src2);
+ out0 = __msa_dotp_s_h(vec0, filt0);
+ out1 = __msa_dotp_s_h(vec1, filt0);
+ out2 = __msa_dotp_s_h(vec2, filt0);
+
+ vec0 = __msa_vshf_b(mask1, src0, src0);
+ vec1 = __msa_vshf_b(mask1, src1, src1);
+ vec2 = __msa_vshf_b(mask1, src2, src2);
+ out0 = __msa_dpadd_s_h(out0, vec0, filt1);
+ out1 = __msa_dpadd_s_h(out1, vec1, filt1);
+ out2 = __msa_dpadd_s_h(out2, vec2, filt1);
+
+ vec0 = __msa_vshf_b(mask2, src0, src0);
+ vec1 = __msa_vshf_b(mask2, src1, src1);
+ vec2 = __msa_vshf_b(mask2, src2, src2);
+ out3 = __msa_dotp_s_h(vec0, filt2);
+ out4 = __msa_dotp_s_h(vec1, filt2);
+ out5 = __msa_dotp_s_h(vec2, filt2);
+
+ vec0 = __msa_vshf_b(mask3, src0, src0);
+ vec1 = __msa_vshf_b(mask3, src1, src1);
+ vec2 = __msa_vshf_b(mask3, src2, src2);
+ out3 = __msa_dpadd_s_h(out3, vec0, filt3);
+ out4 = __msa_dpadd_s_h(out4, vec1, filt3);
+ out5 = __msa_dpadd_s_h(out5, vec2, filt3);
+
+ out0 = __msa_adds_s_h(out0, out3);
+ out1 = __msa_adds_s_h(out1, out4);
+ out2 = __msa_adds_s_h(out2, out5);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out6 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst);
+
+ src1 = LOAD_SB(src + 40);
+ src1 = (v16i8) __msa_xori_b((v16u8) src1, 128);
+
+ vec0 = __msa_vshf_b(mask4, src3, src2);
+ vec1 = __msa_vshf_b(mask0, src3, src3);
+ vec2 = __msa_vshf_b(mask0, src1, src1);
+ out0 = __msa_dotp_s_h(vec0, filt0);
+ out1 = __msa_dotp_s_h(vec1, filt0);
+ out2 = __msa_dotp_s_h(vec2, filt0);
+
+ vec0 = __msa_vshf_b(mask5, src3, src2);
+ vec1 = __msa_vshf_b(mask1, src3, src3);
+ vec2 = __msa_vshf_b(mask1, src1, src1);
+ out0 = __msa_dpadd_s_h(out0, vec0, filt1);
+ out1 = __msa_dpadd_s_h(out1, vec1, filt1);
+ out2 = __msa_dpadd_s_h(out2, vec2, filt1);
+
+ vec0 = __msa_vshf_b(mask6, src3, src2);
+ vec1 = __msa_vshf_b(mask2, src3, src3);
+ vec2 = __msa_vshf_b(mask2, src1, src1);
+ out3 = __msa_dotp_s_h(vec0, filt2);
+ out4 = __msa_dotp_s_h(vec1, filt2);
+ out5 = __msa_dotp_s_h(vec2, filt2);
+
+ vec0 = __msa_vshf_b(mask7, src3, src2);
+ vec1 = __msa_vshf_b(mask3, src3, src3);
+ vec2 = __msa_vshf_b(mask3, src1, src1);
+ out3 = __msa_dpadd_s_h(out3, vec0, filt3);
+ out4 = __msa_dpadd_s_h(out4, vec1, filt3);
+ out5 = __msa_dpadd_s_h(out5, vec2, filt3);
+
+ out3 = __msa_adds_s_h(out0, out3);
+ out4 = __msa_adds_s_h(out1, out4);
+ out5 = __msa_adds_s_h(out2, out5);
+
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+ out4 = SRAR_SATURATE_SIGNED_H(out4, rnd_vec, 7);
+ out5 = SRAR_SATURATE_SIGNED_H(out5, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_VEC(out3, out6, (dst + 16));
+ PCKEV_B_XORI128_STORE_VEC(out5, out4, (dst + 32));
+
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+static void common_hz_8t_64w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ int32_t loop_cnt;
+ v16i8 src0, src1, src2, src3;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16u8 mask0, mask1, mask2, mask3;
+ v8i16 filt, out0, out1, out2, out3;
+ v8u16 rnd_vec;
+
+ mask0 = LOAD_UB(&mc_filt_mask_arr[0]);
+
+ src -= 3;
+
+ /* rearranging filter */
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ mask1 = mask0 + 2;
+ mask2 = mask0 + 4;
+ mask3 = mask0 + 6;
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = height; loop_cnt--;) {
+ src0 = LOAD_SB(src);
+ src2 = LOAD_SB(src + 16);
+ src3 = LOAD_SB(src + 24);
+ src1 = __msa_sld_b(src2, src0, 8);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1,
+ mask2, mask3, filt0, filt1, filt2, filt3,
+ out0, out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst);
+ PCKEV_B_XORI128_STORE_VEC(out3, out2, dst + 16);
+
+ src0 = LOAD_SB(src + 32);
+ src2 = LOAD_SB(src + 48);
+ src3 = LOAD_SB(src + 56);
+ src1 = __msa_sld_b(src2, src0, 8);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);
+
+ HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1,
+ mask2, mask3, filt0, filt1, filt2, filt3,
+ out0, out1, out2, out3);
+
+ out0 = SRAR_SATURATE_SIGNED_H(out0, rnd_vec, 7);
+ out1 = SRAR_SATURATE_SIGNED_H(out1, rnd_vec, 7);
+ out2 = SRAR_SATURATE_SIGNED_H(out2, rnd_vec, 7);
+ out3 = SRAR_SATURATE_SIGNED_H(out3, rnd_vec, 7);
+
+ PCKEV_B_XORI128_STORE_VEC(out1, out0, dst + 32);
+ PCKEV_B_XORI128_STORE_VEC(out3, out2, dst + 48);
+
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+static void common_vt_8t_4w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v16i8 src2110, src4332, src6554, src8776, src10998;
+ v16i8 filt0, filt1, filt2, filt3;
+ v8i16 filt, out10, out32;
+ v8u16 rnd_vec;
+
+ src -= (3 * src_stride);
+
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ LOAD_7VECS_SB(src, src_stride, src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ ILVR_D_3VECS_SB(src2110, src21_r, src10_r, src4332, src43_r, src32_r,
+ src6554, src65_r, src54_r);
+
+ XORI_B_3VECS_SB(src2110, src4332, src6554, src2110, src4332, src6554, 128);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src7, src8, src9, src10);
+ src += (4 * src_stride);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ ILVR_D_2VECS_SB(src8776, src87_r, src76_r, src10998, src109_r, src98_r);
+
+ XORI_B_2VECS_SB(src8776, src10998, src8776, src10998, 128);
+
+ out10 = FILT_8TAP_DPADD_S_H(src2110, src4332, src6554, src8776,
+ filt0, filt1, filt2, filt3);
+ out32 = FILT_8TAP_DPADD_S_H(src4332, src6554, src8776, src10998,
+ filt0, filt1, filt2, filt3);
+
+ out10 = SRAR_SATURATE_SIGNED_H(out10, rnd_vec, 7);
+ out32 = SRAR_SATURATE_SIGNED_H(out32, rnd_vec, 7);
+
+ PCKEV_2B_XORI128_STORE_4_BYTES_4(out10, out32, dst, dst_stride);
+ dst += (4 * dst_stride);
+
+ src2110 = src6554;
+ src4332 = src8776;
+ src6554 = src10998;
+
+ src6 = src10;
+ }
+}
+
+static void common_vt_8t_8w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v16i8 filt0, filt1, filt2, filt3;
+ v8i16 filt, out0_r, out1_r, out2_r, out3_r;
+ v8u16 rnd_vec;
+
+ src -= (3 * src_stride);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ LOAD_7VECS_SB(src, src_stride, src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src7, src8, src9, src10);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src7, src8, src9, src10, src7, src8, src9, src10, 128);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r,
+ filt0, filt1, filt2, filt3);
+ out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r,
+ filt0, filt1, filt2, filt3);
+ out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r,
+ filt0, filt1, filt2, filt3);
+ out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r,
+ filt0, filt1, filt2, filt3);
+
+ out0_r = SRAR_SATURATE_SIGNED_H(out0_r, rnd_vec, 7);
+ out1_r = SRAR_SATURATE_SIGNED_H(out1_r, rnd_vec, 7);
+ out2_r = SRAR_SATURATE_SIGNED_H(out2_r, rnd_vec, 7);
+ out3_r = SRAR_SATURATE_SIGNED_H(out3_r, rnd_vec, 7);
+
+ PCKEV_B_4_XORI128_STORE_8_BYTES_4(out0_r, out1_r, out2_r, out3_r,
+ dst, dst_stride);
+ dst += (4 * dst_stride);
+
+ src10_r = src54_r;
+ src32_r = src76_r;
+ src54_r = src98_r;
+ src21_r = src65_r;
+ src43_r = src87_r;
+ src65_r = src109_r;
+
+ src6 = src10;
+ }
+}
+
+static void common_vt_8t_12w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ int32_t loop_cnt;
+ uint32_t out2, out3;
+ uint64_t out0, out1;
+ v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8;
+ v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7;
+ v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15, vec16;
+ v16i8 res0, res1, res2;
+ v8i16 vec01, vec23, vec45, vec67;
+ v8i16 tmp0, tmp1, tmp2;
+ v8i16 filt, filt0, filt1, filt2, filt3;
+ v8u16 rnd_vec;
+ v4i32 mask = { 2, 6, 2, 6 };
+
+ src -= (3 * src_stride);
+
+ LOAD_7VECS_UB(src, src_stride, src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_4VECS_SB(src0, src1, src2, src3, vec0, vec1, vec2, vec3, 128);
+ vec4 = (v16i8) __msa_xori_b((v16u8) src4, 128);
+ vec5 = (v16i8) __msa_xori_b((v16u8) src5, 128);
+ vec6 = (v16i8) __msa_xori_b((v16u8) src6, 128);
+
+ /* 4 width */
+ vec9 = (v16i8) __msa_vshf_w(mask, (v4i32) vec1, (v4i32) vec0);
+ vec10 = (v16i8) __msa_vshf_w(mask, (v4i32) vec2, (v4i32) vec1);
+ vec11 = (v16i8) __msa_vshf_w(mask, (v4i32) vec3, (v4i32) vec2);
+ vec12 = (v16i8) __msa_vshf_w(mask, (v4i32) vec4, (v4i32) vec3);
+ vec13 = (v16i8) __msa_vshf_w(mask, (v4i32) vec5, (v4i32) vec4);
+ vec14 = (v16i8) __msa_vshf_w(mask, (v4i32) vec6, (v4i32) vec5);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ /* rearranging filter_y */
+ filt = LOAD_SH(filter);
+ filt0 = (v8i16) __msa_splati_h(filt, 0);
+ filt1 = (v8i16) __msa_splati_h(filt, 1);
+ filt2 = (v8i16) __msa_splati_h(filt, 2);
+ filt3 = (v8i16) __msa_splati_h(filt, 3);
+
+ for (loop_cnt = (height >> 1); loop_cnt--;) {
+ LOAD_2VECS_UB(src, src_stride, src7, src8);
+ src += (2 * src_stride);
+
+ XORI_B_2VECS_SB(src7, src8, vec7, vec8, 128);
+
+ ILVR_B_4VECS_SH(vec0, vec2, vec4, vec6, vec1, vec3, vec5, vec7,
+ vec01, vec23, vec45, vec67);
+
+ tmp0 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1,
+ filt2, filt3);
+
+ ILVR_B_4VECS_SH(vec1, vec3, vec5, vec7, vec2, vec4, vec6, vec8,
+ vec01, vec23, vec45, vec67);
+
+ tmp1 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1,
+ filt2, filt3);
+
+ /* 4 width */
+ vec15 = (v16i8) __msa_vshf_w(mask, (v4i32) vec7, (v4i32) vec6);
+ vec16 = (v16i8) __msa_vshf_w(mask, (v4i32) vec8, (v4i32) vec7);
+
+ ILVR_B_4VECS_SH(vec9, vec11, vec13, vec15, vec10, vec12, vec14, vec16,
+ vec01, vec23, vec45, vec67);
+
+ tmp2 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1,
+ filt2, filt3);
+
+ tmp0 = SRAR_SATURATE_SIGNED_H(tmp0, rnd_vec, 7);
+ tmp1 = SRAR_SATURATE_SIGNED_H(tmp1, rnd_vec, 7);
+ tmp2 = SRAR_SATURATE_SIGNED_H(tmp2, rnd_vec, 7);
+
+ res0 = __msa_pckev_b((v16i8) tmp0, (v16i8) tmp0);
+ res1 = __msa_pckev_b((v16i8) tmp1, (v16i8) tmp1);
+ res2 = __msa_pckev_b((v16i8) tmp2, (v16i8) tmp2);
+
+ XORI_B_3VECS_SB(res0, res1, res2, res0, res1, res2, 128);
+
+ out0 = __msa_copy_u_d((v2i64) res0, 0);
+ out1 = __msa_copy_u_d((v2i64) res1, 0);
+ out2 = __msa_copy_u_w((v4i32) res2, 0);
+ out3 = __msa_copy_u_w((v4i32) res2, 1);
+
+ STORE_DWORD(dst, out0);
+ STORE_WORD((dst + 8), out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ STORE_WORD((dst + 8), out3);
+ dst += dst_stride;
+
+ vec0 = vec2;
+ vec1 = vec3;
+ vec2 = vec4;
+ vec3 = vec5;
+ vec4 = vec6;
+ vec5 = vec7;
+ vec6 = vec8;
+ vec9 = vec11;
+ vec10 = vec12;
+ vec11 = vec13;
+ vec12 = vec14;
+ vec13 = vec15;
+ vec14 = vec16;
+ }
+}
+
+static void common_vt_8t_16w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ uint32_t loop_cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v16i8 src10_l, src32_l, src54_l, src76_l, src98_l;
+ v16i8 src21_l, src43_l, src65_l, src87_l, src109_l;
+ v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l;
+ v8i16 filt;
+ v8u16 rnd_vec;
+ v16u8 tmp0, tmp1, tmp2, tmp3;
+
+ src -= (3 * src_stride);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ LOAD_7VECS_SB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ ILVL_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_l, src32_l, src54_l, src21_l, src43_l, src65_l);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src, src_stride, src7, src8, src9, src10);
+ src += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src7, src8, src9, src10,
+ src7, src8, src9, src10, 128);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ ILVL_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_l, src87_l, src98_l, src109_l);
+
+ out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r,
+ filt0, filt1, filt2, filt3);
+ out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r,
+ filt0, filt1, filt2, filt3);
+ out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r,
+ filt0, filt1, filt2, filt3);
+ out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r,
+ filt0, filt1, filt2, filt3);
+
+ out0_l = FILT_8TAP_DPADD_S_H(src10_l, src32_l, src54_l, src76_l,
+ filt0, filt1, filt2, filt3);
+ out1_l = FILT_8TAP_DPADD_S_H(src21_l, src43_l, src65_l, src87_l,
+ filt0, filt1, filt2, filt3);
+ out2_l = FILT_8TAP_DPADD_S_H(src32_l, src54_l, src76_l, src98_l,
+ filt0, filt1, filt2, filt3);
+ out3_l = FILT_8TAP_DPADD_S_H(src43_l, src65_l, src87_l, src109_l,
+ filt0, filt1, filt2, filt3);
+
+ out0_r = SRAR_SATURATE_SIGNED_H(out0_r, rnd_vec, 7);
+ out1_r = SRAR_SATURATE_SIGNED_H(out1_r, rnd_vec, 7);
+ out2_r = SRAR_SATURATE_SIGNED_H(out2_r, rnd_vec, 7);
+ out3_r = SRAR_SATURATE_SIGNED_H(out3_r, rnd_vec, 7);
+ out0_l = SRAR_SATURATE_SIGNED_H(out0_l, rnd_vec, 7);
+ out1_l = SRAR_SATURATE_SIGNED_H(out1_l, rnd_vec, 7);
+ out2_l = SRAR_SATURATE_SIGNED_H(out2_l, rnd_vec, 7);
+ out3_l = SRAR_SATURATE_SIGNED_H(out3_l, rnd_vec, 7);
+
+ PCKEV_B_4VECS_UB(out0_l, out1_l, out2_l, out3_l, out0_r, out1_r, out2_r,
+ out3_r, tmp0, tmp1, tmp2, tmp3);
+
+ XORI_B_4VECS_UB(tmp0, tmp1, tmp2, tmp3, tmp0, tmp1, tmp2, tmp3, 128);
+
+ STORE_4VECS_UB(dst, dst_stride, tmp0, tmp1, tmp2, tmp3);
+ dst += (4 * dst_stride);
+
+ src10_r = src54_r;
+ src32_r = src76_r;
+ src54_r = src98_r;
+ src21_r = src65_r;
+ src43_r = src87_r;
+ src65_r = src109_r;
+ src10_l = src54_l;
+ src32_l = src76_l;
+ src54_l = src98_l;
+ src21_l = src65_l;
+ src43_l = src87_l;
+ src65_l = src109_l;
+
+ src6 = src10;
+ }
+}
+
+static void common_vt_8t_16w_mult_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val, int32_t width)
+{
+ uint8_t *src_tmp;
+ uint8_t *dst_tmp;
+ uint32_t loop_cnt, cnt;
+ v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10;
+ v16i8 filt0, filt1, filt2, filt3;
+ v16i8 src10_r, src32_r, src54_r, src76_r, src98_r;
+ v16i8 src21_r, src43_r, src65_r, src87_r, src109_r;
+ v16i8 src10_l, src32_l, src54_l, src76_l, src98_l;
+ v16i8 src21_l, src43_l, src65_l, src87_l, src109_l;
+ v8i16 filt, out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l;
+ v16u8 tmp0, tmp1, tmp2, tmp3;
+ v8u16 rnd_vec;
+
+ src -= (3 * src_stride);
+
+ rnd_vec = (v8u16) __msa_fill_h(rnd_val);
+
+ filt = LOAD_SH(filter);
+ filt0 = (v16i8) __msa_splati_h(filt, 0);
+ filt1 = (v16i8) __msa_splati_h(filt, 1);
+ filt2 = (v16i8) __msa_splati_h(filt, 2);
+ filt3 = (v16i8) __msa_splati_h(filt, 3);
+
+ for (cnt = (width >> 4); cnt--;) {
+ src_tmp = src;
+ dst_tmp = dst;
+
+ LOAD_7VECS_SB(src_tmp, src_stride,
+ src0, src1, src2, src3, src4, src5, src6);
+ src_tmp += (7 * src_stride);
+
+ XORI_B_7VECS_SB(src0, src1, src2, src3, src4, src5, src6,
+ src0, src1, src2, src3, src4, src5, src6, 128);
+
+ ILVR_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_r, src32_r, src54_r, src21_r, src43_r, src65_r);
+
+ ILVL_B_6VECS_SB(src0, src2, src4, src1, src3, src5,
+ src1, src3, src5, src2, src4, src6,
+ src10_l, src32_l, src54_l, src21_l, src43_l, src65_l);
+
+ for (loop_cnt = (height >> 2); loop_cnt--;) {
+ LOAD_4VECS_SB(src_tmp, src_stride, src7, src8, src9, src10);
+ src_tmp += (4 * src_stride);
+
+ XORI_B_4VECS_SB(src7, src8, src9, src10,
+ src7, src8, src9, src10, 128);
+
+ ILVR_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_r, src87_r, src98_r, src109_r);
+
+ ILVL_B_4VECS_SB(src6, src7, src8, src9, src7, src8, src9, src10,
+ src76_l, src87_l, src98_l, src109_l);
+
+ out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r,
+ filt0, filt1, filt2, filt3);
+ out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r,
+ filt0, filt1, filt2, filt3);
+ out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r,
+ filt0, filt1, filt2, filt3);
+ out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r,
+ filt0, filt1, filt2, filt3);
+
+ out0_l = FILT_8TAP_DPADD_S_H(src10_l, src32_l, src54_l, src76_l,
+ filt0, filt1, filt2, filt3);
+ out1_l = FILT_8TAP_DPADD_S_H(src21_l, src43_l, src65_l, src87_l,
+ filt0, filt1, filt2, filt3);
+ out2_l = FILT_8TAP_DPADD_S_H(src32_l, src54_l, src76_l, src98_l,
+ filt0, filt1, filt2, filt3);
+ out3_l = FILT_8TAP_DPADD_S_H(src43_l, src65_l, src87_l, src109_l,
+ filt0, filt1, filt2, filt3);
+
+ out0_r = SRAR_SATURATE_SIGNED_H(out0_r, rnd_vec, 7);
+ out1_r = SRAR_SATURATE_SIGNED_H(out1_r, rnd_vec, 7);
+ out2_r = SRAR_SATURATE_SIGNED_H(out2_r, rnd_vec, 7);
+ out3_r = SRAR_SATURATE_SIGNED_H(out3_r, rnd_vec, 7);
+ out0_l = SRAR_SATURATE_SIGNED_H(out0_l, rnd_vec, 7);
+ out1_l = SRAR_SATURATE_SIGNED_H(out1_l, rnd_vec, 7);
+ out2_l = SRAR_SATURATE_SIGNED_H(out2_l, rnd_vec, 7);
+ out3_l = SRAR_SATURATE_SIGNED_H(out3_l, rnd_vec, 7);
+
+ PCKEV_B_4VECS_UB(out0_l, out1_l, out2_l, out3_l, out0_r, out1_r,
+ out2_r, out3_r, tmp0, tmp1, tmp2, tmp3);
+
+ XORI_B_4VECS_UB(tmp0, tmp1, tmp2, tmp3,
+ tmp0, tmp1, tmp2, tmp3, 128);
+
+ STORE_4VECS_UB(dst_tmp, dst_stride, tmp0, tmp1, tmp2, tmp3);
+ dst_tmp += (4 * dst_stride);
+
+ src10_r = src54_r;
+ src32_r = src76_r;
+ src54_r = src98_r;
+ src21_r = src65_r;
+ src43_r = src87_r;
+ src65_r = src109_r;
+ src10_l = src54_l;
+ src32_l = src76_l;
+ src54_l = src98_l;
+ src21_l = src65_l;
+ src43_l = src87_l;
+ src65_l = src109_l;
+
+ src6 = src10;
+ }
+
+ src += 16;
+ dst += 16;
+ }
+}
+
+static void common_vt_8t_24w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ common_vt_8t_16w_mult_msa(src, src_stride, dst, dst_stride, filter,
+ height, rnd_val, 16);
+
+ common_vt_8t_8w_msa(src + 16, src_stride, dst + 16, dst_stride,
+ filter, height, rnd_val);
+}
+
+static void common_vt_8t_32w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ common_vt_8t_16w_mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, rnd_val, 32);
+}
+
+static void common_vt_8t_48w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ common_vt_8t_16w_mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, rnd_val, 48);
+}
+
+static void common_vt_8t_64w_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ const int8_t *filter, int32_t height,
+ uint8_t rnd_val)
+{
+ common_vt_8t_16w_mult_msa(src, src_stride, dst, dst_stride,
+ filter, height, rnd_val, 64);
+}
+
+static void copy_width8_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ int32_t cnt;
+ uint64_t out0, out1, out2, out3, out4, out5, out6, out7;
+ v16u8 src0, src1, src2, src3, src4, src5, src6, src7;
+
+ if (0 == height % 12) {
+ for (cnt = (height / 12); cnt--;) {
+ LOAD_8VECS_UB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ out0 = __msa_copy_u_d((v2i64) src0, 0);
+ out1 = __msa_copy_u_d((v2i64) src1, 0);
+ out2 = __msa_copy_u_d((v2i64) src2, 0);
+ out3 = __msa_copy_u_d((v2i64) src3, 0);
+ out4 = __msa_copy_u_d((v2i64) src4, 0);
+ out5 = __msa_copy_u_d((v2i64) src5, 0);
+ out6 = __msa_copy_u_d((v2i64) src6, 0);
+ out7 = __msa_copy_u_d((v2i64) src7, 0);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+ STORE_DWORD(dst, out4);
+ dst += dst_stride;
+ STORE_DWORD(dst, out5);
+ dst += dst_stride;
+ STORE_DWORD(dst, out6);
+ dst += dst_stride;
+ STORE_DWORD(dst, out7);
+ dst += dst_stride;
+
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ out0 = __msa_copy_u_d((v2i64) src0, 0);
+ out1 = __msa_copy_u_d((v2i64) src1, 0);
+ out2 = __msa_copy_u_d((v2i64) src2, 0);
+ out3 = __msa_copy_u_d((v2i64) src3, 0);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+ }
+ } else if (0 == height % 8) {
+ for (cnt = height >> 3; cnt--;) {
+ LOAD_8VECS_UB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ out0 = __msa_copy_u_d((v2i64) src0, 0);
+ out1 = __msa_copy_u_d((v2i64) src1, 0);
+ out2 = __msa_copy_u_d((v2i64) src2, 0);
+ out3 = __msa_copy_u_d((v2i64) src3, 0);
+ out4 = __msa_copy_u_d((v2i64) src4, 0);
+ out5 = __msa_copy_u_d((v2i64) src5, 0);
+ out6 = __msa_copy_u_d((v2i64) src6, 0);
+ out7 = __msa_copy_u_d((v2i64) src7, 0);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+ STORE_DWORD(dst, out4);
+ dst += dst_stride;
+ STORE_DWORD(dst, out5);
+ dst += dst_stride;
+ STORE_DWORD(dst, out6);
+ dst += dst_stride;
+ STORE_DWORD(dst, out7);
+ dst += dst_stride;
+ }
+ } else if (0 == height % 4) {
+ for (cnt = (height / 4); cnt--;) {
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ out0 = __msa_copy_u_d((v2i64) src0, 0);
+ out1 = __msa_copy_u_d((v2i64) src1, 0);
+ out2 = __msa_copy_u_d((v2i64) src2, 0);
+ out3 = __msa_copy_u_d((v2i64) src3, 0);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ dst += dst_stride;
+ }
+ } else if (0 == height % 2) {
+ for (cnt = (height / 2); cnt--;) {
+ LOAD_2VECS_UB(src, src_stride, src0, src1);
+ src += (2 * src_stride);
+
+ out0 = __msa_copy_u_d((v2i64) src0, 0);
+ out1 = __msa_copy_u_d((v2i64) src1, 0);
+
+ STORE_DWORD(dst, out0);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ dst += dst_stride;
+ }
+ }
+}
+
+static void copy_width12_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ int32_t cnt;
+ uint64_t out0, out1, out2, out3, out4, out5, out6, out7;
+ uint32_t out8, out9, out10, out11, out12, out13, out14, out15;
+ v16u8 src0, src1, src2, src3, src4, src5, src6, src7;
+
+ for (cnt = 2; cnt--;) {
+ LOAD_8VECS_UB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ out0 = __msa_copy_u_d((v2i64) src0, 0);
+ out1 = __msa_copy_u_d((v2i64) src1, 0);
+ out2 = __msa_copy_u_d((v2i64) src2, 0);
+ out3 = __msa_copy_u_d((v2i64) src3, 0);
+ out4 = __msa_copy_u_d((v2i64) src4, 0);
+ out5 = __msa_copy_u_d((v2i64) src5, 0);
+ out6 = __msa_copy_u_d((v2i64) src6, 0);
+ out7 = __msa_copy_u_d((v2i64) src7, 0);
+
+ out8 = __msa_copy_u_w((v4i32) src0, 2);
+ out9 = __msa_copy_u_w((v4i32) src1, 2);
+ out10 = __msa_copy_u_w((v4i32) src2, 2);
+ out11 = __msa_copy_u_w((v4i32) src3, 2);
+ out12 = __msa_copy_u_w((v4i32) src4, 2);
+ out13 = __msa_copy_u_w((v4i32) src5, 2);
+ out14 = __msa_copy_u_w((v4i32) src6, 2);
+ out15 = __msa_copy_u_w((v4i32) src7, 2);
+
+ STORE_DWORD(dst, out0);
+ STORE_WORD(dst + 8, out8);
+ dst += dst_stride;
+ STORE_DWORD(dst, out1);
+ STORE_WORD(dst + 8, out9);
+ dst += dst_stride;
+ STORE_DWORD(dst, out2);
+ STORE_WORD(dst + 8, out10);
+ dst += dst_stride;
+ STORE_DWORD(dst, out3);
+ STORE_WORD(dst + 8, out11);
+ dst += dst_stride;
+ STORE_DWORD(dst, out4);
+ STORE_WORD(dst + 8, out12);
+ dst += dst_stride;
+ STORE_DWORD(dst, out5);
+ STORE_WORD(dst + 8, out13);
+ dst += dst_stride;
+ STORE_DWORD(dst, out6);
+ STORE_WORD(dst + 8, out14);
+ dst += dst_stride;
+ STORE_DWORD(dst, out7);
+ STORE_WORD(dst + 8, out15);
+ dst += dst_stride;
+ }
+}
+
+static void copy_16multx8mult_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height, int32_t width)
+{
+ int32_t cnt, loop_cnt;
+ uint8_t *src_tmp, *dst_tmp;
+ v16u8 src0, src1, src2, src3, src4, src5, src6, src7;
+
+ for (cnt = (width >> 4); cnt--;) {
+ src_tmp = src;
+ dst_tmp = dst;
+
+ for (loop_cnt = (height >> 3); loop_cnt--;) {
+ LOAD_8VECS_UB(src_tmp, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src_tmp += (8 * src_stride);
+
+ STORE_8VECS_UB(dst_tmp, dst_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ dst_tmp += (8 * dst_stride);
+ }
+
+ src += 16;
+ dst += 16;
+ }
+}
+
+static void copy_width16_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ int32_t cnt;
+ v16u8 src0, src1, src2, src3, src4, src5, src6, src7;
+
+ if (0 == height % 12) {
+ for (cnt = (height / 12); cnt--;) {
+ LOAD_8VECS_UB(src, src_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ src += (8 * src_stride);
+
+ STORE_8VECS_UB(dst, dst_stride,
+ src0, src1, src2, src3, src4, src5, src6, src7);
+ dst += (8 * dst_stride);
+
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ STORE_4VECS_UB(dst, dst_stride, src0, src1, src2, src3);
+ dst += (4 * dst_stride);
+ }
+ } else if (0 == height % 8) {
+ copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 16);
+ } else if (0 == height % 4) {
+ for (cnt = (height >> 2); cnt--;) {
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ src += (4 * src_stride);
+
+ STORE_4VECS_UB(dst, dst_stride, src0, src1, src2, src3);
+ dst += (4 * dst_stride);
+ }
+ }
+}
+
+static void copy_width24_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 16);
+
+ copy_width8_msa(src + 16, src_stride, dst + 16, dst_stride, height);
+}
+
+static void copy_width32_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ int32_t cnt;
+ v16u8 src0, src1, src2, src3, src4, src5, src6, src7;
+
+ if (0 == height % 12) {
+ for (cnt = (height / 12); cnt--;) {
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ LOAD_4VECS_UB(src + 16, src_stride, src4, src5, src6, src7);
+ src += (4 * src_stride);
+
+ STORE_4VECS_UB(dst, dst_stride, src0, src1, src2, src3);
+ STORE_4VECS_UB(dst + 16, dst_stride, src4, src5, src6, src7);
+ dst += (4 * dst_stride);
+
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ LOAD_4VECS_UB(src + 16, src_stride, src4, src5, src6, src7);
+ src += (4 * src_stride);
+
+ STORE_4VECS_UB(dst, dst_stride, src0, src1, src2, src3);
+ STORE_4VECS_UB(dst + 16, dst_stride, src4, src5, src6, src7);
+ dst += (4 * dst_stride);
+
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ LOAD_4VECS_UB(src + 16, src_stride, src4, src5, src6, src7);
+ src += (4 * src_stride);
+
+ STORE_4VECS_UB(dst, dst_stride, src0, src1, src2, src3);
+ STORE_4VECS_UB(dst + 16, dst_stride, src4, src5, src6, src7);
+ dst += (4 * dst_stride);
+ }
+ } else if (0 == height % 8) {
+ copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 32);
+ } else if (0 == height % 4) {
+ for (cnt = (height >> 2); cnt--;) {
+ LOAD_4VECS_UB(src, src_stride, src0, src1, src2, src3);
+ LOAD_4VECS_UB(src + 16, src_stride, src4, src5, src6, src7);
+ src += (4 * src_stride);
+
+ STORE_4VECS_UB(dst, dst_stride, src0, src1, src2, src3);
+ STORE_4VECS_UB(dst + 16, dst_stride, src4, src5, src6, src7);
+ dst += (4 * dst_stride);
+ }
+ }
+}
+
+static void copy_width48_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 48);
+}
+
+static void copy_width64_msa(uint8_t *src, int32_t src_stride,
+ uint8_t *dst, int32_t dst_stride,
+ int32_t height)
+{
+ copy_16multx8mult_msa(src, src_stride, dst, dst_stride, height, 64);
+}
+
+#define MC_COPY(WIDTH) \
+void ff_hevc_put_hevc_pel_pixels##WIDTH##_8_msa(int16_t *dst, \
+ uint8_t *src, \
+ ptrdiff_t src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width) \
+{ \
+ hevc_copy_##WIDTH##w_msa(src, src_stride, dst, MAX_PB_SIZE, height); \
+}
+
+MC_COPY(4);
+MC_COPY(6);
+MC_COPY(8);
+MC_COPY(12);
+MC_COPY(16);
+MC_COPY(24);
+MC_COPY(32);
+MC_COPY(48);
+MC_COPY(64);
+
+#undef MC_COPY
+
+#define MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \
+void ff_hevc_put_hevc_##PEL##_##DIR####WIDTH##_8_msa(int16_t *dst, \
+ uint8_t *src, \
+ ptrdiff_t src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width) \
+{ \
+ const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \
+ \
+ hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \
+ MAX_PB_SIZE, filter, height); \
+}
+
+MC(qpel, h, 4, 8, hz, mx);
+MC(qpel, h, 8, 8, hz, mx);
+MC(qpel, h, 12, 8, hz, mx);
+MC(qpel, h, 16, 8, hz, mx);
+MC(qpel, h, 24, 8, hz, mx);
+MC(qpel, h, 32, 8, hz, mx);
+MC(qpel, h, 48, 8, hz, mx);
+MC(qpel, h, 64, 8, hz, mx);
+
+MC(qpel, v, 4, 8, vt, my);
+MC(qpel, v, 8, 8, vt, my);
+MC(qpel, v, 12, 8, vt, my);
+MC(qpel, v, 16, 8, vt, my);
+MC(qpel, v, 24, 8, vt, my);
+MC(qpel, v, 32, 8, vt, my);
+MC(qpel, v, 48, 8, vt, my);
+MC(qpel, v, 64, 8, vt, my);
+
+#undef MC
+
+#define MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \
+void ff_hevc_put_hevc_##PEL##_##DIR####WIDTH##_8_msa(int16_t *dst, \
+ uint8_t *src, \
+ ptrdiff_t src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width) \
+{ \
+ const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \
+ const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \
+ \
+ hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, MAX_PB_SIZE, \
+ filter_x, filter_y, height); \
+}
+
+MC_HV(qpel, hv, 4, 8, hv);
+MC_HV(qpel, hv, 8, 8, hv);
+MC_HV(qpel, hv, 12, 8, hv);
+MC_HV(qpel, hv, 16, 8, hv);
+MC_HV(qpel, hv, 24, 8, hv);
+MC_HV(qpel, hv, 32, 8, hv);
+MC_HV(qpel, hv, 48, 8, hv);
+MC_HV(qpel, hv, 64, 8, hv);
+
+#undef MC_HV
+
+#define UNI_MC_COPY(WIDTH) \
+void ff_hevc_put_hevc_uni_pel_pixels##WIDTH##_8_msa(uint8_t *dst, \
+ ptrdiff_t dst_stride, \
+ uint8_t *src, \
+ ptrdiff_t src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width) \
+{ \
+ copy_width##WIDTH##_msa(src, src_stride, dst, dst_stride, height); \
+}
+
+UNI_MC_COPY(8);
+UNI_MC_COPY(12);
+UNI_MC_COPY(16);
+UNI_MC_COPY(24);
+UNI_MC_COPY(32);
+UNI_MC_COPY(48);
+UNI_MC_COPY(64);
+
+#undef UNI_MC_COPY
+
+#define UNI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \
+void ff_hevc_put_hevc_uni_##PEL##_##DIR####WIDTH##_8_msa(uint8_t *dst, \
+ ptrdiff_t \
+ dst_stride, \
+ uint8_t *src, \
+ ptrdiff_t \
+ src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width) \
+{ \
+ const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \
+ \
+ common_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, dst_stride, \
+ filter, height, 6); \
+}
+
+UNI_MC(qpel, h, 4, 8, hz, mx);
+UNI_MC(qpel, h, 8, 8, hz, mx);
+UNI_MC(qpel, h, 12, 8, hz, mx);
+UNI_MC(qpel, h, 16, 8, hz, mx);
+UNI_MC(qpel, h, 24, 8, hz, mx);
+UNI_MC(qpel, h, 32, 8, hz, mx);
+UNI_MC(qpel, h, 48, 8, hz, mx);
+UNI_MC(qpel, h, 64, 8, hz, mx);
+
+UNI_MC(qpel, v, 4, 8, vt, my);
+UNI_MC(qpel, v, 8, 8, vt, my);
+UNI_MC(qpel, v, 12, 8, vt, my);
+UNI_MC(qpel, v, 16, 8, vt, my);
+UNI_MC(qpel, v, 24, 8, vt, my);
+UNI_MC(qpel, v, 32, 8, vt, my);
+UNI_MC(qpel, v, 48, 8, vt, my);
+UNI_MC(qpel, v, 64, 8, vt, my);
+
+#undef UNI_MC
+
+#define UNI_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \
+void ff_hevc_put_hevc_uni_##PEL##_##DIR####WIDTH##_8_msa(uint8_t *dst, \
+ ptrdiff_t \
+ dst_stride, \
+ uint8_t *src, \
+ ptrdiff_t \
+ src_stride, \
+ int height, \
+ intptr_t mx, \
+ intptr_t my, \
+ int width) \
+{ \
+ const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \
+ const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \
+ \
+ hevc_##DIR1##_uni_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \
+ dst_stride, filter_x, \
+ filter_y, height); \
+}
+
+UNI_MC_HV(qpel, hv, 4, 8, hv);
+UNI_MC_HV(qpel, hv, 8, 8, hv);
+UNI_MC_HV(qpel, hv, 12, 8, hv);
+UNI_MC_HV(qpel, hv, 16, 8, hv);
+UNI_MC_HV(qpel, hv, 24, 8, hv);
+UNI_MC_HV(qpel, hv, 32, 8, hv);
+UNI_MC_HV(qpel, hv, 48, 8, hv);
+UNI_MC_HV(qpel, hv, 64, 8, hv);
+
+#undef UNI_MC_HV
diff --git a/libavcodec/mips/iirfilter_mips.c b/libavcodec/mips/iirfilter_mips.c
new file mode 100644
index 0000000000..5a145cff58
--- /dev/null
+++ b/libavcodec/mips/iirfilter_mips.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Bojan Zivkovic (bojan@mips.com)
+ *
+ * IIR filter optimized for MIPS floating-point architecture
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ /**
+ * @file
+ * Reference: libavcodec/iirfilter.c
+ */
+
+#include "libavcodec/iirfilter.h"
+
+#if HAVE_INLINE_ASM
+#if !HAVE_LOONGSON3
+typedef struct FFIIRFilterCoeffs {
+ int order;
+ float gain;
+ int *cx;
+ float *cy;
+} FFIIRFilterCoeffs;
+
+typedef struct FFIIRFilterState {
+ float x[1];
+} FFIIRFilterState;
+
+static void ff_iir_filter_flt_mips(const struct FFIIRFilterCoeffs *c,
+ struct FFIIRFilterState *s, int size,
+ const float *src, int sstep, float *dst, int dstep)
+{
+ if (c->order == 2) {
+ int i;
+ const float *src0 = src;
+ float *dst0 = dst;
+ for (i = 0; i < size; i++) {
+ float in = *src0 * c->gain + s->x[0] * c->cy[0] + s->x[1] * c->cy[1];
+ *dst0 = s->x[0] + in + s->x[1] * c->cx[1];
+ s->x[0] = s->x[1];
+ s->x[1] = in;
+ src0 += sstep;
+ dst0 += dstep;
+ }
+ } else if (c->order == 4) {
+ int i;
+ const float *src0 = src;
+ float *dst0 = dst;
+ float four = 4.0;
+ float six = 6.0;
+ for (i = 0; i < size; i += 4) {
+ float in1, in2, in3, in4;
+ float res1, res2, res3, res4;
+ float *x = s->x;
+ float *cy = c->cy;
+ float gain = c->gain;
+ float src0_0 = src0[0 ];
+ float src0_1 = src0[sstep ];
+ float src0_2 = src0[2*sstep];
+ float src0_3 = src0[3*sstep];
+
+ __asm__ volatile (
+ "lwc1 $f0, 0(%[cy]) \n\t"
+ "lwc1 $f4, 0(%[x]) \n\t"
+ "lwc1 $f5, 4(%[x]) \n\t"
+ "lwc1 $f6, 8(%[x]) \n\t"
+ "lwc1 $f7, 12(%[x]) \n\t"
+ "mul.s %[in1], %[src0_0], %[gain] \n\t"
+ "mul.s %[in2], %[src0_1], %[gain] \n\t"
+ "mul.s %[in3], %[src0_2], %[gain] \n\t"
+ "mul.s %[in4], %[src0_3], %[gain] \n\t"
+ "lwc1 $f1, 4(%[cy]) \n\t"
+ "madd.s %[in1], %[in1], $f0, $f4 \n\t"
+ "madd.s %[in2], %[in2], $f0, $f5 \n\t"
+ "madd.s %[in3], %[in3], $f0, $f6 \n\t"
+ "madd.s %[in4], %[in4], $f0, $f7 \n\t"
+ "lwc1 $f2, 8(%[cy]) \n\t"
+ "madd.s %[in1], %[in1], $f1, $f5 \n\t"
+ "madd.s %[in2], %[in2], $f1, $f6 \n\t"
+ "madd.s %[in3], %[in3], $f1, $f7 \n\t"
+ "lwc1 $f3, 12(%[cy]) \n\t"
+ "add.s $f8, $f5, $f7 \n\t"
+ "madd.s %[in1], %[in1], $f2, $f6 \n\t"
+ "madd.s %[in2], %[in2], $f2, $f7 \n\t"
+ "mul.s $f9, $f6, %[six] \n\t"
+ "mul.s $f10, $f7, %[six] \n\t"
+ "madd.s %[in1], %[in1], $f3, $f7 \n\t"
+ "madd.s %[in2], %[in2], $f3, %[in1] \n\t"
+ "madd.s %[in3], %[in3], $f2, %[in1] \n\t"
+ "madd.s %[in4], %[in4], $f1, %[in1] \n\t"
+ "add.s %[res1], $f4, %[in1] \n\t"
+ "swc1 %[in1], 0(%[x]) \n\t"
+ "add.s $f0, $f6, %[in1] \n\t"
+ "madd.s %[in3], %[in3], $f3, %[in2] \n\t"
+ "madd.s %[in4], %[in4], $f2, %[in2] \n\t"
+ "add.s %[res2], $f5, %[in2] \n\t"
+ "madd.s %[res1], %[res1], $f8, %[four] \n\t"
+ "add.s $f8, $f7, %[in2] \n\t"
+ "swc1 %[in2], 4(%[x]) \n\t"
+ "madd.s %[in4], %[in4], $f3, %[in3] \n\t"
+ "add.s %[res3], $f6, %[in3] \n\t"
+ "add.s %[res1], %[res1], $f9 \n\t"
+ "madd.s %[res2], %[res2], $f0, %[four] \n\t"
+ "swc1 %[in3], 8(%[x]) \n\t"
+ "add.s %[res4], $f7, %[in4] \n\t"
+ "madd.s %[res3], %[res3], $f8, %[four] \n\t"
+ "swc1 %[in4], 12(%[x]) \n\t"
+ "add.s %[res2], %[res2], $f10 \n\t"
+ "add.s $f8, %[in1], %[in3] \n\t"
+ "madd.s %[res3], %[res3], %[in1], %[six] \n\t"
+ "madd.s %[res4], %[res4], $f8, %[four] \n\t"
+ "madd.s %[res4], %[res4], %[in2], %[six] \n\t"
+
+ : [in1]"=&f"(in1), [in2]"=&f"(in2),
+ [in3]"=&f"(in3), [in4]"=&f"(in4),
+ [res1]"=&f"(res1), [res2]"=&f"(res2),
+ [res3]"=&f"(res3), [res4]"=&f"(res4)
+ : [src0_0]"f"(src0_0), [src0_1]"f"(src0_1),
+ [src0_2]"f"(src0_2), [src0_3]"f"(src0_3),
+ [gain]"f"(gain), [x]"r"(x), [cy]"r"(cy),
+ [four]"f"(four), [six]"f"(six)
+ : "$f0", "$f1", "$f2", "$f3",
+ "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10",
+ "memory"
+ );
+
+ dst0[0 ] = res1;
+ dst0[sstep ] = res2;
+ dst0[2*sstep] = res3;
+ dst0[3*sstep] = res4;
+
+ src0 += 4*sstep;
+ dst0 += 4*dstep;
+ }
+ } else {
+ int i;
+ const float *src0 = src;
+ float *dst0 = dst;
+ for (i = 0; i < size; i++) {
+ int j;
+ float in, res;
+ in = *src0 * c->gain;
+ for(j = 0; j < c->order; j++)
+ in += c->cy[j] * s->x[j];
+ res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1];
+ for(j = 1; j < c->order >> 1; j++)
+ res += (s->x[j] + s->x[c->order - j]) * c->cx[j];
+ for(j = 0; j < c->order - 1; j++)
+ s->x[j] = s->x[j + 1];
+ *dst0 = res;
+ s->x[c->order - 1] = in;
+ src0 += sstep;
+ dst0 += dstep;
+ }
+ }
+}
+#endif /* !HAVE_LOONGSON3 */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_iir_filter_init_mips(FFIIRFilterContext *f) {
+#if HAVE_INLINE_ASM
+#if !HAVE_LOONGSON3
+ f->filter_flt = ff_iir_filter_flt_mips;
+#endif /* !HAVE_LOONGSON3 */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mips/lsp_mips.h b/libavcodec/mips/lsp_mips.h
new file mode 100644
index 0000000000..9d7521865b
--- /dev/null
+++ b/libavcodec/mips/lsp_mips.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * LSP routines for ACELP-based codecs 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/lsp.c
+ */
+#ifndef AVCODEC_LSP_MIPS_H
+#define AVCODEC_LSP_MIPS_H
+
+#if HAVE_MIPSFPU && HAVE_INLINE_ASM
+#include "libavutil/mips/asmdefs.h"
+
+static av_always_inline void ff_lsp2polyf_mips(const double *lsp, double *f, int lp_half_order)
+{
+ int i, j = 0;
+ double * p_fi = f;
+ double * p_f = 0;
+
+ f[0] = 1.0;
+ f[1] = -2 * lsp[0];
+ lsp -= 2;
+
+ for(i=2; i<=lp_half_order; i++)
+ {
+ double tmp, f_j_2, f_j_1, f_j;
+ double val = lsp[2*i];
+
+ __asm__ volatile(
+ "move %[p_f], %[p_fi] \n\t"
+ "add.d %[val], %[val], %[val] \n\t"
+ PTR_ADDIU "%[p_fi], 8 \n\t"
+ "ldc1 %[f_j_1], 0(%[p_f]) \n\t"
+ "ldc1 %[f_j], 8(%[p_f]) \n\t"
+ "neg.d %[val], %[val] \n\t"
+ "add.d %[tmp], %[f_j_1], %[f_j_1] \n\t"
+ "madd.d %[tmp], %[tmp], %[f_j], %[val] \n\t"
+ "addiu %[j], %[i], -2 \n\t"
+ "ldc1 %[f_j_2], -8(%[p_f]) \n\t"
+ "sdc1 %[tmp], 16(%[p_f]) \n\t"
+ "beqz %[j], ff_lsp2polyf_lp_j_end%= \n\t"
+ "ff_lsp2polyf_lp_j%=: \n\t"
+ "add.d %[tmp], %[f_j], %[f_j_2] \n\t"
+ "madd.d %[tmp], %[tmp], %[f_j_1], %[val] \n\t"
+ "mov.d %[f_j], %[f_j_1] \n\t"
+ "addiu %[j], -1 \n\t"
+ "mov.d %[f_j_1], %[f_j_2] \n\t"
+ "ldc1 %[f_j_2], -16(%[p_f]) \n\t"
+ "sdc1 %[tmp], 8(%[p_f]) \n\t"
+ PTR_ADDIU "%[p_f], -8 \n\t"
+ "bgtz %[j], ff_lsp2polyf_lp_j%= \n\t"
+ "ff_lsp2polyf_lp_j_end%=: \n\t"
+
+ : [f_j_2]"=&f"(f_j_2), [f_j_1]"=&f"(f_j_1), [val]"+f"(val),
+ [tmp]"=&f"(tmp), [f_j]"=&f"(f_j), [p_f]"+r"(p_f),
+ [j]"+r"(j), [p_fi]"+r"(p_fi)
+ : [i]"r"(i)
+ : "memory"
+ );
+ f[1] += val;
+ }
+}
+#define ff_lsp2polyf ff_lsp2polyf_mips
+#endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM */
+#endif /* AVCODEC_LSP_MIPS_H */
diff --git a/libavcodec/mips/mathops.h b/libavcodec/mips/mathops.h
index dd80f68072..bb9dc8375a 100644
--- a/libavcodec/mips/mathops.h
+++ b/libavcodec/mips/mathops.h
@@ -1,20 +1,21 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
+ * Copyright (c) 2015 Zhou Xiaoyong <zhouxiaoyong@loongson.cn>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,55 +28,39 @@
#if HAVE_INLINE_ASM
-#if HAVE_LOONGSON
+#if HAVE_LOONGSON3
-static inline av_const int64_t MAC64(int64_t d, int a, int b)
+#define MULH MULH
+static inline av_const int MULH(int a, int b)
{
- int64_t m;
- __asm__ ("dmult.g %1, %2, %3 \n\t"
- "daddu %0, %0, %1 \n\t"
- : "+r"(d), "=&r"(m) : "r"(a), "r"(b));
- return d;
-}
-#define MAC64(d, a, b) ((d) = MAC64(d, a, b))
-
-static inline av_const int64_t MLS64(int64_t d, int a, int b)
-{
- int64_t m;
- __asm__ ("dmult.g %1, %2, %3 \n\t"
- "dsubu %0, %0, %1 \n\t"
- : "+r"(d), "=&r"(m) : "r"(a), "r"(b));
- return d;
-}
-#define MLS64(d, a, b) ((d) = MLS64(d, a, b))
-
-#elif ARCH_MIPS64
-
-static inline av_const int64_t MAC64(int64_t d, int a, int b)
-{
- int64_t m;
- __asm__ ("dmult %2, %3 \n\t"
- "mflo %1 \n\t"
- "daddu %0, %0, %1 \n\t"
- : "+r"(d), "=&r"(m) : "r"(a), "r"(b)
+ int c;
+ __asm__ ("dmult %1, %2 \n\t"
+ "mflo %0 \n\t"
+ "dsrl %0, %0, 32 \n\t"
+ : "=r"(c)
+ : "r"(a),"r"(b)
: "hi", "lo");
- return d;
+ return c;
}
-#define MAC64(d, a, b) ((d) = MAC64(d, a, b))
-static inline av_const int64_t MLS64(int64_t d, int a, int b)
+#define mid_pred mid_pred
+static inline av_const int mid_pred(int a, int b, int c)
{
- int64_t m;
- __asm__ ("dmult %2, %3 \n\t"
- "mflo %1 \n\t"
- "dsubu %0, %0, %1 \n\t"
- : "+r"(d), "=&r"(m) : "r"(a), "r"(b)
- : "hi", "lo");
- return d;
+ int t = b;
+ __asm__ ("sgt $8, %1, %2 \n\t"
+ "movn %0, %1, $8 \n\t"
+ "movn %1, %2, $8 \n\t"
+ "sgt $8, %1, %3 \n\t"
+ "movz %1, %3, $8 \n\t"
+ "sgt $8, %0, %1 \n\t"
+ "movn %0, %1, $8 \n\t"
+ : "+&r"(t),"+&r"(a)
+ : "r"(b),"r"(c)
+ : "$8");
+ return t;
}
-#define MLS64(d, a, b) ((d) = MLS64(d, a, b))
-#endif
+#endif /* HAVE_LOONGSON3 */
#endif /* HAVE_INLINE_ASM */
diff --git a/libavcodec/mips/mpegaudiodsp_mips_fixed.c b/libavcodec/mips/mpegaudiodsp_mips_fixed.c
new file mode 100644
index 0000000000..86ea13d8d6
--- /dev/null
+++ b/libavcodec/mips/mpegaudiodsp_mips_fixed.c
@@ -0,0 +1,908 @@
+ /*
+ * 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)
+ *
+ * MPEG Audio decoder optimized for MIPS fixed-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/mpegaudiodsp_template.c
+ */
+
+#include <string.h>
+
+#include "libavutil/mips/asmdefs.h"
+#include "libavcodec/mpegaudiodsp.h"
+
+static void ff_mpadsp_apply_window_mips_fixed(int32_t *synth_buf, int32_t *window,
+ int *dither_state, int16_t *samples, int incr)
+{
+ register const int32_t *w, *w2, *p;
+ int j;
+ int16_t *samples2;
+ int w_asm, p_asm, w_asm1, p_asm1, w_asm2, p_asm2;
+ int w2_asm, w2_asm1, *p_temp1, *p_temp2;
+ int sum1 = 0;
+ int const min_asm = -32768, max_asm = 32767;
+ int temp1, temp2 = 0, temp3 = 0;
+ int64_t sum;
+
+ /* copy to avoid wrap */
+ memcpy(synth_buf + 512, synth_buf, 32 * sizeof(*synth_buf));
+ samples2 = samples + 31 * incr;
+ w = window;
+ w2 = window + 31;
+ sum = *dither_state;
+ p = synth_buf + 16;
+ p_temp1 = synth_buf + 16;
+ p_temp2 = synth_buf + 48;
+ temp1 = sum;
+
+ /**
+ * use of round_sample function from the original code is eliminated,
+ * changed with appropriate assembly instructions.
+ */
+ __asm__ volatile (
+ "mthi $zero \n\t"
+ "mtlo %[temp1] \n\t"
+ "lw %[w_asm], 0(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p]) \n\t"
+ "lw %[w_asm1], 64*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p]) \n\t"
+ "lw %[w_asm2], 128*4(%[w]) \n\t"
+ "lw %[p_asm2], 128*4(%[p]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "madd %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 192*4(%[w]) \n\t"
+ "lw %[p_asm], 192*4(%[p]) \n\t"
+ "lw %[w_asm1], 256*4(%[w]) \n\t"
+ "lw %[p_asm1], 256*4(%[p]) \n\t"
+ "lw %[w_asm2], 320*4(%[w]) \n\t"
+ "lw %[p_asm2], 320*4(%[p]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "madd %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 384*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p]) \n\t"
+ "lw %[w_asm1], 448*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p]) \n\t"
+ "lw %[w_asm2], 32*4(%[w]) \n\t"
+ "lw %[p_asm2], 32*4(%[p]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 96*4(%[w]) \n\t"
+ "lw %[p_asm], 96*4(%[p]) \n\t"
+ "lw %[w_asm1], 160*4(%[w]) \n\t"
+ "lw %[p_asm1], 160*4(%[p]) \n\t"
+ "lw %[w_asm2], 224*4(%[w]) \n\t"
+ "lw %[p_asm2], 224*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 288*4(%[w]) \n\t"
+ "lw %[p_asm], 288*4(%[p]) \n\t"
+ "lw %[w_asm1], 352*4(%[w]) \n\t"
+ "lw %[p_asm1], 352*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "lw %[w_asm], 480*4(%[w]) \n\t"
+ "lw %[p_asm], 480*4(%[p]) \n\t"
+ "lw %[w_asm2], 416*4(%[w]) \n\t"
+ "lw %[p_asm2], 416*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+
+ /*round_sample function from the original code is eliminated,
+ * changed with appropriate assembly instructions
+ * code example:
+
+ "extr.w %[sum1],$ac0,24 \n\t"
+ "mflo %[temp3], $ac0 \n\t"
+ "and %[temp1], %[temp3], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm],%[temp2] \n\t"
+ "slt %[temp2], %[max_asm],%[sum1] \n\t"
+ "movn %[sum1], %[max_asm],%[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+ */
+
+ "extr.w %[sum1], $ac0, 24 \n\t"
+ "mflo %[temp3] \n\t"
+ PTR_ADDIU "%[w], %[w], 4 \n\t"
+ "and %[temp1], %[temp3], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+
+ : [w_asm] "=&r" (w_asm), [p_asm] "=&r" (p_asm), [w_asm1] "=&r" (w_asm1),
+ [p_asm1] "=&r" (p_asm1), [temp1] "+r" (temp1), [temp2] "+r" (temp2),
+ [w_asm2] "=&r" (w_asm2), [p_asm2] "=&r" (p_asm2),
+ [sum1] "+r" (sum1), [w] "+r" (w), [temp3] "+r" (temp3)
+ : [p] "r" (p), [samples] "r" (samples), [min_asm] "r" (min_asm),
+ [max_asm] "r" (max_asm)
+ : "memory", "hi","lo"
+ );
+
+ samples += incr;
+
+ /* we calculate two samples at the same time to avoid one memory
+ access per two sample */
+
+ for(j = 1; j < 16; j++) {
+ __asm__ volatile (
+ "mthi $0, $ac1 \n\t"
+ "mtlo $0, $ac1 \n\t"
+ "mthi $0 \n\t"
+ "mtlo %[temp1] \n\t"
+ PTR_ADDIU "%[p_temp1], %[p_temp1], 4 \n\t"
+ "lw %[w_asm], 0(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 0(%[w2]) \n\t"
+ "lw %[w_asm1], 64*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 64*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 128*4(%[w]) \n\t"
+ "lw %[p_asm], 128*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 128*4(%[w2]) \n\t"
+ "lw %[w_asm1], 192*4(%[w]) \n\t"
+ "lw %[p_asm1], 192*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 192*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 256*4(%[w]) \n\t"
+ "lw %[p_asm], 256*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 256*4(%[w2]) \n\t"
+ "lw %[w_asm1], 320*4(%[w]) \n\t"
+ "lw %[p_asm1], 320*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 320*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 384*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm], 384*4(%[w2]) \n\t"
+ "lw %[w_asm1], 448*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p_temp1]) \n\t"
+ "lw %[w2_asm1], 448*4(%[w2]) \n\t"
+ "madd %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "madd %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ PTR_ADDIU "%[p_temp2], %[p_temp2], -4 \n\t"
+ "lw %[w_asm], 32*4(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 32*4(%[w2]) \n\t"
+ "lw %[w_asm1], 96*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 96*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 160*4(%[w]) \n\t"
+ "lw %[p_asm], 128*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 160*4(%[w2]) \n\t"
+ "lw %[w_asm1], 224*4(%[w]) \n\t"
+ "lw %[p_asm1], 192*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 224*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 288*4(%[w]) \n\t"
+ "lw %[p_asm], 256*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 288*4(%[w2]) \n\t"
+ "lw %[w_asm1], 352*4(%[w]) \n\t"
+ "lw %[p_asm1], 320*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 352*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ "lw %[w_asm], 416*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm], 416*4(%[w2]) \n\t"
+ "lw %[w_asm1], 480*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p_temp2]) \n\t"
+ "lw %[w2_asm1], 480*4(%[w2]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub $ac1, %[w2_asm], %[p_asm] \n\t"
+ "msub $ac1, %[w2_asm1], %[p_asm1] \n\t"
+ PTR_ADDIU "%[w], %[w], 4 \n\t"
+ PTR_ADDIU "%[w2], %[w2], -4 \n\t"
+ "mflo %[temp2] \n\t"
+ "extr.w %[sum1], $ac0, 24 \n\t"
+ "li %[temp3], 1 \n\t"
+ "and %[temp1], %[temp2], 0x00ffffff \n\t"
+ "madd $ac1, %[temp1], %[temp3] \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+ "mflo %[temp3], $ac1 \n\t"
+ "extr.w %[sum1], $ac1, 24 \n\t"
+ "and %[temp1], %[temp3], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples2]) \n\t"
+
+ : [w_asm] "=&r" (w_asm), [p_asm] "=&r" (p_asm), [w_asm1] "=&r" (w_asm1),
+ [p_asm1] "=&r" (p_asm1), [w2_asm1] "=&r" (w2_asm1),
+ [w2_asm] "=&r" (w2_asm), [temp1] "+r" (temp1), [temp2] "+r" (temp2),
+ [p_temp1] "+r" (p_temp1), [p_temp2] "+r" (p_temp2), [sum1] "+r" (sum1),
+ [w] "+r" (w), [w2] "+r" (w2), [samples] "+r" (samples),
+ [samples2] "+r" (samples2), [temp3] "+r" (temp3)
+ : [min_asm] "r" (min_asm), [max_asm] "r" (max_asm)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo"
+ );
+
+ samples += incr;
+ samples2 -= incr;
+ }
+
+ p = synth_buf + 32;
+
+ __asm__ volatile (
+ "mthi $0 \n\t"
+ "mtlo %[temp1] \n\t"
+ "lw %[w_asm], 32*4(%[w]) \n\t"
+ "lw %[p_asm], 0(%[p]) \n\t"
+ "lw %[w_asm1], 96*4(%[w]) \n\t"
+ "lw %[p_asm1], 64*4(%[p]) \n\t"
+ "lw %[w_asm2], 160*4(%[w]) \n\t"
+ "lw %[p_asm2], 128*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 224*4(%[w]) \n\t"
+ "lw %[p_asm], 192*4(%[p]) \n\t"
+ "lw %[w_asm1], 288*4(%[w]) \n\t"
+ "lw %[p_asm1], 256*4(%[p]) \n\t"
+ "lw %[w_asm2], 352*4(%[w]) \n\t"
+ "lw %[p_asm2], 320*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "msub %[w_asm2], %[p_asm2] \n\t"
+ "lw %[w_asm], 416*4(%[w]) \n\t"
+ "lw %[p_asm], 384*4(%[p]) \n\t"
+ "lw %[w_asm1], 480*4(%[w]) \n\t"
+ "lw %[p_asm1], 448*4(%[p]) \n\t"
+ "msub %[w_asm], %[p_asm] \n\t"
+ "msub %[w_asm1], %[p_asm1] \n\t"
+ "extr.w %[sum1], $ac0, 24 \n\t"
+ "mflo %[temp2] \n\t"
+ "and %[temp1], %[temp2], 0x00ffffff \n\t"
+ "slt %[temp2], %[sum1], %[min_asm] \n\t"
+ "movn %[sum1], %[min_asm], %[temp2] \n\t"
+ "slt %[temp2], %[max_asm], %[sum1] \n\t"
+ "movn %[sum1], %[max_asm], %[temp2] \n\t"
+ "sh %[sum1], 0(%[samples]) \n\t"
+
+ : [w_asm] "=&r" (w_asm), [p_asm] "=&r" (p_asm), [w_asm1] "=&r" (w_asm1),
+ [p_asm1] "=&r" (p_asm1), [temp1] "+r" (temp1), [temp2] "+r" (temp2),
+ [w_asm2] "=&r" (w_asm2), [p_asm2] "=&r" (p_asm2), [sum1] "+r" (sum1)
+ : [w] "r" (w), [p] "r" (p), [samples] "r" (samples), [min_asm] "r" (min_asm),
+ [max_asm] "r" (max_asm)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo"
+ );
+
+ *dither_state= temp1;
+}
+
+static void imdct36_mips_fixed(int *out, int *buf, int *in, int *win)
+{
+ int j;
+ int t0, t1, t2, t3, s0, s1, s2, s3;
+ int tmp[18], *tmp1, *in1;
+ /* temporary variables */
+ int temp_reg1, temp_reg2, temp_reg3, temp_reg4, temp_reg5, temp_reg6;
+ int t4, t5, t6, t8, t7;
+
+ /* values defined in macros and tables are
+ * eliminated - they are directly loaded in appropriate variables
+ */
+ int const C_1 = 4229717092; /* cos(pi*1/18)*2 */
+ int const C_2 = 4035949074; /* cos(pi*2/18)*2 */
+ int const C_3 = 575416510; /* -cos(pi*3/18)*2 */
+ int const C_3A = 3719550786; /* cos(pi*3/18)*2 */
+ int const C_4 = 1004831466; /* -cos(pi*4/18)*2 */
+ int const C_5 = 1534215534; /* -cos(pi*5/18)*2 */
+ int const C_7 = -1468965330; /* -cos(pi*7/18)*2 */
+ int const C_8 = -745813244; /* -cos(pi*8/18)*2 */
+
+ /*
+ * instructions of the first two loops are reorganized and loops are unrolled,
+ * in order to eliminate unnecessary readings and writings in array
+ */
+
+ __asm__ volatile (
+ "lw %[t1], 17*4(%[in]) \n\t"
+ "lw %[t2], 16*4(%[in]) \n\t"
+ "lw %[t3], 15*4(%[in]) \n\t"
+ "lw %[t4], 14*4(%[in]) \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "addu %[t2], %[t2], %[t3] \n\t"
+ "addu %[t3], %[t3], %[t4] \n\t"
+ "lw %[t5], 13*4(%[in]) \n\t"
+ "addu %[t1], %[t1], %[t3] \n\t"
+ "sw %[t2], 16*4(%[in]) \n\t"
+ "lw %[t6], 12*4(%[in]) \n\t"
+ "sw %[t1], 17*4(%[in]) \n\t"
+ "addu %[t4], %[t4], %[t5] \n\t"
+ "addu %[t5], %[t5], %[t6] \n\t"
+ "lw %[t7], 11*4(%[in]) \n\t"
+ "addu %[t3], %[t3], %[t5] \n\t"
+ "sw %[t4], 14*4(%[in]) \n\t"
+ "lw %[t8], 10*4(%[in]) \n\t"
+ "sw %[t3], 15*4(%[in]) \n\t"
+ "addu %[t6], %[t6], %[t7] \n\t"
+ "addu %[t7], %[t7], %[t8] \n\t"
+ "sw %[t6], 12*4(%[in]) \n\t"
+ "addu %[t5], %[t5], %[t7] \n\t"
+ "lw %[t1], 9*4(%[in]) \n\t"
+ "lw %[t2], 8*4(%[in]) \n\t"
+ "sw %[t5], 13*4(%[in]) \n\t"
+ "addu %[t8], %[t8], %[t1] \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "sw %[t8], 10*4(%[in]) \n\t"
+ "addu %[t7], %[t7], %[t1] \n\t"
+ "lw %[t3], 7*4(%[in]) \n\t"
+ "lw %[t4], 6*4(%[in]) \n\t"
+ "sw %[t7], 11*4(%[in]) \n\t"
+ "addu %[t2], %[t2], %[t3] \n\t"
+ "addu %[t3], %[t3], %[t4] \n\t"
+ "sw %[t2], 8*4(%[in]) \n\t"
+ "addu %[t1], %[t1], %[t3] \n\t"
+ "lw %[t5], 5*4(%[in]) \n\t"
+ "lw %[t6], 4*4(%[in]) \n\t"
+ "sw %[t1], 9*4(%[in]) \n\t"
+ "addu %[t4], %[t4], %[t5] \n\t"
+ "addu %[t5], %[t5], %[t6] \n\t"
+ "sw %[t4], 6*4(%[in]) \n\t"
+ "addu %[t3], %[t3], %[t5] \n\t"
+ "lw %[t7], 3*4(%[in]) \n\t"
+ "lw %[t8], 2*4(%[in]) \n\t"
+ "sw %[t3], 7*4(%[in]) \n\t"
+ "addu %[t6], %[t6], %[t7] \n\t"
+ "addu %[t7], %[t7], %[t8] \n\t"
+ "sw %[t6], 4*4(%[in]) \n\t"
+ "addu %[t5], %[t5], %[t7] \n\t"
+ "lw %[t1], 1*4(%[in]) \n\t"
+ "lw %[t2], 0*4(%[in]) \n\t"
+ "sw %[t5], 5*4(%[in]) \n\t"
+ "addu %[t8], %[t8], %[t1] \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "sw %[t8], 2*4(%[in]) \n\t"
+ "addu %[t7], %[t7], %[t1] \n\t"
+ "sw %[t7], 3*4(%[in]) \n\t"
+ "sw %[t1], 1*4(%[in]) \n\t"
+
+ : [in] "+r" (in), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3),
+ [t4] "=&r" (t4), [t5] "=&r" (t5), [t6] "=&r" (t6),
+ [t7] "=&r" (t7), [t8] "=&r" (t8)
+ :
+ : "memory"
+ );
+
+ for(j = 0; j < 2; j++) {
+
+ tmp1 = tmp + j;
+ in1 = in + j;
+
+ /**
+ * Original constants are multiplied by two in advanced
+ * for assembly optimization (e.g. C_2 = 2 * C2).
+ * That can lead to overflow in operations where they are used.
+ *
+ * Example of the solution:
+ *
+ * in original code:
+ * t0 = ((int64_t)(in1[2*2] + in1[2*4]) * (int64_t)(2*C2))>>32
+ *
+ * in assembly:
+ * C_2 = 2 * C2;
+ * .
+ * .
+ * "lw %[t7], 4*4(%[in1]) \n\t"
+ * "lw %[t8], 8*4(%[in1]) \n\t"
+ * "addu %[temp_reg2],%[t7], %[t8] \n\t"
+ * "multu %[C_2], %[temp_reg2] \n\t"
+ * "mfhi %[temp_reg1] \n\t"
+ * "sra %[temp_reg2],%[temp_reg2],31 \n\t"
+ * "move %[t0], $0 \n\t"
+ * "movn %[t0], %[C_2], %[temp_reg2] \n\t"
+ * "sub %[t0], %[temp_reg1],%[t0] \n\t"
+ */
+
+ __asm__ volatile (
+ "lw %[t7], 4*4(%[in1]) \n\t"
+ "lw %[t8], 8*4(%[in1]) \n\t"
+ "lw %[t6], 16*4(%[in1]) \n\t"
+ "lw %[t4], 0*4(%[in1]) \n\t"
+ "addu %[temp_reg2], %[t7], %[t8] \n\t"
+ "addu %[t2], %[t6], %[t8] \n\t"
+ "multu %[C_2], %[temp_reg2] \n\t"
+ "lw %[t5], 12*4(%[in1]) \n\t"
+ "sub %[t2], %[t2], %[t7] \n\t"
+ "sub %[t1], %[t4], %[t5] \n\t"
+ "sra %[t3], %[t5], 1 \n\t"
+ "sra %[temp_reg1], %[t2], 1 \n\t"
+ "addu %[t3], %[t3], %[t4] \n\t"
+ "sub %[temp_reg1], %[t1], %[temp_reg1] \n\t"
+ "sra %[temp_reg2], %[temp_reg2], 31 \n\t"
+ "sw %[temp_reg1], 6*4(%[tmp1]) \n\t"
+ "move %[t0], $0 \n\t"
+ "movn %[t0], %[C_2], %[temp_reg2] \n\t"
+ "mfhi %[temp_reg1] \n\t"
+ "addu %[t1], %[t1], %[t2] \n\t"
+ "sw %[t1], 16*4(%[tmp1]) \n\t"
+ "sub %[temp_reg4], %[t8], %[t6] \n\t"
+ "add %[temp_reg2], %[t7], %[t6] \n\t"
+ "mult $ac1, %[C_8], %[temp_reg4] \n\t"
+ "multu $ac2, %[C_4], %[temp_reg2] \n\t"
+ "sub %[t0], %[temp_reg1], %[t0] \n\t"
+ "sra %[temp_reg1], %[temp_reg2], 31 \n\t"
+ "move %[t2], $0 \n\t"
+ "movn %[t2], %[C_4], %[temp_reg1] \n\t"
+ "mfhi %[t1], $ac1 \n\t"
+ "mfhi %[temp_reg1], $ac2 \n\t"
+ "lw %[t6], 10*4(%[in1]) \n\t"
+ "lw %[t8], 14*4(%[in1]) \n\t"
+ "lw %[t7], 2*4(%[in1]) \n\t"
+ "lw %[t4], 6*4(%[in1]) \n\t"
+ "sub %[temp_reg3], %[t3], %[t0] \n\t"
+ "add %[temp_reg4], %[t3], %[t0] \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[t1] \n\t"
+ "sub %[t2], %[temp_reg1], %[t2] \n\t"
+ "sw %[temp_reg4], 2*4(%[tmp1]) \n\t"
+ "sub %[temp_reg3], %[temp_reg3], %[t2] \n\t"
+ "add %[temp_reg1], %[t3], %[t2] \n\t"
+ "sw %[temp_reg3], 10*4(%[tmp1]) \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[t1] \n\t"
+ "addu %[temp_reg2], %[t6], %[t8] \n\t"
+ "sw %[temp_reg1], 14*4(%[tmp1]) \n\t"
+ "sub %[temp_reg2], %[temp_reg2], %[t7] \n\t"
+ "addu %[temp_reg3], %[t7], %[t6] \n\t"
+ "multu $ac3, %[C_3], %[temp_reg2] \n\t"
+ "multu %[C_1], %[temp_reg3] \n\t"
+ "sra %[temp_reg1], %[temp_reg2], 31 \n\t"
+ "move %[t1], $0 \n\t"
+ "sra %[temp_reg3], %[temp_reg3], 31 \n\t"
+ "movn %[t1], %[C_3], %[temp_reg1] \n\t"
+ "mfhi %[temp_reg1], $ac3 \n\t"
+ "mfhi %[temp_reg4] \n\t"
+ "move %[t2], $0 \n\t"
+ "movn %[t2], %[C_1], %[temp_reg3] \n\t"
+ "sub %[temp_reg3], %[t6], %[t8] \n\t"
+ "sub %[t2], %[temp_reg4], %[t2] \n\t"
+ "multu $ac1, %[C_7], %[temp_reg3] \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "sra %[temp_reg4], %[temp_reg3], 31 \n\t"
+ "sub %[t1], %[temp_reg1], %[t1] \n\t"
+ "move %[t3], $0 \n\t"
+ "sw %[t1], 4*4(%[tmp1]) \n\t"
+ "movn %[t3], %[C_7], %[temp_reg4] \n\t"
+ "multu $ac2, %[C_3A], %[t4] \n\t"
+ "add %[temp_reg2], %[t7], %[t8] \n\t"
+ "move %[t1], $0 \n\t"
+ "mfhi %[temp_reg4], $ac1 \n\t"
+ "multu $ac3,%[C_5], %[temp_reg2] \n\t"
+ "move %[t0], $0 \n\t"
+ "sra %[temp_reg1], %[temp_reg2], 31 \n\t"
+ "movn %[t1],%[C_5], %[temp_reg1] \n\t"
+ "sub %[temp_reg4], %[temp_reg4], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg1], $ac3 \n\t"
+ "sra %[temp_reg3], %[t4], 31 \n\t"
+ "movn %[t0], %[C_3A], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "sub %[t3], %[temp_reg4], %[t3] \n\t"
+ "add %[temp_reg4], %[t3], %[t2] \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "sub %[t1], %[temp_reg1], %[t1] \n\t"
+ "sub %[t0], %[temp_reg3], %[t0] \n\t"
+ "add %[temp_reg1], %[t2], %[t1] \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[t0] \n\t"
+ "sub %[temp_reg2], %[t3], %[t1] \n\t"
+ "sw %[temp_reg4], 0*4(%[tmp1]) \n\t"
+ "sub %[temp_reg1], %[temp_reg1], %[t0] \n\t"
+ "sub %[temp_reg2], %[temp_reg2], %[t0] \n\t"
+ "sw %[temp_reg1], 12*4(%[tmp1]) \n\t"
+ "sw %[temp_reg2], 8*4(%[tmp1]) \n\t"
+
+ : [t7] "=&r" (t7), [temp_reg1] "=&r" (temp_reg1),
+ [temp_reg2] "=&r" (temp_reg2), [temp_reg4] "=&r" (temp_reg4),
+ [temp_reg3] "=&r" (temp_reg3), [t8] "=&r" (t8), [t0] "=&r" (t0),
+ [t4] "=&r" (t4), [t5] "=&r" (t5), [t6] "=&r"(t6), [t2] "=&r" (t2),
+ [t3] "=&r" (t3), [t1] "=&r" (t1)
+ : [C_2] "r" (C_2), [in1] "r" (in1), [tmp1] "r" (tmp1), [C_8] "r" (C_8),
+ [C_4] "r" (C_4), [C_3] "r" (C_3), [C_1] "r" (C_1), [C_7] "r" (C_7),
+ [C_3A] "r" (C_3A), [C_5] "r" (C_5)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo"
+ );
+ }
+
+ /**
+ * loop is unrolled four times
+ *
+ * values defined in tables(icos36[] and icos36h[]) are not loaded from
+ * these tables - they are directly loaded in appropriate registers
+ *
+ */
+
+ __asm__ volatile (
+ "lw %[t2], 1*4(%[tmp]) \n\t"
+ "lw %[t3], 3*4(%[tmp]) \n\t"
+ "lw %[t0], 0*4(%[tmp]) \n\t"
+ "lw %[t1], 2*4(%[tmp]) \n\t"
+ "addu %[temp_reg1], %[t3], %[t2] \n\t"
+ "li %[temp_reg2], 0x807D2B1E \n\t"
+ "move %[s1], $0 \n\t"
+ "multu %[temp_reg2], %[temp_reg1] \n\t"
+ "sra %[temp_reg1], %[temp_reg1], 31 \n\t"
+ "movn %[s1], %[temp_reg2], %[temp_reg1] \n\t"
+ "sub %[temp_reg3], %[t3], %[t2] \n\t"
+ "li %[temp_reg4], 0x2de5151 \n\t"
+ "mfhi %[temp_reg2] \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "lw %[temp_reg5], 9*4(%[win]) \n\t"
+ "mult $ac1, %[temp_reg4], %[temp_reg3] \n\t"
+ "lw %[temp_reg6], 4*9*4(%[buf]) \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "lw %[temp_reg3], 29*4(%[win]) \n\t"
+ "subu %[s1], %[temp_reg2], %[s1] \n\t"
+ "lw %[temp_reg4], 28*4(%[win]) \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "extr.w %[s3], $ac1,23 \n\t"
+ "mult $ac2, %[t0], %[temp_reg3] \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "lw %[temp_reg1], 4*8*4(%[buf]) \n\t"
+ "mult %[t1], %[temp_reg5] \n\t"
+ "lw %[temp_reg2], 8*4(%[win]) \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mult $ac3, %[t0], %[temp_reg4] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "mfhi %[temp_reg5] \n\t"
+ "mult $ac1, %[t1], %[temp_reg2] \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "sw %[temp_reg3], 4*9*4(%[buf]) \n\t"
+ "mfhi %[temp_reg4], $ac3 \n\t"
+ "lw %[temp_reg3], 37*4(%[win]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "lw %[temp_reg6], 17*4(%[win]) \n\t"
+ "sw %[temp_reg5], 32*9*4(%[out]) \n\t"
+ "sw %[temp_reg4], 4*8*4(%[buf]) \n\t"
+ "mult %[t1], %[temp_reg6] \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "lw %[temp_reg2], 0*4(%[win]) \n\t"
+ "lw %[temp_reg5], 4*17*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 8*32*4(%[out]) \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "mult $ac1, %[t1], %[temp_reg2] \n\t"
+ "lw %[temp_reg4], 20*4(%[win]) \n\t"
+ "lw %[temp_reg1], 0(%[buf]) \n\t"
+ "mult $ac2, %[t0], %[temp_reg3] \n\t"
+ "mult %[t0], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "lw %[t0], 4*4(%[tmp]) \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mfhi %[temp_reg4] \n\t"
+ "sw %[temp_reg5], 17*32*4(%[out]) \n\t"
+ "lw %[t1], 6*4(%[tmp]) \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "lw %[t2], 5*4(%[tmp]) \n\t"
+ "sw %[temp_reg1], 0*32*4(%[out]) \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "sw %[temp_reg3], 4*17*4(%[buf]) \n\t"
+ "lw %[t3], 7*4(%[tmp]) \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "sw %[temp_reg4], 0(%[buf]) \n\t"
+ "addu %[temp_reg5], %[t3], %[t2] \n\t"
+ "li %[temp_reg6], 0x8483EE0C \n\t"
+ "move %[s1], $0 \n\t"
+ "multu %[temp_reg6], %[temp_reg5] \n\t"
+ "sub %[temp_reg1], %[t3], %[t2] \n\t"
+ "li %[temp_reg2], 0xf746ea \n\t"
+ "sra %[temp_reg5], %[temp_reg5], 31 \n\t"
+ "mult $ac1, %[temp_reg2], %[temp_reg1] \n\t"
+ "movn %[s1], %[temp_reg6], %[temp_reg5] \n\t"
+ "mfhi %[temp_reg5] \n\t"
+ "lw %[temp_reg3], 10*4(%[win]) \n\t"
+ "lw %[temp_reg4], 4*10*4(%[buf]) \n\t"
+ "extr.w %[s3], $ac1, 23 \n\t"
+ "lw %[temp_reg1], 4*7*4(%[buf]) \n\t"
+ "lw %[temp_reg2], 7*4(%[win]) \n\t"
+ "lw %[temp_reg6], 30*4(%[win]) \n\t"
+ "subu %[s1], %[temp_reg5], %[s1] \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "mult $ac2, %[t1], %[temp_reg3] \n\t"
+ "mult $ac3, %[t1], %[temp_reg2] \n\t"
+ "mult %[t0], %[temp_reg6] \n\t"
+ "lw %[temp_reg5], 27*4(%[win]) \n\t"
+ "mult $ac1, %[t0], %[temp_reg5] \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mfhi %[temp_reg2], $ac3 \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "add %[temp_reg3], %[temp_reg3], %[temp_reg4] \n\t"
+ "lw %[temp_reg4], 16*4(%[win]) \n\t"
+ "mfhi %[temp_reg5], $ac1 \n\t"
+ "sw %[temp_reg3], 32*10*4(%[out]) \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "lw %[temp_reg3], 4*16*4(%[buf]) \n\t"
+ "sw %[temp_reg6], 4*10*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 7*32*4(%[out]) \n\t"
+ "mult $ac2, %[t1], %[temp_reg4] \n\t"
+ "sw %[temp_reg5], 4*7*4(%[buf]) \n\t"
+ "lw %[temp_reg6], 1*4(%[win]) \n\t"
+ "lw %[temp_reg5], 4*1*4(%[buf]) \n\t"
+ "lw %[temp_reg1], 36*4(%[win]) \n\t"
+ "mult $ac3, %[t1], %[temp_reg6] \n\t"
+ "lw %[temp_reg2], 21*4(%[win]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "mult %[t0], %[temp_reg1] \n\t"
+ "mult $ac1, %[t0],%[temp_reg2] \n\t"
+ "lw %[t0], 8*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg6], $ac3 \n\t"
+ "lw %[t1], 10*4(%[tmp]) \n\t"
+ "lw %[t3], 11*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg1] \n\t"
+ "add %[temp_reg3], %[temp_reg3], %[temp_reg4] \n\t"
+ "lw %[t2], 9*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "sw %[temp_reg3], 16*32*4(%[out]) \n\t"
+ "sw %[temp_reg5], 1*32*4(%[out]) \n\t"
+ "sw %[temp_reg1], 4*16*4(%[buf]) \n\t"
+ "addu %[temp_reg3], %[t3], %[t2] \n\t"
+ "li %[temp_reg4], 0x8D3B7CD6 \n\t"
+ "sw %[temp_reg2], 4*1*4(%[buf]) \n\t"
+ "multu %[temp_reg4],%[temp_reg3] \n\t"
+ "sra %[temp_reg3], %[temp_reg3], 31 \n\t"
+ "move %[s1], $0 \n\t"
+ "movn %[s1], %[temp_reg4], %[temp_reg3] \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "mfhi %[temp_reg3] \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "sub %[temp_reg5], %[t3], %[t2] \n\t"
+ "li %[temp_reg6], 0x976fd9 \n\t"
+ "lw %[temp_reg2], 11*4(%[win]) \n\t"
+ "lw %[temp_reg1], 4*11*4(%[buf]) \n\t"
+ "mult $ac1, %[temp_reg6], %[temp_reg5] \n\t"
+ "subu %[s1], %[temp_reg3], %[s1] \n\t"
+ "lw %[temp_reg5], 31*4(%[win]) \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "mult $ac2, %[t1], %[temp_reg2] \n\t"
+ "mult %[t0], %[temp_reg5] \n\t"
+ "lw %[temp_reg4], 6*4(%[win]) \n\t"
+ "extr.w %[s3], $ac1, 23 \n\t"
+ "lw %[temp_reg3], 4*6*4(%[buf]) \n\t"
+ "mfhi %[temp_reg2], $ac2 \n\t"
+ "lw %[temp_reg6], 26*4(%[win]) \n\t"
+ "mfhi %[temp_reg5] \n\t"
+ "mult $ac3, %[t1], %[temp_reg4] \n\t"
+ "mult $ac1, %[t0], %[temp_reg6] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "add %[temp_reg2], %[temp_reg2], %[temp_reg1] \n\t"
+ "mfhi %[temp_reg4], $ac3 \n\t"
+ "mfhi %[temp_reg6], $ac1 \n\t"
+ "sw %[temp_reg5], 4*11*4(%[buf]) \n\t"
+ "sw %[temp_reg2], 32*11*4(%[out]) \n\t"
+ "lw %[temp_reg1], 4*15*4(%[buf]) \n\t"
+ "add %[temp_reg3], %[temp_reg3], %[temp_reg4] \n\t"
+ "lw %[temp_reg2], 15*4(%[win]) \n\t"
+ "sw %[temp_reg3], 6*32*4(%[out]) \n\t"
+ "sw %[temp_reg6], 4*6*4(%[buf]) \n\t"
+ "mult %[t1], %[temp_reg2] \n\t"
+ "lw %[temp_reg3], 2*4(%[win]) \n\t"
+ "lw %[temp_reg4], 4*2*4(%[buf]) \n\t"
+ "lw %[temp_reg5], 35*4(%[win]) \n\t"
+ "mult $ac1, %[t1], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg2] \n\t"
+ "lw %[temp_reg6], 22*4(%[win]) \n\t"
+ "mult $ac2, %[t0], %[temp_reg5] \n\t"
+ "lw %[t1], 14*4(%[tmp]) \n\t"
+ "mult $ac3, %[t0], %[temp_reg6] \n\t"
+ "lw %[t0], 12*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg3], $ac1 \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "mfhi %[temp_reg5], $ac2 \n\t"
+ "sw %[temp_reg1], 15*32*4(%[out]) \n\t"
+ "mfhi %[temp_reg6], $ac3 \n\t"
+ "lw %[t2], 13*4(%[tmp]) \n\t"
+ "lw %[t3], 15*4(%[tmp]) \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[temp_reg3] \n\t"
+ "sw %[temp_reg5], 4*15*4(%[buf]) \n\t"
+ "addu %[temp_reg1], %[t3], %[t2] \n\t"
+ "li %[temp_reg2], 0x9C42577C \n\t"
+ "move %[s1], $0 \n\t"
+ "multu %[temp_reg2], %[temp_reg1] \n\t"
+ "sw %[temp_reg4], 2*32*4(%[out]) \n\t"
+ "sra %[temp_reg1], %[temp_reg1], 31 \n\t"
+ "movn %[s1], %[temp_reg2], %[temp_reg1] \n\t"
+ "sub %[temp_reg3], %[t3], %[t2] \n\t"
+ "li %[temp_reg4], 0x6f94a2 \n\t"
+ "mfhi %[temp_reg1] \n\t"
+ "addu %[s0], %[t1], %[t0] \n\t"
+ "sw %[temp_reg6], 4*2*4(%[buf]) \n\t"
+ "mult $ac1, %[temp_reg4], %[temp_reg3] \n\t"
+ "sub %[s2], %[t1], %[t0] \n\t"
+ "lw %[temp_reg5], 12*4(%[win]) \n\t"
+ "lw %[temp_reg6], 4*12*4(%[buf]) \n\t"
+ "subu %[s1], %[temp_reg1], %[s1] \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "lw %[temp_reg3], 32*4(%[win]) \n\t"
+ "mult $ac2, %[t1], %[temp_reg5] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "extr.w %[s3], $ac1, 23 \n\t"
+ "lw %[temp_reg2], 5*4(%[win]) \n\t"
+ "mult %[t0], %[temp_reg3] \n\t"
+ "mfhi %[temp_reg5], $ac2 \n\t"
+ "lw %[temp_reg4], 25*4(%[win]) \n\t"
+ "lw %[temp_reg1], 4*5*4(%[buf]) \n\t"
+ "mult $ac3, %[t1], %[temp_reg2] \n\t"
+ "mult $ac1, %[t0], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg3] \n\t"
+ "add %[t0], %[s2], %[s3] \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg2], $ac3 \n\t"
+ "mfhi %[temp_reg4], $ac1 \n\t"
+ "sub %[t1], %[s2], %[s3] \n\t"
+ "sw %[temp_reg5], 32*12*4(%[out]) \n\t"
+ "sw %[temp_reg3], 4*12*4(%[buf]) \n\t"
+ "lw %[temp_reg6], 14*4(%[win]) \n\t"
+ "lw %[temp_reg5], 4*14*4(%[buf]) \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "sw %[temp_reg4], 4*5*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 5*32*4(%[out]) \n\t"
+ "mult %[t1], %[temp_reg6] \n\t"
+ "lw %[temp_reg4], 34*4(%[win]) \n\t"
+ "lw %[temp_reg2], 3*4(%[win]) \n\t"
+ "lw %[temp_reg1], 4*3*4(%[buf]) \n\t"
+ "mult $ac2, %[t0], %[temp_reg4] \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "mult $ac1, %[t1], %[temp_reg2] \n\t"
+ "lw %[temp_reg3], 23*4(%[win]) \n\t"
+ "lw %[s0], 16*4(%[tmp]) \n\t"
+ "mfhi %[temp_reg4], $ac2 \n\t"
+ "lw %[t1], 17*4(%[tmp]) \n\t"
+ "mult $ac3, %[t0], %[temp_reg3] \n\t"
+ "move %[s1], $0 \n\t"
+ "add %[temp_reg5], %[temp_reg5], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg2], $ac1 \n\t"
+ "sw %[temp_reg5], 14*32*4(%[out]) \n\t"
+ "sw %[temp_reg4], 4*14*4(%[buf]) \n\t"
+ "mfhi %[temp_reg3], $ac3 \n\t"
+ "li %[temp_reg5], 0xB504F334 \n\t"
+ "add %[temp_reg1], %[temp_reg1], %[temp_reg2] \n\t"
+ "multu %[temp_reg5], %[t1] \n\t"
+ "lw %[temp_reg2], 4*13*4(%[buf]) \n\t"
+ "sw %[temp_reg1], 3*32*4(%[out]) \n\t"
+ "sra %[t1], %[t1], 31 \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "movn %[s1], %[temp_reg5], %[t1] \n\t"
+ "sw %[temp_reg3], 4*3*4(%[buf]) \n\t"
+ "lw %[temp_reg1], 13*4(%[win]) \n\t"
+ "lw %[temp_reg4], 4*4*4(%[buf]) \n\t"
+ "lw %[temp_reg3], 4*4(%[win]) \n\t"
+ "lw %[temp_reg5], 33*4(%[win]) \n\t"
+ "subu %[s1], %[temp_reg6], %[s1] \n\t"
+ "lw %[temp_reg6], 24*4(%[win]) \n\t"
+ "sub %[t1], %[s0], %[s1] \n\t"
+ "add %[t0], %[s0], %[s1] \n\t"
+ "mult $ac1, %[t1], %[temp_reg1] \n\t"
+ "mult $ac2, %[t1], %[temp_reg3] \n\t"
+ "mult $ac3, %[t0], %[temp_reg5] \n\t"
+ "mult %[t0], %[temp_reg6] \n\t"
+ "mfhi %[temp_reg1], $ac1 \n\t"
+ "mfhi %[temp_reg3], $ac2 \n\t"
+ "mfhi %[temp_reg5], $ac3 \n\t"
+ "mfhi %[temp_reg6] \n\t"
+ "add %[temp_reg2], %[temp_reg2], %[temp_reg1] \n\t"
+ "add %[temp_reg4], %[temp_reg4], %[temp_reg3] \n\t"
+ "sw %[temp_reg2], 13*32*4(%[out]) \n\t"
+ "sw %[temp_reg4], 4*32*4(%[out]) \n\t"
+ "sw %[temp_reg5], 4*13*4(%[buf]) \n\t"
+ "sw %[temp_reg6], 4*4*4(%[buf]) \n\t"
+
+ : [t0] "=&r" (t0), [t1] "=&r" (t1), [t2] "=&r" (t2), [t3] "=&r" (t3),
+ [s0] "=&r" (s0), [s2] "=&r" (s2), [temp_reg1] "=&r" (temp_reg1),
+ [temp_reg2] "=&r" (temp_reg2), [s1] "=&r" (s1), [s3] "=&r" (s3),
+ [temp_reg3] "=&r" (temp_reg3), [temp_reg4] "=&r" (temp_reg4),
+ [temp_reg5] "=&r" (temp_reg5), [temp_reg6] "=&r" (temp_reg6),
+ [out] "+r" (out)
+ : [tmp] "r" (tmp), [win] "r" (win), [buf] "r" (buf)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo",
+ "$ac3hi", "$ac3lo"
+ );
+}
+
+static void ff_imdct36_blocks_mips_fixed(int *out, int *buf, int *in,
+ int count, int switch_point, int block_type)
+{
+ int j;
+ for (j=0 ; j < count; j++) {
+ /* apply window & overlap with previous buffer */
+
+ /* select window */
+ int win_idx = (switch_point && j < 2) ? 0 : block_type;
+ int *win = ff_mdct_win_fixed[win_idx + (4 & -(j & 1))];
+
+ imdct36_mips_fixed(out, buf, in, win);
+
+ in += 18;
+ buf += ((j&3) != 3 ? 1 : (72-3));
+ out++;
+ }
+}
+
+void ff_mpadsp_init_mipsdspr1(MPADSPContext *s)
+{
+ s->apply_window_fixed = ff_mpadsp_apply_window_mips_fixed;
+ s->imdct36_blocks_fixed = ff_imdct36_blocks_mips_fixed;
+}
diff --git a/libavcodec/mips/mpegaudiodsp_mips_float.c b/libavcodec/mips/mpegaudiodsp_mips_float.c
new file mode 100644
index 0000000000..beebace544
--- /dev/null
+++ b/libavcodec/mips/mpegaudiodsp_mips_float.c
@@ -0,0 +1,1257 @@
+/*
+ * 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)
+ *
+ * MPEG Audio decoder 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/mpegaudiodsp_template.c
+ * libavcodec/dct32.c
+ */
+
+#include <string.h>
+
+#include "libavutil/mips/asmdefs.h"
+#include "libavcodec/mpegaudiodsp.h"
+
+static void ff_mpadsp_apply_window_mips_float(float *synth_buf, float *window,
+ int *dither_state, float *samples, int incr)
+{
+ register const float *w, *w2, *p;
+ int j;
+ float *samples2;
+ float sum, sum2;
+ /* temporary variables */
+ int incr1 = incr << 2;
+ int t_sample;
+ float in1, in2, in3, in4, in5, in6, in7, in8;
+ float *p2;
+
+ /* copy to avoid wrap */
+ memcpy(synth_buf + 512, synth_buf, 32 * sizeof(*synth_buf));
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ * use of round_sample function from the original code is
+ * changed with appropriate assembly instructions.
+ */
+
+ __asm__ volatile (
+ "lwc1 %[sum], 0(%[dither_state]) \t\n"
+ "sll %[t_sample], %[incr1], 5 \t\n"
+ "sub %[t_sample], %[t_sample], %[incr1] \n\t"
+ "li %[j], 4 \t\n"
+ "lwc1 %[in1], 0(%[window]) \t\n"
+ "lwc1 %[in2], 16*4(%[synth_buf]) \t\n"
+ "sw $zero, 0(%[dither_state]) \t\n"
+ "lwc1 %[in3], 64*4(%[window]) \t\n"
+ "lwc1 %[in4], 80*4(%[synth_buf]) \t\n"
+ PTR_ADDU "%[samples2],%[samples], %[t_sample] \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 128*4(%[window]) \t\n"
+ "lwc1 %[in6], 144*4(%[synth_buf]) \t\n"
+ "lwc1 %[in7], 192*4(%[window]) \t\n"
+ "madd.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in8], 208*4(%[synth_buf]) \t\n"
+ "lwc1 %[in1], 256*4(%[window]) \t\n"
+ "lwc1 %[in2], 272*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 320*4(%[window]) \t\n"
+ "lwc1 %[in4], 336*4(%[synth_buf]) \t\n"
+ "lwc1 %[in5], 384*4(%[window]) \t\n"
+ "madd.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in6], 400*4(%[synth_buf]) \t\n"
+ "lwc1 %[in7], 448*4(%[window]) \t\n"
+ "lwc1 %[in8], 464*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in1], 32*4(%[window]) \t\n"
+ "lwc1 %[in2], 48*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in3], 96*4(%[window]) \t\n"
+ "lwc1 %[in4], 112*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "lwc1 %[in5], 160*4(%[window]) \t\n"
+ "lwc1 %[in6], 176*4(%[synth_buf]) \t\n"
+ "madd.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in7], 224*4(%[window]) \t\n"
+ "lwc1 %[in8], 240*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in1], 288*4(%[window]) \t\n"
+ "lwc1 %[in2], 304*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in3], 352*4(%[window]) \t\n"
+ "lwc1 %[in4], 368*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "lwc1 %[in5], 416*4(%[window]) \t\n"
+ "lwc1 %[in6], 432*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in7], 480*4(%[window]) \t\n"
+ "lwc1 %[in8], 496*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ PTR_ADDU "%[w], %[window], 4 \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ PTR_ADDU "%[w2], %[window], 124 \t\n"
+ PTR_ADDIU "%[p], %[synth_buf], 68 \t\n"
+ PTR_ADDIU "%[p2], %[synth_buf], 188 \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+ PTR_ADDU "%[samples], %[samples], %[incr1] \t\n"
+
+ /* calculate two samples at the same time to avoid one memory
+ access per two sample */
+
+ "ff_mpadsp_apply_window_loop%=: \t\n"
+ "lwc1 %[in1], 0(%[w]) \t\n"
+ "lwc1 %[in2], 0(%[p]) \t\n"
+ "lwc1 %[in3], 0(%[w2]) \t\n"
+ "lwc1 %[in4], 64*4(%[w]) \t\n"
+ "lwc1 %[in5], 64*4(%[p]) \t\n"
+ "lwc1 %[in6], 64*4(%[w2]) \t\n"
+ "mul.s %[sum], %[in1], %[in2] \t\n"
+ "mul.s %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 128*4(%[w]) \t\n"
+ "lwc1 %[in2], 128*4(%[p]) \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "nmadd.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 128*4(%[w2]) \t\n"
+ "lwc1 %[in4], 192*4(%[w]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 192*4(%[p]) \t\n"
+ "lwc1 %[in6], 192*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 256*4(%[w]) \t\n"
+ "lwc1 %[in2], 256*4(%[p]) \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 256*4(%[w2]) \t\n"
+ "lwc1 %[in4], 320*4(%[w]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 320*4(%[p]) \t\n"
+ "lwc1 %[in6], 320*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 384*4(%[w]) \t\n"
+ "lwc1 %[in2], 384*4(%[p]) \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 384*4(%[w2]) \t\n"
+ "lwc1 %[in4], 448*4(%[w]) \t\n"
+ "madd.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in5], 448*4(%[p]) \t\n"
+ "lwc1 %[in6], 448*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "madd.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in1], 32*4(%[w]) \t\n"
+ "lwc1 %[in2], 0(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 32*4(%[w2]) \t\n"
+ "lwc1 %[in4], 96*4(%[w]) \t\n"
+ "lwc1 %[in5], 64*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 96*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 160*4(%[w]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in2], 128*4(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 160*4(%[w2]) \t\n"
+ "lwc1 %[in4], 224*4(%[w]) \t\n"
+ "lwc1 %[in5], 192*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 224*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 288*4(%[w]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in2], 256*4(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 288*4(%[w2]) \t\n"
+ "lwc1 %[in4], 352*4(%[w]) \t\n"
+ "lwc1 %[in5], 320*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 352*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ "lwc1 %[in1], 416*4(%[w]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ "lwc1 %[in2], 384*4(%[p2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "lwc1 %[in3], 416*4(%[w2]) \t\n"
+ "lwc1 %[in4], 480*4(%[w]) \t\n"
+ "lwc1 %[in5], 448*4(%[p2]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in6], 480*4(%[w2]) \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in2], %[in3] \t\n"
+ PTR_ADDIU "%[w], %[w], 4 \t\n"
+ "nmsub.s %[sum], %[sum], %[in4], %[in5] \t\n"
+ PTR_ADDIU "%[w2], %[w2], -4 \t\n"
+ "nmsub.s %[sum2], %[sum2], %[in5], %[in6] \t\n"
+ "addu %[j], %[j], 4 \t\n"
+ PTR_ADDIU "%[p], 4 \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+ PTR_ADDIU "%[p2], -4 \t\n"
+ "swc1 %[sum2], 0(%[samples2]) \t\n"
+ PTR_ADDU "%[samples], %[samples], %[incr1] \t\n"
+ PTR_SUBU "%[samples2],%[samples2], %[incr1] \t\n"
+ "bne %[j], 64, ff_mpadsp_apply_window_loop%= \t\n"
+
+ "lwc1 %[in1], 48*4(%[window]) \t\n"
+ "lwc1 %[in2], 32*4(%[synth_buf]) \t\n"
+ "lwc1 %[in3], 112*4(%[window]) \t\n"
+ "lwc1 %[in4], 96*4(%[synth_buf]) \t\n"
+ "lwc1 %[in5], 176*4(%[window]) \t\n"
+ "lwc1 %[in6], 160*4(%[synth_buf]) \t\n"
+ "mul.s %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in7], 240*4(%[window]) \t\n"
+ "lwc1 %[in8], 224*4(%[synth_buf]) \t\n"
+ "lwc1 %[in1], 304*4(%[window]) \t\n"
+ "nmadd.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "lwc1 %[in2], 288*4(%[synth_buf]) \t\n"
+ "lwc1 %[in3], 368*4(%[window]) \t\n"
+ "lwc1 %[in4], 352*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "lwc1 %[in5], 432*4(%[window]) \t\n"
+ "lwc1 %[in6], 416*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in1], %[in2] \t\n"
+ "lwc1 %[in7], 496*4(%[window]) \t\n"
+ "lwc1 %[in8], 480*4(%[synth_buf]) \t\n"
+ "nmsub.s %[sum], %[sum], %[in3], %[in4] \t\n"
+ "nmsub.s %[sum], %[sum], %[in5], %[in6] \t\n"
+ "nmsub.s %[sum], %[sum], %[in7], %[in8] \t\n"
+ "swc1 %[sum], 0(%[samples]) \t\n"
+
+ : [sum] "=&f" (sum), [sum2] "=&f" (sum2),
+ [w2] "=&r" (w2), [w] "=&r" (w),
+ [p] "=&r" (p), [p2] "=&r" (p2), [j] "=&r" (j),
+ [samples] "+r" (samples), [samples2] "=&r" (samples2),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [in7] "=&f" (in7), [in8] "=&f" (in8),
+ [t_sample] "=&r" (t_sample)
+ : [synth_buf] "r" (synth_buf), [window] "r" (window),
+ [dither_state] "r" (dither_state), [incr1] "r" (incr1)
+ : "memory"
+ );
+}
+
+#if !HAVE_LOONGSON3
+static void ff_dct32_mips_float(float *out, const float *tab)
+{
+ float val0 , val1 , val2 , val3 , val4 , val5 , val6 , val7,
+ val8 , val9 , val10, val11, val12, val13, val14, val15,
+ val16, val17, val18, val19, val20, val21, val22, val23,
+ val24, val25, val26, val27, val28, val29, val30, val31;
+ float fTmp1, fTmp2, fTmp3, fTmp4, fTmp5, fTmp6, fTmp7, fTmp8,
+ fTmp9, fTmp10, fTmp11;
+
+ /**
+ * instructions are scheduled to minimize pipeline stall.
+ */
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 0*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 31*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 15*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 16*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.50241928618815570551 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.50060299823519630134 \n\t"
+ "li.s %[fTmp11], 10.19000812354805681150 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val0], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val15], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 7*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 24*4(%[tab]) \n\t"
+ "madd.s %[val16], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val31], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val15], %[val15], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 8*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 23*4(%[tab]) \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "mul.s %[val31], %[val31], %[fTmp7] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp7], 5.10114861868916385802 \n\t"
+ "li.s %[fTmp10], 0.67480834145500574602 \n\t"
+ "li.s %[fTmp11], 0.74453627100229844977 \n\t"
+ "add.s %[val7], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val8], %[fTmp5], %[fTmp6] \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "li.s %[fTmp1], 0.50979557910415916894 \n\t"
+ "sub.s %[fTmp2], %[val0], %[val7] \n\t"
+ "mul.s %[val8], %[val8], %[fTmp7] \n\t"
+ "madd.s %[val23], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val24], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "add.s %[val0], %[val0], %[val7] \n\t"
+ "mul.s %[val7], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp2], %[val15], %[val8] \n\t"
+ "add.s %[val8], %[val15], %[val8] \n\t"
+ "mul.s %[val24], %[val24], %[fTmp7] \n\t"
+ "sub.s %[fTmp3], %[val16], %[val23] \n\t"
+ "add.s %[val16], %[val16], %[val23] \n\t"
+ "mul.s %[val15], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp4], %[val31], %[val24] \n\t"
+ "mul.s %[val23], %[fTmp1], %[fTmp3] \n\t"
+ "add.s %[val24], %[val31], %[val24] \n\t"
+ "mul.s %[val31], %[fTmp1], %[fTmp4] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val0] "=f" (val0), [val7] "=f" (val7),
+ [val8] "=f" (val8), [val15] "=f" (val15),
+ [val16] "=f" (val16), [val23] "=f" (val23),
+ [val24] "=f" (val24), [val31] "=f" (val31)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 3*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 28*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 12*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 19*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.64682178335999012954 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.53104259108978417447 \n\t"
+ "li.s %[fTmp11], 1.48416461631416627724 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val3], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val12], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 4*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 27*4(%[tab]) \n\t"
+ "madd.s %[val19], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val28], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val12], %[val12], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 11*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 20*4(%[tab]) \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "mul.s %[val28], %[val28], %[fTmp7] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "li.s %[fTmp7], 0.78815462345125022473 \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.55310389603444452782 \n\t"
+ "li.s %[fTmp11], 1.16943993343288495515 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val4], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val11], %[fTmp5], %[fTmp6] \n\t"
+ "li.s %[fTmp1], 2.56291544774150617881 \n\t"
+ "madd.s %[val20], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val27], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val11], %[val11], %[fTmp7] \n\t"
+ "sub.s %[fTmp2], %[val3], %[val4] \n\t"
+ "add.s %[val3], %[val3], %[val4] \n\t"
+ "sub.s %[fTmp4], %[val19], %[val20] \n\t"
+ "mul.s %[val27], %[val27], %[fTmp7] \n\t"
+ "sub.s %[fTmp3], %[val12], %[val11] \n\t"
+ "mul.s %[val4], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val11], %[val12], %[val11] \n\t"
+ "add.s %[val19], %[val19], %[val20] \n\t"
+ "mul.s %[val20], %[fTmp1], %[fTmp4] \n\t"
+ "mul.s %[val12], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val28], %[val27] \n\t"
+ "add.s %[val27], %[val28], %[val27] \n\t"
+ "mul.s %[val28], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val3] "=f" (val3), [val4] "=f" (val4),
+ [val11] "=f" (val11), [val12] "=f" (val12),
+ [val19] "=f" (val19), [val20] "=f" (val20),
+ [val27] "=f" (val27), [val28] "=f" (val28)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "li.s %[fTmp1], 0.54119610014619698439 \n\t"
+ "sub.s %[fTmp2], %[val0], %[val3] \n\t"
+ "add.s %[val0], %[val0], %[val3] \n\t"
+ "sub.s %[fTmp3], %[val7], %[val4] \n\t"
+ "add.s %[val4], %[val7], %[val4] \n\t"
+ "sub.s %[fTmp4], %[val8], %[val11] \n\t"
+ "mul.s %[val3], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val8], %[val8], %[val11] \n\t"
+ "mul.s %[val7], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val15], %[val12] \n\t"
+ "mul.s %[val11], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val12], %[val15], %[val12] \n\t"
+ "mul.s %[val15], %[fTmp1], %[fTmp2] \n\t"
+
+ : [val0] "+f" (val0), [val3] "+f" (val3),
+ [val4] "+f" (val4), [val7] "+f" (val7),
+ [val8] "+f" (val8), [val11] "+f" (val11),
+ [val12] "+f" (val12), [val15] "+f" (val15),
+ [fTmp1] "=f" (fTmp1), [fTmp2] "=&f" (fTmp2),
+ [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4)
+ :
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val16], %[val19] \n\t"
+ "add.s %[val16], %[val16], %[val19] \n\t"
+ "sub.s %[fTmp3], %[val23], %[val20] \n\t"
+ "add.s %[val20], %[val23], %[val20] \n\t"
+ "sub.s %[fTmp4], %[val24], %[val27] \n\t"
+ "mul.s %[val19], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val24], %[val24], %[val27] \n\t"
+ "mul.s %[val23], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val31], %[val28] \n\t"
+ "mul.s %[val27], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val28], %[val31], %[val28] \n\t"
+ "mul.s %[val31], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val16] "+f" (val16), [val19] "+f" (val19), [val20] "+f" (val20),
+ [val23] "+f" (val23), [val24] "+f" (val24), [val27] "+f" (val27),
+ [val28] "+f" (val28), [val31] "+f" (val31)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 1*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 30*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 14*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 17*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.52249861493968888062 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.50547095989754365998 \n\t"
+ "li.s %[fTmp11], 3.40760841846871878570 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val1], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val14], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 6*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 25*4(%[tab]) \n\t"
+ "madd.s %[val17], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val30], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val14], %[val14], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 9*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 22*4(%[tab]) \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "mul.s %[val30], %[val30], %[fTmp7] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp7], 1.72244709823833392782 \n\t"
+ "li.s %[fTmp10], 0.62250412303566481615 \n\t"
+ "li.s %[fTmp11], 0.83934964541552703873 \n\t"
+ "add.s %[val6], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val9], %[fTmp5], %[fTmp6] \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "li.s %[fTmp1], 0.60134488693504528054 \n\t"
+ "sub.s %[fTmp2], %[val1], %[val6] \n\t"
+ "add.s %[val1], %[val1], %[val6] \n\t"
+ "mul.s %[val9], %[val9], %[fTmp7] \n\t"
+ "madd.s %[val22], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val25], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val6], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp2], %[val14], %[val9] \n\t"
+ "add.s %[val9], %[val14], %[val9] \n\t"
+ "mul.s %[val25], %[val25], %[fTmp7] \n\t"
+ "sub.s %[fTmp3], %[val17], %[val22] \n\t"
+ "add.s %[val17], %[val17], %[val22] \n\t"
+ "mul.s %[val14], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp2], %[val30], %[val25] \n\t"
+ "mul.s %[val22], %[fTmp1], %[fTmp3] \n\t"
+ "add.s %[val25], %[val30], %[val25] \n\t"
+ "mul.s %[val30], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val1] "=f" (val1), [val6] "=f" (val6),
+ [val9] "=f" (val9), [val14] "=f" (val14),
+ [val17] "=f" (val17), [val22] "=f" (val22),
+ [val25] "=f" (val25), [val30] "=f" (val30)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "lwc1 %[fTmp1], 2*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 29*4(%[tab]) \n\t"
+ "lwc1 %[fTmp3], 13*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 18*4(%[tab]) \n\t"
+ "li.s %[fTmp7], 0.56694403481635770368 \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp10], 0.51544730992262454697 \n\t"
+ "li.s %[fTmp11], 2.05778100995341155085 \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "add.s %[val2], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val13], %[fTmp5], %[fTmp6] \n\t"
+ "lwc1 %[fTmp1], 5*4(%[tab]) \n\t"
+ "lwc1 %[fTmp2], 26*4(%[tab]) \n\t"
+ "madd.s %[val18], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val29], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "mul.s %[val13], %[val13], %[fTmp7] \n\t"
+ "lwc1 %[fTmp3], 10*4(%[tab]) \n\t"
+ "lwc1 %[fTmp4], 21*4(%[tab]) \n\t"
+ "mul.s %[val29], %[val29], %[fTmp7] \n\t"
+ "add.s %[fTmp5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp8], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[fTmp6], %[fTmp3], %[fTmp4] \n\t"
+ "sub.s %[fTmp9], %[fTmp3], %[fTmp4] \n\t"
+ "li.s %[fTmp7], 1.06067768599034747134 \n\t"
+ "li.s %[fTmp10], 0.58293496820613387367 \n\t"
+ "li.s %[fTmp11], 0.97256823786196069369 \n\t"
+ "add.s %[val5], %[fTmp5], %[fTmp6] \n\t"
+ "sub.s %[val10], %[fTmp5], %[fTmp6] \n\t"
+ "mul.s %[fTmp8], %[fTmp8], %[fTmp10] \n\t"
+ "li.s %[fTmp1], 0.89997622313641570463 \n\t"
+ "sub.s %[fTmp2], %[val2], %[val5] \n\t"
+ "mul.s %[val10], %[val10], %[fTmp7] \n\t"
+ "madd.s %[val21], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "nmsub.s %[val26], %[fTmp8], %[fTmp9], %[fTmp11] \n\t"
+ "add.s %[val2], %[val2], %[val5] \n\t"
+ "mul.s %[val5], %[fTmp1], %[fTmp2] \n\t"
+ "sub.s %[fTmp3], %[val13], %[val10] \n\t"
+ "add.s %[val10], %[val13], %[val10] \n\t"
+ "mul.s %[val26], %[val26], %[fTmp7] \n\t"
+ "sub.s %[fTmp4], %[val18], %[val21] \n\t"
+ "add.s %[val18], %[val18], %[val21] \n\t"
+ "mul.s %[val13], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val29], %[val26] \n\t"
+ "add.s %[val26], %[val29], %[val26] \n\t"
+ "mul.s %[val21], %[fTmp1], %[fTmp4] \n\t"
+ "mul.s %[val29], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=&f" (fTmp1), [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3),
+ [fTmp4] "=&f" (fTmp4), [fTmp5] "=&f" (fTmp5), [fTmp6] "=&f" (fTmp6),
+ [fTmp7] "=&f" (fTmp7), [fTmp8] "=&f" (fTmp8), [fTmp9] "=&f" (fTmp9),
+ [fTmp10] "=&f" (fTmp10), [fTmp11] "=&f" (fTmp11),
+ [val2] "=f" (val2), [val5] "=f" (val5),
+ [val10] "=f" (val10), [val13] "=f" (val13),
+ [val18] "=f" (val18), [val21] "=f" (val21),
+ [val26] "=f" (val26), [val29] "=f" (val29)
+ : [tab] "r" (tab)
+ : "memory"
+ );
+
+ __asm__ volatile (
+ "li.s %[fTmp1], 1.30656296487637652785 \n\t"
+ "sub.s %[fTmp2], %[val1], %[val2] \n\t"
+ "add.s %[val1], %[val1], %[val2] \n\t"
+ "sub.s %[fTmp3], %[val6], %[val5] \n\t"
+ "add.s %[val5], %[val6], %[val5] \n\t"
+ "sub.s %[fTmp4], %[val9], %[val10] \n\t"
+ "mul.s %[val2], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val9], %[val9], %[val10] \n\t"
+ "mul.s %[val6], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val14], %[val13] \n\t"
+ "mul.s %[val10], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val13], %[val14], %[val13] \n\t"
+ "mul.s %[val14], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp1] "=f" (fTmp1), [fTmp2] "=&f" (fTmp2),
+ [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val1] "+f" (val1), [val2] "+f" (val2),
+ [val5] "+f" (val5), [val6] "+f" (val6),
+ [val9] "+f" (val9), [val10] "+f" (val10),
+ [val13] "+f" (val13), [val14] "+f" (val14)
+ :
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val17], %[val18] \n\t"
+ "add.s %[val17], %[val17], %[val18] \n\t"
+ "sub.s %[fTmp3], %[val22], %[val21] \n\t"
+ "add.s %[val21], %[val22], %[val21] \n\t"
+ "sub.s %[fTmp4], %[val25], %[val26] \n\t"
+ "mul.s %[val18], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val25], %[val25], %[val26] \n\t"
+ "mul.s %[val22], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val30], %[val29] \n\t"
+ "mul.s %[val26], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val29], %[val30], %[val29] \n\t"
+ "mul.s %[val30], %[fTmp1], %[fTmp2] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val17] "+f" (val17), [val18] "+f" (val18), [val21] "+f" (val21),
+ [val22] "+f" (val22), [val25] "+f" (val25), [val26] "+f" (val26),
+ [val29] "+f" (val29), [val30] "+f" (val30)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ __asm__ volatile (
+ "li.s %[fTmp1], 0.70710678118654752439 \n\t"
+ "sub.s %[fTmp2], %[val0], %[val1] \n\t"
+ "add.s %[val0], %[val0], %[val1] \n\t"
+ "sub.s %[fTmp3], %[val3], %[val2] \n\t"
+ "add.s %[val2], %[val3], %[val2] \n\t"
+ "sub.s %[fTmp4], %[val4], %[val5] \n\t"
+ "mul.s %[val1], %[fTmp1], %[fTmp2] \n\t"
+ "swc1 %[val0], 0(%[out]) \n\t"
+ "mul.s %[val3], %[fTmp3], %[fTmp1] \n\t"
+ "add.s %[val4], %[val4], %[val5] \n\t"
+ "mul.s %[val5], %[fTmp1], %[fTmp4] \n\t"
+ "swc1 %[val1], 16*4(%[out]) \n\t"
+ "sub.s %[fTmp2], %[val7], %[val6] \n\t"
+ "add.s %[val2], %[val2], %[val3] \n\t"
+ "swc1 %[val3], 24*4(%[out]) \n\t"
+ "add.s %[val6], %[val7], %[val6] \n\t"
+ "mul.s %[val7], %[fTmp1], %[fTmp2] \n\t"
+ "swc1 %[val2], 8*4(%[out]) \n\t"
+ "add.s %[val6], %[val6], %[val7] \n\t"
+ "swc1 %[val7], 28*4(%[out]) \n\t"
+ "add.s %[val4], %[val4], %[val6] \n\t"
+ "add.s %[val6], %[val6], %[val5] \n\t"
+ "add.s %[val5], %[val5], %[val7] \n\t"
+ "swc1 %[val4], 4*4(%[out]) \n\t"
+ "swc1 %[val5], 20*4(%[out]) \n\t"
+ "swc1 %[val6], 12*4(%[out]) \n\t"
+
+ : [fTmp1] "=f" (fTmp1), [fTmp2] "=&f" (fTmp2),
+ [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val0] "+f" (val0), [val1] "+f" (val1),
+ [val2] "+f" (val2), [val3] "+f" (val3),
+ [val4] "+f" (val4), [val5] "+f" (val5),
+ [val6] "+f" (val6), [val7] "+f" (val7)
+ : [out] "r" (out)
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val8], %[val9] \n\t"
+ "add.s %[val8], %[val8], %[val9] \n\t"
+ "sub.s %[fTmp3], %[val11], %[val10] \n\t"
+ "add.s %[val10], %[val11], %[val10] \n\t"
+ "sub.s %[fTmp4], %[val12], %[val13] \n\t"
+ "mul.s %[val9], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val12], %[val12], %[val13] \n\t"
+ "mul.s %[val11], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val15], %[val14] \n\t"
+ "mul.s %[val13], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val14], %[val15], %[val14] \n\t"
+ "add.s %[val10], %[val10], %[val11] \n\t"
+ "mul.s %[val15], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val14], %[val14], %[val15] \n\t"
+ "add.s %[val12], %[val12], %[val14] \n\t"
+ "add.s %[val14], %[val14], %[val13] \n\t"
+ "add.s %[val13], %[val13], %[val15] \n\t"
+ "add.s %[val8], %[val8], %[val12] \n\t"
+ "add.s %[val12], %[val12], %[val10] \n\t"
+ "add.s %[val10], %[val10], %[val14] \n\t"
+ "add.s %[val14], %[val14], %[val9] \n\t"
+ "add.s %[val9], %[val9], %[val13] \n\t"
+ "add.s %[val13], %[val13], %[val11] \n\t"
+ "add.s %[val11], %[val11], %[val15] \n\t"
+ "swc1 %[val8], 2*4(%[out]) \n\t"
+ "swc1 %[val9], 18*4(%[out]) \n\t"
+ "swc1 %[val10], 10*4(%[out]) \n\t"
+ "swc1 %[val11], 26*4(%[out]) \n\t"
+ "swc1 %[val12], 6*4(%[out]) \n\t"
+ "swc1 %[val13], 22*4(%[out]) \n\t"
+ "swc1 %[val14], 14*4(%[out]) \n\t"
+ "swc1 %[val15], 30*4(%[out]) \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val8] "+f" (val8), [val9] "+f" (val9), [val10] "+f" (val10),
+ [val11] "+f" (val11), [val12] "+f" (val12), [val13] "+f" (val13),
+ [val14] "+f" (val14), [val15] "+f" (val15)
+ : [fTmp1] "f" (fTmp1), [out] "r" (out)
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val16], %[val17] \n\t"
+ "add.s %[val16], %[val16], %[val17] \n\t"
+ "sub.s %[fTmp3], %[val19], %[val18] \n\t"
+ "add.s %[val18], %[val19], %[val18] \n\t"
+ "sub.s %[fTmp4], %[val20], %[val21] \n\t"
+ "mul.s %[val17], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val20], %[val20], %[val21] \n\t"
+ "mul.s %[val19], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val23], %[val22] \n\t"
+ "mul.s %[val21], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val22], %[val23], %[val22] \n\t"
+ "add.s %[val18], %[val18], %[val19] \n\t"
+ "mul.s %[val23], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val22], %[val22], %[val23] \n\t"
+ "add.s %[val20], %[val20], %[val22] \n\t"
+ "add.s %[val22], %[val22], %[val21] \n\t"
+ "add.s %[val21], %[val21], %[val23] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val16] "+f" (val16), [val17] "+f" (val17), [val18] "+f" (val18),
+ [val19] "+f" (val19), [val20] "+f" (val20), [val21] "+f" (val21),
+ [val22] "+f" (val22), [val23] "+f" (val23)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ __asm__ volatile (
+ "sub.s %[fTmp2], %[val24], %[val25] \n\t"
+ "add.s %[val24], %[val24], %[val25] \n\t"
+ "sub.s %[fTmp3], %[val27], %[val26] \n\t"
+ "add.s %[val26], %[val27], %[val26] \n\t"
+ "sub.s %[fTmp4], %[val28], %[val29] \n\t"
+ "mul.s %[val25], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val28], %[val28], %[val29] \n\t"
+ "mul.s %[val27], %[fTmp1], %[fTmp3] \n\t"
+ "sub.s %[fTmp2], %[val31], %[val30] \n\t"
+ "mul.s %[val29], %[fTmp1], %[fTmp4] \n\t"
+ "add.s %[val30], %[val31], %[val30] \n\t"
+ "add.s %[val26], %[val26], %[val27] \n\t"
+ "mul.s %[val31], %[fTmp1], %[fTmp2] \n\t"
+ "add.s %[val30], %[val30], %[val31] \n\t"
+ "add.s %[val28], %[val28], %[val30] \n\t"
+ "add.s %[val30], %[val30], %[val29] \n\t"
+ "add.s %[val29], %[val29], %[val31] \n\t"
+ "add.s %[val24], %[val24], %[val28] \n\t"
+ "add.s %[val28], %[val28], %[val26] \n\t"
+ "add.s %[val26], %[val26], %[val30] \n\t"
+ "add.s %[val30], %[val30], %[val25] \n\t"
+ "add.s %[val25], %[val25], %[val29] \n\t"
+ "add.s %[val29], %[val29], %[val27] \n\t"
+ "add.s %[val27], %[val27], %[val31] \n\t"
+
+ : [fTmp2] "=&f" (fTmp2), [fTmp3] "=&f" (fTmp3), [fTmp4] "=&f" (fTmp4),
+ [val24] "+f" (val24), [val25] "+f" (val25), [val26] "+f" (val26),
+ [val27] "+f" (val27), [val28] "+f" (val28), [val29] "+f" (val29),
+ [val30] "+f" (val30), [val31] "+f" (val31)
+ : [fTmp1] "f" (fTmp1)
+ );
+
+ out[ 1] = val16 + val24;
+ out[17] = val17 + val25;
+ out[ 9] = val18 + val26;
+ out[25] = val19 + val27;
+ out[ 5] = val20 + val28;
+ out[21] = val21 + val29;
+ out[13] = val22 + val30;
+ out[29] = val23 + val31;
+ out[ 3] = val24 + val20;
+ out[19] = val25 + val21;
+ out[11] = val26 + val22;
+ out[27] = val27 + val23;
+ out[ 7] = val28 + val18;
+ out[23] = val29 + val19;
+ out[15] = val30 + val17;
+ out[31] = val31;
+}
+#endif /* !HAVE_LOONGSON3 */
+
+static void imdct36_mips_float(float *out, float *buf, float *in, float *win)
+{
+ float t0, t1, t2, t3, s0, s1, s2, s3;
+ float tmp[18];
+ /* temporary variables */
+ float in1, in2, in3, in4, in5, in6;
+ float out1, out2, out3, out4, out5;
+ float c1, c2, c3, c4, c5, c6, c7, c8, c9;
+
+ /**
+ * all loops are unrolled totally, and instructions are scheduled to
+ * minimize pipeline stall. instructions of the first two loops are
+ * reorganized, in order to eliminate unnecessary readings and
+ * writings into array. values defined in macros and tables are
+ * eliminated - they are directly loaded in appropriate variables
+ */
+
+ /* loop 1 and 2 */
+ __asm__ volatile (
+ "lwc1 %[in1], 17*4(%[in]) \t\n"
+ "lwc1 %[in2], 16*4(%[in]) \t\n"
+ "lwc1 %[in3], 15*4(%[in]) \t\n"
+ "lwc1 %[in4], 14*4(%[in]) \t\n"
+ "lwc1 %[in5], 13*4(%[in]) \t\n"
+ "lwc1 %[in6], 12*4(%[in]) \t\n"
+ "add.s %[out1], %[in1], %[in2] \t\n"
+ "add.s %[out2], %[in2], %[in3] \t\n"
+ "add.s %[out3], %[in3], %[in4] \t\n"
+ "add.s %[out4], %[in4], %[in5] \t\n"
+ "add.s %[out5], %[in5], %[in6] \t\n"
+ "lwc1 %[in1], 11*4(%[in]) \t\n"
+ "swc1 %[out2], 16*4(%[in]) \t\n"
+ "add.s %[out1], %[out1], %[out3] \t\n"
+ "swc1 %[out4], 14*4(%[in]) \t\n"
+ "add.s %[out3], %[out3], %[out5] \t\n"
+ "lwc1 %[in2], 10*4(%[in]) \t\n"
+ "lwc1 %[in3], 9*4(%[in]) \t\n"
+ "swc1 %[out1], 17*4(%[in]) \t\n"
+ "lwc1 %[in4], 8*4(%[in]) \t\n"
+ "swc1 %[out3], 15*4(%[in]) \t\n"
+ "add.s %[out1], %[in6], %[in1] \t\n"
+ "add.s %[out2], %[in1], %[in2] \t\n"
+ "add.s %[out3], %[in2], %[in3] \t\n"
+ "add.s %[out4], %[in3], %[in4] \t\n"
+ "lwc1 %[in5], 7*4(%[in]) \t\n"
+ "swc1 %[out1], 12*4(%[in]) \t\n"
+ "add.s %[out5], %[out5], %[out2] \t\n"
+ "swc1 %[out3], 10*4(%[in]) \t\n"
+ "add.s %[out2], %[out2], %[out4] \t\n"
+ "lwc1 %[in6], 6*4(%[in]) \t\n"
+ "lwc1 %[in1], 5*4(%[in]) \t\n"
+ "swc1 %[out5], 13*4(%[in]) \t\n"
+ "lwc1 %[in2], 4*4(%[in]) \t\n"
+ "swc1 %[out2], 11*4(%[in]) \t\n"
+ "add.s %[out5], %[in4], %[in5] \t\n"
+ "add.s %[out1], %[in5], %[in6] \t\n"
+ "add.s %[out2], %[in6], %[in1] \t\n"
+ "add.s %[out3], %[in1], %[in2] \t\n"
+ "lwc1 %[in3], 3*4(%[in]) \t\n"
+ "swc1 %[out5], 8*4(%[in]) \t\n"
+ "add.s %[out4], %[out4], %[out1] \t\n"
+ "swc1 %[out2], 6*4(%[in]) \t\n"
+ "add.s %[out1], %[out1], %[out3] \t\n"
+ "lwc1 %[in4], 2*4(%[in]) \t\n"
+ "lwc1 %[in5], 1*4(%[in]) \t\n"
+ "swc1 %[out4], 9*4(%[in]) \t\n"
+ "lwc1 %[in6], 0(%[in]) \t\n"
+ "swc1 %[out1], 7*4(%[in]) \t\n"
+ "add.s %[out4], %[in2], %[in3] \t\n"
+ "add.s %[out5], %[in3], %[in4] \t\n"
+ "add.s %[out1], %[in4], %[in5] \t\n"
+ "add.s %[out2], %[in5], %[in6] \t\n"
+ "swc1 %[out4], 4*4(%[in]) \t\n"
+ "add.s %[out3], %[out3], %[out5] \t\n"
+ "swc1 %[out1], 2*4(%[in]) \t\n"
+ "add.s %[out5], %[out5], %[out2] \t\n"
+ "swc1 %[out2], 1*4(%[in]) \t\n"
+ "swc1 %[out3], 5*4(%[in]) \t\n"
+ "swc1 %[out5], 3*4(%[in]) \t\n"
+
+ : [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3), [out4] "=&f" (out4),
+ [out5] "=&f" (out5)
+ : [in] "r" (in)
+ : "memory"
+ );
+
+ /* loop 3 */
+ __asm__ volatile (
+ "li.s %[c1], 0.5 \t\n"
+ "lwc1 %[in1], 8*4(%[in]) \t\n"
+ "lwc1 %[in2], 16*4(%[in]) \t\n"
+ "lwc1 %[in3], 4*4(%[in]) \t\n"
+ "lwc1 %[in4], 0(%[in]) \t\n"
+ "lwc1 %[in5], 12*4(%[in]) \t\n"
+ "li.s %[c2], 0.93969262078590838405 \t\n"
+ "add.s %[t2], %[in1], %[in2] \t\n"
+ "add.s %[t0], %[in1], %[in3] \t\n"
+ "li.s %[c3], -0.76604444311897803520 \t\n"
+ "madd.s %[t3], %[in4], %[in5], %[c1] \t\n"
+ "sub.s %[t1], %[in4], %[in5] \t\n"
+ "sub.s %[t2], %[t2], %[in3] \t\n"
+ "mul.s %[t0], %[t0], %[c2] \t\n"
+ "li.s %[c4], -0.17364817766693034885 \t\n"
+ "li.s %[c5], -0.86602540378443864676 \t\n"
+ "li.s %[c6], 0.98480775301220805936 \t\n"
+ "nmsub.s %[out1], %[t1], %[t2], %[c1] \t\n"
+ "add.s %[out2], %[t1], %[t2] \t\n"
+ "add.s %[t2], %[in2], %[in3] \t\n"
+ "sub.s %[t1], %[in1], %[in2] \t\n"
+ "sub.s %[out3], %[t3], %[t0] \t\n"
+ "swc1 %[out1], 6*4(%[tmp]) \t\n"
+ "swc1 %[out2], 16*4(%[tmp]) \t\n"
+ "mul.s %[t2], %[t2], %[c3] \t\n"
+ "mul.s %[t1], %[t1], %[c4] \t\n"
+ "add.s %[out1], %[t3], %[t0] \t\n"
+ "lwc1 %[in1], 10*4(%[in]) \t\n"
+ "lwc1 %[in2], 14*4(%[in]) \t\n"
+ "sub.s %[out3], %[out3], %[t2] \t\n"
+ "add.s %[out2], %[t3], %[t2] \t\n"
+ "add.s %[out1], %[out1], %[t1] \t\n"
+ "lwc1 %[in3], 2*4(%[in]) \t\n"
+ "lwc1 %[in4], 6*4(%[in]) \t\n"
+ "swc1 %[out3], 10*4(%[tmp]) \t\n"
+ "sub.s %[out2], %[out2], %[t1] \t\n"
+ "swc1 %[out1], 2*4(%[tmp]) \t\n"
+ "add.s %[out1], %[in1], %[in2] \t\n"
+ "add.s %[t2], %[in1], %[in3] \t\n"
+ "sub.s %[t3], %[in1], %[in2] \t\n"
+ "swc1 %[out2], 14*4(%[tmp]) \t\n"
+ "li.s %[c7], -0.34202014332566873304 \t\n"
+ "sub.s %[out1], %[out1], %[in3] \t\n"
+ "mul.s %[t2], %[t2], %[c6] \t\n"
+ "mul.s %[t3], %[t3], %[c7] \t\n"
+ "li.s %[c8], 0.86602540378443864676 \t\n"
+ "mul.s %[t0], %[in4], %[c8] \t\n"
+ "mul.s %[out1], %[out1], %[c5] \t\n"
+ "add.s %[t1], %[in2], %[in3] \t\n"
+ "li.s %[c9], -0.64278760968653932632 \t\n"
+ "add.s %[out2], %[t2], %[t3] \t\n"
+ "lwc1 %[in1], 9*4(%[in]) \t\n"
+ "swc1 %[out1], 4*4(%[tmp]) \t\n"
+ "mul.s %[t1], %[t1], %[c9] \t\n"
+ "lwc1 %[in2], 17*4(%[in]) \t\n"
+ "add.s %[out2], %[out2], %[t0] \t\n"
+ "lwc1 %[in3], 5*4(%[in]) \t\n"
+ "lwc1 %[in4], 1*4(%[in]) \t\n"
+ "add.s %[out3], %[t2], %[t1] \t\n"
+ "sub.s %[out1], %[t3], %[t1] \t\n"
+ "swc1 %[out2], 0(%[tmp]) \t\n"
+ "lwc1 %[in5], 13*4(%[in]) \t\n"
+ "add.s %[t2], %[in1], %[in2] \t\n"
+ "sub.s %[out3], %[out3], %[t0] \t\n"
+ "sub.s %[out1], %[out1], %[t0] \t\n"
+ "add.s %[t0], %[in1], %[in3] \t\n"
+ "madd.s %[t3], %[in4], %[in5], %[c1] \t\n"
+ "sub.s %[t2], %[t2], %[in3] \t\n"
+ "swc1 %[out3], 12*4(%[tmp]) \t\n"
+ "swc1 %[out1], 8*4(%[tmp]) \t\n"
+ "sub.s %[t1], %[in4], %[in5] \t\n"
+ "mul.s %[t0], %[t0], %[c2] \t\n"
+ "nmsub.s %[out1], %[t1], %[t2], %[c1] \t\n"
+ "add.s %[out2], %[t1], %[t2] \t\n"
+ "add.s %[t2], %[in2], %[in3] \t\n"
+ "sub.s %[t1], %[in1], %[in2] \t\n"
+ "sub.s %[out3], %[t3], %[t0] \t\n"
+ "swc1 %[out1], 7*4(%[tmp]) \t\n"
+ "swc1 %[out2], 17*4(%[tmp]) \t\n"
+ "mul.s %[t2], %[t2], %[c3] \t\n"
+ "mul.s %[t1], %[t1], %[c4] \t\n"
+ "add.s %[out1], %[t3], %[t0] \t\n"
+ "lwc1 %[in1], 11*4(%[in]) \t\n"
+ "lwc1 %[in2], 15*4(%[in]) \t\n"
+ "sub.s %[out3], %[out3], %[t2] \t\n"
+ "add.s %[out2], %[t3], %[t2] \t\n"
+ "add.s %[out1], %[out1], %[t1] \t\n"
+ "lwc1 %[in3], 3*4(%[in]) \t\n"
+ "lwc1 %[in4], 7*4(%[in]) \t\n"
+ "swc1 %[out3], 11*4(%[tmp]) \t\n"
+ "sub.s %[out2], %[out2], %[t1] \t\n"
+ "swc1 %[out1], 3*4(%[tmp]) \t\n"
+ "add.s %[out3], %[in1], %[in2] \t\n"
+ "add.s %[t2], %[in1], %[in3] \t\n"
+ "sub.s %[t3], %[in1], %[in2] \t\n"
+ "swc1 %[out2], 15*4(%[tmp]) \t\n"
+ "mul.s %[t0], %[in4], %[c8] \t\n"
+ "sub.s %[out3], %[out3], %[in3] \t\n"
+ "mul.s %[t2], %[t2], %[c6] \t\n"
+ "mul.s %[t3], %[t3], %[c7] \t\n"
+ "add.s %[t1], %[in2], %[in3] \t\n"
+ "mul.s %[out3], %[out3], %[c5] \t\n"
+ "add.s %[out1], %[t2], %[t3] \t\n"
+ "mul.s %[t1], %[t1], %[c9] \t\n"
+ "swc1 %[out3], 5*4(%[tmp]) \t\n"
+ "add.s %[out1], %[out1], %[t0] \t\n"
+ "add.s %[out2], %[t2], %[t1] \t\n"
+ "sub.s %[out3], %[t3], %[t1] \t\n"
+ "swc1 %[out1], 1*4(%[tmp]) \t\n"
+ "sub.s %[out2], %[out2], %[t0] \t\n"
+ "sub.s %[out3], %[out3], %[t0] \t\n"
+ "swc1 %[out2], 13*4(%[tmp]) \t\n"
+ "swc1 %[out3], 9*4(%[tmp]) \t\n"
+
+ : [t0] "=&f" (t0), [t1] "=&f" (t1),
+ [t2] "=&f" (t2), [t3] "=&f" (t3),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3),
+ [c1] "=&f" (c1), [c2] "=&f" (c2),
+ [c3] "=&f" (c3), [c4] "=&f" (c4),
+ [c5] "=&f" (c5), [c6] "=&f" (c6),
+ [c7] "=&f" (c7), [c8] "=&f" (c8),
+ [c9] "=&f" (c9)
+ : [in] "r" (in), [tmp] "r" (tmp)
+ : "memory"
+ );
+
+ /* loop 4 */
+ __asm__ volatile (
+ "lwc1 %[in1], 2*4(%[tmp]) \t\n"
+ "lwc1 %[in2], 0(%[tmp]) \t\n"
+ "lwc1 %[in3], 3*4(%[tmp]) \t\n"
+ "lwc1 %[in4], 1*4(%[tmp]) \t\n"
+ "li.s %[c1], 0.50190991877167369479 \t\n"
+ "li.s %[c2], 5.73685662283492756461 \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 9*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*9*4(%[buf]) \t\n"
+ "lwc1 %[in3], 8*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "lwc1 %[in4], 4*8*4(%[buf]) \t\n"
+ "lwc1 %[in5], 29*4(%[win]) \t\n"
+ "lwc1 %[in6], 28*4(%[win]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "li.s %[c1], 0.51763809020504152469 \t\n"
+ "li.s %[c2], 1.93185165257813657349 \t\n"
+ "mul.s %[out3], %[in5], %[t0] \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out4], %[in6], %[t0] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "swc1 %[out3], 4*9*4(%[buf]) \t\n"
+ "swc1 %[out1], 288*4(%[out]) \t\n"
+ "swc1 %[out2], 256*4(%[out]) \t\n"
+ "swc1 %[out4], 4*8*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "lwc1 %[in1], 17*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*17*4(%[buf]) \t\n"
+ "lwc1 %[in3], 0(%[win]) \t\n"
+ "lwc1 %[in4], 0(%[buf]) \t\n"
+ "lwc1 %[in5], 37*4(%[win]) \t\n"
+ "lwc1 %[in6], 20*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "lwc1 %[in1], 6*4(%[tmp]) \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "swc1 %[out1], 544*4(%[out]) \t\n"
+ "lwc1 %[in2], 4*4(%[tmp]) \t\n"
+ "swc1 %[out2], 0(%[out]) \t\n"
+ "swc1 %[out3], 4*17*4(%[buf]) \t\n"
+ "swc1 %[out4], 0(%[buf]) \t\n"
+ "lwc1 %[in3], 7*4(%[tmp]) \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "lwc1 %[in4], 5*4(%[tmp]) \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 10*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*10*4(%[buf]) \t\n"
+ "lwc1 %[in3], 7*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "lwc1 %[in4], 4*7*4(%[buf]) \t\n"
+ "lwc1 %[in5], 30*4(%[win]) \t\n"
+ "lwc1 %[in6], 27*4(%[win]) \t\n"
+ "li.s %[c1], 0.55168895948124587824 \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "swc1 %[out1], 320*4(%[out]) \t\n"
+ "swc1 %[out2], 224*4(%[out]) \t\n"
+ "swc1 %[out3], 4*10*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*7*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "lwc1 %[in1], 16*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*16*4(%[buf]) \t\n"
+ "lwc1 %[in3], 1*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*1*4(%[buf]) \t\n"
+ "lwc1 %[in5], 36*4(%[win]) \t\n"
+ "lwc1 %[in6], 21*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "lwc1 %[in1], 10*4(%[tmp]) \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[in5], %[t0] \t\n"
+ "mul.s %[out4], %[in6], %[t0] \t\n"
+ "swc1 %[out1], 512*4(%[out]) \t\n"
+ "lwc1 %[in2], 8*4(%[tmp]) \t\n"
+ "swc1 %[out2], 32*4(%[out]) \t\n"
+ "swc1 %[out3], 4*16*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*1*4(%[buf]) \t\n"
+ "li.s %[c2], 1.18310079157624925896 \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "lwc1 %[in3], 11*4(%[tmp]) \t\n"
+ "lwc1 %[in4], 9*4(%[tmp]) \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 11*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*11*4(%[buf]) \t\n"
+ "lwc1 %[in3], 6*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "lwc1 %[in4], 4*6*4(%[buf]) \t\n"
+ "lwc1 %[in5], 31*4(%[win]) \t\n"
+ "lwc1 %[in6], 26*4(%[win]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "swc1 %[out3], 4*11*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*6*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "swc1 %[out1], 352*4(%[out]) \t\n"
+ "swc1 %[out2], 192*4(%[out]) \t\n"
+ "lwc1 %[in1], 15*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*15*4(%[buf]) \t\n"
+ "lwc1 %[in3], 2*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*2*4(%[buf]) \t\n"
+ "lwc1 %[in5], 35*4(%[win]) \t\n"
+ "lwc1 %[in6], 22*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "lwc1 %[in1], 14*4(%[tmp]) \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "swc1 %[out1], 480*4(%[out]) \t\n"
+ "lwc1 %[in2], 12*4(%[tmp]) \t\n"
+ "swc1 %[out2], 64*4(%[out]) \t\n"
+ "swc1 %[out3], 4*15*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*2*4(%[buf]) \t\n"
+ "lwc1 %[in3], 15*4(%[tmp]) \t\n"
+ "add.s %[s0], %[in1], %[in2] \t\n"
+ "sub.s %[s2], %[in1], %[in2] \t\n"
+ "lwc1 %[in4], 13*4(%[tmp]) \t\n"
+ "li.s %[c1], 0.61038729438072803416 \t\n"
+ "li.s %[c2], 0.87172339781054900991 \t\n"
+ "add.s %[s1], %[in3], %[in4] \t\n"
+ "sub.s %[s3], %[in3], %[in4] \t\n"
+ "lwc1 %[in1], 12*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*12*4(%[buf]) \t\n"
+ "lwc1 %[in3], 5*4(%[win]) \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "mul.s %[s3], %[s3], %[c2] \t\n"
+ "lwc1 %[in4], 4*5*4(%[buf]) \t\n"
+ "lwc1 %[in5], 32*4(%[win]) \t\n"
+ "lwc1 %[in6], 25*4(%[win]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "lwc1 %[s0], 16*4(%[tmp]) \t\n"
+ "lwc1 %[s1], 17*4(%[tmp]) \t\n"
+ "li.s %[c1], 0.70710678118654752439 \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "add.s %[t0], %[s2], %[s3] \t\n"
+ "swc1 %[out3], 4*12*4(%[buf]) \t\n"
+ "swc1 %[out1], 384*4(%[out]) \t\n"
+ "swc1 %[out2], 160*4(%[out]) \t\n"
+ "swc1 %[out4], 4*5*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s2], %[s3] \t\n"
+ "lwc1 %[in1], 14*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*14*4(%[buf]) \t\n"
+ "lwc1 %[in3], 3*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*3*4(%[buf]) \t\n"
+ "lwc1 %[in5], 34*4(%[win]) \t\n"
+ "lwc1 %[in6], 23*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "mul.s %[s1], %[s1], %[c1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[in5], %[t0] \t\n"
+ "mul.s %[out4], %[in6], %[t0] \t\n"
+ "swc1 %[out1], 448*4(%[out]) \t\n"
+ "add.s %[t0], %[s0], %[s1] \t\n"
+ "swc1 %[out2], 96*4(%[out]) \t\n"
+ "swc1 %[out3], 4*14*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*3*4(%[buf]) \t\n"
+ "sub.s %[t1], %[s0], %[s1] \t\n"
+ "lwc1 %[in1], 13*4(%[win]) \t\n"
+ "lwc1 %[in2], 4*13*4(%[buf]) \t\n"
+ "lwc1 %[in3], 4*4(%[win]) \t\n"
+ "lwc1 %[in4], 4*4*4(%[buf]) \t\n"
+ "lwc1 %[in5], 33*4(%[win]) \t\n"
+ "lwc1 %[in6], 24*4(%[win]) \t\n"
+ "madd.s %[out1], %[in2], %[in1], %[t1] \t\n"
+ "madd.s %[out2], %[in4], %[in3], %[t1] \t\n"
+ "mul.s %[out3], %[t0], %[in5] \t\n"
+ "mul.s %[out4], %[t0], %[in6] \t\n"
+ "swc1 %[out1], 416*4(%[out]) \t\n"
+ "swc1 %[out2], 128*4(%[out]) \t\n"
+ "swc1 %[out3], 4*13*4(%[buf]) \t\n"
+ "swc1 %[out4], 4*4*4(%[buf]) \t\n"
+
+ : [c1] "=&f" (c1), [c2] "=&f" (c2),
+ [in1] "=&f" (in1), [in2] "=&f" (in2),
+ [in3] "=&f" (in3), [in4] "=&f" (in4),
+ [in5] "=&f" (in5), [in6] "=&f" (in6),
+ [out1] "=&f" (out1), [out2] "=&f" (out2),
+ [out3] "=&f" (out3), [out4] "=&f" (out4),
+ [t0] "=&f" (t0), [t1] "=&f" (t1),
+ [t2] "=&f" (t2), [t3] "=&f" (t3),
+ [s0] "=&f" (s0), [s1] "=&f" (s1),
+ [s2] "=&f" (s2), [s3] "=&f" (s3)
+ : [tmp] "r" (tmp), [win] "r" (win),
+ [buf] "r" (buf), [out] "r" (out)
+ : "memory"
+ );
+}
+
+#if !HAVE_LOONGSON3
+static void ff_imdct36_blocks_mips_float(float *out, float *buf, float *in,
+ int count, int switch_point, int block_type)
+{
+ int j;
+ for (j=0 ; j < count; j++) {
+ /* apply window & overlap with previous buffer */
+
+ /* select window */
+ int win_idx = (switch_point && j < 2) ? 0 : block_type;
+ float *win = ff_mdct_win_float[win_idx + (4 & -(j & 1))];
+
+ imdct36_mips_float(out, buf, in, win);
+
+ in += 18;
+ buf += ((j&3) != 3 ? 1 : (72-3));
+ out++;
+ }
+}
+#endif /* !HAVE_LOONGSON3 */
+
+void ff_mpadsp_init_mipsfpu(MPADSPContext *s)
+{
+ s->apply_window_float = ff_mpadsp_apply_window_mips_float;
+#if !HAVE_LOONGSON3
+ s->imdct36_blocks_float = ff_imdct36_blocks_mips_float;
+ s->dct32_float = ff_dct32_mips_float;
+#endif /* !HAVE_LOONGSON3 */
+}
diff --git a/libavcodec/mips/sbrdsp_mips.c b/libavcodec/mips/sbrdsp_mips.c
new file mode 100644
index 0000000000..63361e4e1b
--- /dev/null
+++ b/libavcodec/mips/sbrdsp_mips.c
@@ -0,0 +1,911 @@
+/*
+ * 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
+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_MIPSFPU
+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"
+ );
+ }
+}
+
+#if !HAVE_LOONGSON3
+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"
+ );
+}
+#endif /* !HAVE_LOONGSON3 */
+
+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;
+ float *ff_table;
+ float y0,y1, temp0, temp1, 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 %[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"
+ "sub.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"
+
+ : [temp0]"=&r"(temp0), [ff_table]"=&r"(ff_table), [y0]"=&f"(y0),
+ [y1]"=&f"(y1), [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_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_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+
+void ff_sbrdsp_init_mips(SBRDSPContext *s)
+{
+#if HAVE_INLINE_ASM
+ s->qmf_pre_shuffle = sbr_qmf_pre_shuffle_mips;
+ s->qmf_post_shuffle = sbr_qmf_post_shuffle_mips;
+#if HAVE_MIPSFPU
+ s->sum64x5 = sbr_sum64x5_mips;
+ s->sum_square = sbr_sum_square_mips;
+ s->qmf_deint_bfly = sbr_qmf_deint_bfly_mips;
+#if !HAVE_LOONGSON3
+ s->autocorrelate = sbr_autocorrelate_mips;
+#endif /* !HAVE_LOONGSON3 */
+ 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_MIPSFPU */
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/mjpeg.h b/libavcodec/mjpeg.h
index 1ebe283748..cd5d0af2ac 100644
--- a/libavcodec/mjpeg.h
+++ b/libavcodec/mjpeg.h
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -117,6 +117,7 @@ enum JpegMarker {
#define PREDICT(ret, topleft, top, left, predictor)\
switch(predictor){\
+ case 0: ret= 0; break;\
case 1: ret= left; break;\
case 2: ret= top; break;\
case 3: ret= topleft; break;\
diff --git a/libavcodec/mjpeg2jpeg_bsf.c b/libavcodec/mjpeg2jpeg_bsf.c
index d27793420e..68640db9e6 100644
--- a/libavcodec/mjpeg2jpeg_bsf.c
+++ b/libavcodec/mjpeg2jpeg_bsf.c
@@ -2,20 +2,20 @@
* MJPEG/AVI1 to JPEG/JFIF bitstream format filter
* Copyright (c) 2010 Adrian Daerr and Nicolas George
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mjpeg_parser.c b/libavcodec/mjpeg_parser.c
index ab654614eb..e548b00f40 100644
--- a/libavcodec/mjpeg_parser.c
+++ b/libavcodec/mjpeg_parser.c
@@ -4,20 +4,20 @@
* Copyright (c) 2003 Alex Beregszaszi
* Copyright (c) 2003-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,27 +28,44 @@
#include "parser.h"
+typedef struct MJPEGParserContext{
+ ParseContext pc;
+ int size;
+}MJPEGParserContext;
/**
* Find the end of the current frame in the bitstream.
* @return the position of the first byte of the next frame, or -1
*/
-static int find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size){
+static int find_frame_end(MJPEGParserContext *m, const uint8_t *buf, int buf_size){
+ ParseContext *pc= &m->pc;
int vop_found, i;
- uint16_t state;
+ uint32_t state;
vop_found= pc->frame_start_found;
state= pc->state;
i=0;
if(!vop_found){
- for(i=0; i<buf_size; i++){
+ for(i=0; i<buf_size;){
state= (state<<8) | buf[i];
- if(state == 0xFFD8){
- i++;
- vop_found=1;
- break;
+ if(state>=0xFFC00000 && state<=0xFFFEFFFF){
+ if(state>=0xFFD80000 && state<=0xFFD8FFFF){
+ i++;
+ vop_found=1;
+ break;
+ }else if(state<0xFFD00000 || state>0xFFD9FFFF){
+ m->size= (state&0xFFFF)-1;
+ }
}
+ if(m->size>0){
+ int size= FFMIN(buf_size-i, m->size);
+ i+=size;
+ m->size-=size;
+ state=0;
+ continue;
+ }else
+ i++;
}
}
@@ -56,13 +73,25 @@ static int find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size){
/* EOF considered as end of frame */
if (buf_size == 0)
return 0;
- for(; i<buf_size; i++){
+ for(; i<buf_size;){
state= (state<<8) | buf[i];
- if(state == 0xFFD8){
- pc->frame_start_found=0;
- pc->state=0;
- return i-1;
+ if(state>=0xFFC00000 && state<=0xFFFEFFFF){
+ if(state>=0xFFD80000 && state<=0xFFD8FFFF){
+ pc->frame_start_found=0;
+ pc->state=0;
+ return i-3;
+ } else if(state<0xFFD00000 || state>0xFFD9FFFF){
+ m->size= (state&0xFFFF)-1;
+ }
}
+ if(m->size>0){
+ int size= FFMIN(buf_size-i, m->size);
+ i+=size;
+ m->size-=size;
+ state=0;
+ continue;
+ }else
+ i++;
}
}
pc->frame_start_found= vop_found;
@@ -75,13 +104,14 @@ static int jpeg_parse(AVCodecParserContext *s,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
{
- ParseContext *pc = s->priv_data;
+ MJPEGParserContext *m = s->priv_data;
+ ParseContext *pc = &m->pc;
int next;
if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
next= buf_size;
}else{
- next= find_frame_end(pc, buf, buf_size);
+ next= find_frame_end(m, buf, buf_size);
if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
*poutbuf = NULL;
@@ -98,7 +128,7 @@ static int jpeg_parse(AVCodecParserContext *s,
AVCodecParser ff_mjpeg_parser = {
.codec_ids = { AV_CODEC_ID_MJPEG },
- .priv_data_size = sizeof(ParseContext),
+ .priv_data_size = sizeof(MJPEGParserContext),
.parser_parse = jpeg_parse,
.parser_close = ff_parse_close,
};
diff --git a/libavcodec/mjpega_dump_header_bsf.c b/libavcodec/mjpega_dump_header_bsf.c
index 1bcb9e7223..87829fae8f 100644
--- a/libavcodec/mjpega_dump_header_bsf.c
+++ b/libavcodec/mjpega_dump_header_bsf.c
@@ -2,20 +2,20 @@
* MJPEG A dump header bitstream filter
* Copyright (c) 2006 Baptiste Coudurier
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -90,7 +90,6 @@ static int mjpega_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *av
}
AVBitStreamFilter ff_mjpega_dump_header_bsf = {
- "mjpegadump",
- 0,
- mjpega_dump_header,
+ .name = "mjpegadump",
+ .filter = mjpega_dump_header,
};
diff --git a/libavcodec/mjpegbdec.c b/libavcodec/mjpegbdec.c
index ef1df9c08d..8ac60c22a1 100644
--- a/libavcodec/mjpegbdec.c
+++ b/libavcodec/mjpegbdec.c
@@ -2,20 +2,20 @@
* Apple MJPEG-B decoder
* Copyright (c) 2002 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,6 +55,7 @@ static int mjpegb_decode_frame(AVCodecContext *avctx,
buf_ptr = buf;
buf_end = buf + buf_size;
+ s->got_picture = 0;
read_header:
/* reset on every SOI */
@@ -122,7 +123,7 @@ read_header:
8 * FFMIN(field_size, buf_end - buf_ptr - sos_offs));
s->mjpb_skiptosod = (sod_offs - sos_offs - show_bits(&s->gb, 16));
s->start_code = SOS;
- if (ff_mjpeg_decode_sos(s, NULL, NULL) < 0 &&
+ if (ff_mjpeg_decode_sos(s, NULL, 0, NULL) < 0 &&
(avctx->err_recognition & AV_EF_EXPLODE))
return AVERROR_INVALIDDATA;
}
@@ -133,13 +134,17 @@ read_header:
if (s->bottom_field != s->interlace_polarity && second_field_offs)
{
buf_ptr = buf + second_field_offs;
- second_field_offs = 0;
goto read_header;
}
}
//XXX FIXME factorize, this looks very similar to the EOI code
+ if(!s->got_picture) {
+ av_log(avctx, AV_LOG_WARNING, "no picture\n");
+ return buf_size;
+ }
+
if ((ret = av_frame_ref(data, s->picture_ptr)) < 0)
return ret;
*got_frame = 1;
@@ -162,5 +167,6 @@ AVCodec ff_mjpegb_decoder = {
.close = ff_mjpeg_decode_end,
.decode = mjpegb_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c
index c28553de86..1ce332833d 100644
--- a/libavcodec/mjpegdec.c
+++ b/libavcodec/mjpegdec.c
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,12 +30,12 @@
* MJPEG decoder.
*/
-#include <assert.h>
-
#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "avcodec.h"
#include "blockdsp.h"
+#include "copy_block.h"
#include "idctdsp.h"
#include "internal.h"
#include "jpegtables.h"
@@ -43,6 +43,9 @@
#include "mjpegdec.h"
#include "jpeglsdec.h"
#include "put_bits.h"
+#include "tiff.h"
+#include "exif.h"
+#include "bytestream.h"
static int build_vlc(VLC *vlc, const uint8_t *bits_table,
@@ -54,7 +57,7 @@ static int build_vlc(VLC *vlc, const uint8_t *bits_table,
uint16_t huff_sym[256];
int i;
- assert(nb_codes <= 256);
+ av_assert0(nb_codes <= 256);
ff_mjpeg_build_huffman_codes(huff_size, huff_code, bits_table, val_table);
@@ -84,6 +87,17 @@ static void build_basic_mjpeg_vlc(MJpegDecodeContext *s)
avpriv_mjpeg_val_ac_chrominance, 251, 0, 0);
}
+static void parse_avid(MJpegDecodeContext *s, uint8_t *buf, int len)
+{
+ s->buggy_avid = 1;
+ if (len > 14 && buf[12] == 1) /* 1 - NTSC */
+ s->interlace_polarity = 1;
+ if (len > 14 && buf[12] == 2) /* 2 - PAL */
+ s->interlace_polarity = 0;
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(s->avctx, AV_LOG_INFO, "AVID: len:%d %d\n", len, len > 14 ? buf[12] : -1);
+}
+
av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
{
MJpegDecodeContext *s = avctx->priv_data;
@@ -105,6 +119,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
s->buffer = NULL;
s->start_code = -1;
s->first_picture = 1;
+ s->got_picture = 0;
s->org_height = avctx->coded_height;
avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
avctx->colorspace = AVCOL_SPC_BT470BG;
@@ -112,19 +127,28 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx)
build_basic_mjpeg_vlc(s);
if (s->extern_huff) {
- int ret;
- av_log(avctx, AV_LOG_INFO, "mjpeg: using external huffman table\n");
+ av_log(avctx, AV_LOG_INFO, "using external huffman table\n");
init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size * 8);
- if ((ret = ff_mjpeg_decode_dht(s))) {
+ if (ff_mjpeg_decode_dht(s)) {
av_log(avctx, AV_LOG_ERROR,
- "mjpeg: error using external huffman table\n");
- return ret;
+ "error using external huffman table, switching back to internal\n");
+ build_basic_mjpeg_vlc(s);
}
}
if (avctx->field_order == AV_FIELD_BB) { /* quicktime icefloe 019 */
s->interlace_polarity = 1; /* bottom field first */
- av_log(avctx, AV_LOG_DEBUG, "mjpeg bottom field first\n");
+ av_log(avctx, AV_LOG_DEBUG, "bottom field first\n");
+ } else if (avctx->field_order == AV_FIELD_UNKNOWN) {
+ if (avctx->codec_tag == AV_RL32("MJPG"))
+ s->interlace_polarity = 1;
+ }
+
+ if ( avctx->extradata_size > 8
+ && AV_RL32(avctx->extradata) == 0x2C
+ && AV_RL32(avctx->extradata+4) == 0x18) {
+ parse_avid(s, avctx->extradata, avctx->extradata_size);
}
+
if (avctx->codec->id == AV_CODEC_ID_AMV)
s->flipped = 1;
@@ -139,11 +163,16 @@ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s)
len = get_bits(&s->gb, 16) - 2;
+ if (8*len > get_bits_left(&s->gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "dqt: len %d is too large\n", len);
+ return AVERROR_INVALIDDATA;
+ }
+
while (len >= 65) {
- /* only 8 bit precision handled */
- if (get_bits(&s->gb, 4) != 0) {
- av_log(s->avctx, AV_LOG_ERROR, "dqt: 16bit precision\n");
- return -1;
+ int pr = get_bits(&s->gb, 4);
+ if (pr > 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "dqt: invalid precision\n");
+ return AVERROR_INVALIDDATA;
}
index = get_bits(&s->gb, 4);
if (index >= 4)
@@ -152,7 +181,7 @@ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s)
/* read quant table */
for (i = 0; i < 64; i++) {
j = s->scantable.permutated[i];
- s->quant_matrixes[index][j] = get_bits(&s->gb, 8);
+ s->quant_matrixes[index][j] = get_bits(&s->gb, pr ? 16 : 8);
}
// XXX FIXME finetune, and perhaps add dc too
@@ -160,7 +189,7 @@ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s)
s->quant_matrixes[index][s->scantable.permutated[8]]) >> 1;
av_log(s->avctx, AV_LOG_DEBUG, "qscale[%d]: %d\n",
index, s->qscale[index]);
- len -= 65;
+ len -= 1 + 64 * (1+pr);
}
return 0;
}
@@ -175,6 +204,11 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
len = get_bits(&s->gb, 16) - 2;
+ if (8*len > get_bits_left(&s->gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "dht: len %d is too large\n", len);
+ return AVERROR_INVALIDDATA;
+ }
+
while (len > 0) {
if (len < 17)
return AVERROR_INVALIDDATA;
@@ -222,27 +256,41 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s)
int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
{
+ int len, nb_components, i, width, height, bits, ret;
+ unsigned pix_fmt_id;
int h_count[MAX_COMPONENTS] = { 0 };
int v_count[MAX_COMPONENTS] = { 0 };
- int len, nb_components, i, width, height, bits, pix_fmt_id, ret;
+
+ s->cur_scan = 0;
+ memset(s->upscale_h, 0, sizeof(s->upscale_h));
+ memset(s->upscale_v, 0, sizeof(s->upscale_v));
/* XXX: verify len field validity */
len = get_bits(&s->gb, 16);
+ s->avctx->bits_per_raw_sample =
bits = get_bits(&s->gb, 8);
+ if (bits > 16 || bits < 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "bits %d is invalid\n", bits);
+ return AVERROR_INVALIDDATA;
+ }
+
if (s->pegasus_rct)
bits = 9;
if (bits == 9 && !s->pegasus_rct)
s->rct = 1; // FIXME ugly
- if (bits != 8 && !s->lossless) {
- av_log(s->avctx, AV_LOG_ERROR, "only 8 bits/component accepted\n");
+ if(s->lossless && s->avctx->lowres){
+ av_log(s->avctx, AV_LOG_ERROR, "lowres is not possible with lossless jpeg\n");
return -1;
}
height = get_bits(&s->gb, 16);
width = get_bits(&s->gb, 16);
+ if (s->avctx->codec_id == AV_CODEC_ID_AMV && (height&15))
+ avpriv_request_sample(s->avctx, "non mod 16 height AMV\n");
+
// HACK for odd_height.mov
if (s->interlaced && s->width == width && s->height == height + 1)
height= s->height;
@@ -282,8 +330,10 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
if (v_count[i] > s->v_max)
s->v_max = v_count[i];
s->quant_index[i] = get_bits(&s->gb, 8);
- if (s->quant_index[i] >= 4)
+ if (s->quant_index[i] >= 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "quant_index is invalid\n");
return AVERROR_INVALIDDATA;
+ }
if (!h_count[i] || !v_count[i]) {
av_log(s->avctx, AV_LOG_ERROR,
"Invalid sampling factor in component %d %d:%d\n",
@@ -301,19 +351,19 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
return AVERROR_PATCHWELCOME;
}
- if (s->v_max == 1 && s->h_max == 1 && s->lossless == 1)
- s->rgb = 1;
/* if different size, realloc/alloc picture */
if (width != s->width || height != s->height || bits != s->bits ||
memcmp(s->h_count, h_count, sizeof(h_count)) ||
memcmp(s->v_count, v_count, sizeof(v_count))) {
+
s->width = width;
s->height = height;
s->bits = bits;
memcpy(s->h_count, h_count, sizeof(h_count));
memcpy(s->v_count, v_count, sizeof(v_count));
s->interlaced = 0;
+ s->got_picture = 0;
/* test interlaced mode */
if (s->first_picture &&
@@ -333,9 +383,18 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
s->first_picture = 0;
}
- if (!(s->interlaced && (s->bottom_field == !s->interlace_polarity))) {
+ if (s->got_picture && s->interlaced && (s->bottom_field == !s->interlace_polarity)) {
+ if (s->progressive) {
+ avpriv_request_sample(s->avctx, "progressively coded interlaced picture");
+ return AVERROR_INVALIDDATA;
+ }
+ } else{
+ if (s->v_max == 1 && s->h_max == 1 && s->lossless==1 && (nb_components==3 || nb_components==4))
+ s->rgb = 1;
+ else if (!s->lossless)
+ s->rgb = 0;
/* XXX: not complete test ! */
- pix_fmt_id = (s->h_count[0] << 28) | (s->v_count[0] << 24) |
+ pix_fmt_id = ((unsigned)s->h_count[0] << 28) | (s->v_count[0] << 24) |
(s->h_count[1] << 20) | (s->v_count[1] << 16) |
(s->h_count[2] << 12) | (s->v_count[2] << 8) |
(s->h_count[3] << 4) | s->v_count[3];
@@ -347,38 +406,187 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
if (!(pix_fmt_id & 0x0D0D0D0D))
pix_fmt_id -= (pix_fmt_id & 0x0F0F0F0F) >> 1;
+ for (i = 0; i < 8; i++) {
+ int j = 6 + (i&1) - (i&6);
+ int is = (pix_fmt_id >> (4*i)) & 0xF;
+ int js = (pix_fmt_id >> (4*j)) & 0xF;
+
+ if (is == 1 && js != 2 && (i < 2 || i > 5))
+ js = (pix_fmt_id >> ( 8 + 4*(i&1))) & 0xF;
+ if (is == 1 && js != 2 && (i < 2 || i > 5))
+ js = (pix_fmt_id >> (16 + 4*(i&1))) & 0xF;
+
+ if (is == 1 && js == 2) {
+ if (i & 1) s->upscale_h[j/2] = 1;
+ else s->upscale_v[j/2] = 1;
+ }
+ }
+
switch (pix_fmt_id) {
case 0x11111100:
if (s->rgb)
- s->avctx->pix_fmt = AV_PIX_FMT_BGRA;
+ s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_BGR48;
+ else {
+ if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') {
+ s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_GBRP : AV_PIX_FMT_GBRP16;
+ } else {
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ else s->avctx->pix_fmt = AV_PIX_FMT_YUV444P16;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ }
+ }
+ av_assert0(s->nb_components == 3);
+ break;
+ case 0x11111111:
+ if (s->rgb)
+ s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA64;
else {
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ if (s->adobe_transform == 0 && s->bits <= 8) {
+ s->avctx->pix_fmt = AV_PIX_FMT_GBRAP;
+ } else {
+ s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_YUVA444P : AV_PIX_FMT_YUVA444P16;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ }
+ }
+ av_assert0(s->nb_components == 4);
+ break;
+ case 0x22111122:
+ case 0x22111111:
+ if (s->adobe_transform == 0 && s->bits <= 8) {
+ s->avctx->pix_fmt = AV_PIX_FMT_GBRAP;
+ s->upscale_v[1] = s->upscale_v[2] = 1;
+ s->upscale_h[1] = s->upscale_h[2] = 1;
+ } else if (s->adobe_transform == 2 && s->bits <= 8) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+ s->upscale_v[1] = s->upscale_v[2] = 1;
+ s->upscale_h[1] = s->upscale_h[2] = 1;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ } else {
+ if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUVA420P;
+ else s->avctx->pix_fmt = AV_PIX_FMT_YUVA420P16;
s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
}
- assert(s->nb_components == 3);
+ av_assert0(s->nb_components == 4);
+ break;
+ case 0x12121100:
+ case 0x22122100:
+ case 0x21211100:
+ case 0x22211200:
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ else
+ goto unk_pixfmt;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ break;
+ case 0x22221100:
+ case 0x22112200:
+ case 0x11222200:
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ else
+ goto unk_pixfmt;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
break;
case 0x11000000:
- s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ case 0x13000000:
+ case 0x14000000:
+ case 0x31000000:
+ case 0x33000000:
+ case 0x34000000:
+ case 0x41000000:
+ case 0x43000000:
+ case 0x44000000:
+ if(s->bits <= 8)
+ s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ else
+ s->avctx->pix_fmt = AV_PIX_FMT_GRAY16;
break;
case 0x12111100:
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV440P : AV_PIX_FMT_YUVJ440P;
- s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ case 0x14121200:
+ case 0x14111100:
+ case 0x22211100:
+ case 0x22112100:
+ if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') {
+ if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GBRP;
+ else
+ goto unk_pixfmt;
+ s->upscale_v[0] = s->upscale_v[1] = 1;
+ } else {
+ if (pix_fmt_id == 0x14111100)
+ s->upscale_v[1] = s->upscale_v[2] = 1;
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV440P : AV_PIX_FMT_YUVJ440P;
+ else
+ goto unk_pixfmt;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ }
break;
case 0x21111100:
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P;
+ if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') {
+ if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GBRP;
+ else
+ goto unk_pixfmt;
+ s->upscale_h[0] = s->upscale_h[1] = 1;
+ } else {
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P;
+ else s->avctx->pix_fmt = AV_PIX_FMT_YUV422P16;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ }
+ break;
+ case 0x31111100:
+ if (s->bits > 8)
+ goto unk_pixfmt;
+ s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ s->upscale_h[1] = s->upscale_h[2] = 2;
+ break;
+ case 0x22121100:
+ case 0x22111200:
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P;
+ else
+ goto unk_pixfmt;
s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
break;
case 0x22111100:
- s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUVJ420P;
+ case 0x42111100:
+ case 0x24111100:
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUVJ420P;
+ else s->avctx->pix_fmt = AV_PIX_FMT_YUV420P16;
+ s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
+ if (pix_fmt_id == 0x42111100) {
+ if (s->bits > 8)
+ goto unk_pixfmt;
+ s->upscale_h[1] = s->upscale_h[2] = 1;
+ } else if (pix_fmt_id == 0x24111100) {
+ if (s->bits > 8)
+ goto unk_pixfmt;
+ s->upscale_v[1] = s->upscale_v[2] = 1;
+ }
+ break;
+ case 0x41111100:
+ if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV411P : AV_PIX_FMT_YUVJ411P;
+ else
+ goto unk_pixfmt;
s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG;
break;
default:
- av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x\n", pix_fmt_id);
+unk_pixfmt:
+ av_log(s->avctx, AV_LOG_ERROR, "Unhandled pixel format 0x%x bits:%d\n", pix_fmt_id, s->bits);
+ memset(s->upscale_h, 0, sizeof(s->upscale_h));
+ memset(s->upscale_v, 0, sizeof(s->upscale_v));
+ return AVERROR_PATCHWELCOME;
+ }
+ if ((AV_RB32(s->upscale_h) || AV_RB32(s->upscale_v)) && s->avctx->lowres) {
+ av_log(s->avctx, AV_LOG_ERROR, "lowres not supported for weird subsampling\n");
return AVERROR_PATCHWELCOME;
}
if (s->ls) {
- if (s->nb_components > 1)
+ memset(s->upscale_h, 0, sizeof(s->upscale_h));
+ memset(s->upscale_v, 0, sizeof(s->upscale_v));
+ if (s->nb_components == 3) {
s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ } else if (s->nb_components != 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "Unsupported number of components %d\n", s->nb_components);
+ return AVERROR_PATCHWELCOME;
+ } else if (s->palette_index && s->bits <= 8)
+ s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
else if (s->bits <= 8)
s->avctx->pix_fmt = AV_PIX_FMT_GRAY8;
else
@@ -392,15 +600,13 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
}
av_frame_unref(s->picture_ptr);
- if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0)
return -1;
- }
s->picture_ptr->pict_type = AV_PICTURE_TYPE_I;
s->picture_ptr->key_frame = 1;
s->got_picture = 1;
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
s->linesize[i] = s->picture_ptr->linesize[i] << s->interlaced;
ff_dlog(s->avctx, "%d %d %d %d %d %d\n",
@@ -411,6 +617,11 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
av_log(s->avctx, AV_LOG_DEBUG, "decode_sof0: error, len(%d) mismatch\n", len);
}
+ if (s->rgb && !s->lossless && !s->ls) {
+ av_log(s->avctx, AV_LOG_ERROR, "Unsupported coding and pixel format combination\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
/* totally blank picture as progressive JPEG will only add details to it */
if (s->progressive) {
int bw = (width + s->h_max * 8 - 1) / (s->h_max * 8);
@@ -419,8 +630,10 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s)
int size = bw * bh * s->h_count[i] * s->v_count[i];
av_freep(&s->blocks[i]);
av_freep(&s->last_nnz[i]);
- s->blocks[i] = av_malloc(size * sizeof(**s->blocks));
- s->last_nnz[i] = av_mallocz(size * sizeof(**s->last_nnz));
+ s->blocks[i] = av_mallocz_array(size, sizeof(**s->blocks));
+ s->last_nnz[i] = av_mallocz_array(size, sizeof(**s->last_nnz));
+ if (!s->blocks[i] || !s->last_nnz[i])
+ return AVERROR(ENOMEM);
s->block_stride[i] = bw * s->h_count[i];
}
memset(s->coefs_finished, 0, sizeof(s->coefs_finished));
@@ -432,11 +645,11 @@ static inline int mjpeg_decode_dc(MJpegDecodeContext *s, int dc_index)
{
int code;
code = get_vlc2(&s->gb, s->vlcs[0][dc_index].table, 9, 2);
- if (code < 0) {
+ if (code < 0 || code > 16) {
av_log(s->avctx, AV_LOG_WARNING,
"mjpeg_decode_dc: bad vlc: %d:%d (%p)\n",
0, dc_index, &s->vlcs[0][dc_index]);
- return 0xffff;
+ return 0xfffff;
}
if (code)
@@ -453,7 +666,7 @@ static int decode_block(MJpegDecodeContext *s, int16_t *block, int component,
/* DC coef */
val = mjpeg_decode_dc(s, dc_index);
- if (val == 0xffff) {
+ if (val == 0xfffff) {
av_log(s->avctx, AV_LOG_ERROR, "error dc\n");
return AVERROR_INVALIDDATA;
}
@@ -501,7 +714,7 @@ static int decode_dc_progressive(MJpegDecodeContext *s, int16_t *block,
int val;
s->bdsp.clear_block(block);
val = mjpeg_decode_dc(s, dc_index);
- if (val == 0xffff) {
+ if (val == 0xfffff) {
av_log(s->avctx, AV_LOG_ERROR, "error dc\n");
return AVERROR_INVALIDDATA;
}
@@ -675,46 +888,101 @@ static int decode_block_refinement(MJpegDecodeContext *s, int16_t *block,
#undef REFINE_BIT
#undef ZERO_RUN
-static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor,
- int point_transform)
+static int handle_rstn(MJpegDecodeContext *s, int nb_components)
+{
+ int i;
+ int reset = 0;
+
+ if (s->restart_interval) {
+ s->restart_count--;
+ if(s->restart_count == 0 && s->avctx->codec_id == AV_CODEC_ID_THP){
+ align_get_bits(&s->gb);
+ for (i = 0; i < nb_components; i++) /* reset dc */
+ s->last_dc[i] = (4 << s->bits);
+ }
+
+ i = 8 + ((-get_bits_count(&s->gb)) & 7);
+ /* skip RSTn */
+ if (s->restart_count == 0) {
+ if( show_bits(&s->gb, i) == (1 << i) - 1
+ || show_bits(&s->gb, i) == 0xFF) {
+ int pos = get_bits_count(&s->gb);
+ align_get_bits(&s->gb);
+ while (get_bits_left(&s->gb) >= 8 && show_bits(&s->gb, 8) == 0xFF)
+ skip_bits(&s->gb, 8);
+ if (get_bits_left(&s->gb) >= 8 && (get_bits(&s->gb, 8) & 0xF8) == 0xD0) {
+ for (i = 0; i < nb_components; i++) /* reset dc */
+ s->last_dc[i] = (4 << s->bits);
+ reset = 1;
+ } else
+ skip_bits_long(&s->gb, pos - get_bits_count(&s->gb));
+ }
+ }
+ }
+ return reset;
+}
+
+static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int nb_components, int predictor, int point_transform)
{
int i, mb_x, mb_y;
uint16_t (*buffer)[4];
- int left[3], top[3], topleft[3];
+ int left[4], top[4], topleft[4];
const int linesize = s->linesize[0];
- const int mask = (1 << s->bits) - 1;
+ const int mask = ((1 << s->bits) - 1) << point_transform;
+ int resync_mb_y = 0;
+ int resync_mb_x = 0;
+
+ if (s->nb_components != 3 && s->nb_components != 4)
+ return AVERROR_INVALIDDATA;
+ if (s->v_max != 1 || s->h_max != 1 || !s->lossless)
+ return AVERROR_INVALIDDATA;
+
+
+ s->restart_count = s->restart_interval;
av_fast_malloc(&s->ljpeg_buffer, &s->ljpeg_buffer_size,
(unsigned)s->mb_width * 4 * sizeof(s->ljpeg_buffer[0][0]));
buffer = s->ljpeg_buffer;
- for (i = 0; i < 3; i++)
- buffer[0][i] = 1 << (s->bits + point_transform - 1);
+ for (i = 0; i < 4; i++)
+ buffer[0][i] = 1 << (s->bits - 1);
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
- const int modified_predictor = mb_y ? predictor : 1;
uint8_t *ptr = s->picture_ptr->data[0] + (linesize * mb_y);
if (s->interlaced && s->bottom_field)
ptr += linesize >> 1;
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
top[i] = left[i] = topleft[i] = buffer[0][i];
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
- if (s->restart_interval && !s->restart_count)
+ int modified_predictor = predictor;
+
+ if (s->restart_interval && !s->restart_count){
s->restart_count = s->restart_interval;
+ resync_mb_x = mb_x;
+ resync_mb_y = mb_y;
+ for(i=0; i<4; i++)
+ top[i] = left[i]= topleft[i]= 1 << (s->bits - 1);
+ }
+ if (mb_y == resync_mb_y || mb_y == resync_mb_y+1 && mb_x < resync_mb_x || !mb_x)
+ modified_predictor = 1;
- for (i = 0; i < 3; i++) {
- int pred;
+ for (i=0;i<nb_components;i++) {
+ int pred, dc;
topleft[i] = top[i];
top[i] = buffer[mb_x][i];
PREDICT(pred, topleft[i], top[i], left[i], modified_predictor);
+ dc = mjpeg_decode_dc(s, s->dc_index[i]);
+ if(dc == 0xFFFFF)
+ return -1;
+
left[i] = buffer[mb_x][i] =
- mask & (pred + (mjpeg_decode_dc(s, s->dc_index[i]) << point_transform));
+ mask & (pred + (dc << point_transform));
}
if (s->restart_interval && !--s->restart_count) {
@@ -722,24 +990,47 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor,
skip_bits(&s->gb, 16); /* skip RSTn */
}
}
-
- if (s->rct) {
+ if (s->nb_components == 4) {
+ for(i=0; i<nb_components; i++) {
+ int c= s->comp_index[i];
+ if (s->bits <= 8) {
+ for(mb_x = 0; mb_x < s->mb_width; mb_x++) {
+ ptr[4*mb_x+3-c] = buffer[mb_x][i];
+ }
+ } else if(s->bits == 9) {
+ return AVERROR_PATCHWELCOME;
+ } else {
+ for(mb_x = 0; mb_x < s->mb_width; mb_x++) {
+ ((uint16_t*)ptr)[4*mb_x+c] = buffer[mb_x][i];
+ }
+ }
+ }
+ } else if (s->rct) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
- ptr[4 * mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2] - 0x200) >> 2);
- ptr[4 * mb_x + 0] = buffer[mb_x][1] + ptr[4 * mb_x + 1];
- ptr[4 * mb_x + 2] = buffer[mb_x][2] + ptr[4 * mb_x + 1];
+ ptr[3*mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2] - 0x200) >> 2);
+ ptr[3*mb_x + 0] = buffer[mb_x][1] + ptr[3*mb_x + 1];
+ ptr[3*mb_x + 2] = buffer[mb_x][2] + ptr[3*mb_x + 1];
}
} else if (s->pegasus_rct) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
- ptr[4 * mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2]) >> 2);
- ptr[4 * mb_x + 0] = buffer[mb_x][1] + ptr[4 * mb_x + 1];
- ptr[4 * mb_x + 2] = buffer[mb_x][2] + ptr[4 * mb_x + 1];
+ ptr[3*mb_x + 1] = buffer[mb_x][0] - ((buffer[mb_x][1] + buffer[mb_x][2]) >> 2);
+ ptr[3*mb_x + 0] = buffer[mb_x][1] + ptr[3*mb_x + 1];
+ ptr[3*mb_x + 2] = buffer[mb_x][2] + ptr[3*mb_x + 1];
}
} else {
- for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
- ptr[4 * mb_x + 0] = buffer[mb_x][2];
- ptr[4 * mb_x + 1] = buffer[mb_x][1];
- ptr[4 * mb_x + 2] = buffer[mb_x][0];
+ for(i=0; i<nb_components; i++) {
+ int c= s->comp_index[i];
+ if (s->bits <= 8) {
+ for(mb_x = 0; mb_x < s->mb_width; mb_x++) {
+ ptr[3*mb_x+2-c] = buffer[mb_x][i];
+ }
+ } else if(s->bits == 9) {
+ return AVERROR_PATCHWELCOME;
+ } else {
+ for(mb_x = 0; mb_x < s->mb_width; mb_x++) {
+ ((uint16_t*)ptr)[3*mb_x+2-c] = buffer[mb_x][i];
+ }
+ }
}
}
}
@@ -749,48 +1040,88 @@ static int ljpeg_decode_rgb_scan(MJpegDecodeContext *s, int predictor,
static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor,
int point_transform, int nb_components)
{
- int i, mb_x, mb_y;
+ int i, mb_x, mb_y, mask;
+ int bits= (s->bits+7)&~7;
+ int resync_mb_y = 0;
+ int resync_mb_x = 0;
+
+ point_transform += bits - s->bits;
+ mask = ((1 << s->bits) - 1) << point_transform;
+
+ av_assert0(nb_components>=1 && nb_components<=4);
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
for (mb_x = 0; mb_x < s->mb_width; mb_x++) {
- if (s->restart_interval && !s->restart_count)
+ if (s->restart_interval && !s->restart_count){
s->restart_count = s->restart_interval;
+ resync_mb_x = mb_x;
+ resync_mb_y = mb_y;
+ }
- if (mb_x == 0 || mb_y == 0 || s->interlaced) {
+ if(!mb_x || mb_y == resync_mb_y || mb_y == resync_mb_y+1 && mb_x < resync_mb_x || s->interlaced){
+ int toprow = mb_y == resync_mb_y || mb_y == resync_mb_y+1 && mb_x < resync_mb_x;
+ int leftcol = !mb_x || mb_y == resync_mb_y && mb_x == resync_mb_x;
for (i = 0; i < nb_components; i++) {
uint8_t *ptr;
+ uint16_t *ptr16;
int n, h, v, x, y, c, j, linesize;
- n = s->nb_blocks[i];
- c = s->comp_index[i];
- h = s->h_scount[i];
- v = s->v_scount[i];
- x = 0;
- y = 0;
- linesize = s->linesize[c];
-
- for (j = 0; j < n; j++) {
- int pred;
- // FIXME optimize this crap
- ptr = s->picture_ptr->data[c] +
- (linesize * (v * mb_y + y)) +
- (h * mb_x + x);
- if (y == 0 && mb_y == 0) {
- if (x == 0 && mb_x == 0)
- pred = 128 << point_transform;
- else
- pred = ptr[-1];
- } else {
- if (x == 0 && mb_x == 0)
- pred = ptr[-linesize];
- else
- PREDICT(pred, ptr[-linesize - 1],
- ptr[-linesize], ptr[-1], predictor);
- }
+ n = s->nb_blocks[i];
+ c = s->comp_index[i];
+ h = s->h_scount[i];
+ v = s->v_scount[i];
+ x = 0;
+ y = 0;
+ linesize= s->linesize[c];
+
+ if(bits>8) linesize /= 2;
+
+ for(j=0; j<n; j++) {
+ int pred, dc;
+
+ dc = mjpeg_decode_dc(s, s->dc_index[i]);
+ if(dc == 0xFFFFF)
+ return -1;
+ if(bits<=8){
+ ptr = s->picture_ptr->data[c] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap
+ if(y==0 && toprow){
+ if(x==0 && leftcol){
+ pred= 1 << (bits - 1);
+ }else{
+ pred= ptr[-1];
+ }
+ }else{
+ if(x==0 && leftcol){
+ pred= ptr[-linesize];
+ }else{
+ PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor);
+ }
+ }
if (s->interlaced && s->bottom_field)
ptr += linesize >> 1;
- *ptr = pred + (mjpeg_decode_dc(s, s->dc_index[i]) << point_transform);
+ pred &= mask;
+ *ptr= pred + (dc << point_transform);
+ }else{
+ ptr16 = (uint16_t*)(s->picture_ptr->data[c] + 2*(linesize * (v * mb_y + y)) + 2*(h * mb_x + x)); //FIXME optimize this crap
+ if(y==0 && toprow){
+ if(x==0 && leftcol){
+ pred= 1 << (bits - 1);
+ }else{
+ pred= ptr16[-1];
+ }
+ }else{
+ if(x==0 && leftcol){
+ pred= ptr16[-linesize];
+ }else{
+ PREDICT(pred, ptr16[-linesize-1], ptr16[-linesize], ptr16[-1], predictor);
+ }
+ }
+ if (s->interlaced && s->bottom_field)
+ ptr16 += linesize >> 1;
+ pred &= mask;
+ *ptr16= pred + (dc << point_transform);
+ }
if (++x == h) {
x = 0;
y++;
@@ -800,7 +1131,8 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor,
} else {
for (i = 0; i < nb_components; i++) {
uint8_t *ptr;
- int n, h, v, x, y, c, j, linesize;
+ uint16_t *ptr16;
+ int n, h, v, x, y, c, j, linesize, dc;
n = s->nb_blocks[i];
c = s->comp_index[i];
h = s->h_scount[i];
@@ -809,16 +1141,30 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor,
y = 0;
linesize = s->linesize[c];
+ if(bits>8) linesize /= 2;
+
for (j = 0; j < n; j++) {
int pred;
- // FIXME optimize this crap
- ptr = s->picture_ptr->data[c] +
+ dc = mjpeg_decode_dc(s, s->dc_index[i]);
+ if(dc == 0xFFFFF)
+ return -1;
+ if(bits<=8){
+ ptr = s->picture_ptr->data[c] +
(linesize * (v * mb_y + y)) +
- (h * mb_x + x);
- PREDICT(pred, ptr[-linesize - 1],
- ptr[-linesize], ptr[-1], predictor);
- *ptr = pred + (mjpeg_decode_dc(s, s->dc_index[i]) << point_transform);
+ (h * mb_x + x); //FIXME optimize this crap
+ PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor);
+
+ pred &= mask;
+ *ptr = pred + (dc << point_transform);
+ }else{
+ ptr16 = (uint16_t*)(s->picture_ptr->data[c] + 2*(linesize * (v * mb_y + y)) + 2*(h * mb_x + x)); //FIXME optimize this crap
+ PREDICT(pred, ptr16[-linesize-1], ptr16[-linesize], ptr16[-1], predictor);
+
+ pred &= mask;
+ *ptr16= pred + (dc << point_transform);
+ }
+
if (++x == h) {
x = 0;
y++;
@@ -835,18 +1181,58 @@ static int ljpeg_decode_yuv_scan(MJpegDecodeContext *s, int predictor,
return 0;
}
+static av_always_inline void mjpeg_copy_block(MJpegDecodeContext *s,
+ uint8_t *dst, const uint8_t *src,
+ int linesize, int lowres)
+{
+ switch (lowres) {
+ case 0: s->hdsp.put_pixels_tab[1][0](dst, src, linesize, 8);
+ break;
+ case 1: copy_block4(dst, src, linesize, linesize, 4);
+ break;
+ case 2: copy_block2(dst, src, linesize, linesize, 2);
+ break;
+ case 3: *dst = *src;
+ break;
+ }
+}
+
+static void shift_output(MJpegDecodeContext *s, uint8_t *ptr, int linesize)
+{
+ int block_x, block_y;
+ int size = 8 >> s->avctx->lowres;
+ if (s->bits > 8) {
+ for (block_y=0; block_y<size; block_y++)
+ for (block_x=0; block_x<size; block_x++)
+ *(uint16_t*)(ptr + 2*block_x + block_y*linesize) <<= 16 - s->bits;
+ } else {
+ for (block_y=0; block_y<size; block_y++)
+ for (block_x=0; block_x<size; block_x++)
+ *(ptr + block_x + block_y*linesize) <<= 8 - s->bits;
+ }
+}
+
static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
int Al, const uint8_t *mb_bitmask,
+ int mb_bitmask_size,
const AVFrame *reference)
{
int i, mb_x, mb_y;
uint8_t *data[MAX_COMPONENTS];
const uint8_t *reference_data[MAX_COMPONENTS];
int linesize[MAX_COMPONENTS];
- GetBitContext mb_bitmask_gb;
+ GetBitContext mb_bitmask_gb = {0}; // initialize to silence gcc warning
+ int bytes_per_pixel = 1 + (s->bits > 8);
- if (mb_bitmask)
+ if (mb_bitmask) {
+ if (mb_bitmask_size != (s->mb_width * s->mb_height + 7)>>3) {
+ av_log(s->avctx, AV_LOG_ERROR, "mb_bitmask_size mismatches\n");
+ return AVERROR_INVALIDDATA;
+ }
init_get_bits(&mb_bitmask_gb, mb_bitmask, s->mb_width * s->mb_height);
+ }
+
+ s->restart_count = 0;
for (i = 0; i < nb_components; i++) {
int c = s->comp_index[i];
@@ -879,27 +1265,36 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
x = 0;
y = 0;
for (j = 0; j < n; j++) {
- block_offset = ((linesize[c] * (v * mb_y + y) * 8) +
- (h * mb_x + x) * 8);
+ block_offset = (((linesize[c] * (v * mb_y + y) * 8) +
+ (h * mb_x + x) * 8 * bytes_per_pixel) >> s->avctx->lowres);
if (s->interlaced && s->bottom_field)
block_offset += linesize[c] >> 1;
- ptr = data[c] + block_offset;
+ if ( 8*(h * mb_x + x) < s->width
+ && 8*(v * mb_y + y) < s->height) {
+ ptr = data[c] + block_offset;
+ } else
+ ptr = NULL;
if (!s->progressive) {
- if (copy_mb)
- s->hdsp.put_pixels_tab[1][0](ptr,
- reference_data[c] + block_offset,
- linesize[c], 8);
- else {
+ if (copy_mb) {
+ if (ptr)
+ mjpeg_copy_block(s, ptr, reference_data[c] + block_offset,
+ linesize[c], s->avctx->lowres);
+
+ } else {
s->bdsp.clear_block(s->block);
if (decode_block(s, s->block, i,
s->dc_index[i], s->ac_index[i],
- s->quant_matrixes[s->quant_index[c]]) < 0) {
+ s->quant_matrixes[s->quant_sindex[i]]) < 0) {
av_log(s->avctx, AV_LOG_ERROR,
"error y=%d x=%d\n", mb_y, mb_x);
return AVERROR_INVALIDDATA;
}
- s->idsp.idct_put(ptr, linesize[c], s->block);
+ if (ptr) {
+ s->idsp.idct_put(ptr, linesize[c], s->block);
+ if (s->bits & 7)
+ shift_output(s, ptr, linesize[c]);
+ }
}
} else {
int block_idx = s->block_stride[c] * (v * mb_y + y) +
@@ -907,9 +1302,9 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
int16_t *block = s->blocks[c][block_idx];
if (Ah)
block[0] += get_bits1(&s->gb) *
- s->quant_matrixes[s->quant_index[c]][0] << Al;
+ s->quant_matrixes[s->quant_sindex[i]][0] << Al;
else if (decode_dc_progressive(s, block, i, s->dc_index[i],
- s->quant_matrixes[s->quant_index[c]],
+ s->quant_matrixes[s->quant_sindex[i]],
Al) < 0) {
av_log(s->avctx, AV_LOG_ERROR,
"error y=%d x=%d\n", mb_y, mb_x);
@@ -927,74 +1322,52 @@ static int mjpeg_decode_scan(MJpegDecodeContext *s, int nb_components, int Ah,
}
}
- if (s->restart_interval) {
- s->restart_count--;
- i = 8 + ((-get_bits_count(&s->gb)) & 7);
- /* skip RSTn */
- if (show_bits(&s->gb, i) == (1 << i) - 1) {
- int pos = get_bits_count(&s->gb);
- align_get_bits(&s->gb);
- while (get_bits_left(&s->gb) >= 8 && show_bits(&s->gb, 8) == 0xFF)
- skip_bits(&s->gb, 8);
- if ((get_bits(&s->gb, 8) & 0xF8) == 0xD0) {
- for (i = 0; i < nb_components; i++) /* reset dc */
- s->last_dc[i] = 1024;
- } else
- skip_bits_long(&s->gb, pos - get_bits_count(&s->gb));
- }
- }
+ handle_rstn(s, nb_components);
}
}
return 0;
}
static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s, int ss,
- int se, int Ah, int Al,
- const uint8_t *mb_bitmask,
- const AVFrame *reference)
+ int se, int Ah, int Al)
{
int mb_x, mb_y;
int EOBRUN = 0;
int c = s->comp_index[0];
uint8_t *data = s->picture_ptr->data[c];
- const uint8_t *reference_data = reference ? reference->data[c] : NULL;
int linesize = s->linesize[c];
int last_scan = 0;
- int16_t *quant_matrix = s->quant_matrixes[s->quant_index[c]];
- GetBitContext mb_bitmask_gb;
+ int16_t *quant_matrix = s->quant_matrixes[s->quant_sindex[0]];
+ int bytes_per_pixel = 1 + (s->bits > 8);
- if (ss < 0 || ss >= 64 ||
- se < ss || se >= 64 ||
- Ah < 0 || Al < 0)
+ av_assert0(ss>=0 && Ah>=0 && Al>=0);
+ if (se < ss || se > 63) {
+ av_log(s->avctx, AV_LOG_ERROR, "SS/SE %d/%d is invalid\n", ss, se);
return AVERROR_INVALIDDATA;
-
- if (mb_bitmask)
- init_get_bits(&mb_bitmask_gb, mb_bitmask, s->mb_width * s->mb_height);
+ }
if (!Al) {
// s->coefs_finished is a bitmask for coefficients coded
// ss and se are parameters telling start and end coefficients
- s->coefs_finished[c] |= (~0ULL >> (63 - (se - ss))) << ss;
+ s->coefs_finished[c] |= (2ULL << se) - (1ULL << ss);
last_scan = !~s->coefs_finished[c];
}
- if (s->interlaced && s->bottom_field) {
- int offset = linesize >> 1;
- data += offset;
- reference_data += offset;
- }
+ if (s->interlaced && s->bottom_field)
+ data += linesize >> 1;
+
+ s->restart_count = 0;
for (mb_y = 0; mb_y < s->mb_height; mb_y++) {
- int block_offset = mb_y * linesize * 8;
- uint8_t *ptr = data + block_offset;
+ uint8_t *ptr = data + (mb_y * linesize * 8 >> s->avctx->lowres);
int block_idx = mb_y * s->block_stride[c];
int16_t (*block)[64] = &s->blocks[c][block_idx];
uint8_t *last_nnz = &s->last_nnz[c][block_idx];
for (mb_x = 0; mb_x < s->mb_width; mb_x++, block++, last_nnz++) {
- const int copy_mb = mb_bitmask && !get_bits1(&mb_bitmask_gb);
-
- if (!copy_mb) {
int ret;
+ if (s->restart_interval && !s->restart_count)
+ s->restart_count = s->restart_interval;
+
if (Ah)
ret = decode_block_refinement(s, *block, last_nnz, s->ac_index[0],
quant_matrix, ss, se, Al, &EOBRUN);
@@ -1006,31 +1379,35 @@ static int mjpeg_decode_scan_progressive_ac(MJpegDecodeContext *s, int ss,
"error y=%d x=%d\n", mb_y, mb_x);
return AVERROR_INVALIDDATA;
}
- }
if (last_scan) {
- if (copy_mb) {
- s->hdsp.put_pixels_tab[1][0](ptr,
- reference_data + block_offset,
- linesize, 8);
- } else {
s->idsp.idct_put(ptr, linesize, *block);
- ptr += 8;
- }
+ if (s->bits & 7)
+ shift_output(s, ptr, linesize);
+ ptr += bytes_per_pixel*8 >> s->avctx->lowres;
}
+ if (handle_rstn(s, 0))
+ EOBRUN = 0;
}
}
return 0;
}
int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
- const AVFrame *reference)
+ int mb_bitmask_size, const AVFrame *reference)
{
int len, nb_components, i, h, v, predictor, point_transform;
int index, id, ret;
const int block_size = s->lossless ? 1 : 8;
int ilv, prev_shift;
+ if (!s->got_picture) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "Can not process SOS before SOF, skipping\n");
+ return -1;
+ }
+
+ av_assert0(s->picture_ptr->data[0]);
/* XXX: verify len field validity */
len = get_bits(&s->gb, 16);
nb_components = get_bits(&s->gb, 8);
@@ -1060,27 +1437,35 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
&& nb_components == 3 && s->nb_components == 3 && i)
index = 3 - i;
- s->comp_index[i] = index;
-
+ s->quant_sindex[i] = s->quant_index[index];
s->nb_blocks[i] = s->h_count[index] * s->v_count[index];
s->h_scount[i] = s->h_count[index];
s->v_scount[i] = s->v_count[index];
+ if(nb_components == 3 && s->nb_components == 3 && s->avctx->pix_fmt == AV_PIX_FMT_GBR24P)
+ index = (i+2)%3;
+ if(nb_components == 1 && s->nb_components == 3 && s->avctx->pix_fmt == AV_PIX_FMT_GBR24P)
+ index = (index+2)%3;
+
+ s->comp_index[i] = index;
+
s->dc_index[i] = get_bits(&s->gb, 4);
s->ac_index[i] = get_bits(&s->gb, 4);
if (s->dc_index[i] < 0 || s->ac_index[i] < 0 ||
s->dc_index[i] >= 4 || s->ac_index[i] >= 4)
goto out_of_range;
- if (!s->vlcs[0][s->dc_index[i]].table ||
- !s->vlcs[1][s->ac_index[i]].table)
+ if (!s->vlcs[0][s->dc_index[i]].table || !(s->progressive ? s->vlcs[2][s->ac_index[0]].table : s->vlcs[1][s->ac_index[i]].table))
goto out_of_range;
}
predictor = get_bits(&s->gb, 8); /* JPEG Ss / lossless JPEG predictor /JPEG-LS NEAR */
ilv = get_bits(&s->gb, 8); /* JPEG Se / JPEG-LS ILV */
- prev_shift = get_bits(&s->gb, 4); /* Ah */
- point_transform = get_bits(&s->gb, 4); /* Al */
+ if(s->avctx->codec_tag != AV_RL32("CJPG")){
+ prev_shift = get_bits(&s->gb, 4); /* Ah */
+ point_transform = get_bits(&s->gb, 4); /* Al */
+ }else
+ prev_shift = point_transform = 0;
if (nb_components > 1) {
/* interleaved stream */
@@ -1097,10 +1482,10 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
}
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(s->avctx, AV_LOG_DEBUG, "%s %s p:%d >>:%d ilv:%d bits:%d %s\n",
+ av_log(s->avctx, AV_LOG_DEBUG, "%s %s p:%d >>:%d ilv:%d bits:%d skip:%d %s comp:%d\n",
s->lossless ? "lossless" : "sequential DCT", s->rgb ? "RGB" : "",
- predictor, point_transform, ilv, s->bits,
- s->pegasus_rct ? "PRCT" : (s->rct ? "RCT" : ""));
+ predictor, point_transform, ilv, s->bits, s->mjpb_skiptosod,
+ s->pegasus_rct ? "PRCT" : (s->rct ? "RCT" : ""), nb_components);
/* mjpeg-b can have padding bytes between sos and image data, skip them */
@@ -1109,9 +1494,10 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask,
next_field:
for (i = 0; i < nb_components; i++)
- s->last_dc[i] = 1024;
+ s->last_dc[i] = (4 << s->bits);
if (s->lossless) {
+ av_assert0(s->picture_ptr == s->picture);
if (CONFIG_JPEGLS_DECODER && s->ls) {
// for () {
// reset_ls_coding_parameters(s, 0);
@@ -1121,8 +1507,7 @@ next_field:
return ret;
} else {
if (s->rgb) {
- if ((ret = ljpeg_decode_rgb_scan(s, predictor,
- point_transform)) < 0)
+ if ((ret = ljpeg_decode_rgb_scan(s, nb_components, predictor, point_transform)) < 0)
return ret;
} else {
if ((ret = ljpeg_decode_yuv_scan(s, predictor,
@@ -1133,16 +1518,15 @@ next_field:
}
} else {
if (s->progressive && predictor) {
+ av_assert0(s->picture_ptr == s->picture);
if ((ret = mjpeg_decode_scan_progressive_ac(s, predictor,
ilv, prev_shift,
- point_transform,
- mb_bitmask,
- reference)) < 0)
+ point_transform)) < 0)
return ret;
} else {
if ((ret = mjpeg_decode_scan(s, nb_components,
prev_shift, point_transform,
- mb_bitmask, reference)) < 0)
+ mb_bitmask, mb_bitmask_size, reference)) < 0)
return ret;
}
}
@@ -1153,7 +1537,7 @@ next_field:
GetBitContext bak = s->gb;
align_get_bits(&bak);
if (show_bits(&bak, 16) == 0xFFD1) {
- ff_dlog(s->avctx, "AVRn interlaced picture marker found\n");
+ av_log(s->avctx, AV_LOG_DEBUG, "AVRn interlaced picture marker found\n");
s->gb = bak;
skip_bits(&s->gb, 16);
s->bottom_field ^= 1;
@@ -1186,22 +1570,24 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
int len, id, i;
len = get_bits(&s->gb, 16);
- if (len < 5)
+ if (len < 6)
return AVERROR_INVALIDDATA;
if (8 * len > get_bits_left(&s->gb))
return AVERROR_INVALIDDATA;
id = get_bits_long(&s->gb, 32);
- id = av_be2ne32(id);
len -= 6;
- if (s->avctx->debug & FF_DEBUG_STARTCODE)
- av_log(s->avctx, AV_LOG_DEBUG, "APPx %8X\n", id);
+ if (s->avctx->debug & FF_DEBUG_STARTCODE) {
+ char id_str[32];
+ av_get_codec_tag_string(id_str, sizeof(id_str), av_bswap32(id));
+ av_log(s->avctx, AV_LOG_DEBUG, "APPx (%s / %8X) len=%d\n", id_str, id, len);
+ }
/* Buggy AVID, it puts EOI only at every 10th frame. */
/* Also, this fourcc is used by non-avid files too, it holds some
information, but it's always present in AVID-created files. */
- if (id == AV_RL32("AVI1")) {
+ if (id == AV_RB32("AVI1")) {
/* structure:
4bytes AVI1
1bytes polarity
@@ -1209,12 +1595,9 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
4bytes field_size
4bytes field_size_less_padding
*/
- s->buggy_avid = 1;
- i = get_bits(&s->gb, 8);
- if (i == 2)
- s->bottom_field = 1;
- else if (i == 1)
- s->bottom_field = 0;
+ s->buggy_avid = 1;
+ i = get_bits(&s->gb, 8); len--;
+ av_log(s->avctx, AV_LOG_DEBUG, "polarity %d\n", i);
#if 0
skip_bits(&s->gb, 8);
skip_bits(&s->gb, 32);
@@ -1226,7 +1609,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
// len -= 2;
- if (id == AV_RL32("JFIF")) {
+ if (id == AV_RB32("JFIF")) {
int t_w, t_h, v1, v2;
skip_bits(&s->gb, 8); /* the trailing zero-byte */
v1 = get_bits(&s->gb, 8);
@@ -1255,48 +1638,147 @@ static int mjpeg_decode_app(MJpegDecodeContext *s)
goto out;
}
- if (id == AV_RL32("Adob") && (get_bits(&s->gb, 8) == 'e')) {
- if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(s->avctx, AV_LOG_INFO, "mjpeg: Adobe header found\n");
+ if (id == AV_RB32("Adob") && (get_bits(&s->gb, 8) == 'e')) {
skip_bits(&s->gb, 16); /* version */
skip_bits(&s->gb, 16); /* flags0 */
skip_bits(&s->gb, 16); /* flags1 */
- skip_bits(&s->gb, 8); /* transform */
+ s->adobe_transform = get_bits(&s->gb, 8);
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(s->avctx, AV_LOG_INFO, "mjpeg: Adobe header found, transform=%d\n", s->adobe_transform);
len -= 7;
goto out;
}
- if (id == AV_RL32("LJIF")) {
+ if (id == AV_RB32("LJIF")) {
+ int rgb = s->rgb;
+ int pegasus_rct = s->pegasus_rct;
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
av_log(s->avctx, AV_LOG_INFO,
"Pegasus lossless jpeg header found\n");
skip_bits(&s->gb, 16); /* version ? */
- skip_bits(&s->gb, 16); /* unknwon always 0? */
- skip_bits(&s->gb, 16); /* unknwon always 0? */
- skip_bits(&s->gb, 16); /* unknwon always 0? */
- switch (get_bits(&s->gb, 8)) {
+ skip_bits(&s->gb, 16); /* unknown always 0? */
+ skip_bits(&s->gb, 16); /* unknown always 0? */
+ skip_bits(&s->gb, 16); /* unknown always 0? */
+ switch (i=get_bits(&s->gb, 8)) {
case 1:
- s->rgb = 1;
- s->pegasus_rct = 0;
+ rgb = 1;
+ pegasus_rct = 0;
break;
case 2:
- s->rgb = 1;
- s->pegasus_rct = 1;
+ rgb = 1;
+ pegasus_rct = 1;
break;
default:
- av_log(s->avctx, AV_LOG_ERROR, "unknown colorspace\n");
+ av_log(s->avctx, AV_LOG_ERROR, "unknown colorspace %d\n", i);
}
+
len -= 9;
+ if (s->got_picture)
+ if (rgb != s->rgb || pegasus_rct != s->pegasus_rct) {
+ av_log(s->avctx, AV_LOG_WARNING, "Mismatching LJIF tag\n");
+ goto out;
+ }
+
+ s->rgb = rgb;
+ s->pegasus_rct = pegasus_rct;
+
+ goto out;
+ }
+ if (id == AV_RL32("colr") && len > 0) {
+ s->colr = get_bits(&s->gb, 8);
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(s->avctx, AV_LOG_INFO, "COLR %d\n", s->colr);
+ len --;
+ goto out;
+ }
+ if (id == AV_RL32("xfrm") && len > 0) {
+ s->xfrm = get_bits(&s->gb, 8);
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(s->avctx, AV_LOG_INFO, "XFRM %d\n", s->xfrm);
+ len --;
+ goto out;
+ }
+
+ /* JPS extension by VRex */
+ if (s->start_code == APP3 && id == AV_RB32("_JPS") && len >= 10) {
+ int flags, layout, type;
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(s->avctx, AV_LOG_INFO, "_JPSJPS_\n");
+
+ skip_bits(&s->gb, 32); len -= 4; /* JPS_ */
+ skip_bits(&s->gb, 16); len -= 2; /* block length */
+ skip_bits(&s->gb, 8); /* reserved */
+ flags = get_bits(&s->gb, 8);
+ layout = get_bits(&s->gb, 8);
+ type = get_bits(&s->gb, 8);
+ len -= 4;
+
+ s->stereo3d = av_stereo3d_alloc();
+ if (!s->stereo3d) {
+ goto out;
+ }
+ if (type == 0) {
+ s->stereo3d->type = AV_STEREO3D_2D;
+ } else if (type == 1) {
+ switch (layout) {
+ case 0x01:
+ s->stereo3d->type = AV_STEREO3D_LINES;
+ break;
+ case 0x02:
+ s->stereo3d->type = AV_STEREO3D_SIDEBYSIDE;
+ break;
+ case 0x03:
+ s->stereo3d->type = AV_STEREO3D_TOPBOTTOM;
+ break;
+ }
+ if (!(flags & 0x04)) {
+ s->stereo3d->flags = AV_STEREO3D_FLAG_INVERT;
+ }
+ }
+ goto out;
+ }
+
+ /* EXIF metadata */
+ if (s->start_code == APP1 && id == AV_RB32("Exif") && len >= 2) {
+ GetByteContext gbytes;
+ int ret, le, ifd_offset, bytes_read;
+ const uint8_t *aligned;
+
+ skip_bits(&s->gb, 16); // skip padding
+ len -= 2;
+
+ // init byte wise reading
+ aligned = align_get_bits(&s->gb);
+ bytestream2_init(&gbytes, aligned, len);
+
+ // read TIFF header
+ ret = ff_tdecode_header(&gbytes, &le, &ifd_offset);
+ if (ret) {
+ av_log(s->avctx, AV_LOG_ERROR, "mjpeg: invalid TIFF header in EXIF data\n");
+ } else {
+ bytestream2_seek(&gbytes, ifd_offset, SEEK_SET);
+
+ // read 0th IFD and store the metadata
+ // (return values > 0 indicate the presence of subimage metadata)
+ ret = avpriv_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "mjpeg: error decoding EXIF data\n");
+ }
+ }
+
+ bytes_read = bytestream2_tell(&gbytes);
+ skip_bits(&s->gb, bytes_read << 3);
+ len -= bytes_read;
+
goto out;
}
/* Apple MJPEG-A */
if ((s->start_code == APP1) && (len > (0x28 - 8))) {
id = get_bits_long(&s->gb, 32);
- id = av_be2ne32(id);
len -= 4;
/* Apple MJPEG-A */
- if (id == AV_RL32("mjpg")) {
+ if (id == AV_RB32("mjpg")) {
#if 0
skip_bits(&s->gb, 32); /* field size */
skip_bits(&s->gb, 32); /* pad field size */
@@ -1338,15 +1820,15 @@ static int mjpeg_decode_com(MJpegDecodeContext *s)
cbuf[i] = 0;
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(s->avctx, AV_LOG_INFO, "mjpeg comment: '%s'\n", cbuf);
+ av_log(s->avctx, AV_LOG_INFO, "comment: '%s'\n", cbuf);
/* buggy avid, it puts EOI only at every 10th frame */
- if (!strcmp(cbuf, "AVID")) {
- s->buggy_avid = 1;
+ if (!strncmp(cbuf, "AVID", 4)) {
+ parse_avid(s, cbuf, len);
} else if (!strcmp(cbuf, "CS=ITU601"))
s->cs_itu601 = 1;
- else if ((len > 20 && !strncmp(cbuf, "Intel(R) JPEG Library", 21)) ||
- (len > 19 && !strncmp(cbuf, "Metasoft MJPEG Codec", 20)))
+ else if ((!strncmp(cbuf, "Intel(R) JPEG Library, version 1", 32) && s->avctx->codec_tag) ||
+ (!strncmp(cbuf, "Metasoft MJPEG Codec", 20)))
s->flipped = 1;
av_free(cbuf);
@@ -1363,22 +1845,19 @@ static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end)
const uint8_t *buf_ptr;
unsigned int v, v2;
int val;
-#ifdef DEBUG
int skipped = 0;
-#endif
buf_ptr = *pbuf_ptr;
- while (buf_ptr < buf_end) {
+ while (buf_end - buf_ptr > 1) {
v = *buf_ptr++;
v2 = *buf_ptr;
if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe) && buf_ptr < buf_end) {
val = *buf_ptr++;
goto found;
}
-#ifdef DEBUG
skipped++;
-#endif
}
+ buf_ptr = buf_end;
val = -1;
found:
ff_dlog(NULL, "find_marker skipped %d bytes\n", skipped);
@@ -1424,7 +1903,7 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
memset(s->buffer + *unescaped_buf_size, 0,
FF_INPUT_BUFFER_PADDING_SIZE);
- av_log(s->avctx, AV_LOG_DEBUG, "escaping removed %td bytes\n",
+ av_log(s->avctx, AV_LOG_DEBUG, "escaping removed %"PTRDIFF_SPECIFIER" bytes\n",
(buf_end - *buf_ptr) - (dst - s->buffer));
} else if (start_code == SOS && s->ls) {
const uint8_t *src = *buf_ptr;
@@ -1433,8 +1912,6 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
int t = 0, b = 0;
PutBitContext pb;
- s->cur_scan++;
-
/* find marker */
while (src + t < buf_end) {
uint8_t x = src[t++];
@@ -1442,7 +1919,7 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
while ((src + t < buf_end) && x == 0xff)
x = src[t++];
if (x & 0x80) {
- t -= 2;
+ t -= FFMIN(2, t);
break;
}
}
@@ -1456,6 +1933,10 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s,
put_bits(&pb, 8, x);
if (x == 0xFF) {
x = src[b++];
+ if (x & 0x80) {
+ av_log(s->avctx, AV_LOG_WARNING, "Invalid escape sequence\n");
+ x &= 0x7f;
+ }
put_bits(&pb, 7, x);
bit_count--;
}
@@ -1483,11 +1964,17 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
MJpegDecodeContext *s = avctx->priv_data;
const uint8_t *buf_end, *buf_ptr;
const uint8_t *unescaped_buf_ptr;
+ int hshift, vshift;
int unescaped_buf_size;
int start_code;
+ int i, index;
int ret = 0;
+ int is16bit;
+
+ av_dict_free(&s->exif_metadata);
+ av_freep(&s->stereo3d);
+ s->adobe_transform = -1;
- s->got_picture = 0; // picture from previous image can not be reused
buf_ptr = buf;
buf_end = buf + buf_size;
while (buf_ptr < buf_end) {
@@ -1497,21 +1984,22 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
&unescaped_buf_size);
/* EOF */
if (start_code < 0) {
- goto the_end;
+ break;
} else if (unescaped_buf_size > INT_MAX / 8) {
av_log(avctx, AV_LOG_ERROR,
"MJPEG packet 0x%x too big (%d/%d), corrupt data?\n",
start_code, unescaped_buf_size, buf_size);
return AVERROR_INVALIDDATA;
}
-
- av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%td\n",
+ av_log(avctx, AV_LOG_DEBUG, "marker=%x avail_size_in_buf=%"PTRDIFF_SPECIFIER"\n",
start_code, buf_end - buf_ptr);
- ret = init_get_bits(&s->gb, unescaped_buf_ptr,
- unescaped_buf_size * 8);
- if (ret < 0)
- return ret;
+ ret = init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size);
+
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid buffer\n");
+ goto fail;
+ }
s->start_code = start_code;
if (s->avctx->debug & FF_DEBUG_STARTCODE)
@@ -1528,6 +2016,8 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
else if (start_code == COM)
mjpeg_decode_com(s);
+ ret = -1;
+
if (!CONFIG_JPEGLS_DECODER &&
(start_code == SOF48 || start_code == LSE)) {
av_log(avctx, AV_LOG_ERROR, "JPEG-LS support not enabled.\n");
@@ -1546,7 +2036,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
case DHT:
if ((ret = ff_mjpeg_decode_dht(s)) < 0) {
av_log(avctx, AV_LOG_ERROR, "huffman table decode error\n");
- return ret;
+ goto fail;
}
break;
case SOF0:
@@ -1555,39 +2045,37 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->ls = 0;
s->progressive = 0;
if ((ret = ff_mjpeg_decode_sof(s)) < 0)
- return ret;
+ goto fail;
break;
case SOF2:
s->lossless = 0;
s->ls = 0;
s->progressive = 1;
if ((ret = ff_mjpeg_decode_sof(s)) < 0)
- return ret;
+ goto fail;
break;
case SOF3:
s->lossless = 1;
s->ls = 0;
s->progressive = 0;
if ((ret = ff_mjpeg_decode_sof(s)) < 0)
- return ret;
+ goto fail;
break;
case SOF48:
s->lossless = 1;
s->ls = 1;
s->progressive = 0;
if ((ret = ff_mjpeg_decode_sof(s)) < 0)
- return ret;
+ goto fail;
break;
case LSE:
if (!CONFIG_JPEGLS_DECODER ||
(ret = ff_jpegls_decode_lse(s)) < 0)
- return ret;
+ goto fail;
break;
case EOI:
- s->cur_scan = 0;
- if ((s->buggy_avid && !s->interlaced) || s->restart_interval)
- break;
eoi_parser:
+ s->cur_scan = 0;
if (!s->got_picture) {
av_log(avctx, AV_LOG_WARNING,
"Found EOI before any SOF, ignoring\n");
@@ -1597,43 +2085,34 @@ eoi_parser:
s->bottom_field ^= 1;
/* if not bottom field, do not output image yet */
if (s->bottom_field == !s->interlace_polarity)
- goto not_the_end;
+ break;
}
if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0)
return ret;
- if (s->flipped) {
- int i;
- for (i = 0; frame->data[i]; i++) {
- int h = frame->height >> ((i == 1 || i == 2) ?
- s->pix_desc->log2_chroma_h : 0);
- frame->data[i] += frame->linesize[i] * (h - 1);
- frame->linesize[i] *= -1;
- }
- }
*got_frame = 1;
+ s->got_picture = 0;
+
+ if (!s->lossless) {
+ int qp = FFMAX3(s->qscale[0],
+ s->qscale[1],
+ s->qscale[2]);
+ int qpw = (s->width + 15) / 16;
+ AVBufferRef *qp_table_buf = av_buffer_alloc(qpw);
+ if (qp_table_buf) {
+ memset(qp_table_buf->data, qp, qpw);
+ av_frame_set_qp_table(data, qp_table_buf, 0, FF_QSCALE_TYPE_MPEG1);
+ }
- if (!s->lossless &&
- avctx->debug & FF_DEBUG_QP) {
- av_log(avctx, AV_LOG_DEBUG,
- "QP: %d\n", FFMAX3(s->qscale[0],
- s->qscale[1],
- s->qscale[2]));
+ if(avctx->debug & FF_DEBUG_QP)
+ av_log(avctx, AV_LOG_DEBUG, "QP: %d\n", qp);
}
goto the_end;
case SOS:
- if (!s->got_picture) {
- av_log(avctx, AV_LOG_WARNING,
- "Can not process SOS before SOF, skipping\n");
- break;
- }
- if ((ret = ff_mjpeg_decode_sos(s, NULL, NULL)) < 0 &&
+ s->cur_scan++;
+ if ((ret = ff_mjpeg_decode_sos(s, NULL, 0, NULL)) < 0 &&
(avctx->err_recognition & AV_EF_EXPLODE))
- return ret;
- /* buggy avid puts EOI every 10-20th frame */
- /* if restart period is over process EOI */
- if ((s->buggy_avid && !s->interlaced) || s->restart_interval)
- goto eoi_parser;
+ goto fail;
break;
case DRI:
mjpeg_decode_dri(s);
@@ -1653,21 +2132,201 @@ eoi_parser:
break;
}
-not_the_end:
/* eof process start code */
buf_ptr += (get_bits_count(&s->gb) + 7) / 8;
av_log(avctx, AV_LOG_DEBUG,
"marker parser used %d bytes (%d bits)\n",
(get_bits_count(&s->gb) + 7) / 8, get_bits_count(&s->gb));
}
- if (s->got_picture) {
+ if (s->got_picture && s->cur_scan) {
av_log(avctx, AV_LOG_WARNING, "EOI missing, emulating\n");
goto eoi_parser;
}
av_log(avctx, AV_LOG_FATAL, "No JPEG data found in image\n");
return AVERROR_INVALIDDATA;
+fail:
+ s->got_picture = 0;
+ return ret;
the_end:
- av_log(avctx, AV_LOG_DEBUG, "mjpeg decode frame unused %td bytes\n",
+
+ is16bit = av_pix_fmt_desc_get(s->avctx->pix_fmt)->comp[0].step_minus1;
+
+ if (AV_RB32(s->upscale_h)) {
+ int p;
+ av_assert0(avctx->pix_fmt == AV_PIX_FMT_YUVJ444P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV444P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVJ440P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV440P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVA444P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVJ420P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV420P16||
+ avctx->pix_fmt == AV_PIX_FMT_YUVA420P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVA420P16||
+ avctx->pix_fmt == AV_PIX_FMT_GBRP ||
+ avctx->pix_fmt == AV_PIX_FMT_GBRAP
+ );
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift);
+ for (p = 0; p<4; p++) {
+ uint8_t *line = s->picture_ptr->data[p];
+ int w = s->width;
+ int h = s->height;
+ if (!s->upscale_h[p])
+ continue;
+ if (p==1 || p==2) {
+ w = FF_CEIL_RSHIFT(w, hshift);
+ h = FF_CEIL_RSHIFT(h, vshift);
+ }
+ if (s->upscale_v[p])
+ h = (h+1)>>1;
+ av_assert0(w > 0);
+ for (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];
+ for (index = w - 2; index > 0; index--) {
+ if (is16bit)
+ ((uint16_t*)line)[index] = (((uint16_t*)line)[index / 2] + ((uint16_t*)line)[(index + 1) / 2]) >> 1;
+ else
+ line[index] = (line[index / 2] + line[(index + 1) / 2]) >> 1;
+ }
+ } else if (s->upscale_h[p] == 2) {
+ if (is16bit) {
+ ((uint16_t*)line)[w - 1] =
+ ((uint16_t*)line)[w - 2] = ((uint16_t*)line)[(w - 1) / 3];
+ } else {
+ line[w - 1] =
+ line[w - 2] = line[(w - 1) / 3];
+ }
+ for (index = w - 3; index > 0; index--) {
+ line[index] = (line[index / 3] + line[(index + 1) / 3] + line[(index + 2) / 3] + 1) / 3;
+ }
+ }
+ line += s->linesize[p];
+ }
+ }
+ }
+ if (AV_RB32(s->upscale_v)) {
+ int p;
+ av_assert0(avctx->pix_fmt == AV_PIX_FMT_YUVJ444P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV444P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVJ422P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV422P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVJ420P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV440P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVJ440P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVA444P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVA420P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVA420P16||
+ avctx->pix_fmt == AV_PIX_FMT_GBRP ||
+ avctx->pix_fmt == AV_PIX_FMT_GBRAP
+ );
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift);
+ for (p = 0; p < 4; p++) {
+ uint8_t *dst;
+ int w = s->width;
+ int h = s->height;
+ if (!s->upscale_v[p])
+ continue;
+ if (p==1 || p==2) {
+ w = FF_CEIL_RSHIFT(w, hshift);
+ h = FF_CEIL_RSHIFT(h, vshift);
+ }
+ dst = &((uint8_t *)s->picture_ptr->data[p])[(h - 1) * s->linesize[p]];
+ for (i = h - 1; i; i--) {
+ uint8_t *src1 = &((uint8_t *)s->picture_ptr->data[p])[i / 2 * s->linesize[p]];
+ uint8_t *src2 = &((uint8_t *)s->picture_ptr->data[p])[(i + 1) / 2 * s->linesize[p]];
+ if (src1 == src2 || i == h - 1) {
+ memcpy(dst, src1, w);
+ } else {
+ for (index = 0; index < w; index++)
+ dst[index] = (src1[index] + src2[index]) >> 1;
+ }
+ dst -= s->linesize[p];
+ }
+ }
+ }
+ if (s->flipped) {
+ int j;
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift);
+ for (index=0; index<4; index++) {
+ uint8_t *dst = s->picture_ptr->data[index];
+ int w = s->picture_ptr->width;
+ int h = s->picture_ptr->height;
+ if(index && index<3){
+ w = FF_CEIL_RSHIFT(w, hshift);
+ h = FF_CEIL_RSHIFT(h, vshift);
+ }
+ if(dst){
+ uint8_t *dst2 = dst + s->picture_ptr->linesize[index]*(h-1);
+ for (i=0; i<h/2; i++) {
+ for (j=0; j<w; j++)
+ FFSWAP(int, dst[j], dst2[j]);
+ dst += s->picture_ptr->linesize[index];
+ dst2 -= s->picture_ptr->linesize[index];
+ }
+ }
+ }
+ }
+ if (s->adobe_transform == 0 && s->avctx->pix_fmt == AV_PIX_FMT_GBRAP) {
+ int w = s->picture_ptr->width;
+ int h = s->picture_ptr->height;
+ for (i=0; i<h; i++) {
+ int j;
+ uint8_t *dst[4];
+ for (index=0; index<4; index++) {
+ dst[index] = s->picture_ptr->data[index]
+ + s->picture_ptr->linesize[index]*i;
+ }
+ for (j=0; j<w; j++) {
+ int k = dst[3][j];
+ int r = dst[0][j] * k;
+ int g = dst[1][j] * k;
+ int b = dst[2][j] * k;
+ dst[0][j] = g*257 >> 16;
+ dst[1][j] = b*257 >> 16;
+ dst[2][j] = r*257 >> 16;
+ dst[3][j] = 255;
+ }
+ }
+ }
+ if (s->adobe_transform == 2 && s->avctx->pix_fmt == AV_PIX_FMT_YUVA444P) {
+ int w = s->picture_ptr->width;
+ int h = s->picture_ptr->height;
+ for (i=0; i<h; i++) {
+ int j;
+ uint8_t *dst[4];
+ for (index=0; index<4; index++) {
+ dst[index] = s->picture_ptr->data[index]
+ + s->picture_ptr->linesize[index]*i;
+ }
+ for (j=0; j<w; j++) {
+ int k = dst[3][j];
+ int r = (255 - dst[0][j]) * k;
+ int g = (128 - dst[1][j]) * k;
+ int b = (128 - dst[2][j]) * k;
+ dst[0][j] = r*257 >> 16;
+ dst[1][j] = (g*257 >> 16) + 128;
+ dst[2][j] = (b*257 >> 16) + 128;
+ dst[3][j] = 255;
+ }
+ }
+ }
+
+ if (s->stereo3d) {
+ AVStereo3D *stereo = av_stereo3d_create_side_data(data);
+ if (stereo) {
+ stereo->type = s->stereo3d->type;
+ stereo->flags = s->stereo3d->flags;
+ }
+ av_freep(&s->stereo3d);
+ }
+
+ av_dict_copy(avpriv_frame_get_metadatap(data), s->exif_metadata, 0);
+ av_dict_free(&s->exif_metadata);
+
+ av_log(avctx, AV_LOG_DEBUG, "decode frame unused %"PTRDIFF_SPECIFIER" bytes\n",
buf_end - buf_ptr);
// return buf_end - buf_ptr;
return buf_ptr - buf;
@@ -1678,13 +2337,18 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
MJpegDecodeContext *s = avctx->priv_data;
int i, j;
+ if (s->interlaced && s->bottom_field == !s->interlace_polarity && s->got_picture && !avctx->frame_number) {
+ av_log(avctx, AV_LOG_INFO, "Single field\n");
+ }
+
if (s->picture) {
av_frame_free(&s->picture);
s->picture_ptr = NULL;
} else if (s->picture_ptr)
av_frame_unref(s->picture_ptr);
- av_free(s->buffer);
+ av_freep(&s->buffer);
+ av_freep(&s->stereo3d);
av_freep(&s->ljpeg_buffer);
s->ljpeg_buffer_size = 0;
@@ -1696,9 +2360,17 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx)
av_freep(&s->blocks[i]);
av_freep(&s->last_nnz[i]);
}
+ av_dict_free(&s->exif_metadata);
return 0;
}
+static void decode_flush(AVCodecContext *avctx)
+{
+ MJpegDecodeContext *s = avctx->priv_data;
+ s->got_picture = 0;
+}
+
+#if CONFIG_MJPEG_DECODER
#define OFFSET(x) offsetof(MJpegDecodeContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
@@ -1723,11 +2395,14 @@ AVCodec ff_mjpeg_decoder = {
.init = ff_mjpeg_decode_init,
.close = ff_mjpeg_decode_end,
.decode = ff_mjpeg_decode_frame,
+ .flush = decode_flush,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.priv_class = &mjpegdec_class,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
-
+#endif
+#if CONFIG_THP_DECODER
AVCodec ff_thp_decoder = {
.name = "thp",
.long_name = NULL_IF_CONFIG_SMALL("Nintendo Gamecube THP video"),
@@ -1737,6 +2412,9 @@ AVCodec ff_thp_decoder = {
.init = ff_mjpeg_decode_init,
.close = ff_mjpeg_decode_end,
.decode = ff_mjpeg_decode_frame,
+ .flush = decode_flush,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
+#endif
diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h
index aa4703a24d..28d3e4aa7d 100644
--- a/libavcodec/mjpegdec.h
+++ b/libavcodec/mjpegdec.h
@@ -4,20 +4,20 @@
* Copyright (c) 2003 Alex Beregszaszi
* Copyright (c) 2003-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "libavutil/log.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/stereo3d.h"
#include "avcodec.h"
#include "blockdsp.h"
@@ -61,14 +62,19 @@ typedef struct MJpegDecodeContext {
int ls;
int progressive;
int rgb;
+ uint8_t upscale_h[4];
+ uint8_t upscale_v[4];
int rct; /* standard rct */
int pegasus_rct; /* pegasus reversible colorspace transform */
int bits; /* bits per component */
+ int colr;
+ int xfrm;
+ int adobe_transform;
int maxval;
int near; ///< near lossless bound (si 0 for lossless)
int t1,t2,t3;
- int reset; ///< context halfing intervall ?rename
+ int reset; ///< context halfing interval ?rename
int width, height;
int mb_width, mb_height;
@@ -83,6 +89,7 @@ typedef struct MJpegDecodeContext {
int nb_blocks[MAX_COMPONENTS];
int h_scount[MAX_COMPONENTS];
int v_scount[MAX_COMPONENTS];
+ int quant_sindex[MAX_COMPONENTS];
int h_max, v_max; /* maximum h and v counts */
int quant_index[4]; /* quant table index for each component */
int last_dc[MAX_COMPONENTS]; /* last DEQUANTIZED dc (XXX: am I right to do that ?) */
@@ -95,6 +102,7 @@ typedef struct MJpegDecodeContext {
int16_t (*blocks[MAX_COMPONENTS])[64]; ///< intermediate sums (progressive mode)
uint8_t *last_nnz[MAX_COMPONENTS];
uint64_t coefs_finished[MAX_COMPONENTS]; ///< bitmask of which coefs have been completely decoded (progressive mode)
+ int palette_index;
ScanTable scantable;
BlockDSPContext bdsp;
HpelDSPContext hdsp;
@@ -116,6 +124,9 @@ typedef struct MJpegDecodeContext {
unsigned int ljpeg_buffer_size;
int extern_huff;
+ AVDictionary *exif_metadata;
+
+ AVStereo3D *stereo3d; ///!< stereoscopic information (cached, since it is read before frame allocation)
const AVPixFmtDescriptor *pix_desc;
} MJpegDecodeContext;
@@ -129,7 +140,8 @@ int ff_mjpeg_decode_dqt(MJpegDecodeContext *s);
int ff_mjpeg_decode_dht(MJpegDecodeContext *s);
int ff_mjpeg_decode_sof(MJpegDecodeContext *s);
int ff_mjpeg_decode_sos(MJpegDecodeContext *s,
- const uint8_t *mb_bitmask, const AVFrame *reference);
+ const uint8_t *mb_bitmask,int mb_bitmask_size,
+ const AVFrame *reference);
int ff_mjpeg_find_marker(MJpegDecodeContext *s,
const uint8_t **buf_ptr, const uint8_t *buf_end,
const uint8_t **unescaped_buf_ptr, int *unescaped_buf_size);
diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c
index 6724310d98..2188725e26 100644
--- a/libavcodec/mjpegenc.c
+++ b/libavcodec/mjpegenc.c
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,8 +30,6 @@
* MJPEG encoder.
*/
-#include <assert.h>
-
#include "libavutil/pixdesc.h"
#include "avcodec.h"
@@ -41,10 +39,44 @@
#include "mjpeg.h"
#include "mjpegenc.h"
+static uint8_t uni_ac_vlc_len[64 * 64 * 2];
+static uint8_t uni_chroma_ac_vlc_len[64 * 64 * 2];
+
+static av_cold void init_uni_ac_vlc(const uint8_t huff_size_ac[256], uint8_t *uni_ac_vlc_len)
+{
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ int level = i - 64;
+ int run;
+ if (!level)
+ continue;
+ for (run = 0; run < 64; run++) {
+ int len, code, nbits;
+ int alevel = FFABS(level);
+
+ len = (run >> 4) * huff_size_ac[0xf0];
+
+ nbits= av_log2_16bit(alevel) + 1;
+ code = ((15&run) << 4) | nbits;
+
+ len += huff_size_ac[code] + nbits;
+
+ uni_ac_vlc_len[UNI_AC_ENC_INDEX(run, i)] = len;
+ // We ignore EOB as its just a constant which does not change generally
+ }
+ }
+}
+
av_cold int ff_mjpeg_encode_init(MpegEncContext *s)
{
MJpegContext *m;
+ if (s->width > 65500 || s->height > 65500) {
+ av_log(s, AV_LOG_ERROR, "JPEG does not support resolutions above 65500x65500\n");
+ return AVERROR(EINVAL);
+ }
+
m = av_malloc(sizeof(MJpegContext));
if (!m)
return AVERROR(ENOMEM);
@@ -70,13 +102,20 @@ av_cold int ff_mjpeg_encode_init(MpegEncContext *s)
avpriv_mjpeg_bits_ac_chrominance,
avpriv_mjpeg_val_ac_chrominance);
+ init_uni_ac_vlc(m->huff_size_ac_luminance, uni_ac_vlc_len);
+ init_uni_ac_vlc(m->huff_size_ac_chrominance, uni_chroma_ac_vlc_len);
+ s->intra_ac_vlc_length =
+ s->intra_ac_vlc_last_length = uni_ac_vlc_len;
+ s->intra_chroma_ac_vlc_length =
+ s->intra_chroma_ac_vlc_last_length = uni_chroma_ac_vlc_len;
+
s->mjpeg_ctx = m;
return 0;
}
-void ff_mjpeg_encode_close(MpegEncContext *s)
+av_cold void ff_mjpeg_encode_close(MpegEncContext *s)
{
- av_free(s->mjpeg_ctx);
+ av_freep(&s->mjpeg_ctx);
}
static void encode_block(MpegEncContext *s, int16_t *block, int n)
@@ -122,7 +161,7 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n)
mant--;
}
- nbits= av_log2(val) + 1;
+ nbits= av_log2_16bit(val) + 1;
code = (run << 4) | nbits;
put_bits(&s->pb, huff_size_ac[code], huff_code_ac[code]);
@@ -137,23 +176,84 @@ static void encode_block(MpegEncContext *s, int16_t *block, int n)
put_bits(&s->pb, huff_size_ac[0], huff_code_ac[0]);
}
-void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[8][64])
+void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64])
{
int i;
- for(i=0;i<5;i++) {
- encode_block(s, block[i], i);
- }
- if (s->chroma_format == CHROMA_420) {
+ if (s->chroma_format == CHROMA_444) {
+ encode_block(s, block[0], 0);
+ encode_block(s, block[2], 2);
+ encode_block(s, block[4], 4);
+ encode_block(s, block[8], 8);
encode_block(s, block[5], 5);
+ encode_block(s, block[9], 9);
+
+ if (16*s->mb_x+8 < s->width) {
+ encode_block(s, block[1], 1);
+ encode_block(s, block[3], 3);
+ encode_block(s, block[6], 6);
+ encode_block(s, block[10], 10);
+ encode_block(s, block[7], 7);
+ encode_block(s, block[11], 11);
+ }
} else {
- encode_block(s, block[6], 6);
- encode_block(s, block[5], 5);
- encode_block(s, block[7], 7);
+ for(i=0;i<5;i++) {
+ encode_block(s, block[i], i);
+ }
+ if (s->chroma_format == CHROMA_420) {
+ encode_block(s, block[5], 5);
+ } else {
+ encode_block(s, block[6], 6);
+ encode_block(s, block[5], 5);
+ encode_block(s, block[7], 7);
+ }
}
s->i_tex_bits += get_bits_diff(s);
}
+// maximum over s->mjpeg_vsample[i]
+#define V_MAX 2
+static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic_arg, int *got_packet)
+
+{
+ MpegEncContext *s = avctx->priv_data;
+ 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);
+
+ //CODEC_FLAG_EMU_EDGE have to be cleared
+ if(s->avctx->flags & CODEC_FLAG_EMU_EDGE)
+ return AVERROR(EINVAL);
+
+ if ((avctx->height & 15) && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Heights which are not a multiple of 16 might fail with some decoders, "
+ "use vstrict=-1 / -strict -1 to use %d anyway.\n", avctx->height);
+ av_log(avctx, AV_LOG_WARNING, "If you have a device that plays AMV videos, please test if videos "
+ "with such heights work with it and report your findings to ffmpeg-devel@ffmpeg.org\n");
+ return AVERROR_EXPERIMENTAL;
+ }
+
+ pic = av_frame_clone(pic_arg);
+ if (!pic)
+ return AVERROR(ENOMEM);
+ //picture should be flipped upside-down
+ for(i=0; i < 3; i++) {
+ int vsample = i ? 2 >> chroma_v_shift : 2;
+ pic->data[i] += pic->linesize[i] * (vsample * s->height / V_MAX - 1);
+ pic->linesize[i] *= -1;
+ }
+ ret = ff_mpv_encode_picture(avctx, pkt, pic, got_packet);
+ av_frame_free(&pic);
+ return ret;
+}
+
+#if CONFIG_MJPEG_ENCODER
+FF_MPV_GENERIC_CLASS(mjpeg)
+
AVCodec ff_mjpeg_encoder = {
.name = "mjpeg",
.long_name = NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
@@ -163,7 +263,28 @@ AVCodec ff_mjpeg_encoder = {
.init = ff_mpv_encode_init,
.encode2 = ff_mpv_encode_picture,
.close = ff_mpv_encode_end,
+ .capabilities = CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .pix_fmts = (const enum AVPixelFormat[]){
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE
+ },
+ .priv_class = &mjpeg_class,
+};
+#endif
+#if CONFIG_AMV_ENCODER
+FF_MPV_GENERIC_CLASS(amv)
+
+AVCodec ff_amv_encoder = {
+ .name = "amv",
+ .long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AMV,
+ .priv_data_size = sizeof(MpegEncContext),
+ .init = ff_mpv_encode_init,
+ .encode2 = amv_encode_picture,
+ .close = ff_mpv_encode_end,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_NONE
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_NONE
},
+ .priv_class = &amv_class,
};
+#endif
diff --git a/libavcodec/mjpegenc.h b/libavcodec/mjpegenc.h
index aa8697edc8..4d77e166ee 100644
--- a/libavcodec/mjpegenc.h
+++ b/libavcodec/mjpegenc.h
@@ -8,20 +8,20 @@
* aspecting, new decode_frame mechanism and apple mjpeg-b support
* by Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,6 +59,6 @@ static inline void put_marker(PutBitContext *p, enum JpegMarker code)
int ff_mjpeg_encode_init(MpegEncContext *s);
void ff_mjpeg_encode_close(MpegEncContext *s);
-void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[8][64]);
+void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64]);
#endif /* AVCODEC_MJPEGENC_H */
diff --git a/libavcodec/mjpegenc_common.c b/libavcodec/mjpegenc_common.c
index d9a5eda370..daa5b6924d 100644
--- a/libavcodec/mjpegenc_common.c
+++ b/libavcodec/mjpegenc_common.c
@@ -1,20 +1,22 @@
/*
* lossless JPEG shared bits
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ * Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,20 +56,43 @@ static int put_huffman_table(PutBitContext *p, int table_class, int table_id,
return n + 17;
}
-static void jpeg_table_header(PutBitContext *p, ScanTable *intra_scantable,
- uint16_t intra_matrix[64])
+static void jpeg_table_header(AVCodecContext *avctx, PutBitContext *p,
+ ScanTable *intra_scantable,
+ uint16_t luma_intra_matrix[64],
+ uint16_t chroma_intra_matrix[64],
+ int hsample[3])
{
int i, j, size;
uint8_t *ptr;
+ if (avctx->codec_id != AV_CODEC_ID_LJPEG) {
+ int matrix_count = 1 + !!memcmp(luma_intra_matrix,
+ chroma_intra_matrix,
+ sizeof(luma_intra_matrix[0]) * 64);
/* quant matrixes */
put_marker(p, DQT);
- put_bits(p, 16, 2 + 1 * (1 + 64));
+ put_bits(p, 16, 2 + matrix_count * (1 + 64));
put_bits(p, 4, 0); /* 8 bit precision */
put_bits(p, 4, 0); /* table 0 */
for(i=0;i<64;i++) {
j = intra_scantable->permutated[i];
- put_bits(p, 8, intra_matrix[j]);
+ put_bits(p, 8, luma_intra_matrix[j]);
+ }
+
+ if (matrix_count > 1) {
+ put_bits(p, 4, 0); /* 8 bit precision */
+ put_bits(p, 4, 1); /* table 1 */
+ for(i=0;i<64;i++) {
+ j = intra_scantable->permutated[i];
+ put_bits(p, 8, chroma_intra_matrix[j]);
+ }
+ }
+ }
+
+ if(avctx->active_thread_type & FF_THREAD_SLICE){
+ put_marker(p, DRI);
+ put_bits(p, 16, 4);
+ put_bits(p, 16, (avctx->width-1)/(8*hsample[0]) + 1);
}
/* huffman table */
@@ -133,22 +158,22 @@ static void jpeg_put_comments(AVCodecContext *avctx, PutBitContext *p)
}
}
-void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb,
- ScanTable *intra_scantable,
- uint16_t intra_matrix[64])
+void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[3], int vsample[3])
{
int chroma_h_shift, chroma_v_shift;
- const int lossless = avctx->codec_id != AV_CODEC_ID_MJPEG;
- int hsample[3], vsample[3];
av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift,
&chroma_v_shift);
-
if (avctx->codec->id == AV_CODEC_ID_LJPEG &&
- avctx->pix_fmt == AV_PIX_FMT_BGR24) {
+ ( avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || avctx->pix_fmt == AV_PIX_FMT_BGR24)) {
vsample[0] = hsample[0] =
vsample[1] = hsample[1] =
vsample[2] = hsample[2] = 1;
+ } else if (avctx->pix_fmt == AV_PIX_FMT_YUV444P || avctx->pix_fmt == AV_PIX_FMT_YUVJ444P) {
+ vsample[0] = vsample[1] = vsample[2] = 2;
+ hsample[0] = hsample[1] = hsample[2] = 1;
} else {
vsample[0] = 2;
vsample[1] = 2 >> chroma_v_shift;
@@ -157,21 +182,41 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb,
hsample[1] = 2 >> chroma_h_shift;
hsample[2] = 2 >> chroma_h_shift;
}
+}
+
+void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb,
+ ScanTable *intra_scantable,
+ uint16_t luma_intra_matrix[64],
+ uint16_t chroma_intra_matrix[64])
+{
+ const int lossless = avctx->codec_id != AV_CODEC_ID_MJPEG && avctx->codec_id != AV_CODEC_ID_AMV;
+ int hsample[3], vsample[3];
+ int i;
+ int chroma_matrix = !!memcmp(luma_intra_matrix,
+ chroma_intra_matrix,
+ sizeof(luma_intra_matrix[0])*64);
+
+ ff_mjpeg_init_hvsample(avctx, hsample, vsample);
put_marker(pb, SOI);
+ // hack for AMV mjpeg format
+ if(avctx->codec_id == AV_CODEC_ID_AMV) goto end;
+
jpeg_put_comments(avctx, pb);
- jpeg_table_header(pb, intra_scantable, intra_matrix);
+ jpeg_table_header(avctx, pb, intra_scantable, luma_intra_matrix, chroma_intra_matrix, hsample);
switch (avctx->codec_id) {
case AV_CODEC_ID_MJPEG: put_marker(pb, SOF0 ); break;
case AV_CODEC_ID_LJPEG: put_marker(pb, SOF3 ); break;
- default: assert(0);
+ default: av_assert0(0);
}
put_bits(pb, 16, 17);
- if (lossless && avctx->pix_fmt == AV_PIX_FMT_BGR24)
+ if (lossless && ( avctx->pix_fmt == AV_PIX_FMT_BGR0
+ || avctx->pix_fmt == AV_PIX_FMT_BGRA
+ || avctx->pix_fmt == AV_PIX_FMT_BGR24))
put_bits(pb, 8, 9); /* 9 bits/component RCT */
else
put_bits(pb, 8, 8); /* 8 bits/component */
@@ -189,13 +234,13 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb,
put_bits(pb, 8, 2); /* component number */
put_bits(pb, 4, hsample[1]); /* H factor */
put_bits(pb, 4, vsample[1]); /* V factor */
- put_bits(pb, 8, 0); /* select matrix */
+ put_bits(pb, 8, lossless ? 0 : chroma_matrix); /* select matrix */
/* Cr component */
put_bits(pb, 8, 3); /* component number */
put_bits(pb, 4, hsample[2]); /* H factor */
put_bits(pb, 4, vsample[2]); /* V factor */
- put_bits(pb, 8, 0); /* select matrix */
+ put_bits(pb, 8, lossless ? 0 : chroma_matrix); /* select matrix */
/* scan header */
put_marker(pb, SOS);
@@ -222,20 +267,37 @@ void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb,
switch (avctx->codec_id) {
case AV_CODEC_ID_MJPEG: put_bits(pb, 8, 63); break; /* Se (not used) */
case AV_CODEC_ID_LJPEG: put_bits(pb, 8, 0); break; /* not used */
- default: assert(0);
+ default: av_assert0(0);
}
put_bits(pb, 8, 0); /* Ah/Al (not used) */
+
+end:
+ if (!lossless) {
+ MpegEncContext *s = avctx->priv_data;
+ av_assert0(avctx->codec->priv_data_size == sizeof(MpegEncContext));
+
+ s->esc_pos = put_bits_count(pb) >> 3;
+ for(i=1; i<s->slice_context_count; i++)
+ s->thread_context[i]->esc_pos = 0;
+ }
}
-static void escape_FF(PutBitContext *pb, int start)
+void ff_mjpeg_escape_FF(PutBitContext *pb, int start)
{
- int size = put_bits_count(pb) - start * 8;
+ int size;
int i, ff_count;
uint8_t *buf = pb->buf + start;
int align= (-(size_t)(buf))&3;
+ int pad = (-put_bits_count(pb))&7;
+
+ if (pad)
+ put_bits(pb, pad, (1<<pad)-1);
+
+ flush_put_bits(pb);
+ size = put_bits_count(pb) - start * 8;
- assert((size&7) == 0);
+ av_assert1((size&7) == 0);
size >>= 3;
ff_count=0;
@@ -280,21 +342,35 @@ static void escape_FF(PutBitContext *pb, int start)
}
}
-void ff_mjpeg_encode_stuffing(PutBitContext * pbc)
+int ff_mjpeg_encode_stuffing(MpegEncContext *s)
{
- int length;
- length= (-put_bits_count(pbc))&7;
- if(length) put_bits(pbc, length, (1<<length)-1);
+ int i;
+ PutBitContext *pbc = &s->pb;
+ int mb_y = s->mb_y - !s->mb_x;
+
+ int ret = ff_mpv_reallocate_putbitbuffer(s, put_bits_count(&s->pb) / 8 + 100,
+ put_bits_count(&s->pb) / 4 + 1000);
+ if (ret < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "Buffer reallocation failed\n");
+ goto fail;
+ }
+
+ ff_mjpeg_escape_FF(pbc, s->esc_pos);
+
+ if((s->avctx->active_thread_type & FF_THREAD_SLICE) && mb_y < s->mb_height)
+ put_marker(pbc, RST0 + (mb_y&7));
+ s->esc_pos = put_bits_count(pbc) >> 3;
+fail:
+
+ for(i=0; i<3; i++)
+ s->last_dc[i] = 128 << s->intra_dc_precision;
+
+ return ret;
}
void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits)
{
- ff_mjpeg_encode_stuffing(pb);
- flush_put_bits(pb);
-
- assert((header_bits & 7) == 0);
-
- escape_FF(pb, header_bits >> 3);
+ av_assert1((header_bits & 7) == 0);
put_marker(pb, EOI);
}
diff --git a/libavcodec/mjpegenc_common.h b/libavcodec/mjpegenc_common.h
index b48911e364..87f150550d 100644
--- a/libavcodec/mjpegenc_common.h
+++ b/libavcodec/mjpegenc_common.h
@@ -1,20 +1,20 @@
/*
* lossless JPEG shared bits
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,13 +25,18 @@
#include "avcodec.h"
#include "idctdsp.h"
+#include "mpegvideo.h"
#include "put_bits.h"
void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb,
ScanTable *intra_scantable,
- uint16_t intra_matrix[64]);
+ uint16_t luma_intra_matrix[64],
+ uint16_t chroma_intra_matrix[64]);
void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits);
-void ff_mjpeg_encode_stuffing(PutBitContext *pbc);
+void ff_mjpeg_escape_FF(PutBitContext *pb, int start);
+int ff_mjpeg_encode_stuffing(MpegEncContext *s);
+void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[3], int vsample[3]);
+
void ff_mjpeg_encode_dc(PutBitContext *pb, int val,
uint8_t *huff_size, uint16_t *huff_code);
diff --git a/libavcodec/mlp.c b/libavcodec/mlp.c
index 9615b66ee1..87f7c77139 100644
--- a/libavcodec/mlp.c
+++ b/libavcodec/mlp.c
@@ -2,20 +2,20 @@
* MLP codec common code
* Copyright (c) 2007-2008 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mlp.h b/libavcodec/mlp.h
index 8a1584e112..05d8dbaa61 100644
--- a/libavcodec/mlp.h
+++ b/libavcodec/mlp.h
@@ -2,20 +2,20 @@
* MLP codec common header file
* Copyright (c) 2007-2008 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c
index 0c7d4a2c7a..deaa844fc0 100644
--- a/libavcodec/mlp_parser.c
+++ b/libavcodec/mlp_parser.c
@@ -2,20 +2,20 @@
* MLP parser
* Copyright (c) 2007 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,28 +44,28 @@ static const uint8_t mlp_channels[32] = {
5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-static const uint64_t mlp_layout[32] = {
+const uint64_t ff_mlp_layout[32] = {
AV_CH_LAYOUT_MONO,
AV_CH_LAYOUT_STEREO,
AV_CH_LAYOUT_2_1,
- AV_CH_LAYOUT_2_2,
+ AV_CH_LAYOUT_QUAD,
AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY,
AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY,
- AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY,
+ AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY,
AV_CH_LAYOUT_SURROUND,
AV_CH_LAYOUT_4POINT0,
- AV_CH_LAYOUT_5POINT0,
+ AV_CH_LAYOUT_5POINT0_BACK,
AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY,
AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY,
- AV_CH_LAYOUT_5POINT1,
+ AV_CH_LAYOUT_5POINT1_BACK,
AV_CH_LAYOUT_4POINT0,
- AV_CH_LAYOUT_5POINT0,
+ AV_CH_LAYOUT_5POINT0_BACK,
AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY,
AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY,
- AV_CH_LAYOUT_5POINT1,
- AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY,
- AV_CH_LAYOUT_5POINT0,
- AV_CH_LAYOUT_5POINT1,
+ AV_CH_LAYOUT_5POINT1_BACK,
+ AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY,
+ AV_CH_LAYOUT_5POINT0_BACK,
+ AV_CH_LAYOUT_5POINT1_BACK,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
@@ -108,7 +108,7 @@ static int truehd_channels(int chanmap)
return channels;
}
-static uint64_t truehd_layout(int chanmap)
+uint64_t ff_truehd_layout(int chanmap)
{
int i;
uint64_t layout = 0;
@@ -147,7 +147,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
int ratebits, channel_arrangement, header_size;
uint16_t checksum;
- assert(get_bits_count(gb) == 0);
+ av_assert1(get_bits_count(gb) == 0);
header_size = ff_mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3);
if (header_size < 0 || gb->size_in_bits < header_size << 3) {
@@ -177,9 +177,10 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
skip_bits(gb, 11);
+ mh->channel_arrangement=
channel_arrangement = get_bits(gb, 5);
mh->channels_mlp = mlp_channels[channel_arrangement];
- mh->channel_layout_mlp = mlp_layout[channel_arrangement];
+ mh->channel_layout_mlp = ff_mlp_layout[channel_arrangement];
} else if (mh->stream_type == 0xba) {
mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere?
mh->group2_bits = 0;
@@ -193,15 +194,16 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
mh->channel_modifier_thd_stream0 = get_bits(gb, 2);
mh->channel_modifier_thd_stream1 = get_bits(gb, 2);
+ mh->channel_arrangement=
channel_arrangement = get_bits(gb, 5);
mh->channels_thd_stream1 = truehd_channels(channel_arrangement);
- mh->channel_layout_thd_stream1 = truehd_layout(channel_arrangement);
+ mh->channel_layout_thd_stream1 = ff_truehd_layout(channel_arrangement);
mh->channel_modifier_thd_stream2 = get_bits(gb, 2);
channel_arrangement = get_bits(gb, 13);
mh->channels_thd_stream2 = truehd_channels(channel_arrangement);
- mh->channel_layout_thd_stream2 = truehd_layout(channel_arrangement);
+ mh->channel_layout_thd_stream2 = ff_truehd_layout(channel_arrangement);
} else
return AVERROR_INVALIDDATA;
@@ -247,6 +249,7 @@ static int mlp_parse(AVCodecParserContext *s,
int sync_present;
uint8_t parity_bits;
int next;
+ int ret;
int i, p = 0;
*poutbuf_size = 0;
@@ -268,11 +271,15 @@ static int mlp_parse(AVCodecParserContext *s,
}
if (!mp->in_sync) {
- ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size);
+ if (ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size) != -1)
+ av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n");
return buf_size;
}
- ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size);
+ if ((ret = ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size)) < 0) {
+ av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n");
+ return ret;
+ }
return i - 7;
}
@@ -286,13 +293,17 @@ static int mlp_parse(AVCodecParserContext *s,
}
if (mp->pc.index + buf_size < 2) {
- ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size);
+ if (ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size) != -1)
+ av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n");
return buf_size;
}
mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8)
| (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]);
mp->bytes_left = (mp->bytes_left & 0xfff) * 2;
+ if (mp->bytes_left <= 0) { // prevent infinite loop
+ goto lost_sync;
+ }
mp->bytes_left -= mp->pc.index;
}
@@ -343,6 +354,7 @@ static int mlp_parse(AVCodecParserContext *s,
avctx->sample_rate = mh.group1_samplerate;
s->duration = mh.access_unit_size;
+ if(!avctx->channels || !avctx->channel_layout) {
if (mh.stream_type == 0xbb) {
/* MLP stream */
#if FF_API_REQUEST_CHANNELS
@@ -351,8 +363,8 @@ FF_DISABLE_DEPRECATION_WARNINGS
mh.num_substreams > 1) {
avctx->channels = 2;
avctx->channel_layout = AV_CH_LAYOUT_STEREO;
- } else
FF_ENABLE_DEPRECATION_WARNINGS
+ } else
#endif
if (avctx->request_channel_layout &&
(avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) ==
@@ -376,8 +388,8 @@ FF_DISABLE_DEPRECATION_WARNINGS
avctx->request_channels <= mh.channels_thd_stream1) {
avctx->channels = mh.channels_thd_stream1;
avctx->channel_layout = mh.channel_layout_thd_stream1;
- } else
FF_ENABLE_DEPRECATION_WARNINGS
+ } else
#endif
if (avctx->request_channel_layout &&
(avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) ==
@@ -396,6 +408,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
avctx->channel_layout = mh.channel_layout_thd_stream2;
}
}
+ }
if (!mh.is_vbr) /* Stream is CBR */
avctx->bit_rate = mh.peak_bitrate;
diff --git a/libavcodec/mlp_parser.h b/libavcodec/mlp_parser.h
index 06ab421ba9..0c0109efcc 100644
--- a/libavcodec/mlp_parser.h
+++ b/libavcodec/mlp_parser.h
@@ -2,20 +2,20 @@
* MLP parser prototypes
* Copyright (c) 2007 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,6 +40,8 @@ typedef struct MLPHeaderInfo
int group1_samplerate; ///< Sample rate of first substream
int group2_samplerate; ///< Sample rate of second substream (MLP only)
+ int channel_arrangement;
+
int channel_modifier_thd_stream0; ///< Channel modifier for substream 0 of TrueHD sreams ("2-channel presentation")
int channel_modifier_thd_stream1; ///< Channel modifier for substream 1 of TrueHD sreams ("6-channel presentation")
int channel_modifier_thd_stream2; ///< Channel modifier for substream 2 of TrueHD sreams ("8-channel presentation")
@@ -62,5 +64,8 @@ typedef struct MLPHeaderInfo
int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb);
+uint64_t ff_truehd_layout(int chanmap);
+
+extern const uint64_t ff_mlp_layout[32];
#endif /* AVCODEC_MLP_PARSER_H */
diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c
index a0b0b9646d..490d107e78 100644
--- a/libavcodec/mlpdec.c
+++ b/libavcodec/mlpdec.c
@@ -2,20 +2,20 @@
* MLP decoder
* Copyright (c) 2007-2008 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -105,7 +105,7 @@ typedef struct SubStream {
/// Whether the LSBs of the matrix output are encoded in the bitstream.
uint8_t lsb_bypass[MAX_MATRICES];
/// Matrix coefficients, stored as 2.14 fixed point.
- int32_t matrix_coeff[MAX_MATRICES][MAX_CHANNELS];
+ DECLARE_ALIGNED(32, int32_t, matrix_coeff)[MAX_MATRICES][MAX_CHANNELS];
/// Left shift to apply to noise values in 0x31eb substreams.
uint8_t matrix_noise_shift[MAX_MATRICES];
//@}
@@ -144,6 +144,9 @@ typedef struct MLPDecodeContext {
/// Index of the last substream to decode - further substreams are skipped.
uint8_t max_decoded_substream;
+ /// Stream needs channel reordering to comply with FFmpeg's channel order
+ uint8_t needs_reordering;
+
/// number of PCM samples contained in each frame
int access_unit_size;
/// next power of two above the number of samples in each frame
@@ -156,7 +159,7 @@ typedef struct MLPDecodeContext {
int8_t noise_buffer[MAX_BLOCKSIZE_POW2];
int8_t bypassed_lsbs[MAX_BLOCKSIZE][MAX_CHANNELS];
- int32_t sample_buffer[MAX_BLOCKSIZE][MAX_CHANNELS];
+ DECLARE_ALIGNED(32, int32_t, sample_buffer)[MAX_BLOCKSIZE][MAX_CHANNELS];
MLPDSPContext dsp;
} MLPDecodeContext;
@@ -380,10 +383,22 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
* substream is Stereo. Subsequent substreams' layouts are indicated in the
* major sync. */
if (m->avctx->codec_id == AV_CODEC_ID_MLP) {
+ if (mh.stream_type != 0xbb) {
+ avpriv_request_sample(m->avctx,
+ "unexpected stream_type %X in MLP",
+ mh.stream_type);
+ return AVERROR_PATCHWELCOME;
+ }
if ((substr = (mh.num_substreams > 1)))
m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO;
m->substream[substr].ch_layout = mh.channel_layout_mlp;
} else {
+ if (mh.stream_type != 0xba) {
+ avpriv_request_sample(m->avctx,
+ "unexpected stream_type %X in !MLP",
+ mh.stream_type);
+ return AVERROR_PATCHWELCOME;
+ }
if ((substr = (mh.num_substreams > 1)))
m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO;
if (mh.num_substreams > 2)
@@ -392,8 +407,17 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
else
m->substream[2].ch_layout = mh.channel_layout_thd_stream1;
m->substream[substr].ch_layout = mh.channel_layout_thd_stream1;
+
+ if (m->avctx->channels<=2 && m->substream[substr].ch_layout == AV_CH_LAYOUT_MONO && m->max_decoded_substream == 1) {
+ av_log(m->avctx, AV_LOG_DEBUG, "Mono stream with 2 substreams, ignoring 2nd\n");
+ m->max_decoded_substream = 0;
+ if (m->avctx->channels==2)
+ m->avctx->channel_layout = AV_CH_LAYOUT_STEREO;
+ }
}
+ m->needs_reordering = mh.channel_arrangement >= 18 && mh.channel_arrangement <= 20;
+
/* Parse the TrueHD decoder channel modifiers and set each substream's
* AVMatrixEncoding accordingly.
*
@@ -479,7 +503,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
if (max_matrix_channel > std_max_matrix_channel) {
av_log(m->avctx, AV_LOG_ERROR,
"Max matrix channel cannot be greater than %d.\n",
- max_matrix_channel);
+ std_max_matrix_channel);
return AVERROR_INVALIDDATA;
}
@@ -491,11 +515,11 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
/* This should happen for TrueHD streams with >6 channels and MLP's noise
* type. It is not yet known if this is allowed. */
- if (s->max_channel > MAX_MATRIX_CHANNEL_MLP && !s->noise_type) {
+ if (max_channel > MAX_MATRIX_CHANNEL_MLP && !s->noise_type) {
avpriv_request_sample(m->avctx,
"%d channels (more than the "
"maximum supported by the decoder)",
- s->max_channel + 2);
+ max_channel + 2);
return AVERROR_PATCHWELCOME;
}
@@ -519,8 +543,8 @@ FF_DISABLE_DEPRECATION_WARNINGS
"Further substreams will be skipped.\n",
s->max_channel + 1, substr);
m->max_decoded_substream = substr;
- } else
FF_ENABLE_DEPRECATION_WARNINGS
+ } else
#endif
if (m->avctx->request_channel_layout && (s->ch_layout & m->avctx->request_channel_layout) ==
m->avctx->request_channel_layout && m->max_decoded_substream > substr) {
@@ -603,6 +627,20 @@ FF_ENABLE_DEPRECATION_WARNINGS
s->output_shift,
s->max_matrix_channel,
m->avctx->sample_fmt == AV_SAMPLE_FMT_S32);
+
+ if (m->avctx->codec_id == AV_CODEC_ID_MLP && m->needs_reordering) {
+ if (m->avctx->channel_layout == (AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY) ||
+ m->avctx->channel_layout == AV_CH_LAYOUT_5POINT0_BACK) {
+ int i = s->ch_assign[4];
+ s->ch_assign[4] = s->ch_assign[3];
+ s->ch_assign[3] = s->ch_assign[2];
+ s->ch_assign[2] = i;
+ } else if (m->avctx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) {
+ FFSWAP(int, s->ch_assign[2], s->ch_assign[4]);
+ FFSWAP(int, s->ch_assign[3], s->ch_assign[5]);
+ }
+ }
+
}
return 0;
@@ -621,7 +659,7 @@ static int read_filter_params(MLPDecodeContext *m, GetBitContext *gbp,
int i, order;
// Filter is 0 for FIR, 1 for IIR.
- assert(filter < 2);
+ av_assert0(filter < 2);
if (m->filter_changed[channel][filter]++ > 1) {
av_log(m->avctx, AV_LOG_ERROR, "Filters may change only once per access unit.\n");
@@ -676,7 +714,7 @@ static int read_filter_params(MLPDecodeContext *m, GetBitContext *gbp,
/* TODO: Check validity of state data. */
for (i = 0; i < order; i++)
- fp->state[i] = get_sbits(gbp, state_bits) << state_shift;
+ fp->state[i] = state_bits ? get_sbits(gbp, state_bits) << state_shift : 0;
}
}
@@ -795,6 +833,7 @@ static int read_channel_params(MLPDecodeContext *m, unsigned int substr,
if (cp->huff_lsbs > 24) {
av_log(m->avctx, AV_LOG_ERROR, "Invalid huff_lsbs.\n");
+ cp->huff_lsbs = 0;
return AVERROR_INVALIDDATA;
}
@@ -821,7 +860,7 @@ static int read_decoding_params(MLPDecodeContext *m, GetBitContext *gbp,
if (get_bits1(gbp)) {
s->blocksize = get_bits(gbp, 9);
if (s->blocksize < 8 || s->blocksize > m->access_unit_size) {
- av_log(m->avctx, AV_LOG_ERROR, "Invalid blocksize.");
+ av_log(m->avctx, AV_LOG_ERROR, "Invalid blocksize.\n");
s->blocksize = 0;
return AVERROR_INVALIDDATA;
}
@@ -861,7 +900,7 @@ static int read_decoding_params(MLPDecodeContext *m, GetBitContext *gbp,
return 0;
}
-#define MSB_MASK(bits) (-1u << bits)
+#define MSB_MASK(bits) (-1u << (bits))
/** Generate PCM samples using the prediction filters and residual values
* read from the data stream, and update the filter state. */
@@ -999,15 +1038,27 @@ static void fill_noise_buffer(MLPDecodeContext *m, unsigned int substr)
s->noisegen_seed = seed;
}
+/** Write the audio data into the output buffer. */
-/** Apply the channel matrices in turn to reconstruct the original audio
- * samples. */
-
-static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
+static int output_data(MLPDecodeContext *m, unsigned int substr,
+ AVFrame *frame, int *got_frame_ptr)
{
+ AVCodecContext *avctx = m->avctx;
SubStream *s = &m->substream[substr];
unsigned int mat;
unsigned int maxchan;
+ int ret;
+ int is32 = (m->avctx->sample_fmt == AV_SAMPLE_FMT_S32);
+
+ if (m->avctx->channels != s->max_matrix_channel + 1) {
+ av_log(m->avctx, AV_LOG_ERROR, "channel count mismatch\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!s->blockpos) {
+ av_log(avctx, AV_LOG_ERROR, "No samples to output.\n");
+ return AVERROR_INVALIDDATA;
+ }
maxchan = s->max_matrix_channel;
if (!s->noise_type) {
@@ -1017,6 +1068,8 @@ static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
fill_noise_buffer(m, substr);
}
+ /* Apply the channel matrices in turn to reconstruct the original audio
+ * samples. */
for (mat = 0; mat < s->num_primitive_matrices; mat++) {
unsigned int dest_ch = s->matrix_out_ch[mat];
m->dsp.mlp_rematrix_channel(&m->sample_buffer[0][0],
@@ -1031,34 +1084,11 @@ static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
m->access_unit_size_pow2,
MSB_MASK(s->quant_step_size[dest_ch]));
}
-}
-
-/** Write the audio data into the output buffer. */
-
-static int output_data(MLPDecodeContext *m, unsigned int substr,
- AVFrame *frame, int *got_frame_ptr)
-{
- AVCodecContext *avctx = m->avctx;
- SubStream *s = &m->substream[substr];
- int ret;
- int is32 = (m->avctx->sample_fmt == AV_SAMPLE_FMT_S32);
-
- if (m->avctx->channels != s->max_matrix_channel + 1) {
- av_log(m->avctx, AV_LOG_ERROR, "channel count mismatch\n");
- return AVERROR_INVALIDDATA;
- }
-
- if (!s->blockpos) {
- av_log(avctx, AV_LOG_ERROR, "No samples to output.\n");
- return AVERROR_INVALIDDATA;
- }
/* get output buffer */
frame->nb_samples = s->blockpos;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
s->lossless_check_data = m->dsp.mlp_pack_output(s->lossless_check_data,
s->blockpos,
m->sample_buffer,
@@ -1098,7 +1128,7 @@ static int read_access_unit(AVCodecContext *avctx, void* data,
int ret;
if (buf_size < 4)
- return 0;
+ return AVERROR_INVALIDDATA;
length = (AV_RB16(buf) & 0xfff) * 2;
@@ -1261,8 +1291,6 @@ next_substr:
buf += substream_data_len[substr];
}
- rematrix_channels(m, m->max_decoded_substream);
-
if ((ret = output_data(m, m->max_decoded_substream, data, got_frame_ptr)) < 0)
return ret;
@@ -1277,6 +1305,7 @@ error:
return AVERROR_INVALIDDATA;
}
+#if CONFIG_MLP_DECODER
AVCodec ff_mlp_decoder = {
.name = "mlp",
.long_name = NULL_IF_CONFIG_SMALL("MLP (Meridian Lossless Packing)"),
@@ -1287,7 +1316,7 @@ AVCodec ff_mlp_decoder = {
.decode = read_access_unit,
.capabilities = CODEC_CAP_DR1,
};
-
+#endif
#if CONFIG_TRUEHD_DECODER
AVCodec ff_truehd_decoder = {
.name = "truehd",
diff --git a/libavcodec/mlpdsp.c b/libavcodec/mlpdsp.c
index aded554ea1..3ae8c37708 100644
--- a/libavcodec/mlpdsp.c
+++ b/libavcodec/mlpdsp.c
@@ -2,20 +2,20 @@
* Copyright (c) 2007-2008 Ian Caulfield
* 2009 Ramiro Polla
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mlpdsp.h b/libavcodec/mlpdsp.h
index acd48fc663..a0edeb7762 100644
--- a/libavcodec/mlpdsp.h
+++ b/libavcodec/mlpdsp.h
@@ -2,20 +2,20 @@
* MLP codec common header file
* Copyright (c) 2007-2008 Ian Caulfield
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c
index 76d26bcb9c..aa46621d06 100644
--- a/libavcodec/mmaldec.c
+++ b/libavcodec/mmaldec.c
@@ -2,20 +2,20 @@
* MMAL Video Decoder
* Copyright (c) 2015 Rodger Combs
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mmvideo.c b/libavcodec/mmvideo.c
index 25124a3edf..8b04965d59 100644
--- a/libavcodec/mmvideo.c
+++ b/libavcodec/mmvideo.c
@@ -2,20 +2,20 @@
* American Laser Games MM Video Decoder
* Copyright (c) 2006,2008 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,7 @@
typedef struct MmContext {
AVCodecContext *avctx;
AVFrame *frame;
- int palette[AVPALETTE_COUNT];
+ unsigned int palette[AVPALETTE_COUNT];
GetByteContext gb;
} MmContext;
@@ -75,17 +75,15 @@ static av_cold int mm_decode_init(AVCodecContext *avctx)
return 0;
}
-static int mm_decode_pal(MmContext *s)
+static void mm_decode_pal(MmContext *s)
{
int i;
bytestream2_skip(&s->gb, 4);
for (i = 0; i < 128; i++) {
- s->palette[i] = bytestream2_get_be24(&s->gb);
+ s->palette[i] = 0xFFU << 24 | bytestream2_get_be24(&s->gb);
s->palette[i+128] = s->palette[i]<<2;
}
-
- return 0;
}
/**
@@ -113,9 +111,12 @@ static int mm_decode_intra(MmContext * s, int half_horiz, int half_vert)
if (half_horiz)
run_length *=2;
+ if (run_length > s->avctx->width - x)
+ return AVERROR_INVALIDDATA;
+
if (color) {
memset(s->frame->data[0] + y*s->frame->linesize[0] + x, color, run_length);
- if (half_vert)
+ if (half_vert && y + half_vert < s->avctx->height)
memset(s->frame->data[0] + (y+1)*s->frame->linesize[0] + x, color, run_length);
}
x+= run_length;
@@ -129,7 +130,7 @@ static int mm_decode_intra(MmContext * s, int half_horiz, int half_vert)
return 0;
}
-/*
+/**
* @param half_horiz Half horizontal resolution (0 or 1)
* @param half_vert Half vertical resolution (0 or 1)
*/
@@ -200,13 +201,11 @@ static int mm_decode_frame(AVCodecContext *avctx,
buf_size -= MM_PREAMBLE_SIZE;
bytestream2_init(&s->gb, buf, buf_size);
- if ((res = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((res = ff_reget_buffer(avctx, s->frame)) < 0)
return res;
- }
switch(type) {
- case MM_TYPE_PALETTE : res = mm_decode_pal(s); return buf_size;
+ case MM_TYPE_PALETTE : mm_decode_pal(s); return avpkt->size;
case MM_TYPE_INTRA : res = mm_decode_intra(s, 0, 0); break;
case MM_TYPE_INTRA_HH : res = mm_decode_intra(s, 1, 0); break;
case MM_TYPE_INTRA_HHV : res = mm_decode_intra(s, 1, 1); break;
@@ -227,7 +226,7 @@ static int mm_decode_frame(AVCodecContext *avctx,
*got_frame = 1;
- return buf_size;
+ return avpkt->size;
}
static av_cold int mm_decode_end(AVCodecContext *avctx)
diff --git a/libavcodec/motion-test.c b/libavcodec/motion-test.c
new file mode 100644
index 0000000000..7cfe41cf6e
--- /dev/null
+++ b/libavcodec/motion-test.c
@@ -0,0 +1,152 @@
+/*
+ * (c) 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * motion test.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+#include "me_cmp.h"
+#include "libavutil/internal.h"
+#include "libavutil/lfg.h"
+#include "libavutil/mem.h"
+#include "libavutil/time.h"
+
+#undef printf
+
+#define WIDTH 64
+#define HEIGHT 64
+
+static uint8_t img1[WIDTH * HEIGHT];
+static uint8_t img2[WIDTH * HEIGHT];
+
+static void fill_random(uint8_t *tab, int size)
+{
+ int i;
+ AVLFG prng;
+
+ av_lfg_init(&prng, 1);
+ for(i=0;i<size;i++) {
+ tab[i] = av_lfg_get(&prng) % 256;
+ }
+}
+
+static void help(void)
+{
+ printf("motion-test [-h]\n"
+ "test motion implementations\n");
+}
+
+#define NB_ITS 500
+
+int dummy;
+
+static void test_motion(const char *name,
+ me_cmp_func test_func, me_cmp_func ref_func)
+{
+ int x, y, d1, d2, it;
+ uint8_t *ptr;
+ int64_t ti;
+ printf("testing '%s'\n", name);
+
+ /* test correctness */
+ for(it=0;it<20;it++) {
+
+ fill_random(img1, WIDTH * HEIGHT);
+ fill_random(img2, WIDTH * HEIGHT);
+
+ for(y=0;y<HEIGHT-17;y++) {
+ for(x=0;x<WIDTH-17;x++) {
+ ptr = img2 + y * WIDTH + x;
+ d1 = test_func(NULL, img1, ptr, WIDTH, 8);
+ d2 = ref_func(NULL, img1, ptr, WIDTH, 8);
+ if (d1 != d2) {
+ printf("error: mmx=%d c=%d\n", d1, d2);
+ }
+ }
+ }
+ }
+ emms_c();
+
+ /* speed test */
+ ti = av_gettime_relative();
+ d1 = 0;
+ for(it=0;it<NB_ITS;it++) {
+ for(y=0;y<HEIGHT-17;y++) {
+ for(x=0;x<WIDTH-17;x++) {
+ ptr = img2 + y * WIDTH + x;
+ d1 += test_func(NULL, img1, ptr, WIDTH, 8);
+ }
+ }
+ }
+ emms_c();
+ dummy = d1; /* avoid optimization */
+ ti = av_gettime_relative() - ti;
+
+ printf(" %0.0f kop/s\n",
+ (double)NB_ITS * (WIDTH - 16) * (HEIGHT - 16) /
+ (double)(ti / 1000.0));
+}
+
+
+int main(int argc, char **argv)
+{
+ AVCodecContext *ctx;
+ int c;
+ MECmpContext cctx, mmxctx;
+ int flags[2] = { AV_CPU_FLAG_MMX, AV_CPU_FLAG_MMXEXT };
+ int flags_size = HAVE_MMXEXT ? 2 : 1;
+
+ if (argc > 1) {
+ help();
+ return 1;
+ }
+
+ printf("ffmpeg motion test\n");
+
+ ctx = avcodec_alloc_context3(NULL);
+ ctx->flags |= 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++) {
+ printf("%s for %dx%d pixels\n", c ? "mmx2" : "mmx",
+ x ? 8 : 16, x ? 8 : 16);
+ test_motion("mmx", mmxctx.pix_abs[x][0], cctx.pix_abs[x][0]);
+ test_motion("mmx_x2", mmxctx.pix_abs[x][1], cctx.pix_abs[x][1]);
+ test_motion("mmx_y2", mmxctx.pix_abs[x][2], cctx.pix_abs[x][2]);
+ test_motion("mmx_xy2", mmxctx.pix_abs[x][3], cctx.pix_abs[x][3]);
+ }
+ }
+ av_free(ctx);
+
+ return 0;
+}
diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c
index c51be8d89e..ed226c5d73 100644
--- a/libavcodec/motion_est.c
+++ b/libavcodec/motion_est.c
@@ -5,20 +5,20 @@
*
* new motion estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,9 +37,6 @@
#include "mpegutils.h"
#include "mpegvideo.h"
-#undef NDEBUG
-#include <assert.h>
-
#define P_LEFT P[1]
#define P_TOP P[2]
#define P_TOPRIGHT P[3]
@@ -117,7 +114,7 @@ static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, co
uint8_t * const * const src= c->src[src_index];
int d;
//FIXME check chroma 4mv, (no crashes ...)
- assert(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1));
+ av_assert2(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1));
if(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)){
const int time_pp= s->pp_time;
const int time_pb= s->pb_time;
@@ -159,14 +156,14 @@ static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, co
c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride);
c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride);
}else{
- assert((fx>>1) + 16*s->mb_x >= -16);
- assert((fy>>1) + 16*s->mb_y >= -16);
- assert((fx>>1) + 16*s->mb_x <= s->width);
- assert((fy>>1) + 16*s->mb_y <= s->height);
- assert((bx>>1) + 16*s->mb_x >= -16);
- assert((by>>1) + 16*s->mb_y >= -16);
- assert((bx>>1) + 16*s->mb_x <= s->width);
- assert((by>>1) + 16*s->mb_y <= s->height);
+ av_assert2((fx>>1) + 16*s->mb_x >= -16);
+ av_assert2((fy>>1) + 16*s->mb_y >= -16);
+ av_assert2((fx>>1) + 16*s->mb_x <= s->width);
+ av_assert2((fy>>1) + 16*s->mb_y <= s->height);
+ av_assert2((bx>>1) + 16*s->mb_x >= -16);
+ av_assert2((by>>1) + 16*s->mb_y >= -16);
+ av_assert2((bx>>1) + 16*s->mb_x <= s->width);
+ av_assert2((by>>1) + 16*s->mb_y <= s->height);
c->hpel_put[0][fxy](c->temp, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 16);
c->hpel_avg[0][bxy](c->temp, ref[8] + (bx>>1) + (by>>1)*stride, stride, 16);
@@ -194,7 +191,13 @@ static av_always_inline int cmp_inline(MpegEncContext *s, const int x, const int
int uvdxy; /* no, it might not be used uninitialized */
if(dxy){
if(qpel){
- c->qpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride); //FIXME prototype (add h)
+ if (h << size == 16) {
+ c->qpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride); //FIXME prototype (add h)
+ } else if (size == 0 && h == 8) {
+ c->qpel_put[1][dxy](c->temp , ref[0] + x + y*stride , stride);
+ c->qpel_put[1][dxy](c->temp + 8, ref[0] + x + y*stride + 8, stride);
+ } else
+ av_assert2(0);
if(chroma){
int cx= hx/2;
int cy= hy/2;
@@ -304,19 +307,21 @@ int ff_init_me(MpegEncContext *s){
int cache_size= FFMIN(ME_MAP_SIZE>>ME_MAP_SHIFT, 1<<ME_MAP_SHIFT);
int dia_size= FFMAX(FFABS(s->avctx->dia_size)&255, FFABS(s->avctx->pre_dia_size)&255);
- if(FFMIN(s->avctx->dia_size, s->avctx->pre_dia_size) < -ME_MAP_SIZE){
+ 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 (s->me_method != ME_ZERO &&
- s->me_method != ME_EPZS &&
- s->me_method != ME_X1) {
+ //special case of snow is needed because snow uses its own iterative ME code
+ if(s->me_method!=ME_ZERO && s->me_method!=ME_EPZS && s->me_method!=ME_X1 && s->avctx->codec_id != AV_CODEC_ID_SNOW){
av_log(s->avctx, AV_LOG_ERROR, "me_method is only allowed to be set to zero and epzs; for hex,umh,full and others see dia_size\n");
return -1;
}
c->avctx= s->avctx;
+ if(s->codec_id == AV_CODEC_ID_H261)
+ c->avctx->me_sub_cmp = c->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");
}
@@ -365,12 +370,14 @@ int ff_init_me(MpegEncContext *s){
/* 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 ((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_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;
@@ -396,10 +403,9 @@ static int sad_hpel_motion_search(MpegEncContext * s,
int mx, my, dminh;
uint8_t *pix, *ptr;
int stride= c->stride;
- const int flags= c->sub_flags;
LOAD_COMMON
- assert(flags == 0);
+ av_assert2(c->sub_flags == 0);
if(c->skip){
*mx_ptr = 0;
@@ -523,6 +529,7 @@ static inline void get_limits(MpegEncContext *s, int x, int y)
{
MotionEstContext * const c= &s->me;
int range= c->avctx->me_range >> (1 + !!(c->flags&FLAG_QPEL));
+ int max_range = MAX_MV >> (1 + !!(c->flags&FLAG_QPEL));
/*
if(c->avctx->me_range) c->range= c->avctx->me_range >> 1;
else c->range= 16;
@@ -530,8 +537,8 @@ static inline void get_limits(MpegEncContext *s, int x, int y)
if (s->unrestricted_mv) {
c->xmin = - x - 16;
c->ymin = - y - 16;
- c->xmax = - x + s->mb_width *16;
- c->ymax = - y + s->mb_height*16;
+ c->xmax = - x + s->width;
+ c->ymax = - y + s->height;
} else if (s->out_format == FMT_H261){
// Search range of H261 is different from other codec standards
c->xmin = (x > 15) ? - 15 : 0;
@@ -544,6 +551,8 @@ static inline void get_limits(MpegEncContext *s, int x, int y)
c->xmax = - x + s->mb_width *16 - 16;
c->ymax = - y + s->mb_height*16 - 16;
}
+ if(!range || range > max_range)
+ range = max_range;
if(range){
c->xmin = FFMAX(c->xmin,-range);
c->xmax = FFMIN(c->xmax, range);
@@ -570,10 +579,11 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift)
const int h=8;
int block;
int P[10][2];
- int dmin_sum=0, mx4_sum=0, my4_sum=0;
+ int dmin_sum=0, mx4_sum=0, my4_sum=0, i;
int same=1;
const int stride= c->stride;
uint8_t *mv_penalty= c->current_mv_penalty;
+ int saftey_cliping= s->unrestricted_mv && (s->width&15) && (s->height&15);
init_mv4_ref(c);
@@ -585,6 +595,11 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift)
const int mot_stride = s->b8_stride;
const int mot_xy = s->block_index[block];
+ if(saftey_cliping){
+ c->xmax = - 16*s->mb_x + s->width - 8*(block &1);
+ 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];
@@ -612,6 +627,15 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift)
}
P_MV1[0]= mx;
P_MV1[1]= my;
+ if(saftey_cliping)
+ for(i=1; i<10; i++){
+ if (s->first_slice_line && block<2 && i>1 && i<9)
+ continue;
+ if (i>4 && i<9)
+ continue;
+ if(P[i][0] > (c->xmax<<shift)) P[i][0]= (c->xmax<<shift);
+ if(P[i][1] > (c->ymax<<shift)) P[i][1]= (c->ymax<<shift);
+ }
dmin4 = epzs_motion_search4(s, &mx4, &my4, P, block, block, s->p_mv_table, (1<<16)>>shift);
@@ -746,8 +770,8 @@ static int interlaced_search(MpegEncContext *s, int ref_index,
int16_t (*mv_table)[2]= mv_tables[block][field_select];
if(user_field_select){
- assert(field_select==0 || field_select==1);
- assert(field_select_tables[block][xy]==0 || field_select_tables[block][xy]==1);
+ av_assert1(field_select==0 || field_select==1);
+ av_assert1(field_select_tables[block][xy]==0 || field_select_tables[block][xy]==1);
if(field_select_tables[block][xy] != field_select)
continue;
}
@@ -844,6 +868,10 @@ static inline int get_penalty_factor(int lambda, int lambda2, int type){
return lambda>>FF_LAMBDA_SHIFT;
case FF_CMP_DCT:
return (3*lambda)>>(FF_LAMBDA_SHIFT+1);
+ case FF_CMP_W53:
+ return (4*lambda)>>(FF_LAMBDA_SHIFT);
+ case FF_CMP_W97:
+ return (2*lambda)>>(FF_LAMBDA_SHIFT);
case FF_CMP_SATD:
case FF_CMP_DCT264:
return (2*lambda)>>FF_LAMBDA_SHIFT;
@@ -872,9 +900,9 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
init_ref(c, s->new_picture.f->data, s->last_picture.f->data, NULL, 16*mb_x, 16*mb_y, 0);
- assert(s->quarter_sample==0 || s->quarter_sample==1);
- assert(s->linesize == c->stride);
- assert(s->uvlinesize == c->uvstride);
+ av_assert0(s->quarter_sample==0 || s->quarter_sample==1);
+ av_assert0(s->linesize == c->stride);
+ av_assert0(s->uvlinesize == c->uvstride);
c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp);
c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp);
@@ -1052,7 +1080,7 @@ int ff_pre_estimate_p_frame_motion(MpegEncContext * s,
const int xy= mb_x + mb_y*s->mb_stride;
init_ref(c, s->new_picture.f->data, s->last_picture.f->data, NULL, 16*mb_x, 16*mb_y, 0);
- assert(s->quarter_sample==0 || s->quarter_sample==1);
+ 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_MV;
@@ -1430,7 +1458,7 @@ static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y)
if(s->mv_type == MV_TYPE_16X16) break;
}
- assert(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16);
+ av_assert2(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16);
if(xmax < 0 || xmin >0 || ymax < 0 || ymin > 0){
s->b_direct_mv_table[mot_xy][0]= 0;
@@ -1647,12 +1675,12 @@ void ff_fix_long_p_mvs(MpegEncContext * s)
MotionEstContext * const c= &s->me;
const int f_code= s->f_code;
int y, range;
- assert(s->pict_type==AV_PICTURE_TYPE_P);
+ av_assert0(s->pict_type==AV_PICTURE_TYPE_P);
range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version) ? 8 : 16) << f_code);
- assert(range <= 16 || !s->msmpeg4_version);
- assert(range <=256 || !(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL));
+ av_assert0(range <= 16 || !s->msmpeg4_version);
+ 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;
diff --git a/libavcodec/motion_est_template.c b/libavcodec/motion_est_template.c
index 01936c6a83..ae2cbdea4d 100644
--- a/libavcodec/motion_est_template.c
+++ b/libavcodec/motion_est_template.c
@@ -2,20 +2,20 @@
* Motion estimation
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -91,19 +91,18 @@ static int hpel_motion_search(MpegEncContext * s,
const int b= score_map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)]
+ (mv_penalty[bx - pred_x] + mv_penalty[by+2 - pred_y])*c->penalty_factor;
+#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1
unsigned key;
unsigned map_generation= c->map_generation;
-#ifndef NDEBUG
- uint32_t *map= c->map;
-#endif
key= ((my-1)<<ME_MAP_MV_BITS) + (mx) + map_generation;
- assert(map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
+ av_assert2(c->map[(index-(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
key= ((my+1)<<ME_MAP_MV_BITS) + (mx) + map_generation;
- assert(map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
+ av_assert2(c->map[(index+(1<<ME_MAP_SHIFT))&(ME_MAP_SIZE-1)] == key);
key= ((my)<<ME_MAP_MV_BITS) + (mx+1) + map_generation;
- assert(map[(index+1)&(ME_MAP_SIZE-1)] == key);
+ av_assert2(c->map[(index+1)&(ME_MAP_SIZE-1)] == key);
key= ((my)<<ME_MAP_MV_BITS) + (mx-1) + map_generation;
- assert(map[(index-1)&(ME_MAP_SIZE-1)] == key);
+ av_assert2(c->map[(index-1)&(ME_MAP_SIZE-1)] == key);
+#endif
if(t<=b){
CHECK_HALF_MV(0, 1, mx ,my-1)
if(l<=r){
@@ -143,7 +142,7 @@ static int hpel_motion_search(MpegEncContext * s,
}
CHECK_HALF_MV(0, 1, mx , my)
}
- assert(bx >= xmin*2 && bx <= xmax*2 && by >= ymin*2 && by <= ymax*2);
+ av_assert2(bx >= xmin*2 && bx <= xmax*2 && by >= ymin*2 && by <= ymax*2);
}
*mx_ptr = bx;
@@ -181,9 +180,6 @@ static inline int get_mb_score(MpegEncContext *s, int mx, int my,
cmp_sub = s->mecc.mb_cmp[size];
chroma_cmp_sub = s->mecc.mb_cmp[size + 1];
-// assert(!c->skip);
-// assert(c->avctx->me_sub_cmp != c->avctx->mb_cmp);
-
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
if(add_rate && (mx || my || size>0))
@@ -310,11 +306,11 @@ static int qpel_motion_search(MpegEncContext * s,
cxy= 2*tl + (cx + cy)/4 - (cx2 + cy2) - 2*c;
- assert(16*cx2 + 4*cx + 32*c == 32*r);
- assert(16*cx2 - 4*cx + 32*c == 32*l);
- assert(16*cy2 + 4*cy + 32*c == 32*b);
- assert(16*cy2 - 4*cy + 32*c == 32*t);
- assert(16*cxy + 16*cy2 + 16*cx2 - 4*cy - 4*cx + 32*c == 32*tl);
+ av_assert2(16*cx2 + 4*cx + 32*c == 32*r);
+ av_assert2(16*cx2 - 4*cx + 32*c == 32*l);
+ av_assert2(16*cy2 + 4*cy + 32*c == 32*b);
+ av_assert2(16*cy2 - 4*cy + 32*c == 32*t);
+ av_assert2(16*cxy + 16*cy2 + 16*cx2 - 4*cy - 4*cx + 32*c == 32*tl);
for(ny= -3; ny <= 3; ny++){
for(nx= -3; nx <= 3; nx++){
@@ -347,7 +343,7 @@ static int qpel_motion_search(MpegEncContext * s,
CHECK_QUARTER_MV(nx&3, ny&3, nx>>2, ny>>2)
}
- assert(bx >= xmin*4 && bx <= xmax*4 && by >= ymin*4 && by <= ymax*4);
+ av_assert2(bx >= xmin*4 && bx <= xmax*4 && by >= ymin*4 && by <= ymax*4);
*mx_ptr = bx;
*my_ptr = by;
@@ -364,10 +360,10 @@ static int qpel_motion_search(MpegEncContext * s,
{\
const unsigned key = ((y)<<ME_MAP_MV_BITS) + (x) + map_generation;\
const int index= (((y)<<ME_MAP_SHIFT) + (x))&(ME_MAP_SIZE-1);\
- assert((x) >= xmin);\
- assert((x) <= xmax);\
- assert((y) >= ymin);\
- assert((y) <= ymax);\
+ av_assert2((x) >= xmin);\
+ av_assert2((x) <= xmax);\
+ av_assert2((y) >= ymin);\
+ av_assert2((y) <= ymax);\
if(map[index]!=key){\
d= cmp(s, x, y, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);\
map[index]= key;\
@@ -405,10 +401,10 @@ static int qpel_motion_search(MpegEncContext * s,
}
#define check(x,y,S,v)\
-if( (x)<(xmin<<(S)) ) printf("%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\
-if( (x)>(xmax<<(S)) ) printf("%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\
-if( (y)<(ymin<<(S)) ) printf("%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\
-if( (y)>(ymax<<(S)) ) printf("%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\
+if( (x)<(xmin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmin" #v, xmin, (x), (y), s->mb_x, s->mb_y);\
+if( (x)>(xmax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d xmax" #v, xmax, (x), (y), s->mb_x, s->mb_y);\
+if( (y)<(ymin<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymin" #v, ymin, (x), (y), s->mb_x, s->mb_y);\
+if( (y)>(ymax<<(S)) ) av_log(NULL, AV_LOG_ERROR, "%d %d %d %d %d ymax" #v, ymax, (x), (y), s->mb_x, s->mb_y);\
#define LOAD_COMMON2\
uint32_t *map= c->map;\
@@ -693,6 +689,8 @@ static int sab_diamond_search(MpegEncContext * s, int *best, int dmin,
LOAD_COMMON2
unsigned map_generation = c->map_generation;
+ av_assert1(minima_count <= MAX_SAB_SIZE);
+
cmpf = s->mecc.me_cmp[size];
chroma_cmpf = s->mecc.me_cmp[size + 1];
@@ -889,7 +887,7 @@ static av_always_inline int epzs_motion_search_internal(MpegEncContext * s, int
map_generation= update_map_generation(c);
- assert(cmpf);
+ av_assert2(cmpf);
dmin= cmp(s, 0, 0, 0, 0, size, h, ref_index, src_index, cmpf, chroma_cmpf, flags);
map[0]= map_generation;
score_map[0]= dmin;
diff --git a/libavcodec/motionpixels.c b/libavcodec/motionpixels.c
index c8cf00b69c..84517f990a 100644
--- a/libavcodec/motionpixels.c
+++ b/libavcodec/motionpixels.c
@@ -2,20 +2,20 @@
* Motion Pixels Video Decoder
* Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,13 +69,24 @@ static av_cold int mp_decode_init(AVCodecContext *avctx)
int w4 = (avctx->width + 3) & ~3;
int h4 = (avctx->height + 3) & ~3;
+ if(avctx->extradata_size < 2){
+ av_log(avctx, AV_LOG_ERROR, "extradata too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
motionpixels_tableinit();
mp->avctx = avctx;
ff_bswapdsp_init(&mp->bdsp);
- mp->changes_map = av_mallocz(avctx->width * h4);
+ mp->changes_map = av_mallocz_array(avctx->width, h4);
mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1;
- mp->vpt = av_mallocz(avctx->height * sizeof(YuvPixel));
- mp->hpt = av_mallocz(h4 * w4 / 16 * sizeof(YuvPixel));
+ mp->vpt = av_mallocz_array(avctx->height, sizeof(YuvPixel));
+ mp->hpt = av_mallocz_array(h4 / 4, w4 / 4 * sizeof(YuvPixel));
+ if (!mp->changes_map || !mp->vpt || !mp->hpt) {
+ av_freep(&mp->changes_map);
+ av_freep(&mp->vpt);
+ av_freep(&mp->hpt);
+ return AVERROR(ENOMEM);
+ }
avctx->pix_fmt = AV_PIX_FMT_RGB555;
mp->frame = av_frame_alloc();
@@ -116,38 +127,48 @@ static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int
}
}
-static void mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code)
+static int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code)
{
while (get_bits1(gb)) {
++size;
if (size > mp->max_codes_bits) {
av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
- return;
+ return AVERROR_INVALIDDATA;
}
code <<= 1;
- mp_get_code(mp, gb, size, code + 1);
+ if (mp_get_code(mp, gb, size, code + 1) < 0)
+ return AVERROR_INVALIDDATA;
}
if (mp->current_codes_count >= MAX_HUFF_CODES) {
av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
- return;
+ return AVERROR_INVALIDDATA;
}
+
mp->codes[mp->current_codes_count ].code = code;
mp->codes[mp->current_codes_count++].size = size;
+ return 0;
}
-static void mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
+static int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
{
if (mp->codes_count == 1) {
mp->codes[0].delta = get_bits(gb, 4);
} else {
int i;
+ int ret;
mp->max_codes_bits = get_bits(gb, 4);
for (i = 0; i < mp->codes_count; ++i)
mp->codes[i].delta = get_bits(gb, 4);
mp->current_codes_count = 0;
- mp_get_code(mp, gb, 0, 0);
+ if ((ret = mp_get_code(mp, gb, 0, 0)) < 0)
+ return ret;
+ if (mp->current_codes_count < mp->codes_count) {
+ av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n");
+ return AVERROR_INVALIDDATA;
+ }
}
+ return 0;
}
static int mp_gradient(MotionPixelsContext *mp, int component, int v)
@@ -180,7 +201,6 @@ static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb)
int i;
i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1);
- i = FFMIN(i, FF_ARRAY_ELEMS(mp->codes) - 1);
return mp->codes[i].delta;
}
@@ -236,6 +256,8 @@ static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb)
YuvPixel p;
int y, y0;
+ av_assert1(mp->changes_map[0]);
+
for (y = 0; y < mp->avctx->height; ++y) {
if (mp->changes_map[y * mp->avctx->width] != 0) {
memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
@@ -268,20 +290,17 @@ static int mp_decode_frame(AVCodecContext *avctx,
GetBitContext gb;
int i, count1, count2, sz, ret;
- if ((ret = ff_reget_buffer(avctx, mp->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, mp->frame)) < 0)
return ret;
- }
/* le32 bitstream msb first */
- av_fast_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size);
if (!mp->bswapbuf)
return AVERROR(ENOMEM);
mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf,
buf_size / 4);
if (buf_size & 3)
memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
- memset(mp->bswapbuf + buf_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
init_get_bits(&gb, mp->bswapbuf, buf_size * 8);
memset(mp->changes_map, 0, avctx->width * avctx->height);
@@ -300,7 +319,8 @@ static int mp_decode_frame(AVCodecContext *avctx,
*(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15);
mp->changes_map[0] = 1;
}
- mp_read_codes_table(mp, &gb);
+ if (mp_read_codes_table(mp, &gb) < 0)
+ goto end;
sz = get_bits(&gb, 18);
if (avctx->extradata[0] != 5)
diff --git a/libavcodec/motionpixels_tablegen.c b/libavcodec/motionpixels_tablegen.c
index 410b76fb05..14b7b9bb8c 100644
--- a/libavcodec/motionpixels_tablegen.c
+++ b/libavcodec/motionpixels_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/motionpixels_tablegen.h b/libavcodec/motionpixels_tablegen.h
index e6c32c7dec..4ffe74cbe5 100644
--- a/libavcodec/motionpixels_tablegen.h
+++ b/libavcodec/motionpixels_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,13 +24,14 @@
#define AVCODEC_MOTIONPIXELS_TABLEGEN_H
#include <stdint.h>
+#include "libavutil/attributes.h"
typedef struct YuvPixel {
int8_t y, v, u;
} YuvPixel;
static int mp_yuv_to_rgb(int y, int v, int u, int clip_rgb) {
- static const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
+ const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
int r, g, b;
r = (1000 * y + 701 * v) / 1000;
@@ -49,7 +50,7 @@ static int mp_yuv_to_rgb(int y, int v, int u, int clip_rgb) {
#else
static YuvPixel mp_rgb_yuv_table[1 << 15];
-static void mp_set_zero_yuv(YuvPixel *p)
+static av_cold void mp_set_zero_yuv(YuvPixel *p)
{
int i, j;
@@ -63,7 +64,7 @@ static void mp_set_zero_yuv(YuvPixel *p)
}
}
-static void mp_build_rgb_yuv_table(YuvPixel *p)
+static av_cold void mp_build_rgb_yuv_table(YuvPixel *p)
{
int y, v, u, i;
@@ -81,7 +82,7 @@ static void mp_build_rgb_yuv_table(YuvPixel *p)
mp_set_zero_yuv(p + i * 32);
}
-static void motionpixels_tableinit(void)
+static av_cold void motionpixels_tableinit(void)
{
if (!mp_rgb_yuv_table[0].u)
mp_build_rgb_yuv_table(mp_rgb_yuv_table);
diff --git a/libavcodec/movsub_bsf.c b/libavcodec/movsub_bsf.c
index 7b4cd62548..4820b26388 100644
--- a/libavcodec/movsub_bsf.c
+++ b/libavcodec/movsub_bsf.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Reimar Döffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,9 +37,8 @@ static int text2movsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, co
}
AVBitStreamFilter ff_text2movsub_bsf={
- "text2movsub",
- 0,
- text2movsub,
+ .name = "text2movsub",
+ .filter = text2movsub,
};
static int mov2textsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
@@ -55,7 +54,6 @@ static int mov2textsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, co
}
AVBitStreamFilter ff_mov2textsub_bsf={
- "mov2textsub",
- 0,
- mov2textsub,
+ .name = "mov2textsub",
+ .filter = mov2textsub,
};
diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c
new file mode 100644
index 0000000000..8dda5cea0d
--- /dev/null
+++ b/libavcodec/movtextdec.c
@@ -0,0 +1,223 @@
+/*
+ * 3GPP TS 26.245 Timed Text decoder
+ * Copyright (c) 2012 Philip Langdale <philipl@overt.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/avstring.h"
+#include "libavutil/common.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+
+#define STYLE_FLAG_BOLD 1
+#define STYLE_FLAG_ITALIC 2
+#define STYLE_FLAG_UNDERLINE 4
+
+static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end,
+ char **style_start, char **style_end,
+ uint8_t **style_flags, int style_entries)
+{
+ int i = 0;
+ while (text < text_end) {
+ for (i = 0; i < style_entries; i++) {
+ if (*style_flags[i] && text == style_start[i]) {
+ if (*style_flags[i] & STYLE_FLAG_BOLD)
+ av_bprintf(buf, "{\\b1}");
+ if (*style_flags[i] & STYLE_FLAG_ITALIC)
+ av_bprintf(buf, "{\\i1}");
+ if (*style_flags[i] & STYLE_FLAG_UNDERLINE)
+ av_bprintf(buf, "{\\u1}");
+ }
+ }
+
+ switch (*text) {
+ case '\r':
+ break;
+ case '\n':
+ av_bprintf(buf, "\\N");
+ break;
+ default:
+ av_bprint_chars(buf, *text, 1);
+ break;
+ }
+
+ for (i = 0; i < style_entries; i++) {
+ if (*style_flags[i] && text == style_end[i]) {
+ if (*style_flags[i] & STYLE_FLAG_BOLD)
+ av_bprintf(buf, "{\\b0}");
+ if (*style_flags[i] & STYLE_FLAG_ITALIC)
+ av_bprintf(buf, "{\\i0}");
+ if (*style_flags[i] & STYLE_FLAG_UNDERLINE)
+ av_bprintf(buf, "{\\u0}");
+ }
+ }
+ text++;
+ }
+
+ return 0;
+}
+
+static int mov_text_init(AVCodecContext *avctx) {
+ /*
+ * TODO: Handle the default text style.
+ * NB: Most players ignore styles completely, with the result that
+ * it's very common to find files where the default style is broken
+ * and respecting it results in a worse experience than ignoring it.
+ */
+ return ff_ass_subtitle_header_default(avctx);
+}
+
+static int mov_text_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ AVSubtitle *sub = data;
+ int ret, ts_start, ts_end;
+ AVBPrint buf;
+ char *ptr = avpkt->data;
+ char *end;
+ //char *ptr_temp;
+ int text_length, tsmb_type, style_entries;
+ uint64_t tsmb_size, tracksize;
+ char **style_start = { 0, };
+ char **style_end = { 0, };
+ uint8_t **style_flags = { 0, };
+ const uint8_t *tsmb;
+ int index, i, size_var;
+ uint8_t *flag;
+ char *style_pos;
+
+ if (!ptr || avpkt->size < 2)
+ return AVERROR_INVALIDDATA;
+
+ /*
+ * A packet of size two with value zero is an empty subtitle
+ * used to mark the end of the previous non-empty subtitle.
+ * We can just drop them here as we have duration information
+ * already. If the value is non-zero, then it's technically a
+ * bad packet.
+ */
+ if (avpkt->size == 2)
+ return AV_RB16(ptr) == 0 ? 0 : AVERROR_INVALIDDATA;
+
+ /*
+ * The first two bytes of the packet are the length of the text string
+ * In complex cases, there are style descriptors appended to the string
+ * so we can't just assume the packet size is the string size.
+ */
+ text_length = AV_RB16(ptr);
+ end = ptr + FFMIN(2 + text_length, avpkt->size);
+ ptr += 2;
+
+ ts_start = av_rescale_q(avpkt->pts,
+ avctx->time_base,
+ (AVRational){1,100});
+ ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
+ avctx->time_base,
+ (AVRational){1,100});
+
+ tsmb_size = 0;
+ tracksize = 2 + text_length;
+ // Note that the spec recommends lines be no longer than 2048 characters.
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if (text_length + 2 != avpkt->size) {
+ while (tracksize + 8 <= avpkt->size) {
+ // A box is a minimum of 8 bytes.
+ tsmb = ptr + tracksize - 2;
+ tsmb_size = AV_RB32(tsmb);
+ tsmb += 4;
+ tsmb_type = AV_RB32(tsmb);
+ tsmb += 4;
+
+ if (tsmb_size == 1) {
+ if (tracksize + 16 > avpkt->size)
+ break;
+ tsmb_size = AV_RB64(tsmb);
+ tsmb += 8;
+ size_var = 18;
+ } else
+ size_var = 10;
+ //size_var is equal to 10 or 18 depending on the size of box
+
+ if (tracksize + tsmb_size > avpkt->size)
+ break;
+
+ if (tsmb_type == MKBETAG('s','t','y','l')) {
+ if (tracksize + size_var > avpkt->size)
+ break;
+ style_entries = AV_RB16(tsmb);
+ tsmb += 2;
+
+ // A single style record is of length 12 bytes.
+ if (tracksize + size_var + style_entries * 12 > avpkt->size)
+ break;
+
+ for(i = 0; i < style_entries; i++) {
+ style_pos = ptr + AV_RB16(tsmb);
+ index = i;
+ av_dynarray_add(&style_start, &index, style_pos);
+ tsmb += 2;
+ style_pos = ptr + AV_RB16(tsmb);
+ index = i;
+ av_dynarray_add(&style_end, &index, style_pos);
+ tsmb += 2;
+ // fontID = AV_RB16(tsmb);
+ tsmb += 2;
+ flag = av_malloc(1);
+ if (!flag)
+ return AVERROR(ENOMEM);
+ *flag = AV_RB8(tsmb);
+ index = i;
+ av_dynarray_add(&style_flags, &index, flag);
+ //fontsize=AV_RB8(tsmb);
+ tsmb += 2;
+ // text-color-rgba
+ tsmb += 4;
+ }
+ text_to_ass(&buf, ptr, end, style_start, style_end, style_flags, style_entries);
+
+ for(i = 0; i < style_entries; i++) {
+ av_freep(&style_flags[i]);
+ }
+ av_freep(&style_start);
+ av_freep(&style_end);
+ av_freep(&style_flags);
+ }
+ tracksize = tracksize + tsmb_size;
+ }
+ } else
+ text_to_ass(&buf, ptr, end, NULL, NULL, 0, 0);
+
+ ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_end - ts_start);
+ av_bprint_finalize(&buf, NULL);
+ if (ret < 0)
+ return ret;
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_movtext_decoder = {
+ .name = "mov_text",
+ .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_MOV_TEXT,
+ .init = mov_text_init,
+ .decode = mov_text_decode_frame,
+};
diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c
new file mode 100644
index 0000000000..1b8f454f8b
--- /dev/null
+++ b/libavcodec/movtextenc.c
@@ -0,0 +1,165 @@
+/*
+ * 3GPP TS 26.245 Timed Text encoder
+ * Copyright (c) 2012 Philip Langdale <philipl@overt.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdarg.h>
+#include "avcodec.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/intreadwrite.h"
+#include "ass_split.h"
+#include "ass.h"
+
+typedef struct {
+ ASSSplitContext *ass_ctx;
+ char buffer[2048];
+ char *ptr;
+ char *end;
+} MovTextContext;
+
+
+static av_cold int mov_text_encode_init(AVCodecContext *avctx)
+{
+ /*
+ * For now, we'll use a fixed default style. When we add styling
+ * support, this will be generated from the ASS style.
+ */
+ static const uint8_t text_sample_entry[] = {
+ 0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
+ 0x01, // int8_t horizontal-justification
+ 0xFF, // int8_t vertical-justification
+ 0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
+ // BoxRecord {
+ 0x00, 0x00, // int16_t top
+ 0x00, 0x00, // int16_t left
+ 0x00, 0x00, // int16_t bottom
+ 0x00, 0x00, // int16_t right
+ // };
+ // StyleRecord {
+ 0x00, 0x00, // uint16_t startChar
+ 0x00, 0x00, // uint16_t endChar
+ 0x00, 0x01, // uint16_t font-ID
+ 0x00, // uint8_t face-style-flags
+ 0x12, // uint8_t font-size
+ 0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
+ // };
+ // FontTableBox {
+ 0x00, 0x00, 0x00, 0x12, // uint32_t size
+ 'f', 't', 'a', 'b', // uint8_t name[4]
+ 0x00, 0x01, // uint16_t entry-count
+ // FontRecord {
+ 0x00, 0x01, // uint16_t font-ID
+ 0x05, // uint8_t font-name-length
+ 'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
+ // };
+ // };
+ };
+
+ MovTextContext *s = avctx->priv_data;
+
+ avctx->extradata_size = sizeof text_sample_entry;
+ avctx->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
+
+ memcpy(avctx->extradata, text_sample_entry, avctx->extradata_size);
+
+ s->ass_ctx = ff_ass_split(avctx->subtitle_header);
+ return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
+}
+
+static void mov_text_text_cb(void *priv, const char *text, int len)
+{
+ MovTextContext *s = priv;
+ av_assert0(s->end >= s->ptr);
+ av_strlcpy(s->ptr, text, FFMIN(s->end - s->ptr, len + 1));
+ s->ptr += FFMIN(s->end - s->ptr, len);
+}
+
+static void mov_text_new_line_cb(void *priv, int forced)
+{
+ MovTextContext *s = priv;
+ av_assert0(s->end >= s->ptr);
+ av_strlcpy(s->ptr, "\n", FFMIN(s->end - s->ptr, 2));
+ if (s->end > s->ptr)
+ s->ptr++;
+}
+
+static const ASSCodesCallbacks mov_text_callbacks = {
+ .text = mov_text_text_cb,
+ .new_line = mov_text_new_line_cb,
+};
+
+static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
+ int bufsize, const AVSubtitle *sub)
+{
+ MovTextContext *s = avctx->priv_data;
+ ASSDialog *dialog;
+ int i, len, num;
+
+ s->ptr = s->buffer;
+ s->end = s->ptr + sizeof(s->buffer);
+
+ for (i = 0; i < sub->num_rects; i++) {
+
+ if (sub->rects[i]->type != SUBTITLE_ASS) {
+ av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+ return AVERROR(ENOSYS);
+ }
+
+ dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
+ for (; dialog && num--; dialog++) {
+ ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
+ }
+ }
+
+ if (s->ptr == s->buffer)
+ return 0;
+
+ AV_WB16(buf, strlen(s->buffer));
+ buf += 2;
+
+ len = av_strlcpy(buf, s->buffer, bufsize - 2);
+
+ if (len > bufsize-3) {
+ av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
+ return AVERROR(EINVAL);
+ }
+
+ return len + 2;
+}
+
+static int mov_text_encode_close(AVCodecContext *avctx)
+{
+ MovTextContext *s = avctx->priv_data;
+ ff_ass_split_free(s->ass_ctx);
+ return 0;
+}
+
+AVCodec ff_movtext_encoder = {
+ .name = "mov_text",
+ .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_MOV_TEXT,
+ .priv_data_size = sizeof(MovTextContext),
+ .init = mov_text_encode_init,
+ .encode_sub = mov_text_encode_frame,
+ .close = mov_text_encode_close,
+};
diff --git a/libavcodec/mp3_header_decompress_bsf.c b/libavcodec/mp3_header_decompress_bsf.c
new file mode 100644
index 0000000000..df455322df
--- /dev/null
+++ b/libavcodec/mp3_header_decompress_bsf.c
@@ -0,0 +1,97 @@
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/intreadwrite.h"
+#include "avcodec.h"
+#include "mpegaudiodecheader.h"
+#include "mpegaudiodata.h"
+
+
+static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
+ uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size, int keyframe){
+ uint32_t header;
+ int sample_rate= avctx->sample_rate;
+ int sample_rate_index=0;
+ int lsf, mpeg25, bitrate_index, frame_size;
+
+ header = AV_RB32(buf);
+ if(ff_mpa_check_header(header) >= 0){
+ *poutbuf= (uint8_t *) buf;
+ *poutbuf_size= buf_size;
+
+ return 0;
+ }
+
+ if(avctx->extradata_size != 15 || strcmp(avctx->extradata, "FFCMP3 0.0")){
+ av_log(avctx, AV_LOG_ERROR, "Extradata invalid %d\n", avctx->extradata_size);
+ return -1;
+ }
+
+ header= AV_RB32(avctx->extradata+11) & MP3_MASK;
+
+ lsf = sample_rate < (24000+32000)/2;
+ mpeg25 = sample_rate < (12000+16000)/2;
+ sample_rate_index= (header>>10)&3;
+ sample_rate= avpriv_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25); //in case sample rate is a little off
+
+ for(bitrate_index=2; bitrate_index<30; bitrate_index++){
+ frame_size = avpriv_mpa_bitrate_tab[lsf][2][bitrate_index>>1];
+ frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index&1);
+ if(frame_size == buf_size + 4)
+ break;
+ if(frame_size == buf_size + 6)
+ break;
+ }
+ if(bitrate_index == 30){
+ av_log(avctx, AV_LOG_ERROR, "Could not find bitrate_index.\n");
+ return -1;
+ }
+
+ header |= (bitrate_index&1)<<9;
+ header |= (bitrate_index>>1)<<12;
+ header |= (frame_size == buf_size + 4)<<16; //FIXME actually set a correct crc instead of 0
+
+ *poutbuf_size= frame_size;
+ *poutbuf= av_malloc(frame_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ memcpy(*poutbuf + frame_size - buf_size, buf, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+
+ if(avctx->channels==2){
+ uint8_t *p= *poutbuf + frame_size - buf_size;
+ if(lsf){
+ FFSWAP(int, p[1], p[2]);
+ header |= (p[1] & 0xC0)>>2;
+ p[1] &= 0x3F;
+ }else{
+ header |= p[1] & 0x30;
+ p[1] &= 0xCF;
+ }
+ }
+
+ AV_WB32(*poutbuf, header);
+
+ return 1;
+}
+
+AVBitStreamFilter ff_mp3_header_decompress_bsf={
+ .name = "mp3decomp",
+ .filter = mp3_header_decompress,
+};
diff --git a/libavcodec/mpc.c b/libavcodec/mpc.c
index 763ea2c058..7af30bd0e1 100644
--- a/libavcodec/mpc.c
+++ b/libavcodec/mpc.c
@@ -2,20 +2,20 @@
* Musepack decoder core
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -74,13 +74,13 @@ void ff_mpc_dequantize_and_synth(MPCContext * c, int maxband, int16_t **out,
for(ch = 0; ch < 2; ch++){
if(bands[i].res[ch]){
j = 0;
- mul = mpc_CC[bands[i].res[ch] + 1] * mpc_SCF[bands[i].scf_idx[ch][0]+6];
+ mul = (mpc_CC+1)[bands[i].res[ch]] * mpc_SCF[bands[i].scf_idx[ch][0] & 0xFF];
for(; j < 12; j++)
c->sb_samples[ch][j][i] = mul * c->Q[ch][j + off];
- mul = mpc_CC[bands[i].res[ch] + 1] * mpc_SCF[bands[i].scf_idx[ch][1]+6];
+ mul = (mpc_CC+1)[bands[i].res[ch]] * mpc_SCF[bands[i].scf_idx[ch][1] & 0xFF];
for(; j < 24; j++)
c->sb_samples[ch][j][i] = mul * c->Q[ch][j + off];
- mul = mpc_CC[bands[i].res[ch] + 1] * mpc_SCF[bands[i].scf_idx[ch][2]+6];
+ mul = (mpc_CC+1)[bands[i].res[ch]] * mpc_SCF[bands[i].scf_idx[ch][2] & 0xFF];
for(; j < 36; j++)
c->sb_samples[ch][j][i] = mul * c->Q[ch][j + off];
}
diff --git a/libavcodec/mpc.h b/libavcodec/mpc.h
index cdf49c1a4e..4cb8574897 100644
--- a/libavcodec/mpc.h
+++ b/libavcodec/mpc.h
@@ -2,20 +2,20 @@
* Musepack decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpc7.c b/libavcodec/mpc7.c
index 2185aec88b..0f1e34a8f4 100644
--- a/libavcodec/mpc7.c
+++ b/libavcodec/mpc7.c
@@ -2,20 +2,20 @@
* Musepack SV7 decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,10 +36,6 @@
#include "mpc.h"
#include "mpc7data.h"
-#define BANDS 32
-#define SAMPLES_PER_BAND 36
-#define MPC_FRAME_SIZE (BANDS * SAMPLES_PER_BAND)
-
static VLC scfi_vlc, dscf_vlc, hdr_vlc, quant_vlc[MPC7_QUANT_VLC_TABLES][2];
static const uint16_t quant_offsets[MPC7_QUANT_VLC_TABLES*2 + 1] =
@@ -190,7 +186,7 @@ static int get_scale_idx(GetBitContext *gb, int ref)
int t = get_vlc2(gb, dscf_vlc.table, MPC7_DSCF_BITS, 1) - 7;
if (t == 8)
return get_bits(gb, 6);
- return av_clip_uintp2(ref + t, 7);
+ return ref + t;
}
static int mpc7_decode_frame(AVCodecContext * avctx, void *data,
@@ -226,11 +222,9 @@ static int mpc7_decode_frame(AVCodecContext * avctx, void *data,
buf_size -= 4;
/* get output buffer */
- frame->nb_samples = last_frame ? c->lastframelen : MPC_FRAME_SIZE;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ frame->nb_samples = MPC_FRAME_SIZE;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
av_fast_padded_malloc(&c->bits, &c->buf_size, buf_size);
if (!c->bits)
@@ -246,7 +240,11 @@ static int mpc7_decode_frame(AVCodecContext * avctx, void *data,
int t = 4;
if(i) t = get_vlc2(&gb, hdr_vlc.table, MPC7_HDR_BITS, 1) - 5;
if(t == 4) bands[i].res[ch] = get_bits(&gb, 4);
- else bands[i].res[ch] = av_clip(bands[i-1].res[ch] + t, 0, 17);
+ else bands[i].res[ch] = bands[i-1].res[ch] + t;
+ if (bands[i].res[ch] < -1 || bands[i].res[ch] > 17) {
+ av_log(avctx, AV_LOG_ERROR, "subband index invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
}
if(bands[i].res[0] || bands[i].res[1]){
@@ -293,6 +291,8 @@ static int mpc7_decode_frame(AVCodecContext * avctx, void *data,
idx_to_quant(c, &gb, bands[i].res[ch], c->Q[ch] + off);
ff_mpc_dequantize_and_synth(c, mb, (int16_t **)frame->extended_data, 2);
+ if(last_frame)
+ frame->nb_samples = c->lastframelen;
bits_used = get_bits_count(&gb);
bits_avail = buf_size * 8;
diff --git a/libavcodec/mpc7data.h b/libavcodec/mpc7data.h
index f205ffe97f..5609e8fbf3 100644
--- a/libavcodec/mpc7data.h
+++ b/libavcodec/mpc7data.h
@@ -2,20 +2,20 @@
* Musepack decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpc8.c b/libavcodec/mpc8.c
index ee05a938b6..29c65f9ef5 100644
--- a/libavcodec/mpc8.c
+++ b/libavcodec/mpc8.c
@@ -2,20 +2,20 @@
* Musepack SV8 decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -126,6 +126,10 @@ static av_cold int mpc8_decode_init(AVCodecContext * avctx)
skip_bits(&gb, 3);//sample rate
c->maxbands = get_bits(&gb, 5) + 1;
+ if (c->maxbands >= BANDS) {
+ av_log(avctx,AV_LOG_ERROR, "maxbands %d too high\n", c->maxbands);
+ return AVERROR_INVALIDDATA;
+ }
channels = get_bits(&gb, 4) + 1;
if (channels > 2) {
avpriv_request_sample(avctx, "Multichannel MPC SV8");
@@ -135,7 +139,8 @@ static av_cold int mpc8_decode_init(AVCodecContext * avctx)
c->frames = 1 << (get_bits(&gb, 3) * 2);
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
- avctx->channel_layout = (avctx->channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
+ avctx->channel_layout = (channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
+ avctx->channels = channels;
if(vlc_initialized) return 0;
av_log(avctx, AV_LOG_DEBUG, "Initing VLC\n");
@@ -247,10 +252,8 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data,
/* get output buffer */
frame->nb_samples = MPC_FRAME_SIZE;
- if ((res = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
return res;
- }
keyframe = c->cur_frame == 0;
@@ -267,8 +270,11 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data,
maxband = c->last_max_band + get_vlc2(gb, band_vlc.table, MPC8_BANDS_BITS, 2);
if(maxband > 32) maxband -= 33;
}
- if(maxband > c->maxbands + 1)
+
+ if(maxband > c->maxbands + 1) {
+ av_log(avctx, AV_LOG_ERROR, "maxband %d too large\n",maxband);
return AVERROR_INVALIDDATA;
+ }
c->last_max_band = maxband;
/* read subband indexes */
diff --git a/libavcodec/mpc8data.h b/libavcodec/mpc8data.h
index 2940b30733..22c2be43bf 100644
--- a/libavcodec/mpc8data.h
+++ b/libavcodec/mpc8data.h
@@ -2,20 +2,20 @@
* Musepack SV8 decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpc8huff.h b/libavcodec/mpc8huff.h
index 6005e214e8..8491037aa4 100644
--- a/libavcodec/mpc8huff.h
+++ b/libavcodec/mpc8huff.h
@@ -2,20 +2,20 @@
* Musepack SV8 decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpcdata.h b/libavcodec/mpcdata.h
index 15724f3b74..64fb4ab326 100644
--- a/libavcodec/mpcdata.h
+++ b/libavcodec/mpcdata.h
@@ -2,20 +2,20 @@
* Musepack decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,9 +30,7 @@ static const float mpc_CC[18+1] = {
4.0002, 2.0001, 1.0000
};
-static const float mpc_SCF[128+6] = {
- 920.016296386718750000, 766.355773925781250000, 638.359558105468750000,
- 531.741149902343750000, 442.930114746093750000, 368.952209472656250000,
+static const float mpc_SCF[256] = {
307.330047607421875000, 255.999984741210937500, 213.243041992187500000, 177.627334594726562500,
147.960128784179687500, 123.247924804687500000, 102.663139343261718750, 85.516410827636718750,
71.233520507812500000, 59.336143493652343750, 49.425861358642578125, 41.170787811279296875,
@@ -64,7 +62,39 @@ static const float mpc_SCF[128+6] = {
0.000000396931966407, 0.000000330636652279, 0.000000275413924555, 0.000000229414467867,
0.000000191097811353, 0.000000159180785886, 0.000000132594522029, 0.000000110448674207,
0.000000092001613439, 0.000000076635565449, 0.000000063835940978, 0.000000053174105119,
- 0.000000044293003043, 0.000000036895215771, 0.000000030733001921, 0.000000025599996789
+ 0.000000044293003043, 0.000000036895215771, 0.000000030733001921, 0.000000025599996789,
+ 0.000000021324305018, 3689522167600.270019531250000000, 3073300627835.926757812500000000, 2560000000000.002929687500000000,
+ 2132430501800.519042968750000000, 1776273376956.721923828125000000, 1479601378343.250244140625000000, 1232479339720.794189453125000000,
+ 1026631459710.774291992187500000, 855164155779.391845703125000000, 712335206965.024780273437500000, 593361454233.829101562500000000,
+ 494258618594.112609863281250000, 411707872682.763122558593750000, 342944697476.612365722656250000, 285666302081.983886718750000000,
+ 237954506209.446411132812500000, 198211502766.368713378906250000, 165106349338.563323974609375000, 137530396629.095306396484375000,
+ 114560161209.611633300781250000, 95426399240.062576293945312500, 79488345475.196502685546875000, 66212254855.064872741699218750,
+ 55153528064.816276550292968750, 45941822471.611343383789062500, 38268649822.956413269042968750, 31877045369.216873168945312500,
+ 26552962442.420688629150390625, 22118104306.789615631103515625, 18423953228.829509735107421875, 15346796808.164905548095703125,
+ 12783585007.291271209716796875, 10648479137.463939666748046875, 8869977230.669750213623046875, 7388519530.061036109924316406,
+ 6154493909.785535812377929688, 5126574428.270387649536132812, 4270337375.232155323028564453, 3557108465.595236301422119141,
+ 2963002574.315670013427734375, 2468123854.056322574615478516, 2055899448.676229715347290039, 1712524489.450022459030151367,
+ 1426499787.649837732315063477, 1188246741.404872417449951172, 989786560.561257958412170410, 824473067.192597866058349609,
+ 686770123.591610312461853027, 572066234.090648531913757324, 476520111.962911486625671387, 396932039.637152194976806641,
+ 330636714.243810534477233887, 275413990.026798009872436523, 229414528.498330980539321899, 191097866.455478429794311523,
+ 159180827.835415601730346680, 132594551.788319095969200134, 110448697.892960876226425171, 92001629.793398514389991760,
+ 76635578.744844585657119751, 63835955.327594503760337830, 53174116.504741288721561432, 44293010.914454914629459381,
+ 36895221.676002673804759979, 30733006.278359245508909225, 25600000.000000011175870895, 21324305.018005173653364182,
+ 17762733.769567202776670456, 14796013.783432489261031151, 12324793.397207930684089661, 10266314.597107734531164169,
+ 8551641.557793911546468735, 7123352.069650243036448956, 5933614.542338287457823753, 4942586.185941123403608799,
+ 4117078.726827629376202822, 3429446.974766122177243233, 2856663.020819837693125010, 2379545.062094463035464287,
+ 1982115.027663686312735081, 1651063.493385632522404194, 1375303.966290952404960990, 1145601.612096115713939071,
+ 954263.992400625254958868, 794883.454751964658498764, 662122.548550648498348892, 551535.280648162588477135,
+ 459418.224716113239992410, 382686.498229563992936164, 318770.453692168579436839, 265529.624424206791445613,
+ 221181.043067896069260314, 184239.532288295013131574, 153467.968081648985389620, 127835.850072912653558888,
+ 106484.791374639346031472, 88699.772306697457679547, 73885.195300610314006917, 61544.939097855312866159,
+ 51265.744282703839417081, 42703.373752321524079889, 35571.084655952341563534, 29630.025743156678800005,
+ 24681.238540563208516687, 20558.994486762283486314, 17125.244894500214286381, 14264.997876498367986642,
+ 11882.467414048716818797, 9897.865605612574654515, 8244.730671925974093028, 6867.701235916098994494,
+ 5720.662340906482313585, 4765.201119629112326948, 3969.320396371519564127, 3306.367142438103201130,
+ 2754.139900267978191550, 2294.145284983308101801, 1910.978664554782881169, 1591.808278354154936096,
+ 1325.945517883190177599, 1104.486978929608085309, 920.016297933984674273, 766.355787448445425980,
+ 638.359553275944676898, 531.741165047412550848, 442.930109144548907807, 368.952216760026544762,
};
#endif /* AVCODEC_MPCDATA_H */
diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c
index be5227f058..3128e8d1e3 100644
--- a/libavcodec/mpeg12.c
+++ b/libavcodec/mpeg12.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,12 @@
* MPEG-1/2 decoder
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
+#include "libavutil/timecode.h"
+
#include "internal.h"
#include "avcodec.h"
#include "mpegvideo.h"
@@ -33,6 +38,7 @@
#include "mpeg12.h"
#include "mpeg12data.h"
#include "bytestream.h"
+#include "vdpau_internal.h"
#include "thread.h"
uint8_t ff_mpeg12_static_rl_table_store[2][2][2*MAX_RUN + MAX_LEVEL + 3];
@@ -64,21 +70,21 @@ static const uint8_t table_mb_btype[11][2] = {
#define INIT_2D_VLC_RL(rl, static_size)\
{\
static RL_VLC_ELEM rl_vlc_table[static_size];\
- INIT_VLC_STATIC(&rl.vlc, TEX_VLC_BITS, rl.n + 2,\
- &rl.table_vlc[0][1], 4, 2,\
- &rl.table_vlc[0][0], 4, 2, static_size);\
-\
rl.rl_vlc[0] = rl_vlc_table;\
- init_2d_vlc_rl(&rl);\
+ init_2d_vlc_rl(&rl, static_size);\
}
-static av_cold void init_2d_vlc_rl(RLTable *rl)
+static av_cold void init_2d_vlc_rl(RLTable *rl, unsigned static_size)
{
int i;
-
- for (i = 0; i < rl->vlc.table_size; i++) {
- int code = rl->vlc.table[i][0];
- int len = rl->vlc.table[i][1];
+ VLC_TYPE table[680][2] = {{0}};
+ VLC vlc = { .table = table, .table_allocated = static_size };
+ av_assert0(static_size <= FF_ARRAY_ELEMS(table));
+ init_vlc(&vlc, TEX_VLC_BITS, rl->n + 2, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC);
+
+ for (i = 0; i < vlc.table_size; i++) {
+ int code = vlc.table[i][0];
+ int len = vlc.table[i][1];
int level, run;
if (len == 0) { // illegal code
@@ -194,7 +200,7 @@ int ff_mpeg1_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size,
*/
for (i = 0; i < buf_size; i++) {
- assert(pc->frame_start_found >= 0 && pc->frame_start_found <= 4);
+ av_assert1(pc->frame_start_found >= 0 && pc->frame_start_found <= 4);
if (pc->frame_start_found & 1) {
if (state == EXT_START_CODE && (buf[i] & 0xF0) != 0x80)
pc->frame_start_found--;
@@ -228,10 +234,11 @@ int ff_mpeg1_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size,
}
}
if (pc->frame_start_found == 0 && s && state == PICTURE_START_CODE) {
- ff_fetch_timestamp(s, i - 3, 1);
+ ff_fetch_timestamp(s, i - 3, 1, i > 3);
}
}
}
pc->state = state;
return END_NOT_FOUND;
}
+
diff --git a/libavcodec/mpeg12.h b/libavcodec/mpeg12.h
index 9132dc3d2d..b4ebd23fa8 100644
--- a/libavcodec/mpeg12.h
+++ b/libavcodec/mpeg12.h
@@ -2,20 +2,20 @@
* MPEG1/2 common code
* Copyright (c) 2007 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpeg12data.c b/libavcodec/mpeg12data.c
index ccc3d2deb9..e8c4a5d3d1 100644
--- a/libavcodec/mpeg12data.c
+++ b/libavcodec/mpeg12data.c
@@ -3,20 +3,20 @@
* copyright (c) 2000,2001 Fabrice Bellard
* copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
#include "mpeg12data.h"
-const uint16_t ff_mpeg1_default_intra_matrix[64] = {
+const uint16_t ff_mpeg1_default_intra_matrix[256] = {
8, 16, 19, 22, 26, 27, 29, 34,
16, 16, 22, 24, 27, 29, 34, 37,
19, 22, 26, 27, 29, 34, 34, 38,
@@ -325,6 +325,72 @@ const AVRational ff_mpeg12_frame_rate_tab[16] = {
{ 0, 0},
};
+const AVRational ff_mpeg2_frame_rate_tab[] = {
+ { 1, 1},
+ { 2, 1},
+ { 3, 1},
+ { 4, 1},
+ { 5, 1},
+ { 6, 1},
+ { 8, 1},
+ { 9, 1},
+ { 10, 1},
+ { 12, 1},
+ { 15, 1},
+ { 16, 1},
+ { 18, 1},
+ { 20, 1},
+ { 24, 1},
+ { 25, 1},
+ { 30, 1},
+ { 32, 1},
+ { 36, 1},
+ { 40, 1},
+ { 45, 1},
+ { 48, 1},
+ { 50, 1},
+ { 60, 1},
+ { 72, 1},
+ { 75, 1},
+ { 80, 1},
+ { 90, 1},
+ { 96, 1},
+ { 100, 1},
+ { 120, 1},
+ { 150, 1},
+ { 180, 1},
+ { 200, 1},
+ { 240, 1},
+ { 750, 1001},
+ { 800, 1001},
+ { 960, 1001},
+ { 1000, 1001},
+ { 1200, 1001},
+ { 1250, 1001},
+ { 1500, 1001},
+ { 1600, 1001},
+ { 1875, 1001},
+ { 2000, 1001},
+ { 2400, 1001},
+ { 2500, 1001},
+ { 3000, 1001},
+ { 3750, 1001},
+ { 4000, 1001},
+ { 4800, 1001},
+ { 5000, 1001},
+ { 6000, 1001},
+ { 7500, 1001},
+ { 8000, 1001},
+ { 10000, 1001},
+ { 12000, 1001},
+ { 15000, 1001},
+ { 20000, 1001},
+ { 24000, 1001},
+ { 30000, 1001},
+ { 60000, 1001},
+ { 0, 0},
+};
+
const float ff_mpeg1_aspect[16]={
0.0000,
1.0000,
diff --git a/libavcodec/mpeg12data.h b/libavcodec/mpeg12data.h
index 633a2915e6..65b94855a8 100644
--- a/libavcodec/mpeg12data.h
+++ b/libavcodec/mpeg12data.h
@@ -3,20 +3,20 @@
* copyright (c) 2000,2001 Fabrice Bellard
* copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,7 +32,7 @@
#include "libavutil/rational.h"
#include "rl.h"
-extern const uint16_t ff_mpeg1_default_intra_matrix[64];
+extern const uint16_t ff_mpeg1_default_intra_matrix[];
extern const uint16_t ff_mpeg1_default_non_intra_matrix[64];
extern const uint16_t ff_mpeg12_vlc_dc_lum_code[12];
@@ -49,6 +49,7 @@ extern const uint8_t ff_mpeg12_mbPatTable[64][2];
extern const uint8_t ff_mpeg12_mbMotionVectorTable[17][2];
extern const AVRational ff_mpeg12_frame_rate_tab[];
+extern const AVRational ff_mpeg2_frame_rate_tab[];
extern const float ff_mpeg1_aspect[16];
extern const AVRational ff_mpeg2_aspect[16];
diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c
index c66d6aa508..f180c3d62b 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -1,22 +1,22 @@
/*
* MPEG-1/2 decoder
* Copyright (c) 2000, 2001 Fabrice Bellard
- * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2002-2013 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,9 +25,11 @@
* MPEG-1/2 decoder
*/
+#define UNCHECKED_BITSTREAM_READER 1
#include <inttypes.h>
#include "libavutil/attributes.h"
+#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/stereo3d.h"
@@ -43,6 +45,7 @@
#include "mpegvideo.h"
#include "thread.h"
#include "version.h"
+#include "vdpau_internal.h"
#include "xvmc_internal.h"
typedef struct Mpeg1Context {
@@ -57,11 +60,11 @@ typedef struct Mpeg1Context {
uint8_t afd;
int has_afd;
int slice_count;
- int save_aspect_info;
+ AVRational save_aspect;
int save_width, save_height, save_progressive_seq;
AVRational frame_rate_ext; /* MPEG-2 specific framerate modificator */
int sync; /* Did we reach a sync point like a GOP/SEQ/KEYFrame? */
- int closed_gop; /* GOP is closed */
+ int tmpgexs;
int first_slice;
int extradata_decoded;
} Mpeg1Context;
@@ -154,19 +157,20 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s,
dc += diff;
s->last_dc[component] = dc;
block[0] = dc * quant_matrix[0];
- ff_dlog(s->avctx, "dc=%d diff=%d\n", dc, diff);
+ ff_tlog(s->avctx, "dc=%d diff=%d\n", dc, diff);
i = 0;
{
OPEN_READER(re, &s->gb);
+ UPDATE_CACHE(re, &s->gb);
+ if (((int32_t)GET_CACHE(re, &s->gb)) <= (int32_t)0xBFFFFFFF)
+ goto end;
+
/* now quantify & encode AC coefficients */
for (;;) {
- UPDATE_CACHE(re, &s->gb);
GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0],
TEX_VLC_BITS, 2, 0);
- if (level == 127) {
- break;
- } else if (level != 0) {
+ if (level != 0) {
i += run;
check_scantable_index(s, i);
j = scantable[i];
@@ -174,7 +178,7 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s,
level = (level - 1) | 1;
level = (level ^ SHOW_SBITS(re, &s->gb, 1)) -
SHOW_SBITS(re, &s->gb, 1);
- LAST_SKIP_BITS(re, &s->gb, 1);
+ SKIP_BITS(re, &s->gb, 1);
} else {
/* escape */
run = SHOW_UBITS(re, &s->gb, 6) + 1;
@@ -184,10 +188,10 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s,
SKIP_BITS(re, &s->gb, 8);
if (level == -128) {
level = SHOW_UBITS(re, &s->gb, 8) - 256;
- LAST_SKIP_BITS(re, &s->gb, 8);
+ SKIP_BITS(re, &s->gb, 8);
} else if (level == 0) {
level = SHOW_UBITS(re, &s->gb, 8);
- LAST_SKIP_BITS(re, &s->gb, 8);
+ SKIP_BITS(re, &s->gb, 8);
}
i += run;
check_scantable_index(s, i);
@@ -204,7 +208,13 @@ static inline int mpeg1_decode_block_intra(MpegEncContext *s,
}
block[j] = level;
+ if (((int32_t)GET_CACHE(re, &s->gb)) <= (int32_t)0xBFFFFFFF)
+ break;
+
+ UPDATE_CACHE(re, &s->gb);
}
+end:
+ LAST_SKIP_BITS(re, &s->gb, 2);
CLOSE_READER(re, &s->gb);
}
s->block_last_index[n] = i;
@@ -296,6 +306,11 @@ end:
return 0;
}
+/**
+ * Note: this function can read out of range and crash for corrupt streams.
+ * Changing this would eat up any speed benefits it has.
+ * Do not use "fast" flag if you need the code to be robust.
+ */
static inline int mpeg1_fast_decode_block_inter(MpegEncContext *s,
int16_t *block, int n)
{
@@ -458,6 +473,11 @@ end:
return 0;
}
+/**
+ * Note: this function can read out of range and crash for corrupt streams.
+ * Changing this would eat up any speed benefits it has.
+ * Do not use "fast" flag if you need the code to be robust.
+ */
static inline int mpeg2_fast_decode_block_non_intra(MpegEncContext *s,
int16_t *block, int n)
{
@@ -487,7 +507,6 @@ static inline int mpeg2_fast_decode_block_non_intra(MpegEncContext *s,
if (level != 0) {
i += run;
- check_scantable_index(s, i);
j = scantable[i];
level = ((level * 2 + 1) * qscale) >> 1;
level = (level ^ SHOW_SBITS(re, &s->gb, 1)) -
@@ -502,7 +521,6 @@ static inline int mpeg2_fast_decode_block_non_intra(MpegEncContext *s,
SKIP_BITS(re, &s->gb, 12);
i += run;
- check_scantable_index(s, i);
j = scantable[i];
if (level < 0) {
level = ((-level * 2 + 1) * qscale) >> 1;
@@ -513,8 +531,9 @@ static inline int mpeg2_fast_decode_block_non_intra(MpegEncContext *s,
}
block[j] = level;
- if (((int32_t) GET_CACHE(re, &s->gb)) <= (int32_t) 0xBFFFFFFF)
+ if (((int32_t) GET_CACHE(re, &s->gb)) <= (int32_t) 0xBFFFFFFF || i > 63)
break;
+
UPDATE_CACHE(re, &s->gb);
}
end:
@@ -550,7 +569,7 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s,
dc += diff;
s->last_dc[component] = dc;
block[0] = dc << (3 - s->intra_dc_precision);
- ff_dlog(s->avctx, "dc=%d\n", block[0]);
+ ff_tlog(s->avctx, "dc=%d\n", block[0]);
mismatch = block[0] ^ 1;
i = 0;
if (s->intra_vlc_format)
@@ -605,6 +624,11 @@ static inline int mpeg2_decode_block_intra(MpegEncContext *s,
return 0;
}
+/**
+ * Note: this function can read out of range and crash for corrupt streams.
+ * Changing this would eat up any speed benefits it has.
+ * Do not use "fast" flag if you need the code to be robust.
+ */
static inline int mpeg2_fast_decode_block_intra(MpegEncContext *s,
int16_t *block, int n)
{
@@ -644,11 +668,10 @@ static inline int mpeg2_fast_decode_block_intra(MpegEncContext *s,
GET_RL_VLC(level, run, re, &s->gb, rl->rl_vlc[0],
TEX_VLC_BITS, 2, 0);
- if (level == 127) {
+ if (level >= 64 || i > 63) {
break;
} else if (level != 0) {
i += run;
- check_scantable_index(s, i);
j = scantable[i];
level = (level * qscale * quant_matrix[j]) >> 4;
level = (level ^ SHOW_SBITS(re, &s->gb, 1)) -
@@ -662,7 +685,6 @@ static inline int mpeg2_fast_decode_block_intra(MpegEncContext *s,
level = SHOW_SBITS(re, &s->gb, 12);
SKIP_BITS(re, &s->gb, 12);
i += run;
- check_scantable_index(s, i);
j = scantable[i];
if (level < 0) {
level = (-level * qscale * quant_matrix[j]) >> 4;
@@ -701,6 +723,7 @@ static inline int get_qscale(MpegEncContext *s)
return qscale << 1;
}
+
/* motion type (for MPEG-2) */
#define MT_FIELD 1
#define MT_FRAME 2
@@ -713,9 +736,9 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
const int mb_block_count = 4 + (1 << s->chroma_format);
int ret;
- ff_dlog(s->avctx, "decode_mb: x=%d y=%d\n", s->mb_x, s->mb_y);
+ ff_tlog(s->avctx, "decode_mb: x=%d y=%d\n", s->mb_x, s->mb_y);
- assert(s->mb_skipped == 0);
+ av_assert2(s->mb_skipped == 0);
if (s->mb_skip_run-- != 0) {
if (s->pict_type == AV_PICTURE_TYPE_P) {
@@ -730,11 +753,12 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
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];
- if (IS_INTRA(mb_type))
+ 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] =
mb_type | MB_TYPE_SKIP;
-// assert(s->current_picture.mb_type[s->mb_x + s->mb_y * s->mb_stride - 1] & (MB_TYPE_16x16 | MB_TYPE_16x8));
if ((s->mv[0][0][0] | s->mv[0][0][1] | s->mv[1][0][0] | s->mv[1][0][1]) == 0)
s->mb_skipped = 1;
@@ -777,7 +801,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
mb_type = btype2mb_type[mb_type];
break;
}
- ff_dlog(s->avctx, "mb_type=%x\n", mb_type);
+ ff_tlog(s->avctx, "mb_type=%x\n", mb_type);
// motion_type = 0; /* avoid warning */
if (IS_INTRA(mb_type)) {
s->bdsp.clear_blocks(s->block[0]);
@@ -808,19 +832,15 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64])
s->last_mv[0][1][1] = mpeg_decode_motion(s, s->mpeg_f_code[0][1],
s->last_mv[0][0][1]);
- skip_bits1(&s->gb); /* marker */
+ check_marker(&s->gb, "after concealment_motion_vectors");
} else {
/* reset mv prediction */
memset(s->last_mv, 0, sizeof(s->last_mv));
}
s->mb_intra = 1;
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
// if 1, we memcpy blocks in xvmcvideo
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration > 1)
+ if ((CONFIG_MPEG1_XVMC_HWACCEL || CONFIG_MPEG2_XVMC_HWACCEL) && s->pack_pblocks)
ff_xvmc_pack_pblocks(s, -1); // inter are always full blocks
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
if (s->avctx->flags2 & CODEC_FLAG2_FAST) {
@@ -838,11 +858,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
} else {
if (mb_type & MB_TYPE_ZERO_MV) {
- assert(mb_type & MB_TYPE_CBP);
+ av_assert2(mb_type & MB_TYPE_CBP);
s->mv_dir = MV_DIR_FORWARD;
if (s->picture_structure == PICT_FRAME) {
- if (!s->frame_pred_frame_dct)
+ if (s->picture_structure == PICT_FRAME
+ && !s->frame_pred_frame_dct)
s->interlaced_dct = get_bits1(&s->gb);
s->mv_type = MV_TYPE_16X16;
} else {
@@ -861,10 +882,10 @@ FF_ENABLE_DEPRECATION_WARNINGS
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
} else {
- assert(mb_type & MB_TYPE_L0L1);
+ av_assert2(mb_type & MB_TYPE_L0L1);
// FIXME decide if MBs in field pictures are MB_TYPE_INTERLACED
/* get additional motion vector type */
- if (s->frame_pred_frame_dct) {
+ if (s->picture_structure == PICT_FRAME && s->frame_pred_frame_dct) {
motion_type = MT_FRAME;
} else {
motion_type = get_bits(&s->gb, 2);
@@ -877,7 +898,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
/* motion vectors */
s->mv_dir = (mb_type >> 13) & 3;
- ff_dlog(s->avctx, "motion_type=%d\n", motion_type);
+ ff_tlog(s->avctx, "motion_type=%d\n", motion_type);
switch (motion_type) {
case MT_FRAME: /* or MT_16X8 */
if (s->picture_structure == PICT_FRAME) {
@@ -934,16 +955,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
s->last_mv[i][j][0]);
s->last_mv[i][j][0] = val;
s->mv[i][j][0] = val;
- ff_dlog(s->avctx, "fmx=%d\n", val);
+ ff_tlog(s->avctx, "fmx=%d\n", val);
val = mpeg_decode_motion(s, s->mpeg_f_code[i][1],
s->last_mv[i][j][1] >> 1);
- s->last_mv[i][j][1] = val << 1;
+ s->last_mv[i][j][1] = 2 * val;
s->mv[i][j][1] = val;
- ff_dlog(s->avctx, "fmy=%d\n", val);
+ ff_tlog(s->avctx, "fmy=%d\n", val);
}
}
}
} else {
+ 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)) {
@@ -960,6 +982,10 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
break;
case MT_DMV:
+ if (s->progressive_sequence){
+ av_log(s->avctx, AV_LOG_ERROR, "MT_DMV in progressive_sequence\n");
+ return AVERROR_INVALIDDATA;
+ }
s->mv_type = MV_TYPE_DMV;
for (i = 0; i < 2; i++) {
if (USES_LIST(mb_type, i)) {
@@ -1028,17 +1054,13 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
if (cbp <= 0) {
av_log(s->avctx, AV_LOG_ERROR,
- "invalid cbp at %d %d\n", s->mb_x, s->mb_y);
+ "invalid cbp %d at %d %d\n", cbp, s->mb_x, s->mb_y);
return AVERROR_INVALIDDATA;
}
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
// if 1, we memcpy blocks in xvmcvideo
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration > 1)
+ if ((CONFIG_MPEG1_XVMC_HWACCEL || CONFIG_MPEG2_XVMC_HWACCEL) && s->pack_pblocks)
ff_xvmc_pack_pblocks(s, cbp);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
if (s->avctx->flags2 & CODEC_FLAG2_FAST) {
@@ -1101,6 +1123,11 @@ static av_cold int mpeg_decode_init(AVCodecContext *avctx)
ff_mpv_decode_defaults(s2);
+ 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);
+
s->mpeg_enc_ctx.avctx = avctx;
/* we need some permutation to store matrices,
@@ -1114,10 +1141,6 @@ static av_cold int mpeg_decode_init(AVCodecContext *avctx)
s->repeat_field = 0;
s->mpeg_enc_ctx.codec_id = avctx->codec->id;
avctx->color_range = AVCOL_RANGE_MPEG;
- if (avctx->codec->id == AV_CODEC_ID_MPEG1VIDEO)
- avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
- else
- avctx->chroma_sample_location = AVCHROMA_LOC_LEFT;
return 0;
}
@@ -1137,11 +1160,8 @@ static int mpeg_decode_update_thread_context(AVCodecContext *avctx,
if (err)
return err;
- if (!ctx->mpeg_enc_ctx_allocated) {
- // copy the whole context after the initial MpegEncContext structure
- memcpy(ctx, ctx_from, sizeof(*ctx));
- memset(&ctx->mpeg_enc_ctx, 0, sizeof(ctx->mpeg_enc_ctx));
- }
+ if (!ctx->mpeg_enc_ctx_allocated)
+ memcpy(s + 1, s1 + 1, sizeof(Mpeg1Context) - sizeof(MpegEncContext));
if (!(s->pict_type == AV_PICTURE_TYPE_B || s->low_delay))
s->picture_number++;
@@ -1161,15 +1181,26 @@ static void quant_matrix_rebuild(uint16_t *matrix, const uint8_t *old_perm,
matrix[new_perm[i]] = temp_matrix[old_perm[i]];
}
-#if FF_API_XVMC
-static const enum AVPixelFormat pixfmt_xvmc_mpg2_420[] = {
- AV_PIX_FMT_XVMC_MPEG2_IDCT,
- AV_PIX_FMT_XVMC_MPEG2_MC,
+static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = {
+#if CONFIG_MPEG1_XVMC_HWACCEL
+ AV_PIX_FMT_XVMC,
+#endif
+#if CONFIG_MPEG1_VDPAU_HWACCEL
+ AV_PIX_FMT_VDPAU_MPEG1,
+ AV_PIX_FMT_VDPAU,
+#endif
+ AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
};
-#endif /* FF_API_XVMC */
-static const enum AVPixelFormat mpeg12_hwaccel_pixfmt_list_420[] = {
+static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = {
+#if CONFIG_MPEG2_XVMC_HWACCEL
+ AV_PIX_FMT_XVMC,
+#endif
+#if CONFIG_MPEG2_VDPAU_HWACCEL
+ AV_PIX_FMT_VDPAU_MPEG2,
+ AV_PIX_FMT_VDPAU,
+#endif
#if CONFIG_MPEG2_DXVA2_HWACCEL
AV_PIX_FMT_DXVA2_VLD,
#endif
@@ -1179,9 +1210,6 @@ static const enum AVPixelFormat mpeg12_hwaccel_pixfmt_list_420[] = {
#if CONFIG_MPEG2_VAAPI_HWACCEL
AV_PIX_FMT_VAAPI_VLD,
#endif
-#if CONFIG_MPEG1_VDPAU_HWACCEL | CONFIG_MPEG2_VDPAU_HWACCEL
- AV_PIX_FMT_VDPAU,
-#endif
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
};
@@ -1196,27 +1224,47 @@ static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = {
AV_PIX_FMT_NONE
};
+static inline int uses_vdpau(AVCodecContext *avctx) {
+ return avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG1 || avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG2;
+}
+
static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx)
{
Mpeg1Context *s1 = avctx->priv_data;
MpegEncContext *s = &s1->mpeg_enc_ctx;
const enum AVPixelFormat *pix_fmts;
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- if (avctx->xvmc_acceleration)
- return ff_get_format(avctx, pixfmt_xvmc_mpg2_420);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
+ if (CONFIG_GRAY && (avctx->flags & CODEC_FLAG_GRAY))
+ return AV_PIX_FMT_GRAY8;
if (s->chroma_format < 2)
- pix_fmts = mpeg12_hwaccel_pixfmt_list_420;
+ pix_fmts = avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO ?
+ mpeg1_hwaccel_pixfmt_list_420 :
+ mpeg2_hwaccel_pixfmt_list_420;
else if (s->chroma_format == 2)
pix_fmts = mpeg12_pixfmt_list_422;
else
pix_fmts = mpeg12_pixfmt_list_444;
- return ff_get_format(avctx, pix_fmts);
+ return ff_thread_get_format(avctx, pix_fmts);
+}
+
+static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx)
+{
+ // until then pix_fmt may be changed right after codec init
+ if (avctx->hwaccel || uses_vdpau(avctx))
+ if (avctx->idct_algo == FF_IDCT_AUTO)
+ avctx->idct_algo = FF_IDCT_SIMPLE;
+
+ if (avctx->hwaccel && avctx->pix_fmt == AV_PIX_FMT_XVMC) {
+ Mpeg1Context *s1 = avctx->priv_data;
+ MpegEncContext *s = &s1->mpeg_enc_ctx;
+
+ s->pack_pblocks = 1;
+#if FF_API_XVMC
+ avctx->xvmc_acceleration = 2;
+#endif /* FF_API_XVMC */
+ }
}
/* Call this function when we know all parameters.
@@ -1228,27 +1276,83 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
uint8_t old_permutation[64];
int ret;
+ if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
+ // MPEG-1 aspect
+ avctx->sample_aspect_ratio = av_d2q(1.0 / ff_mpeg1_aspect[s->aspect_ratio_info], 255);
+ } else { // MPEG-2
+ // MPEG-2 aspect
+ if (s->aspect_ratio_info > 1) {
+ AVRational dar =
+ av_mul_q(av_div_q(ff_mpeg2_aspect[s->aspect_ratio_info],
+ (AVRational) { s1->pan_scan.width,
+ s1->pan_scan.height }),
+ (AVRational) { s->width, s->height });
+
+ /* We ignore the spec here and guess a bit as reality does not
+ * match the spec, see for example res_change_ffmpeg_aspect.ts
+ * and sequence-display-aspect.mpg.
+ * issue1613, 621, 562 */
+ if ((s1->pan_scan.width == 0) || (s1->pan_scan.height == 0) ||
+ (av_cmp_q(dar, (AVRational) { 4, 3 }) &&
+ av_cmp_q(dar, (AVRational) { 16, 9 }))) {
+ s->avctx->sample_aspect_ratio =
+ av_div_q(ff_mpeg2_aspect[s->aspect_ratio_info],
+ (AVRational) { s->width, s->height });
+ } else {
+ s->avctx->sample_aspect_ratio =
+ av_div_q(ff_mpeg2_aspect[s->aspect_ratio_info],
+ (AVRational) { s1->pan_scan.width, s1->pan_scan.height });
+// issue1613 4/3 16/9 -> 16/9
+// res_change_ffmpeg_aspect.ts 4/3 225/44 ->4/3
+// widescreen-issue562.mpg 4/3 16/9 -> 16/9
+// s->avctx->sample_aspect_ratio = av_mul_q(s->avctx->sample_aspect_ratio, (AVRational) {s->width, s->height});
+ ff_dlog(avctx, "aspect A %d/%d\n",
+ ff_mpeg2_aspect[s->aspect_ratio_info].num,
+ ff_mpeg2_aspect[s->aspect_ratio_info].den);
+ ff_dlog(avctx, "aspect B %d/%d\n", s->avctx->sample_aspect_ratio.num,
+ s->avctx->sample_aspect_ratio.den);
+ }
+ } else {
+ s->avctx->sample_aspect_ratio =
+ ff_mpeg2_aspect[s->aspect_ratio_info];
+ }
+ } // MPEG-2
+
+ if (av_image_check_sar(s->width, s->height,
+ avctx->sample_aspect_ratio) < 0) {
+ av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
+ avctx->sample_aspect_ratio.num,
+ avctx->sample_aspect_ratio.den);
+ avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
+ }
+
if ((s1->mpeg_enc_ctx_allocated == 0) ||
avctx->coded_width != s->width ||
avctx->coded_height != s->height ||
s1->save_width != s->width ||
s1->save_height != s->height ||
- s1->save_aspect_info != s->aspect_ratio_info ||
- s1->save_progressive_seq != s->progressive_sequence ||
+ 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) {
ParseContext pc = s->parse_context;
s->parse_context.buffer = 0;
ff_mpv_common_end(s);
s->parse_context = pc;
+ s1->mpeg_enc_ctx_allocated = 0;
}
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
- avctx->bit_rate = s->bit_rate;
- s1->save_aspect_info = s->aspect_ratio_info;
+ if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->bit_rate) {
+ avctx->rc_max_rate = s->bit_rate;
+ } else if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && s->bit_rate &&
+ (s->bit_rate != 0x3FFFF*400 || s->vbv_delay != 0xFFFF)) {
+ avctx->bit_rate = s->bit_rate;
+ }
+ s1->save_aspect = s->avctx->sample_aspect_ratio;
s1->save_width = s->width;
s1->save_height = s->height;
s1->save_progressive_seq = s->progressive_sequence;
@@ -1260,66 +1364,27 @@ static int mpeg_decode_postinit(AVCodecContext *avctx)
if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
// MPEG-1 fps
avctx->framerate = ff_mpeg12_frame_rate_tab[s->frame_rate_index];
- // MPEG-1 aspect
- avctx->sample_aspect_ratio = av_d2q(1.0 / ff_mpeg1_aspect[s->aspect_ratio_info], 255);
avctx->ticks_per_frame = 1;
+
+ avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
} else { // MPEG-2
// MPEG-2 fps
av_reduce(&s->avctx->framerate.num,
&s->avctx->framerate.den,
- ff_mpeg12_frame_rate_tab[s->frame_rate_index].num * s1->frame_rate_ext.num * 2,
+ ff_mpeg12_frame_rate_tab[s->frame_rate_index].num * s1->frame_rate_ext.num,
ff_mpeg12_frame_rate_tab[s->frame_rate_index].den * s1->frame_rate_ext.den,
1 << 30);
avctx->ticks_per_frame = 2;
- // MPEG-2 aspect
- if (s->aspect_ratio_info > 1) {
- AVRational dar =
- av_mul_q(av_div_q(ff_mpeg2_aspect[s->aspect_ratio_info],
- (AVRational) { s1->pan_scan.width,
- s1->pan_scan.height }),
- (AVRational) { s->width, s->height });
- /* We ignore the spec here and guess a bit as reality does not
- * match the spec, see for example res_change_ffmpeg_aspect.ts
- * and sequence-display-aspect.mpg.
- * issue1613, 621, 562 */
- if ((s1->pan_scan.width == 0) || (s1->pan_scan.height == 0) ||
- (av_cmp_q(dar, (AVRational) { 4, 3 }) &&
- av_cmp_q(dar, (AVRational) { 16, 9 }))) {
- s->avctx->sample_aspect_ratio =
- av_div_q(ff_mpeg2_aspect[s->aspect_ratio_info],
- (AVRational) { s->width, s->height });
- } else {
- s->avctx->sample_aspect_ratio =
- av_div_q(ff_mpeg2_aspect[s->aspect_ratio_info],
- (AVRational) { s1->pan_scan.width, s1->pan_scan.height });
-// issue1613 4/3 16/9 -> 16/9
-// res_change_ffmpeg_aspect.ts 4/3 225/44 ->4/3
-// widescreen-issue562.mpg 4/3 16/9 -> 16/9
-// s->avctx->sample_aspect_ratio = av_mul_q(s->avctx->sample_aspect_ratio, (AVRational) {s->width, s->height});
- ff_dlog(avctx, "A %d/%d\n",
- ff_mpeg2_aspect[s->aspect_ratio_info].num,
- ff_mpeg2_aspect[s->aspect_ratio_info].den);
- ff_dlog(avctx, "B %d/%d\n", s->avctx->sample_aspect_ratio.num,
- s->avctx->sample_aspect_ratio.den);
- }
- } else {
- s->avctx->sample_aspect_ratio =
- ff_mpeg2_aspect[s->aspect_ratio_info];
+ switch (s->chroma_format) {
+ case 1: avctx->chroma_sample_location = AVCHROMA_LOC_LEFT; break;
+ case 2:
+ case 3: avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; break;
}
} // MPEG-2
- ff_set_sar(s->avctx, s->avctx->sample_aspect_ratio);
-
avctx->pix_fmt = mpeg_get_pixelformat(avctx);
- // until then pix_fmt may be changed right after codec init
-#if FF_API_XVMC
- if ((avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT ||
- avctx->hwaccel) && avctx->idct_algo == FF_IDCT_AUTO)
-#else
- if (avctx->hwaccel && avctx->idct_algo == FF_IDCT_AUTO)
-#endif /* FF_API_XVMC */
- avctx->idct_algo = FF_IDCT_SIMPLE;
+ setup_hwaccel_for_pixfmt(avctx);
/* Quantization matrices may need reordering
* if DCT permutation is changed. */
@@ -1354,20 +1419,23 @@ static int mpeg1_decode_picture(AVCodecContext *avctx, const uint8_t *buf,
return AVERROR_INVALIDDATA;
vbv_delay = get_bits(&s->gb, 16);
+ s->vbv_delay = vbv_delay;
if (s->pict_type == AV_PICTURE_TYPE_P ||
s->pict_type == AV_PICTURE_TYPE_B) {
s->full_pel[0] = get_bits1(&s->gb);
f_code = get_bits(&s->gb, 3);
- if (f_code == 0 && (avctx->err_recognition & AV_EF_BITSTREAM))
+ if (f_code == 0 && (avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)))
return AVERROR_INVALIDDATA;
+ f_code += !f_code;
s->mpeg_f_code[0][0] = f_code;
s->mpeg_f_code[0][1] = f_code;
}
if (s->pict_type == AV_PICTURE_TYPE_B) {
s->full_pel[1] = get_bits1(&s->gb);
f_code = get_bits(&s->gb, 3);
- if (f_code == 0 && (avctx->err_recognition & AV_EF_BITSTREAM))
+ if (f_code == 0 && (avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)))
return AVERROR_INVALIDDATA;
+ f_code += !f_code;
s->mpeg_f_code[1][0] = f_code;
s->mpeg_f_code[1][1] = f_code;
}
@@ -1400,7 +1468,7 @@ static void mpeg_decode_sequence_extension(Mpeg1Context *s1)
s->height |= (vert_size_ext << 12);
bit_rate_ext = get_bits(&s->gb, 12); /* XXX: handle it */
s->bit_rate += (bit_rate_ext << 18) * 400;
- skip_bits1(&s->gb); /* marker */
+ check_marker(&s->gb, "after bit rate extension");
s->avctx->rc_buffer_size += get_bits(&s->gb, 8) * 1024 * 16 << 10;
s->low_delay = get_bits1(&s->gb);
@@ -1415,8 +1483,8 @@ static void mpeg_decode_sequence_extension(Mpeg1Context *s1)
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
av_log(s->avctx, AV_LOG_DEBUG,
- "profile: %d, level: %d vbv buffer: %d, bitrate:%d\n",
- s->avctx->profile, s->avctx->level,
+ "profile: %d, level: %d ps: %d cf:%d vbv buffer: %d, bitrate:%d\n",
+ s->avctx->profile, s->avctx->level, s->progressive_sequence, s->chroma_format,
s->avctx->rc_buffer_size, s->bit_rate);
}
@@ -1491,7 +1559,7 @@ static int load_matrix(MpegEncContext *s, uint16_t matrix0[64],
return AVERROR_INVALIDDATA;
}
if (intra && i == 0 && v != 8) {
- av_log(s->avctx, AV_LOG_ERROR, "intra matrix invalid, ignoring\n");
+ av_log(s->avctx, AV_LOG_DEBUG, "intra matrix specifies invalid DC quantizer %d, ignoring\n", v);
v = 8; // needed by pink.mpg / issue1046
}
matrix0[j] = v;
@@ -1537,6 +1605,11 @@ static void mpeg_decode_picture_coding_extension(Mpeg1Context *s1)
s->current_picture.f->pict_type = s->pict_type;
s->current_picture.f->key_frame = s->pict_type == AV_PICTURE_TYPE_I;
}
+ s->mpeg_f_code[0][0] += !s->mpeg_f_code[0][0];
+ s->mpeg_f_code[0][1] += !s->mpeg_f_code[0][1];
+ s->mpeg_f_code[1][0] += !s->mpeg_f_code[1][0];
+ s->mpeg_f_code[1][1] += !s->mpeg_f_code[1][1];
+
s->intra_dc_precision = get_bits(&s->gb, 2);
s->picture_structure = get_bits(&s->gb, 2);
s->top_field_first = get_bits1(&s->gb);
@@ -1549,32 +1622,6 @@ static void mpeg_decode_picture_coding_extension(Mpeg1Context *s1)
s->chroma_420_type = get_bits1(&s->gb);
s->progressive_frame = get_bits1(&s->gb);
- if (s->progressive_sequence && !s->progressive_frame) {
- s->progressive_frame = 1;
- av_log(s->avctx, AV_LOG_ERROR,
- "interlaced frame in progressive sequence, ignoring\n");
- }
-
- if (s->picture_structure == 0 ||
- (s->progressive_frame && s->picture_structure != PICT_FRAME)) {
- av_log(s->avctx, AV_LOG_ERROR,
- "picture_structure %d invalid, ignoring\n",
- s->picture_structure);
- s->picture_structure = PICT_FRAME;
- }
-
- if (s->progressive_sequence && !s->frame_pred_frame_dct)
- av_log(s->avctx, AV_LOG_WARNING, "invalid frame_pred_frame_dct\n");
-
- if (s->picture_structure == PICT_FRAME) {
- s->first_field = 0;
- s->v_edge_pos = 16 * s->mb_height;
- } else {
- s->first_field ^= 1;
- s->v_edge_pos = 8 * s->mb_height;
- memset(s->mbskip_table, 0, s->mb_stride * s->mb_height);
- }
-
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);
@@ -1689,16 +1736,6 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
return ret;
}
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
-// ff_mpv_frame_start will call this function too,
-// but we need to call it on every field
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
- if (ff_xvmc_field_start(s, avctx) < 0)
- return -1;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
-
return 0;
}
@@ -1715,15 +1752,18 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
const uint8_t **buf, int buf_size)
{
AVCodecContext *avctx = s->avctx;
+ const int lowres = s->avctx->lowres;
const int field_pic = s->picture_structure != PICT_FRAME;
int ret;
s->resync_mb_x =
s->resync_mb_y = -1;
- assert(mb_y < s->mb_height);
+ av_assert0(mb_y < s->mb_height);
init_get_bits(&s->gb, *buf, buf_size * 8);
+ if (s->codec_id != AV_CODEC_ID_MPEG1VIDEO && s->mb_height > 2800/16)
+ skip_bits(&s->gb, 3);
ff_mpeg1_clean_buffers(s);
s->interlaced_dct = 0;
@@ -1736,8 +1776,8 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
}
/* extra slice info */
- while (get_bits1(&s->gb) != 0)
- skip_bits(&s->gb, 8);
+ if (skip_1stop_8data_bits(&s->gb) < 0)
+ return AVERROR_INVALIDDATA;
s->mb_x = 0;
@@ -1767,7 +1807,7 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
return AVERROR_INVALIDDATA;
}
- if (avctx->hwaccel) {
+ if (avctx->hwaccel && avctx->hwaccel->decode_slice) {
const uint8_t *buf_end, *buf_start = *buf - 4; /* include start_code */
int start_code = -1;
buf_end = avpriv_find_start_code(buf_start + 2, *buf + buf_size, &start_code);
@@ -1807,13 +1847,9 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y,
}
for (;;) {
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
// If 1, we memcpy blocks in xvmcvideo.
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration > 1)
+ if ((CONFIG_MPEG1_XVMC_HWACCEL || CONFIG_MPEG2_XVMC_HWACCEL) && s->pack_pblocks)
ff_xvmc_init_block(s); // set s->block
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
if ((ret = mpeg_decode_mb(s, s->block)) < 0)
return ret;
@@ -1845,22 +1881,22 @@ FF_ENABLE_DEPRECATION_WARNINGS
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];
- assert(s->field_select[dir][i] == 0 ||
- s->field_select[dir][i] == 1);
+ av_assert2(s->field_select[dir][i] == 0 ||
+ s->field_select[dir][i] == 1);
}
xy += wrap;
b8_xy += 2;
}
}
- s->dest[0] += 16;
- s->dest[1] += 16 >> s->chroma_x_shift;
- s->dest[2] += 16 >> s->chroma_x_shift;
+ s->dest[0] += 16 >> lowres;
+ s->dest[1] +=(16 >> lowres) >> s->chroma_x_shift;
+ s->dest[2] +=(16 >> lowres) >> s->chroma_x_shift;
ff_mpv_decode_mb(s, s->block);
if (++s->mb_x >= s->mb_width) {
- const int mb_size = 16;
+ const int mb_size = 16 >> s->avctx->lowres;
ff_mpeg_draw_horiz_band(s, mb_size * (s->mb_y >> field_pic), mb_size);
ff_mpv_report_decode_progress(s);
@@ -1878,15 +1914,36 @@ FF_ENABLE_DEPRECATION_WARNINGS
s->progressive_frame == 0
/* vbv_delay == 0xBBB || 0xE10 */;
+ if (left >= 32 && !is_d10) {
+ GetBitContext gb = s->gb;
+ align_get_bits(&gb);
+ if (show_bits(&gb, 24) == 0x060E2B) {
+ av_log(avctx, AV_LOG_DEBUG, "Invalid MXF data found in video stream\n");
+ is_d10 = 1;
+ }
+ }
+
if (left < 0 ||
(left && show_bits(&s->gb, FFMIN(left, 23)) && !is_d10) ||
- ((avctx->err_recognition & AV_EF_BUFFER) && left > 8)) {
+ ((avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE)) && left > 8)) {
av_log(avctx, AV_LOG_ERROR, "end mismatch left=%d %0X\n",
left, show_bits(&s->gb, FFMIN(left, 23)));
return AVERROR_INVALIDDATA;
} else
goto eos;
}
+ // There are some files out there which are missing the last slice
+ // in cases where the slice is completely outside the visible
+ // area, we detect this here instead of running into the end expecting
+ // more data
+ if (s->mb_y >= ((s->height + 15) >> 4) &&
+ s->progressive_frame &&
+ !s->progressive_sequence &&
+ get_bits_left(&s->gb) <= 8 &&
+ get_bits_left(&s->gb) >= 0 &&
+ s->mb_skip_run == -1 &&
+ show_bits(&s->gb, 8) == 0)
+ goto eos;
ff_init_block_index(s);
}
@@ -1952,8 +2009,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
}
eos: // end of slice
+ if (get_bits_left(&s->gb) < 0) {
+ av_log(s, AV_LOG_ERROR, "overread %d\n", -get_bits_left(&s->gb));
+ return AVERROR_INVALIDDATA;
+ }
*buf += (get_bits_count(&s->gb) - 1) / 8;
- ff_dlog(s, "y %d %d %d %d\n", s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y);
+ ff_dlog(s, "Slice start:%d %d end:%d %d\n", s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y);
return 0;
}
@@ -1993,7 +2054,10 @@ static int slice_decode_thread(AVCodecContext *c, void *arg)
start_code = -1;
buf = avpriv_find_start_code(buf, s->gb.buffer_end, &start_code);
- mb_y = (start_code - SLICE_MIN_START_CODE) << field_pic;
+ mb_y = start_code - SLICE_MIN_START_CODE;
+ if (s->codec_id != AV_CODEC_ID_MPEG1VIDEO && s->mb_height > 2800/16)
+ mb_y += (*buf&0xE0)<<2;
+ mb_y <<= field_pic;
if (s->picture_structure == PICT_BOTTOM_FIELD)
mb_y++;
if (mb_y < 0 || mb_y >= s->end_mb_y)
@@ -2019,15 +2083,8 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict)
"hardware accelerator failed to decode picture\n");
}
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
- ff_xvmc_field_end(s);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
-
/* end of slice reached */
- if (/* s->mb_y << field_pic == s->mb_height && */ !s->first_field) {
+ if (/* s->mb_y << field_pic == s->mb_height && */ !s->first_field && !s1->first_slice) {
/* end of image */
ff_er_frame_end(&s->er);
@@ -2038,7 +2095,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
int ret = av_frame_ref(pict, s->current_picture_ptr->f);
if (ret < 0)
return ret;
- ff_print_debug_info(s, s->current_picture_ptr);
+ ff_print_debug_info(s, s->current_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_QSCALE_TYPE_MPEG2);
} else {
if (avctx->active_thread_type & FF_THREAD_FRAME)
s->picture_number++;
@@ -2048,7 +2106,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
int ret = av_frame_ref(pict, s->last_picture_ptr->f);
if (ret < 0)
return ret;
- ff_print_debug_info(s, s->last_picture_ptr);
+ ff_print_debug_info(s, s->last_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_QSCALE_TYPE_MPEG2);
}
}
@@ -2073,24 +2132,23 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx,
if (width == 0 || height == 0) {
av_log(avctx, AV_LOG_WARNING,
"Invalid horizontal or vertical size value.\n");
- if (avctx->err_recognition & AV_EF_BITSTREAM)
+ if (avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT))
return AVERROR_INVALIDDATA;
}
s->aspect_ratio_info = get_bits(&s->gb, 4);
if (s->aspect_ratio_info == 0) {
av_log(avctx, AV_LOG_ERROR, "aspect ratio has forbidden 0 value\n");
- if (avctx->err_recognition & AV_EF_BITSTREAM)
+ if (avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_COMPLIANT))
return AVERROR_INVALIDDATA;
}
s->frame_rate_index = get_bits(&s->gb, 4);
if (s->frame_rate_index == 0 || s->frame_rate_index > 13) {
av_log(avctx, AV_LOG_WARNING,
"frame_rate_index %d is invalid\n", s->frame_rate_index);
- return AVERROR_INVALIDDATA;
+ s->frame_rate_index = 1;
}
s->bit_rate = get_bits(&s->gb, 18) * 400;
- if (get_bits1(&s->gb) == 0) { /* marker */
- av_log(avctx, AV_LOG_ERROR, "Marker in sequence header missing\n");
+ if (check_marker(&s->gb, "in sequence header") == 0) {
return AVERROR_INVALIDDATA;
}
s->width = width;
@@ -2130,17 +2188,19 @@ static int mpeg1_decode_sequence(AVCodecContext *avctx,
s->progressive_sequence = 1;
s->progressive_frame = 1;
s->picture_structure = PICT_FRAME;
+ s->first_field = 0;
s->frame_pred_frame_dct = 1;
s->chroma_format = 1;
s->codec_id =
s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO;
s->out_format = FMT_MPEG1;
+ s->swap_uv = 0; // AFAIK VCR2 does not have SEQ_HEADER
if (s->avctx->flags & CODEC_FLAG_LOW_DELAY)
s->low_delay = 1;
if (s->avctx->debug & FF_DEBUG_PICT_INFO)
- av_log(s->avctx, AV_LOG_DEBUG, "vbv buffer: %d, bitrate:%d\n",
- s->avctx->rc_buffer_size, s->bit_rate);
+ av_log(s->avctx, AV_LOG_DEBUG, "vbv buffer: %d, bitrate:%d, aspect_ratio_info: %d \n",
+ s->avctx->rc_buffer_size, s->bit_rate, s->aspect_ratio_info);
return 0;
}
@@ -2155,6 +2215,7 @@ static int vcr2_init_sequence(AVCodecContext *avctx)
s->out_format = FMT_MPEG1;
if (s1->mpeg_enc_ctx_allocated) {
ff_mpv_common_end(s);
+ s1->mpeg_enc_ctx_allocated = 0;
}
s->width = avctx->coded_width;
s->height = avctx->coded_height;
@@ -2162,14 +2223,7 @@ static int vcr2_init_sequence(AVCodecContext *avctx)
s->low_delay = 1;
avctx->pix_fmt = mpeg_get_pixelformat(avctx);
-
-#if FF_API_XVMC
- if ((avctx->pix_fmt == AV_PIX_FMT_XVMC_MPEG2_IDCT || avctx->hwaccel) &&
- avctx->idct_algo == FF_IDCT_AUTO)
-#else
- if (avctx->hwaccel && avctx->idct_algo == FF_IDCT_AUTO)
-#endif /* FF_API_XVMC */
- avctx->idct_algo = FF_IDCT_SIMPLE;
+ setup_hwaccel_for_pixfmt(avctx);
ff_mpv_idct_init(s);
if ((ret = ff_mpv_common_init(s)) < 0)
@@ -2190,9 +2244,15 @@ static int vcr2_init_sequence(AVCodecContext *avctx)
s->progressive_sequence = 1;
s->progressive_frame = 1;
s->picture_structure = PICT_FRAME;
+ s->first_field = 0;
s->frame_pred_frame_dct = 1;
s->chroma_format = 1;
- s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO;
+ if (s->codec_tag == AV_RL32("BW10")) {
+ s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO;
+ } else {
+ s->swap_uv = 1; // in case of xvmc we need to swap uv for each MB
+ s->codec_id = s->avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO;
+ }
s1->save_width = s->width;
s1->save_height = s->height;
s1->save_progressive_seq = s->progressive_sequence;
@@ -2255,9 +2315,25 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx,
static void mpeg_decode_user_data(AVCodecContext *avctx,
const uint8_t *p, int buf_size)
{
+ Mpeg1Context *s = avctx->priv_data;
const uint8_t *buf_end = p + buf_size;
Mpeg1Context *s1 = avctx->priv_data;
+#if 0
+ int i;
+ for(i=0; !(!p[i-2] && !p[i-1] && p[i]==1) && i<buf_size; i++){
+ av_log(avctx, AV_LOG_ERROR, "%c", p[i]);
+ }
+ av_log(avctx, AV_LOG_ERROR, "\n");
+#endif
+
+ if (buf_size > 29){
+ int i;
+ for(i=0; i<20; i++)
+ if (!memcmp(p+i, "\0TMPGEXS\0", 9)){
+ s->tmpgexs= 1;
+ }
+ }
/* we parse the DTG active format information */
if (buf_end - p >= 5 &&
p[0] == 'D' && p[1] == 'T' && p[2] == 'G' && p[3] == '1') {
@@ -2316,32 +2392,26 @@ static void mpeg_decode_gop(AVCodecContext *avctx,
{
Mpeg1Context *s1 = avctx->priv_data;
MpegEncContext *s = &s1->mpeg_enc_ctx;
-
- int time_code_hours, time_code_minutes;
- int time_code_seconds, time_code_pictures;
int broken_link;
+ int64_t tc;
init_get_bits(&s->gb, buf, buf_size * 8);
- skip_bits1(&s->gb); /* drop_frame_flag */
-
- time_code_hours = get_bits(&s->gb, 5);
- time_code_minutes = get_bits(&s->gb, 6);
- skip_bits1(&s->gb); // marker bit
- time_code_seconds = get_bits(&s->gb, 6);
- time_code_pictures = get_bits(&s->gb, 6);
+ tc = avctx->timecode_frame_start = get_bits(&s->gb, 25);
- s1->closed_gop = get_bits1(&s->gb);
+ s->closed_gop = get_bits1(&s->gb);
/* broken_link indicate that after editing the
* reference frames of the first B-Frames after GOP I-Frame
* are missing (open gop) */
broken_link = get_bits1(&s->gb);
- if (s->avctx->debug & FF_DEBUG_PICT_INFO)
+ if (s->avctx->debug & FF_DEBUG_PICT_INFO) {
+ char tcbuf[AV_TIMECODE_STR_SIZE];
+ av_timecode_make_mpeg_tc_string(tcbuf, tc);
av_log(s->avctx, AV_LOG_DEBUG,
- "GOP (%2d:%02d:%02d.[%02d]) closed_gop=%d broken_link=%d\n",
- time_code_hours, time_code_minutes, time_code_seconds,
- time_code_pictures, s1->closed_gop, broken_link);
+ "GOP (%s) closed_gop=%d broken_link=%d\n",
+ tcbuf, s->closed_gop, broken_link);
+ }
}
static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
@@ -2353,6 +2423,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
const uint8_t *buf_end = buf + buf_size;
int ret, input_size;
int last_code = 0, skip_frame = 0;
+ int picture_start_code_seen = 0;
for (;;) {
/* find next start code */
@@ -2364,6 +2435,7 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
(avctx->active_thread_type & FF_THREAD_SLICE) &&
!avctx->hwaccel) {
int i;
+ av_assert0(avctx->thread_count > 1);
avctx->execute(avctx, slice_decode_thread,
&s2->thread_context[0], NULL,
@@ -2372,6 +2444,10 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
s2->er.error_count += s2->thread_context[i]->er.error_count;
}
+ if ((CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER)
+ && uses_vdpau(avctx))
+ ff_vdpau_mpeg_picture_complete(s2, buf, buf_size, s->slice_count);
+
ret = slice_end(avctx, picture);
if (ret < 0)
return ret;
@@ -2382,13 +2458,17 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
}
}
s2->pict_type = 0;
+
+ if (avctx->err_recognition & AV_EF_EXPLODE && s2->er.error_count)
+ return AVERROR_INVALIDDATA;
+
return FFMAX(0, buf_ptr - buf - s2->parse_context.last_index);
}
input_size = buf_end - buf_ptr;
if (avctx->debug & FF_DEBUG_STARTCODE)
- av_log(avctx, AV_LOG_DEBUG, "%3"PRIX32" at %td left %d\n",
+ av_log(avctx, AV_LOG_DEBUG, "%3"PRIX32" at %"PTRDIFF_SPECIFIER" left %d\n",
start_code, buf_ptr - buf, input_size);
/* prepare data for next start code */
@@ -2396,7 +2476,8 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
case SEQ_START_CODE:
if (last_code == 0) {
mpeg1_decode_sequence(avctx, buf_ptr, input_size);
- s->sync = 1;
+ if (buf != avctx->extradata)
+ s->sync = 1;
} else {
av_log(avctx, AV_LOG_ERROR,
"ignoring SEQ_START_CODE after %X\n", last_code);
@@ -2406,12 +2487,24 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
break;
case PICTURE_START_CODE:
+ if (picture_start_code_seen && s2->picture_structure == PICT_FRAME) {
+ /* If it's a frame picture, there can't be more than one picture header.
+ Yet, it does happen and we need to handle it. */
+ av_log(avctx, AV_LOG_WARNING, "ignoring extra picture following a frame-picture\n");
+ break;
+ }
+ picture_start_code_seen = 1;
+
if (s2->width <= 0 || s2->height <= 0) {
av_log(avctx, AV_LOG_ERROR, "Invalid frame dimensions %dx%d.\n",
s2->width, s2->height);
return AVERROR_INVALIDDATA;
}
+ if (s->tmpgexs){
+ s2->intra_dc_precision= 3;
+ s2->intra_matrix[0]= 1;
+ }
if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) &&
!avctx->hwaccel && s->slice_count) {
int i;
@@ -2495,14 +2588,50 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
break;
default:
if (start_code >= SLICE_MIN_START_CODE &&
+ start_code <= SLICE_MAX_START_CODE && last_code == PICTURE_START_CODE) {
+ if (s2->progressive_sequence && !s2->progressive_frame) {
+ s2->progressive_frame = 1;
+ av_log(s2->avctx, AV_LOG_ERROR,
+ "interlaced frame in progressive sequence, ignoring\n");
+ }
+
+ if (s2->picture_structure == 0 ||
+ (s2->progressive_frame && s2->picture_structure != PICT_FRAME)) {
+ av_log(s2->avctx, AV_LOG_ERROR,
+ "picture_structure %d invalid, ignoring\n",
+ s2->picture_structure);
+ s2->picture_structure = PICT_FRAME;
+ }
+
+ if (s2->progressive_sequence && !s2->frame_pred_frame_dct)
+ av_log(s2->avctx, AV_LOG_WARNING, "invalid frame_pred_frame_dct\n");
+
+ if (s2->picture_structure == PICT_FRAME) {
+ s2->first_field = 0;
+ s2->v_edge_pos = 16 * s2->mb_height;
+ } else {
+ s2->first_field ^= 1;
+ s2->v_edge_pos = 8 * s2->mb_height;
+ memset(s2->mbskip_table, 0, s2->mb_stride * s2->mb_height);
+ }
+ }
+ if (start_code >= SLICE_MIN_START_CODE &&
start_code <= SLICE_MAX_START_CODE && last_code != 0) {
const int field_pic = s2->picture_structure != PICT_FRAME;
- int mb_y = (start_code - SLICE_MIN_START_CODE) << field_pic;
+ int mb_y = start_code - SLICE_MIN_START_CODE;
last_code = SLICE_MIN_START_CODE;
+ if (s2->codec_id != AV_CODEC_ID_MPEG1VIDEO && s2->mb_height > 2800/16)
+ mb_y += (*buf_ptr&0xE0)<<2;
+ mb_y <<= field_pic;
if (s2->picture_structure == PICT_BOTTOM_FIELD)
mb_y++;
+ if (buf_end - buf_ptr < 2) {
+ av_log(s2->avctx, AV_LOG_ERROR, "slice too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
if (mb_y >= s2->mb_height) {
av_log(s2->avctx, AV_LOG_ERROR,
"slice below image (%d >= %d)\n", mb_y, s2->mb_height);
@@ -2513,13 +2642,13 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
/* Skip B-frames if we do not have reference frames and
* GOP is not closed. */
if (s2->pict_type == AV_PICTURE_TYPE_B) {
- if (!s->closed_gop) {
+ if (!s2->closed_gop) {
skip_frame = 1;
break;
}
}
}
- if (s2->pict_type == AV_PICTURE_TYPE_I)
+ if (s2->pict_type == AV_PICTURE_TYPE_I || (s2->avctx->flags2 & CODEC_FLAG2_SHOW_ALL))
s->sync = 1;
if (!s2->next_picture_ptr) {
/* Skip P-frames if we do not have a reference frame or
@@ -2566,12 +2695,18 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture,
return AVERROR_INVALIDDATA;
}
+ if (uses_vdpau(avctx)) {
+ s->slice_count++;
+ break;
+ }
+
if (HAVE_THREADS &&
(avctx->active_thread_type & FF_THREAD_SLICE) &&
!avctx->hwaccel) {
int threshold = (s2->mb_height * s->slice_count +
s2->slice_context_count / 2) /
s2->slice_context_count;
+ av_assert0(avctx->thread_count > 1);
if (threshold <= mb_y) {
MpegEncContext *thread_context = s2->thread_context[s->slice_count];
@@ -2614,11 +2749,11 @@ static int mpeg_decode_frame(AVCodecContext *avctx, void *data,
int *got_output, AVPacket *avpkt)
{
const uint8_t *buf = avpkt->data;
+ int ret;
int buf_size = avpkt->size;
Mpeg1Context *s = avctx->priv_data;
AVFrame *picture = data;
MpegEncContext *s2 = &s->mpeg_enc_ctx;
- ff_dlog(avctx, "fill_buffer\n");
if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == SEQ_END_CODE)) {
/* special case for last picture */
@@ -2643,20 +2778,33 @@ static int mpeg_decode_frame(AVCodecContext *avctx, void *data,
return buf_size;
}
- if (s->mpeg_enc_ctx_allocated == 0 && avctx->codec_tag == AV_RL32("VCR2"))
+ s2->codec_tag = avpriv_toupper4(avctx->codec_tag);
+ if (s->mpeg_enc_ctx_allocated == 0 && ( s2->codec_tag == AV_RL32("VCR2")
+ || s2->codec_tag == AV_RL32("BW10")
+ ))
vcr2_init_sequence(avctx);
s->slice_count = 0;
if (avctx->extradata && !s->extradata_decoded) {
- int ret = decode_chunks(avctx, picture, got_output,
- avctx->extradata, avctx->extradata_size);
+ ret = decode_chunks(avctx, picture, got_output,
+ avctx->extradata, avctx->extradata_size);
+ if (*got_output) {
+ av_log(avctx, AV_LOG_ERROR, "picture in extradata\n");
+ *got_output = 0;
+ }
s->extradata_decoded = 1;
- if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
+ if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) {
+ s2->current_picture_ptr = NULL;
return ret;
+ }
}
- return decode_chunks(avctx, picture, got_output, buf, buf_size);
+ ret = decode_chunks(avctx, picture, got_output, buf, buf_size);
+ if (ret<0 || *got_output)
+ s2->current_picture_ptr = NULL;
+
+ return ret;
}
static void flush(AVCodecContext *avctx)
@@ -2664,7 +2812,6 @@ static void flush(AVCodecContext *avctx)
Mpeg1Context *s = avctx->priv_data;
s->sync = 0;
- s->closed_gop = 0;
ff_mpeg_flush(avctx);
}
@@ -2704,6 +2851,7 @@ AVCodec ff_mpeg1video_decoder = {
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
CODEC_CAP_SLICE_THREADS,
.flush = flush,
+ .max_lowres = 3,
.update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context)
};
@@ -2720,9 +2868,25 @@ AVCodec ff_mpeg2video_decoder = {
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
CODEC_CAP_SLICE_THREADS,
.flush = flush,
+ .max_lowres = 3,
.profiles = NULL_IF_CONFIG_SMALL(mpeg2_video_profiles),
};
+//legacy decoder
+AVCodec ff_mpegvideo_decoder = {
+ .name = "mpegvideo",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG2VIDEO,
+ .priv_data_size = sizeof(Mpeg1Context),
+ .init = mpeg_decode_init,
+ .close = mpeg_decode_end,
+ .decode = mpeg_decode_frame,
+ .capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS,
+ .flush = flush,
+ .max_lowres = 3,
+};
+
#if FF_API_XVMC
#if CONFIG_MPEG_XVMC_DECODER
static av_cold int mpeg_mc_decode_init(AVCodecContext *avctx)
@@ -2758,3 +2922,35 @@ AVCodec ff_mpeg_xvmc_decoder = {
#endif
#endif /* FF_API_XVMC */
+
+#if CONFIG_MPEG_VDPAU_DECODER
+AVCodec ff_mpeg_vdpau_decoder = {
+ .name = "mpegvideo_vdpau",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video (VDPAU acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG2VIDEO,
+ .priv_data_size = sizeof(Mpeg1Context),
+ .init = mpeg_decode_init,
+ .close = mpeg_decode_end,
+ .decode = mpeg_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED |
+ CODEC_CAP_HWACCEL_VDPAU | CODEC_CAP_DELAY,
+ .flush = flush,
+};
+#endif
+
+#if CONFIG_MPEG1_VDPAU_DECODER
+AVCodec ff_mpeg1_vdpau_decoder = {
+ .name = "mpeg1video_vdpau",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video (VDPAU acceleration)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG1VIDEO,
+ .priv_data_size = sizeof(Mpeg1Context),
+ .init = mpeg_decode_init,
+ .close = mpeg_decode_end,
+ .decode = mpeg_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED |
+ CODEC_CAP_HWACCEL_VDPAU | CODEC_CAP_DELAY,
+ .flush = flush,
+};
+#endif
diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c
index 29438f3b92..25e216703c 100644
--- a/libavcodec/mpeg12enc.c
+++ b/libavcodec/mpeg12enc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,8 +28,10 @@
#include <stdint.h>
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#include "libavutil/stereo3d.h"
#include "avcodec.h"
@@ -86,7 +88,7 @@ static av_cold void init_uni_ac_vlc(RLTable *rl, uint8_t *uni_ac_vlc_len)
/* length of VLC and sign */
len = rl->table_vlc[code][1] + 1;
} else {
- len = rl->table_vlc[111][1] + 6; /* rl->n */
+ len = rl->table_vlc[111 /* rl->n */][1] + 6;
if (alevel < 128)
len += 8;
@@ -102,26 +104,37 @@ static av_cold void init_uni_ac_vlc(RLTable *rl, uint8_t *uni_ac_vlc_len)
static int find_frame_rate_index(MpegEncContext *s)
{
int i;
- int64_t dmin = INT64_MAX;
- int64_t d;
+ AVRational bestq = (AVRational) {0, 0};
+ AVRational ext;
+ AVRational target = av_inv_q(s->avctx->time_base);
for (i = 1; i < 14; i++) {
- int64_t n0 = 1001LL / ff_mpeg12_frame_rate_tab[i].den *
- ff_mpeg12_frame_rate_tab[i].num * s->avctx->time_base.num;
- int64_t n1 = 1001LL * s->avctx->time_base.den;
-
if (s->avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL &&
i >= 9)
break;
- d = FFABS(n0 - n1);
- if (d < dmin) {
- dmin = d;
- s->frame_rate_index = i;
+ for (ext.num=1; ext.num <= 4; ext.num++) {
+ for (ext.den=1; ext.den <= 32; ext.den++) {
+ AVRational q = av_mul_q(ext, ff_mpeg12_frame_rate_tab[i]);
+
+ if (s->codec_id != AV_CODEC_ID_MPEG2VIDEO && (ext.den!=1 || ext.num!=1))
+ continue;
+ if (av_gcd(ext.den, ext.num) != 1)
+ continue;
+
+ if ( bestq.num==0
+ || av_nearer_q(target, bestq, q) < 0
+ || ext.num==1 && ext.den==1 && av_nearer_q(target, bestq, q) == 0) {
+ bestq = q;
+ s->frame_rate_index = i;
+ s->mpeg2_frame_rate_ext.num = ext.num;
+ s->mpeg2_frame_rate_ext.den = ext.den;
+ }
+ }
}
}
- if (dmin)
+ if (av_cmp_q(target, bestq))
return -1;
else
return 0;
@@ -131,6 +144,9 @@ static av_cold int encode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
+ if (avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && avctx->height > 2800)
+ avctx->thread_count = 1;
+
if (ff_mpv_encode_init(avctx) < 0)
return -1;
@@ -176,12 +192,38 @@ static av_cold int encode_init(AVCodecContext *avctx)
}
}
+ if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) {
+ av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
+ if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) {
+ av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n"
+ "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ s->drop_frame_timecode = s->drop_frame_timecode || !!(avctx->flags2 & CODEC_FLAG2_DROP_FRAME_TIMECODE);
+ if (s->drop_frame_timecode)
+ s->tc.flags |= AV_TIMECODE_FLAG_DROPFRAME;
if (s->drop_frame_timecode && s->frame_rate_index != 4) {
av_log(avctx, AV_LOG_ERROR,
"Drop frame time code only allowed with 1001/30000 fps\n");
return -1;
}
+ if (s->tc_opt_str) {
+ AVRational rate = ff_mpeg12_frame_rate_tab[s->frame_rate_index];
+ int ret = av_timecode_init_from_string(&s->tc, rate, s->tc_opt_str, s);
+ if (ret < 0)
+ return ret;
+ s->drop_frame_timecode = !!(s->tc.flags & AV_TIMECODE_FLAG_DROPFRAME);
+ s->avctx->timecode_frame_start = s->tc.start;
+ } else {
+ s->avctx->timecode_frame_start = 0; // default is -1
+ }
return 0;
}
@@ -198,11 +240,11 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s)
unsigned int vbv_buffer_size, fps, v;
int i, constraint_parameter_flag;
uint64_t time_code;
- float best_aspect_error = 1E10;
- float aspect_ratio = av_q2d(s->avctx->sample_aspect_ratio);
+ int64_t best_aspect_error = INT64_MAX;
+ AVRational aspect_ratio = s->avctx->sample_aspect_ratio;
- if (aspect_ratio == 0.0)
- aspect_ratio = 1.0; // pixel aspect 1.1 (VGA)
+ if (aspect_ratio.num == 0 || aspect_ratio.den == 0)
+ aspect_ratio = (AVRational){1,1}; // pixel aspect 1.1 (VGA)
if (s->current_picture.f->key_frame) {
AVRational framerate = ff_mpeg12_frame_rate_tab[s->frame_rate_index];
@@ -210,19 +252,19 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s)
/* mpeg1 header repeated every gop */
put_header(s, SEQ_START_CODE);
- put_sbits(&s->pb, 12, s->width);
- put_sbits(&s->pb, 12, s->height);
+ put_sbits(&s->pb, 12, s->width & 0xFFF);
+ put_sbits(&s->pb, 12, s->height & 0xFFF);
for (i = 1; i < 15; i++) {
- float error = aspect_ratio;
+ int64_t error = aspect_ratio.num * (1LL<<32) / aspect_ratio.den;
if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || i <= 1)
- error -= 1.0 / ff_mpeg1_aspect[i];
+ error -= (1LL<<32) / ff_mpeg1_aspect[i];
else
- error -= av_q2d(ff_mpeg2_aspect[i]) * s->height / s->width;
+ error -= (1LL<<32)*ff_mpeg2_aspect[i].num * s->height / s->width / ff_mpeg2_aspect[i].den;
error = FFABS(error);
- if (error < best_aspect_error) {
+ if (error - 2 <= best_aspect_error) {
best_aspect_error = error;
s->aspect_ratio_info = i;
}
@@ -269,6 +311,11 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s)
ff_write_quant_matrix(&s->pb, s->avctx->inter_matrix);
if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+ AVFrameSideData *side_data;
+ int width = s->width;
+ int height = s->height;
+ int use_seq_disp_ext;
+
put_header(s, EXT_START_CODE);
put_bits(&s->pb, 4, 1); // seq ext
@@ -285,20 +332,37 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s)
put_bits(&s->pb, 1, 1); // marker
put_bits(&s->pb, 8, vbv_buffer_size >> 10); // vbv buffer ext
put_bits(&s->pb, 1, s->low_delay);
- put_bits(&s->pb, 2, 0); // frame_rate_ext_n
- put_bits(&s->pb, 5, 0); // frame_rate_ext_d
+ put_bits(&s->pb, 2, s->mpeg2_frame_rate_ext.num-1); // frame_rate_ext_n
+ put_bits(&s->pb, 5, s->mpeg2_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);
+ if (side_data) {
+ AVPanScan *pan_scan = (AVPanScan *)side_data->data;
+ if (pan_scan->width && pan_scan->height) {
+ width = pan_scan->width >> 4;
+ height = pan_scan->height >> 4;
+ }
+ }
- put_header(s, EXT_START_CODE);
- put_bits(&s->pb, 4, 2); // sequence display extension
- put_bits(&s->pb, 3, 0); // video_format: 0 is components
- put_bits(&s->pb, 1, 1); // colour_description
- put_bits(&s->pb, 8, s->avctx->color_primaries); // colour_primaries
- put_bits(&s->pb, 8, s->avctx->color_trc); // transfer_characteristics
- put_bits(&s->pb, 8, s->avctx->colorspace); // matrix_coefficients
- put_bits(&s->pb, 14, s->width); // display_horizontal_size
- put_bits(&s->pb, 1, 1); // marker_bit
- put_bits(&s->pb, 14, s->height); // display_vertical_size
- put_bits(&s->pb, 3, 0); // remaining 3 bits are zero padding
+ use_seq_disp_ext = (width != s->width ||
+ height != s->height ||
+ s->avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
+ s->avctx->color_trc != AVCOL_TRC_UNSPECIFIED ||
+ s->avctx->colorspace != AVCOL_SPC_UNSPECIFIED);
+
+ if (s->seq_disp_ext == 1 || (s->seq_disp_ext == -1 && use_seq_disp_ext)) {
+ put_header(s, EXT_START_CODE);
+ put_bits(&s->pb, 4, 2); // sequence display extension
+ put_bits(&s->pb, 3, 0); // video_format: 0 is components
+ put_bits(&s->pb, 1, 1); // colour_description
+ put_bits(&s->pb, 8, s->avctx->color_primaries); // colour_primaries
+ put_bits(&s->pb, 8, s->avctx->color_trc); // transfer_characteristics
+ put_bits(&s->pb, 8, s->avctx->colorspace); // matrix_coefficients
+ put_bits(&s->pb, 14, width); // display_horizontal_size
+ put_bits(&s->pb, 1, 1); // marker_bit
+ put_bits(&s->pb, 14, height); // display_vertical_size
+ put_bits(&s->pb, 3, 0); // remaining 3 bits are zero padding
+ }
}
put_header(s, GOP_START_CODE);
@@ -310,21 +374,17 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s)
s->avctx->timecode_frame_start;
s->gop_picture_number = s->current_picture_ptr->f->coded_picture_number;
- if (s->drop_frame_timecode) {
- /* only works for NTSC 29.97 */
- int d = time_code / 17982;
- int m = time_code % 17982;
- /* not needed since -2,-1 / 1798 in C returns 0 */
- // if (m < 2)
- // m += 2;
- time_code += 18 * d + 2 * ((m - 2) / 1798);
- }
+
+ av_assert0(s->drop_frame_timecode == !!(s->tc.flags & AV_TIMECODE_FLAG_DROPFRAME));
+ if (s->drop_frame_timecode)
+ time_code = av_timecode_adjust_ntsc_framenum2(time_code, fps);
+
put_bits(&s->pb, 5, (uint32_t)((time_code / (fps * 3600)) % 24));
put_bits(&s->pb, 6, (uint32_t)((time_code / (fps * 60)) % 60));
put_bits(&s->pb, 1, 1);
put_bits(&s->pb, 6, (uint32_t)((time_code / fps) % 60));
put_bits(&s->pb, 6, (uint32_t)((time_code % fps)));
- put_bits(&s->pb, 1, !!(s->avctx->flags & CODEC_FLAG_CLOSED_GOP));
+ put_bits(&s->pb, 1, !!(s->avctx->flags & CODEC_FLAG_CLOSED_GOP) || s->intra_only || !s->gop_picture_number);
put_bits(&s->pb, 1, 0); // broken link
}
}
@@ -342,7 +402,7 @@ static inline void encode_mb_skip_run(MpegEncContext *s, int run)
static av_always_inline void put_qscale(MpegEncContext *s)
{
if (s->q_scale_type) {
- assert(s->qscale >= 1 && s->qscale <= 12);
+ av_assert2(s->qscale >= 1 && s->qscale <= 12);
put_bits(&s->pb, 5, inv_non_linear_qscale[s->qscale]);
} else {
put_bits(&s->pb, 5, s->qscale);
@@ -351,7 +411,7 @@ static av_always_inline void put_qscale(MpegEncContext *s)
void ff_mpeg1_encode_slice_header(MpegEncContext *s)
{
- if (s->height > 2800) {
+ if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->height > 2800) {
put_header(s, SLICE_MIN_START_CODE + (s->mb_y & 127));
/* slice_vertical_position_extension */
put_bits(&s->pb, 3, s->mb_y >> 7);
@@ -420,7 +480,7 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s, int picture_number)
}
put_bits(&s->pb, 2, s->intra_dc_precision);
- assert(s->picture_structure == PICT_FRAME);
+ av_assert0(s->picture_structure == PICT_FRAME);
put_bits(&s->pb, 2, s->picture_structure);
if (s->progressive_sequence)
put_bits(&s->pb, 1, 0); /* no repeat */
@@ -532,7 +592,7 @@ static void mpeg1_encode_motion(MpegEncContext *s, int val, int f_or_b_code)
sign = 1;
}
- assert(code > 0 && code <= 16);
+ av_assert2(code > 0 && code <= 16);
put_bits(&s->pb,
ff_mpeg12_mbMotionVectorTable[code][1],
@@ -560,12 +620,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) +
- (diff & ((1 << index) - 1)));
+ av_mod_uintp2(diff, index));
else
put_bits(&s->pb,
ff_mpeg12_vlc_dc_chroma_bits[index] + index,
(ff_mpeg12_vlc_dc_chroma_code[index] << index) +
- (diff & ((1 << index) - 1)));
+ av_mod_uintp2(diff, index));
} else {
if (component == 0)
put_bits(&s->pb,
@@ -675,7 +735,7 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s,
if (cbp == 0 && !first_mb && s->mv_type == MV_TYPE_16X16 &&
(mb_x != s->mb_width - 1 ||
- (mb_y != s->mb_height - 1 && s->codec_id == AV_CODEC_ID_MPEG1VIDEO)) &&
+ (mb_y != s->end_mb_y - 1 && s->codec_id == AV_CODEC_ID_MPEG1VIDEO)) &&
((s->pict_type == AV_PICTURE_TYPE_P && (motion_x | motion_y) == 0) ||
(s->pict_type == AV_PICTURE_TYPE_B && s->mv_dir == s->last_mv_dir &&
(((s->mv_dir & MV_DIR_FORWARD)
@@ -697,7 +757,7 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s,
}
} else {
if (first_mb) {
- assert(s->mb_skip_run == 0);
+ av_assert0(s->mb_skip_run == 0);
encode_mb_skip_run(s, s->mb_x);
} else {
encode_mb_skip_run(s, s->mb_skip_run);
@@ -776,7 +836,7 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s,
s->last_mv[0][1][0] = s->last_mv[0][0][0] = motion_x;
s->last_mv[0][1][1] = s->last_mv[0][0][1] = motion_y;
} else {
- assert(!s->frame_pred_frame_dct && s->mv_type == MV_TYPE_FIELD);
+ av_assert2(!s->frame_pred_frame_dct && s->mv_type == MV_TYPE_FIELD);
if (cbp) {
if (s->dquant) {
@@ -863,8 +923,8 @@ static av_always_inline void mpeg1_encode_mb_internal(MpegEncContext *s,
s->b_count++;
}
} else {
- assert(s->mv_type == MV_TYPE_FIELD);
- assert(!s->frame_pred_frame_dct);
+ av_assert2(s->mv_type == MV_TYPE_FIELD);
+ av_assert2(!s->frame_pred_frame_dct);
if (cbp) { // With coded bloc pattern
if (s->dquant) {
if (s->mv_dir == MV_DIR_FORWARD)
@@ -981,12 +1041,12 @@ av_cold void ff_mpeg1_encode_init(MpegEncContext *s)
bits = ff_mpeg12_vlc_dc_lum_bits[index] + index;
code = (ff_mpeg12_vlc_dc_lum_code[index] << index) +
- (diff & ((1 << index) - 1));
+ av_mod_uintp2(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) +
- (diff & ((1 << index) - 1));
+ av_mod_uintp2(diff, index);
mpeg1_chr_dc_uni[i + 255] = bits + (code << 8);
}
@@ -1045,6 +1105,8 @@ av_cold void ff_mpeg1_encode_init(MpegEncContext *s)
#define OFFSET(x) offsetof(MpegEncContext, x)
#define VE AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
#define COMMON_OPTS \
+ { "gop_timecode", "MPEG GOP Timecode in hh:mm:ss[:;.]ff format", \
+ OFFSET(tc_opt_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, VE },\
{ "intra_vlc", "Use MPEG-2 intra VLC table.", \
OFFSET(intra_vlc_format), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, \
{ "drop_frame_timecode", "Timecode is in drop frame format.", \
@@ -1062,6 +1124,10 @@ static const AVOption mpeg2_options[] = {
COMMON_OPTS
{ "non_linear_quant", "Use nonlinear quantizer.", OFFSET(q_scale_type), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
{ "alternate_scan", "Enable alternate scantable.", OFFSET(alternate_scan), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "seq_disp_ext", "Write sequence_display_extension blocks.", OFFSET(seq_disp_ext), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE, "seq_disp_ext" },
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, "seq_disp_ext" },
+ { "never", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, VE, "seq_disp_ext" },
+ { "always", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, VE, "seq_disp_ext" },
FF_MPV_COMMON_OPTS
{ NULL },
};
@@ -1102,7 +1168,7 @@ AVCodec ff_mpeg2video_encoder = {
.init = encode_init,
.encode2 = ff_mpv_encode_picture,
.close = ff_mpv_encode_end,
- .supported_framerates = ff_mpeg12_frame_rate_tab + 1,
+ .supported_framerates = ff_mpeg2_frame_rate_tab,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P,
AV_PIX_FMT_YUV422P,
AV_PIX_FMT_NONE },
diff --git a/libavcodec/mpeg4_unpack_bframes_bsf.c b/libavcodec/mpeg4_unpack_bframes_bsf.c
new file mode 100644
index 0000000000..e85ea08b08
--- /dev/null
+++ b/libavcodec/mpeg4_unpack_bframes_bsf.c
@@ -0,0 +1,194 @@
+/*
+ * Bitstream filter for unpacking DivX-style packed B-frames in MPEG-4 (divx_packed)
+ * Copyright (c) 2015 Andreas Cadhalpun <Andreas.Cadhalpun@googlemail.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
+ */
+
+#include "avcodec.h"
+#include "mpeg4video.h"
+
+typedef struct UnpackBFramesBSFContext {
+ uint8_t *b_frame_buf;
+ int b_frame_buf_size;
+ int updated_extradata;
+} UnpackBFramesBSFContext;
+
+/* search next start code */
+static unsigned int find_startcode(const uint8_t *buf, int buf_size, int *pos)
+{
+ unsigned int startcode = 0xFF;
+
+ for (; *pos < buf_size;) {
+ startcode = ((startcode << 8) | buf[*pos]) & 0xFFFFFFFF;
+ *pos +=1;
+ if ((startcode & 0xFFFFFF00) != 0x100)
+ continue; /* no startcode */
+ return startcode;
+ }
+
+ return 0;
+}
+
+/* determine the position of the packed marker in the userdata,
+ * the number of VOPs and the position of the second VOP */
+static void scan_buffer(const uint8_t *buf, int buf_size,
+ int *pos_p, int *nb_vop, int *pos_vop2) {
+ unsigned int startcode;
+ int pos, i;
+
+ for (pos = 0; pos < buf_size;) {
+ startcode = find_startcode(buf, buf_size, &pos);
+
+ if (startcode == USER_DATA_STARTCODE && pos_p) {
+ /* check if the (DivX) userdata string ends with 'p' (packed) */
+ for (i = 0; i < 255 && pos + i + 1 < buf_size; i++) {
+ if (buf[pos + i] == 'p' && buf[pos + i + 1] == '\0') {
+ *pos_p = pos + i;
+ break;
+ }
+ }
+ } else if (startcode == VOP_STARTCODE && nb_vop) {
+ *nb_vop += 1;
+ if (*nb_vop == 2 && pos_vop2) {
+ *pos_vop2 = pos - 4; /* subtract 4 bytes startcode */
+ }
+ }
+ }
+}
+
+/* allocate new buffer and copy size bytes from src */
+static uint8_t *create_new_buffer(const uint8_t *src, int size) {
+ uint8_t *dst = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+
+ if (dst) {
+ memcpy(dst, src, size);
+ memset(dst + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ }
+
+ return dst;
+}
+
+static int mpeg4_unpack_bframes_filter(AVBitStreamFilterContext *bsfc,
+ AVCodecContext *avctx, const char *args,
+ uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size,
+ int keyframe)
+{
+ UnpackBFramesBSFContext *ctx = bsfc->priv_data;
+ int pos_p = -1, nb_vop = 0, pos_vop2 = -1, ret = 0;
+
+ if (avctx->codec_id != AV_CODEC_ID_MPEG4) {
+ av_log(avctx, AV_LOG_ERROR,
+ "The mpeg4_unpack_bframes bitstream filter is only useful for mpeg4.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!ctx->updated_extradata && avctx->extradata) {
+ int pos_p_ext = -1;
+ scan_buffer(avctx->extradata, avctx->extradata_size, &pos_p_ext, NULL, NULL);
+ if (pos_p_ext >= 0) {
+ av_log(avctx, AV_LOG_DEBUG,
+ "Updating DivX userdata (remove trailing 'p') in extradata.\n");
+ avctx->extradata[pos_p_ext] = '\0';
+ }
+ ctx->updated_extradata = 1;
+ }
+
+ scan_buffer(buf, buf_size, &pos_p, &nb_vop, &pos_vop2);
+ av_log(avctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop);
+
+ if (pos_vop2 >= 0) {
+ if (ctx->b_frame_buf) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Missing one N-VOP packet, discarding one B-frame.\n");
+ av_freep(&ctx->b_frame_buf);
+ ctx->b_frame_buf_size = 0;
+ }
+ /* store the packed B-frame in the BSFContext */
+ ctx->b_frame_buf_size = buf_size - pos_vop2;
+ ctx->b_frame_buf = create_new_buffer(buf + pos_vop2, ctx->b_frame_buf_size);
+ if (!ctx->b_frame_buf) {
+ ctx->b_frame_buf_size = 0;
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (nb_vop > 2) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop);
+ }
+
+ if (nb_vop == 1 && ctx->b_frame_buf) {
+ /* use frame from BSFContext */
+ *poutbuf = ctx->b_frame_buf;
+ *poutbuf_size = ctx->b_frame_buf_size;
+ /* the output buffer is distinct from the input buffer */
+ ret = 1;
+ if (buf_size <= MAX_NVOP_SIZE) {
+ /* N-VOP */
+ av_log(avctx, AV_LOG_DEBUG, "Skipping N-VOP.\n");
+ ctx->b_frame_buf = NULL;
+ ctx->b_frame_buf_size = 0;
+ } else {
+ /* copy packet into BSFContext */
+ ctx->b_frame_buf_size = buf_size;
+ ctx->b_frame_buf = create_new_buffer(buf , buf_size);
+ if (!ctx->b_frame_buf) {
+ ctx->b_frame_buf_size = 0;
+ av_freep(poutbuf);
+ *poutbuf_size = 0;
+ return AVERROR(ENOMEM);
+ }
+ }
+ } else if (nb_vop >= 2) {
+ /* use first frame of the packet */
+ *poutbuf = (uint8_t *) buf;
+ *poutbuf_size = pos_vop2;
+ } else if (pos_p >= 0) {
+ av_log(avctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n");
+ *poutbuf_size = buf_size;
+ *poutbuf = create_new_buffer(buf, buf_size);
+ if (!*poutbuf) {
+ *poutbuf_size = 0;
+ return AVERROR(ENOMEM);
+ }
+ /* remove 'p' (packed) from the end of the (DivX) userdata string */
+ (*poutbuf)[pos_p] = '\0';
+ /* the output buffer is distinct from the input buffer */
+ ret = 1;
+ } else {
+ /* copy packet */
+ *poutbuf = (uint8_t *) buf;
+ *poutbuf_size = buf_size;
+ }
+
+ return ret;
+}
+
+static void mpeg4_unpack_bframes_close(AVBitStreamFilterContext *bsfc)
+{
+ UnpackBFramesBSFContext *ctx = bsfc->priv_data;
+ av_freep(&ctx->b_frame_buf);
+}
+
+AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = {
+ .name = "mpeg4_unpack_bframes",
+ .priv_data_size = sizeof(UnpackBFramesBSFContext),
+ .filter = mpeg4_unpack_bframes_filter,
+ .close = mpeg4_unpack_bframes_close
+};
diff --git a/libavcodec/mpeg4audio.c b/libavcodec/mpeg4audio.c
index 2363cb637d..188d843eee 100644
--- a/libavcodec/mpeg4audio.c
+++ b/libavcodec/mpeg4audio.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
* Copyright (c) 2009 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,6 +52,8 @@ static int parse_config_ALS(GetBitContext *gb, MPEG4AudioConfig *c)
return 0;
}
+/* XXX: make sure to update the copies in the different encoders if you change
+ * this table */
const int avpriv_mpeg4audio_sample_rates[16] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000, 7350
@@ -82,9 +84,13 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
GetBitContext gb;
int specific_config_bitindex, ret;
+ if (bit_size <= 0)
+ return AVERROR_INVALIDDATA;
+
ret = init_get_bits(&gb, buf, bit_size);
if (ret < 0)
return ret;
+
c->object_type = get_object_type(&gb);
c->sample_rate = get_sample_rate(&gb, &c->sampling_index);
c->chan_config = get_bits(&gb, 4);
@@ -125,8 +131,11 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
if (show_bits(&gb, 11) == 0x2b7) { // sync extension
get_bits(&gb, 11);
c->ext_object_type = get_object_type(&gb);
- if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(&gb)) == 1)
+ if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(&gb)) == 1) {
c->ext_sample_rate = get_sample_rate(&gb, &c->ext_sampling_index);
+ if (c->ext_sample_rate == c->sample_rate)
+ c->sbr = -1;
+ }
if (get_bits_left(&gb) > 11 && get_bits(&gb, 11) == 0x548)
c->ps = get_bits1(&gb);
break;
diff --git a/libavcodec/mpeg4audio.h b/libavcodec/mpeg4audio.h
index 2eef2205bd..8239081747 100644
--- a/libavcodec/mpeg4audio.h
+++ b/libavcodec/mpeg4audio.h
@@ -2,20 +2,20 @@
* MPEG-4 Audio common header
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -102,7 +102,7 @@ enum AudioObjectType {
AOT_USAC, ///< N Unified Speech and Audio Coding
};
-#define MAX_PCE_SIZE 304 ///<Maximum size of a PCE including the 3-bit ID_PCE
+#define MAX_PCE_SIZE 320 ///<Maximum size of a PCE including the 3-bit ID_PCE
///<marker and the comment
int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb);
diff --git a/libavcodec/mpeg4data.h b/libavcodec/mpeg4data.h
index 87bb5391b1..1ac5840e03 100644
--- a/libavcodec/mpeg4data.h
+++ b/libavcodec/mpeg4data.h
@@ -3,20 +3,20 @@
* H263+ support
* copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpeg4video.c b/libavcodec/mpeg4video.c
index e37aafab38..d7c6fe7ecc 100644
--- a/libavcodec/mpeg4video.c
+++ b/libavcodec/mpeg4video.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h
index 252029cd3a..49bc13f87a 100644
--- a/libavcodec/mpeg4video.h
+++ b/libavcodec/mpeg4video.h
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,6 +59,9 @@
#define VISUAL_OBJ_STARTCODE 0x1B5
#define VOP_STARTCODE 0x1B6
+/* smaller packets likely don't contain a real frame */
+#define MAX_NVOP_SIZE 19
+
typedef struct Mpeg4DecContext {
MpegEncContext m;
@@ -84,6 +87,7 @@ typedef struct Mpeg4DecContext {
int enhancement_type;
int scalability;
int use_intra_dc_vlc;
+
/// QP above which the ac VLC should be used for intra dc
int intra_dc_threshold;
@@ -92,6 +96,7 @@ typedef struct Mpeg4DecContext {
int divx_build;
int xvid_build;
int lavc_build;
+
/// flag for having shown the warning about invalid Divx B-frames
int showed_packed_warning;
/** does the stream contain the low_delay flag,
@@ -148,6 +153,8 @@ int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx);
int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s);
int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx);
void ff_mpeg4_init_direct_mv(MpegEncContext *s);
+void ff_mpeg4videodec_static_init(void);
+int ff_mpeg4_workaround_bugs(AVCodecContext *avctx);
int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size);
/**
@@ -223,21 +230,21 @@ static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level,
} else {
level += pred;
ret = level;
- if (s->avctx->err_recognition & AV_EF_BITSTREAM) {
+ }
+ level *= scale;
+ if (level & (~2047)) {
+ if (!s->encoding && (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE))) {
if (level < 0) {
av_log(s->avctx, AV_LOG_ERROR,
"dc<0 at %dx%d\n", s->mb_x, s->mb_y);
return -1;
}
- if (level * scale > 2048 + scale) {
+ if (level > 2048 + scale) {
av_log(s->avctx, AV_LOG_ERROR,
"dc overflow at %dx%d\n", s->mb_x, s->mb_y);
return -1;
}
}
- }
- level *= scale;
- if (level & (~2047)) {
if (level < 0)
level = 0;
else if (!(s->workaround_bugs & FF_BUG_DC_CLIP))
diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c
index 246bb9ca4e..aa5e87a544 100644
--- a/libavcodec/mpeg4video_parser.c
+++ b/libavcodec/mpeg4video_parser.c
@@ -3,23 +3,25 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
#include "internal.h"
#include "parser.h"
#include "mpegvideo.h"
@@ -86,6 +88,8 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx,
if (avctx->extradata_size && pc->first_picture) {
init_get_bits(gb, avctx->extradata, avctx->extradata_size * 8);
ret = ff_mpeg4_decode_picture_header(dec_ctx, gb);
+ if (ret < -1)
+ av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata\n");
}
init_get_bits(gb, buf, 8 * buf_size);
@@ -96,6 +100,13 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx,
if (ret < 0)
return ret;
}
+ if((s1->flags & PARSER_FLAG_USE_CODEC_TS) && s->avctx->time_base.den>0 && ret>=0){
+ av_assert1(s1->pts == AV_NOPTS_VALUE);
+ av_assert1(s1->dts == AV_NOPTS_VALUE);
+
+ s1->pts = av_rescale_q(s->time, (AVRational){1, s->avctx->time_base.den}, (AVRational){1, 1200000});
+ }
+
s1->pict_type = s->pict_type;
pc->first_picture = 0;
return ret;
@@ -105,8 +116,12 @@ static av_cold int mpeg4video_parse_init(AVCodecParserContext *s)
{
struct Mp4vParseContext *pc = s->priv_data;
+ ff_mpeg4videodec_static_init();
+
pc->first_picture = 1;
+ pc->dec_ctx.m.quant_precision = 5;
pc->dec_ctx.m.slice_context_count = 1;
+ pc->dec_ctx.showed_packed_warning = 1;
return 0;
}
diff --git a/libavcodec/mpeg4video_parser.h b/libavcodec/mpeg4video_parser.h
index 0f56e7fd9e..50f8b44403 100644
--- a/libavcodec/mpeg4video_parser.h
+++ b/libavcodec/mpeg4video_parser.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c
index 8dbdbf9b13..cbae9a04ff 100644
--- a/libavcodec/mpeg4videodec.c
+++ b/libavcodec/mpeg4videodec.c
@@ -3,23 +3,26 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define UNCHECKED_BITSTREAM_READER 1
+
+#include "libavutil/opt.h"
#include "error_resilience.h"
#include "idctdsp.h"
#include "internal.h"
@@ -109,12 +112,13 @@ void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, int dir)
* check if the next stuff is a resync marker or the end.
* @return 0 if not
*/
-static inline int mpeg4_is_resync(MpegEncContext *s)
+static inline int mpeg4_is_resync(Mpeg4DecContext *ctx)
{
+ MpegEncContext *s = &ctx->m;
int bits_count = get_bits_count(&s->gb);
int v = show_bits(&s->gb, 16);
- if (s->workaround_bugs & FF_BUG_NO_PADDING)
+ if (s->workaround_bugs & FF_BUG_NO_PADDING && !ctx->resync_marker)
return 0;
while (v <= 0xFF) {
@@ -131,10 +135,11 @@ static inline int mpeg4_is_resync(MpegEncContext *s)
v |= 0x7F >> (7 - (bits_count & 7));
if (v == 0x7F)
- return 1;
+ return s->mb_num;
} else {
if (v == ff_mpeg4_resync_prefix[bits_count & 7]) {
- int len;
+ int len, mb_num;
+ int mb_num_bits = av_log2(s->mb_num - 1) + 1;
GetBitContext gb = s->gb;
skip_bits(&s->gb, 1);
@@ -144,10 +149,14 @@ static inline int mpeg4_is_resync(MpegEncContext *s)
if (get_bits1(&s->gb))
break;
+ mb_num = get_bits(&s->gb, mb_num_bits);
+ if (!mb_num || mb_num > s->mb_num || get_bits_count(&s->gb)+6 > s->gb.size_in_bits)
+ mb_num= -1;
+
s->gb = gb;
if (len >= ff_mpeg4_get_video_packet_prefix_length(s))
- return 1;
+ return mb_num;
}
}
return 0;
@@ -180,17 +189,17 @@ static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *g
int x = 0, y = 0;
length = get_vlc2(gb, sprite_trajectory.table, SPRITE_TRAJ_VLC_BITS, 3);
- if (length)
+ if (length > 0)
x = get_xbits(gb, length);
if (!(ctx->divx_version == 500 && ctx->divx_build == 413))
- skip_bits1(gb); /* marker bit */
+ check_marker(gb, "before sprite_trajectory");
length = get_vlc2(gb, sprite_trajectory.table, SPRITE_TRAJ_VLC_BITS, 3);
- if (length)
+ if (length > 0)
y = get_xbits(gb, length);
- skip_bits1(gb); /* marker bit */
+ check_marker(gb, "after sprite_trajectory");
ctx->sprite_traj[i][0] = d[i][0] = x;
ctx->sprite_traj[i][1] = d[i][1] = y;
}
@@ -368,6 +377,17 @@ static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *g
return 0;
}
+static int decode_new_pred(Mpeg4DecContext *ctx, GetBitContext *gb) {
+ int len = FFMIN(ctx->time_increment_bits + 3, 15);
+
+ get_bits(gb, len);
+ if (get_bits1(gb))
+ get_bits(gb, len);
+ check_marker(gb, "after new_pred");
+
+ return 0;
+}
+
/**
* Decode the next video packet.
* @return <0 if something went wrong
@@ -403,19 +423,6 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx)
"illegal mb_num in video packet (%d %d) \n", mb_num, s->mb_num);
return -1;
}
- if (s->pict_type == AV_PICTURE_TYPE_B) {
- int mb_x = 0, mb_y = 0;
-
- while (s->next_picture.mbskip_table[s->mb_index2xy[mb_num]]) {
- if (!mb_x)
- ff_thread_await_progress(&s->next_picture_ptr->tf, mb_y++, 0);
- mb_num++;
- if (++mb_x == s->mb_width)
- mb_x = 0;
- }
- if (mb_num >= s->mb_num)
- return -1; // slice contains just skipped MBs (already decoded)
- }
s->mb_x = mb_num % s->mb_width;
s->mb_y = mb_num / s->mb_width;
@@ -468,7 +475,8 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx)
}
}
}
- // FIXME new-pred stuff
+ if (ctx->new_pred)
+ decode_new_pred(ctx, &s->gb);
return 0;
}
@@ -563,7 +571,7 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr)
if (code > 8) {
if (get_bits1(&s->gb) == 0) { /* marker */
- if (s->avctx->err_recognition & AV_EF_BITSTREAM) {
+ if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) {
av_log(s->avctx, AV_LOG_ERROR, "dc marker bit missing\n");
return -1;
}
@@ -608,7 +616,7 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx)
cbpc = get_vlc2(&s->gb, ff_h263_intra_MCBPC_vlc.table, INTRA_MCBPC_VLC_BITS, 2);
if (cbpc < 0) {
av_log(s->avctx, AV_LOG_ERROR,
- "cbpc corrupted at %d %d\n", s->mb_x, s->mb_y);
+ "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y);
return -1;
}
} while (cbpc == 8);
@@ -680,7 +688,7 @@ try_again:
cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc.table, INTER_MCBPC_VLC_BITS, 2);
if (cbpc < 0) {
av_log(s->avctx, AV_LOG_ERROR,
- "cbpc corrupted at %d %d\n", s->mb_x, s->mb_y);
+ "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y);
return -1;
}
if (cbpc == 20)
@@ -932,7 +940,8 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block,
int n, int coded, int intra, int rvlc)
{
MpegEncContext *s = &ctx->m;
- int level, i, last, run, qmul, qadd, dc_pred_dir;
+ int level, i, last, run, qmul, qadd;
+ int av_uninit(dc_pred_dir);
RLTable *rl;
RL_VLC_ELEM *rl_vlc;
const uint8_t *scan_table;
@@ -1077,7 +1086,8 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block,
if (SHOW_UBITS(re, &s->gb, 1) == 0) {
av_log(s->avctx, AV_LOG_ERROR,
"1. marker bit missing in 3. esc\n");
- return -1;
+ if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR))
+ return -1;
}
SKIP_CACHE(re, &s->gb, 1);
@@ -1087,19 +1097,42 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block,
if (SHOW_UBITS(re, &s->gb, 1) == 0) {
av_log(s->avctx, AV_LOG_ERROR,
"2. marker bit missing in 3. esc\n");
- return -1;
+ if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR))
+ return -1;
}
SKIP_COUNTER(re, &s->gb, 1 + 12 + 1);
}
+#if 0
+ if (s->error_recognition >= FF_ER_COMPLIANT) {
+ const int abs_level= FFABS(level);
+ if (abs_level<=MAX_LEVEL && run<=MAX_RUN) {
+ const int run1= run - rl->max_run[last][abs_level] - 1;
+ if (abs_level <= rl->max_level[last][run]) {
+ av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, vlc encoding possible\n");
+ return -1;
+ }
+ if (s->error_recognition > FF_ER_COMPLIANT) {
+ if (abs_level <= rl->max_level[last][run]*2) {
+ av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, esc 1 encoding possible\n");
+ return -1;
+ }
+ if (run1 >= 0 && abs_level <= rl->max_level[last][run1]) {
+ av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, esc 2 encoding possible\n");
+ return -1;
+ }
+ }
+ }
+ }
+#endif
if (level > 0)
level = level * qmul + qadd;
else
level = level * qmul - qadd;
if ((unsigned)(level + 2048) > 4095) {
- if (s->avctx->err_recognition & AV_EF_BITSTREAM) {
+ if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_AGGRESSIVE)) {
if (level > 2560 || level < -2560) {
av_log(s->avctx, AV_LOG_ERROR,
"|level| overflow in 3. esc, qp=%d\n",
@@ -1136,6 +1169,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block,
level = (level ^ SHOW_SBITS(re, &s->gb, 1)) - SHOW_SBITS(re, &s->gb, 1);
LAST_SKIP_BITS(re, &s->gb, 1);
}
+ ff_tlog(s->avctx, "dct[%d][%d] = %- 4d end?:%d\n", scan_table[i&63]&7, scan_table[i&63] >> 3, level, i>62);
if (i > 62) {
i -= 192;
if (i & (~63)) {
@@ -1244,12 +1278,12 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64])
/* per-MB end of slice check */
if (--s->mb_num_left <= 0) {
- if (mpeg4_is_resync(s))
+ if (mpeg4_is_resync(ctx))
return SLICE_END;
else
return SLICE_NOEND;
} else {
- if (mpeg4_is_resync(s)) {
+ if (mpeg4_is_resync(ctx)) {
const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1;
if (s->cbp_table[xy + delta])
return SLICE_END;
@@ -1266,7 +1300,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64])
static int8_t quant_tab[4] = { -1, -2, 1, 2 };
const int xy = s->mb_x + s->mb_y * s->mb_stride;
- assert(s->h263_pred);
+ av_assert2(s->h263_pred);
if (s->pict_type == AV_PICTURE_TYPE_P ||
s->pict_type == AV_PICTURE_TYPE_S) {
@@ -1302,7 +1336,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64])
cbpc = get_vlc2(&s->gb, ff_h263_inter_MCBPC_vlc.table, INTER_MCBPC_VLC_BITS, 2);
if (cbpc < 0) {
av_log(s->avctx, AV_LOG_ERROR,
- "cbpc damaged at %d %d\n", s->mb_x, s->mb_y);
+ "mcbpc damaged at %d %d\n", s->mb_x, s->mb_y);
return -1;
}
} while (cbpc == 20);
@@ -1608,20 +1642,23 @@ intra:
end:
/* per-MB end of slice check */
if (s->codec_id == AV_CODEC_ID_MPEG4) {
- if (mpeg4_is_resync(s)) {
- const int delta = s->mb_x + 1 == s->mb_width ? 2 : 1;
+ int next = mpeg4_is_resync(ctx);
+ if (next) {
+ if (s->mb_x + s->mb_y*s->mb_width + 1 > next && (s->avctx->err_recognition & AV_EF_AGGRESSIVE)) {
+ return -1;
+ } else if (s->mb_x + s->mb_y*s->mb_width + 1 >= next)
+ return SLICE_END;
- if (s->pict_type == AV_PICTURE_TYPE_B &&
- s->next_picture.mbskip_table[xy + delta]) {
+ 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,
(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])
+ return SLICE_OK;
}
- if (s->pict_type == AV_PICTURE_TYPE_B &&
- s->next_picture.mbskip_table[xy + delta])
- return SLICE_OK;
return SLICE_END;
}
}
@@ -1632,29 +1669,30 @@ end:
static int mpeg4_decode_gop_header(MpegEncContext *s, GetBitContext *gb)
{
int hours, minutes, seconds;
- unsigned time_code = show_bits(gb, 18);
-
- if (time_code & 0x40) { /* marker_bit */
- hours = time_code >> 13;
- minutes = time_code >> 7 & 0x3f;
- seconds = time_code & 0x3f;
- s->time_base = seconds + 60 * (minutes + 60 * hours);
- skip_bits(gb, 20); /* time_code, closed_gov, broken_link */
- } else {
- av_log(s->avctx, AV_LOG_WARNING, "GOP header missing marker_bit\n");
+
+ if (!show_bits(gb, 23)) {
+ av_log(s->avctx, AV_LOG_WARNING, "GOP header invalid\n");
+ return -1;
}
+ hours = get_bits(gb, 5);
+ minutes = get_bits(gb, 6);
+ check_marker(gb, "in gop_header");
+ seconds = get_bits(gb, 6);
+
+ s->time_base = seconds + 60*(minutes + 60*hours);
+
+ skip_bits1(gb);
+ skip_bits1(gb);
+
return 0;
}
static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb)
{
- int profile_and_level_indication;
-
- profile_and_level_indication = get_bits(gb, 8);
- s->avctx->profile = (profile_and_level_indication & 0xf0) >> 4;
- s->avctx->level = (profile_and_level_indication & 0x0f);
+ s->avctx->profile = get_bits(gb, 4);
+ s->avctx->level = get_bits(gb, 4);
// for Simple profile, level 0
if (s->avctx->profile == 0 && s->avctx->level == 8) {
@@ -1694,20 +1732,20 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
s->low_delay = get_bits1(gb);
if (get_bits1(gb)) { /* vbv parameters */
get_bits(gb, 15); /* first_half_bitrate */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after first_half_bitrate");
get_bits(gb, 15); /* latter_half_bitrate */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after latter_half_bitrate");
get_bits(gb, 15); /* first_half_vbv_buffer_size */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after first_half_vbv_buffer_size");
get_bits(gb, 3); /* latter_half_vbv_buffer_size */
get_bits(gb, 11); /* first_half_vbv_occupancy */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after first_half_vbv_occupancy");
get_bits(gb, 15); /* latter_half_vbv_occupancy */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after latter_half_vbv_occupancy");
}
} else {
/* is setting low delay flag only once the smartest thing to do?
- * low delay detection won't be overriden. */
+ * low delay detection won't be overridden. */
if (s->picture_number == 0)
s->low_delay = 0;
}
@@ -1725,7 +1763,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
s->avctx->framerate.num = get_bits(gb, 16);
if (!s->avctx->framerate.num) {
av_log(s->avctx, AV_LOG_ERROR, "framerate==0\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
ctx->time_increment_bits = av_log2(s->avctx->framerate.num - 1) + 1;
@@ -1739,15 +1777,17 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
else
s->avctx->framerate.den = 1;
+ s->avctx->time_base = av_inv_q(av_mul_q(s->avctx->framerate, (AVRational){s->avctx->ticks_per_frame, 1}));
+
ctx->t_frame = 0;
if (ctx->shape != BIN_ONLY_SHAPE) {
if (ctx->shape == RECT_SHAPE) {
- skip_bits1(gb); /* marker */
+ check_marker(gb, "before width");
width = get_bits(gb, 13);
- skip_bits1(gb); /* marker */
+ check_marker(gb, "before height");
height = get_bits(gb, 13);
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after height");
if (width && height && /* they should be non zero but who knows */
!(s->width && s->codec_tag == AV_RL32("MP4S"))) {
if (s->width && s->height &&
@@ -1775,13 +1815,13 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
ctx->vol_sprite_usage == GMC_SPRITE) {
if (ctx->vol_sprite_usage == STATIC_SPRITE) {
skip_bits(gb, 13); // sprite_width
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after sprite_width");
skip_bits(gb, 13); // sprite_height
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after sprite_height");
skip_bits(gb, 13); // sprite_left
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after sprite_left");
skip_bits(gb, 13); // sprite_top
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after sprite_top");
}
ctx->num_sprite_warping_points = get_bits(gb, 6);
if (ctx->num_sprite_warping_points > 3) {
@@ -1789,7 +1829,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
"%d sprite_warping_points\n",
ctx->num_sprite_warping_points);
ctx->num_sprite_warping_points = 0;
- return -1;
+ return AVERROR_INVALIDDATA;
}
s->sprite_warping_accuracy = get_bits(gb, 2);
ctx->sprite_brightness_change = get_bits1(gb);
@@ -1805,6 +1845,9 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
if (s->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;
+ }
} else {
s->quant_precision = 5;
}
@@ -1880,6 +1923,11 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb)
else
s->quarter_sample = 0;
+ if (get_bits_left(gb) < 4) {
+ av_log(s->avctx, AV_LOG_ERROR, "VOL Header truncated\n");
+ return AVERROR_INVALIDDATA;
+ }
+
if (!get_bits1(gb)) {
int pos = get_bits_count(gb);
int estimation_method = get_bits(gb, 2);
@@ -1987,6 +2035,17 @@ no_cplx_est:
}
}
+ if (s->avctx->debug&FF_DEBUG_PICT_INFO) {
+ av_log(s->avctx, AV_LOG_DEBUG, "tb %d/%d, tincrbits:%d, qp_prec:%d, ps:%d, %s%s%s%s\n",
+ s->avctx->framerate.den, s->avctx->framerate.num,
+ ctx->time_increment_bits,
+ s->quant_precision,
+ s->progressive_sequence,
+ ctx->scalability ? "scalability " :"" , s->quarter_sample ? "qpel " : "",
+ s->data_partitioning ? "partition " : "", ctx->rvlc ? "rvlc " : ""
+ );
+ }
+
return 0;
}
@@ -2018,11 +2077,6 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb)
ctx->divx_version = ver;
ctx->divx_build = build;
s->divx_packed = e == 3 && last == 'p';
- if (s->divx_packed && !ctx->showed_packed_warning) {
- av_log(s->avctx, AV_LOG_WARNING,
- "Invalid and inefficient vfw-avi packed B frames detected\n");
- ctx->showed_packed_warning = 1;
- }
}
/* libavcodec detection */
@@ -2046,6 +2100,14 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb)
if (e == 1)
ctx->xvid_build = build;
+ return 0;
+}
+
+int ff_mpeg4_workaround_bugs(AVCodecContext *avctx)
+{
+ Mpeg4DecContext *ctx = avctx->priv_data;
+ MpegEncContext *s = &ctx->m;
+
if (ctx->xvid_build == -1 && ctx->divx_version == -1 && ctx->lavc_build == -1) {
if (s->codec_tag == AV_RL32("XVID") ||
s->codec_tag == AV_RL32("XVIX") ||
@@ -2065,8 +2127,89 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb)
ctx->divx_build = -1;
}
- if (CONFIG_MPEG4_DECODER && ctx->xvid_build >= 0)
- ff_xvid_idct_init(&s->idsp, s->avctx);
+ if (s->workaround_bugs & FF_BUG_AUTODETECT) {
+ if (s->codec_tag == AV_RL32("XVIX"))
+ s->workaround_bugs |= FF_BUG_XVID_ILACE;
+
+ if (s->codec_tag == AV_RL32("UMP4"))
+ s->workaround_bugs |= FF_BUG_UMP4;
+
+ if (ctx->divx_version >= 500 && ctx->divx_build < 1814)
+ s->workaround_bugs |= FF_BUG_QPEL_CHROMA;
+
+ if (ctx->divx_version > 502 && ctx->divx_build < 1814)
+ s->workaround_bugs |= FF_BUG_QPEL_CHROMA2;
+
+ if (ctx->xvid_build <= 3U)
+ s->padding_bug_score = 256 * 256 * 256 * 64;
+
+ if (ctx->xvid_build <= 1U)
+ s->workaround_bugs |= FF_BUG_QPEL_CHROMA;
+
+ if (ctx->xvid_build <= 12U)
+ s->workaround_bugs |= FF_BUG_EDGE;
+
+ if (ctx->xvid_build <= 32U)
+ s->workaround_bugs |= FF_BUG_DC_CLIP;
+
+#define SET_QPEL_FUNC(postfix1, postfix2) \
+ s->qdsp.put_ ## postfix1 = ff_put_ ## postfix2; \
+ s->qdsp.put_no_rnd_ ## postfix1 = ff_put_no_rnd_ ## postfix2; \
+ s->qdsp.avg_ ## postfix1 = ff_avg_ ## postfix2;
+
+ if (ctx->lavc_build < 4653U)
+ s->workaround_bugs |= FF_BUG_STD_QPEL;
+
+ if (ctx->lavc_build < 4655U)
+ s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE;
+
+ if (ctx->lavc_build < 4670U)
+ s->workaround_bugs |= FF_BUG_EDGE;
+
+ if (ctx->lavc_build <= 4712U)
+ s->workaround_bugs |= FF_BUG_DC_CLIP;
+
+ if (ctx->divx_version >= 0)
+ s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE;
+ if (ctx->divx_version == 501 && ctx->divx_build == 20020416)
+ s->padding_bug_score = 256 * 256 * 256 * 64;
+
+ if (ctx->divx_version < 500U)
+ s->workaround_bugs |= FF_BUG_EDGE;
+
+ if (ctx->divx_version >= 0)
+ s->workaround_bugs |= FF_BUG_HPEL_CHROMA;
+ }
+
+ if (s->workaround_bugs & FF_BUG_STD_QPEL) {
+ SET_QPEL_FUNC(qpel_pixels_tab[0][5], qpel16_mc11_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[0][7], qpel16_mc31_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[0][9], qpel16_mc12_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[0][11], qpel16_mc32_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[0][13], qpel16_mc13_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[0][15], qpel16_mc33_old_c)
+
+ SET_QPEL_FUNC(qpel_pixels_tab[1][5], qpel8_mc11_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[1][7], qpel8_mc31_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[1][9], qpel8_mc12_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[1][11], qpel8_mc32_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[1][13], qpel8_mc13_old_c)
+ SET_QPEL_FUNC(qpel_pixels_tab[1][15], qpel8_mc33_old_c)
+ }
+
+ if (avctx->debug & FF_DEBUG_BUGS)
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "bugs: %X lavc_build:%d xvid_build:%d divx_version:%d divx_build:%d %s\n",
+ s->workaround_bugs, ctx->lavc_build, ctx->xvid_build,
+ ctx->divx_version, ctx->divx_build, s->divx_packed ? "p" : "");
+
+ if (CONFIG_MPEG4_DECODER && ctx->xvid_build >= 0 &&
+ s->codec_id == AV_CODEC_ID_MPEG4 &&
+ avctx->idct_algo == FF_IDCT_AUTO) {
+ avctx->idct_algo = FF_IDCT_XVID;
+ ff_mpv_idct_init(s);
+ return 1;
+ }
return 0;
}
@@ -2075,6 +2218,7 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
{
MpegEncContext *s = &ctx->m;
int time_incr, time_increment;
+ int64_t pts;
s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* pict type: I = 0 , P = 1 */
if (s->pict_type == AV_PICTURE_TYPE_B && s->low_delay &&
@@ -2097,7 +2241,9 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
if (ctx->time_increment_bits == 0 ||
!(show_bits(gb, ctx->time_increment_bits + 1) & 1)) {
- /* Headers seem incomplete; try to guess time_increment_bits. */
+ av_log(s->avctx, AV_LOG_WARNING,
+ "time_increment_bits %d is invalid in relation to the current bitstream, this is likely caused by a missing VOL header\n", ctx->time_increment_bits);
+
for (ctx->time_increment_bits = 1;
ctx->time_increment_bits < 16;
ctx->time_increment_bits++) {
@@ -2109,6 +2255,13 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
} else if ((show_bits(gb, ctx->time_increment_bits + 5) & 0x1F) == 0x18)
break;
}
+
+ av_log(s->avctx, AV_LOG_WARNING,
+ "time_increment_bits set to %d bits, based on bitstream analysis\n", ctx->time_increment_bits);
+ if (s->avctx->framerate.num && 4*s->avctx->framerate.num < 1<<ctx->time_increment_bits) {
+ s->avctx->framerate.num = 1<<ctx->time_increment_bits;
+ s->avctx->time_base = av_inv_q(av_mul_q(s->avctx->framerate, (AVRational){s->avctx->ticks_per_frame, 1}));
+ }
}
if (IS_3IV1)
@@ -2149,12 +2302,22 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2;
s->pb_field_time = (ROUNDED_DIV(s->time, ctx->t_frame) -
ROUNDED_DIV(s->last_non_b_time - s->pp_time, ctx->t_frame)) * 2;
- if (!s->progressive_sequence) {
- if (s->pp_field_time <= s->pb_field_time || s->pb_field_time <= 1)
+ if (s->pp_field_time <= s->pb_field_time || s->pb_field_time <= 1) {
+ s->pb_field_time = 2;
+ s->pp_field_time = 4;
+ if (!s->progressive_sequence)
return FRAME_SKIPPED;
}
}
+ if (s->avctx->framerate.den)
+ pts = ROUNDED_DIV(s->time, s->avctx->framerate.den);
+ else
+ pts = AV_NOPTS_VALUE;
+ if (s->avctx->debug&FF_DEBUG_PTS)
+ av_log(s->avctx, AV_LOG_DEBUG, "MPEG4 PTS: %"PRId64"\n",
+ pts);
+
check_marker(gb, "before vop_coded");
/* vop coded */
@@ -2163,6 +2326,9 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
av_log(s->avctx, AV_LOG_ERROR, "vop not coded\n");
return FRAME_SKIPPED;
}
+ if (ctx->new_pred)
+ decode_new_pred(ctx, gb);
+
if (ctx->shape != BIN_ONLY_SHAPE &&
(s->pict_type == AV_PICTURE_TYPE_P ||
(s->pict_type == AV_PICTURE_TYPE_S &&
@@ -2177,11 +2343,11 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
if (ctx->shape != RECT_SHAPE) {
if (ctx->vol_sprite_usage != 1 || s->pict_type != AV_PICTURE_TYPE_I) {
skip_bits(gb, 13); /* width */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after width");
skip_bits(gb, 13); /* height */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after height");
skip_bits(gb, 13); /* hor_spat_ref */
- skip_bits1(gb); /* marker */
+ check_marker(gb, "after hor_spat_ref");
skip_bits(gb, 13); /* ver_spat_ref */
}
skip_bits1(gb); /* change_CR_disable */
@@ -2199,6 +2365,10 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
if (s->pict_type == AV_PICTURE_TYPE_B)
skip_bits_long(gb, ctx->cplx_estimation_trash_b);
+ if (get_bits_left(gb) < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "Header truncated\n");
+ return AVERROR_INVALIDDATA;
+ }
ctx->intra_dc_threshold = ff_mpeg4_dc_threshold[get_bits(gb, 3)];
if (!s->progressive_sequence) {
s->top_field_first = get_bits1(gb);
@@ -2236,7 +2406,7 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
if (s->qscale == 0) {
av_log(s->avctx, AV_LOG_ERROR,
"Error, header damaged or not MPEG4 header (qscale=0)\n");
- return -1; // makes no sense to continue, as there is nothing left from the image then
+ return AVERROR_INVALIDDATA; // makes no sense to continue, as there is nothing left from the image then
}
if (s->pict_type != AV_PICTURE_TYPE_I) {
@@ -2244,29 +2414,39 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb)
if (s->f_code == 0) {
av_log(s->avctx, AV_LOG_ERROR,
"Error, header damaged or not MPEG4 header (f_code=0)\n");
- return -1; // makes no sense to continue, as there is nothing left from the image then
+ s->f_code = 1;
+ return AVERROR_INVALIDDATA; // makes no sense to continue, as there is nothing left from the image then
}
} else
s->f_code = 1;
if (s->pict_type == AV_PICTURE_TYPE_B) {
s->b_code = get_bits(gb, 3);
+ if (s->b_code == 0) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Error, header damaged or not MPEG4 header (b_code=0)\n");
+ s->b_code=1;
+ return AVERROR_INVALIDDATA; // makes no sense to continue, as the MV decoding will break very quickly
+ }
} else
s->b_code = 1;
if (s->avctx->debug & FF_DEBUG_PICT_INFO) {
av_log(s->avctx, AV_LOG_DEBUG,
- "qp:%d fc:%d,%d %s size:%d pro:%d alt:%d top:%d %spel part:%d resync:%d w:%d a:%d rnd:%d vot:%d%s dc:%d ce:%d/%d/%d\n",
+ "qp:%d fc:%d,%d %s size:%d pro:%d alt:%d top:%d %spel part:%d resync:%d w:%d a:%d rnd:%d vot:%d%s dc:%d ce:%d/%d/%d time:%"PRId64" tincr:%d\n",
s->qscale, s->f_code, s->b_code,
s->pict_type == AV_PICTURE_TYPE_I ? "I" : (s->pict_type == AV_PICTURE_TYPE_P ? "P" : (s->pict_type == AV_PICTURE_TYPE_B ? "B" : "S")),
- gb->size_in_bits, s->progressive_sequence, s->alternate_scan,
+ gb->size_in_bits,s->progressive_sequence, s->alternate_scan,
s->top_field_first, s->quarter_sample ? "q" : "h",
s->data_partitioning, ctx->resync_marker,
ctx->num_sprite_warping_points, s->sprite_warping_accuracy,
1 - s->no_rounding, s->vo_type,
ctx->vol_control_parameters ? " VOLC" : " ", ctx->intra_dc_threshold,
ctx->cplx_estimation_trash_i, ctx->cplx_estimation_trash_p,
- ctx->cplx_estimation_trash_b);
+ ctx->cplx_estimation_trash_b,
+ s->time,
+ time_increment
+ );
}
if (!ctx->scalability) {
@@ -2315,6 +2495,7 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)
{
MpegEncContext *s = &ctx->m;
unsigned startcode, v;
+ int ret;
/* search next start code */
align_get_bits(gb);
@@ -2329,8 +2510,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)
for (;;) {
if (get_bits_count(gb) >= gb->size_in_bits) {
if (gb->size_in_bits == 8 &&
- (ctx->divx_version >= 0 || ctx->xvid_build >= 0)) {
- av_log(s->avctx, AV_LOG_WARNING, "frame skip %d\n", gb->size_in_bits);
+ (ctx->divx_version >= 0 || ctx->xvid_build >= 0) || s->codec_tag == AV_RL32("QMP4")) {
+ av_log(s->avctx, AV_LOG_VERBOSE, "frame skip %d\n", gb->size_in_bits);
return FRAME_SKIPPED; // divx bug
} else
return -1; // end of stream
@@ -2403,8 +2584,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb)
}
if (startcode >= 0x120 && startcode <= 0x12F) {
- if (decode_vol_header(ctx, gb) < 0)
- return -1;
+ if ((ret = decode_vol_header(ctx, gb)) < 0)
+ return ret;
} else if (startcode == USER_DATA_STARTCODE) {
decode_user_data(ctx, gb);
} else if (startcode == GOP_STARTCODE) {
@@ -2424,64 +2605,33 @@ end:
s->low_delay = 1;
s->avctx->has_b_frames = !s->low_delay;
- if (s->workaround_bugs & FF_BUG_AUTODETECT) {
- if (s->codec_tag == AV_RL32("XVIX"))
- s->workaround_bugs |= FF_BUG_XVID_ILACE;
-
- if (s->codec_tag == AV_RL32("UMP4"))
- s->workaround_bugs |= FF_BUG_UMP4;
-
- if (ctx->divx_version >= 500 && ctx->divx_build < 1814)
- s->workaround_bugs |= FF_BUG_QPEL_CHROMA;
-
- if (ctx->divx_version > 502 && ctx->divx_build < 1814)
- s->workaround_bugs |= FF_BUG_QPEL_CHROMA2;
-
- if (ctx->xvid_build <= 3U)
- s->padding_bug_score = 256 * 256 * 256 * 64;
-
- if (ctx->xvid_build <= 1U)
- s->workaround_bugs |= FF_BUG_QPEL_CHROMA;
-
- if (ctx->xvid_build <= 12U)
- s->workaround_bugs |= FF_BUG_EDGE;
-
- if (ctx->xvid_build <= 32U)
- s->workaround_bugs |= FF_BUG_DC_CLIP;
-
- if (ctx->lavc_build < 4653U)
- s->workaround_bugs |= FF_BUG_STD_QPEL;
-
- if (ctx->lavc_build < 4655U)
- s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE;
-
- if (ctx->lavc_build < 4670U)
- s->workaround_bugs |= FF_BUG_EDGE;
-
- if (ctx->lavc_build <= 4712U)
- s->workaround_bugs |= FF_BUG_DC_CLIP;
-
- if (ctx->divx_version >= 0)
- s->workaround_bugs |= FF_BUG_DIRECT_BLOCKSIZE;
-
- if (ctx->divx_version == 501 && ctx->divx_build == 20020416)
- s->padding_bug_score = 256 * 256 * 256 * 64;
+ return decode_vop_header(ctx, gb);
+}
- if (ctx->divx_version < 500U)
- s->workaround_bugs |= FF_BUG_EDGE;
+av_cold void ff_mpeg4videodec_static_init(void) {
+ static int done = 0;
- if (ctx->divx_version >= 0)
- s->workaround_bugs |= FF_BUG_HPEL_CHROMA;
+ if (!done) {
+ ff_init_rl(&ff_mpeg4_rl_intra, ff_mpeg4_static_rl_table_store[0]);
+ ff_init_rl(&ff_rvlc_rl_inter, ff_mpeg4_static_rl_table_store[1]);
+ ff_init_rl(&ff_rvlc_rl_intra, ff_mpeg4_static_rl_table_store[2]);
+ INIT_VLC_RL(ff_mpeg4_rl_intra, 554);
+ INIT_VLC_RL(ff_rvlc_rl_inter, 1072);
+ INIT_VLC_RL(ff_rvlc_rl_intra, 1072);
+ INIT_VLC_STATIC(&dc_lum, DC_VLC_BITS, 10 /* 13 */,
+ &ff_mpeg4_DCtab_lum[0][1], 2, 1,
+ &ff_mpeg4_DCtab_lum[0][0], 2, 1, 512);
+ INIT_VLC_STATIC(&dc_chrom, DC_VLC_BITS, 10 /* 13 */,
+ &ff_mpeg4_DCtab_chrom[0][1], 2, 1,
+ &ff_mpeg4_DCtab_chrom[0][0], 2, 1, 512);
+ INIT_VLC_STATIC(&sprite_trajectory, SPRITE_TRAJ_VLC_BITS, 15,
+ &ff_sprite_trajectory_tab[0][1], 4, 2,
+ &ff_sprite_trajectory_tab[0][0], 4, 2, 128);
+ INIT_VLC_STATIC(&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, 16);
+ done = 1;
}
-
-
- if (s->avctx->debug & FF_DEBUG_BUGS)
- av_log(s->avctx, AV_LOG_DEBUG,
- "bugs: %X lavc_build:%d xvid_build:%d divx_version:%d divx_build:%d %s\n",
- s->workaround_bugs, ctx->lavc_build, ctx->xvid_build,
- ctx->divx_version, ctx->divx_build, s->divx_packed ? "p" : "");
-
- return decode_vop_header(ctx, gb);
}
int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
@@ -2489,33 +2639,37 @@ int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
Mpeg4DecContext *ctx = avctx->priv_data;
MpegEncContext *s = &ctx->m;
- /* divx 5.01+ bistream reorder stuff */
+ /* divx 5.01+ bitstream reorder stuff */
+ /* Since this clobbers the input buffer and hwaccel codecs still need the
+ * data during hwaccel->end_frame we should not do this any earlier */
if (s->divx_packed) {
- int current_pos = get_bits_count(&s->gb) >> 3;
+ int current_pos = s->gb.buffer == s->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3);
int startcode_found = 0;
- if (buf_size - current_pos > 5) {
+ if (buf_size - current_pos > 7) {
+
int i;
- for (i = current_pos; i < buf_size - 3; i++)
+ for (i = current_pos; i < buf_size - 4; i++)
+
if (buf[i] == 0 &&
buf[i + 1] == 0 &&
buf[i + 2] == 1 &&
buf[i + 3] == 0xB6) {
- startcode_found = 1;
+ startcode_found = !(buf[i + 4] & 0x40);
break;
}
}
- if (s->gb.buffer == s->bitstream_buffer && buf_size > 7 &&
- ctx->xvid_build >= 0) { // xvid style
- startcode_found = 1;
- current_pos = 0;
- }
if (startcode_found) {
- av_fast_malloc(&s->bitstream_buffer,
+ if (!ctx->showed_packed_warning) {
+ av_log(s->avctx, AV_LOG_INFO, "Video uses a non-standard and "
+ "wasteful way to store B-frames ('packed B-frames'). "
+ "Consider using the mpeg4_unpack_bframes bitstream filter to fix it.\n");
+ ctx->showed_packed_warning = 1;
+ }
+ av_fast_padded_malloc(&s->bitstream_buffer,
&s->allocated_bitstream_buffer_size,
- buf_size - current_pos +
- FF_INPUT_BUFFER_PADDING_SIZE);
+ buf_size - current_pos);
if (!s->bitstream_buffer)
return AVERROR(ENOMEM);
memcpy(s->bitstream_buffer, buf + current_pos,
@@ -2539,13 +2693,11 @@ static int mpeg4_update_thread_context(AVCodecContext *dst,
if (ret < 0)
return ret;
+ memcpy(((uint8_t*)s) + sizeof(MpegEncContext), ((uint8_t*)s1) + sizeof(MpegEncContext), sizeof(Mpeg4DecContext) - sizeof(MpegEncContext));
+
if (CONFIG_MPEG4_DECODER && !init && s1->xvid_build >= 0)
ff_xvid_idct_init(&s->m.idsp, dst);
- s->shape = s1->shape;
- s->time_increment_bits = s1->time_increment_bits;
- s->xvid_build = s1->xvid_build;
-
return 0;
}
@@ -2554,7 +2706,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
Mpeg4DecContext *ctx = avctx->priv_data;
MpegEncContext *s = &ctx->m;
int ret;
- static int done = 0;
ctx->divx_version =
ctx->divx_build =
@@ -2564,31 +2715,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
if ((ret = ff_h263_decode_init(avctx)) < 0)
return ret;
- if (!done) {
- done = 1;
-
- ff_init_rl(&ff_mpeg4_rl_intra, ff_mpeg4_static_rl_table_store[0]);
- ff_init_rl(&ff_rvlc_rl_inter, ff_mpeg4_static_rl_table_store[1]);
- ff_init_rl(&ff_rvlc_rl_intra, ff_mpeg4_static_rl_table_store[2]);
- INIT_VLC_RL(ff_mpeg4_rl_intra, 554);
- INIT_VLC_RL(ff_rvlc_rl_inter, 1072);
- INIT_VLC_RL(ff_rvlc_rl_intra, 1072);
- INIT_VLC_STATIC(&dc_lum, DC_VLC_BITS, 10 /* 13 */,
- &ff_mpeg4_DCtab_lum[0][1], 2, 1,
- &ff_mpeg4_DCtab_lum[0][0], 2, 1, 512);
- INIT_VLC_STATIC(&dc_chrom, DC_VLC_BITS, 10 /* 13 */,
- &ff_mpeg4_DCtab_chrom[0][1], 2, 1,
- &ff_mpeg4_DCtab_chrom[0][0], 2, 1, 512);
- INIT_VLC_STATIC(&sprite_trajectory, SPRITE_TRAJ_VLC_BITS, 15,
- &ff_sprite_trajectory_tab[0][1], 4, 2,
- &ff_sprite_trajectory_tab[0][0], 4, 2, 128);
- INIT_VLC_STATIC(&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, 16);
- }
+ ff_mpeg4videodec_static_init();
s->h263_pred = 1;
- s->low_delay = 0; /* default, might be overriden in the vol header during header parsing */
+ 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 */
@@ -2615,6 +2745,20 @@ static const AVProfile mpeg4_video_profiles[] = {
{ FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE, "Advanced Scalable Texture Profile" },
{ FF_PROFILE_MPEG4_SIMPLE_STUDIO, "Simple Studio Profile" },
{ FF_PROFILE_MPEG4_ADVANCED_SIMPLE, "Advanced Simple Profile" },
+ { FF_PROFILE_UNKNOWN },
+};
+
+static const AVOption mpeg4_options[] = {
+ {"quarter_sample", "1/4 subpel MC", offsetof(MpegEncContext, quarter_sample), FF_OPT_TYPE_INT, {.i64 = 0}, 0, 1, 0},
+ {"divx_packed", "divx style packed b frames", offsetof(MpegEncContext, divx_packed), FF_OPT_TYPE_INT, {.i64 = 0}, 0, 1, 0},
+ {NULL}
+};
+
+static const AVClass mpeg4_class = {
+ "MPEG4 Video Decoder",
+ av_default_item_name,
+ mpeg4_options,
+ LIBAVUTIL_VERSION_INT,
};
AVCodec ff_mpeg4_decoder = {
@@ -2630,7 +2774,35 @@ AVCodec ff_mpeg4_decoder = {
CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
CODEC_CAP_FRAME_THREADS,
.flush = ff_mpeg_flush,
+ .max_lowres = 3,
.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
.profiles = NULL_IF_CONFIG_SMALL(mpeg4_video_profiles),
.update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg4_update_thread_context),
+ .priv_class = &mpeg4_class,
+};
+
+
+#if CONFIG_MPEG4_VDPAU_DECODER
+static const AVClass mpeg4_vdpau_class = {
+ "MPEG4 Video VDPAU Decoder",
+ av_default_item_name,
+ mpeg4_options,
+ LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_mpeg4_vdpau_decoder = {
+ .name = "mpeg4_vdpau",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 (VDPAU)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG4,
+ .priv_data_size = sizeof(Mpeg4DecContext),
+ .init = decode_init,
+ .close = ff_h263_decode_end,
+ .decode = ff_h263_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
+ CODEC_CAP_HWACCEL_VDPAU,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VDPAU_MPEG4,
+ AV_PIX_FMT_NONE },
+ .priv_class = &mpeg4_vdpau_class,
};
+#endif
diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c
index ab279dd849..4b602f0a79 100644
--- a/libavcodec/mpeg4videoenc.c
+++ b/libavcodec/mpeg4videoenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -208,7 +208,7 @@ static inline int decide_ac_pred(MpegEncContext *s, int16_t block[6][64],
}
/**
- * modify mb_type & qscale so that encoding is acually possible in mpeg4
+ * modify mb_type & qscale so that encoding is actually possible in mpeg4
*/
void ff_clean_mpeg4_qscales(MpegEncContext *s)
{
@@ -278,19 +278,19 @@ static inline void mpeg4_encode_dc(PutBitContext *s, int level, int n)
if (n < 4) {
/* luminance */
- put_bits(&s->pb, ff_mpeg4_DCtab_lum[size][1], ff_mpeg4_DCtab_lum[size][0]);
+ put_bits(s, ff_mpeg4_DCtab_lum[size][1], ff_mpeg4_DCtab_lum[size][0]);
} else {
/* chrominance */
- put_bits(&s->pb, ff_mpeg4_DCtab_chrom[size][1], ff_mpeg4_DCtab_chrom[size][0]);
+ put_bits(s, ff_mpeg4_DCtab_chrom[size][1], ff_mpeg4_DCtab_chrom[size][0]);
}
/* encode remaining bits */
if (size > 0) {
if (level < 0)
level = (-level) ^ ((1 << size) - 1);
- put_bits(&s->pb, size, level);
+ put_bits(s, size, level);
if (size > 8)
- put_bits(&s->pb, 1, 1);
+ put_bits(s, 1, 1);
}
#endif
}
@@ -525,9 +525,9 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
s->last_mv[i][1][1] = 0;
}
- assert(s->dquant >= -2 && s->dquant <= 2);
- assert((s->dquant & 1) == 0);
- assert(mb_type >= 0);
+ av_assert2(s->dquant >= -2 && s->dquant <= 2);
+ av_assert2((s->dquant & 1) == 0);
+ 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 & ...
@@ -547,7 +547,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
if ((cbp | motion_x | motion_y | mb_type) == 0) {
/* direct MB with MV={0,0} */
- assert(s->dquant == 0);
+ av_assert2(s->dquant == 0);
put_bits(&s->pb, 1, 1); /* mb not coded modb1=1 */
@@ -584,12 +584,12 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
s->misc_bits += get_bits_diff(s);
if (!mb_type) {
- assert(s->mv_dir & MV_DIRECT);
+ av_assert2(s->mv_dir & MV_DIRECT);
ff_h263_encode_motion_vector(s, motion_x, motion_y, 1);
s->b_count++;
s->f_count++;
} else {
- assert(mb_type > 0 && mb_type < 4);
+ av_assert2(mb_type > 0 && mb_type < 4);
if (s->mv_type != MV_TYPE_FIELD) {
if (s->mv_dir & MV_DIR_FORWARD) {
ff_h263_encode_motion_vector(s,
@@ -669,10 +669,6 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
x = s->mb_x * 16;
y = s->mb_y * 16;
- if (x + 16 > s->width)
- x = s->width - 16;
- if (y + 16 > s->height)
- y = s->height - 16;
offset = x + y * s->linesize;
p_pic = s->new_picture.f->data[0] + offset;
@@ -689,7 +685,21 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
b_pic = pic->f->data[0] + offset;
if (!pic->shared)
b_pic += INPLACE_OFFSET;
- diff = s->mecc.sad[0](NULL, p_pic, b_pic, s->linesize, 16);
+
+ if (x + 16 > s->width || y + 16 > s->height) {
+ int x1, y1;
+ int xe = FFMIN(16, s->width - x);
+ int ye = FFMIN(16, s->height - y);
+ diff = 0;
+ for (y1 = 0; y1 < ye; y1++) {
+ for (x1 = 0; x1 < xe; x1++) {
+ diff += FFABS(p_pic[x1 + y1 * s->linesize] - b_pic[x1 + y1 * s->linesize]);
+ }
+ }
+ diff = diff * 256 / (xe * ye);
+ } else {
+ diff = s->mecc.sad[0](NULL, p_pic, b_pic, s->linesize, 16);
+ }
if (diff > s->qscale * 70) { // FIXME check that 70 is optimal
s->mb_skipped = 0;
break;
@@ -754,7 +764,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
if (s->dquant)
put_bits(pb2, 2, dquant_code[s->dquant + 2]);
- assert(!s->progressive_sequence);
+ av_assert2(!s->progressive_sequence);
if (cbp)
put_bits(pb2, 1, s->interlaced_dct);
put_bits(pb2, 1, 1);
@@ -778,7 +788,7 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64],
s->mv[0][1][1] - pred_y,
s->f_code);
} else {
- assert(s->mv_type == MV_TYPE_8X8);
+ av_assert2(s->mv_type == MV_TYPE_8X8);
put_bits(&s->pb,
ff_h263_inter_MCBPC_bits[cbpc + 16],
ff_h263_inter_MCBPC_code[cbpc + 16]);
@@ -894,7 +904,7 @@ void ff_set_mpeg4_time(MpegEncContext *s)
ff_mpeg4_init_direct_mv(s);
} else {
s->last_time_base = s->time_base;
- s->time_base = s->time / s->avctx->time_base.den;
+ s->time_base = FFUDIV(s->time, s->avctx->time_base.den);
}
}
@@ -910,13 +920,12 @@ static void mpeg4_encode_gop_header(MpegEncContext *s)
if (s->reordered_input_picture[1])
time = FFMIN(time, s->reordered_input_picture[1]->f->pts);
time = time * s->avctx->time_base.num;
+ s->last_time_base = FFUDIV(time, s->avctx->time_base.den);
- seconds = time / s->avctx->time_base.den;
- minutes = seconds / 60;
- seconds %= 60;
- hours = minutes / 60;
- minutes %= 60;
- hours %= 24;
+ seconds = FFUDIV(time, s->avctx->time_base.den);
+ minutes = FFUDIV(seconds, 60); seconds = FFUMOD(seconds, 60);
+ hours = FFUDIV(minutes, 60); minutes = FFUMOD(minutes, 60);
+ hours = FFUMOD(hours , 24);
put_bits(&s->pb, 5, hours);
put_bits(&s->pb, 6, minutes);
@@ -926,8 +935,6 @@ static void mpeg4_encode_gop_header(MpegEncContext *s)
put_bits(&s->pb, 1, !!(s->avctx->flags & CODEC_FLAG_CLOSED_GOP));
put_bits(&s->pb, 1, 0); // broken link == NO
- s->last_time_base = time / s->avctx->time_base.den;
-
ff_mpeg4_stuffing(&s->pb);
}
@@ -1011,6 +1018,8 @@ static void mpeg4_encode_vol_header(MpegEncContext *s,
put_bits(&s->pb, 4, s->aspect_ratio_info); /* aspect ratio info */
if (s->aspect_ratio_info == FF_ASPECT_EXTENDED) {
+ av_reduce(&s->avctx->sample_aspect_ratio.num, &s->avctx->sample_aspect_ratio.den,
+ s->avctx->sample_aspect_ratio.num, s->avctx->sample_aspect_ratio.den, 255);
put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.num);
put_bits(&s->pb, 8, s->avctx->sample_aspect_ratio.den);
}
@@ -1099,11 +1108,10 @@ void ff_mpeg4_encode_picture_header(MpegEncContext *s, int picture_number)
put_bits(&s->pb, 16, VOP_STARTCODE); /* vop header */
put_bits(&s->pb, 2, s->pict_type - 1); /* pict type: I = 0 , P = 1 */
- assert(s->time >= 0);
- time_div = s->time / s->avctx->time_base.den;
- time_mod = s->time % s->avctx->time_base.den;
+ time_div = FFUDIV(s->time, s->avctx->time_base.den);
+ time_mod = FFUMOD(s->time, s->avctx->time_base.den);
time_incr = time_div - s->last_time_base;
- assert(time_incr >= 0);
+ av_assert0(time_incr >= 0);
while (time_incr--)
put_bits(&s->pb, 1, 1);
@@ -1191,8 +1199,8 @@ static av_cold void init_uni_mpeg4_rl_tab(RLTable *rl, uint32_t *bits_tab,
{
int slevel, run, last;
- assert(MAX_LEVEL >= 64);
- assert(MAX_RUN >= 63);
+ av_assert0(MAX_LEVEL >= 64);
+ av_assert0(MAX_RUN >= 63);
for (slevel = -64; slevel < 64; slevel++) {
if (slevel == 0)
@@ -1287,6 +1295,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
int ret;
static int done = 0;
+ if (avctx->width >= (1<<13) || avctx->height >= (1<<13)) {
+ av_log(avctx, AV_LOG_ERROR, "dimensions too large for MPEG-4\n");
+ return AVERROR(EINVAL);
+ }
+
if ((ret = ff_mpv_encode_init(avctx)) < 0)
return ret;
diff --git a/libavcodec/mpeg_er.c b/libavcodec/mpeg_er.c
index 7a1b6b2764..3d90582db3 100644
--- a/libavcodec/mpeg_er.c
+++ b/libavcodec/mpeg_er.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@ static void set_erpic(ERPicture *dst, Picture *src)
{
int i;
+ memset(dst, 0, sizeof(*dst));
if (!src) {
dst->f = NULL;
dst->tf = NULL;
diff --git a/libavcodec/mpeg_er.h b/libavcodec/mpeg_er.h
index 19681843d7..bd74fbb0c8 100644
--- a/libavcodec/mpeg_er.h
+++ b/libavcodec/mpeg_er.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegaudio.c b/libavcodec/mpegaudio.c
index 1a8363540e..cba52992ef 100644
--- a/libavcodec/mpegaudio.c
+++ b/libavcodec/mpegaudio.c
@@ -2,20 +2,20 @@
* MPEG Audio common code
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegaudio.h b/libavcodec/mpegaudio.h
index b55680100b..1591a170d7 100644
--- a/libavcodec/mpegaudio.h
+++ b/libavcodec/mpegaudio.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,8 @@
#ifndef AVCODEC_MPEGAUDIO_H
#define AVCODEC_MPEGAUDIO_H
-#ifndef CONFIG_FLOAT
-# define CONFIG_FLOAT 0
+#ifndef USE_FLOATS
+# define USE_FLOATS 0
#endif
#include <stdint.h>
@@ -52,11 +52,13 @@
#define WFRAC_BITS 16 /* fractional bits for window */
#endif
+#define IMDCT_SCALAR 1.759
+
#define FRAC_ONE (1 << FRAC_BITS)
#define FIX(a) ((int)((a) * FRAC_ONE))
-#if CONFIG_FLOAT
+#if USE_FLOATS
# define INTFLOAT float
typedef float MPA_INT;
typedef float OUT_INT;
diff --git a/libavcodec/mpegaudio_parser.c b/libavcodec/mpegaudio_parser.c
index 84c20d882f..58098d89f0 100644
--- a/libavcodec/mpegaudio_parser.c
+++ b/libavcodec/mpegaudio_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,6 +55,7 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
int inc= FFMIN(buf_size - i, s->frame_size);
i += inc;
s->frame_size -= inc;
+ state = 0;
if(!s->frame_size){
next= i;
@@ -67,24 +68,26 @@ static int mpegaudio_parse(AVCodecParserContext *s1,
state= (state<<8) + buf[i++];
- ret = avpriv_mpa_decode_header(avctx, state, &sr, &channels, &frame_size, &bit_rate);
+ ret = avpriv_mpa_decode_header2(state, &sr, &channels, &frame_size, &bit_rate, &codec_id);
if (ret < 4) {
if (i > 4)
s->header_count = -2;
} else {
+ int header_threshold = avctx->codec_id != AV_CODEC_ID_NONE && avctx->codec_id != codec_id;
if((state&SAME_HEADER_MASK) != (s->header&SAME_HEADER_MASK) && s->header)
s->header_count= -3;
s->header= state;
s->header_count++;
s->frame_size = ret-4;
- if (s->header_count > 0) {
+ if (s->header_count > header_threshold) {
avctx->sample_rate= sr;
avctx->channels = channels;
s1->duration = frame_size;
+ avctx->codec_id = codec_id;
if (s->no_bitrate || !avctx->bit_rate) {
s->no_bitrate = 1;
- avctx->bit_rate += (bit_rate - avctx->bit_rate) / s->header_count;
+ avctx->bit_rate += (bit_rate - avctx->bit_rate) / (s->header_count - header_threshold);
}
}
diff --git a/libavcodec/mpegaudio_tablegen.c b/libavcodec/mpegaudio_tablegen.c
index b4c240bd7c..90c9de430a 100644
--- a/libavcodec/mpegaudio_tablegen.c
+++ b/libavcodec/mpegaudio_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegaudio_tablegen.h b/libavcodec/mpegaudio_tablegen.h
index 8a3e51ae60..86b2cd32b0 100644
--- a/libavcodec/mpegaudio_tablegen.h
+++ b/libavcodec/mpegaudio_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
#include <stdint.h>
#include <math.h>
+#include "libavutil/attributes.h"
#define TABLE_4_3_SIZE (8191 + 16)*4
#if CONFIG_HARDCODED_TABLES
@@ -39,8 +40,9 @@ static float exp_table_float[512];
static float expval_table_float[512][16];
#define FRAC_BITS 23
+#define IMDCT_SCALAR 1.759
-static void mpegaudio_tableinit(void)
+static av_cold void mpegaudio_tableinit(void)
{
int i, value, exponent;
for (i = 1; i < TABLE_4_3_SIZE; i++) {
@@ -48,7 +50,7 @@ static void mpegaudio_tableinit(void)
double f, fm;
int e, m;
/* cbrtf() isn't available on all systems, so we use powf(). */
- f = value * powf(value, 1.0 / 3.0) * pow(2, (i & 3) * 0.25);
+ f = value / IMDCT_SCALAR * pow(value, 1.0 / 3.0) * pow(2, (i & 3) * 0.25);
fm = frexp(f, &e);
m = (uint32_t)(fm * (1LL << 31) + 0.5);
e += FRAC_BITS - 31 + 5 - 100;
@@ -60,9 +62,9 @@ static void mpegaudio_tableinit(void)
for (exponent = 0; exponent < 512; exponent++) {
for (value = 0; value < 16; value++) {
/* cbrtf() isn't available on all systems, so we use powf(). */
- double f = (double)value * powf(value, 1.0 / 3.0) * pow(2, (exponent - 400) * 0.25 + FRAC_BITS + 5);
+ double f = (double)value * pow(value, 1.0 / 3.0) * pow(2, (exponent - 400) * 0.25 + FRAC_BITS + 5) / IMDCT_SCALAR;
/* llrint() isn't always available, so round and cast manually. */
- expval_table_fixed[exponent][value] = (long long int) (f >= 0 ? floor(f + 0.5) : ceil(f - 0.5));
+ expval_table_fixed[exponent][value] = (long long int) (f < 0xFFFFFFFF ? floor(f + 0.5) : 0xFFFFFFFF);
expval_table_float[exponent][value] = f;
}
exp_table_fixed[exponent] = expval_table_fixed[exponent][1];
diff --git a/libavcodec/mpegaudiodata.c b/libavcodec/mpegaudiodata.c
index 009a02a4e8..0569281109 100644
--- a/libavcodec/mpegaudiodata.c
+++ b/libavcodec/mpegaudiodata.c
@@ -2,20 +2,20 @@
* MPEG Audio common tables
* copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,11 +29,11 @@
const uint16_t avpriv_mpa_bitrate_tab[2][3][15] = {
{ {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 },
- {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 },
- {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } },
- { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
- {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
- {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 },
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } },
+ { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160},
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}
}
};
diff --git a/libavcodec/mpegaudiodata.h b/libavcodec/mpegaudiodata.h
index 2b8ff6587f..29a26588b2 100644
--- a/libavcodec/mpegaudiodata.h
+++ b/libavcodec/mpegaudiodata.h
@@ -2,20 +2,20 @@
* MPEG Audio common tables
* copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegaudiodec_fixed.c b/libavcodec/mpegaudiodec_fixed.c
index 6f21b0c61b..904c88561d 100644
--- a/libavcodec/mpegaudiodec_fixed.c
+++ b/libavcodec/mpegaudiodec_fixed.c
@@ -1,27 +1,27 @@
/*
* Fixed-point MPEG audio decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/samplefmt.h"
-#define CONFIG_FLOAT 0
+#define USE_FLOATS 0
#include "mpegaudio.h"
diff --git a/libavcodec/mpegaudiodec_float.c b/libavcodec/mpegaudiodec_float.c
index 3a76055522..f432c83296 100644
--- a/libavcodec/mpegaudiodec_float.c
+++ b/libavcodec/mpegaudiodec_float.c
@@ -2,27 +2,27 @@
* Float MPEG Audio decoder
* Copyright (c) 2010 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/samplefmt.h"
-#define CONFIG_FLOAT 1
+#define USE_FLOATS 1
#include "mpegaudio.h"
@@ -46,6 +46,7 @@ AVCodec ff_mp1float_decoder = {
.id = AV_CODEC_ID_MP1,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
+ .close = decode_close,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
.flush = flush,
@@ -63,6 +64,7 @@ AVCodec ff_mp2float_decoder = {
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
.decode = decode_frame,
+ .close = decode_close,
.capabilities = CODEC_CAP_DR1,
.flush = flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
@@ -78,6 +80,7 @@ AVCodec ff_mp3float_decoder = {
.id = AV_CODEC_ID_MP3,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
+ .close = decode_close,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
.flush = flush,
@@ -94,6 +97,7 @@ AVCodec ff_mp3adufloat_decoder = {
.id = AV_CODEC_ID_MP3ADU,
.priv_data_size = sizeof(MPADecodeContext),
.init = decode_init,
+ .close = decode_close,
.decode = decode_frame_adu,
.capabilities = CODEC_CAP_DR1,
.flush = flush,
diff --git a/libavcodec/mpegaudiodec_template.c b/libavcodec/mpegaudiodec_template.c
index 08dd18bf2e..1cc5ac47f4 100644
--- a/libavcodec/mpegaudiodec_template.c
+++ b/libavcodec/mpegaudiodec_template.c
@@ -2,20 +2,20 @@
* MPEG Audio decoder
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,7 @@
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/float_dsp.h"
+#include "libavutil/libm.h"
#include "avcodec.h"
#include "get_bits.h"
#include "internal.h"
@@ -84,7 +85,7 @@ typedef struct MPADecodeContext {
int err_recognition;
AVCodecContext* avctx;
MPADSPContext mpadsp;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
AVFrame *frame;
} MPADecodeContext;
@@ -184,6 +185,8 @@ static void compute_band_indexes(MPADecodeContext *s, GranuleDef *g)
{
if (g->block_type == 2) {
if (g->switch_point) {
+ if(s->sample_rate_index == 8)
+ avpriv_request_sample(s->avctx, "switch point in 8khz");
/* if switched mode, we handle the 36 first samples as
long blocks. For 8000Hz, we handle the 72 first
exponents as long blocks */
@@ -213,7 +216,7 @@ static inline int l1_unscale(int n, int mant, int scale_factor)
shift = scale_factor_modshift[scale_factor];
mod = shift & 3;
shift >>= 2;
- val = MUL64(mant + (-1 << n) + 1, scale_factor_mult[n-1][mod]);
+ val = MUL64((int)(mant + (-1U << n) + 1), scale_factor_mult[n-1][mod]);
shift += n;
/* NOTE: at this point, 1 <= shift >= 21 + 15 */
return (int)((val + (1LL << (shift - 1))) >> shift);
@@ -243,7 +246,10 @@ static inline int l3_unscale(int value, int exponent)
e = table_4_3_exp [4 * value + (exponent & 3)];
m = table_4_3_value[4 * value + (exponent & 3)];
e -= exponent >> 2;
- assert(e >= 1);
+#ifdef DEBUG
+ if(e < 1)
+ av_log(NULL, AV_LOG_WARNING, "l3_unscale: e is %d\n", e);
+#endif
if (e > 31)
return 0;
m = (m + (1 << (e - 1))) >> e;
@@ -307,7 +313,7 @@ static av_cold void decode_init_static(void)
INIT_VLC_USE_NEW_STATIC);
offset += huff_vlc_tables_sizes[i];
}
- assert(offset == FF_ARRAY_ELEMS(huff_vlc_tables));
+ av_assert0(offset == FF_ARRAY_ELEMS(huff_vlc_tables));
offset = 0;
for (i = 0; i < 2; i++) {
@@ -318,7 +324,7 @@ static av_cold void decode_init_static(void)
INIT_VLC_USE_NEW_STATIC);
offset += huff_quad_vlc_tables_sizes[i];
}
- assert(offset == FF_ARRAY_ELEMS(huff_quad_vlc_tables));
+ av_assert0(offset == FF_ARRAY_ELEMS(huff_quad_vlc_tables));
for (i = 0; i < 9; i++) {
k = 0;
@@ -371,7 +377,7 @@ static av_cold void decode_init_static(void)
for (j = 0; j < 2; j++) {
e = -(j + 1) * ((i + 1) >> 1);
- f = pow(2.0, e / 4.0);
+ f = exp2(e / 4.0);
k = i & 1;
is_table_lsf[j][k ^ 1][i] = FIXR(f);
is_table_lsf[j][k ][i] = FIXR(1.0);
@@ -382,11 +388,11 @@ static av_cold void decode_init_static(void)
}
for (i = 0; i < 8; i++) {
- float ci, cs, ca;
+ double ci, cs, ca;
ci = ci_table[i];
cs = 1.0 / sqrt(1.0 + ci * ci);
ca = cs * ci;
-#if !CONFIG_FLOAT
+#if !USE_FLOATS
csa_table[i][0] = FIXHR(cs/4);
csa_table[i][1] = FIXHR(ca/4);
csa_table[i][2] = FIXHR(ca/4) + FIXHR(cs/4);
@@ -400,6 +406,16 @@ static av_cold void decode_init_static(void)
}
}
+#if USE_FLOATS
+static av_cold int decode_close(AVCodecContext * avctx)
+{
+ MPADecodeContext *s = avctx->priv_data;
+ av_freep(&s->fdsp);
+
+ return 0;
+}
+#endif
+
static av_cold int decode_init(AVCodecContext * avctx)
{
static int initialized_tables = 0;
@@ -412,7 +428,12 @@ static av_cold int decode_init(AVCodecContext * avctx)
s->avctx = avctx;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+#if USE_FLOATS
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
+#endif
+
ff_mpadsp_init(&s->mpadsp);
if (avctx->request_sample_fmt == OUT_FMT &&
@@ -808,7 +829,7 @@ static void switch_buffer(MPADecodeContext *s, int *pos, int *end_pos,
if (s->in_gb.buffer && *pos >= s->gb.size_in_bits) {
s->gb = s->in_gb;
s->in_gb.buffer = NULL;
- assert((get_bits_count(&s->gb) & 7) == 0);
+ av_assert2((get_bits_count(&s->gb) & 7) == 0);
skip_bits_long(&s->gb, *pos - *end_pos);
*end_pos2 =
*end_pos = *end_pos2 + get_bits_count(&s->gb) - *pos;
@@ -822,7 +843,7 @@ static void switch_buffer(MPADecodeContext *s, int *pos, int *end_pos,
v = -v;
*dst = v;
*/
-#if CONFIG_FLOAT
+#if USE_FLOATS
#define READ_FLIP_SIGN(dst,src) \
v = AV_RN32A(src) ^ (get_bits1(&s->gb) << 31); \
AV_WN32A(dst, v);
@@ -937,7 +958,7 @@ static int huffman_decode(MPADecodeContext *s, GranuleDef *g,
s_index -= 4;
skip_bits_long(&s->gb, last_pos - pos);
av_log(s->avctx, AV_LOG_INFO, "overread, skip %d enddists: %d %d\n", last_pos - pos, end_pos-pos, end_pos2-pos);
- if(s->err_recognition & AV_EF_BITSTREAM)
+ if(s->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))
s_index=0;
break;
}
@@ -964,10 +985,10 @@ static int huffman_decode(MPADecodeContext *s, GranuleDef *g,
}
/* skip extension bits */
bits_left = end_pos2 - get_bits_count(&s->gb);
- if (bits_left < 0 && (s->err_recognition & AV_EF_BUFFER)) {
+ if (bits_left < 0 && (s->err_recognition & (AV_EF_BUFFER|AV_EF_COMPLIANT))) {
av_log(s->avctx, AV_LOG_ERROR, "bits_left=%d\n", bits_left);
s_index=0;
- } else if (bits_left > 0 && (s->err_recognition & AV_EF_BUFFER)) {
+ } else if (bits_left > 0 && (s->err_recognition & (AV_EF_BUFFER|AV_EF_AGGRESSIVE))) {
av_log(s->avctx, AV_LOG_ERROR, "bits_left=%d\n", bits_left);
s_index = 0;
}
@@ -1131,8 +1152,8 @@ found2:
/* ms stereo ONLY */
/* NOTE: the 1/sqrt(2) normalization factor is included in the
global gain */
-#if CONFIG_FLOAT
- s->fdsp.butterflies_float(g0->sb_hybrid, g1->sb_hybrid, 576);
+#if USE_FLOATS
+ s->fdsp->butterflies_float(g0->sb_hybrid, g1->sb_hybrid, 576);
#else
tab0 = g0->sb_hybrid;
tab1 = g1->sb_hybrid;
@@ -1146,7 +1167,18 @@ found2:
}
}
-#if CONFIG_FLOAT
+#if USE_FLOATS
+#if HAVE_MIPSFPU
+# include "mips/compute_antialias_float.h"
+#endif /* HAVE_MIPSFPU */
+#else
+#if HAVE_MIPSDSPR1
+# include "mips/compute_antialias_fixed.h"
+#endif /* HAVE_MIPSDSPR1 */
+#endif /* USE_FLOATS */
+
+#ifndef compute_antialias
+#if USE_FLOATS
#define AA(j) do { \
float tmp0 = ptr[-1-j]; \
float tmp1 = ptr[ j]; \
@@ -1192,6 +1224,7 @@ static void compute_antialias(MPADecodeContext *s, GranuleDef *g)
ptr += 18;
}
}
+#endif /* compute_antialias */
static void compute_imdct(MPADecodeContext *s, GranuleDef *g,
INTFLOAT *sb_samples, INTFLOAT *mdct_buf)
@@ -1361,9 +1394,8 @@ static int mp_decode_layer3(MPADecodeContext *s)
if (!s->adu_mode) {
int skip;
const uint8_t *ptr = s->gb.buffer + (get_bits_count(&s->gb)>>3);
- int extrasize = av_clip(get_bits_left(&s->gb) >> 3, 0,
- FFMAX(0, LAST_BUF_SIZE - s->last_buf_size));
- assert((get_bits_count(&s->gb) & 7) == 0);
+ int extrasize = av_clip(get_bits_left(&s->gb) >> 3, 0, EXTRABYTES);
+ av_assert1((get_bits_count(&s->gb) & 7) == 0);
/* now we get bits from the main_data_begin offset */
ff_dlog(s->avctx, "seekback:%d, lastbuf:%d\n",
main_data_begin, s->last_buf_size);
@@ -1372,7 +1404,7 @@ static int mp_decode_layer3(MPADecodeContext *s)
s->in_gb = s->gb;
init_get_bits(&s->gb, s->last_buf, s->last_buf_size*8);
#if !UNCHECKED_BITSTREAM_READER
- s->gb.size_in_bits_plus8 += extrasize * 8;
+ s->gb.size_in_bits_plus8 += FFMAX(extrasize, LAST_BUF_SIZE - s->last_buf_size) * 8;
#endif
s->last_buf_size <<= 3;
for (gr = 0; gr < nb_granules && (s->last_buf_size >> 3) < main_data_begin; gr++) {
@@ -1554,9 +1586,6 @@ static int mp_decode_frame(MPADecodeContext *s, OUT_INT **samples,
default:
nb_frames = mp_decode_layer3(s);
- if (nb_frames < 0)
- return nb_frames;
-
s->last_buf_size=0;
if (s->in_gb.buffer) {
align_get_bits(&s->gb);
@@ -1571,7 +1600,7 @@ static int mp_decode_frame(MPADecodeContext *s, OUT_INT **samples,
}
align_get_bits(&s->gb);
- assert((get_bits_count(&s->gb) & 7) == 0);
+ av_assert1((get_bits_count(&s->gb) & 7) == 0);
i = get_bits_left(&s->gb) >> 3;
if (i < 0 || i > BACKSTEP_SIZE || nb_frames < 0) {
@@ -1579,19 +1608,20 @@ static int mp_decode_frame(MPADecodeContext *s, OUT_INT **samples,
av_log(s->avctx, AV_LOG_ERROR, "invalid new backstep %d\n", i);
i = FFMIN(BACKSTEP_SIZE, buf_size - HEADER_SIZE);
}
- assert(i <= buf_size - HEADER_SIZE && i >= 0);
+ av_assert1(i <= buf_size - HEADER_SIZE && i >= 0);
memcpy(s->last_buf + s->last_buf_size, s->gb.buffer + buf_size - HEADER_SIZE - i, i);
s->last_buf_size += i;
}
+ if(nb_frames < 0)
+ return nb_frames;
+
/* get output buffer */
if (!samples) {
- av_assert0(s->frame != NULL);
+ av_assert0(s->frame);
s->frame->nb_samples = s->avctx->frame_size;
- if ((ret = ff_get_buffer(s->avctx, s->frame, 0)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(s->avctx, s->frame, 0)) < 0)
return ret;
- }
samples = (OUT_INT **)s->frame->extended_data;
}
@@ -1627,10 +1657,19 @@ static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame_ptr,
uint32_t header;
int ret;
+ while(buf_size && !*buf){
+ buf++;
+ buf_size--;
+ }
+
if (buf_size < HEADER_SIZE)
return AVERROR_INVALIDDATA;
header = AV_RB32(buf);
+ if (header>>8 == AV_RB32("TAG")>>8) {
+ av_log(avctx, AV_LOG_DEBUG, "discarding ID3 tag\n");
+ return buf_size;
+ }
if (ff_mpa_check_header(header) < 0) {
av_log(avctx, AV_LOG_ERROR, "Header missing\n");
return AVERROR_INVALIDDATA;
@@ -1651,6 +1690,7 @@ static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame_ptr,
av_log(avctx, AV_LOG_ERROR, "incomplete frame\n");
return AVERROR_INVALIDDATA;
} else if (s->frame_size < buf_size) {
+ av_log(avctx, AV_LOG_DEBUG, "incorrect frame size - multiple frames in buffer?\n");
buf_size= s->frame_size;
}
@@ -1680,7 +1720,9 @@ static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame_ptr,
static void mp_flush(MPADecodeContext *ctx)
{
memset(ctx->synth_buf, 0, sizeof(ctx->synth_buf));
+ memset(ctx->mdct_buf, 0, sizeof(ctx->mdct_buf));
ctx->last_buf_size = 0;
+ ctx->dither_state = 0;
}
static void flush(AVCodecContext *avctx)
@@ -1697,6 +1739,7 @@ static int decode_frame_adu(AVCodecContext *avctx, void *data,
MPADecodeContext *s = avctx->priv_data;
uint32_t header;
int len, ret;
+ int av_unused out_size;
len = buf_size;
@@ -1791,7 +1834,7 @@ static av_cold int decode_close_mp3on4(AVCodecContext * avctx)
int i;
for (i = 0; i < s->frames; i++)
- av_free(s->mp3decctx[i]);
+ av_freep(&s->mp3decctx[i]);
return 0;
}
@@ -1885,10 +1928,8 @@ static int decode_frame_mp3on4(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = MPA_FRAME_SIZE;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
out_samples = (OUT_INT **)frame->extended_data;
// Discard too short frames
@@ -1902,7 +1943,7 @@ static int decode_frame_mp3on4(AVCodecContext *avctx, void *data,
fsize = AV_RB16(buf) >> 4;
fsize = FFMIN3(fsize, len, MPA_MAX_CODED_FRAME_SIZE);
m = s->mp3decctx[fr];
- assert(m != NULL);
+ av_assert1(m);
if (fsize < HEADER_SIZE) {
av_log(avctx, AV_LOG_ERROR, "Frame size smaller than header size\n");
@@ -1910,8 +1951,10 @@ static int decode_frame_mp3on4(AVCodecContext *avctx, void *data,
}
header = (AV_RB32(buf) & 0x000fffff) | s->syncword; // patch header
- if (ff_mpa_check_header(header) < 0) // Bad header, discard block
- break;
+ if (ff_mpa_check_header(header) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Bad header, discard block\n");
+ return AVERROR_INVALIDDATA;
+ }
avpriv_mpegaudio_decode_header((MPADecodeHeader *)m, header);
@@ -1927,8 +1970,13 @@ static int decode_frame_mp3on4(AVCodecContext *avctx, void *data,
if (m->nb_channels > 1)
outptr[1] = out_samples[s->coff[fr] + 1];
- if ((ret = mp_decode_frame(m, outptr, buf, fsize)) < 0)
- return ret;
+ if ((ret = mp_decode_frame(m, outptr, buf, fsize)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "failed to decode channel %d\n", ch);
+ memset(outptr[0], 0, MPA_FRAME_SIZE*sizeof(OUT_INT));
+ if (m->nb_channels > 1)
+ memset(outptr[1], 0, MPA_FRAME_SIZE*sizeof(OUT_INT));
+ ret = m->nb_channels * MPA_FRAME_SIZE*sizeof(OUT_INT);
+ }
out_size += ret;
buf += fsize;
@@ -1936,6 +1984,10 @@ static int decode_frame_mp3on4(AVCodecContext *avctx, void *data,
avctx->bit_rate += m->bit_rate;
}
+ if (ch != avctx->channels) {
+ av_log(avctx, AV_LOG_ERROR, "failed to decode all channels\n");
+ return AVERROR_INVALIDDATA;
+ }
/* update codec info */
avctx->sample_rate = s->mp3decctx[0]->sample_rate;
diff --git a/libavcodec/mpegaudiodecheader.c b/libavcodec/mpegaudiodecheader.c
index 3d840d7ecb..d522c064ac 100644
--- a/libavcodec/mpegaudiodecheader.c
+++ b/libavcodec/mpegaudiodecheader.c
@@ -2,20 +2,20 @@
* MPEG Audio header decoder
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "libavutil/common.h"
#include "avcodec.h"
+#include "internal.h"
#include "mpegaudio.h"
#include "mpegaudiodata.h"
#include "mpegaudiodecheader.h"
@@ -112,7 +113,7 @@ int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header)
return 0;
}
-int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate)
+int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate, enum AVCodecID *codec_id)
{
MPADecodeHeader s1, *s = &s1;
@@ -125,17 +126,17 @@ int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_r
switch(s->layer) {
case 1:
- avctx->codec_id = AV_CODEC_ID_MP1;
+ *codec_id = AV_CODEC_ID_MP1;
*frame_size = 384;
break;
case 2:
- avctx->codec_id = AV_CODEC_ID_MP2;
+ *codec_id = AV_CODEC_ID_MP2;
*frame_size = 1152;
break;
default:
case 3:
- if (avctx->codec_id != AV_CODEC_ID_MP3ADU)
- avctx->codec_id = AV_CODEC_ID_MP3;
+ if (*codec_id != AV_CODEC_ID_MP3ADU)
+ *codec_id = AV_CODEC_ID_MP3;
if (s->lsf)
*frame_size = 576;
else
@@ -148,3 +149,8 @@ int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_r
*bit_rate = s->bit_rate;
return s->frame_size;
}
+
+int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate)
+{
+ return avpriv_mpa_decode_header2(head, sample_rate, channels, frame_size, bit_rate, &avctx->codec_id);
+}
diff --git a/libavcodec/mpegaudiodecheader.h b/libavcodec/mpegaudiodecheader.h
index 764e8abde4..444b85f265 100644
--- a/libavcodec/mpegaudiodecheader.h
+++ b/libavcodec/mpegaudiodecheader.h
@@ -2,20 +2,20 @@
* MPEG Audio header decoder
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,6 +56,8 @@ int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header);
header, otherwise the coded frame size in bytes */
int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate);
+int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id);
+
/* fast header check for resync */
static inline int ff_mpa_check_header(uint32_t header){
/* header */
diff --git a/libavcodec/mpegaudiodectab.h b/libavcodec/mpegaudiodectab.h
index 1221657988..accd12b8e2 100644
--- a/libavcodec/mpegaudiodectab.h
+++ b/libavcodec/mpegaudiodectab.h
@@ -2,20 +2,20 @@
* MPEG Audio decoder
* copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegaudiodsp.c b/libavcodec/mpegaudiodsp.c
index 58ea1d1585..5fe3444896 100644
--- a/libavcodec/mpegaudiodsp.c
+++ b/libavcodec/mpegaudiodsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,4 +45,6 @@ av_cold void ff_mpadsp_init(MPADSPContext *s)
if (ARCH_ARM) ff_mpadsp_init_arm(s);
if (ARCH_PPC) ff_mpadsp_init_ppc(s);
if (ARCH_X86) ff_mpadsp_init_x86(s);
+ if (HAVE_MIPSFPU) ff_mpadsp_init_mipsfpu(s);
+ if (HAVE_MIPSDSPR1) ff_mpadsp_init_mipsdspr1(s);
}
diff --git a/libavcodec/mpegaudiodsp.h b/libavcodec/mpegaudiodsp.h
index 909c652951..a722a2f36b 100644
--- a/libavcodec/mpegaudiodsp.h
+++ b/libavcodec/mpegaudiodsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@ typedef struct MPADSPContext {
int *dither_state, int16_t *samples, int incr);
void (*dct32_float)(float *dst, const float *src);
void (*dct32_fixed)(int *dst, const int *src);
+
void (*imdct36_blocks_float)(float *out, float *buf, float *in,
int count, int switch_point, int block_type);
void (*imdct36_blocks_fixed)(int *out, int *buf, int *in,
@@ -58,6 +59,8 @@ void ff_mpadsp_init_aarch64(MPADSPContext *s);
void ff_mpadsp_init_arm(MPADSPContext *s);
void ff_mpadsp_init_ppc(MPADSPContext *s);
void ff_mpadsp_init_x86(MPADSPContext *s);
+void ff_mpadsp_init_mipsfpu(MPADSPContext *s);
+void ff_mpadsp_init_mipsdspr1(MPADSPContext *s);
void ff_mpa_synth_init_float(float *window);
void ff_mpa_synth_init_fixed(int32_t *window);
diff --git a/libavcodec/mpegaudiodsp_data.c b/libavcodec/mpegaudiodsp_data.c
index 5cf86b8352..4550de9b80 100644
--- a/libavcodec/mpegaudiodsp_data.c
+++ b/libavcodec/mpegaudiodsp_data.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegaudiodsp_fixed.c b/libavcodec/mpegaudiodsp_fixed.c
index 3c49a568b7..83c9d66095 100644
--- a/libavcodec/mpegaudiodsp_fixed.c
+++ b/libavcodec/mpegaudiodsp_fixed.c
@@ -1,20 +1,20 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define CONFIG_FLOAT 0
+#define USE_FLOATS 0
#include "mpegaudiodsp_template.c"
diff --git a/libavcodec/mpegaudiodsp_float.c b/libavcodec/mpegaudiodsp_float.c
index 2d8d53ea26..c45b136089 100644
--- a/libavcodec/mpegaudiodsp_float.c
+++ b/libavcodec/mpegaudiodsp_float.c
@@ -1,20 +1,20 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define CONFIG_FLOAT 1
+#define USE_FLOATS 1
#include "mpegaudiodsp_template.c"
diff --git a/libavcodec/mpegaudiodsp_template.c b/libavcodec/mpegaudiodsp_template.c
index 621bbd4eba..62454ca306 100644
--- a/libavcodec/mpegaudiodsp_template.c
+++ b/libavcodec/mpegaudiodsp_template.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
#include "mpegaudiodsp.h"
#include "mpegaudio.h"
-#if CONFIG_FLOAT
+#if USE_FLOATS
#define RENAME(n) n##_float
static inline float round_sample(float *sum)
@@ -125,7 +125,7 @@ void RENAME(ff_mpadsp_apply_window)(MPA_INT *synth_buf, MPA_INT *window,
register const MPA_INT *w, *w2, *p;
int j;
OUT_INT *samples2;
-#if CONFIG_FLOAT
+#if USE_FLOATS
float sum, sum2;
#else
int64_t sum, sum2;
@@ -200,7 +200,7 @@ av_cold void RENAME(ff_mpa_synth_init)(MPA_INT *window)
for(i=0;i<257;i++) {
INTFLOAT v;
v = ff_mpa_enwindow[i];
-#if CONFIG_FLOAT
+#if USE_FLOATS
v *= 1.0 / (1LL<<(16 + FRAC_BITS));
#endif
window[i] = v;
@@ -243,7 +243,7 @@ av_cold void RENAME(ff_init_mpadsp_tabs)(void)
else if (i < 18) d = 1;
}
//merge last stage of imdct into the window coefficients
- d *= 0.5 / cos(M_PI * (2 * i + 19) / 72);
+ d *= 0.5 * IMDCT_SCALAR / cos(M_PI * (2 * i + 19) / 72);
if (j == 2)
RENAME(ff_mdct_win)[j][i/3] = FIXHR((d / (1<<5)));
@@ -398,3 +398,4 @@ void RENAME(ff_imdct36_blocks)(INTFLOAT *out, INTFLOAT *buf, INTFLOAT *in,
out++;
}
}
+
diff --git a/libavcodec/mpegaudioenc.c b/libavcodec/mpegaudioenc.c
deleted file mode 100644
index 7b0261f2cc..0000000000
--- a/libavcodec/mpegaudioenc.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * The simplest mpeg audio layer 2 encoder
- * Copyright (c) 2000, 2001 Fabrice Bellard
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * The simplest mpeg audio layer 2 encoder.
- */
-
-#include "libavutil/channel_layout.h"
-
-#include "avcodec.h"
-#include "internal.h"
-#include "put_bits.h"
-
-#define FRAC_BITS 15 /* fractional bits for sb_samples and dct */
-#define WFRAC_BITS 14 /* fractional bits for window */
-
-#include "mpegaudio.h"
-#include "mpegaudiodsp.h"
-#include "mpegaudiodata.h"
-#include "mpegaudiotab.h"
-
-/* currently, cannot change these constants (need to modify
- quantization stage) */
-#define MUL(a,b) (((int64_t)(a) * (int64_t)(b)) >> FRAC_BITS)
-
-#define SAMPLES_BUF_SIZE 4096
-
-typedef struct MpegAudioContext {
- PutBitContext pb;
- int nb_channels;
- int lsf; /* 1 if mpeg2 low bitrate selected */
- int bitrate_index; /* bit rate */
- int freq_index;
- int frame_size; /* frame size, in bits, without padding */
- /* padding computation */
- int frame_frac, frame_frac_incr, do_padding;
- short samples_buf[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */
- int samples_offset[MPA_MAX_CHANNELS]; /* offset in samples_buf */
- int sb_samples[MPA_MAX_CHANNELS][3][12][SBLIMIT];
- unsigned char scale_factors[MPA_MAX_CHANNELS][SBLIMIT][3]; /* scale factors */
- /* code to group 3 scale factors */
- unsigned char scale_code[MPA_MAX_CHANNELS][SBLIMIT];
- int sblimit; /* number of used subbands */
- const unsigned char *alloc_table;
- int16_t filter_bank[512];
- int scale_factor_table[64];
- unsigned char scale_diff_table[128];
- float scale_factor_inv_table[64];
- unsigned short total_quant_bits[17]; /* total number of bits per allocation group */
-} MpegAudioContext;
-
-static av_cold int MPA_encode_init(AVCodecContext *avctx)
-{
- MpegAudioContext *s = avctx->priv_data;
- int freq = avctx->sample_rate;
- int bitrate = avctx->bit_rate;
- int channels = avctx->channels;
- int i, v, table;
- float a;
-
- if (channels <= 0 || channels > 2){
- av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed in mp2\n", channels);
- return AVERROR(EINVAL);
- }
- bitrate = bitrate / 1000;
- s->nb_channels = channels;
- avctx->frame_size = MPA_FRAME_SIZE;
- avctx->initial_padding = 512 - 32 + 1;
-
- /* encoding freq */
- s->lsf = 0;
- for(i=0;i<3;i++) {
- if (avpriv_mpa_freq_tab[i] == freq)
- break;
- if ((avpriv_mpa_freq_tab[i] / 2) == freq) {
- s->lsf = 1;
- break;
- }
- }
- if (i == 3){
- av_log(avctx, AV_LOG_ERROR, "Sampling rate %d is not allowed in mp2\n", freq);
- return AVERROR(EINVAL);
- }
- s->freq_index = i;
-
- /* encoding bitrate & frequency */
- for(i=0;i<15;i++) {
- if (avpriv_mpa_bitrate_tab[s->lsf][1][i] == bitrate)
- break;
- }
- if (i == 15){
- av_log(avctx, AV_LOG_ERROR, "bitrate %d is not allowed in mp2\n", bitrate);
- return AVERROR(EINVAL);
- }
- s->bitrate_index = i;
-
- /* compute total header size & pad bit */
-
- a = (float)(bitrate * 1000 * MPA_FRAME_SIZE) / (freq * 8.0);
- s->frame_size = ((int)a) * 8;
-
- /* frame fractional size to compute padding */
- s->frame_frac = 0;
- s->frame_frac_incr = (int)((a - floor(a)) * 65536.0);
-
- /* select the right allocation table */
- table = ff_mpa_l2_select_table(bitrate, s->nb_channels, freq, s->lsf);
-
- /* number of used subbands */
- s->sblimit = ff_mpa_sblimit_table[table];
- s->alloc_table = ff_mpa_alloc_tables[table];
-
- ff_dlog(avctx, "%d kb/s, %d Hz, frame_size=%d bits, table=%d, padincr=%x\n",
- bitrate, freq, s->frame_size, table, s->frame_frac_incr);
-
- for(i=0;i<s->nb_channels;i++)
- s->samples_offset[i] = 0;
-
- for(i=0;i<257;i++) {
- int v;
- v = ff_mpa_enwindow[i];
-#if WFRAC_BITS != 16
- v = (v + (1 << (16 - WFRAC_BITS - 1))) >> (16 - WFRAC_BITS);
-#endif
- s->filter_bank[i] = v;
- if ((i & 63) != 0)
- v = -v;
- if (i != 0)
- s->filter_bank[512 - i] = v;
- }
-
- for(i=0;i<64;i++) {
- v = (int)(pow(2.0, (3 - i) / 3.0) * (1 << 20));
- if (v <= 0)
- v = 1;
- s->scale_factor_table[i] = v;
- s->scale_factor_inv_table[i] = pow(2.0, -(3 - i) / 3.0) / (float)(1 << 20);
- }
- for(i=0;i<128;i++) {
- v = i - 64;
- if (v <= -3)
- v = 0;
- else if (v < 0)
- v = 1;
- else if (v == 0)
- v = 2;
- else if (v < 3)
- v = 3;
- else
- v = 4;
- s->scale_diff_table[i] = v;
- }
-
- for(i=0;i<17;i++) {
- v = ff_mpa_quant_bits[i];
- if (v < 0)
- v = -v;
- else
- v = v * 3;
- s->total_quant_bits[i] = 12 * v;
- }
-
- return 0;
-}
-
-/* 32 point floating point IDCT without 1/sqrt(2) coef zero scaling */
-static void idct32(int *out, int *tab)
-{
- int i, j;
- int *t, *t1, xr;
- const int *xp = costab32;
-
- for(j=31;j>=3;j-=2) tab[j] += tab[j - 2];
-
- t = tab + 30;
- t1 = tab + 2;
- do {
- t[0] += t[-4];
- t[1] += t[1 - 4];
- t -= 4;
- } while (t != t1);
-
- t = tab + 28;
- t1 = tab + 4;
- do {
- t[0] += t[-8];
- t[1] += t[1-8];
- t[2] += t[2-8];
- t[3] += t[3-8];
- t -= 8;
- } while (t != t1);
-
- t = tab;
- t1 = tab + 32;
- do {
- t[ 3] = -t[ 3];
- t[ 6] = -t[ 6];
-
- t[11] = -t[11];
- t[12] = -t[12];
- t[13] = -t[13];
- t[15] = -t[15];
- t += 16;
- } while (t != t1);
-
-
- t = tab;
- t1 = tab + 8;
- do {
- int x1, x2, x3, x4;
-
- x3 = MUL(t[16], FIX(SQRT2*0.5));
- x4 = t[0] - x3;
- x3 = t[0] + x3;
-
- x2 = MUL(-(t[24] + t[8]), FIX(SQRT2*0.5));
- x1 = MUL((t[8] - x2), xp[0]);
- x2 = MUL((t[8] + x2), xp[1]);
-
- t[ 0] = x3 + x1;
- t[ 8] = x4 - x2;
- t[16] = x4 + x2;
- t[24] = x3 - x1;
- t++;
- } while (t != t1);
-
- xp += 2;
- t = tab;
- t1 = tab + 4;
- do {
- xr = MUL(t[28],xp[0]);
- t[28] = (t[0] - xr);
- t[0] = (t[0] + xr);
-
- xr = MUL(t[4],xp[1]);
- t[ 4] = (t[24] - xr);
- t[24] = (t[24] + xr);
-
- xr = MUL(t[20],xp[2]);
- t[20] = (t[8] - xr);
- t[ 8] = (t[8] + xr);
-
- xr = MUL(t[12],xp[3]);
- t[12] = (t[16] - xr);
- t[16] = (t[16] + xr);
- t++;
- } while (t != t1);
- xp += 4;
-
- for (i = 0; i < 4; i++) {
- xr = MUL(tab[30-i*4],xp[0]);
- tab[30-i*4] = (tab[i*4] - xr);
- tab[ i*4] = (tab[i*4] + xr);
-
- xr = MUL(tab[ 2+i*4],xp[1]);
- tab[ 2+i*4] = (tab[28-i*4] - xr);
- tab[28-i*4] = (tab[28-i*4] + xr);
-
- xr = MUL(tab[31-i*4],xp[0]);
- tab[31-i*4] = (tab[1+i*4] - xr);
- tab[ 1+i*4] = (tab[1+i*4] + xr);
-
- xr = MUL(tab[ 3+i*4],xp[1]);
- tab[ 3+i*4] = (tab[29-i*4] - xr);
- tab[29-i*4] = (tab[29-i*4] + xr);
-
- xp += 2;
- }
-
- t = tab + 30;
- t1 = tab + 1;
- do {
- xr = MUL(t1[0], *xp);
- t1[0] = (t[0] - xr);
- t[0] = (t[0] + xr);
- t -= 2;
- t1 += 2;
- xp++;
- } while (t >= tab);
-
- for(i=0;i<32;i++) {
- out[i] = tab[bitinv32[i]];
- }
-}
-
-#define WSHIFT (WFRAC_BITS + 15 - FRAC_BITS)
-
-static void filter(MpegAudioContext *s, int ch, const short *samples, int incr)
-{
- short *p, *q;
- int sum, offset, i, j;
- int tmp[64];
- int tmp1[32];
- int *out;
-
- offset = s->samples_offset[ch];
- out = &s->sb_samples[ch][0][0][0];
- for(j=0;j<36;j++) {
- /* 32 samples at once */
- for(i=0;i<32;i++) {
- s->samples_buf[ch][offset + (31 - i)] = samples[0];
- samples += incr;
- }
-
- /* filter */
- p = s->samples_buf[ch] + offset;
- q = s->filter_bank;
- /* maxsum = 23169 */
- for(i=0;i<64;i++) {
- sum = p[0*64] * q[0*64];
- sum += p[1*64] * q[1*64];
- sum += p[2*64] * q[2*64];
- sum += p[3*64] * q[3*64];
- sum += p[4*64] * q[4*64];
- sum += p[5*64] * q[5*64];
- sum += p[6*64] * q[6*64];
- sum += p[7*64] * q[7*64];
- tmp[i] = sum;
- p++;
- q++;
- }
- tmp1[0] = tmp[16] >> WSHIFT;
- for( i=1; i<=16; i++ ) tmp1[i] = (tmp[i+16]+tmp[16-i]) >> WSHIFT;
- for( i=17; i<=31; i++ ) tmp1[i] = (tmp[i+16]-tmp[80-i]) >> WSHIFT;
-
- idct32(out, tmp1);
-
- /* advance of 32 samples */
- offset -= 32;
- out += 32;
- /* handle the wrap around */
- if (offset < 0) {
- memmove(s->samples_buf[ch] + SAMPLES_BUF_SIZE - (512 - 32),
- s->samples_buf[ch], (512 - 32) * 2);
- offset = SAMPLES_BUF_SIZE - 512;
- }
- }
- s->samples_offset[ch] = offset;
-}
-
-static void compute_scale_factors(MpegAudioContext *s,
- unsigned char scale_code[SBLIMIT],
- unsigned char scale_factors[SBLIMIT][3],
- int sb_samples[3][12][SBLIMIT],
- int sblimit)
-{
- int *p, vmax, v, n, i, j, k, code;
- int index, d1, d2;
- unsigned char *sf = &scale_factors[0][0];
-
- for(j=0;j<sblimit;j++) {
- for(i=0;i<3;i++) {
- /* find the max absolute value */
- p = &sb_samples[i][0][j];
- vmax = abs(*p);
- for(k=1;k<12;k++) {
- p += SBLIMIT;
- v = abs(*p);
- if (v > vmax)
- vmax = v;
- }
- /* compute the scale factor index using log 2 computations */
- if (vmax > 1) {
- n = av_log2(vmax);
- /* n is the position of the MSB of vmax. now
- use at most 2 compares to find the index */
- index = (21 - n) * 3 - 3;
- if (index >= 0) {
- while (vmax <= s->scale_factor_table[index+1])
- index++;
- } else {
- index = 0; /* very unlikely case of overflow */
- }
- } else {
- index = 62; /* value 63 is not allowed */
- }
-
- ff_dlog(NULL, "%2d:%d in=%x %x %d\n",
- j, i, vmax, s->scale_factor_table[index], index);
- /* store the scale factor */
- assert(index >=0 && index <= 63);
- sf[i] = index;
- }
-
- /* compute the transmission factor : look if the scale factors
- are close enough to each other */
- d1 = s->scale_diff_table[sf[0] - sf[1] + 64];
- d2 = s->scale_diff_table[sf[1] - sf[2] + 64];
-
- /* handle the 25 cases */
- switch(d1 * 5 + d2) {
- case 0*5+0:
- case 0*5+4:
- case 3*5+4:
- case 4*5+0:
- case 4*5+4:
- code = 0;
- break;
- case 0*5+1:
- case 0*5+2:
- case 4*5+1:
- case 4*5+2:
- code = 3;
- sf[2] = sf[1];
- break;
- case 0*5+3:
- case 4*5+3:
- code = 3;
- sf[1] = sf[2];
- break;
- case 1*5+0:
- case 1*5+4:
- case 2*5+4:
- code = 1;
- sf[1] = sf[0];
- break;
- case 1*5+1:
- case 1*5+2:
- case 2*5+0:
- case 2*5+1:
- case 2*5+2:
- code = 2;
- sf[1] = sf[2] = sf[0];
- break;
- case 2*5+3:
- case 3*5+3:
- code = 2;
- sf[0] = sf[1] = sf[2];
- break;
- case 3*5+0:
- case 3*5+1:
- case 3*5+2:
- code = 2;
- sf[0] = sf[2] = sf[1];
- break;
- case 1*5+3:
- code = 2;
- if (sf[0] > sf[2])
- sf[0] = sf[2];
- sf[1] = sf[2] = sf[0];
- break;
- default:
- assert(0); //cannot happen
- code = 0; /* kill warning */
- }
-
- ff_dlog(NULL, "%d: %2d %2d %2d %d %d -> %d\n", j,
- sf[0], sf[1], sf[2], d1, d2, code);
- scale_code[j] = code;
- sf += 3;
- }
-}
-
-/* The most important function : psycho acoustic module. In this
- encoder there is basically none, so this is the worst you can do,
- but also this is the simpler. */
-static void psycho_acoustic_model(MpegAudioContext *s, short smr[SBLIMIT])
-{
- int i;
-
- for(i=0;i<s->sblimit;i++) {
- smr[i] = (int)(fixed_smr[i] * 10);
- }
-}
-
-
-#define SB_NOTALLOCATED 0
-#define SB_ALLOCATED 1
-#define SB_NOMORE 2
-
-/* Try to maximize the smr while using a number of bits inferior to
- the frame size. I tried to make the code simpler, faster and
- smaller than other encoders :-) */
-static void compute_bit_allocation(MpegAudioContext *s,
- short smr1[MPA_MAX_CHANNELS][SBLIMIT],
- unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
- int *padding)
-{
- int i, ch, b, max_smr, max_ch, max_sb, current_frame_size, max_frame_size;
- int incr;
- short smr[MPA_MAX_CHANNELS][SBLIMIT];
- unsigned char subband_status[MPA_MAX_CHANNELS][SBLIMIT];
- const unsigned char *alloc;
-
- memcpy(smr, smr1, s->nb_channels * sizeof(short) * SBLIMIT);
- memset(subband_status, SB_NOTALLOCATED, s->nb_channels * SBLIMIT);
- memset(bit_alloc, 0, s->nb_channels * SBLIMIT);
-
- /* compute frame size and padding */
- max_frame_size = s->frame_size;
- s->frame_frac += s->frame_frac_incr;
- if (s->frame_frac >= 65536) {
- s->frame_frac -= 65536;
- s->do_padding = 1;
- max_frame_size += 8;
- } else {
- s->do_padding = 0;
- }
-
- /* compute the header + bit alloc size */
- current_frame_size = 32;
- alloc = s->alloc_table;
- for(i=0;i<s->sblimit;i++) {
- incr = alloc[0];
- current_frame_size += incr * s->nb_channels;
- alloc += 1 << incr;
- }
- for(;;) {
- /* look for the subband with the largest signal to mask ratio */
- max_sb = -1;
- max_ch = -1;
- max_smr = INT_MIN;
- for(ch=0;ch<s->nb_channels;ch++) {
- for(i=0;i<s->sblimit;i++) {
- if (smr[ch][i] > max_smr && subband_status[ch][i] != SB_NOMORE) {
- max_smr = smr[ch][i];
- max_sb = i;
- max_ch = ch;
- }
- }
- }
- if (max_sb < 0)
- break;
- ff_dlog(NULL, "current=%d max=%d max_sb=%d max_ch=%d alloc=%d\n",
- current_frame_size, max_frame_size, max_sb, max_ch,
- bit_alloc[max_ch][max_sb]);
-
- /* find alloc table entry (XXX: not optimal, should use
- pointer table) */
- alloc = s->alloc_table;
- for(i=0;i<max_sb;i++) {
- alloc += 1 << alloc[0];
- }
-
- if (subband_status[max_ch][max_sb] == SB_NOTALLOCATED) {
- /* nothing was coded for this band: add the necessary bits */
- incr = 2 + nb_scale_factors[s->scale_code[max_ch][max_sb]] * 6;
- incr += s->total_quant_bits[alloc[1]];
- } else {
- /* increments bit allocation */
- b = bit_alloc[max_ch][max_sb];
- incr = s->total_quant_bits[alloc[b + 1]] -
- s->total_quant_bits[alloc[b]];
- }
-
- if (current_frame_size + incr <= max_frame_size) {
- /* can increase size */
- b = ++bit_alloc[max_ch][max_sb];
- current_frame_size += incr;
- /* decrease smr by the resolution we added */
- smr[max_ch][max_sb] = smr1[max_ch][max_sb] - quant_snr[alloc[b]];
- /* max allocation size reached ? */
- if (b == ((1 << alloc[0]) - 1))
- subband_status[max_ch][max_sb] = SB_NOMORE;
- else
- subband_status[max_ch][max_sb] = SB_ALLOCATED;
- } else {
- /* cannot increase the size of this subband */
- subband_status[max_ch][max_sb] = SB_NOMORE;
- }
- }
- *padding = max_frame_size - current_frame_size;
- assert(*padding >= 0);
-}
-
-/*
- * Output the mpeg audio layer 2 frame. Note how the code is small
- * compared to other encoders :-)
- */
-static void encode_frame(MpegAudioContext *s,
- unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
- int padding)
-{
- int i, j, k, l, bit_alloc_bits, b, ch;
- unsigned char *sf;
- int q[3];
- PutBitContext *p = &s->pb;
-
- /* header */
-
- put_bits(p, 12, 0xfff);
- put_bits(p, 1, 1 - s->lsf); /* 1 = mpeg1 ID, 0 = mpeg2 lsf ID */
- put_bits(p, 2, 4-2); /* layer 2 */
- put_bits(p, 1, 1); /* no error protection */
- put_bits(p, 4, s->bitrate_index);
- put_bits(p, 2, s->freq_index);
- put_bits(p, 1, s->do_padding); /* use padding */
- put_bits(p, 1, 0); /* private_bit */
- put_bits(p, 2, s->nb_channels == 2 ? MPA_STEREO : MPA_MONO);
- put_bits(p, 2, 0); /* mode_ext */
- put_bits(p, 1, 0); /* no copyright */
- put_bits(p, 1, 1); /* original */
- put_bits(p, 2, 0); /* no emphasis */
-
- /* bit allocation */
- j = 0;
- for(i=0;i<s->sblimit;i++) {
- bit_alloc_bits = s->alloc_table[j];
- for(ch=0;ch<s->nb_channels;ch++) {
- put_bits(p, bit_alloc_bits, bit_alloc[ch][i]);
- }
- j += 1 << bit_alloc_bits;
- }
-
- /* scale codes */
- for(i=0;i<s->sblimit;i++) {
- for(ch=0;ch<s->nb_channels;ch++) {
- if (bit_alloc[ch][i])
- put_bits(p, 2, s->scale_code[ch][i]);
- }
- }
-
- /* scale factors */
- for(i=0;i<s->sblimit;i++) {
- for(ch=0;ch<s->nb_channels;ch++) {
- if (bit_alloc[ch][i]) {
- sf = &s->scale_factors[ch][i][0];
- switch(s->scale_code[ch][i]) {
- case 0:
- put_bits(p, 6, sf[0]);
- put_bits(p, 6, sf[1]);
- put_bits(p, 6, sf[2]);
- break;
- case 3:
- case 1:
- put_bits(p, 6, sf[0]);
- put_bits(p, 6, sf[2]);
- break;
- case 2:
- put_bits(p, 6, sf[0]);
- break;
- }
- }
- }
- }
-
- /* quantization & write sub band samples */
-
- for(k=0;k<3;k++) {
- for(l=0;l<12;l+=3) {
- j = 0;
- for(i=0;i<s->sblimit;i++) {
- bit_alloc_bits = s->alloc_table[j];
- for(ch=0;ch<s->nb_channels;ch++) {
- b = bit_alloc[ch][i];
- if (b) {
- int qindex, steps, m, sample, bits;
- /* we encode 3 sub band samples of the same sub band at a time */
- qindex = s->alloc_table[j+b];
- steps = ff_mpa_quant_steps[qindex];
- for(m=0;m<3;m++) {
- float a;
- sample = s->sb_samples[ch][k][l + m][i];
- /* divide by scale factor */
- a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]];
- q[m] = (int)((a + 1.0) * steps * 0.5);
- if (q[m] >= steps)
- q[m] = steps - 1;
- assert(q[m] >= 0 && q[m] < steps);
- }
- bits = ff_mpa_quant_bits[qindex];
- if (bits < 0) {
- /* group the 3 values to save bits */
- put_bits(p, -bits,
- q[0] + steps * (q[1] + steps * q[2]));
- } else {
- put_bits(p, bits, q[0]);
- put_bits(p, bits, q[1]);
- put_bits(p, bits, q[2]);
- }
- }
- }
- /* next subband in alloc table */
- j += 1 << bit_alloc_bits;
- }
- }
- }
-
- /* padding */
- for(i=0;i<padding;i++)
- put_bits(p, 1, 0);
-
- /* flush */
- flush_put_bits(p);
-}
-
-static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
- const AVFrame *frame, int *got_packet_ptr)
-{
- MpegAudioContext *s = avctx->priv_data;
- const int16_t *samples = (const int16_t *)frame->data[0];
- short smr[MPA_MAX_CHANNELS][SBLIMIT];
- unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT];
- int padding, i, ret;
-
- for(i=0;i<s->nb_channels;i++) {
- filter(s, i, samples + i, s->nb_channels);
- }
-
- for(i=0;i<s->nb_channels;i++) {
- compute_scale_factors(s, s->scale_code[i], s->scale_factors[i],
- s->sb_samples[i], s->sblimit);
- }
- for(i=0;i<s->nb_channels;i++) {
- psycho_acoustic_model(s, smr[i]);
- }
- compute_bit_allocation(s, smr, bit_alloc, &padding);
-
- if ((ret = ff_alloc_packet(avpkt, MPA_MAX_CODED_FRAME_SIZE))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
- return ret;
- }
-
- init_put_bits(&s->pb, avpkt->data, avpkt->size);
-
- encode_frame(s, bit_alloc, padding);
-
- if (frame->pts != AV_NOPTS_VALUE)
- avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding);
-
- avpkt->size = put_bits_count(&s->pb) / 8;
- *got_packet_ptr = 1;
- return 0;
-}
-
-static const AVCodecDefault mp2_defaults[] = {
- { "b", "384000" },
- { NULL },
-};
-
-AVCodec ff_mp2_encoder = {
- .name = "mp2",
- .long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
- .type = AVMEDIA_TYPE_AUDIO,
- .id = AV_CODEC_ID_MP2,
- .priv_data_size = sizeof(MpegAudioContext),
- .init = MPA_encode_init,
- .encode2 = MPA_encode_frame,
- .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
- AV_SAMPLE_FMT_NONE },
- .supported_samplerates = (const int[]){
- 44100, 48000, 32000, 22050, 24000, 16000, 0
- },
- .channel_layouts = (const uint64_t[]){ AV_CH_LAYOUT_MONO,
- AV_CH_LAYOUT_STEREO,
- 0 },
- .defaults = mp2_defaults,
-};
diff --git a/libavcodec/mpegaudioenc_fixed.c b/libavcodec/mpegaudioenc_fixed.c
new file mode 100644
index 0000000000..022b6fedd3
--- /dev/null
+++ b/libavcodec/mpegaudioenc_fixed.c
@@ -0,0 +1,41 @@
+/*
+ * The simplest mpeg audio layer 2 encoder
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "mpegaudioenc_template.c"
+
+AVCodec ff_mp2fixed_encoder = {
+ .name = "mp2fixed",
+ .long_name = NULL_IF_CONFIG_SMALL("MP2 fixed point (MPEG audio layer 2)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_MP2,
+ .priv_data_size = sizeof(MpegAudioContext),
+ .init = MPA_encode_init,
+ .encode2 = MPA_encode_frame,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .supported_samplerates = (const int[]){
+ 44100, 48000, 32000, 22050, 24000, 16000, 0
+ },
+ .channel_layouts = (const uint64_t[]){ AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ 0 },
+ .defaults = mp2_defaults,
+};
diff --git a/libavcodec/mpegaudioenc_float.c b/libavcodec/mpegaudioenc_float.c
new file mode 100644
index 0000000000..4d4ab2d7fa
--- /dev/null
+++ b/libavcodec/mpegaudioenc_float.c
@@ -0,0 +1,42 @@
+/*
+ * The simplest mpeg audio layer 2 encoder
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define USE_FLOATS 1
+#include "mpegaudioenc_template.c"
+
+AVCodec ff_mp2_encoder = {
+ .name = "mp2",
+ .long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_MP2,
+ .priv_data_size = sizeof(MpegAudioContext),
+ .init = MPA_encode_init,
+ .encode2 = MPA_encode_frame,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .supported_samplerates = (const int[]){
+ 44100, 48000, 32000, 22050, 24000, 16000, 0
+ },
+ .channel_layouts = (const uint64_t[]){ AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ 0 },
+ .defaults = mp2_defaults,
+};
diff --git a/libavcodec/mpegaudioenc_template.c b/libavcodec/mpegaudioenc_template.c
new file mode 100644
index 0000000000..5a0897f036
--- /dev/null
+++ b/libavcodec/mpegaudioenc_template.c
@@ -0,0 +1,785 @@
+/*
+ * The simplest mpeg audio layer 2 encoder
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * The simplest mpeg audio layer 2 encoder.
+ */
+
+#include "libavutil/channel_layout.h"
+
+#include "avcodec.h"
+#include "internal.h"
+#include "put_bits.h"
+
+#define FRAC_BITS 15 /* fractional bits for sb_samples and dct */
+#define WFRAC_BITS 14 /* fractional bits for window */
+
+#include "mpegaudio.h"
+#include "mpegaudiodsp.h"
+#include "mpegaudiodata.h"
+#include "mpegaudiotab.h"
+
+/* currently, cannot change these constants (need to modify
+ quantization stage) */
+#define MUL(a,b) (((int64_t)(a) * (int64_t)(b)) >> FRAC_BITS)
+
+#define SAMPLES_BUF_SIZE 4096
+
+typedef struct MpegAudioContext {
+ PutBitContext pb;
+ int nb_channels;
+ int lsf; /* 1 if mpeg2 low bitrate selected */
+ int bitrate_index; /* bit rate */
+ int freq_index;
+ int frame_size; /* frame size, in bits, without padding */
+ /* padding computation */
+ int frame_frac, frame_frac_incr, do_padding;
+ short samples_buf[MPA_MAX_CHANNELS][SAMPLES_BUF_SIZE]; /* buffer for filter */
+ int samples_offset[MPA_MAX_CHANNELS]; /* offset in samples_buf */
+ int sb_samples[MPA_MAX_CHANNELS][3][12][SBLIMIT];
+ unsigned char scale_factors[MPA_MAX_CHANNELS][SBLIMIT][3]; /* scale factors */
+ /* code to group 3 scale factors */
+ unsigned char scale_code[MPA_MAX_CHANNELS][SBLIMIT];
+ int sblimit; /* number of used subbands */
+ const unsigned char *alloc_table;
+ int16_t filter_bank[512];
+ int scale_factor_table[64];
+ unsigned char scale_diff_table[128];
+#if USE_FLOATS
+ float scale_factor_inv_table[64];
+#else
+ int8_t scale_factor_shift[64];
+ unsigned short scale_factor_mult[64];
+#endif
+ unsigned short total_quant_bits[17]; /* total number of bits per allocation group */
+} MpegAudioContext;
+
+static av_cold int MPA_encode_init(AVCodecContext *avctx)
+{
+ MpegAudioContext *s = avctx->priv_data;
+ int freq = avctx->sample_rate;
+ int bitrate = avctx->bit_rate;
+ int channels = avctx->channels;
+ int i, v, table;
+ float a;
+
+ if (channels <= 0 || channels > 2){
+ av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed in mp2\n", channels);
+ return AVERROR(EINVAL);
+ }
+ bitrate = bitrate / 1000;
+ s->nb_channels = channels;
+ avctx->frame_size = MPA_FRAME_SIZE;
+ avctx->initial_padding = 512 - 32 + 1;
+
+ /* encoding freq */
+ s->lsf = 0;
+ for(i=0;i<3;i++) {
+ if (avpriv_mpa_freq_tab[i] == freq)
+ break;
+ if ((avpriv_mpa_freq_tab[i] / 2) == freq) {
+ s->lsf = 1;
+ break;
+ }
+ }
+ if (i == 3){
+ av_log(avctx, AV_LOG_ERROR, "Sampling rate %d is not allowed in mp2\n", freq);
+ return AVERROR(EINVAL);
+ }
+ s->freq_index = i;
+
+ /* encoding bitrate & frequency */
+ for(i=1;i<15;i++) {
+ if (avpriv_mpa_bitrate_tab[s->lsf][1][i] == bitrate)
+ break;
+ }
+ if (i == 15 && !avctx->bit_rate) {
+ i = 14;
+ bitrate = avpriv_mpa_bitrate_tab[s->lsf][1][i];
+ avctx->bit_rate = bitrate * 1000;
+ }
+ if (i == 15){
+ av_log(avctx, AV_LOG_ERROR, "bitrate %d is not allowed in mp2\n", bitrate);
+ return AVERROR(EINVAL);
+ }
+ s->bitrate_index = i;
+
+ /* compute total header size & pad bit */
+
+ a = (float)(bitrate * 1000 * MPA_FRAME_SIZE) / (freq * 8.0);
+ s->frame_size = ((int)a) * 8;
+
+ /* frame fractional size to compute padding */
+ s->frame_frac = 0;
+ s->frame_frac_incr = (int)((a - floor(a)) * 65536.0);
+
+ /* select the right allocation table */
+ table = ff_mpa_l2_select_table(bitrate, s->nb_channels, freq, s->lsf);
+
+ /* number of used subbands */
+ s->sblimit = ff_mpa_sblimit_table[table];
+ s->alloc_table = ff_mpa_alloc_tables[table];
+
+ ff_dlog(avctx, "%d kb/s, %d Hz, frame_size=%d bits, table=%d, padincr=%x\n",
+ bitrate, freq, s->frame_size, table, s->frame_frac_incr);
+
+ for(i=0;i<s->nb_channels;i++)
+ s->samples_offset[i] = 0;
+
+ for(i=0;i<257;i++) {
+ int v;
+ v = ff_mpa_enwindow[i];
+#if WFRAC_BITS != 16
+ v = (v + (1 << (16 - WFRAC_BITS - 1))) >> (16 - WFRAC_BITS);
+#endif
+ s->filter_bank[i] = v;
+ if ((i & 63) != 0)
+ v = -v;
+ if (i != 0)
+ s->filter_bank[512 - i] = v;
+ }
+
+ for(i=0;i<64;i++) {
+ v = (int)(exp2((3 - i) / 3.0) * (1 << 20));
+ if (v <= 0)
+ v = 1;
+ s->scale_factor_table[i] = v;
+#if USE_FLOATS
+ s->scale_factor_inv_table[i] = exp2(-(3 - i) / 3.0) / (float)(1 << 20);
+#else
+#define P 15
+ s->scale_factor_shift[i] = 21 - P - (i / 3);
+ s->scale_factor_mult[i] = (1 << P) * exp2((i % 3) / 3.0);
+#endif
+ }
+ for(i=0;i<128;i++) {
+ v = i - 64;
+ if (v <= -3)
+ v = 0;
+ else if (v < 0)
+ v = 1;
+ else if (v == 0)
+ v = 2;
+ else if (v < 3)
+ v = 3;
+ else
+ v = 4;
+ s->scale_diff_table[i] = v;
+ }
+
+ for(i=0;i<17;i++) {
+ v = ff_mpa_quant_bits[i];
+ if (v < 0)
+ v = -v;
+ else
+ v = v * 3;
+ s->total_quant_bits[i] = 12 * v;
+ }
+
+ return 0;
+}
+
+/* 32 point floating point IDCT without 1/sqrt(2) coef zero scaling */
+static void idct32(int *out, int *tab)
+{
+ int i, j;
+ int *t, *t1, xr;
+ const int *xp = costab32;
+
+ for(j=31;j>=3;j-=2) tab[j] += tab[j - 2];
+
+ t = tab + 30;
+ t1 = tab + 2;
+ do {
+ t[0] += t[-4];
+ t[1] += t[1 - 4];
+ t -= 4;
+ } while (t != t1);
+
+ t = tab + 28;
+ t1 = tab + 4;
+ do {
+ t[0] += t[-8];
+ t[1] += t[1-8];
+ t[2] += t[2-8];
+ t[3] += t[3-8];
+ t -= 8;
+ } while (t != t1);
+
+ t = tab;
+ t1 = tab + 32;
+ do {
+ t[ 3] = -t[ 3];
+ t[ 6] = -t[ 6];
+
+ t[11] = -t[11];
+ t[12] = -t[12];
+ t[13] = -t[13];
+ t[15] = -t[15];
+ t += 16;
+ } while (t != t1);
+
+
+ t = tab;
+ t1 = tab + 8;
+ do {
+ int x1, x2, x3, x4;
+
+ x3 = MUL(t[16], FIX(SQRT2*0.5));
+ x4 = t[0] - x3;
+ x3 = t[0] + x3;
+
+ x2 = MUL(-(t[24] + t[8]), FIX(SQRT2*0.5));
+ x1 = MUL((t[8] - x2), xp[0]);
+ x2 = MUL((t[8] + x2), xp[1]);
+
+ t[ 0] = x3 + x1;
+ t[ 8] = x4 - x2;
+ t[16] = x4 + x2;
+ t[24] = x3 - x1;
+ t++;
+ } while (t != t1);
+
+ xp += 2;
+ t = tab;
+ t1 = tab + 4;
+ do {
+ xr = MUL(t[28],xp[0]);
+ t[28] = (t[0] - xr);
+ t[0] = (t[0] + xr);
+
+ xr = MUL(t[4],xp[1]);
+ t[ 4] = (t[24] - xr);
+ t[24] = (t[24] + xr);
+
+ xr = MUL(t[20],xp[2]);
+ t[20] = (t[8] - xr);
+ t[ 8] = (t[8] + xr);
+
+ xr = MUL(t[12],xp[3]);
+ t[12] = (t[16] - xr);
+ t[16] = (t[16] + xr);
+ t++;
+ } while (t != t1);
+ xp += 4;
+
+ for (i = 0; i < 4; i++) {
+ xr = MUL(tab[30-i*4],xp[0]);
+ tab[30-i*4] = (tab[i*4] - xr);
+ tab[ i*4] = (tab[i*4] + xr);
+
+ xr = MUL(tab[ 2+i*4],xp[1]);
+ tab[ 2+i*4] = (tab[28-i*4] - xr);
+ tab[28-i*4] = (tab[28-i*4] + xr);
+
+ xr = MUL(tab[31-i*4],xp[0]);
+ tab[31-i*4] = (tab[1+i*4] - xr);
+ tab[ 1+i*4] = (tab[1+i*4] + xr);
+
+ xr = MUL(tab[ 3+i*4],xp[1]);
+ tab[ 3+i*4] = (tab[29-i*4] - xr);
+ tab[29-i*4] = (tab[29-i*4] + xr);
+
+ xp += 2;
+ }
+
+ t = tab + 30;
+ t1 = tab + 1;
+ do {
+ xr = MUL(t1[0], *xp);
+ t1[0] = (t[0] - xr);
+ t[0] = (t[0] + xr);
+ t -= 2;
+ t1 += 2;
+ xp++;
+ } while (t >= tab);
+
+ for(i=0;i<32;i++) {
+ out[i] = tab[bitinv32[i]];
+ }
+}
+
+#define WSHIFT (WFRAC_BITS + 15 - FRAC_BITS)
+
+static void filter(MpegAudioContext *s, int ch, const short *samples, int incr)
+{
+ short *p, *q;
+ int sum, offset, i, j;
+ int tmp[64];
+ int tmp1[32];
+ int *out;
+
+ offset = s->samples_offset[ch];
+ out = &s->sb_samples[ch][0][0][0];
+ for(j=0;j<36;j++) {
+ /* 32 samples at once */
+ for(i=0;i<32;i++) {
+ s->samples_buf[ch][offset + (31 - i)] = samples[0];
+ samples += incr;
+ }
+
+ /* filter */
+ p = s->samples_buf[ch] + offset;
+ q = s->filter_bank;
+ /* maxsum = 23169 */
+ for(i=0;i<64;i++) {
+ sum = p[0*64] * q[0*64];
+ sum += p[1*64] * q[1*64];
+ sum += p[2*64] * q[2*64];
+ sum += p[3*64] * q[3*64];
+ sum += p[4*64] * q[4*64];
+ sum += p[5*64] * q[5*64];
+ sum += p[6*64] * q[6*64];
+ sum += p[7*64] * q[7*64];
+ tmp[i] = sum;
+ p++;
+ q++;
+ }
+ tmp1[0] = tmp[16] >> WSHIFT;
+ for( i=1; i<=16; i++ ) tmp1[i] = (tmp[i+16]+tmp[16-i]) >> WSHIFT;
+ for( i=17; i<=31; i++ ) tmp1[i] = (tmp[i+16]-tmp[80-i]) >> WSHIFT;
+
+ idct32(out, tmp1);
+
+ /* advance of 32 samples */
+ offset -= 32;
+ out += 32;
+ /* handle the wrap around */
+ if (offset < 0) {
+ memmove(s->samples_buf[ch] + SAMPLES_BUF_SIZE - (512 - 32),
+ s->samples_buf[ch], (512 - 32) * 2);
+ offset = SAMPLES_BUF_SIZE - 512;
+ }
+ }
+ s->samples_offset[ch] = offset;
+}
+
+static void compute_scale_factors(MpegAudioContext *s,
+ unsigned char scale_code[SBLIMIT],
+ unsigned char scale_factors[SBLIMIT][3],
+ int sb_samples[3][12][SBLIMIT],
+ int sblimit)
+{
+ int *p, vmax, v, n, i, j, k, code;
+ int index, d1, d2;
+ unsigned char *sf = &scale_factors[0][0];
+
+ for(j=0;j<sblimit;j++) {
+ for(i=0;i<3;i++) {
+ /* find the max absolute value */
+ p = &sb_samples[i][0][j];
+ vmax = abs(*p);
+ for(k=1;k<12;k++) {
+ p += SBLIMIT;
+ v = abs(*p);
+ if (v > vmax)
+ vmax = v;
+ }
+ /* compute the scale factor index using log 2 computations */
+ if (vmax > 1) {
+ n = av_log2(vmax);
+ /* n is the position of the MSB of vmax. now
+ use at most 2 compares to find the index */
+ index = (21 - n) * 3 - 3;
+ if (index >= 0) {
+ while (vmax <= s->scale_factor_table[index+1])
+ index++;
+ } else {
+ index = 0; /* very unlikely case of overflow */
+ }
+ } else {
+ index = 62; /* value 63 is not allowed */
+ }
+
+ ff_dlog(NULL, "%2d:%d in=%x %x %d\n",
+ j, i, vmax, s->scale_factor_table[index], index);
+ /* store the scale factor */
+ av_assert2(index >=0 && index <= 63);
+ sf[i] = index;
+ }
+
+ /* compute the transmission factor : look if the scale factors
+ are close enough to each other */
+ d1 = s->scale_diff_table[sf[0] - sf[1] + 64];
+ d2 = s->scale_diff_table[sf[1] - sf[2] + 64];
+
+ /* handle the 25 cases */
+ switch(d1 * 5 + d2) {
+ case 0*5+0:
+ case 0*5+4:
+ case 3*5+4:
+ case 4*5+0:
+ case 4*5+4:
+ code = 0;
+ break;
+ case 0*5+1:
+ case 0*5+2:
+ case 4*5+1:
+ case 4*5+2:
+ code = 3;
+ sf[2] = sf[1];
+ break;
+ case 0*5+3:
+ case 4*5+3:
+ code = 3;
+ sf[1] = sf[2];
+ break;
+ case 1*5+0:
+ case 1*5+4:
+ case 2*5+4:
+ code = 1;
+ sf[1] = sf[0];
+ break;
+ case 1*5+1:
+ case 1*5+2:
+ case 2*5+0:
+ case 2*5+1:
+ case 2*5+2:
+ code = 2;
+ sf[1] = sf[2] = sf[0];
+ break;
+ case 2*5+3:
+ case 3*5+3:
+ code = 2;
+ sf[0] = sf[1] = sf[2];
+ break;
+ case 3*5+0:
+ case 3*5+1:
+ case 3*5+2:
+ code = 2;
+ sf[0] = sf[2] = sf[1];
+ break;
+ case 1*5+3:
+ code = 2;
+ if (sf[0] > sf[2])
+ sf[0] = sf[2];
+ sf[1] = sf[2] = sf[0];
+ break;
+ default:
+ av_assert2(0); //cannot happen
+ code = 0; /* kill warning */
+ }
+
+ ff_dlog(NULL, "%d: %2d %2d %2d %d %d -> %d\n", j,
+ sf[0], sf[1], sf[2], d1, d2, code);
+ scale_code[j] = code;
+ sf += 3;
+ }
+}
+
+/* The most important function : psycho acoustic module. In this
+ encoder there is basically none, so this is the worst you can do,
+ but also this is the simpler. */
+static void psycho_acoustic_model(MpegAudioContext *s, short smr[SBLIMIT])
+{
+ int i;
+
+ for(i=0;i<s->sblimit;i++) {
+ smr[i] = (int)(fixed_smr[i] * 10);
+ }
+}
+
+
+#define SB_NOTALLOCATED 0
+#define SB_ALLOCATED 1
+#define SB_NOMORE 2
+
+/* Try to maximize the smr while using a number of bits inferior to
+ the frame size. I tried to make the code simpler, faster and
+ smaller than other encoders :-) */
+static void compute_bit_allocation(MpegAudioContext *s,
+ short smr1[MPA_MAX_CHANNELS][SBLIMIT],
+ unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
+ int *padding)
+{
+ int i, ch, b, max_smr, max_ch, max_sb, current_frame_size, max_frame_size;
+ int incr;
+ short smr[MPA_MAX_CHANNELS][SBLIMIT];
+ unsigned char subband_status[MPA_MAX_CHANNELS][SBLIMIT];
+ const unsigned char *alloc;
+
+ memcpy(smr, smr1, s->nb_channels * sizeof(short) * SBLIMIT);
+ memset(subband_status, SB_NOTALLOCATED, s->nb_channels * SBLIMIT);
+ memset(bit_alloc, 0, s->nb_channels * SBLIMIT);
+
+ /* compute frame size and padding */
+ max_frame_size = s->frame_size;
+ s->frame_frac += s->frame_frac_incr;
+ if (s->frame_frac >= 65536) {
+ s->frame_frac -= 65536;
+ s->do_padding = 1;
+ max_frame_size += 8;
+ } else {
+ s->do_padding = 0;
+ }
+
+ /* compute the header + bit alloc size */
+ current_frame_size = 32;
+ alloc = s->alloc_table;
+ for(i=0;i<s->sblimit;i++) {
+ incr = alloc[0];
+ current_frame_size += incr * s->nb_channels;
+ alloc += 1 << incr;
+ }
+ for(;;) {
+ /* look for the subband with the largest signal to mask ratio */
+ max_sb = -1;
+ max_ch = -1;
+ max_smr = INT_MIN;
+ for(ch=0;ch<s->nb_channels;ch++) {
+ for(i=0;i<s->sblimit;i++) {
+ if (smr[ch][i] > max_smr && subband_status[ch][i] != SB_NOMORE) {
+ max_smr = smr[ch][i];
+ max_sb = i;
+ max_ch = ch;
+ }
+ }
+ }
+ if (max_sb < 0)
+ break;
+ ff_dlog(NULL, "current=%d max=%d max_sb=%d max_ch=%d alloc=%d\n",
+ current_frame_size, max_frame_size, max_sb, max_ch,
+ bit_alloc[max_ch][max_sb]);
+
+ /* find alloc table entry (XXX: not optimal, should use
+ pointer table) */
+ alloc = s->alloc_table;
+ for(i=0;i<max_sb;i++) {
+ alloc += 1 << alloc[0];
+ }
+
+ if (subband_status[max_ch][max_sb] == SB_NOTALLOCATED) {
+ /* nothing was coded for this band: add the necessary bits */
+ incr = 2 + nb_scale_factors[s->scale_code[max_ch][max_sb]] * 6;
+ incr += s->total_quant_bits[alloc[1]];
+ } else {
+ /* increments bit allocation */
+ b = bit_alloc[max_ch][max_sb];
+ incr = s->total_quant_bits[alloc[b + 1]] -
+ s->total_quant_bits[alloc[b]];
+ }
+
+ if (current_frame_size + incr <= max_frame_size) {
+ /* can increase size */
+ b = ++bit_alloc[max_ch][max_sb];
+ current_frame_size += incr;
+ /* decrease smr by the resolution we added */
+ smr[max_ch][max_sb] = smr1[max_ch][max_sb] - quant_snr[alloc[b]];
+ /* max allocation size reached ? */
+ if (b == ((1 << alloc[0]) - 1))
+ subband_status[max_ch][max_sb] = SB_NOMORE;
+ else
+ subband_status[max_ch][max_sb] = SB_ALLOCATED;
+ } else {
+ /* cannot increase the size of this subband */
+ subband_status[max_ch][max_sb] = SB_NOMORE;
+ }
+ }
+ *padding = max_frame_size - current_frame_size;
+ av_assert0(*padding >= 0);
+}
+
+/*
+ * Output the mpeg audio layer 2 frame. Note how the code is small
+ * compared to other encoders :-)
+ */
+static void encode_frame(MpegAudioContext *s,
+ unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT],
+ int padding)
+{
+ int i, j, k, l, bit_alloc_bits, b, ch;
+ unsigned char *sf;
+ int q[3];
+ PutBitContext *p = &s->pb;
+
+ /* header */
+
+ put_bits(p, 12, 0xfff);
+ put_bits(p, 1, 1 - s->lsf); /* 1 = mpeg1 ID, 0 = mpeg2 lsf ID */
+ put_bits(p, 2, 4-2); /* layer 2 */
+ put_bits(p, 1, 1); /* no error protection */
+ put_bits(p, 4, s->bitrate_index);
+ put_bits(p, 2, s->freq_index);
+ put_bits(p, 1, s->do_padding); /* use padding */
+ put_bits(p, 1, 0); /* private_bit */
+ put_bits(p, 2, s->nb_channels == 2 ? MPA_STEREO : MPA_MONO);
+ put_bits(p, 2, 0); /* mode_ext */
+ put_bits(p, 1, 0); /* no copyright */
+ put_bits(p, 1, 1); /* original */
+ put_bits(p, 2, 0); /* no emphasis */
+
+ /* bit allocation */
+ j = 0;
+ for(i=0;i<s->sblimit;i++) {
+ bit_alloc_bits = s->alloc_table[j];
+ for(ch=0;ch<s->nb_channels;ch++) {
+ put_bits(p, bit_alloc_bits, bit_alloc[ch][i]);
+ }
+ j += 1 << bit_alloc_bits;
+ }
+
+ /* scale codes */
+ for(i=0;i<s->sblimit;i++) {
+ for(ch=0;ch<s->nb_channels;ch++) {
+ if (bit_alloc[ch][i])
+ put_bits(p, 2, s->scale_code[ch][i]);
+ }
+ }
+
+ /* scale factors */
+ for(i=0;i<s->sblimit;i++) {
+ for(ch=0;ch<s->nb_channels;ch++) {
+ if (bit_alloc[ch][i]) {
+ sf = &s->scale_factors[ch][i][0];
+ switch(s->scale_code[ch][i]) {
+ case 0:
+ put_bits(p, 6, sf[0]);
+ put_bits(p, 6, sf[1]);
+ put_bits(p, 6, sf[2]);
+ break;
+ case 3:
+ case 1:
+ put_bits(p, 6, sf[0]);
+ put_bits(p, 6, sf[2]);
+ break;
+ case 2:
+ put_bits(p, 6, sf[0]);
+ break;
+ }
+ }
+ }
+ }
+
+ /* quantization & write sub band samples */
+
+ for(k=0;k<3;k++) {
+ for(l=0;l<12;l+=3) {
+ j = 0;
+ for(i=0;i<s->sblimit;i++) {
+ bit_alloc_bits = s->alloc_table[j];
+ for(ch=0;ch<s->nb_channels;ch++) {
+ b = bit_alloc[ch][i];
+ if (b) {
+ int qindex, steps, m, sample, bits;
+ /* we encode 3 sub band samples of the same sub band at a time */
+ qindex = s->alloc_table[j+b];
+ steps = ff_mpa_quant_steps[qindex];
+ for(m=0;m<3;m++) {
+ sample = s->sb_samples[ch][k][l + m][i];
+ /* divide by scale factor */
+#if USE_FLOATS
+ {
+ float a;
+ a = (float)sample * s->scale_factor_inv_table[s->scale_factors[ch][i][k]];
+ q[m] = (int)((a + 1.0) * steps * 0.5);
+ }
+#else
+ {
+ int q1, e, shift, mult;
+ e = s->scale_factors[ch][i][k];
+ shift = s->scale_factor_shift[e];
+ mult = s->scale_factor_mult[e];
+
+ /* normalize to P bits */
+ if (shift < 0)
+ q1 = sample << (-shift);
+ else
+ q1 = sample >> shift;
+ q1 = (q1 * mult) >> P;
+ q1 += 1 << P;
+ if (q1 < 0)
+ q1 = 0;
+ q[m] = (q1 * (unsigned)steps) >> (P + 1);
+ }
+#endif
+ if (q[m] >= steps)
+ q[m] = steps - 1;
+ av_assert2(q[m] >= 0 && q[m] < steps);
+ }
+ bits = ff_mpa_quant_bits[qindex];
+ if (bits < 0) {
+ /* group the 3 values to save bits */
+ put_bits(p, -bits,
+ q[0] + steps * (q[1] + steps * q[2]));
+ } else {
+ put_bits(p, bits, q[0]);
+ put_bits(p, bits, q[1]);
+ put_bits(p, bits, q[2]);
+ }
+ }
+ }
+ /* next subband in alloc table */
+ j += 1 << bit_alloc_bits;
+ }
+ }
+ }
+
+ /* padding */
+ for(i=0;i<padding;i++)
+ put_bits(p, 1, 0);
+
+ /* flush */
+ flush_put_bits(p);
+}
+
+static int MPA_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ MpegAudioContext *s = avctx->priv_data;
+ const int16_t *samples = (const int16_t *)frame->data[0];
+ short smr[MPA_MAX_CHANNELS][SBLIMIT];
+ unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT];
+ int padding, i, ret;
+
+ for(i=0;i<s->nb_channels;i++) {
+ filter(s, i, samples + i, s->nb_channels);
+ }
+
+ for(i=0;i<s->nb_channels;i++) {
+ compute_scale_factors(s, s->scale_code[i], s->scale_factors[i],
+ s->sb_samples[i], s->sblimit);
+ }
+ for(i=0;i<s->nb_channels;i++) {
+ psycho_acoustic_model(s, smr[i]);
+ }
+ compute_bit_allocation(s, smr, bit_alloc, &padding);
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0)
+ return ret;
+
+ init_put_bits(&s->pb, avpkt->data, avpkt->size);
+
+ encode_frame(s, bit_alloc, padding);
+
+ if (frame->pts != AV_NOPTS_VALUE)
+ avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding);
+
+ avpkt->size = put_bits_count(&s->pb) / 8;
+ *got_packet_ptr = 1;
+ return 0;
+}
+
+static const AVCodecDefault mp2_defaults[] = {
+ { "b", "0" },
+ { NULL },
+};
+
diff --git a/libavcodec/mpegaudiotab.h b/libavcodec/mpegaudiotab.h
index d30ef1b752..42d42d883d 100644
--- a/libavcodec/mpegaudiotab.h
+++ b/libavcodec/mpegaudiotab.h
@@ -4,20 +4,20 @@
*
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegutils.c b/libavcodec/mpegutils.c
index bc430f0531..62cc36aa6e 100644
--- a/libavcodec/mpegutils.c
+++ b/libavcodec/mpegutils.c
@@ -1,20 +1,20 @@
/*
* Mpeg video formats-related defines and utility functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegutils.h b/libavcodec/mpegutils.h
index 9446724f30..6d59c22424 100644
--- a/libavcodec/mpegutils.h
+++ b/libavcodec/mpegutils.h
@@ -1,20 +1,20 @@
/*
* Mpeg video formats-related defines and utility functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c
index f81e357a52..6fbf500b5f 100644
--- a/libavcodec/mpegvideo.c
+++ b/libavcodec/mpegvideo.c
@@ -5,20 +5,20 @@
*
* 4MV & hq & B-frame encoding stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,9 +31,11 @@
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
+#include "libavutil/motion_vector.h"
#include "libavutil/timer.h"
#include "avcodec.h"
#include "blockdsp.h"
+#include "h264chroma.h"
#include "idctdsp.h"
#include "internal.h"
#include "mathops.h"
@@ -42,7 +44,6 @@
#include "mjpegenc.h"
#include "msmpeg4.h"
#include "qpeldsp.h"
-#include "xvmc_internal.h"
#include "thread.h"
#include <limits.h>
@@ -137,10 +138,7 @@ static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s,
nCoeffs= s->block_last_index[n];
- if (n < 4)
- block[0] = block[0] * s->y_dc_scale;
- else
- block[0] = block[0] * s->c_dc_scale;
+ block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale;
/* XXX: only mpeg1 */
quant_matrix = s->intra_matrix;
for(i=1;i<=nCoeffs;i++) {
@@ -199,10 +197,7 @@ static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s,
if(s->alternate_scan) nCoeffs= 63;
else nCoeffs= s->block_last_index[n];
- if (n < 4)
- block[0] = block[0] * s->y_dc_scale;
- else
- block[0] = block[0] * s->c_dc_scale;
+ block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale;
quant_matrix = s->intra_matrix;
for(i=1;i<=nCoeffs;i++) {
int j= s->intra_scantable.permutated[i];
@@ -230,10 +225,8 @@ static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s,
if(s->alternate_scan) nCoeffs= 63;
else nCoeffs= s->block_last_index[n];
- if (n < 4)
- block[0] = block[0] * s->y_dc_scale;
- else
- block[0] = block[0] * s->c_dc_scale;
+ block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale;
+ sum += block[0];
quant_matrix = s->intra_matrix;
for(i=1;i<=nCoeffs;i++) {
int j= s->intra_scantable.permutated[i];
@@ -290,15 +283,12 @@ static void dct_unquantize_h263_intra_c(MpegEncContext *s,
int i, level, qmul, qadd;
int nCoeffs;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0 || s->h263_aic);
qmul = qscale << 1;
if (!s->h263_aic) {
- if (n < 4)
- block[0] = block[0] * s->y_dc_scale;
- else
- block[0] = block[0] * s->c_dc_scale;
+ block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale;
qadd = (qscale - 1) | 1;
}else{
qadd = 0;
@@ -327,7 +317,7 @@ static void dct_unquantize_h263_inter_c(MpegEncContext *s,
int i, level, qmul, qadd;
int nCoeffs;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
qadd = (qscale - 1) | 1;
qmul = qscale << 1;
@@ -376,14 +366,40 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type,
ff_mpv_decode_mb(s, s->block);
}
+static void gray16(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h)
+{
+ while(h--)
+ memset(dst + h*linesize, 128, 16);
+}
+
+static void gray8(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h)
+{
+ while(h--)
+ memset(dst + h*linesize, 128, 8);
+}
+
/* init common dct for both encoder and decoder */
static av_cold int dct_init(MpegEncContext *s)
{
ff_blockdsp_init(&s->bdsp, s->avctx);
+ ff_h264chroma_init(&s->h264chroma, 8); //for lowres
ff_hpeldsp_init(&s->hdsp, s->avctx->flags);
ff_mpegvideodsp_init(&s->mdsp);
ff_videodsp_init(&s->vdsp, s->avctx->bits_per_raw_sample);
+ if (s->avctx->debug & FF_DEBUG_NOMC) {
+ int i;
+ for (i=0; i<4; i++) {
+ s->hdsp.avg_pixels_tab[0][i] = gray16;
+ s->hdsp.put_pixels_tab[0][i] = gray16;
+ s->hdsp.put_no_rnd_pixels_tab[0][i] = gray16;
+
+ s->hdsp.avg_pixels_tab[1][i] = gray8;
+ s->hdsp.put_pixels_tab[1][i] = gray8;
+ 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;
@@ -396,6 +412,8 @@ static av_cold int dct_init(MpegEncContext *s)
if (HAVE_INTRINSICS_NEON)
ff_mpv_common_init_neon(s);
+ if (ARCH_ALPHA)
+ ff_mpv_common_init_axp(s);
if (ARCH_ARM)
ff_mpv_common_init_arm(s);
if (ARCH_PPC)
@@ -426,17 +444,26 @@ av_cold void ff_mpv_idct_init(MpegEncContext *s)
static int frame_size_alloc(MpegEncContext *s, int linesize)
{
- int alloc_size = FFALIGN(FFABS(linesize) + 32, 32);
+ int alloc_size = FFALIGN(FFABS(linesize) + 64, 32);
+
+ if (s->avctx->hwaccel || s->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+ return 0;
+
+ if (linesize < 24) {
+ av_log(s->avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
+ return AVERROR_PATCHWELCOME;
+ }
// edge emu needs blocksize + filter length - 1
// (= 17x17 for halfpel / 21x21 for h264)
// VC1 computes luma and chroma simultaneously and needs 19X19 + 9x9
// at uvlinesize. It supports only YUV420 so 24x24 is enough
// linesize * interlaced * MBsize
- FF_ALLOCZ_OR_GOTO(s->avctx, s->edge_emu_buffer, alloc_size * 2 * 24,
+ // we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines
+ FF_ALLOCZ_ARRAY_OR_GOTO(s->avctx, s->edge_emu_buffer, alloc_size, 4 * 68,
fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->me.scratchpad, alloc_size * 2 * 16 * 3,
+ FF_ALLOCZ_ARRAY_OR_GOTO(s->avctx, s->me.scratchpad, alloc_size, 4 * 16 * 2,
fail)
s->me.temp = s->me.scratchpad;
s->rd_scratchpad = s->me.scratchpad;
@@ -535,6 +562,9 @@ void ff_free_picture_tables(Picture *pic)
{
int i;
+ pic->alloc_mb_width =
+ pic->alloc_mb_height = 0;
+
av_buffer_unref(&pic->mb_var_buf);
av_buffer_unref(&pic->mc_mb_var_buf);
av_buffer_unref(&pic->mb_mean_buf);
@@ -571,7 +601,8 @@ static int alloc_picture_tables(MpegEncContext *s, Picture *pic)
return AVERROR(ENOMEM);
}
- if (s->out_format == FMT_H263 || s->encoding) {
+ if (s->out_format == FMT_H263 || s->encoding || s->avctx->debug_mv ||
+ (s->avctx->flags2 & CODEC_FLAG2_EXPORT_MVS)) {
int mv_size = 2 * (b8_array_size + 4) * sizeof(int16_t);
int ref_index_size = 4 * mb_array_size;
@@ -583,6 +614,9 @@ static int alloc_picture_tables(MpegEncContext *s, Picture *pic)
}
}
+ pic->alloc_mb_width = s->mb_width;
+ pic->alloc_mb_height = s->mb_height;
+
return 0;
}
@@ -619,11 +653,16 @@ int ff_alloc_picture(MpegEncContext *s, Picture *pic, int shared)
{
int i, ret;
+ if (pic->qscale_table_buf)
+ if ( pic->alloc_mb_width != s->mb_width
+ || pic->alloc_mb_height != s->mb_height)
+ ff_free_picture_tables(pic);
+
if (shared) {
- assert(pic->f->data[0]);
+ av_assert0(pic->f->data[0]);
pic->shared = 1;
} else {
- assert(!pic->f->buf[0]);
+ av_assert0(!pic->f->buf[0]);
if (alloc_frame_buffer(s, pic) < 0)
return -1;
@@ -669,6 +708,8 @@ fail:
*/
void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *pic)
{
+ int off = offsetof(Picture, mb_mean) + sizeof(pic->mb_mean);
+
pic->tf.f = pic->f;
/* WM Image / Screen codecs allocate internal buffers with different
* dimensions / colorspaces; ignore user-defined callbacks for these. */
@@ -683,6 +724,8 @@ void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *pic)
if (pic->needs_realloc)
ff_free_picture_tables(pic);
+
+ memset((uint8_t*)pic + off, 0, sizeof(*pic) - off);
}
static int update_picture_tables(Picture *dst, Picture *src)
@@ -724,6 +767,9 @@ do {\
dst->ref_index[i] = src->ref_index[i];
}
+ dst->alloc_mb_width = src->alloc_mb_width;
+ dst->alloc_mb_height = src->alloc_mb_height;
+
return 0;
}
@@ -781,6 +827,9 @@ static int init_duplicate_context(MpegEncContext *s)
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;
+
s->edge_emu_buffer =
s->me.scratchpad =
s->me.temp =
@@ -899,9 +948,11 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
int i, ret;
MpegEncContext *s = dst->priv_data, *s1 = src->priv_data;
- if (dst == src || !s1->context_initialized)
+ if (dst == src)
return 0;
+ av_assert0(s != s1);
+
// FIXME can parameters change on I-frames?
// in that case dst may need a reinit
if (!s->context_initialized) {
@@ -912,18 +963,24 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
s->bitstream_buffer = NULL;
s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0;
- ff_mpv_idct_init(s);
- if ((err = ff_mpv_common_init(s)) < 0)
- return err;
+ if (s1->context_initialized){
+// s->picture_range_start += MAX_PICTURE_COUNT;
+// s->picture_range_end += MAX_PICTURE_COUNT;
+ ff_mpv_idct_init(s);
+ if((err = ff_mpv_common_init(s)) < 0){
+ memset(s, 0, sizeof(MpegEncContext));
+ s->avctx = dst;
+ return err;
+ }
+ }
}
if (s->height != s1->height || s->width != s1->width || s->context_reinit) {
- int err;
s->context_reinit = 0;
s->height = s1->height;
s->width = s1->width;
- if ((err = ff_mpv_common_frame_size_change(s)) < 0)
- return err;
+ if ((ret = ff_mpv_common_frame_size_change(s)) < 0)
+ return ret;
}
s->avctx->coded_height = s1->avctx->coded_height;
@@ -934,6 +991,8 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
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 (i = 0; i < MAX_PICTURE_COUNT; i++) {
ff_mpeg_unref_picture(s->avctx, &s->picture[i]);
if (s1->picture[i].f->buf[0] &&
@@ -944,7 +1003,7 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst,
#define UPDATE_PICTURE(pic)\
do {\
ff_mpeg_unref_picture(s->avctx, &s->pic);\
- if (s1->pic.f->buf[0])\
+ if (s1->pic.f && s1->pic.f->buf[0])\
ret = ff_mpeg_ref_picture(s->avctx, &s->pic, &s1->pic);\
else\
ret = update_picture_tables(&s->pic, &s1->pic);\
@@ -968,6 +1027,7 @@ do {\
// Error/bug resilience
s->next_p_frame_damaged = s1->next_p_frame_damaged;
s->workaround_bugs = s1->workaround_bugs;
+ s->padding_bug_score = s1->padding_bug_score;
// MPEG4 timing info
memcpy(&s->last_time_base, &s1->last_time_base,
@@ -1006,7 +1066,6 @@ do {\
} else {
av_log(s->avctx, AV_LOG_ERROR, "Context scratch buffers could not "
"be allocated due to unknown size.\n");
- return AVERROR_BUG;
}
// MPEG2/interlacing info
@@ -1056,6 +1115,18 @@ void ff_mpv_decode_defaults(MpegEncContext *s)
ff_mpv_common_defaults(s);
}
+void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx)
+{
+ s->avctx = avctx;
+ s->width = avctx->coded_width;
+ s->height = avctx->coded_height;
+ s->codec_id = avctx->codec->id;
+ s->workaround_bugs = avctx->workaround_bugs;
+
+ /* convert fourcc to upper case */
+ s->codec_tag = avpriv_toupper4(avctx->codec_tag);
+}
+
static int init_er(MpegEncContext *s)
{
ERContext *er = &s->er;
@@ -1105,7 +1176,7 @@ static int init_context_frame(MpegEncContext *s)
mb_array_size = s->mb_height * s->mb_stride;
mv_table_size = (s->mb_height + 2) * s->mb_stride + 1;
- /* set default edge pos, will be overriden
+ /* set default edge pos, will be overridden
* in decode_header if needed */
s->h_edge_pos = s->mb_width * 16;
s->v_edge_pos = s->mb_height * 16;
@@ -1123,44 +1194,35 @@ static int init_context_frame(MpegEncContext *s)
c_size = s->mb_stride * (s->mb_height + 1);
yc_size = y_size + 2 * c_size;
- FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_index2xy, (s->mb_num + 1) * sizeof(int),
- fail); // error ressilience code looks cleaner with this
+ if (s->mb_height & 1)
+ yc_size += 2*s->b8_stride + 2*s->mb_stride;
+
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_index2xy, (s->mb_num + 1) * sizeof(int), fail); // error ressilience code looks cleaner with this
for (y = 0; y < s->mb_height; y++)
for (x = 0; x < s->mb_width; x++)
s->mb_index2xy[x + y * s->mb_width] = x + y * s->mb_stride;
- s->mb_index2xy[s->mb_height * s->mb_width] =
- (s->mb_height - 1) * s->mb_stride + s->mb_width; // FIXME really needed?
+ s->mb_index2xy[s->mb_height * s->mb_width] = (s->mb_height - 1) * s->mb_stride + s->mb_width; // FIXME really needed?
if (s->encoding) {
/* Allocate MV tables */
- FF_ALLOCZ_OR_GOTO(s->avctx, s->p_mv_table_base,
- mv_table_size * 2 * sizeof(int16_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->b_forw_mv_table_base,
- mv_table_size * 2 * sizeof(int16_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->b_back_mv_table_base,
- mv_table_size * 2 * sizeof(int16_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_forw_mv_table_base,
- mv_table_size * 2 * sizeof(int16_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_back_mv_table_base,
- mv_table_size * 2 * sizeof(int16_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->b_direct_mv_table_base,
- mv_table_size * 2 * sizeof(int16_t), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->p_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->b_forw_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->b_back_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_forw_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_back_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->b_direct_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail)
s->p_mv_table = s->p_mv_table_base + s->mb_stride + 1;
s->b_forw_mv_table = s->b_forw_mv_table_base + s->mb_stride + 1;
s->b_back_mv_table = s->b_back_mv_table_base + s->mb_stride + 1;
- s->b_bidir_forw_mv_table = s->b_bidir_forw_mv_table_base +
- s->mb_stride + 1;
- s->b_bidir_back_mv_table = s->b_bidir_back_mv_table_base +
- s->mb_stride + 1;
+ s->b_bidir_forw_mv_table = s->b_bidir_forw_mv_table_base + s->mb_stride + 1;
+ s->b_bidir_back_mv_table = s->b_bidir_back_mv_table_base + s->mb_stride + 1;
s->b_direct_mv_table = s->b_direct_mv_table_base + s->mb_stride + 1;
/* Allocate MB type table */
- FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_type, mb_array_size *
- sizeof(uint16_t), fail); // needed for encoding
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_type, mb_array_size * sizeof(uint16_t), fail) // needed for encoding
- FF_ALLOCZ_OR_GOTO(s->avctx, s->lambda_table, mb_array_size *
- sizeof(int), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->lambda_table, mb_array_size * sizeof(int), fail)
FF_ALLOC_OR_GOTO(s->avctx, s->cplx_tab,
mb_array_size * sizeof(float), fail);
@@ -1183,34 +1245,27 @@ static int init_context_frame(MpegEncContext *s)
s->b_field_mv_table[i][j][k] = s->b_field_mv_table_base[i][j][k] +
s->mb_stride + 1;
}
- FF_ALLOCZ_OR_GOTO(s->avctx, s->b_field_select_table [i][j],
- mb_array_size * 2 * sizeof(uint8_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_mv_table_base[i][j],
- mv_table_size * 2 * sizeof(int16_t), fail);
- s->p_field_mv_table[i][j] = s->p_field_mv_table_base[i][j]
- + s->mb_stride + 1;
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->b_field_select_table [i][j], mb_array_size * 2 * sizeof(uint8_t), fail)
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_mv_table_base[i][j], mv_table_size * 2 * sizeof(int16_t), fail)
+ s->p_field_mv_table[i][j] = s->p_field_mv_table_base[i][j] + s->mb_stride + 1;
}
- FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_select_table[i],
- mb_array_size * 2 * sizeof(uint8_t), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_select_table[i], mb_array_size * 2 * sizeof(uint8_t), fail)
}
}
if (s->out_format == FMT_H263) {
/* cbp values */
- FF_ALLOCZ_OR_GOTO(s->avctx, s->coded_block_base, y_size, fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->coded_block_base, y_size + (s->mb_height&1)*2*s->b8_stride, fail);
s->coded_block = s->coded_block_base + s->b8_stride + 1;
/* cbp, ac_pred, pred_dir */
- FF_ALLOCZ_OR_GOTO(s->avctx, s->cbp_table,
- mb_array_size * sizeof(uint8_t), fail);
- FF_ALLOCZ_OR_GOTO(s->avctx, s->pred_dir_table,
- mb_array_size * sizeof(uint8_t), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->cbp_table , mb_array_size * sizeof(uint8_t), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->pred_dir_table, mb_array_size * sizeof(uint8_t), fail);
}
if (s->h263_pred || s->h263_plus || !s->encoding) {
/* dc values */
// MN: we need these for error resilience of intra-frames
- FF_ALLOCZ_OR_GOTO(s->avctx, s->dc_val_base,
- yc_size * sizeof(int16_t), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->dc_val_base, yc_size * sizeof(int16_t), fail);
s->dc_val[0] = s->dc_val_base + s->b8_stride + 1;
s->dc_val[1] = s->dc_val_base + y_size + s->mb_stride + 1;
s->dc_val[2] = s->dc_val[1] + c_size;
@@ -1274,12 +1329,10 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
dct_init(s);
/* set chroma shifts */
- av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt,
- &s->chroma_x_shift,
- &s->chroma_y_shift);
+ avcodec_get_chroma_sub_sample(s->avctx->pix_fmt,
+ &s->chroma_x_shift,
+ &s->chroma_y_shift);
- /* convert fourcc to upper case */
- s->codec_tag = avpriv_toupper4(s->avctx->codec_tag);
FF_ALLOCZ_OR_GOTO(s->avctx, s->picture,
MAX_PICTURE_COUNT * sizeof(Picture), fail);
@@ -1305,17 +1358,15 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
if (!s->new_picture.f)
goto fail;
- if (s->width && s->height) {
if (init_context_frame(s))
goto fail;
s->parse_context.state = -1;
- }
- s->context_initialized = 1;
- s->thread_context[0] = s;
+ s->context_initialized = 1;
+ s->thread_context[0] = s;
- if (s->width && s->height) {
+// if (s->width && s->height) {
if (nb_slices > 1) {
for (i = 1; i < nb_slices; i++) {
s->thread_context[i] = av_malloc(sizeof(MpegEncContext));
@@ -1337,7 +1388,7 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
s->end_mb_y = s->mb_height;
}
s->slice_context_count = nb_slices;
- }
+// }
return 0;
fail:
@@ -1392,6 +1443,7 @@ static void free_context_frame(MpegEncContext *s)
av_freep(&s->er.er_temp_buffer);
av_freep(&s->mb_index2xy);
av_freep(&s->lambda_table);
+
av_freep(&s->cplx_tab);
av_freep(&s->bits_tab);
@@ -1402,6 +1454,9 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
{
int i, err = 0;
+ if (!s->context_initialized)
+ return AVERROR(EINVAL);
+
if (s->slice_context_count > 1) {
for (i = 0; i < s->slice_context_count; i++) {
free_duplicate_context(s->thread_context[i]);
@@ -1455,7 +1510,8 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
(s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
}
} else {
- if (init_duplicate_context(s) < 0)
+ err = init_duplicate_context(s);
+ if (err < 0)
goto fail;
s->start_mb_y = 0;
s->end_mb_y = s->mb_height;
@@ -1572,9 +1628,13 @@ av_cold void ff_init_rl(RLTable *rl,
}
}
-av_cold void ff_init_vlc_rl(RLTable *rl)
+av_cold void ff_init_vlc_rl(RLTable *rl, unsigned static_size)
{
int i, q;
+ VLC_TYPE table[1500][2] = {{0}};
+ VLC vlc = { .table = table, .table_allocated = static_size };
+ av_assert0(static_size <= FF_ARRAY_ELEMS(table));
+ init_vlc(&vlc, 9, rl->n + 1, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC);
for (q = 0; q < 32; q++) {
int qmul = q * 2;
@@ -1584,9 +1644,9 @@ av_cold void ff_init_vlc_rl(RLTable *rl)
qmul = 1;
qadd = 0;
}
- for (i = 0; i < rl->vlc.table_size; i++) {
- int code = rl->vlc.table[i][0];
- int len = rl->vlc.table[i][1];
+ for (i = 0; i < vlc.table_size; i++) {
+ int code = vlc.table[i][0];
+ int len = vlc.table[i][1];
int level, run;
if (len == 0) { // illegal code
@@ -1632,7 +1692,7 @@ static inline int pic_is_unused(Picture *pic)
return 0;
}
-static int find_unused_picture(Picture *picture, int shared)
+static int find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared)
{
int i;
@@ -1648,12 +1708,26 @@ static int find_unused_picture(Picture *picture, int shared)
}
}
- return AVERROR_INVALIDDATA;
+ 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(picture, shared);
+ int ret = find_unused_picture(avctx, picture, shared);
if (ret >= 0 && ret < MAX_PICTURE_COUNT) {
if (picture[ret].needs_realloc) {
@@ -1665,6 +1739,22 @@ int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared)
return ret;
}
+static void gray_frame(AVFrame *frame)
+{
+ int i, h_chroma_shift, v_chroma_shift;
+
+ av_pix_fmt_get_chroma_sub_sample(frame->format, &h_chroma_shift, &v_chroma_shift);
+
+ for(i=0; i<frame->height; i++)
+ memset(frame->data[0] + frame->linesize[0]*i, 0x80, frame->width);
+ for(i=0; i<FF_CEIL_RSHIFT(frame->height, v_chroma_shift); i++) {
+ memset(frame->data[1] + frame->linesize[1]*i,
+ 0x80, FF_CEIL_RSHIFT(frame->width, h_chroma_shift));
+ memset(frame->data[2] + frame->linesize[2]*i,
+ 0x80, FF_CEIL_RSHIFT(frame->width, h_chroma_shift));
+ }
+}
+
/**
* generic function called after decoding
* the header and before a frame is decoded.
@@ -1675,6 +1765,11 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
Picture *pic;
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;
+ }
+
/* mark & release old frames */
if (s->pict_type != AV_PICTURE_TYPE_B && s->last_picture_ptr &&
s->last_picture_ptr != s->next_picture_ptr &&
@@ -1763,11 +1858,14 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
int h_chroma_shift, v_chroma_shift;
av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt,
&h_chroma_shift, &v_chroma_shift);
- if (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");
else if (s->picture_structure != PICT_FRAME)
- av_log(avctx, AV_LOG_INFO,
+ av_log(avctx, AV_LOG_DEBUG,
"allocate dummy last picture for field based first keyframe\n");
/* Allocate a dummy frame */
@@ -1779,21 +1877,32 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
s->last_picture_ptr = &s->picture[i];
s->last_picture_ptr->reference = 3;
- s->last_picture_ptr->f->pict_type = AV_PICTURE_TYPE_I;
+ s->last_picture_ptr->f->key_frame = 0;
+ s->last_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P;
if (ff_alloc_picture(s, s->last_picture_ptr, 0) < 0) {
s->last_picture_ptr = NULL;
return -1;
}
- memset(s->last_picture_ptr->f->data[0], 0,
- avctx->height * s->last_picture_ptr->f->linesize[0]);
- memset(s->last_picture_ptr->f->data[1], 0x80,
- (avctx->height >> v_chroma_shift) *
- s->last_picture_ptr->f->linesize[1]);
- memset(s->last_picture_ptr->f->data[2], 0x80,
- (avctx->height >> v_chroma_shift) *
- s->last_picture_ptr->f->linesize[2]);
+ if (!avctx->hwaccel && !(avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)) {
+ for(i=0; i<avctx->height; i++)
+ memset(s->last_picture_ptr->f->data[0] + s->last_picture_ptr->f->linesize[0]*i,
+ 0x80, avctx->width);
+ if (s->last_picture_ptr->f->data[2]) {
+ for(i=0; i<FF_CEIL_RSHIFT(avctx->height, v_chroma_shift); i++) {
+ memset(s->last_picture_ptr->f->data[1] + s->last_picture_ptr->f->linesize[1]*i,
+ 0x80, FF_CEIL_RSHIFT(avctx->width, h_chroma_shift));
+ memset(s->last_picture_ptr->f->data[2] + s->last_picture_ptr->f->linesize[2]*i,
+ 0x80, FF_CEIL_RSHIFT(avctx->width, h_chroma_shift));
+ }
+ }
+
+ if(s->codec_id == AV_CODEC_ID_FLV1 || s->codec_id == AV_CODEC_ID_H263){
+ for(i=0; i<avctx->height; i++)
+ memset(s->last_picture_ptr->f->data[0] + s->last_picture_ptr->f->linesize[0]*i, 16, avctx->width);
+ }
+ }
ff_thread_report_progress(&s->last_picture_ptr->tf, INT_MAX, 0);
ff_thread_report_progress(&s->last_picture_ptr->tf, INT_MAX, 1);
@@ -1809,7 +1918,8 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
s->next_picture_ptr = &s->picture[i];
s->next_picture_ptr->reference = 3;
- s->next_picture_ptr->f->pict_type = AV_PICTURE_TYPE_I;
+ s->next_picture_ptr->f->key_frame = 0;
+ s->next_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P;
if (ff_alloc_picture(s, s->next_picture_ptr, 0) < 0) {
s->next_picture_ptr = NULL;
@@ -1819,6 +1929,10 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
ff_thread_report_progress(&s->next_picture_ptr->tf, INT_MAX, 1);
}
+#if 0 // BUFREF-FIXME
+ memset(s->last_picture.f->data, 0, sizeof(s->last_picture.f->data));
+ memset(s->next_picture.f->data, 0, sizeof(s->next_picture.f->data));
+#endif
if (s->last_picture_ptr) {
ff_mpeg_unref_picture(s->avctx, &s->last_picture);
if (s->last_picture_ptr->f->buf[0] &&
@@ -1834,12 +1948,8 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
return ret;
}
- if (s->pict_type != AV_PICTURE_TYPE_I &&
- !(s->last_picture_ptr && s->last_picture_ptr->f->buf[0])) {
- av_log(s, AV_LOG_ERROR,
- "Non-reference picture received and no reference available\n");
- return AVERROR_INVALIDDATA;
- }
+ 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) {
int i;
@@ -1868,12 +1978,9 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx)
s->dct_unquantize_inter = s->dct_unquantize_mpeg1_inter;
}
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration)
- return ff_xvmc_field_start(s, avctx);
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
+ if (s->avctx->debug & FF_DEBUG_NOMC) {
+ gray_frame(s->current_picture_ptr->f);
+ }
return 0;
}
@@ -1881,119 +1988,935 @@ FF_ENABLE_DEPRECATION_WARNINGS
/* called after a frame has been decoded. */
void ff_mpv_frame_end(MpegEncContext *s)
{
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- /* redraw edges for the frame if decoding didn't complete */
- // just to make sure that all data is rendered.
- if (CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration) {
- ff_xvmc_field_end(s);
- } else
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
-
emms_c();
if (s->current_picture.reference)
ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0);
}
+
+#if FF_API_VISMV
+static int clip_line(int *sx, int *sy, int *ex, int *ey, int maxx)
+{
+ if(*sx > *ex)
+ return clip_line(ex, ey, sx, sy, maxx);
+
+ if (*sx < 0) {
+ if (*ex < 0)
+ return 1;
+ *sy = *ey + (*sy - *ey) * (int64_t)*ex / (*ex - *sx);
+ *sx = 0;
+ }
+
+ if (*ex > maxx) {
+ if (*sx > maxx)
+ return 1;
+ *ey = *sy + (*ey - *sy) * (int64_t)(maxx - *sx) / (*ex - *sx);
+ *ex = maxx;
+ }
+ return 0;
+}
+
+
+/**
+ * Draw a line from (ex, ey) -> (sx, sy).
+ * @param w width of the image
+ * @param h height of the image
+ * @param stride stride/linesize of the image
+ * @param color color of the arrow
+ */
+static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey,
+ int w, int h, int stride, int color)
+{
+ int x, y, fr, f;
+
+ if (clip_line(&sx, &sy, &ex, &ey, w - 1))
+ return;
+ if (clip_line(&sy, &sx, &ey, &ex, h - 1))
+ return;
+
+ sx = av_clip(sx, 0, w - 1);
+ sy = av_clip(sy, 0, h - 1);
+ ex = av_clip(ex, 0, w - 1);
+ ey = av_clip(ey, 0, h - 1);
+
+ buf[sy * stride + sx] += color;
+
+ if (FFABS(ex - sx) > FFABS(ey - sy)) {
+ if (sx > ex) {
+ FFSWAP(int, sx, ex);
+ FFSWAP(int, sy, ey);
+ }
+ buf += sx + sy * stride;
+ ex -= sx;
+ f = ((ey - sy) << 16) / ex;
+ for (x = 0; x <= ex; x++) {
+ y = (x * f) >> 16;
+ fr = (x * f) & 0xFFFF;
+ buf[y * stride + x] += (color * (0x10000 - fr)) >> 16;
+ if(fr) buf[(y + 1) * stride + x] += (color * fr ) >> 16;
+ }
+ } else {
+ if (sy > ey) {
+ FFSWAP(int, sx, ex);
+ FFSWAP(int, sy, ey);
+ }
+ buf += sx + sy * stride;
+ ey -= sy;
+ if (ey)
+ f = ((ex - sx) << 16) / ey;
+ else
+ f = 0;
+ for(y= 0; y <= ey; y++){
+ x = (y*f) >> 16;
+ fr = (y*f) & 0xFFFF;
+ buf[y * stride + x] += (color * (0x10000 - fr)) >> 16;
+ if(fr) buf[y * stride + x + 1] += (color * fr ) >> 16;
+ }
+ }
+}
+
+/**
+ * Draw an arrow from (ex, ey) -> (sx, sy).
+ * @param w width of the image
+ * @param h height of the image
+ * @param stride stride/linesize of the image
+ * @param color color of the arrow
+ */
+static void draw_arrow(uint8_t *buf, int sx, int sy, int ex,
+ int ey, int w, int h, int stride, int color, int tail, int direction)
+{
+ int dx,dy;
+
+ if (direction) {
+ FFSWAP(int, sx, ex);
+ FFSWAP(int, sy, ey);
+ }
+
+ sx = av_clip(sx, -100, w + 100);
+ sy = av_clip(sy, -100, h + 100);
+ ex = av_clip(ex, -100, w + 100);
+ ey = av_clip(ey, -100, h + 100);
+
+ dx = ex - sx;
+ dy = ey - sy;
+
+ if (dx * dx + dy * dy > 3 * 3) {
+ int rx = dx + dy;
+ int ry = -dx + dy;
+ int length = ff_sqrt((rx * rx + ry * ry) << 8);
+
+ // FIXME subpixel accuracy
+ rx = ROUNDED_DIV(rx * 3 << 4, length);
+ ry = ROUNDED_DIV(ry * 3 << 4, length);
+
+ if (tail) {
+ rx = -rx;
+ ry = -ry;
+ }
+
+ draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, stride, color);
+ draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, stride, color);
+ }
+ draw_line(buf, sx, sy, ex, ey, w, h, stride, color);
+}
+#endif
+
+static int add_mb(AVMotionVector *mb, uint32_t mb_type,
+ int dst_x, int dst_y,
+ int src_x, int src_y,
+ int direction)
+{
+ mb->w = IS_8X8(mb_type) || IS_8X16(mb_type) ? 8 : 16;
+ mb->h = IS_8X8(mb_type) || IS_16X8(mb_type) ? 8 : 16;
+ mb->src_x = src_x;
+ mb->src_y = src_y;
+ mb->dst_x = dst_x;
+ mb->dst_y = dst_y;
+ mb->source = direction ? 1 : -1;
+ mb->flags = 0; // XXX: does mb_type contain extra information that could be exported here?
+ return 1;
+}
+
/**
* Print debugging info for the given picture.
*/
-void ff_print_debug_info(MpegEncContext *s, Picture *p)
+void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table,
+ uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2],
+ int *low_delay,
+ int mb_width, int mb_height, int mb_stride, int quarter_sample)
{
- AVFrame *pict;
- if (s->avctx->hwaccel || !p || !p->mb_type)
+ if ((avctx->flags2 & CODEC_FLAG2_EXPORT_MVS) && mbtype_table && motion_val[0]) {
+ const int shift = 1 + quarter_sample;
+ 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);
+ int mb_x, mb_y, mbcount = 0;
+
+ /* size is width * height * 2 * 4 where 2 is for directions and 4 is
+ * for the maximum number of MB (4 MB in case of IS_8x8) */
+ AVMotionVector *mvs = av_malloc_array(mb_width * mb_height, 2 * 4 * sizeof(AVMotionVector));
+ if (!mvs)
+ return;
+
+ for (mb_y = 0; mb_y < mb_height; mb_y++) {
+ 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))
+ continue;
+ if (IS_8X8(mb_type)) {
+ for (i = 0; i < 4; i++) {
+ int sx = mb_x * 16 + 4 + 8 * (i & 1);
+ int sy = mb_y * 16 + 4 + 8 * (i >> 1);
+ int xy = (mb_x * 2 + (i & 1) +
+ (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1);
+ int mx = (motion_val[direction][xy][0] >> shift) + sx;
+ int my = (motion_val[direction][xy][1] >> shift) + sy;
+ mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, direction);
+ }
+ } else if (IS_16X8(mb_type)) {
+ for (i = 0; i < 2; i++) {
+ int sx = mb_x * 16 + 8;
+ int sy = mb_y * 16 + 4 + 8 * i;
+ int xy = (mb_x * 2 + (mb_y * 2 + i) * mv_stride) << (mv_sample_log2 - 1);
+ int mx = (motion_val[direction][xy][0] >> shift);
+ int my = (motion_val[direction][xy][1] >> shift);
+
+ if (IS_INTERLACED(mb_type))
+ my *= 2;
+
+ mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx + sx, my + sy, direction);
+ }
+ } else if (IS_8X16(mb_type)) {
+ for (i = 0; i < 2; i++) {
+ int sx = mb_x * 16 + 4 + 8 * i;
+ int sy = mb_y * 16 + 8;
+ int xy = (mb_x * 2 + i + mb_y * 2 * mv_stride) << (mv_sample_log2 - 1);
+ int mx = motion_val[direction][xy][0] >> shift;
+ int my = motion_val[direction][xy][1] >> shift;
+
+ if (IS_INTERLACED(mb_type))
+ my *= 2;
+
+ mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx + sx, my + sy, direction);
+ }
+ } else {
+ int sx = mb_x * 16 + 8;
+ int sy = mb_y * 16 + 8;
+ int xy = (mb_x + mb_y * mv_stride) << mv_sample_log2;
+ int mx = (motion_val[direction][xy][0]>>shift) + sx;
+ int my = (motion_val[direction][xy][1]>>shift) + sy;
+ mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, direction);
+ }
+ }
+ }
+ }
+
+ if (mbcount) {
+ AVFrameSideData *sd;
+
+ av_log(avctx, AV_LOG_DEBUG, "Adding %d MVs info to frame %d\n", mbcount, avctx->frame_number);
+ sd = av_frame_new_side_data(pict, AV_FRAME_DATA_MOTION_VECTORS, mbcount * sizeof(AVMotionVector));
+ if (!sd) {
+ av_freep(&mvs);
+ return;
+ }
+ memcpy(sd->data, mvs, mbcount * sizeof(AVMotionVector));
+ }
+
+ av_freep(&mvs);
+ }
+
+ /* TODO: export all the following to make them accessible for users (and filters) */
+ if (avctx->hwaccel || !mbtype_table
+ || (avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU))
return;
- pict = p->f;
- if (s->avctx->debug & (FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) {
+
+ if (avctx->debug & (FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) {
int x,y;
- av_log(s->avctx,AV_LOG_DEBUG,"New frame, type: ");
- switch (pict->pict_type) {
- case AV_PICTURE_TYPE_I:
- av_log(s->avctx,AV_LOG_DEBUG,"I\n");
- break;
- case AV_PICTURE_TYPE_P:
- av_log(s->avctx,AV_LOG_DEBUG,"P\n");
- break;
- case AV_PICTURE_TYPE_B:
- av_log(s->avctx,AV_LOG_DEBUG,"B\n");
- break;
- case AV_PICTURE_TYPE_S:
- av_log(s->avctx,AV_LOG_DEBUG,"S\n");
- break;
- case AV_PICTURE_TYPE_SI:
- av_log(s->avctx,AV_LOG_DEBUG,"SI\n");
- break;
- case AV_PICTURE_TYPE_SP:
- av_log(s->avctx,AV_LOG_DEBUG,"SP\n");
- break;
- }
- for (y = 0; y < s->mb_height; y++) {
- for (x = 0; x < s->mb_width; x++) {
- if (s->avctx->debug & FF_DEBUG_SKIP) {
- int count = s->mbskip_table[x + y * s->mb_stride];
+ av_log(avctx, AV_LOG_DEBUG, "New frame, type: %c\n",
+ av_get_picture_type_char(pict->pict_type));
+ for (y = 0; y < mb_height; y++) {
+ for (x = 0; x < mb_width; x++) {
+ if (avctx->debug & FF_DEBUG_SKIP) {
+ int count = mbskip_table ? mbskip_table[x + y * mb_stride] : 0;
if (count > 9)
count = 9;
- av_log(s->avctx, AV_LOG_DEBUG, "%1d", count);
+ av_log(avctx, AV_LOG_DEBUG, "%1d", count);
}
- if (s->avctx->debug & FF_DEBUG_QP) {
- av_log(s->avctx, AV_LOG_DEBUG, "%2d",
- p->qscale_table[x + y * s->mb_stride]);
+ if (avctx->debug & FF_DEBUG_QP) {
+ av_log(avctx, AV_LOG_DEBUG, "%2d",
+ qscale_table[x + y * mb_stride]);
}
- if (s->avctx->debug & FF_DEBUG_MB_TYPE) {
- int mb_type = p->mb_type[x + y * s->mb_stride];
+ if (avctx->debug & FF_DEBUG_MB_TYPE) {
+ int mb_type = mbtype_table[x + y * mb_stride];
// Type & MV direction
if (IS_PCM(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "P");
+ av_log(avctx, AV_LOG_DEBUG, "P");
else if (IS_INTRA(mb_type) && IS_ACPRED(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "A");
+ av_log(avctx, AV_LOG_DEBUG, "A");
else if (IS_INTRA4x4(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "i");
+ av_log(avctx, AV_LOG_DEBUG, "i");
else if (IS_INTRA16x16(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "I");
+ av_log(avctx, AV_LOG_DEBUG, "I");
else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "d");
+ av_log(avctx, AV_LOG_DEBUG, "d");
else if (IS_DIRECT(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "D");
+ av_log(avctx, AV_LOG_DEBUG, "D");
else if (IS_GMC(mb_type) && IS_SKIP(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "g");
+ av_log(avctx, AV_LOG_DEBUG, "g");
else if (IS_GMC(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "G");
+ av_log(avctx, AV_LOG_DEBUG, "G");
else if (IS_SKIP(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "S");
+ av_log(avctx, AV_LOG_DEBUG, "S");
else if (!USES_LIST(mb_type, 1))
- av_log(s->avctx, AV_LOG_DEBUG, ">");
+ av_log(avctx, AV_LOG_DEBUG, ">");
else if (!USES_LIST(mb_type, 0))
- av_log(s->avctx, AV_LOG_DEBUG, "<");
+ av_log(avctx, AV_LOG_DEBUG, "<");
else {
- assert(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1));
- av_log(s->avctx, AV_LOG_DEBUG, "X");
+ av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1));
+ av_log(avctx, AV_LOG_DEBUG, "X");
}
// segmentation
if (IS_8X8(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "+");
+ av_log(avctx, AV_LOG_DEBUG, "+");
else if (IS_16X8(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "-");
+ av_log(avctx, AV_LOG_DEBUG, "-");
else if (IS_8X16(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "|");
+ av_log(avctx, AV_LOG_DEBUG, "|");
else if (IS_INTRA(mb_type) || IS_16X16(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, " ");
+ av_log(avctx, AV_LOG_DEBUG, " ");
else
- av_log(s->avctx, AV_LOG_DEBUG, "?");
+ av_log(avctx, AV_LOG_DEBUG, "?");
if (IS_INTERLACED(mb_type))
- av_log(s->avctx, AV_LOG_DEBUG, "=");
+ av_log(avctx, AV_LOG_DEBUG, "=");
else
- av_log(s->avctx, AV_LOG_DEBUG, " ");
+ av_log(avctx, AV_LOG_DEBUG, " ");
+ }
+ }
+ av_log(avctx, AV_LOG_DEBUG, "\n");
+ }
+ }
+
+ if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) ||
+ (avctx->debug_mv)) {
+ int mb_y;
+ int i;
+ int h_chroma_shift, v_chroma_shift, block_height;
+#if FF_API_VISMV
+ const int shift = 1 + quarter_sample;
+ uint8_t *ptr;
+ const int width = avctx->width;
+ const int height = avctx->height;
+#endif
+ 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);
+
+ *low_delay = 0; // needed to see the vectors without trashing the buffers
+
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift);
+
+ av_frame_make_writable(pict);
+
+ pict->opaque = NULL;
+#if FF_API_VISMV
+ ptr = pict->data[0];
+#endif
+ block_height = 16 >> v_chroma_shift;
+
+ for (mb_y = 0; mb_y < mb_height; mb_y++) {
+ int mb_x;
+ for (mb_x = 0; mb_x < mb_width; mb_x++) {
+ const int mb_index = mb_x + mb_y * mb_stride;
+#if FF_API_VISMV
+ if ((avctx->debug_mv) && motion_val[0]) {
+ int type;
+ for (type = 0; type < 3; type++) {
+ int direction = 0;
+ switch (type) {
+ case 0:
+ if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_P_FOR)) ||
+ (pict->pict_type!= AV_PICTURE_TYPE_P))
+ continue;
+ direction = 0;
+ break;
+ case 1:
+ if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_B_FOR)) ||
+ (pict->pict_type!= AV_PICTURE_TYPE_B))
+ continue;
+ direction = 0;
+ break;
+ case 2:
+ if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_B_BACK)) ||
+ (pict->pict_type!= AV_PICTURE_TYPE_B))
+ continue;
+ direction = 1;
+ break;
+ }
+ if (!USES_LIST(mbtype_table[mb_index], direction))
+ continue;
+
+ if (IS_8X8(mbtype_table[mb_index])) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ int sx = mb_x * 16 + 4 + 8 * (i & 1);
+ int sy = mb_y * 16 + 4 + 8 * (i >> 1);
+ int xy = (mb_x * 2 + (i & 1) +
+ (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1);
+ int mx = (motion_val[direction][xy][0] >> shift) + sx;
+ int my = (motion_val[direction][xy][1] >> shift) + sy;
+ draw_arrow(ptr, sx, sy, mx, my, width,
+ height, pict->linesize[0], 100, 0, direction);
+ }
+ } else if (IS_16X8(mbtype_table[mb_index])) {
+ int i;
+ for (i = 0; i < 2; i++) {
+ int sx = mb_x * 16 + 8;
+ int sy = mb_y * 16 + 4 + 8 * i;
+ int xy = (mb_x * 2 + (mb_y * 2 + i) * mv_stride) << (mv_sample_log2 - 1);
+ int mx = (motion_val[direction][xy][0] >> shift);
+ int my = (motion_val[direction][xy][1] >> shift);
+
+ if (IS_INTERLACED(mbtype_table[mb_index]))
+ my *= 2;
+
+ draw_arrow(ptr, sx, sy, mx + sx, my + sy, width,
+ height, pict->linesize[0], 100, 0, direction);
+ }
+ } else if (IS_8X16(mbtype_table[mb_index])) {
+ int i;
+ for (i = 0; i < 2; i++) {
+ int sx = mb_x * 16 + 4 + 8 * i;
+ int sy = mb_y * 16 + 8;
+ int xy = (mb_x * 2 + i + mb_y * 2 * mv_stride) << (mv_sample_log2 - 1);
+ int mx = motion_val[direction][xy][0] >> shift;
+ int my = motion_val[direction][xy][1] >> shift;
+
+ if (IS_INTERLACED(mbtype_table[mb_index]))
+ my *= 2;
+
+ draw_arrow(ptr, sx, sy, mx + sx, my + sy, width,
+ height, pict->linesize[0], 100, 0, direction);
+ }
+ } else {
+ int sx= mb_x * 16 + 8;
+ int sy= mb_y * 16 + 8;
+ int xy= (mb_x + mb_y * mv_stride) << mv_sample_log2;
+ int mx= (motion_val[direction][xy][0]>>shift) + sx;
+ int my= (motion_val[direction][xy][1]>>shift) + sy;
+ draw_arrow(ptr, sx, sy, mx, my, width, height, pict->linesize[0], 100, 0, direction);
+ }
+ }
+ }
+#endif
+ if ((avctx->debug & FF_DEBUG_VIS_QP)) {
+ uint64_t c = (qscale_table[mb_index] * 128 / 31) *
+ 0x0101010101010101ULL;
+ int y;
+ for (y = 0; y < block_height; y++) {
+ *(uint64_t *)(pict->data[1] + 8 * mb_x +
+ (block_height * mb_y + y) *
+ pict->linesize[1]) = c;
+ *(uint64_t *)(pict->data[2] + 8 * mb_x +
+ (block_height * mb_y + y) *
+ pict->linesize[2]) = c;
+ }
+ }
+ if ((avctx->debug & FF_DEBUG_VIS_MB_TYPE) &&
+ motion_val[0]) {
+ int mb_type = mbtype_table[mb_index];
+ uint64_t u,v;
+ int y;
+#define COLOR(theta, r) \
+ u = (int)(128 + r * cos(theta * 3.141592 / 180)); \
+ v = (int)(128 + r * sin(theta * 3.141592 / 180));
+
+
+ u = v = 128;
+ if (IS_PCM(mb_type)) {
+ COLOR(120, 48)
+ } else if ((IS_INTRA(mb_type) && IS_ACPRED(mb_type)) ||
+ IS_INTRA16x16(mb_type)) {
+ COLOR(30, 48)
+ } else if (IS_INTRA4x4(mb_type)) {
+ COLOR(90, 48)
+ } else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) {
+ // COLOR(120, 48)
+ } else if (IS_DIRECT(mb_type)) {
+ COLOR(150, 48)
+ } else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) {
+ COLOR(170, 48)
+ } else if (IS_GMC(mb_type)) {
+ COLOR(190, 48)
+ } else if (IS_SKIP(mb_type)) {
+ // COLOR(180, 48)
+ } else if (!USES_LIST(mb_type, 1)) {
+ COLOR(240, 48)
+ } else if (!USES_LIST(mb_type, 0)) {
+ COLOR(0, 48)
+ } else {
+ av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1));
+ COLOR(300,48)
+ }
+
+ u *= 0x0101010101010101ULL;
+ v *= 0x0101010101010101ULL;
+ for (y = 0; y < block_height; y++) {
+ *(uint64_t *)(pict->data[1] + 8 * mb_x +
+ (block_height * mb_y + y) * pict->linesize[1]) = u;
+ *(uint64_t *)(pict->data[2] + 8 * mb_x +
+ (block_height * mb_y + y) * pict->linesize[2]) = v;
+ }
+
+ // segmentation
+ if (IS_8X8(mb_type) || IS_16X8(mb_type)) {
+ *(uint64_t *)(pict->data[0] + 16 * mb_x + 0 +
+ (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL;
+ *(uint64_t *)(pict->data[0] + 16 * mb_x + 8 +
+ (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL;
+ }
+ if (IS_8X8(mb_type) || IS_8X16(mb_type)) {
+ for (y = 0; y < 16; y++)
+ pict->data[0][16 * mb_x + 8 + (16 * mb_y + y) *
+ pict->linesize[0]] ^= 0x80;
+ }
+ if (IS_8X8(mb_type) && mv_sample_log2 >= 2) {
+ int dm = 1 << (mv_sample_log2 - 2);
+ for (i = 0; i < 4; i++) {
+ int sx = mb_x * 16 + 8 * (i & 1);
+ int sy = mb_y * 16 + 8 * (i >> 1);
+ int xy = (mb_x * 2 + (i & 1) +
+ (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1);
+ // FIXME bidir
+ int32_t *mv = (int32_t *) &motion_val[0][xy];
+ if (mv[0] != mv[dm] ||
+ mv[dm * mv_stride] != mv[dm * (mv_stride + 1)])
+ for (y = 0; y < 8; y++)
+ pict->data[0][sx + 4 + (sy + y) * pict->linesize[0]] ^= 0x80;
+ if (mv[0] != mv[dm * mv_stride] || mv[dm] != mv[dm * (mv_stride + 1)])
+ *(uint64_t *)(pict->data[0] + sx + (sy + 4) *
+ pict->linesize[0]) ^= 0x8080808080808080ULL;
+ }
+ }
+
+ if (IS_INTERLACED(mb_type) &&
+ avctx->codec->id == AV_CODEC_ID_H264) {
+ // hmm
+ }
+ }
+ if (mbskip_table)
+ mbskip_table[mb_index] = 0;
+ }
+ }
+ }
+}
+
+void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict)
+{
+ ff_print_debug_info2(s->avctx, pict, s->mbskip_table, p->mb_type,
+ p->qscale_table, p->motion_val, &s->low_delay,
+ s->mb_width, s->mb_height, s->mb_stride, s->quarter_sample);
+}
+
+int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type)
+{
+ AVBufferRef *ref = av_buffer_ref(p->qscale_table_buf);
+ int offset = 2*s->mb_stride + 1;
+ if(!ref)
+ return AVERROR(ENOMEM);
+ av_assert0(ref->size >= offset + s->mb_stride * ((f->height+15)/16));
+ ref->size -= offset;
+ ref->data += offset;
+ return av_frame_set_qp_table(f, ref, s->mb_stride, qp_type);
+}
+
+static inline int hpel_motion_lowres(MpegEncContext *s,
+ uint8_t *dest, uint8_t *src,
+ int field_based, int field_select,
+ int src_x, int src_y,
+ int width, int height, ptrdiff_t stride,
+ int h_edge_pos, int v_edge_pos,
+ int w, int h, h264_chroma_mc_func *pix_op,
+ int motion_x, int motion_y)
+{
+ const int lowres = s->avctx->lowres;
+ const int op_index = FFMIN(lowres, 3);
+ const int s_mask = (2 << lowres) - 1;
+ int emu = 0;
+ int sx, sy;
+
+ if (s->quarter_sample) {
+ motion_x /= 2;
+ motion_y /= 2;
+ }
+
+ sx = motion_x & s_mask;
+ sy = motion_y & s_mask;
+ src_x += motion_x >> lowres + 1;
+ src_y += motion_y >> lowres + 1;
+
+ src += src_y * stride + src_x;
+
+ if ((unsigned)src_x > FFMAX( h_edge_pos - (!!sx) - w, 0) ||
+ (unsigned)src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, src,
+ s->linesize, s->linesize,
+ w + 1, (h + 1) << field_based,
+ src_x, src_y << field_based,
+ h_edge_pos, v_edge_pos);
+ src = s->edge_emu_buffer;
+ emu = 1;
+ }
+
+ sx = (sx << 2) >> lowres;
+ sy = (sy << 2) >> lowres;
+ if (field_select)
+ src += s->linesize;
+ pix_op[op_index](dest, src, stride, h, sx, sy);
+ return emu;
+}
+
+/* apply one mpeg motion vector to the three components */
+static av_always_inline void mpeg_motion_lowres(MpegEncContext *s,
+ uint8_t *dest_y,
+ uint8_t *dest_cb,
+ uint8_t *dest_cr,
+ int field_based,
+ int bottom_field,
+ int field_select,
+ uint8_t **ref_picture,
+ h264_chroma_mc_func *pix_op,
+ int motion_x, int motion_y,
+ int h, int mb_y)
+{
+ uint8_t *ptr_y, *ptr_cb, *ptr_cr;
+ 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 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;
+ linesize = s->current_picture.f->linesize[0] << field_based;
+ uvlinesize = s->current_picture.f->linesize[1] << field_based;
+
+ // FIXME obviously not perfect but qpel will not work in lowres anyway
+ if (s->quarter_sample) {
+ motion_x /= 2;
+ motion_y /= 2;
+ }
+
+ if(field_based){
+ motion_y += (bottom_field - field_select)*((1 << lowres)-1);
+ }
+
+ sx = motion_x & s_mask;
+ sy = motion_y & s_mask;
+ src_x = s->mb_x * 2 * block_s + (motion_x >> lowres + 1);
+ src_y = (mb_y * 2 * block_s >> field_based) + (motion_y >> lowres + 1);
+
+ if (s->out_format == FMT_H263) {
+ uvsx = ((motion_x >> 1) & s_mask) | (sx & 1);
+ uvsy = ((motion_y >> 1) & s_mask) | (sy & 1);
+ uvsrc_x = src_x >> 1;
+ uvsrc_y = src_y >> 1;
+ } else if (s->out_format == FMT_H261) {
+ // even chroma mv's are full pel in H261
+ mx = motion_x / 4;
+ my = motion_y / 4;
+ uvsx = (2 * mx) & s_mask;
+ uvsy = (2 * my) & s_mask;
+ uvsrc_x = s->mb_x * block_s + (mx >> lowres);
+ uvsrc_y = mb_y * block_s + (my >> lowres);
+ } else {
+ if(s->chroma_y_shift){
+ mx = motion_x / 2;
+ my = motion_y / 2;
+ uvsx = mx & s_mask;
+ uvsy = my & s_mask;
+ uvsrc_x = s->mb_x * block_s + (mx >> lowres + 1);
+ uvsrc_y = (mb_y * block_s >> field_based) + (my >> lowres + 1);
+ } else {
+ if(s->chroma_x_shift){
+ //Chroma422
+ mx = motion_x / 2;
+ uvsx = mx & s_mask;
+ uvsy = motion_y & s_mask;
+ uvsrc_y = src_y;
+ uvsrc_x = s->mb_x*block_s + (mx >> (lowres+1));
+ } else {
+ //Chroma444
+ uvsx = motion_x & s_mask;
+ uvsy = motion_y & s_mask;
+ uvsrc_x = src_x;
+ uvsrc_y = src_y;
+ }
+ }
+ }
+
+ ptr_y = ref_picture[0] + src_y * linesize + src_x;
+ ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;
+ ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;
+
+ if ((unsigned) src_x > FFMAX( h_edge_pos - (!!sx) - 2 * block_s, 0) || uvsrc_y<0 ||
+ (unsigned) src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
+ linesize >> field_based, linesize >> field_based,
+ 17, 17 + field_based,
+ src_x, src_y << field_based, h_edge_pos,
+ v_edge_pos);
+ ptr_y = s->edge_emu_buffer;
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ uint8_t *ubuf = s->edge_emu_buffer + 18 * s->linesize;
+ uint8_t *vbuf =ubuf + 9 * s->uvlinesize;
+ s->vdsp.emulated_edge_mc(ubuf, ptr_cb,
+ uvlinesize >> field_based, uvlinesize >> field_based,
+ 9, 9 + field_based,
+ uvsrc_x, uvsrc_y << field_based,
+ h_edge_pos >> 1, v_edge_pos >> 1);
+ s->vdsp.emulated_edge_mc(vbuf, ptr_cr,
+ uvlinesize >> field_based,uvlinesize >> field_based,
+ 9, 9 + field_based,
+ uvsrc_x, uvsrc_y << field_based,
+ h_edge_pos >> 1, v_edge_pos >> 1);
+ ptr_cb = ubuf;
+ ptr_cr = vbuf;
+ }
+ }
+
+ // FIXME use this for field pix too instead of the obnoxious hack which changes picture.f->data
+ if (bottom_field) {
+ dest_y += s->linesize;
+ dest_cb += s->uvlinesize;
+ dest_cr += s->uvlinesize;
+ }
+
+ if (field_select) {
+ ptr_y += s->linesize;
+ ptr_cb += s->uvlinesize;
+ ptr_cr += s->uvlinesize;
+ }
+
+ sx = (sx << 2) >> lowres;
+ sy = (sy << 2) >> lowres;
+ pix_op[lowres - 1](dest_y, ptr_y, linesize, h, sx, sy);
+
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ int hc = s->chroma_y_shift ? (h+1-bottom_field)>>1 : h;
+ uvsx = (uvsx << 2) >> lowres;
+ uvsy = (uvsy << 2) >> lowres;
+ if (hc) {
+ pix_op[op_index](dest_cb, ptr_cb, uvlinesize, hc, uvsx, uvsy);
+ pix_op[op_index](dest_cr, ptr_cr, uvlinesize, hc, uvsx, uvsy);
+ }
+ }
+ // FIXME h261 lowres loop filter
+}
+
+static inline void chroma_4mv_motion_lowres(MpegEncContext *s,
+ uint8_t *dest_cb, uint8_t *dest_cr,
+ uint8_t **ref_picture,
+ h264_chroma_mc_func * pix_op,
+ int mx, int my)
+{
+ const int lowres = s->avctx->lowres;
+ const int op_index = FFMIN(lowres, 3);
+ const int block_s = 8 >> lowres;
+ const int s_mask = (2 << lowres) - 1;
+ const int h_edge_pos = s->h_edge_pos >> lowres + 1;
+ const int v_edge_pos = s->v_edge_pos >> lowres + 1;
+ int emu = 0, src_x, src_y, sx, sy;
+ ptrdiff_t offset;
+ uint8_t *ptr;
+
+ if (s->quarter_sample) {
+ mx /= 2;
+ my /= 2;
+ }
+
+ /* In case of 8X8, we construct a single chroma motion vector
+ with a special rounding */
+ mx = ff_h263_round_chroma(mx);
+ my = ff_h263_round_chroma(my);
+
+ sx = mx & s_mask;
+ sy = my & s_mask;
+ src_x = s->mb_x * block_s + (mx >> lowres + 1);
+ src_y = s->mb_y * block_s + (my >> lowres + 1);
+
+ offset = src_y * s->uvlinesize + src_x;
+ ptr = ref_picture[1] + offset;
+ if ((unsigned) src_x > FFMAX(h_edge_pos - (!!sx) - block_s, 0) ||
+ (unsigned) src_y > FFMAX(v_edge_pos - (!!sy) - block_s, 0)) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
+ s->uvlinesize, s->uvlinesize,
+ 9, 9,
+ src_x, src_y, h_edge_pos, v_edge_pos);
+ ptr = s->edge_emu_buffer;
+ emu = 1;
+ }
+ sx = (sx << 2) >> lowres;
+ sy = (sy << 2) >> lowres;
+ pix_op[op_index](dest_cb, ptr, s->uvlinesize, block_s, sx, sy);
+
+ ptr = ref_picture[2] + offset;
+ if (emu) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
+ s->uvlinesize, s->uvlinesize,
+ 9, 9,
+ src_x, src_y, h_edge_pos, v_edge_pos);
+ ptr = s->edge_emu_buffer;
+ }
+ pix_op[op_index](dest_cr, ptr, s->uvlinesize, block_s, sx, sy);
+}
+
+/**
+ * motion compensation of a single macroblock
+ * @param s context
+ * @param dest_y luma destination pointer
+ * @param dest_cb chroma cb/u destination pointer
+ * @param dest_cr chroma cr/v destination pointer
+ * @param dir direction (0->forward, 1->backward)
+ * @param ref_picture array[3] of pointers to the 3 planes of the reference picture
+ * @param pix_op halfpel motion compensation function (average or put normally)
+ * the motion vectors are taken from s->mv and the MV type from s->mv_type
+ */
+static inline void MPV_motion_lowres(MpegEncContext *s,
+ uint8_t *dest_y, uint8_t *dest_cb,
+ uint8_t *dest_cr,
+ int dir, uint8_t **ref_picture,
+ h264_chroma_mc_func *pix_op)
+{
+ int mx, my;
+ int mb_x, mb_y, i;
+ const int lowres = s->avctx->lowres;
+ const int block_s = 8 >>lowres;
+
+ mb_x = s->mb_x;
+ mb_y = s->mb_y;
+
+ switch (s->mv_type) {
+ case MV_TYPE_16X16:
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, 0,
+ ref_picture, pix_op,
+ s->mv[dir][0][0], s->mv[dir][0][1],
+ 2 * block_s, mb_y);
+ break;
+ case MV_TYPE_8X8:
+ mx = 0;
+ my = 0;
+ for (i = 0; i < 4; i++) {
+ hpel_motion_lowres(s, dest_y + ((i & 1) + (i >> 1) *
+ s->linesize) * block_s,
+ ref_picture[0], 0, 0,
+ (2 * mb_x + (i & 1)) * block_s,
+ (2 * mb_y + (i >> 1)) * block_s,
+ s->width, s->height, s->linesize,
+ s->h_edge_pos >> lowres, s->v_edge_pos >> lowres,
+ block_s, block_s, pix_op,
+ s->mv[dir][i][0], s->mv[dir][i][1]);
+
+ mx += s->mv[dir][i][0];
+ my += s->mv[dir][i][1];
+ }
+
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY))
+ chroma_4mv_motion_lowres(s, dest_cb, dest_cr, ref_picture,
+ pix_op, mx, my);
+ break;
+ case MV_TYPE_FIELD:
+ if (s->picture_structure == PICT_FRAME) {
+ /* top field */
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 1, 0, s->field_select[dir][0],
+ ref_picture, pix_op,
+ s->mv[dir][0][0], s->mv[dir][0][1],
+ block_s, mb_y);
+ /* bottom field */
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 1, 1, s->field_select[dir][1],
+ ref_picture, pix_op,
+ 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 = s->current_picture_ptr->f->data;
+
+ }
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, s->field_select[dir][0],
+ ref_picture, pix_op,
+ s->mv[dir][0][0],
+ s->mv[dir][0][1], 2 * block_s, mb_y >> 1);
+ }
+ break;
+ case MV_TYPE_16X8:
+ for (i = 0; i < 2; i++) {
+ uint8_t **ref2picture;
+
+ 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;
+ }
+
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, s->field_select[dir][i],
+ ref2picture, pix_op,
+ s->mv[dir][i][0], s->mv[dir][i][1] +
+ 2 * block_s * i, block_s, mb_y >> 1);
+
+ dest_y += 2 * block_s * s->linesize;
+ dest_cb += (2 * block_s >> s->chroma_y_shift) * s->uvlinesize;
+ dest_cr += (2 * block_s >> s->chroma_y_shift) * s->uvlinesize;
+ }
+ break;
+ case MV_TYPE_DMV:
+ if (s->picture_structure == PICT_FRAME) {
+ for (i = 0; i < 2; i++) {
+ int j;
+ for (j = 0; j < 2; j++) {
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 1, j, j ^ i,
+ ref_picture, pix_op,
+ s->mv[dir][2 * i + j][0],
+ s->mv[dir][2 * i + j][1],
+ block_s, mb_y);
+ }
+ pix_op = s->h264chroma.avg_h264_chroma_pixels_tab;
+ }
+ } else {
+ for (i = 0; i < 2; i++) {
+ mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr,
+ 0, 0, s->picture_structure != i + 1,
+ ref_picture, pix_op,
+ s->mv[dir][2 * i][0],s->mv[dir][2 * i][1],
+ 2 * block_s, mb_y >> 1);
+
+ // after put we make avg of the same block
+ pix_op = s->h264chroma.avg_h264_chroma_pixels_tab;
+
+ // 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;
}
}
- av_log(s->avctx, AV_LOG_DEBUG, "\n");
}
+ break;
+ default:
+ av_assert2(0);
}
}
@@ -2023,12 +2946,12 @@ int ff_mpv_lowest_referenced_row(MpegEncContext *s, int dir)
}
for (i = 0; i < mvs; i++) {
- my = s->mv[dir][i][1]<<qpel_shift;
+ my = s->mv[dir][i][1];
my_max = FFMAX(my_max, my);
my_min = FFMIN(my_min, my);
}
- off = (FFMAX(-my_min, my_max) + 63) >> 6;
+ off = ((FFMAX(-my_min, my_max)<<qpel_shift) + 63) >> 6;
return FFMIN(FFMAX(s->mb_y + off, 0), s->mb_height-1);
unhandled:
@@ -2107,18 +3030,15 @@ void ff_clean_intra_table_entries(MpegEncContext *s)
*/
static av_always_inline
void mpv_decode_mb_internal(MpegEncContext *s, int16_t block[12][64],
- int is_mpeg12)
+ int lowres_flag, int is_mpeg12)
{
const int mb_xy = s->mb_y * s->mb_stride + s->mb_x;
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration){
- ff_xvmc_decode_mb(s);//xvmc uses pblocks
+ if (CONFIG_XVMC &&
+ s->avctx->hwaccel && s->avctx->hwaccel->decode_mb) {
+ s->avctx->hwaccel->decode_mb(s);//xvmc uses pblocks
return;
}
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
if(s->avctx->debug&FF_DEBUG_DCT_COEFF) {
/* print DCT coefficients */
@@ -2149,7 +3069,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
else if (!is_mpeg12 && (s->h263_pred || s->h263_aic))
s->mbintra_table[mb_xy]=1;
- if ((s->avctx->flags & CODEC_FLAG_PSNR) ||
+ if ((s->avctx->flags & CODEC_FLAG_PSNR) || s->avctx->frame_skip_threshold || s->avctx->frame_skip_factor ||
!(s->encoding && (s->intra_only || s->pict_type == AV_PICTURE_TYPE_B) &&
s->avctx->mb_decision != FF_MB_DECISION_RD)) { // FIXME precalc
uint8_t *dest_y, *dest_cb, *dest_cr;
@@ -2158,8 +3078,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
qpel_mc_func (*op_qpix)[16];
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= s->pict_type != AV_PICTURE_TYPE_B || s->encoding || s->avctx->draw_horiz_band;
- const int block_size = 8;
+ const int readable= s->pict_type != AV_PICTURE_TYPE_B || s->encoding || s->avctx->draw_horiz_band || lowres_flag;
+ const int block_size= lowres_flag ? 8>>s->avctx->lowres : 8;
/* avoid copy if macroblock skipped in last frame too */
/* skip only during decoding as we might trash the buffers during encoding a bit */
@@ -2168,7 +3088,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (s->mb_skipped) {
s->mb_skipped= 0;
- assert(s->pict_type!=AV_PICTURE_TYPE_I);
+ av_assert2(s->pict_type!=AV_PICTURE_TYPE_I);
*mbskip_ptr = 1;
} else if(!s->current_picture.reference) {
*mbskip_ptr = 1;
@@ -2208,19 +3128,31 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
}
- op_qpix= s->me.qpel_put;
- if ((!s->no_rounding) || s->pict_type==AV_PICTURE_TYPE_B){
- op_pix = s->hdsp.put_pixels_tab;
+ if(lowres_flag){
+ 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);
+ 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);
+ }
}else{
- op_pix = s->hdsp.put_no_rnd_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);
- op_pix = s->hdsp.avg_pixels_tab;
- op_qpix= s->me.qpel_avg;
- }
- 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);
+ op_qpix = s->me.qpel_put;
+ if ((!s->no_rounding) || s->pict_type==AV_PICTURE_TYPE_B){
+ op_pix = s->hdsp.put_pixels_tab;
+ }else{
+ op_pix = s->hdsp.put_no_rnd_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);
+ op_pix = s->hdsp.avg_pixels_tab;
+ op_qpix= s->me.qpel_avg;
+ }
+ 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);
+ }
}
}
@@ -2266,17 +3198,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
}else{
//chroma422
dct_linesize = uvlinesize << s->interlaced_dct;
- dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize * 8;
+ dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size;
add_dct(s, block[4], 4, dest_cb, dct_linesize);
add_dct(s, block[5], 5, dest_cr, dct_linesize);
add_dct(s, block[6], 6, dest_cb+dct_offset, dct_linesize);
add_dct(s, block[7], 7, dest_cr+dct_offset, dct_linesize);
if(!s->chroma_x_shift){//Chroma444
- add_dct(s, block[8], 8, dest_cb+8, dct_linesize);
- add_dct(s, block[9], 9, dest_cr+8, dct_linesize);
- add_dct(s, block[10], 10, dest_cb+8+dct_offset, dct_linesize);
- add_dct(s, block[11], 11, dest_cr+8+dct_offset, dct_linesize);
+ add_dct(s, block[8], 8, dest_cb+block_size, dct_linesize);
+ add_dct(s, block[9], 9, dest_cr+block_size, dct_linesize);
+ add_dct(s, block[10], 10, dest_cb+block_size+dct_offset, dct_linesize);
+ add_dct(s, block[11], 11, dest_cr+block_size+dct_offset, dct_linesize);
}
}
}//fi gray
@@ -2318,17 +3250,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
}else{
dct_linesize = uvlinesize << s->interlaced_dct;
- dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize * 8;
+ dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size;
s->idsp.idct_put(dest_cb, dct_linesize, block[4]);
s->idsp.idct_put(dest_cr, dct_linesize, block[5]);
s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]);
s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]);
if(!s->chroma_x_shift){//Chroma444
- s->idsp.idct_put(dest_cb + 8, dct_linesize, block[8]);
- s->idsp.idct_put(dest_cr + 8, dct_linesize, block[9]);
- s->idsp.idct_put(dest_cb + 8 + dct_offset, dct_linesize, block[10]);
- s->idsp.idct_put(dest_cr + 8 + dct_offset, dct_linesize, block[11]);
+ s->idsp.idct_put(dest_cb + block_size, dct_linesize, block[8]);
+ s->idsp.idct_put(dest_cr + block_size, dct_linesize, block[9]);
+ s->idsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]);
+ s->idsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]);
}
}
}//gray
@@ -2337,8 +3269,10 @@ FF_ENABLE_DEPRECATION_WARNINGS
skip_idct:
if(!readable){
s->hdsp.put_pixels_tab[0][0](s->dest[0], dest_y , linesize,16);
- 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);
+ if (!CONFIG_GRAY || !(s->avctx->flags & 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);
+ }
}
}
}
@@ -2347,23 +3281,25 @@ void ff_mpv_decode_mb(MpegEncContext *s, int16_t block[12][64])
{
#if !CONFIG_SMALL
if(s->out_format == FMT_MPEG1) {
- mpv_decode_mb_internal(s, block, 1);
+ if(s->avctx->lowres) mpv_decode_mb_internal(s, block, 1, 1);
+ else mpv_decode_mb_internal(s, block, 0, 1);
} else
#endif
- mpv_decode_mb_internal(s, block, 0);
+ if(s->avctx->lowres) mpv_decode_mb_internal(s, block, 1, 0);
+ else mpv_decode_mb_internal(s, block, 0, 0);
}
void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h)
{
- ff_draw_horiz_band(s->avctx, s->current_picture.f,
- s->last_picture.f, y, h, s->picture_structure,
+ ff_draw_horiz_band(s->avctx, s->current_picture_ptr->f,
+ s->last_picture_ptr ? s->last_picture_ptr->f : NULL, y, h, s->picture_structure,
s->first_field, s->low_delay);
}
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 mb_size= 4;
+ const int mb_size= 4 - s->avctx->lowres;
s->block_index[0]= s->b8_stride*(s->mb_y*2 ) - 2 + s->mb_x*2;
s->block_index[1]= s->b8_stride*(s->mb_y*2 ) - 1 + s->mb_x*2;
@@ -2373,9 +3309,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] + ((s->mb_x - 1) << mb_size);
- s->dest[1] = s->current_picture.f->data[1] + ((s->mb_x - 1) << (mb_size - s->chroma_x_shift));
- s->dest[2] = s->current_picture.f->data[2] + ((s->mb_x - 1) << (mb_size - s->chroma_x_shift));
+ s->dest[0] = s->current_picture.f->data[0] + (int)((s->mb_x - 1U) << mb_size);
+ s->dest[1] = s->current_picture.f->data[1] + (int)((s->mb_x - 1U) << (mb_size - s->chroma_x_shift));
+ s->dest[2] = s->current_picture.f->data[2] + (int)((s->mb_x - 1U) << (mb_size - s->chroma_x_shift));
if(!(s->pict_type==AV_PICTURE_TYPE_B && s->avctx->draw_horiz_band && s->picture_structure==PICT_FRAME))
{
@@ -2387,7 +3323,7 @@ void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename
s->dest[0] += (s->mb_y>>1) * linesize << mb_size;
s->dest[1] += (s->mb_y>>1) * uvlinesize << (mb_size - s->chroma_y_shift);
s->dest[2] += (s->mb_y>>1) * uvlinesize << (mb_size - s->chroma_y_shift);
- assert((s->mb_y&1) == (s->picture_structure == PICT_BOTTOM_FIELD));
+ av_assert1((s->mb_y&1) == (s->picture_structure == PICT_BOTTOM_FIELD));
}
}
}
@@ -2437,6 +3373,7 @@ void ff_mpeg_flush(AVCodecContext *avctx){
ff_mpeg_unref_picture(s->avctx, &s->next_picture);
s->mb_x= s->mb_y= 0;
+ s->closed_gop= 0;
s->parse_context.state= -1;
s->parse_context.frame_start_found= 0;
diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h
index 8ac7851d2c..a042dc11c6 100644
--- a/libavcodec/mpegvideo.h
+++ b/libavcodec/mpegvideo.h
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,6 +35,7 @@
#include "error_resilience.h"
#include "fdctdsp.h"
#include "get_bits.h"
+#include "h264chroma.h"
#include "h263dsp.h"
#include "hpeldsp.h"
#include "idctdsp.h"
@@ -52,6 +53,7 @@
#include "videodsp.h"
#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#define FRAME_SKIPPED 100 ///< return value for header parsers if frame is not coded
@@ -63,11 +65,10 @@ enum OutputFormat {
};
#define MAX_FCODE 7
-#define MAX_MV 2048
+#define MAX_MV 4096
-#define MAX_THREADS 16
-
-#define MAX_PICTURE_COUNT 32
+#define MAX_THREADS 32
+#define MAX_PICTURE_COUNT 36
#define MAX_B_FRAMES 16
@@ -123,6 +124,9 @@ typedef struct Picture{
AVBufferRef *mc_mb_var_buf;
uint16_t *mc_mb_var; ///< Table for motion compensated MB variances
+ int alloc_mb_width; ///< mb_width used to allocate tables
+ int alloc_mb_height; ///< mb_height used to allocate tables
+
AVBufferRef *mb_mean_buf;
uint8_t *mb_mean; ///< Table for MB luminance
@@ -134,14 +138,16 @@ typedef struct Picture{
int field_picture; ///< whether or not the picture was encoded in separate fields
- int mb_var_sum; ///< sum of MB variance for current frame
- int mc_mb_var_sum; ///< motion compensated MB variance for current frame
+ 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
- int b_frame_score; /* */
+ int b_frame_score;
int needs_realloc; ///< Picture needs to be reallocated (eg due to a frame size change)
int reference;
int shared;
+
+ uint64_t error[AV_NUM_DATA_POINTERS];
} Picture;
/**
@@ -184,8 +190,8 @@ typedef struct MotionEstContext{
int stride;
int uvstride;
/* temp variables for picture complexity calculation */
- int mc_mb_var_sum_temp;
- int mb_var_sum_temp;
+ int64_t mc_mb_var_sum_temp;
+ int64_t mb_var_sum_temp;
int scene_change_score;
/* cmp, chroma_cmp;*/
op_pixels_func (*hpel_put)[4];
@@ -316,7 +322,7 @@ typedef struct MpegEncContext {
uint8_t *coded_block_base;
uint8_t *coded_block; ///< used for coded block pattern prediction (msmpeg4v3, wmv1)
int16_t (*ac_val_base)[16];
- int16_t (*ac_val[3])[16]; ///< used for for mpeg4 AC prediction, all 3 arrays must be continuous
+ int16_t (*ac_val[3])[16]; ///< used for mpeg4 AC prediction, all 3 arrays must be continuous
int mb_skipped; ///< MUST BE SET only during DECODING
uint8_t *mbskip_table; /**< used to avoid copy if macroblock skipped (for black regions for example)
and used for b-frame encoding & decoding (contains skip table of next P Frame) */
@@ -335,11 +341,14 @@ typedef struct MpegEncContext {
int *lambda_table;
int adaptive_quant; ///< use adaptive quantization
int dquant; ///< qscale difference to prev qscale
+ int closed_gop; ///< MPEG1/2 GOP is closed
int pict_type; ///< AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, ...
+ int vbv_delay;
int last_pict_type; //FIXME removes
int last_non_b_pict_type; ///< used for mpeg4 gmc b-frames & ratecontrol
int droppable;
int frame_rate_index;
+ AVRational mpeg2_frame_rate_ext;
int last_lambda_for[5]; ///< last lambda for a specific pict type
int skipdct; ///< skip dct and code zero residual
@@ -349,6 +358,7 @@ typedef struct MpegEncContext {
BlockDSPContext bdsp;
FDCTDSPContext fdsp;
+ H264ChromaContext h264chroma;
HpelDSPContext hdsp;
IDCTDSPContext idsp;
MECmpContext mecc;
@@ -430,18 +440,22 @@ typedef struct MpegEncContext {
int ac_esc_length; ///< num of bits needed to encode the longest esc
uint8_t *intra_ac_vlc_length;
uint8_t *intra_ac_vlc_last_length;
+ uint8_t *intra_chroma_ac_vlc_length;
+ uint8_t *intra_chroma_ac_vlc_last_length;
uint8_t *inter_ac_vlc_length;
uint8_t *inter_ac_vlc_last_length;
uint8_t *luma_dc_vlc_length;
#define UNI_AC_ENC_INDEX(run,level) ((run)*128 + (level))
- int coded_score[8];
+ int coded_score[12];
/** precomputed matrix (combine qscale and DCT renorm) */
int (*q_intra_matrix)[64];
+ int (*q_chroma_intra_matrix)[64];
int (*q_inter_matrix)[64];
/** identical to the above but for MMX & these are not permutated, second 64 entries are bias*/
uint16_t (*q_intra_matrix16)[2][64];
+ uint16_t (*q_chroma_intra_matrix16)[2][64];
uint16_t (*q_inter_matrix16)[2][64];
/* noise reduction */
@@ -452,6 +466,7 @@ typedef struct MpegEncContext {
/* bit rate control */
int64_t total_bits;
int frame_bits; ///< bits used for the current frame
+ int stuffing_bits; ///< bits used for stuffing
int next_lambda; ///< next lambda used for retrying to encode a frame
RateControlContext rc_context; ///< contains stuff only accessed in ratecontrol.c
@@ -483,6 +498,7 @@ typedef struct MpegEncContext {
int prev_mb_info, last_mb_info;
uint8_t *mb_info_ptr;
int mb_info_size;
+ int ehc_mode;
/* H.263+ specific */
int umvplus; ///< == H263+ && unrestricted_mv
@@ -533,6 +549,7 @@ typedef struct MpegEncContext {
/* MJPEG specific */
struct MJpegContext *mjpeg_ctx;
+ int esc_pos;
/* MSMPEG4 specific */
int mv_table_index;
@@ -574,11 +591,13 @@ typedef struct MpegEncContext {
int q_scale_type;
int intra_vlc_format;
int alternate_scan;
+ int seq_disp_ext;
int repeat_first_field;
int chroma_420_type;
int chroma_format;
#define CHROMA_420 1
#define CHROMA_422 2
+#define CHROMA_444 3
int chroma_x_shift;//depend on pix_format, that depend on chroma_format
int chroma_y_shift;
@@ -592,7 +611,12 @@ typedef struct MpegEncContext {
/* RTP specific */
int rtp_mode;
+ char *tc_opt_str; ///< timecode option string
+ AVTimecode tc; ///< timecode context
+
uint8_t *ptr_lastgob;
+ int swap_uv; //vcr2 codec is an MPEG-2 variant with U and V swapped
+ int pack_pblocks; //xvmc needs to keep blocks without gaps.
int16_t (*pblocks[12])[64];
int16_t (*block)[64]; ///< points to one of the following blocks
@@ -628,7 +652,7 @@ typedef struct MpegEncContext {
/**
* ratecontrol qmin qmax limiting method
- * 0-> clipping, 1-> use a nice continuous function to limit qscale wthin qmin/qmax.
+ * 0-> clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax.
*/
float rc_qsquish;
float rc_qmod_amp;
@@ -663,7 +687,9 @@ typedef struct MpegEncContext {
#define FF_MPV_FLAG_NAQ 0x0010
#define FF_MPV_FLAG_MV0 0x0020
+#ifndef FF_MPV_OFFSET
#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x)
+#endif
#define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
#define FF_MPV_COMMON_OPTS \
{ "mpv_flags", "Flags common for all mpegvideo-based encoders.", FF_MPV_OFFSET(mpv_flags), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "mpv_flags" },\
@@ -712,8 +738,11 @@ static const AVClass name ## _class = {\
*/
void ff_mpv_common_defaults(MpegEncContext *s);
+void ff_dct_encode_init_x86(MpegEncContext *s);
+
int ff_mpv_common_init(MpegEncContext *s);
void ff_mpv_common_init_arm(MpegEncContext *s);
+void ff_mpv_common_init_axp(MpegEncContext *s);
void ff_mpv_common_init_neon(MpegEncContext *s);
void ff_mpv_common_init_ppc(MpegEncContext *s);
void ff_mpv_common_init_x86(MpegEncContext *s);
@@ -722,6 +751,7 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s);
void ff_mpv_common_end(MpegEncContext *s);
void ff_mpv_decode_defaults(MpegEncContext *s);
+void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx);
void ff_mpv_decode_mb(MpegEncContext *s, int16_t block[12][64]);
void ff_mpv_report_decode_progress(MpegEncContext *s);
@@ -736,11 +766,20 @@ void ff_mpv_encode_init_x86(MpegEncContext *s);
int ff_mpv_encode_end(AVCodecContext *avctx);
int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet);
+int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase);
void ff_clean_intra_table_entries(MpegEncContext *s);
void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h);
void ff_mpeg_flush(AVCodecContext *avctx);
-void ff_print_debug_info(MpegEncContext *s, Picture *p);
+
+void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict);
+void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table,
+ uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2],
+ int *low_delay,
+ int mb_width, int mb_height, int mb_stride, int quarter_sample);
+
+int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type);
+
void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix);
int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared);
@@ -749,6 +788,7 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, const AVCodecContext *src
void ff_set_qscale(MpegEncContext * s, int qscale);
void ff_mpv_idct_init(MpegEncContext *s);
+int ff_dct_encode_init(MpegEncContext *s);
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);
int ff_dct_quantize_c(MpegEncContext *s, int16_t *block, int n, int qscale, int *overflow);
@@ -775,7 +815,7 @@ int ff_alloc_picture(MpegEncContext *s, Picture *pic, int shared);
void ff_block_permute(int16_t *block, uint8_t *permutation, const uint8_t *scantable, int last);
static inline void ff_update_block_index(MpegEncContext *s){
- const int block_size = 8;
+ const int block_size= 8 >> s->avctx->lowres;
s->block_index[0]+=2;
s->block_index[1]+=2;
@@ -868,4 +908,5 @@ int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src);
void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *picture);
void ff_free_picture_tables(Picture *pic);
+
#endif /* AVCODEC_MPEGVIDEO_H */
diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
index 15cca64c49..2833c55bbb 100644
--- a/libavcodec/mpegvideo_enc.c
+++ b/libavcodec/mpegvideo_enc.c
@@ -5,20 +5,20 @@
*
* 4MV & hq & B-frame encoding stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,11 +57,12 @@
#include "internal.h"
#include "bytestream.h"
#include <limits.h>
+#include "sp5x.h"
#define QUANT_BIAS_SHIFT 8
#define QMAT_SHIFT_MMX 16
-#define QMAT_SHIFT 22
+#define QMAT_SHIFT 21
static int encode_picture(MpegEncContext *s, int picture_number);
static int dct_quantize_refine(MpegEncContext *s, int16_t *block, int16_t *weight, int16_t *orig, int n, int qscale);
@@ -233,6 +234,23 @@ static void mpv_encode_defaults(MpegEncContext *s)
s->picture_in_gop_number = 0;
}
+av_cold int ff_dct_encode_init(MpegEncContext *s) {
+ if (ARCH_X86)
+ ff_dct_encode_init_x86(s);
+
+ 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;
+
+ return 0;
+}
+
/* init video encoder */
av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
{
@@ -251,18 +269,22 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
}
break;
case AV_CODEC_ID_MJPEG:
+ case AV_CODEC_ID_AMV:
format_supported = 0;
/* JPEG color space */
if (avctx->pix_fmt == AV_PIX_FMT_YUVJ420P ||
avctx->pix_fmt == AV_PIX_FMT_YUVJ422P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUVJ444P ||
(avctx->color_range == AVCOL_RANGE_JPEG &&
(avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
- avctx->pix_fmt == AV_PIX_FMT_YUV422P)))
+ avctx->pix_fmt == AV_PIX_FMT_YUV422P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV444P)))
format_supported = 1;
/* MPEG color space */
else if (avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL &&
(avctx->pix_fmt == AV_PIX_FMT_YUV420P ||
- avctx->pix_fmt == AV_PIX_FMT_YUV422P))
+ avctx->pix_fmt == AV_PIX_FMT_YUV422P ||
+ avctx->pix_fmt == AV_PIX_FMT_YUV444P))
format_supported = 1;
if (!format_supported) {
@@ -278,6 +300,10 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
}
switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUVJ444P:
+ case AV_PIX_FMT_YUV444P:
+ s->chroma_format = CHROMA_444;
+ break;
case AV_PIX_FMT_YUVJ422P:
case AV_PIX_FMT_YUV422P:
s->chroma_format = CHROMA_422;
@@ -294,8 +320,9 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->height = avctx->height;
if (avctx->gop_size > 600 &&
avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
- av_log(avctx, AV_LOG_ERROR,
- "Warning keyframe interval too large! reducing it ...\n");
+ av_log(avctx, AV_LOG_WARNING,
+ "keyframe interval too large!, reducing it from %d to %d\n",
+ avctx->gop_size, 600);
avctx->gop_size = 600;
}
s->gop_size = avctx->gop_size;
@@ -303,6 +330,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
if (avctx->max_b_frames > MAX_B_FRAMES) {
av_log(avctx, AV_LOG_ERROR, "Too many B-frames requested, maximum "
"is %d.\n", MAX_B_FRAMES);
+ avctx->max_b_frames = MAX_B_FRAMES;
}
s->max_b_frames = avctx->max_b_frames;
s->codec_id = avctx->codec->id;
@@ -311,6 +339,24 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->mpeg_quant = avctx->mpeg_quant;
s->rtp_mode = !!avctx->rtp_payload_size;
s->intra_dc_precision = avctx->intra_dc_precision;
+
+ // workaround some differences between how applications specify dc precision
+ if (s->intra_dc_precision < 0) {
+ s->intra_dc_precision += 8;
+ } else if (s->intra_dc_precision >= 8)
+ s->intra_dc_precision -= 8;
+
+ if (s->intra_dc_precision < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "intra dc precision must be positive, note some applications use"
+ " 0 and some 8 as base meaning 8bit, the value must not be smaller than that\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (s->intra_dc_precision > (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 3 : 0)) {
+ av_log(avctx, AV_LOG_ERROR, "intra dc precision too large\n");
+ return AVERROR(EINVAL);
+ }
s->user_specified_pts = AV_NOPTS_VALUE;
if (s->gop_size <= 1) {
@@ -344,9 +390,33 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->loop_filter = !!(s->avctx->flags & CODEC_FLAG_LOOP_FILTER);
if (avctx->rc_max_rate && !avctx->rc_buffer_size) {
- av_log(avctx, AV_LOG_ERROR,
- "a vbv buffer size is needed, "
- "for encoding with a maximum bitrate\n");
+ switch(avctx->codec_id) {
+ case AV_CODEC_ID_MPEG1VIDEO:
+ case AV_CODEC_ID_MPEG2VIDEO:
+ avctx->rc_buffer_size = FFMAX(avctx->rc_max_rate, 15000000) * 112LL / 15000000 * 16384;
+ break;
+ case AV_CODEC_ID_MPEG4:
+ case AV_CODEC_ID_MSMPEG4V1:
+ case AV_CODEC_ID_MSMPEG4V2:
+ case AV_CODEC_ID_MSMPEG4V3:
+ if (avctx->rc_max_rate >= 15000000) {
+ avctx->rc_buffer_size = 320 + (avctx->rc_max_rate - 15000000LL) * (760-320) / (38400000 - 15000000);
+ } else if(avctx->rc_max_rate >= 2000000) {
+ avctx->rc_buffer_size = 80 + (avctx->rc_max_rate - 2000000LL) * (320- 80) / (15000000 - 2000000);
+ } else if(avctx->rc_max_rate >= 384000) {
+ avctx->rc_buffer_size = 40 + (avctx->rc_max_rate - 384000LL) * ( 80- 40) / ( 2000000 - 384000);
+ } else
+ avctx->rc_buffer_size = 40;
+ avctx->rc_buffer_size *= 16384;
+ break;
+ }
+ if (avctx->rc_buffer_size) {
+ av_log(avctx, AV_LOG_INFO, "Automatically choosing VBV buffer size of %d kbyte\n", avctx->rc_buffer_size/8192);
+ }
+ }
+
+ if ((!avctx->rc_max_rate) != (!avctx->rc_buffer_size)) {
+ av_log(avctx, AV_LOG_ERROR, "Either both buffer size and max rate or neither must be specified\n");
return -1;
}
@@ -361,7 +431,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
}
if (avctx->rc_max_rate && avctx->rc_max_rate < avctx->bit_rate) {
- av_log(avctx, AV_LOG_INFO, "bitrate above max bitrate\n");
+ av_log(avctx, AV_LOG_ERROR, "bitrate above max bitrate\n");
return -1;
}
@@ -382,9 +452,9 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
if (!s->fixed_qscale &&
avctx->bit_rate * av_q2d(avctx->time_base) >
avctx->bit_rate_tolerance) {
- av_log(avctx, AV_LOG_ERROR,
- "bitrate tolerance too small for bitrate\n");
- return -1;
+ av_log(avctx, AV_LOG_WARNING,
+ "bitrate tolerance %d too small for bitrate %d, overriding\n", avctx->bit_rate_tolerance, avctx->bit_rate);
+ avctx->bit_rate_tolerance = 5 * avctx->bit_rate * av_q2d(avctx->time_base);
}
if (s->avctx->rc_max_rate &&
@@ -423,18 +493,74 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "b frames not supported by codec\n");
return -1;
}
+ if (s->max_b_frames < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "max b frames must be 0 or positive for mpegvideo based encoders\n");
+ return -1;
+ }
if ((s->codec_id == AV_CODEC_ID_MPEG4 ||
s->codec_id == AV_CODEC_ID_H263 ||
s->codec_id == AV_CODEC_ID_H263P) &&
(avctx->sample_aspect_ratio.num > 255 ||
avctx->sample_aspect_ratio.den > 255)) {
- av_log(avctx, AV_LOG_ERROR,
- "Invalid pixel aspect ratio %i/%i, limit is 255/255\n",
+ av_log(avctx, AV_LOG_WARNING,
+ "Invalid pixel aspect ratio %i/%i, limit is 255/255 reducing\n",
avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den);
+ av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den,
+ avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 255);
+ }
+
+ if ((s->codec_id == AV_CODEC_ID_H263 ||
+ s->codec_id == AV_CODEC_ID_H263P) &&
+ (avctx->width > 2048 ||
+ avctx->height > 1152 )) {
+ av_log(avctx, AV_LOG_ERROR, "H.263 does not support resolutions above 2048x1152\n");
+ return -1;
+ }
+ if ((s->codec_id == AV_CODEC_ID_H263 ||
+ s->codec_id == AV_CODEC_ID_H263P) &&
+ ((avctx->width &3) ||
+ (avctx->height&3) )) {
+ av_log(avctx, AV_LOG_ERROR, "w/h must be a multiple of 4\n");
+ return -1;
+ }
+
+ if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO &&
+ (avctx->width > 4095 ||
+ avctx->height > 4095 )) {
+ av_log(avctx, AV_LOG_ERROR, "MPEG-1 does not support resolutions above 4095x4095\n");
+ return -1;
+ }
+
+ if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
+ (avctx->width > 16383 ||
+ avctx->height > 16383 )) {
+ av_log(avctx, AV_LOG_ERROR, "MPEG-2 does not support resolutions above 16383x16383\n");
return -1;
}
+ if (s->codec_id == AV_CODEC_ID_RV10 &&
+ (avctx->width &15 ||
+ avctx->height&15 )) {
+ av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 16\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (s->codec_id == AV_CODEC_ID_RV20 &&
+ (avctx->width &3 ||
+ avctx->height&3 )) {
+ av_log(avctx, AV_LOG_ERROR, "width and height must be a multiple of 4\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((s->codec_id == AV_CODEC_ID_WMV1 ||
+ s->codec_id == AV_CODEC_ID_WMV2) &&
+ avctx->width & 1) {
+ av_log(avctx, AV_LOG_ERROR, "width must be multiple of 2\n");
+ return -1;
+ }
+
if ((s->avctx->flags & (CODEC_FLAG_INTERLACED_DCT | CODEC_FLAG_INTERLACED_ME)) &&
s->codec_id != AV_CODEC_ID_MPEG4 && s->codec_id != AV_CODEC_ID_MPEG2VIDEO) {
av_log(avctx, AV_LOG_ERROR, "interlacing not supported by codec\n");
@@ -442,7 +568,8 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
}
// FIXME mpeg2 uses that too
- if (s->mpeg_quant && s->codec_id != AV_CODEC_ID_MPEG4) {
+ if (s->mpeg_quant && ( s->codec_id != AV_CODEC_ID_MPEG4
+ && s->codec_id != AV_CODEC_ID_MPEG2VIDEO)) {
av_log(avctx, AV_LOG_ERROR,
"mpeg2 style quantization not supported by codec\n");
return -1;
@@ -492,6 +619,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->codec_id != AV_CODEC_ID_MPEG4 &&
s->codec_id != AV_CODEC_ID_MPEG1VIDEO &&
s->codec_id != AV_CODEC_ID_MPEG2VIDEO &&
+ s->codec_id != AV_CODEC_ID_MJPEG &&
(s->codec_id != AV_CODEC_ID_H263P)) {
av_log(avctx, AV_LOG_ERROR,
"multi threaded encoding not supported by codec\n");
@@ -500,14 +628,17 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
if (s->avctx->thread_count < 1) {
av_log(avctx, AV_LOG_ERROR,
- "automatic thread number detection not supported by codec,"
+ "automatic thread number detection not supported by codec, "
"patch welcome\n");
return -1;
}
- if (s->avctx->thread_count > 1)
+ if (s->avctx->slices > 1 || s->avctx->thread_count > 1)
s->rtp_mode = 1;
+ if (s->avctx->thread_count > 1 && s->codec_id == AV_CODEC_ID_H263P)
+ s->h263_slice_structured = 1;
+
if (!avctx->time_base.den || !avctx->time_base.num) {
av_log(avctx, AV_LOG_ERROR, "framerate not set\n");
return -1;
@@ -527,8 +658,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
//return -1;
}
- if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO ||
- s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG) {
+ if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG1VIDEO || s->codec_id == AV_CODEC_ID_MPEG2VIDEO || s->codec_id == AV_CODEC_ID_MJPEG || s->codec_id==AV_CODEC_ID_AMV) {
// (a + x * 3 / 8) / x
s->intra_quant_bias = 3 << (QUANT_BIAS_SHIFT - 3);
s->inter_quant_bias = 0;
@@ -538,11 +668,18 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->inter_quant_bias = -(1 << (QUANT_BIAS_SHIFT - 2));
}
+ if (avctx->qmin > avctx->qmax || avctx->qmin <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "qmin and or qmax are invalid, they must be 0 < min <= max\n");
+ return AVERROR(EINVAL);
+ }
+
if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS)
s->intra_quant_bias = avctx->intra_quant_bias;
if (avctx->inter_quant_bias != FF_DEFAULT_QUANT_BIAS)
s->inter_quant_bias = avctx->inter_quant_bias;
+ av_log(avctx, AV_LOG_DEBUG, "intra_quant_bias = %d inter_quant_bias = %d\n",s->intra_quant_bias,s->inter_quant_bias);
+
if (avctx->codec_id == AV_CODEC_ID_MPEG4 &&
s->avctx->time_base.den > (1 << 16) - 1) {
av_log(avctx, AV_LOG_ERROR,
@@ -567,6 +704,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->rtp_mode = 1;
break;
case AV_CODEC_ID_MJPEG:
+ case AV_CODEC_ID_AMV:
s->out_format = FMT_MJPEG;
s->intra_only = 1; /* force intra only for jpeg */
if (!CONFIG_MJPEG_ENCODER ||
@@ -592,13 +730,13 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
break;
case AV_CODEC_ID_H263:
if (!CONFIG_H263_ENCODER)
- return -1;
+ return -1;
if (ff_match_2uint16(ff_h263_format, FF_ARRAY_ELEMS(ff_h263_format),
s->width, s->height) == 8) {
- av_log(avctx, AV_LOG_INFO,
+ av_log(avctx, AV_LOG_ERROR,
"The specified picture size of %dx%d is not valid for "
"the H.263 codec.\nValid sizes are 128x96, 176x144, "
- "352x288, 704x576, and 1408x1152."
+ "352x288, 704x576, and 1408x1152. "
"Try H.263+.\n", s->width, s->height);
return -1;
}
@@ -703,9 +841,6 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
if (ff_mpv_common_init(s) < 0)
return -1;
- if (ARCH_X86)
- ff_mpv_encode_init_x86(s);
-
ff_fdctdsp_init(&s->fdsp, avctx);
ff_me_cmp_init(&s->mecc, avctx);
ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx);
@@ -722,8 +857,10 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
FF_ALLOCZ_OR_GOTO(s->avctx, s->avctx->stats_out, 256, fail);
FF_ALLOCZ_OR_GOTO(s->avctx, s->q_intra_matrix, 64 * 32 * sizeof(int), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->q_chroma_intra_matrix, 64 * 32 * sizeof(int), fail);
FF_ALLOCZ_OR_GOTO(s->avctx, s->q_inter_matrix, 64 * 32 * sizeof(int), fail);
FF_ALLOCZ_OR_GOTO(s->avctx, s->q_intra_matrix16, 64 * 32 * 2 * sizeof(uint16_t), fail);
+ FF_ALLOCZ_OR_GOTO(s->avctx, s->q_chroma_intra_matrix16, 64 * 32 * 2 * sizeof(uint16_t), fail);
FF_ALLOCZ_OR_GOTO(s->avctx, s->q_inter_matrix16, 64 * 32 * 2 * sizeof(uint16_t), fail);
FF_ALLOCZ_OR_GOTO(s->avctx, s->input_picture,
MAX_PICTURE_COUNT * sizeof(Picture *), fail);
@@ -735,15 +872,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
2 * 64 * sizeof(uint16_t), fail);
}
- 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 (avctx->trellis)
- s->dct_quantize = dct_quantize_trellis_c;
+ ff_dct_encode_init(s);
if ((CONFIG_H263P_ENCODER || CONFIG_RV20_ENCODER) && s->modified_quant)
s->chroma_qscale_table = ff_h263_chroma_qscale_table;
@@ -776,6 +905,7 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx)
s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i];
} else {
/* mpeg1/2 */
+ s->chroma_intra_matrix[j] =
s->intra_matrix[j] = ff_mpeg1_default_intra_matrix[i];
s->inter_matrix[j] = ff_mpeg1_default_non_intra_matrix[i];
}
@@ -891,6 +1021,10 @@ av_cold int ff_mpv_encode_end(AVCodecContext *avctx)
av_freep(&s->avctx->stats_out);
av_freep(&s->ac_stats);
+ if(s->q_chroma_intra_matrix != s->q_intra_matrix ) av_freep(&s->q_chroma_intra_matrix);
+ if(s->q_chroma_intra_matrix16 != s->q_intra_matrix16) av_freep(&s->q_chroma_intra_matrix16);
+ s->q_chroma_intra_matrix= NULL;
+ s->q_chroma_intra_matrix16= NULL;
av_freep(&s->q_intra_matrix);
av_freep(&s->q_inter_matrix);
av_freep(&s->q_intra_matrix16);
@@ -955,18 +1089,17 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
if (pts != AV_NOPTS_VALUE) {
if (s->user_specified_pts != AV_NOPTS_VALUE) {
- int64_t time = pts;
int64_t last = s->user_specified_pts;
- if (time <= last) {
+ if (pts <= last) {
av_log(s->avctx, AV_LOG_ERROR,
- "Error, Invalid timestamp=%"PRId64", "
- "last=%"PRId64"\n", pts, s->user_specified_pts);
- return -1;
+ "Invalid pts (%"PRId64") <= last (%"PRId64")\n",
+ pts, last);
+ return AVERROR(EINVAL);
}
if (!s->low_delay && display_picture_number == 1)
- s->dts_delta = time - last;
+ s->dts_delta = pts - last;
}
s->user_specified_pts = pts;
} else {
@@ -990,8 +1123,12 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
direct = 0;
if ((s->width & 15) || (s->height & 15))
direct = 0;
+ if (((intptr_t)(pic_arg->data[0])) & (STRIDE_ALIGN-1))
+ direct = 0;
+ if (s->linesize & (STRIDE_ALIGN-1))
+ direct = 0;
- ff_dlog(s->avctx, "%d %d %td %td\n", pic_arg->linesize[0],
+ 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);
@@ -1029,6 +1166,12 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
int h = s->height >> v_shift;
uint8_t *src = pic_arg->data[i];
uint8_t *dst = pic->f->data[i];
+ int vpad = 16;
+
+ if ( s->codec_id == AV_CODEC_ID_MPEG2VIDEO
+ && !s->progressive_sequence
+ && FFALIGN(s->height, 32) - s->height > 16)
+ vpad = 32;
if (!s->avctx->rc_buffer_size)
dst += INPLACE_OFFSET;
@@ -1044,11 +1187,11 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
src += src_stride;
}
}
- if ((s->width & 15) || (s->height & 15)) {
+ if ((s->width & 15) || (s->height & (vpad-1))) {
s->mpvencdsp.draw_edges(dst, dst_stride,
w, h,
16 >> h_shift,
- 16 >> v_shift,
+ vpad >> v_shift,
EDGE_BOTTOM);
}
}
@@ -1087,19 +1230,23 @@ static int skip_check(MpegEncContext *s, Picture *p, Picture *ref)
uint8_t *rptr = ref->f->data[plane] + 8 * (x + y * stride);
int v = s->mecc.frame_skip_cmp[1](s, dptr, rptr, stride, 8);
- switch (s->avctx->frame_skip_exp) {
+ switch (FFABS(s->avctx->frame_skip_exp)) {
case 0: score = FFMAX(score, v); break;
case 1: score += FFABS(v); break;
- case 2: score += v * v; break;
- case 3: score64 += FFABS(v * v * (int64_t)v); break;
- case 4: score64 += v * v * (int64_t)(v * v); break;
+ case 2: score64 += v * (int64_t)v; break;
+ case 3: score64 += FFABS(v * (int64_t)v * v); break;
+ case 4: score64 += (v * (int64_t)v) * (v * (int64_t)v); break;
}
}
}
}
+ emms_c();
if (score)
score64 = score;
+ if (s->avctx->frame_skip_exp < 0)
+ score64 = pow(score64 / (double)(s->mb_width * s->mb_height),
+ -1.0/s->avctx->frame_skip_exp);
if (score64 < s->avctx->frame_skip_threshold)
return 1;
@@ -1134,7 +1281,7 @@ static int estimate_best_b_count(MpegEncContext *s)
if (!c)
return AVERROR(ENOMEM);
- assert(scale >= 0 && scale <= 3);
+ av_assert0(scale >= 0 && scale <= 3);
//emms_c();
//s->next_picture_ptr->quality;
@@ -1164,29 +1311,31 @@ static int estimate_best_b_count(MpegEncContext *s)
for (i = 0; i < s->max_b_frames + 2; i++) {
Picture pre_input, *pre_input_ptr = i ? s->input_picture[i - 1] :
s->next_picture_ptr;
+ uint8_t *data[4];
if (pre_input_ptr && (!i || s->input_picture[i - 1])) {
pre_input = *pre_input_ptr;
+ memcpy(data, pre_input_ptr->f->data, sizeof(data));
if (!pre_input.shared && i) {
- pre_input.f->data[0] += INPLACE_OFFSET;
- pre_input.f->data[1] += INPLACE_OFFSET;
- pre_input.f->data[2] += INPLACE_OFFSET;
+ data[0] += INPLACE_OFFSET;
+ data[1] += INPLACE_OFFSET;
+ data[2] += INPLACE_OFFSET;
}
s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[0],
s->tmp_frames[i]->linesize[0],
- pre_input.f->data[0],
+ data[0],
pre_input.f->linesize[0],
c->width, c->height);
s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[1],
s->tmp_frames[i]->linesize[1],
- pre_input.f->data[1],
+ data[1],
pre_input.f->linesize[1],
c->width >> 1, c->height >> 1);
s->mpvencdsp.shrink[scale](s->tmp_frames[i]->data[2],
s->tmp_frames[i]->linesize[2],
- pre_input.f->data[2],
+ data[2],
pre_input.f->linesize[2],
c->width >> 1, c->height >> 1);
}
@@ -1249,6 +1398,19 @@ static int select_input_picture(MpegEncContext *s)
/* set next picture type & ordering */
if (!s->reordered_input_picture[0] && s->input_picture[0]) {
+ if (s->avctx->frame_skip_threshold || s->avctx->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 te gop check above is +-1 correct
+ av_frame_unref(s->input_picture[0]->f);
+
+ 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];
@@ -1258,19 +1420,6 @@ static int select_input_picture(MpegEncContext *s)
} else {
int b_frames;
- if (s->avctx->frame_skip_threshold || s->avctx->frame_skip_factor) {
- if (s->picture_in_gop_number < s->gop_size &&
- skip_check(s, s->input_picture[0], s->next_picture_ptr)) {
- // FIXME check that te gop check above is +-1 correct
- av_frame_unref(s->input_picture[0]->f);
-
- emms_c();
- ff_vbv_update(s, 0);
-
- goto no_output_pic;
- }
- }
-
if (s->avctx->flags & CODEC_FLAG_PASS2) {
for (i = 0; i < s->max_b_frames + 1; i++) {
int pict_num = s->input_picture[0]->f->display_picture_number + i;
@@ -1419,25 +1568,26 @@ no_output_pic:
static void frame_end(MpegEncContext *s)
{
- int i;
-
if (s->unrestricted_mv &&
s->current_picture.reference &&
!s->intra_only) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
int hshift = desc->log2_chroma_w;
int vshift = desc->log2_chroma_h;
- s->mpvencdsp.draw_edges(s->current_picture.f->data[0], s->linesize,
+ s->mpvencdsp.draw_edges(s->current_picture.f->data[0],
+ s->current_picture.f->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->uvlinesize,
+ s->mpvencdsp.draw_edges(s->current_picture.f->data[1],
+ s->current_picture.f->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->uvlinesize,
+ s->mpvencdsp.draw_edges(s->current_picture.f->data[2],
+ s->current_picture.f->linesize[2],
s->h_edge_pos >> hshift,
s->v_edge_pos >> vshift,
EDGE_WIDTH >> hshift,
@@ -1452,14 +1602,6 @@ static void frame_end(MpegEncContext *s)
if (s->pict_type!= AV_PICTURE_TYPE_B)
s->last_non_b_pict_type = s->pict_type;
- if (s->encoding) {
- /* release non-reference frames */
- for (i = 0; i < MAX_PICTURE_COUNT; i++) {
- if (!s->picture[i].reference)
- ff_mpeg_unref_picture(s->avctx, &s->picture[i]);
- }
- }
-
s->avctx->coded_frame = s->current_picture_ptr->f;
}
@@ -1550,7 +1692,7 @@ static int frame_start(MpegEncContext *s)
}
if (s->dct_error_sum) {
- assert(s->avctx->noise_reduction && s->encoding);
+ av_assert2(s->avctx->noise_reduction && s->encoding);
update_noise_reduction(s);
}
@@ -1575,8 +1717,11 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
/* output? */
if (s->new_picture.f->data[0]) {
- if (!pkt->data &&
- (ret = ff_alloc_packet(pkt, s->mb_width*s->mb_height*MAX_MB_BYTES)) < 0)
+ int growing_buffer = context_count == 1 && !pkt->data && !s->data_partitioning;
+ int pkt_size = growing_buffer ? FFMAX(s->mb_width*s->mb_height*64+10000, avctx->internal->byte_buffer_size) - FF_INPUT_BUFFER_PADDING_SIZE
+ :
+ s->mb_width*s->mb_height*(MAX_MB_BYTES+100)+10000;
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size)) < 0)
return ret;
if (s->mb_info) {
s->mb_info_ptr = av_packet_new_side_data(pkt,
@@ -1601,7 +1746,13 @@ int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt,
if (ret < 0)
return ret;
vbv_retry:
- if (encode_picture(s, s->picture_number) < 0)
+ ret = encode_picture(s, s->picture_number);
+ if (growing_buffer) {
+ av_assert0(s->pb.buf == avctx->internal->byte_buffer);
+ pkt->data = s->pb.buf;
+ pkt->size = avctx->internal->byte_buffer_size;
+ }
+ if (ret < 0)
return -1;
avctx->header_bits = s->header_bits;
@@ -1621,7 +1772,7 @@ vbv_retry:
if (avctx->rc_buffer_size) {
RateControlContext *rcc = &s->rc_context;
- int max_size = rcc->buffer_index * avctx->rc_max_available_vbv_use;
+ int max_size = FFMAX(rcc->buffer_index * avctx->rc_max_available_vbv_use, rcc->buffer_index - 500);
if (put_bits_count(&s->pb) > max_size &&
s->lambda < s->lmax) {
@@ -1651,17 +1802,20 @@ vbv_retry:
PutBitContext *pb = &s->thread_context[i]->pb;
init_put_bits(pb, pb->buf, pb->buf_end - pb->buf);
}
+ av_log(s->avctx, AV_LOG_VERBOSE, "reencoding frame due to VBV\n");
goto vbv_retry;
}
- assert(s->avctx->rc_max_rate);
+ av_assert0(s->avctx->rc_max_rate);
}
if (s->avctx->flags & CODEC_FLAG_PASS1)
ff_write_pass1_stats(s);
for (i = 0; i < 4; i++) {
- s->current_picture_ptr->f->error[i] = s->current_picture.f->error[i];
+ s->current_picture_ptr->f->error[i] =
+ s->current_picture.f->error[i] =
+ s->current_picture.error[i];
avctx->error[i] += s->current_picture_ptr->f->error[i];
}
@@ -1673,6 +1827,7 @@ vbv_retry:
s->frame_bits = put_bits_count(&s->pb);
stuffing_count = ff_vbv_update(s, s->frame_bits);
+ s->stuffing_bits = 8*stuffing_count;
if (stuffing_count) {
if (s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb) >> 3) <
stuffing_count + 50) {
@@ -1727,7 +1882,7 @@ vbv_retry:
vbv_delay = FFMAX(vbv_delay, min_delay);
- assert(vbv_delay < 0xFFFF);
+ av_assert0(vbv_delay < 0xFFFF);
s->vbv_delay_ptr[0] &= 0xF8;
s->vbv_delay_ptr[0] |= vbv_delay >> 13;
@@ -1755,7 +1910,14 @@ vbv_retry:
} else {
s->frame_bits = 0;
}
- assert((s->frame_bits & 7) == 0);
+
+ /* release non-reference frames */
+ for (i = 0; i < MAX_PICTURE_COUNT; i++) {
+ if (!s->picture[i].reference)
+ ff_mpeg_unref_picture(s->avctx, &s->picture[i]);
+ }
+
+ av_assert1((s->frame_bits & 7) == 0);
pkt->size = s->frame_bits / 8;
*got_packet = !!pkt->size;
@@ -1879,15 +2041,17 @@ static void get_visual_weight(int16_t *weight, uint8_t *ptr, int stride)
static av_always_inline void encode_mb_internal(MpegEncContext *s,
int motion_x, int motion_y,
int mb_block_height,
+ int mb_block_width,
int mb_block_count)
{
- int16_t weight[8][64];
- int16_t orig[8][64];
+ int16_t weight[12][64];
+ int16_t orig[12][64];
const int mb_x = s->mb_x;
const int mb_y = s->mb_y;
int i;
- int skip_dct[8];
+ int skip_dct[12];
int dct_offset = s->linesize * 8; // default for progressive frames
+ int uv_dct_offset = s->uvlinesize * 8;
uint8_t *ptr_y, *ptr_cb, *ptr_cr;
ptrdiff_t wrap_y, wrap_c;
@@ -1929,27 +2093,31 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
ptr_y = s->new_picture.f->data[0] +
(mb_y * 16 * wrap_y) + mb_x * 16;
ptr_cb = s->new_picture.f->data[1] +
- (mb_y * mb_block_height * wrap_c) + mb_x * 8;
+ (mb_y * mb_block_height * wrap_c) + mb_x * mb_block_width;
ptr_cr = s->new_picture.f->data[2] +
- (mb_y * mb_block_height * wrap_c) + mb_x * 8;
+ (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) {
- uint8_t *ebuf = s->edge_emu_buffer + 32;
+ if((mb_x * 16 + 16 > s->width || mb_y * 16 + 16 > s->height) && s->codec_id != AV_CODEC_ID_AMV){
+ uint8_t *ebuf = s->edge_emu_buffer + 36 * wrap_y;
+ int cw = (s->width + s->chroma_x_shift) >> s->chroma_x_shift;
+ int ch = (s->height + s->chroma_y_shift) >> s->chroma_y_shift;
s->vdsp.emulated_edge_mc(ebuf, ptr_y,
wrap_y, wrap_y,
16, 16, mb_x * 16, mb_y * 16,
s->width, s->height);
ptr_y = ebuf;
- s->vdsp.emulated_edge_mc(ebuf + 18 * wrap_y, ptr_cb,
+ s->vdsp.emulated_edge_mc(ebuf + 16 * wrap_y, ptr_cb,
wrap_c, wrap_c,
- 8, mb_block_height, mb_x * 8, mb_y * 8,
- s->width >> 1, s->height >> 1);
- ptr_cb = ebuf + 18 * wrap_y;
- s->vdsp.emulated_edge_mc(ebuf + 18 * wrap_y + 8, ptr_cr,
+ mb_block_width, mb_block_height,
+ mb_x * mb_block_width, mb_y * mb_block_height,
+ cw, ch);
+ ptr_cb = ebuf + 16 * wrap_y;
+ s->vdsp.emulated_edge_mc(ebuf + 16 * wrap_y + 16, ptr_cr,
wrap_c, wrap_c,
- 8, mb_block_height, mb_x * 8, mb_y * 8,
- s->width >> 1, s->height >> 1);
- ptr_cr = ebuf + 18 * wrap_y + 8;
+ mb_block_width, mb_block_height,
+ mb_x * mb_block_width, mb_y * mb_block_height,
+ cw, ch);
+ ptr_cr = ebuf + 16 * wrap_y + 16;
}
if (s->mb_intra) {
@@ -1970,8 +2138,10 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
s->interlaced_dct = 1;
dct_offset = wrap_y;
+ uv_dct_offset = wrap_c;
wrap_y <<= 1;
- if (s->chroma_format == CHROMA_422)
+ if (s->chroma_format == CHROMA_422 ||
+ s->chroma_format == CHROMA_444)
wrap_c <<= 1;
}
}
@@ -1988,11 +2158,16 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
} else {
s->pdsp.get_pixels(s->block[4], ptr_cb, wrap_c);
s->pdsp.get_pixels(s->block[5], ptr_cr, wrap_c);
- if (!s->chroma_y_shift) { /* 422 */
- s->pdsp.get_pixels(s->block[6],
- ptr_cb + (dct_offset >> 1), wrap_c);
- s->pdsp.get_pixels(s->block[7],
- ptr_cr + (dct_offset >> 1), wrap_c);
+ if (!s->chroma_y_shift && s->chroma_x_shift) { /* 422 */
+ s->pdsp.get_pixels(s->block[6], ptr_cb + uv_dct_offset, wrap_c);
+ s->pdsp.get_pixels(s->block[7], ptr_cr + uv_dct_offset, wrap_c);
+ } else if (!s->chroma_y_shift && !s->chroma_x_shift) { /* 444 */
+ s->pdsp.get_pixels(s->block[ 6], ptr_cb + 8, wrap_c);
+ s->pdsp.get_pixels(s->block[ 7], ptr_cr + 8, wrap_c);
+ s->pdsp.get_pixels(s->block[ 8], ptr_cb + uv_dct_offset, wrap_c);
+ s->pdsp.get_pixels(s->block[ 9], ptr_cr + uv_dct_offset, wrap_c);
+ s->pdsp.get_pixels(s->block[10], ptr_cb + uv_dct_offset + 8, wrap_c);
+ s->pdsp.get_pixels(s->block[11], ptr_cr + uv_dct_offset + 8, wrap_c);
}
}
} else {
@@ -2048,6 +2223,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
s->interlaced_dct = 1;
dct_offset = wrap_y;
+ uv_dct_offset = wrap_c;
wrap_y <<= 1;
if (s->chroma_format == CHROMA_422)
wrap_c <<= 1;
@@ -2069,10 +2245,10 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
s->pdsp.diff_pixels(s->block[4], ptr_cb, dest_cb, wrap_c);
s->pdsp.diff_pixels(s->block[5], ptr_cr, dest_cr, wrap_c);
if (!s->chroma_y_shift) { /* 422 */
- s->pdsp.diff_pixels(s->block[6], ptr_cb + (dct_offset >> 1),
- dest_cb + (dct_offset >> 1), wrap_c);
- s->pdsp.diff_pixels(s->block[7], ptr_cr + (dct_offset >> 1),
- dest_cr + (dct_offset >> 1), wrap_c);
+ s->pdsp.diff_pixels(s->block[6], ptr_cb + uv_dct_offset,
+ dest_cb + uv_dct_offset, wrap_c);
+ s->pdsp.diff_pixels(s->block[7], ptr_cr + uv_dct_offset,
+ dest_cr + uv_dct_offset, wrap_c);
}
}
/* pre quantization */
@@ -2094,12 +2270,12 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
if (s->mecc.sad[1](NULL, ptr_cr, dest_cr, wrap_c, 8) < 20 * s->qscale)
skip_dct[5] = 1;
if (!s->chroma_y_shift) { /* 422 */
- if (s->mecc.sad[1](NULL, ptr_cb + (dct_offset >> 1),
- dest_cb + (dct_offset >> 1),
+ if (s->mecc.sad[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 + (dct_offset >> 1),
- dest_cr + (dct_offset >> 1),
+ if (s->mecc.sad[1](NULL, ptr_cr + uv_dct_offset,
+ dest_cr + uv_dct_offset,
wrap_c, 8) < 20 * s->qscale)
skip_dct[7] = 1;
}
@@ -2121,17 +2297,17 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
get_visual_weight(weight[5], ptr_cr , wrap_c);
if (!s->chroma_y_shift) { /* 422 */
if (!skip_dct[6])
- get_visual_weight(weight[6], ptr_cb + (dct_offset >> 1),
+ get_visual_weight(weight[6], ptr_cb + uv_dct_offset,
wrap_c);
if (!skip_dct[7])
- get_visual_weight(weight[7], ptr_cr + (dct_offset >> 1),
+ get_visual_weight(weight[7], ptr_cr + uv_dct_offset,
wrap_c);
}
memcpy(orig[0], s->block[0], sizeof(int16_t) * 64 * mb_block_count);
}
/* DCT & quantize */
- assert(s->out_format != FMT_MJPEG || s->qscale == 8);
+ av_assert2(s->out_format != FMT_MJPEG || s->qscale == 8);
{
for (i = 0; i < mb_block_count; i++) {
if (!skip_dct[i]) {
@@ -2177,6 +2353,12 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
s->block_last_index[5] = 0;
s->block[4][0] =
s->block[5][0] = (1024 + s->c_dc_scale / 2) / s->c_dc_scale;
+ if (!s->chroma_y_shift) { /* 422 / 444 */
+ for (i=6; i<12; i++) {
+ s->block_last_index[i] = 0;
+ s->block[i][0] = s->block[4][0];
+ }
+ }
}
// non c quantize code returns incorrect block_last_index FIXME
@@ -2227,18 +2409,20 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s,
ff_h263_encode_mb(s, s->block, motion_x, motion_y);
break;
case AV_CODEC_ID_MJPEG:
+ case AV_CODEC_ID_AMV:
if (CONFIG_MJPEG_ENCODER)
ff_mjpeg_encode_mb(s, s->block);
break;
default:
- assert(0);
+ av_assert1(0);
}
}
static av_always_inline 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, 6);
- else encode_mb_internal(s, motion_x, motion_y, 16, 8);
+ if (s->chroma_format == CHROMA_420) encode_mb_internal(s, motion_x, motion_y, 8, 8, 6);
+ else if (s->chroma_format == CHROMA_422) encode_mb_internal(s, motion_x, motion_y, 16, 8, 8);
+ else encode_mb_internal(s, motion_x, motion_y, 16, 16, 12);
}
static inline void copy_context_before_encode(MpegEncContext *d, MpegEncContext *s, int type){
@@ -2329,7 +2513,7 @@ static inline void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegE
s->dest[0] = s->rd_scratchpad;
s->dest[1] = s->rd_scratchpad + 16*s->linesize;
s->dest[2] = s->rd_scratchpad + 16*s->linesize + 8;
- assert(s->linesize >= 32); //FIXME
+ av_assert0(s->linesize >= 32); //FIXME
}
encode_mb(s, motion_x, motion_y);
@@ -2375,7 +2559,7 @@ static int sse(MpegEncContext *s, uint8_t *src1, uint8_t *src2, int w, int h, in
}
}
- assert(acc>=0);
+ av_assert2(acc>=0);
return acc;
}
@@ -2425,6 +2609,8 @@ static int pre_estimate_motion_thread(AVCodecContext *c, void *arg){
static int estimate_motion_thread(AVCodecContext *c, void *arg){
MpegEncContext *s= *(void**)arg;
+ ff_check_alignment();
+
s->me.dia_size= s->avctx->dia_size;
s->first_slice_line=1;
for(s->mb_y= s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) {
@@ -2451,6 +2637,8 @@ static int mb_var_thread(AVCodecContext *c, void *arg){
MpegEncContext *s= *(void**)arg;
int mb_x, mb_y;
+ ff_check_alignment();
+
for(mb_y=s->start_mb_y; mb_y < s->end_mb_y; mb_y++) {
for(mb_x=0; mb_x < s->mb_width; mb_x++) {
int xx = mb_x * 16;
@@ -2478,7 +2666,7 @@ static void write_slice_end(MpegEncContext *s){
ff_mpeg4_stuffing(&s->pb);
}else if(CONFIG_MJPEG_ENCODER && s->out_format == FMT_MJPEG){
- ff_mjpeg_encode_stuffing(&s->pb);
+ ff_mjpeg_encode_stuffing(s);
}
avpriv_align_put_bits(&s->pb);
@@ -2531,6 +2719,35 @@ static void update_mb_info(MpegEncContext *s, int startcode)
write_mb_info(s);
}
+int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase)
+{
+ if ( s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < threshold
+ && s->slice_context_count == 1
+ && s->pb.buf == s->avctx->internal->byte_buffer) {
+ int lastgob_pos = s->ptr_lastgob - s->pb.buf;
+ int vbv_pos = s->vbv_delay_ptr - s->pb.buf;
+
+ uint8_t *new_buffer = NULL;
+ int new_buffer_size = 0;
+
+ av_fast_padded_malloc(&new_buffer, &new_buffer_size,
+ s->avctx->internal->byte_buffer_size + size_increase);
+ if (!new_buffer)
+ return AVERROR(ENOMEM);
+
+ memcpy(new_buffer, s->avctx->internal->byte_buffer, s->avctx->internal->byte_buffer_size);
+ av_free(s->avctx->internal->byte_buffer);
+ s->avctx->internal->byte_buffer = new_buffer;
+ s->avctx->internal->byte_buffer_size = new_buffer_size;
+ rebase_put_bits(&s->pb, new_buffer, new_buffer_size);
+ s->ptr_lastgob = s->pb.buf + lastgob_pos;
+ s->vbv_delay_ptr = s->pb.buf + vbv_pos;
+ }
+ if (s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < threshold)
+ return AVERROR(EINVAL);
+ return 0;
+}
+
static int encode_thread(AVCodecContext *c, void *arg){
MpegEncContext *s= *(void**)arg;
int mb_x, mb_y, pdif = 0;
@@ -2542,6 +2759,8 @@ static int encode_thread(AVCodecContext *c, void *arg){
uint8_t bit_buf_tex[2][MAX_MB_BYTES];
PutBitContext pb[2], pb2[2], tex_pb[2];
+ ff_check_alignment();
+
for(i=0; i<2; i++){
init_put_bits(&pb [i], bit_buf [i], MAX_MB_BYTES);
init_put_bits(&pb2 [i], bit_buf2 [i], MAX_MB_BYTES);
@@ -2563,7 +2782,12 @@ static int encode_thread(AVCodecContext *c, void *arg){
/* note: quant matrix value (8) is implied here */
s->last_dc[i] = 128 << s->intra_dc_precision;
- s->current_picture.f->error[i] = 0;
+ s->current_picture.error[i] = 0;
+ }
+ if(s->codec_id==AV_CODEC_ID_AMV){
+ s->last_dc[0] = 128*8/13;
+ s->last_dc[1] = 128*8/14;
+ s->last_dc[2] = 128*8/14;
}
s->mb_skip_run = 0;
memset(s->last_mv, 0, sizeof(s->last_mv));
@@ -2600,7 +2824,10 @@ static int encode_thread(AVCodecContext *c, void *arg){
// int d;
int dmin= INT_MAX;
int dir;
+ int size_increase = s->avctx->internal->byte_buffer_size/4
+ + s->mb_width*MAX_MB_BYTES;
+ ff_mpv_reallocate_putbitbuffer(s, MAX_MB_BYTES, size_increase);
if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < MAX_MB_BYTES){
av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
return -1;
@@ -2608,7 +2835,7 @@ static int encode_thread(AVCodecContext *c, void *arg){
if(s->data_partitioning){
if( s->pb2 .buf_end - s->pb2 .buf - (put_bits_count(&s-> pb2)>>3) < MAX_MB_BYTES
|| s->tex_pb.buf_end - s->tex_pb.buf - (put_bits_count(&s->tex_pb )>>3) < MAX_MB_BYTES){
- av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ av_log(s->avctx, AV_LOG_ERROR, "encoded partitioned frame too large\n");
return -1;
}
}
@@ -2644,6 +2871,9 @@ static int encode_thread(AVCodecContext *c, void *arg){
case AV_CODEC_ID_MPEG1VIDEO:
if(s->mb_skip_run) is_gob_start=0;
break;
+ case AV_CODEC_ID_MJPEG:
+ if(s->mb_x==0 && s->mb_y!=0) is_gob_start=1;
+ break;
}
if(is_gob_start){
@@ -2655,7 +2885,7 @@ static int encode_thread(AVCodecContext *c, void *arg){
}
}
- assert((put_bits_count(&s->pb)&7) == 0);
+ av_assert2((put_bits_count(&s->pb)&7) == 0);
current_packet_size= put_bits_ptr(&s->pb) - s->ptr_lastgob;
if (s->error_rate && s->resync_mb_x + s->resync_mb_y > 0) {
@@ -2862,8 +3092,9 @@ static int encode_thread(AVCodecContext *c, void *arg){
int16_t ac[6][16];
const int mvdir= (best_s.mv_dir&MV_DIR_BACKWARD) ? 1 : 0;
static const int dquant_tab[4]={-1,1,-2,2};
+ int storecoefs = s->mb_intra && s->dc_val[0];
- assert(backup_s.dquant == 0);
+ av_assert2(backup_s.dquant == 0);
//FIXME intra
s->mv_dir= best_s.mv_dir;
@@ -2881,7 +3112,7 @@ static int encode_thread(AVCodecContext *c, void *arg){
if(qp < s->avctx->qmin || qp > s->avctx->qmax)
continue;
backup_s.dquant= dquant;
- if(s->mb_intra && s->dc_val[0]){
+ if(storecoefs){
for(i=0; i<6; i++){
dc[i]= s->dc_val[0][ s->block_index[i] ];
memcpy(ac[i], s->ac_val[0][s->block_index[i]], sizeof(int16_t)*16);
@@ -2891,7 +3122,7 @@ static int encode_thread(AVCodecContext *c, void *arg){
encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_INTER /* wrong but unused */, pb, pb2, tex_pb,
&dmin, &next_block, s->mv[mvdir][0][0], s->mv[mvdir][0][1]);
if(best_s.qscale != qp){
- if(s->mb_intra && s->dc_val[0]){
+ if(storecoefs){
for(i=0; i<6; i++){
s->dc_val[0][ s->block_index[i] ]= dc[i];
memcpy(s->ac_val[0][s->block_index[i]], ac[i], sizeof(int16_t)*16);
@@ -3121,13 +3352,13 @@ static int encode_thread(AVCodecContext *c, void *arg){
if(s->mb_x*16 + 16 > s->width ) w= s->width - s->mb_x*16;
if(s->mb_y*16 + 16 > s->height) h= s->height- s->mb_y*16;
- s->current_picture.f->error[0] += sse(
+ s->current_picture.error[0] += sse(
s, s->new_picture.f->data[0] + s->mb_x*16 + s->mb_y*s->linesize*16,
s->dest[0], w, h, s->linesize);
- s->current_picture.f->error[1] += sse(
+ s->current_picture.error[1] += sse(
s, s->new_picture.f->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->current_picture.f->error[2] += sse(
+ s->current_picture.error[2] += sse(
s, s->new_picture.f->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);
}
@@ -3180,9 +3411,9 @@ static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src)
MERGE(misc_bits);
MERGE(er.error_count);
MERGE(padding_bug_score);
- MERGE(current_picture.f->error[0]);
- MERGE(current_picture.f->error[1]);
- MERGE(current_picture.f->error[2]);
+ MERGE(current_picture.error[0]);
+ MERGE(current_picture.error[1]);
+ MERGE(current_picture.error[2]);
if(dst->avctx->noise_reduction){
for(i=0; i<64; i++){
@@ -3235,7 +3466,7 @@ static int estimate_qp(MpegEncContext *s, int dry_run){
/* must be called before writing the header */
static void set_frame_distances(MpegEncContext * s){
- assert(s->current_picture_ptr->f->pts != AV_NOPTS_VALUE);
+ av_assert1(s->current_picture_ptr->f->pts != AV_NOPTS_VALUE);
s->time = s->current_picture_ptr->f->pts * s->avctx->time_base.num;
if(s->pict_type==AV_PICTURE_TYPE_B){
@@ -3291,6 +3522,13 @@ static int encode_picture(MpegEncContext *s, int picture_number)
update_qscale(s);
}
+ if(s->codec_id != AV_CODEC_ID_AMV && s->codec_id != AV_CODEC_ID_MJPEG){
+ if(s->q_chroma_intra_matrix != s->q_intra_matrix ) av_freep(&s->q_chroma_intra_matrix);
+ if(s->q_chroma_intra_matrix16 != s->q_intra_matrix16) av_freep(&s->q_chroma_intra_matrix16);
+ s->q_chroma_intra_matrix = s->q_intra_matrix;
+ s->q_chroma_intra_matrix16 = s->q_intra_matrix16;
+ }
+
s->mb_intra=0; //for the rate distortion & bit compare functions
for(i=1; i<context_count; i++){
ret = ff_update_duplicate_context(s->thread_context[i], s);
@@ -3333,7 +3571,9 @@ static int encode_picture(MpegEncContext *s, int picture_number)
s->pict_type= AV_PICTURE_TYPE_I;
for(i=0; i<s->mb_stride*s->mb_height; i++)
s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA;
- ff_dlog(s, "Scene change detected, encoding as I Frame %d %d\n",
+ if(s->msmpeg4_version >= 3)
+ s->no_rounding=1;
+ ff_dlog(s, "Scene change detected, encoding as I Frame %"PRId64" %"PRId64"\n",
s->current_picture.mb_var_sum, s->current_picture.mc_mb_var_sum);
}
@@ -3400,17 +3640,50 @@ static int encode_picture(MpegEncContext *s, int picture_number)
s->qscale= 3; //reduce clipping problems
if (s->out_format == FMT_MJPEG) {
+ const uint16_t * luma_matrix = ff_mpeg1_default_intra_matrix;
+ const uint16_t *chroma_matrix = ff_mpeg1_default_intra_matrix;
+
+ if (s->avctx->intra_matrix) {
+ chroma_matrix =
+ luma_matrix = s->avctx->intra_matrix;
+ }
+ if (s->avctx->chroma_intra_matrix)
+ chroma_matrix = s->avctx->chroma_intra_matrix;
+
/* for mjpeg, we do include qscale in the matrix */
for(i=1;i<64;i++){
int j = s->idsp.idct_permutation[i];
- s->intra_matrix[j] = av_clip_uint8((ff_mpeg1_default_intra_matrix[i] * s->qscale) >> 3);
+ s->chroma_intra_matrix[j] = av_clip_uint8((chroma_matrix[i] * s->qscale) >> 3);
+ s-> intra_matrix[j] = av_clip_uint8(( luma_matrix[i] * s->qscale) >> 3);
}
s->y_dc_scale_table=
s->c_dc_scale_table= ff_mpeg2_dc_scale_table[s->intra_dc_precision];
+ s->chroma_intra_matrix[0] =
s->intra_matrix[0] = ff_mpeg2_dc_scale_table[s->intra_dc_precision][8];
ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16,
s->intra_matrix, s->intra_quant_bias, 8, 8, 1);
+ ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16,
+ s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1);
+ s->qscale= 8;
+ }
+ if(s->codec_id == AV_CODEC_ID_AMV){
+ static const uint8_t y[32]={13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13};
+ static const uint8_t c[32]={14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14};
+ for(i=1;i<64;i++){
+ int j= s->idsp.idct_permutation[ff_zigzag_direct[i]];
+
+ s->intra_matrix[j] = sp5x_quant_table[5*2+0][i];
+ s->chroma_intra_matrix[j] = sp5x_quant_table[5*2+1][i];
+ }
+ s->y_dc_scale_table= y;
+ s->c_dc_scale_table= c;
+ s->intra_matrix[0] = 13;
+ s->chroma_intra_matrix[0] = 14;
+ ff_convert_matrix(s, s->q_intra_matrix, s->q_intra_matrix16,
+ s->intra_matrix, s->intra_quant_bias, 8, 8, 1);
+ ff_convert_matrix(s, s->q_chroma_intra_matrix, s->q_chroma_intra_matrix16,
+ s->chroma_intra_matrix, s->intra_quant_bias, 8, 8, 1);
s->qscale= 8;
}
@@ -3423,12 +3696,13 @@ static int encode_picture(MpegEncContext *s, int picture_number)
if (s->current_picture.f->key_frame)
s->picture_in_gop_number=0;
+ s->mb_x = s->mb_y = 0;
s->last_bits= put_bits_count(&s->pb);
switch(s->out_format) {
case FMT_MJPEG:
if (CONFIG_MJPEG_ENCODER)
ff_mjpeg_encode_picture_header(s->avctx, &s->pb, &s->intra_scantable,
- s->intra_matrix);
+ s->intra_matrix, s->chroma_intra_matrix);
break;
case FMT_H261:
if (CONFIG_H261_ENCODER)
@@ -3458,7 +3732,7 @@ static int encode_picture(MpegEncContext *s, int picture_number)
ff_mpeg1_encode_picture_header(s, picture_number);
break;
default:
- assert(0);
+ av_assert0(0);
}
bits= put_bits_count(&s->pb);
s->header_bits= bits - s->last_bits;
@@ -3468,6 +3742,8 @@ static int encode_picture(MpegEncContext *s, int picture_number)
}
s->avctx->execute(s->avctx, encode_thread, &s->thread_context[0], NULL, context_count, sizeof(void*));
for(i=1; i<context_count; i++){
+ if (s->pb.buf_end == s->thread_context[i]->pb.buf)
+ set_put_bits_buffer_size(&s->pb, FFMIN(s->thread_context[i]->pb.buf_end - s->pb.buf, INT_MAX/8-32));
merge_context_after_encode(s, s->thread_context[i]);
}
emms_c();
@@ -3502,6 +3778,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
int16_t *block, int n,
int qscale, int *overflow){
const int *qmat;
+ const uint16_t *matrix;
const uint8_t *scantable= s->intra_scantable.scantable;
const uint8_t *perm_scantable= s->intra_scantable.permutated;
int max=0;
@@ -3549,15 +3826,23 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
block[0] = (block[0] + (q >> 1)) / q;
start_i = 1;
last_non_zero = 0;
- qmat = s->q_intra_matrix[qscale];
- if(s->mpeg_quant || s->out_format == FMT_MPEG1)
+ qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale];
+ matrix = n < 4 ? s->intra_matrix : s->chroma_intra_matrix;
+ if(s->mpeg_quant || s->out_format == FMT_MPEG1 || s->out_format == FMT_MJPEG)
bias= 1<<(QMAT_SHIFT-1);
- length = s->intra_ac_vlc_length;
- last_length= s->intra_ac_vlc_last_length;
+
+ if (n > 3 && s->intra_chroma_ac_vlc_length) {
+ length = s->intra_chroma_ac_vlc_length;
+ last_length= s->intra_chroma_ac_vlc_last_length;
+ } else {
+ length = s->intra_ac_vlc_length;
+ last_length= s->intra_ac_vlc_last_length;
+ }
} else {
start_i = 0;
last_non_zero = -1;
qmat = s->q_inter_matrix[qscale];
+ matrix = s->inter_matrix;
length = s->inter_ac_vlc_length;
last_length= s->inter_ac_vlc_last_length;
}
@@ -3595,7 +3880,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
// coeff[2][k]= -level+2;
}
coeff_count[i]= FFMIN(level, 2);
- assert(coeff_count[i]);
+ av_assert2(coeff_count[i]);
max |=level;
}else{
coeff[0][i]= (level>>31)|1;
@@ -3629,17 +3914,20 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
const int alevel= FFABS(level);
int unquant_coeff;
- assert(level);
+ av_assert2(level);
- if(s->out_format == FMT_H263){
+ if(s->out_format == FMT_H263 || s->out_format == FMT_H261){
unquant_coeff= alevel*qmul + qadd;
+ } else if(s->out_format == FMT_MJPEG) {
+ j = s->idsp.idct_permutation[scantable[i]];
+ unquant_coeff = alevel * matrix[j] * 8;
}else{ //MPEG1
j = s->idsp.idct_permutation[scantable[i]]; // FIXME: optimize
if(s->mb_intra){
- unquant_coeff = (int)( alevel * qscale * s->intra_matrix[j]) >> 3;
+ unquant_coeff = (int)( alevel * qscale * matrix[j]) >> 3;
unquant_coeff = (unquant_coeff - 1) | 1;
}else{
- unquant_coeff = ((( alevel << 1) + 1) * qscale * ((int) s->inter_matrix[j])) >> 4;
+ unquant_coeff = ((( alevel << 1) + 1) * qscale * ((int) matrix[j])) >> 4;
unquant_coeff = (unquant_coeff - 1) | 1;
}
unquant_coeff<<= 3;
@@ -3660,7 +3948,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
}
}
- if(s->out_format == FMT_H263){
+ if(s->out_format == FMT_H263 || s->out_format == FMT_H261){
for(j=survivor_count-1; j>=0; j--){
int run= i - survivor[j];
int score= distortion + last_length[UNI_AC_ENC_INDEX(run, level)]*lambda;
@@ -3686,7 +3974,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
}
}
- if(s->out_format == FMT_H263){
+ if(s->out_format == FMT_H263 || s->out_format == FMT_H261){
for(j=survivor_count-1; j>=0; j--){
int run= i - survivor[j];
int score= distortion + score_tab[i-run];
@@ -3719,7 +4007,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
survivor[ survivor_count++ ]= i+1;
}
- if(s->out_format != FMT_H263){
+ if(s->out_format != FMT_H263 && s->out_format != FMT_H261){
last_score= 256*256*256*120;
for(i= survivor[0]; i<=last_non_zero + 1; i++){
int score= score_tab[i];
@@ -3752,10 +4040,10 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
int alevel= FFABS(level);
int unquant_coeff, score, distortion;
- if(s->out_format == FMT_H263){
+ if(s->out_format == FMT_H263 || s->out_format == FMT_H261){
unquant_coeff= (alevel*qmul + qadd)>>3;
}else{ //MPEG1
- unquant_coeff = ((( alevel << 1) + 1) * qscale * ((int) s->inter_matrix[0])) >> 4;
+ unquant_coeff = ((( alevel << 1) + 1) * qscale * ((int) matrix[0])) >> 4;
unquant_coeff = (unquant_coeff - 1) | 1;
}
unquant_coeff = (unquant_coeff + 4) >> 3;
@@ -3778,7 +4066,7 @@ static int dct_quantize_trellis_c(MpegEncContext *s,
}
i= last_i;
- assert(last_level);
+ av_assert2(last_level);
block[ perm_scantable[last_non_zero] ]= last_level;
i -= last_run + 1;
@@ -3862,8 +4150,13 @@ static int messed_sign=0;
start_i = 1;
// if(s->mpeg_quant || s->out_format == FMT_MPEG1)
// bias= 1<<(QMAT_SHIFT-1);
- length = s->intra_ac_vlc_length;
- last_length= s->intra_ac_vlc_last_length;
+ if (n > 3 && s->intra_chroma_ac_vlc_length) {
+ length = s->intra_chroma_ac_vlc_length;
+ last_length= s->intra_chroma_ac_vlc_last_length;
+ } else {
+ length = s->intra_ac_vlc_length;
+ last_length= s->intra_ac_vlc_last_length;
+ }
} else {
dc= 0;
start_i = 0;
@@ -3894,8 +4187,8 @@ STOP_TIMER("memset rem[]")}
weight[i] = w;
// w=weight[i] = (63*qns + (w/2)) / w;
- assert(w>0);
- assert(w<(1<<6));
+ av_assert2(w>0);
+ av_assert2(w<(1<<6));
sum += w*w;
}
lambda= sum*(uint64_t)s->lambda2 >> (FF_LAMBDA_SHIFT - 6 + 6 + 6 + 6);
@@ -3961,7 +4254,7 @@ STOP_TIMER("dct")}
const int level= block[0];
int change, old_coeff;
- assert(s->mb_intra);
+ av_assert2(s->mb_intra);
old_coeff= q*level;
@@ -4005,7 +4298,7 @@ STOP_TIMER("dct")}
}else{
old_coeff=0;
run2--;
- assert(run2>=0 || i >= last_non_zero );
+ av_assert2(run2>=0 || i >= last_non_zero );
}
for(change=-1; change<=1; change+=2){
@@ -4033,7 +4326,7 @@ STOP_TIMER("dct")}
- last_length[UNI_AC_ENC_INDEX(run, level+64)];
}
}else{
- assert(FFABS(new_level)==1);
+ av_assert2(FFABS(new_level)==1);
if(analyze_gradient){
int g= d1[ scantable[i] ];
@@ -4066,7 +4359,7 @@ STOP_TIMER("dct")}
}
}else{
new_coeff=0;
- assert(FFABS(level)==1);
+ av_assert2(FFABS(level)==1);
if(i < last_non_zero){
int next_i= i + run2 + 1;
@@ -4095,7 +4388,7 @@ STOP_TIMER("dct")}
score *= lambda;
unquant_change= new_coeff - old_coeff;
- assert((score < 100*lambda && score > -100*lambda) || lambda==0);
+ av_assert2((score < 100*lambda && score > -100*lambda) || lambda==0);
score += s->mpvencdsp.try_8x8basis(rem, weight, basis[j],
unquant_change);
@@ -4127,7 +4420,7 @@ STOP_TIMER("iterative step")}
if(best_coeff > last_non_zero){
last_non_zero= best_coeff;
- assert(block[j]);
+ av_assert2(block[j]);
#ifdef REFINE_STATS
after_last++;
#endif
@@ -4155,7 +4448,7 @@ if(block[j]){
#ifdef REFINE_STATS
count++;
if(256*256*256*64 % count == 0){
- printf("after_last:%d to_zero:%d from_zero:%d raise:%d lower:%d sign:%d xyp:%d/%d/%d\n", after_last, to_zero, from_zero, raise, lower, messed_sign, s->mb_x, s->mb_y, s->picture_number);
+ av_log(s->avctx, AV_LOG_DEBUG, "after_last:%d to_zero:%d from_zero:%d raise:%d lower:%d sign:%d xyp:%d/%d/%d\n", after_last, to_zero, from_zero, raise, lower, messed_sign, s->mb_x, s->mb_y, s->picture_number);
}
#endif
run=0;
@@ -4218,7 +4511,7 @@ int ff_dct_quantize_c(MpegEncContext *s,
block[0] = (block[0] + (q >> 1)) / q;
start_i = 1;
last_non_zero = 0;
- qmat = s->q_intra_matrix[qscale];
+ qmat = n < 4 ? s->q_intra_matrix[qscale] : s->q_chroma_intra_matrix[qscale];
bias= s->intra_quant_bias<<(QMAT_SHIFT - QUANT_BIAS_SHIFT);
} else {
start_i = 0;
diff --git a/libavcodec/mpegvideo_motion.c b/libavcodec/mpegvideo_motion.c
index 95414d1230..0d75ffa9ce 100644
--- a/libavcodec/mpegvideo_motion.c
+++ b/libavcodec/mpegvideo_motion.c
@@ -4,25 +4,26 @@
*
* 4MV & hq & B-frame encoding stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/internal.h"
#include "avcodec.h"
#include "h261.h"
@@ -177,7 +178,7 @@ static void gmc_motion(MpegEncContext *s,
s->sprite_delta[0][0], s->sprite_delta[0][1],
s->sprite_delta[1][0], s->sprite_delta[1][1],
a + 1, (1 << (2 * a + 1)) - s->no_rounding,
- s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+ (s->h_edge_pos + 1) >> 1, (s->v_edge_pos + 1) >> 1);
ptr = ref_picture[2];
s->mdsp.gmc(dest_cr, ptr, uvlinesize, 8,
@@ -185,7 +186,7 @@ static void gmc_motion(MpegEncContext *s,
s->sprite_delta[0][0], s->sprite_delta[0][1],
s->sprite_delta[1][0], s->sprite_delta[1][1],
a + 1, (1 << (2 * a + 1)) - s->no_rounding,
- s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+ (s->h_edge_pos + 1) >> 1, (s->v_edge_pos + 1) >> 1);
}
static inline int hpel_motion(MpegEncContext *s,
@@ -209,18 +210,16 @@ static inline int hpel_motion(MpegEncContext *s,
dxy |= (motion_y & 1) << 1;
src += src_y * s->linesize + src_x;
- if (s->unrestricted_mv) {
- if ((unsigned)src_x > FFMAX(s->h_edge_pos - (motion_x & 1) - 8, 0) ||
- (unsigned)src_y > FFMAX(s->v_edge_pos - (motion_y & 1) - 8, 0)) {
+ if ((unsigned)src_x >= FFMAX(s->h_edge_pos - (motion_x & 1) - 7, 0) ||
+ (unsigned)src_y >= FFMAX(s->v_edge_pos - (motion_y & 1) - 7, 0)) {
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, src,
s->linesize, s->linesize,
9, 9,
- src_x, src_y, s->h_edge_pos,
- s->v_edge_pos);
+ src_x, src_y,
+ s->h_edge_pos, s->v_edge_pos);
src = s->edge_emu_buffer;
emu = 1;
}
- }
pix_op[dxy](dest, src, s->linesize, 8);
return emu;
}
@@ -307,8 +306,8 @@ void mpeg_motion_internal(MpegEncContext *s,
ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;
ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;
- if ((unsigned)src_x > FFMAX(s->h_edge_pos - (motion_x & 1) - 16, 0) ||
- (unsigned)src_y > FFMAX(v_edge_pos - (motion_y & 1) - h, 0)) {
+ if ((unsigned)src_x >= FFMAX(s->h_edge_pos - (motion_x & 1) - 15 , 0) ||
+ (unsigned)src_y >= FFMAX( v_edge_pos - (motion_y & 1) - h + 1, 0)) {
if (is_mpeg12 ||
s->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
s->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
@@ -317,26 +316,29 @@ void mpeg_motion_internal(MpegEncContext *s,
src_y);
return;
}
+ src_y = (unsigned)src_y << field_based;
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
s->linesize, s->linesize,
17, 17 + field_based,
- src_x, src_y << field_based,
+ src_x, src_y,
s->h_edge_pos, s->v_edge_pos);
ptr_y = s->edge_emu_buffer;
if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
- uint8_t *uvbuf = s->edge_emu_buffer + 18 * s->linesize;
- s->vdsp.emulated_edge_mc(uvbuf, ptr_cb,
+ uint8_t *ubuf = s->edge_emu_buffer + 18 * s->linesize;
+ uint8_t *vbuf = ubuf + 9 * s->uvlinesize;
+ uvsrc_y = (unsigned)uvsrc_y << field_based;
+ s->vdsp.emulated_edge_mc(ubuf, ptr_cb,
s->uvlinesize, s->uvlinesize,
9, 9 + field_based,
- uvsrc_x, uvsrc_y << field_based,
+ uvsrc_x, uvsrc_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
- s->vdsp.emulated_edge_mc(uvbuf + 16, ptr_cr,
+ s->vdsp.emulated_edge_mc(vbuf, ptr_cr,
s->uvlinesize, s->uvlinesize,
9, 9 + field_based,
- uvsrc_x, uvsrc_y << field_based,
+ uvsrc_x, uvsrc_y,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
- ptr_cb = uvbuf;
- ptr_cr = uvbuf + 16;
+ ptr_cb = ubuf;
+ ptr_cr = vbuf;
}
}
@@ -394,7 +396,7 @@ static void mpeg_motion_field(MpegEncContext *s, uint8_t *dest_y,
int motion_x, int motion_y, int h, int mb_y)
{
#if !CONFIG_SMALL
- if(s->out_format == FMT_MPEG1)
+ 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, mb_y);
@@ -469,7 +471,7 @@ static inline void obmc_motion(MpegEncContext *s,
int i;
uint8_t *ptr[5];
- assert(s->quarter_sample == 0);
+ av_assert2(s->quarter_sample == 0);
for (i = 0; i < 5; i++) {
if (i && mv[i][0] == mv[MID][0] && mv[i][1] == mv[MID][1]) {
@@ -536,8 +538,8 @@ static inline void qpel_motion(MpegEncContext *s,
ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x;
ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x;
- if ((unsigned)src_x > FFMAX(s->h_edge_pos - (motion_x & 3) - 16, 0) ||
- (unsigned)src_y > FFMAX(v_edge_pos - (motion_y & 3) - h, 0)) {
+ if ((unsigned)src_x >= FFMAX(s->h_edge_pos - (motion_x & 3) - 15 , 0) ||
+ (unsigned)src_y >= FFMAX( v_edge_pos - (motion_y & 3) - h + 1, 0)) {
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr_y,
s->linesize, s->linesize,
17, 17 + field_based,
@@ -545,19 +547,20 @@ static inline void qpel_motion(MpegEncContext *s,
s->h_edge_pos, s->v_edge_pos);
ptr_y = s->edge_emu_buffer;
if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
- uint8_t *uvbuf = s->edge_emu_buffer + 18 * s->linesize;
- s->vdsp.emulated_edge_mc(uvbuf, ptr_cb,
+ uint8_t *ubuf = s->edge_emu_buffer + 18 * s->linesize;
+ uint8_t *vbuf = ubuf + 9 * s->uvlinesize;
+ s->vdsp.emulated_edge_mc(ubuf, ptr_cb,
s->uvlinesize, s->uvlinesize,
9, 9 + field_based,
uvsrc_x, uvsrc_y << field_based,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
- s->vdsp.emulated_edge_mc(uvbuf + 16, ptr_cr,
+ s->vdsp.emulated_edge_mc(vbuf, ptr_cr,
s->uvlinesize, s->uvlinesize,
9, 9 + field_based,
uvsrc_x, uvsrc_y << field_based,
s->h_edge_pos >> 1, s->v_edge_pos >> 1);
- ptr_cb = uvbuf;
- ptr_cr = uvbuf + 16;
+ ptr_cb = ubuf;
+ ptr_cr = vbuf;
}
}
@@ -619,8 +622,8 @@ static void chroma_4mv_motion(MpegEncContext *s,
offset = src_y * s->uvlinesize + src_x;
ptr = ref_picture[1] + offset;
- if ((unsigned)src_x > FFMAX((s->h_edge_pos >> 1) - (dxy & 1) - 8, 0) ||
- (unsigned)src_y > FFMAX((s->v_edge_pos >> 1) - (dxy >> 1) - 8, 0)) {
+ if ((unsigned)src_x >= FFMAX((s->h_edge_pos >> 1) - (dxy & 1) - 7, 0) ||
+ (unsigned)src_y >= FFMAX((s->v_edge_pos >> 1) - (dxy >> 1) - 7, 0)) {
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
s->uvlinesize, s->uvlinesize,
9, 9, src_x, src_y,
@@ -671,7 +674,7 @@ static inline void apply_obmc(MpegEncContext *s,
const int mot_xy = mb_x * 2 + mb_y * 2 * mot_stride;
int mx, my, i;
- assert(!s->mb_skipped);
+ av_assert2(!s->mb_skipped);
AV_COPY32(mv_cache[1][1], cur_frame->motion_val[0][mot_xy]);
AV_COPY32(mv_cache[1][2], cur_frame->motion_val[0][mot_xy + 1]);
@@ -777,8 +780,8 @@ static inline void apply_8x8(MpegEncContext *s,
dxy &= ~12;
ptr = ref_picture[0] + (src_y * s->linesize) + (src_x);
- if ((unsigned)src_x > FFMAX(s->h_edge_pos - (motion_x & 3) - 8, 0) ||
- (unsigned)src_y > FFMAX(s->v_edge_pos - (motion_y & 3) - 8, 0)) {
+ if ((unsigned)src_x >= FFMAX(s->h_edge_pos - (motion_x & 3) - 7, 0) ||
+ (unsigned)src_y >= FFMAX(s->v_edge_pos - (motion_y & 3) - 7, 0)) {
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ptr,
s->linesize, s->linesize,
9, 9,
@@ -898,8 +901,8 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s,
s->mv[dir][1][0], s->mv[dir][1][1], 8, mb_y);
}
} else {
- if (s->picture_structure != s->field_select[dir][0] + 1 &&
- s->pict_type != AV_PICTURE_TYPE_B && !s->first_field) {
+ 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;
}
@@ -913,8 +916,8 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s,
for (i = 0; i < 2; i++) {
uint8_t **ref2picture;
- if (s->picture_structure == s->field_select[dir][i] + 1
- || s->pict_type == AV_PICTURE_TYPE_B || s->first_field) {
+ if ((s->picture_structure == s->field_select[dir][i] + 1
+ || s->pict_type == AV_PICTURE_TYPE_B || s->first_field) && ref_picture[0]) {
ref2picture = ref_picture;
} else {
ref2picture = s->current_picture_ptr->f->data;
@@ -943,6 +946,9 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s,
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,
@@ -961,7 +967,7 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s,
}
}
break;
- default: assert(0);
+ default: av_assert2(0);
}
}
diff --git a/libavcodec/mpegvideo_parser.c b/libavcodec/mpegvideo_parser.c
index 620083f3ea..cbea9b6cec 100644
--- a/libavcodec/mpegvideo_parser.c
+++ b/libavcodec/mpegvideo_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,6 +44,9 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
int top_field_first, repeat_first_field, progressive_frame;
int horiz_size_ext, vert_size_ext, bit_rate_ext;
int did_set_size=0;
+ int set_dim_ret = 0;
+ int bit_rate = 0;
+ int vbv_delay = 0;
//FIXME replace the crap with get_bits()
s->repeat_pict = 0;
@@ -55,6 +58,8 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
case PICTURE_START_CODE:
if (bytes_left >= 2) {
s->pict_type = (buf[1] >> 3) & 7;
+ if (bytes_left >= 4)
+ vbv_delay = ((buf[1] & 0x07) << 13) | (buf[2] << 5) | (buf[3] >> 3);
}
break;
case SEQ_START_CODE:
@@ -62,13 +67,14 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
pc->width = (buf[0] << 4) | (buf[1] >> 4);
pc->height = ((buf[1] & 0x0f) << 8) | buf[2];
if(!avctx->width || !avctx->height || !avctx->coded_width || !avctx->coded_height){
- ff_set_dimensions(avctx, pc->width, pc->height);
+ set_dim_ret = ff_set_dimensions(avctx, pc->width, pc->height);
did_set_size=1;
}
frame_rate_index = buf[3] & 0xf;
pc->frame_rate = avctx->framerate = ff_mpeg12_frame_rate_tab[frame_rate_index];
- avctx->bit_rate = ((buf[4]<<10) | (buf[5]<<2) | (buf[6]>>6))*400;
+ bit_rate = (buf[4]<<10) | (buf[5]<<2) | (buf[6]>>6);
avctx->codec_id = AV_CODEC_ID_MPEG1VIDEO;
+ avctx->ticks_per_frame = 1;
}
break;
case EXT_START_CODE:
@@ -85,14 +91,15 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
pc->progressive_sequence = buf[1] & (1 << 3);
avctx->has_b_frames= !(buf[5] >> 7);
- pc->width |=(horiz_size_ext << 12);
- pc->height |=( vert_size_ext << 12);
- avctx->bit_rate += (bit_rate_ext << 18) * 400;
+ pc->width = (pc->width & 0xFFF) | (horiz_size_ext << 12);
+ pc->height = (pc->height& 0xFFF) | ( vert_size_ext << 12);
+ bit_rate = (bit_rate&0x3FFFF) | (bit_rate_ext << 18);
if(did_set_size)
- ff_set_dimensions(avctx, pc->width, pc->height);
- avctx->framerate.num = pc->frame_rate.num * (frame_rate_ext_n + 1) * 2;
+ set_dim_ret = ff_set_dimensions(avctx, pc->width, pc->height);
+ avctx->framerate.num = pc->frame_rate.num * (frame_rate_ext_n + 1);
avctx->framerate.den = pc->frame_rate.den * (frame_rate_ext_d + 1);
avctx->codec_id = AV_CODEC_ID_MPEG2VIDEO;
+ avctx->ticks_per_frame = 2;
}
break;
case 0x8: /* picture coding extension */
@@ -138,9 +145,19 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s,
}
}
the_end: ;
+ if (set_dim_ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "Failed to set dimensions\n");
+
+ if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && bit_rate) {
+ avctx->rc_max_rate = 400*bit_rate;
+ }
+ if (bit_rate &&
+ ((avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && bit_rate != 0x3FFFF) || vbv_delay != 0xFFFF)) {
+ avctx->bit_rate = 400*bit_rate;
+ }
#if FF_API_AVCTX_TIMEBASE
if (avctx->framerate.num)
- avctx->time_base = av_inv_q(avctx->framerate);
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
#endif
}
@@ -170,7 +187,7 @@ static int mpegvideo_parse(AVCodecParserContext *s,
function should be negligible for uncorrupted streams */
mpegvideo_extract_headers(s, avctx, buf, buf_size);
ff_dlog(NULL, "pict_type=%d frame_rate=%0.3f repeat_pict=%d\n",
- s->pict_type, (double)avctx->time_base.den / avctx->time_base.num, s->repeat_pict);
+ s->pict_type, av_q2d(avctx->framerate), s->repeat_pict);
*poutbuf = buf;
*poutbuf_size = buf_size;
@@ -182,18 +199,28 @@ static int mpegvideo_split(AVCodecContext *avctx,
{
int i;
uint32_t state= -1;
+ int found=0;
for(i=0; i<buf_size; i++){
state= (state<<8) | buf[i];
- if(state != 0x1B3 && state != 0x1B5 && state < 0x200 && state >= 0x100)
+ if(state == 0x1B3){
+ found=1;
+ }else if(found && state != 0x1B5 && state < 0x200 && state >= 0x100)
return i-3;
}
return 0;
}
+static int mpegvideo_parse_init(AVCodecParserContext *s)
+{
+ s->pict_type = AV_PICTURE_TYPE_NONE; // first frame might be partial
+ return 0;
+}
+
AVCodecParser ff_mpegvideo_parser = {
.codec_ids = { AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO },
.priv_data_size = sizeof(struct MpvParseContext),
+ .parser_init = mpegvideo_parse_init,
.parser_parse = mpegvideo_parse,
.parser_close = ff_parse_close,
.split = mpegvideo_split,
diff --git a/libavcodec/mpegvideo_xvmc.c b/libavcodec/mpegvideo_xvmc.c
index 4628360a02..10475e0559 100644
--- a/libavcodec/mpegvideo_xvmc.c
+++ b/libavcodec/mpegvideo_xvmc.c
@@ -2,20 +2,20 @@
* XVideo Motion Compensation
* Copyright (c) 2003 Ivan Kalvachev
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,8 +33,6 @@
#include "xvmc_internal.h"
#include "version.h"
-#if FF_API_XVMC
-
/**
* Initialize the block field of the MpegEncContext pointer passed as
* parameter after making sure that the data is not corrupted.
@@ -50,6 +48,15 @@ void ff_xvmc_init_block(MpegEncContext *s)
s->block = (int16_t (*)[64])(render->data_blocks + render->next_free_data_block_num * 64);
}
+static void exchange_uv(MpegEncContext *s)
+{
+ int16_t (*tmp)[64];
+
+ tmp = s->pblocks[4];
+ s->pblocks[4] = s->pblocks[5];
+ s->pblocks[5] = tmp;
+}
+
/**
* Fill individual block pointers, so there are no gaps in the data_block array
* in case not all blocks in the macroblock are coded.
@@ -67,6 +74,9 @@ void ff_xvmc_pack_pblocks(MpegEncContext *s, int cbp)
s->pblocks[i] = NULL;
cbp += cbp;
}
+ if (s->swap_uv) {
+ exchange_uv(s);
+ }
}
/**
@@ -74,8 +84,9 @@ void ff_xvmc_pack_pblocks(MpegEncContext *s, int cbp)
* This function should be called for every new field and/or frame.
* It should be safe to call the function a few times for the same field.
*/
-int ff_xvmc_field_start(MpegEncContext *s, AVCodecContext *avctx)
+static int ff_xvmc_field_start(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size)
{
+ struct MpegEncContext *s = avctx->priv_data;
struct xvmc_pix_fmt *last, *next, *render = (struct xvmc_pix_fmt*)s->current_picture.f->data[2];
const int mb_block_count = 4 + (1 << s->chroma_format);
@@ -142,20 +153,22 @@ return -1;
* some leftover blocks, for example from error_resilience(), may remain.
* It should be safe to call the function a few times for the same field.
*/
-void ff_xvmc_field_end(MpegEncContext *s)
+static int ff_xvmc_field_end(AVCodecContext *avctx)
{
+ struct MpegEncContext *s = avctx->priv_data;
struct xvmc_pix_fmt *render = (struct xvmc_pix_fmt*)s->current_picture.f->data[2];
assert(render);
if (render->filled_mv_blocks_num > 0)
ff_mpeg_draw_horiz_band(s, 0, 0);
+ return 0;
}
/**
* Synthesize the data needed by XvMC to render one macroblock of data.
* Fill all relevant fields, if necessary do IDCT.
*/
-void ff_xvmc_decode_mb(MpegEncContext *s)
+static void ff_xvmc_decode_mb(struct MpegEncContext *s)
{
XvMCMacroBlock *mv_block;
struct xvmc_pix_fmt *render;
@@ -314,7 +327,7 @@ void ff_xvmc_decode_mb(MpegEncContext *s)
* slowdown. */
}
// copy blocks only if the codec doesn't support pblocks reordering
- if (s->avctx->xvmc_acceleration == 1) {
+ if (!s->pack_pblocks) {
memcpy(&render->data_blocks[render->next_free_data_block_num*64],
s->pblocks[i], sizeof(*s->pblocks[i]));
}
@@ -334,4 +347,30 @@ void ff_xvmc_decode_mb(MpegEncContext *s)
ff_mpeg_draw_horiz_band(s, 0, 0);
}
-#endif /* FF_API_XVMC */
+#if CONFIG_MPEG1_XVMC_HWACCEL
+AVHWAccel ff_mpeg1_xvmc_hwaccel = {
+ .name = "mpeg1_xvmc",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG1VIDEO,
+ .pix_fmt = AV_PIX_FMT_XVMC,
+ .start_frame = ff_xvmc_field_start,
+ .end_frame = ff_xvmc_field_end,
+ .decode_slice = NULL,
+ .decode_mb = ff_xvmc_decode_mb,
+ .priv_data_size = 0,
+};
+#endif
+
+#if CONFIG_MPEG2_XVMC_HWACCEL
+AVHWAccel ff_mpeg2_xvmc_hwaccel = {
+ .name = "mpeg2_xvmc",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MPEG2VIDEO,
+ .pix_fmt = AV_PIX_FMT_XVMC,
+ .start_frame = ff_xvmc_field_start,
+ .end_frame = ff_xvmc_field_end,
+ .decode_slice = NULL,
+ .decode_mb = ff_xvmc_decode_mb,
+ .priv_data_size = 0,
+};
+#endif
diff --git a/libavcodec/mpegvideodsp.c b/libavcodec/mpegvideodsp.c
index 915a844d6b..a58e45ad43 100644
--- a/libavcodec/mpegvideodsp.c
+++ b/libavcodec/mpegvideodsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegvideodsp.h b/libavcodec/mpegvideodsp.h
index b0f45db0bb..293e2548d3 100644
--- a/libavcodec/mpegvideodsp.h
+++ b/libavcodec/mpegvideodsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpegvideoencdsp.c b/libavcodec/mpegvideoencdsp.c
index 109bbe5da8..860c2d8574 100644
--- a/libavcodec/mpegvideoencdsp.c
+++ b/libavcodec/mpegvideoencdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,6 +21,7 @@
#include <string.h>
#include "config.h"
+#include "libavutil/avassert.h"
#include "libavutil/attributes.h"
#include "libavutil/imgutils.h"
#include "avcodec.h"
@@ -40,7 +41,7 @@ static int try_8x8basis_c(int16_t rem[64], int16_t weight[64],
(BASIS_SHIFT - RECON_SHIFT));
int w = weight[i];
b >>= RECON_SHIFT;
- assert(-512 < b && b < 512);
+ av_assert2(-512 < b && b < 512);
sum += (w * b) * (w * b) >> 4;
}
diff --git a/libavcodec/mpegvideoencdsp.h b/libavcodec/mpegvideoencdsp.h
index 91a292a296..e12f4c6a39 100644
--- a/libavcodec/mpegvideoencdsp.h
+++ b/libavcodec/mpegvideoencdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mpl2dec.c b/libavcodec/mpl2dec.c
new file mode 100644
index 0000000000..ca95dc8ae8
--- /dev/null
+++ b/libavcodec/mpl2dec.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * MPL2 subtitles decoder
+ *
+ * @see http://web.archive.org/web/20090328040233/http://napisy.ussbrowarek.org/mpl2-eng.html
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/bprint.h"
+
+static int mpl2_event_to_ass(AVBPrint *buf, const char *p)
+{
+ if (*p == ' ')
+ p++;
+
+ while (*p) {
+ int got_style = 0;
+
+ while (*p && strchr("/\\_", *p)) {
+ if (*p == '/') av_bprintf(buf, "{\\i1}");
+ else if (*p == '\\') av_bprintf(buf, "{\\b1}");
+ else if (*p == '_') av_bprintf(buf, "{\\u1}");
+ got_style = 1;
+ p++;
+ }
+
+ while (*p && *p != '|') {
+ if (*p != '\r' && *p != '\n')
+ av_bprint_chars(buf, *p, 1);
+ p++;
+ }
+
+ if (*p == '|') {
+ if (got_style)
+ av_bprintf(buf, "{\\r}");
+ av_bprintf(buf, "\\N");
+ p++;
+ }
+ }
+
+ return 0;
+}
+
+static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_sub_ptr, AVPacket *avpkt)
+{
+ int ret = 0;
+ AVBPrint buf;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
+ const int ts_duration = avpkt->duration != -1 ?
+ av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if (ptr && avpkt->size > 0 && *ptr && !mpl2_event_to_ass(&buf, ptr))
+ ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
+ av_bprint_finalize(&buf, NULL);
+ if (ret < 0)
+ return ret;
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_mpl2_decoder = {
+ .name = "mpl2",
+ .long_name = NULL_IF_CONFIG_SMALL("MPL2 subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_MPL2,
+ .decode = mpl2_decode_frame,
+ .init = ff_ass_subtitle_header_default,
+};
diff --git a/libavcodec/mqc.c b/libavcodec/mqc.c
index 01445817cf..f2d1e3b838 100644
--- a/libavcodec/mqc.c
+++ b/libavcodec/mqc.c
@@ -2,20 +2,20 @@
* MQ-coder encoder and decoder common functions
* Copyright (c) 2007 Kamil Nowosad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mqc.h b/libavcodec/mqc.h
index a65433e2b2..c0827bd526 100644
--- a/libavcodec/mqc.h
+++ b/libavcodec/mqc.h
@@ -2,20 +2,20 @@
* MQ-coder: structures, common and decoder functions
* Copyright (c) 2007 Kamil Nowosad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,6 +45,20 @@ typedef struct MqcState {
uint8_t cx_states[19];
} MqcState;
+/* encoder */
+
+/** initialize the encoder */
+void ff_mqc_initenc(MqcState *mqc, uint8_t *bp);
+
+/** code bit d with context cx */
+void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d);
+
+/** number of encoded bytes */
+int ff_mqc_length(MqcState *mqc);
+
+/** flush the encoder [returns number of bytes encoded] */
+int ff_mqc_flush(MqcState *mqc);
+
/* decoder */
/**
diff --git a/libavcodec/mqcdec.c b/libavcodec/mqcdec.c
index 889763ac66..362506992a 100644
--- a/libavcodec/mqcdec.c
+++ b/libavcodec/mqcdec.c
@@ -2,20 +2,20 @@
* MQ-coder decoder
* Copyright (c) 2007 Kamil Nowosad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mqcenc.c b/libavcodec/mqcenc.c
new file mode 100644
index 0000000000..97d352be44
--- /dev/null
+++ b/libavcodec/mqcenc.c
@@ -0,0 +1,119 @@
+/*
+ * MQ-coder encoder
+ * Copyright (c) 2007 Kamil Nowosad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * MQ-coder encoder
+ * @file
+ * @author Kamil Nowosad
+ */
+
+#include "mqc.h"
+
+static void byteout(MqcState *mqc)
+{
+retry:
+ if (*mqc->bp == 0xff){
+ mqc->bp++;
+ *mqc->bp = mqc->c >> 20;
+ mqc->c &= 0xfffff;
+ mqc->ct = 7;
+ } else if ((mqc->c & 0x8000000)){
+ (*mqc->bp)++;
+ mqc->c &= 0x7ffffff;
+ goto retry;
+ } else{
+ mqc->bp++;
+ *mqc->bp = mqc->c >> 19;
+ mqc->c &= 0x7ffff;
+ mqc->ct = 8;
+ }
+}
+
+static void renorme(MqcState *mqc)
+{
+ do{
+ mqc->a += mqc->a;
+ mqc->c += mqc->c;
+ if (!--mqc->ct)
+ byteout(mqc);
+ } while (!(mqc->a & 0x8000));
+}
+
+static void setbits(MqcState *mqc)
+{
+ int tmp = mqc->c + mqc->a;
+ mqc->c |= 0xffff;
+ if (mqc->c >= tmp)
+ mqc->c -= 0x8000;
+}
+
+void ff_mqc_initenc(MqcState *mqc, uint8_t *bp)
+{
+ ff_mqc_init_contexts(mqc);
+ mqc->a = 0x8000;
+ mqc->c = 0;
+ mqc->bp = bp-1;
+ mqc->bpstart = bp;
+ mqc->ct = 12 + (*mqc->bp == 0xff);
+}
+
+void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d)
+{
+ int qe;
+
+ qe = ff_mqc_qe[*cxstate];
+ mqc->a -= qe;
+ if ((*cxstate & 1) == d){
+ if (!(mqc->a & 0x8000)){
+ if (mqc->a < qe)
+ mqc->a = qe;
+ else
+ mqc->c += qe;
+ *cxstate = ff_mqc_nmps[*cxstate];
+ renorme(mqc);
+ } else
+ mqc->c += qe;
+ } else{
+ if (mqc->a < qe)
+ mqc->c += qe;
+ else
+ mqc->a = qe;
+ *cxstate = ff_mqc_nlps[*cxstate];
+ renorme(mqc);
+ }
+}
+
+int ff_mqc_length(MqcState *mqc)
+{
+ return mqc->bp - mqc->bpstart;
+}
+
+int ff_mqc_flush(MqcState *mqc)
+{
+ setbits(mqc);
+ mqc->c = mqc->c << mqc->ct;
+ byteout(mqc);
+ mqc->c = mqc->c << mqc->ct;
+ byteout(mqc);
+ if (*mqc->bp != 0xff)
+ mqc->bp++;
+ return mqc->bp - mqc->bpstart;
+}
diff --git a/libavcodec/msgsmdec.c b/libavcodec/msgsmdec.c
index be5062ad91..4c4ddb46f5 100644
--- a/libavcodec/msgsmdec.c
+++ b/libavcodec/msgsmdec.c
@@ -2,20 +2,20 @@
* gsm 06.10 decoder, Microsoft variant
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/msgsmdec.h b/libavcodec/msgsmdec.h
index adbda9a9d0..b2a1a627a5 100644
--- a/libavcodec/msgsmdec.h
+++ b/libavcodec/msgsmdec.h
@@ -2,20 +2,20 @@
* gsm 06.10 decoder, Microsoft variant
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/msmpeg4.c b/libavcodec/msmpeg4.c
index 95b5c93ea3..7300af316e 100644
--- a/libavcodec/msmpeg4.c
+++ b/libavcodec/msmpeg4.c
@@ -5,20 +5,20 @@
*
* msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,6 +36,7 @@
#include "mpeg4video.h"
#include "msmpeg4data.h"
#include "vc1data.h"
+#include "libavutil/imgutils.h"
/*
* You can also call this codec : MPEG4 with a twist !
@@ -51,6 +52,9 @@ static av_cold void init_h263_dc_for_msmpeg4(void)
{
int level, uni_code, uni_len;
+ if(ff_v2_dc_chroma_table[255 + 256][1])
+ return;
+
for(level=-256; level<256; level++){
int size, v, l;
/* find number of bits */
@@ -103,8 +107,6 @@ static av_cold void init_h263_dc_for_msmpeg4(void)
av_cold void ff_msmpeg4_common_init(MpegEncContext *s)
{
- static int initialized=0;
-
switch(s->msmpeg4_version){
case 1:
case 2:
@@ -143,11 +145,7 @@ av_cold void ff_msmpeg4_common_init(MpegEncContext *s)
}
//Note the default tables are set in common_init in mpegvideo.c
- if(!initialized){
- initialized=1;
-
- init_h263_dc_for_msmpeg4();
- }
+ init_h263_dc_for_msmpeg4();
}
/* predict coded block */
@@ -177,13 +175,13 @@ int ff_msmpeg4_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block
return pred;
}
-static int get_dc(uint8_t *src, int stride, int scale)
+static int get_dc(uint8_t *src, int stride, int scale, int block_size)
{
int y;
int sum=0;
- for(y=0; y<8; y++){
+ for(y=0; y<block_size; y++){
int x;
- for(x=0; x<8; x++){
+ for(x=0; x<block_size; x++){
sum+=src[x + y*stride];
}
}
@@ -229,13 +227,13 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n,
"addl %%eax, %2 \n\t"
"addl %%eax, %1 \n\t"
"addl %0, %%eax \n\t"
- "mull %4 \n\t"
+ "imull %4 \n\t"
"movl %%edx, %0 \n\t"
"movl %1, %%eax \n\t"
- "mull %4 \n\t"
+ "imull %4 \n\t"
"movl %%edx, %1 \n\t"
"movl %2, %%eax \n\t"
- "mull %4 \n\t"
+ "imull %4 \n\t"
"movl %%edx, %2 \n\t"
: "+b" (a), "+c" (b), "+D" (c)
: "g" (scale), "S" (ff_inverse[scale])
@@ -275,17 +273,18 @@ int ff_msmpeg4_pred_dc(MpegEncContext *s, int n,
*dir_ptr = 0;
}
}else{
+ 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) * 8* wrap ) + ((n & 1) + 2*s->mb_x) * 8;
+ dest= s->current_picture.f->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 * 8 * wrap) + s->mb_x * 8;
+ dest= s->current_picture.f->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-8, wrap, scale*8);
+ else a= get_dc(dest-bs, wrap, scale*8>>(2*s->avctx->lowres), bs);
if(s->mb_y==0) c= (1024 + (scale>>1))/scale;
- else c= get_dc(dest-8*wrap, wrap, scale*8);
+ else c= get_dc(dest-bs*wrap, wrap, scale*8>>(2*s->avctx->lowres), bs);
if (s->h263_aic_dir==0) {
pred= a;
diff --git a/libavcodec/msmpeg4.h b/libavcodec/msmpeg4.h
index 0a8ecd9e23..db77ce1d73 100644
--- a/libavcodec/msmpeg4.h
+++ b/libavcodec/msmpeg4.h
@@ -2,20 +2,20 @@
* MSMPEG4 backend for encoder and decoder
* copyright (c) 2007 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,10 +59,12 @@ int ff_wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]);
#define CONFIG_MSMPEG4_DECODER (CONFIG_MSMPEG4V1_DECODER || \
CONFIG_MSMPEG4V2_DECODER || \
CONFIG_MSMPEG4V3_DECODER || \
+ CONFIG_WMV1_DECODER || \
CONFIG_WMV2_DECODER || \
CONFIG_VC1_DECODER)
#define CONFIG_MSMPEG4_ENCODER (CONFIG_MSMPEG4V2_ENCODER || \
CONFIG_MSMPEG4V3_ENCODER || \
+ CONFIG_WMV1_ENCODER || \
CONFIG_WMV2_ENCODER)
#endif /* AVCODEC_MSMPEG4_H */
diff --git a/libavcodec/msmpeg4data.c b/libavcodec/msmpeg4data.c
index cf291afc80..8eb07e95cb 100644
--- a/libavcodec/msmpeg4data.c
+++ b/libavcodec/msmpeg4data.c
@@ -5,20 +5,20 @@
*
* msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/msmpeg4data.h b/libavcodec/msmpeg4data.h
index ca2dac14bd..24a10d9f2e 100644
--- a/libavcodec/msmpeg4data.h
+++ b/libavcodec/msmpeg4data.h
@@ -5,20 +5,20 @@
*
* msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/msmpeg4dec.c b/libavcodec/msmpeg4dec.c
index ea770f9d5c..c492fdbe48 100644
--- a/libavcodec/msmpeg4dec.c
+++ b/libavcodec/msmpeg4dec.c
@@ -1,24 +1,24 @@
/*
* MSMPEG4 backend for encoder and decoder
* Copyright (c) 2001 Fabrice Bellard
- * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2002-2013 Michael Niedermayer <michaelni@gmx.at>
*
* msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "mpegutils.h"
#include "mpegvideo.h"
#include "msmpeg4.h"
+#include "libavutil/imgutils.h"
#include "libavutil/x86/asm.h"
#include "h263.h"
#include "mpeg4video.h"
@@ -103,6 +104,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];
if (s->pict_type == AV_PICTURE_TYPE_P) {
if (s->use_skip_mb_code) {
@@ -116,6 +118,7 @@ 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;
return 0;
}
}
@@ -164,6 +167,7 @@ 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;
} else {
if(s->msmpeg4_version==2){
s->ac_pred = get_bits1(&s->gb);
@@ -173,6 +177,7 @@ static int msmpeg4v12_decode_mb(MpegEncContext *s, int16_t block[6][64])
cbp|= get_vlc2(&s->gb, ff_h263_cbpy_vlc.table, CBPY_VLC_BITS, 1)<<2; //FIXME check errors
if(s->pict_type==AV_PICTURE_TYPE_P) cbp^=0x3C;
}
+ *mb_type_ptr = MB_TYPE_INTRA;
}
s->bdsp.clear_blocks(s->block[0]);
@@ -282,18 +287,19 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64])
av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx)
{
MpegEncContext *s = avctx->priv_data;
- static int done = 0;
- int i;
+ static volatile int done = 0;
+ int i, ret;
MVTable *mv;
+ if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
+ return ret;
+
if (ff_h263_decode_init(avctx) < 0)
return -1;
ff_msmpeg4_common_init(s);
if (!done) {
- done = 1;
-
for(i=0;i<NB_RL_TABLES;i++) {
ff_init_rl(&ff_rl_table[i], ff_static_rl_table_store[i]);
}
@@ -363,6 +369,7 @@ av_cold int ff_msmpeg4_decode_init(AVCodecContext *avctx)
INIT_VLC_STATIC(&ff_inter_intra_vlc, INTER_INTRA_VLC_BITS, 4,
&ff_table_inter_intra[0][1], 2, 1,
&ff_table_inter_intra[0][0], 2, 1, 8);
+ done = 1;
}
switch(s->msmpeg4_version){
@@ -580,8 +587,11 @@ static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr)
} else {
level = get_vlc2(&s->gb, v2_dc_chroma_vlc.table, DC_VLC_BITS, 3);
}
- if (level < 0)
+ if (level < 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n");
+ *dir_ptr = 0;
return -1;
+ }
level-=256;
}else{ //FIXME optimize use unified tables & index
if (n < 4) {
@@ -591,6 +601,7 @@ static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr)
}
if (level < 0){
av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n");
+ *dir_ptr = 0;
return -1;
}
@@ -647,7 +658,6 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block,
if (level < 0){
av_log(s->avctx, AV_LOG_ERROR, "dc overflow- block: %d qscale: %d//\n", n, s->qscale);
if(s->inter_intra_pred) level=0;
- else return -1;
}
if (n < 4) {
rl = &ff_rl_table[s->rl_table_index];
@@ -834,9 +844,10 @@ int ff_msmpeg4_decode_block(MpegEncContext * s, int16_t * block,
if(i&(~63)){
const int left= get_bits_left(&s->gb);
if (((i + 192 == 64 && level / qmul == -1) ||
- !(s->avctx->err_recognition & AV_EF_BITSTREAM)) &&
+ !(s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT))) &&
left >= 0) {
av_log(s->avctx, AV_LOG_ERROR, "ignoring overflow at %d %d\n", s->mb_x, s->mb_y);
+ i = 63;
break;
}else{
av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y);
@@ -913,6 +924,7 @@ AVCodec ff_msmpeg4v1_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
@@ -929,6 +941,7 @@ AVCodec ff_msmpeg4v2_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
@@ -945,6 +958,7 @@ AVCodec ff_msmpeg4v3_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
@@ -961,6 +975,7 @@ AVCodec ff_wmv1_decoder = {
.close = ff_h263_decode_end,
.decode = ff_h263_decode_frame,
.capabilities = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
diff --git a/libavcodec/msmpeg4enc.c b/libavcodec/msmpeg4enc.c
index 072f6fcf7b..cd81c9486c 100644
--- a/libavcodec/msmpeg4enc.c
+++ b/libavcodec/msmpeg4enc.c
@@ -5,20 +5,20 @@
*
* msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,7 +34,6 @@
#include "libavutil/avutil.h"
#include "libavutil/mem.h"
#include "mpegvideo.h"
-#include "msmpeg4.h"
#include "h263.h"
#include "internal.h"
#include "mpeg4video.h"
@@ -160,8 +159,8 @@ av_cold int ff_msmpeg4_encode_init(MpegEncContext *s)
static void find_best_tables(MpegEncContext * s)
{
int i;
- int best =-1, best_size =9999999;
- int chroma_best=-1, best_chroma_size=9999999;
+ int best = 0, best_size = INT_MAX;
+ int chroma_best = 0, best_chroma_size = INT_MAX;
for(i=0; i<3; i++){
int level;
@@ -284,14 +283,15 @@ void ff_msmpeg4_encode_picture_header(MpegEncContext * s, int picture_number)
void ff_msmpeg4_encode_ext_header(MpegEncContext * s)
{
- put_bits(&s->pb, 5, s->avctx->time_base.den / s->avctx->time_base.num); //yes 29.97 -> 29
+ unsigned fps = s->avctx->time_base.den / s->avctx->time_base.num / FFMAX(s->avctx->ticks_per_frame, 1);
+ put_bits(&s->pb, 5, FFMIN(fps, 31)); //yes 29.97 -> 29
put_bits(&s->pb, 11, FFMIN(s->bit_rate/1024, 2047));
if(s->msmpeg4_version>=3)
put_bits(&s->pb, 1, s->flipflop_rounding);
else
- assert(s->flipflop_rounding==0);
+ av_assert0(s->flipflop_rounding==0);
}
void ff_msmpeg4_encode_motion(MpegEncContext * s,
@@ -504,7 +504,7 @@ void ff_msmpeg4_encode_mb(MpegEncContext * s,
static void msmpeg4_encode_dc(MpegEncContext * s, int level, int n, int *dir_ptr)
{
int sign, code;
- int pred, extquant;
+ int pred, av_uninit(extquant);
int extrabits = 0;
int16_t *dc_val;
diff --git a/libavcodec/msrle.c b/libavcodec/msrle.c
index 4b39c92061..260ad807ea 100644
--- a/libavcodec/msrle.c
+++ b/libavcodec/msrle.c
@@ -1,21 +1,21 @@
/*
* Microsoft RLE video decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,6 +35,7 @@
#include "avcodec.h"
#include "internal.h"
#include "msrledec.h"
+#include "libavutil/imgutils.h"
typedef struct MsrleContext {
AVCodecContext *avctx;
@@ -50,10 +51,14 @@ typedef struct MsrleContext {
static av_cold int msrle_decode_init(AVCodecContext *avctx)
{
MsrleContext *s = avctx->priv_data;
+ int i;
s->avctx = avctx;
switch (avctx->bits_per_coded_sample) {
+ case 1:
+ avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
+ break;
case 4:
case 8:
avctx->pix_fmt = AV_PIX_FMT_PAL8;
@@ -70,6 +75,10 @@ static av_cold int msrle_decode_init(AVCodecContext *avctx)
if (!s->frame)
return AVERROR(ENOMEM);
+ if (avctx->extradata_size >= 4)
+ for (i = 0; i < FFMIN(avctx->extradata_size, AVPALETTE_SIZE)/4; i++)
+ s->pal[i] = 0xFFU<<24 | AV_RL32(avctx->extradata+4*i);
+
return 0;
}
@@ -86,30 +95,30 @@ static int msrle_decode_frame(AVCodecContext *avctx,
s->buf = buf;
s->size = buf_size;
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
- if (avctx->bits_per_coded_sample <= 8) {
+ if (avctx->bits_per_coded_sample > 1 && avctx->bits_per_coded_sample <= 8) {
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
if (pal) {
s->frame->palette_has_changed = 1;
memcpy(s->pal, pal, AVPALETTE_SIZE);
}
-
/* make the palette available */
memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
}
/* FIXME how to correctly detect RLE ??? */
if (avctx->height * istride == avpkt->size) { /* assume uncompressed */
- int linesize = avctx->width * avctx->bits_per_coded_sample / 8;
+ int linesize = av_image_get_linesize(avctx->pix_fmt, avctx->width, 0);
uint8_t *ptr = s->frame->data[0];
uint8_t *buf = avpkt->data + (avctx->height-1)*istride;
int i, j;
+ if (linesize < 0)
+ return linesize;
+
for (i = 0; i < avctx->height; i++) {
if (avctx->bits_per_coded_sample == 4) {
for (j = 0; j < avctx->width - 1; j += 2) {
diff --git a/libavcodec/msrledec.c b/libavcodec/msrledec.c
index af2a2478b1..3aa5e3ceb9 100644
--- a/libavcodec/msrledec.c
+++ b/libavcodec/msrledec.c
@@ -2,20 +2,20 @@
* Microsoft RLE decoder
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,17 +36,15 @@ static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
unsigned char rle_code;
unsigned char extra_byte, odd_pixel;
unsigned char stream_byte;
- unsigned int pixel_ptr = 0;
- int row_dec = pic->linesize[0];
- int row_ptr = (avctx->height - 1) * row_dec;
- int frame_size = row_dec * avctx->height;
+ int pixel_ptr = 0;
+ int line = avctx->height - 1;
int i;
- while (row_ptr >= 0) {
+ while (line >= 0 && pixel_ptr <= avctx->width) {
if (bytestream2_get_bytes_left(gb) <= 0) {
av_log(avctx, AV_LOG_ERROR,
- "MS RLE: bytestream overrun, %d rows left\n",
- row_ptr);
+ "MS RLE: bytestream overrun, %dx%d left\n",
+ avctx->width - pixel_ptr, line);
return AVERROR_INVALIDDATA;
}
rle_code = stream_byte = bytestream2_get_byteu(gb);
@@ -55,7 +53,7 @@ static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
stream_byte = bytestream2_get_byte(gb);
if (stream_byte == 0) {
/* line is done, goto the next one */
- row_ptr -= row_dec;
+ line--;
pixel_ptr = 0;
} else if (stream_byte == 1) {
/* decode is done */
@@ -65,13 +63,13 @@ static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
stream_byte = bytestream2_get_byte(gb);
pixel_ptr += stream_byte;
stream_byte = bytestream2_get_byte(gb);
- row_ptr -= stream_byte * row_dec;
+ avpriv_request_sample(avctx, "Unused stream byte %X", stream_byte);
} else {
// copy pixels from encoded stream
odd_pixel = stream_byte & 1;
rle_code = (stream_byte + 1) / 2;
extra_byte = rle_code & 0x01;
- if (row_ptr + pixel_ptr + stream_byte > frame_size ||
+ if (pixel_ptr + 2*rle_code - odd_pixel > avctx->width ||
bytestream2_get_bytes_left(gb) < rle_code) {
av_log(avctx, AV_LOG_ERROR,
"MS RLE: frame/stream ptr just went out of bounds (copy)\n");
@@ -82,13 +80,13 @@ static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
if (pixel_ptr >= avctx->width)
break;
stream_byte = bytestream2_get_byteu(gb);
- pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
+ pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4;
pixel_ptr++;
if (i + 1 == rle_code && odd_pixel)
break;
if (pixel_ptr >= avctx->width)
break;
- pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
+ pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F;
pixel_ptr++;
}
@@ -98,9 +96,9 @@ static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
}
} else {
// decode a run of data
- if (row_ptr + pixel_ptr + stream_byte > frame_size) {
+ if (pixel_ptr + rle_code > avctx->width + 1) {
av_log(avctx, AV_LOG_ERROR,
- "MS RLE: frame ptr just went out of bounds (run)\n");
+ "MS RLE: frame ptr just went out of bounds (run) %d %d %d\n", pixel_ptr, rle_code, avctx->width);
return AVERROR_INVALIDDATA;
}
stream_byte = bytestream2_get_byte(gb);
@@ -108,9 +106,9 @@ static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
if (pixel_ptr >= avctx->width)
break;
if ((i & 1) == 0)
- pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
+ pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte >> 4;
else
- pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
+ pic->data[0][line * pic->linesize[0] + pixel_ptr] = stream_byte & 0x0F;
pixel_ptr++;
}
}
@@ -138,7 +136,8 @@ static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic,
unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3);
output = pic->data[0] + (avctx->height - 1) * pic->linesize[0];
- output_end = pic->data[0] + avctx->height * pic->linesize[0];
+ output_end = output + FFABS(pic->linesize[0]);
+
while (bytestream2_get_bytes_left(gb) > 0) {
p1 = bytestream2_get_byteu(gb);
if(p1 == 0) { //Escape code
@@ -155,6 +154,7 @@ static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic,
}
}
output = pic->data[0] + line * pic->linesize[0];
+ output_end = output + FFABS(pic->linesize[0]);
pos = 0;
continue;
} else if(p2 == 1) { //End-of-picture
@@ -169,11 +169,11 @@ static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic,
return -1;
}
output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
+ output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]);
continue;
}
// Copy data
- if ((pic->linesize[0] > 0 && output + p2 * (depth >> 3) > output_end) ||
- (pic->linesize[0] < 0 && output + p2 * (depth >> 3) < output_end)) {
+ if (output + p2 * (depth >> 3) > output_end) {
bytestream2_skip(gb, 2 * (depth >> 3));
continue;
} else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) {
@@ -182,9 +182,9 @@ static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic,
}
if ((depth == 8) || (depth == 24)) {
- for(i = 0; i < p2 * (depth >> 3); i++) {
- *output++ = bytestream2_get_byteu(gb);
- }
+ bytestream2_get_bufferu(gb, output, p2 * (depth >> 3));
+ output += p2 * (depth >> 3);
+
// RLE8 copy is actually padded - and runs are not!
if(depth == 8 && (p2 & 1)) {
bytestream2_skip(gb, 1);
@@ -203,36 +203,39 @@ static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic,
pos += p2;
} else { //run of pixels
uint8_t pix[3]; //original pixel
- switch(depth){
- case 8: pix[0] = bytestream2_get_byte(gb);
- break;
- case 16: pix16 = bytestream2_get_le16(gb);
- break;
- case 24: pix[0] = bytestream2_get_byte(gb);
- pix[1] = bytestream2_get_byte(gb);
- pix[2] = bytestream2_get_byte(gb);
- break;
- case 32: pix32 = bytestream2_get_le32(gb);
- break;
- }
- if ((pic->linesize[0] > 0 && output + p1 * (depth >> 3) > output_end) ||
- (pic->linesize[0] < 0 && output + p1 * (depth >> 3) < output_end))
+ if (output + p1 * (depth >> 3) > output_end)
continue;
- for(i = 0; i < p1; i++) {
- switch(depth){
- case 8: *output++ = pix[0];
- break;
- case 16: *(uint16_t*)output = pix16;
- output += 2;
- break;
- case 24: *output++ = pix[0];
- *output++ = pix[1];
- *output++ = pix[2];
- break;
- case 32: *(uint32_t*)output = pix32;
- output += 4;
- break;
+
+ switch(depth){
+ case 8:
+ pix[0] = bytestream2_get_byte(gb);
+ memset(output, pix[0], p1);
+ output += p1;
+ break;
+ case 16:
+ pix16 = bytestream2_get_le16(gb);
+ for(i = 0; i < p1; i++) {
+ *(uint16_t*)output = pix16;
+ output += 2;
+ }
+ break;
+ case 24:
+ pix[0] = bytestream2_get_byte(gb);
+ pix[1] = bytestream2_get_byte(gb);
+ pix[2] = bytestream2_get_byte(gb);
+ for(i = 0; i < p1; i++) {
+ *output++ = pix[0];
+ *output++ = pix[1];
+ *output++ = pix[2];
+ }
+ break;
+ case 32:
+ pix32 = bytestream2_get_le32(gb);
+ for(i = 0; i < p1; i++) {
+ *(uint32_t*)output = pix32;
+ output += 4;
}
+ break;
}
pos += p1;
}
diff --git a/libavcodec/msrledec.h b/libavcodec/msrledec.h
index a594de37be..3f666360c5 100644
--- a/libavcodec/msrledec.h
+++ b/libavcodec/msrledec.h
@@ -2,20 +2,20 @@
* Microsoft RLE decoder
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mss1.c b/libavcodec/mss1.c
index a67a942ac2..2eb67df6b8 100644
--- a/libavcodec/mss1.c
+++ b/libavcodec/mss1.c
@@ -2,20 +2,20 @@
* Microsoft Screen 1 (aka Windows Media Video V7 Screen) decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -60,7 +60,7 @@ static void arith_normalise(ArithCoder *c)
}
}
-ARITH_GET_BIT()
+ARITH_GET_BIT(arith)
static int arith_get_bits(ArithCoder *c, int bits)
{
@@ -105,7 +105,7 @@ static int arith_get_prob(ArithCoder *c, int16_t *probs)
return sym;
}
-ARITH_GET_MODEL_SYM()
+ARITH_GET_MODEL_SYM(arith)
static void arith_init(ArithCoder *c, GetBitContext *gb)
{
@@ -130,7 +130,7 @@ static int decode_pal(MSS12Context *ctx, ArithCoder *acoder)
r = arith_get_bits(acoder, 8);
g = arith_get_bits(acoder, 8);
b = arith_get_bits(acoder, 8);
- *pal++ = (r << 16) | (g << 8) | b;
+ *pal++ = (0xFFU << 24) | (r << 16) | (g << 8) | b;
}
return !!ncol;
@@ -139,8 +139,6 @@ static int decode_pal(MSS12Context *ctx, ArithCoder *acoder)
static int mss1_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
MSS1Context *ctx = avctx->priv_data;
MSS12Context *c = &ctx->ctx;
GetBitContext gb;
@@ -148,13 +146,13 @@ static int mss1_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int pal_changed = 0;
int ret;
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
+ return ret;
+
arith_init(&acoder, &gb);
- if ((ret = ff_reget_buffer(avctx, ctx->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, ctx->pic)) < 0)
return ret;
- }
c->pal_pic = ctx->pic->data[0] + ctx->pic->linesize[0] * (avctx->height - 1);
c->pal_stride = -ctx->pic->linesize[0];
@@ -184,7 +182,7 @@ static int mss1_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
*got_frame = 1;
/* always report that the buffer was completely consumed */
- return buf_size;
+ return avpkt->size;
}
static av_cold int mss1_decode_init(AVCodecContext *avctx)
@@ -199,6 +197,8 @@ static av_cold int mss1_decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
ret = ff_mss12_decode_init(&c->ctx, 0, &c->sc, NULL);
+ if (ret < 0)
+ av_frame_free(&c->pic);
avctx->pix_fmt = AV_PIX_FMT_PAL8;
diff --git a/libavcodec/mss12.c b/libavcodec/mss12.c
index d4b621fc89..6b58aa2955 100644
--- a/libavcodec/mss12.c
+++ b/libavcodec/mss12.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -450,7 +450,7 @@ static int decode_pivot(SliceContext *sc, ArithCoder *acoder, int base)
val = acoder->get_number(acoder, (base + 1) / 2 - 2) + 3;
}
- if (val >= base)
+ if ((unsigned)val >= base)
return -1;
return inv ? base - val : val;
@@ -588,6 +588,11 @@ av_cold int ff_mss12_decode_init(MSS12Context *c, int version,
avctx->coded_width, avctx->coded_height);
return AVERROR_INVALIDDATA;
}
+ if (avctx->coded_width < 1 || avctx->coded_height < 1) {
+ av_log(avctx, AV_LOG_ERROR, "Frame dimensions %dx%d too small",
+ avctx->coded_width, avctx->coded_height);
+ return AVERROR_INVALIDDATA;
+ }
av_log(avctx, AV_LOG_DEBUG, "Encoder version %"PRIu32".%"PRIu32"\n",
AV_RB32(avctx->extradata + 4), AV_RB32(avctx->extradata + 8));
@@ -647,11 +652,11 @@ av_cold int ff_mss12_decode_init(MSS12Context *c, int version,
}
for (i = 0; i < 256; i++)
- c->pal[i] = AV_RB24(avctx->extradata + 52 +
+ c->pal[i] = 0xFFU << 24 | AV_RB24(avctx->extradata + 52 +
(version ? 8 : 0) + i * 3);
c->mask_stride = FFALIGN(avctx->width, 16);
- c->mask = av_malloc(c->mask_stride * avctx->height);
+ c->mask = av_malloc_array(c->mask_stride, avctx->height);
if (!c->mask) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate mask plane\n");
return AVERROR(ENOMEM);
diff --git a/libavcodec/mss12.h b/libavcodec/mss12.h
index 5b1fee8913..f953167389 100644
--- a/libavcodec/mss12.h
+++ b/libavcodec/mss12.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -99,8 +99,8 @@ int ff_mss12_decode_init(MSS12Context *c, int version,
SliceContext *sc1, SliceContext *sc2);
int ff_mss12_decode_end(MSS12Context *ctx);
-#define ARITH_GET_BIT(VERSION) \
-static int arith ## VERSION ## _get_bit(ArithCoder *c) \
+#define ARITH_GET_BIT(prefix) \
+static int prefix ## _get_bit(ArithCoder *c) \
{ \
int range = c->high - c->low + 1; \
int bit = 2 * c->value - c->low >= c->high; \
@@ -110,22 +110,22 @@ static int arith ## VERSION ## _get_bit(ArithCoder *c) \
else \
c->high = c->low + (range >> 1) - 1; \
\
- arith ## VERSION ## _normalise(c); \
+ prefix ## _normalise(c); \
\
return bit; \
}
-#define ARITH_GET_MODEL_SYM(VERSION) \
-static int arith ## VERSION ## _get_model_sym(ArithCoder *c, Model *m) \
+#define ARITH_GET_MODEL_SYM(prefix) \
+static int prefix ## _get_model_sym(ArithCoder *c, Model *m) \
{ \
int idx, val; \
\
- idx = arith ## VERSION ## _get_prob(c, m->cum_prob); \
+ idx = prefix ## _get_prob(c, m->cum_prob); \
\
val = m->idx2sym[idx]; \
ff_mss12_model_update(m, idx); \
\
- arith ## VERSION ## _normalise(c); \
+ prefix ## _normalise(c); \
\
return val; \
}
diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c
index d71d30844a..5e56e4dbb2 100644
--- a/libavcodec/mss2.c
+++ b/libavcodec/mss2.c
@@ -1,20 +1,20 @@
/*
* Microsoft Screen 2 (aka Windows Media Video V9 Screen) decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,7 +57,7 @@ static void arith2_normalise(ArithCoder *c)
}
}
-ARITH_GET_BIT(2)
+ARITH_GET_BIT(arith2)
/* L. Stuiver and A. Moffat: "Piecewise Integer Mapping for Arithmetic Coding."
* In Proc. 8th Data Compression Conference (DCC '98), pp. 3-12, Mar. 1998 */
@@ -130,7 +130,7 @@ static int arith2_get_prob(ArithCoder *c, int16_t *probs)
return i;
}
-ARITH_GET_MODEL_SYM(2)
+ARITH_GET_MODEL_SYM(arith2)
static int arith2_get_consumed_bytes(ArithCoder *c)
{
@@ -317,7 +317,7 @@ static int decode_rle(GetBitContext *gb, uint8_t *pal_dst, int pal_stride,
if (next_code != 1 << current_length)
return AVERROR_INVALIDDATA;
- if (i = init_vlc(&vlc, 9, alphabet_size, bits, 1, 1, codes, 4, 4, 0))
+ if ((i = init_vlc(&vlc, 9, alphabet_size, bits, 1, 1, codes, 4, 4, 0)) < 0)
return i;
/* frame decode */
@@ -380,7 +380,8 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size,
ff_mpeg_flush(avctx);
- init_get_bits(&s->gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&s->gb, buf, buf_size)) < 0)
+ return ret;
s->loop_filter = avctx->skip_loop_filter < AVDISCARD_ALL;
@@ -423,8 +424,8 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size,
if (v->respic == 3) {
ctx->dsp.upsample_plane(f->data[0], f->linesize[0], w, h);
- ctx->dsp.upsample_plane(f->data[1], f->linesize[1], w >> 1, h >> 1);
- ctx->dsp.upsample_plane(f->data[2], f->linesize[2], w >> 1, h >> 1);
+ ctx->dsp.upsample_plane(f->data[1], f->linesize[1], w+1 >> 1, h+1 >> 1);
+ ctx->dsp.upsample_plane(f->data[2], f->linesize[2], w+1 >> 1, h+1 >> 1);
} else if (v->respic)
avpriv_request_sample(v->s.avctx,
"Asymmetric WMV9 rectangle subsampling");
@@ -478,7 +479,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_assert0(FF_INPUT_BUFFER_PADDING_SIZE >=
ARITH2_PADDING + (MIN_CACHE_BITS + 7) / 8);
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
+ return ret;
if (keyframe = get_bits1(&gb))
skip_bits(&gb, 7);
@@ -594,10 +596,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (c->mvX < 0 || c->mvY < 0) {
FFSWAP(uint8_t *, c->pal_pic, c->last_pal_pic);
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if (ctx->last_pic->data[0]) {
av_assert0(frame->linesize[0] == ctx->last_pic->linesize[0]);
@@ -608,10 +608,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
} else {
- if ((ret = ff_reget_buffer(avctx, ctx->last_pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, ctx->last_pic)) < 0)
return ret;
- }
if ((ret = av_frame_ref(frame, ctx->last_pic)) < 0)
return ret;
@@ -640,7 +638,8 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ff_mss12_slicecontext_reset(&ctx->sc[1]);
}
if (is_rle) {
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
+ return ret;
if (ret = decode_rle(&gb, c->pal_pic, c->pal_stride,
c->rgb_pic, c->rgb_stride, c->pal, keyframe,
ctx->split_position, 0,
@@ -818,10 +817,11 @@ static av_cold int mss2_decode_init(AVCodecContext *avctx)
c->avctx = avctx;
if (ret = ff_mss12_decode_init(c, 1, &ctx->sc[0], &ctx->sc[1]))
return ret;
+ ctx->last_pic = av_frame_alloc();
c->pal_stride = c->mask_stride;
c->pal_pic = av_mallocz(c->pal_stride * avctx->height);
c->last_pal_pic = av_mallocz(c->pal_stride * avctx->height);
- if (!c->pal_pic || !c->last_pal_pic) {
+ if (!c->pal_pic || !c->last_pal_pic || !ctx->last_pic) {
mss2_decode_end(avctx);
return AVERROR(ENOMEM);
}
@@ -835,11 +835,6 @@ static av_cold int mss2_decode_init(AVCodecContext *avctx)
avctx->pix_fmt = c->free_colours == 127 ? AV_PIX_FMT_RGB555
: AV_PIX_FMT_RGB24;
- ctx->last_pic = av_frame_alloc();
- if (!ctx->last_pic) {
- mss2_decode_end(avctx);
- return AVERROR(ENOMEM);
- }
return 0;
}
diff --git a/libavcodec/mss2dsp.c b/libavcodec/mss2dsp.c
index aa13577d48..c5fc1f8dcf 100644
--- a/libavcodec/mss2dsp.c
+++ b/libavcodec/mss2dsp.c
@@ -1,20 +1,20 @@
/*
* Microsoft Screen 2 (aka Windows Media Video V9 Screen) decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -106,6 +106,9 @@ static void upsample_plane_c(uint8_t *plane, int plane_stride, int w, int h)
uint8_t *src1, *src2, *dst1, *dst2, *p, a, b;
int i, j;
+ if(!w || !h)
+ return;
+
w += (w & 1);
h += (h & 1);
diff --git a/libavcodec/mss2dsp.h b/libavcodec/mss2dsp.h
index 61c3a04fcd..7368abb581 100644
--- a/libavcodec/mss2dsp.h
+++ b/libavcodec/mss2dsp.h
@@ -1,20 +1,20 @@
/*
* Microsoft Screen 2 (aka Windows Media Video V9 Screen) decoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mss3.c b/libavcodec/mss3.c
index 9a0b1fb3e8..075685b902 100644
--- a/libavcodec/mss3.c
+++ b/libavcodec/mss3.c
@@ -2,20 +2,20 @@
* Microsoft Screen 3 (aka Microsoft ATC Screen) decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -296,7 +296,7 @@ static void rac_normalise(RangeCoder *c)
c->low |= *c->src++;
} else if (!c->low) {
c->got_error = 1;
- return;
+ c->low = 1;
}
if (c->range >= RAC_BOTTOM)
return;
@@ -731,10 +731,8 @@ static int mss3_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return buf_size;
c->got_error = 0;
- if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
return ret;
- }
c->pic->key_frame = keyframe;
c->pic->pict_type = keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
if (!bytestream2_get_bytes_left(&gb)) {
@@ -840,6 +838,7 @@ static av_cold int mss3_decode_init(AVCodecContext *avctx)
b_width * b_height);
if (!c->dct_coder[i].prev_dc) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate buffer\n");
+ av_frame_free(&c->pic);
while (i >= 0) {
av_freep(&c->dct_coder[i].prev_dc);
i--;
diff --git a/libavcodec/mss34dsp.c b/libavcodec/mss34dsp.c
index 11abb2de11..0397add17d 100644
--- a/libavcodec/mss34dsp.c
+++ b/libavcodec/mss34dsp.c
@@ -2,20 +2,20 @@
* Common stuff for some Microsoft Screen codecs
* Copyright (C) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -84,8 +84,8 @@ void ff_mss34_gen_quant_mat(uint16_t *qmat, int quality, int luma)
blk[6 * step] = (-(t3 + t7) + t8 + tA) >> shift; \
blk[7 * step] = (-(t1 + t6) + t9 + tB) >> shift; \
-#define SOP_ROW(a) ((a) << 16) + 0x2000
-#define SOP_COL(a) ((a + 32) << 16)
+#define SOP_ROW(a) (((a) << 16) + 0x2000)
+#define SOP_COL(a) (((a) + 32) << 16)
void ff_mss34_dct_put(uint8_t *dst, int stride, int *block)
{
diff --git a/libavcodec/mss34dsp.h b/libavcodec/mss34dsp.h
index b2cc5501ec..2f9827d3e5 100644
--- a/libavcodec/mss34dsp.h
+++ b/libavcodec/mss34dsp.h
@@ -2,20 +2,20 @@
* Common stuff for some Microsoft Screen codecs
* Copyright (C) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mss4.c b/libavcodec/mss4.c
index 9198acc6a7..00c31dda15 100644
--- a/libavcodec/mss4.c
+++ b/libavcodec/mss4.c
@@ -2,20 +2,20 @@
* Microsoft Screen 4 (aka Microsoft Expression Encoder Screen) decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -125,7 +125,7 @@ static const uint8_t mss4_vec_entry_vlc_syms[2][9] = {
#define MAX_ENTRIES 162
typedef struct MSS4Context {
- AVFrame *pic;
+ AVFrame *pic;
VLC dc_vlc[2], ac_vlc[2];
VLC vec_entry_vlc[2];
@@ -363,7 +363,7 @@ static int get_value_cached(GetBitContext *gb, int vec_pos, uint8_t *vec,
return prev[component];
}
-#define MKVAL(vals) (vals[0] | (vals[1] << 3) | (vals[2] << 6))
+#define MKVAL(vals) ((vals)[0] | ((vals)[1] << 3) | ((vals)[2] << 6))
/* Image mode - the hardest to comprehend MSS4 coding mode.
*
@@ -553,10 +553,8 @@ static int mss4_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
return ret;
- }
c->pic->key_frame = (frame_type == INTRA_FRAME);
c->pic->pict_type = (frame_type == INTRA_FRAME) ? AV_PICTURE_TYPE_I
: AV_PICTURE_TYPE_P;
@@ -574,7 +572,8 @@ static int mss4_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ff_mss34_gen_quant_mat(c->quant_mat[i], quality, !i);
}
- init_get_bits(&gb, buf + HEADER_SIZE, (buf_size - HEADER_SIZE) * 8);
+ if ((ret = init_get_bits8(&gb, buf + HEADER_SIZE, buf_size - HEADER_SIZE)) < 0)
+ return ret;
mb_width = FFALIGN(width, 16) >> 4;
mb_height = FFALIGN(height, 16) >> 4;
@@ -652,7 +651,7 @@ static av_cold int mss4_decode_init(AVCodecContext *avctx)
}
for (i = 0; i < 3; i++) {
c->dc_stride[i] = FFALIGN(avctx->width, 16) >> (2 + !!i);
- c->prev_dc[i] = av_malloc(sizeof(**c->prev_dc) * c->dc_stride[i]);
+ c->prev_dc[i] = av_malloc_array(c->dc_stride[i], sizeof(**c->prev_dc));
if (!c->prev_dc[i]) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate buffer\n");
mss4_free_vlcs(c);
diff --git a/libavcodec/msvideo1.c b/libavcodec/msvideo1.c
index 7fd863354e..88397beb00 100644
--- a/libavcodec/msvideo1.c
+++ b/libavcodec/msvideo1.c
@@ -1,21 +1,21 @@
/*
* Microsoft Video-1 Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -67,6 +67,8 @@ static av_cold int msvideo1_decode_init(AVCodecContext *avctx)
if (s->avctx->bits_per_coded_sample == 8) {
s->mode_8bit = 1;
avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ if (avctx->extradata_size >= AVPALETTE_SIZE)
+ memcpy(s->pal, avctx->extradata, AVPALETTE_SIZE);
} else {
s->mode_8bit = 0;
avctx->pix_fmt = AV_PIX_FMT_RGB555;
@@ -300,10 +302,8 @@ static int msvideo1_decode_frame(AVCodecContext *avctx,
s->buf = buf;
s->size = buf_size;
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
if (s->mode_8bit) {
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
diff --git a/libavcodec/msvideo1enc.c b/libavcodec/msvideo1enc.c
new file mode 100644
index 0000000000..5e6cdfa3f8
--- /dev/null
+++ b/libavcodec/msvideo1enc.c
@@ -0,0 +1,305 @@
+/*
+ * Microsoft Video-1 Encoder
+ * Copyright (c) 2009 Konstantin Shishkov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Microsoft Video-1 encoder
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "bytestream.h"
+#include "libavutil/lfg.h"
+#include "elbg.h"
+#include "libavutil/imgutils.h"
+/**
+ * Encoder context
+ */
+typedef struct Msvideo1EncContext {
+ AVCodecContext *avctx;
+ AVLFG rnd;
+ uint8_t *prev;
+
+ int block[16*3];
+ int block2[16*3];
+ int codebook[8*3];
+ int codebook2[8*3];
+ int output[16*3];
+ int output2[16*3];
+ int avg[3];
+ int bestpos;
+ int keyint;
+} Msvideo1EncContext;
+
+enum MSV1Mode{
+ MODE_SKIP = 0,
+ MODE_FILL,
+ MODE_2COL,
+ MODE_8COL,
+};
+
+#define SKIP_PREFIX 0x8400
+#define SKIPS_MAX 0x03FF
+#define MKRGB555(in, off) (((in)[off] << 10) | ((in)[(off) + 1] << 5) | ((in)[(off) + 2]))
+
+static const int remap[16] = { 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15 };
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ Msvideo1EncContext * const c = avctx->priv_data;
+ const AVFrame *p = pict;
+ uint16_t *src;
+ uint8_t *prevptr;
+ uint8_t *dst, *buf;
+ int keyframe = 0;
+ int no_skips = 1;
+ int i, j, k, x, y, ret;
+ int skips = 0;
+ int quality = 24;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*9 + FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+ dst= buf= pkt->data;
+
+ if(!c->prev)
+ c->prev = av_malloc(avctx->width * 3 * (avctx->height + 3));
+ prevptr = c->prev + avctx->width * 3 * (FFALIGN(avctx->height, 4) - 1);
+ src = (uint16_t*)(p->data[0] + p->linesize[0]*(FFALIGN(avctx->height, 4) - 1));
+ if(c->keyint >= avctx->keyint_min)
+ keyframe = 1;
+
+
+ for(y = 0; y < avctx->height; y += 4){
+ for(x = 0; x < avctx->width; x += 4){
+ int bestmode = MODE_SKIP;
+ int bestscore = INT_MAX;
+ int flags = 0;
+ int score;
+
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4; i++){
+ uint16_t val = src[x + i - j*p->linesize[0]/2];
+ for(k = 0; k < 3; k++){
+ c->block[(i + j*4)*3 + k] =
+ c->block2[remap[i + j*4]*3 + k] = (val >> (10-k*5)) & 0x1F;
+ }
+ }
+ }
+ if(!keyframe){
+ bestscore = 0;
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4*3; i++){
+ int t = prevptr[x*3 + i - j*3*avctx->width] - c->block[i + j*4*3];
+ bestscore += t*t;
+ }
+ }
+ bestscore /= quality;
+ }
+ // try to find optimal value to fill whole 4x4 block
+ score = 0;
+ avpriv_init_elbg(c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
+ avpriv_do_elbg (c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
+ if(c->avg[0] == 1) // red component = 1 will be written as skip code
+ c->avg[0] = 0;
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4; i++){
+ for(k = 0; k < 3; k++){
+ int t = c->avg[k] - c->block[(i+j*4)*3+k];
+ score += t*t;
+ }
+ }
+ }
+ score /= quality;
+ score += 2;
+ if(score < bestscore){
+ bestscore = score;
+ bestmode = MODE_FILL;
+ }
+ // search for optimal filling of 2-color block
+ score = 0;
+ avpriv_init_elbg(c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
+ avpriv_do_elbg (c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
+ // last output value should be always 1, swap codebooks if needed
+ if(!c->output[15]){
+ for(i = 0; i < 3; i++)
+ FFSWAP(uint8_t, c->codebook[i], c->codebook[i+3]);
+ for(i = 0; i < 16; i++)
+ c->output[i] ^= 1;
+ }
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4; i++){
+ for(k = 0; k < 3; k++){
+ int t = c->codebook[c->output[i+j*4]*3 + k] - c->block[i*3+k+j*4*3];
+ score += t*t;
+ }
+ }
+ }
+ score /= quality;
+ score += 6;
+ if(score < bestscore){
+ bestscore = score;
+ bestmode = MODE_2COL;
+ }
+ // search for optimal filling of 2-color 2x2 subblocks
+ score = 0;
+ for(i = 0; i < 4; i++){
+ avpriv_init_elbg(c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
+ avpriv_do_elbg (c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
+ }
+ // last value should be always 1, swap codebooks if needed
+ if(!c->output2[15]){
+ for(i = 0; i < 3; i++)
+ FFSWAP(uint8_t, c->codebook2[i+18], c->codebook2[i+21]);
+ for(i = 12; i < 16; i++)
+ c->output2[i] ^= 1;
+ }
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4; i++){
+ for(k = 0; k < 3; k++){
+ int t = c->codebook2[(c->output2[remap[i+j*4]] + (i&2) + (j&2)*2)*3+k] - c->block[i*3+k + j*4*3];
+ score += t*t;
+ }
+ }
+ }
+ score /= quality;
+ score += 18;
+ if(score < bestscore){
+ bestscore = score;
+ bestmode = MODE_8COL;
+ }
+
+ if(bestmode == MODE_SKIP){
+ skips++;
+ no_skips = 0;
+ }
+ if((bestmode != MODE_SKIP && skips) || skips == SKIPS_MAX){
+ bytestream_put_le16(&dst, skips | SKIP_PREFIX);
+ skips = 0;
+ }
+
+ switch(bestmode){
+ case MODE_FILL:
+ bytestream_put_le16(&dst, MKRGB555(c->avg,0) | 0x8000);
+ for(j = 0; j < 4; j++)
+ for(i = 0; i < 4; i++)
+ for(k = 0; k < 3; k++)
+ prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->avg[k];
+ break;
+ case MODE_2COL:
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4; i++){
+ flags |= (c->output[i + j*4]^1) << (i + j*4);
+ for(k = 0; k < 3; k++)
+ prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook[c->output[i + j*4]*3 + k];
+ }
+ }
+ bytestream_put_le16(&dst, flags);
+ bytestream_put_le16(&dst, MKRGB555(c->codebook, 0));
+ bytestream_put_le16(&dst, MKRGB555(c->codebook, 3));
+ break;
+ case MODE_8COL:
+ for(j = 0; j < 4; j++){
+ for(i = 0; i < 4; i++){
+ flags |= (c->output2[remap[i + j*4]]^1) << (i + j*4);
+ for(k = 0; k < 3; k++)
+ prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook2[(c->output2[remap[i+j*4]] + (i&2) + (j&2)*2)*3 + k];
+ }
+ }
+ bytestream_put_le16(&dst, flags);
+ bytestream_put_le16(&dst, MKRGB555(c->codebook2, 0) | 0x8000);
+ for(i = 3; i < 24; i += 3)
+ bytestream_put_le16(&dst, MKRGB555(c->codebook2, i));
+ break;
+ }
+ }
+ src -= p->linesize[0] << 1;
+ prevptr -= avctx->width * 3 * 4;
+ }
+ if(skips)
+ bytestream_put_le16(&dst, skips | SKIP_PREFIX);
+ //EOF
+ bytestream_put_byte(&dst, 0);
+ bytestream_put_byte(&dst, 0);
+
+ if(no_skips)
+ keyframe = 1;
+ if(keyframe)
+ c->keyint = 0;
+ else
+ c->keyint++;
+ if (keyframe) pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->size = dst - buf;
+ *got_packet = 1;
+
+ return 0;
+}
+
+
+/**
+ * init encoder
+ */
+static av_cold int encode_init(AVCodecContext *avctx)
+{
+ Msvideo1EncContext * const c = avctx->priv_data;
+
+ c->avctx = avctx;
+ if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
+ return -1;
+ }
+ if((avctx->width&3) || (avctx->height&3)){
+ av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of 4\n");
+ return -1;
+ }
+
+ avctx->bits_per_coded_sample = 16;
+
+ c->keyint = avctx->keyint_min;
+ av_lfg_init(&c->rnd, 1);
+
+ return 0;
+}
+
+
+
+/**
+ * Uninit encoder
+ */
+static av_cold int encode_end(AVCodecContext *avctx)
+{
+ Msvideo1EncContext * const c = avctx->priv_data;
+
+ av_freep(&c->prev);
+
+ return 0;
+}
+
+AVCodec ff_msvideo1_encoder = {
+ .name = "msvideo1",
+ .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video-1"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_MSVIDEO1,
+ .priv_data_size = sizeof(Msvideo1EncContext),
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_end,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB555, AV_PIX_FMT_NONE},
+};
diff --git a/libavcodec/mvcdec.c b/libavcodec/mvcdec.c
index 7cc0329257..69f0ee259c 100644
--- a/libavcodec/mvcdec.c
+++ b/libavcodec/mvcdec.c
@@ -2,20 +2,20 @@
* Silicon Graphics Motion Video Compressor 1 & 2 decoder
* Copyright (c) 2012 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/mxpegdec.c b/libavcodec/mxpegdec.c
index 46536981e4..05c74eed2b 100644
--- a/libavcodec/mxpegdec.c
+++ b/libavcodec/mxpegdec.c
@@ -2,20 +2,20 @@
* MxPEG decoder
* Copyright (c) 2011 Anatoly Nenashev
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,6 +54,7 @@ static av_cold int mxpeg_decode_end(AVCodecContext *avctx)
for (i = 0; i < 2; ++i)
av_frame_free(&s->picture[i]);
+ s->bitmask_size = 0;
av_freep(&s->mxm_bitmask);
av_freep(&s->completion_bitmask);
@@ -105,6 +106,7 @@ static int mxpeg_decode_mxm(MXpegDecodeContext *s,
}
if (s->bitmask_size != bitmask_size) {
+ s->bitmask_size = 0;
av_freep(&s->mxm_bitmask);
s->mxm_bitmask = av_malloc(bitmask_size);
if (!s->mxm_bitmask) {
@@ -272,11 +274,9 @@ static int mxpeg_decode_frame(AVCodecContext *avctx,
}
/* use stored SOF data to allocate current picture */
av_frame_unref(jpg->picture_ptr);
- if (ff_get_buffer(avctx, jpg->picture_ptr,
- AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return AVERROR(ENOMEM);
- }
+ if ((ret = ff_get_buffer(avctx, jpg->picture_ptr,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
jpg->picture_ptr->pict_type = AV_PICTURE_TYPE_P;
jpg->picture_ptr->key_frame = 0;
jpg->got_picture = 1;
@@ -292,17 +292,15 @@ static int mxpeg_decode_frame(AVCodecContext *avctx,
/* allocate dummy reference picture if needed */
if (!reference_ptr->data[0] &&
- ff_get_buffer(avctx, reference_ptr,
- AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return AVERROR(ENOMEM);
- }
+ (ret = ff_get_buffer(avctx, reference_ptr,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
- ret = ff_mjpeg_decode_sos(jpg, s->mxm_bitmask, reference_ptr);
+ ret = ff_mjpeg_decode_sos(jpg, s->mxm_bitmask, s->bitmask_size, reference_ptr);
if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
return ret;
} else {
- ret = ff_mjpeg_decode_sos(jpg, NULL, NULL);
+ ret = ff_mjpeg_decode_sos(jpg, NULL, 0, NULL);
if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
return ret;
}
@@ -346,5 +344,6 @@ AVCodec ff_mxpeg_decoder = {
.close = mxpeg_decode_end,
.decode = mxpeg_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
diff --git a/libavcodec/nellymoserdec.c b/libavcodec/nellymoserdec.c
index e86846679e..d5a69ed0de 100644
--- a/libavcodec/nellymoserdec.c
+++ b/libavcodec/nellymoserdec.c
@@ -50,7 +50,7 @@ typedef struct NellyMoserDecodeContext {
AVLFG random_state;
GetBitContext gb;
float scale_bias;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext imdct_ctx;
DECLARE_ALIGNED(32, float, imdct_buf)[2][NELLY_BUF_LEN];
float *imdct_out;
@@ -105,7 +105,7 @@ static void nelly_decode_block(NellyMoserDecodeContext *s,
(NELLY_BUF_LEN - NELLY_FILL_LEN) * sizeof(float));
s->imdct_ctx.imdct_half(&s->imdct_ctx, s->imdct_out, aptr);
- s->fdsp.vector_fmul_window(aptr, s->imdct_prev + NELLY_BUF_LEN / 2,
+ s->fdsp->vector_fmul_window(aptr, s->imdct_prev + NELLY_BUF_LEN / 2,
s->imdct_out, ff_sine_128,
NELLY_BUF_LEN / 2);
FFSWAP(float *, s->imdct_out, s->imdct_prev);
@@ -121,7 +121,9 @@ static av_cold int decode_init(AVCodecContext * avctx) {
av_lfg_init(&s->random_state, 0);
ff_mdct_init(&s->imdct_ctx, 8, 1, 1.0);
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
s->scale_bias = 1.0/(32768*8);
avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
@@ -141,16 +143,19 @@ static int decode_tag(AVCodecContext *avctx, void *data,
{
AVFrame *frame = data;
const uint8_t *buf = avpkt->data;
+ const uint8_t *side=av_packet_get_side_data(avpkt, 'F', NULL);
int buf_size = avpkt->size;
NellyMoserDecodeContext *s = avctx->priv_data;
int blocks, i, ret;
float *samples_flt;
blocks = buf_size / NELLY_BLOCK_LEN;
+
if (blocks <= 0) {
av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
return AVERROR_INVALIDDATA;
}
+
if (buf_size % NELLY_BLOCK_LEN) {
av_log(avctx, AV_LOG_WARNING, "Leftover bytes: %d.\n",
buf_size % NELLY_BLOCK_LEN);
@@ -162,13 +167,13 @@ static int decode_tag(AVCodecContext *avctx, void *data,
* 22050 Hz - 4
* 44100 Hz - 8
*/
+ if(side && blocks>1 && avctx->sample_rate%11025==0 && (1<<((side[0]>>2)&3)) == blocks)
+ avctx->sample_rate= 11025*(blocks/2);
/* get output buffer */
frame->nb_samples = NELLY_SAMPLES * blocks;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples_flt = (float *)frame->data[0];
for (i=0 ; i<blocks ; i++) {
@@ -186,6 +191,7 @@ static av_cold int decode_end(AVCodecContext * avctx) {
NellyMoserDecodeContext *s = avctx->priv_data;
ff_mdct_end(&s->imdct_ctx);
+ av_freep(&s->fdsp);
return 0;
}
diff --git a/libavcodec/nellymoserenc.c b/libavcodec/nellymoserenc.c
index 98c2b390cc..7c77ff74e0 100644
--- a/libavcodec/nellymoserenc.c
+++ b/libavcodec/nellymoserenc.c
@@ -4,20 +4,20 @@
*
* Copyright (c) 2008 Bartlomiej Wolowiec
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,7 +28,7 @@
*
* Generic codec information: libavcodec/nellymoserdec.c
*
- * Some information also from: http://samples.libav.org/A-codecs/Nelly_Moser/ASAO/ASAO.zip
+ * Some information also from: http://samples.mplayerhq.hu/A-codecs/Nelly_Moser/ASAO/ASAO.zip
* (Copyright Joseph Artsimovich and UAB "DKD")
*
* for more information about nellymoser format, visit:
@@ -56,7 +56,7 @@
typedef struct NellyMoserEncodeContext {
AVCodecContext *avctx;
int last_frame;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext mdct_ctx;
AudioFrameQueue afq;
DECLARE_ALIGNED(32, float, mdct_out)[NELLY_SAMPLES];
@@ -66,7 +66,7 @@ typedef struct NellyMoserEncodeContext {
uint8_t (*path)[OPT_SIZE];
} NellyMoserEncodeContext;
-static float pow_table[POW_TABLE_SIZE]; ///< -pow(2, -i / 2048.0 - 3.0);
+static float pow_table[POW_TABLE_SIZE]; ///< pow(2, -i / 2048.0 - 3.0);
static const uint8_t sf_lut[96] = {
0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4,
@@ -122,12 +122,12 @@ static void apply_mdct(NellyMoserEncodeContext *s)
float *in1 = s->buf + NELLY_BUF_LEN;
float *in2 = s->buf + 2 * NELLY_BUF_LEN;
- s->fdsp.vector_fmul (s->in_buff, in0, ff_sine_128, NELLY_BUF_LEN);
- s->fdsp.vector_fmul_reverse(s->in_buff + NELLY_BUF_LEN, in1, ff_sine_128, NELLY_BUF_LEN);
+ s->fdsp->vector_fmul (s->in_buff, in0, ff_sine_128, NELLY_BUF_LEN);
+ s->fdsp->vector_fmul_reverse(s->in_buff + NELLY_BUF_LEN, in1, ff_sine_128, NELLY_BUF_LEN);
s->mdct_ctx.mdct_calc(&s->mdct_ctx, s->mdct_out, s->in_buff);
- s->fdsp.vector_fmul (s->in_buff, in1, ff_sine_128, NELLY_BUF_LEN);
- s->fdsp.vector_fmul_reverse(s->in_buff + NELLY_BUF_LEN, in2, ff_sine_128, NELLY_BUF_LEN);
+ s->fdsp->vector_fmul (s->in_buff, in1, ff_sine_128, NELLY_BUF_LEN);
+ s->fdsp->vector_fmul_reverse(s->in_buff + NELLY_BUF_LEN, in2, ff_sine_128, NELLY_BUF_LEN);
s->mdct_ctx.mdct_calc(&s->mdct_ctx, s->mdct_out + NELLY_BUF_LEN, s->in_buff);
}
@@ -138,10 +138,11 @@ static av_cold int encode_end(AVCodecContext *avctx)
ff_mdct_end(&s->mdct_ctx);
if (s->avctx->trellis) {
- av_free(s->opt);
- av_free(s->path);
+ av_freep(&s->opt);
+ av_freep(&s->path);
}
ff_af_queue_close(&s->afq);
+ av_freep(&s->fdsp);
return 0;
}
@@ -170,12 +171,16 @@ static av_cold int encode_init(AVCodecContext *avctx)
s->avctx = avctx;
if ((ret = ff_mdct_init(&s->mdct_ctx, 8, 0, 32768.0)) < 0)
goto error;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
/* Generate overlap window */
- ff_sine_window_init(ff_sine_128, 128);
+ ff_init_ff_sine_windows(7);
for (i = 0; i < POW_TABLE_SIZE; i++)
- pow_table[i] = -pow(2, -i / 2048.0 - 3.0 + POW_TABLE_OFFSET);
+ pow_table[i] = pow(2, -i / 2048.0 - 3.0 + POW_TABLE_OFFSET);
if (s->avctx->trellis) {
s->opt = av_malloc(NELLY_BANDS * OPT_SIZE * sizeof(float ));
@@ -231,7 +236,7 @@ static void get_exponent_dynamic(NellyMoserEncodeContext *s, float *cand, int *i
float (*opt )[OPT_SIZE] = s->opt ;
uint8_t(*path)[OPT_SIZE] = s->path;
- for (i = 0; i < OPT_SIZE; i++) {
+ for (i = 0; i < NELLY_BANDS * OPT_SIZE; i++) {
opt[0][i] = INFINITY;
}
@@ -266,7 +271,7 @@ static void get_exponent_dynamic(NellyMoserEncodeContext *s, float *cand, int *i
}
}
}
- assert(c); //FIXME
+ av_assert1(c); //FIXME
}
best_val = INFINITY;
@@ -303,7 +308,7 @@ static void encode_block(NellyMoserEncodeContext *s, unsigned char *output, int
apply_mdct(s);
- init_put_bits(&pb, output, output_size * 8);
+ init_put_bits(&pb, output, output_size);
i = 0;
for (band = 0; band < NELLY_BANDS; band++) {
@@ -392,10 +397,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
s->last_frame = 1;
}
- if ((ret = ff_alloc_packet(avpkt, NELLY_BLOCK_LEN))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, NELLY_BLOCK_LEN)) < 0)
return ret;
- }
encode_block(s, avpkt->data, avpkt->size);
/* Get the next frame pts/duration */
diff --git a/libavcodec/neon/mpegvideo.c b/libavcodec/neon/mpegvideo.c
index fe952ae256..a96ae519f5 100644
--- a/libavcodec/neon/mpegvideo.c
+++ b/libavcodec/neon/mpegvideo.c
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Mans Rullgard
* Copyright (c) 2014 James Yu <james.yu@linaro.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/noise_bsf.c b/libavcodec/noise_bsf.c
index 00ceeadfec..4f609de7bf 100644
--- a/libavcodec/noise_bsf.c
+++ b/libavcodec/noise_bsf.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,9 +32,13 @@ static int noise(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const ch
int amount= args ? atoi(args) : (*state % 10001+1);
int i;
+ if(amount <= 0)
+ return AVERROR(EINVAL);
+
*poutbuf= av_malloc(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!*poutbuf)
return AVERROR(ENOMEM);
+
memcpy(*poutbuf, buf, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
for(i=0; i<buf_size; i++){
(*state) += (*poutbuf)[i] + 1;
@@ -45,7 +49,7 @@ static int noise(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const ch
}
AVBitStreamFilter ff_noise_bsf={
- "noise",
- sizeof(int),
- noise,
+ .name = "noise",
+ .priv_data_size = sizeof(int),
+ .filter = noise,
};
diff --git a/libavcodec/nuv.c b/libavcodec/nuv.c
index b3acde4f9d..e0cec52907 100644
--- a/libavcodec/nuv.c
+++ b/libavcodec/nuv.c
@@ -2,25 +2,26 @@
* NuppelVideo decoder
* Copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include "libavutil/bswap.h"
#include "libavutil/common.h"
@@ -121,23 +122,26 @@ static int codec_reinit(AVCodecContext *avctx, int width, int height,
if (quality >= 0)
get_quant_quality(c, quality);
if (width != c->width || height != c->height) {
- void *ptr;
+ // also reserve space for a possible additional header
+ int buf_size = height * width * 3 / 2
+ + FFMAX(AV_LZO_OUTPUT_PADDING, FF_INPUT_BUFFER_PADDING_SIZE)
+ + RTJPEG_HEADER_SIZE;
+ if (buf_size > INT_MAX/8)
+ return -1;
if ((ret = av_image_check_size(height, width, 0, avctx)) < 0)
return ret;
avctx->width = c->width = width;
avctx->height = c->height = height;
- ptr = av_fast_realloc(c->decomp_buf, &c->decomp_size,
- c->height * c->width * 3 / 2 +
- FF_INPUT_BUFFER_PADDING_SIZE +
- RTJPEG_HEADER_SIZE);
- if (!ptr) {
+ av_fast_malloc(&c->decomp_buf, &c->decomp_size,
+ buf_size);
+ if (!c->decomp_buf) {
av_log(avctx, AV_LOG_ERROR,
"Can't allocate decompression buffer.\n");
return AVERROR(ENOMEM);
- } else
- c->decomp_buf = ptr;
+ }
ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
av_frame_unref(c->pic);
+ return 1;
} else if (quality != c->quality)
ff_rtjpeg_decode_init(&c->rtj, c->width, c->height, c->lq, c->cq);
@@ -153,6 +157,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVFrame *picture = data;
int orig_size = buf_size;
int keyframe, ret;
+ int size_change = 0;
int result, init_frame = !avctx->frame_number;
enum {
NUV_UNCOMPRESSED = '0',
@@ -181,7 +186,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return orig_size;
}
- if (buf[0] != 'V' || buf_size < 12) {
+ if (buf_size < 12 || buf[0] != 'V') {
av_log(avctx, AV_LOG_ERROR, "not a nuv video frame\n");
return AVERROR_INVALIDDATA;
}
@@ -198,24 +203,32 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
keyframe = 1;
break;
}
+retry:
// skip rest of the frameheader.
buf = &buf[12];
buf_size -= 12;
if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO) {
- int outlen = c->decomp_size - FF_INPUT_BUFFER_PADDING_SIZE;
+ int outlen = c->decomp_size - FFMAX(FF_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING);
int inlen = buf_size;
if (av_lzo1x_decode(c->decomp_buf, &outlen, buf, &inlen)) {
av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n");
return AVERROR_INVALIDDATA;
}
buf = c->decomp_buf;
- buf_size = outlen;
+ buf_size = c->decomp_size - FFMAX(FF_INPUT_BUFFER_PADDING_SIZE, AV_LZO_OUTPUT_PADDING) - outlen;
+ memset(c->decomp_buf + buf_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
}
if (c->codec_frameheader) {
int w, h, q;
- if (buf_size < RTJPEG_HEADER_SIZE || buf[4] != RTJPEG_HEADER_SIZE ||
- buf[5] != RTJPEG_FILE_VERSION) {
- av_log(avctx, AV_LOG_ERROR, "invalid nuv video frame\n");
+ if (buf_size < RTJPEG_HEADER_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "Too small NUV video frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+ // There seem to exist two variants of this header: one starts with 'V'
+ // and 5 bytes unknown, the other matches current MythTV and is 4 bytes size,
+ // 1 byte header size (== 12), 1 byte version (== 0)
+ if (buf[0] != 'V' && AV_RL16(&buf[4]) != 0x000c) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown secondary frame header (wrong codec_tag?)\n");
return AVERROR_INVALIDDATA;
}
w = AV_RL16(&buf[6]);
@@ -223,22 +236,23 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
q = buf[10];
if ((result = codec_reinit(avctx, w, h, q)) < 0)
return result;
- if (comptype == NUV_RTJPEG_IN_LZO || comptype == NUV_LZO)
- buf = c->decomp_buf;
+ if (result) {
+ buf = avpkt->data;
+ buf_size = avpkt->size;
+ size_change = 1;
+ goto retry;
+ }
buf = &buf[RTJPEG_HEADER_SIZE];
buf_size -= RTJPEG_HEADER_SIZE;
}
- if (keyframe) {
+ if (size_change || keyframe) {
av_frame_unref(c->pic);
init_frame = 1;
}
- result = ff_reget_buffer(avctx, c->pic);
- if (result < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((result = ff_reget_buffer(avctx, c->pic)) < 0)
return result;
- }
if (init_frame) {
memset(c->pic->data[0], 0, avctx->height * c->pic->linesize[0]);
memset(c->pic->data[1], 0x80, avctx->height * c->pic->linesize[1] / 2);
@@ -256,7 +270,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
av_log(avctx, AV_LOG_ERROR, "uncompressed frame too short\n");
height = buf_size / c->width / 3 * 2;
}
- copy_frame(c->pic, buf, c->width, height);
+ if(height > 0)
+ copy_frame(c->pic, buf, c->width, height);
break;
}
case NUV_RTJPEG_IN_LZO:
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
new file mode 100644
index 0000000000..de082d1fc7
--- /dev/null
+++ b/libavcodec/nvenc.c
@@ -0,0 +1,1452 @@
+/*
+ * H.264 hardware encoding using nvidia nvenc
+ * Copyright (c) 2014 Timo Rothenpieler <timo@rothenpieler.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if defined(_WIN32)
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+#include <nvEncodeAPI.h>
+
+#include "libavutil/internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/mem.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "thread.h"
+
+#if defined(_WIN32)
+#define CUDAAPI __stdcall
+#else
+#define CUDAAPI
+#endif
+
+#if defined(_WIN32)
+#define LOAD_FUNC(l, s) GetProcAddress(l, s)
+#define DL_CLOSE_FUNC(l) FreeLibrary(l)
+#else
+#define LOAD_FUNC(l, s) dlsym(l, s)
+#define DL_CLOSE_FUNC(l) dlclose(l)
+#endif
+
+typedef enum cudaError_enum {
+ CUDA_SUCCESS = 0
+} CUresult;
+typedef int CUdevice;
+typedef void* CUcontext;
+
+typedef CUresult(CUDAAPI *PCUINIT)(unsigned int Flags);
+typedef CUresult(CUDAAPI *PCUDEVICEGETCOUNT)(int *count);
+typedef CUresult(CUDAAPI *PCUDEVICEGET)(CUdevice *device, int ordinal);
+typedef CUresult(CUDAAPI *PCUDEVICEGETNAME)(char *name, int len, CUdevice dev);
+typedef CUresult(CUDAAPI *PCUDEVICECOMPUTECAPABILITY)(int *major, int *minor, CUdevice dev);
+typedef CUresult(CUDAAPI *PCUCTXCREATE)(CUcontext *pctx, unsigned int flags, CUdevice dev);
+typedef CUresult(CUDAAPI *PCUCTXPOPCURRENT)(CUcontext *pctx);
+typedef CUresult(CUDAAPI *PCUCTXDESTROY)(CUcontext ctx);
+
+typedef NVENCSTATUS (NVENCAPI* PNVENCODEAPICREATEINSTANCE)(NV_ENCODE_API_FUNCTION_LIST *functionList);
+
+typedef struct NvencInputSurface
+{
+ NV_ENC_INPUT_PTR input_surface;
+ int width;
+ int height;
+
+ int lockCount;
+
+ NV_ENC_BUFFER_FORMAT format;
+} NvencInputSurface;
+
+typedef struct NvencOutputSurface
+{
+ NV_ENC_OUTPUT_PTR output_surface;
+ int size;
+
+ NvencInputSurface* input_surface;
+
+ int busy;
+} NvencOutputSurface;
+
+typedef struct NvencData
+{
+ union {
+ int64_t timestamp;
+ NvencOutputSurface *surface;
+ };
+} NvencData;
+
+typedef struct NvencDataList
+{
+ NvencData* data;
+
+ uint32_t pos;
+ uint32_t count;
+ uint32_t size;
+} NvencDataList;
+
+typedef struct NvencDynLoadFunctions
+{
+ PCUINIT cu_init;
+ PCUDEVICEGETCOUNT cu_device_get_count;
+ PCUDEVICEGET cu_device_get;
+ PCUDEVICEGETNAME cu_device_get_name;
+ PCUDEVICECOMPUTECAPABILITY cu_device_compute_capability;
+ PCUCTXCREATE cu_ctx_create;
+ PCUCTXPOPCURRENT cu_ctx_pop_current;
+ PCUCTXDESTROY cu_ctx_destroy;
+
+ NV_ENCODE_API_FUNCTION_LIST nvenc_funcs;
+ int nvenc_device_count;
+ CUdevice nvenc_devices[16];
+
+#if defined(_WIN32)
+ HMODULE cuda_lib;
+ HMODULE nvenc_lib;
+#else
+ void* cuda_lib;
+ void* nvenc_lib;
+#endif
+} NvencDynLoadFunctions;
+
+typedef struct NvencValuePair
+{
+ const char *str;
+ uint32_t num;
+} NvencValuePair;
+
+typedef struct NvencContext
+{
+ AVClass *avclass;
+
+ NvencDynLoadFunctions nvenc_dload_funcs;
+
+ NV_ENC_INITIALIZE_PARAMS init_encode_params;
+ NV_ENC_CONFIG encode_config;
+ CUcontext cu_context;
+
+ int max_surface_count;
+ NvencInputSurface *input_surfaces;
+ NvencOutputSurface *output_surfaces;
+
+ NvencDataList output_surface_queue;
+ NvencDataList output_surface_ready_queue;
+ NvencDataList timestamp_list;
+ int64_t last_dts;
+
+ void *nvencoder;
+
+ char *preset;
+ char *profile;
+ char *level;
+ char *tier;
+ int cbr;
+ int twopass;
+ int gpu;
+} NvencContext;
+
+static const NvencValuePair nvenc_h264_level_pairs[] = {
+ { "auto", NV_ENC_LEVEL_AUTOSELECT },
+ { "1" , NV_ENC_LEVEL_H264_1 },
+ { "1.0" , NV_ENC_LEVEL_H264_1 },
+ { "1b" , NV_ENC_LEVEL_H264_1b },
+ { "1.0b", NV_ENC_LEVEL_H264_1b },
+ { "1.1" , NV_ENC_LEVEL_H264_11 },
+ { "1.2" , NV_ENC_LEVEL_H264_12 },
+ { "1.3" , NV_ENC_LEVEL_H264_13 },
+ { "2" , NV_ENC_LEVEL_H264_2 },
+ { "2.0" , NV_ENC_LEVEL_H264_2 },
+ { "2.1" , NV_ENC_LEVEL_H264_21 },
+ { "2.2" , NV_ENC_LEVEL_H264_22 },
+ { "3" , NV_ENC_LEVEL_H264_3 },
+ { "3.0" , NV_ENC_LEVEL_H264_3 },
+ { "3.1" , NV_ENC_LEVEL_H264_31 },
+ { "3.2" , NV_ENC_LEVEL_H264_32 },
+ { "4" , NV_ENC_LEVEL_H264_4 },
+ { "4.0" , NV_ENC_LEVEL_H264_4 },
+ { "4.1" , NV_ENC_LEVEL_H264_41 },
+ { "4.2" , NV_ENC_LEVEL_H264_42 },
+ { "5" , NV_ENC_LEVEL_H264_5 },
+ { "5.0" , NV_ENC_LEVEL_H264_5 },
+ { "5.1" , NV_ENC_LEVEL_H264_51 },
+ { NULL }
+};
+
+static const NvencValuePair nvenc_h265_level_pairs[] = {
+ { "auto", NV_ENC_LEVEL_AUTOSELECT },
+ { "1" , NV_ENC_LEVEL_HEVC_1 },
+ { "1.0" , NV_ENC_LEVEL_HEVC_1 },
+ { "2" , NV_ENC_LEVEL_HEVC_2 },
+ { "2.0" , NV_ENC_LEVEL_HEVC_2 },
+ { "2.1" , NV_ENC_LEVEL_HEVC_21 },
+ { "3" , NV_ENC_LEVEL_HEVC_3 },
+ { "3.0" , NV_ENC_LEVEL_HEVC_3 },
+ { "3.1" , NV_ENC_LEVEL_HEVC_31 },
+ { "4" , NV_ENC_LEVEL_HEVC_4 },
+ { "4.0" , NV_ENC_LEVEL_HEVC_4 },
+ { "4.1" , NV_ENC_LEVEL_HEVC_41 },
+ { "5" , NV_ENC_LEVEL_HEVC_5 },
+ { "5.0" , NV_ENC_LEVEL_HEVC_5 },
+ { "5.1" , NV_ENC_LEVEL_HEVC_51 },
+ { "5.2" , NV_ENC_LEVEL_HEVC_52 },
+ { "6" , NV_ENC_LEVEL_HEVC_6 },
+ { "6.0" , NV_ENC_LEVEL_HEVC_6 },
+ { "6.1" , NV_ENC_LEVEL_HEVC_61 },
+ { "6.2" , NV_ENC_LEVEL_HEVC_62 },
+ { NULL }
+};
+
+static int input_string_to_uint32(AVCodecContext *avctx, const NvencValuePair *pair, const char *input, uint32_t *output)
+{
+ for (; pair->str; ++pair) {
+ if (!strcmp(input, pair->str)) {
+ *output = pair->num;
+ return 0;
+ }
+ }
+
+ return AVERROR(EINVAL);
+}
+
+static NvencData* data_queue_dequeue(NvencDataList* queue)
+{
+ uint32_t mask;
+ uint32_t read_pos;
+
+ av_assert0(queue);
+ av_assert0(queue->size);
+ av_assert0(queue->data);
+
+ if (!queue->count)
+ return NULL;
+
+ /* Size always is a multiple of two */
+ mask = queue->size - 1;
+ read_pos = (queue->pos - queue->count) & mask;
+ queue->count--;
+
+ return &queue->data[read_pos];
+}
+
+static int data_queue_enqueue(NvencDataList* queue, NvencData *data)
+{
+ NvencDataList new_queue;
+ NvencData* tmp_data;
+ uint32_t mask;
+
+ if (!queue->size) {
+ /* size always has to be a multiple of two */
+ queue->size = 4;
+ queue->pos = 0;
+ queue->count = 0;
+
+ queue->data = av_malloc(queue->size * sizeof(*(queue->data)));
+
+ if (!queue->data) {
+ queue->size = 0;
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (queue->count == queue->size) {
+ new_queue.size = queue->size << 1;
+ new_queue.pos = 0;
+ new_queue.count = 0;
+ new_queue.data = av_malloc(new_queue.size * sizeof(*(queue->data)));
+
+ if (!new_queue.data)
+ return AVERROR(ENOMEM);
+
+ while (tmp_data = data_queue_dequeue(queue))
+ data_queue_enqueue(&new_queue, tmp_data);
+
+ av_free(queue->data);
+ *queue = new_queue;
+ }
+
+ mask = queue->size - 1;
+
+ queue->data[queue->pos] = *data;
+ queue->pos = (queue->pos + 1) & mask;
+ queue->count++;
+
+ return 0;
+}
+
+static int out_surf_queue_enqueue(NvencDataList* queue, NvencOutputSurface* surface)
+{
+ NvencData data;
+ data.surface = surface;
+
+ return data_queue_enqueue(queue, &data);
+}
+
+static NvencOutputSurface* out_surf_queue_dequeue(NvencDataList* queue)
+{
+ NvencData* res = data_queue_dequeue(queue);
+
+ if (!res)
+ return NULL;
+
+ return res->surface;
+}
+
+static int timestamp_queue_enqueue(NvencDataList* queue, int64_t timestamp)
+{
+ NvencData data;
+ data.timestamp = timestamp;
+
+ return data_queue_enqueue(queue, &data);
+}
+
+static int64_t timestamp_queue_dequeue(NvencDataList* queue)
+{
+ NvencData* res = data_queue_dequeue(queue);
+
+ if (!res)
+ return AV_NOPTS_VALUE;
+
+ return res->timestamp;
+}
+
+#define CHECK_LOAD_FUNC(t, f, s) \
+do { \
+ (f) = (t)LOAD_FUNC(dl_fn->cuda_lib, s); \
+ if (!(f)) { \
+ av_log(avctx, AV_LOG_FATAL, "Failed loading %s from CUDA library\n", s); \
+ goto error; \
+ } \
+} while (0)
+
+static av_cold int nvenc_dyload_cuda(AVCodecContext *avctx)
+{
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+
+ if (dl_fn->cuda_lib)
+ return 1;
+
+#if defined(_WIN32)
+ dl_fn->cuda_lib = LoadLibrary(TEXT("nvcuda.dll"));
+#else
+ dl_fn->cuda_lib = dlopen("libcuda.so", RTLD_LAZY);
+#endif
+
+ if (!dl_fn->cuda_lib) {
+ av_log(avctx, AV_LOG_FATAL, "Failed loading CUDA library\n");
+ goto error;
+ }
+
+ CHECK_LOAD_FUNC(PCUINIT, dl_fn->cu_init, "cuInit");
+ CHECK_LOAD_FUNC(PCUDEVICEGETCOUNT, dl_fn->cu_device_get_count, "cuDeviceGetCount");
+ CHECK_LOAD_FUNC(PCUDEVICEGET, dl_fn->cu_device_get, "cuDeviceGet");
+ CHECK_LOAD_FUNC(PCUDEVICEGETNAME, dl_fn->cu_device_get_name, "cuDeviceGetName");
+ CHECK_LOAD_FUNC(PCUDEVICECOMPUTECAPABILITY, dl_fn->cu_device_compute_capability, "cuDeviceComputeCapability");
+ CHECK_LOAD_FUNC(PCUCTXCREATE, dl_fn->cu_ctx_create, "cuCtxCreate_v2");
+ CHECK_LOAD_FUNC(PCUCTXPOPCURRENT, dl_fn->cu_ctx_pop_current, "cuCtxPopCurrent_v2");
+ CHECK_LOAD_FUNC(PCUCTXDESTROY, dl_fn->cu_ctx_destroy, "cuCtxDestroy_v2");
+
+ return 1;
+
+error:
+
+ if (dl_fn->cuda_lib)
+ DL_CLOSE_FUNC(dl_fn->cuda_lib);
+
+ dl_fn->cuda_lib = NULL;
+
+ return 0;
+}
+
+static av_cold int check_cuda_errors(AVCodecContext *avctx, CUresult err, const char *func)
+{
+ if (err != CUDA_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, ">> %s - failed with error code 0x%x\n", func, err);
+ return 0;
+ }
+ return 1;
+}
+#define check_cuda_errors(f) if (!check_cuda_errors(avctx, f, #f)) goto error
+
+static av_cold int nvenc_check_cuda(AVCodecContext *avctx)
+{
+ int device_count = 0;
+ CUdevice cu_device = 0;
+ char gpu_name[128];
+ int smminor = 0, smmajor = 0;
+ int i, smver, target_smver;
+
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ target_smver = 0x30;
+ break;
+ case AV_CODEC_ID_H265:
+ target_smver = 0x52;
+ break;
+ default:
+ av_log(avctx, AV_LOG_FATAL, "nvenc: Unknown codec name\n");
+ goto error;
+ }
+
+ if (!nvenc_dyload_cuda(avctx))
+ return 0;
+
+ if (dl_fn->nvenc_device_count > 0)
+ return 1;
+
+ check_cuda_errors(dl_fn->cu_init(0));
+
+ check_cuda_errors(dl_fn->cu_device_get_count(&device_count));
+
+ if (!device_count) {
+ av_log(avctx, AV_LOG_FATAL, "No CUDA capable devices found\n");
+ goto error;
+ }
+
+ av_log(avctx, AV_LOG_VERBOSE, "%d CUDA capable devices found\n", device_count);
+
+ dl_fn->nvenc_device_count = 0;
+
+ for (i = 0; i < device_count; ++i) {
+ check_cuda_errors(dl_fn->cu_device_get(&cu_device, i));
+ check_cuda_errors(dl_fn->cu_device_get_name(gpu_name, sizeof(gpu_name), cu_device));
+ check_cuda_errors(dl_fn->cu_device_compute_capability(&smmajor, &smminor, cu_device));
+
+ smver = (smmajor << 4) | smminor;
+
+ av_log(avctx, AV_LOG_VERBOSE, "[ GPU #%d - < %s > has Compute SM %d.%d, NVENC %s ]\n", i, gpu_name, smmajor, smminor, (smver >= target_smver) ? "Available" : "Not Available");
+
+ if (smver >= target_smver)
+ dl_fn->nvenc_devices[dl_fn->nvenc_device_count++] = cu_device;
+ }
+
+ if (!dl_fn->nvenc_device_count) {
+ av_log(avctx, AV_LOG_FATAL, "No NVENC capable devices found\n");
+ goto error;
+ }
+
+ return 1;
+
+error:
+
+ dl_fn->nvenc_device_count = 0;
+
+ return 0;
+}
+
+static av_cold int nvenc_dyload_nvenc(AVCodecContext *avctx)
+{
+ PNVENCODEAPICREATEINSTANCE nvEncodeAPICreateInstance = 0;
+ NVENCSTATUS nvstatus;
+
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+
+ if (!nvenc_check_cuda(avctx))
+ return 0;
+
+ if (dl_fn->nvenc_lib)
+ return 1;
+
+#if defined(_WIN32)
+ if (sizeof(void*) == 8) {
+ dl_fn->nvenc_lib = LoadLibrary(TEXT("nvEncodeAPI64.dll"));
+ } else {
+ dl_fn->nvenc_lib = LoadLibrary(TEXT("nvEncodeAPI.dll"));
+ }
+#else
+ dl_fn->nvenc_lib = dlopen("libnvidia-encode.so.1", RTLD_LAZY);
+#endif
+
+ if (!dl_fn->nvenc_lib) {
+ av_log(avctx, AV_LOG_FATAL, "Failed loading the nvenc library\n");
+ goto error;
+ }
+
+ nvEncodeAPICreateInstance = (PNVENCODEAPICREATEINSTANCE)LOAD_FUNC(dl_fn->nvenc_lib, "NvEncodeAPICreateInstance");
+
+ if (!nvEncodeAPICreateInstance) {
+ av_log(avctx, AV_LOG_FATAL, "Failed to load nvenc entrypoint\n");
+ goto error;
+ }
+
+ dl_fn->nvenc_funcs.version = NV_ENCODE_API_FUNCTION_LIST_VER;
+
+ nvstatus = nvEncodeAPICreateInstance(&dl_fn->nvenc_funcs);
+
+ if (nvstatus != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "Failed to create nvenc instance\n");
+ goto error;
+ }
+
+ av_log(avctx, AV_LOG_VERBOSE, "Nvenc initialized successfully\n");
+
+ return 1;
+
+error:
+ if (dl_fn->nvenc_lib)
+ DL_CLOSE_FUNC(dl_fn->nvenc_lib);
+
+ dl_fn->nvenc_lib = NULL;
+
+ return 0;
+}
+
+static av_cold void nvenc_unload_nvenc(AVCodecContext *avctx)
+{
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+
+ DL_CLOSE_FUNC(dl_fn->nvenc_lib);
+ dl_fn->nvenc_lib = NULL;
+
+ dl_fn->nvenc_device_count = 0;
+
+ DL_CLOSE_FUNC(dl_fn->cuda_lib);
+ dl_fn->cuda_lib = NULL;
+
+ dl_fn->cu_init = NULL;
+ dl_fn->cu_device_get_count = NULL;
+ dl_fn->cu_device_get = NULL;
+ dl_fn->cu_device_get_name = NULL;
+ dl_fn->cu_device_compute_capability = NULL;
+ dl_fn->cu_ctx_create = NULL;
+ dl_fn->cu_ctx_pop_current = NULL;
+ dl_fn->cu_ctx_destroy = NULL;
+
+ av_log(avctx, AV_LOG_VERBOSE, "Nvenc unloaded\n");
+}
+
+static av_cold int nvenc_encode_init(AVCodecContext *avctx)
+{
+ NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS encode_session_params = { 0 };
+ NV_ENC_PRESET_CONFIG preset_config = { 0 };
+ CUcontext cu_context_curr;
+ CUresult cu_res;
+ GUID encoder_preset = NV_ENC_PRESET_HQ_GUID;
+ GUID codec;
+ NVENCSTATUS nv_status = NV_ENC_SUCCESS;
+ int surfaceCount = 0;
+ int i, num_mbs;
+ int isLL = 0;
+ int res = 0;
+ int dw, dh;
+
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+ NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
+
+ if (!nvenc_dyload_nvenc(avctx))
+ return AVERROR_EXTERNAL;
+
+ avctx->coded_frame = av_frame_alloc();
+ if (!avctx->coded_frame) {
+ res = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ ctx->last_dts = AV_NOPTS_VALUE;
+
+ ctx->encode_config.version = NV_ENC_CONFIG_VER;
+ ctx->init_encode_params.version = NV_ENC_INITIALIZE_PARAMS_VER;
+ preset_config.version = NV_ENC_PRESET_CONFIG_VER;
+ preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
+ encode_session_params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
+ encode_session_params.apiVersion = NVENCAPI_VERSION;
+
+ if (ctx->gpu >= dl_fn->nvenc_device_count) {
+ av_log(avctx, AV_LOG_FATAL, "Requested GPU %d, but only %d GPUs are available!\n", ctx->gpu, dl_fn->nvenc_device_count);
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+
+ ctx->cu_context = NULL;
+ cu_res = dl_fn->cu_ctx_create(&ctx->cu_context, 0, dl_fn->nvenc_devices[ctx->gpu]);
+
+ if (cu_res != CUDA_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "Failed creating CUDA context for NVENC: 0x%x\n", (int)cu_res);
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ cu_res = dl_fn->cu_ctx_pop_current(&cu_context_curr);
+
+ if (cu_res != CUDA_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "Failed popping CUDA context: 0x%x\n", (int)cu_res);
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ encode_session_params.device = ctx->cu_context;
+ encode_session_params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
+
+ nv_status = p_nvenc->nvEncOpenEncodeSessionEx(&encode_session_params, &ctx->nvencoder);
+ if (nv_status != NV_ENC_SUCCESS) {
+ ctx->nvencoder = NULL;
+ av_log(avctx, AV_LOG_FATAL, "OpenEncodeSessionEx failed: 0x%x - invalid license key?\n", (int)nv_status);
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ if (ctx->preset) {
+ if (!strcmp(ctx->preset, "hp")) {
+ encoder_preset = NV_ENC_PRESET_HP_GUID;
+ } else if (!strcmp(ctx->preset, "hq")) {
+ encoder_preset = NV_ENC_PRESET_HQ_GUID;
+ } else if (!strcmp(ctx->preset, "bd")) {
+ encoder_preset = NV_ENC_PRESET_BD_GUID;
+ } else if (!strcmp(ctx->preset, "ll")) {
+ encoder_preset = NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID;
+ isLL = 1;
+ } else if (!strcmp(ctx->preset, "llhp")) {
+ encoder_preset = NV_ENC_PRESET_LOW_LATENCY_HP_GUID;
+ isLL = 1;
+ } else if (!strcmp(ctx->preset, "llhq")) {
+ encoder_preset = NV_ENC_PRESET_LOW_LATENCY_HQ_GUID;
+ isLL = 1;
+ } else if (!strcmp(ctx->preset, "default")) {
+ encoder_preset = NV_ENC_PRESET_DEFAULT_GUID;
+ } else {
+ av_log(avctx, AV_LOG_FATAL, "Preset \"%s\" is unknown! Supported presets: hp, hq, bd, ll, llhp, llhq, default\n", ctx->preset);
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+ }
+
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ codec = NV_ENC_CODEC_H264_GUID;
+ break;
+ case AV_CODEC_ID_H265:
+ codec = NV_ENC_CODEC_HEVC_GUID;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "nvenc: Unknown codec name\n");
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+
+ nv_status = p_nvenc->nvEncGetEncodePresetConfig(ctx->nvencoder, codec, encoder_preset, &preset_config);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "GetEncodePresetConfig failed: 0x%x\n", (int)nv_status);
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ ctx->init_encode_params.encodeGUID = codec;
+ ctx->init_encode_params.encodeHeight = avctx->height;
+ ctx->init_encode_params.encodeWidth = avctx->width;
+
+ if (avctx->sample_aspect_ratio.num && avctx->sample_aspect_ratio.den &&
+ (avctx->sample_aspect_ratio.num != 1 || avctx->sample_aspect_ratio.num != 1)) {
+ av_reduce(&dw, &dh,
+ avctx->width * avctx->sample_aspect_ratio.num,
+ avctx->height * avctx->sample_aspect_ratio.den,
+ 1024 * 1024);
+ ctx->init_encode_params.darHeight = dh;
+ ctx->init_encode_params.darWidth = dw;
+ } else {
+ ctx->init_encode_params.darHeight = avctx->height;
+ ctx->init_encode_params.darWidth = avctx->width;
+ }
+
+ // De-compensate for hardware, dubiously, trying to compensate for
+ // playback at 704 pixel width.
+ if (avctx->width == 720 &&
+ (avctx->height == 480 || avctx->height == 576)) {
+ av_reduce(&dw, &dh,
+ ctx->init_encode_params.darWidth * 44,
+ ctx->init_encode_params.darHeight * 45,
+ 1024 * 1204);
+ ctx->init_encode_params.darHeight = dh;
+ ctx->init_encode_params.darWidth = dw;
+ }
+
+ ctx->init_encode_params.frameRateNum = avctx->time_base.den;
+ ctx->init_encode_params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
+
+ num_mbs = ((avctx->width + 15) >> 4) * ((avctx->height + 15) >> 4);
+ ctx->max_surface_count = (num_mbs >= 8160) ? 32 : 48;
+
+ ctx->init_encode_params.enableEncodeAsync = 0;
+ ctx->init_encode_params.enablePTD = 1;
+
+ ctx->init_encode_params.presetGUID = encoder_preset;
+
+ ctx->init_encode_params.encodeConfig = &ctx->encode_config;
+ memcpy(&ctx->encode_config, &preset_config.presetCfg, sizeof(ctx->encode_config));
+ ctx->encode_config.version = NV_ENC_CONFIG_VER;
+
+ if (avctx->refs >= 0) {
+ /* 0 means "let the hardware decide" */
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ ctx->encode_config.encodeCodecConfig.h264Config.maxNumRefFrames = avctx->refs;
+ break;
+ case AV_CODEC_ID_H265:
+ ctx->encode_config.encodeCodecConfig.hevcConfig.maxNumRefFramesInDPB = avctx->refs;
+ break;
+ /* Earlier switch/case will return if unknown codec is passed. */
+ }
+ }
+
+ if (avctx->gop_size > 0) {
+ if (avctx->max_b_frames >= 0) {
+ /* 0 is intra-only, 1 is I/P only, 2 is one B Frame, 3 two B frames, and so on. */
+ ctx->encode_config.frameIntervalP = avctx->max_b_frames + 1;
+ }
+
+ ctx->encode_config.gopLength = avctx->gop_size;
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ ctx->encode_config.encodeCodecConfig.h264Config.idrPeriod = avctx->gop_size;
+ break;
+ case AV_CODEC_ID_H265:
+ ctx->encode_config.encodeCodecConfig.hevcConfig.idrPeriod = avctx->gop_size;
+ break;
+ /* Earlier switch/case will return if unknown codec is passed. */
+ }
+ } else if (avctx->gop_size == 0) {
+ ctx->encode_config.frameIntervalP = 0;
+ ctx->encode_config.gopLength = 1;
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ ctx->encode_config.encodeCodecConfig.h264Config.idrPeriod = 1;
+ break;
+ case AV_CODEC_ID_H265:
+ ctx->encode_config.encodeCodecConfig.hevcConfig.idrPeriod = 1;
+ break;
+ /* Earlier switch/case will return if unknown codec is passed. */
+ }
+ }
+
+ /* when there're b frames, set dts offset */
+ if (ctx->encode_config.frameIntervalP >= 2)
+ ctx->last_dts = -2;
+
+ if (avctx->bit_rate > 0)
+ ctx->encode_config.rcParams.averageBitRate = avctx->bit_rate;
+
+ if (avctx->rc_max_rate > 0)
+ ctx->encode_config.rcParams.maxBitRate = avctx->rc_max_rate;
+
+ if (ctx->cbr) {
+ if (!ctx->twopass) {
+ ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
+ } else if (ctx->twopass == 1 || isLL) {
+ ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_2_PASS_QUALITY;
+
+ if (avctx->codec->id == AV_CODEC_ID_H264) {
+ ctx->encode_config.encodeCodecConfig.h264Config.adaptiveTransformMode = NV_ENC_H264_ADAPTIVE_TRANSFORM_ENABLE;
+ ctx->encode_config.encodeCodecConfig.h264Config.fmoMode = NV_ENC_H264_FMO_DISABLE;
+ }
+
+ if (!isLL)
+ av_log(avctx, AV_LOG_WARNING, "Twopass mode is only known to work with low latency (ll, llhq, llhp) presets.\n");
+ } else {
+ ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR;
+ }
+ } else if (avctx->global_quality > 0) {
+ ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CONSTQP;
+ ctx->encode_config.rcParams.constQP.qpInterB = avctx->global_quality;
+ ctx->encode_config.rcParams.constQP.qpInterP = avctx->global_quality;
+ ctx->encode_config.rcParams.constQP.qpIntra = avctx->global_quality;
+
+ avctx->qmin = -1;
+ avctx->qmax = -1;
+ } else if (avctx->qmin >= 0 && avctx->qmax >= 0) {
+ ctx->encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_VBR;
+
+ ctx->encode_config.rcParams.enableMinQP = 1;
+ ctx->encode_config.rcParams.enableMaxQP = 1;
+
+ ctx->encode_config.rcParams.minQP.qpInterB = avctx->qmin;
+ ctx->encode_config.rcParams.minQP.qpInterP = avctx->qmin;
+ ctx->encode_config.rcParams.minQP.qpIntra = avctx->qmin;
+
+ ctx->encode_config.rcParams.maxQP.qpInterB = avctx->qmax;
+ ctx->encode_config.rcParams.maxQP.qpInterP = avctx->qmax;
+ ctx->encode_config.rcParams.maxQP.qpIntra = avctx->qmax;
+ }
+
+ if (avctx->rc_buffer_size > 0)
+ ctx->encode_config.rcParams.vbvBufferSize = avctx->rc_buffer_size;
+
+ if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
+ ctx->encode_config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
+ } else {
+ ctx->encode_config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
+ }
+
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourDescriptionPresentFlag = 1;
+ ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.videoSignalTypePresentFlag = 1;
+
+ ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourMatrix = avctx->colorspace;
+ ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.colourPrimaries = avctx->color_primaries;
+ ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.transferCharacteristics = avctx->color_trc;
+
+ ctx->encode_config.encodeCodecConfig.h264Config.h264VUIParameters.videoFullRangeFlag = avctx->color_range == AVCOL_RANGE_JPEG;
+
+ ctx->encode_config.encodeCodecConfig.h264Config.disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
+ ctx->encode_config.encodeCodecConfig.h264Config.repeatSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
+
+ if (!ctx->profile) {
+ switch (avctx->profile) {
+ case FF_PROFILE_H264_BASELINE:
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
+ break;
+ case FF_PROFILE_H264_MAIN:
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
+ break;
+ case FF_PROFILE_H264_HIGH:
+ case FF_PROFILE_UNKNOWN:
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
+ break;
+ default:
+ av_log(avctx, AV_LOG_WARNING, "Unsupported profile requested, falling back to high\n");
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
+ break;
+ }
+ } else {
+ if (!strcmp(ctx->profile, "high")) {
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
+ avctx->profile = FF_PROFILE_H264_HIGH;
+ } else if (!strcmp(ctx->profile, "main")) {
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_MAIN_GUID;
+ avctx->profile = FF_PROFILE_H264_MAIN;
+ } else if (!strcmp(ctx->profile, "baseline")) {
+ ctx->encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID;
+ avctx->profile = FF_PROFILE_H264_BASELINE;
+ } else {
+ av_log(avctx, AV_LOG_FATAL, "Profile \"%s\" is unknown! Supported profiles: high, main, baseline\n", ctx->profile);
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+ }
+
+ if (ctx->level) {
+ res = input_string_to_uint32(avctx, nvenc_h264_level_pairs, ctx->level, &ctx->encode_config.encodeCodecConfig.h264Config.level);
+
+ if (res) {
+ av_log(avctx, AV_LOG_FATAL, "Level \"%s\" is unknown! Supported levels: auto, 1, 1b, 1.1, 1.2, 1.3, 2, 2.1, 2.2, 3, 3.1, 3.2, 4, 4.1, 4.2, 5, 5.1\n", ctx->level);
+ goto error;
+ }
+ } else {
+ ctx->encode_config.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_AUTOSELECT;
+ }
+
+ break;
+ case AV_CODEC_ID_H265:
+ ctx->encode_config.encodeCodecConfig.hevcConfig.disableSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 1 : 0;
+ ctx->encode_config.encodeCodecConfig.hevcConfig.repeatSPSPPS = (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) ? 0 : 1;
+
+ /* No other profile is supported in the current SDK version 5 */
+ ctx->encode_config.profileGUID = NV_ENC_HEVC_PROFILE_MAIN_GUID;
+ avctx->profile = FF_PROFILE_HEVC_MAIN;
+
+ if (ctx->level) {
+ res = input_string_to_uint32(avctx, nvenc_h265_level_pairs, ctx->level, &ctx->encode_config.encodeCodecConfig.hevcConfig.level);
+
+ if (res) {
+ av_log(avctx, AV_LOG_FATAL, "Level \"%s\" is unknown! Supported levels: auto, 1, 2, 2.1, 3, 3.1, 4, 4.1, 5, 5.1, 5.2, 6, 6.1, 6.2\n", ctx->level);
+ goto error;
+ }
+ } else {
+ ctx->encode_config.encodeCodecConfig.hevcConfig.level = NV_ENC_LEVEL_AUTOSELECT;
+ }
+
+ if (ctx->tier) {
+ if (!strcmp(ctx->tier, "main")) {
+ ctx->encode_config.encodeCodecConfig.hevcConfig.tier = NV_ENC_TIER_HEVC_MAIN;
+ } else if (!strcmp(ctx->tier, "high")) {
+ ctx->encode_config.encodeCodecConfig.hevcConfig.tier = NV_ENC_TIER_HEVC_HIGH;
+ } else {
+ av_log(avctx, AV_LOG_FATAL, "Tier \"%s\" is unknown! Supported tiers: main, high\n", ctx->tier);
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+ }
+
+ break;
+ /* Earlier switch/case will return if unknown codec is passed. */
+ }
+
+ nv_status = p_nvenc->nvEncInitializeEncoder(ctx->nvencoder, &ctx->init_encode_params);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "InitializeEncoder failed: 0x%x\n", (int)nv_status);
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ ctx->input_surfaces = av_malloc(ctx->max_surface_count * sizeof(*ctx->input_surfaces));
+
+ if (!ctx->input_surfaces) {
+ res = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ ctx->output_surfaces = av_malloc(ctx->max_surface_count * sizeof(*ctx->output_surfaces));
+
+ if (!ctx->output_surfaces) {
+ res = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ for (surfaceCount = 0; surfaceCount < ctx->max_surface_count; ++surfaceCount) {
+ NV_ENC_CREATE_INPUT_BUFFER allocSurf = { 0 };
+ NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 };
+ allocSurf.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
+ allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
+
+ allocSurf.width = (avctx->width + 31) & ~31;
+ allocSurf.height = (avctx->height + 31) & ~31;
+
+ allocSurf.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
+
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_YUV420P:
+ allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_YV12_PL;
+ break;
+
+ case AV_PIX_FMT_NV12:
+ allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12_PL;
+ break;
+
+ case AV_PIX_FMT_YUV444P:
+ allocSurf.bufferFmt = NV_ENC_BUFFER_FORMAT_YUV444_PL;
+ break;
+
+ default:
+ av_log(avctx, AV_LOG_FATAL, "Invalid input pixel format\n");
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+
+ nv_status = p_nvenc->nvEncCreateInputBuffer(ctx->nvencoder, &allocSurf);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "CreateInputBuffer failed\n");
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ ctx->input_surfaces[surfaceCount].lockCount = 0;
+ ctx->input_surfaces[surfaceCount].input_surface = allocSurf.inputBuffer;
+ ctx->input_surfaces[surfaceCount].format = allocSurf.bufferFmt;
+ ctx->input_surfaces[surfaceCount].width = allocSurf.width;
+ ctx->input_surfaces[surfaceCount].height = allocSurf.height;
+
+ /* 1MB is large enough to hold most output frames. NVENC increases this automaticaly if it's not enough. */
+ allocOut.size = 1024 * 1024;
+
+ allocOut.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_CACHED;
+
+ nv_status = p_nvenc->nvEncCreateBitstreamBuffer(ctx->nvencoder, &allocOut);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "CreateBitstreamBuffer failed\n");
+ ctx->output_surfaces[surfaceCount++].output_surface = NULL;
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ ctx->output_surfaces[surfaceCount].output_surface = allocOut.bitstreamBuffer;
+ ctx->output_surfaces[surfaceCount].size = allocOut.size;
+ ctx->output_surfaces[surfaceCount].busy = 0;
+ }
+
+ if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+ uint32_t outSize = 0;
+ char tmpHeader[256];
+ NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = { 0 };
+ payload.version = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER;
+
+ payload.spsppsBuffer = tmpHeader;
+ payload.inBufferSize = sizeof(tmpHeader);
+ payload.outSPSPPSPayloadSize = &outSize;
+
+ nv_status = p_nvenc->nvEncGetSequenceParams(ctx->nvencoder, &payload);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "GetSequenceParams failed\n");
+ goto error;
+ }
+
+ avctx->extradata_size = outSize;
+ avctx->extradata = av_mallocz(outSize + FF_INPUT_BUFFER_PADDING_SIZE);
+
+ if (!avctx->extradata) {
+ res = AVERROR(ENOMEM);
+ goto error;
+ }
+
+ memcpy(avctx->extradata, tmpHeader, outSize);
+ }
+
+ if (ctx->encode_config.frameIntervalP > 1)
+ avctx->has_b_frames = 2;
+
+ if (ctx->encode_config.rcParams.averageBitRate > 0)
+ avctx->bit_rate = ctx->encode_config.rcParams.averageBitRate;
+
+ return 0;
+
+error:
+
+ for (i = 0; i < surfaceCount; ++i) {
+ p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->input_surfaces[i].input_surface);
+ if (ctx->output_surfaces[i].output_surface)
+ p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->output_surfaces[i].output_surface);
+ }
+
+ if (ctx->nvencoder)
+ p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
+
+ if (ctx->cu_context)
+ dl_fn->cu_ctx_destroy(ctx->cu_context);
+
+ av_frame_free(&avctx->coded_frame);
+
+ nvenc_unload_nvenc(avctx);
+
+ ctx->nvencoder = NULL;
+ ctx->cu_context = NULL;
+
+ return res;
+}
+
+static av_cold int nvenc_encode_close(AVCodecContext *avctx)
+{
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+ NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
+ int i;
+
+ av_freep(&ctx->timestamp_list.data);
+ av_freep(&ctx->output_surface_ready_queue.data);
+ av_freep(&ctx->output_surface_queue.data);
+
+ for (i = 0; i < ctx->max_surface_count; ++i) {
+ p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->input_surfaces[i].input_surface);
+ p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->output_surfaces[i].output_surface);
+ }
+ ctx->max_surface_count = 0;
+
+ p_nvenc->nvEncDestroyEncoder(ctx->nvencoder);
+ ctx->nvencoder = NULL;
+
+ dl_fn->cu_ctx_destroy(ctx->cu_context);
+ ctx->cu_context = NULL;
+
+ nvenc_unload_nvenc(avctx);
+
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, AVFrame *coded_frame, NvencOutputSurface *tmpoutsurf)
+{
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+ NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
+
+ uint32_t slice_mode_data;
+ uint32_t *slice_offsets;
+ NV_ENC_LOCK_BITSTREAM lock_params = { 0 };
+ NVENCSTATUS nv_status;
+ int res = 0;
+
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ slice_mode_data = ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData;
+ break;
+ case AV_CODEC_ID_H265:
+ slice_mode_data = ctx->encode_config.encodeCodecConfig.hevcConfig.sliceModeData;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "nvenc: Unknown codec name\n");
+ res = AVERROR(EINVAL);
+ goto error;
+ }
+ slice_offsets = av_mallocz(slice_mode_data * sizeof(*slice_offsets));
+
+ if (!slice_offsets)
+ return AVERROR(ENOMEM);
+
+ lock_params.version = NV_ENC_LOCK_BITSTREAM_VER;
+
+ lock_params.doNotWait = 0;
+ lock_params.outputBitstream = tmpoutsurf->output_surface;
+ lock_params.sliceOffsets = slice_offsets;
+
+ nv_status = p_nvenc->nvEncLockBitstream(ctx->nvencoder, &lock_params);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed locking bitstream buffer\n");
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ if (res = ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes)) {
+ p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
+ goto error;
+ }
+
+ memcpy(pkt->data, lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes);
+
+ nv_status = p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
+ if (nv_status != NV_ENC_SUCCESS)
+ av_log(avctx, AV_LOG_ERROR, "Failed unlocking bitstream buffer, expect the gates of mordor to open\n");
+
+ switch (lock_params.pictureType) {
+ case NV_ENC_PIC_TYPE_IDR:
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ case NV_ENC_PIC_TYPE_I:
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ break;
+ case NV_ENC_PIC_TYPE_P:
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P;
+ break;
+ case NV_ENC_PIC_TYPE_B:
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B;
+ break;
+ case NV_ENC_PIC_TYPE_BI:
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_BI;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unknown picture type encountered, expect the output to be broken.\n");
+ av_log(avctx, AV_LOG_ERROR, "Please report this error and include as much information on how to reproduce it as possible.\n");
+ res = AVERROR_EXTERNAL;
+ goto error;
+ }
+
+ pkt->pts = lock_params.outputTimeStamp;
+ pkt->dts = timestamp_queue_dequeue(&ctx->timestamp_list);
+
+ /* when there're b frame(s), set dts offset */
+ if (ctx->encode_config.frameIntervalP >= 2)
+ pkt->dts -= 1;
+
+ if (pkt->dts > pkt->pts)
+ pkt->dts = pkt->pts;
+
+ if (ctx->last_dts != AV_NOPTS_VALUE && pkt->dts <= ctx->last_dts)
+ pkt->dts = ctx->last_dts + 1;
+
+ ctx->last_dts = pkt->dts;
+
+ av_free(slice_offsets);
+
+ return 0;
+
+error:
+
+ av_free(slice_offsets);
+ timestamp_queue_dequeue(&ctx->timestamp_list);
+
+ return res;
+}
+
+static int nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ NVENCSTATUS nv_status;
+ NvencOutputSurface *tmpoutsurf;
+ int res, i = 0;
+
+ NvencContext *ctx = avctx->priv_data;
+ NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs;
+ NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs;
+
+ NV_ENC_PIC_PARAMS pic_params = { 0 };
+ pic_params.version = NV_ENC_PIC_PARAMS_VER;
+
+ if (frame) {
+ NV_ENC_LOCK_INPUT_BUFFER lockBufferParams = { 0 };
+ NvencInputSurface *inSurf = NULL;
+
+ for (i = 0; i < ctx->max_surface_count; ++i) {
+ if (!ctx->input_surfaces[i].lockCount) {
+ inSurf = &ctx->input_surfaces[i];
+ break;
+ }
+ }
+
+ av_assert0(inSurf);
+
+ inSurf->lockCount = 1;
+
+ lockBufferParams.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
+ lockBufferParams.inputBuffer = inSurf->input_surface;
+
+ nv_status = p_nvenc->nvEncLockInputBuffer(ctx->nvencoder, &lockBufferParams);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed locking nvenc input buffer\n");
+ return 0;
+ }
+
+ if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) {
+ uint8_t *buf = lockBufferParams.bufferDataPtr;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch,
+ frame->data[0], frame->linesize[0],
+ avctx->width, avctx->height);
+
+ buf += inSurf->height * lockBufferParams.pitch;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch >> 1,
+ frame->data[2], frame->linesize[2],
+ avctx->width >> 1, avctx->height >> 1);
+
+ buf += (inSurf->height * lockBufferParams.pitch) >> 2;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch >> 1,
+ frame->data[1], frame->linesize[1],
+ avctx->width >> 1, avctx->height >> 1);
+ } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) {
+ uint8_t *buf = lockBufferParams.bufferDataPtr;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch,
+ frame->data[0], frame->linesize[0],
+ avctx->width, avctx->height);
+
+ buf += inSurf->height * lockBufferParams.pitch;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch,
+ frame->data[1], frame->linesize[1],
+ avctx->width, avctx->height >> 1);
+ } else if (avctx->pix_fmt == AV_PIX_FMT_YUV444P) {
+ uint8_t *buf = lockBufferParams.bufferDataPtr;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch,
+ frame->data[0], frame->linesize[0],
+ avctx->width, avctx->height);
+
+ buf += inSurf->height * lockBufferParams.pitch;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch,
+ frame->data[1], frame->linesize[1],
+ avctx->width, avctx->height);
+
+ buf += inSurf->height * lockBufferParams.pitch;
+
+ av_image_copy_plane(buf, lockBufferParams.pitch,
+ frame->data[2], frame->linesize[2],
+ avctx->width, avctx->height);
+ } else {
+ av_log(avctx, AV_LOG_FATAL, "Invalid pixel format!\n");
+ return AVERROR(EINVAL);
+ }
+
+ nv_status = p_nvenc->nvEncUnlockInputBuffer(ctx->nvencoder, inSurf->input_surface);
+ if (nv_status != NV_ENC_SUCCESS) {
+ av_log(avctx, AV_LOG_FATAL, "Failed unlocking input buffer!\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ for (i = 0; i < ctx->max_surface_count; ++i)
+ if (!ctx->output_surfaces[i].busy)
+ break;
+
+ if (i == ctx->max_surface_count) {
+ inSurf->lockCount = 0;
+ av_log(avctx, AV_LOG_FATAL, "No free output surface found!\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ ctx->output_surfaces[i].input_surface = inSurf;
+
+ pic_params.inputBuffer = inSurf->input_surface;
+ pic_params.bufferFmt = inSurf->format;
+ pic_params.inputWidth = avctx->width;
+ pic_params.inputHeight = avctx->height;
+ pic_params.outputBitstream = ctx->output_surfaces[i].output_surface;
+ pic_params.completionEvent = 0;
+
+ if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
+ if (frame->top_field_first) {
+ pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
+ } else {
+ pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
+ }
+ } else {
+ pic_params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
+ }
+
+ pic_params.encodePicFlags = 0;
+ pic_params.inputTimeStamp = frame->pts;
+ pic_params.inputDuration = 0;
+ switch (avctx->codec->id) {
+ case AV_CODEC_ID_H264:
+ pic_params.codecPicParams.h264PicParams.sliceMode = ctx->encode_config.encodeCodecConfig.h264Config.sliceMode;
+ pic_params.codecPicParams.h264PicParams.sliceModeData = ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData;
+ break;
+ case AV_CODEC_ID_H265:
+ pic_params.codecPicParams.hevcPicParams.sliceMode = ctx->encode_config.encodeCodecConfig.hevcConfig.sliceMode;
+ pic_params.codecPicParams.hevcPicParams.sliceModeData = ctx->encode_config.encodeCodecConfig.hevcConfig.sliceModeData;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "nvenc: Unknown codec name\n");
+ return AVERROR(EINVAL);
+ }
+
+ res = timestamp_queue_enqueue(&ctx->timestamp_list, frame->pts);
+
+ if (res)
+ return res;
+ } else {
+ pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
+ }
+
+ nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params);
+
+ if (frame && nv_status == NV_ENC_ERR_NEED_MORE_INPUT) {
+ res = out_surf_queue_enqueue(&ctx->output_surface_queue, &ctx->output_surfaces[i]);
+
+ if (res)
+ return res;
+
+ ctx->output_surfaces[i].busy = 1;
+ }
+
+ if (nv_status != NV_ENC_SUCCESS && nv_status != NV_ENC_ERR_NEED_MORE_INPUT) {
+ av_log(avctx, AV_LOG_ERROR, "EncodePicture failed!\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if (nv_status != NV_ENC_ERR_NEED_MORE_INPUT) {
+ while (ctx->output_surface_queue.count) {
+ tmpoutsurf = out_surf_queue_dequeue(&ctx->output_surface_queue);
+ res = out_surf_queue_enqueue(&ctx->output_surface_ready_queue, tmpoutsurf);
+
+ if (res)
+ return res;
+ }
+
+ if (frame) {
+ res = out_surf_queue_enqueue(&ctx->output_surface_ready_queue, &ctx->output_surfaces[i]);
+
+ if (res)
+ return res;
+
+ ctx->output_surfaces[i].busy = 1;
+ }
+ }
+
+ if (ctx->output_surface_ready_queue.count) {
+ tmpoutsurf = out_surf_queue_dequeue(&ctx->output_surface_ready_queue);
+
+ res = process_output_surface(avctx, pkt, avctx->coded_frame, tmpoutsurf);
+
+ if (res)
+ return res;
+
+ tmpoutsurf->busy = 0;
+ av_assert0(tmpoutsurf->input_surface->lockCount);
+ tmpoutsurf->input_surface->lockCount--;
+
+ *got_packet = 1;
+ } else {
+ *got_packet = 0;
+ }
+
+ return 0;
+}
+
+static const enum AVPixelFormat pix_fmts_nvenc[] = {
+ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_NONE
+};
+
+#define OFFSET(x) offsetof(NvencContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "preset", "Set the encoding preset (one of hq, hp, bd, ll, llhq, llhp, default)", OFFSET(preset), AV_OPT_TYPE_STRING, { .str = "hq" }, 0, 0, VE },
+ { "profile", "Set the encoding profile (high, main or baseline)", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
+ { "level", "Set the encoding level restriction (auto, 1.0, 1.0b, 1.1, 1.2, ..., 4.2, 5.0, 5.1)", OFFSET(level), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
+ { "tier", "Set the encoding tier (main or high)", OFFSET(tier), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
+ { "cbr", "Use cbr encoding mode", OFFSET(cbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "2pass", "Use 2pass cbr encoding mode (low latency mode only)", OFFSET(twopass), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE },
+ { "gpu", "Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on.", OFFSET(gpu), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
+ { NULL }
+};
+
+static const AVCodecDefault nvenc_defaults[] = {
+ { "b", "0" },
+ { "qmin", "-1" },
+ { "qmax", "-1" },
+ { "qdiff", "-1" },
+ { "qblur", "-1" },
+ { "qcomp", "-1" },
+ { NULL },
+};
+
+#if CONFIG_NVENC_ENCODER
+static const AVClass nvenc_class = {
+ .class_name = "nvenc",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_nvenc_encoder = {
+ .name = "nvenc",
+ .long_name = NULL_IF_CONFIG_SMALL("Nvidia NVENC h264 encoder"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(NvencContext),
+ .init = nvenc_encode_init,
+ .encode2 = nvenc_encode_frame,
+ .close = nvenc_encode_close,
+ .capabilities = CODEC_CAP_DELAY,
+ .priv_class = &nvenc_class,
+ .defaults = nvenc_defaults,
+ .pix_fmts = pix_fmts_nvenc,
+};
+#endif
+
+#if CONFIG_NVENC_H265_ENCODER
+static const AVClass nvenc_h265_class = {
+ .class_name = "nvenc_h265",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_nvenc_h265_encoder = {
+ .name = "nvenc_h265",
+ .long_name = NULL_IF_CONFIG_SMALL("Nvidia NVENC h265 encoder"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H265,
+ .priv_data_size = sizeof(NvencContext),
+ .init = nvenc_encode_init,
+ .encode2 = nvenc_encode_frame,
+ .close = nvenc_encode_close,
+ .capabilities = CODEC_CAP_DELAY,
+ .priv_class = &nvenc_h265_class,
+ .defaults = nvenc_defaults,
+ .pix_fmts = pix_fmts_nvenc,
+};
+#endif
diff --git a/libavcodec/old_codec_ids.h b/libavcodec/old_codec_ids.h
new file mode 100644
index 0000000000..c7aa0e0a12
--- /dev/null
+++ b/libavcodec/old_codec_ids.h
@@ -0,0 +1,397 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_OLD_CODEC_IDS_H
+#define AVCODEC_OLD_CODEC_IDS_H
+
+/*
+ * This header exists to prevent new codec IDs from being accidentally added to
+ * the deprecated list.
+ * Do not include it directly. It will be removed on next major bump
+ *
+ * Do not add new items to this list. Use the AVCodecID enum instead.
+ */
+
+ CODEC_ID_NONE = AV_CODEC_ID_NONE,
+
+ /* video codecs */
+ CODEC_ID_MPEG1VIDEO,
+ CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding
+#if FF_API_XVMC
+ CODEC_ID_MPEG2VIDEO_XVMC,
+#endif
+ CODEC_ID_H261,
+ CODEC_ID_H263,
+ CODEC_ID_RV10,
+ CODEC_ID_RV20,
+ CODEC_ID_MJPEG,
+ CODEC_ID_MJPEGB,
+ CODEC_ID_LJPEG,
+ CODEC_ID_SP5X,
+ CODEC_ID_JPEGLS,
+ CODEC_ID_MPEG4,
+ CODEC_ID_RAWVIDEO,
+ CODEC_ID_MSMPEG4V1,
+ CODEC_ID_MSMPEG4V2,
+ CODEC_ID_MSMPEG4V3,
+ CODEC_ID_WMV1,
+ CODEC_ID_WMV2,
+ CODEC_ID_H263P,
+ CODEC_ID_H263I,
+ CODEC_ID_FLV1,
+ CODEC_ID_SVQ1,
+ CODEC_ID_SVQ3,
+ CODEC_ID_DVVIDEO,
+ CODEC_ID_HUFFYUV,
+ CODEC_ID_CYUV,
+ CODEC_ID_H264,
+ CODEC_ID_INDEO3,
+ CODEC_ID_VP3,
+ CODEC_ID_THEORA,
+ CODEC_ID_ASV1,
+ CODEC_ID_ASV2,
+ CODEC_ID_FFV1,
+ CODEC_ID_4XM,
+ CODEC_ID_VCR1,
+ CODEC_ID_CLJR,
+ CODEC_ID_MDEC,
+ CODEC_ID_ROQ,
+ CODEC_ID_INTERPLAY_VIDEO,
+ CODEC_ID_XAN_WC3,
+ CODEC_ID_XAN_WC4,
+ CODEC_ID_RPZA,
+ CODEC_ID_CINEPAK,
+ CODEC_ID_WS_VQA,
+ CODEC_ID_MSRLE,
+ CODEC_ID_MSVIDEO1,
+ CODEC_ID_IDCIN,
+ CODEC_ID_8BPS,
+ CODEC_ID_SMC,
+ CODEC_ID_FLIC,
+ CODEC_ID_TRUEMOTION1,
+ CODEC_ID_VMDVIDEO,
+ CODEC_ID_MSZH,
+ CODEC_ID_ZLIB,
+ CODEC_ID_QTRLE,
+ CODEC_ID_TSCC,
+ CODEC_ID_ULTI,
+ CODEC_ID_QDRAW,
+ CODEC_ID_VIXL,
+ CODEC_ID_QPEG,
+ CODEC_ID_PNG,
+ CODEC_ID_PPM,
+ CODEC_ID_PBM,
+ CODEC_ID_PGM,
+ CODEC_ID_PGMYUV,
+ CODEC_ID_PAM,
+ CODEC_ID_FFVHUFF,
+ CODEC_ID_RV30,
+ CODEC_ID_RV40,
+ CODEC_ID_VC1,
+ CODEC_ID_WMV3,
+ CODEC_ID_LOCO,
+ CODEC_ID_WNV1,
+ CODEC_ID_AASC,
+ CODEC_ID_INDEO2,
+ CODEC_ID_FRAPS,
+ CODEC_ID_TRUEMOTION2,
+ CODEC_ID_BMP,
+ CODEC_ID_CSCD,
+ CODEC_ID_MMVIDEO,
+ CODEC_ID_ZMBV,
+ CODEC_ID_AVS,
+ CODEC_ID_SMACKVIDEO,
+ CODEC_ID_NUV,
+ CODEC_ID_KMVC,
+ CODEC_ID_FLASHSV,
+ CODEC_ID_CAVS,
+ CODEC_ID_JPEG2000,
+ CODEC_ID_VMNC,
+ CODEC_ID_VP5,
+ CODEC_ID_VP6,
+ CODEC_ID_VP6F,
+ CODEC_ID_TARGA,
+ CODEC_ID_DSICINVIDEO,
+ CODEC_ID_TIERTEXSEQVIDEO,
+ CODEC_ID_TIFF,
+ CODEC_ID_GIF,
+ CODEC_ID_DXA,
+ CODEC_ID_DNXHD,
+ CODEC_ID_THP,
+ CODEC_ID_SGI,
+ CODEC_ID_C93,
+ CODEC_ID_BETHSOFTVID,
+ CODEC_ID_PTX,
+ CODEC_ID_TXD,
+ CODEC_ID_VP6A,
+ CODEC_ID_AMV,
+ CODEC_ID_VB,
+ CODEC_ID_PCX,
+ CODEC_ID_SUNRAST,
+ CODEC_ID_INDEO4,
+ CODEC_ID_INDEO5,
+ CODEC_ID_MIMIC,
+ CODEC_ID_RL2,
+ CODEC_ID_ESCAPE124,
+ CODEC_ID_DIRAC,
+ CODEC_ID_BFI,
+ CODEC_ID_CMV,
+ CODEC_ID_MOTIONPIXELS,
+ CODEC_ID_TGV,
+ CODEC_ID_TGQ,
+ CODEC_ID_TQI,
+ CODEC_ID_AURA,
+ CODEC_ID_AURA2,
+ CODEC_ID_V210X,
+ CODEC_ID_TMV,
+ CODEC_ID_V210,
+ CODEC_ID_DPX,
+ CODEC_ID_MAD,
+ CODEC_ID_FRWU,
+ CODEC_ID_FLASHSV2,
+ CODEC_ID_CDGRAPHICS,
+ CODEC_ID_R210,
+ CODEC_ID_ANM,
+ CODEC_ID_BINKVIDEO,
+ CODEC_ID_IFF_ILBM,
+ CODEC_ID_IFF_BYTERUN1,
+ CODEC_ID_KGV1,
+ CODEC_ID_YOP,
+ CODEC_ID_VP8,
+ CODEC_ID_PICTOR,
+ CODEC_ID_ANSI,
+ CODEC_ID_A64_MULTI,
+ CODEC_ID_A64_MULTI5,
+ CODEC_ID_R10K,
+ CODEC_ID_MXPEG,
+ CODEC_ID_LAGARITH,
+ CODEC_ID_PRORES,
+ CODEC_ID_JV,
+ CODEC_ID_DFA,
+ CODEC_ID_WMV3IMAGE,
+ CODEC_ID_VC1IMAGE,
+ CODEC_ID_UTVIDEO,
+ CODEC_ID_BMV_VIDEO,
+ CODEC_ID_VBLE,
+ CODEC_ID_DXTORY,
+ CODEC_ID_V410,
+ CODEC_ID_XWD,
+ CODEC_ID_CDXL,
+ CODEC_ID_XBM,
+ CODEC_ID_ZEROCODEC,
+ CODEC_ID_MSS1,
+ CODEC_ID_MSA1,
+ CODEC_ID_TSCC2,
+ CODEC_ID_MTS2,
+ CODEC_ID_CLLC,
+ CODEC_ID_Y41P = MKBETAG('Y','4','1','P'),
+ CODEC_ID_ESCAPE130 = MKBETAG('E','1','3','0'),
+ CODEC_ID_EXR = MKBETAG('0','E','X','R'),
+ CODEC_ID_AVRP = MKBETAG('A','V','R','P'),
+
+ CODEC_ID_G2M = MKBETAG( 0 ,'G','2','M'),
+ CODEC_ID_AVUI = MKBETAG('A','V','U','I'),
+ CODEC_ID_AYUV = MKBETAG('A','Y','U','V'),
+ CODEC_ID_V308 = MKBETAG('V','3','0','8'),
+ CODEC_ID_V408 = MKBETAG('V','4','0','8'),
+ CODEC_ID_YUV4 = MKBETAG('Y','U','V','4'),
+ CODEC_ID_SANM = MKBETAG('S','A','N','M'),
+ CODEC_ID_PAF_VIDEO = MKBETAG('P','A','F','V'),
+ CODEC_ID_SNOW = AV_CODEC_ID_SNOW,
+
+ /* various PCM "codecs" */
+ CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
+ CODEC_ID_PCM_S16LE = 0x10000,
+ CODEC_ID_PCM_S16BE,
+ CODEC_ID_PCM_U16LE,
+ CODEC_ID_PCM_U16BE,
+ CODEC_ID_PCM_S8,
+ CODEC_ID_PCM_U8,
+ CODEC_ID_PCM_MULAW,
+ CODEC_ID_PCM_ALAW,
+ CODEC_ID_PCM_S32LE,
+ CODEC_ID_PCM_S32BE,
+ CODEC_ID_PCM_U32LE,
+ CODEC_ID_PCM_U32BE,
+ CODEC_ID_PCM_S24LE,
+ CODEC_ID_PCM_S24BE,
+ CODEC_ID_PCM_U24LE,
+ CODEC_ID_PCM_U24BE,
+ CODEC_ID_PCM_S24DAUD,
+ CODEC_ID_PCM_ZORK,
+ CODEC_ID_PCM_S16LE_PLANAR,
+ CODEC_ID_PCM_DVD,
+ CODEC_ID_PCM_F32BE,
+ CODEC_ID_PCM_F32LE,
+ CODEC_ID_PCM_F64BE,
+ CODEC_ID_PCM_F64LE,
+ CODEC_ID_PCM_BLURAY,
+ CODEC_ID_PCM_LXF,
+ CODEC_ID_S302M,
+ CODEC_ID_PCM_S8_PLANAR,
+
+ /* various ADPCM codecs */
+ CODEC_ID_ADPCM_IMA_QT = 0x11000,
+ CODEC_ID_ADPCM_IMA_WAV,
+ CODEC_ID_ADPCM_IMA_DK3,
+ CODEC_ID_ADPCM_IMA_DK4,
+ CODEC_ID_ADPCM_IMA_WS,
+ CODEC_ID_ADPCM_IMA_SMJPEG,
+ CODEC_ID_ADPCM_MS,
+ CODEC_ID_ADPCM_4XM,
+ CODEC_ID_ADPCM_XA,
+ CODEC_ID_ADPCM_ADX,
+ CODEC_ID_ADPCM_EA,
+ CODEC_ID_ADPCM_G726,
+ CODEC_ID_ADPCM_CT,
+ CODEC_ID_ADPCM_SWF,
+ CODEC_ID_ADPCM_YAMAHA,
+ CODEC_ID_ADPCM_SBPRO_4,
+ CODEC_ID_ADPCM_SBPRO_3,
+ CODEC_ID_ADPCM_SBPRO_2,
+ CODEC_ID_ADPCM_THP,
+ CODEC_ID_ADPCM_IMA_AMV,
+ CODEC_ID_ADPCM_EA_R1,
+ CODEC_ID_ADPCM_EA_R3,
+ CODEC_ID_ADPCM_EA_R2,
+ CODEC_ID_ADPCM_IMA_EA_SEAD,
+ CODEC_ID_ADPCM_IMA_EA_EACS,
+ CODEC_ID_ADPCM_EA_XAS,
+ CODEC_ID_ADPCM_EA_MAXIS_XA,
+ CODEC_ID_ADPCM_IMA_ISS,
+ CODEC_ID_ADPCM_G722,
+ CODEC_ID_ADPCM_IMA_APC,
+ CODEC_ID_VIMA = MKBETAG('V','I','M','A'),
+
+ /* AMR */
+ CODEC_ID_AMR_NB = 0x12000,
+ CODEC_ID_AMR_WB,
+
+ /* RealAudio codecs*/
+ CODEC_ID_RA_144 = 0x13000,
+ CODEC_ID_RA_288,
+
+ /* various DPCM codecs */
+ CODEC_ID_ROQ_DPCM = 0x14000,
+ CODEC_ID_INTERPLAY_DPCM,
+ CODEC_ID_XAN_DPCM,
+ CODEC_ID_SOL_DPCM,
+
+ /* audio codecs */
+ CODEC_ID_MP2 = 0x15000,
+ CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3
+ CODEC_ID_AAC,
+ CODEC_ID_AC3,
+ CODEC_ID_DTS,
+ CODEC_ID_VORBIS,
+ CODEC_ID_DVAUDIO,
+ CODEC_ID_WMAV1,
+ CODEC_ID_WMAV2,
+ CODEC_ID_MACE3,
+ CODEC_ID_MACE6,
+ CODEC_ID_VMDAUDIO,
+ CODEC_ID_FLAC,
+ CODEC_ID_MP3ADU,
+ CODEC_ID_MP3ON4,
+ CODEC_ID_SHORTEN,
+ CODEC_ID_ALAC,
+ CODEC_ID_WESTWOOD_SND1,
+ CODEC_ID_GSM, ///< as in Berlin toast format
+ CODEC_ID_QDM2,
+ CODEC_ID_COOK,
+ CODEC_ID_TRUESPEECH,
+ CODEC_ID_TTA,
+ CODEC_ID_SMACKAUDIO,
+ CODEC_ID_QCELP,
+ CODEC_ID_WAVPACK,
+ CODEC_ID_DSICINAUDIO,
+ CODEC_ID_IMC,
+ CODEC_ID_MUSEPACK7,
+ CODEC_ID_MLP,
+ CODEC_ID_GSM_MS, /* as found in WAV */
+ CODEC_ID_ATRAC3,
+ CODEC_ID_VOXWARE,
+ CODEC_ID_APE,
+ CODEC_ID_NELLYMOSER,
+ CODEC_ID_MUSEPACK8,
+ CODEC_ID_SPEEX,
+ CODEC_ID_WMAVOICE,
+ CODEC_ID_WMAPRO,
+ CODEC_ID_WMALOSSLESS,
+ CODEC_ID_ATRAC3P,
+ CODEC_ID_EAC3,
+ CODEC_ID_SIPR,
+ CODEC_ID_MP1,
+ CODEC_ID_TWINVQ,
+ CODEC_ID_TRUEHD,
+ CODEC_ID_MP4ALS,
+ CODEC_ID_ATRAC1,
+ CODEC_ID_BINKAUDIO_RDFT,
+ CODEC_ID_BINKAUDIO_DCT,
+ CODEC_ID_AAC_LATM,
+ CODEC_ID_QDMC,
+ CODEC_ID_CELT,
+ CODEC_ID_G723_1,
+ CODEC_ID_G729,
+ CODEC_ID_8SVX_EXP,
+ CODEC_ID_8SVX_FIB,
+ CODEC_ID_BMV_AUDIO,
+ CODEC_ID_RALF,
+ CODEC_ID_IAC,
+ CODEC_ID_ILBC,
+ CODEC_ID_FFWAVESYNTH = MKBETAG('F','F','W','S'),
+ CODEC_ID_SONIC = MKBETAG('S','O','N','C'),
+ CODEC_ID_SONIC_LS = MKBETAG('S','O','N','L'),
+ CODEC_ID_PAF_AUDIO = MKBETAG('P','A','F','A'),
+ CODEC_ID_OPUS = MKBETAG('O','P','U','S'),
+
+ /* subtitle codecs */
+ CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
+ CODEC_ID_DVD_SUBTITLE = 0x17000,
+ CODEC_ID_DVB_SUBTITLE,
+ CODEC_ID_TEXT, ///< raw UTF-8 text
+ CODEC_ID_XSUB,
+ CODEC_ID_SSA,
+ CODEC_ID_MOV_TEXT,
+ CODEC_ID_HDMV_PGS_SUBTITLE,
+ CODEC_ID_DVB_TELETEXT,
+ CODEC_ID_SRT,
+ CODEC_ID_MICRODVD = MKBETAG('m','D','V','D'),
+ CODEC_ID_EIA_608 = MKBETAG('c','6','0','8'),
+ CODEC_ID_JACOSUB = MKBETAG('J','S','U','B'),
+ CODEC_ID_SAMI = MKBETAG('S','A','M','I'),
+ CODEC_ID_REALTEXT = MKBETAG('R','T','X','T'),
+ CODEC_ID_SUBVIEWER = MKBETAG('S','u','b','V'),
+
+ /* other specific kind of codecs (generally used for attachments) */
+ CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
+ CODEC_ID_TTF = 0x18000,
+ CODEC_ID_BINTEXT = MKBETAG('B','T','X','T'),
+ CODEC_ID_XBIN = MKBETAG('X','B','I','N'),
+ CODEC_ID_IDF = MKBETAG( 0 ,'I','D','F'),
+ CODEC_ID_OTF = MKBETAG( 0 ,'O','T','F'),
+
+ CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like CODEC_ID_NONE) but lavf should attempt to identify it
+
+ CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS
+ * stream (only used by libavformat) */
+ CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems
+ * stream (only used by libavformat) */
+ CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information.
+
+#endif /* AVCODEC_OLD_CODEC_IDS_H */
diff --git a/libavcodec/on2avc.c b/libavcodec/on2avc.c
index c00339f7b0..1d8fcbc596 100644
--- a/libavcodec/on2avc.c
+++ b/libavcodec/on2avc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2013 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,7 +47,7 @@ enum WindowTypes {
typedef struct On2AVCContext {
AVCodecContext *avctx;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext mdct, mdct_half, mdct_small;
FFTContext fft128, fft256, fft512, fft1024;
void (*wtf)(struct On2AVCContext *ctx, float *out, float *in, int size);
@@ -119,12 +119,12 @@ static int on2avc_decode_band_types(On2AVCContext *c, GetBitContext *gb)
run_len = 1;
do {
run = get_bits(gb, bits_per_sect);
+ if (run > num_bands - band - run_len) {
+ av_log(c->avctx, AV_LOG_ERROR, "Invalid band type run\n");
+ return AVERROR_INVALIDDATA;
+ }
run_len += run;
} while (run == esc_val);
- if (band + run_len > num_bands) {
- av_log(c->avctx, AV_LOG_ERROR, "Invalid band type run\n");
- return AVERROR_INVALIDDATA;
- }
for (i = band; i < band + run_len; i++) {
c->band_type[i] = band_type;
c->band_run_end[i] = band + run_len;
@@ -313,7 +313,7 @@ static void zero_head_and_tail(float *src, int len, int order0, int order1)
}
static void pretwiddle(float *src, float *dst, int dst_len, int tab_step,
- int step, int order0, int order1, const double **tabs)
+ int step, int order0, int order1, const double * const *tabs)
{
float *src2, *out;
const double *tab;
@@ -341,7 +341,7 @@ static void pretwiddle(float *src, float *dst, int dst_len, int tab_step,
static void twiddle(float *src1, float *src2, int src2_len,
const double *tab, int tab_len, int step,
- int order0, int order1, const double **tabs)
+ int order0, int order1, const double * const *tabs)
{
int steps;
int mask;
@@ -714,7 +714,7 @@ static int on2avc_reconstruct_stereo(On2AVCContext *c, AVFrame *dst, int offset)
}
memcpy(out, saved, 448 * sizeof(float));
- c->fdsp.vector_fmul_window(wout, saved + 448, buf, c->short_win, 64);
+ c->fdsp->vector_fmul_window(wout, saved + 448, buf, c->short_win, 64);
memcpy(wout + 128, buf + 64, 448 * sizeof(float));
memcpy(saved, buf + 512, 448 * sizeof(float));
memcpy(saved + 448, buf + 7*128 + 64, 64 * sizeof(float));
@@ -750,20 +750,20 @@ static int on2avc_reconstruct_channel(On2AVCContext *c, int channel,
c->prev_window_type == WINDOW_TYPE_LONG_STOP) &&
(c->window_type == WINDOW_TYPE_LONG ||
c->window_type == WINDOW_TYPE_LONG_START)) {
- c->fdsp.vector_fmul_window(out, saved, buf, c->long_win, 512);
+ c->fdsp->vector_fmul_window(out, saved, buf, c->long_win, 512);
} else {
float *wout = out + 448;
memcpy(out, saved, 448 * sizeof(float));
if (c->window_type == WINDOW_TYPE_8SHORT) {
- c->fdsp.vector_fmul_window(wout + 0*128, saved + 448, buf + 0*128, c->short_win, 64);
- c->fdsp.vector_fmul_window(wout + 1*128, buf + 0*128 + 64, buf + 1*128, c->short_win, 64);
- c->fdsp.vector_fmul_window(wout + 2*128, buf + 1*128 + 64, buf + 2*128, c->short_win, 64);
- c->fdsp.vector_fmul_window(wout + 3*128, buf + 2*128 + 64, buf + 3*128, c->short_win, 64);
- c->fdsp.vector_fmul_window(temp, buf + 3*128 + 64, buf + 4*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(wout + 0*128, saved + 448, buf + 0*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(wout + 1*128, buf + 0*128 + 64, buf + 1*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(wout + 2*128, buf + 1*128 + 64, buf + 2*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(wout + 3*128, buf + 2*128 + 64, buf + 3*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(temp, buf + 3*128 + 64, buf + 4*128, c->short_win, 64);
memcpy(wout + 4*128, temp, 64 * sizeof(float));
} else {
- c->fdsp.vector_fmul_window(wout, saved + 448, buf, c->short_win, 64);
+ c->fdsp->vector_fmul_window(wout, saved + 448, buf, c->short_win, 64);
memcpy(wout + 128, buf + 64, 448 * sizeof(float));
}
}
@@ -772,9 +772,9 @@ static int on2avc_reconstruct_channel(On2AVCContext *c, int channel,
switch (c->window_type) {
case WINDOW_TYPE_8SHORT:
memcpy(saved, temp + 64, 64 * sizeof(float));
- c->fdsp.vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, c->short_win, 64);
- c->fdsp.vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, c->short_win, 64);
- c->fdsp.vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, c->short_win, 64);
+ c->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, c->short_win, 64);
memcpy(saved + 448, buf + 7*128 + 64, 64 * sizeof(float));
break;
case WINDOW_TYPE_LONG_START:
@@ -795,7 +795,9 @@ static int on2avc_decode_subframe(On2AVCContext *c, const uint8_t *buf,
GetBitContext gb;
int i, ret;
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
+ return ret;
+
if (get_bits1(&gb)) {
av_log(c->avctx, AV_LOG_ERROR, "enh bit set\n");
return AVERROR_INVALIDDATA;
@@ -846,10 +848,8 @@ static int on2avc_decode_frame(AVCodecContext * avctx, void *data,
if (c->is_av500) {
/* get output buffer */
frame->nb_samples = ON2AVC_SUBFRAME_SIZE;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if ((ret = on2avc_decode_subframe(c, buf, buf_size, frame, 0)) < 0)
return ret;
@@ -872,10 +872,8 @@ static int on2avc_decode_frame(AVCodecContext * avctx, void *data,
/* get output buffer */
frame->nb_samples = ON2AVC_SUBFRAME_SIZE * num_frames;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
audio_off = 0;
bytestream2_init(&gb, buf, buf_size);
@@ -908,6 +906,11 @@ static av_cold int on2avc_decode_init(AVCodecContext *avctx)
On2AVCContext *c = avctx->priv_data;
int i;
+ if (avctx->channels > 2U) {
+ avpriv_request_sample(avctx, "Decoding more than 2 channels");
+ return AVERROR_PATCHWELCOME;
+ }
+
c->avctx = avctx;
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
avctx->channel_layout = (avctx->channels == 2) ? AV_CH_LAYOUT_STEREO
@@ -918,10 +921,7 @@ static av_cold int on2avc_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "0x500 version should be mono\n");
return AVERROR_INVALIDDATA;
}
- if (avctx->channels > 2) {
- av_log(avctx, AV_LOG_ERROR, "Only 1 or 2 channels are supported.\n");
- return AVERROR(EINVAL);
- }
+
if (avctx->channels == 2)
av_log(avctx, AV_LOG_WARNING,
"Stereo mode support is not good, patch is welcome\n");
@@ -951,13 +951,14 @@ static av_cold int on2avc_decode_init(AVCodecContext *avctx)
ff_fft_init(&c->fft256, 7, 0);
ff_fft_init(&c->fft512, 8, 1);
ff_fft_init(&c->fft1024, 9, 1);
- avpriv_float_dsp_init(&c->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ c->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!c->fdsp)
+ return AVERROR(ENOMEM);
if (init_vlc(&c->scale_diff, 9, ON2AVC_SCALE_DIFFS,
ff_on2avc_scale_diff_bits, 1, 1,
ff_on2avc_scale_diff_codes, 4, 4, 0)) {
- av_log(avctx, AV_LOG_ERROR, "Cannot init VLC\n");
- return AVERROR(ENOMEM);
+ goto vlc_fail;
}
for (i = 1; i < 9; i++) {
int idx = i - 1;
@@ -965,9 +966,7 @@ static av_cold int on2avc_decode_init(AVCodecContext *avctx)
ff_on2avc_quad_cb_bits[idx], 1, 1,
ff_on2avc_quad_cb_codes[idx], 4, 4,
ff_on2avc_quad_cb_syms[idx], 2, 2, 0)) {
- av_log(avctx, AV_LOG_ERROR, "Cannot init VLC\n");
- on2avc_free_vlcs(c);
- return AVERROR(ENOMEM);
+ goto vlc_fail;
}
}
for (i = 9; i < 16; i++) {
@@ -976,13 +975,16 @@ static av_cold int on2avc_decode_init(AVCodecContext *avctx)
ff_on2avc_pair_cb_bits[idx], 1, 1,
ff_on2avc_pair_cb_codes[idx], 2, 2,
ff_on2avc_pair_cb_syms[idx], 2, 2, 0)) {
- av_log(avctx, AV_LOG_ERROR, "Cannot init VLC\n");
- on2avc_free_vlcs(c);
- return AVERROR(ENOMEM);
+ goto vlc_fail;
}
}
return 0;
+vlc_fail:
+ av_log(avctx, AV_LOG_ERROR, "Cannot init VLC\n");
+ on2avc_free_vlcs(c);
+ av_freep(&c->fdsp);
+ return AVERROR(ENOMEM);
}
static av_cold int on2avc_decode_close(AVCodecContext *avctx)
@@ -997,6 +999,8 @@ static av_cold int on2avc_decode_close(AVCodecContext *avctx)
ff_fft_end(&c->fft512);
ff_fft_end(&c->fft1024);
+ av_freep(&c->fdsp);
+
on2avc_free_vlcs(c);
return 0;
diff --git a/libavcodec/on2avcdata.c b/libavcodec/on2avcdata.c
index d039f23509..abe598350b 100644
--- a/libavcodec/on2avcdata.c
+++ b/libavcodec/on2avcdata.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2013 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -7641,11 +7641,11 @@ static const double tabs_4_10[4 * 2][10] = {
-0.099339873, -0.041293536, 0.31028851, 0.17727433, -0.92756648 }
};
-const double *ff_on2avc_tabs_4_10_1[4] = {
+const double * const ff_on2avc_tabs_4_10_1[4] = {
tabs_4_10[0], tabs_4_10[1], tabs_4_10[2], tabs_4_10[3]
};
-const double *ff_on2avc_tabs_4_10_2[4] = {
+const double * const ff_on2avc_tabs_4_10_2[4] = {
tabs_4_10[4], tabs_4_10[5], tabs_4_10[6], tabs_4_10[7]
};
@@ -7724,12 +7724,12 @@ static const double tabs_9_20[9 * 2][20] = {
0.22783, 0.058894795, -0.61350902, 0.69559873, -0.27013783, }
};
-const double* ff_on2avc_tabs_9_20_1[9] = {
+const double* const ff_on2avc_tabs_9_20_1[9] = {
tabs_9_20[0], tabs_9_20[1], tabs_9_20[2], tabs_9_20[3], tabs_9_20[4],
tabs_9_20[5], tabs_9_20[6], tabs_9_20[7], tabs_9_20[8]
};
-const double* ff_on2avc_tabs_9_20_2[9] = {
+const double* const ff_on2avc_tabs_9_20_2[9] = {
tabs_9_20[ 9], tabs_9_20[10], tabs_9_20[11], tabs_9_20[12], tabs_9_20[13],
tabs_9_20[14], tabs_9_20[15], tabs_9_20[16], tabs_9_20[17]
};
@@ -7927,7 +7927,7 @@ static const double tabs_19_40[19 * 2][40] = {
0.019871848, -0.11989559, 0.036659135, 0.26632201, -0.3057397, -0.23220335, 0.68741352, -0.54024027, }
};
-const double* ff_on2avc_tabs_19_40_1[19] = {
+const double* const ff_on2avc_tabs_19_40_1[19] = {
tabs_19_40[ 0], tabs_19_40[ 1], tabs_19_40[ 2], tabs_19_40[ 3],
tabs_19_40[ 4], tabs_19_40[ 5], tabs_19_40[ 6], tabs_19_40[ 7],
tabs_19_40[ 8], tabs_19_40[ 9], tabs_19_40[10], tabs_19_40[11],
@@ -7935,7 +7935,7 @@ const double* ff_on2avc_tabs_19_40_1[19] = {
tabs_19_40[16], tabs_19_40[17], tabs_19_40[18],
};
-const double* ff_on2avc_tabs_19_40_2[19] = {
+const double* const ff_on2avc_tabs_19_40_2[19] = {
tabs_19_40[19], tabs_19_40[20], tabs_19_40[21], tabs_19_40[22],
tabs_19_40[23], tabs_19_40[24], tabs_19_40[25], tabs_19_40[26],
tabs_19_40[27], tabs_19_40[28], tabs_19_40[29], tabs_19_40[30],
@@ -8826,7 +8826,7 @@ static const double tabs_20_84[20 * 4][84] = {
0.51434408, -0.41486443, 0.27672635, -0.10432054, },
};
-const double* ff_on2avc_tabs_20_84_1[20] = {
+const double* const ff_on2avc_tabs_20_84_1[20] = {
tabs_20_84[ 0], tabs_20_84[ 1], tabs_20_84[ 2], tabs_20_84[ 3],
tabs_20_84[ 4], tabs_20_84[ 5], tabs_20_84[ 6], tabs_20_84[ 7],
tabs_20_84[ 8], tabs_20_84[ 9], tabs_20_84[10], tabs_20_84[11],
@@ -8834,7 +8834,7 @@ const double* ff_on2avc_tabs_20_84_1[20] = {
tabs_20_84[16], tabs_20_84[17], tabs_20_84[18], tabs_20_84[19]
};
-const double* ff_on2avc_tabs_20_84_2[20] = {
+const double* const ff_on2avc_tabs_20_84_2[20] = {
tabs_20_84[20], tabs_20_84[21], tabs_20_84[22], tabs_20_84[23],
tabs_20_84[24], tabs_20_84[25], tabs_20_84[26], tabs_20_84[27],
tabs_20_84[28], tabs_20_84[29], tabs_20_84[30], tabs_20_84[31],
@@ -8842,7 +8842,7 @@ const double* ff_on2avc_tabs_20_84_2[20] = {
tabs_20_84[36], tabs_20_84[37], tabs_20_84[38], tabs_20_84[39]
};
-const double* ff_on2avc_tabs_20_84_3[20] = {
+const double* const ff_on2avc_tabs_20_84_3[20] = {
tabs_20_84[40], tabs_20_84[41], tabs_20_84[42], tabs_20_84[43],
tabs_20_84[44], tabs_20_84[45], tabs_20_84[46], tabs_20_84[47],
tabs_20_84[48], tabs_20_84[49], tabs_20_84[50], tabs_20_84[51],
@@ -8850,7 +8850,7 @@ const double* ff_on2avc_tabs_20_84_3[20] = {
tabs_20_84[56], tabs_20_84[57], tabs_20_84[58], tabs_20_84[59]
};
-const double* ff_on2avc_tabs_20_84_4[20] = {
+const double* const ff_on2avc_tabs_20_84_4[20] = {
tabs_20_84[60], tabs_20_84[61], tabs_20_84[62], tabs_20_84[63],
tabs_20_84[64], tabs_20_84[65], tabs_20_84[66], tabs_20_84[67],
tabs_20_84[68], tabs_20_84[69], tabs_20_84[70], tabs_20_84[71],
diff --git a/libavcodec/on2avcdata.h b/libavcodec/on2avcdata.h
index 39d29110ec..7f498e58e4 100644
--- a/libavcodec/on2avcdata.h
+++ b/libavcodec/on2avcdata.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2013 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,16 +64,16 @@ extern const double ff_on2avc_tab_84_1[];
extern const double ff_on2avc_tab_84_2[];
extern const double ff_on2avc_tab_84_3[];
extern const double ff_on2avc_tab_84_4[];
-extern const double* ff_on2avc_tabs_4_10_1[4];
-extern const double* ff_on2avc_tabs_4_10_2[4];
-extern const double* ff_on2avc_tabs_9_20_1[9];
-extern const double* ff_on2avc_tabs_9_20_2[9];
-extern const double* ff_on2avc_tabs_19_40_1[19];
-extern const double* ff_on2avc_tabs_19_40_2[19];
-extern const double* ff_on2avc_tabs_20_84_1[20];
-extern const double* ff_on2avc_tabs_20_84_2[20];
-extern const double* ff_on2avc_tabs_20_84_3[20];
-extern const double* ff_on2avc_tabs_20_84_4[20];
+extern const double* const ff_on2avc_tabs_4_10_1[4];
+extern const double* const ff_on2avc_tabs_4_10_2[4];
+extern const double* const ff_on2avc_tabs_9_20_1[9];
+extern const double* const ff_on2avc_tabs_9_20_2[9];
+extern const double* const ff_on2avc_tabs_19_40_1[19];
+extern const double* const ff_on2avc_tabs_19_40_2[19];
+extern const double* const ff_on2avc_tabs_20_84_1[20];
+extern const double* const ff_on2avc_tabs_20_84_2[20];
+extern const double* const ff_on2avc_tabs_20_84_3[20];
+extern const double* const ff_on2avc_tabs_20_84_4[20];
extern const float ff_on2avc_ctab_1[2048];
extern const float ff_on2avc_ctab_2[2048];
extern const float ff_on2avc_ctab_3[2048];
diff --git a/libavcodec/options.c b/libavcodec/options.c
index c00dca078e..17dca08060 100644
--- a/libavcodec/options.c
+++ b/libavcodec/options.c
@@ -2,20 +2,20 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -68,6 +68,13 @@ static const AVClass *codec_child_class_next(const AVClass *prev)
return NULL;
}
+static AVClassCategory get_category(void *ptr)
+{
+ AVCodecContext* avctx = ptr;
+ if(avctx->codec && avctx->codec->decode) return AV_CLASS_CATEGORY_DECODER;
+ else return AV_CLASS_CATEGORY_ENCODER;
+}
+
static const AVClass av_codec_context_class = {
.class_name = "AVCodecContext",
.item_name = context_to_name,
@@ -76,20 +83,34 @@ static const AVClass av_codec_context_class = {
.log_level_offset_offset = offsetof(AVCodecContext, log_level_offset),
.child_next = codec_child_next,
.child_class_next = codec_child_class_next,
+ .category = AV_CLASS_CATEGORY_ENCODER,
+ .get_category = get_category,
};
int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec)
{
+ int flags=0;
memset(s, 0, sizeof(AVCodecContext));
s->av_class = &av_codec_context_class;
s->codec_type = codec ? codec->type : AVMEDIA_TYPE_UNKNOWN;
- s->codec = codec;
- av_opt_set_defaults(s);
+ if (codec) {
+ s->codec = codec;
+ s->codec_id = codec->id;
+ }
+
+ if(s->codec_type == AVMEDIA_TYPE_AUDIO)
+ flags= AV_OPT_FLAG_AUDIO_PARAM;
+ else if(s->codec_type == AVMEDIA_TYPE_VIDEO)
+ flags= AV_OPT_FLAG_VIDEO_PARAM;
+ else if(s->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ flags= AV_OPT_FLAG_SUBTITLE_PARAM;
+ av_opt_set_defaults2(s, flags, flags);
s->time_base = (AVRational){0,1};
s->framerate = (AVRational){ 0, 1 };
+ s->pkt_timebase = (AVRational){ 0, 1 };
s->get_buffer2 = avcodec_default_get_buffer2;
s->get_format = avcodec_default_get_format;
s->execute = avcodec_default_execute;
@@ -149,6 +170,9 @@ void avcodec_free_context(AVCodecContext **pavctx)
av_freep(&avctx->extradata);
av_freep(&avctx->subtitle_header);
+ av_freep(&avctx->intra_matrix);
+ av_freep(&avctx->inter_matrix);
+ av_freep(&avctx->rc_override);
av_freep(pavctx);
}
@@ -164,15 +188,30 @@ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
src, dest);
return AVERROR(EINVAL);
}
+
+ av_opt_free(dest);
+ av_freep(&dest->rc_override);
+ av_freep(&dest->intra_matrix);
+ av_freep(&dest->inter_matrix);
+ av_freep(&dest->extradata);
+ av_freep(&dest->subtitle_header);
+
memcpy(dest, src, sizeof(*dest));
+ av_opt_copy(dest, src);
dest->priv_data = orig_priv_data;
dest->codec = orig_codec;
+ if (orig_priv_data && src->codec && src->codec->priv_class &&
+ dest->codec && dest->codec->priv_class)
+ av_opt_copy(orig_priv_data, src->priv_data);
+
+
/* set values specific to opened codecs back to their default state */
dest->slice_offset = NULL;
dest->hwaccel = NULL;
dest->internal = NULL;
+ dest->coded_frame = NULL;
/* reallocate values that should be allocated separately */
dest->extradata = NULL;
@@ -180,16 +219,6 @@ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
dest->inter_matrix = NULL;
dest->rc_override = NULL;
dest->subtitle_header = NULL;
-#if FF_API_MPV_OPT
- FF_DISABLE_DEPRECATION_WARNINGS
- dest->rc_eq = NULL;
- if (src->rc_eq) {
- dest->rc_eq = av_strdup(src->rc_eq);
- if (!dest->rc_eq)
- return AVERROR(ENOMEM);
- }
- FF_ENABLE_DEPRECATION_WARNINGS
-#endif
#define alloc_and_copy_or_fail(obj, size, pad) \
if (src->obj && size > 0) { \
@@ -202,11 +231,12 @@ int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
}
alloc_and_copy_or_fail(extradata, src->extradata_size,
FF_INPUT_BUFFER_PADDING_SIZE);
+ dest->extradata_size = src->extradata_size;
alloc_and_copy_or_fail(intra_matrix, 64 * sizeof(int16_t), 0);
alloc_and_copy_or_fail(inter_matrix, 64 * sizeof(int16_t), 0);
alloc_and_copy_or_fail(rc_override, src->rc_override_count * sizeof(*src->rc_override), 0);
- alloc_and_copy_or_fail(subtitle_header, src->subtitle_header_size, 0);
- dest->subtitle_header_size = src->subtitle_header_size;
+ alloc_and_copy_or_fail(subtitle_header, src->subtitle_header_size, 1);
+ av_assert0(dest->subtitle_header_size == src->subtitle_header_size);
#undef alloc_and_copy_or_fail
return 0;
@@ -216,11 +246,10 @@ fail:
av_freep(&dest->intra_matrix);
av_freep(&dest->inter_matrix);
av_freep(&dest->extradata);
-#if FF_API_MPV_OPT
- FF_DISABLE_DEPRECATION_WARNINGS
- av_freep(&dest->rc_eq);
- FF_ENABLE_DEPRECATION_WARNINGS
-#endif
+ av_freep(&dest->subtitle_header);
+ dest->subtitle_header_size = 0;
+ dest->extradata_size = 0;
+ av_opt_free(dest);
return AVERROR(ENOMEM);
}
@@ -228,3 +257,226 @@ const AVClass *avcodec_get_class(void)
{
return &av_codec_context_class;
}
+
+#define FOFFSET(x) offsetof(AVFrame,x)
+
+static const AVOption frame_options[]={
+{"best_effort_timestamp", "", FOFFSET(best_effort_timestamp), AV_OPT_TYPE_INT64, {.i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, 0},
+{"pkt_pos", "", FOFFSET(pkt_pos), AV_OPT_TYPE_INT64, {.i64 = -1 }, INT64_MIN, INT64_MAX, 0},
+{"pkt_size", "", FOFFSET(pkt_size), AV_OPT_TYPE_INT64, {.i64 = -1 }, INT64_MIN, INT64_MAX, 0},
+{"sample_aspect_ratio", "", FOFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, 0, INT_MAX, 0},
+{"width", "", FOFFSET(width), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"height", "", FOFFSET(height), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"format", "", FOFFSET(format), AV_OPT_TYPE_INT, {.i64 = -1 }, 0, INT_MAX, 0},
+{"channel_layout", "", FOFFSET(channel_layout), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, 0},
+{"sample_rate", "", FOFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{NULL},
+};
+
+static const AVClass av_frame_class = {
+ .class_name = "AVFrame",
+ .item_name = NULL,
+ .option = frame_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const AVClass *avcodec_get_frame_class(void)
+{
+ return &av_frame_class;
+}
+
+#define SROFFSET(x) offsetof(AVSubtitleRect,x)
+
+static const AVOption subtitle_rect_options[]={
+{"x", "", SROFFSET(x), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"y", "", SROFFSET(y), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"w", "", SROFFSET(w), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"h", "", SROFFSET(h), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"type", "", SROFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0},
+{"flags", "", SROFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, 1, 0, "flags"},
+{"forced", "", SROFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, 1, 0},
+{NULL},
+};
+
+static const AVClass av_subtitle_rect_class = {
+ .class_name = "AVSubtitleRect",
+ .item_name = NULL,
+ .option = subtitle_rect_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const AVClass *avcodec_get_subtitle_rect_class(void)
+{
+ return &av_subtitle_rect_class;
+}
+
+#ifdef TEST
+static int dummy_init(AVCodecContext *ctx)
+{
+ //TODO: this code should set every possible pointer that could be set by codec and is not an option;
+ ctx->extradata_size = 8;
+ ctx->extradata = av_malloc(ctx->extradata_size);
+ ctx->coded_frame = av_frame_alloc();
+ return 0;
+}
+
+static int dummy_close(AVCodecContext *ctx)
+{
+ av_freep(&ctx->extradata);
+ ctx->extradata_size = 0;
+ av_frame_free(&ctx->coded_frame);
+ return 0;
+}
+
+static int dummy_encode(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, int *got_packet)
+{
+ return AVERROR(ENOSYS);
+}
+
+typedef struct Dummy12Context {
+ AVClass *av_class;
+ int num;
+ char* str;
+} Dummy12Context;
+
+typedef struct Dummy3Context {
+ void *fake_av_class;
+ int num;
+ char* str;
+} Dummy3Context;
+
+#define OFFSET(x) offsetof(Dummy12Context, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption dummy_options[] = {
+ { "str", "set str", OFFSET(str), AV_OPT_TYPE_STRING, { .str = "i'm src default value" }, 0, 0, VE},
+ { "num", "set num", OFFSET(num), AV_OPT_TYPE_INT, { .i64 = 1500100900 }, 0, INT_MAX, VE},
+ { NULL },
+};
+
+static const AVClass dummy_v1_class = {
+ .class_name = "dummy_v1_class",
+ .item_name = av_default_item_name,
+ .option = dummy_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVClass dummy_v2_class = {
+ .class_name = "dummy_v2_class",
+ .item_name = av_default_item_name,
+ .option = dummy_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+/* codec with options */
+AVCodec dummy_v1_encoder = {
+ .name = "dummy_v1_codec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_NONE - 1,
+ .encode2 = dummy_encode,
+ .init = dummy_init,
+ .close = dummy_close,
+ .priv_class = &dummy_v1_class,
+ .priv_data_size = sizeof(Dummy12Context),
+};
+
+/* codec with options, different class */
+AVCodec dummy_v2_encoder = {
+ .name = "dummy_v2_codec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_NONE - 2,
+ .encode2 = dummy_encode,
+ .init = dummy_init,
+ .close = dummy_close,
+ .priv_class = &dummy_v2_class,
+ .priv_data_size = sizeof(Dummy12Context),
+};
+
+/* codec with priv data, but no class */
+AVCodec dummy_v3_encoder = {
+ .name = "dummy_v3_codec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_NONE - 3,
+ .encode2 = dummy_encode,
+ .init = dummy_init,
+ .close = dummy_close,
+ .priv_data_size = sizeof(Dummy3Context),
+};
+
+/* codec without priv data */
+AVCodec dummy_v4_encoder = {
+ .name = "dummy_v4_codec",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_NONE - 4,
+ .encode2 = dummy_encode,
+ .init = dummy_init,
+ .close = dummy_close,
+};
+
+static void test_copy_print_codec(const AVCodecContext *ctx)
+{
+ printf("%-14s: %dx%d prv: %s",
+ ctx->codec ? ctx->codec->name : "NULL",
+ ctx->width, ctx->height,
+ ctx->priv_data ? "set" : "null");
+ if (ctx->codec && ctx->codec->priv_class && ctx->codec->priv_data_size) {
+ int64_t i64;
+ char *str = NULL;
+ av_opt_get_int(ctx->priv_data, "num", 0, &i64);
+ av_opt_get(ctx->priv_data, "str", 0, (uint8_t**)&str);
+ printf(" opts: %"PRId64" %s", i64, str);
+ av_free(str);
+ }
+ printf("\n");
+}
+
+static void test_copy(const AVCodec *c1, const AVCodec *c2)
+{
+ AVCodecContext *ctx1, *ctx2;
+ printf("%s -> %s\nclosed:\n", c1 ? c1->name : "NULL", c2 ? c2->name : "NULL");
+ ctx1 = avcodec_alloc_context3(c1);
+ ctx2 = avcodec_alloc_context3(c2);
+ ctx1->width = ctx1->height = 128;
+ if (ctx2->codec && ctx2->codec->priv_class && ctx2->codec->priv_data_size) {
+ av_opt_set(ctx2->priv_data, "num", "667", 0);
+ av_opt_set(ctx2->priv_data, "str", "i'm dest value before copy", 0);
+ }
+ avcodec_copy_context(ctx2, ctx1);
+ test_copy_print_codec(ctx1);
+ test_copy_print_codec(ctx2);
+ if (ctx1->codec) {
+ printf("opened:\n");
+ avcodec_open2(ctx1, ctx1->codec, NULL);
+ if (ctx2->codec && ctx2->codec->priv_class && ctx2->codec->priv_data_size) {
+ av_opt_set(ctx2->priv_data, "num", "667", 0);
+ av_opt_set(ctx2->priv_data, "str", "i'm dest value before copy", 0);
+ }
+ avcodec_copy_context(ctx2, ctx1);
+ test_copy_print_codec(ctx1);
+ test_copy_print_codec(ctx2);
+ avcodec_close(ctx1);
+ }
+ avcodec_free_context(&ctx1);
+ avcodec_free_context(&ctx2);
+}
+
+int main(void)
+{
+ AVCodec *dummy_codec[] = {
+ &dummy_v1_encoder,
+ &dummy_v2_encoder,
+ &dummy_v3_encoder,
+ &dummy_v4_encoder,
+ NULL,
+ };
+ int i, j;
+
+ for (i = 0; dummy_codec[i]; i++)
+ avcodec_register(dummy_codec[i]);
+
+ printf("testing avcodec_copy_context()\n");
+ for (i = 0; i < FF_ARRAY_ELEMS(dummy_codec); i++)
+ for (j = 0; j < FF_ARRAY_ELEMS(dummy_codec); j++)
+ test_copy(dummy_codec[i], dummy_codec[j]);
+ return 0;
+}
+#endif
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index 621f77fd63..a906864dcd 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -1,19 +1,21 @@
/*
+ * Copyright (c) 2001 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +29,6 @@
#include "libavutil/opt.h"
#include "avcodec.h"
#include "version.h"
-#include "config.h"
#define OFFSET(x) offsetof(AVCodecContext,x)
#define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C
@@ -41,12 +42,13 @@
#define AV_CODEC_DEFAULT_BITRATE 200*1000
static const AVOption avcodec_options[] = {
-{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE }, INT_MIN, INT_MAX, V|A|E},
+{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, INT_MAX, A|V|E},
+{"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT, {.i64 = 128*1000 }, 0, INT_MAX, A|E},
{"bt", "Set video bitrate tolerance (in bits/s). In 1-pass mode, bitrate tolerance specifies how far "
"ratecontrol is willing to deviate from the target average bitrate value. This is not related "
"to minimum/maximum bitrate. Lowering tolerance too much has an adverse effect on quality.",
OFFSET(bit_rate_tolerance), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE*20 }, 1, INT_MAX, V|E},
-{"flags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, UINT_MAX, V|A|E|D, "flags"},
+{"flags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, UINT_MAX, V|A|S|E|D, "flags"},
{"unaligned", "allow decoders to produce unaligned output", 0, AV_OPT_TYPE_CONST, { .i64 = CODEC_FLAG_UNALIGNED }, INT_MIN, INT_MAX, V | D, "flags" },
{"mv4", "use four motion vectors per macroblock (MPEG-4)", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_4MV }, INT_MIN, INT_MAX, V|E, "flags"},
{"qpel", "use 1/4-pel motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_QPEL }, INT_MIN, INT_MAX, V|E, "flags"},
@@ -82,8 +84,12 @@ static const AVOption avcodec_options[] = {
{"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"},
{"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"},
{"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"},
-{"ignorecrop", "ignore cropping information from sps", 1, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_IGNORE_CROP }, INT_MIN, INT_MAX, V|D, "flags2"},
+{"ignorecrop", "ignore cropping information from sps", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_IGNORE_CROP }, INT_MIN, INT_MAX, V|D, "flags2"},
{"local_header", "place global headers at every keyframe instead of in extradata", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_LOCAL_HEADER }, INT_MIN, INT_MAX, V|E, "flags2"},
+{"chunks", "Frame data might be split into multiple chunks", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_CHUNKS }, INT_MIN, INT_MAX, V|D, "flags2"},
+{"showall", "Show all frames before the first keyframe", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_SHOW_ALL }, INT_MIN, INT_MAX, V|D, "flags2"},
+{"export_mvs", "export motion vectors through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_EXPORT_MVS}, INT_MIN, INT_MAX, V|D, "flags2"},
+{"skip_manual", "do not skip samples and export skip information as frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG2_SKIP_MANUAL}, INT_MIN, INT_MAX, V|D, "flags2"},
{"me_method", "set motion estimation method", OFFSET(me_method), AV_OPT_TYPE_INT, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method"},
{"zero", "zero motion estimation (fastest)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ZERO }, INT_MIN, INT_MAX, V|E, "me_method" },
{"full", "full motion estimation (slowest)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_FULL }, INT_MIN, INT_MAX, V|E, "me_method" },
@@ -96,11 +102,11 @@ static const AVOption avcodec_options[] = {
{"x1", "X1 motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_X1 }, INT_MIN, INT_MAX, V|E, "me_method" },
{"hex", "hex motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_HEX }, INT_MIN, INT_MAX, V|E, "me_method" },
{"umh", "umh motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_UMH }, INT_MIN, INT_MAX, V|E, "me_method" },
-{"extradata_size", NULL, OFFSET(extradata_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
+{"iter", "iter motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ITER }, INT_MIN, INT_MAX, V|E, "me_method" },
{"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, INT_MIN, 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 }, INT_MIN, INT_MAX, A|D|E},
-{"ac", "set number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|D|E},
+{"ar", "set audio sampling rate (in Hz)", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E},
+{"ac", "set number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E},
{"cutoff", "set cutoff bandwidth", OFFSET(cutoff), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|E},
{"frame_size", NULL, OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|E},
{"frame_number", NULL, OFFSET(frame_number), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
@@ -110,9 +116,9 @@ static const AVOption avcodec_options[] = {
OFFSET(qcompress), AV_OPT_TYPE_FLOAT, {.dbl = 0.5 }, -FLT_MAX, FLT_MAX, V|E},
{"qblur", "video quantizer scale blur (VBR)", OFFSET(qblur), AV_OPT_TYPE_FLOAT, {.dbl = 0.5 }, -1, FLT_MAX, V|E},
{"qmin", "minimum video quantizer scale (VBR)", OFFSET(qmin), AV_OPT_TYPE_INT, {.i64 = 2 }, -1, 69, V|E},
-{"qmax", "maximum video quantizer scale (VBR)", OFFSET(qmax), AV_OPT_TYPE_INT, {.i64 = 31 }, -1, 69, V|E},
+{"qmax", "maximum video quantizer scale (VBR)", OFFSET(qmax), AV_OPT_TYPE_INT, {.i64 = 31 }, -1, 1024, V|E},
{"qdiff", "maximum difference between the quantizer scales (VBR)", OFFSET(max_qdiff), AV_OPT_TYPE_INT, {.i64 = 3 }, INT_MIN, INT_MAX, V|E},
-{"bf", "use 'frames' B frames", OFFSET(max_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, -1, INT_MAX, V|E},
+{"bf", "set maximum number of B frames between non-B-frames", OFFSET(max_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, -1, INT_MAX, V|E},
{"b_qfactor", "QP factor between P- and B-frames", OFFSET(b_quant_factor), AV_OPT_TYPE_FLOAT, {.dbl = 1.25 }, -FLT_MAX, FLT_MAX, V|E},
{"rc_strategy", "ratecontrol method", OFFSET(rc_strategy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"b_strategy", "strategy to choose between I/P/B-frames", OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, V|E},
@@ -155,11 +161,15 @@ static const AVOption avcodec_options[] = {
{"unofficial", "allow unofficial extensions", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_UNOFFICIAL }, INT_MIN, INT_MAX, V|D|E, "strict"},
{"experimental", "allow non-standardized experimental things", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_EXPERIMENTAL }, INT_MIN, INT_MAX, V|D|E, "strict"},
{"b_qoffset", "QP offset between P- and B-frames", OFFSET(b_quant_offset), AV_OPT_TYPE_FLOAT, {.dbl = 1.25 }, -FLT_MAX, FLT_MAX, V|E},
-{"err_detect", "set error detection flags", OFFSET(err_recognition), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, A|V|D, "err_detect"},
-{"crccheck", "verify embedded CRCs", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, V|D, "err_detect"},
-{"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, V|D, "err_detect"},
-{"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, V|D, "err_detect"},
-{"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, V|D, "err_detect"},
+{"err_detect", "set error detection flags", OFFSET(err_recognition), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"crccheck", "verify embedded CRCs", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"ignore_err", "ignore errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_IGNORE_ERR }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"careful", "consider things that violate the spec, are fast to check and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_COMPLIANT }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
+{"aggressive", "consider things that a sane encoder should not do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, A|V|D, "err_detect"},
{"has_b_frames", NULL, OFFSET(has_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"block_align", NULL, OFFSET(block_align), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"mpeg_quant", "use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
@@ -172,8 +182,8 @@ static const AVOption avcodec_options[] = {
#if FF_API_MPV_OPT
{"rc_eq", "deprecated, use encoder private options instead", OFFSET(rc_eq), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, V|E},
#endif
-{"maxrate", "Set maximum bitrate tolerance (in bits/s). Requires bufsize to be set.", OFFSET(rc_max_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E},
-{"minrate", "Set minimum bitrate tolerance (in bits/s). Most useful in setting up a CBR encode. It is of little use otherwise.",
+{"maxrate", "maximum bitrate (in bits/s). Used for VBV together with bufsize.", OFFSET(rc_max_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|A|E},
+{"minrate", "minimum bitrate (in bits/s). Most useful in setting up a CBR encode. It is of little use otherwise.",
OFFSET(rc_min_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E},
{"bufsize", "set ratecontrol buffer size (in bits)", OFFSET(rc_buffer_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|V|E},
#if FF_API_MPV_OPT
@@ -219,14 +229,14 @@ static const AVOption avcodec_options[] = {
{"ipp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_IPP }, INT_MIN, INT_MAX, V|E|D, "idct"},
#endif /* FF_API_UNUSED_MEMBERS */
{"xvid", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"},
-#if FF_API_IDCT_XVIDMMX
-{"xvidmmx", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"},
-#endif /* FF_API_IDCT_XVIDMMX */
+{"xvidmmx", "deprecated, for compatibility only", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"},
{"faani", "floating point AAN IDCT", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_FAAN }, INT_MIN, INT_MAX, V|D|E, "idct"},
+{"simpleauto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEAUTO }, INT_MIN, INT_MAX, V|E|D, "idct"},
{"slice_count", NULL, OFFSET(slice_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"ec", "set error concealment strategy", OFFSET(error_concealment), AV_OPT_TYPE_FLAGS, {.i64 = 3 }, INT_MIN, INT_MAX, V|D, "ec"},
{"guess_mvs", "iterative motion vector (MV) search (slow)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_EC_GUESS_MVS }, INT_MIN, INT_MAX, V|D, "ec"},
{"deblock", "use strong deblock filter for damaged MBs", 0, AV_OPT_TYPE_CONST, {.i64 = FF_EC_DEBLOCK }, INT_MIN, INT_MAX, V|D, "ec"},
+{"favor_inter", "favor predicting from the previous frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_EC_FAVOR_INTER }, INT_MIN, INT_MAX, V|D, "ec"},
{"bits_per_coded_sample", NULL, OFFSET(bits_per_coded_sample), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"pred", "prediction method", OFFSET(prediction_method), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "pred"},
{"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PRED_LEFT }, INT_MIN, INT_MAX, V|E, "pred"},
@@ -251,14 +261,13 @@ static const AVOption avcodec_options[] = {
{"er", "error recognition", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_ER }, INT_MIN, INT_MAX, V|D, "debug"},
{"mmco", "memory management control operations (H.264)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_MMCO }, INT_MIN, INT_MAX, V|D, "debug"},
{"bugs", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUGS }, INT_MIN, INT_MAX, V|D, "debug"},
-#if FF_API_DEBUG_MV
{"vis_qp", "visualize quantization parameter (QP), lower QP are tinted greener", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_QP }, INT_MIN, INT_MAX, V|D, "debug"},
{"vis_mb_type", "visualize block types", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MB_TYPE }, INT_MIN, INT_MAX, V|D, "debug"},
-#endif
{"buffers", "picture buffer allocations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUFFERS }, INT_MIN, INT_MAX, V|D, "debug"},
-{"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|D, "debug"},
-#if FF_API_DEBUG_MV
-{"vismv", "visualize motion vectors (MVs)", OFFSET(debug_mv), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|D, "debug_mv"},
+{"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|A|D, "debug"},
+{"nomc", "skip motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_NOMC }, INT_MIN, INT_MAX, V|A|D, "debug"},
+#if FF_API_VISMV
+{"vismv", "visualize motion vectors (MVs) (deprecated)", OFFSET(debug_mv), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, V|D, "debug_mv"},
{"pf", "forward predicted MVs of P-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_P_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"},
{"bf", "forward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"},
{"bb", "backward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_BACK }, INT_MIN, INT_MAX, V|D, "debug_mv"},
@@ -282,6 +291,10 @@ static const AVOption avcodec_options[] = {
{"vsad", "sum of absolute vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"vsse", "sum of squared vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"nsse", "noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"},
+#if CONFIG_SNOW_ENCODER
+{"w53", "5/3 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W53 }, INT_MIN, INT_MAX, V|E, "cmp_func"},
+{"w97", "9/7 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W97 }, INT_MIN, INT_MAX, V|E, "cmp_func"},
+#endif
{"dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, V|E, "cmp_func"},
{"pre_dia_size", "diamond type & size for motion estimation pre-pass", OFFSET(pre_dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
@@ -304,7 +317,7 @@ static const AVOption avcodec_options[] = {
#if FF_API_XVMC
{"xvmc_acceleration", NULL, OFFSET(xvmc_acceleration), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
#endif /* FF_API_XVMC */
-{"mbd", "macroblock decision algorithm (high quality mode)", OFFSET(mb_decision), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "mbd"},
+{"mbd", "macroblock decision algorithm (high quality mode)", OFFSET(mb_decision), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, 2, V|E, "mbd"},
{"simple", "use mbcmp (default)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_SIMPLE }, INT_MIN, INT_MAX, V|E, "mbd"},
{"bits", "use fewest bits", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_BITS }, INT_MIN, INT_MAX, V|E, "mbd"},
{"rd", "use best rate distortion", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_RD }, INT_MIN, INT_MAX, V|E, "mbd"},
@@ -322,13 +335,13 @@ static const AVOption avcodec_options[] = {
#if FF_API_ERROR_RATE
{"error", NULL, OFFSET(error_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
#endif
-{"threads", NULL, OFFSET(thread_count), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, V|E|D, "threads"},
+{"threads", NULL, OFFSET(thread_count), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, V|A|E|D, "threads"},
{"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, V|E|D, "threads"},
#if FF_API_MPV_OPT
{"me_threshold", "motion estimation threshold", OFFSET(me_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"mb_threshold", "macroblock threshold", OFFSET(mb_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
#endif
-{"dc", "intra_dc_precision", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, V|E},
+{"dc", "intra_dc_precision", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, -8, 16, V|E},
{"nssew", "nsse weight", OFFSET(nsse_weight), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E},
{"skip_top", "number of macroblock rows at the top which are skipped", OFFSET(skip_top), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D},
{"skip_bottom", "number of macroblock rows at the bottom which are skipped", OFFSET(skip_bottom), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D},
@@ -349,8 +362,13 @@ static const AVOption avcodec_options[] = {
{"dts_96_24", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_96_24 }, INT_MIN, INT_MAX, A|E, "profile"},
{"dts_hd_hra", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_HD_HRA }, INT_MIN, INT_MAX, A|E, "profile"},
{"dts_hd_ma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_HD_MA }, INT_MIN, INT_MAX, A|E, "profile"},
+{"mpeg4_sp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_SIMPLE }, INT_MIN, INT_MAX, V|E, "profile"},
+{"mpeg4_core", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_CORE }, INT_MIN, INT_MAX, V|E, "profile"},
+{"mpeg4_main", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_MAIN }, INT_MIN, INT_MAX, V|E, "profile"},
+{"mpeg4_asp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_ADVANCED_SIMPLE }, INT_MIN, INT_MAX, V|E, "profile"},
{"level", NULL, OFFSET(level), AV_OPT_TYPE_INT, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "level"},
{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "level"},
+{"lowres", "decode at 1= 1/2, 2=1/4, 3=1/8 resolutions", OFFSET(lowres), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|A|D},
{"skip_threshold", "frame skip threshold", OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"skip_factor", "frame skip factor", OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"skip_exp", "frame skip exponent", OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
@@ -361,18 +379,19 @@ static const AVOption avcodec_options[] = {
{"mblmin", "minimum macroblock Lagrange factor (VBR)", OFFSET(mb_lmin), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 2 }, 1, FF_LAMBDA_MAX, V|E},
{"mblmax", "maximum macroblock Lagrange factor (VBR)", OFFSET(mb_lmax), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 31 }, 1, FF_LAMBDA_MAX, V|E},
{"mepc", "motion estimation bitrate penalty compensation (1.0 = 256)", OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, V|E},
-{"skip_loop_filter", NULL, OFFSET(skip_loop_filter), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"skip_idct" , NULL, OFFSET(skip_idct) , AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"skip_frame" , NULL, OFFSET(skip_frame) , AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"none" , NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONE }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"default" , NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"noref" , NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONREF }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"bidir" , NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_BIDIR }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"nokey" , NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONKEY }, INT_MIN, INT_MAX, V|D, "avdiscard"},
-{"all" , NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_ALL }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"skip_loop_filter", "skip loop filtering process for the selected frames", OFFSET(skip_loop_filter), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"skip_idct" , "skip IDCT/dequantization for the selected frames", OFFSET(skip_idct), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"skip_frame" , "skip decoding for the selected frames", OFFSET(skip_frame), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"none" , "discard no frame", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONE }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"default" , "discard useless frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"noref" , "discard all non-reference frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONREF }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"bidir" , "discard all bidirectional frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_BIDIR }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"nokey" , "discard all frames except keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONKEY }, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"nointra" , "discard all frames except I frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONINTRA}, INT_MIN, INT_MAX, V|D, "avdiscard"},
+{"all" , "discard all frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_ALL }, INT_MIN, INT_MAX, V|D, "avdiscard"},
{"bidir_refine", "refine the two motion vectors used in bidirectional macroblocks", OFFSET(bidir_refine), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 4, V|E},
{"brd_scale", "downscale frames for dynamic B-frame decision", OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, 10, V|E},
-{"keyint_min", "minimum interval between IDR-frames (x264)", OFFSET(keyint_min), AV_OPT_TYPE_INT, {.i64 = 25 }, INT_MIN, INT_MAX, V|E},
+{"keyint_min", "minimum interval between IDR-frames", OFFSET(keyint_min), AV_OPT_TYPE_INT, {.i64 = 25 }, INT_MIN, INT_MAX, V|E},
{"refs", "reference frames to consider for motion compensation", OFFSET(refs), AV_OPT_TYPE_INT, {.i64 = 1 }, INT_MIN, INT_MAX, V|E},
{"chromaoffset", "chroma QP offset from luma", OFFSET(chromaoffset), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E},
{"trellis", "rate-distortion optimal quantization", OFFSET(trellis), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E},
@@ -384,14 +403,14 @@ static const AVOption avcodec_options[] = {
{"compression_level", NULL, OFFSET(compression_level), AV_OPT_TYPE_INT, {.i64 = FF_COMPRESSION_DEFAULT }, INT_MIN, INT_MAX, V|A|E},
{"min_prediction_order", NULL, OFFSET(min_prediction_order), AV_OPT_TYPE_INT, {.i64 = -1 }, INT_MIN, INT_MAX, A|E},
{"max_prediction_order", NULL, OFFSET(max_prediction_order), AV_OPT_TYPE_INT, {.i64 = -1 }, INT_MIN, INT_MAX, A|E},
-{"timecode_frame_start", "GOP timecode frame start number, in non-drop-frame format", OFFSET(timecode_frame_start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, V|E},
+{"timecode_frame_start", "GOP timecode frame start number, in non-drop-frame format", OFFSET(timecode_frame_start), AV_OPT_TYPE_INT64, {.i64 = -1 }, -1, INT64_MAX, V|E},
#if FF_API_REQUEST_CHANNELS
{"request_channels", "set desired number of audio channels", OFFSET(request_channels), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D},
#endif
{"bits_per_raw_sample", NULL, OFFSET(bits_per_raw_sample), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX},
{"channel_layout", NULL, OFFSET(channel_layout), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT64_MAX, A|E|D, "channel_layout"},
{"request_channel_layout", NULL, OFFSET(request_channel_layout), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT64_MAX, A|D, "request_channel_layout"},
-{"rc_max_vbv_use", NULL, OFFSET(rc_max_available_vbv_use), AV_OPT_TYPE_FLOAT, {.dbl = 1.0/3 }, 0.0, FLT_MAX, V|E},
+{"rc_max_vbv_use", NULL, OFFSET(rc_max_available_vbv_use), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0.0, FLT_MAX, V|E},
{"rc_min_vbv_use", NULL, OFFSET(rc_min_vbv_overflow_use), AV_OPT_TYPE_FLOAT, {.dbl = 3 }, 0.0, FLT_MAX, V|E},
{"ticks_per_frame", NULL, OFFSET(ticks_per_frame), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, INT_MAX, A|V|E|D},
{"color_primaries", "color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_UNSPECIFIED }, 1, AVCOL_PRI_NB-1, V|E|D, "color_primaries_type"},
@@ -443,7 +462,7 @@ static const AVOption avcodec_options[] = {
{"bottom", "Bottom", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOM }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"},
{"log_level_offset", "set the log level offset", OFFSET(log_level_offset), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX },
{"slices", "number of slices, used in parallelized encoding", OFFSET(slices), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E},
-{"thread_type", "select multithreading type", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, {.i64 = FF_THREAD_SLICE|FF_THREAD_FRAME }, 0, INT_MAX, V|E|D, "thread_type"},
+{"thread_type", "select multithreading type", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, {.i64 = FF_THREAD_SLICE|FF_THREAD_FRAME }, 0, INT_MAX, V|A|E|D, "thread_type"},
{"slice", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_THREAD_SLICE }, INT_MIN, INT_MAX, V|E|D, "thread_type"},
{"frame", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_THREAD_FRAME }, INT_MIN, INT_MAX, V|E|D, "thread_type"},
{"audio_service_type", "audio service type", OFFSET(audio_service_type), AV_OPT_TYPE_INT, {.i64 = AV_AUDIO_SERVICE_TYPE_MAIN }, 0, AV_AUDIO_SERVICE_TYPE_NB-1, A|E, "audio_service_type"},
@@ -456,19 +475,26 @@ static const AVOption avcodec_options[] = {
{"em", "Emergency", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_EMERGENCY }, INT_MIN, INT_MAX, A|E, "audio_service_type"},
{"vo", "Voice Over", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_VOICE_OVER }, INT_MIN, INT_MAX, A|E, "audio_service_type"},
{"ka", "Karaoke", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_KARAOKE }, INT_MIN, INT_MAX, A|E, "audio_service_type"},
-{"request_sample_fmt", NULL, OFFSET(request_sample_fmt), AV_OPT_TYPE_INT, {.i64 = AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, A|D, "request_sample_fmt"},
-{"u8" , "8-bit unsigned integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8 }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"s16", "16-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16 }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"s32", "32-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32 }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"flt", "32-bit float", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLT }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"dbl", "64-bit double", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBL }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"u8p" , "8-bit unsigned integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8P }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"s16p", "16-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16P }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"s32p", "32-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32P }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"fltp", "32-bit float planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLTP }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
-{"dblp", "64-bit double planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBLP }, INT_MIN, INT_MAX, A|D, "request_sample_fmt"},
+{"request_sample_fmt", "sample format audio decoders should prefer", OFFSET(request_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, {.i64=AV_SAMPLE_FMT_NONE}, -1, INT_MAX, A|D, "request_sample_fmt"},
+{"pkt_timebase", NULL, OFFSET(pkt_timebase), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, 0, INT_MAX, 0},
+{"sub_charenc", "set input text subtitles character encoding", OFFSET(sub_charenc), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, S|D},
+{"sub_charenc_mode", "set input text subtitles character encoding mode", OFFSET(sub_charenc_mode), AV_OPT_TYPE_FLAGS, {.i64 = FF_SUB_CHARENC_MODE_AUTOMATIC}, -1, INT_MAX, S|D, "sub_charenc_mode"},
+{"do_nothing", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_DO_NOTHING}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"},
+{"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_AUTOMATIC}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"},
+{"pre_decoder", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_PRE_DECODER}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"},
{"refcounted_frames", NULL, OFFSET(refcounted_frames), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, A|V|D },
{"side_data_only_packets", NULL, OFFSET(side_data_only_packets), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, A|V|E },
+{"skip_alpha", "Skip processing alpha", OFFSET(skip_alpha), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, V|D },
+{"field_order", "Field order", OFFSET(field_order), AV_OPT_TYPE_INT, {.i64 = AV_FIELD_UNKNOWN }, 0, 5, V|D|E, "field_order" },
+{"progressive", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_PROGRESSIVE }, 0, 0, V|D|E, "field_order" },
+{"tt", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_TT }, 0, 0, V|D|E, "field_order" },
+{"bb", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_BB }, 0, 0, V|D|E, "field_order" },
+{"tb", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_TB }, 0, 0, V|D|E, "field_order" },
+{"bt", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_BT }, 0, 0, V|D|E, "field_order" },
+{"dump_separator", "set information dump field separator", OFFSET(dump_separator), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, A|V|S|D|E},
+{"codec_whitelist", "List of decoders that are allowed to be used", OFFSET(codec_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, A|V|S|D },
+{"pixel_format", "set pixel format", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64=AV_PIX_FMT_NONE}, -1, INT_MAX, 0 },
+{"video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str=NULL}, 0, INT_MAX, 0 },
{NULL},
};
diff --git a/libavcodec/opus.c b/libavcodec/opus.c
index 1bc417b477..6b3d3c310e 100644
--- a/libavcodec/opus.c
+++ b/libavcodec/opus.c
@@ -2,20 +2,20 @@
* Copyright (c) 2012 Andrew D'Addesio
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/opus.h b/libavcodec/opus.h
index 94993d623e..92bb28a371 100644
--- a/libavcodec/opus.h
+++ b/libavcodec/opus.h
@@ -3,20 +3,20 @@
* Copyright (c) 2012 Andrew D'Addesio
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,7 +29,7 @@
#include "libavutil/float_dsp.h"
#include "libavutil/frame.h"
-#include "libavresample/avresample.h"
+#include "libswresample/swresample.h"
#include "avcodec.h"
#include "get_bits.h"
@@ -57,7 +57,7 @@
#define SILK_HISTORY 322
#define SILK_MAX_LPC 16
-#define ROUND_MULL(a,b,s) (((MUL64(a, b) >> (s - 1)) + 1) >> 1)
+#define ROUND_MULL(a,b,s) (((MUL64(a, b) >> ((s) - 1)) + 1) >> 1)
#define ROUND_MUL16(a,b) ((MUL16(a, b) + 16384) >> 15)
#define opus_ilog(i) (av_log2(i) + !!(i))
@@ -104,19 +104,19 @@ typedef struct SilkContext SilkContext;
typedef struct CeltContext CeltContext;
typedef struct OpusPacket {
- int packet_size; /** packet size */
- int data_size; /** size of the useful data -- packet size - padding */
- int code; /** packet code: specifies the frame layout */
- int stereo; /** whether this packet is mono or stereo */
- int vbr; /** vbr flag */
- int config; /** configuration: tells the audio mode,
+ int packet_size; /**< packet size */
+ int data_size; /**< size of the useful data -- packet size - padding */
+ int code; /**< packet code: specifies the frame layout */
+ int stereo; /**< whether this packet is mono or stereo */
+ int vbr; /**< vbr flag */
+ int config; /**< configuration: tells the audio mode,
** bandwidth, and frame duration */
- int frame_count; /** frame count */
- int frame_offset[MAX_FRAMES]; /** frame offsets */
- int frame_size[MAX_FRAMES]; /** frame sizes */
- int frame_duration; /** frame duration, in samples @ 48kHz */
- enum OpusMode mode; /** mode */
- enum OpusBandwidth bandwidth; /** bandwidth */
+ int frame_count; /**< frame count */
+ int frame_offset[MAX_FRAMES]; /**< frame offsets */
+ int frame_size[MAX_FRAMES]; /**< frame sizes */
+ int frame_duration; /**< frame duration, in samples @ 48kHz */
+ enum OpusMode mode; /**< mode */
+ enum OpusBandwidth bandwidth; /**< bandwidth */
} OpusPacket;
typedef struct OpusStreamContext {
@@ -144,7 +144,7 @@ typedef struct OpusStreamContext {
float *out_dummy;
int out_dummy_allocated_size;
- AVAudioResampleContext *avr;
+ SwrContext *swr;
AVAudioFifo *celt_delay;
int silk_samplerate;
/* number of samples we still want to get from the resampler */
@@ -176,7 +176,7 @@ typedef struct OpusContext {
int nb_streams;
int nb_stereo_streams;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
int16_t gain_i;
float gain;
@@ -279,7 +279,7 @@ static av_always_inline unsigned int opus_getrawbits(OpusRangeCoder *rc, unsigne
rc->rb.bytes--;
}
- value = rc->rb.cacheval & ((1<<count)-1);
+ value = av_mod_uintp2(rc->rb.cacheval, count);
rc->rb.cacheval >>= count;
rc->rb.cachelen -= count;
rc->total_read_bits += count;
diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c
index d453e2d2e9..42623d9163 100644
--- a/libavcodec/opus_celt.c
+++ b/libavcodec/opus_celt.c
@@ -2,20 +2,20 @@
* Copyright (c) 2012 Andrew D'Addesio
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -62,7 +62,7 @@ struct CeltContext {
// constant values that do not change during context lifetime
AVCodecContext *avctx;
IMDCT15Context *imdct[4];
- AVFloatDSPContext dsp;
+ AVFloatDSPContext *dsp;
int output_channels;
// values that have inter-frame effect and must be reset on flush
@@ -991,7 +991,7 @@ static inline int celt_pulses2bits(const uint8_t *cache, int pulses)
return (pulses == 0) ? 0 : cache[pulses] + 1;
}
-static inline void celt_normalize_residual(const int * restrict iy, float * restrict X,
+static inline void celt_normalize_residual(const int * av_restrict iy, float * av_restrict X,
int N, float g)
{
int i;
@@ -1295,7 +1295,7 @@ static inline float celt_decode_pulses(OpusRangeCoder *rc, int *y, unsigned int
{
unsigned int idx;
#define CELT_PVQ_U(n, k) (celt_pvq_u_row[FFMIN(n, k)][FFMAX(n, k)])
-#define CELT_PVQ_V(n, k) (CELT_PVQ_U(n, k) + CELT_PVQ_U(n, k + 1))
+#define CELT_PVQ_V(n, k) (CELT_PVQ_U(n, k) + CELT_PVQ_U(n, (k) + 1))
idx = opus_rc_unimodel(rc, CELT_PVQ_V(N, K));
return celt_cwrsi(N, K, idx, y);
}
@@ -1454,7 +1454,7 @@ static unsigned int celt_decode_band(CeltContext *s, OpusRangeCoder *rc,
if (itheta == 0) {
imid = 32767;
iside = 0;
- fill &= (1 << blocks) - 1;
+ fill = av_mod_uintp2(fill, blocks);
delta = -16384;
} else if (itheta == 16384) {
imid = 0;
@@ -1666,7 +1666,7 @@ static unsigned int celt_decode_band(CeltContext *s, OpusRangeCoder *rc,
for (j = 0; j < N0; j++)
lowband_out[j] = n * X[j];
}
- cm &= (1 << blocks) - 1;
+ cm = av_mod_uintp2(cm, blocks);
}
return cm;
}
@@ -2072,7 +2072,7 @@ int ff_celt_decode_frame(CeltContext *s, OpusRangeCoder *rc,
/* stereo -> mono downmix */
if (s->output_channels < s->coded_channels) {
- s->dsp.vector_fmac_scalar(s->coeffs[0], s->coeffs[1], 1.0, FFALIGN(frame_size, 16));
+ s->dsp->vector_fmac_scalar(s->coeffs[0], s->coeffs[1], 1.0, FFALIGN(frame_size, 16));
imdct_scale = 0.5;
} else if (s->output_channels > s->coded_channels)
memcpy(s->coeffs[1], s->coeffs[0], frame_size * sizeof(float));
@@ -2098,7 +2098,7 @@ int ff_celt_decode_frame(CeltContext *s, OpusRangeCoder *rc,
imdct->imdct_half(imdct, dst + CELT_OVERLAP / 2, s->coeffs[i] + j,
s->blocks, imdct_scale);
- s->dsp.vector_fmul_window(dst, dst, dst + CELT_OVERLAP / 2,
+ s->dsp->vector_fmul_window(dst, dst, dst + CELT_OVERLAP / 2,
celt_window, CELT_OVERLAP / 2);
}
@@ -2181,6 +2181,7 @@ void ff_celt_free(CeltContext **ps)
for (i = 0; i < FF_ARRAY_ELEMS(s->imdct); i++)
ff_imdct15_uninit(&s->imdct[i]);
+ av_freep(&s->dsp);
av_freep(ps);
}
@@ -2208,7 +2209,11 @@ int ff_celt_init(AVCodecContext *avctx, CeltContext **ps, int output_channels)
goto fail;
}
- avpriv_float_dsp_init(&s->dsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->dsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->dsp) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
ff_celt_flush(s);
diff --git a/libavcodec/opus_parser.c b/libavcodec/opus_parser.c
index d256fbb2d5..c30fd7bbd4 100644
--- a/libavcodec/opus_parser.c
+++ b/libavcodec/opus_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/opus_silk.c b/libavcodec/opus_silk.c
index f881325d7b..841d1ed25c 100644
--- a/libavcodec/opus_silk.c
+++ b/libavcodec/opus_silk.c
@@ -2,20 +2,20 @@
* Copyright (c) 2012 Andrew D'Addesio
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c
index 771922e973..2ee3f2ad36 100644
--- a/libavcodec/opusdec.c
+++ b/libavcodec/opusdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2012 Andrew D'Addesio
* Copyright (c) 2013-2014 Mozilla Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,11 +40,9 @@
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
-#include "libavresample/avresample.h"
+#include "libswresample/swresample.h"
#include "avcodec.h"
-#include "celp_filters.h"
-#include "fft.h"
#include "get_bits.h"
#include "internal.h"
#include "mathops.h"
@@ -114,9 +112,9 @@ static int opus_flush_resample(OpusStreamContext *s, int nb_samples)
{
int celt_size = av_audio_fifo_size(s->celt_delay);
int ret, i;
-
- ret = avresample_convert(s->avr, (uint8_t**)s->out, s->out_size, nb_samples,
- NULL, 0, 0);
+ ret = swr_convert(s->swr,
+ (uint8_t**)s->out, nb_samples,
+ NULL, 0);
if (ret < 0)
return ret;
else if (ret != nb_samples) {
@@ -155,19 +153,20 @@ static int opus_flush_resample(OpusStreamContext *s, int nb_samples)
static int opus_init_resample(OpusStreamContext *s)
{
- float delay[16] = { 0.0 };
- uint8_t *delayptr[2] = { (uint8_t*)delay, (uint8_t*)delay };
+ static const float delay[16] = { 0.0 };
+ const uint8_t *delayptr[2] = { (uint8_t*)delay, (uint8_t*)delay };
int ret;
- av_opt_set_int(s->avr, "in_sample_rate", s->silk_samplerate, 0);
- ret = avresample_open(s->avr);
+ av_opt_set_int(s->swr, "in_sample_rate", s->silk_samplerate, 0);
+ ret = swr_init(s->swr);
if (ret < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Error opening the resampler.\n");
return ret;
}
- ret = avresample_convert(s->avr, NULL, 0, 0, delayptr, sizeof(delay),
- silk_resample_delay[s->packet.bandwidth]);
+ ret = swr_convert(s->swr,
+ NULL, 0,
+ delayptr, silk_resample_delay[s->packet.bandwidth]);
if (ret < 0) {
av_log(s->avctx, AV_LOG_ERROR,
"Error feeding initial silence to the resampler.\n");
@@ -218,7 +217,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size
/* decode the silk frame */
if (s->packet.mode == OPUS_MODE_SILK || s->packet.mode == OPUS_MODE_HYBRID) {
- if (!avresample_is_open(s->avr)) {
+ if (!swr_is_initialized(s->swr)) {
ret = opus_init_resample(s);
if (ret < 0)
return ret;
@@ -232,16 +231,14 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size
av_log(s->avctx, AV_LOG_ERROR, "Error decoding a SILK frame.\n");
return samples;
}
-
- samples = avresample_convert(s->avr, (uint8_t**)s->out, s->out_size,
- s->packet.frame_duration,
- (uint8_t**)s->silk_output,
- sizeof(s->silk_buf[0]),
- samples);
+ samples = swr_convert(s->swr,
+ (uint8_t**)s->out, s->packet.frame_duration,
+ (const uint8_t**)s->silk_output, samples);
if (samples < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Error resampling SILK data.\n");
return samples;
}
+ av_assert2((samples & 7) == 0);
s->delayed_samples += s->packet.frame_duration - samples;
} else
ff_silk_flush(s->silk);
@@ -374,10 +371,10 @@ static int opus_decode_subpacket(OpusStreamContext *s,
int i, j, ret;
/* check if we need to flush the resampler */
- if (avresample_is_open(s->avr)) {
+ if (swr_is_initialized(s->swr)) {
if (buf) {
int64_t cur_samplerate;
- av_opt_get_int(s->avr, "in_sample_rate", 0, &cur_samplerate);
+ av_opt_get_int(s->swr, "in_sample_rate", 0, &cur_samplerate);
flush_needed = (s->packet.mode == OPUS_MODE_CELT) || (cur_samplerate != s->silk_samplerate);
} else {
flush_needed = !!s->delayed_samples;
@@ -406,7 +403,7 @@ static int opus_decode_subpacket(OpusStreamContext *s,
av_log(s->avctx, AV_LOG_ERROR, "Error flushing the resampler.\n");
return ret;
}
- avresample_close(s->avr);
+ swr_close(s->swr);
output_samples += s->delayed_samples;
s->delayed_samples = 0;
@@ -452,6 +449,14 @@ static int opus_decode_packet(AVCodecContext *avctx, void *data,
int coded_samples = 0;
int decoded_samples = 0;
int i, ret;
+ int delayed_samples = 0;
+
+ for (i = 0; i < c->nb_streams; i++) {
+ OpusStreamContext *s = &c->streams[i];
+ s->out[0] =
+ s->out[1] = NULL;
+ delayed_samples = FFMAX(delayed_samples, s->delayed_samples);
+ }
/* decode the header of the first sub-packet to find out the sample count */
if (buf) {
@@ -465,7 +470,7 @@ static int opus_decode_packet(AVCodecContext *avctx, void *data,
c->streams[0].silk_samplerate = get_silk_samplerate(pkt->config);
}
- frame->nb_samples = coded_samples + c->streams[0].delayed_samples;
+ frame->nb_samples = coded_samples + delayed_samples;
/* no input or buffered data => nothing to do */
if (!frame->nb_samples) {
@@ -475,10 +480,8 @@ static int opus_decode_packet(AVCodecContext *avctx, void *data,
/* setup the data buffers */
ret = ff_get_buffer(avctx, frame, 0);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if (ret < 0)
return ret;
- }
frame->nb_samples = 0;
for (i = 0; i < avctx->channels; i++) {
@@ -536,7 +539,7 @@ static int opus_decode_packet(AVCodecContext *avctx, void *data,
}
if (c->gain_i) {
- c->fdsp.vector_fmul_scalar((float*)frame->extended_data[i],
+ c->fdsp->vector_fmul_scalar((float*)frame->extended_data[i],
(float*)frame->extended_data[i],
c->gain, FFALIGN(decoded_samples, 8));
}
@@ -561,7 +564,7 @@ static av_cold void opus_decode_flush(AVCodecContext *ctx)
if (s->celt_delay)
av_audio_fifo_drain(s->celt_delay, av_audio_fifo_size(s->celt_delay));
- avresample_close(s->avr);
+ swr_close(s->swr);
ff_silk_flush(s->silk);
ff_celt_flush(s->celt);
@@ -583,13 +586,14 @@ static av_cold int opus_decode_close(AVCodecContext *avctx)
s->out_dummy_allocated_size = 0;
av_audio_fifo_free(s->celt_delay);
- avresample_free(&s->avr);
+ swr_free(&s->swr);
}
av_freep(&c->streams);
c->nb_streams = 0;
av_freep(&c->channel_maps);
+ av_freep(&c->fdsp);
return 0;
}
@@ -602,7 +606,9 @@ static av_cold int opus_decode_init(AVCodecContext *avctx)
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
avctx->sample_rate = 48000;
- avpriv_float_dsp_init(&c->fdsp, 0);
+ c->fdsp = avpriv_float_dsp_alloc(0);
+ if (!c->fdsp)
+ return AVERROR(ENOMEM);
/* find out the channel configuration */
ret = ff_opus_parse_extradata(avctx, c);
@@ -631,18 +637,19 @@ static av_cold int opus_decode_init(AVCodecContext *avctx)
s->redundancy_output[j] = s->redundancy_buf[j];
}
- s->fdsp = &c->fdsp;
+ s->fdsp = c->fdsp;
- s->avr = avresample_alloc_context();
- if (!s->avr)
+ s->swr =swr_alloc();
+ if (!s->swr)
goto fail;
layout = (s->output_channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO;
- av_opt_set_int(s->avr, "in_sample_fmt", avctx->sample_fmt, 0);
- av_opt_set_int(s->avr, "out_sample_fmt", avctx->sample_fmt, 0);
- av_opt_set_int(s->avr, "in_channel_layout", layout, 0);
- av_opt_set_int(s->avr, "out_channel_layout", layout, 0);
- av_opt_set_int(s->avr, "out_sample_rate", avctx->sample_rate, 0);
+ av_opt_set_int(s->swr, "in_sample_fmt", avctx->sample_fmt, 0);
+ av_opt_set_int(s->swr, "out_sample_fmt", avctx->sample_fmt, 0);
+ av_opt_set_int(s->swr, "in_channel_layout", layout, 0);
+ av_opt_set_int(s->swr, "out_channel_layout", layout, 0);
+ av_opt_set_int(s->swr, "out_sample_rate", avctx->sample_rate, 0);
+ av_opt_set_int(s->swr, "filter_size", 16, 0);
ret = ff_silk_init(avctx, &s->silk, s->output_channels);
if (ret < 0)
diff --git a/libavcodec/paf.h b/libavcodec/paf.h
new file mode 100644
index 0000000000..ce8245f223
--- /dev/null
+++ b/libavcodec/paf.h
@@ -0,0 +1,28 @@
+/*
+ * Packed Animation File decoder/demuxer common code
+ * Copyright (c) 2012 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 AVCODEC_PAF_H
+#define AVCODEC_PAF_H
+
+#define PAF_SOUND_SAMPLES 2205
+#define PAF_SOUND_FRAME_SIZE ((256 + PAF_SOUND_SAMPLES) * 2)
+
+#endif /* AVCODEC_PAF_H */
diff --git a/libavcodec/pafaudio.c b/libavcodec/pafaudio.c
index 52aaabfcd5..aaaef5e9c8 100644
--- a/libavcodec/pafaudio.c
+++ b/libavcodec/pafaudio.c
@@ -2,20 +2,20 @@
* Packed Animation File audio decoder
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,9 +24,7 @@
#include "avcodec.h"
#include "internal.h"
#include "mathops.h"
-
-#define PAF_SOUND_SAMPLES 2205
-#define PAF_SOUND_FRAME_SIZE ((256 + PAF_SOUND_SAMPLES) * 2)
+#include "paf.h"
static av_cold int paf_audio_init(AVCodecContext *avctx)
{
diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c
index 650d036945..a27afed56d 100644
--- a/libavcodec/pafvideo.c
+++ b/libavcodec/pafvideo.c
@@ -2,20 +2,20 @@
* Packed Animation File video decoder
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,15 +26,24 @@
#include "copy_block.h"
#include "internal.h"
+
static const uint8_t block_sequences[16][8] = {
- { 0, 0, 0, 0, 0, 0, 0, 0 }, { 2, 0, 0, 0, 0, 0, 0, 0 },
- { 5, 7, 0, 0, 0, 0, 0, 0 }, { 5, 0, 0, 0, 0, 0, 0, 0 },
- { 6, 0, 0, 0, 0, 0, 0, 0 }, { 5, 7, 5, 7, 0, 0, 0, 0 },
- { 5, 7, 5, 0, 0, 0, 0, 0 }, { 5, 7, 6, 0, 0, 0, 0, 0 },
- { 5, 5, 0, 0, 0, 0, 0, 0 }, { 3, 0, 0, 0, 0, 0, 0, 0 },
- { 6, 6, 0, 0, 0, 0, 0, 0 }, { 2, 4, 0, 0, 0, 0, 0, 0 },
- { 2, 4, 5, 7, 0, 0, 0, 0 }, { 2, 4, 5, 0, 0, 0, 0, 0 },
- { 2, 4, 6, 0, 0, 0, 0, 0 }, { 2, 4, 5, 7, 5, 7, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 2, 0, 0, 0, 0, 0, 0, 0 },
+ { 5, 7, 0, 0, 0, 0, 0, 0 },
+ { 5, 0, 0, 0, 0, 0, 0, 0 },
+ { 6, 0, 0, 0, 0, 0, 0, 0 },
+ { 5, 7, 5, 7, 0, 0, 0, 0 },
+ { 5, 7, 5, 0, 0, 0, 0, 0 },
+ { 5, 7, 6, 0, 0, 0, 0, 0 },
+ { 5, 5, 0, 0, 0, 0, 0, 0 },
+ { 3, 0, 0, 0, 0, 0, 0, 0 },
+ { 6, 6, 0, 0, 0, 0, 0, 0 },
+ { 2, 4, 0, 0, 0, 0, 0, 0 },
+ { 2, 4, 5, 7, 0, 0, 0, 0 },
+ { 2, 4, 5, 0, 0, 0, 0, 0 },
+ { 2, 4, 6, 0, 0, 0, 0, 0 },
+ { 2, 4, 5, 7, 5, 7, 0, 0 },
};
typedef struct PAFVideoDecContext {
@@ -156,9 +165,11 @@ static int decode_0(PAFVideoDecContext *c, uint8_t *pkt, uint8_t code)
i = bytestream2_get_byte(&c->gb);
if (i) {
if (code & 0x10) {
- int pos = bytestream2_tell(&c->gb) & 3;
- if (pos)
- bytestream2_skip(&c->gb, 4 - pos);
+ int align;
+
+ align = bytestream2_tell(&c->gb) & 3;
+ if (align)
+ bytestream2_skip(&c->gb, 4 - align);
}
do {
int page, val, x, y;
diff --git a/libavcodec/pamenc.c b/libavcodec/pamenc.c
index 8535d3d235..7a51fe62b3 100644
--- a/libavcodec/pamenc.c
+++ b/libavcodec/pamenc.c
@@ -2,52 +2,39 @@
* PAM image format
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
-#include "bytestream.h"
#include "internal.h"
static int pam_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+ const AVFrame *p, int *got_packet)
{
uint8_t *bytestream_start, *bytestream, *bytestream_end;
- const AVFrame * const p = pict;
int i, h, w, n, linesize, depth, maxval, ret;
const char *tuple_type;
uint8_t *ptr;
- if ((ret = ff_alloc_packet(pkt, avpicture_get_size(avctx->pix_fmt,
- avctx->width,
- avctx->height) + 200)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
- return ret;
- }
-
- bytestream_start =
- bytestream = pkt->data;
- bytestream_end = pkt->data + pkt->size;
-
h = avctx->height;
w = avctx->width;
switch (avctx->pix_fmt) {
- case AV_PIX_FMT_MONOWHITE:
- n = (w + 7) >> 3;
+ case AV_PIX_FMT_MONOBLACK:
+ n = w;
depth = 1;
maxval = 1;
tuple_type = "BLACKANDWHITE";
@@ -58,21 +45,59 @@ static int pam_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
maxval = 255;
tuple_type = "GRAYSCALE";
break;
+ case AV_PIX_FMT_GRAY16BE:
+ n = w * 2;
+ depth = 1;
+ maxval = 0xFFFF;
+ tuple_type = "GRAYSCALE";
+ break;
+ case AV_PIX_FMT_GRAY8A:
+ n = w * 2;
+ depth = 2;
+ maxval = 255;
+ tuple_type = "GRAYSCALE_ALPHA";
+ break;
+ case AV_PIX_FMT_YA16BE:
+ n = w * 4;
+ depth = 2;
+ maxval = 0xFFFF;
+ tuple_type = "GRAYSCALE_ALPHA";
+ break;
case AV_PIX_FMT_RGB24:
n = w * 3;
depth = 3;
maxval = 255;
tuple_type = "RGB";
break;
- case AV_PIX_FMT_RGB32:
+ case AV_PIX_FMT_RGBA:
n = w * 4;
depth = 4;
maxval = 255;
tuple_type = "RGB_ALPHA";
break;
+ case AV_PIX_FMT_RGB48BE:
+ n = w * 6;
+ depth = 3;
+ maxval = 0xFFFF;
+ tuple_type = "RGB";
+ break;
+ case AV_PIX_FMT_RGBA64BE:
+ n = w * 8;
+ depth = 4;
+ maxval = 0xFFFF;
+ tuple_type = "RGB_ALPHA";
+ break;
default:
return -1;
}
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, n*h + 200)) < 0)
+ return ret;
+
+ bytestream_start =
+ bytestream = pkt->data;
+ bytestream_end = pkt->data + pkt->size;
+
snprintf(bytestream, bytestream_end - bytestream,
"P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n",
w, h, depth, maxval, tuple_type);
@@ -81,16 +106,11 @@ static int pam_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ptr = p->data[0];
linesize = p->linesize[0];
- if (avctx->pix_fmt == AV_PIX_FMT_RGB32) {
+ if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK){
int j;
- unsigned int v;
-
for (i = 0; i < h; i++) {
- for (j = 0; j < w; j++) {
- v = ((uint32_t *)ptr)[j];
- bytestream_put_be24(&bytestream, v);
- *bytestream++ = v >> 24;
- }
+ for (j = 0; j < w; j++)
+ *bytestream++ = ptr[j >> 3] >> (7 - j & 7) & 1;
ptr += linesize;
}
} else {
@@ -134,7 +154,10 @@ AVCodec ff_pam_encoder = {
.close = pam_encode_close,
.encode2 = pam_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_GRAY8, AV_PIX_FMT_MONOWHITE,
- AV_PIX_FMT_NONE
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
+ AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
+ AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
},
};
diff --git a/libavcodec/parser.c b/libavcodec/parser.c
index ef83728580..b06a959560 100644
--- a/libavcodec/parser.c
+++ b/libavcodec/parser.c
@@ -3,26 +3,28 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <string.h>
+#include "libavutil/avassert.h"
+#include "libavutil/atomic.h"
#include "libavutil/mem.h"
#include "internal.h"
@@ -40,20 +42,21 @@ AVCodecParser *av_parser_next(const AVCodecParser *p)
void av_register_codec_parser(AVCodecParser *parser)
{
- parser->next = av_first_parser;
- av_first_parser = parser;
+ do {
+ parser->next = av_first_parser;
+ } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser));
}
AVCodecParserContext *av_parser_init(int codec_id)
{
- AVCodecParserContext *s;
+ AVCodecParserContext *s = NULL;
AVCodecParser *parser;
int ret;
if (codec_id == AV_CODEC_ID_NONE)
return NULL;
- for (parser = av_first_parser; parser != NULL; parser = parser->next) {
+ for (parser = av_first_parser; parser; parser = parser->next) {
if (parser->codec_ids[0] == codec_id ||
parser->codec_ids[1] == codec_id ||
parser->codec_ids[2] == codec_id ||
@@ -66,25 +69,18 @@ AVCodecParserContext *av_parser_init(int codec_id)
found:
s = av_mallocz(sizeof(AVCodecParserContext));
if (!s)
- return NULL;
+ goto err_out;
s->parser = parser;
- if (parser->priv_data_size) {
- s->priv_data = av_mallocz(parser->priv_data_size);
- if (!s->priv_data) {
- av_free(s);
- return NULL;
- }
- }
+ s->priv_data = av_mallocz(parser->priv_data_size);
+ if (!s->priv_data)
+ goto err_out;
+ s->fetch_timestamp=1;
+ s->pict_type = AV_PICTURE_TYPE_I;
if (parser->parser_init) {
ret = parser->parser_init(s);
- if (ret != 0) {
- av_free(s->priv_data);
- av_free(s);
- return NULL;
- }
+ if (ret != 0)
+ goto err_out;
}
- s->fetch_timestamp = 1;
- s->pict_type = AV_PICTURE_TYPE_I;
s->key_frame = -1;
s->convergence_duration = 0;
s->dts_sync_point = INT_MIN;
@@ -93,25 +89,37 @@ found:
s->format = -1;
return s;
+
+err_out:
+ if (s)
+ av_freep(&s->priv_data);
+ av_free(s);
+ return NULL;
}
-void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove)
+void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove, int fuzzy)
{
int i;
- s->dts =
- s->pts = AV_NOPTS_VALUE;
- s->pos = -1;
- s->offset = 0;
+ if (!fuzzy) {
+ s->dts =
+ s->pts = AV_NOPTS_VALUE;
+ s->pos = -1;
+ s->offset = 0;
+ }
for (i = 0; i < AV_PARSER_PTS_NB; i++) {
if (s->cur_offset + off >= s->cur_frame_offset[i] &&
(s->frame_offset < s->cur_frame_offset[i] ||
- (!s->frame_offset && !s->next_frame_offset)) &&
- s->cur_frame_end[i]) {
- s->dts = s->cur_frame_dts[i];
- s->pts = s->cur_frame_pts[i];
- s->pos = s->cur_frame_pos[i];
- s->offset = s->next_frame_offset - s->cur_frame_offset[i];
+ (!s->frame_offset && !s->next_frame_offset)) && // first field/frame
+ // check disabled since MPEG-TS does not send complete PES packets
+ /*s->next_frame_offset + off <*/ s->cur_frame_end[i]){
+
+ if (!fuzzy || s->cur_frame_dts[i] != AV_NOPTS_VALUE) {
+ s->dts = s->cur_frame_dts[i];
+ s->pts = s->cur_frame_pts[i];
+ s->pos = s->cur_frame_pos[i];
+ s->offset = s->next_frame_offset - s->cur_frame_offset[i];
+ }
if (remove)
s->cur_frame_offset[i] = INT64_MAX;
if (s->cur_offset + off < s->cur_frame_end[i])
@@ -154,11 +162,12 @@ int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx,
s->last_pts = s->pts;
s->last_dts = s->dts;
s->last_pos = s->pos;
- ff_fetch_timestamp(s, 0, 0);
+ ff_fetch_timestamp(s, 0, 0, 0);
}
/* WARNING: the returned index can be negative */
index = s->parser->parser_parse(s, avctx, (const uint8_t **) poutbuf,
poutbuf_size, buf, buf_size);
+ av_assert0(index > -0x20000000); // The API does not allow returning AVERROR codes
/* update the file pointer */
if (*poutbuf_size) {
/* fill the data for the current frame */
@@ -214,7 +223,7 @@ void av_parser_close(AVCodecParserContext *s)
if (s) {
if (s->parser->parser_close)
s->parser->parser_close(s);
- av_free(s->priv_data);
+ av_freep(&s->priv_data);
av_free(s);
}
}
@@ -245,8 +254,10 @@ int ff_combine_frame(ParseContext *pc, int next,
*buf_size + pc->index +
FF_INPUT_BUFFER_PADDING_SIZE);
- if (!new_buffer)
+ if (!new_buffer) {
+ pc->index = 0;
return AVERROR(ENOMEM);
+ }
pc->buffer = new_buffer;
memcpy(&pc->buffer[pc->index], *buf, *buf_size);
pc->index += *buf_size;
@@ -261,9 +272,11 @@ int ff_combine_frame(ParseContext *pc, int next,
void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size,
next + pc->index +
FF_INPUT_BUFFER_PADDING_SIZE);
-
- if (!new_buffer)
+ if (!new_buffer) {
+ pc->overread_index =
+ pc->index = 0;
return AVERROR(ENOMEM);
+ }
pc->buffer = new_buffer;
if (next > -FF_INPUT_BUFFER_PADDING_SIZE)
memcpy(&pc->buffer[pc->index], *buf,
@@ -298,13 +311,14 @@ void ff_parse_close(AVCodecParserContext *s)
int ff_mpeg4video_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
{
- int i;
uint32_t state = -1;
+ const uint8_t *ptr = buf, *end = buf + buf_size;
- for (i = 0; i < buf_size; i++) {
- state = state << 8 | buf[i];
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &state);
if (state == 0x1B3 || state == 0x1B6)
- return i - 3;
+ return ptr - 4 - buf;
}
+
return 0;
}
diff --git a/libavcodec/parser.h b/libavcodec/parser.h
index ea1cae28a2..ef35547e9b 100644
--- a/libavcodec/parser.h
+++ b/libavcodec/parser.h
@@ -3,20 +3,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -53,7 +53,8 @@ void ff_parse_close(AVCodecParserContext *s);
* Fetch timestamps for a specific byte within the current access unit.
* @param off byte position within the access unit
* @param remove Found timestamps will be removed if set to 1, kept if set to 0.
+ * @param fuzzy Only use found value if it is more informative than what we already have
*/
-void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove);
+void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove, int fuzzy);
#endif /* AVCODEC_PARSER_H */
diff --git a/libavcodec/pcm-bluray.c b/libavcodec/pcm-bluray.c
index 85703ebfe6..5819e5371c 100644
--- a/libavcodec/pcm-bluray.c
+++ b/libavcodec/pcm-bluray.c
@@ -2,20 +2,20 @@
* LPCM codecs for PCM format found in Blu-ray PCM streams
* Copyright (c) 2009, 2013 Christian Schmidt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,13 +71,14 @@ static int pcm_bluray_parse_header(AVCodecContext *avctx,
/* get the sample depth and derive the sample format from it */
avctx->bits_per_coded_sample = bits_per_samples[header[3] >> 6];
- if (!avctx->bits_per_coded_sample) {
- av_log(avctx, AV_LOG_ERROR, "reserved sample depth (0)\n");
+ if (!(avctx->bits_per_coded_sample == 16 || avctx->bits_per_coded_sample == 24)) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported sample depth (%d)\n", avctx->bits_per_coded_sample);
return AVERROR_INVALIDDATA;
}
avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16
: AV_SAMPLE_FMT_S32;
- avctx->bits_per_raw_sample = avctx->bits_per_coded_sample;
+ if (avctx->sample_fmt == AV_SAMPLE_FMT_S32)
+ avctx->bits_per_raw_sample = avctx->bits_per_coded_sample;
/* get the sample rate. Not all values are used. */
switch (header[2] & 0x0f) {
@@ -154,10 +155,8 @@ static int pcm_bluray_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = samples;
- if ((retval = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((retval = ff_get_buffer(avctx, frame, 0)) < 0)
return retval;
- }
dst16 = (int16_t *)frame->data[0];
dst32 = (int32_t *)frame->data[0];
diff --git a/libavcodec/pcm-dvd.c b/libavcodec/pcm-dvd.c
index cb6bb0e5ed..47d5d68dfd 100644
--- a/libavcodec/pcm-dvd.c
+++ b/libavcodec/pcm-dvd.c
@@ -2,20 +2,20 @@
* LPCM codecs for PCM formats found in Video DVD streams
* Copyright (c) 2013 Christian Schmidt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
typedef struct PCMDVDContext {
uint32_t last_header; // Cached header to see if parsing is needed
int block_size; // Size of a block of samples in bytes
+ int last_block_size; // Size of the last block of samples in bytes
int samples_per_block; // Number of samples per channel per block
int groups_per_block; // Number of 20/24bit sample groups per block
uint8_t *extra_samples; // Pointer to leftover samples from a frame
@@ -69,6 +70,7 @@ static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
/* early exit if the header didn't change apart from the frame number */
if (s->last_header == header_int)
return 0;
+ s->last_header = -1;
if (avctx->debug & FF_DEBUG_PICT_INFO)
ff_dlog(avctx, "pcm_dvd_parse_header: header = %02x%02x%02x\n",
@@ -85,7 +87,9 @@ static int pcm_dvd_parse_header(AVCodecContext *avctx, const uint8_t *header)
/* get the sample depth and derive the sample format from it */
avctx->bits_per_coded_sample = 16 + (header[1] >> 6 & 3) * 4;
if (avctx->bits_per_coded_sample == 28) {
- av_log(avctx, AV_LOG_ERROR, "PCM DVD unsupported sample depth\n");
+ av_log(avctx, AV_LOG_ERROR,
+ "PCM DVD unsupported sample depth %i\n",
+ avctx->bits_per_coded_sample);
return AVERROR_INVALIDDATA;
}
avctx->sample_fmt = avctx->bits_per_coded_sample == 16 ? AV_SAMPLE_FMT_S16
@@ -170,6 +174,17 @@ static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src,
return dst16;
}
case 20:
+ if (avctx->channels == 1) {
+ do {
+ for (i = 2; i; i--) {
+ dst32[0] = bytestream2_get_be16u(&gb) << 16;
+ dst32[1] = bytestream2_get_be16u(&gb) << 16;
+ t = bytestream2_get_byteu(&gb);
+ *dst32++ += (t & 0xf0) << 8;
+ *dst32++ += (t & 0x0f) << 12;
+ }
+ } while (--blocks);
+ } else {
do {
for (i = s->groups_per_block; i; i--) {
dst32[0] = bytestream2_get_be16u(&gb) << 16;
@@ -184,8 +199,19 @@ static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src,
*dst32++ += (t & 0x0f) << 12;
}
} while (--blocks);
+ }
return dst32;
case 24:
+ if (avctx->channels == 1) {
+ do {
+ for (i = 2; i; i--) {
+ dst32[0] = bytestream2_get_be16u(&gb) << 16;
+ dst32[1] = bytestream2_get_be16u(&gb) << 16;
+ *dst32++ += bytestream2_get_byteu(&gb) << 8;
+ *dst32++ += bytestream2_get_byteu(&gb) << 8;
+ }
+ } while (--blocks);
+ } else {
do {
for (i = s->groups_per_block; i; i--) {
dst32[0] = bytestream2_get_be16u(&gb) << 16;
@@ -198,6 +224,7 @@ static void *pcm_dvd_decode_samples(AVCodecContext *avctx, const uint8_t *src,
*dst32++ += bytestream2_get_byteu(&gb) << 8;
}
} while (--blocks);
+ }
return dst32;
default:
return NULL;
@@ -222,6 +249,11 @@ static int pcm_dvd_decode_frame(AVCodecContext *avctx, void *data,
if ((retval = pcm_dvd_parse_header(avctx, src)))
return retval;
+ if (s->last_block_size && s->last_block_size != s->block_size) {
+ av_log(avctx, AV_LOG_WARNING, "block_size has changed %d != %d\n", s->last_block_size, s->block_size);
+ s->extra_sample_count = 0;
+ }
+ s->last_block_size = s->block_size;
src += 3;
buf_size -= 3;
@@ -229,10 +261,8 @@ static int pcm_dvd_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = blocks * s->samples_per_block;
- if ((retval = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((retval = ff_get_buffer(avctx, frame, 0)) < 0)
return retval;
- }
dst = frame->data[0];
/* consume leftover samples from last packet */
diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c
index e06712e841..0a4ad0b9d9 100644
--- a/libavcodec/pcm.c
+++ b/libavcodec/pcm.c
@@ -2,20 +2,20 @@
* PCM codecs
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,16 +48,6 @@ static av_cold int pcm_encode_init(AVCodecContext *avctx)
avctx->bits_per_coded_sample = av_get_bits_per_sample(avctx->codec->id);
avctx->block_align = avctx->channels * avctx->bits_per_coded_sample / 8;
avctx->bit_rate = avctx->block_align * avctx->sample_rate * 8;
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- return 0;
-}
-
-static av_cold int pcm_encode_close(AVCodecContext *avctx)
-{
- av_freep(&avctx->coded_frame);
return 0;
}
@@ -79,13 +69,24 @@ static av_cold int pcm_encode_close(AVCodecContext *avctx)
bytestream_put_ ## endian(&dst, v); \
}
+#define ENCODE_PLANAR(type, endian, dst, n, shift, offset) \
+ n /= avctx->channels; \
+ for (c = 0; c < avctx->channels; c++) { \
+ int i; \
+ samples_ ## type = (const type *) frame->extended_data[c]; \
+ for (i = n; i > 0; i--) { \
+ register type v = (*samples_ ## type++ >> shift) + offset; \
+ bytestream_put_ ## endian(&dst, v); \
+ } \
+ }
+
static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
- int n, sample_size, v, ret;
+ int n, c, sample_size, v, ret;
const short *samples;
unsigned char *dst;
- const uint8_t *srcu8;
+ const uint8_t *samples_uint8_t;
const int16_t *samples_int16_t;
const int32_t *samples_int32_t;
const int64_t *samples_int64_t;
@@ -96,10 +97,8 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
n = frame->nb_samples * avctx->channels;
samples = (const short *)frame->data[0];
- if ((ret = ff_alloc_packet(avpkt, n * sample_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, n * sample_size)) < 0)
return ret;
- }
dst = avpkt->data;
switch (avctx->codec->id) {
@@ -112,6 +111,9 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
case AV_CODEC_ID_PCM_S24LE:
ENCODE(int32_t, le24, samples, dst, n, 8, 0)
break;
+ case AV_CODEC_ID_PCM_S24LE_PLANAR:
+ ENCODE_PLANAR(int32_t, le24, dst, n, 8, 0)
+ break;
case AV_CODEC_ID_PCM_S24BE:
ENCODE(int32_t, be24, samples, dst, n, 8, 0)
break;
@@ -137,11 +139,10 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
ENCODE(uint16_t, be16, samples, dst, n, 0, 0x8000)
break;
case AV_CODEC_ID_PCM_S8:
- srcu8 = frame->data[0];
- for (; n > 0; n--) {
- v = *srcu8++;
- *dst++ = v - 128;
- }
+ ENCODE(uint8_t, byte, samples, dst, n, 0, -128)
+ break;
+ case AV_CODEC_ID_PCM_S8_PLANAR:
+ ENCODE_PLANAR(uint8_t, byte, dst, n, 0, -128)
break;
#if HAVE_BIGENDIAN
case AV_CODEC_ID_PCM_F64LE:
@@ -151,9 +152,15 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
case AV_CODEC_ID_PCM_F32LE:
ENCODE(int32_t, le32, samples, dst, n, 0, 0)
break;
+ case AV_CODEC_ID_PCM_S32LE_PLANAR:
+ ENCODE_PLANAR(int32_t, le32, dst, n, 0, 0)
+ break;
case AV_CODEC_ID_PCM_S16LE:
ENCODE(int16_t, le16, samples, dst, n, 0, 0)
break;
+ case AV_CODEC_ID_PCM_S16LE_PLANAR:
+ ENCODE_PLANAR(int16_t, le16, dst, n, 0, 0)
+ break;
case AV_CODEC_ID_PCM_F64BE:
case AV_CODEC_ID_PCM_F32BE:
case AV_CODEC_ID_PCM_S32BE:
@@ -169,6 +176,9 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
case AV_CODEC_ID_PCM_S16BE:
ENCODE(int16_t, be16, samples, dst, n, 0, 0)
break;
+ case AV_CODEC_ID_PCM_S16BE_PLANAR:
+ ENCODE_PLANAR(int16_t, be16, dst, n, 0, 0)
+ break;
case AV_CODEC_ID_PCM_F64LE:
case AV_CODEC_ID_PCM_F32LE:
case AV_CODEC_ID_PCM_S32LE:
@@ -176,7 +186,18 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
#endif /* HAVE_BIGENDIAN */
case AV_CODEC_ID_PCM_U8:
memcpy(dst, samples, n * sample_size);
- dst += n * sample_size;
+ break;
+#if HAVE_BIGENDIAN
+ case AV_CODEC_ID_PCM_S16BE_PLANAR:
+#else
+ case AV_CODEC_ID_PCM_S16LE_PLANAR:
+ case AV_CODEC_ID_PCM_S32LE_PLANAR:
+#endif /* HAVE_BIGENDIAN */
+ n /= avctx->channels;
+ for (c = 0; c < avctx->channels; c++) {
+ const uint8_t *src = frame->extended_data[c];
+ bytestream_put_buffer(&dst, src, n * sample_size);
+ }
break;
case AV_CODEC_ID_PCM_ALAW:
for (; n > 0; n--) {
@@ -212,7 +233,7 @@ static av_cold int pcm_decode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
- switch (avctx->codec->id) {
+ switch (avctx->codec_id) {
case AV_CODEC_ID_PCM_ALAW:
for (i = 0; i < 256; i++)
s->table[i] = alaw2linear(i);
@@ -228,7 +249,7 @@ static av_cold int pcm_decode_init(AVCodecContext *avctx)
avctx->sample_fmt = avctx->codec->sample_fmts[0];
if (avctx->sample_fmt == AV_SAMPLE_FMT_S32)
- avctx->bits_per_raw_sample = av_get_bits_per_sample(avctx->codec->id);
+ avctx->bits_per_raw_sample = av_get_bits_per_sample(avctx->codec_id);
return 0;
}
@@ -250,28 +271,17 @@ static av_cold int pcm_decode_init(AVCodecContext *avctx)
dst += size / 8; \
}
-#if HAVE_BIGENDIAN
-#define DECODE_PLANAR(size, endian, src, dst, n, shift, offset) \
- { \
- int n2; \
- n /= avctx->channels; \
- for (c = 0; c < avctx->channels; c++) { \
- samples = frame->extended_data[c]; \
- n2 = n; \
- DECODE(size, endian, src, samples, n2, 0, 0) \
- } \
- }
-#else
#define DECODE_PLANAR(size, endian, src, dst, n, shift, offset) \
- { \
- n /= avctx->channels; \
- for (c = 0; c < avctx->channels; c++) { \
- samples = frame->extended_data[c]; \
- memcpy(samples, src, n * size / 8); \
- src += n * size / 8; \
+ n /= avctx->channels; \
+ for (c = 0; c < avctx->channels; c++) { \
+ int i; \
+ dst = frame->extended_data[c]; \
+ for (i = n; i > 0; i--) { \
+ uint ## size ## _t v = bytestream_get_ ## endian(&src); \
+ AV_WN ## size ## A(dst, (v - offset) << shift); \
+ dst += size / 8; \
} \
}
-#endif /* HAVE_BIGENDIAN */
static int pcm_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
@@ -299,12 +309,24 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR(EINVAL);
}
+ if (avctx->channels == 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (avctx->codec_id != avctx->codec->id) {
+ av_log(avctx, AV_LOG_ERROR, "codec ids mismatch\n");
+ return AVERROR(EINVAL);
+ }
+
n = avctx->channels * sample_size;
if (n && buf_size % n) {
if (buf_size < n) {
- av_log(avctx, AV_LOG_ERROR, "invalid PCM packet\n");
- return -1;
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid PCM packet, data has size %d but at least a size of %d was expected\n",
+ buf_size, n);
+ return AVERROR_INVALIDDATA;
} else
buf_size -= buf_size % n;
}
@@ -313,13 +335,11 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = n * samples_per_block / avctx->channels;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = frame->data[0];
- switch (avctx->codec->id) {
+ switch (avctx->codec_id) {
case AV_CODEC_ID_PCM_U32LE:
DECODE(32, le32, src, samples, n, 0, 0x80000000)
break;
@@ -329,6 +349,9 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
case AV_CODEC_ID_PCM_S24LE:
DECODE(32, le24, src, samples, n, 8, 0)
break;
+ case AV_CODEC_ID_PCM_S24LE_PLANAR:
+ DECODE_PLANAR(32, le24, src, samples, n, 8, 0);
+ break;
case AV_CODEC_ID_PCM_S24BE:
DECODE(32, be24, src, samples, n, 8, 0)
break;
@@ -347,15 +370,6 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
samples += 2;
}
break;
- case AV_CODEC_ID_PCM_S16LE_PLANAR:
- DECODE_PLANAR(16, le16, src, samples, n, 0, 0);
- break;
- case AV_CODEC_ID_PCM_S24LE_PLANAR:
- DECODE_PLANAR(32, le24, src, samples, n, 8, 0);
- break;
- case AV_CODEC_ID_PCM_S32LE_PLANAR:
- DECODE_PLANAR(32, le32, src, samples, n, 0, 0);
- break;
case AV_CODEC_ID_PCM_U16LE:
DECODE(16, le16, src, samples, n, 0, 0x8000)
break;
@@ -366,6 +380,15 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
for (; n > 0; n--)
*samples++ = *src++ + 128;
break;
+ case AV_CODEC_ID_PCM_S8_PLANAR:
+ n /= avctx->channels;
+ for (c = 0; c < avctx->channels; c++) {
+ int i;
+ samples = frame->extended_data[c];
+ for (i = n; i > 0; i--)
+ *samples++ = *src++ + 128;
+ }
+ break;
#if HAVE_BIGENDIAN
case AV_CODEC_ID_PCM_F64LE:
DECODE(64, le64, src, samples, n, 0, 0)
@@ -374,9 +397,15 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
case AV_CODEC_ID_PCM_F32LE:
DECODE(32, le32, src, samples, n, 0, 0)
break;
+ case AV_CODEC_ID_PCM_S32LE_PLANAR:
+ DECODE_PLANAR(32, le32, src, samples, n, 0, 0);
+ break;
case AV_CODEC_ID_PCM_S16LE:
DECODE(16, le16, src, samples, n, 0, 0)
break;
+ case AV_CODEC_ID_PCM_S16LE_PLANAR:
+ DECODE_PLANAR(16, le16, src, samples, n, 0, 0);
+ break;
case AV_CODEC_ID_PCM_F64BE:
case AV_CODEC_ID_PCM_F32BE:
case AV_CODEC_ID_PCM_S32BE:
@@ -392,6 +421,9 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
case AV_CODEC_ID_PCM_S16BE:
DECODE(16, be16, src, samples, n, 0, 0)
break;
+ case AV_CODEC_ID_PCM_S16BE_PLANAR:
+ DECODE_PLANAR(16, be16, src, samples, n, 0, 0);
+ break;
case AV_CODEC_ID_PCM_F64LE:
case AV_CODEC_ID_PCM_F32LE:
case AV_CODEC_ID_PCM_S32LE:
@@ -400,6 +432,18 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data,
case AV_CODEC_ID_PCM_U8:
memcpy(samples, src, n * sample_size);
break;
+#if HAVE_BIGENDIAN
+ case AV_CODEC_ID_PCM_S16BE_PLANAR:
+#else
+ case AV_CODEC_ID_PCM_S16LE_PLANAR:
+ case AV_CODEC_ID_PCM_S32LE_PLANAR:
+#endif /* HAVE_BIGENDIAN */
+ n /= avctx->channels;
+ for (c = 0; c < avctx->channels; c++) {
+ samples = frame->extended_data[c];
+ bytestream_get_buffer(&src, samples, n * sample_size);
+ }
+ break;
case AV_CODEC_ID_PCM_ZORK:
for (; n > 0; n--) {
int v = *src++;
@@ -457,7 +501,6 @@ AVCodec ff_ ## name_ ## _encoder = { \
.id = AV_CODEC_ID_ ## id_, \
.init = pcm_encode_init, \
.encode2 = pcm_encode_frame, \
- .close = pcm_encode_close, \
.capabilities = CODEC_CAP_VARIABLE_FRAME_SIZE, \
.sample_fmts = (const enum AVSampleFormat[]){ sample_fmt_, \
AV_SAMPLE_FMT_NONE }, \
@@ -497,24 +540,26 @@ AVCodec ff_ ## name_ ## _decoder = { \
PCM_DECODER(id, sample_fmt_, name, long_name_)
/* Note: Do not forget to add new entries to the Makefile as well. */
-PCM_CODEC (PCM_ALAW, AV_SAMPLE_FMT_S16, pcm_alaw, "PCM A-law");
+PCM_CODEC (PCM_ALAW, AV_SAMPLE_FMT_S16, pcm_alaw, "PCM A-law / G.711 A-law");
PCM_CODEC (PCM_F32BE, AV_SAMPLE_FMT_FLT, pcm_f32be, "PCM 32-bit floating point big-endian");
PCM_CODEC (PCM_F32LE, AV_SAMPLE_FMT_FLT, pcm_f32le, "PCM 32-bit floating point little-endian");
PCM_CODEC (PCM_F64BE, AV_SAMPLE_FMT_DBL, pcm_f64be, "PCM 64-bit floating point big-endian");
PCM_CODEC (PCM_F64LE, AV_SAMPLE_FMT_DBL, pcm_f64le, "PCM 64-bit floating point little-endian");
-PCM_DECODER(PCM_LXF, AV_SAMPLE_FMT_S32P, pcm_lxf, "PCM signed 20-bit little-endian planar");
-PCM_CODEC (PCM_MULAW, AV_SAMPLE_FMT_S16, pcm_mulaw, "PCM mu-law");
+PCM_DECODER(PCM_LXF, AV_SAMPLE_FMT_S32P,pcm_lxf, "PCM signed 20-bit little-endian planar");
+PCM_CODEC (PCM_MULAW, AV_SAMPLE_FMT_S16, pcm_mulaw, "PCM mu-law / G.711 mu-law");
PCM_CODEC (PCM_S8, AV_SAMPLE_FMT_U8, pcm_s8, "PCM signed 8-bit");
+PCM_CODEC (PCM_S8_PLANAR, AV_SAMPLE_FMT_U8P, pcm_s8_planar, "PCM signed 8-bit planar");
PCM_CODEC (PCM_S16BE, AV_SAMPLE_FMT_S16, pcm_s16be, "PCM signed 16-bit big-endian");
+PCM_CODEC (PCM_S16BE_PLANAR, AV_SAMPLE_FMT_S16P,pcm_s16be_planar, "PCM signed 16-bit big-endian planar");
PCM_CODEC (PCM_S16LE, AV_SAMPLE_FMT_S16, pcm_s16le, "PCM signed 16-bit little-endian");
-PCM_DECODER(PCM_S16LE_PLANAR, AV_SAMPLE_FMT_S16P, pcm_s16le_planar, "PCM 16-bit little-endian planar");
+PCM_CODEC (PCM_S16LE_PLANAR, AV_SAMPLE_FMT_S16P,pcm_s16le_planar, "PCM signed 16-bit little-endian planar");
PCM_CODEC (PCM_S24BE, AV_SAMPLE_FMT_S32, pcm_s24be, "PCM signed 24-bit big-endian");
PCM_CODEC (PCM_S24DAUD, AV_SAMPLE_FMT_S16, pcm_s24daud, "PCM D-Cinema audio signed 24-bit");
PCM_CODEC (PCM_S24LE, AV_SAMPLE_FMT_S32, pcm_s24le, "PCM signed 24-bit little-endian");
-PCM_DECODER(PCM_S24LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s24le_planar, "PCM signed 24-bit little-endian planar");
+PCM_CODEC (PCM_S24LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s24le_planar, "PCM signed 24-bit little-endian planar");
PCM_CODEC (PCM_S32BE, AV_SAMPLE_FMT_S32, pcm_s32be, "PCM signed 32-bit big-endian");
PCM_CODEC (PCM_S32LE, AV_SAMPLE_FMT_S32, pcm_s32le, "PCM signed 32-bit little-endian");
-PCM_DECODER(PCM_S32LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s32le_planar, "PCM signed 32-bit little-endian planar");
+PCM_CODEC (PCM_S32LE_PLANAR, AV_SAMPLE_FMT_S32P,pcm_s32le_planar, "PCM signed 32-bit little-endian planar");
PCM_CODEC (PCM_U8, AV_SAMPLE_FMT_U8, pcm_u8, "PCM unsigned 8-bit");
PCM_CODEC (PCM_U16BE, AV_SAMPLE_FMT_S16, pcm_u16be, "PCM unsigned 16-bit big-endian");
PCM_CODEC (PCM_U16LE, AV_SAMPLE_FMT_S16, pcm_u16le, "PCM unsigned 16-bit little-endian");
@@ -523,3 +568,4 @@ PCM_CODEC (PCM_U24LE, AV_SAMPLE_FMT_S32, pcm_u24le, "PCM unsigned
PCM_CODEC (PCM_U32BE, AV_SAMPLE_FMT_S32, pcm_u32be, "PCM unsigned 32-bit big-endian");
PCM_CODEC (PCM_U32LE, AV_SAMPLE_FMT_S32, pcm_u32le, "PCM unsigned 32-bit little-endian");
PCM_DECODER(PCM_ZORK, AV_SAMPLE_FMT_U8, pcm_zork, "PCM Zork");
+
diff --git a/libavcodec/pcm_tablegen.c b/libavcodec/pcm_tablegen.c
index 7b4bc8c6c9..bf8e7fb707 100644
--- a/libavcodec/pcm_tablegen.c
+++ b/libavcodec/pcm_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pcm_tablegen.h b/libavcodec/pcm_tablegen.h
index 79d6561646..1387210a58 100644
--- a/libavcodec/pcm_tablegen.h
+++ b/libavcodec/pcm_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pcx.c b/libavcodec/pcx.c
index 61c971e073..6487aa573b 100644
--- a/libavcodec/pcx.c
+++ b/libavcodec/pcx.c
@@ -5,20 +5,20 @@
* This decoder does not support CGA palettes. I am unable to find samples
* and Netpbm cannot generate them.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,44 +28,37 @@
#include "get_bits.h"
#include "internal.h"
-/**
- * @return advanced src pointer
- */
-static const uint8_t *pcx_rle_decode(const uint8_t *src,
- const uint8_t *end,
- uint8_t *dst,
- unsigned int bytes_per_scanline,
- int compressed)
+static void pcx_rle_decode(GetByteContext *gb,
+ uint8_t *dst,
+ unsigned int bytes_per_scanline,
+ int compressed)
{
unsigned int i = 0;
unsigned char run, value;
if (compressed) {
- while (i < bytes_per_scanline && src < end) {
+ while (i < bytes_per_scanline && bytestream2_get_bytes_left(gb)>0) {
run = 1;
- value = *src++;
- if (value >= 0xc0 && src < end) {
+ value = bytestream2_get_byte(gb);
+ if (value >= 0xc0 && bytestream2_get_bytes_left(gb)>0) {
run = value & 0x3f;
- value = *src++;
+ value = bytestream2_get_byte(gb);
}
while (i < bytes_per_scanline && run--)
dst[i++] = value;
}
} else {
- memcpy(dst, src, bytes_per_scanline);
- src += bytes_per_scanline;
+ bytestream2_get_buffer(gb, dst, bytes_per_scanline);
}
-
- return src;
}
-static void pcx_palette(const uint8_t **src, uint32_t *dst,
- unsigned int pallen)
+static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen)
{
- unsigned int i;
+ int i;
+ pallen = FFMIN(pallen, bytestream2_get_bytes_left(gb) / 3);
for (i = 0; i < pallen; i++)
- *dst++ = bytestream_get_be24(src);
+ *dst++ = 0xFF000000 | bytestream2_get_be24u(gb);
if (pallen < 256)
memset(dst, 0, (256 - pallen) * sizeof(*dst));
}
@@ -73,28 +66,32 @@ static void pcx_palette(const uint8_t **src, uint32_t *dst,
static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
- AVFrame *const p = data;
+ GetByteContext gb;
+ AVFrame * const p = data;
int compressed, xmin, ymin, xmax, ymax;
+ int ret;
unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
bytes_per_scanline;
- uint8_t *ptr;
- const uint8_t *buf_end = buf + buf_size;
- uint8_t const *bufstart = buf;
- uint8_t *scanline;
- int ret = -1;
+ uint8_t *ptr, *scanline;
+
+ if (avpkt->size < 128)
+ return AVERROR_INVALIDDATA;
+
+ bytestream2_init(&gb, avpkt->data, avpkt->size);
- if (buf[0] != 0x0a || buf[1] > 5) {
+ if (bytestream2_get_byteu(&gb) != 0x0a || bytestream2_get_byteu(&gb) > 5) {
av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n");
return AVERROR_INVALIDDATA;
}
- compressed = buf[2];
- xmin = AV_RL16(buf + 4);
- ymin = AV_RL16(buf + 6);
- xmax = AV_RL16(buf + 8);
- ymax = AV_RL16(buf + 10);
+ compressed = bytestream2_get_byteu(&gb);
+ bits_per_pixel = bytestream2_get_byteu(&gb);
+ xmin = bytestream2_get_le16u(&gb);
+ ymin = bytestream2_get_le16u(&gb);
+ xmax = bytestream2_get_le16u(&gb);
+ ymax = bytestream2_get_le16u(&gb);
+ avctx->sample_aspect_ratio.num = bytestream2_get_le16u(&gb);
+ avctx->sample_aspect_ratio.den = bytestream2_get_le16u(&gb);
if (xmax < xmin || ymax < ymin) {
av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n");
@@ -104,13 +101,13 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
w = xmax - xmin + 1;
h = ymax - ymin + 1;
- bits_per_pixel = buf[3];
- bytes_per_line = AV_RL16(buf + 66);
- nplanes = buf[65];
+ bytestream2_skipu(&gb, 49);
+ nplanes = bytestream2_get_byteu(&gb);
+ bytes_per_line = bytestream2_get_le16u(&gb);
bytes_per_scanline = nplanes * bytes_per_line;
if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8 ||
- (!compressed && bytes_per_scanline > buf_size / h)) {
+ (!compressed && bytes_per_scanline > bytestream2_get_bytes_left(&gb) / h)) {
av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
return AVERROR_INVALIDDATA;
}
@@ -133,29 +130,26 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- buf += 128;
+ bytestream2_skipu(&gb, 60);
if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
ptr = p->data[0];
stride = p->linesize[0];
- scanline = av_malloc(bytes_per_scanline);
+ scanline = av_malloc(bytes_per_scanline + FF_INPUT_BUFFER_PADDING_SIZE);
if (!scanline)
return AVERROR(ENOMEM);
if (nplanes == 3 && bits_per_pixel == 8) {
for (y = 0; y < h; y++) {
- buf = pcx_rle_decode(buf, buf_end,
- scanline, bytes_per_scanline, compressed);
+ pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
for (x = 0; x < w; x++) {
ptr[3 * x] = scanline[x];
@@ -166,39 +160,37 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
ptr += stride;
}
} else if (nplanes == 1 && bits_per_pixel == 8) {
- const uint8_t *palstart = bufstart + buf_size - 769;
+ int palstart = avpkt->size - 769;
- if (buf_size < 769) {
+ if (avpkt->size < 769) {
av_log(avctx, AV_LOG_ERROR, "File is too short\n");
ret = avctx->err_recognition & AV_EF_EXPLODE ?
- AVERROR_INVALIDDATA : buf_size;
+ AVERROR_INVALIDDATA : avpkt->size;
goto end;
}
for (y = 0; y < h; y++, ptr += stride) {
- buf = pcx_rle_decode(buf, buf_end,
- scanline, bytes_per_scanline, compressed);
+ pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
memcpy(ptr, scanline, w);
}
- if (buf != palstart) {
+ if (bytestream2_tell(&gb) != palstart) {
av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n");
- buf = palstart;
+ bytestream2_seek(&gb, palstart, SEEK_SET);
}
- if (*buf++ != 12) {
+ if (bytestream2_get_byte(&gb) != 12) {
av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n");
ret = avctx->err_recognition & AV_EF_EXPLODE ?
- AVERROR_INVALIDDATA : buf_size;
+ AVERROR_INVALIDDATA : avpkt->size;
goto end;
}
} else if (nplanes == 1) { /* all packed formats, max. 16 colors */
GetBitContext s;
for (y = 0; y < h; y++) {
- init_get_bits(&s, scanline, bytes_per_scanline << 3);
+ init_get_bits8(&s, scanline, bytes_per_scanline);
- buf = pcx_rle_decode(buf, buf_end,
- scanline, bytes_per_scanline, compressed);
+ pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
for (x = 0; x < w; x++)
ptr[x] = get_bits(&s, bits_per_pixel);
@@ -208,8 +200,7 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int i;
for (y = 0; y < h; y++) {
- buf = pcx_rle_decode(buf, buf_end,
- scanline, bytes_per_scanline, compressed);
+ pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
for (x = 0; x < w; x++) {
int m = 0x80 >> (x & 7), v = 0;
@@ -223,16 +214,20 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
}
+ ret = bytestream2_tell(&gb);
if (nplanes == 1 && bits_per_pixel == 8) {
- pcx_palette(&buf, (uint32_t *)p->data[1], 256);
+ pcx_palette(&gb, (uint32_t *)p->data[1], 256);
+ ret += 256 * 3;
+ } else if (bits_per_pixel * nplanes == 1) {
+ AV_WN32A(p->data[1] , 0xFF000000);
+ AV_WN32A(p->data[1]+4, 0xFFFFFFFF);
} else if (bits_per_pixel < 8) {
- const uint8_t *palette = bufstart + 16;
- pcx_palette(&palette, (uint32_t *)p->data[1], 16);
+ bytestream2_seek(&gb, 16, SEEK_SET);
+ pcx_palette(&gb, (uint32_t *)p->data[1], 16);
}
*got_frame = 1;
- ret = buf - bufstart;
end:
av_free(scanline);
return ret;
diff --git a/libavcodec/pcxenc.c b/libavcodec/pcxenc.c
index 8553fe166e..a718428d7a 100644
--- a/libavcodec/pcxenc.c
+++ b/libavcodec/pcxenc.c
@@ -2,20 +2,20 @@
* PC Paintbrush PCX (.pcx) image encoder
* Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,7 @@
#include "avcodec.h"
#include "bytestream.h"
+#include "libavutil/imgutils.h"
#include "internal.h"
static const uint32_t monoblack_pal[16] = { 0x000000, 0xFFFFFF };
@@ -106,8 +107,9 @@ static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const uint8_t *buf_end;
uint8_t *buf;
- int bpp, nplanes, i, y, line_bytes, written, ret, max_pkt_size;
+ int bpp, nplanes, i, y, line_bytes, written, ret, max_pkt_size, sw, sh;
const uint32_t *pal = NULL;
+ uint32_t palette256[256];
const uint8_t *src;
if (avctx->width > 65535 || avctx->height > 65535) {
@@ -125,6 +127,11 @@ static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case AV_PIX_FMT_RGB4_BYTE:
case AV_PIX_FMT_BGR4_BYTE:
case AV_PIX_FMT_GRAY8:
+ bpp = 8;
+ nplanes = 1;
+ avpriv_set_systematic_pal2(palette256, avctx->pix_fmt);
+ pal = palette256;
+ break;
case AV_PIX_FMT_PAL8:
bpp = 8;
nplanes = 1;
@@ -144,13 +151,16 @@ static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
line_bytes = (line_bytes + 1) & ~1;
max_pkt_size = 128 + avctx->height * 2 * line_bytes * nplanes + (pal ? 256*3 + 1 : 0);
- if ((ret = ff_alloc_packet(pkt, max_pkt_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", max_pkt_size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, max_pkt_size)) < 0)
return ret;
- }
buf = pkt->data;
buf_end = pkt->data + pkt->size;
+ sw = avctx->sample_aspect_ratio.num;
+ sh = avctx->sample_aspect_ratio.den;
+ if (sw > 0xFFFFu || sh > 0xFFFFu)
+ av_reduce(&sw, &sh, sw, sh, 0xFFFFu);
+
bytestream_put_byte(&buf, 10); // manufacturer
bytestream_put_byte(&buf, 5); // version
bytestream_put_byte(&buf, 1); // encoding
@@ -159,8 +169,8 @@ static int pcx_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bytestream_put_le16(&buf, 0); // y min
bytestream_put_le16(&buf, avctx->width - 1); // x max
bytestream_put_le16(&buf, avctx->height - 1); // y max
- bytestream_put_le16(&buf, 0); // horizontal DPI
- bytestream_put_le16(&buf, 0); // vertical DPI
+ bytestream_put_le16(&buf, sw); // horizontal DPI
+ bytestream_put_le16(&buf, sh); // vertical DPI
for (i = 0; i < 16; i++)
bytestream_put_be24(&buf, pal ? pal[i] : 0);// palette (<= 16 color only)
bytestream_put_byte(&buf, 0); // reserved
diff --git a/libavcodec/pel_template.c b/libavcodec/pel_template.c
index b832ae7624..6da7a56b2d 100644
--- a/libavcodec/pel_template.c
+++ b/libavcodec/pel_template.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c
index 72142e6f7c..0d307f5302 100644
--- a/libavcodec/pgssubdec.c
+++ b/libavcodec/pgssubdec.c
@@ -2,20 +2,20 @@
* PGS subtitle decoder
* Copyright (c) 2009 Stephen Backway
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "libavutil/colorspace.h"
#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define MAX_EPOCH_PALETTES 8 // Max 8 allowed per PGS epoch
@@ -90,9 +91,11 @@ typedef struct PGSSubPalettes {
} PGSSubPalettes;
typedef struct PGSSubContext {
+ AVClass *class;
PGSSubPresentation presentation;
PGSSubPalettes palettes;
PGSSubObjects objects;
+ int forced_subs_only;
} PGSSubContext;
static void flush_cache(AVCodecContext *avctx)
@@ -133,7 +136,7 @@ static PGSSubPalette * find_palette(int id, PGSSubPalettes *palettes)
static av_cold int init_decoder(AVCodecContext *avctx)
{
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
return 0;
}
@@ -148,7 +151,7 @@ static av_cold int close_decoder(AVCodecContext *avctx)
/**
* Decode the RLE data.
*
- * The subtitle is stored as an Run Length Encoded image.
+ * The subtitle is stored as a Run Length Encoded image.
*
* @param avctx contains the current codec context
* @param sub pointer to the processed subtitle data
@@ -163,7 +166,7 @@ static int decode_rle(AVCodecContext *avctx, AVSubtitleRect *rect,
rle_bitmap_end = buf + buf_size;
- rect->pict.data[0] = av_malloc(rect->w * rect->h);
+ rect->pict.data[0] = av_malloc_array(rect->w, rect->h);
if (!rect->pict.data[0])
return AVERROR(ENOMEM);
@@ -295,7 +298,7 @@ static int parse_object_segment(AVCodecContext *avctx,
object->w = width;
object->h = height;
- av_fast_malloc(&object->rle, &object->rle_buffer_size, rle_bitmap_len);
+ av_fast_padded_malloc(&object->rle, &object->rle_buffer_size, rle_bitmap_len);
if (!object->rle)
return AVERROR(ENOMEM);
@@ -378,8 +381,8 @@ static int parse_presentation_segment(AVCodecContext *avctx,
int64_t pts)
{
PGSSubContext *ctx = avctx->priv_data;
-
int i, state, ret;
+ const uint8_t *buf_end = buf + buf_size;
// Video descriptor
int w = bytestream_get_be16(&buf);
@@ -428,8 +431,16 @@ static int parse_presentation_segment(AVCodecContext *avctx,
}
}
+
for (i = 0; i < ctx->presentation.object_count; i++)
{
+
+ if (buf_end - buf < 8) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficent space for object\n");
+ ctx->presentation.object_count = i;
+ return AVERROR_INVALIDDATA;
+ }
+
ctx->presentation.objects[i].id = bytestream_get_be16(&buf);
ctx->presentation.objects[i].window_id = bytestream_get_byte(&buf);
ctx->presentation.objects[i].composition_flag = bytestream_get_byte(&buf);
@@ -480,11 +491,14 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
{
AVSubtitle *sub = data;
PGSSubContext *ctx = avctx->priv_data;
+ int64_t pts;
PGSSubPalette *palette;
int i, ret;
+ pts = ctx->presentation.pts != AV_NOPTS_VALUE ? ctx->presentation.pts : sub->pts;
memset(sub, 0, sizeof(*sub));
- sub->pts = ctx->presentation.pts;
+ sub->pts = pts;
+ ctx->presentation.pts = AV_NOPTS_VALUE;
sub->start_display_time = 0;
// There is no explicit end time for PGS subtitles. The end time
// is defined by the start of the next sub which may contain no
@@ -495,7 +509,7 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
// Blank if last object_count was 0.
if (!ctx->presentation.object_count)
return 1;
- sub->rects = av_mallocz(sizeof(*sub->rects) * ctx->presentation.object_count);
+ sub->rects = av_mallocz_array(ctx->presentation.object_count, sizeof(*sub->rects));
if (!sub->rects) {
return AVERROR(ENOMEM);
}
@@ -570,6 +584,7 @@ static int display_end_segment(AVCodecContext *avctx, void *data,
return AVERROR(ENOMEM);
}
+ if (!ctx->forced_subs_only || ctx->presentation.objects[i].composition_flag & 0x40)
memcpy(sub->rects[i]->pict.data[1], palette->clut, sub->rects[i]->nb_colors * sizeof(uint32_t));
}
@@ -625,7 +640,7 @@ static int decode(AVCodecContext *avctx, void *data, int *data_size,
ret = parse_object_segment(avctx, buf, segment_length);
break;
case PRESENTATION_SEGMENT:
- ret = parse_presentation_segment(avctx, buf, segment_length, avpkt->pts);
+ ret = parse_presentation_segment(avctx, buf, segment_length, ((AVSubtitle*)(data))->pts);
break;
case WINDOW_SEGMENT:
/*
@@ -657,6 +672,20 @@ static int decode(AVCodecContext *avctx, void *data, int *data_size,
return buf_size;
}
+#define OFFSET(x) offsetof(PGSSubContext, x)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ {"forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD},
+ { NULL },
+};
+
+static const AVClass pgsdec_class = {
+ .class_name = "PGS subtitle decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_pgssub_decoder = {
.name = "pgssub",
.long_name = NULL_IF_CONFIG_SMALL("HDMV Presentation Graphic Stream subtitles"),
@@ -666,4 +695,5 @@ AVCodec ff_pgssub_decoder = {
.init = init_decoder,
.close = close_decoder,
.decode = decode,
+ .priv_class = &pgsdec_class,
};
diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c
index 33c4545483..1bc51bcf24 100644
--- a/libavcodec/pictordec.c
+++ b/libavcodec/pictordec.c
@@ -2,20 +2,20 @@
* Pictor/PC Paint decoder
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -105,7 +105,7 @@ static int decode_frame(AVCodecContext *avctx,
AVFrame *frame = data;
uint32_t *palette;
int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
- int i, x, y, plane, tmp, ret;
+ int i, x, y, plane, tmp, ret, val;
bytestream2_init(&s->g, avpkt->data, avpkt->size);
@@ -127,7 +127,7 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_PATCHWELCOME;
}
- if (bytestream2_peek_byte(&s->g) == 0xFF) {
+ if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
bytestream2_skip(&s->g, 2);
etype = bytestream2_get_le16(&s->g);
esize = bytestream2_get_le16(&s->g);
@@ -140,16 +140,16 @@ static int decode_frame(AVCodecContext *avctx,
avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
+ return -1;
if (s->width != avctx->width && s->height != avctx->height) {
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
}
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
memset(frame->data[0], 0, s->height * frame->linesize[0]);
frame->pict_type = AV_PICTURE_TYPE_I;
frame->palette_has_changed = 1;
@@ -165,7 +165,7 @@ static int decode_frame(AVCodecContext *avctx,
npal = FFMIN(esize, 16);
for (i = 0; i < npal; i++) {
int pal_idx = bytestream2_get_byte(&s->g);
- palette[i] = ff_cga_palette[FFMIN(pal_idx, 16)];
+ palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
}
} else if (etype == 3) {
npal = FFMIN(esize, 16);
@@ -175,13 +175,15 @@ static int decode_frame(AVCodecContext *avctx,
}
} else if (etype == 4 || etype == 5) {
npal = FFMIN(esize / 3, 256);
- for (i = 0; i < npal; i++)
+ for (i = 0; i < npal; i++) {
palette[i] = bytestream2_get_be24(&s->g) << 2;
+ palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
+ }
} else {
if (bpp == 1) {
npal = 2;
- palette[0] = 0x000000;
- palette[1] = 0xFFFFFF;
+ palette[0] = 0xFF000000;
+ palette[1] = 0xFFFFFFFF;
} else if (bpp == 2) {
npal = 4;
for (i = 0; i < npal; i++)
@@ -196,10 +198,11 @@ static int decode_frame(AVCodecContext *avctx,
// skip remaining palette bytes
bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
- x = 0;
+ val = 0;
y = s->height - 1;
- plane = 0;
if (bytestream2_get_le16(&s->g)) {
+ x = 0;
+ plane = 0;
while (bytestream2_get_bytes_left(&s->g) >= 6) {
int stop_size, marker, t1, t2;
@@ -213,7 +216,7 @@ static int decode_frame(AVCodecContext *avctx,
while (plane < s->nb_planes &&
bytestream2_get_bytes_left(&s->g) > stop_size) {
int run = 1;
- int val = bytestream2_get_byte(&s->g);
+ val = bytestream2_get_byte(&s->g);
if (val == marker) {
run = bytestream2_get_byte(&s->g);
if (run == 0)
@@ -232,9 +235,20 @@ static int decode_frame(AVCodecContext *avctx,
}
}
}
+
+ if (x < avctx->width) {
+ int run = (y + 1) * avctx->width - x;
+ if (bits_per_plane == 8)
+ picmemset_8bpp(s, frame, val, run, &x, &y);
+ else
+ picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
+ }
} else {
- avpriv_request_sample(avctx, "Uncompressed image");
- return avpkt->size;
+ while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
+ memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
+ bytestream2_skip(&s->g, avctx->width);
+ y--;
+ }
}
finish:
diff --git a/libavcodec/pixblockdsp.c b/libavcodec/pixblockdsp.c
index 71423f9cfc..ebde68b6a4 100644
--- a/libavcodec/pixblockdsp.c
+++ b/libavcodec/pixblockdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,7 @@
#define BIT_DEPTH 8
#include "pixblockdsp_template.c"
-static void diff_pixels_c(int16_t *restrict block, const uint8_t *s1,
+static void diff_pixels_c(int16_t *av_restrict block, const uint8_t *s1,
const uint8_t *s2, int stride)
{
int i;
@@ -60,13 +60,19 @@ av_cold void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx)
switch (avctx->bits_per_raw_sample) {
case 9:
case 10:
+ case 12:
+ case 14:
c->get_pixels = get_pixels_16_c;
break;
default:
- c->get_pixels = get_pixels_8_c;
+ if (avctx->bits_per_raw_sample<=8 || avctx->codec_type != AVMEDIA_TYPE_VIDEO) {
+ c->get_pixels = get_pixels_8_c;
+ }
break;
}
+ if (ARCH_ALPHA)
+ ff_pixblockdsp_init_alpha(c, avctx, high_bit_depth);
if (ARCH_ARM)
ff_pixblockdsp_init_arm(c, avctx, high_bit_depth);
if (ARCH_PPC)
diff --git a/libavcodec/pixblockdsp.h b/libavcodec/pixblockdsp.h
index 8094d14b68..d4b8590341 100644
--- a/libavcodec/pixblockdsp.h
+++ b/libavcodec/pixblockdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,7 +26,7 @@
typedef struct PixblockDSPContext {
void (*get_pixels)(int16_t *block /* align 16 */,
const uint8_t *pixels /* align 8 */,
- int line_size);
+ ptrdiff_t line_size);
void (*diff_pixels)(int16_t *block /* align 16 */,
const uint8_t *s1 /* align 8 */,
const uint8_t *s2 /* align 8 */,
@@ -34,6 +34,8 @@ typedef struct PixblockDSPContext {
} PixblockDSPContext;
void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx);
+void ff_pixblockdsp_init_alpha(PixblockDSPContext *c, AVCodecContext *avctx,
+ unsigned high_bit_depth);
void ff_pixblockdsp_init_arm(PixblockDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth);
void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, AVCodecContext *avctx,
diff --git a/libavcodec/pixblockdsp_template.c b/libavcodec/pixblockdsp_template.c
index 71d3cf150d..d1e91022a7 100644
--- a/libavcodec/pixblockdsp_template.c
+++ b/libavcodec/pixblockdsp_template.c
@@ -1,25 +1,25 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "bit_depth_template.c"
-static void FUNCC(get_pixels)(int16_t *restrict block, const uint8_t *_pixels,
- int line_size)
+static void FUNCC(get_pixels)(int16_t *av_restrict block, const uint8_t *_pixels,
+ ptrdiff_t line_size)
{
const pixel *pixels = (const pixel *) _pixels;
int i;
diff --git a/libavcodec/pixels.h b/libavcodec/pixels.h
index d9d2fde92c..98eacd4df6 100644
--- a/libavcodec/pixels.h
+++ b/libavcodec/pixels.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/png.c b/libavcodec/png.c
index cd75dc1815..ef52b51bd4 100644
--- a/libavcodec/png.c
+++ b/libavcodec/png.c
@@ -2,29 +2,25 @@
* PNG image format
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
-#include "bytestream.h"
#include "png.h"
-const uint8_t ff_pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
-const uint8_t ff_mngsig[8] = { 138, 77, 78, 71, 13, 10, 26, 10 };
-
/* Mask to determine which y pixels are valid in a pass */
const uint8_t ff_png_pass_ymask[NB_PASSES] = {
0x80, 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55,
@@ -40,11 +36,6 @@ static const uint8_t ff_png_pass_xshift[NB_PASSES] = {
3, 3, 2, 2, 1, 1, 0
};
-/* Mask to determine which pixels are valid in a pass */
-const uint8_t ff_png_pass_mask[NB_PASSES] = {
- 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff
-};
-
void *ff_png_zalloc(void *opaque, unsigned int items, unsigned int size)
{
return av_mallocz_array(items, size);
diff --git a/libavcodec/png.h b/libavcodec/png.h
index b8c72eebc9..948c2f714f 100644
--- a/libavcodec/png.h
+++ b/libavcodec/png.h
@@ -2,20 +2,20 @@
* PNG image format
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,15 +49,12 @@
#define NB_PASSES 7
-extern const uint8_t ff_pngsig[8];
-extern const uint8_t ff_mngsig[8];
+#define PNGSIG 0x89504e470d0a1a0a
+#define MNGSIG 0x8a4d4e470d0a1a0a
/* Mask to determine which y pixels are valid in a pass */
extern const uint8_t ff_png_pass_ymask[NB_PASSES];
-/* Mask to determine which pixels are valid in a pass */
-extern const uint8_t ff_png_pass_mask[NB_PASSES];
-
void *ff_png_zalloc(void *opaque, unsigned int items, unsigned int size);
void ff_png_zfree(void *opaque, void *ptr);
diff --git a/libavcodec/png_parser.c b/libavcodec/png_parser.c
index c66caf31a3..74f2964118 100644
--- a/libavcodec/png_parser.c
+++ b/libavcodec/png_parser.c
@@ -2,20 +2,20 @@
* PNG parser
* Copyright (c) 2009 Peter Holik
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,20 +24,14 @@
* PNG parser
*/
-#include "libavutil/intreadwrite.h"
-#include "libavutil/common.h"
-
#include "parser.h"
-
-#define PNG_SIGNATURE UINT64_C(0x89504e470d0a1a0a)
-#define MNG_SIGNATURE UINT64_C(0x8a4d4e470d0a1a0a)
+#include "png.h"
typedef struct PNGParseContext {
ParseContext pc;
-
- int chunk_pos; ///< position inside current chunk
- uint32_t chunk_length; ///< length of the current chunk
- int remaining_size; ///< remaining size of the current chunk
+ uint32_t chunk_pos; ///< position inside current chunk
+ uint32_t chunk_length; ///< length of the current chunk
+ uint32_t remaining_size; ///< remaining size of the current chunk
} PNGParseContext;
static int png_parse(AVCodecParserContext *s, AVCodecContext *avctx,
@@ -48,16 +42,15 @@ static int png_parse(AVCodecParserContext *s, AVCodecContext *avctx,
int next = END_NOT_FOUND;
int i = 0;
+ s->pict_type = AV_PICTURE_TYPE_NONE;
+
*poutbuf_size = 0;
- if (buf_size == 0)
- return 0;
if (!ppc->pc.frame_start_found) {
uint64_t state64 = ppc->pc.state64;
for (; i < buf_size; i++) {
state64 = (state64 << 8) | buf[i];
- if (state64 == PNG_SIGNATURE ||
- state64 == MNG_SIGNATURE) {
+ if (state64 == PNGSIG || state64 == MNGSIG) {
i++;
ppc->pc.frame_start_found = 1;
break;
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 823d77f027..251279968b 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -2,43 +2,51 @@
* PNG image format
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+
+//#define DEBUG
+
+#include "libavutil/bprint.h"
#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
+#include "apng.h"
#include "png.h"
#include "pngdsp.h"
-
-/* TODO:
- * - add 2, 4 and 16 bit depth support
- */
+#include "thread.h"
#include <zlib.h>
typedef struct PNGDecContext {
PNGDSPContext dsp;
+ AVCodecContext *avctx;
GetByteContext gb;
- AVFrame *prev;
+ ThreadFrame previous_picture;
+ ThreadFrame last_picture;
+ ThreadFrame picture;
int state;
int width, height;
+ int cur_w, cur_h;
+ int x_offset, y_offset;
+ uint8_t dispose_op, blend_op;
int bit_depth;
int color_type;
int compression_type;
@@ -48,12 +56,17 @@ typedef struct PNGDecContext {
int bits_per_pixel;
int bpp;
+ int frame_id;
uint8_t *image_buf;
int image_linesize;
uint32_t palette[256];
uint8_t *crow_buf;
uint8_t *last_row;
+ unsigned int last_row_size;
uint8_t *tmp_row;
+ unsigned int tmp_row_size;
+ uint8_t *buffer;
+ int buffer_size;
int pass;
int crow_size; /* compressed row size (include filter type) */
int row_size; /* decompressed row size */
@@ -62,9 +75,14 @@ typedef struct PNGDecContext {
z_stream zstream;
} PNGDecContext;
+/* Mask to determine which pixels are valid in a pass */
+static const uint8_t png_pass_mask[NB_PASSES] = {
+ 0x01, 0x01, 0x11, 0x11, 0x55, 0x55, 0xff,
+};
+
/* Mask to determine which y pixels can be written in a pass */
static const uint8_t png_pass_dsp_ymask[NB_PASSES] = {
- 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55,
+ 0xff, 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55,
};
/* Mask to determine which pixels to overwrite while displaying */
@@ -83,40 +101,55 @@ static void png_put_interlaced_row(uint8_t *dst, int width,
uint8_t *d;
const uint8_t *s;
- mask = ff_png_pass_mask[pass];
+ mask = png_pass_mask[pass];
dsp_mask = png_pass_dsp_mask[pass];
switch (bits_per_pixel) {
case 1:
- /* we must initialize the line to zero before writing to it */
- if (pass == 0)
- memset(dst, 0, (width + 7) >> 3);
src_x = 0;
for (x = 0; x < width; x++) {
j = (x & 7);
if ((dsp_mask << j) & 0x80) {
b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1;
+ dst[x >> 3] &= 0xFF7F>>j;
dst[x >> 3] |= b << (7 - j);
}
if ((mask << j) & 0x80)
src_x++;
}
break;
+ case 2:
+ src_x = 0;
+ for (x = 0; x < width; x++) {
+ int j2 = 2 * (x & 3);
+ j = (x & 7);
+ if ((dsp_mask << j) & 0x80) {
+ b = (src[src_x >> 2] >> (6 - 2*(src_x & 3))) & 3;
+ dst[x >> 2] &= 0xFF3F>>j2;
+ dst[x >> 2] |= b << (6 - j2);
+ }
+ if ((mask << j) & 0x80)
+ src_x++;
+ }
+ break;
+ case 4:
+ src_x = 0;
+ for (x = 0; x < width; x++) {
+ int j2 = 4*(x&1);
+ j = (x & 7);
+ if ((dsp_mask << j) & 0x80) {
+ b = (src[src_x >> 1] >> (4 - 4*(src_x & 1))) & 15;
+ dst[x >> 1] &= 0xFF0F>>j2;
+ dst[x >> 1] |= b << (4 - j2);
+ }
+ if ((mask << j) & 0x80)
+ src_x++;
+ }
+ break;
default:
bpp = bits_per_pixel >> 3;
d = dst;
s = src;
- if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- for (x = 0; x < width; x++) {
- j = x & 7;
- if ((dsp_mask << j) & 0x80) {
- *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2];
- }
- d += bpp;
- if ((mask << j) & 0x80)
- s += bpp;
- }
- } else {
for (x = 0; x < width; x++) {
j = x & 7;
if ((dsp_mask << j) & 0x80) {
@@ -126,7 +159,6 @@ static void png_put_interlaced_row(uint8_t *dst, int width,
if ((mask << j) & 0x80)
s += bpp;
}
- }
break;
}
}
@@ -168,7 +200,7 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
b = dst[2]; \
if (bpp >= 4) \
a = dst[3]; \
- for (; i < size; i += bpp) { \
+ for (; i <= size - bpp; i += bpp) { \
dst[i + 0] = r = op(r, src[i + 0], last[i + 0]); \
if (bpp == 1) \
continue; \
@@ -191,12 +223,9 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
UNROLL1(3, op) \
} else if (bpp == 4) { \
UNROLL1(4, op) \
- } else { \
- for (; i < size; i += bpp) { \
- int j; \
- for (j = 0; j < bpp; j++) \
- dst[i + j] = op(dst[i + j - bpp], src[i + j], last[i + j]); \
- } \
+ } \
+ for (; i < size; i++) { \
+ dst[i] = op(dst[i - bpp], src[i], last[i]); \
}
/* NOTE: 'dst' can be equal to 'last' */
@@ -215,12 +244,12 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
if (bpp == 4) {
p = *(int *)dst;
for (; i < size; i += bpp) {
- int s = *(int *)(src + i);
+ unsigned s = *(int *)(src + i);
p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080);
*(int *)(dst + i) = p;
}
} else {
-#define OP_SUB(x, s, l) x + s
+#define OP_SUB(x, s, l) ((x) + (s))
UNROLL_FILTER(OP_SUB);
}
break;
@@ -232,7 +261,7 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
p = (last[i] >> 1);
dst[i] = p + src[i];
}
-#define OP_AVG(x, s, l) (((x + l) >> 1) + s) & 0xff
+#define OP_AVG(x, s, l) (((((x) + (l)) >> 1) + (s)) & 0xff)
UNROLL_FILTER(OP_AVG);
break;
case PNG_FILTER_VALUE_PAETH:
@@ -243,55 +272,33 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
if (bpp > 2 && size > 4) {
/* would write off the end of the array if we let it process
* the last pixel with bpp=3 */
- int w = bpp == 4 ? size : size - 3;
- dsp->add_paeth_prediction(dst + i, src + i, last + i, w - i, bpp);
- i = w;
+ int w = (bpp & 3) ? size - 3 : size;
+
+ if (w > i) {
+ dsp->add_paeth_prediction(dst + i, src + i, last + i, size - i, bpp);
+ i = w;
+ }
}
ff_add_png_paeth_prediction(dst + i, src + i, last + i, size - i, bpp);
break;
}
}
-static av_always_inline void convert_to_rgb32_loco(uint8_t *dst,
- const uint8_t *src,
- int width, int loco)
-{
- int j;
- unsigned int r, g, b, a;
-
- for (j = 0; j < width; j++) {
- r = src[0];
- g = src[1];
- b = src[2];
- a = src[3];
- if (loco) {
- r = (r + g) & 0xff;
- b = (b + g) & 0xff;
- }
- *(uint32_t *) dst = (a << 24) | (r << 16) | (g << 8) | b;
- dst += 4;
- src += 4;
- }
+/* This used to be called "deloco" in FFmpeg
+ * and is actually an inverse reversible colorspace transformation */
+#define YUV2RGB(NAME, TYPE) \
+static void deloco_ ## NAME(TYPE *dst, int size, int alpha) \
+{ \
+ int i; \
+ for (i = 0; i < size; i += 3 + alpha) { \
+ int g = dst [i + 1]; \
+ dst[i + 0] += g; \
+ dst[i + 2] += g; \
+ } \
}
-static void convert_to_rgb32(uint8_t *dst, const uint8_t *src,
- int width, int loco)
-{
- if (loco)
- convert_to_rgb32_loco(dst, src, width, 1);
- else
- convert_to_rgb32_loco(dst, src, width, 0);
-}
-
-static void deloco_rgb24(uint8_t *dst, int size)
-{
- int i;
- for (i = 0; i < size; i += 3) {
- int g = dst[i + 1];
- dst[i + 0] += g;
- dst[i + 2] += g;
- }
-}
+YUV2RGB(rgb8, uint8_t)
+YUV2RGB(rgb16, uint16_t)
/* process exactly one decompressed row */
static void png_handle_row(PNGDecContext *s)
@@ -300,39 +307,41 @@ static void png_handle_row(PNGDecContext *s)
int got_line;
if (!s->interlace_type) {
- ptr = s->image_buf + s->image_linesize * s->y;
- /* need to swap bytes correctly for RGB_ALPHA */
- if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
- s->last_row, s->row_size, s->bpp);
- convert_to_rgb32(ptr, s->tmp_row, s->width,
- s->filter_type == PNG_FILTER_TYPE_LOCO);
- FFSWAP(uint8_t *, s->last_row, s->tmp_row);
- } else {
- /* in normal case, we avoid one copy */
- if (s->y == 0)
- last_row = s->last_row;
- else
- last_row = ptr - s->image_linesize;
-
- png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1,
- last_row, s->row_size, s->bpp);
- }
+ ptr = s->image_buf + s->image_linesize * (s->y + s->y_offset) + s->x_offset * s->bpp;
+ if (s->y == 0)
+ last_row = s->last_row;
+ else
+ last_row = ptr - s->image_linesize;
+
+ png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1,
+ last_row, s->row_size, s->bpp);
/* loco lags by 1 row so that it doesn't interfere with top prediction */
- if (s->filter_type == PNG_FILTER_TYPE_LOCO &&
- s->color_type == PNG_COLOR_TYPE_RGB && s->y > 0)
- deloco_rgb24(ptr - s->image_linesize, s->row_size);
+ if (s->filter_type == PNG_FILTER_TYPE_LOCO && s->y > 0) {
+ if (s->bit_depth == 16) {
+ deloco_rgb16((uint16_t *)(ptr - s->image_linesize), s->row_size / 2,
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
+ } else {
+ deloco_rgb8(ptr - s->image_linesize, s->row_size,
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
+ }
+ }
s->y++;
- if (s->y == s->height) {
+ if (s->y == s->cur_h) {
s->state |= PNG_ALLIMAGE;
- if (s->filter_type == PNG_FILTER_TYPE_LOCO &&
- s->color_type == PNG_COLOR_TYPE_RGB)
- deloco_rgb24(ptr, s->row_size);
+ if (s->filter_type == PNG_FILTER_TYPE_LOCO) {
+ if (s->bit_depth == 16) {
+ deloco_rgb16((uint16_t *)ptr, s->row_size / 2,
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
+ } else {
+ deloco_rgb8(ptr, s->row_size,
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
+ }
+ }
}
} else {
got_line = 0;
for (;;) {
- ptr = s->image_buf + s->image_linesize * s->y;
+ ptr = s->image_buf + s->image_linesize * (s->y + s->y_offset) + s->x_offset * s->bpp;
if ((ff_png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) {
/* if we already read one row, it is time to stop to
* wait for the next one */
@@ -341,15 +350,16 @@ static void png_handle_row(PNGDecContext *s)
png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
s->last_row, s->pass_row_size, s->bpp);
FFSWAP(uint8_t *, s->last_row, s->tmp_row);
+ FFSWAP(unsigned int, s->last_row_size, s->tmp_row_size);
got_line = 1;
}
if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) {
- /* NOTE: RGB32 is handled directly in png_put_interlaced_row */
- png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass,
+ png_put_interlaced_row(ptr, s->cur_w, s->bits_per_pixel, s->pass,
s->color_type, s->last_row);
}
s->y++;
- if (s->y == s->height) {
+ if (s->y == s->cur_h) {
+ memset(s->last_row, 0, s->row_size);
for (;;) {
if (s->pass == NB_PASSES - 1) {
s->state |= PNG_ALLIMAGE;
@@ -359,7 +369,7 @@ static void png_handle_row(PNGDecContext *s)
s->y = 0;
s->pass_row_size = ff_png_pass_row_size(s->pass,
s->bits_per_pixel,
- s->width);
+ s->cur_w);
s->crow_size = s->pass_row_size + 1;
if (s->pass_row_size != 0)
break;
@@ -376,14 +386,15 @@ static int png_decode_idat(PNGDecContext *s, int length)
{
int ret;
s->zstream.avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb));
- s->zstream.next_in = s->gb.buffer;
+ s->zstream.next_in = (unsigned char *)s->gb.buffer;
bytestream2_skip(&s->gb, length);
/* decode one line if possible */
while (s->zstream.avail_in > 0) {
ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
- return -1;
+ av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret);
+ return AVERROR_EXTERNAL;
}
if (s->zstream.avail_out == 0) {
if (!(s->state & PNG_ALLIMAGE)) {
@@ -401,202 +412,652 @@ static int png_decode_idat(PNGDecContext *s, int length)
return 0;
}
-static int decode_frame(AVCodecContext *avctx,
- void *data, int *got_frame,
- AVPacket *avpkt)
+static int decode_zbuf(AVBPrint *bp, const uint8_t *data,
+ const uint8_t *data_end)
{
- PNGDecContext *const s = avctx->priv_data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
- AVFrame *p = data;
- uint8_t *crow_buf_base = NULL;
- uint32_t tag, length;
+ z_stream zstream;
+ unsigned char *buf;
+ unsigned buf_size;
int ret;
- /* check signature */
- if (buf_size < 8 ||
- (memcmp(buf, ff_pngsig, 8) != 0 && memcmp(buf, ff_mngsig, 8) != 0)) {
- av_log(avctx, AV_LOG_ERROR, "Invalid PNG signature (%d).\n", buf_size);
+ zstream.zalloc = ff_png_zalloc;
+ zstream.zfree = ff_png_zfree;
+ zstream.opaque = NULL;
+ if (inflateInit(&zstream) != Z_OK)
+ return AVERROR_EXTERNAL;
+ zstream.next_in = (unsigned char *)data;
+ zstream.avail_in = data_end - data;
+ av_bprint_init(bp, 0, -1);
+
+ while (zstream.avail_in > 0) {
+ av_bprint_get_buffer(bp, 1, &buf, &buf_size);
+ if (!buf_size) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ zstream.next_out = buf;
+ zstream.avail_out = buf_size;
+ ret = inflate(&zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ bp->len += zstream.next_out - buf;
+ if (ret == Z_STREAM_END)
+ break;
+ }
+ inflateEnd(&zstream);
+ bp->str[bp->len] = 0;
+ return 0;
+
+fail:
+ inflateEnd(&zstream);
+ av_bprint_finalize(bp, NULL);
+ return ret;
+}
+
+static uint8_t *iso88591_to_utf8(const uint8_t *in, size_t size_in)
+{
+ size_t extra = 0, i;
+ uint8_t *out, *q;
+
+ for (i = 0; i < size_in; i++)
+ extra += in[i] >= 0x80;
+ if (size_in == SIZE_MAX || extra > SIZE_MAX - size_in - 1)
+ return NULL;
+ q = out = av_malloc(size_in + extra + 1);
+ if (!out)
+ return NULL;
+ for (i = 0; i < size_in; i++) {
+ if (in[i] >= 0x80) {
+ *(q++) = 0xC0 | (in[i] >> 6);
+ *(q++) = 0x80 | (in[i] & 0x3F);
+ } else {
+ *(q++) = in[i];
+ }
+ }
+ *(q++) = 0;
+ return out;
+}
+
+static int decode_text_chunk(PNGDecContext *s, uint32_t length, int compressed,
+ AVDictionary **dict)
+{
+ int ret, method;
+ const uint8_t *data = s->gb.buffer;
+ const uint8_t *data_end = data + length;
+ const uint8_t *keyword = data;
+ const uint8_t *keyword_end = memchr(keyword, 0, data_end - keyword);
+ uint8_t *kw_utf8 = NULL, *text, *txt_utf8 = NULL;
+ unsigned text_len;
+ AVBPrint bp;
+
+ if (!keyword_end)
return AVERROR_INVALIDDATA;
+ data = keyword_end + 1;
+
+ if (compressed) {
+ if (data == data_end)
+ return AVERROR_INVALIDDATA;
+ method = *(data++);
+ if (method)
+ return AVERROR_INVALIDDATA;
+ if ((ret = decode_zbuf(&bp, data, data_end)) < 0)
+ return ret;
+ text_len = bp.len;
+ av_bprint_finalize(&bp, (char **)&text);
+ if (!text)
+ return AVERROR(ENOMEM);
+ } else {
+ text = (uint8_t *)data;
+ text_len = data_end - text;
}
- bytestream2_init(&s->gb, buf + 8, buf_size - 8);
- s->y = s->state = 0;
+ kw_utf8 = iso88591_to_utf8(keyword, keyword_end - keyword);
+ txt_utf8 = iso88591_to_utf8(text, text_len);
+ if (text != data)
+ av_free(text);
+ if (!(kw_utf8 && txt_utf8)) {
+ av_free(kw_utf8);
+ av_free(txt_utf8);
+ return AVERROR(ENOMEM);
+ }
+
+ av_dict_set(dict, kw_utf8, txt_utf8,
+ AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+ return 0;
+}
+
+static int decode_ihdr_chunk(AVCodecContext *avctx, PNGDecContext *s,
+ uint32_t length)
+{
+ if (length != 13)
+ return AVERROR_INVALIDDATA;
+
+ if (s->state & PNG_IDAT) {
+ av_log(avctx, AV_LOG_ERROR, "IHDR after IDAT\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ s->width = s->cur_w = bytestream2_get_be32(&s->gb);
+ s->height = s->cur_h = bytestream2_get_be32(&s->gb);
+ if (av_image_check_size(s->width, s->height, 0, avctx)) {
+ s->width = s->height = 0;
+ av_log(avctx, AV_LOG_ERROR, "Invalid image size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ s->bit_depth = bytestream2_get_byte(&s->gb);
+ s->color_type = bytestream2_get_byte(&s->gb);
+ s->compression_type = bytestream2_get_byte(&s->gb);
+ s->filter_type = bytestream2_get_byte(&s->gb);
+ s->interlace_type = bytestream2_get_byte(&s->gb);
+ bytestream2_skip(&s->gb, 4); /* crc */
+ s->state |= PNG_IHDR;
+ if (avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(avctx, AV_LOG_DEBUG, "width=%d height=%d depth=%d color_type=%d "
+ "compression_type=%d filter_type=%d interlace_type=%d\n",
+ s->width, s->height, s->bit_depth, s->color_type,
+ s->compression_type, s->filter_type, s->interlace_type);
+
+ return 0;
+}
+
+static int decode_phys_chunk(AVCodecContext *avctx, PNGDecContext *s)
+{
+ if (s->state & PNG_IDAT) {
+ av_log(avctx, AV_LOG_ERROR, "pHYs after IDAT\n");
+ return AVERROR_INVALIDDATA;
+ }
+ avctx->sample_aspect_ratio.num = bytestream2_get_be32(&s->gb);
+ avctx->sample_aspect_ratio.den = bytestream2_get_be32(&s->gb);
+ if (avctx->sample_aspect_ratio.num < 0 || avctx->sample_aspect_ratio.den < 0)
+ avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
+ bytestream2_skip(&s->gb, 1); /* unit specifier */
+ bytestream2_skip(&s->gb, 4); /* crc */
+
+ return 0;
+}
+
+static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s,
+ uint32_t length, AVFrame *p)
+{
+ int ret;
+
+ if (!(s->state & PNG_IHDR)) {
+ av_log(avctx, AV_LOG_ERROR, "IDAT without IHDR\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (!(s->state & PNG_IDAT)) {
+ /* init image info */
+ avctx->width = s->width;
+ avctx->height = s->height;
+
+ s->channels = ff_png_get_nb_channels(s->color_type);
+ s->bits_per_pixel = s->bit_depth * s->channels;
+ s->bpp = (s->bits_per_pixel + 7) >> 3;
+ s->row_size = (s->cur_w * s->bits_per_pixel + 7) >> 3;
+
+ if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) &&
+ s->color_type == PNG_COLOR_TYPE_RGB) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) &&
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+ avctx->pix_fmt = AV_PIX_FMT_RGBA;
+ } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) &&
+ s->color_type == PNG_COLOR_TYPE_GRAY) {
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ } else if (s->bit_depth == 16 &&
+ s->color_type == PNG_COLOR_TYPE_GRAY) {
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
+ } else if (s->bit_depth == 16 &&
+ s->color_type == PNG_COLOR_TYPE_RGB) {
+ avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
+ } else if (s->bit_depth == 16 &&
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+ avctx->pix_fmt = AV_PIX_FMT_RGBA64BE;
+ } else if ((s->bits_per_pixel == 1 || s->bits_per_pixel == 2 || s->bits_per_pixel == 4 || s->bits_per_pixel == 8) &&
+ s->color_type == PNG_COLOR_TYPE_PALETTE) {
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ } else if (s->bit_depth == 1 && s->bits_per_pixel == 1 && avctx->codec_id != AV_CODEC_ID_APNG) {
+ avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
+ } else if (s->bit_depth == 8 &&
+ s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ avctx->pix_fmt = AV_PIX_FMT_YA8;
+ } else if (s->bit_depth == 16 &&
+ s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ avctx->pix_fmt = AV_PIX_FMT_YA16BE;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "unsupported bit depth %d "
+ "and color type %d\n",
+ s->bit_depth, s->color_type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = ff_thread_get_buffer(avctx, &s->picture, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+ ff_thread_finish_setup(avctx);
+
+ p->pict_type = AV_PICTURE_TYPE_I;
+ p->key_frame = 1;
+ p->interlaced_frame = !!s->interlace_type;
+
+ /* compute the compressed row size */
+ if (!s->interlace_type) {
+ s->crow_size = s->row_size + 1;
+ } else {
+ s->pass = 0;
+ s->pass_row_size = ff_png_pass_row_size(s->pass,
+ s->bits_per_pixel,
+ s->cur_w);
+ s->crow_size = s->pass_row_size + 1;
+ }
+ ff_dlog(avctx, "row_size=%d crow_size =%d\n",
+ s->row_size, s->crow_size);
+ s->image_buf = p->data[0];
+ s->image_linesize = p->linesize[0];
+ /* copy the palette if needed */
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
+ memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t));
+ /* empty row is used if differencing to the first row */
+ av_fast_padded_mallocz(&s->last_row, &s->last_row_size, s->row_size);
+ if (!s->last_row)
+ return AVERROR_INVALIDDATA;
+ if (s->interlace_type ||
+ s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+ av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size);
+ if (!s->tmp_row)
+ return AVERROR_INVALIDDATA;
+ }
+ /* compressed row */
+ av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16);
+ if (!s->buffer)
+ return AVERROR(ENOMEM);
+
+ /* we want crow_buf+1 to be 16-byte aligned */
+ s->crow_buf = s->buffer + 15;
+ s->zstream.avail_out = s->crow_size;
+ s->zstream.next_out = s->crow_buf;
+ }
+ s->state |= PNG_IDAT;
+ if ((ret = png_decode_idat(s, length)) < 0)
+ return ret;
+ bytestream2_skip(&s->gb, 4); /* crc */
+
+ return 0;
+}
+
+static int decode_plte_chunk(AVCodecContext *avctx, PNGDecContext *s,
+ uint32_t length)
+{
+ int n, i, r, g, b;
+
+ if ((length % 3) != 0 || length > 256 * 3)
+ return AVERROR_INVALIDDATA;
+ /* read the palette */
+ n = length / 3;
+ for (i = 0; i < n; i++) {
+ r = bytestream2_get_byte(&s->gb);
+ g = bytestream2_get_byte(&s->gb);
+ b = bytestream2_get_byte(&s->gb);
+ s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
+ }
+ for (; i < 256; i++)
+ s->palette[i] = (0xFFU << 24);
+ s->state |= PNG_PLTE;
+ bytestream2_skip(&s->gb, 4); /* crc */
+
+ return 0;
+}
+
+static int decode_trns_chunk(AVCodecContext *avctx, PNGDecContext *s,
+ uint32_t length)
+{
+ int v, i;
+
+ /* read the transparency. XXX: Only palette mode supported */
+ if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
+ length > 256 ||
+ !(s->state & PNG_PLTE))
+ return AVERROR_INVALIDDATA;
+ for (i = 0; i < length; i++) {
+ v = bytestream2_get_byte(&s->gb);
+ s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
+ }
+ bytestream2_skip(&s->gb, 4); /* crc */
+
+ return 0;
+}
+
+static void handle_small_bpp(PNGDecContext *s, AVFrame *p)
+{
+ if (s->bits_per_pixel == 1 && s->color_type == PNG_COLOR_TYPE_PALETTE) {
+ int i, j, k;
+ uint8_t *pd = p->data[0];
+ for (j = 0; j < s->height; j++) {
+ i = s->width / 8;
+ for (k = 7; k >= 1; k--)
+ if ((s->width&7) >= k)
+ pd[8*i + k - 1] = (pd[i]>>8-k) & 1;
+ for (i--; i >= 0; i--) {
+ pd[8*i + 7]= pd[i] & 1;
+ pd[8*i + 6]= (pd[i]>>1) & 1;
+ pd[8*i + 5]= (pd[i]>>2) & 1;
+ pd[8*i + 4]= (pd[i]>>3) & 1;
+ pd[8*i + 3]= (pd[i]>>4) & 1;
+ pd[8*i + 2]= (pd[i]>>5) & 1;
+ pd[8*i + 1]= (pd[i]>>6) & 1;
+ pd[8*i + 0]= pd[i]>>7;
+ }
+ pd += s->image_linesize;
+ }
+ } else if (s->bits_per_pixel == 2) {
+ int i, j;
+ uint8_t *pd = p->data[0];
+ for (j = 0; j < s->height; j++) {
+ i = s->width / 4;
+ if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
+ if ((s->width&3) >= 3) pd[4*i + 2]= (pd[i] >> 2) & 3;
+ if ((s->width&3) >= 2) pd[4*i + 1]= (pd[i] >> 4) & 3;
+ if ((s->width&3) >= 1) pd[4*i + 0]= pd[i] >> 6;
+ for (i--; i >= 0; i--) {
+ pd[4*i + 3]= pd[i] & 3;
+ pd[4*i + 2]= (pd[i]>>2) & 3;
+ pd[4*i + 1]= (pd[i]>>4) & 3;
+ pd[4*i + 0]= pd[i]>>6;
+ }
+ } else {
+ if ((s->width&3) >= 3) pd[4*i + 2]= ((pd[i]>>2) & 3)*0x55;
+ if ((s->width&3) >= 2) pd[4*i + 1]= ((pd[i]>>4) & 3)*0x55;
+ if ((s->width&3) >= 1) pd[4*i + 0]= ( pd[i]>>6 )*0x55;
+ for (i--; i >= 0; i--) {
+ pd[4*i + 3]= ( pd[i] & 3)*0x55;
+ pd[4*i + 2]= ((pd[i]>>2) & 3)*0x55;
+ pd[4*i + 1]= ((pd[i]>>4) & 3)*0x55;
+ pd[4*i + 0]= ( pd[i]>>6 )*0x55;
+ }
+ }
+ pd += s->image_linesize;
+ }
+ } else if (s->bits_per_pixel == 4) {
+ int i, j;
+ uint8_t *pd = p->data[0];
+ for (j = 0; j < s->height; j++) {
+ i = s->width/2;
+ if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
+ if (s->width&1) pd[2*i+0]= pd[i]>>4;
+ for (i--; i >= 0; i--) {
+ pd[2*i + 1] = pd[i] & 15;
+ pd[2*i + 0] = pd[i] >> 4;
+ }
+ } else {
+ if (s->width & 1) pd[2*i + 0]= (pd[i] >> 4) * 0x11;
+ for (i--; i >= 0; i--) {
+ pd[2*i + 1] = (pd[i] & 15) * 0x11;
+ pd[2*i + 0] = (pd[i] >> 4) * 0x11;
+ }
+ }
+ pd += s->image_linesize;
+ }
+ }
+}
+
+static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
+ uint32_t length)
+{
+ uint32_t sequence_number;
+
+ if (length != 26)
+ return AVERROR_INVALIDDATA;
+
+ sequence_number = bytestream2_get_be32(&s->gb);
+ s->cur_w = bytestream2_get_be32(&s->gb);
+ s->cur_h = bytestream2_get_be32(&s->gb);
+ s->x_offset = bytestream2_get_be32(&s->gb);
+ s->y_offset = bytestream2_get_be32(&s->gb);
+ bytestream2_skip(&s->gb, 4); /* delay_num (2), delay_den (2) */
+ s->dispose_op = bytestream2_get_byte(&s->gb);
+ s->blend_op = bytestream2_get_byte(&s->gb);
+ bytestream2_skip(&s->gb, 4); /* crc */
+
+ if (sequence_number == 0 &&
+ (s->cur_w != s->width ||
+ s->cur_h != s->height ||
+ s->x_offset != 0 ||
+ s->y_offset != 0) ||
+ s->cur_w <= 0 || s->cur_h <= 0 ||
+ s->x_offset < 0 || s->y_offset < 0 ||
+ s->cur_w > s->width - s->x_offset|| s->cur_h > s->height - s->y_offset)
+ return AVERROR_INVALIDDATA;
+
+ /* always (re)start with a clean frame */
+ if (sequence_number == 0) {
+ s->dispose_op = APNG_DISPOSE_OP_BACKGROUND;
+ s->frame_id = 0;
+ } else {
+ s->frame_id++;
+ if (s->frame_id == 1 && s->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
+ /* previous for the second frame is the first frame */
+ s->dispose_op = APNG_DISPOSE_OP_NONE;
+ }
+
+ return 0;
+}
+
+static void handle_p_frame_png(PNGDecContext *s, AVFrame *p)
+{
+ int i, j;
+ uint8_t *pd = p->data[0];
+ uint8_t *pd_last = s->last_picture.f->data[0];
+ int ls = FFMIN(av_image_get_linesize(p->format, s->width, 0), s->width * s->bpp);
+
+ ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
+ for (j = 0; j < s->height; j++) {
+ for (i = 0; i < ls; i++)
+ pd[i] += pd_last[i];
+ pd += s->image_linesize;
+ pd_last += s->image_linesize;
+ }
+}
+
+// divide by 255 and round to nearest
+// apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
+#define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
+
+static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
+ AVFrame *p)
+{
+ int i, j;
+ uint8_t *pd = p->data[0];
+ uint8_t *pd_last = s->last_picture.f->data[0];
+ uint8_t *pd_last_region = s->dispose_op == APNG_DISPOSE_OP_PREVIOUS ?
+ s->previous_picture.f->data[0] : s->last_picture.f->data[0];
+ int ls = FFMIN(av_image_get_linesize(p->format, s->width, 0), s->width * s->bpp);
+
+ if (ls < 0)
+ return ls;
+
+ if (s->blend_op == APNG_BLEND_OP_OVER &&
+ avctx->pix_fmt != AV_PIX_FMT_RGBA && avctx->pix_fmt != AV_PIX_FMT_ARGB) {
+ avpriv_request_sample(avctx, "Blending with pixel format %s",
+ av_get_pix_fmt_name(avctx->pix_fmt));
+ return AVERROR_PATCHWELCOME;
+ }
+
+ ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
+ if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS)
+ ff_thread_await_progress(&s->previous_picture, INT_MAX, 0);
+
+ for (j = 0; j < s->y_offset; j++) {
+ memcpy(pd, pd_last, ls);
+ pd += s->image_linesize;
+ pd_last += s->image_linesize;
+ }
+
+ if (s->dispose_op != APNG_DISPOSE_OP_BACKGROUND && s->blend_op == APNG_BLEND_OP_OVER) {
+ uint8_t ri, gi, bi, ai;
+
+ pd_last_region += s->y_offset * s->image_linesize;
+ if (avctx->pix_fmt == AV_PIX_FMT_RGBA) {
+ ri = 0;
+ gi = 1;
+ bi = 2;
+ ai = 3;
+ } else {
+ ri = 3;
+ gi = 2;
+ bi = 1;
+ ai = 0;
+ }
+
+ for (j = s->y_offset; j < s->y_offset + s->cur_h; j++) {
+ i = s->x_offset * s->bpp;
+ if (i)
+ memcpy(pd, pd_last, i);
+ for (; i < (s->x_offset + s->cur_w) * s->bpp; i += s->bpp) {
+ uint8_t alpha = pd[i+ai];
+
+ /* output = alpha * foreground + (1-alpha) * background */
+ switch (alpha) {
+ case 0:
+ pd[i+ri] = pd_last_region[i+ri];
+ pd[i+gi] = pd_last_region[i+gi];
+ pd[i+bi] = pd_last_region[i+bi];
+ pd[i+ai] = 0xff;
+ break;
+ case 255:
+ break;
+ default:
+ pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last_region[i+ri]);
+ pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last_region[i+gi]);
+ pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last_region[i+bi]);
+ pd[i+ai] = 0xff;
+ break;
+ }
+ }
+ if (ls - i)
+ memcpy(pd+i, pd_last+i, ls - i);
+ pd += s->image_linesize;
+ pd_last += s->image_linesize;
+ pd_last_region += s->image_linesize;
+ }
+ } else {
+ for (j = s->y_offset; j < s->y_offset + s->cur_h; j++) {
+ int end_offset = (s->x_offset + s->cur_w) * s->bpp;
+ int end_len = ls - end_offset;
+ if (s->x_offset)
+ memcpy(pd, pd_last, s->x_offset * s->bpp);
+ if (end_len)
+ memcpy(pd+end_offset, pd_last+end_offset, end_len);
+ pd += s->image_linesize;
+ pd_last += s->image_linesize;
+ }
+ }
+
+ for (j = s->y_offset + s->cur_h; j < s->height; j++) {
+ memcpy(pd, pd_last, ls);
+ pd += s->image_linesize;
+ pd_last += s->image_linesize;
+ }
+
+ return 0;
+}
+
+static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
+ AVFrame *p, AVPacket *avpkt)
+{
+ AVDictionary *metadata = NULL;
+ uint32_t tag, length;
+ int decode_next_dat = 0;
+ int ret;
+ AVFrame *ref;
- /* init the zlib */
- s->zstream.zalloc = ff_png_zalloc;
- s->zstream.zfree = ff_png_zfree;
- s->zstream.opaque = NULL;
- ret = inflateInit(&s->zstream);
- if (ret != Z_OK)
- return -1;
for (;;) {
- if (bytestream2_get_bytes_left(&s->gb) <= 0)
+ length = bytestream2_get_bytes_left(&s->gb);
+ if (length <= 0) {
+ if (CONFIG_APNG_DECODER && avctx->codec_id == AV_CODEC_ID_APNG && length == 0) {
+ if (!(s->state & PNG_IDAT))
+ return 0;
+ else
+ goto exit_loop;
+ }
+ av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", length);
+ if ( s->state & PNG_ALLIMAGE
+ && avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)
+ goto exit_loop;
+ ret = AVERROR_INVALIDDATA;
goto fail;
+ }
+
length = bytestream2_get_be32(&s->gb);
- if (length > 0x7fffffff)
+ if (length > 0x7fffffff || length > bytestream2_get_bytes_left(&s->gb)) {
+ av_log(avctx, AV_LOG_ERROR, "chunk too big\n");
+ ret = AVERROR_INVALIDDATA;
goto fail;
+ }
tag = bytestream2_get_le32(&s->gb);
- ff_dlog(avctx, "png: tag=%c%c%c%c length=%u\n",
+ if (avctx->debug & FF_DEBUG_STARTCODE)
+ av_log(avctx, AV_LOG_DEBUG, "png: tag=%c%c%c%c length=%u\n",
(tag & 0xff),
((tag >> 8) & 0xff),
((tag >> 16) & 0xff),
((tag >> 24) & 0xff), length);
switch (tag) {
case MKTAG('I', 'H', 'D', 'R'):
- if (length != 13)
+ if ((ret = decode_ihdr_chunk(avctx, s, length)) < 0)
goto fail;
- s->width = bytestream2_get_be32(&s->gb);
- s->height = bytestream2_get_be32(&s->gb);
- if (av_image_check_size(s->width, s->height, 0, avctx)) {
- s->width = s->height = 0;
+ break;
+ case MKTAG('p', 'H', 'Y', 's'):
+ if ((ret = decode_phys_chunk(avctx, s)) < 0)
goto fail;
- }
- s->bit_depth = bytestream2_get_byte(&s->gb);
- s->color_type = bytestream2_get_byte(&s->gb);
- s->compression_type = bytestream2_get_byte(&s->gb);
- s->filter_type = bytestream2_get_byte(&s->gb);
- s->interlace_type = bytestream2_get_byte(&s->gb);
- bytestream2_skip(&s->gb, 4); /* crc */
- s->state |= PNG_IHDR;
- ff_dlog(avctx, "width=%d height=%d depth=%d color_type=%d "
- "compression_type=%d filter_type=%d interlace_type=%d\n",
- s->width, s->height, s->bit_depth, s->color_type,
- s->compression_type, s->filter_type, s->interlace_type);
break;
- case MKTAG('I', 'D', 'A', 'T'):
- if (!(s->state & PNG_IHDR))
+ case MKTAG('f', 'c', 'T', 'L'):
+ if (!CONFIG_APNG_DECODER || avctx->codec_id != AV_CODEC_ID_APNG)
+ goto skip_tag;
+ if ((ret = decode_fctl_chunk(avctx, s, length)) < 0)
+ goto fail;
+ decode_next_dat = 1;
+ break;
+ case MKTAG('f', 'd', 'A', 'T'):
+ if (!CONFIG_APNG_DECODER || avctx->codec_id != AV_CODEC_ID_APNG)
+ goto skip_tag;
+ if (!decode_next_dat) {
+ ret = AVERROR_INVALIDDATA;
goto fail;
- if (!(s->state & PNG_IDAT)) {
- /* init image info */
- avctx->width = s->width;
- avctx->height = s->height;
-
- s->channels = ff_png_get_nb_channels(s->color_type);
- s->bits_per_pixel = s->bit_depth * s->channels;
- s->bpp = (s->bits_per_pixel + 7) >> 3;
- s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3;
-
- if (s->bit_depth == 8 &&
- s->color_type == PNG_COLOR_TYPE_RGB) {
- avctx->pix_fmt = AV_PIX_FMT_RGB24;
- } else if (s->bit_depth == 8 &&
- s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- avctx->pix_fmt = AV_PIX_FMT_RGB32;
- } else if (s->bit_depth == 8 &&
- s->color_type == PNG_COLOR_TYPE_GRAY) {
- avctx->pix_fmt = AV_PIX_FMT_GRAY8;
- } else if (s->bit_depth == 16 &&
- s->color_type == PNG_COLOR_TYPE_GRAY) {
- avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
- } else if (s->bit_depth == 16 &&
- s->color_type == PNG_COLOR_TYPE_RGB) {
- avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
- } else if (s->bit_depth == 1 &&
- s->color_type == PNG_COLOR_TYPE_GRAY) {
- avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
- } else if (s->bit_depth == 8 &&
- s->color_type == PNG_COLOR_TYPE_PALETTE) {
- avctx->pix_fmt = AV_PIX_FMT_PAL8;
- } else if (s->bit_depth == 8 &&
- s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
- avctx->pix_fmt = AV_PIX_FMT_YA8;
- } else if (s->bit_depth == 16 &&
- s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
- avctx->pix_fmt = AV_PIX_FMT_YA16BE;
- } else {
- goto fail;
- }
-
- if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- goto fail;
- }
- p->pict_type = AV_PICTURE_TYPE_I;
- p->key_frame = 1;
- p->interlaced_frame = !!s->interlace_type;
-
- /* compute the compressed row size */
- if (!s->interlace_type) {
- s->crow_size = s->row_size + 1;
- } else {
- s->pass = 0;
- s->pass_row_size = ff_png_pass_row_size(s->pass,
- s->bits_per_pixel,
- s->width);
- s->crow_size = s->pass_row_size + 1;
- }
- ff_dlog(avctx, "row_size=%d crow_size =%d\n",
- s->row_size, s->crow_size);
- s->image_buf = p->data[0];
- s->image_linesize = p->linesize[0];
- /* copy the palette if needed */
- if (s->color_type == PNG_COLOR_TYPE_PALETTE)
- memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t));
- /* empty row is used if differencing to the first row */
- s->last_row = av_mallocz(s->row_size);
- if (!s->last_row)
- goto fail;
- if (s->interlace_type ||
- s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- s->tmp_row = av_malloc(s->row_size);
- if (!s->tmp_row)
- goto fail;
- }
- /* compressed row */
- crow_buf_base = av_malloc(s->row_size + 16);
- if (!crow_buf_base)
- goto fail;
-
- /* we want crow_buf+1 to be 16-byte aligned */
- s->crow_buf = crow_buf_base + 15;
- s->zstream.avail_out = s->crow_size;
- s->zstream.next_out = s->crow_buf;
}
- s->state |= PNG_IDAT;
- if (png_decode_idat(s, length) < 0)
+ bytestream2_get_be32(&s->gb);
+ length -= 4;
+ /* fallthrough */
+ case MKTAG('I', 'D', 'A', 'T'):
+ if (CONFIG_APNG_DECODER && avctx->codec_id == AV_CODEC_ID_APNG && !decode_next_dat)
+ goto skip_tag;
+ if ((ret = decode_idat_chunk(avctx, s, length, p)) < 0)
goto fail;
- bytestream2_skip(&s->gb, 4); /* crc */
break;
case MKTAG('P', 'L', 'T', 'E'):
- {
- int n, i, r, g, b;
-
- if ((length % 3) != 0 || length > 256 * 3)
+ if (decode_plte_chunk(avctx, s, length) < 0)
goto skip_tag;
- /* read the palette */
- n = length / 3;
- for (i = 0; i < n; i++) {
- r = bytestream2_get_byte(&s->gb);
- g = bytestream2_get_byte(&s->gb);
- b = bytestream2_get_byte(&s->gb);
- s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
- }
- for (; i < 256; i++)
- s->palette[i] = (0xff << 24);
- s->state |= PNG_PLTE;
- bytestream2_skip(&s->gb, 4); /* crc */
- }
- break;
+ break;
case MKTAG('t', 'R', 'N', 'S'):
- {
- int v, i;
-
- /* read the transparency. XXX: Only palette mode supported */
- if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
- length > 256 ||
- !(s->state & PNG_PLTE))
+ if (decode_trns_chunk(avctx, s, length) < 0)
goto skip_tag;
- for (i = 0; i < length; i++) {
- v = bytestream2_get_byte(&s->gb);
- s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
- }
- bytestream2_skip(&s->gb, 4); /* crc */
- }
- break;
+ break;
+ case MKTAG('t', 'E', 'X', 't'):
+ if (decode_text_chunk(s, length, 0, &metadata) < 0)
+ av_log(avctx, AV_LOG_WARNING, "Broken tEXt chunk\n");
+ bytestream2_skip(&s->gb, length + 4);
+ break;
+ case MKTAG('z', 'T', 'X', 't'):
+ if (decode_text_chunk(s, length, 1, &metadata) < 0)
+ av_log(avctx, AV_LOG_WARNING, "Broken zTXt chunk\n");
+ bytestream2_skip(&s->gb, length + 4);
+ break;
case MKTAG('I', 'E', 'N', 'D'):
if (!(s->state & PNG_ALLIMAGE))
+ av_log(avctx, AV_LOG_ERROR, "IEND without all image\n");
+ if (!(s->state & (PNG_ALLIMAGE|PNG_IDAT))) {
+ ret = AVERROR_INVALIDDATA;
goto fail;
+ }
bytestream2_skip(&s->gb, 4); /* crc */
goto exit_loop;
default:
@@ -607,39 +1068,175 @@ skip_tag:
}
}
exit_loop:
+
+ if (s->bits_per_pixel <= 4)
+ handle_small_bpp(s, p);
+
/* handle p-frames only if a predecessor frame is available */
- if (s->prev->data[0]) {
- if (!(avpkt->flags & AV_PKT_FLAG_KEY)) {
- int i, j;
- uint8_t *pd = p->data[0];
- uint8_t *pd_last = s->prev->data[0];
-
- for (j = 0; j < s->height; j++) {
- for (i = 0; i < s->width * s->bpp; i++)
- pd[i] += pd_last[i];
- pd += s->image_linesize;
- pd_last += s->image_linesize;
- }
+ ref = s->dispose_op == APNG_DISPOSE_OP_PREVIOUS ?
+ s->previous_picture.f : s->last_picture.f;
+ if (ref->data[0] && s->last_picture.f->data[0]) {
+ if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")
+ && ref->width == p->width
+ && ref->height== p->height
+ && ref->format== p->format
+ ) {
+ if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG)
+ handle_p_frame_png(s, p);
+ else if (CONFIG_APNG_DECODER &&
+ avctx->codec_id == AV_CODEC_ID_APNG &&
+ (ret = handle_p_frame_apng(avctx, s, p)) < 0)
+ goto fail;
}
}
+ ff_thread_report_progress(&s->picture, INT_MAX, 0);
+
+ av_frame_set_metadata(p, metadata);
+ metadata = NULL;
+ return 0;
+
+fail:
+ av_dict_free(&metadata);
+ ff_thread_report_progress(&s->picture, INT_MAX, 0);
+ return ret;
+}
+
+#if CONFIG_PNG_DECODER
+static int decode_frame_png(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ PNGDecContext *const s = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ AVFrame *p;
+ int64_t sig;
+ int ret;
+
+ ff_thread_release_buffer(avctx, &s->last_picture);
+ FFSWAP(ThreadFrame, s->picture, s->last_picture);
+ p = s->picture.f;
+
+ bytestream2_init(&s->gb, buf, buf_size);
+
+ /* check signature */
+ sig = bytestream2_get_be64(&s->gb);
+ if (sig != PNGSIG &&
+ sig != MNGSIG) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid PNG signature (%d).\n", buf_size);
+ return AVERROR_INVALIDDATA;
+ }
- av_frame_unref(s->prev);
- if ((ret = av_frame_ref(s->prev, p)) < 0)
- goto fail;
+ s->y = s->state = 0;
+
+ /* init the zlib */
+ s->zstream.zalloc = ff_png_zalloc;
+ s->zstream.zfree = ff_png_zfree;
+ s->zstream.opaque = NULL;
+ ret = inflateInit(&s->zstream);
+ if (ret != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
+ return AVERROR_EXTERNAL;
+ }
+
+ if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
+ goto the_end;
+
+ if ((ret = av_frame_ref(data, s->picture.f)) < 0)
+ return ret;
*got_frame = 1;
ret = bytestream2_tell(&s->gb);
the_end:
inflateEnd(&s->zstream);
- av_free(crow_buf_base);
s->crow_buf = NULL;
- av_freep(&s->last_row);
- av_freep(&s->tmp_row);
return ret;
-fail:
- ret = -1;
- goto the_end;
+}
+#endif
+
+#if CONFIG_APNG_DECODER
+static int decode_frame_apng(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ PNGDecContext *const s = avctx->priv_data;
+ int ret;
+ AVFrame *p;
+ ThreadFrame tmp;
+
+ ff_thread_release_buffer(avctx, &s->previous_picture);
+ tmp = s->previous_picture;
+ s->previous_picture = s->last_picture;
+ s->last_picture = s->picture;
+ s->picture = tmp;
+ p = s->picture.f;
+
+ if (!(s->state & PNG_IHDR)) {
+ if (!avctx->extradata_size)
+ return AVERROR_INVALIDDATA;
+
+ /* only init fields, there is no zlib use in extradata */
+ s->zstream.zalloc = ff_png_zalloc;
+ s->zstream.zfree = ff_png_zfree;
+
+ bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size);
+ if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
+ goto end;
+ }
+
+ /* reset state for a new frame */
+ if ((ret = inflateInit(&s->zstream)) != Z_OK) {
+ av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ s->y = 0;
+ s->state &= ~(PNG_IDAT | PNG_ALLIMAGE);
+ bytestream2_init(&s->gb, avpkt->data, avpkt->size);
+ if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
+ goto end;
+
+ if (!(s->state & PNG_ALLIMAGE))
+ av_log(avctx, AV_LOG_WARNING, "Frame did not contain a complete image\n");
+ if (!(s->state & (PNG_ALLIMAGE|PNG_IDAT))) {
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+ if ((ret = av_frame_ref(data, s->picture.f)) < 0)
+ goto end;
+
+ *got_frame = 1;
+ ret = bytestream2_tell(&s->gb);
+
+end:
+ inflateEnd(&s->zstream);
+ return ret;
+}
+#endif
+
+static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
+{
+ PNGDecContext *psrc = src->priv_data;
+ PNGDecContext *pdst = dst->priv_data;
+ int ret;
+
+ if (dst == src)
+ return 0;
+
+ pdst->frame_id = psrc->frame_id;
+
+ ff_thread_release_buffer(dst, &pdst->picture);
+ if (psrc->picture.f->data[0] &&
+ (ret = ff_thread_ref_frame(&pdst->picture, &psrc->picture)) < 0)
+ return ret;
+ if (CONFIG_APNG_DECODER && dst->codec_id == AV_CODEC_ID_APNG) {
+ ff_thread_release_buffer(dst, &pdst->last_picture);
+ if (psrc->last_picture.f->data[0])
+ return ff_thread_ref_frame(&pdst->last_picture, &psrc->last_picture);
+ }
+
+ return 0;
}
static av_cold int png_dec_init(AVCodecContext *avctx)
@@ -648,11 +1245,21 @@ static av_cold int png_dec_init(AVCodecContext *avctx)
avctx->color_range = AVCOL_RANGE_JPEG;
- s->prev = av_frame_alloc();
- if (!s->prev)
+ s->avctx = avctx;
+ s->previous_picture.f = av_frame_alloc();
+ s->last_picture.f = av_frame_alloc();
+ s->picture.f = av_frame_alloc();
+ if (!s->previous_picture.f || !s->last_picture.f || !s->picture.f) {
+ av_frame_free(&s->previous_picture.f);
+ av_frame_free(&s->last_picture.f);
+ av_frame_free(&s->picture.f);
return AVERROR(ENOMEM);
+ }
- ff_pngdsp_init(&s->dsp);
+ if (!avctx->internal->is_copy) {
+ avctx->internal->allocate_progress = 1;
+ ff_pngdsp_init(&s->dsp);
+ }
return 0;
}
@@ -661,11 +1268,39 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
{
PNGDecContext *s = avctx->priv_data;
- av_frame_free(&s->prev);
+ ff_thread_release_buffer(avctx, &s->previous_picture);
+ av_frame_free(&s->previous_picture.f);
+ ff_thread_release_buffer(avctx, &s->last_picture);
+ av_frame_free(&s->last_picture.f);
+ ff_thread_release_buffer(avctx, &s->picture);
+ av_frame_free(&s->picture.f);
+ av_freep(&s->buffer);
+ s->buffer_size = 0;
+ av_freep(&s->last_row);
+ s->last_row_size = 0;
+ av_freep(&s->tmp_row);
+ s->tmp_row_size = 0;
return 0;
}
+#if CONFIG_APNG_DECODER
+AVCodec ff_apng_decoder = {
+ .name = "apng",
+ .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_APNG,
+ .priv_data_size = sizeof(PNGDecContext),
+ .init = png_dec_init,
+ .close = png_dec_end,
+ .decode = decode_frame_apng,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
+ .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+};
+#endif
+
+#if CONFIG_PNG_DECODER
AVCodec ff_png_decoder = {
.name = "png",
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
@@ -674,6 +1309,9 @@ AVCodec ff_png_decoder = {
.priv_data_size = sizeof(PNGDecContext),
.init = png_dec_init,
.close = png_dec_end,
- .decode = decode_frame,
- .capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+ .decode = decode_frame_png,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
+ .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
};
+#endif
diff --git a/libavcodec/pngdsp.c b/libavcodec/pngdsp.c
index c0e9402948..d2753163da 100644
--- a/libavcodec/pngdsp.c
+++ b/libavcodec/pngdsp.c
@@ -2,20 +2,20 @@
* PNG image format
* Copyright (c) 2008 Loren Merrit <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pngdsp.h b/libavcodec/pngdsp.h
index 98d29a8a2f..fbc1a508e7 100644
--- a/libavcodec/pngdsp.h
+++ b/libavcodec/pngdsp.h
@@ -2,20 +2,20 @@
* PNG image format
* Copyright (c) 2008 Loren Merrit <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,9 +25,9 @@
#include <stdint.h>
typedef struct PNGDSPContext {
- void (*add_bytes_l2)(uint8_t *dst /* align 16 */,
+ void (*add_bytes_l2)(uint8_t *dst,
uint8_t *src1 /* align 16 */,
- uint8_t *src2 /* align 16 */, int w);
+ uint8_t *src2, int w);
/* this might write to dst[w] */
void (*add_paeth_prediction)(uint8_t *dst, uint8_t *src,
diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c
index 3d11f370cb..7a9d0b0f79 100644
--- a/libavcodec/pngenc.c
+++ b/libavcodec/pngenc.c
@@ -2,37 +2,42 @@
* PNG image format
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
+#include "internal.h"
#include "bytestream.h"
#include "huffyuvencdsp.h"
#include "png.h"
+#include "apng.h"
-/* TODO:
- * - add 2, 4 and 16 bit depth support
- */
+#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
+#include "libavutil/libm.h"
+#include "libavutil/opt.h"
+#include "libavutil/color_utils.h"
#include <zlib.h>
#define IOBUF_SIZE 4096
typedef struct PNGEncContext {
+ AVClass *class;
HuffYUVEncDSPContext hdsp;
uint8_t *bytestream;
@@ -43,6 +48,17 @@ typedef struct PNGEncContext {
z_stream zstream;
uint8_t buf[IOBUF_SIZE];
+ int dpi; ///< Physical pixel density, in dots per inch, if set
+ int dpm; ///< Physical pixel density, in dots per meter, if set
+
+ int is_progressive;
+ int bit_depth;
+ int color_type;
+ int bits_per_pixel;
+
+ // APNG
+ uint32_t palette_checksum; // Used to ensure a single unique palette
+ uint32_t sequence_number;
} PNGEncContext;
static void png_get_interlaced_row(uint8_t *dst, int row_size,
@@ -52,8 +68,9 @@ static void png_get_interlaced_row(uint8_t *dst, int row_size,
int x, mask, dst_x, j, b, bpp;
uint8_t *d;
const uint8_t *s;
+ static const int masks[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
- mask = ff_png_pass_mask[pass];
+ mask = masks[pass];
switch (bits_per_pixel) {
case 1:
memset(dst, 0, row_size);
@@ -111,6 +128,22 @@ static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
}
}
+static void sub_left_prediction(PNGEncContext *c, uint8_t *dst, const uint8_t *src, int bpp, int size)
+{
+ const uint8_t *src1 = src + bpp;
+ const uint8_t *src2 = src;
+ int x, unaligned_w;
+
+ memcpy(dst, src, bpp);
+ dst += bpp;
+ size -= bpp;
+ unaligned_w = FFMIN(32 - bpp, size);
+ for (x = 0; x < unaligned_w; x++)
+ *dst++ = *src1++ - *src2++;
+ size -= unaligned_w;
+ c->hdsp.diff_bytes(dst, src1, src2, size);
+}
+
static void png_filter_row(PNGEncContext *c, uint8_t *dst, int filter_type,
uint8_t *src, uint8_t *top, int size, int bpp)
{
@@ -121,8 +154,7 @@ static void png_filter_row(PNGEncContext *c, uint8_t *dst, int filter_type,
memcpy(dst, src, size);
break;
case PNG_FILTER_VALUE_SUB:
- c->hdsp.diff_bytes(dst, src, src - bpp, size);
- memcpy(dst, src, bpp);
+ sub_left_prediction(c, dst, src, bpp, size);
break;
case PNG_FILTER_VALUE_UP:
c->hdsp.diff_bytes(dst, src, top, size);
@@ -145,7 +177,7 @@ static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst,
uint8_t *src, uint8_t *top, int size, int bpp)
{
int pred = s->filter_type;
- assert(bpp || !pred);
+ av_assert0(bpp || !pred);
if (!top && pred)
pred = PNG_FILTER_VALUE_SUB;
if (pred == PNG_FILTER_VALUE_MIXED) {
@@ -171,45 +203,56 @@ static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst,
}
}
-static void convert_from_rgb32(uint8_t *dst, const uint8_t *src, int width)
-{
- uint8_t *d;
- int j;
- unsigned int v;
-
- d = dst;
- for (j = 0; j < width; j++) {
- v = ((const uint32_t *) src)[j];
- d[0] = v >> 16;
- d[1] = v >> 8;
- d[2] = v;
- d[3] = v >> 24;
- d += 4;
- }
-}
-
static void png_write_chunk(uint8_t **f, uint32_t tag,
const uint8_t *buf, int length)
{
- uint32_t crc;
+ const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
+ uint32_t crc = ~0U;
uint8_t tagbuf[4];
bytestream_put_be32(f, length);
- crc = crc32(0, Z_NULL, 0);
AV_WL32(tagbuf, tag);
- crc = crc32(crc, tagbuf, 4);
+ crc = av_crc(crc_table, crc, tagbuf, 4);
bytestream_put_be32(f, av_bswap32(tag));
if (length > 0) {
- crc = crc32(crc, buf, length);
+ crc = av_crc(crc_table, crc, buf, length);
memcpy(*f, buf, length);
*f += length;
}
- bytestream_put_be32(f, crc);
+ bytestream_put_be32(f, ~crc);
+}
+
+static void png_write_image_data(AVCodecContext *avctx,
+ const uint8_t *buf, int length)
+{
+ PNGEncContext *s = avctx->priv_data;
+ const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
+ uint32_t crc = ~0U;
+
+ if (avctx->codec_id == AV_CODEC_ID_PNG || avctx->frame_number == 0) {
+ png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), buf, length);
+ return;
+ }
+
+ bytestream_put_be32(&s->bytestream, length + 4);
+
+ bytestream_put_be32(&s->bytestream, MKBETAG('f', 'd', 'A', 'T'));
+ bytestream_put_be32(&s->bytestream, s->sequence_number);
+ crc = av_crc(crc_table, crc, s->bytestream - 8, 8);
+
+ crc = av_crc(crc_table, crc, buf, length);
+ memcpy(s->bytestream, buf, length);
+ s->bytestream += length;
+
+ bytestream_put_be32(&s->bytestream, ~crc);
+
+ ++s->sequence_number;
}
/* XXX: do filtering */
-static int png_write_row(PNGEncContext *s, const uint8_t *data, int size)
+static int png_write_row(AVCodecContext *avctx, const uint8_t *data, int size)
{
+ PNGEncContext *s = avctx->priv_data;
int ret;
s->zstream.avail_in = size;
@@ -220,8 +263,7 @@ static int png_write_row(PNGEncContext *s, const uint8_t *data, int size)
return -1;
if (s->zstream.avail_out == 0) {
if (s->bytestream_end - s->bytestream > IOBUF_SIZE + 100)
- png_write_chunk(&s->bytestream,
- MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE);
+ png_write_image_data(avctx, s->buf, IOBUF_SIZE);
s->zstream.avail_out = IOBUF_SIZE;
s->zstream.next_out = s->buf;
}
@@ -229,136 +271,112 @@ static int png_write_row(PNGEncContext *s, const uint8_t *data, int size)
return 0;
}
-static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+#define AV_WB32_PNG(buf, n) AV_WB32(buf, lrint((n) * 100000))
+static int png_get_chrm(enum AVColorPrimaries prim, uint8_t *buf)
{
- PNGEncContext *s = avctx->priv_data;
- const AVFrame *const p = pict;
- int bit_depth, color_type, y, len, row_size, ret, is_progressive;
- int bits_per_pixel, pass_row_size, enc_row_size, max_packet_size;
- int compression_level;
- uint8_t *ptr, *top, *crow_buf, *crow;
- uint8_t *crow_base = NULL;
- uint8_t *progressive_buf = NULL;
- uint8_t *rgba_buf = NULL;
- uint8_t *top_buf = NULL;
-
- is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
- switch (avctx->pix_fmt) {
- case AV_PIX_FMT_RGBA64BE:
- bit_depth = 16;
- color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- case AV_PIX_FMT_RGB48BE:
- bit_depth = 16;
- color_type = PNG_COLOR_TYPE_RGB;
- break;
- case AV_PIX_FMT_RGB32:
- bit_depth = 8;
- color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- break;
- case AV_PIX_FMT_RGB24:
- bit_depth = 8;
- color_type = PNG_COLOR_TYPE_RGB;
- break;
- case AV_PIX_FMT_GRAY16BE:
- bit_depth = 16;
- color_type = PNG_COLOR_TYPE_GRAY;
- break;
- case AV_PIX_FMT_GRAY8:
- bit_depth = 8;
- color_type = PNG_COLOR_TYPE_GRAY;
- break;
- case AV_PIX_FMT_MONOBLACK:
- bit_depth = 1;
- color_type = PNG_COLOR_TYPE_GRAY;
- break;
- case AV_PIX_FMT_PAL8:
- bit_depth = 8;
- color_type = PNG_COLOR_TYPE_PALETTE;
- break;
- default:
- return -1;
+ double rx, ry, gx, gy, bx, by, wx = 0.3127, wy = 0.3290;
+ switch (prim) {
+ case AVCOL_PRI_BT709:
+ rx = 0.640; ry = 0.330;
+ gx = 0.300; gy = 0.600;
+ bx = 0.150; by = 0.060;
+ break;
+ case AVCOL_PRI_BT470M:
+ rx = 0.670; ry = 0.330;
+ gx = 0.210; gy = 0.710;
+ bx = 0.140; by = 0.080;
+ wx = 0.310; wy = 0.316;
+ break;
+ case AVCOL_PRI_BT470BG:
+ rx = 0.640; ry = 0.330;
+ gx = 0.290; gy = 0.600;
+ bx = 0.150; by = 0.060;
+ break;
+ case AVCOL_PRI_SMPTE170M:
+ case AVCOL_PRI_SMPTE240M:
+ rx = 0.630; ry = 0.340;
+ gx = 0.310; gy = 0.595;
+ bx = 0.155; by = 0.070;
+ break;
+ case AVCOL_PRI_BT2020:
+ rx = 0.708; ry = 0.292;
+ gx = 0.170; gy = 0.797;
+ bx = 0.131; by = 0.046;
+ break;
+ default:
+ return 0;
}
- bits_per_pixel = ff_png_get_nb_channels(color_type) * bit_depth;
- row_size = (avctx->width * bits_per_pixel + 7) >> 3;
- s->zstream.zalloc = ff_png_zalloc;
- s->zstream.zfree = ff_png_zfree;
- s->zstream.opaque = NULL;
- compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT
- ? Z_DEFAULT_COMPRESSION
- : av_clip(avctx->compression_level, 0, 9);
- ret = deflateInit2(&s->zstream, compression_level,
- Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY);
- if (ret != Z_OK)
- return -1;
+ AV_WB32_PNG(buf , wx); AV_WB32_PNG(buf + 4 , wy);
+ AV_WB32_PNG(buf + 8 , rx); AV_WB32_PNG(buf + 12, ry);
+ AV_WB32_PNG(buf + 16, gx); AV_WB32_PNG(buf + 20, gy);
+ AV_WB32_PNG(buf + 24, bx); AV_WB32_PNG(buf + 28, by);
+ return 1;
+}
- enc_row_size = deflateBound(&s->zstream, row_size);
- max_packet_size = avctx->height * (enc_row_size +
- ((enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) * 12)
- + FF_MIN_BUFFER_SIZE;
- if (!pkt->data &&
- (ret = av_new_packet(pkt, max_packet_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate output packet of size %d.\n",
- max_packet_size);
- return ret;
- }
+static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf)
+{
+ double gamma = avpriv_get_gamma_from_trc(trc);
+ if (gamma <= 1e-6)
+ return 0;
- s->bytestream_start =
- s->bytestream = pkt->data;
- s->bytestream_end = pkt->data + pkt->size;
+ AV_WB32_PNG(buf, 1.0 / gamma);
+ return 1;
+}
- crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED));
- if (!crow_base)
- goto fail;
- // pixel data should be aligned, but there's a control byte before it
- crow_buf = crow_base + 15;
- if (is_progressive) {
- progressive_buf = av_malloc(row_size + 1);
- if (!progressive_buf)
- goto fail;
- }
- if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- rgba_buf = av_malloc(row_size + 1);
- if (!rgba_buf)
- goto fail;
- }
- if (is_progressive || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- top_buf = av_malloc(row_size + 1);
- if (!top_buf)
- goto fail;
- }
+static int encode_headers(AVCodecContext *avctx, const AVFrame *pict)
+{
+ PNGEncContext *s = avctx->priv_data;
/* write png header */
- memcpy(s->bytestream, ff_pngsig, 8);
- s->bytestream += 8;
-
AV_WB32(s->buf, avctx->width);
AV_WB32(s->buf + 4, avctx->height);
- s->buf[8] = bit_depth;
- s->buf[9] = color_type;
+ s->buf[8] = s->bit_depth;
+ s->buf[9] = s->color_type;
s->buf[10] = 0; /* compression type */
s->buf[11] = 0; /* filter type */
- s->buf[12] = is_progressive; /* interlace type */
-
+ s->buf[12] = s->is_progressive; /* interlace type */
png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
+ /* write physical information */
+ if (s->dpm) {
+ AV_WB32(s->buf, s->dpm);
+ AV_WB32(s->buf + 4, s->dpm);
+ s->buf[8] = 1; /* unit specifier is meter */
+ } else {
+ AV_WB32(s->buf, avctx->sample_aspect_ratio.num);
+ AV_WB32(s->buf + 4, avctx->sample_aspect_ratio.den);
+ s->buf[8] = 0; /* unit specifier is unknown */
+ }
+ png_write_chunk(&s->bytestream, MKTAG('p', 'H', 'Y', 's'), s->buf, 9);
+
+ /* write colorspace information */
+ if (pict->color_primaries == AVCOL_PRI_BT709 &&
+ pict->color_trc == AVCOL_TRC_IEC61966_2_1) {
+ s->buf[0] = 1; /* rendering intent, relative colorimetric by default */
+ png_write_chunk(&s->bytestream, MKTAG('s', 'R', 'G', 'B'), s->buf, 1);
+ }
+
+ if (png_get_chrm(pict->color_primaries, s->buf))
+ png_write_chunk(&s->bytestream, MKTAG('c', 'H', 'R', 'M'), s->buf, 32);
+ if (png_get_gama(pict->color_trc, s->buf))
+ png_write_chunk(&s->bytestream, MKTAG('g', 'A', 'M', 'A'), s->buf, 4);
+
/* put the palette if needed */
- if (color_type == PNG_COLOR_TYPE_PALETTE) {
+ if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
int has_alpha, alpha, i;
unsigned int v;
uint32_t *palette;
- uint8_t *alpha_ptr;
+ uint8_t *ptr, *alpha_ptr;
- palette = (uint32_t *)p->data[1];
+ palette = (uint32_t *)pict->data[1];
ptr = s->buf;
alpha_ptr = s->buf + 256 * 3;
has_alpha = 0;
for (i = 0; i < 256; i++) {
v = palette[i];
alpha = v >> 24;
- if (alpha && alpha != 0xff)
+ if (alpha != 0xff)
has_alpha = 1;
*alpha_ptr++ = alpha;
bytestream_put_be24(&ptr, v);
@@ -371,32 +389,60 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
}
- /* now put each row */
+ return 0;
+}
+
+static int encode_frame(AVCodecContext *avctx, const AVFrame *pict)
+{
+ PNGEncContext *s = avctx->priv_data;
+ const AVFrame *const p = pict;
+ int y, len, ret;
+ int row_size, pass_row_size;
+ uint8_t *ptr, *top, *crow_buf, *crow;
+ uint8_t *crow_base = NULL;
+ uint8_t *progressive_buf = NULL;
+ uint8_t *top_buf = NULL;
+
+ row_size = (avctx->width * s->bits_per_pixel + 7) >> 3;
+
+ crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED));
+ if (!crow_base) {
+ ret = AVERROR(ENOMEM);
+ goto the_end;
+ }
+ // pixel data should be aligned, but there's a control byte before it
+ crow_buf = crow_base + 15;
+ if (s->is_progressive) {
+ progressive_buf = av_malloc(row_size + 1);
+ top_buf = av_malloc(row_size + 1);
+ if (!progressive_buf || !top_buf) {
+ ret = AVERROR(ENOMEM);
+ goto the_end;
+ }
+ }
+
+ /* put each row */
s->zstream.avail_out = IOBUF_SIZE;
s->zstream.next_out = s->buf;
- if (is_progressive) {
+ if (s->is_progressive) {
int pass;
for (pass = 0; pass < NB_PASSES; pass++) {
/* NOTE: a pass is completely omitted if no pixels would be
* output */
- pass_row_size = ff_png_pass_row_size(pass, bits_per_pixel, avctx->width);
+ pass_row_size = ff_png_pass_row_size(pass, s->bits_per_pixel, avctx->width);
if (pass_row_size > 0) {
top = NULL;
for (y = 0; y < avctx->height; y++)
if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) {
ptr = p->data[0] + y * p->linesize[0];
FFSWAP(uint8_t *, progressive_buf, top_buf);
- if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- convert_from_rgb32(rgba_buf, ptr, avctx->width);
- ptr = rgba_buf;
- }
png_get_interlaced_row(progressive_buf, pass_row_size,
- bits_per_pixel, pass,
+ s->bits_per_pixel, pass,
ptr, avctx->width);
crow = png_choose_filter(s, crow_buf, progressive_buf,
- top, pass_row_size, bits_per_pixel >> 3);
- png_write_row(s, crow, pass_row_size + 1);
+ top, pass_row_size, s->bits_per_pixel >> 3);
+ png_write_row(avctx, crow, pass_row_size + 1);
top = progressive_buf;
}
}
@@ -405,14 +451,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
top = NULL;
for (y = 0; y < avctx->height; y++) {
ptr = p->data[0] + y * p->linesize[0];
- if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- FFSWAP(uint8_t *, rgba_buf, top_buf);
- convert_from_rgb32(rgba_buf, ptr, avctx->width);
- ptr = rgba_buf;
- }
crow = png_choose_filter(s, crow_buf, ptr, top,
- row_size, bits_per_pixel >> 3);
- png_write_row(s, crow, row_size + 1);
+ row_size, s->bits_per_pixel >> 3);
+ png_write_row(avctx, crow, row_size + 1);
top = ptr;
}
}
@@ -422,38 +463,169 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (ret == Z_OK || ret == Z_STREAM_END) {
len = IOBUF_SIZE - s->zstream.avail_out;
if (len > 0 && s->bytestream_end - s->bytestream > len + 100) {
- png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), s->buf, len);
+ png_write_image_data(avctx, s->buf, len);
}
s->zstream.avail_out = IOBUF_SIZE;
s->zstream.next_out = s->buf;
if (ret == Z_STREAM_END)
break;
} else {
- goto fail;
+ ret = -1;
+ goto the_end;
}
}
+
+ ret = 0;
+
+the_end:
+ av_freep(&crow_base);
+ av_freep(&progressive_buf);
+ av_freep(&top_buf);
+ deflateReset(&s->zstream);
+ return ret;
+}
+
+static int encode_png(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ PNGEncContext *s = avctx->priv_data;
+ int ret;
+ int enc_row_size;
+ size_t max_packet_size;
+
+ enc_row_size = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
+ max_packet_size =
+ FF_MIN_BUFFER_SIZE + // headers
+ avctx->height * (
+ enc_row_size +
+ 12 * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // IDAT * ceil(enc_row_size / IOBUF_SIZE)
+ );
+ if (max_packet_size > INT_MAX)
+ return AVERROR(ENOMEM);
+ ret = ff_alloc_packet2(avctx, pkt, max_packet_size);
+ if (ret < 0)
+ return ret;
+
+ s->bytestream_start =
+ s->bytestream = pkt->data;
+ s->bytestream_end = pkt->data + pkt->size;
+
+ AV_WB64(s->bytestream, PNGSIG);
+ s->bytestream += 8;
+
+ ret = encode_headers(avctx, pict);
+ if (ret < 0)
+ return ret;
+
+ ret = encode_frame(avctx, pict);
+ if (ret < 0)
+ return ret;
+
png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
- pkt->size = s->bytestream - s->bytestream_start;
+ pkt->size = s->bytestream - s->bytestream_start;
pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = 1;
- ret = 0;
-the_end:
- av_free(crow_base);
- av_free(progressive_buf);
- av_free(rgba_buf);
- av_free(top_buf);
- deflateEnd(&s->zstream);
- return ret;
-fail:
- ret = -1;
- goto the_end;
+ return 0;
+}
+
+static int encode_apng(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ PNGEncContext *s = avctx->priv_data;
+ int ret;
+ int enc_row_size;
+ size_t max_packet_size;
+ uint8_t buf[26];
+
+ if (avctx->codec_id == AV_CODEC_ID_APNG && s->color_type == PNG_COLOR_TYPE_PALETTE) {
+ uint32_t checksum = ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, pict->data[1], 256 * sizeof(uint32_t));
+
+ if (avctx->frame_number == 0) {
+ s->palette_checksum = checksum;
+ } else if (checksum != s->palette_checksum) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Input contains more than one unique palette. APNG does not support multiple palettes.\n");
+ return -1;
+ }
+ }
+
+ enc_row_size = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
+ max_packet_size =
+ FF_MIN_BUFFER_SIZE + // headers
+ avctx->height * (
+ enc_row_size +
+ (4 + 12) * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // fdAT * ceil(enc_row_size / IOBUF_SIZE)
+ );
+ if (max_packet_size > INT_MAX)
+ return AVERROR(ENOMEM);
+ ret = ff_alloc_packet2(avctx, pkt, max_packet_size);
+ if (ret < 0)
+ return ret;
+
+ s->bytestream_start =
+ s->bytestream = pkt->data;
+ s->bytestream_end = pkt->data + pkt->size;
+
+ if (avctx->frame_number == 0) {
+ ret = encode_headers(avctx, pict);
+ if (ret < 0)
+ return ret;
+
+ avctx->extradata = av_malloc(s->bytestream - s->bytestream_start);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
+ avctx->extradata_size = s->bytestream - s->bytestream_start;
+ memcpy(avctx->extradata, s->bytestream_start, s->bytestream - s->bytestream_start);
+
+ s->bytestream = s->bytestream_start;
+ }
+
+ AV_WB32(buf, s->sequence_number);
+ AV_WB32(buf + 4, avctx->width);
+ AV_WB32(buf + 8, avctx->height);
+ AV_WB32(buf + 12, 0); // x offset
+ AV_WB32(buf + 16, 0); // y offset
+ AV_WB16(buf + 20, 0); // delay numerator (filled in during muxing)
+ AV_WB16(buf + 22, 0); // delay denominator
+ buf[24] = APNG_DISPOSE_OP_BACKGROUND;
+ buf[25] = APNG_BLEND_OP_SOURCE;
+ png_write_chunk(&s->bytestream, MKTAG('f', 'c', 'T', 'L'), buf, 26);
+ ++s->sequence_number;
+
+ ret = encode_frame(avctx, pict);
+ if (ret < 0)
+ return ret;
+
+ pkt->size = s->bytestream - s->bytestream_start;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
}
static av_cold int png_enc_init(AVCodecContext *avctx)
{
PNGEncContext *s = avctx->priv_data;
+ int compression_level;
+
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_RGBA:
+ avctx->bits_per_coded_sample = 32;
+ break;
+ case AV_PIX_FMT_RGB24:
+ avctx->bits_per_coded_sample = 24;
+ break;
+ case AV_PIX_FMT_GRAY8:
+ avctx->bits_per_coded_sample = 0x28;
+ break;
+ case AV_PIX_FMT_MONOBLACK:
+ avctx->bits_per_coded_sample = 1;
+ break;
+ case AV_PIX_FMT_PAL8:
+ avctx->bits_per_coded_sample = 8;
+ }
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame)
@@ -470,15 +642,103 @@ static av_cold int png_enc_init(AVCodecContext *avctx)
if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK)
s->filter_type = PNG_FILTER_VALUE_NONE;
+ if (s->dpi && s->dpm) {
+ av_log(avctx, AV_LOG_ERROR, "Only one of 'dpi' or 'dpm' options should be set\n");
+ return AVERROR(EINVAL);
+ } else if (s->dpi) {
+ s->dpm = s->dpi * 10000 / 254;
+ }
+
+ s->is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
+ switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_RGBA64BE:
+ s->bit_depth = 16;
+ s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case AV_PIX_FMT_RGB48BE:
+ s->bit_depth = 16;
+ s->color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case AV_PIX_FMT_RGBA:
+ s->bit_depth = 8;
+ s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ break;
+ case AV_PIX_FMT_RGB24:
+ s->bit_depth = 8;
+ s->color_type = PNG_COLOR_TYPE_RGB;
+ break;
+ case AV_PIX_FMT_GRAY16BE:
+ s->bit_depth = 16;
+ s->color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ case AV_PIX_FMT_GRAY8:
+ s->bit_depth = 8;
+ s->color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ case AV_PIX_FMT_GRAY8A:
+ s->bit_depth = 8;
+ s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ break;
+ case AV_PIX_FMT_YA16BE:
+ s->bit_depth = 16;
+ s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ break;
+ case AV_PIX_FMT_MONOBLACK:
+ s->bit_depth = 1;
+ s->color_type = PNG_COLOR_TYPE_GRAY;
+ break;
+ case AV_PIX_FMT_PAL8:
+ s->bit_depth = 8;
+ s->color_type = PNG_COLOR_TYPE_PALETTE;
+ break;
+ default:
+ return -1;
+ }
+ s->bits_per_pixel = ff_png_get_nb_channels(s->color_type) * s->bit_depth;
+
+ s->zstream.zalloc = ff_png_zalloc;
+ s->zstream.zfree = ff_png_zfree;
+ s->zstream.opaque = NULL;
+ compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT
+ ? Z_DEFAULT_COMPRESSION
+ : av_clip(avctx->compression_level, 0, 9);
+ if (deflateInit2(&s->zstream, compression_level, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
+ return -1;
+
return 0;
}
static av_cold int png_enc_close(AVCodecContext *avctx)
{
+ PNGEncContext *s = avctx->priv_data;
+
+ deflateEnd(&s->zstream);
av_frame_free(&avctx->coded_frame);
return 0;
}
+#define OFFSET(x) offsetof(PNGEncContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ {"dpi", "Set image resolution (in dots per inch)", OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE},
+ {"dpm", "Set image resolution (in dots per meter)", OFFSET(dpm), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE},
+ { NULL }
+};
+
+static const AVClass pngenc_class = {
+ .class_name = "PNG encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVClass apngenc_class = {
+ .class_name = "APNG encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_png_encoder = {
.name = "png",
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
@@ -487,10 +747,35 @@ AVCodec ff_png_encoder = {
.priv_data_size = sizeof(PNGEncContext),
.init = png_enc_init,
.close = png_enc_close,
- .encode2 = encode_frame,
+ .encode2 = encode_png,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
+ AV_PIX_FMT_PAL8,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
+ AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
+ AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
+ },
+ .priv_class = &pngenc_class,
+};
+
+AVCodec ff_apng_encoder = {
+ .name = "apng",
+ .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_APNG,
+ .priv_data_size = sizeof(PNGEncContext),
+ .init = png_enc_init,
+ .close = png_enc_close,
+ .encode2 = encode_apng,
.pix_fmts = (const enum AVPixelFormat[]) {
- AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB32, AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8,
- AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_RGB48BE, AV_PIX_FMT_GRAY16BE,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
+ AV_PIX_FMT_PAL8,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
+ AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
},
+ .priv_class = &apngenc_class,
};
diff --git a/libavcodec/pnm.c b/libavcodec/pnm.c
index 1c380b0ff8..1675959fbf 100644
--- a/libavcodec/pnm.c
+++ b/libavcodec/pnm.c
@@ -2,20 +2,20 @@
* PNM image format
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,12 +37,12 @@ static void pnm_get(PNMContext *sc, char *str, int buf_size)
int c;
/* skip spaces and comments */
- for (;;) {
+ while (sc->bytestream < sc->bytestream_end) {
c = *sc->bytestream++;
if (c == '#') {
- do {
+ while (c != '\n' && sc->bytestream < sc->bytestream_end) {
c = *sc->bytestream++;
- } while (c != '\n' && sc->bytestream < sc->bytestream_end);
+ }
} else if (!pnm_space(c)) {
break;
}
@@ -63,9 +63,9 @@ int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s)
int h, w, depth, maxval;
pnm_get(s, buf1, sizeof(buf1));
- s->type= buf1[1]-'0';
if(buf1[0] != 'P')
return AVERROR_INVALIDDATA;
+ s->type= buf1[1]-'0';
if (s->type==1 || s->type==4) {
avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
@@ -107,26 +107,38 @@ int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s)
}
}
/* check that all tags are present */
- if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || av_image_check_size(w, h, 0, avctx))
+ if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || av_image_check_size(w, h, 0, avctx) || s->bytestream >= s->bytestream_end)
return AVERROR_INVALIDDATA;
avctx->width = w;
avctx->height = h;
+ s->maxval = maxval;
if (depth == 1) {
- if (maxval == 1)
- avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
- else
+ if (maxval == 1) {
+ avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
+ } else if (maxval < 256) {
avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16;
+ }
+ } else if (depth == 2) {
+ if (maxval < 256) {
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_YA16;
+ }
} else if (depth == 3) {
if (maxval < 256) {
- avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
} else {
- av_log(avctx, AV_LOG_ERROR, "16-bit components are only supported for grayscale\n");
- avctx->pix_fmt = AV_PIX_FMT_NONE;
- return AVERROR_INVALIDDATA;
+ avctx->pix_fmt = AV_PIX_FMT_RGB48;
}
} else if (depth == 4) {
- avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ if (maxval < 256) {
+ avctx->pix_fmt = AV_PIX_FMT_RGBA;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_RGBA64;
+ }
} else {
return AVERROR_INVALIDDATA;
}
@@ -135,14 +147,16 @@ int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s)
return AVERROR_INVALIDDATA;
}
pnm_get(s, buf1, sizeof(buf1));
- avctx->width = atoi(buf1);
- if (avctx->width <= 0)
- return AVERROR_INVALIDDATA;
+ w = atoi(buf1);
pnm_get(s, buf1, sizeof(buf1));
- avctx->height = atoi(buf1);
- if(av_image_check_size(avctx->width, avctx->height, 0, avctx))
+ h = atoi(buf1);
+ if(w <= 0 || h <= 0 || av_image_check_size(w, h, 0, avctx) || s->bytestream >= s->bytestream_end)
return AVERROR_INVALIDDATA;
- if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE) {
+
+ avctx->width = w;
+ avctx->height = h;
+
+ if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE && avctx->pix_fmt != AV_PIX_FMT_MONOBLACK) {
pnm_get(s, buf1, sizeof(buf1));
s->maxval = atoi(buf1);
if (s->maxval <= 0) {
@@ -151,17 +165,14 @@ int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s)
}
if (s->maxval >= 256) {
if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
- avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
- if (s->maxval != 65535)
- avctx->pix_fmt = AV_PIX_FMT_GRAY16;
+ avctx->pix_fmt = AV_PIX_FMT_GRAY16;
} else if (avctx->pix_fmt == AV_PIX_FMT_RGB24) {
- if (s->maxval > 255)
- avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
+ avctx->pix_fmt = AV_PIX_FMT_RGB48;
} else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P && s->maxval < 65536) {
if (s->maxval < 512)
- avctx->pix_fmt = AV_PIX_FMT_YUV420P9BE;
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P9;
else if (s->maxval < 1024)
- avctx->pix_fmt = AV_PIX_FMT_YUV420P10BE;
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
else
avctx->pix_fmt = AV_PIX_FMT_YUV420P16;
} else {
diff --git a/libavcodec/pnm.h b/libavcodec/pnm.h
index 5fc6513ed7..5bc0aad29f 100644
--- a/libavcodec/pnm.h
+++ b/libavcodec/pnm.h
@@ -2,20 +2,20 @@
* PNM image format
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pnm_parser.c b/libavcodec/pnm_parser.c
index 2e00c0a31e..2a9e3e1cba 100644
--- a/libavcodec/pnm_parser.c
+++ b/libavcodec/pnm_parser.c
@@ -2,20 +2,20 @@
* PNM image parser
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pnmdec.c b/libavcodec/pnmdec.c
index 9074d9b28c..e634500674 100644
--- a/libavcodec/pnmdec.c
+++ b/libavcodec/pnmdec.c
@@ -2,29 +2,39 @@
* PNM image format
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
-#include "bytestream.h"
#include "internal.h"
#include "put_bits.h"
#include "pnm.h"
+static void samplecpy(uint8_t *dst, const uint8_t *src, int n, int maxval)
+{
+ if (maxval <= 255) {
+ memcpy(dst, src, n);
+ } else {
+ int i;
+ for (i=0; i<n/2; i++) {
+ ((uint16_t *)dst)[i] = AV_RB16(src+2*i);
+ }
+ }
+}
static int pnm_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
@@ -33,36 +43,51 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
int buf_size = avpkt->size;
PNMContext * const s = avctx->priv_data;
AVFrame * const p = data;
- int i, j, n, linesize, h, upgrade = 0;
+ int i, j, n, linesize, h, upgrade = 0, is_mono = 0;
unsigned char *ptr;
int components, sample_len, ret;
s->bytestream_start =
- s->bytestream = buf;
- s->bytestream_end = buf + buf_size;
+ s->bytestream = (uint8_t *)buf;
+ s->bytestream_end = (uint8_t *)buf + buf_size;
if ((ret = ff_pnm_decode_header(avctx, s)) < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
+ avctx->bits_per_raw_sample = av_log2(s->maxval) + 1;
switch (avctx->pix_fmt) {
default:
return AVERROR(EINVAL);
- case AV_PIX_FMT_RGB48BE:
+ case AV_PIX_FMT_RGBA64:
+ n = avctx->width * 8;
+ components=4;
+ sample_len=16;
+ if (s->maxval < 65535)
+ upgrade = 2;
+ goto do_read;
+ case AV_PIX_FMT_RGB48:
n = avctx->width * 6;
components=3;
sample_len=16;
+ if (s->maxval < 65535)
+ upgrade = 2;
+ goto do_read;
+ case AV_PIX_FMT_RGBA:
+ n = avctx->width * 4;
+ components=4;
+ sample_len=8;
goto do_read;
case AV_PIX_FMT_RGB24:
n = avctx->width * 3;
components=3;
sample_len=8;
+ if (s->maxval < 255)
+ upgrade = 1;
goto do_read;
case AV_PIX_FMT_GRAY8:
n = avctx->width;
@@ -71,48 +96,71 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
if (s->maxval < 255)
upgrade = 1;
goto do_read;
- case AV_PIX_FMT_GRAY16BE:
- case AV_PIX_FMT_GRAY16LE:
+ case AV_PIX_FMT_GRAY8A:
+ n = avctx->width * 2;
+ components=2;
+ sample_len=8;
+ goto do_read;
+ case AV_PIX_FMT_GRAY16:
n = avctx->width * 2;
components=1;
sample_len=16;
if (s->maxval < 65535)
upgrade = 2;
goto do_read;
+ case AV_PIX_FMT_YA16:
+ n = avctx->width * 4;
+ components=2;
+ sample_len=16;
+ if (s->maxval < 65535)
+ upgrade = 2;
+ goto do_read;
case AV_PIX_FMT_MONOWHITE:
case AV_PIX_FMT_MONOBLACK:
n = (avctx->width + 7) >> 3;
components=1;
sample_len=1;
+ is_mono = 1;
do_read:
ptr = p->data[0];
linesize = p->linesize[0];
if (s->bytestream + n * avctx->height > s->bytestream_end)
return AVERROR_INVALIDDATA;
- if(s->type < 4){
+ if(s->type < 4 || (is_mono && s->type==7)){
for (i=0; i<avctx->height; i++) {
PutBitContext pb;
init_put_bits(&pb, ptr, linesize);
for(j=0; j<avctx->width * components; j++){
unsigned int c=0;
int v=0;
+ if(s->type < 4)
while(s->bytestream < s->bytestream_end && (*s->bytestream < '0' || *s->bytestream > '9' ))
s->bytestream++;
if(s->bytestream >= s->bytestream_end)
return AVERROR_INVALIDDATA;
- do{
- v= 10*v + c;
- c= (*s->bytestream++) - '0';
- }while(c <= 9);
- put_bits(&pb, sample_len, (((1<<sample_len)-1)*v + (s->maxval>>1))/s->maxval);
+ if (is_mono) {
+ /* read a single digit */
+ v = (*s->bytestream++)&1;
+ } else {
+ /* read a sequence of digits */
+ do {
+ v = 10*v + c;
+ c = (*s->bytestream++) - '0';
+ } while (c <= 9);
+ }
+ if (sample_len == 16) {
+ ((uint16_t*)ptr)[j] = (((1<<sample_len)-1)*v + (s->maxval>>1))/s->maxval;
+ } else
+ put_bits(&pb, sample_len, (((1<<sample_len)-1)*v + (s->maxval>>1))/s->maxval);
}
- flush_put_bits(&pb);
+ if (sample_len != 16)
+ flush_put_bits(&pb);
ptr+= linesize;
}
}else{
for (i = 0; i < avctx->height; i++) {
if (!upgrade)
- memcpy(ptr, s->bytestream, n);
+ samplecpy(ptr, s->bytestream, n, s->maxval);
else if (upgrade == 1) {
unsigned int j, f = (255 * 128 + s->maxval / 2) / s->maxval;
for (j = 0; j < n; j++)
@@ -130,8 +178,8 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
}
break;
case AV_PIX_FMT_YUV420P:
- case AV_PIX_FMT_YUV420P9BE:
- case AV_PIX_FMT_YUV420P10BE:
+ case AV_PIX_FMT_YUV420P9:
+ case AV_PIX_FMT_YUV420P10:
{
unsigned char *ptr1, *ptr2;
@@ -143,7 +191,7 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
if (s->bytestream + n * avctx->height * 3 / 2 > s->bytestream_end)
return AVERROR_INVALIDDATA;
for (i = 0; i < avctx->height; i++) {
- memcpy(ptr, s->bytestream, n);
+ samplecpy(ptr, s->bytestream, n, s->maxval);
s->bytestream += n;
ptr += linesize;
}
@@ -152,9 +200,9 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
n >>= 1;
h = avctx->height >> 1;
for (i = 0; i < h; i++) {
- memcpy(ptr1, s->bytestream, n);
+ samplecpy(ptr1, s->bytestream, n, s->maxval);
s->bytestream += n;
- memcpy(ptr2, s->bytestream, n);
+ samplecpy(ptr2, s->bytestream, n, s->maxval);
s->bytestream += n;
ptr1 += p->linesize[1];
ptr2 += p->linesize[2];
@@ -202,24 +250,6 @@ static int pnm_decode_frame(AVCodecContext *avctx, void *data,
}
}
break;
- case AV_PIX_FMT_RGB32:
- ptr = p->data[0];
- linesize = p->linesize[0];
- if (s->bytestream + avctx->width * avctx->height * 4 > s->bytestream_end)
- return AVERROR_INVALIDDATA;
- for (i = 0; i < avctx->height; i++) {
- int j, r, g, b, a;
-
- for (j = 0; j < avctx->width; j++) {
- r = *s->bytestream++;
- g = *s->bytestream++;
- b = *s->bytestream++;
- a = *s->bytestream++;
- ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
- }
- ptr += linesize;
- }
- break;
}
*got_frame = 1;
diff --git a/libavcodec/pnmenc.c b/libavcodec/pnmenc.c
index 7513552815..e6c3635e7b 100644
--- a/libavcodec/pnmenc.c
+++ b/libavcodec/pnmenc.c
@@ -2,42 +2,38 @@
* PNM image format
* Copyright (c) 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/pixdesc.h"
#include "avcodec.h"
-#include "bytestream.h"
#include "internal.h"
static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pict, int *got_packet)
+ const AVFrame *p, int *got_packet)
{
uint8_t *bytestream, *bytestream_start, *bytestream_end;
- const AVFrame * const p = pict;
int i, h, h1, c, n, linesize, ret;
uint8_t *ptr, *ptr1, *ptr2;
- if ((ret = ff_alloc_packet(pkt, avpicture_get_size(avctx->pix_fmt,
+ if ((ret = ff_alloc_packet2(avctx, pkt, avpicture_get_size(avctx->pix_fmt,
avctx->width,
- avctx->height) + 200)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ avctx->height) + 200)) < 0)
return ret;
- }
bytestream_start =
bytestream = pkt->data;
@@ -67,6 +63,10 @@ static int pnm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
n = avctx->width * 6;
break;
case AV_PIX_FMT_YUV420P:
+ if (avctx->width & 1 || avctx->height & 1) {
+ av_log(avctx, AV_LOG_ERROR, "pgmyuv needs even width and height\n");
+ return AVERROR(EINVAL);
+ }
c = '5';
n = avctx->width;
h1 = (h * 3) / 2;
diff --git a/libavcodec/ppc/Makefile b/libavcodec/ppc/Makefile
index ea8a74516e..30d04b846a 100644
--- a/libavcodec/ppc/Makefile
+++ b/libavcodec/ppc/Makefile
@@ -2,10 +2,11 @@
OBJS-$(CONFIG_AUDIODSP) += ppc/audiodsp.o
OBJS-$(CONFIG_BLOCKDSP) += ppc/blockdsp.o
OBJS-$(CONFIG_FFT) += ppc/fft_init.o \
- ppc/fft_altivec.o
+ ppc/fft_altivec.o \
+ ppc/fft_vsx.o
OBJS-$(CONFIG_FMTCONVERT) += ppc/fmtconvert_altivec.o
OBJS-$(CONFIG_H264CHROMA) += ppc/h264chroma_init.o
-OBJS-$(CONFIG_H264DSP) += ppc/h264dsp.o
+OBJS-$(CONFIG_H264DSP) += ppc/h264dsp.o ppc/hpeldsp_altivec.o
OBJS-$(CONFIG_H264QPEL) += ppc/h264qpel.o
OBJS-$(CONFIG_HPELDSP) += ppc/hpeldsp_altivec.o
OBJS-$(CONFIG_HUFFYUVDSP) += ppc/huffyuvdsp_altivec.o
@@ -21,7 +22,7 @@ OBJS-$(CONFIG_VIDEODSP) += ppc/videodsp_ppc.o
OBJS-$(CONFIG_VP3DSP) += ppc/vp3dsp_altivec.o
# decoders/encoders
-OBJS-$(CONFIG_APE_DECODER) += ppc/apedsp_altivec.o
+OBJS-$(CONFIG_LLAUDDSP) += ppc/lossless_audiodsp_altivec.o
OBJS-$(CONFIG_SVQ1_ENCODER) += ppc/svq1enc_altivec.o
OBJS-$(CONFIG_VC1_DECODER) += ppc/vc1dsp_altivec.o
OBJS-$(CONFIG_VORBIS_DECODER) += ppc/vorbisdsp_altivec.o
diff --git a/libavcodec/ppc/apedsp_altivec.c b/libavcodec/ppc/apedsp_altivec.c
deleted file mode 100644
index d8bf4bd167..0000000000
--- a/libavcodec/ppc/apedsp_altivec.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2007 Luca Barbato <lu_zero@gentoo.org>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#if HAVE_ALTIVEC_H
-#include <altivec.h>
-#endif
-
-#include "libavutil/attributes.h"
-#include "libavutil/cpu.h"
-#include "libavutil/ppc/cpu.h"
-#include "libavutil/ppc/types_altivec.h"
-#include "libavcodec/apedsp.h"
-
-#if HAVE_ALTIVEC
-static int32_t scalarproduct_and_madd_int16_altivec(int16_t *v1,
- const int16_t *v2,
- const int16_t *v3,
- int order, int mul)
-{
- LOAD_ZERO;
- vec_s16 *pv1 = (vec_s16 *) v1;
- register vec_s16 muls = { mul, mul, mul, mul, mul, mul, mul, mul };
- register vec_s16 t0, t1, i0, i1, i4;
- register vec_s16 i2 = vec_ld(0, v2), i3 = vec_ld(0, v3);
- register vec_s32 res = zero_s32v;
- register vec_u8 align = vec_lvsl(0, v2);
- int32_t ires;
-
- order >>= 4;
- do {
- i1 = vec_ld(16, v2);
- t0 = vec_perm(i2, i1, align);
- i2 = vec_ld(32, v2);
- t1 = vec_perm(i1, i2, align);
- i0 = pv1[0];
- i1 = pv1[1];
- res = vec_msum(t0, i0, res);
- res = vec_msum(t1, i1, res);
- i4 = vec_ld(16, v3);
- t0 = vec_perm(i3, i4, align);
- i3 = vec_ld(32, v3);
- t1 = vec_perm(i4, i3, align);
- pv1[0] = vec_mladd(t0, muls, i0);
- pv1[1] = vec_mladd(t1, muls, i1);
- pv1 += 2;
- v2 += 16;
- v3 += 16;
- } while (--order);
- res = vec_splat(vec_sums(res, zero_s32v), 3);
- vec_ste(res, 0, &ires);
-
- return ires;
-}
-#endif /* HAVE_ALTIVEC */
-
-av_cold void ff_apedsp_init_ppc(APEDSPContext *c)
-{
-#if HAVE_ALTIVEC
- if (!PPC_ALTIVEC(av_get_cpu_flags()))
- return;
-
- c->scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_altivec;
-#endif /* HAVE_ALTIVEC */
-}
diff --git a/libavcodec/ppc/asm.S b/libavcodec/ppc/asm.S
index 141dee9b78..a3edeed202 100644
--- a/libavcodec/ppc/asm.S
+++ b/libavcodec/ppc/asm.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/audiodsp.c b/libavcodec/ppc/audiodsp.c
index 36506ce902..c88c3d9167 100644
--- a/libavcodec/ppc/audiodsp.c
+++ b/libavcodec/ppc/audiodsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/blockdsp.c b/libavcodec/ppc/blockdsp.c
index 679bc0454f..0059b3b448 100644
--- a/libavcodec/ppc/blockdsp.c
+++ b/libavcodec/ppc/blockdsp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Dieter Shirley
* Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/dct-test.c b/libavcodec/ppc/dct-test.c
index 37fd8bbd23..2328516ca4 100644
--- a/libavcodec/ppc/dct-test.c
+++ b/libavcodec/ppc/dct-test.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/fdct.h b/libavcodec/ppc/fdct.h
index 74710354ef..437f815258 100644
--- a/libavcodec/ppc/fdct.h
+++ b/libavcodec/ppc/fdct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/fdctdsp.c b/libavcodec/ppc/fdctdsp.c
index 51417a5828..40f4c6c967 100644
--- a/libavcodec/ppc/fdctdsp.c
+++ b/libavcodec/ppc/fdctdsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2003 James Klicman <james@klicman.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,7 +59,7 @@
#define WA (SQRT_2 * (-C3 - C5))
#define WB (SQRT_2 * (C5 - C3))
-static vector float fdctconsts[3] = {
+static const vector float fdctconsts[3] = {
{ W0, W1, W2, W3 },
{ W4, W5, W6, W7 },
{ W8, W9, WA, WB }
@@ -196,7 +196,7 @@ static vector float fdctconsts[3] = {
void ff_fdct_altivec(int16_t *block)
{
vector signed short *bp;
- vector float *cp = fdctconsts;
+ const vector float *cp = fdctconsts;
vector float b00, b10, b20, b30, b40, b50, b60, b70;
vector float b01, b11, b21, b31, b41, b51, b61, b71;
vector float mzero, cnst, cnsts0, cnsts1, cnsts2;
diff --git a/libavcodec/ppc/fft_altivec.S b/libavcodec/ppc/fft_altivec.S
index c92b30b897..aab669ea45 100644
--- a/libavcodec/ppc/fft_altivec.S
+++ b/libavcodec/ppc/fft_altivec.S
@@ -5,20 +5,20 @@
* This algorithm (though not any of the implementation details) is
* based on libdjbfft by D. J. Bernstein.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/fft_init.c b/libavcodec/ppc/fft_init.c
index 8fcc033b53..675fa33a95 100644
--- a/libavcodec/ppc/fft_init.c
+++ b/libavcodec/ppc/fft_init.c
@@ -3,20 +3,20 @@
* AltiVec-enabled
* Copyright (c) 2009 Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,8 +36,12 @@
* It also assumes all FFTComplex are 8 bytes-aligned pairs of floats.
*/
+#if HAVE_VSX
+#include "fft_vsx.h"
+#else
void ff_fft_calc_altivec(FFTContext *s, FFTComplex *z);
void ff_fft_calc_interleave_altivec(FFTContext *s, FFTComplex *z);
+#endif
#if HAVE_GNU_AS && HAVE_ALTIVEC
static void imdct_half_altivec(FFTContext *s, FFTSample *output, const FFTSample *input)
@@ -94,7 +98,11 @@ static void imdct_half_altivec(FFTContext *s, FFTSample *output, const FFTSample
k--;
} while(k >= 0);
+#if HAVE_VSX
+ ff_fft_calc_vsx(s, (FFTComplex*)output);
+#else
ff_fft_calc_altivec(s, (FFTComplex*)output);
+#endif
/* post rotation + reordering */
j = -n32;
@@ -147,7 +155,11 @@ av_cold void ff_fft_init_ppc(FFTContext *s)
if (!PPC_ALTIVEC(av_get_cpu_flags()))
return;
+#if HAVE_VSX
+ s->fft_calc = ff_fft_calc_interleave_vsx;
+#else
s->fft_calc = ff_fft_calc_interleave_altivec;
+#endif
if (s->mdct_bits >= 5) {
s->imdct_calc = imdct_calc_altivec;
s->imdct_half = imdct_half_altivec;
diff --git a/libavcodec/ppc/fft_vsx.c b/libavcodec/ppc/fft_vsx.c
new file mode 100644
index 0000000000..e92975f74e
--- /dev/null
+++ b/libavcodec/ppc/fft_vsx.c
@@ -0,0 +1,227 @@
+/*
+ * FFT transform, optimized with VSX built-in functions
+ * Copyright (c) 2014 Rong Yan
+ *
+ * This algorithm (though not any of the implementation details) is
+ * based on libdjbfft by D. J. Bernstein.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/cpu.h"
+#include "libavutil/ppc/types_altivec.h"
+#include "libavutil/ppc/util_altivec.h"
+#include "libavcodec/fft.h"
+#include "libavcodec/fft-internal.h"
+#include "fft_vsx.h"
+
+#if HAVE_VSX
+
+static void fft32_vsx_interleave(FFTComplex *z)
+{
+ fft16_vsx_interleave(z);
+ fft8_vsx_interleave(z+16);
+ fft8_vsx_interleave(z+24);
+ pass_vsx_interleave(z,ff_cos_32,4);
+}
+
+static void fft64_vsx_interleave(FFTComplex *z)
+{
+ fft32_vsx_interleave(z);
+ fft16_vsx_interleave(z+32);
+ fft16_vsx_interleave(z+48);
+ pass_vsx_interleave(z,ff_cos_64, 8);
+}
+static void fft128_vsx_interleave(FFTComplex *z)
+{
+ fft64_vsx_interleave(z);
+ fft32_vsx_interleave(z+64);
+ fft32_vsx_interleave(z+96);
+ pass_vsx_interleave(z,ff_cos_128,16);
+}
+static void fft256_vsx_interleave(FFTComplex *z)
+{
+ fft128_vsx_interleave(z);
+ fft64_vsx_interleave(z+128);
+ fft64_vsx_interleave(z+192);
+ pass_vsx_interleave(z,ff_cos_256,32);
+}
+static void fft512_vsx_interleave(FFTComplex *z)
+{
+ fft256_vsx_interleave(z);
+ fft128_vsx_interleave(z+256);
+ fft128_vsx_interleave(z+384);
+ pass_vsx_interleave(z,ff_cos_512,64);
+}
+static void fft1024_vsx_interleave(FFTComplex *z)
+{
+ fft512_vsx_interleave(z);
+ fft256_vsx_interleave(z+512);
+ fft256_vsx_interleave(z+768);
+ pass_vsx_interleave(z,ff_cos_1024,128);
+
+}
+static void fft2048_vsx_interleave(FFTComplex *z)
+{
+ fft1024_vsx_interleave(z);
+ fft512_vsx_interleave(z+1024);
+ fft512_vsx_interleave(z+1536);
+ pass_vsx_interleave(z,ff_cos_2048,256);
+}
+static void fft4096_vsx_interleave(FFTComplex *z)
+{
+ fft2048_vsx_interleave(z);
+ fft1024_vsx_interleave(z+2048);
+ fft1024_vsx_interleave(z+3072);
+ pass_vsx_interleave(z,ff_cos_4096, 512);
+}
+static void fft8192_vsx_interleave(FFTComplex *z)
+{
+ fft4096_vsx_interleave(z);
+ fft2048_vsx_interleave(z+4096);
+ fft2048_vsx_interleave(z+6144);
+ pass_vsx_interleave(z,ff_cos_8192,1024);
+}
+static void fft16384_vsx_interleave(FFTComplex *z)
+{
+ fft8192_vsx_interleave(z);
+ fft4096_vsx_interleave(z+8192);
+ fft4096_vsx_interleave(z+12288);
+ pass_vsx_interleave(z,ff_cos_16384,2048);
+}
+static void fft32768_vsx_interleave(FFTComplex *z)
+{
+ fft16384_vsx_interleave(z);
+ fft8192_vsx_interleave(z+16384);
+ fft8192_vsx_interleave(z+24576);
+ pass_vsx_interleave(z,ff_cos_32768,4096);
+}
+static void fft65536_vsx_interleave(FFTComplex *z)
+{
+ fft32768_vsx_interleave(z);
+ fft16384_vsx_interleave(z+32768);
+ fft16384_vsx_interleave(z+49152);
+ pass_vsx_interleave(z,ff_cos_65536,8192);
+}
+
+static void fft32_vsx(FFTComplex *z)
+{
+ fft16_vsx(z);
+ fft8_vsx(z+16);
+ fft8_vsx(z+24);
+ pass_vsx(z,ff_cos_32,4);
+}
+
+static void fft64_vsx(FFTComplex *z)
+{
+ fft32_vsx(z);
+ fft16_vsx(z+32);
+ fft16_vsx(z+48);
+ pass_vsx(z,ff_cos_64, 8);
+}
+static void fft128_vsx(FFTComplex *z)
+{
+ fft64_vsx(z);
+ fft32_vsx(z+64);
+ fft32_vsx(z+96);
+ pass_vsx(z,ff_cos_128,16);
+}
+static void fft256_vsx(FFTComplex *z)
+{
+ fft128_vsx(z);
+ fft64_vsx(z+128);
+ fft64_vsx(z+192);
+ pass_vsx(z,ff_cos_256,32);
+}
+static void fft512_vsx(FFTComplex *z)
+{
+ fft256_vsx(z);
+ fft128_vsx(z+256);
+ fft128_vsx(z+384);
+ pass_vsx(z,ff_cos_512,64);
+}
+static void fft1024_vsx(FFTComplex *z)
+{
+ fft512_vsx(z);
+ fft256_vsx(z+512);
+ fft256_vsx(z+768);
+ pass_vsx(z,ff_cos_1024,128);
+
+}
+static void fft2048_vsx(FFTComplex *z)
+{
+ fft1024_vsx(z);
+ fft512_vsx(z+1024);
+ fft512_vsx(z+1536);
+ pass_vsx(z,ff_cos_2048,256);
+}
+static void fft4096_vsx(FFTComplex *z)
+{
+ fft2048_vsx(z);
+ fft1024_vsx(z+2048);
+ fft1024_vsx(z+3072);
+ pass_vsx(z,ff_cos_4096, 512);
+}
+static void fft8192_vsx(FFTComplex *z)
+{
+ fft4096_vsx(z);
+ fft2048_vsx(z+4096);
+ fft2048_vsx(z+6144);
+ pass_vsx(z,ff_cos_8192,1024);
+}
+static void fft16384_vsx(FFTComplex *z)
+{
+ fft8192_vsx(z);
+ fft4096_vsx(z+8192);
+ fft4096_vsx(z+12288);
+ pass_vsx(z,ff_cos_16384,2048);
+}
+static void fft32768_vsx(FFTComplex *z)
+{
+ fft16384_vsx(z);
+ fft8192_vsx(z+16384);
+ fft8192_vsx(z+24576);
+ pass_vsx(z,ff_cos_32768,4096);
+}
+static void fft65536_vsx(FFTComplex *z)
+{
+ fft32768_vsx(z);
+ fft16384_vsx(z+32768);
+ fft16384_vsx(z+49152);
+ pass_vsx(z,ff_cos_65536,8192);
+}
+
+static void (* const fft_dispatch_vsx[])(FFTComplex*) = {
+ fft4_vsx, fft8_vsx, fft16_vsx, fft32_vsx, fft64_vsx, fft128_vsx, fft256_vsx, fft512_vsx, fft1024_vsx,
+ fft2048_vsx, fft4096_vsx, fft8192_vsx, fft16384_vsx, fft32768_vsx, fft65536_vsx,
+};
+static void (* const fft_dispatch_vsx_interleave[])(FFTComplex*) = {
+ fft4_vsx_interleave, fft8_vsx_interleave, fft16_vsx_interleave, fft32_vsx_interleave, fft64_vsx_interleave,
+ fft128_vsx_interleave, fft256_vsx_interleave, fft512_vsx_interleave, fft1024_vsx_interleave,
+ fft2048_vsx_interleave, fft4096_vsx_interleave, fft8192_vsx_interleave, fft16384_vsx_interleave, fft32768_vsx_interleave, fft65536_vsx_interleave,
+};
+void ff_fft_calc_interleave_vsx(FFTContext *s, FFTComplex *z)
+{
+ fft_dispatch_vsx_interleave[s->nbits-2](z);
+}
+void ff_fft_calc_vsx(FFTContext *s, FFTComplex *z)
+{
+ fft_dispatch_vsx[s->nbits-2](z);
+}
+#endif /* HAVE_VSX */
diff --git a/libavcodec/ppc/fft_vsx.h b/libavcodec/ppc/fft_vsx.h
new file mode 100644
index 0000000000..a85475d160
--- /dev/null
+++ b/libavcodec/ppc/fft_vsx.h
@@ -0,0 +1,830 @@
+#ifndef AVCODEC_PPC_FFT_VSX_H
+#define AVCODEC_PPC_FFT_VSX_H
+/*
+ * FFT transform, optimized with VSX built-in functions
+ * Copyright (c) 2014 Rong Yan Copyright (c) 2009 Loren Merritt
+ *
+ * This algorithm (though not any of the implementation details) is
+ * based on libdjbfft by D. J. Bernstein, and fft_altivec_s.S.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/cpu.h"
+#include "libavutil/ppc/types_altivec.h"
+#include "libavutil/ppc/util_altivec.h"
+#include "libavcodec/fft.h"
+#include "libavcodec/fft-internal.h"
+
+#if HAVE_VSX
+
+void ff_fft_calc_interleave_vsx(FFTContext *s, FFTComplex *z);
+void ff_fft_calc_vsx(FFTContext *s, FFTComplex *z);
+
+
+#define byte_2complex (2*sizeof(FFTComplex))
+#define byte_4complex (4*sizeof(FFTComplex))
+#define byte_6complex (6*sizeof(FFTComplex))
+#define byte_8complex (8*sizeof(FFTComplex))
+#define byte_10complex (10*sizeof(FFTComplex))
+#define byte_12complex (12*sizeof(FFTComplex))
+#define byte_14complex (14*sizeof(FFTComplex))
+
+inline static void pass_vsx_interleave(FFTComplex *z, const FFTSample *wre, unsigned int n)
+{
+ int o1 = n<<1;
+ int o2 = n<<2;
+ int o3 = o1+o2;
+ int i1, i2, i3;
+ FFTSample* out = (FFTSample*)z;
+ const FFTSample *wim = wre+o1;
+ vec_f vz0, vzo1, vzo2, vzo3;
+ vec_f x0, x1, x2, x3;
+ vec_f x4, x5, x6, x7;
+ vec_f x8, x9, x10, x11;
+ vec_f x12, x13, x14, x15;
+ vec_f x16, x17, x18, x19;
+ vec_f x20, x21, x22, x23;
+ vec_f vz0plus1, vzo1plus1, vzo2plus1, vzo3plus1;
+ vec_f y0, y1, y2, y3;
+ vec_f y4, y5, y8, y9;
+ vec_f y10, y13, y14, y15;
+ vec_f y16, y17, y18, y19;
+ vec_f y20, y21, y22, y23;
+ vec_f wr1, wi1, wr0, wi0;
+ vec_f wr2, wi2, wr3, wi3;
+ vec_f xmulwi0, xmulwi1, ymulwi2, ymulwi3;
+
+ n = n-2;
+ i1 = o1*sizeof(FFTComplex);
+ i2 = o2*sizeof(FFTComplex);
+ i3 = o3*sizeof(FFTComplex);
+ vzo2 = vec_ld(i2, &(out[0])); // zo2.r zo2.i z(o2+1).r z(o2+1).i
+ vzo2plus1 = vec_ld(i2+16, &(out[0]));
+ vzo3 = vec_ld(i3, &(out[0])); // zo3.r zo3.i z(o3+1).r z(o3+1).i
+ vzo3plus1 = vec_ld(i3+16, &(out[0]));
+ vz0 = vec_ld(0, &(out[0])); // z0.r z0.i z1.r z1.i
+ vz0plus1 = vec_ld(16, &(out[0]));
+ vzo1 = vec_ld(i1, &(out[0])); // zo1.r zo1.i z(o1+1).r z(o1+1).i
+ vzo1plus1 = vec_ld(i1+16, &(out[0]));
+
+ x0 = vec_add(vzo2, vzo3);
+ x1 = vec_sub(vzo2, vzo3);
+ y0 = vec_add(vzo2plus1, vzo3plus1);
+ y1 = vec_sub(vzo2plus1, vzo3plus1);
+
+ wr1 = vec_splats(wre[1]);
+ wi1 = vec_splats(wim[-1]);
+ wi2 = vec_splats(wim[-2]);
+ wi3 = vec_splats(wim[-3]);
+ wr2 = vec_splats(wre[2]);
+ wr3 = vec_splats(wre[3]);
+
+ x2 = vec_perm(x0, x1, vcprm(2,s2,3,s3));
+ x3 = vec_perm(x0, x1, vcprm(s3,3,s2,2));
+
+ y4 = vec_perm(y0, y1, vcprm(s1,1,s0,0));
+ y5 = vec_perm(y0, y1, vcprm(s3,3,s2,2));
+ y2 = vec_perm(y0, y1, vcprm(0,s0,1,s1));
+ y3 = vec_perm(y0, y1, vcprm(2,s2,3,s3));
+
+ ymulwi2 = vec_mul(y4, wi2);
+ ymulwi3 = vec_mul(y5, wi3);
+ x4 = vec_mul(x2, wr1);
+ x5 = vec_mul(x3, wi1);
+ y8 = vec_madd(y2, wr2, ymulwi2);
+ y9 = vec_msub(y2, wr2, ymulwi2);
+ x6 = vec_add(x4, x5);
+ x7 = vec_sub(x4, x5);
+ y13 = vec_madd(y3, wr3, ymulwi3);
+ y14 = vec_msub(y3, wr3, ymulwi3);
+
+ x8 = vec_perm(x6, x7, vcprm(0,1,s2,s3));
+ y10 = vec_perm(y8, y9, vcprm(0,1,s2,s3));
+ y15 = vec_perm(y13, y14, vcprm(0,1,s2,s3));
+
+ x9 = vec_perm(x0, x8, vcprm(0,1,s0,s2));
+ x10 = vec_perm(x1, x8, vcprm(1,0,s3,s1));
+
+ y16 = vec_perm(y10, y15, vcprm(0,2,s0,s2));
+ y17 = vec_perm(y10, y15, vcprm(3,1,s3,s1));
+
+ x11 = vec_add(vz0, x9);
+ x12 = vec_sub(vz0, x9);
+ x13 = vec_add(vzo1, x10);
+ x14 = vec_sub(vzo1, x10);
+
+ y18 = vec_add(vz0plus1, y16);
+ y19 = vec_sub(vz0plus1, y16);
+ y20 = vec_add(vzo1plus1, y17);
+ y21 = vec_sub(vzo1plus1, y17);
+
+ x15 = vec_perm(x13, x14, vcprm(0,s1,2,s3));
+ x16 = vec_perm(x13, x14, vcprm(s0,1,s2,3));
+ y22 = vec_perm(y20, y21, vcprm(0,s1,2,s3));
+ y23 = vec_perm(y20, y21, vcprm(s0,1,s2,3));
+
+
+ vec_st(x11, 0, &(out[0]));
+ vec_st(y18, 16, &(out[0]));
+ vec_st(x15, i1, &(out[0]));
+ vec_st(y22, i1+16, &(out[0]));
+ vec_st(x12, i2, &(out[0]));
+ vec_st(y19, i2+16, &(out[0]));
+ vec_st(x16, i3, &(out[0]));
+ vec_st(y23, i3+16, &(out[0]));
+
+ do {
+ out += 8;
+ wre += 4;
+ wim -= 4;
+ wr0 = vec_splats(wre[0]);
+ wr1 = vec_splats(wre[1]);
+ wi0 = vec_splats(wim[0]);
+ wi1 = vec_splats(wim[-1]);
+
+ wr2 = vec_splats(wre[2]);
+ wr3 = vec_splats(wre[3]);
+ wi2 = vec_splats(wim[-2]);
+ wi3 = vec_splats(wim[-3]);
+
+ vzo2 = vec_ld(i2, &(out[0])); // zo2.r zo2.i z(o2+1).r z(o2+1).i
+ vzo2plus1 = vec_ld(i2+16, &(out[0]));
+ vzo3 = vec_ld(i3, &(out[0])); // zo3.r zo3.i z(o3+1).r z(o3+1).i
+ vzo3plus1 = vec_ld(i3+16, &(out[0]));
+ vz0 = vec_ld(0, &(out[0])); // z0.r z0.i z1.r z1.i
+ vz0plus1 = vec_ld(16, &(out[0]));
+ vzo1 = vec_ld(i1, &(out[0])); // zo1.r zo1.i z(o1+1).r z(o1+1).i
+ vzo1plus1 = vec_ld(i1+16, &(out[0]));
+
+ x0 = vec_add(vzo2, vzo3);
+ x1 = vec_sub(vzo2, vzo3);
+
+ y0 = vec_add(vzo2plus1, vzo3plus1);
+ y1 = vec_sub(vzo2plus1, vzo3plus1);
+
+ x4 = vec_perm(x0, x1, vcprm(s1,1,s0,0));
+ x5 = vec_perm(x0, x1, vcprm(s3,3,s2,2));
+ x2 = vec_perm(x0, x1, vcprm(0,s0,1,s1));
+ x3 = vec_perm(x0, x1, vcprm(2,s2,3,s3));
+
+ y2 = vec_perm(y0, y1, vcprm(0,s0,1,s1));
+ y3 = vec_perm(y0, y1, vcprm(2,s2,3,s3));
+ xmulwi0 = vec_mul(x4, wi0);
+ xmulwi1 = vec_mul(x5, wi1);
+
+ y4 = vec_perm(y0, y1, vcprm(s1,1,s0,0));
+ y5 = vec_perm(y0, y1, vcprm(s3,3,s2,2));
+
+ x8 = vec_madd(x2, wr0, xmulwi0);
+ x9 = vec_msub(x2, wr0, xmulwi0);
+ ymulwi2 = vec_mul(y4, wi2);
+ ymulwi3 = vec_mul(y5, wi3);
+
+ x13 = vec_madd(x3, wr1, xmulwi1);
+ x14 = vec_msub(x3, wr1, xmulwi1);
+
+ y8 = vec_madd(y2, wr2, ymulwi2);
+ y9 = vec_msub(y2, wr2, ymulwi2);
+ y13 = vec_madd(y3, wr3, ymulwi3);
+ y14 = vec_msub(y3, wr3, ymulwi3);
+
+ x10 = vec_perm(x8, x9, vcprm(0,1,s2,s3));
+ x15 = vec_perm(x13, x14, vcprm(0,1,s2,s3));
+
+ y10 = vec_perm(y8, y9, vcprm(0,1,s2,s3));
+ y15 = vec_perm(y13, y14, vcprm(0,1,s2,s3));
+
+ x16 = vec_perm(x10, x15, vcprm(0,2,s0,s2));
+ x17 = vec_perm(x10, x15, vcprm(3,1,s3,s1));
+
+ y16 = vec_perm(y10, y15, vcprm(0,2,s0,s2));
+ y17 = vec_perm(y10, y15, vcprm(3,1,s3,s1));
+
+ x18 = vec_add(vz0, x16);
+ x19 = vec_sub(vz0, x16);
+ x20 = vec_add(vzo1, x17);
+ x21 = vec_sub(vzo1, x17);
+
+ y18 = vec_add(vz0plus1, y16);
+ y19 = vec_sub(vz0plus1, y16);
+ y20 = vec_add(vzo1plus1, y17);
+ y21 = vec_sub(vzo1plus1, y17);
+
+ x22 = vec_perm(x20, x21, vcprm(0,s1,2,s3));
+ x23 = vec_perm(x20, x21, vcprm(s0,1,s2,3));
+
+ y22 = vec_perm(y20, y21, vcprm(0,s1,2,s3));
+ y23 = vec_perm(y20, y21, vcprm(s0,1,s2,3));
+
+ vec_st(x18, 0, &(out[0]));
+ vec_st(y18, 16, &(out[0]));
+ vec_st(x22, i1, &(out[0]));
+ vec_st(y22, i1+16, &(out[0]));
+ vec_st(x19, i2, &(out[0]));
+ vec_st(y19, i2+16, &(out[0]));
+ vec_st(x23, i3, &(out[0]));
+ vec_st(y23, i3+16, &(out[0]));
+ } while (n-=2);
+}
+
+inline static void fft2_vsx_interleave(FFTComplex *z)
+{
+ FFTSample r1, i1;
+
+ r1 = z[0].re - z[1].re;
+ z[0].re += z[1].re;
+ z[1].re = r1;
+
+ i1 = z[0].im - z[1].im;
+ z[0].im += z[1].im;
+ z[1].im = i1;
+ }
+
+inline static void fft4_vsx_interleave(FFTComplex *z)
+{
+ vec_f a, b, c, d;
+ float* out= (float*)z;
+ a = vec_ld(0, &(out[0]));
+ b = vec_ld(byte_2complex, &(out[0]));
+
+ c = vec_perm(a, b, vcprm(0,1,s2,s1));
+ d = vec_perm(a, b, vcprm(2,3,s0,s3));
+ a = vec_add(c, d);
+ b = vec_sub(c, d);
+
+ c = vec_perm(a, b, vcprm(0,1,s0,s1));
+ d = vec_perm(a, b, vcprm(2,3,s3,s2));
+
+ a = vec_add(c, d);
+ b = vec_sub(c, d);
+ vec_st(a, 0, &(out[0]));
+ vec_st(b, byte_2complex, &(out[0]));
+}
+
+inline static void fft8_vsx_interleave(FFTComplex *z)
+{
+ vec_f vz0, vz1, vz2, vz3;
+ vec_f x0, x1, x2, x3;
+ vec_f x4, x5, x6, x7;
+ vec_f x8, x9, x10, x11;
+ vec_f x12, x13, x14, x15;
+ vec_f x16, x17, x18, x19;
+ vec_f x20, x21, x22, x23;
+ vec_f x24, x25, x26, x27;
+ vec_f x28, x29, x30, x31;
+ vec_f x32, x33, x34;
+
+ float* out= (float*)z;
+ vec_f vc1 = {sqrthalf, sqrthalf, sqrthalf, sqrthalf};
+
+ vz0 = vec_ld(0, &(out[0]));
+ vz1 = vec_ld(byte_2complex, &(out[0]));
+ vz2 = vec_ld(byte_4complex, &(out[0]));
+ vz3 = vec_ld(byte_6complex, &(out[0]));
+
+ x0 = vec_perm(vz0, vz1, vcprm(0,1,s2,s1));
+ x1 = vec_perm(vz0, vz1, vcprm(2,3,s0,s3));
+ x2 = vec_perm(vz2, vz3, vcprm(2,1,s0,s1));
+ x3 = vec_perm(vz2, vz3, vcprm(0,3,s2,s3));
+
+ x4 = vec_add(x0, x1);
+ x5 = vec_sub(x0, x1);
+ x6 = vec_add(x2, x3);
+ x7 = vec_sub(x2, x3);
+
+ x8 = vec_perm(x4, x5, vcprm(0,1,s0,s1));
+ x9 = vec_perm(x4, x5, vcprm(2,3,s3,s2));
+ x10 = vec_perm(x6, x7, vcprm(2,1,s2,s1));
+ x11 = vec_perm(x6, x7, vcprm(0,3,s0,s3));
+
+ x12 = vec_add(x8, x9);
+ x13 = vec_sub(x8, x9);
+ x14 = vec_add(x10, x11);
+ x15 = vec_sub(x10, x11);
+ x16 = vec_perm(x12, x13, vcprm(0,s0,1,s1));
+ x17 = vec_perm(x14, x15, vcprm(0,s0,1,s1));
+ x18 = vec_perm(x16, x17, vcprm(s0,s3,s2,s1));
+ x19 = vec_add(x16, x18); // z0.r z2.r z0.i z2.i
+ x20 = vec_sub(x16, x18); // z4.r z6.r z4.i z6.i
+
+ x21 = vec_perm(x12, x13, vcprm(2,s2,3,s3));
+ x22 = vec_perm(x14, x15, vcprm(2,3,s2,s3));
+ x23 = vec_perm(x14, x15, vcprm(3,2,s3,s2));
+ x24 = vec_add(x22, x23);
+ x25 = vec_sub(x22, x23);
+ x26 = vec_mul( vec_perm(x24, x25, vcprm(2,s2,0,s0)), vc1);
+
+ x27 = vec_add(x21, x26); // z1.r z7.r z1.i z3.i
+ x28 = vec_sub(x21, x26); //z5.r z3.r z5.i z7.i
+
+ x29 = vec_perm(x19, x27, vcprm(0,2,s0,s2)); // z0.r z0.i z1.r z1.i
+ x30 = vec_perm(x19, x27, vcprm(1,3,s1,s3)); // z2.r z2.i z7.r z3.i
+ x31 = vec_perm(x20, x28, vcprm(0,2,s0,s2)); // z4.r z4.i z5.r z5.i
+ x32 = vec_perm(x20, x28, vcprm(1,3,s1,s3)); // z6.r z6.i z3.r z7.i
+ x33 = vec_perm(x30, x32, vcprm(0,1,s2,3)); // z2.r z2.i z3.r z3.i
+ x34 = vec_perm(x30, x32, vcprm(s0,s1,2,s3)); // z6.r z6.i z7.r z7.i
+
+ vec_st(x29, 0, &(out[0]));
+ vec_st(x33, byte_2complex, &(out[0]));
+ vec_st(x31, byte_4complex, &(out[0]));
+ vec_st(x34, byte_6complex, &(out[0]));
+}
+
+inline static void fft16_vsx_interleave(FFTComplex *z)
+{
+ float* out= (float*)z;
+ vec_f vc0 = {sqrthalf, sqrthalf, sqrthalf, sqrthalf};
+ vec_f vc1 = {ff_cos_16[1], ff_cos_16[1], ff_cos_16[1], ff_cos_16[1]};
+ vec_f vc2 = {ff_cos_16[3], ff_cos_16[3], ff_cos_16[3], ff_cos_16[3]};
+ vec_f vz0, vz1, vz2, vz3;
+ vec_f vz4, vz5, vz6, vz7;
+ vec_f x0, x1, x2, x3;
+ vec_f x4, x5, x6, x7;
+ vec_f x8, x9, x10, x11;
+ vec_f x12, x13, x14, x15;
+ vec_f x16, x17, x18, x19;
+ vec_f x20, x21, x22, x23;
+ vec_f x24, x25, x26, x27;
+ vec_f x28, x29, x30, x31;
+ vec_f x32, x33, x34, x35;
+ vec_f x36, x37, x38, x39;
+ vec_f x40, x41, x42, x43;
+ vec_f x44, x45, x46, x47;
+ vec_f x48, x49, x50, x51;
+ vec_f x52, x53, x54, x55;
+ vec_f x56, x57, x58, x59;
+ vec_f x60, x61, x62, x63;
+ vec_f x64, x65, x66, x67;
+ vec_f x68, x69, x70, x71;
+ vec_f x72, x73, x74, x75;
+ vec_f x76, x77, x78, x79;
+ vec_f x80, x81, x82, x83;
+ vec_f x84, x85, x86;
+
+ vz0 = vec_ld(0, &(out[0]));
+ vz1 = vec_ld(byte_2complex, &(out[0]));
+ vz2 = vec_ld(byte_4complex, &(out[0]));
+ vz3 = vec_ld(byte_6complex, &(out[0]));
+ vz4 = vec_ld(byte_8complex, &(out[0]));
+ vz5 = vec_ld(byte_10complex, &(out[0]));
+ vz6 = vec_ld(byte_12complex, &(out[0]));
+ vz7 = vec_ld(byte_14complex, &(out[0]));
+
+ x0 = vec_perm(vz0, vz1, vcprm(0,1,s2,s1));
+ x1 = vec_perm(vz0, vz1, vcprm(2,3,s0,s3));
+ x2 = vec_perm(vz2, vz3, vcprm(0,1,s0,s1));
+ x3 = vec_perm(vz2, vz3, vcprm(2,3,s2,s3));
+
+ x4 = vec_perm(vz4, vz5, vcprm(0,1,s2,s1));
+ x5 = vec_perm(vz4, vz5, vcprm(2,3,s0,s3));
+ x6 = vec_perm(vz6, vz7, vcprm(0,1,s2,s1));
+ x7 = vec_perm(vz6, vz7, vcprm(2,3,s0,s3));
+
+ x8 = vec_add(x0, x1);
+ x9 = vec_sub(x0, x1);
+ x10 = vec_add(x2, x3);
+ x11 = vec_sub(x2, x3);
+
+ x12 = vec_add(x4, x5);
+ x13 = vec_sub(x4, x5);
+ x14 = vec_add(x6, x7);
+ x15 = vec_sub(x6, x7);
+
+ x16 = vec_perm(x8, x9, vcprm(0,1,s0,s1));
+ x17 = vec_perm(x8, x9, vcprm(2,3,s3,s2));
+ x18 = vec_perm(x10, x11, vcprm(2,1,s1,s2));
+ x19 = vec_perm(x10, x11, vcprm(0,3,s0,s3));
+ x20 = vec_perm(x12, x14, vcprm(0,1,s0, s1));
+ x21 = vec_perm(x12, x14, vcprm(2,3,s2,s3));
+ x22 = vec_perm(x13, x15, vcprm(0,1,s0,s1));
+ x23 = vec_perm(x13, x15, vcprm(3,2,s3,s2));
+
+ x24 = vec_add(x16, x17);
+ x25 = vec_sub(x16, x17);
+ x26 = vec_add(x18, x19);
+ x27 = vec_sub(x18, x19);
+ x28 = vec_add(x20, x21);
+ x29 = vec_sub(x20, x21);
+ x30 = vec_add(x22, x23);
+ x31 = vec_sub(x22, x23);
+
+ x32 = vec_add(x24, x26);
+ x33 = vec_sub(x24, x26);
+ x34 = vec_perm(x32, x33, vcprm(0,1,s0,s1));
+
+ x35 = vec_perm(x28, x29, vcprm(2,1,s1,s2));
+ x36 = vec_perm(x28, x29, vcprm(0,3,s0,s3));
+ x37 = vec_add(x35, x36);
+ x38 = vec_sub(x35, x36);
+ x39 = vec_perm(x37, x38, vcprm(0,1,s1,s0));
+
+ x40 = vec_perm(x27, x38, vcprm(3,2,s2,s3));
+ x41 = vec_perm(x26, x37, vcprm(2,3,s3,s2));
+ x42 = vec_add(x40, x41);
+ x43 = vec_sub(x40, x41);
+ x44 = vec_mul(x42, vc0);
+ x45 = vec_mul(x43, vc0);
+
+ x46 = vec_add(x34, x39); // z0.r z0.i z4.r z4.i
+ x47 = vec_sub(x34, x39); // z8.r z8.i z12.r z12.i
+
+ x48 = vec_perm(x30, x31, vcprm(2,1,s1,s2));
+ x49 = vec_perm(x30, x31, vcprm(0,3,s3,s0));
+ x50 = vec_add(x48, x49);
+ x51 = vec_sub(x48, x49);
+ x52 = vec_mul(x50, vc1);
+ x53 = vec_mul(x50, vc2);
+ x54 = vec_mul(x51, vc1);
+ x55 = vec_mul(x51, vc2);
+
+ x56 = vec_perm(x24, x25, vcprm(2,3,s2,s3));
+ x57 = vec_perm(x44, x45, vcprm(0,1,s1,s0));
+ x58 = vec_add(x56, x57);
+ x59 = vec_sub(x56, x57);
+
+ x60 = vec_perm(x54, x55, vcprm(1,0,3,2));
+ x61 = vec_perm(x54, x55, vcprm(s1,s0,s3,s2));
+ x62 = vec_add(x52, x61);
+ x63 = vec_sub(x52, x61);
+ x64 = vec_add(x60, x53);
+ x65 = vec_sub(x60, x53);
+ x66 = vec_perm(x62, x64, vcprm(0,1,s3,s2));
+ x67 = vec_perm(x63, x65, vcprm(s0,s1,3,2));
+
+ x68 = vec_add(x58, x66); // z1.r z1.i z3.r z3.i
+ x69 = vec_sub(x58, x66); // z9.r z9.i z11.r z11.i
+ x70 = vec_add(x59, x67); // z5.r z5.i z15.r z15.i
+ x71 = vec_sub(x59, x67); // z13.r z13.i z7.r z7.i
+
+ x72 = vec_perm(x25, x27, vcprm(s1,s0,s2,s3));
+ x73 = vec_add(x25, x72);
+ x74 = vec_sub(x25, x72);
+ x75 = vec_perm(x73, x74, vcprm(0,1,s0,s1));
+ x76 = vec_perm(x44, x45, vcprm(3,2,s2,s3));
+ x77 = vec_add(x75, x76); // z2.r z2.i z6.r z6.i
+ x78 = vec_sub(x75, x76); // z10.r z10.i z14.r z14.i
+
+ x79 = vec_perm(x46, x68, vcprm(0,1,s0,s1)); // z0.r z0.i z1.r z1.i
+ x80 = vec_perm(x77, x68, vcprm(0,1,s2,s3)); // z2.r z2.i z3.r z3.i
+ x81 = vec_perm(x46, x70, vcprm(2,3,s0,s1)); // z4.r z4.i z5.r z5.i
+ x82 = vec_perm(x71, x77, vcprm(s2,s3,2,3)); // z6.r z6.i z7.r z7.i
+ vec_st(x79, 0, &(out[0]));
+ vec_st(x80, byte_2complex, &(out[0]));
+ vec_st(x81, byte_4complex, &(out[0]));
+ vec_st(x82, byte_6complex, &(out[0]));
+ x83 = vec_perm(x47, x69, vcprm(0,1,s0,s1)); // z8.r z8.i z9.r z9.i
+ x84 = vec_perm(x78, x69, vcprm(0,1,s2,s3)); // z10.r z10.i z11.r z11.i
+ x85 = vec_perm(x47, x71, vcprm(2,3,s0,s1)); // z12.r z12.i z13.r z13.i
+ x86 = vec_perm(x70, x78, vcprm(s2,s3,2,3)); // z14.r z14.i z15.r z15.i
+ vec_st(x83, byte_8complex, &(out[0]));
+ vec_st(x84, byte_10complex, &(out[0]));
+ vec_st(x85, byte_12complex, &(out[0]));
+ vec_st(x86, byte_14complex, &(out[0]));
+}
+
+inline static void fft4_vsx(FFTComplex *z)
+{
+ vec_f a, b, c, d;
+ float* out= (float*)z;
+ a = vec_ld(0, &(out[0]));
+ b = vec_ld(byte_2complex, &(out[0]));
+
+ c = vec_perm(a, b, vcprm(0,1,s2,s1));
+ d = vec_perm(a, b, vcprm(2,3,s0,s3));
+ a = vec_add(c, d);
+ b = vec_sub(c, d);
+
+ c = vec_perm(a,b, vcprm(0,s0,1,s1));
+ d = vec_perm(a, b, vcprm(2,s3,3,s2));
+
+ a = vec_add(c, d);
+ b = vec_sub(c, d);
+
+ c = vec_perm(a, b, vcprm(0,1,s0,s1));
+ d = vec_perm(a, b, vcprm(2,3,s2,s3));
+
+ vec_st(c, 0, &(out[0]));
+ vec_st(d, byte_2complex, &(out[0]));
+ return;
+}
+
+inline static void fft8_vsx(FFTComplex *z)
+{
+ vec_f vz0, vz1, vz2, vz3;
+ vec_f vz4, vz5, vz6, vz7, vz8;
+
+ float* out= (float*)z;
+ vec_f vc0 = {0.0, 0.0, 0.0, 0.0};
+ vec_f vc1 = {-sqrthalf, sqrthalf, sqrthalf, -sqrthalf};
+ vec_f vc2 = {sqrthalf, sqrthalf, sqrthalf, sqrthalf};
+
+ vz0 = vec_ld(0, &(out[0]));
+ vz1 = vec_ld(byte_2complex, &(out[0]));
+ vz2 = vec_ld(byte_4complex, &(out[0]));
+ vz3 = vec_ld(byte_6complex, &(out[0]));
+
+ vz6 = vec_perm(vz2, vz3, vcprm(0,s0,1,s1));
+ vz7 = vec_perm(vz2, vz3, vcprm(2,s2,3,s3));
+ vz4 = vec_perm(vz0, vz1, vcprm(0,1,s2,s1));
+ vz5 = vec_perm(vz0, vz1, vcprm(2,3,s0,s3));
+
+ vz2 = vec_add(vz6, vz7);
+ vz3 = vec_sub(vz6, vz7);
+ vz8 = vec_perm(vz3, vz3, vcprm(2,3,0,1));
+
+ vz0 = vec_add(vz4, vz5);
+ vz1 = vec_sub(vz4, vz5);
+
+ vz3 = vec_madd(vz3, vc1, vc0);
+ vz3 = vec_madd(vz8, vc2, vz3);
+
+ vz4 = vec_perm(vz0, vz1, vcprm(0,s0,1,s1));
+ vz5 = vec_perm(vz0, vz1, vcprm(2,s3,3,s2));
+ vz6 = vec_perm(vz2, vz3, vcprm(1,2,s3,s0));
+ vz7 = vec_perm(vz2, vz3, vcprm(0,3,s2,s1));
+
+ vz0 = vec_add(vz4, vz5);
+ vz1 = vec_sub(vz4, vz5);
+ vz2 = vec_add(vz6, vz7);
+ vz3 = vec_sub(vz6, vz7);
+
+ vz4 = vec_perm(vz0, vz1, vcprm(0,1,s0,s1));
+ vz5 = vec_perm(vz0, vz1, vcprm(2,3,s2,s3));
+ vz6 = vec_perm(vz2, vz3, vcprm(0,2,s1,s3));
+ vz7 = vec_perm(vz2, vz3, vcprm(1,3,s0,s2));
+
+
+ vz2 = vec_sub(vz4, vz6);
+ vz3 = vec_sub(vz5, vz7);
+
+ vz0 = vec_add(vz4, vz6);
+ vz1 = vec_add(vz5, vz7);
+
+ vec_st(vz0, 0, &(out[0]));
+ vec_st(vz1, byte_2complex, &(out[0]));
+ vec_st(vz2, byte_4complex, &(out[0]));
+ vec_st(vz3, byte_6complex, &(out[0]));
+ return;
+}
+
+inline static void fft16_vsx(FFTComplex *z)
+{
+ float* out= (float*)z;
+ vec_f vc0 = {0.0, 0.0, 0.0, 0.0};
+ vec_f vc1 = {-sqrthalf, sqrthalf, sqrthalf, -sqrthalf};
+ vec_f vc2 = {sqrthalf, sqrthalf, sqrthalf, sqrthalf};
+ vec_f vc3 = {1.0, 0.92387953, sqrthalf, 0.38268343};
+ vec_f vc4 = {0.0, 0.38268343, sqrthalf, 0.92387953};
+ vec_f vc5 = {-0.0, -0.38268343, -sqrthalf, -0.92387953};
+
+ vec_f vz0, vz1, vz2, vz3;
+ vec_f vz4, vz5, vz6, vz7;
+ vec_f vz8, vz9, vz10, vz11;
+ vec_f vz12, vz13;
+
+ vz0 = vec_ld(byte_8complex, &(out[0]));
+ vz1 = vec_ld(byte_10complex, &(out[0]));
+ vz2 = vec_ld(byte_12complex, &(out[0]));
+ vz3 = vec_ld(byte_14complex, &(out[0]));
+
+ vz4 = vec_perm(vz0, vz1, vcprm(0,1,s2,s1));
+ vz5 = vec_perm(vz0, vz1, vcprm(2,3,s0,s3));
+ vz6 = vec_perm(vz2, vz3, vcprm(0,1,s2,s1));
+ vz7 = vec_perm(vz2, vz3, vcprm(2,3,s0,s3));
+
+ vz0 = vec_add(vz4, vz5);
+ vz1= vec_sub(vz4, vz5);
+ vz2 = vec_add(vz6, vz7);
+ vz3 = vec_sub(vz6, vz7);
+
+ vz4 = vec_perm(vz0, vz1, vcprm(0,s0,1,s1));
+ vz5 = vec_perm(vz0, vz1, vcprm(2,s3,3,s2));
+ vz6 = vec_perm(vz2, vz3, vcprm(0,s0,1,s1));
+ vz7 = vec_perm(vz2, vz3, vcprm(2,s3,3,s2));
+
+ vz0 = vec_add(vz4, vz5);
+ vz1 = vec_sub(vz4, vz5);
+ vz2 = vec_add(vz6, vz7);
+ vz3 = vec_sub(vz6, vz7);
+
+ vz4 = vec_perm(vz0, vz1, vcprm(0,1,s0,s1));
+ vz5 = vec_perm(vz0, vz1, vcprm(2,3,s2,s3));
+
+ vz6 = vec_perm(vz2, vz3, vcprm(0,1,s0,s1));
+ vz7 = vec_perm(vz2, vz3, vcprm(2,3,s2,s3));
+
+ vz0 = vec_ld(0, &(out[0]));
+ vz1 = vec_ld(byte_2complex, &(out[0]));
+ vz2 = vec_ld(byte_4complex, &(out[0]));
+ vz3 = vec_ld(byte_6complex, &(out[0]));
+ vz10 = vec_perm(vz2, vz3, vcprm(0,s0,1,s1));
+ vz11 = vec_perm(vz2, vz3, vcprm(2,s2,3,s3));
+ vz8 = vec_perm(vz0, vz1, vcprm(0,1,s2,s1));
+ vz9 = vec_perm(vz0, vz1, vcprm(2,3,s0,s3));
+
+ vz2 = vec_add(vz10, vz11);
+ vz3 = vec_sub(vz10, vz11);
+ vz12 = vec_perm(vz3, vz3, vcprm(2,3,0,1));
+ vz0 = vec_add(vz8, vz9);
+ vz1 = vec_sub(vz8, vz9);
+
+ vz3 = vec_madd(vz3, vc1, vc0);
+ vz3 = vec_madd(vz12, vc2, vz3);
+ vz8 = vec_perm(vz0, vz1, vcprm(0,s0,1,s1));
+ vz9 = vec_perm(vz0, vz1, vcprm(2,s3,3,s2));
+ vz10 = vec_perm(vz2, vz3, vcprm(1,2,s3,s0));
+ vz11 = vec_perm(vz2, vz3, vcprm(0,3,s2,s1));
+
+ vz0 = vec_add(vz8, vz9);
+ vz1 = vec_sub(vz8, vz9);
+ vz2 = vec_add(vz10, vz11);
+ vz3 = vec_sub(vz10, vz11);
+
+ vz8 = vec_perm(vz0, vz1, vcprm(0,1,s0,s1));
+ vz9 = vec_perm(vz0, vz1, vcprm(2,3,s2,s3));
+ vz10 = vec_perm(vz2, vz3, vcprm(0,2,s1,s3));
+ vz11 = vec_perm(vz2, vz3, vcprm(1,3,s0,s2));
+
+ vz2 = vec_sub(vz8, vz10);
+ vz3 = vec_sub(vz9, vz11);
+ vz0 = vec_add(vz8, vz10);
+ vz1 = vec_add(vz9, vz11);
+
+ vz8 = vec_madd(vz4, vc3, vc0);
+ vz9 = vec_madd(vz5, vc3, vc0);
+ vz10 = vec_madd(vz6, vc3, vc0);
+ vz11 = vec_madd(vz7, vc3, vc0);
+
+ vz8 = vec_madd(vz5, vc4, vz8);
+ vz9 = vec_madd(vz4, vc5, vz9);
+ vz10 = vec_madd(vz7, vc5, vz10);
+ vz11 = vec_madd(vz6, vc4, vz11);
+
+ vz12 = vec_sub(vz10, vz8);
+ vz10 = vec_add(vz10, vz8);
+
+ vz13 = vec_sub(vz9, vz11);
+ vz11 = vec_add(vz9, vz11);
+
+ vz4 = vec_sub(vz0, vz10);
+ vz0 = vec_add(vz0, vz10);
+
+ vz7= vec_sub(vz3, vz12);
+ vz3= vec_add(vz3, vz12);
+
+ vz5 = vec_sub(vz1, vz11);
+ vz1 = vec_add(vz1, vz11);
+
+ vz6 = vec_sub(vz2, vz13);
+ vz2 = vec_add(vz2, vz13);
+
+ vec_st(vz0, 0, &(out[0]));
+ vec_st(vz1, byte_2complex, &(out[0]));
+ vec_st(vz2, byte_4complex, &(out[0]));
+ vec_st(vz3, byte_6complex, &(out[0]));
+ vec_st(vz4, byte_8complex, &(out[0]));
+ vec_st(vz5, byte_10complex, &(out[0]));
+ vec_st(vz6, byte_12complex, &(out[0]));
+ vec_st(vz7, byte_14complex, &(out[0]));
+ return;
+
+}
+inline static void pass_vsx(FFTComplex * z, const FFTSample * wre, unsigned int n)
+{
+ int o1 = n<<1;
+ int o2 = n<<2;
+ int o3 = o1+o2;
+ int i1, i2, i3;
+ FFTSample* out = (FFTSample*)z;
+ const FFTSample *wim = wre+o1;
+ vec_f v0, v1, v2, v3;
+ vec_f v4, v5, v6, v7;
+ vec_f v8, v9, v10, v11;
+ vec_f v12, v13;
+
+ n = n-2;
+ i1 = o1*sizeof(FFTComplex);
+ i2 = o2*sizeof(FFTComplex);
+ i3 = o3*sizeof(FFTComplex);
+
+ v8 = vec_ld(0, &(wre[0]));
+ v10 = vec_ld(0, &(wim[0]));
+ v9 = vec_ld(0, &(wim[-4]));
+ v9 = vec_perm(v9, v10, vcprm(s0,3,2,1));
+
+ v4 = vec_ld(i2, &(out[0]));
+ v5 = vec_ld(i2+16, &(out[0]));
+ v6 = vec_ld(i3, &(out[0]));
+ v7 = vec_ld(i3+16, &(out[0]));
+ v10 = vec_mul(v4, v8); // r2*wre
+ v11 = vec_mul(v5, v8); // i2*wre
+ v12 = vec_mul(v6, v8); // r3*wre
+ v13 = vec_mul(v7, v8); // i3*wre
+
+ v0 = vec_ld(0, &(out[0])); // r0
+ v3 = vec_ld(i1+16, &(out[0])); // i1
+ v10 = vec_madd(v5, v9, v10); // r2*wim
+ v11 = vec_nmsub(v4, v9, v11); // i2*wim
+ v12 = vec_nmsub(v7, v9, v12); // r3*wim
+ v13 = vec_madd(v6, v9, v13); // i3*wim
+
+ v1 = vec_ld(16, &(out[0])); // i0
+ v2 = vec_ld(i1, &(out[0])); // r1
+ v8 = vec_sub(v12, v10);
+ v12 = vec_add(v12, v10);
+ v9 = vec_sub(v11, v13);
+ v13 = vec_add(v11, v13);
+ v4 = vec_sub(v0, v12);
+ v0 = vec_add(v0, v12);
+ v7 = vec_sub(v3, v8);
+ v3 = vec_add(v3, v8);
+
+ vec_st(v0, 0, &(out[0])); // r0
+ vec_st(v3, i1+16, &(out[0])); // i1
+ vec_st(v4, i2, &(out[0])); // r2
+ vec_st(v7, i3+16, &(out[0]));// i3
+
+ v5 = vec_sub(v1, v13);
+ v1 = vec_add(v1, v13);
+ v6 = vec_sub(v2, v9);
+ v2 = vec_add(v2, v9);
+
+ vec_st(v1, 16, &(out[0])); // i0
+ vec_st(v2, i1, &(out[0])); // r1
+ vec_st(v5, i2+16, &(out[0])); // i2
+ vec_st(v6, i3, &(out[0])); // r3
+
+ do {
+ out += 8;
+ wre += 4;
+ wim -= 4;
+
+ v8 = vec_ld(0, &(wre[0]));
+ v10 = vec_ld(0, &(wim[0]));
+ v9 = vec_ld(0, &(wim[-4]));
+ v9 = vec_perm(v9, v10, vcprm(s0,3,2,1));
+
+ v4 = vec_ld(i2, &(out[0])); // r2
+ v5 = vec_ld(i2+16, &(out[0])); // i2
+ v6 = vec_ld(i3, &(out[0])); // r3
+ v7 = vec_ld(i3+16, &(out[0]));// i3
+ v10 = vec_mul(v4, v8); // r2*wre
+ v11 = vec_mul(v5, v8); // i2*wre
+ v12 = vec_mul(v6, v8); // r3*wre
+ v13 = vec_mul(v7, v8); // i3*wre
+
+ v0 = vec_ld(0, &(out[0])); // r0
+ v3 = vec_ld(i1+16, &(out[0])); // i1
+ v10 = vec_madd(v5, v9, v10); // r2*wim
+ v11 = vec_nmsub(v4, v9, v11); // i2*wim
+ v12 = vec_nmsub(v7, v9, v12); // r3*wim
+ v13 = vec_madd(v6, v9, v13); // i3*wim
+
+ v1 = vec_ld(16, &(out[0])); // i0
+ v2 = vec_ld(i1, &(out[0])); // r1
+ v8 = vec_sub(v12, v10);
+ v12 = vec_add(v12, v10);
+ v9 = vec_sub(v11, v13);
+ v13 = vec_add(v11, v13);
+ v4 = vec_sub(v0, v12);
+ v0 = vec_add(v0, v12);
+ v7 = vec_sub(v3, v8);
+ v3 = vec_add(v3, v8);
+
+ vec_st(v0, 0, &(out[0])); // r0
+ vec_st(v3, i1+16, &(out[0])); // i1
+ vec_st(v4, i2, &(out[0])); // r2
+ vec_st(v7, i3+16, &(out[0])); // i3
+
+ v5 = vec_sub(v1, v13);
+ v1 = vec_add(v1, v13);
+ v6 = vec_sub(v2, v9);
+ v2 = vec_add(v2, v9);
+
+ vec_st(v1, 16, &(out[0])); // i0
+ vec_st(v2, i1, &(out[0])); // r1
+ vec_st(v5, i2+16, &(out[0])); // i2
+ vec_st(v6, i3, &(out[0])); // r3
+ } while (n-=2);
+}
+
+#endif
+
+#endif /* AVCODEC_PPC_FFT_VSX_H */
diff --git a/libavcodec/ppc/fmtconvert_altivec.c b/libavcodec/ppc/fmtconvert_altivec.c
index 7536703ff4..7323eff0bd 100644
--- a/libavcodec/ppc/fmtconvert_altivec.c
+++ b/libavcodec/ppc/fmtconvert_altivec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/h264chroma_init.c b/libavcodec/ppc/h264chroma_init.c
index 6d656d46ba..876efeca09 100644
--- a/libavcodec/ppc/h264chroma_init.c
+++ b/libavcodec/ppc/h264chroma_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/h264chroma_template.c b/libavcodec/ppc/h264chroma_template.c
index 293fef5c90..cb1e0957e1 100644
--- a/libavcodec/ppc/h264chroma_template.c
+++ b/libavcodec/ppc/h264chroma_template.c
@@ -1,30 +1,32 @@
/*
* Copyright (c) 2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/ppc/types_altivec.h"
+#include "libavutil/ppc/util_altivec.h"
/* this code assume that stride % 16 == 0 */
#define CHROMA_MC8_ALTIVEC_CORE(BIAS1, BIAS2) \
- vsrc2ssH = (vec_s16)vec_mergeh(zero_u8v,(vec_u8)vsrc2uc);\
- vsrc3ssH = (vec_s16)vec_mergeh(zero_u8v,(vec_u8)vsrc3uc);\
+ vsrc2ssH = (vec_s16)VEC_MERGEH(zero_u8v,(vec_u8)vsrc2uc);\
+ vsrc3ssH = (vec_s16)VEC_MERGEH(zero_u8v,(vec_u8)vsrc3uc);\
\
psum = vec_mladd(vA, vsrc0ssH, BIAS1);\
psum = vec_mladd(vB, vsrc1ssH, psum);\
@@ -49,8 +51,8 @@
#define CHROMA_MC8_ALTIVEC_CORE_SIMPLE \
\
- vsrc0ssH = (vec_s16)vec_mergeh(zero_u8v,(vec_u8)vsrc0uc);\
- vsrc1ssH = (vec_s16)vec_mergeh(zero_u8v,(vec_u8)vsrc1uc);\
+ vsrc0ssH = (vec_s16)VEC_MERGEH(zero_u8v,(vec_u8)vsrc0uc);\
+ vsrc1ssH = (vec_s16)VEC_MERGEH(zero_u8v,(vec_u8)vsrc1uc);\
\
psum = vec_mladd(vA, vsrc0ssH, v32ss);\
psum = vec_mladd(vE, vsrc1ssH, psum);\
@@ -70,6 +72,43 @@
#define noop(a) a
#define add28(a) vec_add(v28ss, a)
+#if HAVE_BIGENDIAN
+#define GET_VSRC1(vs0, off, b, perm0, s){ \
+ vec_u8 vsrcCuc, vsrcDuc; \
+ vsrcCuc = vec_ld(off, s); \
+ if (loadSecond){ \
+ vsrcDuc = vec_ld(off + b, s); \
+ } else \
+ vsrcDuc = vsrcCuc; \
+ \
+ vs0 = vec_perm(vsrcCuc, vsrcDuc, perm0); \
+}
+#define GET_VSRC(vs0, vs1, off, b, perm0, perm1, s){ \
+ vec_u8 vsrcCuc, vsrcDuc; \
+ vsrcCuc = vec_ld(off, s); \
+ if (loadSecond){ \
+ vsrcDuc = vec_ld(off + b, s); \
+ } else \
+ vsrcDuc = vsrcCuc; \
+ \
+ vs0 = vec_perm(vsrcCuc, vsrcDuc, perm0); \
+ if (reallyBadAlign){ \
+ vs1 = vsrcDuc; \
+ } else \
+ vs1 = vec_perm(vsrcCuc, vsrcDuc, perm1); \
+ }
+
+#else
+
+#define GET_VSRC1(vs0, off, b, perm0, s){ \
+ vs0 = vec_vsx_ld(off, s); \
+ }
+#define GET_VSRC(vs0, vs1, off, b, perm0, perm1, s){ \
+ vs0 = vec_vsx_ld(off, s); \
+ vs1 = vec_vsx_ld(off + 1, s); \
+ }
+#endif /* HAVE_BIGENDIAN */
+
#ifdef PREFIX_h264_chroma_mc8_altivec
static void PREFIX_h264_chroma_mc8_altivec(uint8_t * dst, uint8_t * src,
int stride, int h, int x, int y) {
@@ -80,23 +119,27 @@ static void PREFIX_h264_chroma_mc8_altivec(uint8_t * dst, uint8_t * src,
(( x) * ( y))};
register int i;
vec_u8 fperm;
- const vec_s32 vABCD = vec_ld(0, ABCD);
- const vec_s16 vA = vec_splat((vec_s16)vABCD, 1);
- const vec_s16 vB = vec_splat((vec_s16)vABCD, 3);
- const vec_s16 vC = vec_splat((vec_s16)vABCD, 5);
- const vec_s16 vD = vec_splat((vec_s16)vABCD, 7);
LOAD_ZERO;
+ const vec_s32 vABCD = vec_ld(0, ABCD);
+ const vec_s16 vA = VEC_SPLAT16(vABCD, 1);
+ const vec_s16 vB = VEC_SPLAT16(vABCD, 3);
+ const vec_s16 vC = VEC_SPLAT16(vABCD, 5);
+ const vec_s16 vD = VEC_SPLAT16(vABCD, 7);
const vec_s16 v32ss = vec_sl(vec_splat_s16(1),vec_splat_u16(5));
const vec_u16 v6us = vec_splat_u16(6);
- register int loadSecond = (((unsigned long)src) % 16) <= 7 ? 0 : 1;
- register int reallyBadAlign = (((unsigned long)src) % 16) == 15 ? 1 : 0;
- vec_u8 vsrcAuc, av_uninit(vsrcBuc), vsrcperm0, vsrcperm1;
+ vec_u8 vsrcperm0, vsrcperm1;
vec_u8 vsrc0uc, vsrc1uc;
vec_s16 vsrc0ssH, vsrc1ssH;
- vec_u8 vsrcCuc, vsrc2uc, vsrc3uc;
+ vec_u8 vsrc2uc, vsrc3uc;
vec_s16 vsrc2ssH, vsrc3ssH, psum;
vec_u8 vdst, ppsum, vfdst, fsum;
+#if HAVE_BIGENDIAN
+ register int loadSecond = (((unsigned long)src) % 16) <= 7 ? 0 : 1;
+ register int reallyBadAlign = (((unsigned long)src) % 16) == 15 ? 1 : 0;
+ vsrcperm0 = vec_lvsl(0, src);
+ vsrcperm1 = vec_lvsl(1, src);
+#endif
if (((unsigned long)dst) % 16 == 0) {
fperm = (vec_u8){0x10, 0x11, 0x12, 0x13,
@@ -110,89 +153,28 @@ static void PREFIX_h264_chroma_mc8_altivec(uint8_t * dst, uint8_t * src,
0x1C, 0x1D, 0x1E, 0x1F};
}
- vsrcAuc = vec_ld(0, src);
-
- if (loadSecond)
- vsrcBuc = vec_ld(16, src);
- vsrcperm0 = vec_lvsl(0, src);
- vsrcperm1 = vec_lvsl(1, src);
-
- vsrc0uc = vec_perm(vsrcAuc, vsrcBuc, vsrcperm0);
- if (reallyBadAlign)
- vsrc1uc = vsrcBuc;
- else
- vsrc1uc = vec_perm(vsrcAuc, vsrcBuc, vsrcperm1);
+ GET_VSRC(vsrc0uc, vsrc1uc, 0, 16, vsrcperm0, vsrcperm1, src);
- vsrc0ssH = (vec_s16)vec_mergeh(zero_u8v,(vec_u8)vsrc0uc);
- vsrc1ssH = (vec_s16)vec_mergeh(zero_u8v,(vec_u8)vsrc1uc);
+ vsrc0ssH = (vec_s16)VEC_MERGEH(zero_u8v,(vec_u8)vsrc0uc);
+ vsrc1ssH = (vec_s16)VEC_MERGEH(zero_u8v,(vec_u8)vsrc1uc);
if (ABCD[3]) {
- if (!loadSecond) {// -> !reallyBadAlign
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(stride + 0, src);
- vsrc2uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm0);
- vsrc3uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm1);
-
- CHROMA_MC8_ALTIVEC_CORE(v32ss, noop)
- }
- } else {
- vec_u8 vsrcDuc;
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(stride + 0, src);
- vsrcDuc = vec_ld(stride + 16, src);
- vsrc2uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm0);
- if (reallyBadAlign)
- vsrc3uc = vsrcDuc;
- else
- vsrc3uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm1);
-
- CHROMA_MC8_ALTIVEC_CORE(v32ss, noop)
- }
+ for (i = 0 ; i < h ; i++) {
+ GET_VSRC(vsrc2uc, vsrc3uc, stride, 16, vsrcperm0, vsrcperm1, src);
+ CHROMA_MC8_ALTIVEC_CORE(v32ss, noop);
}
} else {
const vec_s16 vE = vec_add(vB, vC);
if (ABCD[2]) { // x == 0 B == 0
- if (!loadSecond) {// -> !reallyBadAlign
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(stride + 0, src);
- vsrc1uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm0);
- CHROMA_MC8_ALTIVEC_CORE_SIMPLE
-
- vsrc0uc = vsrc1uc;
- }
- } else {
- vec_u8 vsrcDuc;
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(stride + 0, src);
- vsrcDuc = vec_ld(stride + 15, src);
- vsrc1uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm0);
- CHROMA_MC8_ALTIVEC_CORE_SIMPLE
-
- vsrc0uc = vsrc1uc;
- }
+ for (i = 0 ; i < h ; i++) {
+ GET_VSRC1(vsrc1uc, stride, 15, vsrcperm0, src);
+ CHROMA_MC8_ALTIVEC_CORE_SIMPLE;
+ vsrc0uc = vsrc1uc;
}
} else { // y == 0 C == 0
- if (!loadSecond) {// -> !reallyBadAlign
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(0, src);
- vsrc0uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm0);
- vsrc1uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm1);
-
- CHROMA_MC8_ALTIVEC_CORE_SIMPLE
- }
- } else {
- vec_u8 vsrcDuc;
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(0, src);
- vsrcDuc = vec_ld(15, src);
- vsrc0uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm0);
- if (reallyBadAlign)
- vsrc1uc = vsrcDuc;
- else
- vsrc1uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm1);
-
- CHROMA_MC8_ALTIVEC_CORE_SIMPLE
- }
+ for (i = 0 ; i < h ; i++) {
+ GET_VSRC(vsrc0uc, vsrc1uc, 0, 15, vsrcperm0, vsrcperm1, src);
+ CHROMA_MC8_ALTIVEC_CORE_SIMPLE;
}
}
}
@@ -209,23 +191,27 @@ static void PREFIX_no_rnd_vc1_chroma_mc8_altivec(uint8_t * dst, uint8_t * src, i
(( x) * ( y))};
register int i;
vec_u8 fperm;
- const vec_s32 vABCD = vec_ld(0, ABCD);
- const vec_s16 vA = vec_splat((vec_s16)vABCD, 1);
- const vec_s16 vB = vec_splat((vec_s16)vABCD, 3);
- const vec_s16 vC = vec_splat((vec_s16)vABCD, 5);
- const vec_s16 vD = vec_splat((vec_s16)vABCD, 7);
LOAD_ZERO;
+ const vec_s32 vABCD = vec_ld(0, ABCD);
+ const vec_s16 vA = VEC_SPLAT16(vABCD, 1);
+ const vec_s16 vB = VEC_SPLAT16(vABCD, 3);
+ const vec_s16 vC = VEC_SPLAT16(vABCD, 5);
+ const vec_s16 vD = VEC_SPLAT16(vABCD, 7);
const vec_s16 v28ss = vec_sub(vec_sl(vec_splat_s16(1),vec_splat_u16(5)),vec_splat_s16(4));
const vec_u16 v6us = vec_splat_u16(6);
- register int loadSecond = (((unsigned long)src) % 16) <= 7 ? 0 : 1;
- register int reallyBadAlign = (((unsigned long)src) % 16) == 15 ? 1 : 0;
- vec_u8 vsrcAuc, av_uninit(vsrcBuc), vsrcperm0, vsrcperm1;
+ vec_u8 vsrcperm0, vsrcperm1;
vec_u8 vsrc0uc, vsrc1uc;
vec_s16 vsrc0ssH, vsrc1ssH;
- vec_u8 vsrcCuc, vsrc2uc, vsrc3uc;
+ vec_u8 vsrc2uc, vsrc3uc;
vec_s16 vsrc2ssH, vsrc3ssH, psum;
vec_u8 vdst, ppsum, vfdst, fsum;
+#if HAVE_BIGENDIAN
+ register int loadSecond = (((unsigned long)src) % 16) <= 7 ? 0 : 1;
+ register int reallyBadAlign = (((unsigned long)src) % 16) == 15 ? 1 : 0;
+ vsrcperm0 = vec_lvsl(0, src);
+ vsrcperm1 = vec_lvsl(1, src);
+#endif
if (((unsigned long)dst) % 16 == 0) {
fperm = (vec_u8){0x10, 0x11, 0x12, 0x13,
@@ -239,47 +225,14 @@ static void PREFIX_no_rnd_vc1_chroma_mc8_altivec(uint8_t * dst, uint8_t * src, i
0x1C, 0x1D, 0x1E, 0x1F};
}
- vsrcAuc = vec_ld(0, src);
-
- if (loadSecond)
- vsrcBuc = vec_ld(16, src);
- vsrcperm0 = vec_lvsl(0, src);
- vsrcperm1 = vec_lvsl(1, src);
-
- vsrc0uc = vec_perm(vsrcAuc, vsrcBuc, vsrcperm0);
- if (reallyBadAlign)
- vsrc1uc = vsrcBuc;
- else
- vsrc1uc = vec_perm(vsrcAuc, vsrcBuc, vsrcperm1);
-
- vsrc0ssH = (vec_s16)vec_mergeh(zero_u8v, (vec_u8)vsrc0uc);
- vsrc1ssH = (vec_s16)vec_mergeh(zero_u8v, (vec_u8)vsrc1uc);
-
- if (!loadSecond) {// -> !reallyBadAlign
- for (i = 0 ; i < h ; i++) {
-
-
- vsrcCuc = vec_ld(stride + 0, src);
+ GET_VSRC(vsrc0uc, vsrc1uc, 0, 16, vsrcperm0, vsrcperm1, src);
- vsrc2uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm0);
- vsrc3uc = vec_perm(vsrcCuc, vsrcCuc, vsrcperm1);
+ vsrc0ssH = (vec_s16)VEC_MERGEH(zero_u8v, (vec_u8)vsrc0uc);
+ vsrc1ssH = (vec_s16)VEC_MERGEH(zero_u8v, (vec_u8)vsrc1uc);
- CHROMA_MC8_ALTIVEC_CORE(vec_splat_s16(0), add28)
- }
- } else {
- vec_u8 vsrcDuc;
- for (i = 0 ; i < h ; i++) {
- vsrcCuc = vec_ld(stride + 0, src);
- vsrcDuc = vec_ld(stride + 16, src);
-
- vsrc2uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm0);
- if (reallyBadAlign)
- vsrc3uc = vsrcDuc;
- else
- vsrc3uc = vec_perm(vsrcCuc, vsrcDuc, vsrcperm1);
-
- CHROMA_MC8_ALTIVEC_CORE(vec_splat_s16(0), add28)
- }
+ for (i = 0 ; i < h ; i++) {
+ GET_VSRC(vsrc2uc, vsrc3uc, stride, 16, vsrcperm0, vsrcperm1, src);
+ CHROMA_MC8_ALTIVEC_CORE(vec_splat_s16(0), add28);
}
}
#endif
diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c
index 31dc141d29..3822c7f55a 100644
--- a/libavcodec/ppc/h264dsp.c
+++ b/libavcodec/ppc/h264dsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -62,10 +62,17 @@
b2 = vec_mergeh( a1, a3 ); \
b3 = vec_mergel( a1, a3 )
+#if HAVE_BIGENDIAN
+#define vdst_load(d) \
+ vdst_orig = vec_ld(0, dst); \
+ vdst = vec_perm(vdst_orig, zero_u8v, vdst_mask);
+#else
+#define vdst_load(d) vdst = vec_vsx_ld(0, dst)
+#endif
+
#define VEC_LOAD_U8_ADD_S16_STORE_U8(va) \
- vdst_orig = vec_ld(0, dst); \
- vdst = vec_perm(vdst_orig, zero_u8v, vdst_mask); \
- vdst_ss = (vec_s16) vec_mergeh(zero_u8v, vdst); \
+ vdst_load(); \
+ vdst_ss = (vec_s16) VEC_MERGEH(zero_u8v, vdst); \
va = vec_add(va, vdst_ss); \
va_u8 = vec_packsu(va, zero_s16v); \
va_u32 = vec_splat((vec_u32)va_u8, 0); \
@@ -165,26 +172,43 @@ static void h264_idct_add_altivec(uint8_t *dst, int16_t *block, int stride)
d7 = vec_sub(b0v, b7v); \
}
+#if HAVE_BIGENDIAN
+#define GET_2PERM(ldv, stv, d) \
+ ldv = vec_lvsl(0, d); \
+ stv = vec_lvsr(8, d);
+#define dstv_load(d) \
+ vec_u8 hv = vec_ld( 0, d ); \
+ vec_u8 lv = vec_ld( 7, d); \
+ vec_u8 dstv = vec_perm( hv, lv, (vec_u8)perm_ldv );
+#define dest_unligned_store(d) \
+ vec_u8 edgehv; \
+ vec_u8 bodyv = vec_perm( idstsum8, idstsum8, perm_stv ); \
+ vec_u8 edgelv = vec_perm( sel, zero_u8v, perm_stv ); \
+ lv = vec_sel( lv, bodyv, edgelv ); \
+ vec_st( lv, 7, d ); \
+ hv = vec_ld( 0, d ); \
+ edgehv = vec_perm( zero_u8v, sel, perm_stv ); \
+ hv = vec_sel( hv, bodyv, edgehv ); \
+ vec_st( hv, 0, d );
+#else
+
+#define GET_2PERM(ldv, stv, d) {}
+#define dstv_load(d) vec_u8 dstv = vec_vsx_ld(0, d)
+#define dest_unligned_store(d)\
+ vec_u8 dst8 = vec_perm((vec_u8)idstsum8, dstv, vcprm(2,3,s2,s3));\
+ vec_vsx_st(dst8, 0, d)
+#endif /* HAVE_BIGENDIAN */
+
#define ALTIVEC_STORE_SUM_CLIP(dest, idctv, perm_ldv, perm_stv, sel) { \
/* unaligned load */ \
- vec_u8 hv = vec_ld( 0, dest ); \
- vec_u8 lv = vec_ld( 7, dest ); \
- vec_u8 dstv = vec_perm( hv, lv, (vec_u8)perm_ldv ); \
+ dstv_load(dest); \
vec_s16 idct_sh6 = vec_sra(idctv, sixv); \
- vec_u16 dst16 = (vec_u16)vec_mergeh(zero_u8v, dstv); \
+ vec_u16 dst16 = (vec_u16)VEC_MERGEH(zero_u8v, dstv); \
vec_s16 idstsum = vec_adds(idct_sh6, (vec_s16)dst16); \
vec_u8 idstsum8 = vec_packsu(zero_s16v, idstsum); \
- vec_u8 edgehv; \
/* unaligned store */ \
- vec_u8 bodyv = vec_perm( idstsum8, idstsum8, perm_stv );\
- vec_u8 edgelv = vec_perm( sel, zero_u8v, perm_stv ); \
- lv = vec_sel( lv, bodyv, edgelv ); \
- vec_st( lv, 7, dest ); \
- hv = vec_ld( 0, dest ); \
- edgehv = vec_perm( zero_u8v, sel, perm_stv ); \
- hv = vec_sel( hv, bodyv, edgehv ); \
- vec_st( hv, 0, dest ); \
- }
+ dest_unligned_store(dest);\
+}
static void h264_idct8_add_altivec(uint8_t *dst, int16_t *dct, int stride)
{
@@ -192,8 +216,8 @@ static void h264_idct8_add_altivec(uint8_t *dst, int16_t *dct, int stride)
vec_s16 d0, d1, d2, d3, d4, d5, d6, d7;
vec_s16 idct0, idct1, idct2, idct3, idct4, idct5, idct6, idct7;
- vec_u8 perm_ldv = vec_lvsl(0, dst);
- vec_u8 perm_stv = vec_lvsr(8, dst);
+ vec_u8 perm_ldv, perm_stv;
+ GET_2PERM(perm_ldv, perm_stv, dst);
const vec_u16 onev = vec_splat_u16(1);
const vec_u16 twov = vec_splat_u16(2);
@@ -232,32 +256,41 @@ static void h264_idct8_add_altivec(uint8_t *dst, int16_t *dct, int stride)
ALTIVEC_STORE_SUM_CLIP(&dst[7*stride], idct7, perm_ldv, perm_stv, sel);
}
+#if HAVE_BIGENDIAN
+#define DST_LD vec_ld
+#else
+#define DST_LD vec_vsx_ld
+#endif
static av_always_inline void h264_idct_dc_add_internal(uint8_t *dst, int16_t *block, int stride, int size)
{
vec_s16 dc16;
vec_u8 dcplus, dcminus, v0, v1, v2, v3, aligner;
+ vec_s32 v_dc32;
LOAD_ZERO;
DECLARE_ALIGNED(16, int, dc);
int i;
dc = (block[0] + 32) >> 6;
block[0] = 0;
- dc16 = vec_splat((vec_s16) vec_lde(0, &dc), 1);
+ v_dc32 = vec_lde(0, &dc);
+ dc16 = VEC_SPLAT16((vec_s16)v_dc32, 1);
if (size == 4)
- dc16 = vec_sld(dc16, zero_s16v, 8);
+ dc16 = VEC_SLD16(dc16, zero_s16v, 8);
dcplus = vec_packsu(dc16, zero_s16v);
dcminus = vec_packsu(vec_sub(zero_s16v, dc16), zero_s16v);
+#if HAVE_BIGENDIAN
aligner = vec_lvsr(0, dst);
dcplus = vec_perm(dcplus, dcplus, aligner);
dcminus = vec_perm(dcminus, dcminus, aligner);
+#endif
for (i = 0; i < size; i += 4) {
- v0 = vec_ld(0, dst+0*stride);
- v1 = vec_ld(0, dst+1*stride);
- v2 = vec_ld(0, dst+2*stride);
- v3 = vec_ld(0, dst+3*stride);
+ v0 = DST_LD(0, dst+0*stride);
+ v1 = DST_LD(0, dst+1*stride);
+ v2 = DST_LD(0, dst+2*stride);
+ v3 = DST_LD(0, dst+3*stride);
v0 = vec_adds(v0, dcplus);
v1 = vec_adds(v1, dcplus);
@@ -269,10 +302,10 @@ static av_always_inline void h264_idct_dc_add_internal(uint8_t *dst, int16_t *bl
v2 = vec_subs(v2, dcminus);
v3 = vec_subs(v3, dcminus);
- vec_st(v0, 0, dst+0*stride);
- vec_st(v1, 0, dst+1*stride);
- vec_st(v2, 0, dst+2*stride);
- vec_st(v3, 0, dst+3*stride);
+ VEC_ST(v0, 0, dst+0*stride);
+ VEC_ST(v1, 0, dst+1*stride);
+ VEC_ST(v2, 0, dst+2*stride);
+ VEC_ST(v3, 0, dst+3*stride);
dst += 4*stride;
}
@@ -633,6 +666,9 @@ void weight_h264_W_altivec(uint8_t *block, int stride, int height,
temp[2] = offset;
vtemp = (vec_s16)vec_ld(0, temp);
+#if !HAVE_BIGENDIAN
+ vtemp =(vec_s16)vec_perm(vtemp, vtemp, vcswapi2s(0,1,2,3));
+#endif
vlog2_denom = (vec_u16)vec_splat(vtemp, 1);
vweight = vec_splat(vtemp, 3);
voffset = vec_splat(vtemp, 5);
@@ -641,8 +677,8 @@ void weight_h264_W_altivec(uint8_t *block, int stride, int height,
for (y = 0; y < height; y++) {
vblock = vec_ld(0, block);
- v0 = (vec_s16)vec_mergeh(zero_u8v, vblock);
- v1 = (vec_s16)vec_mergel(zero_u8v, vblock);
+ v0 = (vec_s16)VEC_MERGEH(zero_u8v, vblock);
+ v1 = (vec_s16)VEC_MERGEL(zero_u8v, vblock);
if (w == 16 || aligned) {
v0 = vec_mladd(v0, vweight, zero_s16v);
@@ -679,6 +715,9 @@ void biweight_h264_W_altivec(uint8_t *dst, uint8_t *src, int stride, int height,
temp[3] = offset;
vtemp = (vec_s16)vec_ld(0, temp);
+#if !HAVE_BIGENDIAN
+ vtemp =(vec_s16)vec_perm(vtemp, vtemp, vcswapi2s(0,1,2,3));
+#endif
vlog2_denom = (vec_u16)vec_splat(vtemp, 1);
vweights = vec_splat(vtemp, 3);
vweightd = vec_splat(vtemp, 5);
@@ -690,10 +729,10 @@ void biweight_h264_W_altivec(uint8_t *dst, uint8_t *src, int stride, int height,
vdst = vec_ld(0, dst);
vsrc = vec_ld(0, src);
- v0 = (vec_s16)vec_mergeh(zero_u8v, vdst);
- v1 = (vec_s16)vec_mergel(zero_u8v, vdst);
- v2 = (vec_s16)vec_mergeh(zero_u8v, vsrc);
- v3 = (vec_s16)vec_mergel(zero_u8v, vsrc);
+ v0 = (vec_s16)VEC_MERGEH(zero_u8v, vdst);
+ v1 = (vec_s16)VEC_MERGEL(zero_u8v, vdst);
+ v2 = (vec_s16)VEC_MERGEH(zero_u8v, vsrc);
+ v3 = (vec_s16)VEC_MERGEL(zero_u8v, vsrc);
if (w == 8) {
if (src_aligned)
diff --git a/libavcodec/ppc/h264qpel.c b/libavcodec/ppc/h264qpel.c
index f840277c88..575f504d32 100644
--- a/libavcodec/ppc/h264qpel.c
+++ b/libavcodec/ppc/h264qpel.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -191,86 +191,79 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## CODETYPE(uint8_t *dst, cons
OPNAME ## pixels ## SIZE ## _l2_ ## CODETYPE(dst, halfV, halfHV, stride, SIZE, SIZE);\
}\
+#if HAVE_BIGENDIAN
+#define put_unligned_store(s, dest) { \
+ tmp1 = vec_ld(0, dest); \
+ mask = vec_lvsl(0, dest); \
+ tmp2 = vec_ld(15, dest); \
+ edges = vec_perm(tmp2, tmp1, mask); \
+ align = vec_lvsr(0, dest); \
+ tmp2 = vec_perm(s, edges, align); \
+ tmp1 = vec_perm(edges, s, align); \
+ vec_st(tmp2, 15, dest); \
+ vec_st(tmp1, 0 , dest); \
+ }
+#else
+#define put_unligned_store(s, dest) vec_vsx_st(s, 0, dest);
+#endif /* HAVE_BIGENDIAN */
+
static inline void put_pixels16_l2_altivec( uint8_t * dst, const uint8_t * src1,
const uint8_t * src2, int dst_stride,
int src_stride1, int h)
{
int i;
- vec_u8 a, b, d, tmp1, tmp2, mask, mask_, edges, align;
-
+ vec_u8 a, b, d, mask_;
+#if HAVE_BIGENDIAN
+ vec_u8 tmp1, tmp2, mask, edges, align;
mask_ = vec_lvsl(0, src2);
+#endif
for (i = 0; i < h; i++) {
-
- tmp1 = vec_ld(i * src_stride1, src1);
- mask = vec_lvsl(i * src_stride1, src1);
- tmp2 = vec_ld(i * src_stride1 + 15, src1);
-
- a = vec_perm(tmp1, tmp2, mask);
-
- tmp1 = vec_ld(i * 16, src2);
- tmp2 = vec_ld(i * 16 + 15, src2);
-
- b = vec_perm(tmp1, tmp2, mask_);
-
- tmp1 = vec_ld(0, dst);
- mask = vec_lvsl(0, dst);
- tmp2 = vec_ld(15, dst);
-
+ a = unaligned_load(i * src_stride1, src1);
+ b = load_with_perm_vec(i * 16, src2, mask_);
d = vec_avg(a, b);
-
- edges = vec_perm(tmp2, tmp1, mask);
-
- align = vec_lvsr(0, dst);
-
- tmp2 = vec_perm(d, edges, align);
- tmp1 = vec_perm(edges, d, align);
-
- vec_st(tmp2, 15, dst);
- vec_st(tmp1, 0 , dst);
-
+ put_unligned_store(d, dst);
dst += dst_stride;
}
}
+#if HAVE_BIGENDIAN
+#define avg_unligned_store(s, dest){ \
+ tmp1 = vec_ld(0, dest); \
+ mask = vec_lvsl(0, dest); \
+ tmp2 = vec_ld(15, dest); \
+ a = vec_avg(vec_perm(tmp1, tmp2, mask), s); \
+ edges = vec_perm(tmp2, tmp1, mask); \
+ align = vec_lvsr(0, dest); \
+ tmp2 = vec_perm(a, edges, align); \
+ tmp1 = vec_perm(edges, a, align); \
+ vec_st(tmp2, 15, dest); \
+ vec_st(tmp1, 0 , dest); \
+ }
+#else
+#define avg_unligned_store(s, dest){ \
+ a = vec_avg(vec_vsx_ld(0, dst), s); \
+ vec_vsx_st(a, 0, dst); \
+ }
+#endif /* HAVE_BIGENDIAN */
+
static inline void avg_pixels16_l2_altivec( uint8_t * dst, const uint8_t * src1,
const uint8_t * src2, int dst_stride,
int src_stride1, int h)
{
int i;
- vec_u8 a, b, d, tmp1, tmp2, mask, mask_, edges, align;
+ vec_u8 a, b, d, mask_;
+#if HAVE_BIGENDIAN
+ vec_u8 tmp1, tmp2, mask, edges, align;
mask_ = vec_lvsl(0, src2);
+#endif
for (i = 0; i < h; i++) {
-
- tmp1 = vec_ld(i * src_stride1, src1);
- mask = vec_lvsl(i * src_stride1, src1);
- tmp2 = vec_ld(i * src_stride1 + 15, src1);
-
- a = vec_perm(tmp1, tmp2, mask);
-
- tmp1 = vec_ld(i * 16, src2);
- tmp2 = vec_ld(i * 16 + 15, src2);
-
- b = vec_perm(tmp1, tmp2, mask_);
-
- tmp1 = vec_ld(0, dst);
- mask = vec_lvsl(0, dst);
- tmp2 = vec_ld(15, dst);
-
- d = vec_avg(vec_perm(tmp1, tmp2, mask), vec_avg(a, b));
-
- edges = vec_perm(tmp2, tmp1, mask);
-
- align = vec_lvsr(0, dst);
-
- tmp2 = vec_perm(d, edges, align);
- tmp1 = vec_perm(edges, d, align);
-
- vec_st(tmp2, 15, dst);
- vec_st(tmp1, 0 , dst);
-
+ a = unaligned_load(i * src_stride1, src1);
+ b = load_with_perm_vec(i * 16, src2, mask_);
+ d = vec_avg(a, b);
+ avg_unligned_store(d, dst);
dst += dst_stride;
}
}
diff --git a/libavcodec/ppc/h264qpel_template.c b/libavcodec/ppc/h264qpel_template.c
index fe83146e63..5ff72e32f0 100644
--- a/libavcodec/ppc/h264qpel_template.c
+++ b/libavcodec/ppc/h264qpel_template.c
@@ -1,30 +1,104 @@
/*
* Copyright (c) 2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "config.h"
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
-#ifdef DEBUG
-#define ASSERT_ALIGNED(ptr) assert(((unsigned long)ptr&0x0000000F));
+#include "libavutil/avassert.h"
+#include "libavutil/mem.h"
+#include "libavutil/ppc/types_altivec.h"
+#include "libavutil/ppc/util_altivec.h"
+
+#define ASSERT_ALIGNED(ptr) av_assert2(!((uintptr_t)ptr&0x0000000F));
+
+#if HAVE_BIGENDIAN
+#define load_alignment(s, ali, pm2, pm1, pp0, pp1, pp2, pp3){\
+ vec_u8 srcR1 = vec_ld(-2, s);\
+ vec_u8 srcR2 = vec_ld(14, s);\
+ switch (ali) {\
+ default: {\
+ srcM2 = vec_perm(srcR1, srcR2, pm2);\
+ srcM1 = vec_perm(srcR1, srcR2, pm1);\
+ srcP0 = vec_perm(srcR1, srcR2, pp0);\
+ srcP1 = vec_perm(srcR1, srcR2, pp1);\
+ srcP2 = vec_perm(srcR1, srcR2, pp2);\
+ srcP3 = vec_perm(srcR1, srcR2, pp3);\
+ } break;\
+ case 11: {\
+ srcM2 = vec_perm(srcR1, srcR2, pm2);\
+ srcM1 = vec_perm(srcR1, srcR2, pm1);\
+ srcP0 = vec_perm(srcR1, srcR2, pp0);\
+ srcP1 = vec_perm(srcR1, srcR2, pp1);\
+ srcP2 = vec_perm(srcR1, srcR2, pp2);\
+ srcP3 = srcR2;\
+ } break;\
+ case 12: {\
+ vec_u8 srcR3 = vec_ld(30, s);\
+ srcM2 = vec_perm(srcR1, srcR2, pm2);\
+ srcM1 = vec_perm(srcR1, srcR2, pm1);\
+ srcP0 = vec_perm(srcR1, srcR2, pp0);\
+ srcP1 = vec_perm(srcR1, srcR2, pp1);\
+ srcP2 = srcR2;\
+ srcP3 = vec_perm(srcR2, srcR3, pp3);\
+ } break;\
+ case 13: {\
+ vec_u8 srcR3 = vec_ld(30, s);\
+ srcM2 = vec_perm(srcR1, srcR2, pm2);\
+ srcM1 = vec_perm(srcR1, srcR2, pm1);\
+ srcP0 = vec_perm(srcR1, srcR2, pp0);\
+ srcP1 = srcR2;\
+ srcP2 = vec_perm(srcR2, srcR3, pp2);\
+ srcP3 = vec_perm(srcR2, srcR3, pp3);\
+ } break;\
+ case 14: {\
+ vec_u8 srcR3 = vec_ld(30, s);\
+ srcM2 = vec_perm(srcR1, srcR2, pm2);\
+ srcM1 = vec_perm(srcR1, srcR2, pm1);\
+ srcP0 = srcR2;\
+ srcP1 = vec_perm(srcR2, srcR3, pp1);\
+ srcP2 = vec_perm(srcR2, srcR3, pp2);\
+ srcP3 = vec_perm(srcR2, srcR3, pp3);\
+ } break;\
+ case 15: {\
+ vec_u8 srcR3 = vec_ld(30, s);\
+ srcM2 = vec_perm(srcR1, srcR2, pm2);\
+ srcM1 = srcR2;\
+ srcP0 = vec_perm(srcR2, srcR3, pp0);\
+ srcP1 = vec_perm(srcR2, srcR3, pp1);\
+ srcP2 = vec_perm(srcR2, srcR3, pp2);\
+ srcP3 = vec_perm(srcR2, srcR3, pp3);\
+ } break;\
+ }\
+ }
#else
-#define ASSERT_ALIGNED(ptr) ;
-#endif
+#define load_alignment(s, ali, pm2, pm1, pp0, pp1, pp2, pp3){\
+ srcM2 = vec_vsx_ld(-2, s);\
+ srcM1 = vec_vsx_ld(-1, s);\
+ srcP0 = vec_vsx_ld(0, s);\
+ srcP1 = vec_vsx_ld(1, s);\
+ srcP2 = vec_vsx_ld(2, s);\
+ srcP3 = vec_vsx_ld(3, s);\
+ }
+#endif /* HAVE_BIGENDIAN */
/* this code assume stride % 16 == 0 */
#ifdef PREFIX_h264_qpel16_h_lowpass_altivec
@@ -35,12 +109,7 @@ static void PREFIX_h264_qpel16_h_lowpass_altivec(uint8_t *dst,
register int i;
LOAD_ZERO;
- const vec_u8 permM2 = vec_lvsl(-2, src);
- const vec_u8 permM1 = vec_lvsl(-1, src);
- const vec_u8 permP0 = vec_lvsl(+0, src);
- const vec_u8 permP1 = vec_lvsl(+1, src);
- const vec_u8 permP2 = vec_lvsl(+2, src);
- const vec_u8 permP3 = vec_lvsl(+3, src);
+ vec_u8 permM2, permM1, permP0, permP1, permP2, permP3;
const vec_s16 v5ss = vec_splat_s16(5);
const vec_u16 v5us = vec_splat_u16(5);
const vec_s16 v20ss = vec_sl(vec_splat_s16(5),vec_splat_u16(2));
@@ -59,79 +128,32 @@ static void PREFIX_h264_qpel16_h_lowpass_altivec(uint8_t *dst,
vec_u8 sum, fsum;
+#if HAVE_BIGENDIAN
+ permM2 = vec_lvsl(-2, src);
+ permM1 = vec_lvsl(-1, src);
+ permP0 = vec_lvsl(+0, src);
+ permP1 = vec_lvsl(+1, src);
+ permP2 = vec_lvsl(+2, src);
+ permP3 = vec_lvsl(+3, src);
+#endif /* HAVE_BIGENDIAN */
+
for (i = 0 ; i < 16 ; i ++) {
- vec_u8 srcR1 = vec_ld(-2, src);
- vec_u8 srcR2 = vec_ld(14, src);
-
- switch (align) {
- default: {
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = vec_perm(srcR1, srcR2, permP1);
- srcP2 = vec_perm(srcR1, srcR2, permP2);
- srcP3 = vec_perm(srcR1, srcR2, permP3);
- } break;
- case 11: {
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = vec_perm(srcR1, srcR2, permP1);
- srcP2 = vec_perm(srcR1, srcR2, permP2);
- srcP3 = srcR2;
- } break;
- case 12: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = vec_perm(srcR1, srcR2, permP1);
- srcP2 = srcR2;
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- case 13: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = srcR2;
- srcP2 = vec_perm(srcR2, srcR3, permP2);
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- case 14: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = srcR2;
- srcP1 = vec_perm(srcR2, srcR3, permP1);
- srcP2 = vec_perm(srcR2, srcR3, permP2);
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- case 15: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = srcR2;
- srcP0 = vec_perm(srcR2, srcR3, permP0);
- srcP1 = vec_perm(srcR2, srcR3, permP1);
- srcP2 = vec_perm(srcR2, srcR3, permP2);
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- }
-
- srcP0A = (vec_s16) vec_mergeh(zero_u8v, srcP0);
- srcP0B = (vec_s16) vec_mergel(zero_u8v, srcP0);
- srcP1A = (vec_s16) vec_mergeh(zero_u8v, srcP1);
- srcP1B = (vec_s16) vec_mergel(zero_u8v, srcP1);
-
- srcP2A = (vec_s16) vec_mergeh(zero_u8v, srcP2);
- srcP2B = (vec_s16) vec_mergel(zero_u8v, srcP2);
- srcP3A = (vec_s16) vec_mergeh(zero_u8v, srcP3);
- srcP3B = (vec_s16) vec_mergel(zero_u8v, srcP3);
-
- srcM1A = (vec_s16) vec_mergeh(zero_u8v, srcM1);
- srcM1B = (vec_s16) vec_mergel(zero_u8v, srcM1);
- srcM2A = (vec_s16) vec_mergeh(zero_u8v, srcM2);
- srcM2B = (vec_s16) vec_mergel(zero_u8v, srcM2);
+ load_alignment(src, align, permM2, permM1, permP0, permP1, permP2, permP3);
+
+ srcP0A = (vec_s16) VEC_MERGEH(zero_u8v, srcP0);
+ srcP0B = (vec_s16) VEC_MERGEL(zero_u8v, srcP0);
+ srcP1A = (vec_s16) VEC_MERGEH(zero_u8v, srcP1);
+ srcP1B = (vec_s16) VEC_MERGEL(zero_u8v, srcP1);
+
+ srcP2A = (vec_s16) VEC_MERGEH(zero_u8v, srcP2);
+ srcP2B = (vec_s16) VEC_MERGEL(zero_u8v, srcP2);
+ srcP3A = (vec_s16) VEC_MERGEH(zero_u8v, srcP3);
+ srcP3B = (vec_s16) VEC_MERGEL(zero_u8v, srcP3);
+
+ srcM1A = (vec_s16) VEC_MERGEH(zero_u8v, srcM1);
+ srcM1B = (vec_s16) VEC_MERGEL(zero_u8v, srcM1);
+ srcM2A = (vec_s16) VEC_MERGEH(zero_u8v, srcM2);
+ srcM2B = (vec_s16) VEC_MERGEL(zero_u8v, srcM2);
sum1A = vec_adds(srcP0A, srcP1A);
sum1B = vec_adds(srcP0B, srcP1B);
@@ -178,7 +200,10 @@ static void PREFIX_h264_qpel16_v_lowpass_altivec(uint8_t *dst,
register int i;
LOAD_ZERO;
- const vec_u8 perm = vec_lvsl(0, src);
+ vec_u8 perm;
+#if HAVE_BIGENDIAN
+ perm = vec_lvsl(0, src);
+#endif
const vec_s16 v20ss = vec_sl(vec_splat_s16(5),vec_splat_u16(2));
const vec_u16 v5us = vec_splat_u16(5);
const vec_s16 v5ss = vec_splat_s16(5);
@@ -186,52 +211,41 @@ static void PREFIX_h264_qpel16_v_lowpass_altivec(uint8_t *dst,
const uint8_t *srcbis = src - (srcStride * 2);
- const vec_u8 srcM2a = vec_ld(0, srcbis);
- const vec_u8 srcM2b = vec_ld(16, srcbis);
- const vec_u8 srcM2 = vec_perm(srcM2a, srcM2b, perm);
- //srcbis += srcStride;
- const vec_u8 srcM1a = vec_ld(0, srcbis += srcStride);
- const vec_u8 srcM1b = vec_ld(16, srcbis);
- const vec_u8 srcM1 = vec_perm(srcM1a, srcM1b, perm);
- //srcbis += srcStride;
- const vec_u8 srcP0a = vec_ld(0, srcbis += srcStride);
- const vec_u8 srcP0b = vec_ld(16, srcbis);
- const vec_u8 srcP0 = vec_perm(srcP0a, srcP0b, perm);
- //srcbis += srcStride;
- const vec_u8 srcP1a = vec_ld(0, srcbis += srcStride);
- const vec_u8 srcP1b = vec_ld(16, srcbis);
- const vec_u8 srcP1 = vec_perm(srcP1a, srcP1b, perm);
- //srcbis += srcStride;
- const vec_u8 srcP2a = vec_ld(0, srcbis += srcStride);
- const vec_u8 srcP2b = vec_ld(16, srcbis);
- const vec_u8 srcP2 = vec_perm(srcP2a, srcP2b, perm);
- //srcbis += srcStride;
-
- vec_s16 srcM2ssA = (vec_s16) vec_mergeh(zero_u8v, srcM2);
- vec_s16 srcM2ssB = (vec_s16) vec_mergel(zero_u8v, srcM2);
- vec_s16 srcM1ssA = (vec_s16) vec_mergeh(zero_u8v, srcM1);
- vec_s16 srcM1ssB = (vec_s16) vec_mergel(zero_u8v, srcM1);
- vec_s16 srcP0ssA = (vec_s16) vec_mergeh(zero_u8v, srcP0);
- vec_s16 srcP0ssB = (vec_s16) vec_mergel(zero_u8v, srcP0);
- vec_s16 srcP1ssA = (vec_s16) vec_mergeh(zero_u8v, srcP1);
- vec_s16 srcP1ssB = (vec_s16) vec_mergel(zero_u8v, srcP1);
- vec_s16 srcP2ssA = (vec_s16) vec_mergeh(zero_u8v, srcP2);
- vec_s16 srcP2ssB = (vec_s16) vec_mergel(zero_u8v, srcP2);
+ const vec_u8 srcM2 = load_with_perm_vec(0, srcbis, perm);
+ srcbis += srcStride;
+ const vec_u8 srcM1 = load_with_perm_vec(0, srcbis, perm);
+ srcbis += srcStride;
+ const vec_u8 srcP0 = load_with_perm_vec(0, srcbis, perm);
+ srcbis += srcStride;
+ const vec_u8 srcP1 = load_with_perm_vec(0, srcbis, perm);
+ srcbis += srcStride;
+ const vec_u8 srcP2 = load_with_perm_vec(0, srcbis, perm);
+ srcbis += srcStride;
+
+ vec_s16 srcM2ssA = (vec_s16) VEC_MERGEH(zero_u8v, srcM2);
+ vec_s16 srcM2ssB = (vec_s16) VEC_MERGEL(zero_u8v, srcM2);
+ vec_s16 srcM1ssA = (vec_s16) VEC_MERGEH(zero_u8v, srcM1);
+ vec_s16 srcM1ssB = (vec_s16) VEC_MERGEL(zero_u8v, srcM1);
+ vec_s16 srcP0ssA = (vec_s16) VEC_MERGEH(zero_u8v, srcP0);
+ vec_s16 srcP0ssB = (vec_s16) VEC_MERGEL(zero_u8v, srcP0);
+ vec_s16 srcP1ssA = (vec_s16) VEC_MERGEH(zero_u8v, srcP1);
+ vec_s16 srcP1ssB = (vec_s16) VEC_MERGEL(zero_u8v, srcP1);
+ vec_s16 srcP2ssA = (vec_s16) VEC_MERGEH(zero_u8v, srcP2);
+ vec_s16 srcP2ssB = (vec_s16) VEC_MERGEL(zero_u8v, srcP2);
vec_s16 pp1A, pp1B, pp2A, pp2B, pp3A, pp3B,
psumA, psumB, sumA, sumB,
srcP3ssA, srcP3ssB,
sum1A, sum1B, sum2A, sum2B, sum3A, sum3B;
- vec_u8 sum, fsum, srcP3a, srcP3b, srcP3;
+ vec_u8 sum, fsum, srcP3;
for (i = 0 ; i < 16 ; i++) {
- srcP3a = vec_ld(0, srcbis += srcStride);
- srcP3b = vec_ld(16, srcbis);
- srcP3 = vec_perm(srcP3a, srcP3b, perm);
- srcP3ssA = (vec_s16) vec_mergeh(zero_u8v, srcP3);
- srcP3ssB = (vec_s16) vec_mergel(zero_u8v, srcP3);
- //srcbis += srcStride;
+ srcP3 = load_with_perm_vec(0, srcbis, perm);
+ srcbis += srcStride;
+
+ srcP3ssA = (vec_s16) VEC_MERGEH(zero_u8v, srcP3);
+ srcP3ssB = (vec_s16) VEC_MERGEL(zero_u8v, srcP3);
sum1A = vec_adds(srcP0ssA, srcP1ssA);
sum1B = vec_adds(srcP0ssB, srcP1ssB);
@@ -288,12 +302,7 @@ static void PREFIX_h264_qpel16_hv_lowpass_altivec(uint8_t *dst, int16_t *tmp,
{
register int i;
LOAD_ZERO;
- const vec_u8 permM2 = vec_lvsl(-2, src);
- const vec_u8 permM1 = vec_lvsl(-1, src);
- const vec_u8 permP0 = vec_lvsl(+0, src);
- const vec_u8 permP1 = vec_lvsl(+1, src);
- const vec_u8 permP2 = vec_lvsl(+2, src);
- const vec_u8 permP3 = vec_lvsl(+3, src);
+ vec_u8 permM2, permM1, permP0, permP1, permP2, permP3;
const vec_s16 v20ss = vec_sl(vec_splat_s16(5),vec_splat_u16(2));
const vec_u32 v10ui = vec_splat_u32(10);
const vec_s16 v5ss = vec_splat_s16(5);
@@ -325,81 +334,35 @@ static void PREFIX_h264_qpel16_hv_lowpass_altivec(uint8_t *dst, int16_t *tmp,
vec_u8 fsum, sumv, sum;
vec_s16 ssume, ssumo;
+#if HAVE_BIGENDIAN
+ permM2 = vec_lvsl(-2, src);
+ permM1 = vec_lvsl(-1, src);
+ permP0 = vec_lvsl(+0, src);
+ permP1 = vec_lvsl(+1, src);
+ permP2 = vec_lvsl(+2, src);
+ permP3 = vec_lvsl(+3, src);
+#endif /* HAVE_BIGENDIAN */
+
src -= (2 * srcStride);
for (i = 0 ; i < 21 ; i ++) {
vec_u8 srcM2, srcM1, srcP0, srcP1, srcP2, srcP3;
- vec_u8 srcR1 = vec_ld(-2, src);
- vec_u8 srcR2 = vec_ld(14, src);
-
- switch (align) {
- default: {
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = vec_perm(srcR1, srcR2, permP1);
- srcP2 = vec_perm(srcR1, srcR2, permP2);
- srcP3 = vec_perm(srcR1, srcR2, permP3);
- } break;
- case 11: {
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = vec_perm(srcR1, srcR2, permP1);
- srcP2 = vec_perm(srcR1, srcR2, permP2);
- srcP3 = srcR2;
- } break;
- case 12: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = vec_perm(srcR1, srcR2, permP1);
- srcP2 = srcR2;
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- case 13: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = vec_perm(srcR1, srcR2, permP0);
- srcP1 = srcR2;
- srcP2 = vec_perm(srcR2, srcR3, permP2);
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- case 14: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = vec_perm(srcR1, srcR2, permM1);
- srcP0 = srcR2;
- srcP1 = vec_perm(srcR2, srcR3, permP1);
- srcP2 = vec_perm(srcR2, srcR3, permP2);
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- case 15: {
- vec_u8 srcR3 = vec_ld(30, src);
- srcM2 = vec_perm(srcR1, srcR2, permM2);
- srcM1 = srcR2;
- srcP0 = vec_perm(srcR2, srcR3, permP0);
- srcP1 = vec_perm(srcR2, srcR3, permP1);
- srcP2 = vec_perm(srcR2, srcR3, permP2);
- srcP3 = vec_perm(srcR2, srcR3, permP3);
- } break;
- }
-
- srcP0A = (vec_s16) vec_mergeh(zero_u8v, srcP0);
- srcP0B = (vec_s16) vec_mergel(zero_u8v, srcP0);
- srcP1A = (vec_s16) vec_mergeh(zero_u8v, srcP1);
- srcP1B = (vec_s16) vec_mergel(zero_u8v, srcP1);
-
- srcP2A = (vec_s16) vec_mergeh(zero_u8v, srcP2);
- srcP2B = (vec_s16) vec_mergel(zero_u8v, srcP2);
- srcP3A = (vec_s16) vec_mergeh(zero_u8v, srcP3);
- srcP3B = (vec_s16) vec_mergel(zero_u8v, srcP3);
-
- srcM1A = (vec_s16) vec_mergeh(zero_u8v, srcM1);
- srcM1B = (vec_s16) vec_mergel(zero_u8v, srcM1);
- srcM2A = (vec_s16) vec_mergeh(zero_u8v, srcM2);
- srcM2B = (vec_s16) vec_mergel(zero_u8v, srcM2);
+
+ load_alignment(src, align, permM2, permM1, permP0, permP1, permP2, permP3);
+
+ srcP0A = (vec_s16) VEC_MERGEH(zero_u8v, srcP0);
+ srcP0B = (vec_s16) VEC_MERGEL(zero_u8v, srcP0);
+ srcP1A = (vec_s16) VEC_MERGEH(zero_u8v, srcP1);
+ srcP1B = (vec_s16) VEC_MERGEL(zero_u8v, srcP1);
+
+ srcP2A = (vec_s16) VEC_MERGEH(zero_u8v, srcP2);
+ srcP2B = (vec_s16) VEC_MERGEL(zero_u8v, srcP2);
+ srcP3A = (vec_s16) VEC_MERGEH(zero_u8v, srcP3);
+ srcP3B = (vec_s16) VEC_MERGEL(zero_u8v, srcP3);
+
+ srcM1A = (vec_s16) VEC_MERGEH(zero_u8v, srcM1);
+ srcM1B = (vec_s16) VEC_MERGEL(zero_u8v, srcM1);
+ srcM2A = (vec_s16) VEC_MERGEH(zero_u8v, srcM2);
+ srcM2B = (vec_s16) VEC_MERGEL(zero_u8v, srcM2);
sum1A = vec_adds(srcP0A, srcP1A);
sum1B = vec_adds(srcP0B, srcP1B);
@@ -448,8 +411,8 @@ static void PREFIX_h264_qpel16_hv_lowpass_altivec(uint8_t *dst, int16_t *tmp,
const vec_s16 sum1B = vec_adds(tmpP0ssB, tmpP1ssB);
const vec_s16 sum2A = vec_adds(tmpM1ssA, tmpP2ssA);
const vec_s16 sum2B = vec_adds(tmpM1ssB, tmpP2ssB);
- const vec_s16 sum3A = vec_adds(tmpM2ssA, tmpP3ssA);
- const vec_s16 sum3B = vec_adds(tmpM2ssB, tmpP3ssB);
+ vec_s16 sum3A = vec_adds(tmpM2ssA, tmpP3ssA);
+ vec_s16 sum3B = vec_adds(tmpM2ssB, tmpP3ssB);
tmpbis += tmpStride;
@@ -474,10 +437,14 @@ static void PREFIX_h264_qpel16_hv_lowpass_altivec(uint8_t *dst, int16_t *tmp,
pp2Be = vec_mule(sum2B, v5ss);
pp2Bo = vec_mulo(sum2B, v5ss);
- pp3Ae = vec_sra((vec_s32)sum3A, v16ui);
pp3Ao = vec_mulo(sum3A, v1ss);
- pp3Be = vec_sra((vec_s32)sum3B, v16ui);
pp3Bo = vec_mulo(sum3B, v1ss);
+#if !HAVE_BIGENDIAN
+ sum3A = (vec_s16)vec_perm(sum3A, sum3A,vcswapi2s(0,1,2,3));
+ sum3B = (vec_s16)vec_perm(sum3B, sum3B,vcswapi2s(0,1,2,3));
+#endif
+ pp3Ae = vec_sra((vec_s32)sum3A, v16ui);
+ pp3Be = vec_sra((vec_s32)sum3B, v16ui);
pp1cAe = vec_add(pp1Ae, v512si);
pp1cAo = vec_add(pp1Ao, v512si);
diff --git a/libavcodec/ppc/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c
index fd6ae73915..87a1f05b6a 100644
--- a/libavcodec/ppc/hpeldsp_altivec.c
+++ b/libavcodec/ppc/hpeldsp_altivec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Dieter Shirley
* Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,12 +38,11 @@
/* next one assumes that ((line_size % 16) == 0) */
void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
{
- register vector unsigned char pixelsv1, pixelsv2;
- register vector unsigned char pixelsv1B, pixelsv2B;
- register vector unsigned char pixelsv1C, pixelsv2C;
- register vector unsigned char pixelsv1D, pixelsv2D;
+ register vector unsigned char pixelsv1;
+ register vector unsigned char pixelsv1B;
+ register vector unsigned char pixelsv1C;
+ register vector unsigned char pixelsv1D;
- register vector unsigned char perm = vec_lvsl(0, pixels);
int i;
register ptrdiff_t line_size_2 = line_size << 1;
register ptrdiff_t line_size_3 = line_size + line_size_2;
@@ -55,22 +54,14 @@ void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li
// -funroll-loops w/ this is bad - 74 cycles again.
// all this is on a 7450, tuning for the 7450
for (i = 0; i < h; i += 4) {
- pixelsv1 = vec_ld( 0, pixels);
- pixelsv2 = vec_ld(15, pixels);
- pixelsv1B = vec_ld(line_size, pixels);
- pixelsv2B = vec_ld(15 + line_size, pixels);
- pixelsv1C = vec_ld(line_size_2, pixels);
- pixelsv2C = vec_ld(15 + line_size_2, pixels);
- pixelsv1D = vec_ld(line_size_3, pixels);
- pixelsv2D = vec_ld(15 + line_size_3, pixels);
- vec_st(vec_perm(pixelsv1, pixelsv2, perm),
- 0, (unsigned char*)block);
- vec_st(vec_perm(pixelsv1B, pixelsv2B, perm),
- line_size, (unsigned char*)block);
- vec_st(vec_perm(pixelsv1C, pixelsv2C, perm),
- line_size_2, (unsigned char*)block);
- vec_st(vec_perm(pixelsv1D, pixelsv2D, perm),
- line_size_3, (unsigned char*)block);
+ pixelsv1 = unaligned_load( 0, pixels);
+ pixelsv1B = unaligned_load(line_size, pixels);
+ pixelsv1C = unaligned_load(line_size_2, pixels);
+ pixelsv1D = unaligned_load(line_size_3, pixels);
+ VEC_ST(pixelsv1, 0, (unsigned char*)block);
+ VEC_ST(pixelsv1B, line_size, (unsigned char*)block);
+ VEC_ST(pixelsv1C, line_size_2, (unsigned char*)block);
+ VEC_ST(pixelsv1D, line_size_3, (unsigned char*)block);
pixels+=line_size_4;
block +=line_size_4;
}
@@ -80,15 +71,12 @@ void ff_put_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li
#define op_avg(a,b) a = ( ((a)|(b)) - ((((a)^(b))&0xFEFEFEFEUL)>>1) )
void ff_avg_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
{
- register vector unsigned char pixelsv1, pixelsv2, pixelsv, blockv;
- register vector unsigned char perm = vec_lvsl(0, pixels);
- int i;
+ register vector unsigned char pixelsv, blockv;
+ int i;
for (i = 0; i < h; i++) {
- pixelsv1 = vec_ld( 0, pixels);
- pixelsv2 = vec_ld(16,pixels);
blockv = vec_ld(0, block);
- pixelsv = vec_perm(pixelsv1, pixelsv2, perm);
+ pixelsv = VEC_LD( 0, pixels);
blockv = vec_avg(blockv,pixelsv);
vec_st(blockv, 0, (unsigned char*)block);
pixels+=line_size;
@@ -108,9 +96,7 @@ static void avg_pixels8_altivec(uint8_t * block, const uint8_t * pixels, ptrdiff
int rightside = ((unsigned long)block & 0x0000000F);
blockv = vec_ld(0, block);
- pixelsv1 = vec_ld( 0, pixels);
- pixelsv2 = vec_ld(16, pixels);
- pixelsv = vec_perm(pixelsv1, pixelsv2, vec_lvsl(0, pixels));
+ pixelsv = VEC_LD( 0, pixels);
if (rightside) {
pixelsv = vec_perm(blockv, pixelsv, vcprm(0,1,s0,s1));
@@ -132,21 +118,16 @@ static void put_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdi
{
register int i;
register vector unsigned char pixelsv1, pixelsv2, pixelsavg;
- register vector unsigned char blockv, temp1, temp2;
+ register vector unsigned char blockv;
register vector unsigned short pixelssum1, pixelssum2, temp3;
register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
- temp1 = vec_ld(0, pixels);
- temp2 = vec_ld(16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
- if ((((unsigned long)pixels) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
- }
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = VEC_LD(0, pixels);
+ pixelsv2 = VEC_LD(1, pixels);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
+
pixelssum1 = vec_add((vector unsigned short)pixelsv1,
(vector unsigned short)pixelsv2);
pixelssum1 = vec_add(pixelssum1, vctwo);
@@ -155,17 +136,10 @@ static void put_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdi
int rightside = ((unsigned long)block & 0x0000000F);
blockv = vec_ld(0, block);
- temp1 = vec_ld(line_size, pixels);
- temp2 = vec_ld(line_size + 16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
- if (((((unsigned long)pixels) + line_size) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
- }
-
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = unaligned_load(line_size, pixels);
+ pixelsv2 = unaligned_load(line_size+1, pixels);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum2 = vec_add((vector unsigned short)pixelsv1,
(vector unsigned short)pixelsv2);
temp3 = vec_add(pixelssum1, pixelssum2);
@@ -191,22 +165,16 @@ static void put_no_rnd_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels
{
register int i;
register vector unsigned char pixelsv1, pixelsv2, pixelsavg;
- register vector unsigned char blockv, temp1, temp2;
+ register vector unsigned char blockv;
register vector unsigned short pixelssum1, pixelssum2, temp3;
register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
register const vector unsigned short vcone = (const vector unsigned short)vec_splat_u16(1);
register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
- temp1 = vec_ld(0, pixels);
- temp2 = vec_ld(16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
- if ((((unsigned long)pixels) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
- }
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = VEC_LD(0, pixels);
+ pixelsv2 = VEC_LD(1, pixels);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum1 = vec_add((vector unsigned short)pixelsv1,
(vector unsigned short)pixelsv2);
pixelssum1 = vec_add(pixelssum1, vcone);
@@ -215,17 +183,10 @@ static void put_no_rnd_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels
int rightside = ((unsigned long)block & 0x0000000F);
blockv = vec_ld(0, block);
- temp1 = vec_ld(line_size, pixels);
- temp2 = vec_ld(line_size + 16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
- if (((((unsigned long)pixels) + line_size) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
- }
-
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = unaligned_load(line_size, pixels);
+ pixelsv2 = unaligned_load(line_size+1, pixels);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum2 = vec_add((vector unsigned short)pixelsv1,
(vector unsigned short)pixelsv2);
temp3 = vec_add(pixelssum1, pixelssum2);
@@ -251,24 +212,18 @@ static void put_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pixels, pt
{
register int i;
register vector unsigned char pixelsv1, pixelsv2, pixelsv3, pixelsv4;
- register vector unsigned char blockv, temp1, temp2;
+ register vector unsigned char blockv;
register vector unsigned short temp3, temp4,
pixelssum1, pixelssum2, pixelssum3, pixelssum4;
register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
- temp1 = vec_ld(0, pixels);
- temp2 = vec_ld(16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
- if ((((unsigned long)pixels) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
- }
- pixelsv3 = vec_mergel(vczero, pixelsv1);
- pixelsv4 = vec_mergel(vczero, pixelsv2);
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = VEC_LD(0, pixels);
+ pixelsv2 = VEC_LD(1, pixels);
+ pixelsv3 = VEC_MERGEL(vczero, pixelsv1);
+ pixelsv4 = VEC_MERGEL(vczero, pixelsv2);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum3 = vec_add((vector unsigned short)pixelsv3,
(vector unsigned short)pixelsv4);
pixelssum3 = vec_add(pixelssum3, vctwo);
@@ -279,20 +234,13 @@ static void put_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pixels, pt
for (i = 0; i < h ; i++) {
blockv = vec_ld(0, block);
- temp1 = vec_ld(line_size, pixels);
- temp2 = vec_ld(line_size + 16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
- if (((((unsigned long)pixels) + line_size) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
- }
-
- pixelsv3 = vec_mergel(vczero, pixelsv1);
- pixelsv4 = vec_mergel(vczero, pixelsv2);
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = unaligned_load(line_size, pixels);
+ pixelsv2 = unaligned_load(line_size+1, pixels);
+ pixelsv3 = VEC_MERGEL(vczero, pixelsv1);
+ pixelsv4 = VEC_MERGEL(vczero, pixelsv2);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum4 = vec_add((vector unsigned short)pixelsv3,
(vector unsigned short)pixelsv4);
pixelssum2 = vec_add((vector unsigned short)pixelsv1,
@@ -319,25 +267,19 @@ static void put_no_rnd_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pix
{
register int i;
register vector unsigned char pixelsv1, pixelsv2, pixelsv3, pixelsv4;
- register vector unsigned char blockv, temp1, temp2;
+ register vector unsigned char blockv;
register vector unsigned short temp3, temp4,
pixelssum1, pixelssum2, pixelssum3, pixelssum4;
register const vector unsigned char vczero = (const vector unsigned char)vec_splat_u8(0);
register const vector unsigned short vcone = (const vector unsigned short)vec_splat_u16(1);
register const vector unsigned short vctwo = (const vector unsigned short)vec_splat_u16(2);
- temp1 = vec_ld(0, pixels);
- temp2 = vec_ld(16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
- if ((((unsigned long)pixels) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
- }
- pixelsv3 = vec_mergel(vczero, pixelsv1);
- pixelsv4 = vec_mergel(vczero, pixelsv2);
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = VEC_LD(0, pixels);
+ pixelsv2 = VEC_LD(1, pixels);
+ pixelsv3 = VEC_MERGEL(vczero, pixelsv1);
+ pixelsv4 = VEC_MERGEL(vczero, pixelsv2);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum3 = vec_add((vector unsigned short)pixelsv3,
(vector unsigned short)pixelsv4);
pixelssum3 = vec_add(pixelssum3, vcone);
@@ -346,22 +288,13 @@ static void put_no_rnd_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pix
pixelssum1 = vec_add(pixelssum1, vcone);
for (i = 0; i < h ; i++) {
- blockv = vec_ld(0, block);
-
- temp1 = vec_ld(line_size, pixels);
- temp2 = vec_ld(line_size + 16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
- if (((((unsigned long)pixels) + line_size) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
- }
-
- pixelsv3 = vec_mergel(vczero, pixelsv1);
- pixelsv4 = vec_mergel(vczero, pixelsv2);
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = unaligned_load(line_size, pixels);
+ pixelsv2 = unaligned_load(line_size+1, pixels);
+ pixelsv3 = VEC_MERGEL(vczero, pixelsv1);
+ pixelsv4 = VEC_MERGEL(vczero, pixelsv2);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum4 = vec_add((vector unsigned short)pixelsv3,
(vector unsigned short)pixelsv4);
pixelssum2 = vec_add((vector unsigned short)pixelsv1,
@@ -376,7 +309,7 @@ static void put_no_rnd_pixels16_xy2_altivec(uint8_t * block, const uint8_t * pix
blockv = vec_packsu(temp3, temp4);
- vec_st(blockv, 0, block);
+ VEC_ST(blockv, 0, block);
block += line_size;
pixels += line_size;
@@ -388,7 +321,7 @@ static void avg_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdi
{
register int i;
register vector unsigned char pixelsv1, pixelsv2, pixelsavg;
- register vector unsigned char blockv, temp1, temp2, blocktemp;
+ register vector unsigned char blockv, blocktemp;
register vector unsigned short pixelssum1, pixelssum2, temp3;
register const vector unsigned char vczero = (const vector unsigned char)
@@ -396,16 +329,10 @@ static void avg_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdi
register const vector unsigned short vctwo = (const vector unsigned short)
vec_splat_u16(2);
- temp1 = vec_ld(0, pixels);
- temp2 = vec_ld(16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(0, pixels));
- if ((((unsigned long)pixels) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(1, pixels));
- }
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = VEC_LD(0, pixels);
+ pixelsv2 = VEC_LD(1, pixels);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum1 = vec_add((vector unsigned short)pixelsv1,
(vector unsigned short)pixelsv2);
pixelssum1 = vec_add(pixelssum1, vctwo);
@@ -414,17 +341,11 @@ static void avg_pixels8_xy2_altivec(uint8_t *block, const uint8_t *pixels, ptrdi
int rightside = ((unsigned long)block & 0x0000000F);
blockv = vec_ld(0, block);
- temp1 = vec_ld(line_size, pixels);
- temp2 = vec_ld(line_size + 16, pixels);
- pixelsv1 = vec_perm(temp1, temp2, vec_lvsl(line_size, pixels));
- if (((((unsigned long)pixels) + line_size) & 0x0000000F) == 0x0000000F) {
- pixelsv2 = temp2;
- } else {
- pixelsv2 = vec_perm(temp1, temp2, vec_lvsl(line_size + 1, pixels));
- }
+ pixelsv1 = unaligned_load(line_size, pixels);
+ pixelsv2 = unaligned_load(line_size+1, pixels);
- pixelsv1 = vec_mergeh(vczero, pixelsv1);
- pixelsv2 = vec_mergeh(vczero, pixelsv2);
+ pixelsv1 = VEC_MERGEH(vczero, pixelsv1);
+ pixelsv2 = VEC_MERGEH(vczero, pixelsv2);
pixelssum2 = vec_add((vector unsigned short)pixelsv1,
(vector unsigned short)pixelsv2);
temp3 = vec_add(pixelssum1, pixelssum2);
diff --git a/libavcodec/ppc/hpeldsp_altivec.h b/libavcodec/ppc/hpeldsp_altivec.h
index 98dd80ea1c..590809f539 100644
--- a/libavcodec/ppc/hpeldsp_altivec.h
+++ b/libavcodec/ppc/hpeldsp_altivec.h
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Dieter Shirley
* Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/huffyuvdsp_altivec.c b/libavcodec/ppc/huffyuvdsp_altivec.c
index 7c34a67ea4..6701524e4a 100644
--- a/libavcodec/ppc/huffyuvdsp_altivec.c
+++ b/libavcodec/ppc/huffyuvdsp_altivec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Dieter Shirley
* Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,7 @@
#include "libavcodec/huffyuvdsp.h"
#if HAVE_ALTIVEC
-static void add_bytes_altivec(uint8_t *dst, uint8_t *src, int w)
+static void add_bytes_altivec(uint8_t *dst, uint8_t *src, intptr_t w)
{
register int i;
register vector unsigned char vdst, vsrc;
diff --git a/libavcodec/ppc/idctdsp.c b/libavcodec/ppc/idctdsp.c
index 17f7dbbc7f..ea56a70948 100644
--- a/libavcodec/ppc/idctdsp.c
+++ b/libavcodec/ppc/idctdsp.c
@@ -1,28 +1,28 @@
/*
* Copyright (c) 2001 Michel Lespinasse
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* NOTE: This code is based on GPL code from the libmpeg2 project. The
* author, Michel Lespinasses, has given explicit permission to release
- * under LGPL as part of Libav.
+ * under LGPL as part of FFmpeg.
*
- * Libav integration by Dieter Shirley
+ * FFmpeg integration by Dieter Shirley
*
* This file is a direct copy of the AltiVec IDCT module from the libmpeg2
* project. I've deleted all of the libmpeg2-specific code, renamed the
@@ -153,6 +153,22 @@ static const vec_s16 constants[5] = {
{ 19266, 26722, 25172, 22654, 19266, 22654, 25172, 26722 }
};
+static void idct_altivec(int16_t *blk)
+{
+ vec_s16 *block = (vec_s16 *) blk;
+
+ IDCT;
+
+ block[0] = vx0;
+ block[1] = vx1;
+ block[2] = vx2;
+ block[3] = vx3;
+ block[4] = vx4;
+ block[5] = vx5;
+ block[6] = vx6;
+ block[7] = vx7;
+}
+
static void idct_put_altivec(uint8_t *dest, int stride, int16_t *blk)
{
vec_s16 *block = (vec_s16 *) blk;
@@ -193,16 +209,26 @@ static void idct_add_altivec(uint8_t *dest, int stride, int16_t *blk)
IDCT;
+#if HAVE_BIGENDIAN
p0 = vec_lvsl(0, dest);
p1 = vec_lvsl(stride, dest);
p = vec_splat_u8(-1);
perm0 = vec_mergeh(p, p0);
perm1 = vec_mergeh(p, p1);
+#endif
-#define ADD(dest, src, perm) \
- /* *(uint64_t *) &tmp = *(uint64_t *) dest; */ \
+#if HAVE_BIGENDIAN
+#define GET_TMP2(dest, prm) \
tmp = vec_ld(0, dest); \
- tmp2 = (vec_s16) vec_perm(tmp, (vec_u8) zero, perm); \
+ tmp2 = (vec_s16) vec_perm(tmp, (vec_u8) zero, prm);
+#else
+#define GET_TMP2(dest, prm) \
+ tmp = vec_vsx_ld(0, dest); \
+ tmp2 = (vec_s16) vec_mergeh(tmp, (vec_u8) zero)
+#endif
+
+#define ADD(dest, src, perm) \
+ GET_TMP2(dest, perm); \
tmp3 = vec_adds(tmp2, src); \
tmp = vec_packsu(tmp3, tmp3); \
vec_ste((vec_u32) tmp, 0, (unsigned int *) dest); \
@@ -234,9 +260,10 @@ av_cold void ff_idctdsp_init_ppc(IDCTDSPContext *c, AVCodecContext *avctx,
if (!PPC_ALTIVEC(av_get_cpu_flags()))
return;
- if (!high_bit_depth) {
- if ((avctx->idct_algo == FF_IDCT_AUTO) ||
+ if (!high_bit_depth && avctx->lowres == 0) {
+ if ((avctx->idct_algo == FF_IDCT_AUTO && !(avctx->flags & CODEC_FLAG_BITEXACT)) ||
(avctx->idct_algo == FF_IDCT_ALTIVEC)) {
+ c->idct = idct_altivec;
c->idct_add = idct_add_altivec;
c->idct_put = idct_put_altivec;
c->perm_type = FF_IDCT_PERM_TRANSPOSE;
diff --git a/libavcodec/ppc/lossless_audiodsp_altivec.c b/libavcodec/ppc/lossless_audiodsp_altivec.c
new file mode 100644
index 0000000000..bdec25223d
--- /dev/null
+++ b/libavcodec/ppc/lossless_audiodsp_altivec.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007 Luca Barbato <lu_zero@gentoo.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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"
+#if HAVE_ALTIVEC_H
+#include <altivec.h>
+#endif
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/ppc/cpu.h"
+#include "libavutil/ppc/types_altivec.h"
+#include "libavcodec/lossless_audiodsp.h"
+
+#if HAVE_BIGENDIAN
+#define GET_T(tt0,tt1,src,a,b){ \
+ a = vec_ld(16, src); \
+ tt0 = vec_perm(b, a, align); \
+ b = vec_ld(32, src); \
+ tt1 = vec_perm(a, b, align); \
+ }
+#else
+#define GET_T(tt0,tt1,src,a,b){ \
+ tt0 = vec_vsx_ld(0, src); \
+ tt1 = vec_vsx_ld(16, src); \
+ }
+#endif
+
+#if HAVE_ALTIVEC
+static int32_t scalarproduct_and_madd_int16_altivec(int16_t *v1,
+ const int16_t *v2,
+ const int16_t *v3,
+ int order, int mul)
+{
+ LOAD_ZERO;
+ vec_s16 *pv1 = (vec_s16 *) v1;
+ register vec_s16 muls = { mul, mul, mul, mul, mul, mul, mul, mul };
+ register vec_s16 t0, t1, i0, i1, i4, i2, i3;
+ register vec_s32 res = zero_s32v;
+#if HAVE_BIGENDIAN
+ register vec_u8 align = vec_lvsl(0, v2);
+ i2 = vec_ld(0, v2);
+ i3 = vec_ld(0, v3);
+#endif
+ int32_t ires;
+
+ order >>= 4;
+ do {
+ GET_T(t0,t1,v2,i1,i2);
+ i0 = pv1[0];
+ i1 = pv1[1];
+ res = vec_msum(t0, i0, res);
+ res = vec_msum(t1, i1, res);
+ GET_T(t0,t1,v3,i4,i3);
+ pv1[0] = vec_mladd(t0, muls, i0);
+ pv1[1] = vec_mladd(t1, muls, i1);
+ pv1 += 2;
+ v2 += 16;
+ v3 += 16;
+ } while (--order);
+ res = vec_splat(vec_sums(res, zero_s32v), 3);
+ vec_ste(res, 0, &ires);
+
+ return ires;
+}
+#endif /* HAVE_ALTIVEC */
+
+av_cold void ff_llauddsp_init_ppc(LLAudDSPContext *c)
+{
+#if HAVE_ALTIVEC
+ if (!PPC_ALTIVEC(av_get_cpu_flags()))
+ return;
+
+ c->scalarproduct_and_madd_int16 = scalarproduct_and_madd_int16_altivec;
+#endif /* HAVE_ALTIVEC */
+}
diff --git a/libavcodec/ppc/mathops.h b/libavcodec/ppc/mathops.h
index 34ddb11800..dbd714fcd4 100644
--- a/libavcodec/ppc/mathops.h
+++ b/libavcodec/ppc/mathops.h
@@ -3,20 +3,20 @@
* Copyright (c) 2001, 2002 Fabrice Bellard
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/me_cmp.c b/libavcodec/ppc/me_cmp.c
index fd67cf34ee..38a7ba1476 100644
--- a/libavcodec/ppc/me_cmp.c
+++ b/libavcodec/ppc/me_cmp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Dieter Shirley
* Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,26 +35,43 @@
#include "libavcodec/me_cmp.h"
#if HAVE_ALTIVEC
+
+#if HAVE_BIGENDIAN
+#define GET_PERM(per1, per2, pix) {\
+ per1 = vec_lvsl(0, pix);\
+ per2 = vec_add(per1, vec_splat_u8(1));\
+}
+#define LOAD_PIX(v, iv, pix, per1, per2) {\
+ vector unsigned char pix2l = vec_ld(0, pix);\
+ vector unsigned char pix2r = vec_ld(16, pix);\
+ v = vec_perm(pix2l, pix2r, per1);\
+ iv = vec_perm(pix2l, pix2r, per2);\
+}
+#else
+#define GET_PERM(per1, per2, pix) {}
+#define LOAD_PIX(v, iv, pix, per1, per2) {\
+ v = vec_vsx_ld(0, pix);\
+ iv = vec_vsx_ld(1, pix);\
+}
+#endif
static int sad16_x2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s = 0;
+ int i;
+ int __attribute__((aligned(16))) s = 0;
const vector unsigned char zero =
(const vector unsigned char) vec_splat_u8(0);
- vector unsigned char perm1 = vec_lvsl(0, pix2);
- vector unsigned char perm2 = vec_add(perm1, vec_splat_u8(1));
vector unsigned int sad = (vector unsigned int) vec_splat_u32(0);
vector signed int sumdiffs;
+ vector unsigned char perm1, perm2, pix2v, pix2iv;
+ GET_PERM(perm1, perm2, pix2);
for (i = 0; i < h; i++) {
/* Read unaligned pixels into our vectors. The vectors are as follows:
* pix1v: pix1[0] - pix1[15]
* pix2v: pix2[0] - pix2[15] pix2iv: pix2[1] - pix2[16] */
vector unsigned char pix1v = vec_ld(0, pix1);
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(16, pix2);
- vector unsigned char pix2v = vec_perm(pix2l, pix2r, perm1);
- vector unsigned char pix2iv = vec_perm(pix2l, pix2r, perm2);
+ LOAD_PIX(pix2v, pix2iv, pix2, perm1, perm2);
/* Calculate the average vector. */
vector unsigned char avgv = vec_avg(pix2v, pix2iv);
@@ -80,13 +97,14 @@ static int sad16_x2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
static int sad16_y2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s = 0;
+ int i;
+ int __attribute__((aligned(16))) s = 0;
const vector unsigned char zero =
(const vector unsigned char) vec_splat_u8(0);
- vector unsigned char perm = vec_lvsl(0, pix2);
vector unsigned char pix1v, pix3v, avgv, t5;
vector unsigned int sad = (vector unsigned int) vec_splat_u32(0);
vector signed int sumdiffs;
+
uint8_t *pix3 = pix2 + stride;
/* Due to the fact that pix3 = pix2 + stride, the pix3 of one
@@ -96,19 +114,14 @@ static int sad16_y2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
* Read unaligned pixels into our vectors. The vectors are as follows:
* pix2v: pix2[0] - pix2[15]
* Split the pixel vectors into shorts. */
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(15, pix2);
- vector unsigned char pix2v = vec_perm(pix2l, pix2r, perm);
+ vector unsigned char pix2v = VEC_LD(0, pix2);
for (i = 0; i < h; i++) {
/* Read unaligned pixels into our vectors. The vectors are as follows:
* pix1v: pix1[0] - pix1[15]
* pix3v: pix3[0] - pix3[15] */
pix1v = vec_ld(0, pix1);
-
- pix2l = vec_ld(0, pix3);
- pix2r = vec_ld(15, pix3);
- pix3v = vec_perm(pix2l, pix2r, perm);
+ pix3v = VEC_LD(0, pix3);
/* Calculate the average vector. */
avgv = vec_avg(pix2v, pix3v);
@@ -134,20 +147,21 @@ static int sad16_y2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
static int sad16_xy2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s = 0;
+ int i;
+ int __attribute__((aligned(16))) s = 0;
uint8_t *pix3 = pix2 + stride;
const vector unsigned char zero =
(const vector unsigned char) vec_splat_u8(0);
const vector unsigned short two =
(const vector unsigned short) vec_splat_u16(2);
vector unsigned char avgv, t5;
- vector unsigned char perm1 = vec_lvsl(0, pix2);
- vector unsigned char perm2 = vec_add(perm1, vec_splat_u8(1));
vector unsigned char pix1v, pix3v, pix3iv;
vector unsigned short pix3lv, pix3hv, pix3ilv, pix3ihv;
vector unsigned short avghv, avglv;
vector unsigned int sad = (vector unsigned int) vec_splat_u32(0);
vector signed int sumdiffs;
+ vector unsigned char perm1, perm2, pix2v, pix2iv;
+ GET_PERM(perm1, perm2, pix2);
/* Due to the fact that pix3 = pix2 + stride, the pix3 of one
* iteration becomes pix2 in the next iteration. We can use this
@@ -156,19 +170,16 @@ static int sad16_xy2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
* Read unaligned pixels into our vectors. The vectors are as follows:
* pix2v: pix2[0] - pix2[15] pix2iv: pix2[1] - pix2[16]
* Split the pixel vectors into shorts. */
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(16, pix2);
- vector unsigned char pix2v = vec_perm(pix2l, pix2r, perm1);
- vector unsigned char pix2iv = vec_perm(pix2l, pix2r, perm2);
-
+ LOAD_PIX(pix2v, pix2iv, pix2, perm1, perm2);
vector unsigned short pix2hv =
- (vector unsigned short) vec_mergeh(zero, pix2v);
+ (vector unsigned short) VEC_MERGEH(zero, pix2v);
vector unsigned short pix2lv =
- (vector unsigned short) vec_mergel(zero, pix2v);
+ (vector unsigned short) VEC_MERGEL(zero, pix2v);
vector unsigned short pix2ihv =
- (vector unsigned short) vec_mergeh(zero, pix2iv);
+ (vector unsigned short) VEC_MERGEH(zero, pix2iv);
vector unsigned short pix2ilv =
- (vector unsigned short) vec_mergel(zero, pix2iv);
+ (vector unsigned short) VEC_MERGEL(zero, pix2iv);
+
vector unsigned short t1 = vec_add(pix2hv, pix2ihv);
vector unsigned short t2 = vec_add(pix2lv, pix2ilv);
vector unsigned short t3, t4;
@@ -178,11 +189,7 @@ static int sad16_xy2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
* pix1v: pix1[0] - pix1[15]
* pix3v: pix3[0] - pix3[15] pix3iv: pix3[1] - pix3[16] */
pix1v = vec_ld(0, pix1);
-
- pix2l = vec_ld(0, pix3);
- pix2r = vec_ld(16, pix3);
- pix3v = vec_perm(pix2l, pix2r, perm1);
- pix3iv = vec_perm(pix2l, pix2r, perm2);
+ LOAD_PIX(pix3v, pix3iv, pix3, perm1, perm2);
/* Note that AltiVec does have vec_avg, but this works on vector pairs
* and rounds up. We could do avg(avg(a, b), avg(c, d)), but the
@@ -191,10 +198,10 @@ static int sad16_xy2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
* vectors of shorts and do the averaging by hand. */
/* Split the pixel vectors into shorts. */
- pix3hv = (vector unsigned short) vec_mergeh(zero, pix3v);
- pix3lv = (vector unsigned short) vec_mergel(zero, pix3v);
- pix3ihv = (vector unsigned short) vec_mergeh(zero, pix3iv);
- pix3ilv = (vector unsigned short) vec_mergel(zero, pix3iv);
+ pix3hv = (vector unsigned short) VEC_MERGEH(zero, pix3v);
+ pix3lv = (vector unsigned short) VEC_MERGEL(zero, pix3v);
+ pix3ihv = (vector unsigned short) VEC_MERGEH(zero, pix3iv);
+ pix3ilv = (vector unsigned short) VEC_MERGEL(zero, pix3iv);
/* Do the averaging on them. */
t3 = vec_add(pix3hv, pix3ihv);
@@ -229,19 +236,17 @@ static int sad16_xy2_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
static int sad16_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s;
+ int i;
+ int __attribute__((aligned(16))) s;
const vector unsigned int zero =
(const vector unsigned int) vec_splat_u32(0);
- vector unsigned char perm = vec_lvsl(0, pix2);
vector unsigned int sad = (vector unsigned int) vec_splat_u32(0);
vector signed int sumdiffs;
for (i = 0; i < h; i++) {
/* Read potentially unaligned pixels into t1 and t2. */
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(15, pix2);
- vector unsigned char t1 = vec_ld(0, pix1);
- vector unsigned char t2 = vec_perm(pix2l, pix2r, perm);
+ vector unsigned char t1 =vec_ld(0, pix1);
+ vector unsigned char t2 = VEC_LD(0, pix2);
/* Calculate a sum of abs differences vector. */
vector unsigned char t3 = vec_max(t1, t2);
@@ -266,14 +271,13 @@ static int sad16_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
static int sad8_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s;
+ int i;
+ int __attribute__((aligned(16))) s;
const vector unsigned int zero =
(const vector unsigned int) vec_splat_u32(0);
const vector unsigned char permclear =
(vector unsigned char)
{ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0 };
- vector unsigned char perm1 = vec_lvsl(0, pix1);
- vector unsigned char perm2 = vec_lvsl(0, pix2);
vector unsigned int sad = (vector unsigned int) vec_splat_u32(0);
vector signed int sumdiffs;
@@ -281,14 +285,10 @@ static int sad8_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
/* Read potentially unaligned pixels into t1 and t2.
* Since we're reading 16 pixels, and actually only want 8,
* mask out the last 8 pixels. The 0s don't change the sum. */
- vector unsigned char pix1l = vec_ld(0, pix1);
- vector unsigned char pix1r = vec_ld(7, pix1);
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(7, pix2);
- vector unsigned char t1 = vec_and(vec_perm(pix1l, pix1r, perm1),
- permclear);
- vector unsigned char t2 = vec_and(vec_perm(pix2l, pix2r, perm2),
- permclear);
+ vector unsigned char pix1l = VEC_LD(0, pix1);
+ vector unsigned char pix2l = VEC_LD(0, pix2);
+ vector unsigned char t1 = vec_and(pix1l, permclear);
+ vector unsigned char t2 = vec_and(pix2l, permclear);
/* Calculate a sum of abs differences vector. */
vector unsigned char t3 = vec_max(t1, t2);
@@ -315,14 +315,13 @@ static int sad8_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
static int sse8_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s;
+ int i;
+ int __attribute__((aligned(16))) s;
const vector unsigned int zero =
(const vector unsigned int) vec_splat_u32(0);
const vector unsigned char permclear =
(vector unsigned char)
{ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0 };
- vector unsigned char perm1 = vec_lvsl(0, pix1);
- vector unsigned char perm2 = vec_lvsl(0, pix2);
vector unsigned int sum = (vector unsigned int) vec_splat_u32(0);
vector signed int sumsqr;
@@ -330,14 +329,8 @@ static int sse8_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
/* Read potentially unaligned pixels into t1 and t2.
* Since we're reading 16 pixels, and actually only want 8,
* mask out the last 8 pixels. The 0s don't change the sum. */
- vector unsigned char pix1l = vec_ld(0, pix1);
- vector unsigned char pix1r = vec_ld(7, pix1);
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(7, pix2);
- vector unsigned char t1 = vec_and(vec_perm(pix1l, pix1r, perm1),
- permclear);
- vector unsigned char t2 = vec_and(vec_perm(pix2l, pix2r, perm2),
- permclear);
+ vector unsigned char t1 = vec_and(VEC_LD(0, pix1), permclear);
+ vector unsigned char t2 = vec_and(VEC_LD(0, pix2), permclear);
/* Since we want to use unsigned chars, we can take advantage
* of the fact that abs(a - b) ^ 2 = (a - b) ^ 2. */
@@ -367,19 +360,17 @@ static int sse8_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
static int sse16_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int i, s;
+ int i;
+ int __attribute__((aligned(16))) s;
const vector unsigned int zero =
(const vector unsigned int) vec_splat_u32(0);
- vector unsigned char perm = vec_lvsl(0, pix2);
vector unsigned int sum = (vector unsigned int) vec_splat_u32(0);
vector signed int sumsqr;
for (i = 0; i < h; i++) {
/* Read potentially unaligned pixels into t1 and t2. */
- vector unsigned char pix2l = vec_ld(0, pix2);
- vector unsigned char pix2r = vec_ld(15, pix2);
vector unsigned char t1 = vec_ld(0, pix1);
- vector unsigned char t2 = vec_perm(pix2l, pix2r, perm);
+ vector unsigned char t2 = VEC_LD(0, pix2);
/* Since we want to use unsigned chars, we can take advantage
* of the fact that abs(a - b) ^ 2 = (a - b) ^ 2. */
@@ -399,15 +390,15 @@ static int sse16_altivec(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
/* Sum up the four partial sums, and put the result into s. */
sumsqr = vec_sums((vector signed int) sum, (vector signed int) zero);
sumsqr = vec_splat(sumsqr, 3);
- vec_ste(sumsqr, 0, &s);
+ vec_ste(sumsqr, 0, &s);
return s;
}
static int hadamard8_diff8x8_altivec(MpegEncContext *s, uint8_t *dst,
uint8_t *src, ptrdiff_t stride, int h)
{
- int sum;
+ int __attribute__((aligned(16))) sum;
register const vector unsigned char vzero =
(const vector unsigned char) vec_splat_u8(0);
register vector signed short temp0, temp1, temp2, temp3, temp4,
@@ -432,24 +423,19 @@ static int hadamard8_diff8x8_altivec(MpegEncContext *s, uint8_t *dst,
{ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+
#define ONEITERBUTTERFLY(i, res) \
{ \
- register vector unsigned char src1 = vec_ld(stride * i, src); \
- register vector unsigned char src2 = vec_ld(stride * i + 15, src); \
- register vector unsigned char srcO = \
- vec_perm(src1, src2, vec_lvsl(stride * i, src)); \
- register vector unsigned char dst1 = vec_ld(stride * i, dst); \
- register vector unsigned char dst2 = vec_ld(stride * i + 15, dst); \
- register vector unsigned char dstO = \
- vec_perm(dst1, dst2, vec_lvsl(stride * i, dst)); \
+ register vector unsigned char srcO = unaligned_load(stride * i, src); \
+ register vector unsigned char dstO = unaligned_load(stride * i, dst);\
\
/* Promote the unsigned chars to signed shorts. */ \
/* We're in the 8x8 function, we only care for the first 8. */ \
register vector signed short srcV = \
- (vector signed short) vec_mergeh((vector signed char) vzero, \
+ (vector signed short) VEC_MERGEH((vector signed char) vzero, \
(vector signed char) srcO); \
register vector signed short dstV = \
- (vector signed short) vec_mergeh((vector signed char) vzero, \
+ (vector signed short) VEC_MERGEH((vector signed char) vzero, \
(vector signed char) dstO); \
\
/* subtractions inside the first butterfly */ \
@@ -461,6 +447,7 @@ static int hadamard8_diff8x8_altivec(MpegEncContext *s, uint8_t *dst,
register vector signed short op3 = vec_perm(but2, but2, perm3); \
res = vec_mladd(but2, vprod3, op3); \
}
+
ONEITERBUTTERFLY(0, temp0);
ONEITERBUTTERFLY(1, temp1);
ONEITERBUTTERFLY(2, temp2);
@@ -510,6 +497,7 @@ static int hadamard8_diff8x8_altivec(MpegEncContext *s, uint8_t *dst,
vsum = vec_sum4s(vec_abs(line7C), vsum);
vsum = vec_sums(vsum, (vector signed int) vzero);
vsum = vec_splat(vsum, 3);
+
vec_ste(vsum, 0, &sum);
}
return sum;
@@ -536,7 +524,7 @@ static int hadamard8_diff8x8_altivec(MpegEncContext *s, uint8_t *dst,
static int hadamard8_diff16x8_altivec(MpegEncContext *s, uint8_t *dst,
uint8_t *src, ptrdiff_t stride, int h)
{
- int sum;
+ int __attribute__((aligned(16))) sum;
register vector signed short
temp0 __asm__ ("v0"),
temp1 __asm__ ("v1"),
@@ -584,31 +572,23 @@ static int hadamard8_diff16x8_altivec(MpegEncContext *s, uint8_t *dst,
#define ONEITERBUTTERFLY(i, res1, res2) \
{ \
- register vector unsigned char src1 __asm__ ("v22") = \
- vec_ld(stride * i, src); \
- register vector unsigned char src2 __asm__ ("v23") = \
- vec_ld(stride * i + 16, src); \
register vector unsigned char srcO __asm__ ("v22") = \
- vec_perm(src1, src2, vec_lvsl(stride * i, src)); \
- register vector unsigned char dst1 __asm__ ("v24") = \
- vec_ld(stride * i, dst); \
- register vector unsigned char dst2 __asm__ ("v25") = \
- vec_ld(stride * i + 16, dst); \
+ unaligned_load(stride * i, src); \
register vector unsigned char dstO __asm__ ("v23") = \
- vec_perm(dst1, dst2, vec_lvsl(stride * i, dst)); \
+ unaligned_load(stride * i, dst);\
\
/* Promote the unsigned chars to signed shorts. */ \
register vector signed short srcV __asm__ ("v24") = \
- (vector signed short) vec_mergeh((vector signed char) vzero, \
+ (vector signed short) VEC_MERGEH((vector signed char) vzero, \
(vector signed char) srcO); \
register vector signed short dstV __asm__ ("v25") = \
- (vector signed short) vec_mergeh((vector signed char) vzero, \
+ (vector signed short) VEC_MERGEH((vector signed char) vzero, \
(vector signed char) dstO); \
register vector signed short srcW __asm__ ("v26") = \
- (vector signed short) vec_mergel((vector signed char) vzero, \
+ (vector signed short) VEC_MERGEL((vector signed char) vzero, \
(vector signed char) srcO); \
register vector signed short dstW __asm__ ("v27") = \
- (vector signed short) vec_mergel((vector signed char) vzero, \
+ (vector signed short) VEC_MERGEL((vector signed char) vzero, \
(vector signed char) dstO); \
\
/* subtractions inside the first butterfly */ \
@@ -639,6 +619,7 @@ static int hadamard8_diff16x8_altivec(MpegEncContext *s, uint8_t *dst,
res1 = vec_mladd(but2, vprod3, op3); \
res2 = vec_mladd(but2S, vprod3, op3S); \
}
+
ONEITERBUTTERFLY(0, temp0, temp0S);
ONEITERBUTTERFLY(1, temp1, temp1S);
ONEITERBUTTERFLY(2, temp2, temp2S);
@@ -725,6 +706,7 @@ static int hadamard8_diff16x8_altivec(MpegEncContext *s, uint8_t *dst,
vsum = vec_sum4s(vec_abs(line7CS), vsum);
vsum = vec_sums(vsum, (vector signed int) vzero);
vsum = vec_splat(vsum, 3);
+
vec_ste(vsum, 0, &sum);
}
return sum;
diff --git a/libavcodec/ppc/mpegaudiodsp_altivec.c b/libavcodec/ppc/mpegaudiodsp_altivec.c
index c37f8ec975..ddfe5dcbb7 100644
--- a/libavcodec/ppc/mpegaudiodsp_altivec.c
+++ b/libavcodec/ppc/mpegaudiodsp_altivec.c
@@ -2,20 +2,20 @@
* Altivec optimized MP3 decoding functions
* Copyright (c) 2010 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/mpegvideo_altivec.c b/libavcodec/ppc/mpegvideo_altivec.c
index 9ae849f173..1b6bda6c36 100644
--- a/libavcodec/ppc/mpegvideo_altivec.c
+++ b/libavcodec/ppc/mpegvideo_altivec.c
@@ -4,20 +4,20 @@
* dct_unquantize_h263_altivec:
* Copyright (c) 2003 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,8 +42,6 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s,
int i, level, qmul, qadd;
int nCoeffs;
- assert(s->block_last_index[n]>=0);
-
qadd = (qscale - 1) | 1;
qmul = qscale << 1;
@@ -59,6 +57,7 @@ static void dct_unquantize_h263_altivec(MpegEncContext *s,
nCoeffs= 63; //does not always use zigzag table
} else {
i = 0;
+ av_assert2(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
}
diff --git a/libavcodec/ppc/mpegvideodsp.c b/libavcodec/ppc/mpegvideodsp.c
index 2bdf909e4a..7696954335 100644
--- a/libavcodec/ppc/mpegvideodsp.c
+++ b/libavcodec/ppc/mpegvideodsp.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2003 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,7 +66,7 @@ static void gmc1_altivec(uint8_t *dst /* align 8 */, uint8_t *src /* align1 */,
vec_lvsl(0, src));
if (src_really_odd != 0x0000000F)
- /* If src & 0xF == 0xF, then (src + 1) is properly aligned
+ /* If (src & 0xF) == 0xF, then (src + 1) is properly aligned
* on the second vector. */
srcvB = vec_perm(src_0, src_1, vec_lvsl(1, src));
else
@@ -88,7 +88,7 @@ static void gmc1_altivec(uint8_t *dst /* align 8 */, uint8_t *src /* align1 */,
srcvC = vec_perm(src_0, src_1, vec_lvsl(stride + 0, src));
if (src_really_odd != 0x0000000F)
- /* If src & 0xF == 0xF, then (src + 1) is properly aligned
+ /* If (src & 0xF) == 0xF, then (src + 1) is properly aligned
* on the second vector. */
srcvD = vec_perm(src_0, src_1, vec_lvsl(stride + 1, src));
else
diff --git a/libavcodec/ppc/mpegvideoencdsp.c b/libavcodec/ppc/mpegvideoencdsp.c
index b5348e6abd..3e6765ce15 100644
--- a/libavcodec/ppc/mpegvideoencdsp.c
+++ b/libavcodec/ppc/mpegvideoencdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,34 @@
#if HAVE_ALTIVEC
+#if HAVE_VSX
+static int pix_norm1_altivec(uint8_t *pix, int line_size)
+{
+ int i, s = 0;
+ const vector unsigned int zero =
+ (const vector unsigned int) vec_splat_u32(0);
+ vector unsigned int sv = (vector unsigned int) vec_splat_u32(0);
+ vector signed int sum;
+
+ for (i = 0; i < 16; i++) {
+ /* Read the potentially unaligned pixels. */
+ //vector unsigned char pixl = vec_ld(0, pix);
+ //vector unsigned char pixr = vec_ld(15, pix);
+ //vector unsigned char pixv = vec_perm(pixl, pixr, perm);
+ vector unsigned char pixv = vec_vsx_ld(0, pix);
+
+ /* Square the values, and add them to our sum. */
+ sv = vec_msum(pixv, pixv, sv);
+
+ pix += line_size;
+ }
+ /* Sum up the four partial sums, and put the result into s. */
+ sum = vec_sums((vector signed int) sv, (vector signed int) zero);
+ sum = vec_splat(sum, 3);
+ vec_ste(sum, 0, &s);
+ return s;
+}
+#else
static int pix_norm1_altivec(uint8_t *pix, int line_size)
{
int i, s = 0;
@@ -58,7 +86,37 @@ static int pix_norm1_altivec(uint8_t *pix, int line_size)
return s;
}
+#endif /* HAVE_VSX */
+
+#if HAVE_VSX
+static int pix_sum_altivec(uint8_t *pix, int line_size)
+{
+ int i, s;
+ const vector unsigned int zero =
+ (const vector unsigned int) vec_splat_u32(0);
+ vector unsigned int sad = (vector unsigned int) vec_splat_u32(0);
+ vector signed int sumdiffs;
+
+ for (i = 0; i < 16; i++) {
+ /* Read the potentially unaligned 16 pixels into t1. */
+ //vector unsigned char pixl = vec_ld(0, pix);
+ //vector unsigned char pixr = vec_ld(15, pix);
+ //vector unsigned char t1 = vec_perm(pixl, pixr, perm);
+ vector unsigned char t1 = vec_vsx_ld(0, pix);
+ /* Add each 4 pixel group together and put 4 results into sad. */
+ sad = vec_sum4s(t1, sad);
+
+ pix += line_size;
+ }
+
+ /* Sum up the four partial sums, and put the result into s. */
+ sumdiffs = vec_sums((vector signed int) sad, (vector signed int) zero);
+ sumdiffs = vec_splat(sumdiffs, 3);
+ vec_ste(sumdiffs, 0, &s);
+ return s;
+}
+#else
static int pix_sum_altivec(uint8_t *pix, int line_size)
{
int i, s;
@@ -88,6 +146,8 @@ static int pix_sum_altivec(uint8_t *pix, int line_size)
return s;
}
+#endif /* HAVE_VSX */
+
#endif /* HAVE_ALTIVEC */
av_cold void ff_mpegvideoencdsp_init_ppc(MpegvideoEncDSPContext *c,
diff --git a/libavcodec/ppc/pixblockdsp.c b/libavcodec/ppc/pixblockdsp.c
index 698d655fc6..9bbdf96d12 100644
--- a/libavcodec/ppc/pixblockdsp.c
+++ b/libavcodec/ppc/pixblockdsp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Dieter Shirley
* Copyright (c) 2003-2004 Romain Dolbeau <romain@dolbeau.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,8 +35,36 @@
#if HAVE_ALTIVEC
+#if HAVE_VSX
static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
- int line_size)
+ ptrdiff_t line_size)
+{
+ int i;
+ vector unsigned char perm =
+ (vector unsigned char) {0x00,0x10, 0x01,0x11,0x02,0x12,0x03,0x13,\
+ 0x04,0x14,0x05,0x15,0x06,0x16,0x07,0x17};
+ const vector unsigned char zero =
+ (const vector unsigned char) vec_splat_u8(0);
+
+ for (i = 0; i < 8; i++) {
+ /* Read potentially unaligned pixels.
+ * We're reading 16 pixels, and actually only want 8,
+ * but we simply ignore the extras. */
+ vector unsigned char bytes = vec_vsx_ld(0, pixels);
+
+ // Convert the bytes into shorts.
+ //vector signed short shorts = (vector signed short) vec_perm(zero, bytes, perm);
+ vector signed short shorts = (vector signed short) vec_perm(bytes, zero, perm);
+
+ // Save the data to the block, we assume the block is 16-byte aligned.
+ vec_vsx_st(shorts, i * 16, (vector signed short *) block);
+
+ pixels += line_size;
+ }
+}
+#else
+static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
+ ptrdiff_t line_size)
{
int i;
vector unsigned char perm = vec_lvsl(0, pixels);
@@ -62,6 +90,71 @@ static void get_pixels_altivec(int16_t *restrict block, const uint8_t *pixels,
}
}
+#endif /* HAVE_VSX */
+
+#if HAVE_VSX
+static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
+ const uint8_t *s2, int stride)
+{
+ int i;
+ const vector unsigned char zero =
+ (const vector unsigned char) vec_splat_u8(0);
+ vector signed short shorts1, shorts2;
+
+ for (i = 0; i < 4; i++) {
+ /* Read potentially unaligned pixels.
+ * We're reading 16 pixels, and actually only want 8,
+ * but we simply ignore the extras. */
+ vector unsigned char bytes = vec_vsx_ld(0, s1);
+
+ // Convert the bytes into shorts.
+ shorts1 = (vector signed short) vec_mergeh(bytes, zero);
+
+ // Do the same for the second block of pixels.
+ bytes =vec_vsx_ld(0, s2);
+
+ // Convert the bytes into shorts.
+ shorts2 = (vector signed short) vec_mergeh(bytes, zero);
+
+ // Do the subtraction.
+ shorts1 = vec_sub(shorts1, shorts2);
+
+ // Save the data to the block, we assume the block is 16-byte aligned.
+ vec_vsx_st(shorts1, 0, (vector signed short *) block);
+
+ s1 += stride;
+ s2 += stride;
+ block += 8;
+
+ /* The code below is a copy of the code above...
+ * This is a manual unroll. */
+
+ /* Read potentially unaligned pixels.
+ * We're reading 16 pixels, and actually only want 8,
+ * but we simply ignore the extras. */
+ bytes = vec_vsx_ld(0, s1);
+
+ // Convert the bytes into shorts.
+ shorts1 = (vector signed short) vec_mergeh(bytes, zero);
+
+ // Do the same for the second block of pixels.
+ bytes = vec_vsx_ld(0, s2);
+
+ // Convert the bytes into shorts.
+ shorts2 = (vector signed short) vec_mergeh(bytes, zero);
+
+ // Do the subtraction.
+ shorts1 = vec_sub(shorts1, shorts2);
+
+ // Save the data to the block, we assume the block is 16-byte aligned.
+ vec_vsx_st(shorts1, 0, (vector signed short *) block);
+
+ s1 += stride;
+ s2 += stride;
+ block += 8;
+ }
+}
+#else
static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
const uint8_t *s2, int stride)
{
@@ -134,6 +227,8 @@ static void diff_pixels_altivec(int16_t *restrict block, const uint8_t *s1,
}
}
+#endif /* HAVE_VSX */
+
#endif /* HAVE_ALTIVEC */
av_cold void ff_pixblockdsp_init_ppc(PixblockDSPContext *c,
diff --git a/libavcodec/ppc/svq1enc_altivec.c b/libavcodec/ppc/svq1enc_altivec.c
index 564f12986b..4e25e253f6 100644
--- a/libavcodec/ppc/svq1enc_altivec.c
+++ b/libavcodec/ppc/svq1enc_altivec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/vc1dsp_altivec.c b/libavcodec/ppc/vc1dsp_altivec.c
index 90c3d27e82..35bb280842 100644
--- a/libavcodec/ppc/vc1dsp_altivec.c
+++ b/libavcodec/ppc/vc1dsp_altivec.c
@@ -2,20 +2,20 @@
* VC-1 and WMV3 decoder - DSP functions AltiVec-optimized
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -304,16 +304,23 @@ static void vc1_inv_trans_8x4_altivec(uint8_t *dest, int stride, int16_t *block)
src2 = vec_pack(s2, sA);
src3 = vec_pack(s3, sB);
+#if HAVE_BIGENDIAN
p0 = vec_lvsl (0, dest);
p1 = vec_lvsl (stride, dest);
p = vec_splat_u8 (-1);
perm0 = vec_mergeh (p, p0);
perm1 = vec_mergeh (p, p1);
+#define GET_TMP2(dst, p) \
+ tmp = vec_ld (0, dest); \
+ tmp2 = (vector signed short)vec_perm (tmp, vec_splat_u8(0), p);
+#else
+#define GET_TMP2(dst,p) \
+ tmp = vec_vsx_ld (0, dst); \
+ tmp2 = (vector signed short)vec_mergeh (tmp, vec_splat_u8(0));
+#endif
#define ADD(dest,src,perm) \
- /* *(uint64_t *)&tmp = *(uint64_t *)dest; */ \
- tmp = vec_ld (0, dest); \
- tmp2 = (vector signed short)vec_perm (tmp, vec_splat_u8(0), perm); \
+ GET_TMP2(dest, perm); \
tmp3 = vec_adds (tmp2, src); \
tmp = vec_packsu (tmp3, tmp3); \
vec_ste ((vector unsigned int)tmp, 0, (unsigned int *)dest); \
diff --git a/libavcodec/ppc/videodsp_ppc.c b/libavcodec/ppc/videodsp_ppc.c
index b9e003b487..915702252e 100644
--- a/libavcodec/ppc/videodsp_ppc.c
+++ b/libavcodec/ppc/videodsp_ppc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003-2004 Romain Dolbeau
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/vorbisdsp_altivec.c b/libavcodec/ppc/vorbisdsp_altivec.c
index 43f4d0325b..d7557c815b 100644
--- a/libavcodec/ppc/vorbisdsp_altivec.c
+++ b/libavcodec/ppc/vorbisdsp_altivec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ppc/vp3dsp_altivec.c b/libavcodec/ppc/vp3dsp_altivec.c
index bce49e3170..4a367b655e 100644
--- a/libavcodec/ppc/vp3dsp_altivec.c
+++ b/libavcodec/ppc/vp3dsp_altivec.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2009 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,8 +32,13 @@
static const vec_s16 constants =
{0, 64277, 60547, 54491, 46341, 36410, 25080, 12785};
+#if HAVE_BIGENDIAN
static const vec_u8 interleave_high =
{0, 1, 16, 17, 4, 5, 20, 21, 8, 9, 24, 25, 12, 13, 28, 29};
+#else
+static const vec_u8 interleave_high =
+ {2, 3, 18, 19, 6, 7, 22, 23, 10, 11, 26, 27, 14, 15, 30, 31};
+#endif
#define IDCT_START \
vec_s16 A, B, C, D, Ad, Bd, Cd, Dd, E, F, G, H;\
@@ -156,9 +161,18 @@ static void vp3_idct_add_altivec(uint8_t *dst, int stride, int16_t block[64])
TRANSPOSE8(b0, b1, b2, b3, b4, b5, b6, b7);
IDCT_1D(ADD8, SHIFT4)
-#define ADD(a)\
+#if HAVE_BIGENDIAN
+#define GET_VDST16\
vdst = vec_ld(0, dst);\
- vdst_16 = (vec_s16)vec_perm(vdst, zero_u8v, vdst_mask);\
+ vdst_16 = (vec_s16)vec_perm(vdst, zero_u8v, vdst_mask);
+#else
+#define GET_VDST16\
+ vdst = vec_vsx_ld(0,dst);\
+ vdst_16 = (vec_s16)vec_mergeh(vdst, zero_u8v);
+#endif
+
+#define ADD(a)\
+ GET_VDST16;\
vdst_16 = vec_adds(a, vdst_16);\
t = vec_packsu(vdst_16, vdst_16);\
vec_ste((vec_u32)t, 0, (unsigned int *)dst);\
diff --git a/libavcodec/ppc/vp8dsp_altivec.c b/libavcodec/ppc/vp8dsp_altivec.c
index e010dee4d2..23e4ace7da 100644
--- a/libavcodec/ppc/vp8dsp_altivec.c
+++ b/libavcodec/ppc/vp8dsp_altivec.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2010 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,17 +59,30 @@ static const vec_s8 h_subpel_filters_outer[3] =
vec_s8 filter_outerh = h_subpel_filters_outer[(i)>>1]; \
vec_s8 filter_outerl = vec_sld(filter_outerh, filter_outerh, 2)
+#if HAVE_BIGENDIAN
+#define GET_PIXHL(offset) \
+ a = vec_ld((offset)-is6tap-1, src); \
+ b = vec_ld((offset)-is6tap-1+15, src); \
+ pixh = vec_perm(a, b, permh##offset); \
+ pixl = vec_perm(a, b, perml##offset)
+
+#define GET_OUTER(offset) outer = vec_perm(a, b, perm_6tap##offset)
+#else
+#define GET_PIXHL(offset) \
+ a = vec_vsx_ld((offset)-is6tap-1, src); \
+ pixh = vec_perm(a, a, perm_inner); \
+ pixl = vec_perm(a, a, vec_add(perm_inner, vec_splat_u8(4)))
+
+#define GET_OUTER(offset) outer = vec_perm(a, a, perm_outer)
+#endif
+
#define FILTER_H(dstv, off) \
- a = vec_ld((off)-is6tap-1, src); \
- b = vec_ld((off)-is6tap-1+15, src); \
-\
- pixh = vec_perm(a, b, permh##off); \
- pixl = vec_perm(a, b, perml##off); \
+ GET_PIXHL(off); \
filth = vec_msum(filter_inner, pixh, c64); \
filtl = vec_msum(filter_inner, pixl, c64); \
\
if (is6tap) { \
- outer = vec_perm(a, b, perm_6tap##off); \
+ GET_OUTER(off); \
filth = vec_msum(filter_outerh, outer, filth); \
filtl = vec_msum(filter_outerl, outer, filtl); \
} \
@@ -84,9 +97,12 @@ void put_vp8_epel_h_altivec_core(uint8_t *dst, ptrdiff_t dst_stride,
int h, int mx, int w, int is6tap)
{
LOAD_H_SUBPEL_FILTER(mx-1);
- vec_u8 align_vec0, align_vec8, permh0, permh8, filt;
+#if HAVE_BIGENDIAN
+ vec_u8 align_vec0, align_vec8, permh0, permh8;
vec_u8 perm_6tap0, perm_6tap8, perml0, perml8;
- vec_u8 a, b, pixh, pixl, outer;
+ vec_u8 b;
+#endif
+ vec_u8 filt, a, pixh, pixl, outer;
vec_s16 f16h, f16l;
vec_s32 filth, filtl;
@@ -97,6 +113,7 @@ void put_vp8_epel_h_altivec_core(uint8_t *dst, ptrdiff_t dst_stride,
vec_s32 c64 = vec_sl(vec_splat_s32(1), vec_splat_u32(6));
vec_u16 c7 = vec_splat_u16(7);
+#if HAVE_BIGENDIAN
align_vec0 = vec_lvsl( -is6tap-1, src);
align_vec8 = vec_lvsl(8-is6tap-1, src);
@@ -107,6 +124,7 @@ void put_vp8_epel_h_altivec_core(uint8_t *dst, ptrdiff_t dst_stride,
perml8 = vec_perm(align_vec8, align_vec8, perm_inner);
perm_6tap0 = vec_perm(align_vec0, align_vec0, perm_outer);
perm_6tap8 = vec_perm(align_vec8, align_vec8, perm_outer);
+#endif
while (h --> 0) {
FILTER_H(f16h, 0);
@@ -164,6 +182,12 @@ static const vec_u8 v_subpel_filters[7] =
dstv = vec_adds(dstv, c64); \
dstv = vec_sra(dstv, c7)
+#if HAVE_BIGENDIAN
+#define LOAD_HL(off, s, perm) load_with_perm_vec(off, s, perm)
+#else
+#define LOAD_HL(off, s, perm) vec_mergeh(vec_vsx_ld(off,s), vec_vsx_ld(off+8,s))
+#endif
+
static av_always_inline
void put_vp8_epel_v_altivec_core(uint8_t *dst, ptrdiff_t dst_stride,
uint8_t *src, ptrdiff_t src_stride,
@@ -175,6 +199,7 @@ void put_vp8_epel_v_altivec_core(uint8_t *dst, ptrdiff_t dst_stride,
vec_s16 c64 = vec_sl(vec_splat_s16(1), vec_splat_u16(6));
vec_u16 c7 = vec_splat_u16(7);
+#if HAVE_BIGENDIAN
// we want pixels 0-7 to be in the even positions and 8-15 in the odd,
// so combine this permute with the alignment permute vector
align_vech = vec_lvsl(0, src);
@@ -183,22 +208,23 @@ void put_vp8_epel_v_altivec_core(uint8_t *dst, ptrdiff_t dst_stride,
perm_vec = vec_mergeh(align_vech, align_vecl);
else
perm_vec = vec_mergeh(align_vech, align_vech);
+#endif
if (is6tap)
- s0 = load_with_perm_vec(-2*src_stride, src, perm_vec);
- s1 = load_with_perm_vec(-1*src_stride, src, perm_vec);
- s2 = load_with_perm_vec( 0*src_stride, src, perm_vec);
- s3 = load_with_perm_vec( 1*src_stride, src, perm_vec);
+ s0 = LOAD_HL(-2*src_stride, src, perm_vec);
+ s1 = LOAD_HL(-1*src_stride, src, perm_vec);
+ s2 = LOAD_HL( 0*src_stride, src, perm_vec);
+ s3 = LOAD_HL( 1*src_stride, src, perm_vec);
if (is6tap)
- s4 = load_with_perm_vec( 2*src_stride, src, perm_vec);
+ s4 = LOAD_HL( 2*src_stride, src, perm_vec);
src += (2+is6tap)*src_stride;
while (h --> 0) {
if (is6tap)
- s5 = load_with_perm_vec(0, src, perm_vec);
+ s5 = LOAD_HL(0, src, perm_vec);
else
- s4 = load_with_perm_vec(0, src, perm_vec);
+ s4 = LOAD_HL(0, src, perm_vec);
FILTER_V(f16h, vec_mule);
@@ -272,39 +298,25 @@ EPEL_HV(4, 4,4)
static void put_vp8_pixels16_altivec(uint8_t *dst, ptrdiff_t dstride, uint8_t *src, ptrdiff_t sstride, int h, int mx, int my)
{
- register vector unsigned char pixelsv1, pixelsv2;
- register vector unsigned char pixelsv1B, pixelsv2B;
- register vector unsigned char pixelsv1C, pixelsv2C;
- register vector unsigned char pixelsv1D, pixelsv2D;
-
- register vector unsigned char perm = vec_lvsl(0, src);
+ register vector unsigned char perm;
int i;
register ptrdiff_t dstride2 = dstride << 1, sstride2 = sstride << 1;
register ptrdiff_t dstride3 = dstride2 + dstride, sstride3 = sstride + sstride2;
register ptrdiff_t dstride4 = dstride << 2, sstride4 = sstride << 2;
+#if HAVE_BIGENDIAN
+ perm = vec_lvsl(0, src);
+#endif
// hand-unrolling the loop by 4 gains about 15%
// mininum execution time goes from 74 to 60 cycles
// it's faster than -funroll-loops, but using
// -funroll-loops w/ this is bad - 74 cycles again.
// all this is on a 7450, tuning for the 7450
for (i = 0; i < h; i += 4) {
- pixelsv1 = vec_ld( 0, src);
- pixelsv2 = vec_ld(15, src);
- pixelsv1B = vec_ld(sstride, src);
- pixelsv2B = vec_ld(15 + sstride, src);
- pixelsv1C = vec_ld(sstride2, src);
- pixelsv2C = vec_ld(15 + sstride2, src);
- pixelsv1D = vec_ld(sstride3, src);
- pixelsv2D = vec_ld(15 + sstride3, src);
- vec_st(vec_perm(pixelsv1, pixelsv2, perm),
- 0, (unsigned char*)dst);
- vec_st(vec_perm(pixelsv1B, pixelsv2B, perm),
- dstride, (unsigned char*)dst);
- vec_st(vec_perm(pixelsv1C, pixelsv2C, perm),
- dstride2, (unsigned char*)dst);
- vec_st(vec_perm(pixelsv1D, pixelsv2D, perm),
- dstride3, (unsigned char*)dst);
+ vec_st(load_with_perm_vec(0, src, perm), 0, dst);
+ vec_st(load_with_perm_vec(sstride, src, perm), dstride, dst);
+ vec_st(load_with_perm_vec(sstride2, src, perm), dstride2, dst);
+ vec_st(load_with_perm_vec(sstride3, src, perm), dstride3, dst);
src += sstride4;
dst += dstride4;
}
diff --git a/libavcodec/proresdata.c b/libavcodec/proresdata.c
index fcaf32a1af..9849b5cc00 100644
--- a/libavcodec/proresdata.c
+++ b/libavcodec/proresdata.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/proresdata.h b/libavcodec/proresdata.h
index 1e5d05ece6..ee8278d5f4 100644
--- a/libavcodec/proresdata.h
+++ b/libavcodec/proresdata.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c
deleted file mode 100644
index b2c2b28fdf..0000000000
--- a/libavcodec/proresdec.c
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * Apple ProRes compatible decoder
- *
- * Copyright (c) 2010-2011 Maxim Poliakovski
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * This is a decoder for Apple ProRes 422 SD/HQ/LT/Proxy and ProRes 4444.
- * It is used for storing and editing high definition video data in Apple's Final Cut Pro.
- *
- * @see http://wiki.multimedia.cx/index.php?title=Apple_ProRes
- */
-
-#define LONG_BITSTREAM_READER // some ProRes vlc codes require up to 28 bits to be read at once
-
-#include <stdint.h>
-
-#include "libavutil/intmath.h"
-#include "avcodec.h"
-#include "idctdsp.h"
-#include "internal.h"
-#include "proresdata.h"
-#include "proresdsp.h"
-#include "get_bits.h"
-
-typedef struct ProresThreadData {
- const uint8_t *index; ///< pointers to the data of this slice
- int slice_num;
- int x_pos, y_pos;
- int slice_width;
- int prev_slice_sf; ///< scalefactor of the previous decoded slice
- DECLARE_ALIGNED(16, int16_t, blocks)[8 * 4 * 64];
- DECLARE_ALIGNED(16, int16_t, qmat_luma_scaled)[64];
- DECLARE_ALIGNED(16, int16_t, qmat_chroma_scaled)[64];
-} ProresThreadData;
-
-typedef struct ProresContext {
- ProresDSPContext dsp;
- AVFrame *frame;
- ScanTable scantable;
- int scantable_type; ///< -1 = uninitialized, 0 = progressive, 1/2 = interlaced
-
- int frame_type; ///< 0 = progressive, 1 = top-field first, 2 = bottom-field first
- int pic_format; ///< 2 = 422, 3 = 444
- uint8_t qmat_luma[64]; ///< dequantization matrix for luma
- uint8_t qmat_chroma[64]; ///< dequantization matrix for chroma
- int qmat_changed; ///< 1 - global quantization matrices changed
- int total_slices; ///< total number of slices in a picture
- ProresThreadData *slice_data;
- int pic_num;
- int chroma_factor;
- int mb_chroma_factor;
- int num_chroma_blocks; ///< number of chrominance blocks in a macroblock
- int num_x_slices;
- int num_y_slices;
- int slice_width_factor;
- int slice_height_factor;
- int num_x_mbs;
- int num_y_mbs;
- int alpha_info;
-} ProresContext;
-
-
-static av_cold int decode_init(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
-
- ctx->total_slices = 0;
- ctx->slice_data = NULL;
-
- avctx->bits_per_raw_sample = PRORES_BITS_PER_SAMPLE;
- ff_proresdsp_init(&ctx->dsp);
-
- ctx->scantable_type = -1; // set scantable type to uninitialized
- memset(ctx->qmat_luma, 4, 64);
- memset(ctx->qmat_chroma, 4, 64);
-
- return 0;
-}
-
-
-static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
- const int data_size, AVCodecContext *avctx)
-{
- int hdr_size, version, width, height, flags;
- const uint8_t *ptr;
-
- hdr_size = AV_RB16(buf);
- if (hdr_size > data_size) {
- av_log(avctx, AV_LOG_ERROR, "frame data too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- version = AV_RB16(buf + 2);
- if (version >= 2) {
- av_log(avctx, AV_LOG_ERROR,
- "unsupported header version: %d\n", version);
- return AVERROR_INVALIDDATA;
- }
-
- width = AV_RB16(buf + 8);
- height = AV_RB16(buf + 10);
- if (width != avctx->width || height != avctx->height) {
- av_log(avctx, AV_LOG_ERROR,
- "picture dimension changed: old: %d x %d, new: %d x %d\n",
- avctx->width, avctx->height, width, height);
- return AVERROR_INVALIDDATA;
- }
-
- ctx->frame_type = (buf[12] >> 2) & 3;
- if (ctx->frame_type > 2) {
- av_log(avctx, AV_LOG_ERROR,
- "unsupported frame type: %d\n", ctx->frame_type);
- return AVERROR_INVALIDDATA;
- }
-
- ctx->chroma_factor = (buf[12] >> 6) & 3;
- ctx->mb_chroma_factor = ctx->chroma_factor + 2;
- ctx->num_chroma_blocks = (1 << ctx->chroma_factor) >> 1;
- ctx->alpha_info = buf[17] & 0xf;
-
- if (ctx->alpha_info > 2) {
- av_log(avctx, AV_LOG_ERROR, "Invalid alpha mode %d\n", ctx->alpha_info);
- return AVERROR_INVALIDDATA;
- }
-
- switch (ctx->chroma_factor) {
- case 2:
- avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA422P10
- : AV_PIX_FMT_YUV422P10;
- break;
- case 3:
- avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA444P10
- : AV_PIX_FMT_YUV444P10;
- break;
- default:
- av_log(avctx, AV_LOG_ERROR,
- "unsupported picture format: %d\n", ctx->pic_format);
- return AVERROR_INVALIDDATA;
- }
-
- if (ctx->scantable_type != ctx->frame_type) {
- if (!ctx->frame_type)
- ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
- ff_prores_progressive_scan);
- else
- ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
- ff_prores_interlaced_scan);
- ctx->scantable_type = ctx->frame_type;
- }
-
- if (ctx->frame_type) { /* if interlaced */
- ctx->frame->interlaced_frame = 1;
- ctx->frame->top_field_first = ctx->frame_type & 1;
- } else {
- ctx->frame->interlaced_frame = 0;
- }
-
- avctx->color_primaries = buf[14];
- avctx->color_trc = buf[15];
- avctx->colorspace = buf[16];
-
- ctx->qmat_changed = 0;
- ptr = buf + 20;
- flags = buf[19];
- if (flags & 2) {
- if (ptr - buf > hdr_size - 64) {
- av_log(avctx, AV_LOG_ERROR, "header data too small\n");
- return AVERROR_INVALIDDATA;
- }
- if (memcmp(ctx->qmat_luma, ptr, 64)) {
- memcpy(ctx->qmat_luma, ptr, 64);
- ctx->qmat_changed = 1;
- }
- ptr += 64;
- } else {
- memset(ctx->qmat_luma, 4, 64);
- ctx->qmat_changed = 1;
- }
-
- if (flags & 1) {
- if (ptr - buf > hdr_size - 64) {
- av_log(avctx, AV_LOG_ERROR, "header data too small\n");
- return -1;
- }
- if (memcmp(ctx->qmat_chroma, ptr, 64)) {
- memcpy(ctx->qmat_chroma, ptr, 64);
- ctx->qmat_changed = 1;
- }
- } else {
- memset(ctx->qmat_chroma, 4, 64);
- ctx->qmat_changed = 1;
- }
-
- return hdr_size;
-}
-
-
-static int decode_picture_header(ProresContext *ctx, const uint8_t *buf,
- const int data_size, AVCodecContext *avctx)
-{
- int i, hdr_size, pic_data_size, num_slices;
- int slice_width_factor, slice_height_factor;
- int remainder, num_x_slices;
- const uint8_t *data_ptr, *index_ptr;
-
- hdr_size = data_size > 0 ? buf[0] >> 3 : 0;
- if (hdr_size < 8 || hdr_size > data_size) {
- av_log(avctx, AV_LOG_ERROR, "picture header too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- pic_data_size = AV_RB32(buf + 1);
- if (pic_data_size > data_size) {
- av_log(avctx, AV_LOG_ERROR, "picture data too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- slice_width_factor = buf[7] >> 4;
- slice_height_factor = buf[7] & 0xF;
- if (slice_width_factor > 3 || slice_height_factor) {
- av_log(avctx, AV_LOG_ERROR,
- "unsupported slice dimension: %d x %d\n",
- 1 << slice_width_factor, 1 << slice_height_factor);
- return AVERROR_INVALIDDATA;
- }
-
- ctx->slice_width_factor = slice_width_factor;
- ctx->slice_height_factor = slice_height_factor;
-
- ctx->num_x_mbs = (avctx->width + 15) >> 4;
- ctx->num_y_mbs = (avctx->height +
- (1 << (4 + ctx->frame->interlaced_frame)) - 1) >>
- (4 + ctx->frame->interlaced_frame);
-
- remainder = ctx->num_x_mbs & ((1 << slice_width_factor) - 1);
- num_x_slices = (ctx->num_x_mbs >> slice_width_factor) + (remainder & 1) +
- ((remainder >> 1) & 1) + ((remainder >> 2) & 1);
-
- num_slices = num_x_slices * ctx->num_y_mbs;
- if (num_slices != AV_RB16(buf + 5)) {
- av_log(avctx, AV_LOG_ERROR, "invalid number of slices\n");
- return AVERROR_INVALIDDATA;
- }
-
- if (ctx->total_slices != num_slices) {
- av_freep(&ctx->slice_data);
- ctx->slice_data = av_malloc((num_slices + 1) * sizeof(ctx->slice_data[0]));
- if (!ctx->slice_data)
- return AVERROR(ENOMEM);
- ctx->total_slices = num_slices;
- }
-
- if (hdr_size + num_slices * 2 > data_size) {
- av_log(avctx, AV_LOG_ERROR, "slice table too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- /* parse slice table allowing quick access to the slice data */
- index_ptr = buf + hdr_size;
- data_ptr = index_ptr + num_slices * 2;
-
- for (i = 0; i < num_slices; i++) {
- ctx->slice_data[i].index = data_ptr;
- ctx->slice_data[i].prev_slice_sf = 0;
- data_ptr += AV_RB16(index_ptr + i * 2);
- }
- ctx->slice_data[i].index = data_ptr;
- ctx->slice_data[i].prev_slice_sf = 0;
-
- if (data_ptr > buf + data_size) {
- av_log(avctx, AV_LOG_ERROR, "out of slice data\n");
- return -1;
- }
-
- return pic_data_size;
-}
-
-
-/**
- * Read an unsigned rice/exp golomb codeword.
- */
-static inline int decode_vlc_codeword(GetBitContext *gb, unsigned codebook)
-{
- unsigned int rice_order, exp_order, switch_bits;
- unsigned int buf, code;
- int log, prefix_len, len;
-
- OPEN_READER(re, gb);
- UPDATE_CACHE(re, gb);
- buf = GET_CACHE(re, gb);
-
- /* number of prefix bits to switch between Rice and expGolomb */
- switch_bits = (codebook & 3) + 1;
- rice_order = codebook >> 5; /* rice code order */
- exp_order = (codebook >> 2) & 7; /* exp golomb code order */
-
- log = 31 - av_log2(buf); /* count prefix bits (zeroes) */
-
- if (log < switch_bits) { /* ok, we got a rice code */
- if (!rice_order) {
- /* shortcut for faster decoding of rice codes without remainder */
- code = log;
- LAST_SKIP_BITS(re, gb, log + 1);
- } else {
- prefix_len = log + 1;
- code = (log << rice_order) + NEG_USR32(buf << prefix_len, rice_order);
- LAST_SKIP_BITS(re, gb, prefix_len + rice_order);
- }
- } else { /* otherwise we got a exp golomb code */
- len = (log << 1) - switch_bits + exp_order + 1;
- code = NEG_USR32(buf, len) - (1 << exp_order) + (switch_bits << rice_order);
- LAST_SKIP_BITS(re, gb, len);
- }
-
- CLOSE_READER(re, gb);
-
- return code;
-}
-
-#define LSB2SIGN(x) (-((x) & 1))
-#define TOSIGNED(x) (((x) >> 1) ^ LSB2SIGN(x))
-
-/**
- * Decode DC coefficients for all blocks in a slice.
- */
-static inline void decode_dc_coeffs(GetBitContext *gb, int16_t *out,
- int nblocks)
-{
- int16_t prev_dc;
- int i, sign;
- int16_t delta;
- unsigned int code;
-
- code = decode_vlc_codeword(gb, FIRST_DC_CB);
- out[0] = prev_dc = TOSIGNED(code);
-
- out += 64; /* move to the DC coeff of the next block */
- delta = 3;
-
- for (i = 1; i < nblocks; i++, out += 64) {
- code = decode_vlc_codeword(gb, ff_prores_dc_codebook[FFMIN(FFABS(delta), 3)]);
-
- sign = -(((delta >> 15) & 1) ^ (code & 1));
- delta = (((code + 1) >> 1) ^ sign) - sign;
- prev_dc += delta;
- out[0] = prev_dc;
- }
-}
-
-#define MAX_PADDING 16
-
-/**
- * Decode AC coefficients for all blocks in a slice.
- */
-static inline int decode_ac_coeffs(GetBitContext *gb, int16_t *out,
- int blocks_per_slice,
- int plane_size_factor,
- const uint8_t *scan)
-{
- int pos, block_mask, run, level, sign, run_cb_index, lev_cb_index;
- int max_coeffs, bits_left;
-
- /* set initial prediction values */
- run = 4;
- level = 2;
-
- max_coeffs = blocks_per_slice << 6;
- block_mask = blocks_per_slice - 1;
-
- for (pos = blocks_per_slice - 1; pos < max_coeffs;) {
- run_cb_index = ff_prores_run_to_cb_index[FFMIN(run, 15)];
- lev_cb_index = ff_prores_lev_to_cb_index[FFMIN(level, 9)];
-
- bits_left = get_bits_left(gb);
- if (bits_left <= 0 || (bits_left <= MAX_PADDING && !show_bits(gb, bits_left)))
- return 0;
-
- run = decode_vlc_codeword(gb, ff_prores_ac_codebook[run_cb_index]);
- if (run < 0)
- return AVERROR_INVALIDDATA;
-
- bits_left = get_bits_left(gb);
- if (bits_left <= 0 || (bits_left <= MAX_PADDING && !show_bits(gb, bits_left)))
- return AVERROR_INVALIDDATA;
-
- level = decode_vlc_codeword(gb, ff_prores_ac_codebook[lev_cb_index]) + 1;
- if (level < 0)
- return AVERROR_INVALIDDATA;
-
- pos += run + 1;
- if (pos >= max_coeffs)
- break;
-
- sign = get_sbits(gb, 1);
- out[((pos & block_mask) << 6) + scan[pos >> plane_size_factor]] =
- (level ^ sign) - sign;
- }
-
- return 0;
-}
-
-
-/**
- * Decode a slice plane (luma or chroma).
- */
-static int decode_slice_plane(ProresContext *ctx, ProresThreadData *td,
- const uint8_t *buf,
- int data_size, uint16_t *out_ptr,
- int linesize, int mbs_per_slice,
- int blocks_per_mb, int plane_size_factor,
- const int16_t *qmat, int is_chroma)
-{
- GetBitContext gb;
- int16_t *block_ptr;
- int mb_num, blocks_per_slice, ret;
-
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
-
- memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
-
- init_get_bits(&gb, buf, data_size << 3);
-
- decode_dc_coeffs(&gb, td->blocks, blocks_per_slice);
-
- ret = decode_ac_coeffs(&gb, td->blocks, blocks_per_slice,
- plane_size_factor, ctx->scantable.permutated);
- if (ret < 0)
- return ret;
-
- /* inverse quantization, inverse transform and output */
- block_ptr = td->blocks;
-
- if (!is_chroma) {
- for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
- ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
- block_ptr += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- }
- ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
- block_ptr += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- }
- }
- } else {
- for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
- ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
- block_ptr += 64;
- ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
- block_ptr += 64;
- if (blocks_per_mb > 2) {
- ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
- block_ptr += 64;
- }
- }
- }
- return 0;
-}
-
-
-static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
- const int num_bits)
-{
- const int mask = (1 << num_bits) - 1;
- int i, idx, val, alpha_val;
-
- idx = 0;
- alpha_val = mask;
- do {
- do {
- if (get_bits1(gb))
- val = get_bits(gb, num_bits);
- else {
- int sign;
- val = get_bits(gb, num_bits == 16 ? 7 : 4);
- sign = val & 1;
- val = (val + 2) >> 1;
- if (sign)
- val = -val;
- }
- alpha_val = (alpha_val + val) & mask;
- if (num_bits == 16)
- dst[idx++] = alpha_val >> 6;
- else
- dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
- if (idx >= num_coeffs - 1)
- break;
- } while (get_bits1(gb));
- val = get_bits(gb, 4);
- if (!val)
- val = get_bits(gb, 11);
- if (idx + val > num_coeffs)
- val = num_coeffs - idx;
- if (num_bits == 16)
- for (i = 0; i < val; i++)
- dst[idx++] = alpha_val >> 6;
- else
- for (i = 0; i < val; i++)
- dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
- } while (idx < num_coeffs);
-}
-
-/**
- * Decode alpha slice plane.
- */
-static void decode_alpha_plane(ProresContext *ctx, ProresThreadData *td,
- const uint8_t *buf, int data_size,
- uint16_t *out_ptr, int linesize,
- int mbs_per_slice)
-{
- GetBitContext gb;
- int i;
- uint16_t *block_ptr;
-
- memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
-
- init_get_bits(&gb, buf, data_size << 3);
-
- if (ctx->alpha_info == 2)
- unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 16);
- else
- unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 8);
-
- block_ptr = td->blocks;
-
- for (i = 0; i < 16; i++) {
- memcpy(out_ptr, block_ptr, 16 * mbs_per_slice * sizeof(*out_ptr));
- out_ptr += linesize >> 1;
- block_ptr += 16 * mbs_per_slice;
- }
-}
-
-static int decode_slice(AVCodecContext *avctx, void *tdata)
-{
- ProresThreadData *td = tdata;
- ProresContext *ctx = avctx->priv_data;
- int mb_x_pos = td->x_pos;
- int mb_y_pos = td->y_pos;
- int pic_num = ctx->pic_num;
- int slice_num = td->slice_num;
- int mbs_per_slice = td->slice_width;
- const uint8_t *buf;
- uint8_t *y_data, *u_data, *v_data, *a_data;
- AVFrame *pic = ctx->frame;
- int i, sf, slice_width_factor;
- int slice_data_size, hdr_size;
- int y_data_size, u_data_size, v_data_size, a_data_size;
- int y_linesize, u_linesize, v_linesize, a_linesize;
- int coff[4];
- int ret;
-
- buf = ctx->slice_data[slice_num].index;
- slice_data_size = ctx->slice_data[slice_num + 1].index - buf;
-
- slice_width_factor = av_log2(mbs_per_slice);
-
- y_data = pic->data[0];
- u_data = pic->data[1];
- v_data = pic->data[2];
- a_data = pic->data[3];
- y_linesize = pic->linesize[0];
- u_linesize = pic->linesize[1];
- v_linesize = pic->linesize[2];
- a_linesize = pic->linesize[3];
-
- if (pic->interlaced_frame) {
- if (!(pic_num ^ pic->top_field_first)) {
- y_data += y_linesize;
- u_data += u_linesize;
- v_data += v_linesize;
- if (a_data)
- a_data += a_linesize;
- }
- y_linesize <<= 1;
- u_linesize <<= 1;
- v_linesize <<= 1;
- a_linesize <<= 1;
- }
- y_data += (mb_y_pos << 4) * y_linesize + (mb_x_pos << 5);
- u_data += (mb_y_pos << 4) * u_linesize + (mb_x_pos << ctx->mb_chroma_factor);
- v_data += (mb_y_pos << 4) * v_linesize + (mb_x_pos << ctx->mb_chroma_factor);
- if (a_data)
- a_data += (mb_y_pos << 4) * a_linesize + (mb_x_pos << 5);
-
- if (slice_data_size < 6) {
- av_log(avctx, AV_LOG_ERROR, "slice data too small\n");
- return AVERROR_INVALIDDATA;
- }
-
- /* parse slice header */
- hdr_size = buf[0] >> 3;
- coff[0] = hdr_size;
- y_data_size = AV_RB16(buf + 2);
- coff[1] = coff[0] + y_data_size;
- u_data_size = AV_RB16(buf + 4);
- coff[2] = coff[1] + u_data_size;
- v_data_size = hdr_size > 7 ? AV_RB16(buf + 6) : slice_data_size - coff[2];
- coff[3] = coff[2] + v_data_size;
- a_data_size = slice_data_size - coff[3];
-
- /* if V or alpha component size is negative that means that previous
- component sizes are too large */
- if (v_data_size < 0 || a_data_size < 0 || hdr_size < 6) {
- av_log(avctx, AV_LOG_ERROR, "invalid data size\n");
- return AVERROR_INVALIDDATA;
- }
-
- sf = av_clip(buf[1], 1, 224);
- sf = sf > 128 ? (sf - 96) << 2 : sf;
-
- /* scale quantization matrixes according with slice's scale factor */
- /* TODO: this can be SIMD-optimized a lot */
- if (ctx->qmat_changed || sf != td->prev_slice_sf) {
- td->prev_slice_sf = sf;
- for (i = 0; i < 64; i++) {
- td->qmat_luma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_luma[i] * sf;
- td->qmat_chroma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_chroma[i] * sf;
- }
- }
-
- /* decode luma plane */
- ret = decode_slice_plane(ctx, td, buf + coff[0], y_data_size,
- (uint16_t*) y_data, y_linesize,
- mbs_per_slice, 4, slice_width_factor + 2,
- td->qmat_luma_scaled, 0);
-
- if (ret < 0)
- return ret;
-
- /* decode U chroma plane */
- ret = decode_slice_plane(ctx, td, buf + coff[1], u_data_size,
- (uint16_t*) u_data, u_linesize,
- mbs_per_slice, ctx->num_chroma_blocks,
- slice_width_factor + ctx->chroma_factor - 1,
- td->qmat_chroma_scaled, 1);
- if (ret < 0)
- return ret;
-
- /* decode V chroma plane */
- ret = decode_slice_plane(ctx, td, buf + coff[2], v_data_size,
- (uint16_t*) v_data, v_linesize,
- mbs_per_slice, ctx->num_chroma_blocks,
- slice_width_factor + ctx->chroma_factor - 1,
- td->qmat_chroma_scaled, 1);
- if (ret < 0)
- return ret;
-
- /* decode alpha plane if available */
- if (a_data && a_data_size)
- decode_alpha_plane(ctx, td, buf + coff[3], a_data_size,
- (uint16_t*) a_data, a_linesize,
- mbs_per_slice);
-
- return 0;
-}
-
-
-static int decode_picture(ProresContext *ctx, int pic_num,
- AVCodecContext *avctx)
-{
- int slice_num, slice_width, x_pos, y_pos;
-
- slice_num = 0;
-
- ctx->pic_num = pic_num;
- for (y_pos = 0; y_pos < ctx->num_y_mbs; y_pos++) {
- slice_width = 1 << ctx->slice_width_factor;
-
- for (x_pos = 0; x_pos < ctx->num_x_mbs && slice_width;
- x_pos += slice_width) {
- while (ctx->num_x_mbs - x_pos < slice_width)
- slice_width >>= 1;
-
- ctx->slice_data[slice_num].slice_num = slice_num;
- ctx->slice_data[slice_num].x_pos = x_pos;
- ctx->slice_data[slice_num].y_pos = y_pos;
- ctx->slice_data[slice_num].slice_width = slice_width;
-
- slice_num++;
- }
- }
-
- return avctx->execute(avctx, decode_slice,
- ctx->slice_data, NULL, slice_num,
- sizeof(ctx->slice_data[0]));
-}
-
-
-#define MOVE_DATA_PTR(nbytes) buf += (nbytes); buf_size -= (nbytes)
-
-static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
- AVPacket *avpkt)
-{
- ProresContext *ctx = avctx->priv_data;
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
- int frame_hdr_size, pic_num, pic_data_size;
-
- ctx->frame = data;
- ctx->frame->pict_type = AV_PICTURE_TYPE_I;
- ctx->frame->key_frame = 1;
-
- /* check frame atom container */
- if (buf_size < 28 || buf_size < AV_RB32(buf) ||
- AV_RB32(buf + 4) != FRAME_ID) {
- av_log(avctx, AV_LOG_ERROR, "invalid frame\n");
- return AVERROR_INVALIDDATA;
- }
-
- MOVE_DATA_PTR(8);
-
- frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
- if (frame_hdr_size < 0)
- return AVERROR_INVALIDDATA;
-
- MOVE_DATA_PTR(frame_hdr_size);
-
- if (ff_get_buffer(avctx, ctx->frame, 0) < 0)
- return -1;
-
- for (pic_num = 0; ctx->frame->interlaced_frame - pic_num + 1; pic_num++) {
- pic_data_size = decode_picture_header(ctx, buf, buf_size, avctx);
- if (pic_data_size < 0)
- return AVERROR_INVALIDDATA;
-
- if (decode_picture(ctx, pic_num, avctx))
- return -1;
-
- MOVE_DATA_PTR(pic_data_size);
- }
-
- ctx->frame = NULL;
- *got_frame = 1;
-
- return avpkt->size;
-}
-
-
-static av_cold int decode_close(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
-
- av_freep(&ctx->slice_data);
-
- return 0;
-}
-
-
-AVCodec ff_prores_decoder = {
- .name = "prores",
- .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_PRORES,
- .priv_data_size = sizeof(ProresContext),
- .init = decode_init,
- .close = decode_close,
- .decode = decode_frame,
- .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
-};
diff --git a/libavcodec/proresdec.h b/libavcodec/proresdec.h
new file mode 100644
index 0000000000..14ede5d16b
--- /dev/null
+++ b/libavcodec/proresdec.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2010-2011 Maxim Poliakovski
+ * Copyright (c) 2010-2011 Elvis Presley
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_PRORESDEC_H
+#define AVCODEC_PRORESDEC_H
+
+#include "blockdsp.h"
+#include "proresdsp.h"
+
+typedef struct {
+ const uint8_t *data;
+ unsigned mb_x;
+ unsigned mb_y;
+ unsigned mb_count;
+ unsigned data_size;
+ int ret;
+} SliceContext;
+
+typedef struct {
+ BlockDSPContext bdsp;
+ ProresDSPContext prodsp;
+ AVFrame *frame;
+ int frame_type; ///< 0 = progressive, 1 = tff, 2 = bff
+ uint8_t qmat_luma[64];
+ uint8_t qmat_chroma[64];
+ SliceContext *slices;
+ int slice_count; ///< number of slices in the current picture
+ unsigned mb_width; ///< width of the current picture in mb
+ unsigned mb_height; ///< height of the current picture in mb
+ uint8_t progressive_scan[64];
+ uint8_t interlaced_scan[64];
+ const uint8_t *scan;
+ int first_field;
+ int alpha_info;
+} ProresContext;
+
+#endif /* AVCODEC_PRORESDEC_H */
diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c
new file mode 100644
index 0000000000..a1d497f049
--- /dev/null
+++ b/libavcodec/proresdec2.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2010-2011 Maxim Poliakovski
+ * Copyright (c) 2010-2011 Elvis Presley
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Known FOURCCs: 'apch' (HQ), 'apcn' (SD), 'apcs' (LT), 'acpo' (Proxy), 'ap4h' (4444)
+ */
+
+//#define DEBUG
+
+#define LONG_BITSTREAM_READER
+
+#include "avcodec.h"
+#include "get_bits.h"
+#include "idctdsp.h"
+#include "internal.h"
+#include "simple_idct.h"
+#include "proresdec.h"
+#include "proresdata.h"
+
+static void permute(uint8_t *dst, const uint8_t *src, const uint8_t permutation[64])
+{
+ int i;
+ for (i = 0; i < 64; i++)
+ dst[i] = permutation[src[i]];
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ uint8_t idct_permutation[64];
+
+ avctx->bits_per_raw_sample = 10;
+
+ ff_blockdsp_init(&ctx->bdsp, avctx);
+ ff_proresdsp_init(&ctx->prodsp, avctx);
+
+ ff_init_scantable_permutation(idct_permutation,
+ ctx->prodsp.idct_permutation_type);
+
+ permute(ctx->progressive_scan, ff_prores_progressive_scan, idct_permutation);
+ permute(ctx->interlaced_scan, ff_prores_interlaced_scan, idct_permutation);
+
+ return 0;
+}
+
+static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
+ const int data_size, AVCodecContext *avctx)
+{
+ int hdr_size, width, height, flags;
+ int version;
+ const uint8_t *ptr;
+
+ hdr_size = AV_RB16(buf);
+ av_dlog(avctx, "header size %d\n", hdr_size);
+ if (hdr_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "error, wrong header size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ version = AV_RB16(buf + 2);
+ av_dlog(avctx, "%.4s version %d\n", buf+4, version);
+ if (version > 1) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported version: %d\n", version);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ width = AV_RB16(buf + 8);
+ height = AV_RB16(buf + 10);
+ if (width != avctx->width || height != avctx->height) {
+ av_log(avctx, AV_LOG_ERROR, "picture resolution change: %dx%d -> %dx%d\n",
+ avctx->width, avctx->height, width, height);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ ctx->frame_type = (buf[12] >> 2) & 3;
+ ctx->alpha_info = buf[17] & 0xf;
+
+ if (ctx->alpha_info > 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid alpha mode %d\n", ctx->alpha_info);
+ return AVERROR_INVALIDDATA;
+ }
+ if (avctx->skip_alpha) ctx->alpha_info = 0;
+
+ av_dlog(avctx, "frame type %d\n", ctx->frame_type);
+
+ if (ctx->frame_type == 0) {
+ ctx->scan = ctx->progressive_scan; // permuted
+ } else {
+ ctx->scan = ctx->interlaced_scan; // permuted
+ ctx->frame->interlaced_frame = 1;
+ ctx->frame->top_field_first = ctx->frame_type == 1;
+ }
+
+ if (ctx->alpha_info) {
+ avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P10 : AV_PIX_FMT_YUVA422P10;
+ } else {
+ avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P10 : AV_PIX_FMT_YUV422P10;
+ }
+
+ ptr = buf + 20;
+ flags = buf[19];
+ av_dlog(avctx, "flags %x\n", flags);
+
+ if (flags & 2) {
+ if(buf + data_size - ptr < 64) {
+ av_log(avctx, AV_LOG_ERROR, "Header truncated\n");
+ return AVERROR_INVALIDDATA;
+ }
+ permute(ctx->qmat_luma, ctx->prodsp.idct_permutation, ptr);
+ ptr += 64;
+ } else {
+ memset(ctx->qmat_luma, 4, 64);
+ }
+
+ if (flags & 1) {
+ if(buf + data_size - ptr < 64) {
+ av_log(avctx, AV_LOG_ERROR, "Header truncated\n");
+ return AVERROR_INVALIDDATA;
+ }
+ permute(ctx->qmat_chroma, ctx->prodsp.idct_permutation, ptr);
+ } else {
+ memset(ctx->qmat_chroma, 4, 64);
+ }
+
+ return hdr_size;
+}
+
+static int decode_picture_header(AVCodecContext *avctx, const uint8_t *buf, const int buf_size)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i, hdr_size, slice_count;
+ unsigned pic_data_size;
+ int log2_slice_mb_width, log2_slice_mb_height;
+ int slice_mb_count, mb_x, mb_y;
+ const uint8_t *data_ptr, *index_ptr;
+
+ hdr_size = buf[0] >> 3;
+ if (hdr_size < 8 || hdr_size > buf_size) {
+ av_log(avctx, AV_LOG_ERROR, "error, wrong picture header size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ pic_data_size = AV_RB32(buf + 1);
+ if (pic_data_size > buf_size) {
+ av_log(avctx, AV_LOG_ERROR, "error, wrong picture data size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ log2_slice_mb_width = buf[7] >> 4;
+ log2_slice_mb_height = buf[7] & 0xF;
+ if (log2_slice_mb_width > 3 || log2_slice_mb_height) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported slice resolution: %dx%d\n",
+ 1 << log2_slice_mb_width, 1 << log2_slice_mb_height);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->mb_width = (avctx->width + 15) >> 4;
+ if (ctx->frame_type)
+ ctx->mb_height = (avctx->height + 31) >> 5;
+ else
+ ctx->mb_height = (avctx->height + 15) >> 4;
+
+ slice_count = AV_RB16(buf + 5);
+
+ if (ctx->slice_count != slice_count || !ctx->slices) {
+ av_freep(&ctx->slices);
+ ctx->slice_count = 0;
+ ctx->slices = av_mallocz_array(slice_count, sizeof(*ctx->slices));
+ if (!ctx->slices)
+ return AVERROR(ENOMEM);
+ ctx->slice_count = slice_count;
+ }
+
+ if (!slice_count)
+ return AVERROR(EINVAL);
+
+ if (hdr_size + slice_count*2 > buf_size) {
+ av_log(avctx, AV_LOG_ERROR, "error, wrong slice count\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ // parse slice information
+ index_ptr = buf + hdr_size;
+ data_ptr = index_ptr + slice_count*2;
+
+ slice_mb_count = 1 << log2_slice_mb_width;
+ mb_x = 0;
+ mb_y = 0;
+
+ for (i = 0; i < slice_count; i++) {
+ SliceContext *slice = &ctx->slices[i];
+
+ slice->data = data_ptr;
+ data_ptr += AV_RB16(index_ptr + i*2);
+
+ while (ctx->mb_width - mb_x < slice_mb_count)
+ slice_mb_count >>= 1;
+
+ slice->mb_x = mb_x;
+ slice->mb_y = mb_y;
+ slice->mb_count = slice_mb_count;
+ slice->data_size = data_ptr - slice->data;
+
+ if (slice->data_size < 6) {
+ av_log(avctx, AV_LOG_ERROR, "error, wrong slice data size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ mb_x += slice_mb_count;
+ if (mb_x == ctx->mb_width) {
+ slice_mb_count = 1 << log2_slice_mb_width;
+ mb_x = 0;
+ mb_y++;
+ }
+ if (data_ptr > buf + buf_size) {
+ av_log(avctx, AV_LOG_ERROR, "error, slice out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (mb_x || mb_y != ctx->mb_height) {
+ av_log(avctx, AV_LOG_ERROR, "error wrong mb count y %d h %d\n",
+ mb_y, ctx->mb_height);
+ return AVERROR_INVALIDDATA;
+ }
+
+ return pic_data_size;
+}
+
+#define DECODE_CODEWORD(val, codebook) \
+ do { \
+ unsigned int rice_order, exp_order, switch_bits; \
+ unsigned int q, buf, bits; \
+ \
+ UPDATE_CACHE(re, gb); \
+ buf = GET_CACHE(re, gb); \
+ \
+ /* number of bits to switch between rice and exp golomb */ \
+ switch_bits = codebook & 3; \
+ rice_order = codebook >> 5; \
+ exp_order = (codebook >> 2) & 7; \
+ \
+ q = 31 - av_log2(buf); \
+ \
+ if (q > switch_bits) { /* exp golomb */ \
+ bits = exp_order - switch_bits + (q<<1); \
+ val = SHOW_UBITS(re, gb, bits) - (1 << exp_order) + \
+ ((switch_bits + 1) << rice_order); \
+ SKIP_BITS(re, gb, bits); \
+ } else if (rice_order) { \
+ SKIP_BITS(re, gb, q+1); \
+ val = (q << rice_order) + SHOW_UBITS(re, gb, rice_order); \
+ SKIP_BITS(re, gb, rice_order); \
+ } else { \
+ val = q; \
+ SKIP_BITS(re, gb, q+1); \
+ } \
+ } while (0)
+
+#define TOSIGNED(x) (((x) >> 1) ^ (-((x) & 1)))
+
+#define FIRST_DC_CB 0xB8
+
+static const uint8_t dc_codebook[7] = { 0x04, 0x28, 0x28, 0x4D, 0x4D, 0x70, 0x70};
+
+static av_always_inline void decode_dc_coeffs(GetBitContext *gb, int16_t *out,
+ int blocks_per_slice)
+{
+ int16_t prev_dc;
+ int code, i, sign;
+
+ OPEN_READER(re, gb);
+
+ DECODE_CODEWORD(code, FIRST_DC_CB);
+ prev_dc = TOSIGNED(code);
+ out[0] = prev_dc;
+
+ out += 64; // dc coeff for the next block
+
+ code = 5;
+ sign = 0;
+ for (i = 1; i < blocks_per_slice; i++, out += 64) {
+ DECODE_CODEWORD(code, dc_codebook[FFMIN(code, 6U)]);
+ if(code) sign ^= -(code & 1);
+ else sign = 0;
+ prev_dc += (((code + 1) >> 1) ^ sign) - sign;
+ out[0] = prev_dc;
+ }
+ CLOSE_READER(re, gb);
+}
+
+// adaptive codebook switching lut according to previous run/level values
+static const uint8_t run_to_cb[16] = { 0x06, 0x06, 0x05, 0x05, 0x04, 0x29, 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4C };
+static const uint8_t lev_to_cb[10] = { 0x04, 0x0A, 0x05, 0x06, 0x04, 0x28, 0x28, 0x28, 0x28, 0x4C };
+
+static av_always_inline int decode_ac_coeffs(AVCodecContext *avctx, GetBitContext *gb,
+ int16_t *out, int blocks_per_slice)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int block_mask, sign;
+ unsigned pos, run, level;
+ int max_coeffs, i, bits_left;
+ int log2_block_count = av_log2(blocks_per_slice);
+
+ OPEN_READER(re, gb);
+ UPDATE_CACHE(re, gb); \
+ run = 4;
+ level = 2;
+
+ max_coeffs = 64 << log2_block_count;
+ block_mask = blocks_per_slice - 1;
+
+ for (pos = block_mask;;) {
+ bits_left = gb->size_in_bits - re_index;
+ if (!bits_left || (bits_left < 32 && !SHOW_UBITS(re, gb, bits_left)))
+ break;
+
+ DECODE_CODEWORD(run, run_to_cb[FFMIN(run, 15)]);
+ pos += run + 1;
+ if (pos >= max_coeffs) {
+ av_log(avctx, AV_LOG_ERROR, "ac tex damaged %d, %d\n", pos, max_coeffs);
+ return AVERROR_INVALIDDATA;
+ }
+
+ DECODE_CODEWORD(level, lev_to_cb[FFMIN(level, 9)]);
+ level += 1;
+
+ i = pos >> log2_block_count;
+
+ sign = SHOW_SBITS(re, gb, 1);
+ SKIP_BITS(re, gb, 1);
+ out[((pos & block_mask) << 6) + ctx->scan[i]] = ((level ^ sign) - sign);
+ }
+
+ CLOSE_READER(re, gb);
+ return 0;
+}
+
+static int decode_slice_luma(AVCodecContext *avctx, SliceContext *slice,
+ uint16_t *dst, int dst_stride,
+ const uint8_t *buf, unsigned buf_size,
+ const int16_t *qmat)
+{
+ ProresContext *ctx = avctx->priv_data;
+ LOCAL_ALIGNED_16(int16_t, blocks, [8*4*64]);
+ int16_t *block;
+ GetBitContext gb;
+ int i, blocks_per_slice = slice->mb_count<<2;
+ int ret;
+
+ for (i = 0; i < blocks_per_slice; i++)
+ ctx->bdsp.clear_block(blocks+(i<<6));
+
+ init_get_bits(&gb, buf, buf_size << 3);
+
+ decode_dc_coeffs(&gb, blocks, blocks_per_slice);
+ if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0)
+ return ret;
+
+ block = blocks;
+ for (i = 0; i < slice->mb_count; i++) {
+ ctx->prodsp.idct_put(dst, dst_stride, block+(0<<6), qmat);
+ ctx->prodsp.idct_put(dst +8, dst_stride, block+(1<<6), qmat);
+ ctx->prodsp.idct_put(dst+4*dst_stride , dst_stride, block+(2<<6), qmat);
+ ctx->prodsp.idct_put(dst+4*dst_stride+8, dst_stride, block+(3<<6), qmat);
+ block += 4*64;
+ dst += 16;
+ }
+ return 0;
+}
+
+static int decode_slice_chroma(AVCodecContext *avctx, SliceContext *slice,
+ uint16_t *dst, int dst_stride,
+ const uint8_t *buf, unsigned buf_size,
+ const int16_t *qmat, int log2_blocks_per_mb)
+{
+ ProresContext *ctx = avctx->priv_data;
+ LOCAL_ALIGNED_16(int16_t, blocks, [8*4*64]);
+ int16_t *block;
+ GetBitContext gb;
+ int i, j, blocks_per_slice = slice->mb_count << log2_blocks_per_mb;
+ int ret;
+
+ for (i = 0; i < blocks_per_slice; i++)
+ ctx->bdsp.clear_block(blocks+(i<<6));
+
+ init_get_bits(&gb, buf, buf_size << 3);
+
+ decode_dc_coeffs(&gb, blocks, blocks_per_slice);
+ if ((ret = decode_ac_coeffs(avctx, &gb, blocks, blocks_per_slice)) < 0)
+ return ret;
+
+ block = blocks;
+ for (i = 0; i < slice->mb_count; i++) {
+ for (j = 0; j < log2_blocks_per_mb; j++) {
+ ctx->prodsp.idct_put(dst, dst_stride, block+(0<<6), qmat);
+ ctx->prodsp.idct_put(dst+4*dst_stride, dst_stride, block+(1<<6), qmat);
+ block += 2*64;
+ dst += 8;
+ }
+ }
+ return 0;
+}
+
+static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
+ const int num_bits)
+{
+ const int mask = (1 << num_bits) - 1;
+ int i, idx, val, alpha_val;
+
+ idx = 0;
+ alpha_val = mask;
+ do {
+ do {
+ if (get_bits1(gb)) {
+ val = get_bits(gb, num_bits);
+ } else {
+ int sign;
+ val = get_bits(gb, num_bits == 16 ? 7 : 4);
+ sign = val & 1;
+ val = (val + 2) >> 1;
+ if (sign)
+ val = -val;
+ }
+ alpha_val = (alpha_val + val) & mask;
+ if (num_bits == 16) {
+ dst[idx++] = alpha_val >> 6;
+ } else {
+ dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
+ }
+ if (idx >= num_coeffs)
+ break;
+ } while (get_bits_left(gb)>0 && get_bits1(gb));
+ val = get_bits(gb, 4);
+ if (!val)
+ val = get_bits(gb, 11);
+ if (idx + val > num_coeffs)
+ val = num_coeffs - idx;
+ if (num_bits == 16) {
+ for (i = 0; i < val; i++)
+ dst[idx++] = alpha_val >> 6;
+ } else {
+ for (i = 0; i < val; i++)
+ dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
+
+ }
+ } while (idx < num_coeffs);
+}
+
+/**
+ * Decode alpha slice plane.
+ */
+static void decode_slice_alpha(ProresContext *ctx,
+ uint16_t *dst, int dst_stride,
+ const uint8_t *buf, int buf_size,
+ int blocks_per_slice)
+{
+ GetBitContext gb;
+ int i;
+ LOCAL_ALIGNED_16(int16_t, blocks, [8*4*64]);
+ int16_t *block;
+
+ for (i = 0; i < blocks_per_slice<<2; i++)
+ ctx->bdsp.clear_block(blocks+(i<<6));
+
+ init_get_bits(&gb, buf, buf_size << 3);
+
+ if (ctx->alpha_info == 2) {
+ unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 16);
+ } else {
+ unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 8);
+ }
+
+ block = blocks;
+ for (i = 0; i < 16; i++) {
+ memcpy(dst, block, 16 * blocks_per_slice * sizeof(*dst));
+ dst += dst_stride >> 1;
+ block += 16 * blocks_per_slice;
+ }
+}
+
+static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int threadnr)
+{
+ ProresContext *ctx = avctx->priv_data;
+ SliceContext *slice = &ctx->slices[jobnr];
+ const uint8_t *buf = slice->data;
+ AVFrame *pic = ctx->frame;
+ int i, hdr_size, qscale, log2_chroma_blocks_per_mb;
+ int luma_stride, chroma_stride;
+ int y_data_size, u_data_size, v_data_size, a_data_size;
+ uint8_t *dest_y, *dest_u, *dest_v, *dest_a;
+ int16_t qmat_luma_scaled[64];
+ int16_t qmat_chroma_scaled[64];
+ int mb_x_shift;
+ int ret;
+
+ slice->ret = -1;
+ //av_log(avctx, AV_LOG_INFO, "slice %d mb width %d mb x %d y %d\n",
+ // jobnr, slice->mb_count, slice->mb_x, slice->mb_y);
+
+ // slice header
+ hdr_size = buf[0] >> 3;
+ qscale = av_clip(buf[1], 1, 224);
+ qscale = qscale > 128 ? qscale - 96 << 2: qscale;
+ y_data_size = AV_RB16(buf + 2);
+ u_data_size = AV_RB16(buf + 4);
+ v_data_size = slice->data_size - y_data_size - u_data_size - hdr_size;
+ if (hdr_size > 7) v_data_size = AV_RB16(buf + 6);
+ a_data_size = slice->data_size - y_data_size - u_data_size -
+ v_data_size - hdr_size;
+
+ if (y_data_size < 0 || u_data_size < 0 || v_data_size < 0
+ || hdr_size+y_data_size+u_data_size+v_data_size > slice->data_size){
+ av_log(avctx, AV_LOG_ERROR, "invalid plane data size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ buf += hdr_size;
+
+ for (i = 0; i < 64; i++) {
+ qmat_luma_scaled [i] = ctx->qmat_luma [i] * qscale;
+ qmat_chroma_scaled[i] = ctx->qmat_chroma[i] * qscale;
+ }
+
+ if (ctx->frame_type == 0) {
+ luma_stride = pic->linesize[0];
+ chroma_stride = pic->linesize[1];
+ } else {
+ luma_stride = pic->linesize[0] << 1;
+ chroma_stride = pic->linesize[1] << 1;
+ }
+
+ if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) {
+ mb_x_shift = 5;
+ log2_chroma_blocks_per_mb = 2;
+ } else {
+ mb_x_shift = 4;
+ log2_chroma_blocks_per_mb = 1;
+ }
+
+ dest_y = pic->data[0] + (slice->mb_y << 4) * luma_stride + (slice->mb_x << 5);
+ dest_u = pic->data[1] + (slice->mb_y << 4) * chroma_stride + (slice->mb_x << mb_x_shift);
+ dest_v = pic->data[2] + (slice->mb_y << 4) * chroma_stride + (slice->mb_x << mb_x_shift);
+ dest_a = pic->data[3] + (slice->mb_y << 4) * luma_stride + (slice->mb_x << 5);
+
+ if (ctx->frame_type && ctx->first_field ^ ctx->frame->top_field_first) {
+ dest_y += pic->linesize[0];
+ dest_u += pic->linesize[1];
+ dest_v += pic->linesize[2];
+ dest_a += pic->linesize[3];
+ }
+
+ ret = decode_slice_luma(avctx, slice, (uint16_t*)dest_y, luma_stride,
+ buf, y_data_size, qmat_luma_scaled);
+ if (ret < 0)
+ return ret;
+
+ if (!(avctx->flags & CODEC_FLAG_GRAY)) {
+ ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_u, chroma_stride,
+ buf + y_data_size, u_data_size,
+ qmat_chroma_scaled, log2_chroma_blocks_per_mb);
+ if (ret < 0)
+ return ret;
+
+ ret = decode_slice_chroma(avctx, slice, (uint16_t*)dest_v, chroma_stride,
+ buf + y_data_size + u_data_size, v_data_size,
+ qmat_chroma_scaled, log2_chroma_blocks_per_mb);
+ if (ret < 0)
+ return ret;
+ }
+ /* decode alpha plane if available */
+ if (ctx->alpha_info && pic->data[3] && a_data_size)
+ decode_slice_alpha(ctx, (uint16_t*)dest_a, luma_stride,
+ buf + y_data_size + u_data_size + v_data_size,
+ a_data_size, slice->mb_count);
+
+ slice->ret = 0;
+ return 0;
+}
+
+static int decode_picture(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i;
+
+ avctx->execute2(avctx, decode_slice_thread, NULL, NULL, ctx->slice_count);
+
+ for (i = 0; i < ctx->slice_count; i++)
+ if (ctx->slices[i].ret < 0)
+ return ctx->slices[i].ret;
+
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ ProresContext *ctx = avctx->priv_data;
+ AVFrame *frame = data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int frame_hdr_size, pic_size, ret;
+
+ if (buf_size < 28 || AV_RL32(buf + 4) != AV_RL32("icpf")) {
+ av_log(avctx, AV_LOG_ERROR, "invalid frame header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->frame = frame;
+ ctx->frame->pict_type = AV_PICTURE_TYPE_I;
+ ctx->frame->key_frame = 1;
+ ctx->first_field = 1;
+
+ buf += 8;
+ buf_size -= 8;
+
+ frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
+ if (frame_hdr_size < 0)
+ return frame_hdr_size;
+
+ buf += frame_hdr_size;
+ buf_size -= frame_hdr_size;
+
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ decode_picture:
+ pic_size = decode_picture_header(avctx, buf, buf_size);
+ if (pic_size < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding picture header\n");
+ return pic_size;
+ }
+
+ if ((ret = decode_picture(avctx)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding picture\n");
+ return ret;
+ }
+
+ buf += pic_size;
+ buf_size -= pic_size;
+
+ if (ctx->frame_type && buf_size > 0 && ctx->first_field) {
+ ctx->first_field = 0;
+ goto decode_picture;
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+static av_cold int decode_close(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+
+ av_freep(&ctx->slices);
+
+ return 0;
+}
+
+AVCodec ff_prores_decoder = {
+ .name = "prores",
+ .long_name = NULL_IF_CONFIG_SMALL("ProRes"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = decode_init,
+ .close = decode_close,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+};
diff --git a/libavcodec/proresdec_lgpl.c b/libavcodec/proresdec_lgpl.c
new file mode 100644
index 0000000000..4bdf392461
--- /dev/null
+++ b/libavcodec/proresdec_lgpl.c
@@ -0,0 +1,784 @@
+/*
+ * Apple ProRes compatible decoder
+ *
+ * Copyright (c) 2010-2011 Maxim Poliakovski
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * This is a decoder for Apple ProRes 422 SD/HQ/LT/Proxy and ProRes 4444.
+ * It is used for storing and editing high definition video data in Apple's Final Cut Pro.
+ *
+ * @see http://wiki.multimedia.cx/index.php?title=Apple_ProRes
+ */
+
+#define LONG_BITSTREAM_READER // some ProRes vlc codes require up to 28 bits to be read at once
+
+#include <stdint.h>
+
+#include "libavutil/intmath.h"
+#include "avcodec.h"
+#include "idctdsp.h"
+#include "internal.h"
+#include "proresdata.h"
+#include "proresdsp.h"
+#include "get_bits.h"
+
+typedef struct ProresThreadData {
+ const uint8_t *index; ///< pointers to the data of this slice
+ int slice_num;
+ int x_pos, y_pos;
+ int slice_width;
+ int prev_slice_sf; ///< scalefactor of the previous decoded slice
+ DECLARE_ALIGNED(16, int16_t, blocks)[8 * 4 * 64];
+ DECLARE_ALIGNED(16, int16_t, qmat_luma_scaled)[64];
+ DECLARE_ALIGNED(16, int16_t, qmat_chroma_scaled)[64];
+} ProresThreadData;
+
+typedef struct ProresContext {
+ ProresDSPContext dsp;
+ AVFrame *frame;
+ ScanTable scantable;
+ int scantable_type; ///< -1 = uninitialized, 0 = progressive, 1/2 = interlaced
+
+ int frame_type; ///< 0 = progressive, 1 = top-field first, 2 = bottom-field first
+ int pic_format; ///< 2 = 422, 3 = 444
+ uint8_t qmat_luma[64]; ///< dequantization matrix for luma
+ uint8_t qmat_chroma[64]; ///< dequantization matrix for chroma
+ int qmat_changed; ///< 1 - global quantization matrices changed
+ int total_slices; ///< total number of slices in a picture
+ ProresThreadData *slice_data;
+ int pic_num;
+ int chroma_factor;
+ int mb_chroma_factor;
+ int num_chroma_blocks; ///< number of chrominance blocks in a macroblock
+ int num_x_slices;
+ int num_y_slices;
+ int slice_width_factor;
+ int slice_height_factor;
+ int num_x_mbs;
+ int num_y_mbs;
+ int alpha_info;
+} ProresContext;
+
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+
+ ctx->total_slices = 0;
+ ctx->slice_data = NULL;
+
+ avctx->bits_per_raw_sample = PRORES_BITS_PER_SAMPLE;
+ ff_proresdsp_init(&ctx->dsp, avctx);
+
+ ctx->scantable_type = -1; // set scantable type to uninitialized
+ memset(ctx->qmat_luma, 4, 64);
+ memset(ctx->qmat_chroma, 4, 64);
+
+ return 0;
+}
+
+
+static int decode_frame_header(ProresContext *ctx, const uint8_t *buf,
+ const int data_size, AVCodecContext *avctx)
+{
+ int hdr_size, version, width, height, flags;
+ const uint8_t *ptr;
+
+ hdr_size = AV_RB16(buf);
+ if (hdr_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "frame data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ version = AV_RB16(buf + 2);
+ if (version >= 2) {
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported header version: %d\n", version);
+ return AVERROR_INVALIDDATA;
+ }
+
+ width = AV_RB16(buf + 8);
+ height = AV_RB16(buf + 10);
+ if (width != avctx->width || height != avctx->height) {
+ av_log(avctx, AV_LOG_ERROR,
+ "picture dimension changed: old: %d x %d, new: %d x %d\n",
+ avctx->width, avctx->height, width, height);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->frame_type = (buf[12] >> 2) & 3;
+ if (ctx->frame_type > 2) {
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported frame type: %d\n", ctx->frame_type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->chroma_factor = (buf[12] >> 6) & 3;
+ ctx->mb_chroma_factor = ctx->chroma_factor + 2;
+ ctx->num_chroma_blocks = (1 << ctx->chroma_factor) >> 1;
+ ctx->alpha_info = buf[17] & 0xf;
+
+ if (ctx->alpha_info > 2) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid alpha mode %d\n", ctx->alpha_info);
+ return AVERROR_INVALIDDATA;
+ }
+ if (avctx->skip_alpha) ctx->alpha_info = 0;
+
+ switch (ctx->chroma_factor) {
+ case 2:
+ avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA422P10
+ : AV_PIX_FMT_YUV422P10;
+ break;
+ case 3:
+ avctx->pix_fmt = ctx->alpha_info ? AV_PIX_FMT_YUVA444P10
+ : AV_PIX_FMT_YUV444P10;
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported picture format: %d\n", ctx->pic_format);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (ctx->scantable_type != ctx->frame_type) {
+ if (!ctx->frame_type)
+ ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
+ ff_prores_progressive_scan);
+ else
+ ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable,
+ ff_prores_interlaced_scan);
+ ctx->scantable_type = ctx->frame_type;
+ }
+
+ if (ctx->frame_type) { /* if interlaced */
+ ctx->frame->interlaced_frame = 1;
+ ctx->frame->top_field_first = ctx->frame_type & 1;
+ } else {
+ ctx->frame->interlaced_frame = 0;
+ }
+
+ avctx->color_primaries = buf[14];
+ avctx->color_trc = buf[15];
+ avctx->colorspace = buf[16];
+
+ ctx->qmat_changed = 0;
+ ptr = buf + 20;
+ flags = buf[19];
+ if (flags & 2) {
+ if (ptr - buf > hdr_size - 64) {
+ av_log(avctx, AV_LOG_ERROR, "header data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (memcmp(ctx->qmat_luma, ptr, 64)) {
+ memcpy(ctx->qmat_luma, ptr, 64);
+ ctx->qmat_changed = 1;
+ }
+ ptr += 64;
+ } else {
+ memset(ctx->qmat_luma, 4, 64);
+ ctx->qmat_changed = 1;
+ }
+
+ if (flags & 1) {
+ if (ptr - buf > hdr_size - 64) {
+ av_log(avctx, AV_LOG_ERROR, "header data too small\n");
+ return -1;
+ }
+ if (memcmp(ctx->qmat_chroma, ptr, 64)) {
+ memcpy(ctx->qmat_chroma, ptr, 64);
+ ctx->qmat_changed = 1;
+ }
+ } else {
+ memset(ctx->qmat_chroma, 4, 64);
+ ctx->qmat_changed = 1;
+ }
+
+ return hdr_size;
+}
+
+
+static int decode_picture_header(ProresContext *ctx, const uint8_t *buf,
+ const int data_size, AVCodecContext *avctx)
+{
+ int i, hdr_size, pic_data_size, num_slices;
+ int slice_width_factor, slice_height_factor;
+ int remainder, num_x_slices;
+ const uint8_t *data_ptr, *index_ptr;
+
+ hdr_size = data_size > 0 ? buf[0] >> 3 : 0;
+ if (hdr_size < 8 || hdr_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "picture header too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ pic_data_size = AV_RB32(buf + 1);
+ if (pic_data_size > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "picture data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ slice_width_factor = buf[7] >> 4;
+ slice_height_factor = buf[7] & 0xF;
+ if (slice_width_factor > 3 || slice_height_factor) {
+ av_log(avctx, AV_LOG_ERROR,
+ "unsupported slice dimension: %d x %d\n",
+ 1 << slice_width_factor, 1 << slice_height_factor);
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->slice_width_factor = slice_width_factor;
+ ctx->slice_height_factor = slice_height_factor;
+
+ ctx->num_x_mbs = (avctx->width + 15) >> 4;
+ ctx->num_y_mbs = (avctx->height +
+ (1 << (4 + ctx->frame->interlaced_frame)) - 1) >>
+ (4 + ctx->frame->interlaced_frame);
+
+ remainder = ctx->num_x_mbs & ((1 << slice_width_factor) - 1);
+ num_x_slices = (ctx->num_x_mbs >> slice_width_factor) + (remainder & 1) +
+ ((remainder >> 1) & 1) + ((remainder >> 2) & 1);
+
+ num_slices = num_x_slices * ctx->num_y_mbs;
+ if (num_slices != AV_RB16(buf + 5)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid number of slices\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (ctx->total_slices != num_slices) {
+ av_freep(&ctx->slice_data);
+ ctx->slice_data = av_malloc_array(num_slices + 1, sizeof(ctx->slice_data[0]));
+ if (!ctx->slice_data)
+ return AVERROR(ENOMEM);
+ ctx->total_slices = num_slices;
+ }
+
+ if (hdr_size + num_slices * 2 > data_size) {
+ av_log(avctx, AV_LOG_ERROR, "slice table too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* parse slice table allowing quick access to the slice data */
+ index_ptr = buf + hdr_size;
+ data_ptr = index_ptr + num_slices * 2;
+
+ for (i = 0; i < num_slices; i++) {
+ ctx->slice_data[i].index = data_ptr;
+ ctx->slice_data[i].prev_slice_sf = 0;
+ data_ptr += AV_RB16(index_ptr + i * 2);
+ }
+ ctx->slice_data[i].index = data_ptr;
+ ctx->slice_data[i].prev_slice_sf = 0;
+
+ if (data_ptr > buf + data_size) {
+ av_log(avctx, AV_LOG_ERROR, "out of slice data\n");
+ return -1;
+ }
+
+ return pic_data_size;
+}
+
+
+/**
+ * Read an unsigned rice/exp golomb codeword.
+ */
+static inline int decode_vlc_codeword(GetBitContext *gb, unsigned codebook)
+{
+ unsigned int rice_order, exp_order, switch_bits;
+ unsigned int buf, code;
+ int log, prefix_len, len;
+
+ OPEN_READER(re, gb);
+ UPDATE_CACHE(re, gb);
+ buf = GET_CACHE(re, gb);
+
+ /* number of prefix bits to switch between Rice and expGolomb */
+ switch_bits = (codebook & 3) + 1;
+ rice_order = codebook >> 5; /* rice code order */
+ exp_order = (codebook >> 2) & 7; /* exp golomb code order */
+
+ log = 31 - av_log2(buf); /* count prefix bits (zeroes) */
+
+ if (log < switch_bits) { /* ok, we got a rice code */
+ if (!rice_order) {
+ /* shortcut for faster decoding of rice codes without remainder */
+ code = log;
+ LAST_SKIP_BITS(re, gb, log + 1);
+ } else {
+ prefix_len = log + 1;
+ code = (log << rice_order) + NEG_USR32(buf << prefix_len, rice_order);
+ LAST_SKIP_BITS(re, gb, prefix_len + rice_order);
+ }
+ } else { /* otherwise we got a exp golomb code */
+ len = (log << 1) - switch_bits + exp_order + 1;
+ code = NEG_USR32(buf, len) - (1 << exp_order) + (switch_bits << rice_order);
+ LAST_SKIP_BITS(re, gb, len);
+ }
+
+ CLOSE_READER(re, gb);
+
+ return code;
+}
+
+#define LSB2SIGN(x) (-((x) & 1))
+#define TOSIGNED(x) (((x) >> 1) ^ LSB2SIGN(x))
+
+/**
+ * Decode DC coefficients for all blocks in a slice.
+ */
+static inline void decode_dc_coeffs(GetBitContext *gb, int16_t *out,
+ int nblocks)
+{
+ int16_t prev_dc;
+ int i, sign;
+ int16_t delta;
+ unsigned int code;
+
+ code = decode_vlc_codeword(gb, FIRST_DC_CB);
+ out[0] = prev_dc = TOSIGNED(code);
+
+ out += 64; /* move to the DC coeff of the next block */
+ delta = 3;
+
+ for (i = 1; i < nblocks; i++, out += 64) {
+ code = decode_vlc_codeword(gb, ff_prores_dc_codebook[FFMIN(FFABS(delta), 3)]);
+
+ sign = -(((delta >> 15) & 1) ^ (code & 1));
+ delta = (((code + 1) >> 1) ^ sign) - sign;
+ prev_dc += delta;
+ out[0] = prev_dc;
+ }
+}
+
+#define MAX_PADDING 16
+
+/**
+ * Decode AC coefficients for all blocks in a slice.
+ */
+static inline int decode_ac_coeffs(GetBitContext *gb, int16_t *out,
+ int blocks_per_slice,
+ int plane_size_factor,
+ const uint8_t *scan)
+{
+ int pos, block_mask, run, level, sign, run_cb_index, lev_cb_index;
+ int max_coeffs, bits_left;
+
+ /* set initial prediction values */
+ run = 4;
+ level = 2;
+
+ max_coeffs = blocks_per_slice << 6;
+ block_mask = blocks_per_slice - 1;
+
+ for (pos = blocks_per_slice - 1; pos < max_coeffs;) {
+ run_cb_index = ff_prores_run_to_cb_index[FFMIN(run, 15)];
+ lev_cb_index = ff_prores_lev_to_cb_index[FFMIN(level, 9)];
+
+ bits_left = get_bits_left(gb);
+ if (bits_left <= 0 || (bits_left <= MAX_PADDING && !show_bits(gb, bits_left)))
+ return 0;
+
+ run = decode_vlc_codeword(gb, ff_prores_ac_codebook[run_cb_index]);
+ if (run < 0)
+ return AVERROR_INVALIDDATA;
+
+ bits_left = get_bits_left(gb);
+ if (bits_left <= 0 || (bits_left <= MAX_PADDING && !show_bits(gb, bits_left)))
+ return AVERROR_INVALIDDATA;
+
+ level = decode_vlc_codeword(gb, ff_prores_ac_codebook[lev_cb_index]) + 1;
+ if (level < 0)
+ return AVERROR_INVALIDDATA;
+
+ pos += run + 1;
+ if (pos >= max_coeffs)
+ break;
+
+ sign = get_sbits(gb, 1);
+ out[((pos & block_mask) << 6) + scan[pos >> plane_size_factor]] =
+ (level ^ sign) - sign;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Decode a slice plane (luma or chroma).
+ */
+static int decode_slice_plane(ProresContext *ctx, ProresThreadData *td,
+ const uint8_t *buf,
+ int data_size, uint16_t *out_ptr,
+ int linesize, int mbs_per_slice,
+ int blocks_per_mb, int plane_size_factor,
+ const int16_t *qmat, int is_chroma)
+{
+ GetBitContext gb;
+ int16_t *block_ptr;
+ int mb_num, blocks_per_slice, ret;
+
+ blocks_per_slice = mbs_per_slice * blocks_per_mb;
+
+ memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
+
+ init_get_bits(&gb, buf, data_size << 3);
+
+ decode_dc_coeffs(&gb, td->blocks, blocks_per_slice);
+
+ ret = decode_ac_coeffs(&gb, td->blocks, blocks_per_slice,
+ plane_size_factor, ctx->scantable.permutated);
+ if (ret < 0)
+ return ret;
+
+ /* inverse quantization, inverse transform and output */
+ block_ptr = td->blocks;
+
+ if (!is_chroma) {
+ for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
+ ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ }
+ ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ }
+ }
+ } else {
+ for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) {
+ ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ if (blocks_per_mb > 2) {
+ ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat);
+ block_ptr += 64;
+ }
+ }
+ }
+ return 0;
+}
+
+
+static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs,
+ const int num_bits)
+{
+ const int mask = (1 << num_bits) - 1;
+ int i, idx, val, alpha_val;
+
+ idx = 0;
+ alpha_val = mask;
+ do {
+ do {
+ if (get_bits1(gb))
+ val = get_bits(gb, num_bits);
+ else {
+ int sign;
+ val = get_bits(gb, num_bits == 16 ? 7 : 4);
+ sign = val & 1;
+ val = (val + 2) >> 1;
+ if (sign)
+ val = -val;
+ }
+ alpha_val = (alpha_val + val) & mask;
+ if (num_bits == 16)
+ dst[idx++] = alpha_val >> 6;
+ else
+ dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
+ if (idx >= num_coeffs) {
+ break;
+ }
+ } while (get_bits1(gb));
+ val = get_bits(gb, 4);
+ if (!val)
+ val = get_bits(gb, 11);
+ if (idx + val > num_coeffs)
+ val = num_coeffs - idx;
+ if (num_bits == 16)
+ for (i = 0; i < val; i++)
+ dst[idx++] = alpha_val >> 6;
+ else
+ for (i = 0; i < val; i++)
+ dst[idx++] = (alpha_val << 2) | (alpha_val >> 6);
+ } while (idx < num_coeffs);
+}
+
+/**
+ * Decode alpha slice plane.
+ */
+static void decode_alpha_plane(ProresContext *ctx, ProresThreadData *td,
+ const uint8_t *buf, int data_size,
+ uint16_t *out_ptr, int linesize,
+ int mbs_per_slice)
+{
+ GetBitContext gb;
+ int i;
+ uint16_t *block_ptr;
+
+ memset(td->blocks, 0, 8 * 4 * 64 * sizeof(*td->blocks));
+
+ init_get_bits(&gb, buf, data_size << 3);
+
+ if (ctx->alpha_info == 2)
+ unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 16);
+ else
+ unpack_alpha(&gb, td->blocks, mbs_per_slice * 4 * 64, 8);
+
+ block_ptr = td->blocks;
+
+ for (i = 0; i < 16; i++) {
+ memcpy(out_ptr, block_ptr, 16 * mbs_per_slice * sizeof(*out_ptr));
+ out_ptr += linesize >> 1;
+ block_ptr += 16 * mbs_per_slice;
+ }
+}
+
+static int decode_slice(AVCodecContext *avctx, void *tdata)
+{
+ ProresThreadData *td = tdata;
+ ProresContext *ctx = avctx->priv_data;
+ int mb_x_pos = td->x_pos;
+ int mb_y_pos = td->y_pos;
+ int pic_num = ctx->pic_num;
+ int slice_num = td->slice_num;
+ int mbs_per_slice = td->slice_width;
+ const uint8_t *buf;
+ uint8_t *y_data, *u_data, *v_data, *a_data;
+ AVFrame *pic = ctx->frame;
+ int i, sf, slice_width_factor;
+ int slice_data_size, hdr_size;
+ int y_data_size, u_data_size, v_data_size, a_data_size;
+ int y_linesize, u_linesize, v_linesize, a_linesize;
+ int coff[4];
+ int ret;
+
+ buf = ctx->slice_data[slice_num].index;
+ slice_data_size = ctx->slice_data[slice_num + 1].index - buf;
+
+ slice_width_factor = av_log2(mbs_per_slice);
+
+ y_data = pic->data[0];
+ u_data = pic->data[1];
+ v_data = pic->data[2];
+ a_data = pic->data[3];
+ y_linesize = pic->linesize[0];
+ u_linesize = pic->linesize[1];
+ v_linesize = pic->linesize[2];
+ a_linesize = pic->linesize[3];
+
+ if (pic->interlaced_frame) {
+ if (!(pic_num ^ pic->top_field_first)) {
+ y_data += y_linesize;
+ u_data += u_linesize;
+ v_data += v_linesize;
+ if (a_data)
+ a_data += a_linesize;
+ }
+ y_linesize <<= 1;
+ u_linesize <<= 1;
+ v_linesize <<= 1;
+ a_linesize <<= 1;
+ }
+ y_data += (mb_y_pos << 4) * y_linesize + (mb_x_pos << 5);
+ u_data += (mb_y_pos << 4) * u_linesize + (mb_x_pos << ctx->mb_chroma_factor);
+ v_data += (mb_y_pos << 4) * v_linesize + (mb_x_pos << ctx->mb_chroma_factor);
+ if (a_data)
+ a_data += (mb_y_pos << 4) * a_linesize + (mb_x_pos << 5);
+
+ if (slice_data_size < 6) {
+ av_log(avctx, AV_LOG_ERROR, "slice data too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* parse slice header */
+ hdr_size = buf[0] >> 3;
+ coff[0] = hdr_size;
+ y_data_size = AV_RB16(buf + 2);
+ coff[1] = coff[0] + y_data_size;
+ u_data_size = AV_RB16(buf + 4);
+ coff[2] = coff[1] + u_data_size;
+ v_data_size = hdr_size > 7 ? AV_RB16(buf + 6) : slice_data_size - coff[2];
+ coff[3] = coff[2] + v_data_size;
+ a_data_size = ctx->alpha_info ? slice_data_size - coff[3] : 0;
+
+ /* if V or alpha component size is negative that means that previous
+ component sizes are too large */
+ if (v_data_size < 0 || a_data_size < 0 || hdr_size < 6) {
+ av_log(avctx, AV_LOG_ERROR, "invalid data size\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ sf = av_clip(buf[1], 1, 224);
+ sf = sf > 128 ? (sf - 96) << 2 : sf;
+
+ /* scale quantization matrixes according with slice's scale factor */
+ /* TODO: this can be SIMD-optimized a lot */
+ if (ctx->qmat_changed || sf != td->prev_slice_sf) {
+ td->prev_slice_sf = sf;
+ for (i = 0; i < 64; i++) {
+ td->qmat_luma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_luma[i] * sf;
+ td->qmat_chroma_scaled[ctx->dsp.idct_permutation[i]] = ctx->qmat_chroma[i] * sf;
+ }
+ }
+
+ /* decode luma plane */
+ ret = decode_slice_plane(ctx, td, buf + coff[0], y_data_size,
+ (uint16_t*) y_data, y_linesize,
+ mbs_per_slice, 4, slice_width_factor + 2,
+ td->qmat_luma_scaled, 0);
+
+ if (ret < 0)
+ return ret;
+
+ /* decode U chroma plane */
+ ret = decode_slice_plane(ctx, td, buf + coff[1], u_data_size,
+ (uint16_t*) u_data, u_linesize,
+ mbs_per_slice, ctx->num_chroma_blocks,
+ slice_width_factor + ctx->chroma_factor - 1,
+ td->qmat_chroma_scaled, 1);
+ if (ret < 0)
+ return ret;
+
+ /* decode V chroma plane */
+ ret = decode_slice_plane(ctx, td, buf + coff[2], v_data_size,
+ (uint16_t*) v_data, v_linesize,
+ mbs_per_slice, ctx->num_chroma_blocks,
+ slice_width_factor + ctx->chroma_factor - 1,
+ td->qmat_chroma_scaled, 1);
+ if (ret < 0)
+ return ret;
+
+ /* decode alpha plane if available */
+ if (a_data && a_data_size)
+ decode_alpha_plane(ctx, td, buf + coff[3], a_data_size,
+ (uint16_t*) a_data, a_linesize,
+ mbs_per_slice);
+
+ return 0;
+}
+
+
+static int decode_picture(ProresContext *ctx, int pic_num,
+ AVCodecContext *avctx)
+{
+ int slice_num, slice_width, x_pos, y_pos;
+
+ slice_num = 0;
+
+ ctx->pic_num = pic_num;
+ for (y_pos = 0; y_pos < ctx->num_y_mbs; y_pos++) {
+ slice_width = 1 << ctx->slice_width_factor;
+
+ for (x_pos = 0; x_pos < ctx->num_x_mbs && slice_width;
+ x_pos += slice_width) {
+ while (ctx->num_x_mbs - x_pos < slice_width)
+ slice_width >>= 1;
+
+ ctx->slice_data[slice_num].slice_num = slice_num;
+ ctx->slice_data[slice_num].x_pos = x_pos;
+ ctx->slice_data[slice_num].y_pos = y_pos;
+ ctx->slice_data[slice_num].slice_width = slice_width;
+
+ slice_num++;
+ }
+ }
+
+ return avctx->execute(avctx, decode_slice,
+ ctx->slice_data, NULL, slice_num,
+ sizeof(ctx->slice_data[0]));
+}
+
+
+#define MOVE_DATA_PTR(nbytes) buf += (nbytes); buf_size -= (nbytes)
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ ProresContext *ctx = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int frame_hdr_size, pic_num, pic_data_size;
+
+ ctx->frame = data;
+ ctx->frame->pict_type = AV_PICTURE_TYPE_I;
+ ctx->frame->key_frame = 1;
+
+ /* check frame atom container */
+ if (buf_size < 28 || buf_size < AV_RB32(buf) ||
+ AV_RB32(buf + 4) != FRAME_ID) {
+ av_log(avctx, AV_LOG_ERROR, "invalid frame\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ MOVE_DATA_PTR(8);
+
+ frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx);
+ if (frame_hdr_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ MOVE_DATA_PTR(frame_hdr_size);
+
+ if (ff_get_buffer(avctx, ctx->frame, 0) < 0)
+ return -1;
+
+ for (pic_num = 0; ctx->frame->interlaced_frame - pic_num + 1; pic_num++) {
+ pic_data_size = decode_picture_header(ctx, buf, buf_size, avctx);
+ if (pic_data_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ if (decode_picture(ctx, pic_num, avctx))
+ return -1;
+
+ MOVE_DATA_PTR(pic_data_size);
+ }
+
+ ctx->frame = NULL;
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+
+static av_cold int decode_close(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+
+ av_freep(&ctx->slice_data);
+
+ return 0;
+}
+
+
+AVCodec ff_prores_lgpl_decoder = {
+ .name = "prores_lgpl",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = decode_init,
+ .close = decode_close,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
+};
diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c
index 3af2f0b9bb..82d6009b58 100644
--- a/libavcodec/proresdsp.c
+++ b/libavcodec/proresdsp.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,7 @@
#define CLIP_MIN (1 << (PRORES_BITS_PER_SAMPLE - 8)) ///< minimum value for clipping resulting pixels
#define CLIP_MAX (1 << PRORES_BITS_PER_SAMPLE) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels
-#define CLIP_AND_BIAS(x) (av_clip((x) + BIAS, CLIP_MIN, CLIP_MAX))
+#define CLIP(x) (av_clip((x), CLIP_MIN, CLIP_MAX))
/**
* Add bias value, clamp and output pixels of a slice
@@ -44,7 +44,7 @@ static void put_pixels(uint16_t *dst, int stride, const int16_t *in)
for (x = 0; x < 8; x++) {
src_offset = (y << 3) + x;
- dst[dst_offset + x] = CLIP_AND_BIAS(in[src_offset]);
+ dst[dst_offset + x] = CLIP(in[src_offset]);
}
}
}
@@ -55,13 +55,13 @@ static void prores_idct_put_c(uint16_t *out, int linesize, int16_t *block, const
put_pixels(out, linesize >> 1, block);
}
-av_cold void ff_proresdsp_init(ProresDSPContext *dsp)
+av_cold void ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx)
{
dsp->idct_put = prores_idct_put_c;
dsp->idct_permutation_type = FF_IDCT_PERM_NONE;
if (ARCH_X86)
- ff_proresdsp_init_x86(dsp);
+ ff_proresdsp_init_x86(dsp, avctx);
ff_init_scantable_permutation(dsp->idct_permutation,
dsp->idct_permutation_type);
diff --git a/libavcodec/proresdsp.h b/libavcodec/proresdsp.h
index e8a3ea96a7..159862ec3d 100644
--- a/libavcodec/proresdsp.h
+++ b/libavcodec/proresdsp.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#define AVCODEC_PRORESDSP_H
#include <stdint.h>
+#include "avcodec.h"
#define PRORES_BITS_PER_SAMPLE 10 ///< output precision of prores decoder
@@ -33,8 +34,8 @@ typedef struct ProresDSPContext {
void (* idct_put) (uint16_t *out, int linesize, int16_t *block, const int16_t *qmat);
} ProresDSPContext;
-void ff_proresdsp_init(ProresDSPContext *dsp);
+void ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx);
-void ff_proresdsp_init_x86(ProresDSPContext *dsp);
+void ff_proresdsp_init_x86(ProresDSPContext *dsp, AVCodecContext *avctx);
#endif /* AVCODEC_PRORESDSP_H */
diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c
deleted file mode 100644
index 3a5524aa4c..0000000000
--- a/libavcodec/proresenc.c
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * Apple ProRes encoder
- *
- * Copyright (c) 2012 Konstantin Shishkov
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; 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/pixdesc.h"
-#include "avcodec.h"
-#include "fdctdsp.h"
-#include "put_bits.h"
-#include "bytestream.h"
-#include "internal.h"
-#include "proresdata.h"
-
-#define CFACTOR_Y422 2
-#define CFACTOR_Y444 3
-
-#define MAX_MBS_PER_SLICE 8
-
-#define MAX_PLANES 4
-
-enum {
- PRORES_PROFILE_PROXY = 0,
- PRORES_PROFILE_LT,
- PRORES_PROFILE_STANDARD,
- PRORES_PROFILE_HQ,
- PRORES_PROFILE_4444,
-};
-
-enum {
- QUANT_MAT_PROXY = 0,
- QUANT_MAT_LT,
- QUANT_MAT_STANDARD,
- QUANT_MAT_HQ,
- QUANT_MAT_DEFAULT,
-};
-
-static const uint8_t prores_quant_matrices[][64] = {
- { // proxy
- 4, 7, 9, 11, 13, 14, 15, 63,
- 7, 7, 11, 12, 14, 15, 63, 63,
- 9, 11, 13, 14, 15, 63, 63, 63,
- 11, 11, 13, 14, 63, 63, 63, 63,
- 11, 13, 14, 63, 63, 63, 63, 63,
- 13, 14, 63, 63, 63, 63, 63, 63,
- 13, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- },
- { // LT
- 4, 5, 6, 7, 9, 11, 13, 15,
- 5, 5, 7, 8, 11, 13, 15, 17,
- 6, 7, 9, 11, 13, 15, 15, 17,
- 7, 7, 9, 11, 13, 15, 17, 19,
- 7, 9, 11, 13, 14, 16, 19, 23,
- 9, 11, 13, 14, 16, 19, 23, 29,
- 9, 11, 13, 15, 17, 21, 28, 35,
- 11, 13, 16, 17, 21, 28, 35, 41,
- },
- { // standard
- 4, 4, 5, 5, 6, 7, 7, 9,
- 4, 4, 5, 6, 7, 7, 9, 9,
- 5, 5, 6, 7, 7, 9, 9, 10,
- 5, 5, 6, 7, 7, 9, 9, 10,
- 5, 6, 7, 7, 8, 9, 10, 12,
- 6, 7, 7, 8, 9, 10, 12, 15,
- 6, 7, 7, 9, 10, 11, 14, 17,
- 7, 7, 9, 10, 11, 14, 17, 21,
- },
- { // high quality
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 5,
- 4, 4, 4, 4, 4, 4, 5, 5,
- 4, 4, 4, 4, 4, 5, 5, 6,
- 4, 4, 4, 4, 5, 5, 6, 7,
- 4, 4, 4, 4, 5, 6, 7, 7,
- },
- { // codec default
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- },
-};
-
-#define NUM_MB_LIMITS 4
-static const int prores_mb_limits[NUM_MB_LIMITS] = {
- 1620, // up to 720x576
- 2700, // up to 960x720
- 6075, // up to 1440x1080
- 9216, // up to 2048x1152
-};
-
-static const struct prores_profile {
- const char *full_name;
- uint32_t tag;
- int min_quant;
- int max_quant;
- int br_tab[NUM_MB_LIMITS];
- int quant;
-} prores_profile_info[5] = {
- {
- .full_name = "proxy",
- .tag = MKTAG('a', 'p', 'c', 'o'),
- .min_quant = 4,
- .max_quant = 8,
- .br_tab = { 300, 242, 220, 194 },
- .quant = QUANT_MAT_PROXY,
- },
- {
- .full_name = "LT",
- .tag = MKTAG('a', 'p', 'c', 's'),
- .min_quant = 1,
- .max_quant = 9,
- .br_tab = { 720, 560, 490, 440 },
- .quant = QUANT_MAT_LT,
- },
- {
- .full_name = "standard",
- .tag = MKTAG('a', 'p', 'c', 'n'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 1050, 808, 710, 632 },
- .quant = QUANT_MAT_STANDARD,
- },
- {
- .full_name = "high quality",
- .tag = MKTAG('a', 'p', 'c', 'h'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 1566, 1216, 1070, 950 },
- .quant = QUANT_MAT_HQ,
- },
- {
- .full_name = "4444",
- .tag = MKTAG('a', 'p', '4', 'h'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 2350, 1828, 1600, 1425 },
- .quant = QUANT_MAT_HQ,
- }
-};
-
-#define TRELLIS_WIDTH 16
-#define SCORE_LIMIT INT_MAX / 2
-
-struct TrellisNode {
- int prev_node;
- int quant;
- int bits;
- int score;
-};
-
-#define MAX_STORED_Q 16
-
-typedef struct ProresThreadData {
- DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
- DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
- int16_t custom_q[64];
- struct TrellisNode *nodes;
-} ProresThreadData;
-
-typedef struct ProresContext {
- AVClass *class;
- DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
- DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
- int16_t quants[MAX_STORED_Q][64];
- int16_t custom_q[64];
- const uint8_t *quant_mat;
- const uint8_t *scantable;
-
- void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src,
- int linesize, int16_t *block);
- FDCTDSPContext fdsp;
-
- int mb_width, mb_height;
- int mbs_per_slice;
- int num_chroma_blocks, chroma_factor;
- int slices_width;
- int slices_per_picture;
- int pictures_per_frame; // 1 for progressive, 2 for interlaced
- int cur_picture_idx;
- int num_planes;
- int bits_per_mb;
- int force_quant;
- int alpha_bits;
- int warn;
-
- char *vendor;
- int quant_sel;
-
- int frame_size_upper_bound;
-
- int profile;
- const struct prores_profile *profile_info;
-
- int *slice_q;
-
- ProresThreadData *tdata;
-} ProresContext;
-
-static void get_slice_data(ProresContext *ctx, const uint16_t *src,
- int linesize, int x, int y, int w, int h,
- int16_t *blocks, uint16_t *emu_buf,
- int mbs_per_slice, int blocks_per_mb, int is_chroma)
-{
- const uint16_t *esrc;
- const int mb_width = 4 * blocks_per_mb;
- int elinesize;
- int i, j, k;
-
- for (i = 0; i < mbs_per_slice; i++, src += mb_width) {
- if (x >= w) {
- memset(blocks, 0, 64 * (mbs_per_slice - i) * blocks_per_mb
- * sizeof(*blocks));
- return;
- }
- if (x + mb_width <= w && y + 16 <= h) {
- esrc = src;
- elinesize = linesize;
- } else {
- int bw, bh, pix;
-
- esrc = emu_buf;
- elinesize = 16 * sizeof(*emu_buf);
-
- bw = FFMIN(w - x, mb_width);
- bh = FFMIN(h - y, 16);
-
- for (j = 0; j < bh; j++) {
- memcpy(emu_buf + j * 16,
- (const uint8_t*)src + j * linesize,
- bw * sizeof(*src));
- pix = emu_buf[j * 16 + bw - 1];
- for (k = bw; k < mb_width; k++)
- emu_buf[j * 16 + k] = pix;
- }
- for (; j < 16; j++)
- memcpy(emu_buf + j * 16,
- emu_buf + (bh - 1) * 16,
- mb_width * sizeof(*emu_buf));
- }
- if (!is_chroma) {
- ctx->fdct(&ctx->fdsp, esrc, elinesize, blocks);
- blocks += 64;
- if (blocks_per_mb > 2) {
- ctx->fdct(&ctx->fdsp, esrc + 8, elinesize, blocks);
- blocks += 64;
- }
- ctx->fdct(&ctx->fdsp, esrc + elinesize * 4, elinesize, blocks);
- blocks += 64;
- if (blocks_per_mb > 2) {
- ctx->fdct(&ctx->fdsp, esrc + elinesize * 4 + 8, elinesize, blocks);
- blocks += 64;
- }
- } else {
- ctx->fdct(&ctx->fdsp, esrc, elinesize, blocks);
- blocks += 64;
- ctx->fdct(&ctx->fdsp, esrc + elinesize * 4, elinesize, blocks);
- blocks += 64;
- if (blocks_per_mb > 2) {
- ctx->fdct(&ctx->fdsp, esrc + 8, elinesize, blocks);
- blocks += 64;
- ctx->fdct(&ctx->fdsp, esrc + elinesize * 4 + 8, elinesize, blocks);
- blocks += 64;
- }
- }
-
- x += mb_width;
- }
-}
-
-static void get_alpha_data(ProresContext *ctx, const uint16_t *src,
- int linesize, int x, int y, int w, int h,
- int16_t *blocks, int mbs_per_slice, int abits)
-{
- const int slice_width = 16 * mbs_per_slice;
- int i, j, copy_w, copy_h;
-
- copy_w = FFMIN(w - x, slice_width);
- copy_h = FFMIN(h - y, 16);
- for (i = 0; i < copy_h; i++) {
- memcpy(blocks, src, copy_w * sizeof(*src));
- if (abits == 8)
- for (j = 0; j < copy_w; j++)
- blocks[j] >>= 2;
- else
- for (j = 0; j < copy_w; j++)
- blocks[j] = (blocks[j] << 6) | (blocks[j] >> 4);
- for (j = copy_w; j < slice_width; j++)
- blocks[j] = blocks[copy_w - 1];
- blocks += slice_width;
- src += linesize >> 1;
- }
- for (; i < 16; i++) {
- memcpy(blocks, blocks - slice_width, slice_width * sizeof(*blocks));
- blocks += slice_width;
- }
-}
-
-/**
- * Write an unsigned rice/exp golomb codeword.
- */
-static inline void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
-{
- unsigned int rice_order, exp_order, switch_bits, switch_val;
- int exponent;
-
- /* number of prefix bits to switch between Rice and expGolomb */
- switch_bits = (codebook & 3) + 1;
- rice_order = codebook >> 5; /* rice code order */
- exp_order = (codebook >> 2) & 7; /* exp golomb code order */
-
- switch_val = switch_bits << rice_order;
-
- if (val >= switch_val) {
- val -= switch_val - (1 << exp_order);
- exponent = av_log2(val);
-
- put_bits(pb, exponent - exp_order + switch_bits, 0);
- put_bits(pb, exponent + 1, val);
- } else {
- exponent = val >> rice_order;
-
- if (exponent)
- put_bits(pb, exponent, 0);
- put_bits(pb, 1, 1);
- if (rice_order)
- put_sbits(pb, rice_order, val);
- }
-}
-
-#define GET_SIGN(x) ((x) >> 31)
-#define MAKE_CODE(x) (((x) << 1) ^ GET_SIGN(x))
-
-static void encode_dcs(PutBitContext *pb, int16_t *blocks,
- int blocks_per_slice, int scale)
-{
- int i;
- int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
-
- prev_dc = (blocks[0] - 0x4000) / scale;
- encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
- sign = 0;
- codebook = 3;
- blocks += 64;
-
- for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
- dc = (blocks[0] - 0x4000) / scale;
- delta = dc - prev_dc;
- new_sign = GET_SIGN(delta);
- delta = (delta ^ sign) - sign;
- code = MAKE_CODE(delta);
- encode_vlc_codeword(pb, ff_prores_dc_codebook[codebook], code);
- codebook = (code + (code & 1)) >> 1;
- codebook = FFMIN(codebook, 3);
- sign = new_sign;
- prev_dc = dc;
- }
-}
-
-static void encode_acs(PutBitContext *pb, int16_t *blocks,
- int blocks_per_slice,
- int plane_size_factor,
- const uint8_t *scan, const int16_t *qmat)
-{
- int idx, i;
- int run, level, run_cb, lev_cb;
- int max_coeffs, abs_level;
-
- max_coeffs = blocks_per_slice << 6;
- run_cb = ff_prores_run_to_cb_index[4];
- lev_cb = ff_prores_lev_to_cb_index[2];
- run = 0;
-
- for (i = 1; i < 64; i++) {
- for (idx = scan[i]; idx < max_coeffs; idx += 64) {
- level = blocks[idx] / qmat[scan[i]];
- if (level) {
- abs_level = FFABS(level);
- encode_vlc_codeword(pb, ff_prores_ac_codebook[run_cb], run);
- encode_vlc_codeword(pb, ff_prores_ac_codebook[lev_cb],
- abs_level - 1);
- put_sbits(pb, 1, GET_SIGN(level));
-
- run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
- lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
- run = 0;
- } else {
- run++;
- }
- }
- }
-}
-
-static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
- const uint16_t *src, int linesize,
- int mbs_per_slice, int16_t *blocks,
- int blocks_per_mb, int plane_size_factor,
- const int16_t *qmat)
-{
- int blocks_per_slice, saved_pos;
-
- saved_pos = put_bits_count(pb);
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
-
- encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
- encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
- ctx->scantable, qmat);
- flush_put_bits(pb);
-
- return (put_bits_count(pb) - saved_pos) >> 3;
-}
-
-static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
-{
- const int mask = (1 << abits) - 1;
- const int dbits = (abits == 8) ? 4 : 7;
- const int dsize = 1 << dbits - 1;
- int diff = cur - prev;
-
- diff &= mask;
- if (diff >= (1 << abits) - dsize)
- diff -= 1 << abits;
- if (diff < -dsize || diff > dsize || !diff) {
- put_bits(pb, 1, 1);
- put_bits(pb, abits, diff);
- } else {
- put_bits(pb, 1, 0);
- put_bits(pb, dbits - 1, FFABS(diff) - 1);
- put_bits(pb, 1, diff < 0);
- }
-}
-
-static void put_alpha_run(PutBitContext *pb, int run)
-{
- if (run) {
- put_bits(pb, 1, 0);
- if (run < 0x10)
- put_bits(pb, 4, run);
- else
- put_bits(pb, 15, run);
- } else {
- put_bits(pb, 1, 1);
- }
-}
-
-// todo alpha quantisation for high quants
-static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
- int mbs_per_slice, uint16_t *blocks,
- int quant)
-{
- const int abits = ctx->alpha_bits;
- const int mask = (1 << abits) - 1;
- const int num_coeffs = mbs_per_slice * 256;
- int saved_pos = put_bits_count(pb);
- int prev = mask, cur;
- int idx = 0;
- int run = 0;
-
- cur = blocks[idx++];
- put_alpha_diff(pb, cur, prev, abits);
- prev = cur;
- do {
- cur = blocks[idx++];
- if (cur != prev) {
- put_alpha_run (pb, run);
- put_alpha_diff(pb, cur, prev, abits);
- prev = cur;
- run = 0;
- } else {
- run++;
- }
- } while (idx < num_coeffs);
- if (run)
- put_alpha_run(pb, run);
- flush_put_bits(pb);
- return (put_bits_count(pb) - saved_pos) >> 3;
-}
-
-static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
- PutBitContext *pb,
- int sizes[4], int x, int y, int quant,
- int mbs_per_slice)
-{
- ProresContext *ctx = avctx->priv_data;
- int i, xp, yp;
- int total_size = 0;
- const uint16_t *src;
- int slice_width_factor = av_log2(mbs_per_slice);
- int num_cblocks, pwidth, linesize, line_add;
- int plane_factor, is_chroma;
- uint16_t *qmat;
-
- if (ctx->pictures_per_frame == 1)
- line_add = 0;
- else
- line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
-
- if (ctx->force_quant) {
- qmat = ctx->quants[0];
- } else if (quant < MAX_STORED_Q) {
- qmat = ctx->quants[quant];
- } else {
- qmat = ctx->custom_q;
- for (i = 0; i < 64; i++)
- qmat[i] = ctx->quant_mat[i] * quant;
- }
-
- for (i = 0; i < ctx->num_planes; i++) {
- is_chroma = (i == 1 || i == 2);
- plane_factor = slice_width_factor + 2;
- if (is_chroma)
- plane_factor += ctx->chroma_factor - 3;
- if (!is_chroma || ctx->chroma_factor == CFACTOR_Y444) {
- xp = x << 4;
- yp = y << 4;
- num_cblocks = 4;
- pwidth = avctx->width;
- } else {
- xp = x << 3;
- yp = y << 4;
- num_cblocks = 2;
- pwidth = avctx->width >> 1;
- }
-
- linesize = pic->linesize[i] * ctx->pictures_per_frame;
- src = (const uint16_t*)(pic->data[i] + yp * linesize +
- line_add * pic->linesize[i]) + xp;
-
- if (i < 3) {
- get_slice_data(ctx, src, linesize, xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- ctx->blocks[0], ctx->emu_buf,
- mbs_per_slice, num_cblocks, is_chroma);
- sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
- mbs_per_slice, ctx->blocks[0],
- num_cblocks, plane_factor,
- qmat);
- } else {
- get_alpha_data(ctx, src, linesize, xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
- sizes[i] = encode_alpha_plane(ctx, pb, mbs_per_slice,
- ctx->blocks[0], quant);
- }
- total_size += sizes[i];
- if (put_bits_left(pb) < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "Underestimated required buffer size.\n");
- return AVERROR_BUG;
- }
- }
- return total_size;
-}
-
-static inline int estimate_vlc(unsigned codebook, int val)
-{
- unsigned int rice_order, exp_order, switch_bits, switch_val;
- int exponent;
-
- /* number of prefix bits to switch between Rice and expGolomb */
- switch_bits = (codebook & 3) + 1;
- rice_order = codebook >> 5; /* rice code order */
- exp_order = (codebook >> 2) & 7; /* exp golomb code order */
-
- switch_val = switch_bits << rice_order;
-
- if (val >= switch_val) {
- val -= switch_val - (1 << exp_order);
- exponent = av_log2(val);
-
- return exponent * 2 - exp_order + switch_bits + 1;
- } else {
- return (val >> rice_order) + rice_order + 1;
- }
-}
-
-static int estimate_dcs(int *error, int16_t *blocks, int blocks_per_slice,
- int scale)
-{
- int i;
- int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
- int bits;
-
- prev_dc = (blocks[0] - 0x4000) / scale;
- bits = estimate_vlc(FIRST_DC_CB, MAKE_CODE(prev_dc));
- sign = 0;
- codebook = 3;
- blocks += 64;
- *error += FFABS(blocks[0] - 0x4000) % scale;
-
- for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
- dc = (blocks[0] - 0x4000) / scale;
- *error += FFABS(blocks[0] - 0x4000) % scale;
- delta = dc - prev_dc;
- new_sign = GET_SIGN(delta);
- delta = (delta ^ sign) - sign;
- code = MAKE_CODE(delta);
- bits += estimate_vlc(ff_prores_dc_codebook[codebook], code);
- codebook = (code + (code & 1)) >> 1;
- codebook = FFMIN(codebook, 3);
- sign = new_sign;
- prev_dc = dc;
- }
-
- return bits;
-}
-
-static int estimate_acs(int *error, int16_t *blocks, int blocks_per_slice,
- int plane_size_factor,
- const uint8_t *scan, const int16_t *qmat)
-{
- int idx, i;
- int run, level, run_cb, lev_cb;
- int max_coeffs, abs_level;
- int bits = 0;
-
- max_coeffs = blocks_per_slice << 6;
- run_cb = ff_prores_run_to_cb_index[4];
- lev_cb = ff_prores_lev_to_cb_index[2];
- run = 0;
-
- for (i = 1; i < 64; i++) {
- for (idx = scan[i]; idx < max_coeffs; idx += 64) {
- level = blocks[idx] / qmat[scan[i]];
- *error += FFABS(blocks[idx]) % qmat[scan[i]];
- if (level) {
- abs_level = FFABS(level);
- bits += estimate_vlc(ff_prores_ac_codebook[run_cb], run);
- bits += estimate_vlc(ff_prores_ac_codebook[lev_cb],
- abs_level - 1) + 1;
-
- run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
- lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
- run = 0;
- } else {
- run++;
- }
- }
- }
-
- return bits;
-}
-
-static int estimate_slice_plane(ProresContext *ctx, int *error, int plane,
- const uint16_t *src, int linesize,
- int mbs_per_slice,
- int blocks_per_mb, int plane_size_factor,
- const int16_t *qmat, ProresThreadData *td)
-{
- int blocks_per_slice;
- int bits;
-
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
-
- bits = estimate_dcs(error, td->blocks[plane], blocks_per_slice, qmat[0]);
- bits += estimate_acs(error, td->blocks[plane], blocks_per_slice,
- plane_size_factor, ctx->scantable, qmat);
-
- return FFALIGN(bits, 8);
-}
-
-static int est_alpha_diff(int cur, int prev, int abits)
-{
- const int mask = (1 << abits) - 1;
- const int dbits = (abits == 8) ? 4 : 7;
- const int dsize = 1 << dbits - 1;
- int diff = cur - prev;
-
- diff &= mask;
- if (diff >= (1 << abits) - dsize)
- diff -= 1 << abits;
- if (diff < -dsize || diff > dsize || !diff)
- return abits + 1;
- else
- return dbits + 1;
-}
-
-static int estimate_alpha_plane(ProresContext *ctx, int *error,
- const uint16_t *src, int linesize,
- int mbs_per_slice, int quant,
- int16_t *blocks)
-{
- const int abits = ctx->alpha_bits;
- const int mask = (1 << abits) - 1;
- const int num_coeffs = mbs_per_slice * 256;
- int prev = mask, cur;
- int idx = 0;
- int run = 0;
- int bits;
-
- *error = 0;
- cur = blocks[idx++];
- bits = est_alpha_diff(cur, prev, abits);
- prev = cur;
- do {
- cur = blocks[idx++];
- if (cur != prev) {
- if (!run)
- bits++;
- else if (run < 0x10)
- bits += 4;
- else
- bits += 15;
- bits += est_alpha_diff(cur, prev, abits);
- prev = cur;
- run = 0;
- } else {
- run++;
- }
- } while (idx < num_coeffs);
-
- if (run) {
- if (run < 0x10)
- bits += 4;
- else
- bits += 15;
- }
-
- return bits;
-}
-
-static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
- int trellis_node, int x, int y, int mbs_per_slice,
- ProresThreadData *td)
-{
- ProresContext *ctx = avctx->priv_data;
- int i, q, pq, xp, yp;
- const uint16_t *src;
- int slice_width_factor = av_log2(mbs_per_slice);
- int num_cblocks[MAX_PLANES], pwidth;
- int plane_factor[MAX_PLANES], is_chroma[MAX_PLANES];
- const int min_quant = ctx->profile_info->min_quant;
- const int max_quant = ctx->profile_info->max_quant;
- int error, bits, bits_limit;
- int mbs, prev, cur, new_score;
- int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
- int overquant;
- uint16_t *qmat;
- int linesize[4], line_add;
-
- if (ctx->pictures_per_frame == 1)
- line_add = 0;
- else
- line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
- mbs = x + mbs_per_slice;
-
- for (i = 0; i < ctx->num_planes; i++) {
- is_chroma[i] = (i == 1 || i == 2);
- plane_factor[i] = slice_width_factor + 2;
- if (is_chroma[i])
- plane_factor[i] += ctx->chroma_factor - 3;
- if (!is_chroma[i] || ctx->chroma_factor == CFACTOR_Y444) {
- xp = x << 4;
- yp = y << 4;
- num_cblocks[i] = 4;
- pwidth = avctx->width;
- } else {
- xp = x << 3;
- yp = y << 4;
- num_cblocks[i] = 2;
- pwidth = avctx->width >> 1;
- }
-
- linesize[i] = pic->linesize[i] * ctx->pictures_per_frame;
- src = (const uint16_t*)(pic->data[i] + yp * linesize[i] +
- line_add * pic->linesize[i]) + xp;
-
- if (i < 3) {
- get_slice_data(ctx, src, linesize[i], xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- td->blocks[i], td->emu_buf,
- mbs_per_slice, num_cblocks[i], is_chroma[i]);
- } else {
- get_alpha_data(ctx, src, linesize[i], xp, yp,
- pwidth, avctx->height / ctx->pictures_per_frame,
- td->blocks[i], mbs_per_slice, ctx->alpha_bits);
- }
- }
-
- for (q = min_quant; q < max_quant + 2; q++) {
- td->nodes[trellis_node + q].prev_node = -1;
- td->nodes[trellis_node + q].quant = q;
- }
-
- // todo: maybe perform coarser quantising to fit into frame size when needed
- for (q = min_quant; q <= max_quant; q++) {
- bits = 0;
- error = 0;
- for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
- bits += estimate_slice_plane(ctx, &error, i,
- src, linesize[i],
- mbs_per_slice,
- num_cblocks[i], plane_factor[i],
- ctx->quants[q], td);
- }
- if (ctx->alpha_bits)
- bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
- mbs_per_slice, q, td->blocks[3]);
- if (bits > 65000 * 8)
- error = SCORE_LIMIT;
-
- slice_bits[q] = bits;
- slice_score[q] = error;
- }
- if (slice_bits[max_quant] <= ctx->bits_per_mb * mbs_per_slice) {
- slice_bits[max_quant + 1] = slice_bits[max_quant];
- slice_score[max_quant + 1] = slice_score[max_quant] + 1;
- overquant = max_quant;
- } else {
- for (q = max_quant + 1; q < 128; q++) {
- bits = 0;
- error = 0;
- if (q < MAX_STORED_Q) {
- qmat = ctx->quants[q];
- } else {
- qmat = td->custom_q;
- for (i = 0; i < 64; i++)
- qmat[i] = ctx->quant_mat[i] * q;
- }
- for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
- bits += estimate_slice_plane(ctx, &error, i,
- src, linesize[i],
- mbs_per_slice,
- num_cblocks[i], plane_factor[i],
- qmat, td);
- }
- if (ctx->alpha_bits)
- bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
- mbs_per_slice, q, td->blocks[3]);
- if (bits <= ctx->bits_per_mb * mbs_per_slice)
- break;
- }
-
- slice_bits[max_quant + 1] = bits;
- slice_score[max_quant + 1] = error;
- overquant = q;
- }
- td->nodes[trellis_node + max_quant + 1].quant = overquant;
-
- bits_limit = mbs * ctx->bits_per_mb;
- for (pq = min_quant; pq < max_quant + 2; pq++) {
- prev = trellis_node - TRELLIS_WIDTH + pq;
-
- for (q = min_quant; q < max_quant + 2; q++) {
- cur = trellis_node + q;
-
- bits = td->nodes[prev].bits + slice_bits[q];
- error = slice_score[q];
- if (bits > bits_limit)
- error = SCORE_LIMIT;
-
- if (td->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT)
- new_score = td->nodes[prev].score + error;
- else
- new_score = SCORE_LIMIT;
- if (td->nodes[cur].prev_node == -1 ||
- td->nodes[cur].score >= new_score) {
-
- td->nodes[cur].bits = bits;
- td->nodes[cur].score = new_score;
- td->nodes[cur].prev_node = prev;
- }
- }
- }
-
- error = td->nodes[trellis_node + min_quant].score;
- pq = trellis_node + min_quant;
- for (q = min_quant + 1; q < max_quant + 2; q++) {
- if (td->nodes[trellis_node + q].score <= error) {
- error = td->nodes[trellis_node + q].score;
- pq = trellis_node + q;
- }
- }
-
- return pq;
-}
-
-static int find_quant_thread(AVCodecContext *avctx, void *arg,
- int jobnr, int threadnr)
-{
- ProresContext *ctx = avctx->priv_data;
- ProresThreadData *td = ctx->tdata + threadnr;
- int mbs_per_slice = ctx->mbs_per_slice;
- int x, y = jobnr, mb, q = 0;
-
- for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
- while (ctx->mb_width - x < mbs_per_slice)
- mbs_per_slice >>= 1;
- q = find_slice_quant(avctx, avctx->coded_frame,
- (mb + 1) * TRELLIS_WIDTH, x, y,
- mbs_per_slice, td);
- }
-
- for (x = ctx->slices_width - 1; x >= 0; x--) {
- ctx->slice_q[x + y * ctx->slices_width] = td->nodes[q].quant;
- q = td->nodes[q].prev_node;
- }
-
- return 0;
-}
-
-static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *pic, int *got_packet)
-{
- ProresContext *ctx = avctx->priv_data;
- uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes, *tmp;
- uint8_t *picture_size_pos;
- PutBitContext pb;
- int x, y, i, mb, q = 0;
- int sizes[4] = { 0 };
- int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1);
- int frame_size, picture_size, slice_size;
- int pkt_size, ret, max_slice_size = 0;
- uint8_t frame_flags;
-
- *avctx->coded_frame = *pic;
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
-
- pkt_size = ctx->frame_size_upper_bound;
-
- if ((ret = ff_alloc_packet(pkt, pkt_size + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
- return ret;
- }
-
- orig_buf = pkt->data;
-
- // frame atom
- orig_buf += 4; // frame size
- bytestream_put_be32 (&orig_buf, FRAME_ID); // frame container ID
- buf = orig_buf;
-
- // frame header
- tmp = buf;
- buf += 2; // frame header size will be stored here
- bytestream_put_be16 (&buf, 0); // version 1
- bytestream_put_buffer(&buf, ctx->vendor, 4);
- bytestream_put_be16 (&buf, avctx->width);
- bytestream_put_be16 (&buf, avctx->height);
-
- frame_flags = ctx->chroma_factor << 6;
- if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
- frame_flags |= pic->top_field_first ? 0x04 : 0x08;
- bytestream_put_byte (&buf, frame_flags);
-
- bytestream_put_byte (&buf, 0); // reserved
- bytestream_put_byte (&buf, avctx->color_primaries);
- bytestream_put_byte (&buf, avctx->color_trc);
- bytestream_put_byte (&buf, avctx->colorspace);
- bytestream_put_byte (&buf, 0x40 | (ctx->alpha_bits >> 3));
- bytestream_put_byte (&buf, 0); // reserved
- if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
- bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
- // luma quantisation matrix
- for (i = 0; i < 64; i++)
- bytestream_put_byte(&buf, ctx->quant_mat[i]);
- // chroma quantisation matrix
- for (i = 0; i < 64; i++)
- bytestream_put_byte(&buf, ctx->quant_mat[i]);
- } else {
- bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used
- }
- bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header size
-
- for (ctx->cur_picture_idx = 0;
- ctx->cur_picture_idx < ctx->pictures_per_frame;
- ctx->cur_picture_idx++) {
- // picture header
- picture_size_pos = buf + 1;
- bytestream_put_byte (&buf, 0x40); // picture header size (in bits)
- buf += 4; // picture data size will be stored here
- bytestream_put_be16 (&buf, ctx->slices_per_picture);
- bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs
-
- // seek table - will be filled during slice encoding
- slice_sizes = buf;
- buf += ctx->slices_per_picture * 2;
-
- // slices
- if (!ctx->force_quant) {
- ret = avctx->execute2(avctx, find_quant_thread, NULL, NULL,
- ctx->mb_height);
- if (ret)
- return ret;
- }
-
- for (y = 0; y < ctx->mb_height; y++) {
- int mbs_per_slice = ctx->mbs_per_slice;
- for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
- q = ctx->force_quant ? ctx->force_quant
- : ctx->slice_q[mb + y * ctx->slices_width];
-
- while (ctx->mb_width - x < mbs_per_slice)
- mbs_per_slice >>= 1;
-
- bytestream_put_byte(&buf, slice_hdr_size << 3);
- slice_hdr = buf;
- buf += slice_hdr_size - 1;
- if (pkt_size <= buf - orig_buf + 2 * max_slice_size) {
- uint8_t *start = pkt->data;
- // Recompute new size according to max_slice_size
- // and deduce delta
- int delta = 200 + ctx->pictures_per_frame *
- ctx->slices_per_picture * max_slice_size -
- pkt_size;
-
- delta = FFMAX(delta, 2 * max_slice_size);
- ctx->frame_size_upper_bound += delta;
-
- if (!ctx->warn) {
- avpriv_request_sample(avctx,
- "Packet too small: is %i,"
- " needs %i (slice: %i). "
- "Correct allocation",
- pkt_size, delta, max_slice_size);
- ctx->warn = 1;
- }
-
- ret = av_grow_packet(pkt, delta);
- if (ret < 0)
- return ret;
-
- pkt_size += delta;
- // restore pointers
- orig_buf = pkt->data + (orig_buf - start);
- buf = pkt->data + (buf - start);
- picture_size_pos = pkt->data + (picture_size_pos - start);
- slice_sizes = pkt->data + (slice_sizes - start);
- slice_hdr = pkt->data + (slice_hdr - start);
- tmp = pkt->data + (tmp - start);
- }
- init_put_bits(&pb, buf, (pkt_size - (buf - orig_buf)) * 8);
- ret = encode_slice(avctx, pic, &pb, sizes, x, y, q,
- mbs_per_slice);
- if (ret < 0)
- return ret;
-
- bytestream_put_byte(&slice_hdr, q);
- slice_size = slice_hdr_size + sizes[ctx->num_planes - 1];
- for (i = 0; i < ctx->num_planes - 1; i++) {
- bytestream_put_be16(&slice_hdr, sizes[i]);
- slice_size += sizes[i];
- }
- bytestream_put_be16(&slice_sizes, slice_size);
- buf += slice_size - slice_hdr_size;
- if (max_slice_size < slice_size)
- max_slice_size = slice_size;
- }
- }
-
- if (ctx->pictures_per_frame == 1)
- picture_size = buf - picture_size_pos - 6;
- else
- picture_size = buf - picture_size_pos + 1;
- bytestream_put_be32(&picture_size_pos, picture_size);
- }
-
- orig_buf -= 8;
- frame_size = buf - orig_buf;
- bytestream_put_be32(&orig_buf, frame_size);
-
- pkt->size = frame_size;
- pkt->flags |= AV_PKT_FLAG_KEY;
- *got_packet = 1;
-
- return 0;
-}
-
-static av_cold int encode_close(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
- int i;
-
- av_freep(&avctx->coded_frame);
-
- if (ctx->tdata) {
- for (i = 0; i < avctx->thread_count; i++)
- av_free(ctx->tdata[i].nodes);
- }
- av_freep(&ctx->tdata);
- av_freep(&ctx->slice_q);
-
- return 0;
-}
-
-static void prores_fdct(FDCTDSPContext *fdsp, const uint16_t *src,
- int linesize, int16_t *block)
-{
- int x, y;
- const uint16_t *tsrc = src;
-
- for (y = 0; y < 8; y++) {
- for (x = 0; x < 8; x++)
- block[y * 8 + x] = tsrc[x];
- tsrc += linesize >> 1;
- }
- fdsp->fdct(block);
-}
-
-static av_cold int encode_init(AVCodecContext *avctx)
-{
- ProresContext *ctx = avctx->priv_data;
- int mps;
- int i, j;
- int min_quant, max_quant;
- int interlaced = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
-
- avctx->bits_per_raw_sample = 10;
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- ctx->fdct = prores_fdct;
- ctx->scantable = interlaced ? ff_prores_interlaced_scan
- : ff_prores_progressive_scan;
- ff_fdctdsp_init(&ctx->fdsp, avctx);
-
- mps = ctx->mbs_per_slice;
- if (mps & (mps - 1)) {
- av_log(avctx, AV_LOG_ERROR,
- "there should be an integer power of two MBs per slice\n");
- return AVERROR(EINVAL);
- }
- if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
- if (ctx->alpha_bits & 7) {
- av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
- return AVERROR(EINVAL);
- }
- avctx->bits_per_coded_sample = 32;
- } else {
- ctx->alpha_bits = 0;
- }
-
- ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10
- ? CFACTOR_Y422
- : CFACTOR_Y444;
- ctx->profile_info = prores_profile_info + ctx->profile;
- ctx->num_planes = 3 + !!ctx->alpha_bits;
-
- ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
-
- if (interlaced)
- ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
- else
- ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
-
- ctx->slices_width = ctx->mb_width / mps;
- ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
- ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
- ctx->pictures_per_frame = 1 + interlaced;
-
- if (ctx->quant_sel == -1)
- ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
- else
- ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
-
- if (strlen(ctx->vendor) != 4) {
- av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
- return AVERROR_INVALIDDATA;
- }
-
- ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
- if (!ctx->force_quant) {
- if (!ctx->bits_per_mb) {
- for (i = 0; i < NUM_MB_LIMITS - 1; i++)
- if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
- ctx->pictures_per_frame)
- break;
- ctx->bits_per_mb = ctx->profile_info->br_tab[i];
- } else if (ctx->bits_per_mb < 128) {
- av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n");
- return AVERROR_INVALIDDATA;
- }
-
- min_quant = ctx->profile_info->min_quant;
- max_quant = ctx->profile_info->max_quant;
- for (i = min_quant; i < MAX_STORED_Q; i++) {
- for (j = 0; j < 64; j++)
- ctx->quants[i][j] = ctx->quant_mat[j] * i;
- }
-
- ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
- if (!ctx->slice_q) {
- encode_close(avctx);
- return AVERROR(ENOMEM);
- }
-
- ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata));
- if (!ctx->tdata) {
- encode_close(avctx);
- return AVERROR(ENOMEM);
- }
-
- for (j = 0; j < avctx->thread_count; j++) {
- ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1)
- * TRELLIS_WIDTH
- * sizeof(*ctx->tdata->nodes));
- if (!ctx->tdata[j].nodes) {
- encode_close(avctx);
- return AVERROR(ENOMEM);
- }
- for (i = min_quant; i < max_quant + 2; i++) {
- ctx->tdata[j].nodes[i].prev_node = -1;
- ctx->tdata[j].nodes[i].bits = 0;
- ctx->tdata[j].nodes[i].score = 0;
- }
- }
- } else {
- int ls = 0;
-
- if (ctx->force_quant > 64) {
- av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
- return AVERROR_INVALIDDATA;
- }
-
- for (j = 0; j < 64; j++) {
- ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
- ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
- }
-
- ctx->bits_per_mb = ls * 8;
- if (ctx->chroma_factor == CFACTOR_Y444)
- ctx->bits_per_mb += ls * 4;
- }
-
- ctx->frame_size_upper_bound = ctx->pictures_per_frame *
- ctx->slices_per_picture *
- (2 + 2 * ctx->num_planes +
- (mps * ctx->bits_per_mb) / 8)
- + 200;
-
- if (ctx->alpha_bits) {
- // The alpha plane is run-coded and might exceed the bit budget.
- ctx->frame_size_upper_bound += ctx->pictures_per_frame *
- ctx->slices_per_picture *
- /* num pixels per slice */ (ctx->mbs_per_slice * 256 *
- /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3);
- }
-
- avctx->codec_tag = ctx->profile_info->tag;
-
- av_log(avctx, AV_LOG_DEBUG,
- "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
- ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
- interlaced ? "yes" : "no", ctx->bits_per_mb);
- av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
- ctx->frame_size_upper_bound);
-
- return 0;
-}
-
-#define OFFSET(x) offsetof(ProresContext, x)
-#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
-
-static const AVOption options[] = {
- { "mbs_per_slice", "macroblocks per slice", OFFSET(mbs_per_slice),
- AV_OPT_TYPE_INT, { .i64 = 8 }, 1, MAX_MBS_PER_SLICE, VE },
- { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT,
- { .i64 = PRORES_PROFILE_STANDARD },
- PRORES_PROFILE_PROXY, PRORES_PROFILE_4444, VE, "profile" },
- { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_PROXY },
- 0, 0, VE, "profile" },
- { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_LT },
- 0, 0, VE, "profile" },
- { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_STANDARD },
- 0, 0, VE, "profile" },
- { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_HQ },
- 0, 0, VE, "profile" },
- { "4444", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444 },
- 0, 0, VE, "profile" },
- { "vendor", "vendor ID", OFFSET(vendor),
- AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
- { "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
- AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
- { "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
- { .i64 = -1 }, -1, QUANT_MAT_DEFAULT, VE, "quant_mat" },
- { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 },
- 0, 0, VE, "quant_mat" },
- { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_PROXY },
- 0, 0, VE, "quant_mat" },
- { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_LT },
- 0, 0, VE, "quant_mat" },
- { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_STANDARD },
- 0, 0, VE, "quant_mat" },
- { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_HQ },
- 0, 0, VE, "quant_mat" },
- { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_DEFAULT },
- 0, 0, VE, "quant_mat" },
- { "alpha_bits", "bits for alpha plane", OFFSET(alpha_bits), AV_OPT_TYPE_INT,
- { .i64 = 16 }, 0, 16, VE },
- { NULL }
-};
-
-static const AVClass proresenc_class = {
- .class_name = "ProRes encoder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVCodec ff_prores_encoder = {
- .name = "prores",
- .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_PRORES,
- .priv_data_size = sizeof(ProresContext),
- .init = encode_init,
- .close = encode_close,
- .encode2 = encode_frame,
- .capabilities = CODEC_CAP_SLICE_THREADS,
- .pix_fmts = (const enum AVPixelFormat[]) {
- AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
- AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
- },
- .priv_class = &proresenc_class,
-};
diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c
new file mode 100644
index 0000000000..cc98c6611e
--- /dev/null
+++ b/libavcodec/proresenc_anatoliy.c
@@ -0,0 +1,635 @@
+/*
+ * Apple ProRes encoder
+ *
+ * Copyright (c) 2011 Anatoliy Wasserman
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Apple ProRes encoder (Anatoliy Wasserman version)
+ * Known FOURCCs: 'apch' (HQ), 'apcn' (SD), 'apcs' (LT), 'acpo' (Proxy)
+ */
+
+#include "avcodec.h"
+#include "dct.h"
+#include "internal.h"
+#include "put_bits.h"
+#include "bytestream.h"
+#include "fdctdsp.h"
+
+#define DEFAULT_SLICE_MB_WIDTH 8
+
+#define FF_PROFILE_PRORES_PROXY 0
+#define FF_PROFILE_PRORES_LT 1
+#define FF_PROFILE_PRORES_STANDARD 2
+#define FF_PROFILE_PRORES_HQ 3
+
+static const AVProfile profiles[] = {
+ { FF_PROFILE_PRORES_PROXY, "apco"},
+ { FF_PROFILE_PRORES_LT, "apcs"},
+ { FF_PROFILE_PRORES_STANDARD, "apcn"},
+ { FF_PROFILE_PRORES_HQ, "apch"},
+ { FF_PROFILE_UNKNOWN }
+};
+
+static const int qp_start_table[4] = { 4, 1, 1, 1 };
+static const int qp_end_table[4] = { 8, 9, 6, 6 };
+static const int bitrate_table[5] = { 1000, 2100, 3500, 5400 };
+
+static const uint8_t progressive_scan[64] = {
+ 0, 1, 8, 9, 2, 3, 10, 11,
+ 16, 17, 24, 25, 18, 19, 26, 27,
+ 4, 5, 12, 20, 13, 6, 7, 14,
+ 21, 28, 29, 22, 15, 23, 30, 31,
+ 32, 33, 40, 48, 41, 34, 35, 42,
+ 49, 56, 57, 50, 43, 36, 37, 44,
+ 51, 58, 59, 52, 45, 38, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+static const uint8_t QMAT_LUMA[4][64] = {
+ {
+ 4, 7, 9, 11, 13, 14, 15, 63,
+ 7, 7, 11, 12, 14, 15, 63, 63,
+ 9, 11, 13, 14, 15, 63, 63, 63,
+ 11, 11, 13, 14, 63, 63, 63, 63,
+ 11, 13, 14, 63, 63, 63, 63, 63,
+ 13, 14, 63, 63, 63, 63, 63, 63,
+ 13, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63
+ }, {
+ 4, 5, 6, 7, 9, 11, 13, 15,
+ 5, 5, 7, 8, 11, 13, 15, 17,
+ 6, 7, 9, 11, 13, 15, 15, 17,
+ 7, 7, 9, 11, 13, 15, 17, 19,
+ 7, 9, 11, 13, 14, 16, 19, 23,
+ 9, 11, 13, 14, 16, 19, 23, 29,
+ 9, 11, 13, 15, 17, 21, 28, 35,
+ 11, 13, 16, 17, 21, 28, 35, 41
+ }, {
+ 4, 4, 5, 5, 6, 7, 7, 9,
+ 4, 4, 5, 6, 7, 7, 9, 9,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 6, 7, 7, 8, 9, 10, 12,
+ 6, 7, 7, 8, 9, 10, 12, 15,
+ 6, 7, 7, 9, 10, 11, 14, 17,
+ 7, 7, 9, 10, 11, 14, 17, 21
+ }, {
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 4, 4, 4, 4, 4, 4, 5, 5,
+ 4, 4, 4, 4, 4, 5, 5, 6,
+ 4, 4, 4, 4, 5, 5, 6, 7,
+ 4, 4, 4, 4, 5, 6, 7, 7
+ }
+};
+
+static const uint8_t QMAT_CHROMA[4][64] = {
+ {
+ 4, 7, 9, 11, 13, 14, 63, 63,
+ 7, 7, 11, 12, 14, 63, 63, 63,
+ 9, 11, 13, 14, 63, 63, 63, 63,
+ 11, 11, 13, 14, 63, 63, 63, 63,
+ 11, 13, 14, 63, 63, 63, 63, 63,
+ 13, 14, 63, 63, 63, 63, 63, 63,
+ 13, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63
+ }, {
+ 4, 5, 6, 7, 9, 11, 13, 15,
+ 5, 5, 7, 8, 11, 13, 15, 17,
+ 6, 7, 9, 11, 13, 15, 15, 17,
+ 7, 7, 9, 11, 13, 15, 17, 19,
+ 7, 9, 11, 13, 14, 16, 19, 23,
+ 9, 11, 13, 14, 16, 19, 23, 29,
+ 9, 11, 13, 15, 17, 21, 28, 35,
+ 11, 13, 16, 17, 21, 28, 35, 41
+ }, {
+ 4, 4, 5, 5, 6, 7, 7, 9,
+ 4, 4, 5, 6, 7, 7, 9, 9,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 6, 7, 7, 8, 9, 10, 12,
+ 6, 7, 7, 8, 9, 10, 12, 15,
+ 6, 7, 7, 9, 10, 11, 14, 17,
+ 7, 7, 9, 10, 11, 14, 17, 21
+ }, {
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 4, 4, 4, 4, 4, 4, 5, 5,
+ 4, 4, 4, 4, 4, 5, 5, 6,
+ 4, 4, 4, 4, 5, 5, 6, 7,
+ 4, 4, 4, 4, 5, 6, 7, 7
+ }
+};
+
+
+typedef struct {
+ FDCTDSPContext fdsp;
+ uint8_t* fill_y;
+ uint8_t* fill_u;
+ uint8_t* fill_v;
+
+ int qmat_luma[16][64];
+ int qmat_chroma[16][64];
+} ProresContext;
+
+static void encode_codeword(PutBitContext *pb, int val, int codebook)
+{
+ unsigned int rice_order, exp_order, switch_bits, first_exp, exp, zeros;
+
+ /* number of bits to switch between rice and exp golomb */
+ switch_bits = codebook & 3;
+ rice_order = codebook >> 5;
+ exp_order = (codebook >> 2) & 7;
+
+ first_exp = ((switch_bits + 1) << rice_order);
+
+ if (val >= first_exp) { /* exp golomb */
+ val -= first_exp;
+ val += (1 << exp_order);
+ exp = av_log2(val);
+ zeros = exp - exp_order + switch_bits + 1;
+ put_bits(pb, zeros, 0);
+ put_bits(pb, exp + 1, val);
+ } else if (rice_order) {
+ put_bits(pb, (val >> rice_order), 0);
+ put_bits(pb, 1, 1);
+ put_sbits(pb, rice_order, val);
+ } else {
+ put_bits(pb, val, 0);
+ put_bits(pb, 1, 1);
+ }
+}
+
+#define QSCALE(qmat,ind,val) ((val) / ((qmat)[ind]))
+#define TO_GOLOMB(val) (((val) << 1) ^ ((val) >> 31))
+#define DIFF_SIGN(val, sign) (((val) >> 31) ^ (sign))
+#define IS_NEGATIVE(val) ((((val) >> 31) ^ -1) + 1)
+#define TO_GOLOMB2(val,sign) ((val)==0 ? 0 : ((val) << 1) + (sign))
+
+static av_always_inline int get_level(int val)
+{
+ int sign = (val >> 31);
+ return (val ^ sign) - sign;
+}
+
+#define FIRST_DC_CB 0xB8
+
+static const uint8_t dc_codebook[7] = { 0x04, 0x28, 0x28, 0x4D, 0x4D, 0x70, 0x70};
+
+static void encode_dc_coeffs(PutBitContext *pb, int16_t *in,
+ int blocks_per_slice, int *qmat)
+{
+ int prev_dc, code;
+ int i, sign, idx;
+ int new_dc, delta, diff_sign, new_code;
+
+ prev_dc = QSCALE(qmat, 0, in[0] - 16384);
+ code = TO_GOLOMB(prev_dc);
+ encode_codeword(pb, code, FIRST_DC_CB);
+
+ code = 5; sign = 0; idx = 64;
+ for (i = 1; i < blocks_per_slice; i++, idx += 64) {
+ new_dc = QSCALE(qmat, 0, in[idx] - 16384);
+ delta = new_dc - prev_dc;
+ diff_sign = DIFF_SIGN(delta, sign);
+ new_code = TO_GOLOMB2(get_level(delta), diff_sign);
+
+ encode_codeword(pb, new_code, dc_codebook[FFMIN(code, 6)]);
+
+ code = new_code;
+ sign = delta >> 31;
+ prev_dc = new_dc;
+ }
+}
+
+static const uint8_t run_to_cb[16] = { 0x06, 0x06, 0x05, 0x05, 0x04, 0x29,
+ 0x29, 0x29, 0x29, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4C };
+static const uint8_t lev_to_cb[10] = { 0x04, 0x0A, 0x05, 0x06, 0x04, 0x28,
+ 0x28, 0x28, 0x28, 0x4C };
+
+static void encode_ac_coeffs(AVCodecContext *avctx, PutBitContext *pb,
+ int16_t *in, int blocks_per_slice, int *qmat)
+{
+ int prev_run = 4;
+ int prev_level = 2;
+
+ int run = 0, level, code, i, j;
+ for (i = 1; i < 64; i++) {
+ int indp = progressive_scan[i];
+ for (j = 0; j < blocks_per_slice; j++) {
+ int val = QSCALE(qmat, indp, in[(j << 6) + indp]);
+ if (val) {
+ encode_codeword(pb, run, run_to_cb[FFMIN(prev_run, 15)]);
+
+ prev_run = run;
+ run = 0;
+ level = get_level(val);
+ code = level - 1;
+
+ encode_codeword(pb, code, lev_to_cb[FFMIN(prev_level, 9)]);
+
+ prev_level = level;
+
+ put_bits(pb, 1, IS_NEGATIVE(val));
+ } else {
+ ++run;
+ }
+ }
+ }
+}
+
+static void get(uint8_t *pixels, int stride, int16_t* block)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ AV_WN64(block, AV_RN64(pixels));
+ AV_WN64(block+4, AV_RN64(pixels+8));
+ pixels += stride;
+ block += 8;
+ }
+}
+
+static void fdct_get(FDCTDSPContext *fdsp, uint8_t *pixels, int stride, int16_t* block)
+{
+ get(pixels, stride, block);
+ fdsp->fdct(block);
+}
+
+static int encode_slice_plane(AVCodecContext *avctx, int mb_count,
+ uint8_t *src, int src_stride, uint8_t *buf, unsigned buf_size,
+ int *qmat, int chroma)
+{
+ ProresContext* ctx = avctx->priv_data;
+ FDCTDSPContext *fdsp = &ctx->fdsp;
+ LOCAL_ALIGNED(16, int16_t, blocks, [DEFAULT_SLICE_MB_WIDTH << 8]);
+ int16_t *block;
+ int i, blocks_per_slice;
+ PutBitContext pb;
+
+ block = blocks;
+ for (i = 0; i < mb_count; i++) {
+ fdct_get(fdsp, src, src_stride, block + (0 << 6));
+ fdct_get(fdsp, src + 8 * src_stride, src_stride, block + ((2 - chroma) << 6));
+ if (!chroma) {
+ fdct_get(fdsp, src + 16, src_stride, block + (1 << 6));
+ fdct_get(fdsp, src + 16 + 8 * src_stride, src_stride, block + (3 << 6));
+ }
+
+ block += (256 >> chroma);
+ src += (32 >> chroma);
+ }
+
+ blocks_per_slice = mb_count << (2 - chroma);
+ init_put_bits(&pb, buf, buf_size);
+
+ encode_dc_coeffs(&pb, blocks, blocks_per_slice, qmat);
+ encode_ac_coeffs(avctx, &pb, blocks, blocks_per_slice, qmat);
+
+ flush_put_bits(&pb);
+ return put_bits_ptr(&pb) - pb.buf;
+}
+
+static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx,
+ uint8_t *dest_y, uint8_t *dest_u, uint8_t *dest_v, int luma_stride,
+ int chroma_stride, unsigned mb_count, uint8_t *buf, unsigned data_size,
+ unsigned* y_data_size, unsigned* u_data_size, unsigned* v_data_size,
+ int qp)
+{
+ ProresContext* ctx = avctx->priv_data;
+
+ *y_data_size = encode_slice_plane(avctx, mb_count, dest_y, luma_stride,
+ buf, data_size, ctx->qmat_luma[qp - 1], 0);
+
+ if (!(avctx->flags & CODEC_FLAG_GRAY)) {
+ *u_data_size = encode_slice_plane(avctx, mb_count, dest_u,
+ chroma_stride, buf + *y_data_size, data_size - *y_data_size,
+ ctx->qmat_chroma[qp - 1], 1);
+
+ *v_data_size = encode_slice_plane(avctx, mb_count, dest_v,
+ chroma_stride, buf + *y_data_size + *u_data_size,
+ data_size - *y_data_size - *u_data_size,
+ ctx->qmat_chroma[qp - 1], 1);
+ }
+
+ return *y_data_size + *u_data_size + *v_data_size;
+}
+
+static void subimage_with_fill(uint16_t *src, unsigned x, unsigned y,
+ unsigned stride, unsigned width, unsigned height, uint16_t *dst,
+ unsigned dst_width, unsigned dst_height)
+{
+
+ int box_width = FFMIN(width - x, dst_width);
+ int box_height = FFMIN(height - y, dst_height);
+ int i, j, src_stride = stride >> 1;
+ uint16_t last_pix, *last_line;
+
+ src += y * src_stride + x;
+ for (i = 0; i < box_height; ++i) {
+ for (j = 0; j < box_width; ++j) {
+ dst[j] = src[j];
+ }
+ last_pix = dst[j - 1];
+ for (; j < dst_width; j++)
+ dst[j] = last_pix;
+ src += src_stride;
+ dst += dst_width;
+ }
+ last_line = dst - dst_width;
+ for (; i < dst_height; i++) {
+ for (j = 0; j < dst_width; ++j) {
+ dst[j] = last_line[j];
+ }
+ dst += dst_width;
+ }
+}
+
+static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, int mb_x,
+ int mb_y, unsigned mb_count, uint8_t *buf, unsigned data_size,
+ int unsafe, int *qp)
+{
+ int luma_stride, chroma_stride;
+ int hdr_size = 6, slice_size;
+ uint8_t *dest_y, *dest_u, *dest_v;
+ unsigned y_data_size = 0, u_data_size = 0, v_data_size = 0;
+ ProresContext* ctx = avctx->priv_data;
+ int tgt_bits = (mb_count * bitrate_table[avctx->profile]) >> 2;
+ int low_bytes = (tgt_bits - (tgt_bits >> 3)) >> 3; // 12% bitrate fluctuation
+ int high_bytes = (tgt_bits + (tgt_bits >> 3)) >> 3;
+
+ luma_stride = pic->linesize[0];
+ chroma_stride = pic->linesize[1];
+
+ dest_y = pic->data[0] + (mb_y << 4) * luma_stride + (mb_x << 5);
+ dest_u = pic->data[1] + (mb_y << 4) * chroma_stride + (mb_x << 4);
+ dest_v = pic->data[2] + (mb_y << 4) * chroma_stride + (mb_x << 4);
+
+ if (unsafe) {
+
+ subimage_with_fill((uint16_t *) pic->data[0], mb_x << 4, mb_y << 4,
+ luma_stride, avctx->width, avctx->height,
+ (uint16_t *) ctx->fill_y, mb_count << 4, 16);
+ subimage_with_fill((uint16_t *) pic->data[1], mb_x << 3, mb_y << 4,
+ chroma_stride, avctx->width >> 1, avctx->height,
+ (uint16_t *) ctx->fill_u, mb_count << 3, 16);
+ subimage_with_fill((uint16_t *) pic->data[2], mb_x << 3, mb_y << 4,
+ chroma_stride, avctx->width >> 1, avctx->height,
+ (uint16_t *) ctx->fill_v, mb_count << 3, 16);
+
+ encode_slice_data(avctx, ctx->fill_y, ctx->fill_u, ctx->fill_v,
+ mb_count << 5, mb_count << 4, mb_count, buf + hdr_size,
+ data_size - hdr_size, &y_data_size, &u_data_size, &v_data_size,
+ *qp);
+ } else {
+ slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v,
+ luma_stride, chroma_stride, mb_count, buf + hdr_size,
+ data_size - hdr_size, &y_data_size, &u_data_size, &v_data_size,
+ *qp);
+
+ if (slice_size > high_bytes && *qp < qp_end_table[avctx->profile]) {
+ do {
+ *qp += 1;
+ slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v,
+ luma_stride, chroma_stride, mb_count, buf + hdr_size,
+ data_size - hdr_size, &y_data_size, &u_data_size,
+ &v_data_size, *qp);
+ } while (slice_size > high_bytes && *qp < qp_end_table[avctx->profile]);
+ } else if (slice_size < low_bytes && *qp
+ > qp_start_table[avctx->profile]) {
+ do {
+ *qp -= 1;
+ slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v,
+ luma_stride, chroma_stride, mb_count, buf + hdr_size,
+ data_size - hdr_size, &y_data_size, &u_data_size,
+ &v_data_size, *qp);
+ } while (slice_size < low_bytes && *qp > qp_start_table[avctx->profile]);
+ }
+ }
+
+ buf[0] = hdr_size << 3;
+ buf[1] = *qp;
+ AV_WB16(buf + 2, y_data_size);
+ AV_WB16(buf + 4, u_data_size);
+
+ return hdr_size + y_data_size + u_data_size + v_data_size;
+}
+
+static int prores_encode_picture(AVCodecContext *avctx, const AVFrame *pic,
+ uint8_t *buf, const int buf_size)
+{
+ int mb_width = (avctx->width + 15) >> 4;
+ int mb_height = (avctx->height + 15) >> 4;
+ int hdr_size, sl_size, i;
+ int mb_y, sl_data_size, qp;
+ int unsafe_bot, unsafe_right;
+ uint8_t *sl_data, *sl_data_sizes;
+ int slice_per_line = 0, rem = mb_width;
+
+ for (i = av_log2(DEFAULT_SLICE_MB_WIDTH); i >= 0; --i) {
+ slice_per_line += rem >> i;
+ rem &= (1 << i) - 1;
+ }
+
+ qp = qp_start_table[avctx->profile];
+ hdr_size = 8; sl_data_size = buf_size - hdr_size;
+ sl_data_sizes = buf + hdr_size;
+ sl_data = sl_data_sizes + (slice_per_line * mb_height * 2);
+ for (mb_y = 0; mb_y < mb_height; mb_y++) {
+ int mb_x = 0;
+ int slice_mb_count = DEFAULT_SLICE_MB_WIDTH;
+ while (mb_x < mb_width) {
+ while (mb_width - mb_x < slice_mb_count)
+ slice_mb_count >>= 1;
+
+ unsafe_bot = (avctx->height & 0xf) && (mb_y == mb_height - 1);
+ unsafe_right = (avctx->width & 0xf) && (mb_x + slice_mb_count == mb_width);
+
+ sl_size = encode_slice(avctx, pic, mb_x, mb_y, slice_mb_count,
+ sl_data, sl_data_size, unsafe_bot || unsafe_right, &qp);
+
+ bytestream_put_be16(&sl_data_sizes, sl_size);
+ sl_data += sl_size;
+ sl_data_size -= sl_size;
+ mb_x += slice_mb_count;
+ }
+ }
+
+ buf[0] = hdr_size << 3;
+ AV_WB32(buf + 1, sl_data - buf);
+ AV_WB16(buf + 5, slice_per_line * mb_height);
+ buf[7] = av_log2(DEFAULT_SLICE_MB_WIDTH) << 4;
+
+ return sl_data - buf;
+}
+
+static int prores_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ int header_size = 148;
+ uint8_t *buf;
+ int pic_size, ret;
+ int frame_size = FFALIGN(avctx->width, 16) * FFALIGN(avctx->height, 16)*16 + 500 + FF_MIN_BUFFER_SIZE; //FIXME choose tighter limit
+
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, frame_size + FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+
+ buf = pkt->data;
+ pic_size = prores_encode_picture(avctx, pict, buf + header_size + 8,
+ pkt->size - header_size - 8);
+
+ bytestream_put_be32(&buf, pic_size + 8 + header_size);
+ bytestream_put_buffer(&buf, "icpf", 4);
+
+ bytestream_put_be16(&buf, header_size);
+ bytestream_put_be16(&buf, 0);
+ bytestream_put_buffer(&buf, "fmpg", 4);
+ bytestream_put_be16(&buf, avctx->width);
+ bytestream_put_be16(&buf, avctx->height);
+ *buf++ = 0x83; // {10}(422){00}{00}(frame){11}
+ *buf++ = 0;
+ *buf++ = 2;
+ *buf++ = 2;
+ *buf++ = 6;
+ *buf++ = 32;
+ *buf++ = 0;
+ *buf++ = 3;
+
+ bytestream_put_buffer(&buf, QMAT_LUMA[avctx->profile], 64);
+ bytestream_put_buffer(&buf, QMAT_CHROMA[avctx->profile], 64);
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->size = pic_size + 8 + header_size;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static void scale_mat(const uint8_t* src, int* dst, int scale)
+{
+ int i;
+ for (i = 0; i < 64; i++)
+ dst[i] = src[i] * scale;
+}
+
+static av_cold int prores_encode_init(AVCodecContext *avctx)
+{
+ int i;
+ ProresContext* ctx = avctx->priv_data;
+
+ if (avctx->pix_fmt != AV_PIX_FMT_YUV422P10) {
+ av_log(avctx, AV_LOG_ERROR, "need YUV422P10\n");
+ return -1;
+ }
+ avctx->bits_per_raw_sample = 10;
+
+ if (avctx->width & 0x1) {
+ av_log(avctx, AV_LOG_ERROR,
+ "frame width needs to be multiple of 2\n");
+ return -1;
+ }
+
+ if (avctx->width > 65534 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR,
+ "The maximum dimensions are 65534x65535\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((avctx->height & 0xf) || (avctx->width & 0xf)) {
+ ctx->fill_y = av_malloc(4 * (DEFAULT_SLICE_MB_WIDTH << 8));
+ if (!ctx->fill_y)
+ return AVERROR(ENOMEM);
+ ctx->fill_u = ctx->fill_y + (DEFAULT_SLICE_MB_WIDTH << 9);
+ ctx->fill_v = ctx->fill_u + (DEFAULT_SLICE_MB_WIDTH << 8);
+ }
+
+ if (avctx->profile == FF_PROFILE_UNKNOWN) {
+ avctx->profile = FF_PROFILE_PRORES_STANDARD;
+ av_log(avctx, AV_LOG_INFO,
+ "encoding with ProRes standard (apcn) profile\n");
+
+ } else if (avctx->profile < FF_PROFILE_PRORES_PROXY
+ || avctx->profile > FF_PROFILE_PRORES_HQ) {
+ av_log(
+ avctx,
+ AV_LOG_ERROR,
+ "unknown profile %d, use [0 - apco, 1 - apcs, 2 - apcn (default), 3 - apch]\n",
+ avctx->profile);
+ return -1;
+ }
+
+ ff_fdctdsp_init(&ctx->fdsp, avctx);
+
+ avctx->codec_tag = AV_RL32((const uint8_t*)profiles[avctx->profile].name);
+
+ for (i = 1; i <= 16; i++) {
+ scale_mat(QMAT_LUMA[avctx->profile] , ctx->qmat_luma[i - 1] , i);
+ scale_mat(QMAT_CHROMA[avctx->profile], ctx->qmat_chroma[i - 1], i);
+ }
+
+ avctx->coded_frame = av_frame_alloc();
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ return 0;
+}
+
+static av_cold int prores_encode_close(AVCodecContext *avctx)
+{
+ ProresContext* ctx = avctx->priv_data;
+ av_frame_free(&avctx->coded_frame);
+ av_freep(&ctx->fill_y);
+
+ return 0;
+}
+
+AVCodec ff_prores_aw_encoder = {
+ .name = "prores_aw",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = prores_encode_init,
+ .close = prores_encode_close,
+ .encode2 = prores_encode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE},
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .profiles = profiles
+};
+
+AVCodec ff_prores_encoder = {
+ .name = "prores",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = prores_encode_init,
+ .close = prores_encode_close,
+ .encode2 = prores_encode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE},
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
+ .profiles = profiles
+};
diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c
new file mode 100644
index 0000000000..18413681f6
--- /dev/null
+++ b/libavcodec/proresenc_kostya.c
@@ -0,0 +1,1355 @@
+/*
+ * Apple ProRes encoder
+ *
+ * Copyright (c) 2012 Konstantin Shishkov
+ *
+ * This encoder appears to be based on Anatoliy Wassermans considering
+ * similarities in the bugs.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/pixdesc.h"
+#include "avcodec.h"
+#include "fdctdsp.h"
+#include "put_bits.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "proresdata.h"
+
+#define CFACTOR_Y422 2
+#define CFACTOR_Y444 3
+
+#define MAX_MBS_PER_SLICE 8
+
+#define MAX_PLANES 4
+
+enum {
+ PRORES_PROFILE_AUTO = -1,
+ PRORES_PROFILE_PROXY = 0,
+ PRORES_PROFILE_LT,
+ PRORES_PROFILE_STANDARD,
+ PRORES_PROFILE_HQ,
+ PRORES_PROFILE_4444,
+};
+
+enum {
+ QUANT_MAT_PROXY = 0,
+ QUANT_MAT_LT,
+ QUANT_MAT_STANDARD,
+ QUANT_MAT_HQ,
+ QUANT_MAT_DEFAULT,
+};
+
+static const uint8_t prores_quant_matrices[][64] = {
+ { // proxy
+ 4, 7, 9, 11, 13, 14, 15, 63,
+ 7, 7, 11, 12, 14, 15, 63, 63,
+ 9, 11, 13, 14, 15, 63, 63, 63,
+ 11, 11, 13, 14, 63, 63, 63, 63,
+ 11, 13, 14, 63, 63, 63, 63, 63,
+ 13, 14, 63, 63, 63, 63, 63, 63,
+ 13, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ },
+ { // LT
+ 4, 5, 6, 7, 9, 11, 13, 15,
+ 5, 5, 7, 8, 11, 13, 15, 17,
+ 6, 7, 9, 11, 13, 15, 15, 17,
+ 7, 7, 9, 11, 13, 15, 17, 19,
+ 7, 9, 11, 13, 14, 16, 19, 23,
+ 9, 11, 13, 14, 16, 19, 23, 29,
+ 9, 11, 13, 15, 17, 21, 28, 35,
+ 11, 13, 16, 17, 21, 28, 35, 41,
+ },
+ { // standard
+ 4, 4, 5, 5, 6, 7, 7, 9,
+ 4, 4, 5, 6, 7, 7, 9, 9,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 6, 7, 7, 8, 9, 10, 12,
+ 6, 7, 7, 8, 9, 10, 12, 15,
+ 6, 7, 7, 9, 10, 11, 14, 17,
+ 7, 7, 9, 10, 11, 14, 17, 21,
+ },
+ { // high quality
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 4, 4, 4, 4, 4, 4, 5, 5,
+ 4, 4, 4, 4, 4, 5, 5, 6,
+ 4, 4, 4, 4, 5, 5, 6, 7,
+ 4, 4, 4, 4, 5, 6, 7, 7,
+ },
+ { // codec default
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ },
+};
+
+#define NUM_MB_LIMITS 4
+static const int prores_mb_limits[NUM_MB_LIMITS] = {
+ 1620, // up to 720x576
+ 2700, // up to 960x720
+ 6075, // up to 1440x1080
+ 9216, // up to 2048x1152
+};
+
+static const struct prores_profile {
+ const char *full_name;
+ uint32_t tag;
+ int min_quant;
+ int max_quant;
+ int br_tab[NUM_MB_LIMITS];
+ int quant;
+} prores_profile_info[5] = {
+ {
+ .full_name = "proxy",
+ .tag = MKTAG('a', 'p', 'c', 'o'),
+ .min_quant = 4,
+ .max_quant = 8,
+ .br_tab = { 300, 242, 220, 194 },
+ .quant = QUANT_MAT_PROXY,
+ },
+ {
+ .full_name = "LT",
+ .tag = MKTAG('a', 'p', 'c', 's'),
+ .min_quant = 1,
+ .max_quant = 9,
+ .br_tab = { 720, 560, 490, 440 },
+ .quant = QUANT_MAT_LT,
+ },
+ {
+ .full_name = "standard",
+ .tag = MKTAG('a', 'p', 'c', 'n'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 1050, 808, 710, 632 },
+ .quant = QUANT_MAT_STANDARD,
+ },
+ {
+ .full_name = "high quality",
+ .tag = MKTAG('a', 'p', 'c', 'h'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 1566, 1216, 1070, 950 },
+ .quant = QUANT_MAT_HQ,
+ },
+ {
+ .full_name = "4444",
+ .tag = MKTAG('a', 'p', '4', 'h'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 2350, 1828, 1600, 1425 },
+ .quant = QUANT_MAT_HQ,
+ }
+};
+
+#define TRELLIS_WIDTH 16
+#define SCORE_LIMIT INT_MAX / 2
+
+struct TrellisNode {
+ int prev_node;
+ int quant;
+ int bits;
+ int score;
+};
+
+#define MAX_STORED_Q 16
+
+typedef struct ProresThreadData {
+ DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
+ DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
+ int16_t custom_q[64];
+ struct TrellisNode *nodes;
+} ProresThreadData;
+
+typedef struct ProresContext {
+ AVClass *class;
+ DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
+ DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
+ int16_t quants[MAX_STORED_Q][64];
+ int16_t custom_q[64];
+ const uint8_t *quant_mat;
+ const uint8_t *scantable;
+
+ void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src,
+ int linesize, int16_t *block);
+ FDCTDSPContext fdsp;
+
+ int mb_width, mb_height;
+ int mbs_per_slice;
+ int num_chroma_blocks, chroma_factor;
+ int slices_width;
+ int slices_per_picture;
+ int pictures_per_frame; // 1 for progressive, 2 for interlaced
+ int cur_picture_idx;
+ int num_planes;
+ int bits_per_mb;
+ int force_quant;
+ int alpha_bits;
+ int warn;
+
+ char *vendor;
+ int quant_sel;
+
+ int frame_size_upper_bound;
+
+ int profile;
+ const struct prores_profile *profile_info;
+
+ int *slice_q;
+
+ ProresThreadData *tdata;
+} ProresContext;
+
+static void get_slice_data(ProresContext *ctx, const uint16_t *src,
+ int linesize, int x, int y, int w, int h,
+ int16_t *blocks, uint16_t *emu_buf,
+ int mbs_per_slice, int blocks_per_mb, int is_chroma)
+{
+ const uint16_t *esrc;
+ const int mb_width = 4 * blocks_per_mb;
+ int elinesize;
+ int i, j, k;
+
+ for (i = 0; i < mbs_per_slice; i++, src += mb_width) {
+ if (x >= w) {
+ memset(blocks, 0, 64 * (mbs_per_slice - i) * blocks_per_mb
+ * sizeof(*blocks));
+ return;
+ }
+ if (x + mb_width <= w && y + 16 <= h) {
+ esrc = src;
+ elinesize = linesize;
+ } else {
+ int bw, bh, pix;
+
+ esrc = emu_buf;
+ elinesize = 16 * sizeof(*emu_buf);
+
+ bw = FFMIN(w - x, mb_width);
+ bh = FFMIN(h - y, 16);
+
+ for (j = 0; j < bh; j++) {
+ memcpy(emu_buf + j * 16,
+ (const uint8_t*)src + j * linesize,
+ bw * sizeof(*src));
+ pix = emu_buf[j * 16 + bw - 1];
+ for (k = bw; k < mb_width; k++)
+ emu_buf[j * 16 + k] = pix;
+ }
+ for (; j < 16; j++)
+ memcpy(emu_buf + j * 16,
+ emu_buf + (bh - 1) * 16,
+ mb_width * sizeof(*emu_buf));
+ }
+ if (!is_chroma) {
+ ctx->fdct(&ctx->fdsp, esrc, elinesize, blocks);
+ blocks += 64;
+ if (blocks_per_mb > 2) {
+ ctx->fdct(&ctx->fdsp, esrc + 8, elinesize, blocks);
+ blocks += 64;
+ }
+ ctx->fdct(&ctx->fdsp, esrc + elinesize * 4, elinesize, blocks);
+ blocks += 64;
+ if (blocks_per_mb > 2) {
+ ctx->fdct(&ctx->fdsp, esrc + elinesize * 4 + 8, elinesize, blocks);
+ blocks += 64;
+ }
+ } else {
+ ctx->fdct(&ctx->fdsp, esrc, elinesize, blocks);
+ blocks += 64;
+ ctx->fdct(&ctx->fdsp, esrc + elinesize * 4, elinesize, blocks);
+ blocks += 64;
+ if (blocks_per_mb > 2) {
+ ctx->fdct(&ctx->fdsp, esrc + 8, elinesize, blocks);
+ blocks += 64;
+ ctx->fdct(&ctx->fdsp, esrc + elinesize * 4 + 8, elinesize, blocks);
+ blocks += 64;
+ }
+ }
+
+ x += mb_width;
+ }
+}
+
+static void get_alpha_data(ProresContext *ctx, const uint16_t *src,
+ int linesize, int x, int y, int w, int h,
+ int16_t *blocks, int mbs_per_slice, int abits)
+{
+ const int slice_width = 16 * mbs_per_slice;
+ int i, j, copy_w, copy_h;
+
+ copy_w = FFMIN(w - x, slice_width);
+ copy_h = FFMIN(h - y, 16);
+ for (i = 0; i < copy_h; i++) {
+ memcpy(blocks, src, copy_w * sizeof(*src));
+ if (abits == 8)
+ for (j = 0; j < copy_w; j++)
+ blocks[j] >>= 2;
+ else
+ for (j = 0; j < copy_w; j++)
+ blocks[j] = (blocks[j] << 6) | (blocks[j] >> 4);
+ for (j = copy_w; j < slice_width; j++)
+ blocks[j] = blocks[copy_w - 1];
+ blocks += slice_width;
+ src += linesize >> 1;
+ }
+ for (; i < 16; i++) {
+ memcpy(blocks, blocks - slice_width, slice_width * sizeof(*blocks));
+ blocks += slice_width;
+ }
+}
+
+/**
+ * Write an unsigned rice/exp golomb codeword.
+ */
+static inline void encode_vlc_codeword(PutBitContext *pb, unsigned codebook, int val)
+{
+ unsigned int rice_order, exp_order, switch_bits, switch_val;
+ int exponent;
+
+ /* number of prefix bits to switch between Rice and expGolomb */
+ switch_bits = (codebook & 3) + 1;
+ rice_order = codebook >> 5; /* rice code order */
+ exp_order = (codebook >> 2) & 7; /* exp golomb code order */
+
+ switch_val = switch_bits << rice_order;
+
+ if (val >= switch_val) {
+ val -= switch_val - (1 << exp_order);
+ exponent = av_log2(val);
+
+ put_bits(pb, exponent - exp_order + switch_bits, 0);
+ put_bits(pb, exponent + 1, val);
+ } else {
+ exponent = val >> rice_order;
+
+ if (exponent)
+ put_bits(pb, exponent, 0);
+ put_bits(pb, 1, 1);
+ if (rice_order)
+ put_sbits(pb, rice_order, val);
+ }
+}
+
+#define GET_SIGN(x) ((x) >> 31)
+#define MAKE_CODE(x) (((x) << 1) ^ GET_SIGN(x))
+
+static void encode_dcs(PutBitContext *pb, int16_t *blocks,
+ int blocks_per_slice, int scale)
+{
+ int i;
+ int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
+
+ prev_dc = (blocks[0] - 0x4000) / scale;
+ encode_vlc_codeword(pb, FIRST_DC_CB, MAKE_CODE(prev_dc));
+ sign = 0;
+ codebook = 3;
+ blocks += 64;
+
+ for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
+ dc = (blocks[0] - 0x4000) / scale;
+ delta = dc - prev_dc;
+ new_sign = GET_SIGN(delta);
+ delta = (delta ^ sign) - sign;
+ code = MAKE_CODE(delta);
+ encode_vlc_codeword(pb, ff_prores_dc_codebook[codebook], code);
+ codebook = (code + (code & 1)) >> 1;
+ codebook = FFMIN(codebook, 3);
+ sign = new_sign;
+ prev_dc = dc;
+ }
+}
+
+static void encode_acs(PutBitContext *pb, int16_t *blocks,
+ int blocks_per_slice,
+ int plane_size_factor,
+ const uint8_t *scan, const int16_t *qmat)
+{
+ int idx, i;
+ int run, level, run_cb, lev_cb;
+ int max_coeffs, abs_level;
+
+ max_coeffs = blocks_per_slice << 6;
+ run_cb = ff_prores_run_to_cb_index[4];
+ lev_cb = ff_prores_lev_to_cb_index[2];
+ run = 0;
+
+ for (i = 1; i < 64; i++) {
+ for (idx = scan[i]; idx < max_coeffs; idx += 64) {
+ level = blocks[idx] / qmat[scan[i]];
+ if (level) {
+ abs_level = FFABS(level);
+ encode_vlc_codeword(pb, ff_prores_ac_codebook[run_cb], run);
+ encode_vlc_codeword(pb, ff_prores_ac_codebook[lev_cb],
+ abs_level - 1);
+ put_sbits(pb, 1, GET_SIGN(level));
+
+ run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
+ lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
+ run = 0;
+ } else {
+ run++;
+ }
+ }
+ }
+}
+
+static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice, int16_t *blocks,
+ int blocks_per_mb, int plane_size_factor,
+ const int16_t *qmat)
+{
+ int blocks_per_slice, saved_pos;
+
+ saved_pos = put_bits_count(pb);
+ blocks_per_slice = mbs_per_slice * blocks_per_mb;
+
+ encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
+ encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
+ ctx->scantable, qmat);
+ flush_put_bits(pb);
+
+ return (put_bits_count(pb) - saved_pos) >> 3;
+}
+
+static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
+{
+ const int dbits = (abits == 8) ? 4 : 7;
+ const int dsize = 1 << dbits - 1;
+ int diff = cur - prev;
+
+ diff = av_mod_uintp2(diff, abits);
+ if (diff >= (1 << abits) - dsize)
+ diff -= 1 << abits;
+ if (diff < -dsize || diff > dsize || !diff) {
+ put_bits(pb, 1, 1);
+ put_bits(pb, abits, diff);
+ } else {
+ put_bits(pb, 1, 0);
+ put_bits(pb, dbits - 1, FFABS(diff) - 1);
+ put_bits(pb, 1, diff < 0);
+ }
+}
+
+static void put_alpha_run(PutBitContext *pb, int run)
+{
+ if (run) {
+ put_bits(pb, 1, 0);
+ if (run < 0x10)
+ put_bits(pb, 4, run);
+ else
+ put_bits(pb, 15, run);
+ } else {
+ put_bits(pb, 1, 1);
+ }
+}
+
+// todo alpha quantisation for high quants
+static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
+ int mbs_per_slice, uint16_t *blocks,
+ int quant)
+{
+ const int abits = ctx->alpha_bits;
+ const int mask = (1 << abits) - 1;
+ const int num_coeffs = mbs_per_slice * 256;
+ int saved_pos = put_bits_count(pb);
+ int prev = mask, cur;
+ int idx = 0;
+ int run = 0;
+
+ cur = blocks[idx++];
+ put_alpha_diff(pb, cur, prev, abits);
+ prev = cur;
+ do {
+ cur = blocks[idx++];
+ if (cur != prev) {
+ put_alpha_run (pb, run);
+ put_alpha_diff(pb, cur, prev, abits);
+ prev = cur;
+ run = 0;
+ } else {
+ run++;
+ }
+ } while (idx < num_coeffs);
+ if (run)
+ put_alpha_run(pb, run);
+ flush_put_bits(pb);
+ return (put_bits_count(pb) - saved_pos) >> 3;
+}
+
+static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
+ PutBitContext *pb,
+ int sizes[4], int x, int y, int quant,
+ int mbs_per_slice)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i, xp, yp;
+ int total_size = 0;
+ const uint16_t *src;
+ int slice_width_factor = av_log2(mbs_per_slice);
+ int num_cblocks, pwidth, linesize, line_add;
+ int plane_factor, is_chroma;
+ uint16_t *qmat;
+
+ if (ctx->pictures_per_frame == 1)
+ line_add = 0;
+ else
+ line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
+
+ if (ctx->force_quant) {
+ qmat = ctx->quants[0];
+ } else if (quant < MAX_STORED_Q) {
+ qmat = ctx->quants[quant];
+ } else {
+ qmat = ctx->custom_q;
+ for (i = 0; i < 64; i++)
+ qmat[i] = ctx->quant_mat[i] * quant;
+ }
+
+ for (i = 0; i < ctx->num_planes; i++) {
+ is_chroma = (i == 1 || i == 2);
+ plane_factor = slice_width_factor + 2;
+ if (is_chroma)
+ plane_factor += ctx->chroma_factor - 3;
+ if (!is_chroma || ctx->chroma_factor == CFACTOR_Y444) {
+ xp = x << 4;
+ yp = y << 4;
+ num_cblocks = 4;
+ pwidth = avctx->width;
+ } else {
+ xp = x << 3;
+ yp = y << 4;
+ num_cblocks = 2;
+ pwidth = avctx->width >> 1;
+ }
+
+ linesize = pic->linesize[i] * ctx->pictures_per_frame;
+ src = (const uint16_t*)(pic->data[i] + yp * linesize +
+ line_add * pic->linesize[i]) + xp;
+
+ if (i < 3) {
+ get_slice_data(ctx, src, linesize, xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ ctx->blocks[0], ctx->emu_buf,
+ mbs_per_slice, num_cblocks, is_chroma);
+ sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
+ mbs_per_slice, ctx->blocks[0],
+ num_cblocks, plane_factor,
+ qmat);
+ } else {
+ get_alpha_data(ctx, src, linesize, xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
+ sizes[i] = encode_alpha_plane(ctx, pb, mbs_per_slice,
+ ctx->blocks[0], quant);
+ }
+ total_size += sizes[i];
+ if (put_bits_left(pb) < 0) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Underestimated required buffer size.\n");
+ return AVERROR_BUG;
+ }
+ }
+ return total_size;
+}
+
+static inline int estimate_vlc(unsigned codebook, int val)
+{
+ unsigned int rice_order, exp_order, switch_bits, switch_val;
+ int exponent;
+
+ /* number of prefix bits to switch between Rice and expGolomb */
+ switch_bits = (codebook & 3) + 1;
+ rice_order = codebook >> 5; /* rice code order */
+ exp_order = (codebook >> 2) & 7; /* exp golomb code order */
+
+ switch_val = switch_bits << rice_order;
+
+ if (val >= switch_val) {
+ val -= switch_val - (1 << exp_order);
+ exponent = av_log2(val);
+
+ return exponent * 2 - exp_order + switch_bits + 1;
+ } else {
+ return (val >> rice_order) + rice_order + 1;
+ }
+}
+
+static int estimate_dcs(int *error, int16_t *blocks, int blocks_per_slice,
+ int scale)
+{
+ int i;
+ int codebook = 3, code, dc, prev_dc, delta, sign, new_sign;
+ int bits;
+
+ prev_dc = (blocks[0] - 0x4000) / scale;
+ bits = estimate_vlc(FIRST_DC_CB, MAKE_CODE(prev_dc));
+ sign = 0;
+ codebook = 3;
+ blocks += 64;
+ *error += FFABS(blocks[0] - 0x4000) % scale;
+
+ for (i = 1; i < blocks_per_slice; i++, blocks += 64) {
+ dc = (blocks[0] - 0x4000) / scale;
+ *error += FFABS(blocks[0] - 0x4000) % scale;
+ delta = dc - prev_dc;
+ new_sign = GET_SIGN(delta);
+ delta = (delta ^ sign) - sign;
+ code = MAKE_CODE(delta);
+ bits += estimate_vlc(ff_prores_dc_codebook[codebook], code);
+ codebook = (code + (code & 1)) >> 1;
+ codebook = FFMIN(codebook, 3);
+ sign = new_sign;
+ prev_dc = dc;
+ }
+
+ return bits;
+}
+
+static int estimate_acs(int *error, int16_t *blocks, int blocks_per_slice,
+ int plane_size_factor,
+ const uint8_t *scan, const int16_t *qmat)
+{
+ int idx, i;
+ int run, level, run_cb, lev_cb;
+ int max_coeffs, abs_level;
+ int bits = 0;
+
+ max_coeffs = blocks_per_slice << 6;
+ run_cb = ff_prores_run_to_cb_index[4];
+ lev_cb = ff_prores_lev_to_cb_index[2];
+ run = 0;
+
+ for (i = 1; i < 64; i++) {
+ for (idx = scan[i]; idx < max_coeffs; idx += 64) {
+ level = blocks[idx] / qmat[scan[i]];
+ *error += FFABS(blocks[idx]) % qmat[scan[i]];
+ if (level) {
+ abs_level = FFABS(level);
+ bits += estimate_vlc(ff_prores_ac_codebook[run_cb], run);
+ bits += estimate_vlc(ff_prores_ac_codebook[lev_cb],
+ abs_level - 1) + 1;
+
+ run_cb = ff_prores_run_to_cb_index[FFMIN(run, 15)];
+ lev_cb = ff_prores_lev_to_cb_index[FFMIN(abs_level, 9)];
+ run = 0;
+ } else {
+ run++;
+ }
+ }
+ }
+
+ return bits;
+}
+
+static int estimate_slice_plane(ProresContext *ctx, int *error, int plane,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice,
+ int blocks_per_mb, int plane_size_factor,
+ const int16_t *qmat, ProresThreadData *td)
+{
+ int blocks_per_slice;
+ int bits;
+
+ blocks_per_slice = mbs_per_slice * blocks_per_mb;
+
+ bits = estimate_dcs(error, td->blocks[plane], blocks_per_slice, qmat[0]);
+ bits += estimate_acs(error, td->blocks[plane], blocks_per_slice,
+ plane_size_factor, ctx->scantable, qmat);
+
+ return FFALIGN(bits, 8);
+}
+
+static int est_alpha_diff(int cur, int prev, int abits)
+{
+ const int dbits = (abits == 8) ? 4 : 7;
+ const int dsize = 1 << dbits - 1;
+ int diff = cur - prev;
+
+ diff = av_mod_uintp2(diff, abits);
+ if (diff >= (1 << abits) - dsize)
+ diff -= 1 << abits;
+ if (diff < -dsize || diff > dsize || !diff)
+ return abits + 1;
+ else
+ return dbits + 1;
+}
+
+static int estimate_alpha_plane(ProresContext *ctx, int *error,
+ const uint16_t *src, int linesize,
+ int mbs_per_slice, int quant,
+ int16_t *blocks)
+{
+ const int abits = ctx->alpha_bits;
+ const int mask = (1 << abits) - 1;
+ const int num_coeffs = mbs_per_slice * 256;
+ int prev = mask, cur;
+ int idx = 0;
+ int run = 0;
+ int bits;
+
+ *error = 0;
+ cur = blocks[idx++];
+ bits = est_alpha_diff(cur, prev, abits);
+ prev = cur;
+ do {
+ cur = blocks[idx++];
+ if (cur != prev) {
+ if (!run)
+ bits++;
+ else if (run < 0x10)
+ bits += 4;
+ else
+ bits += 15;
+ bits += est_alpha_diff(cur, prev, abits);
+ prev = cur;
+ run = 0;
+ } else {
+ run++;
+ }
+ } while (idx < num_coeffs);
+
+ if (run) {
+ if (run < 0x10)
+ bits += 4;
+ else
+ bits += 15;
+ }
+
+ return bits;
+}
+
+static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
+ int trellis_node, int x, int y, int mbs_per_slice,
+ ProresThreadData *td)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i, q, pq, xp, yp;
+ const uint16_t *src;
+ int slice_width_factor = av_log2(mbs_per_slice);
+ int num_cblocks[MAX_PLANES], pwidth;
+ int plane_factor[MAX_PLANES], is_chroma[MAX_PLANES];
+ const int min_quant = ctx->profile_info->min_quant;
+ const int max_quant = ctx->profile_info->max_quant;
+ int error, bits, bits_limit;
+ int mbs, prev, cur, new_score;
+ int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
+ int overquant;
+ uint16_t *qmat;
+ int linesize[4], line_add;
+
+ if (ctx->pictures_per_frame == 1)
+ line_add = 0;
+ else
+ line_add = ctx->cur_picture_idx ^ !pic->top_field_first;
+ mbs = x + mbs_per_slice;
+
+ for (i = 0; i < ctx->num_planes; i++) {
+ is_chroma[i] = (i == 1 || i == 2);
+ plane_factor[i] = slice_width_factor + 2;
+ if (is_chroma[i])
+ plane_factor[i] += ctx->chroma_factor - 3;
+ if (!is_chroma[i] || ctx->chroma_factor == CFACTOR_Y444) {
+ xp = x << 4;
+ yp = y << 4;
+ num_cblocks[i] = 4;
+ pwidth = avctx->width;
+ } else {
+ xp = x << 3;
+ yp = y << 4;
+ num_cblocks[i] = 2;
+ pwidth = avctx->width >> 1;
+ }
+
+ linesize[i] = pic->linesize[i] * ctx->pictures_per_frame;
+ src = (const uint16_t*)(pic->data[i] + yp * linesize[i] +
+ line_add * pic->linesize[i]) + xp;
+
+ if (i < 3) {
+ get_slice_data(ctx, src, linesize[i], xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ td->blocks[i], td->emu_buf,
+ mbs_per_slice, num_cblocks[i], is_chroma[i]);
+ } else {
+ get_alpha_data(ctx, src, linesize[i], xp, yp,
+ pwidth, avctx->height / ctx->pictures_per_frame,
+ td->blocks[i], mbs_per_slice, ctx->alpha_bits);
+ }
+ }
+
+ for (q = min_quant; q < max_quant + 2; q++) {
+ td->nodes[trellis_node + q].prev_node = -1;
+ td->nodes[trellis_node + q].quant = q;
+ }
+
+ // todo: maybe perform coarser quantising to fit into frame size when needed
+ for (q = min_quant; q <= max_quant; q++) {
+ bits = 0;
+ error = 0;
+ for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+ bits += estimate_slice_plane(ctx, &error, i,
+ src, linesize[i],
+ mbs_per_slice,
+ num_cblocks[i], plane_factor[i],
+ ctx->quants[q], td);
+ }
+ if (ctx->alpha_bits)
+ bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
+ mbs_per_slice, q, td->blocks[3]);
+ if (bits > 65000 * 8)
+ error = SCORE_LIMIT;
+
+ slice_bits[q] = bits;
+ slice_score[q] = error;
+ }
+ if (slice_bits[max_quant] <= ctx->bits_per_mb * mbs_per_slice) {
+ slice_bits[max_quant + 1] = slice_bits[max_quant];
+ slice_score[max_quant + 1] = slice_score[max_quant] + 1;
+ overquant = max_quant;
+ } else {
+ for (q = max_quant + 1; q < 128; q++) {
+ bits = 0;
+ error = 0;
+ if (q < MAX_STORED_Q) {
+ qmat = ctx->quants[q];
+ } else {
+ qmat = td->custom_q;
+ for (i = 0; i < 64; i++)
+ qmat[i] = ctx->quant_mat[i] * q;
+ }
+ for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+ bits += estimate_slice_plane(ctx, &error, i,
+ src, linesize[i],
+ mbs_per_slice,
+ num_cblocks[i], plane_factor[i],
+ qmat, td);
+ }
+ if (ctx->alpha_bits)
+ bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
+ mbs_per_slice, q, td->blocks[3]);
+ if (bits <= ctx->bits_per_mb * mbs_per_slice)
+ break;
+ }
+
+ slice_bits[max_quant + 1] = bits;
+ slice_score[max_quant + 1] = error;
+ overquant = q;
+ }
+ td->nodes[trellis_node + max_quant + 1].quant = overquant;
+
+ bits_limit = mbs * ctx->bits_per_mb;
+ for (pq = min_quant; pq < max_quant + 2; pq++) {
+ prev = trellis_node - TRELLIS_WIDTH + pq;
+
+ for (q = min_quant; q < max_quant + 2; q++) {
+ cur = trellis_node + q;
+
+ bits = td->nodes[prev].bits + slice_bits[q];
+ error = slice_score[q];
+ if (bits > bits_limit)
+ error = SCORE_LIMIT;
+
+ if (td->nodes[prev].score < SCORE_LIMIT && error < SCORE_LIMIT)
+ new_score = td->nodes[prev].score + error;
+ else
+ new_score = SCORE_LIMIT;
+ if (td->nodes[cur].prev_node == -1 ||
+ td->nodes[cur].score >= new_score) {
+
+ td->nodes[cur].bits = bits;
+ td->nodes[cur].score = new_score;
+ td->nodes[cur].prev_node = prev;
+ }
+ }
+ }
+
+ error = td->nodes[trellis_node + min_quant].score;
+ pq = trellis_node + min_quant;
+ for (q = min_quant + 1; q < max_quant + 2; q++) {
+ if (td->nodes[trellis_node + q].score <= error) {
+ error = td->nodes[trellis_node + q].score;
+ pq = trellis_node + q;
+ }
+ }
+
+ return pq;
+}
+
+static int find_quant_thread(AVCodecContext *avctx, void *arg,
+ int jobnr, int threadnr)
+{
+ ProresContext *ctx = avctx->priv_data;
+ ProresThreadData *td = ctx->tdata + threadnr;
+ int mbs_per_slice = ctx->mbs_per_slice;
+ int x, y = jobnr, mb, q = 0;
+
+ for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
+ while (ctx->mb_width - x < mbs_per_slice)
+ mbs_per_slice >>= 1;
+ q = find_slice_quant(avctx, arg,
+ (mb + 1) * TRELLIS_WIDTH, x, y,
+ mbs_per_slice, td);
+ }
+
+ for (x = ctx->slices_width - 1; x >= 0; x--) {
+ ctx->slice_q[x + y * ctx->slices_width] = td->nodes[q].quant;
+ q = td->nodes[q].prev_node;
+ }
+
+ return 0;
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ ProresContext *ctx = avctx->priv_data;
+ uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes, *tmp;
+ uint8_t *picture_size_pos;
+ PutBitContext pb;
+ int x, y, i, mb, q = 0;
+ int sizes[4] = { 0 };
+ int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1);
+ int frame_size, picture_size, slice_size;
+ int pkt_size, ret;
+ int max_slice_size = (ctx->frame_size_upper_bound - 200) / (ctx->pictures_per_frame * ctx->slices_per_picture + 1);
+ uint8_t frame_flags;
+
+ pkt_size = ctx->frame_size_upper_bound;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size + FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+
+ orig_buf = pkt->data;
+
+ // frame atom
+ orig_buf += 4; // frame size
+ bytestream_put_be32 (&orig_buf, FRAME_ID); // frame container ID
+ buf = orig_buf;
+
+ // frame header
+ tmp = buf;
+ buf += 2; // frame header size will be stored here
+ bytestream_put_be16 (&buf, 0); // version 1
+ bytestream_put_buffer(&buf, ctx->vendor, 4);
+ bytestream_put_be16 (&buf, avctx->width);
+ bytestream_put_be16 (&buf, avctx->height);
+
+ frame_flags = ctx->chroma_factor << 6;
+ if (avctx->flags & CODEC_FLAG_INTERLACED_DCT)
+ frame_flags |= pic->top_field_first ? 0x04 : 0x08;
+ bytestream_put_byte (&buf, frame_flags);
+
+ bytestream_put_byte (&buf, 0); // reserved
+ bytestream_put_byte (&buf, avctx->color_primaries);
+ bytestream_put_byte (&buf, avctx->color_trc);
+ bytestream_put_byte (&buf, avctx->colorspace);
+ bytestream_put_byte (&buf, 0x40 | (ctx->alpha_bits >> 3));
+ bytestream_put_byte (&buf, 0); // reserved
+ if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
+ bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
+ // luma quantisation matrix
+ for (i = 0; i < 64; i++)
+ bytestream_put_byte(&buf, ctx->quant_mat[i]);
+ // chroma quantisation matrix
+ for (i = 0; i < 64; i++)
+ bytestream_put_byte(&buf, ctx->quant_mat[i]);
+ } else {
+ bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used
+ }
+ bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header size
+
+ for (ctx->cur_picture_idx = 0;
+ ctx->cur_picture_idx < ctx->pictures_per_frame;
+ ctx->cur_picture_idx++) {
+ // picture header
+ picture_size_pos = buf + 1;
+ bytestream_put_byte (&buf, 0x40); // picture header size (in bits)
+ buf += 4; // picture data size will be stored here
+ bytestream_put_be16 (&buf, ctx->slices_per_picture);
+ bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice width and height in MBs
+
+ // seek table - will be filled during slice encoding
+ slice_sizes = buf;
+ buf += ctx->slices_per_picture * 2;
+
+ // slices
+ if (!ctx->force_quant) {
+ ret = avctx->execute2(avctx, find_quant_thread, (void*)pic, NULL,
+ ctx->mb_height);
+ if (ret)
+ return ret;
+ }
+
+ for (y = 0; y < ctx->mb_height; y++) {
+ int mbs_per_slice = ctx->mbs_per_slice;
+ for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
+ q = ctx->force_quant ? ctx->force_quant
+ : ctx->slice_q[mb + y * ctx->slices_width];
+
+ while (ctx->mb_width - x < mbs_per_slice)
+ mbs_per_slice >>= 1;
+
+ bytestream_put_byte(&buf, slice_hdr_size << 3);
+ slice_hdr = buf;
+ buf += slice_hdr_size - 1;
+ if (pkt_size <= buf - orig_buf + 2 * max_slice_size) {
+ uint8_t *start = pkt->data;
+ // Recompute new size according to max_slice_size
+ // and deduce delta
+ int delta = 200 + (ctx->pictures_per_frame *
+ ctx->slices_per_picture + 1) *
+ max_slice_size - pkt_size;
+
+ delta = FFMAX(delta, 2 * max_slice_size);
+ ctx->frame_size_upper_bound += delta;
+
+ if (!ctx->warn) {
+ avpriv_request_sample(avctx,
+ "Packet too small: is %i,"
+ " needs %i (slice: %i). "
+ "Correct allocation",
+ pkt_size, delta, max_slice_size);
+ ctx->warn = 1;
+ }
+
+ ret = av_grow_packet(pkt, delta);
+ if (ret < 0)
+ return ret;
+
+ pkt_size += delta;
+ // restore pointers
+ orig_buf = pkt->data + (orig_buf - start);
+ buf = pkt->data + (buf - start);
+ picture_size_pos = pkt->data + (picture_size_pos - start);
+ slice_sizes = pkt->data + (slice_sizes - start);
+ slice_hdr = pkt->data + (slice_hdr - start);
+ tmp = pkt->data + (tmp - start);
+ }
+ init_put_bits(&pb, buf, (pkt_size - (buf - orig_buf)));
+ ret = encode_slice(avctx, pic, &pb, sizes, x, y, q,
+ mbs_per_slice);
+ if (ret < 0)
+ return ret;
+
+ bytestream_put_byte(&slice_hdr, q);
+ slice_size = slice_hdr_size + sizes[ctx->num_planes - 1];
+ for (i = 0; i < ctx->num_planes - 1; i++) {
+ bytestream_put_be16(&slice_hdr, sizes[i]);
+ slice_size += sizes[i];
+ }
+ bytestream_put_be16(&slice_sizes, slice_size);
+ buf += slice_size - slice_hdr_size;
+ if (max_slice_size < slice_size)
+ max_slice_size = slice_size;
+ }
+ }
+
+ picture_size = buf - (picture_size_pos - 1);
+ bytestream_put_be32(&picture_size_pos, picture_size);
+ }
+
+ orig_buf -= 8;
+ frame_size = buf - orig_buf;
+ bytestream_put_be32(&orig_buf, frame_size);
+
+ pkt->size = frame_size;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static av_cold int encode_close(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int i;
+
+ av_frame_free(&avctx->coded_frame);
+
+ if (ctx->tdata) {
+ for (i = 0; i < avctx->thread_count; i++)
+ av_freep(&ctx->tdata[i].nodes);
+ }
+ av_freep(&ctx->tdata);
+ av_freep(&ctx->slice_q);
+
+ return 0;
+}
+
+static void prores_fdct(FDCTDSPContext *fdsp, const uint16_t *src,
+ int linesize, int16_t *block)
+{
+ int x, y;
+ const uint16_t *tsrc = src;
+
+ for (y = 0; y < 8; y++) {
+ for (x = 0; x < 8; x++)
+ block[y * 8 + x] = tsrc[x];
+ tsrc += linesize >> 1;
+ }
+ fdsp->fdct(block);
+}
+
+static av_cold int encode_init(AVCodecContext *avctx)
+{
+ ProresContext *ctx = avctx->priv_data;
+ int mps;
+ int i, j;
+ int min_quant, max_quant;
+ int interlaced = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
+
+ avctx->bits_per_raw_sample = 10;
+ avctx->coded_frame = av_frame_alloc();
+ if (!avctx->coded_frame)
+ return AVERROR(ENOMEM);
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ avctx->coded_frame->key_frame = 1;
+
+ ctx->fdct = prores_fdct;
+ ctx->scantable = interlaced ? ff_prores_interlaced_scan
+ : ff_prores_progressive_scan;
+ ff_fdctdsp_init(&ctx->fdsp, avctx);
+
+ mps = ctx->mbs_per_slice;
+ if (mps & (mps - 1)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "there should be an integer power of two MBs per slice\n");
+ return AVERROR(EINVAL);
+ }
+ if (ctx->profile == PRORES_PROFILE_AUTO) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA ||
+ !(desc->log2_chroma_w + desc->log2_chroma_h))
+ ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ;
+ av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden "
+ "through -profile option.\n", ctx->profile == PRORES_PROFILE_4444
+ ? "4:4:4:4 profile because of the used input colorspace"
+ : "HQ profile to keep best quality");
+ }
+ if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
+ if (ctx->profile != PRORES_PROFILE_4444) {
+ // force alpha and warn
+ av_log(avctx, AV_LOG_WARNING, "Profile selected will not "
+ "encode alpha. Override with -profile if needed.\n");
+ ctx->alpha_bits = 0;
+ }
+ if (ctx->alpha_bits & 7) {
+ av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
+ return AVERROR(EINVAL);
+ }
+ avctx->bits_per_coded_sample = 32;
+ } else {
+ ctx->alpha_bits = 0;
+ }
+
+ ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10
+ ? CFACTOR_Y422
+ : CFACTOR_Y444;
+ ctx->profile_info = prores_profile_info + ctx->profile;
+ ctx->num_planes = 3 + !!ctx->alpha_bits;
+
+ ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
+
+ if (interlaced)
+ ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
+ else
+ ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
+
+ ctx->slices_width = ctx->mb_width / mps;
+ ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
+ ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
+ ctx->pictures_per_frame = 1 + interlaced;
+
+ if (ctx->quant_sel == -1)
+ ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
+ else
+ ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
+
+ if (strlen(ctx->vendor) != 4) {
+ av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
+ if (!ctx->force_quant) {
+ if (!ctx->bits_per_mb) {
+ for (i = 0; i < NUM_MB_LIMITS - 1; i++)
+ if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
+ ctx->pictures_per_frame)
+ break;
+ ctx->bits_per_mb = ctx->profile_info->br_tab[i];
+ } else if (ctx->bits_per_mb < 128) {
+ av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at least 128\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ min_quant = ctx->profile_info->min_quant;
+ max_quant = ctx->profile_info->max_quant;
+ for (i = min_quant; i < MAX_STORED_Q; i++) {
+ for (j = 0; j < 64; j++)
+ ctx->quants[i][j] = ctx->quant_mat[j] * i;
+ }
+
+ ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
+ if (!ctx->slice_q) {
+ encode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+
+ ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata));
+ if (!ctx->tdata) {
+ encode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+
+ for (j = 0; j < avctx->thread_count; j++) {
+ ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1)
+ * TRELLIS_WIDTH
+ * sizeof(*ctx->tdata->nodes));
+ if (!ctx->tdata[j].nodes) {
+ encode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
+ for (i = min_quant; i < max_quant + 2; i++) {
+ ctx->tdata[j].nodes[i].prev_node = -1;
+ ctx->tdata[j].nodes[i].bits = 0;
+ ctx->tdata[j].nodes[i].score = 0;
+ }
+ }
+ } else {
+ int ls = 0;
+
+ if (ctx->force_quant > 64) {
+ av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (j = 0; j < 64; j++) {
+ ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
+ ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
+ }
+
+ ctx->bits_per_mb = ls * 8;
+ if (ctx->chroma_factor == CFACTOR_Y444)
+ ctx->bits_per_mb += ls * 4;
+ }
+
+ ctx->frame_size_upper_bound = (ctx->pictures_per_frame *
+ ctx->slices_per_picture + 1) *
+ (2 + 2 * ctx->num_planes +
+ (mps * ctx->bits_per_mb) / 8)
+ + 200;
+
+ if (ctx->alpha_bits) {
+ // The alpha plane is run-coded and might exceed the bit budget.
+ ctx->frame_size_upper_bound += (ctx->pictures_per_frame *
+ ctx->slices_per_picture + 1) *
+ /* num pixels per slice */ (ctx->mbs_per_slice * 256 *
+ /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3);
+ }
+
+ avctx->codec_tag = ctx->profile_info->tag;
+
+ av_log(avctx, AV_LOG_DEBUG,
+ "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
+ ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
+ interlaced ? "yes" : "no", ctx->bits_per_mb);
+ av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
+ ctx->frame_size_upper_bound);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(ProresContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+ { "mbs_per_slice", "macroblocks per slice", OFFSET(mbs_per_slice),
+ AV_OPT_TYPE_INT, { .i64 = 8 }, 1, MAX_MBS_PER_SLICE, VE },
+ { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT,
+ { .i64 = PRORES_PROFILE_AUTO },
+ PRORES_PROFILE_AUTO, PRORES_PROFILE_4444, VE, "profile" },
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_AUTO },
+ 0, 0, VE, "profile" },
+ { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_PROXY },
+ 0, 0, VE, "profile" },
+ { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_LT },
+ 0, 0, VE, "profile" },
+ { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_STANDARD },
+ 0, 0, VE, "profile" },
+ { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_HQ },
+ 0, 0, VE, "profile" },
+ { "4444", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444 },
+ 0, 0, VE, "profile" },
+ { "vendor", "vendor ID", OFFSET(vendor),
+ AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
+ { "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
+ { "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
+ { .i64 = -1 }, -1, QUANT_MAT_DEFAULT, VE, "quant_mat" },
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 },
+ 0, 0, VE, "quant_mat" },
+ { "proxy", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_PROXY },
+ 0, 0, VE, "quant_mat" },
+ { "lt", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_LT },
+ 0, 0, VE, "quant_mat" },
+ { "standard", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_STANDARD },
+ 0, 0, VE, "quant_mat" },
+ { "hq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_HQ },
+ 0, 0, VE, "quant_mat" },
+ { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = QUANT_MAT_DEFAULT },
+ 0, 0, VE, "quant_mat" },
+ { "alpha_bits", "bits for alpha plane", OFFSET(alpha_bits), AV_OPT_TYPE_INT,
+ { .i64 = 16 }, 0, 16, VE },
+ { NULL }
+};
+
+static const AVClass proresenc_class = {
+ .class_name = "ProRes encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_prores_ks_encoder = {
+ .name = "prores_ks",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_PRORES,
+ .priv_data_size = sizeof(ProresContext),
+ .init = encode_init,
+ .close = encode_close,
+ .encode2 = encode_frame,
+ .capabilities = CODEC_CAP_SLICE_THREADS,
+ .pix_fmts = (const enum AVPixelFormat[]) {
+ AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
+ },
+ .priv_class = &proresenc_class,
+};
diff --git a/libavcodec/psymodel.c b/libavcodec/psymodel.c
index a2af61175e..059cbefe37 100644
--- a/libavcodec/psymodel.c
+++ b/libavcodec/psymodel.c
@@ -2,20 +2,20 @@
* audio encoder psychoacoustic model
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,10 +35,10 @@ av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens,
int i, j, k = 0;
ctx->avctx = avctx;
- ctx->ch = av_mallocz(sizeof(ctx->ch[0]) * avctx->channels * 2);
- ctx->group = av_mallocz(sizeof(ctx->group[0]) * num_groups);
- ctx->bands = av_malloc (sizeof(ctx->bands[0]) * num_lens);
- ctx->num_bands = av_malloc (sizeof(ctx->num_bands[0]) * num_lens);
+ ctx->ch = av_mallocz_array(sizeof(ctx->ch[0]), avctx->channels * 2);
+ ctx->group = av_mallocz_array(sizeof(ctx->group[0]), num_groups);
+ ctx->bands = av_malloc_array (sizeof(ctx->bands[0]), num_lens);
+ ctx->num_bands = av_malloc_array (sizeof(ctx->num_bands[0]), num_lens);
memcpy(ctx->bands, bands, sizeof(ctx->bands[0]) * num_lens);
memcpy(ctx->num_bands, num_bands, sizeof(ctx->num_bands[0]) * num_lens);
@@ -75,7 +75,7 @@ FFPsyChannelGroup *ff_psy_find_group(FFPsyContext *ctx, int channel)
av_cold void ff_psy_end(FFPsyContext *ctx)
{
- if (ctx->model->end)
+ if (ctx->model && ctx->model->end)
ctx->model->end(ctx);
av_freep(&ctx->bands);
av_freep(&ctx->num_bands);
@@ -88,6 +88,7 @@ typedef struct FFPsyPreprocessContext{
float stereo_att;
struct FFIIRFilterCoeffs *fcoeffs;
struct FFIIRFilterState **fstate;
+ struct FFIIRFilterContext fiir;
}FFPsyPreprocessContext;
#define FILT_ORDER 4
@@ -103,15 +104,21 @@ av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *av
if (avctx->cutoff > 0)
cutoff_coeff = 2.0 * avctx->cutoff / avctx->sample_rate;
- if (cutoff_coeff)
+ if (!cutoff_coeff && avctx->codec_id == AV_CODEC_ID_AAC)
+ cutoff_coeff = 2.0 * AAC_CUTOFF(avctx) / avctx->sample_rate;
+
+ if (cutoff_coeff && cutoff_coeff < 0.98)
ctx->fcoeffs = ff_iir_filter_init_coeffs(avctx, FF_FILTER_TYPE_BUTTERWORTH,
FF_FILTER_MODE_LOWPASS, FILT_ORDER,
cutoff_coeff, 0.0, 0.0);
if (ctx->fcoeffs) {
- ctx->fstate = av_mallocz(sizeof(ctx->fstate[0]) * avctx->channels);
+ ctx->fstate = av_mallocz_array(sizeof(ctx->fstate[0]), avctx->channels);
for (i = 0; i < avctx->channels; i++)
ctx->fstate[i] = ff_iir_filter_init_state(FILT_ORDER);
}
+
+ ff_iir_filter_init(&ctx->fiir);
+
return ctx;
}
@@ -119,21 +126,22 @@ void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int ch
{
int ch;
int frame_size = ctx->avctx->frame_size;
+ FFIIRFilterContext *iir = &ctx->fiir;
if (ctx->fstate) {
for (ch = 0; ch < channels; ch++)
- ff_iir_filter_flt(ctx->fcoeffs, ctx->fstate[ch], frame_size,
- &audio[ch][frame_size], 1, &audio[ch][frame_size], 1);
+ iir->filter_flt(ctx->fcoeffs, ctx->fstate[ch], frame_size,
+ &audio[ch][frame_size], 1, &audio[ch][frame_size], 1);
}
}
av_cold void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx)
{
int i;
- ff_iir_filter_free_coeffs(ctx->fcoeffs);
+ ff_iir_filter_free_coeffsp(&ctx->fcoeffs);
if (ctx->fstate)
for (i = 0; i < ctx->avctx->channels; i++)
- ff_iir_filter_free_state(ctx->fstate[i]);
+ ff_iir_filter_free_statep(&ctx->fstate[i]);
av_freep(&ctx->fstate);
av_free(ctx);
}
diff --git a/libavcodec/psymodel.h b/libavcodec/psymodel.h
index 1cc30668e4..75261ba4be 100644
--- a/libavcodec/psymodel.h
+++ b/libavcodec/psymodel.h
@@ -2,20 +2,20 @@
* audio encoder psychoacoustic model
* Copyright (C) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,8 @@
/** maximum number of channels */
#define PSY_MAX_CHANS 20
+#define AAC_CUTOFF(s) ((s)->bit_rate ? FFMIN3(4000 + (s)->bit_rate/8, 12000 + (s)->bit_rate/32, (s)->sample_rate / 2) : ((s)->sample_rate / 2))
+
/**
* single band psychoacoustic information
*/
diff --git a/libavcodec/pthread.c b/libavcodec/pthread.c
index 682fd051cc..407ca2e271 100644
--- a/libavcodec/pthread.c
+++ b/libavcodec/pthread.c
@@ -6,20 +6,20 @@
* to Michael Niedermayer <michaelni@gmx.at> for writing initial
* implementation.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index effc9a5ac3..e80990558b 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,8 @@
#include <pthread.h>
#elif HAVE_W32THREADS
#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#endif
#include "avcodec.h"
@@ -46,6 +48,7 @@
#include "libavutil/internal.h"
#include "libavutil/log.h"
#include "libavutil/mem.h"
+#include "libavutil/opt.h"
/**
* Context used by codec threads and stored in their AVCodecInternal thread_ctx.
@@ -77,6 +80,10 @@ typedef struct PerThreadContext {
* Set when the codec calls get_buffer().
* State is returned to STATE_SETTING_UP afterwards.
*/
+ STATE_GET_FORMAT, /**<
+ * Set when the codec calls get_format().
+ * State is returned to STATE_SETTING_UP afterwards.
+ */
STATE_SETUP_FINISHED ///< Set after the codec has called ff_thread_finish_setup().
} state;
@@ -90,6 +97,9 @@ typedef struct PerThreadContext {
AVFrame *requested_frame; ///< AVFrame the codec passed to get_buffer()
int requested_flags; ///< flags passed to get_buffer() for requested_frame
+
+ const enum AVPixelFormat *available_formats; ///< Format array for get_format()
+ enum AVPixelFormat result_format; ///< get_format() result
} PerThreadContext;
/**
@@ -112,6 +122,14 @@ typedef struct FrameThreadContext {
int die; ///< Set when threads should exit.
} FrameThreadContext;
+#if FF_API_GET_BUFFER
+#define THREAD_SAFE_CALLBACKS(avctx) \
+((avctx)->thread_safe_callbacks || (!(avctx)->get_buffer && (avctx)->get_buffer2 == avcodec_default_get_buffer2))
+#else
+#define THREAD_SAFE_CALLBACKS(avctx) \
+((avctx)->thread_safe_callbacks || (avctx)->get_buffer2 == avcodec_default_get_buffer2)
+#endif
+
/**
* Codec worker thread.
*
@@ -126,20 +144,16 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
AVCodecContext *avctx = p->avctx;
const AVCodec *codec = avctx->codec;
+ pthread_mutex_lock(&p->mutex);
while (1) {
- if (p->state == STATE_INPUT_READY && !fctx->die) {
- pthread_mutex_lock(&p->mutex);
while (p->state == STATE_INPUT_READY && !fctx->die)
pthread_cond_wait(&p->input_cond, &p->mutex);
- pthread_mutex_unlock(&p->mutex);
- }
if (fctx->die) break;
- if (!codec->update_thread_context && avctx->thread_safe_callbacks)
+ if (!codec->update_thread_context && THREAD_SAFE_CALLBACKS(avctx))
ff_thread_finish_setup(avctx);
- pthread_mutex_lock(&p->mutex);
av_frame_unref(p->frame);
p->got_frame = 0;
p->result = codec->decode(avctx, p->frame, &p->got_frame, &p->avpkt);
@@ -153,14 +167,21 @@ static attribute_align_arg void *frame_worker_thread(void *arg)
if (p->state == STATE_SETTING_UP) ff_thread_finish_setup(avctx);
+ pthread_mutex_lock(&p->progress_mutex);
+#if 0 //BUFREF-FIXME
+ for (i = 0; i < MAX_BUFFERS; i++)
+ if (p->progress_used[i] && (p->got_frame || p->result<0 || avctx->codec_id != AV_CODEC_ID_H264)) {
+ p->progress[i][0] = INT_MAX;
+ p->progress[i][1] = INT_MAX;
+ }
+#endif
p->state = STATE_INPUT_READY;
- pthread_mutex_lock(&p->progress_mutex);
+ pthread_cond_broadcast(&p->progress_cond);
pthread_cond_signal(&p->output_cond);
pthread_mutex_unlock(&p->progress_mutex);
-
- pthread_mutex_unlock(&p->mutex);
}
+ pthread_mutex_unlock(&p->mutex);
return NULL;
}
@@ -211,10 +232,16 @@ FF_ENABLE_DEPRECATION_WARNINGS
dst->hwaccel = src->hwaccel;
dst->hwaccel_context = src->hwaccel_context;
+
+ dst->channels = src->channels;
+ dst->sample_rate = src->sample_rate;
+ dst->sample_fmt = src->sample_fmt;
+ dst->channel_layout = src->channel_layout;
dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data;
}
if (for_user) {
+ dst->delay = src->thread_count - 1;
dst->coded_frame = src->coded_frame;
} else {
if (dst->codec->update_thread_context)
@@ -247,6 +274,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
dst->opaque = src->opaque;
dst->debug = src->debug;
+ dst->debug_mv = src->debug_mv;
dst->slice_flags = src->slice_flags;
dst->flags2 = src->flags2;
@@ -255,16 +283,14 @@ FF_ENABLE_DEPRECATION_WARNINGS
dst->frame_number = src->frame_number;
dst->reordered_opaque = src->reordered_opaque;
+ dst->thread_safe_callbacks = src->thread_safe_callbacks;
if (src->slice_count && src->slice_offset) {
if (dst->slice_count < src->slice_count) {
- int *tmp = av_realloc(dst->slice_offset, src->slice_count *
- sizeof(*dst->slice_offset));
- if (!tmp) {
- av_free(dst->slice_offset);
- return AVERROR(ENOMEM);
- }
- dst->slice_offset = tmp;
+ int err = av_reallocp_array(&dst->slice_offset, src->slice_count,
+ sizeof(*dst->slice_offset));
+ if (err < 0)
+ return err;
}
memcpy(dst->slice_offset, src->slice_offset,
src->slice_count * sizeof(*dst->slice_offset));
@@ -285,7 +311,8 @@ static void release_delayed_buffers(PerThreadContext *p)
pthread_mutex_lock(&fctx->buffer_mutex);
// fix extended data in case the caller screwed it up
- av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO);
+ av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ p->avctx->codec_type == AVMEDIA_TYPE_AUDIO);
f = &p->released_buffers[--p->num_released_buffers];
f->extended_data = f->data;
av_frame_unref(f);
@@ -337,18 +364,30 @@ static int submit_packet(PerThreadContext *p, AVPacket *avpkt)
FF_DISABLE_DEPRECATION_WARNINGS
if (!p->avctx->thread_safe_callbacks && (
+ p->avctx->get_format != avcodec_default_get_format ||
#if FF_API_GET_BUFFER
p->avctx->get_buffer ||
#endif
p->avctx->get_buffer2 != avcodec_default_get_buffer2)) {
FF_ENABLE_DEPRECATION_WARNINGS
while (p->state != STATE_SETUP_FINISHED && p->state != STATE_INPUT_READY) {
+ int call_done = 1;
pthread_mutex_lock(&p->progress_mutex);
while (p->state == STATE_SETTING_UP)
pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
- if (p->state == STATE_GET_BUFFER) {
+ switch (p->state) {
+ case STATE_GET_BUFFER:
p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags);
+ break;
+ case STATE_GET_FORMAT:
+ p->result_format = ff_get_format(p->avctx, p->available_formats);
+ break;
+ default:
+ call_done = 0;
+ break;
+ }
+ if (call_done) {
p->state = STATE_SETTING_UP;
pthread_cond_signal(&p->progress_cond);
}
@@ -385,9 +424,10 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
* If we're still receiving the initial packets, don't return a frame.
*/
- if (fctx->delaying) {
- if (fctx->next_decoding >= (avctx->thread_count-1)) fctx->delaying = 0;
+ 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)
return avpkt->size;
@@ -438,7 +478,7 @@ int ff_thread_decode_frame(AVCodecContext *avctx,
void ff_thread_report_progress(ThreadFrame *f, int n, int field)
{
PerThreadContext *p;
- int *progress = f->progress ? (int*)f->progress->data : NULL;
+ volatile int *progress = f->progress ? (int*)f->progress->data : NULL;
if (!progress || progress[field] >= n) return;
@@ -456,7 +496,7 @@ void ff_thread_report_progress(ThreadFrame *f, int n, int field)
void ff_thread_await_progress(ThreadFrame *f, int n, int field)
{
PerThreadContext *p;
- int *progress = f->progress ? (int*)f->progress->data : NULL;
+ volatile int *progress = f->progress ? (int*)f->progress->data : NULL;
if (!progress || progress[field] >= n) return;
@@ -476,6 +516,10 @@ void ff_thread_finish_setup(AVCodecContext *avctx) {
if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return;
+ if(p->state == STATE_SETUP_FINISHED){
+ av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n");
+ }
+
pthread_mutex_lock(&p->progress_mutex);
p->state = STATE_SETUP_FINISHED;
pthread_cond_broadcast(&p->progress_cond);
@@ -496,6 +540,7 @@ 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;
}
}
@@ -508,7 +553,11 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
park_frame_worker_threads(fctx, thread_count);
if (fctx->prev_thread && fctx->prev_thread != fctx->threads)
- update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0);
+ if (update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Final thread update failed\n");
+ fctx->prev_thread->avctx->internal->is_copy = fctx->threads->avctx->internal->is_copy;
+ fctx->threads->avctx->internal->is_copy = 1;
+ }
fctx->die = 1;
@@ -521,12 +570,11 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
if (p->thread_init)
pthread_join(p->thread, NULL);
+ p->thread_init=0;
if (codec->close)
codec->close(p->avctx);
- avctx->codec = NULL;
-
release_delayed_buffers(p);
av_frame_free(&p->frame);
}
@@ -554,6 +602,10 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
av_freep(&fctx->threads);
pthread_mutex_destroy(&fctx->buffer_mutex);
av_freep(&avctx->internal->thread_ctx);
+
+ if (avctx->priv_data && avctx->codec && avctx->codec->priv_class)
+ av_opt_free(avctx->priv_data);
+ avctx->codec = NULL;
}
int ff_frame_thread_init(AVCodecContext *avctx)
@@ -570,7 +622,8 @@ int ff_frame_thread_init(AVCodecContext *avctx)
if (!thread_count) {
int nb_cpus = av_cpu_count();
- av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus);
+ if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv)
+ nb_cpus = 1;
// use number of cores + 1 as thread count if there is more than one
if (nb_cpus > 1)
thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS);
@@ -585,7 +638,7 @@ int ff_frame_thread_init(AVCodecContext *avctx)
avctx->internal->thread_ctx = fctx = av_mallocz(sizeof(FrameThreadContext));
- fctx->threads = av_mallocz(sizeof(PerThreadContext) * thread_count);
+ fctx->threads = av_mallocz_array(thread_count, sizeof(PerThreadContext));
pthread_mutex_init(&fctx->buffer_mutex, NULL);
fctx->delaying = 1;
@@ -647,8 +700,10 @@ int ff_frame_thread_init(AVCodecContext *avctx)
if (err) goto error;
- if (!pthread_create(&p->thread, NULL, frame_worker_thread, p))
- p->thread_init = 1;
+ err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p));
+ p->thread_init= !err;
+ if(!p->thread_init)
+ goto error;
}
return 0;
@@ -688,18 +743,30 @@ void ff_thread_flush(AVCodecContext *avctx)
}
}
-int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
+int ff_thread_can_start_frame(AVCodecContext *avctx)
+{
+ PerThreadContext *p = avctx->internal->thread_ctx;
+ if ((avctx->active_thread_type&FF_THREAD_FRAME) && p->state != STATE_SETTING_UP &&
+ (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) {
+ return 0;
+ }
+ return 1;
+}
+
+static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int flags)
{
PerThreadContext *p = avctx->internal->thread_ctx;
int err;
f->owner = avctx;
+ ff_init_buffer_info(avctx, f->f);
+
if (!(avctx->active_thread_type & FF_THREAD_FRAME))
return ff_get_buffer(avctx, f->f, flags);
if (p->state != STATE_SETTING_UP &&
- (avctx->codec->update_thread_context || !avctx->thread_safe_callbacks)) {
+ (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() cannot be called after ff_thread_finish_setup()\n");
return -1;
}
@@ -725,11 +792,11 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
err = ff_get_buffer(avctx, f->f, flags);
} else {
+ pthread_mutex_lock(&p->progress_mutex);
p->requested_frame = f->f;
p->requested_flags = flags;
p->state = STATE_GET_BUFFER;
- pthread_mutex_lock(&p->progress_mutex);
- pthread_cond_signal(&p->progress_cond);
+ pthread_cond_broadcast(&p->progress_cond);
while (p->state != STATE_SETTING_UP)
pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
@@ -739,7 +806,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
pthread_mutex_unlock(&p->progress_mutex);
}
- if (!avctx->thread_safe_callbacks && !avctx->codec->update_thread_context)
+ if (!THREAD_SAFE_CALLBACKS(avctx) && !avctx->codec->update_thread_context)
ff_thread_finish_setup(avctx);
if (err)
@@ -750,6 +817,40 @@ FF_ENABLE_DEPRECATION_WARNINGS
return err;
}
+enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
+{
+ enum AVPixelFormat res;
+ PerThreadContext *p = avctx->internal->thread_ctx;
+ if (!(avctx->active_thread_type & FF_THREAD_FRAME) || avctx->thread_safe_callbacks ||
+ avctx->get_format == avcodec_default_get_format)
+ return ff_get_format(avctx, fmt);
+ if (p->state != STATE_SETTING_UP) {
+ av_log(avctx, AV_LOG_ERROR, "get_format() cannot be called after ff_thread_finish_setup()\n");
+ return -1;
+ }
+ pthread_mutex_lock(&p->progress_mutex);
+ p->available_formats = fmt;
+ p->state = STATE_GET_FORMAT;
+ pthread_cond_broadcast(&p->progress_cond);
+
+ while (p->state != STATE_SETTING_UP)
+ pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
+
+ res = p->result_format;
+
+ pthread_mutex_unlock(&p->progress_mutex);
+
+ return res;
+}
+
+int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
+{
+ int ret = thread_get_buffer_internal(avctx, f, flags);
+ if (ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "thread_get_buffer() failed\n");
+ return ret;
+}
+
void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f)
{
PerThreadContext *p = avctx->internal->thread_ctx;
diff --git a/libavcodec/pthread_internal.h b/libavcodec/pthread_internal.h
index 5dfd0b2a26..6a2f3781db 100644
--- a/libavcodec/pthread_internal.h
+++ b/libavcodec/pthread_internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c
index d7c73f0884..c8e69f0a9a 100644
--- a/libavcodec/pthread_slice.c
+++ b/libavcodec/pthread_slice.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,8 @@
#include <pthread.h>
#elif HAVE_W32THREADS
#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#endif
#include "avcodec.h"
@@ -58,6 +60,12 @@ typedef struct SliceThreadContext {
unsigned current_execute;
int current_job;
int done;
+
+ int *entries;
+ int entries_count;
+ int thread_count;
+ pthread_cond_t *progress_cond;
+ pthread_mutex_t *progress_mutex;
} SliceThreadContext;
static void* attribute_align_arg worker(void *v)
@@ -104,15 +112,27 @@ void ff_slice_thread_free(AVCodecContext *avctx)
pthread_mutex_lock(&c->current_job_lock);
c->done = 1;
pthread_cond_broadcast(&c->current_job_cond);
+ for (i = 0; i < c->thread_count; i++)
+ pthread_cond_broadcast(&c->progress_cond[i]);
pthread_mutex_unlock(&c->current_job_lock);
for (i=0; i<avctx->thread_count; i++)
pthread_join(c->workers[i], NULL);
+ for (i = 0; i < c->thread_count; i++) {
+ pthread_mutex_destroy(&c->progress_mutex[i]);
+ pthread_cond_destroy(&c->progress_cond[i]);
+ }
+
pthread_mutex_destroy(&c->current_job_lock);
pthread_cond_destroy(&c->current_job_cond);
pthread_cond_destroy(&c->last_job_cond);
- av_free(c->workers);
+
+ av_freep(&c->entries);
+ av_freep(&c->progress_mutex);
+ av_freep(&c->progress_cond);
+
+ av_freep(&c->workers);
av_freep(&avctx->internal->thread_ctx);
}
@@ -175,7 +195,8 @@ int ff_slice_thread_init(AVCodecContext *avctx)
if (!thread_count) {
int nb_cpus = av_cpu_count();
- av_log(avctx, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus);
+ if (avctx->height)
+ nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16);
// use number of cores + 1 as thread count if there is more than one
if (nb_cpus > 1)
thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS);
@@ -192,7 +213,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
if (!c)
return -1;
- c->workers = av_mallocz(sizeof(pthread_t)*thread_count);
+ c->workers = av_mallocz_array(thread_count, sizeof(pthread_t));
if (!c->workers) {
av_free(c);
return -1;
@@ -222,3 +243,65 @@ int ff_slice_thread_init(AVCodecContext *avctx)
avctx->execute2 = thread_execute2;
return 0;
}
+
+void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n)
+{
+ SliceThreadContext *p = avctx->internal->thread_ctx;
+ int *entries = p->entries;
+
+ pthread_mutex_lock(&p->progress_mutex[thread]);
+ entries[field] +=n;
+ pthread_cond_signal(&p->progress_cond[thread]);
+ pthread_mutex_unlock(&p->progress_mutex[thread]);
+}
+
+void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift)
+{
+ SliceThreadContext *p = avctx->internal->thread_ctx;
+ int *entries = p->entries;
+
+ if (!entries || !field) return;
+
+ thread = thread ? thread - 1 : p->thread_count - 1;
+
+ pthread_mutex_lock(&p->progress_mutex[thread]);
+ while ((entries[field - 1] - entries[field]) < shift){
+ pthread_cond_wait(&p->progress_cond[thread], &p->progress_mutex[thread]);
+ }
+ pthread_mutex_unlock(&p->progress_mutex[thread]);
+}
+
+int ff_alloc_entries(AVCodecContext *avctx, int count)
+{
+ int i;
+
+ if (avctx->active_thread_type & FF_THREAD_SLICE) {
+ SliceThreadContext *p = avctx->internal->thread_ctx;
+ p->thread_count = avctx->thread_count;
+ p->entries = av_mallocz_array(count, sizeof(int));
+
+ p->progress_mutex = av_malloc_array(p->thread_count, sizeof(pthread_mutex_t));
+ p->progress_cond = av_malloc_array(p->thread_count, sizeof(pthread_cond_t));
+
+ if (!p->entries || !p->progress_mutex || !p->progress_cond) {
+ av_freep(&p->entries);
+ av_freep(&p->progress_mutex);
+ av_freep(&p->progress_cond);
+ return AVERROR(ENOMEM);
+ }
+ p->entries_count = count;
+
+ for (i = 0; i < p->thread_count; i++) {
+ pthread_mutex_init(&p->progress_mutex[i], NULL);
+ pthread_cond_init(&p->progress_cond[i], NULL);
+ }
+ }
+
+ return 0;
+}
+
+void ff_reset_entries(AVCodecContext *avctx)
+{
+ SliceThreadContext *p = avctx->internal->thread_ctx;
+ memset(p->entries, 0, p->entries_count * sizeof(int));
+}
diff --git a/libavcodec/ptx.c b/libavcodec/ptx.c
index 76fff26bb6..8c3abd7ddb 100644
--- a/libavcodec/ptx.c
+++ b/libavcodec/ptx.c
@@ -2,20 +2,20 @@
* V.Flash PTX (.ptx) image decoder
* Copyright (c) 2007 Ivo van Poorten
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,7 +46,7 @@ static int ptx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_PATCHWELCOME;
}
- avctx->pix_fmt = AV_PIX_FMT_RGB555;
+ avctx->pix_fmt = AV_PIX_FMT_BGR555LE;
if (buf_end - buf < offset)
return AVERROR_INVALIDDATA;
@@ -58,10 +58,8 @@ static int ptx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
@@ -69,13 +67,7 @@ static int ptx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
stride = p->linesize[0];
for (y = 0; y < h && buf_end - buf >= w * bytes_per_pixel; y++) {
-#if HAVE_BIGENDIAN
- unsigned int x;
- for (x=0; x<w*bytes_per_pixel; x+=bytes_per_pixel)
- AV_WN16(ptr+x, AV_RL16(buf+x));
-#else
memcpy(ptr, buf, w*bytes_per_pixel);
-#endif
ptr += stride;
buf += w*bytes_per_pixel;
}
diff --git a/libavcodec/put_bits.h b/libavcodec/put_bits.h
index 17666fac48..5b1bc8b8b7 100644
--- a/libavcodec/put_bits.h
+++ b/libavcodec/put_bits.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,9 +28,9 @@
#include <stdint.h>
#include <stddef.h>
-#include <assert.h>
#include "libavutil/intreadwrite.h"
+#include "libavutil/avassert.h"
typedef struct PutBitContext {
uint32_t bit_buf;
@@ -62,6 +62,24 @@ static inline void init_put_bits(PutBitContext *s, uint8_t *buffer,
}
/**
+ * Rebase the bit writer onto a reallocated buffer.
+ *
+ * @param buffer the buffer where to put bits
+ * @param buffer_size the size in bytes of buffer,
+ * must be larger than the previous size
+ */
+static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer,
+ int buffer_size)
+{
+ av_assert0(8*buffer_size > s->size_in_bits);
+
+ s->buf_end = buffer + buffer_size;
+ s->buf_ptr = buffer + (s->buf_ptr - s->buf);
+ s->buf = buffer;
+ s->size_in_bits = 8 * buffer_size;
+}
+
+/**
* @return the total number of bits written to the bitstream.
*/
static inline int put_bits_count(PutBitContext *s)
@@ -136,7 +154,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value)
unsigned int bit_buf;
int bit_left;
- assert(n <= 31 && value < (1U << n));
+ av_assert2(n <= 31 && value < (1U << n));
bit_buf = s->bit_buf;
bit_left = s->bit_left;
@@ -145,9 +163,10 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value)
#ifdef BITSTREAM_WRITER_LE
bit_buf |= value << (32 - bit_left);
if (n >= bit_left) {
+ av_assert2(s->buf_ptr+3<s->buf_end);
AV_WL32(s->buf_ptr, bit_buf);
s->buf_ptr += 4;
- bit_buf = (bit_left == 32) ? 0 : value >> bit_left;
+ bit_buf = value >> bit_left;
bit_left += 32;
}
bit_left -= n;
@@ -158,6 +177,7 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value)
} else {
bit_buf <<= bit_left;
bit_buf |= value >> (n - bit_left);
+ av_assert2(s->buf_ptr+3<s->buf_end);
AV_WB32(s->buf_ptr, bit_buf);
s->buf_ptr += 4;
bit_left += 32 - n;
@@ -171,9 +191,9 @@ static inline void put_bits(PutBitContext *s, int n, unsigned int value)
static inline void put_sbits(PutBitContext *pb, int n, int32_t value)
{
- assert(n >= 0 && n <= 31);
+ av_assert2(n >= 0 && n <= 31);
- put_bits(pb, n, value & ((1 << n) - 1));
+ put_bits(pb, n, av_mod_uintp2(value, n));
}
/**
@@ -207,8 +227,9 @@ static inline uint8_t *put_bits_ptr(PutBitContext *s)
*/
static inline void skip_put_bytes(PutBitContext *s, int n)
{
- assert((put_bits_count(s) & 7) == 0);
- assert(s->bit_left == 32);
+ av_assert2((put_bits_count(s) & 7) == 0);
+ av_assert2(s->bit_left == 32);
+ av_assert0(n <= s->buf_end - s->buf_ptr);
s->buf_ptr += n;
}
@@ -231,7 +252,9 @@ static inline void skip_put_bits(PutBitContext *s, int n)
*/
static inline void set_put_bits_buffer_size(PutBitContext *s, int size)
{
+ av_assert0(size <= INT_MAX/8 - 32);
s->buf_end = s->buf + size;
+ s->size_in_bits = 8*size;
}
#endif /* AVCODEC_PUT_BITS_H */
diff --git a/libavcodec/qcelpdata.h b/libavcodec/qcelpdata.h
index 319833e904..931c990b09 100644
--- a/libavcodec/qcelpdata.h
+++ b/libavcodec/qcelpdata.h
@@ -2,20 +2,20 @@
* QCELP decoder
* Copyright (c) 2007 Reynaldo H. Verdejo Pinochet
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,7 +26,7 @@
* @file
* Data tables for the QCELP decoder
* @author Reynaldo H. Verdejo Pinochet
- * @remark Libav merging spearheaded by Kenan Gillet
+ * @remark FFmpeg merging spearheaded by Kenan Gillet
* @remark Development mentored by Benjamin Larson
*/
@@ -66,7 +66,7 @@ typedef struct QCELPFrame {
} QCELPFrame;
/**
- * pre-calculated table for hammsinc function
+ * Pre-calculated table for hammsinc function.
* Only half of the table is needed because of symmetry.
*
* TIA/EIA/IS-733 2.4.5.2-2/3
@@ -82,7 +82,7 @@ typedef struct QCELPBitmap {
#define QCELP_OF(variable, bit, len) {offsetof(QCELPFrame, variable), bit, len}
/**
- * bitmap unpacking tables for RATE_FULL
+ * Bitmap unpacking tables for RATE_FULL
*
* TIA/EIA/IS-733 Table 2.4.7.1-1
*/
@@ -169,7 +169,7 @@ static const QCELPBitmap qcelp_rate_full_bitmap[] = {
};
/**
- * bitmap unpacking tables for RATE_HALF
+ * Bitmap unpacking tables for RATE_HALF
*
* TIA/EIA/IS-733 Table 2.4.7.2-1
*/
@@ -211,7 +211,7 @@ static const QCELPBitmap qcelp_rate_half_bitmap[] = {
};
/**
- * bitmap unpacking tables for RATE_QUARTER
+ * Bitmap unpacking tables for RATE_QUARTER
*
* TIA/EIA/IS-733 Table 2.4.7.3-1
*/
@@ -232,7 +232,7 @@ static const QCELPBitmap qcelp_rate_quarter_bitmap[] = {
};
/**
- * bitmap unpacking tables for RATE_OCTAVE
+ * Bitmap unpacking tables for RATE_OCTAVE
*
* trick: CBSEED is written into QCELPContext.cbsign[15],
* which is not used for RATE_OCTAVE.
@@ -257,12 +257,12 @@ static const QCELPBitmap qcelp_rate_octave_bitmap[] = {
QCELP_OF(lspv [8], 0, 1), // 8
QCELP_OF(cbsign[15], 0, 1), // 7
QCELP_OF(lspv [9], 0, 1), // 6
- QCELP_OF(cbgain [0], 0, 2), // 7
+ QCELP_OF(cbgain [0], 0, 2), // 5
QCELP_OF(reserved, 0, 4) // 3
};
/**
- * position of the bitmapping data for each packet type in
+ * Bitmapping data position for each packet type in
* the QCELPContext
*/
static const QCELPBitmap * const qcelp_unpacking_bitmaps_per_rate[5] = {
@@ -420,12 +420,12 @@ static const qcelp_vector * const qcelp_lspvq[5] = {
};
/**
- * the final gain scalefactor before clipping into a usable output float
+ * The final gain scalefactor before clipping into a usable output float
*/
#define QCELP_SCALE 8192.
/**
- * table for computing Ga (decoded linear codebook gain magnitude)
+ * Table for computing Ga (decoded linear codebook gain magnitude)
*
* @note The table could fit in int16_t in x*8 form, but it seems
* to be slower on x86
@@ -452,7 +452,7 @@ static const float qcelp_g12ga[61] = {
1000.000/QCELP_SCALE};
/**
- * circular codebook for rate 1 frames in x*100 form
+ * Circular codebook for rate 1 frames in x*100 form
*
* TIA/EIA/IS-733 2.4.6.1-2
*/
@@ -477,7 +477,7 @@ static const int16_t qcelp_rate_full_codebook[128] = {
#define QCELP_RATE_FULL_CODEBOOK_RATIO .01
/**
- * circular codebook for rate 1/2 frames in x*2 form
+ * Circular codebook for rate 1/2 frames in x*2 form
*
* TIA/EIA/IS-733 2.4.6.1-1
*/
@@ -511,7 +511,7 @@ static const int8_t qcelp_rate_half_codebook[128] = {
#define QCELP_SQRT1887 1.373681186
/**
- * table for impulse response of BPF used to filter
+ * Table for impulse response of BPF used to filter
* the white excitation for bitrate 1/4 synthesis
*
* Only half the tables are needed because of symmetry.
@@ -526,14 +526,14 @@ static const double qcelp_rnd_fir_coefs[11] = {
/**
* This spread factor is used, for bitrate 1/8 and I_F_Q,
- * to force the LSP frequencies to be at least 80 Hz apart.
+ * to force LSP frequencies to be at least 80 Hz apart.
*
* TIA/EIA/IS-733 2.4.3.3.2
*/
#define QCELP_LSP_SPREAD_FACTOR 0.02
/**
- * predictor coefficient for the conversion of LSP codes
+ * Predictor coefficient for the conversion of LSP codes
* to LSP frequencies for 1/8 and I_F_Q
*
* TIA/EIA/IS-733 2.4.3.2.7-2
@@ -541,7 +541,7 @@ static const double qcelp_rnd_fir_coefs[11] = {
#define QCELP_LSP_OCTAVE_PREDICTOR 29.0/32
/**
- * initial coefficient to perform bandwidth expansion on LPC
+ * Initial coefficient to perform bandwidth expansion on LPC
*
* @note: 0.9883 looks like an approximation of 253/256.
*
diff --git a/libavcodec/qcelpdec.c b/libavcodec/qcelpdec.c
index d4a82ee901..22564edb7a 100644
--- a/libavcodec/qcelpdec.c
+++ b/libavcodec/qcelpdec.c
@@ -2,20 +2,20 @@
* QCELP decoder
* Copyright (c) 2007 Reynaldo H. Verdejo Pinochet
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,12 +23,13 @@
* @file
* QCELP decoder
* @author Reynaldo H. Verdejo Pinochet
- * @remark Libav merging spearheaded by Kenan Gillet
+ * @remark FFmpeg merging spearheaded by Kenan Gillet
* @remark Development mentored by Benjamin Larson
*/
#include <stddef.h>
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/float_dsp.h"
#include "avcodec.h"
@@ -40,9 +41,6 @@
#include "acelp_vectors.h"
#include "lsp.h"
-#undef NDEBUG
-#include <assert.h>
-
typedef enum {
I_F_Q = -1, /**< insufficient frame quality */
SILENCE,
@@ -135,7 +133,7 @@ static int decode_lspf(QCELPContext *q, float *lspf)
} else {
erasure_coeff = QCELP_LSP_OCTAVE_PREDICTOR;
- assert(q->bitrate == I_F_Q);
+ av_assert2(q->bitrate == I_F_Q);
if (q->erasure_count > 1)
erasure_coeff *= q->erasure_count < 4 ? 0.9 : 0.7;
@@ -239,7 +237,7 @@ static void decode_gain_and_index(QCELPContext *q, float *gain)
av_clip((q->prev_g1[0] + q->prev_g1[1]) / 2 - 5, 0, 54);
subframes_count = 8;
} else {
- assert(q->bitrate == I_F_Q);
+ av_assert2(q->bitrate == I_F_Q);
g1[0] = q->prev_g1[1];
switch (q->erasure_count) {
@@ -321,7 +319,8 @@ static void compute_svector(QCELPContext *q, const float *gain,
tmp_gain = gain[i] * QCELP_RATE_FULL_CODEBOOK_RATIO;
cindex = -q->frame.cindex[i];
for (j = 0; j < 10; j++)
- *cdn_vector++ = tmp_gain * qcelp_rate_full_codebook[cindex++ & 127];
+ *cdn_vector++ = tmp_gain *
+ qcelp_rate_full_codebook[cindex++ & 127];
}
break;
case RATE_HALF:
@@ -329,7 +328,8 @@ static void compute_svector(QCELPContext *q, const float *gain,
tmp_gain = gain[i] * QCELP_RATE_HALF_CODEBOOK_RATIO;
cindex = -q->frame.cindex[i];
for (j = 0; j < 40; j++)
- *cdn_vector++ = tmp_gain * qcelp_rate_half_codebook[cindex++ & 127];
+ *cdn_vector++ = tmp_gain *
+ qcelp_rate_half_codebook[cindex++ & 127];
}
break;
case RATE_QUARTER:
@@ -374,7 +374,8 @@ static void compute_svector(QCELPContext *q, const float *gain,
for (i = 0; i < 4; i++) {
tmp_gain = gain[i] * QCELP_RATE_FULL_CODEBOOK_RATIO;
for (j = 0; j < 40; j++)
- *cdn_vector++ = tmp_gain * qcelp_rate_full_codebook[cbseed++ & 127];
+ *cdn_vector++ = tmp_gain *
+ qcelp_rate_full_codebook[cbseed++ & 127];
}
break;
case SILENCE:
@@ -435,7 +436,8 @@ static const float *do_pitchfilter(float memory[303], const float v_in[160],
for (v_len = v_in + 40; v_in < v_len; v_in++) {
if (pfrac[i]) { // If it is a fractional lag...
for (j = 0, *v_out = 0.0; j < 4; j++)
- *v_out += qcelp_hammsinc_table[j] * (v_lag[j - 4] + v_lag[3 - j]);
+ *v_out += qcelp_hammsinc_table[j] *
+ (v_lag[j - 4] + v_lag[3 - j]);
} else
*v_out = *v_lag;
@@ -486,7 +488,7 @@ static void apply_pitch_filters(QCELPContext *q, float *cdn_vector)
else
max_pitch_gain = 0.0;
} else {
- assert(q->bitrate == SILENCE);
+ av_assert2(q->bitrate == SILENCE);
max_pitch_gain = 1.0;
}
for (i = 0; i < 4; i++)
@@ -511,7 +513,8 @@ static void apply_pitch_filters(QCELPContext *q, float *cdn_vector)
apply_gain_ctrl(cdn_vector, v_synthesis_filtered, v_pre_filtered);
} else {
- memcpy(q->pitch_synthesis_filter_mem, cdn_vector + 17, 143 * sizeof(float));
+ memcpy(q->pitch_synthesis_filter_mem,
+ cdn_vector + 17, 143 * sizeof(float));
memcpy(q->pitch_pre_filter_mem, cdn_vector + 17, 143 * sizeof(float));
memset(q->pitch_gain, 0, sizeof(q->pitch_gain));
memset(q->pitch_lag, 0, sizeof(q->pitch_lag));
@@ -630,7 +633,7 @@ static qcelp_packet_rate determine_bitrate(AVCodecContext *avctx,
(*buf)++;
} else if ((bitrate = buf_size2bitrate(buf_size + 1)) >= 0) {
av_log(avctx, AV_LOG_WARNING,
- "Bitrate byte is missing, guessing the bitrate from packet size.\n");
+ "Bitrate byte missing, guessing bitrate from packet size.\n");
} else
return I_F_Q;
@@ -695,14 +698,12 @@ static int qcelp_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = 160;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
outbuffer = (float *)frame->data[0];
if ((q->bitrate = determine_bitrate(avctx, buf_size, &buf)) == I_F_Q) {
- warn_insufficient_frame_quality(avctx, "bitrate cannot be determined.");
+ warn_insufficient_frame_quality(avctx, "Bitrate cannot be determined.");
goto erasure;
}
@@ -718,7 +719,8 @@ static int qcelp_decode_frame(AVCodecContext *avctx, void *data,
qcelp_unpacking_bitmaps_lengths[q->bitrate];
uint8_t *unpacked_data = (uint8_t *)&q->frame;
- init_get_bits(&q->gb, buf, 8 * buf_size);
+ if ((ret = init_get_bits8(&q->gb, buf, buf_size)) < 0)
+ return ret;
memset(&q->frame, 0, sizeof(QCELPFrame));
@@ -770,7 +772,8 @@ erasure:
formant_mem = q->formant_mem + 10;
for (i = 0; i < 4; i++) {
interpolate_lpc(q, quantized_lspf, lpc, i);
- ff_celp_lp_synthesis_filterf(formant_mem, lpc, outbuffer + i * 40, 40, 10);
+ ff_celp_lp_synthesis_filterf(formant_mem, lpc,
+ outbuffer + i * 40, 40, 10);
formant_mem += 40;
}
diff --git a/libavcodec/qdm2.c b/libavcodec/qdm2.c
index 7ef979b5dd..a02c5e536c 100644
--- a/libavcodec/qdm2.c
+++ b/libavcodec/qdm2.c
@@ -5,20 +5,20 @@
* Copyright (c) 2005 Alex Beregszaszi
* Copyright (c) 2005 Roberto Togni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,13 +44,8 @@
#include "mpegaudiodsp.h"
#include "mpegaudio.h"
-#include "qdm2data.h"
#include "qdm2_tablegen.h"
-#undef NDEBUG
-#include <assert.h>
-
-
#define QDM2_LIST_ADD(list, size, packet) \
do { \
if (size > 0) { \
@@ -168,7 +163,7 @@ typedef struct QDM2Context {
/// I/O data
const uint8_t *compressed_data;
int compressed_size;
- float output_buffer[QDM2_MAX_FRAME_SIZE * 2];
+ float output_buffer[QDM2_MAX_FRAME_SIZE * MPA_MAX_CHANNELS * 2];
/// Synthesis filter
MPADSPContext mpadsp;
@@ -197,173 +192,11 @@ typedef struct QDM2Context {
int noise_idx; ///< index for dithering noise table
} QDM2Context;
-
-static VLC vlc_tab_level;
-static VLC vlc_tab_diff;
-static VLC vlc_tab_run;
-static VLC fft_level_exp_alt_vlc;
-static VLC fft_level_exp_vlc;
-static VLC fft_stereo_exp_vlc;
-static VLC fft_stereo_phase_vlc;
-static VLC vlc_tab_tone_level_idx_hi1;
-static VLC vlc_tab_tone_level_idx_mid;
-static VLC vlc_tab_tone_level_idx_hi2;
-static VLC vlc_tab_type30;
-static VLC vlc_tab_type34;
-static VLC vlc_tab_fft_tone_offset[5];
-
-static const uint16_t qdm2_vlc_offs[] = {
- 0,260,566,598,894,1166,1230,1294,1678,1950,2214,2278,2310,2570,2834,3124,3448,3838,
-};
-
static const int switchtable[23] = {
0, 5, 1, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 5, 5, 5, 4
};
-static av_cold void qdm2_init_vlc(void)
-{
- static VLC_TYPE qdm2_table[3838][2];
-
- vlc_tab_level.table = &qdm2_table[qdm2_vlc_offs[0]];
- vlc_tab_level.table_allocated = qdm2_vlc_offs[1] - qdm2_vlc_offs[0];
- init_vlc(&vlc_tab_level, 8, 24,
- vlc_tab_level_huffbits, 1, 1,
- vlc_tab_level_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_diff.table = &qdm2_table[qdm2_vlc_offs[1]];
- vlc_tab_diff.table_allocated = qdm2_vlc_offs[2] - qdm2_vlc_offs[1];
- init_vlc(&vlc_tab_diff, 8, 37,
- vlc_tab_diff_huffbits, 1, 1,
- vlc_tab_diff_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_run.table = &qdm2_table[qdm2_vlc_offs[2]];
- vlc_tab_run.table_allocated = qdm2_vlc_offs[3] - qdm2_vlc_offs[2];
- init_vlc(&vlc_tab_run, 5, 6,
- vlc_tab_run_huffbits, 1, 1,
- vlc_tab_run_huffcodes, 1, 1,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- fft_level_exp_alt_vlc.table = &qdm2_table[qdm2_vlc_offs[3]];
- fft_level_exp_alt_vlc.table_allocated = qdm2_vlc_offs[4] -
- qdm2_vlc_offs[3];
- init_vlc(&fft_level_exp_alt_vlc, 8, 28,
- fft_level_exp_alt_huffbits, 1, 1,
- fft_level_exp_alt_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- fft_level_exp_vlc.table = &qdm2_table[qdm2_vlc_offs[4]];
- fft_level_exp_vlc.table_allocated = qdm2_vlc_offs[5] - qdm2_vlc_offs[4];
- init_vlc(&fft_level_exp_vlc, 8, 20,
- fft_level_exp_huffbits, 1, 1,
- fft_level_exp_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- fft_stereo_exp_vlc.table = &qdm2_table[qdm2_vlc_offs[5]];
- fft_stereo_exp_vlc.table_allocated = qdm2_vlc_offs[6] -
- qdm2_vlc_offs[5];
- init_vlc(&fft_stereo_exp_vlc, 6, 7,
- fft_stereo_exp_huffbits, 1, 1,
- fft_stereo_exp_huffcodes, 1, 1,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- fft_stereo_phase_vlc.table = &qdm2_table[qdm2_vlc_offs[6]];
- fft_stereo_phase_vlc.table_allocated = qdm2_vlc_offs[7] -
- qdm2_vlc_offs[6];
- init_vlc(&fft_stereo_phase_vlc, 6, 9,
- fft_stereo_phase_huffbits, 1, 1,
- fft_stereo_phase_huffcodes, 1, 1,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_tone_level_idx_hi1.table =
- &qdm2_table[qdm2_vlc_offs[7]];
- vlc_tab_tone_level_idx_hi1.table_allocated = qdm2_vlc_offs[8] -
- qdm2_vlc_offs[7];
- init_vlc(&vlc_tab_tone_level_idx_hi1, 8, 20,
- vlc_tab_tone_level_idx_hi1_huffbits, 1, 1,
- vlc_tab_tone_level_idx_hi1_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_tone_level_idx_mid.table =
- &qdm2_table[qdm2_vlc_offs[8]];
- vlc_tab_tone_level_idx_mid.table_allocated = qdm2_vlc_offs[9] -
- qdm2_vlc_offs[8];
- init_vlc(&vlc_tab_tone_level_idx_mid, 8, 24,
- vlc_tab_tone_level_idx_mid_huffbits, 1, 1,
- vlc_tab_tone_level_idx_mid_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_tone_level_idx_hi2.table =
- &qdm2_table[qdm2_vlc_offs[9]];
- vlc_tab_tone_level_idx_hi2.table_allocated = qdm2_vlc_offs[10] -
- qdm2_vlc_offs[9];
- init_vlc(&vlc_tab_tone_level_idx_hi2, 8, 24,
- vlc_tab_tone_level_idx_hi2_huffbits, 1, 1,
- vlc_tab_tone_level_idx_hi2_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_type30.table = &qdm2_table[qdm2_vlc_offs[10]];
- vlc_tab_type30.table_allocated = qdm2_vlc_offs[11] - qdm2_vlc_offs[10];
- init_vlc(&vlc_tab_type30, 6, 9,
- vlc_tab_type30_huffbits, 1, 1,
- vlc_tab_type30_huffcodes, 1, 1,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_type34.table = &qdm2_table[qdm2_vlc_offs[11]];
- vlc_tab_type34.table_allocated = qdm2_vlc_offs[12] - qdm2_vlc_offs[11];
- init_vlc(&vlc_tab_type34, 5, 10,
- vlc_tab_type34_huffbits, 1, 1,
- vlc_tab_type34_huffcodes, 1, 1,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_fft_tone_offset[0].table =
- &qdm2_table[qdm2_vlc_offs[12]];
- vlc_tab_fft_tone_offset[0].table_allocated = qdm2_vlc_offs[13] -
- qdm2_vlc_offs[12];
- init_vlc(&vlc_tab_fft_tone_offset[0], 8, 23,
- vlc_tab_fft_tone_offset_0_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_0_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_fft_tone_offset[1].table =
- &qdm2_table[qdm2_vlc_offs[13]];
- vlc_tab_fft_tone_offset[1].table_allocated = qdm2_vlc_offs[14] -
- qdm2_vlc_offs[13];
- init_vlc(&vlc_tab_fft_tone_offset[1], 8, 28,
- vlc_tab_fft_tone_offset_1_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_1_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_fft_tone_offset[2].table =
- &qdm2_table[qdm2_vlc_offs[14]];
- vlc_tab_fft_tone_offset[2].table_allocated = qdm2_vlc_offs[15] -
- qdm2_vlc_offs[14];
- init_vlc(&vlc_tab_fft_tone_offset[2], 8, 32,
- vlc_tab_fft_tone_offset_2_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_2_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_fft_tone_offset[3].table =
- &qdm2_table[qdm2_vlc_offs[15]];
- vlc_tab_fft_tone_offset[3].table_allocated = qdm2_vlc_offs[16] -
- qdm2_vlc_offs[15];
- init_vlc(&vlc_tab_fft_tone_offset[3], 8, 35,
- vlc_tab_fft_tone_offset_3_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_3_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-
- vlc_tab_fft_tone_offset[4].table =
- &qdm2_table[qdm2_vlc_offs[16]];
- vlc_tab_fft_tone_offset[4].table_allocated = qdm2_vlc_offs[17] -
- qdm2_vlc_offs[16];
- init_vlc(&vlc_tab_fft_tone_offset[4], 8, 38,
- vlc_tab_fft_tone_offset_4_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_4_huffcodes, 2, 2,
- INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
-}
-
-static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth)
+static int qdm2_get_vlc(GetBitContext *gb, const VLC *vlc, int flag, int depth)
{
int value;
@@ -375,7 +208,14 @@ static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth)
/* stage-3, optional */
if (flag) {
- int tmp = vlc_stage3_values[value];
+ int tmp;
+
+ if (value >= 60) {
+ av_log(NULL, AV_LOG_ERROR, "value %d in qdm2_get_vlc too large\n", value);
+ return 0;
+ }
+
+ tmp= vlc_stage3_values[value];
if ((value & ~3) > 0)
tmp += get_bits(gb, (value >> 2));
@@ -385,7 +225,7 @@ static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth)
return value;
}
-static int qdm2_get_se_vlc(VLC *vlc, GetBitContext *gb, int depth)
+static int qdm2_get_se_vlc(const VLC *vlc, GetBitContext *gb, int depth)
{
int value = qdm2_get_vlc(gb, vlc, 0, depth);
@@ -694,7 +534,8 @@ static void fill_coding_method_array(sb_int8_array tone_level_idx,
if (!superblocktype_2_3) {
/* This case is untested, no samples available */
- SAMPLES_NEEDED
+ avpriv_request_sample(NULL, "!superblocktype_2_3");
+ return;
for (ch = 0; ch < nb_channels; ch++)
for (sb = 0; sb < 30; sb++) {
for (j = 1; j < 63; j++) { // The loop only iterates to 63 so the code doesn't overflow the buffer
@@ -806,7 +647,7 @@ static void fill_coding_method_array(sb_int8_array tone_level_idx,
* @param sb_min lower subband processed (sb_min included)
* @param sb_max higher subband processed (sb_max excluded)
*/
-static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
+static int synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
int length, int sb_min, int sb_max)
{
int sb, j, k, n, ch, run, channels;
@@ -814,14 +655,15 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
int type34_first;
float type34_div = 0;
float type34_predictor;
- float samples[10], sign_bits[16];
+ float samples[10];
+ int sign_bits[16] = {0};
if (length == 0) {
// If no data use noise
for (sb=sb_min; sb < sb_max; sb++)
build_sb_samples_from_noise(q, sb);
- return;
+ return 0;
}
for (sb = sb_min; sb < sb_max; sb++) {
@@ -845,6 +687,7 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
if (fix_coding_method_array(sb, q->nb_channels,
q->coding_method)) {
+ av_log(NULL, AV_LOG_ERROR, "coding method invalid\n");
build_sb_samples_from_noise(q, sb);
continue;
}
@@ -869,6 +712,11 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
}
} else {
n = get_bits(gb, 8);
+ if (n >= 243) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid 8bit codeword\n");
+ return AVERROR_INVALIDDATA;
+ }
+
for (k = 0; k < 5; k++)
samples[2 * k] = dequant_1bit[joined_stereo][random_dequant_index[n][k]];
}
@@ -905,6 +753,11 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
}
} else {
n = get_bits (gb, 8);
+ if (n >= 243) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid 8bit codeword\n");
+ return AVERROR_INVALIDDATA;
+ }
+
for (k = 0; k < 5; k++)
samples[k] = dequant_1bit[joined_stereo][random_dequant_index[n][k]];
}
@@ -918,6 +771,11 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
case 24:
if (get_bits_left(gb) >= 7) {
n = get_bits(gb, 7);
+ if (n >= 125) {
+ av_log(NULL, AV_LOG_ERROR, "Invalid 7bit codeword\n");
+ return AVERROR_INVALIDDATA;
+ }
+
for (k = 0; k < 3; k++)
samples[k] = (random_dequant_type24[n][k] - 2.0) * 0.5;
} else {
@@ -930,10 +788,11 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
case 30:
if (get_bits_left(gb) >= 4) {
unsigned index = qdm2_get_vlc(gb, &vlc_tab_type30, 0, 1);
- if (index < FF_ARRAY_ELEMS(type30_dequant)) {
- samples[0] = type30_dequant[index];
- } else
- samples[0] = SB_DITHERING_NOISE(sb,q->noise_idx);
+ if (index >= FF_ARRAY_ELEMS(type30_dequant)) {
+ av_log(NULL, AV_LOG_ERROR, "index %d out of type30_dequant array\n", index);
+ return AVERROR_INVALIDDATA;
+ }
+ samples[0] = type30_dequant[index];
} else
samples[0] = SB_DITHERING_NOISE(sb,q->noise_idx);
@@ -949,11 +808,12 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
type34_first = 0;
} else {
unsigned index = qdm2_get_vlc(gb, &vlc_tab_type34, 0, 1);
- if (index < FF_ARRAY_ELEMS(type34_delta)) {
- samples[0] = type34_delta[index] / type34_div + type34_predictor;
- type34_predictor = samples[0];
- } else
- samples[0] = SB_DITHERING_NOISE(sb,q->noise_idx);
+ if (index >= FF_ARRAY_ELEMS(type34_delta)) {
+ av_log(NULL, AV_LOG_ERROR, "index %d out of type34_delta array\n", index);
+ return AVERROR_INVALIDDATA;
+ }
+ samples[0] = type34_delta[index] / type34_div + type34_predictor;
+ type34_predictor = samples[0];
}
} else {
samples[0] = SB_DITHERING_NOISE(sb,q->noise_idx);
@@ -990,6 +850,7 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
} // j loop
} // channel loop
} // subband loop
+ return 0;
}
/**
@@ -1002,24 +863,27 @@ static void synthfilt_build_sb_samples(QDM2Context *q, GetBitContext *gb,
* @param quantized_coeffs pointer to quantized_coeffs[ch][0]
* @param gb bitreader context
*/
-static void init_quantized_coeffs_elem0(int8_t *quantized_coeffs,
+static int init_quantized_coeffs_elem0(int8_t *quantized_coeffs,
GetBitContext *gb)
{
int i, k, run, level, diff;
if (get_bits_left(gb) < 16)
- return;
+ return -1;
level = qdm2_get_vlc(gb, &vlc_tab_level, 0, 2);
quantized_coeffs[0] = level;
for (i = 0; i < 7; ) {
if (get_bits_left(gb) < 16)
- break;
+ return -1;
run = qdm2_get_vlc(gb, &vlc_tab_run, 0, 1) + 1;
+ if (i + run >= 8)
+ return -1;
+
if (get_bits_left(gb) < 16)
- break;
+ return -1;
diff = qdm2_get_se_vlc(&vlc_tab_diff, gb, 2);
for (k = 1; k <= run; k++)
@@ -1028,6 +892,7 @@ static void init_quantized_coeffs_elem0(int8_t *quantized_coeffs,
level += diff;
i += run;
}
+ return 0;
}
/**
@@ -1102,7 +967,7 @@ static void init_tone_level_dequantization(QDM2Context *q, GetBitContext *gb)
* @param q context
* @param node pointer to node with packet
*/
-static void process_subpacket_9(QDM2Context *q, QDM2SubPNode *node)
+static int process_subpacket_9(QDM2Context *q, QDM2SubPNode *node)
{
GetBitContext gb;
int i, j, k, n, ch, run, level, diff;
@@ -1120,6 +985,9 @@ static void process_subpacket_9(QDM2Context *q, QDM2SubPNode *node)
run = qdm2_get_vlc(&gb, &vlc_tab_run, 0, 1) + 1;
diff = qdm2_get_se_vlc(&vlc_tab_diff, &gb, 2);
+ if (j + run >= 8)
+ return -1;
+
for (k = 1; k <= run; k++)
q->quantized_coeffs[ch][i][j + k] = (level + ((k * diff) / run));
@@ -1131,6 +999,8 @@ static void process_subpacket_9(QDM2Context *q, QDM2SubPNode *node)
for (ch = 0; ch < q->nb_channels; ch++)
for (i = 0; i < 8; i++)
q->quantized_coeffs[ch][0][i] = 0;
+
+ return 0;
}
/**
@@ -1200,7 +1070,7 @@ static void process_subpacket_12(QDM2Context *q, QDM2SubPNode *node)
synthfilt_build_sb_samples(q, &gb, length, 8, QDM2_SB_USED(q->sub_sampling));
}
-/*
+/**
* Process new subpackets for synthesis filter
*
* @param q context
@@ -1233,7 +1103,7 @@ static void process_synthesis_subpackets(QDM2Context *q, QDM2SubPNode *list)
process_subpacket_12(q, NULL);
}
-/*
+/**
* Decode superblock, fill packet lists.
*
* @param q context
@@ -1393,9 +1263,14 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration,
local_int_10 = 1 << (q->group_order - duration - 1);
offset = 1;
- while (1) {
+ while (get_bits_left(gb)>0) {
if (q->superblocktype_2_3) {
while ((n = qdm2_get_vlc(gb, &vlc_tab_fft_tone_offset[local_int_8], 1, 2)) < 2) {
+ if (get_bits_left(gb)<0) {
+ if(local_int_4 < q->group_size)
+ av_log(NULL, AV_LOG_ERROR, "overread in qdm2_fft_decode_tones()\n");
+ return;
+ }
offset = 1;
if (n == 0) {
local_int_4 += local_int_10;
@@ -1708,12 +1583,19 @@ static void qdm2_synthesis_filter(QDM2Context *q, int index)
*
* @param q context
*/
-static av_cold void qdm2_init_static_data(AVCodec *codec) {
+static av_cold void qdm2_init_static_data(void) {
+ static int done;
+
+ if(done)
+ return;
+
qdm2_init_vlc();
ff_mpa_synth_init_float(ff_mpa_synth_window_float);
softclip_table_init();
rnd_table_init();
init_noise_samples();
+
+ done = 1;
}
/**
@@ -1726,6 +1608,8 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx)
int extradata_size;
int tmp_val, tmp, size;
+ qdm2_init_static_data();
+
/* extradata parsing
Structure:
@@ -1814,8 +1698,10 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx)
avctx->channels = s->nb_channels = s->channels = AV_RB32(extradata);
extradata += 4;
- if (s->channels <= 0 || s->channels > MPA_MAX_CHANNELS)
+ if (s->channels <= 0 || s->channels > MPA_MAX_CHANNELS) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n");
return AVERROR_INVALIDDATA;
+ }
avctx->channel_layout = avctx->channels == 2 ? AV_CH_LAYOUT_STEREO :
AV_CH_LAYOUT_MONO;
@@ -1842,6 +1728,7 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx)
// something like max decodable tones
s->group_order = av_log2(s->group_size) + 1;
s->frame_size = s->group_size / 16; // 16 iterations per super block
+
if (s->frame_size > QDM2_MAX_FRAME_SIZE)
return AVERROR_INVALIDDATA;
@@ -1864,18 +1751,9 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx)
if ((tmp * 2240) < avctx->bit_rate) tmp_val = 4;
s->cm_table_select = tmp_val;
- if (s->sub_sampling == 0)
- tmp = 7999;
- else
- tmp = ((-(s->sub_sampling -1)) & 8000) + 20000;
- /*
- 0: 7999 -> 0
- 1: 20000 -> 2
- 2: 28000 -> 2
- */
- if (tmp < 8000)
+ if (avctx->bit_rate <= 8000)
s->coeff_per_sb_select = 0;
- else if (tmp <= 16000)
+ else if (avctx->bit_rate < 16000)
s->coeff_per_sb_select = 1;
else
s->coeff_per_sb_select = 2;
@@ -1912,6 +1790,9 @@ static int qdm2_decode(QDM2Context *q, const uint8_t *in, int16_t *out)
int ch, i;
const int frame_size = (q->frame_size * q->channels);
+ if((unsigned)frame_size > FF_ARRAY_ELEMS(q->output_buffer)/2)
+ return -1;
+
/* select input buffer */
q->compressed_data = in;
q->compressed_size = q->checksum_size;
@@ -1983,10 +1864,8 @@ static int qdm2_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = 16 * s->frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
out = (int16_t *)frame->data[0];
for (i = 0; i < 16; i++) {
@@ -2007,7 +1886,6 @@ AVCodec ff_qdm2_decoder = {
.id = AV_CODEC_ID_QDM2,
.priv_data_size = sizeof(QDM2Context),
.init = qdm2_decode_init,
- .init_static_data = qdm2_init_static_data,
.close = qdm2_decode_close,
.decode = qdm2_decode_frame,
.capabilities = CODEC_CAP_DR1,
diff --git a/libavcodec/qdm2_tablegen.c b/libavcodec/qdm2_tablegen.c
index 59d82df851..e19b49b235 100644
--- a/libavcodec/qdm2_tablegen.c
+++ b/libavcodec/qdm2_tablegen.c
@@ -3,27 +3,27 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
+#include "tableprint_vlc.h"
#define CONFIG_HARDCODED_TABLES 0
#include "qdm2_tablegen.h"
-#include "tableprint.h"
int main(void)
{
@@ -40,5 +40,22 @@ int main(void)
WRITE_2D_ARRAY("static const", uint8_t, random_dequant_index);
WRITE_2D_ARRAY("static const", uint8_t, random_dequant_type24);
+ qdm2_init_vlc();
+
+ WRITE_2D_ARRAY("static const", VLC_TYPE, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_level, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_diff, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_run, qdm2_table);
+ WRITE_VLC_TYPE("static const", fft_level_exp_alt_vlc, qdm2_table);
+ WRITE_VLC_TYPE("static const", fft_level_exp_vlc, qdm2_table);
+ WRITE_VLC_TYPE("static const", fft_stereo_exp_vlc, qdm2_table);
+ WRITE_VLC_TYPE("static const", fft_stereo_phase_vlc, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_tone_level_idx_hi1, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_tone_level_idx_mid, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_tone_level_idx_hi2, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_type30, qdm2_table);
+ WRITE_VLC_TYPE("static const", vlc_tab_type34, qdm2_table);
+ WRITE_VLC_ARRAY("static const", vlc_tab_fft_tone_offset, qdm2_table);
+
return 0;
}
diff --git a/libavcodec/qdm2_tablegen.h b/libavcodec/qdm2_tablegen.h
index bb73d92531..2331ebfbb2 100644
--- a/libavcodec/qdm2_tablegen.h
+++ b/libavcodec/qdm2_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include <stdint.h>
#include <math.h>
#include "libavutil/attributes.h"
+#include "qdm2data.h"
#define SOFTCLIP_THRESHOLD 27600
#define HARDCLIP_THRESHOLD 35716
@@ -34,10 +35,11 @@
#define softclip_table_init()
#define rnd_table_init()
#define init_noise_samples()
+#define qdm2_init_vlc()
#include "libavcodec/qdm2_tables.h"
#else
static uint16_t softclip_table[HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1];
-static float noise_table[4096];
+static float noise_table[4096 + 20];
static uint8_t random_dequant_index[256][5];
static uint8_t random_dequant_type24[128][3];
static float noise_samples[128];
@@ -54,8 +56,7 @@ static av_cold void softclip_table_init(void) {
// random generated table
static av_cold void rnd_table_init(void) {
int i,j;
- uint32_t ldw,hdw;
- uint64_t tmp64_1;
+ uint32_t ldw;
uint64_t random_seed = 0;
float delta = 1.0 / 16384.0;
for(i = 0; i < 4096 ;i++) {
@@ -67,22 +68,18 @@ static av_cold void rnd_table_init(void) {
random_seed = 81;
ldw = i;
for (j = 0; j < 5 ;j++) {
- random_dequant_index[i][j] = (uint8_t)((ldw / random_seed) & 0xFF);
- ldw = (uint32_t)ldw % (uint32_t)random_seed;
- tmp64_1 = (random_seed * 0x55555556);
- hdw = (uint32_t)(tmp64_1 >> 32);
- random_seed = (uint64_t)(hdw + (ldw >> 31));
+ random_dequant_index[i][j] = ldw / random_seed;
+ ldw %= random_seed;
+ random_seed /= 3;
}
}
for (i = 0; i < 128 ;i++) {
random_seed = 25;
ldw = i;
for (j = 0; j < 3 ;j++) {
- random_dequant_type24[i][j] = (uint8_t)((ldw / random_seed) & 0xFF);
- ldw = (uint32_t)ldw % (uint32_t)random_seed;
- tmp64_1 = (random_seed * 0x66666667);
- hdw = (uint32_t)(tmp64_1 >> 33);
- random_seed = hdw + (ldw >> 31);
+ random_dequant_type24[i][j] = ldw / random_seed;
+ ldw %= random_seed;
+ random_seed /= 5;
}
}
}
@@ -97,6 +94,168 @@ static av_cold void init_noise_samples(void) {
noise_samples[i] = (delta * (float)((random_seed >> 16) & 0x00007fff) - 1.0);
}
}
+
+static VLC vlc_tab_level;
+static VLC vlc_tab_diff;
+static VLC vlc_tab_run;
+static VLC fft_level_exp_alt_vlc;
+static VLC fft_level_exp_vlc;
+static VLC fft_stereo_exp_vlc;
+static VLC fft_stereo_phase_vlc;
+static VLC vlc_tab_tone_level_idx_hi1;
+static VLC vlc_tab_tone_level_idx_mid;
+static VLC vlc_tab_tone_level_idx_hi2;
+static VLC vlc_tab_type30;
+static VLC vlc_tab_type34;
+static VLC vlc_tab_fft_tone_offset[5];
+
+static const uint16_t qdm2_vlc_offs[] = {
+ 0,260,566,598,894,1166,1230,1294,1678,1950,2214,2278,2310,2570,2834,3124,3448,3838,
+};
+
+static VLC_TYPE qdm2_table[3838][2];
+
+static av_cold void qdm2_init_vlc(void)
+{
+ vlc_tab_level.table = &qdm2_table[qdm2_vlc_offs[0]];
+ vlc_tab_level.table_allocated = qdm2_vlc_offs[1] - qdm2_vlc_offs[0];
+ init_vlc(&vlc_tab_level, 8, 24,
+ vlc_tab_level_huffbits, 1, 1,
+ vlc_tab_level_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_diff.table = &qdm2_table[qdm2_vlc_offs[1]];
+ vlc_tab_diff.table_allocated = qdm2_vlc_offs[2] - qdm2_vlc_offs[1];
+ init_vlc(&vlc_tab_diff, 8, 37,
+ vlc_tab_diff_huffbits, 1, 1,
+ vlc_tab_diff_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_run.table = &qdm2_table[qdm2_vlc_offs[2]];
+ vlc_tab_run.table_allocated = qdm2_vlc_offs[3] - qdm2_vlc_offs[2];
+ init_vlc(&vlc_tab_run, 5, 6,
+ vlc_tab_run_huffbits, 1, 1,
+ vlc_tab_run_huffcodes, 1, 1,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ fft_level_exp_alt_vlc.table = &qdm2_table[qdm2_vlc_offs[3]];
+ fft_level_exp_alt_vlc.table_allocated = qdm2_vlc_offs[4] -
+ qdm2_vlc_offs[3];
+ init_vlc(&fft_level_exp_alt_vlc, 8, 28,
+ fft_level_exp_alt_huffbits, 1, 1,
+ fft_level_exp_alt_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ fft_level_exp_vlc.table = &qdm2_table[qdm2_vlc_offs[4]];
+ fft_level_exp_vlc.table_allocated = qdm2_vlc_offs[5] - qdm2_vlc_offs[4];
+ init_vlc(&fft_level_exp_vlc, 8, 20,
+ fft_level_exp_huffbits, 1, 1,
+ fft_level_exp_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ fft_stereo_exp_vlc.table = &qdm2_table[qdm2_vlc_offs[5]];
+ fft_stereo_exp_vlc.table_allocated = qdm2_vlc_offs[6] -
+ qdm2_vlc_offs[5];
+ init_vlc(&fft_stereo_exp_vlc, 6, 7,
+ fft_stereo_exp_huffbits, 1, 1,
+ fft_stereo_exp_huffcodes, 1, 1,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ fft_stereo_phase_vlc.table = &qdm2_table[qdm2_vlc_offs[6]];
+ fft_stereo_phase_vlc.table_allocated = qdm2_vlc_offs[7] -
+ qdm2_vlc_offs[6];
+ init_vlc(&fft_stereo_phase_vlc, 6, 9,
+ fft_stereo_phase_huffbits, 1, 1,
+ fft_stereo_phase_huffcodes, 1, 1,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_tone_level_idx_hi1.table =
+ &qdm2_table[qdm2_vlc_offs[7]];
+ vlc_tab_tone_level_idx_hi1.table_allocated = qdm2_vlc_offs[8] -
+ qdm2_vlc_offs[7];
+ init_vlc(&vlc_tab_tone_level_idx_hi1, 8, 20,
+ vlc_tab_tone_level_idx_hi1_huffbits, 1, 1,
+ vlc_tab_tone_level_idx_hi1_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_tone_level_idx_mid.table =
+ &qdm2_table[qdm2_vlc_offs[8]];
+ vlc_tab_tone_level_idx_mid.table_allocated = qdm2_vlc_offs[9] -
+ qdm2_vlc_offs[8];
+ init_vlc(&vlc_tab_tone_level_idx_mid, 8, 24,
+ vlc_tab_tone_level_idx_mid_huffbits, 1, 1,
+ vlc_tab_tone_level_idx_mid_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_tone_level_idx_hi2.table =
+ &qdm2_table[qdm2_vlc_offs[9]];
+ vlc_tab_tone_level_idx_hi2.table_allocated = qdm2_vlc_offs[10] -
+ qdm2_vlc_offs[9];
+ init_vlc(&vlc_tab_tone_level_idx_hi2, 8, 24,
+ vlc_tab_tone_level_idx_hi2_huffbits, 1, 1,
+ vlc_tab_tone_level_idx_hi2_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_type30.table = &qdm2_table[qdm2_vlc_offs[10]];
+ vlc_tab_type30.table_allocated = qdm2_vlc_offs[11] - qdm2_vlc_offs[10];
+ init_vlc(&vlc_tab_type30, 6, 9,
+ vlc_tab_type30_huffbits, 1, 1,
+ vlc_tab_type30_huffcodes, 1, 1,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_type34.table = &qdm2_table[qdm2_vlc_offs[11]];
+ vlc_tab_type34.table_allocated = qdm2_vlc_offs[12] - qdm2_vlc_offs[11];
+ init_vlc(&vlc_tab_type34, 5, 10,
+ vlc_tab_type34_huffbits, 1, 1,
+ vlc_tab_type34_huffcodes, 1, 1,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_fft_tone_offset[0].table =
+ &qdm2_table[qdm2_vlc_offs[12]];
+ vlc_tab_fft_tone_offset[0].table_allocated = qdm2_vlc_offs[13] -
+ qdm2_vlc_offs[12];
+ init_vlc(&vlc_tab_fft_tone_offset[0], 8, 23,
+ vlc_tab_fft_tone_offset_0_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_0_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_fft_tone_offset[1].table =
+ &qdm2_table[qdm2_vlc_offs[13]];
+ vlc_tab_fft_tone_offset[1].table_allocated = qdm2_vlc_offs[14] -
+ qdm2_vlc_offs[13];
+ init_vlc(&vlc_tab_fft_tone_offset[1], 8, 28,
+ vlc_tab_fft_tone_offset_1_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_1_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_fft_tone_offset[2].table =
+ &qdm2_table[qdm2_vlc_offs[14]];
+ vlc_tab_fft_tone_offset[2].table_allocated = qdm2_vlc_offs[15] -
+ qdm2_vlc_offs[14];
+ init_vlc(&vlc_tab_fft_tone_offset[2], 8, 32,
+ vlc_tab_fft_tone_offset_2_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_2_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_fft_tone_offset[3].table =
+ &qdm2_table[qdm2_vlc_offs[15]];
+ vlc_tab_fft_tone_offset[3].table_allocated = qdm2_vlc_offs[16] -
+ qdm2_vlc_offs[15];
+ init_vlc(&vlc_tab_fft_tone_offset[3], 8, 35,
+ vlc_tab_fft_tone_offset_3_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_3_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+
+ vlc_tab_fft_tone_offset[4].table =
+ &qdm2_table[qdm2_vlc_offs[16]];
+ vlc_tab_fft_tone_offset[4].table_allocated = qdm2_vlc_offs[17] -
+ qdm2_vlc_offs[16];
+ init_vlc(&vlc_tab_fft_tone_offset[4], 8, 38,
+ vlc_tab_fft_tone_offset_4_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_4_huffcodes, 2, 2,
+ INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE);
+}
+
#endif /* CONFIG_HARDCODED_TABLES */
#endif /* AVCODEC_QDM2_TABLEGEN_H */
diff --git a/libavcodec/qdm2data.h b/libavcodec/qdm2data.h
index ad6ea88ff6..355d61387b 100644
--- a/libavcodec/qdm2data.h
+++ b/libavcodec/qdm2data.h
@@ -5,20 +5,20 @@
* Copyright (c) 2005 Alex Beregszaszi
* Copyright (c) 2005 Roberto Togni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c
index 477175c066..838f836516 100644
--- a/libavcodec/qdrw.c
+++ b/libavcodec/qdrw.c
@@ -3,20 +3,20 @@
* Copyright (c) 2004 Konstantin Shishkov
* Copyright (c) 2015 Vittorio Giovara
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -95,6 +95,8 @@ static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
pos -= offset;
pos++;
}
+ if (pos >= offset)
+ return AVERROR_INVALIDDATA;
}
left -= 2;
} else { /* copy */
@@ -105,6 +107,8 @@ static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
pos -= offset;
pos++;
}
+ if (pos >= offset)
+ return AVERROR_INVALIDDATA;
}
left -= 2 + code;
}
@@ -114,6 +118,29 @@ static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
return 0;
}
+static int check_header(const char *buf, int buf_size)
+{
+ unsigned w, h, v0, v1;
+
+ if (buf_size < 40)
+ return 0;
+
+ w = AV_RB16(buf+6);
+ h = AV_RB16(buf+8);
+ v0 = AV_RB16(buf+10);
+ v1 = AV_RB16(buf+12);
+
+ if (!w || !h)
+ return 0;
+
+ if (v0 == 0x1101)
+ return 1;
+ if (v0 == 0x0011 && v1 == 0x02FF)
+ return 2;
+ return 0;
+}
+
+
static int decode_frame(AVCodecContext *avctx,
void *data, int *got_frame,
AVPacket *avpkt)
@@ -122,13 +149,16 @@ static int decode_frame(AVCodecContext *avctx,
GetByteContext gbc;
int colors;
int w, h, ret;
+ int ver;
bytestream2_init(&gbc, avpkt->data, avpkt->size);
-
- /* PICT images start with a 512 bytes empty header */
- if (bytestream2_peek_be32(&gbc) == 0)
+ if ( bytestream2_get_bytes_left(&gbc) >= 552
+ && check_header(gbc.buffer + 512, bytestream2_get_bytes_left(&gbc) - 512)
+ )
bytestream2_skip(&gbc, 512);
+ ver = check_header(gbc.buffer, bytestream2_get_bytes_left(&gbc));
+
/* smallest PICT header */
if (bytestream2_get_bytes_left(&gbc) < 40) {
av_log(avctx, AV_LOG_ERROR, "Frame is too small %d\n",
@@ -146,12 +176,15 @@ static int decode_frame(AVCodecContext *avctx,
/* version 1 is identified by 0x1101
* it uses byte-aligned opcodes rather than word-aligned */
- if (bytestream2_get_be32(&gbc) != 0x001102FF) {
+ if (ver == 1) {
avpriv_request_sample(avctx, "QuickDraw version 1");
return AVERROR_PATCHWELCOME;
+ } else if (ver != 2) {
+ avpriv_request_sample(avctx, "QuickDraw version unknown (%X)", bytestream2_get_be32(&gbc));
+ return AVERROR_PATCHWELCOME;
}
- bytestream2_skip(&gbc, 26);
+ bytestream2_skip(&gbc, 4+26);
while (bytestream2_get_bytes_left(&gbc) >= 4) {
int bppcnt, bpp;
@@ -191,10 +224,8 @@ static int decode_frame(AVCodecContext *avctx,
bytestream2_get_bytes_left(&gbc));
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors);
p->palette_has_changed = 1;
diff --git a/libavcodec/qpeg.c b/libavcodec/qpeg.c
index 4de1655ebb..71f322b828 100644
--- a/libavcodec/qpeg.c
+++ b/libavcodec/qpeg.c
@@ -2,20 +2,20 @@
* QPEG codec
* Copyright (c) 2004 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,8 +30,7 @@
typedef struct QpegContext{
AVCodecContext *avctx;
- AVFrame *pic;
- uint8_t *refdata;
+ AVFrame *pic, *ref;
uint32_t pal[256];
GetByteContext buffer;
} QpegContext;
@@ -111,7 +110,7 @@ static const int qpeg_table_w[16] =
{ 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
/* Decodes delta frames */
-static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
+static void av_noinline qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
int stride, int width, int height,
int delta, const uint8_t *ctable,
uint8_t *refdata)
@@ -121,9 +120,13 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
int filled = 0;
int orig_height;
- /* copy prev frame */
- for(i = 0; i < height; i++)
- memcpy(refdata + (i * width), dst + (i * stride), width);
+ if (refdata) {
+ /* copy prev frame */
+ for (i = 0; i < height; i++)
+ memcpy(dst + (i * stride), refdata + (i * stride), width);
+ } else {
+ refdata = dst;
+ }
orig_height = height;
height--;
@@ -134,7 +137,7 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
if(delta) {
/* motion compensation */
- while((code & 0xF0) == 0xF0) {
+ while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) {
if(delta == 1) {
int me_idx;
int me_w, me_h, me_x, me_y;
@@ -161,16 +164,16 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
/* check motion vector */
if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
- (height - me_y - me_h < 0) || (height - me_y > orig_height) ||
+ (height - me_y - me_h < 0) || (height - me_y >= orig_height) ||
(filled + me_w > width) || (height - me_h < 0))
av_log(NULL, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
me_x, me_y, me_w, me_h, filled, height);
else {
/* do motion compensation */
- me_plane = refdata + (filled + me_x) + (height - me_y) * width;
+ me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
for(j = 0; j < me_h; j++) {
for(i = 0; i < me_w; i++)
- dst[filled + i - (j * stride)] = me_plane[i - (j * width)];
+ dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
}
}
}
@@ -198,6 +201,9 @@ static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
} else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
code &= 0x1F;
+ if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
+ break;
+
for(i = 0; i <= code; i++) {
dst[filled++] = bytestream2_get_byte(&qctx->buffer);
if(filled >= width) {
@@ -251,6 +257,7 @@ static int decode_frame(AVCodecContext *avctx,
uint8_t ctable[128];
QpegContext * const a = avctx->priv_data;
AVFrame * const p = a->pic;
+ AVFrame * const ref = a->ref;
uint8_t* outdata;
int delta, ret;
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
@@ -261,10 +268,12 @@ static int decode_frame(AVCodecContext *avctx,
}
bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
- if ((ret = ff_reget_buffer(avctx, p)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+
+ av_frame_unref(ref);
+ av_frame_move_ref(ref, p);
+
+ if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
outdata = p->data[0];
bytestream2_skip(&a->buffer, 4);
bytestream2_get_buffer(&a->buffer, ctable, 128);
@@ -274,7 +283,7 @@ static int decode_frame(AVCodecContext *avctx,
if(delta == 0x10) {
qpeg_decode_intra(a, outdata, p->linesize[0], avctx->width, avctx->height);
} else {
- qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, a->refdata);
+ qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, ref->data[0]);
}
/* make the palette available on the way out */
@@ -292,13 +301,25 @@ static int decode_frame(AVCodecContext *avctx,
return avpkt->size;
}
+static void decode_flush(AVCodecContext *avctx){
+ QpegContext * const a = avctx->priv_data;
+ int i, pal_size;
+ const uint8_t *pal_src;
+
+ pal_size = FFMIN(1024U, avctx->extradata_size);
+ pal_src = avctx->extradata + avctx->extradata_size - pal_size;
+
+ for (i=0; i<pal_size/4; i++)
+ a->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
+}
+
static av_cold int decode_end(AVCodecContext *avctx)
{
QpegContext * const a = avctx->priv_data;
av_frame_free(&a->pic);
+ av_frame_free(&a->ref);
- av_free(a->refdata);
return 0;
}
@@ -307,10 +328,12 @@ static av_cold int decode_init(AVCodecContext *avctx){
a->avctx = avctx;
avctx->pix_fmt= AV_PIX_FMT_PAL8;
- a->refdata = av_malloc(avctx->width * avctx->height);
+
+ decode_flush(avctx);
a->pic = av_frame_alloc();
- if (!a->pic) {
+ a->ref = av_frame_alloc();
+ if (!a->pic || !a->ref) {
decode_end(avctx);
return AVERROR(ENOMEM);
}
@@ -327,5 +350,6 @@ AVCodec ff_qpeg_decoder = {
.init = decode_init,
.close = decode_end,
.decode = decode_frame,
+ .flush = decode_flush,
.capabilities = CODEC_CAP_DR1,
};
diff --git a/libavcodec/qpel_template.c b/libavcodec/qpel_template.c
index 2106160741..e52a78cf22 100644
--- a/libavcodec/qpel_template.c
+++ b/libavcodec/qpel_template.c
@@ -1,20 +1,22 @@
/*
* quarterpel DSP function templates
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qpeldsp.c b/libavcodec/qpeldsp.c
index 1d0422a382..1c0ec637d0 100644
--- a/libavcodec/qpeldsp.c
+++ b/libavcodec/qpeldsp.c
@@ -1,20 +1,22 @@
/*
* quarterpel DSP functions
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +32,7 @@
#include "libavutil/attributes.h"
#include "copy_block.h"
#include "qpeldsp.h"
+#include "diracdsp.h"
#define BIT_DEPTH 8
#include "hpel_template.c"
@@ -732,6 +735,51 @@ void ff_put_pixels8_l2_8(uint8_t *dst, const uint8_t *src1, const uint8_t *src2,
}
+#if CONFIG_DIRAC_DECODER
+#define DIRAC_MC(OPNAME)\
+void ff_ ## OPNAME ## _dirac_pixels8_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels8_8_c(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels16_8_c(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels16_8_c(dst , src[0] , stride, h);\
+ OPNAME ## _pixels16_8_c(dst+16, src[0]+16, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels8_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels8_l2_8(dst, src[0], src[1], stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels16_l2_8(dst, src[0], src[1], stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels16_l2_8(dst , src[0] , src[1] , stride, stride, stride, h);\
+ OPNAME ## _pixels16_l2_8(dst+16, src[0]+16, src[1]+16, stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels8_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels8_l4_8(dst, src[0], src[1], src[2], src[3], stride, stride, stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels16_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels16_l4_8(dst, src[0], src[1], src[2], src[3], stride, stride, stride, stride, stride, h);\
+}\
+void ff_ ## OPNAME ## _dirac_pixels32_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ OPNAME ## _pixels16_l4_8(dst , src[0] , src[1] , src[2] , src[3] , stride, stride, stride, stride, stride, h);\
+ OPNAME ## _pixels16_l4_8(dst+16, src[0]+16, src[1]+16, src[2]+16, src[3]+16, stride, stride, stride, stride, stride, h);\
+}
+DIRAC_MC(put)
+DIRAC_MC(avg)
+#endif
+
av_cold void ff_qpeldsp_init(QpelDSPContext *c)
{
#define dspfunc(PFX, IDX, NUM) \
diff --git a/libavcodec/qpeldsp.h b/libavcodec/qpeldsp.h
index 4ad141d057..b51420a6a2 100644
--- a/libavcodec/qpeldsp.h
+++ b/libavcodec/qpeldsp.h
@@ -1,20 +1,20 @@
/*
* quarterpel DSP functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index bd9e18d43e..31be9d1fa3 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -1,20 +1,20 @@
/*
* Intel MediaSDK QSV encoder/decoder shared code
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsv.h b/libavcodec/qsv.h
index 6532594257..e7487c88ea 100644
--- a/libavcodec/qsv.h
+++ b/libavcodec/qsv.h
@@ -1,20 +1,20 @@
/*
* Intel MediaSDK QSV public API
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsv_api.c b/libavcodec/qsv_api.c
index 234b5961e3..327ff7d813 100644
--- a/libavcodec/qsv_api.c
+++ b/libavcodec/qsv_api.c
@@ -1,20 +1,20 @@
/*
* Intel MediaSDK QSV public API functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index d13848a850..86fca5fd8c 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -1,20 +1,20 @@
/*
* Intel MediaSDK QSV encoder/decoder shared code
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,7 +40,7 @@ typedef struct QSVFrame {
} QSVFrame;
/**
- * Convert a libmfx error code into a libav error code.
+ * Convert a libmfx error code into a ffmpeg error code.
*/
int ff_qsv_error(int mfx_err);
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index c077b110db..47709b50f4 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -4,20 +4,20 @@
* copyright (c) 2013 Luca Barbato
* copyright (c) 2015 Anton Khirnov <anton@khirnov.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index 486a7e3c54..373cc72b2a 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -3,20 +3,20 @@
*
* copyright (c) 2013 Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsvdec_h264.c b/libavcodec/qsvdec_h264.c
index b6527f0cc0..7eb7a6c134 100644
--- a/libavcodec/qsvdec_h264.c
+++ b/libavcodec/qsvdec_h264.c
@@ -4,20 +4,20 @@
* copyright (c) 2013 Luca Barbato
* copyright (c) 2015 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 2830b0d836..bcf3d73c58 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -4,20 +4,20 @@
* copyright (c) 2013 Yukinori Yamazoe
* copyright (c) 2015 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index 05d268a948..9f7f8ccfa5 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -3,20 +3,20 @@
*
* copyright (c) 2013 Yukinori Yamazoe
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c
index 441ede8b14..d0b9b03f2e 100644
--- a/libavcodec/qsvenc_h264.c
+++ b/libavcodec/qsvenc_h264.c
@@ -3,20 +3,20 @@
*
* copyright (c) 2013 Yukinori Yamazoe
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c
index 28f1720aea..b367643782 100644
--- a/libavcodec/qtrle.c
+++ b/libavcodec/qtrle.c
@@ -1,21 +1,21 @@
/*
* Quicktime Animation (RLE) Video Decoder
- * Copyright (C) 2004 the ffmpeg project
+ * Copyright (c) 2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,17 +59,25 @@ static void qtrle_decode_1bpp(QtrleContext *s, int row_ptr, int lines_to_change)
int rle_code;
int pixel_ptr;
int row_inc = s->frame->linesize[0];
- unsigned char pi0, pi1; /* 2 8-pixel values */
- unsigned char *rgb = s->frame->data[0];
+ uint8_t pi0, pi1; /* 2 8-pixel values */
+ uint8_t *rgb = s->frame->data[0];
int pixel_limit = s->frame->linesize[0] * s->avctx->height;
int skip;
+ /* skip & 0x80 appears to mean 'start a new line', which can be interpreted
+ * as 'go to next line' during the decoding of a frame but is 'go to first
+ * line' at the beginning. Since we always interpret it as 'go to next line'
+ * in the decoding loop (which makes code simpler/faster), the first line
+ * would not be counted, so we count one more.
+ * See: https://trac.ffmpeg.org/ticket/226
+ * In the following decoding loop, row_ptr will be the position of the
+ * current row. */
row_ptr -= row_inc;
pixel_ptr = row_ptr;
lines_to_change++;
while (lines_to_change) {
skip = bytestream2_get_byte(&s->g);
- rle_code = (signed char)bytestream2_get_byte(&s->g);
+ rle_code = (int8_t)bytestream2_get_byte(&s->g);
if (rle_code == 0)
break;
if(skip & 0x80) {
@@ -80,6 +88,9 @@ static void qtrle_decode_1bpp(QtrleContext *s, int row_ptr, int lines_to_change)
pixel_ptr += 2 * skip;
CHECK_PIXEL_PTR(0); /* make sure pixel_ptr is positive */
+ if(rle_code == -1)
+ continue;
+
if (rle_code < 0) {
/* decode the run length code */
rle_code = -rle_code;
@@ -99,8 +110,8 @@ static void qtrle_decode_1bpp(QtrleContext *s, int row_ptr, int lines_to_change)
rle_code *= 2;
CHECK_PIXEL_PTR(rle_code);
- while (rle_code--)
- rgb[pixel_ptr++] = bytestream2_get_byte(&s->g);
+ bytestream2_get_buffer(&s->g, &rgb[pixel_ptr], rle_code);
+ pixel_ptr += rle_code;
}
}
}
@@ -111,8 +122,8 @@ static inline void qtrle_decode_2n4bpp(QtrleContext *s, int row_ptr,
int rle_code, i;
int pixel_ptr;
int row_inc = s->frame->linesize[0];
- unsigned char pi[16]; /* 16 palette indices */
- unsigned char *rgb = s->frame->data[0];
+ uint8_t pi[16]; /* 16 palette indices */
+ uint8_t *rgb = s->frame->data[0];
int pixel_limit = s->frame->linesize[0] * s->avctx->height;
int num_pixels = (bpp == 4) ? 8 : 16;
@@ -120,7 +131,7 @@ static inline void qtrle_decode_2n4bpp(QtrleContext *s, int row_ptr,
pixel_ptr = row_ptr + (num_pixels * (bytestream2_get_byte(&s->g) - 1));
CHECK_PIXEL_PTR(0);
- while ((rle_code = (signed char)bytestream2_get_byte(&s->g)) != -1) {
+ while ((rle_code = (int8_t)bytestream2_get_byte(&s->g)) != -1) {
if (rle_code == 0) {
/* there's another skip code in the stream */
pixel_ptr += (num_pixels * (bytestream2_get_byte(&s->g) - 1));
@@ -136,8 +147,8 @@ static inline void qtrle_decode_2n4bpp(QtrleContext *s, int row_ptr,
}
CHECK_PIXEL_PTR(rle_code * num_pixels);
while (rle_code--) {
- for (i = 0; i < num_pixels; i++)
- rgb[pixel_ptr++] = pi[i];
+ memcpy(&rgb[pixel_ptr], &pi, num_pixels);
+ pixel_ptr += num_pixels;
}
} else {
/* copy the same pixel directly to output 4 times */
@@ -167,15 +178,15 @@ static void qtrle_decode_8bpp(QtrleContext *s, int row_ptr, int lines_to_change)
int rle_code;
int pixel_ptr;
int row_inc = s->frame->linesize[0];
- unsigned char pi1, pi2, pi3, pi4; /* 4 palette indexes */
- unsigned char *rgb = s->frame->data[0];
+ uint8_t pi1, pi2, pi3, pi4; /* 4 palette indexes */
+ uint8_t *rgb = s->frame->data[0];
int pixel_limit = s->frame->linesize[0] * s->avctx->height;
while (lines_to_change--) {
pixel_ptr = row_ptr + (4 * (bytestream2_get_byte(&s->g) - 1));
CHECK_PIXEL_PTR(0);
- while ((rle_code = (signed char)bytestream2_get_byte(&s->g)) != -1) {
+ while ((rle_code = (int8_t)bytestream2_get_byte(&s->g)) != -1) {
if (rle_code == 0) {
/* there's another skip code in the stream */
pixel_ptr += (4 * (bytestream2_get_byte(&s->g) - 1));
@@ -203,9 +214,8 @@ static void qtrle_decode_8bpp(QtrleContext *s, int row_ptr, int lines_to_change)
rle_code *= 4;
CHECK_PIXEL_PTR(rle_code);
- while (rle_code--) {
- rgb[pixel_ptr++] = bytestream2_get_byte(&s->g);
- }
+ bytestream2_get_buffer(&s->g, &rgb[pixel_ptr], rle_code);
+ pixel_ptr += rle_code;
}
}
row_ptr += row_inc;
@@ -217,15 +227,15 @@ static void qtrle_decode_16bpp(QtrleContext *s, int row_ptr, int lines_to_change
int rle_code;
int pixel_ptr;
int row_inc = s->frame->linesize[0];
- unsigned short rgb16;
- unsigned char *rgb = s->frame->data[0];
+ uint16_t rgb16;
+ uint8_t *rgb = s->frame->data[0];
int pixel_limit = s->frame->linesize[0] * s->avctx->height;
while (lines_to_change--) {
pixel_ptr = row_ptr + (bytestream2_get_byte(&s->g) - 1) * 2;
CHECK_PIXEL_PTR(0);
- while ((rle_code = (signed char)bytestream2_get_byte(&s->g)) != -1) {
+ while ((rle_code = (int8_t)bytestream2_get_byte(&s->g)) != -1) {
if (rle_code == 0) {
/* there's another skip code in the stream */
pixel_ptr += (bytestream2_get_byte(&s->g) - 1) * 2;
@@ -238,7 +248,7 @@ static void qtrle_decode_16bpp(QtrleContext *s, int row_ptr, int lines_to_change
CHECK_PIXEL_PTR(rle_code * 2);
while (rle_code--) {
- *(unsigned short *)(&rgb[pixel_ptr]) = rgb16;
+ *(uint16_t *)(&rgb[pixel_ptr]) = rgb16;
pixel_ptr += 2;
}
} else {
@@ -247,7 +257,7 @@ static void qtrle_decode_16bpp(QtrleContext *s, int row_ptr, int lines_to_change
/* copy pixels directly to output */
while (rle_code--) {
rgb16 = bytestream2_get_be16(&s->g);
- *(unsigned short *)(&rgb[pixel_ptr]) = rgb16;
+ *(uint16_t *)(&rgb[pixel_ptr]) = rgb16;
pixel_ptr += 2;
}
}
@@ -261,15 +271,15 @@ static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change
int rle_code;
int pixel_ptr;
int row_inc = s->frame->linesize[0];
- unsigned char r, g, b;
- unsigned char *rgb = s->frame->data[0];
+ uint8_t r, g, b;
+ uint8_t *rgb = s->frame->data[0];
int pixel_limit = s->frame->linesize[0] * s->avctx->height;
while (lines_to_change--) {
pixel_ptr = row_ptr + (bytestream2_get_byte(&s->g) - 1) * 3;
CHECK_PIXEL_PTR(0);
- while ((rle_code = (signed char)bytestream2_get_byte(&s->g)) != -1) {
+ while ((rle_code = (int8_t)bytestream2_get_byte(&s->g)) != -1) {
if (rle_code == 0) {
/* there's another skip code in the stream */
pixel_ptr += (bytestream2_get_byte(&s->g) - 1) * 3;
@@ -309,14 +319,14 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change
int pixel_ptr;
int row_inc = s->frame->linesize[0];
unsigned int argb;
- unsigned char *rgb = s->frame->data[0];
+ uint8_t *rgb = s->frame->data[0];
int pixel_limit = s->frame->linesize[0] * s->avctx->height;
while (lines_to_change--) {
pixel_ptr = row_ptr + (bytestream2_get_byte(&s->g) - 1) * 4;
CHECK_PIXEL_PTR(0);
- while ((rle_code = (signed char)bytestream2_get_byte(&s->g)) != -1) {
+ while ((rle_code = (int8_t)bytestream2_get_byte(&s->g)) != -1) {
if (rle_code == 0) {
/* there's another skip code in the stream */
pixel_ptr += (bytestream2_get_byte(&s->g) - 1) * 4;
@@ -403,10 +413,8 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
int ret;
bytestream2_init(&s->g, avpkt->data, avpkt->size);
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log (s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
/* check if this frame is even supposed to change */
if (avpkt->size < 8)
@@ -426,6 +434,8 @@ static int qtrle_decode_frame(AVCodecContext *avctx,
bytestream2_skip(&s->g, 2);
height = bytestream2_get_be16(&s->g);
bytestream2_skip(&s->g, 2);
+ if (height > s->avctx->height - start_line)
+ goto done;
} else {
start_line = 0;
height = s->avctx->height;
diff --git a/libavcodec/qtrleenc.c b/libavcodec/qtrleenc.c
index 7c98bea5f6..d723188413 100644
--- a/libavcodec/qtrleenc.c
+++ b/libavcodec/qtrleenc.c
@@ -5,20 +5,20 @@
*
* This file is based on flashsvenc.c.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,6 +39,7 @@ typedef struct QtrleEncContext {
int pixel_size;
AVPicture previous_frame;
unsigned int max_buf_size;
+ int logical_width;
/**
* This array will contain at ith position the value of the best RLE code
* if the line started at pixel i
@@ -75,13 +76,23 @@ static av_cold int qtrle_encode_end(AVCodecContext *avctx)
static av_cold int qtrle_encode_init(AVCodecContext *avctx)
{
QtrleEncContext *s = avctx->priv_data;
+ int ret;
if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
- return -1;
+ return AVERROR(EINVAL);
}
s->avctx=avctx;
+ s->logical_width=avctx->width;
switch (avctx->pix_fmt) {
+ case AV_PIX_FMT_GRAY8:
+ if (avctx->width % 4) {
+ av_log(avctx, AV_LOG_ERROR, "Width not being a multiple of 4 is not supported\n");
+ return AVERROR(EINVAL);
+ }
+ s->logical_width = avctx->width / 4;
+ s->pixel_size = 4;
+ break;
case AV_PIX_FMT_RGB555BE:
s->pixel_size = 2;
break;
@@ -95,24 +106,24 @@ static av_cold int qtrle_encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n");
break;
}
- avctx->bits_per_coded_sample = s->pixel_size*8;
+ avctx->bits_per_coded_sample = avctx->pix_fmt == AV_PIX_FMT_GRAY8 ? 40 : s->pixel_size*8;
- s->rlecode_table = av_mallocz(s->avctx->width);
- s->skip_table = av_mallocz(s->avctx->width);
- s->length_table = av_mallocz((s->avctx->width + 1)*sizeof(int));
+ s->rlecode_table = av_mallocz(s->logical_width);
+ s->skip_table = av_mallocz(s->logical_width);
+ s->length_table = av_mallocz_array(s->logical_width + 1, sizeof(int));
if (!s->skip_table || !s->length_table || !s->rlecode_table) {
av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n");
- return -1;
+ return AVERROR(ENOMEM);
}
- if (avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height) < 0) {
+ if ((ret = avpicture_alloc(&s->previous_frame, avctx->pix_fmt, avctx->width, avctx->height)) < 0) {
av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n");
- return -1;
+ return ret;
}
- s->max_buf_size = s->avctx->width*s->avctx->height*s->pixel_size*2 /* image base material */
- + 15 /* header + footer */
- + s->avctx->height*2 /* skip code+rle end */
- + s->avctx->width/MAX_RLE_BULK + 1 /* rle codes */;
+ s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size*2 /* image base material */
+ + 15 /* header + footer */
+ + s->avctx->height*2 /* skip code+rle end */
+ + s->logical_width/MAX_RLE_BULK + 1 /* rle codes */;
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame) {
@@ -128,26 +139,26 @@ static av_cold int qtrle_encode_init(AVCodecContext *avctx)
*/
static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, uint8_t **buf)
{
- int width=s->avctx->width;
+ int width=s->logical_width;
int i;
signed char rlecode;
- /* We will use it to compute the best bulk copy sequence */
- unsigned int bulkcount;
/* This will be the number of pixels equal to the preivous frame one's
* starting from the ith pixel */
unsigned int skipcount;
/* This will be the number of consecutive equal pixels in the current
* frame, starting from the ith one also */
- unsigned int repeatcount;
+ unsigned int av_uninit(repeatcount);
/* The cost of the three different possibilities */
- int total_bulk_cost;
int total_skip_cost;
int total_repeat_cost;
- int temp_cost;
- int j;
+ int base_bulk_cost;
+ int lowest_bulk_cost;
+ int lowest_bulk_cost_index;
+ int sec_lowest_bulk_cost;
+ int sec_lowest_bulk_cost_index;
uint8_t *this_line = p-> data[0] + line*p-> linesize[0] +
(width - 1)*s->pixel_size;
@@ -157,8 +168,57 @@ static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, ui
s->length_table[width] = 0;
skipcount = 0;
+ /* Initial values */
+ lowest_bulk_cost = INT_MAX / 2;
+ lowest_bulk_cost_index = width;
+ sec_lowest_bulk_cost = INT_MAX / 2;
+ sec_lowest_bulk_cost_index = width;
+
+ base_bulk_cost = 1 + s->pixel_size;
+
for (i = width - 1; i >= 0; i--) {
+ int prev_bulk_cost;
+
+ /* If our lowest bulk cost index is too far away, replace it
+ * with the next lowest bulk cost */
+ if (FFMIN(width, i + MAX_RLE_BULK) < lowest_bulk_cost_index) {
+ lowest_bulk_cost = sec_lowest_bulk_cost;
+ lowest_bulk_cost_index = sec_lowest_bulk_cost_index;
+
+ sec_lowest_bulk_cost = INT_MAX / 2;
+ sec_lowest_bulk_cost_index = width;
+ }
+
+ /* Deal with the first pixel's bulk cost */
+ if (!i) {
+ base_bulk_cost++;
+ lowest_bulk_cost++;
+ sec_lowest_bulk_cost++;
+ }
+
+ /* Look at the bulk cost of the previous loop and see if it is
+ * a new lower bulk cost */
+ prev_bulk_cost = s->length_table[i + 1] + base_bulk_cost;
+ if (prev_bulk_cost <= sec_lowest_bulk_cost) {
+ /* If it's lower than the 2nd lowest, then it may be lower
+ * than the lowest */
+ if (prev_bulk_cost <= lowest_bulk_cost) {
+
+ /* If we have found a new lowest bulk cost,
+ * then the 2nd lowest bulk cost is now farther than the
+ * lowest bulk cost, and will never be used */
+ sec_lowest_bulk_cost = INT_MAX / 2;
+
+ lowest_bulk_cost = prev_bulk_cost;
+ lowest_bulk_cost_index = i + 1;
+ } else {
+ /* Then it must be the 2nd lowest bulk cost */
+ sec_lowest_bulk_cost = prev_bulk_cost;
+ sec_lowest_bulk_cost_index = i + 1;
+ }
+ }
+
if (!s->avctx->coded_frame->key_frame && !memcmp(this_line, prev_line, s->pixel_size))
skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP);
else
@@ -194,31 +254,22 @@ static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, ui
}
else {
/* We cannot do neither skip nor repeat
- * thus we search for the best bulk copy to do */
-
- int limit = FFMIN(width - i, MAX_RLE_BULK);
+ * thus we use the best bulk copy */
- temp_cost = 1 + s->pixel_size + !i;
- total_bulk_cost = INT_MAX;
+ s->length_table[i] = lowest_bulk_cost;
+ s->rlecode_table[i] = lowest_bulk_cost_index - i;
- for (j = 1; j <= limit; j++) {
- if (s->length_table[i + j] + temp_cost < total_bulk_cost) {
- /* We have found a better bulk copy ... */
- total_bulk_cost = s->length_table[i + j] + temp_cost;
- bulkcount = j;
- }
- temp_cost += s->pixel_size;
- }
-
- s->length_table[i] = total_bulk_cost;
- s->rlecode_table[i] = bulkcount;
}
+ /* These bulk costs increase every iteration */
+ lowest_bulk_cost += s->pixel_size;
+ sec_lowest_bulk_cost += s->pixel_size;
+
this_line -= s->pixel_size;
prev_line -= s->pixel_size;
}
- /* Good ! Now we have the best sequence for this line, let's ouput it */
+ /* Good ! Now we have the best sequence for this line, let's output it */
/* We do a special case for the first pixel so that we avoid testing it in
* the whole loop */
@@ -243,12 +294,28 @@ static void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, ui
}
else if (rlecode > 0) {
/* bulk copy */
- bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size);
+ if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
+ int j;
+ // QT grayscale colorspace has 0=white and 255=black, we will
+ // ignore the palette that is included in the AVFrame because
+ // AV_PIX_FMT_GRAY8 has defined color mapping
+ for (j = 0; j < rlecode*s->pixel_size; ++j)
+ bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
+ } else {
+ bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size);
+ }
i += rlecode;
}
else {
/* repeat the bits */
- bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size);
+ if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
+ int j;
+ // QT grayscale colorspace has 0=white and 255=black, ...
+ for (j = 0; j < s->pixel_size; ++j)
+ bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff);
+ } else {
+ bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size);
+ }
i -= rlecode;
}
}
@@ -264,7 +331,7 @@ static int encode_frame(QtrleEncContext *s, const AVFrame *p, uint8_t *buf)
uint8_t *orig_buf = buf;
if (!s->avctx->coded_frame->key_frame) {
- unsigned line_size = s->avctx->width * s->pixel_size;
+ unsigned line_size = s->logical_width * s->pixel_size;
for (start_line = 0; start_line < s->avctx->height; start_line++)
if (memcmp(p->data[0] + start_line*p->linesize[0],
s->previous_frame.data[0] + start_line*s->previous_frame.linesize[0],
@@ -304,11 +371,8 @@ static int qtrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
AVFrame * const p = avctx->coded_frame;
int ret;
- if ((ret = ff_alloc_packet(pkt, s->max_buf_size)) < 0) {
- /* Upper bound check for compressed data */
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", s->max_buf_size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, s->max_buf_size)) < 0)
return ret;
- }
if (avctx->gop_size == 0 || (s->avctx->frame_number % avctx->gop_size) == 0) {
/* I-Frame */
@@ -343,6 +407,6 @@ AVCodec ff_qtrle_encoder = {
.encode2 = qtrle_encode_frame,
.close = qtrle_encode_end,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_NONE
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
},
};
diff --git a/libavcodec/r210dec.c b/libavcodec/r210dec.c
index 6adaac0d35..fc9e7e5ce5 100644
--- a/libavcodec/r210dec.c
+++ b/libavcodec/r210dec.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Doeffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,11 @@
static av_cold int decode_init(AVCodecContext *avctx)
{
- avctx->pix_fmt = AV_PIX_FMT_RGB48;
+ if ((avctx->codec_tag & 0xFFFFFF) == MKTAG('r', '1', '0', 0)) {
+ avctx->pix_fmt = AV_PIX_FMT_BGR48;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_RGB48;
+ }
avctx->bits_per_raw_sample = 10;
return 0;
@@ -39,8 +43,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int h, w, ret;
AVFrame *pic = data;
const uint32_t *src = (const uint32_t *)avpkt->data;
- int aligned_width = FFALIGN(avctx->width, 64);
+ int aligned_width = FFALIGN(avctx->width,
+ avctx->codec_id == AV_CODEC_ID_R10K ? 1 : 64);
uint8_t *dst_line;
+ int r10 = (avctx->codec_tag & 0xFFFFFF) == MKTAG('r', '1', '0', 0);
+ int le = avctx->codec_tag == MKTAG('R', '1', '0', 'k') &&
+ avctx->extradata_size >= 12 && !memcmp(&avctx->extradata[4], "DpxE", 4) &&
+ !avctx->extradata[11];
if (avpkt->size < 4 * aligned_width * avctx->height) {
av_log(avctx, AV_LOG_ERROR, "packet too small\n");
@@ -57,14 +66,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
for (h = 0; h < avctx->height; h++) {
uint16_t *dst = (uint16_t *)dst_line;
for (w = 0; w < avctx->width; w++) {
- uint32_t pixel = av_be2ne32(*src++);
+ uint32_t pixel;
uint16_t r, g, b;
- if (avctx->codec_id==AV_CODEC_ID_R210) {
+ if (avctx->codec_id == AV_CODEC_ID_AVRP || r10 || le) {
+ pixel = av_le2ne32(*src++);
+ } else {
+ pixel = av_be2ne32(*src++);
+ }
+ if (avctx->codec_id == AV_CODEC_ID_R210 || r10) {
b = pixel << 6;
g = (pixel >> 4) & 0xffc0;
r = (pixel >> 14) & 0xffc0;
} else {
- b = pixel << 4;
+ b = (pixel << 4) & 0xffc0;
g = (pixel >> 6) & 0xffc0;
r = (pixel >> 16) & 0xffc0;
}
@@ -103,3 +117,14 @@ AVCodec ff_r10k_decoder = {
.capabilities = CODEC_CAP_DR1,
};
#endif
+#if CONFIG_AVRP_DECODER
+AVCodec ff_avrp_decoder = {
+ .name = "avrp",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVRP,
+ .init = decode_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
diff --git a/libavcodec/r210enc.c b/libavcodec/r210enc.c
new file mode 100644
index 0000000000..b7d5a07deb
--- /dev/null
+++ b/libavcodec/r210enc.c
@@ -0,0 +1,123 @@
+/*
+ * R210 encoder
+ *
+ * Copyright (c) 2012 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
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "bytestream.h"
+
+static av_cold int encode_init(AVCodecContext *avctx)
+{
+ avctx->coded_frame = av_frame_alloc();
+
+ if (!avctx->coded_frame)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ int i, j, ret;
+ int aligned_width = FFALIGN(avctx->width,
+ avctx->codec_id == AV_CODEC_ID_R10K ? 1 : 64);
+ int pad = (aligned_width - avctx->width) * 4;
+ uint8_t *src_line;
+ uint8_t *dst;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, 4 * aligned_width * avctx->height)) < 0)
+ return ret;
+
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ src_line = pic->data[0];
+ dst = pkt->data;
+
+ for (i = 0; i < avctx->height; i++) {
+ uint16_t *src = (uint16_t *)src_line;
+ for (j = 0; j < avctx->width; j++) {
+ uint32_t pixel;
+ uint16_t r = *src++ >> 6;
+ uint16_t g = *src++ >> 6;
+ uint16_t b = *src++ >> 6;
+ if (avctx->codec_id == AV_CODEC_ID_R210)
+ pixel = (r << 20) | (g << 10) | b;
+ else
+ pixel = (r << 22) | (g << 12) | (b << 2);
+ if (avctx->codec_id == AV_CODEC_ID_AVRP)
+ bytestream_put_le32(&dst, pixel);
+ else
+ bytestream_put_be32(&dst, pixel);
+ }
+ memset(dst, 0, pad);
+ dst += pad;
+ src_line += pic->linesize[0];
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+#if CONFIG_R210_ENCODER
+AVCodec ff_r210_encoder = {
+ .name = "r210",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed RGB 10-bit"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_R210,
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE },
+};
+#endif
+#if CONFIG_R10K_ENCODER
+AVCodec ff_r10k_encoder = {
+ .name = "r10k",
+ .long_name = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_R10K,
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE },
+};
+#endif
+#if CONFIG_AVRP_ENCODER
+AVCodec ff_avrp_encoder = {
+ .name = "avrp",
+ .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AVRP,
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE },
+};
+#endif
diff --git a/libavcodec/ra144.c b/libavcodec/ra144.c
index 355baddf33..696a49e7ab 100644
--- a/libavcodec/ra144.c
+++ b/libavcodec/ra144.c
@@ -1,21 +1,21 @@
/*
* Real Audio 1.0 (14.4K)
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -1566,8 +1566,15 @@ int ff_eval_refl(int *refl, const int16_t *coefs, AVCodecContext *avctx)
if (!b)
b = -2;
- for (j=0; j <= i; j++)
- bp1[j] = ((bp2[j] - ((refl[i+1] * bp2[i-j]) >> 12)) * (0x1000000 / b)) >> 12;
+ b = 0x1000000 / b;
+ for (j=0; j <= i; j++) {
+#if CONFIG_FTRAPV
+ int a = bp2[j] - ((refl[i+1] * bp2[i-j]) >> 12);
+ if((int)(a*(unsigned)b) != a*(int64_t)b)
+ return 1;
+#endif
+ bp1[j] = ((bp2[j] - ((refl[i+1] * bp2[i-j]) >> 12)) * b) >> 12;
+ }
if ((unsigned) bp1[i] + 0x1000 > 0x1fff)
return 1;
@@ -1674,12 +1681,9 @@ unsigned int ff_rescale_rms(unsigned int rms, unsigned int energy)
}
/** inverse root mean square */
-int ff_irms(const int16_t *data)
+int ff_irms(AudioDSPContext *adsp, const int16_t *data)
{
- unsigned int i, sum = 0;
-
- for (i=0; i < BLOCKSIZE; i++)
- sum += data[i] * data[i];
+ unsigned int sum = adsp->scalarproduct_int16(data, data, BLOCKSIZE);
if (sum == 0)
return 0; /* OOPS - division by zero */
@@ -1687,18 +1691,17 @@ int ff_irms(const int16_t *data)
return 0x20000000 / (ff_t_sqrt(sum) >> 8);
}
-void ff_subblock_synthesis(RA144Context *ractx, const uint16_t *lpc_coefs,
+void ff_subblock_synthesis(RA144Context *ractx, const int16_t *lpc_coefs,
int cba_idx, int cb1_idx, int cb2_idx,
int gval, int gain)
{
- uint16_t buffer_a[BLOCKSIZE];
- uint16_t *block;
+ int16_t *block;
int m[3];
if (cba_idx) {
cba_idx += BLOCKSIZE/2 - 1;
- ff_copy_and_dup(buffer_a, ractx->adapt_cb, cba_idx);
- m[0] = (ff_irms(buffer_a) * gval) >> 12;
+ ff_copy_and_dup(ractx->buffer_a, ractx->adapt_cb, cba_idx);
+ m[0] = (ff_irms(&ractx->adsp, ractx->buffer_a) * gval) >> 12;
} else {
m[0] = 0;
}
@@ -1709,7 +1712,7 @@ void ff_subblock_synthesis(RA144Context *ractx, const uint16_t *lpc_coefs,
block = ractx->adapt_cb + BUFFERSIZE - BLOCKSIZE;
- add_wav(block, gain, cba_idx, m, cba_idx? buffer_a: NULL,
+ add_wav(block, gain, cba_idx, m, cba_idx? ractx->buffer_a: NULL,
ff_cb1_vects[cb1_idx], ff_cb2_vects[cb2_idx]);
memcpy(ractx->curr_sblock, ractx->curr_sblock + BLOCKSIZE,
diff --git a/libavcodec/ra144.h b/libavcodec/ra144.h
index 81d6964abc..df747905b3 100644
--- a/libavcodec/ra144.h
+++ b/libavcodec/ra144.h
@@ -1,21 +1,21 @@
/*
* Real Audio 1.0 (14.4K)
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,16 +25,18 @@
#include <stdint.h>
#include "lpc.h"
#include "audio_frame_queue.h"
+#include "audiodsp.h"
#define NBLOCKS 4 ///< number of subblocks within a block
#define BLOCKSIZE 40 ///< subblock size in 16-bit words
#define BUFFERSIZE 146 ///< the size of the adaptive codebook
#define FIXED_CB_SIZE 128 ///< size of fixed codebooks
-#define FRAMESIZE 20 ///< size of encoded frame
+#define FRAME_SIZE 20 ///< size of encoded frame
#define LPC_ORDER 10 ///< order of LPC filter
typedef struct RA144Context {
AVCodecContext *avctx;
+ AudioDSPContext adsp;
LPCContext lpc_ctx;
AudioFrameQueue afq;
int last_frame;
@@ -56,7 +58,9 @@ typedef struct RA144Context {
/** Adaptive codebook, its size is two units bigger to avoid a
* buffer overflow. */
- uint16_t adapt_cb[146+2];
+ int16_t adapt_cb[146+2];
+
+ DECLARE_ALIGNED(16, int16_t, buffer_a)[FFALIGN(BLOCKSIZE,16)];
} RA144Context;
void ff_copy_and_dup(int16_t *target, const int16_t *source, int offset);
@@ -68,8 +72,8 @@ unsigned int ff_rms(const int *data);
int ff_interp(RA144Context *ractx, int16_t *out, int a, int copyold,
int energy);
unsigned int ff_rescale_rms(unsigned int rms, unsigned int energy);
-int ff_irms(const int16_t *data);
-void ff_subblock_synthesis(RA144Context *ractx, const uint16_t *lpc_coefs,
+int ff_irms(AudioDSPContext *adsp, const int16_t *data/*align 16*/);
+void ff_subblock_synthesis(RA144Context *ractx, const int16_t *lpc_coefs,
int cba_idx, int cb1_idx, int cb2_idx,
int gval, int gain);
diff --git a/libavcodec/ra144dec.c b/libavcodec/ra144dec.c
index 3be3877f31..29c78229bb 100644
--- a/libavcodec/ra144dec.c
+++ b/libavcodec/ra144dec.c
@@ -5,20 +5,20 @@
* Copyright (c) 2003 Nick Kurshev
* Based on public domain decoder at http://www.honeypot.net/audio
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@ static av_cold int ra144_decode_init(AVCodecContext * avctx)
RA144Context *ractx = avctx->priv_data;
ractx->avctx = avctx;
+ ff_audiodsp_init(&ractx->adsp);
ractx->lpc_coef[0] = ractx->lpc_tables[0];
ractx->lpc_coef[1] = ractx->lpc_tables[1];
@@ -45,7 +46,7 @@ static av_cold int ra144_decode_init(AVCodecContext * avctx)
return 0;
}
-static void do_output_subblock(RA144Context *ractx, const uint16_t *lpc_coefs,
+static void do_output_subblock(RA144Context *ractx, const int16_t *lpc_coefs,
int gval, GetBitContext *gb)
{
int cba_idx = get_bits(gb, 7); // index of the adaptive CB, 0 if none
@@ -66,7 +67,7 @@ static int ra144_decode_frame(AVCodecContext * avctx, void *data,
int buf_size = avpkt->size;
static const uint8_t sizes[LPC_ORDER] = {6, 5, 5, 4, 4, 3, 3, 3, 3, 2};
unsigned int refl_rms[NBLOCKS]; // RMS of the reflection coefficients
- uint16_t block_coefs[NBLOCKS][LPC_ORDER]; // LPC coefficients of each sub-block
+ int16_t block_coefs[NBLOCKS][LPC_ORDER]; // LPC coefficients of each sub-block
unsigned int lpc_refl[LPC_ORDER]; // LPC reflection coefficients of the frame
int i, j;
int ret;
@@ -76,7 +77,7 @@ static int ra144_decode_frame(AVCodecContext * avctx, void *data,
RA144Context *ractx = avctx->priv_data;
GetBitContext gb;
- if (buf_size < FRAMESIZE) {
+ if (buf_size < FRAME_SIZE) {
av_log(avctx, AV_LOG_ERROR,
"Frame too small (%d bytes). Truncated file?\n", buf_size);
*got_frame_ptr = 0;
@@ -85,13 +86,11 @@ static int ra144_decode_frame(AVCodecContext * avctx, void *data,
/* get output buffer */
frame->nb_samples = NBLOCKS * BLOCKSIZE;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t *)frame->data[0];
- init_get_bits(&gb, buf, FRAMESIZE * 8);
+ init_get_bits8(&gb, buf, FRAME_SIZE);
for (i = 0; i < LPC_ORDER; i++)
lpc_refl[i] = ff_lpc_refl_cb[i][get_bits(&gb, sizes[i])];
@@ -124,7 +123,7 @@ static int ra144_decode_frame(AVCodecContext * avctx, void *data,
*got_frame_ptr = 1;
- return FRAMESIZE;
+ return FRAME_SIZE;
}
AVCodec ff_ra_144_decoder = {
diff --git a/libavcodec/ra144enc.c b/libavcodec/ra144enc.c
index fd04766561..3ad3f4ea96 100644
--- a/libavcodec/ra144enc.c
+++ b/libavcodec/ra144enc.c
@@ -2,20 +2,20 @@
* Real Audio 1.0 (14.4K) encoder
* Copyright (c) 2010 Francesco Lavra <francescolavra@interfree.it>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,7 +35,6 @@
#include "put_bits.h"
#include "ra144.h"
-
static av_cold int ra144_encode_close(AVCodecContext *avctx)
{
RA144Context *ractx = avctx->priv_data;
@@ -62,6 +61,7 @@ static av_cold int ra144_encode_init(AVCodecContext * avctx)
ractx->lpc_coef[0] = ractx->lpc_tables[0];
ractx->lpc_coef[1] = ractx->lpc_tables[1];
ractx->avctx = avctx;
+ ff_audiodsp_init(&ractx->adsp);
ret = ff_lpc_init(&ractx->lpc_ctx, avctx->frame_size, LPC_ORDER,
FF_LPC_TYPE_LEVINSON);
if (ret < 0)
@@ -198,8 +198,8 @@ static void create_adapt_vect(float *vect, const int16_t *cb, int lag)
static int adaptive_cb_search(const int16_t *adapt_cb, float *work,
const float *coefs, float *data)
{
- int i, best_vect;
- float score, gain, best_score, best_gain;
+ int i, av_uninit(best_vect);
+ float score, gain, best_score, av_uninit(best_gain);
float exc[BLOCKSIZE];
gain = best_score = 0;
@@ -335,9 +335,9 @@ static void ra144_encode_subblock(RA144Context *ractx,
float data[BLOCKSIZE] = { 0 }, work[LPC_ORDER + BLOCKSIZE];
float coefs[LPC_ORDER];
float zero[BLOCKSIZE], cba[BLOCKSIZE], cb1[BLOCKSIZE], cb2[BLOCKSIZE];
- int16_t cba_vect[BLOCKSIZE];
int cba_idx, cb1_idx, cb2_idx, gain;
- int i, n, m[3];
+ int i, n;
+ unsigned m[3];
float g[3];
float error, best_error;
@@ -373,8 +373,8 @@ static void ra144_encode_subblock(RA144Context *ractx,
*/
memcpy(cba, work + LPC_ORDER, sizeof(cba));
- ff_copy_and_dup(cba_vect, ractx->adapt_cb, cba_idx + BLOCKSIZE / 2 - 1);
- m[0] = (ff_irms(cba_vect) * rms) >> 12;
+ ff_copy_and_dup(ractx->buffer_a, ractx->adapt_cb, cba_idx + BLOCKSIZE / 2 - 1);
+ m[0] = (ff_irms(&ractx->adsp, ractx->buffer_a) * rms) >> 12;
}
fixed_cb_search(work + LPC_ORDER, coefs, data, cba_idx, &cb1_idx, &cb2_idx);
for (i = 0; i < BLOCKSIZE; i++) {
@@ -447,10 +447,8 @@ static int ra144_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
if (ractx->last_frame)
return 0;
- if ((ret = ff_alloc_packet(avpkt, FRAMESIZE))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, FRAME_SIZE)) < 0)
return ret;
- }
/**
* Since the LPC coefficients are calculated on a frame centered over the
@@ -538,7 +536,7 @@ static int ra144_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
ff_af_queue_remove(&ractx->afq, avctx->frame_size, &avpkt->pts,
&avpkt->duration);
- avpkt->size = FRAMESIZE;
+ avpkt->size = FRAME_SIZE;
*got_packet_ptr = 1;
return 0;
}
@@ -556,4 +554,6 @@ AVCodec ff_ra_144_encoder = {
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_SMALL_LAST_FRAME,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16,
AV_SAMPLE_FMT_NONE },
+ .supported_samplerates = (const int[]){ 8000, 0 },
+ .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, 0 },
};
diff --git a/libavcodec/ra288.c b/libavcodec/ra288.c
index a67c6571fd..189d5c51f8 100644
--- a/libavcodec/ra288.c
+++ b/libavcodec/ra288.c
@@ -1,21 +1,21 @@
/*
* RealAudio 2.0 (28.8K)
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@
#define RA288_BLOCKS_PER_FRAME 32
typedef struct RA288Context {
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
DECLARE_ALIGNED(32, float, sp_lpc)[FFALIGN(36, 16)]; ///< LPC coefficients for speech data (spec: A)
DECLARE_ALIGNED(32, float, gain_lpc)[FFALIGN(10, 16)]; ///< LPC coefficients for gain (spec: GB)
@@ -59,6 +59,15 @@ typedef struct RA288Context {
float gain_rec[11];
} RA288Context;
+static av_cold int ra288_decode_close(AVCodecContext *avctx)
+{
+ RA288Context *ractx = avctx->priv_data;
+
+ av_freep(&ractx->fdsp);
+
+ return 0;
+}
+
static av_cold int ra288_decode_init(AVCodecContext *avctx)
{
RA288Context *ractx = avctx->priv_data;
@@ -67,7 +76,14 @@ static av_cold int ra288_decode_init(AVCodecContext *avctx)
avctx->channel_layout = AV_CH_LAYOUT_MONO;
avctx->sample_fmt = AV_SAMPLE_FMT_FLT;
- avpriv_float_dsp_init(&ractx->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ if (avctx->block_align <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported block align\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ ractx->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!ractx->fdsp)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -104,14 +120,14 @@ static void decode(RA288Context *ractx, float gain, int cb_coef)
for (i=0; i < 5; i++)
buffer[i] = codetable[cb_coef][i] * sumsum;
- sum = avpriv_scalarproduct_float_c(buffer, buffer, 5) * ((1 << 24) / 5.0);
+ sum = avpriv_scalarproduct_float_c(buffer, buffer, 5);
- sum = FFMAX(sum, 1);
+ sum = FFMAX(sum, 5.0 / (1<<24));
/* shift and store */
memmove(gain_block, gain_block + 1, 9 * sizeof(*gain_block));
- gain_block[9] = 10 * log10(sum) - 32;
+ gain_block[9] = 10 * log10(sum) + (10*log10(((1<<24)/5.)) - 32);
ff_celp_lp_synthesis_filterf(block, ractx->sp_lpc, buffer, 5, 36);
}
@@ -139,7 +155,9 @@ static void do_hybrid_window(RA288Context *ractx,
MAX_BACKWARD_FILTER_LEN +
MAX_BACKWARD_FILTER_NONREC, 16)]);
- ractx->fdsp.vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16));
+ av_assert2(order>=0);
+
+ ractx->fdsp->vector_fmul(work, window, hist, FFALIGN(order + n + non_rec, 16));
convolve(buffer1, work + order , n , order);
convolve(buffer2, work + order + n, non_rec, order);
@@ -166,7 +184,7 @@ static void backward_filter(RA288Context *ractx,
do_hybrid_window(ractx, order, n, non_rec, temp, hist, rec, window);
if (!compute_lpc_coefs(temp, order, lpc, 0, 1, 1))
- ractx->fdsp.vector_fmul(lpc, lpc, tab, FFALIGN(order, 16));
+ ractx->fdsp->vector_fmul(lpc, lpc, tab, FFALIGN(order, 16));
memmove(hist, hist + n, move_size*sizeof(*hist));
}
@@ -191,13 +209,11 @@ static int ra288_decode_frame(AVCodecContext * avctx, void *data,
/* get output buffer */
frame->nb_samples = RA288_BLOCK_SIZE * RA288_BLOCKS_PER_FRAME;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
out = (float *)frame->data[0];
- init_get_bits(&gb, buf, avctx->block_align * 8);
+ init_get_bits8(&gb, buf, avctx->block_align);
for (i=0; i < RA288_BLOCKS_PER_FRAME; i++) {
float gain = amptable[get_bits(&gb, 3)];
@@ -230,5 +246,6 @@ AVCodec ff_ra_288_decoder = {
.priv_data_size = sizeof(RA288Context),
.init = ra288_decode_init,
.decode = ra288_decode_frame,
+ .close = ra288_decode_close,
.capabilities = CODEC_CAP_DR1,
};
diff --git a/libavcodec/ra288.h b/libavcodec/ra288.h
index 9f4beebbcf..d30e49a0e3 100644
--- a/libavcodec/ra288.h
+++ b/libavcodec/ra288.h
@@ -1,21 +1,21 @@
/*
* RealAudio 2.0 (28.8K)
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/ralf.c b/libavcodec/ralf.c
index ebcdf6fbe3..8a319ac824 100644
--- a/libavcodec/ralf.c
+++ b/libavcodec/ralf.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -461,10 +461,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr,
}
frame->nb_samples = ctx->max_frame_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Me fail get_buffer()? That's unpossible!\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples0 = (int16_t *)frame->data[0];
samples1 = (int16_t *)frame->data[1];
diff --git a/libavcodec/ralfdata.h b/libavcodec/ralfdata.h
index 83eb970f5a..9a84e45a32 100644
--- a/libavcodec/ralfdata.h
+++ b/libavcodec/ralfdata.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rangecoder.c b/libavcodec/rangecoder.c
index af0a8c009e..29fb909668 100644
--- a/libavcodec/rangecoder.c
+++ b/libavcodec/rangecoder.c
@@ -2,20 +2,20 @@
* Range coder
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@
#include <string.h>
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "rangecoder.h"
#include "bytestream.h"
@@ -55,7 +56,7 @@ av_cold void ff_init_range_decoder(RangeCoder *c, const uint8_t *buf,
/* cast to avoid compiler warning */
ff_init_range_encoder(c, (uint8_t *)buf, buf_size);
- c->low = bytestream_get_be16(&c->bytestream);
+ c->low = bytestream_get_be16((const uint8_t **)&c->bytestream);
}
void ff_build_rac_states(RangeCoder *c, int factor, int max_p)
@@ -107,8 +108,8 @@ int ff_rac_terminate(RangeCoder *c)
c->range = 0xFF;
renorm_encoder(c);
- assert(c->low == 0);
- assert(c->range >= 0x100);
+ av_assert1(c->low == 0);
+ av_assert1(c->range >= 0x100);
return c->bytestream - c->bytestream_start;
}
@@ -119,11 +120,12 @@ int ff_rac_terminate(RangeCoder *c)
#include "libavutil/lfg.h"
#include "libavutil/log.h"
+static uint8_t b[9 * SIZE];
+static uint8_t r[9 * SIZE];
+
int main(void)
{
RangeCoder c;
- uint8_t b[9 * SIZE];
- uint8_t r[9 * SIZE];
int i;
uint8_t state[10];
AVLFG prng;
diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h
index 4c88169790..d36fbd7c54 100644
--- a/libavcodec/rangecoder.h
+++ b/libavcodec/rangecoder.h
@@ -2,20 +2,20 @@
* Range coder
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,9 +28,9 @@
#define AVCODEC_RANGECODER_H
#include <stdint.h>
-#include <assert.h>
#include "libavutil/common.h"
+#include "libavutil/avassert.h"
typedef struct RangeCoder {
int low;
@@ -86,9 +86,9 @@ static inline void put_rac(RangeCoder *c, uint8_t *const state, int bit)
{
int range1 = (c->range * (*state)) >> 8;
- assert(*state);
- assert(range1 < c->range);
- assert(range1 > 0);
+ av_assert2(*state);
+ av_assert2(range1 < c->range);
+ av_assert2(range1 > 0);
if (!bit) {
c->range -= range1;
*state = c->zero_state[*state];
diff --git a/libavcodec/ratecontrol.c b/libavcodec/ratecontrol.c
index 620c854ad4..4eb363013c 100644
--- a/libavcodec/ratecontrol.c
+++ b/libavcodec/ratecontrol.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,9 +33,6 @@
#include "mpegvideo.h"
#include "libavutil/eval.h"
-#undef NDEBUG // Always check asserts, the speed effect is far too small to disable them.
-#include <assert.h>
-
#ifndef M_E
#define M_E 2.718281828
#endif
@@ -48,7 +45,7 @@ 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:%d var:%d icount:%d skipcount:%d hbits:%d;\n",
+ "fcode:%d bcode:%d mc-var:%"PRId64" var:%"PRId64" icount:%d skipcount:%d hbits:%d;\n",
s->current_picture_ptr->f->display_picture_number,
s->current_picture_ptr->f->coded_picture_number,
s->pict_type,
@@ -65,6 +62,11 @@ void ff_write_pass1_stats(MpegEncContext *s)
s->header_bits);
}
+static double get_fps(AVCodecContext *avctx)
+{
+ return 1.0 / av_q2d(avctx->time_base) / FFMAX(avctx->ticks_per_frame, 1);
+}
+
static inline double qp2bits(RateControlEntry *rce, double qp)
{
if (qp <= 0.0) {
@@ -126,6 +128,13 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
};
emms_c();
+ if (!s->avctx->rc_max_available_vbv_use && s->avctx->rc_buffer_size) {
+ if (s->avctx->rc_max_rate) {
+ s->avctx->rc_max_available_vbv_use = av_clipf(s->avctx->rc_max_rate/(s->avctx->rc_buffer_size*get_fps(s->avctx)), 1.0/3, 1.0);
+ } else
+ s->avctx->rc_max_available_vbv_use = 1.0;
+ }
+
res = av_expr_parse(&rcc->rc_eq_eval,
s->rc_eq ? s->rc_eq : "tex^qComp",
const_names, func1_names, func1,
@@ -149,6 +158,8 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
rcc->last_qscale_for[i] = FF_QP2LAMBDA * 5;
}
rcc->buffer_index = s->avctx->rc_initial_buffer_occupancy;
+ if (!rcc->buffer_index)
+ rcc->buffer_index = s->avctx->rc_buffer_size * 3 / 4;
if (s->avctx->flags & CODEC_FLAG_PASS2) {
int i;
@@ -162,6 +173,8 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
if (i <= 0 || i >= INT_MAX / sizeof(RateControlEntry))
return -1;
rcc->entry = av_mallocz(i * sizeof(RateControlEntry));
+ if (!rcc->entry)
+ return AVERROR(ENOMEM);
rcc->num_entries = i;
/* init all to skipped p frames
@@ -190,11 +203,11 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
}
e = sscanf(p, " in:%d ", &picture_number);
- assert(picture_number >= 0);
- assert(picture_number < rcc->num_entries);
+ av_assert0(picture_number >= 0);
+ 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:%d var:%d 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 skipcount:%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,
@@ -277,7 +290,7 @@ av_cold int ff_rate_control_init(MpegEncContext *s)
get_qscale(s, &rce, rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum, i);
// FIXME misbehaves a little for variable fps
- rcc->pass1_wanted_bits += s->bit_rate / (1 / av_q2d(s->avctx->time_base));
+ rcc->pass1_wanted_bits += s->bit_rate / get_fps(s->avctx);
}
}
}
@@ -302,7 +315,7 @@ av_cold void ff_rate_control_uninit(MpegEncContext *s)
int ff_vbv_update(MpegEncContext *s, int frame_size)
{
RateControlContext *rcc = &s->rc_context;
- const double fps = 1 / av_q2d(s->avctx->time_base);
+ const double fps = get_fps(s->avctx);
const int buffer_size = s->avctx->rc_buffer_size;
const double min_rate = s->avctx->rc_min_rate / fps;
const double max_rate = s->avctx->rc_max_rate / fps;
@@ -316,6 +329,9 @@ int ff_vbv_update(MpegEncContext *s, int frame_size)
rcc->buffer_index -= frame_size;
if (rcc->buffer_index < 0) {
av_log(s->avctx, AV_LOG_ERROR, "rc buffer underflow\n");
+ if (frame_size > max_rate && s->qscale == s->avctx->qmax) {
+ av_log(s->avctx, AV_LOG_ERROR, "max bitrate possibly too small or try trellis with large lmax or increase qmax\n");
+ }
rcc->buffer_index = 0;
}
@@ -464,7 +480,7 @@ static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pic
int qmin = s->lmin;
int qmax = s->lmax;
- assert(qmin <= qmax);
+ av_assert0(qmin <= qmax);
switch (pict_type) {
case AV_PICTURE_TYPE_B:
@@ -492,7 +508,7 @@ static double modify_qscale(MpegEncContext *s, RateControlEntry *rce,
{
RateControlContext *rcc = &s->rc_context;
const double buffer_size = s->avctx->rc_buffer_size;
- const double fps = 1 / av_q2d(s->avctx->time_base);
+ const double fps = get_fps(s->avctx);
const double min_rate = s->avctx->rc_min_rate / fps;
const double max_rate = s->avctx->rc_max_rate / fps;
const int pict_type = rce->new_pict_type;
@@ -738,7 +754,7 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
RateControlEntry local_rce, *rce;
double bits;
double rate_factor;
- int var;
+ int64_t var;
const int pict_type = s->pict_type;
Picture * const pic = &s->current_picture;
emms_c();
@@ -751,19 +767,25 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
get_qminmax(&qmin, &qmax, s, pict_type);
- fps = 1 / av_q2d(s->avctx->time_base);
+ fps = get_fps(s->avctx);
/* update predictors */
if (picture_number > 2 && !dry_run) {
- const int last_var = s->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum
- : rcc->last_mc_mb_var_sum;
+ const int64_t last_var =
+ s->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum
+ : rcc->last_mc_mb_var_sum;
+ av_assert1(s->frame_bits >= s->stuffing_bits);
update_predictor(&rcc->pred[s->last_pict_type],
rcc->last_qscale,
- sqrt(last_var), s->frame_bits);
+ sqrt(last_var),
+ s->frame_bits - s->stuffing_bits);
}
if (s->avctx->flags & CODEC_FLAG_PASS2) {
- assert(picture_number >= 0);
- assert(picture_number < rcc->num_entries);
+ av_assert0(picture_number >= 0);
+ if (picture_number >= rcc->num_entries) {
+ av_log(s, AV_LOG_ERROR, "Input is longer than 2-pass log file\n");
+ return -1;
+ }
rce = &rcc->entry[picture_number];
wanted_bits = rce->expected_bits;
} else {
@@ -794,10 +816,10 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
short_term_q = 0; /* avoid warning */
if (s->avctx->flags & CODEC_FLAG_PASS2) {
if (pict_type != AV_PICTURE_TYPE_I)
- assert(pict_type == rce->new_pict_type);
+ av_assert0(pict_type == rce->new_pict_type);
q = rce->new_qscale / br_compensation;
- ff_dlog(s, "%f %f %f last:%d var:%d type:%d//\n", q, rce->new_qscale,
+ ff_dlog(s, "%f %f %f last:%d var:%"PRId64" type:%d//\n", q, rce->new_qscale,
br_compensation, s->frame_bits, var, pict_type);
} else {
rce->pict_type =
@@ -826,7 +848,6 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
rcc->mv_bits_sum[pict_type] += rce->mv_bits;
rcc->frame_count[pict_type]++;
- bits = rce->i_tex_bits + rce->p_tex_bits;
rate_factor = rcc->pass1_wanted_bits /
rcc->pass1_rc_eq_output_sum * br_compensation;
@@ -834,9 +855,9 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
if (q < 0)
return -1;
- assert(q > 0.0);
+ av_assert0(q > 0.0);
q = get_diff_limited_q(s, rce, q);
- assert(q > 0.0);
+ av_assert0(q > 0.0);
// FIXME type dependent blur like in 2-pass
if (pict_type == AV_PICTURE_TYPE_P || s->intra_only) {
@@ -847,19 +868,19 @@ float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run)
rcc->short_term_qcount++;
q = short_term_q = rcc->short_term_qsum / rcc->short_term_qcount;
}
- assert(q > 0.0);
+ av_assert0(q > 0.0);
q = modify_qscale(s, rce, q, picture_number);
rcc->pass1_wanted_bits += s->bit_rate / fps;
- assert(q > 0.0);
+ av_assert0(q > 0.0);
}
if (s->avctx->debug & FF_DEBUG_RC) {
av_log(s->avctx, AV_LOG_DEBUG,
"%c qp:%d<%2.1f<%d %d want:%d total:%d comp:%f st_q:%2.2f "
- "size:%d var:%d/%d br:%d fps:%d\n",
+ "size:%d var:%"PRId64"/%"PRId64" br:%d fps:%d\n",
av_get_picture_type_char(pict_type),
qmin, q, qmax, picture_number,
(int)wanted_bits / 1000, (int)s->total_bits / 1000,
@@ -894,7 +915,7 @@ static int init_pass2(MpegEncContext *s)
RateControlContext *rcc = &s->rc_context;
AVCodecContext *a = s->avctx;
int i, toobig;
- double fps = 1 / av_q2d(s->avctx->time_base);
+ double fps = get_fps(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;
@@ -903,7 +924,7 @@ static int init_pass2(MpegEncContext *s)
double rate_factor = 0;
double step;
const int filter_size = (int)(a->qblur * 4) | 1;
- double expected_bits;
+ double expected_bits = 0; // init to silence gcc warning
double *qscale, *blurred_qscale, qscale_sum;
/* find complexity & const_bits & decide the pict_types */
@@ -930,8 +951,13 @@ static int init_pass2(MpegEncContext *s)
return -1;
}
- qscale = av_malloc(sizeof(double) * rcc->num_entries);
- blurred_qscale = av_malloc(sizeof(double) * rcc->num_entries);
+ qscale = av_malloc_array(rcc->num_entries, sizeof(double));
+ blurred_qscale = av_malloc_array(rcc->num_entries, sizeof(double));
+ if (!qscale || !blurred_qscale) {
+ av_free(qscale);
+ av_free(blurred_qscale);
+ return AVERROR(ENOMEM);
+ }
toobig = 0;
for (step = 256 * 256; step > 0.0000001; step *= 0.5) {
@@ -947,9 +973,15 @@ static int init_pass2(MpegEncContext *s)
qscale[i] = get_qscale(s, &rcc->entry[i], rate_factor, i);
rcc->last_qscale_for[rce->pict_type] = qscale[i];
}
- assert(filter_size % 2 == 1);
+ av_assert0(filter_size % 2 == 1);
/* 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];
+
+ qscale[i] = get_diff_limited_q(s, rce, qscale[i]);
+ }
+
for (i = rcc->num_entries - 1; i >= 0; i--) {
RateControlEntry *rce = &rcc->entry[i];
@@ -1013,7 +1045,7 @@ static int init_pass2(MpegEncContext *s)
qscale_sum += av_clip(rcc->entry[i].new_qscale / FF_QP2LAMBDA,
s->avctx->qmin, s->avctx->qmax);
}
- assert(toobig <= 40);
+ av_assert0(toobig <= 40);
av_log(s->avctx, AV_LOG_DEBUG,
"[lavc rc] requested bitrate: %d bps expected bitrate: %d bps\n",
s->bit_rate,
diff --git a/libavcodec/ratecontrol.h b/libavcodec/ratecontrol.h
index 63ebeb2586..eeb4bb96c0 100644
--- a/libavcodec/ratecontrol.h
+++ b/libavcodec/ratecontrol.h
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,8 +49,8 @@ typedef struct RateControlEntry{
uint64_t expected_bits;
int new_pict_type;
float new_qscale;
- int mc_mb_var_sum;
- int mb_var_sum;
+ int64_t mc_mb_var_sum;
+ int64_t mb_var_sum;
int i_count;
int skip_count;
int f_code;
@@ -71,8 +71,8 @@ typedef struct RateControlContext{
double pass1_wanted_bits; ///< bits which should have been outputed by the pass1 code (including complexity init)
double last_qscale;
double last_qscale_for[5]; ///< last qscale for a specific pict type, used for max_diff & ipb factor stuff
- int last_mc_mb_var_sum;
- int last_mb_var_sum;
+ int64_t last_mc_mb_var_sum;
+ int64_t last_mb_var_sum;
uint64_t i_cplx_sum[5];
uint64_t p_cplx_sum[5];
uint64_t mv_bits_sum[5];
diff --git a/libavcodec/raw.c b/libavcodec/raw.c
index 541ef7aa3a..62ad338b9f 100644
--- a/libavcodec/raw.c
+++ b/libavcodec/raw.c
@@ -2,20 +2,20 @@
* Raw Video Codec
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,6 +65,7 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'u', 'p') },
{ AV_PIX_FMT_UYVY422, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */
{ AV_PIX_FMT_UYVY422, MKTAG('a', 'u', 'v', '2') },
+ { AV_PIX_FMT_UYVY422, MKTAG('c', 'y', 'u', 'v') }, /* CYUV is also Creative YUV */
{ AV_PIX_FMT_UYYVYY411, MKTAG('Y', '4', '1', '1') },
{ AV_PIX_FMT_GRAY8, MKTAG('G', 'R', 'E', 'Y') },
{ AV_PIX_FMT_NV12, MKTAG('N', 'V', '1', '2') },
@@ -83,14 +84,18 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_BGR444LE, MKTAG('B', 'G', 'R', 12) },
{ AV_PIX_FMT_RGB444BE, MKTAG(12 , 'B', 'G', 'R') },
{ AV_PIX_FMT_BGR444BE, MKTAG(12 , 'R', 'G', 'B') },
- { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') },
- { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') },
{ AV_PIX_FMT_RGBA64LE, MKTAG('R', 'B', 'A', 64 ) },
{ AV_PIX_FMT_BGRA64LE, MKTAG('B', 'R', 'A', 64 ) },
{ AV_PIX_FMT_RGBA64BE, MKTAG(64 , 'R', 'B', 'A') },
{ AV_PIX_FMT_BGRA64BE, MKTAG(64 , 'B', 'R', 'A') },
+ { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') },
+ { AV_PIX_FMT_RGB0, MKTAG('R', 'G', 'B', 0 ) },
+ { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') },
+ { AV_PIX_FMT_BGR0, MKTAG('B', 'G', 'R', 0 ) },
{ AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') },
+ { AV_PIX_FMT_0BGR, MKTAG( 0 , 'B', 'G', 'R') },
{ AV_PIX_FMT_ARGB, MKTAG('A', 'R', 'G', 'B') },
+ { AV_PIX_FMT_0RGB, MKTAG( 0 , 'R', 'G', 'B') },
{ AV_PIX_FMT_RGB24, MKTAG('R', 'G', 'B', 24 ) },
{ AV_PIX_FMT_BGR24, MKTAG('B', 'G', 'R', 24 ) },
{ AV_PIX_FMT_YUV411P, MKTAG('4', '1', '1', 'P') },
@@ -120,6 +125,18 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_YUV422P10BE, MKTAG(10 , 10 , '3', 'Y') },
{ AV_PIX_FMT_YUV444P10LE, MKTAG('Y', '3', 0 , 10 ) },
{ AV_PIX_FMT_YUV444P10BE, MKTAG(10 , 0 , '3', 'Y') },
+ { AV_PIX_FMT_YUV420P12LE, MKTAG('Y', '3', 11 , 12 ) },
+ { AV_PIX_FMT_YUV420P12BE, MKTAG(12 , 11 , '3', 'Y') },
+ { AV_PIX_FMT_YUV422P12LE, MKTAG('Y', '3', 10 , 12 ) },
+ { AV_PIX_FMT_YUV422P12BE, MKTAG(12 , 10 , '3', 'Y') },
+ { AV_PIX_FMT_YUV444P12LE, MKTAG('Y', '3', 0 , 12 ) },
+ { AV_PIX_FMT_YUV444P12BE, MKTAG(12 , 0 , '3', 'Y') },
+ { AV_PIX_FMT_YUV420P14LE, MKTAG('Y', '3', 11 , 14 ) },
+ { AV_PIX_FMT_YUV420P14BE, MKTAG(14 , 11 , '3', 'Y') },
+ { AV_PIX_FMT_YUV422P14LE, MKTAG('Y', '3', 10 , 14 ) },
+ { AV_PIX_FMT_YUV422P14BE, MKTAG(14 , 10 , '3', 'Y') },
+ { AV_PIX_FMT_YUV444P14LE, MKTAG('Y', '3', 0 , 14 ) },
+ { AV_PIX_FMT_YUV444P14BE, MKTAG(14 , 0 , '3', 'Y') },
{ AV_PIX_FMT_YUV420P16LE, MKTAG('Y', '3', 11 , 16 ) },
{ AV_PIX_FMT_YUV420P16BE, MKTAG(16 , 11 , '3', 'Y') },
{ AV_PIX_FMT_YUV422P16LE, MKTAG('Y', '3', 10 , 16 ) },
@@ -127,6 +144,8 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_YUV444P16LE, MKTAG('Y', '3', 0 , 16 ) },
{ AV_PIX_FMT_YUV444P16BE, MKTAG(16 , 0 , '3', 'Y') },
{ AV_PIX_FMT_YUVA420P, MKTAG('Y', '4', 11 , 8 ) },
+ { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) },
+ { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) },
{ AV_PIX_FMT_YA8, MKTAG('Y', '2', 0 , 8 ) },
{ AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) },
@@ -148,10 +167,41 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_YUVA444P16LE, MKTAG('Y', '4', 0 , 16 ) },
{ AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') },
+ { AV_PIX_FMT_GBRP, MKTAG('G', '3', 00 , 8 ) },
+ { AV_PIX_FMT_GBRP9LE, MKTAG('G', '3', 00 , 9 ) },
+ { AV_PIX_FMT_GBRP9BE, MKTAG( 9 , 00 , '3', 'G') },
+ { AV_PIX_FMT_GBRP10LE, MKTAG('G', '3', 00 , 10 ) },
+ { AV_PIX_FMT_GBRP10BE, MKTAG(10 , 00 , '3', 'G') },
+ { AV_PIX_FMT_GBRP12LE, MKTAG('G', '3', 00 , 12 ) },
+ { AV_PIX_FMT_GBRP12BE, MKTAG(12 , 00 , '3', 'G') },
+ { AV_PIX_FMT_GBRP14LE, MKTAG('G', '3', 00 , 14 ) },
+ { AV_PIX_FMT_GBRP14BE, MKTAG(14 , 00 , '3', 'G') },
+ { AV_PIX_FMT_GBRP16LE, MKTAG('G', '3', 00 , 16 ) },
+ { AV_PIX_FMT_GBRP16BE, MKTAG(16 , 00 , '3', 'G') },
+
+ { AV_PIX_FMT_XYZ12LE, MKTAG('X', 'Y', 'Z' , 36 ) },
+ { AV_PIX_FMT_XYZ12BE, MKTAG(36 , 'Z' , 'Y', 'X') },
+
+ { AV_PIX_FMT_BAYER_BGGR8, MKTAG(0xBA, 'B', 'G', 8 ) },
+ { AV_PIX_FMT_BAYER_BGGR16LE, MKTAG(0xBA, 'B', 'G', 16 ) },
+ { AV_PIX_FMT_BAYER_BGGR16BE, MKTAG(16 , 'G', 'B', 0xBA) },
+ { AV_PIX_FMT_BAYER_RGGB8, MKTAG(0xBA, 'R', 'G', 8 ) },
+ { AV_PIX_FMT_BAYER_RGGB16LE, MKTAG(0xBA, 'R', 'G', 16 ) },
+ { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG(16 , 'G', 'R', 0xBA) },
+ { AV_PIX_FMT_BAYER_GBRG8, MKTAG(0xBA, 'G', 'B', 8 ) },
+ { AV_PIX_FMT_BAYER_GBRG16LE, MKTAG(0xBA, 'G', 'B', 16 ) },
+ { AV_PIX_FMT_BAYER_GBRG16BE, MKTAG(16, 'B', 'G', 0xBA) },
+ { AV_PIX_FMT_BAYER_GRBG8, MKTAG(0xBA, 'G', 'R', 8 ) },
+ { AV_PIX_FMT_BAYER_GRBG16LE, MKTAG(0xBA, 'G', 'R', 16 ) },
+ { AV_PIX_FMT_BAYER_GRBG16BE, MKTAG(16, 'R', 'G', 0xBA) },
+
/* quicktime */
+ { AV_PIX_FMT_YUV420P, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */
+ { AV_PIX_FMT_YUV411P, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */
{ AV_PIX_FMT_UYVY422, MKTAG('2', 'v', 'u', 'y') },
{ AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', 'y') },
{ AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'U', 'I') }, /* FIXME merge both fields */
+ { AV_PIX_FMT_UYVY422, MKTAG('b', 'x', 'y', 'v') },
{ AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', '2') },
{ AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', 's') },
{ AV_PIX_FMT_YUYV422, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */
@@ -159,8 +209,10 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_RGB565LE,MKTAG('L', '5', '6', '5') },
{ AV_PIX_FMT_RGB565BE,MKTAG('B', '5', '6', '5') },
{ AV_PIX_FMT_BGR24, MKTAG('2', '4', 'B', 'G') },
+ { AV_PIX_FMT_BGR24, MKTAG('b', 'x', 'b', 'g') },
{ AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') },
{ AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') },
+ { AV_PIX_FMT_RGB24, MKTAG('b', 'x', 'r', 'g') },
{ AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') },
{ AV_PIX_FMT_GRAY16BE,MKTAG('b', '1', '6', 'g') },
{ AV_PIX_FMT_RGB48BE, MKTAG('b', '4', '8', 'r') },
@@ -172,6 +224,11 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = {
{ AV_PIX_FMT_NONE, 0 },
};
+const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void)
+{
+ return ff_raw_pix_fmt_tags;
+}
+
unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat fmt)
{
const PixelFormatTag *tags = ff_raw_pix_fmt_tags;
@@ -182,3 +239,28 @@ unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat fmt)
}
return 0;
}
+
+const PixelFormatTag avpriv_pix_fmt_bps_avi[] = {
+ { AV_PIX_FMT_MONOWHITE, 1 },
+ { AV_PIX_FMT_PAL8, 2 },
+ { AV_PIX_FMT_PAL8, 4 },
+ { AV_PIX_FMT_PAL8, 8 },
+ { AV_PIX_FMT_RGB444LE, 12 },
+ { AV_PIX_FMT_RGB555LE, 15 },
+ { AV_PIX_FMT_RGB555LE, 16 },
+ { AV_PIX_FMT_BGR24, 24 },
+ { AV_PIX_FMT_BGRA, 32 },
+ { AV_PIX_FMT_NONE, 0 },
+};
+
+const PixelFormatTag avpriv_pix_fmt_bps_mov[] = {
+ { AV_PIX_FMT_MONOWHITE, 1 },
+ { AV_PIX_FMT_PAL8, 2 },
+ { AV_PIX_FMT_PAL8, 4 },
+ { AV_PIX_FMT_PAL8, 8 },
+ { AV_PIX_FMT_RGB555BE, 16 },
+ { AV_PIX_FMT_RGB24, 24 },
+ { AV_PIX_FMT_ARGB, 32 },
+ { AV_PIX_FMT_MONOWHITE,33 },
+ { AV_PIX_FMT_NONE, 0 },
+};
diff --git a/libavcodec/raw.h b/libavcodec/raw.h
index bf66671d16..24bf4cc55a 100644
--- a/libavcodec/raw.h
+++ b/libavcodec/raw.h
@@ -2,20 +2,20 @@
* Raw Video Codec
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,12 +28,20 @@
#define AVCODEC_RAW_H
#include "avcodec.h"
+#include "libavutil/internal.h"
typedef struct PixelFormatTag {
enum AVPixelFormat pix_fmt;
unsigned int fourcc;
} PixelFormatTag;
-extern const PixelFormatTag ff_raw_pix_fmt_tags[];
+extern const PixelFormatTag ff_raw_pix_fmt_tags[]; // exposed through avpriv_get_raw_pix_fmt_tags()
+
+const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void);
+
+enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags, unsigned int fourcc);
+
+extern av_export const PixelFormatTag avpriv_pix_fmt_bps_avi[];
+extern av_export const PixelFormatTag avpriv_pix_fmt_bps_mov[];
#endif /* AVCODEC_RAW_H */
diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c
index 3b69e49e84..647dfa9a0a 100644
--- a/libavcodec/rawdec.c
+++ b/libavcodec/rawdec.c
@@ -2,20 +2,20 @@
* Raw Video Decoder
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,72 +25,61 @@
*/
#include "avcodec.h"
+#include "bswapdsp.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/opt.h"
typedef struct RawVideoContext {
+ AVClass *av_class;
AVBufferRef *palette;
int frame_size; /* size of the frame in bytes */
int flip;
int is_2_4_bpp; // 2 or 4 bpp raw in avi/mov
int is_yuv2;
+ int is_lt_16bpp; // 16bpp pixfmt and bits_per_coded_sample < 16
+ int tff;
+
+ BswapDSPContext bbdsp;
+ void *bitstream_buf;
+ unsigned int bitstream_buf_size;
} RawVideoContext;
-static const PixelFormatTag pix_fmt_bps_avi[] = {
- { AV_PIX_FMT_PAL8, 4 },
- { AV_PIX_FMT_PAL8, 8 },
- { AV_PIX_FMT_RGB444, 12 },
- { AV_PIX_FMT_RGB555, 15 },
- { AV_PIX_FMT_RGB555, 16 },
- { AV_PIX_FMT_BGR24, 24 },
- { AV_PIX_FMT_RGB32, 32 },
- { AV_PIX_FMT_NONE, 0 },
+static const AVOption options[]={
+{"top", "top field first", offsetof(RawVideoContext, tff), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM|AV_OPT_FLAG_VIDEO_PARAM},
+{NULL}
};
-static const PixelFormatTag pix_fmt_bps_mov[] = {
- { AV_PIX_FMT_MONOWHITE, 1 },
- { AV_PIX_FMT_PAL8, 2 },
- { AV_PIX_FMT_PAL8, 4 },
- { AV_PIX_FMT_PAL8, 8 },
- // FIXME swscale does not support 16 bit in .mov, sample 16bit.mov
- // http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
- { AV_PIX_FMT_RGB555BE, 16 },
- { AV_PIX_FMT_RGB24, 24 },
- { AV_PIX_FMT_ARGB, 32 },
- { AV_PIX_FMT_MONOWHITE,33 },
- { AV_PIX_FMT_NONE, 0 },
+static const AVClass rawdec_class = {
+ .class_name = "rawdec",
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
};
-static enum AVPixelFormat find_pix_fmt(const PixelFormatTag *tags,
- unsigned int fourcc)
-{
- while (tags->pix_fmt >= 0) {
- if (tags->fourcc == fourcc)
- return tags->pix_fmt;
- tags++;
- }
- return AV_PIX_FMT_YUV420P;
-}
-
static av_cold int raw_init_decoder(AVCodecContext *avctx)
{
RawVideoContext *context = avctx->priv_data;
const AVPixFmtDescriptor *desc;
- if (avctx->codec_tag == MKTAG('r', 'a', 'w', ' '))
- avctx->pix_fmt = find_pix_fmt(pix_fmt_bps_mov,
+ ff_bswapdsp_init(&context->bbdsp);
+
+ if ( avctx->codec_tag == MKTAG('r','a','w',' ')
+ || avctx->codec_tag == MKTAG('N','O','1','6'))
+ avctx->pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_mov,
avctx->bits_per_coded_sample);
else if (avctx->codec_tag == MKTAG('W', 'R', 'A', 'W'))
- avctx->pix_fmt = find_pix_fmt(pix_fmt_bps_avi,
+ avctx->pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi,
avctx->bits_per_coded_sample);
- else if (avctx->codec_tag)
- avctx->pix_fmt = find_pix_fmt(ff_raw_pix_fmt_tags, avctx->codec_tag);
+ else if (avctx->codec_tag && (avctx->codec_tag & 0xFFFFFF) != MKTAG('B','I','T', 0))
+ avctx->pix_fmt = avpriv_find_pix_fmt(ff_raw_pix_fmt_tags, avctx->codec_tag);
else if (avctx->pix_fmt == AV_PIX_FMT_NONE && avctx->bits_per_coded_sample)
- avctx->pix_fmt = find_pix_fmt(pix_fmt_bps_avi,
+ avctx->pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi,
avctx->bits_per_coded_sample);
desc = av_pix_fmt_desc_get(avctx->pix_fmt);
@@ -109,15 +98,9 @@ static av_cold int raw_init_decoder(AVCodecContext *avctx)
memset(context->palette->data, 0, AVPALETTE_SIZE);
}
- context->frame_size = avpicture_get_size(avctx->pix_fmt, avctx->width,
- avctx->height);
- if ((avctx->bits_per_coded_sample == 4 || avctx->bits_per_coded_sample == 2) &&
- avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
- (!avctx->codec_tag || avctx->codec_tag == MKTAG('r','a','w',' ')))
- context->is_2_4_bpp = 1;
-
if ((avctx->extradata_size >= 9 &&
!memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9)) ||
+ avctx->codec_tag == MKTAG('c','y','u','v') ||
avctx->codec_tag == MKTAG(3, 0, 0, 0) ||
avctx->codec_tag == MKTAG('W','R','A','W'))
context->flip = 1;
@@ -135,6 +118,34 @@ static void flip(AVCodecContext *avctx, AVPicture *picture)
picture->linesize[0] *= -1;
}
+/*
+ * Scale sample to 16-bit resolution
+ */
+#define SCALE16(x, bits) (((x) << (16 - (bits))) | ((x) >> (2 * (bits) - 16)))
+
+/**
+ * Scale buffer to 16 bits per coded sample resolution
+ */
+#define MKSCALE16(name, r16, w16) \
+static void name(AVCodecContext *avctx, uint8_t * dst, const uint8_t *buf, int buf_size, int packed) \
+{ \
+ int i; \
+ if (!packed) { \
+ for (i = 0; i + 1 < buf_size; i += 2) \
+ w16(dst + i, SCALE16(r16(buf + i), avctx->bits_per_coded_sample)); \
+ } else { \
+ GetBitContext gb; \
+ init_get_bits(&gb, buf, buf_size * 8); \
+ for (i = 0; i < avctx->width * avctx->height; i++) { \
+ int sample = get_bits(&gb, avctx->bits_per_coded_sample); \
+ w16(dst + i*2, SCALE16(sample, avctx->bits_per_coded_sample)); \
+ } \
+ } \
+}
+
+MKSCALE16(scale16be, AV_RB16, AV_WB16)
+MKSCALE16(scale16le, AV_RL16, AV_WL16)
+
static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
@@ -142,12 +153,30 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
RawVideoContext *context = avctx->priv_data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
- int need_copy = !avpkt->buf || context->is_2_4_bpp || context->is_yuv2;
- int res;
+ int linesize_align = 4;
+ int res, len;
+ int need_copy;
AVFrame *frame = data;
AVPicture *picture = data;
+ if ((avctx->bits_per_coded_sample == 4 || avctx->bits_per_coded_sample == 2) &&
+ avctx->pix_fmt == AV_PIX_FMT_PAL8 &&
+ (!avctx->codec_tag || avctx->codec_tag == MKTAG('r','a','w',' '))) {
+ context->is_2_4_bpp = 1;
+ context->frame_size = avpicture_get_size(avctx->pix_fmt,
+ FFALIGN(avctx->width, 16),
+ avctx->height);
+ } else {
+ context->is_lt_16bpp = av_get_bits_per_pixel(desc) == 16 && avctx->bits_per_coded_sample && avctx->bits_per_coded_sample < 16;
+ context->frame_size = avpicture_get_size(avctx->pix_fmt, avctx->width,
+ avctx->height);
+ }
+ if (context->frame_size < 0)
+ return context->frame_size;
+
+ need_copy = !avpkt->buf || context->is_2_4_bpp || context->is_yuv2 || context->is_lt_16bpp;
+
frame->pict_type = AV_PICTURE_TYPE_I;
frame->key_frame = 1;
@@ -155,12 +184,19 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
if (res < 0)
return res;
- if (buf_size < context->frame_size - (avctx->pix_fmt == AV_PIX_FMT_PAL8 ?
- AVPALETTE_SIZE : 0))
- return -1;
+ av_frame_set_pkt_pos (frame, avctx->internal->pkt->pos);
+ av_frame_set_pkt_duration(frame, avctx->internal->pkt->duration);
+
+ if (context->tff >= 0) {
+ frame->interlaced_frame = 1;
+ frame->top_field_first = context->tff;
+ }
+
+ if ((res = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
+ return res;
if (need_copy)
- frame->buf[0] = av_buffer_alloc(context->frame_size);
+ frame->buf[0] = av_buffer_alloc(FFMAX(context->frame_size, buf_size));
else
frame->buf[0] = av_buffer_ref(avpkt->buf);
if (!frame->buf[0])
@@ -172,21 +208,48 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
uint8_t *dst = frame->buf[0]->data;
buf_size = context->frame_size - AVPALETTE_SIZE;
if (avctx->bits_per_coded_sample == 4) {
- for (i = 0; 2 * i + 1 < buf_size; i++) {
+ for (i = 0; 2 * i + 1 < buf_size && i<avpkt->size; i++) {
dst[2 * i + 0] = buf[i] >> 4;
dst[2 * i + 1] = buf[i] & 15;
}
+ linesize_align = 8;
} else {
- for (i = 0; 4 * i + 3 < buf_size; i++) {
+ av_assert0(avctx->bits_per_coded_sample == 2);
+ for (i = 0; 4 * i + 3 < buf_size && i<avpkt->size; i++) {
dst[4 * i + 0] = buf[i] >> 6;
dst[4 * i + 1] = buf[i] >> 4 & 3;
dst[4 * i + 2] = buf[i] >> 2 & 3;
dst[4 * i + 3] = buf[i] & 3;
}
+ linesize_align = 16;
+ }
+ buf = dst;
+ } else if (context->is_lt_16bpp) {
+ uint8_t *dst = frame->buf[0]->data;
+ int packed = (avctx->codec_tag & 0xFFFFFF) == MKTAG('B','I','T', 0);
+ int swap = avctx->codec_tag >> 24;
+
+ if (packed && swap) {
+ av_fast_padded_malloc(&context->bitstream_buf, &context->bitstream_buf_size, buf_size);
+ if (!context->bitstream_buf)
+ return AVERROR(ENOMEM);
+ if (swap == 16)
+ context->bbdsp.bswap16_buf(context->bitstream_buf, (const uint16_t*)buf, buf_size / 2);
+ else if (swap == 32)
+ context->bbdsp.bswap_buf(context->bitstream_buf, (const uint32_t*)buf, buf_size / 4);
+ else
+ return AVERROR_INVALIDDATA;
+ buf = context->bitstream_buf;
}
+
+ if (desc->flags & AV_PIX_FMT_FLAG_BE)
+ scale16be(avctx, dst, buf, buf_size, packed);
+ else
+ scale16le(avctx, dst, buf, buf_size, packed);
+
buf = dst;
} else if (need_copy) {
- memcpy(frame->buf[0]->data, buf, FFMIN(buf_size, context->frame_size));
+ memcpy(frame->buf[0]->data, buf, buf_size);
buf = frame->buf[0]->data;
}
@@ -194,9 +257,18 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
avctx->codec_tag == MKTAG('A', 'V', 'u', 'p'))
buf += buf_size - context->frame_size;
+ len = context->frame_size - (avctx->pix_fmt==AV_PIX_FMT_PAL8 ? AVPALETTE_SIZE : 0);
+ if (buf_size < len && (avctx->codec_tag & 0xFFFFFF) != MKTAG('B','I','T', 0)) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid buffer size, packet size %d < expected frame_size %d\n", buf_size, len);
+ av_buffer_unref(&frame->buf[0]);
+ return AVERROR(EINVAL);
+ }
+
if ((res = avpicture_fill(picture, buf, avctx->pix_fmt,
- avctx->width, avctx->height)) < 0)
+ avctx->width, avctx->height)) < 0) {
+ av_buffer_unref(&frame->buf[0]);
return res;
+ }
if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE,
@@ -205,20 +277,44 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
if (pal) {
av_buffer_unref(&context->palette);
context->palette = av_buffer_alloc(AVPALETTE_SIZE);
- if (!context->palette)
+ if (!context->palette) {
+ av_buffer_unref(&frame->buf[0]);
return AVERROR(ENOMEM);
+ }
memcpy(context->palette->data, pal, AVPALETTE_SIZE);
frame->palette_has_changed = 1;
}
}
+ if ((avctx->pix_fmt==AV_PIX_FMT_BGR24 ||
+ avctx->pix_fmt==AV_PIX_FMT_GRAY8 ||
+ avctx->pix_fmt==AV_PIX_FMT_RGB555LE ||
+ avctx->pix_fmt==AV_PIX_FMT_RGB555BE ||
+ avctx->pix_fmt==AV_PIX_FMT_RGB565LE ||
+ avctx->pix_fmt==AV_PIX_FMT_MONOWHITE ||
+ avctx->pix_fmt==AV_PIX_FMT_PAL8) &&
+ FFALIGN(frame->linesize[0], linesize_align) * avctx->height <= buf_size)
+ frame->linesize[0] = FFALIGN(frame->linesize[0], linesize_align);
+
+ if (avctx->pix_fmt == AV_PIX_FMT_NV12 && avctx->codec_tag == MKTAG('N', 'V', '1', '2') &&
+ FFALIGN(frame->linesize[0], linesize_align) * avctx->height +
+ FFALIGN(frame->linesize[1], linesize_align) * ((avctx->height + 1) / 2) <= buf_size) {
+ int la0 = FFALIGN(frame->linesize[0], linesize_align);
+ frame->data[1] += (la0 - frame->linesize[0]) * avctx->height;
+ frame->linesize[0] = la0;
+ frame->linesize[1] = FFALIGN(frame->linesize[1], linesize_align);
+ }
+
if ((avctx->pix_fmt == AV_PIX_FMT_PAL8 && buf_size < context->frame_size) ||
(desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)) {
frame->buf[1] = av_buffer_ref(context->palette);
- if (!frame->buf[1])
+ if (!frame->buf[1]) {
+ av_buffer_unref(&frame->buf[0]);
return AVERROR(ENOMEM);
+ }
frame->data[1] = frame->buf[1]->data;
}
+
if (avctx->pix_fmt == AV_PIX_FMT_BGR24 &&
((frame->linesize[0] + 3) & ~3) * avctx->height <= buf_size)
frame->linesize[0] = (frame->linesize[0] + 3) & ~3;
@@ -232,6 +328,11 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
avctx->codec_tag == MKTAG('Y', 'V', 'U', '9'))
FFSWAP(uint8_t *, picture->data[1], picture->data[2]);
+ if (avctx->codec_tag == AV_RL32("I420") && (avctx->width+1)*(avctx->height+1) * 3/2 == buf_size) {
+ picture->data[1] = picture->data[1] + (avctx->width+1)*(avctx->height+1) -avctx->width*avctx->height;
+ picture->data[2] = picture->data[2] + ((avctx->width+1)*(avctx->height+1) -avctx->width*avctx->height)*5/4;
+ }
+
if (avctx->codec_tag == AV_RL32("yuv2") &&
avctx->pix_fmt == AV_PIX_FMT_YUYV422) {
int x, y;
@@ -243,6 +344,12 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame,
}
}
+ if (avctx->field_order > AV_FIELD_PROGRESSIVE) { /* we have interlaced material flagged in container */
+ frame->interlaced_frame = 1;
+ if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB)
+ frame->top_field_first = 1;
+ }
+
*got_frame = 1;
return buf_size;
}
@@ -264,4 +371,6 @@ AVCodec ff_rawvideo_decoder = {
.init = raw_init_decoder,
.close = raw_close_decoder,
.decode = raw_decode,
+ .priv_class = &rawdec_class,
+ .capabilities = CODEC_CAP_PARAM_CHANGE,
};
diff --git a/libavcodec/rawenc.c b/libavcodec/rawenc.c
index d6e8009341..d7923931bb 100644
--- a/libavcodec/rawenc.c
+++ b/libavcodec/rawenc.c
@@ -2,20 +2,20 @@
* Raw Video Encoder
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,7 +40,6 @@ static av_cold int raw_encode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
avctx->bits_per_coded_sample = av_get_bits_per_pixel(desc);
if(!avctx->codec_tag)
avctx->codec_tag = avcodec_pix_fmt_to_codec_tag(avctx->pix_fmt);
@@ -55,7 +54,7 @@ static int raw_encode(AVCodecContext *avctx, AVPacket *pkt,
if (ret < 0)
return ret;
- if ((ret = ff_alloc_packet(pkt, ret)) < 0)
+ if ((ret = ff_alloc_packet2(avctx, pkt, ret)) < 0)
return ret;
if ((ret = avpicture_layout((const AVPicture *)frame, avctx->pix_fmt, avctx->width,
avctx->height, pkt->data, pkt->size)) < 0)
diff --git a/libavcodec/rdft.c b/libavcodec/rdft.c
index 19652537f8..e85219e45b 100644
--- a/libavcodec/rdft.c
+++ b/libavcodec/rdft.c
@@ -2,20 +2,20 @@
* (I)RDFT transforms
* Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
diff --git a/libavcodec/rdft.h b/libavcodec/rdft.h
index 8ff620fb59..37c40e7c80 100644
--- a/libavcodec/rdft.h
+++ b/libavcodec/rdft.h
@@ -2,24 +2,24 @@
* (I)RDFT transforms
* Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_RDFT_H
+#if !defined(AVCODEC_RDFT_H) && (!defined(FFT_FLOAT) || FFT_FLOAT)
#define AVCODEC_RDFT_H
#include "config.h"
diff --git a/libavcodec/realtextdec.c b/libavcodec/realtextdec.c
new file mode 100644
index 0000000000..870953bf3c
--- /dev/null
+++ b/libavcodec/realtextdec.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * RealText subtitle decoder
+ * @see http://service.real.com/help/library/guides/ProductionGuide/prodguide/htmfiles/realtext.htm
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+
+static int rt_event_to_ass(AVBPrint *buf, const char *p)
+{
+ int prev_chr_is_space = 1;
+
+ while (*p) {
+ if (*p != '<') {
+ if (!av_isspace(*p))
+ av_bprint_chars(buf, *p, 1);
+ else if (!prev_chr_is_space)
+ av_bprint_chars(buf, ' ', 1);
+ prev_chr_is_space = av_isspace(*p);
+ } else {
+ const char *end = strchr(p, '>');
+ if (!end)
+ break;
+ if (!av_strncasecmp(p, "<br/>", 5) ||
+ !av_strncasecmp(p, "<br>", 4)) {
+ av_bprintf(buf, "\\N");
+ }
+ p = end;
+ }
+ p++;
+ }
+ return 0;
+}
+
+static int realtext_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ int ret = 0;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 0, 4096);
+ // note: no need to rescale pts & duration since they are in the same
+ // timebase as ASS (1/100)
+ if (ptr && avpkt->size > 0 && !rt_event_to_ass(&buf, ptr))
+ ret = ff_ass_add_rect_bprint(sub, &buf, avpkt->pts, avpkt->duration);
+ av_bprint_finalize(&buf, NULL);
+ if (ret < 0)
+ return ret;
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_realtext_decoder = {
+ .name = "realtext",
+ .long_name = NULL_IF_CONFIG_SMALL("RealText subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_REALTEXT,
+ .decode = realtext_decode_frame,
+ .init = ff_ass_subtitle_header_default,
+};
diff --git a/libavcodec/rectangle.h b/libavcodec/rectangle.h
index 73e8b0abd1..594a760801 100644
--- a/libavcodec/rectangle.h
+++ b/libavcodec/rectangle.h
@@ -2,20 +2,20 @@
* rectangle filling function
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,9 +28,9 @@
#ifndef AVCODEC_RECTANGLE_H
#define AVCODEC_RECTANGLE_H
-#include <assert.h>
#include "config.h"
#include "libavutil/common.h"
+#include "libavutil/avassert.h"
/**
* fill a rectangle.
@@ -40,13 +40,14 @@
*/
static av_always_inline void fill_rectangle(void *vp, int w, int h, int stride, uint32_t val, int size){
uint8_t *p= (uint8_t*)vp;
- assert(size==1 || size==2 || size==4);
- assert(w<=4);
+ av_assert2(size==1 || size==2 || size==4);
+ av_assert2(w<=4);
w *= size;
stride *= size;
- assert((stride&(w-1))==0);
+ av_assert2((((long)vp)&(FFMIN(w, 8<<(HAVE_NEON|ARCH_PPC|HAVE_MMX))-1)) == 0);
+ av_assert2((stride&(w-1))==0);
if(w==2){
const uint16_t v= size==4 ? val : val*0x0101;
*(uint16_t*)(p + 0*stride)= v;
@@ -116,8 +117,8 @@ static av_always_inline void fill_rectangle(void *vp, int w, int h, int stride,
*(uint32_t*)(p +12+3*stride)= val;
#endif
}else
- assert(0);
- assert(h==4);
+ av_assert2(0);
+ av_assert2(h==4);
}
#endif /* AVCODEC_RECTANGLE_H */
diff --git a/libavcodec/remove_extradata_bsf.c b/libavcodec/remove_extradata_bsf.c
index 460482a8ff..e880b95809 100644
--- a/libavcodec/remove_extradata_bsf.c
+++ b/libavcodec/remove_extradata_bsf.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,6 @@ static int remove_extradata(AVBitStreamFilterContext *bsfc, AVCodecContext *avct
}
AVBitStreamFilter ff_remove_extradata_bsf={
- "remove_extra",
- 0,
- remove_extradata,
+ .name = "remove_extra",
+ .filter = remove_extradata,
};
diff --git a/libavcodec/resample.c b/libavcodec/resample.c
new file mode 100644
index 0000000000..c45aa16cd1
--- /dev/null
+++ b/libavcodec/resample.c
@@ -0,0 +1,443 @@
+/*
+ * samplerate conversion for both audio and video
+ * Copyright (c) 2000 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * samplerate conversion for both audio and video
+ */
+
+#include <string.h>
+
+#include "avcodec.h"
+#include "audioconvert.h"
+#include "libavutil/opt.h"
+#include "libavutil/mem.h"
+#include "libavutil/samplefmt.h"
+
+#if FF_API_AVCODEC_RESAMPLE
+
+#define MAX_CHANNELS 8
+
+struct AVResampleContext;
+
+static const char *context_to_name(void *ptr)
+{
+ return "audioresample";
+}
+
+static const AVOption options[] = {{NULL}};
+static const AVClass audioresample_context_class = {
+ "ReSampleContext", context_to_name, options, LIBAVUTIL_VERSION_INT
+};
+
+struct ReSampleContext {
+ struct AVResampleContext *resample_context;
+ short *temp[MAX_CHANNELS];
+ int temp_len;
+ float ratio;
+ /* channel convert */
+ int input_channels, output_channels, filter_channels;
+ AVAudioConvert *convert_ctx[2];
+ enum AVSampleFormat sample_fmt[2]; ///< input and output sample format
+ unsigned sample_size[2]; ///< size of one sample in sample_fmt
+ short *buffer[2]; ///< buffers used for conversion to S16
+ unsigned buffer_size[2]; ///< sizes of allocated buffers
+};
+
+/* n1: number of samples */
+static void stereo_to_mono(short *output, short *input, int n1)
+{
+ short *p, *q;
+ int n = n1;
+
+ p = input;
+ q = output;
+ while (n >= 4) {
+ q[0] = (p[0] + p[1]) >> 1;
+ q[1] = (p[2] + p[3]) >> 1;
+ q[2] = (p[4] + p[5]) >> 1;
+ q[3] = (p[6] + p[7]) >> 1;
+ q += 4;
+ p += 8;
+ n -= 4;
+ }
+ while (n > 0) {
+ q[0] = (p[0] + p[1]) >> 1;
+ q++;
+ p += 2;
+ n--;
+ }
+}
+
+/* n1: number of samples */
+static void mono_to_stereo(short *output, short *input, int n1)
+{
+ short *p, *q;
+ int n = n1;
+ int v;
+
+ p = input;
+ q = output;
+ while (n >= 4) {
+ v = p[0]; q[0] = v; q[1] = v;
+ v = p[1]; q[2] = v; q[3] = v;
+ v = p[2]; q[4] = v; q[5] = v;
+ v = p[3]; q[6] = v; q[7] = v;
+ q += 8;
+ p += 4;
+ n -= 4;
+ }
+ while (n > 0) {
+ v = p[0]; q[0] = v; q[1] = v;
+ q += 2;
+ p += 1;
+ n--;
+ }
+}
+
+/*
+5.1 to stereo input: [fl, fr, c, lfe, rl, rr]
+- Left = front_left + rear_gain * rear_left + center_gain * center
+- Right = front_right + rear_gain * rear_right + center_gain * center
+Where rear_gain is usually around 0.5-1.0 and
+ center_gain is almost always 0.7 (-3 dB)
+*/
+static void surround_to_stereo(short **output, short *input, int channels, int samples)
+{
+ int i;
+ short l, r;
+
+ for (i = 0; i < samples; i++) {
+ int fl,fr,c,rl,rr;
+ fl = input[0];
+ fr = input[1];
+ c = input[2];
+ // lfe = input[3];
+ rl = input[4];
+ rr = input[5];
+
+ l = av_clip_int16(fl + (0.5 * rl) + (0.7 * c));
+ r = av_clip_int16(fr + (0.5 * rr) + (0.7 * c));
+
+ /* output l & r. */
+ *output[0]++ = l;
+ *output[1]++ = r;
+
+ /* increment input. */
+ input += channels;
+ }
+}
+
+static void deinterleave(short **output, short *input, int channels, int samples)
+{
+ int i, j;
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ *output[j]++ = *input++;
+ }
+ }
+}
+
+static void interleave(short *output, short **input, int channels, int samples)
+{
+ int i, j;
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ *output++ = *input[j]++;
+ }
+ }
+}
+
+static void ac3_5p1_mux(short *output, short *input1, short *input2, int n)
+{
+ int i;
+ short l, r;
+
+ for (i = 0; i < n; i++) {
+ l = *input1++;
+ r = *input2++;
+ *output++ = l; /* left */
+ *output++ = (l / 2) + (r / 2); /* center */
+ *output++ = r; /* right */
+ *output++ = 0; /* left surround */
+ *output++ = 0; /* right surroud */
+ *output++ = 0; /* low freq */
+ }
+}
+
+#define SUPPORT_RESAMPLE(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8) \
+ ch8<<7 | ch7<<6 | ch6<<5 | ch5<<4 | ch4<<3 | ch3<<2 | ch2<<1 | ch1<<0
+
+static const uint8_t supported_resampling[MAX_CHANNELS] = {
+ // output ch: 1 2 3 4 5 6 7 8
+ SUPPORT_RESAMPLE(1, 1, 0, 0, 0, 0, 0, 0), // 1 input channel
+ SUPPORT_RESAMPLE(1, 1, 0, 0, 0, 1, 0, 0), // 2 input channels
+ SUPPORT_RESAMPLE(0, 0, 1, 0, 0, 0, 0, 0), // 3 input channels
+ SUPPORT_RESAMPLE(0, 0, 0, 1, 0, 0, 0, 0), // 4 input channels
+ SUPPORT_RESAMPLE(0, 0, 0, 0, 1, 0, 0, 0), // 5 input channels
+ SUPPORT_RESAMPLE(0, 1, 0, 0, 0, 1, 0, 0), // 6 input channels
+ SUPPORT_RESAMPLE(0, 0, 0, 0, 0, 0, 1, 0), // 7 input channels
+ SUPPORT_RESAMPLE(0, 0, 0, 0, 0, 0, 0, 1), // 8 input channels
+};
+
+ReSampleContext *av_audio_resample_init(int output_channels, int input_channels,
+ int output_rate, int input_rate,
+ enum AVSampleFormat sample_fmt_out,
+ enum AVSampleFormat sample_fmt_in,
+ int filter_length, int log2_phase_count,
+ int linear, double cutoff)
+{
+ ReSampleContext *s;
+
+ if (input_channels > MAX_CHANNELS) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Resampling with input channels greater than %d is unsupported.\n",
+ MAX_CHANNELS);
+ return NULL;
+ }
+ if (!(supported_resampling[input_channels-1] & (1<<(output_channels-1)))) {
+ int i;
+ av_log(NULL, AV_LOG_ERROR, "Unsupported audio resampling. Allowed "
+ "output channels for %d input channel%s", input_channels,
+ input_channels > 1 ? "s:" : ":");
+ for (i = 0; i < MAX_CHANNELS; i++)
+ if (supported_resampling[input_channels-1] & (1<<i))
+ av_log(NULL, AV_LOG_ERROR, " %d", i + 1);
+ av_log(NULL, AV_LOG_ERROR, "\n");
+ return NULL;
+ }
+
+ s = av_mallocz(sizeof(ReSampleContext));
+ if (!s) {
+ av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for resample context.\n");
+ return NULL;
+ }
+
+ s->ratio = (float)output_rate / (float)input_rate;
+
+ s->input_channels = input_channels;
+ s->output_channels = output_channels;
+
+ s->filter_channels = s->input_channels;
+ if (s->output_channels < s->filter_channels)
+ s->filter_channels = s->output_channels;
+
+ s->sample_fmt[0] = sample_fmt_in;
+ s->sample_fmt[1] = sample_fmt_out;
+ s->sample_size[0] = av_get_bytes_per_sample(s->sample_fmt[0]);
+ s->sample_size[1] = av_get_bytes_per_sample(s->sample_fmt[1]);
+
+ if (s->sample_fmt[0] != AV_SAMPLE_FMT_S16) {
+ if (!(s->convert_ctx[0] = av_audio_convert_alloc(AV_SAMPLE_FMT_S16, 1,
+ s->sample_fmt[0], 1, NULL, 0))) {
+ av_log(s, AV_LOG_ERROR,
+ "Cannot convert %s sample format to s16 sample format\n",
+ av_get_sample_fmt_name(s->sample_fmt[0]));
+ av_free(s);
+ return NULL;
+ }
+ }
+
+ if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) {
+ if (!(s->convert_ctx[1] = av_audio_convert_alloc(s->sample_fmt[1], 1,
+ AV_SAMPLE_FMT_S16, 1, NULL, 0))) {
+ av_log(s, AV_LOG_ERROR,
+ "Cannot convert s16 sample format to %s sample format\n",
+ av_get_sample_fmt_name(s->sample_fmt[1]));
+ av_audio_convert_free(s->convert_ctx[0]);
+ av_free(s);
+ return NULL;
+ }
+ }
+
+ s->resample_context = av_resample_init(output_rate, input_rate,
+ filter_length, log2_phase_count,
+ linear, cutoff);
+
+ *(const AVClass**)s->resample_context = &audioresample_context_class;
+
+ return s;
+}
+
+/* resample audio. 'nb_samples' is the number of input samples */
+/* XXX: optimize it ! */
+int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples)
+{
+ int i, nb_samples1;
+ short *bufin[MAX_CHANNELS];
+ short *bufout[MAX_CHANNELS];
+ short *buftmp2[MAX_CHANNELS], *buftmp3[MAX_CHANNELS];
+ short *output_bak = NULL;
+ int lenout;
+
+ if (s->input_channels == s->output_channels && s->ratio == 1.0 && 0) {
+ /* nothing to do */
+ memcpy(output, input, nb_samples * s->input_channels * sizeof(short));
+ return nb_samples;
+ }
+
+ if (s->sample_fmt[0] != AV_SAMPLE_FMT_S16) {
+ int istride[1] = { s->sample_size[0] };
+ int ostride[1] = { 2 };
+ const void *ibuf[1] = { input };
+ void *obuf[1];
+ unsigned input_size = nb_samples * s->input_channels * 2;
+
+ if (!s->buffer_size[0] || s->buffer_size[0] < input_size) {
+ av_free(s->buffer[0]);
+ s->buffer_size[0] = input_size;
+ s->buffer[0] = av_malloc(s->buffer_size[0]);
+ if (!s->buffer[0]) {
+ av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n");
+ return 0;
+ }
+ }
+
+ obuf[0] = s->buffer[0];
+
+ if (av_audio_convert(s->convert_ctx[0], obuf, ostride,
+ ibuf, istride, nb_samples * s->input_channels) < 0) {
+ av_log(s->resample_context, AV_LOG_ERROR,
+ "Audio sample format conversion failed\n");
+ return 0;
+ }
+
+ input = s->buffer[0];
+ }
+
+ lenout= 2*s->output_channels*nb_samples * s->ratio + 16;
+
+ if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) {
+ int out_size = lenout * av_get_bytes_per_sample(s->sample_fmt[1]) *
+ s->output_channels;
+ output_bak = output;
+
+ if (!s->buffer_size[1] || s->buffer_size[1] < out_size) {
+ av_free(s->buffer[1]);
+ s->buffer_size[1] = out_size;
+ s->buffer[1] = av_malloc(s->buffer_size[1]);
+ if (!s->buffer[1]) {
+ av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n");
+ return 0;
+ }
+ }
+
+ output = s->buffer[1];
+ }
+
+ /* XXX: move those malloc to resample init code */
+ for (i = 0; i < s->filter_channels; i++) {
+ bufin[i] = av_malloc_array((nb_samples + s->temp_len), sizeof(short));
+ bufout[i] = av_malloc_array(lenout, sizeof(short));
+
+ if (!bufin[i] || !bufout[i]) {
+ av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n");
+ nb_samples1 = 0;
+ goto fail;
+ }
+
+ memcpy(bufin[i], s->temp[i], s->temp_len * sizeof(short));
+ buftmp2[i] = bufin[i] + s->temp_len;
+ }
+
+ if (s->input_channels == 2 && s->output_channels == 1) {
+ buftmp3[0] = output;
+ stereo_to_mono(buftmp2[0], input, nb_samples);
+ } else if (s->output_channels >= 2 && s->input_channels == 1) {
+ buftmp3[0] = bufout[0];
+ memcpy(buftmp2[0], input, nb_samples * sizeof(short));
+ } else if (s->input_channels == 6 && s->output_channels ==2) {
+ buftmp3[0] = bufout[0];
+ buftmp3[1] = bufout[1];
+ surround_to_stereo(buftmp2, input, s->input_channels, nb_samples);
+ } else if (s->output_channels >= s->input_channels && s->input_channels >= 2) {
+ for (i = 0; i < s->input_channels; i++) {
+ buftmp3[i] = bufout[i];
+ }
+ deinterleave(buftmp2, input, s->input_channels, nb_samples);
+ } else {
+ buftmp3[0] = output;
+ memcpy(buftmp2[0], input, nb_samples * sizeof(short));
+ }
+
+ nb_samples += s->temp_len;
+
+ /* resample each channel */
+ nb_samples1 = 0; /* avoid warning */
+ for (i = 0; i < s->filter_channels; i++) {
+ int consumed;
+ int is_last = i + 1 == s->filter_channels;
+
+ nb_samples1 = av_resample(s->resample_context, buftmp3[i], bufin[i],
+ &consumed, nb_samples, lenout, is_last);
+ s->temp_len = nb_samples - consumed;
+ s->temp[i] = av_realloc_array(s->temp[i], s->temp_len, sizeof(short));
+ memcpy(s->temp[i], bufin[i] + consumed, s->temp_len * sizeof(short));
+ }
+
+ if (s->output_channels == 2 && s->input_channels == 1) {
+ mono_to_stereo(output, buftmp3[0], nb_samples1);
+ } else if (s->output_channels == 6 && s->input_channels == 2) {
+ ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1);
+ } else if ((s->output_channels == s->input_channels && s->input_channels >= 2) ||
+ (s->output_channels == 2 && s->input_channels == 6)) {
+ interleave(output, buftmp3, s->output_channels, nb_samples1);
+ }
+
+ if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) {
+ int istride[1] = { 2 };
+ int ostride[1] = { s->sample_size[1] };
+ const void *ibuf[1] = { output };
+ void *obuf[1] = { output_bak };
+
+ if (av_audio_convert(s->convert_ctx[1], obuf, ostride,
+ ibuf, istride, nb_samples1 * s->output_channels) < 0) {
+ av_log(s->resample_context, AV_LOG_ERROR,
+ "Audio sample format conversion failed\n");
+ return 0;
+ }
+ }
+
+fail:
+ for (i = 0; i < s->filter_channels; i++) {
+ av_free(bufin[i]);
+ av_free(bufout[i]);
+ }
+
+ return nb_samples1;
+}
+
+void audio_resample_close(ReSampleContext *s)
+{
+ int i;
+ av_resample_close(s->resample_context);
+ for (i = 0; i < s->filter_channels; i++)
+ av_freep(&s->temp[i]);
+ av_freep(&s->buffer[0]);
+ av_freep(&s->buffer[1]);
+ av_audio_convert_free(s->convert_ctx[0]);
+ av_audio_convert_free(s->convert_ctx[1]);
+ av_free(s);
+}
+
+#endif
diff --git a/libavcodec/resample2.c b/libavcodec/resample2.c
new file mode 100644
index 0000000000..cd9fe1ce56
--- /dev/null
+++ b/libavcodec/resample2.c
@@ -0,0 +1,319 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio resampling
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "libavutil/avassert.h"
+#include "avcodec.h"
+#include "libavutil/common.h"
+
+#if FF_API_AVCODEC_RESAMPLE
+
+#ifndef CONFIG_RESAMPLE_HP
+#define FILTER_SHIFT 15
+
+#define FELEM int16_t
+#define FELEM2 int32_t
+#define FELEML int64_t
+#define FELEM_MAX INT16_MAX
+#define FELEM_MIN INT16_MIN
+#define WINDOW_TYPE 9
+#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE)
+#define FILTER_SHIFT 30
+
+#define FELEM int32_t
+#define FELEM2 int64_t
+#define FELEML int64_t
+#define FELEM_MAX INT32_MAX
+#define FELEM_MIN INT32_MIN
+#define WINDOW_TYPE 12
+#else
+#define FILTER_SHIFT 0
+
+#define FELEM double
+#define FELEM2 double
+#define FELEML double
+#define WINDOW_TYPE 24
+#endif
+
+
+typedef struct AVResampleContext{
+ const AVClass *av_class;
+ FELEM *filter_bank;
+ int filter_length;
+ int ideal_dst_incr;
+ int dst_incr;
+ int index;
+ int frac;
+ int src_incr;
+ int compensation_distance;
+ int phase_shift;
+ int phase_mask;
+ int linear;
+}AVResampleContext;
+
+/**
+ * 0th order modified bessel function of the first kind.
+ */
+static double bessel(double x){
+ double v=1;
+ double lastv=0;
+ double t=1;
+ int i;
+
+ x= x*x/4;
+ for(i=1; v != lastv; i++){
+ lastv=v;
+ t *= x/(i*i);
+ v += t;
+ }
+ return v;
+}
+
+/**
+ * Build a polyphase filterbank.
+ * @param factor resampling factor
+ * @param scale wanted sum of coefficients for each filter
+ * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16
+ * @return 0 on success, negative on error
+ */
+static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){
+ int ph, i;
+ double x, y, w;
+ double *tab = av_malloc_array(tap_count, sizeof(*tab));
+ const int center= (tap_count-1)/2;
+
+ if (!tab)
+ return AVERROR(ENOMEM);
+
+ /* if upsampling, only need to interpolate, no filter */
+ if (factor > 1.0)
+ factor = 1.0;
+
+ for(ph=0;ph<phase_count;ph++) {
+ double norm = 0;
+ for(i=0;i<tap_count;i++) {
+ x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
+ if (x == 0) y = 1.0;
+ else y = sin(x) / x;
+ switch(type){
+ case 0:{
+ const float d= -0.5; //first order derivative = -0.5
+ x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
+ if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
+ else y= d*(-4 + 8*x - 5*x*x + x*x*x);
+ break;}
+ case 1:
+ w = 2.0*x / (factor*tap_count) + M_PI;
+ y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
+ break;
+ default:
+ w = 2.0*x / (factor*tap_count*M_PI);
+ y *= bessel(type*sqrt(FFMAX(1-w*w, 0)));
+ break;
+ }
+
+ tab[i] = y;
+ norm += y;
+ }
+
+ /* normalize so that an uniform color remains the same */
+ for(i=0;i<tap_count;i++) {
+#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
+ filter[ph * tap_count + i] = tab[i] / norm;
+#else
+ filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), FELEM_MIN, FELEM_MAX);
+#endif
+ }
+ }
+#if 0
+ {
+#define LEN 1024
+ int j,k;
+ double sine[LEN + tap_count];
+ double filtered[LEN];
+ double maxff=-2, minff=2, maxsf=-2, minsf=2;
+ for(i=0; i<LEN; i++){
+ double ss=0, sf=0, ff=0;
+ for(j=0; j<LEN+tap_count; j++)
+ sine[j]= cos(i*j*M_PI/LEN);
+ for(j=0; j<LEN; j++){
+ double sum=0;
+ ph=0;
+ for(k=0; k<tap_count; k++)
+ sum += filter[ph * tap_count + k] * sine[k+j];
+ filtered[j]= sum / (1<<FILTER_SHIFT);
+ ss+= sine[j + center] * sine[j + center];
+ ff+= filtered[j] * filtered[j];
+ sf+= sine[j + center] * filtered[j];
+ }
+ ss= sqrt(2*ss/LEN);
+ ff= sqrt(2*ff/LEN);
+ sf= 2*sf/LEN;
+ maxff= FFMAX(maxff, ff);
+ minff= FFMIN(minff, ff);
+ maxsf= FFMAX(maxsf, sf);
+ minsf= FFMIN(minsf, sf);
+ if(i%11==0){
+ av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf);
+ minff=minsf= 2;
+ maxff=maxsf= -2;
+ }
+ }
+ }
+#endif
+
+ av_free(tab);
+ return 0;
+}
+
+AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_size, int phase_shift, int linear, double cutoff){
+ AVResampleContext *c= av_mallocz(sizeof(AVResampleContext));
+ double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
+ int phase_count= 1<<phase_shift;
+
+ if (!c)
+ return NULL;
+
+ c->phase_shift= phase_shift;
+ c->phase_mask= phase_count-1;
+ c->linear= linear;
+
+ c->filter_length= FFMAX((int)ceil(filter_size/factor), 1);
+ c->filter_bank= av_mallocz_array(c->filter_length, (phase_count+1)*sizeof(FELEM));
+ if (!c->filter_bank)
+ goto error;
+ if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<<FILTER_SHIFT, WINDOW_TYPE))
+ goto error;
+ memcpy(&c->filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM));
+ c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1];
+
+ if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2))
+ goto error;
+ c->ideal_dst_incr= c->dst_incr;
+
+ c->index= -phase_count*((c->filter_length-1)/2);
+
+ return c;
+error:
+ av_free(c->filter_bank);
+ av_free(c);
+ return NULL;
+}
+
+void av_resample_close(AVResampleContext *c){
+ av_freep(&c->filter_bank);
+ av_freep(&c);
+}
+
+void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){
+// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr;
+ c->compensation_distance= compensation_distance;
+ c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance;
+}
+
+int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){
+ int dst_index, i;
+ int index= c->index;
+ int frac= c->frac;
+ int dst_incr_frac= c->dst_incr % c->src_incr;
+ int dst_incr= c->dst_incr / c->src_incr;
+ int compensation_distance= c->compensation_distance;
+
+ if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){
+ int64_t index2= ((int64_t)index)<<32;
+ int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr;
+ dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr);
+
+ for(dst_index=0; dst_index < dst_size; dst_index++){
+ dst[dst_index] = src[index2>>32];
+ index2 += incr;
+ }
+ index += dst_index * dst_incr;
+ index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr;
+ frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr;
+ }else{
+ for(dst_index=0; dst_index < dst_size; dst_index++){
+ FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask);
+ int sample_index= index >> c->phase_shift;
+ FELEM2 val=0;
+
+ if(sample_index < 0){
+ for(i=0; i<c->filter_length; i++)
+ val += src[FFABS(sample_index + i) % src_size] * filter[i];
+ }else if(sample_index + c->filter_length > src_size){
+ break;
+ }else if(c->linear){
+ FELEM2 v2=0;
+ for(i=0; i<c->filter_length; i++){
+ val += src[sample_index + i] * (FELEM2)filter[i];
+ v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length];
+ }
+ val+=(v2-val)*(FELEML)frac / c->src_incr;
+ }else{
+ for(i=0; i<c->filter_length; i++){
+ val += src[sample_index + i] * (FELEM2)filter[i];
+ }
+ }
+
+#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE
+ dst[dst_index] = av_clip_int16(lrintf(val));
+#else
+ val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;
+ dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val;
+#endif
+
+ frac += dst_incr_frac;
+ index += dst_incr;
+ if(frac >= c->src_incr){
+ frac -= c->src_incr;
+ index++;
+ }
+
+ if(dst_index + 1 == compensation_distance){
+ compensation_distance= 0;
+ dst_incr_frac= c->ideal_dst_incr % c->src_incr;
+ dst_incr= c->ideal_dst_incr / c->src_incr;
+ }
+ }
+ }
+ *consumed= FFMAX(index, 0) >> c->phase_shift;
+ if(index>=0) index &= c->phase_mask;
+
+ if(compensation_distance){
+ compensation_distance -= dst_index;
+ av_assert2(compensation_distance > 0);
+ }
+ if(update_ctx){
+ c->frac= frac;
+ c->index= index;
+ c->dst_incr= dst_incr_frac + c->src_incr*dst_incr;
+ c->compensation_distance= compensation_distance;
+ }
+
+ return dst_index;
+}
+
+#endif
diff --git a/libavcodec/rl.h b/libavcodec/rl.h
index 367cc986af..2897ec5aa1 100644
--- a/libavcodec/rl.h
+++ b/libavcodec/rl.h
@@ -2,20 +2,20 @@
* Copyright (c) 2000-2002 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,7 +44,6 @@ typedef struct RLTable {
uint8_t *index_run[2]; ///< encoding only
int8_t *max_level[2]; ///< encoding & decoding
int8_t *max_run[2]; ///< encoding & decoding
- VLC vlc; ///< decoding only deprecated FIXME remove
RL_VLC_ELEM *rl_vlc[32]; ///< decoding only
} RLTable;
@@ -54,21 +53,18 @@ typedef struct RLTable {
* the level and run tables, if this is NULL av_malloc() will be used
*/
void ff_init_rl(RLTable *rl, uint8_t static_store[2][2*MAX_RUN + MAX_LEVEL + 3]);
-void ff_init_vlc_rl(RLTable *rl);
+void ff_init_vlc_rl(RLTable *rl, unsigned static_size);
#define INIT_VLC_RL(rl, static_size)\
{\
int q;\
static RL_VLC_ELEM rl_vlc_table[32][static_size];\
- INIT_VLC_STATIC(&rl.vlc, 9, rl.n + 1,\
- &rl.table_vlc[0][1], 4, 2,\
- &rl.table_vlc[0][0], 4, 2, static_size);\
\
if(!rl.rl_vlc[0]){\
for(q=0; q<32; q++)\
rl.rl_vlc[q]= rl_vlc_table[q];\
\
- ff_init_vlc_rl(&rl);\
+ ff_init_vlc_rl(&rl, static_size);\
}\
}
diff --git a/libavcodec/rl2.c b/libavcodec/rl2.c
index 54b3e6a010..eaf31b63a0 100644
--- a/libavcodec/rl2.c
+++ b/libavcodec/rl2.c
@@ -2,20 +2,20 @@
* RL2 Video Decoder
* Copyright (C) 2008 Sascha Sommer (saschasommer@freenet.de)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -53,7 +53,7 @@ typedef struct Rl2Context {
* @param s rl2 context
* @param in input buffer
* @param size input buffer size
- * @param out ouput buffer
+ * @param out output buffer
* @param stride stride of the output buffer
* @param video_base offset of the rle data inside the frame
*/
@@ -155,7 +155,7 @@ static av_cold int rl2_decode_init(AVCodecContext *avctx)
/** initialize palette */
for (i = 0; i < AVPALETTE_COUNT; i++)
- s->palette[i] = AV_RB24(&avctx->extradata[6 + i * 3]);
+ s->palette[i] = 0xFFU << 24 | AV_RB24(&avctx->extradata[6 + i * 3]);
/** decode background frame if present */
back_size = avctx->extradata_size - EXTRADATA1_SIZE;
@@ -181,10 +181,8 @@ static int rl2_decode_frame(AVCodecContext *avctx,
int ret, buf_size = avpkt->size;
Rl2Context *s = avctx->priv_data;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
/** run length decode */
rl2_rle_decode(s, buf, buf_size, frame->data[0], frame->linesize[0],
@@ -209,7 +207,7 @@ static av_cold int rl2_decode_end(AVCodecContext *avctx)
{
Rl2Context *s = avctx->priv_data;
- av_free(s->back_frame);
+ av_freep(&s->back_frame);
return 0;
}
diff --git a/libavcodec/rle.c b/libavcodec/rle.c
index cbbde93f56..d2ec68c407 100644
--- a/libavcodec/rle.c
+++ b/libavcodec/rle.c
@@ -2,20 +2,20 @@
* RLE encoder
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
diff --git a/libavcodec/rle.h b/libavcodec/rle.h
index 00261d3598..24851321fe 100644
--- a/libavcodec/rle.h
+++ b/libavcodec/rle.h
@@ -1,20 +1,20 @@
/*
* RLE encoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rnd_avg.h b/libavcodec/rnd_avg.h
index 412cda5203..344775e31f 100644
--- a/libavcodec/rnd_avg.h
+++ b/libavcodec/rnd_avg.h
@@ -1,18 +1,21 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2001-2003 BERO <bero@geocities.co.jp>
+ * Copyright (c) 2011 Oskar Arvidsson
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/roqaudioenc.c b/libavcodec/roqaudioenc.c
index 936b809e39..c373ccca47 100644
--- a/libavcodec/roqaudioenc.c
+++ b/libavcodec/roqaudioenc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2005 Eric Lasota
* Based on RoQ specs (c)2001 Tim Ferguson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -160,10 +160,8 @@ static int roq_dpcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
else
data_size = avctx->channels * avctx->frame_size;
- if ((ret = ff_alloc_packet(avpkt, ROQ_HEADER_SIZE + data_size))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, ROQ_HEADER_SIZE + data_size)) < 0)
return ret;
- }
out = avpkt->data;
bytestream_put_byte(&out, stereo ? 0x21 : 0x20);
diff --git a/libavcodec/roqvideo.c b/libavcodec/roqvideo.c
index b0fd6ba7f3..8eda93c13c 100644
--- a/libavcodec/roqvideo.c
+++ b/libavcodec/roqvideo.c
@@ -2,20 +2,20 @@
* Copyright (C) 2003 Mike Melanson
* Copyright (C) 2003 Dr. Tim Ferguson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/roqvideo.h b/libavcodec/roqvideo.h
index 3f000225e9..3da6eaa991 100644
--- a/libavcodec/roqvideo.h
+++ b/libavcodec/roqvideo.h
@@ -2,20 +2,20 @@
* Copyright (C) 2003 Mike Melanson
* Copyright (C) 2003 Dr. Tim Ferguson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,6 +43,7 @@ struct RoqTempData;
typedef struct RoqContext {
+ const AVClass *class;
AVCodecContext *avctx;
AVFrame *last_frame;
AVFrame *current_frame;
@@ -69,6 +70,9 @@ typedef struct RoqContext {
const AVFrame *frame_to_enc;
uint8_t *out_buf;
struct RoqTempData *tmpData;
+
+ int quake3_compat; // Quake 3 compatibility option
+
} RoqContext;
#define RoQ_INFO 0x1001
diff --git a/libavcodec/roqvideodec.c b/libavcodec/roqvideodec.c
index ac7d4bafe0..b716e258ee 100644
--- a/libavcodec/roqvideodec.c
+++ b/libavcodec/roqvideodec.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,10 +25,7 @@
* http://www.csse.monash.edu.au/~timf/
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
@@ -72,9 +69,19 @@ static void roqvideo_decode_frame(RoqContext *ri)
chunk_start = bytestream2_tell(&ri->gb);
xpos = ypos = 0;
+
+ if (chunk_size > bytestream2_get_bytes_left(&ri->gb)) {
+ av_log(ri->avctx, AV_LOG_ERROR, "Chunk does not fit in input buffer\n");
+ chunk_size = bytestream2_get_bytes_left(&ri->gb);
+ }
+
while (bytestream2_tell(&ri->gb) < chunk_start + chunk_size) {
for (yp = ypos; yp < ypos + 16; yp += 8)
for (xp = xpos; xp < xpos + 16; xp += 8) {
+ if (bytestream2_tell(&ri->gb) >= chunk_start + chunk_size) {
+ av_log(ri->avctx, AV_LOG_VERBOSE, "Chunk is too short\n");
+ return;
+ }
if (vqflg_pos < 0) {
vqflg = bytestream2_get_le16(&ri->gb);
vqflg_pos = 7;
@@ -106,6 +113,10 @@ static void roqvideo_decode_frame(RoqContext *ri)
if(k & 0x01) x += 4;
if(k & 0x02) y += 4;
+ if (bytestream2_tell(&ri->gb) >= chunk_start + chunk_size) {
+ av_log(ri->avctx, AV_LOG_VERBOSE, "Chunk is too short\n");
+ return;
+ }
if (vqflg_pos < 0) {
vqflg = bytestream2_get_le16(&ri->gb);
vqflg_pos = 7;
@@ -140,7 +151,7 @@ static void roqvideo_decode_frame(RoqContext *ri)
}
break;
default:
- av_log(ri->avctx, AV_LOG_ERROR, "Unknown vq code: %d\n", vqid);
+ av_assert2(0);
}
}
@@ -178,7 +189,8 @@ static av_cold int roq_decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
}
- avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+ avctx->pix_fmt = AV_PIX_FMT_YUVJ444P;
+ avctx->color_range = AVCOL_RANGE_JPEG;
return 0;
}
@@ -193,10 +205,8 @@ static int roq_decode_frame(AVCodecContext *avctx,
int copy= !s->current_frame->data[0];
int ret;
- if ((ret = ff_reget_buffer(avctx, s->current_frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->current_frame)) < 0)
return ret;
- }
if(copy)
av_picture_copy((AVPicture*)s->current_frame, (AVPicture*)s->last_frame,
diff --git a/libavcodec/roqvideoenc.c b/libavcodec/roqvideoenc.c
index 872bee8c1a..89879e81b3 100644
--- a/libavcodec/roqvideoenc.c
+++ b/libavcodec/roqvideoenc.c
@@ -5,27 +5,27 @@
* Copyright (C) 2004-2007 Eric Lasota
* Based on RoQ specs (C) 2001 Tim Ferguson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* id RoQ encoder by Vitor. Based on the Switchblade3 library and the
- * Switchblade3 Libav glue by Eric Lasota.
+ * Switchblade3 FFmpeg glue by Eric Lasota.
*/
/*
@@ -57,6 +57,7 @@
#include <string.h>
#include "libavutil/attributes.h"
+#include "libavutil/opt.h"
#include "roqvideo.h"
#include "bytestream.h"
#include "elbg.h"
@@ -69,7 +70,7 @@
* Maximum number of generated 4x4 codebooks. Can't be 256 to workaround a
* Quake 3 bug.
*/
-#define MAX_CBS_4x4 255
+#define MAX_CBS_4x4 256
#define MAX_CBS_2x2 256 ///< Maximum number of 2x2 codebooks.
@@ -245,7 +246,7 @@ static int create_cel_evals(RoqContext *enc, RoqTempdata *tempData)
{
int n=0, x, y, i;
- tempData->cel_evals = av_malloc(enc->width*enc->height/64 * sizeof(CelEvaluation));
+ tempData->cel_evals = av_malloc_array(enc->width*enc->height/64, sizeof(CelEvaluation));
if (!tempData->cel_evals)
return AVERROR(ENOMEM);
@@ -541,7 +542,7 @@ static void remap_codebooks(RoqContext *enc, RoqTempdata *tempData)
int i, j, idx=0;
/* Make remaps for the final codebook usage */
- for (i=0; i<MAX_CBS_4x4; i++) {
+ for (i=0; i<(enc->quake3_compat ? MAX_CBS_4x4-1 : MAX_CBS_4x4); i++) {
if (tempData->codebooks.usedCB4[i]) {
tempData->i2f4[i] = idx;
tempData->f2i4[idx] = i;
@@ -798,14 +799,14 @@ static int generate_codebook(RoqContext *enc, RoqTempdata *tempdata,
int i, j, k, ret = 0;
int c_size = size*size/4;
int *buf;
- int *codebook = av_malloc(6*c_size*cbsize*sizeof(int));
+ int *codebook = av_malloc_array(6*c_size, cbsize*sizeof(int));
int *closest_cb;
if (!codebook)
return AVERROR(ENOMEM);
if (size == 4) {
- closest_cb = av_malloc(6*c_size*inputCount*sizeof(int));
+ closest_cb = av_malloc_array(6*c_size, inputCount*sizeof(int));
if (!closest_cb) {
ret = AVERROR(ENOMEM);
goto out;
@@ -813,11 +814,11 @@ static int generate_codebook(RoqContext *enc, RoqTempdata *tempdata,
} else
closest_cb = tempdata->closest_cb2;
- ret = ff_init_elbg(points, 6 * c_size, inputCount, codebook,
+ ret = avpriv_init_elbg(points, 6 * c_size, inputCount, codebook,
cbsize, 1, closest_cb, &enc->randctx);
if (ret < 0)
goto out;
- ret = ff_do_elbg(points, 6 * c_size, inputCount, codebook,
+ ret = avpriv_do_elbg(points, 6 * c_size, inputCount, codebook,
cbsize, 1, closest_cb, &enc->randctx);
if (ret < 0)
goto out;
@@ -846,8 +847,8 @@ static int generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData)
int max = enc->width*enc->height/16;
uint8_t mb2[3*4];
roq_cell *results4 = av_malloc(sizeof(roq_cell)*MAX_CBS_4x4*4);
- uint8_t *yuvClusters=av_malloc(sizeof(int)*max*6*4);
- int *points = av_malloc(max*6*4*sizeof(int));
+ uint8_t *yuvClusters=av_malloc_array(max, sizeof(int)*6*4);
+ int *points = av_malloc_array(max, 6*4*sizeof(int));
int bias;
if (!results4 || !yuvClusters || !points) {
@@ -866,12 +867,12 @@ static int generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData)
/* Create 4x4 codebooks */
if ((ret = generate_codebook(enc, tempData, points, max,
- results4, 4, MAX_CBS_4x4)) < 0)
+ results4, 4, (enc->quake3_compat ? MAX_CBS_4x4-1 : MAX_CBS_4x4))) < 0)
goto out;
- codebooks->numCB4 = MAX_CBS_4x4;
+ codebooks->numCB4 = (enc->quake3_compat ? MAX_CBS_4x4-1 : MAX_CBS_4x4);
- tempData->closest_cb2 = av_malloc(max*4*sizeof(int));
+ tempData->closest_cb2 = av_malloc_array(max, 4*sizeof(int));
if (!tempData->closest_cb2) {
ret = AVERROR(ENOMEM);
goto out;
@@ -932,10 +933,14 @@ static int roq_encode_video(RoqContext *enc)
gather_data_for_cel(tempData->cel_evals + i, enc, tempData);
/* Quake 3 can't handle chunks bigger than 65535 bytes */
- if (tempData->mainChunkSize/8 > 65535) {
+ if (tempData->mainChunkSize/8 > 65535 && enc->quake3_compat) {
+ if (enc->lambda > 100000) {
+ av_log(enc->avctx, AV_LOG_ERROR, "Cannot encode video in Quake compatible form\n");
+ return AVERROR(EINVAL);
+ }
av_log(enc->avctx, AV_LOG_ERROR,
- "Warning, generated a frame too big (%d > 65535), "
- "try using a smaller qscale value.\n",
+ "Warning, generated a frame too big for Quake (%d > 65535), "
+ "now switching to a bigger qscale value.\n",
tempData->mainChunkSize/8);
enc->lambda *= 1.5;
tempData->mainChunkSize = 0;
@@ -955,15 +960,16 @@ static int roq_encode_video(RoqContext *enc)
reconstruct_and_encode_image(enc, tempData, enc->width, enc->height,
enc->width*enc->height/64);
- enc->avctx->coded_frame = enc->current_frame;
+ av_frame_unref(enc->avctx->coded_frame);
+ av_frame_ref(enc->avctx->coded_frame, enc->current_frame);
/* Rotate frame history */
FFSWAP(AVFrame *, enc->current_frame, enc->last_frame);
FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4);
FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8);
- av_free(tempData->cel_evals);
- av_free(tempData->closest_cb2);
+ av_freep(&tempData->cel_evals);
+ av_freep(&tempData->closest_cb2);
enc->framesSinceKeyframe++;
@@ -976,12 +982,13 @@ static av_cold int roq_encode_end(AVCodecContext *avctx)
av_frame_free(&enc->current_frame);
av_frame_free(&enc->last_frame);
+ av_frame_free(&enc->avctx->coded_frame);
- av_free(enc->tmpData);
- av_free(enc->this_motion4);
- av_free(enc->last_motion4);
- av_free(enc->this_motion8);
- av_free(enc->last_motion8);
+ av_freep(&enc->tmpData);
+ av_freep(&enc->this_motion4);
+ av_freep(&enc->last_motion4);
+ av_freep(&enc->this_motion8);
+ av_freep(&enc->last_motion8);
return 0;
}
@@ -997,11 +1004,16 @@ static av_cold int roq_encode_init(AVCodecContext *avctx)
enc->framesSinceKeyframe = 0;
if ((avctx->width & 0xf) || (avctx->height & 0xf)) {
av_log(avctx, AV_LOG_ERROR, "Dimensions must be divisible by 16\n");
- return -1;
+ return AVERROR(EINVAL);
+ }
+
+ if (avctx->width > 65535 || avctx->height > 65535) {
+ av_log(avctx, AV_LOG_ERROR, "Dimensions are max %d\n", enc->quake3_compat ? 32768 : 65535);
+ return AVERROR(EINVAL);
}
if (((avctx->width)&(avctx->width-1))||((avctx->height)&(avctx->height-1)))
- av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two\n");
+ av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two, this is not supported by quake\n");
enc->width = avctx->width;
enc->height = avctx->height;
@@ -1011,7 +1023,8 @@ static av_cold int roq_encode_init(AVCodecContext *avctx)
enc->last_frame = av_frame_alloc();
enc->current_frame = av_frame_alloc();
- if (!enc->last_frame || !enc->current_frame) {
+ avctx->coded_frame = av_frame_alloc();
+ if (!enc->last_frame || !enc->current_frame || !avctx->coded_frame) {
roq_encode_end(avctx);
return AVERROR(ENOMEM);
}
@@ -1019,16 +1032,22 @@ static av_cold int roq_encode_init(AVCodecContext *avctx)
enc->tmpData = av_malloc(sizeof(RoqTempdata));
enc->this_motion4 =
- av_mallocz((enc->width*enc->height/16)*sizeof(motion_vect));
+ av_mallocz_array((enc->width*enc->height/16), sizeof(motion_vect));
enc->last_motion4 =
- av_malloc ((enc->width*enc->height/16)*sizeof(motion_vect));
+ av_malloc_array ((enc->width*enc->height/16), sizeof(motion_vect));
enc->this_motion8 =
- av_mallocz((enc->width*enc->height/64)*sizeof(motion_vect));
+ av_mallocz_array((enc->width*enc->height/64), sizeof(motion_vect));
enc->last_motion8 =
- av_malloc ((enc->width*enc->height/64)*sizeof(motion_vect));
+ av_malloc_array ((enc->width*enc->height/64), sizeof(motion_vect));
+
+ if (!enc->tmpData || !enc->this_motion4 || !enc->last_motion4 ||
+ !enc->this_motion8 || !enc->last_motion8) {
+ roq_encode_end(avctx);
+ return AVERROR(ENOMEM);
+ }
return 0;
}
@@ -1076,10 +1095,8 @@ static int roq_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* 138 bits max per 8x8 block +
* 256 codebooks*(6 bytes 2x2 + 4 bytes 4x4) + 8 bytes frame header */
size = ((enc->width * enc->height / 64) * 138 + 7) / 8 + 256 * (6 + 4) + 8;
- if ((ret = ff_alloc_packet(pkt, size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet with size %d.\n", size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, size)) < 0)
return ret;
- }
enc->out_buf = pkt->data;
/* Check for I frame */
@@ -1089,11 +1106,9 @@ static int roq_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (enc->first_frame) {
/* Alloc memory for the reconstruction data (we must know the stride
for that) */
- if (ff_get_buffer(avctx, enc->current_frame, 0) ||
- ff_get_buffer(avctx, enc->last_frame, 0)) {
- av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_get_buffer(avctx, enc->current_frame, 0)) < 0 ||
+ (ret = ff_get_buffer(avctx, enc->last_frame, 0)) < 0)
+ return ret;
/* Before the first video frame, write a "video info" chunk */
roq_write_video_info_chunk(enc);
@@ -1114,6 +1129,20 @@ static int roq_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
+#define OFFSET(x) offsetof(RoqContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "quake3_compat", "Whether to respect known limitations in Quake 3 decoder", OFFSET(quake3_compat), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
+ { NULL },
+};
+
+static const AVClass roq_class = {
+ .class_name = "RoQ",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_roq_encoder = {
.name = "roqvideo",
.long_name = NULL_IF_CONFIG_SMALL("id RoQ video"),
@@ -1123,7 +1152,7 @@ AVCodec ff_roq_encoder = {
.init = roq_encode_init,
.encode2 = roq_encode_frame,
.close = roq_encode_end,
- .supported_framerates = (const AVRational[]){ {30,1}, {0,0} },
- .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVJ444P,
AV_PIX_FMT_NONE },
+ .priv_class = &roq_class,
};
diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c
index 83dde7a9c3..732b09ac94 100644
--- a/libavcodec/rpza.c
+++ b/libavcodec/rpza.c
@@ -1,21 +1,21 @@
/*
* Quicktime Video (RPZA) Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,7 +80,7 @@ static void rpza_decode_stream(RpzaContext *s)
uint16_t *pixels = (uint16_t *)s->frame->data[0];
int row_ptr = 0;
- int pixel_ptr = 0;
+ int pixel_ptr = -4;
int block_ptr;
int pixel_x, pixel_y;
int total_blocks;
@@ -94,8 +94,12 @@ static void rpza_decode_stream(RpzaContext *s)
chunk_size = bytestream2_get_be32(&s->gb) & 0x00FFFFFF;
/* If length mismatch use size from MOV file and try to decode anyway */
- if (chunk_size != bytestream2_get_bytes_left(&s->gb) - 4)
- av_log(s->avctx, AV_LOG_WARNING, "MOV chunk size != encoded chunk size\n");
+ if (chunk_size != bytestream2_get_bytes_left(&s->gb) + 4)
+ av_log(s->avctx, AV_LOG_WARNING,
+ "MOV chunk size %d != encoded chunk size %d\n",
+ chunk_size,
+ bytestream2_get_bytes_left(&s->gb) + 4
+ );
/* Number of 4x4 blocks in frame. */
total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
@@ -134,6 +138,7 @@ static void rpza_decode_stream(RpzaContext *s)
case 0xa0:
colorA = bytestream2_get_be16(&s->gb);
while (n_blocks--) {
+ ADVANCE_BLOCK()
block_ptr = row_ptr + pixel_ptr;
for (pixel_y = 0; pixel_y < 4; pixel_y++) {
for (pixel_x = 0; pixel_x < 4; pixel_x++){
@@ -142,7 +147,6 @@ static void rpza_decode_stream(RpzaContext *s)
}
block_ptr += row_inc;
}
- ADVANCE_BLOCK();
}
break;
@@ -179,6 +183,7 @@ static void rpza_decode_stream(RpzaContext *s)
if (bytestream2_get_bytes_left(&s->gb) < n_blocks * 4)
return;
while (n_blocks--) {
+ ADVANCE_BLOCK();
block_ptr = row_ptr + pixel_ptr;
for (pixel_y = 0; pixel_y < 4; pixel_y++) {
uint8_t index = bytestream2_get_byteu(&s->gb);
@@ -189,7 +194,6 @@ static void rpza_decode_stream(RpzaContext *s)
}
block_ptr += row_inc;
}
- ADVANCE_BLOCK();
}
break;
@@ -197,6 +201,7 @@ static void rpza_decode_stream(RpzaContext *s)
case 0x00:
if (bytestream2_get_bytes_left(&s->gb) < 30)
return;
+ ADVANCE_BLOCK();
block_ptr = row_ptr + pixel_ptr;
for (pixel_y = 0; pixel_y < 4; pixel_y++) {
for (pixel_x = 0; pixel_x < 4; pixel_x++){
@@ -208,7 +213,6 @@ static void rpza_decode_stream(RpzaContext *s)
}
block_ptr += row_inc;
}
- ADVANCE_BLOCK();
break;
/* Unknown opcode */
@@ -244,10 +248,8 @@ static int rpza_decode_frame(AVCodecContext *avctx,
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
rpza_decode_stream(s);
diff --git a/libavcodec/rtjpeg.c b/libavcodec/rtjpeg.c
index 67eeff8f4a..8e02bce2e8 100644
--- a/libavcodec/rtjpeg.c
+++ b/libavcodec/rtjpeg.c
@@ -2,20 +2,20 @@
* RTJpeg decoding functions
* Copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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"
diff --git a/libavcodec/rtjpeg.h b/libavcodec/rtjpeg.h
index cd300797c5..d22ff4070e 100644
--- a/libavcodec/rtjpeg.h
+++ b/libavcodec/rtjpeg.h
@@ -2,20 +2,20 @@
* RTJpeg decoding functions
* copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv10.c b/libavcodec/rv10.c
index 20230f40bd..707b38e3aa 100644
--- a/libavcodec/rv10.c
+++ b/libavcodec/rv10.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -305,7 +305,7 @@ static int rv20_decode_picture_header(RVDecContext *rv)
{
MpegEncContext *s = &rv->m;
int seq, mb_pos, i, ret;
- int rpr_bits;
+ int rpr_max;
i = get_bits(&s->gb, 2);
switch (i) {
@@ -326,6 +326,10 @@ static int rv20_decode_picture_header(RVDecContext *rv)
return AVERROR_INVALIDDATA;
}
+ if (s->low_delay && s->pict_type == AV_PICTURE_TYPE_B) {
+ 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) {
av_log(s->avctx, AV_LOG_ERROR, "early B-frame\n");
return AVERROR_INVALIDDATA;
@@ -343,17 +347,17 @@ static int rv20_decode_picture_header(RVDecContext *rv)
}
if (RV_GET_MINOR_VER(rv->sub_id) >= 2)
- s->loop_filter = get_bits1(&s->gb);
+ s->loop_filter = get_bits1(&s->gb) && !s->avctx->lowres;
if (RV_GET_MINOR_VER(rv->sub_id) <= 1)
seq = get_bits(&s->gb, 8) << 7;
else
seq = get_bits(&s->gb, 13) << 2;
- rpr_bits = s->avctx->extradata[1] & 7;
- if (rpr_bits) {
+ rpr_max = s->avctx->extradata[1] & 7;
+ if (rpr_max) {
int f, new_w, new_h;
- rpr_bits = FFMIN((rpr_bits >> 1) + 1, 3);
+ int rpr_bits = av_log2(rpr_max) + 1;
f = get_bits(&s->gb, rpr_bits);
@@ -370,10 +374,21 @@ static int rv20_decode_picture_header(RVDecContext *rv)
new_h = rv->orig_height;
}
if (new_w != s->width || new_h != s->height) {
+ AVRational old_aspect = s->avctx->sample_aspect_ratio;
av_log(s->avctx, AV_LOG_DEBUG,
"attempting to change resolution to %dx%d\n", new_w, new_h);
+ if (av_image_check_size(new_w, new_h, 0, s->avctx) < 0)
+ return AVERROR_INVALIDDATA;
ff_mpv_common_end(s);
+ // attempt to keep aspect during typical resolution switches
+ if (!old_aspect.num)
+ old_aspect = (AVRational){1, 1};
+ if (2 * new_w * s->height == new_h * s->width)
+ s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){2, 1});
+ if (new_w * s->height == 2 * new_h * s->width)
+ s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){1, 2});
+
ret = ff_set_dimensions(s->avctx, new_w, new_h);
if (ret < 0)
return ret;
@@ -385,9 +400,10 @@ static int rv20_decode_picture_header(RVDecContext *rv)
}
if (s->avctx->debug & FF_DEBUG_PICT_INFO) {
- av_log(s->avctx, AV_LOG_DEBUG, "F %d/%d\n", f, rpr_bits);
+ av_log(s->avctx, AV_LOG_DEBUG, "F %d/%d/%d\n", f, rpr_bits, rpr_max);
}
- } else if (av_image_check_size(s->width, s->height, 0, s->avctx) < 0)
+ }
+ if (av_image_check_size(s->width, s->height, 0, s->avctx) < 0)
return AVERROR_INVALIDDATA;
mb_pos = ff_h263_decode_mba(s);
@@ -406,15 +422,17 @@ static int rv20_decode_picture_header(RVDecContext *rv)
} else {
s->time = seq;
s->pb_time = s->pp_time - (s->last_non_b_time - s->time);
- if (s->pp_time <= s->pb_time ||
- s->pp_time <= s->pp_time - s->pb_time || s->pp_time <= 0) {
- av_log(s->avctx, AV_LOG_DEBUG, "messed up order, possible "
- "from seeking? skipping current b frame\n");
- return FRAME_SKIPPED;
- }
- ff_mpeg4_init_direct_mv(s);
}
}
+ if (s->pict_type == AV_PICTURE_TYPE_B) {
+ if (s->pp_time <=s->pb_time || s->pp_time <= s->pp_time - s->pb_time || s->pp_time<=0) {
+ av_log(s->avctx, AV_LOG_DEBUG,
+ "messed up order, possible from seeking? skipping current b frame\n");
+#define ERROR_SKIP_FRAME -123
+ return ERROR_SKIP_FRAME;
+ }
+ ff_mpeg4_init_direct_mv(s);
+ }
s->no_rounding = get_bits1(&s->gb);
@@ -426,7 +444,8 @@ static int rv20_decode_picture_header(RVDecContext *rv)
s->unrestricted_mv = 1;
s->h263_aic = s->pict_type == AV_PICTURE_TYPE_I;
s->modified_quant = 1;
- s->loop_filter = 1;
+ if (!s->avctx->lowres)
+ s->loop_filter = 1;
if (s->avctx->debug & FF_DEBUG_PICT_INFO) {
av_log(s->avctx, AV_LOG_INFO,
@@ -435,7 +454,7 @@ static int rv20_decode_picture_header(RVDecContext *rv)
s->no_rounding);
}
- assert(s->pict_type != AV_PICTURE_TYPE_B || !s->low_delay);
+ av_assert0(s->pict_type != AV_PICTURE_TYPE_B || !s->low_delay);
return s->mb_width * s->mb_height - mb_pos;
}
@@ -456,10 +475,9 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx)
return ret;
ff_mpv_decode_defaults(s);
+ ff_mpv_decode_init(s, avctx);
- s->avctx = avctx;
s->out_format = FMT_H263;
- s->codec_id = avctx->codec_id;
rv->orig_width =
s->width = avctx->coded_width;
@@ -492,8 +510,8 @@ static av_cold int rv10_decode_init(AVCodecContext *avctx)
}
if (avctx->debug & FF_DEBUG_PICT_INFO) {
- av_log(avctx, AV_LOG_DEBUG, "ver:%X ver0:%X\n", rv->sub_id,
- avctx->extradata_size >= 4 ? ((int *) avctx->extradata)[0] : -1);
+ av_log(avctx, AV_LOG_DEBUG, "ver:%X ver0:%"PRIX32"\n", rv->sub_id,
+ ((uint32_t *) avctx->extradata)[0]);
}
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
@@ -541,7 +559,8 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf,
else
mb_count = rv20_decode_picture_header(rv);
if (mb_count < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "HEADER ERROR\n");
+ if (mb_count != ERROR_SKIP_FRAME)
+ av_log(s->avctx, AV_LOG_ERROR, "HEADER ERROR\n");
return AVERROR_INVALIDDATA;
}
@@ -574,6 +593,7 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf,
}
}
+
ff_dlog(avctx, "qscale=%d\n", s->qscale);
/* default quantization values */
@@ -614,7 +634,7 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf,
for (s->mb_num_left = mb_count; s->mb_num_left > 0; s->mb_num_left--) {
int ret;
ff_update_block_index(s);
- ff_dlog(avctx, "**mb x=%d y=%d\n", s->mb_x, s->mb_y);
+ ff_tlog(avctx, "**mb x=%d y=%d\n", s->mb_x, s->mb_y);
s->mv_dir = MV_DIR_FORWARD;
s->mv_type = MV_TYPE_16X16;
@@ -744,11 +764,13 @@ static int rv10_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->current_picture_ptr);
+ ff_print_debug_info(s, s->current_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_QSCALE_TYPE_MPEG1);
} else if (s->last_picture_ptr) {
if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->last_picture_ptr);
+ ff_print_debug_info(s, s->last_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict,s->last_picture_ptr, FF_QSCALE_TYPE_MPEG1);
}
if (s->last_picture_ptr || s->low_delay) {
@@ -772,6 +794,7 @@ AVCodec ff_rv10_decoder = {
.close = rv10_decode_end,
.decode = rv10_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
@@ -789,6 +812,7 @@ AVCodec ff_rv20_decoder = {
.decode = rv10_decode_frame,
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY,
.flush = ff_mpeg_flush,
+ .max_lowres = 3,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE
diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c
index 2eca9c3c88..45f11365c9 100644
--- a/libavcodec/rv10enc.c
+++ b/libavcodec/rv10enc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv20enc.c b/libavcodec/rv20enc.c
index 4462bde01d..03275c7654 100644
--- a/libavcodec/rv20enc.c
+++ b/libavcodec/rv20enc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,12 +40,12 @@ void ff_rv20_encode_picture_header(MpegEncContext *s, int picture_number){
put_bits(&s->pb, 1, s->no_rounding);
- assert(s->f_code == 1);
- assert(s->unrestricted_mv == 0);
- assert(s->alt_inter_vlc == 0);
- assert(s->umvplus == 0);
- assert(s->modified_quant==1);
- assert(s->loop_filter==1);
+ av_assert0(s->f_code == 1);
+ av_assert0(s->unrestricted_mv == 0);
+ av_assert0(s->alt_inter_vlc == 0);
+ av_assert0(s->umvplus == 0);
+ av_assert0(s->modified_quant==1);
+ av_assert0(s->loop_filter==1);
s->h263_aic= s->pict_type == AV_PICTURE_TYPE_I;
if(s->h263_aic){
diff --git a/libavcodec/rv30.c b/libavcodec/rv30.c
index 1675ea2278..1483107c66 100644
--- a/libavcodec/rv30.c
+++ b/libavcodec/rv30.c
@@ -2,20 +2,20 @@
* RV30 decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,8 +51,13 @@ static int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceIn
si->quant = get_bits(gb, 5);
skip_bits1(gb);
si->pts = get_bits(gb, 13);
- rpr = get_bits(gb, r->rpr);
+ rpr = get_bits(gb, av_log2(r->max_rpr) + 1);
if(rpr){
+ if (rpr > r->max_rpr) {
+ av_log(avctx, AV_LOG_ERROR, "rpr too large\n");
+ return AVERROR_INVALIDDATA;
+ }
+
if (avctx->extradata_size < rpr * 2 + 8) {
av_log(avctx, AV_LOG_ERROR,
"Insufficient extradata - need at least %d bytes, got %d\n",
@@ -82,7 +87,7 @@ static int rv30_decode_intra_types(RV34DecContext *r, GetBitContext *gb, int8_t
for(i = 0; i < 4; i++, dst += r->intra_types_stride - 4){
for(j = 0; j < 4; j+= 2){
unsigned code = svq3_get_ue_golomb(gb) << 1;
- if(code >= 81*2){
+ if (code > 80U*2U) {
av_log(r->s.avctx, AV_LOG_ERROR, "Incorrect intra prediction code\n");
return -1;
}
@@ -254,15 +259,19 @@ static av_cold int rv30_decode_init(AVCodecContext *avctx)
RV34DecContext *r = avctx->priv_data;
int ret;
+ if (avctx->extradata_size < 2) {
+ av_log(avctx, AV_LOG_ERROR, "Extradata is too small.\n");
+ return AVERROR(EINVAL);
+ }
r->rv30 = 1;
if ((ret = ff_rv34_decode_init(avctx)) < 0)
return ret;
- if(avctx->extradata_size < 2){
- av_log(avctx, AV_LOG_ERROR, "Extradata is too small.\n");
- return -1;
+
+ r->max_rpr = avctx->extradata[1] & 7;
+ if(avctx->extradata_size < 2*r->max_rpr + 8){
+ av_log(avctx, AV_LOG_WARNING, "Insufficient extradata - need at least %d bytes, got %d\n",
+ 2*r->max_rpr + 8, avctx->extradata_size);
}
- r->rpr = (avctx->extradata[1] & 7) >> 1;
- r->rpr = FFMIN(r->rpr + 1, 3);
r->parse_slice_header = rv30_parse_slice_header;
r->decode_intra_types = rv30_decode_intra_types;
diff --git a/libavcodec/rv30data.h b/libavcodec/rv30data.h
index 5ee304802c..5c4cb9710b 100644
--- a/libavcodec/rv30data.h
+++ b/libavcodec/rv30data.h
@@ -2,20 +2,20 @@
* RealVideo 3 decoder
* copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,7 +58,7 @@ static const uint8_t rv30_itype_code[9*9*2] = {
*
* This is really a three-dimensional matrix with dimensions
* [-1..9][-1..9][0..9]. The first and second coordinates are
- * detemined by the top and left neighbors (-1 if unavailable).
+ * determined by the top and left neighbors (-1 if unavailable).
*/
static const uint8_t rv30_itype_from_context[900] = {
0, 9, 9, 9, 9, 9, 9, 9, 9,
diff --git a/libavcodec/rv30dsp.c b/libavcodec/rv30dsp.c
index 50f418697b..8b205e09b6 100644
--- a/libavcodec/rv30dsp.c
+++ b/libavcodec/rv30dsp.c
@@ -2,20 +2,20 @@
* RV30 decoder motion compensation functions
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c
index 26ab7e4df2..a232ab2593 100644
--- a/libavcodec/rv34.c
+++ b/libavcodec/rv34.c
@@ -2,20 +2,20 @@
* RV30/40 decoder common data
* Copyright (c) 2007 Mike Melanson, Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
* RV30/40 decoder common data
*/
+#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "avcodec.h"
@@ -215,7 +216,7 @@ static int rv34_decode_cbp(GetBitContext *gb, RV34VLC *vlc, int table)
}
/**
- * Get one coefficient value from the bistream and store it.
+ * Get one coefficient value from the bitstream and store it.
*/
static inline void decode_coeff(int16_t *dst, int coef, int esc, GetBitContext *gb, VLC* vlc, int q)
{
@@ -510,7 +511,7 @@ static void rv34_pred_mv(RV34DecContext *r, int block_type, int subblock_no, int
}
}
-#define GET_PTS_DIFF(a, b) ((a - b + 8192) & 0x1FFF)
+#define GET_PTS_DIFF(a, b) (((a) - (b) + 8192) & 0x1FFF)
/**
* Calculate motion vector component that should be added for direct blocks.
@@ -672,6 +673,7 @@ static inline void rv34_mc(RV34DecContext *r, const int block_type,
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;
if(thirdpel){
int chroma_mx, chroma_my;
@@ -723,24 +725,14 @@ static inline void rv34_mc(RV34DecContext *r, const int block_type,
if(s->h_edge_pos - (width << 3) < 6 || s->v_edge_pos - (height << 3) < 6 ||
(unsigned)(src_x - !!lx*2) > s->h_edge_pos - !!lx*2 - (width <<3) - 4 ||
(unsigned)(src_y - !!ly*2) > s->v_edge_pos - !!ly*2 - (height<<3) - 4) {
- uint8_t *uvbuf = s->edge_emu_buffer + 22 * s->linesize;
-
srcY -= 2 + 2*s->linesize;
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY,
s->linesize, s->linesize,
(width << 3) + 6, (height << 3) + 6,
- src_x - 2, src_y - 2, s->h_edge_pos, s->v_edge_pos);
+ src_x - 2, src_y - 2,
+ s->h_edge_pos, s->v_edge_pos);
srcY = s->edge_emu_buffer + 2 + 2*s->linesize;
- s->vdsp.emulated_edge_mc(uvbuf, srcU,
- s->uvlinesize,s->uvlinesize,
- (width << 2) + 1, (height << 2) + 1,
- uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
- s->vdsp.emulated_edge_mc(uvbuf + 16, srcV,
- s->uvlinesize, s->uvlinesize,
- (width << 2) + 1, (height << 2) + 1,
- uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
- srcU = uvbuf;
- srcV = uvbuf + 16;
+ emu = 1;
}
if(!weighted){
Y = s->dest[0] + xoff + yoff *s->linesize;
@@ -763,6 +755,24 @@ static inline void rv34_mc(RV34DecContext *r, const int block_type,
}
is16x16 = (block_type != RV34_MB_P_8x8) && (block_type != RV34_MB_P_16x8) && (block_type != RV34_MB_P_8x16);
qpel_mc[!is16x16][dxy](Y, srcY, s->linesize);
+ if (emu) {
+ uint8_t *uvbuf = s->edge_emu_buffer;
+
+ s->vdsp.emulated_edge_mc(uvbuf, srcU,
+ s->uvlinesize, s->uvlinesize,
+ (width << 2) + 1, (height << 2) + 1,
+ uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+ srcU = uvbuf;
+ uvbuf += 9*s->uvlinesize;
+
+ s->vdsp.emulated_edge_mc(uvbuf, srcV,
+ s->uvlinesize, s->uvlinesize,
+ (width << 2) + 1, (height << 2) + 1,
+ uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, s->v_edge_pos >> 1);
+ srcV = uvbuf;
+ }
chroma_mc[2-width] (U, srcU, s->uvlinesize, height*4, uvmx, uvmy);
chroma_mc[2-width] (V, srcV, s->uvlinesize, height*4, uvmx, uvmy);
}
@@ -1339,7 +1349,7 @@ static int check_slice_end(RV34DecContext *r, MpegEncContext *s)
if(r->s.mb_skip_run > 1)
return 0;
bits = get_bits_left(&s->gb);
- if(bits < 0 || (bits < 8 && !show_bits(&s->gb, bits)))
+ if(bits <= 0 || (bits < 8 && !show_bits(&s->gb, bits)))
return 1;
return 0;
}
@@ -1361,11 +1371,11 @@ static int rv34_decoder_alloc(RV34DecContext *r)
{
r->intra_types_stride = r->s.mb_width * 4 + 4;
- r->cbp_chroma = av_malloc(r->s.mb_stride * r->s.mb_height *
+ r->cbp_chroma = av_mallocz(r->s.mb_stride * r->s.mb_height *
sizeof(*r->cbp_chroma));
- r->cbp_luma = av_malloc(r->s.mb_stride * r->s.mb_height *
+ r->cbp_luma = av_mallocz(r->s.mb_stride * r->s.mb_height *
sizeof(*r->cbp_luma));
- r->deblock_coefs = av_malloc(r->s.mb_stride * r->s.mb_height *
+ r->deblock_coefs = av_mallocz(r->s.mb_stride * r->s.mb_height *
sizeof(*r->deblock_coefs));
r->intra_types_hist = av_malloc(r->intra_types_stride * 4 * 2 *
sizeof(*r->intra_types_hist));
@@ -1410,6 +1420,10 @@ static int rv34_decode_slice(RV34DecContext *r, int end, const uint8_t* buf, int
av_log(s->avctx, AV_LOG_ERROR, "Slice type mismatch\n");
return AVERROR_INVALIDDATA;
}
+ if (s->width != r->si.width || s->height != r->si.height) {
+ av_log(s->avctx, AV_LOG_ERROR, "Size mismatch\n");
+ return AVERROR_INVALIDDATA;
+ }
r->si.end = end;
s->qscale = r->si.quant;
@@ -1476,14 +1490,9 @@ av_cold int ff_rv34_decode_init(AVCodecContext *avctx)
int ret;
ff_mpv_decode_defaults(s);
- s->avctx = avctx;
+ ff_mpv_decode_init(s, avctx);
s->out_format = FMT_H263;
- s->codec_id = avctx->codec_id;
-
- s->width = avctx->width;
- s->height = avctx->height;
- r->s.avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
avctx->has_b_frames = 1;
s->low_delay = 0;
@@ -1591,18 +1600,30 @@ static int finish_frame(AVCodecContext *avctx, AVFrame *pict)
if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->current_picture_ptr);
+ ff_print_debug_info(s, s->current_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->current_picture_ptr, FF_QSCALE_TYPE_MPEG1);
got_picture = 1;
} else if (s->last_picture_ptr) {
if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0)
return ret;
- ff_print_debug_info(s, s->last_picture_ptr);
+ ff_print_debug_info(s, s->last_picture_ptr, pict);
+ ff_mpv_export_qp_table(s, pict, s->last_picture_ptr, FF_QSCALE_TYPE_MPEG1);
got_picture = 1;
}
return got_picture;
}
+static AVRational update_sar(int old_w, int old_h, AVRational sar, int new_w, int new_h)
+{
+ // attempt to keep aspect during typical resolution switches
+ if (!sar.num)
+ sar = (AVRational){1, 1};
+
+ sar = av_mul_q(sar, (AVRational){new_h * old_w, new_w * old_h});
+ return sar;
+}
+
int ff_rv34_decode_frame(AVCodecContext *avctx,
void *data, int *got_picture_ptr,
AVPacket *avpkt)
@@ -1663,8 +1684,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx,
/* first slice */
if (si.start == 0) {
- if (s->mb_num_left > 0) {
- av_log(avctx, AV_LOG_ERROR, "New frame but still %d MB left.",
+ if (s->mb_num_left > 0 && s->current_picture_ptr) {
+ av_log(avctx, AV_LOG_ERROR, "New frame but still %d MB left.\n",
s->mb_num_left);
ff_er_frame_end(&s->er);
ff_mpv_frame_end(s);
@@ -1676,6 +1697,12 @@ int ff_rv34_decode_frame(AVCodecContext *avctx,
av_log(s->avctx, AV_LOG_WARNING, "Changing dimensions to %dx%d\n",
si.width, si.height);
+ if (av_image_check_size(si.width, si.height, 0, s->avctx))
+ return AVERROR_INVALIDDATA;
+
+ s->avctx->sample_aspect_ratio = update_sar(
+ s->width, s->height, s->avctx->sample_aspect_ratio,
+ si.width, si.height);
s->width = si.width;
s->height = si.height;
diff --git a/libavcodec/rv34.h b/libavcodec/rv34.h
index c32c089cdd..870164c6e5 100644
--- a/libavcodec/rv34.h
+++ b/libavcodec/rv34.h
@@ -2,20 +2,20 @@
* RV30/40 decoder common data declarations
* Copyright (c) 2007 Mike Melanson, Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -102,7 +102,7 @@ typedef struct RV34DecContext{
int dmv[4][2]; ///< differential motion vectors for the current macroblock
int rv30; ///< indicates which RV variasnt is currently decoded
- int rpr; ///< one field size in RV30 slice header
+ int max_rpr;
int cur_pts, last_pts, next_pts;
int scaled_weight;
diff --git a/libavcodec/rv34_parser.c b/libavcodec/rv34_parser.c
index ec6d3a5644..765d390550 100644
--- a/libavcodec/rv34_parser.c
+++ b/libavcodec/rv34_parser.c
@@ -2,20 +2,20 @@
* RV30/40 parser
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv34data.h b/libavcodec/rv34data.h
index 30641249da..4b2701fee6 100644
--- a/libavcodec/rv34data.h
+++ b/libavcodec/rv34data.h
@@ -2,20 +2,20 @@
* RealVideo 4 decoder
* copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv34dsp.c b/libavcodec/rv34dsp.c
index 7234ee808b..c3f245eb85 100644
--- a/libavcodec/rv34dsp.c
+++ b/libavcodec/rv34dsp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Mike Melanson, Konstantin Shishkov
* Copyright (c) 2011 Janne Grunau
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv34dsp.h b/libavcodec/rv34dsp.h
index 1aa80cf7ef..2e9ec4eee4 100644
--- a/libavcodec/rv34dsp.h
+++ b/libavcodec/rv34dsp.h
@@ -2,20 +2,20 @@
* RV30/40 decoder motion compensation functions
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv34vlc.h b/libavcodec/rv34vlc.h
index f4670c1625..aa29357c78 100644
--- a/libavcodec/rv34vlc.h
+++ b/libavcodec/rv34vlc.h
@@ -2,20 +2,20 @@
* RealVideo 3/4 decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv40.c b/libavcodec/rv40.c
index 6553667efa..e9cd110928 100644
--- a/libavcodec/rv40.c
+++ b/libavcodec/rv40.c
@@ -2,20 +2,20 @@
* RV40 decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -230,8 +230,11 @@ static int rv40_decode_mb_info(RV34DecContext *r)
int prev_type = 0;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
- if(!r->s.mb_skip_run)
+ if(!r->s.mb_skip_run) {
r->s.mb_skip_run = svq3_get_ue_golomb(gb) + 1;
+ if(r->s.mb_skip_run > (unsigned)s->mb_num)
+ return -1;
+ }
if(--r->s.mb_skip_run)
return RV34_MB_SKIP;
@@ -358,7 +361,7 @@ static void rv40_loop_filter(RV34DecContext *r, int row)
int uvcbp[4][2];
/**
* This mask represents the pattern of luma subblocks that should be filtered
- * in addition to the coded ones because because they lie at the edge of
+ * in addition to the coded ones because they lie at the edge of
* 8x8 block with different enough motion vectors
*/
unsigned mvmasks[4];
diff --git a/libavcodec/rv40data.h b/libavcodec/rv40data.h
index 42328af5a8..36f9f919bd 100644
--- a/libavcodec/rv40data.h
+++ b/libavcodec/rv40data.h
@@ -2,20 +2,20 @@
* RealVideo 4 decoder
* copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/rv40dsp.c b/libavcodec/rv40dsp.c
index da3efb4442..19b0e93696 100644
--- a/libavcodec/rv40dsp.c
+++ b/libavcodec/rv40dsp.c
@@ -2,20 +2,20 @@
* RV40 decoder motion compensation functions
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,7 @@
#include "pixels.h"
#include "rnd_avg.h"
#include "rv34dsp.h"
+#include "libavutil/avassert.h"
#define RV40_LOWPASS(OPNAME, OP) \
static void OPNAME ## rv40_qpel8_h_lowpass(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride,\
@@ -299,7 +300,7 @@ static void OPNAME ## rv40_chroma_mc4_c(uint8_t *dst/*align 8*/, uint8_t *src/*a
int i;\
int bias = rv40_bias[y>>1][x>>1];\
\
- assert(x<8 && y<8 && x>=0 && y>=0);\
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);\
\
if(D){\
for(i = 0; i < h; i++){\
@@ -332,7 +333,7 @@ static void OPNAME ## rv40_chroma_mc8_c(uint8_t *dst/*align 8*/, uint8_t *src/*a
int i;\
int bias = rv40_bias[y>>1][x>>1];\
\
- assert(x<8 && y<8 && x>=0 && y>=0);\
+ av_assert2(x<8 && y<8 && x>=0 && y>=0);\
\
if(D){\
for(i = 0; i < h; i++){\
diff --git a/libavcodec/rv40vlc2.h b/libavcodec/rv40vlc2.h
index 2f63fc27e3..15119a145b 100644
--- a/libavcodec/rv40vlc2.h
+++ b/libavcodec/rv40vlc2.h
@@ -2,20 +2,20 @@
* RealVideo 4 decoder
* copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/s302m.c b/libavcodec/s302m.c
index 36384fb29a..7639a0f1c9 100644
--- a/libavcodec/s302m.c
+++ b/libavcodec/s302m.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Laurent Aimar <fenrir@videolan.org>
* Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,18 +59,31 @@ static int s302m_parse_frame_header(AVCodecContext *avctx, const uint8_t *buf,
}
/* Set output properties */
- avctx->bits_per_coded_sample = bits;
+ avctx->bits_per_raw_sample = bits;
if (bits > 16)
avctx->sample_fmt = AV_SAMPLE_FMT_S32;
else
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
avctx->channels = channels;
+ switch(channels) {
+ case 2:
+ avctx->channel_layout = AV_CH_LAYOUT_STEREO;
+ break;
+ case 4:
+ avctx->channel_layout = AV_CH_LAYOUT_QUAD;
+ break;
+ case 6:
+ avctx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK;
+ break;
+ case 8:
+ avctx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK | AV_CH_LAYOUT_STEREO_DOWNMIX;
+ }
avctx->sample_rate = 48000;
- avctx->bit_rate = 48000 * avctx->channels * (avctx->bits_per_coded_sample + 4) +
+ avctx->bit_rate = 48000 * avctx->channels * (avctx->bits_per_raw_sample + 4) +
32 * (48000 / (buf_size * 8 /
(avctx->channels *
- (avctx->bits_per_coded_sample + 4))));
+ (avctx->bits_per_raw_sample + 4))));
return frame_size;
}
@@ -91,16 +104,14 @@ static int s302m_decode_frame(AVCodecContext *avctx, void *data,
buf += AES3_HEADER_LEN;
/* get output buffer */
- block_size = (avctx->bits_per_coded_sample + 4) / 4;
+ block_size = (avctx->bits_per_raw_sample + 4) / 4;
frame->nb_samples = 2 * (buf_size / block_size) / avctx->channels;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
buf_size = (frame->nb_samples * avctx->channels / 2) * block_size;
- if (avctx->bits_per_coded_sample == 24) {
+ if (avctx->bits_per_raw_sample == 24) {
uint32_t *o = (uint32_t *)frame->data[0];
for (; buf_size > 6; buf_size -= 7) {
*o++ = (ff_reverse[buf[2]] << 24) |
@@ -112,7 +123,7 @@ static int s302m_decode_frame(AVCodecContext *avctx, void *data,
(ff_reverse[buf[3] & 0x0f] << 4);
buf += 7;
}
- } else if (avctx->bits_per_coded_sample == 20) {
+ } else if (avctx->bits_per_raw_sample == 20) {
uint32_t *o = (uint32_t *)frame->data[0];
for (; buf_size > 5; buf_size -= 6) {
*o++ = (ff_reverse[buf[2] & 0xf0] << 28) |
diff --git a/libavcodec/s302menc.c b/libavcodec/s302menc.c
new file mode 100644
index 0000000000..e738f09d19
--- /dev/null
+++ b/libavcodec/s302menc.c
@@ -0,0 +1,178 @@
+/*
+ * SMPTE 302M encoder
+ * Copyright (c) 2010 Google, Inc.
+ * Copyright (c) 2013 Darryl Wallace <wallacdj@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
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "mathops.h"
+#include "put_bits.h"
+
+#define AES3_HEADER_LEN 4
+
+typedef struct S302MEncContext {
+ uint8_t framing_index; /* Set for even channels on multiple of 192 samples */
+} S302MEncContext;
+
+static av_cold int s302m_encode_init(AVCodecContext *avctx)
+{
+ S302MEncContext *s = avctx->priv_data;
+
+ if (avctx->channels & 1 || avctx->channels > 8) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Encoding %d channel(s) is not allowed. Only 2, 4, 6 and 8 channels are supported.\n",
+ avctx->channels);
+ return AVERROR(EINVAL);
+ }
+
+ switch (avctx->sample_fmt) {
+ case AV_SAMPLE_FMT_S16:
+ avctx->bits_per_raw_sample = 16;
+ break;
+ case AV_SAMPLE_FMT_S32:
+ if (avctx->bits_per_raw_sample > 20) {
+ if (avctx->bits_per_raw_sample > 24)
+ av_log(avctx, AV_LOG_WARNING, "encoding as 24 bits-per-sample\n");
+ avctx->bits_per_raw_sample = 24;
+ } else if (!avctx->bits_per_raw_sample) {
+ avctx->bits_per_raw_sample = 24;
+ } else if (avctx->bits_per_raw_sample <= 20) {
+ avctx->bits_per_raw_sample = 20;
+ }
+ }
+
+ avctx->frame_size = 0;
+ avctx->bit_rate = 48000 * avctx->channels *
+ (avctx->bits_per_raw_sample + 4);
+ s->framing_index = 0;
+
+ return 0;
+}
+
+static int s302m_encode2_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ S302MEncContext *s = avctx->priv_data;
+ const int buf_size = AES3_HEADER_LEN +
+ (frame->nb_samples *
+ avctx->channels *
+ (avctx->bits_per_raw_sample + 4)) / 8;
+ int ret, c, channels;
+ uint8_t *o;
+ PutBitContext pb;
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, buf_size)) < 0)
+ return ret;
+
+ o = avpkt->data;
+ init_put_bits(&pb, o, buf_size);
+ put_bits(&pb, 16, buf_size - AES3_HEADER_LEN);
+ put_bits(&pb, 2, (avctx->channels - 2) >> 1); // number of channels
+ put_bits(&pb, 8, 0); // channel ID
+ put_bits(&pb, 2, (avctx->bits_per_raw_sample - 16) / 4); // bits per samples (0 = 16bit, 1 = 20bit, 2 = 24bit)
+ put_bits(&pb, 4, 0); // alignments
+ flush_put_bits(&pb);
+ o += AES3_HEADER_LEN;
+
+ if (avctx->bits_per_raw_sample == 24) {
+ const uint32_t *samples = (uint32_t *)frame->data[0];
+
+ for (c = 0; c < frame->nb_samples; c++) {
+ uint8_t vucf = s->framing_index == 0 ? 0x10: 0;
+
+ for (channels = 0; channels < avctx->channels; channels += 2) {
+ o[0] = ff_reverse[(samples[0] & 0x0000FF00) >> 8];
+ o[1] = ff_reverse[(samples[0] & 0x00FF0000) >> 16];
+ o[2] = ff_reverse[(samples[0] & 0xFF000000) >> 24];
+ o[3] = ff_reverse[(samples[1] & 0x00000F00) >> 4] | vucf;
+ o[4] = ff_reverse[(samples[1] & 0x000FF000) >> 12];
+ o[5] = ff_reverse[(samples[1] & 0x0FF00000) >> 20];
+ o[6] = ff_reverse[(samples[1] & 0xF0000000) >> 28];
+ o += 7;
+ samples += 2;
+ }
+
+ s->framing_index++;
+ if (s->framing_index >= 192)
+ s->framing_index = 0;
+ }
+ } else if (avctx->bits_per_raw_sample == 20) {
+ const uint32_t *samples = (uint32_t *)frame->data[0];
+
+ for (c = 0; c < frame->nb_samples; c++) {
+ uint8_t vucf = s->framing_index == 0 ? 0x80: 0;
+
+ for (channels = 0; channels < avctx->channels; channels += 2) {
+ o[0] = ff_reverse[ (samples[0] & 0x000FF000) >> 12];
+ o[1] = ff_reverse[ (samples[0] & 0x0FF00000) >> 20];
+ o[2] = ff_reverse[((samples[0] & 0xF0000000) >> 28) | vucf];
+ o[3] = ff_reverse[ (samples[1] & 0x000FF000) >> 12];
+ o[4] = ff_reverse[ (samples[1] & 0x0FF00000) >> 20];
+ o[5] = ff_reverse[ (samples[1] & 0xF0000000) >> 28];
+ o += 6;
+ samples += 2;
+ }
+
+ s->framing_index++;
+ if (s->framing_index >= 192)
+ s->framing_index = 0;
+ }
+ } else if (avctx->bits_per_raw_sample == 16) {
+ const uint16_t *samples = (uint16_t *)frame->data[0];
+
+ for (c = 0; c < frame->nb_samples; c++) {
+ uint8_t vucf = s->framing_index == 0 ? 0x10 : 0;
+
+ for (channels = 0; channels < avctx->channels; channels += 2) {
+ o[0] = ff_reverse[ samples[0] & 0xFF];
+ o[1] = ff_reverse[(samples[0] & 0xFF00) >> 8];
+ o[2] = ff_reverse[(samples[1] & 0x0F) << 4] | vucf;
+ o[3] = ff_reverse[(samples[1] & 0x0FF0) >> 4];
+ o[4] = ff_reverse[(samples[1] & 0xF000) >> 12];
+ o += 5;
+ samples += 2;
+
+ }
+
+ s->framing_index++;
+ if (s->framing_index >= 192)
+ s->framing_index = 0;
+ }
+ }
+
+ *got_packet_ptr = 1;
+
+ return 0;
+}
+
+AVCodec ff_s302m_encoder = {
+ .name = "s302m",
+ .long_name = NULL_IF_CONFIG_SMALL("SMPTE 302M"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_S302M,
+ .priv_data_size = sizeof(S302MEncContext),
+ .init = s302m_encode_init,
+ .encode2 = s302m_encode2_frame,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE },
+ .capabilities = CODEC_CAP_VARIABLE_FRAME_SIZE | CODEC_CAP_EXPERIMENTAL,
+ .supported_samplerates = (const int[]) { 48000, 0 },
+};
diff --git a/libavcodec/s3tc.c b/libavcodec/s3tc.c
index d35cf2ac07..a422874d17 100644
--- a/libavcodec/s3tc.c
+++ b/libavcodec/s3tc.c
@@ -4,20 +4,20 @@
*
* see also: http://wiki.multimedia.cx/index.php?title=S3TC
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "s3tc.h"
static inline void dxt1_decode_pixels(GetByteContext *gb, uint32_t *d,
+ unsigned int w, unsigned int h,
unsigned int qstride, unsigned int flag,
uint64_t alpha) {
unsigned int x, y, c0, c1, a = (!flag * 255u) << 24;
@@ -62,14 +63,18 @@ static inline void dxt1_decode_pixels(GetByteContext *gb, uint32_t *d,
colors[2] = rb2 + g2 + a;
pixels = bytestream2_get_le32(gb);
- for (y=0; y<4; y++) {
- for (x=0; x<4; x++) {
+ for (y=0; y<h; y++) {
+ for (x=0; x<w; x++) {
a = (alpha & 0x0f) << 28;
a += a >> 4;
d[x] = a + colors[pixels&3];
pixels >>= 2;
alpha >>= 4;
}
+ for (; x<4; x++) {
+ pixels >>= 2;
+ alpha >>= 4;
+ }
d += qstride;
}
}
@@ -77,21 +82,21 @@ static inline void dxt1_decode_pixels(GetByteContext *gb, uint32_t *d,
void ff_decode_dxt1(GetByteContext *gb, uint8_t *dst,
const unsigned int w, const unsigned int h,
const unsigned int stride) {
- unsigned int bx, by, qstride = stride/4;
+ unsigned int x, y, qstride = stride/4;
uint32_t *d = (uint32_t *) dst;
- for (by=0; by < h/4; by++, d += stride-w)
- for (bx = 0; bx < w / 4; bx++, d += 4)
- dxt1_decode_pixels(gb, d, qstride, 0, 0LL);
+ for (y=0; y < h; y += 4, d += stride-w)
+ for (x = 0; x < w; d += FFMIN(4, w-x), x += 4)
+ dxt1_decode_pixels(gb, d, FFMIN(4, w-x), FFMIN(4, h-y), qstride, 0, 0LL);
}
void ff_decode_dxt3(GetByteContext *gb, uint8_t *dst,
const unsigned int w, const unsigned int h,
const unsigned int stride) {
- unsigned int bx, by, qstride = stride/4;
+ unsigned int x, y, qstride = stride/4;
uint32_t *d = (uint32_t *) dst;
- for (by=0; by < h/4; by++, d += stride-w)
- for (bx = 0; bx < w / 4; bx++, d += 4)
- dxt1_decode_pixels(gb, d, qstride, 1, bytestream2_get_le64(gb));
+ for (y=0; y < h; y += 4, d += stride-w)
+ for (x = 0; x < w; d += FFMIN(4, w-x), x += 4)
+ dxt1_decode_pixels(gb, d, FFMIN(4, w-x), FFMIN(4, h-y), qstride, 1, bytestream2_get_le64(gb));
}
diff --git a/libavcodec/s3tc.h b/libavcodec/s3tc.h
index 25237b95bd..2d77b3abe3 100644
--- a/libavcodec/s3tc.h
+++ b/libavcodec/s3tc.h
@@ -2,20 +2,20 @@
* S3 Texture Compression (S3TC) decoding functions
* Copyright (c) 2007 by Ivo van Poorten
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c
new file mode 100644
index 0000000000..47850e2126
--- /dev/null
+++ b/libavcodec/samidec.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * SAMI subtitle decoder
+ * @see http://msdn.microsoft.com/en-us/library/ms971327.aspx
+ */
+
+#include "ass.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+
+typedef struct {
+ AVBPrint source;
+ AVBPrint content;
+ AVBPrint full;
+} SAMIContext;
+
+static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src)
+{
+ SAMIContext *sami = avctx->priv_data;
+ int ret = 0;
+ char *tag = NULL;
+ char *dupsrc = av_strdup(src);
+ char *p = dupsrc;
+
+ av_bprint_clear(&sami->content);
+ for (;;) {
+ char *saveptr = NULL;
+ int prev_chr_is_space = 0;
+ AVBPrint *dst = &sami->content;
+
+ /* parse & extract paragraph tag */
+ p = av_stristr(p, "<P");
+ if (!p)
+ break;
+ if (p[2] != '>' && !av_isspace(p[2])) { // avoid confusion with tags such as <PRE>
+ p++;
+ continue;
+ }
+ if (dst->len) // add a separator with the previous paragraph if there was one
+ av_bprintf(dst, "\\N");
+ tag = av_strtok(p, ">", &saveptr);
+ if (!tag || !saveptr)
+ break;
+ p = saveptr;
+
+ /* check if the current paragraph is the "source" (speaker name) */
+ if (av_stristr(tag, "ID=Source") || av_stristr(tag, "ID=\"Source\"")) {
+ dst = &sami->source;
+ av_bprint_clear(dst);
+ }
+
+ /* if empty event -> skip subtitle */
+ while (av_isspace(*p))
+ p++;
+ if (!strncmp(p, "&nbsp;", 6)) {
+ ret = -1;
+ goto end;
+ }
+
+ /* extract the text, stripping most of the tags */
+ while (*p) {
+ if (*p == '<') {
+ if (!av_strncasecmp(p, "<P", 2) && (p[2] == '>' || av_isspace(p[2])))
+ break;
+ if (!av_strncasecmp(p, "<BR", 3))
+ av_bprintf(dst, "\\N");
+ p++;
+ while (*p && *p != '>')
+ p++;
+ if (!*p)
+ break;
+ if (*p == '>')
+ p++;
+ continue;
+ }
+ if (!av_isspace(*p))
+ av_bprint_chars(dst, *p, 1);
+ else if (!prev_chr_is_space)
+ av_bprint_chars(dst, ' ', 1);
+ prev_chr_is_space = av_isspace(*p);
+ p++;
+ }
+ }
+
+ av_bprint_clear(&sami->full);
+ if (sami->source.len)
+ av_bprintf(&sami->full, "{\\i1}%s{\\i0}\\N", sami->source.str);
+ av_bprintf(&sami->full, "%s", sami->content.str);
+
+end:
+ av_free(dupsrc);
+ return ret;
+}
+
+static int sami_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ SAMIContext *sami = avctx->priv_data;
+
+ if (ptr && avpkt->size > 0 && !sami_paragraph_to_ass(avctx, ptr)) {
+ int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
+ int ts_duration = avpkt->duration != -1 ?
+ av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
+ int ret = ff_ass_add_rect_bprint(sub, &sami->full, ts_start, ts_duration);
+ if (ret < 0)
+ return ret;
+ }
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+static av_cold int sami_init(AVCodecContext *avctx)
+{
+ SAMIContext *sami = avctx->priv_data;
+ av_bprint_init(&sami->source, 0, 2048);
+ av_bprint_init(&sami->content, 0, 2048);
+ av_bprint_init(&sami->full, 0, 2048);
+ return ff_ass_subtitle_header_default(avctx);
+}
+
+static av_cold int sami_close(AVCodecContext *avctx)
+{
+ SAMIContext *sami = avctx->priv_data;
+ av_bprint_finalize(&sami->source, NULL);
+ av_bprint_finalize(&sami->content, NULL);
+ av_bprint_finalize(&sami->full, NULL);
+ return 0;
+}
+
+AVCodec ff_sami_decoder = {
+ .name = "sami",
+ .long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SAMI,
+ .priv_data_size = sizeof(SAMIContext),
+ .init = sami_init,
+ .close = sami_close,
+ .decode = sami_decode_frame,
+};
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c
index 41c65510e5..9e5ec5400e 100644
--- a/libavcodec/sanm.c
+++ b/libavcodec/sanm.c
@@ -3,20 +3,20 @@
* Copyright (c) 2006 Cyril Zorin
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -105,108 +105,159 @@ static const int8_t motion_vectors[256][2] = {
};
static const int8_t c37_mv[] = {
- 0, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0, 13, 0, 21,
- 0, -1, 0, -2, 0, -3, 0, -5, 0, -8, 0, -13, 0, -17, 0,
- -21, 0, 0, 1, 1, 1, 2, 1, 3, 1, 5, 1, 8, 1, 13,
- 1, 21, 1, -1, 1, -2, 1, -3, 1, -5, 1, -8, 1, -13, 1,
- -17, 1, -21, 1, 0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 8,
- 2, 13, 2, 21, 2, -1, 2, -2, 2, -3, 2, -5, 2, -8, 2,
- -13, 2, -17, 2, -21, 2, 0, 3, 1, 3, 2, 3, 3, 3, 5,
- 3, 8, 3, 13, 3, 21, 3, -1, 3, -2, 3, -3, 3, -5, 3,
- -8, 3, -13, 3, -17, 3, -21, 3, 0, 5, 1, 5, 2, 5, 3,
- 5, 5, 5, 8, 5, 13, 5, 21, 5, -1, 5, -2, 5, -3, 5,
- -5, 5, -8, 5, -13, 5, -17, 5, -21, 5, 0, 8, 1, 8, 2,
- 8, 3, 8, 5, 8, 8, 8, 13, 8, 21, 8, -1, 8, -2, 8,
- -3, 8, -5, 8, -8, 8, -13, 8, -17, 8, -21, 8, 0, 13, 1,
- 13, 2, 13, 3, 13, 5, 13, 8, 13, 13, 13, 21, 13, -1, 13,
- -2, 13, -3, 13, -5, 13, -8, 13, -13, 13, -17, 13, -21, 13, 0,
- 21, 1, 21, 2, 21, 3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
- -1, 21, -2, 21, -3, 21, -5, 21, -8, 21, -13, 21, -17, 21, -21,
- 21, 0, -1, 1, -1, 2, -1, 3, -1, 5, -1, 8, -1, 13, -1,
- 21, -1, -1, -1, -2, -1, -3, -1, -5, -1, -8, -1, -13, -1, -17,
- -1, -21, -1, 0, -2, 1, -2, 2, -2, 3, -2, 5, -2, 8, -2,
- 13, -2, 21, -2, -1, -2, -2, -2, -3, -2, -5, -2, -8, -2, -13,
- -2, -17, -2, -21, -2, 0, -3, 1, -3, 2, -3, 3, -3, 5, -3,
- 8, -3, 13, -3, 21, -3, -1, -3, -2, -3, -3, -3, -5, -3, -8,
- -3, -13, -3, -17, -3, -21, -3, 0, -5, 1, -5, 2, -5, 3, -5,
- 5, -5, 8, -5, 13, -5, 21, -5, -1, -5, -2, -5, -3, -5, -5,
- -5, -8, -5, -13, -5, -17, -5, -21, -5, 0, -8, 1, -8, 2, -8,
- 3, -8, 5, -8, 8, -8, 13, -8, 21, -8, -1, -8, -2, -8, -3,
- -8, -5, -8, -8, -8, -13, -8, -17, -8, -21, -8, 0, -13, 1, -13,
- 2, -13, 3, -13, 5, -13, 8, -13, 13, -13, 21, -13, -1, -13, -2,
- -13, -3, -13, -5, -13, -8, -13, -13, -13, -17, -13, -21, -13, 0, -17,
- 1, -17, 2, -17, 3, -17, 5, -17, 8, -17, 13, -17, 21, -17, -1,
- -17, -2, -17, -3, -17, -5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
- 0, -21, 1, -21, 2, -21, 3, -21, 5, -21, 8, -21, 13, -21, 21,
- -21, -1, -21, -2, -21, -3, -21, -5, -21, -8, -21, -13, -21, -17, -21,
- 0, 0, -8, -29, 8, -29, -18, -25, 17, -25, 0, -23, -6, -22, 6,
- -22, -13, -19, 12, -19, 0, -18, 25, -18, -25, -17, -5, -17, 5, -17,
- -10, -15, 10, -15, 0, -14, -4, -13, 4, -13, 19, -13, -19, -12, -8,
- -11, -2, -11, 0, -11, 2, -11, 8, -11, -15, -10, -4, -10, 4, -10,
- 15, -10, -6, -9, -1, -9, 1, -9, 6, -9, -29, -8, -11, -8, -8,
- -8, -3, -8, 3, -8, 8, -8, 11, -8, 29, -8, -5, -7, -2, -7,
- 0, -7, 2, -7, 5, -7, -22, -6, -9, -6, -6, -6, -3, -6, -1,
- -6, 1, -6, 3, -6, 6, -6, 9, -6, 22, -6, -17, -5, -7, -5,
- -4, -5, -2, -5, 0, -5, 2, -5, 4, -5, 7, -5, 17, -5, -13,
- -4, -10, -4, -5, -4, -3, -4, -1, -4, 0, -4, 1, -4, 3, -4,
- 5, -4, 10, -4, 13, -4, -8, -3, -6, -3, -4, -3, -3, -3, -2,
- -3, -1, -3, 0, -3, 1, -3, 2, -3, 4, -3, 6, -3, 8, -3,
- -11, -2, -7, -2, -5, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1,
- -2, 2, -2, 3, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
- -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3,
- -1, 4, -1, 6, -1, 9, -1, -31, 0, -23, 0, -18, 0, -14, 0,
- -11, 0, -7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0,
- -31, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
- 14, 0, 18, 0, 23, 0, 31, 0, -9, 1, -6, 1, -4, 1, -3,
- 1, -2, 1, -1, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
- 6, 1, 9, 1, -11, 2, -7, 2, -5, 2, -3, 2, -2, 2, -1,
- 2, 0, 2, 1, 2, 2, 2, 3, 2, 5, 2, 7, 2, 11, 2,
- -8, 3, -6, 3, -4, 3, -2, 3, -1, 3, 0, 3, 1, 3, 2,
- 3, 3, 3, 4, 3, 6, 3, 8, 3, -13, 4, -10, 4, -5, 4,
- -3, 4, -1, 4, 0, 4, 1, 4, 3, 4, 5, 4, 10, 4, 13,
- 4, -17, 5, -7, 5, -4, 5, -2, 5, 0, 5, 2, 5, 4, 5,
- 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6, 1,
- 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
- 2, 7, 5, 7, -29, 8, -11, 8, -8, 8, -3, 8, 3, 8, 8,
- 8, 11, 8, 29, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
- -4, 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8,
- 11, 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15,
- -5, 17, 5, 17, 25, 17, -25, 18, 0, 18, -12, 19, 13, 19, -6,
- 22, 6, 22, 0, 23, -17, 25, 18, 25, -8, 29, 8, 29, 0, 31,
- 0, 0, -6, -22, 6, -22, -13, -19, 12, -19, 0, -18, -5, -17, 5,
- -17, -10, -15, 10, -15, 0, -14, -4, -13, 4, -13, 19, -13, -19, -12,
- -8, -11, -2, -11, 0, -11, 2, -11, 8, -11, -15, -10, -4, -10, 4,
- -10, 15, -10, -6, -9, -1, -9, 1, -9, 6, -9, -11, -8, -8, -8,
- -3, -8, 0, -8, 3, -8, 8, -8, 11, -8, -5, -7, -2, -7, 0,
- -7, 2, -7, 5, -7, -22, -6, -9, -6, -6, -6, -3, -6, -1, -6,
- 1, -6, 3, -6, 6, -6, 9, -6, 22, -6, -17, -5, -7, -5, -4,
- -5, -2, -5, -1, -5, 0, -5, 1, -5, 2, -5, 4, -5, 7, -5,
- 17, -5, -13, -4, -10, -4, -5, -4, -3, -4, -2, -4, -1, -4, 0,
- -4, 1, -4, 2, -4, 3, -4, 5, -4, 10, -4, 13, -4, -8, -3,
- -6, -3, -4, -3, -3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2,
- -3, 3, -3, 4, -3, 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
- -4, -2, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 3,
- -2, 4, -2, 5, -2, 7, -2, 11, -2, -9, -1, -6, -1, -5, -1,
- -4, -1, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, 3,
- -1, 4, -1, 5, -1, 6, -1, 9, -1, -23, 0, -18, 0, -14, 0,
- -11, 0, -7, 0, -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 0,
- -23, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
- 14, 0, 18, 0, 23, 0, -9, 1, -6, 1, -5, 1, -4, 1, -3,
- 1, -2, 1, -1, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
- 5, 1, 6, 1, 9, 1, -11, 2, -7, 2, -5, 2, -4, 2, -3,
- 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2,
- 5, 2, 7, 2, 11, 2, -8, 3, -6, 3, -4, 3, -3, 3, -2,
- 3, -1, 3, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 6, 3,
- 8, 3, -13, 4, -10, 4, -5, 4, -3, 4, -2, 4, -1, 4, 0,
- 4, 1, 4, 2, 4, 3, 4, 5, 4, 10, 4, 13, 4, -17, 5,
- -7, 5, -4, 5, -2, 5, -1, 5, 0, 5, 1, 5, 2, 5, 4,
- 5, 7, 5, 17, 5, -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
- 1, 6, 3, 6, 6, 6, 9, 6, 22, 6, -5, 7, -2, 7, 0,
- 7, 2, 7, 5, 7, -11, 8, -8, 8, -3, 8, 0, 8, 3, 8,
- 8, 8, 11, 8, -6, 9, -1, 9, 1, 9, 6, 9, -15, 10, -4,
- 10, 4, 10, 15, 10, -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
- 19, 12, -19, 13, -4, 13, 4, 13, 0, 14, -10, 15, 10, 15, -5,
- 17, 5, 17, 0, 18, -12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
+ 0, 0, 1, 0, 2, 0, 3, 0, 5, 0,
+ 8, 0, 13, 0, 21, 0, -1, 0, -2, 0,
+ -3, 0, -5, 0, -8, 0, -13, 0, -17, 0,
+ -21, 0, 0, 1, 1, 1, 2, 1, 3, 1,
+ 5, 1, 8, 1, 13, 1, 21, 1, -1, 1,
+ -2, 1, -3, 1, -5, 1, -8, 1, -13, 1,
+ -17, 1, -21, 1, 0, 2, 1, 2, 2, 2,
+ 3, 2, 5, 2, 8, 2, 13, 2, 21, 2,
+ -1, 2, -2, 2, -3, 2, -5, 2, -8, 2,
+ -13, 2, -17, 2, -21, 2, 0, 3, 1, 3,
+ 2, 3, 3, 3, 5, 3, 8, 3, 13, 3,
+ 21, 3, -1, 3, -2, 3, -3, 3, -5, 3,
+ -8, 3, -13, 3, -17, 3, -21, 3, 0, 5,
+ 1, 5, 2, 5, 3, 5, 5, 5, 8, 5,
+ 13, 5, 21, 5, -1, 5, -2, 5, -3, 5,
+ -5, 5, -8, 5, -13, 5, -17, 5, -21, 5,
+ 0, 8, 1, 8, 2, 8, 3, 8, 5, 8,
+ 8, 8, 13, 8, 21, 8, -1, 8, -2, 8,
+ -3, 8, -5, 8, -8, 8, -13, 8, -17, 8,
+ -21, 8, 0, 13, 1, 13, 2, 13, 3, 13,
+ 5, 13, 8, 13, 13, 13, 21, 13, -1, 13,
+ -2, 13, -3, 13, -5, 13, -8, 13, -13, 13,
+ -17, 13, -21, 13, 0, 21, 1, 21, 2, 21,
+ 3, 21, 5, 21, 8, 21, 13, 21, 21, 21,
+ -1, 21, -2, 21, -3, 21, -5, 21, -8, 21,
+ -13, 21, -17, 21, -21, 21, 0, -1, 1, -1,
+ 2, -1, 3, -1, 5, -1, 8, -1, 13, -1,
+ 21, -1, -1, -1, -2, -1, -3, -1, -5, -1,
+ -8, -1, -13, -1, -17, -1, -21, -1, 0, -2,
+ 1, -2, 2, -2, 3, -2, 5, -2, 8, -2,
+ 13, -2, 21, -2, -1, -2, -2, -2, -3, -2,
+ -5, -2, -8, -2, -13, -2, -17, -2, -21, -2,
+ 0, -3, 1, -3, 2, -3, 3, -3, 5, -3,
+ 8, -3, 13, -3, 21, -3, -1, -3, -2, -3,
+ -3, -3, -5, -3, -8, -3, -13, -3, -17, -3,
+ -21, -3, 0, -5, 1, -5, 2, -5, 3, -5,
+ 5, -5, 8, -5, 13, -5, 21, -5, -1, -5,
+ -2, -5, -3, -5, -5, -5, -8, -5, -13, -5,
+ -17, -5, -21, -5, 0, -8, 1, -8, 2, -8,
+ 3, -8, 5, -8, 8, -8, 13, -8, 21, -8,
+ -1, -8, -2, -8, -3, -8, -5, -8, -8, -8,
+ -13, -8, -17, -8, -21, -8, 0, -13, 1, -13,
+ 2, -13, 3, -13, 5, -13, 8, -13, 13, -13,
+ 21, -13, -1, -13, -2, -13, -3, -13, -5, -13,
+ -8, -13, -13, -13, -17, -13, -21, -13, 0, -17,
+ 1, -17, 2, -17, 3, -17, 5, -17, 8, -17,
+ 13, -17, 21, -17, -1, -17, -2, -17, -3, -17,
+ -5, -17, -8, -17, -13, -17, -17, -17, -21, -17,
+ 0, -21, 1, -21, 2, -21, 3, -21, 5, -21,
+ 8, -21, 13, -21, 21, -21, -1, -21, -2, -21,
+ -3, -21, -5, -21, -8, -21, -13, -21, -17, -21,
+ 0, 0, -8, -29, 8, -29, -18, -25, 17, -25,
+ 0, -23, -6, -22, 6, -22, -13, -19, 12, -19,
+ 0, -18, 25, -18, -25, -17, -5, -17, 5, -17,
+ -10, -15, 10, -15, 0, -14, -4, -13, 4, -13,
+ 19, -13, -19, -12, -8, -11, -2, -11, 0, -11,
+ 2, -11, 8, -11, -15, -10, -4, -10, 4, -10,
+ 15, -10, -6, -9, -1, -9, 1, -9, 6, -9,
+ -29, -8, -11, -8, -8, -8, -3, -8, 3, -8,
+ 8, -8, 11, -8, 29, -8, -5, -7, -2, -7,
+ 0, -7, 2, -7, 5, -7, -22, -6, -9, -6,
+ -6, -6, -3, -6, -1, -6, 1, -6, 3, -6,
+ 6, -6, 9, -6, 22, -6, -17, -5, -7, -5,
+ -4, -5, -2, -5, 0, -5, 2, -5, 4, -5,
+ 7, -5, 17, -5, -13, -4, -10, -4, -5, -4,
+ -3, -4, -1, -4, 0, -4, 1, -4, 3, -4,
+ 5, -4, 10, -4, 13, -4, -8, -3, -6, -3,
+ -4, -3, -3, -3, -2, -3, -1, -3, 0, -3,
+ 1, -3, 2, -3, 4, -3, 6, -3, 8, -3,
+ -11, -2, -7, -2, -5, -2, -3, -2, -2, -2,
+ -1, -2, 0, -2, 1, -2, 2, -2, 3, -2,
+ 5, -2, 7, -2, 11, -2, -9, -1, -6, -1,
+ -4, -1, -3, -1, -2, -1, -1, -1, 0, -1,
+ 1, -1, 2, -1, 3, -1, 4, -1, 6, -1,
+ 9, -1, -31, 0, -23, 0, -18, 0, -14, 0,
+ -11, 0, -7, 0, -5, 0, -4, 0, -3, 0,
+ -2, 0, -1, 0, 0, -31, 1, 0, 2, 0,
+ 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
+ 14, 0, 18, 0, 23, 0, 31, 0, -9, 1,
+ -6, 1, -4, 1, -3, 1, -2, 1, -1, 1,
+ 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
+ 6, 1, 9, 1, -11, 2, -7, 2, -5, 2,
+ -3, 2, -2, 2, -1, 2, 0, 2, 1, 2,
+ 2, 2, 3, 2, 5, 2, 7, 2, 11, 2,
+ -8, 3, -6, 3, -4, 3, -2, 3, -1, 3,
+ 0, 3, 1, 3, 2, 3, 3, 3, 4, 3,
+ 6, 3, 8, 3, -13, 4, -10, 4, -5, 4,
+ -3, 4, -1, 4, 0, 4, 1, 4, 3, 4,
+ 5, 4, 10, 4, 13, 4, -17, 5, -7, 5,
+ -4, 5, -2, 5, 0, 5, 2, 5, 4, 5,
+ 7, 5, 17, 5, -22, 6, -9, 6, -6, 6,
+ -3, 6, -1, 6, 1, 6, 3, 6, 6, 6,
+ 9, 6, 22, 6, -5, 7, -2, 7, 0, 7,
+ 2, 7, 5, 7, -29, 8, -11, 8, -8, 8,
+ -3, 8, 3, 8, 8, 8, 11, 8, 29, 8,
+ -6, 9, -1, 9, 1, 9, 6, 9, -15, 10,
+ -4, 10, 4, 10, 15, 10, -8, 11, -2, 11,
+ 0, 11, 2, 11, 8, 11, 19, 12, -19, 13,
+ -4, 13, 4, 13, 0, 14, -10, 15, 10, 15,
+ -5, 17, 5, 17, 25, 17, -25, 18, 0, 18,
+ -12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
+ -17, 25, 18, 25, -8, 29, 8, 29, 0, 31,
+ 0, 0, -6, -22, 6, -22, -13, -19, 12, -19,
+ 0, -18, -5, -17, 5, -17, -10, -15, 10, -15,
+ 0, -14, -4, -13, 4, -13, 19, -13, -19, -12,
+ -8, -11, -2, -11, 0, -11, 2, -11, 8, -11,
+ -15, -10, -4, -10, 4, -10, 15, -10, -6, -9,
+ -1, -9, 1, -9, 6, -9, -11, -8, -8, -8,
+ -3, -8, 0, -8, 3, -8, 8, -8, 11, -8,
+ -5, -7, -2, -7, 0, -7, 2, -7, 5, -7,
+ -22, -6, -9, -6, -6, -6, -3, -6, -1, -6,
+ 1, -6, 3, -6, 6, -6, 9, -6, 22, -6,
+ -17, -5, -7, -5, -4, -5, -2, -5, -1, -5,
+ 0, -5, 1, -5, 2, -5, 4, -5, 7, -5,
+ 17, -5, -13, -4, -10, -4, -5, -4, -3, -4,
+ -2, -4, -1, -4, 0, -4, 1, -4, 2, -4,
+ 3, -4, 5, -4, 10, -4, 13, -4, -8, -3,
+ -6, -3, -4, -3, -3, -3, -2, -3, -1, -3,
+ 0, -3, 1, -3, 2, -3, 3, -3, 4, -3,
+ 6, -3, 8, -3, -11, -2, -7, -2, -5, -2,
+ -4, -2, -3, -2, -2, -2, -1, -2, 0, -2,
+ 1, -2, 2, -2, 3, -2, 4, -2, 5, -2,
+ 7, -2, 11, -2, -9, -1, -6, -1, -5, -1,
+ -4, -1, -3, -1, -2, -1, -1, -1, 0, -1,
+ 1, -1, 2, -1, 3, -1, 4, -1, 5, -1,
+ 6, -1, 9, -1, -23, 0, -18, 0, -14, 0,
+ -11, 0, -7, 0, -5, 0, -4, 0, -3, 0,
+ -2, 0, -1, 0, 0, -23, 1, 0, 2, 0,
+ 3, 0, 4, 0, 5, 0, 7, 0, 11, 0,
+ 14, 0, 18, 0, 23, 0, -9, 1, -6, 1,
+ -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
+ 0, 1, 1, 1, 2, 1, 3, 1, 4, 1,
+ 5, 1, 6, 1, 9, 1, -11, 2, -7, 2,
+ -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
+ 0, 2, 1, 2, 2, 2, 3, 2, 4, 2,
+ 5, 2, 7, 2, 11, 2, -8, 3, -6, 3,
+ -4, 3, -3, 3, -2, 3, -1, 3, 0, 3,
+ 1, 3, 2, 3, 3, 3, 4, 3, 6, 3,
+ 8, 3, -13, 4, -10, 4, -5, 4, -3, 4,
+ -2, 4, -1, 4, 0, 4, 1, 4, 2, 4,
+ 3, 4, 5, 4, 10, 4, 13, 4, -17, 5,
+ -7, 5, -4, 5, -2, 5, -1, 5, 0, 5,
+ 1, 5, 2, 5, 4, 5, 7, 5, 17, 5,
+ -22, 6, -9, 6, -6, 6, -3, 6, -1, 6,
+ 1, 6, 3, 6, 6, 6, 9, 6, 22, 6,
+ -5, 7, -2, 7, 0, 7, 2, 7, 5, 7,
+ -11, 8, -8, 8, -3, 8, 0, 8, 3, 8,
+ 8, 8, 11, 8, -6, 9, -1, 9, 1, 9,
+ 6, 9, -15, 10, -4, 10, 4, 10, 15, 10,
+ -8, 11, -2, 11, 0, 11, 2, 11, 8, 11,
+ 19, 12, -19, 13, -4, 13, 4, 13, 0, 14,
+ -10, 15, 10, 15, -5, 17, 5, 17, 0, 18,
+ -12, 19, 13, 19, -6, 22, 6, 22, 0, 23,
};
typedef struct SANMVideoContext {
@@ -460,7 +511,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
}
ctx->subversion = AV_RL16(avctx->extradata);
- for (i = 0; i < 256; i++)
+ for (i = 0; i < PALETTE_SIZE; i++)
ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4);
}
@@ -1466,7 +1517,7 @@ static int decode_frame(AVCodecContext *avctx, void *data,
AVCodec ff_sanm_decoder = {
.name = "sanm",
- .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM video"),
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM/Smush video"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_SANM,
.priv_data_size = sizeof(SANMVideoContext),
diff --git a/libavcodec/sbr.h b/libavcodec/sbr.h
index a47ad6eedb..e28fccda09 100644
--- a/libavcodec/sbr.h
+++ b/libavcodec/sbr.h
@@ -3,20 +3,20 @@
* Copyright (c) 2008-2009 Robert Swain ( rob opendot cl )
* Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,8 @@
#include "aacps.h"
#include "sbrdsp.h"
+typedef struct AACContext AACContext;
+
/**
* Spectral Band Replication header - spectrum parameters that invoke a reset if they differ from the previous header.
*/
@@ -108,10 +110,31 @@ typedef struct SBRData {
/** @} */
} SBRData;
+typedef struct SpectralBandReplication SpectralBandReplication;
+
+/**
+ * aacsbr functions pointers
+ */
+typedef struct AACSBRContext {
+ int (*sbr_lf_gen)(AACContext *ac, SpectralBandReplication *sbr,
+ float X_low[32][40][2], const float W[2][32][32][2],
+ int buf_idx);
+ void (*sbr_hf_assemble)(float Y1[38][64][2],
+ const float X_high[64][40][2],
+ SpectralBandReplication *sbr, SBRData *ch_data,
+ const int e_a[2]);
+ int (*sbr_x_gen)(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);
+ void (*sbr_hf_inverse_filter)(SBRDSPContext *dsp,
+ float (*alpha0)[2], float (*alpha1)[2],
+ const float X_low[32][40][2], int k0);
+} AACSBRContext;
+
/**
* Spectral Band Replication
*/
-typedef struct SpectralBandReplication {
+struct SpectralBandReplication {
int sample_rate;
int start;
int reset;
@@ -153,7 +176,7 @@ typedef struct SpectralBandReplication {
///Frequency borders for noise floors
uint16_t f_tablenoise[6];
///Frequency borders for the limiter
- uint16_t f_tablelim[29];
+ uint16_t f_tablelim[30];
unsigned num_patches;
uint8_t patch_num_subbands[6];
uint8_t patch_start_subband[6];
@@ -184,6 +207,7 @@ typedef struct SpectralBandReplication {
FFTContext mdct_ana;
FFTContext mdct;
SBRDSPContext dsp;
-} SpectralBandReplication;
+ AACSBRContext c;
+};
#endif /* AVCODEC_SBR_H */
diff --git a/libavcodec/sbrdsp.c b/libavcodec/sbrdsp.c
index b7917dc9af..e4f053b107 100644
--- a/libavcodec/sbrdsp.c
+++ b/libavcodec/sbrdsp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008-2009 Robert Swain ( rob opendot cl )
* Copyright (c) 2009-2010 Alex Converse <alex.converse@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,6 +72,7 @@ static void sbr_qmf_pre_shuffle_c(float *z)
zi[64 + 2 * k + 2].i = zi[63 - k].i ^ (1U << 31);
zi[64 + 2 * k + 3].i = zi[ k + 2].i;
}
+
zi[64 + 2 * 31 + 0].i = zi[64 - 31].i ^ (1U << 31);
zi[64 + 2 * 31 + 1].i = zi[31 + 1].i;
}
@@ -289,4 +290,6 @@ av_cold void ff_sbrdsp_init(SBRDSPContext *s)
ff_sbrdsp_init_arm(s);
if (ARCH_X86)
ff_sbrdsp_init_x86(s);
+ if (ARCH_MIPS)
+ ff_sbrdsp_init_mips(s);
}
diff --git a/libavcodec/sbrdsp.h b/libavcodec/sbrdsp.h
index 07235c68e6..1c1bcdfa90 100644
--- a/libavcodec/sbrdsp.h
+++ b/libavcodec/sbrdsp.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,5 +47,6 @@ extern const float ff_sbr_noise_table[][2];
void ff_sbrdsp_init(SBRDSPContext *s);
void ff_sbrdsp_init_arm(SBRDSPContext *s);
void ff_sbrdsp_init_x86(SBRDSPContext *s);
+void ff_sbrdsp_init_mips(SBRDSPContext *s);
#endif /* AVCODEC_SBRDSP_H */
diff --git a/libavcodec/sgi.h b/libavcodec/sgi.h
index 3c47d3a58b..5ec891e431 100644
--- a/libavcodec/sgi.h
+++ b/libavcodec/sgi.h
@@ -2,20 +2,20 @@
* SGI image encoder
* Xiaohui Sun <tjnksxh@hotmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sgidec.c b/libavcodec/sgidec.c
index ebca2e8f00..3ddbf77bc8 100644
--- a/libavcodec/sgidec.c
+++ b/libavcodec/sgidec.c
@@ -2,24 +2,25 @@
* SGI image decoder
* Todd Kirby <doubleshot@pacbell.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "bytestream.h"
#include "internal.h"
@@ -41,7 +42,7 @@ typedef struct SgiState {
* @param out_buf Points to one line after the output buffer.
* @param len length of out_buf in bytes
* @param pixelstride pixel stride of input buffer
- * @return size of output in bytes, -1 if buffer overflows
+ * @return size of output in bytes, else return error code.
*/
static int expand_rle_row8(SgiState *s, uint8_t *out_buf,
int len, int pixelstride)
@@ -59,7 +60,7 @@ static int expand_rle_row8(SgiState *s, uint8_t *out_buf,
}
/* Check for buffer overflow. */
- if (pixelstride * (count - 1) >= len) {
+ if (out_end - out_buf <= pixelstride * (count - 1)) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid pixel count.\n");
return AVERROR_INVALIDDATA;
}
@@ -97,7 +98,7 @@ static int expand_rle_row16(SgiState *s, uint16_t *out_buf,
break;
/* Check for buffer overflow. */
- if (pixelstride * (count - 1) >= len) {
+ if (out_end - out_buf <= pixelstride * (count - 1)) {
av_log(s->avctx, AV_LOG_ERROR, "Invalid pixel count.\n");
return AVERROR_INVALIDDATA;
}
@@ -125,7 +126,7 @@ static int expand_rle_row16(SgiState *s, uint16_t *out_buf,
* Read a run length encoded SGI image.
* @param out_buf output buffer
* @param s the current image state
- * @return 0 if no error, else return error number.
+ * @return 0 if no error, else return error code.
*/
static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
{
@@ -144,7 +145,7 @@ static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
for (z = 0; z < s->depth; z++) {
dest_row = out_buf;
for (y = 0; y < s->height; y++) {
- linesize = s->width * s->depth * s->bytes_per_channel;
+ linesize = s->width * s->depth;
dest_row -= s->linesize;
start_offset = bytestream2_get_be32(&g_table);
bytestream2_seek(&s->g, start_offset, SEEK_SET);
@@ -163,7 +164,7 @@ static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
* Read an uncompressed SGI image.
* @param out_buf output buffer
* @param s the current image state
- * @return 0 if read success, otherwise return -1.
+ * @return 0 if read success, else return error code.
*/
static int read_uncompressed_sgi(unsigned char *out_buf, SgiState *s)
{
@@ -215,27 +216,27 @@ static int decode_frame(AVCodecContext *avctx,
}
/* Test for SGI magic. */
- if (bytestream2_get_be16(&s->g) != SGI_MAGIC) {
+ if (bytestream2_get_be16u(&s->g) != SGI_MAGIC) {
av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
return AVERROR_INVALIDDATA;
}
- rle = bytestream2_get_byte(&s->g);
- s->bytes_per_channel = bytestream2_get_byte(&s->g);
- dimension = bytestream2_get_be16(&s->g);
- s->width = bytestream2_get_be16(&s->g);
- s->height = bytestream2_get_be16(&s->g);
- s->depth = bytestream2_get_be16(&s->g);
+ rle = bytestream2_get_byteu(&s->g);
+ s->bytes_per_channel = bytestream2_get_byteu(&s->g);
+ dimension = bytestream2_get_be16u(&s->g);
+ s->width = bytestream2_get_be16u(&s->g);
+ s->height = bytestream2_get_be16u(&s->g);
+ s->depth = bytestream2_get_be16u(&s->g);
if (s->bytes_per_channel != 1 && s->bytes_per_channel != 2) {
av_log(avctx, AV_LOG_ERROR, "wrong channel number\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
/* Check for supported image dimensions. */
if (dimension != 2 && dimension != 3) {
av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (s->depth == SGI_GRAYSCALE) {
@@ -246,17 +247,15 @@ static int decode_frame(AVCodecContext *avctx,
avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_RGBA64BE : AV_PIX_FMT_RGBA;
} else {
av_log(avctx, AV_LOG_ERROR, "wrong picture format\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
- if (ff_get_buffer(avctx, p, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n");
- return -1;
- }
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
+ return ret;
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
@@ -273,13 +272,11 @@ static int decode_frame(AVCodecContext *avctx,
} else {
ret = read_uncompressed_sgi(out_buf, s);
}
-
- if (ret == 0) {
- *got_frame = 1;
- return avpkt->size;
- } else {
+ if (ret)
return ret;
- }
+
+ *got_frame = 1;
+ return avpkt->size;
}
static av_cold int sgi_decode_init(AVCodecContext *avctx)
diff --git a/libavcodec/sgienc.c b/libavcodec/sgienc.c
index bfc0995a5a..2f45eb3984 100644
--- a/libavcodec/sgienc.c
+++ b/libavcodec/sgienc.c
@@ -2,20 +2,20 @@
* SGI image encoder
* Todd Kirby <doubleshot@pacbell.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (avctx->width > 65535 || avctx->height > 65535) {
av_log(avctx, AV_LOG_ERROR,
"Unsupported resolution %dx%d.\n", avctx->width, avctx->height);
+ av_log(avctx, AV_LOG_ERROR, "SGI does not support resolutions above 65535x65535\n");
return AVERROR_INVALIDDATA;
}
@@ -113,10 +114,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
else // assume ff_rl_encode() produces at most 2x size of input
length += tablesize * 2 + depth * height * (2 * width + 1);
- if ((ret = ff_alloc_packet(pkt, bytes_per_channel * length)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet of size %d.\n", length);
+ if ((ret = ff_alloc_packet2(avctx, pkt, bytes_per_channel * length)) < 0)
return ret;
- }
buf = pkt->data;
end_buf = pkt->data + pkt->size;
@@ -154,7 +153,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* Make an intermediate consecutive buffer. */
if (!(encode_buf = av_malloc(width)))
- return -1;
+ return AVERROR(ENOMEM);
for (z = 0; z < depth; z++) {
in_buf = p->data[0] + p->linesize[0] * (height - 1) + z;
@@ -184,13 +183,15 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
for (y = 0; y < height; y++) {
for (x = 0; x < width * depth; x += depth)
- if (bytes_per_channel == 1)
+ if (bytes_per_channel == 1) {
bytestream_put_byte(&buf, in_buf[x]);
- else
- if (put_be)
+ } else {
+ if (put_be) {
bytestream_put_be16(&buf, ((uint16_t *)in_buf)[x]);
- else
+ } else {
bytestream_put_le16(&buf, ((uint16_t *)in_buf)[x]);
+ }
+ }
in_buf -= p->linesize[0];
}
diff --git a/libavcodec/sgirledec.c b/libavcodec/sgirledec.c
index d7bc5a9ea4..69d012e8e4 100644
--- a/libavcodec/sgirledec.c
+++ b/libavcodec/sgirledec.c
@@ -2,20 +2,20 @@
* Silicon Graphics RLE 8-bit video decoder
* Copyright (c) 2012 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,9 +49,9 @@ static av_cold int sgirle_decode_init(AVCodecContext *avctx)
* Convert SGI RBG323 pixel into AV_PIX_FMT_BGR8
* SGI RGB data is packed as 8bpp, (msb)3R 2B 3G(lsb)
*/
-#define RBG323_TO_BGR8(x) (((x << 3) & 0xC0) | \
- ((x << 3) & 0x38) | \
- ((x >> 5) & 7))
+#define RBG323_TO_BGR8(x) ((((x) << 3) & 0xC0) | \
+ (((x) << 3) & 0x38) | \
+ (((x) >> 5) & 7))
static av_always_inline
void rbg323_to_bgr8(uint8_t *dst, const uint8_t *src, int size)
{
@@ -110,8 +110,8 @@ static int decode_sgirle8(AVCodecContext *avctx, uint8_t *dst,
v -= length;
} while (v > 0);
} else {
- av_log(avctx, AV_LOG_ERROR, "Invalid opcode %d.\n", v);
- return AVERROR_INVALIDDATA;
+ avpriv_request_sample(avctx, "opcode %d", v);
+ return AVERROR_PATCHWELCOME;
}
}
return 0;
diff --git a/libavcodec/sh4/README b/libavcodec/sh4/README
new file mode 100644
index 0000000000..8dd61fe875
--- /dev/null
+++ b/libavcodec/sh4/README
@@ -0,0 +1,6 @@
+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/shorten.c b/libavcodec/shorten.c
index c93ba6b026..db2e3c5feb 100644
--- a/libavcodec/shorten.c
+++ b/libavcodec/shorten.c
@@ -2,20 +2,20 @@
* Shorten decoder
* Copyright (c) 2005 Jeff Muizelaar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,8 +50,12 @@
#define ENERGYSIZE 3
#define BITSHIFTSIZE 2
+#define TYPE_S8 1
+#define TYPE_U8 2
#define TYPE_S16HL 3
+#define TYPE_U16HL 4
#define TYPE_S16LH 5
+#define TYPE_U16LH 6
#define NWRAP 3
#define NSKIPSIZE 1
@@ -112,7 +116,6 @@ static av_cold int shorten_decode_init(AVCodecContext *avctx)
{
ShortenContext *s = avctx->priv_data;
s->avctx = avctx;
- avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
return 0;
}
@@ -126,19 +129,18 @@ static int allocate_buffers(ShortenContext *s)
av_log(s->avctx, AV_LOG_ERROR, "nmean too large\n");
return AVERROR_INVALIDDATA;
}
- if (s->blocksize + s->nwrap >= UINT_MAX / sizeof(int32_t) ||
- s->blocksize + s->nwrap <= (unsigned)s->nwrap) {
+ if (s->blocksize + (uint64_t)s->nwrap >= UINT_MAX / sizeof(int32_t)) {
av_log(s->avctx, AV_LOG_ERROR,
"s->blocksize + s->nwrap too large\n");
return AVERROR_INVALIDDATA;
}
- if ((err = av_reallocp(&s->offset[chan],
- sizeof(int32_t) *
+ if ((err = av_reallocp_array(&s->offset[chan],
+ sizeof(int32_t),
FFMAX(1, s->nmean))) < 0)
return err;
- if ((err = av_reallocp(&s->decoded_base[chan], (s->blocksize + s->nwrap) *
+ if ((err = av_reallocp_array(&s->decoded_base[chan], (s->blocksize + s->nwrap),
sizeof(s->decoded_base[0][0]))) < 0)
return err;
for (i = 0; i < s->nwrap; i++)
@@ -146,7 +148,7 @@ static int allocate_buffers(ShortenContext *s)
s->decoded[chan] = s->decoded_base[chan] + s->nwrap;
}
- if ((err = av_reallocp(&s->coeffs, s->nwrap * sizeof(*s->coeffs))) < 0)
+ if ((err = av_reallocp_array(&s->coeffs, s->nwrap, sizeof(*s->coeffs))) < 0)
return err;
return 0;
@@ -175,13 +177,17 @@ static int init_offset(ShortenContext *s)
int nblock = FFMAX(1, s->nmean);
/* initialise offset */
switch (s->internal_ftype) {
+ case TYPE_U8:
+ s->avctx->sample_fmt = AV_SAMPLE_FMT_U8P;
+ mean = 0x80;
+ break;
case TYPE_S16HL:
case TYPE_S16LH:
- mean = 0;
+ s->avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
break;
default:
- av_log(s->avctx, AV_LOG_ERROR, "unknown audio type");
- return AVERROR_INVALIDDATA;
+ av_log(s->avctx, AV_LOG_ERROR, "unknown audio type\n");
+ return AVERROR_PATCHWELCOME;
}
for (chan = 0; chan < s->channels; chan++)
@@ -193,7 +199,7 @@ static int init_offset(ShortenContext *s)
static int decode_wave_header(AVCodecContext *avctx, const uint8_t *header,
int header_size)
{
- int len;
+ int len, bps;
short wave_format;
GetByteContext gb;
@@ -214,7 +220,7 @@ static int decode_wave_header(AVCodecContext *avctx, const uint8_t *header,
while (bytestream2_get_le32(&gb) != MKTAG('f', 'm', 't', ' ')) {
len = bytestream2_get_le32(&gb);
bytestream2_skip(&gb, len);
- if (bytestream2_get_bytes_left(&gb) < 16) {
+ if (len < 0 || bytestream2_get_bytes_left(&gb) < 16) {
av_log(avctx, AV_LOG_ERROR, "no fmt chunk found\n");
return AVERROR_INVALIDDATA;
}
@@ -240,10 +246,11 @@ static int decode_wave_header(AVCodecContext *avctx, const uint8_t *header,
avctx->sample_rate = bytestream2_get_le32(&gb);
bytestream2_skip(&gb, 4); // skip bit rate (represents original uncompressed bit rate)
bytestream2_skip(&gb, 2); // skip block align (not needed)
- avctx->bits_per_coded_sample = bytestream2_get_le16(&gb);
+ bps = bytestream2_get_le16(&gb);
+ avctx->bits_per_coded_sample = bps;
- if (avctx->bits_per_coded_sample != 16) {
- av_log(avctx, AV_LOG_ERROR, "unsupported number of bits per sample\n");
+ if (bps != 16 && bps != 8) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported number of bits per sample: %d\n", bps);
return AVERROR(ENOSYS);
}
@@ -254,18 +261,6 @@ static int decode_wave_header(AVCodecContext *avctx, const uint8_t *header,
return 0;
}
-static void output_buffer(int16_t **samples, int nchan, int blocksize,
- int32_t **buffer)
-{
- int i, ch;
- for (ch = 0; ch < nchan; ch++) {
- int32_t *in = buffer[ch];
- int16_t *out = samples[ch];
- for (i = 0; i < blocksize; i++)
- out[i] = av_clip_int16(in[i]);
- }
-}
-
static const int fixed_coeffs[][3] = {
{ 0, 0, 0 },
{ 1, 0, 0 },
@@ -282,7 +277,7 @@ static int decode_subframe_lpc(ShortenContext *s, int command, int channel,
if (command == FN_QLPC) {
/* read/validate prediction order */
pred_order = get_ur_golomb_shorten(&s->gb, LPCQSIZE);
- if (pred_order > s->nwrap) {
+ if ((unsigned)pred_order > s->nwrap) {
av_log(s->avctx, AV_LOG_ERROR, "invalid pred_order %d\n",
pred_order);
return AVERROR(EINVAL);
@@ -374,6 +369,11 @@ static int read_header(ShortenContext *s)
s->nmean = get_uint(s, 0);
skip_bytes = get_uint(s, NSKIPSIZE);
+ if ((unsigned)skip_bytes > get_bits_left(&s->gb)/8) {
+ av_log(s->avctx, AV_LOG_ERROR, "invalid skip_bytes: %d\n", skip_bytes);
+ return AVERROR_INVALIDDATA;
+ }
+
for (i = 0; i < skip_bytes; i++)
skip_bits(&s->gb, 8);
}
@@ -429,13 +429,14 @@ static int shorten_decode_frame(AVCodecContext *avctx, void *data,
/* allocate internal bitstream buffer */
if (s->max_framesize == 0) {
void *tmp_ptr;
- s->max_framesize = 1024; // should hopefully be enough for the first header
+ s->max_framesize = 8192; // should hopefully be enough for the first header
tmp_ptr = av_fast_realloc(s->bitstream, &s->allocated_bitstream_size,
s->max_framesize + FF_INPUT_BUFFER_PADDING_SIZE);
if (!tmp_ptr) {
av_log(avctx, AV_LOG_ERROR, "error allocating bitstream buffer\n");
return AVERROR(ENOMEM);
}
+ memset(tmp_ptr, 0, s->allocated_bitstream_size);
s->bitstream = tmp_ptr;
}
@@ -444,7 +445,7 @@ static int shorten_decode_frame(AVCodecContext *avctx, void *data,
buf_size = FFMIN(buf_size, s->max_framesize - s->bitstream_size);
input_buf_size = buf_size;
- if (s->bitstream_index + s->bitstream_size + buf_size >
+ if (s->bitstream_index + s->bitstream_size + buf_size + FF_INPUT_BUFFER_PADDING_SIZE >
s->allocated_bitstream_size) {
memmove(s->bitstream, &s->bitstream[s->bitstream_index],
s->bitstream_size);
@@ -508,11 +509,16 @@ static int shorten_decode_frame(AVCodecContext *avctx, void *data,
while (len--)
get_ur_golomb_shorten(&s->gb, VERBATIM_BYTE_SIZE);
break;
- case FN_BITSHIFT:
- s->bitshift = get_ur_golomb_shorten(&s->gb, BITSHIFTSIZE);
- if (s->bitshift < 0)
+ case FN_BITSHIFT: {
+ unsigned bitshift = get_ur_golomb_shorten(&s->gb, BITSHIFTSIZE);
+ if (bitshift > 31) {
+ av_log(avctx, AV_LOG_ERROR, "bitshift %d is invalid\n",
+ bitshift);
return AVERROR_INVALIDDATA;
+ }
+ s->bitshift = bitshift;
break;
+ }
case FN_BLOCKSIZE: {
unsigned blocksize = get_uint(s, av_log2(s->blocksize));
if (blocksize > s->blocksize) {
@@ -560,7 +566,7 @@ static int shorten_decode_frame(AVCodecContext *avctx, void *data,
sum += s->offset[channel][i];
coffset = sum / s->nmean;
if (s->version >= 2)
- coffset >>= FFMIN(1, s->bitshift);
+ coffset = s->bitshift == 0 ? coffset : coffset >> s->bitshift - 1 >> 1;
}
/* decode samples for this channel */
@@ -599,15 +605,30 @@ static int shorten_decode_frame(AVCodecContext *avctx, void *data,
/* if this is the last channel in the block, output the samples */
s->cur_chan++;
if (s->cur_chan == s->channels) {
+ uint8_t *samples_u8;
+ int16_t *samples_s16;
+ int chan;
+
/* get output buffer */
frame->nb_samples = s->blocksize;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
+
+ for (chan = 0; chan < s->channels; chan++) {
+ samples_u8 = ((uint8_t **)frame->extended_data)[chan];
+ samples_s16 = ((int16_t **)frame->extended_data)[chan];
+ for (i = 0; i < s->blocksize; i++) {
+ switch (s->internal_ftype) {
+ case TYPE_U8:
+ *samples_u8++ = av_clip_uint8(s->decoded[chan][i]);
+ break;
+ case TYPE_S16HL:
+ case TYPE_S16LH:
+ *samples_s16++ = av_clip_int16(s->decoded[chan][i]);
+ break;
+ }
+ }
}
- /* interleave output */
- output_buffer((int16_t **)frame->extended_data, s->channels,
- s->blocksize, s->decoded);
*got_frame_ptr = 1;
}
@@ -660,5 +681,6 @@ AVCodec ff_shorten_decoder = {
.decode = shorten_decode_frame,
.capabilities = CODEC_CAP_DELAY | CODEC_CAP_DR1,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_NONE },
};
diff --git a/libavcodec/simple_idct.c b/libavcodec/simple_idct.c
index f61e9e639d..eeb627999c 100644
--- a/libavcodec/simple_idct.c
+++ b/libavcodec/simple_idct.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,6 +38,10 @@
#include "simple_idct_template.c"
#undef BIT_DEPTH
+#define BIT_DEPTH 12
+#include "simple_idct_template.c"
+#undef BIT_DEPTH
+
/* 2x4x8 idct */
#define CN_SHIFT 12
@@ -228,6 +232,8 @@ void ff_prores_idct(int16_t *block, const int16_t *qmat)
for (i = 0; i < 8; i++)
idctRowCondDC_10(block + i*8, 2);
- for (i = 0; i < 8; i++)
+ for (i = 0; i < 8; i++) {
+ block[i] += 8192;
idctSparseCol_10(block + i);
+ }
}
diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h
index 7f14aae5d0..154e297470 100644
--- a/libavcodec/simple_idct.h
+++ b/libavcodec/simple_idct.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,6 +37,11 @@ void ff_simple_idct_8(int16_t *block);
void ff_simple_idct_put_10(uint8_t *dest, int line_size, int16_t *block);
void ff_simple_idct_add_10(uint8_t *dest, int line_size, int16_t *block);
void ff_simple_idct_10(int16_t *block);
+
+void ff_simple_idct_put_12(uint8_t *dest, int line_size, int16_t *block);
+void ff_simple_idct_add_12(uint8_t *dest, int line_size, int16_t *block);
+void ff_simple_idct_12(int16_t *block);
+
/**
* Special version of ff_simple_idct_10() which does dequantization
* and scales by a factor of 2 more between the two IDCTs to account
diff --git a/libavcodec/simple_idct_template.c b/libavcodec/simple_idct_template.c
index b287c4f6bf..789db8d0ac 100644
--- a/libavcodec/simple_idct_template.c
+++ b/libavcodec/simple_idct_template.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2001 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,19 +64,33 @@
#define MUL(a, b) MUL16(a, b)
#define MAC(a, b, c) MAC16(a, b, c)
-#elif BIT_DEPTH == 10
+#elif BIT_DEPTH == 10 || BIT_DEPTH == 12
-#define W1 90901
-#define W2 85627
-#define W3 77062
-#define W4 65535
-#define W5 51491
-#define W6 35468
-#define W7 18081
+#if BIT_DEPTH == 10
+#define W1 (22725*4) // 90901
+#define W2 (21407*4) // 85627
+#define W3 (19265*4) // 77062
+#define W4 (16384*4) // 65535
+#define W5 (12873*4) // 51491
+#define W6 ( 8867*4) // 35468
+#define W7 ( 4520*4) // 18081
#define ROW_SHIFT 15
#define COL_SHIFT 20
#define DC_SHIFT 1
+#else
+#define W1 45451
+#define W2 42813
+#define W3 38531
+#define W4 32767
+#define W5 25746
+#define W6 17734
+#define W7 9041
+
+#define ROW_SHIFT 16
+#define COL_SHIFT 17
+#define DC_SHIFT -1
+#endif
#define MUL(a, b) ((a) * (b))
#define MAC(a, b, c) ((a) += (b) * (c))
@@ -95,13 +109,13 @@ static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift)
#define ROW0_MASK (0xffffLL << 48 * HAVE_BIGENDIAN)
if (((((uint64_t *)row)[0] & ~ROW0_MASK) | ((uint64_t *)row)[1]) == 0) {
uint64_t temp;
- if (DC_SHIFT - extra_shift > 0) {
- temp = (row[0] << (DC_SHIFT - extra_shift)) & 0xffff;
+ if (DC_SHIFT - extra_shift >= 0) {
+ temp = (row[0] * (1 << (DC_SHIFT - extra_shift))) & 0xffff;
} else {
- temp = (row[0] >> (extra_shift - DC_SHIFT)) & 0xffff;
+ temp = ((row[0] + (1<<(extra_shift - DC_SHIFT-1))) >> (extra_shift - DC_SHIFT)) & 0xffff;
}
- temp += temp << 16;
- temp += temp << 32;
+ temp += temp * (1 << 16);
+ temp += temp * ((uint64_t) 1 << 32);
((uint64_t *)row)[0] = temp;
((uint64_t *)row)[1] = temp;
return;
@@ -112,19 +126,19 @@ static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift)
((uint32_t*)row)[3] |
row[1])) {
uint32_t temp;
- if (DC_SHIFT - extra_shift > 0) {
- temp = (row[0] << (DC_SHIFT - extra_shift)) & 0xffff;
+ if (DC_SHIFT - extra_shift >= 0) {
+ temp = (row[0] * (1 << (DC_SHIFT - extra_shift))) & 0xffff;
} else {
- temp = (row[0] >> (extra_shift - DC_SHIFT)) & 0xffff;
+ temp = ((row[0] + (1<<(extra_shift - DC_SHIFT-1))) >> (extra_shift - DC_SHIFT)) & 0xffff;
}
- temp += temp << 16;
+ temp += temp * (1 << 16);
((uint32_t*)row)[0]=((uint32_t*)row)[1] =
((uint32_t*)row)[2]=((uint32_t*)row)[3] = temp;
return;
}
#endif
- a0 = (W4 * row[0]) + (1 << (ROW_SHIFT - 1));
+ a0 = (W4 * row[0]) + (1 << (ROW_SHIFT + extra_shift - 1));
a1 = a0;
a2 = a0;
a3 = a0;
diff --git a/libavcodec/sinewin.c b/libavcodec/sinewin.c
index be38dbc713..1fa0e953f0 100644
--- a/libavcodec/sinewin.c
+++ b/libavcodec/sinewin.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sinewin.h b/libavcodec/sinewin.h
index 478036d3c6..2268fd52f4 100644
--- a/libavcodec/sinewin.h
+++ b/libavcodec/sinewin.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Robert Swain
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sinewin_tablegen.c b/libavcodec/sinewin_tablegen.c
index 90a75c2267..561ae3ea1d 100644
--- a/libavcodec/sinewin_tablegen.c
+++ b/libavcodec/sinewin_tablegen.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sinewin_tablegen.h b/libavcodec/sinewin_tablegen.h
index 1ee225bf67..2b9c4f2393 100644
--- a/libavcodec/sinewin_tablegen.h
+++ b/libavcodec/sinewin_tablegen.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sipr.c b/libavcodec/sipr.c
index 81c38a3a99..af1edf50b8 100644
--- a/libavcodec/sipr.c
+++ b/libavcodec/sipr.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 Vladimir Voroshilov
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -139,7 +139,7 @@ const float ff_pow_0_5[] = {
1.0/(1 << 13), 1.0/(1 << 14), 1.0/(1 << 15), 1.0/(1 << 16)
};
-static void dequant(float *out, const int *idx, const float *cbs[])
+static void dequant(float *out, const int *idx, const float * const cbs[])
{
int i;
int stride = 2;
@@ -543,10 +543,8 @@ static int sipr_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = mode_par->frames_per_packet * subframe_size *
mode_par->subframe_count;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (float *)frame->data[0];
init_get_bits(&gb, buf, mode_par->bits_per_frame);
diff --git a/libavcodec/sipr.h b/libavcodec/sipr.h
index 4cdea67e51..34f7f994cd 100644
--- a/libavcodec/sipr.h
+++ b/libavcodec/sipr.h
@@ -4,20 +4,20 @@
* Copyright (c) 2008 Vladimir Voroshilov
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sipr16k.c b/libavcodec/sipr16k.c
index f7fcb34315..9c8f684003 100644
--- a/libavcodec/sipr16k.c
+++ b/libavcodec/sipr16k.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 Vladimir Voroshilov
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,7 +29,6 @@
#include "libavutil/float_dsp.h"
#include "libavutil/mathematics.h"
#include "lsp.h"
-#include "celp_filters.h"
#include "acelp_vectors.h"
#include "acelp_pitch_delay.h"
#include "acelp_filters.h"
@@ -51,7 +50,7 @@ static void lsf2lsp(const float *lsf, double *lsp)
lsp[i] = cosf(lsf[i]);
}
-static void dequant(float *out, const int *idx, const float *cbs[])
+static void dequant(float *out, const int *idx, const float * const cbs[])
{
int i;
diff --git a/libavcodec/sipr16kdata.h b/libavcodec/sipr16kdata.h
index ec60c29b51..16a653da94 100644
--- a/libavcodec/sipr16kdata.h
+++ b/libavcodec/sipr16kdata.h
@@ -4,20 +4,20 @@
* Copyright (c) 2008 Vladimir Voroshilov
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -525,7 +525,7 @@ static const float lsf_cb5_16k[128][4] = {
{ 0.124405, 0.009943, -0.148477, -0.205184}
};
-static const float *lsf_codebooks_16k[] = {
+static const float * const lsf_codebooks_16k[] = {
lsf_cb1_16k[0], lsf_cb2_16k[0], lsf_cb3_16k[0], lsf_cb4_16k[0],
lsf_cb5_16k[0]
};
diff --git a/libavcodec/siprdata.h b/libavcodec/siprdata.h
index 92037a4a87..0dbc113fca 100644
--- a/libavcodec/siprdata.h
+++ b/libavcodec/siprdata.h
@@ -4,20 +4,20 @@
* Copyright (c) 2008 Vladimir Voroshilov
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -206,7 +206,7 @@ static const float lsf_cb5[32][2] = {
{ 0.150514, 0.034366}, { 0.186092, -0.069272}
};
-static const float *lsf_codebooks[] = {
+static const float * const lsf_codebooks[] = {
lsf_cb1[0], lsf_cb2[0], lsf_cb3[0], lsf_cb4[0], lsf_cb5[0]
};
diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c
index ba693034e5..b5538c7494 100644
--- a/libavcodec/smacker.c
+++ b/libavcodec/smacker.c
@@ -2,20 +2,20 @@
* Smacker decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -97,10 +97,14 @@ enum SmkBlockTypes {
*/
static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length)
{
+ if(length > 32 || length > 3*SMKTREE_BITS) {
+ av_log(NULL, AV_LOG_ERROR, "length too long\n");
+ return AVERROR_INVALIDDATA;
+ }
if(!get_bits1(gb)){ //Leaf
- if(hc->current >= 256){
+ if(hc->current >= hc->length){
av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(length){
hc->bits[hc->current] = prefix;
@@ -131,14 +135,14 @@ static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, DBCtx *ctx
{
if (hc->current + 1 >= hc->length) {
av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(!get_bits1(gb)){ //Leaf
int val, i1, i2;
i1 = ctx->v1->table ? get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3) : 0;
i2 = ctx->v2->table ? get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3) : 0;
if (i1 < 0 || i2 < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
val = ctx->recode1[i1] | (ctx->recode2[i2] << 8);
if(val == ctx->escapes[0]) {
ctx->last[0] = hc->current;
@@ -170,7 +174,7 @@ static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, DBCtx *ctx
}
/**
- * Store large tree as Libav's vlc codes
+ * Store large tree as FFmpeg's vlc codes
*/
static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int **recodes, int *last, int size)
{
@@ -184,7 +188,7 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
if(size >= UINT_MAX>>4){ // (((size + 3) >> 2) + 3) << 2 must not overflow
av_log(smk->avctx, AV_LOG_ERROR, "size too large\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
tmp1.length = 256;
@@ -207,40 +211,51 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
}
if(get_bits1(gb)) {
- smacker_decode_tree(gb, &tmp1, 0, 0);
- skip_bits1(gb);
- res = init_vlc(&vlc[0], SMKTREE_BITS, tmp1.length,
- tmp1.lengths, sizeof(int), sizeof(int),
- tmp1.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
- if(res < 0) {
- av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
+ res = smacker_decode_tree(gb, &tmp1, 0, 0);
+ if (res < 0) {
err = res;
goto error;
}
- } else {
+ skip_bits1(gb);
+ if(tmp1.current > 1) {
+ res = init_vlc(&vlc[0], SMKTREE_BITS, tmp1.length,
+ tmp1.lengths, sizeof(int), sizeof(int),
+ tmp1.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
+ if(res < 0) {
+ av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
+ err = res;
+ goto error;
+ }
+ }
+ }
+ if (!vlc[0].table) {
av_log(smk->avctx, AV_LOG_ERROR, "Skipping low bytes tree\n");
}
if(get_bits1(gb)){
- smacker_decode_tree(gb, &tmp2, 0, 0);
- skip_bits1(gb);
- res = init_vlc(&vlc[1], SMKTREE_BITS, tmp2.length,
- tmp2.lengths, sizeof(int), sizeof(int),
- tmp2.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
- if(res < 0) {
- av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
+ res = smacker_decode_tree(gb, &tmp2, 0, 0);
+ if (res < 0) {
err = res;
goto error;
}
- } else {
+ skip_bits1(gb);
+ if(tmp2.current > 1) {
+ res = init_vlc(&vlc[1], SMKTREE_BITS, tmp2.length,
+ tmp2.lengths, sizeof(int), sizeof(int),
+ tmp2.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);
+ if(res < 0) {
+ av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
+ err = res;
+ goto error;
+ }
+ }
+ }
+ if (!vlc[1].table) {
av_log(smk->avctx, AV_LOG_ERROR, "Skipping high bytes tree\n");
}
- escapes[0] = get_bits(gb, 8);
- escapes[0] |= get_bits(gb, 8) << 8;
- escapes[1] = get_bits(gb, 8);
- escapes[1] |= get_bits(gb, 8) << 8;
- escapes[2] = get_bits(gb, 8);
- escapes[2] |= get_bits(gb, 8) << 8;
+ escapes[0] = get_bits(gb, 16);
+ escapes[1] = get_bits(gb, 16);
+ escapes[2] = get_bits(gb, 16);
last[0] = last[1] = last[2] = -1;
@@ -256,7 +271,7 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
huff.length = ((size + 3) >> 2) + 4;
huff.maxlength = 0;
huff.current = 0;
- huff.values = av_mallocz(huff.length * sizeof(int));
+ huff.values = av_mallocz_array(huff.length, sizeof(int));
if (!huff.values) {
err = AVERROR(ENOMEM);
goto error;
@@ -294,14 +309,14 @@ error:
static int decode_header_trees(SmackVContext *smk) {
GetBitContext gb;
- int mmap_size, mclr_size, full_size, type_size;
+ int mmap_size, mclr_size, full_size, type_size, ret;
mmap_size = AV_RL32(smk->avctx->extradata);
mclr_size = AV_RL32(smk->avctx->extradata + 4);
full_size = AV_RL32(smk->avctx->extradata + 8);
type_size = AV_RL32(smk->avctx->extradata + 12);
- init_get_bits(&gb, smk->avctx->extradata + 16, (smk->avctx->extradata_size - 16) * 8);
+ init_get_bits8(&gb, smk->avctx->extradata + 16, smk->avctx->extradata_size - 16);
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping MMAP tree\n");
@@ -311,8 +326,9 @@ static int decode_header_trees(SmackVContext *smk) {
smk->mmap_tbl[0] = 0;
smk->mmap_last[0] = smk->mmap_last[1] = smk->mmap_last[2] = 1;
} else {
- if (smacker_decode_header_tree(smk, &gb, &smk->mmap_tbl, smk->mmap_last, mmap_size))
- return -1;
+ ret = smacker_decode_header_tree(smk, &gb, &smk->mmap_tbl, smk->mmap_last, mmap_size);
+ if (ret < 0)
+ return ret;
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping MCLR tree\n");
@@ -322,8 +338,9 @@ static int decode_header_trees(SmackVContext *smk) {
smk->mclr_tbl[0] = 0;
smk->mclr_last[0] = smk->mclr_last[1] = smk->mclr_last[2] = 1;
} else {
- if (smacker_decode_header_tree(smk, &gb, &smk->mclr_tbl, smk->mclr_last, mclr_size))
- return -1;
+ ret = smacker_decode_header_tree(smk, &gb, &smk->mclr_tbl, smk->mclr_last, mclr_size);
+ if (ret < 0)
+ return ret;
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping FULL tree\n");
@@ -333,8 +350,9 @@ static int decode_header_trees(SmackVContext *smk) {
smk->full_tbl[0] = 0;
smk->full_last[0] = smk->full_last[1] = smk->full_last[2] = 1;
} else {
- if (smacker_decode_header_tree(smk, &gb, &smk->full_tbl, smk->full_last, full_size))
- return -1;
+ ret = smacker_decode_header_tree(smk, &gb, &smk->full_tbl, smk->full_last, full_size);
+ if (ret < 0)
+ return ret;
}
if(!get_bits1(&gb)) {
av_log(smk->avctx, AV_LOG_INFO, "Skipping TYPE tree\n");
@@ -344,8 +362,9 @@ static int decode_header_trees(SmackVContext *smk) {
smk->type_tbl[0] = 0;
smk->type_last[0] = smk->type_last[1] = smk->type_last[2] = 1;
} else {
- if (smacker_decode_header_tree(smk, &gb, &smk->type_tbl, smk->type_last, type_size))
- return -1;
+ ret = smacker_decode_header_tree(smk, &gb, &smk->type_tbl, smk->type_last, type_size);
+ if (ret < 0)
+ return ret;
}
return 0;
@@ -389,12 +408,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int flags;
if (avpkt->size <= 769)
- return 0;
+ return AVERROR_INVALIDDATA;
- if ((ret = ff_reget_buffer(avctx, smk->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, smk->pic)) < 0)
return ret;
- }
/* make the palette available on the way out */
pal = (uint32_t*)smk->pic->data[1];
@@ -402,25 +419,25 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
flags = bytestream2_get_byteu(&gb2);
smk->pic->palette_has_changed = flags & 1;
smk->pic->key_frame = !!(flags & 2);
- if(smk->pic->key_frame)
+ if (smk->pic->key_frame)
smk->pic->pict_type = AV_PICTURE_TYPE_I;
else
smk->pic->pict_type = AV_PICTURE_TYPE_P;
for(i = 0; i < 256; i++)
- *pal++ = bytestream2_get_be24u(&gb2);
+ *pal++ = 0xFFU << 24 | bytestream2_get_be24u(&gb2);
last_reset(smk->mmap_tbl, smk->mmap_last);
last_reset(smk->mclr_tbl, smk->mclr_last);
last_reset(smk->full_tbl, smk->full_last);
last_reset(smk->type_tbl, smk->type_last);
- init_get_bits(&gb, avpkt->data + 769, (avpkt->size - 769) * 8);
+ if ((ret = init_get_bits8(&gb, avpkt->data + 769, avpkt->size - 769)) < 0)
+ return ret;
blk = 0;
bw = avctx->width >> 2;
bh = avctx->height >> 2;
blocks = bw * bh;
- out = smk->pic->data[0];
stride = smk->pic->linesize[0];
while(blk < blocks) {
int type, run, mode;
@@ -481,7 +498,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
out += stride;
out[0] = out[1] = pix & 0xFF;
out[2] = out[3] = pix >> 8;
- out += stride;
break;
case 2:
for(i = 0; i < 2; i++) {
@@ -560,6 +576,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
static av_cold int decode_init(AVCodecContext *avctx)
{
SmackVContext * const c = avctx->priv_data;
+ int ret;
c->avctx = avctx;
@@ -572,19 +589,20 @@ static av_cold int decode_init(AVCodecContext *avctx)
/* decode huffman trees from extradata */
if(avctx->extradata_size < 16){
av_log(avctx, AV_LOG_ERROR, "Extradata missing!\n");
- return -1;
+ decode_end(avctx);
+ return AVERROR(EINVAL);
}
- if (decode_header_trees(c)) {
+ ret = decode_header_trees(c);
+ if (ret < 0) {
decode_end(avctx);
- return -1;
+ return ret;
}
return 0;
}
-
static av_cold int smka_decode_init(AVCodecContext *avctx)
{
if (avctx->channels < 1 || avctx->channels > 2) {
@@ -624,7 +642,13 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
unp_size = AV_RL32(buf);
- init_get_bits(&gb, buf + 4, (buf_size - 4) * 8);
+ if (unp_size > (1U<<24)) {
+ av_log(avctx, AV_LOG_ERROR, "packet is too big\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = init_get_bits8(&gb, buf + 4, buf_size - 4)) < 0)
+ return ret;
if(!get_bits1(&gb)){
av_log(avctx, AV_LOG_INFO, "Sound: no data\n");
@@ -637,17 +661,15 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "channels mismatch\n");
return AVERROR(EINVAL);
}
- if (bits && avctx->sample_fmt == AV_SAMPLE_FMT_U8) {
+ if (bits == (avctx->sample_fmt == AV_SAMPLE_FMT_U8)) {
av_log(avctx, AV_LOG_ERROR, "sample format mismatch\n");
return AVERROR(EINVAL);
}
/* get output buffer */
frame->nb_samples = unp_size / (avctx->channels * (bits + 1));
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t *)frame->data[0];
samples8 = frame->data[0];
@@ -687,16 +709,26 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
for(i = 0; i <= stereo; i++)
*samples++ = pred[i];
for(; i < unp_size / 2; i++) {
+ if(get_bits_left(&gb)<0)
+ return AVERROR_INVALIDDATA;
if(i & stereo) {
if(vlc[2].table)
res = get_vlc2(&gb, vlc[2].table, SMKTREE_BITS, 3);
else
res = 0;
+ if (res < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
+ return AVERROR_INVALIDDATA;
+ }
val = h[2].values[res];
if(vlc[3].table)
res = get_vlc2(&gb, vlc[3].table, SMKTREE_BITS, 3);
else
res = 0;
+ if (res < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
+ return AVERROR_INVALIDDATA;
+ }
val |= h[3].values[res] << 8;
pred[1] += sign_extend(val, 16);
*samples++ = pred[1];
@@ -705,11 +737,19 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
else
res = 0;
+ if (res < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
+ return AVERROR_INVALIDDATA;
+ }
val = h[0].values[res];
if(vlc[1].table)
res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
else
res = 0;
+ if (res < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
+ return AVERROR_INVALIDDATA;
+ }
val |= h[1].values[res] << 8;
pred[0] += sign_extend(val, 16);
*samples++ = pred[0];
@@ -721,11 +761,17 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
for(i = 0; i <= stereo; i++)
*samples8++ = pred[i];
for(; i < unp_size; i++) {
+ if(get_bits_left(&gb)<0)
+ return AVERROR_INVALIDDATA;
if(i & stereo){
if(vlc[1].table)
res = get_vlc2(&gb, vlc[1].table, SMKTREE_BITS, 3);
else
res = 0;
+ if (res < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
+ return AVERROR_INVALIDDATA;
+ }
pred[1] += sign_extend(h[1].values[res], 8);
*samples8++ = pred[1];
} else {
@@ -733,6 +779,10 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
res = get_vlc2(&gb, vlc[0].table, SMKTREE_BITS, 3);
else
res = 0;
+ if (res < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid vlc\n");
+ return AVERROR_INVALIDDATA;
+ }
pred[0] += sign_extend(h[0].values[res], 8);
*samples8++ = pred[0];
}
diff --git a/libavcodec/smc.c b/libavcodec/smc.c
index c6541da843..131300a595 100644
--- a/libavcodec/smc.c
+++ b/libavcodec/smc.c
@@ -1,21 +1,21 @@
/*
* Quicktime Graphics (SMC) Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -84,7 +84,7 @@ static void smc_decode_stream(SmcContext *s)
int stride = s->frame->linesize[0];
int i;
int chunk_size;
- int buf_size = (int) (s->gb.buffer_end - s->gb.buffer_start);
+ int buf_size = bytestream2_size(&s->gb);
unsigned char opcode;
int n_blocks;
unsigned int color_flags;
@@ -436,10 +436,8 @@ static int smc_decode_frame(AVCodecContext *avctx,
bytestream2_init(&s->gb, buf, buf_size);
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
if (pal) {
s->frame->palette_has_changed = 1;
diff --git a/libavcodec/smvjpegdec.c b/libavcodec/smvjpegdec.c
new file mode 100644
index 0000000000..45faff29fc
--- /dev/null
+++ b/libavcodec/smvjpegdec.c
@@ -0,0 +1,218 @@
+/*
+ * SMV JPEG decoder
+ * Copyright (c) 2013 Ash Hughes
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * SMV JPEG decoder.
+ */
+
+// #define DEBUG
+#include "avcodec.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "mjpegdec.h"
+#include "internal.h"
+
+typedef struct SMVJpegDecodeContext {
+ MJpegDecodeContext jpg;
+ AVFrame *picture[2]; /* pictures array */
+ AVCodecContext* avctx;
+ int frames_per_jpeg;
+ int mjpeg_data_size;
+} SMVJpegDecodeContext;
+
+static inline void smv_img_pnt_plane(uint8_t **dst, uint8_t *src,
+ int src_linesize, int height, int nlines)
+{
+ if (!dst || !src)
+ return;
+ src += (nlines) * src_linesize * height;
+ *dst = src;
+}
+
+static inline void smv_img_pnt(uint8_t *dst_data[4], uint8_t *src_data[4],
+ const int src_linesizes[4],
+ enum AVPixelFormat pix_fmt, int width, int height,
+ int nlines)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ int i, planes_nb = 0;
+
+ if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
+ return;
+
+ for (i = 0; i < desc->nb_components; i++)
+ planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1);
+
+ for (i = 0; i < planes_nb; i++) {
+ int h = height;
+ if (i == 1 || i == 2) {
+ h = FF_CEIL_RSHIFT(height, desc->log2_chroma_h);
+ }
+ smv_img_pnt_plane(&dst_data[i], src_data[i],
+ src_linesizes[i], h, nlines);
+ }
+ if (desc->flags & AV_PIX_FMT_FLAG_PAL ||
+ desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)
+ dst_data[1] = src_data[1];
+}
+
+static av_cold int smvjpeg_decode_end(AVCodecContext *avctx)
+{
+ SMVJpegDecodeContext *s = avctx->priv_data;
+ MJpegDecodeContext *jpg = &s->jpg;
+ int ret;
+
+ jpg->picture_ptr = NULL;
+ av_frame_free(&s->picture[0]);
+ av_frame_free(&s->picture[1]);
+ ret = avcodec_close(s->avctx);
+ av_freep(&s->avctx);
+ return ret;
+}
+
+static av_cold int smvjpeg_decode_init(AVCodecContext *avctx)
+{
+ SMVJpegDecodeContext *s = avctx->priv_data;
+ AVCodec *codec;
+ AVDictionary *thread_opt = NULL;
+ int ret = 0, r;
+
+ s->frames_per_jpeg = 0;
+
+ s->picture[0] = av_frame_alloc();
+ if (!s->picture[0])
+ return AVERROR(ENOMEM);
+
+ s->picture[1] = av_frame_alloc();
+ if (!s->picture[1]) {
+ av_frame_free(&s->picture[0]);
+ return AVERROR(ENOMEM);
+ }
+
+ s->jpg.picture_ptr = s->picture[0];
+
+ if (avctx->extradata_size >= 4)
+ s->frames_per_jpeg = AV_RL32(avctx->extradata);
+
+ if (s->frames_per_jpeg <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of frames per jpeg.\n");
+ ret = AVERROR_INVALIDDATA;
+ }
+
+ codec = avcodec_find_decoder(AV_CODEC_ID_MJPEG);
+ if (!codec) {
+ av_log(avctx, AV_LOG_ERROR, "MJPEG codec not found\n");
+ smvjpeg_decode_end(avctx);
+ return AVERROR_DECODER_NOT_FOUND;
+ }
+
+ s->avctx = avcodec_alloc_context3(codec);
+
+ av_dict_set(&thread_opt, "threads", "1", 0);
+ s->avctx->refcounted_frames = 1;
+ s->avctx->flags = avctx->flags;
+ s->avctx->idct_algo = avctx->idct_algo;
+ if ((r = ff_codec_open2_recursive(s->avctx, codec, &thread_opt)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "MJPEG codec failed to open\n");
+ ret = r;
+ }
+ av_dict_free(&thread_opt);
+
+ if (ret < 0)
+ smvjpeg_decode_end(avctx);
+ return ret;
+}
+
+static int smvjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
+ AVPacket *avpkt)
+{
+ const AVPixFmtDescriptor *desc;
+ SMVJpegDecodeContext *s = avctx->priv_data;
+ AVFrame* mjpeg_data = s->picture[0];
+ int i, cur_frame = 0, ret = 0;
+
+ cur_frame = avpkt->pts % s->frames_per_jpeg;
+
+ /* Are we at the start of a block? */
+ if (!cur_frame) {
+ av_frame_unref(mjpeg_data);
+ ret = avcodec_decode_video2(s->avctx, mjpeg_data, &s->mjpeg_data_size, avpkt);
+ if (ret < 0) {
+ s->mjpeg_data_size = 0;
+ return ret;
+ }
+ } else if (!s->mjpeg_data_size)
+ return AVERROR(EINVAL);
+
+ desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
+ if (desc && mjpeg_data->height % (s->frames_per_jpeg << desc->log2_chroma_h)) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid height\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /*use the last lot... */
+ *data_size = s->mjpeg_data_size;
+
+ avctx->pix_fmt = s->avctx->pix_fmt;
+
+ /* We shouldn't get here if frames_per_jpeg <= 0 because this was rejected
+ in init */
+ ret = ff_set_dimensions(avctx, mjpeg_data->width, mjpeg_data->height / s->frames_per_jpeg);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to set dimensions\n");
+ return ret;
+ }
+
+ if (*data_size) {
+ s->picture[1]->extended_data = NULL;
+ s->picture[1]->width = avctx->width;
+ s->picture[1]->height = avctx->height;
+ s->picture[1]->format = avctx->pix_fmt;
+ /* ff_init_buffer_info(avctx, &s->picture[1]); */
+ smv_img_pnt(s->picture[1]->data, mjpeg_data->data, mjpeg_data->linesize,
+ avctx->pix_fmt, avctx->width, avctx->height, cur_frame);
+ for (i = 0; i < AV_NUM_DATA_POINTERS; i++)
+ s->picture[1]->linesize[i] = mjpeg_data->linesize[i];
+
+ ret = av_frame_ref(data, s->picture[1]);
+ }
+
+ return ret;
+}
+
+static const AVClass smvjpegdec_class = {
+ .class_name = "SMVJPEG decoder",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_smvjpeg_decoder = {
+ .name = "smvjpeg",
+ .long_name = NULL_IF_CONFIG_SMALL("SMV JPEG"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_SMVJPEG,
+ .priv_data_size = sizeof(SMVJpegDecodeContext),
+ .init = smvjpeg_decode_init,
+ .close = smvjpeg_decode_end,
+ .decode = smvjpeg_decode_frame,
+ .priv_class = &smvjpegdec_class,
+};
diff --git a/libavcodec/snow.c b/libavcodec/snow.c
new file mode 100644
index 0000000000..33a2dbc129
--- /dev/null
+++ b/libavcodec/snow.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intmath.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "me_cmp.h"
+#include "snow_dwt.h"
+#include "internal.h"
+#include "snow.h"
+#include "snowdata.h"
+
+#include "rangecoder.h"
+#include "mathops.h"
+#include "h263.h"
+
+
+void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
+ int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+ int y, x;
+ IDWTELEM * dst;
+ for(y=0; y<b_h; y++){
+ //FIXME ugly misuse of obmc_stride
+ const uint8_t *obmc1= obmc + y*obmc_stride;
+ const uint8_t *obmc2= obmc1+ (obmc_stride>>1);
+ const uint8_t *obmc3= obmc1+ obmc_stride*(obmc_stride>>1);
+ const uint8_t *obmc4= obmc3+ (obmc_stride>>1);
+ dst = slice_buffer_get_line(sb, src_y + y);
+ for(x=0; x<b_w; x++){
+ int v= obmc1[x] * block[3][x + y*src_stride]
+ +obmc2[x] * block[2][x + y*src_stride]
+ +obmc3[x] * block[1][x + y*src_stride]
+ +obmc4[x] * block[0][x + y*src_stride];
+
+ v <<= 8 - LOG2_OBMC_MAX;
+ if(FRAC_BITS != 8){
+ v >>= 8 - FRAC_BITS;
+ }
+ if(add){
+ v += dst[x + src_x];
+ v = (v + (1<<(FRAC_BITS-1))) >> FRAC_BITS;
+ if(v&(~255)) v= ~(v>>31);
+ dst8[x + y*src_stride] = v;
+ }else{
+ dst[x + src_x] -= v;
+ }
+ }
+ }
+}
+
+int ff_snow_get_buffer(SnowContext *s, AVFrame *frame)
+{
+ int ret, i;
+ int edges_needed = av_codec_is_encoder(s->avctx->codec);
+
+ frame->width = s->avctx->width ;
+ frame->height = s->avctx->height;
+ if (edges_needed) {
+ frame->width += 2 * EDGE_WIDTH;
+ frame->height += 2 * EDGE_WIDTH;
+ }
+ if ((ret = ff_get_buffer(s->avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+ if (edges_needed) {
+ for (i = 0; frame->data[i]; i++) {
+ int offset = (EDGE_WIDTH >> (i ? s->chroma_v_shift : 0)) *
+ frame->linesize[i] +
+ (EDGE_WIDTH >> (i ? s->chroma_h_shift : 0));
+ frame->data[i] += offset;
+ }
+ frame->width = s->avctx->width;
+ frame->height = s->avctx->height;
+ }
+
+ return 0;
+}
+
+void ff_snow_reset_contexts(SnowContext *s){ //FIXME better initial contexts
+ int plane_index, level, orientation;
+
+ for(plane_index=0; plane_index<3; plane_index++){
+ for(level=0; level<MAX_DECOMPOSITIONS; level++){
+ for(orientation=level ? 1:0; orientation<4; orientation++){
+ memset(s->plane[plane_index].band[level][orientation].state, MID_STATE, sizeof(s->plane[plane_index].band[level][orientation].state));
+ }
+ }
+ }
+ memset(s->header_state, MID_STATE, sizeof(s->header_state));
+ memset(s->block_state, MID_STATE, sizeof(s->block_state));
+}
+
+int ff_snow_alloc_blocks(SnowContext *s){
+ int w= FF_CEIL_RSHIFT(s->avctx->width, LOG2_MB_SIZE);
+ int h= FF_CEIL_RSHIFT(s->avctx->height, LOG2_MB_SIZE);
+
+ s->b_width = w;
+ s->b_height= h;
+
+ av_free(s->block);
+ s->block= av_mallocz_array(w * h, sizeof(BlockNode) << (s->block_max_depth*2));
+ if (!s->block)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static av_cold void init_qexp(void){
+ int i;
+ double v=128;
+
+ for(i=0; i<QROOT; i++){
+ ff_qexp[i]= lrintf(v);
+ v *= pow(2, 1.0 / QROOT);
+ }
+}
+static void mc_block(Plane *p, uint8_t *dst, const uint8_t *src, int stride, int b_w, int b_h, int dx, int dy){
+ static const uint8_t weight[64]={
+ 8,7,6,5,4,3,2,1,
+ 7,7,0,0,0,0,0,1,
+ 6,0,6,0,0,0,2,0,
+ 5,0,0,5,0,3,0,0,
+ 4,0,0,0,4,0,0,0,
+ 3,0,0,5,0,3,0,0,
+ 2,0,6,0,0,0,2,0,
+ 1,7,0,0,0,0,0,1,
+ };
+
+ static const uint8_t brane[256]={
+ 0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x11,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+ 0x04,0x05,0xcc,0xcc,0xcc,0xcc,0xcc,0x41,0x15,0x16,0xcc,0xcc,0xcc,0xcc,0xcc,0x52,
+ 0x04,0xcc,0x05,0xcc,0xcc,0xcc,0x41,0xcc,0x15,0xcc,0x16,0xcc,0xcc,0xcc,0x52,0xcc,
+ 0x04,0xcc,0xcc,0x05,0xcc,0x41,0xcc,0xcc,0x15,0xcc,0xcc,0x16,0xcc,0x52,0xcc,0xcc,
+ 0x04,0xcc,0xcc,0xcc,0x41,0xcc,0xcc,0xcc,0x15,0xcc,0xcc,0xcc,0x16,0xcc,0xcc,0xcc,
+ 0x04,0xcc,0xcc,0x41,0xcc,0x05,0xcc,0xcc,0x15,0xcc,0xcc,0x52,0xcc,0x16,0xcc,0xcc,
+ 0x04,0xcc,0x41,0xcc,0xcc,0xcc,0x05,0xcc,0x15,0xcc,0x52,0xcc,0xcc,0xcc,0x16,0xcc,
+ 0x04,0x41,0xcc,0xcc,0xcc,0xcc,0xcc,0x05,0x15,0x52,0xcc,0xcc,0xcc,0xcc,0xcc,0x16,
+ 0x44,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x55,0x56,0x56,0x56,0x56,0x56,0x56,0x56,
+ 0x48,0x49,0xcc,0xcc,0xcc,0xcc,0xcc,0x85,0x59,0x5A,0xcc,0xcc,0xcc,0xcc,0xcc,0x96,
+ 0x48,0xcc,0x49,0xcc,0xcc,0xcc,0x85,0xcc,0x59,0xcc,0x5A,0xcc,0xcc,0xcc,0x96,0xcc,
+ 0x48,0xcc,0xcc,0x49,0xcc,0x85,0xcc,0xcc,0x59,0xcc,0xcc,0x5A,0xcc,0x96,0xcc,0xcc,
+ 0x48,0xcc,0xcc,0xcc,0x49,0xcc,0xcc,0xcc,0x59,0xcc,0xcc,0xcc,0x96,0xcc,0xcc,0xcc,
+ 0x48,0xcc,0xcc,0x85,0xcc,0x49,0xcc,0xcc,0x59,0xcc,0xcc,0x96,0xcc,0x5A,0xcc,0xcc,
+ 0x48,0xcc,0x85,0xcc,0xcc,0xcc,0x49,0xcc,0x59,0xcc,0x96,0xcc,0xcc,0xcc,0x5A,0xcc,
+ 0x48,0x85,0xcc,0xcc,0xcc,0xcc,0xcc,0x49,0x59,0x96,0xcc,0xcc,0xcc,0xcc,0xcc,0x5A,
+ };
+
+ static const uint8_t needs[16]={
+ 0,1,0,0,
+ 2,4,2,0,
+ 0,1,0,0,
+ 15
+ };
+
+ int x, y, b, r, l;
+ int16_t tmpIt [64*(32+HTAPS_MAX)];
+ uint8_t tmp2t[3][64*(32+HTAPS_MAX)];
+ int16_t *tmpI= tmpIt;
+ uint8_t *tmp2= tmp2t[0];
+ const uint8_t *hpel[11];
+ av_assert2(dx<16 && dy<16);
+ r= brane[dx + 16*dy]&15;
+ l= brane[dx + 16*dy]>>4;
+
+ b= needs[l] | needs[r];
+ if(p && !p->diag_mc)
+ b= 15;
+
+ if(b&5){
+ for(y=0; y < b_h+HTAPS_MAX-1; y++){
+ for(x=0; x < b_w; x++){
+ int a_1=src[x + HTAPS_MAX/2-4];
+ int a0= src[x + HTAPS_MAX/2-3];
+ int a1= src[x + HTAPS_MAX/2-2];
+ int a2= src[x + HTAPS_MAX/2-1];
+ int a3= src[x + HTAPS_MAX/2+0];
+ int a4= src[x + HTAPS_MAX/2+1];
+ int a5= src[x + HTAPS_MAX/2+2];
+ int a6= src[x + HTAPS_MAX/2+3];
+ int am=0;
+ if(!p || p->fast_mc){
+ am= 20*(a2+a3) - 5*(a1+a4) + (a0+a5);
+ tmpI[x]= am;
+ am= (am+16)>>5;
+ }else{
+ am= p->hcoeff[0]*(a2+a3) + p->hcoeff[1]*(a1+a4) + p->hcoeff[2]*(a0+a5) + p->hcoeff[3]*(a_1+a6);
+ tmpI[x]= am;
+ am= (am+32)>>6;
+ }
+
+ if(am&(~255)) am= ~(am>>31);
+ tmp2[x]= am;
+ }
+ tmpI+= 64;
+ tmp2+= 64;
+ src += stride;
+ }
+ src -= stride*y;
+ }
+ src += HTAPS_MAX/2 - 1;
+ tmp2= tmp2t[1];
+
+ if(b&2){
+ for(y=0; y < b_h; y++){
+ for(x=0; x < b_w+1; x++){
+ int a_1=src[x + (HTAPS_MAX/2-4)*stride];
+ int a0= src[x + (HTAPS_MAX/2-3)*stride];
+ int a1= src[x + (HTAPS_MAX/2-2)*stride];
+ int a2= src[x + (HTAPS_MAX/2-1)*stride];
+ int a3= src[x + (HTAPS_MAX/2+0)*stride];
+ int a4= src[x + (HTAPS_MAX/2+1)*stride];
+ int a5= src[x + (HTAPS_MAX/2+2)*stride];
+ int a6= src[x + (HTAPS_MAX/2+3)*stride];
+ int am=0;
+ if(!p || p->fast_mc)
+ am= (20*(a2+a3) - 5*(a1+a4) + (a0+a5) + 16)>>5;
+ else
+ am= (p->hcoeff[0]*(a2+a3) + p->hcoeff[1]*(a1+a4) + p->hcoeff[2]*(a0+a5) + p->hcoeff[3]*(a_1+a6) + 32)>>6;
+
+ if(am&(~255)) am= ~(am>>31);
+ tmp2[x]= am;
+ }
+ src += stride;
+ tmp2+= 64;
+ }
+ src -= stride*y;
+ }
+ src += stride*(HTAPS_MAX/2 - 1);
+ tmp2= tmp2t[2];
+ tmpI= tmpIt;
+ if(b&4){
+ for(y=0; y < b_h; y++){
+ for(x=0; x < b_w; x++){
+ int a_1=tmpI[x + (HTAPS_MAX/2-4)*64];
+ int a0= tmpI[x + (HTAPS_MAX/2-3)*64];
+ int a1= tmpI[x + (HTAPS_MAX/2-2)*64];
+ int a2= tmpI[x + (HTAPS_MAX/2-1)*64];
+ int a3= tmpI[x + (HTAPS_MAX/2+0)*64];
+ int a4= tmpI[x + (HTAPS_MAX/2+1)*64];
+ int a5= tmpI[x + (HTAPS_MAX/2+2)*64];
+ int a6= tmpI[x + (HTAPS_MAX/2+3)*64];
+ int am=0;
+ if(!p || p->fast_mc)
+ am= (20*(a2+a3) - 5*(a1+a4) + (a0+a5) + 512)>>10;
+ else
+ am= (p->hcoeff[0]*(a2+a3) + p->hcoeff[1]*(a1+a4) + p->hcoeff[2]*(a0+a5) + p->hcoeff[3]*(a_1+a6) + 2048)>>12;
+ if(am&(~255)) am= ~(am>>31);
+ tmp2[x]= am;
+ }
+ tmpI+= 64;
+ tmp2+= 64;
+ }
+ }
+
+ hpel[ 0]= src;
+ hpel[ 1]= tmp2t[0] + 64*(HTAPS_MAX/2-1);
+ hpel[ 2]= src + 1;
+
+ hpel[ 4]= tmp2t[1];
+ hpel[ 5]= tmp2t[2];
+ hpel[ 6]= tmp2t[1] + 1;
+
+ hpel[ 8]= src + stride;
+ hpel[ 9]= hpel[1] + 64;
+ hpel[10]= hpel[8] + 1;
+
+#define MC_STRIDE(x) (needs[x] ? 64 : stride)
+
+ if(b==15){
+ int dxy = dx / 8 + dy / 8 * 4;
+ const uint8_t *src1 = hpel[dxy ];
+ const uint8_t *src2 = hpel[dxy + 1];
+ const uint8_t *src3 = hpel[dxy + 4];
+ const uint8_t *src4 = hpel[dxy + 5];
+ int stride1 = MC_STRIDE(dxy);
+ int stride2 = MC_STRIDE(dxy + 1);
+ int stride3 = MC_STRIDE(dxy + 4);
+ int stride4 = MC_STRIDE(dxy + 5);
+ dx&=7;
+ dy&=7;
+ for(y=0; y < b_h; y++){
+ for(x=0; x < b_w; x++){
+ dst[x]= ((8-dx)*(8-dy)*src1[x] + dx*(8-dy)*src2[x]+
+ (8-dx)* dy *src3[x] + dx* dy *src4[x]+32)>>6;
+ }
+ src1+=stride1;
+ src2+=stride2;
+ src3+=stride3;
+ src4+=stride4;
+ dst +=stride;
+ }
+ }else{
+ const uint8_t *src1= hpel[l];
+ const uint8_t *src2= hpel[r];
+ int stride1 = MC_STRIDE(l);
+ int stride2 = MC_STRIDE(r);
+ int a= weight[((dx&7) + (8*(dy&7)))];
+ int b= 8-a;
+ for(y=0; y < b_h; y++){
+ for(x=0; x < b_w; x++){
+ dst[x]= (a*src1[x] + b*src2[x] + 4)>>3;
+ }
+ src1+=stride1;
+ src2+=stride2;
+ dst +=stride;
+ }
+ }
+}
+
+void ff_snow_pred_block(SnowContext *s, uint8_t *dst, uint8_t *tmp, ptrdiff_t stride, int sx, int sy, int b_w, int b_h, const BlockNode *block, int plane_index, int w, int h){
+ if(block->type & BLOCK_INTRA){
+ int x, y;
+ const unsigned color = block->color[plane_index];
+ const unsigned color4 = color*0x01010101;
+ if(b_w==32){
+ for(y=0; y < b_h; y++){
+ *(uint32_t*)&dst[0 + y*stride]= color4;
+ *(uint32_t*)&dst[4 + y*stride]= color4;
+ *(uint32_t*)&dst[8 + y*stride]= color4;
+ *(uint32_t*)&dst[12+ y*stride]= color4;
+ *(uint32_t*)&dst[16+ y*stride]= color4;
+ *(uint32_t*)&dst[20+ y*stride]= color4;
+ *(uint32_t*)&dst[24+ y*stride]= color4;
+ *(uint32_t*)&dst[28+ y*stride]= color4;
+ }
+ }else if(b_w==16){
+ for(y=0; y < b_h; y++){
+ *(uint32_t*)&dst[0 + y*stride]= color4;
+ *(uint32_t*)&dst[4 + y*stride]= color4;
+ *(uint32_t*)&dst[8 + y*stride]= color4;
+ *(uint32_t*)&dst[12+ y*stride]= color4;
+ }
+ }else if(b_w==8){
+ for(y=0; y < b_h; y++){
+ *(uint32_t*)&dst[0 + y*stride]= color4;
+ *(uint32_t*)&dst[4 + y*stride]= color4;
+ }
+ }else if(b_w==4){
+ for(y=0; y < b_h; y++){
+ *(uint32_t*)&dst[0 + y*stride]= color4;
+ }
+ }else{
+ for(y=0; y < b_h; y++){
+ for(x=0; x < b_w; x++){
+ dst[x + y*stride]= color;
+ }
+ }
+ }
+ }else{
+ uint8_t *src= s->last_picture[block->ref]->data[plane_index];
+ const int scale= plane_index ? (2*s->mv_scale)>>s->chroma_h_shift : 2*s->mv_scale;
+ int mx= block->mx*scale;
+ int my= block->my*scale;
+ const int dx= mx&15;
+ const int dy= my&15;
+ const int tab_index= 3 - (b_w>>2) + (b_w>>4);
+ sx += (mx>>4) - (HTAPS_MAX/2-1);
+ sy += (my>>4) - (HTAPS_MAX/2-1);
+ src += sx + sy*stride;
+ if( (unsigned)sx >= FFMAX(w - b_w - (HTAPS_MAX-2), 0)
+ || (unsigned)sy >= FFMAX(h - b_h - (HTAPS_MAX-2), 0)){
+ s->vdsp.emulated_edge_mc(tmp + MB_SIZE, src,
+ stride, stride,
+ b_w+HTAPS_MAX-1, b_h+HTAPS_MAX-1,
+ sx, sy, w, h);
+ src= tmp + MB_SIZE;
+ }
+
+ av_assert2(s->chroma_h_shift == s->chroma_v_shift); // only one mv_scale
+
+ av_assert2((tab_index>=0 && tab_index<4) || b_w==32);
+ if( (dx&3) || (dy&3)
+ || !(b_w == b_h || 2*b_w == b_h || b_w == 2*b_h)
+ || (b_w&(b_w-1))
+ || b_w == 1
+ || b_h == 1
+ || !s->plane[plane_index].fast_mc )
+ mc_block(&s->plane[plane_index], dst, src, stride, b_w, b_h, dx, dy);
+ else if(b_w==32){
+ int y;
+ for(y=0; y<b_h; y+=16){
+ s->h264qpel.put_h264_qpel_pixels_tab[0][dy+(dx>>2)](dst + y*stride, src + 3 + (y+3)*stride,stride);
+ s->h264qpel.put_h264_qpel_pixels_tab[0][dy+(dx>>2)](dst + 16 + y*stride, src + 19 + (y+3)*stride,stride);
+ }
+ }else if(b_w==b_h)
+ s->h264qpel.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst,src + 3 + 3*stride,stride);
+ else if(b_w==2*b_h){
+ s->h264qpel.put_h264_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst ,src + 3 + 3*stride,stride);
+ s->h264qpel.put_h264_qpel_pixels_tab[tab_index+1][dy+(dx>>2)](dst+b_h,src + 3 + b_h + 3*stride,stride);
+ }else{
+ av_assert2(2*b_w==b_h);
+ s->h264qpel.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst ,src + 3 + 3*stride ,stride);
+ s->h264qpel.put_h264_qpel_pixels_tab[tab_index ][dy+(dx>>2)](dst+b_w*stride,src + 3 + 3*stride+b_w*stride,stride);
+ }
+ }
+}
+
+#define mca(dx,dy,b_w)\
+static void mc_block_hpel ## dx ## dy ## b_w(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h){\
+ av_assert2(h==b_w);\
+ mc_block(NULL, dst, src-(HTAPS_MAX/2-1)-(HTAPS_MAX/2-1)*stride, stride, b_w, b_w, dx, dy);\
+}
+
+mca( 0, 0,16)
+mca( 8, 0,16)
+mca( 0, 8,16)
+mca( 8, 8,16)
+mca( 0, 0,8)
+mca( 8, 0,8)
+mca( 0, 8,8)
+mca( 8, 8,8)
+
+av_cold int ff_snow_common_init(AVCodecContext *avctx){
+ SnowContext *s = avctx->priv_data;
+ int width, height;
+ int i, j;
+
+ s->avctx= avctx;
+ s->max_ref_frames=1; //just make sure it's not an invalid value in case of no initial keyframe
+ s->spatial_decomposition_count = 1;
+
+ ff_me_cmp_init(&s->mecc, avctx);
+ ff_hpeldsp_init(&s->hdsp, avctx->flags);
+ ff_videodsp_init(&s->vdsp, 8);
+ ff_dwt_init(&s->dwt);
+ ff_h264qpel_init(&s->h264qpel, 8);
+
+#define mcf(dx,dy)\
+ s->qdsp.put_qpel_pixels_tab [0][dy+dx/4]=\
+ s->qdsp.put_no_rnd_qpel_pixels_tab[0][dy+dx/4]=\
+ s->h264qpel.put_h264_qpel_pixels_tab[0][dy+dx/4];\
+ s->qdsp.put_qpel_pixels_tab [1][dy+dx/4]=\
+ s->qdsp.put_no_rnd_qpel_pixels_tab[1][dy+dx/4]=\
+ s->h264qpel.put_h264_qpel_pixels_tab[1][dy+dx/4];
+
+ mcf( 0, 0)
+ mcf( 4, 0)
+ mcf( 8, 0)
+ mcf(12, 0)
+ mcf( 0, 4)
+ mcf( 4, 4)
+ mcf( 8, 4)
+ mcf(12, 4)
+ mcf( 0, 8)
+ mcf( 4, 8)
+ mcf( 8, 8)
+ mcf(12, 8)
+ mcf( 0,12)
+ mcf( 4,12)
+ mcf( 8,12)
+ mcf(12,12)
+
+#define mcfh(dx,dy)\
+ s->hdsp.put_pixels_tab [0][dy/4+dx/8]=\
+ s->hdsp.put_no_rnd_pixels_tab[0][dy/4+dx/8]=\
+ mc_block_hpel ## dx ## dy ## 16;\
+ s->hdsp.put_pixels_tab [1][dy/4+dx/8]=\
+ s->hdsp.put_no_rnd_pixels_tab[1][dy/4+dx/8]=\
+ mc_block_hpel ## dx ## dy ## 8;
+
+ mcfh(0, 0)
+ mcfh(8, 0)
+ mcfh(0, 8)
+ mcfh(8, 8)
+
+ init_qexp();
+
+// dec += FFMAX(s->chroma_h_shift, s->chroma_v_shift);
+
+ width= s->avctx->width;
+ height= s->avctx->height;
+
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->spatial_idwt_buffer, width, height * sizeof(IDWTELEM), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->spatial_dwt_buffer, width, height * sizeof(DWTELEM), fail); //FIXME this does not belong here
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->temp_dwt_buffer, width, sizeof(DWTELEM), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->temp_idwt_buffer, width, sizeof(IDWTELEM), fail);
+ FF_ALLOC_ARRAY_OR_GOTO(avctx, s->run_buffer, ((width + 1) >> 1), ((height + 1) >> 1) * sizeof(*s->run_buffer), fail);
+
+ for(i=0; i<MAX_REF_FRAMES; i++) {
+ for(j=0; j<MAX_REF_FRAMES; j++)
+ ff_scale_mv_ref[i][j] = 256*(i+1)/(j+1);
+ s->last_picture[i] = av_frame_alloc();
+ if (!s->last_picture[i])
+ goto fail;
+ }
+
+ s->mconly_picture = av_frame_alloc();
+ s->current_picture = av_frame_alloc();
+ if (!s->mconly_picture || !s->current_picture)
+ goto fail;
+
+ return 0;
+fail:
+ return AVERROR(ENOMEM);
+}
+
+int ff_snow_common_init_after_header(AVCodecContext *avctx) {
+ SnowContext *s = avctx->priv_data;
+ int plane_index, level, orientation;
+ int ret, emu_buf_size;
+
+ if(!s->scratchbuf) {
+ if ((ret = ff_get_buffer(s->avctx, s->mconly_picture,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+ FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->scratchbuf, FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256), 7*MB_SIZE, fail);
+ emu_buf_size = FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256) * (2 * MB_SIZE + HTAPS_MAX - 1);
+ FF_ALLOC_OR_GOTO(avctx, s->emu_edge_buffer, emu_buf_size, fail);
+ }
+
+ if(s->mconly_picture->format != avctx->pix_fmt) {
+ av_log(avctx, AV_LOG_ERROR, "pixel format changed\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for(plane_index=0; plane_index < s->nb_planes; plane_index++){
+ int w= s->avctx->width;
+ int h= s->avctx->height;
+
+ if(plane_index){
+ w = FF_CEIL_RSHIFT(w, s->chroma_h_shift);
+ h = FF_CEIL_RSHIFT(h, s->chroma_v_shift);
+ }
+ s->plane[plane_index].width = w;
+ s->plane[plane_index].height= h;
+
+ for(level=s->spatial_decomposition_count-1; level>=0; level--){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &s->plane[plane_index].band[level][orientation];
+
+ b->buf= s->spatial_dwt_buffer;
+ b->level= level;
+ b->stride= s->plane[plane_index].width << (s->spatial_decomposition_count - level);
+ b->width = (w + !(orientation&1))>>1;
+ b->height= (h + !(orientation>1))>>1;
+
+ b->stride_line = 1 << (s->spatial_decomposition_count - level);
+ b->buf_x_offset = 0;
+ b->buf_y_offset = 0;
+
+ if(orientation&1){
+ b->buf += (w+1)>>1;
+ b->buf_x_offset = (w+1)>>1;
+ }
+ if(orientation>1){
+ b->buf += b->stride>>1;
+ b->buf_y_offset = b->stride_line >> 1;
+ }
+ b->ibuf= s->spatial_idwt_buffer + (b->buf - s->spatial_dwt_buffer);
+
+ if(level)
+ b->parent= &s->plane[plane_index].band[level-1][orientation];
+ //FIXME avoid this realloc
+ av_freep(&b->x_coeff);
+ b->x_coeff=av_mallocz_array(((b->width+1) * b->height+1), sizeof(x_and_coeff));
+ if (!b->x_coeff)
+ goto fail;
+ }
+ w= (w+1)>>1;
+ h= (h+1)>>1;
+ }
+ }
+
+ return 0;
+fail:
+ return AVERROR(ENOMEM);
+}
+
+#define USE_HALFPEL_PLANE 0
+
+static int halfpel_interpol(SnowContext *s, uint8_t *halfpel[4][4], AVFrame *frame){
+ int p,x,y;
+
+ for(p=0; p < s->nb_planes; p++){
+ int is_chroma= !!p;
+ int w= is_chroma ? FF_CEIL_RSHIFT(s->avctx->width, s->chroma_h_shift) : s->avctx->width;
+ int h= is_chroma ? FF_CEIL_RSHIFT(s->avctx->height, s->chroma_v_shift) : s->avctx->height;
+ int ls= frame->linesize[p];
+ uint8_t *src= frame->data[p];
+
+ halfpel[1][p] = av_malloc_array(ls, (h + 2 * EDGE_WIDTH));
+ halfpel[2][p] = av_malloc_array(ls, (h + 2 * EDGE_WIDTH));
+ halfpel[3][p] = av_malloc_array(ls, (h + 2 * EDGE_WIDTH));
+ if (!halfpel[1][p] || !halfpel[2][p] || !halfpel[3][p]) {
+ av_freep(&halfpel[1][p]);
+ av_freep(&halfpel[2][p]);
+ av_freep(&halfpel[3][p]);
+ return AVERROR(ENOMEM);
+ }
+ halfpel[1][p] += EDGE_WIDTH * (1 + ls);
+ halfpel[2][p] += EDGE_WIDTH * (1 + ls);
+ halfpel[3][p] += EDGE_WIDTH * (1 + ls);
+
+ halfpel[0][p]= src;
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= y*ls + x;
+
+ halfpel[1][p][i]= (20*(src[i] + src[i+1]) - 5*(src[i-1] + src[i+2]) + (src[i-2] + src[i+3]) + 16 )>>5;
+ }
+ }
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= y*ls + x;
+
+ halfpel[2][p][i]= (20*(src[i] + src[i+ls]) - 5*(src[i-ls] + src[i+2*ls]) + (src[i-2*ls] + src[i+3*ls]) + 16 )>>5;
+ }
+ }
+ src= halfpel[1][p];
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= y*ls + x;
+
+ halfpel[3][p][i]= (20*(src[i] + src[i+ls]) - 5*(src[i-ls] + src[i+2*ls]) + (src[i-2*ls] + src[i+3*ls]) + 16 )>>5;
+ }
+ }
+
+//FIXME border!
+ }
+ return 0;
+}
+
+void ff_snow_release_buffer(AVCodecContext *avctx)
+{
+ SnowContext *s = avctx->priv_data;
+ int i;
+
+ if(s->last_picture[s->max_ref_frames-1]->data[0]){
+ av_frame_unref(s->last_picture[s->max_ref_frames-1]);
+ for(i=0; i<9; i++)
+ if(s->halfpel_plane[s->max_ref_frames-1][1+i/3][i%3]) {
+ av_free(s->halfpel_plane[s->max_ref_frames-1][1+i/3][i%3] - EDGE_WIDTH*(1+s->current_picture->linesize[i%3]));
+ s->halfpel_plane[s->max_ref_frames-1][1+i/3][i%3] = NULL;
+ }
+ }
+}
+
+int ff_snow_frame_start(SnowContext *s){
+ AVFrame *tmp;
+ int i, ret;
+
+ ff_snow_release_buffer(s->avctx);
+
+ tmp= s->last_picture[s->max_ref_frames-1];
+ for(i=s->max_ref_frames-1; i>0; i--)
+ s->last_picture[i] = s->last_picture[i-1];
+ memmove(s->halfpel_plane+1, s->halfpel_plane, (s->max_ref_frames-1)*sizeof(void*)*4*4);
+ if(USE_HALFPEL_PLANE && s->current_picture->data[0]) {
+ if((ret = halfpel_interpol(s, s->halfpel_plane[0], s->current_picture)) < 0)
+ return ret;
+ }
+ s->last_picture[0] = s->current_picture;
+ s->current_picture = tmp;
+
+ if(s->keyframe){
+ s->ref_frames= 0;
+ }else{
+ int i;
+ for(i=0; i<s->max_ref_frames && s->last_picture[i]->data[0]; i++)
+ if(i && s->last_picture[i-1]->key_frame)
+ break;
+ s->ref_frames= i;
+ if(s->ref_frames==0){
+ av_log(s->avctx,AV_LOG_ERROR, "No reference frames\n");
+ return -1;
+ }
+ }
+ if ((ret = ff_snow_get_buffer(s, s->current_picture)) < 0)
+ return ret;
+
+ s->current_picture->key_frame= s->keyframe;
+
+ return 0;
+}
+
+av_cold void ff_snow_common_end(SnowContext *s)
+{
+ int plane_index, level, orientation, i;
+
+ av_freep(&s->spatial_dwt_buffer);
+ av_freep(&s->temp_dwt_buffer);
+ av_freep(&s->spatial_idwt_buffer);
+ av_freep(&s->temp_idwt_buffer);
+ av_freep(&s->run_buffer);
+
+ s->m.me.temp= NULL;
+ av_freep(&s->m.me.scratchpad);
+ av_freep(&s->m.me.map);
+ av_freep(&s->m.me.score_map);
+ av_freep(&s->m.obmc_scratchpad);
+
+ av_freep(&s->block);
+ av_freep(&s->scratchbuf);
+ av_freep(&s->emu_edge_buffer);
+
+ for(i=0; i<MAX_REF_FRAMES; i++){
+ av_freep(&s->ref_mvs[i]);
+ av_freep(&s->ref_scores[i]);
+ if(s->last_picture[i] && s->last_picture[i]->data[0]) {
+ av_assert0(s->last_picture[i]->data[0] != s->current_picture->data[0]);
+ }
+ av_frame_free(&s->last_picture[i]);
+ }
+
+ for(plane_index=0; plane_index < MAX_PLANES; plane_index++){
+ for(level=MAX_DECOMPOSITIONS-1; level>=0; level--){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &s->plane[plane_index].band[level][orientation];
+
+ av_freep(&b->x_coeff);
+ }
+ }
+ }
+ av_frame_free(&s->mconly_picture);
+ av_frame_free(&s->current_picture);
+}
diff --git a/libavcodec/snow.h b/libavcodec/snow.h
new file mode 100644
index 0000000000..95e07cd0ae
--- /dev/null
+++ b/libavcodec/snow.h
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2006 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_SNOW_H
+#define AVCODEC_SNOW_H
+
+#include "libavutil/motion_vector.h"
+
+#include "hpeldsp.h"
+#include "me_cmp.h"
+#include "qpeldsp.h"
+#include "snow_dwt.h"
+
+#include "rangecoder.h"
+#include "mathops.h"
+
+#define FF_MPV_OFFSET(x) (offsetof(MpegEncContext, x) + offsetof(SnowContext, m))
+#include "mpegvideo.h"
+#include "h264qpel.h"
+
+#define MID_STATE 128
+
+#define MAX_PLANES 4
+#define QSHIFT 5
+#define QROOT (1<<QSHIFT)
+#define LOSSLESS_QLOG -128
+#define FRAC_BITS 4
+#define MAX_REF_FRAMES 8
+
+#define LOG2_OBMC_MAX 8
+#define OBMC_MAX (1<<(LOG2_OBMC_MAX))
+typedef struct BlockNode{
+ int16_t mx;
+ int16_t my;
+ uint8_t ref;
+ uint8_t color[3];
+ uint8_t type;
+//#define TYPE_SPLIT 1
+#define BLOCK_INTRA 1
+#define BLOCK_OPT 2
+//#define TYPE_NOCOLOR 4
+ uint8_t level; //FIXME merge into type?
+}BlockNode;
+
+static const BlockNode null_block= { //FIXME add border maybe
+ .color= {128,128,128},
+ .mx= 0,
+ .my= 0,
+ .ref= 0,
+ .type= 0,
+ .level= 0,
+};
+
+#define LOG2_MB_SIZE 4
+#define MB_SIZE (1<<LOG2_MB_SIZE)
+#define ENCODER_EXTRA_BITS 4
+#define HTAPS_MAX 8
+
+typedef struct x_and_coeff{
+ int16_t x;
+ uint16_t coeff;
+} x_and_coeff;
+
+typedef struct SubBand{
+ int level;
+ int stride;
+ int width;
+ int height;
+ int qlog; ///< log(qscale)/log[2^(1/6)]
+ DWTELEM *buf;
+ IDWTELEM *ibuf;
+ int buf_x_offset;
+ int buf_y_offset;
+ int stride_line; ///< Stride measured in lines, not pixels.
+ x_and_coeff * x_coeff;
+ struct SubBand *parent;
+ uint8_t state[/*7*2*/ 7 + 512][32];
+}SubBand;
+
+typedef struct Plane{
+ int width;
+ int height;
+ SubBand band[MAX_DECOMPOSITIONS][4];
+
+ int htaps;
+ int8_t hcoeff[HTAPS_MAX/2];
+ int diag_mc;
+ int fast_mc;
+
+ int last_htaps;
+ int8_t last_hcoeff[HTAPS_MAX/2];
+ int last_diag_mc;
+}Plane;
+
+typedef struct SnowContext{
+ AVClass *class;
+ AVCodecContext *avctx;
+ RangeCoder c;
+ MECmpContext mecc;
+ HpelDSPContext hdsp;
+ QpelDSPContext qdsp;
+ VideoDSPContext vdsp;
+ H264QpelContext h264qpel;
+ MpegvideoEncDSPContext mpvencdsp;
+ SnowDWTContext dwt;
+ const AVFrame *new_picture;
+ AVFrame *input_picture; ///< new_picture with the internal linesizes
+ AVFrame *current_picture;
+ AVFrame *last_picture[MAX_REF_FRAMES];
+ uint8_t *halfpel_plane[MAX_REF_FRAMES][4][4];
+ AVFrame *mconly_picture;
+// uint8_t q_context[16];
+ uint8_t header_state[32];
+ uint8_t block_state[128 + 32*128];
+ int keyframe;
+ int always_reset;
+ int version;
+ int spatial_decomposition_type;
+ int last_spatial_decomposition_type;
+ int temporal_decomposition_type;
+ int spatial_decomposition_count;
+ int last_spatial_decomposition_count;
+ int temporal_decomposition_count;
+ int max_ref_frames;
+ int ref_frames;
+ int16_t (*ref_mvs[MAX_REF_FRAMES])[2];
+ uint32_t *ref_scores[MAX_REF_FRAMES];
+ DWTELEM *spatial_dwt_buffer;
+ DWTELEM *temp_dwt_buffer;
+ IDWTELEM *spatial_idwt_buffer;
+ IDWTELEM *temp_idwt_buffer;
+ int *run_buffer;
+ int colorspace_type;
+ int chroma_h_shift;
+ int chroma_v_shift;
+ int spatial_scalability;
+ int qlog;
+ int last_qlog;
+ int lambda;
+ int lambda2;
+ int pass1_rc;
+ int mv_scale;
+ int last_mv_scale;
+ int qbias;
+ int last_qbias;
+#define QBIAS_SHIFT 3
+ int b_width;
+ int b_height;
+ int block_max_depth;
+ int last_block_max_depth;
+ int nb_planes;
+ Plane plane[MAX_PLANES];
+ BlockNode *block;
+#define ME_CACHE_SIZE 1024
+ unsigned me_cache[ME_CACHE_SIZE];
+ unsigned me_cache_generation;
+ slice_buffer sb;
+ int memc_only;
+ int no_bitstream;
+ int intra_penalty;
+
+ 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)
+
+ uint8_t *scratchbuf;
+ uint8_t *emu_edge_buffer;
+
+ AVMotionVector *avmv;
+ int avmv_index;
+}SnowContext;
+
+/* Tables */
+extern const uint8_t * const ff_obmc_tab[4];
+extern uint8_t ff_qexp[QROOT];
+extern int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES];
+
+/* C bits used by mmx/sse2/altivec */
+
+static av_always_inline void snow_interleave_line_header(int * i, int width, IDWTELEM * low, IDWTELEM * high){
+ (*i) = (width) - 2;
+
+ if (width & 1){
+ low[(*i)+1] = low[((*i)+1)>>1];
+ (*i)--;
+ }
+}
+
+static av_always_inline void snow_interleave_line_footer(int * i, IDWTELEM * low, IDWTELEM * high){
+ for (; (*i)>=0; (*i)-=2){
+ low[(*i)+1] = high[(*i)>>1];
+ low[*i] = low[(*i)>>1];
+ }
+}
+
+static av_always_inline void snow_horizontal_compose_lift_lead_out(int i, IDWTELEM * dst, IDWTELEM * src, IDWTELEM * ref, int width, int w, int lift_high, int mul, int add, int shift){
+ for(; i<w; i++){
+ dst[i] = src[i] - ((mul * (ref[i] + ref[i + 1]) + add) >> shift);
+ }
+
+ if((width^lift_high)&1){
+ dst[w] = src[w] - ((mul * 2 * ref[w] + add) >> shift);
+ }
+}
+
+static av_always_inline void snow_horizontal_compose_liftS_lead_out(int i, IDWTELEM * dst, IDWTELEM * src, IDWTELEM * ref, int width, int w){
+ for(; i<w; i++){
+ dst[i] = src[i] + ((ref[i] + ref[(i+1)]+W_BO + 4 * src[i]) >> W_BS);
+ }
+
+ if(width&1){
+ dst[w] = src[w] + ((2 * ref[w] + W_BO + 4 * src[w]) >> W_BS);
+ }
+}
+
+/* common code */
+
+int ff_snow_common_init(AVCodecContext *avctx);
+int ff_snow_common_init_after_header(AVCodecContext *avctx);
+void ff_snow_common_end(SnowContext *s);
+void ff_snow_release_buffer(AVCodecContext *avctx);
+void ff_snow_reset_contexts(SnowContext *s);
+int ff_snow_alloc_blocks(SnowContext *s);
+int ff_snow_frame_start(SnowContext *s);
+void ff_snow_pred_block(SnowContext *s, uint8_t *dst, uint8_t *tmp, ptrdiff_t stride,
+ int sx, int sy, int b_w, int b_h, const BlockNode *block,
+ int plane_index, int w, int h);
+int ff_snow_get_buffer(SnowContext *s, AVFrame *frame);
+/* common inline functions */
+//XXX doublecheck all of them should stay inlined
+
+static inline void snow_set_blocks(SnowContext *s, int level, int x, int y, int l, int cb, int cr, int mx, int my, int ref, int type){
+ const int w= s->b_width << s->block_max_depth;
+ const int rem_depth= s->block_max_depth - level;
+ const int index= (x + y*w) << rem_depth;
+ const int block_w= 1<<rem_depth;
+ BlockNode block;
+ int i,j;
+
+ block.color[0]= l;
+ block.color[1]= cb;
+ block.color[2]= cr;
+ block.mx= mx;
+ block.my= my;
+ block.ref= ref;
+ block.type= type;
+ block.level= level;
+
+ for(j=0; j<block_w; j++){
+ for(i=0; i<block_w; i++){
+ s->block[index + i + j*w]= block;
+ }
+ }
+}
+
+static inline void pred_mv(SnowContext *s, int *mx, int *my, int ref,
+ const BlockNode *left, const BlockNode *top, const BlockNode *tr){
+ if(s->ref_frames == 1){
+ *mx = mid_pred(left->mx, top->mx, tr->mx);
+ *my = mid_pred(left->my, top->my, tr->my);
+ }else{
+ const int *scale = ff_scale_mv_ref[ref];
+ *mx = mid_pred((left->mx * scale[left->ref] + 128) >>8,
+ (top ->mx * scale[top ->ref] + 128) >>8,
+ (tr ->mx * scale[tr ->ref] + 128) >>8);
+ *my = mid_pred((left->my * scale[left->ref] + 128) >>8,
+ (top ->my * scale[top ->ref] + 128) >>8,
+ (tr ->my * scale[tr ->ref] + 128) >>8);
+ }
+}
+
+static av_always_inline int same_block(BlockNode *a, BlockNode *b){
+ if((a->type&BLOCK_INTRA) && (b->type&BLOCK_INTRA)){
+ return !((a->color[0] - b->color[0]) | (a->color[1] - b->color[1]) | (a->color[2] - b->color[2]));
+ }else{
+ return !((a->mx - b->mx) | (a->my - b->my) | (a->ref - b->ref) | ((a->type ^ b->type)&BLOCK_INTRA));
+ }
+}
+
+//FIXME name cleanup (b_w, block_w, b_width stuff)
+//XXX should we really inline it?
+static av_always_inline void add_yblock(SnowContext *s, int sliced, slice_buffer *sb, IDWTELEM *dst, uint8_t *dst8, const uint8_t *obmc, int src_x, int src_y, int b_w, int b_h, int w, int h, int dst_stride, int src_stride, int obmc_stride, int b_x, int b_y, int add, int offset_dst, int plane_index){
+ const int b_width = s->b_width << s->block_max_depth;
+ const int b_height= s->b_height << s->block_max_depth;
+ const int b_stride= b_width;
+ BlockNode *lt= &s->block[b_x + b_y*b_stride];
+ BlockNode *rt= lt+1;
+ BlockNode *lb= lt+b_stride;
+ BlockNode *rb= lb+1;
+ uint8_t *block[4];
+ int tmp_step= src_stride >= 7*MB_SIZE ? MB_SIZE : MB_SIZE*src_stride;
+ uint8_t *tmp = s->scratchbuf;
+ uint8_t *ptmp;
+ int x,y;
+
+ if(b_x<0){
+ lt= rt;
+ lb= rb;
+ }else if(b_x + 1 >= b_width){
+ rt= lt;
+ rb= lb;
+ }
+ if(b_y<0){
+ lt= lb;
+ rt= rb;
+ }else if(b_y + 1 >= b_height){
+ lb= lt;
+ rb= rt;
+ }
+
+ if(src_x<0){ //FIXME merge with prev & always round internal width up to *16
+ obmc -= src_x;
+ b_w += src_x;
+ if(!sliced && !offset_dst)
+ dst -= src_x;
+ src_x=0;
+ }
+ if(src_x + b_w > w){
+ b_w = w - src_x;
+ }
+ if(src_y<0){
+ obmc -= src_y*obmc_stride;
+ b_h += src_y;
+ if(!sliced && !offset_dst)
+ dst -= src_y*dst_stride;
+ src_y=0;
+ }
+ if(src_y + b_h> h){
+ b_h = h - src_y;
+ }
+
+ if(b_w<=0 || b_h<=0) return;
+
+ av_assert2(src_stride > 2*MB_SIZE + 5);
+
+ if(!sliced && offset_dst)
+ dst += src_x + src_y*dst_stride;
+ dst8+= src_x + src_y*src_stride;
+// src += src_x + src_y*src_stride;
+
+ ptmp= tmp + 3*tmp_step;
+ block[0]= ptmp;
+ ptmp+=tmp_step;
+ ff_snow_pred_block(s, block[0], tmp, src_stride, src_x, src_y, b_w, b_h, lt, plane_index, w, h);
+
+ if(same_block(lt, rt)){
+ block[1]= block[0];
+ }else{
+ block[1]= ptmp;
+ ptmp+=tmp_step;
+ ff_snow_pred_block(s, block[1], tmp, src_stride, src_x, src_y, b_w, b_h, rt, plane_index, w, h);
+ }
+
+ if(same_block(lt, lb)){
+ block[2]= block[0];
+ }else if(same_block(rt, lb)){
+ block[2]= block[1];
+ }else{
+ block[2]= ptmp;
+ ptmp+=tmp_step;
+ ff_snow_pred_block(s, block[2], tmp, src_stride, src_x, src_y, b_w, b_h, lb, plane_index, w, h);
+ }
+
+ if(same_block(lt, rb) ){
+ block[3]= block[0];
+ }else if(same_block(rt, rb)){
+ block[3]= block[1];
+ }else if(same_block(lb, rb)){
+ block[3]= block[2];
+ }else{
+ block[3]= ptmp;
+ ff_snow_pred_block(s, block[3], tmp, src_stride, src_x, src_y, b_w, b_h, rb, plane_index, w, h);
+ }
+ if(sliced){
+ s->dwt.inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+ }else{
+ for(y=0; y<b_h; y++){
+ //FIXME ugly misuse of obmc_stride
+ const uint8_t *obmc1= obmc + y*obmc_stride;
+ const uint8_t *obmc2= obmc1+ (obmc_stride>>1);
+ const uint8_t *obmc3= obmc1+ obmc_stride*(obmc_stride>>1);
+ const uint8_t *obmc4= obmc3+ (obmc_stride>>1);
+ for(x=0; x<b_w; x++){
+ int v= obmc1[x] * block[3][x + y*src_stride]
+ +obmc2[x] * block[2][x + y*src_stride]
+ +obmc3[x] * block[1][x + y*src_stride]
+ +obmc4[x] * block[0][x + y*src_stride];
+
+ v <<= 8 - LOG2_OBMC_MAX;
+ if(FRAC_BITS != 8){
+ v >>= 8 - FRAC_BITS;
+ }
+ if(add){
+ v += dst[x + y*dst_stride];
+ v = (v + (1<<(FRAC_BITS-1))) >> FRAC_BITS;
+ if(v&(~255)) v= ~(v>>31);
+ dst8[x + y*src_stride] = v;
+ }else{
+ dst[x + y*dst_stride] -= v;
+ }
+ }
+ }
+ }
+}
+
+static av_always_inline void predict_slice(SnowContext *s, IDWTELEM *buf, int plane_index, int add, int mb_y){
+ Plane *p= &s->plane[plane_index];
+ const int mb_w= s->b_width << s->block_max_depth;
+ const int mb_h= s->b_height << s->block_max_depth;
+ int x, y, mb_x;
+ int block_size = MB_SIZE >> s->block_max_depth;
+ int block_w = plane_index ? block_size>>s->chroma_h_shift : block_size;
+ int block_h = plane_index ? block_size>>s->chroma_v_shift : block_size;
+ const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+s->chroma_h_shift] : ff_obmc_tab[s->block_max_depth];
+ const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
+ int ref_stride= s->current_picture->linesize[plane_index];
+ uint8_t *dst8= s->current_picture->data[plane_index];
+ int w= p->width;
+ int h= p->height;
+ av_assert2(s->chroma_h_shift == s->chroma_v_shift); // obmc params assume squares
+ if(s->keyframe || (s->avctx->debug&512)){
+ if(mb_y==mb_h)
+ return;
+
+ if(add){
+ for(y=block_h*mb_y; y<FFMIN(h,block_h*(mb_y+1)); y++){
+ for(x=0; x<w; x++){
+ int v= buf[x + y*w] + (128<<FRAC_BITS) + (1<<(FRAC_BITS-1));
+ v >>= FRAC_BITS;
+ if(v&(~255)) v= ~(v>>31);
+ dst8[x + y*ref_stride]= v;
+ }
+ }
+ }else{
+ for(y=block_h*mb_y; y<FFMIN(h,block_h*(mb_y+1)); y++){
+ for(x=0; x<w; x++){
+ buf[x + y*w]-= 128<<FRAC_BITS;
+ }
+ }
+ }
+
+ return;
+ }
+
+ for(mb_x=0; mb_x<=mb_w; mb_x++){
+ add_yblock(s, 0, NULL, buf, dst8, obmc,
+ block_w*mb_x - block_w/2,
+ block_h*mb_y - block_h/2,
+ block_w, block_h,
+ w, h,
+ w, ref_stride, obmc_stride,
+ mb_x - 1, mb_y - 1,
+ add, 1, plane_index);
+ }
+}
+
+static av_always_inline void predict_plane(SnowContext *s, IDWTELEM *buf, int plane_index, int add){
+ const int mb_h= s->b_height << s->block_max_depth;
+ int mb_y;
+ for(mb_y=0; mb_y<=mb_h; mb_y++)
+ predict_slice(s, buf, plane_index, add, mb_y);
+}
+
+static inline void set_blocks(SnowContext *s, int level, int x, int y, int l, int cb, int cr, int mx, int my, int ref, int type){
+ const int w= s->b_width << s->block_max_depth;
+ const int rem_depth= s->block_max_depth - level;
+ const int index= (x + y*w) << rem_depth;
+ const int block_w= 1<<rem_depth;
+ const int block_h= 1<<rem_depth; //FIXME "w!=h"
+ BlockNode block;
+ int i,j;
+
+ block.color[0]= l;
+ block.color[1]= cb;
+ block.color[2]= cr;
+ block.mx= mx;
+ block.my= my;
+ block.ref= ref;
+ block.type= type;
+ block.level= level;
+
+ for(j=0; j<block_h; j++){
+ for(i=0; i<block_w; i++){
+ s->block[index + i + j*w]= block;
+ }
+ }
+}
+
+static inline void init_ref(MotionEstContext *c, uint8_t *src[3], uint8_t *ref[3], uint8_t *ref2[3], int x, int y, int ref_index){
+ SnowContext *s = c->avctx->priv_data;
+ const int offset[3]= {
+ y*c-> stride + x,
+ ((y*c->uvstride + x)>>s->chroma_h_shift),
+ ((y*c->uvstride + x)>>s->chroma_h_shift),
+ };
+ int i;
+ for(i=0; i<3; i++){
+ c->src[0][i]= src [i];
+ c->ref[0][i]= ref [i] + offset[i];
+ }
+ av_assert2(!ref_index);
+}
+
+
+/* bitstream functions */
+
+extern const int8_t ff_quant3bA[256];
+
+#define QEXPSHIFT (7-FRAC_BITS+8) //FIXME try to change this to 0
+
+static inline void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed){
+ int i;
+
+ if(v){
+ const int a= FFABS(v);
+ const int e= av_log2(a);
+ const int el= FFMIN(e, 10);
+ put_rac(c, state+0, 0);
+
+ for(i=0; i<el; i++){
+ put_rac(c, state+1+i, 1); //1..10
+ }
+ for(; i<e; i++){
+ put_rac(c, state+1+9, 1); //1..10
+ }
+ put_rac(c, state+1+FFMIN(i,9), 0);
+
+ for(i=e-1; i>=el; i--){
+ put_rac(c, state+22+9, (a>>i)&1); //22..31
+ }
+ for(; i>=0; i--){
+ put_rac(c, state+22+i, (a>>i)&1); //22..31
+ }
+
+ if(is_signed)
+ put_rac(c, state+11 + el, v < 0); //11..21
+ }else{
+ put_rac(c, state+0, 1);
+ }
+}
+
+static inline int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){
+ if(get_rac(c, state+0))
+ return 0;
+ else{
+ int i, e, a;
+ e= 0;
+ while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10
+ e++;
+ }
+
+ a= 1;
+ for(i=e-1; i>=0; i--){
+ a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31
+ }
+
+ e= -(is_signed && get_rac(c, state+11 + FFMIN(e,10))); //11..21
+ return (a^e)-e;
+ }
+}
+
+static inline void put_symbol2(RangeCoder *c, uint8_t *state, int v, int log2){
+ int i;
+ int r= log2>=0 ? 1<<log2 : 1;
+
+ av_assert2(v>=0);
+ av_assert2(log2>=-4);
+
+ while(v >= r){
+ put_rac(c, state+4+log2, 1);
+ v -= r;
+ log2++;
+ if(log2>0) r+=r;
+ }
+ put_rac(c, state+4+log2, 0);
+
+ for(i=log2-1; i>=0; i--){
+ put_rac(c, state+31-i, (v>>i)&1);
+ }
+}
+
+static inline int get_symbol2(RangeCoder *c, uint8_t *state, int log2){
+ int i;
+ int r= log2>=0 ? 1<<log2 : 1;
+ int v=0;
+
+ av_assert2(log2>=-4);
+
+ while(log2<28 && get_rac(c, state+4+log2)){
+ v+= r;
+ log2++;
+ if(log2>0) r+=r;
+ }
+
+ for(i=log2-1; i>=0; i--){
+ v+= get_rac(c, state+31-i)<<i;
+ }
+
+ return v;
+}
+
+static inline void unpack_coeffs(SnowContext *s, SubBand *b, SubBand * parent, int orientation){
+ const int w= b->width;
+ const int h= b->height;
+ int x,y;
+
+ int run, runs;
+ x_and_coeff *xc= b->x_coeff;
+ x_and_coeff *prev_xc= NULL;
+ x_and_coeff *prev2_xc= xc;
+ x_and_coeff *parent_xc= parent ? parent->x_coeff : NULL;
+ x_and_coeff *prev_parent_xc= parent_xc;
+
+ runs= get_symbol2(&s->c, b->state[30], 0);
+ if(runs-- > 0) run= get_symbol2(&s->c, b->state[1], 3);
+ else run= INT_MAX;
+
+ for(y=0; y<h; y++){
+ int v=0;
+ int lt=0, t=0, rt=0;
+
+ if(y && prev_xc->x == 0){
+ rt= prev_xc->coeff;
+ }
+ for(x=0; x<w; x++){
+ int p=0;
+ const int l= v;
+
+ lt= t; t= rt;
+
+ if(y){
+ if(prev_xc->x <= x)
+ prev_xc++;
+ if(prev_xc->x == x + 1)
+ rt= prev_xc->coeff;
+ else
+ rt=0;
+ }
+ if(parent_xc){
+ if(x>>1 > parent_xc->x){
+ parent_xc++;
+ }
+ if(x>>1 == parent_xc->x){
+ p= parent_xc->coeff;
+ }
+ }
+ if(/*ll|*/l|lt|t|rt|p){
+ int context= av_log2(/*FFABS(ll) + */3*(l>>1) + (lt>>1) + (t&~1) + (rt>>1) + (p>>1));
+
+ v=get_rac(&s->c, &b->state[0][context]);
+ if(v){
+ v= 2*(get_symbol2(&s->c, b->state[context + 2], context-4) + 1);
+ v+=get_rac(&s->c, &b->state[0][16 + 1 + 3 + ff_quant3bA[l&0xFF] + 3*ff_quant3bA[t&0xFF]]);
+ if ((uint16_t)v != v) {
+ av_log(s->avctx, AV_LOG_ERROR, "Coefficient damaged\n");
+ v = 1;
+ }
+ xc->x=x;
+ (xc++)->coeff= v;
+ }
+ }else{
+ if(!run){
+ if(runs-- > 0) run= get_symbol2(&s->c, b->state[1], 3);
+ else run= INT_MAX;
+ v= 2*(get_symbol2(&s->c, b->state[0 + 2], 0-4) + 1);
+ v+=get_rac(&s->c, &b->state[0][16 + 1 + 3]);
+ if ((uint16_t)v != v) {
+ av_log(s->avctx, AV_LOG_ERROR, "Coefficient damaged\n");
+ v = 1;
+ }
+
+ xc->x=x;
+ (xc++)->coeff= v;
+ }else{
+ int max_run;
+ run--;
+ v=0;
+ av_assert2(run >= 0);
+ if(y) max_run= FFMIN(run, prev_xc->x - x - 2);
+ else max_run= FFMIN(run, w-x-1);
+ if(parent_xc)
+ max_run= FFMIN(max_run, 2*parent_xc->x - x - 1);
+ av_assert2(max_run >= 0 && max_run <= run);
+
+ x+= max_run;
+ run-= max_run;
+ }
+ }
+ }
+ (xc++)->x= w+1; //end marker
+ prev_xc= prev2_xc;
+ prev2_xc= xc;
+
+ if(parent_xc){
+ if(y&1){
+ while(parent_xc->x != parent->width+1)
+ parent_xc++;
+ parent_xc++;
+ prev_parent_xc= parent_xc;
+ }else{
+ parent_xc= prev_parent_xc;
+ }
+ }
+ }
+
+ (xc++)->x= w+1; //end marker
+}
+
+#endif /* AVCODEC_SNOW_H */
diff --git a/libavcodec/snow_dwt.c b/libavcodec/snow_dwt.c
new file mode 100644
index 0000000000..25681e7edd
--- /dev/null
+++ b/libavcodec/snow_dwt.c
@@ -0,0 +1,860 @@
+/*
+ * Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2008 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/avassert.h"
+#include "libavutil/common.h"
+#include "me_cmp.h"
+#include "snow_dwt.h"
+
+int ff_slice_buffer_init(slice_buffer *buf, int line_count,
+ int max_allocated_lines, int line_width,
+ IDWTELEM *base_buffer)
+{
+ int i;
+
+ buf->base_buffer = base_buffer;
+ buf->line_count = line_count;
+ buf->line_width = line_width;
+ buf->data_count = max_allocated_lines;
+ buf->line = av_mallocz_array(line_count, sizeof(IDWTELEM *));
+ if (!buf->line)
+ return AVERROR(ENOMEM);
+ buf->data_stack = av_malloc_array(max_allocated_lines, sizeof(IDWTELEM *));
+ if (!buf->data_stack) {
+ av_freep(&buf->line);
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < max_allocated_lines; i++) {
+ buf->data_stack[i] = av_malloc_array(line_width, sizeof(IDWTELEM));
+ if (!buf->data_stack[i]) {
+ for (i--; i >=0; i--)
+ av_freep(&buf->data_stack[i]);
+ av_freep(&buf->data_stack);
+ av_freep(&buf->line);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ buf->data_stack_top = max_allocated_lines - 1;
+ return 0;
+}
+
+IDWTELEM *ff_slice_buffer_load_line(slice_buffer *buf, int line)
+{
+ IDWTELEM *buffer;
+
+ av_assert0(buf->data_stack_top >= 0);
+// av_assert1(!buf->line[line]);
+ if (buf->line[line])
+ return buf->line[line];
+
+ buffer = buf->data_stack[buf->data_stack_top];
+ buf->data_stack_top--;
+ buf->line[line] = buffer;
+
+ return buffer;
+}
+
+void ff_slice_buffer_release(slice_buffer *buf, int line)
+{
+ IDWTELEM *buffer;
+
+ av_assert1(line >= 0 && line < buf->line_count);
+ av_assert1(buf->line[line]);
+
+ buffer = buf->line[line];
+ buf->data_stack_top++;
+ buf->data_stack[buf->data_stack_top] = buffer;
+ buf->line[line] = NULL;
+}
+
+void ff_slice_buffer_flush(slice_buffer *buf)
+{
+ int i;
+
+ if (!buf->line)
+ return;
+
+ for (i = 0; i < buf->line_count; i++)
+ if (buf->line[i])
+ ff_slice_buffer_release(buf, i);
+}
+
+void ff_slice_buffer_destroy(slice_buffer *buf)
+{
+ int i;
+ ff_slice_buffer_flush(buf);
+
+ if (buf->data_stack)
+ for (i = buf->data_count - 1; i >= 0; i--)
+ av_freep(&buf->data_stack[i]);
+ av_freep(&buf->data_stack);
+ av_freep(&buf->line);
+}
+
+static av_always_inline void lift(DWTELEM *dst, DWTELEM *src, DWTELEM *ref,
+ int dst_step, int src_step, int ref_step,
+ int width, int mul, int add, int shift,
+ int highpass, int inverse)
+{
+ const int mirror_left = !highpass;
+ const int mirror_right = (width & 1) ^ highpass;
+ const int w = (width >> 1) - 1 + (highpass & width);
+ int i;
+
+#define LIFT(src, ref, inv) ((src) + ((inv) ? -(ref) : +(ref)))
+ if (mirror_left) {
+ dst[0] = LIFT(src[0], ((mul * 2 * ref[0] + add) >> shift), inverse);
+ dst += dst_step;
+ src += src_step;
+ }
+
+ for (i = 0; i < w; i++)
+ dst[i * dst_step] = LIFT(src[i * src_step],
+ ((mul * (ref[i * ref_step] +
+ ref[(i + 1) * ref_step]) +
+ add) >> shift),
+ inverse);
+
+ if (mirror_right)
+ dst[w * dst_step] = LIFT(src[w * src_step],
+ ((mul * 2 * ref[w * ref_step] + add) >> shift),
+ inverse);
+}
+
+static av_always_inline void liftS(DWTELEM *dst, DWTELEM *src, DWTELEM *ref,
+ int dst_step, int src_step, int ref_step,
+ int width, int mul, int add, int shift,
+ int highpass, int inverse)
+{
+ const int mirror_left = !highpass;
+ const int mirror_right = (width & 1) ^ highpass;
+ const int w = (width >> 1) - 1 + (highpass & width);
+ int i;
+
+ av_assert1(shift == 4);
+#define LIFTS(src, ref, inv) \
+ ((inv) ? (src) + (((ref) + 4 * (src)) >> shift) \
+ : -((-16 * (src) + (ref) + add / \
+ 4 + 1 + (5 << 25)) / (5 * 4) - (1 << 23)))
+ if (mirror_left) {
+ dst[0] = LIFTS(src[0], mul * 2 * ref[0] + add, inverse);
+ dst += dst_step;
+ src += src_step;
+ }
+
+ for (i = 0; i < w; i++)
+ dst[i * dst_step] = LIFTS(src[i * src_step],
+ mul * (ref[i * ref_step] +
+ ref[(i + 1) * ref_step]) + add,
+ inverse);
+
+ if (mirror_right)
+ dst[w * dst_step] = LIFTS(src[w * src_step],
+ mul * 2 * ref[w * ref_step] + add,
+ inverse);
+}
+
+static void horizontal_decompose53i(DWTELEM *b, DWTELEM *temp, int width)
+{
+ const int width2 = width >> 1;
+ int x;
+ const int w2 = (width + 1) >> 1;
+
+ for (x = 0; x < width2; x++) {
+ temp[x] = b[2 * x];
+ temp[x + w2] = b[2 * x + 1];
+ }
+ if (width & 1)
+ temp[x] = b[2 * x];
+ lift(b + w2, temp + w2, temp, 1, 1, 1, width, -1, 0, 1, 1, 0);
+ lift(b, temp, b + w2, 1, 1, 1, width, 1, 2, 2, 0, 0);
+}
+
+static void vertical_decompose53iH0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] -= (b0[i] + b2[i]) >> 1;
+}
+
+static void vertical_decompose53iL0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] += (b0[i] + b2[i] + 2) >> 2;
+}
+
+static void spatial_decompose53i(DWTELEM *buffer, DWTELEM *temp,
+ int width, int height, int stride)
+{
+ int y;
+ DWTELEM *b0 = buffer + avpriv_mirror(-2 - 1, height - 1) * stride;
+ DWTELEM *b1 = buffer + avpriv_mirror(-2, height - 1) * stride;
+
+ for (y = -2; y < height; y += 2) {
+ DWTELEM *b2 = buffer + avpriv_mirror(y + 1, height - 1) * stride;
+ DWTELEM *b3 = buffer + avpriv_mirror(y + 2, height - 1) * stride;
+
+ if (y + 1 < (unsigned)height)
+ horizontal_decompose53i(b2, temp, width);
+ if (y + 2 < (unsigned)height)
+ horizontal_decompose53i(b3, temp, width);
+
+ if (y + 1 < (unsigned)height)
+ vertical_decompose53iH0(b1, b2, b3, width);
+ if (y + 0 < (unsigned)height)
+ vertical_decompose53iL0(b0, b1, b2, width);
+
+ b0 = b2;
+ b1 = b3;
+ }
+}
+
+static void horizontal_decompose97i(DWTELEM *b, DWTELEM *temp, int width)
+{
+ const int w2 = (width + 1) >> 1;
+
+ lift(temp + w2, b + 1, b, 1, 2, 2, width, W_AM, W_AO, W_AS, 1, 1);
+ liftS(temp, b, temp + w2, 1, 2, 1, width, W_BM, W_BO, W_BS, 0, 0);
+ lift(b + w2, temp + w2, temp, 1, 1, 1, width, W_CM, W_CO, W_CS, 1, 0);
+ lift(b, temp, b + w2, 1, 1, 1, width, W_DM, W_DO, W_DS, 0, 0);
+}
+
+static void vertical_decompose97iH0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] -= (W_AM * (b0[i] + b2[i]) + W_AO) >> W_AS;
+}
+
+static void vertical_decompose97iH1(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] += (W_CM * (b0[i] + b2[i]) + W_CO) >> W_CS;
+}
+
+static void vertical_decompose97iL0(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] = (16 * 4 * b1[i] - 4 * (b0[i] + b2[i]) + W_BO * 5 + (5 << 27)) /
+ (5 * 16) - (1 << 23);
+}
+
+static void vertical_decompose97iL1(DWTELEM *b0, DWTELEM *b1, DWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] += (W_DM * (b0[i] + b2[i]) + W_DO) >> W_DS;
+}
+
+static void spatial_decompose97i(DWTELEM *buffer, DWTELEM *temp,
+ int width, int height, int stride)
+{
+ int y;
+ DWTELEM *b0 = buffer + avpriv_mirror(-4 - 1, height - 1) * stride;
+ DWTELEM *b1 = buffer + avpriv_mirror(-4, height - 1) * stride;
+ DWTELEM *b2 = buffer + avpriv_mirror(-4 + 1, height - 1) * stride;
+ DWTELEM *b3 = buffer + avpriv_mirror(-4 + 2, height - 1) * stride;
+
+ for (y = -4; y < height; y += 2) {
+ DWTELEM *b4 = buffer + avpriv_mirror(y + 3, height - 1) * stride;
+ DWTELEM *b5 = buffer + avpriv_mirror(y + 4, height - 1) * stride;
+
+ if (y + 3 < (unsigned)height)
+ horizontal_decompose97i(b4, temp, width);
+ if (y + 4 < (unsigned)height)
+ horizontal_decompose97i(b5, temp, width);
+
+ if (y + 3 < (unsigned)height)
+ vertical_decompose97iH0(b3, b4, b5, width);
+ if (y + 2 < (unsigned)height)
+ vertical_decompose97iL0(b2, b3, b4, width);
+ if (y + 1 < (unsigned)height)
+ vertical_decompose97iH1(b1, b2, b3, width);
+ if (y + 0 < (unsigned)height)
+ vertical_decompose97iL1(b0, b1, b2, width);
+
+ b0 = b2;
+ b1 = b3;
+ b2 = b4;
+ b3 = b5;
+ }
+}
+
+void ff_spatial_dwt(DWTELEM *buffer, DWTELEM *temp, int width, int height,
+ int stride, int type, int decomposition_count)
+{
+ int level;
+
+ for (level = 0; level < decomposition_count; level++) {
+ switch (type) {
+ case DWT_97:
+ spatial_decompose97i(buffer, temp,
+ width >> level, height >> level,
+ stride << level);
+ break;
+ case DWT_53:
+ spatial_decompose53i(buffer, temp,
+ width >> level, height >> level,
+ stride << level);
+ break;
+ }
+ }
+}
+
+static void horizontal_compose53i(IDWTELEM *b, IDWTELEM *temp, int width)
+{
+ const int width2 = width >> 1;
+ const int w2 = (width + 1) >> 1;
+ int x;
+
+ for (x = 0; x < width2; x++) {
+ temp[2 * x] = b[x];
+ temp[2 * x + 1] = b[x + w2];
+ }
+ if (width & 1)
+ temp[2 * x] = b[x];
+
+ b[0] = temp[0] - ((temp[1] + 1) >> 1);
+ for (x = 2; x < width - 1; x += 2) {
+ b[x] = temp[x] - ((temp[x - 1] + temp[x + 1] + 2) >> 2);
+ b[x - 1] = temp[x - 1] + ((b[x - 2] + b[x] + 1) >> 1);
+ }
+ if (width & 1) {
+ b[x] = temp[x] - ((temp[x - 1] + 1) >> 1);
+ b[x - 1] = temp[x - 1] + ((b[x - 2] + b[x] + 1) >> 1);
+ } else
+ b[x - 1] = temp[x - 1] + b[x - 2];
+}
+
+static void vertical_compose53iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] += (b0[i] + b2[i]) >> 1;
+}
+
+static void vertical_compose53iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] -= (b0[i] + b2[i] + 2) >> 2;
+}
+
+static void spatial_compose53i_buffered_init(DWTCompose *cs, slice_buffer *sb,
+ int height, int stride_line)
+{
+ cs->b0 = slice_buffer_get_line(sb,
+ avpriv_mirror(-1 - 1, height - 1) * stride_line);
+ cs->b1 = slice_buffer_get_line(sb, avpriv_mirror(-1, height - 1) * stride_line);
+ cs->y = -1;
+}
+
+static void spatial_compose53i_init(DWTCompose *cs, IDWTELEM *buffer,
+ int height, int stride)
+{
+ cs->b0 = buffer + avpriv_mirror(-1 - 1, height - 1) * stride;
+ cs->b1 = buffer + avpriv_mirror(-1, height - 1) * stride;
+ cs->y = -1;
+}
+
+static void spatial_compose53i_dy_buffered(DWTCompose *cs, slice_buffer *sb,
+ IDWTELEM *temp,
+ int width, int height,
+ int stride_line)
+{
+ int y = cs->y;
+
+ IDWTELEM *b0 = cs->b0;
+ IDWTELEM *b1 = cs->b1;
+ IDWTELEM *b2 = slice_buffer_get_line(sb,
+ avpriv_mirror(y + 1, height - 1) *
+ stride_line);
+ IDWTELEM *b3 = slice_buffer_get_line(sb,
+ avpriv_mirror(y + 2, height - 1) *
+ stride_line);
+
+ if (y + 1 < (unsigned)height && y < (unsigned)height) {
+ int x;
+
+ for (x = 0; x < width; x++) {
+ b2[x] -= (b1[x] + b3[x] + 2) >> 2;
+ b1[x] += (b0[x] + b2[x]) >> 1;
+ }
+ } else {
+ if (y + 1 < (unsigned)height)
+ vertical_compose53iL0(b1, b2, b3, width);
+ if (y + 0 < (unsigned)height)
+ vertical_compose53iH0(b0, b1, b2, width);
+ }
+
+ if (y - 1 < (unsigned)height)
+ horizontal_compose53i(b0, temp, width);
+ if (y + 0 < (unsigned)height)
+ horizontal_compose53i(b1, temp, width);
+
+ cs->b0 = b2;
+ cs->b1 = b3;
+ cs->y += 2;
+}
+
+static void spatial_compose53i_dy(DWTCompose *cs, IDWTELEM *buffer,
+ IDWTELEM *temp, int width, int height,
+ int stride)
+{
+ int y = cs->y;
+ IDWTELEM *b0 = cs->b0;
+ IDWTELEM *b1 = cs->b1;
+ IDWTELEM *b2 = buffer + avpriv_mirror(y + 1, height - 1) * stride;
+ IDWTELEM *b3 = buffer + avpriv_mirror(y + 2, height - 1) * stride;
+
+ if (y + 1 < (unsigned)height)
+ vertical_compose53iL0(b1, b2, b3, width);
+ if (y + 0 < (unsigned)height)
+ vertical_compose53iH0(b0, b1, b2, width);
+
+ if (y - 1 < (unsigned)height)
+ horizontal_compose53i(b0, temp, width);
+ if (y + 0 < (unsigned)height)
+ horizontal_compose53i(b1, temp, width);
+
+ cs->b0 = b2;
+ cs->b1 = b3;
+ cs->y += 2;
+}
+
+void ff_snow_horizontal_compose97i(IDWTELEM *b, IDWTELEM *temp, int width)
+{
+ const int w2 = (width + 1) >> 1;
+ int x;
+
+ temp[0] = b[0] - ((3 * b[w2] + 2) >> 2);
+ for (x = 1; x < (width >> 1); x++) {
+ temp[2 * x] = b[x] - ((3 * (b[x + w2 - 1] + b[x + w2]) + 4) >> 3);
+ temp[2 * x - 1] = b[x + w2 - 1] - temp[2 * x - 2] - temp[2 * x];
+ }
+ if (width & 1) {
+ temp[2 * x] = b[x] - ((3 * b[x + w2 - 1] + 2) >> 2);
+ temp[2 * x - 1] = b[x + w2 - 1] - temp[2 * x - 2] - temp[2 * x];
+ } else
+ temp[2 * x - 1] = b[x + w2 - 1] - 2 * temp[2 * x - 2];
+
+ b[0] = temp[0] + ((2 * temp[0] + temp[1] + 4) >> 3);
+ for (x = 2; x < width - 1; x += 2) {
+ b[x] = temp[x] + ((4 * temp[x] + temp[x - 1] + temp[x + 1] + 8) >> 4);
+ b[x - 1] = temp[x - 1] + ((3 * (b[x - 2] + b[x])) >> 1);
+ }
+ if (width & 1) {
+ b[x] = temp[x] + ((2 * temp[x] + temp[x - 1] + 4) >> 3);
+ b[x - 1] = temp[x - 1] + ((3 * (b[x - 2] + b[x])) >> 1);
+ } else
+ b[x - 1] = temp[x - 1] + 3 * b[x - 2];
+}
+
+static void vertical_compose97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] += (W_AM * (b0[i] + b2[i]) + W_AO) >> W_AS;
+}
+
+static void vertical_compose97iH1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] -= (W_CM * (b0[i] + b2[i]) + W_CO) >> W_CS;
+}
+
+static void vertical_compose97iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] += (W_BM * (b0[i] + b2[i]) + 4 * b1[i] + W_BO) >> W_BS;
+}
+
+static void vertical_compose97iL1(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++)
+ b1[i] -= (W_DM * (b0[i] + b2[i]) + W_DO) >> W_DS;
+}
+
+void ff_snow_vertical_compose97i(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5,
+ int width)
+{
+ int i;
+
+ for (i = 0; i < width; i++) {
+ b4[i] -= (W_DM * (b3[i] + b5[i]) + W_DO) >> W_DS;
+ b3[i] -= (W_CM * (b2[i] + b4[i]) + W_CO) >> W_CS;
+ b2[i] += (W_BM * (b1[i] + b3[i]) + 4 * b2[i] + W_BO) >> W_BS;
+ b1[i] += (W_AM * (b0[i] + b2[i]) + W_AO) >> W_AS;
+ }
+}
+
+static void spatial_compose97i_buffered_init(DWTCompose *cs, slice_buffer *sb,
+ int height, int stride_line)
+{
+ cs->b0 = slice_buffer_get_line(sb, avpriv_mirror(-3 - 1, height - 1) * stride_line);
+ cs->b1 = slice_buffer_get_line(sb, avpriv_mirror(-3, height - 1) * stride_line);
+ cs->b2 = slice_buffer_get_line(sb, avpriv_mirror(-3 + 1, height - 1) * stride_line);
+ cs->b3 = slice_buffer_get_line(sb, avpriv_mirror(-3 + 2, height - 1) * stride_line);
+ cs->y = -3;
+}
+
+static void spatial_compose97i_init(DWTCompose *cs, IDWTELEM *buffer, int height,
+ int stride)
+{
+ cs->b0 = buffer + avpriv_mirror(-3 - 1, height - 1) * stride;
+ cs->b1 = buffer + avpriv_mirror(-3, height - 1) * stride;
+ cs->b2 = buffer + avpriv_mirror(-3 + 1, height - 1) * stride;
+ cs->b3 = buffer + avpriv_mirror(-3 + 2, height - 1) * stride;
+ cs->y = -3;
+}
+
+static void spatial_compose97i_dy_buffered(SnowDWTContext *dsp, DWTCompose *cs,
+ slice_buffer * sb, IDWTELEM *temp,
+ int width, int height,
+ int stride_line)
+{
+ int y = cs->y;
+
+ IDWTELEM *b0 = cs->b0;
+ IDWTELEM *b1 = cs->b1;
+ IDWTELEM *b2 = cs->b2;
+ IDWTELEM *b3 = cs->b3;
+ IDWTELEM *b4 = slice_buffer_get_line(sb,
+ avpriv_mirror(y + 3, height - 1) *
+ stride_line);
+ IDWTELEM *b5 = slice_buffer_get_line(sb,
+ avpriv_mirror(y + 4, height - 1) *
+ stride_line);
+
+ if (y > 0 && y + 4 < height) {
+ dsp->vertical_compose97i(b0, b1, b2, b3, b4, b5, width);
+ } else {
+ if (y + 3 < (unsigned)height)
+ vertical_compose97iL1(b3, b4, b5, width);
+ if (y + 2 < (unsigned)height)
+ vertical_compose97iH1(b2, b3, b4, width);
+ if (y + 1 < (unsigned)height)
+ vertical_compose97iL0(b1, b2, b3, width);
+ if (y + 0 < (unsigned)height)
+ vertical_compose97iH0(b0, b1, b2, width);
+ }
+
+ if (y - 1 < (unsigned)height)
+ dsp->horizontal_compose97i(b0, temp, width);
+ if (y + 0 < (unsigned)height)
+ dsp->horizontal_compose97i(b1, temp, width);
+
+ cs->b0 = b2;
+ cs->b1 = b3;
+ cs->b2 = b4;
+ cs->b3 = b5;
+ cs->y += 2;
+}
+
+static void spatial_compose97i_dy(DWTCompose *cs, IDWTELEM *buffer,
+ IDWTELEM *temp, int width, int height,
+ int stride)
+{
+ int y = cs->y;
+ IDWTELEM *b0 = cs->b0;
+ IDWTELEM *b1 = cs->b1;
+ IDWTELEM *b2 = cs->b2;
+ IDWTELEM *b3 = cs->b3;
+ IDWTELEM *b4 = buffer + avpriv_mirror(y + 3, height - 1) * stride;
+ IDWTELEM *b5 = buffer + avpriv_mirror(y + 4, height - 1) * stride;
+
+ if (y + 3 < (unsigned)height)
+ vertical_compose97iL1(b3, b4, b5, width);
+ if (y + 2 < (unsigned)height)
+ vertical_compose97iH1(b2, b3, b4, width);
+ if (y + 1 < (unsigned)height)
+ vertical_compose97iL0(b1, b2, b3, width);
+ if (y + 0 < (unsigned)height)
+ vertical_compose97iH0(b0, b1, b2, width);
+
+ if (y - 1 < (unsigned)height)
+ ff_snow_horizontal_compose97i(b0, temp, width);
+ if (y + 0 < (unsigned)height)
+ ff_snow_horizontal_compose97i(b1, temp, width);
+
+ cs->b0 = b2;
+ cs->b1 = b3;
+ cs->b2 = b4;
+ cs->b3 = b5;
+ cs->y += 2;
+}
+
+void ff_spatial_idwt_buffered_init(DWTCompose *cs, slice_buffer *sb, int width,
+ int height, int stride_line, int type,
+ int decomposition_count)
+{
+ int level;
+ for (level = decomposition_count - 1; level >= 0; level--) {
+ switch (type) {
+ case DWT_97:
+ spatial_compose97i_buffered_init(cs + level, sb, height >> level,
+ stride_line << level);
+ break;
+ case DWT_53:
+ spatial_compose53i_buffered_init(cs + level, sb, height >> level,
+ stride_line << level);
+ break;
+ }
+ }
+}
+
+void ff_spatial_idwt_buffered_slice(SnowDWTContext *dsp, DWTCompose *cs,
+ slice_buffer *slice_buf, IDWTELEM *temp,
+ int width, int height, int stride_line,
+ int type, int decomposition_count, int y)
+{
+ const int support = type == 1 ? 3 : 5;
+ int level;
+ if (type == 2)
+ return;
+
+ for (level = decomposition_count - 1; level >= 0; level--)
+ while (cs[level].y <= FFMIN((y >> level) + support, height >> level)) {
+ switch (type) {
+ case DWT_97:
+ spatial_compose97i_dy_buffered(dsp, cs + level, slice_buf, temp,
+ width >> level,
+ height >> level,
+ stride_line << level);
+ break;
+ case DWT_53:
+ spatial_compose53i_dy_buffered(cs + level, slice_buf, temp,
+ width >> level,
+ height >> level,
+ stride_line << level);
+ break;
+ }
+ }
+}
+
+static void spatial_idwt_init(DWTCompose *cs, IDWTELEM *buffer, int width,
+ int height, int stride, int type,
+ int decomposition_count)
+{
+ int level;
+ for (level = decomposition_count - 1; level >= 0; level--) {
+ switch (type) {
+ case DWT_97:
+ spatial_compose97i_init(cs + level, buffer, height >> level,
+ stride << level);
+ break;
+ case DWT_53:
+ spatial_compose53i_init(cs + level, buffer, height >> level,
+ stride << level);
+ break;
+ }
+ }
+}
+
+static void spatial_idwt_slice(DWTCompose *cs, IDWTELEM *buffer,
+ IDWTELEM *temp, int width, int height,
+ int stride, int type,
+ int decomposition_count, int y)
+{
+ const int support = type == 1 ? 3 : 5;
+ int level;
+ if (type == 2)
+ return;
+
+ for (level = decomposition_count - 1; level >= 0; level--)
+ while (cs[level].y <= FFMIN((y >> level) + support, height >> level)) {
+ switch (type) {
+ case DWT_97:
+ spatial_compose97i_dy(cs + level, buffer, temp, width >> level,
+ height >> level, stride << level);
+ break;
+ case DWT_53:
+ spatial_compose53i_dy(cs + level, buffer, temp, width >> level,
+ height >> level, stride << level);
+ break;
+ }
+ }
+}
+
+void ff_spatial_idwt(IDWTELEM *buffer, IDWTELEM *temp, int width, int height,
+ int stride, int type, int decomposition_count)
+{
+ DWTCompose cs[MAX_DECOMPOSITIONS];
+ int y;
+ spatial_idwt_init(cs, buffer, width, height, stride, type,
+ decomposition_count);
+ for (y = 0; y < height; y += 4)
+ spatial_idwt_slice(cs, buffer, temp, width, height, stride, type,
+ decomposition_count, y);
+}
+
+static inline int w_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size,
+ int w, int h, int type)
+{
+ int s, i, j;
+ const int dec_count = w == 8 ? 3 : 4;
+ int tmp[32 * 32], tmp2[32];
+ int level, ori;
+ static const int scale[2][2][4][4] = {
+ {
+ { // 9/7 8x8 dec=3
+ { 268, 239, 239, 213 },
+ { 0, 224, 224, 152 },
+ { 0, 135, 135, 110 },
+ },
+ { // 9/7 16x16 or 32x32 dec=4
+ { 344, 310, 310, 280 },
+ { 0, 320, 320, 228 },
+ { 0, 175, 175, 136 },
+ { 0, 129, 129, 102 },
+ }
+ },
+ {
+ { // 5/3 8x8 dec=3
+ { 275, 245, 245, 218 },
+ { 0, 230, 230, 156 },
+ { 0, 138, 138, 113 },
+ },
+ { // 5/3 16x16 or 32x32 dec=4
+ { 352, 317, 317, 286 },
+ { 0, 328, 328, 233 },
+ { 0, 180, 180, 140 },
+ { 0, 132, 132, 105 },
+ }
+ }
+ };
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j += 4) {
+ tmp[32 * i + j + 0] = (pix1[j + 0] - pix2[j + 0]) << 4;
+ tmp[32 * i + j + 1] = (pix1[j + 1] - pix2[j + 1]) << 4;
+ tmp[32 * i + j + 2] = (pix1[j + 2] - pix2[j + 2]) << 4;
+ tmp[32 * i + j + 3] = (pix1[j + 3] - pix2[j + 3]) << 4;
+ }
+ pix1 += line_size;
+ pix2 += line_size;
+ }
+
+ ff_spatial_dwt(tmp, tmp2, w, h, 32, type, dec_count);
+
+ s = 0;
+ av_assert1(w == h);
+ for (level = 0; level < dec_count; level++)
+ for (ori = level ? 1 : 0; ori < 4; ori++) {
+ int size = w >> (dec_count - level);
+ int sx = (ori & 1) ? size : 0;
+ int stride = 32 << (dec_count - level);
+ int sy = (ori & 2) ? stride >> 1 : 0;
+
+ for (i = 0; i < size; i++)
+ for (j = 0; j < size; j++) {
+ int v = tmp[sx + sy + i * stride + j] *
+ scale[type][dec_count - 3][level][ori];
+ s += FFABS(v);
+ }
+ }
+ av_assert1(s >= 0);
+ return s >> 9;
+}
+
+static int w53_8_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 8, h, 1);
+}
+
+static int w97_8_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 8, h, 0);
+}
+
+static int w53_16_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 16, h, 1);
+}
+
+static int w97_16_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 16, h, 0);
+}
+
+int ff_w53_32_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 32, h, 1);
+}
+
+int ff_w97_32_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h)
+{
+ return w_c(v, pix1, pix2, line_size, 32, h, 0);
+}
+
+av_cold void ff_dsputil_init_dwt(MECmpContext *c)
+{
+ c->w53[0] = w53_16_c;
+ c->w53[1] = w53_8_c;
+ c->w97[0] = w97_16_c;
+ c->w97[1] = w97_8_c;
+}
+
+av_cold void ff_dwt_init(SnowDWTContext *c)
+{
+ c->vertical_compose97i = ff_snow_vertical_compose97i;
+ c->horizontal_compose97i = ff_snow_horizontal_compose97i;
+ c->inner_add_yblock = ff_snow_inner_add_yblock;
+
+ if (HAVE_MMX)
+ ff_dwt_init_x86(c);
+}
+
+
diff --git a/libavcodec/snow_dwt.h b/libavcodec/snow_dwt.h
new file mode 100644
index 0000000000..e2d7528056
--- /dev/null
+++ b/libavcodec/snow_dwt.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2004-2010 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_SNOW_DWT_H
+#define AVCODEC_SNOW_DWT_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef int DWTELEM;
+typedef short IDWTELEM;
+
+#define MAX_DECOMPOSITIONS 8
+
+typedef struct DWTCompose {
+ IDWTELEM *b0;
+ IDWTELEM *b1;
+ IDWTELEM *b2;
+ IDWTELEM *b3;
+ int y;
+} DWTCompose;
+
+/** Used to minimize the amount of memory used in order to
+ * optimize cache performance. **/
+typedef struct slice_buffer_s {
+ IDWTELEM **line; ///< For use by idwt and predict_slices.
+ IDWTELEM **data_stack; ///< Used for internal purposes.
+ int data_stack_top;
+ int line_count;
+ int line_width;
+ int data_count;
+ IDWTELEM *base_buffer; ///< Buffer that this structure is caching.
+} slice_buffer;
+
+struct SnowDWTContext;
+
+typedef struct SnowDWTContext {
+ void (*vertical_compose97i)(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5,
+ int width);
+ void (*horizontal_compose97i)(IDWTELEM *b, IDWTELEM *temp, int width);
+ void (*inner_add_yblock)(const uint8_t *obmc, const int obmc_stride,
+ uint8_t **block, int b_w, int b_h, int src_x,
+ int src_y, int src_stride, slice_buffer *sb,
+ int add, uint8_t *dst8);
+} SnowDWTContext;
+
+
+#define DWT_97 0
+#define DWT_53 1
+
+#define liftS lift
+#define W_AM 3
+#define W_AO 0
+#define W_AS 1
+
+#undef liftS
+#define W_BM 1
+#define W_BO 8
+#define W_BS 4
+
+#define W_CM 1
+#define W_CO 0
+#define W_CS 0
+
+#define W_DM 3
+#define W_DO 4
+#define W_DS 3
+
+#define slice_buffer_get_line(slice_buf, line_num) \
+ ((slice_buf)->line[line_num] ? (slice_buf)->line[line_num] \
+ : ff_slice_buffer_load_line((slice_buf), \
+ (line_num)))
+
+int ff_slice_buffer_init(slice_buffer *buf, int line_count,
+ int max_allocated_lines, int line_width,
+ IDWTELEM *base_buffer);
+void ff_slice_buffer_release(slice_buffer *buf, int line);
+void ff_slice_buffer_flush(slice_buffer *buf);
+void ff_slice_buffer_destroy(slice_buffer *buf);
+IDWTELEM *ff_slice_buffer_load_line(slice_buffer *buf, int line);
+
+void ff_snow_vertical_compose97i(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+ IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5,
+ int width);
+void ff_snow_horizontal_compose97i(IDWTELEM *b, IDWTELEM *temp, int width);
+void ff_snow_inner_add_yblock(const uint8_t *obmc, const int obmc_stride,
+ uint8_t **block, int b_w, int b_h, int src_x,
+ int src_y, int src_stride, slice_buffer *sb,
+ int add, uint8_t *dst8);
+
+int ff_w53_32_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h);
+int ff_w97_32_c(struct MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t line_size, int h);
+
+void ff_spatial_dwt(int *buffer, int *temp, int width, int height, int stride,
+ int type, int decomposition_count);
+
+void ff_spatial_idwt_buffered_init(DWTCompose *cs, slice_buffer *sb, int width,
+ int height, int stride_line, int type,
+ int decomposition_count);
+void ff_spatial_idwt_buffered_slice(SnowDWTContext *dsp, DWTCompose *cs,
+ slice_buffer *slice_buf, IDWTELEM *temp,
+ int width, int height, int stride_line,
+ int type, int decomposition_count, int y);
+void ff_spatial_idwt(IDWTELEM *buffer, IDWTELEM *temp, int width, int height,
+ int stride, int type, int decomposition_count);
+
+void ff_dwt_init(SnowDWTContext *c);
+void ff_dwt_init_x86(SnowDWTContext *c);
+
+#endif /* AVCODEC_DWT_H */
diff --git a/libavcodec/snowdata.h b/libavcodec/snowdata.h
new file mode 100644
index 0000000000..490fdf8bd6
--- /dev/null
+++ b/libavcodec/snowdata.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2006 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_SNOWDATA_H
+#define AVCODEC_SNOWDATA_H
+
+#include "snow.h"
+
+static const uint8_t obmc32[1024]={
+ 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0,
+ 0, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 16, 20, 20, 20, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 8, 8, 8, 4, 4, 4, 0,
+ 0, 4, 8, 8, 12, 12, 16, 20, 20, 24, 28, 28, 32, 32, 36, 40, 40, 36, 32, 32, 28, 28, 24, 20, 20, 16, 12, 12, 8, 8, 4, 0,
+ 0, 4, 8, 12, 16, 20, 24, 28, 28, 32, 36, 40, 44, 48, 52, 56, 56, 52, 48, 44, 40, 36, 32, 28, 28, 24, 20, 16, 12, 8, 4, 0,
+ 4, 8, 12, 16, 20, 24, 28, 32, 40, 44, 48, 52, 56, 60, 64, 68, 68, 64, 60, 56, 52, 48, 44, 40, 32, 28, 24, 20, 16, 12, 8, 4,
+ 4, 8, 12, 20, 24, 32, 36, 40, 48, 52, 56, 64, 68, 76, 80, 84, 84, 80, 76, 68, 64, 56, 52, 48, 40, 36, 32, 24, 20, 12, 8, 4,
+ 4, 8, 16, 24, 28, 36, 44, 48, 56, 60, 68, 76, 80, 88, 96,100,100, 96, 88, 80, 76, 68, 60, 56, 48, 44, 36, 28, 24, 16, 8, 4,
+ 4, 12, 20, 28, 32, 40, 48, 56, 64, 72, 80, 88, 92,100,108,116,116,108,100, 92, 88, 80, 72, 64, 56, 48, 40, 32, 28, 20, 12, 4,
+ 4, 12, 20, 28, 40, 48, 56, 64, 72, 80, 88, 96,108,116,124,132,132,124,116,108, 96, 88, 80, 72, 64, 56, 48, 40, 28, 20, 12, 4,
+ 4, 16, 24, 32, 44, 52, 60, 72, 80, 92,100,108,120,128,136,148,148,136,128,120,108,100, 92, 80, 72, 60, 52, 44, 32, 24, 16, 4,
+ 4, 16, 28, 36, 48, 56, 68, 80, 88,100,112,120,132,140,152,164,164,152,140,132,120,112,100, 88, 80, 68, 56, 48, 36, 28, 16, 4,
+ 4, 16, 28, 40, 52, 64, 76, 88, 96,108,120,132,144,156,168,180,180,168,156,144,132,120,108, 96, 88, 76, 64, 52, 40, 28, 16, 4,
+ 8, 20, 32, 44, 56, 68, 80, 92,108,120,132,144,156,168,180,192,192,180,168,156,144,132,120,108, 92, 80, 68, 56, 44, 32, 20, 8,
+ 8, 20, 32, 48, 60, 76, 88,100,116,128,140,156,168,184,196,208,208,196,184,168,156,140,128,116,100, 88, 76, 60, 48, 32, 20, 8,
+ 8, 20, 36, 52, 64, 80, 96,108,124,136,152,168,180,196,212,224,224,212,196,180,168,152,136,124,108, 96, 80, 64, 52, 36, 20, 8,
+ 8, 24, 40, 56, 68, 84,100,116,132,148,164,180,192,208,224,240,240,224,208,192,180,164,148,132,116,100, 84, 68, 56, 40, 24, 8,
+ 8, 24, 40, 56, 68, 84,100,116,132,148,164,180,192,208,224,240,240,224,208,192,180,164,148,132,116,100, 84, 68, 56, 40, 24, 8,
+ 8, 20, 36, 52, 64, 80, 96,108,124,136,152,168,180,196,212,224,224,212,196,180,168,152,136,124,108, 96, 80, 64, 52, 36, 20, 8,
+ 8, 20, 32, 48, 60, 76, 88,100,116,128,140,156,168,184,196,208,208,196,184,168,156,140,128,116,100, 88, 76, 60, 48, 32, 20, 8,
+ 8, 20, 32, 44, 56, 68, 80, 92,108,120,132,144,156,168,180,192,192,180,168,156,144,132,120,108, 92, 80, 68, 56, 44, 32, 20, 8,
+ 4, 16, 28, 40, 52, 64, 76, 88, 96,108,120,132,144,156,168,180,180,168,156,144,132,120,108, 96, 88, 76, 64, 52, 40, 28, 16, 4,
+ 4, 16, 28, 36, 48, 56, 68, 80, 88,100,112,120,132,140,152,164,164,152,140,132,120,112,100, 88, 80, 68, 56, 48, 36, 28, 16, 4,
+ 4, 16, 24, 32, 44, 52, 60, 72, 80, 92,100,108,120,128,136,148,148,136,128,120,108,100, 92, 80, 72, 60, 52, 44, 32, 24, 16, 4,
+ 4, 12, 20, 28, 40, 48, 56, 64, 72, 80, 88, 96,108,116,124,132,132,124,116,108, 96, 88, 80, 72, 64, 56, 48, 40, 28, 20, 12, 4,
+ 4, 12, 20, 28, 32, 40, 48, 56, 64, 72, 80, 88, 92,100,108,116,116,108,100, 92, 88, 80, 72, 64, 56, 48, 40, 32, 28, 20, 12, 4,
+ 4, 8, 16, 24, 28, 36, 44, 48, 56, 60, 68, 76, 80, 88, 96,100,100, 96, 88, 80, 76, 68, 60, 56, 48, 44, 36, 28, 24, 16, 8, 4,
+ 4, 8, 12, 20, 24, 32, 36, 40, 48, 52, 56, 64, 68, 76, 80, 84, 84, 80, 76, 68, 64, 56, 52, 48, 40, 36, 32, 24, 20, 12, 8, 4,
+ 4, 8, 12, 16, 20, 24, 28, 32, 40, 44, 48, 52, 56, 60, 64, 68, 68, 64, 60, 56, 52, 48, 44, 40, 32, 28, 24, 20, 16, 12, 8, 4,
+ 0, 4, 8, 12, 16, 20, 24, 28, 28, 32, 36, 40, 44, 48, 52, 56, 56, 52, 48, 44, 40, 36, 32, 28, 28, 24, 20, 16, 12, 8, 4, 0,
+ 0, 4, 8, 8, 12, 12, 16, 20, 20, 24, 28, 28, 32, 32, 36, 40, 40, 36, 32, 32, 28, 28, 24, 20, 20, 16, 12, 12, 8, 8, 4, 0,
+ 0, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 16, 20, 20, 20, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 8, 8, 8, 4, 4, 4, 0,
+ 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0,
+ //error:0.000020
+};
+static const uint8_t obmc16[256]={
+ 0, 4, 4, 8, 8, 12, 12, 16, 16, 12, 12, 8, 8, 4, 4, 0,
+ 4, 8, 16, 20, 28, 32, 40, 44, 44, 40, 32, 28, 20, 16, 8, 4,
+ 4, 16, 24, 36, 44, 56, 64, 76, 76, 64, 56, 44, 36, 24, 16, 4,
+ 8, 20, 36, 48, 64, 76, 92,104,104, 92, 76, 64, 48, 36, 20, 8,
+ 8, 28, 44, 64, 80,100,116,136,136,116,100, 80, 64, 44, 28, 8,
+ 12, 32, 56, 76,100,120,144,164,164,144,120,100, 76, 56, 32, 12,
+ 12, 40, 64, 92,116,144,168,196,196,168,144,116, 92, 64, 40, 12,
+ 16, 44, 76,104,136,164,196,224,224,196,164,136,104, 76, 44, 16,
+ 16, 44, 76,104,136,164,196,224,224,196,164,136,104, 76, 44, 16,
+ 12, 40, 64, 92,116,144,168,196,196,168,144,116, 92, 64, 40, 12,
+ 12, 32, 56, 76,100,120,144,164,164,144,120,100, 76, 56, 32, 12,
+ 8, 28, 44, 64, 80,100,116,136,136,116,100, 80, 64, 44, 28, 8,
+ 8, 20, 36, 48, 64, 76, 92,104,104, 92, 76, 64, 48, 36, 20, 8,
+ 4, 16, 24, 36, 44, 56, 64, 76, 76, 64, 56, 44, 36, 24, 16, 4,
+ 4, 8, 16, 20, 28, 32, 40, 44, 44, 40, 32, 28, 20, 16, 8, 4,
+ 0, 4, 4, 8, 8, 12, 12, 16, 16, 12, 12, 8, 8, 4, 4, 0,
+//error:0.000015
+};
+
+//linear *64
+static const uint8_t obmc8[64]={
+ 4, 12, 20, 28, 28, 20, 12, 4,
+ 12, 36, 60, 84, 84, 60, 36, 12,
+ 20, 60,100,140,140,100, 60, 20,
+ 28, 84,140,196,196,140, 84, 28,
+ 28, 84,140,196,196,140, 84, 28,
+ 20, 60,100,140,140,100, 60, 20,
+ 12, 36, 60, 84, 84, 60, 36, 12,
+ 4, 12, 20, 28, 28, 20, 12, 4,
+//error:0.000000
+};
+
+//linear *64
+static const uint8_t obmc4[16]={
+ 16, 48, 48, 16,
+ 48,144,144, 48,
+ 48,144,144, 48,
+ 16, 48, 48, 16,
+//error:0.000000
+};
+
+const int8_t ff_quant3bA[256]={
+ 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+ 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1,
+};
+
+const uint8_t * const ff_obmc_tab[4]= {
+ obmc32, obmc16, obmc8, obmc4
+};
+
+/* runtime generated tables */
+uint8_t ff_qexp[QROOT];
+int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES];
+
+
+#endif /* AVCODEC_SNOW_H */
diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c
new file mode 100644
index 0000000000..e12cb21fcd
--- /dev/null
+++ b/libavcodec/snowdec.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intmath.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "snow_dwt.h"
+#include "internal.h"
+#include "snow.h"
+
+#include "rangecoder.h"
+#include "mathops.h"
+
+#include "mpegvideo.h"
+#include "h263.h"
+
+static av_always_inline void predict_slice_buffered(SnowContext *s, slice_buffer * sb, IDWTELEM * old_buffer, int plane_index, int add, int mb_y){
+ Plane *p= &s->plane[plane_index];
+ const int mb_w= s->b_width << s->block_max_depth;
+ const int mb_h= s->b_height << s->block_max_depth;
+ int x, y, mb_x;
+ int block_size = MB_SIZE >> s->block_max_depth;
+ int block_w = plane_index ? block_size>>s->chroma_h_shift : block_size;
+ int block_h = plane_index ? block_size>>s->chroma_v_shift : block_size;
+ const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+s->chroma_h_shift] : ff_obmc_tab[s->block_max_depth];
+ int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
+ int ref_stride= s->current_picture->linesize[plane_index];
+ uint8_t *dst8= s->current_picture->data[plane_index];
+ int w= p->width;
+ int h= p->height;
+
+ if(s->keyframe || (s->avctx->debug&512)){
+ if(mb_y==mb_h)
+ return;
+
+ if(add){
+ for(y=block_h*mb_y; y<FFMIN(h,block_h*(mb_y+1)); y++){
+// DWTELEM * line = slice_buffer_get_line(sb, y);
+ IDWTELEM * line = sb->line[y];
+ for(x=0; x<w; x++){
+// int v= buf[x + y*w] + (128<<FRAC_BITS) + (1<<(FRAC_BITS-1));
+ int v= line[x] + (128<<FRAC_BITS) + (1<<(FRAC_BITS-1));
+ v >>= FRAC_BITS;
+ if(v&(~255)) v= ~(v>>31);
+ dst8[x + y*ref_stride]= v;
+ }
+ }
+ }else{
+ for(y=block_h*mb_y; y<FFMIN(h,block_h*(mb_y+1)); y++){
+// DWTELEM * line = slice_buffer_get_line(sb, y);
+ IDWTELEM * line = sb->line[y];
+ for(x=0; x<w; x++){
+ line[x] -= 128 << FRAC_BITS;
+// buf[x + y*w]-= 128<<FRAC_BITS;
+ }
+ }
+ }
+
+ return;
+ }
+
+ for(mb_x=0; mb_x<=mb_w; mb_x++){
+ add_yblock(s, 1, sb, old_buffer, dst8, obmc,
+ block_w*mb_x - block_w/2,
+ block_h*mb_y - block_h/2,
+ block_w, block_h,
+ w, h,
+ w, ref_stride, obmc_stride,
+ mb_x - 1, mb_y - 1,
+ add, 0, plane_index);
+ }
+
+ if(s->avmv && mb_y < mb_h && plane_index == 0)
+ for(mb_x=0; mb_x<mb_w; mb_x++){
+ AVMotionVector *avmv = s->avmv + s->avmv_index;
+ const int b_width = s->b_width << s->block_max_depth;
+ const int b_stride= b_width;
+ BlockNode *bn= &s->block[mb_x + mb_y*b_stride];
+
+ if (bn->type)
+ continue;
+
+ s->avmv_index++;
+
+ avmv->w = block_w;
+ avmv->h = block_h;
+ avmv->dst_x = block_w*mb_x - block_w/2;
+ avmv->dst_y = block_h*mb_y - block_h/2;
+ avmv->src_x = avmv->dst_x + (bn->mx * s->mv_scale)/8;
+ avmv->src_y = avmv->dst_y + (bn->my * s->mv_scale)/8;
+ avmv->source= -1 - bn->ref;
+ avmv->flags = 0;
+ }
+}
+
+static inline void decode_subband_slice_buffered(SnowContext *s, SubBand *b, slice_buffer * sb, int start_y, int h, int save_state[1]){
+ const int w= b->width;
+ int y;
+ const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
+ int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
+ int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
+ int new_index = 0;
+
+ if(b->ibuf == s->spatial_idwt_buffer || s->qlog == LOSSLESS_QLOG){
+ qadd= 0;
+ qmul= 1<<QEXPSHIFT;
+ }
+
+ /* If we are on the second or later slice, restore our index. */
+ if (start_y != 0)
+ new_index = save_state[0];
+
+
+ for(y=start_y; y<h; y++){
+ int x = 0;
+ int v;
+ IDWTELEM * line = slice_buffer_get_line(sb, y * b->stride_line + b->buf_y_offset) + b->buf_x_offset;
+ memset(line, 0, b->width*sizeof(IDWTELEM));
+ v = b->x_coeff[new_index].coeff;
+ x = b->x_coeff[new_index++].x;
+ while(x < w){
+ register int t= ( (v>>1)*qmul + qadd)>>QEXPSHIFT;
+ register int u= -(v&1);
+ line[x] = (t^u) - u;
+
+ v = b->x_coeff[new_index].coeff;
+ x = b->x_coeff[new_index++].x;
+ }
+ }
+
+ /* Save our variables for the next slice. */
+ save_state[0] = new_index;
+
+ return;
+}
+
+static int decode_q_branch(SnowContext *s, int level, int x, int y){
+ const int w= s->b_width << s->block_max_depth;
+ const int rem_depth= s->block_max_depth - level;
+ const int index= (x + y*w) << rem_depth;
+ int trx= (x+1)<<rem_depth;
+ const BlockNode *left = x ? &s->block[index-1] : &null_block;
+ const BlockNode *top = y ? &s->block[index-w] : &null_block;
+ const BlockNode *tl = y && x ? &s->block[index-w-1] : left;
+ const BlockNode *tr = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
+ int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
+ int res;
+
+ if(s->keyframe){
+ set_blocks(s, level, x, y, null_block.color[0], null_block.color[1], null_block.color[2], null_block.mx, null_block.my, null_block.ref, BLOCK_INTRA);
+ return 0;
+ }
+
+ if(level==s->block_max_depth || get_rac(&s->c, &s->block_state[4 + s_context])){
+ int type, mx, my;
+ int l = left->color[0];
+ int cb= left->color[1];
+ int cr= left->color[2];
+ unsigned ref = 0;
+ int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
+ int mx_context= av_log2(2*FFABS(left->mx - top->mx)) + 0*av_log2(2*FFABS(tr->mx - top->mx));
+ int my_context= av_log2(2*FFABS(left->my - top->my)) + 0*av_log2(2*FFABS(tr->my - top->my));
+
+ type= get_rac(&s->c, &s->block_state[1 + left->type + top->type]) ? BLOCK_INTRA : 0;
+
+ if(type){
+ pred_mv(s, &mx, &my, 0, left, top, tr);
+ l += get_symbol(&s->c, &s->block_state[32], 1);
+ if (s->nb_planes > 2) {
+ cb+= get_symbol(&s->c, &s->block_state[64], 1);
+ cr+= get_symbol(&s->c, &s->block_state[96], 1);
+ }
+ }else{
+ if(s->ref_frames > 1)
+ ref= get_symbol(&s->c, &s->block_state[128 + 1024 + 32*ref_context], 0);
+ if (ref >= s->ref_frames) {
+ av_log(s->avctx, AV_LOG_ERROR, "Invalid ref\n");
+ return AVERROR_INVALIDDATA;
+ }
+ pred_mv(s, &mx, &my, ref, left, top, tr);
+ mx+= get_symbol(&s->c, &s->block_state[128 + 32*(mx_context + 16*!!ref)], 1);
+ my+= get_symbol(&s->c, &s->block_state[128 + 32*(my_context + 16*!!ref)], 1);
+ }
+ set_blocks(s, level, x, y, l, cb, cr, mx, my, ref, type);
+ }else{
+ if ((res = decode_q_branch(s, level+1, 2*x+0, 2*y+0)) < 0 ||
+ (res = decode_q_branch(s, level+1, 2*x+1, 2*y+0)) < 0 ||
+ (res = decode_q_branch(s, level+1, 2*x+0, 2*y+1)) < 0 ||
+ (res = decode_q_branch(s, level+1, 2*x+1, 2*y+1)) < 0)
+ return res;
+ }
+ return 0;
+}
+
+static void dequantize_slice_buffered(SnowContext *s, slice_buffer * sb, SubBand *b, IDWTELEM *src, int stride, int start_y, int end_y){
+ const int w= b->width;
+ const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
+ const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
+ const int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
+ int x,y;
+
+ if(s->qlog == LOSSLESS_QLOG) return;
+
+ for(y=start_y; y<end_y; y++){
+// DWTELEM * line = slice_buffer_get_line_from_address(sb, src + (y * stride));
+ IDWTELEM * line = slice_buffer_get_line(sb, (y * b->stride_line) + b->buf_y_offset) + b->buf_x_offset;
+ for(x=0; x<w; x++){
+ int i= line[x];
+ if(i<0){
+ line[x]= -((-i*qmul + qadd)>>(QEXPSHIFT)); //FIXME try different bias
+ }else if(i>0){
+ line[x]= (( i*qmul + qadd)>>(QEXPSHIFT));
+ }
+ }
+ }
+}
+
+static void correlate_slice_buffered(SnowContext *s, slice_buffer * sb, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median, int start_y, int end_y){
+ const int w= b->width;
+ int x,y;
+
+ IDWTELEM * line=0; // silence silly "could be used without having been initialized" warning
+ IDWTELEM * prev;
+
+ if (start_y != 0)
+ line = slice_buffer_get_line(sb, ((start_y - 1) * b->stride_line) + b->buf_y_offset) + b->buf_x_offset;
+
+ for(y=start_y; y<end_y; y++){
+ prev = line;
+// line = slice_buffer_get_line_from_address(sb, src + (y * stride));
+ line = slice_buffer_get_line(sb, (y * b->stride_line) + b->buf_y_offset) + b->buf_x_offset;
+ for(x=0; x<w; x++){
+ if(x){
+ if(use_median){
+ if(y && x+1<w) line[x] += mid_pred(line[x - 1], prev[x], prev[x + 1]);
+ else line[x] += line[x - 1];
+ }else{
+ if(y) line[x] += mid_pred(line[x - 1], prev[x], line[x - 1] + prev[x] - prev[x - 1]);
+ else line[x] += line[x - 1];
+ }
+ }else{
+ if(y) line[x] += prev[x];
+ }
+ }
+ }
+}
+
+static void decode_qlogs(SnowContext *s){
+ int plane_index, level, orientation;
+
+ for(plane_index=0; plane_index < s->nb_planes; plane_index++){
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1:0; orientation<4; orientation++){
+ int q;
+ if (plane_index==2) q= s->plane[1].band[level][orientation].qlog;
+ else if(orientation==2) q= s->plane[plane_index].band[level][1].qlog;
+ else q= get_symbol(&s->c, s->header_state, 1);
+ s->plane[plane_index].band[level][orientation].qlog= q;
+ }
+ }
+ }
+}
+
+#define GET_S(dst, check) \
+ tmp= get_symbol(&s->c, s->header_state, 0);\
+ if(!(check)){\
+ av_log(s->avctx, AV_LOG_ERROR, "Error " #dst " is %d\n", tmp);\
+ return AVERROR_INVALIDDATA;\
+ }\
+ dst= tmp;
+
+static int decode_header(SnowContext *s){
+ int plane_index, tmp;
+ uint8_t kstate[32];
+
+ memset(kstate, MID_STATE, sizeof(kstate));
+
+ s->keyframe= get_rac(&s->c, kstate);
+ if(s->keyframe || s->always_reset){
+ ff_snow_reset_contexts(s);
+ s->spatial_decomposition_type=
+ s->qlog=
+ s->qbias=
+ s->mv_scale=
+ s->block_max_depth= 0;
+ }
+ if(s->keyframe){
+ GET_S(s->version, tmp <= 0U)
+ s->always_reset= get_rac(&s->c, s->header_state);
+ s->temporal_decomposition_type= get_symbol(&s->c, s->header_state, 0);
+ s->temporal_decomposition_count= get_symbol(&s->c, s->header_state, 0);
+ GET_S(s->spatial_decomposition_count, 0 < tmp && tmp <= MAX_DECOMPOSITIONS)
+ s->colorspace_type= get_symbol(&s->c, s->header_state, 0);
+ if (s->colorspace_type == 1) {
+ s->avctx->pix_fmt= AV_PIX_FMT_GRAY8;
+ s->nb_planes = 1;
+ } else if(s->colorspace_type == 0) {
+ s->chroma_h_shift= get_symbol(&s->c, s->header_state, 0);
+ s->chroma_v_shift= get_symbol(&s->c, s->header_state, 0);
+
+ if(s->chroma_h_shift == 1 && s->chroma_v_shift==1){
+ s->avctx->pix_fmt= AV_PIX_FMT_YUV420P;
+ }else if(s->chroma_h_shift == 0 && s->chroma_v_shift==0){
+ s->avctx->pix_fmt= AV_PIX_FMT_YUV444P;
+ }else if(s->chroma_h_shift == 2 && s->chroma_v_shift==2){
+ s->avctx->pix_fmt= AV_PIX_FMT_YUV410P;
+ } else {
+ av_log(s, AV_LOG_ERROR, "unsupported color subsample mode %d %d\n", s->chroma_h_shift, s->chroma_v_shift);
+ s->chroma_h_shift = s->chroma_v_shift = 1;
+ s->avctx->pix_fmt= AV_PIX_FMT_YUV420P;
+ return AVERROR_INVALIDDATA;
+ }
+ s->nb_planes = 3;
+ } else {
+ av_log(s, AV_LOG_ERROR, "unsupported color space\n");
+ s->chroma_h_shift = s->chroma_v_shift = 1;
+ s->avctx->pix_fmt= AV_PIX_FMT_YUV420P;
+ return AVERROR_INVALIDDATA;
+ }
+
+
+ s->spatial_scalability= get_rac(&s->c, s->header_state);
+// s->rate_scalability= get_rac(&s->c, s->header_state);
+ GET_S(s->max_ref_frames, tmp < (unsigned)MAX_REF_FRAMES)
+ s->max_ref_frames++;
+
+ decode_qlogs(s);
+ }
+
+ if(!s->keyframe){
+ if(get_rac(&s->c, s->header_state)){
+ for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
+ int htaps, i, sum=0;
+ Plane *p= &s->plane[plane_index];
+ p->diag_mc= get_rac(&s->c, s->header_state);
+ htaps= get_symbol(&s->c, s->header_state, 0)*2 + 2;
+ if((unsigned)htaps > HTAPS_MAX || htaps==0)
+ return AVERROR_INVALIDDATA;
+ p->htaps= htaps;
+ for(i= htaps/2; i; i--){
+ p->hcoeff[i]= get_symbol(&s->c, s->header_state, 0) * (1-2*(i&1));
+ sum += p->hcoeff[i];
+ }
+ p->hcoeff[0]= 32-sum;
+ }
+ s->plane[2].diag_mc= s->plane[1].diag_mc;
+ s->plane[2].htaps = s->plane[1].htaps;
+ memcpy(s->plane[2].hcoeff, s->plane[1].hcoeff, sizeof(s->plane[1].hcoeff));
+ }
+ if(get_rac(&s->c, s->header_state)){
+ GET_S(s->spatial_decomposition_count, 0 < tmp && tmp <= MAX_DECOMPOSITIONS)
+ decode_qlogs(s);
+ }
+ }
+
+ s->spatial_decomposition_type+= get_symbol(&s->c, s->header_state, 1);
+ if(s->spatial_decomposition_type > 1U){
+ av_log(s->avctx, AV_LOG_ERROR, "spatial_decomposition_type %d not supported\n", s->spatial_decomposition_type);
+ return AVERROR_INVALIDDATA;
+ }
+ if(FFMIN(s->avctx-> width>>s->chroma_h_shift,
+ s->avctx->height>>s->chroma_v_shift) >> (s->spatial_decomposition_count-1) <= 1){
+ av_log(s->avctx, AV_LOG_ERROR, "spatial_decomposition_count %d too large for size\n", s->spatial_decomposition_count);
+ return AVERROR_INVALIDDATA;
+ }
+
+
+ s->qlog += get_symbol(&s->c, s->header_state, 1);
+ s->mv_scale += get_symbol(&s->c, s->header_state, 1);
+ s->qbias += get_symbol(&s->c, s->header_state, 1);
+ s->block_max_depth+= get_symbol(&s->c, s->header_state, 1);
+ if(s->block_max_depth > 1 || s->block_max_depth < 0){
+ av_log(s->avctx, AV_LOG_ERROR, "block_max_depth= %d is too large\n", s->block_max_depth);
+ s->block_max_depth= 0;
+ return AVERROR_INVALIDDATA;
+ }
+
+ return 0;
+}
+
+static av_cold int decode_init(AVCodecContext *avctx)
+{
+ int ret;
+
+ if ((ret = ff_snow_common_init(avctx)) < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int decode_blocks(SnowContext *s){
+ int x, y;
+ int w= s->b_width;
+ int h= s->b_height;
+ int res;
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ if ((res = decode_q_branch(s, 0, x, y)) < 0)
+ return res;
+ }
+ }
+ return 0;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ SnowContext *s = avctx->priv_data;
+ RangeCoder * const c= &s->c;
+ int bytes_read;
+ AVFrame *picture = data;
+ int level, orientation, plane_index;
+ int res;
+
+ ff_init_range_decoder(c, buf, buf_size);
+ ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
+
+ s->current_picture->pict_type= AV_PICTURE_TYPE_I; //FIXME I vs. P
+ if ((res = decode_header(s)) < 0)
+ return res;
+ if ((res=ff_snow_common_init_after_header(avctx)) < 0)
+ return res;
+
+ // realloc slice buffer for the case that spatial_decomposition_count changed
+ ff_slice_buffer_destroy(&s->sb);
+ if ((res = ff_slice_buffer_init(&s->sb, s->plane[0].height,
+ (MB_SIZE >> s->block_max_depth) +
+ s->spatial_decomposition_count * 11 + 1,
+ s->plane[0].width,
+ s->spatial_idwt_buffer)) < 0)
+ return res;
+
+ for(plane_index=0; plane_index < s->nb_planes; plane_index++){
+ Plane *p= &s->plane[plane_index];
+ p->fast_mc= p->diag_mc && p->htaps==6 && p->hcoeff[0]==40
+ && p->hcoeff[1]==-10
+ && p->hcoeff[2]==2;
+ }
+
+ ff_snow_alloc_blocks(s);
+
+ if((res = ff_snow_frame_start(s)) < 0)
+ return res;
+
+ s->current_picture->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+
+ //keyframe flag duplication mess FIXME
+ if(avctx->debug&FF_DEBUG_PICT_INFO)
+ av_log(avctx, AV_LOG_ERROR,
+ "keyframe:%d qlog:%d qbias: %d mvscale: %d "
+ "decomposition_type:%d decomposition_count:%d\n",
+ s->keyframe, s->qlog, s->qbias, s->mv_scale,
+ s->spatial_decomposition_type,
+ s->spatial_decomposition_count
+ );
+
+ av_assert0(!s->avmv);
+ if (s->avctx->flags2 & CODEC_FLAG2_EXPORT_MVS) {
+ s->avmv = av_malloc_array(s->b_width * s->b_height, sizeof(AVMotionVector) << (s->block_max_depth*2));
+ }
+ s->avmv_index = 0;
+
+ if ((res = decode_blocks(s)) < 0)
+ return res;
+
+ for(plane_index=0; plane_index < s->nb_planes; plane_index++){
+ Plane *p= &s->plane[plane_index];
+ int w= p->width;
+ int h= p->height;
+ int x, y;
+ int decode_state[MAX_DECOMPOSITIONS][4][1]; /* Stored state info for unpack_coeffs. 1 variable per instance. */
+
+ if(s->avctx->debug&2048){
+ memset(s->spatial_dwt_buffer, 0, sizeof(DWTELEM)*w*h);
+ predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int v= s->current_picture->data[plane_index][y*s->current_picture->linesize[plane_index] + x];
+ s->mconly_picture->data[plane_index][y*s->mconly_picture->linesize[plane_index] + x]= v;
+ }
+ }
+ }
+
+ {
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+ unpack_coeffs(s, b, b->parent, orientation);
+ }
+ }
+ }
+
+ {
+ const int mb_h= s->b_height << s->block_max_depth;
+ const int block_size = MB_SIZE >> s->block_max_depth;
+ const int block_h = plane_index ? block_size>>s->chroma_v_shift : block_size;
+ int mb_y;
+ DWTCompose cs[MAX_DECOMPOSITIONS];
+ int yd=0, yq=0;
+ int y;
+ int end_y;
+
+ ff_spatial_idwt_buffered_init(cs, &s->sb, w, h, 1, s->spatial_decomposition_type, s->spatial_decomposition_count);
+ for(mb_y=0; mb_y<=mb_h; mb_y++){
+
+ int slice_starty = block_h*mb_y;
+ int slice_h = block_h*(mb_y+1);
+
+ if (!(s->keyframe || s->avctx->debug&512)){
+ slice_starty = FFMAX(0, slice_starty - (block_h >> 1));
+ slice_h -= (block_h >> 1);
+ }
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+ int start_y;
+ int end_y;
+ int our_mb_start = mb_y;
+ int our_mb_end = (mb_y + 1);
+ const int extra= 3;
+ start_y = (mb_y ? ((block_h * our_mb_start) >> (s->spatial_decomposition_count - level)) + s->spatial_decomposition_count - level + extra: 0);
+ end_y = (((block_h * our_mb_end) >> (s->spatial_decomposition_count - level)) + s->spatial_decomposition_count - level + extra);
+ if (!(s->keyframe || s->avctx->debug&512)){
+ start_y = FFMAX(0, start_y - (block_h >> (1+s->spatial_decomposition_count - level)));
+ end_y = FFMAX(0, end_y - (block_h >> (1+s->spatial_decomposition_count - level)));
+ }
+ start_y = FFMIN(b->height, start_y);
+ end_y = FFMIN(b->height, end_y);
+
+ if (start_y != end_y){
+ if (orientation == 0){
+ SubBand * correlate_band = &p->band[0][0];
+ int correlate_end_y = FFMIN(b->height, end_y + 1);
+ int correlate_start_y = FFMIN(b->height, (start_y ? start_y + 1 : 0));
+ decode_subband_slice_buffered(s, correlate_band, &s->sb, correlate_start_y, correlate_end_y, decode_state[0][0]);
+ correlate_slice_buffered(s, &s->sb, correlate_band, correlate_band->ibuf, correlate_band->stride, 1, 0, correlate_start_y, correlate_end_y);
+ dequantize_slice_buffered(s, &s->sb, correlate_band, correlate_band->ibuf, correlate_band->stride, start_y, end_y);
+ }
+ else
+ decode_subband_slice_buffered(s, b, &s->sb, start_y, end_y, decode_state[level][orientation]);
+ }
+ }
+ }
+
+ for(; yd<slice_h; yd+=4){
+ ff_spatial_idwt_buffered_slice(&s->dwt, cs, &s->sb, s->temp_idwt_buffer, w, h, 1, s->spatial_decomposition_type, s->spatial_decomposition_count, yd);
+ }
+
+ if(s->qlog == LOSSLESS_QLOG){
+ for(; yq<slice_h && yq<h; yq++){
+ IDWTELEM * line = slice_buffer_get_line(&s->sb, yq);
+ for(x=0; x<w; x++){
+ line[x] <<= FRAC_BITS;
+ }
+ }
+ }
+
+ predict_slice_buffered(s, &s->sb, s->spatial_idwt_buffer, plane_index, 1, mb_y);
+
+ y = FFMIN(p->height, slice_starty);
+ end_y = FFMIN(p->height, slice_h);
+ while(y < end_y)
+ ff_slice_buffer_release(&s->sb, y++);
+ }
+
+ ff_slice_buffer_flush(&s->sb);
+ }
+
+ }
+
+ emms_c();
+
+ ff_snow_release_buffer(avctx);
+
+ if(!(s->avctx->debug&2048))
+ res = av_frame_ref(picture, s->current_picture);
+ else
+ res = av_frame_ref(picture, s->mconly_picture);
+ if (res >= 0 && s->avmv_index) {
+ AVFrameSideData *sd;
+
+ sd = av_frame_new_side_data(picture, AV_FRAME_DATA_MOTION_VECTORS, s->avmv_index * sizeof(AVMotionVector));
+ if (!sd)
+ return AVERROR(ENOMEM);
+ memcpy(sd->data, s->avmv, s->avmv_index * sizeof(AVMotionVector));
+ }
+
+ av_freep(&s->avmv);
+
+ if (res < 0)
+ return res;
+
+ *got_frame = 1;
+
+ bytes_read= c->bytestream - c->bytestream_start;
+ if(bytes_read ==0) av_log(s->avctx, AV_LOG_ERROR, "error at end of frame\n"); //FIXME
+
+ return bytes_read;
+}
+
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+ SnowContext *s = avctx->priv_data;
+
+ ff_slice_buffer_destroy(&s->sb);
+
+ ff_snow_common_end(s);
+
+ return 0;
+}
+
+AVCodec ff_snow_decoder = {
+ .name = "snow",
+ .long_name = NULL_IF_CONFIG_SMALL("Snow"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_SNOW,
+ .priv_data_size = sizeof(SnowContext),
+ .init = decode_init,
+ .close = decode_end,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c
new file mode 100644
index 0000000000..aab7146714
--- /dev/null
+++ b/libavcodec/snowenc.c
@@ -0,0 +1,2038 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intmath.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "snow_dwt.h"
+#include "snow.h"
+
+#include "rangecoder.h"
+#include "mathops.h"
+
+#include "mpegvideo.h"
+#include "h263.h"
+
+static av_cold int encode_init(AVCodecContext *avctx)
+{
+ SnowContext *s = avctx->priv_data;
+ int plane_index, ret;
+ int i;
+
+ if(avctx->prediction_method == DWT_97
+ && (avctx->flags & CODEC_FLAG_QSCALE)
+ && avctx->global_quality == 0){
+ av_log(avctx, AV_LOG_ERROR, "The 9/7 wavelet is incompatible with lossless mode.\n");
+ return -1;
+ }
+
+ s->spatial_decomposition_type= avctx->prediction_method; //FIXME add decorrelator type r transform_type
+
+ s->mv_scale = (avctx->flags & CODEC_FLAG_QPEL) ? 2 : 4;
+ s->block_max_depth= (avctx->flags & CODEC_FLAG_4MV ) ? 1 : 0;
+
+ for(plane_index=0; plane_index<3; plane_index++){
+ s->plane[plane_index].diag_mc= 1;
+ s->plane[plane_index].htaps= 6;
+ s->plane[plane_index].hcoeff[0]= 40;
+ s->plane[plane_index].hcoeff[1]= -10;
+ s->plane[plane_index].hcoeff[2]= 2;
+ s->plane[plane_index].fast_mc= 1;
+ }
+
+ if ((ret = ff_snow_common_init(avctx)) < 0) {
+ return ret;
+ }
+ ff_mpegvideoencdsp_init(&s->mpvencdsp, avctx);
+
+ ff_snow_alloc_blocks(s);
+
+ s->version=0;
+
+ s->m.avctx = avctx;
+ s->m.bit_rate= avctx->bit_rate;
+
+ s->m.me.temp =
+ s->m.me.scratchpad= av_mallocz_array((avctx->width+64), 2*16*2*sizeof(uint8_t));
+ s->m.me.map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
+ s->m.me.score_map = av_mallocz(ME_MAP_SIZE*sizeof(uint32_t));
+ s->m.obmc_scratchpad= av_mallocz(MB_SIZE*MB_SIZE*12*sizeof(uint32_t));
+ if (!s->m.me.scratchpad || !s->m.me.map || !s->m.me.score_map || !s->m.obmc_scratchpad)
+ return AVERROR(ENOMEM);
+
+ ff_h263_encode_init(&s->m); //mv_penalty
+
+ s->max_ref_frames = FFMAX(FFMIN(avctx->refs, MAX_REF_FRAMES), 1);
+
+ if(avctx->flags&CODEC_FLAG_PASS1){
+ if(!avctx->stats_out)
+ avctx->stats_out = av_mallocz(256);
+
+ if (!avctx->stats_out)
+ return AVERROR(ENOMEM);
+ }
+ if((avctx->flags&CODEC_FLAG_PASS2) || !(avctx->flags&CODEC_FLAG_QSCALE)){
+ if(ff_rate_control_init(&s->m) < 0)
+ return -1;
+ }
+ s->pass1_rc= !(avctx->flags & (CODEC_FLAG_QSCALE|CODEC_FLAG_PASS2));
+
+ switch(avctx->pix_fmt){
+ case AV_PIX_FMT_YUV444P:
+// case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUV420P:
+// case AV_PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUV410P:
+ s->nb_planes = 3;
+ s->colorspace_type= 0;
+ break;
+ case AV_PIX_FMT_GRAY8:
+ s->nb_planes = 1;
+ s->colorspace_type = 1;
+ break;
+/* case AV_PIX_FMT_RGB32:
+ s->colorspace= 1;
+ break;*/
+ default:
+ av_log(avctx, AV_LOG_ERROR, "pixel format not supported\n");
+ return -1;
+ }
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift);
+
+ ff_set_cmp(&s->mecc, s->mecc.me_cmp, s->avctx->me_cmp);
+ ff_set_cmp(&s->mecc, s->mecc.me_sub_cmp, s->avctx->me_sub_cmp);
+
+ s->input_picture = av_frame_alloc();
+ avctx->coded_frame = av_frame_alloc();
+ if (!s->input_picture || !avctx->coded_frame)
+ return AVERROR(ENOMEM);
+
+ if ((ret = ff_snow_get_buffer(s, s->input_picture)) < 0)
+ return ret;
+
+ if(s->avctx->me_method == ME_ITER){
+ int size= s->b_width * s->b_height << 2*s->block_max_depth;
+ for(i=0; i<s->max_ref_frames; i++){
+ s->ref_mvs[i]= av_mallocz_array(size, sizeof(int16_t[2]));
+ s->ref_scores[i]= av_mallocz_array(size, sizeof(uint32_t));
+ if (!s->ref_mvs[i] || !s->ref_scores[i])
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
+
+//near copy & paste from dsputil, FIXME
+static int pix_sum(uint8_t * pix, int line_size, int w, int h)
+{
+ int s, i, j;
+
+ s = 0;
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ s += pix[0];
+ pix ++;
+ }
+ pix += line_size - w;
+ }
+ return s;
+}
+
+//near copy & paste from dsputil, FIXME
+static int pix_norm1(uint8_t * pix, int line_size, int w)
+{
+ int s, i, j;
+ uint32_t *sq = ff_square_tab + 256;
+
+ s = 0;
+ for (i = 0; i < w; i++) {
+ for (j = 0; j < w; j ++) {
+ s += sq[pix[0]];
+ pix ++;
+ }
+ pix += line_size - w;
+ }
+ return s;
+}
+
+static inline int get_penalty_factor(int lambda, int lambda2, int type){
+ switch(type&0xFF){
+ default:
+ case FF_CMP_SAD:
+ return lambda>>FF_LAMBDA_SHIFT;
+ case FF_CMP_DCT:
+ return (3*lambda)>>(FF_LAMBDA_SHIFT+1);
+ case FF_CMP_W53:
+ return (4*lambda)>>(FF_LAMBDA_SHIFT);
+ case FF_CMP_W97:
+ return (2*lambda)>>(FF_LAMBDA_SHIFT);
+ case FF_CMP_SATD:
+ case FF_CMP_DCT264:
+ return (2*lambda)>>FF_LAMBDA_SHIFT;
+ case FF_CMP_RD:
+ case FF_CMP_PSNR:
+ case FF_CMP_SSE:
+ case FF_CMP_NSSE:
+ return lambda2>>FF_LAMBDA_SHIFT;
+ case FF_CMP_BIT:
+ return 1;
+ }
+}
+
+//FIXME copy&paste
+#define P_LEFT P[1]
+#define P_TOP P[2]
+#define P_TOPRIGHT P[3]
+#define P_MEDIAN P[4]
+#define P_MV1 P[9]
+#define FLAG_QPEL 1 //must be 1
+
+static int encode_q_branch(SnowContext *s, int level, int x, int y){
+ uint8_t p_buffer[1024];
+ uint8_t i_buffer[1024];
+ uint8_t p_state[sizeof(s->block_state)];
+ uint8_t i_state[sizeof(s->block_state)];
+ RangeCoder pc, ic;
+ uint8_t *pbbak= s->c.bytestream;
+ uint8_t *pbbak_start= s->c.bytestream_start;
+ int score, score2, iscore, i_len, p_len, block_s, sum, base_bits;
+ const int w= s->b_width << s->block_max_depth;
+ const int h= s->b_height << s->block_max_depth;
+ const int rem_depth= s->block_max_depth - level;
+ const int index= (x + y*w) << rem_depth;
+ const int block_w= 1<<(LOG2_MB_SIZE - level);
+ int trx= (x+1)<<rem_depth;
+ int try= (y+1)<<rem_depth;
+ const BlockNode *left = x ? &s->block[index-1] : &null_block;
+ const BlockNode *top = y ? &s->block[index-w] : &null_block;
+ const BlockNode *right = trx<w ? &s->block[index+1] : &null_block;
+ const BlockNode *bottom= try<h ? &s->block[index+w] : &null_block;
+ const BlockNode *tl = y && x ? &s->block[index-w-1] : left;
+ const BlockNode *tr = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
+ int pl = left->color[0];
+ int pcb= left->color[1];
+ int pcr= left->color[2];
+ int pmx, pmy;
+ int mx=0, my=0;
+ int l,cr,cb;
+ const int stride= s->current_picture->linesize[0];
+ const int uvstride= s->current_picture->linesize[1];
+ uint8_t *current_data[3]= { s->input_picture->data[0] + (x + y* stride)*block_w,
+ s->input_picture->data[1] + ((x*block_w)>>s->chroma_h_shift) + ((y*uvstride*block_w)>>s->chroma_v_shift),
+ s->input_picture->data[2] + ((x*block_w)>>s->chroma_h_shift) + ((y*uvstride*block_w)>>s->chroma_v_shift)};
+ int P[10][2];
+ int16_t last_mv[3][2];
+ int qpel= !!(s->avctx->flags & CODEC_FLAG_QPEL); //unused
+ const int shift= 1+qpel;
+ MotionEstContext *c= &s->m.me;
+ int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
+ int mx_context= av_log2(2*FFABS(left->mx - top->mx));
+ int my_context= av_log2(2*FFABS(left->my - top->my));
+ int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
+ int ref, best_ref, ref_score, ref_mx, ref_my;
+
+ av_assert0(sizeof(s->block_state) >= 256);
+ if(s->keyframe){
+ set_blocks(s, level, x, y, pl, pcb, pcr, 0, 0, 0, BLOCK_INTRA);
+ return 0;
+ }
+
+// clip predictors / edge ?
+
+ P_LEFT[0]= left->mx;
+ P_LEFT[1]= left->my;
+ P_TOP [0]= top->mx;
+ P_TOP [1]= top->my;
+ P_TOPRIGHT[0]= tr->mx;
+ P_TOPRIGHT[1]= tr->my;
+
+ last_mv[0][0]= s->block[index].mx;
+ last_mv[0][1]= s->block[index].my;
+ last_mv[1][0]= right->mx;
+ last_mv[1][1]= right->my;
+ last_mv[2][0]= bottom->mx;
+ last_mv[2][1]= bottom->my;
+
+ s->m.mb_stride=2;
+ s->m.mb_x=
+ s->m.mb_y= 0;
+ c->skip= 0;
+
+ av_assert1(c-> stride == stride);
+ av_assert1(c->uvstride == uvstride);
+
+ c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp);
+ c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp);
+ c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp);
+ c->current_mv_penalty= c->mv_penalty[s->m.f_code=1] + MAX_MV;
+
+ c->xmin = - x*block_w - 16+3;
+ c->ymin = - y*block_w - 16+3;
+ c->xmax = - (x+1)*block_w + (w<<(LOG2_MB_SIZE - s->block_max_depth)) + 16-3;
+ c->ymax = - (y+1)*block_w + (h<<(LOG2_MB_SIZE - s->block_max_depth)) + 16-3;
+
+ if(P_LEFT[0] > (c->xmax<<shift)) P_LEFT[0] = (c->xmax<<shift);
+ if(P_LEFT[1] > (c->ymax<<shift)) P_LEFT[1] = (c->ymax<<shift);
+ if(P_TOP[0] > (c->xmax<<shift)) P_TOP[0] = (c->xmax<<shift);
+ if(P_TOP[1] > (c->ymax<<shift)) P_TOP[1] = (c->ymax<<shift);
+ if(P_TOPRIGHT[0] < (c->xmin<<shift)) P_TOPRIGHT[0]= (c->xmin<<shift);
+ if(P_TOPRIGHT[0] > (c->xmax<<shift)) P_TOPRIGHT[0]= (c->xmax<<shift); //due to pmx no clip
+ if(P_TOPRIGHT[1] > (c->ymax<<shift)) P_TOPRIGHT[1]= (c->ymax<<shift);
+
+ P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]);
+ P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]);
+
+ if (!y) {
+ c->pred_x= P_LEFT[0];
+ c->pred_y= P_LEFT[1];
+ } else {
+ c->pred_x = P_MEDIAN[0];
+ c->pred_y = P_MEDIAN[1];
+ }
+
+ score= INT_MAX;
+ best_ref= 0;
+ for(ref=0; ref<s->ref_frames; ref++){
+ init_ref(c, current_data, s->last_picture[ref]->data, NULL, block_w*x, block_w*y, 0);
+
+ ref_score= ff_epzs_motion_search(&s->m, &ref_mx, &ref_my, P, 0, /*ref_index*/ 0, last_mv,
+ (1<<16)>>shift, level-LOG2_MB_SIZE+4, block_w);
+
+ av_assert2(ref_mx >= c->xmin);
+ av_assert2(ref_mx <= c->xmax);
+ av_assert2(ref_my >= c->ymin);
+ av_assert2(ref_my <= c->ymax);
+
+ ref_score= c->sub_motion_search(&s->m, &ref_mx, &ref_my, ref_score, 0, 0, level-LOG2_MB_SIZE+4, block_w);
+ ref_score= ff_get_mb_score(&s->m, ref_mx, ref_my, 0, 0, level-LOG2_MB_SIZE+4, block_w, 0);
+ ref_score+= 2*av_log2(2*ref)*c->penalty_factor;
+ if(s->ref_mvs[ref]){
+ s->ref_mvs[ref][index][0]= ref_mx;
+ s->ref_mvs[ref][index][1]= ref_my;
+ s->ref_scores[ref][index]= ref_score;
+ }
+ if(score > ref_score){
+ score= ref_score;
+ best_ref= ref;
+ mx= ref_mx;
+ my= ref_my;
+ }
+ }
+ //FIXME if mb_cmp != SSE then intra cannot be compared currently and mb_penalty vs. lambda2
+
+ // subpel search
+ base_bits= get_rac_count(&s->c) - 8*(s->c.bytestream - s->c.bytestream_start);
+ pc= s->c;
+ pc.bytestream_start=
+ pc.bytestream= p_buffer; //FIXME end/start? and at the other stoo
+ memcpy(p_state, s->block_state, sizeof(s->block_state));
+
+ if(level!=s->block_max_depth)
+ put_rac(&pc, &p_state[4 + s_context], 1);
+ put_rac(&pc, &p_state[1 + left->type + top->type], 0);
+ if(s->ref_frames > 1)
+ put_symbol(&pc, &p_state[128 + 1024 + 32*ref_context], best_ref, 0);
+ pred_mv(s, &pmx, &pmy, best_ref, left, top, tr);
+ put_symbol(&pc, &p_state[128 + 32*(mx_context + 16*!!best_ref)], mx - pmx, 1);
+ put_symbol(&pc, &p_state[128 + 32*(my_context + 16*!!best_ref)], my - pmy, 1);
+ p_len= pc.bytestream - pc.bytestream_start;
+ score += (s->lambda2*(get_rac_count(&pc)-base_bits))>>FF_LAMBDA_SHIFT;
+
+ block_s= block_w*block_w;
+ sum = pix_sum(current_data[0], stride, block_w, block_w);
+ l= (sum + block_s/2)/block_s;
+ iscore = pix_norm1(current_data[0], stride, block_w) - 2*l*sum + l*l*block_s;
+
+ if (s->nb_planes > 2) {
+ block_s= block_w*block_w>>(s->chroma_h_shift + s->chroma_v_shift);
+ sum = pix_sum(current_data[1], uvstride, block_w>>s->chroma_h_shift, block_w>>s->chroma_v_shift);
+ cb= (sum + block_s/2)/block_s;
+ // iscore += pix_norm1(&current_mb[1][0], uvstride, block_w>>1) - 2*cb*sum + cb*cb*block_s;
+ sum = pix_sum(current_data[2], uvstride, block_w>>s->chroma_h_shift, block_w>>s->chroma_v_shift);
+ cr= (sum + block_s/2)/block_s;
+ // iscore += pix_norm1(&current_mb[2][0], uvstride, block_w>>1) - 2*cr*sum + cr*cr*block_s;
+ }else
+ cb = cr = 0;
+
+ ic= s->c;
+ ic.bytestream_start=
+ ic.bytestream= i_buffer; //FIXME end/start? and at the other stoo
+ memcpy(i_state, s->block_state, sizeof(s->block_state));
+ if(level!=s->block_max_depth)
+ put_rac(&ic, &i_state[4 + s_context], 1);
+ put_rac(&ic, &i_state[1 + left->type + top->type], 1);
+ put_symbol(&ic, &i_state[32], l-pl , 1);
+ if (s->nb_planes > 2) {
+ put_symbol(&ic, &i_state[64], cb-pcb, 1);
+ put_symbol(&ic, &i_state[96], cr-pcr, 1);
+ }
+ i_len= ic.bytestream - ic.bytestream_start;
+ iscore += (s->lambda2*(get_rac_count(&ic)-base_bits))>>FF_LAMBDA_SHIFT;
+
+ av_assert1(iscore < 255*255*256 + s->lambda2*10);
+ av_assert1(iscore >= 0);
+ av_assert1(l>=0 && l<=255);
+ av_assert1(pl>=0 && pl<=255);
+
+ if(level==0){
+ int varc= iscore >> 8;
+ int vard= score >> 8;
+ if (vard <= 64 || vard < varc)
+ c->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
+ else
+ c->scene_change_score+= s->m.qscale;
+ }
+
+ if(level!=s->block_max_depth){
+ put_rac(&s->c, &s->block_state[4 + s_context], 0);
+ score2 = encode_q_branch(s, level+1, 2*x+0, 2*y+0);
+ score2+= encode_q_branch(s, level+1, 2*x+1, 2*y+0);
+ score2+= encode_q_branch(s, level+1, 2*x+0, 2*y+1);
+ score2+= encode_q_branch(s, level+1, 2*x+1, 2*y+1);
+ score2+= s->lambda2>>FF_LAMBDA_SHIFT; //FIXME exact split overhead
+
+ if(score2 < score && score2 < iscore)
+ return score2;
+ }
+
+ if(iscore < score){
+ pred_mv(s, &pmx, &pmy, 0, left, top, tr);
+ memcpy(pbbak, i_buffer, i_len);
+ s->c= ic;
+ s->c.bytestream_start= pbbak_start;
+ s->c.bytestream= pbbak + i_len;
+ set_blocks(s, level, x, y, l, cb, cr, pmx, pmy, 0, BLOCK_INTRA);
+ memcpy(s->block_state, i_state, sizeof(s->block_state));
+ return iscore;
+ }else{
+ memcpy(pbbak, p_buffer, p_len);
+ s->c= pc;
+ s->c.bytestream_start= pbbak_start;
+ s->c.bytestream= pbbak + p_len;
+ set_blocks(s, level, x, y, pl, pcb, pcr, mx, my, best_ref, 0);
+ memcpy(s->block_state, p_state, sizeof(s->block_state));
+ return score;
+ }
+}
+
+static void encode_q_branch2(SnowContext *s, int level, int x, int y){
+ const int w= s->b_width << s->block_max_depth;
+ const int rem_depth= s->block_max_depth - level;
+ const int index= (x + y*w) << rem_depth;
+ int trx= (x+1)<<rem_depth;
+ BlockNode *b= &s->block[index];
+ const BlockNode *left = x ? &s->block[index-1] : &null_block;
+ const BlockNode *top = y ? &s->block[index-w] : &null_block;
+ const BlockNode *tl = y && x ? &s->block[index-w-1] : left;
+ const BlockNode *tr = y && trx<w && ((x&1)==0 || level==0) ? &s->block[index-w+(1<<rem_depth)] : tl; //FIXME use lt
+ int pl = left->color[0];
+ int pcb= left->color[1];
+ int pcr= left->color[2];
+ int pmx, pmy;
+ int ref_context= av_log2(2*left->ref) + av_log2(2*top->ref);
+ int mx_context= av_log2(2*FFABS(left->mx - top->mx)) + 16*!!b->ref;
+ int my_context= av_log2(2*FFABS(left->my - top->my)) + 16*!!b->ref;
+ int s_context= 2*left->level + 2*top->level + tl->level + tr->level;
+
+ if(s->keyframe){
+ set_blocks(s, level, x, y, pl, pcb, pcr, 0, 0, 0, BLOCK_INTRA);
+ return;
+ }
+
+ if(level!=s->block_max_depth){
+ if(same_block(b,b+1) && same_block(b,b+w) && same_block(b,b+w+1)){
+ put_rac(&s->c, &s->block_state[4 + s_context], 1);
+ }else{
+ put_rac(&s->c, &s->block_state[4 + s_context], 0);
+ encode_q_branch2(s, level+1, 2*x+0, 2*y+0);
+ encode_q_branch2(s, level+1, 2*x+1, 2*y+0);
+ encode_q_branch2(s, level+1, 2*x+0, 2*y+1);
+ encode_q_branch2(s, level+1, 2*x+1, 2*y+1);
+ return;
+ }
+ }
+ if(b->type & BLOCK_INTRA){
+ pred_mv(s, &pmx, &pmy, 0, left, top, tr);
+ put_rac(&s->c, &s->block_state[1 + (left->type&1) + (top->type&1)], 1);
+ put_symbol(&s->c, &s->block_state[32], b->color[0]-pl , 1);
+ if (s->nb_planes > 2) {
+ put_symbol(&s->c, &s->block_state[64], b->color[1]-pcb, 1);
+ put_symbol(&s->c, &s->block_state[96], b->color[2]-pcr, 1);
+ }
+ set_blocks(s, level, x, y, b->color[0], b->color[1], b->color[2], pmx, pmy, 0, BLOCK_INTRA);
+ }else{
+ pred_mv(s, &pmx, &pmy, b->ref, left, top, tr);
+ put_rac(&s->c, &s->block_state[1 + (left->type&1) + (top->type&1)], 0);
+ if(s->ref_frames > 1)
+ put_symbol(&s->c, &s->block_state[128 + 1024 + 32*ref_context], b->ref, 0);
+ put_symbol(&s->c, &s->block_state[128 + 32*mx_context], b->mx - pmx, 1);
+ put_symbol(&s->c, &s->block_state[128 + 32*my_context], b->my - pmy, 1);
+ set_blocks(s, level, x, y, pl, pcb, pcr, b->mx, b->my, b->ref, 0);
+ }
+}
+
+static int get_dc(SnowContext *s, int mb_x, int mb_y, int plane_index){
+ int i, x2, y2;
+ Plane *p= &s->plane[plane_index];
+ const int block_size = MB_SIZE >> s->block_max_depth;
+ const int block_w = plane_index ? block_size>>s->chroma_h_shift : block_size;
+ const int block_h = plane_index ? block_size>>s->chroma_v_shift : block_size;
+ const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+s->chroma_h_shift] : ff_obmc_tab[s->block_max_depth];
+ const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
+ const int ref_stride= s->current_picture->linesize[plane_index];
+ uint8_t *src= s-> input_picture->data[plane_index];
+ IDWTELEM *dst= (IDWTELEM*)s->m.obmc_scratchpad + plane_index*block_size*block_size*4; //FIXME change to unsigned
+ const int b_stride = s->b_width << s->block_max_depth;
+ const int w= p->width;
+ const int h= p->height;
+ int index= mb_x + mb_y*b_stride;
+ BlockNode *b= &s->block[index];
+ BlockNode backup= *b;
+ int ab=0;
+ int aa=0;
+
+ av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc stuff above
+
+ b->type|= BLOCK_INTRA;
+ b->color[plane_index]= 0;
+ memset(dst, 0, obmc_stride*obmc_stride*sizeof(IDWTELEM));
+
+ for(i=0; i<4; i++){
+ int mb_x2= mb_x + (i &1) - 1;
+ int mb_y2= mb_y + (i>>1) - 1;
+ int x= block_w*mb_x2 + block_w/2;
+ int y= block_h*mb_y2 + block_h/2;
+
+ add_yblock(s, 0, NULL, dst + (i&1)*block_w + (i>>1)*obmc_stride*block_h, NULL, obmc,
+ x, y, block_w, block_h, w, h, obmc_stride, ref_stride, obmc_stride, mb_x2, mb_y2, 0, 0, plane_index);
+
+ for(y2= FFMAX(y, 0); y2<FFMIN(h, y+block_h); y2++){
+ for(x2= FFMAX(x, 0); x2<FFMIN(w, x+block_w); x2++){
+ int index= x2-(block_w*mb_x - block_w/2) + (y2-(block_h*mb_y - block_h/2))*obmc_stride;
+ int obmc_v= obmc[index];
+ int d;
+ if(y<0) obmc_v += obmc[index + block_h*obmc_stride];
+ if(x<0) obmc_v += obmc[index + block_w];
+ if(y+block_h>h) obmc_v += obmc[index - block_h*obmc_stride];
+ if(x+block_w>w) obmc_v += obmc[index - block_w];
+ //FIXME precalculate this or simplify it somehow else
+
+ d = -dst[index] + (1<<(FRAC_BITS-1));
+ dst[index] = d;
+ ab += (src[x2 + y2*ref_stride] - (d>>FRAC_BITS)) * obmc_v;
+ aa += obmc_v * obmc_v; //FIXME precalculate this
+ }
+ }
+ }
+ *b= backup;
+
+ return av_clip_uint8( ROUNDED_DIV(ab<<LOG2_OBMC_MAX, aa) ); //FIXME we should not need clipping
+}
+
+static inline int get_block_bits(SnowContext *s, int x, int y, int w){
+ const int b_stride = s->b_width << s->block_max_depth;
+ const int b_height = s->b_height<< s->block_max_depth;
+ int index= x + y*b_stride;
+ const BlockNode *b = &s->block[index];
+ const BlockNode *left = x ? &s->block[index-1] : &null_block;
+ const BlockNode *top = y ? &s->block[index-b_stride] : &null_block;
+ const BlockNode *tl = y && x ? &s->block[index-b_stride-1] : left;
+ const BlockNode *tr = y && x+w<b_stride ? &s->block[index-b_stride+w] : tl;
+ int dmx, dmy;
+// int mx_context= av_log2(2*FFABS(left->mx - top->mx));
+// int my_context= av_log2(2*FFABS(left->my - top->my));
+
+ if(x<0 || x>=b_stride || y>=b_height)
+ return 0;
+/*
+1 0 0
+01X 1-2 1
+001XX 3-6 2-3
+0001XXX 7-14 4-7
+00001XXXX 15-30 8-15
+*/
+//FIXME try accurate rate
+//FIXME intra and inter predictors if surrounding blocks are not the same type
+ if(b->type & BLOCK_INTRA){
+ return 3+2*( av_log2(2*FFABS(left->color[0] - b->color[0]))
+ + av_log2(2*FFABS(left->color[1] - b->color[1]))
+ + av_log2(2*FFABS(left->color[2] - b->color[2])));
+ }else{
+ pred_mv(s, &dmx, &dmy, b->ref, left, top, tr);
+ dmx-= b->mx;
+ dmy-= b->my;
+ return 2*(1 + av_log2(2*FFABS(dmx)) //FIXME kill the 2* can be merged in lambda
+ + av_log2(2*FFABS(dmy))
+ + av_log2(2*b->ref));
+ }
+}
+
+static int get_block_rd(SnowContext *s, int mb_x, int mb_y, int plane_index, uint8_t (*obmc_edged)[MB_SIZE * 2]){
+ Plane *p= &s->plane[plane_index];
+ const int block_size = MB_SIZE >> s->block_max_depth;
+ const int block_w = plane_index ? block_size>>s->chroma_h_shift : block_size;
+ const int block_h = plane_index ? block_size>>s->chroma_v_shift : block_size;
+ const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
+ const int ref_stride= s->current_picture->linesize[plane_index];
+ uint8_t *dst= s->current_picture->data[plane_index];
+ uint8_t *src= s-> input_picture->data[plane_index];
+ IDWTELEM *pred= (IDWTELEM*)s->m.obmc_scratchpad + plane_index*block_size*block_size*4;
+ uint8_t *cur = s->scratchbuf;
+ uint8_t *tmp = s->emu_edge_buffer;
+ const int b_stride = s->b_width << s->block_max_depth;
+ const int b_height = s->b_height<< s->block_max_depth;
+ const int w= p->width;
+ const int h= p->height;
+ int distortion;
+ int rate= 0;
+ const int penalty_factor= get_penalty_factor(s->lambda, s->lambda2, s->avctx->me_cmp);
+ int sx= block_w*mb_x - block_w/2;
+ int sy= block_h*mb_y - block_h/2;
+ int x0= FFMAX(0,-sx);
+ int y0= FFMAX(0,-sy);
+ int x1= FFMIN(block_w*2, w-sx);
+ int y1= FFMIN(block_h*2, h-sy);
+ int i,x,y;
+
+ av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below chckinhg only block_w
+
+ ff_snow_pred_block(s, cur, tmp, ref_stride, sx, sy, block_w*2, block_h*2, &s->block[mb_x + mb_y*b_stride], plane_index, w, h);
+
+ for(y=y0; y<y1; y++){
+ const uint8_t *obmc1= obmc_edged[y];
+ const IDWTELEM *pred1 = pred + y*obmc_stride;
+ uint8_t *cur1 = cur + y*ref_stride;
+ uint8_t *dst1 = dst + sx + (sy+y)*ref_stride;
+ for(x=x0; x<x1; x++){
+#if FRAC_BITS >= LOG2_OBMC_MAX
+ int v = (cur1[x] * obmc1[x]) << (FRAC_BITS - LOG2_OBMC_MAX);
+#else
+ int v = (cur1[x] * obmc1[x] + (1<<(LOG2_OBMC_MAX - FRAC_BITS-1))) >> (LOG2_OBMC_MAX - FRAC_BITS);
+#endif
+ v = (v + pred1[x]) >> FRAC_BITS;
+ if(v&(~255)) v= ~(v>>31);
+ dst1[x] = v;
+ }
+ }
+
+ /* copy the regions where obmc[] = (uint8_t)256 */
+ if(LOG2_OBMC_MAX == 8
+ && (mb_x == 0 || mb_x == b_stride-1)
+ && (mb_y == 0 || mb_y == b_height-1)){
+ if(mb_x == 0)
+ x1 = block_w;
+ else
+ x0 = block_w;
+ if(mb_y == 0)
+ y1 = block_h;
+ else
+ y0 = block_h;
+ for(y=y0; y<y1; y++)
+ memcpy(dst + sx+x0 + (sy+y)*ref_stride, cur + x0 + y*ref_stride, x1-x0);
+ }
+
+ if(block_w==16){
+ /* FIXME rearrange dsputil to fit 32x32 cmp functions */
+ /* FIXME check alignment of the cmp wavelet vs the encoding wavelet */
+ /* FIXME cmps overlap but do not cover the wavelet's whole support.
+ * So improving the score of one block is not strictly guaranteed
+ * to improve the score of the whole frame, thus iterative motion
+ * estimation does not always converge. */
+ if(s->avctx->me_cmp == FF_CMP_W97)
+ distortion = ff_w97_32_c(&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32);
+ else if(s->avctx->me_cmp == FF_CMP_W53)
+ distortion = ff_w53_32_c(&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, 32);
+ else{
+ distortion = 0;
+ for(i=0; i<4; i++){
+ int off = sx+16*(i&1) + (sy+16*(i>>1))*ref_stride;
+ distortion += s->mecc.me_cmp[0](&s->m, src + off, dst + off, ref_stride, 16);
+ }
+ }
+ }else{
+ av_assert2(block_w==8);
+ distortion = s->mecc.me_cmp[0](&s->m, src + sx + sy*ref_stride, dst + sx + sy*ref_stride, ref_stride, block_w*2);
+ }
+
+ if(plane_index==0){
+ for(i=0; i<4; i++){
+/* ..RRr
+ * .RXx.
+ * rxx..
+ */
+ rate += get_block_bits(s, mb_x + (i&1) - (i>>1), mb_y + (i>>1), 1);
+ }
+ if(mb_x == b_stride-2)
+ rate += get_block_bits(s, mb_x + 1, mb_y + 1, 1);
+ }
+ return distortion + rate*penalty_factor;
+}
+
+static int get_4block_rd(SnowContext *s, int mb_x, int mb_y, int plane_index){
+ int i, y2;
+ Plane *p= &s->plane[plane_index];
+ const int block_size = MB_SIZE >> s->block_max_depth;
+ const int block_w = plane_index ? block_size>>s->chroma_h_shift : block_size;
+ const int block_h = plane_index ? block_size>>s->chroma_v_shift : block_size;
+ const uint8_t *obmc = plane_index ? ff_obmc_tab[s->block_max_depth+s->chroma_h_shift] : ff_obmc_tab[s->block_max_depth];
+ const int obmc_stride= plane_index ? (2*block_size)>>s->chroma_h_shift : 2*block_size;
+ const int ref_stride= s->current_picture->linesize[plane_index];
+ uint8_t *dst= s->current_picture->data[plane_index];
+ uint8_t *src= s-> input_picture->data[plane_index];
+ //FIXME zero_dst is const but add_yblock changes dst if add is 0 (this is never the case for dst=zero_dst
+ // const has only been removed from zero_dst to suppress a warning
+ static IDWTELEM zero_dst[4096]; //FIXME
+ const int b_stride = s->b_width << s->block_max_depth;
+ const int w= p->width;
+ const int h= p->height;
+ int distortion= 0;
+ int rate= 0;
+ const int penalty_factor= get_penalty_factor(s->lambda, s->lambda2, s->avctx->me_cmp);
+
+ av_assert2(s->chroma_h_shift == s->chroma_v_shift); //obmc and square assumtions below
+
+ for(i=0; i<9; i++){
+ int mb_x2= mb_x + (i%3) - 1;
+ int mb_y2= mb_y + (i/3) - 1;
+ int x= block_w*mb_x2 + block_w/2;
+ int y= block_h*mb_y2 + block_h/2;
+
+ add_yblock(s, 0, NULL, zero_dst, dst, obmc,
+ x, y, block_w, block_h, w, h, /*dst_stride*/0, ref_stride, obmc_stride, mb_x2, mb_y2, 1, 1, plane_index);
+
+ //FIXME find a cleaner/simpler way to skip the outside stuff
+ for(y2= y; y2<0; y2++)
+ memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, block_w);
+ for(y2= h; y2<y+block_h; y2++)
+ memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, block_w);
+ if(x<0){
+ for(y2= y; y2<y+block_h; y2++)
+ memcpy(dst + x + y2*ref_stride, src + x + y2*ref_stride, -x);
+ }
+ if(x+block_w > w){
+ for(y2= y; y2<y+block_h; y2++)
+ memcpy(dst + w + y2*ref_stride, src + w + y2*ref_stride, x+block_w - w);
+ }
+
+ av_assert1(block_w== 8 || block_w==16);
+ distortion += s->mecc.me_cmp[block_w==8](&s->m, src + x + y*ref_stride, dst + x + y*ref_stride, ref_stride, block_h);
+ }
+
+ if(plane_index==0){
+ BlockNode *b= &s->block[mb_x+mb_y*b_stride];
+ int merged= same_block(b,b+1) && same_block(b,b+b_stride) && same_block(b,b+b_stride+1);
+
+/* ..RRRr
+ * .RXXx.
+ * .RXXx.
+ * rxxx.
+ */
+ if(merged)
+ rate = get_block_bits(s, mb_x, mb_y, 2);
+ for(i=merged?4:0; i<9; i++){
+ static const int dxy[9][2] = {{0,0},{1,0},{0,1},{1,1},{2,0},{2,1},{-1,2},{0,2},{1,2}};
+ rate += get_block_bits(s, mb_x + dxy[i][0], mb_y + dxy[i][1], 1);
+ }
+ }
+ return distortion + rate*penalty_factor;
+}
+
+static int encode_subband_c0run(SnowContext *s, SubBand *b, const IDWTELEM *src, const IDWTELEM *parent, int stride, int orientation){
+ const int w= b->width;
+ const int h= b->height;
+ int x, y;
+
+ if(1){
+ int run=0;
+ int *runs = s->run_buffer;
+ int run_index=0;
+ int max_index;
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int v, p=0;
+ int /*ll=0, */l=0, lt=0, t=0, rt=0;
+ v= src[x + y*stride];
+
+ if(y){
+ t= src[x + (y-1)*stride];
+ if(x){
+ lt= src[x - 1 + (y-1)*stride];
+ }
+ if(x + 1 < w){
+ rt= src[x + 1 + (y-1)*stride];
+ }
+ }
+ if(x){
+ l= src[x - 1 + y*stride];
+ /*if(x > 1){
+ if(orientation==1) ll= src[y + (x-2)*stride];
+ else ll= src[x - 2 + y*stride];
+ }*/
+ }
+ if(parent){
+ int px= x>>1;
+ int py= y>>1;
+ if(px<b->parent->width && py<b->parent->height)
+ p= parent[px + py*2*stride];
+ }
+ if(!(/*ll|*/l|lt|t|rt|p)){
+ if(v){
+ runs[run_index++]= run;
+ run=0;
+ }else{
+ run++;
+ }
+ }
+ }
+ }
+ max_index= run_index;
+ runs[run_index++]= run;
+ run_index=0;
+ run= runs[run_index++];
+
+ put_symbol2(&s->c, b->state[30], max_index, 0);
+ if(run_index <= max_index)
+ put_symbol2(&s->c, b->state[1], run, 3);
+
+ for(y=0; y<h; y++){
+ if(s->c.bytestream_end - s->c.bytestream < w*40){
+ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ return -1;
+ }
+ for(x=0; x<w; x++){
+ int v, p=0;
+ int /*ll=0, */l=0, lt=0, t=0, rt=0;
+ v= src[x + y*stride];
+
+ if(y){
+ t= src[x + (y-1)*stride];
+ if(x){
+ lt= src[x - 1 + (y-1)*stride];
+ }
+ if(x + 1 < w){
+ rt= src[x + 1 + (y-1)*stride];
+ }
+ }
+ if(x){
+ l= src[x - 1 + y*stride];
+ /*if(x > 1){
+ if(orientation==1) ll= src[y + (x-2)*stride];
+ else ll= src[x - 2 + y*stride];
+ }*/
+ }
+ if(parent){
+ int px= x>>1;
+ int py= y>>1;
+ if(px<b->parent->width && py<b->parent->height)
+ p= parent[px + py*2*stride];
+ }
+ if(/*ll|*/l|lt|t|rt|p){
+ int context= av_log2(/*FFABS(ll) + */3*FFABS(l) + FFABS(lt) + 2*FFABS(t) + FFABS(rt) + FFABS(p));
+
+ put_rac(&s->c, &b->state[0][context], !!v);
+ }else{
+ if(!run){
+ run= runs[run_index++];
+
+ if(run_index <= max_index)
+ put_symbol2(&s->c, b->state[1], run, 3);
+ av_assert2(v);
+ }else{
+ run--;
+ av_assert2(!v);
+ }
+ }
+ if(v){
+ int context= av_log2(/*FFABS(ll) + */3*FFABS(l) + FFABS(lt) + 2*FFABS(t) + FFABS(rt) + FFABS(p));
+ int l2= 2*FFABS(l) + (l<0);
+ int t2= 2*FFABS(t) + (t<0);
+
+ put_symbol2(&s->c, b->state[context + 2], FFABS(v)-1, context-4);
+ put_rac(&s->c, &b->state[0][16 + 1 + 3 + ff_quant3bA[l2&0xFF] + 3*ff_quant3bA[t2&0xFF]], v<0);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int encode_subband(SnowContext *s, SubBand *b, const IDWTELEM *src, const IDWTELEM *parent, int stride, int orientation){
+// encode_subband_qtree(s, b, src, parent, stride, orientation);
+// encode_subband_z0run(s, b, src, parent, stride, orientation);
+ return encode_subband_c0run(s, b, src, parent, stride, orientation);
+// encode_subband_dzr(s, b, src, parent, stride, orientation);
+}
+
+static av_always_inline int check_block(SnowContext *s, int mb_x, int mb_y, int p[3], int intra, uint8_t (*obmc_edged)[MB_SIZE * 2], int *best_rd){
+ const int b_stride= s->b_width << s->block_max_depth;
+ BlockNode *block= &s->block[mb_x + mb_y * b_stride];
+ BlockNode backup= *block;
+ unsigned value;
+ int rd, index;
+
+ av_assert2(mb_x>=0 && mb_y>=0);
+ av_assert2(mb_x<b_stride);
+
+ if(intra){
+ block->color[0] = p[0];
+ block->color[1] = p[1];
+ block->color[2] = p[2];
+ block->type |= BLOCK_INTRA;
+ }else{
+ index= (p[0] + 31*p[1]) & (ME_CACHE_SIZE-1);
+ value= s->me_cache_generation + (p[0]>>10) + (p[1]<<6) + (block->ref<<12);
+ if(s->me_cache[index] == value)
+ return 0;
+ s->me_cache[index]= value;
+
+ block->mx= p[0];
+ block->my= p[1];
+ block->type &= ~BLOCK_INTRA;
+ }
+
+ rd= get_block_rd(s, mb_x, mb_y, 0, obmc_edged) + s->intra_penalty * !!intra;
+
+//FIXME chroma
+ if(rd < *best_rd){
+ *best_rd= rd;
+ return 1;
+ }else{
+ *block= backup;
+ return 0;
+ }
+}
+
+/* special case for int[2] args we discard afterwards,
+ * fixes compilation problem with gcc 2.95 */
+static av_always_inline int check_block_inter(SnowContext *s, int mb_x, int mb_y, int p0, int p1, uint8_t (*obmc_edged)[MB_SIZE * 2], int *best_rd){
+ int p[2] = {p0, p1};
+ return check_block(s, mb_x, mb_y, p, 0, obmc_edged, best_rd);
+}
+
+static av_always_inline int check_4block_inter(SnowContext *s, int mb_x, int mb_y, int p0, int p1, int ref, int *best_rd){
+ const int b_stride= s->b_width << s->block_max_depth;
+ BlockNode *block= &s->block[mb_x + mb_y * b_stride];
+ BlockNode backup[4];
+ unsigned value;
+ int rd, index;
+
+ /* We don't initialize backup[] during variable declaration, because
+ * that fails to compile on MSVC: "cannot convert from 'BlockNode' to
+ * 'int16_t'". */
+ backup[0] = block[0];
+ backup[1] = block[1];
+ backup[2] = block[b_stride];
+ backup[3] = block[b_stride + 1];
+
+ av_assert2(mb_x>=0 && mb_y>=0);
+ av_assert2(mb_x<b_stride);
+ av_assert2(((mb_x|mb_y)&1) == 0);
+
+ index= (p0 + 31*p1) & (ME_CACHE_SIZE-1);
+ value= s->me_cache_generation + (p0>>10) + (p1<<6) + (block->ref<<12);
+ if(s->me_cache[index] == value)
+ return 0;
+ s->me_cache[index]= value;
+
+ block->mx= p0;
+ block->my= p1;
+ block->ref= ref;
+ block->type &= ~BLOCK_INTRA;
+ block[1]= block[b_stride]= block[b_stride+1]= *block;
+
+ rd= get_4block_rd(s, mb_x, mb_y, 0);
+
+//FIXME chroma
+ if(rd < *best_rd){
+ *best_rd= rd;
+ return 1;
+ }else{
+ block[0]= backup[0];
+ block[1]= backup[1];
+ block[b_stride]= backup[2];
+ block[b_stride+1]= backup[3];
+ return 0;
+ }
+}
+
+static void iterative_me(SnowContext *s){
+ int pass, mb_x, mb_y;
+ const int b_width = s->b_width << s->block_max_depth;
+ const int b_height= s->b_height << s->block_max_depth;
+ const int b_stride= b_width;
+ int color[3];
+
+ {
+ RangeCoder r = s->c;
+ uint8_t state[sizeof(s->block_state)];
+ memcpy(state, s->block_state, sizeof(s->block_state));
+ for(mb_y= 0; mb_y<s->b_height; mb_y++)
+ for(mb_x= 0; mb_x<s->b_width; mb_x++)
+ encode_q_branch(s, 0, mb_x, mb_y);
+ s->c = r;
+ memcpy(s->block_state, state, sizeof(s->block_state));
+ }
+
+ for(pass=0; pass<25; pass++){
+ int change= 0;
+
+ for(mb_y= 0; mb_y<b_height; mb_y++){
+ for(mb_x= 0; mb_x<b_width; mb_x++){
+ int dia_change, i, j, ref;
+ int best_rd= INT_MAX, ref_rd;
+ BlockNode backup, ref_b;
+ const int index= mb_x + mb_y * b_stride;
+ BlockNode *block= &s->block[index];
+ BlockNode *tb = mb_y ? &s->block[index-b_stride ] : NULL;
+ BlockNode *lb = mb_x ? &s->block[index -1] : NULL;
+ BlockNode *rb = mb_x+1<b_width ? &s->block[index +1] : NULL;
+ BlockNode *bb = mb_y+1<b_height ? &s->block[index+b_stride ] : NULL;
+ BlockNode *tlb= mb_x && mb_y ? &s->block[index-b_stride-1] : NULL;
+ BlockNode *trb= mb_x+1<b_width && mb_y ? &s->block[index-b_stride+1] : NULL;
+ BlockNode *blb= mb_x && mb_y+1<b_height ? &s->block[index+b_stride-1] : NULL;
+ BlockNode *brb= mb_x+1<b_width && mb_y+1<b_height ? &s->block[index+b_stride+1] : NULL;
+ const int b_w= (MB_SIZE >> s->block_max_depth);
+ uint8_t obmc_edged[MB_SIZE * 2][MB_SIZE * 2];
+
+ if(pass && (block->type & BLOCK_OPT))
+ continue;
+ block->type |= BLOCK_OPT;
+
+ backup= *block;
+
+ if(!s->me_cache_generation)
+ memset(s->me_cache, 0, sizeof(s->me_cache));
+ s->me_cache_generation += 1<<22;
+
+ //FIXME precalculate
+ {
+ int x, y;
+ for (y = 0; y < b_w * 2; y++)
+ memcpy(obmc_edged[y], ff_obmc_tab[s->block_max_depth] + y * b_w * 2, b_w * 2);
+ if(mb_x==0)
+ for(y=0; y<b_w*2; y++)
+ memset(obmc_edged[y], obmc_edged[y][0] + obmc_edged[y][b_w-1], b_w);
+ if(mb_x==b_stride-1)
+ for(y=0; y<b_w*2; y++)
+ memset(obmc_edged[y]+b_w, obmc_edged[y][b_w] + obmc_edged[y][b_w*2-1], b_w);
+ if(mb_y==0){
+ for(x=0; x<b_w*2; x++)
+ obmc_edged[0][x] += obmc_edged[b_w-1][x];
+ for(y=1; y<b_w; y++)
+ memcpy(obmc_edged[y], obmc_edged[0], b_w*2);
+ }
+ if(mb_y==b_height-1){
+ for(x=0; x<b_w*2; x++)
+ obmc_edged[b_w*2-1][x] += obmc_edged[b_w][x];
+ for(y=b_w; y<b_w*2-1; y++)
+ memcpy(obmc_edged[y], obmc_edged[b_w*2-1], b_w*2);
+ }
+ }
+
+ //skip stuff outside the picture
+ if(mb_x==0 || mb_y==0 || mb_x==b_width-1 || mb_y==b_height-1){
+ uint8_t *src= s-> input_picture->data[0];
+ uint8_t *dst= s->current_picture->data[0];
+ const int stride= s->current_picture->linesize[0];
+ const int block_w= MB_SIZE >> s->block_max_depth;
+ const int block_h= MB_SIZE >> s->block_max_depth;
+ const int sx= block_w*mb_x - block_w/2;
+ const int sy= block_h*mb_y - block_h/2;
+ const int w= s->plane[0].width;
+ const int h= s->plane[0].height;
+ int y;
+
+ for(y=sy; y<0; y++)
+ memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
+ for(y=h; y<sy+block_h*2; y++)
+ memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
+ if(sx<0){
+ for(y=sy; y<sy+block_h*2; y++)
+ memcpy(dst + sx + y*stride, src + sx + y*stride, -sx);
+ }
+ if(sx+block_w*2 > w){
+ for(y=sy; y<sy+block_h*2; y++)
+ memcpy(dst + w + y*stride, src + w + y*stride, sx+block_w*2 - w);
+ }
+ }
+
+ // intra(black) = neighbors' contribution to the current block
+ for(i=0; i < s->nb_planes; i++)
+ color[i]= get_dc(s, mb_x, mb_y, i);
+
+ // get previous score (cannot be cached due to OBMC)
+ if(pass > 0 && (block->type&BLOCK_INTRA)){
+ int color0[3]= {block->color[0], block->color[1], block->color[2]};
+ check_block(s, mb_x, mb_y, color0, 1, obmc_edged, &best_rd);
+ }else
+ check_block_inter(s, mb_x, mb_y, block->mx, block->my, obmc_edged, &best_rd);
+
+ ref_b= *block;
+ ref_rd= best_rd;
+ for(ref=0; ref < s->ref_frames; ref++){
+ int16_t (*mvr)[2]= &s->ref_mvs[ref][index];
+ if(s->ref_scores[ref][index] > s->ref_scores[ref_b.ref][index]*3/2) //FIXME tune threshold
+ continue;
+ block->ref= ref;
+ best_rd= INT_MAX;
+
+ check_block_inter(s, mb_x, mb_y, mvr[0][0], mvr[0][1], obmc_edged, &best_rd);
+ check_block_inter(s, mb_x, mb_y, 0, 0, obmc_edged, &best_rd);
+ if(tb)
+ check_block_inter(s, mb_x, mb_y, mvr[-b_stride][0], mvr[-b_stride][1], obmc_edged, &best_rd);
+ if(lb)
+ check_block_inter(s, mb_x, mb_y, mvr[-1][0], mvr[-1][1], obmc_edged, &best_rd);
+ if(rb)
+ check_block_inter(s, mb_x, mb_y, mvr[1][0], mvr[1][1], obmc_edged, &best_rd);
+ if(bb)
+ check_block_inter(s, mb_x, mb_y, mvr[b_stride][0], mvr[b_stride][1], obmc_edged, &best_rd);
+
+ /* fullpel ME */
+ //FIXME avoid subpel interpolation / round to nearest integer
+ do{
+ int newx = block->mx;
+ int newy = block->my;
+ dia_change=0;
+ for(i=0; i<FFMAX(s->avctx->dia_size, 1); i++){
+ for(j=0; j<i; j++){
+ dia_change |= check_block_inter(s, mb_x, mb_y, newx+4*(i-j), newy+(4*j), obmc_edged, &best_rd);
+ dia_change |= check_block_inter(s, mb_x, mb_y, newx-4*(i-j), newy-(4*j), obmc_edged, &best_rd);
+ dia_change |= check_block_inter(s, mb_x, mb_y, newx-(4*j), newy+4*(i-j), obmc_edged, &best_rd);
+ dia_change |= check_block_inter(s, mb_x, mb_y, newx+(4*j), newy-4*(i-j), obmc_edged, &best_rd);
+ }
+ }
+ }while(dia_change);
+ /* subpel ME */
+ do{
+ static const int square[8][2]= {{+1, 0},{-1, 0},{ 0,+1},{ 0,-1},{+1,+1},{-1,-1},{+1,-1},{-1,+1},};
+ dia_change=0;
+ for(i=0; i<8; i++)
+ dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+square[i][0], block->my+square[i][1], obmc_edged, &best_rd);
+ }while(dia_change);
+ //FIXME or try the standard 2 pass qpel or similar
+
+ mvr[0][0]= block->mx;
+ mvr[0][1]= block->my;
+ if(ref_rd > best_rd){
+ ref_rd= best_rd;
+ ref_b= *block;
+ }
+ }
+ best_rd= ref_rd;
+ *block= ref_b;
+ check_block(s, mb_x, mb_y, color, 1, obmc_edged, &best_rd);
+ //FIXME RD style color selection
+ if(!same_block(block, &backup)){
+ if(tb ) tb ->type &= ~BLOCK_OPT;
+ if(lb ) lb ->type &= ~BLOCK_OPT;
+ if(rb ) rb ->type &= ~BLOCK_OPT;
+ if(bb ) bb ->type &= ~BLOCK_OPT;
+ if(tlb) tlb->type &= ~BLOCK_OPT;
+ if(trb) trb->type &= ~BLOCK_OPT;
+ if(blb) blb->type &= ~BLOCK_OPT;
+ if(brb) brb->type &= ~BLOCK_OPT;
+ change ++;
+ }
+ }
+ }
+ av_log(s->avctx, AV_LOG_DEBUG, "pass:%d changed:%d\n", pass, change);
+ if(!change)
+ break;
+ }
+
+ if(s->block_max_depth == 1){
+ int change= 0;
+ for(mb_y= 0; mb_y<b_height; mb_y+=2){
+ for(mb_x= 0; mb_x<b_width; mb_x+=2){
+ int i;
+ int best_rd, init_rd;
+ const int index= mb_x + mb_y * b_stride;
+ BlockNode *b[4];
+
+ b[0]= &s->block[index];
+ b[1]= b[0]+1;
+ b[2]= b[0]+b_stride;
+ b[3]= b[2]+1;
+ if(same_block(b[0], b[1]) &&
+ same_block(b[0], b[2]) &&
+ same_block(b[0], b[3]))
+ continue;
+
+ if(!s->me_cache_generation)
+ memset(s->me_cache, 0, sizeof(s->me_cache));
+ s->me_cache_generation += 1<<22;
+
+ init_rd= best_rd= get_4block_rd(s, mb_x, mb_y, 0);
+
+ //FIXME more multiref search?
+ check_4block_inter(s, mb_x, mb_y,
+ (b[0]->mx + b[1]->mx + b[2]->mx + b[3]->mx + 2) >> 2,
+ (b[0]->my + b[1]->my + b[2]->my + b[3]->my + 2) >> 2, 0, &best_rd);
+
+ for(i=0; i<4; i++)
+ if(!(b[i]->type&BLOCK_INTRA))
+ check_4block_inter(s, mb_x, mb_y, b[i]->mx, b[i]->my, b[i]->ref, &best_rd);
+
+ if(init_rd != best_rd)
+ change++;
+ }
+ }
+ av_log(s->avctx, AV_LOG_ERROR, "pass:4mv changed:%d\n", change*4);
+ }
+}
+
+static void encode_blocks(SnowContext *s, int search){
+ int x, y;
+ int w= s->b_width;
+ int h= s->b_height;
+
+ if(s->avctx->me_method == ME_ITER && !s->keyframe && search)
+ iterative_me(s);
+
+ for(y=0; y<h; y++){
+ if(s->c.bytestream_end - s->c.bytestream < w*MB_SIZE*MB_SIZE*3){ //FIXME nicer limit
+ av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ return;
+ }
+ for(x=0; x<w; x++){
+ if(s->avctx->me_method == ME_ITER || !search)
+ encode_q_branch2(s, 0, x, y);
+ else
+ encode_q_branch (s, 0, x, y);
+ }
+ }
+}
+
+static void quantize(SnowContext *s, SubBand *b, IDWTELEM *dst, DWTELEM *src, int stride, int bias){
+ const int w= b->width;
+ const int h= b->height;
+ const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
+ const int qmul= ff_qexp[qlog&(QROOT-1)]<<((qlog>>QSHIFT) + ENCODER_EXTRA_BITS);
+ int x,y, thres1, thres2;
+
+ if(s->qlog == LOSSLESS_QLOG){
+ for(y=0; y<h; y++)
+ for(x=0; x<w; x++)
+ dst[x + y*stride]= src[x + y*stride];
+ return;
+ }
+
+ bias= bias ? 0 : (3*qmul)>>3;
+ thres1= ((qmul - bias)>>QEXPSHIFT) - 1;
+ thres2= 2*thres1;
+
+ if(!bias){
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= src[x + y*stride];
+
+ if((unsigned)(i+thres1) > thres2){
+ if(i>=0){
+ i<<= QEXPSHIFT;
+ i/= qmul; //FIXME optimize
+ dst[x + y*stride]= i;
+ }else{
+ i= -i;
+ i<<= QEXPSHIFT;
+ i/= qmul; //FIXME optimize
+ dst[x + y*stride]= -i;
+ }
+ }else
+ dst[x + y*stride]= 0;
+ }
+ }
+ }else{
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= src[x + y*stride];
+
+ if((unsigned)(i+thres1) > thres2){
+ if(i>=0){
+ i<<= QEXPSHIFT;
+ i= (i + bias) / qmul; //FIXME optimize
+ dst[x + y*stride]= i;
+ }else{
+ i= -i;
+ i<<= QEXPSHIFT;
+ i= (i + bias) / qmul; //FIXME optimize
+ dst[x + y*stride]= -i;
+ }
+ }else
+ dst[x + y*stride]= 0;
+ }
+ }
+ }
+}
+
+static void dequantize(SnowContext *s, SubBand *b, IDWTELEM *src, int stride){
+ const int w= b->width;
+ const int h= b->height;
+ const int qlog= av_clip(s->qlog + b->qlog, 0, QROOT*16);
+ const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
+ const int qadd= (s->qbias*qmul)>>QBIAS_SHIFT;
+ int x,y;
+
+ if(s->qlog == LOSSLESS_QLOG) return;
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= src[x + y*stride];
+ if(i<0){
+ src[x + y*stride]= -((-i*qmul + qadd)>>(QEXPSHIFT)); //FIXME try different bias
+ }else if(i>0){
+ src[x + y*stride]= (( i*qmul + qadd)>>(QEXPSHIFT));
+ }
+ }
+ }
+}
+
+static void decorrelate(SnowContext *s, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median){
+ const int w= b->width;
+ const int h= b->height;
+ int x,y;
+
+ for(y=h-1; y>=0; y--){
+ for(x=w-1; x>=0; x--){
+ int i= x + y*stride;
+
+ if(x){
+ if(use_median){
+ if(y && x+1<w) src[i] -= mid_pred(src[i - 1], src[i - stride], src[i - stride + 1]);
+ else src[i] -= src[i - 1];
+ }else{
+ if(y) src[i] -= mid_pred(src[i - 1], src[i - stride], src[i - 1] + src[i - stride] - src[i - 1 - stride]);
+ else src[i] -= src[i - 1];
+ }
+ }else{
+ if(y) src[i] -= src[i - stride];
+ }
+ }
+ }
+}
+
+static void correlate(SnowContext *s, SubBand *b, IDWTELEM *src, int stride, int inverse, int use_median){
+ const int w= b->width;
+ const int h= b->height;
+ int x,y;
+
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int i= x + y*stride;
+
+ if(x){
+ if(use_median){
+ if(y && x+1<w) src[i] += mid_pred(src[i - 1], src[i - stride], src[i - stride + 1]);
+ else src[i] += src[i - 1];
+ }else{
+ if(y) src[i] += mid_pred(src[i - 1], src[i - stride], src[i - 1] + src[i - stride] - src[i - 1 - stride]);
+ else src[i] += src[i - 1];
+ }
+ }else{
+ if(y) src[i] += src[i - stride];
+ }
+ }
+ }
+}
+
+static void encode_qlogs(SnowContext *s){
+ int plane_index, level, orientation;
+
+ for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1:0; orientation<4; orientation++){
+ if(orientation==2) continue;
+ put_symbol(&s->c, s->header_state, s->plane[plane_index].band[level][orientation].qlog, 1);
+ }
+ }
+ }
+}
+
+static void encode_header(SnowContext *s){
+ int plane_index, i;
+ uint8_t kstate[32];
+
+ memset(kstate, MID_STATE, sizeof(kstate));
+
+ put_rac(&s->c, kstate, s->keyframe);
+ if(s->keyframe || s->always_reset){
+ ff_snow_reset_contexts(s);
+ s->last_spatial_decomposition_type=
+ s->last_qlog=
+ s->last_qbias=
+ s->last_mv_scale=
+ s->last_block_max_depth= 0;
+ for(plane_index=0; plane_index<2; plane_index++){
+ Plane *p= &s->plane[plane_index];
+ p->last_htaps=0;
+ p->last_diag_mc=0;
+ memset(p->last_hcoeff, 0, sizeof(p->last_hcoeff));
+ }
+ }
+ if(s->keyframe){
+ put_symbol(&s->c, s->header_state, s->version, 0);
+ put_rac(&s->c, s->header_state, s->always_reset);
+ put_symbol(&s->c, s->header_state, s->temporal_decomposition_type, 0);
+ put_symbol(&s->c, s->header_state, s->temporal_decomposition_count, 0);
+ put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0);
+ put_symbol(&s->c, s->header_state, s->colorspace_type, 0);
+ if (s->nb_planes > 2) {
+ put_symbol(&s->c, s->header_state, s->chroma_h_shift, 0);
+ put_symbol(&s->c, s->header_state, s->chroma_v_shift, 0);
+ }
+ put_rac(&s->c, s->header_state, s->spatial_scalability);
+// put_rac(&s->c, s->header_state, s->rate_scalability);
+ put_symbol(&s->c, s->header_state, s->max_ref_frames-1, 0);
+
+ encode_qlogs(s);
+ }
+
+ if(!s->keyframe){
+ int update_mc=0;
+ for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
+ Plane *p= &s->plane[plane_index];
+ update_mc |= p->last_htaps != p->htaps;
+ update_mc |= p->last_diag_mc != p->diag_mc;
+ update_mc |= !!memcmp(p->last_hcoeff, p->hcoeff, sizeof(p->hcoeff));
+ }
+ put_rac(&s->c, s->header_state, update_mc);
+ if(update_mc){
+ for(plane_index=0; plane_index<FFMIN(s->nb_planes, 2); plane_index++){
+ Plane *p= &s->plane[plane_index];
+ put_rac(&s->c, s->header_state, p->diag_mc);
+ put_symbol(&s->c, s->header_state, p->htaps/2-1, 0);
+ for(i= p->htaps/2; i; i--)
+ put_symbol(&s->c, s->header_state, FFABS(p->hcoeff[i]), 0);
+ }
+ }
+ if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){
+ put_rac(&s->c, s->header_state, 1);
+ put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0);
+ encode_qlogs(s);
+ }else
+ put_rac(&s->c, s->header_state, 0);
+ }
+
+ put_symbol(&s->c, s->header_state, s->spatial_decomposition_type - s->last_spatial_decomposition_type, 1);
+ put_symbol(&s->c, s->header_state, s->qlog - s->last_qlog , 1);
+ put_symbol(&s->c, s->header_state, s->mv_scale - s->last_mv_scale, 1);
+ put_symbol(&s->c, s->header_state, s->qbias - s->last_qbias , 1);
+ put_symbol(&s->c, s->header_state, s->block_max_depth - s->last_block_max_depth, 1);
+
+}
+
+static void update_last_header_values(SnowContext *s){
+ int plane_index;
+
+ if(!s->keyframe){
+ for(plane_index=0; plane_index<2; plane_index++){
+ Plane *p= &s->plane[plane_index];
+ p->last_diag_mc= p->diag_mc;
+ p->last_htaps = p->htaps;
+ memcpy(p->last_hcoeff, p->hcoeff, sizeof(p->hcoeff));
+ }
+ }
+
+ s->last_spatial_decomposition_type = s->spatial_decomposition_type;
+ s->last_qlog = s->qlog;
+ s->last_qbias = s->qbias;
+ s->last_mv_scale = s->mv_scale;
+ s->last_block_max_depth = s->block_max_depth;
+ s->last_spatial_decomposition_count = s->spatial_decomposition_count;
+}
+
+static int qscale2qlog(int qscale){
+ return rint(QROOT*log2(qscale / (float)FF_QP2LAMBDA))
+ + 61*QROOT/8; ///< 64 > 60
+}
+
+static int ratecontrol_1pass(SnowContext *s, AVFrame *pict)
+{
+ /* Estimate the frame's complexity as a sum of weighted dwt coefficients.
+ * FIXME we know exact mv bits at this point,
+ * but ratecontrol isn't set up to include them. */
+ uint32_t coef_sum= 0;
+ int level, orientation, delta_qlog;
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &s->plane[0].band[level][orientation];
+ IDWTELEM *buf= b->ibuf;
+ const int w= b->width;
+ const int h= b->height;
+ const int stride= b->stride;
+ const int qlog= av_clip(2*QROOT + b->qlog, 0, QROOT*16);
+ const int qmul= ff_qexp[qlog&(QROOT-1)]<<(qlog>>QSHIFT);
+ const int qdiv= (1<<16)/qmul;
+ int x, y;
+ //FIXME this is ugly
+ for(y=0; y<h; y++)
+ for(x=0; x<w; x++)
+ buf[x+y*stride]= b->buf[x+y*stride];
+ if(orientation==0)
+ decorrelate(s, b, buf, stride, 1, 0);
+ for(y=0; y<h; y++)
+ for(x=0; x<w; x++)
+ coef_sum+= abs(buf[x+y*stride]) * qdiv >> 16;
+ }
+ }
+
+ /* ugly, ratecontrol just takes a sqrt again */
+ av_assert0(coef_sum < INT_MAX);
+ coef_sum = (uint64_t)coef_sum * coef_sum >> 16;
+
+ if(pict->pict_type == AV_PICTURE_TYPE_I){
+ s->m.current_picture.mb_var_sum= coef_sum;
+ s->m.current_picture.mc_mb_var_sum= 0;
+ }else{
+ s->m.current_picture.mc_mb_var_sum= coef_sum;
+ s->m.current_picture.mb_var_sum= 0;
+ }
+
+ pict->quality= ff_rate_estimate_qscale(&s->m, 1);
+ if (pict->quality < 0)
+ return INT_MIN;
+ s->lambda= pict->quality * 3/2;
+ delta_qlog= qscale2qlog(pict->quality) - s->qlog;
+ s->qlog+= delta_qlog;
+ return delta_qlog;
+}
+
+static void calculate_visual_weight(SnowContext *s, Plane *p){
+ int width = p->width;
+ int height= p->height;
+ int level, orientation, x, y;
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+ IDWTELEM *ibuf= b->ibuf;
+ int64_t error=0;
+
+ memset(s->spatial_idwt_buffer, 0, sizeof(*s->spatial_idwt_buffer)*width*height);
+ ibuf[b->width/2 + b->height/2*b->stride]= 256*16;
+ ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, width, height, width, s->spatial_decomposition_type, s->spatial_decomposition_count);
+ for(y=0; y<height; y++){
+ for(x=0; x<width; x++){
+ int64_t d= s->spatial_idwt_buffer[x + y*width]*16;
+ error += d*d;
+ }
+ }
+
+ b->qlog= (int)(log(352256.0/sqrt(error)) / log(pow(2.0, 1.0/QROOT))+0.5);
+ }
+ }
+}
+
+static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pict, int *got_packet)
+{
+ SnowContext *s = avctx->priv_data;
+ RangeCoder * const c= &s->c;
+ AVFrame *pic = pict;
+ const int width= s->avctx->width;
+ const int height= s->avctx->height;
+ int level, orientation, plane_index, i, y, ret;
+ uint8_t rc_header_bak[sizeof(s->header_state)];
+ uint8_t rc_block_bak[sizeof(s->block_state)];
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, s->b_width*s->b_height*MB_SIZE*MB_SIZE*3 + FF_MIN_BUFFER_SIZE)) < 0)
+ return ret;
+
+ ff_init_range_encoder(c, pkt->data, pkt->size);
+ ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
+
+ for(i=0; i < s->nb_planes; i++){
+ int hshift= i ? s->chroma_h_shift : 0;
+ int vshift= i ? s->chroma_v_shift : 0;
+ for(y=0; y<FF_CEIL_RSHIFT(height, vshift); y++)
+ memcpy(&s->input_picture->data[i][y * s->input_picture->linesize[i]],
+ &pict->data[i][y * pict->linesize[i]],
+ FF_CEIL_RSHIFT(width, hshift));
+ s->mpvencdsp.draw_edges(s->input_picture->data[i], s->input_picture->linesize[i],
+ FF_CEIL_RSHIFT(width, hshift), FF_CEIL_RSHIFT(height, vshift),
+ EDGE_WIDTH >> hshift, EDGE_WIDTH >> vshift,
+ EDGE_TOP | EDGE_BOTTOM);
+
+ }
+ emms_c();
+ s->new_picture = pict;
+
+ s->m.picture_number= avctx->frame_number;
+ if(avctx->flags&CODEC_FLAG_PASS2){
+ s->m.pict_type = pic->pict_type = s->m.rc_context.entry[avctx->frame_number].new_pict_type;
+ s->keyframe = pic->pict_type == AV_PICTURE_TYPE_I;
+ if(!(avctx->flags&CODEC_FLAG_QSCALE)) {
+ pic->quality = ff_rate_estimate_qscale(&s->m, 0);
+ if (pic->quality < 0)
+ return -1;
+ }
+ }else{
+ s->keyframe= avctx->gop_size==0 || avctx->frame_number % avctx->gop_size == 0;
+ s->m.pict_type = pic->pict_type = s->keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+ }
+
+ if(s->pass1_rc && avctx->frame_number == 0)
+ pic->quality = 2*FF_QP2LAMBDA;
+ if (pic->quality) {
+ s->qlog = qscale2qlog(pic->quality);
+ s->lambda = pic->quality * 3/2;
+ }
+ if (s->qlog < 0 || (!pic->quality && (avctx->flags & CODEC_FLAG_QSCALE))) {
+ s->qlog= LOSSLESS_QLOG;
+ s->lambda = 0;
+ }//else keep previous frame's qlog until after motion estimation
+
+ if (s->current_picture->data[0] && !(s->avctx->flags&CODEC_FLAG_EMU_EDGE)) {
+ int w = s->avctx->width;
+ int h = s->avctx->height;
+
+ s->mpvencdsp.draw_edges(s->current_picture->data[0],
+ s->current_picture->linesize[0], w , h ,
+ EDGE_WIDTH , EDGE_WIDTH , EDGE_TOP | EDGE_BOTTOM);
+ if (s->current_picture->data[2]) {
+ s->mpvencdsp.draw_edges(s->current_picture->data[1],
+ s->current_picture->linesize[1], w>>s->chroma_h_shift, h>>s->chroma_v_shift,
+ EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM);
+ s->mpvencdsp.draw_edges(s->current_picture->data[2],
+ s->current_picture->linesize[2], w>>s->chroma_h_shift, h>>s->chroma_v_shift,
+ EDGE_WIDTH>>s->chroma_h_shift, EDGE_WIDTH>>s->chroma_v_shift, EDGE_TOP | EDGE_BOTTOM);
+ }
+ }
+
+ ff_snow_frame_start(s);
+ av_frame_unref(avctx->coded_frame);
+ ret = av_frame_ref(avctx->coded_frame, s->current_picture);
+ if (ret < 0)
+ return ret;
+
+ s->m.current_picture_ptr= &s->m.current_picture;
+ s->m.current_picture.f = s->current_picture;
+ s->m.current_picture.f->pts = pict->pts;
+ if(pic->pict_type == AV_PICTURE_TYPE_P){
+ int block_width = (width +15)>>4;
+ int block_height= (height+15)>>4;
+ int stride= s->current_picture->linesize[0];
+
+ av_assert0(s->current_picture->data[0]);
+ av_assert0(s->last_picture[0]->data[0]);
+
+ s->m.avctx= s->avctx;
+ s->m. last_picture.f = s->last_picture[0];
+ s->m. new_picture.f = s->input_picture;
+ s->m. last_picture_ptr= &s->m. last_picture;
+ s->m.linesize = stride;
+ s->m.uvlinesize= s->current_picture->linesize[1];
+ s->m.width = width;
+ s->m.height= height;
+ s->m.mb_width = block_width;
+ s->m.mb_height= block_height;
+ s->m.mb_stride= s->m.mb_width+1;
+ s->m.b8_stride= 2*s->m.mb_width+1;
+ s->m.f_code=1;
+ s->m.pict_type = pic->pict_type;
+ s->m.me_method= s->avctx->me_method;
+ s->m.me.scene_change_score=0;
+ s->m.me.dia_size = avctx->dia_size;
+ s->m.quarter_sample= (s->avctx->flags & CODEC_FLAG_QPEL)!=0;
+ s->m.out_format= FMT_H263;
+ s->m.unrestricted_mv= 1;
+
+ s->m.lambda = s->lambda;
+ s->m.qscale= (s->m.lambda*139 + FF_LAMBDA_SCALE*64) >> (FF_LAMBDA_SHIFT + 7);
+ s->lambda2= s->m.lambda2= (s->m.lambda*s->m.lambda + FF_LAMBDA_SCALE/2) >> FF_LAMBDA_SHIFT;
+
+ s->m.mecc= s->mecc; //move
+ s->m.qdsp= s->qdsp; //move
+ s->m.hdsp = s->hdsp;
+ ff_init_me(&s->m);
+ s->hdsp = s->m.hdsp;
+ s->mecc= s->m.mecc;
+ }
+
+ if(s->pass1_rc){
+ memcpy(rc_header_bak, s->header_state, sizeof(s->header_state));
+ memcpy(rc_block_bak, s->block_state, sizeof(s->block_state));
+ }
+
+redo_frame:
+
+ s->spatial_decomposition_count= 5;
+
+ while( !(width >>(s->chroma_h_shift + s->spatial_decomposition_count))
+ || !(height>>(s->chroma_v_shift + s->spatial_decomposition_count)))
+ s->spatial_decomposition_count--;
+
+ if (s->spatial_decomposition_count <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Resolution too low\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->m.pict_type = pic->pict_type;
+ s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0;
+
+ ff_snow_common_init_after_header(avctx);
+
+ if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){
+ for(plane_index=0; plane_index < s->nb_planes; plane_index++){
+ calculate_visual_weight(s, &s->plane[plane_index]);
+ }
+ }
+
+ encode_header(s);
+ s->m.misc_bits = 8*(s->c.bytestream - s->c.bytestream_start);
+ encode_blocks(s, 1);
+ s->m.mv_bits = 8*(s->c.bytestream - s->c.bytestream_start) - s->m.misc_bits;
+
+ for(plane_index=0; plane_index < s->nb_planes; plane_index++){
+ Plane *p= &s->plane[plane_index];
+ int w= p->width;
+ int h= p->height;
+ int x, y;
+// int bits= put_bits_count(&s->c.pb);
+
+ if (!s->memc_only) {
+ //FIXME optimize
+ if(pict->data[plane_index]) //FIXME gray hack
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ s->spatial_idwt_buffer[y*w + x]= pict->data[plane_index][y*pict->linesize[plane_index] + x]<<FRAC_BITS;
+ }
+ }
+ predict_plane(s, s->spatial_idwt_buffer, plane_index, 0);
+
+ if( plane_index==0
+ && pic->pict_type == AV_PICTURE_TYPE_P
+ && !(avctx->flags&CODEC_FLAG_PASS2)
+ && s->m.me.scene_change_score > s->avctx->scenechange_threshold){
+ ff_init_range_encoder(c, pkt->data, pkt->size);
+ ff_build_rac_states(c, 0.05*(1LL<<32), 256-8);
+ pic->pict_type= AV_PICTURE_TYPE_I;
+ s->keyframe=1;
+ s->current_picture->key_frame=1;
+ goto redo_frame;
+ }
+
+ if(s->qlog == LOSSLESS_QLOG){
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ s->spatial_dwt_buffer[y*w + x]= (s->spatial_idwt_buffer[y*w + x] + (1<<(FRAC_BITS-1))-1)>>FRAC_BITS;
+ }
+ }
+ }else{
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ s->spatial_dwt_buffer[y*w + x]=s->spatial_idwt_buffer[y*w + x]<<ENCODER_EXTRA_BITS;
+ }
+ }
+ }
+
+ ff_spatial_dwt(s->spatial_dwt_buffer, s->temp_dwt_buffer, w, h, w, s->spatial_decomposition_type, s->spatial_decomposition_count);
+
+ if(s->pass1_rc && plane_index==0){
+ int delta_qlog = ratecontrol_1pass(s, pic);
+ if (delta_qlog <= INT_MIN)
+ return -1;
+ if(delta_qlog){
+ //reordering qlog in the bitstream would eliminate this reset
+ ff_init_range_encoder(c, pkt->data, pkt->size);
+ memcpy(s->header_state, rc_header_bak, sizeof(s->header_state));
+ memcpy(s->block_state, rc_block_bak, sizeof(s->block_state));
+ encode_header(s);
+ encode_blocks(s, 0);
+ }
+ }
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+
+ quantize(s, b, b->ibuf, b->buf, b->stride, s->qbias);
+ if(orientation==0)
+ decorrelate(s, b, b->ibuf, b->stride, pic->pict_type == AV_PICTURE_TYPE_P, 0);
+ if (!s->no_bitstream)
+ encode_subband(s, b, b->ibuf, b->parent ? b->parent->ibuf : NULL, b->stride, orientation);
+ av_assert0(b->parent==NULL || b->parent->stride == b->stride*2);
+ if(orientation==0)
+ correlate(s, b, b->ibuf, b->stride, 1, 0);
+ }
+ }
+
+ for(level=0; level<s->spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ SubBand *b= &p->band[level][orientation];
+
+ dequantize(s, b, b->ibuf, b->stride);
+ }
+ }
+
+ ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, w, h, w, s->spatial_decomposition_type, s->spatial_decomposition_count);
+ if(s->qlog == LOSSLESS_QLOG){
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ s->spatial_idwt_buffer[y*w + x]<<=FRAC_BITS;
+ }
+ }
+ }
+ predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
+ }else{
+ //ME/MC only
+ if(pic->pict_type == AV_PICTURE_TYPE_I){
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ s->current_picture->data[plane_index][y*s->current_picture->linesize[plane_index] + x]=
+ pict->data[plane_index][y*pict->linesize[plane_index] + x];
+ }
+ }
+ }else{
+ memset(s->spatial_idwt_buffer, 0, sizeof(IDWTELEM)*w*h);
+ predict_plane(s, s->spatial_idwt_buffer, plane_index, 1);
+ }
+ }
+ if(s->avctx->flags&CODEC_FLAG_PSNR){
+ int64_t error= 0;
+
+ if(pict->data[plane_index]) //FIXME gray hack
+ for(y=0; y<h; y++){
+ for(x=0; x<w; x++){
+ int d= s->current_picture->data[plane_index][y*s->current_picture->linesize[plane_index] + x] - pict->data[plane_index][y*pict->linesize[plane_index] + x];
+ error += d*d;
+ }
+ }
+ s->avctx->error[plane_index] += error;
+ s->current_picture->error[plane_index] = error;
+ }
+
+ }
+
+ update_last_header_values(s);
+
+ ff_snow_release_buffer(avctx);
+
+ s->current_picture->coded_picture_number = avctx->frame_number;
+ s->current_picture->pict_type = pict->pict_type;
+ s->current_picture->quality = pict->quality;
+ s->m.frame_bits = 8*(s->c.bytestream - s->c.bytestream_start);
+ s->m.p_tex_bits = s->m.frame_bits - s->m.misc_bits - s->m.mv_bits;
+ s->m.current_picture.f->display_picture_number =
+ s->m.current_picture.f->coded_picture_number = avctx->frame_number;
+ s->m.current_picture.f->quality = pic->quality;
+ s->m.total_bits += 8*(s->c.bytestream - s->c.bytestream_start);
+ if(s->pass1_rc)
+ if (ff_rate_estimate_qscale(&s->m, 0) < 0)
+ return -1;
+ if(avctx->flags&CODEC_FLAG_PASS1)
+ ff_write_pass1_stats(&s->m);
+ s->m.last_pict_type = s->m.pict_type;
+ avctx->frame_bits = s->m.frame_bits;
+ avctx->mv_bits = s->m.mv_bits;
+ avctx->misc_bits = s->m.misc_bits;
+ avctx->p_tex_bits = s->m.p_tex_bits;
+
+ emms_c();
+
+ pkt->size = ff_rac_terminate(c);
+ if (avctx->coded_frame->key_frame)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static av_cold int encode_end(AVCodecContext *avctx)
+{
+ SnowContext *s = avctx->priv_data;
+
+ ff_snow_common_end(s);
+ ff_rate_control_uninit(&s->m);
+ av_frame_free(&s->input_picture);
+ av_frame_free(&avctx->coded_frame);
+ av_freep(&avctx->stats_out);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(SnowContext, x)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ FF_MPV_COMMON_OPTS
+ { "memc_only", "Only do ME/MC (I frames -> ref, P frame -> ME+MC).", OFFSET(memc_only), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "no_bitstream", "Skip final bitstream writeout.", OFFSET(no_bitstream), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
+ { "intra_penalty", "Penalty for intra blocks in block decission", OFFSET(intra_penalty), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
+ { NULL },
+};
+
+static const AVClass snowenc_class = {
+ .class_name = "snow encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_snow_encoder = {
+ .name = "snow",
+ .long_name = NULL_IF_CONFIG_SMALL("Snow"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_SNOW,
+ .priv_data_size = sizeof(SnowContext),
+ .init = encode_init,
+ .encode2 = encode_frame,
+ .close = encode_end,
+ .pix_fmts = (const enum AVPixelFormat[]){
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ },
+ .priv_class = &snowenc_class,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
+ FF_CODEC_CAP_INIT_CLEANUP,
+};
+
+
+#ifdef TEST
+#undef malloc
+#undef free
+#undef printf
+
+#include "libavutil/lfg.h"
+#include "libavutil/mathematics.h"
+
+int main(void){
+#define width 256
+#define height 256
+ int buffer[2][width*height];
+ SnowContext s;
+ int i;
+ AVLFG prng;
+ s.spatial_decomposition_count=6;
+ s.spatial_decomposition_type=1;
+
+ s.temp_dwt_buffer = av_mallocz_array(width, sizeof(DWTELEM));
+ s.temp_idwt_buffer = av_mallocz_array(width, sizeof(IDWTELEM));
+
+ if (!s.temp_dwt_buffer || !s.temp_idwt_buffer) {
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+
+ av_lfg_init(&prng, 1);
+
+ printf("testing 5/3 DWT\n");
+ for(i=0; i<width*height; i++)
+ buffer[0][i] = buffer[1][i] = av_lfg_get(&prng) % 54321 - 12345;
+
+ ff_spatial_dwt(buffer[0], s.temp_dwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
+ ff_spatial_idwt((IDWTELEM*)buffer[0], s.temp_idwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
+
+ for(i=0; i<width*height; i++)
+ if(buffer[0][i]!= buffer[1][i]) printf("fsck: %6d %12d %7d\n",i, buffer[0][i], buffer[1][i]);
+
+ printf("testing 9/7 DWT\n");
+ s.spatial_decomposition_type=0;
+ for(i=0; i<width*height; i++)
+ buffer[0][i] = buffer[1][i] = av_lfg_get(&prng) % 54321 - 12345;
+
+ ff_spatial_dwt(buffer[0], s.temp_dwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
+ ff_spatial_idwt((IDWTELEM*)buffer[0], s.temp_idwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
+
+ for(i=0; i<width*height; i++)
+ if(FFABS(buffer[0][i] - buffer[1][i])>20) printf("fsck: %6d %12d %7d\n",i, buffer[0][i], buffer[1][i]);
+
+ {
+ int level, orientation, x, y;
+ int64_t errors[8][4];
+ int64_t g=0;
+
+ memset(errors, 0, sizeof(errors));
+ s.spatial_decomposition_count=3;
+ s.spatial_decomposition_type=0;
+ for(level=0; level<s.spatial_decomposition_count; level++){
+ for(orientation=level ? 1 : 0; orientation<4; orientation++){
+ int w= width >> (s.spatial_decomposition_count-level);
+ int h= height >> (s.spatial_decomposition_count-level);
+ int stride= width << (s.spatial_decomposition_count-level);
+ DWTELEM *buf= buffer[0];
+ int64_t error=0;
+
+ if(orientation&1) buf+=w;
+ if(orientation>1) buf+=stride>>1;
+
+ memset(buffer[0], 0, sizeof(int)*width*height);
+ buf[w/2 + h/2*stride]= 256*256;
+ ff_spatial_idwt((IDWTELEM*)buffer[0], s.temp_idwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
+ for(y=0; y<height; y++){
+ for(x=0; x<width; x++){
+ int64_t d= buffer[0][x + y*width];
+ error += d*d;
+ if(FFABS(width/2-x)<9 && FFABS(height/2-y)<9 && level==2) printf("%8"PRId64" ", d);
+ }
+ if(FFABS(height/2-y)<9 && level==2) printf("\n");
+ }
+ error= (int)(sqrt(error)+0.5);
+ errors[level][orientation]= error;
+ if(g) g=av_gcd(g, error);
+ else g= error;
+ }
+ }
+ printf("static int const visual_weight[][4]={\n");
+ for(level=0; level<s.spatial_decomposition_count; level++){
+ printf(" {");
+ for(orientation=0; orientation<4; orientation++){
+ printf("%8"PRId64",", errors[level][orientation]/g);
+ }
+ printf("},\n");
+ }
+ printf("};\n");
+ {
+ int level=2;
+ int w= width >> (s.spatial_decomposition_count-level);
+ //int h= height >> (s.spatial_decomposition_count-level);
+ int stride= width << (s.spatial_decomposition_count-level);
+ DWTELEM *buf= buffer[0];
+ int64_t error=0;
+
+ buf+=w;
+ buf+=stride>>1;
+
+ memset(buffer[0], 0, sizeof(int)*width*height);
+ for(y=0; y<height; y++){
+ for(x=0; x<width; x++){
+ int tab[4]={0,2,3,1};
+ buffer[0][x+width*y]= 256*256*tab[(x&1) + 2*(y&1)];
+ }
+ }
+ ff_spatial_dwt(buffer[0], s.temp_dwt_buffer, width, height, width, s.spatial_decomposition_type, s.spatial_decomposition_count);
+ for(y=0; y<height; y++){
+ for(x=0; x<width; x++){
+ int64_t d= buffer[0][x + y*width];
+ error += d*d;
+ if(FFABS(width/2-x)<9 && FFABS(height/2-y)<9) printf("%8"PRId64" ", d);
+ }
+ if(FFABS(height/2-y)<9) printf("\n");
+ }
+ }
+
+ }
+ return 0;
+}
+#endif /* TEST */
diff --git a/libavcodec/sonic.c b/libavcodec/sonic.c
new file mode 100644
index 0000000000..3db77f30a3
--- /dev/null
+++ b/libavcodec/sonic.c
@@ -0,0 +1,1115 @@
+/*
+ * Simple free lossless/lossy audio codec
+ * Copyright (c) 2004 Alex Beregszaszi
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "avcodec.h"
+#include "get_bits.h"
+#include "golomb.h"
+#include "internal.h"
+#include "rangecoder.h"
+
+
+/**
+ * @file
+ * Simple free lossless/lossy audio codec
+ * Based on Paul Francis Harrison's Bonk (http://www.logarithmic.net/pfh/bonk)
+ * Written and designed by Alex Beregszaszi
+ *
+ * TODO:
+ * - CABAC put/get_symbol
+ * - independent quantizer for channels
+ * - >2 channels support
+ * - more decorrelation types
+ * - more tap_quant tests
+ * - selectable intlist writers/readers (bonk-style, golomb, cabac)
+ */
+
+#define MAX_CHANNELS 2
+
+#define MID_SIDE 0
+#define LEFT_SIDE 1
+#define RIGHT_SIDE 2
+
+typedef struct SonicContext {
+ int version;
+ int minor_version;
+ int lossless, decorrelation;
+
+ int num_taps, downsampling;
+ double quantization;
+
+ int channels, samplerate, block_align, frame_size;
+
+ int *tap_quant;
+ int *int_samples;
+ int *coded_samples[MAX_CHANNELS];
+
+ // for encoding
+ int *tail;
+ int tail_size;
+ int *window;
+ int window_size;
+
+ // for decoding
+ int *predictor_k;
+ int *predictor_state[MAX_CHANNELS];
+} SonicContext;
+
+#define LATTICE_SHIFT 10
+#define SAMPLE_SHIFT 4
+#define LATTICE_FACTOR (1 << LATTICE_SHIFT)
+#define SAMPLE_FACTOR (1 << SAMPLE_SHIFT)
+
+#define BASE_QUANT 0.6
+#define RATE_VARIATION 3.0
+
+static inline int shift(int a,int b)
+{
+ return (a+(1<<(b-1))) >> b;
+}
+
+static inline int shift_down(int a,int b)
+{
+ return (a>>b)+(a<0);
+}
+
+static av_always_inline av_flatten void put_symbol(RangeCoder *c, uint8_t *state, int v, int is_signed, uint64_t rc_stat[256][2], uint64_t rc_stat2[32][2]){
+ int i;
+
+#define put_rac(C,S,B) \
+do{\
+ if(rc_stat){\
+ rc_stat[*(S)][B]++;\
+ rc_stat2[(S)-state][B]++;\
+ }\
+ put_rac(C,S,B);\
+}while(0)
+
+ if(v){
+ const int a= FFABS(v);
+ const int e= av_log2(a);
+ put_rac(c, state+0, 0);
+ if(e<=9){
+ for(i=0; i<e; i++){
+ put_rac(c, state+1+i, 1); //1..10
+ }
+ put_rac(c, state+1+i, 0);
+
+ for(i=e-1; i>=0; i--){
+ put_rac(c, state+22+i, (a>>i)&1); //22..31
+ }
+
+ if(is_signed)
+ put_rac(c, state+11 + e, v < 0); //11..21
+ }else{
+ for(i=0; i<e; i++){
+ put_rac(c, state+1+FFMIN(i,9), 1); //1..10
+ }
+ put_rac(c, state+1+9, 0);
+
+ for(i=e-1; i>=0; i--){
+ put_rac(c, state+22+FFMIN(i,9), (a>>i)&1); //22..31
+ }
+
+ if(is_signed)
+ put_rac(c, state+11 + 10, v < 0); //11..21
+ }
+ }else{
+ put_rac(c, state+0, 1);
+ }
+#undef put_rac
+}
+
+static inline av_flatten int get_symbol(RangeCoder *c, uint8_t *state, int is_signed){
+ if(get_rac(c, state+0))
+ return 0;
+ else{
+ int i, e, a;
+ e= 0;
+ while(get_rac(c, state+1 + FFMIN(e,9))){ //1..10
+ e++;
+ }
+
+ a= 1;
+ for(i=e-1; i>=0; i--){
+ a += a + get_rac(c, state+22 + FFMIN(i,9)); //22..31
+ }
+
+ e= -(is_signed && get_rac(c, state+11 + FFMIN(e, 10))); //11..21
+ return (a^e)-e;
+ }
+}
+
+#if 1
+static inline int intlist_write(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part)
+{
+ int i;
+
+ for (i = 0; i < entries; i++)
+ put_symbol(c, state, buf[i], 1, NULL, NULL);
+
+ return 1;
+}
+
+static inline int intlist_read(RangeCoder *c, uint8_t *state, int *buf, int entries, int base_2_part)
+{
+ int i;
+
+ for (i = 0; i < entries; i++)
+ buf[i] = get_symbol(c, state, 1);
+
+ return 1;
+}
+#elif 1
+static inline int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part)
+{
+ int i;
+
+ for (i = 0; i < entries; i++)
+ set_se_golomb(pb, buf[i]);
+
+ return 1;
+}
+
+static inline int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part)
+{
+ int i;
+
+ for (i = 0; i < entries; i++)
+ buf[i] = get_se_golomb(gb);
+
+ return 1;
+}
+
+#else
+
+#define ADAPT_LEVEL 8
+
+static int bits_to_store(uint64_t x)
+{
+ int res = 0;
+
+ while(x)
+ {
+ res++;
+ x >>= 1;
+ }
+ return res;
+}
+
+static void write_uint_max(PutBitContext *pb, unsigned int value, unsigned int max)
+{
+ int i, bits;
+
+ if (!max)
+ return;
+
+ bits = bits_to_store(max);
+
+ for (i = 0; i < bits-1; i++)
+ put_bits(pb, 1, value & (1 << i));
+
+ if ( (value | (1 << (bits-1))) <= max)
+ put_bits(pb, 1, value & (1 << (bits-1)));
+}
+
+static unsigned int read_uint_max(GetBitContext *gb, int max)
+{
+ int i, bits, value = 0;
+
+ if (!max)
+ return 0;
+
+ bits = bits_to_store(max);
+
+ for (i = 0; i < bits-1; i++)
+ if (get_bits1(gb))
+ value += 1 << i;
+
+ if ( (value | (1<<(bits-1))) <= max)
+ if (get_bits1(gb))
+ value += 1 << (bits-1);
+
+ return value;
+}
+
+static int intlist_write(PutBitContext *pb, int *buf, int entries, int base_2_part)
+{
+ int i, j, x = 0, low_bits = 0, max = 0;
+ int step = 256, pos = 0, dominant = 0, any = 0;
+ int *copy, *bits;
+
+ copy = av_calloc(entries, sizeof(*copy));
+ if (!copy)
+ return AVERROR(ENOMEM);
+
+ if (base_2_part)
+ {
+ int energy = 0;
+
+ for (i = 0; i < entries; i++)
+ energy += abs(buf[i]);
+
+ low_bits = bits_to_store(energy / (entries * 2));
+ if (low_bits > 15)
+ low_bits = 15;
+
+ put_bits(pb, 4, low_bits);
+ }
+
+ for (i = 0; i < entries; i++)
+ {
+ put_bits(pb, low_bits, abs(buf[i]));
+ copy[i] = abs(buf[i]) >> low_bits;
+ if (copy[i] > max)
+ max = abs(copy[i]);
+ }
+
+ bits = av_calloc(entries*max, sizeof(*bits));
+ if (!bits)
+ {
+ av_free(copy);
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i <= max; i++)
+ {
+ for (j = 0; j < entries; j++)
+ if (copy[j] >= i)
+ bits[x++] = copy[j] > i;
+ }
+
+ // store bitstream
+ while (pos < x)
+ {
+ int steplet = step >> 8;
+
+ if (pos + steplet > x)
+ steplet = x - pos;
+
+ for (i = 0; i < steplet; i++)
+ if (bits[i+pos] != dominant)
+ any = 1;
+
+ put_bits(pb, 1, any);
+
+ if (!any)
+ {
+ pos += steplet;
+ step += step / ADAPT_LEVEL;
+ }
+ else
+ {
+ int interloper = 0;
+
+ while (((pos + interloper) < x) && (bits[pos + interloper] == dominant))
+ interloper++;
+
+ // note change
+ write_uint_max(pb, interloper, (step >> 8) - 1);
+
+ pos += interloper + 1;
+ step -= step / ADAPT_LEVEL;
+ }
+
+ if (step < 256)
+ {
+ step = 65536 / step;
+ dominant = !dominant;
+ }
+ }
+
+ // store signs
+ for (i = 0; i < entries; i++)
+ if (buf[i])
+ put_bits(pb, 1, buf[i] < 0);
+
+ av_free(bits);
+ av_free(copy);
+
+ return 0;
+}
+
+static int intlist_read(GetBitContext *gb, int *buf, int entries, int base_2_part)
+{
+ int i, low_bits = 0, x = 0;
+ int n_zeros = 0, step = 256, dominant = 0;
+ int pos = 0, level = 0;
+ int *bits = av_calloc(entries, sizeof(*bits));
+
+ if (!bits)
+ return AVERROR(ENOMEM);
+
+ if (base_2_part)
+ {
+ low_bits = get_bits(gb, 4);
+
+ if (low_bits)
+ for (i = 0; i < entries; i++)
+ buf[i] = get_bits(gb, low_bits);
+ }
+
+// av_log(NULL, AV_LOG_INFO, "entries: %d, low bits: %d\n", entries, low_bits);
+
+ while (n_zeros < entries)
+ {
+ int steplet = step >> 8;
+
+ if (!get_bits1(gb))
+ {
+ for (i = 0; i < steplet; i++)
+ bits[x++] = dominant;
+
+ if (!dominant)
+ n_zeros += steplet;
+
+ step += step / ADAPT_LEVEL;
+ }
+ else
+ {
+ int actual_run = read_uint_max(gb, steplet-1);
+
+// av_log(NULL, AV_LOG_INFO, "actual run: %d\n", actual_run);
+
+ for (i = 0; i < actual_run; i++)
+ bits[x++] = dominant;
+
+ bits[x++] = !dominant;
+
+ if (!dominant)
+ n_zeros += actual_run;
+ else
+ n_zeros++;
+
+ step -= step / ADAPT_LEVEL;
+ }
+
+ if (step < 256)
+ {
+ step = 65536 / step;
+ dominant = !dominant;
+ }
+ }
+
+ // reconstruct unsigned values
+ n_zeros = 0;
+ for (i = 0; n_zeros < entries; i++)
+ {
+ while(1)
+ {
+ if (pos >= entries)
+ {
+ pos = 0;
+ level += 1 << low_bits;
+ }
+
+ if (buf[pos] >= level)
+ break;
+
+ pos++;
+ }
+
+ if (bits[i])
+ buf[pos] += 1 << low_bits;
+ else
+ n_zeros++;
+
+ pos++;
+ }
+ av_free(bits);
+
+ // read signs
+ for (i = 0; i < entries; i++)
+ if (buf[i] && get_bits1(gb))
+ buf[i] = -buf[i];
+
+// av_log(NULL, AV_LOG_INFO, "zeros: %d pos: %d\n", n_zeros, pos);
+
+ return 0;
+}
+#endif
+
+static void predictor_init_state(int *k, int *state, int order)
+{
+ int i;
+
+ for (i = order-2; i >= 0; i--)
+ {
+ int j, p, x = state[i];
+
+ for (j = 0, p = i+1; p < order; j++,p++)
+ {
+ int tmp = x + shift_down(k[j] * state[p], LATTICE_SHIFT);
+ state[p] += shift_down(k[j]*x, LATTICE_SHIFT);
+ x = tmp;
+ }
+ }
+}
+
+static int predictor_calc_error(int *k, int *state, int order, int error)
+{
+ int i, x = error - shift_down(k[order-1] * state[order-1], LATTICE_SHIFT);
+
+#if 1
+ int *k_ptr = &(k[order-2]),
+ *state_ptr = &(state[order-2]);
+ for (i = order-2; i >= 0; i--, k_ptr--, state_ptr--)
+ {
+ int k_value = *k_ptr, state_value = *state_ptr;
+ x -= shift_down(k_value * state_value, LATTICE_SHIFT);
+ state_ptr[1] = state_value + shift_down(k_value * x, LATTICE_SHIFT);
+ }
+#else
+ for (i = order-2; i >= 0; i--)
+ {
+ x -= shift_down(k[i] * state[i], LATTICE_SHIFT);
+ state[i+1] = state[i] + shift_down(k[i] * x, LATTICE_SHIFT);
+ }
+#endif
+
+ // don't drift too far, to avoid overflows
+ if (x > (SAMPLE_FACTOR<<16)) x = (SAMPLE_FACTOR<<16);
+ if (x < -(SAMPLE_FACTOR<<16)) x = -(SAMPLE_FACTOR<<16);
+
+ state[0] = x;
+
+ return x;
+}
+
+#if CONFIG_SONIC_ENCODER || CONFIG_SONIC_LS_ENCODER
+// Heavily modified Levinson-Durbin algorithm which
+// copes better with quantization, and calculates the
+// actual whitened result as it goes.
+
+static int modified_levinson_durbin(int *window, int window_entries,
+ int *out, int out_entries, int channels, int *tap_quant)
+{
+ int i;
+ int *state = av_calloc(window_entries, sizeof(*state));
+
+ if (!state)
+ return AVERROR(ENOMEM);
+
+ memcpy(state, window, 4* window_entries);
+
+ for (i = 0; i < out_entries; i++)
+ {
+ int step = (i+1)*channels, k, j;
+ double xx = 0.0, xy = 0.0;
+#if 1
+ int *x_ptr = &(window[step]);
+ int *state_ptr = &(state[0]);
+ j = window_entries - step;
+ for (;j>0;j--,x_ptr++,state_ptr++)
+ {
+ double x_value = *x_ptr;
+ double state_value = *state_ptr;
+ xx += state_value*state_value;
+ xy += x_value*state_value;
+ }
+#else
+ for (j = 0; j <= (window_entries - step); j++);
+ {
+ double stepval = window[step+j];
+ double stateval = window[j];
+// xx += (double)window[j]*(double)window[j];
+// xy += (double)window[step+j]*(double)window[j];
+ xx += stateval*stateval;
+ xy += stepval*stateval;
+ }
+#endif
+ if (xx == 0.0)
+ k = 0;
+ else
+ k = (int)(floor(-xy/xx * (double)LATTICE_FACTOR / (double)(tap_quant[i]) + 0.5));
+
+ if (k > (LATTICE_FACTOR/tap_quant[i]))
+ k = LATTICE_FACTOR/tap_quant[i];
+ if (-k > (LATTICE_FACTOR/tap_quant[i]))
+ k = -(LATTICE_FACTOR/tap_quant[i]);
+
+ out[i] = k;
+ k *= tap_quant[i];
+
+#if 1
+ x_ptr = &(window[step]);
+ state_ptr = &(state[0]);
+ j = window_entries - step;
+ for (;j>0;j--,x_ptr++,state_ptr++)
+ {
+ int x_value = *x_ptr;
+ int state_value = *state_ptr;
+ *x_ptr = x_value + shift_down(k*state_value,LATTICE_SHIFT);
+ *state_ptr = state_value + shift_down(k*x_value, LATTICE_SHIFT);
+ }
+#else
+ for (j=0; j <= (window_entries - step); j++)
+ {
+ int stepval = window[step+j];
+ int stateval=state[j];
+ window[step+j] += shift_down(k * stateval, LATTICE_SHIFT);
+ state[j] += shift_down(k * stepval, LATTICE_SHIFT);
+ }
+#endif
+ }
+
+ av_free(state);
+ return 0;
+}
+
+static inline int code_samplerate(int samplerate)
+{
+ switch (samplerate)
+ {
+ case 44100: return 0;
+ case 22050: return 1;
+ case 11025: return 2;
+ case 96000: return 3;
+ case 48000: return 4;
+ case 32000: return 5;
+ case 24000: return 6;
+ case 16000: return 7;
+ case 8000: return 8;
+ }
+ return AVERROR(EINVAL);
+}
+
+static av_cold int sonic_encode_init(AVCodecContext *avctx)
+{
+ SonicContext *s = avctx->priv_data;
+ PutBitContext pb;
+ int i;
+
+ s->version = 2;
+
+ if (avctx->channels > MAX_CHANNELS)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Only mono and stereo streams are supported by now\n");
+ return AVERROR(EINVAL); /* only stereo or mono for now */
+ }
+
+ if (avctx->channels == 2)
+ s->decorrelation = MID_SIDE;
+ else
+ s->decorrelation = 3;
+
+ if (avctx->codec->id == AV_CODEC_ID_SONIC_LS)
+ {
+ s->lossless = 1;
+ s->num_taps = 32;
+ s->downsampling = 1;
+ s->quantization = 0.0;
+ }
+ else
+ {
+ s->num_taps = 128;
+ s->downsampling = 2;
+ s->quantization = 1.0;
+ }
+
+ // max tap 2048
+ if (s->num_taps < 32 || s->num_taps > 1024 || s->num_taps % 32) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of taps\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ // generate taps
+ s->tap_quant = av_calloc(s->num_taps, sizeof(*s->tap_quant));
+ if (!s->tap_quant)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->num_taps; i++)
+ s->tap_quant[i] = ff_sqrt(i+1);
+
+ s->channels = avctx->channels;
+ s->samplerate = avctx->sample_rate;
+
+ s->block_align = 2048LL*s->samplerate/(44100*s->downsampling);
+ s->frame_size = s->channels*s->block_align*s->downsampling;
+
+ s->tail_size = s->num_taps*s->channels;
+ s->tail = av_calloc(s->tail_size, sizeof(*s->tail));
+ if (!s->tail)
+ return AVERROR(ENOMEM);
+
+ s->predictor_k = av_calloc(s->num_taps, sizeof(*s->predictor_k) );
+ if (!s->predictor_k)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->channels; i++)
+ {
+ s->coded_samples[i] = av_calloc(s->block_align, sizeof(**s->coded_samples));
+ if (!s->coded_samples[i])
+ return AVERROR(ENOMEM);
+ }
+
+ s->int_samples = av_calloc(s->frame_size, sizeof(*s->int_samples));
+
+ s->window_size = ((2*s->tail_size)+s->frame_size);
+ s->window = av_calloc(s->window_size, sizeof(*s->window));
+ if (!s->window || !s->int_samples)
+ return AVERROR(ENOMEM);
+
+ avctx->extradata = av_mallocz(16);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
+ init_put_bits(&pb, avctx->extradata, 16*8);
+
+ put_bits(&pb, 2, s->version); // version
+ if (s->version >= 1)
+ {
+ if (s->version >= 2) {
+ put_bits(&pb, 8, s->version);
+ put_bits(&pb, 8, s->minor_version);
+ }
+ put_bits(&pb, 2, s->channels);
+ put_bits(&pb, 4, code_samplerate(s->samplerate));
+ }
+ put_bits(&pb, 1, s->lossless);
+ if (!s->lossless)
+ put_bits(&pb, 3, SAMPLE_SHIFT); // XXX FIXME: sample precision
+ put_bits(&pb, 2, s->decorrelation);
+ put_bits(&pb, 2, s->downsampling);
+ put_bits(&pb, 5, (s->num_taps >> 5)-1); // 32..1024
+ put_bits(&pb, 1, 0); // XXX FIXME: no custom tap quant table
+
+ flush_put_bits(&pb);
+ avctx->extradata_size = put_bits_count(&pb)/8;
+
+ av_log(avctx, AV_LOG_INFO, "Sonic: ver: %d.%d ls: %d dr: %d taps: %d block: %d frame: %d downsamp: %d\n",
+ s->version, s->minor_version, s->lossless, s->decorrelation, s->num_taps, s->block_align, s->frame_size, s->downsampling);
+
+ avctx->frame_size = s->block_align*s->downsampling;
+
+ return 0;
+}
+
+static av_cold int sonic_encode_close(AVCodecContext *avctx)
+{
+ SonicContext *s = avctx->priv_data;
+ int i;
+
+ for (i = 0; i < s->channels; i++)
+ av_freep(&s->coded_samples[i]);
+
+ av_freep(&s->predictor_k);
+ av_freep(&s->tail);
+ av_freep(&s->tap_quant);
+ av_freep(&s->window);
+ av_freep(&s->int_samples);
+
+ return 0;
+}
+
+static int sonic_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ SonicContext *s = avctx->priv_data;
+ RangeCoder c;
+ int i, j, ch, quant = 0, x = 0;
+ int ret;
+ const short *samples = (const int16_t*)frame->data[0];
+ uint8_t state[32];
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, s->frame_size * 5 + 1000)) < 0)
+ return ret;
+
+ ff_init_range_encoder(&c, avpkt->data, avpkt->size);
+ ff_build_rac_states(&c, 0.05*(1LL<<32), 256-8);
+ memset(state, 128, sizeof(state));
+
+ // short -> internal
+ for (i = 0; i < s->frame_size; i++)
+ s->int_samples[i] = samples[i];
+
+ if (!s->lossless)
+ for (i = 0; i < s->frame_size; i++)
+ s->int_samples[i] = s->int_samples[i] << SAMPLE_SHIFT;
+
+ switch(s->decorrelation)
+ {
+ case MID_SIDE:
+ for (i = 0; i < s->frame_size; i += s->channels)
+ {
+ s->int_samples[i] += s->int_samples[i+1];
+ s->int_samples[i+1] -= shift(s->int_samples[i], 1);
+ }
+ break;
+ case LEFT_SIDE:
+ for (i = 0; i < s->frame_size; i += s->channels)
+ s->int_samples[i+1] -= s->int_samples[i];
+ break;
+ case RIGHT_SIDE:
+ for (i = 0; i < s->frame_size; i += s->channels)
+ s->int_samples[i] -= s->int_samples[i+1];
+ break;
+ }
+
+ memset(s->window, 0, 4* s->window_size);
+
+ for (i = 0; i < s->tail_size; i++)
+ s->window[x++] = s->tail[i];
+
+ for (i = 0; i < s->frame_size; i++)
+ s->window[x++] = s->int_samples[i];
+
+ for (i = 0; i < s->tail_size; i++)
+ s->window[x++] = 0;
+
+ for (i = 0; i < s->tail_size; i++)
+ s->tail[i] = s->int_samples[s->frame_size - s->tail_size + i];
+
+ // generate taps
+ ret = modified_levinson_durbin(s->window, s->window_size,
+ s->predictor_k, s->num_taps, s->channels, s->tap_quant);
+ if (ret < 0)
+ return ret;
+
+ if ((ret = intlist_write(&c, state, s->predictor_k, s->num_taps, 0)) < 0)
+ return ret;
+
+ for (ch = 0; ch < s->channels; ch++)
+ {
+ x = s->tail_size+ch;
+ for (i = 0; i < s->block_align; i++)
+ {
+ int sum = 0;
+ for (j = 0; j < s->downsampling; j++, x += s->channels)
+ sum += s->window[x];
+ s->coded_samples[ch][i] = sum;
+ }
+ }
+
+ // simple rate control code
+ if (!s->lossless)
+ {
+ double energy1 = 0.0, energy2 = 0.0;
+ for (ch = 0; ch < s->channels; ch++)
+ {
+ for (i = 0; i < s->block_align; i++)
+ {
+ double sample = s->coded_samples[ch][i];
+ energy2 += sample*sample;
+ energy1 += fabs(sample);
+ }
+ }
+
+ energy2 = sqrt(energy2/(s->channels*s->block_align));
+ energy1 = M_SQRT2*energy1/(s->channels*s->block_align);
+
+ // increase bitrate when samples are like a gaussian distribution
+ // reduce bitrate when samples are like a two-tailed exponential distribution
+
+ if (energy2 > energy1)
+ energy2 += (energy2-energy1)*RATE_VARIATION;
+
+ quant = (int)(BASE_QUANT*s->quantization*energy2/SAMPLE_FACTOR);
+// av_log(avctx, AV_LOG_DEBUG, "quant: %d energy: %f / %f\n", quant, energy1, energy2);
+
+ quant = av_clip(quant, 1, 65534);
+
+ put_symbol(&c, state, quant, 0, NULL, NULL);
+
+ quant *= SAMPLE_FACTOR;
+ }
+
+ // write out coded samples
+ for (ch = 0; ch < s->channels; ch++)
+ {
+ if (!s->lossless)
+ for (i = 0; i < s->block_align; i++)
+ s->coded_samples[ch][i] = ROUNDED_DIV(s->coded_samples[ch][i], quant);
+
+ if ((ret = intlist_write(&c, state, s->coded_samples[ch], s->block_align, 1)) < 0)
+ return ret;
+ }
+
+// av_log(avctx, AV_LOG_DEBUG, "used bytes: %d\n", (put_bits_count(&pb)+7)/8);
+
+ avpkt->size = ff_rac_terminate(&c);
+ *got_packet_ptr = 1;
+ return 0;
+
+}
+#endif /* CONFIG_SONIC_ENCODER || CONFIG_SONIC_LS_ENCODER */
+
+#if CONFIG_SONIC_DECODER
+static const int samplerate_table[] =
+ { 44100, 22050, 11025, 96000, 48000, 32000, 24000, 16000, 8000 };
+
+static av_cold int sonic_decode_init(AVCodecContext *avctx)
+{
+ SonicContext *s = avctx->priv_data;
+ GetBitContext gb;
+ int i;
+
+ s->channels = avctx->channels;
+ s->samplerate = avctx->sample_rate;
+
+ if (!avctx->extradata)
+ {
+ av_log(avctx, AV_LOG_ERROR, "No mandatory headers present\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ init_get_bits8(&gb, avctx->extradata, avctx->extradata_size);
+
+ s->version = get_bits(&gb, 2);
+ if (s->version >= 2) {
+ s->version = get_bits(&gb, 8);
+ s->minor_version = get_bits(&gb, 8);
+ }
+ if (s->version != 2)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported Sonic version, please report\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (s->version >= 1)
+ {
+ int sample_rate_index;
+ s->channels = get_bits(&gb, 2);
+ sample_rate_index = get_bits(&gb, 4);
+ if (sample_rate_index >= FF_ARRAY_ELEMS(samplerate_table)) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid sample_rate_index %d\n", sample_rate_index);
+ return AVERROR_INVALIDDATA;
+ }
+ s->samplerate = samplerate_table[sample_rate_index];
+ av_log(avctx, AV_LOG_INFO, "Sonicv2 chans: %d samprate: %d\n",
+ s->channels, s->samplerate);
+ }
+
+ if (s->channels > MAX_CHANNELS || s->channels < 1)
+ {
+ av_log(avctx, AV_LOG_ERROR, "Only mono and stereo streams are supported by now\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ s->lossless = get_bits1(&gb);
+ if (!s->lossless)
+ skip_bits(&gb, 3); // XXX FIXME
+ s->decorrelation = get_bits(&gb, 2);
+ if (s->decorrelation != 3 && s->channels != 2) {
+ av_log(avctx, AV_LOG_ERROR, "invalid decorrelation %d\n", s->decorrelation);
+ return AVERROR_INVALIDDATA;
+ }
+
+ s->downsampling = get_bits(&gb, 2);
+ if (!s->downsampling) {
+ av_log(avctx, AV_LOG_ERROR, "invalid downsampling value\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ s->num_taps = (get_bits(&gb, 5)+1)<<5;
+ if (get_bits1(&gb)) // XXX FIXME
+ av_log(avctx, AV_LOG_INFO, "Custom quant table\n");
+
+ s->block_align = 2048LL*s->samplerate/(44100*s->downsampling);
+ s->frame_size = s->channels*s->block_align*s->downsampling;
+// avctx->frame_size = s->block_align;
+
+ av_log(avctx, AV_LOG_INFO, "Sonic: ver: %d.%d ls: %d dr: %d taps: %d block: %d frame: %d downsamp: %d\n",
+ s->version, s->minor_version, s->lossless, s->decorrelation, s->num_taps, s->block_align, s->frame_size, s->downsampling);
+
+ // generate taps
+ s->tap_quant = av_calloc(s->num_taps, sizeof(*s->tap_quant));
+ if (!s->tap_quant)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->num_taps; i++)
+ s->tap_quant[i] = ff_sqrt(i+1);
+
+ s->predictor_k = av_calloc(s->num_taps, sizeof(*s->predictor_k));
+
+ for (i = 0; i < s->channels; i++)
+ {
+ s->predictor_state[i] = av_calloc(s->num_taps, sizeof(**s->predictor_state));
+ if (!s->predictor_state[i])
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < s->channels; i++)
+ {
+ s->coded_samples[i] = av_calloc(s->block_align, sizeof(**s->coded_samples));
+ if (!s->coded_samples[i])
+ return AVERROR(ENOMEM);
+ }
+ s->int_samples = av_calloc(s->frame_size, sizeof(*s->int_samples));
+ if (!s->int_samples)
+ return AVERROR(ENOMEM);
+
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+ return 0;
+}
+
+static av_cold int sonic_decode_close(AVCodecContext *avctx)
+{
+ SonicContext *s = avctx->priv_data;
+ int i;
+
+ av_freep(&s->int_samples);
+ av_freep(&s->tap_quant);
+ av_freep(&s->predictor_k);
+
+ for (i = 0; i < s->channels; i++)
+ {
+ av_freep(&s->predictor_state[i]);
+ av_freep(&s->coded_samples[i]);
+ }
+
+ return 0;
+}
+
+static int sonic_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame_ptr,
+ AVPacket *avpkt)
+{
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ SonicContext *s = avctx->priv_data;
+ RangeCoder c;
+ uint8_t state[32];
+ int i, quant, ch, j, ret;
+ int16_t *samples;
+ AVFrame *frame = data;
+
+ if (buf_size == 0) return 0;
+
+ frame->nb_samples = s->frame_size / avctx->channels;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+ samples = (int16_t *)frame->data[0];
+
+// av_log(NULL, AV_LOG_INFO, "buf_size: %d\n", buf_size);
+
+ memset(state, 128, sizeof(state));
+ ff_init_range_decoder(&c, buf, buf_size);
+ ff_build_rac_states(&c, 0.05*(1LL<<32), 256-8);
+
+ intlist_read(&c, state, s->predictor_k, s->num_taps, 0);
+
+ // dequantize
+ for (i = 0; i < s->num_taps; i++)
+ s->predictor_k[i] *= s->tap_quant[i];
+
+ if (s->lossless)
+ quant = 1;
+ else
+ quant = get_symbol(&c, state, 0) * SAMPLE_FACTOR;
+
+// av_log(NULL, AV_LOG_INFO, "quant: %d\n", quant);
+
+ for (ch = 0; ch < s->channels; ch++)
+ {
+ int x = ch;
+
+ predictor_init_state(s->predictor_k, s->predictor_state[ch], s->num_taps);
+
+ intlist_read(&c, state, s->coded_samples[ch], s->block_align, 1);
+
+ for (i = 0; i < s->block_align; i++)
+ {
+ for (j = 0; j < s->downsampling - 1; j++)
+ {
+ s->int_samples[x] = predictor_calc_error(s->predictor_k, s->predictor_state[ch], s->num_taps, 0);
+ x += s->channels;
+ }
+
+ s->int_samples[x] = predictor_calc_error(s->predictor_k, s->predictor_state[ch], s->num_taps, s->coded_samples[ch][i] * quant);
+ x += s->channels;
+ }
+
+ for (i = 0; i < s->num_taps; i++)
+ s->predictor_state[ch][i] = s->int_samples[s->frame_size - s->channels + ch - i*s->channels];
+ }
+
+ switch(s->decorrelation)
+ {
+ case MID_SIDE:
+ for (i = 0; i < s->frame_size; i += s->channels)
+ {
+ s->int_samples[i+1] += shift(s->int_samples[i], 1);
+ s->int_samples[i] -= s->int_samples[i+1];
+ }
+ break;
+ case LEFT_SIDE:
+ for (i = 0; i < s->frame_size; i += s->channels)
+ s->int_samples[i+1] += s->int_samples[i];
+ break;
+ case RIGHT_SIDE:
+ for (i = 0; i < s->frame_size; i += s->channels)
+ s->int_samples[i] += s->int_samples[i+1];
+ break;
+ }
+
+ if (!s->lossless)
+ for (i = 0; i < s->frame_size; i++)
+ s->int_samples[i] = shift(s->int_samples[i], SAMPLE_SHIFT);
+
+ // internal -> short
+ for (i = 0; i < s->frame_size; i++)
+ samples[i] = av_clip_int16(s->int_samples[i]);
+
+ *got_frame_ptr = 1;
+
+ return buf_size;
+}
+
+AVCodec ff_sonic_decoder = {
+ .name = "sonic",
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_SONIC,
+ .priv_data_size = sizeof(SonicContext),
+ .init = sonic_decode_init,
+ .close = sonic_decode_close,
+ .decode = sonic_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_EXPERIMENTAL,
+};
+#endif /* CONFIG_SONIC_DECODER */
+
+#if CONFIG_SONIC_ENCODER
+AVCodec ff_sonic_encoder = {
+ .name = "sonic",
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_SONIC,
+ .priv_data_size = sizeof(SonicContext),
+ .init = sonic_encode_init,
+ .encode2 = sonic_encode_frame,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE },
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .close = sonic_encode_close,
+};
+#endif
+
+#if CONFIG_SONIC_LS_ENCODER
+AVCodec ff_sonic_ls_encoder = {
+ .name = "sonicls",
+ .long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_SONIC_LS,
+ .priv_data_size = sizeof(SonicContext),
+ .init = sonic_encode_init,
+ .encode2 = sonic_encode_frame,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE },
+ .capabilities = CODEC_CAP_EXPERIMENTAL,
+ .close = sonic_encode_close,
+};
+#endif
diff --git a/libavcodec/sp5x.h b/libavcodec/sp5x.h
index 1577302e3c..ecd6e8d649 100644
--- a/libavcodec/sp5x.h
+++ b/libavcodec/sp5x.h
@@ -1,21 +1,21 @@
/*
* Sunplus JPEG tables
- * Copyright (c) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sp5xdec.c b/libavcodec/sp5xdec.c
index 08bdbc097c..3e49c59e06 100644
--- a/libavcodec/sp5xdec.c
+++ b/libavcodec/sp5xdec.c
@@ -2,20 +2,20 @@
* Sunplus JPEG decoder (SP5X)
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -73,7 +73,7 @@ static int sp5x_decode_frame(AVCodecContext *avctx,
for (i = 2; i < buf_size-2 && j < buf_size+1024-2; i++)
recoded[j++] = buf[i];
else
- for (i = 14; i < buf_size && j < buf_size+1024-2; i++)
+ for (i = 14; i < buf_size && j < buf_size+1024-3; i++)
{
recoded[j++] = buf[i];
if (buf[i] == 0xff)
@@ -91,9 +91,10 @@ static int sp5x_decode_frame(AVCodecContext *avctx,
av_free(recoded);
- return i;
+ return i < 0 ? i : avpkt->size;
}
+#if CONFIG_SP5X_DECODER
AVCodec ff_sp5x_decoder = {
.name = "sp5x",
.long_name = NULL_IF_CONFIG_SMALL("Sunplus JPEG (SP5X)"),
@@ -104,9 +105,11 @@ AVCodec ff_sp5x_decoder = {
.close = ff_mjpeg_decode_end,
.decode = sp5x_decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .max_lowres = 3,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
-
+#endif
+#if CONFIG_AMV_DECODER
AVCodec ff_amv_decoder = {
.name = "amv",
.long_name = NULL_IF_CONFIG_SMALL("AMV Video"),
@@ -116,5 +119,7 @@ AVCodec ff_amv_decoder = {
.init = ff_mjpeg_decode_init,
.close = ff_mjpeg_decode_end,
.decode = sp5x_decode_frame,
+ .max_lowres = 3,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
+#endif
diff --git a/libavcodec/sparc/README b/libavcodec/sparc/README
new file mode 100644
index 0000000000..f9f2349cd4
--- /dev/null
+++ b/libavcodec/sparc/README
@@ -0,0 +1,6 @@
+SPARC optimizations have been removed in
+commit b4dd424d96f09f9bafb88e47f37df65dc4529143
+The last revission with the optimizations is fb1b70c1ed50951c5fc1a309c3c446b2eaaf564b
+
+If you want to maintain these (or other) SPARC optimizations in ffmpeg, then please
+contact ffmpeg-devel@ffmpeg.org
diff --git a/libavcodec/srtdec.c b/libavcodec/srtdec.c
index 3bee3c726f..ed3af95063 100644
--- a/libavcodec/srtdec.c
+++ b/libavcodec/srtdec.c
@@ -2,25 +2,26 @@
* SubRip subtitle decoder
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/parseutils.h"
#include "avcodec.h"
#include "ass.h"
@@ -46,10 +47,16 @@ typedef struct SrtStack {
char param[PARAM_NUMBER][128];
} SrtStack;
-static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
- const char *in, int x1, int y1, int x2, int y2)
+static void rstrip_spaces_buf(AVBPrint *buf)
{
- char c, *param, buffer[128], tmp[128];
+ while (buf->len > 0 && buf->str[buf->len - 1] == ' ')
+ buf->str[--buf->len] = 0;
+}
+
+static void srt_to_ass(AVCodecContext *avctx, AVBPrint *dst,
+ const char *in, int x1, int y1, int x2, int y2)
+{
+ char *param, buffer[128], tmp[128];
int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
SrtStack stack[16];
@@ -59,14 +66,25 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
strcpy(stack[0].param[PARAM_FACE], "{\\fn}");
if (x1 >= 0 && y1 >= 0) {
- if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1))
- out += snprintf(out, out_end-out,
- "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
- else
- out += snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
+ /* XXX: here we rescale coordinate assuming they are in DVD resolution
+ * (720x480) since we don't have anything better */
+
+ if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1) && x2 >= x1 && y2 >= y1) {
+ /* text rectangle defined, write the text at the center of the rectangle */
+ const int cx = x1 + (x2 - x1)/2;
+ const int cy = y1 + (y2 - y1)/2;
+ const int scaled_x = cx * ASS_DEFAULT_PLAYRESX / 720;
+ const int scaled_y = cy * ASS_DEFAULT_PLAYRESY / 480;
+ av_bprintf(dst, "{\\an5}{\\pos(%d,%d)}", scaled_x, scaled_y);
+ } else {
+ /* only the top left corner, assume the text starts in that corner */
+ const int scaled_x = x1 * ASS_DEFAULT_PLAYRESX / 720;
+ const int scaled_y = y1 * ASS_DEFAULT_PLAYRESY / 480;
+ av_bprintf(dst, "{\\an1}{\\pos(%d,%d)}", scaled_x, scaled_y);
+ }
}
- for (; out < out_end && !end && *in; in++) {
+ for (; !end && *in; in++) {
switch (*in) {
case '\r':
break;
@@ -75,27 +93,28 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
end = 1;
break;
}
- while (out[-1] == ' ')
- out--;
- out += snprintf(out, out_end-out, "\\N");
+ rstrip_spaces_buf(dst);
+ av_bprintf(dst, "\\N");
line_start = 1;
break;
case ' ':
if (!line_start)
- *out++ = *in;
+ av_bprint_chars(dst, *in, 1);
break;
case '{': /* skip all {\xxx} substrings except for {\an%d}
and all microdvd like styles such as {Y:xxx} */
- an += sscanf(in, "{\\an%*1u}%c", &c) == 1;
- if ((an != 1 && sscanf(in, "{\\%*[^}]}%n%c", &len, &c) > 0) ||
- sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n%c", &len, &c) > 0) {
+ len = 0;
+ an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0;
+ if ((an != 1 && (len = 0, sscanf(in, "{\\%*[^}]}%n", &len) >= 0 && len > 0)) ||
+ (len = 0, sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n", &len) >= 0 && len > 0)) {
in += len - 1;
} else
- *out++ = *in;
+ av_bprint_chars(dst, *in, 1);
break;
case '<':
tag_close = in[1] == '/';
- if (sscanf(in+tag_close+1, "%127[^>]>%n%c", buffer, &len,&c) >= 2) {
+ len = 0;
+ if (sscanf(in+tag_close+1, "%127[^>]>%n", buffer, &len) >= 1 && len > 0) {
if ((param = strchr(buffer, ' ')))
*param++ = 0;
if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) ||
@@ -110,8 +129,7 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
if (stack[sptr-1].param[i][0])
for (j=sptr-2; j>=0; j--)
if (stack[j].param[i][0]) {
- out += snprintf(out, out_end-out,
- "%s", stack[j].param[i]);
+ av_bprintf(dst, "%s", stack[j].param[i]);
break;
}
} else {
@@ -146,12 +164,10 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
}
for (i=0; i<PARAM_NUMBER; i++)
if (stack[sptr].param[i][0])
- out += snprintf(out, out_end-out,
- "%s", stack[sptr].param[i]);
+ av_bprintf(dst, "%s", stack[sptr].param[i]);
}
} else if (!buffer[1] && strspn(buffer, "bisu") == 1) {
- out += snprintf(out, out_end-out,
- "{\\%c%d}", buffer[0], !tag_close);
+ av_bprintf(dst, "{\\%c%d}", buffer[0], !tag_close);
} else {
unknown = 1;
snprintf(tmp, sizeof(tmp), "</%s>", buffer);
@@ -160,7 +176,7 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
sptr--;
} else if (unknown && !strstr(in, tmp)) {
in -= len + tag_close;
- *out++ = *in;
+ av_bprint_chars(dst, *in, 1);
} else
av_strlcpy(stack[sptr++].tag, buffer,
sizeof(stack[0].tag));
@@ -168,75 +184,78 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
}
}
default:
- *out++ = *in;
+ av_bprint_chars(dst, *in, 1);
break;
}
if (*in != ' ' && *in != '\r' && *in != '\n')
line_start = 0;
}
- out = FFMIN(out, out_end-3);
- while (!strncmp(out-2, "\\N", 2))
- out -= 2;
- while (out[-1] == ' ')
- out--;
- out += snprintf(out, out_end-out, "\r\n");
- return in;
-}
-
-static const char *read_ts(const char *buf, int *ts_start, int *ts_end,
- int *x1, int *y1, int *x2, int *y2)
-{
- int i, hs, ms, ss, he, me, se;
-
- for (i=0; i<2; i++) {
- /* try to read timestamps in either the first or second line */
- int c = sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
- "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
- &hs, &ms, &ss, ts_start, &he, &me, &se, ts_end,
- x1, x2, y1, y2);
- buf += strcspn(buf, "\n") + 1;
- if (c >= 8) {
- *ts_start = 100*(ss + 60*(ms + 60*hs)) + *ts_start/10;
- *ts_end = 100*(se + 60*(me + 60*he)) + *ts_end /10;
- return buf;
- }
- }
- return NULL;
+ while (dst->len >= 2 && !strncmp(&dst->str[dst->len - 2], "\\N", 2))
+ dst->len -= 2;
+ dst->str[dst->len] = 0;
+ rstrip_spaces_buf(dst);
}
static int srt_decode_frame(AVCodecContext *avctx,
void *data, int *got_sub_ptr, AVPacket *avpkt)
{
AVSubtitle *sub = data;
+ AVBPrint buffer;
int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
- char buffer[2048];
- const char *ptr = avpkt->data;
- const char *end = avpkt->data + avpkt->size;
+ int size, ret;
+ const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size);
+
+ if (p && size == 16) {
+ x1 = AV_RL32(p );
+ y1 = AV_RL32(p + 4);
+ x2 = AV_RL32(p + 8);
+ y2 = AV_RL32(p + 12);
+ }
if (avpkt->size <= 0)
return avpkt->size;
- ff_ass_init(sub);
+ av_bprint_init(&buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
- while (ptr < end && *ptr) {
- ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2);
- if (!ptr)
- break;
- ptr = srt_to_ass(avctx, buffer, buffer+sizeof(buffer), ptr,
- x1, y1, x2, y2);
- ff_ass_add_rect(sub, buffer, ts_start, ts_end, 0);
- }
+ // TODO: reindent
+ // Do final divide-by-10 outside rescale to force rounding down.
+ ts_start = av_rescale_q(avpkt->pts,
+ avctx->time_base,
+ (AVRational){1,100});
+ ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
+ avctx->time_base,
+ (AVRational){1,100});
+
+ srt_to_ass(avctx, &buffer, avpkt->data, x1, y1, x2, y2);
+ ret = ff_ass_add_rect_bprint(sub, &buffer, ts_start, ts_end-ts_start);
+ av_bprint_finalize(&buffer, NULL);
+ if (ret < 0)
+ return ret;
*got_sub_ptr = sub->num_rects > 0;
return avpkt->size;
}
+#if CONFIG_SRT_DECODER
+/* deprecated decoder */
AVCodec ff_srt_decoder = {
.name = "srt",
.long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
.type = AVMEDIA_TYPE_SUBTITLE,
- .id = AV_CODEC_ID_SRT,
+ .id = AV_CODEC_ID_SUBRIP,
+ .init = ff_ass_subtitle_header_default,
+ .decode = srt_decode_frame,
+};
+#endif
+
+#if CONFIG_SUBRIP_DECODER
+AVCodec ff_subrip_decoder = {
+ .name = "subrip",
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SUBRIP,
.init = ff_ass_subtitle_header_default,
.decode = srt_decode_frame,
};
+#endif
diff --git a/libavcodec/srtenc.c b/libavcodec/srtenc.c
new file mode 100644
index 0000000000..328797089c
--- /dev/null
+++ b/libavcodec/srtenc.c
@@ -0,0 +1,295 @@
+/*
+ * SubRip subtitle encoder
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdarg.h>
+#include "avcodec.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "ass_split.h"
+#include "ass.h"
+
+
+#define SRT_STACK_SIZE 64
+
+typedef struct {
+ AVCodecContext *avctx;
+ ASSSplitContext *ass_ctx;
+ AVBPrint buffer;
+ char stack[SRT_STACK_SIZE];
+ int stack_ptr;
+ int alignment_applied;
+} SRTContext;
+
+
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+static void srt_print(SRTContext *s, const char *str, ...)
+{
+ va_list vargs;
+ va_start(vargs, str);
+ av_vbprintf(&s->buffer, str, vargs);
+ va_end(vargs);
+}
+
+static int srt_stack_push(SRTContext *s, const char c)
+{
+ if (s->stack_ptr >= SRT_STACK_SIZE)
+ return -1;
+ s->stack[s->stack_ptr++] = c;
+ return 0;
+}
+
+static char srt_stack_pop(SRTContext *s)
+{
+ if (s->stack_ptr <= 0)
+ return 0;
+ return s->stack[--s->stack_ptr];
+}
+
+static int srt_stack_find(SRTContext *s, const char c)
+{
+ int i;
+ for (i = s->stack_ptr-1; i >= 0; i--)
+ if (s->stack[i] == c)
+ break;
+ return i;
+}
+
+static void srt_close_tag(SRTContext *s, char tag)
+{
+ srt_print(s, "</%c%s>", tag, tag == 'f' ? "ont" : "");
+}
+
+static void srt_stack_push_pop(SRTContext *s, const char c, int close)
+{
+ if (close) {
+ int i = c ? srt_stack_find(s, c) : 0;
+ if (i < 0)
+ return;
+ while (s->stack_ptr != i)
+ srt_close_tag(s, srt_stack_pop(s));
+ } else if (srt_stack_push(s, c) < 0)
+ av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
+}
+
+static void srt_style_apply(SRTContext *s, const char *style)
+{
+ ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
+ if (st) {
+ int c = st->primary_color & 0xFFFFFF;
+ if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT) ||
+ st->font_size != ASS_DEFAULT_FONT_SIZE ||
+ c != ASS_DEFAULT_COLOR) {
+ srt_print(s, "<font");
+ if (st->font_name && strcmp(st->font_name, ASS_DEFAULT_FONT))
+ srt_print(s, " face=\"%s\"", st->font_name);
+ if (st->font_size != ASS_DEFAULT_FONT_SIZE)
+ srt_print(s, " size=\"%d\"", st->font_size);
+ if (c != ASS_DEFAULT_COLOR)
+ srt_print(s, " color=\"#%06x\"",
+ (c & 0xFF0000) >> 16 | c & 0xFF00 | (c & 0xFF) << 16);
+ srt_print(s, ">");
+ srt_stack_push(s, 'f');
+ }
+ if (st->bold != ASS_DEFAULT_BOLD) {
+ srt_print(s, "<b>");
+ srt_stack_push(s, 'b');
+ }
+ if (st->italic != ASS_DEFAULT_ITALIC) {
+ srt_print(s, "<i>");
+ srt_stack_push(s, 'i');
+ }
+ if (st->underline != ASS_DEFAULT_UNDERLINE) {
+ srt_print(s, "<u>");
+ srt_stack_push(s, 'u');
+ }
+ if (st->alignment != ASS_DEFAULT_ALIGNMENT) {
+ srt_print(s, "{\\an%d}", st->alignment);
+ s->alignment_applied = 1;
+ }
+ }
+}
+
+
+static av_cold int srt_encode_init(AVCodecContext *avctx)
+{
+ SRTContext *s = avctx->priv_data;
+ s->avctx = avctx;
+ s->ass_ctx = ff_ass_split(avctx->subtitle_header);
+ av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
+ return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
+}
+
+static void srt_text_cb(void *priv, const char *text, int len)
+{
+ SRTContext *s = priv;
+ av_bprint_append_data(&s->buffer, text, len);
+}
+
+static void srt_new_line_cb(void *priv, int forced)
+{
+ srt_print(priv, "\r\n");
+}
+
+static void srt_style_cb(void *priv, char style, int close)
+{
+ srt_stack_push_pop(priv, style, close);
+ if (!close)
+ srt_print(priv, "<%c>", style);
+}
+
+static void srt_color_cb(void *priv, unsigned int color, unsigned int color_id)
+{
+ if (color_id > 1)
+ return;
+ srt_stack_push_pop(priv, 'f', color == 0xFFFFFFFF);
+ if (color != 0xFFFFFFFF)
+ srt_print(priv, "<font color=\"#%06x\">",
+ (color & 0xFF0000) >> 16 | color & 0xFF00 | (color & 0xFF) << 16);
+}
+
+static void srt_font_name_cb(void *priv, const char *name)
+{
+ srt_stack_push_pop(priv, 'f', !name);
+ if (name)
+ srt_print(priv, "<font face=\"%s\">", name);
+}
+
+static void srt_font_size_cb(void *priv, int size)
+{
+ srt_stack_push_pop(priv, 'f', size < 0);
+ if (size >= 0)
+ srt_print(priv, "<font size=\"%d\">", size);
+}
+
+static void srt_alignment_cb(void *priv, int alignment)
+{
+ SRTContext *s = priv;
+ if (!s->alignment_applied && alignment >= 0) {
+ srt_print(s, "{\\an%d}", alignment);
+ s->alignment_applied = 1;
+ }
+}
+
+static void srt_cancel_overrides_cb(void *priv, const char *style)
+{
+ srt_stack_push_pop(priv, 0, 1);
+ srt_style_apply(priv, style);
+}
+
+static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2,
+ int t1, int t2)
+{
+ // TODO: add a AV_PKT_DATA_SUBTITLE_POSITION side data when a new subtitles
+ // encoding API passing the AVPacket is available.
+}
+
+static void srt_end_cb(void *priv)
+{
+ srt_stack_push_pop(priv, 0, 1);
+}
+
+static const ASSCodesCallbacks srt_callbacks = {
+ .text = srt_text_cb,
+ .new_line = srt_new_line_cb,
+ .style = srt_style_cb,
+ .color = srt_color_cb,
+ .font_name = srt_font_name_cb,
+ .font_size = srt_font_size_cb,
+ .alignment = srt_alignment_cb,
+ .cancel_overrides = srt_cancel_overrides_cb,
+ .move = srt_move_cb,
+ .end = srt_end_cb,
+};
+
+static int srt_encode_frame(AVCodecContext *avctx,
+ unsigned char *buf, int bufsize, const AVSubtitle *sub)
+{
+ SRTContext *s = avctx->priv_data;
+ ASSDialog *dialog;
+ int i, num;
+
+ av_bprint_clear(&s->buffer);
+
+ for (i=0; i<sub->num_rects; i++) {
+
+ if (sub->rects[i]->type != SUBTITLE_ASS) {
+ av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+ return AVERROR(ENOSYS);
+ }
+
+ dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
+ for (; dialog && num--; dialog++) {
+ s->alignment_applied = 0;
+ srt_style_apply(s, dialog->style);
+ ff_ass_split_override_codes(&srt_callbacks, s, dialog->text);
+ }
+ }
+
+ if (!av_bprint_is_complete(&s->buffer))
+ return AVERROR(ENOMEM);
+ if (!s->buffer.len)
+ return 0;
+
+ if (s->buffer.len > bufsize) {
+ av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
+ return -1;
+ }
+ memcpy(buf, s->buffer.str, s->buffer.len);
+
+ return s->buffer.len;
+}
+
+static int srt_encode_close(AVCodecContext *avctx)
+{
+ SRTContext *s = avctx->priv_data;
+ ff_ass_split_free(s->ass_ctx);
+ av_bprint_finalize(&s->buffer, NULL);
+ return 0;
+}
+
+#if CONFIG_SRT_ENCODER
+/* deprecated encoder */
+AVCodec ff_srt_encoder = {
+ .name = "srt",
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SUBRIP,
+ .priv_data_size = sizeof(SRTContext),
+ .init = srt_encode_init,
+ .encode_sub = srt_encode_frame,
+ .close = srt_encode_close,
+};
+#endif
+
+#if CONFIG_SUBRIP_ENCODER
+AVCodec ff_subrip_encoder = {
+ .name = "subrip",
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SUBRIP,
+ .priv_data_size = sizeof(SRTContext),
+ .init = srt_encode_init,
+ .encode_sub = srt_encode_frame,
+ .close = srt_encode_close,
+};
+#endif
diff --git a/libavcodec/startcode.c b/libavcodec/startcode.c
index d34981e67d..940bbb7107 100644
--- a/libavcodec/startcode.c
+++ b/libavcodec/startcode.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/startcode.h b/libavcodec/startcode.h
index f38ce54d6d..cfa02b0860 100644
--- a/libavcodec/startcode.h
+++ b/libavcodec/startcode.h
@@ -1,21 +1,27 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/**
+ * @file
+ * Accelerated start code search function for start codes common to
+ * MPEG-1/2/4 video, VC-1, H.264/5
+ */
+
#ifndef AVCODEC_STARTCODE_H
#define AVCODEC_STARTCODE_H
diff --git a/libavcodec/subviewerdec.c b/libavcodec/subviewerdec.c
new file mode 100644
index 0000000000..a008828540
--- /dev/null
+++ b/libavcodec/subviewerdec.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * SubViewer subtitle decoder
+ * @see https://en.wikipedia.org/wiki/SubViewer
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/bprint.h"
+
+static int subviewer_event_to_ass(AVBPrint *buf, const char *p)
+{
+ while (*p) {
+ if (!strncmp(p, "[br]", 4)) {
+ av_bprintf(buf, "\\N");
+ p += 4;
+ } else {
+ if (p[0] == '\n' && p[1])
+ av_bprintf(buf, "\\N");
+ else if (*p != '\n' && *p != '\r')
+ av_bprint_chars(buf, *p, 1);
+ p++;
+ }
+ }
+
+ return 0;
+}
+
+static int subviewer_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ int ret = 0;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ // note: no need to rescale pts & duration since they are in the same
+ // timebase as ASS (1/100)
+ if (ptr && avpkt->size > 0 && !subviewer_event_to_ass(&buf, ptr))
+ ret = ff_ass_add_rect_bprint(sub, &buf, avpkt->pts, avpkt->duration);
+ av_bprint_finalize(&buf, NULL);
+ if (ret < 0)
+ return ret;
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_subviewer_decoder = {
+ .name = "subviewer",
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SUBVIEWER,
+ .decode = subviewer_decode_frame,
+ .init = ff_ass_subtitle_header_default,
+};
diff --git a/libavcodec/sunrast.c b/libavcodec/sunrast.c
index ffa685c19f..3fbec1dfbf 100644
--- a/libavcodec/sunrast.c
+++ b/libavcodec/sunrast.c
@@ -2,20 +2,20 @@
* Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image decoder
* Copyright (c) 2007, 2008 Ivo van Poorten
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,7 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
const uint8_t *buf_end = avpkt->data + avpkt->size;
AVFrame * const p = data;
unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen;
- uint8_t *ptr;
+ uint8_t *ptr, *ptr2 = NULL;
const uint8_t *bufstart = buf;
int ret;
@@ -53,7 +53,7 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
maplength = AV_RB32(buf + 28);
buf += 32;
- if (type == RT_FORMAT_TIFF || type == RT_FORMAT_IFF || type == RT_EXPERIMENTAL) {
+ if (type == RT_EXPERIMENTAL) {
avpriv_request_sample(avctx, "TIFF/IFF/EXPERIMENTAL (compression) type");
return AVERROR_PATCHWELCOME;
}
@@ -70,10 +70,17 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
+ if (type == RT_FORMAT_TIFF || type == RT_FORMAT_IFF) {
+ av_log(avctx, AV_LOG_ERROR, "unsupported (compression) type\n");
+ return -1;
+ }
switch (depth) {
case 1:
- avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
+ avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_MONOWHITE;
+ break;
+ case 4:
+ avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_NONE;
break;
case 8:
avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8;
@@ -81,6 +88,9 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
case 24:
avctx->pix_fmt = (type == RT_FORMAT_RGB) ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_BGR24;
break;
+ case 32:
+ avctx->pix_fmt = (type == RT_FORMAT_RGB) ? AV_PIX_FMT_0RGB : AV_PIX_FMT_0BGR;
+ break;
default:
av_log(avctx, AV_LOG_ERROR, "invalid depth\n");
return AVERROR_INVALIDDATA;
@@ -90,17 +100,15 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
if (ret < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
if (buf_end - buf < maplength)
return AVERROR_INVALIDDATA;
- if (depth != 8 && maplength) {
+ if (depth > 8 && maplength) {
av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n");
} else if (maplength) {
@@ -113,13 +121,20 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
ptr = p->data[1];
for (x = 0; x < len; x++, ptr += 4)
- *(uint32_t *)ptr = (buf[x] << 16) + (buf[len + x] << 8) + buf[len + len + x];
+ *(uint32_t *)ptr = (0xFFU<<24) + (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x];
}
buf += maplength;
+ if (maplength && depth < 8) {
+ ptr = ptr2 = av_malloc_array((w + 15), h);
+ if (!ptr)
+ return AVERROR(ENOMEM);
+ stride = (w + 15 >> 3) * depth;
+ } else {
ptr = p->data[0];
stride = p->linesize[0];
+ }
/* scanlines are aligned on 16 bit boundaries */
len = (depth * w + 7) >> 3;
@@ -160,6 +175,30 @@ static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
buf += alen;
}
}
+ if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && depth < 8) {
+ uint8_t *ptr_free = ptr2;
+ ptr = p->data[0];
+ for (y=0; y<h; y++) {
+ for (x = 0; x < (w + 7 >> 3) * depth; x++) {
+ if (depth == 1) {
+ ptr[8*x] = ptr2[x] >> 7;
+ ptr[8*x+1] = ptr2[x] >> 6 & 1;
+ ptr[8*x+2] = ptr2[x] >> 5 & 1;
+ ptr[8*x+3] = ptr2[x] >> 4 & 1;
+ ptr[8*x+4] = ptr2[x] >> 3 & 1;
+ ptr[8*x+5] = ptr2[x] >> 2 & 1;
+ ptr[8*x+6] = ptr2[x] >> 1 & 1;
+ ptr[8*x+7] = ptr2[x] & 1;
+ } else {
+ ptr[2*x] = ptr2[x] >> 4;
+ ptr[2*x+1] = ptr2[x] & 0xF;
+ }
+ }
+ ptr += p->linesize[0];
+ ptr2 += (w + 15 >> 3) * depth;
+ }
+ av_freep(&ptr_free);
+ }
*got_frame = 1;
diff --git a/libavcodec/sunrast.h b/libavcodec/sunrast.h
index d9fe307b67..d162e63b45 100644
--- a/libavcodec/sunrast.h
+++ b/libavcodec/sunrast.h
@@ -2,20 +2,20 @@
* Sun Rasterfile Image Format
* Copyright (c) 2007, 2008 Ivo van Poorten
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/sunrastenc.c b/libavcodec/sunrastenc.c
index 8e90a6cc87..cff8c85c3f 100644
--- a/libavcodec/sunrastenc.c
+++ b/libavcodec/sunrastenc.c
@@ -2,20 +2,20 @@
* Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image encoder
* Copyright (c) 2012 Aneesh Dogra (lionaneesh) <lionaneesh@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,7 +55,7 @@ static void sunrast_image_write_image(AVCodecContext *avctx,
{
SUNRASTContext *s = avctx->priv_data;
const uint8_t *ptr;
- int len, alen, x;
+ int len, alen, x, y;
if (s->maplength) { // palettized
PutByteContext pb_r, pb_g;
@@ -82,33 +82,29 @@ static void sunrast_image_write_image(AVCodecContext *avctx,
if (s->type == RT_BYTE_ENCODED) {
uint8_t value, value2;
int run;
- const uint8_t *start = linesize < 0 ? pixels + (avctx->height - 1) * linesize
- : pixels;
- const uint8_t *end = linesize < 0 ? pixels - linesize
- : pixels + avctx->height * linesize;
ptr = pixels;
-#define GET_VALUE ptr >= end || ptr < start ? 0 : x >= len ? ptr[len-1] : ptr[x]
+#define GET_VALUE y >= avctx->height ? 0 : x >= len ? ptr[len-1] : ptr[x]
- x = 0;
+ x = 0, y = 0;
value2 = GET_VALUE;
- while (ptr < end && ptr >= start) {
+ while (y < avctx->height) {
run = 1;
value = value2;
x++;
if (x >= alen) {
x = 0;
- ptr += linesize;
+ ptr += linesize, y++;
}
value2 = GET_VALUE;
- while (value2 == value && run < 256 && ptr < end && ptr >= start) {
+ while (value2 == value && run < 256 && y < avctx->height) {
x++;
run++;
if (x >= alen) {
x = 0;
- ptr += linesize;
+ ptr += linesize, y++;
}
value2 = GET_VALUE;
}
@@ -127,7 +123,6 @@ static void sunrast_image_write_image(AVCodecContext *avctx,
// update data length for header
s->length = bytestream2_tell_p(&s->p) - 32 - s->maplength;
} else {
- int y;
for (y = 0; y < avctx->height; y++) {
bytestream2_put_buffer(&s->p, ptr, len);
if (len < alen)
@@ -153,12 +148,6 @@ static av_cold int sunrast_encode_init(AVCodecContext *avctx)
return AVERROR(EINVAL);
}
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- avctx->coded_frame->key_frame = 1;
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
s->maptype = RMT_NONE;
s->maplength = 0;
@@ -192,7 +181,7 @@ static int sunrast_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
SUNRASTContext *s = avctx->priv_data;
int ret;
- if ((ret = ff_alloc_packet(avpkt, s->size)) < 0)
+ if ((ret = ff_alloc_packet2(avctx, avpkt, s->size)) < 0)
return ret;
bytestream2_init_writer(&s->p, avpkt->data, avpkt->size);
diff --git a/libavcodec/svq1.c b/libavcodec/svq1.c
index 545df80974..909b0bf5cc 100644
--- a/libavcodec/svq1.c
+++ b/libavcodec/svq1.c
@@ -3,25 +3,25 @@
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
- * Copyright (C) 2002 the xine project
- * Copyright (C) 2002 the ffmpeg project
+ * Copyright (c) 2002 The Xine Project
+ * Copyright (c) 2002 The FFmpeg Project
*
* SVQ1 Encoder (c) 2004 Mike Melanson <melanson@pcisys.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/svq1.h b/libavcodec/svq1.h
index 70b5c37be2..88d61d1e39 100644
--- a/libavcodec/svq1.h
+++ b/libavcodec/svq1.h
@@ -3,25 +3,25 @@
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
- * Copyright (C) 2002 the xine project
- * Copyright (C) 2002 the ffmpeg project
+ * Copyright (c) 2002 The Xine Project
+ * Copyright (c) 2002 The FFmpeg Project
*
* SVQ1 Encoder (c) 2004 Mike Melanson <melanson@pcisys.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/svq13.c b/libavcodec/svq13.c
index e0d21544d9..b821a446d6 100644
--- a/libavcodec/svq13.c
+++ b/libavcodec/svq13.c
@@ -1,20 +1,20 @@
/*
* SVQ1/SVQ3 decoder common code
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/svq1_cb.h b/libavcodec/svq1_cb.h
index e22cd60e23..41485d2af4 100644
--- a/libavcodec/svq1_cb.h
+++ b/libavcodec/svq1_cb.h
@@ -3,23 +3,23 @@
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
- * Copyright (C) 2002 the xine project
- * Copyright (C) 2002 the ffmpeg project
+ * Copyright (c) 2002 The Xine Project
+ * Copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/svq1_vlc.h b/libavcodec/svq1_vlc.h
index 834279dac4..f5d298dfa1 100644
--- a/libavcodec/svq1_vlc.h
+++ b/libavcodec/svq1_vlc.h
@@ -1,20 +1,20 @@
/*
- * copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/svq1dec.c b/libavcodec/svq1dec.c
index 6436881509..21d4acf87d 100644
--- a/libavcodec/svq1dec.c
+++ b/libavcodec/svq1dec.c
@@ -3,25 +3,25 @@
* ported to MPlayer by Arpi <arpi@thot.banki.hu>
* ported to libavcodec by Nick Kurshev <nickols_k@mail.ru>
*
- * Copyright (C) 2002 the xine project
- * Copyright (C) 2002 the ffmpeg project
+ * Copyright (c) 2002 The Xine Project
+ * Copyright (c) 2002 The FFmpeg Project
*
* SVQ1 Encoder (c) 2004 Mike Melanson <melanson@pcisys.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,9 +40,6 @@
#include "mathops.h"
#include "svq1.h"
-#undef NDEBUG
-#include <assert.h>
-
static VLC svq1_block_type;
static VLC svq1_motion_component;
static VLC svq1_intra_multistage[6];
@@ -114,12 +111,11 @@ static const uint8_t string_table[256] = {
break; \
} \
/* divide block if next bit set */ \
- if (get_bits1(bitbuf) == 0) \
+ if (!get_bits1(bitbuf)) \
break; \
/* add child nodes */ \
list[n++] = list[i]; \
- list[n++] = list[i] + \
- (((level & 1) ? pitch : 1) << (level / 2 + 1)); \
+ list[n++] = list[i] + (((level & 1) ? pitch : 1) << ((level >> 1) + 1));\
}
#define SVQ1_ADD_CODEBOOK() \
@@ -155,7 +151,7 @@ static const uint8_t string_table[256] = {
16 * j) << (level + 1); \
} \
mean -= stages * 128; \
- n4 = mean + (mean >> 31) << 16 | (mean & 0xFFFF);
+ n4 = (mean << 16) + mean;
static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels,
int pitch)
@@ -166,7 +162,8 @@ static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels,
const uint32_t *codebook;
int entries[6];
int i, j, m, n;
- int mean, stages;
+ int stages;
+ unsigned mean;
unsigned x, y, width, height, level;
uint32_t n1, n2, n3, n4;
@@ -191,12 +188,13 @@ static int svq1_decode_block_intra(GetBitContext *bitbuf, uint8_t *pixels,
continue; /* skip vector */
}
- if ((stages > 0 && level >= 4) || stages < 0) {
+ if ((stages > 0 && level >= 4)) {
ff_dlog(NULL,
"Error (svq1_decode_block_intra): invalid vector: stages=%i level=%i\n",
stages, level);
return AVERROR_INVALIDDATA; /* invalid vector */
}
+ av_assert0(stages >= 0);
mean = get_vlc2(bitbuf, svq1_intra_mean.table, 8, 3);
@@ -231,7 +229,8 @@ static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels,
const uint32_t *codebook;
int entries[6];
int i, j, m, n;
- int mean, stages;
+ int stages;
+ unsigned mean;
int x, y, width, height, level;
uint32_t n1, n2, n3, n4;
@@ -253,12 +252,13 @@ static int svq1_decode_block_non_intra(GetBitContext *bitbuf, uint8_t *pixels,
if (stages == -1)
continue; /* skip vector */
- if ((stages > 0 && level >= 4) || stages < 0) {
+ if ((stages > 0 && level >= 4)) {
ff_dlog(NULL,
"Error (svq1_decode_block_non_intra): invalid vector: stages=%i level=%i\n",
stages, level);
return AVERROR_INVALIDDATA; /* invalid vector */
}
+ av_assert0(stages >= 0);
mean = get_vlc2(bitbuf, svq1_inter_mean.table, 9, 3) - 256;
@@ -345,8 +345,7 @@ static int svq1_motion_inter_block(HpelDSPContext *hdsp, GetBitContext *bitbuf,
}
result = svq1_decode_motion_vector(bitbuf, &mv, pmv);
-
- if (result != 0)
+ if (result)
return result;
motion[0].x =
@@ -389,8 +388,7 @@ static int svq1_motion_inter_4v_block(HpelDSPContext *hdsp, GetBitContext *bitbu
}
result = svq1_decode_motion_vector(bitbuf, &mv, pmv);
-
- if (result != 0)
+ if (result)
return result;
/* predict and decode motion vector (1) */
@@ -402,8 +400,7 @@ static int svq1_motion_inter_4v_block(HpelDSPContext *hdsp, GetBitContext *bitbu
pmv[1] = &motion[(x / 8) + 3];
}
result = svq1_decode_motion_vector(bitbuf, &motion[0], pmv);
-
- if (result != 0)
+ if (result)
return result;
/* predict and decode motion vector (2) */
@@ -411,8 +408,7 @@ static int svq1_motion_inter_4v_block(HpelDSPContext *hdsp, GetBitContext *bitbu
pmv[2] = &motion[(x / 8) + 1];
result = svq1_decode_motion_vector(bitbuf, &motion[(x / 8) + 2], pmv);
-
- if (result != 0)
+ if (result)
return result;
/* predict and decode motion vector (3) */
@@ -420,8 +416,7 @@ static int svq1_motion_inter_4v_block(HpelDSPContext *hdsp, GetBitContext *bitbu
pmv[3] = &motion[(x / 8) + 3];
result = svq1_decode_motion_vector(bitbuf, pmv[3], pmv);
-
- if (result != 0)
+ if (result)
return result;
/* form predictions */
@@ -505,7 +500,7 @@ static int svq1_decode_delta_block(AVCodecContext *avctx, HpelDSPContext *hdsp,
return result;
}
-static void svq1_parse_string(GetBitContext *bitbuf, uint8_t *out)
+static void svq1_parse_string(GetBitContext *bitbuf, uint8_t out[257])
{
uint8_t seed;
int i;
@@ -517,6 +512,7 @@ static void svq1_parse_string(GetBitContext *bitbuf, uint8_t *out)
out[i] = get_bits(bitbuf, 8) ^ seed;
seed = string_table[out[i] ^ seed];
}
+ out[i] = 0;
}
static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
@@ -524,6 +520,8 @@ static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
SVQ1Context *s = avctx->priv_data;
GetBitContext *bitbuf = &s->gb;
int frame_size_code;
+ int width = s->width;
+ int height = s->height;
skip_bits(bitbuf, 8); /* temporal_reference */
@@ -557,12 +555,12 @@ static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
}
if ((s->frame_code ^ 0x10) >= 0x50) {
- uint8_t msg[256];
+ uint8_t msg[257];
svq1_parse_string(bitbuf, msg);
av_log(avctx, AV_LOG_INFO,
- "embedded message: \"%s\"\n", (char *)msg);
+ "embedded message:\n%s\n", ((char *)msg) + 1);
}
skip_bits(bitbuf, 2);
@@ -574,20 +572,20 @@ static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
if (frame_size_code == 7) {
/* load width, height (12 bits each) */
- s->width = get_bits(bitbuf, 12);
- s->height = get_bits(bitbuf, 12);
+ width = get_bits(bitbuf, 12);
+ height = get_bits(bitbuf, 12);
- if (!s->width || !s->height)
+ if (!width || !height)
return AVERROR_INVALIDDATA;
} else {
/* get width, height from table */
- s->width = ff_svq1_frame_size_table[frame_size_code][0];
- s->height = ff_svq1_frame_size_table[frame_size_code][1];
+ width = ff_svq1_frame_size_table[frame_size_code][0];
+ height = ff_svq1_frame_size_table[frame_size_code][1];
}
}
/* unknown fields */
- if (get_bits1(bitbuf) == 1) {
+ if (get_bits1(bitbuf)) {
skip_bits1(bitbuf); /* use packet checksum if (1) */
skip_bits1(bitbuf); /* component checksums after image data if (1) */
@@ -595,16 +593,18 @@ static int svq1_decode_frame_header(AVCodecContext *avctx, AVFrame *frame)
return AVERROR_INVALIDDATA;
}
- if (get_bits1(bitbuf) == 1) {
+ if (get_bits1(bitbuf)) {
skip_bits1(bitbuf);
skip_bits(bitbuf, 4);
skip_bits1(bitbuf);
skip_bits(bitbuf, 2);
- while (get_bits1(bitbuf) == 1)
- skip_bits(bitbuf, 8);
+ if (skip_1stop_8data_bits(bitbuf) < 0)
+ return AVERROR_INVALIDDATA;
}
+ s->width = width;
+ s->height = height;
return 0;
}
@@ -620,7 +620,7 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data,
svq1_pmv *pmv;
/* initialize bit buffer */
- init_get_bits(&s->gb, buf, buf_size * 8);
+ init_get_bits8(&s->gb, buf, buf_size);
/* decode frame header */
s->frame_code = get_bits(&s->gb, 22);
@@ -655,7 +655,6 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data,
}
result = svq1_decode_frame_header(avctx, cur);
-
if (result != 0) {
ff_dlog(avctx, "Error in svq1_decode_frame_header %i\n", result);
return result;
@@ -700,8 +699,8 @@ static int svq1_decode_frame(AVCodecContext *avctx, void *data,
for (x = 0; x < width; x += 16) {
result = svq1_decode_block_intra(&s->gb, &current[x],
linesize);
- if (result != 0) {
- av_log(avctx, AV_LOG_INFO,
+ if (result) {
+ av_log(avctx, AV_LOG_ERROR,
"Error in svq1_decode_block %i (keyframe)\n",
result);
goto err;
@@ -819,6 +818,7 @@ static av_cold int svq1_decode_end(AVCodecContext *avctx)
av_frame_free(&s->prev);
av_freep(&s->pkt_swapped);
+ s->pkt_swapped_allocated = 0;
return 0;
}
diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c
index 8677503b4f..3fc7ecaa52 100644
--- a/libavcodec/svq1enc.c
+++ b/libavcodec/svq1enc.c
@@ -2,20 +2,20 @@
* SVQ1 Encoder
* Copyright (C) 2004 Mike Melanson <melanson@pcisys.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,9 +36,8 @@
#include "svq1.h"
#include "svq1enc.h"
#include "svq1enc_cb.h"
+#include "libavutil/avassert.h"
-#undef NDEBUG
-#include <assert.h>
static void svq1_write_header(SVQ1EncContext *s, int frame_type)
{
@@ -59,7 +58,7 @@ static void svq1_write_header(SVQ1EncContext *s, int frame_type)
/* output 5 unknown bits (2 + 2 + 1) */
put_bits(&s->pb, 5, 2); /* 2 needed by quicktime decoder */
- i = ff_match_2uint16(ff_svq1_frame_size_table,
+ i = ff_match_2uint16((void*)ff_svq1_frame_size_table,
FF_ARRAY_ELEMS(ff_svq1_frame_size_table),
s->frame_width, s->frame_height);
put_bits(&s->pb, 3, i);
@@ -78,7 +77,7 @@ static void svq1_write_header(SVQ1EncContext *s, int frame_type)
#define THRESHOLD_MULTIPLIER 0.6
static int ssd_int8_vs_int16_c(const int8_t *pix1, const int16_t *pix2,
- int size)
+ intptr_t size)
{
int score = 0, i;
@@ -97,7 +96,7 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
int w = 2 << (level + 2 >> 1);
int h = 2 << (level + 1 >> 1);
int size = w * h;
- int16_t block[7][256];
+ int16_t (*block)[256] = s->encoded_block_levels[level];
const int8_t *codebook_sum, *codebook;
const uint16_t(*mean_vlc)[2];
const uint8_t(*multistage_vlc)[2];
@@ -153,7 +152,7 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
score = sqr - (diff * (int64_t)diff >> (level + 3)); // FIXME: 64bit slooow
if (score < best_vector_score) {
int mean = diff + (size >> 1) >> (level + 3);
- assert(mean > -300 && mean < 300);
+ av_assert2(mean > -300 && mean < 300);
mean = av_clip(mean, intra ? 0 : -256, 255);
best_vector_score = score;
best_vector[stage] = i;
@@ -161,7 +160,7 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
best_vector_mean = mean;
}
}
- assert(best_vector_mean != -999);
+ av_assert0(best_vector_mean != -999);
vector = codebook + stage * size * 16 + best_vector[stage] * size;
for (j = 0; j < size; j++)
block[stage + 1][j] = block[stage][j] - vector[j];
@@ -205,10 +204,10 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
put_bits(&s->reorder_pb[level], 1, split);
if (!split) {
- assert(best_mean >= 0 && best_mean < 256 || !intra);
- assert(best_mean >= -256 && best_mean < 256);
- assert(best_count >= 0 && best_count < 7);
- assert(level < 4 || best_count == 0);
+ av_assert1(best_mean >= 0 && best_mean < 256 || !intra);
+ av_assert1(best_mean >= -256 && best_mean < 256);
+ av_assert1(best_count >= 0 && best_count < 7);
+ av_assert1(level < 4 || best_count == 0);
/* output the encoding */
put_bits(&s->reorder_pb[level],
@@ -218,7 +217,7 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
mean_vlc[best_mean][0]);
for (i = 0; i < best_count; i++) {
- assert(best_vector[i] >= 0 && best_vector[i] < 16);
+ av_assert2(best_vector[i] >= 0 && best_vector[i] < 16);
put_bits(&s->reorder_pb[level], 4, best_vector[i]);
}
@@ -232,6 +231,15 @@ static int encode_block(SVQ1EncContext *s, uint8_t *src, uint8_t *ref,
return best_score;
}
+static void init_block_index(MpegEncContext *s){
+ s->block_index[0]= s->b8_stride*(s->mb_y*2 ) + s->mb_x*2;
+ s->block_index[1]= s->b8_stride*(s->mb_y*2 ) + 1 + s->mb_x*2;
+ s->block_index[2]= s->b8_stride*(s->mb_y*2 + 1) + s->mb_x*2;
+ s->block_index[3]= s->b8_stride*(s->mb_y*2 + 1) + 1 + s->mb_x*2;
+ s->block_index[4]= s->mb_stride*(s->mb_y + 1) + s->b8_stride*s->mb_height*2 + s->mb_x;
+ s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x;
+}
+
static int svq1_encode_plane(SVQ1EncContext *s, int plane,
unsigned char *src_plane,
unsigned char *ref_plane,
@@ -244,7 +252,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
int block_width, block_height;
int level;
int threshold[6];
- uint8_t *src = s->scratchbuf + stride * 16;
+ uint8_t *src = s->scratchbuf + stride * 32;
const int lambda = (f->quality * f->quality) >>
(2 * FF_LAMBDA_SHIFT);
@@ -292,6 +300,8 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
s->motion_val16[plane] = av_mallocz((s->m.mb_stride *
(block_height + 2) + 1) *
2 * sizeof(int16_t));
+ if (!s->motion_val8[plane] || !s->motion_val16[plane])
+ return AVERROR(ENOMEM);
}
s->m.mb_type = s->mb_type;
@@ -326,8 +336,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
for (x = 0; x < block_width; x++) {
s->m.mb_x = x;
- ff_init_block_index(&s->m);
- ff_update_block_index(&s->m);
+ init_block_index(&s->m);
ff_estimate_p_frame_motion(&s->m, x, y);
}
@@ -352,8 +361,8 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
s->m.mb_y = y;
for (x = 0; x < block_width; x++) {
- uint8_t reorder_buffer[3][6][7 * 32];
- int count[3][6];
+ uint8_t reorder_buffer[2][6][7 * 32];
+ int count[2][6];
int offset = y * 16 * stride + x * 16;
uint8_t *decoded = decoded_plane + offset;
uint8_t *ref = ref_plane + offset;
@@ -367,8 +376,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
}
s->m.mb_x = x;
- ff_init_block_index(&s->m);
- ff_update_block_index(&s->m);
+ init_block_index(&s->m);
if (f->pict_type == AV_PICTURE_TYPE_I ||
(s->m.mb_type[x + y * s->m.mb_stride] &
@@ -409,23 +417,23 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
s->m.pb = s->reorder_pb[5];
mx = motion_ptr[0];
my = motion_ptr[1];
- assert(mx >= -32 && mx <= 31);
- assert(my >= -32 && my <= 31);
- assert(pred_x >= -32 && pred_x <= 31);
- assert(pred_y >= -32 && pred_y <= 31);
- ff_h263_encode_motion(&s->m, mx - pred_x, 1);
- ff_h263_encode_motion(&s->m, my - pred_y, 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;
score[1] += lambda * put_bits_count(&s->reorder_pb[5]);
dxy = (mx & 1) + 2 * (my & 1);
- s->hdsp.put_pixels_tab[0][dxy](temp + 16,
+ s->hdsp.put_pixels_tab[0][dxy](temp + 16*stride,
ref + (mx >> 1) +
stride * (my >> 1),
stride, 16);
- score[1] += encode_block(s, src + 16 * x, temp + 16,
+ score[1] += encode_block(s, src + 16 * x, temp + 16*stride,
decoded, stride, 5, 64, lambda, 0);
best = score[1] <= score[0];
@@ -436,8 +444,6 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
if (score[2] < score[best] && mx == 0 && my == 0) {
best = 2;
s->hdsp.put_pixels_tab[0][0](decoded, ref, stride, 16);
- for (i = 0; i < 6; i++)
- count[2][i] = 0;
put_bits(&s->pb, vlc[1], vlc[0]);
}
}
@@ -461,6 +467,7 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane,
s->rd_total += score[best];
+ if (best != 2)
for (i = 5; i >= 0; i--)
avpriv_copy_bits(&s->pb, reorder_buffer[best][i],
count[best][i]);
@@ -549,6 +556,12 @@ static av_cold int svq1_encode_init(AVCodecContext *avctx)
s->y_block_height * sizeof(int32_t));
s->ssd_int8_vs_int16 = ssd_int8_vs_int16_c;
+ if (!s->m.me.scratchpad || !s->m.me.map || !s->m.me.score_map ||
+ !s->mb_type || !s->dummy) {
+ svq1_encode_end(avctx);
+ return AVERROR(ENOMEM);
+ }
+
if (ARCH_PPC)
ff_svq1enc_init_ppc(s);
if (ARCH_X86)
@@ -566,12 +579,9 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
AVFrame *const p = avctx->coded_frame;
int i, ret;
- if (!pkt->data &&
- (ret = av_new_packet(pkt, s->y_block_width * s->y_block_height *
- MAX_MB_BYTES * 3 + FF_MIN_BUFFER_SIZE)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, s->y_block_width * s->y_block_height *
+ MAX_MB_BYTES*3 + FF_MIN_BUFFER_SIZE)) < 0)
return ret;
- }
if (avctx->pix_fmt != AV_PIX_FMT_YUV410P) {
av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n");
@@ -579,9 +589,9 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
if (!s->current_picture->data[0]) {
- ret = ff_get_buffer(avctx, s->current_picture, 0);
- if (ret < 0)
+ if ((ret = ff_get_buffer(avctx, s->current_picture, 0)) < 0) {
return ret;
+ }
}
if (!s->last_picture->data[0]) {
ret = ff_get_buffer(avctx, s->last_picture, 0);
@@ -589,7 +599,7 @@ static int svq1_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return ret;
}
if (!s->scratchbuf) {
- s->scratchbuf = av_malloc(s->current_picture->linesize[0] * 16 * 2);
+ s->scratchbuf = av_malloc_array(s->current_picture->linesize[0], 16 * 3);
if (!s->scratchbuf)
return AVERROR(ENOMEM);
}
diff --git a/libavcodec/svq1enc.h b/libavcodec/svq1enc.h
index 516e875657..8e74885117 100644
--- a/libavcodec/svq1enc.h
+++ b/libavcodec/svq1enc.h
@@ -1,20 +1,20 @@
/*
* SVQ1 encoder
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,6 +59,8 @@ typedef struct SVQ1EncContext {
int c_block_width;
int c_block_height;
+ DECLARE_ALIGNED(16, int16_t, encoded_block_levels)[6][7][256];
+
uint16_t *mb_type;
uint32_t *dummy;
int16_t (*motion_val8[3])[2];
@@ -69,7 +71,7 @@ typedef struct SVQ1EncContext {
uint8_t *scratchbuf;
int (*ssd_int8_vs_int16)(const int8_t *pix1, const int16_t *pix2,
- int size);
+ intptr_t size);
} SVQ1EncContext;
void ff_svq1enc_init_ppc(SVQ1EncContext *c);
diff --git a/libavcodec/svq1enc_cb.h b/libavcodec/svq1enc_cb.h
index a5cd179442..1edb4ecf99 100644
--- a/libavcodec/svq1enc_cb.h
+++ b/libavcodec/svq1enc_cb.h
@@ -2,20 +2,20 @@
* SVQ1 Encoder
* Copyright (C) 2004 Mike Melanson <melanson@pcisys.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c
index 5f8eb0e6ab..0683b0dbfc 100644
--- a/libavcodec/svq3.c
+++ b/libavcodec/svq3.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2003 The Libav Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,7 +37,7 @@
*
* You will know you have these parameters passed correctly when the decoder
* correctly decodes this file:
- * http://samples.libav.org/V-codecs/SVQ3/Vertical400kbit.sorenson3.mov
+ * http://samples.mplayerhq.hu/V-codecs/SVQ3/Vertical400kbit.sorenson3.mov
*/
#include <inttypes.h>
@@ -55,6 +55,7 @@
#include "hpeldsp.h"
#include "rectangle.h"
#include "tpeldsp.h"
+#include "vdpau_internal.h"
#if CONFIG_ZLIB
#include <zlib.h>
@@ -77,9 +78,11 @@ typedef struct SVQ3Context {
H264Picture *last_pic;
int halfpel_flag;
int thirdpel_flag;
- int unknown_flag;
+ int has_watermark;
int next_slice_index;
uint32_t watermark_key;
+ uint8_t *buf;
+ int buf_size;
int adaptive_quant;
int next_p_frame_damaged;
int h_edge_pos;
@@ -159,6 +162,8 @@ static const uint32_t svq3_dequant_coeff[32] = {
61694, 68745, 77615, 89113, 100253, 109366, 126635, 141533
};
+static int svq3_decode_end(AVCodecContext *avctx);
+
void ff_svq3_luma_dc_dequant_idct_c(int16_t *output, int16_t *input, int qp)
{
const int qmul = svq3_dequant_coeff[qp];
@@ -240,14 +245,17 @@ static inline int svq3_decode_block(GetBitContext *gb, int16_t *block,
static const uint8_t *const scan_patterns[4] =
{ luma_dc_zigzag_scan, zigzag_scan, svq3_scan, chroma_dc_scan };
- int run, level, limit;
+ int run, level, sign, limit;
unsigned vlc;
const int intra = 3 * type >> 2;
const uint8_t *const scan = scan_patterns[type];
for (limit = (16 >> intra); index < 16; index = limit, limit += 8) {
for (; (vlc = svq3_get_ue_golomb(gb)) != 0; index++) {
- int sign = (vlc & 1) ? 0 : -1;
+ if ((int32_t)vlc < 0)
+ return -1;
+
+ sign = (vlc & 1) ? 0 : -1;
vlc = vlc + 1 >> 1;
if (type == 3) {
@@ -262,20 +270,19 @@ static inline int svq3_decode_block(GetBitContext *gb, int16_t *block,
level = (vlc + 9 >> 2) - run;
}
} else {
- if (vlc < 16) {
+ if (vlc < 16U) {
run = svq3_dct_tables[intra][vlc].run;
level = svq3_dct_tables[intra][vlc].level;
} else if (intra) {
run = vlc & 0x7;
- level = (vlc >> 3) +
- ((run == 0) ? 8 : ((run < 2) ? 2 : ((run < 5) ? 0 : -1)));
+ level = (vlc >> 3) + ((run == 0) ? 8 : ((run < 2) ? 2 : ((run < 5) ? 0 : -1)));
} else {
run = vlc & 0xF;
- level = (vlc >> 4) +
- ((run == 0) ? 4 : ((run < 3) ? 2 : ((run < 10) ? 1 : 0)));
+ level = (vlc >> 4) + ((run == 0) ? 4 : ((run < 3) ? 2 : ((run < 10) ? 1 : 0)));
}
}
+
if ((index += run) >= limit)
return -1;
@@ -620,7 +627,7 @@ static int svq3_decode_mb(SVQ3Context *s, unsigned int mb_type)
for (i = 0; i < 16; i += 2) {
vlc = svq3_get_ue_golomb(&h->gb);
- if (vlc >= 25) {
+ if (vlc >= 25U) {
av_log(h->avctx, AV_LOG_ERROR,
"luma prediction:%"PRIu32"\n", vlc);
return -1;
@@ -690,7 +697,7 @@ static int svq3_decode_mb(SVQ3Context *s, unsigned int mb_type)
if (!IS_INTRA16x16(mb_type) &&
(!IS_SKIP(mb_type) || h->pict_type == AV_PICTURE_TYPE_B)) {
- if ((vlc = svq3_get_ue_golomb(&h->gb)) >= 48) {
+ if ((vlc = svq3_get_ue_golomb(&h->gb)) >= 48U){
av_log(h->avctx, AV_LOG_ERROR, "cbp_vlc=%"PRIu32"\n", vlc);
return -1;
}
@@ -807,8 +814,8 @@ static int svq3_decode_slice_header(AVCodecContext *avctx)
header ^ s->watermark_key);
}
if (length > 0) {
- memcpy((uint8_t *) &h->gb.buffer[get_bits_count(&h->gb) >> 3],
- &h->gb.buffer[h->gb.size_in_bits >> 3], length - 1);
+ memmove((uint8_t *) &h->gb.buffer[get_bits_count(&h->gb) >> 3],
+ &h->gb.buffer[h->gb.size_in_bits >> 3], length - 1);
}
skip_bits_long(&h->gb, 0);
}
@@ -836,14 +843,14 @@ static int svq3_decode_slice_header(AVCodecContext *avctx)
/* unknown fields */
skip_bits1(&h->gb);
- if (s->unknown_flag)
+ if (s->has_watermark)
skip_bits1(&h->gb);
skip_bits1(&h->gb);
skip_bits(&h->gb, 2);
- while (get_bits1(&h->gb))
- skip_bits(&h->gb, 8);
+ if (skip_1stop_8data_bits(&h->gb) < 0)
+ return AVERROR_INVALIDDATA;
/* reset intra predictors and invalidate motion vector references */
if (sl->mb_x > 0) {
@@ -873,15 +880,14 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
unsigned char *extradata_end;
unsigned int size;
int marker_found = 0;
+ int ret;
s->cur_pic = av_mallocz(sizeof(*s->cur_pic));
s->last_pic = av_mallocz(sizeof(*s->last_pic));
s->next_pic = av_mallocz(sizeof(*s->next_pic));
if (!s->next_pic || !s->last_pic || !s->cur_pic) {
- av_freep(&s->cur_pic);
- av_freep(&s->last_pic);
- av_freep(&s->next_pic);
- return AVERROR(ENOMEM);
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
s->cur_pic->f = av_frame_alloc();
@@ -890,21 +896,23 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
if (!s->cur_pic->f || !s->last_pic->f || !s->next_pic->f)
return AVERROR(ENOMEM);
- if (ff_h264_decode_init(avctx) < 0)
- return -1;
+ if ((ret = ff_h264_decode_init(avctx)) < 0)
+ goto fail;
// we will overwrite it later during decoding
av_frame_free(&h->cur_pic.f);
+ av_frame_free(&h->last_pic_for_ec.f);
+
ff_h264dsp_init(&h->h264dsp, 8, 1);
- ff_h264chroma_init(&h->h264chroma, 8);
- ff_h264qpel_init(&h->h264qpel, 8);
+ av_assert0(h->sps.bit_depth_chroma == 0);
ff_h264_pred_init(&h->hpc, AV_CODEC_ID_SVQ3, 8, 1);
ff_videodsp_init(&h->vdsp, 8);
memset(h->pps.scaling_matrix4, 16, 6 * 16 * sizeof(uint8_t));
memset(h->pps.scaling_matrix8, 16, 2 * 64 * sizeof(uint8_t));
+ avctx->bits_per_raw_sample = 8;
h->sps.bit_depth_luma = 8;
h->chroma_format_idc = 1;
@@ -915,6 +923,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
h->flags = avctx->flags;
sl->is_complex = 1;
+ h->sps.chroma_format_idc = 1;
h->picture_structure = PICT_FRAME;
avctx->pix_fmt = AV_PIX_FMT_YUVJ420P;
avctx->color_range = AVCOL_RANGE_JPEG;
@@ -924,7 +933,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
s->halfpel_flag = 1;
s->thirdpel_flag = 1;
- s->unknown_flag = 0;
+ s->has_watermark = 0;
/* prowl for the "SEQH" marker in the extradata */
extradata = (unsigned char *)avctx->extradata;
@@ -943,10 +952,13 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
if (marker_found) {
GetBitContext gb;
int frame_size_code;
+ int unk0, unk1, unk2, unk3, unk4;
size = AV_RB32(&extradata[4]);
- if (size > extradata_end - extradata - 8)
- return AVERROR_INVALIDDATA;
+ if (size > extradata_end - extradata - 8) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
init_get_bits(&gb, extradata + 8, size * 8);
/* 'frame size code' and optional 'width, height' */
@@ -990,22 +1002,27 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
s->thirdpel_flag = get_bits1(&gb);
/* unknown fields */
- skip_bits1(&gb);
- skip_bits1(&gb);
- skip_bits1(&gb);
- skip_bits1(&gb);
+ unk0 = get_bits1(&gb);
+ unk1 = get_bits1(&gb);
+ unk2 = get_bits1(&gb);
+ unk3 = get_bits1(&gb);
h->low_delay = get_bits1(&gb);
/* unknown field */
- skip_bits1(&gb);
+ unk4 = get_bits1(&gb);
+
+ av_log(avctx, AV_LOG_DEBUG, "Unknown fields %d %d %d %d %d\n",
+ unk0, unk1, unk2, unk3, unk4);
- while (get_bits1(&gb))
- skip_bits(&gb, 8);
+ if (skip_1stop_8data_bits(&gb) < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
- s->unknown_flag = get_bits1(&gb);
+ s->has_watermark = get_bits1(&gb);
avctx->has_b_frames = !h->low_delay;
- if (s->unknown_flag) {
+ if (s->has_watermark) {
#if CONFIG_ZLIB
unsigned watermark_width = svq3_get_ue_golomb(&gb);
unsigned watermark_height = svq3_get_ue_golomb(&gb);
@@ -1018,11 +1035,17 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
int offset = get_bits_count(&gb) + 7 >> 3;
uint8_t *buf;
- if (watermark_height > 0 &&
- (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height)
- return -1;
+ if (watermark_height <= 0 ||
+ (uint64_t)watermark_width * 4 > UINT_MAX / watermark_height) {
+ ret = -1;
+ goto fail;
+ }
buf = av_malloc(buf_len);
+ if (!buf) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
av_log(avctx, AV_LOG_DEBUG, "watermark size: %ux%u\n",
watermark_width, watermark_height);
av_log(avctx, AV_LOG_DEBUG,
@@ -1033,7 +1056,8 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR,
"could not uncompress watermark logo\n");
av_free(buf);
- return -1;
+ ret = -1;
+ goto fail;
}
s->watermark_key = ff_svq1_packet_checksum(buf, buf_len, 0);
s->watermark_key = s->watermark_key << 16 | s->watermark_key;
@@ -1043,7 +1067,8 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
#else
av_log(avctx, AV_LOG_ERROR,
"this svq3 file contains watermark which need zlib support compiled in\n");
- return -1;
+ ret = -1;
+ goto fail;
#endif
}
}
@@ -1058,12 +1083,15 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx)
s->h_edge_pos = h->mb_width * 16;
s->v_edge_pos = h->mb_height * 16;
- if (ff_h264_alloc_tables(h) < 0) {
+ if ((ret = ff_h264_alloc_tables(h)) < 0) {
av_log(avctx, AV_LOG_ERROR, "svq3 memory allocation failed\n");
- return AVERROR(ENOMEM);
+ goto fail;
}
return 0;
+fail:
+ svq3_decode_end(avctx);
+ return ret;
}
static void free_picture(AVCodecContext *avctx, H264Picture *pic)
@@ -1117,7 +1145,7 @@ static int get_buffer(AVCodecContext *avctx, H264Picture *pic)
goto fail;
if (!sl->edge_emu_buffer) {
- sl->edge_emu_buffer = av_mallocz(pic->f->linesize[0] * 17);
+ sl->edge_emu_buffer = av_mallocz_array(pic->f->linesize[0], 17);
if (!sl->edge_emu_buffer)
return AVERROR(ENOMEM);
}
@@ -1134,11 +1162,12 @@ fail:
static int svq3_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
SVQ3Context *s = avctx->priv_data;
H264Context *h = &s->h;
H264SliceContext *sl = &h->slice_ctx[0];
int buf_size = avpkt->size;
+ int left;
+ uint8_t *buf;
int ret, m, i;
/* special case for last picture */
@@ -1153,10 +1182,20 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
return 0;
}
- init_get_bits(&h->gb, buf, 8 * buf_size);
-
sl->mb_x = sl->mb_y = sl->mb_xy = 0;
+ if (s->watermark_key) {
+ av_fast_padded_malloc(&s->buf, &s->buf_size, buf_size);
+ if (!s->buf)
+ return AVERROR(ENOMEM);
+ memcpy(s->buf, avpkt->data, buf_size);
+ buf = s->buf;
+ } else {
+ buf = avpkt->data;
+ }
+
+ init_get_bits(&h->gb, buf, 8 * buf_size);
+
if (svq3_decode_slice_header(avctx))
return -1;
@@ -1192,6 +1231,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
if (h->pict_type != AV_PICTURE_TYPE_I) {
if (!s->last_pic->f->data[0]) {
av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
+ av_frame_unref(s->last_pic->f);
ret = get_buffer(avctx, s->last_pic);
if (ret < 0)
return ret;
@@ -1204,6 +1244,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
if (h->pict_type == AV_PICTURE_TYPE_B && !s->next_pic->f->data[0]) {
av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
+ av_frame_unref(s->next_pic->f);
ret = get_buffer(avctx, s->next_pic);
if (ret < 0)
return ret;
@@ -1293,7 +1334,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
return -1;
}
- if (mb_type != 0)
+ if (mb_type != 0 || sl->cbp)
ff_h264_hl_decode_mb(h, &h->slice_ctx[0]);
if (h->pict_type != AV_PICTURE_TYPE_B && !h->low_delay)
@@ -1307,6 +1348,18 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data,
h->low_delay);
}
+ left = buf_size*8 - get_bits_count(&h->gb);
+
+ if (sl->mb_y != h->mb_height || sl->mb_x != h->mb_width) {
+ av_log(avctx, AV_LOG_INFO, "frame num %d incomplete pic x %d y %d left %d\n", avctx->frame_number, sl->mb_y, sl->mb_x, left);
+ //av_hex_dump(stderr, buf+buf_size-8, 8);
+ }
+
+ if (left < 0) {
+ av_log(avctx, AV_LOG_ERROR, "frame num %d left %d\n", avctx->frame_number, left);
+ return -1;
+ }
+
if (h->pict_type == AV_PICTURE_TYPE_B || h->low_delay)
ret = av_frame_ref(data, s->cur_pic->f);
else if (s->last_pic->f->data[0])
@@ -1346,6 +1399,9 @@ static av_cold int svq3_decode_end(AVCodecContext *avctx)
ff_h264_free_context(h);
+ av_freep(&s->buf);
+ s->buf_size = 0;
+
return 0;
}
diff --git a/libavcodec/svq3.h b/libavcodec/svq3.h
index a20e620f8e..5007a8c1c0 100644
--- a/libavcodec/svq3.h
+++ b/libavcodec/svq3.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/synth_filter.c b/libavcodec/synth_filter.c
index d0ace4040e..d49ffe642d 100644
--- a/libavcodec/synth_filter.c
+++ b/libavcodec/synth_filter.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/synth_filter.h b/libavcodec/synth_filter.h
index f842c701e3..b63fd779b5 100644
--- a/libavcodec/synth_filter.h
+++ b/libavcodec/synth_filter.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/tableprint.h b/libavcodec/tableprint.h
index daa89fe99b..667985f6d7 100644
--- a/libavcodec/tableprint.h
+++ b/libavcodec/tableprint.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,6 +81,16 @@ void write_float_2d_array (const void *, int, int);
#define FMT "zu"
#endif
+#define WRITE_ARRAY_ALIGNED(prefix, align, type, name) \
+ do { \
+ const size_t array_size = FF_ARRAY_ELEMS(name); \
+ printf(prefix" DECLARE_ALIGNED("#align", " \
+ #type", "#name")[%"FMT"] = {\n", \
+ array_size); \
+ write_##type##_array(name, array_size); \
+ printf("};\n"); \
+ } while(0)
+
#define WRITE_ARRAY(prefix, type, name) \
do { \
const size_t array_size = FF_ARRAY_ELEMS(name); \
@@ -104,6 +114,7 @@ void write_float_2d_array (const void *, int, int);
WRITE_1D_FUNC(int8_t, "%3"PRIi8, 15)
WRITE_1D_FUNC(uint8_t, "0x%02"PRIx8, 15)
WRITE_1D_FUNC(uint16_t, "0x%08"PRIx16, 7)
+WRITE_1D_FUNC(int16_t, "%5"PRIi16, 7)
WRITE_1D_FUNC(uint32_t, "0x%08"PRIx32, 7)
WRITE_1D_FUNC(float, "%.18e", 3)
diff --git a/libavcodec/tableprint_vlc.h b/libavcodec/tableprint_vlc.h
new file mode 100644
index 0000000000..33a9c0e756
--- /dev/null
+++ b/libavcodec/tableprint_vlc.h
@@ -0,0 +1,81 @@
+/*
+ * Helpers for generating hard-coded VLC tables
+ *
+ * Copyright (c) 2014 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_TABLEPRINT_VLC_H
+#define AVCODEC_TABLEPRINT_VLC_H
+
+#define FFMPEG_CONFIG_H
+#define AVUTIL_LOG_H
+#define av_log(a, ...) while(0)
+#define ff_dlog(a, ...) while(0)
+#define AVUTIL_MEM_H
+#define av_malloc(s) NULL
+#define av_malloc_array(a, b) NULL
+#define av_realloc_f(p, o, n) NULL
+#define av_free(p) while(0)
+#define av_freep(p) while(0)
+#define AVCODEC_AVCODEC_H
+#define AVCODEC_INTERNAL_H
+#include "tableprint.h"
+#include "get_bits.h"
+#include "mathtables.c"
+#include "bitstream.c"
+
+#define REPLACE_DEFINE2(type) write_##type##_array
+#define REPLACE_DEFINE(type) REPLACE_DEFINE2(type)
+static void write_VLC_TYPE_array(const VLC_TYPE *p, int s) {
+ REPLACE_DEFINE(VLC_TYPE)(p, s);
+}
+
+WRITE_2D_FUNC(VLC_TYPE)
+
+static void write_vlc_type(const VLC *vlc, VLC_TYPE (*base_table)[2], const char *base_table_name)
+{
+ printf(" .bits = %i,\n", vlc->bits);
+ // Unfortunately need to cast away const currently
+ printf(" .table = (VLC_TYPE (*)[2])(%s + 0x%x),\n", base_table_name, (int)(vlc->table - base_table));
+ printf(" .table_size = 0x%x,\n", vlc->table_size);
+ printf(" .table_allocated = 0x%x,\n", vlc->table_allocated);
+}
+
+#define WRITE_VLC_TYPE(prefix, name, base_table) \
+ do { \
+ printf(prefix" VLC "#name" = {\n"); \
+ write_vlc_type(&name, base_table, #base_table); \
+ printf("};\n"); \
+ } while(0)
+
+#define WRITE_VLC_ARRAY(prefix, name, base_table) \
+ do { \
+ int i; \
+ const size_t array_size = FF_ARRAY_ELEMS(name); \
+ printf(prefix" VLC "#name"[%"FMT"] = {{\n", \
+ array_size); \
+ for (i = 0; i < array_size; i++) { \
+ write_vlc_type(name + i, \
+ base_table, #base_table); \
+ if (i != array_size - 1) printf("}, {\n"); \
+ } \
+ printf("}};\n"); \
+ } while(0)
+
+#endif /* AVCODEC_TABLEPRINT_VLC_H */
diff --git a/libavcodec/tak.c b/libavcodec/tak.c
index 867a84bc71..ed41ca8a2e 100644
--- a/libavcodec/tak.c
+++ b/libavcodec/tak.c
@@ -2,28 +2,49 @@
* TAK common code
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/bswap.h"
#include "libavutil/crc.h"
#include "libavutil/intreadwrite.h"
#include "tak.h"
+static const int64_t tak_channel_layouts[] = {
+ 0,
+ AV_CH_FRONT_LEFT,
+ AV_CH_FRONT_RIGHT,
+ AV_CH_FRONT_CENTER,
+ AV_CH_LOW_FREQUENCY,
+ AV_CH_BACK_LEFT,
+ AV_CH_BACK_RIGHT,
+ AV_CH_FRONT_LEFT_OF_CENTER,
+ AV_CH_FRONT_RIGHT_OF_CENTER,
+ AV_CH_BACK_CENTER,
+ AV_CH_SIDE_LEFT,
+ AV_CH_SIDE_RIGHT,
+ AV_CH_TOP_CENTER,
+ AV_CH_TOP_FRONT_LEFT,
+ AV_CH_TOP_FRONT_CENTER,
+ AV_CH_TOP_FRONT_RIGHT,
+ AV_CH_TOP_BACK_LEFT,
+ AV_CH_TOP_BACK_CENTER,
+ AV_CH_TOP_BACK_RIGHT,
+};
+
static const uint16_t frame_duration_type_quants[] = {
3, 4, 6, 8, 4096, 8192, 16384, 512, 1024, 2048,
};
@@ -51,22 +72,6 @@ static int tak_get_nb_samples(int sample_rate, enum TAKFrameSizeType type)
return nb_samples;
}
-static int crc_init = 0;
-#if CONFIG_SMALL
-#define CRC_TABLE_SIZE 257
-#else
-#define CRC_TABLE_SIZE 1024
-#endif
-static AVCRC crc_24[CRC_TABLE_SIZE];
-
-av_cold void ff_tak_init_crc(void)
-{
- if (!crc_init) {
- av_crc_init(crc_24, 0, 24, 0x864CFBU, sizeof(crc_24));
- crc_init = 1;
- }
-}
-
int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size)
{
uint32_t crc, CRC;
@@ -75,8 +80,8 @@ int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size)
return AVERROR_INVALIDDATA;
buf_size -= 3;
- CRC = av_bswap32(AV_RL24(buf + buf_size)) >> 8;
- crc = av_crc(crc_24, 0xCE04B7U, buf, buf_size);
+ CRC = AV_RB24(buf + buf_size);
+ crc = av_crc(av_crc_get_table(AV_CRC_24_IEEE), 0xCE04B7U, buf, buf_size);
if (CRC != crc)
return AVERROR_INVALIDDATA;
@@ -108,8 +113,8 @@ void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s)
for (i = 0; i < s->channels; i++) {
int value = get_bits(gb, TAK_FORMAT_CH_LAYOUT_BITS);
- if (value > 0 && value <= 18)
- channel_mask |= 1 << (value - 1);
+ if (value < FF_ARRAY_ELEMS(tak_channel_layouts))
+ channel_mask |= tak_channel_layouts[value];
}
}
}
@@ -144,6 +149,9 @@ int ff_tak_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb,
align_get_bits(gb);
}
+ if (ti->flags & TAK_FRAME_FLAG_HAS_METADATA)
+ return AVERROR_INVALIDDATA;
+
skip_bits(gb, 24);
return 0;
diff --git a/libavcodec/tak.h b/libavcodec/tak.h
index fa91149793..e8e2dacf7c 100644
--- a/libavcodec/tak.h
+++ b/libavcodec/tak.h
@@ -2,20 +2,20 @@
* TAK decoder/demuxer common code
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -99,7 +99,7 @@
enum TAKCodecType {
TAK_CODEC_MONO_STEREO = 2,
- TAK_CODEC_MULTICHANNEL = 4
+ TAK_CODEC_MULTICHANNEL = 4,
};
enum TAKMetaDataType {
@@ -140,8 +140,6 @@ typedef struct TAKStreamInfo {
int64_t samples;
} TAKStreamInfo;
-void ff_tak_init_crc(void);
-
int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size);
/**
@@ -162,5 +160,4 @@ void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s);
*/
int ff_tak_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb,
TAKStreamInfo *s, int log_level_offset);
-
#endif /* AVCODEC_TAK_H */
diff --git a/libavcodec/tak_parser.c b/libavcodec/tak_parser.c
index 295df2418a..4f2149ae11 100644
--- a/libavcodec/tak_parser.c
+++ b/libavcodec/tak_parser.c
@@ -2,20 +2,20 @@
* TAK parser
* Copyright (c) 2012 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,12 +33,6 @@ typedef struct TAKParseContext {
int index;
} TAKParseContext;
-static av_cold int tak_init(AVCodecParserContext *s)
-{
- ff_tak_init_crc();
- return 0;
-}
-
static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx,
const uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size)
@@ -49,10 +43,12 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx,
GetBitContext gb;
int consumed = 0;
int needed = buf_size ? TAK_MAX_FRAME_HEADER_BYTES : 8;
+ int ret;
if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
TAKStreamInfo ti;
- init_get_bits(&gb, buf, buf_size);
+ if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
+ return ret;
if (!ff_tak_decode_frame_header(avctx, &gb, &ti, 127))
s->duration = t->ti.last_frame_samples ? t->ti.last_frame_samples
: t->ti.frame_samples;
@@ -67,23 +63,23 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx,
buf_size);
const uint8_t *tmp_buf = buf;
- ff_combine_frame(pc, END_NOT_FOUND, &tmp_buf, &tmp_buf_size);
+ if (ff_combine_frame(pc, END_NOT_FOUND, &tmp_buf, &tmp_buf_size) != -1)
+ return AVERROR(ENOMEM);
consumed += tmp_buf_size;
buf += tmp_buf_size;
buf_size -= tmp_buf_size;
}
- for (; t->index + needed <= pc->index; t->index++)
- if (pc->buffer[t->index] == 0xFF &&
- pc->buffer[t->index + 1] == 0xA0) {
+ for (; t->index + needed <= pc->index; t->index++) {
+ if (pc->buffer[ t->index ] == 0xFF &&
+ pc->buffer[ t->index + 1 ] == 0xA0) {
TAKStreamInfo ti;
- init_get_bits(&gb, pc->buffer + t->index,
- 8 * (pc->index - t->index));
+ if ((ret = init_get_bits8(&gb, pc->buffer + t->index,
+ pc->index - t->index)) < 0)
+ return ret;
if (!ff_tak_decode_frame_header(avctx, &gb,
- pc->frame_start_found ? &ti
- : &t->ti,
- 127) &&
+ pc->frame_start_found ? &ti : &t->ti, 127) &&
!ff_tak_check_crc(pc->buffer + t->index,
get_bits_count(&gb) / 8)) {
if (!pc->frame_start_found) {
@@ -91,6 +87,7 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx,
s->duration = t->ti.last_frame_samples ?
t->ti.last_frame_samples :
t->ti.frame_samples;
+ s->key_frame = !!(t->ti.flags & TAK_FRAME_FLAG_HAS_INFO);
} else {
pc->frame_start_found = 0;
next = t->index - pc->index;
@@ -99,9 +96,10 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx,
}
}
}
+ }
}
-
found:
+
if (consumed && !buf_size && next == END_NOT_FOUND ||
ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
*poutbuf = NULL;
@@ -122,7 +120,6 @@ found:
AVCodecParser ff_tak_parser = {
.codec_ids = { AV_CODEC_ID_TAK },
.priv_data_size = sizeof(TAKParseContext),
- .parser_init = tak_init,
.parser_parse = tak_parse,
.parser_close = ff_parse_close,
};
diff --git a/libavcodec/takdec.c b/libavcodec/takdec.c
index 60e80d590a..a453da81ec 100644
--- a/libavcodec/takdec.c
+++ b/libavcodec/takdec.c
@@ -2,20 +2,20 @@
* TAK decoder
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,42 +29,47 @@
#include "libavutil/samplefmt.h"
#include "tak.h"
#include "audiodsp.h"
+#include "thread.h"
#include "avcodec.h"
#include "internal.h"
#include "unary.h"
-#define MAX_SUBFRAMES 8 // max number of subframes per channel
+#define MAX_SUBFRAMES 8 ///< max number of subframes per channel
#define MAX_PREDICTORS 256
typedef struct MCDParam {
- int8_t present; // decorrelation parameter availability for this channel
- int8_t index; // index into array of decorrelation types
+ int8_t present; ///< decorrelation parameter availability for this channel
+ int8_t index; ///< index into array of decorrelation types
int8_t chan1;
int8_t chan2;
} MCDParam;
typedef struct TAKDecContext {
- AVCodecContext *avctx; // parent AVCodecContext
+ AVCodecContext *avctx; ///< parent AVCodecContext
AudioDSPContext adsp;
TAKStreamInfo ti;
- GetBitContext gb; // bitstream reader initialized to start at the current frame
+ GetBitContext gb; ///< bitstream reader initialized to start at the current frame
int uval;
- int nb_samples; // number of samples in the current frame
+ int nb_samples; ///< number of samples in the current frame
uint8_t *decode_buffer;
unsigned int decode_buffer_size;
- int32_t *decoded[TAK_MAX_CHANNELS]; // decoded samples for each channel
+ int32_t *decoded[TAK_MAX_CHANNELS]; ///< decoded samples for each channel
int8_t lpc_mode[TAK_MAX_CHANNELS];
- int8_t sample_shift[TAK_MAX_CHANNELS]; // shift applied to every sample in the channel
+ int8_t sample_shift[TAK_MAX_CHANNELS]; ///< shift applied to every sample in the channel
+ int16_t predictors[MAX_PREDICTORS];
+ int nb_subframes; ///< number of subframes in the current frame
+ int16_t subframe_len[MAX_SUBFRAMES]; ///< subframe length in samples
int subframe_scale;
- int8_t dmode; // channel decorrelation type in the current frame
+ int8_t dmode; ///< channel decorrelation type in the current frame
- MCDParam mcdparams[TAK_MAX_CHANNELS]; // multichannel decorrelation parameters
+ MCDParam mcdparams[TAK_MAX_CHANNELS]; ///< multichannel decorrelation parameters
- int16_t *residues;
- unsigned int residues_buf_size;
+ int8_t coding_mode[128];
+ DECLARE_ALIGNED(16, int16_t, filter)[MAX_PREDICTORS];
+ DECLARE_ALIGNED(16, int16_t, residues)[544];
} TAKDecContext;
static const int8_t mc_dmodes[] = { 1, 3, 4, 6, };
@@ -132,14 +137,9 @@ static const struct CParam {
{ 0x1A, 0x1800000, 0x1800000, 0x6800000, 0xC000000 },
};
-static av_cold void tak_init_static_data(AVCodec *codec)
-{
- ff_tak_init_crc();
-}
-
static int set_bps_params(AVCodecContext *avctx)
{
- switch (avctx->bits_per_coded_sample) {
+ switch (avctx->bits_per_raw_sample) {
case 8:
avctx->sample_fmt = AV_SAMPLE_FMT_U8P;
break;
@@ -150,11 +150,10 @@ static int set_bps_params(AVCodecContext *avctx)
avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
break;
default:
- av_log(avctx, AV_LOG_ERROR, "unsupported bits per sample: %d\n",
- avctx->bits_per_coded_sample);
+ av_log(avctx, AV_LOG_ERROR, "invalid/unsupported bits per sample: %d\n",
+ avctx->bits_per_raw_sample);
return AVERROR_INVALIDDATA;
}
- avctx->bits_per_raw_sample = avctx->bits_per_coded_sample;
return 0;
}
@@ -175,6 +174,7 @@ static av_cold int tak_decode_init(AVCodecContext *avctx)
ff_audiodsp_init(&s->adsp);
s->avctx = avctx;
+ avctx->bits_per_raw_sample = avctx->bits_per_coded_sample;
set_sample_rate_params(avctx);
@@ -236,10 +236,10 @@ static void decode_lpc(int32_t *coeffs, int mode, int length)
}
}
-static int decode_segment(GetBitContext *gb, int mode, int32_t *decoded,
- int len)
+static int decode_segment(TAKDecContext *s, int8_t mode, int32_t *decoded, int len)
{
struct CParam code;
+ GetBitContext *gb = &s->gb;
int i;
if (!mode) {
@@ -290,7 +290,6 @@ static int decode_residues(TAKDecContext *s, int32_t *decoded, int length)
if (get_bits1(gb)) {
int wlength, rval;
- int coding_mode[128];
wlength = length / s->uval;
@@ -304,7 +303,7 @@ static int decode_residues(TAKDecContext *s, int32_t *decoded, int length)
if (wlength <= 1 || wlength > 128)
return AVERROR_INVALIDDATA;
- coding_mode[0] = mode = get_bits(gb, 6);
+ s->coding_mode[0] = mode = get_bits(gb, 6);
for (i = 1; i < wlength; i++) {
int c = get_unary(gb, 1, 6);
@@ -328,14 +327,14 @@ static int decode_residues(TAKDecContext *s, int32_t *decoded, int length)
mode--;
break;
}
- coding_mode[i] = mode;
+ s->coding_mode[i] = mode;
}
i = 0;
while (i < wlength) {
int len = 0;
- mode = coding_mode[i];
+ mode = s->coding_mode[i];
do {
if (i >= wlength - 1)
len += rval;
@@ -345,15 +344,15 @@ static int decode_residues(TAKDecContext *s, int32_t *decoded, int length)
if (i == wlength)
break;
- } while (coding_mode[i] == mode);
+ } while (s->coding_mode[i] == mode);
- if ((ret = decode_segment(gb, mode, decoded, len)) < 0)
+ if ((ret = decode_segment(s, mode, decoded, len)) < 0)
return ret;
decoded += len;
}
} else {
mode = get_bits(gb, 6);
- if ((ret = decode_segment(gb, mode, decoded, length)) < 0)
+ if ((ret = decode_segment(s, mode, decoded, length)) < 0)
return ret;
}
@@ -368,62 +367,13 @@ static int get_bits_esc4(GetBitContext *gb)
return 0;
}
-static void decode_filter_coeffs(TAKDecContext *s, int filter_order, int size,
- int filter_quant, int16_t *filter)
-{
- GetBitContext *gb = &s->gb;
- int i, j, a, b;
- int filter_tmp[MAX_PREDICTORS];
- int16_t predictors[MAX_PREDICTORS];
-
- predictors[0] = get_sbits(gb, 10);
- predictors[1] = get_sbits(gb, 10);
- predictors[2] = get_sbits(gb, size) << (10 - size);
- predictors[3] = get_sbits(gb, size) << (10 - size);
- if (filter_order > 4) {
- int av_uninit(code_size);
- int code_size_base = size - get_bits1(gb);
-
- for (i = 4; i < filter_order; i++) {
- if (!(i & 3))
- code_size = code_size_base - get_bits(gb, 2);
- predictors[i] = get_sbits(gb, code_size) << (10 - size);
- }
- }
-
- filter_tmp[0] = predictors[0] << 6;
- for (i = 1; i < filter_order; i++) {
- int *p1 = &filter_tmp[0];
- int *p2 = &filter_tmp[i - 1];
-
- for (j = 0; j < (i + 1) / 2; j++) {
- int tmp = *p1 + (predictors[i] * *p2 + 256 >> 9);
- *p2 = *p2 + (predictors[i] * *p1 + 256 >> 9);
- *p1 = tmp;
- p1++;
- p2--;
- }
-
- filter_tmp[i] = predictors[i] << 6;
- }
-
- a = 1 << (32 - (15 - filter_quant));
- b = 1 << ((15 - filter_quant) - 1);
- for (i = 0, j = filter_order - 1; i < filter_order / 2; i++, j--) {
- filter[j] = a - ((filter_tmp[i] + b) >> (15 - filter_quant));
- filter[i] = a - ((filter_tmp[j] + b) >> (15 - filter_quant));
- }
-}
-
static int decode_subframe(TAKDecContext *s, int32_t *decoded,
int subframe_size, int prev_subframe_size)
{
- LOCAL_ALIGNED_16(int16_t, filter, [MAX_PREDICTORS]);
GetBitContext *gb = &s->gb;
- int i, ret;
+ int x, y, i, j, ret = 0;
int dshift, size, filter_quant, filter_order;
-
- memset(filter, 0, MAX_PREDICTORS * sizeof(*filter));
+ int tfilter[MAX_PREDICTORS];
if (!get_bits1(gb))
return decode_residues(s, decoded, subframe_size);
@@ -466,30 +416,74 @@ static int decode_subframe(TAKDecContext *s, int32_t *decoded,
return AVERROR_INVALIDDATA;
}
- decode_filter_coeffs(s, filter_order, size, filter_quant, filter);
+ s->predictors[0] = get_sbits(gb, 10);
+ s->predictors[1] = get_sbits(gb, 10);
+ s->predictors[2] = get_sbits(gb, size) << (10 - size);
+ s->predictors[3] = get_sbits(gb, size) << (10 - size);
+ if (filter_order > 4) {
+ int tmp = size - get_bits1(gb);
+
+ for (i = 4; i < filter_order; i++) {
+ if (!(i & 3))
+ x = tmp - get_bits(gb, 2);
+ s->predictors[i] = get_sbits(gb, x) << (10 - size);
+ }
+ }
+
+ tfilter[0] = s->predictors[0] << 6;
+ for (i = 1; i < filter_order; i++) {
+ int32_t *p1 = &tfilter[0];
+ int32_t *p2 = &tfilter[i - 1];
+
+ for (j = 0; j < (i + 1) / 2; j++) {
+ x = *p1 + (s->predictors[i] * *p2 + 256 >> 9);
+ *p2 += s->predictors[i] * *p1 + 256 >> 9;
+ *p1++ = x;
+ p2--;
+ }
+
+ tfilter[i] = s->predictors[i] << 6;
+ }
+
+ x = 1 << (32 - (15 - filter_quant));
+ y = 1 << ((15 - filter_quant) - 1);
+ for (i = 0, j = filter_order - 1; i < filter_order / 2; i++, j--) {
+ s->filter[j] = x - ((tfilter[i] + y) >> (15 - filter_quant));
+ s->filter[i] = x - ((tfilter[j] + y) >> (15 - filter_quant));
+ }
if ((ret = decode_residues(s, &decoded[filter_order],
subframe_size - filter_order)) < 0)
return ret;
- av_fast_malloc(&s->residues, &s->residues_buf_size,
- FFALIGN(subframe_size + 16, 16) * sizeof(*s->residues));
- if (!s->residues)
- return AVERROR(ENOMEM);
- memset(s->residues, 0, s->residues_buf_size);
-
for (i = 0; i < filter_order; i++)
s->residues[i] = *decoded++ >> dshift;
- for (i = 0; i < subframe_size - filter_order; i++) {
- int v = 1 << (filter_quant - 1);
-
- v += s->adsp.scalarproduct_int16(&s->residues[i], filter,
- FFALIGN(filter_order, 16));
+ y = FF_ARRAY_ELEMS(s->residues) - filter_order;
+ x = subframe_size - filter_order;
+ while (x > 0) {
+ int tmp = FFMIN(y, x);
+
+ for (i = 0; i < tmp; i++) {
+ int v = 1 << (filter_quant - 1);
+
+ if (filter_order & -16)
+ v += s->adsp.scalarproduct_int16(&s->residues[i], s->filter,
+ filter_order & -16);
+ for (j = filter_order & -16; j < filter_order; j += 4) {
+ v += s->residues[i + j + 3] * s->filter[j + 3] +
+ s->residues[i + j + 2] * s->filter[j + 2] +
+ s->residues[i + j + 1] * s->filter[j + 1] +
+ s->residues[i + j ] * s->filter[j ];
+ }
+ v = (av_clip_intp2(v >> filter_quant, 13) << dshift) - *decoded;
+ *decoded++ = v;
+ s->residues[filter_order + i] = v >> dshift;
+ }
- v = (av_clip_intp2(v >> filter_quant, 13) << dshift) - *decoded;
- *decoded++ = v;
- s->residues[filter_order + i] = v >> dshift;
+ x -= tmp;
+ if (x > 0)
+ memcpy(s->residues, &s->residues[y], 2 * filter_order);
}
emms_c();
@@ -503,50 +497,42 @@ static int decode_channel(TAKDecContext *s, int chan)
GetBitContext *gb = &s->gb;
int32_t *decoded = s->decoded[chan];
int left = s->nb_samples - 1;
- int i, prev, ret, nb_subframes;
- int subframe_len[MAX_SUBFRAMES];
+ int i = 0, ret, prev = 0;
s->sample_shift[chan] = get_bits_esc4(gb);
- if (s->sample_shift[chan] >= avctx->bits_per_coded_sample)
+ if (s->sample_shift[chan] >= avctx->bits_per_raw_sample)
return AVERROR_INVALIDDATA;
- /* NOTE: TAK 2.2.0 appears to set the sample value to 0 if
- * bits_per_coded_sample - sample_shift is 1, but this produces
- * non-bit-exact output. Reading the 1 bit using get_sbits() instead
- * of skipping it produces bit-exact output. This has been reported
- * to the TAK author. */
- *decoded++ = get_sbits(gb,
- avctx->bits_per_coded_sample -
- s->sample_shift[chan]);
+ *decoded++ = get_sbits(gb, avctx->bits_per_raw_sample - s->sample_shift[chan]);
s->lpc_mode[chan] = get_bits(gb, 2);
- nb_subframes = get_bits(gb, 3) + 1;
+ s->nb_subframes = get_bits(gb, 3) + 1;
- i = 0;
- if (nb_subframes > 1) {
- if (get_bits_left(gb) < (nb_subframes - 1) * 6)
+ if (s->nb_subframes > 1) {
+ if (get_bits_left(gb) < (s->nb_subframes - 1) * 6)
return AVERROR_INVALIDDATA;
- prev = 0;
- for (; i < nb_subframes - 1; i++) {
- int subframe_end = get_bits(gb, 6) * s->subframe_scale;
- if (subframe_end <= prev)
+ for (; i < s->nb_subframes - 1; i++) {
+ int v = get_bits(gb, 6);
+
+ s->subframe_len[i] = (v - prev) * s->subframe_scale;
+ if (s->subframe_len[i] <= 0)
return AVERROR_INVALIDDATA;
- subframe_len[i] = subframe_end - prev;
- left -= subframe_len[i];
- prev = subframe_end;
+
+ left -= s->subframe_len[i];
+ prev = v;
}
if (left <= 0)
return AVERROR_INVALIDDATA;
}
- subframe_len[i] = left;
+ s->subframe_len[i] = left;
prev = 0;
- for (i = 0; i < nb_subframes; i++) {
- if ((ret = decode_subframe(s, decoded, subframe_len[i], prev)) < 0)
+ for (i = 0; i < s->nb_subframes; i++) {
+ if ((ret = decode_subframe(s, decoded, s->subframe_len[i], prev)) < 0)
return ret;
- decoded += subframe_len[i];
- prev = subframe_len[i];
+ decoded += s->subframe_len[i];
+ prev = s->subframe_len[i];
}
return 0;
@@ -599,11 +585,8 @@ static int decorrelate(TAKDecContext *s, int c1, int c2, int length)
case 6:
FFSWAP(int32_t*, p1, p2);
case 7: {
- LOCAL_ALIGNED_16(int16_t, filter, [MAX_PREDICTORS]);
int length2, order_half, filter_order, dval1, dval2;
- int av_uninit(code_size);
-
- memset(filter, 0, MAX_PREDICTORS * sizeof(*filter));
+ int tmp, x, code_size;
if (length < 256)
return AVERROR_INVALIDDATA;
@@ -616,7 +599,7 @@ static int decorrelate(TAKDecContext *s, int c1, int c2, int length)
for (i = 0; i < filter_order; i++) {
if (!(i & 3))
code_size = 14 - get_bits(gb, 3);
- filter[i] = get_sbits(gb, code_size);
+ s->filter[i] = get_sbits(gb, code_size);
}
order_half = filter_order / 2;
@@ -640,24 +623,40 @@ static int decorrelate(TAKDecContext *s, int c1, int c2, int length)
}
}
- av_fast_malloc(&s->residues, &s->residues_buf_size,
- FFALIGN(length + 16, 16) * sizeof(*s->residues));
- if (!s->residues)
- return AVERROR(ENOMEM);
- memset(s->residues, 0, s->residues_buf_size);
- for (i = 0; i < length; i++)
- s->residues[i] = p2[i] >> dshift;
+ for (i = 0; i < filter_order; i++)
+ s->residues[i] = *p2++ >> dshift;
p1 += order_half;
+ x = FF_ARRAY_ELEMS(s->residues) - filter_order;
+ for (; length2 > 0; length2 -= tmp) {
+ tmp = FFMIN(length2, x);
+
+ for (i = 0; i < tmp; i++)
+ s->residues[filter_order + i] = *p2++ >> dshift;
+
+ for (i = 0; i < tmp; i++) {
+ int v = 1 << 9;
+
+ if (filter_order == 16) {
+ v += s->adsp.scalarproduct_int16(&s->residues[i], s->filter,
+ filter_order);
+ } else {
+ v += s->residues[i + 7] * s->filter[7] +
+ s->residues[i + 6] * s->filter[6] +
+ s->residues[i + 5] * s->filter[5] +
+ s->residues[i + 4] * s->filter[4] +
+ s->residues[i + 3] * s->filter[3] +
+ s->residues[i + 2] * s->filter[2] +
+ s->residues[i + 1] * s->filter[1] +
+ s->residues[i ] * s->filter[0];
+ }
- for (i = 0; i < length2; i++) {
- int v = 1 << 9;
-
- v += s->adsp.scalarproduct_int16(&s->residues[i], filter,
- FFALIGN(filter_order, 16));
+ v = (av_clip_intp2(v >> 10, 13) << dshift) - *p1;
+ *p1++ = v;
+ }
- p1[i] = (av_clip_intp2(v >> 10, 13) << dshift) - p1[i];
+ memcpy(s->residues, &s->residues[tmp], 2 * filter_order);
}
emms_c();
@@ -673,24 +672,21 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
{
TAKDecContext *s = avctx->priv_data;
AVFrame *frame = data;
+ ThreadFrame tframe = { .f = data };
GetBitContext *gb = &s->gb;
int chan, i, ret, hsize;
if (pkt->size < TAK_MIN_FRAME_HEADER_BYTES)
return AVERROR_INVALIDDATA;
- init_get_bits(gb, pkt->data, pkt->size * 8);
+ if ((ret = init_get_bits8(gb, pkt->data, pkt->size)) < 0)
+ return ret;
if ((ret = ff_tak_decode_frame_header(avctx, gb, &s->ti, 0)) < 0)
return ret;
- if (s->ti.flags & TAK_FRAME_FLAG_HAS_METADATA) {
- avpriv_request_sample(avctx, "Frame metadata");
- return AVERROR_PATCHWELCOME;
- }
-
hsize = get_bits_count(gb) / 8;
- if (avctx->err_recognition & AV_EF_CRCCHECK) {
+ if (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_COMPLIANT)) {
if (ff_tak_check_crc(pkt->data, hsize)) {
av_log(avctx, AV_LOG_ERROR, "CRC error\n");
if (avctx->err_recognition & AV_EF_EXPLODE)
@@ -724,11 +720,9 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
- if (s->ti.bps != avctx->bits_per_coded_sample) {
- avctx->bits_per_coded_sample = s->ti.bps;
- if ((ret = set_bps_params(avctx)) < 0)
- return ret;
- }
+ avctx->bits_per_raw_sample = s->ti.bps;
+ if ((ret = set_bps_params(avctx)) < 0)
+ return ret;
if (s->ti.sample_rate != avctx->sample_rate) {
avctx->sample_rate = s->ti.sample_rate;
set_sample_rate_params(avctx);
@@ -741,10 +735,11 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
: s->ti.frame_samples;
frame->nb_samples = s->nb_samples;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0)
return ret;
+ ff_thread_finish_setup(avctx);
- if (avctx->bits_per_coded_sample <= 16) {
+ if (avctx->bits_per_raw_sample <= 16) {
int buf_size = av_samples_get_buffer_size(NULL, avctx->channels,
s->nb_samples,
AV_SAMPLE_FMT_S32P, 0);
@@ -767,7 +762,7 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
for (chan = 0; chan < avctx->channels; chan++) {
int32_t *decoded = s->decoded[chan];
for (i = 0; i < s->nb_samples; i++)
- decoded[i] = get_sbits(gb, avctx->bits_per_coded_sample);
+ decoded[i] = get_sbits(gb, avctx->bits_per_raw_sample);
}
} else {
if (s->ti.codec == TAK_CODEC_MONO_STEREO) {
@@ -776,9 +771,9 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
return ret;
if (avctx->channels == 2) {
- if (get_bits1(gb)) {
- // some kind of subframe length, but it seems to be unused
- skip_bits(gb, 6);
+ s->nb_subframes = get_bits(gb, 1) + 1;
+ if (s->nb_subframes > 1) {
+ s->subframe_len[1] = get_bits(gb, 6);
}
s->dmode = get_bits(gb, 3);
@@ -866,7 +861,7 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
else if (get_bits_left(gb) > 0)
av_log(avctx, AV_LOG_DEBUG, "underread\n");
- if (avctx->err_recognition & AV_EF_CRCCHECK) {
+ if (avctx->err_recognition & (AV_EF_CRCCHECK | AV_EF_COMPLIANT)) {
if (ff_tak_check_crc(pkt->data + hsize,
get_bits_count(gb) / 8 - hsize)) {
av_log(avctx, AV_LOG_ERROR, "CRC error\n");
@@ -907,12 +902,30 @@ static int tak_decode_frame(AVCodecContext *avctx, void *data,
return pkt->size;
}
+static int init_thread_copy(AVCodecContext *avctx)
+{
+ TAKDecContext *s = avctx->priv_data;
+ s->avctx = avctx;
+ return 0;
+}
+
+static int update_thread_context(AVCodecContext *dst,
+ const AVCodecContext *src)
+{
+ TAKDecContext *tsrc = src->priv_data;
+ TAKDecContext *tdst = dst->priv_data;
+
+ if (dst == src)
+ return 0;
+ memcpy(&tdst->ti, &tsrc->ti, sizeof(TAKStreamInfo));
+ return 0;
+}
+
static av_cold int tak_decode_close(AVCodecContext *avctx)
{
TAKDecContext *s = avctx->priv_data;
av_freep(&s->decode_buffer);
- av_freep(&s->residues);
return 0;
}
@@ -924,10 +937,11 @@ AVCodec ff_tak_decoder = {
.id = AV_CODEC_ID_TAK,
.priv_data_size = sizeof(TAKDecContext),
.init = tak_decode_init,
- .init_static_data = tak_init_static_data,
.close = tak_decode_close,
.decode = tak_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+ .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_S16P,
AV_SAMPLE_FMT_S32P,
diff --git a/libavcodec/targa.c b/libavcodec/targa.c
index f077c03d65..b0c9b55f33 100644
--- a/libavcodec/targa.c
+++ b/libavcodec/targa.c
@@ -2,20 +2,20 @@
* Targa (.tga) image decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,22 +28,37 @@
typedef struct TargaContext {
GetByteContext gb;
-
- int color_type;
- int compression_type;
} TargaContext;
+static uint8_t *advance_line(uint8_t *start, uint8_t *line,
+ int stride, int *y, int h, int interleave)
+{
+ *y += interleave;
+
+ if (*y < h) {
+ return line + interleave * stride;
+ } else {
+ *y = (*y + 1) & (interleave - 1);
+ if (*y && *y < h) {
+ return start + *y * stride;
+ } else {
+ return NULL;
+ }
+ }
+}
+
static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
- uint8_t *dst, int w, int h, int stride, int bpp)
+ uint8_t *start, int w, int h, int stride,
+ int bpp, int interleave)
{
int x, y;
int depth = (bpp + 1) >> 3;
int type, count;
- int diff;
+ uint8_t *line = start;
+ uint8_t *dst = line;
- diff = stride - w * depth;
- x = y = 0;
- while (y < h) {
+ x = y = count = 0;
+ while (dst) {
if (bytestream2_get_bytes_left(&s->gb) <= 0) {
av_log(avctx, AV_LOG_ERROR,
"Ran ouf of data before end-of-image\n");
@@ -52,12 +67,6 @@ static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
type = bytestream2_get_byteu(&s->gb);
count = (type & 0x7F) + 1;
type &= 0x80;
- if (x + count > w && x + count + 1 > (h - y) * w) {
- av_log(avctx, AV_LOG_ERROR,
- "Packet went out of bounds: position (%i,%i) size %i\n",
- x, y, count);
- return AVERROR_INVALIDDATA;
- }
if (!type) {
do {
int n = FFMIN(count, w - x);
@@ -67,10 +76,9 @@ static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
x += n;
if (x == w) {
x = 0;
- y++;
- dst += diff;
+ dst = line = advance_line(start, line, stride, &y, h, interleave);
}
- } while (count > 0);
+ } while (dst && count > 0);
} else {
uint8_t tmp[4];
bytestream2_get_buffer(&s->gb, tmp, depth);
@@ -84,12 +92,17 @@ static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
} while (--n);
if (x == w) {
x = 0;
- y++;
- dst += diff;
+ dst = line = advance_line(start, line, stride, &y, h, interleave);
}
- } while (count > 0);
+ } while (dst && count > 0);
}
}
+
+ if (count) {
+ av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+
return 0;
}
@@ -101,14 +114,15 @@ static int decode_frame(AVCodecContext *avctx,
AVFrame * const p = data;
uint8_t *dst;
int stride;
- int idlen, compr, y, w, h, bpp, flags, ret;
+ int idlen, pal, compr, y, w, h, bpp, flags, ret;
int first_clr, colors, csize;
+ int interleave;
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
/* parse image header */
idlen = bytestream2_get_byte(&s->gb);
- bytestream2_skip(&s->gb, 1); /* pal */
+ pal = bytestream2_get_byte(&s->gb);
compr = bytestream2_get_byte(&s->gb);
first_clr = bytestream2_get_le16(&s->gb);
colors = bytestream2_get_le16(&s->gb);
@@ -117,17 +131,29 @@ static int decode_frame(AVCodecContext *avctx,
w = bytestream2_get_le16(&s->gb);
h = bytestream2_get_le16(&s->gb);
bpp = bytestream2_get_byte(&s->gb);
+
+ if (bytestream2_get_bytes_left(&s->gb) <= idlen) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Not enough data to read header\n");
+ return AVERROR_INVALIDDATA;
+ }
+
flags = bytestream2_get_byte(&s->gb);
+
+ if (!pal && (first_clr || colors || csize)) {
+ av_log(avctx, AV_LOG_WARNING, "File without colormap has colormap information set.\n");
+ // specification says we should ignore those value in this case
+ first_clr = colors = csize = 0;
+ }
+
// skip identifier if any
bytestream2_skip(&s->gb, idlen);
- switch(bpp){
+ switch (bpp) {
case 8:
avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_PAL8;
break;
case 15:
- avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
- break;
case 16:
avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
break;
@@ -142,28 +168,34 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
+ if (colors && (colors + first_clr) > 256) {
+ av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
+ return AVERROR_INVALIDDATA;
+ }
+
if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0){
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
- if(flags & 0x20){
+ p->pict_type = AV_PICTURE_TYPE_I;
+
+ if (flags & TGA_TOPTOBOTTOM) {
dst = p->data[0];
stride = p->linesize[0];
- }else{ //image is upside-down
+ } else { //image is upside-down
dst = p->data[0] + p->linesize[0] * (h - 1);
stride = -p->linesize[0];
}
- if(colors){
+ interleave = flags & TGA_INTERLEAVE2 ? 2 :
+ flags & TGA_INTERLEAVE4 ? 4 : 1;
+
+ if (colors) {
int pal_size, pal_sample_size;
- if((colors + first_clr) > 256){
- av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
- return AVERROR_INVALIDDATA;
- }
+
switch (csize) {
+ case 32: pal_sample_size = 4; break;
case 24: pal_sample_size = 3; break;
case 16:
case 15: pal_sample_size = 2; break;
@@ -172,9 +204,9 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
pal_size = colors * pal_sample_size;
- if(avctx->pix_fmt != AV_PIX_FMT_PAL8)//should not occur but skip palette anyway
+ if (avctx->pix_fmt != AV_PIX_FMT_PAL8) //should not occur but skip palette anyway
bytestream2_skip(&s->gb, pal_size);
- else{
+ else {
int t;
uint32_t *pal = ((uint32_t *)p->data[1]) + first_clr;
@@ -184,10 +216,14 @@ static int decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
switch (pal_sample_size) {
+ case 4:
+ for (t = 0; t < colors; t++)
+ *pal++ = bytestream2_get_le32u(&s->gb);
+ break;
case 3:
/* RGB24 */
for (t = 0; t < colors; t++)
- *pal++ = bytestream2_get_le24u(&s->gb);
+ *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb);
break;
case 2:
/* RGB555 */
@@ -198,30 +234,59 @@ static int decode_frame(AVCodecContext *avctx,
((v & 0x001F) << 3);
/* left bit replication */
v |= (v & 0xE0E0E0U) >> 5;
- *pal++ = v;
+ *pal++ = (0xffU<<24) | v;
}
break;
}
p->palette_has_changed = 1;
}
}
+
if ((compr & (~TGA_RLE)) == TGA_NODATA) {
memset(p->data[0], 0, p->linesize[0] * h);
} else {
- if(compr & TGA_RLE){
- int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp);
+ if (compr & TGA_RLE) {
+ int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave);
if (res < 0)
return res;
} else {
size_t img_size = w * ((bpp + 1) >> 3);
+ uint8_t *line;
if (bytestream2_get_bytes_left(&s->gb) < img_size * h) {
av_log(avctx, AV_LOG_ERROR,
"Not enough data available for image\n");
return AVERROR_INVALIDDATA;
}
- for (y = 0; y < h; y++) {
- bytestream2_get_bufferu(&s->gb, dst, img_size);
- dst += stride;
+
+ line = dst;
+ y = 0;
+ do {
+ bytestream2_get_buffer(&s->gb, line, img_size);
+ line = advance_line(dst, line, stride, &y, h, interleave);
+ } while (line);
+ }
+ }
+
+ if (flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip
+ int x;
+ for (y = 0; y < h; y++) {
+ void *line = &p->data[0][y * p->linesize[0]];
+ for (x = 0; x < w >> 1; x++) {
+ switch (bpp) {
+ case 32:
+ FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]);
+ break;
+ case 24:
+ FFSWAP(uint8_t, ((uint8_t *)line)[3 * x ], ((uint8_t *)line)[3 * w - 3 * x - 3]);
+ FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]);
+ FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]);
+ break;
+ case 16:
+ FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]);
+ break;
+ case 8:
+ FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]);
+ }
}
}
}
diff --git a/libavcodec/targa.h b/libavcodec/targa.h
index f4ef5537b1..c2f522465b 100644
--- a/libavcodec/targa.h
+++ b/libavcodec/targa.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,4 +38,11 @@ enum TargaCompr {
TGA_RLE = 8, // flag pointing that data is RLE-coded
};
+enum TargaFlags {
+ TGA_RIGHTTOLEFT = 0x10, // right-to-left (flipped horizontally)
+ TGA_TOPTOBOTTOM = 0x20, // top-to-bottom (NOT flipped vertically)
+ TGA_INTERLEAVE2 = 0x40, // 2-way interleave, odd then even lines
+ TGA_INTERLEAVE4 = 0x80, // 4-way interleave
+};
+
#endif /* AVCODEC_TARGA_H */
diff --git a/libavcodec/targa_y216dec.c b/libavcodec/targa_y216dec.c
new file mode 100644
index 0000000000..5f4eeaaad2
--- /dev/null
+++ b/libavcodec/targa_y216dec.c
@@ -0,0 +1,83 @@
+/*
+ * Pinnacle TARGA CineWave YUV16 decoder
+ * Copyright (c) 2012 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int y216_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUV422P16;
+ avctx->bits_per_raw_sample = 14;
+
+ return 0;
+}
+
+static int y216_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVFrame *pic = data;
+ const uint16_t *src = (uint16_t *)avpkt->data;
+ uint16_t *y, *u, *v, aligned_width = FFALIGN(avctx->width, 4);
+ int i, j, ret;
+
+ if (avpkt->size < 4 * avctx->height * aligned_width) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->key_frame = 1;
+ 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];
+
+ for (i = 0; i < avctx->height; i++) {
+ for (j = 0; j < avctx->width >> 1; j++) {
+ u[ j ] = src[4 * j ] << 2 | src[4 * j ] >> 14;
+ y[2 * j ] = src[4 * j + 1] << 2 | src[4 * j + 1] >> 14;
+ v[ j ] = src[4 * j + 2] << 2 | src[4 * j + 2] >> 14;
+ y[2 * j + 1] = src[4 * j + 3] << 2 | src[4 * j + 3] >> 14;
+ }
+
+ y += pic->linesize[0] >> 1;
+ u += pic->linesize[1] >> 1;
+ v += pic->linesize[2] >> 1;
+ src += aligned_width << 1;
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_targa_y216_decoder = {
+ .name = "targa_y216",
+ .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_TARGA_Y216,
+ .init = y216_decode_init,
+ .decode = y216_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/targaenc.c b/libavcodec/targaenc.c
index 7679029643..d4483ec398 100644
--- a/libavcodec/targaenc.c
+++ b/libavcodec/targaenc.c
@@ -2,20 +2,20 @@
* Targa (.tga) image encoder
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -77,7 +77,7 @@ static int targa_encode_normal(uint8_t *outbuf, const AVFrame *pic, int bpp, int
static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *p, int *got_packet)
{
- int bpp, picsize, datasize = -1, ret;
+ int bpp, picsize, datasize = -1, ret, i;
uint8_t *out;
if(avctx->width > 0xffff || avctx->height > 0xffff) {
@@ -85,10 +85,8 @@ static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return AVERROR(EINVAL);
}
picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
- if ((ret = ff_alloc_packet(pkt, picsize + 45)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, picsize + 45)) < 0)
return ret;
- }
/* zero out the header and only set applicable fields */
memset(pkt->data, 0, 12);
@@ -97,13 +95,39 @@ static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
/* image descriptor byte: origin is always top-left, bits 0-3 specify alpha */
pkt->data[17] = 0x20 | (avctx->pix_fmt == AV_PIX_FMT_BGRA ? 8 : 0);
+ out = pkt->data + 18; /* skip past the header we write */
+
+ avctx->bits_per_coded_sample = av_get_bits_per_pixel(av_pix_fmt_desc_get(avctx->pix_fmt));
switch(avctx->pix_fmt) {
+ case AV_PIX_FMT_PAL8: {
+ int pal_bpp = 24; /* Only write 32bit palette if there is transparency information */
+ for (i = 0; i < 256; i++)
+ if (AV_RN32(p->data[1] + 4 * i) >> 24 != 0xFF) {
+ pal_bpp = 32;
+ break;
+ }
+ pkt->data[1] = 1; /* palette present */
+ pkt->data[2] = TGA_PAL; /* uncompressed palettised image */
+ pkt->data[6] = 1; /* palette contains 256 entries */
+ pkt->data[7] = pal_bpp; /* palette contains pal_bpp bit entries */
+ pkt->data[16] = 8; /* bpp */
+ for (i = 0; i < 256; i++)
+ if (pal_bpp == 32) {
+ AV_WL32(pkt->data + 18 + 4 * i, *(uint32_t *)(p->data[1] + i * 4));
+ } else {
+ AV_WL24(pkt->data + 18 + 3 * i, *(uint32_t *)(p->data[1] + i * 4));
+ }
+ out += 32 * pal_bpp; /* skip past the palette we just output */
+ break;
+ }
case AV_PIX_FMT_GRAY8:
pkt->data[2] = TGA_BW; /* uncompressed grayscale image */
+ avctx->bits_per_coded_sample = 0x28;
pkt->data[16] = 8; /* bpp */
break;
case AV_PIX_FMT_RGB555LE:
- pkt->data[2] = TGA_RGB; /* uncompresses true-color image */
+ pkt->data[2] = TGA_RGB; /* uncompressed true-color image */
+ avctx->bits_per_coded_sample =
pkt->data[16] = 16; /* bpp */
break;
case AV_PIX_FMT_BGR24:
@@ -121,15 +145,13 @@ static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
bpp = pkt->data[16] >> 3;
- out = pkt->data + 18; /* skip past the header we just output */
-
/* try RLE compression */
if (avctx->coder_type != FF_CODER_TYPE_RAW)
datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height);
/* if that worked well, mark the picture as RLE compressed */
if(datasize >= 0)
- pkt->data[2] |= 8;
+ pkt->data[2] |= TGA_RLE;
/* if RLE didn't make it smaller, go back to no compression */
else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height);
@@ -175,7 +197,7 @@ AVCodec ff_targa_encoder = {
.close = targa_encode_close,
.encode2 = targa_encode_frame,
.pix_fmts = (const enum AVPixelFormat[]){
- AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8,
AV_PIX_FMT_NONE
},
};
diff --git a/libavcodec/tdsc.c b/libavcodec/tdsc.c
index b46a3c1c63..8f0ebe7c3f 100644
--- a/libavcodec/tdsc.c
+++ b/libavcodec/tdsc.c
@@ -2,20 +2,20 @@
* TDSC decoder
* Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -124,8 +124,8 @@ static av_cold int tdsc_init(AVCodecContext *avctx)
ctx->jpeg_avctx->flags = avctx->flags;
ctx->jpeg_avctx->flags2 = avctx->flags2;
ctx->jpeg_avctx->dct_algo = avctx->dct_algo;
- ctx->jpeg_avctx->idct_algo = avctx->idct_algo;;
- ret = avcodec_open2(ctx->jpeg_avctx, codec, NULL);
+ ctx->jpeg_avctx->idct_algo = avctx->idct_algo;
+ ret = ff_codec_open2_recursive(ctx->jpeg_avctx, codec, NULL);
if (ret < 0)
return ret;
diff --git a/libavcodec/textdec.c b/libavcodec/textdec.c
new file mode 100644
index 0000000000..c9f02a2a4c
--- /dev/null
+++ b/libavcodec/textdec.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Raw subtitles decoder
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/bprint.h"
+#include "libavutil/opt.h"
+
+typedef struct {
+ AVClass *class;
+ const char *linebreaks;
+ int keep_ass_markup;
+} TextContext;
+
+#define OFFSET(x) offsetof(TextContext, x)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "keep_ass_markup", "Set if ASS tags must be escaped", OFFSET(keep_ass_markup), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags=SD },
+ { NULL }
+};
+
+static int text_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_sub_ptr, AVPacket *avpkt)
+{
+ int ret = 0;
+ AVBPrint buf;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ const TextContext *text = avctx->priv_data;
+ const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
+ const int ts_duration = avpkt->duration != -1 ?
+ av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if (ptr && avpkt->size > 0 && *ptr) {
+ ff_ass_bprint_text_event(&buf, ptr, avpkt->size, text->linebreaks, text->keep_ass_markup);
+ ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
+ }
+ av_bprint_finalize(&buf, NULL);
+ if (ret < 0)
+ return ret;
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+#define DECLARE_CLASS(decname) static const AVClass decname ## _decoder_class = { \
+ .class_name = #decname " decoder", \
+ .item_name = av_default_item_name, \
+ .option = decname ## _options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+}
+
+#if CONFIG_TEXT_DECODER
+#define text_options options
+DECLARE_CLASS(text);
+
+AVCodec ff_text_decoder = {
+ .name = "text",
+ .long_name = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
+ .priv_data_size = sizeof(TextContext),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_TEXT,
+ .decode = text_decode_frame,
+ .init = ff_ass_subtitle_header_default,
+ .priv_class = &text_decoder_class,
+};
+#endif
+
+#if CONFIG_VPLAYER_DECODER || CONFIG_PJS_DECODER || CONFIG_SUBVIEWER1_DECODER || CONFIG_STL_DECODER
+
+static int linebreak_init(AVCodecContext *avctx)
+{
+ TextContext *text = avctx->priv_data;
+ text->linebreaks = "|";
+ return ff_ass_subtitle_header_default(avctx);
+}
+
+#if CONFIG_VPLAYER_DECODER
+#define vplayer_options options
+DECLARE_CLASS(vplayer);
+
+AVCodec ff_vplayer_decoder = {
+ .name = "vplayer",
+ .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"),
+ .priv_data_size = sizeof(TextContext),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_VPLAYER,
+ .decode = text_decode_frame,
+ .init = linebreak_init,
+ .priv_class = &vplayer_decoder_class,
+};
+#endif
+
+#if CONFIG_STL_DECODER
+#define stl_options options
+DECLARE_CLASS(stl);
+
+AVCodec ff_stl_decoder = {
+ .name = "stl",
+ .long_name = NULL_IF_CONFIG_SMALL("Spruce subtitle format"),
+ .priv_data_size = sizeof(TextContext),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_STL,
+ .decode = text_decode_frame,
+ .init = linebreak_init,
+ .priv_class = &stl_decoder_class,
+};
+#endif
+
+#if CONFIG_PJS_DECODER
+#define pjs_options options
+DECLARE_CLASS(pjs);
+
+AVCodec ff_pjs_decoder = {
+ .name = "pjs",
+ .long_name = NULL_IF_CONFIG_SMALL("PJS subtitle"),
+ .priv_data_size = sizeof(TextContext),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_PJS,
+ .decode = text_decode_frame,
+ .init = linebreak_init,
+ .priv_class = &pjs_decoder_class,
+};
+#endif
+
+#if CONFIG_SUBVIEWER1_DECODER
+#define subviewer1_options options
+DECLARE_CLASS(subviewer1);
+
+AVCodec ff_subviewer1_decoder = {
+ .name = "subviewer1",
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer1 subtitle"),
+ .priv_data_size = sizeof(TextContext),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_SUBVIEWER1,
+ .decode = text_decode_frame,
+ .init = linebreak_init,
+ .priv_class = &subviewer1_decoder_class,
+};
+#endif
+
+#endif /* text subtitles with '|' line break */
diff --git a/libavcodec/thread.h b/libavcodec/thread.h
index 864e67eb98..c848d7ae8b 100644
--- a/libavcodec/thread.h
+++ b/libavcodec/thread.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Alexander Strange <astrange@ithinksw.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -98,6 +98,16 @@ void ff_thread_report_progress(ThreadFrame *f, int progress, int field);
void ff_thread_await_progress(ThreadFrame *f, int progress, int field);
/**
+ * Wrapper around get_format() for frame-multithreaded codecs.
+ * Call this function instead of avctx->get_format().
+ * Cannot be called after the codec has called ff_thread_finish_setup().
+ *
+ * @param avctx The current context.
+ * @param fmt The list of available formats.
+ */
+enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt);
+
+/**
* Wrapper around get_buffer() for frame-multithreaded codecs.
* Call this function instead of ff_get_buffer(f).
* Cannot be called after the codec has called ff_thread_finish_setup().
@@ -125,4 +135,9 @@ int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src);
int ff_thread_init(AVCodecContext *s);
void ff_thread_free(AVCodecContext *s);
+int ff_alloc_entries(AVCodecContext *avctx, int count);
+void ff_reset_entries(AVCodecContext *avctx);
+void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n);
+void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift);
+
#endif /* AVCODEC_THREAD_H */
diff --git a/libavcodec/tiertexseqv.c b/libavcodec/tiertexseqv.c
index 33b257954f..7c62208dc5 100644
--- a/libavcodec/tiertexseqv.c
+++ b/libavcodec/tiertexseqv.c
@@ -2,20 +2,20 @@
* Tiertex Limited SEQ Video Decoder
* Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -179,7 +179,7 @@ static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int
for (i = 0; i < 256; i++) {
for (j = 0; j < 3; j++, data++)
c[j] = (*data << 2) | (*data >> 4);
- palette[i] = AV_RB24(c);
+ palette[i] = 0xFFU << 24 | AV_RB24(c);
}
seq->frame->palette_has_changed = 1;
}
@@ -234,10 +234,8 @@ static int seqvideo_decode_frame(AVCodecContext *avctx,
SeqVideoContext *seq = avctx->priv_data;
- if ((ret = ff_reget_buffer(avctx, seq->frame)) < 0) {
- av_log(seq->avctx, AV_LOG_ERROR, "tiertexseqvideo: reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, seq->frame)) < 0)
return ret;
- }
if (seqvideo_decode(seq, buf, buf_size))
return AVERROR_INVALIDDATA;
diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
index b071c3bf3a..7a7f9b748d 100644
--- a/libavcodec/tiff.c
+++ b/libavcodec/tiff.c
@@ -1,21 +1,20 @@
/*
- * TIFF image decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,8 +28,13 @@
#if CONFIG_ZLIB
#include <zlib.h>
#endif
+#if CONFIG_LZMA
+#define LZMA_API_STATIC
+#include <lzma.h>
+#endif
#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/imgutils.h"
#include "avcodec.h"
@@ -40,6 +44,8 @@
#include "lzw.h"
#include "mathops.h"
#include "tiff.h"
+#include "tiff_data.h"
+#include "thread.h"
typedef struct TiffContext {
AVCodecContext *avctx;
@@ -53,33 +59,259 @@ typedef struct TiffContext {
enum TiffCompr compr;
enum TiffPhotometric photometric;
int planar;
+ int subsampling[2];
int fax_opts;
int predictor;
int fill_order;
+ uint32_t res[4];
int strips, rps, sstype;
int sot;
int stripsizesoff, stripsize, stripoff, strippos;
LZWState *lzw;
+
+ uint8_t *deinvert_buf;
+ int deinvert_buf_size;
+ uint8_t *yuv_line;
+ unsigned int yuv_line_size;
+
+ int geotag_count;
+ TiffGeoTag *geotags;
} TiffContext;
-static unsigned tget_short(GetByteContext *gb, int le)
+static void free_geotags(TiffContext *const s)
+{
+ int i;
+ for (i = 0; i < s->geotag_count; i++) {
+ if (s->geotags[i].val)
+ av_freep(&s->geotags[i].val);
+ }
+ av_freep(&s->geotags);
+ s->geotag_count = 0;
+}
+
+#define RET_GEOKEY(TYPE, array, element)\
+ if (key >= TIFF_##TYPE##_KEY_ID_OFFSET &&\
+ key - TIFF_##TYPE##_KEY_ID_OFFSET < FF_ARRAY_ELEMS(ff_tiff_##array##_name_type_map))\
+ return ff_tiff_##array##_name_type_map[key - TIFF_##TYPE##_KEY_ID_OFFSET].element;
+
+static const char *get_geokey_name(int key)
+{
+ RET_GEOKEY(VERT, vert, name);
+ RET_GEOKEY(PROJ, proj, name);
+ RET_GEOKEY(GEOG, geog, name);
+ RET_GEOKEY(CONF, conf, name);
+
+ return NULL;
+}
+
+static int get_geokey_type(int key)
+{
+ RET_GEOKEY(VERT, vert, type);
+ RET_GEOKEY(PROJ, proj, type);
+ RET_GEOKEY(GEOG, geog, type);
+ RET_GEOKEY(CONF, conf, type);
+
+ return AVERROR_INVALIDDATA;
+}
+
+static int cmp_id_key(const void *id, const void *k)
+{
+ return *(const int*)id - ((const TiffGeoTagKeyName*)k)->key;
+}
+
+static const char *search_keyval(const TiffGeoTagKeyName *keys, int n, int id)
+{
+ TiffGeoTagKeyName *r = bsearch(&id, keys, n, sizeof(keys[0]), cmp_id_key);
+ if(r)
+ return r->name;
+
+ return NULL;
+}
+
+static char *get_geokey_val(int key, int val)
+{
+ char *ap;
+
+ if (val == TIFF_GEO_KEY_UNDEFINED)
+ return av_strdup("undefined");
+ if (val == TIFF_GEO_KEY_USER_DEFINED)
+ return av_strdup("User-Defined");
+
+#define RET_GEOKEY_VAL(TYPE, array)\
+ if (val >= TIFF_##TYPE##_OFFSET &&\
+ val - TIFF_##TYPE##_OFFSET < FF_ARRAY_ELEMS(ff_tiff_##array##_codes))\
+ return av_strdup(ff_tiff_##array##_codes[val - TIFF_##TYPE##_OFFSET]);
+
+ switch (key) {
+ case TIFF_GT_MODEL_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GT_MODEL_TYPE, gt_model_type);
+ break;
+ case TIFF_GT_RASTER_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GT_RASTER_TYPE, gt_raster_type);
+ break;
+ case TIFF_GEOG_LINEAR_UNITS_GEOKEY:
+ case TIFF_PROJ_LINEAR_UNITS_GEOKEY:
+ case TIFF_VERTICAL_UNITS_GEOKEY:
+ RET_GEOKEY_VAL(LINEAR_UNIT, linear_unit);
+ break;
+ case TIFF_GEOG_ANGULAR_UNITS_GEOKEY:
+ case TIFF_GEOG_AZIMUTH_UNITS_GEOKEY:
+ RET_GEOKEY_VAL(ANGULAR_UNIT, angular_unit);
+ break;
+ case TIFF_GEOGRAPHIC_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(GCS_TYPE, gcs_type);
+ RET_GEOKEY_VAL(GCSE_TYPE, gcse_type);
+ break;
+ case TIFF_GEOG_GEODETIC_DATUM_GEOKEY:
+ RET_GEOKEY_VAL(GEODETIC_DATUM, geodetic_datum);
+ RET_GEOKEY_VAL(GEODETIC_DATUM_E, geodetic_datum_e);
+ break;
+ case TIFF_GEOG_ELLIPSOID_GEOKEY:
+ RET_GEOKEY_VAL(ELLIPSOID, ellipsoid);
+ break;
+ case TIFF_GEOG_PRIME_MERIDIAN_GEOKEY:
+ RET_GEOKEY_VAL(PRIME_MERIDIAN, prime_meridian);
+ break;
+ case TIFF_PROJECTED_CS_TYPE_GEOKEY:
+ ap = av_strdup(search_keyval(ff_tiff_proj_cs_type_codes, FF_ARRAY_ELEMS(ff_tiff_proj_cs_type_codes), val));
+ if(ap) return ap;
+ break;
+ case TIFF_PROJECTION_GEOKEY:
+ ap = av_strdup(search_keyval(ff_tiff_projection_codes, FF_ARRAY_ELEMS(ff_tiff_projection_codes), val));
+ if(ap) return ap;
+ break;
+ case TIFF_PROJ_COORD_TRANS_GEOKEY:
+ RET_GEOKEY_VAL(COORD_TRANS, coord_trans);
+ break;
+ case TIFF_VERTICAL_CS_TYPE_GEOKEY:
+ RET_GEOKEY_VAL(VERT_CS, vert_cs);
+ RET_GEOKEY_VAL(ORTHO_VERT_CS, ortho_vert_cs);
+ break;
+
+ }
+
+ ap = av_malloc(14);
+ if (ap)
+ snprintf(ap, 14, "Unknown-%d", val);
+ return ap;
+}
+
+static char *doubles2str(double *dp, int count, const char *sep)
+{
+ int i;
+ char *ap, *ap0;
+ uint64_t component_len;
+ if (!sep) sep = ", ";
+ component_len = 24LL + strlen(sep);
+ if (count >= (INT_MAX - 1)/component_len)
+ return NULL;
+ ap = av_malloc(component_len * count + 1);
+ if (!ap)
+ return NULL;
+ ap0 = ap;
+ ap[0] = '\0';
+ for (i = 0; i < count; i++) {
+ unsigned l = snprintf(ap, component_len, "%.15g%s", dp[i], sep);
+ if(l >= component_len) {
+ av_free(ap0);
+ return NULL;
+ }
+ ap += l;
+ }
+ ap0[strlen(ap0) - strlen(sep)] = '\0';
+ return ap0;
+}
+
+static int add_metadata(int count, int type,
+ const char *name, const char *sep, TiffContext *s, AVFrame *frame)
+{
+ switch(type) {
+ case TIFF_DOUBLE: return ff_tadd_doubles_metadata(count, name, sep, &s->gb, s->le, avpriv_frame_get_metadatap(frame));
+ case TIFF_SHORT : return ff_tadd_shorts_metadata(count, name, sep, &s->gb, s->le, 0, avpriv_frame_get_metadatap(frame));
+ case TIFF_STRING: return ff_tadd_string_metadata(count, name, &s->gb, s->le, avpriv_frame_get_metadatap(frame));
+ default : return AVERROR_INVALIDDATA;
+ };
+}
+
+static void av_always_inline horizontal_fill(unsigned int bpp, uint8_t* dst,
+ int usePtr, const uint8_t *src,
+ uint8_t c, int width, int offset)
{
- return le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
+ switch (bpp) {
+ case 1:
+ while (--width >= 0) {
+ dst[(width+offset)*8+7] = (usePtr ? src[width] : c) & 0x1;
+ dst[(width+offset)*8+6] = (usePtr ? src[width] : c) >> 1 & 0x1;
+ dst[(width+offset)*8+5] = (usePtr ? src[width] : c) >> 2 & 0x1;
+ dst[(width+offset)*8+4] = (usePtr ? src[width] : c) >> 3 & 0x1;
+ dst[(width+offset)*8+3] = (usePtr ? src[width] : c) >> 4 & 0x1;
+ dst[(width+offset)*8+2] = (usePtr ? src[width] : c) >> 5 & 0x1;
+ dst[(width+offset)*8+1] = (usePtr ? src[width] : c) >> 6 & 0x1;
+ dst[(width+offset)*8+0] = (usePtr ? src[width] : c) >> 7;
+ }
+ break;
+ case 2:
+ while (--width >= 0) {
+ dst[(width+offset)*4+3] = (usePtr ? src[width] : c) & 0x3;
+ dst[(width+offset)*4+2] = (usePtr ? src[width] : c) >> 2 & 0x3;
+ dst[(width+offset)*4+1] = (usePtr ? src[width] : c) >> 4 & 0x3;
+ dst[(width+offset)*4+0] = (usePtr ? src[width] : c) >> 6;
+ }
+ break;
+ case 4:
+ while (--width >= 0) {
+ dst[(width+offset)*2+1] = (usePtr ? src[width] : c) & 0xF;
+ dst[(width+offset)*2+0] = (usePtr ? src[width] : c) >> 4;
+ }
+ break;
+ default:
+ if (usePtr) {
+ memcpy(dst + offset, src, width);
+ } else {
+ memset(dst + offset, c, width);
+ }
+ }
}
-static unsigned tget_long(GetByteContext *gb, int le)
+static int deinvert_buffer(TiffContext *s, const uint8_t *src, int size)
{
- return le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
+ int i;
+
+ av_fast_padded_malloc(&s->deinvert_buf, &s->deinvert_buf_size, size);
+ if (!s->deinvert_buf)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < size; i++)
+ s->deinvert_buf[i] = ff_reverse[src[i]];
+
+ return 0;
}
-static unsigned tget(GetByteContext *gb, int type, int le)
+static void unpack_yuv(TiffContext *s, AVFrame *p,
+ const uint8_t *src, int lnum)
{
- switch (type) {
- case TIFF_BYTE: return bytestream2_get_byte(gb);
- case TIFF_SHORT: return tget_short(gb, le);
- case TIFF_LONG: return tget_long(gb, le);
- default: return UINT_MAX;
+ int i, j, k;
+ int w = (s->width - 1) / s->subsampling[0] + 1;
+ uint8_t *pu = &p->data[1][lnum / s->subsampling[1] * p->linesize[1]];
+ uint8_t *pv = &p->data[2][lnum / s->subsampling[1] * p->linesize[2]];
+ if (s->width % s->subsampling[0] || s->height % s->subsampling[1]) {
+ for (i = 0; i < w; i++) {
+ for (j = 0; j < s->subsampling[1]; j++)
+ for (k = 0; k < s->subsampling[0]; k++)
+ p->data[0][FFMIN(lnum + j, s->height-1) * p->linesize[0] +
+ FFMIN(i * s->subsampling[0] + k, s->width-1)] = *src++;
+ *pu++ = *src++;
+ *pv++ = *src++;
+ }
+ }else{
+ for (i = 0; i < w; i++) {
+ for (j = 0; j < s->subsampling[1]; j++)
+ for (k = 0; k < s->subsampling[0]; k++)
+ p->data[0][(lnum + j) * p->linesize[0] +
+ i * s->subsampling[0] + k] = *src++;
+ *pu++ = *src++;
+ *pv++ = *src++;
+ }
}
}
@@ -90,7 +322,7 @@ static int tiff_uncompress(uint8_t *dst, unsigned long *len, const uint8_t *src,
z_stream zstream = { 0 };
int zret;
- zstream.next_in = src;
+ zstream.next_in = (uint8_t *)src;
zstream.avail_in = size;
zstream.next_out = dst;
zstream.avail_out = *len;
@@ -105,9 +337,9 @@ static int tiff_uncompress(uint8_t *dst, unsigned long *len, const uint8_t *src,
return zret == Z_STREAM_END ? Z_OK : zret;
}
-static int tiff_unpack_zlib(TiffContext *s, uint8_t *dst, int stride,
- const uint8_t *src, int size,
- int width, int lines)
+static int tiff_unpack_zlib(TiffContext *s, AVFrame *p, uint8_t *dst, int stride,
+ const uint8_t *src, int size, int width, int lines,
+ int strip_start, int is_yuv)
{
uint8_t *zbuf;
unsigned long outlen;
@@ -116,6 +348,13 @@ static int tiff_unpack_zlib(TiffContext *s, uint8_t *dst, int stride,
zbuf = av_malloc(outlen);
if (!zbuf)
return AVERROR(ENOMEM);
+ if (s->fill_order) {
+ if ((ret = deinvert_buffer(s, src, size)) < 0) {
+ av_free(zbuf);
+ return ret;
+ }
+ src = s->deinvert_buf;
+ }
ret = tiff_uncompress(zbuf, &outlen, src, size);
if (ret != Z_OK) {
av_log(s->avctx, AV_LOG_ERROR,
@@ -126,7 +365,15 @@ static int tiff_unpack_zlib(TiffContext *s, uint8_t *dst, int stride,
}
src = zbuf;
for (line = 0; line < lines; line++) {
- memcpy(dst, src, width);
+ if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ horizontal_fill(s->bpp, dst, 1, src, 0, width, 0);
+ } else {
+ memcpy(dst, src, width);
+ }
+ if (is_yuv) {
+ unpack_yuv(s, p, dst, strip_start + line);
+ line += s->subsampling[1] - 1;
+ }
dst += stride;
src += width;
}
@@ -135,11 +382,76 @@ static int tiff_unpack_zlib(TiffContext *s, uint8_t *dst, int stride,
}
#endif
+#if CONFIG_LZMA
+static int tiff_uncompress_lzma(uint8_t *dst, uint64_t *len, const uint8_t *src,
+ int size)
+{
+ lzma_stream stream = LZMA_STREAM_INIT;
+ lzma_ret ret;
+
+ stream.next_in = (uint8_t *)src;
+ stream.avail_in = size;
+ stream.next_out = dst;
+ stream.avail_out = *len;
+ ret = lzma_stream_decoder(&stream, UINT64_MAX, 0);
+ if (ret != LZMA_OK) {
+ av_log(NULL, AV_LOG_ERROR, "LZMA init error: %d\n", ret);
+ return ret;
+ }
+ ret = lzma_code(&stream, LZMA_RUN);
+ lzma_end(&stream);
+ *len = stream.total_out;
+ return ret == LZMA_STREAM_END ? LZMA_OK : ret;
+}
+
+static int tiff_unpack_lzma(TiffContext *s, AVFrame *p, uint8_t *dst, int stride,
+ const uint8_t *src, int size, int width, int lines,
+ int strip_start, int is_yuv)
+{
+ uint64_t outlen = width * lines;
+ int ret, line;
+ uint8_t *buf = av_malloc(outlen);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ if (s->fill_order) {
+ if ((ret = deinvert_buffer(s, src, size)) < 0) {
+ av_free(buf);
+ return ret;
+ }
+ src = s->deinvert_buf;
+ }
+ ret = tiff_uncompress_lzma(buf, &outlen, src, size);
+ if (ret != LZMA_OK) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Uncompressing failed (%"PRIu64" of %"PRIu64") with error %d\n", outlen,
+ (uint64_t)width * lines, ret);
+ av_free(buf);
+ return AVERROR_UNKNOWN;
+ }
+ src = buf;
+ for (line = 0; line < lines; line++) {
+ if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) {
+ horizontal_fill(s->bpp, dst, 1, src, 0, width, 0);
+ } else {
+ memcpy(dst, src, width);
+ }
+ if (is_yuv) {
+ unpack_yuv(s, p, dst, strip_start + line);
+ line += s->subsampling[1] - 1;
+ }
+ dst += stride;
+ src += width;
+ }
+ av_free(buf);
+ return 0;
+}
+#endif
static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride,
- const uint8_t *src, int size, int lines)
+ const uint8_t *src, int size, int width, int lines)
{
int i, ret = 0;
+ int line;
uint8_t *src2 = av_malloc((unsigned)size +
FF_INPUT_BUFFER_PADDING_SIZE);
@@ -162,16 +474,26 @@ static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride,
memset(src2 + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
ret = ff_ccitt_unpack(s->avctx, src2, size, dst, lines, stride,
s->compr, s->fax_opts);
+ if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
+ for (line = 0; line < lines; line++) {
+ horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0);
+ dst += stride;
+ }
av_free(src2);
return ret;
}
-static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
- const uint8_t *src, int size, int lines)
+static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int stride,
+ const uint8_t *src, int size, int strip_start, int lines)
{
PutByteContext pb;
int c, line, pixels, code, ret;
+ const uint8_t *ssrc = src;
int width = ((s->width * s->bpp) + 7) >> 3;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(p->format);
+ int is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB) &&
+ (desc->flags & AV_PIX_FMT_FLAG_PLANAR) &&
+ desc->nb_components >= 3;
if (s->planar)
width /= s->bppcount;
@@ -179,9 +501,27 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
if (size <= 0)
return AVERROR_INVALIDDATA;
+ if (is_yuv) {
+ int bytes_per_row = (((s->width - 1) / s->subsampling[0] + 1) * s->bpp *
+ s->subsampling[0] * s->subsampling[1] + 7) >> 3;
+ av_fast_padded_malloc(&s->yuv_line, &s->yuv_line_size, bytes_per_row);
+ if (s->yuv_line == NULL) {
+ av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n");
+ return AVERROR(ENOMEM);
+ }
+ dst = s->yuv_line;
+ stride = 0;
+
+ width = (s->width - 1) / s->subsampling[0] + 1;
+ width = width * s->subsampling[0] * s->subsampling[1] + 2*width;
+ av_assert0(width <= bytes_per_row);
+ av_assert0(s->bpp == 24);
+ }
+
if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) {
#if CONFIG_ZLIB
- return tiff_unpack_zlib(s, dst, stride, src, size, width, lines);
+ return tiff_unpack_zlib(s, p, dst, stride, src, size, width, lines,
+ strip_start, is_yuv);
#else
av_log(s->avctx, AV_LOG_ERROR,
"zlib support not enabled, "
@@ -189,7 +529,25 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
return AVERROR(ENOSYS);
#endif
}
+ if (s->compr == TIFF_LZMA) {
+#if CONFIG_LZMA
+ return tiff_unpack_lzma(s, p, dst, stride, src, size, width, lines,
+ strip_start, is_yuv);
+#else
+ av_log(s->avctx, AV_LOG_ERROR,
+ "LZMA support not enabled\n");
+ return AVERROR(ENOSYS);
+#endif
+ }
if (s->compr == TIFF_LZW) {
+ if (s->fill_order) {
+ if ((ret = deinvert_buffer(s, src, size)) < 0)
+ return ret;
+ ssrc = src = s->deinvert_buf;
+ }
+ if (size > 1 && !src[0] && (src[1]&1)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Old style LZW is unsupported\n");
+ }
if ((ret = ff_lzw_decode_init(s->lzw, 8, src, size, FF_LZW_TIFF)) < 0) {
av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n");
return ret;
@@ -201,6 +559,12 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
pixels, width);
return AVERROR_INVALIDDATA;
}
+ if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
+ horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0);
+ if (is_yuv) {
+ unpack_yuv(s, p, dst, strip_start + line);
+ line += s->subsampling[1] - 1;
+ }
dst += stride;
}
return 0;
@@ -208,49 +572,91 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
if (s->compr == TIFF_CCITT_RLE ||
s->compr == TIFF_G3 ||
s->compr == TIFF_G4) {
- return tiff_unpack_fax(s, dst, stride, src, size, lines);
+ if (is_yuv)
+ return AVERROR_INVALIDDATA;
+
+ return tiff_unpack_fax(s, dst, stride, src, size, width, lines);
}
bytestream2_init(&s->gb, src, size);
- bytestream2_init_writer(&pb, dst, stride * lines);
+ bytestream2_init_writer(&pb, dst, is_yuv ? s->yuv_line_size : (stride * lines));
for (line = 0; line < lines; line++) {
+ if (src - ssrc > size) {
+ av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n");
+ return AVERROR_INVALIDDATA;
+ }
+
if (bytestream2_get_bytes_left(&s->gb) == 0 || bytestream2_get_eof(&pb))
break;
bytestream2_seek_p(&pb, stride * line, SEEK_SET);
switch (s->compr) {
case TIFF_RAW:
+ if (ssrc + size - src < width)
+ return AVERROR_INVALIDDATA;
+
if (!s->fill_order) {
- bytestream2_copy_buffer(&pb, &s->gb, width);
+ horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8),
+ dst, 1, src, 0, width, 0);
} else {
int i;
for (i = 0; i < width; i++)
- bytestream2_put_byte(&pb, ff_reverse[bytestream2_get_byte(&s->gb)]);
+ dst[i] = ff_reverse[src[i]];
}
+ src += width;
break;
case TIFF_PACKBITS:
for (pixels = 0; pixels < width;) {
- code = ff_u8_to_s8(bytestream2_get_byte(&s->gb));
+ if (ssrc + size - src < 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "Read went out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+ code = s->fill_order ? (int8_t) ff_reverse[*src++]: (int8_t) *src++;
if (code >= 0) {
code++;
- bytestream2_copy_buffer(&pb, &s->gb, code);
+ if (pixels + code > width ||
+ ssrc + size - src < code) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Copy went out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+ horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8),
+ dst, 1, src, 0, code, pixels);
+ src += code;
pixels += code;
} else if (code != -128) { // -127..-1
code = (-code) + 1;
- c = bytestream2_get_byte(&s->gb);
- bytestream2_set_buffer(&pb, c, code);
+ if (pixels + code > width) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Run went out of bounds\n");
+ return AVERROR_INVALIDDATA;
+ }
+ c = *src++;
+ horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8),
+ dst, 0, NULL, c, code, pixels);
pixels += code;
}
}
+ if (s->fill_order) {
+ int i;
+ for (i = 0; i < width; i++)
+ dst[i] = ff_reverse[dst[i]];
+ }
break;
}
+ if (is_yuv) {
+ unpack_yuv(s, p, dst, strip_start + line);
+ line += s->subsampling[1] - 1;
+ }
+ dst += stride;
}
return 0;
}
-static int init_image(TiffContext *s, AVFrame *frame)
+static int init_image(TiffContext *s, ThreadFrame *frame)
{
int ret;
+ int create_gray_palette = 0;
// make sure there is no aliasing in the following switch
if (s->bpp >= 100 || s->bppcount >= 10) {
@@ -262,13 +668,40 @@ static int init_image(TiffContext *s, AVFrame *frame)
switch (s->planar * 1000 + s->bpp * 10 + s->bppcount) {
case 11:
- s->avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
+ if (!s->palette_is_set) {
+ s->avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
+ break;
+ }
+ case 21:
+ case 41:
+ s->avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ if (!s->palette_is_set) {
+ create_gray_palette = 1;
+ }
break;
case 81:
s->avctx->pix_fmt = s->palette_is_set ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8;
break;
case 243:
- s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) {
+ if (s->subsampling[0] == 1 && s->subsampling[1] == 1) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+ } else if (s->subsampling[0] == 2 && s->subsampling[1] == 1) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV422P;
+ } else if (s->subsampling[0] == 4 && s->subsampling[1] == 1) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV411P;
+ } else if (s->subsampling[0] == 1 && s->subsampling[1] == 2) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV440P;
+ } else if (s->subsampling[0] == 2 && s->subsampling[1] == 2) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ } else if (s->subsampling[0] == 4 && s->subsampling[1] == 4) {
+ s->avctx->pix_fmt = AV_PIX_FMT_YUV410P;
+ } else {
+ av_log(s->avctx, AV_LOG_ERROR, "Unsupported YCbCr subsampling\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ } else
+ s->avctx->pix_fmt = AV_PIX_FMT_RGB24;
break;
case 161:
s->avctx->pix_fmt = s->le ? AV_PIX_FMT_GRAY16LE : AV_PIX_FMT_GRAY16BE;
@@ -283,10 +716,10 @@ static int init_image(TiffContext *s, AVFrame *frame)
s->avctx->pix_fmt = AV_PIX_FMT_RGBA;
break;
case 483:
- s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB48BE;
+ s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB48BE;
break;
case 644:
- s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGBA64BE;
+ s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_RGBA64BE;
break;
case 1243:
s->avctx->pix_fmt = AV_PIX_FMT_GBRP;
@@ -306,64 +739,80 @@ static int init_image(TiffContext *s, AVFrame *frame)
s->bpp, s->bppcount);
return AVERROR_INVALIDDATA;
}
+
+ if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->avctx->pix_fmt);
+ if((desc->flags & AV_PIX_FMT_FLAG_RGB) ||
+ !(desc->flags & AV_PIX_FMT_FLAG_PLANAR) ||
+ desc->nb_components < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "Unsupported YCbCr variant\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
if (s->width != s->avctx->width || s->height != s->avctx->height) {
ret = ff_set_dimensions(s->avctx, s->width, s->height);
if (ret < 0)
return ret;
}
- if ((ret = ff_get_buffer(s->avctx, frame, 0)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(s->avctx, frame, 0)) < 0)
return ret;
- }
if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8) {
- memcpy(frame->data[1], s->palette, sizeof(s->palette));
+ if (!create_gray_palette)
+ memcpy(frame->f->data[1], s->palette, sizeof(s->palette));
+ else {
+ /* make default grayscale pal */
+ int i;
+ uint32_t *pal = (uint32_t *)frame->f->data[1];
+ for (i = 0; i < 1<<s->bpp; i++)
+ pal[i] = 0xFFU << 24 | i * 255 / ((1<<s->bpp) - 1) * 0x010101;
+ }
}
return 0;
}
-static int tiff_decode_tag(TiffContext *s)
+static void set_sar(TiffContext *s, unsigned tag, unsigned num, unsigned den)
+{
+ int offset = tag == TIFF_YRES ? 2 : 0;
+ s->res[offset++] = num;
+ s->res[offset] = den;
+ if (s->res[0] && s->res[1] && s->res[2] && s->res[3])
+ av_reduce(&s->avctx->sample_aspect_ratio.num, &s->avctx->sample_aspect_ratio.den,
+ s->res[2] * (uint64_t)s->res[1], s->res[0] * (uint64_t)s->res[3], INT32_MAX);
+}
+
+static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
{
- unsigned tag, type, count, off, value = 0;
+ unsigned tag, type, count, off, value = 0, value2 = 0;
int i, start;
+ int pos;
+ int ret;
+ double *dp;
- if (bytestream2_get_bytes_left(&s->gb) < 12)
- return AVERROR_INVALIDDATA;
- tag = tget_short(&s->gb, s->le);
- type = tget_short(&s->gb, s->le);
- count = tget_long(&s->gb, s->le);
- off = tget_long(&s->gb, s->le);
- start = bytestream2_tell(&s->gb);
-
- if (type == 0 || type >= FF_ARRAY_ELEMS(type_sizes)) {
- av_log(s->avctx, AV_LOG_DEBUG, "Unknown tiff type (%u) encountered\n",
- type);
- return 0;
+ ret = ff_tread_tag(&s->gb, s->le, &tag, &type, &count, &start);
+ if (ret < 0) {
+ goto end;
}
+ off = bytestream2_tell(&s->gb);
if (count == 1) {
switch (type) {
case TIFF_BYTE:
case TIFF_SHORT:
- bytestream2_seek(&s->gb, -4, SEEK_CUR);
- value = tget(&s->gb, type, s->le);
- break;
case TIFF_LONG:
- value = off;
+ value = ff_tget(&s->gb, type, s->le);
+ break;
+ case TIFF_RATIONAL:
+ value = ff_tget(&s->gb, TIFF_LONG, s->le);
+ value2 = ff_tget(&s->gb, TIFF_LONG, s->le);
break;
case TIFF_STRING:
if (count <= 4) {
- bytestream2_seek(&s->gb, -4, SEEK_CUR);
break;
}
default:
value = UINT_MAX;
- bytestream2_seek(&s->gb, off, SEEK_SET);
}
- } else {
- if (count <= 4 && type_sizes[type] * count <= 4)
- bytestream2_seek(&s->gb, -4, SEEK_CUR);
- else
- bytestream2_seek(&s->gb, off, SEEK_SET);
}
switch (tag) {
@@ -374,26 +823,25 @@ static int tiff_decode_tag(TiffContext *s)
s->height = value;
break;
case TIFF_BPP:
- s->bppcount = count;
- if (count > 4) {
+ if (count > 4U) {
av_log(s->avctx, AV_LOG_ERROR,
"This format is not supported (bpp=%d, %d components)\n",
- s->bpp, count);
+ value, count);
return AVERROR_INVALIDDATA;
}
+ s->bppcount = count;
if (count == 1)
s->bpp = value;
else {
switch (type) {
case TIFF_BYTE:
- s->bpp = (off & 0xFF) + ((off >> 8) & 0xFF) +
- ((off >> 16) & 0xFF) + ((off >> 24) & 0xFF);
- break;
case TIFF_SHORT:
case TIFF_LONG:
s->bpp = 0;
+ if (bytestream2_get_bytes_left(&s->gb) < type_sizes[type] * count)
+ return AVERROR_INVALIDDATA;
for (i = 0; i < count; i++)
- s->bpp += tget(&s->gb, type, s->le);
+ s->bpp += ff_tget(&s->gb, type, s->le);
break;
default:
s->bpp = -1;
@@ -406,6 +854,11 @@ static int tiff_decode_tag(TiffContext *s)
"Samples per pixel requires a single value, many provided\n");
return AVERROR_INVALIDDATA;
}
+ if (value > 4U) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "Samples per pixel %d is too large\n", value);
+ return AVERROR_INVALIDDATA;
+ }
if (s->bppcount == 1)
s->bpp *= value;
s->bppcount = value;
@@ -436,8 +889,12 @@ static int tiff_decode_tag(TiffContext *s)
avpriv_report_missing_feature(s->avctx, "JPEG compression");
return AVERROR_PATCHWELCOME;
case TIFF_LZMA:
- avpriv_report_missing_feature(s->avctx, "LZMA compression");
- return AVERROR_PATCHWELCOME;
+#if CONFIG_LZMA
+ break;
+#else
+ av_log(s->avctx, AV_LOG_ERROR, "LZMA not compiled in\n");
+ return AVERROR(ENOSYS);
+#endif
default:
av_log(s->avctx, AV_LOG_ERROR, "Unknown compression method %i\n",
s->compr);
@@ -471,6 +928,17 @@ static int tiff_decode_tag(TiffContext *s)
s->strips = count;
s->sstype = type;
break;
+ case TIFF_XRES:
+ case TIFF_YRES:
+ set_sar(s, tag, value, value2);
+ break;
+ case TIFF_TILE_BYTE_COUNTS:
+ case TIFF_TILE_LENGTH:
+ case TIFF_TILE_OFFSETS:
+ case TIFF_TILE_WIDTH:
+ av_log(s->avctx, AV_LOG_ERROR, "Tiled images are not supported\n");
+ return AVERROR_PATCHWELCOME;
+ break;
case TIFF_PREDICTOR:
s->predictor = value;
break;
@@ -480,11 +948,11 @@ static int tiff_decode_tag(TiffContext *s)
case TIFF_PHOTOMETRIC_BLACK_IS_ZERO:
case TIFF_PHOTOMETRIC_RGB:
case TIFF_PHOTOMETRIC_PALETTE:
+ case TIFF_PHOTOMETRIC_YCBCR:
s->photometric = value;
break;
case TIFF_PHOTOMETRIC_ALPHA_MASK:
case TIFF_PHOTOMETRIC_SEPARATED:
- case TIFF_PHOTOMETRIC_YCBCR:
case TIFF_PHOTOMETRIC_CIE_LAB:
case TIFF_PHOTOMETRIC_ICC_LAB:
case TIFF_PHOTOMETRIC_ITU_LAB:
@@ -516,15 +984,17 @@ static int tiff_decode_tag(TiffContext *s)
if (count / 3 > 256 ||
bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3)
return AVERROR_INVALIDDATA;
+
pal_gb[0] = pal_gb[1] = pal_gb[2] = s->gb;
bytestream2_skip(&pal_gb[1], count / 3 * off);
bytestream2_skip(&pal_gb[2], count / 3 * off * 2);
+
off = (type_sizes[type] - 1) << 3;
for (i = 0; i < count / 3; i++) {
uint32_t p = 0xFF000000;
- p |= (tget(&pal_gb[0], type, s->le) >> off) << 16;
- p |= (tget(&pal_gb[1], type, s->le) >> off) << 8;
- p |= tget(&pal_gb[2], type, s->le) >> off;
+ p |= (ff_tget(&pal_gb[0], type, s->le) >> off) << 16;
+ p |= (ff_tget(&pal_gb[1], type, s->le) >> off) << 8;
+ p |= ff_tget(&pal_gb[2], type, s->le) >> off;
s->palette[i] = p;
}
s->palette_is_set = 1;
@@ -533,6 +1003,14 @@ static int tiff_decode_tag(TiffContext *s)
case TIFF_PLANAR:
s->planar = value == 2;
break;
+ case TIFF_YCBCR_SUBSAMPLING:
+ if (count != 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "subsample count invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < count; i++)
+ s->subsampling[i] = ff_tget(&s->gb, type, s->le);
+ break;
case TIFF_T4OPTIONS:
if (s->compr == TIFF_G3)
s->fax_opts = value;
@@ -541,6 +1019,137 @@ static int tiff_decode_tag(TiffContext *s)
if (s->compr == TIFF_G4)
s->fax_opts = value;
break;
+#define ADD_METADATA(count, name, sep)\
+ if ((ret = add_metadata(count, type, name, sep, s, frame)) < 0) {\
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");\
+ goto end;\
+ }
+ case TIFF_MODEL_PIXEL_SCALE:
+ ADD_METADATA(count, "ModelPixelScaleTag", NULL);
+ break;
+ case TIFF_MODEL_TRANSFORMATION:
+ ADD_METADATA(count, "ModelTransformationTag", NULL);
+ break;
+ case TIFF_MODEL_TIEPOINT:
+ ADD_METADATA(count, "ModelTiepointTag", NULL);
+ break;
+ case TIFF_GEO_KEY_DIRECTORY:
+ ADD_METADATA(1, "GeoTIFF_Version", NULL);
+ ADD_METADATA(2, "GeoTIFF_Key_Revision", ".");
+ s->geotag_count = ff_tget_short(&s->gb, s->le);
+ if (s->geotag_count > count / 4 - 1) {
+ s->geotag_count = count / 4 - 1;
+ av_log(s->avctx, AV_LOG_WARNING, "GeoTIFF key directory buffer shorter than specified\n");
+ }
+ if (bytestream2_get_bytes_left(&s->gb) < s->geotag_count * sizeof(int16_t) * 4) {
+ s->geotag_count = 0;
+ return -1;
+ }
+ s->geotags = av_mallocz_array(s->geotag_count, sizeof(TiffGeoTag));
+ if (!s->geotags) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
+ s->geotag_count = 0;
+ goto end;
+ }
+ for (i = 0; i < s->geotag_count; i++) {
+ s->geotags[i].key = ff_tget_short(&s->gb, s->le);
+ s->geotags[i].type = ff_tget_short(&s->gb, s->le);
+ s->geotags[i].count = ff_tget_short(&s->gb, s->le);
+
+ if (!s->geotags[i].type)
+ s->geotags[i].val = get_geokey_val(s->geotags[i].key, ff_tget_short(&s->gb, s->le));
+ else
+ s->geotags[i].offset = ff_tget_short(&s->gb, s->le);
+ }
+ break;
+ case TIFF_GEO_DOUBLE_PARAMS:
+ if (count >= INT_MAX / sizeof(int64_t))
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(&s->gb) < count * sizeof(int64_t))
+ return AVERROR_INVALIDDATA;
+ dp = av_malloc_array(count, sizeof(double));
+ if (!dp) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
+ goto end;
+ }
+ for (i = 0; i < count; i++)
+ dp[i] = ff_tget_double(&s->gb, s->le);
+ for (i = 0; i < s->geotag_count; i++) {
+ if (s->geotags[i].type == TIFF_GEO_DOUBLE_PARAMS) {
+ if (s->geotags[i].count == 0
+ || s->geotags[i].offset + s->geotags[i].count > count) {
+ av_log(s->avctx, AV_LOG_WARNING, "Invalid GeoTIFF key %d\n", s->geotags[i].key);
+ } else {
+ char *ap = doubles2str(&dp[s->geotags[i].offset], s->geotags[i].count, ", ");
+ if (!ap) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
+ av_freep(&dp);
+ return AVERROR(ENOMEM);
+ }
+ s->geotags[i].val = ap;
+ }
+ }
+ }
+ av_freep(&dp);
+ break;
+ case TIFF_GEO_ASCII_PARAMS:
+ pos = bytestream2_tell(&s->gb);
+ for (i = 0; i < s->geotag_count; i++) {
+ if (s->geotags[i].type == TIFF_GEO_ASCII_PARAMS) {
+ if (s->geotags[i].count == 0
+ || s->geotags[i].offset + s->geotags[i].count > count) {
+ av_log(s->avctx, AV_LOG_WARNING, "Invalid GeoTIFF key %d\n", s->geotags[i].key);
+ } else {
+ char *ap;
+
+ bytestream2_seek(&s->gb, pos + s->geotags[i].offset, SEEK_SET);
+ if (bytestream2_get_bytes_left(&s->gb) < s->geotags[i].count)
+ return AVERROR_INVALIDDATA;
+ ap = av_malloc(s->geotags[i].count);
+ if (!ap) {
+ av_log(s->avctx, AV_LOG_ERROR, "Error allocating temporary buffer\n");
+ return AVERROR(ENOMEM);
+ }
+ bytestream2_get_bufferu(&s->gb, ap, s->geotags[i].count);
+ ap[s->geotags[i].count - 1] = '\0'; //replace the "|" delimiter with a 0 byte
+ s->geotags[i].val = ap;
+ }
+ }
+ }
+ break;
+ case TIFF_ARTIST:
+ ADD_METADATA(count, "artist", NULL);
+ break;
+ case TIFF_COPYRIGHT:
+ ADD_METADATA(count, "copyright", NULL);
+ break;
+ case TIFF_DATE:
+ ADD_METADATA(count, "date", NULL);
+ break;
+ case TIFF_DOCUMENT_NAME:
+ ADD_METADATA(count, "document_name", NULL);
+ break;
+ case TIFF_HOST_COMPUTER:
+ ADD_METADATA(count, "computer", NULL);
+ break;
+ case TIFF_IMAGE_DESCRIPTION:
+ ADD_METADATA(count, "description", NULL);
+ break;
+ case TIFF_MAKE:
+ ADD_METADATA(count, "make", NULL);
+ break;
+ case TIFF_MODEL:
+ ADD_METADATA(count, "model", NULL);
+ break;
+ case TIFF_PAGE_NAME:
+ ADD_METADATA(count, "page_name", NULL);
+ break;
+ case TIFF_PAGE_NUMBER:
+ ADD_METADATA(count, "page_number", " / ");
+ break;
+ case TIFF_SOFTWARE_NAME:
+ ADD_METADATA(count, "software", NULL);
+ break;
default:
if (s->avctx->err_recognition & AV_EF_EXPLODE) {
av_log(s->avctx, AV_LOG_ERROR,
@@ -549,6 +1158,14 @@ static int tiff_decode_tag(TiffContext *s)
return AVERROR_INVALIDDATA;
}
}
+end:
+ if (s->bpp > 64U) {
+ av_log(s->avctx, AV_LOG_ERROR,
+ "This format is not supported (bpp=%d, %d components)\n",
+ s->bpp, count);
+ s->bpp = 0;
+ return AVERROR_INVALIDDATA;
+ }
bytestream2_seek(&s->gb, start, SEEK_SET);
return 0;
}
@@ -558,8 +1175,9 @@ static int decode_frame(AVCodecContext *avctx,
{
TiffContext *const s = avctx->priv_data;
AVFrame *const p = data;
+ ThreadFrame frame = { .f = data };
unsigned off;
- int id, le, ret, plane, planes;
+ int le, ret, plane, planes;
int i, j, entries, stride;
unsigned soff, ssize;
uint8_t *dst;
@@ -569,48 +1187,56 @@ static int decode_frame(AVCodecContext *avctx,
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
// parse image header
- if (avpkt->size < 8)
- return AVERROR_INVALIDDATA;
- id = bytestream2_get_le16(&s->gb);
- if (id == 0x4949)
- le = 1;
- else if (id == 0x4D4D)
- le = 0;
- else {
- av_log(avctx, AV_LOG_ERROR, "TIFF header not found\n");
+ if ((ret = ff_tdecode_header(&s->gb, &le, &off))) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid TIFF header\n");
+ return ret;
+ } else if (off >= UINT_MAX - 14 || avpkt->size < off + 14) {
+ av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
return AVERROR_INVALIDDATA;
}
s->le = le;
+ // TIFF_BPP is not a required tag and defaults to 1
+ s->bppcount = s->bpp = 1;
s->photometric = TIFF_PHOTOMETRIC_NONE;
s->compr = TIFF_RAW;
s->fill_order = 0;
- // As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number
- // that further identifies the file as a TIFF file"
- if (tget_short(&s->gb, le) != 42) {
- av_log(avctx, AV_LOG_ERROR,
- "The answer to life, universe and everything is not correct!\n");
- return AVERROR_INVALIDDATA;
- }
+ free_geotags(s);
+
// Reset these offsets so we can tell if they were set this frame
s->stripsizesoff = s->strippos = 0;
/* parse image file directory */
- off = tget_long(&s->gb, le);
- if (off >= UINT_MAX - 14 || avpkt->size < off + 14) {
- av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
- return AVERROR_INVALIDDATA;
- }
bytestream2_seek(&s->gb, off, SEEK_SET);
- entries = tget_short(&s->gb, le);
+ entries = ff_tget_short(&s->gb, le);
+ if (bytestream2_get_bytes_left(&s->gb) < entries * 12)
+ return AVERROR_INVALIDDATA;
for (i = 0; i < entries; i++) {
- if ((ret = tiff_decode_tag(s)) < 0)
+ if ((ret = tiff_decode_tag(s, p)) < 0)
+ return ret;
+ }
+
+ for (i = 0; i<s->geotag_count; i++) {
+ const char *keyname = get_geokey_name(s->geotags[i].key);
+ if (!keyname) {
+ av_log(avctx, AV_LOG_WARNING, "Unknown or unsupported GeoTIFF key %d\n", s->geotags[i].key);
+ continue;
+ }
+ if (get_geokey_type(s->geotags[i].key) != s->geotags[i].type) {
+ av_log(avctx, AV_LOG_WARNING, "Type of GeoTIFF key %d is wrong\n", s->geotags[i].key);
+ continue;
+ }
+ ret = av_dict_set(avpriv_frame_get_metadatap(p), keyname, s->geotags[i].val, 0);
+ if (ret<0) {
+ av_log(avctx, AV_LOG_ERROR, "Writing metadata with key '%s' failed\n", keyname);
return ret;
+ }
}
+
if (!s->strippos && !s->stripoff) {
av_log(avctx, AV_LOG_ERROR, "Image data is missing\n");
return AVERROR_INVALIDDATA;
}
/* now we have the data and may start decoding */
- if ((ret = init_image(s, p)) < 0)
+ if ((ret = init_image(s, &frame)) < 0)
return ret;
if (s->strips == 1 && !s->stripsize) {
@@ -619,30 +1245,35 @@ static int decode_frame(AVCodecContext *avctx,
}
if (s->stripsizesoff) {
- if (s->stripsizesoff >= avpkt->size)
+ if (s->stripsizesoff >= (unsigned)avpkt->size)
return AVERROR_INVALIDDATA;
bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff,
avpkt->size - s->stripsizesoff);
}
if (s->strippos) {
- if (s->strippos >= avpkt->size)
+ if (s->strippos >= (unsigned)avpkt->size)
return AVERROR_INVALIDDATA;
bytestream2_init(&stripdata, avpkt->data + s->strippos,
avpkt->size - s->strippos);
}
+ if (s->rps <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "rps %d invalid\n", s->rps);
+ return AVERROR_INVALIDDATA;
+ }
+
planes = s->planar ? s->bppcount : 1;
for (plane = 0; plane < planes; plane++) {
stride = p->linesize[plane];
dst = p->data[plane];
for (i = 0; i < s->height; i += s->rps) {
if (s->stripsizesoff)
- ssize = tget(&stripsizes, s->sstype, le);
+ ssize = ff_tget(&stripsizes, s->sstype, le);
else
ssize = s->stripsize;
if (s->strippos)
- soff = tget(&stripdata, s->sot, le);
+ soff = ff_tget(&stripdata, s->sot, le);
else
soff = s->stripoff;
@@ -650,7 +1281,7 @@ static int decode_frame(AVCodecContext *avctx,
av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
return AVERROR_INVALIDDATA;
}
- if ((ret = tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize,
+ if ((ret = tiff_unpack_strip(s, p, dst, stride, avpkt->data + soff, ssize, i,
FFMIN(s->rps, s->height - i))) < 0) {
if (avctx->err_recognition & AV_EF_EXPLODE)
return ret;
@@ -659,18 +1290,32 @@ static int decode_frame(AVCodecContext *avctx,
dst += s->rps * stride;
}
if (s->predictor == 2) {
+ if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) {
+ av_log(s->avctx, AV_LOG_ERROR, "predictor == 2 with YUV is unsupported");
+ return AVERROR_PATCHWELCOME;
+ }
dst = p->data[plane];
soff = s->bpp >> 3;
+ if (s->planar)
+ soff = FFMAX(soff / s->bppcount, 1);
ssize = s->width * soff;
if (s->avctx->pix_fmt == AV_PIX_FMT_RGB48LE ||
- s->avctx->pix_fmt == AV_PIX_FMT_RGBA64LE) {
+ s->avctx->pix_fmt == AV_PIX_FMT_RGBA64LE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_GRAY16LE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_YA16LE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_GBRP16LE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_GBRAP16LE) {
for (i = 0; i < s->height; i++) {
for (j = soff; j < ssize; j += 2)
AV_WL16(dst + j, AV_RL16(dst + j) + AV_RL16(dst + j - soff));
dst += stride;
}
} else if (s->avctx->pix_fmt == AV_PIX_FMT_RGB48BE ||
- s->avctx->pix_fmt == AV_PIX_FMT_RGBA64BE) {
+ s->avctx->pix_fmt == AV_PIX_FMT_RGBA64BE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_GRAY16BE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_YA16BE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_GBRP16BE ||
+ s->avctx->pix_fmt == AV_PIX_FMT_GBRAP16BE) {
for (i = 0; i < s->height; i++) {
for (j = soff; j < ssize; j += 2)
AV_WB16(dst + j, AV_RB16(dst + j) + AV_RB16(dst + j - soff));
@@ -689,7 +1334,7 @@ static int decode_frame(AVCodecContext *avctx,
dst = p->data[plane];
for (i = 0; i < s->height; i++) {
for (j = 0; j < stride; j++)
- dst[j] = 255 - dst[j];
+ dst[j] = (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - dst[j];
dst += stride;
}
}
@@ -713,6 +1358,8 @@ static av_cold int tiff_init(AVCodecContext *avctx)
s->width = 0;
s->height = 0;
+ s->subsampling[0] =
+ s->subsampling[1] = 1;
s->avctx = avctx;
ff_lzw_decode_open(&s->lzw);
ff_ccitt_unpack_init();
@@ -724,7 +1371,10 @@ static av_cold int tiff_end(AVCodecContext *avctx)
{
TiffContext *const s = avctx->priv_data;
+ free_geotags(s);
+
ff_lzw_decode_close(&s->lzw);
+ av_freep(&s->deinvert_buf);
return 0;
}
@@ -737,5 +1387,6 @@ AVCodec ff_tiff_decoder = {
.init = tiff_init,
.close = tiff_end,
.decode = decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(tiff_init),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
};
diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h
index 68ac695937..3f692afa00 100644
--- a/libavcodec/tiff.h
+++ b/libavcodec/tiff.h
@@ -1,27 +1,29 @@
/*
- * TIFF tables
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* TIFF tables
+ *
+ * For more information about the TIFF format, check the official docs at:
+ * http://partners.adobe.com/public/developer/tiff/index.html
* @author Konstantin Shishkov
*/
@@ -29,6 +31,7 @@
#define AVCODEC_TIFF_H
#include <stdint.h>
+#include "tiff_common.h"
/** abridged list of TIFF tags */
enum TiffTags {
@@ -39,6 +42,10 @@ enum TiffTags {
TIFF_COMPR,
TIFF_PHOTOMETRIC = 0x106,
TIFF_FILL_ORDER = 0x10A,
+ TIFF_DOCUMENT_NAME = 0x10D,
+ TIFF_IMAGE_DESCRIPTION = 0x10E,
+ TIFF_MAKE = 0x10F,
+ TIFF_MODEL = 0x110,
TIFF_STRIP_OFFS = 0x111,
TIFF_SAMPLES_PER_PIXEL = 0x115,
TIFF_ROWSPERSTRIP = 0x116,
@@ -46,18 +53,35 @@ enum TiffTags {
TIFF_XRES = 0x11A,
TIFF_YRES = 0x11B,
TIFF_PLANAR = 0x11C,
+ TIFF_PAGE_NAME = 0x11D,
TIFF_XPOS = 0x11E,
TIFF_YPOS = 0x11F,
TIFF_T4OPTIONS = 0x124,
TIFF_T6OPTIONS,
TIFF_RES_UNIT = 0x128,
+ TIFF_PAGE_NUMBER = 0x129,
TIFF_SOFTWARE_NAME = 0x131,
+ TIFF_DATE = 0x132,
+ TIFF_ARTIST = 0x13B,
+ TIFF_HOST_COMPUTER = 0x13C,
TIFF_PREDICTOR = 0x13D,
TIFF_PAL = 0x140,
+ TIFF_TILE_WIDTH = 0x142,
+ TIFF_TILE_LENGTH = 0x143,
+ TIFF_TILE_OFFSETS = 0x144,
+ TIFF_TILE_BYTE_COUNTS = 0x145,
+ TIFF_EXTRASAMPLES = 0x152,
TIFF_YCBCR_COEFFICIENTS = 0x211,
TIFF_YCBCR_SUBSAMPLING = 0x212,
TIFF_YCBCR_POSITIONING = 0x213,
TIFF_REFERENCE_BW = 0x214,
+ TIFF_COPYRIGHT = 0x8298,
+ TIFF_MODEL_TIEPOINT = 0x8482,
+ TIFF_MODEL_PIXEL_SCALE = 0x830E,
+ TIFF_MODEL_TRANSFORMATION= 0x8480,
+ TIFF_GEO_KEY_DIRECTORY = 0x87AF,
+ TIFF_GEO_DOUBLE_PARAMS = 0x87B0,
+ TIFF_GEO_ASCII_PARAMS = 0x87B1
};
/** list of TIFF compression types */
@@ -75,12 +99,52 @@ enum TiffCompr {
TIFF_LZMA = 0x886D,
};
-enum TiffTypes {
- TIFF_BYTE = 1,
- TIFF_STRING,
- TIFF_SHORT,
- TIFF_LONG,
- TIFF_RATIONAL,
+enum TiffGeoTagKey {
+ TIFF_GT_MODEL_TYPE_GEOKEY = 1024,
+ TIFF_GT_RASTER_TYPE_GEOKEY = 1025,
+ TIFF_GT_CITATION_GEOKEY = 1026,
+ TIFF_GEOGRAPHIC_TYPE_GEOKEY = 2048,
+ TIFF_GEOG_CITATION_GEOKEY = 2049,
+ TIFF_GEOG_GEODETIC_DATUM_GEOKEY = 2050,
+ TIFF_GEOG_PRIME_MERIDIAN_GEOKEY = 2051,
+ TIFF_GEOG_LINEAR_UNITS_GEOKEY = 2052,
+ TIFF_GEOG_LINEAR_UNIT_SIZE_GEOKEY = 2053,
+ TIFF_GEOG_ANGULAR_UNITS_GEOKEY = 2054,
+ TIFF_GEOG_ANGULAR_UNIT_SIZE_GEOKEY = 2055,
+ TIFF_GEOG_ELLIPSOID_GEOKEY = 2056,
+ TIFF_GEOG_SEMI_MAJOR_AXIS_GEOKEY = 2057,
+ TIFF_GEOG_SEMI_MINOR_AXIS_GEOKEY = 2058,
+ TIFF_GEOG_INV_FLATTENING_GEOKEY = 2059,
+ TIFF_GEOG_AZIMUTH_UNITS_GEOKEY = 2060,
+ TIFF_GEOG_PRIME_MERIDIAN_LONG_GEOKEY = 2061,
+ TIFF_PROJECTED_CS_TYPE_GEOKEY = 3072,
+ TIFF_PCS_CITATION_GEOKEY = 3073,
+ TIFF_PROJECTION_GEOKEY = 3074,
+ TIFF_PROJ_COORD_TRANS_GEOKEY = 3075,
+ TIFF_PROJ_LINEAR_UNITS_GEOKEY = 3076,
+ TIFF_PROJ_LINEAR_UNIT_SIZE_GEOKEY = 3077,
+ TIFF_PROJ_STD_PARALLEL1_GEOKEY = 3078,
+ TIFF_PROJ_STD_PARALLEL2_GEOKEY = 3079,
+ TIFF_PROJ_NAT_ORIGIN_LONG_GEOKEY = 3080,
+ TIFF_PROJ_NAT_ORIGIN_LAT_GEOKEY = 3081,
+ TIFF_PROJ_FALSE_EASTING_GEOKEY = 3082,
+ TIFF_PROJ_FALSE_NORTHING_GEOKEY = 3083,
+ TIFF_PROJ_FALSE_ORIGIN_LONG_GEOKEY = 3084,
+ TIFF_PROJ_FALSE_ORIGIN_LAT_GEOKEY = 3085,
+ TIFF_PROJ_FALSE_ORIGIN_EASTING_GEOKEY = 3086,
+ TIFF_PROJ_FALSE_ORIGIN_NORTHING_GEOKEY = 3087,
+ TIFF_PROJ_CENTER_LONG_GEOKEY = 3088,
+ TIFF_PROJ_CENTER_LAT_GEOKEY = 3089,
+ TIFF_PROJ_CENTER_EASTING_GEOKEY = 3090,
+ TIFF_PROJ_CENTER_NORTHING_GEOKEY = 3091,
+ TIFF_PROJ_SCALE_AT_NAT_ORIGIN_GEOKEY = 3092,
+ TIFF_PROJ_SCALE_AT_CENTER_GEOKEY = 3093,
+ TIFF_PROJ_AZIMUTH_ANGLE_GEOKEY = 3094,
+ TIFF_PROJ_STRAIGHT_VERT_POLE_LONG_GEOKEY = 3095,
+ TIFF_VERTICAL_CS_TYPE_GEOKEY = 4096,
+ TIFF_VERTICAL_CITATION_GEOKEY = 4097,
+ TIFF_VERTICAL_DATUM_GEOKEY = 4098,
+ TIFF_VERTICAL_UNITS_GEOKEY = 4099
};
enum TiffPhotometric {
@@ -101,9 +165,28 @@ enum TiffPhotometric {
TIFF_PHOTOMETRIC_LINEAR_RAW = 34892, /* Linear Raw (DNG) */
};
-/** sizes of various TIFF field types (string size = 100)*/
-static const uint8_t type_sizes[6] = {
- 0, 1, 100, 2, 4, 8
+enum TiffGeoTagType {
+ GEOTIFF_SHORT = 0,
+ GEOTIFF_DOUBLE = 34736,
+ GEOTIFF_STRING = 34737
};
+typedef struct TiffGeoTag {
+ enum TiffGeoTagKey key;
+ enum TiffTags type;
+ int count;
+ int offset;
+ char *val;
+} TiffGeoTag;
+
+typedef struct TiffGeoTagKeyName {
+ const enum TiffGeoTagKey key;
+ const char *const name;
+} TiffGeoTagKeyName;
+
+typedef struct TiffGeoTagNameType {
+ const char *const name;
+ const enum TiffGeoTagType type;
+} TiffGeoTagNameType;
+
#endif /* AVCODEC_TIFF_H */
diff --git a/libavcodec/tiff_common.c b/libavcodec/tiff_common.c
new file mode 100644
index 0000000000..35119af558
--- /dev/null
+++ b/libavcodec/tiff_common.c
@@ -0,0 +1,313 @@
+/*
+ * TIFF Common Routines
+ * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * TIFF Common Routines
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ */
+
+#include "tiff_common.h"
+
+
+int ff_tis_ifd(unsigned tag)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(ifd_tags); i++) {
+ if (ifd_tags[i] == tag) {
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
+
+unsigned ff_tget_short(GetByteContext *gb, int le)
+{
+ return le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
+}
+
+
+unsigned ff_tget_long(GetByteContext *gb, int le)
+{
+ return le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
+}
+
+
+double ff_tget_double(GetByteContext *gb, int le)
+{
+ av_alias64 i = { .u64 = le ? bytestream2_get_le64(gb) : bytestream2_get_be64(gb)};
+ return i.f64;
+}
+
+
+unsigned ff_tget(GetByteContext *gb, int type, int le)
+{
+ switch (type) {
+ case TIFF_BYTE: return bytestream2_get_byte(gb);
+ case TIFF_SHORT: return ff_tget_short(gb, le);
+ case TIFF_LONG: return ff_tget_long(gb, le);
+ default: return UINT_MAX;
+ }
+}
+
+static const char *auto_sep(int count, const char *sep, int i, int columns)
+{
+ if (sep)
+ return i ? sep : "";
+ if (i && i%columns) {
+ return ", ";
+ } else
+ return columns < count ? "\n" : "";
+}
+
+int ff_tadd_rational_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, AVDictionary **metadata)
+{
+ AVBPrint bp;
+ char *ap;
+ int32_t nom, denom;
+ int i;
+
+ if (count >= INT_MAX / sizeof(int64_t) || count <= 0)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t))
+ return AVERROR_INVALIDDATA;
+
+ av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
+
+ for (i = 0; i < count; i++) {
+ nom = ff_tget_long(gb, le);
+ denom = ff_tget_long(gb, le);
+ av_bprintf(&bp, "%s%7i:%-7i", auto_sep(count, sep, i, 4), nom, denom);
+ }
+
+ if ((i = av_bprint_finalize(&bp, &ap))) {
+ return i;
+ }
+ if (!ap) {
+ return AVERROR(ENOMEM);
+ }
+
+ av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
+
+ return 0;
+}
+
+
+int ff_tadd_long_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, AVDictionary **metadata)
+{
+ AVBPrint bp;
+ char *ap;
+ int i;
+
+ if (count >= INT_MAX / sizeof(int32_t) || count <= 0)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(gb) < count * sizeof(int32_t))
+ return AVERROR_INVALIDDATA;
+
+ av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
+
+ for (i = 0; i < count; i++) {
+ av_bprintf(&bp, "%s%7i", auto_sep(count, sep, i, 8), ff_tget_long(gb, le));
+ }
+
+ if ((i = av_bprint_finalize(&bp, &ap))) {
+ return i;
+ }
+ if (!ap) {
+ return AVERROR(ENOMEM);
+ }
+
+ av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
+
+ return 0;
+}
+
+
+int ff_tadd_doubles_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, AVDictionary **metadata)
+{
+ AVBPrint bp;
+ char *ap;
+ int i;
+
+ if (count >= INT_MAX / sizeof(int64_t) || count <= 0)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(gb) < count * sizeof(int64_t))
+ return AVERROR_INVALIDDATA;
+
+ av_bprint_init(&bp, 10 * count, 100 * count);
+
+ for (i = 0; i < count; i++) {
+ av_bprintf(&bp, "%s%.15g", auto_sep(count, sep, i, 4), ff_tget_double(gb, le));
+ }
+
+ if ((i = av_bprint_finalize(&bp, &ap))) {
+ return i;
+ }
+ if (!ap) {
+ return AVERROR(ENOMEM);
+ }
+
+ av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
+
+ return 0;
+}
+
+
+int ff_tadd_shorts_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, int is_signed, AVDictionary **metadata)
+{
+ AVBPrint bp;
+ char *ap;
+ int i;
+
+ if (count >= INT_MAX / sizeof(int16_t) || count <= 0)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(gb) < count * sizeof(int16_t))
+ return AVERROR_INVALIDDATA;
+
+ av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
+
+ for (i = 0; i < count; i++) {
+ int v = is_signed ? (int16_t)ff_tget_short(gb, le) : ff_tget_short(gb, le);
+ av_bprintf(&bp, "%s%5i", auto_sep(count, sep, i, 8), v);
+ }
+
+ if ((i = av_bprint_finalize(&bp, &ap))) {
+ return i;
+ }
+ if (!ap) {
+ return AVERROR(ENOMEM);
+ }
+
+ av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
+
+ return 0;
+}
+
+
+int ff_tadd_bytes_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, int is_signed, AVDictionary **metadata)
+{
+ AVBPrint bp;
+ char *ap;
+ int i;
+
+ if (count >= INT_MAX / sizeof(int8_t) || count < 0)
+ return AVERROR_INVALIDDATA;
+ if (bytestream2_get_bytes_left(gb) < count * sizeof(int8_t))
+ return AVERROR_INVALIDDATA;
+
+ av_bprint_init(&bp, 10 * count, AV_BPRINT_SIZE_UNLIMITED);
+
+ for (i = 0; i < count; i++) {
+ int v = is_signed ? (int8_t)bytestream2_get_byte(gb) : bytestream2_get_byte(gb);
+ av_bprintf(&bp, "%s%3i", auto_sep(count, sep, i, 16), v);
+ }
+
+ if ((i = av_bprint_finalize(&bp, &ap))) {
+ return i;
+ }
+ if (!ap) {
+ return AVERROR(ENOMEM);
+ }
+
+ av_dict_set(metadata, name, ap, AV_DICT_DONT_STRDUP_VAL);
+
+ return 0;
+}
+
+int ff_tadd_string_metadata(int count, const char *name,
+ GetByteContext *gb, int le, AVDictionary **metadata)
+{
+ char *value;
+
+ if (bytestream2_get_bytes_left(gb) < count || count < 0)
+ return AVERROR_INVALIDDATA;
+
+ value = av_malloc(count + 1);
+ if (!value)
+ return AVERROR(ENOMEM);
+
+ bytestream2_get_bufferu(gb, value, count);
+ value[count] = 0;
+
+ av_dict_set(metadata, name, value, AV_DICT_DONT_STRDUP_VAL);
+ return 0;
+}
+
+
+int ff_tdecode_header(GetByteContext *gb, int *le, int *ifd_offset)
+{
+ if (bytestream2_get_bytes_left(gb) < 8) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ *le = bytestream2_get_le16u(gb);
+ if (*le == AV_RB16("II")) {
+ *le = 1;
+ } else if (*le == AV_RB16("MM")) {
+ *le = 0;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (ff_tget_short(gb, *le) != 42) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ *ifd_offset = ff_tget_long(gb, *le);
+
+ return 0;
+}
+
+
+int ff_tread_tag(GetByteContext *gb, int le, unsigned *tag, unsigned *type,
+ unsigned *count, int *next)
+{
+ int ifd_tag;
+ int valid_type;
+
+ *tag = ff_tget_short(gb, le);
+ *type = ff_tget_short(gb, le);
+ *count = ff_tget_long (gb, le);
+
+ ifd_tag = ff_tis_ifd(*tag);
+ valid_type = *type != 0 && *type < FF_ARRAY_ELEMS(type_sizes);
+
+ *next = bytestream2_tell(gb) + 4;
+
+ // check for valid type
+ if (!valid_type) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ // seek to offset if this is an IFD-tag or
+ // if count values do not fit into the offset value
+ if (ifd_tag || (*count > 4 || !(type_sizes[*type] * (*count) <= 4 || *type == TIFF_STRING))) {
+ bytestream2_seek(gb, ff_tget_long (gb, le), SEEK_SET);
+ }
+
+ return 0;
+}
diff --git a/libavcodec/tiff_common.h b/libavcodec/tiff_common.h
new file mode 100644
index 0000000000..03558c31a3
--- /dev/null
+++ b/libavcodec/tiff_common.h
@@ -0,0 +1,152 @@
+/*
+ * TIFF Common Routines
+ * Copyright (c) 2013 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * TIFF Common Routines
+ * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ */
+
+#ifndef AVCODEC_TIFF_COMMON_H
+#define AVCODEC_TIFF_COMMON_H
+
+#include "avcodec.h"
+#include "tiff.h"
+#include "bytestream.h"
+#include "libavutil/bprint.h"
+
+/** data type identifiers for TIFF tags */
+enum TiffTypes {
+ TIFF_BYTE = 1,
+ TIFF_STRING,
+ TIFF_SHORT,
+ TIFF_LONG,
+ TIFF_RATIONAL,
+ TIFF_SBYTE,
+ TIFF_UNDEFINED,
+ TIFF_SSHORT,
+ TIFF_SLONG,
+ TIFF_SRATIONAL,
+ TIFF_FLOAT,
+ TIFF_DOUBLE,
+ TIFF_IFD
+};
+
+/** sizes of various TIFF field types (string size = 100)*/
+static const uint8_t type_sizes[14] = {
+ 0, 1, 100, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4
+};
+
+static const uint16_t ifd_tags[] = {
+ 0x8769, // EXIF IFD
+ 0x8825, // GPS IFD
+ 0xA005 // Interoperability IFD
+};
+
+
+/** Returns a value > 0 if the tag is a known IFD-tag.
+ * The return value is the array index + 1 within ifd_tags[].
+ */
+int ff_tis_ifd(unsigned tag);
+
+/** Reads a short from the bytestream using given endianness. */
+unsigned ff_tget_short(GetByteContext *gb, int le);
+
+/** Reads a long from the bytestream using given endianness. */
+unsigned ff_tget_long(GetByteContext *gb, int le);
+
+/** Reads a double from the bytestream using given endianness. */
+double ff_tget_double(GetByteContext *gb, int le);
+
+/** Reads a byte from the bytestream using given endianness. */
+unsigned ff_tget(GetByteContext *gb, int type, int le);
+
+/** Returns an allocated string containing count
+ * rational values using the given separator.
+ */
+char *ff_trationals2str(int *rp, int count, const char *sep);
+
+/** Returns an allocated string containing count
+ * long values using the given separator.
+ */
+char *ff_tlongs2str(int32_t *lp, int count, const char *sep);
+
+/** Returns an allocated string containing count
+ * double values using the given separator.
+ */
+char *ff_tdoubles2str(double *dp, int count, const char *sep);
+
+/** Returns an allocated string containing count
+ * short values using the given separator.
+ */
+char *ff_tshorts2str(int16_t *sp, int count, const char *sep);
+
+/** Adds count rationals converted to a string
+ * into the metadata dictionary.
+ */
+int ff_tadd_rational_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, AVDictionary **metadata);
+
+/** Adds count longs converted to a string
+ * into the metadata dictionary.
+ */
+int ff_tadd_long_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, AVDictionary **metadata);
+
+/** Adds count doubles converted to a string
+ * into the metadata dictionary.
+ */
+int ff_tadd_doubles_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, AVDictionary **metadata);
+
+/** Adds count shorts converted to a string
+ * into the metadata dictionary.
+ */
+int ff_tadd_shorts_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, int is_signed, AVDictionary **metadata);
+
+/** Adds count bytes converted to a string
+ * into the metadata dictionary.
+ */
+int ff_tadd_bytes_metadata(int count, const char *name, const char *sep,
+ GetByteContext *gb, int le, int is_signed, AVDictionary **metadata);
+
+/** Adds a string of count characters
+ * into the metadata dictionary.
+ */
+int ff_tadd_string_metadata(int count, const char *name,
+ GetByteContext *gb, int le, AVDictionary **metadata);
+
+/** Decodes a TIFF header from the input bytestream
+ * and sets the endianness in *le and the offset to
+ * the first IFD in *ifd_offset accordingly.
+ */
+int ff_tdecode_header(GetByteContext *gb, int *le, int *ifd_offset);
+
+/** Reads the first 3 fields of a TIFF tag, which are
+ * the tag id, the tag type and the count of values for that tag.
+ * Afterwards the bytestream is located at the first value to read and
+ * *next holds the bytestream offset of the following tag.
+ */
+int ff_tread_tag(GetByteContext *gb, int le, unsigned *tag, unsigned *type,
+ unsigned *count, int *next);
+
+#endif /* AVCODEC_TIFF_COMMON_H */
diff --git a/libavcodec/tiff_data.c b/libavcodec/tiff_data.c
new file mode 100644
index 0000000000..88c2256813
--- /dev/null
+++ b/libavcodec/tiff_data.c
@@ -0,0 +1,1870 @@
+/*
+ * TIFF data tables
+ * Copyright (c) 2011 Thomas Kuehnel
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * TIFF data tables
+ * @author Thomas Kuehnel
+ * @see GeoTIFF specification at
+ * http://www.remotesensing.org/geotiff/spec/geotiffhome.html
+ */
+
+#include "tiff_data.h"
+
+const TiffGeoTagNameType ff_tiff_conf_name_type_map[] = {
+ {"GTModelTypeGeoKey", GEOTIFF_SHORT },
+ {"GTRasterTypeGeoKey", GEOTIFF_SHORT },
+ {"GTCitationGeoKey", GEOTIFF_STRING}
+};
+
+const TiffGeoTagNameType ff_tiff_geog_name_type_map[] = {
+ {"GeographicTypeGeoKey", GEOTIFF_SHORT },
+ {"GeogCitationGeoKey", GEOTIFF_STRING},
+ {"GeogGeodeticDatumGeoKey", GEOTIFF_SHORT },
+ {"GeogPrimeMeridianGeoKey", GEOTIFF_SHORT },
+ {"GeogLinearUnitsGeoKey", GEOTIFF_SHORT },
+ {"GeogLinearUnitSizeGeoKey", GEOTIFF_DOUBLE},
+ {"GeogAngularUnitsGeoKey", GEOTIFF_SHORT },
+ {"GeogAngularUnitSizeGeoKey", GEOTIFF_DOUBLE},
+ {"GeogEllipsoidGeoKey", GEOTIFF_SHORT },
+ {"GeogSemiMajorAxisGeoKey", GEOTIFF_DOUBLE},
+ {"GeogSemiMinorAxisGeoKey", GEOTIFF_DOUBLE},
+ {"GeogInvFlatteningGeoKey", GEOTIFF_DOUBLE},
+ {"GeogAzimuthUnitsGeoKey", GEOTIFF_SHORT },
+ {"GeogPrimeMeridianLongGeoKey", GEOTIFF_DOUBLE}
+};
+
+const TiffGeoTagNameType ff_tiff_proj_name_type_map[] = {
+ {"ProjectedCSTypeGeoKey", GEOTIFF_SHORT },
+ {"PCSCitationGeoKey", GEOTIFF_STRING},
+ {"ProjectionGeoKey", GEOTIFF_SHORT },
+ {"ProjCoordTransGeoKey", GEOTIFF_SHORT },
+ {"ProjLinearUnitsGeoKey", GEOTIFF_SHORT },
+ {"ProjLinearUnitSizeGeoKey", GEOTIFF_DOUBLE},
+ {"ProjStdParallel1GeoKey", GEOTIFF_DOUBLE},
+ {"ProjStdParallel2GeoKey", GEOTIFF_DOUBLE},
+ {"ProjNatOriginLongGeoKey", GEOTIFF_DOUBLE},
+ {"ProjNatOriginLatGeoKey", GEOTIFF_DOUBLE},
+ {"ProjFalseEastingGeoKey", GEOTIFF_DOUBLE},
+ {"ProjFalseNorthingGeoKey", GEOTIFF_DOUBLE},
+ {"ProjFalseOriginLongGeoKey", GEOTIFF_DOUBLE},
+ {"ProjFalseOriginLatGeoKey", GEOTIFF_DOUBLE},
+ {"ProjFalseOriginEastingGeoKey", GEOTIFF_DOUBLE},
+ {"ProjFalseOriginNorthingGeoKey", GEOTIFF_DOUBLE},
+ {"ProjCenterLongGeoKey", GEOTIFF_DOUBLE},
+ {"ProjCenterLatGeoKey", GEOTIFF_DOUBLE},
+ {"ProjCenterEastingGeoKey", GEOTIFF_DOUBLE},
+ {"ProjCenterNorthingGeoKey", GEOTIFF_DOUBLE},
+ {"ProjScaleAtNatOriginGeoKey", GEOTIFF_DOUBLE},
+ {"ProjScaleAtCenterGeoKey", GEOTIFF_DOUBLE},
+ {"ProjAzimuthAngleGeoKey", GEOTIFF_DOUBLE},
+ {"ProjStraightVertPoleLongGeoKey", GEOTIFF_DOUBLE}
+};
+
+const TiffGeoTagNameType ff_tiff_vert_name_type_map[] = {
+ {"VerticalCSTypeGeoKey", GEOTIFF_SHORT },
+ {"VerticalCitationGeoKey", GEOTIFF_STRING},
+ {"VerticalDatumGeoKey", GEOTIFF_SHORT },
+ {"VerticalUnitsGeoKey", GEOTIFF_SHORT }
+};
+
+const char *const ff_tiff_gt_model_type_codes[] = {
+ "ModelTypeProjected",
+ "ModelTypeGeographic",
+ "ModelTypeGeocentric"
+};
+
+const char *const ff_tiff_gt_raster_type_codes[] = {
+ "RasterPixelIsArea",
+ "RasterPixelIsPoint"
+};
+
+const char *const ff_tiff_linear_unit_codes[] = {
+ "Linear_Meter",
+ "Linear_Foot",
+ "Linear_Foot_US_Survey",
+ "Linear_Foot_Modified_American",
+ "Linear_Foot_Clarke",
+ "Linear_Foot_Indian",
+ "Linear_Link",
+ "Linear_Link_Benoit",
+ "Linear_Link_Sears",
+ "Linear_Chain_Benoit",
+ "Linear_Chain_Sears",
+ "Linear_Yard_Sears",
+ "Linear_Yard_Indian",
+ "Linear_Fathom",
+ "Linear_Mile_International_Nautical"
+};
+
+const char *const ff_tiff_angular_unit_codes[] = {
+ "Angular_Radian",
+ "Angular_Degree",
+ "Angular_Arc_Minute",
+ "Angular_Arc_Second",
+ "Angular_Grad",
+ "Angular_Gon",
+ "Angular_DMS",
+ "Angular_DMS_Hemisphere"
+};
+
+const char *const ff_tiff_gcs_type_codes[] = {
+ "GCS_Adindan",
+ "GCS_AGD66",
+ "GCS_AGD84",
+ "GCS_Ain_el_Abd",
+ "GCS_Afgooye",
+ "GCS_Agadez",
+ "GCS_Lisbon",
+ "GCS_Aratu",
+ "GCS_Arc_1950",
+ "GCS_Arc_1960",
+ "GCS_Batavia",
+ "GCS_Barbados",
+ "GCS_Beduaram",
+ "GCS_Beijing_1954",
+ "GCS_Belge_1950",
+ "GCS_Bermuda_1957",
+ "GCS_Bern_1898",
+ "GCS_Bogota",
+ "GCS_Bukit_Rimpah",
+ "GCS_Camacupa",
+ "GCS_Campo_Inchauspe",
+ "GCS_Cape",
+ "GCS_Carthage",
+ "GCS_Chua",
+ "GCS_Corrego_Alegre",
+ "GCS_Cote_d_Ivoire",
+ "GCS_Deir_ez_Zor",
+ "GCS_Douala",
+ "GCS_Egypt_1907",
+ "GCS_ED50",
+ "GCS_ED87",
+ "GCS_Fahud",
+ "GCS_Gandajika_1970",
+ "GCS_Garoua",
+ "GCS_Guyane_Francaise",
+ "GCS_Hu_Tzu_Shan",
+ "GCS_HD72",
+ "GCS_ID74",
+ "GCS_Indian_1954",
+ "GCS_Indian_1975",
+ "GCS_Jamaica_1875",
+ "GCS_JAD69",
+ "GCS_Kalianpur",
+ "GCS_Kandawala",
+ "GCS_Kertau",
+ "GCS_KOC",
+ "GCS_La_Canoa",
+ "GCS_PSAD56",
+ "GCS_Lake",
+ "GCS_Leigon",
+ "GCS_Liberia_1964",
+ "GCS_Lome",
+ "GCS_Luzon_1911",
+ "GCS_Hito_XVIII_1963",
+ "GCS_Herat_North",
+ "GCS_Mahe_1971",
+ "GCS_Makassar",
+ "GCS_EUREF89",
+ "GCS_Malongo_1987",
+ "GCS_Manoca",
+ "GCS_Merchich",
+ "GCS_Massawa",
+ "GCS_Minna",
+ "GCS_Mhast",
+ "GCS_Monte_Mario",
+ "GCS_M_poraloko",
+ "GCS_NAD27",
+ "GCS_NAD_Michigan",
+ "GCS_NAD83",
+ "GCS_Nahrwan_1967",
+ "GCS_Naparima_1972",
+ "GCS_GD49",
+ "GCS_NGO_1948",
+ "GCS_Datum_73",
+ "GCS_NTF",
+ "GCS_NSWC_9Z_2",
+ "GCS_OSGB_1936",
+ "GCS_OSGB70",
+ "GCS_OS_SN80",
+ "GCS_Padang",
+ "GCS_Palestine_1923",
+ "GCS_Pointe_Noire",
+ "GCS_GDA94",
+ "GCS_Pulkovo_1942",
+ "GCS_Qatar",
+ "GCS_Qatar_1948",
+ "GCS_Qornoq",
+ "GCS_Loma_Quintana",
+ "GCS_Amersfoort",
+ "GCS_RT38",
+ "GCS_SAD69",
+ "GCS_Sapper_Hill_1943",
+ "GCS_Schwarzeck",
+ "GCS_Segora",
+ "GCS_Serindung",
+ "GCS_Sudan",
+ "GCS_Tananarive",
+ "GCS_Timbalai_1948",
+ "GCS_TM65",
+ "GCS_TM75",
+ "GCS_Tokyo",
+ "GCS_Trinidad_1903",
+ "GCS_TC_1948",
+ "GCS_Voirol_1875",
+ "GCS_Voirol_Unifie",
+ "GCS_Bern_1938",
+ "GCS_Nord_Sahara_1959",
+ "GCS_Stockholm_1938",
+ "GCS_Yacare",
+ "GCS_Yoff",
+ "GCS_Zanderij",
+ "GCS_MGI",
+ "GCS_Belge_1972",
+ "GCS_DHDN",
+ "GCS_Conakry_1905",
+ "GCS_WGS_72",
+ "GCS_WGS_72BE",
+ "GCS_WGS_84",
+ "GCS_Bern_1898_Bern",
+ "GCS_Bogota_Bogota",
+ "GCS_Lisbon_Lisbon",
+ "GCS_Makassar_Jakarta",
+ "GCS_MGI_Ferro",
+ "GCS_Monte_Mario_Rome",
+ "GCS_NTF_Paris",
+ "GCS_Padang_Jakarta",
+ "GCS_Belge_1950_Brussels",
+ "GCS_Tananarive_Paris",
+ "GCS_Voirol_1875_Paris",
+ "GCS_Voirol_Unifie_Paris",
+ "GCS_Batavia_Jakarta",
+ "GCS_ATF_Paris",
+ "GCS_NDG_Paris"
+};
+
+const char *const ff_tiff_gcse_type_codes[] = {
+ "GCSE_Airy1830",
+ "GCSE_AiryModified1849",
+ "GCSE_AustralianNationalSpheroid",
+ "GCSE_Bessel1841",
+ "GCSE_BesselModified",
+ "GCSE_BesselNamibia",
+ "GCSE_Clarke1858",
+ "GCSE_Clarke1866",
+ "GCSE_Clarke1866Michigan",
+ "GCSE_Clarke1880_Benoit",
+ "GCSE_Clarke1880_IGN",
+ "GCSE_Clarke1880_RGS",
+ "GCSE_Clarke1880_Arc",
+ "GCSE_Clarke1880_SGA1922",
+ "GCSE_Everest1830_1937Adjustment",
+ "GCSE_Everest1830_1967Definition",
+ "GCSE_Everest1830_1975Definition",
+ "GCSE_Everest1830Modified",
+ "GCSE_GRS1980",
+ "GCSE_Helmert1906",
+ "GCSE_IndonesianNationalSpheroid",
+ "GCSE_International1924",
+ "GCSE_International1967",
+ "GCSE_Krassowsky1940",
+ "GCSE_NWL9D",
+ "GCSE_NWL10D",
+ "GCSE_Plessis1817",
+ "GCSE_Struve1860",
+ "GCSE_WarOffice",
+ "GCSE_WGS84",
+ "GCSE_GEM10C",
+ "GCSE_OSU86F",
+ "GCSE_OSU91A",
+ "GCSE_Clarke1880",
+ "GCSE_Sphere"
+};
+
+const char *const ff_tiff_geodetic_datum_codes[] = {
+ "Datum_Adindan",
+ "Datum_Australian_Geodetic_Datum_1966",
+ "Datum_Australian_Geodetic_Datum_1984",
+ "Datum_Ain_el_Abd_1970",
+ "Datum_Afgooye",
+ "Datum_Agadez",
+ "Datum_Lisbon",
+ "Datum_Aratu",
+ "Datum_Arc_1950",
+ "Datum_Arc_1960",
+ "Datum_Batavia",
+ "Datum_Barbados",
+ "Datum_Beduaram",
+ "Datum_Beijing_1954",
+ "Datum_Reseau_National_Belge_1950",
+ "Datum_Bermuda_1957",
+ "Datum_Bern_1898",
+ "Datum_Bogota",
+ "Datum_Bukit_Rimpah",
+ "Datum_Camacupa",
+ "Datum_Campo_Inchauspe",
+ "Datum_Cape",
+ "Datum_Carthage",
+ "Datum_Chua",
+ "Datum_Corrego_Alegre",
+ "Datum_Cote_d_Ivoire",
+ "Datum_Deir_ez_Zor",
+ "Datum_Douala",
+ "Datum_Egypt_1907",
+ "Datum_European_Datum_1950",
+ "Datum_European_Datum_1987",
+ "Datum_Fahud",
+ "Datum_Gandajika_1970",
+ "Datum_Garoua",
+ "Datum_Guyane_Francaise",
+ "Datum_Hu_Tzu_Shan",
+ "Datum_Hungarian_Datum_1972",
+ "Datum_Indonesian_Datum_1974",
+ "Datum_Indian_1954",
+ "Datum_Indian_1975",
+ "Datum_Jamaica_1875",
+ "Datum_Jamaica_1969",
+ "Datum_Kalianpur",
+ "Datum_Kandawala",
+ "Datum_Kertau",
+ "Datum_Kuwait_Oil_Company",
+ "Datum_La_Canoa",
+ "Datum_Provisional_S_American_Datum_1956",
+ "Datum_Lake",
+ "Datum_Leigon",
+ "Datum_Liberia_1964",
+ "Datum_Lome",
+ "Datum_Luzon_1911",
+ "Datum_Hito_XVIII_1963",
+ "Datum_Herat_North",
+ "Datum_Mahe_1971",
+ "Datum_Makassar",
+ "Datum_European_Reference_System_1989",
+ "Datum_Malongo_1987",
+ "Datum_Manoca",
+ "Datum_Merchich",
+ "Datum_Massawa",
+ "Datum_Minna",
+ "Datum_Mhast",
+ "Datum_Monte_Mario",
+ "Datum_M_poraloko",
+ "Datum_North_American_Datum_1927",
+ "Datum_NAD_Michigan",
+ "Datum_North_American_Datum_1983",
+ "Datum_Nahrwan_1967",
+ "Datum_Naparima_1972",
+ "Datum_New_Zealand_Geodetic_Datum_1949",
+ "Datum_NGO_1948",
+ "Datum_Datum_73",
+ "Datum_Nouvelle_Triangulation_Francaise",
+ "Datum_NSWC_9Z_2",
+ "Datum_OSGB_1936",
+ "Datum_OSGB_1970_SN",
+ "Datum_OS_SN_1980",
+ "Datum_Padang_1884",
+ "Datum_Palestine_1923",
+ "Datum_Pointe_Noire",
+ "Datum_Geocentric_Datum_of_Australia_1994",
+ "Datum_Pulkovo_1942",
+ "Datum_Qatar",
+ "Datum_Qatar_1948",
+ "Datum_Qornoq",
+ "Datum_Loma_Quintana",
+ "Datum_Amersfoort",
+ "Datum_RT38",
+ "Datum_South_American_Datum_1969",
+ "Datum_Sapper_Hill_1943",
+ "Datum_Schwarzeck",
+ "Datum_Segora",
+ "Datum_Serindung",
+ "Datum_Sudan",
+ "Datum_Tananarive_1925",
+ "Datum_Timbalai_1948",
+ "Datum_TM65",
+ "Datum_TM75",
+ "Datum_Tokyo",
+ "Datum_Trinidad_1903",
+ "Datum_Trucial_Coast_1948",
+ "Datum_Voirol_1875",
+ "Datum_Voirol_Unifie_1960",
+ "Datum_Bern_1938",
+ "Datum_Nord_Sahara_1959",
+ "Datum_Stockholm_1938",
+ "Datum_Yacare",
+ "Datum_Yoff",
+ "Datum_Zanderij",
+ "Datum_Militar_Geographische_Institut",
+ "Datum_Reseau_National_Belge_1972",
+ "Datum_Deutsche_Hauptdreiecksnetz",
+ "Datum_Conakry_1905",
+ "Datum_WGS72",
+ "Datum_WGS72_Transit_Broadcast_Ephemeris",
+ "Datum_WGS84",
+ "Datum_Ancienne_Triangulation_Francaise",
+ "Datum_Nord_de_Guerre"
+};
+
+const char *const ff_tiff_geodetic_datum_e_codes[] = {
+ "DatumE_Airy1830",
+ "DatumE_AiryModified1849",
+ "DatumE_AustralianNationalSpheroid",
+ "DatumE_Bessel1841",
+ "DatumE_BesselModified",
+ "DatumE_BesselNamibia",
+ "DatumE_Clarke1858",
+ "DatumE_Clarke1866",
+ "DatumE_Clarke1866Michigan",
+ "DatumE_Clarke1880_Benoit",
+ "DatumE_Clarke1880_IGN",
+ "DatumE_Clarke1880_RGS",
+ "DatumE_Clarke1880_Arc",
+ "DatumE_Clarke1880_SGA1922",
+ "DatumE_Everest1830_1937Adjustment",
+ "DatumE_Everest1830_1967Definition",
+ "DatumE_Everest1830_1975Definition",
+ "DatumE_Everest1830Modified",
+ "DatumE_GRS1980",
+ "DatumE_Helmert1906",
+ "DatumE_IndonesianNationalSpheroid",
+ "DatumE_International1924",
+ "DatumE_International1967",
+ "DatumE_Krassowsky1960",
+ "DatumE_NWL9D",
+ "DatumE_NWL10D",
+ "DatumE_Plessis1817",
+ "DatumE_Struve1860",
+ "DatumE_WarOffice",
+ "DatumE_WGS84",
+ "DatumE_GEM10C",
+ "DatumE_OSU86F",
+ "DatumE_OSU91A",
+ "DatumE_Clarke1880",
+ "DatumE_Sphere"
+};
+
+const char *const ff_tiff_ellipsoid_codes[] = {
+ "Ellipse_Airy_1830",
+ "Ellipse_Airy_Modified_1849",
+ "Ellipse_Australian_National_Spheroid",
+ "Ellipse_Bessel_1841",
+ "Ellipse_Bessel_Modified",
+ "Ellipse_Bessel_Namibia",
+ "Ellipse_Clarke_1858",
+ "Ellipse_Clarke_1866",
+ "Ellipse_Clarke_1866_Michigan",
+ "Ellipse_Clarke_1880_Benoit",
+ "Ellipse_Clarke_1880_IGN",
+ "Ellipse_Clarke_1880_RGS",
+ "Ellipse_Clarke_1880_Arc",
+ "Ellipse_Clarke_1880_SGA_1922",
+ "Ellipse_Everest_1830_1937_Adjustment",
+ "Ellipse_Everest_1830_1967_Definition",
+ "Ellipse_Everest_1830_1975_Definition",
+ "Ellipse_Everest_1830_Modified",
+ "Ellipse_GRS_1980",
+ "Ellipse_Helmert_1906",
+ "Ellipse_Indonesian_National_Spheroid",
+ "Ellipse_International_1924",
+ "Ellipse_International_1967",
+ "Ellipse_Krassowsky_1940",
+ "Ellipse_NWL_9D",
+ "Ellipse_NWL_10D",
+ "Ellipse_Plessis_1817",
+ "Ellipse_Struve_1860",
+ "Ellipse_War_Office",
+ "Ellipse_WGS_84",
+ "Ellipse_GEM_10C",
+ "Ellipse_OSU86F",
+ "Ellipse_OSU91A",
+ "Ellipse_Clarke_1880",
+ "Ellipse_Sphere"
+};
+
+const char *const ff_tiff_prime_meridian_codes[] = {
+ "PM_Greenwich",
+ "PM_Lisbon",
+ "PM_Paris",
+ "PM_Bogota",
+ "PM_Madrid",
+ "PM_Rome",
+ "PM_Bern",
+ "PM_Jakarta",
+ "PM_Ferro",
+ "PM_Brussels",
+ "PM_Stockholm"
+};
+
+const TiffGeoTagKeyName ff_tiff_proj_cs_type_codes[] = {
+ {20137, "PCS_Adindan_UTM_zone_37N"},
+ {20138, "PCS_Adindan_UTM_zone_38N"},
+ {20248, "PCS_AGD66_AMG_zone_48"},
+ {20249, "PCS_AGD66_AMG_zone_49"},
+ {20250, "PCS_AGD66_AMG_zone_50"},
+ {20251, "PCS_AGD66_AMG_zone_51"},
+ {20252, "PCS_AGD66_AMG_zone_52"},
+ {20253, "PCS_AGD66_AMG_zone_53"},
+ {20254, "PCS_AGD66_AMG_zone_54"},
+ {20255, "PCS_AGD66_AMG_zone_55"},
+ {20256, "PCS_AGD66_AMG_zone_56"},
+ {20257, "PCS_AGD66_AMG_zone_57"},
+ {20258, "PCS_AGD66_AMG_zone_58"},
+ {20348, "PCS_AGD84_AMG_zone_48"},
+ {20349, "PCS_AGD84_AMG_zone_49"},
+ {20350, "PCS_AGD84_AMG_zone_50"},
+ {20351, "PCS_AGD84_AMG_zone_51"},
+ {20352, "PCS_AGD84_AMG_zone_52"},
+ {20353, "PCS_AGD84_AMG_zone_53"},
+ {20354, "PCS_AGD84_AMG_zone_54"},
+ {20355, "PCS_AGD84_AMG_zone_55"},
+ {20356, "PCS_AGD84_AMG_zone_56"},
+ {20357, "PCS_AGD84_AMG_zone_57"},
+ {20358, "PCS_AGD84_AMG_zone_58"},
+ {20437, "PCS_Ain_el_Abd_UTM_zone_37N"},
+ {20438, "PCS_Ain_el_Abd_UTM_zone_38N"},
+ {20439, "PCS_Ain_el_Abd_UTM_zone_39N"},
+ {20499, "PCS_Ain_el_Abd_Bahrain_Grid"},
+ {20538, "PCS_Afgooye_UTM_zone_38N"},
+ {20539, "PCS_Afgooye_UTM_zone_39N"},
+ {20700, "PCS_Lisbon_Portugese_Grid"},
+ {20822, "PCS_Aratu_UTM_zone_22S"},
+ {20823, "PCS_Aratu_UTM_zone_23S"},
+ {20824, "PCS_Aratu_UTM_zone_24S"},
+ {20973, "PCS_Arc_1950_Lo13"},
+ {20975, "PCS_Arc_1950_Lo15"},
+ {20977, "PCS_Arc_1950_Lo17"},
+ {20979, "PCS_Arc_1950_Lo19"},
+ {20981, "PCS_Arc_1950_Lo21"},
+ {20983, "PCS_Arc_1950_Lo23"},
+ {20985, "PCS_Arc_1950_Lo25"},
+ {20987, "PCS_Arc_1950_Lo27"},
+ {20989, "PCS_Arc_1950_Lo29"},
+ {20991, "PCS_Arc_1950_Lo31"},
+ {20993, "PCS_Arc_1950_Lo33"},
+ {20995, "PCS_Arc_1950_Lo35"},
+ {21100, "PCS_Batavia_NEIEZ"},
+ {21148, "PCS_Batavia_UTM_zone_48S"},
+ {21149, "PCS_Batavia_UTM_zone_49S"},
+ {21150, "PCS_Batavia_UTM_zone_50S"},
+ {21413, "PCS_Beijing_Gauss_zone_13"},
+ {21414, "PCS_Beijing_Gauss_zone_14"},
+ {21415, "PCS_Beijing_Gauss_zone_15"},
+ {21416, "PCS_Beijing_Gauss_zone_16"},
+ {21417, "PCS_Beijing_Gauss_zone_17"},
+ {21418, "PCS_Beijing_Gauss_zone_18"},
+ {21419, "PCS_Beijing_Gauss_zone_19"},
+ {21420, "PCS_Beijing_Gauss_zone_20"},
+ {21421, "PCS_Beijing_Gauss_zone_21"},
+ {21422, "PCS_Beijing_Gauss_zone_22"},
+ {21423, "PCS_Beijing_Gauss_zone_23"},
+ {21473, "PCS_Beijing_Gauss_13N"},
+ {21474, "PCS_Beijing_Gauss_14N"},
+ {21475, "PCS_Beijing_Gauss_15N"},
+ {21476, "PCS_Beijing_Gauss_16N"},
+ {21477, "PCS_Beijing_Gauss_17N"},
+ {21478, "PCS_Beijing_Gauss_18N"},
+ {21479, "PCS_Beijing_Gauss_19N"},
+ {21480, "PCS_Beijing_Gauss_20N"},
+ {21481, "PCS_Beijing_Gauss_21N"},
+ {21482, "PCS_Beijing_Gauss_22N"},
+ {21483, "PCS_Beijing_Gauss_23N"},
+ {21500, "PCS_Belge_Lambert_50"},
+ {21790, "PCS_Bern_1898_Swiss_Old"},
+ {21817, "PCS_Bogota_UTM_zone_17N"},
+ {21818, "PCS_Bogota_UTM_zone_18N"},
+ {21891, "PCS_Bogota_Colombia_3W"},
+ {21892, "PCS_Bogota_Colombia_Bogota"},
+ {21893, "PCS_Bogota_Colombia_3E"},
+ {21894, "PCS_Bogota_Colombia_6E"},
+ {22032, "PCS_Camacupa_UTM_32S"},
+ {22033, "PCS_Camacupa_UTM_33S"},
+ {22191, "PCS_C_Inchauspe_Argentina_1"},
+ {22192, "PCS_C_Inchauspe_Argentina_2"},
+ {22193, "PCS_C_Inchauspe_Argentina_3"},
+ {22194, "PCS_C_Inchauspe_Argentina_4"},
+ {22195, "PCS_C_Inchauspe_Argentina_5"},
+ {22196, "PCS_C_Inchauspe_Argentina_6"},
+ {22197, "PCS_C_Inchauspe_Argentina_7"},
+ {22332, "PCS_Carthage_UTM_zone_32N"},
+ {22391, "PCS_Carthage_Nord_Tunisie"},
+ {22392, "PCS_Carthage_Sud_Tunisie"},
+ {22523, "PCS_Corrego_Alegre_UTM_23S"},
+ {22524, "PCS_Corrego_Alegre_UTM_24S"},
+ {22832, "PCS_Douala_UTM_zone_32N"},
+ {22992, "PCS_Egypt_1907_Red_Belt"},
+ {22993, "PCS_Egypt_1907_Purple_Belt"},
+ {22994, "PCS_Egypt_1907_Ext_Purple"},
+ {23028, "PCS_ED50_UTM_zone_28N"},
+ {23029, "PCS_ED50_UTM_zone_29N"},
+ {23030, "PCS_ED50_UTM_zone_30N"},
+ {23031, "PCS_ED50_UTM_zone_31N"},
+ {23032, "PCS_ED50_UTM_zone_32N"},
+ {23033, "PCS_ED50_UTM_zone_33N"},
+ {23034, "PCS_ED50_UTM_zone_34N"},
+ {23035, "PCS_ED50_UTM_zone_35N"},
+ {23036, "PCS_ED50_UTM_zone_36N"},
+ {23037, "PCS_ED50_UTM_zone_37N"},
+ {23038, "PCS_ED50_UTM_zone_38N"},
+ {23239, "PCS_Fahud_UTM_zone_39N"},
+ {23240, "PCS_Fahud_UTM_zone_40N"},
+ {23433, "PCS_Garoua_UTM_zone_33N"},
+ {23846, "PCS_ID74_UTM_zone_46N"},
+ {23847, "PCS_ID74_UTM_zone_47N"},
+ {23848, "PCS_ID74_UTM_zone_48N"},
+ {23849, "PCS_ID74_UTM_zone_49N"},
+ {23850, "PCS_ID74_UTM_zone_50N"},
+ {23851, "PCS_ID74_UTM_zone_51N"},
+ {23852, "PCS_ID74_UTM_zone_52N"},
+ {23853, "PCS_ID74_UTM_zone_53N"},
+ {23886, "PCS_ID74_UTM_zone_46S"},
+ {23887, "PCS_ID74_UTM_zone_47S"},
+ {23888, "PCS_ID74_UTM_zone_48S"},
+ {23889, "PCS_ID74_UTM_zone_49S"},
+ {23890, "PCS_ID74_UTM_zone_50S"},
+ {23891, "PCS_ID74_UTM_zone_51S"},
+ {23892, "PCS_ID74_UTM_zone_52S"},
+ {23893, "PCS_ID74_UTM_zone_53S"},
+ {23894, "PCS_ID74_UTM_zone_54S"},
+ {23947, "PCS_Indian_1954_UTM_47N"},
+ {23948, "PCS_Indian_1954_UTM_48N"},
+ {24047, "PCS_Indian_1975_UTM_47N"},
+ {24048, "PCS_Indian_1975_UTM_48N"},
+ {24100, "PCS_Jamaica_1875_Old_Grid"},
+ {24200, "PCS_JAD69_Jamaica_Grid"},
+ {24370, "PCS_Kalianpur_India_0"},
+ {24371, "PCS_Kalianpur_India_I"},
+ {24372, "PCS_Kalianpur_India_IIa"},
+ {24373, "PCS_Kalianpur_India_IIIa"},
+ {24374, "PCS_Kalianpur_India_IVa"},
+ {24382, "PCS_Kalianpur_India_IIb"},
+ {24383, "PCS_Kalianpur_India_IIIb"},
+ {24384, "PCS_Kalianpur_India_IVb"},
+ {24500, "PCS_Kertau_Singapore_Grid"},
+ {24547, "PCS_Kertau_UTM_zone_47N"},
+ {24548, "PCS_Kertau_UTM_zone_48N"},
+ {24720, "PCS_La_Canoa_UTM_zone_20N"},
+ {24721, "PCS_La_Canoa_UTM_zone_21N"},
+ {24818, "PCS_PSAD56_UTM_zone_18N"},
+ {24819, "PCS_PSAD56_UTM_zone_19N"},
+ {24820, "PCS_PSAD56_UTM_zone_20N"},
+ {24821, "PCS_PSAD56_UTM_zone_21N"},
+ {24877, "PCS_PSAD56_UTM_zone_17S"},
+ {24878, "PCS_PSAD56_UTM_zone_18S"},
+ {24879, "PCS_PSAD56_UTM_zone_19S"},
+ {24880, "PCS_PSAD56_UTM_zone_20S"},
+ {24891, "PCS_PSAD56_Peru_west_zone"},
+ {24892, "PCS_PSAD56_Peru_central"},
+ {24893, "PCS_PSAD56_Peru_east_zone"},
+ {25000, "PCS_Leigon_Ghana_Grid"},
+ {25231, "PCS_Lome_UTM_zone_31N"},
+ {25391, "PCS_Luzon_Philippines_I"},
+ {25392, "PCS_Luzon_Philippines_II"},
+ {25393, "PCS_Luzon_Philippines_III"},
+ {25394, "PCS_Luzon_Philippines_IV"},
+ {25395, "PCS_Luzon_Philippines_V"},
+ {25700, "PCS_Makassar_NEIEZ"},
+ {25932, "PCS_Malongo_1987_UTM_32S"},
+ {26191, "PCS_Merchich_Nord_Maroc"},
+ {26192, "PCS_Merchich_Sud_Maroc"},
+ {26193, "PCS_Merchich_Sahara"},
+ {26237, "PCS_Massawa_UTM_zone_37N"},
+ {26331, "PCS_Minna_UTM_zone_31N"},
+ {26332, "PCS_Minna_UTM_zone_32N"},
+ {26391, "PCS_Minna_Nigeria_West"},
+ {26392, "PCS_Minna_Nigeria_Mid_Belt"},
+ {26393, "PCS_Minna_Nigeria_East"},
+ {26432, "PCS_Mhast_UTM_zone_32S"},
+ {26591, "PCS_Monte_Mario_Italy_1"},
+ {26592, "PCS_Monte_Mario_Italy_2"},
+ {26632, "PCS_M_poraloko_UTM_32N"},
+ {26692, "PCS_M_poraloko_UTM_32S"},
+ {26703, "PCS_NAD27_UTM_zone_3N"},
+ {26704, "PCS_NAD27_UTM_zone_4N"},
+ {26705, "PCS_NAD27_UTM_zone_5N"},
+ {26706, "PCS_NAD27_UTM_zone_6N"},
+ {26707, "PCS_NAD27_UTM_zone_7N"},
+ {26708, "PCS_NAD27_UTM_zone_8N"},
+ {26709, "PCS_NAD27_UTM_zone_9N"},
+ {26710, "PCS_NAD27_UTM_zone_10N"},
+ {26711, "PCS_NAD27_UTM_zone_11N"},
+ {26712, "PCS_NAD27_UTM_zone_12N"},
+ {26713, "PCS_NAD27_UTM_zone_13N"},
+ {26714, "PCS_NAD27_UTM_zone_14N"},
+ {26715, "PCS_NAD27_UTM_zone_15N"},
+ {26716, "PCS_NAD27_UTM_zone_16N"},
+ {26717, "PCS_NAD27_UTM_zone_17N"},
+ {26718, "PCS_NAD27_UTM_zone_18N"},
+ {26719, "PCS_NAD27_UTM_zone_19N"},
+ {26720, "PCS_NAD27_UTM_zone_20N"},
+ {26721, "PCS_NAD27_UTM_zone_21N"},
+ {26722, "PCS_NAD27_UTM_zone_22N"},
+ {26729, "PCS_NAD27_Alabama_East"},
+ {26730, "PCS_NAD27_Alabama_West"},
+ {26731, "PCS_NAD27_Alaska_zone_1"},
+ {26732, "PCS_NAD27_Alaska_zone_2"},
+ {26733, "PCS_NAD27_Alaska_zone_3"},
+ {26734, "PCS_NAD27_Alaska_zone_4"},
+ {26735, "PCS_NAD27_Alaska_zone_5"},
+ {26736, "PCS_NAD27_Alaska_zone_6"},
+ {26737, "PCS_NAD27_Alaska_zone_7"},
+ {26738, "PCS_NAD27_Alaska_zone_8"},
+ {26739, "PCS_NAD27_Alaska_zone_9"},
+ {26740, "PCS_NAD27_Alaska_zone_10"},
+ {26741, "PCS_NAD27_California_I"},
+ {26742, "PCS_NAD27_California_II"},
+ {26743, "PCS_NAD27_California_III"},
+ {26744, "PCS_NAD27_California_IV"},
+ {26745, "PCS_NAD27_California_V"},
+ {26746, "PCS_NAD27_California_VI"},
+ {26747, "PCS_NAD27_California_VII"},
+ {26748, "PCS_NAD27_Arizona_East"},
+ {26749, "PCS_NAD27_Arizona_Central"},
+ {26750, "PCS_NAD27_Arizona_West"},
+ {26751, "PCS_NAD27_Arkansas_North"},
+ {26752, "PCS_NAD27_Arkansas_South"},
+ {26753, "PCS_NAD27_Colorado_North"},
+ {26754, "PCS_NAD27_Colorado_Central"},
+ {26755, "PCS_NAD27_Colorado_South"},
+ {26756, "PCS_NAD27_Connecticut"},
+ {26757, "PCS_NAD27_Delaware"},
+ {26758, "PCS_NAD27_Florida_East"},
+ {26759, "PCS_NAD27_Florida_West"},
+ {26760, "PCS_NAD27_Florida_North"},
+ {26761, "PCS_NAD27_Hawaii_zone_1"},
+ {26762, "PCS_NAD27_Hawaii_zone_2"},
+ {26763, "PCS_NAD27_Hawaii_zone_3"},
+ {26764, "PCS_NAD27_Hawaii_zone_4"},
+ {26765, "PCS_NAD27_Hawaii_zone_5"},
+ {26766, "PCS_NAD27_Georgia_East"},
+ {26767, "PCS_NAD27_Georgia_West"},
+ {26768, "PCS_NAD27_Idaho_East"},
+ {26769, "PCS_NAD27_Idaho_Central"},
+ {26770, "PCS_NAD27_Idaho_West"},
+ {26771, "PCS_NAD27_Illinois_East"},
+ {26772, "PCS_NAD27_Illinois_West"},
+ {26773, "PCS_NAD27_Indiana_East"},
+ {26774, "PCS_NAD27_BLM_14N_feet"},
+ {26774, "PCS_NAD27_Indiana_West"},
+ {26775, "PCS_NAD27_BLM_15N_feet"},
+ {26775, "PCS_NAD27_Iowa_North"},
+ {26776, "PCS_NAD27_BLM_16N_feet"},
+ {26776, "PCS_NAD27_Iowa_South"},
+ {26777, "PCS_NAD27_BLM_17N_feet"},
+ {26777, "PCS_NAD27_Kansas_North"},
+ {26778, "PCS_NAD27_Kansas_South"},
+ {26779, "PCS_NAD27_Kentucky_North"},
+ {26780, "PCS_NAD27_Kentucky_South"},
+ {26781, "PCS_NAD27_Louisiana_North"},
+ {26782, "PCS_NAD27_Louisiana_South"},
+ {26783, "PCS_NAD27_Maine_East"},
+ {26784, "PCS_NAD27_Maine_West"},
+ {26785, "PCS_NAD27_Maryland"},
+ {26786, "PCS_NAD27_Massachusetts"},
+ {26787, "PCS_NAD27_Massachusetts_Is"},
+ {26788, "PCS_NAD27_Michigan_North"},
+ {26789, "PCS_NAD27_Michigan_Central"},
+ {26790, "PCS_NAD27_Michigan_South"},
+ {26791, "PCS_NAD27_Minnesota_North"},
+ {26792, "PCS_NAD27_Minnesota_Cent"},
+ {26793, "PCS_NAD27_Minnesota_South"},
+ {26794, "PCS_NAD27_Mississippi_East"},
+ {26795, "PCS_NAD27_Mississippi_West"},
+ {26796, "PCS_NAD27_Missouri_East"},
+ {26797, "PCS_NAD27_Missouri_Central"},
+ {26798, "PCS_NAD27_Missouri_West"},
+ {26801, "PCS_NAD_Michigan_Michigan_East"},
+ {26802, "PCS_NAD_Michigan_Michigan_Old_Central"},
+ {26803, "PCS_NAD_Michigan_Michigan_West"},
+ {26903, "PCS_NAD83_UTM_zone_3N"},
+ {26904, "PCS_NAD83_UTM_zone_4N"},
+ {26905, "PCS_NAD83_UTM_zone_5N"},
+ {26906, "PCS_NAD83_UTM_zone_6N"},
+ {26907, "PCS_NAD83_UTM_zone_7N"},
+ {26908, "PCS_NAD83_UTM_zone_8N"},
+ {26909, "PCS_NAD83_UTM_zone_9N"},
+ {26910, "PCS_NAD83_UTM_zone_10N"},
+ {26911, "PCS_NAD83_UTM_zone_11N"},
+ {26912, "PCS_NAD83_UTM_zone_12N"},
+ {26913, "PCS_NAD83_UTM_zone_13N"},
+ {26914, "PCS_NAD83_UTM_zone_14N"},
+ {26915, "PCS_NAD83_UTM_zone_15N"},
+ {26916, "PCS_NAD83_UTM_zone_16N"},
+ {26917, "PCS_NAD83_UTM_zone_17N"},
+ {26918, "PCS_NAD83_UTM_zone_18N"},
+ {26919, "PCS_NAD83_UTM_zone_19N"},
+ {26920, "PCS_NAD83_UTM_zone_20N"},
+ {26921, "PCS_NAD83_UTM_zone_21N"},
+ {26922, "PCS_NAD83_UTM_zone_22N"},
+ {26923, "PCS_NAD83_UTM_zone_23N"},
+ {26929, "PCS_NAD83_Alabama_East"},
+ {26930, "PCS_NAD83_Alabama_West"},
+ {26931, "PCS_NAD83_Alaska_zone_1"},
+ {26932, "PCS_NAD83_Alaska_zone_2"},
+ {26933, "PCS_NAD83_Alaska_zone_3"},
+ {26934, "PCS_NAD83_Alaska_zone_4"},
+ {26935, "PCS_NAD83_Alaska_zone_5"},
+ {26936, "PCS_NAD83_Alaska_zone_6"},
+ {26937, "PCS_NAD83_Alaska_zone_7"},
+ {26938, "PCS_NAD83_Alaska_zone_8"},
+ {26939, "PCS_NAD83_Alaska_zone_9"},
+ {26940, "PCS_NAD83_Alaska_zone_10"},
+ {26941, "PCS_NAD83_California_1"},
+ {26942, "PCS_NAD83_California_2"},
+ {26943, "PCS_NAD83_California_3"},
+ {26944, "PCS_NAD83_California_4"},
+ {26945, "PCS_NAD83_California_5"},
+ {26946, "PCS_NAD83_California_6"},
+ {26948, "PCS_NAD83_Arizona_East"},
+ {26949, "PCS_NAD83_Arizona_Central"},
+ {26950, "PCS_NAD83_Arizona_West"},
+ {26951, "PCS_NAD83_Arkansas_North"},
+ {26952, "PCS_NAD83_Arkansas_South"},
+ {26953, "PCS_NAD83_Colorado_North"},
+ {26954, "PCS_NAD83_Colorado_Central"},
+ {26955, "PCS_NAD83_Colorado_South"},
+ {26956, "PCS_NAD83_Connecticut"},
+ {26957, "PCS_NAD83_Delaware"},
+ {26958, "PCS_NAD83_Florida_East"},
+ {26959, "PCS_NAD83_Florida_West"},
+ {26960, "PCS_NAD83_Florida_North"},
+ {26961, "PCS_NAD83_Hawaii_zone_1"},
+ {26962, "PCS_NAD83_Hawaii_zone_2"},
+ {26963, "PCS_NAD83_Hawaii_zone_3"},
+ {26964, "PCS_NAD83_Hawaii_zone_4"},
+ {26965, "PCS_NAD83_Hawaii_zone_5"},
+ {26966, "PCS_NAD83_Georgia_East"},
+ {26967, "PCS_NAD83_Georgia_West"},
+ {26968, "PCS_NAD83_Idaho_East"},
+ {26969, "PCS_NAD83_Idaho_Central"},
+ {26970, "PCS_NAD83_Idaho_West"},
+ {26971, "PCS_NAD83_Illinois_East"},
+ {26972, "PCS_NAD83_Illinois_West"},
+ {26973, "PCS_NAD83_Indiana_East"},
+ {26974, "PCS_NAD83_Indiana_West"},
+ {26975, "PCS_NAD83_Iowa_North"},
+ {26976, "PCS_NAD83_Iowa_South"},
+ {26977, "PCS_NAD83_Kansas_North"},
+ {26978, "PCS_NAD83_Kansas_South"},
+ {26979, "PCS_NAD83_Kentucky_North"},
+ {26980, "PCS_NAD83_Kentucky_South"},
+ {26981, "PCS_NAD83_Louisiana_North"},
+ {26982, "PCS_NAD83_Louisiana_South"},
+ {26983, "PCS_NAD83_Maine_East"},
+ {26984, "PCS_NAD83_Maine_West"},
+ {26985, "PCS_NAD83_Maryland"},
+ {26986, "PCS_NAD83_Massachusetts"},
+ {26987, "PCS_NAD83_Massachusetts_Is"},
+ {26988, "PCS_NAD83_Michigan_North"},
+ {26989, "PCS_NAD83_Michigan_Central"},
+ {26990, "PCS_NAD83_Michigan_South"},
+ {26991, "PCS_NAD83_Minnesota_North"},
+ {26992, "PCS_NAD83_Minnesota_Cent"},
+ {26993, "PCS_NAD83_Minnesota_South"},
+ {26994, "PCS_NAD83_Mississippi_East"},
+ {26995, "PCS_NAD83_Mississippi_West"},
+ {26996, "PCS_NAD83_Missouri_East"},
+ {26997, "PCS_NAD83_Missouri_Central"},
+ {26998, "PCS_NAD83_Missouri_West"},
+ {27038, "PCS_Nahrwan_1967_UTM_38N"},
+ {27039, "PCS_Nahrwan_1967_UTM_39N"},
+ {27040, "PCS_Nahrwan_1967_UTM_40N"},
+ {27120, "PCS_Naparima_UTM_20N"},
+ {27200, "PCS_GD49_NZ_Map_Grid"},
+ {27291, "PCS_GD49_North_Island_Grid"},
+ {27292, "PCS_GD49_South_Island_Grid"},
+ {27429, "PCS_Datum_73_UTM_zone_29N"},
+ {27500, "PCS_ATF_Nord_de_Guerre"},
+ {27581, "PCS_NTF_France_I"},
+ {27582, "PCS_NTF_France_II"},
+ {27583, "PCS_NTF_France_III"},
+ {27591, "PCS_NTF_Nord_France"},
+ {27592, "PCS_NTF_Centre_France"},
+ {27593, "PCS_NTF_Sud_France"},
+ {27700, "PCS_British_National_Grid"},
+ {28232, "PCS_Point_Noire_UTM_32S"},
+ {28348, "PCS_GDA94_MGA_zone_48"},
+ {28349, "PCS_GDA94_MGA_zone_49"},
+ {28350, "PCS_GDA94_MGA_zone_50"},
+ {28351, "PCS_GDA94_MGA_zone_51"},
+ {28352, "PCS_GDA94_MGA_zone_52"},
+ {28353, "PCS_GDA94_MGA_zone_53"},
+ {28354, "PCS_GDA94_MGA_zone_54"},
+ {28355, "PCS_GDA94_MGA_zone_55"},
+ {28356, "PCS_GDA94_MGA_zone_56"},
+ {28357, "PCS_GDA94_MGA_zone_57"},
+ {28358, "PCS_GDA94_MGA_zone_58"},
+ {28404, "PCS_Pulkovo_Gauss_zone_4"},
+ {28405, "PCS_Pulkovo_Gauss_zone_5"},
+ {28406, "PCS_Pulkovo_Gauss_zone_6"},
+ {28407, "PCS_Pulkovo_Gauss_zone_7"},
+ {28408, "PCS_Pulkovo_Gauss_zone_8"},
+ {28409, "PCS_Pulkovo_Gauss_zone_9"},
+ {28410, "PCS_Pulkovo_Gauss_zone_10"},
+ {28411, "PCS_Pulkovo_Gauss_zone_11"},
+ {28412, "PCS_Pulkovo_Gauss_zone_12"},
+ {28413, "PCS_Pulkovo_Gauss_zone_13"},
+ {28414, "PCS_Pulkovo_Gauss_zone_14"},
+ {28415, "PCS_Pulkovo_Gauss_zone_15"},
+ {28416, "PCS_Pulkovo_Gauss_zone_16"},
+ {28417, "PCS_Pulkovo_Gauss_zone_17"},
+ {28418, "PCS_Pulkovo_Gauss_zone_18"},
+ {28419, "PCS_Pulkovo_Gauss_zone_19"},
+ {28420, "PCS_Pulkovo_Gauss_zone_20"},
+ {28421, "PCS_Pulkovo_Gauss_zone_21"},
+ {28422, "PCS_Pulkovo_Gauss_zone_22"},
+ {28423, "PCS_Pulkovo_Gauss_zone_23"},
+ {28424, "PCS_Pulkovo_Gauss_zone_24"},
+ {28425, "PCS_Pulkovo_Gauss_zone_25"},
+ {28426, "PCS_Pulkovo_Gauss_zone_26"},
+ {28427, "PCS_Pulkovo_Gauss_zone_27"},
+ {28428, "PCS_Pulkovo_Gauss_zone_28"},
+ {28429, "PCS_Pulkovo_Gauss_zone_29"},
+ {28430, "PCS_Pulkovo_Gauss_zone_30"},
+ {28431, "PCS_Pulkovo_Gauss_zone_31"},
+ {28432, "PCS_Pulkovo_Gauss_zone_32"},
+ {28464, "PCS_Pulkovo_Gauss_4N"},
+ {28465, "PCS_Pulkovo_Gauss_5N"},
+ {28466, "PCS_Pulkovo_Gauss_6N"},
+ {28467, "PCS_Pulkovo_Gauss_7N"},
+ {28468, "PCS_Pulkovo_Gauss_8N"},
+ {28469, "PCS_Pulkovo_Gauss_9N"},
+ {28470, "PCS_Pulkovo_Gauss_10N"},
+ {28471, "PCS_Pulkovo_Gauss_11N"},
+ {28472, "PCS_Pulkovo_Gauss_12N"},
+ {28473, "PCS_Pulkovo_Gauss_13N"},
+ {28474, "PCS_Pulkovo_Gauss_14N"},
+ {28475, "PCS_Pulkovo_Gauss_15N"},
+ {28476, "PCS_Pulkovo_Gauss_16N"},
+ {28477, "PCS_Pulkovo_Gauss_17N"},
+ {28478, "PCS_Pulkovo_Gauss_18N"},
+ {28479, "PCS_Pulkovo_Gauss_19N"},
+ {28480, "PCS_Pulkovo_Gauss_20N"},
+ {28481, "PCS_Pulkovo_Gauss_21N"},
+ {28482, "PCS_Pulkovo_Gauss_22N"},
+ {28483, "PCS_Pulkovo_Gauss_23N"},
+ {28484, "PCS_Pulkovo_Gauss_24N"},
+ {28485, "PCS_Pulkovo_Gauss_25N"},
+ {28486, "PCS_Pulkovo_Gauss_26N"},
+ {28487, "PCS_Pulkovo_Gauss_27N"},
+ {28488, "PCS_Pulkovo_Gauss_28N"},
+ {28489, "PCS_Pulkovo_Gauss_29N"},
+ {28490, "PCS_Pulkovo_Gauss_30N"},
+ {28491, "PCS_Pulkovo_Gauss_31N"},
+ {28492, "PCS_Pulkovo_Gauss_32N"},
+ {28600, "PCS_Qatar_National_Grid"},
+ {28991, "PCS_RD_Netherlands_Old"},
+ {28992, "PCS_RD_Netherlands_New"},
+ {29118, "PCS_SAD69_UTM_zone_18N"},
+ {29119, "PCS_SAD69_UTM_zone_19N"},
+ {29120, "PCS_SAD69_UTM_zone_20N"},
+ {29121, "PCS_SAD69_UTM_zone_21N"},
+ {29122, "PCS_SAD69_UTM_zone_22N"},
+ {29177, "PCS_SAD69_UTM_zone_17S"},
+ {29178, "PCS_SAD69_UTM_zone_18S"},
+ {29179, "PCS_SAD69_UTM_zone_19S"},
+ {29180, "PCS_SAD69_UTM_zone_20S"},
+ {29181, "PCS_SAD69_UTM_zone_21S"},
+ {29182, "PCS_SAD69_UTM_zone_22S"},
+ {29183, "PCS_SAD69_UTM_zone_23S"},
+ {29184, "PCS_SAD69_UTM_zone_24S"},
+ {29185, "PCS_SAD69_UTM_zone_25S"},
+ {29220, "PCS_Sapper_Hill_UTM_20S"},
+ {29221, "PCS_Sapper_Hill_UTM_21S"},
+ {29333, "PCS_Schwarzeck_UTM_33S"},
+ {29635, "PCS_Sudan_UTM_zone_35N"},
+ {29636, "PCS_Sudan_UTM_zone_36N"},
+ {29700, "PCS_Tananarive_Laborde"},
+ {29738, "PCS_Tananarive_UTM_38S"},
+ {29739, "PCS_Tananarive_UTM_39S"},
+ {29800, "PCS_Timbalai_1948_Borneo"},
+ {29849, "PCS_Timbalai_1948_UTM_49N"},
+ {29850, "PCS_Timbalai_1948_UTM_50N"},
+ {29900, "PCS_TM65_Irish_Nat_Grid"},
+ {30200, "PCS_Trinidad_1903_Trinidad"},
+ {30339, "PCS_TC_1948_UTM_zone_39N"},
+ {30340, "PCS_TC_1948_UTM_zone_40N"},
+ {30491, "PCS_Voirol_N_Algerie_ancien"},
+ {30492, "PCS_Voirol_S_Algerie_ancien"},
+ {30591, "PCS_Voirol_Unifie_N_Algerie"},
+ {30592, "PCS_Voirol_Unifie_S_Algerie"},
+ {30600, "PCS_Bern_1938_Swiss_New"},
+ {30729, "PCS_Nord_Sahara_UTM_29N"},
+ {30730, "PCS_Nord_Sahara_UTM_30N"},
+ {30731, "PCS_Nord_Sahara_UTM_31N"},
+ {30732, "PCS_Nord_Sahara_UTM_32N"},
+ {31028, "PCS_Yoff_UTM_zone_28N"},
+ {31121, "PCS_Zanderij_UTM_zone_21N"},
+ {31291, "PCS_MGI_Austria_West"},
+ {31292, "PCS_MGI_Austria_Central"},
+ {31293, "PCS_MGI_Austria_East"},
+ {31300, "PCS_Belge_Lambert_72"},
+ {31491, "PCS_DHDN_Germany_zone_1"},
+ {31492, "PCS_DHDN_Germany_zone_2"},
+ {31493, "PCS_DHDN_Germany_zone_3"},
+ {31494, "PCS_DHDN_Germany_zone_4"},
+ {31495, "PCS_DHDN_Germany_zone_5"},
+ {32001, "PCS_NAD27_Montana_North"},
+ {32002, "PCS_NAD27_Montana_Central"},
+ {32003, "PCS_NAD27_Montana_South"},
+ {32005, "PCS_NAD27_Nebraska_North"},
+ {32006, "PCS_NAD27_Nebraska_South"},
+ {32007, "PCS_NAD27_Nevada_East"},
+ {32008, "PCS_NAD27_Nevada_Central"},
+ {32009, "PCS_NAD27_Nevada_West"},
+ {32010, "PCS_NAD27_New_Hampshire"},
+ {32011, "PCS_NAD27_New_Jersey"},
+ {32012, "PCS_NAD27_New_Mexico_East"},
+ {32013, "PCS_NAD27_New_Mexico_Cent"},
+ {32014, "PCS_NAD27_New_Mexico_West"},
+ {32015, "PCS_NAD27_New_York_East"},
+ {32016, "PCS_NAD27_New_York_Central"},
+ {32017, "PCS_NAD27_New_York_West"},
+ {32018, "PCS_NAD27_New_York_Long_Is"},
+ {32019, "PCS_NAD27_North_Carolina"},
+ {32020, "PCS_NAD27_North_Dakota_N"},
+ {32021, "PCS_NAD27_North_Dakota_S"},
+ {32022, "PCS_NAD27_Ohio_North"},
+ {32023, "PCS_NAD27_Ohio_South"},
+ {32024, "PCS_NAD27_Oklahoma_North"},
+ {32025, "PCS_NAD27_Oklahoma_South"},
+ {32026, "PCS_NAD27_Oregon_North"},
+ {32027, "PCS_NAD27_Oregon_South"},
+ {32028, "PCS_NAD27_Pennsylvania_N"},
+ {32029, "PCS_NAD27_Pennsylvania_S"},
+ {32030, "PCS_NAD27_Rhode_Island"},
+ {32031, "PCS_NAD27_South_Carolina_N"},
+ {32033, "PCS_NAD27_South_Carolina_S"},
+ {32034, "PCS_NAD27_South_Dakota_N"},
+ {32035, "PCS_NAD27_South_Dakota_S"},
+ {32036, "PCS_NAD27_Tennessee"},
+ {32037, "PCS_NAD27_Texas_North"},
+ {32038, "PCS_NAD27_Texas_North_Cen"},
+ {32039, "PCS_NAD27_Texas_Central"},
+ {32040, "PCS_NAD27_Texas_South_Cen"},
+ {32041, "PCS_NAD27_Texas_South"},
+ {32042, "PCS_NAD27_Utah_North"},
+ {32043, "PCS_NAD27_Utah_Central"},
+ {32044, "PCS_NAD27_Utah_South"},
+ {32045, "PCS_NAD27_Vermont"},
+ {32046, "PCS_NAD27_Virginia_North"},
+ {32047, "PCS_NAD27_Virginia_South"},
+ {32048, "PCS_NAD27_Washington_North"},
+ {32049, "PCS_NAD27_Washington_South"},
+ {32050, "PCS_NAD27_West_Virginia_N"},
+ {32051, "PCS_NAD27_West_Virginia_S"},
+ {32052, "PCS_NAD27_Wisconsin_North"},
+ {32053, "PCS_NAD27_Wisconsin_Cen"},
+ {32054, "PCS_NAD27_Wisconsin_South"},
+ {32055, "PCS_NAD27_Wyoming_East"},
+ {32056, "PCS_NAD27_Wyoming_E_Cen"},
+ {32057, "PCS_NAD27_Wyoming_W_Cen"},
+ {32058, "PCS_NAD27_Wyoming_West"},
+ {32059, "PCS_NAD27_Puerto_Rico"},
+ {32060, "PCS_NAD27_St_Croix"},
+ {32100, "PCS_NAD83_Montana"},
+ {32104, "PCS_NAD83_Nebraska"},
+ {32107, "PCS_NAD83_Nevada_East"},
+ {32108, "PCS_NAD83_Nevada_Central"},
+ {32109, "PCS_NAD83_Nevada_West"},
+ {32110, "PCS_NAD83_New_Hampshire"},
+ {32111, "PCS_NAD83_New_Jersey"},
+ {32112, "PCS_NAD83_New_Mexico_East"},
+ {32113, "PCS_NAD83_New_Mexico_Cent"},
+ {32114, "PCS_NAD83_New_Mexico_West"},
+ {32115, "PCS_NAD83_New_York_East"},
+ {32116, "PCS_NAD83_New_York_Central"},
+ {32117, "PCS_NAD83_New_York_West"},
+ {32118, "PCS_NAD83_New_York_Long_Is"},
+ {32119, "PCS_NAD83_North_Carolina"},
+ {32120, "PCS_NAD83_North_Dakota_N"},
+ {32121, "PCS_NAD83_North_Dakota_S"},
+ {32122, "PCS_NAD83_Ohio_North"},
+ {32123, "PCS_NAD83_Ohio_South"},
+ {32124, "PCS_NAD83_Oklahoma_North"},
+ {32125, "PCS_NAD83_Oklahoma_South"},
+ {32126, "PCS_NAD83_Oregon_North"},
+ {32127, "PCS_NAD83_Oregon_South"},
+ {32128, "PCS_NAD83_Pennsylvania_N"},
+ {32129, "PCS_NAD83_Pennsylvania_S"},
+ {32130, "PCS_NAD83_Rhode_Island"},
+ {32133, "PCS_NAD83_South_Carolina"},
+ {32134, "PCS_NAD83_South_Dakota_N"},
+ {32135, "PCS_NAD83_South_Dakota_S"},
+ {32136, "PCS_NAD83_Tennessee"},
+ {32137, "PCS_NAD83_Texas_North"},
+ {32138, "PCS_NAD83_Texas_North_Cen"},
+ {32139, "PCS_NAD83_Texas_Central"},
+ {32140, "PCS_NAD83_Texas_South_Cen"},
+ {32141, "PCS_NAD83_Texas_South"},
+ {32142, "PCS_NAD83_Utah_North"},
+ {32143, "PCS_NAD83_Utah_Central"},
+ {32144, "PCS_NAD83_Utah_South"},
+ {32145, "PCS_NAD83_Vermont"},
+ {32146, "PCS_NAD83_Virginia_North"},
+ {32147, "PCS_NAD83_Virginia_South"},
+ {32148, "PCS_NAD83_Washington_North"},
+ {32149, "PCS_NAD83_Washington_South"},
+ {32150, "PCS_NAD83_West_Virginia_N"},
+ {32151, "PCS_NAD83_West_Virginia_S"},
+ {32152, "PCS_NAD83_Wisconsin_North"},
+ {32153, "PCS_NAD83_Wisconsin_Cen"},
+ {32154, "PCS_NAD83_Wisconsin_South"},
+ {32155, "PCS_NAD83_Wyoming_East"},
+ {32156, "PCS_NAD83_Wyoming_E_Cen"},
+ {32157, "PCS_NAD83_Wyoming_W_Cen"},
+ {32158, "PCS_NAD83_Wyoming_West"},
+ {32161, "PCS_NAD83_Puerto_Rico_Virgin_Is"},
+ {32201, "PCS_WGS72_UTM_zone_1N"},
+ {32202, "PCS_WGS72_UTM_zone_2N"},
+ {32203, "PCS_WGS72_UTM_zone_3N"},
+ {32204, "PCS_WGS72_UTM_zone_4N"},
+ {32205, "PCS_WGS72_UTM_zone_5N"},
+ {32206, "PCS_WGS72_UTM_zone_6N"},
+ {32207, "PCS_WGS72_UTM_zone_7N"},
+ {32208, "PCS_WGS72_UTM_zone_8N"},
+ {32209, "PCS_WGS72_UTM_zone_9N"},
+ {32210, "PCS_WGS72_UTM_zone_10N"},
+ {32211, "PCS_WGS72_UTM_zone_11N"},
+ {32212, "PCS_WGS72_UTM_zone_12N"},
+ {32213, "PCS_WGS72_UTM_zone_13N"},
+ {32214, "PCS_WGS72_UTM_zone_14N"},
+ {32215, "PCS_WGS72_UTM_zone_15N"},
+ {32216, "PCS_WGS72_UTM_zone_16N"},
+ {32217, "PCS_WGS72_UTM_zone_17N"},
+ {32218, "PCS_WGS72_UTM_zone_18N"},
+ {32219, "PCS_WGS72_UTM_zone_19N"},
+ {32220, "PCS_WGS72_UTM_zone_20N"},
+ {32221, "PCS_WGS72_UTM_zone_21N"},
+ {32222, "PCS_WGS72_UTM_zone_22N"},
+ {32223, "PCS_WGS72_UTM_zone_23N"},
+ {32224, "PCS_WGS72_UTM_zone_24N"},
+ {32225, "PCS_WGS72_UTM_zone_25N"},
+ {32226, "PCS_WGS72_UTM_zone_26N"},
+ {32227, "PCS_WGS72_UTM_zone_27N"},
+ {32228, "PCS_WGS72_UTM_zone_28N"},
+ {32229, "PCS_WGS72_UTM_zone_29N"},
+ {32230, "PCS_WGS72_UTM_zone_30N"},
+ {32231, "PCS_WGS72_UTM_zone_31N"},
+ {32232, "PCS_WGS72_UTM_zone_32N"},
+ {32233, "PCS_WGS72_UTM_zone_33N"},
+ {32234, "PCS_WGS72_UTM_zone_34N"},
+ {32235, "PCS_WGS72_UTM_zone_35N"},
+ {32236, "PCS_WGS72_UTM_zone_36N"},
+ {32237, "PCS_WGS72_UTM_zone_37N"},
+ {32238, "PCS_WGS72_UTM_zone_38N"},
+ {32239, "PCS_WGS72_UTM_zone_39N"},
+ {32240, "PCS_WGS72_UTM_zone_40N"},
+ {32241, "PCS_WGS72_UTM_zone_41N"},
+ {32242, "PCS_WGS72_UTM_zone_42N"},
+ {32243, "PCS_WGS72_UTM_zone_43N"},
+ {32244, "PCS_WGS72_UTM_zone_44N"},
+ {32245, "PCS_WGS72_UTM_zone_45N"},
+ {32246, "PCS_WGS72_UTM_zone_46N"},
+ {32247, "PCS_WGS72_UTM_zone_47N"},
+ {32248, "PCS_WGS72_UTM_zone_48N"},
+ {32249, "PCS_WGS72_UTM_zone_49N"},
+ {32250, "PCS_WGS72_UTM_zone_50N"},
+ {32251, "PCS_WGS72_UTM_zone_51N"},
+ {32252, "PCS_WGS72_UTM_zone_52N"},
+ {32253, "PCS_WGS72_UTM_zone_53N"},
+ {32254, "PCS_WGS72_UTM_zone_54N"},
+ {32255, "PCS_WGS72_UTM_zone_55N"},
+ {32256, "PCS_WGS72_UTM_zone_56N"},
+ {32257, "PCS_WGS72_UTM_zone_57N"},
+ {32258, "PCS_WGS72_UTM_zone_58N"},
+ {32259, "PCS_WGS72_UTM_zone_59N"},
+ {32260, "PCS_WGS72_UTM_zone_60N"},
+ {32301, "PCS_WGS72_UTM_zone_1S"},
+ {32302, "PCS_WGS72_UTM_zone_2S"},
+ {32303, "PCS_WGS72_UTM_zone_3S"},
+ {32304, "PCS_WGS72_UTM_zone_4S"},
+ {32305, "PCS_WGS72_UTM_zone_5S"},
+ {32306, "PCS_WGS72_UTM_zone_6S"},
+ {32307, "PCS_WGS72_UTM_zone_7S"},
+ {32308, "PCS_WGS72_UTM_zone_8S"},
+ {32309, "PCS_WGS72_UTM_zone_9S"},
+ {32310, "PCS_WGS72_UTM_zone_10S"},
+ {32311, "PCS_WGS72_UTM_zone_11S"},
+ {32312, "PCS_WGS72_UTM_zone_12S"},
+ {32313, "PCS_WGS72_UTM_zone_13S"},
+ {32314, "PCS_WGS72_UTM_zone_14S"},
+ {32315, "PCS_WGS72_UTM_zone_15S"},
+ {32316, "PCS_WGS72_UTM_zone_16S"},
+ {32317, "PCS_WGS72_UTM_zone_17S"},
+ {32318, "PCS_WGS72_UTM_zone_18S"},
+ {32319, "PCS_WGS72_UTM_zone_19S"},
+ {32320, "PCS_WGS72_UTM_zone_20S"},
+ {32321, "PCS_WGS72_UTM_zone_21S"},
+ {32322, "PCS_WGS72_UTM_zone_22S"},
+ {32323, "PCS_WGS72_UTM_zone_23S"},
+ {32324, "PCS_WGS72_UTM_zone_24S"},
+ {32325, "PCS_WGS72_UTM_zone_25S"},
+ {32326, "PCS_WGS72_UTM_zone_26S"},
+ {32327, "PCS_WGS72_UTM_zone_27S"},
+ {32328, "PCS_WGS72_UTM_zone_28S"},
+ {32329, "PCS_WGS72_UTM_zone_29S"},
+ {32330, "PCS_WGS72_UTM_zone_30S"},
+ {32331, "PCS_WGS72_UTM_zone_31S"},
+ {32332, "PCS_WGS72_UTM_zone_32S"},
+ {32333, "PCS_WGS72_UTM_zone_33S"},
+ {32334, "PCS_WGS72_UTM_zone_34S"},
+ {32335, "PCS_WGS72_UTM_zone_35S"},
+ {32336, "PCS_WGS72_UTM_zone_36S"},
+ {32337, "PCS_WGS72_UTM_zone_37S"},
+ {32338, "PCS_WGS72_UTM_zone_38S"},
+ {32339, "PCS_WGS72_UTM_zone_39S"},
+ {32340, "PCS_WGS72_UTM_zone_40S"},
+ {32341, "PCS_WGS72_UTM_zone_41S"},
+ {32342, "PCS_WGS72_UTM_zone_42S"},
+ {32343, "PCS_WGS72_UTM_zone_43S"},
+ {32344, "PCS_WGS72_UTM_zone_44S"},
+ {32345, "PCS_WGS72_UTM_zone_45S"},
+ {32346, "PCS_WGS72_UTM_zone_46S"},
+ {32347, "PCS_WGS72_UTM_zone_47S"},
+ {32348, "PCS_WGS72_UTM_zone_48S"},
+ {32349, "PCS_WGS72_UTM_zone_49S"},
+ {32350, "PCS_WGS72_UTM_zone_50S"},
+ {32351, "PCS_WGS72_UTM_zone_51S"},
+ {32352, "PCS_WGS72_UTM_zone_52S"},
+ {32353, "PCS_WGS72_UTM_zone_53S"},
+ {32354, "PCS_WGS72_UTM_zone_54S"},
+ {32355, "PCS_WGS72_UTM_zone_55S"},
+ {32356, "PCS_WGS72_UTM_zone_56S"},
+ {32357, "PCS_WGS72_UTM_zone_57S"},
+ {32358, "PCS_WGS72_UTM_zone_58S"},
+ {32359, "PCS_WGS72_UTM_zone_59S"},
+ {32360, "PCS_WGS72_UTM_zone_60S"},
+ {32401, "PCS_WGS72BE_UTM_zone_1N"},
+ {32402, "PCS_WGS72BE_UTM_zone_2N"},
+ {32403, "PCS_WGS72BE_UTM_zone_3N"},
+ {32404, "PCS_WGS72BE_UTM_zone_4N"},
+ {32405, "PCS_WGS72BE_UTM_zone_5N"},
+ {32406, "PCS_WGS72BE_UTM_zone_6N"},
+ {32407, "PCS_WGS72BE_UTM_zone_7N"},
+ {32408, "PCS_WGS72BE_UTM_zone_8N"},
+ {32409, "PCS_WGS72BE_UTM_zone_9N"},
+ {32410, "PCS_WGS72BE_UTM_zone_10N"},
+ {32411, "PCS_WGS72BE_UTM_zone_11N"},
+ {32412, "PCS_WGS72BE_UTM_zone_12N"},
+ {32413, "PCS_WGS72BE_UTM_zone_13N"},
+ {32414, "PCS_WGS72BE_UTM_zone_14N"},
+ {32415, "PCS_WGS72BE_UTM_zone_15N"},
+ {32416, "PCS_WGS72BE_UTM_zone_16N"},
+ {32417, "PCS_WGS72BE_UTM_zone_17N"},
+ {32418, "PCS_WGS72BE_UTM_zone_18N"},
+ {32419, "PCS_WGS72BE_UTM_zone_19N"},
+ {32420, "PCS_WGS72BE_UTM_zone_20N"},
+ {32421, "PCS_WGS72BE_UTM_zone_21N"},
+ {32422, "PCS_WGS72BE_UTM_zone_22N"},
+ {32423, "PCS_WGS72BE_UTM_zone_23N"},
+ {32424, "PCS_WGS72BE_UTM_zone_24N"},
+ {32425, "PCS_WGS72BE_UTM_zone_25N"},
+ {32426, "PCS_WGS72BE_UTM_zone_26N"},
+ {32427, "PCS_WGS72BE_UTM_zone_27N"},
+ {32428, "PCS_WGS72BE_UTM_zone_28N"},
+ {32429, "PCS_WGS72BE_UTM_zone_29N"},
+ {32430, "PCS_WGS72BE_UTM_zone_30N"},
+ {32431, "PCS_WGS72BE_UTM_zone_31N"},
+ {32432, "PCS_WGS72BE_UTM_zone_32N"},
+ {32433, "PCS_WGS72BE_UTM_zone_33N"},
+ {32434, "PCS_WGS72BE_UTM_zone_34N"},
+ {32435, "PCS_WGS72BE_UTM_zone_35N"},
+ {32436, "PCS_WGS72BE_UTM_zone_36N"},
+ {32437, "PCS_WGS72BE_UTM_zone_37N"},
+ {32438, "PCS_WGS72BE_UTM_zone_38N"},
+ {32439, "PCS_WGS72BE_UTM_zone_39N"},
+ {32440, "PCS_WGS72BE_UTM_zone_40N"},
+ {32441, "PCS_WGS72BE_UTM_zone_41N"},
+ {32442, "PCS_WGS72BE_UTM_zone_42N"},
+ {32443, "PCS_WGS72BE_UTM_zone_43N"},
+ {32444, "PCS_WGS72BE_UTM_zone_44N"},
+ {32445, "PCS_WGS72BE_UTM_zone_45N"},
+ {32446, "PCS_WGS72BE_UTM_zone_46N"},
+ {32447, "PCS_WGS72BE_UTM_zone_47N"},
+ {32448, "PCS_WGS72BE_UTM_zone_48N"},
+ {32449, "PCS_WGS72BE_UTM_zone_49N"},
+ {32450, "PCS_WGS72BE_UTM_zone_50N"},
+ {32451, "PCS_WGS72BE_UTM_zone_51N"},
+ {32452, "PCS_WGS72BE_UTM_zone_52N"},
+ {32453, "PCS_WGS72BE_UTM_zone_53N"},
+ {32454, "PCS_WGS72BE_UTM_zone_54N"},
+ {32455, "PCS_WGS72BE_UTM_zone_55N"},
+ {32456, "PCS_WGS72BE_UTM_zone_56N"},
+ {32457, "PCS_WGS72BE_UTM_zone_57N"},
+ {32458, "PCS_WGS72BE_UTM_zone_58N"},
+ {32459, "PCS_WGS72BE_UTM_zone_59N"},
+ {32460, "PCS_WGS72BE_UTM_zone_60N"},
+ {32501, "PCS_WGS72BE_UTM_zone_1S"},
+ {32502, "PCS_WGS72BE_UTM_zone_2S"},
+ {32503, "PCS_WGS72BE_UTM_zone_3S"},
+ {32504, "PCS_WGS72BE_UTM_zone_4S"},
+ {32505, "PCS_WGS72BE_UTM_zone_5S"},
+ {32506, "PCS_WGS72BE_UTM_zone_6S"},
+ {32507, "PCS_WGS72BE_UTM_zone_7S"},
+ {32508, "PCS_WGS72BE_UTM_zone_8S"},
+ {32509, "PCS_WGS72BE_UTM_zone_9S"},
+ {32510, "PCS_WGS72BE_UTM_zone_10S"},
+ {32511, "PCS_WGS72BE_UTM_zone_11S"},
+ {32512, "PCS_WGS72BE_UTM_zone_12S"},
+ {32513, "PCS_WGS72BE_UTM_zone_13S"},
+ {32514, "PCS_WGS72BE_UTM_zone_14S"},
+ {32515, "PCS_WGS72BE_UTM_zone_15S"},
+ {32516, "PCS_WGS72BE_UTM_zone_16S"},
+ {32517, "PCS_WGS72BE_UTM_zone_17S"},
+ {32518, "PCS_WGS72BE_UTM_zone_18S"},
+ {32519, "PCS_WGS72BE_UTM_zone_19S"},
+ {32520, "PCS_WGS72BE_UTM_zone_20S"},
+ {32521, "PCS_WGS72BE_UTM_zone_21S"},
+ {32522, "PCS_WGS72BE_UTM_zone_22S"},
+ {32523, "PCS_WGS72BE_UTM_zone_23S"},
+ {32524, "PCS_WGS72BE_UTM_zone_24S"},
+ {32525, "PCS_WGS72BE_UTM_zone_25S"},
+ {32526, "PCS_WGS72BE_UTM_zone_26S"},
+ {32527, "PCS_WGS72BE_UTM_zone_27S"},
+ {32528, "PCS_WGS72BE_UTM_zone_28S"},
+ {32529, "PCS_WGS72BE_UTM_zone_29S"},
+ {32530, "PCS_WGS72BE_UTM_zone_30S"},
+ {32531, "PCS_WGS72BE_UTM_zone_31S"},
+ {32532, "PCS_WGS72BE_UTM_zone_32S"},
+ {32533, "PCS_WGS72BE_UTM_zone_33S"},
+ {32534, "PCS_WGS72BE_UTM_zone_34S"},
+ {32535, "PCS_WGS72BE_UTM_zone_35S"},
+ {32536, "PCS_WGS72BE_UTM_zone_36S"},
+ {32537, "PCS_WGS72BE_UTM_zone_37S"},
+ {32538, "PCS_WGS72BE_UTM_zone_38S"},
+ {32539, "PCS_WGS72BE_UTM_zone_39S"},
+ {32540, "PCS_WGS72BE_UTM_zone_40S"},
+ {32541, "PCS_WGS72BE_UTM_zone_41S"},
+ {32542, "PCS_WGS72BE_UTM_zone_42S"},
+ {32543, "PCS_WGS72BE_UTM_zone_43S"},
+ {32544, "PCS_WGS72BE_UTM_zone_44S"},
+ {32545, "PCS_WGS72BE_UTM_zone_45S"},
+ {32546, "PCS_WGS72BE_UTM_zone_46S"},
+ {32547, "PCS_WGS72BE_UTM_zone_47S"},
+ {32548, "PCS_WGS72BE_UTM_zone_48S"},
+ {32549, "PCS_WGS72BE_UTM_zone_49S"},
+ {32550, "PCS_WGS72BE_UTM_zone_50S"},
+ {32551, "PCS_WGS72BE_UTM_zone_51S"},
+ {32552, "PCS_WGS72BE_UTM_zone_52S"},
+ {32553, "PCS_WGS72BE_UTM_zone_53S"},
+ {32554, "PCS_WGS72BE_UTM_zone_54S"},
+ {32555, "PCS_WGS72BE_UTM_zone_55S"},
+ {32556, "PCS_WGS72BE_UTM_zone_56S"},
+ {32557, "PCS_WGS72BE_UTM_zone_57S"},
+ {32558, "PCS_WGS72BE_UTM_zone_58S"},
+ {32559, "PCS_WGS72BE_UTM_zone_59S"},
+ {32560, "PCS_WGS72BE_UTM_zone_60S"},
+ {32601, "PCS_WGS84_UTM_zone_1N"},
+ {32602, "PCS_WGS84_UTM_zone_2N"},
+ {32603, "PCS_WGS84_UTM_zone_3N"},
+ {32604, "PCS_WGS84_UTM_zone_4N"},
+ {32605, "PCS_WGS84_UTM_zone_5N"},
+ {32606, "PCS_WGS84_UTM_zone_6N"},
+ {32607, "PCS_WGS84_UTM_zone_7N"},
+ {32608, "PCS_WGS84_UTM_zone_8N"},
+ {32609, "PCS_WGS84_UTM_zone_9N"},
+ {32610, "PCS_WGS84_UTM_zone_10N"},
+ {32611, "PCS_WGS84_UTM_zone_11N"},
+ {32612, "PCS_WGS84_UTM_zone_12N"},
+ {32613, "PCS_WGS84_UTM_zone_13N"},
+ {32614, "PCS_WGS84_UTM_zone_14N"},
+ {32615, "PCS_WGS84_UTM_zone_15N"},
+ {32616, "PCS_WGS84_UTM_zone_16N"},
+ {32617, "PCS_WGS84_UTM_zone_17N"},
+ {32618, "PCS_WGS84_UTM_zone_18N"},
+ {32619, "PCS_WGS84_UTM_zone_19N"},
+ {32620, "PCS_WGS84_UTM_zone_20N"},
+ {32621, "PCS_WGS84_UTM_zone_21N"},
+ {32622, "PCS_WGS84_UTM_zone_22N"},
+ {32623, "PCS_WGS84_UTM_zone_23N"},
+ {32624, "PCS_WGS84_UTM_zone_24N"},
+ {32625, "PCS_WGS84_UTM_zone_25N"},
+ {32626, "PCS_WGS84_UTM_zone_26N"},
+ {32627, "PCS_WGS84_UTM_zone_27N"},
+ {32628, "PCS_WGS84_UTM_zone_28N"},
+ {32629, "PCS_WGS84_UTM_zone_29N"},
+ {32630, "PCS_WGS84_UTM_zone_30N"},
+ {32631, "PCS_WGS84_UTM_zone_31N"},
+ {32632, "PCS_WGS84_UTM_zone_32N"},
+ {32633, "PCS_WGS84_UTM_zone_33N"},
+ {32634, "PCS_WGS84_UTM_zone_34N"},
+ {32635, "PCS_WGS84_UTM_zone_35N"},
+ {32636, "PCS_WGS84_UTM_zone_36N"},
+ {32637, "PCS_WGS84_UTM_zone_37N"},
+ {32638, "PCS_WGS84_UTM_zone_38N"},
+ {32639, "PCS_WGS84_UTM_zone_39N"},
+ {32640, "PCS_WGS84_UTM_zone_40N"},
+ {32641, "PCS_WGS84_UTM_zone_41N"},
+ {32642, "PCS_WGS84_UTM_zone_42N"},
+ {32643, "PCS_WGS84_UTM_zone_43N"},
+ {32644, "PCS_WGS84_UTM_zone_44N"},
+ {32645, "PCS_WGS84_UTM_zone_45N"},
+ {32646, "PCS_WGS84_UTM_zone_46N"},
+ {32647, "PCS_WGS84_UTM_zone_47N"},
+ {32648, "PCS_WGS84_UTM_zone_48N"},
+ {32649, "PCS_WGS84_UTM_zone_49N"},
+ {32650, "PCS_WGS84_UTM_zone_50N"},
+ {32651, "PCS_WGS84_UTM_zone_51N"},
+ {32652, "PCS_WGS84_UTM_zone_52N"},
+ {32653, "PCS_WGS84_UTM_zone_53N"},
+ {32654, "PCS_WGS84_UTM_zone_54N"},
+ {32655, "PCS_WGS84_UTM_zone_55N"},
+ {32656, "PCS_WGS84_UTM_zone_56N"},
+ {32657, "PCS_WGS84_UTM_zone_57N"},
+ {32658, "PCS_WGS84_UTM_zone_58N"},
+ {32659, "PCS_WGS84_UTM_zone_59N"},
+ {32660, "PCS_WGS84_UTM_zone_60N"},
+ {32701, "PCS_WGS84_UTM_zone_1S"},
+ {32702, "PCS_WGS84_UTM_zone_2S"},
+ {32703, "PCS_WGS84_UTM_zone_3S"},
+ {32704, "PCS_WGS84_UTM_zone_4S"},
+ {32705, "PCS_WGS84_UTM_zone_5S"},
+ {32706, "PCS_WGS84_UTM_zone_6S"},
+ {32707, "PCS_WGS84_UTM_zone_7S"},
+ {32708, "PCS_WGS84_UTM_zone_8S"},
+ {32709, "PCS_WGS84_UTM_zone_9S"},
+ {32710, "PCS_WGS84_UTM_zone_10S"},
+ {32711, "PCS_WGS84_UTM_zone_11S"},
+ {32712, "PCS_WGS84_UTM_zone_12S"},
+ {32713, "PCS_WGS84_UTM_zone_13S"},
+ {32714, "PCS_WGS84_UTM_zone_14S"},
+ {32715, "PCS_WGS84_UTM_zone_15S"},
+ {32716, "PCS_WGS84_UTM_zone_16S"},
+ {32717, "PCS_WGS84_UTM_zone_17S"},
+ {32718, "PCS_WGS84_UTM_zone_18S"},
+ {32719, "PCS_WGS84_UTM_zone_19S"},
+ {32720, "PCS_WGS84_UTM_zone_20S"},
+ {32721, "PCS_WGS84_UTM_zone_21S"},
+ {32722, "PCS_WGS84_UTM_zone_22S"},
+ {32723, "PCS_WGS84_UTM_zone_23S"},
+ {32724, "PCS_WGS84_UTM_zone_24S"},
+ {32725, "PCS_WGS84_UTM_zone_25S"},
+ {32726, "PCS_WGS84_UTM_zone_26S"},
+ {32727, "PCS_WGS84_UTM_zone_27S"},
+ {32728, "PCS_WGS84_UTM_zone_28S"},
+ {32729, "PCS_WGS84_UTM_zone_29S"},
+ {32730, "PCS_WGS84_UTM_zone_30S"},
+ {32731, "PCS_WGS84_UTM_zone_31S"},
+ {32732, "PCS_WGS84_UTM_zone_32S"},
+ {32733, "PCS_WGS84_UTM_zone_33S"},
+ {32734, "PCS_WGS84_UTM_zone_34S"},
+ {32735, "PCS_WGS84_UTM_zone_35S"},
+ {32736, "PCS_WGS84_UTM_zone_36S"},
+ {32737, "PCS_WGS84_UTM_zone_37S"},
+ {32738, "PCS_WGS84_UTM_zone_38S"},
+ {32739, "PCS_WGS84_UTM_zone_39S"},
+ {32740, "PCS_WGS84_UTM_zone_40S"},
+ {32741, "PCS_WGS84_UTM_zone_41S"},
+ {32742, "PCS_WGS84_UTM_zone_42S"},
+ {32743, "PCS_WGS84_UTM_zone_43S"},
+ {32744, "PCS_WGS84_UTM_zone_44S"},
+ {32745, "PCS_WGS84_UTM_zone_45S"},
+ {32746, "PCS_WGS84_UTM_zone_46S"},
+ {32747, "PCS_WGS84_UTM_zone_47S"},
+ {32748, "PCS_WGS84_UTM_zone_48S"},
+ {32749, "PCS_WGS84_UTM_zone_49S"},
+ {32750, "PCS_WGS84_UTM_zone_50S"},
+ {32751, "PCS_WGS84_UTM_zone_51S"},
+ {32752, "PCS_WGS84_UTM_zone_52S"},
+ {32753, "PCS_WGS84_UTM_zone_53S"},
+ {32754, "PCS_WGS84_UTM_zone_54S"},
+ {32755, "PCS_WGS84_UTM_zone_55S"},
+ {32756, "PCS_WGS84_UTM_zone_56S"},
+ {32757, "PCS_WGS84_UTM_zone_57S"},
+ {32758, "PCS_WGS84_UTM_zone_58S"},
+ {32759, "PCS_WGS84_UTM_zone_59S"},
+ {32760, "PCS_WGS84_UTM_zone_60S"}
+};
+
+const TiffGeoTagKeyName ff_tiff_projection_codes[] = {
+ {10101, "Proj_Alabama_CS27_East"},
+ {10102, "Proj_Alabama_CS27_West"},
+ {10131, "Proj_Alabama_CS83_East"},
+ {10132, "Proj_Alabama_CS83_West"},
+ {10201, "Proj_Arizona_Coordinate_System_east"},
+ {10202, "Proj_Arizona_Coordinate_System_Central"},
+ {10203, "Proj_Arizona_Coordinate_System_west"},
+ {10231, "Proj_Arizona_CS83_east"},
+ {10232, "Proj_Arizona_CS83_Central"},
+ {10233, "Proj_Arizona_CS83_west"},
+ {10301, "Proj_Arkansas_CS27_North"},
+ {10302, "Proj_Arkansas_CS27_South"},
+ {10331, "Proj_Arkansas_CS83_North"},
+ {10332, "Proj_Arkansas_CS83_South"},
+ {10401, "Proj_California_CS27_I"},
+ {10402, "Proj_California_CS27_II"},
+ {10403, "Proj_California_CS27_III"},
+ {10404, "Proj_California_CS27_IV"},
+ {10405, "Proj_California_CS27_V"},
+ {10406, "Proj_California_CS27_VI"},
+ {10407, "Proj_California_CS27_VII"},
+ {10431, "Proj_California_CS83_1"},
+ {10432, "Proj_California_CS83_2"},
+ {10433, "Proj_California_CS83_3"},
+ {10434, "Proj_California_CS83_4"},
+ {10435, "Proj_California_CS83_5"},
+ {10436, "Proj_California_CS83_6"},
+ {10501, "Proj_Colorado_CS27_North"},
+ {10502, "Proj_Colorado_CS27_Central"},
+ {10503, "Proj_Colorado_CS27_South"},
+ {10531, "Proj_Colorado_CS83_North"},
+ {10532, "Proj_Colorado_CS83_Central"},
+ {10533, "Proj_Colorado_CS83_South"},
+ {10600, "Proj_Connecticut_CS27"},
+ {10630, "Proj_Connecticut_CS83"},
+ {10700, "Proj_Delaware_CS27"},
+ {10730, "Proj_Delaware_CS83"},
+ {10901, "Proj_Florida_CS27_East"},
+ {10902, "Proj_Florida_CS27_West"},
+ {10903, "Proj_Florida_CS27_North"},
+ {10931, "Proj_Florida_CS83_East"},
+ {10932, "Proj_Florida_CS83_West"},
+ {10933, "Proj_Florida_CS83_North"},
+ {11001, "Proj_Georgia_CS27_East"},
+ {11002, "Proj_Georgia_CS27_West"},
+ {11031, "Proj_Georgia_CS83_East"},
+ {11032, "Proj_Georgia_CS83_West"},
+ {11101, "Proj_Idaho_CS27_East"},
+ {11102, "Proj_Idaho_CS27_Central"},
+ {11103, "Proj_Idaho_CS27_West"},
+ {11131, "Proj_Idaho_CS83_East"},
+ {11132, "Proj_Idaho_CS83_Central"},
+ {11133, "Proj_Idaho_CS83_West"},
+ {11201, "Proj_Illinois_CS27_East"},
+ {11202, "Proj_Illinois_CS27_West"},
+ {11231, "Proj_Illinois_CS83_East"},
+ {11232, "Proj_Illinois_CS83_West"},
+ {11301, "Proj_Indiana_CS27_East"},
+ {11302, "Proj_Indiana_CS27_West"},
+ {11331, "Proj_Indiana_CS83_East"},
+ {11332, "Proj_Indiana_CS83_West"},
+ {11401, "Proj_Iowa_CS27_North"},
+ {11402, "Proj_Iowa_CS27_South"},
+ {11431, "Proj_Iowa_CS83_North"},
+ {11432, "Proj_Iowa_CS83_South"},
+ {11501, "Proj_Kansas_CS27_North"},
+ {11502, "Proj_Kansas_CS27_South"},
+ {11531, "Proj_Kansas_CS83_North"},
+ {11532, "Proj_Kansas_CS83_South"},
+ {11601, "Proj_Kentucky_CS27_North"},
+ {11602, "Proj_Kentucky_CS27_South"},
+ {11631, "Proj_Kentucky_CS83_North"},
+ {11632, "Proj_Kentucky_CS83_South"},
+ {11701, "Proj_Louisiana_CS27_North"},
+ {11702, "Proj_Louisiana_CS27_South"},
+ {11731, "Proj_Louisiana_CS83_North"},
+ {11732, "Proj_Louisiana_CS83_South"},
+ {11801, "Proj_Maine_CS27_East"},
+ {11802, "Proj_Maine_CS27_West"},
+ {11831, "Proj_Maine_CS83_East"},
+ {11832, "Proj_Maine_CS83_West"},
+ {11900, "Proj_Maryland_CS27"},
+ {11930, "Proj_Maryland_CS83"},
+ {12001, "Proj_Massachusetts_CS27_Mainland"},
+ {12002, "Proj_Massachusetts_CS27_Island"},
+ {12031, "Proj_Massachusetts_CS83_Mainland"},
+ {12032, "Proj_Massachusetts_CS83_Island"},
+ {12101, "Proj_Michigan_State_Plane_East"},
+ {12102, "Proj_Michigan_State_Plane_Old_Central"},
+ {12103, "Proj_Michigan_State_Plane_West"},
+ {12111, "Proj_Michigan_CS27_North"},
+ {12112, "Proj_Michigan_CS27_Central"},
+ {12113, "Proj_Michigan_CS27_South"},
+ {12141, "Proj_Michigan_CS83_North"},
+ {12142, "Proj_Michigan_CS83_Central"},
+ {12143, "Proj_Michigan_CS83_South"},
+ {12201, "Proj_Minnesota_CS27_North"},
+ {12202, "Proj_Minnesota_CS27_Central"},
+ {12203, "Proj_Minnesota_CS27_South"},
+ {12231, "Proj_Minnesota_CS83_North"},
+ {12232, "Proj_Minnesota_CS83_Central"},
+ {12233, "Proj_Minnesota_CS83_South"},
+ {12301, "Proj_Mississippi_CS27_East"},
+ {12302, "Proj_Mississippi_CS27_West"},
+ {12331, "Proj_Mississippi_CS83_East"},
+ {12332, "Proj_Mississippi_CS83_West"},
+ {12401, "Proj_Missouri_CS27_East"},
+ {12402, "Proj_Missouri_CS27_Central"},
+ {12403, "Proj_Missouri_CS27_West"},
+ {12431, "Proj_Missouri_CS83_East"},
+ {12432, "Proj_Missouri_CS83_Central"},
+ {12433, "Proj_Missouri_CS83_West"},
+ {12501, "Proj_Montana_CS27_North"},
+ {12502, "Proj_Montana_CS27_Central"},
+ {12503, "Proj_Montana_CS27_South"},
+ {12530, "Proj_Montana_CS83"},
+ {12601, "Proj_Nebraska_CS27_North"},
+ {12602, "Proj_Nebraska_CS27_South"},
+ {12630, "Proj_Nebraska_CS83"},
+ {12701, "Proj_Nevada_CS27_East"},
+ {12702, "Proj_Nevada_CS27_Central"},
+ {12703, "Proj_Nevada_CS27_West"},
+ {12731, "Proj_Nevada_CS83_East"},
+ {12732, "Proj_Nevada_CS83_Central"},
+ {12733, "Proj_Nevada_CS83_West"},
+ {12800, "Proj_New_Hampshire_CS27"},
+ {12830, "Proj_New_Hampshire_CS83"},
+ {12900, "Proj_New_Jersey_CS27"},
+ {12930, "Proj_New_Jersey_CS83"},
+ {13001, "Proj_New_Mexico_CS27_East"},
+ {13002, "Proj_New_Mexico_CS27_Central"},
+ {13003, "Proj_New_Mexico_CS27_West"},
+ {13031, "Proj_New_Mexico_CS83_East"},
+ {13032, "Proj_New_Mexico_CS83_Central"},
+ {13033, "Proj_New_Mexico_CS83_West"},
+ {13101, "Proj_New_York_CS27_East"},
+ {13102, "Proj_New_York_CS27_Central"},
+ {13103, "Proj_New_York_CS27_West"},
+ {13104, "Proj_New_York_CS27_Long_Island"},
+ {13131, "Proj_New_York_CS83_East"},
+ {13132, "Proj_New_York_CS83_Central"},
+ {13133, "Proj_New_York_CS83_West"},
+ {13134, "Proj_New_York_CS83_Long_Island"},
+ {13200, "Proj_North_Carolina_CS27"},
+ {13230, "Proj_North_Carolina_CS83"},
+ {13301, "Proj_North_Dakota_CS27_North"},
+ {13302, "Proj_North_Dakota_CS27_South"},
+ {13331, "Proj_North_Dakota_CS83_North"},
+ {13332, "Proj_North_Dakota_CS83_South"},
+ {13401, "Proj_Ohio_CS27_North"},
+ {13402, "Proj_Ohio_CS27_South"},
+ {13431, "Proj_Ohio_CS83_North"},
+ {13432, "Proj_Ohio_CS83_South"},
+ {13501, "Proj_Oklahoma_CS27_North"},
+ {13502, "Proj_Oklahoma_CS27_South"},
+ {13531, "Proj_Oklahoma_CS83_North"},
+ {13532, "Proj_Oklahoma_CS83_South"},
+ {13601, "Proj_Oregon_CS27_North"},
+ {13602, "Proj_Oregon_CS27_South"},
+ {13631, "Proj_Oregon_CS83_North"},
+ {13632, "Proj_Oregon_CS83_South"},
+ {13701, "Proj_Pennsylvania_CS27_North"},
+ {13702, "Proj_Pennsylvania_CS27_South"},
+ {13731, "Proj_Pennsylvania_CS83_North"},
+ {13732, "Proj_Pennsylvania_CS83_South"},
+ {13800, "Proj_Rhode_Island_CS27"},
+ {13830, "Proj_Rhode_Island_CS83"},
+ {13901, "Proj_South_Carolina_CS27_North"},
+ {13902, "Proj_South_Carolina_CS27_South"},
+ {13930, "Proj_South_Carolina_CS83"},
+ {14001, "Proj_South_Dakota_CS27_North"},
+ {14002, "Proj_South_Dakota_CS27_South"},
+ {14031, "Proj_South_Dakota_CS83_North"},
+ {14032, "Proj_South_Dakota_CS83_South"},
+ {14100, "Proj_Tennessee_CS27"},
+ {14130, "Proj_Tennessee_CS83"},
+ {14201, "Proj_Texas_CS27_North"},
+ {14202, "Proj_Texas_CS27_North_Central"},
+ {14203, "Proj_Texas_CS27_Central"},
+ {14204, "Proj_Texas_CS27_South_Central"},
+ {14205, "Proj_Texas_CS27_South"},
+ {14231, "Proj_Texas_CS83_North"},
+ {14232, "Proj_Texas_CS83_North_Central"},
+ {14233, "Proj_Texas_CS83_Central"},
+ {14234, "Proj_Texas_CS83_South_Central"},
+ {14235, "Proj_Texas_CS83_South"},
+ {14301, "Proj_Utah_CS27_North"},
+ {14302, "Proj_Utah_CS27_Central"},
+ {14303, "Proj_Utah_CS27_South"},
+ {14331, "Proj_Utah_CS83_North"},
+ {14332, "Proj_Utah_CS83_Central"},
+ {14333, "Proj_Utah_CS83_South"},
+ {14400, "Proj_Vermont_CS27"},
+ {14430, "Proj_Vermont_CS83"},
+ {14501, "Proj_Virginia_CS27_North"},
+ {14502, "Proj_Virginia_CS27_South"},
+ {14531, "Proj_Virginia_CS83_North"},
+ {14532, "Proj_Virginia_CS83_South"},
+ {14601, "Proj_Washington_CS27_North"},
+ {14602, "Proj_Washington_CS27_South"},
+ {14631, "Proj_Washington_CS83_North"},
+ {14632, "Proj_Washington_CS83_South"},
+ {14701, "Proj_West_Virginia_CS27_North"},
+ {14702, "Proj_West_Virginia_CS27_South"},
+ {14731, "Proj_West_Virginia_CS83_North"},
+ {14732, "Proj_West_Virginia_CS83_South"},
+ {14801, "Proj_Wisconsin_CS27_North"},
+ {14802, "Proj_Wisconsin_CS27_Central"},
+ {14803, "Proj_Wisconsin_CS27_South"},
+ {14831, "Proj_Wisconsin_CS83_North"},
+ {14832, "Proj_Wisconsin_CS83_Central"},
+ {14833, "Proj_Wisconsin_CS83_South"},
+ {14901, "Proj_Wyoming_CS27_East"},
+ {14902, "Proj_Wyoming_CS27_East_Central"},
+ {14903, "Proj_Wyoming_CS27_West_Central"},
+ {14904, "Proj_Wyoming_CS27_West"},
+ {14931, "Proj_Wyoming_CS83_East"},
+ {14932, "Proj_Wyoming_CS83_East_Central"},
+ {14933, "Proj_Wyoming_CS83_West_Central"},
+ {14934, "Proj_Wyoming_CS83_West"},
+ {15001, "Proj_Alaska_CS27_1"},
+ {15002, "Proj_Alaska_CS27_2"},
+ {15003, "Proj_Alaska_CS27_3"},
+ {15004, "Proj_Alaska_CS27_4"},
+ {15005, "Proj_Alaska_CS27_5"},
+ {15006, "Proj_Alaska_CS27_6"},
+ {15007, "Proj_Alaska_CS27_7"},
+ {15008, "Proj_Alaska_CS27_8"},
+ {15009, "Proj_Alaska_CS27_9"},
+ {15010, "Proj_Alaska_CS27_10"},
+ {15031, "Proj_Alaska_CS83_1"},
+ {15032, "Proj_Alaska_CS83_2"},
+ {15033, "Proj_Alaska_CS83_3"},
+ {15034, "Proj_Alaska_CS83_4"},
+ {15035, "Proj_Alaska_CS83_5"},
+ {15036, "Proj_Alaska_CS83_6"},
+ {15037, "Proj_Alaska_CS83_7"},
+ {15038, "Proj_Alaska_CS83_8"},
+ {15039, "Proj_Alaska_CS83_9"},
+ {15040, "Proj_Alaska_CS83_10"},
+ {15101, "Proj_Hawaii_CS27_1"},
+ {15102, "Proj_Hawaii_CS27_2"},
+ {15103, "Proj_Hawaii_CS27_3"},
+ {15104, "Proj_Hawaii_CS27_4"},
+ {15105, "Proj_Hawaii_CS27_5"},
+ {15131, "Proj_Hawaii_CS83_1"},
+ {15132, "Proj_Hawaii_CS83_2"},
+ {15133, "Proj_Hawaii_CS83_3"},
+ {15134, "Proj_Hawaii_CS83_4"},
+ {15135, "Proj_Hawaii_CS83_5"},
+ {15201, "Proj_Puerto_Rico_CS27"},
+ {15202, "Proj_St_Croix"},
+ {15230, "Proj_Puerto_Rico_Virgin_Is"},
+ {15914, "Proj_BLM_14N_feet"},
+ {15915, "Proj_BLM_15N_feet"},
+ {15916, "Proj_BLM_16N_feet"},
+ {15917, "Proj_BLM_17N_feet"},
+ {17348, "Proj_Map_Grid_of_Australia_48"},
+ {17349, "Proj_Map_Grid_of_Australia_49"},
+ {17350, "Proj_Map_Grid_of_Australia_50"},
+ {17351, "Proj_Map_Grid_of_Australia_51"},
+ {17352, "Proj_Map_Grid_of_Australia_52"},
+ {17353, "Proj_Map_Grid_of_Australia_53"},
+ {17354, "Proj_Map_Grid_of_Australia_54"},
+ {17355, "Proj_Map_Grid_of_Australia_55"},
+ {17356, "Proj_Map_Grid_of_Australia_56"},
+ {17357, "Proj_Map_Grid_of_Australia_57"},
+ {17358, "Proj_Map_Grid_of_Australia_58"},
+ {17448, "Proj_Australian_Map_Grid_48"},
+ {17449, "Proj_Australian_Map_Grid_49"},
+ {17450, "Proj_Australian_Map_Grid_50"},
+ {17451, "Proj_Australian_Map_Grid_51"},
+ {17452, "Proj_Australian_Map_Grid_52"},
+ {17453, "Proj_Australian_Map_Grid_53"},
+ {17454, "Proj_Australian_Map_Grid_54"},
+ {17455, "Proj_Australian_Map_Grid_55"},
+ {17456, "Proj_Australian_Map_Grid_56"},
+ {17457, "Proj_Australian_Map_Grid_57"},
+ {17458, "Proj_Australian_Map_Grid_58"},
+ {18031, "Proj_Argentina_1"},
+ {18032, "Proj_Argentina_2"},
+ {18033, "Proj_Argentina_3"},
+ {18034, "Proj_Argentina_4"},
+ {18035, "Proj_Argentina_5"},
+ {18036, "Proj_Argentina_6"},
+ {18037, "Proj_Argentina_7"},
+ {18051, "Proj_Colombia_3W"},
+ {18052, "Proj_Colombia_Bogota"},
+ {18053, "Proj_Colombia_3E"},
+ {18054, "Proj_Colombia_6E"},
+ {18072, "Proj_Egypt_Red_Belt"},
+ {18073, "Proj_Egypt_Purple_Belt"},
+ {18074, "Proj_Extended_Purple_Belt"},
+ {18141, "Proj_New_Zealand_North_Island_Nat_Grid"},
+ {18142, "Proj_New_Zealand_South_Island_Nat_Grid"},
+ {19900, "Proj_Bahrain_Grid"},
+ {19905, "Proj_Netherlands_E_Indies_Equatorial"},
+ {19912, "Proj_RSO_Borneo"}
+};
+
+const char *const ff_tiff_coord_trans_codes[] = {
+ "CT_TransverseMercator",
+ "CT_TransvMercator_Modified_Alaska",
+ "CT_ObliqueMercator",
+ "CT_ObliqueMercator_Laborde",
+ "CT_ObliqueMercator_Rosenmund",
+ "CT_ObliqueMercator_Spherical",
+ "CT_Mercator",
+ "CT_LambertConfConic_2SP",
+ "CT_LambertConfConic_Helmert",
+ "CT_LambertAzimEqualArea",
+ "CT_AlbersEqualArea",
+ "CT_AzimuthalEquidistant",
+ "CT_EquidistantConic",
+ "CT_Stereographic",
+ "CT_PolarStereographic",
+ "CT_ObliqueStereographic",
+ "CT_Equirectangular",
+ "CT_CassiniSoldner",
+ "CT_Gnomonic",
+ "CT_MillerCylindrical",
+ "CT_Orthographic",
+ "CT_Polyconic",
+ "CT_Robinson",
+ "CT_Sinusoidal",
+ "CT_VanDerGrinten",
+ "CT_NewZealandMapGrid",
+ "CT_TransvMercator_SouthOriented"
+};
+
+const char *const ff_tiff_vert_cs_codes[] = {
+ "VertCS_Airy_1830_ellipsoid",
+ "VertCS_Airy_Modified_1849_ellipsoid",
+ "VertCS_ANS_ellipsoid",
+ "VertCS_Bessel_1841_ellipsoid",
+ "VertCS_Bessel_Modified_ellipsoid",
+ "VertCS_Bessel_Namibia_ellipsoid",
+ "VertCS_Clarke_1858_ellipsoid",
+ "VertCS_Clarke_1866_ellipsoid",
+ "VertCS_Clarke_1880_Benoit_ellipsoid",
+ "VertCS_Clarke_1880_IGN_ellipsoid",
+ "VertCS_Clarke_1880_RGS_ellipsoid",
+ "VertCS_Clarke_1880_Arc_ellipsoid",
+ "VertCS_Clarke_1880_SGA_1922_ellipsoid",
+ "VertCS_Everest_1830_1937_Adjustment_ellipsoid",
+ "VertCS_Everest_1830_1967_Definition_ellipsoid",
+ "VertCS_Everest_1830_1975_Definition_ellipsoid",
+ "VertCS_Everest_1830_Modified_ellipsoid",
+ "VertCS_GRS_1980_ellipsoid",
+ "VertCS_Helmert_1906_ellipsoid",
+ "VertCS_INS_ellipsoid",
+ "VertCS_International_1924_ellipsoid",
+ "VertCS_International_1967_ellipsoid",
+ "VertCS_Krassowsky_1940_ellipsoid",
+ "VertCS_NWL_9D_ellipsoid",
+ "VertCS_NWL_10D_ellipsoid",
+ "VertCS_Plessis_1817_ellipsoid",
+ "VertCS_Struve_1860_ellipsoid",
+ "VertCS_War_Office_ellipsoid",
+ "VertCS_WGS_84_ellipsoid",
+ "VertCS_GEM_10C_ellipsoid",
+ "VertCS_OSU86F_ellipsoid",
+ "VertCS_OSU91A_ellipsoid"
+};
+
+const char *const ff_tiff_ortho_vert_cs_codes[] = {
+ "VertCS_Newlyn",
+ "VertCS_North_American_Vertical_Datum_1929",
+ "VertCS_North_American_Vertical_Datum_1988",
+ "VertCS_Yellow_Sea_1956",
+ "VertCS_Baltic_Sea",
+ "VertCS_Caspian_Sea"
+};
diff --git a/libavcodec/tiff_data.h b/libavcodec/tiff_data.h
new file mode 100644
index 0000000000..57515f9030
--- /dev/null
+++ b/libavcodec/tiff_data.h
@@ -0,0 +1,92 @@
+/*
+ * TIFF data tables
+ * Copyright (c) 2011 Thomas Kuehnel
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * TIFF data tables
+ * @author Thomas Kuehnel
+ * @see GeoTIFF specification at
+ * http://www.remotesensing.org/geotiff/spec/geotiffhome.html
+ */
+
+#ifndef AVCODEC_TIFF_DATA_H
+#define AVCODEC_TIFF_DATA_H
+
+#include "tiff.h"
+
+#define TIFF_CONF_KEY_ID_OFFSET 1024
+extern const TiffGeoTagNameType ff_tiff_conf_name_type_map[3];
+
+#define TIFF_GEOG_KEY_ID_OFFSET 2048
+extern const TiffGeoTagNameType ff_tiff_geog_name_type_map[14];
+
+#define TIFF_PROJ_KEY_ID_OFFSET 3072
+extern const TiffGeoTagNameType ff_tiff_proj_name_type_map[24];
+
+#define TIFF_VERT_KEY_ID_OFFSET 4096
+extern const TiffGeoTagNameType ff_tiff_vert_name_type_map[4];
+
+#define TIFF_GEO_KEY_UNDEFINED 0
+#define TIFF_GEO_KEY_USER_DEFINED 32767
+
+#define TIFF_GT_MODEL_TYPE_OFFSET 1
+extern const char *const ff_tiff_gt_model_type_codes[3];
+
+#define TIFF_GT_RASTER_TYPE_OFFSET 1
+extern const char *const ff_tiff_gt_raster_type_codes[2];
+
+#define TIFF_LINEAR_UNIT_OFFSET 9001
+extern const char *const ff_tiff_linear_unit_codes[15];
+
+#define TIFF_ANGULAR_UNIT_OFFSET 9101
+extern const char *const ff_tiff_angular_unit_codes[8];
+
+#define TIFF_GCS_TYPE_OFFSET 4201
+extern const char *const ff_tiff_gcs_type_codes[133];
+
+#define TIFF_GCSE_TYPE_OFFSET 4001
+extern const char *const ff_tiff_gcse_type_codes[35];
+
+#define TIFF_GEODETIC_DATUM_OFFSET 6201
+extern const char *const ff_tiff_geodetic_datum_codes[120];
+
+#define TIFF_GEODETIC_DATUM_E_OFFSET 6001
+extern const char *const ff_tiff_geodetic_datum_e_codes[35];
+
+#define TIFF_ELLIPSOID_OFFSET 7001
+extern const char *const ff_tiff_ellipsoid_codes[35];
+
+#define TIFF_PRIME_MERIDIAN_OFFSET 8901
+extern const char *const ff_tiff_prime_meridian_codes[11];
+
+extern const TiffGeoTagKeyName ff_tiff_proj_cs_type_codes[978];
+
+extern const TiffGeoTagKeyName ff_tiff_projection_codes[298];
+
+#define TIFF_COORD_TRANS_OFFSET 1
+extern const char *const ff_tiff_coord_trans_codes[27];
+
+#define TIFF_VERT_CS_OFFSET 5001
+extern const char *const ff_tiff_vert_cs_codes[32];
+
+#define TIFF_ORTHO_VERT_CS_OFFSET 5101
+extern const char *const ff_tiff_ortho_vert_cs_codes[6];
+#endif
diff --git a/libavcodec/tiffenc.c b/libavcodec/tiffenc.c
index a020f5f61a..2cdac0b213 100644
--- a/libavcodec/tiffenc.c
+++ b/libavcodec/tiffenc.c
@@ -2,20 +2,20 @@
* TIFF image encoder
* Copyright (c) 2007 Bartlomiej Wolowiec
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,11 +30,13 @@
#include <zlib.h>
#endif
+#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "bytestream.h"
+#include "internal.h"
#include "lzw.h"
#include "put_bits.h"
#include "rle.h"
@@ -43,8 +45,8 @@
#define TIFF_MAX_ENTRY 32
/** sizes of various TIFF field types (string size = 1)*/
-static const uint8_t type_sizes2[6] = {
- 0, 1, 1, 2, 4, 8
+static const uint8_t type_sizes2[14] = {
+ 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4
};
typedef struct TiffEncoderContext {
@@ -58,6 +60,12 @@ typedef struct TiffEncoderContext {
int bpp_tab_size; ///< bpp_tab size
enum TiffPhotometric photometric_interpretation; ///< photometric interpretation
int strips; ///< number of strips
+ uint32_t *strip_sizes;
+ unsigned int strip_sizes_size;
+ uint32_t *strip_offsets;
+ unsigned int strip_offsets_size;
+ uint8_t *yuv_line;
+ unsigned int yuv_line_size;
int rps; ///< row per strip
uint8_t entries[TIFF_MAX_ENTRY * 12]; ///< entries in header
int num_entries; ///< number of entries
@@ -66,10 +74,12 @@ typedef struct TiffEncoderContext {
int buf_size; ///< buffer size
uint16_t subsampling[2]; ///< YUV subsampling factors
struct LZWEncodeState *lzws; ///< LZW encode state
+ uint32_t dpi; ///< image resolution in DPI
} TiffEncoderContext;
/**
- * Check free space in buffer
+ * Check free space in buffer.
+ *
* @param s Tiff context
* @param need Needed bytes
* @return 0 - ok, 1 - no free space
@@ -85,13 +95,13 @@ static inline int check_size(TiffEncoderContext *s, uint64_t need)
}
/**
- * Put n values to buffer
+ * Put n values to buffer.
*
- * @param p Pointer to pointer to output buffer
- * @param n Number of values
- * @param val Pointer to values
- * @param type Type of values
- * @param flip =0 - normal copy, >0 - flip
+ * @param p pointer to pointer to output buffer
+ * @param n number of values
+ * @param val pointer to values
+ * @param type type of values
+ * @param flip = 0 - normal copy, >0 - flip
*/
static void tnput(uint8_t **p, int n, const uint8_t *val, enum TiffTypes type,
int flip)
@@ -106,28 +116,29 @@ static void tnput(uint8_t **p, int n, const uint8_t *val, enum TiffTypes type,
/**
* Add entry to directory in tiff header.
+ *
* @param s Tiff context
- * @param tag Tag that identifies the entry
- * @param type Entry type
- * @param count The number of values
- * @param ptr_val Pointer to values
+ * @param tag tag that identifies the entry
+ * @param type entry type
+ * @param count the number of values
+ * @param ptr_val pointer to values
*/
static int add_entry(TiffEncoderContext *s, enum TiffTags tag,
enum TiffTypes type, int count, const void *ptr_val)
{
uint8_t *entries_ptr = s->entries + 12 * s->num_entries;
- assert(s->num_entries < TIFF_MAX_ENTRY);
+ av_assert0(s->num_entries < TIFF_MAX_ENTRY);
bytestream_put_le16(&entries_ptr, tag);
bytestream_put_le16(&entries_ptr, type);
bytestream_put_le32(&entries_ptr, count);
- if (type_sizes[type] * count <= 4) {
+ if (type_sizes[type] * (int64_t)count <= 4) {
tnput(&entries_ptr, count, ptr_val, type, 0);
} else {
bytestream_put_le32(&entries_ptr, *s->buf - s->buf_start);
- if (check_size(s, count * type_sizes2[type]))
+ if (check_size(s, count * (int64_t)type_sizes2[type]))
return AVERROR_INVALIDDATA;
tnput(s->buf, count, ptr_val, type, 0);
}
@@ -146,14 +157,14 @@ static int add_entry1(TiffEncoderContext *s,
}
/**
- * Encode one strip in tiff file
+ * Encode one strip in tiff file.
*
* @param s Tiff context
- * @param src Input buffer
- * @param dst Output buffer
- * @param n Size of input buffer
- * @param compr Compression method
- * @return Number of output bytes. If an output error is encountered, a negative
+ * @param src input buffer
+ * @param dst output buffer
+ * @param n size of input buffer
+ * @param compr compression method
+ * @return number of output bytes. If an output error is encountered, a negative
* value corresponding to an AVERROR error code is returned.
*/
static int encode_strip(TiffEncoderContext *s, const int8_t *src,
@@ -167,7 +178,7 @@ static int encode_strip(TiffEncoderContext *s, const int8_t *src,
unsigned long zlen = s->buf_size - (*s->buf - s->buf_start);
if (compress(dst, &zlen, src, n) != Z_OK) {
av_log(s->avctx, AV_LOG_ERROR, "Compressing failed\n");
- return AVERROR_UNKNOWN;
+ return AVERROR_EXTERNAL;
}
return zlen;
}
@@ -183,6 +194,8 @@ static int encode_strip(TiffEncoderContext *s, const int8_t *src,
case TIFF_LZW:
return ff_lzw_encode(s->lzws, src, n);
default:
+ av_log(s->avctx, AV_LOG_ERROR, "Unsupported compression method: %d\n",
+ compr);
return AVERROR(EINVAL);
}
}
@@ -194,13 +207,24 @@ static void pack_yuv(TiffEncoderContext *s, const AVFrame *p,
int w = (s->width - 1) / s->subsampling[0] + 1;
uint8_t *pu = &p->data[1][lnum / s->subsampling[1] * p->linesize[1]];
uint8_t *pv = &p->data[2][lnum / s->subsampling[1] * p->linesize[2]];
- for (i = 0; i < w; i++) {
- for (j = 0; j < s->subsampling[1]; j++)
- for (k = 0; k < s->subsampling[0]; k++)
- *dst++ = p->data[0][(lnum + j) * p->linesize[0] +
- i * s->subsampling[0] + k];
- *dst++ = *pu++;
- *dst++ = *pv++;
+ if (s->width % s->subsampling[0] || s->height % s->subsampling[1]) {
+ for (i = 0; i < w; i++) {
+ for (j = 0; j < s->subsampling[1]; j++)
+ for (k = 0; k < s->subsampling[0]; k++)
+ *dst++ = p->data[0][FFMIN(lnum + j, s->height-1) * p->linesize[0] +
+ FFMIN(i * s->subsampling[0] + k, s->width-1)];
+ *dst++ = *pu++;
+ *dst++ = *pv++;
+ }
+ }else{
+ for (i = 0; i < w; i++) {
+ for (j = 0; j < s->subsampling[1]; j++)
+ for (k = 0; k < s->subsampling[0]; k++)
+ *dst++ = p->data[0][(lnum + j) * p->linesize[0] +
+ i * s->subsampling[0] + k];
+ *dst++ = *pu++;
+ *dst++ = *pv++;
+ }
}
}
@@ -209,84 +233,75 @@ static void pack_yuv(TiffEncoderContext *s, const AVFrame *p,
ret = add_entry(s, tag, type, count, ptr_val); \
if (ret < 0) \
goto fail; \
- } while(0);
+ } while (0)
#define ADD_ENTRY1(s, tag, type, val) \
do { \
ret = add_entry1(s, tag, type, val); \
if (ret < 0) \
goto fail; \
- } while(0);
+ } while (0)
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pict, int *got_packet)
{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
TiffEncoderContext *s = avctx->priv_data;
const AVFrame *const p = pict;
int i;
uint8_t *ptr;
uint8_t *offset;
uint32_t strips;
- uint32_t *strip_sizes = NULL;
- uint32_t *strip_offsets = NULL;
int bytes_per_row;
- uint32_t res[2] = { 72, 1 }; // image resolution (72/1)
- uint16_t bpp_tab[] = { 8, 8, 8, 8 };
+ uint32_t res[2] = { s->dpi, 1 }; // image resolution (72/1)
+ uint16_t bpp_tab[4];
int ret = 0;
- int is_yuv = 0;
- uint8_t *yuv_line = NULL;
+ int is_yuv = 0, alpha = 0;
int shift_h, shift_v;
int packet_size;
- const AVPixFmtDescriptor *pfd;
-
- s->avctx = avctx;
s->width = avctx->width;
s->height = avctx->height;
s->subsampling[0] = 1;
s->subsampling[1] = 1;
+ avctx->bits_per_coded_sample =
+ s->bpp = av_get_bits_per_pixel(desc);
+ s->bpp_tab_size = desc->nb_components;
+
switch (avctx->pix_fmt) {
case AV_PIX_FMT_RGBA64LE:
- case AV_PIX_FMT_RGB48LE:
- case AV_PIX_FMT_GRAY16LE:
case AV_PIX_FMT_RGBA:
+ alpha = 1;
+ case AV_PIX_FMT_RGB48LE:
case AV_PIX_FMT_RGB24:
- case AV_PIX_FMT_GRAY8:
- case AV_PIX_FMT_PAL8:
- pfd = av_pix_fmt_desc_get(avctx->pix_fmt);
- s->bpp = av_get_bits_per_pixel(pfd);
- if (pfd->flags & AV_PIX_FMT_FLAG_PAL)
- s->photometric_interpretation = TIFF_PHOTOMETRIC_PALETTE;
- else if (pfd->flags & AV_PIX_FMT_FLAG_RGB)
- s->photometric_interpretation = TIFF_PHOTOMETRIC_RGB;
- else
- s->photometric_interpretation = TIFF_PHOTOMETRIC_BLACK_IS_ZERO;
- s->bpp_tab_size = pfd->nb_components;
- for (i = 0; i < s->bpp_tab_size; i++)
- bpp_tab[i] = s->bpp / s->bpp_tab_size;
+ s->photometric_interpretation = TIFF_PHOTOMETRIC_RGB;
break;
+ case AV_PIX_FMT_GRAY8:
+ avctx->bits_per_coded_sample = 0x28;
+ case AV_PIX_FMT_GRAY8A:
+ case AV_PIX_FMT_YA16LE:
+ alpha = avctx->pix_fmt == AV_PIX_FMT_GRAY8A || avctx->pix_fmt == AV_PIX_FMT_YA16LE;
+ case AV_PIX_FMT_GRAY16LE:
case AV_PIX_FMT_MONOBLACK:
- s->bpp = 1;
s->photometric_interpretation = TIFF_PHOTOMETRIC_BLACK_IS_ZERO;
- s->bpp_tab_size = 0;
+ break;
+ case AV_PIX_FMT_PAL8:
+ s->photometric_interpretation = TIFF_PHOTOMETRIC_PALETTE;
break;
case AV_PIX_FMT_MONOWHITE:
- s->bpp = 1;
s->photometric_interpretation = TIFF_PHOTOMETRIC_WHITE_IS_ZERO;
- s->bpp_tab_size = 0;
break;
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUV440P:
case AV_PIX_FMT_YUV444P:
case AV_PIX_FMT_YUV410P:
case AV_PIX_FMT_YUV411P:
av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &shift_h, &shift_v);
s->photometric_interpretation = TIFF_PHOTOMETRIC_YCBCR;
- s->bpp = 8 + (16 >> (shift_h + shift_v));
s->subsampling[0] = 1 << shift_h;
s->subsampling[1] = 1 << shift_v;
- s->bpp_tab_size = 3;
is_yuv = 1;
break;
default:
@@ -295,6 +310,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return AVERROR(EINVAL);
}
+ for (i = 0; i < s->bpp_tab_size; i++)
+ bpp_tab[i] = desc->comp[i].depth_minus1 + 1;
+
if (s->compr == TIFF_DEFLATE ||
s->compr == TIFF_ADOBE_DEFLATE ||
s->compr == TIFF_LZW)
@@ -308,14 +326,13 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
strips = (s->height - 1) / s->rps + 1;
- packet_size = avctx->height * ((avctx->width * s->bpp + 7) >> 3) * 2 +
+ bytes_per_row = (((s->width - 1) / s->subsampling[0] + 1) * s->bpp *
+ s->subsampling[0] * s->subsampling[1] + 7) >> 3;
+ packet_size = avctx->height * bytes_per_row * 2 +
avctx->height * 4 + FF_MIN_BUFFER_SIZE;
- if (!pkt->data &&
- (ret = av_new_packet(pkt, packet_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, packet_size)) < 0)
return ret;
- }
ptr = pkt->data;
s->buf_start = pkt->data;
s->buf = &ptr;
@@ -333,18 +350,21 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
offset = ptr;
bytestream_put_le32(&ptr, 0);
- strip_sizes = av_mallocz_array(strips, sizeof(*strip_sizes));
- strip_offsets = av_mallocz_array(strips, sizeof(*strip_offsets));
- if (!strip_sizes || !strip_offsets) {
+ if (strips > INT_MAX / FFMAX(sizeof(s->strip_sizes[0]), sizeof(s->strip_offsets[0]))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ av_fast_padded_mallocz(&s->strip_sizes , &s->strip_sizes_size , sizeof(s->strip_sizes [0]) * strips);
+ av_fast_padded_mallocz(&s->strip_offsets, &s->strip_offsets_size, sizeof(s->strip_offsets[0]) * strips);
+
+ if (!s->strip_sizes || !s->strip_offsets) {
ret = AVERROR(ENOMEM);
goto fail;
}
- bytes_per_row = (((s->width - 1) / s->subsampling[0] + 1) * s->bpp *
- s->subsampling[0] * s->subsampling[1] + 7) >> 3;
if (is_yuv) {
- yuv_line = av_malloc(bytes_per_row);
- if (!yuv_line) {
+ av_fast_padded_malloc(&s->yuv_line, &s->yuv_line_size, bytes_per_row);
+ if (s->yuv_line == NULL) {
av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n");
ret = AVERROR(ENOMEM);
goto fail;
@@ -363,12 +383,12 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ret = AVERROR(ENOMEM);
goto fail;
}
- strip_offsets[0] = ptr - pkt->data;
+ s->strip_offsets[0] = ptr - pkt->data;
zn = 0;
for (j = 0; j < s->rps; j++) {
if (is_yuv) {
- pack_yuv(s, p, yuv_line, j);
- memcpy(zbuf + zn, yuv_line, bytes_per_row);
+ pack_yuv(s, p, s->yuv_line, j);
+ memcpy(zbuf + zn, s->yuv_line, bytes_per_row);
j += s->subsampling[1] - 1;
} else
memcpy(zbuf + j * bytes_per_row,
@@ -382,9 +402,10 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
goto fail;
}
ptr += ret;
- strip_sizes[0] = ptr - pkt->data - strip_offsets[0];
+ s->strip_sizes[0] = ptr - pkt->data - s->strip_offsets[0];
} else
#endif
+ {
if (s->compr == TIFF_LZW) {
s->lzws = av_malloc(ff_lzw_encode_state_size);
if (!s->lzws) {
@@ -393,17 +414,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
}
for (i = 0; i < s->height; i++) {
- if (strip_sizes[i / s->rps] == 0) {
+ if (s->strip_sizes[i / s->rps] == 0) {
if (s->compr == TIFF_LZW) {
ff_lzw_encode_init(s->lzws, ptr,
s->buf_size - (*s->buf - s->buf_start),
12, FF_LZW_TIFF, put_bits);
}
- strip_offsets[i / s->rps] = ptr - pkt->data;
+ s->strip_offsets[i / s->rps] = ptr - pkt->data;
}
if (is_yuv) {
- pack_yuv(s, p, yuv_line, i);
- ret = encode_strip(s, yuv_line, ptr, bytes_per_row, s->compr);
+ pack_yuv(s, p, s->yuv_line, i);
+ ret = encode_strip(s, s->yuv_line, ptr, bytes_per_row, s->compr);
i += s->subsampling[1] - 1;
} else
ret = encode_strip(s, p->data[0] + i * p->linesize[0],
@@ -412,17 +433,18 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
av_log(s->avctx, AV_LOG_ERROR, "Encode strip failed\n");
goto fail;
}
- strip_sizes[i / s->rps] += ret;
+ s->strip_sizes[i / s->rps] += ret;
ptr += ret;
if (s->compr == TIFF_LZW &&
(i == s->height - 1 || i % s->rps == s->rps - 1)) {
ret = ff_lzw_encode_flush(s->lzws, flush_put_bits);
- strip_sizes[(i / s->rps)] += ret;
- ptr += ret;
+ s->strip_sizes[(i / s->rps)] += ret;
+ ptr += ret;
}
}
if (s->compr == TIFF_LZW)
- av_free(s->lzws);
+ av_freep(&s->lzws);
+ }
s->num_entries = 0;
@@ -435,14 +457,21 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ADD_ENTRY1(s, TIFF_COMPR, TIFF_SHORT, s->compr);
ADD_ENTRY1(s, TIFF_PHOTOMETRIC, TIFF_SHORT, s->photometric_interpretation);
- ADD_ENTRY(s, TIFF_STRIP_OFFS, TIFF_LONG, strips, strip_offsets);
+ ADD_ENTRY(s, TIFF_STRIP_OFFS, TIFF_LONG, strips, s->strip_offsets);
if (s->bpp_tab_size)
ADD_ENTRY1(s, TIFF_SAMPLES_PER_PIXEL, TIFF_SHORT, s->bpp_tab_size);
ADD_ENTRY1(s, TIFF_ROWSPERSTRIP, TIFF_LONG, s->rps);
- ADD_ENTRY(s, TIFF_STRIP_SIZE, TIFF_LONG, strips, strip_sizes);
+ ADD_ENTRY(s, TIFF_STRIP_SIZE, TIFF_LONG, strips, s->strip_sizes);
ADD_ENTRY(s, TIFF_XRES, TIFF_RATIONAL, 1, res);
+ if (avctx->sample_aspect_ratio.num > 0 &&
+ avctx->sample_aspect_ratio.den > 0) {
+ AVRational y = av_mul_q(av_make_q(s->dpi, 1),
+ avctx->sample_aspect_ratio);
+ res[0] = y.num;
+ res[1] = y.den;
+ }
ADD_ENTRY(s, TIFF_YRES, TIFF_RATIONAL, 1, res);
ADD_ENTRY1(s, TIFF_RES_UNIT, TIFF_SHORT, 2);
@@ -460,10 +489,14 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
ADD_ENTRY(s, TIFF_PAL, TIFF_SHORT, 256 * 3, pal);
}
+ if (alpha)
+ ADD_ENTRY1(s,TIFF_EXTRASAMPLES, TIFF_SHORT, 2);
if (is_yuv) {
/** according to CCIR Recommendation 601.1 */
uint32_t refbw[12] = { 15, 1, 235, 1, 128, 1, 240, 1, 128, 1, 240, 1 };
ADD_ENTRY(s, TIFF_YCBCR_SUBSAMPLING, TIFF_SHORT, 2, s->subsampling);
+ if (avctx->chroma_sample_location == AVCHROMA_LOC_TOPLEFT)
+ ADD_ENTRY1(s, TIFF_YCBCR_POSITIONING, TIFF_SHORT, 2);
ADD_ENTRY(s, TIFF_REFERENCE_BW, TIFF_RATIONAL, 6, refbw);
}
// write offset to dir
@@ -482,33 +515,40 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
*got_packet = 1;
fail:
- av_free(strip_sizes);
- av_free(strip_offsets);
- av_free(yuv_line);
- return ret;
+ return ret < 0 ? ret : 0;
}
static av_cold int encode_init(AVCodecContext *avctx)
{
+ TiffEncoderContext *s = avctx->priv_data;
+
avctx->coded_frame = av_frame_alloc();
if (!avctx->coded_frame)
return AVERROR(ENOMEM);
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
+ s->avctx = avctx;
return 0;
}
static av_cold int encode_close(AVCodecContext *avctx)
{
+ TiffEncoderContext *s = avctx->priv_data;
+
av_frame_free(&avctx->coded_frame);
+ av_freep(&s->strip_sizes);
+ av_freep(&s->strip_offsets);
+ av_freep(&s->yuv_line);
+
return 0;
}
#define OFFSET(x) offsetof(TiffEncoderContext, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
+ {"dpi", "set the image resolution (in dpi)", OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 72}, 1, 0x10000, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_ENCODING_PARAM},
{ "compression_algo", NULL, OFFSET(compr), AV_OPT_TYPE_INT, { .i64 = TIFF_PACKBITS }, TIFF_RAW, TIFF_DEFLATE, VE, "compression_algo" },
{ "packbits", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TIFF_PACKBITS }, 0, 0, VE, "compression_algo" },
{ "raw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TIFF_RAW }, 0, 0, VE, "compression_algo" },
@@ -534,13 +574,14 @@ AVCodec ff_tiff_encoder = {
.priv_data_size = sizeof(TiffEncoderContext),
.init = encode_init,
.close = encode_close,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.encode2 = encode_frame,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48LE, AV_PIX_FMT_PAL8,
AV_PIX_FMT_RGBA, AV_PIX_FMT_RGBA64LE,
- AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16LE,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_YA16LE,
AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_MONOWHITE,
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
AV_PIX_FMT_NONE
},
diff --git a/libavcodec/tmv.c b/libavcodec/tmv.c
index f04a5f5fa1..e525a735f6 100644
--- a/libavcodec/tmv.c
+++ b/libavcodec/tmv.c
@@ -2,20 +2,20 @@
* 8088flex TMV video decoder
* Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "avcodec.h"
#include "internal.h"
#include "libavutil/internal.h"
+#include "libavutil/xga_font_data.h"
#include "cga_data.h"
@@ -45,10 +46,8 @@ static int tmv_decode_frame(AVCodecContext *avctx, void *data,
unsigned x, y, fg, bg, c;
int ret;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if (avpkt->size < 2*char_rows*char_cols) {
av_log(avctx, AV_LOG_ERROR,
@@ -63,6 +62,7 @@ static int tmv_decode_frame(AVCodecContext *avctx, void *data,
frame->palette_has_changed = 1;
memcpy(frame->data[1], ff_cga_palette, 16 * 4);
+ memset(frame->data[1] + 16 * 4, 0, AVPALETTE_SIZE - 16 * 4);
for (y = 0; y < char_rows; y++) {
for (x = 0; x < char_cols; x++) {
@@ -70,7 +70,7 @@ static int tmv_decode_frame(AVCodecContext *avctx, void *data,
bg = *src >> 4;
fg = *src++ & 0xF;
ff_draw_pc_font(dst + x * 8, frame->linesize[0],
- ff_cga_font, 8, c, fg, bg);
+ avpriv_cga_font, 8, c, fg, bg);
}
dst += frame->linesize[0] * 8;
}
diff --git a/libavcodec/tpeldsp.c b/libavcodec/tpeldsp.c
index 7ea1da4f7e..cc4fed328d 100644
--- a/libavcodec/tpeldsp.c
+++ b/libavcodec/tpeldsp.c
@@ -1,20 +1,20 @@
/*
* thirdpel DSP functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/tpeldsp.h b/libavcodec/tpeldsp.h
index 9c67d60850..3732f179f4 100644
--- a/libavcodec/tpeldsp.h
+++ b/libavcodec/tpeldsp.h
@@ -1,20 +1,20 @@
/*
* thirdpel DSP functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/truemotion1.c b/libavcodec/truemotion1.c
index 5dffb4efd9..660ecf5413 100644
--- a/libavcodec/truemotion1.c
+++ b/libavcodec/truemotion1.c
@@ -2,20 +2,20 @@
* Duck TrueMotion 1.0 Decoder
* Copyright (C) 2003 Alex Beregszaszi & Mike Melanson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -415,6 +415,8 @@ static int truemotion1_decode_header(TrueMotion1Context *s)
ff_set_sar(s->avctx, s->avctx->sample_aspect_ratio);
av_fast_malloc(&s->vert_pred, &s->vert_pred_size, s->avctx->width * sizeof(unsigned int));
+ if (!s->vert_pred)
+ return AVERROR(ENOMEM);
}
/* There is 1 change bit per 4 pixels, so each change byte represents
@@ -483,6 +485,8 @@ static av_cold int truemotion1_decode_init(AVCodecContext *avctx)
/* there is a vertical predictor for each pixel in a line; each vertical
* predictor is 0 to start with */
av_fast_malloc(&s->vert_pred, &s->vert_pred_size, s->avctx->width * sizeof(unsigned int));
+ if (!s->vert_pred)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -871,10 +875,8 @@ static int truemotion1_decode_frame(AVCodecContext *avctx,
if ((ret = truemotion1_decode_header(s)) < 0)
return ret;
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
if (compression_types[s->compression].algorithm == ALGO_RGB24H) {
truemotion1_decode_24bit(s);
@@ -896,7 +898,7 @@ static av_cold int truemotion1_decode_end(AVCodecContext *avctx)
TrueMotion1Context *s = avctx->priv_data;
av_frame_free(&s->frame);
- av_free(s->vert_pred);
+ av_freep(&s->vert_pred);
return 0;
}
diff --git a/libavcodec/truemotion1data.h b/libavcodec/truemotion1data.h
index e950450fcd..3e581434e4 100644
--- a/libavcodec/truemotion1data.h
+++ b/libavcodec/truemotion1data.h
@@ -6,20 +6,20 @@
* the GNU LGPL using the common understanding that data tables necessary
* for decoding algorithms are not necessarily copyrightable.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_TRUEMOTION1DATA_H
diff --git a/libavcodec/truemotion2.c b/libavcodec/truemotion2.c
index 122643db0e..d2aa3c6f45 100644
--- a/libavcodec/truemotion2.c
+++ b/libavcodec/truemotion2.c
@@ -2,20 +2,20 @@
* Duck/ON2 TrueMotion 2 Decoder
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,6 +65,9 @@ typedef struct TM2Context {
GetBitContext gb;
BswapDSPContext bdsp;
+ uint8_t *buffer;
+ int buffer_size;
+
/* TM2 streams */
int *tokens[TM2_NUM_STREAMS];
int tok_lens[TM2_NUM_STREAMS];
@@ -87,7 +90,7 @@ typedef struct TM2Context {
* Huffman codes for each of streams
*/
typedef struct TM2Codes {
- VLC vlc; ///< table for Libav bitstream reader
+ VLC vlc; ///< table for FFmpeg bitstream reader
int bits;
int *recode; ///< table for converting from code indexes to values
int length;
@@ -168,9 +171,14 @@ static int tm2_build_huff_table(TM2Context *ctx, TM2Codes *code)
/* allocate space for codes - it is exactly ceil(nodes / 2) entries */
huff.max_num = (huff.nodes + 1) >> 1;
- huff.nums = av_mallocz(huff.max_num * sizeof(int));
- huff.bits = av_mallocz(huff.max_num * sizeof(uint32_t));
- huff.lens = av_mallocz(huff.max_num * sizeof(int));
+ huff.nums = av_calloc(huff.max_num, sizeof(int));
+ huff.bits = av_calloc(huff.max_num, sizeof(uint32_t));
+ huff.lens = av_calloc(huff.max_num, sizeof(int));
+
+ if (!huff.nums || !huff.bits || !huff.lens) {
+ res = AVERROR(ENOMEM);
+ goto fail;
+ }
res = tm2_read_tree(ctx, 0, 0, &huff);
@@ -192,11 +200,16 @@ static int tm2_build_huff_table(TM2Context *ctx, TM2Codes *code)
else {
code->bits = huff.max_bits;
code->length = huff.max_num;
- code->recode = av_malloc(code->length * sizeof(int));
+ code->recode = av_malloc_array(code->length, sizeof(int));
+ if (!code->recode) {
+ res = AVERROR(ENOMEM);
+ goto fail;
+ }
for (i = 0; i < code->length; i++)
code->recode[i] = huff.nums[i];
}
}
+fail:
/* free allocated memory */
av_free(huff.nums);
av_free(huff.bits);
@@ -216,6 +229,8 @@ static inline int tm2_get_token(GetBitContext *gb, TM2Codes *code)
{
int val;
val = get_vlc2(gb, code->vlc.table, code->bits, 1);
+ if(val<0)
+ return -1;
return code->recode[val];
}
@@ -247,7 +262,8 @@ static int tm2_read_deltas(TM2Context *ctx, int stream_id)
d = get_bits(&ctx->gb, 9);
mb = get_bits(&ctx->gb, 5);
- if ((d < 1) || (d > TM2_DELTAS) || (mb < 1) || (mb > 32)) {
+ av_assert2(mb < 32);
+ if ((d < 1) || (d > TM2_DELTAS) || (mb < 1)) {
av_log(ctx->avctx, AV_LOG_ERROR, "Incorrect delta table: %i deltas x %i bits\n", d, mb);
return AVERROR_INVALIDDATA;
}
@@ -273,6 +289,11 @@ static int tm2_read_stream(TM2Context *ctx, const uint8_t *buf, int stream_id, i
TM2Codes codes;
GetByteContext gb;
+ if (buf_size < 4) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "not enough space for len left\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* get stream length in dwords */
bytestream2_init(&gb, buf, buf_size);
len = bytestream2_get_be32(&gb);
@@ -281,8 +302,8 @@ static int tm2_read_stream(TM2Context *ctx, const uint8_t *buf, int stream_id, i
if (len == 0)
return 4;
- if (len >= INT_MAX/4-1 || len < 0 || len > buf_size) {
- av_log(ctx->avctx, AV_LOG_ERROR, "Error, invalid stream size.\n");
+ if (len >= INT_MAX/4-1 || len < 0 || skip > buf_size) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "invalid stream size\n");
return AVERROR_INVALIDDATA;
}
@@ -325,7 +346,11 @@ static int tm2_read_stream(TM2Context *ctx, const uint8_t *buf, int stream_id, i
tm2_free_codes(&codes);
return AVERROR_INVALIDDATA;
}
- ctx->tokens[stream_id] = av_realloc(ctx->tokens[stream_id], toks * sizeof(int));
+ ret = av_reallocp_array(&ctx->tokens[stream_id], toks, sizeof(int));
+ if (ret < 0) {
+ ctx->tok_lens[stream_id] = 0;
+ return ret;
+ }
ctx->tok_lens[stream_id] = toks;
len = bytestream2_get_be32(&gb);
if (len > 0) {
@@ -339,7 +364,7 @@ static int tm2_read_stream(TM2Context *ctx, const uint8_t *buf, int stream_id, i
return AVERROR_INVALIDDATA;
}
ctx->tokens[stream_id][i] = tm2_get_token(&ctx->gb, &codes);
- if (stream_id <= TM2_MOT && ctx->tokens[stream_id][i] >= TM2_DELTAS) {
+ if (stream_id <= TM2_MOT && ctx->tokens[stream_id][i] >= TM2_DELTAS || ctx->tokens[stream_id][i]<0) {
av_log(ctx->avctx, AV_LOG_ERROR, "Invalid delta token index %d for type %d, n=%d\n",
ctx->tokens[stream_id][i], stream_id, i);
return AVERROR_INVALIDDATA;
@@ -366,8 +391,13 @@ static inline int GET_TOK(TM2Context *ctx,int type)
av_log(ctx->avctx, AV_LOG_ERROR, "Read token from stream %i out of bounds (%i>=%i)\n", type, ctx->tok_ptrs[type], ctx->tok_lens[type]);
return 0;
}
- if (type <= TM2_MOT)
+ if (type <= TM2_MOT) {
+ if (ctx->tokens[type][ctx->tok_ptrs[type]] >= TM2_DELTAS) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "token %d is too large\n", ctx->tokens[type][ctx->tok_ptrs[type]]);
+ return 0;
+ }
return ctx->deltas[type][ctx->tokens[type][ctx->tok_ptrs[type]++]];
+ }
return ctx->tokens[type][ctx->tok_ptrs[type]++];
}
@@ -674,6 +704,11 @@ static inline void tm2_motion_block(TM2Context *ctx, AVFrame *pic, int bx, int b
mx = av_clip(mx, -(bx * 4 + 4), ctx->avctx->width - bx * 4);
my = av_clip(my, -(by * 4 + 4), ctx->avctx->height - by * 4);
+ if (4*bx+mx<0 || 4*by+my<0 || 4*bx+mx+4 > ctx->avctx->width || 4*by+my+4 > ctx->avctx->height) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "MV out of picture\n");
+ return;
+ }
+
Yo += my * oYstride + mx;
Uo += (my >> 1) * oUstride + (mx >> 1);
Vo += (my >> 1) * oVstride + (mx >> 1);
@@ -844,37 +879,34 @@ static int decode_frame(AVCodecContext *avctx,
AVFrame * const p = l->pic;
int offset = TM2_HEADER_SIZE;
int i, t, ret;
- uint8_t *swbuf;
- swbuf = av_malloc(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!swbuf) {
+ av_fast_padded_malloc(&l->buffer, &l->buffer_size, buf_size);
+ if (!l->buffer) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n");
return AVERROR(ENOMEM);
}
- if ((ret = ff_reget_buffer(avctx, p)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- av_free(swbuf);
+ if ((ret = ff_reget_buffer(avctx, p)) < 0)
return ret;
- }
- l->bdsp.bswap_buf((uint32_t *) swbuf, (const uint32_t *) buf,
+ l->bdsp.bswap_buf((uint32_t *) l->buffer, (const uint32_t *) buf,
buf_size >> 2);
- if ((ret = tm2_read_header(l, swbuf)) < 0) {
- av_free(swbuf);
+ if ((ret = tm2_read_header(l, l->buffer)) < 0) {
return ret;
}
for (i = 0; i < TM2_NUM_STREAMS; i++) {
if (offset >= buf_size) {
- av_free(swbuf);
+ av_log(avctx, AV_LOG_ERROR, "no space for tm2_read_stream\n");
return AVERROR_INVALIDDATA;
}
- t = tm2_read_stream(l, swbuf + offset, tm2_stream_order[i],
+
+ t = tm2_read_stream(l, l->buffer + offset, tm2_stream_order[i],
buf_size - offset);
if (t < 0) {
- av_free(swbuf);
+ int j = tm2_stream_order[i];
+ memset(l->tokens[j], 0, sizeof(**l->tokens) * l->tok_lens[j]);
return t;
}
offset += t;
@@ -888,7 +920,6 @@ static int decode_frame(AVCodecContext *avctx,
l->cur = !l->cur;
*got_frame = 1;
ret = av_frame_ref(data, l->pic);
- av_free(swbuf);
return (ret < 0) ? ret : buf_size;
}
@@ -912,8 +943,8 @@ static av_cold int decode_init(AVCodecContext *avctx)
ff_bswapdsp_init(&l->bdsp);
- l->last = av_malloc(4 * sizeof(*l->last) * (w >> 2));
- l->clast = av_malloc(4 * sizeof(*l->clast) * (w >> 2));
+ l->last = av_malloc_array(w >> 2, 4 * sizeof(*l->last) );
+ l->clast = av_malloc_array(w >> 2, 4 * sizeof(*l->clast));
for (i = 0; i < TM2_NUM_STREAMS; i++) {
l->tokens[i] = NULL;
@@ -922,15 +953,15 @@ static av_cold int decode_init(AVCodecContext *avctx)
w += 8;
h += 8;
- l->Y1_base = av_malloc(sizeof(*l->Y1_base) * w * h);
- l->Y2_base = av_malloc(sizeof(*l->Y2_base) * w * h);
+ l->Y1_base = av_calloc(w * h, sizeof(*l->Y1_base));
+ l->Y2_base = av_calloc(w * h, sizeof(*l->Y2_base));
l->y_stride = w;
w = (w + 1) >> 1;
h = (h + 1) >> 1;
- l->U1_base = av_malloc(sizeof(*l->U1_base) * w * h);
- l->V1_base = av_malloc(sizeof(*l->V1_base) * w * h);
- l->U2_base = av_malloc(sizeof(*l->U2_base) * w * h);
- l->V2_base = av_malloc(sizeof(*l->V1_base) * w * h);
+ l->U1_base = av_calloc(w * h, sizeof(*l->U1_base));
+ l->V1_base = av_calloc(w * h, sizeof(*l->V1_base));
+ l->U2_base = av_calloc(w * h, sizeof(*l->U2_base));
+ l->V2_base = av_calloc(w * h, sizeof(*l->V1_base));
l->uv_stride = w;
l->cur = 0;
if (!l->Y1_base || !l->Y2_base || !l->U1_base ||
@@ -944,6 +975,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
av_freep(&l->V2_base);
av_freep(&l->last);
av_freep(&l->clast);
+ av_frame_free(&l->pic);
return AVERROR(ENOMEM);
}
l->Y1 = l->Y1_base + l->y_stride * 4 + 4;
@@ -964,15 +996,17 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_free(l->last);
av_free(l->clast);
for (i = 0; i < TM2_NUM_STREAMS; i++)
- av_free(l->tokens[i]);
+ av_freep(&l->tokens[i]);
if (l->Y1) {
- av_free(l->Y1_base);
- av_free(l->U1_base);
- av_free(l->V1_base);
- av_free(l->Y2_base);
- av_free(l->U2_base);
- av_free(l->V2_base);
+ av_freep(&l->Y1_base);
+ av_freep(&l->U1_base);
+ av_freep(&l->V1_base);
+ av_freep(&l->Y2_base);
+ av_freep(&l->U2_base);
+ av_freep(&l->V2_base);
}
+ av_freep(&l->buffer);
+ l->buffer_size = 0;
av_frame_free(&l->pic);
diff --git a/libavcodec/truespeech.c b/libavcodec/truespeech.c
index 9cf9c92efe..f9e860250f 100644
--- a/libavcodec/truespeech.c
+++ b/libavcodec/truespeech.c
@@ -2,20 +2,20 @@
* DSP Group TrueSpeech compatible decoder
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -325,10 +325,8 @@ static int truespeech_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = iterations * 240;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (int16_t *)frame->data[0];
memset(samples, 0, iterations * 240 * sizeof(*samples));
diff --git a/libavcodec/truespeech_data.h b/libavcodec/truespeech_data.h
index 6e9806a0b5..73ebda5e85 100644
--- a/libavcodec/truespeech_data.h
+++ b/libavcodec/truespeech_data.h
@@ -2,20 +2,20 @@
* DSP Group TrueSpeech compatible decoder
* copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/tscc.c b/libavcodec/tscc.c
index 86199342a9..f9b325b68d 100644
--- a/libavcodec/tscc.c
+++ b/libavcodec/tscc.c
@@ -2,20 +2,20 @@
* TechSmith Camtasia decoder
* Copyright (c) 2004 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,6 +47,7 @@
typedef struct TsccContext {
AVCodecContext *avctx;
+ AVFrame *frame;
// Bits per pixel
int bpp;
@@ -67,13 +68,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
CamtasiaContext * const c = avctx->priv_data;
- AVFrame *frame = data;
+ AVFrame *frame = c->frame;
int ret;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0){
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, frame)) < 0)
return ret;
- }
ret = inflateReset(&c->zstream);
if (ret != Z_OK) {
@@ -109,6 +108,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
memcpy(frame->data[1], c->pal, AVPALETTE_SIZE);
}
+ if ((ret = av_frame_ref(data, frame)) < 0)
+ return ret;
*got_frame = 1;
/* always report that the buffer was completely consumed */
@@ -132,9 +133,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
case 24:
avctx->pix_fmt = AV_PIX_FMT_BGR24;
break;
- case 32: avctx->pix_fmt = AV_PIX_FMT_RGB32; break;
+ case 32: avctx->pix_fmt = AV_PIX_FMT_0RGB32; break;
default: av_log(avctx, AV_LOG_ERROR, "Camtasia error: unknown depth %i bpp\n", avctx->bits_per_coded_sample);
- return AVERROR_INVALIDDATA;
+ return AVERROR_PATCHWELCOME;
}
c->bpp = avctx->bits_per_coded_sample;
// buffer size for RLE 'best' case when 2-byte code precedes each pixel and there may be padding after it too
@@ -157,6 +158,8 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR_UNKNOWN;
}
+ c->frame = av_frame_alloc();
+
return 0;
}
@@ -165,6 +168,7 @@ static av_cold int decode_end(AVCodecContext *avctx)
CamtasiaContext * const c = avctx->priv_data;
av_freep(&c->decomp_buf);
+ av_frame_free(&c->frame);
inflateEnd(&c->zstream);
diff --git a/libavcodec/tscc2.c b/libavcodec/tscc2.c
index bd1854b899..92210f7d39 100644
--- a/libavcodec/tscc2.c
+++ b/libavcodec/tscc2.c
@@ -2,20 +2,20 @@
* TechSmith Screen Codec 2 (aka Dora) decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -90,14 +90,14 @@ static av_cold int init_vlcs(TSCC2Context *c)
return 0;
}
-#define DEQUANT(val, q) ((q * val + 0x80) >> 8)
+#define DEQUANT(val, q) (((q) * (val) + 0x80) >> 8)
#define DCT1D(d0, d1, d2, d3, s0, s1, s2, s3, OP) \
OP(d0, 5 * ((s0) + (s1) + (s2)) + 2 * (s3)); \
OP(d1, 5 * ((s0) - (s2) - (s3)) + 2 * (s1)); \
OP(d2, 5 * ((s0) - (s2) + (s3)) - 2 * (s1)); \
OP(d3, 5 * ((s0) - (s1) + (s2)) - 2 * (s3)); \
-#define COL_OP(a, b) a = b
+#define COL_OP(a, b) a = (b)
#define ROW_OP(a, b) a = ((b) + 0x20) >> 6
static void tscc2_idct4_put(int *in, int q[3], uint8_t *dst, int stride)
@@ -194,7 +194,8 @@ static int tscc2_decode_slice(TSCC2Context *c, int mb_y,
int i, mb_x, q, ret;
int off;
- init_get_bits(&c->gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&c->gb, buf, buf_size)) < 0)
+ return ret;
for (mb_x = 0; mb_x < c->mb_width; mb_x++) {
q = c->slice_quants[mb_x + c->mb_width * mb_y];
@@ -234,7 +235,6 @@ static int tscc2_decode_frame(AVCodecContext *avctx, void *data,
}
if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
return ret;
}
diff --git a/libavcodec/tscc2data.h b/libavcodec/tscc2data.h
index 70a06e5e0a..4586da77a5 100644
--- a/libavcodec/tscc2data.h
+++ b/libavcodec/tscc2data.h
@@ -2,20 +2,20 @@
* TechSmith Screen Codec 2 (aka Dora) decoder
* Copyright (c) 2012 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/tta.c b/libavcodec/tta.c
index 4d2e2a00be..01584d957e 100644
--- a/libavcodec/tta.c
+++ b/libavcodec/tta.c
@@ -2,20 +2,20 @@
* TTA (The Lossless True Audio) decoder
* Copyright (c) 2006 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,35 +29,23 @@
#define BITSTREAM_READER_LE
#include <limits.h>
+#include "ttadata.h"
+#include "ttadsp.h"
#include "avcodec.h"
#include "get_bits.h"
+#include "thread.h"
+#include "unary.h"
#include "internal.h"
#include "libavutil/crc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
#define FORMAT_SIMPLE 1
#define FORMAT_ENCRYPTED 2
-#define MAX_ORDER 16
-typedef struct TTAFilter {
- int32_t shift, round, error;
- int32_t qm[MAX_ORDER];
- int32_t dx[MAX_ORDER];
- int32_t dl[MAX_ORDER];
-} TTAFilter;
-
-typedef struct TTARice {
- uint32_t k0, k1, sum0, sum1;
-} TTARice;
-
-typedef struct TTAChannel {
- int32_t predictor;
- TTAFilter filter;
- TTARice rice;
-} TTAChannel;
-
typedef struct TTAContext {
+ AVClass *class;
AVCodecContext *avctx;
- GetBitContext gb;
const AVCRC *crc_table;
int format, channels, bps;
@@ -66,128 +54,65 @@ typedef struct TTAContext {
int32_t *decode_buffer;
+ uint8_t crc_pass[8];
+ uint8_t *pass;
TTAChannel *ch_ctx;
+ TTADSPContext dsp;
} TTAContext;
-static const uint32_t shift_1[] = {
- 0x00000001, 0x00000002, 0x00000004, 0x00000008,
- 0x00000010, 0x00000020, 0x00000040, 0x00000080,
- 0x00000100, 0x00000200, 0x00000400, 0x00000800,
- 0x00001000, 0x00002000, 0x00004000, 0x00008000,
- 0x00010000, 0x00020000, 0x00040000, 0x00080000,
- 0x00100000, 0x00200000, 0x00400000, 0x00800000,
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000, 0x80000000,
- 0x80000000, 0x80000000, 0x80000000, 0x80000000,
- 0x80000000, 0x80000000, 0x80000000, 0x80000000
-};
-
-static const uint32_t * const shift_16 = shift_1 + 4;
-
-static const int32_t ttafilter_configs[4] = {
- 10,
- 9,
- 10,
- 12
+static const int64_t tta_channel_layouts[7] = {
+ AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY,
+ AV_CH_LAYOUT_QUAD,
+ 0,
+ AV_CH_LAYOUT_5POINT1_BACK,
+ AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER,
+ AV_CH_LAYOUT_7POINT1_WIDE
};
-static void ttafilter_init(TTAFilter *c, int32_t shift) {
- memset(c, 0, sizeof(TTAFilter));
- c->shift = shift;
- c->round = shift_1[shift-1];
-// c->round = 1 << (shift - 1);
-}
-
-// FIXME: copy paste from original
-static inline void memshl(register int32_t *a, register int32_t *b) {
- *a++ = *b++;
- *a++ = *b++;
- *a++ = *b++;
- *a++ = *b++;
- *a++ = *b++;
- *a++ = *b++;
- *a++ = *b++;
- *a = *b;
-}
-
-static inline void ttafilter_process(TTAFilter *c, int32_t *in)
+static int tta_check_crc(TTAContext *s, const uint8_t *buf, int buf_size)
{
- register int32_t *dl = c->dl, *qm = c->qm, *dx = c->dx, sum = c->round;
-
- if (!c->error) {
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- sum += *dl++ * *qm, qm++;
- dx += 8;
- } else if(c->error < 0) {
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- sum += *dl++ * (*qm -= *dx++), qm++;
- } else {
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- sum += *dl++ * (*qm += *dx++), qm++;
- }
-
- *(dx-0) = ((*(dl-1) >> 30) | 1) << 2;
- *(dx-1) = ((*(dl-2) >> 30) | 1) << 1;
- *(dx-2) = ((*(dl-3) >> 30) | 1) << 1;
- *(dx-3) = ((*(dl-4) >> 30) | 1);
-
- c->error = *in;
- *in += (sum >> c->shift);
- *dl = *in;
-
- *(dl-1) = *dl - *(dl-1);
- *(dl-2) = *(dl-1) - *(dl-2);
- *(dl-3) = *(dl-2) - *(dl-3);
+ uint32_t crc, CRC;
- memshl(c->dl, c->dl + 1);
- memshl(c->dx, c->dx + 1);
-}
+ CRC = AV_RL32(buf + buf_size);
+ crc = av_crc(s->crc_table, 0xFFFFFFFFU, buf, buf_size);
+ if (CRC != (crc ^ 0xFFFFFFFFU)) {
+ av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
+ return AVERROR_INVALIDDATA;
+ }
-static void rice_init(TTARice *c, uint32_t k0, uint32_t k1)
-{
- c->k0 = k0;
- c->k1 = k1;
- c->sum0 = shift_16[k0];
- c->sum1 = shift_16[k1];
+ return 0;
}
-static int tta_get_unary(GetBitContext *gb)
+static uint64_t tta_check_crc64(uint8_t *pass)
{
- int ret = 0;
+ uint64_t crc = UINT64_MAX, poly = 0x42F0E1EBA9EA3693U;
+ uint8_t *end = pass + strlen(pass);
+ int i;
+
+ while (pass < end) {
+ crc ^= (uint64_t)*pass++ << 56;
+ for (i = 0; i < 8; i++)
+ crc = (crc << 1) ^ (poly & (((int64_t) crc) >> 63));
+ }
- // count ones
- while (get_bits_left(gb) > 0 && get_bits1(gb))
- ret++;
- return ret;
+ return crc ^ UINT64_MAX;
}
-static int tta_check_crc(TTAContext *s, const uint8_t *buf, int buf_size)
+static int allocate_buffers(AVCodecContext *avctx)
{
- uint32_t crc, CRC;
+ TTAContext *s = avctx->priv_data;
- CRC = AV_RL32(buf + buf_size);
- crc = av_crc(s->crc_table, 0xFFFFFFFFU, buf, buf_size);
- if (CRC != (crc ^ 0xFFFFFFFFU)) {
- av_log(s->avctx, AV_LOG_ERROR, "CRC error\n");
- return AVERROR_INVALIDDATA;
+ if (s->bps < 3) {
+ s->decode_buffer = av_mallocz_array(sizeof(int32_t)*s->frame_length, s->channels);
+ if (!s->decode_buffer)
+ return AVERROR(ENOMEM);
+ } else
+ s->decode_buffer = NULL;
+ s->ch_ctx = av_malloc_array(avctx->channels, sizeof(*s->ch_ctx));
+ if (!s->ch_ctx) {
+ av_freep(&s->decode_buffer);
+ return AVERROR(ENOMEM);
}
return 0;
@@ -196,58 +121,59 @@ static int tta_check_crc(TTAContext *s, const uint8_t *buf, int buf_size)
static av_cold int tta_decode_init(AVCodecContext * avctx)
{
TTAContext *s = avctx->priv_data;
+ GetBitContext gb;
int total_frames;
s->avctx = avctx;
- // 30bytes includes a seektable with one frame
- if (avctx->extradata_size < 30)
- return -1;
-
- init_get_bits(&s->gb, avctx->extradata, avctx->extradata_size * 8);
- if (show_bits_long(&s->gb, 32) == AV_RL32("TTA1"))
- {
- if (avctx->err_recognition & AV_EF_CRCCHECK) {
- s->crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
- tta_check_crc(s, avctx->extradata, 18);
- }
+ // 30bytes includes TTA1 header
+ if (avctx->extradata_size < 22)
+ return AVERROR_INVALIDDATA;
+ s->crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
+ init_get_bits8(&gb, avctx->extradata, avctx->extradata_size);
+ if (show_bits_long(&gb, 32) == AV_RL32("TTA1")) {
/* signature */
- skip_bits_long(&s->gb, 32);
+ skip_bits_long(&gb, 32);
- s->format = get_bits(&s->gb, 16);
+ s->format = get_bits(&gb, 16);
if (s->format > 2) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid format\n");
- return -1;
+ av_log(avctx, AV_LOG_ERROR, "Invalid format\n");
+ return AVERROR_INVALIDDATA;
}
if (s->format == FORMAT_ENCRYPTED) {
- avpriv_report_missing_feature(s->avctx, "Encrypted TTA");
- return AVERROR_PATCHWELCOME;
+ if (!s->pass) {
+ av_log(avctx, AV_LOG_ERROR, "Missing password for encrypted stream. Please use the -password option\n");
+ return AVERROR(EINVAL);
+ }
+ AV_WL64(s->crc_pass, tta_check_crc64(s->pass));
}
- avctx->channels = s->channels = get_bits(&s->gb, 16);
- avctx->bits_per_coded_sample = get_bits(&s->gb, 16);
- s->bps = (avctx->bits_per_coded_sample + 7) / 8;
- avctx->sample_rate = get_bits_long(&s->gb, 32);
- s->data_length = get_bits_long(&s->gb, 32);
- skip_bits_long(&s->gb, 32); // CRC32 of header
+ avctx->channels = s->channels = get_bits(&gb, 16);
+ if (s->channels > 1 && s->channels < 9)
+ avctx->channel_layout = tta_channel_layouts[s->channels-2];
+ avctx->bits_per_raw_sample = get_bits(&gb, 16);
+ s->bps = (avctx->bits_per_raw_sample + 7) / 8;
+ avctx->sample_rate = get_bits_long(&gb, 32);
+ s->data_length = get_bits_long(&gb, 32);
+ skip_bits_long(&gb, 32); // CRC32 of header
if (s->channels == 0) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid number of channels\n");
+ av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n");
return AVERROR_INVALIDDATA;
} else if (avctx->sample_rate == 0) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid samplerate\n");
+ av_log(avctx, AV_LOG_ERROR, "Invalid samplerate\n");
return AVERROR_INVALIDDATA;
}
switch(s->bps) {
+ case 1: avctx->sample_fmt = AV_SAMPLE_FMT_U8; break;
case 2:
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
- avctx->bits_per_raw_sample = 16;
break;
case 3:
avctx->sample_fmt = AV_SAMPLE_FMT_S32;
- avctx->bits_per_raw_sample = 24;
break;
+ //case 4: avctx->sample_fmt = AV_SAMPLE_FMT_S32; break;
default:
av_log(avctx, AV_LOG_ERROR, "Invalid/unsupported sample format.\n");
return AVERROR_INVALIDDATA;
@@ -264,54 +190,35 @@ static av_cold int tta_decode_init(AVCodecContext * avctx)
total_frames = s->data_length / s->frame_length +
(s->last_frame_length ? 1 : 0);
- av_log(s->avctx, AV_LOG_DEBUG, "format: %d chans: %d bps: %d rate: %d block: %d\n",
+ av_log(avctx, AV_LOG_DEBUG, "format: %d chans: %d bps: %d rate: %d block: %d\n",
s->format, avctx->channels, avctx->bits_per_coded_sample, avctx->sample_rate,
avctx->block_align);
- av_log(s->avctx, AV_LOG_DEBUG, "data_length: %d frame_length: %d last: %d total: %d\n",
+ av_log(avctx, AV_LOG_DEBUG, "data_length: %d frame_length: %d last: %d total: %d\n",
s->data_length, s->frame_length, s->last_frame_length, total_frames);
- // FIXME: seek table
- if (avctx->extradata_size <= 26 || total_frames > INT_MAX / 4 ||
- avctx->extradata_size - 26 < total_frames * 4)
- av_log(avctx, AV_LOG_WARNING, "Seek table missing or too small\n");
- else if (avctx->err_recognition & AV_EF_CRCCHECK) {
- int ret = tta_check_crc(s, avctx->extradata + 22, total_frames * 4);
- if (ret < 0 && avctx->err_recognition & AV_EF_EXPLODE)
- return AVERROR_INVALIDDATA;
- }
- skip_bits_long(&s->gb, 32 * total_frames);
- skip_bits_long(&s->gb, 32); // CRC32 of seektable
-
if(s->frame_length >= UINT_MAX / (s->channels * sizeof(int32_t))){
av_log(avctx, AV_LOG_ERROR, "frame_length too large\n");
- return -1;
- }
-
- if (s->bps == 2) {
- s->decode_buffer = av_mallocz(sizeof(int32_t)*s->frame_length*s->channels);
- if (!s->decode_buffer)
- return AVERROR(ENOMEM);
- }
- s->ch_ctx = av_malloc(avctx->channels * sizeof(*s->ch_ctx));
- if (!s->ch_ctx) {
- av_freep(&s->decode_buffer);
- return AVERROR(ENOMEM);
+ return AVERROR_INVALIDDATA;
}
} else {
av_log(avctx, AV_LOG_ERROR, "Wrong extradata present\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
- return 0;
+ ff_ttadsp_init(&s->dsp);
+
+ return allocate_buffers(avctx);
}
static int tta_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame_ptr, AVPacket *avpkt)
{
AVFrame *frame = data;
+ ThreadFrame tframe = { .f = data };
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
TTAContext *s = avctx->priv_data;
+ GetBitContext gb;
int i, ret;
int cur_chan = 0, framelen = s->frame_length;
int32_t *p;
@@ -322,14 +229,13 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
- init_get_bits(&s->gb, buf, buf_size*8);
+ if ((ret = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0)
+ return ret;
/* get output buffer */
frame->nb_samples = framelen;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0)
return ret;
- }
// decode directly to output buffer for 24-bit sample format
if (s->bps == 3)
@@ -337,9 +243,15 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
// init per channel states
for (i = 0; i < s->channels; i++) {
+ TTAFilter *filter = &s->ch_ctx[i].filter;
s->ch_ctx[i].predictor = 0;
- ttafilter_init(&s->ch_ctx[i].filter, ttafilter_configs[s->bps-1]);
- rice_init(&s->ch_ctx[i].rice, 10, 10);
+ ff_tta_filter_init(filter, ff_tta_filter_configs[s->bps-1]);
+ if (s->format == FORMAT_ENCRYPTED) {
+ int i;
+ for (i = 0; i < 8; i++)
+ filter->qm[i] = sign_extend(s->crc_pass[i], 8);
+ }
+ ff_tta_rice_init(&s->ch_ctx[i].rice, 10, 10);
}
i = 0;
@@ -350,7 +262,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
uint32_t unary, depth, k;
int32_t value;
- unary = tta_get_unary(&s->gb);
+ unary = get_unary(&gb, 0, get_bits_left(&gb));
if (unary == 0) {
depth = 0;
@@ -361,7 +273,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
unary--;
}
- if (get_bits_left(&s->gb) < k) {
+ if (get_bits_left(&gb) < k) {
ret = AVERROR_INVALIDDATA;
goto error;
}
@@ -371,7 +283,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
ret = AVERROR_INVALIDDATA;
goto error;
}
- value = (unary << k) + get_bits(&s->gb, k);
+ value = (unary << k) + get_bits(&gb, k);
} else
value = unary;
@@ -379,16 +291,16 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
switch (depth) {
case 1:
rice->sum1 += value - (rice->sum1 >> 4);
- if (rice->k1 > 0 && rice->sum1 < shift_16[rice->k1])
+ if (rice->k1 > 0 && rice->sum1 < ff_tta_shift_16[rice->k1])
rice->k1--;
- else if(rice->sum1 > shift_16[rice->k1 + 1])
+ else if(rice->sum1 > ff_tta_shift_16[rice->k1 + 1])
rice->k1++;
- value += shift_1[rice->k0];
+ value += ff_tta_shift_1[rice->k0];
default:
rice->sum0 += value - (rice->sum0 >> 4);
- if (rice->k0 > 0 && rice->sum0 < shift_16[rice->k0])
+ if (rice->k0 > 0 && rice->sum0 < ff_tta_shift_16[rice->k0])
rice->k0--;
- else if(rice->sum0 > shift_16[rice->k0 + 1])
+ else if(rice->sum0 > ff_tta_shift_16[rice->k0 + 1])
rice->k0++;
}
@@ -396,10 +308,11 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
*p = 1 + ((value >> 1) ^ ((value & 1) - 1));
// run hybrid filter
- ttafilter_process(filter, p);
+ s->dsp.ttafilter_process_dec(filter->qm, filter->dx, filter->dl, &filter->error, p,
+ filter->shift, filter->round);
// fixed order prediction
-#define PRED(x, k) (int32_t)((((uint64_t)x << k) - x) >> k)
+#define PRED(x, k) (int32_t)((((uint64_t)(x) << (k)) - (x)) >> (k))
switch (s->bps) {
case 1: *p += PRED(*predictor, 4); break;
case 2:
@@ -421,32 +334,43 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data,
cur_chan = 0;
i++;
// check for last frame
- if (i == s->last_frame_length && get_bits_left(&s->gb) / 8 == 4) {
+ if (i == s->last_frame_length && get_bits_left(&gb) / 8 == 4) {
frame->nb_samples = framelen = s->last_frame_length;
break;
}
}
}
- align_get_bits(&s->gb);
- if (get_bits_left(&s->gb) < 32) {
+ align_get_bits(&gb);
+ if (get_bits_left(&gb) < 32) {
ret = AVERROR_INVALIDDATA;
goto error;
}
- skip_bits_long(&s->gb, 32); // frame crc
+ skip_bits_long(&gb, 32); // frame crc
// convert to output buffer
- if (s->bps == 2) {
+ switch (s->bps) {
+ case 1: {
+ uint8_t *samples = (uint8_t *)frame->data[0];
+ for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++)
+ *samples++ = *p + 0x80;
+ break;
+ }
+ case 2: {
int16_t *samples = (int16_t *)frame->data[0];
for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++)
*samples++ = *p;
- } else {
+ break;
+ }
+ case 3: {
// shift samples for 24-bit sample format
int32_t *samples = (int32_t *)frame->data[0];
for (i = 0; i < framelen * s->channels; i++)
*samples++ <<= 8;
// reset decode buffer
s->decode_buffer = NULL;
+ break;
+ }
}
*got_frame_ptr = 1;
@@ -459,15 +383,38 @@ error:
return ret;
}
+static int init_thread_copy(AVCodecContext *avctx)
+{
+ TTAContext *s = avctx->priv_data;
+ s->avctx = avctx;
+ return allocate_buffers(avctx);
+}
+
static av_cold int tta_decode_close(AVCodecContext *avctx) {
TTAContext *s = avctx->priv_data;
- av_free(s->decode_buffer);
+ if (s->bps < 3)
+ av_freep(&s->decode_buffer);
+ s->decode_buffer = NULL;
av_freep(&s->ch_ctx);
return 0;
}
+#define OFFSET(x) offsetof(TTAContext, x)
+#define DEC (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM)
+static const AVOption options[] = {
+ { "password", "Set decoding password", OFFSET(pass), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, DEC },
+ { NULL },
+};
+
+static const AVClass tta_decoder_class = {
+ .class_name = "TTA Decoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_tta_decoder = {
.name = "tta",
.long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"),
@@ -477,5 +424,7 @@ AVCodec ff_tta_decoder = {
.init = tta_decode_init,
.close = tta_decode_close,
.decode = tta_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
+ .priv_class = &tta_decoder_class,
};
diff --git a/libavcodec/ttadata.c b/libavcodec/ttadata.c
new file mode 100644
index 0000000000..bf793a4cc8
--- /dev/null
+++ b/libavcodec/ttadata.c
@@ -0,0 +1,52 @@
+/*
+ * TTA (The Lossless True Audio) data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ttadata.h"
+
+const uint32_t ff_tta_shift_1[] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x80000000, 0x80000000, 0x80000000, 0x80000000,
+ 0x80000000, 0x80000000, 0x80000000, 0x80000000
+};
+
+const uint32_t * const ff_tta_shift_16 = ff_tta_shift_1 + 4;
+
+const uint8_t ff_tta_filter_configs[] = { 10, 9, 10, 12 };
+
+void ff_tta_rice_init(TTARice *c, uint32_t k0, uint32_t k1)
+{
+ c->k0 = k0;
+ c->k1 = k1;
+ c->sum0 = ff_tta_shift_16[k0];
+ c->sum1 = ff_tta_shift_16[k1];
+}
+
+void ff_tta_filter_init(TTAFilter *c, int32_t shift) {
+ memset(c, 0, sizeof(TTAFilter));
+ c->shift = shift;
+ c->round = ff_tta_shift_1[shift-1];
+}
diff --git a/libavcodec/ttadata.h b/libavcodec/ttadata.h
new file mode 100644
index 0000000000..48c4cd0354
--- /dev/null
+++ b/libavcodec/ttadata.h
@@ -0,0 +1,50 @@
+/*
+ * TTA (The Lossless True Audio) data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_TTADATA_H
+#define AVCODEC_TTADATA_H
+
+#include "internal.h"
+
+#define MAX_ORDER 16
+typedef struct TTAFilter {
+ int32_t shift, round, error;
+ int32_t qm[MAX_ORDER];
+ int32_t dx[MAX_ORDER];
+ int32_t dl[MAX_ORDER];
+} TTAFilter;
+
+typedef struct TTARice {
+ uint32_t k0, k1, sum0, sum1;
+} TTARice;
+
+typedef struct TTAChannel {
+ int32_t predictor;
+ TTAFilter filter;
+ TTARice rice;
+} TTAChannel;
+
+extern const uint32_t ff_tta_shift_1[];
+extern const uint32_t * const ff_tta_shift_16;
+extern const uint8_t ff_tta_filter_configs[];
+
+void ff_tta_rice_init(TTARice *c, uint32_t k0, uint32_t k1);
+void ff_tta_filter_init(TTAFilter *c, int32_t shift);
+#endif /* AVCODEC_TTADATA_H */
diff --git a/libavcodec/ttadsp.c b/libavcodec/ttadsp.c
new file mode 100644
index 0000000000..30b7ab9eb7
--- /dev/null
+++ b/libavcodec/ttadsp.c
@@ -0,0 +1,57 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "ttadsp.h"
+
+static void ttafilter_process_dec_c(int32_t *qm, int32_t *dx, int32_t *dl,
+ int32_t *error, int32_t *in, int32_t shift,
+ int32_t round) {
+ if (*error < 0) {
+ qm[0] -= dx[0]; qm[1] -= dx[1]; qm[2] -= dx[2]; qm[3] -= dx[3];
+ qm[4] -= dx[4]; qm[5] -= dx[5]; qm[6] -= dx[6]; qm[7] -= dx[7];
+ } else if (*error > 0) {
+ qm[0] += dx[0]; qm[1] += dx[1]; qm[2] += dx[2]; qm[3] += dx[3];
+ qm[4] += dx[4]; qm[5] += dx[5]; qm[6] += dx[6]; qm[7] += dx[7];
+ }
+
+ round += dl[0] * qm[0] + dl[1] * qm[1] + dl[2] * qm[2] + dl[3] * qm[3] +
+ dl[4] * qm[4] + dl[5] * qm[5] + dl[6] * qm[6] + dl[7] * qm[7];
+
+ dx[0] = dx[1]; dx[1] = dx[2]; dx[2] = dx[3]; dx[3] = dx[4];
+ dl[0] = dl[1]; dl[1] = dl[2]; dl[2] = dl[3]; dl[3] = dl[4];
+
+ dx[4] = ((dl[4] >> 30) | 1);
+ dx[5] = ((dl[5] >> 30) | 2) & ~1;
+ dx[6] = ((dl[6] >> 30) | 2) & ~1;
+ dx[7] = ((dl[7] >> 30) | 4) & ~3;
+
+ *error = *in;
+ *in += (round >> shift);
+
+ dl[4] = -dl[5]; dl[5] = -dl[6];
+ dl[6] = *in - dl[7]; dl[7] = *in;
+ dl[5] += dl[6]; dl[4] += dl[5];
+}
+
+av_cold void ff_ttadsp_init(TTADSPContext *c)
+{
+ c->ttafilter_process_dec = ttafilter_process_dec_c;
+
+ if (ARCH_X86)
+ ff_ttadsp_init_x86(c);
+}
diff --git a/libavcodec/ttadsp.h b/libavcodec/ttadsp.h
new file mode 100644
index 0000000000..56930f1c85
--- /dev/null
+++ b/libavcodec/ttadsp.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_TTADSP_H
+#define AVCODEC_TTADSP_H
+
+#include <stdint.h>
+#include "ttadata.h"
+
+typedef struct TTADSPContext {
+ void (*ttafilter_process_dec)(int32_t *qm, int32_t *dx, int32_t *dl,
+ int32_t *error, int32_t *in, int32_t shift,
+ int32_t round);
+} TTADSPContext;
+
+void ff_ttadsp_init(TTADSPContext *c);
+void ff_ttadsp_init_x86(TTADSPContext *c);
+
+#endif /* AVCODEC_TTADSP_H */
diff --git a/libavcodec/ttaenc.c b/libavcodec/ttaenc.c
new file mode 100644
index 0000000000..ccd41a90c9
--- /dev/null
+++ b/libavcodec/ttaenc.c
@@ -0,0 +1,232 @@
+/*
+ * TTA (The Lossless True Audio) encoder
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITSTREAM_WRITER_LE
+#include "ttadata.h"
+#include "avcodec.h"
+#include "put_bits.h"
+#include "internal.h"
+#include "libavutil/crc.h"
+
+typedef struct TTAEncContext {
+ const AVCRC *crc_table;
+ int bps;
+ TTAChannel *ch_ctx;
+} TTAEncContext;
+
+static av_cold int tta_encode_init(AVCodecContext *avctx)
+{
+ TTAEncContext *s = avctx->priv_data;
+
+ s->crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
+
+ switch (avctx->sample_fmt) {
+ case AV_SAMPLE_FMT_U8:
+ avctx->bits_per_raw_sample = 8;
+ break;
+ case AV_SAMPLE_FMT_S16:
+ avctx->bits_per_raw_sample = 16;
+ break;
+ case AV_SAMPLE_FMT_S32:
+ if (avctx->bits_per_raw_sample > 24)
+ av_log(avctx, AV_LOG_WARNING, "encoding as 24 bits-per-sample\n");
+ avctx->bits_per_raw_sample = 24;
+ }
+
+ s->bps = avctx->bits_per_raw_sample >> 3;
+ avctx->frame_size = 256 * avctx->sample_rate / 245;
+
+ s->ch_ctx = av_malloc_array(avctx->channels, sizeof(*s->ch_ctx));
+ if (!s->ch_ctx)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static inline void ttafilter_process(TTAFilter *c, int32_t *in)
+{
+ register int32_t *dl = c->dl, *qm = c->qm, *dx = c->dx, sum = c->round;
+
+ if (c->error < 0) {
+ qm[0] -= dx[0]; qm[1] -= dx[1]; qm[2] -= dx[2]; qm[3] -= dx[3];
+ qm[4] -= dx[4]; qm[5] -= dx[5]; qm[6] -= dx[6]; qm[7] -= dx[7];
+ } else if (c->error > 0) {
+ qm[0] += dx[0]; qm[1] += dx[1]; qm[2] += dx[2]; qm[3] += dx[3];
+ qm[4] += dx[4]; qm[5] += dx[5]; qm[6] += dx[6]; qm[7] += dx[7];
+ }
+
+ sum += dl[0] * qm[0] + dl[1] * qm[1] + dl[2] * qm[2] + dl[3] * qm[3] +
+ dl[4] * qm[4] + dl[5] * qm[5] + dl[6] * qm[6] + dl[7] * qm[7];
+
+ dx[0] = dx[1]; dx[1] = dx[2]; dx[2] = dx[3]; dx[3] = dx[4];
+ dl[0] = dl[1]; dl[1] = dl[2]; dl[2] = dl[3]; dl[3] = dl[4];
+
+ dx[4] = ((dl[4] >> 30) | 1);
+ dx[5] = ((dl[5] >> 30) | 2) & ~1;
+ dx[6] = ((dl[6] >> 30) | 2) & ~1;
+ dx[7] = ((dl[7] >> 30) | 4) & ~3;
+
+ dl[4] = -dl[5]; dl[5] = -dl[6];
+ dl[6] = *in - dl[7]; dl[7] = *in;
+ dl[5] += dl[6]; dl[4] += dl[5];
+
+ *in -= (sum >> c->shift);
+ c->error = *in;
+}
+
+static int32_t get_sample(const AVFrame *frame, int sample,
+ enum AVSampleFormat format)
+{
+ int32_t ret;
+
+ if (format == AV_SAMPLE_FMT_U8) {
+ ret = frame->data[0][sample] - 0x80;
+ } else if (format == AV_SAMPLE_FMT_S16) {
+ const int16_t *ptr = (const int16_t *)frame->data[0];
+ ret = ptr[sample];
+ } else {
+ const int32_t *ptr = (const int32_t *)frame->data[0];
+ ret = ptr[sample] >> 8;
+ }
+
+ return ret;
+}
+
+static int tta_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ TTAEncContext *s = avctx->priv_data;
+ PutBitContext pb;
+ int ret, i, out_bytes, cur_chan = 0, res = 0, samples = 0;
+
+ if ((ret = ff_alloc_packet2(avctx, avpkt, frame->nb_samples * 2 * avctx->channels * s->bps)) < 0)
+ return ret;
+ init_put_bits(&pb, avpkt->data, avpkt->size);
+
+ // init per channel states
+ for (i = 0; i < avctx->channels; i++) {
+ s->ch_ctx[i].predictor = 0;
+ ff_tta_filter_init(&s->ch_ctx[i].filter, ff_tta_filter_configs[s->bps - 1]);
+ ff_tta_rice_init(&s->ch_ctx[i].rice, 10, 10);
+ }
+
+ for (i = 0; i < frame->nb_samples * avctx->channels; i++) {
+ TTAChannel *c = &s->ch_ctx[cur_chan];
+ TTAFilter *filter = &c->filter;
+ TTARice *rice = &c->rice;
+ uint32_t k, unary, outval;
+ int32_t value, temp;
+
+ value = get_sample(frame, samples++, avctx->sample_fmt);
+
+ if (avctx->channels > 1) {
+ if (cur_chan < avctx->channels - 1)
+ value = res = get_sample(frame, samples, avctx->sample_fmt) - value;
+ else
+ value -= res / 2;
+ }
+
+ temp = value;
+#define PRED(x, k) (int32_t)((((uint64_t)(x) << (k)) - (x)) >> (k))
+ switch (s->bps) {
+ case 1: value -= PRED(c->predictor, 4); break;
+ case 2:
+ case 3: value -= PRED(c->predictor, 5); break;
+ }
+ c->predictor = temp;
+
+ ttafilter_process(filter, &value);
+ outval = (value > 0) ? (value << 1) - 1: -value << 1;
+
+ k = rice->k0;
+
+ rice->sum0 += outval - (rice->sum0 >> 4);
+ if (rice->k0 > 0 && rice->sum0 < ff_tta_shift_16[rice->k0])
+ rice->k0--;
+ else if (rice->sum0 > ff_tta_shift_16[rice->k0 + 1])
+ rice->k0++;
+
+ if (outval >= ff_tta_shift_1[k]) {
+ outval -= ff_tta_shift_1[k];
+ k = rice->k1;
+
+ rice->sum1 += outval - (rice->sum1 >> 4);
+ if (rice->k1 > 0 && rice->sum1 < ff_tta_shift_16[rice->k1])
+ rice->k1--;
+ else if (rice->sum1 > ff_tta_shift_16[rice->k1 + 1])
+ rice->k1++;
+
+ unary = 1 + (outval >> k);
+ do {
+ if (unary > 31) {
+ put_bits(&pb, 31, 0x7FFFFFFF);
+ unary -= 31;
+ } else {
+ put_bits(&pb, unary, (1 << unary) - 1);
+ unary = 0;
+ }
+ } while (unary);
+ }
+
+ put_bits(&pb, 1, 0);
+
+ if (k)
+ put_bits(&pb, k, outval & (ff_tta_shift_1[k] - 1));
+
+ if (cur_chan < avctx->channels - 1)
+ cur_chan++;
+ else
+ cur_chan = 0;
+ }
+
+ flush_put_bits(&pb);
+ out_bytes = put_bits_count(&pb) >> 3;
+ put_bits32(&pb, av_crc(s->crc_table, UINT32_MAX, avpkt->data, out_bytes) ^ UINT32_MAX);
+ flush_put_bits(&pb);
+
+ avpkt->pts = frame->pts;
+ avpkt->size = out_bytes + 4;
+ avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
+ *got_packet_ptr = 1;
+ return 0;
+}
+
+static av_cold int tta_encode_close(AVCodecContext *avctx)
+{
+ TTAEncContext *s = avctx->priv_data;
+ av_freep(&s->ch_ctx);
+ return 0;
+}
+
+AVCodec ff_tta_encoder = {
+ .name = "tta",
+ .long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_TTA,
+ .priv_data_size = sizeof(TTAEncContext),
+ .init = tta_encode_init,
+ .close = tta_encode_close,
+ .encode2 = tta_encode_frame,
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_LOSSLESS,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_U8,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_NONE },
+};
diff --git a/libavcodec/twinvq.c b/libavcodec/twinvq.c
index e1b1c7bb64..4c289b0c92 100644
--- a/libavcodec/twinvq.c
+++ b/libavcodec/twinvq.c
@@ -2,20 +2,20 @@
* TwinVQ decoder
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -358,7 +358,7 @@ static void imdct_and_window(TwinVQContext *tctx, enum TwinVQFrameType ftype,
mdct->imdct_half(mdct, buf1 + bsize * j, in + bsize * j);
- tctx->fdsp.vector_fmul_window(out2, prev_buf + (bsize - wsize) / 2,
+ tctx->fdsp->vector_fmul_window(out2, prev_buf + (bsize - wsize) / 2,
buf1 + bsize * j,
ff_sine_windows[av_log2(wsize)],
wsize / 2);
@@ -405,7 +405,7 @@ static void imdct_output(TwinVQContext *tctx, enum TwinVQFrameType ftype,
size1 * sizeof(*out2));
memcpy(out2 + size1, &tctx->curr_frame[2 * mtab->size],
size2 * sizeof(*out2));
- tctx->fdsp.butterflies_float(out1, out2, mtab->size);
+ tctx->fdsp->butterflies_float(out1, out2, mtab->size);
}
}
@@ -446,7 +446,7 @@ static void read_and_decode_spectrum(TwinVQContext *tctx, float *out,
bits->bark_use_hist[i][j], i,
tctx->tmp_buf, gain[sub * i + j], ftype);
- tctx->fdsp.vector_fmul(chunk + block_size * j,
+ tctx->fdsp->vector_fmul(chunk + block_size * j,
chunk + block_size * j,
tctx->tmp_buf, block_size);
}
@@ -461,7 +461,7 @@ static void read_and_decode_spectrum(TwinVQContext *tctx, float *out,
dec_lpc_spectrum_inv(tctx, lsp, ftype, tctx->tmp_buf);
for (j = 0; j < mtab->fmode[ftype].sub; j++) {
- tctx->fdsp.vector_fmul(chunk, chunk, tctx->tmp_buf, block_size);
+ tctx->fdsp->vector_fmul(chunk, chunk, tctx->tmp_buf, block_size);
chunk += block_size;
}
}
@@ -487,10 +487,8 @@ int ff_twinvq_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
if (tctx->discarded_packets >= 2) {
frame->nb_samples = mtab->size * tctx->frames_per_packet;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
out = (float **)frame->extended_data;
}
@@ -548,24 +546,24 @@ static av_cold int init_mdct_win(TwinVQContext *tctx)
return ret;
}
- FF_ALLOC_OR_GOTO(tctx->avctx, tctx->tmp_buf,
- mtab->size * sizeof(*tctx->tmp_buf), alloc_fail);
+ FF_ALLOC_ARRAY_OR_GOTO(tctx->avctx, tctx->tmp_buf,
+ mtab->size, sizeof(*tctx->tmp_buf), alloc_fail);
- FF_ALLOC_OR_GOTO(tctx->avctx, tctx->spectrum,
- 2 * mtab->size * channels * sizeof(*tctx->spectrum),
+ FF_ALLOC_ARRAY_OR_GOTO(tctx->avctx, tctx->spectrum,
+ 2 * mtab->size, channels * sizeof(*tctx->spectrum),
alloc_fail);
- FF_ALLOC_OR_GOTO(tctx->avctx, tctx->curr_frame,
- 2 * mtab->size * channels * sizeof(*tctx->curr_frame),
+ FF_ALLOC_ARRAY_OR_GOTO(tctx->avctx, tctx->curr_frame,
+ 2 * mtab->size, channels * sizeof(*tctx->curr_frame),
alloc_fail);
- FF_ALLOC_OR_GOTO(tctx->avctx, tctx->prev_frame,
- 2 * mtab->size * channels * sizeof(*tctx->prev_frame),
+ FF_ALLOC_ARRAY_OR_GOTO(tctx->avctx, tctx->prev_frame,
+ 2 * mtab->size, channels * sizeof(*tctx->prev_frame),
alloc_fail);
for (i = 0; i < 3; i++) {
int m = 4 * mtab->size / mtab->fmode[i].sub;
double freq = 2 * M_PI / m;
- FF_ALLOC_OR_GOTO(tctx->avctx, tctx->cos_tabs[i],
- (m / 4) * sizeof(*tctx->cos_tabs[i]), alloc_fail);
+ FF_ALLOC_ARRAY_OR_GOTO(tctx->avctx, tctx->cos_tabs[i],
+ (m / 4), sizeof(*tctx->cos_tabs[i]), alloc_fail);
for (j = 0; j <= m / 8; j++)
tctx->cos_tabs[i][j] = cos((2 * j + 1) * freq);
@@ -757,13 +755,14 @@ av_cold int ff_twinvq_decode_close(AVCodecContext *avctx)
for (i = 0; i < 3; i++) {
ff_mdct_end(&tctx->mdct_ctx[i]);
- av_free(tctx->cos_tabs[i]);
+ av_freep(&tctx->cos_tabs[i]);
}
- av_free(tctx->curr_frame);
- av_free(tctx->spectrum);
- av_free(tctx->prev_frame);
- av_free(tctx->tmp_buf);
+ av_freep(&tctx->curr_frame);
+ av_freep(&tctx->spectrum);
+ av_freep(&tctx->prev_frame);
+ av_freep(&tctx->tmp_buf);
+ av_freep(&tctx->fdsp);
return 0;
}
@@ -790,7 +789,11 @@ av_cold int ff_twinvq_decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- avpriv_float_dsp_init(&tctx->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ tctx->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!tctx->fdsp) {
+ ff_twinvq_decode_close(avctx);
+ return AVERROR(ENOMEM);
+ }
if ((ret = init_mdct_win(tctx))) {
av_log(avctx, AV_LOG_ERROR, "Error initializing MDCT\n");
ff_twinvq_decode_close(avctx);
diff --git a/libavcodec/twinvq.h b/libavcodec/twinvq.h
index 3148069756..206eeaaf83 100644
--- a/libavcodec/twinvq.h
+++ b/libavcodec/twinvq.h
@@ -2,20 +2,20 @@
* TwinVQ decoder
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -136,7 +136,7 @@ typedef struct TwinVQModeTab {
typedef struct TwinVQContext {
AVCodecContext *avctx;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext mdct_ctx[3];
const TwinVQModeTab *mtab;
diff --git a/libavcodec/twinvq_data.h b/libavcodec/twinvq_data.h
index 01a54a5ea8..375acc245a 100644
--- a/libavcodec/twinvq_data.h
+++ b/libavcodec/twinvq_data.h
@@ -2,20 +2,20 @@
* TwinVQ decoder
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/twinvqdec.c b/libavcodec/twinvqdec.c
index 65028a6640..3ea4dfa136 100644
--- a/libavcodec/twinvqdec.c
+++ b/libavcodec/twinvqdec.c
@@ -2,20 +2,20 @@
* TwinVQ decoder
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -256,9 +256,10 @@ static int twinvq_read_bitstream(AVCodecContext *avctx, TwinVQContext *tctx,
int channels = tctx->avctx->channels;
int sub;
GetBitContext gb;
- int i, j, k;
+ int i, j, k, ret;
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
+ return ret;
skip_bits(&gb, get_bits(&gb, 8));
bits->window_type = get_bits(&gb, TWINVQ_WINDOW_TYPE_BITS);
@@ -312,7 +313,7 @@ static int twinvq_read_bitstream(AVCodecContext *avctx, TwinVQContext *tctx,
}
}
- return 0;
+ return (get_bits_count(&gb) + 7) / 8;
}
static av_cold int twinvq_decode_init(AVCodecContext *avctx)
diff --git a/libavcodec/txd.c b/libavcodec/txd.c
index 8f12291c85..d2884ad1c6 100644
--- a/libavcodec/txd.c
+++ b/libavcodec/txd.c
@@ -4,27 +4,27 @@
*
* See also: http://wiki.multimedia.cx/index.php?title=TXD
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/imgutils.h"
-#include "avcodec.h"
#include "bytestream.h"
+#include "avcodec.h"
#include "internal.h"
#include "s3tc.h"
@@ -66,10 +66,8 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
return ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
@@ -82,6 +80,8 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
v = bytestream2_get_be32(&gb);
pal[y] = (v >> 8) + (v << 24);
}
+ if (bytestream2_get_bytes_left(&gb) < w * h)
+ return AVERROR_INVALIDDATA;
bytestream2_skip(&gb, 4);
for (y=0; y<h; y++) {
bytestream2_get_buffer(&gb, ptr, w);
@@ -94,9 +94,13 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (!(flags & 1))
goto unsupported;
case FF_S3TC_DXT1:
+ if (bytestream2_get_bytes_left(&gb) < FF_CEIL_RSHIFT(w, 2) * FF_CEIL_RSHIFT(h, 2) * 8)
+ return AVERROR_INVALIDDATA;
ff_decode_dxt1(&gb, ptr, w, h, stride);
break;
case FF_S3TC_DXT3:
+ if (bytestream2_get_bytes_left(&gb) < FF_CEIL_RSHIFT(w, 2) * FF_CEIL_RSHIFT(h, 2) * 16)
+ return AVERROR_INVALIDDATA;
ff_decode_dxt3(&gb, ptr, w, h, stride);
break;
default:
@@ -106,6 +110,8 @@ static int txd_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
switch (d3d_format) {
case 0x15:
case 0x16:
+ if (bytestream2_get_bytes_left(&gb) < h * w * 4)
+ return AVERROR_INVALIDDATA;
for (y=0; y<h; y++) {
bytestream2_get_buffer(&gb, ptr, w * 4);
ptr += stride;
diff --git a/libavcodec/ulti.c b/libavcodec/ulti.c
index b955dd7c04..d14603a2cd 100644
--- a/libavcodec/ulti.c
+++ b/libavcodec/ulti.c
@@ -2,20 +2,20 @@
* IBM Ultimotion Video Decoder
* Copyright (C) 2004 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -227,10 +227,8 @@ static int ulti_decode_frame(AVCodecContext *avctx,
int skip;
int tmp;
- if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
bytestream2_init(&s->gb, buf, buf_size);
diff --git a/libavcodec/ulti_cb.h b/libavcodec/ulti_cb.h
index 0bd83ffd37..7061d839a8 100644
--- a/libavcodec/ulti_cb.h
+++ b/libavcodec/ulti_cb.h
@@ -2,20 +2,20 @@
* IBM Ultimotion Video Decoder
* copyright (C) 2004 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/unary.h b/libavcodec/unary.h
index d14929f797..908dc93507 100644
--- a/libavcodec/unary.h
+++ b/libavcodec/unary.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index c9ae19b8d8..8695cb9689 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,9 +26,11 @@
*/
#include "config.h"
+#include "libavutil/atomic.h"
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
#include "libavutil/crc.h"
#include "libavutil/frame.h"
@@ -43,34 +45,124 @@
#include "me_cmp.h"
#include "mpegvideo.h"
#include "thread.h"
+#include "frame_thread_encoder.h"
#include "internal.h"
+#include "raw.h"
#include "bytestream.h"
#include "version.h"
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <float.h>
+#if CONFIG_ICONV
+# include <iconv.h>
+#endif
+
+#if HAVE_PTHREADS
+#include <pthread.h>
+#elif HAVE_W32THREADS
+#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
+#endif
+
+#include "libavutil/ffversion.h"
+const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
+#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS
+static int default_lockmgr_cb(void **arg, enum AVLockOp op)
+{
+ void * volatile * mutex = arg;
+ int err;
+
+ switch (op) {
+ case AV_LOCK_CREATE:
+ return 0;
+ case AV_LOCK_OBTAIN:
+ if (!*mutex) {
+ pthread_mutex_t *tmp = av_malloc(sizeof(pthread_mutex_t));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ if ((err = pthread_mutex_init(tmp, NULL))) {
+ av_free(tmp);
+ return AVERROR(err);
+ }
+ if (avpriv_atomic_ptr_cas(mutex, NULL, tmp)) {
+ pthread_mutex_destroy(tmp);
+ av_free(tmp);
+ }
+ }
+
+ if ((err = pthread_mutex_lock(*mutex)))
+ return AVERROR(err);
+
+ return 0;
+ case AV_LOCK_RELEASE:
+ if ((err = pthread_mutex_unlock(*mutex)))
+ return AVERROR(err);
+
+ return 0;
+ case AV_LOCK_DESTROY:
+ if (*mutex)
+ pthread_mutex_destroy(*mutex);
+ av_free(*mutex);
+ avpriv_atomic_ptr_cas(mutex, *mutex, NULL);
+ return 0;
+ }
+ return 1;
+}
+static int (*lockmgr_cb)(void **mutex, enum AVLockOp op) = default_lockmgr_cb;
+#else
+static int (*lockmgr_cb)(void **mutex, enum AVLockOp op) = NULL;
+#endif
+
+volatile int ff_avcodec_locked;
static int volatile entangled_thread_counter = 0;
-static int (*lockmgr_cb)(void **mutex, enum AVLockOp op);
static void *codec_mutex;
static void *avformat_mutex;
-void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size)
+static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
{
void **p = ptr;
+ if (min_size <= *size && *p)
+ return 0;
+ min_size = FFMAX(17 * min_size / 16 + 32, min_size);
+ av_free(*p);
+ *p = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
+ if (!*p)
+ min_size = 0;
+ *size = min_size;
+ return 1;
+}
+
+void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size)
+{
+ uint8_t **p = ptr;
if (min_size > SIZE_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
av_freep(p);
*size = 0;
return;
}
- av_fast_malloc(p, size, min_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (*size)
- memset((uint8_t *)*p + min_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!ff_fast_malloc(p, size, min_size + FF_INPUT_BUFFER_PADDING_SIZE, 1))
+ memset(*p + min_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+}
+
+void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size)
+{
+ uint8_t **p = ptr;
+ if (min_size > SIZE_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+ av_freep(p);
+ *size = 0;
+ return;
+ }
+ if (!ff_fast_malloc(p, size, min_size + FF_INPUT_BUFFER_PADDING_SIZE, 1))
+ memset(*p, 0, min_size + FF_INPUT_BUFFER_PADDING_SIZE);
}
/* encoder management */
static AVCodec *first_avcodec = NULL;
+static AVCodec **last_avcodec = &first_avcodec;
AVCodec *av_codec_next(const AVCodec *c)
{
@@ -106,12 +198,13 @@ av_cold void avcodec_register(AVCodec *codec)
{
AVCodec **p;
avcodec_init();
- p = &first_avcodec;
- while (*p)
- p = &(*p)->next;
- *p = codec;
+ p = last_avcodec;
codec->next = NULL;
+ while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec))
+ p = &(*p)->next;
+ last_avcodec = &codec->next;
+
if (codec->init_static_data)
codec->init_static_data(codec);
}
@@ -126,7 +219,10 @@ unsigned avcodec_get_edge_width(void)
#if FF_API_SET_DIMENSIONS
void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
{
- ff_set_dimensions(s, width, height);
+ int ret = ff_set_dimensions(s, width, height);
+ if (ret < 0) {
+ av_log(s, AV_LOG_WARNING, "Failed to set dimensions %d %d\n", width, height);
+ }
}
#endif
@@ -136,8 +232,11 @@ int ff_set_dimensions(AVCodecContext *s, int width, int height)
if (ret < 0)
width = height = 0;
- s->width = s->coded_width = width;
- s->height = s->coded_height = height;
+
+ s->coded_width = width;
+ s->coded_height = height;
+ s->width = FF_CEIL_RSHIFT(width, s->lowres);
+ s->height = FF_CEIL_RSHIFT(height, s->lowres);
return ret;
}
@@ -177,18 +276,18 @@ int ff_side_data_update_matrix_encoding(AVFrame *frame,
return 0;
}
-#if HAVE_SIMD_ALIGN_16
-# define STRIDE_ALIGN 16
-#else
-# define STRIDE_ALIGN 8
-#endif
-
void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
int linesize_align[AV_NUM_DATA_POINTERS])
{
int i;
int w_align = 1;
int h_align = 1;
+ AVPixFmtDescriptor const *desc = av_pix_fmt_desc_get(s->pix_fmt);
+
+ if (desc) {
+ w_align = 1 << desc->log2_chroma_w;
+ h_align = 1 << desc->log2_chroma_h;
+ }
switch (s->pix_fmt) {
case AV_PIX_FMT_YUV420P:
@@ -214,47 +313,97 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
case AV_PIX_FMT_YUV420P9BE:
case AV_PIX_FMT_YUV420P10LE:
case AV_PIX_FMT_YUV420P10BE:
+ case AV_PIX_FMT_YUV420P12LE:
+ case AV_PIX_FMT_YUV420P12BE:
+ case AV_PIX_FMT_YUV420P14LE:
+ case AV_PIX_FMT_YUV420P14BE:
+ case AV_PIX_FMT_YUV420P16LE:
+ case AV_PIX_FMT_YUV420P16BE:
+ case AV_PIX_FMT_YUVA420P9LE:
+ case AV_PIX_FMT_YUVA420P9BE:
+ case AV_PIX_FMT_YUVA420P10LE:
+ case AV_PIX_FMT_YUVA420P10BE:
+ case AV_PIX_FMT_YUVA420P16LE:
+ case AV_PIX_FMT_YUVA420P16BE:
case AV_PIX_FMT_YUV422P9LE:
case AV_PIX_FMT_YUV422P9BE:
case AV_PIX_FMT_YUV422P10LE:
case AV_PIX_FMT_YUV422P10BE:
+ case AV_PIX_FMT_YUV422P12LE:
+ case AV_PIX_FMT_YUV422P12BE:
+ case AV_PIX_FMT_YUV422P14LE:
+ case AV_PIX_FMT_YUV422P14BE:
+ case AV_PIX_FMT_YUV422P16LE:
+ case AV_PIX_FMT_YUV422P16BE:
+ case AV_PIX_FMT_YUVA422P9LE:
+ case AV_PIX_FMT_YUVA422P9BE:
case AV_PIX_FMT_YUVA422P10LE:
case AV_PIX_FMT_YUVA422P10BE:
+ case AV_PIX_FMT_YUVA422P16LE:
+ case AV_PIX_FMT_YUVA422P16BE:
+ case AV_PIX_FMT_YUV440P10LE:
+ case AV_PIX_FMT_YUV440P10BE:
+ case AV_PIX_FMT_YUV440P12LE:
+ case AV_PIX_FMT_YUV440P12BE:
case AV_PIX_FMT_YUV444P9LE:
case AV_PIX_FMT_YUV444P9BE:
case AV_PIX_FMT_YUV444P10LE:
case AV_PIX_FMT_YUV444P10BE:
+ case AV_PIX_FMT_YUV444P12LE:
+ case AV_PIX_FMT_YUV444P12BE:
+ case AV_PIX_FMT_YUV444P14LE:
+ case AV_PIX_FMT_YUV444P14BE:
+ case AV_PIX_FMT_YUV444P16LE:
+ case AV_PIX_FMT_YUV444P16BE:
+ case AV_PIX_FMT_YUVA444P9LE:
+ case AV_PIX_FMT_YUVA444P9BE:
case AV_PIX_FMT_YUVA444P10LE:
case AV_PIX_FMT_YUVA444P10BE:
+ case AV_PIX_FMT_YUVA444P16LE:
+ case AV_PIX_FMT_YUVA444P16BE:
case AV_PIX_FMT_GBRP9LE:
case AV_PIX_FMT_GBRP9BE:
case AV_PIX_FMT_GBRP10LE:
case AV_PIX_FMT_GBRP10BE:
+ case AV_PIX_FMT_GBRP12LE:
+ case AV_PIX_FMT_GBRP12BE:
+ case AV_PIX_FMT_GBRP14LE:
+ case AV_PIX_FMT_GBRP14BE:
+ case AV_PIX_FMT_GBRP16LE:
+ case AV_PIX_FMT_GBRP16BE:
w_align = 16; //FIXME assume 16 pixel per macroblock
h_align = 16 * 2; // interlaced needs 2 macroblocks height
break;
case AV_PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUVJ411P:
case AV_PIX_FMT_UYYVYY411:
w_align = 32;
- h_align = 8;
+ h_align = 16 * 2;
break;
case AV_PIX_FMT_YUV410P:
if (s->codec_id == AV_CODEC_ID_SVQ1) {
w_align = 64;
h_align = 64;
}
+ break;
case AV_PIX_FMT_RGB555:
if (s->codec_id == AV_CODEC_ID_RPZA) {
w_align = 4;
h_align = 4;
}
+ break;
case AV_PIX_FMT_PAL8:
case AV_PIX_FMT_BGR8:
case AV_PIX_FMT_RGB8:
- if (s->codec_id == AV_CODEC_ID_SMC) {
+ if (s->codec_id == AV_CODEC_ID_SMC ||
+ s->codec_id == AV_CODEC_ID_CINEPAK) {
w_align = 4;
h_align = 4;
}
+ if (s->codec_id == AV_CODEC_ID_JV) {
+ w_align = 8;
+ h_align = 8;
+ }
break;
case AV_PIX_FMT_BGR24:
if ((s->codec_id == AV_CODEC_ID_MSZH) ||
@@ -263,16 +412,25 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height,
h_align = 4;
}
break;
+ case AV_PIX_FMT_RGB24:
+ if (s->codec_id == AV_CODEC_ID_CINEPAK) {
+ w_align = 4;
+ h_align = 4;
+ }
+ break;
default:
- w_align = 1;
- h_align = 1;
break;
}
+ if (s->codec_id == AV_CODEC_ID_IFF_ILBM || s->codec_id == AV_CODEC_ID_IFF_BYTERUN1) {
+ w_align = FFMAX(w_align, 8);
+ }
+
*width = FFALIGN(*width, w_align);
*height = FFALIGN(*height, h_align);
- if (s->codec_id == AV_CODEC_ID_H264)
+ if (s->codec_id == AV_CODEC_ID_H264 || s->lowres)
// some of the optimized chroma MC reads one line too much
+ // which is also done in mpeg decoders with lowres > 0
*height += 2;
for (i = 0; i < 4; i++)
@@ -294,6 +452,29 @@ void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height)
*width = FFALIGN(*width, align);
}
+int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos)
+{
+ if (pos <= AVCHROMA_LOC_UNSPECIFIED || pos >= AVCHROMA_LOC_NB)
+ return AVERROR(EINVAL);
+ pos--;
+
+ *xpos = (pos&1) * 128;
+ *ypos = ((pos>>1)^(pos<4)) * 128;
+
+ return 0;
+}
+
+enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos)
+{
+ int pos, xout, yout;
+
+ for (pos = AVCHROMA_LOC_UNSPECIFIED + 1; pos < AVCHROMA_LOC_NB; pos++) {
+ if (avcodec_enum_to_chroma_pos(&xout, &yout, pos) == 0 && xout == xpos && yout == ypos)
+ return pos;
+ }
+ return AVCHROMA_LOC_UNSPECIFIED;
+}
+
int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
enum AVSampleFormat sample_fmt, const uint8_t *buf,
int buf_size, int align)
@@ -308,7 +489,7 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
planar = av_sample_fmt_is_planar(sample_fmt);
if (planar && nb_channels > AV_NUM_DATA_POINTERS) {
- if (!(frame->extended_data = av_mallocz(nb_channels *
+ if (!(frame->extended_data = av_mallocz_array(nb_channels,
sizeof(*frame->extended_data))))
return AVERROR(ENOMEM);
} else {
@@ -316,10 +497,10 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
}
if ((ret = av_samples_fill_arrays(frame->extended_data, &frame->linesize[0],
- buf, nb_channels, frame->nb_samples,
+ (uint8_t *)(intptr_t)buf, nb_channels, frame->nb_samples,
sample_fmt, align)) < 0) {
if (frame->extended_data != frame->data)
- av_free(frame->extended_data);
+ av_freep(&frame->extended_data);
return ret;
}
if (frame->extended_data != frame->data) {
@@ -374,7 +555,10 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
av_buffer_pool_uninit(&pool->pools[i]);
pool->linesize[i] = picture.linesize[i];
if (size[i]) {
- pool->pools[i] = av_buffer_pool_init(size[i] + 16, NULL);
+ pool->pools[i] = av_buffer_pool_init(size[i] + 16 + STRIDE_ALIGN - 1,
+ CONFIG_MEMORY_POISONING ?
+ NULL :
+ av_buffer_allocz);
if (!pool->pools[i]) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -388,7 +572,7 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
break;
}
case AVMEDIA_TYPE_AUDIO: {
- int ch = av_get_channel_layout_nb_channels(frame->channel_layout);
+ int ch = av_frame_get_channels(frame); //av_get_channel_layout_nb_channels(frame->channel_layout);
int planar = av_sample_fmt_is_planar(frame->format);
int planes = planar ? ch : 1;
@@ -435,17 +619,19 @@ static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
frame->linesize[0] = pool->linesize[0];
if (planes > AV_NUM_DATA_POINTERS) {
- frame->extended_data = av_mallocz(planes * sizeof(*frame->extended_data));
+ frame->extended_data = av_mallocz_array(planes, sizeof(*frame->extended_data));
frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS;
- frame->extended_buf = av_mallocz(frame->nb_extended_buf *
+ frame->extended_buf = av_mallocz_array(frame->nb_extended_buf,
sizeof(*frame->extended_buf));
if (!frame->extended_data || !frame->extended_buf) {
av_freep(&frame->extended_data);
av_freep(&frame->extended_buf);
return AVERROR(ENOMEM);
}
- } else
+ } else {
frame->extended_data = frame->data;
+ av_assert0(frame->nb_extended_buf == 0);
+ }
for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) {
frame->buf[i] = av_buffer_pool_get(pool->pools[0]);
@@ -507,6 +693,29 @@ fail:
return AVERROR(ENOMEM);
}
+void avpriv_color_frame(AVFrame *frame, const int c[4])
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+ int p, y, x;
+
+ av_assert0(desc->flags & AV_PIX_FMT_FLAG_PLANAR);
+
+ for (p = 0; p<desc->nb_components; p++) {
+ uint8_t *dst = frame->data[p];
+ int is_chroma = p == 1 || p == 2;
+ int bytes = is_chroma ? FF_CEIL_RSHIFT(frame->width, desc->log2_chroma_w) : frame->width;
+ int height = is_chroma ? FF_CEIL_RSHIFT(frame->height, desc->log2_chroma_h) : frame->height;
+ for (y = 0; y < height; y++) {
+ if (desc->comp[0].depth_minus1 >= 8) {
+ for (x = 0; x<bytes; x++)
+ ((uint16_t*)dst)[x] = c[p];
+ }else
+ memset(dst, c[p], bytes);
+ dst += frame->linesize[p];
+ }
+ }
+}
+
int avcodec_default_get_buffer2(AVCodecContext *avctx, AVFrame *frame, int flags)
{
int ret;
@@ -530,39 +739,11 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
}
-#if FF_API_GET_BUFFER
-FF_DISABLE_DEPRECATION_WARNINGS
-int avcodec_default_get_buffer(AVCodecContext *avctx, AVFrame *frame)
-{
- return avcodec_default_get_buffer2(avctx, frame, 0);
-}
-
-typedef struct CompatReleaseBufPriv {
- AVCodecContext avctx;
- AVFrame frame;
-} CompatReleaseBufPriv;
-
-static void compat_free_buffer(void *opaque, uint8_t *data)
-{
- CompatReleaseBufPriv *priv = opaque;
- if (priv->avctx.release_buffer)
- priv->avctx.release_buffer(&priv->avctx, &priv->frame);
- av_freep(&priv);
-}
-
-static void compat_release_buffer(void *opaque, uint8_t *data)
-{
- AVBufferRef *buf = opaque;
- av_buffer_unref(&buf);
-}
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
-
-int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
+int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame)
{
AVPacket *pkt = avctx->internal->pkt;
int i;
- struct {
+ static const struct {
enum AVPacketSideDataType packet;
enum AVFrameSideDataType frame;
} sd[] = {
@@ -572,56 +753,52 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
{ AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE },
};
- frame->color_primaries = avctx->color_primaries;
- frame->color_trc = avctx->color_trc;
- frame->colorspace = avctx->colorspace;
- frame->color_range = avctx->color_range;
- frame->chroma_location = avctx->chroma_sample_location;
-
- frame->reordered_opaque = avctx->reordered_opaque;
- if (!pkt) {
- frame->pkt_pts = AV_NOPTS_VALUE;
- return 0;
- }
-
- frame->pkt_pts = pkt->pts;
-
- for (i = 0; i < FF_ARRAY_ELEMS(sd); i++) {
- int 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);
-
- memcpy(frame_sd->data, packet_sd, size);
+ if (pkt) {
+ frame->pkt_pts = pkt->pts;
+ av_frame_set_pkt_pos (frame, pkt->pos);
+ av_frame_set_pkt_duration(frame, pkt->duration);
+ av_frame_set_pkt_size (frame, pkt->size);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(sd); i++) {
+ int 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);
+
+ memcpy(frame_sd->data, packet_sd, size);
+ }
}
+ } else {
+ frame->pkt_pts = AV_NOPTS_VALUE;
+ av_frame_set_pkt_pos (frame, -1);
+ av_frame_set_pkt_duration(frame, 0);
+ av_frame_set_pkt_size (frame, -1);
}
+ frame->reordered_opaque = avctx->reordered_opaque;
- return 0;
-}
-
-int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
-{
- const AVHWAccel *hwaccel = avctx->hwaccel;
- int override_dimensions = 1;
- int ret;
-
- switch (avctx->codec_type) {
+ if (frame->color_primaries == AVCOL_PRI_UNSPECIFIED)
+ frame->color_primaries = avctx->color_primaries;
+ if (frame->color_trc == AVCOL_TRC_UNSPECIFIED)
+ frame->color_trc = avctx->color_trc;
+ if (av_frame_get_colorspace(frame) == AVCOL_SPC_UNSPECIFIED)
+ av_frame_set_colorspace(frame, avctx->colorspace);
+ if (av_frame_get_color_range(frame) == AVCOL_RANGE_UNSPECIFIED)
+ av_frame_set_color_range(frame, avctx->color_range);
+ if (frame->chroma_location == AVCHROMA_LOC_UNSPECIFIED)
+ frame->chroma_location = avctx->chroma_sample_location;
+
+ switch (avctx->codec->type) {
case AVMEDIA_TYPE_VIDEO:
- if (frame->width <= 0 || frame->height <= 0) {
- frame->width = FFMAX(avctx->width, avctx->coded_width);
- frame->height = FFMAX(avctx->height, avctx->coded_height);
- override_dimensions = 0;
- }
- if (frame->format < 0)
- frame->format = avctx->pix_fmt;
+ frame->format = avctx->pix_fmt;
if (!frame->sample_aspect_ratio.num)
frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
- if (av_image_check_sar(frame->width, frame->height,
+ if (frame->width && frame->height &&
+ av_image_check_sar(frame->width, frame->height,
frame->sample_aspect_ratio) < 0) {
av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n",
frame->sample_aspect_ratio.num,
@@ -629,8 +806,6 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
}
- if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
- return ret;
break;
case AVMEDIA_TYPE_AUDIO:
if (!frame->sample_rate)
@@ -653,19 +828,72 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
avctx->channels);
return AVERROR(ENOSYS);
}
-
- frame->channel_layout = av_get_default_channel_layout(avctx->channels);
- if (!frame->channel_layout)
- frame->channel_layout = (1ULL << avctx->channels) - 1;
}
}
+ av_frame_set_channels(frame, avctx->channels);
break;
- default: return AVERROR(EINVAL);
}
+ return 0;
+}
+
+#if FF_API_GET_BUFFER
+FF_DISABLE_DEPRECATION_WARNINGS
+int avcodec_default_get_buffer(AVCodecContext *avctx, AVFrame *frame)
+{
+ return avcodec_default_get_buffer2(avctx, frame, 0);
+}
+
+typedef struct CompatReleaseBufPriv {
+ AVCodecContext avctx;
+ AVFrame frame;
+ uint8_t avframe_padding[1024]; // hack to allow linking to a avutil with larger AVFrame
+} CompatReleaseBufPriv;
+static void compat_free_buffer(void *opaque, uint8_t *data)
+{
+ CompatReleaseBufPriv *priv = opaque;
+ if (priv->avctx.release_buffer)
+ priv->avctx.release_buffer(&priv->avctx, &priv->frame);
+ av_freep(&priv);
+}
+
+static void compat_release_buffer(void *opaque, uint8_t *data)
+{
+ AVBufferRef *buf = opaque;
+ av_buffer_unref(&buf);
+}
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
+{
+ return ff_init_buffer_info(avctx, frame);
+}
+
+static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags)
+{
+ const AVHWAccel *hwaccel = avctx->hwaccel;
+ int override_dimensions = 1;
+ int ret;
+
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0 || avctx->pix_fmt<0) {
+ av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (frame->width <= 0 || frame->height <= 0) {
+ frame->width = FFMAX(avctx->width, FF_CEIL_RSHIFT(avctx->coded_width, avctx->lowres));
+ frame->height = FFMAX(avctx->height, FF_CEIL_RSHIFT(avctx->coded_height, avctx->lowres));
+ override_dimensions = 0;
+ }
+ }
ret = ff_decode_frame_props(avctx, frame);
if (ret < 0)
return ret;
+ if ((ret = ff_init_buffer_info(avctx, frame)) < 0)
+ return ret;
if (hwaccel) {
if (hwaccel->alloc_frame) {
@@ -678,7 +906,7 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
#if FF_API_GET_BUFFER
FF_DISABLE_DEPRECATION_WARNINGS
/*
- * Wrap an old get_buffer()-allocated buffer in an bunch of AVBuffers.
+ * Wrap an old get_buffer()-allocated buffer in a bunch of AVBuffers.
* We wrap each plane in its own AVBuffer. Each of those has a reference to
* a dummy AVBuffer as its private data, unreffing it on free.
* When all the planes are freed, the dummy buffer's free callback calls
@@ -701,7 +929,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
* avcodec_default_get_buffer
*/
if (frame->buf[0])
- return 0;
+ goto end0;
priv = av_mallocz(sizeof(*priv));
if (!priv) {
@@ -759,7 +987,7 @@ do { \
if (planes > FF_ARRAY_ELEMS(frame->buf)) {
frame->nb_extended_buf = planes - FF_ARRAY_ELEMS(frame->buf);
- frame->extended_buf = av_malloc(sizeof(*frame->extended_buf) *
+ frame->extended_buf = av_malloc_array(sizeof(*frame->extended_buf),
frame->nb_extended_buf);
if (!frame->extended_buf) {
ret = AVERROR(ENOMEM);
@@ -778,6 +1006,7 @@ do { \
av_buffer_unref(&dummy_buf);
+end0:
frame->width = avctx->width;
frame->height = avctx->height;
@@ -803,13 +1032,29 @@ end:
return ret;
}
-int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame)
+int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
+{
+ int ret = get_buffer_internal(avctx, frame, flags);
+ if (ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ return ret;
+}
+
+static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame)
{
AVFrame *tmp;
int ret;
av_assert0(avctx->codec_type == AVMEDIA_TYPE_VIDEO);
+ 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));
+ av_frame_unref(frame);
+ }
+
+ ff_init_buffer_info(avctx, frame);
+
if (!frame->data[0])
return ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF);
@@ -834,9 +1079,19 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame)
return 0;
}
+int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame)
+{
+ int ret = reget_buffer_internal(avctx, frame);
+ if (ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ return ret;
+}
+
#if FF_API_GET_BUFFER
void avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic)
{
+ av_assert0(s->codec_type == AVMEDIA_TYPE_VIDEO);
+
av_frame_unref(pic);
}
@@ -871,6 +1126,17 @@ int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2,
return 0;
}
+enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags,
+ unsigned int fourcc)
+{
+ while (tags->pix_fmt >= 0) {
+ if (tags->fourcc == fourcc)
+ return tags->pix_fmt;
+ tags++;
+ }
+ return AV_PIX_FMT_NONE;
+}
+
static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -965,6 +1231,8 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
break;
+ if (avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+ break;
if (!setup_hwaccel(avctx, ret, desc->name))
break;
@@ -985,30 +1253,20 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
#if FF_API_AVFRAME_LAVC
void avcodec_get_frame_defaults(AVFrame *frame)
{
- if (frame->extended_data != frame->data)
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+ // extended_data should explicitly be freed when needed, this code is unsafe currently
+ // also this is not compatible to the <55 ABI/API
+ if (frame->extended_data != frame->data && 0)
av_freep(&frame->extended_data);
+#endif
memset(frame, 0, sizeof(AVFrame));
-
- frame->pts = AV_NOPTS_VALUE;
- frame->key_frame = 1;
- frame->sample_aspect_ratio = (AVRational) {0, 1 };
- frame->format = -1; /* unknown */
- frame->extended_data = frame->data;
+ av_frame_unref(frame);
}
AVFrame *avcodec_alloc_frame(void)
{
- AVFrame *frame = av_mallocz(sizeof(AVFrame));
-
- if (!frame)
- return NULL;
-
-FF_DISABLE_DEPRECATION_WARNINGS
- avcodec_get_frame_defaults(frame);
-FF_ENABLE_DEPRECATION_WARNINGS
-
- return frame;
+ return av_frame_alloc();
}
void avcodec_free_frame(AVFrame **frame)
@@ -1017,6 +1275,58 @@ void avcodec_free_frame(AVFrame **frame)
}
#endif
+MAKE_ACCESSORS(AVCodecContext, codec, AVRational, pkt_timebase)
+MAKE_ACCESSORS(AVCodecContext, codec, const AVCodecDescriptor *, codec_descriptor)
+MAKE_ACCESSORS(AVCodecContext, codec, int, lowres)
+MAKE_ACCESSORS(AVCodecContext, codec, int, seek_preroll)
+MAKE_ACCESSORS(AVCodecContext, codec, uint16_t*, chroma_intra_matrix)
+
+int av_codec_get_max_lowres(const AVCodec *codec)
+{
+ return codec->max_lowres;
+}
+
+static void get_subtitle_defaults(AVSubtitle *sub)
+{
+ memset(sub, 0, sizeof(*sub));
+ sub->pts = AV_NOPTS_VALUE;
+}
+
+static int get_bit_rate(AVCodecContext *ctx)
+{
+ int bit_rate;
+ int bits_per_sample;
+
+ switch (ctx->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_DATA:
+ case AVMEDIA_TYPE_SUBTITLE:
+ case AVMEDIA_TYPE_ATTACHMENT:
+ bit_rate = ctx->bit_rate;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ bits_per_sample = av_get_bits_per_sample(ctx->codec_id);
+ bit_rate = bits_per_sample ? ctx->sample_rate * ctx->channels * bits_per_sample : ctx->bit_rate;
+ break;
+ default:
+ bit_rate = 0;
+ break;
+ }
+ return bit_rate;
+}
+
+int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
+{
+ int ret = 0;
+
+ ff_unlock_avcodec();
+
+ ret = avcodec_open2(avctx, codec, options);
+
+ ff_lock_avcodec(avctx, codec);
+ return ret;
+}
+
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
{
int ret = 0;
@@ -1026,12 +1336,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
return 0;
if ((!codec && !avctx->codec)) {
- av_log(avctx, AV_LOG_ERROR, "No codec provided to avcodec_open2().\n");
+ av_log(avctx, AV_LOG_ERROR, "No codec provided to avcodec_open2()\n");
return AVERROR(EINVAL);
}
if ((codec && avctx->codec && codec != avctx->codec)) {
av_log(avctx, AV_LOG_ERROR, "This AVCodecContext was allocated for %s, "
- "but %s passed to avcodec_open2().\n", avctx->codec->name, codec->name);
+ "but %s passed to avcodec_open2()\n", avctx->codec->name, codec->name);
return AVERROR(EINVAL);
}
if (!codec)
@@ -1043,22 +1353,9 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
if (options)
av_dict_copy(&tmp, *options, 0);
- /* If there is a user-supplied mutex locking routine, call it. */
- if (lockmgr_cb) {
- if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
- return -1;
- }
-
- entangled_thread_counter++;
- if (entangled_thread_counter != 1 &&
- !(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE)) {
- av_log(avctx, AV_LOG_ERROR,
- "Insufficient thread locking. At least %d threads are "
- "calling avcodec_open2() at the same time right now.\n",
- entangled_thread_counter);
- ret = -1;
- goto end;
- }
+ ret = ff_lock_avcodec(avctx, codec);
+ if (ret < 0)
+ return ret;
avctx->internal = av_mallocz(sizeof(AVCodecInternal));
if (!avctx->internal) {
@@ -1098,17 +1395,27 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
if ((ret = av_opt_set_dict(avctx, &tmp)) < 0)
goto free_and_end;
- if (avctx->coded_width && avctx->coded_height && !avctx->width && !avctx->height)
+ if (avctx->codec_whitelist && av_match_list(codec->name, avctx->codec_whitelist, ',') <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "Codec (%s) not on whitelist\n", codec->name);
+ ret = AVERROR(EINVAL);
+ goto free_and_end;
+ }
+
+ // only call ff_set_dimensions() for non H.264/VP6F codecs so as not to overwrite previously setup dimensions
+ if (!(avctx->coded_width && avctx->coded_height && avctx->width && avctx->height &&
+ (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_VP6F))) {
+ if (avctx->coded_width && avctx->coded_height)
ret = ff_set_dimensions(avctx, avctx->coded_width, avctx->coded_height);
else if (avctx->width && avctx->height)
ret = ff_set_dimensions(avctx, avctx->width, avctx->height);
if (ret < 0)
goto free_and_end;
+ }
if ((avctx->coded_width || avctx->coded_height || avctx->width || avctx->height)
&& ( av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx) < 0
|| av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0)) {
- av_log(avctx, AV_LOG_WARNING, "ignoring invalid width/height values\n");
+ av_log(avctx, AV_LOG_WARNING, "Ignoring invalid width/height values\n");
ff_set_dimensions(avctx, 0, 0);
}
@@ -1140,14 +1447,25 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
}
if (avctx->codec_id != codec->id || (avctx->codec_type != codec->type
&& avctx->codec_type != AVMEDIA_TYPE_ATTACHMENT)) {
- av_log(avctx, AV_LOG_ERROR, "codec type or id mismatches\n");
+ av_log(avctx, AV_LOG_ERROR, "Codec type or id mismatches\n");
ret = AVERROR(EINVAL);
goto free_and_end;
}
avctx->frame_number = 0;
+ avctx->codec_descriptor = avcodec_descriptor_get(avctx->codec_id);
if (avctx->codec->capabilities & CODEC_CAP_EXPERIMENTAL &&
avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+ const char *codec_string = av_codec_is_encoder(codec) ? "encoder" : "decoder";
+ AVCodec *codec2;
+ av_log(avctx, AV_LOG_ERROR,
+ "The %s '%s' is experimental but experimental codecs are not enabled, "
+ "add '-strict %d' if you want to use it.\n",
+ codec_string, codec->name, FF_COMPLIANCE_EXPERIMENTAL);
+ codec2 = av_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id);
+ if (!(codec2->capabilities & CODEC_CAP_EXPERIMENTAL))
+ av_log(avctx, AV_LOG_ERROR, "Alternatively use the non experimental %s '%s'.\n",
+ codec_string, codec2->name);
ret = AVERROR_EXPERIMENTAL;
goto free_and_end;
}
@@ -1158,7 +1476,19 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
avctx->time_base.den = avctx->sample_rate;
}
- if (HAVE_THREADS) {
+ if (!HAVE_THREADS)
+ av_log(avctx, AV_LOG_WARNING, "Warning: not compiled with thread support, using thread emulation\n");
+
+ if (CONFIG_FRAME_THREAD_ENCODER) {
+ ff_unlock_avcodec(); //we will instanciate a few encoders thus kick the counter to prevent false detection of a problem
+ ret = ff_frame_thread_encoder_init(avctx, options ? *options : NULL);
+ ff_lock_avcodec(avctx, codec);
+ if (ret < 0)
+ goto free_and_end;
+ }
+
+ if (HAVE_THREADS
+ && !(avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) {
ret = ff_thread_init(avctx);
if (ret < 0) {
goto free_and_end;
@@ -1167,6 +1497,19 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
if (!HAVE_THREADS && !(codec->capabilities & CODEC_CAP_AUTO_THREADS))
avctx->thread_count = 1;
+ if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) {
+ av_log(avctx, AV_LOG_ERROR, "The maximum value for lowres supported by the decoder is %d\n",
+ avctx->codec->max_lowres);
+ ret = AVERROR(EINVAL);
+ goto free_and_end;
+ }
+
+#if FF_API_VISMV
+ if (avctx->debug_mv)
+ av_log(avctx, AV_LOG_WARNING, "The 'vismv' option is deprecated, "
+ "see the codecview filter instead.\n");
+#endif
+
if (av_codec_is_encoder(avctx->codec)) {
int i;
if (avctx->codec->sample_fmts) {
@@ -1181,7 +1524,10 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
}
}
if (avctx->codec->sample_fmts[i] == AV_SAMPLE_FMT_NONE) {
- av_log(avctx, AV_LOG_ERROR, "Specified sample_fmt is not supported.\n");
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%d", avctx->sample_fmt);
+ av_log(avctx, AV_LOG_ERROR, "Specified sample format %s is invalid or not supported\n",
+ (char *)av_x_if_null(av_get_sample_fmt_name(avctx->sample_fmt), buf));
ret = AVERROR(EINVAL);
goto free_and_end;
}
@@ -1190,12 +1536,18 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
for (i = 0; avctx->codec->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
if (avctx->pix_fmt == avctx->codec->pix_fmts[i])
break;
- if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE) {
- av_log(avctx, AV_LOG_ERROR, "Specified pix_fmt is not supported\n");
+ if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE
+ && !((avctx->codec_id == AV_CODEC_ID_MJPEG || avctx->codec_id == AV_CODEC_ID_LJPEG)
+ && avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%d", avctx->pix_fmt);
+ av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is invalid or not supported\n",
+ (char *)av_x_if_null(av_get_pix_fmt_name(avctx->pix_fmt), buf));
ret = AVERROR(EINVAL);
goto free_and_end;
}
if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ420P ||
+ avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ411P ||
avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ422P ||
avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ440P ||
avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ444P)
@@ -1206,60 +1558,98 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
if (avctx->sample_rate == avctx->codec->supported_samplerates[i])
break;
if (avctx->codec->supported_samplerates[i] == 0) {
- av_log(avctx, AV_LOG_ERROR, "Specified sample_rate is not supported\n");
+ av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported\n",
+ avctx->sample_rate);
ret = AVERROR(EINVAL);
goto free_and_end;
}
}
if (avctx->codec->channel_layouts) {
if (!avctx->channel_layout) {
- av_log(avctx, AV_LOG_WARNING, "channel_layout not specified\n");
+ av_log(avctx, AV_LOG_WARNING, "Channel layout not specified\n");
} else {
for (i = 0; avctx->codec->channel_layouts[i] != 0; i++)
if (avctx->channel_layout == avctx->codec->channel_layouts[i])
break;
if (avctx->codec->channel_layouts[i] == 0) {
- av_log(avctx, AV_LOG_ERROR, "Specified channel_layout is not supported\n");
+ char buf[512];
+ av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
+ av_log(avctx, AV_LOG_ERROR, "Specified channel layout '%s' is not supported\n", buf);
ret = AVERROR(EINVAL);
goto free_and_end;
}
}
}
if (avctx->channel_layout && avctx->channels) {
- if (av_get_channel_layout_nb_channels(avctx->channel_layout) != avctx->channels) {
- av_log(avctx, AV_LOG_ERROR, "channel layout does not match number of channels\n");
+ int channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
+ if (channels != avctx->channels) {
+ char buf[512];
+ av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
+ av_log(avctx, AV_LOG_ERROR,
+ "Channel layout '%s' with %d channels does not match number of specified channels %d\n",
+ buf, channels, avctx->channels);
ret = AVERROR(EINVAL);
goto free_and_end;
}
} else if (avctx->channel_layout) {
avctx->channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
}
+ if(avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (avctx->width <= 0 || avctx->height <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "dimensions not set\n");
+ ret = AVERROR(EINVAL);
+ goto free_and_end;
+ }
+ }
+ if ( (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ && avctx->bit_rate>0 && avctx->bit_rate<1000) {
+ av_log(avctx, AV_LOG_WARNING, "Bitrate %d is extremely low, maybe you mean %dk\n", avctx->bit_rate, avctx->bit_rate);
+ }
if (!avctx->rc_initial_buffer_occupancy)
avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3 / 4;
}
- if (avctx->codec->init && !(avctx->active_thread_type & FF_THREAD_FRAME)) {
+ avctx->pts_correction_num_faulty_pts =
+ avctx->pts_correction_num_faulty_dts = 0;
+ avctx->pts_correction_last_pts =
+ avctx->pts_correction_last_dts = INT64_MIN;
+
+ if ( !CONFIG_GRAY && avctx->flags & CODEC_FLAG_GRAY
+ && avctx->codec_descriptor->type == AVMEDIA_TYPE_VIDEO)
+ av_log(avctx, AV_LOG_WARNING,
+ "gray decoding requested but not enabled at configuration time\n");
+
+ if ( avctx->codec->init && (!(avctx->active_thread_type&FF_THREAD_FRAME)
+ || avctx->internal->frame_thread_encoder)) {
ret = avctx->codec->init(avctx);
if (ret < 0) {
goto free_and_end;
}
}
+ ret=0;
+
#if FF_API_AUDIOENC_DELAY
if (av_codec_is_encoder(avctx->codec))
avctx->delay = avctx->initial_padding;
#endif
if (av_codec_is_decoder(avctx->codec)) {
+ if (!avctx->bit_rate)
+ avctx->bit_rate = get_bit_rate(avctx);
/* validate channel layout from the decoder */
if (avctx->channel_layout) {
int channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
if (!avctx->channels)
avctx->channels = channels;
else if (channels != avctx->channels) {
+ char buf[512];
+ av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
av_log(avctx, AV_LOG_WARNING,
- "channel layout does not match number of channels\n");
+ "Channel layout '%s' with %d channels does not match specified number of channels %d: "
+ "ignoring specified channel layout\n",
+ buf, channels, avctx->channels);
avctx->channel_layout = 0;
}
}
@@ -1268,19 +1658,55 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code
ret = AVERROR(EINVAL);
goto free_and_end;
}
+ if (avctx->sub_charenc) {
+ if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ av_log(avctx, AV_LOG_ERROR, "Character encoding is only "
+ "supported with subtitles codecs\n");
+ ret = AVERROR(EINVAL);
+ goto free_and_end;
+ } else if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) {
+ av_log(avctx, AV_LOG_WARNING, "Codec '%s' is bitmap-based, "
+ "subtitles character encoding will be ignored\n",
+ avctx->codec_descriptor->name);
+ avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_DO_NOTHING;
+ } else {
+ /* input character encoding is set for a text based subtitle
+ * codec at this point */
+ if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_AUTOMATIC)
+ avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_PRE_DECODER;
+
+ if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_PRE_DECODER) {
+#if CONFIG_ICONV
+ iconv_t cd = iconv_open("UTF-8", avctx->sub_charenc);
+ if (cd == (iconv_t)-1) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context "
+ "with input character encoding \"%s\"\n", avctx->sub_charenc);
+ goto free_and_end;
+ }
+ iconv_close(cd);
+#else
+ av_log(avctx, AV_LOG_ERROR, "Character encoding subtitles "
+ "conversion needs a libavcodec built with iconv support "
+ "for this codec\n");
+ ret = AVERROR(ENOSYS);
+ goto free_and_end;
+#endif
+ }
+ }
+ }
#if FF_API_AVCTX_TIMEBASE
if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
- avctx->time_base = av_inv_q(avctx->framerate);
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
#endif
}
-end:
- entangled_thread_counter--;
-
- /* Release any user-supplied mutex. */
- if (lockmgr_cb) {
- (*lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE);
+ if (codec->priv_data_size > 0 && avctx->priv_data && codec->priv_class) {
+ av_assert0(*(const AVClass **)avctx->priv_data == codec->priv_class);
}
+
+end:
+ ff_unlock_avcodec();
if (options) {
av_dict_free(options);
*options = tmp;
@@ -1292,7 +1718,7 @@ free_and_end:
(avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP))
avctx->codec->close(avctx);
- if (avctx->priv_data && avctx->codec && avctx->codec->priv_class)
+ if (codec->priv_class && codec->priv_data_size)
av_opt_free(avctx->priv_data);
av_opt_free(avctx);
@@ -1307,10 +1733,31 @@ free_and_end:
goto end;
}
-int ff_alloc_packet(AVPacket *avpkt, int size)
+int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size)
{
- if (size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
+ if (avpkt->size < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid negative user packet size %d\n", avpkt->size);
+ return AVERROR(EINVAL);
+ }
+ if (size < 0 || size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid minimum required packet size %"PRId64" (max allowed is %d)\n",
+ size, INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE);
return AVERROR(EINVAL);
+ }
+
+ if (avctx) {
+ av_assert0(!avpkt->data || avpkt->data != avctx->internal->byte_buffer);
+ if (!avpkt->data || avpkt->size < size) {
+ av_fast_padded_malloc(&avctx->internal->byte_buffer, &avctx->internal->byte_buffer_size, size);
+ avpkt->data = avctx->internal->byte_buffer;
+ avpkt->size = avctx->internal->byte_buffer_size;
+#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
+ avpkt->destruct = NULL;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ }
+ }
if (avpkt->data) {
AVBufferRef *buf = avpkt->buf;
@@ -1320,8 +1767,10 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
#endif
- if (avpkt->size < size)
+ if (avpkt->size < size) {
+ av_log(avctx, AV_LOG_ERROR, "User packet is too small (%d < %"PRId64")\n", avpkt->size, size);
return AVERROR(EINVAL);
+ }
av_init_packet(avpkt);
#if FF_API_DESTRUCT_PACKET
@@ -1333,10 +1782,18 @@ FF_ENABLE_DEPRECATION_WARNINGS
avpkt->size = size;
return 0;
} else {
- return av_new_packet(avpkt, size);
+ int ret = av_new_packet(avpkt, size);
+ if (ret < 0)
+ av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet of size %"PRId64"\n", size);
+ return ret;
}
}
+int ff_alloc_packet(AVPacket *avpkt, int size)
+{
+ return ff_alloc_packet2(NULL, avpkt, size);
+}
+
/**
* Pad last frame with silence.
*/
@@ -1350,6 +1807,7 @@ static int pad_last_frame(AVCodecContext *s, AVFrame **dst, const AVFrame *src)
frame->format = src->format;
frame->channel_layout = src->channel_layout;
+ av_frame_set_channels(frame, av_frame_get_channels(src));
frame->nb_samples = s->frame_size;
ret = av_frame_get_buffer(frame, 32);
if (ret < 0)
@@ -1381,10 +1839,11 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
const AVFrame *frame,
int *got_packet_ptr)
{
- AVFrame tmp;
+ AVFrame *extended_frame = NULL;
AVFrame *padded_frame = NULL;
int ret;
- int user_packet = !!avpkt->data;
+ AVPacket user_pkt = *avpkt;
+ int needs_realloc = !user_pkt.data;
*got_packet_ptr = 0;
@@ -1405,9 +1864,13 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
}
av_log(avctx, AV_LOG_WARNING, "extended_data is not set.\n");
- tmp = *frame;
- tmp.extended_data = tmp.data;
- frame = &tmp;
+ extended_frame = av_frame_alloc();
+ if (!extended_frame)
+ return AVERROR(ENOMEM);
+
+ memcpy(extended_frame, frame, sizeof(AVFrame));
+ extended_frame->extended_data = extended_frame->data;
+ frame = extended_frame;
}
/* extract audio service type metadata */
@@ -1420,20 +1883,24 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
/* check for valid frame size */
if (frame) {
if (avctx->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
- if (frame->nb_samples > avctx->frame_size)
- return AVERROR(EINVAL);
+ if (frame->nb_samples > avctx->frame_size) {
+ av_log(avctx, AV_LOG_ERROR, "more samples than frame size (avcodec_encode_audio2)\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
} else if (!(avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
if (frame->nb_samples < avctx->frame_size &&
!avctx->internal->last_audio_frame) {
ret = pad_last_frame(avctx, &padded_frame, frame);
if (ret < 0)
- return ret;
+ goto end;
frame = padded_frame;
avctx->internal->last_audio_frame = 1;
}
if (frame->nb_samples != avctx->frame_size) {
+ av_log(avctx, AV_LOG_ERROR, "nb_samples (%d) != frame_size (%d) (avcodec_encode_audio2)\n", frame->nb_samples, avctx->frame_size);
ret = AVERROR(EINVAL);
goto end;
}
@@ -1454,9 +1921,34 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
} else {
avpkt->size = 0;
}
+ }
+ if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) {
+ needs_realloc = 0;
+ if (user_pkt.data) {
+ if (user_pkt.size >= avpkt->size) {
+ memcpy(user_pkt.data, avpkt->data, avpkt->size);
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size);
+ avpkt->size = user_pkt.size;
+ ret = -1;
+ }
+ avpkt->buf = user_pkt.buf;
+ avpkt->data = user_pkt.data;
+#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
+ avpkt->destruct = user_pkt.destruct;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ } else {
+ if (av_dup_packet(avpkt) < 0) {
+ ret = AVERROR(ENOMEM);
+ }
+ }
+ }
- if (!user_packet && avpkt->size) {
- ret = av_buffer_realloc(&avpkt->buf, avpkt->size);
+ if (!ret) {
+ if (needs_realloc && avpkt->data) {
+ ret = av_buffer_realloc(&avpkt->buf, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
if (ret >= 0)
avpkt->data = avpkt->buf->data;
}
@@ -1477,6 +1969,7 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
end:
av_frame_free(&padded_frame);
+ av_free(extended_frame);
#if FF_API_AUDIOENC_DELAY
avctx->delay = avctx->initial_padding;
@@ -1485,16 +1978,144 @@ end:
return ret;
}
+#if FF_API_OLD_ENCODE_AUDIO
+int attribute_align_arg avcodec_encode_audio(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size,
+ const short *samples)
+{
+ AVPacket pkt;
+ AVFrame *frame;
+ int ret, samples_size, got_packet;
+
+ av_init_packet(&pkt);
+ pkt.data = buf;
+ pkt.size = buf_size;
+
+ if (samples) {
+ frame = av_frame_alloc();
+ if (!frame)
+ return AVERROR(ENOMEM);
+
+ if (avctx->frame_size) {
+ frame->nb_samples = avctx->frame_size;
+ } else {
+ /* if frame_size is not set, the number of samples must be
+ * calculated from the buffer size */
+ int64_t nb_samples;
+ if (!av_get_bits_per_sample(avctx->codec_id)) {
+ av_log(avctx, AV_LOG_ERROR, "avcodec_encode_audio() does not "
+ "support this codec\n");
+ av_frame_free(&frame);
+ return AVERROR(EINVAL);
+ }
+ nb_samples = (int64_t)buf_size * 8 /
+ (av_get_bits_per_sample(avctx->codec_id) *
+ avctx->channels);
+ if (nb_samples >= INT_MAX) {
+ av_frame_free(&frame);
+ return AVERROR(EINVAL);
+ }
+ frame->nb_samples = nb_samples;
+ }
+
+ /* it is assumed that the samples buffer is large enough based on the
+ * relevant parameters */
+ samples_size = av_samples_get_buffer_size(NULL, avctx->channels,
+ frame->nb_samples,
+ avctx->sample_fmt, 1);
+ if ((ret = avcodec_fill_audio_frame(frame, avctx->channels,
+ avctx->sample_fmt,
+ (const uint8_t *)samples,
+ samples_size, 1)) < 0) {
+ av_frame_free(&frame);
+ return ret;
+ }
+
+ /* fabricate frame pts from sample count.
+ * this is needed because the avcodec_encode_audio() API does not have
+ * a way for the user to provide pts */
+ if (avctx->sample_rate && avctx->time_base.num)
+ frame->pts = ff_samples_to_time_base(avctx,
+ avctx->internal->sample_count);
+ else
+ frame->pts = AV_NOPTS_VALUE;
+ avctx->internal->sample_count += frame->nb_samples;
+ } else {
+ frame = NULL;
+ }
+
+ got_packet = 0;
+ ret = avcodec_encode_audio2(avctx, &pkt, frame, &got_packet);
+ if (!ret && got_packet && avctx->coded_frame) {
+ avctx->coded_frame->pts = pkt.pts;
+ avctx->coded_frame->key_frame = !!(pkt.flags & AV_PKT_FLAG_KEY);
+ }
+ /* free any side data since we cannot return it */
+ av_packet_free_side_data(&pkt);
+
+ if (frame && frame->extended_data != frame->data)
+ av_freep(&frame->extended_data);
+
+ av_frame_free(&frame);
+ return ret ? ret : pkt.size;
+}
+
+#endif
+
+#if FF_API_OLD_ENCODE_VIDEO
+int attribute_align_arg avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
+ const AVFrame *pict)
+{
+ AVPacket pkt;
+ int ret, got_packet = 0;
+
+ if (buf_size < FF_MIN_BUFFER_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "buffer smaller than minimum size\n");
+ return -1;
+ }
+
+ av_init_packet(&pkt);
+ pkt.data = buf;
+ pkt.size = buf_size;
+
+ ret = avcodec_encode_video2(avctx, &pkt, pict, &got_packet);
+ if (!ret && got_packet && avctx->coded_frame) {
+ avctx->coded_frame->pts = pkt.pts;
+ avctx->coded_frame->key_frame = !!(pkt.flags & AV_PKT_FLAG_KEY);
+ }
+
+ /* free any side data since we cannot return it */
+ if (pkt.side_data_elems > 0) {
+ int i;
+ for (i = 0; i < pkt.side_data_elems; i++)
+ av_free(pkt.side_data[i].data);
+ av_freep(&pkt.side_data);
+ pkt.side_data_elems = 0;
+ }
+
+ return ret ? ret : pkt.size;
+}
+
+#endif
+
int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,
AVPacket *avpkt,
const AVFrame *frame,
int *got_packet_ptr)
{
int ret;
- int user_packet = !!avpkt->data;
+ AVPacket user_pkt = *avpkt;
+ int needs_realloc = !user_pkt.data;
*got_packet_ptr = 0;
+ if(CONFIG_FRAME_THREAD_ENCODER &&
+ avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))
+ return ff_thread_video_encode_frame(avctx, avpkt, frame, got_packet_ptr);
+
+ if ((avctx->flags&CODEC_FLAG_PASS1) && avctx->stats_out)
+ avctx->stats_out[0] = '\0';
+
if (!(avctx->codec->capabilities & CODEC_CAP_DELAY) && !frame) {
av_free_packet(avpkt);
av_init_packet(avpkt);
@@ -1505,17 +2126,48 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,
if (av_image_check_size(avctx->width, avctx->height, 0, avctx))
return AVERROR(EINVAL);
+ if (frame && frame->format == AV_PIX_FMT_NONE)
+ av_log(avctx, AV_LOG_WARNING, "AVFrame.format is not set\n");
+ if (frame && (frame->width == 0 || frame->height == 0))
+ av_log(avctx, AV_LOG_WARNING, "AVFrame.width or height is not set\n");
+
av_assert0(avctx->codec->encode2);
ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr);
+ av_assert0(ret <= 0);
+
+ if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) {
+ needs_realloc = 0;
+ if (user_pkt.data) {
+ if (user_pkt.size >= avpkt->size) {
+ memcpy(user_pkt.data, avpkt->data, avpkt->size);
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size);
+ avpkt->size = user_pkt.size;
+ ret = -1;
+ }
+ avpkt->buf = user_pkt.buf;
+ avpkt->data = user_pkt.data;
+#if FF_API_DESTRUCT_PACKET
+FF_DISABLE_DEPRECATION_WARNINGS
+ avpkt->destruct = user_pkt.destruct;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+ } else {
+ if (av_dup_packet(avpkt) < 0) {
+ ret = AVERROR(ENOMEM);
+ }
+ }
+ }
+
if (!ret) {
if (!*got_packet_ptr)
avpkt->size = 0;
else if (!(avctx->codec->capabilities & CODEC_CAP_DELAY))
avpkt->pts = avpkt->dts = frame->pts;
- if (!user_packet && avpkt->size) {
- ret = av_buffer_realloc(&avpkt->buf, avpkt->size);
+ if (needs_realloc && avpkt->data) {
+ ret = av_buffer_realloc(&avpkt->buf, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
if (ret >= 0)
avpkt->data = avpkt->buf->data;
}
@@ -1525,6 +2177,8 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx,
if (ret < 0 || !*got_packet_ptr)
av_free_packet(avpkt);
+ else
+ av_packet_merge_side_data(avpkt);
emms_c();
return ret;
@@ -1538,13 +2192,48 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n");
return -1;
}
- if (sub->num_rects == 0 || !sub->rects)
- return -1;
+
ret = avctx->codec->encode_sub(avctx, buf, buf_size, sub);
avctx->frame_number++;
return ret;
}
+/**
+ * Attempt to guess proper monotonic timestamps for decoded video frames
+ * which might have incorrect times. Input timestamps may wrap around, in
+ * which case the output will as well.
+ *
+ * @param pts the pts field of the decoded AVPacket, as passed through
+ * AVFrame.pkt_pts
+ * @param dts the dts field of the decoded AVPacket
+ * @return one of the input values, may be AV_NOPTS_VALUE
+ */
+static int64_t guess_correct_pts(AVCodecContext *ctx,
+ int64_t reordered_pts, int64_t dts)
+{
+ int64_t pts = AV_NOPTS_VALUE;
+
+ if (dts != AV_NOPTS_VALUE) {
+ ctx->pts_correction_num_faulty_dts += dts <= ctx->pts_correction_last_dts;
+ ctx->pts_correction_last_dts = dts;
+ } else if (reordered_pts != AV_NOPTS_VALUE)
+ ctx->pts_correction_last_dts = reordered_pts;
+
+ if (reordered_pts != AV_NOPTS_VALUE) {
+ ctx->pts_correction_num_faulty_pts += reordered_pts <= ctx->pts_correction_last_pts;
+ ctx->pts_correction_last_pts = reordered_pts;
+ } else if(dts != AV_NOPTS_VALUE)
+ ctx->pts_correction_last_pts = dts;
+
+ if ((ctx->pts_correction_num_faulty_pts<=ctx->pts_correction_num_faulty_dts || dts == AV_NOPTS_VALUE)
+ && reordered_pts != AV_NOPTS_VALUE)
+ pts = reordered_pts;
+ else
+ pts = dts;
+
+ return pts;
+}
+
static int apply_param_change(AVCodecContext *avctx, AVPacket *avpkt)
{
int size = 0, ret;
@@ -1602,6 +2291,18 @@ fail:
return AVERROR_INVALIDDATA;
}
+static int add_metadata_from_side_data(AVCodecContext *avctx, AVFrame *frame)
+{
+ int size;
+ const uint8_t *side_metadata;
+
+ AVDictionary **frame_md = avpriv_frame_get_metadatap(frame);
+
+ side_metadata = av_packet_get_side_data(avctx->internal->pkt,
+ AV_PKT_DATA_STRINGS_METADATA, &size);
+ return av_packet_unpack_dictionary(side_metadata, size, frame_md);
+}
+
static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame)
{
int ret;
@@ -1620,7 +2321,7 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame)
memcpy(frame->data, avci->to_free->data, sizeof(frame->data));
memcpy(frame->linesize, avci->to_free->linesize, sizeof(frame->linesize));
if (avci->to_free->extended_data != avci->to_free->data) {
- int planes = av_get_channel_layout_nb_channels(avci->to_free->channel_layout);
+ int planes = av_frame_get_channels(avci->to_free);
int size = planes * sizeof(*frame->extended_data);
if (!size) {
@@ -1643,50 +2344,75 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame)
frame->height = avci->to_free->height;
frame->channel_layout = avci->to_free->channel_layout;
frame->nb_samples = avci->to_free->nb_samples;
+ av_frame_set_channels(frame, av_frame_get_channels(avci->to_free));
return 0;
}
int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
- AVPacket *avpkt)
+ const AVPacket *avpkt)
{
AVCodecInternal *avci = avctx->internal;
int ret;
+ // copy to ensure we do not change avpkt
+ AVPacket tmp = *avpkt;
+
+ if (!avctx->codec)
+ return AVERROR(EINVAL);
+ if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n");
+ return AVERROR(EINVAL);
+ }
*got_picture_ptr = 0;
if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
- return -1;
-
- avctx->internal->pkt = avpkt;
- ret = apply_param_change(avctx, avpkt);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
- if (avctx->err_recognition & AV_EF_EXPLODE)
- return ret;
- }
+ return AVERROR(EINVAL);
av_frame_unref(picture);
if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
+ int did_split = av_packet_split_side_data(&tmp);
+ ret = apply_param_change(avctx, &tmp);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
+ if (avctx->err_recognition & AV_EF_EXPLODE)
+ goto fail;
+ }
+
+ avctx->internal->pkt = &tmp;
if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,
- avpkt);
+ &tmp);
else {
ret = avctx->codec->decode(avctx, picture, got_picture_ptr,
- avpkt);
+ &tmp);
picture->pkt_dts = avpkt->dts;
+
+ if(!avctx->has_b_frames){
+ av_frame_set_pkt_pos(picture, avpkt->pos);
+ }
+ //FIXME these should be under if(!avctx->has_b_frames)
/* get_buffer is supposed to set frame parameters */
if (!(avctx->codec->capabilities & CODEC_CAP_DR1)) {
- picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
- picture->width = avctx->width;
- picture->height = avctx->height;
- picture->format = avctx->pix_fmt;
+ if (!picture->sample_aspect_ratio.num) picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
+ if (!picture->width) picture->width = avctx->width;
+ if (!picture->height) picture->height = avctx->height;
+ if (picture->format == AV_PIX_FMT_NONE) picture->format = avctx->pix_fmt;
}
}
+ add_metadata_from_side_data(avctx, picture);
+fail:
emms_c(); //needed to avoid an emms_c() call before every return;
+ avctx->internal->pkt = NULL;
+ if (did_split) {
+ av_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
if (*got_picture_ptr) {
if (!avctx->refcounted_frames) {
int err = unrefcount_frame(avci, picture);
@@ -1695,53 +2421,221 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
}
avctx->frame_number++;
+ av_frame_set_best_effort_timestamp(picture,
+ guess_correct_pts(avctx,
+ picture->pkt_pts,
+ picture->pkt_dts));
} else
av_frame_unref(picture);
} else
ret = 0;
+ /* many decoders assign whole AVFrames, thus overwriting extended_data;
+ * make sure it's set correctly */
+ av_assert0(!picture->extended_data || picture->extended_data == picture->data);
+
#if FF_API_AVCTX_TIMEBASE
if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
- avctx->time_base = av_inv_q(avctx->framerate);
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
#endif
return ret;
}
+#if FF_API_OLD_DECODE_AUDIO
+int attribute_align_arg avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,
+ int *frame_size_ptr,
+ AVPacket *avpkt)
+{
+ AVFrame *frame = av_frame_alloc();
+ int ret, got_frame = 0;
+
+ if (!frame)
+ return AVERROR(ENOMEM);
+ if (avctx->get_buffer != avcodec_default_get_buffer) {
+ av_log(avctx, AV_LOG_ERROR, "Custom get_buffer() for use with"
+ "avcodec_decode_audio3() detected. Overriding with avcodec_default_get_buffer\n");
+ av_log(avctx, AV_LOG_ERROR, "Please port your application to "
+ "avcodec_decode_audio4()\n");
+ avctx->get_buffer = avcodec_default_get_buffer;
+ avctx->release_buffer = avcodec_default_release_buffer;
+ }
+
+ ret = avcodec_decode_audio4(avctx, frame, &got_frame, avpkt);
+
+ if (ret >= 0 && got_frame) {
+ int ch, plane_size;
+ int planar = av_sample_fmt_is_planar(avctx->sample_fmt);
+ int data_size = av_samples_get_buffer_size(&plane_size, avctx->channels,
+ frame->nb_samples,
+ avctx->sample_fmt, 1);
+ if (*frame_size_ptr < data_size) {
+ av_log(avctx, AV_LOG_ERROR, "output buffer size is too small for "
+ "the current frame (%d < %d)\n", *frame_size_ptr, data_size);
+ av_frame_free(&frame);
+ return AVERROR(EINVAL);
+ }
+
+ memcpy(samples, frame->extended_data[0], plane_size);
+
+ if (planar && avctx->channels > 1) {
+ uint8_t *out = ((uint8_t *)samples) + plane_size;
+ for (ch = 1; ch < avctx->channels; ch++) {
+ memcpy(out, frame->extended_data[ch], plane_size);
+ out += plane_size;
+ }
+ }
+ *frame_size_ptr = data_size;
+ } else {
+ *frame_size_ptr = 0;
+ }
+ av_frame_free(&frame);
+ return ret;
+}
+
+#endif
+
int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
AVFrame *frame,
int *got_frame_ptr,
- AVPacket *avpkt)
+ const AVPacket *avpkt)
{
AVCodecInternal *avci = avctx->internal;
int ret = 0;
*got_frame_ptr = 0;
- avctx->internal->pkt = avpkt;
-
if (!avpkt->data && avpkt->size) {
av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
return AVERROR(EINVAL);
}
-
- ret = apply_param_change(avctx, avpkt);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
- if (avctx->err_recognition & AV_EF_EXPLODE)
- return ret;
+ if (!avctx->codec)
+ return AVERROR(EINVAL);
+ if (avctx->codec->type != AVMEDIA_TYPE_AUDIO) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid media type for audio\n");
+ return AVERROR(EINVAL);
}
av_frame_unref(frame);
- if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size) {
- ret = avctx->codec->decode(avctx, frame, got_frame_ptr, avpkt);
+ if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
+ uint8_t *side;
+ int side_size;
+ uint32_t discard_padding = 0;
+ uint8_t skip_reason = 0;
+ uint8_t discard_reason = 0;
+ // copy to ensure we do not change avpkt
+ AVPacket tmp = *avpkt;
+ int did_split = av_packet_split_side_data(&tmp);
+ ret = apply_param_change(avctx, &tmp);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");
+ if (avctx->err_recognition & AV_EF_EXPLODE)
+ goto fail;
+ }
+
+ avctx->internal->pkt = &tmp;
+ if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
+ ret = ff_thread_decode_frame(avctx, frame, got_frame_ptr, &tmp);
+ else {
+ ret = avctx->codec->decode(avctx, frame, got_frame_ptr, &tmp);
+ frame->pkt_dts = avpkt->dts;
+ }
if (ret >= 0 && *got_frame_ptr) {
+ add_metadata_from_side_data(avctx, frame);
avctx->frame_number++;
- frame->pkt_dts = avpkt->dts;
+ av_frame_set_best_effort_timestamp(frame,
+ guess_correct_pts(avctx,
+ frame->pkt_pts,
+ frame->pkt_dts));
if (frame->format == AV_SAMPLE_FMT_NONE)
frame->format = avctx->sample_fmt;
+ if (!frame->channel_layout)
+ frame->channel_layout = avctx->channel_layout;
+ if (!av_frame_get_channels(frame))
+ av_frame_set_channels(frame, avctx->channels);
+ if (!frame->sample_rate)
+ frame->sample_rate = avctx->sample_rate;
+ }
+
+ side= av_packet_get_side_data(avctx->internal->pkt, AV_PKT_DATA_SKIP_SAMPLES, &side_size);
+ if(side && side_size>=10) {
+ avctx->internal->skip_samples = AV_RL32(side);
+ discard_padding = AV_RL32(side + 4);
+ av_log(avctx, AV_LOG_DEBUG, "skip %d / discard %d samples due to side data\n",
+ avctx->internal->skip_samples, (int)discard_padding);
+ skip_reason = AV_RL8(side + 8);
+ discard_reason = AV_RL8(side + 9);
+ }
+ if (avctx->internal->skip_samples && *got_frame_ptr &&
+ !(avctx->flags2 & CODEC_FLAG2_SKIP_MANUAL)) {
+ if(frame->nb_samples <= avctx->internal->skip_samples){
+ *got_frame_ptr = 0;
+ avctx->internal->skip_samples -= frame->nb_samples;
+ av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n",
+ avctx->internal->skip_samples);
+ } else {
+ av_samples_copy(frame->extended_data, frame->extended_data, 0, avctx->internal->skip_samples,
+ frame->nb_samples - avctx->internal->skip_samples, avctx->channels, frame->format);
+ if(avctx->pkt_timebase.num && avctx->sample_rate) {
+ int64_t diff_ts = av_rescale_q(avctx->internal->skip_samples,
+ (AVRational){1, avctx->sample_rate},
+ avctx->pkt_timebase);
+ if(frame->pkt_pts!=AV_NOPTS_VALUE)
+ frame->pkt_pts += diff_ts;
+ if(frame->pkt_dts!=AV_NOPTS_VALUE)
+ frame->pkt_dts += diff_ts;
+ if (av_frame_get_pkt_duration(frame) >= diff_ts)
+ av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for skipped samples.\n");
+ }
+ av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n",
+ avctx->internal->skip_samples, frame->nb_samples);
+ frame->nb_samples -= avctx->internal->skip_samples;
+ avctx->internal->skip_samples = 0;
+ }
+ }
+ if (discard_padding > 0 && discard_padding <= frame->nb_samples && *got_frame_ptr &&
+ !(avctx->flags2 & CODEC_FLAG2_SKIP_MANUAL)) {
+ if (discard_padding == frame->nb_samples) {
+ *got_frame_ptr = 0;
+ } else {
+ if(avctx->pkt_timebase.num && avctx->sample_rate) {
+ int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding,
+ (AVRational){1, avctx->sample_rate},
+ avctx->pkt_timebase);
+ if (av_frame_get_pkt_duration(frame) >= diff_ts)
+ av_frame_set_pkt_duration(frame, av_frame_get_pkt_duration(frame) - diff_ts);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n");
+ }
+ av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n",
+ (int)discard_padding, frame->nb_samples);
+ frame->nb_samples -= discard_padding;
+ }
+ }
+
+ if ((avctx->flags2 & CODEC_FLAG2_SKIP_MANUAL) && *got_frame_ptr) {
+ AVFrameSideData *fside = av_frame_new_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES, 10);
+ if (fside) {
+ AV_WL32(fside->data, avctx->internal->skip_samples);
+ AV_WL32(fside->data + 4, discard_padding);
+ AV_WL8(fside->data + 8, skip_reason);
+ AV_WL8(fside->data + 9, discard_reason);
+ avctx->internal->skip_samples = 0;
+ }
+ }
+fail:
+ avctx->internal->pkt = NULL;
+ if (did_split) {
+ av_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
+ if (ret >= 0 && *got_frame_ptr) {
if (!avctx->refcounted_frames) {
int err = unrefcount_frame(avci, frame);
if (err < 0)
@@ -1751,21 +2645,178 @@ int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx,
av_frame_unref(frame);
}
+ return ret;
+}
+
+#define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */
+static int recode_subtitle(AVCodecContext *avctx,
+ AVPacket *outpkt, const AVPacket *inpkt)
+{
+#if CONFIG_ICONV
+ iconv_t cd = (iconv_t)-1;
+ int ret = 0;
+ char *inb, *outb;
+ size_t inl, outl;
+ AVPacket tmp;
+#endif
+
+ if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_PRE_DECODER || inpkt->size == 0)
+ return 0;
+#if CONFIG_ICONV
+ cd = iconv_open("UTF-8", avctx->sub_charenc);
+ av_assert0(cd != (iconv_t)-1);
+
+ inb = inpkt->data;
+ inl = inpkt->size;
+
+ if (inl >= INT_MAX / UTF8_MAX_BYTES - FF_INPUT_BUFFER_PADDING_SIZE) {
+ av_log(avctx, AV_LOG_ERROR, "Subtitles packet is too big for recoding\n");
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ ret = av_new_packet(&tmp, inl * UTF8_MAX_BYTES);
+ if (ret < 0)
+ goto end;
+ outpkt->buf = tmp.buf;
+ outpkt->data = tmp.data;
+ outpkt->size = tmp.size;
+ outb = outpkt->data;
+ outl = outpkt->size;
+
+ if (iconv(cd, &inb, &inl, &outb, &outl) == (size_t)-1 ||
+ iconv(cd, NULL, NULL, &outb, &outl) == (size_t)-1 ||
+ outl >= outpkt->size || inl != 0) {
+ ret = FFMIN(AVERROR(errno), -1);
+ av_log(avctx, AV_LOG_ERROR, "Unable to recode subtitle event \"%s\" "
+ "from %s to UTF-8\n", inpkt->data, avctx->sub_charenc);
+ av_free_packet(&tmp);
+ goto end;
+ }
+ outpkt->size -= outl;
+ memset(outpkt->data + outpkt->size, 0, outl);
+
+end:
+ if (cd != (iconv_t)-1)
+ iconv_close(cd);
return ret;
+#else
+ av_log(avctx, AV_LOG_ERROR, "requesting subtitles recoding without iconv");
+ return AVERROR(EINVAL);
+#endif
+}
+
+static int utf8_check(const uint8_t *str)
+{
+ const uint8_t *byte;
+ uint32_t codepoint, min;
+
+ while (*str) {
+ byte = str;
+ GET_UTF8(codepoint, *(byte++), return 0;);
+ min = byte - str == 1 ? 0 : byte - str == 2 ? 0x80 :
+ 1 << (5 * (byte - str) - 4);
+ if (codepoint < min || codepoint >= 0x110000 ||
+ codepoint == 0xFFFE /* BOM */ ||
+ codepoint >= 0xD800 && codepoint <= 0xDFFF /* surrogates */)
+ return 0;
+ str = byte;
+ }
+ return 1;
}
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int *got_sub_ptr,
AVPacket *avpkt)
{
- int ret;
+ int i, ret = 0;
+
+ if (!avpkt->data && avpkt->size) {
+ av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n");
+ return AVERROR(EINVAL);
+ }
+ if (!avctx->codec)
+ return AVERROR(EINVAL);
+ if (avctx->codec->type != AVMEDIA_TYPE_SUBTITLE) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid media type for subtitles\n");
+ return AVERROR(EINVAL);
+ }
- avctx->internal->pkt = avpkt;
*got_sub_ptr = 0;
- ret = avctx->codec->decode(avctx, sub, got_sub_ptr, avpkt);
- if (*got_sub_ptr)
- avctx->frame_number++;
+ get_subtitle_defaults(sub);
+
+ if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size) {
+ AVPacket pkt_recoded;
+ AVPacket tmp = *avpkt;
+ int did_split = av_packet_split_side_data(&tmp);
+ //apply_param_change(avctx, &tmp);
+
+ if (did_split) {
+ /* FFMIN() prevents overflow in case the packet wasn't allocated with
+ * proper padding.
+ * If the side data is smaller than the buffer padding size, the
+ * remaining bytes should have already been filled with zeros by the
+ * original packet allocation anyway. */
+ memset(tmp.data + tmp.size, 0,
+ FFMIN(avpkt->size - tmp.size, FF_INPUT_BUFFER_PADDING_SIZE));
+ }
+
+ pkt_recoded = tmp;
+ ret = recode_subtitle(avctx, &pkt_recoded, &tmp);
+ if (ret < 0) {
+ *got_sub_ptr = 0;
+ } else {
+ avctx->internal->pkt = &pkt_recoded;
+
+ if (avctx->pkt_timebase.den && avpkt->pts != AV_NOPTS_VALUE)
+ sub->pts = av_rescale_q(avpkt->pts,
+ avctx->pkt_timebase, AV_TIME_BASE_Q);
+ ret = avctx->codec->decode(avctx, sub, got_sub_ptr, &pkt_recoded);
+ av_assert1((ret >= 0) >= !!*got_sub_ptr &&
+ !!*got_sub_ptr >= !!sub->num_rects);
+
+ if (sub->num_rects && !sub->end_display_time && avpkt->duration &&
+ avctx->pkt_timebase.num) {
+ AVRational ms = { 1, 1000 };
+ sub->end_display_time = av_rescale_q(avpkt->duration,
+ avctx->pkt_timebase, ms);
+ }
+
+ for (i = 0; i < sub->num_rects; i++) {
+ if (sub->rects[i]->ass && !utf8_check(sub->rects[i]->ass)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid UTF-8 in decoded subtitles text; "
+ "maybe missing -sub_charenc option\n");
+ avsubtitle_free(sub);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (tmp.data != pkt_recoded.data) { // did we recode?
+ /* prevent from destroying side data from original packet */
+ pkt_recoded.side_data = NULL;
+ pkt_recoded.side_data_elems = 0;
+
+ av_free_packet(&pkt_recoded);
+ }
+ if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB)
+ sub->format = 0;
+ else if (avctx->codec_descriptor->props & AV_CODEC_PROP_TEXT_SUB)
+ sub->format = 1;
+ avctx->internal->pkt = NULL;
+ }
+
+ if (did_split) {
+ av_packet_free_side_data(&tmp);
+ if(ret == tmp.size)
+ ret = avpkt->size;
+ }
+
+ if (*got_sub_ptr)
+ avctx->frame_number++;
+ }
+
return ret;
}
@@ -1790,14 +2841,23 @@ void avsubtitle_free(AVSubtitle *sub)
av_cold int avcodec_close(AVCodecContext *avctx)
{
+ if (!avctx)
+ return 0;
+
if (avcodec_is_open(avctx)) {
FramePool *pool = avctx->internal->pool;
int i;
+ if (CONFIG_FRAME_THREAD_ENCODER &&
+ avctx->internal->frame_thread_encoder && avctx->thread_count > 1) {
+ ff_frame_thread_encoder_free(avctx);
+ }
if (HAVE_THREADS && avctx->internal->thread_ctx)
ff_thread_free(avctx);
if (avctx->codec && avctx->codec->close)
avctx->codec->close(avctx);
avctx->coded_frame = NULL;
+ avctx->internal->byte_buffer_size = 0;
+ av_freep(&avctx->internal->byte_buffer);
av_frame_free(&avctx->internal->to_free);
for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
av_buffer_pool_uninit(&pool->pools[i]);
@@ -1822,10 +2882,39 @@ av_cold int avcodec_close(AVCodecContext *avctx)
return 0;
}
+static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id)
+{
+ switch(id){
+ //This is for future deprecatec codec ids, its empty since
+ //last major bump but will fill up again over time, please don't remove it
+// case AV_CODEC_ID_UTVIDEO_DEPRECATED: return AV_CODEC_ID_UTVIDEO;
+ case AV_CODEC_ID_BRENDER_PIX_DEPRECATED : return AV_CODEC_ID_BRENDER_PIX;
+ case AV_CODEC_ID_OPUS_DEPRECATED : return AV_CODEC_ID_OPUS;
+ case AV_CODEC_ID_TAK_DEPRECATED : return AV_CODEC_ID_TAK;
+ case AV_CODEC_ID_PAF_AUDIO_DEPRECATED : return AV_CODEC_ID_PAF_AUDIO;
+ case AV_CODEC_ID_PCM_S24LE_PLANAR_DEPRECATED : return AV_CODEC_ID_PCM_S24LE_PLANAR;
+ case AV_CODEC_ID_PCM_S32LE_PLANAR_DEPRECATED : return AV_CODEC_ID_PCM_S32LE_PLANAR;
+ case AV_CODEC_ID_ADPCM_VIMA_DEPRECATED : return AV_CODEC_ID_ADPCM_VIMA;
+ case AV_CODEC_ID_ESCAPE130_DEPRECATED : return AV_CODEC_ID_ESCAPE130;
+ case AV_CODEC_ID_EXR_DEPRECATED : return AV_CODEC_ID_EXR;
+ case AV_CODEC_ID_G2M_DEPRECATED : return AV_CODEC_ID_G2M;
+ case AV_CODEC_ID_PAF_VIDEO_DEPRECATED : return AV_CODEC_ID_PAF_VIDEO;
+ case AV_CODEC_ID_WEBP_DEPRECATED : return AV_CODEC_ID_WEBP;
+ case AV_CODEC_ID_HEVC_DEPRECATED : return AV_CODEC_ID_HEVC;
+ case AV_CODEC_ID_MVC1_DEPRECATED : return AV_CODEC_ID_MVC1;
+ case AV_CODEC_ID_MVC2_DEPRECATED : return AV_CODEC_ID_MVC2;
+ case AV_CODEC_ID_SANM_DEPRECATED : return AV_CODEC_ID_SANM;
+ case AV_CODEC_ID_SGIRLE_DEPRECATED : return AV_CODEC_ID_SGIRLE;
+ case AV_CODEC_ID_VP7_DEPRECATED : return AV_CODEC_ID_VP7;
+ default : return id;
+ }
+}
+
static AVCodec *find_encdec(enum AVCodecID id, int encoder)
{
AVCodec *p, *experimental = NULL;
p = first_avcodec;
+ id= remap_deprecated_codec_id(id);
while (p) {
if ((encoder ? av_codec_is_encoder(p) : av_codec_is_decoder(p)) &&
p->id == id) {
@@ -1877,27 +2966,24 @@ AVCodec *avcodec_find_decoder_by_name(const char *name)
return NULL;
}
-static int get_bit_rate(AVCodecContext *ctx)
+const char *avcodec_get_name(enum AVCodecID id)
{
- int bit_rate;
- int bits_per_sample;
+ const AVCodecDescriptor *cd;
+ AVCodec *codec;
- switch (ctx->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- case AVMEDIA_TYPE_DATA:
- case AVMEDIA_TYPE_SUBTITLE:
- case AVMEDIA_TYPE_ATTACHMENT:
- bit_rate = ctx->bit_rate;
- break;
- case AVMEDIA_TYPE_AUDIO:
- bits_per_sample = av_get_bits_per_sample(ctx->codec_id);
- bit_rate = bits_per_sample ? ctx->sample_rate * ctx->channels * bits_per_sample : ctx->bit_rate;
- break;
- default:
- bit_rate = 0;
- break;
- }
- return bit_rate;
+ if (id == AV_CODEC_ID_NONE)
+ return "none";
+ cd = avcodec_descriptor_get(id);
+ if (cd)
+ return cd->name;
+ av_log(NULL, AV_LOG_WARNING, "Codec 0x%x is not in the full list.\n", id);
+ codec = avcodec_find_decoder(id);
+ if (codec)
+ return codec->name;
+ codec = avcodec_find_encoder(id);
+ if (codec)
+ return codec->name;
+ return "unknown_codec";
}
size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag)
@@ -1907,7 +2993,7 @@ size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_ta
#define TAG_PRINT(x) \
(((x) >= '0' && (x) <= '9') || \
((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || \
- ((x) == '.' || (x) == ' '))
+ ((x) == '.' || (x) == ' ' || (x) == '-' || (x) == '_'))
for (i = 0; i < 4; i++) {
len = snprintf(buf, buf_size,
@@ -1922,75 +3008,97 @@ size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_ta
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
{
+ const char *codec_type;
const char *codec_name;
const char *profile = NULL;
const AVCodec *p;
- char buf1[32];
int bitrate;
int new_line = 0;
AVRational display_aspect_ratio;
+ const char *separator = enc->dump_separator ? (const char *)enc->dump_separator : ", ";
- if (enc->codec)
- p = enc->codec;
- else if (encode)
- p = avcodec_find_encoder(enc->codec_id);
- else
- p = avcodec_find_decoder(enc->codec_id);
-
- if (p) {
- codec_name = p->name;
- profile = av_get_profile_name(p, enc->profile);
- } else if (enc->codec_id == AV_CODEC_ID_MPEG2TS) {
- /* fake mpeg2 transport stream codec (currently not
- * registered) */
- codec_name = "mpeg2ts";
- } else {
- /* output avi tags */
+ if (!buf || buf_size <= 0)
+ return;
+ codec_type = av_get_media_type_string(enc->codec_type);
+ codec_name = avcodec_get_name(enc->codec_id);
+ if (enc->profile != FF_PROFILE_UNKNOWN) {
+ if (enc->codec)
+ p = enc->codec;
+ else
+ p = encode ? avcodec_find_encoder(enc->codec_id) :
+ avcodec_find_decoder(enc->codec_id);
+ if (p)
+ profile = av_get_profile_name(p, enc->profile);
+ }
+
+ snprintf(buf, buf_size, "%s: %s", codec_type ? codec_type : "unknown",
+ codec_name);
+ buf[0] ^= 'a' ^ 'A'; /* first letter in uppercase */
+
+ if (enc->codec && strcmp(enc->codec->name, codec_name))
+ snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s)", enc->codec->name);
+
+ if (profile)
+ snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s)", profile);
+ if ( enc->codec_type == AVMEDIA_TYPE_VIDEO
+ && av_log_get_level() >= AV_LOG_VERBOSE
+ && enc->refs)
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ ", %d reference frame%s",
+ enc->refs, enc->refs > 1 ? "s" : "");
+
+ if (enc->codec_tag) {
char tag_buf[32];
av_get_codec_tag_string(tag_buf, sizeof(tag_buf), enc->codec_tag);
- snprintf(buf1, sizeof(buf1), "%s / 0x%04X", tag_buf, enc->codec_tag);
- codec_name = buf1;
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ " (%s / 0x%04X)", tag_buf, enc->codec_tag);
}
switch (enc->codec_type) {
case AVMEDIA_TYPE_VIDEO:
- snprintf(buf, buf_size,
- "Video: %s%s",
- codec_name, enc->mb_decision ? " (hq)" : "");
- if (profile)
- snprintf(buf + strlen(buf), buf_size - strlen(buf),
- " (%s)", profile);
- if (enc->codec_tag) {
- char tag_buf[32];
- av_get_codec_tag_string(tag_buf, sizeof(tag_buf), enc->codec_tag);
- snprintf(buf + strlen(buf), buf_size - strlen(buf),
- " [%s / 0x%04X]", tag_buf, enc->codec_tag);
- }
+ {
+ char detail[256] = "(";
- av_strlcat(buf, "\n ", buf_size);
- snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ av_strlcat(buf, separator, buf_size);
+
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
"%s", enc->pix_fmt == AV_PIX_FMT_NONE ? "none" :
av_get_pix_fmt_name(enc->pix_fmt));
+ if (enc->bits_per_raw_sample && enc->pix_fmt != AV_PIX_FMT_NONE &&
+ enc->bits_per_raw_sample <= av_pix_fmt_desc_get(enc->pix_fmt)->comp[0].depth_minus1)
+ av_strlcatf(detail, sizeof(detail), "%d bpc, ", enc->bits_per_raw_sample);
+ if (enc->color_range != AVCOL_RANGE_UNSPECIFIED)
+ av_strlcatf(detail, sizeof(detail), "%s, ",
+ av_color_range_name(enc->color_range));
+
+ if (enc->colorspace != AVCOL_SPC_UNSPECIFIED ||
+ enc->color_primaries != AVCOL_PRI_UNSPECIFIED ||
+ enc->color_trc != AVCOL_TRC_UNSPECIFIED) {
+ if (enc->colorspace != (int)enc->color_primaries ||
+ enc->colorspace != (int)enc->color_trc) {
+ new_line = 1;
+ av_strlcatf(detail, sizeof(detail), "%s/%s/%s, ",
+ av_color_space_name(enc->colorspace),
+ av_color_primaries_name(enc->color_primaries),
+ av_color_transfer_name(enc->color_trc));
+ } else
+ av_strlcatf(detail, sizeof(detail), "%s, ",
+ av_get_colorspace_name(enc->colorspace));
+ }
- if (enc->color_range != AVCOL_RANGE_UNSPECIFIED)
- snprintf(buf + strlen(buf), buf_size - strlen(buf), ", %s",
- av_color_range_name(enc->color_range));
- if (enc->colorspace != AVCOL_SPC_UNSPECIFIED ||
- enc->color_primaries != AVCOL_PRI_UNSPECIFIED ||
- enc->color_trc != AVCOL_TRC_UNSPECIFIED) {
- new_line = 1;
- snprintf(buf + strlen(buf), buf_size - strlen(buf), ", %s/%s/%s",
- av_color_space_name(enc->colorspace),
- av_color_primaries_name(enc->color_primaries),
- av_color_transfer_name(enc->color_trc));
- }
- if (av_log_get_level() >= AV_LOG_DEBUG &&
- enc->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
- snprintf(buf + strlen(buf), buf_size - strlen(buf), ", %s",
- av_chroma_location_name(enc->chroma_sample_location));
+ if (av_log_get_level() >= AV_LOG_DEBUG &&
+ enc->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
+ av_strlcatf(detail, sizeof(detail), "%s, ",
+ av_chroma_location_name(enc->chroma_sample_location));
+
+ if (strlen(detail) > 1) {
+ detail[strlen(detail) - 2] = 0;
+ av_strlcatf(buf, buf_size, "%s)", detail);
+ }
+ }
if (enc->width) {
- av_strlcat(buf, new_line ? "\n " : ", ", buf_size);
+ av_strlcat(buf, new_line ? separator : ", ", buf_size);
snprintf(buf + strlen(buf), buf_size - strlen(buf),
"%dx%d",
@@ -2008,7 +3116,7 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
enc->height * enc->sample_aspect_ratio.den,
1024 * 1024);
snprintf(buf + strlen(buf), buf_size - strlen(buf),
- " [PAR %d:%d DAR %d:%d]",
+ " [SAR %d:%d DAR %d:%d]",
enc->sample_aspect_ratio.num, enc->sample_aspect_ratio.den,
display_aspect_ratio.num, display_aspect_ratio.den);
}
@@ -2025,20 +3133,8 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
}
break;
case AVMEDIA_TYPE_AUDIO:
- snprintf(buf, buf_size,
- "Audio: %s",
- codec_name);
- if (profile)
- snprintf(buf + strlen(buf), buf_size - strlen(buf),
- " (%s)", profile);
- if (enc->codec_tag) {
- char tag_buf[32];
- av_get_codec_tag_string(tag_buf, sizeof(tag_buf), enc->codec_tag);
- snprintf(buf + strlen(buf), buf_size - strlen(buf),
- " [%s / 0x%04X]", tag_buf, enc->codec_tag);
- }
+ av_strlcat(buf, separator, buf_size);
- av_strlcat(buf, "\n ", buf_size);
if (enc->sample_rate) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
"%d Hz, ", enc->sample_rate);
@@ -2048,18 +3144,26 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %s", av_get_sample_fmt_name(enc->sample_fmt));
}
+ if ( enc->bits_per_raw_sample > 0
+ && enc->bits_per_raw_sample != av_get_bytes_per_sample(enc->sample_fmt) * 8)
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ " (%d bit)", enc->bits_per_raw_sample);
break;
case AVMEDIA_TYPE_DATA:
- snprintf(buf, buf_size, "Data: %s", codec_name);
+ if (av_log_get_level() >= AV_LOG_DEBUG) {
+ int g = av_gcd(enc->time_base.num, enc->time_base.den);
+ if (g)
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ ", %d/%d",
+ enc->time_base.num / g, enc->time_base.den / g);
+ }
break;
case AVMEDIA_TYPE_SUBTITLE:
- snprintf(buf, buf_size, "Subtitle: %s", codec_name);
- break;
- case AVMEDIA_TYPE_ATTACHMENT:
- snprintf(buf, buf_size, "Attachment: %s", codec_name);
+ if (enc->width)
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ ", %dx%d", enc->width, enc->height);
break;
default:
- snprintf(buf, buf_size, "Invalid Codec type %d", enc->codec_type);
return;
}
if (encode) {
@@ -2074,6 +3178,9 @@ void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
if (bitrate != 0) {
snprintf(buf + strlen(buf), buf_size - strlen(buf),
", %d kb/s", bitrate / 1000);
+ } else if (enc->rc_max_rate > 0) {
+ snprintf(buf + strlen(buf), buf_size - strlen(buf),
+ ", max. %d kb/s", enc->rc_max_rate / 1000);
}
}
@@ -2092,18 +3199,30 @@ const char *av_get_profile_name(const AVCodec *codec, int profile)
unsigned avcodec_version(void)
{
+// av_assert0(AV_CODEC_ID_V410==164);
+ av_assert0(AV_CODEC_ID_PCM_S8_PLANAR==65563);
+ av_assert0(AV_CODEC_ID_ADPCM_G722==69660);
+// av_assert0(AV_CODEC_ID_BMV_AUDIO==86071);
+ av_assert0(AV_CODEC_ID_SRT==94216);
+ av_assert0(LIBAVCODEC_VERSION_MICRO >= 100);
+
+ av_assert0(CODEC_ID_CLLC == AV_CODEC_ID_CLLC);
+ av_assert0(CODEC_ID_PCM_S8_PLANAR == AV_CODEC_ID_PCM_S8_PLANAR);
+ av_assert0(CODEC_ID_ADPCM_IMA_APC == AV_CODEC_ID_ADPCM_IMA_APC);
+ av_assert0(CODEC_ID_ILBC == AV_CODEC_ID_ILBC);
+ av_assert0(CODEC_ID_SRT == AV_CODEC_ID_SRT);
return LIBAVCODEC_VERSION_INT;
}
const char *avcodec_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char *avcodec_license(void)
{
#define LICENSE_PREFIX "libavcodec license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
}
void avcodec_flush_buffers(AVCodecContext *avctx)
@@ -2113,6 +3232,9 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
else if (avctx->codec->flush)
avctx->codec->flush(avctx);
+ avctx->pts_correction_last_pts =
+ avctx->pts_correction_last_dts = INT64_MIN;
+
if (!avctx->refcounted_frames)
av_frame_unref(avctx->internal->to_free);
}
@@ -2120,20 +3242,29 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
int av_get_exact_bits_per_sample(enum AVCodecID codec_id)
{
switch (codec_id) {
+ case AV_CODEC_ID_8SVX_EXP:
+ case AV_CODEC_ID_8SVX_FIB:
case AV_CODEC_ID_ADPCM_CT:
case AV_CODEC_ID_ADPCM_IMA_APC:
case AV_CODEC_ID_ADPCM_IMA_EA_SEAD:
+ case AV_CODEC_ID_ADPCM_IMA_OKI:
case AV_CODEC_ID_ADPCM_IMA_WS:
case AV_CODEC_ID_ADPCM_G722:
case AV_CODEC_ID_ADPCM_YAMAHA:
return 4;
+ case AV_CODEC_ID_DSD_LSBF:
+ case AV_CODEC_ID_DSD_MSBF:
+ case AV_CODEC_ID_DSD_LSBF_PLANAR:
+ case AV_CODEC_ID_DSD_MSBF_PLANAR:
case AV_CODEC_ID_PCM_ALAW:
case AV_CODEC_ID_PCM_MULAW:
case AV_CODEC_ID_PCM_S8:
+ case AV_CODEC_ID_PCM_S8_PLANAR:
case AV_CODEC_ID_PCM_U8:
case AV_CODEC_ID_PCM_ZORK:
return 8;
case AV_CODEC_ID_PCM_S16BE:
+ case AV_CODEC_ID_PCM_S16BE_PLANAR:
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_S16LE_PLANAR:
case AV_CODEC_ID_PCM_U16BE:
@@ -2162,6 +3293,27 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id)
}
}
+enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be)
+{
+ static const enum AVCodecID map[AV_SAMPLE_FMT_NB][2] = {
+ [AV_SAMPLE_FMT_U8 ] = { AV_CODEC_ID_PCM_U8, AV_CODEC_ID_PCM_U8 },
+ [AV_SAMPLE_FMT_S16 ] = { AV_CODEC_ID_PCM_S16LE, AV_CODEC_ID_PCM_S16BE },
+ [AV_SAMPLE_FMT_S32 ] = { AV_CODEC_ID_PCM_S32LE, AV_CODEC_ID_PCM_S32BE },
+ [AV_SAMPLE_FMT_FLT ] = { AV_CODEC_ID_PCM_F32LE, AV_CODEC_ID_PCM_F32BE },
+ [AV_SAMPLE_FMT_DBL ] = { AV_CODEC_ID_PCM_F64LE, AV_CODEC_ID_PCM_F64BE },
+ [AV_SAMPLE_FMT_U8P ] = { AV_CODEC_ID_PCM_U8, AV_CODEC_ID_PCM_U8 },
+ [AV_SAMPLE_FMT_S16P] = { AV_CODEC_ID_PCM_S16LE, AV_CODEC_ID_PCM_S16BE },
+ [AV_SAMPLE_FMT_S32P] = { AV_CODEC_ID_PCM_S32LE, AV_CODEC_ID_PCM_S32BE },
+ [AV_SAMPLE_FMT_FLTP] = { AV_CODEC_ID_PCM_F32LE, AV_CODEC_ID_PCM_F32BE },
+ [AV_SAMPLE_FMT_DBLP] = { AV_CODEC_ID_PCM_F64LE, AV_CODEC_ID_PCM_F64BE },
+ };
+ if (fmt < 0 || fmt >= AV_SAMPLE_FMT_NB)
+ return AV_CODEC_ID_NONE;
+ if (be < 0 || be > 1)
+ be = AV_NE(1, 0);
+ return map[fmt][be];
+}
+
int av_get_bits_per_sample(enum AVCodecID codec_id)
{
switch (codec_id) {
@@ -2192,8 +3344,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
bps = av_get_exact_bits_per_sample(avctx->codec_id);
/* codecs with an exact constant bits per sample */
- if (bps > 0 && ch > 0 && frame_bytes > 0)
- return (frame_bytes * 8) / (bps * ch);
+ if (bps > 0 && ch > 0 && frame_bytes > 0 && ch < 32768 && bps < 32768)
+ return (frame_bytes * 8LL) / (bps * ch);
bps = avctx->bits_per_coded_sample;
/* codecs with a fixed packet duration */
@@ -2202,16 +3354,16 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
case AV_CODEC_ID_ADPCM_IMA_QT: return 64;
case AV_CODEC_ID_ADPCM_EA_XAS: return 128;
case AV_CODEC_ID_AMR_NB:
+ case AV_CODEC_ID_EVRC:
case AV_CODEC_ID_GSM:
case AV_CODEC_ID_QCELP:
- case AV_CODEC_ID_RA_144:
case AV_CODEC_ID_RA_288: return 160;
- case AV_CODEC_ID_IMC: return 256;
case AV_CODEC_ID_AMR_WB:
case AV_CODEC_ID_GSM_MS: return 320;
case AV_CODEC_ID_MP1: return 384;
case AV_CODEC_ID_ATRAC1: return 512;
case AV_CODEC_ID_ATRAC3: return 1024;
+ case AV_CODEC_ID_ATRAC3P: return 2048;
case AV_CODEC_ID_MP2:
case AV_CODEC_ID_MUSEPACK7: return 1152;
case AV_CODEC_ID_AC3: return 1536;
@@ -2252,6 +3404,10 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
return 240 * (frame_bytes / 32);
if (id == AV_CODEC_ID_NELLYMOSER)
return 256 * (frame_bytes / 64);
+ if (id == AV_CODEC_ID_RA_144)
+ return 160 * (frame_bytes / 20);
+ if (id == AV_CODEC_ID_G723_1)
+ return 240 * (frame_bytes / 24);
if (bps > 0) {
/* calc from frame_bytes and bits_per_coded_sample */
@@ -2262,6 +3418,10 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
if (ch > 0) {
/* calc from frame_bytes and channels */
switch (id) {
+ case AV_CODEC_ID_ADPCM_AFC:
+ return frame_bytes / (9 * ch) * 16;
+ case AV_CODEC_ID_ADPCM_DTK:
+ return frame_bytes / (16 * ch) * 28;
case AV_CODEC_ID_ADPCM_4XM:
case AV_CODEC_ID_ADPCM_IMA_ISS:
return (frame_bytes - 4 * ch) * 2 / ch;
@@ -2283,6 +3443,9 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
return 6 * frame_bytes / ch;
case AV_CODEC_ID_PCM_LXF:
return 2 * (frame_bytes / (5 * ch));
+ case AV_CODEC_ID_IAC:
+ case AV_CODEC_ID_IMC:
+ return 4 * frame_bytes / ch;
}
if (tag) {
@@ -2300,11 +3463,15 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
int blocks = frame_bytes / ba;
switch (avctx->codec_id) {
case AV_CODEC_ID_ADPCM_IMA_WAV:
- return blocks * (1 + (ba - 4 * ch) / (4 * ch) * 8);
+ if (bps < 2 || bps > 5)
+ return 0;
+ return blocks * (1 + (ba - 4 * ch) / (bps * ch) * 8);
case AV_CODEC_ID_ADPCM_IMA_DK3:
return blocks * (((ba - 16) * 2 / 3 * 4) / ch);
case AV_CODEC_ID_ADPCM_IMA_DK4:
return blocks * (1 + (ba - 4 * ch) * 2 / ch);
+ case AV_CODEC_ID_ADPCM_IMA_RAD:
+ return blocks * ((ba - 4 * ch) * 2 / ch);
case AV_CODEC_ID_ADPCM_MS:
return blocks * (2 + (ba - 7 * ch) * 2 / ch);
}
@@ -2314,8 +3481,12 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
/* calc from frame_bytes, channels, and bits_per_coded_sample */
switch (avctx->codec_id) {
case AV_CODEC_ID_PCM_DVD:
+ if(bps<4)
+ return 0;
return 2 * (frame_bytes / ((bps * 2 / 8) * ch));
case AV_CODEC_ID_PCM_BLURAY:
+ if(bps<4)
+ return 0;
return frame_bytes / ((FFALIGN(ch, 2) * bps) / 8);
case AV_CODEC_ID_S302M:
return 2 * (frame_bytes / ((bps + 4) / 4)) / ch;
@@ -2324,6 +3495,17 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
}
}
+ /* Fall back on using frame_size */
+ if (avctx->frame_size > 1 && frame_bytes)
+ return avctx->frame_size;
+
+ //For WMA we currently have no other means to calculate duration thus we
+ //do it here by assuming CBR, which is true for all known cases.
+ if (avctx->bit_rate>0 && frame_bytes>0 && avctx->sample_rate>0 && avctx->block_align>1) {
+ if (avctx->codec_id == AV_CODEC_ID_WMAV1 || avctx->codec_id == AV_CODEC_ID_WMAV2)
+ return (frame_bytes * 8LL * avctx->sample_rate) / avctx->bit_rate;
+ }
+
return 0;
}
@@ -2360,7 +3542,7 @@ int ff_match_2uint16(const uint16_t(*tab)[2], int size, int a, int b)
FF_DISABLE_DEPRECATION_WARNINGS
void av_log_missing_feature(void *avc, const char *feature, int want_sample)
{
- av_log(avc, AV_LOG_WARNING, "%s is not implemented. Update your Libav "
+ av_log(avc, AV_LOG_WARNING, "%s is not implemented. Update your FFmpeg "
"version to the newest one from Git. If the problem still "
"occurs, it means that your file has a feature which has not "
"been implemented.\n", feature);
@@ -2377,8 +3559,8 @@ void av_log_ask_for_sample(void *avc, const char *msg, ...)
if (msg)
av_vlog(avc, AV_LOG_WARNING, msg, argument_list);
av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample "
- "of this file to ftp://upload.libav.org/incoming/ "
- "and contact the libav-devel mailing list.\n");
+ "of this file to ftp://upload.ffmpeg.org/incoming/ "
+ "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n");
va_end(argument_list);
}
@@ -2386,14 +3568,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
#endif /* FF_API_MISSING_SAMPLE */
static AVHWAccel *first_hwaccel = NULL;
+static AVHWAccel **last_hwaccel = &first_hwaccel;
void av_register_hwaccel(AVHWAccel *hwaccel)
{
- AVHWAccel **p = &first_hwaccel;
- while (*p)
- p = &(*p)->next;
- *p = hwaccel;
+ AVHWAccel **p = last_hwaccel;
hwaccel->next = NULL;
+ while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel))
+ p = &(*p)->next;
+ last_hwaccel = &hwaccel->next;
}
AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel)
@@ -2433,6 +3616,43 @@ int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op))
return 0;
}
+int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec)
+{
+ if (lockmgr_cb) {
+ if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN))
+ return -1;
+ }
+
+ if (avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, 1) != 1 &&
+ !(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE)) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Insufficient thread locking. At least %d threads are "
+ "calling avcodec_open2() at the same time right now.\n",
+ entangled_thread_counter);
+ if (!lockmgr_cb)
+ av_log(log_ctx, AV_LOG_ERROR, "No lock manager is set, please see av_lockmgr_register()\n");
+ ff_avcodec_locked = 1;
+ ff_unlock_avcodec();
+ return AVERROR(EINVAL);
+ }
+ av_assert0(!ff_avcodec_locked);
+ ff_avcodec_locked = 1;
+ return 0;
+}
+
+int ff_unlock_avcodec(void)
+{
+ av_assert0(ff_avcodec_locked);
+ ff_avcodec_locked = 0;
+ avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, -1);
+ if (lockmgr_cb) {
+ if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE))
+ return -1;
+ }
+
+ return 0;
+}
+
int avpriv_lock_avformat(void)
{
if (lockmgr_cb) {
@@ -2456,7 +3676,7 @@ unsigned int avpriv_toupper4(unsigned int x)
return av_toupper(x & 0xFF) +
(av_toupper((x >> 8) & 0xFF) << 8) +
(av_toupper((x >> 16) & 0xFF) << 16) +
- (av_toupper((x >> 24) & 0xFF) << 24);
+((unsigned)av_toupper((x >> 24) & 0xFF) << 24);
}
int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src)
@@ -2469,6 +3689,8 @@ int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src)
if (ret < 0)
return ret;
+ av_assert0(!dst->progress);
+
if (src->progress &&
!(dst->progress = av_buffer_ref(src->progress))) {
ff_thread_release_buffer(dst->owner, dst);
@@ -2480,6 +3702,11 @@ int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src)
#if !HAVE_THREADS
+enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt)
+{
+ return ff_get_format(avctx, fmt);
+}
+
int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
{
f->owner = avctx;
@@ -2504,10 +3731,38 @@ void ff_thread_await_progress(ThreadFrame *f, int progress, int field)
{
}
+int ff_thread_can_start_frame(AVCodecContext *avctx)
+{
+ return 1;
+}
+
+int ff_alloc_entries(AVCodecContext *avctx, int count)
+{
+ return 0;
+}
+
+void ff_reset_entries(AVCodecContext *avctx)
+{
+}
+
+void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift)
+{
+}
+
+void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n)
+{
+}
+
#endif
enum AVMediaType avcodec_get_type(enum AVCodecID codec_id)
{
+ AVCodec *c= avcodec_find_decoder(codec_id);
+ if(!c)
+ c= avcodec_find_encoder(codec_id);
+ if(c)
+ return c->type;
+
if (codec_id <= AV_CODEC_ID_NONE)
return AVMEDIA_TYPE_UNKNOWN;
else if (codec_id < AV_CODEC_ID_FIRST_AUDIO)
@@ -2525,13 +3780,36 @@ int avcodec_is_open(AVCodecContext *s)
return !!s->internal;
}
-const uint8_t *avpriv_find_start_code(const uint8_t *restrict p,
+int avpriv_bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf)
+{
+ int ret;
+ char *str;
+
+ ret = av_bprint_finalize(buf, &str);
+ if (ret < 0)
+ return ret;
+ if (!av_bprint_is_complete(buf)) {
+ av_free(str);
+ return AVERROR(ENOMEM);
+ }
+
+ avctx->extradata = str;
+ /* Note: the string is NUL terminated (so extradata can be read as a
+ * string), but the ending character is not accounted in the size (in
+ * binary formats you are likely not supposed to mux that character). When
+ * extradata is copied, it is also padded with FF_INPUT_BUFFER_PADDING_SIZE
+ * zeros. */
+ avctx->extradata_size = buf->len;
+ return 0;
+}
+
+const uint8_t *avpriv_find_start_code(const uint8_t *av_restrict p,
const uint8_t *end,
- uint32_t * restrict state)
+ uint32_t *av_restrict state)
{
int i;
- assert(p <= end);
+ av_assert0(p <= end);
if (p >= end)
return end;
diff --git a/libavcodec/utvideo.c b/libavcodec/utvideo.c
index eb5a924222..308adb75d9 100644
--- a/libavcodec/utvideo.c
+++ b/libavcodec/utvideo.c
@@ -2,20 +2,20 @@
* Common Ut Video code
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/utvideo.h b/libavcodec/utvideo.h
index 718273c47f..78c3ec54dc 100644
--- a/libavcodec/utvideo.h
+++ b/libavcodec/utvideo.h
@@ -2,20 +2,20 @@
* Common Ut Video header
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c
index bb8c7aac1e..3a3c46e0bc 100644
--- a/libavcodec/utvideodec.c
+++ b/libavcodec/utvideodec.c
@@ -2,20 +2,20 @@
* Ut Video decoder
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,13 +56,14 @@ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym)
*fsym = he[0].sym;
return 0;
}
- if (he[0].len > 32)
- return -1;
last = 255;
while (he[last].len == 255 && last)
last--;
+ if (he[last].len > 32)
+ return -1;
+
code = 1;
for (i = last; i >= 0; i--) {
codes[i] = code >> (32 - he[i].len);
@@ -71,7 +72,7 @@ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym)
code += 0x80000000u >> (he[i].len - 1);
}
- return ff_init_vlc_sparse(vlc, FFMIN(he[last].len, 9), last + 1,
+ return ff_init_vlc_sparse(vlc, FFMIN(he[last].len, 11), last + 1,
bits, sizeof(*bits), sizeof(*bits),
codes, sizeof(*codes), sizeof(*codes),
syms, sizeof(*syms), sizeof(*syms), 0);
@@ -156,7 +157,7 @@ static int decode_plane(UtvideoContext *c, int plane_no,
"Slice decoding ran out of bits\n");
goto fail;
}
- pix = get_vlc2(&gb, vlc.table, vlc.bits, 4);
+ pix = get_vlc2(&gb, vlc.table, vlc.bits, 3);
if (pix < 0) {
av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n");
goto fail;
@@ -213,9 +214,9 @@ static void restore_median(uint8_t *src, int step, int stride,
slice_start = ((slice * height) / slices) & cmask;
slice_height = ((((slice + 1) * height) / slices) & cmask) -
slice_start;
+
if (!slice_height)
continue;
-
bsrc = src + slice_start * stride;
// first line - left neighbour prediction
@@ -226,7 +227,7 @@ static void restore_median(uint8_t *src, int step, int stride,
A = bsrc[i];
}
bsrc += stride;
- if (slice_height == 1)
+ if (slice_height <= 1)
continue;
// second line - first element has top prediction, the rest uses median
C = bsrc[-stride];
@@ -288,7 +289,7 @@ static void restore_median_il(uint8_t *src, int step, int stride,
A = bsrc[stride + i];
}
bsrc += stride2;
- if (slice_height == 1)
+ if (slice_height <= 1)
continue;
// second line - first element has top prediction, the rest uses median
C = bsrc[-stride2];
@@ -339,12 +340,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
GetByteContext gb;
ThreadFrame frame = { .f = data };
- if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
return ret;
- }
-
- ff_thread_finish_setup(avctx);
/* parse plane structure to get frame flags and validate slice offsets */
bytestream2_init(&gb, buf, buf_size);
diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c
index 8dc208bcde..99791ba1a9 100644
--- a/libavcodec/utvideoenc.c
+++ b/libavcodec/utvideoenc.c
@@ -2,20 +2,20 @@
* Ut Video encoder
* Copyright (c) 2012 Jan Ekström
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,7 +48,7 @@ static av_cold int utvideo_encode_close(AVCodecContext *avctx)
UtvideoContext *c = avctx->priv_data;
int i;
- av_freep(&avctx->coded_frame);
+ av_frame_free(&avctx->coded_frame);
av_freep(&c->slice_bits);
for (i = 0; i < 4; i++)
av_freep(&c->slice_buffer[i]);
@@ -389,7 +389,7 @@ static int write_huff_codes(uint8_t *src, uint8_t *dst, int dst_size,
}
static int encode_plane(AVCodecContext *avctx, uint8_t *src,
- uint8_t *dst, int stride,
+ uint8_t *dst, int stride, int plane_no,
int width, int height, PutByteContext *pb)
{
UtvideoContext *c = avctx->priv_data;
@@ -399,15 +399,17 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src,
HuffEntry he[256];
uint32_t offset = 0, slice_len = 0;
+ const int cmask = ~(!plane_no && avctx->pix_fmt == AV_PIX_FMT_YUV420P);
int i, sstart, send = 0;
int symbol;
+ int ret;
/* Do prediction / make planes */
switch (c->frame_pred) {
case PRED_NONE:
for (i = 0; i < c->slices; i++) {
sstart = send;
- send = height * (i + 1) / c->slices;
+ send = height * (i + 1) / c->slices & cmask;
av_image_copy_plane(dst + sstart * width, width,
src + sstart * stride, stride,
width, send - sstart);
@@ -416,7 +418,7 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src,
case PRED_LEFT:
for (i = 0; i < c->slices; i++) {
sstart = send;
- send = height * (i + 1) / c->slices;
+ send = height * (i + 1) / c->slices & cmask;
left_predict(src + sstart * stride, dst + sstart * width,
stride, width, send - sstart);
}
@@ -424,7 +426,7 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src,
case PRED_MEDIAN:
for (i = 0; i < c->slices; i++) {
sstart = send;
- send = height * (i + 1) / c->slices;
+ send = height * (i + 1) / c->slices & cmask;
median_predict(c, src + sstart * stride, dst + sstart * width,
stride, width, send - sstart);
}
@@ -443,7 +445,7 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src,
/* If non-zero count is found, see if it matches width * height */
if (counts[symbol]) {
/* Special case if only one symbol was used */
- if (counts[symbol] == width * height) {
+ if (counts[symbol] == width * (int64_t)height) {
/*
* Write a zero for the single symbol
* used in the plane, else 0xFF.
@@ -467,7 +469,8 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src,
}
/* Calculate huffman lengths */
- ff_huff_gen_len_table(lengths, counts);
+ if ((ret = ff_huff_gen_len_table(lengths, counts, 256, 1)) < 0)
+ return ret;
/*
* Write the plane's header into the output packet:
@@ -487,14 +490,14 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src,
send = 0;
for (i = 0; i < c->slices; i++) {
sstart = send;
- send = height * (i + 1) / c->slices;
+ send = height * (i + 1) / c->slices & cmask;
/*
* Write the huffman codes to a buffer,
* get the offset in bits and convert to bytes.
*/
offset += write_huff_codes(dst + sstart * width, c->slice_bits,
- width * (send - sstart), width,
+ width * height + 4, width,
send - sstart, he) >> 3;
slice_len = offset - slice_len;
@@ -541,22 +544,17 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
int i, ret = 0;
/* Allocate a new packet if needed, and set it to the pointer dst */
- ret = ff_alloc_packet(pkt, (256 + 4 * c->slices + width * height) *
- c->planes + 4);
+ ret = ff_alloc_packet2(avctx, pkt, (256 + 4 * c->slices + width * height) *
+ c->planes + 4);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "Error allocating the output packet, or the provided packet "
- "was too small.\n");
+ if (ret < 0)
return ret;
- }
dst = pkt->data;
bytestream2_init_writer(&pb, dst, pkt->size);
- av_fast_malloc(&c->slice_bits, &c->slice_bits_size,
- width * height + FF_INPUT_BUFFER_PADDING_SIZE);
+ av_fast_padded_malloc(&c->slice_bits, &c->slice_bits_size, width * height + 4);
if (!c->slice_bits) {
av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer 2.\n");
@@ -574,7 +572,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case AV_PIX_FMT_RGBA:
for (i = 0; i < c->planes; i++) {
ret = encode_plane(avctx, c->slice_buffer[i] + 2 * c->slice_stride,
- c->slice_buffer[i], c->slice_stride,
+ c->slice_buffer[i], c->slice_stride, i,
width, height, &pb);
if (ret) {
@@ -586,7 +584,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case AV_PIX_FMT_YUV422P:
for (i = 0; i < c->planes; i++) {
ret = encode_plane(avctx, pic->data[i], c->slice_buffer[0],
- pic->linesize[i], width >> !!i, height, &pb);
+ pic->linesize[i], i, width >> !!i, height, &pb);
if (ret) {
av_log(avctx, AV_LOG_ERROR, "Error encoding plane %d.\n", i);
@@ -597,7 +595,7 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
case AV_PIX_FMT_YUV420P:
for (i = 0; i < c->planes; i++) {
ret = encode_plane(avctx, pic->data[i], c->slice_buffer[0],
- pic->linesize[i], width >> !!i, height >> !!i,
+ pic->linesize[i], i, width >> !!i, height >> !!i,
&pb);
if (ret) {
@@ -645,6 +643,7 @@ AVCodec ff_utvideo_encoder = {
.init = utvideo_encode_init,
.encode2 = utvideo_encode_frame,
.close = utvideo_encode_close,
+ .capabilities = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_YUV422P,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
diff --git a/libavcodec/v210dec.c b/libavcodec/v210dec.c
index 8827397071..f1e968d9a4 100644
--- a/libavcodec/v210dec.c
+++ b/libavcodec/v210dec.c
@@ -4,31 +4,55 @@
* Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avcodec.h"
#include "internal.h"
+#include "v210dec.h"
#include "libavutil/bswap.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"
+#define READ_PIXELS(a, b, c) \
+ do { \
+ val = av_le2ne32(*src++); \
+ *a++ = val & 0x3FF; \
+ *b++ = (val >> 10) & 0x3FF; \
+ *c++ = (val >> 20) & 0x3FF; \
+ } while (0)
+
+static void v210_planar_unpack_c(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width)
+{
+ uint32_t val;
+ int i;
+
+ for( i = 0; i < width-5; i += 6 ){
+ READ_PIXELS(u, y, v);
+ READ_PIXELS(y, u, y);
+ READ_PIXELS(v, y, u);
+ READ_PIXELS(y, v, y);
+ }
+}
+
static av_cold int decode_init(AVCodecContext *avctx)
{
+ V210DecContext *s = avctx->priv_data;
+
if (avctx->width & 1) {
av_log(avctx, AV_LOG_ERROR, "v210 needs even width\n");
return AVERROR_INVALIDDATA;
@@ -36,22 +60,48 @@ static av_cold int decode_init(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
avctx->bits_per_raw_sample = 10;
+ s->unpack_frame = v210_planar_unpack_c;
+
+ if (HAVE_MMX)
+ ff_v210_x86_init(s);
+
return 0;
}
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
- int h, w, ret;
+ V210DecContext *s = avctx->priv_data;
+
+ int h, w, ret, stride, aligned_input;
AVFrame *pic = data;
const uint8_t *psrc = avpkt->data;
uint16_t *y, *u, *v;
- int aligned_width = ((avctx->width + 47) / 48) * 48;
- int stride = aligned_width * 8 / 3;
+
+ if (s->custom_stride )
+ stride = s->custom_stride;
+ else {
+ int aligned_width = ((avctx->width + 47) / 48) * 48;
+ stride = aligned_width * 8 / 3;
+ }
if (avpkt->size < stride * avctx->height) {
- av_log(avctx, AV_LOG_ERROR, "packet too small\n");
- return AVERROR_INVALIDDATA;
+ if ((((avctx->width + 23) / 24) * 24 * 8) / 3 * avctx->height == avpkt->size) {
+ stride = avpkt->size / avctx->height;
+ if (!s->stride_warning_shown)
+ av_log(avctx, AV_LOG_WARNING, "Broken v210 with too small padding (64 byte) detected\n");
+ s->stride_warning_shown = 1;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "packet too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ aligned_input = !((uintptr_t)psrc & 0xf) && !(stride & 0xf);
+ if (aligned_input != s->aligned_input) {
+ s->aligned_input = aligned_input;
+ if (HAVE_MMX)
+ ff_v210_x86_init(s);
}
if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
@@ -63,36 +113,31 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
pic->pict_type = AV_PICTURE_TYPE_I;
pic->key_frame = 1;
-#define READ_PIXELS(a, b, c) \
- do { \
- val = av_le2ne32(*src++); \
- *a++ = val & 0x3FF; \
- *b++ = (val >> 10) & 0x3FF; \
- *c++ = (val >> 20) & 0x3FF; \
- } while (0)
-
for (h = 0; h < avctx->height; h++) {
const uint32_t *src = (const uint32_t*)psrc;
uint32_t val;
- for (w = 0; w < avctx->width - 5; w += 6) {
- READ_PIXELS(u, y, v);
- READ_PIXELS(y, u, y);
- READ_PIXELS(v, y, u);
- READ_PIXELS(y, v, y);
- }
+
+ w = (avctx->width / 6) * 6;
+ s->unpack_frame(src, y, u, v, w);
+
+ y += w;
+ u += w >> 1;
+ v += w >> 1;
+ src += (w << 1) / 3;
+
if (w < avctx->width - 1) {
READ_PIXELS(u, y, v);
val = av_le2ne32(*src++);
*y++ = val & 0x3FF;
- }
- if (w < avctx->width - 3) {
- *u++ = (val >> 10) & 0x3FF;
- *y++ = (val >> 20) & 0x3FF;
+ if (w < avctx->width - 3) {
+ *u++ = (val >> 10) & 0x3FF;
+ *y++ = (val >> 20) & 0x3FF;
- val = av_le2ne32(*src++);
- *v++ = val & 0x3FF;
- *y++ = (val >> 10) & 0x3FF;
+ val = av_le2ne32(*src++);
+ *v++ = val & 0x3FF;
+ *y++ = (val >> 10) & 0x3FF;
+ }
}
psrc += stride;
@@ -101,17 +146,40 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
v += pic->linesize[2] / 2 - avctx->width / 2;
}
+ if (avctx->field_order > AV_FIELD_PROGRESSIVE) {
+ /* we have interlaced material flagged in container */
+ pic->interlaced_frame = 1;
+ if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB)
+ pic->top_field_first = 1;
+ }
+
*got_frame = 1;
return avpkt->size;
}
+#define V210DEC_FLAGS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption v210dec_options[] = {
+ {"custom_stride", "Custom V210 stride", offsetof(V210DecContext, custom_stride), FF_OPT_TYPE_INT,
+ {.i64 = 0}, INT_MIN, INT_MAX, V210DEC_FLAGS},
+ {NULL}
+};
+
+static const AVClass v210dec_class = {
+ "V210 Decoder",
+ av_default_item_name,
+ v210dec_options,
+ LIBAVUTIL_VERSION_INT,
+};
+
AVCodec ff_v210_decoder = {
.name = "v210",
.long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_V210,
+ .priv_data_size = sizeof(V210DecContext),
.init = decode_init,
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
+ .priv_class = &v210dec_class,
};
diff --git a/libavcodec/v210dec.h b/libavcodec/v210dec.h
new file mode 100644
index 0000000000..533afc435c
--- /dev/null
+++ b/libavcodec/v210dec.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_V210DEC_H
+#define AVCODEC_V210DEC_H
+
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+
+typedef struct {
+ AVClass *av_class;
+ int custom_stride;
+ int aligned_input;
+ int stride_warning_shown;
+ void (*unpack_frame)(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width);
+} V210DecContext;
+
+void ff_v210_x86_init(V210DecContext *s);
+
+#endif /* AVCODEC_V210DEC_H */
diff --git a/libavcodec/v210enc.c b/libavcodec/v210enc.c
index cb887887ee..2e0fd43b4e 100644
--- a/libavcodec/v210enc.c
+++ b/libavcodec/v210enc.c
@@ -4,20 +4,20 @@
* Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -215,7 +215,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
static av_cold int encode_close(AVCodecContext *avctx)
{
- av_freep(&avctx->coded_frame);
+ av_frame_free(&avctx->coded_frame);
return 0;
}
diff --git a/libavcodec/v210enc.h b/libavcodec/v210enc.h
index be9b66de92..9179d7353e 100644
--- a/libavcodec/v210enc.h
+++ b/libavcodec/v210enc.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/v210x.c b/libavcodec/v210x.c
index 2922c05175..6330715793 100644
--- a/libavcodec/v210x.c
+++ b/libavcodec/v210x.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/v308dec.c b/libavcodec/v308dec.c
new file mode 100644
index 0000000000..1d31f0a9c7
--- /dev/null
+++ b/libavcodec/v308dec.c
@@ -0,0 +1,83 @@
+/*
+ * v308 decoder
+ * Copyright (c) 2011 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int v308_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUV444P;
+
+ if (avctx->width & 1)
+ av_log(avctx, AV_LOG_WARNING, "v308 requires width to be even.\n");
+
+ return 0;
+}
+
+static int v308_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVFrame *pic = data;
+ const uint8_t *src = avpkt->data;
+ uint8_t *y, *u, *v;
+ int i, j, ret;
+
+ if (avpkt->size < 3 * avctx->height * avctx->width) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->key_frame = 1;
+ pic->pict_type = AV_PICTURE_TYPE_I;
+
+ y = pic->data[0];
+ u = pic->data[1];
+ v = pic->data[2];
+
+ for (i = 0; i < avctx->height; i++) {
+ for (j = 0; j < avctx->width; j++) {
+ v[j] = *src++;
+ y[j] = *src++;
+ u[j] = *src++;
+ }
+
+ y += pic->linesize[0];
+ u += pic->linesize[1];
+ v += pic->linesize[2];
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_v308_decoder = {
+ .name = "v308",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_V308,
+ .init = v308_decode_init,
+ .decode = v308_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/v308enc.c b/libavcodec/v308enc.c
new file mode 100644
index 0000000000..408784b044
--- /dev/null
+++ b/libavcodec/v308enc.c
@@ -0,0 +1,94 @@
+/*
+ * v308 encoder
+ *
+ * Copyright (c) 2011 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avcodec.h"
+#include "internal.h"
+
+static av_cold int v308_encode_init(AVCodecContext *avctx)
+{
+ if (avctx->width & 1) {
+ av_log(avctx, AV_LOG_ERROR, "v308 requires width to be even.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avctx->coded_frame = av_frame_alloc();
+
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static int v308_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ uint8_t *dst;
+ uint8_t *y, *u, *v;
+ int i, j, ret;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 3)) < 0)
+ return ret;
+ dst = pkt->data;
+
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ y = pic->data[0];
+ u = pic->data[1];
+ v = pic->data[2];
+
+ for (i = 0; i < avctx->height; i++) {
+ for (j = 0; j < avctx->width; j++) {
+ *dst++ = v[j];
+ *dst++ = y[j];
+ *dst++ = u[j];
+ }
+ y += pic->linesize[0];
+ u += pic->linesize[1];
+ v += pic->linesize[2];
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int v308_encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+AVCodec ff_v308_encoder = {
+ .name = "v308",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_V308,
+ .init = v308_encode_init,
+ .encode2 = v308_encode_frame,
+ .close = v308_encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/v408dec.c b/libavcodec/v408dec.c
new file mode 100644
index 0000000000..be442faae1
--- /dev/null
+++ b/libavcodec/v408dec.c
@@ -0,0 +1,103 @@
+/*
+ * v408 decoder
+ * Copyright (c) 2012 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int v408_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
+
+ return 0;
+}
+
+static int v408_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVFrame *pic = data;
+ const uint8_t *src = avpkt->data;
+ uint8_t *y, *u, *v, *a;
+ int i, j, ret;
+
+ if (avpkt->size < 4 * avctx->height * avctx->width) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->key_frame = 1;
+ pic->pict_type = AV_PICTURE_TYPE_I;
+
+ y = pic->data[0];
+ u = pic->data[1];
+ v = pic->data[2];
+ a = pic->data[3];
+
+ for (i = 0; i < avctx->height; i++) {
+ for (j = 0; j < avctx->width; j++) {
+ if (avctx->codec_id==AV_CODEC_ID_AYUV) {
+ v[j] = *src++;
+ u[j] = *src++;
+ y[j] = *src++;
+ a[j] = *src++;
+ } else {
+ u[j] = *src++;
+ y[j] = *src++;
+ v[j] = *src++;
+ a[j] = *src++;
+ }
+ }
+
+ y += pic->linesize[0];
+ u += pic->linesize[1];
+ v += pic->linesize[2];
+ a += pic->linesize[3];
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+#if CONFIG_AYUV_DECODER
+AVCodec ff_ayuv_decoder = {
+ .name = "ayuv",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AYUV,
+ .init = v408_decode_init,
+ .decode = v408_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
+#if CONFIG_V408_DECODER
+AVCodec ff_v408_decoder = {
+ .name = "v408",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_V408,
+ .init = v408_decode_init,
+ .decode = v408_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
diff --git a/libavcodec/v408enc.c b/libavcodec/v408enc.c
new file mode 100644
index 0000000000..cdb2efaf7a
--- /dev/null
+++ b/libavcodec/v408enc.c
@@ -0,0 +1,113 @@
+/*
+ * v408 encoder
+ *
+ * Copyright (c) 2012 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avcodec.h"
+#include "internal.h"
+
+static av_cold int v408_encode_init(AVCodecContext *avctx)
+{
+ avctx->coded_frame = av_frame_alloc();
+
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static int v408_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ uint8_t *dst;
+ uint8_t *y, *u, *v, *a;
+ int i, j, ret;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 4)) < 0)
+ return ret;
+ dst = pkt->data;
+
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ y = pic->data[0];
+ u = pic->data[1];
+ v = pic->data[2];
+ a = pic->data[3];
+
+ for (i = 0; i < avctx->height; i++) {
+ for (j = 0; j < avctx->width; j++) {
+ if (avctx->codec_id==AV_CODEC_ID_AYUV) {
+ *dst++ = v[j];
+ *dst++ = u[j];
+ *dst++ = y[j];
+ *dst++ = a[j];
+ } else {
+ *dst++ = u[j];
+ *dst++ = y[j];
+ *dst++ = v[j];
+ *dst++ = a[j];
+ }
+ }
+ y += pic->linesize[0];
+ u += pic->linesize[1];
+ v += pic->linesize[2];
+ a += pic->linesize[3];
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int v408_encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+#if CONFIG_AYUV_ENCODER
+AVCodec ff_ayuv_encoder = {
+ .name = "ayuv",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_AYUV,
+ .init = v408_encode_init,
+ .encode2 = v408_encode_frame,
+ .close = v408_encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE },
+};
+#endif
+#if CONFIG_V408_ENCODER
+AVCodec ff_v408_encoder = {
+ .name = "v408",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_V408,
+ .init = v408_encode_init,
+ .encode2 = v408_encode_frame,
+ .close = v408_encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE },
+};
+#endif
diff --git a/libavcodec/v410dec.c b/libavcodec/v410dec.c
index 07be502276..e7a9c0e109 100644
--- a/libavcodec/v410dec.c
+++ b/libavcodec/v410dec.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2011 Derek Buitenhuis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,17 +49,15 @@ static int v410_decode_frame(AVCodecContext *avctx, void *data,
uint8_t *src = avpkt->data;
uint16_t *y, *u, *v;
uint32_t val;
- int i, j;
+ int i, j, ret;
if (avpkt->size < 4 * avctx->height * avctx->width) {
av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
return AVERROR(EINVAL);
}
- if (ff_get_buffer(avctx, pic, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
- return AVERROR(ENOMEM);
- }
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
pic->key_frame = 1;
pic->pict_type = AV_PICTURE_TYPE_I;
diff --git a/libavcodec/v410enc.c b/libavcodec/v410enc.c
index 77b32d7ab6..f2f7d7349b 100644
--- a/libavcodec/v410enc.c
+++ b/libavcodec/v410enc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2011 Derek Buitenhuis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,7 +28,7 @@
static av_cold int v410_encode_init(AVCodecContext *avctx)
{
if (avctx->width & 1) {
- av_log(avctx, AV_LOG_ERROR, "v410 requires even width.\n");
+ av_log(avctx, AV_LOG_ERROR, "v410 requires width to be even.\n");
return AVERROR_INVALIDDATA;
}
@@ -50,10 +50,8 @@ static int v410_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
uint32_t val;
int i, j, ret;
- if ((ret = ff_alloc_packet(pkt, avctx->width * avctx->height * 4)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 4)) < 0)
return ret;
- }
dst = pkt->data;
avctx->coded_frame->key_frame = 1;
@@ -83,7 +81,7 @@ static int v410_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
static av_cold int v410_encode_close(AVCodecContext *avctx)
{
- av_freep(&avctx->coded_frame);
+ av_frame_free(&avctx->coded_frame);
return 0;
}
diff --git a/libavcodec/vaapi.c b/libavcodec/vaapi.c
index aa90793952..6ac22e64fa 100644
--- a/libavcodec/vaapi.c
+++ b/libavcodec/vaapi.c
@@ -4,20 +4,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,6 +46,9 @@ int ff_vaapi_render_picture(struct vaapi_context *vactx, VASurfaceID surface)
VABufferID va_buffers[3];
unsigned int n_va_buffers = 0;
+ if (!vactx->pic_param_buf_id)
+ return 0;
+
vaUnmapBuffer(vactx->display, vactx->pic_param_buf_id);
va_buffers[n_va_buffers++] = vactx->pic_param_buf_id;
diff --git a/libavcodec/vaapi.h b/libavcodec/vaapi.h
index 39e88259d6..815a27e226 100644
--- a/libavcodec/vaapi.h
+++ b/libavcodec/vaapi.h
@@ -1,23 +1,23 @@
/*
- * Video Acceleration API (shared data between Libav and the video player)
+ * Video Acceleration API (shared data between FFmpeg and the video player)
* HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,7 +39,7 @@
*/
/**
- * This structure is used to share data between the Libav library and
+ * This structure is used to share data between the FFmpeg library and
* the client video application.
* This shall be zero-allocated and available as
* AVCodecContext.hwaccel_context. All user members can be set once
diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c
index 82a49f6060..eef3c29ab5 100644
--- a/libavcodec/vaapi_h264.c
+++ b/libavcodec/vaapi_h264.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,7 +26,7 @@
/**
* @file
- * This file implements the glue code between Libav's and VA API's
+ * This file implements the glue code between FFmpeg's and VA API's
* structures for H.264 decoding.
*/
@@ -44,10 +44,10 @@ static void init_vaapi_pic(VAPictureH264 *va_pic)
}
/**
- * Translate an Libav Picture into its VA API form.
+ * Translate an FFmpeg Picture into its VA API form.
*
* @param[out] va_pic A pointer to VA API's own picture struct
- * @param[in] pic A pointer to the Libav picture struct to convert
+ * @param[in] pic A pointer to the FFmpeg picture struct to convert
* @param[in] pic_structure The picture field type (as defined in mpegvideo.h),
* supersedes pic's field type if nonzero.
*/
@@ -148,11 +148,11 @@ static int fill_vaapi_ReferenceFrames(VAPictureParameterBufferH264 *pic_param,
}
/**
- * Fill in VA API reference picture lists from the Libav reference
+ * Fill in VA API reference picture lists from the FFmpeg reference
* picture list.
*
* @param[out] RefPicList VA API internal reference picture list
- * @param[in] ref_list A pointer to the Libav reference list
+ * @param[in] ref_list A pointer to the FFmpeg reference list
* @param[in] ref_count The number of reference pictures in ref_list
*/
static void fill_vaapi_RefPicList(VAPictureH264 RefPicList[32],
@@ -260,7 +260,7 @@ static int vaapi_h264_start_frame(AVCodecContext *avctx,
pic_param->seq_fields.bits.delta_pic_order_always_zero_flag = h->sps.delta_pic_order_always_zero_flag;
pic_param->num_slice_groups_minus1 = h->pps.slice_group_count - 1;
pic_param->slice_group_map_type = h->pps.mb_slice_group_map_type;
- pic_param->slice_group_change_rate_minus1 = 0; /* XXX: unimplemented in Libav */
+ pic_param->slice_group_change_rate_minus1 = 0; /* XXX: unimplemented in FFmpeg */
pic_param->pic_init_qp_minus26 = h->pps.init_qp - 26;
pic_param->pic_init_qs_minus26 = h->pps.init_qs - 26;
pic_param->chroma_qp_index_offset = h->pps.chroma_qp_index_offset[0];
diff --git a/libavcodec/vaapi_internal.h b/libavcodec/vaapi_internal.h
index d0fa7ae917..918c718d14 100644
--- a/libavcodec/vaapi_internal.h
+++ b/libavcodec/vaapi_internal.h
@@ -4,20 +4,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c
index d41a14a790..87fab89880 100644
--- a/libavcodec/vaapi_mpeg2.c
+++ b/libavcodec/vaapi_mpeg2.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -117,8 +117,8 @@ static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer
intra_slice_flag = get_bits1(&gb);
if (intra_slice_flag) {
skip_bits(&gb, 8);
- while (get_bits1(&gb) != 0)
- skip_bits(&gb, 8);
+ if (skip_1stop_8data_bits(&gb) < 0)
+ return AVERROR_INVALIDDATA;
}
macroblock_offset = get_bits_count(&gb);
diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c
index 49d5f07e43..9b283f7865 100644
--- a/libavcodec/vaapi_mpeg4.c
+++ b/libavcodec/vaapi_mpeg4.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -125,25 +125,14 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer
ff_dlog(avctx, "vaapi_mpeg4_decode_slice(): buffer %p, size %d\n", buffer, size);
- /* video_plane_with_short_video_header() contains all GOBs
- * in-order, and this is what VA API (Intel backend) expects: only
- * a single slice param. So fake macroblock_number for Libav so
- * that we don't call vaapi_mpeg4_decode_slice() again
- */
- if (avctx->codec->id == AV_CODEC_ID_H263)
- size = s->gb.buffer_end - buffer;
-
/* Fill in VASliceParameterBufferMPEG4 */
slice_param = (VASliceParameterBufferMPEG4 *)ff_vaapi_alloc_slice(avctx->hwaccel_context, buffer, size);
if (!slice_param)
return -1;
slice_param->macroblock_offset = get_bits_count(&s->gb) % 8;
- slice_param->macroblock_number = s->mb_y * s->mb_width + s->mb_x;
+ slice_param->macroblock_number = 0;
slice_param->quant_scale = s->qscale;
- if (avctx->codec->id == AV_CODEC_ID_H263)
- s->mb_y = s->mb_height;
-
return 0;
}
diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c
index fe01c52080..7ef9f2a08d 100644
--- a/libavcodec/vaapi_vc1.c
+++ b/libavcodec/vaapi_vc1.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2008-2009 Splitted-Desktop Systems
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,7 @@
#include "vc1.h"
#include "vc1data.h"
-/** Translate Libav MV modes to VA API */
+/** Translate FFmpeg MV modes to VA API */
static int get_VAMvModeVC1(enum MVModes mv_mode)
{
switch (mv_mode) {
@@ -129,7 +129,7 @@ static inline int vc1_get_TTFRM(VC1Context *v)
return 0;
}
-/** Pack Libav bitplanes into a VABitPlaneBuffer element */
+/** Pack FFmpeg bitplanes into a VABitPlaneBuffer element */
static inline void vc1_pack_bitplanes(uint8_t *bitplane, int n, const uint8_t *ff_bp[3], int x, int y, int stride)
{
const int bitplane_index = n / 2;
diff --git a/libavcodec/vb.c b/libavcodec/vb.c
index 56094d8b9d..41ee42eca5 100644
--- a/libavcodec/vb.c
+++ b/libavcodec/vb.c
@@ -2,20 +2,20 @@
* Beam Software VB decoder
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -73,7 +73,7 @@ static void vb_decode_palette(VBDecContext *c, int data_size)
return;
}
for (i = start; i <= start + size; i++)
- c->pal[i] = bytestream2_get_be24(&c->stream);
+ c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&c->stream);
}
static inline int check_pixel(uint8_t *buf, uint8_t *start, uint8_t *end)
@@ -197,10 +197,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
bytestream2_init(&c->stream, avpkt->data, avpkt->size);
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
flags = bytestream2_get_le16(&c->stream);
@@ -211,6 +209,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
if (flags & VB_HAS_VIDEO) {
size = bytestream2_get_le32(&c->stream);
+ if(size > bytestream2_get_bytes_left(&c->stream)+4 || size<4){
+ av_log(avctx, AV_LOG_ERROR, "Frame size invalid\n");
+ return -1;
+ }
vb_decode_framedata(c, offset);
bytestream2_skip(&c->stream, size - 4);
}
@@ -249,6 +251,12 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->frame = av_mallocz(avctx->width * avctx->height);
c->prev_frame = av_mallocz(avctx->width * avctx->height);
+ if (!c->frame || !c->prev_frame) {
+ av_freep(&c->frame);
+ av_freep(&c->prev_frame);
+ return AVERROR(ENOMEM);
+ }
+
return 0;
}
diff --git a/libavcodec/vble.c b/libavcodec/vble.c
index 8e042c25d1..e7331b19b5 100644
--- a/libavcodec/vble.c
+++ b/libavcodec/vble.c
@@ -2,20 +2,20 @@
* VBLE Decoder
* Copyright (c) 2011 Derek Buitenhuis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,56 +37,52 @@ typedef struct VBLEContext {
HuffYUVDSPContext hdsp;
int size;
- uint8_t *val; /* First holds the lengths of vlc symbols and then their values */
+ uint8_t *val; ///< This array first holds the lengths of vlc symbols and then their value.
} VBLEContext;
-static uint8_t vble_read_reverse_unary(GetBitContext *gb)
-{
- /* At most we need to read 9 bits total to get indices up to 8 */
- uint8_t val = show_bits(gb, 8);
-
- if (val) {
- val = 7 - av_log2_16bit(ff_reverse[val]);
- skip_bits(gb, val + 1);
- return val;
- } else {
- skip_bits(gb, 8);
- if (get_bits1(gb))
- return 8;
- }
-
- /* Return something larger than 8 on error */
- return UINT8_MAX;
-}
-
static int vble_unpack(VBLEContext *ctx, GetBitContext *gb)
{
int i;
+ int allbits = 0;
+ static const uint8_t LUT[256] = {
+ 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ };
/* Read all the lengths in first */
for (i = 0; i < ctx->size; i++) {
- ctx->val[i] = vble_read_reverse_unary(gb);
-
- if (ctx->val[i] == UINT8_MAX)
- return -1;
- }
-
- for (i = 0; i < ctx->size; i++) {
- /* Check we have enough bits left */
- if (get_bits_left(gb) < ctx->val[i])
- return -1;
-
- /* get_bits can't take a length of 0 */
- if (ctx->val[i])
- ctx->val[i] = (1 << ctx->val[i]) + get_bits(gb, ctx->val[i]) - 1;
+ /* At most we need to read 9 bits total to get indices up to 8 */
+ int val = show_bits(gb, 8);
+
+ // read reverse unary
+ if (val) {
+ val = LUT[val];
+ skip_bits(gb, val + 1);
+ ctx->val[i] = val;
+ } else {
+ skip_bits(gb, 8);
+ if (!get_bits1(gb))
+ return -1;
+ ctx->val[i] = 8;
+ }
+ allbits += ctx->val[i];
}
+ /* Check we have enough bits left */
+ if (get_bits_left(gb) < allbits)
+ return -1;
return 0;
}
static void vble_restore_plane(VBLEContext *ctx, AVFrame *pic,
- int plane, int offset,
- int width, int height)
+ GetBitContext *gb, int plane,
+ int offset, int width, int height)
{
uint8_t *dst = pic->data[plane];
uint8_t *val = ctx->val + offset;
@@ -94,9 +90,13 @@ static void vble_restore_plane(VBLEContext *ctx, AVFrame *pic,
int i, j, left, left_top;
for (i = 0; i < height; i++) {
- for (j = 0; j < width; j++)
- val[j] = (val[j] >> 1) ^ -(val[j] & 1);
-
+ for (j = 0; j < width; j++) {
+ /* get_bits can't take a length of 0 */
+ if (val[j]) {
+ int v = (1 << val[j]) + get_bits(gb, val[j]) - 1;
+ val[j] = (v >> 1) ^ -(v & 1);
+ }
+ }
if (i) {
left = 0;
left_top = dst[-stride];
@@ -122,13 +122,17 @@ static int vble_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
int version;
int offset = 0;
int width_uv = avctx->width / 2, height_uv = avctx->height / 2;
+ int ret;
- /* Allocate buffer */
- if (ff_get_buffer(avctx, pic, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
- return AVERROR(ENOMEM);
+ if (avpkt->size < 4 || avpkt->size - 4 > INT_MAX/8) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid packet size\n");
+ return AVERROR_INVALIDDATA;
}
+ /* Allocate buffer */
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
/* Set flags */
pic->key_frame = 1;
pic->pict_type = AV_PICTURE_TYPE_I;
@@ -148,15 +152,15 @@ static int vble_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
}
/* Restore planes. Should be almost identical to Huffyuv's. */
- vble_restore_plane(ctx, pic, 0, offset, avctx->width, avctx->height);
+ vble_restore_plane(ctx, pic, &gb, 0, offset, avctx->width, avctx->height);
/* Chroma */
if (!(ctx->avctx->flags & CODEC_FLAG_GRAY)) {
offset += avctx->width * avctx->height;
- vble_restore_plane(ctx, pic, 1, offset, width_uv, height_uv);
+ vble_restore_plane(ctx, pic, &gb, 1, offset, width_uv, height_uv);
offset += width_uv * height_uv;
- vble_restore_plane(ctx, pic, 2, offset, width_uv, height_uv);
+ vble_restore_plane(ctx, pic, &gb, 2, offset, width_uv, height_uv);
}
*got_frame = 1;
@@ -186,7 +190,7 @@ static av_cold int vble_decode_init(AVCodecContext *avctx)
ctx->size = avpicture_get_size(avctx->pix_fmt,
avctx->width, avctx->height);
- ctx->val = av_malloc(ctx->size * sizeof(*ctx->val));
+ ctx->val = av_malloc_array(ctx->size, sizeof(*ctx->val));
if (!ctx->val) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate values buffer.\n");
diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c
index 0631439a1c..08e1f2c4c7 100644
--- a/libavcodec/vc1.c
+++ b/libavcodec/vc1.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,9 +37,6 @@
#include "unary.h"
#include "simple_idct.h"
-#undef NDEBUG
-#include <assert.h>
-
/***********************************************************************/
/**
* @name VC-1 Bitplane decoding
@@ -47,21 +44,6 @@
* @{
*/
-/**
- * Imode types
- * @{
- */
-enum Imode {
- IMODE_RAW,
- IMODE_NORM2,
- IMODE_DIFF2,
- IMODE_NORM6,
- IMODE_DIFF6,
- IMODE_ROWSKIP,
- IMODE_COLSKIP
-};
-/** @} */ //imode defines
-
/** Decode rows by checking if they are skipped
* @param plane Buffer to store decoded bits
* @param[in] width Width of this buffer
@@ -137,12 +119,16 @@ static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v)
case IMODE_NORM2:
if ((height * width) & 1) {
*planep++ = get_bits1(gb);
- offset = 1;
+ y = offset = 1;
+ if (offset == width) {
+ offset = 0;
+ planep += stride - width;
+ }
}
else
- offset = 0;
+ y = offset = 0;
// decode bitplane as one long line
- for (y = offset; y < height * width; y += 2) {
+ for (; y < height * width; y += 2) {
code = get_vlc2(gb, ff_vc1_norm2_vlc.table, VC1_NORM2_VLC_BITS, 1);
*planep++ = code & 1;
offset++;
@@ -248,37 +234,34 @@ static int vop_dquant_decoding(VC1Context *v)
int pqdiff;
//variable size
- if (v->dquant == 2) {
- pqdiff = get_bits(gb, 3);
- if (pqdiff == 7)
- v->altpq = get_bits(gb, 5);
- else
- v->altpq = v->pq + pqdiff + 1;
- } else {
+ if (v->dquant != 2) {
v->dquantfrm = get_bits1(gb);
- if (v->dquantfrm) {
- v->dqprofile = get_bits(gb, 2);
- switch (v->dqprofile) {
- case DQPROFILE_SINGLE_EDGE:
- case DQPROFILE_DOUBLE_EDGES:
- v->dqsbedge = get_bits(gb, 2);
- break;
- case DQPROFILE_ALL_MBS:
- v->dqbilevel = get_bits1(gb);
- if (!v->dqbilevel)
- v->halfpq = 0;
- default:
- break; //Forbidden ?
- }
- if (v->dqbilevel || v->dqprofile != DQPROFILE_ALL_MBS) {
- pqdiff = get_bits(gb, 3);
- if (pqdiff == 7)
- v->altpq = get_bits(gb, 5);
- else
- v->altpq = v->pq + pqdiff + 1;
+ if (!v->dquantfrm)
+ return 0;
+
+ v->dqprofile = get_bits(gb, 2);
+ switch (v->dqprofile) {
+ case DQPROFILE_SINGLE_EDGE:
+ case DQPROFILE_DOUBLE_EDGES:
+ v->dqsbedge = get_bits(gb, 2);
+ break;
+ case DQPROFILE_ALL_MBS:
+ v->dqbilevel = get_bits1(gb);
+ if (!v->dqbilevel) {
+ v->halfpq = 0;
+ return 0;
}
+ default:
+ break; //Forbidden ?
}
}
+
+ pqdiff = get_bits(gb, 3);
+ if (pqdiff == 7)
+ v->altpq = get_bits(gb, 5);
+ else
+ v->altpq = v->pq + pqdiff + 1;
+
return 0;
}
@@ -293,7 +276,7 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb);
*/
int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitContext *gb)
{
- av_log(avctx, AV_LOG_DEBUG, "Header: %0X\n", show_bits(gb, 32));
+ av_log(avctx, AV_LOG_DEBUG, "Header: %0X\n", show_bits_long(gb, 32));
v->profile = get_bits(gb, 2);
if (v->profile == PROFILE_COMPLEX) {
av_log(avctx, AV_LOG_WARNING, "WMV3 Complex Profile is not fully supported\n");
@@ -304,6 +287,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo
v->zz_4x8 = ff_vc1_adv_progressive_4x8_zz;
return decode_sequence_header_adv(v, gb);
} else {
+ v->chromaformat = 1;
v->zz_8x4 = ff_wmv2_scantableA;
v->zz_4x8 = ff_wmv2_scantableB;
v->res_y411 = get_bits1(gb);
@@ -348,8 +332,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo
return -1;
}
v->extended_mv = get_bits1(gb); //common
- if (!v->profile && v->extended_mv)
- {
+ if (!v->profile && v->extended_mv) {
av_log(avctx, AV_LOG_ERROR,
"Extended MVs unavailable in Simple Profile\n");
return -1;
@@ -358,8 +341,7 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo
v->vstransform = get_bits1(gb); //common
v->res_transtab = get_bits1(gb);
- if (v->res_transtab)
- {
+ if (v->res_transtab) {
av_log(avctx, AV_LOG_ERROR,
"1 for reserved RES_TRANSTAB is forbidden\n");
return -1;
@@ -380,8 +362,13 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo
v->finterpflag = get_bits1(gb); //common
if (v->res_sprite) {
- v->s.avctx->width = v->s.avctx->coded_width = get_bits(gb, 11);
- v->s.avctx->height = v->s.avctx->coded_height = get_bits(gb, 11);
+ int w = get_bits(gb, 11);
+ int h = get_bits(gb, 11);
+ int ret = ff_set_dimensions(v->s.avctx, w, h);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to set dimensions %d %d\n", w, h);
+ return ret;
+ }
skip_bits(gb, 5); //frame rate
v->res_x8 = get_bits1(gb);
if (get_bits1(gb)) { // something to do with DC VLC selection
@@ -433,10 +420,8 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb)
v->bitrtq_postproc = get_bits(gb, 5); //common
v->postprocflag = get_bits1(gb); //common
- v->s.avctx->coded_width = (get_bits(gb, 12) + 1) << 1;
- v->s.avctx->coded_height = (get_bits(gb, 12) + 1) << 1;
- v->s.avctx->width = v->s.avctx->coded_width;
- v->s.avctx->height = v->s.avctx->coded_height;
+ v->max_coded_width = (get_bits(gb, 12) + 1) << 1;
+ v->max_coded_height = (get_bits(gb, 12) + 1) << 1;
v->broadcast = get_bits1(gb);
v->interlace = get_bits1(gb);
v->tfcntrflag = get_bits1(gb);
@@ -497,7 +482,6 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb)
}
}
if (v->broadcast) { // Pulldown may be present
- v->s.avctx->framerate.num *= 2;
v->s.avctx->ticks_per_frame = 2;
}
}
@@ -526,6 +510,8 @@ static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb)
int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContext *gb)
{
int i;
+ int w,h;
+ int ret;
av_log(avctx, AV_LOG_DEBUG, "Entry point: %08X\n", show_bits_long(gb, 32));
v->broken_link = get_bits1(gb);
@@ -533,6 +519,8 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex
v->panscanflag = get_bits1(gb);
v->refdist_flag = get_bits1(gb);
v->s.loop_filter = get_bits1(gb);
+ if (v->s.avctx->skip_loop_filter >= AVDISCARD_ALL)
+ v->s.loop_filter = 0;
v->fastuvmc = get_bits1(gb);
v->extended_mv = get_bits1(gb);
v->dquant = get_bits(gb, 2);
@@ -546,10 +534,18 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex
}
}
- if (get_bits1(gb)) {
- avctx->width = avctx->coded_width = (get_bits(gb, 12) + 1) << 1;
- avctx->height = avctx->coded_height = (get_bits(gb, 12) + 1) << 1;
+ if(get_bits1(gb)){
+ w = (get_bits(gb, 12)+1)<<1;
+ h = (get_bits(gb, 12)+1)<<1;
+ } else {
+ w = v->max_coded_width;
+ h = v->max_coded_height;
+ }
+ if ((ret = ff_set_dimensions(avctx, w, h)) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to set dimensions %d %d\n", w, h);
+ return ret;
}
+
if (v->extended_mv)
v->extended_dmv = get_bits1(gb);
if ((v->range_mapy_flag = get_bits1(gb))) {
@@ -576,13 +572,13 @@ int ff_vc1_decode_entry_point(AVCodecContext *avctx, VC1Context *v, GetBitContex
int scale, shift, i; \
if (!lumscale) { \
scale = -64; \
- shift = (255 - lumshift * 2) << 6; \
+ shift = (255 - lumshift * 2) * 64; \
if (lumshift > 31) \
shift += 128 << 6; \
} else { \
scale = lumscale + 32; \
if (lumshift > 31) \
- shift = (lumshift - 64) << 6; \
+ shift = (lumshift - 64) * 64; \
else \
shift = lumshift << 6; \
} \
@@ -601,32 +597,44 @@ static void rotate_luts(VC1Context *v)
C = A; \
} else { \
DEF; \
- memcpy(&tmp, &L , sizeof(tmp)); \
- memcpy(&L , &N , sizeof(tmp)); \
- memcpy(&N , &tmp, sizeof(tmp)); \
+ 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(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);
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);
- v->curr_use_ic = 0;
- if (v->curr_luty == v->next_luty) {
- // If we just initialized next_lut, clear next_use_ic to match.
- v->next_use_ic = 0;
+ *v->curr_use_ic = 0;
+}
+
+static int read_bfraction(VC1Context *v, GetBitContext* gb) {
+ int bfraction_lut_index = get_vlc2(gb, ff_vc1_bfraction_vlc.table, VC1_BFRACTION_VLC_BITS, 1);
+
+ if (bfraction_lut_index == 21 || bfraction_lut_index < 0) {
+ av_log(v->s.avctx, AV_LOG_ERROR, "bfraction invalid\n");
+ return AVERROR_INVALIDDATA;
}
+ v->bfraction_lut_index = bfraction_lut_index;
+ v->bfraction = ff_vc1_bfraction_lut[v->bfraction_lut_index];
+ return 0;
}
int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
{
int pqindex, lowquant, status;
+ v->field_mode = 0;
+ v->fcm = 0;
if (v->finterpflag)
v->interpfrm = get_bits1(gb);
+ if (!v->s.avctx->codec)
+ return -1;
if (v->s.avctx->codec_id == AV_CODEC_ID_MSS2)
v->respic =
v->rangered =
@@ -636,22 +644,19 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
v->rangeredfrm = 0;
if (v->rangered)
v->rangeredfrm = get_bits1(gb);
- v->s.pict_type = get_bits1(gb);
- if (v->s.avctx->max_b_frames) {
- if (!v->s.pict_type) {
- if (get_bits1(gb))
- v->s.pict_type = AV_PICTURE_TYPE_I;
- else
- v->s.pict_type = AV_PICTURE_TYPE_B;
+ if (get_bits1(gb)) {
+ v->s.pict_type = AV_PICTURE_TYPE_P;
+ } else {
+ if (v->s.avctx->max_b_frames && !get_bits1(gb)) {
+ v->s.pict_type = AV_PICTURE_TYPE_B;
} else
- v->s.pict_type = AV_PICTURE_TYPE_P;
- } else
- v->s.pict_type = v->s.pict_type ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
+ v->s.pict_type = AV_PICTURE_TYPE_I;
+ }
v->bi_type = 0;
if (v->s.pict_type == AV_PICTURE_TYPE_B) {
- v->bfraction_lut_index = get_vlc2(gb, ff_vc1_bfraction_vlc.table, VC1_BFRACTION_VLC_BITS, 1);
- v->bfraction = ff_vc1_bfraction_lut[v->bfraction_lut_index];
+ if (read_bfraction(v, gb) < 0)
+ return AVERROR_INVALIDDATA;
if (v->bfraction == 0) {
v->s.pict_type = AV_PICTURE_TYPE_BI;
}
@@ -676,19 +681,25 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
v->pq = ff_vc1_pquant_table[0][pqindex];
else
v->pq = ff_vc1_pquant_table[1][pqindex];
-
- v->pquantizer = 1;
- if (v->quantizer_mode == QUANT_FRAME_IMPLICIT)
- v->pquantizer = pqindex < 9;
- if (v->quantizer_mode == QUANT_NON_UNIFORM)
- v->pquantizer = 0;
v->pqindex = pqindex;
if (pqindex < 9)
v->halfpq = get_bits1(gb);
else
v->halfpq = 0;
- if (v->quantizer_mode == QUANT_FRAME_EXPLICIT)
+ switch (v->quantizer_mode) {
+ case QUANT_FRAME_IMPLICIT:
+ v->pquantizer = pqindex < 9;
+ break;
+ case QUANT_NON_UNIFORM:
+ v->pquantizer = 0;
+ break;
+ case QUANT_FRAME_EXPLICIT:
v->pquantizer = get_bits1(gb);
+ break;
+ default:
+ v->pquantizer = 1;
+ break;
+ }
v->dquantfrm = 0;
if (v->extended_mv == 1)
v->mvrange = get_unary(gb, 0, 3);
@@ -712,9 +723,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
switch (v->s.pict_type) {
case AV_PICTURE_TYPE_P:
- if (v->pq < 5) v->tt_index = 0;
- else if (v->pq < 13) v->tt_index = 1;
- else v->tt_index = 2;
+ v->tt_index = (v->pq > 4) + (v->pq > 12);
lowquant = (v->pq > 12) ? 0 : 1;
v->mv_mode = ff_vc1_mv_pmode_table[lowquant][get_unary(gb, 1, 4)];
@@ -728,16 +737,15 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
INIT_LUT(v->lumscale, v->lumshift, v->last_luty[1], v->last_lutuv[1], 1);
}
v->qs_last = v->s.quarter_sample;
- if (v->mv_mode == MV_PMODE_1MV_HPEL || v->mv_mode == MV_PMODE_1MV_HPEL_BILIN)
- v->s.quarter_sample = 0;
- else if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
- if (v->mv_mode2 == MV_PMODE_1MV_HPEL || v->mv_mode2 == MV_PMODE_1MV_HPEL_BILIN)
- v->s.quarter_sample = 0;
- else
- v->s.quarter_sample = 1;
- } else
- v->s.quarter_sample = 1;
- v->s.mspel = !(v->mv_mode == MV_PMODE_1MV_HPEL_BILIN || (v->mv_mode == MV_PMODE_INTENSITY_COMP && v->mv_mode2 == MV_PMODE_1MV_HPEL_BILIN));
+ if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
+ v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL &&
+ v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
+ v->s.mspel = (v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
+ } else {
+ v->s.quarter_sample = (v->mv_mode != MV_PMODE_1MV_HPEL &&
+ v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
+ v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
+ }
if ((v->mv_mode == MV_PMODE_INTENSITY_COMP &&
v->mv_mode2 == MV_PMODE_MIXED_MV) ||
@@ -766,21 +774,19 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
vop_dquant_decoding(v);
}
- v->ttfrm = 0; //FIXME Is that so ?
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
- }
+ } else
+ v->ttfrm = 0; //FIXME Is that so ?
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
}
break;
case AV_PICTURE_TYPE_B:
- if (v->pq < 5) v->tt_index = 0;
- else if (v->pq < 13) v->tt_index = 1;
- else v->tt_index = 2;
+ v->tt_index = (v->pq > 4) + (v->pq > 12);
v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN;
v->qs_last = v->s.quarter_sample;
@@ -806,12 +812,12 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb)
vop_dquant_decoding(v);
}
- v->ttfrm = 0;
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
- }
+ } else
+ v->ttfrm = 0;
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
@@ -846,9 +852,12 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->numref = 0;
v->p_frame_skipped = 0;
if (v->second_field) {
- v->s.pict_type = (v->fptype & 1) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
+ if (v->fcm != ILACE_FIELD || v->field_mode!=1)
+ return -1;
if (v->fptype & 4)
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;
if (!v->pic_header_flag)
goto parse_common_info;
@@ -869,12 +878,15 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->field_mode = field_mode;
v->fcm = fcm;
+ av_assert0( v->s.mb_height == v->s.height + 15 >> 4
+ || v->s.mb_height == FFALIGN(v->s.height + 15 >> 4, 2));
if (v->field_mode) {
v->s.mb_height = FFALIGN(v->s.height + 15 >> 4, 2);
v->fptype = get_bits(gb, 3);
- v->s.pict_type = (v->fptype & 2) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
if (v->fptype & 4) // B-picture
v->s.pict_type = (v->fptype & 2) ? AV_PICTURE_TYPE_BI : AV_PICTURE_TYPE_B;
+ else
+ v->s.pict_type = (v->fptype & 2) ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I;
} else {
v->s.mb_height = v->s.height + 15 >> 4;
switch (get_unary(gb, 0, 4)) {
@@ -905,6 +917,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->tff = get_bits1(gb);
v->rff = get_bits1(gb);
}
+ } else {
+ v->tff = 1;
}
if (v->panscanflag) {
avpriv_report_missing_feature(v->s.avctx, "Pan-scan");
@@ -916,6 +930,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->rnd = get_bits1(gb);
if (v->interlace)
v->uvsamp = get_bits1(gb);
+ if(!ff_vc1_bfraction_vlc.table)
+ return 0; //parsing only, vlc tables havnt been allocated
if (v->field_mode) {
if (!v->refdist_flag)
v->refdist = 0;
@@ -925,8 +941,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->refdist += get_unary(gb, 0, 16);
}
if ((v->s.pict_type == AV_PICTURE_TYPE_B) || (v->s.pict_type == AV_PICTURE_TYPE_BI)) {
- v->bfraction_lut_index = get_vlc2(gb, ff_vc1_bfraction_vlc.table, VC1_BFRACTION_VLC_BITS, 1);
- v->bfraction = ff_vc1_bfraction_lut[v->bfraction_lut_index];
+ if (read_bfraction(v, gb) < 0)
+ return AVERROR_INVALIDDATA;
v->frfd = (v->bfraction * v->refdist) >> 8;
v->brfd = v->refdist - v->frfd - 1;
if (v->brfd < 0)
@@ -938,8 +954,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
if (v->finterpflag)
v->interpfrm = get_bits1(gb);
if (v->s.pict_type == AV_PICTURE_TYPE_B) {
- v->bfraction_lut_index = get_vlc2(gb, ff_vc1_bfraction_vlc.table, VC1_BFRACTION_VLC_BITS, 1);
- v->bfraction = ff_vc1_bfraction_lut[v->bfraction_lut_index];
+ if (read_bfraction(v, gb) < 0)
+ return AVERROR_INVALIDDATA;
if (v->bfraction == 0) {
v->s.pict_type = AV_PICTURE_TYPE_BI; /* XXX: should not happen here */
}
@@ -952,24 +968,29 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
pqindex = get_bits(gb, 5);
if (!pqindex)
return -1;
- v->pqindex = pqindex;
if (v->quantizer_mode == QUANT_FRAME_IMPLICIT)
v->pq = ff_vc1_pquant_table[0][pqindex];
else
v->pq = ff_vc1_pquant_table[1][pqindex];
-
- v->pquantizer = 1;
- if (v->quantizer_mode == QUANT_FRAME_IMPLICIT)
- v->pquantizer = pqindex < 9;
- if (v->quantizer_mode == QUANT_NON_UNIFORM)
- v->pquantizer = 0;
v->pqindex = pqindex;
if (pqindex < 9)
v->halfpq = get_bits1(gb);
else
v->halfpq = 0;
- if (v->quantizer_mode == QUANT_FRAME_EXPLICIT)
+ switch (v->quantizer_mode) {
+ case QUANT_FRAME_IMPLICIT:
+ v->pquantizer = pqindex < 9;
+ break;
+ case QUANT_NON_UNIFORM:
+ v->pquantizer = 0;
+ break;
+ case QUANT_FRAME_EXPLICIT:
v->pquantizer = get_bits1(gb);
+ break;
+ default:
+ v->pquantizer = 1;
+ break;
+ }
if (v->postprocflag)
v->postproc = get_bits(gb, 2);
@@ -1059,12 +1080,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->range_x = 1 << (v->k_x - 1);
v->range_y = 1 << (v->k_y - 1);
- if (v->pq < 5)
- v->tt_index = 0;
- else if (v->pq < 13)
- v->tt_index = 1;
- else
- v->tt_index = 2;
+ v->tt_index = (v->pq > 4) + (v->pq > 12);
if (v->fcm != ILACE_FRAME) {
int mvmode;
mvmode = get_unary(gb, 1, 4);
@@ -1100,7 +1116,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
INIT_LUT(v->lumscale2, v->lumshift2, v->curr_luty[v->cur_field_type^1], v->curr_lutuv[v->cur_field_type^1], 0);
INIT_LUT(v->lumscale , v->lumshift , v->last_luty[v->cur_field_type ], v->last_lutuv[v->cur_field_type ], 1);
}
- v->next_use_ic = v->curr_use_ic = 1;
+ v->next_use_ic = *v->curr_use_ic = 1;
} else {
INIT_LUT(v->lumscale , v->lumshift , v->last_luty[0], v->last_lutuv[0], 1);
INIT_LUT(v->lumscale2, v->lumshift2, v->last_luty[1], v->last_lutuv[1], 1);
@@ -1108,18 +1124,15 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->last_use_ic = 1;
}
v->qs_last = v->s.quarter_sample;
- if (v->mv_mode == MV_PMODE_1MV_HPEL || v->mv_mode == MV_PMODE_1MV_HPEL_BILIN)
- v->s.quarter_sample = 0;
- else if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
- if (v->mv_mode2 == MV_PMODE_1MV_HPEL || v->mv_mode2 == MV_PMODE_1MV_HPEL_BILIN)
- v->s.quarter_sample = 0;
- else
- v->s.quarter_sample = 1;
- } else
- v->s.quarter_sample = 1;
- v->s.mspel = !(v->mv_mode == MV_PMODE_1MV_HPEL_BILIN
- || (v->mv_mode == MV_PMODE_INTENSITY_COMP
- && v->mv_mode2 == MV_PMODE_1MV_HPEL_BILIN));
+ if (v->mv_mode == MV_PMODE_INTENSITY_COMP) {
+ v->s.quarter_sample = (v->mv_mode2 != MV_PMODE_1MV_HPEL &&
+ v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
+ v->s.mspel = (v->mv_mode2 != MV_PMODE_1MV_HPEL_BILIN);
+ } else {
+ v->s.quarter_sample = (v->mv_mode != MV_PMODE_1MV_HPEL &&
+ v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
+ v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN);
+ }
}
if (v->fcm == PROGRESSIVE) { // progressive
if ((v->mv_mode == MV_PMODE_INTENSITY_COMP &&
@@ -1170,12 +1183,12 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
vop_dquant_decoding(v);
}
- v->ttfrm = 0; //FIXME Is that so ?
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
- }
+ } else
+ v->ttfrm = 0; //FIXME Is that so ?
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
@@ -1183,8 +1196,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
break;
case AV_PICTURE_TYPE_B:
if (v->fcm == ILACE_FRAME) {
- v->bfraction_lut_index = get_vlc2(gb, ff_vc1_bfraction_vlc.table, VC1_BFRACTION_VLC_BITS, 1);
- v->bfraction = ff_vc1_bfraction_lut[v->bfraction_lut_index];
+ if (read_bfraction(v, gb) < 0)
+ return AVERROR_INVALIDDATA;
if (v->bfraction == 0) {
return -1;
}
@@ -1198,15 +1211,11 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
v->range_x = 1 << (v->k_x - 1);
v->range_y = 1 << (v->k_y - 1);
- if (v->pq < 5)
- v->tt_index = 0;
- else if (v->pq < 13)
- v->tt_index = 1;
- else
- v->tt_index = 2;
+ v->tt_index = (v->pq > 4) + (v->pq > 12);
if (v->field_mode) {
int mvmode;
+ av_log(v->s.avctx, AV_LOG_DEBUG, "B Fields\n");
if (v->extended_dmv)
v->dmvrange = get_unary(gb, 0, 3);
mvmode = get_unary(gb, 1, 3);
@@ -1290,12 +1299,12 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
vop_dquant_decoding(v);
}
- v->ttfrm = 0;
if (v->vstransform) {
v->ttmbf = get_bits1(gb);
if (v->ttmbf) {
v->ttfrm = ff_vc1_ttfrm_to_tt[get_bits(gb, 2)];
- }
+ } else
+ v->ttfrm = 0;
} else {
v->ttmbf = 1;
v->ttfrm = TT_8X8;
@@ -1321,11 +1330,10 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb)
vop_dquant_decoding(v);
}
- v->bi_type = 0;
- if (v->s.pict_type == AV_PICTURE_TYPE_BI) {
+ v->bi_type = (v->s.pict_type == AV_PICTURE_TYPE_BI);
+ if (v->bi_type)
v->s.pict_type = AV_PICTURE_TYPE_B;
- v->bi_type = 1;
- }
+
return 0;
}
diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h
index 0c4958ca77..eefb613ee8 100644
--- a/libavcodec/vc1.h
+++ b/libavcodec/vc1.h
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -151,6 +151,21 @@ enum FrameCodingMode {
ILACE_FIELD ///< in the bitstream is reported as 11b
};
+/**
+ * Imode types
+ * @{
+ */
+enum Imode {
+ IMODE_RAW,
+ IMODE_NORM2,
+ IMODE_DIFF2,
+ IMODE_NORM6,
+ IMODE_DIFF6,
+ IMODE_ROWSKIP,
+ IMODE_COLSKIP
+};
+/** @} */ //imode defines
+
/** The VC1 Context
* @todo Change size wherever another size is more efficient
* Many members are only used for Advanced Profile
@@ -203,6 +218,7 @@ typedef struct VC1Context{
int profile; ///< 2bits, Profile
int frmrtq_postproc; ///< 3bits,
int bitrtq_postproc; ///< 5bits, quantized framerate-based postprocessing strength
+ int max_coded_width, max_coded_height;
int fastuvmc; ///< Rounding of qpel vector to hpel ? (not in Simple)
int extended_mv; ///< Ext MV in P/B (not in Simple)
int dquant; ///< How qscale varies with MBs, 2bits (not in Simple)
@@ -278,7 +294,7 @@ typedef struct VC1Context{
uint8_t aux_luty[2][256], aux_lutuv[2][256]; ///< lookup tables used for intensity compensation
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_use_ic, *curr_use_ic, next_use_ic, aux_use_ic;
int rnd; ///< rounding control
/** Frame decoding info for S/M profiles only */
@@ -329,7 +345,7 @@ typedef struct VC1Context{
uint8_t fourmvbp;
uint8_t* fieldtx_plane;
int fieldtx_is_raw;
- int8_t zzi_8x8[64];
+ uint8_t zzi_8x8[64];
uint8_t *blk_mv_type_base, *blk_mv_type; ///< 0: frame MV, 1: field MV (interlaced frame)
uint8_t *mv_f_base, *mv_f[2]; ///< 0: MV obtained from same field, 1: opposite field
uint8_t *mv_f_next_base, *mv_f_next[2];
diff --git a/libavcodec/vc1_block.c b/libavcodec/vc1_block.c
index 91c926355d..3541ba787e 100644
--- a/libavcodec/vc1_block.c
+++ b/libavcodec/vc1_block.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,8 +40,10 @@
#define DC_VLC_BITS 9
// offset tables for interlaced picture MVDATA decoding
-static const int offset_table1[9] = { 0, 1, 2, 4, 8, 16, 32, 64, 128 };
-static const int offset_table2[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
+static const uint8_t offset_table[2][9] = {
+ { 0, 1, 2, 4, 8, 16, 32, 64, 128 },
+ { 0, 1, 3, 7, 15, 31, 63, 127, 255 },
+};
/***********************************************************************/
/**
@@ -50,22 +52,8 @@ static const int offset_table2[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
* @{
*/
-/**
- * Imode types
- * @{
- */
-enum Imode {
- IMODE_RAW,
- IMODE_NORM2,
- IMODE_DIFF2,
- IMODE_NORM6,
- IMODE_DIFF6,
- IMODE_ROWSKIP,
- IMODE_COLSKIP
-};
-/** @} */ //imode defines
-static void init_block_index(VC1Context *v)
+static inline void init_block_index(VC1Context *v)
{
MpegEncContext *s = &v->s;
ff_init_block_index(s);
@@ -111,12 +99,14 @@ static void vc1_put_signed_blocks_clamped(VC1Context *v)
s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][3],
s->dest[0] - v_dist * s->linesize - 8,
stride_y);
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][4],
s->dest[1] - 8 * s->uvlinesize - 8,
s->uvlinesize);
s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][5],
s->dest[2] - 8 * s->uvlinesize - 8,
s->uvlinesize);
+ }
}
if (s->mb_x == s->mb_width - 1) {
top_mb_pos = (s->mb_y - 1) * s->mb_stride + s->mb_x;
@@ -136,12 +126,14 @@ static void vc1_put_signed_blocks_clamped(VC1Context *v)
s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][3],
s->dest[0] - v_dist * s->linesize + 8,
stride_y);
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][4],
s->dest[1] - 8 * s->uvlinesize,
s->uvlinesize);
s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][5],
s->dest[2] - 8 * s->uvlinesize,
s->uvlinesize);
+ }
}
}
@@ -230,33 +222,32 @@ static void vc1_put_signed_blocks_clamped(VC1Context *v)
s->mb_intra = 1; \
} else { \
index1 = index % 6; \
- if (!s->quarter_sample && index1 == 5) val = 1; \
- else val = 0; \
- if (size_table[index1] - val > 0) \
- val = get_bits(gb, size_table[index1] - val); \
- else val = 0; \
- sign = 0 - (val&1); \
- _dmv_x = (sign ^ ((val>>1) + offset_table[index1])) - sign; \
+ _dmv_x = offset_table[1][index1]; \
+ val = size_table[index1] - (!s->quarter_sample && index1 == 5); \
+ if (val > 0) { \
+ val = get_bits(gb, val); \
+ sign = 0 - (val & 1); \
+ _dmv_x = (sign ^ ((val >> 1) + _dmv_x)) - sign; \
+ } \
\
index1 = index / 6; \
- if (!s->quarter_sample && index1 == 5) val = 1; \
- else val = 0; \
- if (size_table[index1] - val > 0) \
- val = get_bits(gb, size_table[index1] - val); \
- else val = 0; \
- sign = 0 - (val & 1); \
- _dmv_y = (sign ^ ((val >> 1) + offset_table[index1])) - sign; \
+ _dmv_y = offset_table[1][index1]; \
+ val = size_table[index1] - (!s->quarter_sample && index1 == 5); \
+ if (val > 0) { \
+ val = get_bits(gb, val); \
+ sign = 0 - (val & 1); \
+ _dmv_y = (sign ^ ((val >> 1) + _dmv_y)) - sign; \
+ } \
}
static av_always_inline void get_mvdata_interlaced(VC1Context *v, int *dmv_x,
int *dmv_y, int *pred_flag)
{
int index, index1;
- int extend_x = 0, extend_y = 0;
+ int extend_x, extend_y;
GetBitContext *gb = &v->s.gb;
int bits, esc;
int val, sign;
- const int* offs_tab;
if (v->numref) {
bits = VC1_2REF_MVDATA_VLC_BITS;
@@ -265,51 +256,32 @@ static av_always_inline void get_mvdata_interlaced(VC1Context *v, int *dmv_x,
bits = VC1_1REF_MVDATA_VLC_BITS;
esc = 71;
}
- switch (v->dmvrange) {
- case 1:
- extend_x = 1;
- break;
- case 2:
- extend_y = 1;
- break;
- case 3:
- extend_x = extend_y = 1;
- break;
- }
+ extend_x = v->dmvrange & 1;
+ extend_y = (v->dmvrange >> 1) & 1;
index = get_vlc2(gb, v->imv_vlc->table, bits, 3);
if (index == esc) {
*dmv_x = get_bits(gb, v->k_x);
*dmv_y = get_bits(gb, v->k_y);
if (v->numref) {
- if (pred_flag) {
+ if (pred_flag)
*pred_flag = *dmv_y & 1;
- *dmv_y = (*dmv_y + *pred_flag) >> 1;
- } else {
- *dmv_y = (*dmv_y + (*dmv_y & 1)) >> 1;
- }
+ *dmv_y = (*dmv_y + (*dmv_y & 1)) >> 1;
}
}
else {
- if (extend_x)
- offs_tab = offset_table2;
- else
- offs_tab = offset_table1;
+ av_assert0(index < esc);
index1 = (index + 1) % 9;
if (index1 != 0) {
val = get_bits(gb, index1 + extend_x);
- sign = 0 -(val & 1);
- *dmv_x = (sign ^ ((val >> 1) + offs_tab[index1])) - sign;
+ sign = 0 - (val & 1);
+ *dmv_x = (sign ^ ((val >> 1) + offset_table[extend_x][index1])) - sign;
} else
*dmv_x = 0;
- if (extend_y)
- offs_tab = offset_table2;
- else
- offs_tab = offset_table1;
index1 = (index + 1) / 9;
if (index1 > v->numref) {
- val = get_bits(gb, (index1 + (extend_y << v->numref)) >> v->numref);
+ val = get_bits(gb, (index1 >> v->numref) + extend_y);
sign = 0 - (val & 1);
- *dmv_y = (sign ^ ((val >> 1) + offs_tab[index1 >> v->numref])) - sign;
+ *dmv_y = (sign ^ ((val >> 1) + offset_table[extend_y][index1 >> v->numref])) - sign;
} else
*dmv_y = 0;
if (v->numref && pred_flag)
@@ -420,6 +392,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n,
int q1, q2 = 0;
int dqscale_index;
+ /* scale predictors if needed */
+ q1 = s->current_picture.qscale_table[mb_pos];
+ dqscale_index = s->y_dc_scale_table[q1] - 1;
+ if (dqscale_index < 0)
+ return 0;
+
wrap = s->block_wrap[n];
dc_val = s->dc_val[0] + s->block_index[n];
@@ -429,11 +407,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n,
c = dc_val[ - 1];
b = dc_val[ - 1 - wrap];
a = dc_val[ - wrap];
- /* scale predictors if needed */
- q1 = s->current_picture.qscale_table[mb_pos];
- dqscale_index = s->y_dc_scale_table[q1] - 1;
- if (dqscale_index < 0)
- return 0;
+
if (c_avail && (n != 1 && n != 3)) {
q2 = s->current_picture.qscale_table[mb_pos - 1];
if (q2 && q2 != q1)
@@ -455,20 +429,12 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n,
b = (b * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18;
}
- if (a_avail && c_avail) {
- if (abs(a - b) <= abs(b - c)) {
- pred = c;
- *dir_ptr = 1; // left
- } else {
- pred = a;
- *dir_ptr = 0; // top
- }
+ if (c_avail && (!a_avail || abs(a - b) <= abs(b - c))) {
+ pred = c;
+ *dir_ptr = 1; // left
} else if (a_avail) {
pred = a;
*dir_ptr = 0; // top
- } else if (c_avail) {
- pred = c;
- *dir_ptr = 1; // left
} else {
pred = 0;
*dir_ptr = 1; // left
@@ -527,17 +493,16 @@ static void vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip,
int *value, int codingset)
{
GetBitContext *gb = &v->s.gb;
- int index, escape, run = 0, level = 0, lst = 0;
+ int index, run, level, lst, sign;
index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset].table, AC_VLC_BITS, 3);
if (index != ff_vc1_ac_sizes[codingset] - 1) {
run = vc1_index_decode_table[codingset][index][0];
level = vc1_index_decode_table[codingset][index][1];
lst = index >= vc1_last_decode_table[codingset] || get_bits_left(gb) < 0;
- if (get_bits1(gb))
- level = -level;
+ sign = get_bits1(gb);
} else {
- escape = decode210(gb);
+ int escape = decode210(gb);
if (escape != 2) {
index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset].table, AC_VLC_BITS, 3);
run = vc1_index_decode_table[codingset][index][0];
@@ -554,10 +519,8 @@ static void vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip,
else
run += vc1_delta_run_table[codingset][level] + 1;
}
- if (get_bits1(gb))
- level = -level;
+ sign = get_bits1(gb);
} else {
- int sign;
lst = get_bits1(gb);
if (v->s.esc3_level_length == 0) {
if (v->pq < 8 || v->dquantfrm) { // table 59
@@ -572,14 +535,12 @@ static void vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip,
run = get_bits(gb, v->s.esc3_run_length);
sign = get_bits1(gb);
level = get_bits(gb, v->s.esc3_level_length);
- if (sign)
- level = -level;
}
}
*last = lst;
*skip = run;
- *value = level;
+ *value = (level ^ -sign) + sign;
}
/** Decode intra block in intra frames - should be faster than decode_intra_block
@@ -598,7 +559,7 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n,
int i;
int16_t *dc_val;
int16_t *ac_val, *ac_val2;
- int dcdiff;
+ int dcdiff, scale;
/* Get DC differential */
if (n < 4) {
@@ -611,16 +572,12 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n,
return -1;
}
if (dcdiff) {
+ const int m = (v->pq == 1 || v->pq == 2) ? 3 - v->pq : 0;
if (dcdiff == 119 /* ESC index value */) {
- /* TODO: Optimize */
- if (v->pq == 1) dcdiff = get_bits(gb, 10);
- else if (v->pq == 2) dcdiff = get_bits(gb, 9);
- else dcdiff = get_bits(gb, 8);
+ dcdiff = get_bits(gb, 8 + m);
} else {
- if (v->pq == 1)
- dcdiff = (dcdiff << 2) + get_bits(gb, 2) - 3;
- else if (v->pq == 2)
- dcdiff = (dcdiff << 1) + get_bits1(gb) - 1;
+ if (m)
+ dcdiff = (dcdiff << m) + get_bits(gb, m) - ((1 << m) - 1);
}
if (get_bits1(gb))
dcdiff = -dcdiff;
@@ -631,27 +588,29 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n,
*dc_val = dcdiff;
/* Store the quantized DC coeff, used for prediction */
- if (n < 4) {
- block[0] = dcdiff * s->y_dc_scale;
- } else {
- block[0] = dcdiff * s->c_dc_scale;
- }
- /* Skip ? */
- if (!coded) {
- goto not_coded;
- }
+ if (n < 4)
+ scale = s->y_dc_scale;
+ else
+ scale = s->c_dc_scale;
+ block[0] = dcdiff * scale;
- // AC Decoding
- i = 1;
+ ac_val = s->ac_val[0][0] + s->block_index[n] * 16;
+ ac_val2 = ac_val;
+ if (dc_pred_dir) // left
+ ac_val -= 16;
+ else // top
+ ac_val -= 16 * s->block_wrap[n];
- {
+ scale = v->pq * 2 + v->halfpq;
+
+ //AC Decoding
+ i = !!coded;
+
+ if (coded) {
int last = 0, skip, value;
const uint8_t *zz_table;
- int scale;
int k;
- scale = v->pq * 2 + v->halfpq;
-
if (v->s.ac_pred) {
if (!dc_pred_dir)
zz_table = v->zz_8x8[2];
@@ -660,13 +619,6 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n,
} else
zz_table = v->zz_8x8[1];
- ac_val = s->ac_val[0][0] + s->block_index[n] * 16;
- ac_val2 = ac_val;
- if (dc_pred_dir) // left
- ac_val -= 16;
- else // top
- ac_val -= 16 * s->block_wrap[n];
-
while (!last) {
vc1_decode_ac_coeff(v, &last, &skip, &value, codingset);
i += skip;
@@ -677,13 +629,15 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n,
/* apply AC prediction if needed */
if (s->ac_pred) {
+ int sh;
if (dc_pred_dir) { // left
- for (k = 1; k < 8; k++)
- block[k << v->left_blk_sh] += ac_val[k];
+ sh = v->left_blk_sh;
} else { // top
- for (k = 1; k < 8; k++)
- block[k << v->top_blk_sh] += ac_val[k + 8];
+ sh = v->top_blk_sh;
+ ac_val += 8;
}
+ for (k = 1; k < 8; k++)
+ block[k << sh] += ac_val[k];
}
/* save AC coeffs for further prediction */
for (k = 1; k < 8; k++) {
@@ -699,46 +653,30 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n,
block[k] += (block[k] < 0) ? -v->pq : v->pq;
}
- if (s->ac_pred) i = 63;
- }
-
-not_coded:
- if (!coded) {
- int k, scale;
- ac_val = s->ac_val[0][0] + s->block_index[n] * 16;
- ac_val2 = ac_val;
+ } else {
+ int k;
- i = 0;
- scale = v->pq * 2 + v->halfpq;
memset(ac_val2, 0, 16 * 2);
- if (dc_pred_dir) { // left
- ac_val -= 16;
- if (s->ac_pred)
- memcpy(ac_val2, ac_val, 8 * 2);
- } else { // top
- ac_val -= 16 * s->block_wrap[n];
- if (s->ac_pred)
- memcpy(ac_val2 + 8, ac_val + 8, 8 * 2);
- }
/* apply AC prediction if needed */
if (s->ac_pred) {
+ int sh;
if (dc_pred_dir) { //left
- for (k = 1; k < 8; k++) {
- block[k << v->left_blk_sh] = ac_val[k] * scale;
- if (!v->pquantizer && block[k << v->left_blk_sh])
- block[k << v->left_blk_sh] += (block[k << v->left_blk_sh] < 0) ? -v->pq : v->pq;
- }
+ sh = v->left_blk_sh;
} else { // top
- for (k = 1; k < 8; k++) {
- block[k << v->top_blk_sh] = ac_val[k + 8] * scale;
- if (!v->pquantizer && block[k << v->top_blk_sh])
- block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -v->pq : v->pq;
- }
+ sh = v->top_blk_sh;
+ ac_val += 8;
+ ac_val2 += 8;
+ }
+ memcpy(ac_val2, ac_val, 8 * 2);
+ for (k = 1; k < 8; k++) {
+ block[k << sh] = ac_val[k] * scale;
+ if (!v->pquantizer && block[k << sh])
+ block[k << sh] += (block[k << sh] < 0) ? -v->pq : v->pq;
}
- i = 63;
}
}
+ if (s->ac_pred) i = 63;
s->block_last_index[n] = i;
return 0;
@@ -759,7 +697,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n,
MpegEncContext *s = &v->s;
int dc_pred_dir = 0; /* Direction of the DC prediction used */
int i;
- int16_t *dc_val;
+ int16_t *dc_val = NULL;
int16_t *ac_val, *ac_val2;
int dcdiff;
int a_avail = v->a_avail, c_avail = v->c_avail;
@@ -779,16 +717,12 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n,
return -1;
}
if (dcdiff) {
+ const int m = (mquant == 1 || mquant == 2) ? 3 - mquant : 0;
if (dcdiff == 119 /* ESC index value */) {
- /* TODO: Optimize */
- if (mquant == 1) dcdiff = get_bits(gb, 10);
- else if (mquant == 2) dcdiff = get_bits(gb, 9);
- else dcdiff = get_bits(gb, 8);
+ dcdiff = get_bits(gb, 8 + m);
} else {
- if (mquant == 1)
- dcdiff = (dcdiff << 2) + get_bits(gb, 2) - 3;
- else if (mquant == 2)
- dcdiff = (dcdiff << 1) + get_bits1(gb) - 1;
+ if (m)
+ dcdiff = (dcdiff << m) + get_bits(gb, m) - ((1 << m) - 1);
}
if (get_bits1(gb))
dcdiff = -dcdiff;
@@ -799,39 +733,42 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n,
*dc_val = dcdiff;
/* Store the quantized DC coeff, used for prediction */
- if (n < 4) {
- block[0] = dcdiff * s->y_dc_scale;
- } else {
- block[0] = dcdiff * s->c_dc_scale;
- }
-
- //AC Decoding
- i = 1;
+ if (n < 4)
+ scale = s->y_dc_scale;
+ else
+ scale = s->c_dc_scale;
+ block[0] = dcdiff * scale;
/* check if AC is needed at all */
if (!a_avail && !c_avail)
use_pred = 0;
- ac_val = s->ac_val[0][0] + s->block_index[n] * 16;
- ac_val2 = ac_val;
scale = mquant * 2 + ((mquant == v->pq) ? v->halfpq : 0);
+ ac_val = s->ac_val[0][0] + s->block_index[n] * 16;
+ ac_val2 = ac_val;
if (dc_pred_dir) // left
ac_val -= 16;
else // top
ac_val -= 16 * s->block_wrap[n];
q1 = s->current_picture.qscale_table[mb_pos];
- if ( dc_pred_dir && c_avail && mb_pos)
- q2 = s->current_picture.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];
- if ( dc_pred_dir && n == 1)
- q2 = q1;
- if (!dc_pred_dir && n == 2)
- q2 = q1;
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];
+ } 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];
+ }
+
+ //AC Decoding
+ i = 1;
if (coded) {
int last = 0, skip, value;
@@ -864,28 +801,24 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n,
/* apply AC prediction if needed */
if (use_pred) {
+ int sh;
+ if (dc_pred_dir) { // left
+ sh = v->left_blk_sh;
+ } else { // top
+ sh = v->top_blk_sh;
+ ac_val += 8;
+ }
/* scale predictors if needed*/
if (q2 && q1 != q2) {
q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1;
- q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1;
-
if (q1 < 1)
return AVERROR_INVALIDDATA;
- if (dc_pred_dir) { // left
- for (k = 1; k < 8; k++)
- block[k << v->left_blk_sh] += (ac_val[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
- } else { // top
- for (k = 1; k < 8; k++)
- block[k << v->top_blk_sh] += (ac_val[k + 8] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
- }
+ q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1;
+ for (k = 1; k < 8; k++)
+ block[k << sh] += (ac_val[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
} else {
- if (dc_pred_dir) { //left
- for (k = 1; k < 8; k++)
- block[k << v->left_blk_sh] += ac_val[k];
- } else { //top
- for (k = 1; k < 8; k++)
- block[k << v->top_blk_sh] += ac_val[k + 8];
- }
+ for (k = 1; k < 8; k++)
+ block[k << sh] += ac_val[k];
}
}
/* save AC coeffs for further prediction */
@@ -902,55 +835,38 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n,
block[k] += (block[k] < 0) ? -mquant : mquant;
}
- if (use_pred) i = 63;
} else { // no AC coeffs
int k;
memset(ac_val2, 0, 16 * 2);
- if (dc_pred_dir) { // left
- if (use_pred) {
- memcpy(ac_val2, ac_val, 8 * 2);
- if (q2 && q1 != q2) {
- q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1;
- q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1;
- if (q1 < 1)
- return AVERROR_INVALIDDATA;
- for (k = 1; k < 8; k++)
- ac_val2[k] = (ac_val2[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
- }
- }
- } else { // top
- if (use_pred) {
- memcpy(ac_val2 + 8, ac_val + 8, 8 * 2);
- if (q2 && q1 != q2) {
- q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1;
- q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1;
- if (q1 < 1)
- return AVERROR_INVALIDDATA;
- for (k = 1; k < 8; k++)
- ac_val2[k + 8] = (ac_val2[k + 8] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
- }
- }
- }
/* apply AC prediction if needed */
if (use_pred) {
+ int sh;
if (dc_pred_dir) { // left
- for (k = 1; k < 8; k++) {
- block[k << v->left_blk_sh] = ac_val2[k] * scale;
- if (!v->pquantizer && block[k << v->left_blk_sh])
- block[k << v->left_blk_sh] += (block[k << v->left_blk_sh] < 0) ? -mquant : mquant;
- }
+ sh = v->left_blk_sh;
} else { // top
- for (k = 1; k < 8; k++) {
- block[k << v->top_blk_sh] = ac_val2[k + 8] * scale;
- if (!v->pquantizer && block[k << v->top_blk_sh])
- block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -mquant : mquant;
- }
+ sh = v->top_blk_sh;
+ ac_val += 8;
+ ac_val2 += 8;
+ }
+ memcpy(ac_val2, ac_val, 8 * 2);
+ if (q2 && q1 != q2) {
+ q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1;
+ q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1;
+ if (q1 < 1)
+ return AVERROR_INVALIDDATA;
+ for (k = 1; k < 8; k++)
+ ac_val2[k] = (ac_val2[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18;
+ }
+ for (k = 1; k < 8; k++) {
+ block[k << sh] = ac_val2[k] * scale;
+ if (!v->pquantizer && block[k << sh])
+ block[k << sh] += (block[k << sh] < 0) ? -mquant : mquant;
}
- i = 63;
}
}
+ if (use_pred) i = 63;
s->block_last_index[n] = i;
return 0;
@@ -971,7 +887,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n,
MpegEncContext *s = &v->s;
int dc_pred_dir = 0; /* Direction of the DC prediction used */
int i;
- int16_t *dc_val;
+ int16_t *dc_val = NULL;
int16_t *ac_val, *ac_val2;
int dcdiff;
int mb_pos = s->mb_x + s->mb_y * s->mb_stride;
@@ -983,7 +899,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n,
s->bdsp.clear_block(block);
/* XXX: Guard against dumb values of mquant */
- mquant = (mquant < 1) ? 0 : ((mquant > 31) ? 31 : mquant);
+ mquant = av_clip_uintp2(mquant, 5);
/* Set DC scale - y and c use the same */
s->y_dc_scale = s->y_dc_scale_table[mquant];
@@ -1000,16 +916,12 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n,
return -1;
}
if (dcdiff) {
+ const int m = (mquant == 1 || mquant == 2) ? 3 - mquant : 0;
if (dcdiff == 119 /* ESC index value */) {
- /* TODO: Optimize */
- if (mquant == 1) dcdiff = get_bits(gb, 10);
- else if (mquant == 2) dcdiff = get_bits(gb, 9);
- else dcdiff = get_bits(gb, 8);
+ dcdiff = get_bits(gb, 8 + m);
} else {
- if (mquant == 1)
- dcdiff = (dcdiff << 2) + get_bits(gb, 2) - 3;
- else if (mquant == 2)
- dcdiff = (dcdiff << 1) + get_bits1(gb) - 1;
+ if (m)
+ dcdiff = (dcdiff << m) + get_bits(gb, m) - ((1 << m) - 1);
}
if (get_bits1(gb))
dcdiff = -dcdiff;
@@ -1333,8 +1245,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n,
/** @} */ // Macroblock group
-static const int size_table [6] = { 0, 2, 3, 4, 5, 8 };
-static const int offset_table[6] = { 0, 1, 3, 7, 15, 31 };
+static const uint8_t size_table[6] = { 0, 2, 3, 4, 5, 8 };
/** Decode one P-frame MB
*/
@@ -1416,7 +1327,7 @@ static int vc1_decode_p_mb(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if ((i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
if (v->rangeredfrm)
@@ -1437,7 +1348,7 @@ static int vc1_decode_p_mb(VC1Context *v)
} else if (val) {
pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, first_block,
s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize,
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), &block_tt);
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), &block_tt);
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
@@ -1527,7 +1438,7 @@ static int vc1_decode_p_mb(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, is_coded[i], mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if ((i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
if (v->rangeredfrm)
@@ -1549,7 +1460,7 @@ static int vc1_decode_p_mb(VC1Context *v)
pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize,
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY),
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY),
&block_tt);
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
@@ -1602,7 +1513,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
int idx_mbmode = 0, mvbp;
int stride_y, fieldtx;
- mquant = v->pq; /* Loosy initialization */
+ mquant = v->pq; /* Lossy initialization */
if (v->skip_is_raw)
skipped = get_bits1(gb);
@@ -1675,7 +1586,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if ((i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
if (i < 4) {
@@ -1711,19 +1622,14 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
dst_idx = 0;
if (fourmv) {
mvbp = v->fourmvbp;
- for (i = 0; i < 6; i++) {
- if (i < 4) {
- dmv_x = dmv_y = 0;
- val = ((mvbp >> (3 - i)) & 1);
- if (val) {
- get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
- }
- ff_vc1_pred_mv_intfr(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], 0);
- ff_vc1_mc_4mv_luma(v, i, 0, 0);
- } else if (i == 4) {
- ff_vc1_mc_4mv_chroma4(v, 0, 0, 0);
- }
+ for (i = 0; i < 4; i++) {
+ dmv_x = dmv_y = 0;
+ if (mvbp & (8 >> i))
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, 0);
+ ff_vc1_pred_mv_intfr(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], 0);
+ ff_vc1_mc_4mv_luma(v, i, 0, 0);
}
+ ff_vc1_mc_4mv_chroma4(v, 0, 0, 0);
} else if (twomv) {
mvbp = v->twomvbp;
dmv_x = dmv_y = 0;
@@ -1767,7 +1673,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v)
pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : (s->linesize << fieldtx),
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), &block_tt);
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), &block_tt);
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
@@ -1810,11 +1716,11 @@ static int vc1_decode_p_mb_intfi(VC1Context *v)
int val; /* temp values */
int first_block = 1;
int dst_idx, off;
- int pred_flag;
+ int pred_flag = 0;
int block_cbp = 0, pat, block_tt = 0;
int idx_mbmode = 0;
- mquant = v->pq; /* Loosy initialization */
+ mquant = v->pq; /* Lossy initialization */
idx_mbmode = get_vlc2(gb, v->mbmode_vlc->table, VC1_IF_MBMODE_VLC_BITS, 2);
if (idx_mbmode <= 1) { // intra MB
@@ -1846,7 +1752,7 @@ static int vc1_decode_p_mb_intfi(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if ((i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize);
@@ -1859,7 +1765,8 @@ static int vc1_decode_p_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;
- for (i = 0; i < 6; i++) v->mb_type[0][s->block_index[i]] = 0;
+ for (i = 0; i < 6; i++)
+ v->mb_type[0][s->block_index[i]] = 0;
if (idx_mbmode <= 5) { // 1-MV
dmv_x = dmv_y = pred_flag = 0;
if (idx_mbmode & 1) {
@@ -1870,18 +1777,14 @@ static int vc1_decode_p_mb_intfi(VC1Context *v)
mb_has_coeffs = !(idx_mbmode & 2);
} else { // 4-MV
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc->table, VC1_4MV_BLOCK_PATTERN_VLC_BITS, 1);
- for (i = 0; i < 6; i++) {
- if (i < 4) {
- dmv_x = dmv_y = pred_flag = 0;
- val = ((v->fourmvbp >> (3 - i)) & 1);
- if (val) {
- get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag);
- }
- ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0);
- ff_vc1_mc_4mv_luma(v, i, 0, 0);
- } else if (i == 4)
- ff_vc1_mc_4mv_chroma(v, 0);
+ for (i = 0; i < 4; i++) {
+ dmv_x = dmv_y = pred_flag = 0;
+ if (v->fourmvbp & (8 >> i))
+ get_mvdata_interlaced(v, &dmv_x, &dmv_y, &pred_flag);
+ ff_vc1_pred_mv(v, i, dmv_x, dmv_y, 0, v->range_x, v->range_y, v->mb_type[0], pred_flag, 0);
+ ff_vc1_mc_4mv_luma(v, i, 0, 0);
}
+ ff_vc1_mc_4mv_chroma(v, 0);
mb_has_coeffs = idx_mbmode & 1;
}
if (mb_has_coeffs)
@@ -1903,10 +1806,11 @@ static int vc1_decode_p_mb_intfi(VC1Context *v)
pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize,
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY),
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY),
&block_tt);
block_cbp |= pat << (i << 2);
- if (!v->ttmbf && ttmb < 8) ttmb = -1;
+ if (!v->ttmbf && ttmb < 8)
+ ttmb = -1;
first_block = 0;
}
}
@@ -2049,7 +1953,7 @@ static void vc1_decode_b_mb(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if ((i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
if (v->rangeredfrm)
@@ -2063,7 +1967,7 @@ static void vc1_decode_b_mb(VC1Context *v)
vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize,
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), NULL);
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), NULL);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
@@ -2089,9 +1993,9 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
int fwd;
int dmv_x[2], dmv_y[2], pred_flag[2];
int bmvtype = BMV_TYPE_BACKWARD;
- int idx_mbmode, interpmvp;
+ int idx_mbmode;
- mquant = v->pq; /* Loosy initialization */
+ mquant = v->pq; /* Lossy initialization */
s->mb_intra = 0;
idx_mbmode = get_vlc2(gb, v->mbmode_vlc->table, VC1_IF_MBMODE_VLC_BITS, 2);
@@ -2124,7 +2028,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if ((i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
if (v->rangeredfrm)
@@ -2140,12 +2044,14 @@ static void 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;
- for (i = 0; i < 6; i++) v->mb_type[0][s->block_index[i]] = 0;
+ for (i = 0; i < 6; i++)
+ v->mb_type[0][s->block_index[i]] = 0;
if (v->fmb_is_raw)
fwd = v->forward_mb_plane[mb_pos] = get_bits1(gb);
else
fwd = v->forward_mb_plane[mb_pos];
if (idx_mbmode <= 5) { // 1-MV
+ int interpmvp = 0;
dmv_x[0] = dmv_x[1] = dmv_y[0] = dmv_y[1] = 0;
pred_flag[0] = pred_flag[1] = 0;
if (fwd)
@@ -2168,12 +2074,16 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
if (bmvtype != BMV_TYPE_DIRECT && idx_mbmode & 1) {
get_mvdata_interlaced(v, &dmv_x[bmvtype == BMV_TYPE_BACKWARD], &dmv_y[bmvtype == BMV_TYPE_BACKWARD], &pred_flag[bmvtype == BMV_TYPE_BACKWARD]);
}
- if (bmvtype == BMV_TYPE_INTERPOLATED && interpmvp) {
+ if (interpmvp) {
get_mvdata_interlaced(v, &dmv_x[1], &dmv_y[1], &pred_flag[1]);
}
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) {
+ av_log(s->avctx, AV_LOG_ERROR, "Mixed field/frame direct mode not supported\n");
+ return;
+ }
}
ff_vc1_pred_b_mv_intfi(v, 0, dmv_x, dmv_y, 1, pred_flag);
vc1_b_mc(v, dmv_x, dmv_y, (bmvtype == BMV_TYPE_DIRECT), bmvtype);
@@ -2183,21 +2093,18 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
bmvtype = BMV_TYPE_FORWARD;
v->bmvtype = bmvtype;
v->fourmvbp = get_vlc2(gb, v->fourmvbp_vlc->table, VC1_4MV_BLOCK_PATTERN_VLC_BITS, 1);
- for (i = 0; i < 6; i++) {
- if (i < 4) {
- dmv_x[0] = dmv_y[0] = pred_flag[0] = 0;
- dmv_x[1] = dmv_y[1] = pred_flag[1] = 0;
- val = ((v->fourmvbp >> (3 - i)) & 1);
- if (val) {
- get_mvdata_interlaced(v, &dmv_x[bmvtype == BMV_TYPE_BACKWARD],
- &dmv_y[bmvtype == BMV_TYPE_BACKWARD],
- &pred_flag[bmvtype == BMV_TYPE_BACKWARD]);
- }
- ff_vc1_pred_b_mv_intfi(v, i, dmv_x, dmv_y, 0, pred_flag);
- ff_vc1_mc_4mv_luma(v, i, bmvtype == BMV_TYPE_BACKWARD, 0);
- } else if (i == 4)
- ff_vc1_mc_4mv_chroma(v, bmvtype == BMV_TYPE_BACKWARD);
+ for (i = 0; i < 4; i++) {
+ dmv_x[0] = dmv_y[0] = pred_flag[0] = 0;
+ dmv_x[1] = dmv_y[1] = pred_flag[1] = 0;
+ if (v->fourmvbp & (8 >> i)) {
+ get_mvdata_interlaced(v, &dmv_x[bmvtype == BMV_TYPE_BACKWARD],
+ &dmv_y[bmvtype == BMV_TYPE_BACKWARD],
+ &pred_flag[bmvtype == BMV_TYPE_BACKWARD]);
+ }
+ ff_vc1_pred_b_mv_intfi(v, i, dmv_x, dmv_y, 0, pred_flag);
+ ff_vc1_mc_4mv_luma(v, i, bmvtype == BMV_TYPE_BACKWARD, 0);
}
+ ff_vc1_mc_4mv_chroma(v, bmvtype == BMV_TYPE_BACKWARD);
mb_has_coeffs = idx_mbmode & 1;
}
if (mb_has_coeffs)
@@ -2219,7 +2126,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v)
vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : s->linesize,
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), NULL);
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), NULL);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
first_block = 0;
@@ -2281,6 +2188,8 @@ 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)
+ 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);
@@ -2342,7 +2251,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v)
vc1_decode_intra_block(v, s->block[i], i, val, mquant,
(i & 4) ? v->codingset2 : v->codingset);
- if (i > 3 && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && i > 3 && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[i]);
if (i < 4) {
@@ -2508,7 +2417,7 @@ static int vc1_decode_b_mb_intfr(VC1Context *v)
pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb,
first_block, s->dest[dst_idx] + off,
(i & 4) ? s->uvlinesize : (s->linesize << fieldtx),
- (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), &block_tt);
+ CONFIG_GRAY && (i & 4) && (s->avctx->flags & CODEC_FLAG_GRAY), &block_tt);
block_cbp |= pat << (i << 2);
if (!v->ttmbf && ttmb < 8)
ttmb = -1;
@@ -2651,7 +2560,7 @@ static void vc1_decode_i_blocks(VC1Context *v)
vc1_decode_i_block(v, s->block[k], k, val, (k < 4) ? v->codingset : v->codingset2);
- if (k > 3 && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && k > 3 && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(s->block[k]);
if (v->pq >= 9 && v->overlap) {
@@ -2675,7 +2584,7 @@ static void vc1_decode_i_blocks(VC1Context *v)
if (s->mb_x) {
v->vc1dsp.vc1_h_overlap(s->dest[0], s->linesize);
v->vc1dsp.vc1_h_overlap(s->dest[0] + 8 * s->linesize, s->linesize);
- if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
v->vc1dsp.vc1_h_overlap(s->dest[1], s->uvlinesize);
v->vc1dsp.vc1_h_overlap(s->dest[2], s->uvlinesize);
}
@@ -2685,7 +2594,7 @@ static void vc1_decode_i_blocks(VC1Context *v)
if (!s->first_slice_line) {
v->vc1dsp.vc1_v_overlap(s->dest[0], s->linesize);
v->vc1dsp.vc1_v_overlap(s->dest[0] + 8, s->linesize);
- if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
v->vc1dsp.vc1_v_overlap(s->dest[1], s->uvlinesize);
v->vc1dsp.vc1_v_overlap(s->dest[2], s->uvlinesize);
}
@@ -2814,7 +2723,7 @@ static void vc1_decode_i_blocks_adv(VC1Context *v)
vc1_decode_i_block_adv(v, block[k], k, val,
(k < 4) ? v->codingset : v->codingset2, mquant);
- if (k > 3 && (s->avctx->flags & CODEC_FLAG_GRAY))
+ if (CONFIG_GRAY && k > 3 && (s->avctx->flags & CODEC_FLAG_GRAY))
continue;
v->vc1dsp.vc1_inv_trans_8x8(block[k]);
}
@@ -2842,15 +2751,14 @@ static void vc1_decode_i_blocks_adv(VC1Context *v)
/* raw bottom MB row */
s->mb_x = 0;
init_block_index(v);
-
- for (;s->mb_x < s->mb_width; s->mb_x++) {
+ for (; s->mb_x < s->mb_width; s->mb_x++) {
ff_update_block_index(s);
vc1_put_signed_blocks_clamped(v);
if (v->s.loop_filter)
ff_vc1_loop_filter_iblk_delayed(v, v->pq);
}
if (v->s.loop_filter)
- ff_mpeg_draw_horiz_band(s, (s->end_mb_y-1)*16, 16);
+ ff_mpeg_draw_horiz_band(s, (s->end_mb_y - 1) * 16, 16);
ff_er_add_slice(&s->er, 0, s->start_mb_y << v->field_mode, s->mb_width - 1,
(s->end_mb_y << v->field_mode) - 1, ER_MB_END);
}
@@ -2914,7 +2822,8 @@ static void vc1_decode_p_blocks(VC1Context *v)
memmove(v->ttblk_base, v->ttblk, sizeof(v->ttblk_base[0]) * s->mb_stride);
memmove(v->is_intra_base, v->is_intra, sizeof(v->is_intra_base[0]) * s->mb_stride);
memmove(v->luma_mv_base, v->luma_mv, sizeof(v->luma_mv_base[0]) * s->mb_stride);
- if (s->mb_y != s->start_mb_y) ff_mpeg_draw_horiz_band(s, (s->mb_y - 1) * 16, 16);
+ if (s->mb_y != s->start_mb_y)
+ ff_mpeg_draw_horiz_band(s, (s->mb_y - 1) * 16, 16);
s->first_slice_line = 0;
}
if (apply_loop_filter) {
diff --git a/libavcodec/vc1_common.h b/libavcodec/vc1_common.h
index 788d324cd8..b46c33f7e2 100644
--- a/libavcodec/vc1_common.h
+++ b/libavcodec/vc1_common.h
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include <stdint.h>
#include "libavutil/attributes.h"
+#include "internal.h"
/** Markers used in VC-1 AP frame data */
//@{
@@ -57,12 +58,9 @@ enum Profile {
*/
static av_always_inline const uint8_t* find_next_marker(const uint8_t *src, const uint8_t *end)
{
- uint32_t mrk = 0xFFFFFFFF;
-
- if (end-src < 4)
- return end;
- while (src < end) {
- mrk = (mrk << 8) | *src++;
+ if (end - src >= 4) {
+ uint32_t mrk = 0xFFFFFFFF;
+ src = avpriv_find_start_code(src, end, &mrk);
if (IS_MARKER(mrk))
return src - 4;
}
diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c
index e881f475fa..ad0945ff3a 100644
--- a/libavcodec/vc1_loopfilter.c
+++ b/libavcodec/vc1_loopfilter.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,6 +40,7 @@ void ff_vc1_loop_filter_iblk(VC1Context *v, int pq)
if (s->mb_x)
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize, s->linesize, pq);
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize + 8, s->linesize, pq);
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY))
for (j = 0; j < 2; j++) {
v->vc1dsp.vc1_v_loop_filter8(s->dest[j + 1], s->uvlinesize, pq);
if (s->mb_x)
@@ -51,8 +52,10 @@ void ff_vc1_loop_filter_iblk(VC1Context *v, int pq)
if (s->mb_y == s->end_mb_y - 1) {
if (s->mb_x) {
v->vc1dsp.vc1_h_loop_filter16(s->dest[0], s->linesize, pq);
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
v->vc1dsp.vc1_h_loop_filter8(s->dest[1], s->uvlinesize, pq);
v->vc1dsp.vc1_h_loop_filter8(s->dest[2], s->uvlinesize, pq);
+ }
}
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] + 8, s->linesize, pq);
}
@@ -73,6 +76,7 @@ void ff_vc1_loop_filter_iblk_delayed(VC1Context *v, int pq)
if (s->mb_x >= 2)
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize - 16, s->linesize, pq);
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize - 8, s->linesize, pq);
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY))
for (j = 0; j < 2; j++) {
v->vc1dsp.vc1_v_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize - 8, s->uvlinesize, pq);
if (s->mb_x >= 2) {
@@ -90,6 +94,7 @@ void ff_vc1_loop_filter_iblk_delayed(VC1Context *v, int pq)
if (s->mb_x)
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize, s->linesize, pq);
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize + 8, s->linesize, pq);
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY))
for (j = 0; j < 2; j++) {
v->vc1dsp.vc1_v_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize, s->uvlinesize, pq);
if (s->mb_x >= 2) {
@@ -105,7 +110,7 @@ void ff_vc1_loop_filter_iblk_delayed(VC1Context *v, int pq)
if (s->mb_x >= 2)
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize - 16, s->linesize, pq);
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize - 8, s->linesize, pq);
- if (s->mb_x >= 2) {
+ if (s->mb_x >= 2 && (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY))) {
for (j = 0; j < 2; j++) {
v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize - 8, s->uvlinesize, pq);
}
@@ -116,7 +121,7 @@ void ff_vc1_loop_filter_iblk_delayed(VC1Context *v, int pq)
if (s->mb_x)
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize, s->linesize, pq);
v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize + 8, s->linesize, pq);
- if (s->mb_x) {
+ if (s->mb_x && (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY))) {
for (j = 0; j < 2; j++) {
v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize, s->uvlinesize, pq);
}
@@ -150,7 +155,7 @@ void ff_vc1_smooth_overlap_filter_iblk(VC1Context *v)
v->block[v->cur_blk_idx][0]);
v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][3],
v->block[v->cur_blk_idx][2]);
- if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][4],
v->block[v->cur_blk_idx][4]);
v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][5],
@@ -169,7 +174,7 @@ void ff_vc1_smooth_overlap_filter_iblk(VC1Context *v)
v->block[v->cur_blk_idx][0]);
v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][3],
v->block[v->cur_blk_idx][1]);
- if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][4],
v->block[v->cur_blk_idx][4]);
v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][5],
@@ -189,7 +194,7 @@ void ff_vc1_smooth_overlap_filter_iblk(VC1Context *v)
v->block[v->left_blk_idx][0]);
v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][3],
v->block[v->left_blk_idx][1]);
- if (!(s->avctx->flags & CODEC_FLAG_GRAY)) {
+ if (!CONFIG_GRAY || !(s->avctx->flags & CODEC_FLAG_GRAY)) {
v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][4],
v->block[v->left_blk_idx][4]);
v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][5],
@@ -209,7 +214,7 @@ static av_always_inline void vc1_apply_p_v_loop_filter(VC1Context *v, int block_
int mb_cbp = v->cbp[s->mb_x - s->mb_stride],
block_cbp = mb_cbp >> (block_num * 4), bottom_cbp,
mb_is_intra = v->is_intra[s->mb_x - s->mb_stride],
- block_is_intra = mb_is_intra >> (block_num * 4), bottom_is_intra;
+ block_is_intra = mb_is_intra >> block_num, bottom_is_intra;
int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize, ttblk;
uint8_t *dst;
@@ -331,21 +336,22 @@ void ff_vc1_apply_p_loop_filter(VC1Context *v)
{
MpegEncContext *s = &v->s;
int i;
+ int block_count = CONFIG_GRAY && (s->avctx->flags & CODEC_FLAG_GRAY) ? 4 : 6;
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < block_count; i++) {
vc1_apply_p_v_loop_filter(v, i);
}
/* V always precedes H, therefore we run H one MB before V;
* at the end of a row, we catch up to complete the row */
if (s->mb_x) {
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < block_count; i++) {
vc1_apply_p_h_loop_filter(v, i);
}
if (s->mb_x == s->mb_width - 1) {
s->mb_x++;
ff_update_block_index(s);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < block_count; i++) {
vc1_apply_p_h_loop_filter(v, i);
}
}
diff --git a/libavcodec/vc1_mc.c b/libavcodec/vc1_mc.c
index 4dcb2f5a54..1a78c178db 100644
--- a/libavcodec/vc1_mc.c
+++ b/libavcodec/vc1_mc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,140 @@
#include "mpegvideo.h"
#include "vc1.h"
+static av_always_inline void vc1_scale_luma(uint8_t *srcY,
+ int k, int linesize)
+{
+ int i, j;
+ for (j = 0; j < k; j++) {
+ for (i = 0; i < k; i++)
+ srcY[i] = ((srcY[i] - 128) >> 1) + 128;
+ srcY += linesize;
+ }
+}
+
+static av_always_inline void vc1_scale_chroma(uint8_t *srcU, uint8_t *srcV,
+ int k, int uvlinesize)
+{
+ int i, j;
+ for (j = 0; j < k; j++) {
+ for (i = 0; i < k; i++) {
+ srcU[i] = ((srcU[i] - 128) >> 1) + 128;
+ srcV[i] = ((srcV[i] - 128) >> 1) + 128;
+ }
+ srcU += uvlinesize;
+ srcV += uvlinesize;
+ }
+}
+
+static av_always_inline void vc1_lut_scale_luma(uint8_t *srcY,
+ uint8_t *lut1, uint8_t *lut2,
+ int k, int linesize)
+{
+ int i, j;
+
+ for (j = 0; j < k; j += 2) {
+ for (i = 0; i < k; i++)
+ srcY[i] = lut1[srcY[i]];
+ srcY += linesize;
+
+ if (j + 1 == k)
+ break;
+
+ for (i = 0; i < k; i++)
+ srcY[i] = lut2[srcY[i]];
+ srcY += linesize;
+ }
+}
+
+static av_always_inline void vc1_lut_scale_chroma(uint8_t *srcU, uint8_t *srcV,
+ uint8_t *lut1, uint8_t *lut2,
+ int k, int uvlinesize)
+{
+ int i, j;
+
+ for (j = 0; j < k; j += 2) {
+ for (i = 0; i < k; i++) {
+ srcU[i] = lut1[srcU[i]];
+ srcV[i] = lut1[srcV[i]];
+ }
+ srcU += uvlinesize;
+ srcV += uvlinesize;
+
+ if (j + 1 == k)
+ break;
+
+ for (i = 0; i < k; i++) {
+ srcU[i] = lut2[srcU[i]];
+ srcV[i] = lut2[srcV[i]];
+ }
+ srcU += uvlinesize;
+ srcV += uvlinesize;
+ }
+}
+
+static const uint8_t popcount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+
+static av_always_inline int get_luma_mv(VC1Context *v, int dir, int16_t *tx, int16_t *ty)
+{
+ MpegEncContext *s = &v->s;
+ int idx = v->mv_f[dir][s->block_index[0] + v->blocks_off] |
+ (v->mv_f[dir][s->block_index[1] + v->blocks_off] << 1) |
+ (v->mv_f[dir][s->block_index[2] + v->blocks_off] << 2) |
+ (v->mv_f[dir][s->block_index[3] + v->blocks_off] << 3);
+ static const uint8_t index2[16] = { 0, 0, 0, 0x23, 0, 0x13, 0x03, 0, 0, 0x12, 0x02, 0, 0x01, 0, 0, 0 };
+ int opp_count = popcount4[idx];
+
+ switch (opp_count) {
+ case 0:
+ case 4:
+ *tx = median4(s->mv[dir][0][0], s->mv[dir][1][0], s->mv[dir][2][0], s->mv[dir][3][0]);
+ *ty = median4(s->mv[dir][0][1], s->mv[dir][1][1], s->mv[dir][2][1], s->mv[dir][3][1]);
+ break;
+ case 1:
+ *tx = mid_pred(s->mv[dir][idx < 2][0], s->mv[dir][1 + (idx < 4)][0], s->mv[dir][2 + (idx < 8)][0]);
+ *ty = mid_pred(s->mv[dir][idx < 2][1], s->mv[dir][1 + (idx < 4)][1], s->mv[dir][2 + (idx < 8)][1]);
+ break;
+ case 3:
+ *tx = mid_pred(s->mv[dir][idx > 0xd][0], s->mv[dir][1 + (idx > 0xb)][0], s->mv[dir][2 + (idx > 0x7)][0]);
+ *ty = mid_pred(s->mv[dir][idx > 0xd][1], s->mv[dir][1 + (idx > 0xb)][1], s->mv[dir][2 + (idx > 0x7)][1]);
+ break;
+ case 2:
+ *tx = (s->mv[dir][index2[idx] >> 4][0] + s->mv[dir][index2[idx] & 0xf][0]) / 2;
+ *ty = (s->mv[dir][index2[idx] >> 4][1] + s->mv[dir][index2[idx] & 0xf][1]) / 2;
+ break;
+ }
+ return opp_count;
+}
+
+static av_always_inline int get_chroma_mv(VC1Context *v, int dir, int16_t *tx, int16_t *ty)
+{
+ MpegEncContext *s = &v->s;
+ int idx = !v->mb_type[0][s->block_index[0]] |
+ (!v->mb_type[0][s->block_index[1]] << 1) |
+ (!v->mb_type[0][s->block_index[2]] << 2) |
+ (!v->mb_type[0][s->block_index[3]] << 3);
+ static const uint8_t index2[16] = { 0, 0, 0, 0x01, 0, 0x02, 0x12, 0, 0, 0x03, 0x13, 0, 0x23, 0, 0, 0 };
+ int valid_count = popcount4[idx];
+
+ switch (valid_count) {
+ case 4:
+ *tx = median4(s->mv[dir][0][0], s->mv[dir][1][0], s->mv[dir][2][0], s->mv[dir][3][0]);
+ *ty = median4(s->mv[dir][0][1], s->mv[dir][1][1], s->mv[dir][2][1], s->mv[dir][3][1]);
+ break;
+ case 3:
+ *tx = mid_pred(s->mv[dir][idx > 0xd][0], s->mv[dir][1 + (idx > 0xb)][0], s->mv[dir][2 + (idx > 0x7)][0]);
+ *ty = mid_pred(s->mv[dir][idx > 0xd][1], s->mv[dir][1 + (idx > 0xb)][1], s->mv[dir][2 + (idx > 0x7)][1]);
+ break;
+ case 2:
+ *tx = (s->mv[dir][index2[idx] >> 4][0] + s->mv[dir][index2[idx] & 0xf][0]) / 2;
+ *ty = (s->mv[dir][index2[idx] >> 4][1] + s->mv[dir][index2[idx] & 0xf][1]) / 2;
+ break;
+ default:
+ return 0;
+ }
+ return valid_count;
+}
+
/** Do motion compensation over 1 macroblock
* Mostly adapted hpel_motion and qpel_motion from mpegvideo.c
*/
@@ -85,7 +219,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
srcV = s->current_picture.f->data[2];
luty = v->curr_luty;
lutuv = v->curr_lutuv;
- use_ic = v->curr_use_ic;
+ use_ic = *v->curr_use_ic;
} else {
srcY = s->last_picture.f->data[0];
srcU = s->last_picture.f->data[1];
@@ -136,7 +270,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
}
/* for grayscale we should not try to read from unknown area */
- if (s->avctx->flags & CODEC_FLAG_GRAY) {
+ if (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY) {
srcU = s->edge_emu_buffer + 18 * s->linesize;
srcV = s->edge_emu_buffer + 18 * s->linesize;
}
@@ -145,81 +279,51 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
|| s->h_edge_pos < 22 || v_edge_pos < 22
|| (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx&3) - 16 - s->mspel * 3
|| (unsigned)(src_y - 1) > v_edge_pos - (my&3) - 16 - 3) {
- uint8_t *uvbuf = s->edge_emu_buffer + 19 * s->linesize;
+ uint8_t *ubuf = s->edge_emu_buffer + 19 * s->linesize;
+ uint8_t *vbuf = ubuf + 9 * s->uvlinesize;
+ const int k = 17 + s->mspel * 2;
srcY -= s->mspel * (1 + s->linesize);
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY,
s->linesize, s->linesize,
- 17 + s->mspel * 2, 17 + s->mspel * 2,
+ k, k,
src_x - s->mspel, src_y - s->mspel,
s->h_edge_pos, v_edge_pos);
srcY = s->edge_emu_buffer;
- s->vdsp.emulated_edge_mc(uvbuf, srcU,
+ s->vdsp.emulated_edge_mc(ubuf, srcU,
s->uvlinesize, s->uvlinesize,
8 + 1, 8 + 1,
- uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, v_edge_pos >> 1);
- s->vdsp.emulated_edge_mc(uvbuf + 16, srcV,
+ uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, v_edge_pos >> 1);
+ s->vdsp.emulated_edge_mc(vbuf, srcV,
s->uvlinesize, s->uvlinesize,
8 + 1, 8 + 1,
- uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, v_edge_pos >> 1);
- srcU = uvbuf;
- srcV = uvbuf + 16;
+ uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, v_edge_pos >> 1);
+ srcU = ubuf;
+ srcV = vbuf;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
- int i, j;
- uint8_t *src, *src2;
-
- src = srcY;
- for (j = 0; j < 17 + s->mspel * 2; j++) {
- for (i = 0; i < 17 + s->mspel * 2; i++)
- src[i] = ((src[i] - 128) >> 1) + 128;
- src += s->linesize;
- }
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 9; j++) {
- for (i = 0; i < 9; i++) {
- src[i] = ((src[i] - 128) >> 1) + 128;
- src2[i] = ((src2[i] - 128) >> 1) + 128;
- }
- src += s->uvlinesize;
- src2 += s->uvlinesize;
- }
+ vc1_scale_luma(srcY, k, s->linesize);
+ vc1_scale_chroma(srcU, srcV, 9, s->uvlinesize);
}
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
- int i, j;
- uint8_t *src, *src2;
-
- src = srcY;
- for (j = 0; j < 17 + s->mspel * 2; j++) {
- int f = v->field_mode ? v->ref_field_type[dir] : ((j + src_y - s->mspel) & 1) ;
- for (i = 0; i < 17 + s->mspel * 2; i++)
- src[i] = luty[f][src[i]];
- src += s->linesize;
- }
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 9; j++) {
- int f = v->field_mode ? v->ref_field_type[dir] : ((j + uvsrc_y) & 1);
- for (i = 0; i < 9; i++) {
- src[i] = lutuv[f][src[i]];
- src2[i] = lutuv[f][src2[i]];
- }
- src += s->uvlinesize;
- src2 += s->uvlinesize;
- }
+ vc1_lut_scale_luma(srcY,
+ luty[v->field_mode ? v->ref_field_type[dir] : ((0 + src_y - s->mspel) & 1)],
+ luty[v->field_mode ? v->ref_field_type[dir] : ((1 + src_y - s->mspel) & 1)],
+ k, s->linesize);
+ vc1_lut_scale_chroma(srcU, srcV,
+ lutuv[v->field_mode ? v->ref_field_type[dir] : ((0 + uvsrc_y) & 1)],
+ lutuv[v->field_mode ? v->ref_field_type[dir] : ((1 + uvsrc_y) & 1)],
+ 9, s->uvlinesize);
}
srcY += s->mspel * (1 + s->linesize);
}
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
- v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] , srcY , s->linesize, v->rnd);
- v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] + 8, srcY + 8, s->linesize, v->rnd);
- srcY += s->linesize * 8;
- v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] + 8 * s->linesize , srcY , s->linesize, v->rnd);
- v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] + 8 * s->linesize + 8, srcY + 8, s->linesize, v->rnd);
+ v->vc1dsp.put_vc1_mspel_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, v->rnd);
} else { // hpel mc - always used for luma
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
@@ -228,7 +332,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
s->hdsp.put_no_rnd_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
}
- if (s->avctx->flags & CODEC_FLAG_GRAY)
+ if (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY)
return;
/* Chroma MC always uses qpel bilinear */
uvmx = (uvmx & 3) << 1;
@@ -242,17 +346,6 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir)
}
}
-static inline int median4(int a, int b, int c, int d)
-{
- if (a < b) {
- if (c < d) return (FFMIN(b, d) + FFMAX(a, c)) / 2;
- else return (FFMIN(b, c) + FFMAX(a, d)) / 2;
- } else {
- if (c < d) return (FFMIN(a, d) + FFMAX(b, c)) / 2;
- else return (FFMIN(a, c) + FFMAX(b, d)) / 2;
- }
-}
-
/** Do motion compensation for 4-MV macroblock - luminance block
*/
void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
@@ -278,7 +371,7 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
if (v->field_mode && (v->cur_field_type != v->ref_field_type[dir]) && v->second_field) {
srcY = s->current_picture.f->data[0];
luty = v->curr_luty;
- use_ic = v->curr_use_ic;
+ use_ic = *v->curr_use_ic;
} else {
srcY = s->last_picture.f->data[0];
luty = v->last_luty;
@@ -301,35 +394,10 @@ 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 same_count = 0, opp_count = 0, k;
- int chosen_mv[2][4][2], f;
- int tx = 0, ty = 0;
- for (k = 0; k < 4; k++) {
- f = v->mv_f[0][s->block_index[k] + v->blocks_off];
- chosen_mv[f][f ? opp_count : same_count][0] = s->mv[0][k][0];
- chosen_mv[f][f ? opp_count : same_count][1] = s->mv[0][k][1];
- opp_count += f;
- same_count += 1 - f;
- }
- f = opp_count > same_count;
- switch (f ? opp_count : same_count) {
- case 4:
- tx = median4(chosen_mv[f][0][0], chosen_mv[f][1][0],
- chosen_mv[f][2][0], chosen_mv[f][3][0]);
- ty = median4(chosen_mv[f][0][1], chosen_mv[f][1][1],
- chosen_mv[f][2][1], chosen_mv[f][3][1]);
- break;
- case 3:
- tx = mid_pred(chosen_mv[f][0][0], chosen_mv[f][1][0], chosen_mv[f][2][0]);
- ty = mid_pred(chosen_mv[f][0][1], chosen_mv[f][1][1], chosen_mv[f][2][1]);
- break;
- case 2:
- tx = (chosen_mv[f][0][0] + chosen_mv[f][1][0]) / 2;
- ty = (chosen_mv[f][0][1] + chosen_mv[f][1][1]) / 2;
- break;
- }
- 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;
+ 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]);
+ int k, f = opp_count > 2;
for (k = 0; k < 4; k++)
v->mv_f[1][s->block_index[k] + v->blocks_off] = f;
}
@@ -385,46 +453,36 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
if (v->field_mode && v->ref_field_type[dir])
srcY += s->current_picture_ptr->f->linesize[0];
- if (fieldmv && !(src_y & 1))
- v_edge_pos--;
- if (fieldmv && (src_y & 1) && src_y < 4)
- src_y--;
+ if (fieldmv) {
+ if (!(src_y & 1))
+ v_edge_pos--;
+ else
+ src_y -= (src_y < 4);
+ }
if (v->rangeredfrm || use_ic
|| s->h_edge_pos < 13 || v_edge_pos < 23
|| (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx & 3) - 8 - s->mspel * 2
|| (unsigned)(src_y - (s->mspel << fieldmv)) > v_edge_pos - (my & 3) - ((8 + s->mspel * 2) << fieldmv)) {
+ const int k = 9 + s->mspel * 2;
+
srcY -= s->mspel * (1 + (s->linesize << fieldmv));
/* check emulate edge stride and offset */
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY,
s->linesize, s->linesize,
- 9 + s->mspel * 2, (9 + s->mspel * 2) << fieldmv,
+ k, k << fieldmv,
src_x - s->mspel, src_y - (s->mspel << fieldmv),
s->h_edge_pos, v_edge_pos);
srcY = s->edge_emu_buffer;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
- int i, j;
- uint8_t *src;
-
- src = srcY;
- for (j = 0; j < 9 + s->mspel * 2; j++) {
- for (i = 0; i < 9 + s->mspel * 2; i++)
- src[i] = ((src[i] - 128) >> 1) + 128;
- src += s->linesize << fieldmv;
- }
+ vc1_scale_luma(srcY, k, s->linesize << fieldmv);
}
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
- int i, j;
- uint8_t *src;
-
- src = srcY;
- for (j = 0; j < 9 + s->mspel * 2; j++) {
- int f = v->field_mode ? v->ref_field_type[dir] : (((j<<fieldmv)+src_y - (s->mspel << fieldmv)) & 1);
- for (i = 0; i < 9 + s->mspel * 2; i++)
- src[i] = luty[f][src[i]];
- src += s->linesize << fieldmv;
- }
+ vc1_lut_scale_luma(srcY,
+ luty[v->field_mode ? v->ref_field_type[dir] : (((0<<fieldmv)+src_y - (s->mspel << fieldmv)) & 1)],
+ luty[v->field_mode ? v->ref_field_type[dir] : (((1<<fieldmv)+src_y - (s->mspel << fieldmv)) & 1)],
+ k, s->linesize << fieldmv);
}
srcY += s->mspel * (1 + (s->linesize << fieldmv));
}
@@ -432,9 +490,9 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
if (avg)
- v->vc1dsp.avg_vc1_mspel_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
+ v->vc1dsp.avg_vc1_mspel_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
else
- v->vc1dsp.put_vc1_mspel_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
+ v->vc1dsp.put_vc1_mspel_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize << fieldmv, v->rnd);
} else { // hpel mc - always used for luma
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
@@ -444,59 +502,6 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg)
}
}
-static av_always_inline int get_chroma_mv(int *mvx, int *mvy, int *a, int flag, int *tx, int *ty)
-{
- int idx, i;
- static const int count[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
-
- idx = ((a[3] != flag) << 3)
- | ((a[2] != flag) << 2)
- | ((a[1] != flag) << 1)
- | (a[0] != flag);
- if (!idx) {
- *tx = median4(mvx[0], mvx[1], mvx[2], mvx[3]);
- *ty = median4(mvy[0], mvy[1], mvy[2], mvy[3]);
- return 4;
- } else if (count[idx] == 1) {
- switch (idx) {
- case 0x1:
- *tx = mid_pred(mvx[1], mvx[2], mvx[3]);
- *ty = mid_pred(mvy[1], mvy[2], mvy[3]);
- return 3;
- case 0x2:
- *tx = mid_pred(mvx[0], mvx[2], mvx[3]);
- *ty = mid_pred(mvy[0], mvy[2], mvy[3]);
- return 3;
- case 0x4:
- *tx = mid_pred(mvx[0], mvx[1], mvx[3]);
- *ty = mid_pred(mvy[0], mvy[1], mvy[3]);
- return 3;
- case 0x8:
- *tx = mid_pred(mvx[0], mvx[1], mvx[2]);
- *ty = mid_pred(mvy[0], mvy[1], mvy[2]);
- return 3;
- }
- } else if (count[idx] == 2) {
- int t1 = 0, t2 = 0;
- for (i = 0; i < 3; i++)
- if (!a[i]) {
- t1 = i;
- break;
- }
- for (i = t1 + 1; i < 4; i++)
- if (!a[i]) {
- t2 = i;
- break;
- }
- *tx = (mvx[t1] + mvx[t2]) / 2;
- *ty = (mvy[t1] + mvy[t2]) / 2;
- return 2;
- } else {
- return 0;
- }
- return -1;
-}
-
/** Do motion compensation for 4-MV macroblock - both chroma blocks
*/
void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir)
@@ -505,44 +510,30 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir)
H264ChromaContext *h264chroma = &v->h264chroma;
uint8_t *srcU, *srcV;
int uvmx, uvmy, uvsrc_x, uvsrc_y;
- int k, tx = 0, ty = 0;
- int mvx[4], mvy[4], intra[4], mv_f[4];
- int valid_count;
- int chroma_ref_type = v->cur_field_type;
+ int16_t tx, ty;
+ int chroma_ref_type;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
uint8_t (*lutuv)[256];
int use_ic;
if (!v->field_mode && !v->s.last_picture.f->data[0])
return;
- if (s->avctx->flags & CODEC_FLAG_GRAY)
+ if (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY)
return;
- for (k = 0; k < 4; k++) {
- mvx[k] = s->mv[dir][k][0];
- mvy[k] = s->mv[dir][k][1];
- intra[k] = v->mb_type[0][s->block_index[k]];
- if (v->field_mode)
- mv_f[k] = v->mv_f[dir][s->block_index[k] + v->blocks_off];
- }
-
/* calculate chroma MV vector from four luma MVs */
- if (!v->field_mode || (v->field_mode && !v->numref)) {
- valid_count = get_chroma_mv(mvx, mvy, intra, 0, &tx, &ty);
- chroma_ref_type = v->reffield;
+ 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;
v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0;
return; //no need to do MC for intra blocks
}
+ chroma_ref_type = v->ref_field_type[dir];
} else {
- int dominant = 0;
- if (mv_f[0] + mv_f[1] + mv_f[2] + mv_f[3] > 2)
- dominant = 1;
- valid_count = get_chroma_mv(mvx, mvy, mv_f, dominant, &tx, &ty);
- if (dominant)
- chroma_ref_type = !v->cur_field_type;
+ 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])
return;
@@ -578,7 +569,7 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir)
srcU = s->current_picture.f->data[1];
srcV = s->current_picture.f->data[2];
lutuv = v->curr_lutuv;
- use_ic = v->curr_use_ic;
+ use_ic = *v->curr_use_ic;
} else {
srcU = s->last_picture.f->data[1];
srcV = s->last_picture.f->data[2];
@@ -624,36 +615,14 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir)
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
- int i, j;
- uint8_t *src, *src2;
-
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 9; j++) {
- for (i = 0; i < 9; i++) {
- src[i] = ((src[i] - 128) >> 1) + 128;
- src2[i] = ((src2[i] - 128) >> 1) + 128;
- }
- src += s->uvlinesize;
- src2 += s->uvlinesize;
- }
+ vc1_scale_chroma(srcU, srcV, 9, s->uvlinesize);
}
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
- int i, j;
- uint8_t *src, *src2;
-
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 9; j++) {
- int f = v->field_mode ? chroma_ref_type : ((j + uvsrc_y) & 1);
- for (i = 0; i < 9; i++) {
- src[i] = lutuv[f][src[i]];
- src2[i] = lutuv[f][src2[i]];
- }
- src += s->uvlinesize;
- src2 += s->uvlinesize;
- }
+ vc1_lut_scale_chroma(srcU, srcV,
+ lutuv[v->field_mode ? chroma_ref_type : ((0 + uvsrc_y) & 1)],
+ lutuv[v->field_mode ? chroma_ref_type : ((1 + uvsrc_y) & 1)],
+ 9, s->uvlinesize);
}
}
@@ -680,13 +649,13 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg)
int uvmx_field[4], uvmy_field[4];
int i, off, tx, ty;
int fieldmv = v->blk_mv_type[s->block_index[0]];
- static const int s_rndtblfield[16] = { 0, 0, 1, 2, 4, 4, 5, 6, 2, 2, 3, 8, 6, 6, 7, 12 };
+ static const uint8_t s_rndtblfield[16] = { 0, 0, 1, 2, 4, 4, 5, 6, 2, 2, 3, 8, 6, 6, 7, 12 };
int v_dist = fieldmv ? 1 : 4; // vertical offset for lower sub-blocks
int v_edge_pos = s->v_edge_pos >> 1;
int use_ic;
uint8_t (*lutuv)[256];
- if (s->avctx->flags & CODEC_FLAG_GRAY)
+ if (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY)
return;
for (i = 0; i < 4; i++) {
@@ -708,23 +677,29 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg)
uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1);
uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1);
if (i < 2 ? dir : dir2) {
- srcU = s->next_picture.f->data[1] + uvsrc_y * s->uvlinesize + uvsrc_x;
- srcV = s->next_picture.f->data[2] + uvsrc_y * s->uvlinesize + uvsrc_x;
+ srcU = s->next_picture.f->data[1];
+ srcV = s->next_picture.f->data[2];
lutuv = v->next_lutuv;
use_ic = v->next_use_ic;
} else {
- srcU = s->last_picture.f->data[1] + uvsrc_y * s->uvlinesize + uvsrc_x;
- srcV = s->last_picture.f->data[2] + uvsrc_y * s->uvlinesize + uvsrc_x;
+ srcU = s->last_picture.f->data[1];
+ srcV = s->last_picture.f->data[2];
lutuv = v->last_lutuv;
use_ic = v->last_use_ic;
}
+ if (!srcU)
+ return;
+ srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
+ srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
uvmx_field[i] = (uvmx_field[i] & 3) << 1;
uvmy_field[i] = (uvmy_field[i] & 3) << 1;
- if (fieldmv && !(uvsrc_y & 1))
- v_edge_pos--;
- if (fieldmv && (uvsrc_y & 1) && uvsrc_y < 2)
- uvsrc_y--;
+ if (fieldmv) {
+ if (!(uvsrc_y & 1))
+ v_edge_pos = (s->v_edge_pos >> 1) - 1;
+ else
+ uvsrc_y -= (uvsrc_y < 2);
+ }
if (use_ic
|| s->h_edge_pos < 10 || v_edge_pos < (5 << fieldmv)
|| (unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 5
@@ -742,20 +717,10 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg)
/* if we deal with intensity compensation we need to scale source blocks */
if (use_ic) {
- int i, j;
- uint8_t *src, *src2;
-
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 5; j++) {
- int f = (uvsrc_y + (j << fieldmv)) & 1;
- for (i = 0; i < 5; i++) {
- src[i] = lutuv[f][src[i]];
- src2[i] = lutuv[f][src2[i]];
- }
- src += s->uvlinesize << fieldmv;
- src2 += s->uvlinesize << fieldmv;
- }
+ vc1_lut_scale_chroma(srcU, srcV,
+ lutuv[(uvsrc_y + (0 << fieldmv)) & 1],
+ lutuv[(uvsrc_y + (1 << fieldmv)) & 1],
+ 5, s->uvlinesize << fieldmv);
}
}
if (avg) {
@@ -786,7 +751,6 @@ void ff_vc1_interp_mc(VC1Context *v)
H264ChromaContext *h264chroma = &v->h264chroma;
uint8_t *srcY, *srcU, *srcV;
int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
- int off, off_uv;
int v_edge_pos = s->v_edge_pos >> v->field_mode;
int use_ic = v->next_use_ic;
@@ -837,7 +801,7 @@ void ff_vc1_interp_mc(VC1Context *v)
}
/* for grayscale we should not try to read from unknown area */
- if (s->avctx->flags & CODEC_FLAG_GRAY) {
+ if (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY) {
srcU = s->edge_emu_buffer + 18 * s->linesize;
srcV = s->edge_emu_buffer + 18 * s->linesize;
}
@@ -845,105 +809,72 @@ void ff_vc1_interp_mc(VC1Context *v)
if (v->rangeredfrm || s->h_edge_pos < 22 || v_edge_pos < 22 || use_ic
|| (unsigned)(src_x - 1) > s->h_edge_pos - (mx & 3) - 16 - 3
|| (unsigned)(src_y - 1) > v_edge_pos - (my & 3) - 16 - 3) {
- uint8_t *uvbuf = s->edge_emu_buffer + 19 * s->linesize;
+ uint8_t *ubuf = s->edge_emu_buffer + 19 * s->linesize;
+ uint8_t *vbuf = ubuf + 9 * s->uvlinesize;
+ const int k = 17 + s->mspel * 2;
srcY -= s->mspel * (1 + s->linesize);
s->vdsp.emulated_edge_mc(s->edge_emu_buffer, srcY,
s->linesize, s->linesize,
- 17 + s->mspel * 2, 17 + s->mspel * 2,
+ k, k,
src_x - s->mspel, src_y - s->mspel,
s->h_edge_pos, v_edge_pos);
srcY = s->edge_emu_buffer;
- s->vdsp.emulated_edge_mc(uvbuf, srcU,
+ s->vdsp.emulated_edge_mc(ubuf, srcU,
s->uvlinesize, s->uvlinesize,
8 + 1, 8 + 1,
- uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, v_edge_pos >> 1);
- s->vdsp.emulated_edge_mc(uvbuf + 16, srcV,
+ uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, v_edge_pos >> 1);
+ s->vdsp.emulated_edge_mc(vbuf, srcV,
s->uvlinesize, s->uvlinesize,
8 + 1, 8 + 1,
- uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, v_edge_pos >> 1);
- srcU = uvbuf;
- srcV = uvbuf + 16;
+ uvsrc_x, uvsrc_y,
+ s->h_edge_pos >> 1, v_edge_pos >> 1);
+ srcU = ubuf;
+ srcV = vbuf;
/* if we deal with range reduction we need to scale source blocks */
if (v->rangeredfrm) {
- int i, j;
- uint8_t *src, *src2;
-
- src = srcY;
- for (j = 0; j < 17 + s->mspel * 2; j++) {
- for (i = 0; i < 17 + s->mspel * 2; i++)
- src[i] = ((src[i] - 128) >> 1) + 128;
- src += s->linesize;
- }
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 9; j++) {
- for (i = 0; i < 9; i++) {
- src[i] = ((src[i] - 128) >> 1) + 128;
- src2[i] = ((src2[i] - 128) >> 1) + 128;
- }
- src += s->uvlinesize;
- src2 += s->uvlinesize;
- }
+ vc1_scale_luma(srcY, k, s->linesize);
+ vc1_scale_chroma(srcU, srcV, 9, s->uvlinesize);
}
if (use_ic) {
uint8_t (*luty )[256] = v->next_luty;
uint8_t (*lutuv)[256] = v->next_lutuv;
- int i, j;
- uint8_t *src, *src2;
-
- src = srcY;
- for (j = 0; j < 17 + s->mspel * 2; j++) {
- int f = v->field_mode ? v->ref_field_type[1] : ((j+src_y - s->mspel) & 1);
- for (i = 0; i < 17 + s->mspel * 2; i++)
- src[i] = luty[f][src[i]];
- src += s->linesize;
- }
- src = srcU;
- src2 = srcV;
- for (j = 0; j < 9; j++) {
- int f = v->field_mode ? v->ref_field_type[1] : ((j+uvsrc_y) & 1);
- for (i = 0; i < 9; i++) {
- src[i] = lutuv[f][src[i]];
- src2[i] = lutuv[f][src2[i]];
- }
- src += s->uvlinesize;
- src2 += s->uvlinesize;
- }
+ 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)],
+ k, s->linesize);
+ vc1_lut_scale_chroma(srcU, srcV,
+ lutuv[v->field_mode ? v->ref_field_type[1] : ((0+uvsrc_y) & 1)],
+ lutuv[v->field_mode ? v->ref_field_type[1] : ((1+uvsrc_y) & 1)],
+ 9, s->uvlinesize);
}
srcY += s->mspel * (1 + s->linesize);
}
- off = 0;
- off_uv = 0;
-
if (s->mspel) {
dxy = ((my & 3) << 2) | (mx & 3);
- v->vc1dsp.avg_vc1_mspel_pixels_tab[dxy](s->dest[0] + off , srcY , s->linesize, v->rnd);
- v->vc1dsp.avg_vc1_mspel_pixels_tab[dxy](s->dest[0] + off + 8, srcY + 8, s->linesize, v->rnd);
- srcY += s->linesize * 8;
- v->vc1dsp.avg_vc1_mspel_pixels_tab[dxy](s->dest[0] + off + 8 * s->linesize , srcY , s->linesize, v->rnd);
- v->vc1dsp.avg_vc1_mspel_pixels_tab[dxy](s->dest[0] + off + 8 * s->linesize + 8, srcY + 8, s->linesize, v->rnd);
+ v->vc1dsp.avg_vc1_mspel_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, v->rnd);
} else { // hpel mc
dxy = (my & 2) | ((mx & 2) >> 1);
if (!v->rnd)
- s->hdsp.avg_pixels_tab[0][dxy](s->dest[0] + off, srcY, s->linesize, 16);
+ s->hdsp.avg_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
else
- s->hdsp.avg_no_rnd_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize, 16);
+ s->hdsp.avg_no_rnd_pixels_tab[dxy](s->dest[0], srcY, s->linesize, 16);
}
- if (s->avctx->flags & CODEC_FLAG_GRAY)
+ if (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY)
return;
/* Chroma MC always uses qpel blilinear */
uvmx = (uvmx & 3) << 1;
uvmy = (uvmy & 3) << 1;
if (!v->rnd) {
- h264chroma->avg_h264_chroma_pixels_tab[0](s->dest[1] + off_uv, srcU, s->uvlinesize, 8, uvmx, uvmy);
- h264chroma->avg_h264_chroma_pixels_tab[0](s->dest[2] + off_uv, srcV, s->uvlinesize, 8, uvmx, uvmy);
+ h264chroma->avg_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
+ h264chroma->avg_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
} else {
- v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1] + off_uv, srcU, s->uvlinesize, 8, uvmx, uvmy);
- v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2] + off_uv, srcV, s->uvlinesize, 8, uvmx, uvmy);
+ v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
+ v->vc1dsp.avg_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
}
}
diff --git a/libavcodec/vc1_parser.c b/libavcodec/vc1_parser.c
index 38b62f72bd..9ca6154e71 100644
--- a/libavcodec/vc1_parser.c
+++ b/libavcodec/vc1_parser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@
#include "parser.h"
#include "vc1.h"
#include "get_bits.h"
+#include "internal.h"
/** The maximum number of bytes of a sequence, entry point or
* frame header whose values we pay any attention to */
@@ -63,6 +64,7 @@ static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
/* Parse the header we just finished unescaping */
VC1ParseContext *vpc = s->priv_data;
GetBitContext gb;
+ int ret;
vpc->v.s.avctx = avctx;
vpc->v.parse_only = 1;
init_get_bits(&gb, buf, buf_size * 8);
@@ -75,9 +77,12 @@ static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
break;
case VC1_CODE_FRAME & 0xFF:
if(vpc->v.profile < PROFILE_ADVANCED)
- ff_vc1_parse_frame_header (&vpc->v, &gb);
+ ret = ff_vc1_parse_frame_header (&vpc->v, &gb);
else
- ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
+ ret = ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
+
+ if (ret < 0)
+ break;
/* keep AV_PICTURE_TYPE_BI internal to VC1 */
if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
@@ -108,6 +113,8 @@ static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
break;
}
+ if (avctx->framerate.num)
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
}
static int vc1_parse(AVCodecParserContext *s,
@@ -233,7 +240,7 @@ static int vc1_parse(AVCodecParserContext *s,
* the start code we've already seen, or cause extra bytes to be
* inserted at the start of the unescaped buffer. */
vpc->bytes_to_skip = 4;
- if (next < 0 && start_code_found)
+ if (next < 0 && next != END_NOT_FOUND)
vpc->bytes_to_skip += next;
*poutbuf = buf;
@@ -244,20 +251,18 @@ static int vc1_parse(AVCodecParserContext *s,
static int vc1_split(AVCodecContext *avctx,
const uint8_t *buf, int buf_size)
{
- int i;
- uint32_t state= -1;
- int charged=0;
+ uint32_t state = -1;
+ int charged = 0;
+ const uint8_t *ptr = buf, *end = buf + buf_size;
- for(i=0; i<buf_size; i++){
- state= (state<<8) | buf[i];
- if(IS_MARKER(state)){
- if(state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT){
- charged=1;
- }else if(charged){
- return i-3;
- }
- }
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &state);
+ if (state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT) {
+ charged = 1;
+ } else if (charged && IS_MARKER(state))
+ return ptr - 4 - buf;
}
+
return 0;
}
@@ -265,6 +270,7 @@ static av_cold int vc1_parse_init(AVCodecParserContext *s)
{
VC1ParseContext *vpc = s->priv_data;
vpc->v.s.slice_context_count = 1;
+ vpc->v.first_pic_header_flag = 1;
vpc->prev_start_code = 0;
vpc->bytes_to_skip = 0;
vpc->unesc_index = 0;
diff --git a/libavcodec/vc1_pred.c b/libavcodec/vc1_pred.c
index 96426f53ea..13134e5d8a 100644
--- a/libavcodec/vc1_pred.c
+++ b/libavcodec/vc1_pred.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -170,9 +170,9 @@ 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) << hpel;
+ n = scaleforsame_y(v, i, n, dir) * (1 << hpel);
else
- n = scaleforsame_x(v, n, dir) << hpel;
+ n = scaleforsame_x(v, n, dir) * (1 << hpel);
return n;
}
brfd = FFMIN(v->brfd, 3);
@@ -202,7 +202,7 @@ static av_always_inline int scaleforopp(VC1Context *v, int n /* MV */,
refdist = dir ? v->brfd : v->frfd;
scaleopp = ff_vc1_field_mvpred_scales[dir ^ v->second_field][0][refdist];
- n = (n * scaleopp >> 8) << hpel;
+ n = (n * scaleopp >> 8) * (1 << hpel);
return n;
}
@@ -231,8 +231,10 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y,
else
mixedmv_pic = 0;
/* scale MV difference to be quad-pel */
- dmv_x <<= 1 - s->quarter_sample;
- dmv_y <<= 1 - s->quarter_sample;
+ if (!s->quarter_sample) {
+ dmv_x *= 2;
+ dmv_y *= 2;
+ }
wrap = s->b8_stride;
xy = s->block_index[n];
@@ -392,17 +394,13 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y,
/* Pullback MV as specified in 8.3.5.3.4 */
if (!v->field_mode) {
int qx, qy, X, Y;
+ int MV = mv1 ? -60 : -28;
qx = (s->mb_x << 6) + ((n == 1 || n == 3) ? 32 : 0);
qy = (s->mb_y << 6) + ((n == 2 || n == 3) ? 32 : 0);
X = (s->mb_width << 6) - 4;
Y = (s->mb_height << 6) - 4;
- if (mv1) {
- if (qx + px < -60) px = -60 - qx;
- if (qy + py < -60) py = -60 - qy;
- } else {
- if (qx + px < -28) px = -28 - qx;
- if (qy + py < -28) py = -28 - qy;
- }
+ if (qx + px < MV) px = MV - qx;
+ if (qy + py < MV) py = MV - qy;
if (qx + px > X) px = X - qx;
if (qy + py > Y) py = Y - qy;
}
@@ -602,9 +600,9 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
px = mid_pred(A[0], B[0], C[0]);
py = mid_pred(A[1], B[1], C[1]);
} else if (total_valid) {
- if (a_valid) { px = A[0]; py = A[1]; }
- if (b_valid) { px = B[0]; py = B[1]; }
- if (c_valid) { px = C[0]; py = C[1]; }
+ if (a_valid) { px = A[0]; py = A[1]; }
+ else if (b_valid) { px = B[0]; py = B[1]; }
+ else { px = C[0]; py = C[1]; }
}
}
} else {
@@ -644,7 +642,8 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
} else if (!field_b && b_valid) {
px = B[0];
py = B[1];
- } else if (c_valid) {
+ } else /*if (c_valid)*/ {
+ av_assert1(c_valid);
px = C[0];
py = C[1];
}
@@ -652,7 +651,8 @@ void ff_vc1_pred_mv_intfr(VC1Context *v, int n, int dmv_x, int dmv_y,
if (field_a && a_valid) {
px = A[0];
py = A[1];
- } else if (field_b && b_valid) {
+ } else /*if (field_b && b_valid)*/ {
+ av_assert1(field_b && b_valid);
px = B[0];
py = B[1];
}
@@ -692,25 +692,31 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2],
int r_x, r_y;
const uint8_t *is_intra = v->mb_type[0];
+ av_assert0(!v->field_mode);
+
r_x = v->range_x;
r_y = v->range_y;
/* scale MV difference to be quad-pel */
- dmv_x[0] <<= 1 - s->quarter_sample;
- dmv_y[0] <<= 1 - s->quarter_sample;
- dmv_x[1] <<= 1 - s->quarter_sample;
- dmv_y[1] <<= 1 - s->quarter_sample;
+ if (!s->quarter_sample) {
+ dmv_x[0] *= 2;
+ dmv_y[0] *= 2;
+ dmv_x[1] *= 2;
+ dmv_y[1] *= 2;
+ }
wrap = s->b8_stride;
xy = s->block_index[0];
if (s->mb_intra) {
- s->current_picture.motion_val[0][xy + v->blocks_off][0] =
- s->current_picture.motion_val[0][xy + v->blocks_off][1] =
- s->current_picture.motion_val[1][xy + v->blocks_off][0] =
- s->current_picture.motion_val[1][xy + v->blocks_off][1] = 0;
+ 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;
return;
}
- if (!v->field_mode) {
+ if (direct && s->next_picture_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);
@@ -721,12 +727,11 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2],
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 + v->blocks_off][0] = s->mv[0][0][0];
- s->current_picture.motion_val[0][xy + v->blocks_off][1] = s->mv[0][0][1];
- s->current_picture.motion_val[1][xy + v->blocks_off][0] = s->mv[1][0][0];
- s->current_picture.motion_val[1][xy + v->blocks_off][1] = s->mv[1][0][1];
+ 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];
return;
}
@@ -754,25 +759,16 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2],
/* Pullback MV as specified in 8.3.5.3.4 */
{
int qx, qy, X, Y;
- if (v->profile < PROFILE_ADVANCED) {
- qx = (s->mb_x << 5);
- qy = (s->mb_y << 5);
- X = (s->mb_width << 5) - 4;
- Y = (s->mb_height << 5) - 4;
- if (qx + px < -28) px = -28 - qx;
- if (qy + py < -28) py = -28 - qy;
- if (qx + px > X) px = X - qx;
- if (qy + py > Y) py = Y - qy;
- } else {
- qx = (s->mb_x << 6);
- qy = (s->mb_y << 6);
- X = (s->mb_width << 6) - 4;
- Y = (s->mb_height << 6) - 4;
- if (qx + px < -60) px = -60 - qx;
- if (qy + py < -60) py = -60 - qy;
- if (qx + px > X) px = X - qx;
- if (qy + py > Y) py = Y - qy;
- }
+ int sh = v->profile < PROFILE_ADVANCED ? 5 : 6;
+ int MV = 4 - (1 << sh);
+ qx = (s->mb_x << sh);
+ qy = (s->mb_y << sh);
+ X = (s->mb_width << sh) - 4;
+ Y = (s->mb_height << sh) - 4;
+ if (qx + px < MV) px = MV - qx;
+ if (qy + py < MV) py = MV - qy;
+ if (qx + px > X) px = X - qx;
+ if (qy + py > Y) py = Y - qy;
}
/* Calculate hybrid prediction as specified in 8.3.5.3.5 */
if (0 && !s->first_slice_line && s->mb_x) {
@@ -833,25 +829,16 @@ void ff_vc1_pred_b_mv(VC1Context *v, int dmv_x[2], int dmv_y[2],
/* Pullback MV as specified in 8.3.5.3.4 */
{
int qx, qy, X, Y;
- if (v->profile < PROFILE_ADVANCED) {
- qx = (s->mb_x << 5);
- qy = (s->mb_y << 5);
- X = (s->mb_width << 5) - 4;
- Y = (s->mb_height << 5) - 4;
- if (qx + px < -28) px = -28 - qx;
- if (qy + py < -28) py = -28 - qy;
- if (qx + px > X) px = X - qx;
- if (qy + py > Y) py = Y - qy;
- } else {
- qx = (s->mb_x << 6);
- qy = (s->mb_y << 6);
- X = (s->mb_width << 6) - 4;
- Y = (s->mb_height << 6) - 4;
- if (qx + px < -60) px = -60 - qx;
- if (qy + py < -60) py = -60 - qy;
- if (qx + px > X) px = X - qx;
- if (qy + py > Y) py = Y - qy;
- }
+ int sh = v->profile < PROFILE_ADVANCED ? 5 : 6;
+ int MV = 4 - (1 << sh);
+ qx = (s->mb_x << sh);
+ qy = (s->mb_y << sh);
+ X = (s->mb_width << sh) - 4;
+ Y = (s->mb_height << sh) - 4;
+ if (qx + px < MV) px = MV - qx;
+ if (qy + py < MV) py = MV - qy;
+ if (qx + px > X) px = X - qx;
+ if (qy + py > Y) py = Y - qy;
}
/* Calculate hybrid prediction as specified in 8.3.5.3.5 */
if (0 && !s->first_slice_line && s->mb_x) {
diff --git a/libavcodec/vc1_pred.h b/libavcodec/vc1_pred.h
index 34c9c1a08c..4d47f86696 100644
--- a/libavcodec/vc1_pred.h
+++ b/libavcodec/vc1_pred.h
@@ -3,20 +3,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vc1acdata.h b/libavcodec/vc1acdata.h
index 73ebe40bdf..a70b44ae05 100644
--- a/libavcodec/vc1acdata.h
+++ b/libavcodec/vc1acdata.h
@@ -2,20 +2,20 @@
* VC-1 and WMV3 decoder
* copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vc1data.c b/libavcodec/vc1data.c
index 70cead8b2c..fc9ba6da13 100644
--- a/libavcodec/vc1data.c
+++ b/libavcodec/vc1data.c
@@ -4,20 +4,20 @@
* copyright (c) 2006 Konstantin Shishkov
* (c) 2005 anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -1019,21 +1019,21 @@ const uint8_t ff_vc1_mv_diff_bits[4][73] = {
/* DC differentials low+hi-mo, p217 are the same as in msmpeg4data .h */
/* Table 232 */
-const int8_t ff_vc1_simple_progressive_4x4_zz [16] = {
+const uint8_t ff_vc1_simple_progressive_4x4_zz [16] = {
0, 8, 16, 1,
9, 24, 17, 2,
10, 18, 25, 3,
11, 26, 19, 27
};
-const int8_t ff_vc1_adv_progressive_8x4_zz [32] = { /* Table 233 */
+const uint8_t ff_vc1_adv_progressive_8x4_zz [32] = { /* Table 233 */
0, 8, 1, 16, 2, 9, 10, 3,
24, 17, 4, 11, 18, 12, 5, 19,
25, 13, 20, 26, 27, 6, 21, 28,
14, 22, 29, 7, 30, 15, 23, 31
};
-const int8_t ff_vc1_adv_progressive_4x8_zz [32] = { /* Table 234 */
+const uint8_t ff_vc1_adv_progressive_4x8_zz [32] = { /* Table 234 */
0, 1, 8, 2,
9, 16, 17, 24,
10, 32, 25, 18,
@@ -1044,7 +1044,7 @@ const int8_t ff_vc1_adv_progressive_4x8_zz [32] = { /* Table 234 */
35, 43, 51, 59
};
-const int8_t ff_vc1_adv_interlaced_8x8_zz [64] = { /* Table 235 */
+const uint8_t ff_vc1_adv_interlaced_8x8_zz [64] = { /* Table 235 */
0, 8, 1, 16, 24, 9, 2, 32,
40, 48, 56, 17, 10, 3, 25, 18,
11, 4, 33, 41, 49, 57, 26, 34,
@@ -1055,14 +1055,14 @@ const int8_t ff_vc1_adv_interlaced_8x8_zz [64] = { /* Table 235 */
61, 62, 54, 46, 39, 47, 55, 63
};
-const int8_t ff_vc1_adv_interlaced_8x4_zz [32] = { /* Table 236 */
+const uint8_t ff_vc1_adv_interlaced_8x4_zz [32] = { /* Table 236 */
0, 8, 16, 24, 1, 9, 2, 17,
25, 10, 3, 18, 26, 4, 11, 19,
12, 5, 13, 20, 27, 6, 21, 28,
14, 22, 29, 7, 30, 15, 23, 31
};
-const int8_t ff_vc1_adv_interlaced_4x8_zz [32] = { /* Table 237 */
+const uint8_t ff_vc1_adv_interlaced_4x8_zz [32] = { /* Table 237 */
0, 1, 2, 8,
16, 9, 24, 17,
10, 3, 32, 40,
@@ -1073,7 +1073,7 @@ const int8_t ff_vc1_adv_interlaced_4x8_zz [32] = { /* Table 237 */
35, 43, 51, 59
};
-const int8_t ff_vc1_adv_interlaced_4x4_zz [16] = { /* Table 238 */
+const uint8_t ff_vc1_adv_interlaced_4x4_zz [16] = { /* Table 238 */
0, 8, 16, 24,
1, 9, 17, 2,
25, 10, 18, 3,
diff --git a/libavcodec/vc1data.h b/libavcodec/vc1data.h
index 66c569b797..763cd48a60 100644
--- a/libavcodec/vc1data.h
+++ b/libavcodec/vc1data.h
@@ -3,20 +3,20 @@
* copyright (c) 2006 Konstantin Shishkov
* (c) 2005 anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -181,15 +181,15 @@ extern const uint8_t ff_vc1_2ref_mvdata_bits[8][126];
/* DC differentials low+hi-mo, p217 are the same as in msmpeg4data .h */
/* Scantables/ZZ scan are at 11.9 (p262) and 8.1.1.12 (p10) */
-extern const int8_t ff_vc1_simple_progressive_4x4_zz [16];
-extern const int8_t ff_vc1_adv_progressive_8x4_zz [32];
-extern const int8_t ff_vc1_adv_progressive_4x8_zz [32];
-extern const int8_t ff_vc1_adv_interlaced_8x8_zz [64];
-extern const int8_t ff_vc1_adv_interlaced_8x4_zz [32];
-extern const int8_t ff_vc1_adv_interlaced_4x8_zz [32];
-extern const int8_t ff_vc1_adv_interlaced_4x4_zz [16];
-extern const int8_t ff_vc1_intra_horz_8x8_zz [64];
-extern const int8_t ff_vc1_intra_vert_8x8_zz [64];
+extern const uint8_t ff_vc1_simple_progressive_4x4_zz [16];
+extern const uint8_t ff_vc1_adv_progressive_8x4_zz [32];
+extern const uint8_t ff_vc1_adv_progressive_4x8_zz [32];
+extern const uint8_t ff_vc1_adv_interlaced_8x8_zz [64];
+extern const uint8_t ff_vc1_adv_interlaced_8x4_zz [32];
+extern const uint8_t ff_vc1_adv_interlaced_4x8_zz [32];
+extern const uint8_t ff_vc1_adv_interlaced_4x4_zz [16];
+extern const uint8_t ff_vc1_intra_horz_8x8_zz [64];
+extern const uint8_t ff_vc1_intra_vert_8x8_zz [64];
/* DQScale as specified in 8.1.3.9 - almost identical to 0x40000/i */
extern const int32_t ff_vc1_dqscale[63];
diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c
index 2a252d31ee..eab6792f36 100644
--- a/libavcodec/vc1dec.c
+++ b/libavcodec/vc1dec.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006-2007 Konstantin Shishkov
* Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,6 +35,9 @@
#include "msmpeg4data.h"
#include "vc1.h"
#include "vc1data.h"
+#include "vdpau_internal.h"
+#include "libavutil/avassert.h"
+
#if CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER
@@ -96,7 +99,7 @@ static void vc1_sprite_parse_transform(GetBitContext* gb, int c[7])
c[6] = 1 << 16;
}
-static void vc1_parse_sprites(VC1Context *v, GetBitContext* gb, SpriteData* sd)
+static int vc1_parse_sprites(VC1Context *v, GetBitContext* gb, SpriteData* sd)
{
AVCodecContext *avctx = v->s.avctx;
int sprite, i;
@@ -140,7 +143,7 @@ static void vc1_parse_sprites(VC1Context *v, GetBitContext* gb, SpriteData* sd)
sd->effect_pcount2 = get_bits(gb, 16);
if (sd->effect_pcount2 > 10) {
av_log(avctx, AV_LOG_ERROR, "Too many effect parameters\n");
- return;
+ return AVERROR_INVALIDDATA;
} else if (sd->effect_pcount2) {
i = -1;
av_log(avctx, AV_LOG_DEBUG, "Effect params 2: ");
@@ -157,10 +160,14 @@ static void vc1_parse_sprites(VC1Context *v, GetBitContext* gb, SpriteData* sd)
av_log(avctx, AV_LOG_DEBUG, "Effect flag set\n");
if (get_bits_count(gb) >= gb->size_in_bits +
- (avctx->codec_id == AV_CODEC_ID_WMV3IMAGE ? 64 : 0))
+ (avctx->codec_id == AV_CODEC_ID_WMV3IMAGE ? 64 : 0)) {
av_log(avctx, AV_LOG_ERROR, "Buffer overrun\n");
+ return AVERROR_INVALIDDATA;
+ }
if (get_bits_count(gb) < gb->size_in_bits - 8)
av_log(avctx, AV_LOG_WARNING, "Buffer not fully read\n");
+
+ return 0;
}
static void vc1_draw_sprites(VC1Context *v, SpriteData* sd)
@@ -172,7 +179,7 @@ static void vc1_draw_sprites(VC1Context *v, SpriteData* sd)
int ysub[2];
MpegEncContext *s = &v->s;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i <= v->two_sprites; i++) {
xoff[i] = av_clip(sd->coefs[i][2], 0, v->sprite_width-1 << 16);
xadv[i] = sd->coefs[i][0];
if (xadv[i] != 1<<16 || (v->sprite_width << 16) - (v->output_width << 16) - xoff[i])
@@ -183,7 +190,7 @@ static void vc1_draw_sprites(VC1Context *v, SpriteData* sd)
}
alpha = av_clip_uint16(sd->coefs[1][6]);
- for (plane = 0; plane < (s->avctx->flags & CODEC_FLAG_GRAY ? 1 : 3); plane++) {
+ for (plane = 0; plane < (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY ? 1 : 3); plane++) {
int width = v->output_width>>!!plane;
for (row = 0; row < v->output_height>>!!plane; row++) {
@@ -250,7 +257,7 @@ static void vc1_draw_sprites(VC1Context *v, SpriteData* sd)
}
if (!plane) {
- for (i = 0; i < 2; i++) {
+ for (i = 0; i <= v->two_sprites; i++) {
xoff[i] >>= 1;
yoff[i] >>= 1;
}
@@ -262,13 +269,18 @@ static void vc1_draw_sprites(VC1Context *v, SpriteData* sd)
static int vc1_decode_sprites(VC1Context *v, GetBitContext* gb)
{
+ int ret;
MpegEncContext *s = &v->s;
AVCodecContext *avctx = s->avctx;
SpriteData sd;
- vc1_parse_sprites(v, gb, &sd);
+ memset(&sd, 0, sizeof(sd));
+
+ ret = vc1_parse_sprites(v, gb, &sd);
+ if (ret < 0)
+ return ret;
- if (!s->current_picture.f->data[0]) {
+ if (!s->current_picture.f || !s->current_picture.f->data[0]) {
av_log(avctx, AV_LOG_ERROR, "Got no sprites\n");
return -1;
}
@@ -279,10 +291,8 @@ static int vc1_decode_sprites(VC1Context *v, GetBitContext* gb)
}
av_frame_unref(v->sprite_output_frame);
- if (ff_get_buffer(avctx, v->sprite_output_frame, 0) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return -1;
- }
+ if ((ret = ff_get_buffer(avctx, v->sprite_output_frame, 0)) < 0)
+ return ret;
vc1_draw_sprites(v, &sd);
@@ -301,7 +311,7 @@ static void vc1_sprite_flush(AVCodecContext *avctx)
wrong but it looks better than doing nothing. */
if (f && f->data[0])
- for (plane = 0; plane < (s->avctx->flags & CODEC_FLAG_GRAY ? 1 : 3); plane++)
+ for (plane = 0; plane < (CONFIG_GRAY && s->avctx->flags & CODEC_FLAG_GRAY ? 1 : 3); plane++)
for (i = 0; i < v->sprite_height>>!!plane; i++)
memset(f->data[plane] + i * f->linesize[plane],
plane ? 128 : 0, f->linesize[plane]);
@@ -331,7 +341,7 @@ av_cold int ff_vc1_decode_init_alloc_tables(VC1Context *v)
v->ttblk = v->ttblk_base + s->mb_stride;
v->is_intra_base = av_mallocz(sizeof(v->is_intra_base[0]) * 2 * s->mb_stride);
v->is_intra = v->is_intra_base + s->mb_stride;
- v->luma_mv_base = av_malloc(sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride);
+ v->luma_mv_base = av_mallocz(sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride);
v->luma_mv = v->luma_mv_base + s->mb_stride;
/* allocate block type info in that way so it could be used with s->block_index[] */
@@ -362,7 +372,8 @@ av_cold int ff_vc1_decode_init_alloc_tables(VC1Context *v)
if (s->avctx->codec_id == AV_CODEC_ID_WMV3IMAGE || s->avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
for (i = 0; i < 4; i++)
- if (!(v->sr_rows[i >> 1][i & 1] = av_malloc(v->output_width))) return -1;
+ if (!(v->sr_rows[i >> 1][i & 1] = av_malloc(v->output_width)))
+ return AVERROR(ENOMEM);
}
if (!v->mv_type_mb_plane || !v->direct_mb_plane || !v->acpred_plane || !v->over_flags_plane ||
@@ -388,7 +399,7 @@ av_cold void ff_vc1_init_transposed_scantables(VC1Context *v)
{
int i;
for (i = 0; i < 64; i++) {
-#define transpose(x) ((x >> 3) | ((x & 7) << 3))
+#define transpose(x) (((x) >> 3) | (((x) & 7) << 3))
v->zz_8x8[0][i] = transpose(ff_wmv1_scantable[0][i]);
v->zz_8x8[1][i] = transpose(ff_wmv1_scantable[1][i]);
v->zz_8x8[2][i] = transpose(ff_wmv1_scantable[2][i]);
@@ -408,6 +419,7 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
VC1Context *v = avctx->priv_data;
MpegEncContext *s = &v->s;
GetBitContext gb;
+ int ret;
/* save the container output size for WMImage */
v->output_width = avctx->width;
@@ -415,14 +427,27 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
if (!avctx->extradata_size || !avctx->extradata)
return -1;
- if (!(avctx->flags & CODEC_FLAG_GRAY))
+ if (!CONFIG_GRAY || !(avctx->flags & CODEC_FLAG_GRAY))
avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);
- else
+ else {
avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ if (avctx->color_range == AVCOL_RANGE_UNSPECIFIED)
+ avctx->color_range = AVCOL_RANGE_MPEG;
+ }
v->s.avctx = avctx;
- if (ff_vc1_init_common(v) < 0)
- return -1;
+ if ((ret = ff_vc1_init_common(v)) < 0)
+ return ret;
+ // ensure static VLC tables are initialized
+ if ((ret = ff_msmpeg4_decode_init(avctx)) < 0)
+ return ret;
+ if ((ret = ff_vc1_decode_init_alloc_tables(v)) < 0)
+ return ret;
+ // Hack to ensure the above functions will be called
+ // again once we know all necessary settings.
+ // That this is necessary might indicate a bug.
+ ff_vc1_decode_end(avctx);
+
ff_blockdsp_init(&s->bdsp, avctx);
ff_h264chroma_init(&v->h264chroma, 8);
ff_qpeldsp_init(&s->qdsp);
@@ -437,8 +462,8 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
init_get_bits(&gb, avctx->extradata, avctx->extradata_size*8);
- if (ff_vc1_decode_sequence_header(avctx, v, &gb) < 0)
- return -1;
+ if ((ret = ff_vc1_decode_sequence_header(avctx, v, &gb)) < 0)
+ return ret;
count = avctx->extradata_size*8 - get_bits_count(&gb);
if (count > 0) {
@@ -461,6 +486,9 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
}
buf2 = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!buf2)
+ return AVERROR(ENOMEM);
+
start = find_next_marker(start, end); // in WVC1 extradata first byte is its size, but can be 0 in mkv
next = start;
for (; next < end; start = next) {
@@ -472,16 +500,16 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
init_get_bits(&gb, buf2, buf2_size * 8);
switch (AV_RB32(start)) {
case VC1_CODE_SEQHDR:
- if (ff_vc1_decode_sequence_header(avctx, v, &gb) < 0) {
+ if ((ret = ff_vc1_decode_sequence_header(avctx, v, &gb)) < 0) {
av_free(buf2);
- return -1;
+ return ret;
}
seq_initialized = 1;
break;
case VC1_CODE_ENTRYPOINT:
- if (ff_vc1_decode_entry_point(avctx, v, &gb) < 0) {
+ if ((ret = ff_vc1_decode_entry_point(avctx, v, &gb)) < 0) {
av_free(buf2);
- return -1;
+ return ret;
}
ep_initialized = 1;
break;
@@ -535,6 +563,11 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
v->sprite_height > 1 << 14 ||
v->output_width > 1 << 14 ||
v->output_height > 1 << 14) return -1;
+
+ if ((v->sprite_width&1) || (v->sprite_height&1)) {
+ avpriv_request_sample(avctx, "odd sprites support");
+ return AVERROR_PATCHWELCOME;
+ }
}
return 0;
}
@@ -586,14 +619,19 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
MpegEncContext *s = &v->s;
AVFrame *pict = data;
uint8_t *buf2 = NULL;
- const uint8_t *buf_start = buf;
- int mb_height, n_slices1;
+ const uint8_t *buf_start = buf, *buf_start_second_field = NULL;
+ int mb_height, n_slices1=-1;
struct {
uint8_t *buf;
GetBitContext gb;
int mby_start;
} *slices = NULL, *tmp;
+ v->second_field = 0;
+
+ if(s->avctx->flags & CODEC_FLAG_LOW_DELAY)
+ s->low_delay = 1;
+
/* no supplementary picture */
if (buf_size == 0 || (buf_size == 4 && AV_RB32(buf) == VC1_CODE_ENDOFSEQ)) {
/* special case for last picture */
@@ -605,13 +643,22 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
*got_frame = 1;
}
- return 0;
+ return buf_size;
+ }
+
+ if (s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) {
+ if (v->profile < PROFILE_ADVANCED)
+ avctx->pix_fmt = AV_PIX_FMT_VDPAU_WMV3;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_VDPAU_VC1;
}
//for advanced profile we may need to parse and unescape data
if (avctx->codec_id == AV_CODEC_ID_VC1 || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) {
int buf_size2 = 0;
buf2 = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!buf2)
+ return AVERROR(ENOMEM);
if (IS_MARKER(AV_RB32(buf))) { /* frame starts with marker and needs to be parsed */
const uint8_t *start, *end, *next;
@@ -624,13 +671,17 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
if (size <= 0) continue;
switch (AV_RB32(start)) {
case VC1_CODE_FRAME:
- if (avctx->hwaccel)
+ if (avctx->hwaccel ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
buf_start = start;
buf_size2 = vc1_unescape_buffer(start + 4, size, buf2);
break;
case VC1_CODE_FIELD: {
int buf_size3;
- tmp = av_realloc(slices, sizeof(*slices) * (n_slices+1));
+ if (avctx->hwaccel ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+ buf_start_second_field = start;
+ tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1));
if (!tmp)
goto err;
slices = tmp;
@@ -643,7 +694,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
buf_size3 << 3);
/* assuming that the field marker is at the exact middle,
hope it's correct */
- slices[n_slices].mby_start = s->mb_height >> 1;
+ slices[n_slices].mby_start = s->mb_height + 1 >> 1;
n_slices1 = n_slices - 1; // index of the last slice of the first field
n_slices++;
break;
@@ -655,7 +706,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
break;
case VC1_CODE_SLICE: {
int buf_size3;
- tmp = av_realloc(slices, sizeof(*slices) * (n_slices+1));
+ tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1));
if (!tmp)
goto err;
slices = tmp;
@@ -681,7 +732,10 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
av_log(avctx, AV_LOG_ERROR, "Error in WVC1 interlaced frame\n");
goto err;
} else { // found field marker, unescape second field
- tmp = av_realloc(slices, sizeof(*slices) * (n_slices+1));
+ if (avctx->hwaccel ||
+ s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
+ buf_start_second_field = divider;
+ tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1));
if (!tmp)
goto err;
slices = tmp;
@@ -691,7 +745,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
buf_size3 = vc1_unescape_buffer(divider + 4, buf + buf_size - divider - 4, slices[n_slices].buf);
init_get_bits(&slices[n_slices].gb, slices[n_slices].buf,
buf_size3 << 3);
- slices[n_slices].mby_start = s->mb_height >> 1;
+ slices[n_slices].mby_start = s->mb_height + 1 >> 1;
n_slices1 = n_slices - 1;
n_slices++;
}
@@ -738,6 +792,8 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
s->low_delay = !avctx->has_b_frames || v->res_sprite;
if (v->profile == PROFILE_ADVANCED) {
+ if(avctx->coded_width<=1 || avctx->coded_height<=1)
+ goto err;
s->h_edge_pos = avctx->coded_width;
s->v_edge_pos = avctx->coded_height;
}
@@ -757,18 +813,27 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
}
v->first_pic_header_flag = 0;
+ if (avctx->debug & FF_DEBUG_PICT_INFO)
+ av_log(v->s.avctx, AV_LOG_DEBUG, "pict_type: %c\n", av_get_picture_type_char(s->pict_type));
+
if ((avctx->codec_id == AV_CODEC_ID_WMV3IMAGE || avctx->codec_id == AV_CODEC_ID_VC1IMAGE)
&& s->pict_type != AV_PICTURE_TYPE_I) {
av_log(v->s.avctx, AV_LOG_ERROR, "Sprite decoder: expected I-frame\n");
goto err;
}
+ if ((s->mb_height >> v->field_mode) == 0) {
+ av_log(v->s.avctx, AV_LOG_ERROR, "image too short\n");
+ goto err;
+ }
+
// for skipping the frame
s->current_picture.f->pict_type = s->pict_type;
s->current_picture.f->key_frame = s->pict_type == AV_PICTURE_TYPE_I;
/* skip B-frames if we don't have reference frames */
if (!s->last_picture_ptr && (s->pict_type == AV_PICTURE_TYPE_B || s->droppable)) {
+ av_log(v->s.avctx, AV_LOG_DEBUG, "Skipping B frame without reference frames\n");
goto end;
}
if ((avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) ||
@@ -788,6 +853,10 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
goto err;
}
+ v->s.current_picture_ptr->field_picture = v->field_mode;
+ v->s.current_picture_ptr->f->interlaced_frame = (v->fcm != PROGRESSIVE);
+ v->s.current_picture_ptr->f->top_field_first = v->tff;
+
// process pulldown flags
s->current_picture_ptr->f->repeat_pict = 0;
// Pulldown flags are only valid when 'broadcast' has been set.
@@ -803,13 +872,51 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
s->me.qpel_put = s->qdsp.put_qpel_pixels_tab;
s->me.qpel_avg = s->qdsp.avg_qpel_pixels_tab;
- if (avctx->hwaccel) {
- if (avctx->hwaccel->start_frame(avctx, buf, buf_size) < 0)
- goto err;
- if (avctx->hwaccel->decode_slice(avctx, buf_start, (buf + buf_size) - buf_start) < 0)
- goto err;
- if (avctx->hwaccel->end_frame(avctx) < 0)
- goto err;
+ if ((CONFIG_VC1_VDPAU_DECODER)
+ &&s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU) {
+ if (v->field_mode && buf_start_second_field) {
+ ff_vdpau_vc1_decode_picture(s, buf_start, buf_start_second_field - buf_start);
+ ff_vdpau_vc1_decode_picture(s, buf_start_second_field, (buf + buf_size) - buf_start_second_field);
+ } else {
+ ff_vdpau_vc1_decode_picture(s, buf_start, (buf + buf_size) - buf_start);
+ }
+ } else if (avctx->hwaccel) {
+ if (v->field_mode && buf_start_second_field) {
+ // decode first field
+ s->picture_structure = PICT_BOTTOM_FIELD - v->tff;
+ if (avctx->hwaccel->start_frame(avctx, buf_start, buf_start_second_field - buf_start) < 0)
+ goto err;
+ if (avctx->hwaccel->decode_slice(avctx, buf_start, buf_start_second_field - buf_start) < 0)
+ goto err;
+ if (avctx->hwaccel->end_frame(avctx) < 0)
+ goto err;
+
+ // decode second field
+ s->gb = slices[n_slices1 + 1].gb;
+ s->picture_structure = PICT_TOP_FIELD + v->tff;
+ v->second_field = 1;
+ v->pic_header_flag = 0;
+ if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "parsing header for second field failed");
+ goto err;
+ }
+ v->s.current_picture_ptr->f->pict_type = v->s.pict_type;
+
+ if (avctx->hwaccel->start_frame(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field) < 0)
+ goto err;
+ if (avctx->hwaccel->decode_slice(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field) < 0)
+ goto err;
+ if (avctx->hwaccel->end_frame(avctx) < 0)
+ goto err;
+ } else {
+ s->picture_structure = PICT_FRAME;
+ if (avctx->hwaccel->start_frame(avctx, buf_start, (buf + buf_size) - buf_start) < 0)
+ goto err;
+ if (avctx->hwaccel->decode_slice(avctx, buf_start, (buf + buf_size) - buf_start) < 0)
+ goto err;
+ if (avctx->hwaccel->end_frame(avctx) < 0)
+ goto err;
+ }
} else {
int header_ret = 0;
@@ -826,10 +933,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
}
mb_height = s->mb_height >> v->field_mode;
- if (!mb_height) {
- av_log(v->s.avctx, AV_LOG_ERROR, "Invalid mb_height.\n");
- goto err;
- }
+ av_assert0 (mb_height > 0);
for (i = 0; i <= n_slices; i++) {
if (i > 0 && slices[i - 1].mby_start >= mb_height) {
@@ -840,7 +944,8 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
continue;
}
v->second_field = 1;
- v->blocks_off = s->mb_width * s->mb_height << 1;
+ av_assert0((s->mb_height & 1) == 0);
+ v->blocks_off = s->b8_stride * (s->mb_height&~1);
v->mb_off = s->mb_stride * s->mb_height >> 1;
} else {
v->second_field = 0;
@@ -871,8 +976,21 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
s->start_mb_y = (i == 0) ? 0 : FFMAX(0, slices[i-1].mby_start % mb_height);
if (!v->field_mode || v->second_field)
s->end_mb_y = (i == n_slices ) ? mb_height : FFMIN(mb_height, slices[i].mby_start % mb_height);
- else
+ else {
+ if (i >= n_slices) {
+ av_log(v->s.avctx, AV_LOG_ERROR, "first field slice count too large\n");
+ continue;
+ }
s->end_mb_y = (i <= n_slices1 + 1) ? mb_height : FFMIN(mb_height, slices[i].mby_start % mb_height);
+ }
+ if (s->end_mb_y <= s->start_mb_y) {
+ av_log(v->s.avctx, AV_LOG_ERROR, "end mb y %d %d invalid\n", s->end_mb_y, s->start_mb_y);
+ continue;
+ }
+ if (!v->p_frame_skipped && s->pict_type != AV_PICTURE_TYPE_I && !v->cbpcy_vlc) {
+ av_log(v->s.avctx, AV_LOG_ERROR, "missing cbpcy_vlc\n");
+ continue;
+ }
ff_vc1_decode_blocks(v);
if (i != n_slices)
s->gb = slices[i].gb;
@@ -893,6 +1011,8 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data,
get_bits_count(&s->gb), s->gb.size_in_bits);
// if (get_bits_count(&s->gb) > buf_size * 8)
// return -1;
+ if(s->er.error_occurred && s->pict_type == AV_PICTURE_TYPE_B)
+ goto err;
if (!v->field_mode)
ff_er_frame_end(&s->er);
}
@@ -916,12 +1036,12 @@ image:
if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
if ((ret = av_frame_ref(pict, s->current_picture_ptr->f)) < 0)
goto err;
- ff_print_debug_info(s, s->current_picture_ptr);
+ ff_print_debug_info(s, s->current_picture_ptr, pict);
*got_frame = 1;
} else if (s->last_picture_ptr) {
if ((ret = av_frame_ref(pict, s->last_picture_ptr->f)) < 0)
goto err;
- ff_print_debug_info(s, s->last_picture_ptr);
+ ff_print_debug_info(s, s->last_picture_ptr, pict);
*got_frame = 1;
}
}
@@ -999,6 +1119,38 @@ AVCodec ff_wmv3_decoder = {
};
#endif
+#if CONFIG_WMV3_VDPAU_DECODER
+AVCodec ff_wmv3_vdpau_decoder = {
+ .name = "wmv3_vdpau",
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 VDPAU"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_WMV3,
+ .priv_data_size = sizeof(VC1Context),
+ .init = vc1_decode_init,
+ .close = ff_vc1_decode_end,
+ .decode = vc1_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_WMV3, AV_PIX_FMT_NONE },
+ .profiles = NULL_IF_CONFIG_SMALL(profiles)
+};
+#endif
+
+#if CONFIG_VC1_VDPAU_DECODER
+AVCodec ff_vc1_vdpau_decoder = {
+ .name = "vc1_vdpau",
+ .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1 VDPAU"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_VC1,
+ .priv_data_size = sizeof(VC1Context),
+ .init = vc1_decode_init,
+ .close = ff_vc1_decode_end,
+ .decode = vc1_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_HWACCEL_VDPAU,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_VC1, AV_PIX_FMT_NONE },
+ .profiles = NULL_IF_CONFIG_SMALL(profiles)
+};
+#endif
+
#if CONFIG_WMV3IMAGE_DECODER
AVCodec ff_wmv3image_decoder = {
.name = "wmv3image",
diff --git a/libavcodec/vc1dsp.c b/libavcodec/vc1dsp.c
index a193dd704d..a16c8d512c 100644
--- a/libavcodec/vc1dsp.c
+++ b/libavcodec/vc1dsp.c
@@ -2,20 +2,20 @@
* VC-1 and WMV3 decoder - DSP functions
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,9 +25,12 @@
*
*/
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "h264chroma.h"
#include "qpeldsp.h"
+#include "rnd_avg.h"
#include "vc1dsp.h"
#include "startcode.h"
@@ -582,10 +585,10 @@ static av_always_inline int vc1_mspel_filter(const uint8_t *src, int stride,
}
/* Function used to do motion compensation with bicubic interpolation */
-#define VC1_MSPEL_MC(OP, OPNAME) \
+#define VC1_MSPEL_MC(OP, OP4, OPNAME) \
static av_always_inline void OPNAME ## vc1_mspel_mc(uint8_t *dst, \
const uint8_t *src, \
- int stride, \
+ ptrdiff_t stride, \
int hmode, \
int vmode, \
int rnd) \
@@ -640,13 +643,93 @@ static av_always_inline void OPNAME ## vc1_mspel_mc(uint8_t *dst, \
dst += stride; \
src += stride; \
} \
+}\
+static av_always_inline void OPNAME ## vc1_mspel_mc_16(uint8_t *dst, \
+ const uint8_t *src, \
+ ptrdiff_t stride, \
+ int hmode, \
+ int vmode, \
+ int rnd) \
+{ \
+ int i, j; \
+ \
+ if (vmode) { /* Horizontal filter to apply */ \
+ int r; \
+ \
+ if (hmode) { /* Vertical filter to apply, output to tmp */ \
+ static const int shift_value[] = { 0, 5, 1, 5 }; \
+ int shift = (shift_value[hmode] + shift_value[vmode]) >> 1; \
+ int16_t tmp[19 * 16], *tptr = tmp; \
+ \
+ r = (1 << (shift - 1)) + rnd - 1; \
+ \
+ src -= 1; \
+ for (j = 0; j < 16; j++) { \
+ for (i = 0; i < 19; i++) \
+ tptr[i] = (vc1_mspel_ver_filter_16bits(src + i, stride, vmode) + r) >> shift; \
+ src += stride; \
+ tptr += 19; \
+ } \
+ \
+ r = 64 - rnd; \
+ tptr = tmp + 1; \
+ for (j = 0; j < 16; j++) { \
+ for (i = 0; i < 16; i++) \
+ OP(dst[i], (vc1_mspel_hor_filter_16bits(tptr + i, 1, hmode) + r) >> 7); \
+ dst += stride; \
+ tptr += 19; \
+ } \
+ \
+ return; \
+ } else { /* No horizontal filter, output 8 lines to dst */ \
+ r = 1 - rnd; \
+ \
+ for (j = 0; j < 16; j++) { \
+ for (i = 0; i < 16; i++) \
+ OP(dst[i], vc1_mspel_filter(src + i, stride, vmode, r)); \
+ src += stride; \
+ dst += stride; \
+ } \
+ return; \
+ } \
+ } \
+ \
+ /* Horizontal mode with no vertical mode */ \
+ for (j = 0; j < 16; j++) { \
+ for (i = 0; i < 16; i++) \
+ OP(dst[i], vc1_mspel_filter(src + i, 1, hmode, rnd)); \
+ dst += stride; \
+ src += stride; \
+ } \
+}\
+static void OPNAME ## pixels8x8_c(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int rnd){\
+ int i;\
+ for(i=0; i<8; i++){\
+ OP4(*(uint32_t*)(block ), AV_RN32(pixels ));\
+ OP4(*(uint32_t*)(block+4), AV_RN32(pixels+4));\
+ pixels+=line_size;\
+ block +=line_size;\
+ }\
+}\
+static void OPNAME ## pixels16x16_c(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int rnd){\
+ int i;\
+ for(i=0; i<16; i++){\
+ OP4(*(uint32_t*)(block ), AV_RN32(pixels ));\
+ OP4(*(uint32_t*)(block+ 4), AV_RN32(pixels+ 4));\
+ OP4(*(uint32_t*)(block+ 8), AV_RN32(pixels+ 8));\
+ OP4(*(uint32_t*)(block+12), AV_RN32(pixels+12));\
+ pixels+=line_size;\
+ block +=line_size;\
+ }\
}
-#define op_put(a, b) a = av_clip_uint8(b)
-#define op_avg(a, b) a = (a + av_clip_uint8(b) + 1) >> 1
+#define op_put(a, b) (a) = av_clip_uint8(b)
+#define op_avg(a, b) (a) = ((a) + av_clip_uint8(b) + 1) >> 1
+#define op4_avg(a, b) (a) = rnd_avg32(a, b)
+#define op4_put(a, b) (a) = (b)
-VC1_MSPEL_MC(op_put, put_)
-VC1_MSPEL_MC(op_avg, avg_)
+VC1_MSPEL_MC(op_put, op4_put, put_)
+VC1_MSPEL_MC(op_avg, op4_avg, avg_)
/* pixel functions - really are entry points to vc1_mspel_mc */
@@ -662,6 +745,18 @@ static void avg_vc1_mspel_mc ## a ## b ## _c(uint8_t *dst, \
ptrdiff_t stride, int rnd) \
{ \
avg_vc1_mspel_mc(dst, src, stride, a, b, rnd); \
+} \
+static void put_vc1_mspel_mc ## a ## b ## _16_c(uint8_t *dst, \
+ const uint8_t *src, \
+ ptrdiff_t stride, int rnd) \
+{ \
+ put_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
+} \
+static void avg_vc1_mspel_mc ## a ## b ## _16_c(uint8_t *dst, \
+ const uint8_t *src, \
+ ptrdiff_t stride, int rnd) \
+{ \
+ avg_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
}
PUT_VC1_MSPEL(1, 0)
@@ -683,19 +778,6 @@ PUT_VC1_MSPEL(1, 3)
PUT_VC1_MSPEL(2, 3)
PUT_VC1_MSPEL(3, 3)
-
-static void put_vc1_mspel_mc00_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd)
-{
- ff_put_pixels8x8_c(dst, src, stride);
-}
-
-static void avg_vc1_mspel_mc00_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride, int rnd)
-{
- ff_avg_pixels8x8_c(dst, src, stride);
-}
-
#define chroma_mc(a) \
((A * src[a] + B * src[a + 1] + \
C * src[stride + a] + D * src[stride + a + 1] + 32 - 4) >> 6)
@@ -709,7 +791,7 @@ static void put_no_rnd_vc1_chroma_mc8_c(uint8_t *dst /* align 8 */,
const int D = (x) * (y);
int i;
- assert(x < 8 && y < 8 && x >= 0 && y >= 0);
+ av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = chroma_mc(0);
@@ -734,7 +816,7 @@ static void put_no_rnd_vc1_chroma_mc4_c(uint8_t *dst, uint8_t *src,
const int D = (x) * (y);
int i;
- assert(x < 8 && y < 8 && x >= 0 && y >= 0);
+ av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = chroma_mc(0);
@@ -757,7 +839,7 @@ static void avg_no_rnd_vc1_chroma_mc8_c(uint8_t *dst /* align 8 */,
const int D = (x) * (y);
int i;
- assert(x < 8 && y < 8 && x >= 0 && y >= 0);
+ av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = avg2(dst[0], chroma_mc(0));
@@ -783,7 +865,7 @@ static void avg_no_rnd_vc1_chroma_mc4_c(uint8_t *dst /* align 8 */,
const int D = ( x) * ( y);
int i;
- assert(x < 8 && y < 8 && x >= 0 && y >= 0);
+ av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0);
for (i = 0; i < h; i++) {
dst[0] = avg2(dst[0], chroma_mc(0));
@@ -878,6 +960,11 @@ static void sprite_v_double_twoscale_c(uint8_t *dst,
}
#endif /* CONFIG_WMV3IMAGE_DECODER || CONFIG_VC1IMAGE_DECODER */
+#define FN_ASSIGN(X, Y) \
+ dsp->put_vc1_mspel_pixels_tab[1][X+4*Y] = put_vc1_mspel_mc##X##Y##_c; \
+ dsp->put_vc1_mspel_pixels_tab[0][X+4*Y] = put_vc1_mspel_mc##X##Y##_16_c; \
+ dsp->avg_vc1_mspel_pixels_tab[1][X+4*Y] = avg_vc1_mspel_mc##X##Y##_c; \
+ dsp->avg_vc1_mspel_pixels_tab[0][X+4*Y] = avg_vc1_mspel_mc##X##Y##_16_c
av_cold void ff_vc1dsp_init(VC1DSPContext *dsp)
{
@@ -902,39 +989,28 @@ av_cold void ff_vc1dsp_init(VC1DSPContext *dsp)
dsp->vc1_v_loop_filter16 = vc1_v_loop_filter16_c;
dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_c;
- dsp->put_vc1_mspel_pixels_tab[0] = put_vc1_mspel_mc00_c;
- dsp->put_vc1_mspel_pixels_tab[1] = put_vc1_mspel_mc10_c;
- dsp->put_vc1_mspel_pixels_tab[2] = put_vc1_mspel_mc20_c;
- dsp->put_vc1_mspel_pixels_tab[3] = put_vc1_mspel_mc30_c;
- dsp->put_vc1_mspel_pixels_tab[4] = put_vc1_mspel_mc01_c;
- dsp->put_vc1_mspel_pixels_tab[5] = put_vc1_mspel_mc11_c;
- dsp->put_vc1_mspel_pixels_tab[6] = put_vc1_mspel_mc21_c;
- dsp->put_vc1_mspel_pixels_tab[7] = put_vc1_mspel_mc31_c;
- dsp->put_vc1_mspel_pixels_tab[8] = put_vc1_mspel_mc02_c;
- dsp->put_vc1_mspel_pixels_tab[9] = put_vc1_mspel_mc12_c;
- dsp->put_vc1_mspel_pixels_tab[10] = put_vc1_mspel_mc22_c;
- dsp->put_vc1_mspel_pixels_tab[11] = put_vc1_mspel_mc32_c;
- dsp->put_vc1_mspel_pixels_tab[12] = put_vc1_mspel_mc03_c;
- dsp->put_vc1_mspel_pixels_tab[13] = put_vc1_mspel_mc13_c;
- dsp->put_vc1_mspel_pixels_tab[14] = put_vc1_mspel_mc23_c;
- dsp->put_vc1_mspel_pixels_tab[15] = put_vc1_mspel_mc33_c;
-
- dsp->avg_vc1_mspel_pixels_tab[0] = avg_vc1_mspel_mc00_c;
- dsp->avg_vc1_mspel_pixels_tab[1] = avg_vc1_mspel_mc10_c;
- dsp->avg_vc1_mspel_pixels_tab[2] = avg_vc1_mspel_mc20_c;
- dsp->avg_vc1_mspel_pixels_tab[3] = avg_vc1_mspel_mc30_c;
- dsp->avg_vc1_mspel_pixels_tab[4] = avg_vc1_mspel_mc01_c;
- dsp->avg_vc1_mspel_pixels_tab[5] = avg_vc1_mspel_mc11_c;
- dsp->avg_vc1_mspel_pixels_tab[6] = avg_vc1_mspel_mc21_c;
- dsp->avg_vc1_mspel_pixels_tab[7] = avg_vc1_mspel_mc31_c;
- dsp->avg_vc1_mspel_pixels_tab[8] = avg_vc1_mspel_mc02_c;
- dsp->avg_vc1_mspel_pixels_tab[9] = avg_vc1_mspel_mc12_c;
- dsp->avg_vc1_mspel_pixels_tab[10] = avg_vc1_mspel_mc22_c;
- dsp->avg_vc1_mspel_pixels_tab[11] = avg_vc1_mspel_mc32_c;
- dsp->avg_vc1_mspel_pixels_tab[12] = avg_vc1_mspel_mc03_c;
- dsp->avg_vc1_mspel_pixels_tab[13] = avg_vc1_mspel_mc13_c;
- dsp->avg_vc1_mspel_pixels_tab[14] = avg_vc1_mspel_mc23_c;
- dsp->avg_vc1_mspel_pixels_tab[15] = avg_vc1_mspel_mc33_c;
+ dsp->put_vc1_mspel_pixels_tab[0][0] = put_pixels16x16_c;
+ dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_pixels16x16_c;
+ dsp->put_vc1_mspel_pixels_tab[1][0] = put_pixels8x8_c;
+ dsp->avg_vc1_mspel_pixels_tab[1][0] = avg_pixels8x8_c;
+ FN_ASSIGN(0, 1);
+ FN_ASSIGN(0, 2);
+ FN_ASSIGN(0, 3);
+
+ FN_ASSIGN(1, 0);
+ FN_ASSIGN(1, 1);
+ FN_ASSIGN(1, 2);
+ FN_ASSIGN(1, 3);
+
+ FN_ASSIGN(2, 0);
+ FN_ASSIGN(2, 1);
+ FN_ASSIGN(2, 2);
+ FN_ASSIGN(2, 3);
+
+ FN_ASSIGN(3, 0);
+ FN_ASSIGN(3, 1);
+ FN_ASSIGN(3, 2);
+ FN_ASSIGN(3, 3);
dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = put_no_rnd_vc1_chroma_mc8_c;
dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = avg_no_rnd_vc1_chroma_mc8_c;
diff --git a/libavcodec/vc1dsp.h b/libavcodec/vc1dsp.h
index 682f682144..e2f75ac7dc 100644
--- a/libavcodec/vc1dsp.h
+++ b/libavcodec/vc1dsp.h
@@ -2,20 +2,20 @@
* VC-1 and WMV3 decoder - DSP functions
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,8 @@
#include "hpeldsp.h"
#include "h264chroma.h"
+typedef void (*vc1op_pixels_func)(uint8_t *block/*align width (8 or 16)*/, const uint8_t *pixels/*align 1*/, ptrdiff_t line_size, int h);
+
typedef struct VC1DSPContext {
/* vc1 functions */
void (*vc1_inv_trans_8x8)(int16_t *b);
@@ -55,8 +57,8 @@ typedef struct VC1DSPContext {
/* put 8x8 block with bicubic interpolation and quarterpel precision
* last argument is actually round value instead of height
*/
- op_pixels_func put_vc1_mspel_pixels_tab[16];
- op_pixels_func avg_vc1_mspel_pixels_tab[16];
+ vc1op_pixels_func put_vc1_mspel_pixels_tab[2][16];
+ vc1op_pixels_func avg_vc1_mspel_pixels_tab[2][16];
/* This is really one func used in VC-1 decoding */
h264_chroma_mc_func put_no_rnd_vc1_chroma_pixels_tab[3];
diff --git a/libavcodec/vcr1.c b/libavcodec/vcr1.c
index 161704f545..f8281ea05a 100644
--- a/libavcodec/vcr1.c
+++ b/libavcodec/vcr1.c
@@ -2,20 +2,20 @@
* ATI VCR1 codec
* Copyright (c) 2003 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "avcodec.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/internal.h"
typedef struct VCR1Context {
@@ -37,8 +38,8 @@ static av_cold int vcr1_decode_init(AVCodecContext *avctx)
{
avctx->pix_fmt = AV_PIX_FMT_YUV410P;
- if (avctx->width & 7) {
- av_log(avctx, AV_LOG_ERROR, "Width %d is not divisble by 8.\n", avctx->width);
+ if (avctx->width % 8 || avctx->height%4) {
+ avpriv_request_sample(avctx, "odd dimensions (%d x %d) support", avctx->width, avctx->height);
return AVERROR_INVALIDDATA;
}
@@ -48,27 +49,25 @@ static av_cold int vcr1_decode_init(AVCodecContext *avctx)
static int vcr1_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
- const uint8_t *buf = avpkt->data;
- int buf_size = avpkt->size;
VCR1Context *const a = avctx->priv_data;
AVFrame *const p = data;
- const uint8_t *bytestream = buf;
+ const uint8_t *bytestream = avpkt->data;
+ const uint8_t *bytestream_end = bytestream + avpkt->size;
int i, x, y, ret;
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if(avpkt->size < 32 + avctx->height + avctx->width*avctx->height*5/8){
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data. %d < %d\n", avpkt->size , 32 + avctx->height + avctx->width*avctx->height*5/8);
+ return AVERROR(EINVAL);
}
+
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
+ return ret;
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
- if (buf_size < 32)
- goto packet_small;
-
for (i = 0; i < 16; i++) {
a->delta[i] = *bytestream++;
bytestream++;
- buf_size--;
}
for (y = 0; y < avctx->height; y++) {
@@ -79,12 +78,10 @@ static int vcr1_decode_frame(AVCodecContext *avctx, void *data,
uint8_t *cb = &p->data[1][(y >> 2) * p->linesize[1]];
uint8_t *cr = &p->data[2][(y >> 2) * p->linesize[2]];
- if (buf_size < 4 + avctx->width)
- goto packet_small;
+ av_assert0 (bytestream_end - bytestream >= 4 + avctx->width);
for (i = 0; i < 4; i++)
a->offset[i] = *bytestream++;
- buf_size -= 4;
offset = a->offset[0] - a->delta[bytestream[2] & 0xF];
for (x = 0; x < avctx->width; x += 4) {
@@ -98,11 +95,9 @@ static int vcr1_decode_frame(AVCodecContext *avctx, void *data,
*cr++ = bytestream[1];
bytestream += 4;
- buf_size -= 4;
}
} else {
- if (buf_size < avctx->width / 2)
- goto packet_small;
+ av_assert0 (bytestream_end - bytestream >= avctx->width / 2);
offset = a->offset[y & 3] - a->delta[bytestream[2] & 0xF];
@@ -117,17 +112,13 @@ static int vcr1_decode_frame(AVCodecContext *avctx, void *data,
luma[7] = offset += a->delta[bytestream[1] >> 4];
luma += 8;
bytestream += 4;
- buf_size -= 4;
}
}
}
*got_frame = 1;
- return buf_size;
-packet_small:
- av_log(avctx, AV_LOG_ERROR, "Input packet too small.\n");
- return AVERROR_INVALIDDATA;
+ return bytestream - avpkt->data;
}
AVCodec ff_vcr1_decoder = {
diff --git a/libavcodec/vda.c b/libavcodec/vda.c
index eb4b9982cb..5867cae120 100644
--- a/libavcodec/vda.c
+++ b/libavcodec/vda.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vda.h b/libavcodec/vda.h
index 5e7228c94e..bde14e31d7 100644
--- a/libavcodec/vda.h
+++ b/libavcodec/vda.h
@@ -3,20 +3,20 @@
*
* copyright (c) 2011 Sebastien Zwickert
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,6 @@
*/
#include "libavcodec/avcodec.h"
-#include "libavcodec/version.h"
#include <stdint.h>
@@ -42,6 +41,14 @@
#include <VideoDecodeAcceleration/VDADecoder.h>
#undef Picture
+#include "libavcodec/version.h"
+
+// extra flags not defined in VDADecoder.h
+enum {
+ kVDADecodeInfo_Asynchronous = 1UL << 0,
+ kVDADecodeInfo_FrameDropped = 1UL << 1
+};
+
/**
* @defgroup lavc_codec_hwaccel_vda VDA
* @ingroup lavc_codec_hwaccel
@@ -51,7 +58,7 @@
/**
* This structure is used to provide the necessary configurations and data
- * to the VDA Libav HWAccel implementation.
+ * to the VDA FFmpeg HWAccel implementation.
*
* The application must make it available as AVCodecContext.hwaccel_context.
*/
@@ -126,6 +133,17 @@ struct vda_context {
* unused
*/
int priv_allocated_size;
+
+ /**
+ * Use av_buffer to manage buffer.
+ * When the flag is set, the CVPixelBuffers returned by the decoder will
+ * be released automatically, so you have to retain them if necessary.
+ * Not setting this flag may cause memory leak.
+ *
+ * encoding: unused
+ * decoding: Set by user.
+ */
+ int use_ref_buffer;
};
/** Create the video decoder. */
diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c
index 0692f60809..4d2274d649 100644
--- a/libavcodec/vda_h264.c
+++ b/libavcodec/vda_h264.c
@@ -1,33 +1,37 @@
/*
- * VDA H.264 hardware acceleration
+ * VDA H264 HW acceleration.
*
* copyright (c) 2011 Sebastien Zwickert
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <CoreFoundation/CFDictionary.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CFData.h>
-#include <CoreFoundation/CFString.h>
+#include "vda.h"
#include "libavutil/avutil.h"
#include "h264.h"
+
+struct vda_buffer {
+ CVPixelBufferRef cv_buffer;
+};
#include "internal.h"
-#include "vda.h"
#include "vda_internal.h"
typedef struct VDAContext {
@@ -43,7 +47,7 @@ typedef struct VDAContext {
CVImageBufferRef frame;
} VDAContext;
-/* Decoder callback that adds the VDA frame to the queue in display order. */
+/* Decoder callback that adds the vda frame to the queue in display order. */
static void vda_decoder_callback(void *vda_hw_ctx,
CFDictionaryRef user_info,
OSStatus status,
@@ -52,6 +56,9 @@ static void vda_decoder_callback(void *vda_hw_ctx,
{
struct vda_context *vda_ctx = vda_hw_ctx;
+ if (infoFlags & kVDADecodeInfo_FrameDropped)
+ vda_ctx->cv_buffer = NULL;
+
if (!image_buffer)
return;
@@ -87,7 +94,7 @@ static int vda_old_h264_start_frame(AVCodecContext *avctx,
av_unused uint32_t size)
{
VDAContext *vda = avctx->internal->hwaccel_priv_data;
- struct vda_context *vda_ctx = avctx->hwaccel_context;
+ struct vda_context *vda_ctx = avctx->hwaccel_context;
if (!vda_ctx->decoder)
return -1;
@@ -101,8 +108,8 @@ static int vda_old_h264_decode_slice(AVCodecContext *avctx,
const uint8_t *buffer,
uint32_t size)
{
- VDAContext *vda = avctx->internal->hwaccel_priv_data;
- struct vda_context *vda_ctx = avctx->hwaccel_context;
+ VDAContext *vda = avctx->internal->hwaccel_priv_data;
+ struct vda_context *vda_ctx = avctx->hwaccel_context;
void *tmp;
if (!vda_ctx->decoder)
@@ -124,12 +131,21 @@ static int vda_old_h264_decode_slice(AVCodecContext *avctx,
return 0;
}
+static void vda_h264_release_buffer(void *opaque, uint8_t *data)
+{
+ struct vda_buffer *context = opaque;
+ CVPixelBufferRelease(context->cv_buffer);
+ av_free(context);
+}
+
static int vda_old_h264_end_frame(AVCodecContext *avctx)
{
H264Context *h = avctx->priv_data;
VDAContext *vda = avctx->internal->hwaccel_priv_data;
struct vda_context *vda_ctx = avctx->hwaccel_context;
AVFrame *frame = h->cur_pic_ptr->f;
+ struct vda_buffer *context;
+ AVBufferRef *buffer;
int status;
if (!vda_ctx->decoder || !vda->bitstream)
@@ -141,6 +157,20 @@ static int vda_old_h264_end_frame(AVCodecContext *avctx)
if (status)
av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status);
+ if (!vda_ctx->use_ref_buffer || status)
+ return status;
+
+ context = av_mallocz(sizeof(*context));
+ buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0);
+ if (!context || !buffer) {
+ CVPixelBufferRelease(vda_ctx->cv_buffer);
+ av_free(context);
+ return -1;
+ }
+
+ context->cv_buffer = vda_ctx->cv_buffer;
+ frame->buf[3] = buffer;
+
return status;
}
@@ -148,7 +178,7 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx,
uint8_t *extradata,
int extradata_size)
{
- OSStatus status = kVDADecoderNoErr;
+ OSStatus status;
CFNumberRef height;
CFNumberRef width;
CFNumberRef format;
@@ -158,7 +188,10 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx,
CFMutableDictionaryRef io_surface_properties;
CFNumberRef cv_pix_fmt;
- /* Each VCL NAL in the bistream sent to the decoder
+ vda_ctx->priv_bitstream = NULL;
+ vda_ctx->priv_allocated_size = 0;
+
+ /* Each VCL NAL in the bitstream sent to the decoder
* is preceded by a 4 bytes length header.
* Change the avcC atom header if needed, to signal headers of 4 bytes. */
if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) {
@@ -200,9 +233,9 @@ int ff_vda_create_decoder(struct vda_context *vda_ctx,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
- cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault,
- kCFNumberSInt32Type,
- &vda_ctx->cv_pix_fmt_type);
+ cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type,
+ &vda_ctx->cv_pix_fmt_type);
CFDictionarySetValue(buffer_attributes,
kCVPixelBufferPixelFormatTypeKey,
cv_pix_fmt);
@@ -241,9 +274,11 @@ int ff_vda_destroy_decoder(struct vda_context *vda_ctx)
static int vda_h264_uninit(AVCodecContext *avctx)
{
VDAContext *vda = avctx->internal->hwaccel_priv_data;
- av_freep(&vda->bitstream);
- if (vda->frame)
- CVPixelBufferRelease(vda->frame);
+ if (vda) {
+ av_freep(&vda->bitstream);
+ if (vda->frame)
+ CVPixelBufferRelease(vda->frame);
+ }
return 0;
}
@@ -285,9 +320,20 @@ static int vda_h264_start_frame(AVCodecContext *avctx,
uint32_t size)
{
VDAContext *vda = avctx->internal->hwaccel_priv_data;
-
- vda->bitstream_size = 0;
-
+ H264Context *h = avctx->priv_data;
+
+ if (h->is_avc == 1) {
+ void *tmp;
+ vda->bitstream_size = 0;
+ tmp = av_fast_realloc(vda->bitstream,
+ &vda->allocated_size,
+ size);
+ vda->bitstream = tmp;
+ memcpy(vda->bitstream, buffer, size);
+ vda->bitstream_size = size;
+ } else {
+ vda->bitstream_size = 0;
+ }
return 0;
}
@@ -296,8 +342,12 @@ static int vda_h264_decode_slice(AVCodecContext *avctx,
uint32_t size)
{
VDAContext *vda = avctx->internal->hwaccel_priv_data;
+ H264Context *h = avctx->priv_data;
void *tmp;
+ if (h->is_avc == 1)
+ return 0;
+
tmp = av_fast_realloc(vda->bitstream,
&vda->allocated_size,
vda->bitstream_size + size + 4);
@@ -384,7 +434,7 @@ int ff_vda_default_init(AVCodecContext *avctx)
// kCVPixelFormatType_420YpCbCr8Planar;
- /* Each VCL NAL in the bistream sent to the decoder
+ /* Each VCL NAL in the bitstream sent to the decoder
* is preceded by a 4 bytes length header.
* Change the avcC atom header if needed, to signal headers of 4 bytes. */
if (avctx->extradata_size >= 4 && (avctx->extradata[4] & 0x03) != 0x03) {
diff --git a/libavcodec/vda_h264_dec.c b/libavcodec/vda_h264_dec.c
new file mode 100644
index 0000000000..c00e7e4e15
--- /dev/null
+++ b/libavcodec/vda_h264_dec.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2012, Xidorn Quan
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * H.264 decoder via VDA
+ * @author Xidorn Quan <quanxunzhen@gmail.com>
+ */
+
+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "vda.h"
+#include "h264.h"
+#include "avcodec.h"
+
+#ifndef kCFCoreFoundationVersionNumber10_7
+#define kCFCoreFoundationVersionNumber10_7 635.00
+#endif
+
+extern AVCodec ff_h264_decoder, ff_h264_vda_decoder;
+
+static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = {
+ AV_PIX_FMT_UYVY422,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_NONE
+};
+
+static const enum AVPixelFormat vda_pixfmts[] = {
+ AV_PIX_FMT_UYVY422,
+ AV_PIX_FMT_YUYV422,
+ AV_PIX_FMT_NV12,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_NONE
+};
+
+typedef struct {
+ H264Context h264ctx;
+ int h264_initialized;
+ struct vda_context vda_ctx;
+ enum AVPixelFormat pix_fmt;
+
+ /* for backing-up fields set by user.
+ * we have to gain full control of such fields here */
+ void *hwaccel_context;
+ enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt);
+ int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags);
+#if FF_API_GET_BUFFER
+ int (*get_buffer)(struct AVCodecContext *c, AVFrame *pic);
+#endif
+} VDADecoderContext;
+
+static enum AVPixelFormat get_format(struct AVCodecContext *avctx,
+ const enum AVPixelFormat *fmt)
+{
+ return AV_PIX_FMT_VDA_VLD;
+}
+
+typedef struct {
+ CVPixelBufferRef cv_buffer;
+} VDABufferContext;
+
+static void release_buffer(void *opaque, uint8_t *data)
+{
+ VDABufferContext *context = opaque;
+ CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0);
+ CVPixelBufferRelease(context->cv_buffer);
+ av_free(context);
+}
+
+static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag)
+{
+ VDABufferContext *context = av_mallocz(sizeof(VDABufferContext));
+ AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0);
+ if (!context || !buffer) {
+ av_free(context);
+ return AVERROR(ENOMEM);
+ }
+
+ pic->buf[0] = buffer;
+ pic->data[0] = (void *)1;
+ return 0;
+}
+
+static inline void set_context(AVCodecContext *avctx)
+{
+ VDADecoderContext *ctx = avctx->priv_data;
+ ctx->hwaccel_context = avctx->hwaccel_context;
+ avctx->hwaccel_context = &ctx->vda_ctx;
+ ctx->get_format = avctx->get_format;
+ avctx->get_format = get_format;
+ ctx->get_buffer2 = avctx->get_buffer2;
+ avctx->get_buffer2 = get_buffer2;
+#if FF_API_GET_BUFFER
+ ctx->get_buffer = avctx->get_buffer;
+ avctx->get_buffer = NULL;
+#endif
+}
+
+static inline void restore_context(AVCodecContext *avctx)
+{
+ VDADecoderContext *ctx = avctx->priv_data;
+ avctx->hwaccel_context = ctx->hwaccel_context;
+ avctx->get_format = ctx->get_format;
+ avctx->get_buffer2 = ctx->get_buffer2;
+#if FF_API_GET_BUFFER
+ avctx->get_buffer = ctx->get_buffer;
+#endif
+}
+
+static int vdadec_decode(AVCodecContext *avctx,
+ void *data, int *got_frame, AVPacket *avpkt)
+{
+ VDADecoderContext *ctx = avctx->priv_data;
+ AVFrame *pic = data;
+ int ret;
+
+ set_context(avctx);
+ ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt);
+ restore_context(avctx);
+ if (*got_frame) {
+ AVBufferRef *buffer = pic->buf[0];
+ VDABufferContext *context = av_buffer_get_opaque(buffer);
+ CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3];
+
+ CVPixelBufferRetain(cv_buffer);
+ CVPixelBufferLockBaseAddress(cv_buffer, 0);
+ context->cv_buffer = cv_buffer;
+ pic->format = ctx->pix_fmt;
+ if (CVPixelBufferIsPlanar(cv_buffer)) {
+ int i, count = CVPixelBufferGetPlaneCount(cv_buffer);
+ av_assert0(count < 4);
+ for (i = 0; i < count; i++) {
+ pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i);
+ pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i);
+ }
+ } else {
+ pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer);
+ pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer);
+ }
+ }
+ avctx->pix_fmt = ctx->pix_fmt;
+
+ return ret;
+}
+
+static av_cold int vdadec_close(AVCodecContext *avctx)
+{
+ VDADecoderContext *ctx = avctx->priv_data;
+ /* release buffers and decoder */
+ ff_vda_destroy_decoder(&ctx->vda_ctx);
+ /* close H.264 decoder */
+ if (ctx->h264_initialized) {
+ set_context(avctx);
+ ff_h264_decoder.close(avctx);
+ restore_context(avctx);
+ }
+ return 0;
+}
+
+static av_cold int vdadec_init(AVCodecContext *avctx)
+{
+ VDADecoderContext *ctx = avctx->priv_data;
+ struct vda_context *vda_ctx = &ctx->vda_ctx;
+ OSStatus status;
+ int ret, i;
+
+ ctx->h264_initialized = 0;
+
+ /* init pix_fmts of codec */
+ if (!ff_h264_vda_decoder.pix_fmts) {
+ if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7)
+ ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7;
+ else
+ ff_h264_vda_decoder.pix_fmts = vda_pixfmts;
+ }
+
+ /* init vda */
+ memset(vda_ctx, 0, sizeof(struct vda_context));
+ vda_ctx->width = avctx->width;
+ vda_ctx->height = avctx->height;
+ vda_ctx->format = 'avc1';
+ vda_ctx->use_sync_decoding = 1;
+ vda_ctx->use_ref_buffer = 1;
+ ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts);
+ switch (ctx->pix_fmt) {
+ case AV_PIX_FMT_UYVY422:
+ vda_ctx->cv_pix_fmt_type = '2vuy';
+ break;
+ case AV_PIX_FMT_YUYV422:
+ vda_ctx->cv_pix_fmt_type = 'yuvs';
+ break;
+ case AV_PIX_FMT_NV12:
+ vda_ctx->cv_pix_fmt_type = '420v';
+ break;
+ case AV_PIX_FMT_YUV420P:
+ vda_ctx->cv_pix_fmt_type = 'y420';
+ break;
+ default:
+ av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt);
+ goto failed;
+ }
+ status = ff_vda_create_decoder(vda_ctx,
+ avctx->extradata, avctx->extradata_size);
+ if (status != kVDADecoderNoErr) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Failed to init VDA decoder: %d.\n", status);
+ goto failed;
+ }
+
+ /* init H.264 decoder */
+ set_context(avctx);
+ ret = ff_h264_decoder.init(avctx);
+ restore_context(avctx);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n");
+ goto failed;
+ }
+ ctx->h264_initialized = 1;
+
+ for (i = 0; i < MAX_SPS_COUNT; i++) {
+ SPS *sps = ctx->h264ctx.sps_buffers[i];
+ if (sps && (sps->bit_depth_luma != 8 ||
+ sps->chroma_format_idc == 2 ||
+ sps->chroma_format_idc == 3)) {
+ av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n");
+ goto failed;
+ }
+ }
+
+ return 0;
+
+failed:
+ vdadec_close(avctx);
+ return -1;
+}
+
+static void vdadec_flush(AVCodecContext *avctx)
+{
+ set_context(avctx);
+ ff_h264_decoder.flush(avctx);
+ restore_context(avctx);
+}
+
+AVCodec ff_h264_vda_decoder = {
+ .name = "h264_vda",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_H264,
+ .priv_data_size = sizeof(VDADecoderContext),
+ .init = vdadec_init,
+ .close = vdadec_close,
+ .decode = vdadec_decode,
+ .capabilities = CODEC_CAP_DELAY,
+ .flush = vdadec_flush,
+ .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"),
+};
diff --git a/libavcodec/vda_internal.h b/libavcodec/vda_internal.h
index 9d0ed807bf..457916b058 100644
--- a/libavcodec/vda_internal.h
+++ b/libavcodec/vda_internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c
index 8606624a85..0c3893507e 100644
--- a/libavcodec/vdpau.c
+++ b/libavcodec/vdpau.c
@@ -4,20 +4,20 @@
*
* Copyright (c) 2008 NVIDIA
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,6 +64,13 @@ static int vdpau_error(VdpStatus status)
}
}
+AVVDPAUContext *av_alloc_vdpaucontext(void)
+{
+ return av_vdpau_alloc_context();
+}
+
+MAKE_ACCESSORS(AVVDPAUContext, vdpau_hwaccel, AVVDPAU_Render2, render2)
+
int av_vdpau_get_surface_parameters(AVCodecContext *avctx,
VdpChromaType *type,
uint32_t *width, uint32_t *height)
@@ -122,7 +129,12 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
vdctx->width = UINT32_MAX;
vdctx->height = UINT32_MAX;
- hwctx->reset = 0;
+
+ if (!hwctx) {
+ vdctx->device = VDP_INVALID_HANDLE;
+ av_log(avctx, AV_LOG_WARNING, "hwaccel_context has not been setup by the user application, cannot initialize\n");
+ return 0;
+ }
if (hwctx->context.decoder != VDP_INVALID_HANDLE) {
vdctx->decoder = hwctx->context.decoder;
@@ -130,6 +142,7 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
vdctx->device = VDP_INVALID_HANDLE;
return 0; /* Decoder created by user */
}
+ hwctx->reset = 0;
vdctx->device = hwctx->device;
vdctx->get_proc_address = hwctx->get_proc_address;
@@ -264,6 +277,7 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
struct vdpau_picture_context *pic_ctx)
{
VDPAUContext *vdctx = avctx->internal->hwaccel_priv_data;
+ AVVDPAUContext *hwctx = avctx->hwaccel_context;
VdpVideoSurface surf = ff_vdpau_get_surface_id(frame);
VdpStatus status;
int val;
@@ -272,11 +286,34 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
if (val < 0)
return val;
+#if FF_API_BUFS_VDPAU
+FF_DISABLE_DEPRECATION_WARNINGS
+ av_assert0(sizeof(hwctx->info) <= sizeof(pic_ctx->info));
+ memcpy(&hwctx->info, &pic_ctx->info, sizeof(hwctx->info));
+ hwctx->bitstream_buffers = pic_ctx->bitstream_buffers;
+ hwctx->bitstream_buffers_used = pic_ctx->bitstream_buffers_used;
+ hwctx->bitstream_buffers_allocated = pic_ctx->bitstream_buffers_allocated;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+ if (!hwctx->render && hwctx->render2) {
+ status = hwctx->render2(avctx, frame, (void *)&pic_ctx->info,
+ pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers);
+ } else
status = vdctx->render(vdctx->decoder, surf, (void *)&pic_ctx->info,
pic_ctx->bitstream_buffers_used,
pic_ctx->bitstream_buffers);
av_freep(&pic_ctx->bitstream_buffers);
+
+#if FF_API_BUFS_VDPAU
+FF_DISABLE_DEPRECATION_WARNINGS
+ hwctx->bitstream_buffers = NULL;
+ hwctx->bitstream_buffers_used = 0;
+ hwctx->bitstream_buffers_allocated = 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
return vdpau_error(status);
}
@@ -318,6 +355,343 @@ int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx,
return 0;
}
+/* Obsolete non-hwaccel VDPAU support below... */
+
+void ff_vdpau_h264_set_reference_frames(H264Context *h)
+{
+ struct vdpau_render_state *render, *render_ref;
+ VdpReferenceFrameH264 *rf, *rf2;
+ H264Picture *pic;
+ int i, list, pic_frame_idx;
+
+ render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0];
+ assert(render);
+
+ rf = &render->info.h264.referenceFrames[0];
+#define H264_RF_COUNT FF_ARRAY_ELEMS(render->info.h264.referenceFrames)
+
+ for (list = 0; list < 2; ++list) {
+ H264Picture **lp = list ? h->long_ref : h->short_ref;
+ int ls = list ? 16 : h->short_ref_count;
+
+ for (i = 0; i < ls; ++i) {
+ pic = lp[i];
+ if (!pic || !pic->reference)
+ continue;
+ pic_frame_idx = pic->long_ref ? pic->pic_id : pic->frame_num;
+
+ render_ref = (struct vdpau_render_state *)pic->f->data[0];
+ assert(render_ref);
+
+ rf2 = &render->info.h264.referenceFrames[0];
+ while (rf2 != rf) {
+ if (
+ (rf2->surface == render_ref->surface)
+ && (rf2->is_long_term == pic->long_ref)
+ && (rf2->frame_idx == pic_frame_idx)
+ )
+ break;
+ ++rf2;
+ }
+ if (rf2 != rf) {
+ rf2->top_is_reference |= (pic->reference & PICT_TOP_FIELD) ? VDP_TRUE : VDP_FALSE;
+ rf2->bottom_is_reference |= (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE;
+ continue;
+ }
+
+ if (rf >= &render->info.h264.referenceFrames[H264_RF_COUNT])
+ continue;
+
+ rf->surface = render_ref->surface;
+ rf->is_long_term = pic->long_ref;
+ rf->top_is_reference = (pic->reference & PICT_TOP_FIELD) ? VDP_TRUE : VDP_FALSE;
+ rf->bottom_is_reference = (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE;
+ rf->field_order_cnt[0] = pic->field_poc[0];
+ rf->field_order_cnt[1] = pic->field_poc[1];
+ rf->frame_idx = pic_frame_idx;
+
+ ++rf;
+ }
+ }
+
+ for (; rf < &render->info.h264.referenceFrames[H264_RF_COUNT]; ++rf) {
+ rf->surface = VDP_INVALID_HANDLE;
+ rf->is_long_term = 0;
+ rf->top_is_reference = 0;
+ rf->bottom_is_reference = 0;
+ rf->field_order_cnt[0] = 0;
+ rf->field_order_cnt[1] = 0;
+ rf->frame_idx = 0;
+ }
+}
+
+void ff_vdpau_add_data_chunk(uint8_t *data, const uint8_t *buf, int buf_size)
+{
+ struct vdpau_render_state *render = (struct vdpau_render_state*)data;
+ assert(render);
+
+ render->bitstream_buffers= av_fast_realloc(
+ render->bitstream_buffers,
+ &render->bitstream_buffers_allocated,
+ sizeof(*render->bitstream_buffers)*(render->bitstream_buffers_used + 1)
+ );
+
+ render->bitstream_buffers[render->bitstream_buffers_used].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
+ render->bitstream_buffers[render->bitstream_buffers_used].bitstream = buf;
+ render->bitstream_buffers[render->bitstream_buffers_used].bitstream_bytes = buf_size;
+ render->bitstream_buffers_used++;
+}
+
+#if CONFIG_H264_VDPAU_DECODER
+void ff_vdpau_h264_picture_start(H264Context *h)
+{
+ struct vdpau_render_state *render;
+ int i;
+
+ render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0];
+ assert(render);
+
+ for (i = 0; i < 2; ++i) {
+ int foc = h->cur_pic_ptr->field_poc[i];
+ if (foc == INT_MAX)
+ foc = 0;
+ render->info.h264.field_order_cnt[i] = foc;
+ }
+
+ render->info.h264.frame_num = h->frame_num;
+}
+
+void ff_vdpau_h264_picture_complete(H264Context *h)
+{
+ struct vdpau_render_state *render;
+
+ render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0];
+ assert(render);
+
+ render->info.h264.slice_count = h->current_slice;
+ if (render->info.h264.slice_count < 1)
+ return;
+
+ render->info.h264.is_reference = (h->cur_pic_ptr->reference & 3) ? VDP_TRUE : VDP_FALSE;
+ render->info.h264.field_pic_flag = h->picture_structure != PICT_FRAME;
+ render->info.h264.bottom_field_flag = h->picture_structure == PICT_BOTTOM_FIELD;
+ render->info.h264.num_ref_frames = h->sps.ref_frame_count;
+ render->info.h264.mb_adaptive_frame_field_flag = h->sps.mb_aff && !render->info.h264.field_pic_flag;
+ render->info.h264.constrained_intra_pred_flag = h->pps.constrained_intra_pred;
+ render->info.h264.weighted_pred_flag = h->pps.weighted_pred;
+ render->info.h264.weighted_bipred_idc = h->pps.weighted_bipred_idc;
+ render->info.h264.frame_mbs_only_flag = h->sps.frame_mbs_only_flag;
+ render->info.h264.transform_8x8_mode_flag = h->pps.transform_8x8_mode;
+ render->info.h264.chroma_qp_index_offset = h->pps.chroma_qp_index_offset[0];
+ render->info.h264.second_chroma_qp_index_offset = h->pps.chroma_qp_index_offset[1];
+ render->info.h264.pic_init_qp_minus26 = h->pps.init_qp - 26;
+ render->info.h264.num_ref_idx_l0_active_minus1 = h->pps.ref_count[0] - 1;
+ render->info.h264.num_ref_idx_l1_active_minus1 = h->pps.ref_count[1] - 1;
+ render->info.h264.log2_max_frame_num_minus4 = h->sps.log2_max_frame_num - 4;
+ render->info.h264.pic_order_cnt_type = h->sps.poc_type;
+ render->info.h264.log2_max_pic_order_cnt_lsb_minus4 = h->sps.poc_type ? 0 : h->sps.log2_max_poc_lsb - 4;
+ render->info.h264.delta_pic_order_always_zero_flag = h->sps.delta_pic_order_always_zero_flag;
+ render->info.h264.direct_8x8_inference_flag = h->sps.direct_8x8_inference_flag;
+ render->info.h264.entropy_coding_mode_flag = h->pps.cabac;
+ render->info.h264.pic_order_present_flag = h->pps.pic_order_present;
+ render->info.h264.deblocking_filter_control_present_flag = h->pps.deblocking_filter_parameters_present;
+ render->info.h264.redundant_pic_cnt_present_flag = h->pps.redundant_pic_cnt_present;
+ memcpy(render->info.h264.scaling_lists_4x4, h->pps.scaling_matrix4, sizeof(render->info.h264.scaling_lists_4x4));
+ memcpy(render->info.h264.scaling_lists_8x8[0], h->pps.scaling_matrix8[0], sizeof(render->info.h264.scaling_lists_8x8[0]));
+ memcpy(render->info.h264.scaling_lists_8x8[1], h->pps.scaling_matrix8[3], sizeof(render->info.h264.scaling_lists_8x8[0]));
+
+ ff_h264_draw_horiz_band(h, &h->slice_ctx[0], 0, h->avctx->height);
+ render->bitstream_buffers_used = 0;
+}
+#endif /* CONFIG_H264_VDPAU_DECODER */
+
+#if CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER
+void ff_vdpau_mpeg_picture_complete(MpegEncContext *s, const uint8_t *buf,
+ int buf_size, int slice_count)
+{
+ struct vdpau_render_state *render, *last, *next;
+ int i;
+
+ if (!s->current_picture_ptr) return;
+
+ render = (struct vdpau_render_state *)s->current_picture_ptr->f->data[0];
+ assert(render);
+
+ /* fill VdpPictureInfoMPEG1Or2 struct */
+ render->info.mpeg.picture_structure = s->picture_structure;
+ render->info.mpeg.picture_coding_type = s->pict_type;
+ render->info.mpeg.intra_dc_precision = s->intra_dc_precision;
+ render->info.mpeg.frame_pred_frame_dct = s->frame_pred_frame_dct;
+ render->info.mpeg.concealment_motion_vectors = s->concealment_motion_vectors;
+ render->info.mpeg.intra_vlc_format = s->intra_vlc_format;
+ render->info.mpeg.alternate_scan = s->alternate_scan;
+ render->info.mpeg.q_scale_type = s->q_scale_type;
+ render->info.mpeg.top_field_first = s->top_field_first;
+ render->info.mpeg.full_pel_forward_vector = s->full_pel[0]; // MPEG-1 only. Set 0 for MPEG-2
+ render->info.mpeg.full_pel_backward_vector = s->full_pel[1]; // MPEG-1 only. Set 0 for MPEG-2
+ render->info.mpeg.f_code[0][0] = s->mpeg_f_code[0][0]; // For MPEG-1 fill both horiz. & vert.
+ render->info.mpeg.f_code[0][1] = s->mpeg_f_code[0][1];
+ render->info.mpeg.f_code[1][0] = s->mpeg_f_code[1][0];
+ render->info.mpeg.f_code[1][1] = s->mpeg_f_code[1][1];
+ for (i = 0; i < 64; ++i) {
+ render->info.mpeg.intra_quantizer_matrix[i] = s->intra_matrix[i];
+ render->info.mpeg.non_intra_quantizer_matrix[i] = s->inter_matrix[i];
+ }
+
+ render->info.mpeg.forward_reference = VDP_INVALID_HANDLE;
+ render->info.mpeg.backward_reference = VDP_INVALID_HANDLE;
+
+ switch(s->pict_type){
+ case AV_PICTURE_TYPE_B:
+ next = (struct vdpau_render_state *)s->next_picture.f->data[0];
+ assert(next);
+ render->info.mpeg.backward_reference = next->surface;
+ // no return here, going to set forward prediction
+ case AV_PICTURE_TYPE_P:
+ last = (struct vdpau_render_state *)s->last_picture.f->data[0];
+ if (!last) // FIXME: Does this test make sense?
+ last = render; // predict second field from the first
+ render->info.mpeg.forward_reference = last->surface;
+ }
+
+ ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size);
+
+ render->info.mpeg.slice_count = slice_count;
+
+ if (slice_count)
+ ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
+ render->bitstream_buffers_used = 0;
+}
+#endif /* CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER */
+
+#if CONFIG_VC1_VDPAU_DECODER
+void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf,
+ int buf_size)
+{
+ VC1Context *v = s->avctx->priv_data;
+ struct vdpau_render_state *render, *last, *next;
+
+ render = (struct vdpau_render_state *)s->current_picture.f->data[0];
+ assert(render);
+
+ /* fill LvPictureInfoVC1 struct */
+ render->info.vc1.frame_coding_mode = v->fcm ? v->fcm + 1 : 0;
+ render->info.vc1.postprocflag = v->postprocflag;
+ render->info.vc1.pulldown = v->broadcast;
+ render->info.vc1.interlace = v->interlace;
+ render->info.vc1.tfcntrflag = v->tfcntrflag;
+ render->info.vc1.finterpflag = v->finterpflag;
+ render->info.vc1.psf = v->psf;
+ render->info.vc1.dquant = v->dquant;
+ render->info.vc1.panscan_flag = v->panscanflag;
+ render->info.vc1.refdist_flag = v->refdist_flag;
+ render->info.vc1.quantizer = v->quantizer_mode;
+ render->info.vc1.extended_mv = v->extended_mv;
+ render->info.vc1.extended_dmv = v->extended_dmv;
+ render->info.vc1.overlap = v->overlap;
+ render->info.vc1.vstransform = v->vstransform;
+ render->info.vc1.loopfilter = v->s.loop_filter;
+ render->info.vc1.fastuvmc = v->fastuvmc;
+ render->info.vc1.range_mapy_flag = v->range_mapy_flag;
+ render->info.vc1.range_mapy = v->range_mapy;
+ render->info.vc1.range_mapuv_flag = v->range_mapuv_flag;
+ render->info.vc1.range_mapuv = v->range_mapuv;
+ /* Specific to simple/main profile only */
+ render->info.vc1.multires = v->multires;
+ render->info.vc1.syncmarker = v->resync_marker;
+ render->info.vc1.rangered = v->rangered | (v->rangeredfrm << 1);
+ render->info.vc1.maxbframes = v->s.max_b_frames;
+
+ render->info.vc1.deblockEnable = v->postprocflag & 1;
+ render->info.vc1.pquant = v->pq;
+
+ render->info.vc1.forward_reference = VDP_INVALID_HANDLE;
+ render->info.vc1.backward_reference = VDP_INVALID_HANDLE;
+
+ if (v->bi_type)
+ render->info.vc1.picture_type = 4;
+ else
+ render->info.vc1.picture_type = s->pict_type - 1 + s->pict_type / 3;
+
+ switch(s->pict_type){
+ case AV_PICTURE_TYPE_B:
+ next = (struct vdpau_render_state *)s->next_picture.f->data[0];
+ assert(next);
+ render->info.vc1.backward_reference = next->surface;
+ // no break here, going to set forward prediction
+ case AV_PICTURE_TYPE_P:
+ last = (struct vdpau_render_state *)s->last_picture.f->data[0];
+ if (!last) // FIXME: Does this test make sense?
+ last = render; // predict second field from the first
+ render->info.vc1.forward_reference = last->surface;
+ }
+
+ ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size);
+
+ render->info.vc1.slice_count = 1;
+
+ ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
+ render->bitstream_buffers_used = 0;
+}
+#endif /* (CONFIG_VC1_VDPAU_DECODER */
+
+#if CONFIG_MPEG4_VDPAU_DECODER
+void ff_vdpau_mpeg4_decode_picture(Mpeg4DecContext *ctx, const uint8_t *buf,
+ int buf_size)
+{
+ MpegEncContext *s = &ctx->m;
+ struct vdpau_render_state *render, *last, *next;
+ int i;
+
+ if (!s->current_picture_ptr) return;
+
+ render = (struct vdpau_render_state *)s->current_picture_ptr->f->data[0];
+ assert(render);
+
+ /* fill VdpPictureInfoMPEG4Part2 struct */
+ render->info.mpeg4.trd[0] = s->pp_time;
+ render->info.mpeg4.trb[0] = s->pb_time;
+ render->info.mpeg4.trd[1] = s->pp_field_time >> 1;
+ render->info.mpeg4.trb[1] = s->pb_field_time >> 1;
+ render->info.mpeg4.vop_time_increment_resolution = s->avctx->time_base.den;
+ render->info.mpeg4.vop_coding_type = 0;
+ render->info.mpeg4.vop_fcode_forward = s->f_code;
+ render->info.mpeg4.vop_fcode_backward = s->b_code;
+ render->info.mpeg4.resync_marker_disable = !ctx->resync_marker;
+ render->info.mpeg4.interlaced = !s->progressive_sequence;
+ render->info.mpeg4.quant_type = s->mpeg_quant;
+ render->info.mpeg4.quarter_sample = s->quarter_sample;
+ render->info.mpeg4.short_video_header = s->avctx->codec->id == AV_CODEC_ID_H263;
+ render->info.mpeg4.rounding_control = s->no_rounding;
+ render->info.mpeg4.alternate_vertical_scan_flag = s->alternate_scan;
+ render->info.mpeg4.top_field_first = s->top_field_first;
+ for (i = 0; i < 64; ++i) {
+ render->info.mpeg4.intra_quantizer_matrix[i] = s->intra_matrix[i];
+ render->info.mpeg4.non_intra_quantizer_matrix[i] = s->inter_matrix[i];
+ }
+ render->info.mpeg4.forward_reference = VDP_INVALID_HANDLE;
+ render->info.mpeg4.backward_reference = VDP_INVALID_HANDLE;
+
+ switch (s->pict_type) {
+ case AV_PICTURE_TYPE_B:
+ next = (struct vdpau_render_state *)s->next_picture.f->data[0];
+ assert(next);
+ render->info.mpeg4.backward_reference = next->surface;
+ render->info.mpeg4.vop_coding_type = 2;
+ // no break here, going to set forward prediction
+ case AV_PICTURE_TYPE_P:
+ last = (struct vdpau_render_state *)s->last_picture.f->data[0];
+ assert(last);
+ render->info.mpeg4.forward_reference = last->surface;
+ }
+
+ ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size);
+
+ ff_mpeg_draw_horiz_band(s, 0, s->avctx->height);
+ render->bitstream_buffers_used = 0;
+}
+#endif /* CONFIG_MPEG4_VDPAU_DECODER */
+
int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile)
{
#define PROFILE(prof) \
diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h
index 4e5c3518e3..a42ca013f2 100644
--- a/libavcodec/vdpau.h
+++ b/libavcodec/vdpau.h
@@ -4,20 +4,20 @@
*
* Copyright (C) 2008 NVIDIA
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,7 +39,7 @@
* - VDPAU decoding
* - VDPAU presentation
*
- * The VDPAU decoding module parses all headers using Libav
+ * The VDPAU decoding module parses all headers using FFmpeg
* parsing mechanisms and uses VDPAU for the actual decoding.
*
* As per the current implementation, the actual decoding
@@ -51,7 +51,7 @@
#include <vdpau/vdpau.h>
#include <vdpau/vdpau_x11.h>
-
+#include "libavutil/avconfig.h"
#include "libavutil/attributes.h"
#include "avcodec.h"
@@ -66,10 +66,18 @@ union AVVDPAUPictureInfo {
};
#endif
+struct AVCodecContext;
+struct AVFrame;
+
+typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *,
+ const VdpPictureInfo *, uint32_t,
+ const VdpBitstreamBuffer *);
+
/**
* This structure is used to share data between the libavcodec library and
* the client video application.
- * The user shall zero-allocate the structure and make it available as
+ * The user shall allocate the structure via the av_alloc_vdpau_hwaccel
+ * function and make it available as
* AVCodecContext.hwaccel_context. Members can be set by the user once
* during initialization or through each AVCodecContext.get_buffer()
* function call. In any case, they must be valid prior to calling
@@ -128,9 +136,20 @@ typedef struct AVVDPAUContext {
attribute_deprecated
VdpBitstreamBuffer *bitstream_buffers;
#endif
+ AVVDPAU_Render2 render2;
} AVVDPAUContext;
/**
+ * @brief allocation function for AVVDPAUContext
+ *
+ * Allows extending the struct without breaking API/ABI
+ */
+AVVDPAUContext *av_alloc_vdpaucontext(void);
+
+AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *);
+void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2);
+
+/**
* Associate a VDPAU device with a codec context for hardware acceleration.
* This function is meant to be called from the get_format() codec callback,
* or earlier. It can also be called after avcodec_flush_buffers() to change
@@ -138,7 +157,7 @@ typedef struct AVVDPAUContext {
* display preemption).
*
* @note get_format() must return AV_PIX_FMT_VDPAU if this function completes
- * succesfully.
+ * successfully.
*
* @param avctx decoding context whose get_format() callback is invoked
* @param device VDPAU device handle to use for hardware acceleration
@@ -201,19 +220,21 @@ int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile);
#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2
/**
- * @brief This structure is used as a callback between the Libav
+ * @brief This structure is used as a callback between the FFmpeg
* decoder (vd_) and presentation (vo_) module.
* This is used for defining a video frame containing surface,
* picture parameter, bitstream information etc which are passed
- * between the Libav decoder and its clients.
+ * between the FFmpeg decoder and its clients.
*/
struct vdpau_render_state {
VdpVideoSurface surface; ///< Used as rendered surface, never changed.
int state; ///< Holds FF_VDPAU_STATE_* values.
+#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
/** picture parameter information for all supported codecs */
union AVVDPAUPictureInfo info;
+#endif
/** Describe size/location of the compressed video data.
Set to 0 when freeing bitstream_buffers. */
@@ -221,6 +242,11 @@ struct vdpau_render_state {
int bitstream_buffers_used;
/** The user is responsible for freeing this buffer using av_freep(). */
VdpBitstreamBuffer *bitstream_buffers;
+
+#if !AV_HAVE_INCOMPATIBLE_LIBAV_ABI
+ /** picture parameter information for all supported codecs */
+ union AVVDPAUPictureInfo info;
+#endif
};
#endif
diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c
index d03d127ee5..10376ac931 100644
--- a/libavcodec/vdpau_h264.c
+++ b/libavcodec/vdpau_h264.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 NVIDIA
* Copyright (c) 2013 RĂ©mi Denis-Courmont
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software Foundation,
+ * License along with FFmpeg; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
index f35c99d3a5..cc49db8433 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.h
@@ -4,33 +4,37 @@
*
* Copyright (C) 2008 NVIDIA
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_VDPAU_INTERNAL_H
#define AVCODEC_VDPAU_INTERNAL_H
+#include "config.h"
#include <stdint.h>
+#if CONFIG_VDPAU
#include <vdpau/vdpau.h>
+#endif
+#include "h264.h"
#include "libavutil/frame.h"
#include "avcodec.h"
-#include "vdpau.h"
+#include "mpeg4video.h"
/** Extract VdpVideoSurface from an AVFrame */
static inline uintptr_t ff_vdpau_get_surface_id(AVFrame *pic)
@@ -38,6 +42,8 @@ static inline uintptr_t ff_vdpau_get_surface_id(AVFrame *pic)
return (uintptr_t)pic->data[3];
}
+struct vdpau_picture_context;
+#if CONFIG_VDPAU
union VDPAUPictureInfo {
VdpPictureInfoH264 h264;
VdpPictureInfoMPEG1Or2 mpeg;
@@ -48,6 +54,8 @@ union VDPAUPictureInfo {
#endif
};
+#include "vdpau.h"
+
typedef struct VDPAUHWContext {
AVVDPAUContext context;
VdpDevice device;
@@ -105,6 +113,8 @@ struct vdpau_picture_context {
int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile,
int level);
+#endif //CONFIG_VDPAU
+
int ff_vdpau_common_uninit(AVCodecContext *avctx);
int ff_vdpau_common_start_frame(struct vdpau_picture_context *pic,
@@ -115,4 +125,21 @@ int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx);
int ff_vdpau_add_buffer(struct vdpau_picture_context *pic, const uint8_t *buf,
uint32_t buf_size);
+
+void ff_vdpau_add_data_chunk(uint8_t *data, const uint8_t *buf,
+ int buf_size);
+
+void ff_vdpau_mpeg_picture_complete(MpegEncContext *s, const uint8_t *buf,
+ int buf_size, int slice_count);
+
+void ff_vdpau_h264_picture_start(H264Context *h);
+void ff_vdpau_h264_set_reference_frames(H264Context *h);
+void ff_vdpau_h264_picture_complete(H264Context *h);
+
+void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf,
+ int buf_size);
+
+void ff_vdpau_mpeg4_decode_picture(Mpeg4DecContext *s, const uint8_t *buf,
+ int buf_size);
+
#endif /* AVCODEC_VDPAU_INTERNAL_H */
diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c
index cb6f81a76d..3ac2cb827d 100644
--- a/libavcodec/vdpau_mpeg12.c
+++ b/libavcodec/vdpau_mpeg12.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 NVIDIA
* Copyright (c) 2013 RĂ©mi Denis-Courmont
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software Foundation,
+ * License along with FFmpeg; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c
index 978456ad2a..9141becd9f 100644
--- a/libavcodec/vdpau_mpeg4.c
+++ b/libavcodec/vdpau_mpeg4.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 NVIDIA
* Copyright (c) 2013 RĂ©mi Denis-Courmont
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software Foundation,
+ * License along with FFmpeg; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -119,6 +119,9 @@ static int vdpau_mpeg4_init(AVCodecContext *avctx)
case FF_PROFILE_MPEG4_SIMPLE:
profile = VDP_DECODER_PROFILE_MPEG4_PART2_SP;
break;
+ // As any ASP decoder must be able to decode SP, this
+ // should be a safe fallback if profile is unknown/unspecified.
+ case FF_PROFILE_UNKNOWN:
case FF_PROFILE_MPEG4_ADVANCED_SIMPLE:
profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
break;
diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c
index 4f87c52ecc..ffd6505d13 100644
--- a/libavcodec/vdpau_vc1.c
+++ b/libavcodec/vdpau_vc1.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 NVIDIA
* Copyright (c) 2013 RĂ©mi Denis-Courmont
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software Foundation,
+ * License along with FFmpeg; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,14 +44,18 @@ 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);
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);
assert(ref != VDP_INVALID_HANDLE);
info->forward_reference = ref;
+ }
}
info->slice_count = 0;
diff --git a/libavcodec/version.h b/libavcodec/version.h
index c57bd85083..74a1b3048e 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,8 +29,8 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 56
-#define LIBAVCODEC_VERSION_MINOR 25
-#define LIBAVCODEC_VERSION_MICRO 0
+#define LIBAVCODEC_VERSION_MINOR 41
+#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
@@ -48,9 +48,30 @@
* the public API and may change, break or disappear at any time.
*/
+#ifndef FF_API_VIMA_DECODER
+#define FF_API_VIMA_DECODER (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
#ifndef FF_API_REQUEST_CHANNELS
#define FF_API_REQUEST_CHANNELS (LIBAVCODEC_VERSION_MAJOR < 57)
#endif
+#ifndef FF_API_OLD_DECODE_AUDIO
+#define FF_API_OLD_DECODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_OLD_ENCODE_AUDIO
+#define FF_API_OLD_ENCODE_AUDIO (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_OLD_ENCODE_VIDEO
+#define FF_API_OLD_ENCODE_VIDEO (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_CODEC_ID
+#define FF_API_CODEC_ID (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_AUDIO_CONVERT
+#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_AVCODEC_RESAMPLE
+#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT
+#endif
#ifndef FF_API_DEINTERLACE
#define FF_API_DEINTERLACE (LIBAVCODEC_VERSION_MAJOR < 57)
#endif
@@ -114,9 +135,6 @@
#ifndef FF_API_MAX_BFRAMES
#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 57)
#endif
-#ifndef FF_API_FAST_MALLOC
-#define FF_API_FAST_MALLOC (LIBAVCODEC_VERSION_MAJOR < 57)
-#endif
#ifndef FF_API_NEG_LINESIZES
#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 57)
#endif
@@ -153,6 +171,13 @@
#ifndef FF_API_AFD
#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 57)
#endif
+#ifndef FF_API_VISMV
+/* XXX: don't forget to drop the -vismv documentation */
+#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_DV_FRAME_PROFILE
+#define FF_API_DV_FRAME_PROFILE (LIBAVCODEC_VERSION_MAJOR < 57)
+#endif
#ifndef FF_API_AUDIOENC_DELAY
#define FF_API_AUDIOENC_DELAY (LIBAVCODEC_VERSION_MAJOR < 58)
#endif
diff --git a/libavcodec/videodsp.c b/libavcodec/videodsp.c
index e6d9303903..ba618a7bbc 100644
--- a/libavcodec/videodsp.c
+++ b/libavcodec/videodsp.c
@@ -1,24 +1,25 @@
/*
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avassert.h"
#include "libavutil/common.h"
#include "videodsp.h"
diff --git a/libavcodec/videodsp.h b/libavcodec/videodsp.h
index 04c012a826..fc01a31dca 100644
--- a/libavcodec/videodsp.h
+++ b/libavcodec/videodsp.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,14 +29,25 @@
#include <stddef.h>
#include <stdint.h>
+#define EMULATED_EDGE(depth) \
+void ff_emulated_edge_mc_ ## depth(uint8_t *dst, const uint8_t *src, \
+ ptrdiff_t dst_stride, ptrdiff_t src_stride, \
+ int block_w, int block_h,\
+ int src_x, int src_y, int w, int h);
+
+EMULATED_EDGE(8)
+EMULATED_EDGE(16)
+
typedef struct VideoDSPContext {
/**
* Copy a rectangular area of samples to a temporary buffer and replicate
* the border samples.
*
- * @param buf destination buffer
+ * @param dst destination buffer
+ * @param dst_stride number of bytes between 2 vertically adjacent samples
+ * in destination buffer
* @param src source buffer
- * @param buf_linesize number of bytes between 2 vertically adjacent
+ * @param dst_linesize number of bytes between 2 vertically adjacent
* samples in the destination buffer
* @param src_linesize number of bytes between 2 vertically adjacent
* samples in both the source buffer
@@ -49,8 +60,8 @@ typedef struct VideoDSPContext {
* @param w width of the source buffer
* @param h height of the source buffer
*/
- void (*emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
- ptrdiff_t buf_linesize,
+ void (*emulated_edge_mc)(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t dst_linesize,
ptrdiff_t src_linesize,
int block_w, int block_h,
int src_x, int src_y, int w, int h);
diff --git a/libavcodec/videodsp_template.c b/libavcodec/videodsp_template.c
index 28b8c3286d..c569c30d60 100644
--- a/libavcodec/videodsp_template.c
+++ b/libavcodec/videodsp_template.c
@@ -1,42 +1,44 @@
/*
- * Copyright (c) 2002-2004 Michael Niedermayer
+ * Copyright (c) 2002-2012 Michael Niedermayer
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
-
#include "bit_depth_template.c"
-
-static void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
- ptrdiff_t buf_linesize,
- ptrdiff_t src_linesize,
- int block_w, int block_h,
- int src_x, int src_y, int w, int h)
+void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
+ ptrdiff_t buf_linesize,
+ ptrdiff_t src_linesize,
+ int block_w, int block_h,
+ int src_x, int src_y, int w, int h)
{
int x, y;
int start_y, start_x, end_y, end_x;
+ if (!w || !h)
+ return;
+
if (src_y >= h) {
- src += (h - 1 - src_y) * src_linesize;
+ src -= src_y * src_linesize;
+ src += (h - 1) * src_linesize;
src_y = h - 1;
} else if (src_y <= -block_h) {
- src += (1 - block_h - src_y) * src_linesize;
+ src -= src_y * src_linesize;
+ src += (1 - block_h) * src_linesize;
src_y = 1 - block_h;
}
if (src_x >= w) {
@@ -51,8 +53,8 @@ static void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src,
start_x = FFMAX(0, -src_x);
end_y = FFMIN(block_h, h-src_y);
end_x = FFMIN(block_w, w-src_x);
- assert(start_y < end_y && block_h);
- assert(start_x < end_x && block_w);
+ av_assert2(start_y < end_y && block_h);
+ av_assert2(start_x < end_x && block_w);
w = end_x - start_x;
src += start_y * src_linesize + start_x * sizeof(pixel);
diff --git a/libavcodec/vima.c b/libavcodec/vima.c
index 14a3bca3b1..74d6a9a184 100644
--- a/libavcodec/vima.c
+++ b/libavcodec/vima.c
@@ -2,20 +2,20 @@
* LucasArts VIMA decoder
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -216,3 +216,15 @@ AVCodec ff_adpcm_vima_decoder = {
.decode = decode_frame,
.capabilities = CODEC_CAP_DR1,
};
+
+#if FF_API_VIMA_DECODER
+AVCodec ff_vima_decoder = {
+ .name = "vima",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_ADPCM_VIMA,
+ .init = decode_init,
+ .decode = decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
+#endif
diff --git a/libavcodec/vmdaudio.c b/libavcodec/vmdaudio.c
index 66c5865f85..3be0ff8520 100644
--- a/libavcodec/vmdaudio.c
+++ b/libavcodec/vmdaudio.c
@@ -1,20 +1,21 @@
/*
* Sierra VMD audio decoder
+ * Copyright (c) 2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +35,7 @@
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
@@ -74,7 +76,7 @@ static av_cold int vmdaudio_decode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n");
return AVERROR(EINVAL);
}
- if (avctx->block_align < 1) {
+ if (avctx->block_align < 1 || avctx->block_align % avctx->channels) {
av_log(avctx, AV_LOG_ERROR, "invalid block align\n");
return AVERROR(EINVAL);
}
@@ -180,17 +182,16 @@ static int vmdaudio_decode_frame(AVCodecContext *avctx, void *data,
/* get output buffer */
frame->nb_samples = ((silent_chunks + audio_chunks) * avctx->block_align) /
avctx->channels;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
output_samples_u8 = frame->data[0];
output_samples_s16 = (int16_t *)frame->data[0];
/* decode silent chunks */
if (silent_chunks > 0) {
- int silent_size = FFMIN(avctx->block_align * silent_chunks,
- frame->nb_samples * avctx->channels);
+ int silent_size = avctx->block_align * silent_chunks;
+ av_assert0(avctx->block_align * silent_chunks <= frame->nb_samples * avctx->channels);
+
if (s->out_bps == 2) {
memset(output_samples_s16, 0x00, silent_size * 2);
output_samples_s16 += silent_size;
@@ -202,8 +203,9 @@ static int vmdaudio_decode_frame(AVCodecContext *avctx, void *data,
/* decode audio chunks */
if (audio_chunks > 0) {
- buf_end = buf + (buf_size & ~(avctx->channels > 1));
- while (buf + s->chunk_size <= buf_end) {
+ buf_end = buf + buf_size;
+ av_assert0((buf_size & (avctx->channels > 1)) == 0);
+ while (buf_end - buf >= s->chunk_size) {
if (s->out_bps == 2) {
decode_audio_s16(output_samples_s16, buf, s->chunk_size,
avctx->channels);
diff --git a/libavcodec/vmdvideo.c b/libavcodec/vmdvideo.c
index aaeff4308c..a2ba1c959b 100644
--- a/libavcodec/vmdvideo.c
+++ b/libavcodec/vmdvideo.c
@@ -1,20 +1,21 @@
/*
* Sierra VMD video decoder
+ * Copyright (c) 2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -62,7 +63,7 @@ typedef struct VmdVideoContext {
#define QUEUE_SIZE 0x1000
#define QUEUE_MASK 0x0FFF
-static void lz_unpack(const unsigned char *src, int src_len,
+static int lz_unpack(const unsigned char *src, int src_len,
unsigned char *dest, int dest_len)
{
unsigned char *d;
@@ -83,9 +84,9 @@ static void lz_unpack(const unsigned char *src, int src_len,
dataleft = bytestream2_get_le32(&gb);
memset(queue, 0x20, QUEUE_SIZE);
if (bytestream2_get_bytes_left(&gb) < 4)
- return;
+ return AVERROR_INVALIDDATA;
if (bytestream2_peek_le32(&gb) == 0x56781234) {
- bytestream2_get_le32(&gb);
+ bytestream2_skipu(&gb, 4);
qpos = 0x111;
speclen = 0xF + 3;
} else {
@@ -96,8 +97,8 @@ static void lz_unpack(const unsigned char *src, int src_len,
while (dataleft > 0 && bytestream2_get_bytes_left(&gb) > 0) {
tag = bytestream2_get_byteu(&gb);
if ((tag == 0xFF) && (dataleft > 8)) {
- if (d + 8 > d_end || bytestream2_get_bytes_left(&gb) < 8)
- return;
+ if (d_end - d < 8 || bytestream2_get_bytes_left(&gb) < 8)
+ return AVERROR_INVALIDDATA;
for (i = 0; i < 8; i++) {
queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
qpos &= QUEUE_MASK;
@@ -108,9 +109,9 @@ static void lz_unpack(const unsigned char *src, int src_len,
if (dataleft == 0)
break;
if (tag & 0x01) {
- if (d + 1 > d_end || bytestream2_get_bytes_left(&gb) < 1)
- return;
- queue[qpos++] = *d++ = bytestream2_get_byte(&gb);
+ if (d_end - d < 1 || bytestream2_get_bytes_left(&gb) < 1)
+ return AVERROR_INVALIDDATA;
+ queue[qpos++] = *d++ = bytestream2_get_byteu(&gb);
qpos &= QUEUE_MASK;
dataleft--;
} else {
@@ -120,8 +121,8 @@ static void lz_unpack(const unsigned char *src, int src_len,
if (chainlen == speclen) {
chainlen = bytestream2_get_byte(&gb) + 0xF + 3;
}
- if (d + chainlen > d_end)
- return;
+ if (d_end - d < chainlen)
+ return AVERROR_INVALIDDATA;
for (j = 0; j < chainlen; j++) {
*d = queue[chainofs++ & QUEUE_MASK];
queue[qpos++] = *d++;
@@ -133,10 +134,10 @@ static void lz_unpack(const unsigned char *src, int src_len,
}
}
}
+ return d - dest;
}
-
static int rle_unpack(const unsigned char *src, unsigned char *dest,
- int src_count, int src_size, int dest_len)
+ int src_count, int src_size, int dest_len)
{
unsigned char *pd;
int i, l, used = 0;
@@ -159,12 +160,12 @@ static int rle_unpack(const unsigned char *src, unsigned char *dest,
l = bytestream2_get_byteu(&gb);
if (l & 0x80) {
l = (l & 0x7F) * 2;
- if (pd + l > dest_end || bytestream2_get_bytes_left(&gb) < l)
+ if (dest_end - pd < l || bytestream2_get_bytes_left(&gb) < l)
return bytestream2_tell(&gb);
- bytestream2_get_buffer(&gb, pd, l);
+ bytestream2_get_bufferu(&gb, pd, l);
pd += l;
} else {
- if (pd + l > dest_end || bytestream2_get_bytes_left(&gb) < 2)
+ if (dest_end - pd < 2*l || bytestream2_get_bytes_left(&gb) < 2)
return bytestream2_tell(&gb);
run_val = bytestream2_get_ne16(&gb);
for (i = 0; i < l; i++) {
@@ -200,6 +201,16 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
frame_y = AV_RL16(&s->buf[8]);
frame_width = AV_RL16(&s->buf[10]) - frame_x + 1;
frame_height = AV_RL16(&s->buf[12]) - frame_y + 1;
+
+ if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
+ (frame_x || frame_y)) {
+
+ s->x_off = frame_x;
+ s->y_off = frame_y;
+ }
+ frame_x -= s->x_off;
+ frame_y -= s->y_off;
+
if (frame_x < 0 || frame_width < 0 ||
frame_x >= s->avctx->width ||
frame_width > s->avctx->width ||
@@ -219,15 +230,6 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
return AVERROR_INVALIDDATA;
}
- if ((frame_width == s->avctx->width && frame_height == s->avctx->height) &&
- (frame_x || frame_y)) {
-
- s->x_off = frame_x;
- s->y_off = frame_y;
- }
- frame_x -= s->x_off;
- frame_y -= s->y_off;
-
/* if only a certain region will be updated, copy the entire previous
* frame before the decode */
if (s->prev_frame->data[0] &&
@@ -248,13 +250,13 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
r = bytestream2_get_byteu(&gb) * 4;
g = bytestream2_get_byteu(&gb) * 4;
b = bytestream2_get_byteu(&gb) * 4;
- palette32[i] = (r << 16) | (g << 8) | (b);
+ palette32[i] = 0xFFU << 24 | (r << 16) | (g << 8) | (b);
+ palette32[i] |= palette32[i] >> 6 & 0x30303;
}
} else {
av_log(s->avctx, AV_LOG_ERROR, "Incomplete palette\n");
return AVERROR_INVALIDDATA;
}
- s->size -= PALETTE_COUNT * 3 + 2;
}
if (!s->size)
@@ -265,15 +267,18 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
return AVERROR_INVALIDDATA;
meth = bytestream2_get_byteu(&gb);
if (meth & 0x80) {
+ int size;
if (!s->unpack_buffer_size) {
av_log(s->avctx, AV_LOG_ERROR,
"Trying to unpack LZ-compressed frame with no LZ buffer\n");
return AVERROR_INVALIDDATA;
}
- lz_unpack(gb.buffer, bytestream2_get_bytes_left(&gb),
- s->unpack_buffer, s->unpack_buffer_size);
+ size = lz_unpack(gb.buffer, bytestream2_get_bytes_left(&gb),
+ s->unpack_buffer, s->unpack_buffer_size);
+ if (size < 0)
+ return size;
meth &= 0x7F;
- bytestream2_init(&gb, s->unpack_buffer, s->unpack_buffer_size);
+ bytestream2_init(&gb, s->unpack_buffer, size);
}
dp = &frame->data[0][frame_y * frame->linesize[0] + frame_x];
@@ -289,7 +294,7 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
if (ofs + len > frame_width ||
bytestream2_get_bytes_left(&gb) < len)
return AVERROR_INVALIDDATA;
- bytestream2_get_buffer(&gb, &dp[ofs], len);
+ bytestream2_get_bufferu(&gb, &dp[ofs], len);
ofs += len;
} else {
/* interframe pixel copy */
@@ -301,7 +306,7 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
} while (ofs < frame_width);
if (ofs > frame_width) {
av_log(s->avctx, AV_LOG_ERROR,
- "VMD video: offset > width (%d > %d)\n",
+ "offset > width (%d > %d)\n",
ofs, frame_width);
return AVERROR_INVALIDDATA;
}
@@ -334,6 +339,9 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
ofs += slen;
bytestream2_skip(&gb, len);
} else {
+ if (ofs + len > frame_width ||
+ bytestream2_get_bytes_left(&gb) < len)
+ return AVERROR_INVALIDDATA;
bytestream2_get_buffer(&gb, &dp[ofs], len);
ofs += len;
}
@@ -347,7 +355,7 @@ static int vmd_decode(VmdVideoContext *s, AVFrame *frame)
} while (ofs < frame_width);
if (ofs > frame_width) {
av_log(s->avctx, AV_LOG_ERROR,
- "VMD video: offset > width (%d > %d)\n",
+ "offset > width (%d > %d)\n",
ofs, frame_width);
return AVERROR_INVALIDDATA;
}
@@ -364,7 +372,8 @@ static av_cold int vmdvideo_decode_end(AVCodecContext *avctx)
VmdVideoContext *s = avctx->priv_data;
av_frame_free(&s->prev_frame);
- av_free(s->unpack_buffer);
+ av_freep(&s->unpack_buffer);
+ s->unpack_buffer_size = 0;
return 0;
}
@@ -384,9 +393,9 @@ static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
/* make sure the VMD header made it */
if (s->avctx->extradata_size != VMD_HEADER_SIZE) {
- av_log(s->avctx, AV_LOG_ERROR, "VMD video: expected extradata size of %d\n",
+ av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n",
VMD_HEADER_SIZE);
- return -1;
+ return AVERROR_INVALIDDATA;
}
vmd_header = (unsigned char *)avctx->extradata;
@@ -404,7 +413,8 @@ static av_cold int vmdvideo_decode_init(AVCodecContext *avctx)
r = raw_palette[palette_index++] * 4;
g = raw_palette[palette_index++] * 4;
b = raw_palette[palette_index++] * 4;
- palette32[i] = (r << 16) | (g << 8) | (b);
+ palette32[i] = 0xFFU << 24 | (r << 16) | (g << 8) | (b);
+ palette32[i] |= palette32[i] >> 6 & 0x30303;
}
s->prev_frame = av_frame_alloc();
@@ -432,10 +442,8 @@ static int vmdvideo_decode_frame(AVCodecContext *avctx,
if (buf_size < 16)
return AVERROR_INVALIDDATA;
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "VMD Video: get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if ((ret = vmd_decode(s, frame)) < 0)
return ret;
diff --git a/libavcodec/vmnc.c b/libavcodec/vmnc.c
index 23cfe25453..58bd0e26ae 100644
--- a/libavcodec/vmnc.c
+++ b/libavcodec/vmnc.c
@@ -2,20 +2,20 @@
* VMware Screen Codec (VMnc) decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -291,6 +291,11 @@ static int decode_hextile(VmncContext *c, uint8_t* dst, GetByteContext *gb,
fg = vmnc_get_pixel(gb, bpp, c->bigendian);
xy = bytestream2_get_byte(gb);
wh = bytestream2_get_byte(gb);
+ if ( (xy >> 4) + (wh >> 4) + 1 > w - i
+ || (xy & 0xF) + (wh & 0xF)+1 > h - j) {
+ av_log(c->avctx, AV_LOG_ERROR, "Rectangle outside picture\n");
+ return AVERROR_INVALIDDATA;
+ }
paint_rect(dst2, xy >> 4, xy & 0xF,
(wh>>4)+1, (wh & 0xF)+1, fg, bpp, stride);
}
@@ -307,6 +312,8 @@ static void reset_buffers(VmncContext *c)
av_freep(&c->curmask);
av_freep(&c->screendta);
c->cur_w = c->cur_h = 0;
+ c->cur_hx = c->cur_hy = 0;
+
}
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
@@ -319,10 +326,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
uint8_t *outptr;
int dx, dy, w, h, depth, enc, chunks, res, size_left, ret;
- if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
return ret;
- }
bytestream2_init(gb, buf, buf_size);
@@ -360,6 +365,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
bytestream2_skip(gb, 2);
chunks = bytestream2_get_be16(gb);
while (chunks--) {
+ if (bytestream2_get_bytes_left(gb) < 12) {
+ av_log(avctx, AV_LOG_ERROR, "Premature end of data!\n");
+ return -1;
+ }
dx = bytestream2_get_be16(gb);
dy = bytestream2_get_be16(gb);
w = bytestream2_get_be16(gb);
@@ -369,6 +378,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
size_left = bytestream2_get_bytes_left(gb);
switch (enc) {
case MAGIC_WMVd: // cursor
+ if (w*(int64_t)h*c->bpp2 > INT_MAX/2 - 2) {
+ av_log(avctx, AV_LOG_ERROR, "dimensions too large\n");
+ return AVERROR_INVALIDDATA;
+ }
if (size_left < 2 + w * h * c->bpp2 * 2) {
av_log(avctx, AV_LOG_ERROR,
"Premature end of data! (need %i got %i)\n",
@@ -419,18 +432,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
c->pic->pict_type = AV_PICTURE_TYPE_I;
depth = bytestream2_get_byte(gb);
if (depth != c->bpp) {
- av_log(avctx, AV_LOG_WARNING, "Depth mismatch. "
- "Container %i bpp / Codec %i bpp\n", c->bpp, depth);
-
- if (depth != 8 && depth != 16 && depth != 32) {
- av_log(avctx, AV_LOG_ERROR,
- "Unsupported codec bitdepth %i\n", depth);
- return AVERROR_INVALIDDATA;
- }
-
- /* reset values */
- c->bpp = depth;
- c->bpp2 = c->bpp / 8;
+ av_log(avctx, AV_LOG_INFO,
+ "Depth mismatch. Container %i bpp, "
+ "Frame data: %i bpp\n",
+ c->bpp, depth);
}
bytestream2_skip(gb, 1);
c->bigendian = bytestream2_get_byte(gb);
@@ -523,7 +528,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
c->width = avctx->width;
c->height = avctx->height;
c->bpp = avctx->bits_per_coded_sample;
- c->bpp2 = c->bpp / 8;
switch (c->bpp) {
case 8:
@@ -534,14 +538,16 @@ static av_cold int decode_init(AVCodecContext *avctx)
break;
case 24:
/* 24 bits is not technically supported, but some clients might
- * mistakenly set it -- delay the actual check until decode_frame() */
+ * mistakenly set it, so let's assume they actually meant 32 bits */
+ c->bpp = 32;
case 32:
- avctx->pix_fmt = AV_PIX_FMT_RGB32;
+ avctx->pix_fmt = AV_PIX_FMT_0RGB32;
break;
default:
av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", c->bpp);
return AVERROR_INVALIDDATA;
}
+ c->bpp2 = c->bpp / 8;
c->pic = av_frame_alloc();
if (!c->pic)
@@ -556,9 +562,9 @@ static av_cold int decode_end(AVCodecContext *avctx)
av_frame_free(&c->pic);
- av_free(c->curbits);
- av_free(c->curmask);
- av_free(c->screendta);
+ av_freep(&c->curbits);
+ av_freep(&c->curmask);
+ av_freep(&c->screendta);
return 0;
}
diff --git a/libavcodec/vorbis.c b/libavcodec/vorbis.c
index 66fa21b9e1..86d10407f4 100644
--- a/libavcodec/vorbis.c
+++ b/libavcodec/vorbis.c
@@ -1,18 +1,22 @@
-/*
- * This file is part of Libav.
+/**
+ * @file
+ * Common code for Vorbis I encoder and decoder
+ * @author Denes Balatoni ( dbalatoni programozo hu )
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -67,7 +71,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num)
codes[p] = 0;
if (bits[p] > 32)
- return 1;
+ return AVERROR_INVALIDDATA;
for (i = 0; i < bits[p]; ++i)
exit_at_level[i+1] = 1 << i;
@@ -81,9 +85,14 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num)
++p;
+ for (i = p; (bits[i] == 0) && (i < num); ++i)
+ ;
+ if (i == num)
+ return 0;
+
for (; p < num; ++p) {
if (bits[p] > 32)
- return 1;
+ return AVERROR_INVALIDDATA;
if (bits[p] == 0)
continue;
// find corresponding exit(node which the tree can grow further from)
@@ -91,7 +100,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num)
if (exit_at_level[i])
break;
if (!i) // overspecified tree
- return 1;
+ return AVERROR_INVALIDDATA;
code = exit_at_level[i];
exit_at_level[i] = 0;
// construct code (append 0s to end) and introduce new exits
@@ -112,7 +121,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num)
//no exits should be left (underspecified tree - ie. unused valid vlcs - not allowed by SPEC)
for (p = 1; p < 33; p++)
if (exit_at_level[p])
- return 1;
+ return AVERROR_INVALIDDATA;
return 0;
}
diff --git a/libavcodec/vorbis.h b/libavcodec/vorbis.h
index 5ae20ac243..98dd14f9d4 100644
--- a/libavcodec/vorbis.h
+++ b/libavcodec/vorbis.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vorbis_data.c b/libavcodec/vorbis_data.c
index bafb77b1e8..063a075ce0 100644
--- a/libavcodec/vorbis_data.c
+++ b/libavcodec/vorbis_data.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2005 Denes Balatoni ( dbalatoni programozo hu )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vorbis_enc_data.h b/libavcodec/vorbis_enc_data.h
index a1e743ebe5..a51aaec978 100644
--- a/libavcodec/vorbis_enc_data.h
+++ b/libavcodec/vorbis_enc_data.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -492,13 +492,13 @@ static const struct {
int dim;
int subclass;
int masterbook;
- const int *nbooks;
+ const int nbooks[4];
} floor_classes[] = {
- { 3, 0, 0, (const int[]){ 4 } },
- { 4, 1, 0, (const int[]){ 5, 6 } },
- { 3, 1, 1, (const int[]){ 7, 8 } },
- { 4, 2, 2, (const int[]){ -1, 9, 10, 11 } },
- { 3, 2, 3, (const int[]){ -1, 12, 13, 14 } },
+ { 3, 0, 0, { 4 } },
+ { 4, 1, 0, { 5, 6 } },
+ { 3, 1, 1, { 7, 8 } },
+ { 4, 2, 2, { -1, 9, 10, 11 } },
+ { 3, 2, 3, { -1, 12, 13, 14 } },
};
#endif /* AVCODEC_VORBIS_ENC_DATA_H */
diff --git a/libavcodec/vorbis_parser.c b/libavcodec/vorbis_parser.c
index 054635d100..8fa6d99588 100644
--- a/libavcodec/vorbis_parser.c
+++ b/libavcodec/vorbis_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -173,7 +173,7 @@ static int parse_setup_header(AVVorbisParseContext *s,
skip_bits_long(&gb, got_framing_bit);
for (i = mode_count - 1; i >= 0; i--) {
skip_bits_long(&gb, 40);
- s->mode_blocksize[i] = s->blocksize[get_bits1(&gb)];
+ s->mode_blocksize[i] = get_bits1(&gb);
}
bad_header:
@@ -184,7 +184,7 @@ bad_header:
static int vorbis_parse_init(AVVorbisParseContext *s,
const uint8_t *extradata, int extradata_size)
{
- uint8_t *header_start[3];
+ const uint8_t *header_start[3];
int header_len[3];
int ret;
@@ -205,13 +205,13 @@ static int vorbis_parse_init(AVVorbisParseContext *s,
return ret;
s->valid_extradata = 1;
- s->previous_blocksize = s->mode_blocksize[0];
+ s->previous_blocksize = s->blocksize[s->mode_blocksize[0]];
return 0;
}
-int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
- int buf_size)
+int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf,
+ int buf_size, int *flags)
{
int duration = 0;
@@ -220,6 +220,24 @@ int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
int previous_blocksize = s->previous_blocksize;
if (buf[0] & 1) {
+ /* If the user doesn't care about special packets, it's a bad one. */
+ if (!flags)
+ goto bad_packet;
+
+ /* Set the flag for which kind of special packet it is. */
+ if (buf[0] == 1)
+ *flags |= VORBIS_FLAG_HEADER;
+ else if (buf[0] == 3)
+ *flags |= VORBIS_FLAG_COMMENT;
+ else if (buf[0] == 5)
+ *flags |= VORBIS_FLAG_SETUP;
+ else
+ goto bad_packet;
+
+ /* Special packets have no duration. */
+ return 0;
+
+bad_packet:
av_log(s, AV_LOG_ERROR, "Invalid packet\n");
return AVERROR_INVALIDDATA;
}
@@ -231,11 +249,11 @@ int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
av_log(s, AV_LOG_ERROR, "Invalid mode in packet\n");
return AVERROR_INVALIDDATA;
}
- if (mode) {
+ if(s->mode_blocksize[mode]){
int flag = !!(buf[0] & s->prev_mask);
previous_blocksize = s->blocksize[flag];
}
- current_blocksize = s->mode_blocksize[mode];
+ current_blocksize = s->blocksize[s->mode_blocksize[mode]];
duration = (previous_blocksize + current_blocksize) >> 2;
s->previous_blocksize = current_blocksize;
}
@@ -243,10 +261,16 @@ int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
return duration;
}
+int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
+ int buf_size)
+{
+ return av_vorbis_parse_frame_flags(s, buf, buf_size, NULL);
+}
+
void av_vorbis_parse_reset(AVVorbisParseContext *s)
{
if (s->valid_extradata)
- s->previous_blocksize = s->mode_blocksize[0];
+ s->previous_blocksize = s->blocksize[0];
}
void av_vorbis_parse_free(AVVorbisParseContext **s)
@@ -286,6 +310,11 @@ int avpriv_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf,
{
return av_vorbis_parse_frame(s, buf, buf_size);
}
+int avpriv_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf,
+ int buf_size, int *flags)
+{
+ return av_vorbis_parse_frame_flags(s, buf, buf_size, flags);
+}
#endif
#if CONFIG_VORBIS_PARSER
diff --git a/libavcodec/vorbis_parser.h b/libavcodec/vorbis_parser.h
index 9ae1630f9f..06e48bd3b0 100644
--- a/libavcodec/vorbis_parser.h
+++ b/libavcodec/vorbis_parser.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,6 +45,24 @@ AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata,
*/
void av_vorbis_parse_free(AVVorbisParseContext **s);
+#define VORBIS_FLAG_HEADER 0x00000001
+#define VORBIS_FLAG_COMMENT 0x00000002
+#define VORBIS_FLAG_SETUP 0x00000004
+
+/**
+ * Get the duration for a Vorbis packet.
+ *
+ * If @p flags is @c NULL,
+ * special frames are considered invalid.
+ *
+ * @param s Vorbis parser context
+ * @param buf buffer containing a Vorbis frame
+ * @param buf_size size of the buffer
+ * @param flags flags for special frames
+ */
+int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf,
+ int buf_size, int *flags);
+
/**
* Get the duration for a Vorbis packet.
*
diff --git a/libavcodec/vorbis_parser_internal.h b/libavcodec/vorbis_parser_internal.h
index 8f76af706d..49481eeafd 100644
--- a/libavcodec/vorbis_parser_internal.h
+++ b/libavcodec/vorbis_parser_internal.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,6 +56,21 @@ int avpriv_vorbis_parse_extradata(AVCodecContext *avctx, AVVorbisParseContext *s
* Get the duration for a Vorbis packet.
*
* avpriv_vorbis_parse_extradata() must have been successfully called prior to
+ * this in order for a correct duration to be returned. If @p flags is @c NULL,
+ * special frames are considered invalid.
+ *
+ * @param s Vorbis parser context
+ * @param buf buffer containing a Vorbis frame
+ * @param buf_size size of the buffer
+ * @param flags flags for special frames
+ */
+int avpriv_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf,
+ int buf_size, int *flags);
+
+/**
+ * Get the duration for a Vorbis packet.
+ *
+ * avpriv_vorbis_parse_extradata() must have been successfully called prior to
* this in order for a correct duration to be returned.
*
* @param s Vorbis parser context
diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c
index 5812f9a5ac..2926e8e59d 100644
--- a/libavcodec/vorbisdec.c
+++ b/libavcodec/vorbisdec.c
@@ -1,18 +1,22 @@
-/*
- * This file is part of Libav.
+/**
+ * @file
+ * Vorbis I decoder
+ * @author Denes Balatoni ( dbalatoni programozo hu )
+ *
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +31,7 @@
#define BITSTREAM_READER_LE
#include "libavutil/float_dsp.h"
+#include "libavutil/avassert.h"
#include "avcodec.h"
#include "get_bits.h"
#include "fft.h"
@@ -121,7 +126,7 @@ typedef struct vorbis_context_s {
AVCodecContext *avctx;
GetBitContext gb;
VorbisDSPContext dsp;
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
FFTContext mdct[2];
uint8_t first_frame;
@@ -144,7 +149,7 @@ typedef struct vorbis_context_s {
uint8_t mode_count;
vorbis_mode *modes;
uint8_t mode_number; // mode number for the current packet
- uint8_t previous_window;
+ int8_t previous_window;
float *channel_residues;
float *saved;
} vorbis_context;
@@ -186,38 +191,43 @@ static void vorbis_free(vorbis_context *vc)
av_freep(&vc->channel_residues);
av_freep(&vc->saved);
+ av_freep(&vc->fdsp);
- for (i = 0; i < vc->residue_count; i++)
- av_free(vc->residues[i].classifs);
+ if (vc->residues)
+ for (i = 0; i < vc->residue_count; i++)
+ av_freep(&vc->residues[i].classifs);
av_freep(&vc->residues);
av_freep(&vc->modes);
ff_mdct_end(&vc->mdct[0]);
ff_mdct_end(&vc->mdct[1]);
- for (i = 0; i < vc->codebook_count; ++i) {
- av_free(vc->codebooks[i].codevectors);
- ff_free_vlc(&vc->codebooks[i].vlc);
- }
+ if (vc->codebooks)
+ for (i = 0; i < vc->codebook_count; ++i) {
+ av_freep(&vc->codebooks[i].codevectors);
+ ff_free_vlc(&vc->codebooks[i].vlc);
+ }
av_freep(&vc->codebooks);
- for (i = 0; i < vc->floor_count; ++i) {
- if (vc->floors[i].floor_type == 0) {
- av_free(vc->floors[i].data.t0.map[0]);
- av_free(vc->floors[i].data.t0.map[1]);
- av_free(vc->floors[i].data.t0.book_list);
- av_free(vc->floors[i].data.t0.lsp);
- } else {
- av_free(vc->floors[i].data.t1.list);
+ if (vc->floors)
+ for (i = 0; i < vc->floor_count; ++i) {
+ if (vc->floors[i].floor_type == 0) {
+ av_freep(&vc->floors[i].data.t0.map[0]);
+ av_freep(&vc->floors[i].data.t0.map[1]);
+ av_freep(&vc->floors[i].data.t0.book_list);
+ av_freep(&vc->floors[i].data.t0.lsp);
+ } else {
+ av_freep(&vc->floors[i].data.t1.list);
+ }
}
- }
av_freep(&vc->floors);
- for (i = 0; i < vc->mapping_count; ++i) {
- av_free(vc->mappings[i].magnitude);
- av_free(vc->mappings[i].angle);
- av_free(vc->mappings[i].mux);
- }
+ if (vc->mappings)
+ for (i = 0; i < vc->mapping_count; ++i) {
+ av_freep(&vc->mappings[i].magnitude);
+ av_freep(&vc->mappings[i].angle);
+ av_freep(&vc->mappings[i].mux);
+ }
av_freep(&vc->mappings);
}
@@ -369,10 +379,12 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc)
// Weed out unused vlcs and build codevector vector
if (used_entries) {
codebook_setup->codevectors =
- av_mallocz(used_entries * codebook_setup->dimensions *
+ av_mallocz_array(used_entries, codebook_setup->dimensions *
sizeof(*codebook_setup->codevectors));
- if (!codebook_setup->codevectors)
- return AVERROR(ENOMEM);
+ if (!codebook_setup->codevectors) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
} else
codebook_setup->codevectors = NULL;
@@ -555,7 +567,7 @@ static int vorbis_parse_setup_hdr_floors(vorbis_context *vc)
for (j = 0; j < floor_setup->data.t1.partitions; ++j)
floor_setup->data.t1.x_list_dim+=floor_setup->data.t1.class_dimensions[floor_setup->data.t1.partition_class[j]];
- floor_setup->data.t1.list = av_mallocz(floor_setup->data.t1.x_list_dim *
+ floor_setup->data.t1.list = av_mallocz_array(floor_setup->data.t1.x_list_dim,
sizeof(*floor_setup->data.t1.list));
if (!floor_setup->data.t1.list)
return AVERROR(ENOMEM);
@@ -634,8 +646,8 @@ static int vorbis_parse_setup_hdr_floors(vorbis_context *vc)
/* codebook dim is for padding if codebook dim doesn't *
* divide order+1 then we need to read more data */
floor_setup->data.t0.lsp =
- av_malloc((floor_setup->data.t0.order + 1 + max_codebook_dim)
- * sizeof(*floor_setup->data.t0.lsp));
+ av_malloc_array((floor_setup->data.t0.order + 1 + max_codebook_dim),
+ sizeof(*floor_setup->data.t0.lsp));
if (!floor_setup->data.t0.lsp)
return AVERROR(ENOMEM);
@@ -695,8 +707,7 @@ static int vorbis_parse_setup_hdr_residues(vorbis_context *vc)
res_setup->partition_size = get_bits(gb, 24) + 1;
/* Validations to prevent a buffer overflow later. */
if (res_setup->begin>res_setup->end ||
- res_setup->end > (res_setup->type == 2 ? vc->avctx->channels : 1) * vc->blocksize[1] / 2 ||
- (res_setup->end-res_setup->begin) / res_setup->partition_size > V_MAX_PARTITIONS) {
+ (res_setup->end-res_setup->begin) / res_setup->partition_size > FFMIN(V_MAX_PARTITIONS, 65535)) {
av_log(vc->avctx, AV_LOG_ERROR,
"partition out of bounds: type, begin, end, size, blocksize: %"PRIu16", %"PRIu32", %"PRIu32", %u, %"PRIu32"\n",
res_setup->type, res_setup->begin, res_setup->end,
@@ -709,7 +720,7 @@ static int vorbis_parse_setup_hdr_residues(vorbis_context *vc)
res_setup->ptns_to_read =
(res_setup->end - res_setup->begin) / res_setup->partition_size;
- res_setup->classifs = av_malloc(res_setup->ptns_to_read *
+ res_setup->classifs = av_malloc_array(res_setup->ptns_to_read,
vc->audio_channels *
sizeof(*res_setup->classifs));
if (!res_setup->classifs)
@@ -802,7 +813,7 @@ static int vorbis_parse_setup_hdr_mappings(vorbis_context *vc)
}
if (mapping_setup->submaps>1) {
- mapping_setup->mux = av_mallocz(vc->audio_channels *
+ mapping_setup->mux = av_mallocz_array(vc->audio_channels,
sizeof(*mapping_setup->mux));
if (!mapping_setup->mux)
return AVERROR(ENOMEM);
@@ -837,7 +848,7 @@ static int create_map(vorbis_context *vc, unsigned floor_number)
for (blockflag = 0; blockflag < 2; ++blockflag) {
n = vc->blocksize[blockflag] / 2;
floors[floor_number].data.t0.map[blockflag] =
- av_malloc((n + 1) * sizeof(int32_t)); // n + sentinel
+ av_malloc_array(n + 1, sizeof(int32_t)); // n + sentinel
if (!floors[floor_number].data.t0.map[blockflag])
return AVERROR(ENOMEM);
@@ -964,12 +975,12 @@ static int vorbis_parse_id_hdr(vorbis_context *vc)
vc->bitrate_minimum = get_bits_long(gb, 32);
bl0 = get_bits(gb, 4);
bl1 = get_bits(gb, 4);
- vc->blocksize[0] = (1 << bl0);
- vc->blocksize[1] = (1 << bl1);
if (bl0 > 13 || bl0 < 6 || bl1 > 13 || bl1 < 6 || bl1 < bl0) {
av_log(vc->avctx, AV_LOG_ERROR, " Vorbis id header packet corrupt (illegal blocksize). \n");
return AVERROR_INVALIDDATA;
}
+ vc->blocksize[0] = (1 << bl0);
+ vc->blocksize[1] = (1 << bl1);
vc->win[0] = ff_vorbis_vwin[bl0 - 6];
vc->win[1] = ff_vorbis_vwin[bl1 - 6];
@@ -978,15 +989,18 @@ static int vorbis_parse_id_hdr(vorbis_context *vc)
return AVERROR_INVALIDDATA;
}
- vc->channel_residues = av_malloc((vc->blocksize[1] / 2) * vc->audio_channels * sizeof(*vc->channel_residues));
- vc->saved = av_mallocz((vc->blocksize[1] / 4) * vc->audio_channels * sizeof(*vc->saved));
+ vc->channel_residues = av_malloc_array(vc->blocksize[1] / 2, vc->audio_channels * sizeof(*vc->channel_residues));
+ vc->saved = av_mallocz_array(vc->blocksize[1] / 4, vc->audio_channels * sizeof(*vc->saved));
if (!vc->channel_residues || !vc->saved)
return AVERROR(ENOMEM);
- vc->previous_window = 0;
+ vc->previous_window = -1;
ff_mdct_init(&vc->mdct[0], bl0, 1, -1.0);
ff_mdct_init(&vc->mdct[1], bl1, 1, -1.0);
+ vc->fdsp = avpriv_float_dsp_alloc(vc->avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!vc->fdsp)
+ return AVERROR(ENOMEM);
ff_dlog(NULL, " vorbis version %d \n audio_channels %d \n audio_samplerate %d \n bitrate_max %d \n bitrate_nom %d \n bitrate_min %d \n blk_0 %d blk_1 %d \n ",
vc->version, vc->audio_channels, vc->audio_samplerate, vc->bitrate_maximum, vc->bitrate_nominal, vc->bitrate_minimum, vc->blocksize[0], vc->blocksize[1]);
@@ -1008,14 +1022,13 @@ static av_cold int vorbis_decode_init(AVCodecContext *avctx)
vorbis_context *vc = avctx->priv_data;
uint8_t *headers = avctx->extradata;
int headers_len = avctx->extradata_size;
- uint8_t *header_start[3];
+ const uint8_t *header_start[3];
int header_len[3];
GetBitContext *gb = &vc->gb;
int hdr_type, ret;
vc->avctx = avctx;
ff_vorbisdsp_init(&vc->dsp);
- avpriv_float_dsp_init(&vc->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
@@ -1187,7 +1200,7 @@ static int vorbis_floor1_decode(vorbis_context *vc,
uint16_t floor1_Y[258];
uint16_t floor1_Y_final[258];
int floor1_flag[258];
- unsigned class, cdim, cbits, csub, cval, offset, i, j;
+ unsigned partition_class, cdim, cbits, csub, cval, offset, i, j;
int book, adx, ady, dy, off, predicted, err;
@@ -1203,28 +1216,31 @@ static int vorbis_floor1_decode(vorbis_context *vc,
offset = 2;
for (i = 0; i < vf->partitions; ++i) {
- class = vf->partition_class[i];
- cdim = vf->class_dimensions[class];
- cbits = vf->class_subclasses[class];
+ partition_class = vf->partition_class[i];
+ cdim = vf->class_dimensions[partition_class];
+ cbits = vf->class_subclasses[partition_class];
csub = (1 << cbits) - 1;
cval = 0;
ff_dlog(NULL, "Cbits %u\n", cbits);
if (cbits) // this reads all subclasses for this partition's class
- cval = get_vlc2(gb, vc->codebooks[vf->class_masterbook[class]].vlc.table,
- vc->codebooks[vf->class_masterbook[class]].nb_bits, 3);
+ cval = get_vlc2(gb, vc->codebooks[vf->class_masterbook[partition_class]].vlc.table,
+ vc->codebooks[vf->class_masterbook[partition_class]].nb_bits, 3);
for (j = 0; j < cdim; ++j) {
- book = vf->subclass_books[class][cval & csub];
+ book = vf->subclass_books[partition_class][cval & csub];
ff_dlog(NULL, "book %d Cbits %u cval %u bits:%d\n",
book, cbits, cval, get_bits_count(gb));
cval = cval >> cbits;
if (book > -1) {
- floor1_Y[offset+j] = get_vlc2(gb, vc->codebooks[book].vlc.table,
- vc->codebooks[book].nb_bits, 3);
+ int v = get_vlc2(gb, vc->codebooks[book].vlc.table,
+ vc->codebooks[book].nb_bits, 3);
+ if (v < 0)
+ return AVERROR_INVALIDDATA;
+ floor1_Y[offset+j] = v;
} else {
floor1_Y[offset+j] = 0;
}
@@ -1305,7 +1321,9 @@ static av_always_inline int setup_classifs(vorbis_context *vc,
vorbis_residue *vr,
uint8_t *do_not_decode,
unsigned ch_used,
- int partition_count)
+ int partition_count,
+ int ptns_to_read
+ )
{
vorbis_codebook *codebook = vc->codebooks + vr->classbook;
int p, j, i;
@@ -1319,21 +1337,25 @@ static av_always_inline int setup_classifs(vorbis_context *vc,
ff_dlog(NULL, "Classword: %u\n", temp);
+ av_assert0(temp < 65536);
+
if (temp < 0) {
av_log(vc->avctx, AV_LOG_ERROR,
"Invalid vlc code decoding %d channel.", j);
return AVERROR_INVALIDDATA;
}
+ av_assert0(vr->classifications > 1); //needed for inverse[]
+
for (i = partition_count + c_p_c - 1; i >= partition_count; i--) {
temp2 = (((uint64_t)temp) * inverse_class) >> 32;
- if (i < vr->ptns_to_read)
+ if (i < ptns_to_read)
vr->classifs[p + i] = temp - temp2 * vr->classifications;
temp = temp2;
}
}
- p += vr->ptns_to_read;
+ p += ptns_to_read;
}
return 0;
}
@@ -1354,6 +1376,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc,
unsigned pass, ch_used, i, j, k, l;
unsigned max_output = (ch - 1) * vlen;
int ptns_to_read = vr->ptns_to_read;
+ int libvorbis_bug = 0;
if (vr_type == 2) {
for (j = 1; j < ch; ++j)
@@ -1368,8 +1391,13 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc,
}
if (max_output > ch_left * vlen) {
- av_log(vc->avctx, AV_LOG_ERROR, "Insufficient output buffer\n");
- return AVERROR_INVALIDDATA;
+ if (max_output <= ch_left * vlen + vr->partition_size*ch_used/ch) {
+ ptns_to_read--;
+ libvorbis_bug = 1;
+ } else {
+ av_log(vc->avctx, AV_LOG_ERROR, "Insufficient output buffer\n");
+ return AVERROR_INVALIDDATA;
+ }
}
ff_dlog(NULL, " residue type 0/1/2 decode begin, ch: %d cpc %d \n", ch, c_p_c);
@@ -1380,7 +1408,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc,
voffset = vr->begin;
for (partition_count = 0; partition_count < ptns_to_read;) { // SPEC error
if (!pass) {
- int ret = setup_classifs(vc, vr, do_not_decode, ch_used, partition_count);
+ int ret = setup_classifs(vc, vr, do_not_decode, ch_used, partition_count, ptns_to_read);
if (ret < 0)
return ret;
}
@@ -1478,6 +1506,14 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc,
voffset += vr->partition_size;
}
}
+ if (libvorbis_bug && !pass) {
+ for (j = 0; j < ch_used; ++j) {
+ if (!do_not_decode[j]) {
+ get_vlc2(&vc->gb, vc->codebooks[vr->classbook].vlc.table,
+ vc->codebooks[vr->classbook].nb_bits, 3);
+ }
+ }
+ }
}
return 0;
}
@@ -1530,7 +1566,7 @@ static int vorbis_parse_audio_packet(vorbis_context *vc, float **floor_ptr)
{
GetBitContext *gb = &vc->gb;
FFTContext *mdct;
- unsigned previous_window = vc->previous_window;
+ int previous_window = vc->previous_window;
unsigned mode_number, blockflag, blocksize;
int i, j;
uint8_t no_residue[255];
@@ -1563,9 +1599,11 @@ static int vorbis_parse_audio_packet(vorbis_context *vc, float **floor_ptr)
blocksize = vc->blocksize[blockflag];
vlen = blocksize / 2;
if (blockflag) {
- previous_window = get_bits(gb, 1);
- skip_bits1(gb); // next_window
- }
+ int code = get_bits(gb, 2);
+ if (previous_window < 0)
+ previous_window = code>>1;
+ } else if (previous_window < 0)
+ previous_window = 0;
memset(ch_res_ptr, 0, sizeof(float) * vc->audio_channels * vlen); //FIXME can this be removed ?
for (i = 0; i < vc->audio_channels; ++i)
@@ -1653,7 +1691,7 @@ static int vorbis_parse_audio_packet(vorbis_context *vc, float **floor_ptr)
for (j = vc->audio_channels-1;j >= 0; j--) {
ch_res_ptr = vc->channel_residues + res_chan[j] * blocksize / 2;
- vc->fdsp.vector_fmul(floor_ptr[j], floor_ptr[j], ch_res_ptr, blocksize / 2);
+ vc->fdsp->vector_fmul(floor_ptr[j], floor_ptr[j], ch_res_ptr, blocksize / 2);
mdct->imdct_half(mdct, ch_res_ptr, floor_ptr[j]);
}
@@ -1670,13 +1708,13 @@ static int vorbis_parse_audio_packet(vorbis_context *vc, float **floor_ptr)
const float *win = vc->win[blockflag & previous_window];
if (blockflag == previous_window) {
- vc->fdsp.vector_fmul_window(ret, saved, buf, win, blocksize / 4);
+ vc->fdsp->vector_fmul_window(ret, saved, buf, win, blocksize / 4);
} else if (blockflag > previous_window) {
- vc->fdsp.vector_fmul_window(ret, saved, buf, win, bs0 / 4);
+ vc->fdsp->vector_fmul_window(ret, saved, buf, win, bs0 / 4);
memcpy(ret+bs0/2, buf+bs0/4, ((bs1-bs0)/4) * sizeof(float));
} else {
memcpy(ret, saved, ((bs1 - bs0) / 4) * sizeof(float));
- vc->fdsp.vector_fmul_window(ret + (bs1 - bs0) / 4, saved + (bs1 - bs0) / 4, buf, win, bs0 / 4);
+ vc->fdsp->vector_fmul_window(ret + (bs1 - bs0) / 4, saved + (bs1 - bs0) / 4, buf, win, bs0 / 4);
}
memcpy(saved, buf + blocksize / 4, blocksize / 4 * sizeof(float));
}
@@ -1700,12 +1738,49 @@ static int vorbis_decode_frame(AVCodecContext *avctx, void *data,
ff_dlog(NULL, "packet length %d \n", buf_size);
+ if (*buf == 1 && buf_size > 7) {
+ init_get_bits(gb, buf+1, buf_size*8 - 8);
+ vorbis_free(vc);
+ if ((ret = vorbis_parse_id_hdr(vc))) {
+ av_log(avctx, AV_LOG_ERROR, "Id header corrupt.\n");
+ vorbis_free(vc);
+ return ret;
+ }
+
+ if (vc->audio_channels > 8)
+ avctx->channel_layout = 0;
+ else
+ avctx->channel_layout = ff_vorbis_channel_layouts[vc->audio_channels - 1];
+
+ avctx->channels = vc->audio_channels;
+ avctx->sample_rate = vc->audio_samplerate;
+ return buf_size;
+ }
+
+ if (*buf == 3 && buf_size > 7) {
+ av_log(avctx, AV_LOG_DEBUG, "Ignoring comment header\n");
+ return buf_size;
+ }
+
+ if (*buf == 5 && buf_size > 7 && vc->channel_residues && !vc->modes) {
+ init_get_bits(gb, buf+1, buf_size*8 - 8);
+ if ((ret = vorbis_parse_setup_hdr(vc))) {
+ av_log(avctx, AV_LOG_ERROR, "Setup header corrupt.\n");
+ vorbis_free(vc);
+ return ret;
+ }
+ return buf_size;
+ }
+
+ if (!vc->channel_residues || !vc->modes) {
+ av_log(avctx, AV_LOG_ERROR, "Data packet before valid headers\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* get output buffer */
frame->nb_samples = vc->blocksize[1] / 2;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
if (vc->audio_channels > 8) {
for (i = 0; i < vc->audio_channels; i++)
@@ -1757,7 +1832,8 @@ static av_cold void vorbis_decode_flush(AVCodecContext *avctx)
memset(vc->saved, 0, (vc->blocksize[1] / 4) * vc->audio_channels *
sizeof(*vc->saved));
}
- vc->previous_window = 0;
+ vc->previous_window = -1;
+ vc->first_frame = 0;
}
AVCodec ff_vorbis_decoder = {
diff --git a/libavcodec/vorbisdsp.c b/libavcodec/vorbisdsp.c
index c37e2c4124..362a276296 100644
--- a/libavcodec/vorbisdsp.c
+++ b/libavcodec/vorbisdsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vorbisdsp.h b/libavcodec/vorbisdsp.h
index ea41c401ce..7abec4e4b7 100644
--- a/libavcodec/vorbisdsp.h
+++ b/libavcodec/vorbisdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c
index 12a97bc058..dcb2a6e557 100644
--- a/libavcodec/vorbisenc.c
+++ b/libavcodec/vorbisenc.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -142,9 +142,9 @@ typedef struct vorbis_enc_context {
static inline int put_codeword(PutBitContext *pb, vorbis_enc_codebook *cb,
int entry)
{
- assert(entry >= 0);
- assert(entry < cb->nentries);
- assert(cb->lens[entry]);
+ av_assert2(entry >= 0);
+ av_assert2(entry < cb->nentries);
+ av_assert2(cb->lens[entry]);
if (pb->size_in_bits - put_bits_count(pb) < cb->lens[entry])
return AVERROR(EINVAL);
put_bits(pb, cb->lens[entry], cb->codewords[entry]);
@@ -170,8 +170,8 @@ static int ready_codebook(vorbis_enc_codebook *cb)
cb->pow2 = cb->dimensions = NULL;
} else {
int vals = cb_lookup_vals(cb->lookup, cb->ndimensions, cb->nentries);
- cb->dimensions = av_malloc(sizeof(float) * cb->nentries * cb->ndimensions);
- cb->pow2 = av_mallocz(sizeof(float) * cb->nentries);
+ cb->dimensions = av_malloc_array(cb->nentries, sizeof(float) * cb->ndimensions);
+ cb->pow2 = av_mallocz_array(cb->nentries, sizeof(float));
if (!cb->dimensions || !cb->pow2)
return AVERROR(ENOMEM);
for (i = 0; i < cb->nentries; i++) {
@@ -200,8 +200,8 @@ static int ready_codebook(vorbis_enc_codebook *cb)
static int ready_residue(vorbis_enc_residue *rc, vorbis_enc_context *venc)
{
int i;
- assert(rc->type == 2);
- rc->maxes = av_mallocz(sizeof(float[2]) * rc->classifications);
+ av_assert0(rc->type == 2);
+ rc->maxes = av_mallocz_array(rc->classifications, sizeof(float[2]));
if (!rc->maxes)
return AVERROR(ENOMEM);
for (i = 0; i < rc->classifications; i++) {
@@ -266,8 +266,8 @@ static int create_vorbis_context(vorbis_enc_context *venc,
cb->lookup = cvectors[book].lookup;
cb->seq_p = 0;
- cb->lens = av_malloc(sizeof(uint8_t) * cb->nentries);
- cb->codewords = av_malloc(sizeof(uint32_t) * cb->nentries);
+ cb->lens = av_malloc_array(cb->nentries, sizeof(uint8_t));
+ cb->codewords = av_malloc_array(cb->nentries, sizeof(uint32_t));
if (!cb->lens || !cb->codewords)
return AVERROR(ENOMEM);
memcpy(cb->lens, cvectors[book].clens, cvectors[book].len);
@@ -275,7 +275,7 @@ static int create_vorbis_context(vorbis_enc_context *venc,
if (cb->lookup) {
vals = cb_lookup_vals(cb->lookup, cb->ndimensions, cb->nentries);
- cb->quantlist = av_malloc(sizeof(int) * vals);
+ cb->quantlist = av_malloc_array(vals, sizeof(int));
if (!cb->quantlist)
return AVERROR(ENOMEM);
for (i = 0; i < vals; i++)
@@ -305,7 +305,7 @@ static int create_vorbis_context(vorbis_enc_context *venc,
fc->nclasses = FFMAX(fc->nclasses, fc->partition_to_class[i]);
}
fc->nclasses++;
- fc->classes = av_malloc(sizeof(vorbis_enc_floor_class) * fc->nclasses);
+ fc->classes = av_malloc_array(fc->nclasses, sizeof(vorbis_enc_floor_class));
if (!fc->classes)
return AVERROR(ENOMEM);
for (i = 0; i < fc->nclasses; i++) {
@@ -315,7 +315,7 @@ static int create_vorbis_context(vorbis_enc_context *venc,
c->subclass = floor_classes[i].subclass;
c->masterbook = floor_classes[i].masterbook;
books = (1 << c->subclass);
- c->books = av_malloc(sizeof(int) * books);
+ c->books = av_malloc_array(books, sizeof(int));
if (!c->books)
return AVERROR(ENOMEM);
for (j = 0; j < books; j++)
@@ -328,7 +328,7 @@ static int create_vorbis_context(vorbis_enc_context *venc,
for (i = 0; i < fc->partitions; i++)
fc->values += fc->classes[fc->partition_to_class[i]].dim;
- fc->list = av_malloc(sizeof(vorbis_floor1_entry) * fc->values);
+ fc->list = av_malloc_array(fc->values, sizeof(vorbis_floor1_entry));
if (!fc->list)
return AVERROR(ENOMEM);
fc->list[0].x = 0;
@@ -419,10 +419,10 @@ static int create_vorbis_context(vorbis_enc_context *venc,
venc->modes[0].mapping = 0;
venc->have_saved = 0;
- venc->saved = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2);
- venc->samples = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]));
- venc->floor = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2);
- venc->coeffs = av_malloc(sizeof(float) * venc->channels * (1 << venc->log2_blocksize[1]) / 2);
+ venc->saved = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2);
+ venc->samples = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]));
+ venc->floor = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2);
+ venc->coeffs = av_malloc_array(sizeof(float) * venc->channels, (1 << venc->log2_blocksize[1]) / 2);
if (!venc->saved || !venc->samples || !venc->floor || !venc->coeffs)
return AVERROR(ENOMEM);
@@ -585,9 +585,11 @@ static int put_main_header(vorbis_enc_context *venc, uint8_t **out)
{
int i;
PutBitContext pb;
- uint8_t buffer[50000] = {0}, *p = buffer;
- int buffer_len = sizeof buffer;
int len, hlens[3];
+ int buffer_len = 50000;
+ uint8_t *buffer = av_mallocz(buffer_len), *p = buffer;
+ if (!buffer)
+ return AVERROR(ENOMEM);
// identification header
init_put_bits(&pb, p, buffer_len);
@@ -710,6 +712,7 @@ static int put_main_header(vorbis_enc_context *venc, uint8_t **out)
buffer_len += hlens[i];
}
+ av_freep(&buffer);
return p - *out;
}
@@ -880,8 +883,8 @@ static int residue_encode(vorbis_enc_context *venc, vorbis_enc_residue *rc,
int classes[MAX_CHANNELS][NUM_RESIDUE_PARTITIONS];
int classwords = venc->codebooks[rc->classbook].ndimensions;
- assert(rc->type == 2);
- assert(real_ch == 2);
+ av_assert0(rc->type == 2);
+ av_assert0(real_ch == 2);
for (p = 0; p < partitions; p++) {
float max1 = 0.0, max2 = 0.0;
int s = rc->begin + p * psize;
@@ -1015,7 +1018,6 @@ static int apply_window_and_mdct(vorbis_enc_context *venc,
return 1;
}
-
static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
@@ -1031,10 +1033,8 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
return 0;
samples = 1 << (venc->log2_blocksize[0] - 1);
- if ((ret = ff_alloc_packet(avpkt, 8192))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 8192)) < 0)
return ret;
- }
init_put_bits(&pb, avpkt->data, avpkt->size);
@@ -1170,7 +1170,7 @@ static av_cold int vorbis_encode_init(AVCodecContext *avctx)
int ret;
if (avctx->channels != 2) {
- av_log(avctx, AV_LOG_ERROR, "Current Libav Vorbis encoder only supports 2 channels.\n");
+ av_log(avctx, AV_LOG_ERROR, "Current FFmpeg Vorbis encoder only supports 2 channels.\n");
return -1;
}
@@ -1181,7 +1181,7 @@ static av_cold int vorbis_encode_init(AVCodecContext *avctx)
if (avctx->flags & CODEC_FLAG_QSCALE)
venc->quality = avctx->global_quality / (float)FF_QP2LAMBDA;
else
- venc->quality = 3.0;
+ venc->quality = 8;
venc->quality *= venc->quality;
if ((ret = put_main_header(venc, (uint8_t**)&avctx->extradata)) < 0)
diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c
index c48d92737c..005f043b0f 100644
--- a/libavcodec/vp3.c
+++ b/libavcodec/vp3.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2003-2004 the ffmpeg project
+ * Copyright (c) 2003-2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -77,6 +77,10 @@ typedef struct Vp3Fragment {
/* special internal mode */
#define MODE_COPY 8
+static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb);
+static int theora_decode_tables(AVCodecContext *avctx, GetBitContext *gb);
+
+
/* There are 6 preset schemes, plus a free-form scheme */
static const int ModeAlphabet[6][CODING_MODE_COUNT] = {
/* scheme 1: Last motion vector dominates */
@@ -173,6 +177,7 @@ typedef struct Vp3DecodeContext {
int data_offset[3];
uint8_t offset_x;
uint8_t offset_y;
+ int offset_x_warned;
int8_t (*motion_val[2])[2];
@@ -260,6 +265,20 @@ typedef struct Vp3DecodeContext {
* VP3 specific functions
************************************************************************/
+static av_cold void free_tables(AVCodecContext *avctx)
+{
+ Vp3DecodeContext *s = avctx->priv_data;
+
+ av_freep(&s->superblock_coding);
+ av_freep(&s->all_fragments);
+ av_freep(&s->coded_fragment_list[0]);
+ av_freep(&s->dct_tokens_base);
+ av_freep(&s->superblock_fragments);
+ av_freep(&s->macroblock_coding);
+ av_freep(&s->motion_val[0]);
+ av_freep(&s->motion_val[1]);
+}
+
static void vp3_decode_flush(AVCodecContext *avctx)
{
Vp3DecodeContext *s = avctx->priv_data;
@@ -277,16 +296,11 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
Vp3DecodeContext *s = avctx->priv_data;
int i;
- av_freep(&s->superblock_coding);
- av_freep(&s->all_fragments);
- av_freep(&s->coded_fragment_list[0]);
- av_freep(&s->dct_tokens_base);
- av_freep(&s->superblock_fragments);
- av_freep(&s->macroblock_coding);
- av_freep(&s->motion_val[0]);
- av_freep(&s->motion_val[1]);
+ free_tables(avctx);
av_freep(&s->edge_emu_buffer);
+ s->theora_tables = 0;
+
/* release all frames */
vp3_decode_flush(avctx);
av_frame_free(&s->current_frame.f);
@@ -312,7 +326,7 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
return 0;
}
-/*
+/**
* This function sets up all of the various blocks mappings:
* superblocks <-> fragments, macroblocks <-> fragments,
* superblocks <-> macroblocks
@@ -403,7 +417,7 @@ static void init_loop_filter(Vp3DecodeContext *s)
int value;
filter_limit = s->filter_limit_values[s->qps[0]];
- assert(filter_limit < 128);
+ av_assert0(filter_limit < 128U);
/* set up the bounding values */
memset(s->bounding_values_array, 0, 256 * sizeof(int));
@@ -456,7 +470,7 @@ static int unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb)
if (current_run == 34)
current_run += get_bits(gb, 12);
- if (current_superblock + current_run > s->superblock_count) {
+ if (current_run > s->superblock_count - current_superblock) {
av_log(s->avctx, AV_LOG_ERROR,
"Invalid partially coded superblock run length\n");
return -1;
@@ -1021,7 +1035,7 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
if (blocks_ended > s->num_coded_frags[plane][coeff_index])
av_log(s->avctx, AV_LOG_ERROR, "More blocks ended than coded!\n");
- // decrement the number of blocks that have higher coeffecients for each
+ // decrement the number of blocks that have higher coefficients for each
// EOB run at this level
if (blocks_ended)
for (i = coeff_index + 1; i < 64; i++)
@@ -1600,20 +1614,14 @@ static void render_slice(Vp3DecodeContext *s, int slice)
/* invert DCT and place (or add) in final output */
if (s->all_fragments[i].coding_method == MODE_INTRA) {
- int index;
- index = vp3_dequant(s, s->all_fragments + i,
- plane, 0, block);
- if (index > 63)
- continue;
+ vp3_dequant(s, s->all_fragments + i,
+ plane, 0, block);
s->vp3dsp.idct_put(output_plane + first_pixel,
stride,
block);
} else {
- int index = vp3_dequant(s, s->all_fragments + i,
- plane, 1, block);
- if (index > 63)
- continue;
- if (index > 0) {
+ if (vp3_dequant(s, s->all_fragments + i,
+ plane, 1, block)) {
s->vp3dsp.idct_add(output_plane + first_pixel,
stride,
block);
@@ -1657,22 +1665,24 @@ static av_cold int allocate_tables(AVCodecContext *avctx)
Vp3DecodeContext *s = avctx->priv_data;
int y_fragment_count, c_fragment_count;
+ free_tables(avctx);
+
y_fragment_count = s->fragment_width[0] * s->fragment_height[0];
c_fragment_count = s->fragment_width[1] * s->fragment_height[1];
- s->superblock_coding = av_malloc(s->superblock_count);
- s->all_fragments = av_malloc(s->fragment_count * sizeof(Vp3Fragment));
+ s->superblock_coding = av_mallocz(s->superblock_count);
+ s->all_fragments = av_mallocz_array(s->fragment_count, sizeof(Vp3Fragment));
- s->coded_fragment_list[0] = av_malloc(s->fragment_count * sizeof(int));
+ s->coded_fragment_list[0] = av_mallocz_array(s->fragment_count, sizeof(int));
- s->dct_tokens_base = av_malloc(64 * s->fragment_count *
- sizeof(*s->dct_tokens_base));
- s->motion_val[0] = av_malloc(y_fragment_count * sizeof(*s->motion_val[0]));
- s->motion_val[1] = av_malloc(c_fragment_count * sizeof(*s->motion_val[1]));
+ s->dct_tokens_base = av_mallocz_array(s->fragment_count,
+ 64 * sizeof(*s->dct_tokens_base));
+ s->motion_val[0] = av_mallocz_array(y_fragment_count, sizeof(*s->motion_val[0]));
+ s->motion_val[1] = av_mallocz_array(c_fragment_count, sizeof(*s->motion_val[1]));
/* work out the block mapping tables */
- s->superblock_fragments = av_malloc(s->superblock_count * 16 * sizeof(int));
- s->macroblock_coding = av_malloc(s->macroblock_count + 1);
+ s->superblock_fragments = av_mallocz_array(s->superblock_count, 16 * sizeof(int));
+ s->macroblock_coding = av_mallocz(s->macroblock_count + 1);
if (!s->superblock_coding || !s->all_fragments ||
!s->dct_tokens_base || !s->coded_fragment_list[0] ||
@@ -1725,7 +1735,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
s->avctx = avctx;
s->width = FFALIGN(avctx->coded_width, 16);
s->height = FFALIGN(avctx->coded_height, 16);
- if (avctx->pix_fmt == AV_PIX_FMT_NONE)
+ if (avctx->codec_id != AV_CODEC_ID_THEORA)
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
ff_hpeldsp_init(&s->hdsp, avctx->flags | CODEC_FLAG_BITEXACT);
@@ -1733,7 +1743,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
ff_vp3dsp_init(&s->vp3dsp, avctx->flags);
for (i = 0; i < 64; i++) {
-#define TRANSPOSE(x) (x >> 3) | ((x & 7) << 3)
+#define TRANSPOSE(x) (((x) >> 3) | (((x) & 7) << 3))
s->idct_permutation[i] = TRANSPOSE(i);
s->idct_scantable[i] = TRANSPOSE(ff_zigzag_direct[i]);
#undef TRANSPOSE
@@ -1744,8 +1754,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
for (i = 0; i < 3; i++)
s->qps[i] = -1;
- av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift,
- &s->chroma_y_shift);
+ avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift);
s->y_superblock_width = (s->width + 31) / 32;
s->y_superblock_height = (s->height + 31) / 32;
@@ -1989,15 +1998,47 @@ static int vp3_decode_frame(AVCodecContext *avctx,
GetBitContext gb;
int i, ret;
- init_get_bits(&gb, buf, buf_size * 8);
+ if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0)
+ return ret;
+#if CONFIG_THEORA_DECODER
if (s->theora && get_bits1(&gb)) {
+ int type = get_bits(&gb, 7);
+ skip_bits_long(&gb, 6*8); /* "theora" */
+
+ if (s->avctx->active_thread_type&FF_THREAD_FRAME) {
+ av_log(avctx, AV_LOG_ERROR, "midstream reconfiguration with multithreading is unsupported, try -threads 1\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (type == 0) {
+ vp3_decode_end(avctx);
+ ret = theora_decode_header(avctx, &gb);
+
+ if (ret < 0) {
+ vp3_decode_end(avctx);
+ } else
+ ret = vp3_decode_init(avctx);
+ return ret;
+ } else if (type == 2) {
+ ret = theora_decode_tables(avctx, &gb);
+ if (ret < 0) {
+ vp3_decode_end(avctx);
+ } else
+ ret = vp3_decode_init(avctx);
+ return ret;
+ }
+
av_log(avctx, AV_LOG_ERROR,
"Header packet passed to frame decoder, skipping\n");
return -1;
}
+#endif
s->keyframe = !get_bits1(&gb);
+ if (!s->all_fragments) {
+ av_log(avctx, AV_LOG_ERROR, "Data packet without prior valid headers\n");
+ return -1;
+ }
if (!s->theora)
skip_bits(&gb, 1);
for (i = 0; i < 3; i++)
@@ -2032,10 +2073,9 @@ static int vp3_decode_frame(AVCodecContext *avctx,
s->current_frame.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I
: AV_PICTURE_TYPE_P;
- if (ff_thread_get_buffer(avctx, &s->current_frame, AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ s->current_frame.f->key_frame = s->keyframe;
+ if (ff_thread_get_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]));
@@ -2064,10 +2104,8 @@ static int vp3_decode_frame(AVCodecContext *avctx,
s->golden_frame.f->pict_type = AV_PICTURE_TYPE_I;
if (ff_thread_get_buffer(avctx, &s->golden_frame,
- AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ AV_GET_BUFFER_FLAG_REF) < 0)
goto error;
- }
ff_thread_release_buffer(avctx, &s->last_frame);
if ((ret = ff_thread_ref_frame(&s->last_frame,
&s->golden_frame)) < 0)
@@ -2239,7 +2277,7 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb)
if (av_image_check_size(visible_width, visible_height, 0, avctx) < 0 ||
visible_width + offset_x > s->width ||
visible_height + offset_y > s->height) {
- av_log(s, AV_LOG_ERROR,
+ av_log(avctx, AV_LOG_ERROR,
"Invalid frame dimensions - w:%d h:%d x:%d y:%d (%dx%d).\n",
visible_width, visible_height, offset_x, offset_y,
s->width, s->height);
@@ -2276,14 +2314,17 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb)
if (s->theora >= 0x030200) {
skip_bits(gb, 5); /* keyframe frequency force */
avctx->pix_fmt = theora_pix_fmts[get_bits(gb, 2)];
+ if (avctx->pix_fmt == AV_PIX_FMT_NONE) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid pixel format\n");
+ return AVERROR_INVALIDDATA;
+ }
skip_bits(gb, 3); /* reserved */
}
ret = ff_set_dimensions(avctx, s->width, s->height);
if (ret < 0)
return ret;
- if (!(avctx->flags2 & CODEC_FLAG2_IGNORE_CROP) &&
- (visible_width != s->width || visible_height != s->height)) {
+ if (!(avctx->flags2 & CODEC_FLAG2_IGNORE_CROP)) {
avctx->width = visible_width;
avctx->height = visible_height;
// translate offsets from theora axis ([0,0] lower left)
@@ -2293,9 +2334,12 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb)
if ((s->offset_x & 0x1F) && !(avctx->flags & CODEC_FLAG_UNALIGNED)) {
s->offset_x &= ~0x1F;
- av_log(avctx, AV_LOG_WARNING, "Reducing offset_x from %d to %d"
- "chroma samples to preserve alignment.\n",
- offset_x, s->offset_x);
+ if (!s->offset_x_warned) {
+ s->offset_x_warned = 1;
+ av_log(avctx, AV_LOG_WARNING, "Reducing offset_x from %d to %d"
+ "chroma samples to preserve alignment.\n",
+ offset_x, s->offset_x);
+ }
}
}
@@ -2426,10 +2470,12 @@ static av_cold int theora_decode_init(AVCodecContext *avctx)
Vp3DecodeContext *s = avctx->priv_data;
GetBitContext gb;
int ptype;
- uint8_t *header_start[3];
+ const uint8_t *header_start[3];
int header_len[3];
int i;
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
s->theora = 1;
if (!avctx->extradata_size) {
@@ -2446,7 +2492,7 @@ static av_cold int theora_decode_init(AVCodecContext *avctx)
for (i = 0; i < 3; i++) {
if (header_len[i] <= 0)
continue;
- init_get_bits(&gb, header_start[i], header_len[i] * 8);
+ init_get_bits8(&gb, header_start[i], header_len[i]);
ptype = get_bits(&gb, 8);
@@ -2460,7 +2506,8 @@ static av_cold int theora_decode_init(AVCodecContext *avctx)
switch (ptype) {
case 0x80:
- theora_decode_header(avctx, &gb);
+ if (theora_decode_header(avctx, &gb) < 0)
+ return -1;
break;
case 0x81:
// FIXME: is this needed? it breaks sometimes
diff --git a/libavcodec/vp3_parser.c b/libavcodec/vp3_parser.c
index e8fdcca488..7ee046c543 100644
--- a/libavcodec/vp3_parser.c
+++ b/libavcodec/vp3_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2008 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp3data.h b/libavcodec/vp3data.h
index da325c0345..da31f6d026 100644
--- a/libavcodec/vp3data.h
+++ b/libavcodec/vp3data.h
@@ -1,20 +1,20 @@
/*
- * copyright (C) 2003 the ffmpeg project
+ * copyright (C) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,7 +26,7 @@
/* these coefficients dequantize intraframe Y plane coefficients
* (note: same as JPEG) */
-static const int16_t vp31_intra_y_dequant[64] = {
+static const int8_t vp31_intra_y_dequant[64] = {
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
@@ -39,7 +39,7 @@ static const int16_t vp31_intra_y_dequant[64] = {
/* these coefficients dequantize intraframe C plane coefficients
* (note: same as JPEG) */
-static const int16_t vp31_intra_c_dequant[64] = {
+static const int8_t vp31_intra_c_dequant[64] = {
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
@@ -51,7 +51,7 @@ static const int16_t vp31_intra_c_dequant[64] = {
};
/* these coefficients dequantize interframe coefficients (all planes) */
-static const int16_t vp31_inter_dequant[64] = {
+static const int8_t vp31_inter_dequant[64] = {
16, 16, 16, 20, 24, 28, 32, 40,
16, 16, 20, 24, 28, 32, 40, 48,
16, 20, 24, 28, 32, 40, 48, 64,
@@ -62,7 +62,7 @@ static const int16_t vp31_inter_dequant[64] = {
40, 48, 64, 64, 64, 96, 128, 128
};
-static const int16_t vp31_dc_scale_factor[64] = {
+static const uint8_t vp31_dc_scale_factor[64] = {
220, 200, 190, 180, 170, 170, 160, 160,
150, 150, 140, 140, 130, 130, 120, 120,
110, 110, 100, 100, 90, 90, 90, 80,
@@ -176,7 +176,7 @@ static const uint8_t motion_vector_vlc_table[63][2] = {
{ 0xFC, 8 }, { 0xFD, 8 }, { 0xFE, 8 }, { 0xFF, 8 }
};
-static const int motion_vector_table[63] = {
+static const int8_t motion_vector_table[63] = {
0, 1, -1,
2, -2,
3, -3,
@@ -198,21 +198,21 @@ static const int8_t fixed_motion_vector_table[64] = {
};
/* only tokens 0..6 indicate eob runs */
-static const int eob_run_base[7] = {
+static const uint8_t eob_run_base[7] = {
1, 2, 3, 4, 8, 16, 0
};
-static const int eob_run_get_bits[7] = {
+static const uint8_t eob_run_get_bits[7] = {
0, 0, 0, 2, 3, 4, 12
};
-static const int zero_run_base[32] = {
+static const uint8_t zero_run_base[32] = {
0, 0, 0, 0, 0, 0, 0, /* 0..6 are never used */
0, 0, /* 7..8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9..22 */
1, 2, 3, 4, 5, /* 23..27 */
6, 10, 1, 2 /* 28..31 */
};
-static const int zero_run_get_bits[32] = {
+static const uint8_t zero_run_get_bits[32] = {
0, 0, 0, 0, 0, 0, 0, /* 0..6 are never used */
3, 6, /* 7..8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9..22 */
@@ -220,7 +220,7 @@ static const int zero_run_get_bits[32] = {
2, 3, 0, 1 /* 28..31 */
};
-static const int coeff_get_bits[32] = {
+static const uint8_t coeff_get_bits[32] = {
0, 0, 0, 0, 0, 0, 0, /* 0..6 are never used */
0, 0, 0, 0, 0, 0, /* 7..12 use constant coeffs */
1, 1, 1, 1, /* 13..16 are constants but still need sign bit */
diff --git a/libavcodec/vp3dsp.c b/libavcodec/vp3dsp.c
index af687ec5aa..d8a3e0a354 100644
--- a/libavcodec/vp3dsp.c
+++ b/libavcodec/vp3dsp.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2004 the ffmpeg project
+ * Copyright (c) 2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,6 @@
*/
#include "libavutil/attributes.h"
-#include "libavutil/intreadwrite.h"
#include "libavutil/common.h"
#include "libavutil/intreadwrite.h"
diff --git a/libavcodec/vp3dsp.h b/libavcodec/vp3dsp.h
index 3099a7e13c..b95adae79e 100644
--- a/libavcodec/vp3dsp.h
+++ b/libavcodec/vp3dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp5.c b/libavcodec/vp5.c
index b60928241d..1923d6335c 100644
--- a/libavcodec/vp5.c
+++ b/libavcodec/vp5.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,8 +35,7 @@
#include "vp5data.h"
-static int vp5_parse_header(VP56Context *s, const uint8_t *buf, int buf_size,
- int *golden_frame)
+static int vp5_parse_header(VP56Context *s, const uint8_t *buf, int buf_size)
{
VP56RangeCoder *c = &s->c;
int rows, cols;
@@ -86,7 +85,7 @@ static void vp5_parse_vector_adjustment(VP56Context *s, VP56mv *vect)
for (comp=0; comp<2; comp++) {
int delta = 0;
- if (vp56_rac_get_prob(c, model->vector_dct[comp])) {
+ if (vp56_rac_get_prob_branchy(c, model->vector_dct[comp])) {
int sign = vp56_rac_get_prob(c, model->vector_sig[comp]);
di = vp56_rac_get_prob(c, model->vector_pdi[comp][0]);
di |= vp56_rac_get_prob(c, model->vector_pdi[comp][1]) << 1;
@@ -109,19 +108,19 @@ static void vp5_parse_vector_models(VP56Context *s)
int comp, node;
for (comp=0; comp<2; comp++) {
- if (vp56_rac_get_prob(c, vp5_vmc_pct[comp][0]))
+ if (vp56_rac_get_prob_branchy(c, vp5_vmc_pct[comp][0]))
model->vector_dct[comp] = vp56_rac_gets_nn(c, 7);
- if (vp56_rac_get_prob(c, vp5_vmc_pct[comp][1]))
+ if (vp56_rac_get_prob_branchy(c, vp5_vmc_pct[comp][1]))
model->vector_sig[comp] = vp56_rac_gets_nn(c, 7);
- if (vp56_rac_get_prob(c, vp5_vmc_pct[comp][2]))
+ if (vp56_rac_get_prob_branchy(c, vp5_vmc_pct[comp][2]))
model->vector_pdi[comp][0] = vp56_rac_gets_nn(c, 7);
- if (vp56_rac_get_prob(c, vp5_vmc_pct[comp][3]))
+ if (vp56_rac_get_prob_branchy(c, vp5_vmc_pct[comp][3]))
model->vector_pdi[comp][1] = vp56_rac_gets_nn(c, 7);
}
for (comp=0; comp<2; comp++)
for (node=0; node<7; node++)
- if (vp56_rac_get_prob(c, vp5_vmc_pct[comp][4 + node]))
+ if (vp56_rac_get_prob_branchy(c, vp5_vmc_pct[comp][4 + node]))
model->vector_pdv[comp][node] = vp56_rac_gets_nn(c, 7);
}
@@ -138,7 +137,7 @@ static int vp5_parse_coeff_models(VP56Context *s)
for (pt=0; pt<2; pt++)
for (node=0; node<11; node++)
- if (vp56_rac_get_prob(c, vp5_dccv_pct[pt][node])) {
+ if (vp56_rac_get_prob_branchy(c, vp5_dccv_pct[pt][node])) {
def_prob[node] = vp56_rac_gets_nn(c, 7);
model->coeff_dccv[pt][node] = def_prob[node];
} else if (s->frames[VP56_FRAME_CURRENT]->key_frame) {
@@ -149,7 +148,7 @@ static int vp5_parse_coeff_models(VP56Context *s)
for (pt=0; pt<2; pt++)
for (cg=0; cg<6; cg++)
for (node=0; node<11; node++)
- if (vp56_rac_get_prob(c, vp5_ract_pct[ct][pt][cg][node])) {
+ if (vp56_rac_get_prob_branchy(c, vp5_ract_pct[ct][pt][cg][node])) {
def_prob[node] = vp56_rac_gets_nn(c, 7);
model->coeff_ract[pt][ct][cg][node] = def_prob[node];
} else if (s->frames[VP56_FRAME_CURRENT]->key_frame) {
@@ -194,9 +193,9 @@ static void vp5_parse_coeff(VP56Context *s)
coeff_idx = 0;
for (;;) {
- if (vp56_rac_get_prob(c, model2[0])) {
- if (vp56_rac_get_prob(c, model2[2])) {
- if (vp56_rac_get_prob(c, model2[3])) {
+ if (vp56_rac_get_prob_branchy(c, model2[0])) {
+ if (vp56_rac_get_prob_branchy(c, model2[2])) {
+ if (vp56_rac_get_prob_branchy(c, model2[3])) {
s->coeff_ctx[ff_vp56_b6to4[b]][coeff_idx] = 4;
idx = vp56_rac_get_tree(c, ff_vp56_pc_tree, model1);
sign = vp56_rac_get(c);
@@ -204,7 +203,7 @@ static void vp5_parse_coeff(VP56Context *s)
for (i=ff_vp56_coeff_bit_length[idx]; i>=0; i--)
coeff += vp56_rac_get_prob(c, ff_vp56_coeff_parse_table[idx][i]) << i;
} else {
- if (vp56_rac_get_prob(c, model2[4])) {
+ if (vp56_rac_get_prob_branchy(c, model2[4])) {
coeff = 3 + vp56_rac_get_prob(c, model1[5]);
s->coeff_ctx[ff_vp56_b6to4[b]][coeff_idx] = 3;
} else {
@@ -225,7 +224,7 @@ static void vp5_parse_coeff(VP56Context *s)
coeff *= s->dequant_ac;
s->block_coeff[b][permute[coeff_idx]] = coeff;
} else {
- if (ct && !vp56_rac_get_prob(c, model2[1]))
+ if (ct && !vp56_rac_get_prob_branchy(c, model2[1]))
break;
ct = 0;
s->coeff_ctx[ff_vp56_b6to4[b]][coeff_idx] = 0;
diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c
index 2f1de5a5a0..631924828d 100644
--- a/libavcodec/vp56.c
+++ b/libavcodec/vp56.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -83,16 +83,16 @@ static void vp56_parse_mb_type_models(VP56Context *s)
int i, ctx, type;
for (ctx=0; ctx<3; ctx++) {
- if (vp56_rac_get_prob(c, 174)) {
+ if (vp56_rac_get_prob_branchy(c, 174)) {
int idx = vp56_rac_gets(c, 4);
memcpy(model->mb_types_stats[ctx],
ff_vp56_pre_def_mb_type_stats[idx][ctx],
sizeof(model->mb_types_stats[ctx]));
}
- if (vp56_rac_get_prob(c, 254)) {
+ if (vp56_rac_get_prob_branchy(c, 254)) {
for (type=0; type<10; type++) {
for(i=0; i<2; i++) {
- if (vp56_rac_get_prob(c, 205)) {
+ if (vp56_rac_get_prob_branchy(c, 205)) {
int delta, sign = vp56_rac_get(c);
delta = vp56_rac_get_tree(c, ff_vp56_pmbtm_tree,
@@ -153,7 +153,7 @@ static VP56mb vp56_parse_mb_type(VP56Context *s,
uint8_t *mb_type_model = s->modelp->mb_type[ctx][prev_type];
VP56RangeCoder *c = &s->c;
- if (vp56_rac_get_prob(c, mb_type_model[0]))
+ if (vp56_rac_get_prob_branchy(c, mb_type_model[0]))
return prev_type;
else
return vp56_rac_get_tree(c, ff_vp56_pmbt_tree, mb_type_model);
@@ -340,11 +340,11 @@ static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src,
if (x<0 || x+12>=s->plane_width[plane] ||
y<0 || y+12>=s->plane_height[plane]) {
s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
- src + s->block_offset[b] + (dy-2)*stride + (dx-2),
- stride, stride,
- 12, 12, x, y,
- s->plane_width[plane],
- s->plane_height[plane]);
+ src + s->block_offset[b] + (dy-2)*stride + (dx-2),
+ stride, stride,
+ 12, 12, x, y,
+ s->plane_width[plane],
+ s->plane_height[plane]);
src_block = s->edge_emu_buffer;
src_offset = 2 + 2*stride;
} else if (deblock_filtering) {
@@ -453,9 +453,9 @@ static void vp56_decode_mb(VP56Context *s, int row, int col, int is_alpha)
}
}
-static int vp56_size_changed(AVCodecContext *avctx)
+static int vp56_size_changed(VP56Context *s)
{
- VP56Context *s = avctx->priv_data;
+ AVCodecContext *avctx = s->avctx;
int stride = s->frames[VP56_FRAME_CURRENT]->linesize[0];
int i;
@@ -476,19 +476,26 @@ static int vp56_size_changed(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- s->above_blocks = av_realloc(s->above_blocks,
- (4*s->mb_width+6) * sizeof(*s->above_blocks));
- s->macroblocks = av_realloc(s->macroblocks,
- s->mb_width*s->mb_height*sizeof(*s->macroblocks));
+ av_reallocp_array(&s->above_blocks, 4*s->mb_width+6,
+ sizeof(*s->above_blocks));
+ av_reallocp_array(&s->macroblocks, s->mb_width*s->mb_height,
+ sizeof(*s->macroblocks));
av_free(s->edge_emu_buffer_alloc);
s->edge_emu_buffer_alloc = av_malloc(16*stride);
s->edge_emu_buffer = s->edge_emu_buffer_alloc;
+ if (!s->above_blocks || !s->macroblocks || !s->edge_emu_buffer_alloc)
+ return AVERROR(ENOMEM);
if (s->flip < 0)
s->edge_emu_buffer += 15 * stride;
+ if (s->alpha_context)
+ return vp56_size_changed(s->alpha_context);
+
return 0;
}
+static int ff_vp56_decode_mbs(AVCodecContext *avctx, void *, int, int);
+
int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
@@ -496,8 +503,9 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
VP56Context *s = avctx->priv_data;
AVFrame *const p = s->frames[VP56_FRAME_CURRENT];
int remaining_buf_size = avpkt->size;
- int is_alpha, av_uninit(alpha_offset);
- int res;
+ int av_uninit(alpha_offset);
+ int i, res;
+ int ret;
if (s->has_alpha) {
if (remaining_buf_size < 3)
@@ -508,156 +516,184 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- for (is_alpha=0; is_alpha < 1+s->has_alpha; is_alpha++) {
- int mb_row, mb_col, mb_row_flip, mb_offset = 0;
- int block, y, uv;
- ptrdiff_t stride_y, stride_uv;
- int golden_frame = 0;
+ res = s->parse_header(s, buf, remaining_buf_size);
+ if (res < 0)
+ return res;
- s->modelp = &s->models[is_alpha];
+ if (res == VP56_SIZE_CHANGE) {
+ for (i = 0; i < 4; i++) {
+ av_frame_unref(s->frames[i]);
+ if (s->alpha_context)
+ av_frame_unref(s->alpha_context->frames[i]);
+ }
+ }
- res = s->parse_header(s, buf, remaining_buf_size, &golden_frame);
- if (res < 0) {
- int i;
- for (i = 0; i < 4; i++)
- av_frame_unref(s->frames[i]);
- return res;
+ ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF);
+ if (ret < 0)
+ return ret;
+
+ if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
+ av_frame_unref(s->alpha_context->frames[VP56_FRAME_CURRENT]);
+ if ((ret = av_frame_ref(s->alpha_context->frames[VP56_FRAME_CURRENT], p)) < 0) {
+ av_frame_unref(p);
+ return ret;
}
+ }
- if (res == VP56_SIZE_CHANGE) {
- int i;
- for (i = 0; i < 4; i++)
- av_frame_unref(s->frames[i]);
- if (is_alpha) {
- ff_set_dimensions(avctx, 0, 0);
- return AVERROR_INVALIDDATA;
- }
+ if (res == VP56_SIZE_CHANGE) {
+ if (vp56_size_changed(s)) {
+ av_frame_unref(p);
+ return AVERROR_INVALIDDATA;
}
+ }
- if (!is_alpha) {
- int ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
+ if (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) {
+ int bak_w = avctx->width;
+ int bak_h = avctx->height;
+ int bak_cw = avctx->coded_width;
+ int bak_ch = avctx->coded_height;
+ buf += alpha_offset;
+ remaining_buf_size -= alpha_offset;
+
+ res = s->alpha_context->parse_header(s->alpha_context, buf, remaining_buf_size);
+ if (res != 0) {
+ if(res==VP56_SIZE_CHANGE) {
+ av_log(avctx, AV_LOG_ERROR, "Alpha reconfiguration\n");
+ avctx->width = bak_w;
+ avctx->height = bak_h;
+ avctx->coded_width = bak_cw;
+ avctx->coded_height = bak_ch;
}
-
- if (res == VP56_SIZE_CHANGE)
- if (vp56_size_changed(avctx)) {
- av_frame_unref(p);
- return AVERROR_INVALIDDATA;
- }
+ av_frame_unref(p);
+ return AVERROR_INVALIDDATA;
}
+ }
- if (p->key_frame) {
- p->pict_type = AV_PICTURE_TYPE_I;
- s->default_models_init(s);
- for (block=0; block<s->mb_height*s->mb_width; block++)
- s->macroblocks[block].type = VP56_MB_INTRA;
- } else {
- p->pict_type = AV_PICTURE_TYPE_P;
- vp56_parse_mb_type_models(s);
- s->parse_vector_models(s);
- s->mb_type = VP56_MB_INTER_NOVEC_PF;
- }
+ avctx->execute2(avctx, ff_vp56_decode_mbs, 0, 0, (avctx->pix_fmt == AV_PIX_FMT_YUVA420P) + 1);
- if (s->parse_coeff_models(s))
- goto next;
+ if ((res = av_frame_ref(data, p)) < 0)
+ return res;
+ *got_frame = 1;
- memset(s->prev_dc, 0, sizeof(s->prev_dc));
- s->prev_dc[1][VP56_FRAME_CURRENT] = 128;
- s->prev_dc[2][VP56_FRAME_CURRENT] = 128;
+ return avpkt->size;
+}
- for (block=0; block < 4*s->mb_width+6; block++) {
- s->above_blocks[block].ref_frame = VP56_FRAME_NONE;
- s->above_blocks[block].dc_coeff = 0;
- s->above_blocks[block].not_null_dc = 0;
- }
- s->above_blocks[2*s->mb_width + 2].ref_frame = VP56_FRAME_CURRENT;
- s->above_blocks[3*s->mb_width + 4].ref_frame = VP56_FRAME_CURRENT;
+static int ff_vp56_decode_mbs(AVCodecContext *avctx, void *data,
+ int jobnr, int threadnr)
+{
+ VP56Context *s0 = avctx->priv_data;
+ int is_alpha = (jobnr == 1);
+ VP56Context *s = is_alpha ? s0->alpha_context : s0;
+ AVFrame *const p = s->frames[VP56_FRAME_CURRENT];
+ int mb_row, mb_col, mb_row_flip, mb_offset = 0;
+ int block, y, uv;
+ ptrdiff_t stride_y, stride_uv;
+ int res;
+
+ if (p->key_frame) {
+ p->pict_type = AV_PICTURE_TYPE_I;
+ s->default_models_init(s);
+ for (block=0; block<s->mb_height*s->mb_width; block++)
+ s->macroblocks[block].type = VP56_MB_INTRA;
+ } else {
+ p->pict_type = AV_PICTURE_TYPE_P;
+ vp56_parse_mb_type_models(s);
+ s->parse_vector_models(s);
+ s->mb_type = VP56_MB_INTER_NOVEC_PF;
+ }
+
+ if (s->parse_coeff_models(s))
+ goto next;
- stride_y = p->linesize[0];
- stride_uv = p->linesize[1];
+ memset(s->prev_dc, 0, sizeof(s->prev_dc));
+ s->prev_dc[1][VP56_FRAME_CURRENT] = 128;
+ s->prev_dc[2][VP56_FRAME_CURRENT] = 128;
+ for (block=0; block < 4*s->mb_width+6; block++) {
+ s->above_blocks[block].ref_frame = VP56_FRAME_NONE;
+ s->above_blocks[block].dc_coeff = 0;
+ s->above_blocks[block].not_null_dc = 0;
+ }
+ s->above_blocks[2*s->mb_width + 2].ref_frame = VP56_FRAME_CURRENT;
+ s->above_blocks[3*s->mb_width + 4].ref_frame = VP56_FRAME_CURRENT;
+
+ stride_y = p->linesize[0];
+ stride_uv = p->linesize[1];
+
+ if (s->flip < 0)
+ mb_offset = 7;
+
+ /* main macroblocks loop */
+ for (mb_row=0; mb_row<s->mb_height; mb_row++) {
if (s->flip < 0)
- mb_offset = 7;
-
- /* main macroblocks loop */
- for (mb_row=0; mb_row<s->mb_height; mb_row++) {
- if (s->flip < 0)
- mb_row_flip = s->mb_height - mb_row - 1;
- else
- mb_row_flip = mb_row;
-
- for (block=0; block<4; block++) {
- s->left_block[block].ref_frame = VP56_FRAME_NONE;
- s->left_block[block].dc_coeff = 0;
- s->left_block[block].not_null_dc = 0;
- }
- memset(s->coeff_ctx, 0, sizeof(s->coeff_ctx));
- memset(s->coeff_ctx_last, 24, sizeof(s->coeff_ctx_last));
-
- s->above_block_idx[0] = 1;
- s->above_block_idx[1] = 2;
- s->above_block_idx[2] = 1;
- s->above_block_idx[3] = 2;
- s->above_block_idx[4] = 2*s->mb_width + 2 + 1;
- s->above_block_idx[5] = 3*s->mb_width + 4 + 1;
-
- s->block_offset[s->frbi] = (mb_row_flip*16 + mb_offset) * stride_y;
- s->block_offset[s->srbi] = s->block_offset[s->frbi] + 8*stride_y;
- s->block_offset[1] = s->block_offset[0] + 8;
- s->block_offset[3] = s->block_offset[2] + 8;
- s->block_offset[4] = (mb_row_flip*8 + mb_offset) * stride_uv;
- s->block_offset[5] = s->block_offset[4];
-
- for (mb_col=0; mb_col<s->mb_width; mb_col++) {
- vp56_decode_mb(s, mb_row, mb_col, is_alpha);
-
- for (y=0; y<4; y++) {
- s->above_block_idx[y] += 2;
- s->block_offset[y] += 16;
- }
+ mb_row_flip = s->mb_height - mb_row - 1;
+ else
+ mb_row_flip = mb_row;
- for (uv=4; uv<6; uv++) {
- s->above_block_idx[uv] += 1;
- s->block_offset[uv] += 8;
- }
- }
+ for (block=0; block<4; block++) {
+ s->left_block[block].ref_frame = VP56_FRAME_NONE;
+ s->left_block[block].dc_coeff = 0;
+ s->left_block[block].not_null_dc = 0;
}
+ memset(s->coeff_ctx, 0, sizeof(s->coeff_ctx));
+ memset(s->coeff_ctx_last, 24, sizeof(s->coeff_ctx_last));
+
+ s->above_block_idx[0] = 1;
+ s->above_block_idx[1] = 2;
+ s->above_block_idx[2] = 1;
+ s->above_block_idx[3] = 2;
+ s->above_block_idx[4] = 2*s->mb_width + 2 + 1;
+ s->above_block_idx[5] = 3*s->mb_width + 4 + 1;
+
+ s->block_offset[s->frbi] = (mb_row_flip*16 + mb_offset) * stride_y;
+ s->block_offset[s->srbi] = s->block_offset[s->frbi] + 8*stride_y;
+ s->block_offset[1] = s->block_offset[0] + 8;
+ s->block_offset[3] = s->block_offset[2] + 8;
+ s->block_offset[4] = (mb_row_flip*8 + mb_offset) * stride_uv;
+ s->block_offset[5] = s->block_offset[4];
+
+ for (mb_col=0; mb_col<s->mb_width; mb_col++) {
+ vp56_decode_mb(s, mb_row, mb_col, is_alpha);
+
+ for (y=0; y<4; y++) {
+ s->above_block_idx[y] += 2;
+ s->block_offset[y] += 16;
+ }
- next:
- if (p->key_frame || golden_frame) {
- av_frame_unref(s->frames[VP56_FRAME_GOLDEN]);
- if ((res = av_frame_ref(s->frames[VP56_FRAME_GOLDEN], p)) < 0)
- return res;
+ for (uv=4; uv<6; uv++) {
+ s->above_block_idx[uv] += 1;
+ s->block_offset[uv] += 8;
+ }
}
+ }
- if (s->has_alpha) {
- FFSWAP(AVFrame *, s->frames[VP56_FRAME_GOLDEN],
- s->frames[VP56_FRAME_GOLDEN2]);
- buf += alpha_offset;
- remaining_buf_size -= alpha_offset;
- }
+next:
+ if (p->key_frame || s->golden_frame) {
+ av_frame_unref(s->frames[VP56_FRAME_GOLDEN]);
+ if ((res = av_frame_ref(s->frames[VP56_FRAME_GOLDEN], p)) < 0)
+ return res;
}
av_frame_unref(s->frames[VP56_FRAME_PREVIOUS]);
FFSWAP(AVFrame *, s->frames[VP56_FRAME_CURRENT],
s->frames[VP56_FRAME_PREVIOUS]);
-
- if ((res = av_frame_ref(data, p)) < 0)
- return res;
- *got_frame = 1;
-
- return avpkt->size;
+ return 0;
}
av_cold int ff_vp56_init(AVCodecContext *avctx, int flip, int has_alpha)
{
VP56Context *s = avctx->priv_data;
+ return ff_vp56_init_context(avctx, s, flip, has_alpha);
+}
+
+av_cold int ff_vp56_init_context(AVCodecContext *avctx, VP56Context *s,
+ int flip, int has_alpha)
+{
int i;
s->avctx = avctx;
avctx->pix_fmt = has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
+ if (avctx->skip_alpha) avctx->pix_fmt = AV_PIX_FMT_YUV420P;
ff_h264chroma_init(&s->h264chroma, 8);
ff_hpeldsp_init(&s->hdsp, avctx->flags);
@@ -665,7 +701,7 @@ av_cold int ff_vp56_init(AVCodecContext *avctx, int flip, int has_alpha)
ff_vp3dsp_init(&s->vp3dsp, avctx->flags);
ff_vp56dsp_init(&s->vp56dsp, avctx->codec->id);
for (i = 0; i < 64; i++) {
-#define TRANSPOSE(x) (x >> 3) | ((x & 7) << 3)
+#define TRANSPOSE(x) (((x) >> 3) | (((x) & 7) << 3))
s->idct_scantable[i] = TRANSPOSE(ff_zigzag_direct[i]);
#undef TRANSPOSE
}
@@ -683,10 +719,14 @@ av_cold int ff_vp56_init(AVCodecContext *avctx, int flip, int has_alpha)
s->macroblocks = NULL;
s->quantizer = -1;
s->deblock_filtering = 1;
+ s->golden_frame = 0;
s->filter = NULL;
s->has_alpha = has_alpha;
+
+ s->modelp = &s->model;
+
if (flip) {
s->flip = -1;
s->frbi = 2;
@@ -703,6 +743,11 @@ av_cold int ff_vp56_init(AVCodecContext *avctx, int flip, int has_alpha)
av_cold int ff_vp56_free(AVCodecContext *avctx)
{
VP56Context *s = avctx->priv_data;
+ return ff_vp56_free_context(s);
+}
+
+av_cold int ff_vp56_free_context(VP56Context *s)
+{
int i;
av_freep(&s->above_blocks);
diff --git a/libavcodec/vp56.h b/libavcodec/vp56.h
index f2ed770b85..56c30919b7 100644
--- a/libavcodec/vp56.h
+++ b/libavcodec/vp56.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -79,7 +79,7 @@ typedef void (*VP56DefaultModelsInit)(VP56Context *s);
typedef void (*VP56ParseVectorModels)(VP56Context *s);
typedef int (*VP56ParseCoeffModels)(VP56Context *s);
typedef int (*VP56ParseHeader)(VP56Context *s, const uint8_t *buf,
- int buf_size, int *golden_frame);
+ int buf_size);
typedef struct VP56RangeCoder {
int high;
@@ -135,6 +135,7 @@ struct vp56_context {
int sub_version;
/* frame info */
+ int golden_frame;
int plane_width[4];
int plane_height[4];
int mb_width; /* number of horizontal MB */
@@ -189,8 +190,11 @@ struct vp56_context {
VP56ParseCoeffModels parse_coeff_models;
VP56ParseHeader parse_header;
+ /* for "slice" parallelism between YUV and A */
+ VP56Context *alpha_context;
+
VP56Model *modelp;
- VP56Model models[2];
+ VP56Model model;
/* huffman decoding */
int use_huffman;
@@ -203,7 +207,10 @@ struct vp56_context {
int ff_vp56_init(AVCodecContext *avctx, int flip, int has_alpha);
+int ff_vp56_init_context(AVCodecContext *avctx, VP56Context *s,
+ int flip, int has_alpha);
int ff_vp56_free(AVCodecContext *avctx);
+int ff_vp56_free_context(VP56Context *s);
void ff_vp56_init_dequant(VP56Context *s, int quantizer);
int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt);
@@ -356,7 +363,7 @@ int vp56_rac_get_tree(VP56RangeCoder *c,
const uint8_t *probs)
{
while (tree->val > 0) {
- if (vp56_rac_get_prob(c, probs[tree->prob_idx]))
+ if (vp56_rac_get_prob_branchy(c, probs[tree->prob_idx]))
tree += tree->val;
else
tree++;
@@ -364,15 +371,13 @@ int vp56_rac_get_tree(VP56RangeCoder *c,
return -tree->val;
}
-/**
- * This is identical to vp8_rac_get_tree except for the possibility of starting
- * on a node other than the root node, needed for coeff decode where this is
- * used to save a bit after a 0 token (by disallowing EOB to immediately follow.)
- */
-static av_always_inline
-int vp8_rac_get_tree_with_offset(VP56RangeCoder *c, const int8_t (*tree)[2],
- const uint8_t *probs, int i)
+// how probabilities are associated with decisions is different I think
+// well, the new scheme fits in the old but this way has one fewer branches per decision
+static av_always_inline int vp8_rac_get_tree(VP56RangeCoder *c, const int8_t (*tree)[2],
+ const uint8_t *probs)
{
+ int i = 0;
+
do {
i = tree[i][vp56_rac_get_prob(c, probs[i])];
} while (i > 0);
@@ -380,15 +385,6 @@ int vp8_rac_get_tree_with_offset(VP56RangeCoder *c, const int8_t (*tree)[2],
return -i;
}
-// how probabilities are associated with decisions is different I think
-// well, the new scheme fits in the old but this way has one fewer branches per decision
-static av_always_inline
-int vp8_rac_get_tree(VP56RangeCoder *c, const int8_t (*tree)[2],
- const uint8_t *probs)
-{
- return vp8_rac_get_tree_with_offset(c, tree, probs, 0);
-}
-
// DCTextra
static av_always_inline int vp8_rac_get_coeff(VP56RangeCoder *c, const uint8_t *prob)
{
diff --git a/libavcodec/vp56data.c b/libavcodec/vp56data.c
index 989c76a649..0080370f02 100644
--- a/libavcodec/vp56data.c
+++ b/libavcodec/vp56data.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp56data.h b/libavcodec/vp56data.h
index 21907bdb50..3be268c317 100644
--- a/libavcodec/vp56data.h
+++ b/libavcodec/vp56data.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp56dsp.c b/libavcodec/vp56dsp.c
index 5e09d2414e..fa533ec5c9 100644
--- a/libavcodec/vp56dsp.c
+++ b/libavcodec/vp56dsp.c
@@ -2,20 +2,20 @@
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp56dsp.h b/libavcodec/vp56dsp.h
index 389d35901c..7807baa4b1 100644
--- a/libavcodec/vp56dsp.h
+++ b/libavcodec/vp56dsp.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp56rac.c b/libavcodec/vp56rac.c
index 270a3cad3a..6061b7ee72 100644
--- a/libavcodec/vp56rac.c
+++ b/libavcodec/vp56rac.c
@@ -2,20 +2,20 @@
* VP5/6/8 decoder
* Copyright (c) 2010 Fiona Glaser <fiona@x264.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp5data.h b/libavcodec/vp5data.h
index b11b99d9a9..e16ff2da4b 100644
--- a/libavcodec/vp5data.h
+++ b/libavcodec/vp5data.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c
index d10a64001a..e97ef76d1e 100644
--- a/libavcodec/vp6.c
+++ b/libavcodec/vp6.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,8 +43,7 @@
static void vp6_parse_coeff(VP56Context *s);
static void vp6_parse_coeff_huffman(VP56Context *s);
-static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size,
- int *golden_frame)
+static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size)
{
VP56RangeCoder *c = &s->c;
int parse_filter_info = 0;
@@ -113,6 +112,7 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size,
if (sub_version < 8)
vrt_shift = 5;
s->sub_version = sub_version;
+ s->golden_frame = 0;
} else {
if (!s->sub_version || !s->avctx->coded_width || !s->avctx->coded_height)
return AVERROR_INVALIDDATA;
@@ -124,7 +124,7 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size,
}
ff_vp56_init_range_decoder(c, buf+1, buf_size-1);
- *golden_frame = vp56_rac_get(c);
+ s->golden_frame = vp56_rac_get(c);
if (s->filter_header) {
s->deblock_filtering = vp56_rac_get(c);
if (s->deblock_filtering)
@@ -211,20 +211,20 @@ static void vp6_parse_vector_models(VP56Context *s)
int comp, node;
for (comp=0; comp<2; comp++) {
- if (vp56_rac_get_prob(c, vp6_sig_dct_pct[comp][0]))
+ if (vp56_rac_get_prob_branchy(c, vp6_sig_dct_pct[comp][0]))
model->vector_dct[comp] = vp56_rac_gets_nn(c, 7);
- if (vp56_rac_get_prob(c, vp6_sig_dct_pct[comp][1]))
+ if (vp56_rac_get_prob_branchy(c, vp6_sig_dct_pct[comp][1]))
model->vector_sig[comp] = vp56_rac_gets_nn(c, 7);
}
for (comp=0; comp<2; comp++)
for (node=0; node<7; node++)
- if (vp56_rac_get_prob(c, vp6_pdv_pct[comp][node]))
+ if (vp56_rac_get_prob_branchy(c, vp6_pdv_pct[comp][node]))
model->vector_pdv[comp][node] = vp56_rac_gets_nn(c, 7);
for (comp=0; comp<2; comp++)
for (node=0; node<8; node++)
- if (vp56_rac_get_prob(c, vp6_fdv_pct[comp][node]))
+ if (vp56_rac_get_prob_branchy(c, vp6_fdv_pct[comp][node]))
model->vector_fdv[comp][node] = vp56_rac_gets_nn(c, 7);
}
@@ -252,7 +252,8 @@ static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[],
ff_free_vlc(vlc);
/* then build the huffman tree according to probabilities */
- return ff_huff_build_tree(s->avctx, vlc, size, nodes, vp6_huff_cmp,
+ return ff_huff_build_tree(s->avctx, vlc, size, FF_HUFFMAN_BITS,
+ nodes, vp6_huff_cmp,
FF_HUFFMAN_FLAG_HNODE_FIRST);
}
@@ -269,7 +270,7 @@ static int vp6_parse_coeff_models(VP56Context *s)
for (pt=0; pt<2; pt++)
for (node=0; node<11; node++)
- if (vp56_rac_get_prob(c, vp6_dccv_pct[pt][node])) {
+ if (vp56_rac_get_prob_branchy(c, vp6_dccv_pct[pt][node])) {
def_prob[node] = vp56_rac_gets_nn(c, 7);
model->coeff_dccv[pt][node] = def_prob[node];
} else if (s->frames[VP56_FRAME_CURRENT]->key_frame) {
@@ -278,21 +279,21 @@ static int vp6_parse_coeff_models(VP56Context *s)
if (vp56_rac_get(c)) {
for (pos=1; pos<64; pos++)
- if (vp56_rac_get_prob(c, vp6_coeff_reorder_pct[pos]))
+ if (vp56_rac_get_prob_branchy(c, vp6_coeff_reorder_pct[pos]))
model->coeff_reorder[pos] = vp56_rac_gets(c, 4);
vp6_coeff_order_table_init(s);
}
for (cg=0; cg<2; cg++)
for (node=0; node<14; node++)
- if (vp56_rac_get_prob(c, vp6_runv_pct[cg][node]))
+ if (vp56_rac_get_prob_branchy(c, vp6_runv_pct[cg][node]))
model->coeff_runv[cg][node] = vp56_rac_gets_nn(c, 7);
for (ct=0; ct<3; ct++)
for (pt=0; pt<2; pt++)
for (cg=0; cg<6; cg++)
for (node=0; node<11; node++)
- if (vp56_rac_get_prob(c, vp6_ract_pct[ct][pt][cg][node])) {
+ if (vp56_rac_get_prob_branchy(c, vp6_ract_pct[ct][pt][cg][node])) {
def_prob[node] = vp56_rac_gets_nn(c, 7);
model->coeff_ract[pt][ct][cg][node] = def_prob[node];
} else if (s->frames[VP56_FRAME_CURRENT]->key_frame) {
@@ -338,7 +339,7 @@ static void vp6_parse_vector_adjustment(VP56Context *s, VP56mv *vect)
for (comp=0; comp<2; comp++) {
int i, delta = 0;
- if (vp56_rac_get_prob(c, model->vector_dct[comp])) {
+ if (vp56_rac_get_prob_branchy(c, model->vector_dct[comp])) {
static const uint8_t prob_order[] = {0, 1, 2, 7, 6, 5, 4};
for (i=0; i<sizeof(prob_order); i++) {
int j = prob_order[i];
@@ -353,7 +354,7 @@ static void vp6_parse_vector_adjustment(VP56Context *s, VP56mv *vect)
model->vector_pdv[comp]);
}
- if (delta && vp56_rac_get_prob(c, model->vector_sig[comp]))
+ if (delta && vp56_rac_get_prob_branchy(c, model->vector_sig[comp]))
delta = -delta;
if (!comp)
@@ -402,11 +403,11 @@ static void vp6_parse_coeff_huffman(VP56Context *s)
} else {
if (get_bits_left(&s->gb) <= 0)
return;
- coeff = get_vlc2(&s->gb, vlc_coeff->table, 9, 3);
+ coeff = get_vlc2(&s->gb, vlc_coeff->table, FF_HUFFMAN_BITS, 3);
if (coeff == 0) {
if (coeff_idx) {
int pt = (coeff_idx >= 6);
- run += get_vlc2(&s->gb, s->runv_vlc[pt].table, 9, 3);
+ run += get_vlc2(&s->gb, s->runv_vlc[pt].table, FF_HUFFMAN_BITS, 3);
if (run >= 9)
run += get_bits(&s->gb, 6);
} else
@@ -461,16 +462,16 @@ static void vp6_parse_coeff(VP56Context *s)
coeff_idx = 0;
for (;;) {
- if ((coeff_idx>1 && ct==0) || vp56_rac_get_prob(c, model2[0])) {
+ if ((coeff_idx>1 && ct==0) || vp56_rac_get_prob_branchy(c, model2[0])) {
/* parse a coeff */
- if (vp56_rac_get_prob(c, model2[2])) {
- if (vp56_rac_get_prob(c, model2[3])) {
+ if (vp56_rac_get_prob_branchy(c, model2[2])) {
+ if (vp56_rac_get_prob_branchy(c, model2[3])) {
idx = vp56_rac_get_tree(c, ff_vp56_pc_tree, model1);
coeff = ff_vp56_coeff_bias[idx+5];
for (i=ff_vp56_coeff_bit_length[idx]; i>=0; i--)
coeff += vp56_rac_get_prob(c, ff_vp56_coeff_parse_table[idx][i]) << i;
} else {
- if (vp56_rac_get_prob(c, model2[4]))
+ if (vp56_rac_get_prob_branchy(c, model2[4]))
coeff = 3 + vp56_rac_get_prob(c, model1[5]);
else
coeff = 2;
@@ -491,7 +492,7 @@ static void vp6_parse_coeff(VP56Context *s)
/* parse a run */
ct = 0;
if (coeff_idx > 0) {
- if (!vp56_rac_get_prob(c, model2[1]))
+ if (!vp56_rac_get_prob_branchy(c, model2[1]))
break;
model3 = model->coeff_runv[coeff_idx >= 6];
@@ -603,6 +604,8 @@ static void vp6_filter(VP56Context *s, uint8_t *dst, uint8_t *src,
}
}
+static av_cold void vp6_decode_init_context(VP56Context *s);
+
static av_cold int vp6_decode_init(AVCodecContext *avctx)
{
VP56Context *s = avctx->priv_data;
@@ -612,6 +615,21 @@ static av_cold int vp6_decode_init(AVCodecContext *avctx)
avctx->codec->id == AV_CODEC_ID_VP6A)) < 0)
return ret;
+ vp6_decode_init_context(s);
+
+ if (s->has_alpha) {
+ s->alpha_context = av_mallocz(sizeof(VP56Context));
+ ff_vp56_init_context(avctx, s->alpha_context,
+ s->flip == -1, s->has_alpha);
+ vp6_decode_init_context(s->alpha_context);
+ }
+
+ return 0;
+}
+
+static av_cold void vp6_decode_init_context(VP56Context *s)
+{
+ s->deblock_filtering = 0;
s->vp56_coord_div = vp6_coord_div;
s->parse_vector_adjustment = vp6_parse_vector_adjustment;
s->filter = vp6_filter;
@@ -619,16 +637,29 @@ static av_cold int vp6_decode_init(AVCodecContext *avctx)
s->parse_vector_models = vp6_parse_vector_models;
s->parse_coeff_models = vp6_parse_coeff_models;
s->parse_header = vp6_parse_header;
-
- return 0;
}
+static av_cold void vp6_decode_free_context(VP56Context *s);
+
static av_cold int vp6_decode_free(AVCodecContext *avctx)
{
VP56Context *s = avctx->priv_data;
- int pt, ct, cg;
ff_vp56_free(avctx);
+ vp6_decode_free_context(s);
+
+ if (s->alpha_context) {
+ ff_vp56_free_context(s->alpha_context);
+ vp6_decode_free_context(s->alpha_context);
+ av_freep(&s->alpha_context);
+ }
+
+ return 0;
+}
+
+static av_cold void vp6_decode_free_context(VP56Context *s)
+{
+ int pt, ct, cg;
for (pt=0; pt<2; pt++) {
ff_free_vlc(&s->dccv_vlc[pt]);
@@ -637,7 +668,6 @@ static av_cold int vp6_decode_free(AVCodecContext *avctx)
for (cg=0; cg<6; cg++)
ff_free_vlc(&s->ract_vlc[pt][ct][cg]);
}
- return 0;
}
AVCodec ff_vp6_decoder = {
@@ -675,5 +705,5 @@ AVCodec ff_vp6a_decoder = {
.init = vp6_decode_init,
.close = vp6_decode_free,
.decode = ff_vp56_decode_frame,
- .capabilities = CODEC_CAP_DR1,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_SLICE_THREADS,
};
diff --git a/libavcodec/vp6data.h b/libavcodec/vp6data.h
index 2de90e7be7..539e19a627 100644
--- a/libavcodec/vp6data.h
+++ b/libavcodec/vp6data.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp6dsp.c b/libavcodec/vp6dsp.c
index 54a96ed13a..67c6be07de 100644
--- a/libavcodec/vp6dsp.c
+++ b/libavcodec/vp6dsp.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index 4ea6d562b3..dbba5687f2 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -7,20 +7,20 @@
* Copyright (C) 2012 Daniel Kang
* Copyright (C) 2014 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,6 +37,14 @@
# include "arm/vp8.h"
#endif
+#if CONFIG_VP7_DECODER && CONFIG_VP8_DECODER
+#define VPX(vp7, f) (vp7 ? vp7_ ## f : vp8_ ## f)
+#elif CONFIG_VP7_DECODER
+#define VPX(vp7, f) vp7_ ## f
+#else // CONFIG_VP8_DECODER
+#define VPX(vp7, f) vp8_ ## f
+#endif
+
static void free_buffers(VP8Context *s)
{
int i;
@@ -143,7 +151,7 @@ int update_dimensions(VP8Context *s, int width, int height, int is_vp7)
AVCodecContext *avctx = s->avctx;
int i, ret;
- if (width != s->avctx->width ||
+ if (width != s->avctx->width || ((width+15)/16 != s->mb_width || (height+15)/16 != s->mb_height) && s->macroblocks_base ||
height != s->avctx->height) {
vp8_decode_flush_impl(s->avctx, 1);
@@ -202,6 +210,7 @@ static int vp8_update_dimensions(VP8Context *s, int width, int height)
return update_dimensions(s, width, height, IS_VP8);
}
+
static void parse_segment_info(VP8Context *s)
{
VP56RangeCoder *c = &s->c;
@@ -292,7 +301,7 @@ static void vp7_get_quants(VP8Context *s)
s->qmat[0].chroma_qmul[1] = vp7_yac_qlookup[uvac_qi];
}
-static void get_quants(VP8Context *s)
+static void vp8_get_quants(VP8Context *s)
{
VP56RangeCoder *c = &s->c;
int i, base_qi;
@@ -413,7 +422,7 @@ static void update_refs(VP8Context *s)
s->update_altref = ref_to_update(s, update_altref, VP56_FRAME_GOLDEN2);
}
-static void copy_luma(AVFrame *dst, AVFrame *src, int width, int height)
+static void copy_chroma(AVFrame *dst, AVFrame *src, int width, int height)
{
int i, j;
@@ -424,16 +433,16 @@ static void copy_luma(AVFrame *dst, AVFrame *src, int width, int height)
}
}
-static void fade(uint8_t *dst, uint8_t *src,
- int width, int height, int linesize,
+static void fade(uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize,
+ int width, int height,
int alpha, int beta)
{
int i, j;
-
for (j = 0; j < height; j++) {
for (i = 0; i < width; i++) {
- uint8_t y = src[j * linesize + i];
- dst[j * linesize + i] = av_clip_uint8(y + ((y * beta) >> 8) + alpha);
+ uint8_t y = src[j * src_linesize + i];
+ dst[j * dst_linesize + i] = av_clip_uint8(y + ((y * beta) >> 8) + alpha);
}
}
}
@@ -449,8 +458,11 @@ static int vp7_fade_frame(VP8Context *s, VP56RangeCoder *c)
int height = s->mb_height * 16;
AVFrame *src, *dst;
- if (!s->framep[VP56_FRAME_PREVIOUS])
+ if (!s->framep[VP56_FRAME_PREVIOUS] ||
+ !s->framep[VP56_FRAME_GOLDEN]) {
+ av_log(s->avctx, AV_LOG_WARNING, "Discarding interframe without a prior keyframe!\n");
return AVERROR_INVALIDDATA;
+ }
dst =
src = s->framep[VP56_FRAME_PREVIOUS]->tf.f;
@@ -459,15 +471,16 @@ static int vp7_fade_frame(VP8Context *s, VP56RangeCoder *c)
if (s->framep[VP56_FRAME_GOLDEN] == s->framep[VP56_FRAME_PREVIOUS]) {
s->framep[VP56_FRAME_PREVIOUS] = vp8_find_free_buffer(s);
if ((ret = vp8_alloc_frame(s, s->framep[VP56_FRAME_PREVIOUS], 1)) < 0)
- return ret;
+ return ret;
dst = s->framep[VP56_FRAME_PREVIOUS]->tf.f;
- copy_luma(dst, src, width, height);
+ copy_chroma(dst, src, width, height);
}
- fade(dst->data[0], src->data[0],
- width, height, dst->linesize[0], alpha, beta);
+ fade(dst->data[0], dst->linesize[0],
+ src->data[0], src->linesize[0],
+ width, height, alpha, beta);
}
return 0;
@@ -490,6 +503,11 @@ static int vp7_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si
s->invisible = 0;
part1_size = AV_RL24(buf) >> 4;
+ if (buf_size < 4 - s->profile + part1_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "Buffer size %d is too small, needed : %d\n", buf_size, 4 - s->profile + part1_size);
+ return AVERROR_INVALIDDATA;
+ }
+
buf += 4 - s->profile;
buf_size -= 4 - s->profile;
@@ -538,7 +556,7 @@ static int vp7_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si
if (vp7_feature_value_size[s->profile][i])
for (j = 0; j < 4; j++)
s->feature_value[i][j] =
- vp8_rac_get(c) ? vp8_rac_get_uint(c, vp7_feature_value_size[s->profile][i]) : 0;
+ vp8_rac_get(c) ? vp8_rac_get_uint(c, vp7_feature_value_size[s->profile][i]) : 0;
}
}
@@ -701,11 +719,12 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si
}
if (!s->macroblocks_base || /* first frame */
- width != s->avctx->width || height != s->avctx->height)
+ width != s->avctx->width || height != s->avctx->height ||
+ (width+15)/16 != s->mb_width || (height+15)/16 != s->mb_height)
if ((ret = vp8_update_dimensions(s, width, height)) < 0)
return ret;
- get_quants(s);
+ vp8_get_quants(s);
if (!s->keyframe) {
update_refs(s);
@@ -745,7 +764,7 @@ void clamp_mv(VP8Context *s, VP56mv *dst, const VP56mv *src)
/**
* Motion vector coding, 17.1.
*/
-static int read_mv_component(VP56RangeCoder *c, const uint8_t *p, int vp7)
+static av_always_inline int read_mv_component(VP56RangeCoder *c, const uint8_t *p, int vp7)
{
int bit, x = 0;
@@ -773,6 +792,16 @@ static int read_mv_component(VP56RangeCoder *c, const uint8_t *p, int vp7)
return (x && vp56_rac_get_prob(c, p[1])) ? -x : x;
}
+static int vp7_read_mv_component(VP56RangeCoder *c, const uint8_t *p)
+{
+ return read_mv_component(c, p, 1);
+}
+
+static int vp8_read_mv_component(VP56RangeCoder *c, const uint8_t *p)
+{
+ return read_mv_component(c, p, 0);
+}
+
static av_always_inline
const uint8_t *get_submv_prob(uint32_t left, uint32_t top, int is_vp7)
{
@@ -963,8 +992,8 @@ void vp7_decode_mvs(VP8Context *s, VP8Macroblock *mb,
mb->mode = VP8_MVMODE_SPLIT;
mb->mv = mb->bmv[decode_splitmvs(s, c, mb, layout, IS_VP7) - 1];
} else {
- mb->mv.y += read_mv_component(c, s->prob->mvc[0], IS_VP7);
- mb->mv.x += read_mv_component(c, s->prob->mvc[1], IS_VP7);
+ mb->mv.y += vp7_read_mv_component(c, s->prob->mvc[0]);
+ mb->mv.x += vp7_read_mv_component(c, s->prob->mvc[1]);
mb->bmv[0] = mb->mv;
}
} else {
@@ -1063,8 +1092,8 @@ void vp8_decode_mvs(VP8Context *s, VP8Macroblock *mb,
mb->mode = VP8_MVMODE_SPLIT;
mb->mv = mb->bmv[decode_splitmvs(s, c, mb, layout, IS_VP8) - 1];
} else {
- mb->mv.y += read_mv_component(c, s->prob->mvc[0], IS_VP8);
- mb->mv.x += read_mv_component(c, s->prob->mvc[1], IS_VP8);
+ mb->mv.y += vp8_read_mv_component(c, s->prob->mvc[0]);
+ mb->mv.x += vp8_read_mv_component(c, s->prob->mvc[1]);
mb->bmv[0] = mb->mv;
}
} else {
@@ -1088,7 +1117,7 @@ void decode_intra4x4_modes(VP8Context *s, VP56RangeCoder *c, VP8Macroblock *mb,
{
uint8_t *intra4x4 = mb->intra4x4_pred_mode_mb;
- if (layout == 1) {
+ if (layout) {
VP8Macroblock *mb_top = mb - s->mb_width - 1;
memcpy(mb->intra4x4_pred_mode_top, mb_top->intra4x4_pred_mode_top, 4);
}
@@ -1096,7 +1125,7 @@ void decode_intra4x4_modes(VP8Context *s, VP56RangeCoder *c, VP8Macroblock *mb,
int x, y;
uint8_t *top;
uint8_t *const left = s->intra4x4_pred_mode_left;
- if (layout == 1)
+ if (layout)
top = mb->intra4x4_pred_mode_top;
else
top = s->intra4x4_pred_mode_top + 4 * mb_x;
@@ -1131,7 +1160,7 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y,
*segment = 0;
for (i = 0; i < 4; i++) {
if (s->feature_enabled[i]) {
- if (vp56_rac_get_prob(c, s->feature_present_prob[i])) {
+ if (vp56_rac_get_prob_branchy(c, s->feature_present_prob[i])) {
int index = vp8_rac_get_tree(c, vp7_feature_index_tree,
s->feature_index_prob[i]);
av_log(s->avctx, AV_LOG_WARNING,
@@ -1140,9 +1169,10 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y,
}
}
}
- } else if (s->segmentation.update_map)
- *segment = vp8_rac_get_tree(c, vp8_segmentid_tree, s->prob->segmentid);
- else if (s->segmentation.enabled)
+ } else if (s->segmentation.update_map) {
+ int bit = vp56_rac_get_prob(c, s->prob->segmentid[0]);
+ *segment = vp56_rac_get_prob(c, s->prob->segmentid[1+bit]) + 2*bit;
+ } else if (s->segmentation.enabled)
*segment = ref ? *ref : *segment;
mb->segment = *segment;
@@ -1157,7 +1187,7 @@ void decode_mb_mode(VP8Context *s, VP8Macroblock *mb, int mb_x, int mb_y,
} else {
const uint32_t modes = (is_vp7 ? vp7_pred4x4_mode
: vp8_pred4x4_mode)[mb->mode] * 0x01010101u;
- if (s->mb_layout == 1)
+ if (s->mb_layout)
AV_WN32A(mb->intra4x4_pred_mode_top, modes);
else
AV_WN32A(s->intra4x4_pred_mode_top + 4 * mb_x, modes);
@@ -1321,6 +1351,7 @@ static int vp8_decode_block_coeffs_internal(VP56RangeCoder *r,
* @param zero_nhood the initial prediction context for number of surrounding
* all-zero blocks (only left/top, so 0-2)
* @param qmul array holding the dc/ac dequant factor at position 0/1
+ * @param scan scan pattern (VP7 only)
*
* @return 0 if no coeffs were decoded
* otherwise, the index of the last coeff decoded plus one
@@ -1584,7 +1615,7 @@ void intra_predict(VP8Context *s, VP8ThreadData *td, uint8_t *dst[3],
for (x = 0; x < 4; x++) {
int copy = 0, linesize = s->linesize;
uint8_t *dst = ptr + 4 * x;
- DECLARE_ALIGNED(4, uint8_t, copy_dst)[5 * 8];
+ LOCAL_ALIGNED(4, uint8_t, copy_dst, [5 * 8]);
if ((y == 0 || x == 3) && mb_y == 0) {
topright = tr_top;
@@ -1690,8 +1721,8 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst,
if (AV_RN32A(mv)) {
int src_linesize = linesize;
- int mx = (mv->x << 1) & 7, mx_idx = subpel_idx[0][mx];
- int my = (mv->y << 1) & 7, my_idx = subpel_idx[0][my];
+ int mx = (mv->x * 2) & 7, mx_idx = subpel_idx[0][mx];
+ int my = (mv->y * 2) & 7, my_idx = subpel_idx[0][my];
x_off += mv->x >> 2;
y_off += mv->y >> 2;
@@ -1761,7 +1792,8 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1,
s->vdsp.emulated_edge_mc(td->edge_emu_buffer,
src1 - my_idx * linesize - mx_idx,
EDGE_EMU_LINESIZE, linesize,
- block_w + subpel_idx[1][mx], block_h + subpel_idx[1][my],
+ block_w + subpel_idx[1][mx],
+ block_h + subpel_idx[1][my],
x_off - mx_idx, y_off - my_idx, width, height);
src1 = td->edge_emu_buffer + mx_idx + EDGE_EMU_LINESIZE * my_idx;
mc_func[my_idx][mx_idx](dst1, linesize, src1, EDGE_EMU_LINESIZE, block_h, mx, my);
@@ -1769,7 +1801,8 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1,
s->vdsp.emulated_edge_mc(td->edge_emu_buffer,
src2 - my_idx * linesize - mx_idx,
EDGE_EMU_LINESIZE, linesize,
- block_w + subpel_idx[1][mx], block_h + subpel_idx[1][my],
+ block_w + subpel_idx[1][mx],
+ block_h + subpel_idx[1][my],
x_off - mx_idx, y_off - my_idx, width, height);
src2 = td->edge_emu_buffer + mx_idx + EDGE_EMU_LINESIZE * my_idx;
mc_func[my_idx][mx_idx](dst2, linesize, src2, EDGE_EMU_LINESIZE, block_h, mx, my);
@@ -2205,7 +2238,7 @@ static void vp8_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame,
td->wait_mb_pos = INT_MAX; \
pthread_mutex_unlock(&otd->lock); \
} \
- } while (0);
+ } while (0)
#define update_pos(td, mb_y, mb_x) \
do { \
@@ -2224,13 +2257,13 @@ static void vp8_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame,
pthread_cond_broadcast(&td->cond); \
pthread_mutex_unlock(&td->lock); \
} \
- } while (0);
+ } while (0)
#else
-#define check_thread_pos(td, otd, mb_x_check, mb_y_check)
-#define update_pos(td, mb_y, mb_x)
+#define check_thread_pos(td, otd, mb_x_check, mb_y_check) while(0)
+#define update_pos(td, mb_y, mb_x) while(0)
#endif
-static void vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata,
+static av_always_inline void decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata,
int jobnr, int threadnr, int is_vp7)
{
VP8Context *s = avctx->priv_data;
@@ -2351,7 +2384,19 @@ static void vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata,
}
}
-static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata,
+static void vp7_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata,
+ int jobnr, int threadnr)
+{
+ decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 1);
+}
+
+static void vp8_decode_mb_row_no_filter(AVCodecContext *avctx, void *tdata,
+ int jobnr, int threadnr)
+{
+ decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, 0);
+}
+
+static av_always_inline void filter_mb_row(AVCodecContext *avctx, void *tdata,
int jobnr, int threadnr, int is_vp7)
{
VP8Context *s = avctx->priv_data;
@@ -2410,6 +2455,18 @@ static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata,
}
}
+static void vp7_filter_mb_row(AVCodecContext *avctx, void *tdata,
+ int jobnr, int threadnr)
+{
+ filter_mb_row(avctx, tdata, jobnr, threadnr, 1);
+}
+
+static void vp8_filter_mb_row(AVCodecContext *avctx, void *tdata,
+ int jobnr, int threadnr)
+{
+ filter_mb_row(avctx, tdata, jobnr, threadnr, 0);
+}
+
static av_always_inline
int vp78_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, int jobnr,
int threadnr, int is_vp7)
@@ -2425,9 +2482,9 @@ int vp78_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, int jobnr,
if (mb_y >= s->mb_height)
break;
td->thread_mb_pos = mb_y << 16;
- vp8_decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr, is_vp7);
+ s->decode_mb_row_no_filter(avctx, tdata, jobnr, threadnr);
if (s->deblock_filter)
- vp8_filter_mb_row(avctx, tdata, jobnr, threadnr, is_vp7);
+ s->filter_mb_row(avctx, tdata, jobnr, threadnr);
update_pos(td, mb_y, INT_MAX & 0xFFFF);
s->mv_min.y -= 64;
@@ -2520,10 +2577,8 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
curframe->tf.f->key_frame = s->keyframe;
curframe->tf.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I
: AV_PICTURE_TYPE_P;
- if ((ret = vp8_alloc_frame(s, curframe, referenced))) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed!\n");
+ if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0)
goto err;
- }
// check if golden and altref are swapped
if (s->update_altref != VP56_FRAME_NONE)
@@ -2543,7 +2598,8 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->next_framep[VP56_FRAME_CURRENT] = curframe;
- ff_thread_finish_setup(avctx);
+ if (avctx->codec->update_thread_context)
+ ff_thread_finish_setup(avctx);
s->linesize = curframe->tf.f->linesize[0];
s->uvlinesize = curframe->tf.f->linesize[1];
@@ -2656,6 +2712,7 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7)
int ret;
s->avctx = avctx;
+ s->vp7 = avctx->codec->id == AV_CODEC_ID_VP7;
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
avctx->internal->allocate_progress = 1;
@@ -2665,9 +2722,13 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7)
if (CONFIG_VP7_DECODER && is_vp7) {
ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP7, 8, 1);
ff_vp7dsp_init(&s->vp8dsp);
+ s->decode_mb_row_no_filter = vp7_decode_mb_row_no_filter;
+ s->filter_mb_row = vp7_filter_mb_row;
} else if (CONFIG_VP8_DECODER && !is_vp7) {
ff_h264_pred_init(&s->hpc, AV_CODEC_ID_VP8, 8, 1);
ff_vp8dsp_init(&s->vp8dsp);
+ s->decode_mb_row_no_filter = vp8_decode_mb_row_no_filter;
+ s->filter_mb_row = vp8_filter_mb_row;
}
/* does not change for VP8 */
@@ -2709,7 +2770,7 @@ static av_cold int vp8_decode_init_thread_copy(AVCodecContext *avctx)
return 0;
}
-#define REBASE(pic) pic ? pic - &s_src->frames[0] + &s->frames[0] : NULL
+#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)
diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h
index 2919a143af..b650892735 100644
--- a/libavcodec/vp8.h
+++ b/libavcodec/vp8.h
@@ -6,20 +6,20 @@
* Copyright (C) 2010 Fiona Glaser
* Copyright (C) 2012 Daniel Kang
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,6 +35,8 @@
#if HAVE_PTHREADS
# include <pthread.h>
+#elif HAVE_OS2THREADS
+# include "compat/os2threads.h"
#elif HAVE_W32THREADS
# include "compat/w32pthreads.h"
#endif
@@ -275,6 +277,11 @@ typedef struct VP8Context {
*/
int mb_layout;
+ void (*decode_mb_row_no_filter)(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr);
+ void (*filter_mb_row)(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr);
+
+ int vp7;
+
/**
* Fade bit present in bitstream (VP7)
*/
diff --git a/libavcodec/vp8_parser.c b/libavcodec/vp8_parser.c
index 8f6459ccec..afc7f991e6 100644
--- a/libavcodec/vp8_parser.c
+++ b/libavcodec/vp8_parser.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2008 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp8data.h b/libavcodec/vp8data.h
index b49dea98fa..f9dbf56feb 100644
--- a/libavcodec/vp8data.h
+++ b/libavcodec/vp8data.h
@@ -2,20 +2,20 @@
* Copyright (C) 2010 David Conrad
* Copyright (C) 2010 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp8dsp.c b/libavcodec/vp8dsp.c
index 4e4012f88e..e1a91bb8c6 100644
--- a/libavcodec/vp8dsp.c
+++ b/libavcodec/vp8dsp.c
@@ -3,20 +3,20 @@
* Copyright (C) 2010 Ronald S. Bultje
* Copyright (C) 2014 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
*/
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "mathops.h"
#include "vp8dsp.h"
@@ -71,10 +72,7 @@ static void vp7_luma_dc_wht_c(int16_t block[4][4][16], int16_t dc[16])
b1 = (tmp[i + 0] - tmp[i + 8]) * 23170;
c1 = tmp[i + 4] * 12540 - tmp[i + 12] * 30274;
d1 = tmp[i + 4] * 30274 + tmp[i + 12] * 12540;
- dc[i * 4 + 0] = 0;
- dc[i * 4 + 1] = 0;
- dc[i * 4 + 2] = 0;
- dc[i * 4 + 3] = 0;
+ AV_ZERO64(dc + i * 4);
block[0][i][0] = (a1 + d1 + 0x20000) >> 18;
block[3][i][0] = (a1 - d1 + 0x20000) >> 18;
block[1][i][0] = (b1 + c1 + 0x20000) >> 18;
@@ -105,10 +103,7 @@ static void vp7_idct_add_c(uint8_t *dst, int16_t block[16], ptrdiff_t stride)
b1 = (block[i * 4 + 0] - block[i * 4 + 2]) * 23170;
c1 = block[i * 4 + 1] * 12540 - block[i * 4 + 3] * 30274;
d1 = block[i * 4 + 1] * 30274 + block[i * 4 + 3] * 12540;
- block[i * 4 + 0] = 0;
- block[i * 4 + 1] = 0;
- block[i * 4 + 2] = 0;
- block[i * 4 + 3] = 0;
+ AV_ZERO64(block + i * 4);
tmp[i * 4 + 0] = (a1 + d1) >> 14;
tmp[i * 4 + 3] = (a1 - d1) >> 14;
tmp[i * 4 + 1] = (b1 + c1) >> 14;
@@ -171,10 +166,7 @@ static void vp8_luma_dc_wht_c(int16_t block[4][4][16], int16_t dc[16])
t1 = dc[i * 4 + 1] + dc[i * 4 + 2];
t2 = dc[i * 4 + 1] - dc[i * 4 + 2];
t3 = dc[i * 4 + 0] - dc[i * 4 + 3] + 3; // rounding
- dc[i * 4 + 0] = 0;
- dc[i * 4 + 1] = 0;
- dc[i * 4 + 2] = 0;
- dc[i * 4 + 3] = 0;
+ AV_ZERO64(dc + i * 4);
block[i][0][0] = (t0 + t1) >> 3;
block[i][1][0] = (t3 + t2) >> 3;
@@ -262,7 +254,7 @@ MK_IDCT_DC_ADD4_C(vp8)
int av_unused q2 = p[ 2 * stride]; \
int av_unused q3 = p[ 3 * stride];
-#define clip_int8(n) (cm[n + 0x80] - 0x80)
+#define clip_int8(n) (cm[(n) + 0x80] - 0x80)
static av_always_inline void filter_common(uint8_t *p, ptrdiff_t stride,
int is4tap, int is_vp7)
diff --git a/libavcodec/vp8dsp.h b/libavcodec/vp8dsp.h
index 4864cf7969..5fdd3af70d 100644
--- a/libavcodec/vp8dsp.h
+++ b/libavcodec/vp8dsp.h
@@ -2,20 +2,20 @@
* Copyright (C) 2010 David Conrad
* Copyright (C) 2010 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 50b84ae97e..93b3c96e23 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -4,99 +4,414 @@
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
* Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avcodec.h"
#include "get_bits.h"
#include "internal.h"
+#include "thread.h"
#include "videodsp.h"
#include "vp56.h"
#include "vp9.h"
#include "vp9data.h"
+#include "vp9dsp.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
#define VP9_SYNCCODE 0x498342
-#define MAX_PROB 255
-static void vp9_decode_flush(AVCodecContext *avctx)
+enum CompPredMode {
+ PRED_SINGLEREF,
+ PRED_COMPREF,
+ PRED_SWITCHABLE,
+};
+
+enum BlockLevel {
+ BL_64X64,
+ BL_32X32,
+ BL_16X16,
+ BL_8X8,
+};
+
+enum BlockSize {
+ BS_64x64,
+ BS_64x32,
+ BS_32x64,
+ BS_32x32,
+ BS_32x16,
+ BS_16x32,
+ BS_16x16,
+ BS_16x8,
+ BS_8x16,
+ BS_8x8,
+ BS_8x4,
+ BS_4x8,
+ BS_4x4,
+ N_BS_SIZES,
+};
+
+struct VP9mvrefPair {
+ VP56mv mv[2];
+ int8_t ref[2];
+};
+
+typedef struct VP9Frame {
+ ThreadFrame tf;
+ AVBufferRef *extradata;
+ uint8_t *segmentation_map;
+ struct VP9mvrefPair *mv;
+ int uses_2pass;
+} VP9Frame;
+
+struct VP9Filter {
+ uint8_t level[8 * 8];
+ uint8_t /* bit=col */ mask[2 /* 0=y, 1=uv */][2 /* 0=col, 1=row */]
+ [8 /* rows */][4 /* 0=16, 1=8, 2=4, 3=inner4 */];
+};
+
+typedef struct VP9Block {
+ uint8_t seg_id, intra, comp, ref[2], mode[4], uvmode, skip;
+ enum FilterMode filter;
+ VP56mv mv[4 /* b_idx */][2 /* ref */];
+ enum BlockSize bs;
+ enum TxfmMode tx, uvtx;
+ enum BlockLevel bl;
+ enum BlockPartition bp;
+} VP9Block;
+
+typedef struct VP9Context {
+ VP9DSPContext dsp;
+ VideoDSPContext vdsp;
+ GetBitContext gb;
+ VP56RangeCoder c;
+ VP56RangeCoder *c_b;
+ unsigned c_b_size;
+ VP9Block *b_base, *b;
+ int pass;
+ int row, row7, col, col7;
+ uint8_t *dst[3];
+ ptrdiff_t y_stride, uv_stride;
+
+ // bitstream header
+ uint8_t keyframe, last_keyframe;
+ uint8_t last_bpp, bpp, bpp_index, bytesperpixel;
+ uint8_t invisible;
+ uint8_t use_last_frame_mvs;
+ uint8_t errorres;
+ uint8_t ss_h, ss_v;
+ uint8_t intraonly;
+ uint8_t resetctx;
+ uint8_t refreshrefmask;
+ uint8_t highprecisionmvs;
+ enum FilterMode filtermode;
+ uint8_t allowcompinter;
+ uint8_t fixcompref;
+ uint8_t refreshctx;
+ uint8_t parallelmode;
+ uint8_t framectxid;
+ uint8_t refidx[3];
+ uint8_t signbias[3];
+ uint8_t varcompref[2];
+ ThreadFrame refs[8], next_refs[8];
+#define CUR_FRAME 0
+#define REF_FRAME_MVPAIR 1
+#define REF_FRAME_SEGMAP 2
+ VP9Frame frames[3];
+
+ struct {
+ uint8_t level;
+ int8_t sharpness;
+ uint8_t lim_lut[64];
+ uint8_t mblim_lut[64];
+ } filter;
+ struct {
+ uint8_t enabled;
+ int8_t mode[2];
+ int8_t ref[4];
+ } lf_delta;
+ uint8_t yac_qi;
+ int8_t ydc_qdelta, uvdc_qdelta, uvac_qdelta;
+ uint8_t lossless;
+#define MAX_SEGMENT 8
+ struct {
+ uint8_t enabled;
+ uint8_t temporal;
+ uint8_t absolute_vals;
+ uint8_t update_map;
+ uint8_t ignore_refmap;
+ struct {
+ uint8_t q_enabled;
+ uint8_t lf_enabled;
+ uint8_t ref_enabled;
+ uint8_t skip_enabled;
+ uint8_t ref_val;
+ int16_t q_val;
+ int8_t lf_val;
+ int16_t qmul[2][2];
+ uint8_t lflvl[4][2];
+ } feat[MAX_SEGMENT];
+ } segmentation;
+ struct {
+ unsigned log2_tile_cols, log2_tile_rows;
+ unsigned tile_cols, tile_rows;
+ unsigned tile_row_start, tile_row_end, tile_col_start, tile_col_end;
+ } tiling;
+ unsigned sb_cols, sb_rows, rows, cols;
+ struct {
+ prob_context p;
+ uint8_t coef[4][2][2][6][6][3];
+ } prob_ctx[4];
+ struct {
+ prob_context p;
+ uint8_t coef[4][2][2][6][6][11];
+ uint8_t seg[7];
+ uint8_t segpred[3];
+ } prob;
+ struct {
+ unsigned y_mode[4][10];
+ unsigned uv_mode[10][10];
+ unsigned filter[4][3];
+ unsigned mv_mode[7][4];
+ unsigned intra[4][2];
+ unsigned comp[5][2];
+ unsigned single_ref[5][2][2];
+ unsigned comp_ref[5][2];
+ unsigned tx32p[2][4];
+ unsigned tx16p[2][3];
+ unsigned tx8p[2][2];
+ unsigned skip[3][2];
+ unsigned mv_joint[4];
+ struct {
+ unsigned sign[2];
+ unsigned classes[11];
+ unsigned class0[2];
+ unsigned bits[10][2];
+ unsigned class0_fp[2][4];
+ unsigned fp[4];
+ unsigned class0_hp[2];
+ unsigned hp[2];
+ } mv_comp[2];
+ unsigned partition[4][4][4];
+ unsigned coef[4][2][2][6][6][3];
+ unsigned eob[4][2][2][6][6][2];
+ } counts;
+ enum TxfmMode txfmmode;
+ enum CompPredMode comppredmode;
+
+ // contextual (left/above) cache
+ DECLARE_ALIGNED(16, uint8_t, left_y_nnz_ctx)[16];
+ DECLARE_ALIGNED(16, uint8_t, left_mode_ctx)[16];
+ DECLARE_ALIGNED(16, VP56mv, left_mv_ctx)[16][2];
+ DECLARE_ALIGNED(16, uint8_t, left_uv_nnz_ctx)[2][16];
+ DECLARE_ALIGNED(8, uint8_t, left_partition_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_skip_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_txfm_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_segpred_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_intra_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_comp_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_ref_ctx)[8];
+ DECLARE_ALIGNED(8, uint8_t, left_filter_ctx)[8];
+ uint8_t *above_partition_ctx;
+ uint8_t *above_mode_ctx;
+ // FIXME maybe merge some of the below in a flags field?
+ uint8_t *above_y_nnz_ctx;
+ uint8_t *above_uv_nnz_ctx[2];
+ uint8_t *above_skip_ctx; // 1bit
+ uint8_t *above_txfm_ctx; // 2bit
+ uint8_t *above_segpred_ctx; // 1bit
+ uint8_t *above_intra_ctx; // 1bit
+ uint8_t *above_comp_ctx; // 1bit
+ uint8_t *above_ref_ctx; // 2bit
+ uint8_t *above_filter_ctx;
+ VP56mv (*above_mv_ctx)[2];
+
+ // whole-frame cache
+ uint8_t *intra_pred_data[3];
+ struct VP9Filter *lflvl;
+ DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[135 * 144 * 2];
+
+ // block reconstruction intermediates
+ int block_alloc_using_2pass;
+ int16_t *block_base, *block, *uvblock_base[2], *uvblock[2];
+ uint8_t *eob_base, *uveob_base[2], *eob, *uveob[2];
+ struct { int x, y; } min_mv, max_mv;
+ DECLARE_ALIGNED(32, uint8_t, tmp_y)[64 * 64 * 2];
+ DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][64 * 64 * 2];
+ uint16_t mvscale[3][2];
+ uint8_t mvstep[3][2];
+} VP9Context;
+
+static const uint8_t bwh_tab[2][N_BS_SIZES][2] = {
+ {
+ { 16, 16 }, { 16, 8 }, { 8, 16 }, { 8, 8 }, { 8, 4 }, { 4, 8 },
+ { 4, 4 }, { 4, 2 }, { 2, 4 }, { 2, 2 }, { 2, 1 }, { 1, 2 }, { 1, 1 },
+ }, {
+ { 8, 8 }, { 8, 4 }, { 4, 8 }, { 4, 4 }, { 4, 2 }, { 2, 4 },
+ { 2, 2 }, { 2, 1 }, { 1, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 },
+ }
+};
+
+static int vp9_alloc_frame(AVCodecContext *ctx, VP9Frame *f)
{
- VP9Context *s = avctx->priv_data;
- int i;
+ VP9Context *s = ctx->priv_data;
+ int ret, sz;
+
+ if ((ret = ff_thread_get_buffer(ctx, &f->tf, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+ sz = 64 * s->sb_cols * s->sb_rows;
+ if (!(f->extradata = av_buffer_allocz(sz * (1 + sizeof(struct VP9mvrefPair))))) {
+ ff_thread_release_buffer(ctx, &f->tf);
+ return AVERROR(ENOMEM);
+ }
+
+ f->segmentation_map = f->extradata->data;
+ f->mv = (struct VP9mvrefPair *) (f->extradata->data + sz);
+
+ return 0;
+}
- for (i = 0; i < FF_ARRAY_ELEMS(s->refs); i++)
- av_frame_unref(s->refs[i]);
+static void vp9_unref_frame(AVCodecContext *ctx, VP9Frame *f)
+{
+ ff_thread_release_buffer(ctx, &f->tf);
+ av_buffer_unref(&f->extradata);
}
-static int update_size(AVCodecContext *avctx, int w, int h)
+static int vp9_ref_frame(AVCodecContext *ctx, VP9Frame *dst, VP9Frame *src)
{
- VP9Context *s = avctx->priv_data;
+ int res;
+
+ if ((res = ff_thread_ref_frame(&dst->tf, &src->tf)) < 0) {
+ return res;
+ } else if (!(dst->extradata = av_buffer_ref(src->extradata))) {
+ vp9_unref_frame(ctx, dst);
+ return AVERROR(ENOMEM);
+ }
+
+ dst->segmentation_map = src->segmentation_map;
+ dst->mv = src->mv;
+ dst->uses_2pass = src->uses_2pass;
+
+ return 0;
+}
+
+static int update_size(AVCodecContext *ctx, int w, int h, enum AVPixelFormat fmt)
+{
+ VP9Context *s = ctx->priv_data;
uint8_t *p;
+ int bytesperpixel = s->bytesperpixel;
- if (s->above_partition_ctx && w == avctx->width && h == avctx->height)
- return 0;
+ av_assert0(w > 0 && h > 0);
- vp9_decode_flush(avctx);
+ if (s->intra_pred_data[0] && w == ctx->width && h == ctx->height && ctx->pix_fmt == fmt)
+ return 0;
- if (w <= 0 || h <= 0)
- return AVERROR_INVALIDDATA;
+ ctx->width = w;
+ ctx->height = h;
+ ctx->pix_fmt = fmt;
+ s->sb_cols = (w + 63) >> 6;
+ s->sb_rows = (h + 63) >> 6;
+ s->cols = (w + 7) >> 3;
+ s->rows = (h + 7) >> 3;
- avctx->width = w;
- avctx->height = h;
- s->sb_cols = (w + 63) >> 6;
- s->sb_rows = (h + 63) >> 6;
- s->cols = (w + 7) >> 3;
- s->rows = (h + 7) >> 3;
-
-#define assign(var, type, n) var = (type)p; p += s->sb_cols * n * sizeof(*var)
- av_free(s->above_partition_ctx);
- p = av_malloc(s->sb_cols *
- (240 + sizeof(*s->lflvl) + 16 * sizeof(*s->above_mv_ctx) +
- 64 * s->sb_rows * (1 + sizeof(*s->mv[0]) * 2)));
+#define assign(var, type, n) var = (type) p; p += s->sb_cols * (n) * sizeof(*var)
+ av_freep(&s->intra_pred_data[0]);
+ // FIXME we slightly over-allocate here for subsampled chroma, but a little
+ // bit of padding shouldn't affect performance...
+ p = av_malloc(s->sb_cols * (128 + 192 * bytesperpixel +
+ sizeof(*s->lflvl) + 16 * sizeof(*s->above_mv_ctx)));
if (!p)
return AVERROR(ENOMEM);
- assign(s->above_partition_ctx, uint8_t *, 8);
- assign(s->above_skip_ctx, uint8_t *, 8);
- assign(s->above_txfm_ctx, uint8_t *, 8);
- assign(s->above_mode_ctx, uint8_t *, 16);
- assign(s->above_y_nnz_ctx, uint8_t *, 16);
- assign(s->above_uv_nnz_ctx[0], uint8_t *, 8);
- assign(s->above_uv_nnz_ctx[1], uint8_t *, 8);
- assign(s->intra_pred_data[0], uint8_t *, 64);
- assign(s->intra_pred_data[1], uint8_t *, 32);
- assign(s->intra_pred_data[2], uint8_t *, 32);
- assign(s->above_segpred_ctx, uint8_t *, 8);
- assign(s->above_intra_ctx, uint8_t *, 8);
- assign(s->above_comp_ctx, uint8_t *, 8);
- assign(s->above_ref_ctx, uint8_t *, 8);
- assign(s->above_filter_ctx, uint8_t *, 8);
- assign(s->lflvl, VP9Filter *, 1);
- assign(s->above_mv_ctx, VP56mv(*)[2], 16);
- assign(s->segmentation_map, uint8_t *, 64 * s->sb_rows);
- assign(s->mv[0], VP9MVRefPair *, 64 * s->sb_rows);
- assign(s->mv[1], VP9MVRefPair *, 64 * s->sb_rows);
+ assign(s->intra_pred_data[0], uint8_t *, 64 * bytesperpixel);
+ assign(s->intra_pred_data[1], uint8_t *, 64 * bytesperpixel);
+ assign(s->intra_pred_data[2], uint8_t *, 64 * bytesperpixel);
+ assign(s->above_y_nnz_ctx, uint8_t *, 16);
+ assign(s->above_mode_ctx, uint8_t *, 16);
+ assign(s->above_mv_ctx, VP56mv(*)[2], 16);
+ assign(s->above_uv_nnz_ctx[0], uint8_t *, 16);
+ assign(s->above_uv_nnz_ctx[1], uint8_t *, 16);
+ assign(s->above_partition_ctx, uint8_t *, 8);
+ assign(s->above_skip_ctx, uint8_t *, 8);
+ assign(s->above_txfm_ctx, uint8_t *, 8);
+ assign(s->above_segpred_ctx, uint8_t *, 8);
+ assign(s->above_intra_ctx, uint8_t *, 8);
+ assign(s->above_comp_ctx, uint8_t *, 8);
+ assign(s->above_ref_ctx, uint8_t *, 8);
+ assign(s->above_filter_ctx, uint8_t *, 8);
+ assign(s->lflvl, struct VP9Filter *, 1);
#undef assign
+ // these will be re-allocated a little later
+ av_freep(&s->b_base);
+ av_freep(&s->block_base);
+
+ if (s->bpp != s->last_bpp) {
+ ff_vp9dsp_init(&s->dsp, s->bpp);
+ ff_videodsp_init(&s->vdsp, s->bpp);
+ s->last_bpp = s->bpp;
+ }
+
+ return 0;
+}
+
+static int update_block_buffers(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int chroma_blocks, chroma_eobs, bytesperpixel = s->bytesperpixel;
+
+ if (s->b_base && s->block_base && s->block_alloc_using_2pass == s->frames[CUR_FRAME].uses_2pass)
+ return 0;
+
+ av_free(s->b_base);
+ av_free(s->block_base);
+ chroma_blocks = 64 * 64 >> (s->ss_h + s->ss_v);
+ chroma_eobs = 16 * 16 >> (s->ss_h + s->ss_v);
+ if (s->frames[CUR_FRAME].uses_2pass) {
+ int sbs = s->sb_cols * s->sb_rows;
+
+ s->b_base = av_malloc_array(s->cols * s->rows, sizeof(VP9Block));
+ s->block_base = av_mallocz(((64 * 64 + 2 * chroma_blocks) * bytesperpixel * sizeof(int16_t) +
+ 16 * 16 + 2 * chroma_eobs) * sbs);
+ if (!s->b_base || !s->block_base)
+ return AVERROR(ENOMEM);
+ s->uvblock_base[0] = s->block_base + sbs * 64 * 64 * bytesperpixel;
+ s->uvblock_base[1] = s->uvblock_base[0] + sbs * chroma_blocks * bytesperpixel;
+ s->eob_base = (uint8_t *) (s->uvblock_base[1] + sbs * chroma_blocks * bytesperpixel);
+ s->uveob_base[0] = s->eob_base + 16 * 16 * sbs;
+ s->uveob_base[1] = s->uveob_base[0] + chroma_eobs * sbs;
+ } else {
+ s->b_base = av_malloc(sizeof(VP9Block));
+ s->block_base = av_mallocz((64 * 64 + 2 * chroma_blocks) * bytesperpixel * sizeof(int16_t) +
+ 16 * 16 + 2 * chroma_eobs);
+ if (!s->b_base || !s->block_base)
+ return AVERROR(ENOMEM);
+ s->uvblock_base[0] = s->block_base + 64 * 64 * bytesperpixel;
+ s->uvblock_base[1] = s->uvblock_base[0] + chroma_blocks * bytesperpixel;
+ s->eob_base = (uint8_t *) (s->uvblock_base[1] + chroma_blocks * bytesperpixel);
+ s->uveob_base[0] = s->eob_base + 16 * 16;
+ s->uveob_base[1] = s->uveob_base[0] + chroma_eobs;
+ }
+ s->block_alloc_using_2pass = s->frames[CUR_FRAME].uses_2pass;
+
return 0;
}
-// The sign bit is at the end, not the start, of a bit sequence
-static av_always_inline int get_bits_with_sign(GetBitContext *gb, int n)
+// for some reason the sign bit is at the end, not the start, of a bit sequence
+static av_always_inline int get_sbits_inv(GetBitContext *gb, int n)
{
int v = get_bits(gb, n);
return get_bits1(gb) ? -v : v;
@@ -104,17 +419,13 @@ static av_always_inline int get_bits_with_sign(GetBitContext *gb, int n)
static av_always_inline int inv_recenter_nonneg(int v, int m)
{
- if (v > 2 * m)
- return v;
- if (v & 1)
- return m - ((v + 1) >> 1);
- return m + (v >> 1);
+ return v > 2 * m ? v : v & 1 ? m - ((v + 1) >> 1) : m + (v >> 1);
}
// differential forward probability updates
static int update_prob(VP56RangeCoder *c, int p)
{
- static const int inv_map_table[MAX_PROB - 1] = {
+ static const int inv_map_table[254] = {
7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176,
189, 202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24,
@@ -139,13 +450,13 @@ static int update_prob(VP56RangeCoder *c, int p)
/* This code is trying to do a differential probability update. For a
* current probability A in the range [1, 255], the difference to a new
- * probability of any value can be expressed differentially as 1-A, 255-A
+ * probability of any value can be expressed differentially as 1-A,255-A
* where some part of this (absolute range) exists both in positive as
* well as the negative part, whereas another part only exists in one
* half. We're trying to code this shared part differentially, i.e.
* times two where the value of the lowest bit specifies the sign, and
* the single part is then coded on top of this. This absolute difference
- * then again has a value of [0, 254], but a bigger value in this range
+ * then again has a value of [0,254], but a bigger value in this range
* indicates that we're further away from the original value A, so we
* can code this as a VLC code, since higher values are increasingly
* unlikely. The first 20 values in inv_map_table[] allow 'cheap, rough'
@@ -160,65 +471,115 @@ static int update_prob(VP56RangeCoder *c, int p)
d = vp8_rac_get_uint(c, 5) + 32;
} else {
d = vp8_rac_get_uint(c, 7);
- if (d >= 65) {
+ if (d >= 65)
d = (d << 1) - 65 + vp8_rac_get(c);
- d = av_clip(d, 0, MAX_PROB - 65 - 1);
- }
d += 64;
}
- return p <= 128
- ? 1 + inv_recenter_nonneg(inv_map_table[d], p - 1)
- : 255 - inv_recenter_nonneg(inv_map_table[d], 255 - p);
+ return p <= 128 ? 1 + inv_recenter_nonneg(inv_map_table[d], p - 1) :
+ 255 - inv_recenter_nonneg(inv_map_table[d], 255 - p);
+}
+
+static enum AVPixelFormat read_colorspace_details(AVCodecContext *ctx)
+{
+ static const enum AVColorSpace colorspaces[8] = {
+ AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M,
+ AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB,
+ };
+ VP9Context *s = ctx->priv_data;
+ enum AVPixelFormat res;
+ int bits = ctx->profile <= 1 ? 0 : 1 + get_bits1(&s->gb); // 0:8, 1:10, 2:12
+
+ s->bpp_index = bits;
+ s->bpp = 8 + bits * 2;
+ s->bytesperpixel = (7 + s->bpp) >> 3;
+ ctx->colorspace = colorspaces[get_bits(&s->gb, 3)];
+ if (ctx->colorspace == AVCOL_SPC_RGB) { // RGB = profile 1
+ static const enum AVPixelFormat pix_fmt_rgb[3] = {
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12
+ };
+ if (ctx->profile & 1) {
+ s->ss_h = s->ss_v = 1;
+ res = pix_fmt_rgb[bits];
+ ctx->color_range = AVCOL_RANGE_JPEG;
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "RGB not supported in profile %d\n",
+ ctx->profile);
+ return AVERROR_INVALIDDATA;
+ }
+ } else {
+ static const enum AVPixelFormat pix_fmt_for_ss[3][2 /* v */][2 /* h */] = {
+ { { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P },
+ { AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV420P } },
+ { { AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10 },
+ { AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV420P10 } },
+ { { AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12 },
+ { AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV420P12 } }
+ };
+ ctx->color_range = get_bits1(&s->gb) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
+ if (ctx->profile & 1) {
+ s->ss_h = get_bits1(&s->gb);
+ s->ss_v = get_bits1(&s->gb);
+ if ((res = pix_fmt_for_ss[bits][s->ss_v][s->ss_h]) == AV_PIX_FMT_YUV420P) {
+ av_log(ctx, AV_LOG_ERROR, "YUV 4:2:0 not supported in profile %d\n",
+ ctx->profile);
+ return AVERROR_INVALIDDATA;
+ } else if (get_bits1(&s->gb)) {
+ av_log(ctx, AV_LOG_ERROR, "Profile %d color details reserved bit set\n",
+ ctx->profile);
+ return AVERROR_INVALIDDATA;
+ }
+ } else {
+ s->ss_h = s->ss_v = 1;
+ res = pix_fmt_for_ss[bits][1][1];
+ }
+ }
+
+ return res;
}
-static int decode_frame_header(AVCodecContext *avctx,
+static int decode_frame_header(AVCodecContext *ctx,
const uint8_t *data, int size, int *ref)
{
- VP9Context *s = avctx->priv_data;
- int c, i, j, k, l, m, n, w, h, max, size2, ret, sharp;
+ VP9Context *s = ctx->priv_data;
+ int c, i, j, k, l, m, n, w, h, max, size2, res, sharp;
+ enum AVPixelFormat fmt = ctx->pix_fmt;
int last_invisible;
const uint8_t *data2;
/* general header */
- if ((ret = init_get_bits8(&s->gb, data, size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Failed to initialize bitstream reader\n");
- return ret;
+ if ((res = init_get_bits8(&s->gb, data, size)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to initialize bitstream reader\n");
+ return res;
}
if (get_bits(&s->gb, 2) != 0x2) { // frame marker
- av_log(avctx, AV_LOG_ERROR, "Invalid frame marker\n");
+ av_log(ctx, AV_LOG_ERROR, "Invalid frame marker\n");
return AVERROR_INVALIDDATA;
}
- s->profile = get_bits1(&s->gb);
- if (get_bits1(&s->gb)) { // reserved bit
- av_log(avctx, AV_LOG_ERROR, "Reserved bit should be zero\n");
+ ctx->profile = get_bits1(&s->gb);
+ ctx->profile |= get_bits1(&s->gb) << 1;
+ if (ctx->profile == 3) ctx->profile += get_bits1(&s->gb);
+ if (ctx->profile > 3) {
+ av_log(ctx, AV_LOG_ERROR, "Profile %d is not yet supported\n", ctx->profile);
return AVERROR_INVALIDDATA;
}
if (get_bits1(&s->gb)) {
*ref = get_bits(&s->gb, 3);
return 0;
}
-
- s->last_keyframe = s->keyframe;
- s->keyframe = !get_bits1(&s->gb);
-
- last_invisible = s->invisible;
- s->invisible = !get_bits1(&s->gb);
- s->errorres = get_bits1(&s->gb);
- // FIXME disable this upon resolution change
+ s->last_keyframe = s->keyframe;
+ s->keyframe = !get_bits1(&s->gb);
+ last_invisible = s->invisible;
+ s->invisible = !get_bits1(&s->gb);
+ s->errorres = get_bits1(&s->gb);
s->use_last_frame_mvs = !s->errorres && !last_invisible;
-
if (s->keyframe) {
if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode
- av_log(avctx, AV_LOG_ERROR, "Invalid sync code\n");
+ av_log(ctx, AV_LOG_ERROR, "Invalid sync code\n");
return AVERROR_INVALIDDATA;
}
- s->colorspace = get_bits(&s->gb, 3);
- if (s->colorspace == 7) { // RGB = profile 1
- av_log(avctx, AV_LOG_ERROR, "RGB not supported in profile 0\n");
- return AVERROR_INVALIDDATA;
- }
- s->fullrange = get_bits1(&s->gb);
+ if ((fmt = read_colorspace_details(ctx)) < 0)
+ return fmt;
// for profile 1, here follows the subsampling bits
s->refreshrefmask = 0xff;
w = get_bits(&s->gb, 16) + 1;
@@ -226,13 +587,25 @@ static int decode_frame_header(AVCodecContext *avctx,
if (get_bits1(&s->gb)) // display size
skip_bits(&s->gb, 32);
} else {
- s->intraonly = s->invisible ? get_bits1(&s->gb) : 0;
- s->resetctx = s->errorres ? 0 : get_bits(&s->gb, 2);
+ s->intraonly = s->invisible ? get_bits1(&s->gb) : 0;
+ s->resetctx = s->errorres ? 0 : get_bits(&s->gb, 2);
if (s->intraonly) {
if (get_bits_long(&s->gb, 24) != VP9_SYNCCODE) { // synccode
- av_log(avctx, AV_LOG_ERROR, "Invalid sync code\n");
+ av_log(ctx, AV_LOG_ERROR, "Invalid sync code\n");
return AVERROR_INVALIDDATA;
}
+ if (ctx->profile == 1) {
+ if ((fmt = read_colorspace_details(ctx)) < 0)
+ return fmt;
+ } else {
+ s->ss_h = s->ss_v = 1;
+ s->bpp = 8;
+ s->bpp_index = 0;
+ s->bytesperpixel = 1;
+ fmt = AV_PIX_FMT_YUV420P;
+ ctx->colorspace = AVCOL_SPC_BT470BG;
+ ctx->color_range = AVCOL_RANGE_JPEG;
+ }
s->refreshrefmask = get_bits(&s->gb, 8);
w = get_bits(&s->gb, 16) + 1;
h = get_bits(&s->gb, 16) + 1;
@@ -241,38 +614,42 @@ static int decode_frame_header(AVCodecContext *avctx,
} else {
s->refreshrefmask = get_bits(&s->gb, 8);
s->refidx[0] = get_bits(&s->gb, 3);
- s->signbias[0] = get_bits1(&s->gb);
+ s->signbias[0] = get_bits1(&s->gb) && !s->errorres;
s->refidx[1] = get_bits(&s->gb, 3);
- s->signbias[1] = get_bits1(&s->gb);
+ s->signbias[1] = get_bits1(&s->gb) && !s->errorres;
s->refidx[2] = get_bits(&s->gb, 3);
- s->signbias[2] = get_bits1(&s->gb);
- if (!s->refs[s->refidx[0]]->buf[0] ||
- !s->refs[s->refidx[1]]->buf[0] ||
- !s->refs[s->refidx[2]]->buf[0]) {
- av_log(avctx, AV_LOG_ERROR,
- "Not all references are available\n");
+ s->signbias[2] = get_bits1(&s->gb) && !s->errorres;
+ if (!s->refs[s->refidx[0]].f->data[0] ||
+ !s->refs[s->refidx[1]].f->data[0] ||
+ !s->refs[s->refidx[2]].f->data[0]) {
+ av_log(ctx, AV_LOG_ERROR, "Not all references are available\n");
return AVERROR_INVALIDDATA;
}
if (get_bits1(&s->gb)) {
- w = s->refs[s->refidx[0]]->width;
- h = s->refs[s->refidx[0]]->height;
+ w = s->refs[s->refidx[0]].f->width;
+ h = s->refs[s->refidx[0]].f->height;
} else if (get_bits1(&s->gb)) {
- w = s->refs[s->refidx[1]]->width;
- h = s->refs[s->refidx[1]]->height;
+ w = s->refs[s->refidx[1]].f->width;
+ h = s->refs[s->refidx[1]].f->height;
} else if (get_bits1(&s->gb)) {
- w = s->refs[s->refidx[2]]->width;
- h = s->refs[s->refidx[2]]->height;
+ w = s->refs[s->refidx[2]].f->width;
+ h = s->refs[s->refidx[2]].f->height;
} else {
w = get_bits(&s->gb, 16) + 1;
h = get_bits(&s->gb, 16) + 1;
}
+ // Note that in this code, "CUR_FRAME" is actually before we
+ // have formally allocated a frame, and thus actually represents
+ // the _last_ frame
+ s->use_last_frame_mvs &= s->frames[CUR_FRAME].tf.f->width == w &&
+ s->frames[CUR_FRAME].tf.f->height == h;
if (get_bits1(&s->gb)) // display size
skip_bits(&s->gb, 32);
s->highprecisionmvs = get_bits1(&s->gb);
- s->filtermode = get_bits1(&s->gb) ? FILTER_SWITCHABLE :
- get_bits(&s->gb, 2);
- s->allowcompinter = s->signbias[0] != s->signbias[1] ||
- s->signbias[0] != s->signbias[2];
+ s->filtermode = get_bits1(&s->gb) ? FILTER_SWITCHABLE :
+ get_bits(&s->gb, 2);
+ s->allowcompinter = (s->signbias[0] != s->signbias[1] ||
+ s->signbias[0] != s->signbias[2]);
if (s->allowcompinter) {
if (s->signbias[0] == s->signbias[1]) {
s->fixcompref = 2;
@@ -288,18 +665,52 @@ static int decode_frame_header(AVCodecContext *avctx,
s->varcompref[1] = 2;
}
}
+
+ for (i = 0; i < 3; i++) {
+ AVFrame *ref = s->refs[s->refidx[i]].f;
+ int refw = ref->width, refh = ref->height;
+
+ if (ref->format != fmt) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Ref pixfmt (%s) did not match current frame (%s)",
+ av_get_pix_fmt_name(ref->format),
+ av_get_pix_fmt_name(fmt));
+ return AVERROR_INVALIDDATA;
+ } else if (refw == w && refh == h) {
+ s->mvscale[i][0] = s->mvscale[i][1] = 0;
+ } else {
+ if (w * 2 < refw || h * 2 < refh || w > 16 * refw || h > 16 * refh) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid ref frame dimensions %dx%d for frame size %dx%d\n",
+ refw, refh, w, h);
+ return AVERROR_INVALIDDATA;
+ }
+ s->mvscale[i][0] = (refw << 14) / w;
+ s->mvscale[i][1] = (refh << 14) / h;
+ s->mvstep[i][0] = 16 * s->mvscale[i][0] >> 14;
+ s->mvstep[i][1] = 16 * s->mvscale[i][1] >> 14;
+ }
+ }
}
}
-
s->refreshctx = s->errorres ? 0 : get_bits1(&s->gb);
s->parallelmode = s->errorres ? 1 : get_bits1(&s->gb);
s->framectxid = c = get_bits(&s->gb, 2);
/* loopfilter header data */
+ if (s->keyframe || s->errorres || s->intraonly) {
+ // reset loopfilter defaults
+ s->lf_delta.ref[0] = 1;
+ s->lf_delta.ref[1] = 0;
+ s->lf_delta.ref[2] = -1;
+ s->lf_delta.ref[3] = -1;
+ s->lf_delta.mode[0] = 0;
+ s->lf_delta.mode[1] = 0;
+ }
s->filter.level = get_bits(&s->gb, 6);
- sharp = get_bits(&s->gb, 3);
- /* If sharpness changed, reinit lim/mblim LUTs. if it didn't change,
- * keep the old cache values since they are still valid. */
+ sharp = get_bits(&s->gb, 3);
+ // if sharpness changed, reinit lim/mblim LUTs. if it didn't change, keep
+ // the old cache values since they are still valid
if (s->filter.sharpness != sharp)
memset(s->filter.lim_lut, 0, sizeof(s->filter.lim_lut));
s->filter.sharpness = sharp;
@@ -307,42 +718,51 @@ static int decode_frame_header(AVCodecContext *avctx,
if (get_bits1(&s->gb)) {
for (i = 0; i < 4; i++)
if (get_bits1(&s->gb))
- s->lf_delta.ref[i] = get_bits_with_sign(&s->gb, 6);
+ s->lf_delta.ref[i] = get_sbits_inv(&s->gb, 6);
for (i = 0; i < 2; i++)
if (get_bits1(&s->gb))
- s->lf_delta.mode[i] = get_bits_with_sign(&s->gb, 6);
+ s->lf_delta.mode[i] = get_sbits_inv(&s->gb, 6);
}
- } else {
- memset(&s->lf_delta, 0, sizeof(s->lf_delta));
}
/* quantization header data */
s->yac_qi = get_bits(&s->gb, 8);
- s->ydc_qdelta = get_bits1(&s->gb) ? get_bits_with_sign(&s->gb, 4) : 0;
- s->uvdc_qdelta = get_bits1(&s->gb) ? get_bits_with_sign(&s->gb, 4) : 0;
- s->uvac_qdelta = get_bits1(&s->gb) ? get_bits_with_sign(&s->gb, 4) : 0;
+ s->ydc_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0;
+ s->uvdc_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0;
+ s->uvac_qdelta = get_bits1(&s->gb) ? get_sbits_inv(&s->gb, 4) : 0;
s->lossless = s->yac_qi == 0 && s->ydc_qdelta == 0 &&
s->uvdc_qdelta == 0 && s->uvac_qdelta == 0;
/* segmentation header info */
+ s->segmentation.ignore_refmap = 0;
if ((s->segmentation.enabled = get_bits1(&s->gb))) {
if ((s->segmentation.update_map = get_bits1(&s->gb))) {
for (i = 0; i < 7; i++)
s->prob.seg[i] = get_bits1(&s->gb) ?
get_bits(&s->gb, 8) : 255;
- if ((s->segmentation.temporal = get_bits1(&s->gb)))
+ if ((s->segmentation.temporal = get_bits1(&s->gb))) {
for (i = 0; i < 3; i++)
s->prob.segpred[i] = get_bits1(&s->gb) ?
get_bits(&s->gb, 8) : 255;
+ }
+ }
+ if ((!s->segmentation.update_map || s->segmentation.temporal) &&
+ (w != s->frames[CUR_FRAME].tf.f->width ||
+ h != s->frames[CUR_FRAME].tf.f->height)) {
+ av_log(ctx, AV_LOG_WARNING,
+ "Reference segmap (temp=%d,update=%d) enabled on size-change!\n",
+ s->segmentation.temporal, s->segmentation.update_map);
+ s->segmentation.ignore_refmap = 1;
+ //return AVERROR_INVALIDDATA;
}
if (get_bits1(&s->gb)) {
s->segmentation.absolute_vals = get_bits1(&s->gb);
for (i = 0; i < 8; i++) {
if ((s->segmentation.feat[i].q_enabled = get_bits1(&s->gb)))
- s->segmentation.feat[i].q_val = get_bits_with_sign(&s->gb, 8);
+ s->segmentation.feat[i].q_val = get_sbits_inv(&s->gb, 8);
if ((s->segmentation.feat[i].lf_enabled = get_bits1(&s->gb)))
- s->segmentation.feat[i].lf_val = get_bits_with_sign(&s->gb, 6);
+ s->segmentation.feat[i].lf_val = get_sbits_inv(&s->gb, 6);
if ((s->segmentation.feat[i].ref_enabled = get_bits1(&s->gb)))
s->segmentation.feat[i].ref_val = get_bits(&s->gb, 2);
s->segmentation.feat[i].skip_enabled = get_bits1(&s->gb);
@@ -365,45 +785,49 @@ static int decode_frame_header(AVCodecContext *avctx,
else
qyac = s->yac_qi + s->segmentation.feat[i].q_val;
} else {
- qyac = s->yac_qi;
+ qyac = s->yac_qi;
}
qydc = av_clip_uintp2(qyac + s->ydc_qdelta, 8);
quvdc = av_clip_uintp2(qyac + s->uvdc_qdelta, 8);
quvac = av_clip_uintp2(qyac + s->uvac_qdelta, 8);
qyac = av_clip_uintp2(qyac, 8);
- s->segmentation.feat[i].qmul[0][0] = ff_vp9_dc_qlookup[qydc];
- s->segmentation.feat[i].qmul[0][1] = ff_vp9_ac_qlookup[qyac];
- s->segmentation.feat[i].qmul[1][0] = ff_vp9_dc_qlookup[quvdc];
- s->segmentation.feat[i].qmul[1][1] = ff_vp9_ac_qlookup[quvac];
+ s->segmentation.feat[i].qmul[0][0] = vp9_dc_qlookup[s->bpp_index][qydc];
+ s->segmentation.feat[i].qmul[0][1] = vp9_ac_qlookup[s->bpp_index][qyac];
+ s->segmentation.feat[i].qmul[1][0] = vp9_dc_qlookup[s->bpp_index][quvdc];
+ s->segmentation.feat[i].qmul[1][1] = vp9_ac_qlookup[s->bpp_index][quvac];
sh = s->filter.level >= 32;
if (s->segmentation.feat[i].lf_enabled) {
if (s->segmentation.absolute_vals)
- lflvl = s->segmentation.feat[i].lf_val;
+ lflvl = av_clip_uintp2(s->segmentation.feat[i].lf_val, 6);
else
- lflvl = s->filter.level + s->segmentation.feat[i].lf_val;
+ lflvl = av_clip_uintp2(s->filter.level + s->segmentation.feat[i].lf_val, 6);
} else {
- lflvl = s->filter.level;
+ lflvl = s->filter.level;
}
- s->segmentation.feat[i].lflvl[0][0] =
- s->segmentation.feat[i].lflvl[0][1] =
- av_clip_uintp2(lflvl + (s->lf_delta.ref[0] << sh), 6);
- for (j = 1; j < 4; j++) {
- s->segmentation.feat[i].lflvl[j][0] =
- av_clip_uintp2(lflvl + ((s->lf_delta.ref[j] +
- s->lf_delta.mode[0]) << sh), 6);
- s->segmentation.feat[i].lflvl[j][1] =
- av_clip_uintp2(lflvl + ((s->lf_delta.ref[j] +
- s->lf_delta.mode[1]) << sh), 6);
+ if (s->lf_delta.enabled) {
+ s->segmentation.feat[i].lflvl[0][0] =
+ s->segmentation.feat[i].lflvl[0][1] =
+ av_clip_uintp2(lflvl + (s->lf_delta.ref[0] << sh), 6);
+ for (j = 1; j < 4; j++) {
+ s->segmentation.feat[i].lflvl[j][0] =
+ av_clip_uintp2(lflvl + ((s->lf_delta.ref[j] +
+ s->lf_delta.mode[0]) * (1 << sh)), 6);
+ s->segmentation.feat[i].lflvl[j][1] =
+ av_clip_uintp2(lflvl + ((s->lf_delta.ref[j] +
+ s->lf_delta.mode[1]) * (1 << sh)), 6);
+ }
+ } else {
+ memset(s->segmentation.feat[i].lflvl, lflvl,
+ sizeof(s->segmentation.feat[i].lflvl));
}
}
/* tiling info */
- if ((ret = update_size(avctx, w, h)) < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "Failed to initialize decoder for %dx%d\n", w, h);
- return ret;
+ if ((res = update_size(ctx, w, h, fmt)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to initialize decoder for %dx%d @ %d\n", w, h, fmt);
+ return res;
}
for (s->tiling.log2_tile_cols = 0;
(s->sb_cols >> s->tiling.log2_tile_cols) > 64;
@@ -417,56 +841,52 @@ static int decode_frame_header(AVCodecContext *avctx,
break;
}
s->tiling.log2_tile_rows = decode012(&s->gb);
- s->tiling.tile_rows = 1 << s->tiling.log2_tile_rows;
+ s->tiling.tile_rows = 1 << s->tiling.log2_tile_rows;
if (s->tiling.tile_cols != (1 << s->tiling.log2_tile_cols)) {
s->tiling.tile_cols = 1 << s->tiling.log2_tile_cols;
- s->c_b = av_fast_realloc(s->c_b, &s->c_b_size,
- sizeof(VP56RangeCoder) *
- s->tiling.tile_cols);
+ s->c_b = av_fast_realloc(s->c_b, &s->c_b_size,
+ sizeof(VP56RangeCoder) * s->tiling.tile_cols);
if (!s->c_b) {
- av_log(avctx, AV_LOG_ERROR,
- "Ran out of memory during range coder init\n");
+ av_log(ctx, AV_LOG_ERROR, "Ran out of memory during range coder init\n");
return AVERROR(ENOMEM);
}
}
if (s->keyframe || s->errorres || s->intraonly) {
- s->prob_ctx[0].p =
- s->prob_ctx[1].p =
- s->prob_ctx[2].p =
- s->prob_ctx[3].p = ff_vp9_default_probs;
- memcpy(s->prob_ctx[0].coef, ff_vp9_default_coef_probs,
- sizeof(ff_vp9_default_coef_probs));
- memcpy(s->prob_ctx[1].coef, ff_vp9_default_coef_probs,
- sizeof(ff_vp9_default_coef_probs));
- memcpy(s->prob_ctx[2].coef, ff_vp9_default_coef_probs,
- sizeof(ff_vp9_default_coef_probs));
- memcpy(s->prob_ctx[3].coef, ff_vp9_default_coef_probs,
- sizeof(ff_vp9_default_coef_probs));
+ s->prob_ctx[0].p = s->prob_ctx[1].p = s->prob_ctx[2].p =
+ s->prob_ctx[3].p = vp9_default_probs;
+ memcpy(s->prob_ctx[0].coef, vp9_default_coef_probs,
+ sizeof(vp9_default_coef_probs));
+ memcpy(s->prob_ctx[1].coef, vp9_default_coef_probs,
+ sizeof(vp9_default_coef_probs));
+ memcpy(s->prob_ctx[2].coef, vp9_default_coef_probs,
+ sizeof(vp9_default_coef_probs));
+ memcpy(s->prob_ctx[3].coef, vp9_default_coef_probs,
+ sizeof(vp9_default_coef_probs));
}
// next 16 bits is size of the rest of the header (arith-coded)
size2 = get_bits(&s->gb, 16);
data2 = align_get_bits(&s->gb);
if (size2 > size - (data2 - data)) {
- av_log(avctx, AV_LOG_ERROR, "Invalid compressed header size\n");
+ av_log(ctx, AV_LOG_ERROR, "Invalid compressed header size\n");
return AVERROR_INVALIDDATA;
}
ff_vp56_init_range_decoder(&s->c, data2, size2);
if (vp56_rac_get_prob_branchy(&s->c, 128)) { // marker bit
- av_log(avctx, AV_LOG_ERROR, "Marker bit was set\n");
+ av_log(ctx, AV_LOG_ERROR, "Marker bit was set\n");
return AVERROR_INVALIDDATA;
}
- if (s->keyframe || s->intraonly)
- memset(s->counts.coef, 0,
- sizeof(s->counts.coef) + sizeof(s->counts.eob));
- else
+ if (s->keyframe || s->intraonly) {
+ memset(s->counts.coef, 0, sizeof(s->counts.coef));
+ memset(s->counts.eob, 0, sizeof(s->counts.eob));
+ } else {
memset(&s->counts, 0, sizeof(s->counts));
-
- /* FIXME is it faster to not copy here, but do it down in the fw updates
- * as explicit copies if the fw update is missing (and skip the copy upon
- * fw update)? */
+ }
+ // FIXME is it faster to not copy here, but do it down in the fw updates
+ // as explicit copies if the fw update is missing (and skip the copy upon
+ // fw update)?
s->prob.p = s->prob_ctx[c].p;
// txfm updates
@@ -507,10 +927,11 @@ static int decode_frame_header(AVCodecContext *avctx,
if (m >= 3 && l == 0) // dc only has 3 pt
break;
for (n = 0; n < 3; n++) {
- if (vp56_rac_get_prob_branchy(&s->c, 252))
+ if (vp56_rac_get_prob_branchy(&s->c, 252)) {
p[n] = update_prob(&s->c, r[n]);
- else
+ } else {
p[n] = r[n];
+ }
}
p[3] = 0;
}
@@ -595,8 +1016,7 @@ static int decode_frame_header(AVCodecContext *avctx,
for (k = 0; k < 3; k++)
if (vp56_rac_get_prob_branchy(&s->c, 252))
s->prob.p.partition[3 - i][j][k] =
- update_prob(&s->c,
- s->prob.p.partition[3 - i][j][k]);
+ update_prob(&s->c, s->prob.p.partition[3 - i][j][k]);
// mv fields don't use the update_prob subexp model for some reason
for (i = 0; i < 3; i++)
@@ -605,8 +1025,7 @@ static int decode_frame_header(AVCodecContext *avctx,
for (i = 0; i < 2; i++) {
if (vp56_rac_get_prob_branchy(&s->c, 252))
- s->prob.p.mv_comp[i].sign =
- (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+ s->prob.p.mv_comp[i].sign = (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
for (j = 0; j < 10; j++)
if (vp56_rac_get_prob_branchy(&s->c, 252))
@@ -614,8 +1033,7 @@ static int decode_frame_header(AVCodecContext *avctx,
(vp8_rac_get_uint(&s->c, 7) << 1) | 1;
if (vp56_rac_get_prob_branchy(&s->c, 252))
- s->prob.p.mv_comp[i].class0 =
- (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
+ s->prob.p.mv_comp[i].class0 = (vp8_rac_get_uint(&s->c, 7) << 1) | 1;
for (j = 0; j < 10; j++)
if (vp56_rac_get_prob_branchy(&s->c, 252))
@@ -652,640 +1070,3292 @@ static int decode_frame_header(AVCodecContext *avctx,
return (data2 - data) + size2;
}
-static int decode_subblock(AVCodecContext *avctx, int row, int col,
- VP9Filter *lflvl,
- ptrdiff_t yoff, ptrdiff_t uvoff, enum BlockLevel bl)
+static av_always_inline void clamp_mv(VP56mv *dst, const VP56mv *src,
+ VP9Context *s)
+{
+ dst->x = av_clip(src->x, s->min_mv.x, s->max_mv.x);
+ dst->y = av_clip(src->y, s->min_mv.y, s->max_mv.y);
+}
+
+static void find_ref_mvs(VP9Context *s,
+ VP56mv *pmv, int ref, int z, int idx, int sb)
+{
+ static const int8_t mv_ref_blk_off[N_BS_SIZES][8][2] = {
+ [BS_64x64] = {{ 3, -1 }, { -1, 3 }, { 4, -1 }, { -1, 4 },
+ { -1, -1 }, { 0, -1 }, { -1, 0 }, { 6, -1 }},
+ [BS_64x32] = {{ 0, -1 }, { -1, 0 }, { 4, -1 }, { -1, 2 },
+ { -1, -1 }, { 0, -3 }, { -3, 0 }, { 2, -1 }},
+ [BS_32x64] = {{ -1, 0 }, { 0, -1 }, { -1, 4 }, { 2, -1 },
+ { -1, -1 }, { -3, 0 }, { 0, -3 }, { -1, 2 }},
+ [BS_32x32] = {{ 1, -1 }, { -1, 1 }, { 2, -1 }, { -1, 2 },
+ { -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 }},
+ [BS_32x16] = {{ 0, -1 }, { -1, 0 }, { 2, -1 }, { -1, -1 },
+ { -1, 1 }, { 0, -3 }, { -3, 0 }, { -3, -3 }},
+ [BS_16x32] = {{ -1, 0 }, { 0, -1 }, { -1, 2 }, { -1, -1 },
+ { 1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 }},
+ [BS_16x16] = {{ 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, 1 },
+ { -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 }},
+ [BS_16x8] = {{ 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, -1 },
+ { 0, -2 }, { -2, 0 }, { -2, -1 }, { -1, -2 }},
+ [BS_8x16] = {{ -1, 0 }, { 0, -1 }, { -1, 1 }, { -1, -1 },
+ { -2, 0 }, { 0, -2 }, { -1, -2 }, { -2, -1 }},
+ [BS_8x8] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
+ { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }},
+ [BS_8x4] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
+ { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }},
+ [BS_4x8] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
+ { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }},
+ [BS_4x4] = {{ 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
+ { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 }},
+ };
+ VP9Block *b = s->b;
+ int row = s->row, col = s->col, row7 = s->row7;
+ const int8_t (*p)[2] = mv_ref_blk_off[b->bs];
+#define INVALID_MV 0x80008000U
+ uint32_t mem = INVALID_MV, mem_sub8x8 = INVALID_MV;
+ int i;
+
+#define RETURN_DIRECT_MV(mv) \
+ do { \
+ uint32_t m = AV_RN32A(&mv); \
+ if (!idx) { \
+ AV_WN32A(pmv, m); \
+ return; \
+ } else if (mem == INVALID_MV) { \
+ mem = m; \
+ } else if (m != mem) { \
+ AV_WN32A(pmv, m); \
+ return; \
+ } \
+ } while (0)
+
+ if (sb >= 0) {
+ if (sb == 2 || sb == 1) {
+ RETURN_DIRECT_MV(b->mv[0][z]);
+ } else if (sb == 3) {
+ RETURN_DIRECT_MV(b->mv[2][z]);
+ RETURN_DIRECT_MV(b->mv[1][z]);
+ RETURN_DIRECT_MV(b->mv[0][z]);
+ }
+
+#define RETURN_MV(mv) \
+ do { \
+ if (sb > 0) { \
+ VP56mv tmp; \
+ uint32_t m; \
+ av_assert2(idx == 1); \
+ av_assert2(mem != INVALID_MV); \
+ if (mem_sub8x8 == INVALID_MV) { \
+ clamp_mv(&tmp, &mv, s); \
+ m = AV_RN32A(&tmp); \
+ if (m != mem) { \
+ AV_WN32A(pmv, m); \
+ return; \
+ } \
+ mem_sub8x8 = AV_RN32A(&mv); \
+ } else if (mem_sub8x8 != AV_RN32A(&mv)) { \
+ clamp_mv(&tmp, &mv, s); \
+ m = AV_RN32A(&tmp); \
+ if (m != mem) { \
+ AV_WN32A(pmv, m); \
+ } else { \
+ /* BUG I'm pretty sure this isn't the intention */ \
+ AV_WN32A(pmv, 0); \
+ } \
+ return; \
+ } \
+ } else { \
+ uint32_t m = AV_RN32A(&mv); \
+ if (!idx) { \
+ clamp_mv(pmv, &mv, s); \
+ return; \
+ } else if (mem == INVALID_MV) { \
+ mem = m; \
+ } else if (m != mem) { \
+ clamp_mv(pmv, &mv, s); \
+ return; \
+ } \
+ } \
+ } while (0)
+
+ if (row > 0) {
+ struct VP9mvrefPair *mv = &s->frames[CUR_FRAME].mv[(row - 1) * s->sb_cols * 8 + col];
+ if (mv->ref[0] == ref) {
+ RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][0]);
+ } else if (mv->ref[1] == ref) {
+ RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][1]);
+ }
+ }
+ if (col > s->tiling.tile_col_start) {
+ struct VP9mvrefPair *mv = &s->frames[CUR_FRAME].mv[row * s->sb_cols * 8 + col - 1];
+ if (mv->ref[0] == ref) {
+ RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][0]);
+ } else if (mv->ref[1] == ref) {
+ RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][1]);
+ }
+ }
+ i = 2;
+ } else {
+ i = 0;
+ }
+
+ // previously coded MVs in this neighbourhood, using same reference frame
+ for (; i < 8; i++) {
+ int c = p[i][0] + col, r = p[i][1] + row;
+
+ if (c >= s->tiling.tile_col_start && c < s->cols && r >= 0 && r < s->rows) {
+ struct VP9mvrefPair *mv = &s->frames[CUR_FRAME].mv[r * s->sb_cols * 8 + c];
+
+ if (mv->ref[0] == ref) {
+ RETURN_MV(mv->mv[0]);
+ } else if (mv->ref[1] == ref) {
+ RETURN_MV(mv->mv[1]);
+ }
+ }
+ }
+
+ // MV at this position in previous frame, using same reference frame
+ if (s->use_last_frame_mvs) {
+ struct VP9mvrefPair *mv = &s->frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col];
+
+ if (!s->frames[REF_FRAME_MVPAIR].uses_2pass)
+ ff_thread_await_progress(&s->frames[REF_FRAME_MVPAIR].tf, row >> 3, 0);
+ if (mv->ref[0] == ref) {
+ RETURN_MV(mv->mv[0]);
+ } else if (mv->ref[1] == ref) {
+ RETURN_MV(mv->mv[1]);
+ }
+ }
+
+#define RETURN_SCALE_MV(mv, scale) \
+ do { \
+ if (scale) { \
+ VP56mv mv_temp = { -mv.x, -mv.y }; \
+ RETURN_MV(mv_temp); \
+ } else { \
+ RETURN_MV(mv); \
+ } \
+ } while (0)
+
+ // previously coded MVs in this neighbourhood, using different reference frame
+ for (i = 0; i < 8; i++) {
+ int c = p[i][0] + col, r = p[i][1] + row;
+
+ if (c >= s->tiling.tile_col_start && c < s->cols && r >= 0 && r < s->rows) {
+ struct VP9mvrefPair *mv = &s->frames[CUR_FRAME].mv[r * s->sb_cols * 8 + c];
+
+ if (mv->ref[0] != ref && mv->ref[0] >= 0) {
+ RETURN_SCALE_MV(mv->mv[0], s->signbias[mv->ref[0]] != s->signbias[ref]);
+ }
+ if (mv->ref[1] != ref && mv->ref[1] >= 0 &&
+ // BUG - libvpx has this condition regardless of whether
+ // we used the first ref MV and pre-scaling
+ AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) {
+ RETURN_SCALE_MV(mv->mv[1], s->signbias[mv->ref[1]] != s->signbias[ref]);
+ }
+ }
+ }
+
+ // MV at this position in previous frame, using different reference frame
+ if (s->use_last_frame_mvs) {
+ struct VP9mvrefPair *mv = &s->frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col];
+
+ // no need to await_progress, because we already did that above
+ if (mv->ref[0] != ref && mv->ref[0] >= 0) {
+ RETURN_SCALE_MV(mv->mv[0], s->signbias[mv->ref[0]] != s->signbias[ref]);
+ }
+ if (mv->ref[1] != ref && mv->ref[1] >= 0 &&
+ // BUG - libvpx has this condition regardless of whether
+ // we used the first ref MV and pre-scaling
+ AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) {
+ RETURN_SCALE_MV(mv->mv[1], s->signbias[mv->ref[1]] != s->signbias[ref]);
+ }
+ }
+
+ AV_ZERO32(pmv);
+#undef INVALID_MV
+#undef RETURN_MV
+#undef RETURN_SCALE_MV
+}
+
+static av_always_inline int read_mv_component(VP9Context *s, int idx, int hp)
+{
+ int bit, sign = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].sign);
+ int n, c = vp8_rac_get_tree(&s->c, vp9_mv_class_tree,
+ s->prob.p.mv_comp[idx].classes);
+
+ s->counts.mv_comp[idx].sign[sign]++;
+ s->counts.mv_comp[idx].classes[c]++;
+ if (c) {
+ int m;
+
+ for (n = 0, m = 0; m < c; m++) {
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].bits[m]);
+ n |= bit << m;
+ s->counts.mv_comp[idx].bits[m][bit]++;
+ }
+ n <<= 3;
+ bit = vp8_rac_get_tree(&s->c, vp9_mv_fp_tree, s->prob.p.mv_comp[idx].fp);
+ n |= bit << 1;
+ s->counts.mv_comp[idx].fp[bit]++;
+ if (hp) {
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].hp);
+ s->counts.mv_comp[idx].hp[bit]++;
+ n |= bit;
+ } else {
+ n |= 1;
+ // bug in libvpx - we count for bw entropy purposes even if the
+ // bit wasn't coded
+ s->counts.mv_comp[idx].hp[1]++;
+ }
+ n += 8 << c;
+ } else {
+ n = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0);
+ s->counts.mv_comp[idx].class0[n]++;
+ bit = vp8_rac_get_tree(&s->c, vp9_mv_fp_tree,
+ s->prob.p.mv_comp[idx].class0_fp[n]);
+ s->counts.mv_comp[idx].class0_fp[n][bit]++;
+ n = (n << 3) | (bit << 1);
+ if (hp) {
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0_hp);
+ s->counts.mv_comp[idx].class0_hp[bit]++;
+ n |= bit;
+ } else {
+ n |= 1;
+ // bug in libvpx - we count for bw entropy purposes even if the
+ // bit wasn't coded
+ s->counts.mv_comp[idx].class0_hp[1]++;
+ }
+ }
+
+ return sign ? -(n + 1) : (n + 1);
+}
+
+static void fill_mv(VP9Context *s,
+ VP56mv *mv, int mode, int sb)
+{
+ VP9Block *b = s->b;
+
+ if (mode == ZEROMV) {
+ AV_ZERO64(mv);
+ } else {
+ int hp;
+
+ // FIXME cache this value and reuse for other subblocks
+ find_ref_mvs(s, &mv[0], b->ref[0], 0, mode == NEARMV,
+ mode == NEWMV ? -1 : sb);
+ // FIXME maybe move this code into find_ref_mvs()
+ if ((mode == NEWMV || sb == -1) &&
+ !(hp = s->highprecisionmvs && abs(mv[0].x) < 64 && abs(mv[0].y) < 64)) {
+ if (mv[0].y & 1) {
+ if (mv[0].y < 0)
+ mv[0].y++;
+ else
+ mv[0].y--;
+ }
+ if (mv[0].x & 1) {
+ if (mv[0].x < 0)
+ mv[0].x++;
+ else
+ mv[0].x--;
+ }
+ }
+ if (mode == NEWMV) {
+ enum MVJoint j = vp8_rac_get_tree(&s->c, vp9_mv_joint_tree,
+ s->prob.p.mv_joint);
+
+ s->counts.mv_joint[j]++;
+ if (j >= MV_JOINT_V)
+ mv[0].y += read_mv_component(s, 0, hp);
+ if (j & 1)
+ mv[0].x += read_mv_component(s, 1, hp);
+ }
+
+ if (b->comp) {
+ // FIXME cache this value and reuse for other subblocks
+ find_ref_mvs(s, &mv[1], b->ref[1], 1, mode == NEARMV,
+ mode == NEWMV ? -1 : sb);
+ if ((mode == NEWMV || sb == -1) &&
+ !(hp = s->highprecisionmvs && abs(mv[1].x) < 64 && abs(mv[1].y) < 64)) {
+ if (mv[1].y & 1) {
+ if (mv[1].y < 0)
+ mv[1].y++;
+ else
+ mv[1].y--;
+ }
+ if (mv[1].x & 1) {
+ if (mv[1].x < 0)
+ mv[1].x++;
+ else
+ mv[1].x--;
+ }
+ }
+ if (mode == NEWMV) {
+ enum MVJoint j = vp8_rac_get_tree(&s->c, vp9_mv_joint_tree,
+ s->prob.p.mv_joint);
+
+ s->counts.mv_joint[j]++;
+ if (j >= MV_JOINT_V)
+ mv[1].y += read_mv_component(s, 0, hp);
+ if (j & 1)
+ mv[1].x += read_mv_component(s, 1, hp);
+ }
+ }
+ }
+}
+
+static av_always_inline void setctx_2d(uint8_t *ptr, int w, int h,
+ ptrdiff_t stride, int v)
+{
+ switch (w) {
+ case 1:
+ do {
+ *ptr = v;
+ ptr += stride;
+ } while (--h);
+ break;
+ case 2: {
+ int v16 = v * 0x0101;
+ do {
+ AV_WN16A(ptr, v16);
+ ptr += stride;
+ } while (--h);
+ break;
+ }
+ case 4: {
+ uint32_t v32 = v * 0x01010101;
+ do {
+ AV_WN32A(ptr, v32);
+ ptr += stride;
+ } while (--h);
+ break;
+ }
+ case 8: {
+#if HAVE_FAST_64BIT
+ uint64_t v64 = v * 0x0101010101010101ULL;
+ do {
+ AV_WN64A(ptr, v64);
+ ptr += stride;
+ } while (--h);
+#else
+ uint32_t v32 = v * 0x01010101;
+ do {
+ AV_WN32A(ptr, v32);
+ AV_WN32A(ptr + 4, v32);
+ ptr += stride;
+ } while (--h);
+#endif
+ break;
+ }
+ }
+}
+
+static void decode_mode(AVCodecContext *ctx)
+{
+ static const uint8_t left_ctx[N_BS_SIZES] = {
+ 0x0, 0x8, 0x0, 0x8, 0xc, 0x8, 0xc, 0xe, 0xc, 0xe, 0xf, 0xe, 0xf
+ };
+ static const uint8_t above_ctx[N_BS_SIZES] = {
+ 0x0, 0x0, 0x8, 0x8, 0x8, 0xc, 0xc, 0xc, 0xe, 0xe, 0xe, 0xf, 0xf
+ };
+ static const uint8_t max_tx_for_bl_bp[N_BS_SIZES] = {
+ TX_32X32, TX_32X32, TX_32X32, TX_32X32, TX_16X16, TX_16X16,
+ TX_16X16, TX_8X8, TX_8X8, TX_8X8, TX_4X4, TX_4X4, TX_4X4
+ };
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ int row = s->row, col = s->col, row7 = s->row7;
+ enum TxfmMode max_tx = max_tx_for_bl_bp[b->bs];
+ int bw4 = bwh_tab[1][b->bs][0], w4 = FFMIN(s->cols - col, bw4);
+ int bh4 = bwh_tab[1][b->bs][1], h4 = FFMIN(s->rows - row, bh4), y;
+ int have_a = row > 0, have_l = col > s->tiling.tile_col_start;
+ int vref, filter_id;
+
+ if (!s->segmentation.enabled) {
+ b->seg_id = 0;
+ } else if (s->keyframe || s->intraonly) {
+ b->seg_id = vp8_rac_get_tree(&s->c, vp9_segmentation_tree, s->prob.seg);
+ } else if (!s->segmentation.update_map ||
+ (s->segmentation.temporal &&
+ vp56_rac_get_prob_branchy(&s->c,
+ s->prob.segpred[s->above_segpred_ctx[col] +
+ s->left_segpred_ctx[row7]]))) {
+ if (!s->errorres && !s->segmentation.ignore_refmap) {
+ int pred = 8, x;
+ uint8_t *refsegmap = s->frames[REF_FRAME_SEGMAP].segmentation_map;
+
+ if (!s->frames[REF_FRAME_SEGMAP].uses_2pass)
+ ff_thread_await_progress(&s->frames[REF_FRAME_SEGMAP].tf, row >> 3, 0);
+ for (y = 0; y < h4; y++) {
+ int idx_base = (y + row) * 8 * s->sb_cols + col;
+ for (x = 0; x < w4; x++)
+ pred = FFMIN(pred, refsegmap[idx_base + x]);
+ }
+ av_assert1(pred < 8);
+ b->seg_id = pred;
+ } else {
+ b->seg_id = 0;
+ }
+
+ memset(&s->above_segpred_ctx[col], 1, w4);
+ memset(&s->left_segpred_ctx[row7], 1, h4);
+ } else {
+ b->seg_id = vp8_rac_get_tree(&s->c, vp9_segmentation_tree,
+ s->prob.seg);
+
+ memset(&s->above_segpred_ctx[col], 0, w4);
+ memset(&s->left_segpred_ctx[row7], 0, h4);
+ }
+ if (s->segmentation.enabled &&
+ (s->segmentation.update_map || s->keyframe || s->intraonly)) {
+ setctx_2d(&s->frames[CUR_FRAME].segmentation_map[row * 8 * s->sb_cols + col],
+ bw4, bh4, 8 * s->sb_cols, b->seg_id);
+ }
+
+ b->skip = s->segmentation.enabled &&
+ s->segmentation.feat[b->seg_id].skip_enabled;
+ if (!b->skip) {
+ int c = s->left_skip_ctx[row7] + s->above_skip_ctx[col];
+ b->skip = vp56_rac_get_prob(&s->c, s->prob.p.skip[c]);
+ s->counts.skip[c][b->skip]++;
+ }
+
+ if (s->keyframe || s->intraonly) {
+ b->intra = 1;
+ } else if (s->segmentation.feat[b->seg_id].ref_enabled) {
+ b->intra = !s->segmentation.feat[b->seg_id].ref_val;
+ } else {
+ int c, bit;
+
+ if (have_a && have_l) {
+ c = s->above_intra_ctx[col] + s->left_intra_ctx[row7];
+ c += (c == 2);
+ } else {
+ c = have_a ? 2 * s->above_intra_ctx[col] :
+ have_l ? 2 * s->left_intra_ctx[row7] : 0;
+ }
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.intra[c]);
+ s->counts.intra[c][bit]++;
+ b->intra = !bit;
+ }
+
+ if ((b->intra || !b->skip) && s->txfmmode == TX_SWITCHABLE) {
+ int c;
+ if (have_a) {
+ if (have_l) {
+ c = (s->above_skip_ctx[col] ? max_tx :
+ s->above_txfm_ctx[col]) +
+ (s->left_skip_ctx[row7] ? max_tx :
+ s->left_txfm_ctx[row7]) > max_tx;
+ } else {
+ c = s->above_skip_ctx[col] ? 1 :
+ (s->above_txfm_ctx[col] * 2 > max_tx);
+ }
+ } else if (have_l) {
+ c = s->left_skip_ctx[row7] ? 1 :
+ (s->left_txfm_ctx[row7] * 2 > max_tx);
+ } else {
+ c = 1;
+ }
+ switch (max_tx) {
+ case TX_32X32:
+ b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][0]);
+ if (b->tx) {
+ b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][1]);
+ if (b->tx == 2)
+ b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][2]);
+ }
+ s->counts.tx32p[c][b->tx]++;
+ break;
+ case TX_16X16:
+ b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx16p[c][0]);
+ if (b->tx)
+ b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx16p[c][1]);
+ s->counts.tx16p[c][b->tx]++;
+ break;
+ case TX_8X8:
+ b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx8p[c]);
+ s->counts.tx8p[c][b->tx]++;
+ break;
+ case TX_4X4:
+ b->tx = TX_4X4;
+ break;
+ }
+ } else {
+ b->tx = FFMIN(max_tx, s->txfmmode);
+ }
+
+ if (s->keyframe || s->intraonly) {
+ uint8_t *a = &s->above_mode_ctx[col * 2];
+ uint8_t *l = &s->left_mode_ctx[(row7) << 1];
+
+ b->comp = 0;
+ if (b->bs > BS_8x8) {
+ // FIXME the memory storage intermediates here aren't really
+ // necessary, they're just there to make the code slightly
+ // simpler for now
+ b->mode[0] = a[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ vp9_default_kf_ymode_probs[a[0]][l[0]]);
+ if (b->bs != BS_8x4) {
+ b->mode[1] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ vp9_default_kf_ymode_probs[a[1]][b->mode[0]]);
+ l[0] = a[1] = b->mode[1];
+ } else {
+ l[0] = a[1] = b->mode[1] = b->mode[0];
+ }
+ if (b->bs != BS_4x8) {
+ b->mode[2] = a[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ vp9_default_kf_ymode_probs[a[0]][l[1]]);
+ if (b->bs != BS_8x4) {
+ b->mode[3] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ vp9_default_kf_ymode_probs[a[1]][b->mode[2]]);
+ l[1] = a[1] = b->mode[3];
+ } else {
+ l[1] = a[1] = b->mode[3] = b->mode[2];
+ }
+ } else {
+ b->mode[2] = b->mode[0];
+ l[1] = a[1] = b->mode[3] = b->mode[1];
+ }
+ } else {
+ b->mode[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ vp9_default_kf_ymode_probs[*a][*l]);
+ b->mode[3] = b->mode[2] = b->mode[1] = b->mode[0];
+ // FIXME this can probably be optimized
+ memset(a, b->mode[0], bwh_tab[0][b->bs][0]);
+ memset(l, b->mode[0], bwh_tab[0][b->bs][1]);
+ }
+ b->uvmode = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ vp9_default_kf_uvmode_probs[b->mode[3]]);
+ } else if (b->intra) {
+ b->comp = 0;
+ if (b->bs > BS_8x8) {
+ b->mode[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ s->prob.p.y_mode[0]);
+ s->counts.y_mode[0][b->mode[0]]++;
+ if (b->bs != BS_8x4) {
+ b->mode[1] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ s->prob.p.y_mode[0]);
+ s->counts.y_mode[0][b->mode[1]]++;
+ } else {
+ b->mode[1] = b->mode[0];
+ }
+ if (b->bs != BS_4x8) {
+ b->mode[2] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ s->prob.p.y_mode[0]);
+ s->counts.y_mode[0][b->mode[2]]++;
+ if (b->bs != BS_8x4) {
+ b->mode[3] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ s->prob.p.y_mode[0]);
+ s->counts.y_mode[0][b->mode[3]]++;
+ } else {
+ b->mode[3] = b->mode[2];
+ }
+ } else {
+ b->mode[2] = b->mode[0];
+ b->mode[3] = b->mode[1];
+ }
+ } else {
+ static const uint8_t size_group[10] = {
+ 3, 3, 3, 3, 2, 2, 2, 1, 1, 1
+ };
+ int sz = size_group[b->bs];
+
+ b->mode[0] = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ s->prob.p.y_mode[sz]);
+ b->mode[1] = b->mode[2] = b->mode[3] = b->mode[0];
+ s->counts.y_mode[sz][b->mode[3]]++;
+ }
+ b->uvmode = vp8_rac_get_tree(&s->c, vp9_intramode_tree,
+ s->prob.p.uv_mode[b->mode[3]]);
+ s->counts.uv_mode[b->mode[3]][b->uvmode]++;
+ } else {
+ static const uint8_t inter_mode_ctx_lut[14][14] = {
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 3 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 3 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 0, 3 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 4 },
+ };
+
+ if (s->segmentation.feat[b->seg_id].ref_enabled) {
+ av_assert2(s->segmentation.feat[b->seg_id].ref_val != 0);
+ b->comp = 0;
+ b->ref[0] = s->segmentation.feat[b->seg_id].ref_val - 1;
+ } else {
+ // read comp_pred flag
+ if (s->comppredmode != PRED_SWITCHABLE) {
+ b->comp = s->comppredmode == PRED_COMPREF;
+ } else {
+ int c;
+
+ // FIXME add intra as ref=0xff (or -1) to make these easier?
+ if (have_a) {
+ if (have_l) {
+ if (s->above_comp_ctx[col] && s->left_comp_ctx[row7]) {
+ c = 4;
+ } else if (s->above_comp_ctx[col]) {
+ c = 2 + (s->left_intra_ctx[row7] ||
+ s->left_ref_ctx[row7] == s->fixcompref);
+ } else if (s->left_comp_ctx[row7]) {
+ c = 2 + (s->above_intra_ctx[col] ||
+ s->above_ref_ctx[col] == s->fixcompref);
+ } else {
+ c = (!s->above_intra_ctx[col] &&
+ s->above_ref_ctx[col] == s->fixcompref) ^
+ (!s->left_intra_ctx[row7] &&
+ s->left_ref_ctx[row & 7] == s->fixcompref);
+ }
+ } else {
+ c = s->above_comp_ctx[col] ? 3 :
+ (!s->above_intra_ctx[col] && s->above_ref_ctx[col] == s->fixcompref);
+ }
+ } else if (have_l) {
+ c = s->left_comp_ctx[row7] ? 3 :
+ (!s->left_intra_ctx[row7] && s->left_ref_ctx[row7] == s->fixcompref);
+ } else {
+ c = 1;
+ }
+ b->comp = vp56_rac_get_prob(&s->c, s->prob.p.comp[c]);
+ s->counts.comp[c][b->comp]++;
+ }
+
+ // read actual references
+ // FIXME probably cache a few variables here to prevent repetitive
+ // memory accesses below
+ if (b->comp) /* two references */ {
+ int fix_idx = s->signbias[s->fixcompref], var_idx = !fix_idx, c, bit;
+
+ b->ref[fix_idx] = s->fixcompref;
+ // FIXME can this codeblob be replaced by some sort of LUT?
+ if (have_a) {
+ if (have_l) {
+ if (s->above_intra_ctx[col]) {
+ if (s->left_intra_ctx[row7]) {
+ c = 2;
+ } else {
+ c = 1 + 2 * (s->left_ref_ctx[row7] != s->varcompref[1]);
+ }
+ } else if (s->left_intra_ctx[row7]) {
+ c = 1 + 2 * (s->above_ref_ctx[col] != s->varcompref[1]);
+ } else {
+ int refl = s->left_ref_ctx[row7], refa = s->above_ref_ctx[col];
+
+ if (refl == refa && refa == s->varcompref[1]) {
+ c = 0;
+ } else if (!s->left_comp_ctx[row7] && !s->above_comp_ctx[col]) {
+ if ((refa == s->fixcompref && refl == s->varcompref[0]) ||
+ (refl == s->fixcompref && refa == s->varcompref[0])) {
+ c = 4;
+ } else {
+ c = (refa == refl) ? 3 : 1;
+ }
+ } else if (!s->left_comp_ctx[row7]) {
+ if (refa == s->varcompref[1] && refl != s->varcompref[1]) {
+ c = 1;
+ } else {
+ c = (refl == s->varcompref[1] &&
+ refa != s->varcompref[1]) ? 2 : 4;
+ }
+ } else if (!s->above_comp_ctx[col]) {
+ if (refl == s->varcompref[1] && refa != s->varcompref[1]) {
+ c = 1;
+ } else {
+ c = (refa == s->varcompref[1] &&
+ refl != s->varcompref[1]) ? 2 : 4;
+ }
+ } else {
+ c = (refl == refa) ? 4 : 2;
+ }
+ }
+ } else {
+ if (s->above_intra_ctx[col]) {
+ c = 2;
+ } else if (s->above_comp_ctx[col]) {
+ c = 4 * (s->above_ref_ctx[col] != s->varcompref[1]);
+ } else {
+ c = 3 * (s->above_ref_ctx[col] != s->varcompref[1]);
+ }
+ }
+ } else if (have_l) {
+ if (s->left_intra_ctx[row7]) {
+ c = 2;
+ } else if (s->left_comp_ctx[row7]) {
+ c = 4 * (s->left_ref_ctx[row7] != s->varcompref[1]);
+ } else {
+ c = 3 * (s->left_ref_ctx[row7] != s->varcompref[1]);
+ }
+ } else {
+ c = 2;
+ }
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.comp_ref[c]);
+ b->ref[var_idx] = s->varcompref[bit];
+ s->counts.comp_ref[c][bit]++;
+ } else /* single reference */ {
+ int bit, c;
+
+ if (have_a && !s->above_intra_ctx[col]) {
+ if (have_l && !s->left_intra_ctx[row7]) {
+ if (s->left_comp_ctx[row7]) {
+ if (s->above_comp_ctx[col]) {
+ c = 1 + (!s->fixcompref || !s->left_ref_ctx[row7] ||
+ !s->above_ref_ctx[col]);
+ } else {
+ c = (3 * !s->above_ref_ctx[col]) +
+ (!s->fixcompref || !s->left_ref_ctx[row7]);
+ }
+ } else if (s->above_comp_ctx[col]) {
+ c = (3 * !s->left_ref_ctx[row7]) +
+ (!s->fixcompref || !s->above_ref_ctx[col]);
+ } else {
+ c = 2 * !s->left_ref_ctx[row7] + 2 * !s->above_ref_ctx[col];
+ }
+ } else if (s->above_intra_ctx[col]) {
+ c = 2;
+ } else if (s->above_comp_ctx[col]) {
+ c = 1 + (!s->fixcompref || !s->above_ref_ctx[col]);
+ } else {
+ c = 4 * (!s->above_ref_ctx[col]);
+ }
+ } else if (have_l && !s->left_intra_ctx[row7]) {
+ if (s->left_intra_ctx[row7]) {
+ c = 2;
+ } else if (s->left_comp_ctx[row7]) {
+ c = 1 + (!s->fixcompref || !s->left_ref_ctx[row7]);
+ } else {
+ c = 4 * (!s->left_ref_ctx[row7]);
+ }
+ } else {
+ c = 2;
+ }
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.single_ref[c][0]);
+ s->counts.single_ref[c][0][bit]++;
+ if (!bit) {
+ b->ref[0] = 0;
+ } else {
+ // FIXME can this codeblob be replaced by some sort of LUT?
+ if (have_a) {
+ if (have_l) {
+ if (s->left_intra_ctx[row7]) {
+ if (s->above_intra_ctx[col]) {
+ c = 2;
+ } else if (s->above_comp_ctx[col]) {
+ c = 1 + 2 * (s->fixcompref == 1 ||
+ s->above_ref_ctx[col] == 1);
+ } else if (!s->above_ref_ctx[col]) {
+ c = 3;
+ } else {
+ c = 4 * (s->above_ref_ctx[col] == 1);
+ }
+ } else if (s->above_intra_ctx[col]) {
+ if (s->left_intra_ctx[row7]) {
+ c = 2;
+ } else if (s->left_comp_ctx[row7]) {
+ c = 1 + 2 * (s->fixcompref == 1 ||
+ s->left_ref_ctx[row7] == 1);
+ } else if (!s->left_ref_ctx[row7]) {
+ c = 3;
+ } else {
+ c = 4 * (s->left_ref_ctx[row7] == 1);
+ }
+ } else if (s->above_comp_ctx[col]) {
+ if (s->left_comp_ctx[row7]) {
+ if (s->left_ref_ctx[row7] == s->above_ref_ctx[col]) {
+ c = 3 * (s->fixcompref == 1 ||
+ s->left_ref_ctx[row7] == 1);
+ } else {
+ c = 2;
+ }
+ } else if (!s->left_ref_ctx[row7]) {
+ c = 1 + 2 * (s->fixcompref == 1 ||
+ s->above_ref_ctx[col] == 1);
+ } else {
+ c = 3 * (s->left_ref_ctx[row7] == 1) +
+ (s->fixcompref == 1 || s->above_ref_ctx[col] == 1);
+ }
+ } else if (s->left_comp_ctx[row7]) {
+ if (!s->above_ref_ctx[col]) {
+ c = 1 + 2 * (s->fixcompref == 1 ||
+ s->left_ref_ctx[row7] == 1);
+ } else {
+ c = 3 * (s->above_ref_ctx[col] == 1) +
+ (s->fixcompref == 1 || s->left_ref_ctx[row7] == 1);
+ }
+ } else if (!s->above_ref_ctx[col]) {
+ if (!s->left_ref_ctx[row7]) {
+ c = 3;
+ } else {
+ c = 4 * (s->left_ref_ctx[row7] == 1);
+ }
+ } else if (!s->left_ref_ctx[row7]) {
+ c = 4 * (s->above_ref_ctx[col] == 1);
+ } else {
+ c = 2 * (s->left_ref_ctx[row7] == 1) +
+ 2 * (s->above_ref_ctx[col] == 1);
+ }
+ } else {
+ if (s->above_intra_ctx[col] ||
+ (!s->above_comp_ctx[col] && !s->above_ref_ctx[col])) {
+ c = 2;
+ } else if (s->above_comp_ctx[col]) {
+ c = 3 * (s->fixcompref == 1 || s->above_ref_ctx[col] == 1);
+ } else {
+ c = 4 * (s->above_ref_ctx[col] == 1);
+ }
+ }
+ } else if (have_l) {
+ if (s->left_intra_ctx[row7] ||
+ (!s->left_comp_ctx[row7] && !s->left_ref_ctx[row7])) {
+ c = 2;
+ } else if (s->left_comp_ctx[row7]) {
+ c = 3 * (s->fixcompref == 1 || s->left_ref_ctx[row7] == 1);
+ } else {
+ c = 4 * (s->left_ref_ctx[row7] == 1);
+ }
+ } else {
+ c = 2;
+ }
+ bit = vp56_rac_get_prob(&s->c, s->prob.p.single_ref[c][1]);
+ s->counts.single_ref[c][1][bit]++;
+ b->ref[0] = 1 + bit;
+ }
+ }
+ }
+
+ if (b->bs <= BS_8x8) {
+ if (s->segmentation.feat[b->seg_id].skip_enabled) {
+ b->mode[0] = b->mode[1] = b->mode[2] = b->mode[3] = ZEROMV;
+ } else {
+ static const uint8_t off[10] = {
+ 3, 0, 0, 1, 0, 0, 0, 0, 0, 0
+ };
+
+ // FIXME this needs to use the LUT tables from find_ref_mvs
+ // because not all are -1,0/0,-1
+ int c = inter_mode_ctx_lut[s->above_mode_ctx[col + off[b->bs]]]
+ [s->left_mode_ctx[row7 + off[b->bs]]];
+
+ b->mode[0] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree,
+ s->prob.p.mv_mode[c]);
+ b->mode[1] = b->mode[2] = b->mode[3] = b->mode[0];
+ s->counts.mv_mode[c][b->mode[0] - 10]++;
+ }
+ }
+
+ if (s->filtermode == FILTER_SWITCHABLE) {
+ int c;
+
+ if (have_a && s->above_mode_ctx[col] >= NEARESTMV) {
+ if (have_l && s->left_mode_ctx[row7] >= NEARESTMV) {
+ c = s->above_filter_ctx[col] == s->left_filter_ctx[row7] ?
+ s->left_filter_ctx[row7] : 3;
+ } else {
+ c = s->above_filter_ctx[col];
+ }
+ } else if (have_l && s->left_mode_ctx[row7] >= NEARESTMV) {
+ c = s->left_filter_ctx[row7];
+ } else {
+ c = 3;
+ }
+
+ filter_id = vp8_rac_get_tree(&s->c, vp9_filter_tree,
+ s->prob.p.filter[c]);
+ s->counts.filter[c][filter_id]++;
+ b->filter = vp9_filter_lut[filter_id];
+ } else {
+ b->filter = s->filtermode;
+ }
+
+ if (b->bs > BS_8x8) {
+ int c = inter_mode_ctx_lut[s->above_mode_ctx[col]][s->left_mode_ctx[row7]];
+
+ b->mode[0] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree,
+ s->prob.p.mv_mode[c]);
+ s->counts.mv_mode[c][b->mode[0] - 10]++;
+ fill_mv(s, b->mv[0], b->mode[0], 0);
+
+ if (b->bs != BS_8x4) {
+ b->mode[1] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree,
+ s->prob.p.mv_mode[c]);
+ s->counts.mv_mode[c][b->mode[1] - 10]++;
+ fill_mv(s, b->mv[1], b->mode[1], 1);
+ } else {
+ b->mode[1] = b->mode[0];
+ AV_COPY32(&b->mv[1][0], &b->mv[0][0]);
+ AV_COPY32(&b->mv[1][1], &b->mv[0][1]);
+ }
+
+ if (b->bs != BS_4x8) {
+ b->mode[2] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree,
+ s->prob.p.mv_mode[c]);
+ s->counts.mv_mode[c][b->mode[2] - 10]++;
+ fill_mv(s, b->mv[2], b->mode[2], 2);
+
+ if (b->bs != BS_8x4) {
+ b->mode[3] = vp8_rac_get_tree(&s->c, vp9_inter_mode_tree,
+ s->prob.p.mv_mode[c]);
+ s->counts.mv_mode[c][b->mode[3] - 10]++;
+ fill_mv(s, b->mv[3], b->mode[3], 3);
+ } else {
+ b->mode[3] = b->mode[2];
+ AV_COPY32(&b->mv[3][0], &b->mv[2][0]);
+ AV_COPY32(&b->mv[3][1], &b->mv[2][1]);
+ }
+ } else {
+ b->mode[2] = b->mode[0];
+ AV_COPY32(&b->mv[2][0], &b->mv[0][0]);
+ AV_COPY32(&b->mv[2][1], &b->mv[0][1]);
+ b->mode[3] = b->mode[1];
+ AV_COPY32(&b->mv[3][0], &b->mv[1][0]);
+ AV_COPY32(&b->mv[3][1], &b->mv[1][1]);
+ }
+ } else {
+ fill_mv(s, b->mv[0], b->mode[0], -1);
+ AV_COPY32(&b->mv[1][0], &b->mv[0][0]);
+ AV_COPY32(&b->mv[2][0], &b->mv[0][0]);
+ AV_COPY32(&b->mv[3][0], &b->mv[0][0]);
+ AV_COPY32(&b->mv[1][1], &b->mv[0][1]);
+ AV_COPY32(&b->mv[2][1], &b->mv[0][1]);
+ AV_COPY32(&b->mv[3][1], &b->mv[0][1]);
+ }
+
+ vref = b->ref[b->comp ? s->signbias[s->varcompref[0]] : 0];
+ }
+
+#if HAVE_FAST_64BIT
+#define SPLAT_CTX(var, val, n) \
+ switch (n) { \
+ case 1: var = val; break; \
+ case 2: AV_WN16A(&var, val * 0x0101); break; \
+ case 4: AV_WN32A(&var, val * 0x01010101); break; \
+ case 8: AV_WN64A(&var, val * 0x0101010101010101ULL); break; \
+ case 16: { \
+ uint64_t v64 = val * 0x0101010101010101ULL; \
+ AV_WN64A( &var, v64); \
+ AV_WN64A(&((uint8_t *) &var)[8], v64); \
+ break; \
+ } \
+ }
+#else
+#define SPLAT_CTX(var, val, n) \
+ switch (n) { \
+ case 1: var = val; break; \
+ case 2: AV_WN16A(&var, val * 0x0101); break; \
+ case 4: AV_WN32A(&var, val * 0x01010101); break; \
+ case 8: { \
+ uint32_t v32 = val * 0x01010101; \
+ AV_WN32A( &var, v32); \
+ AV_WN32A(&((uint8_t *) &var)[4], v32); \
+ break; \
+ } \
+ case 16: { \
+ uint32_t v32 = val * 0x01010101; \
+ AV_WN32A( &var, v32); \
+ AV_WN32A(&((uint8_t *) &var)[4], v32); \
+ AV_WN32A(&((uint8_t *) &var)[8], v32); \
+ AV_WN32A(&((uint8_t *) &var)[12], v32); \
+ break; \
+ } \
+ }
+#endif
+
+ switch (bwh_tab[1][b->bs][0]) {
+#define SET_CTXS(dir, off, n) \
+ do { \
+ SPLAT_CTX(s->dir##_skip_ctx[off], b->skip, n); \
+ SPLAT_CTX(s->dir##_txfm_ctx[off], b->tx, n); \
+ SPLAT_CTX(s->dir##_partition_ctx[off], dir##_ctx[b->bs], n); \
+ if (!s->keyframe && !s->intraonly) { \
+ SPLAT_CTX(s->dir##_intra_ctx[off], b->intra, n); \
+ SPLAT_CTX(s->dir##_comp_ctx[off], b->comp, n); \
+ SPLAT_CTX(s->dir##_mode_ctx[off], b->mode[3], n); \
+ if (!b->intra) { \
+ SPLAT_CTX(s->dir##_ref_ctx[off], vref, n); \
+ if (s->filtermode == FILTER_SWITCHABLE) { \
+ SPLAT_CTX(s->dir##_filter_ctx[off], filter_id, n); \
+ } \
+ } \
+ } \
+ } while (0)
+ case 1: SET_CTXS(above, col, 1); break;
+ case 2: SET_CTXS(above, col, 2); break;
+ case 4: SET_CTXS(above, col, 4); break;
+ case 8: SET_CTXS(above, col, 8); break;
+ }
+ switch (bwh_tab[1][b->bs][1]) {
+ case 1: SET_CTXS(left, row7, 1); break;
+ case 2: SET_CTXS(left, row7, 2); break;
+ case 4: SET_CTXS(left, row7, 4); break;
+ case 8: SET_CTXS(left, row7, 8); break;
+ }
+#undef SPLAT_CTX
+#undef SET_CTXS
+
+ if (!s->keyframe && !s->intraonly) {
+ if (b->bs > BS_8x8) {
+ int mv0 = AV_RN32A(&b->mv[3][0]), mv1 = AV_RN32A(&b->mv[3][1]);
+
+ AV_COPY32(&s->left_mv_ctx[row7 * 2 + 0][0], &b->mv[1][0]);
+ AV_COPY32(&s->left_mv_ctx[row7 * 2 + 0][1], &b->mv[1][1]);
+ AV_WN32A(&s->left_mv_ctx[row7 * 2 + 1][0], mv0);
+ AV_WN32A(&s->left_mv_ctx[row7 * 2 + 1][1], mv1);
+ AV_COPY32(&s->above_mv_ctx[col * 2 + 0][0], &b->mv[2][0]);
+ AV_COPY32(&s->above_mv_ctx[col * 2 + 0][1], &b->mv[2][1]);
+ AV_WN32A(&s->above_mv_ctx[col * 2 + 1][0], mv0);
+ AV_WN32A(&s->above_mv_ctx[col * 2 + 1][1], mv1);
+ } else {
+ int n, mv0 = AV_RN32A(&b->mv[3][0]), mv1 = AV_RN32A(&b->mv[3][1]);
+
+ for (n = 0; n < w4 * 2; n++) {
+ AV_WN32A(&s->above_mv_ctx[col * 2 + n][0], mv0);
+ AV_WN32A(&s->above_mv_ctx[col * 2 + n][1], mv1);
+ }
+ for (n = 0; n < h4 * 2; n++) {
+ AV_WN32A(&s->left_mv_ctx[row7 * 2 + n][0], mv0);
+ AV_WN32A(&s->left_mv_ctx[row7 * 2 + n][1], mv1);
+ }
+ }
+ }
+
+ // FIXME kinda ugly
+ for (y = 0; y < h4; y++) {
+ int x, o = (row + y) * s->sb_cols * 8 + col;
+ struct VP9mvrefPair *mv = &s->frames[CUR_FRAME].mv[o];
+
+ if (b->intra) {
+ for (x = 0; x < w4; x++) {
+ mv[x].ref[0] =
+ mv[x].ref[1] = -1;
+ }
+ } else if (b->comp) {
+ for (x = 0; x < w4; x++) {
+ mv[x].ref[0] = b->ref[0];
+ mv[x].ref[1] = b->ref[1];
+ AV_COPY32(&mv[x].mv[0], &b->mv[3][0]);
+ AV_COPY32(&mv[x].mv[1], &b->mv[3][1]);
+ }
+ } else {
+ for (x = 0; x < w4; x++) {
+ mv[x].ref[0] = b->ref[0];
+ mv[x].ref[1] = -1;
+ AV_COPY32(&mv[x].mv[0], &b->mv[3][0]);
+ }
+ }
+ }
+}
+
+// FIXME merge cnt/eob arguments?
+static av_always_inline int
+decode_coeffs_b_generic(VP56RangeCoder *c, int16_t *coef, int n_coeffs,
+ int is_tx32x32, int is8bitsperpixel, int bpp, unsigned (*cnt)[6][3],
+ unsigned (*eob)[6][2], uint8_t (*p)[6][11],
+ int nnz, const int16_t *scan, const int16_t (*nb)[2],
+ const int16_t *band_counts, const int16_t *qmul)
+{
+ int i = 0, band = 0, band_left = band_counts[band];
+ uint8_t *tp = p[0][nnz];
+ uint8_t cache[1024];
+
+ do {
+ int val, rc;
+
+ val = vp56_rac_get_prob_branchy(c, tp[0]); // eob
+ eob[band][nnz][val]++;
+ if (!val)
+ break;
+
+ skip_eob:
+ if (!vp56_rac_get_prob_branchy(c, tp[1])) { // zero
+ cnt[band][nnz][0]++;
+ if (!--band_left)
+ band_left = band_counts[++band];
+ cache[scan[i]] = 0;
+ nnz = (1 + cache[nb[i][0]] + cache[nb[i][1]]) >> 1;
+ tp = p[band][nnz];
+ if (++i == n_coeffs)
+ break; //invalid input; blocks should end with EOB
+ goto skip_eob;
+ }
+
+ rc = scan[i];
+ if (!vp56_rac_get_prob_branchy(c, tp[2])) { // one
+ cnt[band][nnz][1]++;
+ val = 1;
+ cache[rc] = 1;
+ } else {
+ // fill in p[3-10] (model fill) - only once per frame for each pos
+ if (!tp[3])
+ memcpy(&tp[3], vp9_model_pareto8[tp[2]], 8);
+
+ cnt[band][nnz][2]++;
+ if (!vp56_rac_get_prob_branchy(c, tp[3])) { // 2, 3, 4
+ if (!vp56_rac_get_prob_branchy(c, tp[4])) {
+ cache[rc] = val = 2;
+ } else {
+ val = 3 + vp56_rac_get_prob(c, tp[5]);
+ cache[rc] = 3;
+ }
+ } else if (!vp56_rac_get_prob_branchy(c, tp[6])) { // cat1/2
+ cache[rc] = 4;
+ if (!vp56_rac_get_prob_branchy(c, tp[7])) {
+ val = 5 + vp56_rac_get_prob(c, 159);
+ } else {
+ val = 7 + (vp56_rac_get_prob(c, 165) << 1);
+ val += vp56_rac_get_prob(c, 145);
+ }
+ } else { // cat 3-6
+ cache[rc] = 5;
+ if (!vp56_rac_get_prob_branchy(c, tp[8])) {
+ if (!vp56_rac_get_prob_branchy(c, tp[9])) {
+ val = 11 + (vp56_rac_get_prob(c, 173) << 2);
+ val += (vp56_rac_get_prob(c, 148) << 1);
+ val += vp56_rac_get_prob(c, 140);
+ } else {
+ val = 19 + (vp56_rac_get_prob(c, 176) << 3);
+ val += (vp56_rac_get_prob(c, 155) << 2);
+ val += (vp56_rac_get_prob(c, 140) << 1);
+ val += vp56_rac_get_prob(c, 135);
+ }
+ } else if (!vp56_rac_get_prob_branchy(c, tp[10])) {
+ val = 35 + (vp56_rac_get_prob(c, 180) << 4);
+ val += (vp56_rac_get_prob(c, 157) << 3);
+ val += (vp56_rac_get_prob(c, 141) << 2);
+ val += (vp56_rac_get_prob(c, 134) << 1);
+ val += vp56_rac_get_prob(c, 130);
+ } else {
+ val = 67;
+ if (!is8bitsperpixel) {
+ if (bpp == 12) {
+ val += vp56_rac_get_prob(c, 255) << 17;
+ val += vp56_rac_get_prob(c, 255) << 16;
+ }
+ val += (vp56_rac_get_prob(c, 255) << 15);
+ val += (vp56_rac_get_prob(c, 255) << 14);
+ }
+ val += (vp56_rac_get_prob(c, 254) << 13);
+ val += (vp56_rac_get_prob(c, 254) << 12);
+ val += (vp56_rac_get_prob(c, 254) << 11);
+ val += (vp56_rac_get_prob(c, 252) << 10);
+ val += (vp56_rac_get_prob(c, 249) << 9);
+ val += (vp56_rac_get_prob(c, 243) << 8);
+ val += (vp56_rac_get_prob(c, 230) << 7);
+ val += (vp56_rac_get_prob(c, 196) << 6);
+ val += (vp56_rac_get_prob(c, 177) << 5);
+ val += (vp56_rac_get_prob(c, 153) << 4);
+ val += (vp56_rac_get_prob(c, 140) << 3);
+ val += (vp56_rac_get_prob(c, 133) << 2);
+ val += (vp56_rac_get_prob(c, 130) << 1);
+ val += vp56_rac_get_prob(c, 129);
+ }
+ }
+ }
+#define STORE_COEF(c, i, v) do { \
+ if (is8bitsperpixel) { \
+ c[i] = v; \
+ } else { \
+ AV_WN32A(&c[i * 2], v); \
+ } \
+} while (0)
+ if (!--band_left)
+ band_left = band_counts[++band];
+ if (is_tx32x32)
+ STORE_COEF(coef, rc, ((vp8_rac_get(c) ? -val : val) * qmul[!!i]) / 2);
+ else
+ STORE_COEF(coef, rc, (vp8_rac_get(c) ? -val : val) * qmul[!!i]);
+ nnz = (1 + cache[nb[i][0]] + cache[nb[i][1]]) >> 1;
+ tp = p[band][nnz];
+ } while (++i < n_coeffs);
+
+ return i;
+}
+
+static int decode_coeffs_b_8bpp(VP9Context *s, int16_t *coef, int n_coeffs,
+ unsigned (*cnt)[6][3], unsigned (*eob)[6][2],
+ uint8_t (*p)[6][11], int nnz, const int16_t *scan,
+ const int16_t (*nb)[2], const int16_t *band_counts,
+ const int16_t *qmul)
+{
+ return decode_coeffs_b_generic(&s->c, coef, n_coeffs, 0, 1, 8, cnt, eob, p,
+ nnz, scan, nb, band_counts, qmul);
+}
+
+static int decode_coeffs_b32_8bpp(VP9Context *s, int16_t *coef, int n_coeffs,
+ unsigned (*cnt)[6][3], unsigned (*eob)[6][2],
+ uint8_t (*p)[6][11], int nnz, const int16_t *scan,
+ const int16_t (*nb)[2], const int16_t *band_counts,
+ const int16_t *qmul)
+{
+ return decode_coeffs_b_generic(&s->c, coef, n_coeffs, 1, 1, 8, cnt, eob, p,
+ nnz, scan, nb, band_counts, qmul);
+}
+
+static int decode_coeffs_b_16bpp(VP9Context *s, int16_t *coef, int n_coeffs,
+ unsigned (*cnt)[6][3], unsigned (*eob)[6][2],
+ uint8_t (*p)[6][11], int nnz, const int16_t *scan,
+ const int16_t (*nb)[2], const int16_t *band_counts,
+ const int16_t *qmul)
+{
+ return decode_coeffs_b_generic(&s->c, coef, n_coeffs, 0, 0, s->bpp, cnt, eob, p,
+ nnz, scan, nb, band_counts, qmul);
+}
+
+static int decode_coeffs_b32_16bpp(VP9Context *s, int16_t *coef, int n_coeffs,
+ unsigned (*cnt)[6][3], unsigned (*eob)[6][2],
+ uint8_t (*p)[6][11], int nnz, const int16_t *scan,
+ const int16_t (*nb)[2], const int16_t *band_counts,
+ const int16_t *qmul)
+{
+ return decode_coeffs_b_generic(&s->c, coef, n_coeffs, 1, 0, s->bpp, cnt, eob, p,
+ nnz, scan, nb, band_counts, qmul);
+}
+
+static av_always_inline int decode_coeffs(AVCodecContext *ctx, int is8bitsperpixel)
+{
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ int row = s->row, col = s->col;
+ uint8_t (*p)[6][11] = s->prob.coef[b->tx][0 /* y */][!b->intra];
+ unsigned (*c)[6][3] = s->counts.coef[b->tx][0 /* y */][!b->intra];
+ unsigned (*e)[6][2] = s->counts.eob[b->tx][0 /* y */][!b->intra];
+ int w4 = bwh_tab[1][b->bs][0] << 1, h4 = bwh_tab[1][b->bs][1] << 1;
+ int end_x = FFMIN(2 * (s->cols - col), w4);
+ int end_y = FFMIN(2 * (s->rows - row), h4);
+ int n, pl, x, y, res;
+ int16_t (*qmul)[2] = s->segmentation.feat[b->seg_id].qmul;
+ int tx = 4 * s->lossless + b->tx;
+ const int16_t * const *yscans = vp9_scans[tx];
+ const int16_t (* const *ynbs)[2] = vp9_scans_nb[tx];
+ const int16_t *uvscan = vp9_scans[b->uvtx][DCT_DCT];
+ const int16_t (*uvnb)[2] = vp9_scans_nb[b->uvtx][DCT_DCT];
+ uint8_t *a = &s->above_y_nnz_ctx[col * 2];
+ uint8_t *l = &s->left_y_nnz_ctx[(row & 7) << 1];
+ static const int16_t band_counts[4][8] = {
+ { 1, 2, 3, 4, 3, 16 - 13 },
+ { 1, 2, 3, 4, 11, 64 - 21 },
+ { 1, 2, 3, 4, 11, 256 - 21 },
+ { 1, 2, 3, 4, 11, 1024 - 21 },
+ };
+ const int16_t *y_band_counts = band_counts[b->tx];
+ const int16_t *uv_band_counts = band_counts[b->uvtx];
+ int bytesperpixel = is8bitsperpixel ? 1 : 2;
+ int total_coeff = 0;
+
+#define MERGE(la, end, step, rd) \
+ for (n = 0; n < end; n += step) \
+ la[n] = !!rd(&la[n])
+#define MERGE_CTX(step, rd) \
+ do { \
+ MERGE(l, end_y, step, rd); \
+ MERGE(a, end_x, step, rd); \
+ } while (0)
+
+#define DECODE_Y_COEF_LOOP(step, mode_index, v) \
+ for (n = 0, y = 0; y < end_y; y += step) { \
+ for (x = 0; x < end_x; x += step, n += step * step) { \
+ enum TxfmType txtp = vp9_intra_txfm_type[b->mode[mode_index]]; \
+ res = (is8bitsperpixel ? decode_coeffs_b##v##_8bpp : decode_coeffs_b##v##_16bpp) \
+ (s, s->block + 16 * n * bytesperpixel, 16 * step * step, \
+ c, e, p, a[x] + l[y], yscans[txtp], \
+ ynbs[txtp], y_band_counts, qmul[0]); \
+ a[x] = l[y] = !!res; \
+ total_coeff |= !!res; \
+ if (step >= 4) { \
+ AV_WN16A(&s->eob[n], res); \
+ } else { \
+ s->eob[n] = res; \
+ } \
+ } \
+ }
+
+#define SPLAT(la, end, step, cond) \
+ if (step == 2) { \
+ for (n = 1; n < end; n += step) \
+ la[n] = la[n - 1]; \
+ } else if (step == 4) { \
+ if (cond) { \
+ for (n = 0; n < end; n += step) \
+ AV_WN32A(&la[n], la[n] * 0x01010101); \
+ } else { \
+ for (n = 0; n < end; n += step) \
+ memset(&la[n + 1], la[n], FFMIN(end - n - 1, 3)); \
+ } \
+ } else /* step == 8 */ { \
+ if (cond) { \
+ if (HAVE_FAST_64BIT) { \
+ for (n = 0; n < end; n += step) \
+ AV_WN64A(&la[n], la[n] * 0x0101010101010101ULL); \
+ } else { \
+ for (n = 0; n < end; n += step) { \
+ uint32_t v32 = la[n] * 0x01010101; \
+ AV_WN32A(&la[n], v32); \
+ AV_WN32A(&la[n + 4], v32); \
+ } \
+ } \
+ } else { \
+ for (n = 0; n < end; n += step) \
+ memset(&la[n + 1], la[n], FFMIN(end - n - 1, 7)); \
+ } \
+ }
+#define SPLAT_CTX(step) \
+ do { \
+ SPLAT(a, end_x, step, end_x == w4); \
+ SPLAT(l, end_y, step, end_y == h4); \
+ } while (0)
+
+ /* y tokens */
+ switch (b->tx) {
+ case TX_4X4:
+ DECODE_Y_COEF_LOOP(1, b->bs > BS_8x8 ? n : 0,);
+ break;
+ case TX_8X8:
+ MERGE_CTX(2, AV_RN16A);
+ DECODE_Y_COEF_LOOP(2, 0,);
+ SPLAT_CTX(2);
+ break;
+ case TX_16X16:
+ MERGE_CTX(4, AV_RN32A);
+ DECODE_Y_COEF_LOOP(4, 0,);
+ SPLAT_CTX(4);
+ break;
+ case TX_32X32:
+ MERGE_CTX(8, AV_RN64A);
+ DECODE_Y_COEF_LOOP(8, 0, 32);
+ SPLAT_CTX(8);
+ break;
+ }
+
+#define DECODE_UV_COEF_LOOP(step, v) \
+ for (n = 0, y = 0; y < end_y; y += step) { \
+ for (x = 0; x < end_x; x += step, n += step * step) { \
+ res = (is8bitsperpixel ? decode_coeffs_b##v##_8bpp : decode_coeffs_b##v##_16bpp) \
+ (s, s->uvblock[pl] + 16 * n * bytesperpixel, \
+ 16 * step * step, c, e, p, a[x] + l[y], \
+ uvscan, uvnb, uv_band_counts, qmul[1]); \
+ a[x] = l[y] = !!res; \
+ total_coeff |= !!res; \
+ if (step >= 4) { \
+ AV_WN16A(&s->uveob[pl][n], res); \
+ } else { \
+ s->uveob[pl][n] = res; \
+ } \
+ } \
+ }
+
+ p = s->prob.coef[b->uvtx][1 /* uv */][!b->intra];
+ c = s->counts.coef[b->uvtx][1 /* uv */][!b->intra];
+ e = s->counts.eob[b->uvtx][1 /* uv */][!b->intra];
+ w4 >>= s->ss_h;
+ end_x >>= s->ss_h;
+ h4 >>= s->ss_v;
+ end_y >>= s->ss_v;
+ for (pl = 0; pl < 2; pl++) {
+ a = &s->above_uv_nnz_ctx[pl][col << !s->ss_h];
+ l = &s->left_uv_nnz_ctx[pl][(row & 7) << !s->ss_v];
+ switch (b->uvtx) {
+ case TX_4X4:
+ DECODE_UV_COEF_LOOP(1,);
+ break;
+ case TX_8X8:
+ MERGE_CTX(2, AV_RN16A);
+ DECODE_UV_COEF_LOOP(2,);
+ SPLAT_CTX(2);
+ break;
+ case TX_16X16:
+ MERGE_CTX(4, AV_RN32A);
+ DECODE_UV_COEF_LOOP(4,);
+ SPLAT_CTX(4);
+ break;
+ case TX_32X32:
+ MERGE_CTX(8, AV_RN64A);
+ DECODE_UV_COEF_LOOP(8, 32);
+ SPLAT_CTX(8);
+ break;
+ }
+ }
+
+ return total_coeff;
+}
+
+static int decode_coeffs_8bpp(AVCodecContext *ctx)
+{
+ return decode_coeffs(ctx, 1);
+}
+
+static int decode_coeffs_16bpp(AVCodecContext *ctx)
+{
+ return decode_coeffs(ctx, 0);
+}
+
+static av_always_inline int check_intra_mode(VP9Context *s, int mode, uint8_t **a,
+ uint8_t *dst_edge, ptrdiff_t stride_edge,
+ uint8_t *dst_inner, ptrdiff_t stride_inner,
+ uint8_t *l, int col, int x, int w,
+ int row, int y, enum TxfmMode tx,
+ int p, int ss_h, int ss_v, int bytesperpixel)
{
- VP9Context *s = avctx->priv_data;
- int c = ((s->above_partition_ctx[col] >> (3 - bl)) & 1) |
+ int have_top = row > 0 || y > 0;
+ int have_left = col > s->tiling.tile_col_start || x > 0;
+ int have_right = x < w - 1;
+ int bpp = s->bpp;
+ static const uint8_t mode_conv[10][2 /* have_left */][2 /* have_top */] = {
+ [VERT_PRED] = { { DC_127_PRED, VERT_PRED },
+ { DC_127_PRED, VERT_PRED } },
+ [HOR_PRED] = { { DC_129_PRED, DC_129_PRED },
+ { HOR_PRED, HOR_PRED } },
+ [DC_PRED] = { { DC_128_PRED, TOP_DC_PRED },
+ { LEFT_DC_PRED, DC_PRED } },
+ [DIAG_DOWN_LEFT_PRED] = { { DC_127_PRED, DIAG_DOWN_LEFT_PRED },
+ { DC_127_PRED, DIAG_DOWN_LEFT_PRED } },
+ [DIAG_DOWN_RIGHT_PRED] = { { DIAG_DOWN_RIGHT_PRED, DIAG_DOWN_RIGHT_PRED },
+ { DIAG_DOWN_RIGHT_PRED, DIAG_DOWN_RIGHT_PRED } },
+ [VERT_RIGHT_PRED] = { { VERT_RIGHT_PRED, VERT_RIGHT_PRED },
+ { VERT_RIGHT_PRED, VERT_RIGHT_PRED } },
+ [HOR_DOWN_PRED] = { { HOR_DOWN_PRED, HOR_DOWN_PRED },
+ { HOR_DOWN_PRED, HOR_DOWN_PRED } },
+ [VERT_LEFT_PRED] = { { DC_127_PRED, VERT_LEFT_PRED },
+ { DC_127_PRED, VERT_LEFT_PRED } },
+ [HOR_UP_PRED] = { { DC_129_PRED, DC_129_PRED },
+ { HOR_UP_PRED, HOR_UP_PRED } },
+ [TM_VP8_PRED] = { { DC_129_PRED, VERT_PRED },
+ { HOR_PRED, TM_VP8_PRED } },
+ };
+ static const struct {
+ uint8_t needs_left:1;
+ uint8_t needs_top:1;
+ uint8_t needs_topleft:1;
+ uint8_t needs_topright:1;
+ uint8_t invert_left:1;
+ } edges[N_INTRA_PRED_MODES] = {
+ [VERT_PRED] = { .needs_top = 1 },
+ [HOR_PRED] = { .needs_left = 1 },
+ [DC_PRED] = { .needs_top = 1, .needs_left = 1 },
+ [DIAG_DOWN_LEFT_PRED] = { .needs_top = 1, .needs_topright = 1 },
+ [DIAG_DOWN_RIGHT_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+ [VERT_RIGHT_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+ [HOR_DOWN_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+ [VERT_LEFT_PRED] = { .needs_top = 1, .needs_topright = 1 },
+ [HOR_UP_PRED] = { .needs_left = 1, .invert_left = 1 },
+ [TM_VP8_PRED] = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
+ [LEFT_DC_PRED] = { .needs_left = 1 },
+ [TOP_DC_PRED] = { .needs_top = 1 },
+ [DC_128_PRED] = { 0 },
+ [DC_127_PRED] = { 0 },
+ [DC_129_PRED] = { 0 }
+ };
+
+ av_assert2(mode >= 0 && mode < 10);
+ mode = mode_conv[mode][have_left][have_top];
+ if (edges[mode].needs_top) {
+ uint8_t *top, *topleft;
+ int n_px_need = 4 << tx, n_px_have = (((s->cols - col) << !ss_h) - x) * 4;
+ int n_px_need_tr = 0;
+
+ if (tx == TX_4X4 && edges[mode].needs_topright && have_right)
+ n_px_need_tr = 4;
+
+ // if top of sb64-row, use s->intra_pred_data[] instead of
+ // dst[-stride] for intra prediction (it contains pre- instead of
+ // post-loopfilter data)
+ if (have_top) {
+ top = !(row & 7) && !y ?
+ s->intra_pred_data[p] + (col * (8 >> ss_h) + x * 4) * bytesperpixel :
+ y == 0 ? &dst_edge[-stride_edge] : &dst_inner[-stride_inner];
+ if (have_left)
+ topleft = !(row & 7) && !y ?
+ s->intra_pred_data[p] + (col * (8 >> ss_h) + x * 4) * bytesperpixel :
+ y == 0 || x == 0 ? &dst_edge[-stride_edge] :
+ &dst_inner[-stride_inner];
+ }
+
+ if (have_top &&
+ (!edges[mode].needs_topleft || (have_left && top == topleft)) &&
+ (tx != TX_4X4 || !edges[mode].needs_topright || have_right) &&
+ n_px_need + n_px_need_tr <= n_px_have) {
+ *a = top;
+ } else {
+ if (have_top) {
+ if (n_px_need <= n_px_have) {
+ memcpy(*a, top, n_px_need * bytesperpixel);
+ } else {
+#define memset_bpp(c, i1, v, i2, num) do { \
+ if (bytesperpixel == 1) { \
+ memset(&(c)[(i1)], (v)[(i2)], (num)); \
+ } else { \
+ int n, val = AV_RN16A(&(v)[(i2) * 2]); \
+ for (n = 0; n < (num); n++) { \
+ AV_WN16A(&(c)[((i1) + n) * 2], val); \
+ } \
+ } \
+} while (0)
+ memcpy(*a, top, n_px_have * bytesperpixel);
+ memset_bpp(*a, n_px_have, (*a), n_px_have - 1, n_px_need - n_px_have);
+ }
+ } else {
+#define memset_val(c, val, num) do { \
+ if (bytesperpixel == 1) { \
+ memset((c), (val), (num)); \
+ } else { \
+ int n; \
+ for (n = 0; n < (num); n++) { \
+ AV_WN16A(&(c)[n * 2], (val)); \
+ } \
+ } \
+} while (0)
+ memset_val(*a, (128 << (bpp - 8)) - 1, n_px_need);
+ }
+ if (edges[mode].needs_topleft) {
+ if (have_left && have_top) {
+#define assign_bpp(c, i1, v, i2) do { \
+ if (bytesperpixel == 1) { \
+ (c)[(i1)] = (v)[(i2)]; \
+ } else { \
+ AV_COPY16(&(c)[(i1) * 2], &(v)[(i2) * 2]); \
+ } \
+} while (0)
+ assign_bpp(*a, -1, topleft, -1);
+ } else {
+#define assign_val(c, i, v) do { \
+ if (bytesperpixel == 1) { \
+ (c)[(i)] = (v); \
+ } else { \
+ AV_WN16A(&(c)[(i) * 2], (v)); \
+ } \
+} while (0)
+ assign_val((*a), -1, (128 << (bpp - 8)) + (have_top ? +1 : -1));
+ }
+ }
+ if (tx == TX_4X4 && edges[mode].needs_topright) {
+ if (have_top && have_right &&
+ n_px_need + n_px_need_tr <= n_px_have) {
+ memcpy(&(*a)[4 * bytesperpixel], &top[4 * bytesperpixel], 4 * bytesperpixel);
+ } else {
+ memset_bpp(*a, 4, *a, 3, 4);
+ }
+ }
+ }
+ }
+ if (edges[mode].needs_left) {
+ if (have_left) {
+ int n_px_need = 4 << tx, i, n_px_have = (((s->rows - row) << !ss_v) - y) * 4;
+ uint8_t *dst = x == 0 ? dst_edge : dst_inner;
+ ptrdiff_t stride = x == 0 ? stride_edge : stride_inner;
+
+ if (edges[mode].invert_left) {
+ if (n_px_need <= n_px_have) {
+ for (i = 0; i < n_px_need; i++)
+ assign_bpp(l, i, &dst[i * stride], -1);
+ } else {
+ for (i = 0; i < n_px_have; i++)
+ assign_bpp(l, i, &dst[i * stride], -1);
+ memset_bpp(l, n_px_have, l, n_px_have - 1, n_px_need - n_px_have);
+ }
+ } else {
+ if (n_px_need <= n_px_have) {
+ for (i = 0; i < n_px_need; i++)
+ assign_bpp(l, n_px_need - 1 - i, &dst[i * stride], -1);
+ } else {
+ for (i = 0; i < n_px_have; i++)
+ assign_bpp(l, n_px_need - 1 - i, &dst[i * stride], -1);
+ memset_bpp(l, 0, l, n_px_need - n_px_have, n_px_need - n_px_have);
+ }
+ }
+ } else {
+ memset_val(l, (128 << (bpp - 8)) + 1, 4 << tx);
+ }
+ }
+
+ return mode;
+}
+
+static av_always_inline void intra_recon(AVCodecContext *ctx, ptrdiff_t y_off,
+ ptrdiff_t uv_off, int bytesperpixel)
+{
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ int row = s->row, col = s->col;
+ int w4 = bwh_tab[1][b->bs][0] << 1, step1d = 1 << b->tx, n;
+ int h4 = bwh_tab[1][b->bs][1] << 1, x, y, step = 1 << (b->tx * 2);
+ int end_x = FFMIN(2 * (s->cols - col), w4);
+ int end_y = FFMIN(2 * (s->rows - row), h4);
+ int tx = 4 * s->lossless + b->tx, uvtx = b->uvtx + 4 * s->lossless;
+ int uvstep1d = 1 << b->uvtx, p;
+ uint8_t *dst = s->dst[0], *dst_r = s->frames[CUR_FRAME].tf.f->data[0] + y_off;
+ LOCAL_ALIGNED_32(uint8_t, a_buf, [96]);
+ LOCAL_ALIGNED_32(uint8_t, l, [64]);
+
+ for (n = 0, y = 0; y < end_y; y += step1d) {
+ uint8_t *ptr = dst, *ptr_r = dst_r;
+ for (x = 0; x < end_x; x += step1d, ptr += 4 * step1d * bytesperpixel,
+ ptr_r += 4 * step1d * bytesperpixel, n += step) {
+ int mode = b->mode[b->bs > BS_8x8 && b->tx == TX_4X4 ?
+ y * 2 + x : 0];
+ uint8_t *a = &a_buf[32];
+ enum TxfmType txtp = vp9_intra_txfm_type[mode];
+ int eob = b->skip ? 0 : b->tx > TX_8X8 ? AV_RN16A(&s->eob[n]) : s->eob[n];
+
+ mode = check_intra_mode(s, mode, &a, ptr_r,
+ s->frames[CUR_FRAME].tf.f->linesize[0],
+ ptr, s->y_stride, l,
+ col, x, w4, row, y, b->tx, 0, 0, 0, bytesperpixel);
+ s->dsp.intra_pred[b->tx][mode](ptr, s->y_stride, l, a);
+ if (eob)
+ s->dsp.itxfm_add[tx][txtp](ptr, s->y_stride,
+ s->block + 16 * n * bytesperpixel, eob);
+ }
+ dst_r += 4 * step1d * s->frames[CUR_FRAME].tf.f->linesize[0];
+ dst += 4 * step1d * s->y_stride;
+ }
+
+ // U/V
+ w4 >>= s->ss_h;
+ end_x >>= s->ss_h;
+ end_y >>= s->ss_v;
+ step = 1 << (b->uvtx * 2);
+ for (p = 0; p < 2; p++) {
+ dst = s->dst[1 + p];
+ dst_r = s->frames[CUR_FRAME].tf.f->data[1 + p] + uv_off;
+ for (n = 0, y = 0; y < end_y; y += uvstep1d) {
+ uint8_t *ptr = dst, *ptr_r = dst_r;
+ for (x = 0; x < end_x; x += uvstep1d, ptr += 4 * uvstep1d * bytesperpixel,
+ ptr_r += 4 * uvstep1d * bytesperpixel, n += step) {
+ int mode = b->uvmode;
+ uint8_t *a = &a_buf[32];
+ int eob = b->skip ? 0 : b->uvtx > TX_8X8 ? AV_RN16A(&s->uveob[p][n]) : s->uveob[p][n];
+
+ mode = check_intra_mode(s, mode, &a, ptr_r,
+ s->frames[CUR_FRAME].tf.f->linesize[1],
+ ptr, s->uv_stride, l, col, x, w4, row, y,
+ b->uvtx, p + 1, s->ss_h, s->ss_v, bytesperpixel);
+ s->dsp.intra_pred[b->uvtx][mode](ptr, s->uv_stride, l, a);
+ if (eob)
+ s->dsp.itxfm_add[uvtx][DCT_DCT](ptr, s->uv_stride,
+ s->uvblock[p] + 16 * n * bytesperpixel, eob);
+ }
+ dst_r += 4 * uvstep1d * s->frames[CUR_FRAME].tf.f->linesize[1];
+ dst += 4 * uvstep1d * s->uv_stride;
+ }
+ }
+}
+
+static void intra_recon_8bpp(AVCodecContext *ctx, ptrdiff_t y_off, ptrdiff_t uv_off)
+{
+ intra_recon(ctx, y_off, uv_off, 1);
+}
+
+static void intra_recon_16bpp(AVCodecContext *ctx, ptrdiff_t y_off, ptrdiff_t uv_off)
+{
+ intra_recon(ctx, y_off, uv_off, 2);
+}
+
+static av_always_inline void mc_luma_scaled(VP9Context *s, vp9_scaled_mc_func smc,
+ uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *ref, ptrdiff_t ref_stride,
+ ThreadFrame *ref_frame,
+ ptrdiff_t y, ptrdiff_t x, const VP56mv *in_mv,
+ int px, int py, int pw, int ph,
+ int bw, int bh, int w, int h, int bytesperpixel,
+ const uint16_t *scale, const uint8_t *step)
+{
+#define scale_mv(n, dim) (((int64_t)(n) * scale[dim]) >> 14)
+ int mx, my;
+ int refbw_m1, refbh_m1;
+ int th;
+ VP56mv mv;
+
+ mv.x = av_clip(in_mv->x, -(x + pw - px + 4) << 3, (s->cols * 8 - x + px + 3) << 3);
+ mv.y = av_clip(in_mv->y, -(y + ph - py + 4) << 3, (s->rows * 8 - y + py + 3) << 3);
+ // BUG libvpx seems to scale the two components separately. This introduces
+ // rounding errors but we have to reproduce them to be exactly compatible
+ // with the output from libvpx...
+ mx = scale_mv(mv.x * 2, 0) + scale_mv(x * 16, 0);
+ my = scale_mv(mv.y * 2, 1) + scale_mv(y * 16, 1);
+
+ y = my >> 4;
+ x = mx >> 4;
+ ref += y * ref_stride + x * bytesperpixel;
+ mx &= 15;
+ my &= 15;
+ refbw_m1 = ((bw - 1) * step[0] + mx) >> 4;
+ refbh_m1 = ((bh - 1) * step[1] + my) >> 4;
+ // FIXME bilinear filter only needs 0/1 pixels, not 3/4
+ // 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);
+ if (x < 3 || y < 3 || x + 4 >= w - refbw_m1 || y + 4 >= h - refbh_m1) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ ref - 3 * ref_stride - 3 * bytesperpixel,
+ 288, ref_stride,
+ refbw_m1 + 8, refbh_m1 + 8,
+ x - 3, y - 3, w, h);
+ ref = s->edge_emu_buffer + 3 * 288 + 3 * bytesperpixel;
+ ref_stride = 288;
+ }
+ smc(dst, dst_stride, ref, ref_stride, bh, mx, my, step[0], step[1]);
+}
+
+static av_always_inline void mc_chroma_scaled(VP9Context *s, vp9_scaled_mc_func smc,
+ uint8_t *dst_u, uint8_t *dst_v,
+ ptrdiff_t dst_stride,
+ const uint8_t *ref_u, ptrdiff_t src_stride_u,
+ const uint8_t *ref_v, ptrdiff_t src_stride_v,
+ ThreadFrame *ref_frame,
+ ptrdiff_t y, ptrdiff_t x, const VP56mv *in_mv,
+ int px, int py, int pw, int ph,
+ int bw, int bh, int w, int h, int bytesperpixel,
+ const uint16_t *scale, const uint8_t *step)
+{
+ int mx, my;
+ int refbw_m1, refbh_m1;
+ int th;
+ VP56mv mv;
+
+ if (s->ss_h) {
+ // BUG https://code.google.com/p/webm/issues/detail?id=820
+ mv.x = av_clip(in_mv->x, -(x + pw - px + 4) << 4, (s->cols * 4 - x + px + 3) << 4);
+ mx = scale_mv(mv.x, 0) + (scale_mv(x * 16, 0) & ~15) + (scale_mv(x * 32, 0) & 15);
+ } else {
+ mv.x = av_clip(in_mv->x, -(x + pw - px + 4) << 3, (s->cols * 8 - x + px + 3) << 3);
+ mx = scale_mv(mv.x << 1, 0) + scale_mv(x * 16, 0);
+ }
+ if (s->ss_v) {
+ // BUG https://code.google.com/p/webm/issues/detail?id=820
+ mv.y = av_clip(in_mv->y, -(y + ph - py + 4) << 4, (s->rows * 4 - y + py + 3) << 4);
+ my = scale_mv(mv.y, 1) + (scale_mv(y * 16, 1) & ~15) + (scale_mv(y * 32, 1) & 15);
+ } else {
+ mv.y = av_clip(in_mv->y, -(y + ph - py + 4) << 3, (s->rows * 8 - y + py + 3) << 3);
+ my = scale_mv(mv.y << 1, 1) + scale_mv(y * 16, 1);
+ }
+#undef scale_mv
+ y = my >> 4;
+ x = mx >> 4;
+ ref_u += y * src_stride_u + x * bytesperpixel;
+ ref_v += y * src_stride_v + x * bytesperpixel;
+ mx &= 15;
+ my &= 15;
+ refbw_m1 = ((bw - 1) * step[0] + mx) >> 4;
+ refbh_m1 = ((bh - 1) * step[1] + my) >> 4;
+ // FIXME bilinear filter only needs 0/1 pixels, not 3/4
+ // 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);
+ if (x < 3 || y < 3 || x + 4 >= w - refbw_m1 || y + 4 >= h - refbh_m1) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ ref_u - 3 * src_stride_u - 3 * bytesperpixel,
+ 288, src_stride_u,
+ refbw_m1 + 8, refbh_m1 + 8,
+ x - 3, y - 3, w, h);
+ ref_u = s->edge_emu_buffer + 3 * 288 + 3 * bytesperpixel;
+ smc(dst_u, dst_stride, ref_u, 288, bh, mx, my, step[0], step[1]);
+
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ ref_v - 3 * src_stride_v - 3 * bytesperpixel,
+ 288, src_stride_v,
+ refbw_m1 + 8, refbh_m1 + 8,
+ x - 3, y - 3, w, h);
+ ref_v = s->edge_emu_buffer + 3 * 288 + 3 * bytesperpixel;
+ smc(dst_v, dst_stride, ref_v, 288, bh, mx, my, step[0], step[1]);
+ } else {
+ smc(dst_u, dst_stride, ref_u, src_stride_u, bh, mx, my, step[0], step[1]);
+ smc(dst_v, dst_stride, ref_v, src_stride_v, bh, mx, my, step[0], step[1]);
+ }
+}
+
+#define mc_luma_dir(s, mc, dst, dst_ls, src, src_ls, tref, row, col, mv, \
+ px, py, pw, ph, bw, bh, w, h, i) \
+ mc_luma_scaled(s, s->dsp.s##mc, dst, dst_ls, src, src_ls, tref, row, col, \
+ mv, px, py, pw, ph, bw, bh, w, h, bytesperpixel, \
+ s->mvscale[b->ref[i]], s->mvstep[b->ref[i]])
+#define mc_chroma_dir(s, mc, dstu, dstv, dst_ls, srcu, srcu_ls, srcv, srcv_ls, tref, \
+ row, col, mv, px, py, pw, ph, bw, bh, w, h, i) \
+ mc_chroma_scaled(s, s->dsp.s##mc, dstu, dstv, dst_ls, srcu, srcu_ls, srcv, srcv_ls, tref, \
+ row, col, mv, px, py, pw, ph, bw, bh, w, h, bytesperpixel, \
+ s->mvscale[b->ref[i]], s->mvstep[b->ref[i]])
+#define SCALED 1
+#define FN(x) x##_scaled_8bpp
+#define BYTES_PER_PIXEL 1
+#include "vp9_mc_template.c"
+#undef FN
+#undef BYTES_PER_PIXEL
+#define FN(x) x##_scaled_16bpp
+#define BYTES_PER_PIXEL 2
+#include "vp9_mc_template.c"
+#undef mc_luma_dir
+#undef mc_chroma_dir
+#undef FN
+#undef BYTES_PER_PIXEL
+#undef SCALED
+
+static av_always_inline void mc_luma_unscaled(VP9Context *s, vp9_mc_func (*mc)[2],
+ uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *ref, ptrdiff_t ref_stride,
+ ThreadFrame *ref_frame,
+ ptrdiff_t y, ptrdiff_t x, const VP56mv *mv,
+ int bw, int bh, int w, int h, int bytesperpixel)
+{
+ int mx = mv->x, my = mv->y, th;
+
+ y += my >> 3;
+ x += mx >> 3;
+ ref += y * ref_stride + x * bytesperpixel;
+ mx &= 7;
+ my &= 7;
+ // FIXME bilinear filter only needs 0/1 pixels, not 3/4
+ // 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);
+ if (x < !!mx * 3 || y < !!my * 3 ||
+ x + !!mx * 4 > w - bw || y + !!my * 4 > h - bh) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ ref - !!my * 3 * ref_stride - !!mx * 3 * bytesperpixel,
+ 160, ref_stride,
+ bw + !!mx * 7, bh + !!my * 7,
+ x - !!mx * 3, y - !!my * 3, w, h);
+ ref = s->edge_emu_buffer + !!my * 3 * 160 + !!mx * 3 * bytesperpixel;
+ ref_stride = 160;
+ }
+ mc[!!mx][!!my](dst, dst_stride, ref, ref_stride, bh, mx << 1, my << 1);
+}
+
+static av_always_inline void mc_chroma_unscaled(VP9Context *s, vp9_mc_func (*mc)[2],
+ uint8_t *dst_u, uint8_t *dst_v,
+ ptrdiff_t dst_stride,
+ const uint8_t *ref_u, ptrdiff_t src_stride_u,
+ const uint8_t *ref_v, ptrdiff_t src_stride_v,
+ ThreadFrame *ref_frame,
+ ptrdiff_t y, ptrdiff_t x, const VP56mv *mv,
+ int bw, int bh, int w, int h, int bytesperpixel)
+{
+ int mx = mv->x << !s->ss_h, my = mv->y << !s->ss_v, th;
+
+ y += my >> 4;
+ x += mx >> 4;
+ ref_u += y * src_stride_u + x * bytesperpixel;
+ ref_v += y * src_stride_v + x * bytesperpixel;
+ mx &= 15;
+ my &= 15;
+ // FIXME bilinear filter only needs 0/1 pixels, not 3/4
+ // 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);
+ if (x < !!mx * 3 || y < !!my * 3 ||
+ x + !!mx * 4 > w - bw || y + !!my * 4 > h - bh) {
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ ref_u - !!my * 3 * src_stride_u - !!mx * 3 * bytesperpixel,
+ 160, src_stride_u,
+ bw + !!mx * 7, bh + !!my * 7,
+ x - !!mx * 3, y - !!my * 3, w, h);
+ ref_u = s->edge_emu_buffer + !!my * 3 * 160 + !!mx * 3 * bytesperpixel;
+ mc[!!mx][!!my](dst_u, dst_stride, ref_u, 160, bh, mx, my);
+
+ s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
+ ref_v - !!my * 3 * src_stride_v - !!mx * 3 * bytesperpixel,
+ 160, src_stride_v,
+ bw + !!mx * 7, bh + !!my * 7,
+ x - !!mx * 3, y - !!my * 3, w, h);
+ ref_v = s->edge_emu_buffer + !!my * 3 * 160 + !!mx * 3 * bytesperpixel;
+ mc[!!mx][!!my](dst_v, dst_stride, ref_v, 160, bh, mx, my);
+ } else {
+ mc[!!mx][!!my](dst_u, dst_stride, ref_u, src_stride_u, bh, mx, my);
+ mc[!!mx][!!my](dst_v, dst_stride, ref_v, src_stride_v, bh, mx, my);
+ }
+}
+
+#define mc_luma_dir(s, mc, dst, dst_ls, src, src_ls, tref, row, col, mv, \
+ px, py, pw, ph, bw, bh, w, h, i) \
+ mc_luma_unscaled(s, s->dsp.mc, dst, dst_ls, src, src_ls, tref, row, col, \
+ mv, bw, bh, w, h, bytesperpixel)
+#define mc_chroma_dir(s, mc, dstu, dstv, dst_ls, srcu, srcu_ls, srcv, srcv_ls, tref, \
+ row, col, mv, px, py, pw, ph, bw, bh, w, h, i) \
+ mc_chroma_unscaled(s, s->dsp.mc, dstu, dstv, dst_ls, srcu, srcu_ls, srcv, srcv_ls, tref, \
+ row, col, mv, bw, bh, w, h, bytesperpixel)
+#define SCALED 0
+#define FN(x) x##_8bpp
+#define BYTES_PER_PIXEL 1
+#include "vp9_mc_template.c"
+#undef FN
+#undef BYTES_PER_PIXEL
+#define FN(x) x##_16bpp
+#define BYTES_PER_PIXEL 2
+#include "vp9_mc_template.c"
+#undef mc_luma_dir_dir
+#undef mc_chroma_dir_dir
+#undef FN
+#undef BYTES_PER_PIXEL
+#undef SCALED
+
+static av_always_inline void inter_recon(AVCodecContext *ctx, int bytesperpixel)
+{
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ int row = s->row, col = s->col;
+
+ if (s->mvscale[b->ref[0]][0] || (b->comp && s->mvscale[b->ref[1]][0])) {
+ if (bytesperpixel == 1) {
+ inter_pred_scaled_8bpp(ctx);
+ } else {
+ inter_pred_scaled_16bpp(ctx);
+ }
+ } else {
+ if (bytesperpixel == 1) {
+ inter_pred_8bpp(ctx);
+ } else {
+ inter_pred_16bpp(ctx);
+ }
+ }
+ if (!b->skip) {
+ /* mostly copied intra_recon() */
+
+ int w4 = bwh_tab[1][b->bs][0] << 1, step1d = 1 << b->tx, n;
+ int h4 = bwh_tab[1][b->bs][1] << 1, x, y, step = 1 << (b->tx * 2);
+ int end_x = FFMIN(2 * (s->cols - col), w4);
+ int end_y = FFMIN(2 * (s->rows - row), h4);
+ int tx = 4 * s->lossless + b->tx, uvtx = b->uvtx + 4 * s->lossless;
+ int uvstep1d = 1 << b->uvtx, p;
+ uint8_t *dst = s->dst[0];
+
+ // y itxfm add
+ for (n = 0, y = 0; y < end_y; y += step1d) {
+ uint8_t *ptr = dst;
+ for (x = 0; x < end_x; x += step1d,
+ ptr += 4 * step1d * bytesperpixel, n += step) {
+ int eob = b->tx > TX_8X8 ? AV_RN16A(&s->eob[n]) : s->eob[n];
+
+ if (eob)
+ s->dsp.itxfm_add[tx][DCT_DCT](ptr, s->y_stride,
+ s->block + 16 * n * bytesperpixel, eob);
+ }
+ dst += 4 * s->y_stride * step1d;
+ }
+
+ // uv itxfm add
+ end_x >>= s->ss_h;
+ end_y >>= s->ss_v;
+ step = 1 << (b->uvtx * 2);
+ for (p = 0; p < 2; p++) {
+ dst = s->dst[p + 1];
+ for (n = 0, y = 0; y < end_y; y += uvstep1d) {
+ uint8_t *ptr = dst;
+ for (x = 0; x < end_x; x += uvstep1d,
+ ptr += 4 * uvstep1d * bytesperpixel, n += step) {
+ int eob = b->uvtx > TX_8X8 ? AV_RN16A(&s->uveob[p][n]) : s->uveob[p][n];
+
+ if (eob)
+ s->dsp.itxfm_add[uvtx][DCT_DCT](ptr, s->uv_stride,
+ s->uvblock[p] + 16 * n * bytesperpixel, eob);
+ }
+ dst += 4 * uvstep1d * s->uv_stride;
+ }
+ }
+ }
+}
+
+static void inter_recon_8bpp(AVCodecContext *ctx)
+{
+ inter_recon(ctx, 1);
+}
+
+static void inter_recon_16bpp(AVCodecContext *ctx)
+{
+ inter_recon(ctx, 2);
+}
+
+static av_always_inline void mask_edges(uint8_t (*mask)[8][4], int ss_h, int ss_v,
+ int row_and_7, int col_and_7,
+ int w, int h, int col_end, int row_end,
+ enum TxfmMode tx, int skip_inter)
+{
+ static const unsigned wide_filter_col_mask[2] = { 0x11, 0x01 };
+ static const unsigned wide_filter_row_mask[2] = { 0x03, 0x07 };
+
+ // FIXME I'm pretty sure all loops can be replaced by a single LUT if
+ // we make VP9Filter.mask uint64_t (i.e. row/col all single variable)
+ // and make the LUT 5-indexed (bl, bp, is_uv, tx and row/col), and then
+ // use row_and_7/col_and_7 as shifts (1*col_and_7+8*row_and_7)
+
+ // the intended behaviour of the vp9 loopfilter is to work on 8-pixel
+ // edges. This means that for UV, we work on two subsampled blocks at
+ // a time, and we only use the topleft block's mode information to set
+ // things like block strength. Thus, for any block size smaller than
+ // 16x16, ignore the odd portion of the block.
+ if (tx == TX_4X4 && (ss_v | ss_h)) {
+ if (h == ss_v) {
+ if (row_and_7 & 1)
+ return;
+ if (!row_end)
+ h += 1;
+ }
+ if (w == ss_h) {
+ if (col_and_7 & 1)
+ return;
+ if (!col_end)
+ w += 1;
+ }
+ }
+
+ if (tx == TX_4X4 && !skip_inter) {
+ int t = 1 << col_and_7, m_col = (t << w) - t, y;
+ // on 32-px edges, use the 8-px wide loopfilter; else, use 4-px wide
+ int m_row_8 = m_col & wide_filter_col_mask[ss_h], m_row_4 = m_col - m_row_8;
+
+ for (y = row_and_7; y < h + row_and_7; y++) {
+ int col_mask_id = 2 - !(y & wide_filter_row_mask[ss_v]);
+
+ mask[0][y][1] |= m_row_8;
+ mask[0][y][2] |= m_row_4;
+ // for odd lines, if the odd col is not being filtered,
+ // skip odd row also:
+ // .---. <-- a
+ // | |
+ // |___| <-- b
+ // ^ ^
+ // c d
+ //
+ // if a/c are even row/col and b/d are odd, and d is skipped,
+ // e.g. right edge of size-66x66.webm, then skip b also (bug)
+ if ((ss_h & ss_v) && (col_end & 1) && (y & 1)) {
+ mask[1][y][col_mask_id] |= (t << (w - 1)) - t;
+ } else {
+ mask[1][y][col_mask_id] |= m_col;
+ }
+ if (!ss_h)
+ mask[0][y][3] |= m_col;
+ if (!ss_v) {
+ if (ss_h && (col_end & 1))
+ mask[1][y][3] |= (t << (w - 1)) - t;
+ else
+ mask[1][y][3] |= m_col;
+ }
+ }
+ } else {
+ int y, t = 1 << col_and_7, m_col = (t << w) - t;
+
+ if (!skip_inter) {
+ int mask_id = (tx == TX_8X8);
+ static const unsigned masks[4] = { 0xff, 0x55, 0x11, 0x01 };
+ int l2 = tx + ss_h - 1, step1d;
+ int m_row = m_col & masks[l2];
+
+ // at odd UV col/row edges tx16/tx32 loopfilter edges, force
+ // 8wd loopfilter to prevent going off the visible edge.
+ if (ss_h && tx > TX_8X8 && (w ^ (w - 1)) == 1) {
+ int m_row_16 = ((t << (w - 1)) - t) & masks[l2];
+ int m_row_8 = m_row - m_row_16;
+
+ for (y = row_and_7; y < h + row_and_7; y++) {
+ mask[0][y][0] |= m_row_16;
+ mask[0][y][1] |= m_row_8;
+ }
+ } else {
+ for (y = row_and_7; y < h + row_and_7; y++)
+ mask[0][y][mask_id] |= m_row;
+ }
+
+ l2 = tx + ss_v - 1;
+ step1d = 1 << l2;
+ if (ss_v && tx > TX_8X8 && (h ^ (h - 1)) == 1) {
+ for (y = row_and_7; y < h + row_and_7 - 1; y += step1d)
+ mask[1][y][0] |= m_col;
+ if (y - row_and_7 == h - 1)
+ mask[1][y][1] |= m_col;
+ } else {
+ for (y = row_and_7; y < h + row_and_7; y += step1d)
+ mask[1][y][mask_id] |= m_col;
+ }
+ } else if (tx != TX_4X4) {
+ int mask_id;
+
+ mask_id = (tx == TX_8X8) || (h == ss_v);
+ mask[1][row_and_7][mask_id] |= m_col;
+ mask_id = (tx == TX_8X8) || (w == ss_h);
+ for (y = row_and_7; y < h + row_and_7; y++)
+ mask[0][y][mask_id] |= t;
+ } else {
+ int t8 = t & wide_filter_col_mask[ss_h], t4 = t - t8;
+
+ for (y = row_and_7; y < h + row_and_7; y++) {
+ mask[0][y][2] |= t4;
+ mask[0][y][1] |= t8;
+ }
+ mask[1][row_and_7][2 - !(row_and_7 & wide_filter_row_mask[ss_v])] |= m_col;
+ }
+ }
+}
+
+static void decode_b(AVCodecContext *ctx, int row, int col,
+ struct VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff,
+ enum BlockLevel bl, enum BlockPartition bp)
+{
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ enum BlockSize bs = bl * 3 + bp;
+ int bytesperpixel = s->bytesperpixel;
+ int w4 = bwh_tab[1][bs][0], h4 = bwh_tab[1][bs][1], lvl;
+ int emu[2];
+ AVFrame *f = s->frames[CUR_FRAME].tf.f;
+
+ s->row = row;
+ s->row7 = row & 7;
+ s->col = col;
+ s->col7 = col & 7;
+ s->min_mv.x = -(128 + col * 64);
+ s->min_mv.y = -(128 + row * 64);
+ s->max_mv.x = 128 + (s->cols - col - w4) * 64;
+ s->max_mv.y = 128 + (s->rows - row - h4) * 64;
+ if (s->pass < 2) {
+ b->bs = bs;
+ b->bl = bl;
+ b->bp = bp;
+ decode_mode(ctx);
+ b->uvtx = b->tx - ((s->ss_h && w4 * 2 == (1 << b->tx)) ||
+ (s->ss_v && h4 * 2 == (1 << b->tx)));
+
+ if (!b->skip) {
+ int has_coeffs;
+
+ if (bytesperpixel == 1) {
+ has_coeffs = decode_coeffs_8bpp(ctx);
+ } else {
+ has_coeffs = decode_coeffs_16bpp(ctx);
+ }
+ if (!has_coeffs && b->bs <= BS_8x8 && !b->intra) {
+ b->skip = 1;
+ memset(&s->above_skip_ctx[col], 1, w4);
+ memset(&s->left_skip_ctx[s->row7], 1, h4);
+ }
+ } else {
+ int row7 = s->row7;
+
+#define SPLAT_ZERO_CTX(v, n) \
+ switch (n) { \
+ case 1: v = 0; break; \
+ case 2: AV_ZERO16(&v); break; \
+ case 4: AV_ZERO32(&v); break; \
+ case 8: AV_ZERO64(&v); break; \
+ case 16: AV_ZERO128(&v); break; \
+ }
+#define SPLAT_ZERO_YUV(dir, var, off, n, dir2) \
+ do { \
+ SPLAT_ZERO_CTX(s->dir##_y_##var[off * 2], n * 2); \
+ if (s->ss_##dir2) { \
+ SPLAT_ZERO_CTX(s->dir##_uv_##var[0][off], n); \
+ SPLAT_ZERO_CTX(s->dir##_uv_##var[1][off], n); \
+ } else { \
+ SPLAT_ZERO_CTX(s->dir##_uv_##var[0][off * 2], n * 2); \
+ SPLAT_ZERO_CTX(s->dir##_uv_##var[1][off * 2], n * 2); \
+ } \
+ } while (0)
+
+ switch (w4) {
+ case 1: SPLAT_ZERO_YUV(above, nnz_ctx, col, 1, h); break;
+ case 2: SPLAT_ZERO_YUV(above, nnz_ctx, col, 2, h); break;
+ case 4: SPLAT_ZERO_YUV(above, nnz_ctx, col, 4, h); break;
+ case 8: SPLAT_ZERO_YUV(above, nnz_ctx, col, 8, h); break;
+ }
+ switch (h4) {
+ case 1: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 1, v); break;
+ case 2: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 2, v); break;
+ case 4: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 4, v); break;
+ case 8: SPLAT_ZERO_YUV(left, nnz_ctx, row7, 8, v); break;
+ }
+ }
+ if (s->pass == 1) {
+ s->b++;
+ s->block += w4 * h4 * 64 * bytesperpixel;
+ s->uvblock[0] += w4 * h4 * 64 * bytesperpixel >> (s->ss_h + s->ss_v);
+ s->uvblock[1] += w4 * h4 * 64 * bytesperpixel >> (s->ss_h + s->ss_v);
+ s->eob += 4 * w4 * h4;
+ s->uveob[0] += 4 * w4 * h4 >> (s->ss_h + s->ss_v);
+ s->uveob[1] += 4 * w4 * h4 >> (s->ss_h + s->ss_v);
+
+ return;
+ }
+ }
+
+ // emulated overhangs if the stride of the target buffer can't hold. This
+ // allows to support emu-edge and so on even if we have large block
+ // overhangs
+ emu[0] = (col + w4) * 8 > f->linesize[0] ||
+ (row + h4) > s->rows;
+ emu[1] = (col + w4) * 4 > f->linesize[1] ||
+ (row + h4) > s->rows;
+ if (emu[0]) {
+ s->dst[0] = s->tmp_y;
+ s->y_stride = 128;
+ } else {
+ s->dst[0] = f->data[0] + yoff;
+ s->y_stride = f->linesize[0];
+ }
+ if (emu[1]) {
+ s->dst[1] = s->tmp_uv[0];
+ s->dst[2] = s->tmp_uv[1];
+ s->uv_stride = 128;
+ } else {
+ s->dst[1] = f->data[1] + uvoff;
+ s->dst[2] = f->data[2] + uvoff;
+ s->uv_stride = f->linesize[1];
+ }
+ if (b->intra) {
+ if (s->bpp > 8) {
+ intra_recon_16bpp(ctx, yoff, uvoff);
+ } else {
+ intra_recon_8bpp(ctx, yoff, uvoff);
+ }
+ } else {
+ if (s->bpp > 8) {
+ inter_recon_16bpp(ctx);
+ } else {
+ inter_recon_8bpp(ctx);
+ }
+ }
+ if (emu[0]) {
+ int w = FFMIN(s->cols - col, w4) * 8, h = FFMIN(s->rows - row, h4) * 8, n, o = 0;
+
+ for (n = 0; o < w; n++) {
+ int bw = 64 >> n;
+
+ av_assert2(n <= 4);
+ if (w & bw) {
+ s->dsp.mc[n][0][0][0][0](f->data[0] + yoff + o, f->linesize[0],
+ s->tmp_y + o, 128, h, 0, 0);
+ o += bw * bytesperpixel;
+ }
+ }
+ }
+ if (emu[1]) {
+ int w = FFMIN(s->cols - col, w4) * 8 >> s->ss_h;
+ int h = FFMIN(s->rows - row, h4) * 8 >> s->ss_v, n, o = 0;
+
+ for (n = s->ss_h; o < w; n++) {
+ int bw = 64 >> n;
+
+ av_assert2(n <= 4);
+ if (w & bw) {
+ s->dsp.mc[n][0][0][0][0](f->data[1] + uvoff + o, f->linesize[1],
+ s->tmp_uv[0] + o, 128, h, 0, 0);
+ s->dsp.mc[n][0][0][0][0](f->data[2] + uvoff + o, f->linesize[2],
+ s->tmp_uv[1] + o, 128, h, 0, 0);
+ o += bw * bytesperpixel;
+ }
+ }
+ }
+
+ // pick filter level and find edges to apply filter to
+ if (s->filter.level &&
+ (lvl = s->segmentation.feat[b->seg_id].lflvl[b->intra ? 0 : b->ref[0] + 1]
+ [b->mode[3] != ZEROMV]) > 0) {
+ int x_end = FFMIN(s->cols - col, w4), y_end = FFMIN(s->rows - row, h4);
+ int skip_inter = !b->intra && b->skip, col7 = s->col7, row7 = s->row7;
+
+ setctx_2d(&lflvl->level[row7 * 8 + col7], w4, h4, 8, lvl);
+ mask_edges(lflvl->mask[0], 0, 0, row7, col7, x_end, y_end, 0, 0, b->tx, skip_inter);
+ if (s->ss_h || s->ss_v)
+ mask_edges(lflvl->mask[1], s->ss_h, s->ss_v, row7, col7, x_end, y_end,
+ s->cols & 1 && col + w4 >= s->cols ? s->cols & 7 : 0,
+ s->rows & 1 && row + h4 >= s->rows ? s->rows & 7 : 0,
+ b->uvtx, skip_inter);
+
+ if (!s->filter.lim_lut[lvl]) {
+ int sharp = s->filter.sharpness;
+ int limit = lvl;
+
+ if (sharp > 0) {
+ limit >>= (sharp + 3) >> 2;
+ limit = FFMIN(limit, 9 - sharp);
+ }
+ limit = FFMAX(limit, 1);
+
+ s->filter.lim_lut[lvl] = limit;
+ s->filter.mblim_lut[lvl] = 2 * (lvl + 2) + limit;
+ }
+ }
+
+ if (s->pass == 2) {
+ s->b++;
+ s->block += w4 * h4 * 64 * bytesperpixel;
+ s->uvblock[0] += w4 * h4 * 64 * bytesperpixel >> (s->ss_v + s->ss_h);
+ s->uvblock[1] += w4 * h4 * 64 * bytesperpixel >> (s->ss_v + s->ss_h);
+ s->eob += 4 * w4 * h4;
+ s->uveob[0] += 4 * w4 * h4 >> (s->ss_v + s->ss_h);
+ s->uveob[1] += 4 * w4 * h4 >> (s->ss_v + s->ss_h);
+ }
+}
+
+static void decode_sb(AVCodecContext *ctx, int row, int col, struct VP9Filter *lflvl,
+ ptrdiff_t yoff, ptrdiff_t uvoff, enum BlockLevel bl)
+{
+ VP9Context *s = ctx->priv_data;
+ int c = ((s->above_partition_ctx[col] >> (3 - bl)) & 1) |
(((s->left_partition_ctx[row & 0x7] >> (3 - bl)) & 1) << 1);
- int ret;
- const uint8_t *p = s->keyframe ? ff_vp9_default_kf_partition_probs[bl][c]
- : s->prob.p.partition[bl][c];
+ const uint8_t *p = s->keyframe || s->intraonly ? vp9_default_kf_partition_probs[bl][c] :
+ s->prob.p.partition[bl][c];
enum BlockPartition bp;
ptrdiff_t hbs = 4 >> bl;
+ AVFrame *f = s->frames[CUR_FRAME].tf.f;
+ ptrdiff_t y_stride = f->linesize[0], uv_stride = f->linesize[1];
+ int bytesperpixel = s->bytesperpixel;
if (bl == BL_8X8) {
- bp = vp8_rac_get_tree(&s->c, ff_vp9_partition_tree, p);
- ret = ff_vp9_decode_block(avctx, row, col, lflvl, yoff, uvoff, bl, bp);
- } else if (col + hbs < s->cols) {
- if (row + hbs < s->rows) {
- bp = vp8_rac_get_tree(&s->c, ff_vp9_partition_tree, p);
+ bp = vp8_rac_get_tree(&s->c, vp9_partition_tree, p);
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
+ } else if (col + hbs < s->cols) { // FIXME why not <=?
+ if (row + hbs < s->rows) { // FIXME why not <=?
+ bp = vp8_rac_get_tree(&s->c, vp9_partition_tree, p);
switch (bp) {
case PARTITION_NONE:
- ret = ff_vp9_decode_block(avctx, row, col, lflvl, yoff, uvoff,
- bl, bp);
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
break;
case PARTITION_H:
- ret = ff_vp9_decode_block(avctx, row, col, lflvl, yoff, uvoff,
- bl, bp);
- if (!ret) {
- yoff += hbs * 8 * s->cur_frame->linesize[0];
- uvoff += hbs * 4 * s->cur_frame->linesize[1];
- ret = ff_vp9_decode_block(avctx, row + hbs, col, lflvl,
- yoff, uvoff, bl, bp);
- }
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 8 * uv_stride >> s->ss_v;
+ decode_b(ctx, row + hbs, col, lflvl, yoff, uvoff, bl, bp);
break;
case PARTITION_V:
- ret = ff_vp9_decode_block(avctx, row, col, lflvl, yoff, uvoff,
- bl, bp);
- if (!ret) {
- yoff += hbs * 8;
- uvoff += hbs * 4;
- ret = ff_vp9_decode_block(avctx, row, col + hbs, lflvl,
- yoff, uvoff, bl, bp);
- }
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
+ yoff += hbs * 8 * bytesperpixel;
+ uvoff += hbs * 8 * bytesperpixel >> s->ss_h;
+ decode_b(ctx, row, col + hbs, lflvl, yoff, uvoff, bl, bp);
break;
case PARTITION_SPLIT:
- ret = decode_subblock(avctx, row, col, lflvl,
- yoff, uvoff, bl + 1);
- if (!ret) {
- ret = decode_subblock(avctx, row, col + hbs, lflvl,
- yoff + 8 * hbs, uvoff + 4 * hbs,
- bl + 1);
- if (!ret) {
- yoff += hbs * 8 * s->cur_frame->linesize[0];
- uvoff += hbs * 4 * s->cur_frame->linesize[1];
- ret = decode_subblock(avctx, row + hbs, col, lflvl,
- yoff, uvoff, bl + 1);
- if (!ret) {
- ret = decode_subblock(avctx, row + hbs, col + hbs,
- lflvl, yoff + 8 * hbs,
- uvoff + 4 * hbs, bl + 1);
- }
- }
- }
+ decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1);
+ decode_sb(ctx, row, col + hbs, lflvl,
+ yoff + 8 * hbs * bytesperpixel,
+ uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1);
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 8 * uv_stride >> s->ss_v;
+ decode_sb(ctx, row + hbs, col, lflvl, yoff, uvoff, bl + 1);
+ decode_sb(ctx, row + hbs, col + hbs, lflvl,
+ yoff + 8 * hbs * bytesperpixel,
+ uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1);
break;
default:
- av_log(avctx, AV_LOG_ERROR, "Unexpected partition %d.", bp);
- return AVERROR_INVALIDDATA;
+ av_assert0(0);
}
} else if (vp56_rac_get_prob_branchy(&s->c, p[1])) {
- bp = PARTITION_SPLIT;
- ret = decode_subblock(avctx, row, col, lflvl, yoff, uvoff, bl + 1);
- if (!ret)
- ret = decode_subblock(avctx, row, col + hbs, lflvl,
- yoff + 8 * hbs, uvoff + 4 * hbs, bl + 1);
+ bp = PARTITION_SPLIT;
+ decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1);
+ decode_sb(ctx, row, col + hbs, lflvl,
+ yoff + 8 * hbs * bytesperpixel,
+ uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1);
} else {
- bp = PARTITION_H;
- ret = ff_vp9_decode_block(avctx, row, col, lflvl, yoff, uvoff,
- bl, bp);
+ bp = PARTITION_H;
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
}
- } else if (row + hbs < s->rows) {
+ } else if (row + hbs < s->rows) { // FIXME why not <=?
if (vp56_rac_get_prob_branchy(&s->c, p[2])) {
- bp = PARTITION_SPLIT;
- ret = decode_subblock(avctx, row, col, lflvl, yoff, uvoff, bl + 1);
- if (!ret) {
- yoff += hbs * 8 * s->cur_frame->linesize[0];
- uvoff += hbs * 4 * s->cur_frame->linesize[1];
- ret = decode_subblock(avctx, row + hbs, col, lflvl,
- yoff, uvoff, bl + 1);
- }
+ bp = PARTITION_SPLIT;
+ decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1);
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 8 * uv_stride >> s->ss_v;
+ decode_sb(ctx, row + hbs, col, lflvl, yoff, uvoff, bl + 1);
} else {
- bp = PARTITION_V;
- ret = ff_vp9_decode_block(avctx, row, col, lflvl, yoff, uvoff,
- bl, bp);
+ bp = PARTITION_V;
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, bl, bp);
}
} else {
- bp = PARTITION_SPLIT;
- ret = decode_subblock(avctx, row, col, lflvl, yoff, uvoff, bl + 1);
+ bp = PARTITION_SPLIT;
+ decode_sb(ctx, row, col, lflvl, yoff, uvoff, bl + 1);
}
s->counts.partition[bl][c][bp]++;
+}
+
+static void decode_sb_mem(AVCodecContext *ctx, int row, int col, struct VP9Filter *lflvl,
+ ptrdiff_t yoff, ptrdiff_t uvoff, enum BlockLevel bl)
+{
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ ptrdiff_t hbs = 4 >> bl;
+ AVFrame *f = s->frames[CUR_FRAME].tf.f;
+ ptrdiff_t y_stride = f->linesize[0], uv_stride = f->linesize[1];
+ int bytesperpixel = s->bytesperpixel;
- return ret;
+ if (bl == BL_8X8) {
+ av_assert2(b->bl == BL_8X8);
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, b->bl, b->bp);
+ } else if (s->b->bl == bl) {
+ decode_b(ctx, row, col, lflvl, yoff, uvoff, b->bl, b->bp);
+ if (b->bp == PARTITION_H && row + hbs < s->rows) {
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 8 * uv_stride >> s->ss_v;
+ decode_b(ctx, row + hbs, col, lflvl, yoff, uvoff, b->bl, b->bp);
+ } else if (b->bp == PARTITION_V && col + hbs < s->cols) {
+ yoff += hbs * 8 * bytesperpixel;
+ uvoff += hbs * 8 * bytesperpixel >> s->ss_h;
+ decode_b(ctx, row, col + hbs, lflvl, yoff, uvoff, b->bl, b->bp);
+ }
+ } else {
+ decode_sb_mem(ctx, row, col, lflvl, yoff, uvoff, bl + 1);
+ if (col + hbs < s->cols) { // FIXME why not <=?
+ if (row + hbs < s->rows) {
+ decode_sb_mem(ctx, row, col + hbs, lflvl, yoff + 8 * hbs * bytesperpixel,
+ uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1);
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 8 * uv_stride >> s->ss_v;
+ decode_sb_mem(ctx, row + hbs, col, lflvl, yoff, uvoff, bl + 1);
+ decode_sb_mem(ctx, row + hbs, col + hbs, lflvl,
+ yoff + 8 * hbs * bytesperpixel,
+ uvoff + (8 * hbs * bytesperpixel >> s->ss_h), bl + 1);
+ } else {
+ yoff += hbs * 8 * bytesperpixel;
+ uvoff += hbs * 8 * bytesperpixel >> s->ss_h;
+ decode_sb_mem(ctx, row, col + hbs, lflvl, yoff, uvoff, bl + 1);
+ }
+ } else if (row + hbs < s->rows) {
+ yoff += hbs * 8 * y_stride;
+ uvoff += hbs * 8 * uv_stride >> s->ss_v;
+ decode_sb_mem(ctx, row + hbs, col, lflvl, yoff, uvoff, bl + 1);
+ }
+ }
}
-static void loopfilter_subblock(AVCodecContext *avctx, VP9Filter *lflvl,
- int row, int col,
- ptrdiff_t yoff, ptrdiff_t uvoff)
+static av_always_inline void filter_plane_cols(VP9Context *s, int col, int ss_h, int ss_v,
+ uint8_t *lvl, uint8_t (*mask)[4],
+ uint8_t *dst, ptrdiff_t ls)
{
- VP9Context *s = avctx->priv_data;
- uint8_t *dst = s->cur_frame->data[0] + yoff, *lvl = lflvl->level;
- ptrdiff_t ls_y = s->cur_frame->linesize[0], ls_uv = s->cur_frame->linesize[1];
- int y, x, p;
-
- /* FIXME: In how far can we interleave the v/h loopfilter calls? E.g.
- * if you think of them as acting on a 8x8 block max, we can interleave
- * each v/h within the single x loop, but that only works if we work on
- * 8 pixel blocks, and we won't always do that (we want at least 16px
- * to use SSE2 optimizations, perhaps 32 for AVX2). */
-
- // filter edges between columns, Y plane (e.g. block1 | block2)
- for (y = 0; y < 8; y += 2, dst += 16 * ls_y, lvl += 16) {
- uint8_t *ptr = dst, *l = lvl, *hmask1 = lflvl->mask[0][0][y];
- uint8_t *hmask2 = lflvl->mask[0][0][y + 1];
+ int y, x, bytesperpixel = s->bytesperpixel;
+
+ // filter edges between columns (e.g. block1 | block2)
+ for (y = 0; y < 8; y += 2 << ss_v, dst += 16 * ls, lvl += 16 << ss_v) {
+ uint8_t *ptr = dst, *l = lvl, *hmask1 = mask[y], *hmask2 = mask[y + 1 + ss_v];
unsigned hm1 = hmask1[0] | hmask1[1] | hmask1[2], hm13 = hmask1[3];
unsigned hm2 = hmask2[1] | hmask2[2], hm23 = hmask2[3];
- unsigned hm = hm1 | hm2 | hm13 | hm23;
+ unsigned hm = hm1 | hm2 | hm13 | hm23;
- for (x = 1; hm & ~(x - 1); x <<= 1, ptr += 8, l++) {
- if (hm1 & x) {
- int L = *l, H = L >> 4;
- int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+ for (x = 1; hm & ~(x - 1); x <<= 1, ptr += 8 * bytesperpixel >> ss_h) {
+ if (col || x > 1) {
+ if (hm1 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- if (col || x > 1) {
if (hmask1[0] & x) {
if (hmask2[0] & x) {
- av_assert2(l[8] == L);
- s->dsp.loop_filter_16[0](ptr, ls_y, E, I, H);
+ av_assert2(l[8 << ss_v] == L);
+ s->dsp.loop_filter_16[0](ptr, ls, E, I, H);
} else {
- s->dsp.loop_filter_8[2][0](ptr, ls_y, E, I, H);
+ s->dsp.loop_filter_8[2][0](ptr, ls, E, I, H);
}
} else if (hm2 & x) {
- L = l[8];
+ L = l[8 << ss_v];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
s->dsp.loop_filter_mix2[!!(hmask1[1] & x)]
[!!(hmask2[1] & x)]
- [0](ptr, ls_y, E, I, H);
+ [0](ptr, ls, E, I, H);
} else {
s->dsp.loop_filter_8[!!(hmask1[1] & x)]
- [0](ptr, ls_y, E, I, H);
+ [0](ptr, ls, E, I, H);
}
- }
- } else if (hm2 & x) {
- int L = l[8], H = L >> 4;
- int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+ } else if (hm2 & x) {
+ int L = l[8 << ss_v], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- if (col || x > 1) {
s->dsp.loop_filter_8[!!(hmask2[1] & x)]
- [0](ptr + 8 * ls_y, ls_y, E, I, H);
+ [0](ptr + 8 * ls, ls, E, I, H);
}
}
- if (hm13 & x) {
- int L = *l, H = L >> 4;
- int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+ if (ss_h) {
+ if (x & 0xAA)
+ l += 2;
+ } else {
+ if (hm13 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- if (hm23 & x) {
- L = l[8];
- H |= (L >> 4) << 8;
- E |= s->filter.mblim_lut[L] << 8;
- I |= s->filter.lim_lut[L] << 8;
- s->dsp.loop_filter_mix2[0][0][0](ptr + 4, ls_y, E, I, H);
- } else {
- s->dsp.loop_filter_8[0][0](ptr + 4, ls_y, E, I, H);
- }
- } else if (hm23 & x) {
- int L = l[8], H = L >> 4;
- int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+ if (hm23 & x) {
+ L = l[8 << ss_v];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[0][0][0](ptr + 4 * bytesperpixel, ls, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[0][0](ptr + 4 * bytesperpixel, ls, E, I, H);
+ }
+ } else if (hm23 & x) {
+ int L = l[8 << ss_v], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- s->dsp.loop_filter_8[0][0](ptr + 8 * ls_y + 4, ls_y, E, I, H);
+ s->dsp.loop_filter_8[0][0](ptr + 8 * ls + 4 * bytesperpixel, ls, E, I, H);
+ }
+ l++;
}
}
}
+}
+
+static av_always_inline void filter_plane_rows(VP9Context *s, int row, int ss_h, int ss_v,
+ uint8_t *lvl, uint8_t (*mask)[4],
+ uint8_t *dst, ptrdiff_t ls)
+{
+ int y, x, bytesperpixel = s->bytesperpixel;
- // block1
- // filter edges between rows, Y plane (e.g. ------)
- // block2
- dst = s->cur_frame->data[0] + yoff;
- lvl = lflvl->level;
- for (y = 0; y < 8; y++, dst += 8 * ls_y, lvl += 8) {
- uint8_t *ptr = dst, *l = lvl, *vmask = lflvl->mask[0][1][y];
+ // block1
+ // filter edges between rows (e.g. ------)
+ // block2
+ for (y = 0; y < 8; y++, dst += 8 * ls >> ss_v) {
+ uint8_t *ptr = dst, *l = lvl, *vmask = mask[y];
unsigned vm = vmask[0] | vmask[1] | vmask[2], vm3 = vmask[3];
- for (x = 1; vm & ~(x - 1); x <<= 2, ptr += 16, l += 2) {
+ for (x = 1; vm & ~(x - 1); x <<= (2 << ss_h), ptr += 16 * bytesperpixel, l += 2 << ss_h) {
if (row || y) {
if (vm & x) {
int L = *l, H = L >> 4;
int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
if (vmask[0] & x) {
- if (vmask[0] & (x << 1)) {
- av_assert2(l[1] == L);
- s->dsp.loop_filter_16[1](ptr, ls_y, E, I, H);
+ if (vmask[0] & (x << (1 + ss_h))) {
+ av_assert2(l[1 + ss_h] == L);
+ s->dsp.loop_filter_16[1](ptr, ls, E, I, H);
} else {
- s->dsp.loop_filter_8[2][1](ptr, ls_y, E, I, H);
+ s->dsp.loop_filter_8[2][1](ptr, ls, E, I, H);
}
- } else if (vm & (x << 1)) {
- L = l[1];
+ } else if (vm & (x << (1 + ss_h))) {
+ L = l[1 + ss_h];
H |= (L >> 4) << 8;
E |= s->filter.mblim_lut[L] << 8;
I |= s->filter.lim_lut[L] << 8;
s->dsp.loop_filter_mix2[!!(vmask[1] & x)]
- [!!(vmask[1] & (x << 1))]
- [1](ptr, ls_y, E, I, H);
+ [!!(vmask[1] & (x << (1 + ss_h)))]
+ [1](ptr, ls, E, I, H);
} else {
s->dsp.loop_filter_8[!!(vmask[1] & x)]
- [1](ptr, ls_y, E, I, H);
+ [1](ptr, ls, E, I, H);
}
- } else if (vm & (x << 1)) {
- int L = l[1], H = L >> 4;
+ } else if (vm & (x << (1 + ss_h))) {
+ int L = l[1 + ss_h], H = L >> 4;
int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- s->dsp.loop_filter_8[!!(vmask[1] & (x << 1))]
- [1](ptr + 8, ls_y, E, I, H);
+ s->dsp.loop_filter_8[!!(vmask[1] & (x << (1 + ss_h)))]
+ [1](ptr + 8 * bytesperpixel, ls, E, I, H);
}
}
- if (vm3 & x) {
- int L = *l, H = L >> 4;
- int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+ if (!ss_v) {
+ if (vm3 & x) {
+ int L = *l, H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- if (vm3 & (x << 1)) {
- L = l[1];
- H |= (L >> 4) << 8;
- E |= s->filter.mblim_lut[L] << 8;
- I |= s->filter.lim_lut[L] << 8;
- s->dsp.loop_filter_mix2[0][0][1](ptr + ls_y * 4, ls_y, E, I, H);
- } else {
- s->dsp.loop_filter_8[0][1](ptr + ls_y * 4, ls_y, E, I, H);
- }
- } else if (vm3 & (x << 1)) {
- int L = l[1], H = L >> 4;
- int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
+ if (vm3 & (x << (1 + ss_h))) {
+ L = l[1 + ss_h];
+ H |= (L >> 4) << 8;
+ E |= s->filter.mblim_lut[L] << 8;
+ I |= s->filter.lim_lut[L] << 8;
+ s->dsp.loop_filter_mix2[0][0][1](ptr + ls * 4, ls, E, I, H);
+ } else {
+ s->dsp.loop_filter_8[0][1](ptr + ls * 4, ls, E, I, H);
+ }
+ } else if (vm3 & (x << (1 + ss_h))) {
+ int L = l[1 + ss_h], H = L >> 4;
+ int E = s->filter.mblim_lut[L], I = s->filter.lim_lut[L];
- s->dsp.loop_filter_8[0][1](ptr + ls_y * 4 + 8, ls_y, E, I, H);
+ s->dsp.loop_filter_8[0][1](ptr + ls * 4 + 8 * bytesperpixel, ls, E, I, H);
+ }
}
}
+ if (ss_v) {
+ if (y & 1)
+ lvl += 16;
+ } else {
+ lvl += 8;
+ }
}
+}
- // same principle but for U/V planes
- for (p = 0; p < 2; p++) {
- lvl = lflvl->level;
- dst = s->cur_frame->data[1 + p] + uvoff;
- for (y = 0; y < 8; y += 4, dst += 16 * ls_uv, lvl += 32) {
- uint8_t *ptr = dst, *l = lvl, *hmask1 = lflvl->mask[1][0][y];
- uint8_t *hmask2 = lflvl->mask[1][0][y + 2];
- unsigned hm1 = hmask1[0] | hmask1[1] | hmask1[2];
- unsigned hm2 = hmask2[1] | hmask2[2], hm = hm1 | hm2;
-
- for (x = 1; hm & ~(x - 1); x <<= 1, ptr += 4) {
- if (col || x > 1) {
- if (hm1 & x) {
- int L = *l, H = L >> 4;
- int E = s->filter.mblim_lut[L];
- int I = s->filter.lim_lut[L];
-
- if (hmask1[0] & x) {
- if (hmask2[0] & x) {
- av_assert2(l[16] == L);
- s->dsp.loop_filter_16[0](ptr, ls_uv, E, I, H);
- } else {
- s->dsp.loop_filter_8[2][0](ptr, ls_uv, E, I, H);
- }
- } else if (hm2 & x) {
- L = l[16];
- H |= (L >> 4) << 8;
- E |= s->filter.mblim_lut[L] << 8;
- I |= s->filter.lim_lut[L] << 8;
- s->dsp.loop_filter_mix2[!!(hmask1[1] & x)]
- [!!(hmask2[1] & x)]
- [0](ptr, ls_uv, E, I, H);
- } else {
- s->dsp.loop_filter_8[!!(hmask1[1] & x)]
- [0](ptr, ls_uv, E, I, H);
- }
- } else if (hm2 & x) {
- int L = l[16], H = L >> 4;
- int E = s->filter.mblim_lut[L];
- int I = s->filter.lim_lut[L];
-
- s->dsp.loop_filter_8[!!(hmask2[1] & x)]
- [0](ptr + 8 * ls_uv, ls_uv, E, I, H);
- }
- }
- if (x & 0xAA)
- l += 2;
- }
- }
- lvl = lflvl->level;
- dst = s->cur_frame->data[1 + p] + uvoff;
- for (y = 0; y < 8; y++, dst += 4 * ls_uv) {
- uint8_t *ptr = dst, *l = lvl, *vmask = lflvl->mask[1][1][y];
- unsigned vm = vmask[0] | vmask[1] | vmask[2];
+static void loopfilter_sb(AVCodecContext *ctx, struct VP9Filter *lflvl,
+ int row, int col, ptrdiff_t yoff, ptrdiff_t uvoff)
+{
+ VP9Context *s = ctx->priv_data;
+ AVFrame *f = s->frames[CUR_FRAME].tf.f;
+ uint8_t *dst = f->data[0] + yoff;
+ ptrdiff_t ls_y = f->linesize[0], ls_uv = f->linesize[1];
+ uint8_t (*uv_masks)[8][4] = lflvl->mask[s->ss_h | s->ss_v];
+ int p;
- for (x = 1; vm & ~(x - 1); x <<= 4, ptr += 16, l += 4) {
- if (row || y) {
- if (vm & x) {
- int L = *l, H = L >> 4;
- int E = s->filter.mblim_lut[L];
- int I = s->filter.lim_lut[L];
+ // FIXME in how far can we interleave the v/h loopfilter calls? E.g.
+ // if you think of them as acting on a 8x8 block max, we can interleave
+ // each v/h within the single x loop, but that only works if we work on
+ // 8 pixel blocks, and we won't always do that (we want at least 16px
+ // to use SSE2 optimizations, perhaps 32 for AVX2)
- if (vmask[0] & x) {
- if (vmask[0] & (x << 2)) {
- av_assert2(l[2] == L);
- s->dsp.loop_filter_16[1](ptr, ls_uv, E, I, H);
- } else {
- s->dsp.loop_filter_8[2][1](ptr, ls_uv, E, I, H);
- }
- } else if (vm & (x << 2)) {
- L = l[2];
- H |= (L >> 4) << 8;
- E |= s->filter.mblim_lut[L] << 8;
- I |= s->filter.lim_lut[L] << 8;
- s->dsp.loop_filter_mix2[!!(vmask[1] & x)]
- [!!(vmask[1] & (x << 2))]
- [1](ptr, ls_uv, E, I, H);
- } else {
- s->dsp.loop_filter_8[!!(vmask[1] & x)]
- [1](ptr, ls_uv, E, I, H);
- }
- } else if (vm & (x << 2)) {
- int L = l[2], H = L >> 4;
- int E = s->filter.mblim_lut[L];
- int I = s->filter.lim_lut[L];
+ filter_plane_cols(s, col, 0, 0, lflvl->level, lflvl->mask[0][0], dst, ls_y);
+ filter_plane_rows(s, row, 0, 0, lflvl->level, lflvl->mask[0][1], dst, ls_y);
- s->dsp.loop_filter_8[!!(vmask[1] & (x << 2))]
- [1](ptr + 8, ls_uv, E, I, H);
- }
- }
- }
- if (y & 1)
- lvl += 16;
- }
+ for (p = 0; p < 2; p++) {
+ dst = f->data[1 + p] + uvoff;
+ filter_plane_cols(s, col, s->ss_h, s->ss_v, lflvl->level, uv_masks[0], dst, ls_uv);
+ filter_plane_rows(s, row, s->ss_h, s->ss_v, lflvl->level, uv_masks[1], dst, ls_uv);
}
}
static void set_tile_offset(int *start, int *end, int idx, int log2_n, int n)
{
- int sb_start = (idx * n) >> log2_n;
+ int sb_start = ( idx * n) >> log2_n;
int sb_end = ((idx + 1) * n) >> log2_n;
*start = FFMIN(sb_start, n) << 3;
*end = FFMIN(sb_end, n) << 3;
}
-static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
- int *got_frame, const uint8_t *data, int size)
+static av_always_inline void adapt_prob(uint8_t *p, unsigned ct0, unsigned ct1,
+ int max_count, int update_factor)
{
- VP9Context *s = avctx->priv_data;
- int ret, tile_row, tile_col, i, ref = -1, row, col;
- ptrdiff_t yoff = 0, uvoff = 0;
+ unsigned ct = ct0 + ct1, p2, p1;
- ret = decode_frame_header(avctx, data, size, &ref);
- if (ret < 0) {
- return ret;
- } else if (!ret) {
- if (!s->refs[ref]->buf[0]) {
- av_log(avctx, AV_LOG_ERROR,
- "Requested reference %d not available\n", ref);
- return AVERROR_INVALIDDATA;
+ if (!ct)
+ return;
+
+ p1 = *p;
+ p2 = ((ct0 << 8) + (ct >> 1)) / ct;
+ p2 = av_clip(p2, 1, 255);
+ ct = FFMIN(ct, max_count);
+ update_factor = FASTDIV(update_factor * ct, max_count);
+
+ // (p1 * (256 - update_factor) + p2 * update_factor + 128) >> 8
+ *p = p1 + (((p2 - p1) * update_factor + 128) >> 8);
+}
+
+static void adapt_probs(VP9Context *s)
+{
+ int i, j, k, l, m;
+ prob_context *p = &s->prob_ctx[s->framectxid].p;
+ int uf = (s->keyframe || s->intraonly || !s->last_keyframe) ? 112 : 128;
+
+ // coefficients
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 2; k++)
+ for (l = 0; l < 6; l++)
+ for (m = 0; m < 6; m++) {
+ uint8_t *pp = s->prob_ctx[s->framectxid].coef[i][j][k][l][m];
+ unsigned *e = s->counts.eob[i][j][k][l][m];
+ unsigned *c = s->counts.coef[i][j][k][l][m];
+
+ if (l == 0 && m >= 3) // dc only has 3 pt
+ break;
+
+ adapt_prob(&pp[0], e[0], e[1], 24, uf);
+ adapt_prob(&pp[1], c[0], c[1] + c[2], 24, uf);
+ adapt_prob(&pp[2], c[1], c[2], 24, uf);
+ }
+
+ if (s->keyframe || s->intraonly) {
+ memcpy(p->skip, s->prob.p.skip, sizeof(p->skip));
+ memcpy(p->tx32p, s->prob.p.tx32p, sizeof(p->tx32p));
+ memcpy(p->tx16p, s->prob.p.tx16p, sizeof(p->tx16p));
+ memcpy(p->tx8p, s->prob.p.tx8p, sizeof(p->tx8p));
+ return;
+ }
+
+ // skip flag
+ for (i = 0; i < 3; i++)
+ adapt_prob(&p->skip[i], s->counts.skip[i][0], s->counts.skip[i][1], 20, 128);
+
+ // intra/inter flag
+ for (i = 0; i < 4; i++)
+ adapt_prob(&p->intra[i], s->counts.intra[i][0], s->counts.intra[i][1], 20, 128);
+
+ // comppred flag
+ if (s->comppredmode == PRED_SWITCHABLE) {
+ for (i = 0; i < 5; i++)
+ adapt_prob(&p->comp[i], s->counts.comp[i][0], s->counts.comp[i][1], 20, 128);
+ }
+
+ // reference frames
+ if (s->comppredmode != PRED_SINGLEREF) {
+ for (i = 0; i < 5; i++)
+ adapt_prob(&p->comp_ref[i], s->counts.comp_ref[i][0],
+ s->counts.comp_ref[i][1], 20, 128);
+ }
+
+ if (s->comppredmode != PRED_COMPREF) {
+ for (i = 0; i < 5; i++) {
+ uint8_t *pp = p->single_ref[i];
+ unsigned (*c)[2] = s->counts.single_ref[i];
+
+ adapt_prob(&pp[0], c[0][0], c[0][1], 20, 128);
+ adapt_prob(&pp[1], c[1][0], c[1][1], 20, 128);
+ }
+ }
+
+ // block partitioning
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++) {
+ uint8_t *pp = p->partition[i][j];
+ unsigned *c = s->counts.partition[i][j];
+
+ adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
+ adapt_prob(&pp[2], c[2], c[3], 20, 128);
}
- ret = av_frame_ref(frame, s->refs[ref]);
- if (ret < 0)
- return ret;
- *got_frame = 1;
- return 0;
+ // tx size
+ if (s->txfmmode == TX_SWITCHABLE) {
+ for (i = 0; i < 2; i++) {
+ unsigned *c16 = s->counts.tx16p[i], *c32 = s->counts.tx32p[i];
+
+ adapt_prob(&p->tx8p[i], s->counts.tx8p[i][0], s->counts.tx8p[i][1], 20, 128);
+ adapt_prob(&p->tx16p[i][0], c16[0], c16[1] + c16[2], 20, 128);
+ adapt_prob(&p->tx16p[i][1], c16[1], c16[2], 20, 128);
+ adapt_prob(&p->tx32p[i][0], c32[0], c32[1] + c32[2] + c32[3], 20, 128);
+ adapt_prob(&p->tx32p[i][1], c32[1], c32[2] + c32[3], 20, 128);
+ adapt_prob(&p->tx32p[i][2], c32[2], c32[3], 20, 128);
+ }
}
- data += ret;
- size -= ret;
- s->cur_frame = frame;
+ // interpolation filter
+ if (s->filtermode == FILTER_SWITCHABLE) {
+ for (i = 0; i < 4; i++) {
+ uint8_t *pp = p->filter[i];
+ unsigned *c = s->counts.filter[i];
- av_frame_unref(s->cur_frame);
- if ((ret = ff_get_buffer(avctx, s->cur_frame,
- s->refreshrefmask ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
- return ret;
- s->cur_frame->key_frame = s->keyframe;
- s->cur_frame->pict_type = s->keyframe ? AV_PICTURE_TYPE_I
- : AV_PICTURE_TYPE_P;
+ adapt_prob(&pp[0], c[0], c[1] + c[2], 20, 128);
+ adapt_prob(&pp[1], c[1], c[2], 20, 128);
+ }
+ }
+
+ // inter modes
+ for (i = 0; i < 7; i++) {
+ uint8_t *pp = p->mv_mode[i];
+ unsigned *c = s->counts.mv_mode[i];
+
+ adapt_prob(&pp[0], c[2], c[1] + c[0] + c[3], 20, 128);
+ adapt_prob(&pp[1], c[0], c[1] + c[3], 20, 128);
+ adapt_prob(&pp[2], c[1], c[3], 20, 128);
+ }
+
+ // mv joints
+ {
+ uint8_t *pp = p->mv_joint;
+ unsigned *c = s->counts.mv_joint;
+
+ adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
+ adapt_prob(&pp[2], c[2], c[3], 20, 128);
+ }
+
+ // mv components
+ for (i = 0; i < 2; i++) {
+ uint8_t *pp;
+ unsigned *c, (*c2)[2], sum;
+
+ adapt_prob(&p->mv_comp[i].sign, s->counts.mv_comp[i].sign[0],
+ s->counts.mv_comp[i].sign[1], 20, 128);
+
+ pp = p->mv_comp[i].classes;
+ c = s->counts.mv_comp[i].classes;
+ sum = c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9] + c[10];
+ adapt_prob(&pp[0], c[0], sum, 20, 128);
+ sum -= c[1];
+ adapt_prob(&pp[1], c[1], sum, 20, 128);
+ sum -= c[2] + c[3];
+ adapt_prob(&pp[2], c[2] + c[3], sum, 20, 128);
+ adapt_prob(&pp[3], c[2], c[3], 20, 128);
+ sum -= c[4] + c[5];
+ adapt_prob(&pp[4], c[4] + c[5], sum, 20, 128);
+ adapt_prob(&pp[5], c[4], c[5], 20, 128);
+ sum -= c[6];
+ adapt_prob(&pp[6], c[6], sum, 20, 128);
+ adapt_prob(&pp[7], c[7] + c[8], c[9] + c[10], 20, 128);
+ adapt_prob(&pp[8], c[7], c[8], 20, 128);
+ adapt_prob(&pp[9], c[9], c[10], 20, 128);
+
+ adapt_prob(&p->mv_comp[i].class0, s->counts.mv_comp[i].class0[0],
+ s->counts.mv_comp[i].class0[1], 20, 128);
+ pp = p->mv_comp[i].bits;
+ c2 = s->counts.mv_comp[i].bits;
+ for (j = 0; j < 10; j++)
+ adapt_prob(&pp[j], c2[j][0], c2[j][1], 20, 128);
+
+ for (j = 0; j < 2; j++) {
+ pp = p->mv_comp[i].class0_fp[j];
+ c = s->counts.mv_comp[i].class0_fp[j];
+ adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
+ adapt_prob(&pp[2], c[2], c[3], 20, 128);
+ }
+ pp = p->mv_comp[i].fp;
+ c = s->counts.mv_comp[i].fp;
+ adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
+ adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
+ adapt_prob(&pp[2], c[2], c[3], 20, 128);
- if (s->fullrange)
- avctx->color_range = AVCOL_RANGE_JPEG;
- else
- avctx->color_range = AVCOL_RANGE_MPEG;
+ if (s->highprecisionmvs) {
+ adapt_prob(&p->mv_comp[i].class0_hp, s->counts.mv_comp[i].class0_hp[0],
+ s->counts.mv_comp[i].class0_hp[1], 20, 128);
+ adapt_prob(&p->mv_comp[i].hp, s->counts.mv_comp[i].hp[0],
+ s->counts.mv_comp[i].hp[1], 20, 128);
+ }
+ }
- switch (s->colorspace) {
- case 1: avctx->colorspace = AVCOL_SPC_BT470BG; break;
- case 2: avctx->colorspace = AVCOL_SPC_BT709; break;
- case 3: avctx->colorspace = AVCOL_SPC_SMPTE170M; break;
- case 4: avctx->colorspace = AVCOL_SPC_SMPTE240M; break;
+ // y intra modes
+ for (i = 0; i < 4; i++) {
+ uint8_t *pp = p->y_mode[i];
+ unsigned *c = s->counts.y_mode[i], sum, s2;
+
+ sum = c[0] + c[1] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9];
+ adapt_prob(&pp[0], c[DC_PRED], sum, 20, 128);
+ sum -= c[TM_VP8_PRED];
+ adapt_prob(&pp[1], c[TM_VP8_PRED], sum, 20, 128);
+ sum -= c[VERT_PRED];
+ adapt_prob(&pp[2], c[VERT_PRED], sum, 20, 128);
+ s2 = c[HOR_PRED] + c[DIAG_DOWN_RIGHT_PRED] + c[VERT_RIGHT_PRED];
+ sum -= s2;
+ adapt_prob(&pp[3], s2, sum, 20, 128);
+ s2 -= c[HOR_PRED];
+ adapt_prob(&pp[4], c[HOR_PRED], s2, 20, 128);
+ adapt_prob(&pp[5], c[DIAG_DOWN_RIGHT_PRED], c[VERT_RIGHT_PRED], 20, 128);
+ sum -= c[DIAG_DOWN_LEFT_PRED];
+ adapt_prob(&pp[6], c[DIAG_DOWN_LEFT_PRED], sum, 20, 128);
+ sum -= c[VERT_LEFT_PRED];
+ adapt_prob(&pp[7], c[VERT_LEFT_PRED], sum, 20, 128);
+ adapt_prob(&pp[8], c[HOR_DOWN_PRED], c[HOR_UP_PRED], 20, 128);
+ }
+
+ // uv intra modes
+ for (i = 0; i < 10; i++) {
+ uint8_t *pp = p->uv_mode[i];
+ unsigned *c = s->counts.uv_mode[i], sum, s2;
+
+ sum = c[0] + c[1] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9];
+ adapt_prob(&pp[0], c[DC_PRED], sum, 20, 128);
+ sum -= c[TM_VP8_PRED];
+ adapt_prob(&pp[1], c[TM_VP8_PRED], sum, 20, 128);
+ sum -= c[VERT_PRED];
+ adapt_prob(&pp[2], c[VERT_PRED], sum, 20, 128);
+ s2 = c[HOR_PRED] + c[DIAG_DOWN_RIGHT_PRED] + c[VERT_RIGHT_PRED];
+ sum -= s2;
+ adapt_prob(&pp[3], s2, sum, 20, 128);
+ s2 -= c[HOR_PRED];
+ adapt_prob(&pp[4], c[HOR_PRED], s2, 20, 128);
+ adapt_prob(&pp[5], c[DIAG_DOWN_RIGHT_PRED], c[VERT_RIGHT_PRED], 20, 128);
+ sum -= c[DIAG_DOWN_LEFT_PRED];
+ adapt_prob(&pp[6], c[DIAG_DOWN_LEFT_PRED], sum, 20, 128);
+ sum -= c[VERT_LEFT_PRED];
+ adapt_prob(&pp[7], c[VERT_LEFT_PRED], sum, 20, 128);
+ adapt_prob(&pp[8], c[HOR_DOWN_PRED], c[HOR_UP_PRED], 20, 128);
+ }
+}
+
+static void free_buffers(VP9Context *s)
+{
+ av_freep(&s->intra_pred_data[0]);
+ av_freep(&s->b_base);
+ av_freep(&s->block_base);
+}
+
+static av_cold int vp9_decode_free(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (s->frames[i].tf.f->data[0])
+ vp9_unref_frame(ctx, &s->frames[i]);
+ av_frame_free(&s->frames[i].tf.f);
+ }
+ for (i = 0; i < 8; i++) {
+ if (s->refs[i].f->data[0])
+ ff_thread_release_buffer(ctx, &s->refs[i]);
+ av_frame_free(&s->refs[i].f);
+ if (s->next_refs[i].f->data[0])
+ ff_thread_release_buffer(ctx, &s->next_refs[i]);
+ av_frame_free(&s->next_refs[i].f);
+ }
+ free_buffers(s);
+ av_freep(&s->c_b);
+ s->c_b_size = 0;
+
+ return 0;
+}
+
+
+static int vp9_decode_frame(AVCodecContext *ctx, void *frame,
+ int *got_frame, AVPacket *pkt)
+{
+ const uint8_t *data = pkt->data;
+ int size = pkt->size;
+ VP9Context *s = ctx->priv_data;
+ int res, tile_row, tile_col, i, ref, row, col;
+ int retain_segmap_ref = s->segmentation.enabled && !s->segmentation.update_map;
+ ptrdiff_t yoff, uvoff, ls_y, ls_uv;
+ AVFrame *f;
+ int bytesperpixel;
+
+ if ((res = decode_frame_header(ctx, data, size, &ref)) < 0) {
+ return res;
+ } else if (res == 0) {
+ if (!s->refs[ref].f->data[0]) {
+ av_log(ctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref);
+ return AVERROR_INVALIDDATA;
+ }
+ if ((res = av_frame_ref(frame, s->refs[ref].f)) < 0)
+ return res;
+ ((AVFrame *)frame)->pkt_pts = pkt->pts;
+ ((AVFrame *)frame)->pkt_dts = pkt->dts;
+ for (i = 0; i < 8; i++) {
+ if (s->next_refs[i].f->data[0])
+ ff_thread_release_buffer(ctx, &s->next_refs[i]);
+ if (s->refs[i].f->data[0] &&
+ (res = ff_thread_ref_frame(&s->next_refs[i], &s->refs[i])) < 0)
+ return res;
+ }
+ *got_frame = 1;
+ return pkt->size;
+ }
+ data += res;
+ size -= res;
+
+ if (!retain_segmap_ref) {
+ if (s->frames[REF_FRAME_SEGMAP].tf.f->data[0])
+ vp9_unref_frame(ctx, &s->frames[REF_FRAME_SEGMAP]);
+ if (!s->keyframe && !s->intraonly && !s->errorres && s->frames[CUR_FRAME].tf.f->data[0] &&
+ (res = vp9_ref_frame(ctx, &s->frames[REF_FRAME_SEGMAP], &s->frames[CUR_FRAME])) < 0)
+ return res;
+ }
+ if (s->frames[REF_FRAME_MVPAIR].tf.f->data[0])
+ vp9_unref_frame(ctx, &s->frames[REF_FRAME_MVPAIR]);
+ if (!s->intraonly && !s->keyframe && !s->errorres && s->frames[CUR_FRAME].tf.f->data[0] &&
+ (res = vp9_ref_frame(ctx, &s->frames[REF_FRAME_MVPAIR], &s->frames[CUR_FRAME])) < 0)
+ return res;
+ if (s->frames[CUR_FRAME].tf.f->data[0])
+ vp9_unref_frame(ctx, &s->frames[CUR_FRAME]);
+ if ((res = vp9_alloc_frame(ctx, &s->frames[CUR_FRAME])) < 0)
+ return res;
+ f = s->frames[CUR_FRAME].tf.f;
+ f->key_frame = s->keyframe;
+ f->pict_type = (s->keyframe || s->intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+ ls_y = f->linesize[0];
+ ls_uv =f->linesize[1];
+
+ // ref frame setup
+ for (i = 0; i < 8; i++) {
+ if (s->next_refs[i].f->data[0])
+ ff_thread_release_buffer(ctx, &s->next_refs[i]);
+ if (s->refreshrefmask & (1 << i)) {
+ res = ff_thread_ref_frame(&s->next_refs[i], &s->frames[CUR_FRAME].tf);
+ } else if (s->refs[i].f->data[0]) {
+ res = ff_thread_ref_frame(&s->next_refs[i], &s->refs[i]);
+ }
+ if (res < 0)
+ return res;
}
// main tile decode loop
+ bytesperpixel = s->bytesperpixel;
memset(s->above_partition_ctx, 0, s->cols);
memset(s->above_skip_ctx, 0, s->cols);
- if (s->keyframe || s->intraonly)
+ if (s->keyframe || s->intraonly) {
memset(s->above_mode_ctx, DC_PRED, s->cols * 2);
- else
+ } else {
memset(s->above_mode_ctx, NEARESTMV, s->cols);
+ }
memset(s->above_y_nnz_ctx, 0, s->sb_cols * 16);
- memset(s->above_uv_nnz_ctx[0], 0, s->sb_cols * 8);
- memset(s->above_uv_nnz_ctx[1], 0, s->sb_cols * 8);
+ memset(s->above_uv_nnz_ctx[0], 0, s->sb_cols * 16 >> s->ss_h);
+ memset(s->above_uv_nnz_ctx[1], 0, s->sb_cols * 16 >> s->ss_h);
memset(s->above_segpred_ctx, 0, s->cols);
- for (tile_row = 0; tile_row < s->tiling.tile_rows; tile_row++) {
- set_tile_offset(&s->tiling.tile_row_start, &s->tiling.tile_row_end,
- tile_row, s->tiling.log2_tile_rows, s->sb_rows);
- for (tile_col = 0; tile_col < s->tiling.tile_cols; tile_col++) {
- int64_t tile_size;
-
- if (tile_col == s->tiling.tile_cols - 1 &&
- tile_row == s->tiling.tile_rows - 1) {
- tile_size = size;
- } else {
- tile_size = AV_RB32(data);
- data += 4;
- size -= 4;
- }
- if (tile_size > size)
- return AVERROR_INVALIDDATA;
- ff_vp56_init_range_decoder(&s->c_b[tile_col], data, tile_size);
- if (vp56_rac_get_prob_branchy(&s->c_b[tile_col], 128)) // marker bit
- return AVERROR_INVALIDDATA;
- data += tile_size;
- size -= tile_size;
- }
-
- for (row = s->tiling.tile_row_start;
- row < s->tiling.tile_row_end;
- row += 8, yoff += s->cur_frame->linesize[0] * 64,
- uvoff += s->cur_frame->linesize[1] * 32) {
- VP9Filter *lflvl = s->lflvl;
- ptrdiff_t yoff2 = yoff, uvoff2 = uvoff;
-
- for (tile_col = 0; tile_col < s->tiling.tile_cols; tile_col++) {
- set_tile_offset(&s->tiling.tile_col_start,
- &s->tiling.tile_col_end,
- tile_col, s->tiling.log2_tile_cols, s->sb_cols);
-
- memset(s->left_partition_ctx, 0, 8);
- memset(s->left_skip_ctx, 0, 8);
- if (s->keyframe || s->intraonly)
- memset(s->left_mode_ctx, DC_PRED, 16);
- else
- memset(s->left_mode_ctx, NEARESTMV, 8);
- memset(s->left_y_nnz_ctx, 0, 16);
- memset(s->left_uv_nnz_ctx, 0, 16);
- memset(s->left_segpred_ctx, 0, 8);
-
- memcpy(&s->c, &s->c_b[tile_col], sizeof(s->c));
- for (col = s->tiling.tile_col_start;
- col < s->tiling.tile_col_end;
- col += 8, yoff2 += 64, uvoff2 += 32, lflvl++) {
- // FIXME integrate with lf code (i.e. zero after each
- // use, similar to invtxfm coefficients, or similar)
- memset(lflvl->mask, 0, sizeof(lflvl->mask));
-
- if ((ret = decode_subblock(avctx, row, col, lflvl,
- yoff2, uvoff2, BL_64X64)) < 0)
- return ret;
- }
- memcpy(&s->c_b[tile_col], &s->c, sizeof(s->c));
- }
-
- // backup pre-loopfilter reconstruction data for intra
- // prediction of next row of sb64s
- if (row + 8 < s->rows) {
- memcpy(s->intra_pred_data[0],
- s->cur_frame->data[0] + yoff +
- 63 * s->cur_frame->linesize[0],
- 8 * s->cols);
- memcpy(s->intra_pred_data[1],
- s->cur_frame->data[1] + uvoff +
- 31 * s->cur_frame->linesize[1],
- 4 * s->cols);
- memcpy(s->intra_pred_data[2],
- s->cur_frame->data[2] + uvoff +
- 31 * s->cur_frame->linesize[2],
- 4 * s->cols);
- }
-
- // loopfilter one row
- if (s->filter.level) {
- yoff2 = yoff;
- uvoff2 = uvoff;
- lflvl = s->lflvl;
- for (col = 0; col < s->cols;
- col += 8, yoff2 += 64, uvoff2 += 32, lflvl++)
- loopfilter_subblock(avctx, lflvl, row, col, yoff2, uvoff2);
- }
- }
- }
-
- // bw adaptivity (or in case of parallel decoding mode, fw adaptivity
- // probability maintenance between frames)
- if (s->refreshctx) {
- if (s->parallelmode) {
- int j, k, l, m;
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 2; j++)
- for (k = 0; k < 2; k++)
- for (l = 0; l < 6; l++)
- for (m = 0; m < 6; m++)
- memcpy(s->prob_ctx[s->framectxid].coef[i][j][k][l][m],
- s->prob.coef[i][j][k][l][m], 3);
- if (s->txfmmode == i)
- break;
- }
- s->prob_ctx[s->framectxid].p = s->prob.p;
- } else {
- ff_vp9_adapt_probs(s);
- }
+ s->pass = s->frames[CUR_FRAME].uses_2pass =
+ ctx->active_thread_type == FF_THREAD_FRAME && s->refreshctx && !s->parallelmode;
+ if ((res = update_block_buffers(ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Failed to allocate block buffers\n");
+ return res;
}
- FFSWAP(VP9MVRefPair *, s->mv[0], s->mv[1]);
+ if (s->refreshctx && s->parallelmode) {
+ int j, k, l, m;
- // ref frame setup
- for (i = 0; i < 8; i++)
- if (s->refreshrefmask & (1 << i)) {
- av_frame_unref(s->refs[i]);
- ret = av_frame_ref(s->refs[i], s->cur_frame);
- if (ret < 0)
- return ret;
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 2; j++)
+ for (k = 0; k < 2; k++)
+ for (l = 0; l < 6; l++)
+ for (m = 0; m < 6; m++)
+ memcpy(s->prob_ctx[s->framectxid].coef[i][j][k][l][m],
+ s->prob.coef[i][j][k][l][m], 3);
+ if (s->txfmmode == i)
+ break;
}
+ s->prob_ctx[s->framectxid].p = s->prob.p;
+ ff_thread_finish_setup(ctx);
+ } else if (!s->refreshctx) {
+ ff_thread_finish_setup(ctx);
+ }
- if (s->invisible)
- av_frame_unref(s->cur_frame);
- else
- *got_frame = 1;
+ do {
+ yoff = uvoff = 0;
+ s->b = s->b_base;
+ s->block = s->block_base;
+ s->uvblock[0] = s->uvblock_base[0];
+ s->uvblock[1] = s->uvblock_base[1];
+ s->eob = s->eob_base;
+ s->uveob[0] = s->uveob_base[0];
+ s->uveob[1] = s->uveob_base[1];
- return 0;
-}
+ for (tile_row = 0; tile_row < s->tiling.tile_rows; tile_row++) {
+ set_tile_offset(&s->tiling.tile_row_start, &s->tiling.tile_row_end,
+ tile_row, s->tiling.log2_tile_rows, s->sb_rows);
+ if (s->pass != 2) {
+ for (tile_col = 0; tile_col < s->tiling.tile_cols; tile_col++) {
+ unsigned tile_size;
-static int vp9_decode_packet(AVCodecContext *avctx, void *frame,
- int *got_frame, AVPacket *avpkt)
-{
- const uint8_t *data = avpkt->data;
- int size = avpkt->size;
- int marker, ret;
-
- /* Read superframe index - this is a collection of individual frames
- * that together lead to one visible frame */
- marker = data[size - 1];
- if ((marker & 0xe0) == 0xc0) {
- int nbytes = 1 + ((marker >> 3) & 0x3);
- int n_frames = 1 + (marker & 0x7);
- int idx_sz = 2 + n_frames * nbytes;
-
- if (size >= idx_sz && data[size - idx_sz] == marker) {
- const uint8_t *idx = data + size + 1 - idx_sz;
-
- while (n_frames--) {
- unsigned sz = AV_RL32(idx);
-
- if (nbytes < 4)
- sz &= (1 << (8 * nbytes)) - 1;
- idx += nbytes;
-
- if (sz > size) {
- av_log(avctx, AV_LOG_ERROR,
- "Superframe packet size too big: %u > %d\n",
- sz, size);
- return AVERROR_INVALIDDATA;
+ if (tile_col == s->tiling.tile_cols - 1 &&
+ tile_row == s->tiling.tile_rows - 1) {
+ tile_size = size;
+ } else {
+ tile_size = AV_RB32(data);
+ data += 4;
+ size -= 4;
+ }
+ if (tile_size > size) {
+ ff_thread_report_progress(&s->frames[CUR_FRAME].tf, INT_MAX, 0);
+ return AVERROR_INVALIDDATA;
+ }
+ ff_vp56_init_range_decoder(&s->c_b[tile_col], data, tile_size);
+ if (vp56_rac_get_prob_branchy(&s->c_b[tile_col], 128)) { // marker bit
+ ff_thread_report_progress(&s->frames[CUR_FRAME].tf, INT_MAX, 0);
+ return AVERROR_INVALIDDATA;
+ }
+ data += tile_size;
+ size -= tile_size;
}
+ }
+
+ for (row = s->tiling.tile_row_start; row < s->tiling.tile_row_end;
+ row += 8, yoff += ls_y * 64, uvoff += ls_uv * 64 >> s->ss_v) {
+ struct VP9Filter *lflvl_ptr = s->lflvl;
+ ptrdiff_t yoff2 = yoff, uvoff2 = uvoff;
+
+ for (tile_col = 0; tile_col < s->tiling.tile_cols; tile_col++) {
+ set_tile_offset(&s->tiling.tile_col_start, &s->tiling.tile_col_end,
+ tile_col, s->tiling.log2_tile_cols, s->sb_cols);
+
+ if (s->pass != 2) {
+ memset(s->left_partition_ctx, 0, 8);
+ memset(s->left_skip_ctx, 0, 8);
+ if (s->keyframe || s->intraonly) {
+ memset(s->left_mode_ctx, DC_PRED, 16);
+ } else {
+ memset(s->left_mode_ctx, NEARESTMV, 8);
+ }
+ memset(s->left_y_nnz_ctx, 0, 16);
+ memset(s->left_uv_nnz_ctx, 0, 32);
+ memset(s->left_segpred_ctx, 0, 8);
+
+ memcpy(&s->c, &s->c_b[tile_col], sizeof(s->c));
+ }
- ret = vp9_decode_frame(avctx, frame, got_frame, data, sz);
- if (ret < 0)
- return ret;
- data += sz;
- size -= sz;
+ for (col = s->tiling.tile_col_start;
+ col < s->tiling.tile_col_end;
+ col += 8, yoff2 += 64 * bytesperpixel,
+ uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
+ // FIXME integrate with lf code (i.e. zero after each
+ // use, similar to invtxfm coefficients, or similar)
+ if (s->pass != 1) {
+ memset(lflvl_ptr->mask, 0, sizeof(lflvl_ptr->mask));
+ }
+
+ if (s->pass == 2) {
+ decode_sb_mem(ctx, row, col, lflvl_ptr,
+ yoff2, uvoff2, BL_64X64);
+ } else {
+ decode_sb(ctx, row, col, lflvl_ptr,
+ yoff2, uvoff2, BL_64X64);
+ }
+ }
+ if (s->pass != 2) {
+ memcpy(&s->c_b[tile_col], &s->c, sizeof(s->c));
+ }
+ }
+
+ if (s->pass == 1) {
+ continue;
+ }
+
+ // backup pre-loopfilter reconstruction data for intra
+ // prediction of next row of sb64s
+ if (row + 8 < s->rows) {
+ memcpy(s->intra_pred_data[0],
+ f->data[0] + yoff + 63 * ls_y,
+ 8 * s->cols * bytesperpixel);
+ memcpy(s->intra_pred_data[1],
+ f->data[1] + uvoff + ((64 >> s->ss_v) - 1) * ls_uv,
+ 8 * s->cols * bytesperpixel >> s->ss_h);
+ memcpy(s->intra_pred_data[2],
+ f->data[2] + uvoff + ((64 >> s->ss_v) - 1) * ls_uv,
+ 8 * s->cols * bytesperpixel >> s->ss_h);
+ }
+
+ // loopfilter one row
+ if (s->filter.level) {
+ yoff2 = yoff;
+ uvoff2 = uvoff;
+ lflvl_ptr = s->lflvl;
+ for (col = 0; col < s->cols;
+ col += 8, yoff2 += 64 * bytesperpixel,
+ uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
+ loopfilter_sb(ctx, lflvl_ptr, row, col, yoff2, uvoff2);
+ }
+ }
+
+ // 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->frames[CUR_FRAME].tf, row >> 3, 0);
}
- return size;
}
+
+ if (s->pass < 2 && s->refreshctx && !s->parallelmode) {
+ adapt_probs(s);
+ ff_thread_finish_setup(ctx);
+ }
+ } while (s->pass++ == 1);
+ ff_thread_report_progress(&s->frames[CUR_FRAME].tf, INT_MAX, 0);
+
+ // ref frame setup
+ for (i = 0; i < 8; i++) {
+ if (s->refs[i].f->data[0])
+ ff_thread_release_buffer(ctx, &s->refs[i]);
+ ff_thread_ref_frame(&s->refs[i], &s->next_refs[i]);
}
- /* If we get here, there was no valid superframe index, i.e. this is just
- * one whole single frame. Decode it as such from the complete input buf. */
- if ((ret = vp9_decode_frame(avctx, frame, got_frame, data, size)) < 0)
- return ret;
- return size;
+ if (!s->invisible) {
+ if ((res = av_frame_ref(frame, s->frames[CUR_FRAME].tf.f)) < 0)
+ return res;
+ *got_frame = 1;
+ }
+
+ return pkt->size;
}
-static av_cold int vp9_decode_free(AVCodecContext *avctx)
+static void vp9_decode_flush(AVCodecContext *ctx)
{
- VP9Context *s = avctx->priv_data;
+ VP9Context *s = ctx->priv_data;
int i;
- for (i = 0; i < FF_ARRAY_ELEMS(s->refs); i++)
- av_frame_free(&s->refs[i]);
+ for (i = 0; i < 3; i++)
+ vp9_unref_frame(ctx, &s->frames[i]);
+ for (i = 0; i < 8; i++)
+ ff_thread_release_buffer(ctx, &s->refs[i]);
+}
- av_freep(&s->c_b);
- av_freep(&s->above_partition_ctx);
+static int init_frames(AVCodecContext *ctx)
+{
+ VP9Context *s = ctx->priv_data;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ s->frames[i].tf.f = av_frame_alloc();
+ if (!s->frames[i].tf.f) {
+ vp9_decode_free(ctx);
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame buffer %d\n", i);
+ return AVERROR(ENOMEM);
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ s->refs[i].f = av_frame_alloc();
+ s->next_refs[i].f = av_frame_alloc();
+ if (!s->refs[i].f || !s->next_refs[i].f) {
+ vp9_decode_free(ctx);
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate frame buffer %d\n", i);
+ return AVERROR(ENOMEM);
+ }
+ }
return 0;
}
-static av_cold int vp9_decode_init(AVCodecContext *avctx)
+static av_cold int vp9_decode_init(AVCodecContext *ctx)
{
- VP9Context *s = avctx->priv_data;
- int i;
+ VP9Context *s = ctx->priv_data;
- avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ ctx->internal->allocate_progress = 1;
+ s->last_bpp = 0;
+ s->filter.sharpness = -1;
- ff_vp9dsp_init(&s->dsp);
- ff_videodsp_init(&s->vdsp, 8);
+ return init_frames(ctx);
+}
- for (i = 0; i < FF_ARRAY_ELEMS(s->refs); i++) {
- s->refs[i] = av_frame_alloc();
- if (!s->refs[i]) {
- vp9_decode_free(avctx);
- return AVERROR(ENOMEM);
+static av_cold int vp9_decode_init_thread_copy(AVCodecContext *avctx)
+{
+ return init_frames(avctx);
+}
+
+static int vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
+{
+ int i, res;
+ VP9Context *s = dst->priv_data, *ssrc = src->priv_data;
+
+ // detect size changes in other threads
+ if (s->intra_pred_data[0] &&
+ (!ssrc->intra_pred_data[0] || s->cols != ssrc->cols || s->rows != ssrc->rows)) {
+ free_buffers(s);
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (s->frames[i].tf.f->data[0])
+ vp9_unref_frame(dst, &s->frames[i]);
+ if (ssrc->frames[i].tf.f->data[0]) {
+ if ((res = vp9_ref_frame(dst, &s->frames[i], &ssrc->frames[i])) < 0)
+ return res;
+ }
+ }
+ for (i = 0; i < 8; i++) {
+ if (s->refs[i].f->data[0])
+ ff_thread_release_buffer(dst, &s->refs[i]);
+ if (ssrc->next_refs[i].f->data[0]) {
+ if ((res = ff_thread_ref_frame(&s->refs[i], &ssrc->next_refs[i])) < 0)
+ return res;
}
}
- s->filter.sharpness = -1;
+ s->invisible = ssrc->invisible;
+ s->keyframe = ssrc->keyframe;
+ s->ss_v = ssrc->ss_v;
+ s->ss_h = ssrc->ss_h;
+ s->segmentation.enabled = ssrc->segmentation.enabled;
+ s->segmentation.update_map = ssrc->segmentation.update_map;
+ s->bytesperpixel = ssrc->bytesperpixel;
+ s->bpp = ssrc->bpp;
+ s->bpp_index = ssrc->bpp_index;
+ memcpy(&s->prob_ctx, &ssrc->prob_ctx, sizeof(s->prob_ctx));
+ memcpy(&s->lf_delta, &ssrc->lf_delta, sizeof(s->lf_delta));
+ if (ssrc->segmentation.enabled) {
+ memcpy(&s->segmentation.feat, &ssrc->segmentation.feat,
+ sizeof(s->segmentation.feat));
+ }
return 0;
}
+static const AVProfile profiles[] = {
+ { FF_PROFILE_VP9_0, "Profile 0" },
+ { FF_PROFILE_VP9_1, "Profile 1" },
+ { FF_PROFILE_VP9_2, "Profile 2" },
+ { FF_PROFILE_VP9_3, "Profile 3" },
+ { FF_PROFILE_UNKNOWN },
+};
+
AVCodec ff_vp9_decoder = {
- .name = "vp9",
- .long_name = NULL_IF_CONFIG_SMALL("Google VP9"),
- .type = AVMEDIA_TYPE_VIDEO,
- .id = AV_CODEC_ID_VP9,
- .priv_data_size = sizeof(VP9Context),
- .init = vp9_decode_init,
- .decode = vp9_decode_packet,
- .flush = vp9_decode_flush,
- .close = vp9_decode_free,
- .capabilities = CODEC_CAP_DR1,
+ .name = "vp9",
+ .long_name = NULL_IF_CONFIG_SMALL("Google VP9"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_VP9,
+ .priv_data_size = sizeof(VP9Context),
+ .init = vp9_decode_init,
+ .close = vp9_decode_free,
+ .decode = vp9_decode_frame,
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
+ .flush = vp9_decode_flush,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp9_decode_init_thread_copy),
+ .update_thread_context = ONLY_IF_THREADS_ENABLED(vp9_decode_update_thread_context),
+ .profiles = NULL_IF_CONFIG_SMALL(profiles),
};
diff --git a/libavcodec/vp9.h b/libavcodec/vp9.h
index 724288dd3d..9a29416e8d 100644
--- a/libavcodec/vp9.h
+++ b/libavcodec/vp9.h
@@ -4,34 +4,26 @@
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
* Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_VP9_H
#define AVCODEC_VP9_H
-#include <stddef.h>
-#include <stdint.h>
-
-#include "libavutil/internal.h"
-
-#include "avcodec.h"
-#include "vp56.h"
-
enum TxfmMode {
TX_4X4,
TX_8X8,
@@ -77,344 +69,4 @@ enum FilterMode {
FILTER_SWITCHABLE,
};
-enum BlockPartition {
- PARTITION_NONE, // [ ] <-.
- PARTITION_H, // [-] |
- PARTITION_V, // [|] |
- PARTITION_SPLIT, // [+] --'
-};
-
-enum InterPredMode {
- NEARESTMV = 10,
- NEARMV = 11,
- ZEROMV = 12,
- NEWMV = 13,
-};
-
-enum MVJoint {
- MV_JOINT_ZERO,
- MV_JOINT_H,
- MV_JOINT_V,
- MV_JOINT_HV,
-};
-
-typedef struct ProbContext {
- uint8_t y_mode[4][9];
- uint8_t uv_mode[10][9];
- uint8_t filter[4][2];
- uint8_t mv_mode[7][3];
- uint8_t intra[4];
- uint8_t comp[5];
- uint8_t single_ref[5][2];
- uint8_t comp_ref[5];
- uint8_t tx32p[2][3];
- uint8_t tx16p[2][2];
- uint8_t tx8p[2];
- uint8_t skip[3];
- uint8_t mv_joint[3];
- struct {
- uint8_t sign;
- uint8_t classes[10];
- uint8_t class0;
- uint8_t bits[10];
- uint8_t class0_fp[2][3];
- uint8_t fp[3];
- uint8_t class0_hp;
- uint8_t hp;
- } mv_comp[2];
- uint8_t partition[4][4][3];
-} ProbContext;
-
-typedef void (*vp9_mc_func)(uint8_t *dst, const uint8_t *ref,
- ptrdiff_t dst_stride,
- ptrdiff_t ref_stride,
- int h, int mx, int my);
-
-typedef struct VP9DSPContext {
- /*
- * dimension 1: 0=4x4, 1=8x8, 2=16x16, 3=32x32
- * dimension 2: intra prediction modes
- *
- * dst/left/top is aligned by transform-size (i.e. 4, 8, 16 or 32 pixels)
- * stride is aligned by 16 pixels
- * top[-1] is top/left; top[4,7] is top-right for 4x4
- */
- // FIXME(rbultje) maybe replace left/top pointers with HAVE_TOP/
- // HAVE_LEFT/HAVE_TOPRIGHT flags instead, and then handle it in-place?
- // also needs to fit in with what h264/vp8/etc do
- void (*intra_pred[N_TXFM_SIZES][N_INTRA_PRED_MODES])(uint8_t *dst,
- ptrdiff_t stride,
- const uint8_t *left,
- const uint8_t *top);
-
- /*
- * dimension 1: 0=4x4, 1=8x8, 2=16x16, 3=32x32, 4=lossless (3-4=dct only)
- * dimension 2: 0=dct/dct, 1=dct/adst, 2=adst/dct, 3=adst/adst
- *
- * dst is aligned by transform-size (i.e. 4, 8, 16 or 32 pixels)
- * stride is aligned by 16 pixels
- * block is 16-byte aligned
- * eob indicates the position (+1) of the last non-zero coefficient,
- * in scan-order. This can be used to write faster versions, e.g. a
- * dc-only 4x4/8x8/16x16/32x32, or a 4x4-only (eob<10) 8x8/16x16/32x32,
- * etc.
- */
- // FIXME also write idct_add_block() versions for whole (inter) pred
- // blocks, so we can do 2 4x4s at once
- void (*itxfm_add[N_TXFM_SIZES + 1][N_TXFM_TYPES])(uint8_t *dst,
- ptrdiff_t stride,
- int16_t *block, int eob);
-
- /*
- * dimension 1: width of filter (0=4, 1=8, 2=16)
- * dimension 2: 0=col-edge filter (h), 1=row-edge filter (v)
- *
- * dst/stride are aligned by 8
- */
- void (*loop_filter_8[3][2])(uint8_t *dst, ptrdiff_t stride,
- int mb_lim, int lim, int hev_thr);
-
- /*
- * dimension 1: 0=col-edge filter (h), 1=row-edge filter (v)
- *
- * The width of filter is assumed to be 16; dst/stride are aligned by 16
- */
- void (*loop_filter_16[2])(uint8_t *dst, ptrdiff_t stride,
- int mb_lim, int lim, int hev_thr);
-
- /*
- * dimension 1/2: width of filter (0=4, 1=8) for each filter half
- * dimension 3: 0=col-edge filter (h), 1=row-edge filter (v)
- *
- * dst/stride are aligned by operation size
- * this basically calls loop_filter[d1][d3][0](), followed by
- * loop_filter[d2][d3][0]() on the next 8 pixels
- * mb_lim/lim/hev_thr contain two values in the lowest two bytes of the
- * integer.
- */
- // FIXME perhaps a mix4 that operates on 32px (for AVX2)
- void (*loop_filter_mix2[2][2][2])(uint8_t *dst, ptrdiff_t stride,
- int mb_lim, int lim, int hev_thr);
-
- /*
- * dimension 1: hsize (0: 64, 1: 32, 2: 16, 3: 8, 4: 4)
- * dimension 2: filter type (0: smooth, 1: regular, 2: sharp, 3: bilin)
- * dimension 3: averaging type (0: put, 1: avg)
- * dimension 4: x subpel interpolation (0: none, 1: 8tap/bilin)
- * dimension 5: y subpel interpolation (1: none, 1: 8tap/bilin)
- *
- * dst/stride are aligned by hsize
- */
- vp9_mc_func mc[5][4][2][2][2];
-} VP9DSPContext;
-
-enum CompPredMode {
- PRED_SINGLEREF,
- PRED_COMPREF,
- PRED_SWITCHABLE,
-};
-
-typedef struct VP9MVRefPair {
- VP56mv mv[2];
- int8_t ref[2];
-} VP9MVRefPair;
-
-typedef struct VP9Filter {
- uint8_t level[8 * 8];
- uint8_t /* bit=col */ mask[2 /* 0=y, 1=uv */][2 /* 0=col, 1=row */]
- [8 /* rows */][4 /* 0=16, 1=8, 2=4, 3=inner4 */];
-} VP9Filter;
-
-enum BlockLevel {
- BL_64X64,
- BL_32X32,
- BL_16X16,
- BL_8X8,
-};
-
-enum BlockSize {
- BS_64x64,
- BS_64x32,
- BS_32x64,
- BS_32x32,
- BS_32x16,
- BS_16x32,
- BS_16x16,
- BS_16x8,
- BS_8x16,
- BS_8x8,
- BS_8x4,
- BS_4x8,
- BS_4x4,
- N_BS_SIZES,
-};
-
-typedef struct VP9Block {
- uint8_t seg_id, intra, comp, ref[2], mode[4], uvmode, skip;
- enum FilterMode filter;
- VP56mv mv[4 /* b_idx */][2 /* ref */];
- enum BlockSize bs;
- enum TxfmMode tx, uvtx;
-
- int row, row7, col, col7;
- uint8_t *dst[3];
- ptrdiff_t y_stride, uv_stride;
-} VP9Block;
-
-typedef struct VP9Context {
- VP9DSPContext dsp;
- VideoDSPContext vdsp;
- GetBitContext gb;
- VP56RangeCoder c;
- VP56RangeCoder *c_b;
- unsigned c_b_size;
- VP9Block b;
-
- // bitstream header
- uint8_t profile;
- uint8_t keyframe, last_keyframe;
- uint8_t invisible;
- uint8_t use_last_frame_mvs;
- uint8_t errorres;
- uint8_t colorspace;
- uint8_t fullrange;
- uint8_t intraonly;
- uint8_t resetctx;
- uint8_t refreshrefmask;
- uint8_t highprecisionmvs;
- enum FilterMode filtermode;
- uint8_t allowcompinter;
- uint8_t fixcompref;
- uint8_t refreshctx;
- uint8_t parallelmode;
- uint8_t framectxid;
- uint8_t refidx[3];
- uint8_t signbias[3];
- uint8_t varcompref[2];
- AVFrame *refs[8];
- AVFrame *cur_frame;
-
- struct {
- uint8_t level;
- int8_t sharpness;
- uint8_t lim_lut[64];
- uint8_t mblim_lut[64];
- } filter;
- struct {
- uint8_t enabled;
- int8_t mode[2];
- int8_t ref[4];
- } lf_delta;
- uint8_t yac_qi;
- int8_t ydc_qdelta, uvdc_qdelta, uvac_qdelta;
- uint8_t lossless;
- struct {
- uint8_t enabled;
- uint8_t temporal;
- uint8_t absolute_vals;
- uint8_t update_map;
- #define MAX_SEGMENT 8
- struct {
- uint8_t q_enabled;
- uint8_t lf_enabled;
- uint8_t ref_enabled;
- uint8_t skip_enabled;
- uint8_t ref_val;
- int16_t q_val;
- int8_t lf_val;
- int16_t qmul[2][2];
- uint8_t lflvl[4][2];
- } feat[MAX_SEGMENT];
- } segmentation;
- struct {
- unsigned log2_tile_cols, log2_tile_rows;
- unsigned tile_cols, tile_rows;
- unsigned tile_row_start, tile_row_end, tile_col_start, tile_col_end;
- } tiling;
- unsigned sb_cols, sb_rows, rows, cols;
- struct {
- ProbContext p;
- uint8_t coef[4][2][2][6][6][3];
- } prob_ctx[4];
- struct {
- ProbContext p;
- uint8_t coef[4][2][2][6][6][11];
- uint8_t seg[7];
- uint8_t segpred[3];
- } prob;
- struct {
- unsigned y_mode[4][10];
- unsigned uv_mode[10][10];
- unsigned filter[4][3];
- unsigned mv_mode[7][4];
- unsigned intra[4][2];
- unsigned comp[5][2];
- unsigned single_ref[5][2][2];
- unsigned comp_ref[5][2];
- unsigned tx32p[2][4];
- unsigned tx16p[2][3];
- unsigned tx8p[2][2];
- unsigned skip[3][2];
- unsigned mv_joint[4];
- struct {
- unsigned sign[2];
- unsigned classes[11];
- unsigned class0[2];
- unsigned bits[10][2];
- unsigned class0_fp[2][4];
- unsigned fp[4];
- unsigned class0_hp[2];
- unsigned hp[2];
- } mv_comp[2];
- unsigned partition[4][4][4];
- unsigned coef[4][2][2][6][6][3];
- unsigned eob[4][2][2][6][6][2];
- } counts;
- enum TxfmMode txfmmode;
- enum CompPredMode comppredmode;
-
- // contextual (left/above) cache
- uint8_t left_partition_ctx[8], *above_partition_ctx;
- uint8_t left_mode_ctx[16], *above_mode_ctx;
- // FIXME maybe merge some of the below in a flags field?
- uint8_t left_y_nnz_ctx[16], *above_y_nnz_ctx;
- uint8_t left_uv_nnz_ctx[2][8], *above_uv_nnz_ctx[2];
- uint8_t left_skip_ctx[8], *above_skip_ctx; // 1bit
- uint8_t left_txfm_ctx[8], *above_txfm_ctx; // 2bit
- uint8_t left_segpred_ctx[8], *above_segpred_ctx; // 1bit
- uint8_t left_intra_ctx[8], *above_intra_ctx; // 1bit
- uint8_t left_comp_ctx[8], *above_comp_ctx; // 1bit
- uint8_t left_ref_ctx[8], *above_ref_ctx; // 2bit
- uint8_t left_filter_ctx[8], *above_filter_ctx;
- VP56mv left_mv_ctx[16][2], (*above_mv_ctx)[2];
-
- // whole-frame cache
- uint8_t *intra_pred_data[3];
- uint8_t *segmentation_map;
- VP9MVRefPair *mv[2];
- VP9Filter *lflvl;
- DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[71 * 80];
-
- // block reconstruction intermediates
- DECLARE_ALIGNED(32, int16_t, block)[4096];
- DECLARE_ALIGNED(32, int16_t, uvblock)[2][1024];
- uint8_t eob[256];
- uint8_t uveob[2][64];
- VP56mv min_mv, max_mv;
- DECLARE_ALIGNED(32, uint8_t, tmp_y)[64 * 64];
- DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][32 * 32];
-} VP9Context;
-
-void ff_vp9dsp_init(VP9DSPContext *dsp);
-
-void ff_vp9dsp_init_x86(VP9DSPContext *dsp);
-
-void ff_vp9_fill_mv(VP9Context *s, VP56mv *mv, int mode, int sb);
-
-void ff_vp9_adapt_probs(VP9Context *s);
-
-int ff_vp9_decode_block(AVCodecContext *avctx, int row, int col,
- VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff,
- enum BlockLevel bl, enum BlockPartition bp);
-
#endif /* AVCODEC_VP9_H */
diff --git a/libavcodec/vp9_mc_template.c b/libavcodec/vp9_mc_template.c
new file mode 100644
index 0000000000..f4eb4e56ac
--- /dev/null
+++ b/libavcodec/vp9_mc_template.c
@@ -0,0 +1,435 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 ROUNDED_DIV_MVx2(a, b) \
+ (VP56mv) { .x = ROUNDED_DIV(a.x + b.x, 2), .y = ROUNDED_DIV(a.y + b.y, 2) }
+#define ROUNDED_DIV_MVx4(a, b, c, d) \
+ (VP56mv) { .x = ROUNDED_DIV(a.x + b.x + c.x + d.x, 4), \
+ .y = ROUNDED_DIV(a.y + b.y + c.y + d.y, 4) }
+
+static void FN(inter_pred)(AVCodecContext *ctx)
+{
+ static const uint8_t bwlog_tab[2][N_BS_SIZES] = {
+ { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 },
+ { 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4 },
+ };
+ VP9Context *s = ctx->priv_data;
+ VP9Block *b = s->b;
+ int row = s->row, col = s->col;
+ ThreadFrame *tref1 = &s->refs[s->refidx[b->ref[0]]], *tref2;
+ AVFrame *ref1 = tref1->f, *ref2;
+ int w1 = ref1->width, h1 = ref1->height, w2, h2;
+ ptrdiff_t ls_y = s->y_stride, ls_uv = s->uv_stride;
+ int bytesperpixel = BYTES_PER_PIXEL;
+
+ if (b->comp) {
+ tref2 = &s->refs[s->refidx[b->ref[1]]];
+ ref2 = tref2->f;
+ w2 = ref2->width;
+ h2 = ref2->height;
+ }
+
+ // y inter pred
+ if (b->bs > BS_8x8) {
+ VP56mv uvmv;
+
+#if SCALED == 0
+ if (b->bs == BS_8x4) {
+ mc_luma_dir(s, mc[3][b->filter][0], s->dst[0], ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, col << 3, &b->mv[0][0],,,,, 8, 4, w1, h1, 0);
+ mc_luma_dir(s, mc[3][b->filter][0],
+ s->dst[0] + 4 * ls_y, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ (row << 3) + 4, col << 3, &b->mv[2][0],,,,, 8, 4, w1, h1, 0);
+ w1 = (w1 + s->ss_h) >> s->ss_h;
+ if (s->ss_v) {
+ h1 = (h1 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[2][0]);
+ mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 2, col << (3 - s->ss_h),
+ &uvmv,,,,, 8 >> s->ss_h, 4, w1, h1, 0);
+ } else {
+ mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 3, col << (3 - s->ss_h),
+ &b->mv[0][0],,,,, 8 >> s->ss_h, 4, w1, h1, 0);
+ // BUG for 4:2:2 bs=8x4, libvpx uses the wrong block index
+ // to get the motion vector for the bottom 4x4 block
+ // https://code.google.com/p/webm/issues/detail?id=993
+ if (s->ss_h == 0) {
+ uvmv = b->mv[2][0];
+ } else {
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[2][0]);
+ }
+ mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][0],
+ s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ (row << 3) + 4, col << (3 - s->ss_h),
+ &uvmv,,,,, 8 >> s->ss_h, 4, w1, h1, 0);
+ }
+
+ if (b->comp) {
+ mc_luma_dir(s, mc[3][b->filter][1], s->dst[0], ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, col << 3, &b->mv[0][1],,,,, 8, 4, w2, h2, 1);
+ mc_luma_dir(s, mc[3][b->filter][1],
+ s->dst[0] + 4 * ls_y, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ (row << 3) + 4, col << 3, &b->mv[2][1],,,,, 8, 4, w2, h2, 1);
+ w2 = (w2 + s->ss_h) >> s->ss_h;
+ if (s->ss_v) {
+ h2 = (h2 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[2][1]);
+ mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 2, col << (3 - s->ss_h),
+ &uvmv,,,,, 8 >> s->ss_h, 4, w2, h2, 1);
+ } else {
+ mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 3, col << (3 - s->ss_h),
+ &b->mv[0][1],,,,, 8 >> s->ss_h, 4, w2, h2, 1);
+ // BUG for 4:2:2 bs=8x4, libvpx uses the wrong block index
+ // to get the motion vector for the bottom 4x4 block
+ // https://code.google.com/p/webm/issues/detail?id=993
+ if (s->ss_h == 0) {
+ uvmv = b->mv[2][1];
+ } else {
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[2][1]);
+ }
+ mc_chroma_dir(s, mc[3 + s->ss_h][b->filter][1],
+ s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ (row << 3) + 4, col << (3 - s->ss_h),
+ &uvmv,,,,, 8 >> s->ss_h, 4, w2, h2, 1);
+ }
+ }
+ } else if (b->bs == BS_4x8) {
+ mc_luma_dir(s, mc[4][b->filter][0], s->dst[0], ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, col << 3, &b->mv[0][0],,,,, 4, 8, w1, h1, 0);
+ mc_luma_dir(s, mc[4][b->filter][0], s->dst[0] + 4 * bytesperpixel, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, (col << 3) + 4, &b->mv[1][0],,,,, 4, 8, w1, h1, 0);
+ h1 = (h1 + s->ss_v) >> s->ss_v;
+ if (s->ss_h) {
+ w1 = (w1 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[1][0]);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << (3 - s->ss_v), col << 2,
+ &uvmv,,,,, 4, 8 >> s->ss_v, w1, h1, 0);
+ } else {
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << (3 - s->ss_v), col << 3,
+ &b->mv[0][0],,,,, 4, 8 >> s->ss_v, w1, h1, 0);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1] + 4 * bytesperpixel,
+ s->dst[2] + 4 * bytesperpixel, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << (3 - s->ss_v), (col << 3) + 4,
+ &b->mv[1][0],,,,, 4, 8 >> s->ss_v, w1, h1, 0);
+ }
+
+ if (b->comp) {
+ mc_luma_dir(s, mc[4][b->filter][1], s->dst[0], ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, col << 3, &b->mv[0][1],,,,, 4, 8, w2, h2, 1);
+ mc_luma_dir(s, mc[4][b->filter][1], s->dst[0] + 4 * bytesperpixel, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, (col << 3) + 4, &b->mv[1][1],,,,, 4, 8, w2, h2, 1);
+ h2 = (h2 + s->ss_v) >> s->ss_v;
+ if (s->ss_h) {
+ w2 = (w2 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[1][1]);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << (3 - s->ss_v), col << 2,
+ &uvmv,,,,, 4, 8 >> s->ss_v, w2, h2, 1);
+ } else {
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << (3 - s->ss_v), col << 3,
+ &b->mv[0][1],,,,, 4, 8 >> s->ss_v, w2, h2, 1);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1] + 4 * bytesperpixel,
+ s->dst[2] + 4 * bytesperpixel, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << (3 - s->ss_v), (col << 3) + 4,
+ &b->mv[1][1],,,,, 4, 8 >> s->ss_v, w2, h2, 1);
+ }
+ }
+ } else
+#endif
+ {
+ av_assert2(b->bs == BS_4x4);
+
+ // FIXME if two horizontally adjacent blocks have the same MV,
+ // do a w8 instead of a w4 call
+ mc_luma_dir(s, mc[4][b->filter][0], s->dst[0], ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, col << 3, &b->mv[0][0],
+ 0, 0, 8, 8, 4, 4, w1, h1, 0);
+ mc_luma_dir(s, mc[4][b->filter][0], s->dst[0] + 4 * bytesperpixel, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, (col << 3) + 4, &b->mv[1][0],
+ 4, 0, 8, 8, 4, 4, w1, h1, 0);
+ mc_luma_dir(s, mc[4][b->filter][0],
+ s->dst[0] + 4 * ls_y, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ (row << 3) + 4, col << 3, &b->mv[2][0],
+ 0, 4, 8, 8, 4, 4, w1, h1, 0);
+ mc_luma_dir(s, mc[4][b->filter][0],
+ s->dst[0] + 4 * ls_y + 4 * bytesperpixel, ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ (row << 3) + 4, (col << 3) + 4, &b->mv[3][0],
+ 4, 4, 8, 8, 4, 4, w1, h1, 0);
+ if (s->ss_v) {
+ h1 = (h1 + 1) >> 1;
+ if (s->ss_h) {
+ w1 = (w1 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx4(b->mv[0][0], b->mv[1][0],
+ b->mv[2][0], b->mv[3][0]);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 2, col << 2,
+ &uvmv, 0, 0, 4, 4, 4, 4, w1, h1, 0);
+ } else {
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[2][0]);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 2, col << 3,
+ &uvmv, 0, 0, 8, 4, 4, 4, w1, h1, 0);
+ uvmv = ROUNDED_DIV_MVx2(b->mv[1][0], b->mv[3][0]);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1] + 4 * bytesperpixel,
+ s->dst[2] + 4 * bytesperpixel, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 2, (col << 3) + 4,
+ &uvmv, 4, 0, 8, 4, 4, 4, w1, h1, 0);
+ }
+ } else {
+ if (s->ss_h) {
+ w1 = (w1 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][0], b->mv[1][0]);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 3, col << 2,
+ &uvmv, 0, 0, 4, 8, 4, 4, w1, h1, 0);
+ // BUG libvpx uses wrong block index for 4:2:2 bs=4x4
+ // bottom block
+ // https://code.google.com/p/webm/issues/detail?id=993
+ uvmv = ROUNDED_DIV_MVx2(b->mv[1][0], b->mv[2][0]);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ (row << 3) + 4, col << 2,
+ &uvmv, 0, 4, 4, 8, 4, 4, w1, h1, 0);
+ } else {
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 3, col << 3,
+ &b->mv[0][0], 0, 0, 8, 8, 4, 4, w1, h1, 0);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1] + 4 * bytesperpixel,
+ s->dst[2] + 4 * bytesperpixel, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << 3, (col << 3) + 4,
+ &b->mv[1][0], 4, 0, 8, 8, 4, 4, w1, h1, 0);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ (row << 3) + 4, col << 3,
+ &b->mv[2][0], 0, 4, 8, 8, 4, 4, w1, h1, 0);
+ mc_chroma_dir(s, mc[4][b->filter][0],
+ s->dst[1] + 4 * ls_uv + 4 * bytesperpixel,
+ s->dst[2] + 4 * ls_uv + 4 * bytesperpixel, ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ (row << 3) + 4, (col << 3) + 4,
+ &b->mv[3][0], 4, 4, 8, 8, 4, 4, w1, h1, 0);
+ }
+ }
+
+ if (b->comp) {
+ mc_luma_dir(s, mc[4][b->filter][1], s->dst[0], ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, col << 3, &b->mv[0][1], 0, 0, 8, 8, 4, 4, w2, h2, 1);
+ mc_luma_dir(s, mc[4][b->filter][1], s->dst[0] + 4 * bytesperpixel, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, (col << 3) + 4, &b->mv[1][1], 4, 0, 8, 8, 4, 4, w2, h2, 1);
+ mc_luma_dir(s, mc[4][b->filter][1],
+ s->dst[0] + 4 * ls_y, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ (row << 3) + 4, col << 3, &b->mv[2][1], 0, 4, 8, 8, 4, 4, w2, h2, 1);
+ mc_luma_dir(s, mc[4][b->filter][1],
+ s->dst[0] + 4 * ls_y + 4 * bytesperpixel, ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ (row << 3) + 4, (col << 3) + 4, &b->mv[3][1], 4, 4, 8, 8, 4, 4, w2, h2, 1);
+ if (s->ss_v) {
+ h2 = (h2 + 1) >> 1;
+ if (s->ss_h) {
+ w2 = (w2 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx4(b->mv[0][1], b->mv[1][1],
+ b->mv[2][1], b->mv[3][1]);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 2, col << 2,
+ &uvmv, 0, 0, 4, 4, 4, 4, w2, h2, 1);
+ } else {
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[2][1]);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 2, col << 3,
+ &uvmv, 0, 0, 8, 4, 4, 4, w2, h2, 1);
+ uvmv = ROUNDED_DIV_MVx2(b->mv[1][1], b->mv[3][1]);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1] + 4 * bytesperpixel,
+ s->dst[2] + 4 * bytesperpixel, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 2, (col << 3) + 4,
+ &uvmv, 4, 0, 8, 4, 4, 4, w2, h2, 1);
+ }
+ } else {
+ if (s->ss_h) {
+ w2 = (w2 + 1) >> 1;
+ uvmv = ROUNDED_DIV_MVx2(b->mv[0][1], b->mv[1][1]);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 3, col << 2,
+ &uvmv, 0, 0, 4, 8, 4, 4, w2, h2, 1);
+ // BUG libvpx uses wrong block index for 4:2:2 bs=4x4
+ // bottom block
+ // https://code.google.com/p/webm/issues/detail?id=993
+ uvmv = ROUNDED_DIV_MVx2(b->mv[1][1], b->mv[2][1]);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ (row << 3) + 4, col << 2,
+ &uvmv, 0, 4, 4, 8, 4, 4, w2, h2, 1);
+ } else {
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 3, col << 3,
+ &b->mv[0][1], 0, 0, 8, 8, 4, 4, w2, h2, 1);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1] + 4 * bytesperpixel,
+ s->dst[2] + 4 * bytesperpixel, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << 3, (col << 3) + 4,
+ &b->mv[1][1], 4, 0, 8, 8, 4, 4, w2, h2, 1);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1] + 4 * ls_uv, s->dst[2] + 4 * ls_uv, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ (row << 3) + 4, col << 3,
+ &b->mv[2][1], 0, 4, 8, 8, 4, 4, w2, h2, 1);
+ mc_chroma_dir(s, mc[4][b->filter][1],
+ s->dst[1] + 4 * ls_uv + 4 * bytesperpixel,
+ s->dst[2] + 4 * ls_uv + 4 * bytesperpixel, ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ (row << 3) + 4, (col << 3) + 4,
+ &b->mv[3][1], 4, 4, 8, 8, 4, 4, w2, h2, 1);
+ }
+ }
+ }
+ }
+ } else {
+ int bwl = bwlog_tab[0][b->bs];
+ int bw = bwh_tab[0][b->bs][0] * 4, bh = bwh_tab[0][b->bs][1] * 4;
+ int uvbw = bwh_tab[s->ss_h][b->bs][0] * 4, uvbh = bwh_tab[s->ss_v][b->bs][1] * 4;
+
+ mc_luma_dir(s, mc[bwl][b->filter][0], s->dst[0], ls_y,
+ ref1->data[0], ref1->linesize[0], tref1,
+ row << 3, col << 3, &b->mv[0][0], 0, 0, bw, bh, bw, bh, w1, h1, 0);
+ w1 = (w1 + s->ss_h) >> s->ss_h;
+ h1 = (h1 + s->ss_v) >> s->ss_v;
+ mc_chroma_dir(s, mc[bwl + s->ss_h][b->filter][0],
+ s->dst[1], s->dst[2], ls_uv,
+ ref1->data[1], ref1->linesize[1],
+ ref1->data[2], ref1->linesize[2], tref1,
+ row << (3 - s->ss_v), col << (3 - s->ss_h),
+ &b->mv[0][0], 0, 0, uvbw, uvbh, uvbw, uvbh, w1, h1, 0);
+
+ if (b->comp) {
+ mc_luma_dir(s, mc[bwl][b->filter][1], s->dst[0], ls_y,
+ ref2->data[0], ref2->linesize[0], tref2,
+ row << 3, col << 3, &b->mv[0][1], 0, 0, bw, bh, bw, bh, w2, h2, 1);
+ w2 = (w2 + s->ss_h) >> s->ss_h;
+ h2 = (h2 + s->ss_v) >> s->ss_v;
+ mc_chroma_dir(s, mc[bwl + s->ss_h][b->filter][1],
+ s->dst[1], s->dst[2], ls_uv,
+ ref2->data[1], ref2->linesize[1],
+ ref2->data[2], ref2->linesize[2], tref2,
+ row << (3 - s->ss_v), col << (3 - s->ss_h),
+ &b->mv[0][1], 0, 0, uvbw, uvbh, uvbw, uvbh, w2, h2, 1);
+ }
+ }
+}
diff --git a/libavcodec/vp9_parser.c b/libavcodec/vp9_parser.c
new file mode 100644
index 0000000000..ab33c33414
--- /dev/null
+++ b/libavcodec/vp9_parser.c
@@ -0,0 +1,136 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "parser.h"
+
+typedef struct VP9ParseContext {
+ int n_frames; // 1-8
+ int size[8];
+ int64_t pts;
+} VP9ParseContext;
+
+static void parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size)
+{
+ VP9ParseContext *s = ctx->priv_data;
+
+ if (buf[0] & 0x4) {
+ ctx->pict_type = AV_PICTURE_TYPE_P;
+ ctx->key_frame = 0;
+ } else {
+ ctx->pict_type = AV_PICTURE_TYPE_I;
+ ctx->key_frame = 1;
+ }
+
+ if (buf[0] & 0x2) {
+ if (ctx->pts == AV_NOPTS_VALUE)
+ ctx->pts = s->pts;
+ s->pts = AV_NOPTS_VALUE;
+ } else {
+ s->pts = ctx->pts;
+ ctx->pts = AV_NOPTS_VALUE;
+ }
+}
+
+static int parse(AVCodecParserContext *ctx,
+ AVCodecContext *avctx,
+ const uint8_t **out_data, int *out_size,
+ const uint8_t *data, int size)
+{
+ VP9ParseContext *s = ctx->priv_data;
+ int full_size = size;
+ int marker;
+
+ if (size <= 0) {
+ *out_size = 0;
+ *out_data = data;
+
+ return 0;
+ }
+
+ if (s->n_frames > 0) {
+ *out_data = data;
+ *out_size = s->size[--s->n_frames];
+ parse_frame(ctx, *out_data, *out_size);
+
+ return s->n_frames > 0 ? *out_size : size /* i.e. include idx tail */;
+ }
+
+ marker = data[size - 1];
+ if ((marker & 0xe0) == 0xc0) {
+ int nbytes = 1 + ((marker >> 3) & 0x3);
+ int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes;
+
+ if (size >= idx_sz && data[size - idx_sz] == marker) {
+ const uint8_t *idx = data + size + 1 - idx_sz;
+ int first = 1;
+
+ switch (nbytes) {
+#define case_n(a, rd) \
+ case a: \
+ while (n_frames--) { \
+ unsigned sz = rd; \
+ idx += a; \
+ if (sz > size) { \
+ s->n_frames = 0; \
+ *out_size = size; \
+ *out_data = data; \
+ av_log(avctx, AV_LOG_ERROR, \
+ "Superframe packet size too big: %u > %d\n", \
+ sz, size); \
+ return full_size; \
+ } \
+ if (first) { \
+ first = 0; \
+ *out_data = data; \
+ *out_size = sz; \
+ s->n_frames = n_frames; \
+ } else { \
+ s->size[n_frames] = sz; \
+ } \
+ data += sz; \
+ size -= sz; \
+ } \
+ parse_frame(ctx, *out_data, *out_size); \
+ return *out_size
+
+ case_n(1, *idx);
+ case_n(2, AV_RL16(idx));
+ case_n(3, AV_RL24(idx));
+ case_n(4, AV_RL32(idx));
+ }
+ }
+ }
+
+ *out_data = data;
+ *out_size = size;
+ parse_frame(ctx, data, size);
+
+ return size;
+}
+
+AVCodecParser ff_vp9_parser = {
+ .codec_ids = { AV_CODEC_ID_VP9 },
+ .priv_data_size = sizeof(VP9ParseContext),
+ .parser_parse = parse,
+};
diff --git a/libavcodec/vp9block.c b/libavcodec/vp9block.c
deleted file mode 100644
index a92c794ebf..0000000000
--- a/libavcodec/vp9block.c
+++ /dev/null
@@ -1,1685 +0,0 @@
-/*
- * VP9 compatible video decoder
- *
- * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
- * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavutil/avassert.h"
-
-#include "avcodec.h"
-#include "get_bits.h"
-#include "internal.h"
-#include "videodsp.h"
-#include "vp56.h"
-#include "vp9.h"
-#include "vp9data.h"
-
-static const uint8_t bwh_tab[2][N_BS_SIZES][2] = {
- {
- { 16, 16 }, { 16, 8 }, { 8, 16 }, { 8, 8 }, { 8, 4 }, { 4, 8 },
- { 4, 4 }, { 4, 2 }, { 2, 4 }, { 2, 2 }, { 2, 1 }, { 1, 2 }, { 1, 1 },
- }, {
- { 8, 8 }, { 8, 4 }, { 4, 8 }, { 4, 4 }, { 4, 2 }, { 2, 4 },
- { 2, 2 }, { 2, 1 }, { 1, 2 }, { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 },
- }
-};
-
-// differential forward probability updates
-static void decode_mode(VP9Context *s, VP9Block *const b)
-{
- static const uint8_t left_ctx[N_BS_SIZES] = {
- 0x0, 0x8, 0x0, 0x8, 0xc, 0x8, 0xc, 0xe, 0xc, 0xe, 0xf, 0xe, 0xf
- };
- static const uint8_t above_ctx[N_BS_SIZES] = {
- 0x0, 0x0, 0x8, 0x8, 0x8, 0xc, 0xc, 0xc, 0xe, 0xe, 0xe, 0xf, 0xf
- };
- static const uint8_t max_tx_for_bl_bp[N_BS_SIZES] = {
- TX_32X32, TX_32X32, TX_32X32, TX_32X32, TX_16X16, TX_16X16,
- TX_16X16, TX_8X8, TX_8X8, TX_8X8, TX_4X4, TX_4X4, TX_4X4
- };
- int row = b->row, col = b->col, row7 = b->row7;
- enum TxfmMode max_tx = max_tx_for_bl_bp[b->bs];
- int w4 = FFMIN(s->cols - col, bwh_tab[1][b->bs][0]);
- int h4 = FFMIN(s->rows - row, bwh_tab[1][b->bs][1]);
- int have_a = row > 0, have_l = col > s->tiling.tile_col_start;
- int y;
-
- if (!s->segmentation.enabled) {
- b->seg_id = 0;
- } else if (s->keyframe || s->intraonly) {
- b->seg_id = s->segmentation.update_map ?
- vp8_rac_get_tree(&s->c, ff_vp9_segmentation_tree, s->prob.seg) : 0;
- } else if (!s->segmentation.update_map ||
- (s->segmentation.temporal &&
- vp56_rac_get_prob_branchy(&s->c,
- s->prob.segpred[s->above_segpred_ctx[col] +
- s->left_segpred_ctx[row7]]))) {
- int pred = MAX_SEGMENT - 1;
- int x;
-
- for (y = 0; y < h4; y++)
- for (x = 0; x < w4; x++)
- pred = FFMIN(pred,
- s->segmentation_map[(y + row) * 8 * s->sb_cols + x + col]);
- b->seg_id = pred;
-
- memset(&s->above_segpred_ctx[col], 1, w4);
- memset(&s->left_segpred_ctx[row7], 1, h4);
- } else {
- b->seg_id = vp8_rac_get_tree(&s->c, ff_vp9_segmentation_tree,
- s->prob.seg);
-
- memset(&s->above_segpred_ctx[col], 0, w4);
- memset(&s->left_segpred_ctx[row7], 0, h4);
- }
- if ((s->segmentation.enabled && s->segmentation.update_map) || s->keyframe) {
- for (y = 0; y < h4; y++)
- memset(&s->segmentation_map[(y + row) * 8 * s->sb_cols + col],
- b->seg_id, w4);
- }
-
- b->skip = s->segmentation.enabled &&
- s->segmentation.feat[b->seg_id].skip_enabled;
- if (!b->skip) {
- int c = s->left_skip_ctx[row7] + s->above_skip_ctx[col];
- b->skip = vp56_rac_get_prob(&s->c, s->prob.p.skip[c]);
- s->counts.skip[c][b->skip]++;
- }
-
- if (s->keyframe || s->intraonly) {
- b->intra = 1;
- } else if (s->segmentation.feat[b->seg_id].ref_enabled) {
- b->intra = !s->segmentation.feat[b->seg_id].ref_val;
- } else {
- int c, bit;
-
- if (have_a && have_l) {
- c = s->above_intra_ctx[col] + s->left_intra_ctx[row7];
- c += (c == 2);
- } else {
- c = have_a ? 2 * s->above_intra_ctx[col] :
- have_l ? 2 * s->left_intra_ctx[row7] : 0;
- }
- bit = vp56_rac_get_prob(&s->c, s->prob.p.intra[c]);
- s->counts.intra[c][bit]++;
- b->intra = !bit;
- }
-
- if ((b->intra || !b->skip) && s->txfmmode == TX_SWITCHABLE) {
- int c;
- if (have_a) {
- if (have_l) {
- c = (s->above_skip_ctx[col] ? max_tx :
- s->above_txfm_ctx[col]) +
- (s->left_skip_ctx[row7] ? max_tx :
- s->left_txfm_ctx[row7]) > max_tx;
- } else {
- c = s->above_skip_ctx[col] ? 1 :
- (s->above_txfm_ctx[col] * 2 > max_tx);
- }
- } else if (have_l) {
- c = s->left_skip_ctx[row7] ? 1 :
- (s->left_txfm_ctx[row7] * 2 > max_tx);
- } else {
- c = 1;
- }
- switch (max_tx) {
- case TX_32X32:
- b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][0]);
- if (b->tx) {
- b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][1]);
- if (b->tx == 2)
- b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx32p[c][2]);
- }
- s->counts.tx32p[c][b->tx]++;
- break;
- case TX_16X16:
- b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx16p[c][0]);
- if (b->tx)
- b->tx += vp56_rac_get_prob(&s->c, s->prob.p.tx16p[c][1]);
- s->counts.tx16p[c][b->tx]++;
- break;
- case TX_8X8:
- b->tx = vp56_rac_get_prob(&s->c, s->prob.p.tx8p[c]);
- s->counts.tx8p[c][b->tx]++;
- break;
- case TX_4X4:
- b->tx = TX_4X4;
- break;
- }
- } else {
- b->tx = FFMIN(max_tx, s->txfmmode);
- }
-
- if (s->keyframe || s->intraonly) {
- uint8_t *a = &s->above_mode_ctx[col * 2];
- uint8_t *l = &s->left_mode_ctx[(row7) << 1];
-
- b->comp = 0;
- if (b->bs > BS_8x8) {
- // FIXME the memory storage intermediates here aren't really
- // necessary, they're just there to make the code slightly
- // simpler for now
- b->mode[0] =
- a[0] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- ff_vp9_default_kf_ymode_probs[a[0]][l[0]]);
- if (b->bs != BS_8x4) {
- b->mode[1] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- ff_vp9_default_kf_ymode_probs[a[1]][b->mode[0]]);
- l[0] =
- a[1] = b->mode[1];
- } else {
- l[0] =
- a[1] =
- b->mode[1] = b->mode[0];
- }
- if (b->bs != BS_4x8) {
- b->mode[2] =
- a[0] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- ff_vp9_default_kf_ymode_probs[a[0]][l[1]]);
- if (b->bs != BS_8x4) {
- b->mode[3] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- ff_vp9_default_kf_ymode_probs[a[1]][b->mode[2]]);
- l[1] =
- a[1] = b->mode[3];
- } else {
- l[1] =
- a[1] =
- b->mode[3] = b->mode[2];
- }
- } else {
- b->mode[2] = b->mode[0];
- l[1] =
- a[1] =
- b->mode[3] = b->mode[1];
- }
- } else {
- b->mode[0] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- ff_vp9_default_kf_ymode_probs[*a][*l]);
- b->mode[3] =
- b->mode[2] =
- b->mode[1] = b->mode[0];
- // FIXME this can probably be optimized
- memset(a, b->mode[0], bwh_tab[0][b->bs][0]);
- memset(l, b->mode[0], bwh_tab[0][b->bs][1]);
- }
- b->uvmode = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- ff_vp9_default_kf_uvmode_probs[b->mode[3]]);
- } else if (b->intra) {
- b->comp = 0;
- if (b->bs > BS_8x8) {
- b->mode[0] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- s->prob.p.y_mode[0]);
- s->counts.y_mode[0][b->mode[0]]++;
- if (b->bs != BS_8x4) {
- b->mode[1] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- s->prob.p.y_mode[0]);
- s->counts.y_mode[0][b->mode[1]]++;
- } else {
- b->mode[1] = b->mode[0];
- }
- if (b->bs != BS_4x8) {
- b->mode[2] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- s->prob.p.y_mode[0]);
- s->counts.y_mode[0][b->mode[2]]++;
- if (b->bs != BS_8x4) {
- b->mode[3] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- s->prob.p.y_mode[0]);
- s->counts.y_mode[0][b->mode[3]]++;
- } else {
- b->mode[3] = b->mode[2];
- }
- } else {
- b->mode[2] = b->mode[0];
- b->mode[3] = b->mode[1];
- }
- } else {
- static const uint8_t size_group[10] = {
- 3, 3, 3, 3, 2, 2, 2, 1, 1, 1
- };
- int sz = size_group[b->bs];
-
- b->mode[0] = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- s->prob.p.y_mode[sz]);
- b->mode[1] =
- b->mode[2] =
- b->mode[3] = b->mode[0];
- s->counts.y_mode[sz][b->mode[3]]++;
- }
- b->uvmode = vp8_rac_get_tree(&s->c, ff_vp9_intramode_tree,
- s->prob.p.uv_mode[b->mode[3]]);
- s->counts.uv_mode[b->mode[3]][b->uvmode]++;
- } else {
- static const uint8_t inter_mode_ctx_lut[14][14] = {
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5 },
- { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 3 },
- { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 1, 3 },
- { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 0, 3 },
- { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 4 },
- };
-
- if (s->segmentation.feat[b->seg_id].ref_enabled) {
- av_assert2(s->segmentation.feat[b->seg_id].ref_val != 0);
- b->comp = 0;
- b->ref[0] = s->segmentation.feat[b->seg_id].ref_val - 1;
- } else {
- // read comp_pred flag
- if (s->comppredmode != PRED_SWITCHABLE) {
- b->comp = s->comppredmode == PRED_COMPREF;
- } else {
- int c;
-
- // FIXME add intra as ref=0xff (or -1) to make these easier?
- if (have_a) {
- if (have_l) {
- if (s->above_comp_ctx[col] && s->left_comp_ctx[row7]) {
- c = 4;
- } else if (s->above_comp_ctx[col]) {
- c = 2 + (s->left_intra_ctx[row7] ||
- s->left_ref_ctx[row7] == s->fixcompref);
- } else if (s->left_comp_ctx[row7]) {
- c = 2 + (s->above_intra_ctx[col] ||
- s->above_ref_ctx[col] == s->fixcompref);
- } else {
- c = (!s->above_intra_ctx[col] &&
- s->above_ref_ctx[col] == s->fixcompref) ^
- (!s->left_intra_ctx[row7] &&
- s->left_ref_ctx[row & 7] == s->fixcompref);
- }
- } else {
- c = s->above_comp_ctx[col] ? 3 :
- (!s->above_intra_ctx[col] && s->above_ref_ctx[col] == s->fixcompref);
- }
- } else if (have_l) {
- c = s->left_comp_ctx[row7] ? 3 :
- (!s->left_intra_ctx[row7] && s->left_ref_ctx[row7] == s->fixcompref);
- } else {
- c = 1;
- }
- b->comp = vp56_rac_get_prob(&s->c, s->prob.p.comp[c]);
- s->counts.comp[c][b->comp]++;
- }
-
- // read actual references
- // FIXME probably cache a few variables here to prevent repetitive
- // memory accesses below
- if (b->comp) { /* two references */
- int fix_idx = s->signbias[s->fixcompref], var_idx = !fix_idx, c, bit;
-
- b->ref[fix_idx] = s->fixcompref;
- // FIXME can this codeblob be replaced by some sort of LUT?
- if (have_a) {
- if (have_l) {
- if (s->above_intra_ctx[col]) {
- if (s->left_intra_ctx[row7]) {
- c = 2;
- } else {
- c = 1 + 2 * (s->left_ref_ctx[row7] != s->varcompref[1]);
- }
- } else if (s->left_intra_ctx[row7]) {
- c = 1 + 2 * (s->above_ref_ctx[col] != s->varcompref[1]);
- } else {
- int refl = s->left_ref_ctx[row7], refa = s->above_ref_ctx[col];
-
- if (refl == refa && refa == s->varcompref[1]) {
- c = 0;
- } else if (!s->left_comp_ctx[row7] && !s->above_comp_ctx[col]) {
- if ((refa == s->fixcompref && refl == s->varcompref[0]) ||
- (refl == s->fixcompref && refa == s->varcompref[0])) {
- c = 4;
- } else {
- c = (refa == refl) ? 3 : 1;
- }
- } else if (!s->left_comp_ctx[row7]) {
- if (refa == s->varcompref[1] && refl != s->varcompref[1]) {
- c = 1;
- } else {
- c = (refl == s->varcompref[1] &&
- refa != s->varcompref[1]) ? 2 : 4;
- }
- } else if (!s->above_comp_ctx[col]) {
- if (refl == s->varcompref[1] && refa != s->varcompref[1]) {
- c = 1;
- } else {
- c = (refa == s->varcompref[1] &&
- refl != s->varcompref[1]) ? 2 : 4;
- }
- } else {
- c = (refl == refa) ? 4 : 2;
- }
- }
- } else {
- if (s->above_intra_ctx[col]) {
- c = 2;
- } else if (s->above_comp_ctx[col]) {
- c = 4 * (s->above_ref_ctx[col] != s->varcompref[1]);
- } else {
- c = 3 * (s->above_ref_ctx[col] != s->varcompref[1]);
- }
- }
- } else if (have_l) {
- if (s->left_intra_ctx[row7]) {
- c = 2;
- } else if (s->left_comp_ctx[row7]) {
- c = 4 * (s->left_ref_ctx[row7] != s->varcompref[1]);
- } else {
- c = 3 * (s->left_ref_ctx[row7] != s->varcompref[1]);
- }
- } else {
- c = 2;
- }
- bit = vp56_rac_get_prob(&s->c, s->prob.p.comp_ref[c]);
- b->ref[var_idx] = s->varcompref[bit];
- s->counts.comp_ref[c][bit]++;
- } else { /* single reference */
- int bit, c;
-
- if (have_a && !s->above_intra_ctx[col]) {
- if (have_l && !s->left_intra_ctx[row7]) {
- if (s->left_comp_ctx[row7]) {
- if (s->above_comp_ctx[col]) {
- c = 1 + (!s->fixcompref || !s->left_ref_ctx[row7] ||
- !s->above_ref_ctx[col]);
- } else {
- c = (3 * !s->above_ref_ctx[col]) +
- (!s->fixcompref || !s->left_ref_ctx[row7]);
- }
- } else if (s->above_comp_ctx[col]) {
- c = (3 * !s->left_ref_ctx[row7]) +
- (!s->fixcompref || !s->above_ref_ctx[col]);
- } else {
- c = 2 * !s->left_ref_ctx[row7] + 2 * !s->above_ref_ctx[col];
- }
- } else if (s->above_intra_ctx[col]) {
- c = 2;
- } else if (s->above_comp_ctx[col]) {
- c = 1 + (!s->fixcompref || !s->above_ref_ctx[col]);
- } else {
- c = 4 * (!s->above_ref_ctx[col]);
- }
- } else if (have_l && !s->left_intra_ctx[row7]) {
- if (s->left_intra_ctx[row7]) {
- c = 2;
- } else if (s->left_comp_ctx[row7]) {
- c = 1 + (!s->fixcompref || !s->left_ref_ctx[row7]);
- } else {
- c = 4 * (!s->left_ref_ctx[row7]);
- }
- } else {
- c = 2;
- }
- bit = vp56_rac_get_prob(&s->c, s->prob.p.single_ref[c][0]);
- s->counts.single_ref[c][0][bit]++;
- if (!bit) {
- b->ref[0] = 0;
- } else {
- // FIXME can this codeblob be replaced by some sort of LUT?
- if (have_a) {
- if (have_l) {
- if (s->left_intra_ctx[row7]) {
- if (s->above_intra_ctx[col]) {
- c = 2;
- } else if (s->above_comp_ctx[col]) {
- c = 1 + 2 * (s->fixcompref == 1 ||
- s->above_ref_ctx[col] == 1);
- } else if (!s->above_ref_ctx[col]) {
- c = 3;
- } else {
- c = 4 * (s->above_ref_ctx[col] == 1);
- }
- } else if (s->above_intra_ctx[col]) {
- if (s->left_intra_ctx[row7]) {
- c = 2;
- } else if (s->left_comp_ctx[row7]) {
- c = 1 + 2 * (s->fixcompref == 1 ||
- s->left_ref_ctx[row7] == 1);
- } else if (!s->left_ref_ctx[row7]) {
- c = 3;
- } else {
- c = 4 * (s->left_ref_ctx[row7] == 1);
- }
- } else if (s->above_comp_ctx[col]) {
- if (s->left_comp_ctx[row7]) {
- if (s->left_ref_ctx[row7] == s->above_ref_ctx[col]) {
- c = 3 * (s->fixcompref == 1 ||
- s->left_ref_ctx[row7] == 1);
- } else {
- c = 2;
- }
- } else if (!s->left_ref_ctx[row7]) {
- c = 1 + 2 * (s->fixcompref == 1 ||
- s->above_ref_ctx[col] == 1);
- } else {
- c = 3 * (s->left_ref_ctx[row7] == 1) +
- (s->fixcompref == 1 || s->above_ref_ctx[col] == 1);
- }
- } else if (s->left_comp_ctx[row7]) {
- if (!s->above_ref_ctx[col]) {
- c = 1 + 2 * (s->fixcompref == 1 ||
- s->left_ref_ctx[row7] == 1);
- } else {
- c = 3 * (s->above_ref_ctx[col] == 1) +
- (s->fixcompref == 1 || s->left_ref_ctx[row7] == 1);
- }
- } else if (!s->above_ref_ctx[col]) {
- if (!s->left_ref_ctx[row7]) {
- c = 3;
- } else {
- c = 4 * (s->left_ref_ctx[row7] == 1);
- }
- } else if (!s->left_ref_ctx[row7]) {
- c = 4 * (s->above_ref_ctx[col] == 1);
- } else {
- c = 2 * (s->left_ref_ctx[row7] == 1) +
- 2 * (s->above_ref_ctx[col] == 1);
- }
- } else {
- if (s->above_intra_ctx[col] ||
- (!s->above_comp_ctx[col] && !s->above_ref_ctx[col])) {
- c = 2;
- } else if (s->above_comp_ctx[col]) {
- c = 3 * (s->fixcompref == 1 || s->above_ref_ctx[col] == 1);
- } else {
- c = 4 * (s->above_ref_ctx[col] == 1);
- }
- }
- } else if (have_l) {
- if (s->left_intra_ctx[row7] ||
- (!s->left_comp_ctx[row7] && !s->left_ref_ctx[row7])) {
- c = 2;
- } else if (s->left_comp_ctx[row7]) {
- c = 3 * (s->fixcompref == 1 || s->left_ref_ctx[row7] == 1);
- } else {
- c = 4 * (s->left_ref_ctx[row7] == 1);
- }
- } else {
- c = 2;
- }
- bit = vp56_rac_get_prob(&s->c, s->prob.p.single_ref[c][1]);
- s->counts.single_ref[c][1][bit]++;
- b->ref[0] = 1 + bit;
- }
- }
- }
-
- if (b->bs <= BS_8x8) {
- if (s->segmentation.feat[b->seg_id].skip_enabled) {
- b->mode[0] =
- b->mode[1] =
- b->mode[2] =
- b->mode[3] = ZEROMV;
- } else {
- static const uint8_t off[10] = {
- 3, 0, 0, 1, 0, 0, 0, 0, 0, 0
- };
-
- // FIXME this needs to use the LUT tables from find_ref_mvs
- // because not all are -1,0/0,-1
- int c = inter_mode_ctx_lut[s->above_mode_ctx[col + off[b->bs]]]
- [s->left_mode_ctx[row7 + off[b->bs]]];
-
- b->mode[0] = vp8_rac_get_tree(&s->c, ff_vp9_inter_mode_tree,
- s->prob.p.mv_mode[c]);
- b->mode[1] =
- b->mode[2] =
- b->mode[3] = b->mode[0];
- s->counts.mv_mode[c][b->mode[0] - 10]++;
- }
- }
-
- if (s->filtermode == FILTER_SWITCHABLE) {
- int c;
-
- if (have_a && s->above_mode_ctx[col] >= NEARESTMV) {
- if (have_l && s->left_mode_ctx[row7] >= NEARESTMV) {
- c = s->above_filter_ctx[col] == s->left_filter_ctx[row7] ?
- s->left_filter_ctx[row7] : 3;
- } else {
- c = s->above_filter_ctx[col];
- }
- } else if (have_l && s->left_mode_ctx[row7] >= NEARESTMV) {
- c = s->left_filter_ctx[row7];
- } else {
- c = 3;
- }
-
- b->filter = vp8_rac_get_tree(&s->c, ff_vp9_filter_tree,
- s->prob.p.filter[c]);
- s->counts.filter[c][b->filter]++;
- } else {
- b->filter = s->filtermode;
- }
-
- if (b->bs > BS_8x8) {
- int c = inter_mode_ctx_lut[s->above_mode_ctx[col]][s->left_mode_ctx[row7]];
-
- b->mode[0] = vp8_rac_get_tree(&s->c, ff_vp9_inter_mode_tree,
- s->prob.p.mv_mode[c]);
- s->counts.mv_mode[c][b->mode[0] - 10]++;
- ff_vp9_fill_mv(s, b->mv[0], b->mode[0], 0);
-
- if (b->bs != BS_8x4) {
- b->mode[1] = vp8_rac_get_tree(&s->c, ff_vp9_inter_mode_tree,
- s->prob.p.mv_mode[c]);
- s->counts.mv_mode[c][b->mode[1] - 10]++;
- ff_vp9_fill_mv(s, b->mv[1], b->mode[1], 1);
- } else {
- b->mode[1] = b->mode[0];
- AV_COPY32(&b->mv[1][0], &b->mv[0][0]);
- AV_COPY32(&b->mv[1][1], &b->mv[0][1]);
- }
-
- if (b->bs != BS_4x8) {
- b->mode[2] = vp8_rac_get_tree(&s->c, ff_vp9_inter_mode_tree,
- s->prob.p.mv_mode[c]);
- s->counts.mv_mode[c][b->mode[2] - 10]++;
- ff_vp9_fill_mv(s, b->mv[2], b->mode[2], 2);
-
- if (b->bs != BS_8x4) {
- b->mode[3] = vp8_rac_get_tree(&s->c, ff_vp9_inter_mode_tree,
- s->prob.p.mv_mode[c]);
- s->counts.mv_mode[c][b->mode[3] - 10]++;
- ff_vp9_fill_mv(s, b->mv[3], b->mode[3], 3);
- } else {
- b->mode[3] = b->mode[2];
- AV_COPY32(&b->mv[3][0], &b->mv[2][0]);
- AV_COPY32(&b->mv[3][1], &b->mv[2][1]);
- }
- } else {
- b->mode[2] = b->mode[0];
- AV_COPY32(&b->mv[2][0], &b->mv[0][0]);
- AV_COPY32(&b->mv[2][1], &b->mv[0][1]);
- b->mode[3] = b->mode[1];
- AV_COPY32(&b->mv[3][0], &b->mv[1][0]);
- AV_COPY32(&b->mv[3][1], &b->mv[1][1]);
- }
- } else {
- ff_vp9_fill_mv(s, b->mv[0], b->mode[0], -1);
- AV_COPY32(&b->mv[1][0], &b->mv[0][0]);
- AV_COPY32(&b->mv[2][0], &b->mv[0][0]);
- AV_COPY32(&b->mv[3][0], &b->mv[0][0]);
- AV_COPY32(&b->mv[1][1], &b->mv[0][1]);
- AV_COPY32(&b->mv[2][1], &b->mv[0][1]);
- AV_COPY32(&b->mv[3][1], &b->mv[0][1]);
- }
- }
-
- // FIXME this can probably be optimized
- memset(&s->above_skip_ctx[col], b->skip, w4);
- memset(&s->left_skip_ctx[row7], b->skip, h4);
- memset(&s->above_txfm_ctx[col], b->tx, w4);
- memset(&s->left_txfm_ctx[row7], b->tx, h4);
- memset(&s->above_partition_ctx[col], above_ctx[b->bs], w4);
- memset(&s->left_partition_ctx[row7], left_ctx[b->bs], h4);
- if (!s->keyframe && !s->intraonly) {
- memset(&s->above_intra_ctx[col], b->intra, w4);
- memset(&s->left_intra_ctx[row7], b->intra, h4);
- memset(&s->above_comp_ctx[col], b->comp, w4);
- memset(&s->left_comp_ctx[row7], b->comp, h4);
- memset(&s->above_mode_ctx[col], b->mode[3], w4);
- memset(&s->left_mode_ctx[row7], b->mode[3], h4);
- if (s->filtermode == FILTER_SWITCHABLE && !b->intra) {
- memset(&s->above_filter_ctx[col], b->filter, w4);
- memset(&s->left_filter_ctx[row7], b->filter, h4);
- b->filter = ff_vp9_filter_lut[b->filter];
- }
- if (b->bs > BS_8x8) {
- int mv0 = AV_RN32A(&b->mv[3][0]), mv1 = AV_RN32A(&b->mv[3][1]);
-
- AV_COPY32(&s->left_mv_ctx[row7 * 2 + 0][0], &b->mv[1][0]);
- AV_COPY32(&s->left_mv_ctx[row7 * 2 + 0][1], &b->mv[1][1]);
- AV_WN32A(&s->left_mv_ctx[row7 * 2 + 1][0], mv0);
- AV_WN32A(&s->left_mv_ctx[row7 * 2 + 1][1], mv1);
- AV_COPY32(&s->above_mv_ctx[col * 2 + 0][0], &b->mv[2][0]);
- AV_COPY32(&s->above_mv_ctx[col * 2 + 0][1], &b->mv[2][1]);
- AV_WN32A(&s->above_mv_ctx[col * 2 + 1][0], mv0);
- AV_WN32A(&s->above_mv_ctx[col * 2 + 1][1], mv1);
- } else {
- int n, mv0 = AV_RN32A(&b->mv[3][0]), mv1 = AV_RN32A(&b->mv[3][1]);
-
- for (n = 0; n < w4 * 2; n++) {
- AV_WN32A(&s->above_mv_ctx[col * 2 + n][0], mv0);
- AV_WN32A(&s->above_mv_ctx[col * 2 + n][1], mv1);
- }
- for (n = 0; n < h4 * 2; n++) {
- AV_WN32A(&s->left_mv_ctx[row7 * 2 + n][0], mv0);
- AV_WN32A(&s->left_mv_ctx[row7 * 2 + n][1], mv1);
- }
- }
-
- if (!b->intra) { // FIXME write 0xff or -1 if intra, so we can use this
- // as a direct check in above branches
- int vref = b->ref[b->comp ? s->signbias[s->varcompref[0]] : 0];
-
- memset(&s->above_ref_ctx[col], vref, w4);
- memset(&s->left_ref_ctx[row7], vref, h4);
- }
- }
-
- // FIXME kinda ugly
- for (y = 0; y < h4; y++) {
- int x, o = (row + y) * s->sb_cols * 8 + col;
-
- if (b->intra) {
- for (x = 0; x < w4; x++) {
- s->mv[0][o + x].ref[0] =
- s->mv[0][o + x].ref[1] = -1;
- }
- } else if (b->comp) {
- for (x = 0; x < w4; x++) {
- s->mv[0][o + x].ref[0] = b->ref[0];
- s->mv[0][o + x].ref[1] = b->ref[1];
- AV_COPY32(&s->mv[0][o + x].mv[0], &b->mv[3][0]);
- AV_COPY32(&s->mv[0][o + x].mv[1], &b->mv[3][1]);
- }
- } else {
- for (x = 0; x < w4; x++) {
- s->mv[0][o + x].ref[0] = b->ref[0];
- s->mv[0][o + x].ref[1] = -1;
- AV_COPY32(&s->mv[0][o + x].mv[0], &b->mv[3][0]);
- }
- }
- }
-}
-
-// FIXME remove tx argument, and merge cnt/eob arguments?
-static int decode_block_coeffs(VP56RangeCoder *c, int16_t *coef, int n_coeffs,
- enum TxfmMode tx, unsigned (*cnt)[6][3],
- unsigned (*eob)[6][2], uint8_t(*p)[6][11],
- int nnz, const int16_t *scan,
- const int16_t(*nb)[2],
- const int16_t *band_counts, const int16_t *qmul)
-{
- int i = 0, band = 0, band_left = band_counts[band];
- uint8_t *tp = p[0][nnz];
- uint8_t cache[1024];
-
- do {
- int val, rc;
-
- val = vp56_rac_get_prob_branchy(c, tp[0]); // eob
- eob[band][nnz][val]++;
- if (!val)
- break;
-
-skip_eob:
- if (!vp56_rac_get_prob_branchy(c, tp[1])) { // zero
- cnt[band][nnz][0]++;
- if (!--band_left)
- band_left = band_counts[++band];
- cache[scan[i]] = 0;
- nnz = (1 + cache[nb[i][0]] + cache[nb[i][1]]) >> 1;
- tp = p[band][nnz];
- if (++i == n_coeffs)
- break; //invalid input; blocks should end with EOB
- goto skip_eob;
- }
-
- rc = scan[i];
- if (!vp56_rac_get_prob_branchy(c, tp[2])) { // one
- cnt[band][nnz][1]++;
- val = 1;
- cache[rc] = 1;
- } else {
- // fill in p[3-10] (model fill) - only once per frame for each pos
- if (!tp[3])
- memcpy(&tp[3], ff_vp9_model_pareto8[tp[2]], 8);
-
- cnt[band][nnz][2]++;
- if (!vp56_rac_get_prob_branchy(c, tp[3])) { // 2, 3, 4
- if (!vp56_rac_get_prob_branchy(c, tp[4])) {
- cache[rc] = val = 2;
- } else {
- val = 3 + vp56_rac_get_prob(c, tp[5]);
- cache[rc] = 3;
- }
- } else if (!vp56_rac_get_prob_branchy(c, tp[6])) { // cat1/2
- cache[rc] = 4;
- if (!vp56_rac_get_prob_branchy(c, tp[7])) {
- val = vp56_rac_get_prob(c, 159) + 5;
- } else {
- val = (vp56_rac_get_prob(c, 165) << 1) + 7;
- val += vp56_rac_get_prob(c, 145);
- }
- } else { // cat 3-6
- cache[rc] = 5;
- if (!vp56_rac_get_prob_branchy(c, tp[8])) {
- if (!vp56_rac_get_prob_branchy(c, tp[9])) {
- val = (vp56_rac_get_prob(c, 173) << 2) + 11;
- val += (vp56_rac_get_prob(c, 148) << 1);
- val += vp56_rac_get_prob(c, 140);
- } else {
- val = (vp56_rac_get_prob(c, 176) << 3) + 19;
- val += (vp56_rac_get_prob(c, 155) << 2);
- val += (vp56_rac_get_prob(c, 140) << 1);
- val += vp56_rac_get_prob(c, 135);
- }
- } else if (!vp56_rac_get_prob_branchy(c, tp[10])) {
- val = (vp56_rac_get_prob(c, 180) << 4) + 35;
- val += (vp56_rac_get_prob(c, 157) << 3);
- val += (vp56_rac_get_prob(c, 141) << 2);
- val += (vp56_rac_get_prob(c, 134) << 1);
- val += vp56_rac_get_prob(c, 130);
- } else {
- val = (vp56_rac_get_prob(c, 254) << 13) + 67;
- val += (vp56_rac_get_prob(c, 254) << 12);
- val += (vp56_rac_get_prob(c, 254) << 11);
- val += (vp56_rac_get_prob(c, 252) << 10);
- val += (vp56_rac_get_prob(c, 249) << 9);
- val += (vp56_rac_get_prob(c, 243) << 8);
- val += (vp56_rac_get_prob(c, 230) << 7);
- val += (vp56_rac_get_prob(c, 196) << 6);
- val += (vp56_rac_get_prob(c, 177) << 5);
- val += (vp56_rac_get_prob(c, 153) << 4);
- val += (vp56_rac_get_prob(c, 140) << 3);
- val += (vp56_rac_get_prob(c, 133) << 2);
- val += (vp56_rac_get_prob(c, 130) << 1);
- val += vp56_rac_get_prob(c, 129);
- }
- }
- }
- if (!--band_left)
- band_left = band_counts[++band];
- if (tx == TX_32X32) // FIXME slow
- coef[rc] = ((vp8_rac_get(c) ? -val : val) * qmul[!!i]) / 2;
- else
- coef[rc] = (vp8_rac_get(c) ? -val : val) * qmul[!!i];
- nnz = (1 + cache[nb[i][0]] + cache[nb[i][1]]) >> 1;
- tp = p[band][nnz];
- } while (++i < n_coeffs);
-
- return i;
-}
-
-static int decode_coeffs(AVCodecContext *avctx)
-{
- VP9Context *s = avctx->priv_data;
- VP9Block *const b = &s->b;
- int row = b->row, col = b->col;
- uint8_t (*p)[6][11] = s->prob.coef[b->tx][0 /* y */][!b->intra];
- unsigned (*c)[6][3] = s->counts.coef[b->tx][0 /* y */][!b->intra];
- unsigned (*e)[6][2] = s->counts.eob[b->tx][0 /* y */][!b->intra];
- int w4 = bwh_tab[1][b->bs][0] << 1, h4 = bwh_tab[1][b->bs][1] << 1;
- int end_x = FFMIN(2 * (s->cols - col), w4);
- int end_y = FFMIN(2 * (s->rows - row), h4);
- int n, pl, x, y, step1d = 1 << b->tx, step = 1 << (b->tx * 2);
- int uvstep1d = 1 << b->uvtx, uvstep = 1 << (b->uvtx * 2), ret;
- int16_t (*qmul)[2] = s->segmentation.feat[b->seg_id].qmul;
- int tx = 4 * s->lossless + b->tx;
- const int16_t **yscans = ff_vp9_scans[tx];
- const int16_t (**ynbs)[2] = ff_vp9_scans_nb[tx];
- const int16_t *uvscan = ff_vp9_scans[b->uvtx][DCT_DCT];
- const int16_t (*uvnb)[2] = ff_vp9_scans_nb[b->uvtx][DCT_DCT];
- uint8_t *a = &s->above_y_nnz_ctx[col * 2];
- uint8_t *l = &s->left_y_nnz_ctx[(row & 7) << 1];
- static const int16_t band_counts[4][8] = {
- { 1, 2, 3, 4, 3, 16 - 13, 0 },
- { 1, 2, 3, 4, 11, 64 - 21, 0 },
- { 1, 2, 3, 4, 11, 256 - 21, 0 },
- { 1, 2, 3, 4, 11, 1024 - 21, 0 },
- };
- const int16_t *y_band_counts = band_counts[b->tx];
- const int16_t *uv_band_counts = band_counts[b->uvtx];
-
- /* y tokens */
- if (b->tx > TX_4X4) { // FIXME slow
- for (y = 0; y < end_y; y += step1d)
- for (x = 1; x < step1d; x++)
- l[y] |= l[y + x];
- for (x = 0; x < end_x; x += step1d)
- for (y = 1; y < step1d; y++)
- a[x] |= a[x + y];
- }
- for (n = 0, y = 0; y < end_y; y += step1d) {
- for (x = 0; x < end_x; x += step1d, n += step) {
- enum TxfmType txtp = ff_vp9_intra_txfm_type[b->mode[b->tx == TX_4X4 &&
- b->bs > BS_8x8 ?
- n : 0]];
- int nnz = a[x] + l[y];
- if ((ret = decode_block_coeffs(&s->c, s->block + 16 * n, 16 * step,
- b->tx, c, e, p, nnz, yscans[txtp],
- ynbs[txtp], y_band_counts,
- qmul[0])) < 0)
- return ret;
- a[x] = l[y] = !!ret;
- if (b->tx > TX_8X8)
- AV_WN16A(&s->eob[n], ret);
- else
- s->eob[n] = ret;
- }
- }
- if (b->tx > TX_4X4) { // FIXME slow
- for (y = 0; y < end_y; y += step1d)
- memset(&l[y + 1], l[y], FFMIN(end_y - y - 1, step1d - 1));
- for (x = 0; x < end_x; x += step1d)
- memset(&a[x + 1], a[x], FFMIN(end_x - x - 1, step1d - 1));
- }
-
- p = s->prob.coef[b->uvtx][1 /* uv */][!b->intra];
- c = s->counts.coef[b->uvtx][1 /* uv */][!b->intra];
- e = s->counts.eob[b->uvtx][1 /* uv */][!b->intra];
- w4 >>= 1;
- h4 >>= 1;
- end_x >>= 1;
- end_y >>= 1;
- for (pl = 0; pl < 2; pl++) {
- a = &s->above_uv_nnz_ctx[pl][col];
- l = &s->left_uv_nnz_ctx[pl][row & 7];
- if (b->uvtx > TX_4X4) { // FIXME slow
- for (y = 0; y < end_y; y += uvstep1d)
- for (x = 1; x < uvstep1d; x++)
- l[y] |= l[y + x];
- for (x = 0; x < end_x; x += uvstep1d)
- for (y = 1; y < uvstep1d; y++)
- a[x] |= a[x + y];
- }
- for (n = 0, y = 0; y < end_y; y += uvstep1d) {
- for (x = 0; x < end_x; x += uvstep1d, n += uvstep) {
- int nnz = a[x] + l[y];
- if ((ret = decode_block_coeffs(&s->c, s->uvblock[pl] + 16 * n,
- 16 * uvstep, b->uvtx, c, e, p,
- nnz, uvscan, uvnb,
- uv_band_counts, qmul[1])) < 0)
- return ret;
- a[x] = l[y] = !!ret;
- if (b->uvtx > TX_8X8)
- AV_WN16A(&s->uveob[pl][n], ret);
- else
- s->uveob[pl][n] = ret;
- }
- }
- if (b->uvtx > TX_4X4) { // FIXME slow
- for (y = 0; y < end_y; y += uvstep1d)
- memset(&l[y + 1], l[y], FFMIN(end_y - y - 1, uvstep1d - 1));
- for (x = 0; x < end_x; x += uvstep1d)
- memset(&a[x + 1], a[x], FFMIN(end_x - x - 1, uvstep1d - 1));
- }
- }
-
- return 0;
-}
-
-static av_always_inline int check_intra_mode(VP9Context *s, int mode,
- uint8_t **a,
- uint8_t *dst_edge,
- ptrdiff_t stride_edge,
- uint8_t *dst_inner,
- ptrdiff_t stride_inner,
- uint8_t *l, int col, int x, int w,
- int row, int y, enum TxfmMode tx,
- int p)
-{
- int have_top = row > 0 || y > 0;
- int have_left = col > s->tiling.tile_col_start || x > 0;
- int have_right = x < w - 1;
- static const uint8_t mode_conv[10][2 /* have_left */][2 /* have_top */] = {
- [VERT_PRED] = { { DC_127_PRED, VERT_PRED },
- { DC_127_PRED, VERT_PRED } },
- [HOR_PRED] = { { DC_129_PRED, DC_129_PRED },
- { HOR_PRED, HOR_PRED } },
- [DC_PRED] = { { DC_128_PRED, TOP_DC_PRED },
- { LEFT_DC_PRED, DC_PRED } },
- [DIAG_DOWN_LEFT_PRED] = { { DC_127_PRED, DIAG_DOWN_LEFT_PRED },
- { DC_127_PRED, DIAG_DOWN_LEFT_PRED } },
- [DIAG_DOWN_RIGHT_PRED] = { { DIAG_DOWN_RIGHT_PRED, DIAG_DOWN_RIGHT_PRED },
- { DIAG_DOWN_RIGHT_PRED, DIAG_DOWN_RIGHT_PRED } },
- [VERT_RIGHT_PRED] = { { VERT_RIGHT_PRED, VERT_RIGHT_PRED },
- { VERT_RIGHT_PRED, VERT_RIGHT_PRED } },
- [HOR_DOWN_PRED] = { { HOR_DOWN_PRED, HOR_DOWN_PRED },
- { HOR_DOWN_PRED, HOR_DOWN_PRED } },
- [VERT_LEFT_PRED] = { { DC_127_PRED, VERT_LEFT_PRED },
- { DC_127_PRED, VERT_LEFT_PRED } },
- [HOR_UP_PRED] = { { DC_129_PRED, DC_129_PRED },
- { HOR_UP_PRED, HOR_UP_PRED } },
- [TM_VP8_PRED] = { { DC_129_PRED, VERT_PRED },
- { HOR_PRED, TM_VP8_PRED } },
- };
- static const struct {
- uint8_t needs_left:1;
- uint8_t needs_top:1;
- uint8_t needs_topleft:1;
- uint8_t needs_topright:1;
- } edges[N_INTRA_PRED_MODES] = {
- [VERT_PRED] = { .needs_top = 1 },
- [HOR_PRED] = { .needs_left = 1 },
- [DC_PRED] = { .needs_top = 1, .needs_left = 1 },
- [DIAG_DOWN_LEFT_PRED] = { .needs_top = 1, .needs_topright = 1 },
- [DIAG_DOWN_RIGHT_PRED] = { .needs_left = 1, .needs_top = 1,
- .needs_topleft = 1 },
- [VERT_RIGHT_PRED] = { .needs_left = 1, .needs_top = 1,
- .needs_topleft = 1 },
- [HOR_DOWN_PRED] = { .needs_left = 1, .needs_top = 1,
- .needs_topleft = 1 },
- [VERT_LEFT_PRED] = { .needs_top = 1, .needs_topright = 1 },
- [HOR_UP_PRED] = { .needs_left = 1 },
- [TM_VP8_PRED] = { .needs_left = 1, .needs_top = 1,
- .needs_topleft = 1 },
- [LEFT_DC_PRED] = { .needs_left = 1 },
- [TOP_DC_PRED] = { .needs_top = 1 },
- [DC_128_PRED] = { 0 },
- [DC_127_PRED] = { 0 },
- [DC_129_PRED] = { 0 }
- };
-
- av_assert2(mode >= 0 && mode < 10);
- mode = mode_conv[mode][have_left][have_top];
- if (edges[mode].needs_top) {
- uint8_t *top = NULL, *topleft = NULL;
- int n_px_need = 4 << tx, n_px_have = (((s->cols - col) << !p) - x) * 4;
- int n_px_need_tr = 0;
-
- if (tx == TX_4X4 && edges[mode].needs_topright && have_right)
- n_px_need_tr = 4;
-
- // if top of sb64-row, use s->intra_pred_data[] instead of
- // dst[-stride] for intra prediction (it contains pre- instead of
- // post-loopfilter data)
- if (have_top) {
- top = !(row & 7) && !y ?
- s->intra_pred_data[p] + col * (8 >> !!p) + x * 4 :
- y == 0 ? &dst_edge[-stride_edge] : &dst_inner[-stride_inner];
- if (have_left)
- topleft = !(row & 7) && !y ?
- s->intra_pred_data[p] + col * (8 >> !!p) + x * 4 :
- y == 0 || x == 0 ? &dst_edge[-stride_edge] :
- &dst_inner[-stride_inner];
- }
-
- if (have_top &&
- (!edges[mode].needs_topleft || (have_left && top == topleft)) &&
- (tx != TX_4X4 || !edges[mode].needs_topright || have_right) &&
- n_px_need + n_px_need_tr <= n_px_have) {
- *a = top;
- } else {
- if (have_top) {
- if (n_px_need <= n_px_have) {
- memcpy(*a, top, n_px_need);
- } else {
- memcpy(*a, top, n_px_have);
- memset(&(*a)[n_px_have], (*a)[n_px_have - 1],
- n_px_need - n_px_have);
- }
- } else {
- memset(*a, 127, n_px_need);
- }
- if (edges[mode].needs_topleft) {
- if (have_left && have_top)
- (*a)[-1] = topleft[-1];
- else
- (*a)[-1] = have_top ? 129 : 127;
- }
- if (tx == TX_4X4 && edges[mode].needs_topright) {
- if (have_top && have_right &&
- n_px_need + n_px_need_tr <= n_px_have) {
- memcpy(&(*a)[4], &top[4], 4);
- } else {
- memset(&(*a)[4], (*a)[3], 4);
- }
- }
- }
- }
- if (edges[mode].needs_left) {
- if (have_left) {
- int i;
- int n_px_need = 4 << tx;
- int n_px_have = (((s->rows - row) << !p) - y) * 4;
- uint8_t *dst = x == 0 ? dst_edge : dst_inner;
- ptrdiff_t stride = x == 0 ? stride_edge : stride_inner;
-
- if (n_px_need <= n_px_have) {
- for (i = 0; i < n_px_need; i++)
- l[i] = dst[i * stride - 1];
- } else {
- for (i = 0; i < n_px_have; i++)
- l[i] = dst[i * stride - 1];
- memset(&l[i], l[i - 1], n_px_need - n_px_have);
- }
- } else {
- memset(l, 129, 4 << tx);
- }
- }
-
- return mode;
-}
-
-static void intra_recon(AVCodecContext *avctx, ptrdiff_t y_off, ptrdiff_t uv_off)
-{
- VP9Context *s = avctx->priv_data;
- VP9Block *const b = &s->b;
- int row = b->row, col = b->col;
- int w4 = bwh_tab[1][b->bs][0] << 1, step1d = 1 << b->tx, n;
- int h4 = bwh_tab[1][b->bs][1] << 1, x, y, step = 1 << (b->tx * 2);
- int end_x = FFMIN(2 * (s->cols - col), w4);
- int end_y = FFMIN(2 * (s->rows - row), h4);
- int tx = 4 * s->lossless + b->tx, uvtx = b->uvtx + 4 * s->lossless;
- int uvstep1d = 1 << b->uvtx, p;
- uint8_t *dst = b->dst[0], *dst_r = s->cur_frame->data[0] + y_off;
-
- for (n = 0, y = 0; y < end_y; y += step1d) {
- uint8_t *ptr = dst, *ptr_r = dst_r;
- for (x = 0; x < end_x;
- x += step1d, ptr += 4 * step1d, ptr_r += 4 * step1d, n += step) {
- int mode = b->mode[b->bs > BS_8x8 && b->tx == TX_4X4 ?
- y * 2 + x : 0];
- LOCAL_ALIGNED_16(uint8_t, a_buf, [48]);
- uint8_t *a = &a_buf[16], l[32];
- enum TxfmType txtp = ff_vp9_intra_txfm_type[mode];
- int eob = b->tx > TX_8X8 ? AV_RN16A(&s->eob[n]) : s->eob[n];
-
- mode = check_intra_mode(s, mode, &a, ptr_r,
- s->cur_frame->linesize[0],
- ptr, b->y_stride, l,
- col, x, w4, row, y, b->tx, 0);
- s->dsp.intra_pred[b->tx][mode](ptr, b->y_stride, l, a);
- if (eob)
- s->dsp.itxfm_add[tx][txtp](ptr, b->y_stride,
- s->block + 16 * n, eob);
- }
- dst_r += 4 * s->cur_frame->linesize[0] * step1d;
- dst += 4 * b->y_stride * step1d;
- }
-
- // U/V
- h4 >>= 1;
- w4 >>= 1;
- end_x >>= 1;
- end_y >>= 1;
- step = 1 << (b->uvtx * 2);
- for (p = 0; p < 2; p++) {
- dst = b->dst[1 + p];
- dst_r = s->cur_frame->data[1 + p] + uv_off;
- for (n = 0, y = 0; y < end_y; y += uvstep1d) {
- uint8_t *ptr = dst, *ptr_r = dst_r;
- for (x = 0; x < end_x;
- x += uvstep1d, ptr += 4 * uvstep1d,
- ptr_r += 4 * uvstep1d, n += step) {
- int mode = b->uvmode;
- LOCAL_ALIGNED_16(uint8_t, a_buf, [48]);
- uint8_t *a = &a_buf[16], l[32];
- int eob = b->uvtx > TX_8X8 ? AV_RN16A(&s->uveob[p][n])
- : s->uveob[p][n];
-
- mode = check_intra_mode(s, mode, &a, ptr_r,
- s->cur_frame->linesize[1],
- ptr, b->uv_stride, l,
- col, x, w4, row, y, b->uvtx, p + 1);
- s->dsp.intra_pred[b->uvtx][mode](ptr, b->uv_stride, l, a);
- if (eob)
- s->dsp.itxfm_add[uvtx][DCT_DCT](ptr, b->uv_stride,
- s->uvblock[p] + 16 * n,
- eob);
- }
- dst_r += 4 * uvstep1d * s->cur_frame->linesize[1];
- dst += 4 * uvstep1d * b->uv_stride;
- }
- }
-}
-
-static av_always_inline void mc_luma_dir(VP9Context *s, vp9_mc_func(*mc)[2],
- uint8_t *dst, ptrdiff_t dst_stride,
- const uint8_t *ref,
- ptrdiff_t ref_stride,
- ptrdiff_t y, ptrdiff_t x,
- const VP56mv *mv,
- int bw, int bh, int w, int h)
-{
- int mx = mv->x, my = mv->y;
-
- y += my >> 3;
- x += mx >> 3;
- ref += y * ref_stride + x;
- mx &= 7;
- my &= 7;
- // FIXME bilinear filter only needs 0/1 pixels, not 3/4
- if (x < !!mx * 3 || y < !!my * 3 ||
- x + !!mx * 4 > w - bw || y + !!my * 4 > h - bh) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
- ref - !!my * 3 * ref_stride - !!mx * 3,
- 80,
- ref_stride,
- bw + !!mx * 7, bh + !!my * 7,
- x - !!mx * 3, y - !!my * 3, w, h);
- ref = s->edge_emu_buffer + !!my * 3 * 80 + !!mx * 3;
- ref_stride = 80;
- }
- mc[!!mx][!!my](dst, ref, dst_stride, ref_stride, bh, mx << 1, my << 1);
-}
-
-static av_always_inline void mc_chroma_dir(VP9Context *s, vp9_mc_func(*mc)[2],
- uint8_t *dst_u, uint8_t *dst_v,
- ptrdiff_t dst_stride,
- const uint8_t *ref_u,
- ptrdiff_t src_stride_u,
- const uint8_t *ref_v,
- ptrdiff_t src_stride_v,
- ptrdiff_t y, ptrdiff_t x,
- const VP56mv *mv,
- int bw, int bh, int w, int h)
-{
- int mx = mv->x, my = mv->y;
-
- y += my >> 4;
- x += mx >> 4;
- ref_u += y * src_stride_u + x;
- ref_v += y * src_stride_v + x;
- mx &= 15;
- my &= 15;
- // FIXME bilinear filter only needs 0/1 pixels, not 3/4
- if (x < !!mx * 3 || y < !!my * 3 ||
- x + !!mx * 4 > w - bw || y + !!my * 4 > h - bh) {
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
- ref_u - !!my * 3 * src_stride_u - !!mx * 3,
- 80,
- src_stride_u,
- bw + !!mx * 7, bh + !!my * 7,
- x - !!mx * 3, y - !!my * 3, w, h);
- ref_u = s->edge_emu_buffer + !!my * 3 * 80 + !!mx * 3;
- mc[!!mx][!!my](dst_u, ref_u, dst_stride, 80, bh, mx, my);
-
- s->vdsp.emulated_edge_mc(s->edge_emu_buffer,
- ref_v - !!my * 3 * src_stride_v - !!mx * 3,
- 80,
- src_stride_v,
- bw + !!mx * 7, bh + !!my * 7,
- x - !!mx * 3, y - !!my * 3, w, h);
- ref_v = s->edge_emu_buffer + !!my * 3 * 80 + !!mx * 3;
- mc[!!mx][!!my](dst_v, ref_v, dst_stride, 80, bh, mx, my);
- } else {
- mc[!!mx][!!my](dst_u, ref_u, dst_stride, src_stride_u, bh, mx, my);
- mc[!!mx][!!my](dst_v, ref_v, dst_stride, src_stride_v, bh, mx, my);
- }
-}
-
-static int inter_recon(AVCodecContext *avctx)
-{
- static const uint8_t bwlog_tab[2][N_BS_SIZES] = {
- { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 },
- { 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4 },
- };
- VP9Context *s = avctx->priv_data;
- VP9Block *const b = &s->b;
- int row = b->row, col = b->col;
- AVFrame *ref1 = s->refs[s->refidx[b->ref[0]]];
- AVFrame *ref2 = b->comp ? s->refs[s->refidx[b->ref[1]]] : NULL;
- int w = avctx->width, h = avctx->height;
- ptrdiff_t ls_y = b->y_stride, ls_uv = b->uv_stride;
-
- if (!ref1->data[0] || (b->comp && !ref2->data[0]))
- return AVERROR_INVALIDDATA;
-
- // y inter pred
- if (b->bs > BS_8x8) {
- if (b->bs == BS_8x4) {
- mc_luma_dir(s, s->dsp.mc[3][b->filter][0], b->dst[0], ls_y,
- ref1->data[0], ref1->linesize[0],
- row << 3, col << 3, &b->mv[0][0], 8, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[3][b->filter][0],
- b->dst[0] + 4 * ls_y, ls_y,
- ref1->data[0], ref1->linesize[0],
- (row << 3) + 4, col << 3, &b->mv[2][0], 8, 4, w, h);
-
- if (b->comp) {
- mc_luma_dir(s, s->dsp.mc[3][b->filter][1], b->dst[0], ls_y,
- ref2->data[0], ref2->linesize[0],
- row << 3, col << 3, &b->mv[0][1], 8, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[3][b->filter][1],
- b->dst[0] + 4 * ls_y, ls_y,
- ref2->data[0], ref2->linesize[0],
- (row << 3) + 4, col << 3, &b->mv[2][1], 8, 4, w, h);
- }
- } else if (b->bs == BS_4x8) {
- mc_luma_dir(s, s->dsp.mc[4][b->filter][0], b->dst[0], ls_y,
- ref1->data[0], ref1->linesize[0],
- row << 3, col << 3, &b->mv[0][0], 4, 8, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][0], b->dst[0] + 4, ls_y,
- ref1->data[0], ref1->linesize[0],
- row << 3, (col << 3) + 4, &b->mv[1][0], 4, 8, w, h);
-
- if (b->comp) {
- mc_luma_dir(s, s->dsp.mc[4][b->filter][1], b->dst[0], ls_y,
- ref2->data[0], ref2->linesize[0],
- row << 3, col << 3, &b->mv[0][1], 4, 8, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][1], b->dst[0] + 4, ls_y,
- ref2->data[0], ref2->linesize[0],
- row << 3, (col << 3) + 4, &b->mv[1][1], 4, 8, w, h);
- }
- } else {
- av_assert2(b->bs == BS_4x4);
-
- // FIXME if two horizontally adjacent blocks have the same MV,
- // do a w8 instead of a w4 call
- mc_luma_dir(s, s->dsp.mc[4][b->filter][0], b->dst[0], ls_y,
- ref1->data[0], ref1->linesize[0],
- row << 3, col << 3, &b->mv[0][0], 4, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][0], b->dst[0] + 4, ls_y,
- ref1->data[0], ref1->linesize[0],
- row << 3, (col << 3) + 4, &b->mv[1][0], 4, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][0],
- b->dst[0] + 4 * ls_y, ls_y,
- ref1->data[0], ref1->linesize[0],
- (row << 3) + 4, col << 3, &b->mv[2][0], 4, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][0],
- b->dst[0] + 4 * ls_y + 4, ls_y,
- ref1->data[0], ref1->linesize[0],
- (row << 3) + 4, (col << 3) + 4, &b->mv[3][0], 4, 4, w, h);
-
- if (b->comp) {
- mc_luma_dir(s, s->dsp.mc[4][b->filter][1], b->dst[0], ls_y,
- ref2->data[0], ref2->linesize[0],
- row << 3, col << 3, &b->mv[0][1], 4, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][1], b->dst[0] + 4, ls_y,
- ref2->data[0], ref2->linesize[0],
- row << 3, (col << 3) + 4, &b->mv[1][1], 4, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][1],
- b->dst[0] + 4 * ls_y, ls_y,
- ref2->data[0], ref2->linesize[0],
- (row << 3) + 4, col << 3, &b->mv[2][1], 4, 4, w, h);
- mc_luma_dir(s, s->dsp.mc[4][b->filter][1],
- b->dst[0] + 4 * ls_y + 4, ls_y,
- ref2->data[0], ref2->linesize[0],
- (row << 3) + 4, (col << 3) + 4, &b->mv[3][1], 4, 4, w, h);
- }
- }
- } else {
- int bwl = bwlog_tab[0][b->bs];
- int bw = bwh_tab[0][b->bs][0] * 4;
- int bh = bwh_tab[0][b->bs][1] * 4;
-
- mc_luma_dir(s, s->dsp.mc[bwl][b->filter][0], b->dst[0], ls_y,
- ref1->data[0], ref1->linesize[0],
- row << 3, col << 3, &b->mv[0][0], bw, bh, w, h);
-
- if (b->comp)
- mc_luma_dir(s, s->dsp.mc[bwl][b->filter][1], b->dst[0], ls_y,
- ref2->data[0], ref2->linesize[0],
- row << 3, col << 3, &b->mv[0][1], bw, bh, w, h);
- }
-
- // uv inter pred
- {
- int bwl = bwlog_tab[1][b->bs];
- int bw = bwh_tab[1][b->bs][0] * 4, bh = bwh_tab[1][b->bs][1] * 4;
- VP56mv mvuv;
-
- w = (w + 1) >> 1;
- h = (h + 1) >> 1;
- if (b->bs > BS_8x8) {
- mvuv.x = ROUNDED_DIV(b->mv[0][0].x + b->mv[1][0].x +
- b->mv[2][0].x + b->mv[3][0].x, 4);
- mvuv.y = ROUNDED_DIV(b->mv[0][0].y + b->mv[1][0].y +
- b->mv[2][0].y + b->mv[3][0].y, 4);
- } else {
- mvuv = b->mv[0][0];
- }
-
- mc_chroma_dir(s, s->dsp.mc[bwl][b->filter][0],
- b->dst[1], b->dst[2], ls_uv,
- ref1->data[1], ref1->linesize[1],
- ref1->data[2], ref1->linesize[2],
- row << 2, col << 2, &mvuv, bw, bh, w, h);
-
- if (b->comp) {
- if (b->bs > BS_8x8) {
- mvuv.x = ROUNDED_DIV(b->mv[0][1].x + b->mv[1][1].x +
- b->mv[2][1].x + b->mv[3][1].x, 4);
- mvuv.y = ROUNDED_DIV(b->mv[0][1].y + b->mv[1][1].y +
- b->mv[2][1].y + b->mv[3][1].y, 4);
- } else {
- mvuv = b->mv[0][1];
- }
- mc_chroma_dir(s, s->dsp.mc[bwl][b->filter][1],
- b->dst[1], b->dst[2], ls_uv,
- ref2->data[1], ref2->linesize[1],
- ref2->data[2], ref2->linesize[2],
- row << 2, col << 2, &mvuv, bw, bh, w, h);
- }
- }
-
- if (!b->skip) {
- /* mostly copied intra_reconn() */
-
- int w4 = bwh_tab[1][b->bs][0] << 1, step1d = 1 << b->tx, n;
- int h4 = bwh_tab[1][b->bs][1] << 1, x, y, step = 1 << (b->tx * 2);
- int end_x = FFMIN(2 * (s->cols - col), w4);
- int end_y = FFMIN(2 * (s->rows - row), h4);
- int tx = 4 * s->lossless + b->tx, uvtx = b->uvtx + 4 * s->lossless;
- int uvstep1d = 1 << b->uvtx, p;
- uint8_t *dst = b->dst[0];
-
- // y itxfm add
- for (n = 0, y = 0; y < end_y; y += step1d) {
- uint8_t *ptr = dst;
- for (x = 0; x < end_x; x += step1d, ptr += 4 * step1d, n += step) {
- int eob = b->tx > TX_8X8 ? AV_RN16A(&s->eob[n]) : s->eob[n];
-
- if (eob)
- s->dsp.itxfm_add[tx][DCT_DCT](ptr, b->y_stride,
- s->block + 16 * n, eob);
- }
- dst += 4 * b->y_stride * step1d;
- }
-
- // uv itxfm add
- h4 >>= 1;
- w4 >>= 1;
- end_x >>= 1;
- end_y >>= 1;
- step = 1 << (b->uvtx * 2);
- for (p = 0; p < 2; p++) {
- dst = b->dst[p + 1];
- for (n = 0, y = 0; y < end_y; y += uvstep1d) {
- uint8_t *ptr = dst;
- for (x = 0; x < end_x; x += uvstep1d, ptr += 4 * uvstep1d, n += step) {
- int eob = b->uvtx > TX_8X8 ? AV_RN16A(&s->uveob[p][n])
- : s->uveob[p][n];
- if (eob)
- s->dsp.itxfm_add[uvtx][DCT_DCT](ptr, b->uv_stride,
- s->uvblock[p] + 16 * n, eob);
- }
- dst += 4 * uvstep1d * b->uv_stride;
- }
- }
- }
- return 0;
-}
-
-static av_always_inline void mask_edges(VP9Filter *lflvl, int is_uv,
- int row_and_7, int col_and_7,
- int w, int h, int col_end, int row_end,
- enum TxfmMode tx, int skip_inter)
-{
- // FIXME I'm pretty sure all loops can be replaced by a single LUT if
- // we make VP9Filter.mask uint64_t (i.e. row/col all single variable)
- // and make the LUT 5-indexed (bl, bp, is_uv, tx and row/col), and then
- // use row_and_7/col_and_7 as shifts (1*col_and_7+8*row_and_7)
-
- // the intended behaviour of the vp9 loopfilter is to work on 8-pixel
- // edges. This means that for UV, we work on two subsampled blocks at
- // a time, and we only use the topleft block's mode information to set
- // things like block strength. Thus, for any block size smaller than
- // 16x16, ignore the odd portion of the block.
- if (tx == TX_4X4 && is_uv) {
- if (h == 1) {
- if (row_and_7 & 1)
- return;
- if (!row_end)
- h += 1;
- }
- if (w == 1) {
- if (col_and_7 & 1)
- return;
- if (!col_end)
- w += 1;
- }
- }
-
- if (tx == TX_4X4 && !skip_inter) {
- int t = 1 << col_and_7, m_col = (t << w) - t, y;
- int m_col_odd = (t << (w - 1)) - t;
-
- // on 32-px edges, use the 8-px wide loopfilter; else, use 4-px wide
- if (is_uv) {
- int m_row_8 = m_col & 0x01, m_row_4 = m_col - m_row_8;
-
- for (y = row_and_7; y < h + row_and_7; y++) {
- int col_mask_id = 2 - !(y & 7);
-
- lflvl->mask[is_uv][0][y][1] |= m_row_8;
- lflvl->mask[is_uv][0][y][2] |= m_row_4;
- // for odd lines, if the odd col is not being filtered,
- // skip odd row also:
- // .---. <-- a
- // | |
- // |___| <-- b
- // ^ ^
- // c d
- //
- // if a/c are even row/col and b/d are odd, and d is skipped,
- // e.g. right edge of size-66x66.webm, then skip b also (bug)
- if ((col_end & 1) && (y & 1)) {
- lflvl->mask[is_uv][1][y][col_mask_id] |= m_col_odd;
- } else {
- lflvl->mask[is_uv][1][y][col_mask_id] |= m_col;
- }
- }
- } else {
- int m_row_8 = m_col & 0x11, m_row_4 = m_col - m_row_8;
-
- for (y = row_and_7; y < h + row_and_7; y++) {
- int col_mask_id = 2 - !(y & 3);
-
- lflvl->mask[is_uv][0][y][1] |= m_row_8; // row edge
- lflvl->mask[is_uv][0][y][2] |= m_row_4;
- lflvl->mask[is_uv][1][y][col_mask_id] |= m_col; // col edge
- lflvl->mask[is_uv][0][y][3] |= m_col;
- lflvl->mask[is_uv][1][y][3] |= m_col;
- }
- }
- } else {
- int y, t = 1 << col_and_7, m_col = (t << w) - t;
-
- if (!skip_inter) {
- int mask_id = (tx == TX_8X8);
- int l2 = tx + is_uv - 1, step1d = 1 << l2;
- static const unsigned masks[4] = { 0xff, 0x55, 0x11, 0x01 };
- int m_row = m_col & masks[l2];
-
- // at odd UV col/row edges tx16/tx32 loopfilter edges, force
- // 8wd loopfilter to prevent going off the visible edge.
- if (is_uv && tx > TX_8X8 && (w ^ (w - 1)) == 1) {
- int m_row_16 = ((t << (w - 1)) - t) & masks[l2];
- int m_row_8 = m_row - m_row_16;
-
- for (y = row_and_7; y < h + row_and_7; y++) {
- lflvl->mask[is_uv][0][y][0] |= m_row_16;
- lflvl->mask[is_uv][0][y][1] |= m_row_8;
- }
- } else {
- for (y = row_and_7; y < h + row_and_7; y++)
- lflvl->mask[is_uv][0][y][mask_id] |= m_row;
- }
-
- if (is_uv && tx > TX_8X8 && (h ^ (h - 1)) == 1) {
- for (y = row_and_7; y < h + row_and_7 - 1; y += step1d)
- lflvl->mask[is_uv][1][y][0] |= m_col;
- if (y - row_and_7 == h - 1)
- lflvl->mask[is_uv][1][y][1] |= m_col;
- } else {
- for (y = row_and_7; y < h + row_and_7; y += step1d)
- lflvl->mask[is_uv][1][y][mask_id] |= m_col;
- }
- } else if (tx != TX_4X4) {
- int mask_id;
-
- mask_id = (tx == TX_8X8) || (is_uv && h == 1);
- lflvl->mask[is_uv][1][row_and_7][mask_id] |= m_col;
- mask_id = (tx == TX_8X8) || (is_uv && w == 1);
- for (y = row_and_7; y < h + row_and_7; y++)
- lflvl->mask[is_uv][0][y][mask_id] |= t;
- } else if (is_uv) {
- int t8 = t & 0x01, t4 = t - t8;
-
- for (y = row_and_7; y < h + row_and_7; y++) {
- lflvl->mask[is_uv][0][y][2] |= t4;
- lflvl->mask[is_uv][0][y][1] |= t8;
- }
- lflvl->mask[is_uv][1][row_and_7][2 - !(row_and_7 & 7)] |= m_col;
- } else {
- int t8 = t & 0x11, t4 = t - t8;
-
- for (y = row_and_7; y < h + row_and_7; y++) {
- lflvl->mask[is_uv][0][y][2] |= t4;
- lflvl->mask[is_uv][0][y][1] |= t8;
- }
- lflvl->mask[is_uv][1][row_and_7][2 - !(row_and_7 & 3)] |= m_col;
- }
- }
-}
-
-int ff_vp9_decode_block(AVCodecContext *avctx, int row, int col,
- VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff,
- enum BlockLevel bl, enum BlockPartition bp)
-{
- VP9Context *s = avctx->priv_data;
- VP9Block *const b = &s->b;
- enum BlockSize bs = bl * 3 + bp;
- int ret, y, w4 = bwh_tab[1][bs][0], h4 = bwh_tab[1][bs][1], lvl;
- int emu[2];
-
- b->row = row;
- b->row7 = row & 7;
- b->col = col;
- b->col7 = col & 7;
-
- s->min_mv.x = -(128 + col * 64);
- s->min_mv.y = -(128 + row * 64);
- s->max_mv.x = 128 + (s->cols - col - w4) * 64;
- s->max_mv.y = 128 + (s->rows - row - h4) * 64;
-
- b->bs = bs;
- decode_mode(s, b);
- b->uvtx = b->tx - (w4 * 2 == (1 << b->tx) || h4 * 2 == (1 << b->tx));
-
- if (!b->skip) {
- if ((ret = decode_coeffs(avctx)) < 0)
- return ret;
- } else {
- int pl;
-
- memset(&s->above_y_nnz_ctx[col * 2], 0, w4 * 2);
- memset(&s->left_y_nnz_ctx[(row & 7) << 1], 0, h4 * 2);
- for (pl = 0; pl < 2; pl++) {
- memset(&s->above_uv_nnz_ctx[pl][col], 0, w4);
- memset(&s->left_uv_nnz_ctx[pl][row & 7], 0, h4);
- }
- }
-
- /* Emulated overhangs if the stride of the target buffer can't hold.
- * This allows to support emu-edge and so on even if we have large
- * block overhangs. */
- emu[0] = (col + w4) * 8 > s->cur_frame->linesize[0] ||
- (row + h4) > s->rows;
- emu[1] = (col + w4) * 4 > s->cur_frame->linesize[1] ||
- (row + h4) > s->rows;
- if (emu[0]) {
- b->dst[0] = s->tmp_y;
- b->y_stride = 64;
- } else {
- b->dst[0] = s->cur_frame->data[0] + yoff;
- b->y_stride = s->cur_frame->linesize[0];
- }
- if (emu[1]) {
- b->dst[1] = s->tmp_uv[0];
- b->dst[2] = s->tmp_uv[1];
- b->uv_stride = 32;
- } else {
- b->dst[1] = s->cur_frame->data[1] + uvoff;
- b->dst[2] = s->cur_frame->data[2] + uvoff;
- b->uv_stride = s->cur_frame->linesize[1];
- }
- if (b->intra) {
- intra_recon(avctx, yoff, uvoff);
- } else {
- if ((ret = inter_recon(avctx)) < 0)
- return ret;
- }
- if (emu[0]) {
- int w = FFMIN(s->cols - col, w4) * 8;
- int h = FFMIN(s->rows - row, h4) * 8;
- int n, o = 0;
-
- for (n = 0; o < w; n++) {
- int bw = 64 >> n;
-
- av_assert2(n <= 4);
- if (w & bw) {
- s->dsp.mc[n][0][0][0][0](s->cur_frame->data[0] + yoff + o,
- s->tmp_y + o,
- s->cur_frame->linesize[0],
- 64, h, 0, 0);
- o += bw;
- }
- }
- }
- if (emu[1]) {
- int w = FFMIN(s->cols - col, w4) * 4;
- int h = FFMIN(s->rows - row, h4) * 4;
- int n, o = 0;
-
- for (n = 1; o < w; n++) {
- int bw = 64 >> n;
-
- av_assert2(n <= 4);
- if (w & bw) {
- s->dsp.mc[n][0][0][0][0](s->cur_frame->data[1] + uvoff + o,
- s->tmp_uv[0] + o,
- s->cur_frame->linesize[1],
- 32, h, 0, 0);
- s->dsp.mc[n][0][0][0][0](s->cur_frame->data[2] + uvoff + o,
- s->tmp_uv[1] + o,
- s->cur_frame->linesize[2],
- 32, h, 0, 0);
- o += bw;
- }
- }
- }
-
- // pick filter level and find edges to apply filter to
- if (s->filter.level &&
- (lvl = s->segmentation.feat[b->seg_id].lflvl[b->intra ? 0 : b->ref[0] + 1]
- [b->mode[3] != ZEROMV]) > 0) {
- int x_end = FFMIN(s->cols - col, w4);
- int y_end = FFMIN(s->rows - row, h4);
- int skip_inter = !b->intra && b->skip;
-
- for (y = 0; y < h4; y++)
- memset(&lflvl->level[((row & 7) + y) * 8 + (col & 7)], lvl, w4);
- mask_edges(lflvl, 0, row & 7, col & 7, x_end, y_end, 0, 0, b->tx, skip_inter);
- mask_edges(lflvl, 1, row & 7, col & 7, x_end, y_end,
- s->cols & 1 && col + w4 >= s->cols ? s->cols & 7 : 0,
- s->rows & 1 && row + h4 >= s->rows ? s->rows & 7 : 0,
- b->uvtx, skip_inter);
-
- if (!s->filter.lim_lut[lvl]) {
- int sharp = s->filter.sharpness;
- int limit = lvl;
-
- if (sharp > 0) {
- limit >>= (sharp + 3) >> 2;
- limit = FFMIN(limit, 9 - sharp);
- }
- limit = FFMAX(limit, 1);
-
- s->filter.lim_lut[lvl] = limit;
- s->filter.mblim_lut[lvl] = 2 * (lvl + 2) + limit;
- }
- }
-
- return 0;
-}
diff --git a/libavcodec/vp9data.c b/libavcodec/vp9data.c
deleted file mode 100644
index 374fa8bb8c..0000000000
--- a/libavcodec/vp9data.c
+++ /dev/null
@@ -1,2133 +0,0 @@
-/*
- * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
- * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "vp9.h"
-#include "vp9data.h"
-
-const int8_t ff_vp9_partition_tree[3][2] = {
- { -PARTITION_NONE, 1 }, // '0'
- { -PARTITION_H, 2 }, // '10'
- { -PARTITION_V, -PARTITION_SPLIT }, // '110', '111'
-};
-
-const uint8_t ff_vp9_default_kf_partition_probs[4][4][3] = {
- { /* 64x64 -> 32x32 */
- { 174, 35, 49 } /* a/l both not split */,
- { 68, 11, 27 } /* a split, l not split */,
- { 57, 15, 9 } /* l split, a not split */,
- { 12, 3, 3 } /* a/l both split */
- }, { /* 32x32 -> 16x16 */
- { 150, 40, 39 } /* a/l both not split */,
- { 78, 12, 26 } /* a split, l not split */,
- { 67, 33, 11 } /* l split, a not split */,
- { 24, 7, 5 } /* a/l both split */,
- }, { /* 16x16 -> 8x8 */
- { 149, 53, 53 } /* a/l both not split */,
- { 94, 20, 48 } /* a split, l not split */,
- { 83, 53, 24 } /* l split, a not split */,
- { 52, 18, 18 } /* a/l both split */,
- }, { /* 8x8 -> 4x4 */
- { 158, 97, 94 } /* a/l both not split */,
- { 93, 24, 99 } /* a split, l not split */,
- { 85, 119, 44 } /* l split, a not split */,
- { 62, 59, 67 } /* a/l both split */,
- },
-};
-
-const int8_t ff_vp9_segmentation_tree[7][2] = {
- { 1, 2 },
- { 3, 4 },
- { 5, 6 },
- { -0, -1 }, // '00x'
- { -2, -3 }, // '01x'
- { -4, -5 }, // '10x'
- { -6, -7 }, // '11x'
-};
-
-const int8_t ff_vp9_intramode_tree[9][2] = {
- { -DC_PRED, 1 }, // '0'
- { -TM_VP8_PRED, 2 }, // '10'
- { -VERT_PRED, 3 }, // '110'
- { 4, 6 },
- { -HOR_PRED, 5 }, // '11100'
- { -DIAG_DOWN_RIGHT_PRED, -VERT_RIGHT_PRED }, // '11101x'
- { -DIAG_DOWN_LEFT_PRED, 7 }, // '11110'
- { -VERT_LEFT_PRED, 8 }, // '111110'
- { -HOR_DOWN_PRED, -HOR_UP_PRED }, // '111111x'
-};
-
-const uint8_t ff_vp9_default_kf_ymode_probs[10][10][9] = {
- { /* above = v */
- { 43, 46, 168, 134, 107, 128, 69, 142, 92 } /* left = v */,
- { 44, 29, 68, 159, 201, 177, 50, 57, 77 } /* left = h */,
- { 63, 36, 126, 146, 123, 158, 60, 90, 96 } /* left = dc */,
- { 58, 38, 76, 114, 97, 172, 78, 133, 92 } /* left = d45 */,
- { 46, 41, 76, 140, 63, 184, 69, 112, 57 } /* left = d135 */,
- { 38, 32, 85, 140, 46, 112, 54, 151, 133 } /* left = d117 */,
- { 39, 27, 61, 131, 110, 175, 44, 75, 136 } /* left = d153 */,
- { 47, 35, 80, 100, 74, 143, 64, 163, 74 } /* left = d63 */,
- { 52, 30, 74, 113, 130, 175, 51, 64, 58 } /* left = d27 */,
- { 36, 61, 116, 114, 128, 162, 80, 125, 82 } /* left = tm */
- }, { /* above = h */
- { 55, 44, 68, 166, 179, 192, 57, 57, 108 } /* left = v */,
- { 42, 26, 11, 199, 241, 228, 23, 15, 85 } /* left = h */,
- { 82, 26, 26, 171, 208, 204, 44, 32, 105 } /* left = dc */,
- { 68, 42, 19, 131, 160, 199, 55, 52, 83 } /* left = d45 */,
- { 58, 50, 25, 139, 115, 232, 39, 52, 118 } /* left = d135 */,
- { 50, 35, 33, 153, 104, 162, 64, 59, 131 } /* left = d117 */,
- { 44, 24, 16, 150, 177, 202, 33, 19, 156 } /* left = d153 */,
- { 53, 49, 21, 110, 116, 168, 59, 80, 76 } /* left = d63 */,
- { 55, 27, 12, 153, 203, 218, 26, 27, 49 } /* left = d27 */,
- { 38, 72, 19, 168, 203, 212, 50, 50, 107 } /* left = tm */
- }, { /* above = dc */
- { 92, 45, 102, 136, 116, 180, 74, 90, 100 } /* left = v */,
- { 73, 32, 19, 187, 222, 215, 46, 34, 100 } /* left = h */,
- { 137, 30, 42, 148, 151, 207, 70, 52, 91 } /* left = dc */,
- { 91, 30, 32, 116, 121, 186, 93, 86, 94 } /* left = d45 */,
- { 72, 35, 36, 149, 68, 206, 68, 63, 105 } /* left = d135 */,
- { 73, 31, 28, 138, 57, 124, 55, 122, 151 } /* left = d117 */,
- { 67, 23, 21, 140, 126, 197, 40, 37, 171 } /* left = d153 */,
- { 74, 32, 27, 107, 86, 160, 63, 134, 102 } /* left = d63 */,
- { 86, 27, 28, 128, 154, 212, 45, 43, 53 } /* left = d27 */,
- { 59, 67, 44, 140, 161, 202, 78, 67, 119 } /* left = tm */
- }, { /* above = d45 */
- { 59, 38, 83, 112, 103, 162, 98, 136, 90 } /* left = v */,
- { 62, 30, 23, 158, 200, 207, 59, 57, 50 } /* left = h */,
- { 103, 26, 36, 129, 132, 201, 83, 80, 93 } /* left = dc */,
- { 67, 30, 29, 84, 86, 191, 102, 91, 59 } /* left = d45 */,
- { 60, 32, 33, 112, 71, 220, 64, 89, 104 } /* left = d135 */,
- { 53, 26, 34, 130, 56, 149, 84, 120, 103 } /* left = d117 */,
- { 53, 21, 23, 133, 109, 210, 56, 77, 172 } /* left = d153 */,
- { 61, 29, 29, 93, 97, 165, 83, 175, 162 } /* left = d63 */,
- { 77, 19, 29, 112, 142, 228, 55, 66, 36 } /* left = d27 */,
- { 47, 47, 43, 114, 137, 181, 100, 99, 95 } /* left = tm */
- }, { /* above = d135 */
- { 53, 40, 55, 139, 69, 183, 61, 80, 110 } /* left = v */,
- { 40, 29, 19, 161, 180, 207, 43, 24, 91 } /* left = h */,
- { 69, 23, 29, 128, 83, 199, 46, 44, 101 } /* left = dc */,
- { 60, 34, 19, 105, 61, 198, 53, 64, 89 } /* left = d45 */,
- { 52, 31, 22, 158, 40, 209, 58, 62, 89 } /* left = d135 */,
- { 44, 31, 29, 147, 46, 158, 56, 102, 198 } /* left = d117 */,
- { 35, 19, 12, 135, 87, 209, 41, 45, 167 } /* left = d153 */,
- { 51, 38, 25, 113, 58, 164, 70, 93, 97 } /* left = d63 */,
- { 55, 25, 21, 118, 95, 215, 38, 39, 66 } /* left = d27 */,
- { 47, 54, 34, 146, 108, 203, 72, 103, 151 } /* left = tm */
- }, { /* above = d117 */
- { 46, 27, 80, 150, 55, 124, 55, 121, 135 } /* left = v */,
- { 36, 23, 27, 165, 149, 166, 54, 64, 118 } /* left = h */,
- { 64, 19, 37, 156, 66, 138, 49, 95, 133 } /* left = dc */,
- { 53, 21, 36, 131, 63, 163, 60, 109, 81 } /* left = d45 */,
- { 40, 26, 35, 154, 40, 185, 51, 97, 123 } /* left = d135 */,
- { 35, 19, 34, 179, 19, 97, 48, 129, 124 } /* left = d117 */,
- { 36, 20, 26, 136, 62, 164, 33, 77, 154 } /* left = d153 */,
- { 45, 26, 28, 129, 45, 129, 49, 147, 123 } /* left = d63 */,
- { 45, 18, 32, 130, 90, 157, 40, 79, 91 } /* left = d27 */,
- { 38, 44, 51, 136, 74, 162, 57, 97, 121 } /* left = tm */
- }, { /* above = d153 */
- { 56, 39, 58, 133, 117, 173, 48, 53, 187 } /* left = v */,
- { 35, 21, 12, 161, 212, 207, 20, 23, 145 } /* left = h */,
- { 75, 17, 22, 136, 138, 185, 32, 34, 166 } /* left = dc */,
- { 56, 29, 19, 117, 109, 181, 55, 68, 112 } /* left = d45 */,
- { 47, 29, 17, 153, 64, 220, 59, 51, 114 } /* left = d135 */,
- { 46, 16, 24, 136, 76, 147, 41, 64, 172 } /* left = d117 */,
- { 34, 17, 11, 108, 152, 187, 13, 15, 209 } /* left = d153 */,
- { 55, 30, 18, 122, 79, 179, 44, 88, 116 } /* left = d63 */,
- { 51, 24, 14, 115, 133, 209, 32, 26, 104 } /* left = d27 */,
- { 37, 49, 25, 129, 168, 164, 41, 54, 148 } /* left = tm */
- }, { /* above = d63 */
- { 48, 34, 86, 101, 92, 146, 78, 179, 134 } /* left = v */,
- { 47, 22, 24, 138, 187, 178, 68, 69, 59 } /* left = h */,
- { 78, 23, 39, 111, 117, 170, 74, 124, 94 } /* left = dc */,
- { 56, 25, 33, 105, 112, 187, 95, 177, 129 } /* left = d45 */,
- { 48, 31, 27, 114, 63, 183, 82, 116, 56 } /* left = d135 */,
- { 43, 28, 37, 121, 63, 123, 61, 192, 169 } /* left = d117 */,
- { 42, 17, 24, 109, 97, 177, 56, 76, 122 } /* left = d153 */,
- { 46, 23, 32, 74, 86, 150, 67, 183, 88 } /* left = d63 */,
- { 58, 18, 28, 105, 139, 182, 70, 92, 63 } /* left = d27 */,
- { 36, 38, 48, 92, 122, 165, 88, 137, 91 } /* left = tm */
- }, { /* above = d27 */
- { 62, 44, 61, 123, 105, 189, 48, 57, 64 } /* left = v */,
- { 47, 25, 17, 175, 222, 220, 24, 30, 86 } /* left = h */,
- { 82, 22, 32, 127, 143, 213, 39, 41, 70 } /* left = dc */,
- { 68, 36, 17, 106, 102, 206, 59, 74, 74 } /* left = d45 */,
- { 57, 39, 23, 151, 68, 216, 55, 63, 58 } /* left = d135 */,
- { 49, 30, 35, 141, 70, 168, 82, 40, 115 } /* left = d117 */,
- { 51, 25, 15, 136, 129, 202, 38, 35, 139 } /* left = d153 */,
- { 59, 39, 19, 114, 75, 180, 77, 104, 42 } /* left = d63 */,
- { 68, 26, 16, 111, 141, 215, 29, 28, 28 } /* left = d27 */,
- { 40, 61, 26, 126, 152, 206, 61, 59, 93 } /* left = tm */
- }, { /* above = tm */
- { 44, 78, 115, 132, 119, 173, 71, 112, 93 } /* left = v */,
- { 39, 38, 21, 184, 227, 206, 42, 32, 64 } /* left = h */,
- { 65, 70, 60, 155, 159, 199, 61, 60, 81 } /* left = dc */,
- { 58, 47, 36, 124, 137, 193, 80, 82, 78 } /* left = d45 */,
- { 49, 50, 35, 144, 95, 205, 63, 78, 59 } /* left = d135 */,
- { 41, 53, 52, 148, 71, 142, 65, 128, 51 } /* left = d117 */,
- { 40, 36, 28, 143, 143, 202, 40, 55, 137 } /* left = d153 */,
- { 42, 44, 44, 104, 105, 164, 64, 130, 80 } /* left = d63 */,
- { 52, 34, 29, 129, 183, 227, 42, 35, 43 } /* left = d27 */,
- { 43, 81, 53, 140, 169, 204, 68, 84, 72 } /* left = tm */
- }
-};
-
-const uint8_t ff_vp9_default_kf_uvmode_probs[10][9] = {
- { 118, 15, 123, 148, 131, 101, 44, 93, 131 } /* y = v */,
- { 113, 12, 23, 188, 226, 142, 26, 32, 125 } /* y = h */,
- { 144, 11, 54, 157, 195, 130, 46, 58, 108 } /* y = dc */,
- { 120, 11, 50, 123, 163, 135, 64, 77, 103 } /* y = d45 */,
- { 113, 9, 36, 155, 111, 157, 32, 44, 161 } /* y = d135 */,
- { 116, 9, 55, 176, 76, 96, 37, 61, 149 } /* y = d117 */,
- { 115, 9, 28, 141, 161, 167, 21, 25, 193 } /* y = d153 */,
- { 116, 12, 64, 120, 140, 125, 49, 115, 121 } /* y = d63 */,
- { 120, 12, 32, 145, 195, 142, 32, 38, 86 } /* y = d27 */,
- { 102, 19, 66, 162, 182, 122, 35, 59, 128 } /* y = tm */
-};
-
-const int8_t ff_vp9_inter_mode_tree[3][2] = {
- { -ZEROMV, 1 }, // '0'
- { -NEARESTMV, 2 }, // '10'
- { -NEARMV, -NEWMV }, // '11x'
-};
-
-const int8_t ff_vp9_filter_tree[2][2] = {
- { -0, 1 }, // '0'
- { -1, -2 }, // '1x'
-};
-
-const enum FilterMode ff_vp9_filter_lut[3] = {
- FILTER_8TAP_REGULAR,
- FILTER_8TAP_SMOOTH,
- FILTER_8TAP_SHARP,
-};
-
-const int16_t ff_vp9_dc_qlookup[256] = {
- 4, 8, 8, 9, 10, 11, 12, 12,
- 13, 14, 15, 16, 17, 18, 19, 19,
- 20, 21, 22, 23, 24, 25, 26, 26,
- 27, 28, 29, 30, 31, 32, 32, 33,
- 34, 35, 36, 37, 38, 38, 39, 40,
- 41, 42, 43, 43, 44, 45, 46, 47,
- 48, 48, 49, 50, 51, 52, 53, 53,
- 54, 55, 56, 57, 57, 58, 59, 60,
- 61, 62, 62, 63, 64, 65, 66, 66,
- 67, 68, 69, 70, 70, 71, 72, 73,
- 74, 74, 75, 76, 77, 78, 78, 79,
- 80, 81, 81, 82, 83, 84, 85, 85,
- 87, 88, 90, 92, 93, 95, 96, 98,
- 99, 101, 102, 104, 105, 107, 108, 110,
- 111, 113, 114, 116, 117, 118, 120, 121,
- 123, 125, 127, 129, 131, 134, 136, 138,
- 140, 142, 144, 146, 148, 150, 152, 154,
- 156, 158, 161, 164, 166, 169, 172, 174,
- 177, 180, 182, 185, 187, 190, 192, 195,
- 199, 202, 205, 208, 211, 214, 217, 220,
- 223, 226, 230, 233, 237, 240, 243, 247,
- 250, 253, 257, 261, 265, 269, 272, 276,
- 280, 284, 288, 292, 296, 300, 304, 309,
- 313, 317, 322, 326, 330, 335, 340, 344,
- 349, 354, 359, 364, 369, 374, 379, 384,
- 389, 395, 400, 406, 411, 417, 423, 429,
- 435, 441, 447, 454, 461, 467, 475, 482,
- 489, 497, 505, 513, 522, 530, 539, 549,
- 559, 569, 579, 590, 602, 614, 626, 640,
- 654, 668, 684, 700, 717, 736, 755, 775,
- 796, 819, 843, 869, 896, 925, 955, 988,
- 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336,
-};
-
-const int16_t ff_vp9_ac_qlookup[256] = {
- 4, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 32, 33, 34, 35, 36, 37, 38,
- 39, 40, 41, 42, 43, 44, 45, 46,
- 47, 48, 49, 50, 51, 52, 53, 54,
- 55, 56, 57, 58, 59, 60, 61, 62,
- 63, 64, 65, 66, 67, 68, 69, 70,
- 71, 72, 73, 74, 75, 76, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86,
- 87, 88, 89, 90, 91, 92, 93, 94,
- 95, 96, 97, 98, 99, 100, 101, 102,
- 104, 106, 108, 110, 112, 114, 116, 118,
- 120, 122, 124, 126, 128, 130, 132, 134,
- 136, 138, 140, 142, 144, 146, 148, 150,
- 152, 155, 158, 161, 164, 167, 170, 173,
- 176, 179, 182, 185, 188, 191, 194, 197,
- 200, 203, 207, 211, 215, 219, 223, 227,
- 231, 235, 239, 243, 247, 251, 255, 260,
- 265, 270, 275, 280, 285, 290, 295, 300,
- 305, 311, 317, 323, 329, 335, 341, 347,
- 353, 359, 366, 373, 380, 387, 394, 401,
- 408, 416, 424, 432, 440, 448, 456, 465,
- 474, 483, 492, 501, 510, 520, 530, 540,
- 550, 560, 571, 582, 593, 604, 615, 627,
- 639, 651, 663, 676, 689, 702, 715, 729,
- 743, 757, 771, 786, 801, 816, 832, 848,
- 864, 881, 898, 915, 933, 951, 969, 988,
- 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151,
- 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343,
- 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567,
- 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
-};
-
-const enum TxfmType ff_vp9_intra_txfm_type[14] = {
- [VERT_PRED] = ADST_DCT,
- [HOR_PRED] = DCT_ADST,
- [DC_PRED] = DCT_DCT,
- [DIAG_DOWN_LEFT_PRED] = DCT_DCT,
- [DIAG_DOWN_RIGHT_PRED] = ADST_ADST,
- [VERT_RIGHT_PRED] = ADST_DCT,
- [HOR_DOWN_PRED] = DCT_ADST,
- [VERT_LEFT_PRED] = ADST_DCT,
- [HOR_UP_PRED] = DCT_ADST,
- [TM_VP8_PRED] = ADST_ADST,
- [NEARESTMV] = DCT_DCT,
- [NEARMV] = DCT_DCT,
- [ZEROMV] = DCT_DCT,
- [NEWMV] = DCT_DCT,
-};
-
-const int16_t ff_vp9_default_scan_4x4[16] = {
- 0, 1, 4, 5,
- 2, 8, 3, 6,
- 12, 9, 7, 10,
- 13, 11, 14, 15,
-};
-
-const int16_t ff_vp9_col_scan_4x4[16] = {
- 0, 1, 2, 4,
- 3, 5, 6, 8,
- 7, 9, 10, 12,
- 13, 11, 14, 15,
-};
-
-const int16_t ff_vp9_row_scan_4x4[16] = {
- 0, 4, 1, 8,
- 5, 12, 9, 2,
- 6, 13, 3, 10,
- 7, 14, 11, 15,
-};
-
-const int16_t ff_vp9_default_scan_8x8[64] = {
- 0, 1, 8, 2, 9, 16, 10, 3,
- 17, 24, 18, 11, 4, 25, 32, 19,
- 12, 26, 5, 33, 20, 27, 40, 13,
- 34, 6, 41, 28, 21, 35, 42, 48,
- 14, 7, 36, 29, 43, 56, 49, 22,
- 15, 37, 50, 44, 57, 30, 23, 51,
- 45, 58, 38, 31, 52, 59, 39, 46,
- 53, 60, 47, 54, 61, 55, 62, 63,
-};
-
-const int16_t ff_vp9_col_scan_8x8[64] = {
- 0, 1, 2, 8, 3, 9, 4, 10,
- 16, 5, 11, 17, 12, 18, 6, 24,
- 19, 13, 25, 7, 26, 20, 32, 14,
- 27, 21, 33, 28, 34, 15, 22, 35,
- 40, 29, 41, 36, 23, 30, 42, 37,
- 48, 43, 31, 44, 49, 38, 50, 56,
- 45, 39, 51, 57, 52, 46, 58, 53,
- 59, 47, 60, 54, 61, 55, 62, 63,
-};
-
-const int16_t ff_vp9_row_scan_8x8[64] = {
- 0, 8, 16, 1, 9, 24, 2, 17,
- 32, 10, 25, 3, 40, 18, 11, 33,
- 26, 19, 4, 48, 41, 34, 12, 27,
- 56, 20, 5, 42, 35, 13, 49, 28,
- 6, 21, 43, 36, 14, 50, 29, 57,
- 7, 44, 22, 37, 51, 15, 58, 30,
- 23, 45, 52, 38, 59, 31, 46, 53,
- 39, 60, 47, 61, 54, 62, 55, 63,
-};
-
-const int16_t ff_vp9_default_scan_16x16[256] = {
- 0, 1, 16, 2, 17, 32, 3, 18, 33, 48, 4, 34, 19, 49, 20, 5,
- 35, 64, 50, 36, 65, 21, 6, 51, 80, 66, 37, 22, 52, 7, 81, 67,
- 38, 82, 53, 23, 96, 68, 8, 83, 97, 54, 39, 69, 112, 24, 98, 84,
- 70, 55, 9, 40, 85, 99, 113, 128, 25, 114, 100, 71, 86, 56, 10, 41,
- 115, 101, 129, 116, 72, 87, 26, 130, 144, 102, 57, 11, 42, 117, 131, 145,
- 88, 103, 27, 73, 132, 118, 146, 58, 160, 12, 43, 133, 147, 104, 89, 119,
- 161, 74, 148, 134, 28, 162, 59, 13, 176, 120, 149, 90, 135, 105, 163, 44,
- 75, 177, 164, 29, 150, 121, 136, 178, 165, 14, 106, 60, 91, 151, 45, 179,
- 192, 137, 166, 122, 76, 180, 152, 30, 61, 15, 107, 167, 181, 193, 92, 208,
- 46, 138, 123, 153, 194, 77, 168, 182, 31, 195, 209, 183, 108, 139, 62, 154,
- 47, 196, 93, 169, 210, 197, 224, 124, 184, 211, 78, 109, 170, 155, 63, 198,
- 212, 185, 225, 240, 140, 94, 199, 125, 79, 213, 226, 171, 186, 156, 214, 200,
- 110, 227, 141, 95, 241, 215, 228, 201, 126, 242, 187, 172, 157, 229, 111, 216,
- 243, 142, 202, 230, 127, 217, 244, 173, 188, 231, 158, 203, 143, 245, 218, 232,
- 189, 246, 159, 174, 233, 247, 219, 204, 175, 190, 248, 234, 205, 220, 249, 191,
- 235, 221, 250, 206, 222, 251, 236, 207, 237, 223, 252, 238, 253, 239, 254, 255,
-};
-
-const int16_t ff_vp9_col_scan_16x16[256] = {
- 0, 1, 2, 3, 16, 4, 17, 5, 18, 6, 19, 32, 20, 7, 33, 21,
- 34, 8, 35, 22, 48, 36, 9, 49, 23, 50, 37, 10, 38, 51, 24, 64,
- 52, 11, 65, 39, 25, 53, 66, 54, 40, 67, 12, 80, 26, 68, 55, 81,
- 41, 69, 13, 27, 82, 56, 70, 83, 42, 14, 84, 96, 71, 28, 57, 85,
- 97, 15, 72, 98, 43, 86, 58, 99, 29, 87, 100, 112, 73, 44, 101, 59,
- 30, 113, 88, 114, 74, 128, 102, 45, 31, 115, 60, 103, 89, 116, 75, 129,
- 117, 46, 104, 90, 61, 130, 118, 131, 132, 105, 76, 47, 119, 144, 91, 62,
- 133, 106, 145, 120, 146, 134, 77, 147, 121, 92, 135, 148, 63, 107, 136, 122,
- 93, 149, 160, 78, 150, 137, 108, 161, 162, 151, 123, 79, 138, 163, 152, 94,
- 164, 109, 165, 153, 124, 139, 176, 166, 95, 177, 167, 110, 154, 178, 125, 179,
- 140, 168, 155, 111, 180, 192, 181, 169, 141, 126, 182, 193, 194, 156, 183, 170,
- 195, 127, 142, 196, 184, 208, 197, 157, 171, 143, 185, 198, 209, 199, 210, 172,
- 158, 186, 211, 224, 212, 200, 240, 159, 213, 225, 187, 201, 173, 226, 214, 215,
- 227, 202, 228, 188, 241, 216, 174, 229, 242, 203, 243, 217, 230, 175, 189, 244,
- 231, 204, 218, 232, 245, 219, 246, 190, 233, 205, 191, 247, 234, 248, 220, 206,
- 249, 235, 221, 207, 250, 236, 222, 251, 223, 237, 238, 252, 239, 253, 254, 255,
-};
-
-const int16_t ff_vp9_row_scan_16x16[256] = {
- 0, 16, 32, 1, 48, 17, 64, 33, 2, 80, 18, 49, 96, 34, 3, 65,
- 19, 112, 50, 81, 35, 4, 128, 66, 20, 97, 51, 82, 5, 144, 36, 67,
- 113, 98, 21, 52, 160, 83, 129, 37, 68, 6, 114, 176, 99, 53, 22, 84,
- 145, 38, 69, 130, 7, 115, 192, 100, 54, 23, 85, 161, 146, 131, 39, 70,
- 208, 116, 8, 101, 177, 55, 86, 24, 162, 147, 132, 71, 224, 117, 40, 102,
- 9, 148, 56, 87, 193, 163, 240, 133, 178, 25, 118, 72, 41, 103, 164, 10,
- 149, 88, 134, 209, 179, 57, 119, 194, 26, 73, 165, 150, 104, 42, 135, 11,
- 180, 120, 89, 225, 195, 58, 27, 210, 151, 181, 166, 74, 43, 105, 12, 136,
- 90, 59, 241, 121, 28, 196, 167, 211, 152, 44, 182, 137, 75, 13, 226, 106,
- 122, 60, 197, 91, 168, 29, 183, 153, 14, 76, 212, 138, 45, 107, 15, 198,
- 92, 227, 169, 30, 123, 154, 61, 242, 184, 213, 139, 46, 77, 31, 108, 170,
- 199, 185, 124, 228, 93, 155, 214, 62, 140, 243, 78, 47, 200, 109, 186, 171,
- 201, 94, 63, 215, 229, 156, 79, 125, 141, 110, 216, 187, 172, 244, 202, 230,
- 217, 95, 157, 126, 245, 111, 142, 231, 188, 127, 158, 218, 173, 232, 246, 233,
- 203, 143, 247, 174, 189, 159, 219, 204, 248, 234, 249, 175, 190, 220, 205, 250,
- 235, 191, 221, 251, 236, 206, 252, 222, 207, 237, 223, 253, 238, 254, 239, 255,
-};
-
-const int16_t ff_vp9_default_scan_32x32[1024] = {
- 0, 1, 32, 2, 33, 64, 3, 34, 65, 4, 96, 35, 66, 5, 36, 97,
- 67, 128, 98, 68, 37, 6, 129, 99, 7, 160, 69, 38, 130, 100, 161, 131,
- 39, 70, 8, 101, 162, 132, 192, 71, 40, 9, 102, 163, 133, 193, 72, 224,
- 103, 41, 164, 10, 194, 134, 165, 73, 104, 135, 225, 42, 195, 11, 256, 166,
- 226, 196, 74, 105, 136, 43, 12, 167, 197, 227, 257, 75, 106, 137, 228, 44,
- 198, 168, 258, 288, 13, 229, 76, 107, 199, 138, 259, 169, 289, 45, 230, 260,
- 200, 108, 14, 170, 139, 320, 290, 77, 231, 261, 46, 201, 140, 291, 109, 232,
- 321, 262, 171, 78, 292, 15, 322, 202, 263, 352, 172, 293, 233, 141, 323, 110,
- 47, 203, 264, 234, 294, 353, 324, 16, 79, 204, 265, 295, 325, 173, 354, 142,
- 235, 384, 48, 296, 111, 266, 355, 326, 80, 17, 205, 236, 174, 356, 385, 327,
- 143, 297, 267, 357, 386, 112, 49, 328, 298, 206, 416, 237, 358, 387, 81, 175,
- 18, 329, 359, 388, 299, 330, 389, 113, 417, 238, 360, 50, 207, 418, 390, 331,
- 19, 448, 361, 82, 419, 391, 239, 51, 362, 420, 114, 449, 480, 421, 83, 363,
- 450, 422, 512, 451, 423, 115, 452, 481, 453, 482, 454, 544, 483, 455, 513, 484,
- 514, 485, 515, 486, 545, 576, 487, 546, 547, 608, 577, 578, 579, 609, 610, 611,
- 20, 144, 268, 392, 516, 640, 21, 52, 145, 176, 269, 300, 393, 424, 517, 548,
- 641, 672, 22, 53, 84, 146, 177, 208, 270, 301, 332, 394, 425, 456, 518, 549,
- 580, 642, 673, 704, 23, 54, 85, 116, 147, 178, 209, 240, 271, 302, 333, 364,
- 395, 426, 457, 488, 519, 550, 581, 612, 643, 674, 705, 736, 55, 86, 117, 179,
- 210, 241, 303, 334, 365, 427, 458, 489, 551, 582, 613, 675, 706, 737, 87, 118,
- 211, 242, 335, 366, 459, 490, 583, 614, 707, 738, 119, 243, 367, 491, 615, 739,
- 24, 148, 272, 396, 520, 644, 768, 25, 56, 149, 180, 273, 304, 397, 428, 521,
- 552, 645, 676, 769, 800, 26, 57, 88, 150, 181, 212, 274, 305, 336, 398, 429,
- 460, 522, 553, 584, 646, 677, 708, 770, 801, 832, 27, 58, 89, 120, 151, 182,
- 213, 244, 275, 306, 337, 368, 399, 430, 461, 492, 523, 554, 585, 616, 647, 678,
- 709, 740, 771, 802, 833, 864, 59, 90, 121, 183, 214, 245, 307, 338, 369, 431,
- 462, 493, 555, 586, 617, 679, 710, 741, 803, 834, 865, 91, 122, 215, 246, 339,
- 370, 463, 494, 587, 618, 711, 742, 835, 866, 123, 247, 371, 495, 619, 743, 867,
- 28, 152, 276, 400, 524, 648, 772, 896, 29, 60, 153, 184, 277, 308, 401, 432,
- 525, 556, 649, 680, 773, 804, 897, 928, 30, 61, 92, 154, 185, 216, 278, 309,
- 340, 402, 433, 464, 526, 557, 588, 650, 681, 712, 774, 805, 836, 898, 929, 960,
- 31, 62, 93, 124, 155, 186, 217, 248, 279, 310, 341, 372, 403, 434, 465, 496,
- 527, 558, 589, 620, 651, 682, 713, 744, 775, 806, 837, 868, 899, 930, 961, 992,
- 63, 94, 125, 187, 218, 249, 311, 342, 373, 435, 466, 497, 559, 590, 621, 683,
- 714, 745, 807, 838, 869, 931, 962, 993, 95, 126, 219, 250, 343, 374, 467, 498,
- 591, 622, 715, 746, 839, 870, 963, 994, 127, 251, 375, 499, 623, 747, 871, 995,
- 156, 280, 404, 528, 652, 776, 900, 157, 188, 281, 312, 405, 436, 529, 560, 653,
- 684, 777, 808, 901, 932, 158, 189, 220, 282, 313, 344, 406, 437, 468, 530, 561,
- 592, 654, 685, 716, 778, 809, 840, 902, 933, 964, 159, 190, 221, 252, 283, 314,
- 345, 376, 407, 438, 469, 500, 531, 562, 593, 624, 655, 686, 717, 748, 779, 810,
- 841, 872, 903, 934, 965, 996, 191, 222, 253, 315, 346, 377, 439, 470, 501, 563,
- 594, 625, 687, 718, 749, 811, 842, 873, 935, 966, 997, 223, 254, 347, 378, 471,
- 502, 595, 626, 719, 750, 843, 874, 967, 998, 255, 379, 503, 627, 751, 875, 999,
- 284, 408, 532, 656, 780, 904, 285, 316, 409, 440, 533, 564, 657, 688, 781, 812,
- 905, 936, 286, 317, 348, 410, 441, 472, 534, 565, 596, 658, 689, 720, 782, 813,
- 844, 906, 937, 968, 287, 318, 349, 380, 411, 442, 473, 504, 535, 566, 597, 628,
- 659, 690, 721, 752, 783, 814, 845, 876, 907, 938, 969, 1000, 319, 350, 381, 443,
- 474, 505, 567, 598, 629, 691, 722, 753, 815, 846, 877, 939, 970, 1001, 351, 382,
- 475, 506, 599, 630, 723, 754, 847, 878, 971, 1002, 383, 507, 631, 755, 879, 1003,
- 412, 536, 660, 784, 908, 413, 444, 537, 568, 661, 692, 785, 816, 909, 940, 414,
- 445, 476, 538, 569, 600, 662, 693, 724, 786, 817, 848, 910, 941, 972, 415, 446,
- 477, 508, 539, 570, 601, 632, 663, 694, 725, 756, 787, 818, 849, 880, 911, 942,
- 973, 1004, 447, 478, 509, 571, 602, 633, 695, 726, 757, 819, 850, 881, 943, 974,
- 1005, 479, 510, 603, 634, 727, 758, 851, 882, 975, 1006, 511, 635, 759, 883, 1007,
- 540, 664, 788, 912, 541, 572, 665, 696, 789, 820, 913, 944, 542, 573, 604, 666,
- 697, 728, 790, 821, 852, 914, 945, 976, 543, 574, 605, 636, 667, 698, 729, 760,
- 791, 822, 853, 884, 915, 946, 977, 1008, 575, 606, 637, 699, 730, 761, 823, 854,
- 885, 947, 978, 1009, 607, 638, 731, 762, 855, 886, 979, 1010, 639, 763, 887, 1011,
- 668, 792, 916, 669, 700, 793, 824, 917, 948, 670, 701, 732, 794, 825, 856, 918,
- 949, 980, 671, 702, 733, 764, 795, 826, 857, 888, 919, 950, 981, 1012, 703, 734,
- 765, 827, 858, 889, 951, 982, 1013, 735, 766, 859, 890, 983, 1014, 767, 891, 1015,
- 796, 920, 797, 828, 921, 952, 798, 829, 860, 922, 953, 984, 799, 830, 861, 892,
- 923, 954, 985, 1016, 831, 862, 893, 955, 986, 1017, 863, 894, 987, 1018, 895, 1019,
- 924, 925, 956, 926, 957, 988, 927, 958, 989, 1020, 959, 990, 1021, 991, 1022, 1023,
-};
-
-const int16_t *ff_vp9_scans[5][4] = {
- {
- ff_vp9_default_scan_4x4, ff_vp9_col_scan_4x4,
- ff_vp9_row_scan_4x4, ff_vp9_default_scan_4x4
- }, {
- ff_vp9_default_scan_8x8, ff_vp9_col_scan_8x8,
- ff_vp9_row_scan_8x8, ff_vp9_default_scan_8x8
- }, {
- ff_vp9_default_scan_16x16, ff_vp9_col_scan_16x16,
- ff_vp9_row_scan_16x16, ff_vp9_default_scan_16x16
- }, {
- ff_vp9_default_scan_32x32, ff_vp9_default_scan_32x32,
- ff_vp9_default_scan_32x32, ff_vp9_default_scan_32x32
- }, { // lossless
- ff_vp9_default_scan_4x4, ff_vp9_default_scan_4x4,
- ff_vp9_default_scan_4x4, ff_vp9_default_scan_4x4
- }
-};
-
-const int16_t ff_vp9_default_scan_4x4_nb[16][2] = {
- { 0, 0 }, { 0, 0 }, { 4, 1 }, { 1, 1 },
- { 4, 4 }, { 2, 2 }, { 5, 2 }, { 8, 8 },
- { 8, 5 }, { 6, 3 }, { 9, 6 }, { 12, 9 },
- { 10, 7 }, { 13, 10 }, { 14, 11 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_col_scan_4x4_nb[16][2] = {
- { 0, 0 }, { 1, 1 }, { 0, 0 }, { 2, 2 },
- { 4, 4 }, { 5, 5 }, { 4, 4 }, { 6, 6 },
- { 8, 8 }, { 9, 9 }, { 8, 8 }, { 12, 12 },
- { 10, 10 }, { 13, 13 }, { 14, 14 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_row_scan_4x4_nb[16][2] = {
- { 0, 0 }, { 0, 0 }, { 4, 4 }, { 1, 1 },
- { 8, 8 }, { 5, 5 }, { 1, 1 }, { 2, 2 },
- { 9, 9 }, { 2, 2 }, { 6, 6 }, { 3, 3 },
- { 10, 10 }, { 7, 7 }, { 11, 11 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_default_scan_8x8_nb[64][2] = {
- { 0, 0 }, { 0, 0 }, { 1, 1 }, { 8, 1 },
- { 8, 8 }, { 9, 2 }, { 2, 2 }, { 16, 9 },
- { 16, 16 }, { 17, 10 }, { 10, 3 }, { 3, 3 },
- { 24, 17 }, { 24, 24 }, { 18, 11 }, { 11, 4 },
- { 25, 18 }, { 4, 4 }, { 32, 25 }, { 19, 12 },
- { 26, 19 }, { 32, 32 }, { 12, 5 }, { 33, 26 },
- { 5, 5 }, { 40, 33 }, { 27, 20 }, { 20, 13 },
- { 34, 27 }, { 41, 34 }, { 40, 40 }, { 13, 6 },
- { 6, 6 }, { 35, 28 }, { 28, 21 }, { 42, 35 },
- { 48, 48 }, { 48, 41 }, { 21, 14 }, { 14, 7 },
- { 36, 29 }, { 49, 42 }, { 43, 36 }, { 56, 49 },
- { 29, 22 }, { 22, 15 }, { 50, 43 }, { 44, 37 },
- { 57, 50 }, { 37, 30 }, { 30, 23 }, { 51, 44 },
- { 58, 51 }, { 38, 31 }, { 45, 38 }, { 52, 45 },
- { 59, 52 }, { 46, 39 }, { 53, 46 }, { 60, 53 },
- { 54, 47 }, { 61, 54 }, { 62, 55 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_col_scan_8x8_nb[64][2] = {
- { 0, 0 }, { 1, 1 }, { 0, 0 }, { 2, 2 },
- { 8, 8 }, { 3, 3 }, { 9, 9 }, { 8, 8 },
- { 4, 4 }, { 10, 10 }, { 16, 16 }, { 11, 11 },
- { 17, 17 }, { 5, 5 }, { 16, 16 }, { 18, 18 },
- { 12, 12 }, { 24, 24 }, { 6, 6 }, { 25, 25 },
- { 19, 19 }, { 24, 24 }, { 13, 13 }, { 26, 26 },
- { 20, 20 }, { 32, 32 }, { 27, 27 }, { 33, 33 },
- { 14, 14 }, { 21, 21 }, { 34, 34 }, { 32, 32 },
- { 28, 28 }, { 40, 40 }, { 35, 35 }, { 22, 22 },
- { 29, 29 }, { 41, 41 }, { 36, 36 }, { 40, 40 },
- { 42, 42 }, { 30, 30 }, { 43, 43 }, { 48, 48 },
- { 37, 37 }, { 49, 49 }, { 48, 48 }, { 44, 44 },
- { 38, 38 }, { 50, 50 }, { 56, 56 }, { 51, 51 },
- { 45, 45 }, { 57, 57 }, { 52, 52 }, { 58, 58 },
- { 46, 46 }, { 59, 59 }, { 53, 53 }, { 60, 60 },
- { 54, 54 }, { 61, 61 }, { 62, 62 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_row_scan_8x8_nb[64][2] = {
- { 0, 0 }, { 8, 8 }, { 0, 0 }, { 1, 1 },
- { 16, 16 }, { 1, 1 }, { 9, 9 }, { 24, 24 },
- { 2, 2 }, { 17, 17 }, { 2, 2 }, { 32, 32 },
- { 10, 10 }, { 3, 3 }, { 25, 25 }, { 18, 18 },
- { 11, 11 }, { 3, 3 }, { 40, 40 }, { 33, 33 },
- { 26, 26 }, { 4, 4 }, { 19, 19 }, { 48, 48 },
- { 12, 12 }, { 4, 4 }, { 34, 34 }, { 27, 27 },
- { 5, 5 }, { 41, 41 }, { 20, 20 }, { 5, 5 },
- { 13, 13 }, { 35, 35 }, { 28, 28 }, { 6, 6 },
- { 42, 42 }, { 21, 21 }, { 49, 49 }, { 6, 6 },
- { 36, 36 }, { 14, 14 }, { 29, 29 }, { 43, 43 },
- { 7, 7 }, { 50, 50 }, { 22, 22 }, { 15, 15 },
- { 37, 37 }, { 44, 44 }, { 30, 30 }, { 51, 51 },
- { 23, 23 }, { 38, 38 }, { 45, 45 }, { 31, 31 },
- { 52, 52 }, { 39, 39 }, { 53, 53 }, { 46, 46 },
- { 54, 54 }, { 47, 47 }, { 55, 55 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_default_scan_16x16_nb[256][2] = {
- { 0, 0 }, { 0, 0 }, { 1, 1 }, { 16, 1 },
- { 16, 16 }, { 2, 2 }, { 17, 2 }, { 32, 17 },
- { 32, 32 }, { 3, 3 }, { 33, 18 }, { 18, 3 },
- { 48, 33 }, { 19, 4 }, { 4, 4 }, { 34, 19 },
- { 48, 48 }, { 49, 34 }, { 35, 20 }, { 64, 49 },
- { 20, 5 }, { 5, 5 }, { 50, 35 }, { 64, 64 },
- { 65, 50 }, { 36, 21 }, { 21, 6 }, { 51, 36 },
- { 6, 6 }, { 80, 65 }, { 66, 51 }, { 37, 22 },
- { 81, 66 }, { 52, 37 }, { 22, 7 }, { 80, 80 },
- { 67, 52 }, { 7, 7 }, { 82, 67 }, { 96, 81 },
- { 53, 38 }, { 38, 23 }, { 68, 53 }, { 96, 96 },
- { 23, 8 }, { 97, 82 }, { 83, 68 }, { 69, 54 },
- { 54, 39 }, { 8, 8 }, { 39, 24 }, { 84, 69 },
- { 98, 83 }, { 112, 97 }, { 112, 112 }, { 24, 9 },
- { 113, 98 }, { 99, 84 }, { 70, 55 }, { 85, 70 },
- { 55, 40 }, { 9, 9 }, { 40, 25 }, { 114, 99 },
- { 100, 85 }, { 128, 113 }, { 115, 100 }, { 71, 56 },
- { 86, 71 }, { 25, 10 }, { 129, 114 }, { 128, 128 },
- { 101, 86 }, { 56, 41 }, { 10, 10 }, { 41, 26 },
- { 116, 101 }, { 130, 115 }, { 144, 129 }, { 87, 72 },
- { 102, 87 }, { 26, 11 }, { 72, 57 }, { 131, 116 },
- { 117, 102 }, { 145, 130 }, { 57, 42 }, { 144, 144 },
- { 11, 11 }, { 42, 27 }, { 132, 117 }, { 146, 131 },
- { 103, 88 }, { 88, 73 }, { 118, 103 }, { 160, 145 },
- { 73, 58 }, { 147, 132 }, { 133, 118 }, { 27, 12 },
- { 161, 146 }, { 58, 43 }, { 12, 12 }, { 160, 160 },
- { 119, 104 }, { 148, 133 }, { 89, 74 }, { 134, 119 },
- { 104, 89 }, { 162, 147 }, { 43, 28 }, { 74, 59 },
- { 176, 161 }, { 163, 148 }, { 28, 13 }, { 149, 134 },
- { 120, 105 }, { 135, 120 }, { 177, 162 }, { 164, 149 },
- { 13, 13 }, { 105, 90 }, { 59, 44 }, { 90, 75 },
- { 150, 135 }, { 44, 29 }, { 178, 163 }, { 176, 176 },
- { 136, 121 }, { 165, 150 }, { 121, 106 }, { 75, 60 },
- { 179, 164 }, { 151, 136 }, { 29, 14 }, { 60, 45 },
- { 14, 14 }, { 106, 91 }, { 166, 151 }, { 180, 165 },
- { 192, 177 }, { 91, 76 }, { 192, 192 }, { 45, 30 },
- { 137, 122 }, { 122, 107 }, { 152, 137 }, { 193, 178 },
- { 76, 61 }, { 167, 152 }, { 181, 166 }, { 30, 15 },
- { 194, 179 }, { 208, 193 }, { 182, 167 }, { 107, 92 },
- { 138, 123 }, { 61, 46 }, { 153, 138 }, { 46, 31 },
- { 195, 180 }, { 92, 77 }, { 168, 153 }, { 209, 194 },
- { 196, 181 }, { 208, 208 }, { 123, 108 }, { 183, 168 },
- { 210, 195 }, { 77, 62 }, { 108, 93 }, { 169, 154 },
- { 154, 139 }, { 62, 47 }, { 197, 182 }, { 211, 196 },
- { 184, 169 }, { 224, 209 }, { 224, 224 }, { 139, 124 },
- { 93, 78 }, { 198, 183 }, { 124, 109 }, { 78, 63 },
- { 212, 197 }, { 225, 210 }, { 170, 155 }, { 185, 170 },
- { 155, 140 }, { 213, 198 }, { 199, 184 }, { 109, 94 },
- { 226, 211 }, { 140, 125 }, { 94, 79 }, { 240, 225 },
- { 214, 199 }, { 227, 212 }, { 200, 185 }, { 125, 110 },
- { 241, 226 }, { 186, 171 }, { 171, 156 }, { 156, 141 },
- { 228, 213 }, { 110, 95 }, { 215, 200 }, { 242, 227 },
- { 141, 126 }, { 201, 186 }, { 229, 214 }, { 126, 111 },
- { 216, 201 }, { 243, 228 }, { 172, 157 }, { 187, 172 },
- { 230, 215 }, { 157, 142 }, { 202, 187 }, { 142, 127 },
- { 244, 229 }, { 217, 202 }, { 231, 216 }, { 188, 173 },
- { 245, 230 }, { 158, 143 }, { 173, 158 }, { 232, 217 },
- { 246, 231 }, { 218, 203 }, { 203, 188 }, { 174, 159 },
- { 189, 174 }, { 247, 232 }, { 233, 218 }, { 204, 189 },
- { 219, 204 }, { 248, 233 }, { 190, 175 }, { 234, 219 },
- { 220, 205 }, { 249, 234 }, { 205, 190 }, { 221, 206 },
- { 250, 235 }, { 235, 220 }, { 206, 191 }, { 236, 221 },
- { 222, 207 }, { 251, 236 }, { 237, 222 }, { 252, 237 },
- { 238, 223 }, { 253, 238 }, { 254, 239 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_col_scan_16x16_nb[256][2] = {
- { 0, 0 }, { 1, 1 }, { 2, 2 }, { 0, 0 },
- { 3, 3 }, { 16, 16 }, { 4, 4 }, { 17, 17 },
- { 5, 5 }, { 18, 18 }, { 16, 16 }, { 19, 19 },
- { 6, 6 }, { 32, 32 }, { 20, 20 }, { 33, 33 },
- { 7, 7 }, { 34, 34 }, { 21, 21 }, { 32, 32 },
- { 35, 35 }, { 8, 8 }, { 48, 48 }, { 22, 22 },
- { 49, 49 }, { 36, 36 }, { 9, 9 }, { 37, 37 },
- { 50, 50 }, { 23, 23 }, { 48, 48 }, { 51, 51 },
- { 10, 10 }, { 64, 64 }, { 38, 38 }, { 24, 24 },
- { 52, 52 }, { 65, 65 }, { 53, 53 }, { 39, 39 },
- { 66, 66 }, { 11, 11 }, { 64, 64 }, { 25, 25 },
- { 67, 67 }, { 54, 54 }, { 80, 80 }, { 40, 40 },
- { 68, 68 }, { 12, 12 }, { 26, 26 }, { 81, 81 },
- { 55, 55 }, { 69, 69 }, { 82, 82 }, { 41, 41 },
- { 13, 13 }, { 83, 83 }, { 80, 80 }, { 70, 70 },
- { 27, 27 }, { 56, 56 }, { 84, 84 }, { 96, 96 },
- { 14, 14 }, { 71, 71 }, { 97, 97 }, { 42, 42 },
- { 85, 85 }, { 57, 57 }, { 98, 98 }, { 28, 28 },
- { 86, 86 }, { 99, 99 }, { 96, 96 }, { 72, 72 },
- { 43, 43 }, { 100, 100 }, { 58, 58 }, { 29, 29 },
- { 112, 112 }, { 87, 87 }, { 113, 113 }, { 73, 73 },
- { 112, 112 }, { 101, 101 }, { 44, 44 }, { 30, 30 },
- { 114, 114 }, { 59, 59 }, { 102, 102 }, { 88, 88 },
- { 115, 115 }, { 74, 74 }, { 128, 128 }, { 116, 116 },
- { 45, 45 }, { 103, 103 }, { 89, 89 }, { 60, 60 },
- { 129, 129 }, { 117, 117 }, { 130, 130 }, { 131, 131 },
- { 104, 104 }, { 75, 75 }, { 46, 46 }, { 118, 118 },
- { 128, 128 }, { 90, 90 }, { 61, 61 }, { 132, 132 },
- { 105, 105 }, { 144, 144 }, { 119, 119 }, { 145, 145 },
- { 133, 133 }, { 76, 76 }, { 146, 146 }, { 120, 120 },
- { 91, 91 }, { 134, 134 }, { 147, 147 }, { 62, 62 },
- { 106, 106 }, { 135, 135 }, { 121, 121 }, { 92, 92 },
- { 148, 148 }, { 144, 144 }, { 77, 77 }, { 149, 149 },
- { 136, 136 }, { 107, 107 }, { 160, 160 }, { 161, 161 },
- { 150, 150 }, { 122, 122 }, { 78, 78 }, { 137, 137 },
- { 162, 162 }, { 151, 151 }, { 93, 93 }, { 163, 163 },
- { 108, 108 }, { 164, 164 }, { 152, 152 }, { 123, 123 },
- { 138, 138 }, { 160, 160 }, { 165, 165 }, { 94, 94 },
- { 176, 176 }, { 166, 166 }, { 109, 109 }, { 153, 153 },
- { 177, 177 }, { 124, 124 }, { 178, 178 }, { 139, 139 },
- { 167, 167 }, { 154, 154 }, { 110, 110 }, { 179, 179 },
- { 176, 176 }, { 180, 180 }, { 168, 168 }, { 140, 140 },
- { 125, 125 }, { 181, 181 }, { 192, 192 }, { 193, 193 },
- { 155, 155 }, { 182, 182 }, { 169, 169 }, { 194, 194 },
- { 126, 126 }, { 141, 141 }, { 195, 195 }, { 183, 183 },
- { 192, 192 }, { 196, 196 }, { 156, 156 }, { 170, 170 },
- { 142, 142 }, { 184, 184 }, { 197, 197 }, { 208, 208 },
- { 198, 198 }, { 209, 209 }, { 171, 171 }, { 157, 157 },
- { 185, 185 }, { 210, 210 }, { 208, 208 }, { 211, 211 },
- { 199, 199 }, { 224, 224 }, { 158, 158 }, { 212, 212 },
- { 224, 224 }, { 186, 186 }, { 200, 200 }, { 172, 172 },
- { 225, 225 }, { 213, 213 }, { 214, 214 }, { 226, 226 },
- { 201, 201 }, { 227, 227 }, { 187, 187 }, { 240, 240 },
- { 215, 215 }, { 173, 173 }, { 228, 228 }, { 241, 241 },
- { 202, 202 }, { 242, 242 }, { 216, 216 }, { 229, 229 },
- { 174, 174 }, { 188, 188 }, { 243, 243 }, { 230, 230 },
- { 203, 203 }, { 217, 217 }, { 231, 231 }, { 244, 244 },
- { 218, 218 }, { 245, 245 }, { 189, 189 }, { 232, 232 },
- { 204, 204 }, { 190, 190 }, { 246, 246 }, { 233, 233 },
- { 247, 247 }, { 219, 219 }, { 205, 205 }, { 248, 248 },
- { 234, 234 }, { 220, 220 }, { 206, 206 }, { 249, 249 },
- { 235, 235 }, { 221, 221 }, { 250, 250 }, { 222, 222 },
- { 236, 236 }, { 237, 237 }, { 251, 251 }, { 238, 238 },
- { 252, 252 }, { 253, 253 }, { 254, 254 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_row_scan_16x16_nb[256][2] = {
- { 0, 0 }, { 16, 16 }, { 0, 0 }, { 32, 32 },
- { 1, 1 }, { 48, 48 }, { 17, 17 }, { 1, 1 },
- { 64, 64 }, { 2, 2 }, { 33, 33 }, { 80, 80 },
- { 18, 18 }, { 2, 2 }, { 49, 49 }, { 3, 3 },
- { 96, 96 }, { 34, 34 }, { 65, 65 }, { 19, 19 },
- { 3, 3 }, { 112, 112 }, { 50, 50 }, { 4, 4 },
- { 81, 81 }, { 35, 35 }, { 66, 66 }, { 4, 4 },
- { 128, 128 }, { 20, 20 }, { 51, 51 }, { 97, 97 },
- { 82, 82 }, { 5, 5 }, { 36, 36 }, { 144, 144 },
- { 67, 67 }, { 113, 113 }, { 21, 21 }, { 52, 52 },
- { 5, 5 }, { 98, 98 }, { 160, 160 }, { 83, 83 },
- { 37, 37 }, { 6, 6 }, { 68, 68 }, { 129, 129 },
- { 22, 22 }, { 53, 53 }, { 114, 114 }, { 6, 6 },
- { 99, 99 }, { 176, 176 }, { 84, 84 }, { 38, 38 },
- { 7, 7 }, { 69, 69 }, { 145, 145 }, { 130, 130 },
- { 115, 115 }, { 23, 23 }, { 54, 54 }, { 192, 192 },
- { 100, 100 }, { 7, 7 }, { 85, 85 }, { 161, 161 },
- { 39, 39 }, { 70, 70 }, { 8, 8 }, { 146, 146 },
- { 131, 131 }, { 116, 116 }, { 55, 55 }, { 208, 208 },
- { 101, 101 }, { 24, 24 }, { 86, 86 }, { 8, 8 },
- { 132, 132 }, { 40, 40 }, { 71, 71 }, { 177, 177 },
- { 147, 147 }, { 224, 224 }, { 117, 117 }, { 162, 162 },
- { 9, 9 }, { 102, 102 }, { 56, 56 }, { 25, 25 },
- { 87, 87 }, { 148, 148 }, { 9, 9 }, { 133, 133 },
- { 72, 72 }, { 118, 118 }, { 193, 193 }, { 163, 163 },
- { 41, 41 }, { 103, 103 }, { 178, 178 }, { 10, 10 },
- { 57, 57 }, { 149, 149 }, { 134, 134 }, { 88, 88 },
- { 26, 26 }, { 119, 119 }, { 10, 10 }, { 164, 164 },
- { 104, 104 }, { 73, 73 }, { 209, 209 }, { 179, 179 },
- { 42, 42 }, { 11, 11 }, { 194, 194 }, { 135, 135 },
- { 165, 165 }, { 150, 150 }, { 58, 58 }, { 27, 27 },
- { 89, 89 }, { 11, 11 }, { 120, 120 }, { 74, 74 },
- { 43, 43 }, { 225, 225 }, { 105, 105 }, { 12, 12 },
- { 180, 180 }, { 151, 151 }, { 195, 195 }, { 136, 136 },
- { 28, 28 }, { 166, 166 }, { 121, 121 }, { 59, 59 },
- { 12, 12 }, { 210, 210 }, { 90, 90 }, { 106, 106 },
- { 44, 44 }, { 181, 181 }, { 75, 75 }, { 152, 152 },
- { 13, 13 }, { 167, 167 }, { 137, 137 }, { 13, 13 },
- { 60, 60 }, { 196, 196 }, { 122, 122 }, { 29, 29 },
- { 91, 91 }, { 14, 14 }, { 182, 182 }, { 76, 76 },
- { 211, 211 }, { 153, 153 }, { 14, 14 }, { 107, 107 },
- { 138, 138 }, { 45, 45 }, { 226, 226 }, { 168, 168 },
- { 197, 197 }, { 123, 123 }, { 30, 30 }, { 61, 61 },
- { 15, 15 }, { 92, 92 }, { 154, 154 }, { 183, 183 },
- { 169, 169 }, { 108, 108 }, { 212, 212 }, { 77, 77 },
- { 139, 139 }, { 198, 198 }, { 46, 46 }, { 124, 124 },
- { 227, 227 }, { 62, 62 }, { 31, 31 }, { 184, 184 },
- { 93, 93 }, { 170, 170 }, { 155, 155 }, { 185, 185 },
- { 78, 78 }, { 47, 47 }, { 199, 199 }, { 213, 213 },
- { 140, 140 }, { 63, 63 }, { 109, 109 }, { 125, 125 },
- { 94, 94 }, { 200, 200 }, { 171, 171 }, { 156, 156 },
- { 228, 228 }, { 186, 186 }, { 214, 214 }, { 201, 201 },
- { 79, 79 }, { 141, 141 }, { 110, 110 }, { 229, 229 },
- { 95, 95 }, { 126, 126 }, { 215, 215 }, { 172, 172 },
- { 111, 111 }, { 142, 142 }, { 202, 202 }, { 157, 157 },
- { 216, 216 }, { 230, 230 }, { 217, 217 }, { 187, 187 },
- { 127, 127 }, { 231, 231 }, { 158, 158 }, { 173, 173 },
- { 143, 143 }, { 203, 203 }, { 188, 188 }, { 232, 232 },
- { 218, 218 }, { 233, 233 }, { 159, 159 }, { 174, 174 },
- { 204, 204 }, { 189, 189 }, { 234, 234 }, { 219, 219 },
- { 175, 175 }, { 205, 205 }, { 235, 235 }, { 220, 220 },
- { 190, 190 }, { 236, 236 }, { 206, 206 }, { 191, 191 },
- { 221, 221 }, { 207, 207 }, { 237, 237 }, { 222, 222 },
- { 238, 238 }, { 223, 223 }, { 239, 239 }, { 0, 0 },
-};
-
-const int16_t ff_vp9_default_scan_32x32_nb[1024][2] = {
- { 0, 0 }, { 0, 0 }, { 1, 1 }, { 32, 1 },
- { 32, 32 }, { 2, 2 }, { 33, 2 }, { 64, 33 },
- { 3, 3 }, { 64, 64 }, { 34, 3 }, { 65, 34 },
- { 4, 4 }, { 35, 4 }, { 96, 65 }, { 66, 35 },
- { 96, 96 }, { 97, 66 }, { 67, 36 }, { 36, 5 },
- { 5, 5 }, { 128, 97 }, { 98, 67 }, { 6, 6 },
- { 128, 128 }, { 68, 37 }, { 37, 6 }, { 129, 98 },
- { 99, 68 }, { 160, 129 }, { 130, 99 }, { 38, 7 },
- { 69, 38 }, { 7, 7 }, { 100, 69 }, { 161, 130 },
- { 131, 100 }, { 160, 160 }, { 70, 39 }, { 39, 8 },
- { 8, 8 }, { 101, 70 }, { 162, 131 }, { 132, 101 },
- { 192, 161 }, { 71, 40 }, { 192, 192 }, { 102, 71 },
- { 40, 9 }, { 163, 132 }, { 9, 9 }, { 193, 162 },
- { 133, 102 }, { 164, 133 }, { 72, 41 }, { 103, 72 },
- { 134, 103 }, { 224, 193 }, { 41, 10 }, { 194, 163 },
- { 10, 10 }, { 224, 224 }, { 165, 134 }, { 225, 194 },
- { 195, 164 }, { 73, 42 }, { 104, 73 }, { 135, 104 },
- { 42, 11 }, { 11, 11 }, { 166, 135 }, { 196, 165 },
- { 226, 195 }, { 256, 225 }, { 74, 43 }, { 105, 74 },
- { 136, 105 }, { 227, 196 }, { 43, 12 }, { 197, 166 },
- { 167, 136 }, { 257, 226 }, { 256, 256 }, { 12, 12 },
- { 228, 197 }, { 75, 44 }, { 106, 75 }, { 198, 167 },
- { 137, 106 }, { 258, 227 }, { 168, 137 }, { 288, 257 },
- { 44, 13 }, { 229, 198 }, { 259, 228 }, { 199, 168 },
- { 107, 76 }, { 13, 13 }, { 169, 138 }, { 138, 107 },
- { 288, 288 }, { 289, 258 }, { 76, 45 }, { 230, 199 },
- { 260, 229 }, { 45, 14 }, { 200, 169 }, { 139, 108 },
- { 290, 259 }, { 108, 77 }, { 231, 200 }, { 320, 289 },
- { 261, 230 }, { 170, 139 }, { 77, 46 }, { 291, 260 },
- { 14, 14 }, { 321, 290 }, { 201, 170 }, { 262, 231 },
- { 320, 320 }, { 171, 140 }, { 292, 261 }, { 232, 201 },
- { 140, 109 }, { 322, 291 }, { 109, 78 }, { 46, 15 },
- { 202, 171 }, { 263, 232 }, { 233, 202 }, { 293, 262 },
- { 352, 321 }, { 323, 292 }, { 15, 15 }, { 78, 47 },
- { 203, 172 }, { 264, 233 }, { 294, 263 }, { 324, 293 },
- { 172, 141 }, { 353, 322 }, { 141, 110 }, { 234, 203 },
- { 352, 352 }, { 47, 16 }, { 295, 264 }, { 110, 79 },
- { 265, 234 }, { 354, 323 }, { 325, 294 }, { 79, 48 },
- { 16, 16 }, { 204, 173 }, { 235, 204 }, { 173, 142 },
- { 355, 324 }, { 384, 353 }, { 326, 295 }, { 142, 111 },
- { 296, 265 }, { 266, 235 }, { 356, 325 }, { 385, 354 },
- { 111, 80 }, { 48, 17 }, { 327, 296 }, { 297, 266 },
- { 205, 174 }, { 384, 384 }, { 236, 205 }, { 357, 326 },
- { 386, 355 }, { 80, 49 }, { 174, 143 }, { 17, 17 },
- { 328, 297 }, { 358, 327 }, { 387, 356 }, { 298, 267 },
- { 329, 298 }, { 388, 357 }, { 112, 81 }, { 416, 385 },
- { 237, 206 }, { 359, 328 }, { 49, 18 }, { 206, 175 },
- { 417, 386 }, { 389, 358 }, { 330, 299 }, { 18, 18 },
- { 416, 416 }, { 360, 329 }, { 81, 50 }, { 418, 387 },
- { 390, 359 }, { 238, 207 }, { 50, 19 }, { 361, 330 },
- { 419, 388 }, { 113, 82 }, { 448, 417 }, { 448, 448 },
- { 420, 389 }, { 82, 51 }, { 362, 331 }, { 449, 418 },
- { 421, 390 }, { 480, 480 }, { 450, 419 }, { 422, 391 },
- { 114, 83 }, { 451, 420 }, { 480, 449 }, { 452, 421 },
- { 481, 450 }, { 453, 422 }, { 512, 512 }, { 482, 451 },
- { 454, 423 }, { 512, 481 }, { 483, 452 }, { 513, 482 },
- { 484, 453 }, { 514, 483 }, { 485, 454 }, { 544, 513 },
- { 544, 544 }, { 486, 455 }, { 545, 514 }, { 546, 515 },
- { 576, 576 }, { 576, 545 }, { 577, 546 }, { 578, 547 },
- { 608, 577 }, { 609, 578 }, { 610, 579 }, { 19, 19 },
- { 143, 112 }, { 267, 236 }, { 391, 360 }, { 515, 484 },
- { 608, 608 }, { 20, 20 }, { 51, 20 }, { 144, 113 },
- { 175, 144 }, { 268, 237 }, { 299, 268 }, { 392, 361 },
- { 423, 392 }, { 516, 485 }, { 547, 516 }, { 640, 609 },
- { 640, 640 }, { 21, 21 }, { 52, 21 }, { 83, 52 },
- { 145, 114 }, { 176, 145 }, { 207, 176 }, { 269, 238 },
- { 300, 269 }, { 331, 300 }, { 393, 362 }, { 424, 393 },
- { 455, 424 }, { 517, 486 }, { 548, 517 }, { 579, 548 },
- { 641, 610 }, { 672, 641 }, { 672, 672 }, { 22, 22 },
- { 53, 22 }, { 84, 53 }, { 115, 84 }, { 146, 115 },
- { 177, 146 }, { 208, 177 }, { 239, 208 }, { 270, 239 },
- { 301, 270 }, { 332, 301 }, { 363, 332 }, { 394, 363 },
- { 425, 394 }, { 456, 425 }, { 487, 456 }, { 518, 487 },
- { 549, 518 }, { 580, 549 }, { 611, 580 }, { 642, 611 },
- { 673, 642 }, { 704, 673 }, { 704, 704 }, { 54, 23 },
- { 85, 54 }, { 116, 85 }, { 178, 147 }, { 209, 178 },
- { 240, 209 }, { 302, 271 }, { 333, 302 }, { 364, 333 },
- { 426, 395 }, { 457, 426 }, { 488, 457 }, { 550, 519 },
- { 581, 550 }, { 612, 581 }, { 674, 643 }, { 705, 674 },
- { 736, 705 }, { 86, 55 }, { 117, 86 }, { 210, 179 },
- { 241, 210 }, { 334, 303 }, { 365, 334 }, { 458, 427 },
- { 489, 458 }, { 582, 551 }, { 613, 582 }, { 706, 675 },
- { 737, 706 }, { 118, 87 }, { 242, 211 }, { 366, 335 },
- { 490, 459 }, { 614, 583 }, { 738, 707 }, { 23, 23 },
- { 147, 116 }, { 271, 240 }, { 395, 364 }, { 519, 488 },
- { 643, 612 }, { 736, 736 }, { 24, 24 }, { 55, 24 },
- { 148, 117 }, { 179, 148 }, { 272, 241 }, { 303, 272 },
- { 396, 365 }, { 427, 396 }, { 520, 489 }, { 551, 520 },
- { 644, 613 }, { 675, 644 }, { 768, 737 }, { 768, 768 },
- { 25, 25 }, { 56, 25 }, { 87, 56 }, { 149, 118 },
- { 180, 149 }, { 211, 180 }, { 273, 242 }, { 304, 273 },
- { 335, 304 }, { 397, 366 }, { 428, 397 }, { 459, 428 },
- { 521, 490 }, { 552, 521 }, { 583, 552 }, { 645, 614 },
- { 676, 645 }, { 707, 676 }, { 769, 738 }, { 800, 769 },
- { 800, 800 }, { 26, 26 }, { 57, 26 }, { 88, 57 },
- { 119, 88 }, { 150, 119 }, { 181, 150 }, { 212, 181 },
- { 243, 212 }, { 274, 243 }, { 305, 274 }, { 336, 305 },
- { 367, 336 }, { 398, 367 }, { 429, 398 }, { 460, 429 },
- { 491, 460 }, { 522, 491 }, { 553, 522 }, { 584, 553 },
- { 615, 584 }, { 646, 615 }, { 677, 646 }, { 708, 677 },
- { 739, 708 }, { 770, 739 }, { 801, 770 }, { 832, 801 },
- { 832, 832 }, { 58, 27 }, { 89, 58 }, { 120, 89 },
- { 182, 151 }, { 213, 182 }, { 244, 213 }, { 306, 275 },
- { 337, 306 }, { 368, 337 }, { 430, 399 }, { 461, 430 },
- { 492, 461 }, { 554, 523 }, { 585, 554 }, { 616, 585 },
- { 678, 647 }, { 709, 678 }, { 740, 709 }, { 802, 771 },
- { 833, 802 }, { 864, 833 }, { 90, 59 }, { 121, 90 },
- { 214, 183 }, { 245, 214 }, { 338, 307 }, { 369, 338 },
- { 462, 431 }, { 493, 462 }, { 586, 555 }, { 617, 586 },
- { 710, 679 }, { 741, 710 }, { 834, 803 }, { 865, 834 },
- { 122, 91 }, { 246, 215 }, { 370, 339 }, { 494, 463 },
- { 618, 587 }, { 742, 711 }, { 866, 835 }, { 27, 27 },
- { 151, 120 }, { 275, 244 }, { 399, 368 }, { 523, 492 },
- { 647, 616 }, { 771, 740 }, { 864, 864 }, { 28, 28 },
- { 59, 28 }, { 152, 121 }, { 183, 152 }, { 276, 245 },
- { 307, 276 }, { 400, 369 }, { 431, 400 }, { 524, 493 },
- { 555, 524 }, { 648, 617 }, { 679, 648 }, { 772, 741 },
- { 803, 772 }, { 896, 865 }, { 896, 896 }, { 29, 29 },
- { 60, 29 }, { 91, 60 }, { 153, 122 }, { 184, 153 },
- { 215, 184 }, { 277, 246 }, { 308, 277 }, { 339, 308 },
- { 401, 370 }, { 432, 401 }, { 463, 432 }, { 525, 494 },
- { 556, 525 }, { 587, 556 }, { 649, 618 }, { 680, 649 },
- { 711, 680 }, { 773, 742 }, { 804, 773 }, { 835, 804 },
- { 897, 866 }, { 928, 897 }, { 928, 928 }, { 30, 30 },
- { 61, 30 }, { 92, 61 }, { 123, 92 }, { 154, 123 },
- { 185, 154 }, { 216, 185 }, { 247, 216 }, { 278, 247 },
- { 309, 278 }, { 340, 309 }, { 371, 340 }, { 402, 371 },
- { 433, 402 }, { 464, 433 }, { 495, 464 }, { 526, 495 },
- { 557, 526 }, { 588, 557 }, { 619, 588 }, { 650, 619 },
- { 681, 650 }, { 712, 681 }, { 743, 712 }, { 774, 743 },
- { 805, 774 }, { 836, 805 }, { 867, 836 }, { 898, 867 },
- { 929, 898 }, { 960, 929 }, { 960, 960 }, { 62, 31 },
- { 93, 62 }, { 124, 93 }, { 186, 155 }, { 217, 186 },
- { 248, 217 }, { 310, 279 }, { 341, 310 }, { 372, 341 },
- { 434, 403 }, { 465, 434 }, { 496, 465 }, { 558, 527 },
- { 589, 558 }, { 620, 589 }, { 682, 651 }, { 713, 682 },
- { 744, 713 }, { 806, 775 }, { 837, 806 }, { 868, 837 },
- { 930, 899 }, { 961, 930 }, { 992, 961 }, { 94, 63 },
- { 125, 94 }, { 218, 187 }, { 249, 218 }, { 342, 311 },
- { 373, 342 }, { 466, 435 }, { 497, 466 }, { 590, 559 },
- { 621, 590 }, { 714, 683 }, { 745, 714 }, { 838, 807 },
- { 869, 838 }, { 962, 931 }, { 993, 962 }, { 126, 95 },
- { 250, 219 }, { 374, 343 }, { 498, 467 }, { 622, 591 },
- { 746, 715 }, { 870, 839 }, { 994, 963 }, { 155, 124 },
- { 279, 248 }, { 403, 372 }, { 527, 496 }, { 651, 620 },
- { 775, 744 }, { 899, 868 }, { 156, 125 }, { 187, 156 },
- { 280, 249 }, { 311, 280 }, { 404, 373 }, { 435, 404 },
- { 528, 497 }, { 559, 528 }, { 652, 621 }, { 683, 652 },
- { 776, 745 }, { 807, 776 }, { 900, 869 }, { 931, 900 },
- { 157, 126 }, { 188, 157 }, { 219, 188 }, { 281, 250 },
- { 312, 281 }, { 343, 312 }, { 405, 374 }, { 436, 405 },
- { 467, 436 }, { 529, 498 }, { 560, 529 }, { 591, 560 },
- { 653, 622 }, { 684, 653 }, { 715, 684 }, { 777, 746 },
- { 808, 777 }, { 839, 808 }, { 901, 870 }, { 932, 901 },
- { 963, 932 }, { 158, 127 }, { 189, 158 }, { 220, 189 },
- { 251, 220 }, { 282, 251 }, { 313, 282 }, { 344, 313 },
- { 375, 344 }, { 406, 375 }, { 437, 406 }, { 468, 437 },
- { 499, 468 }, { 530, 499 }, { 561, 530 }, { 592, 561 },
- { 623, 592 }, { 654, 623 }, { 685, 654 }, { 716, 685 },
- { 747, 716 }, { 778, 747 }, { 809, 778 }, { 840, 809 },
- { 871, 840 }, { 902, 871 }, { 933, 902 }, { 964, 933 },
- { 995, 964 }, { 190, 159 }, { 221, 190 }, { 252, 221 },
- { 314, 283 }, { 345, 314 }, { 376, 345 }, { 438, 407 },
- { 469, 438 }, { 500, 469 }, { 562, 531 }, { 593, 562 },
- { 624, 593 }, { 686, 655 }, { 717, 686 }, { 748, 717 },
- { 810, 779 }, { 841, 810 }, { 872, 841 }, { 934, 903 },
- { 965, 934 }, { 996, 965 }, { 222, 191 }, { 253, 222 },
- { 346, 315 }, { 377, 346 }, { 470, 439 }, { 501, 470 },
- { 594, 563 }, { 625, 594 }, { 718, 687 }, { 749, 718 },
- { 842, 811 }, { 873, 842 }, { 966, 935 }, { 997, 966 },
- { 254, 223 }, { 378, 347 }, { 502, 471 }, { 626, 595 },
- { 750, 719 }, { 874, 843 }, { 998, 967 }, { 283, 252 },
- { 407, 376 }, { 531, 500 }, { 655, 624 }, { 779, 748 },
- { 903, 872 }, { 284, 253 }, { 315, 284 }, { 408, 377 },
- { 439, 408 }, { 532, 501 }, { 563, 532 }, { 656, 625 },
- { 687, 656 }, { 780, 749 }, { 811, 780 }, { 904, 873 },
- { 935, 904 }, { 285, 254 }, { 316, 285 }, { 347, 316 },
- { 409, 378 }, { 440, 409 }, { 471, 440 }, { 533, 502 },
- { 564, 533 }, { 595, 564 }, { 657, 626 }, { 688, 657 },
- { 719, 688 }, { 781, 750 }, { 812, 781 }, { 843, 812 },
- { 905, 874 }, { 936, 905 }, { 967, 936 }, { 286, 255 },
- { 317, 286 }, { 348, 317 }, { 379, 348 }, { 410, 379 },
- { 441, 410 }, { 472, 441 }, { 503, 472 }, { 534, 503 },
- { 565, 534 }, { 596, 565 }, { 627, 596 }, { 658, 627 },
- { 689, 658 }, { 720, 689 }, { 751, 720 }, { 782, 751 },
- { 813, 782 }, { 844, 813 }, { 875, 844 }, { 906, 875 },
- { 937, 906 }, { 968, 937 }, { 999, 968 }, { 318, 287 },
- { 349, 318 }, { 380, 349 }, { 442, 411 }, { 473, 442 },
- { 504, 473 }, { 566, 535 }, { 597, 566 }, { 628, 597 },
- { 690, 659 }, { 721, 690 }, { 752, 721 }, { 814, 783 },
- { 845, 814 }, { 876, 845 }, { 938, 907 }, { 969, 938 },
- { 1000, 969 }, { 350, 319 }, { 381, 350 }, { 474, 443 },
- { 505, 474 }, { 598, 567 }, { 629, 598 }, { 722, 691 },
- { 753, 722 }, { 846, 815 }, { 877, 846 }, { 970, 939 },
- { 1001, 970 }, { 382, 351 }, { 506, 475 }, { 630, 599 },
- { 754, 723 }, { 878, 847 }, { 1002, 971 }, { 411, 380 },
- { 535, 504 }, { 659, 628 }, { 783, 752 }, { 907, 876 },
- { 412, 381 }, { 443, 412 }, { 536, 505 }, { 567, 536 },
- { 660, 629 }, { 691, 660 }, { 784, 753 }, { 815, 784 },
- { 908, 877 }, { 939, 908 }, { 413, 382 }, { 444, 413 },
- { 475, 444 }, { 537, 506 }, { 568, 537 }, { 599, 568 },
- { 661, 630 }, { 692, 661 }, { 723, 692 }, { 785, 754 },
- { 816, 785 }, { 847, 816 }, { 909, 878 }, { 940, 909 },
- { 971, 940 }, { 414, 383 }, { 445, 414 }, { 476, 445 },
- { 507, 476 }, { 538, 507 }, { 569, 538 }, { 600, 569 },
- { 631, 600 }, { 662, 631 }, { 693, 662 }, { 724, 693 },
- { 755, 724 }, { 786, 755 }, { 817, 786 }, { 848, 817 },
- { 879, 848 }, { 910, 879 }, { 941, 910 }, { 972, 941 },
- { 1003, 972 }, { 446, 415 }, { 477, 446 }, { 508, 477 },
- { 570, 539 }, { 601, 570 }, { 632, 601 }, { 694, 663 },
- { 725, 694 }, { 756, 725 }, { 818, 787 }, { 849, 818 },
- { 880, 849 }, { 942, 911 }, { 973, 942 }, { 1004, 973 },
- { 478, 447 }, { 509, 478 }, { 602, 571 }, { 633, 602 },
- { 726, 695 }, { 757, 726 }, { 850, 819 }, { 881, 850 },
- { 974, 943 }, { 1005, 974 }, { 510, 479 }, { 634, 603 },
- { 758, 727 }, { 882, 851 }, { 1006, 975 }, { 539, 508 },
- { 663, 632 }, { 787, 756 }, { 911, 880 }, { 540, 509 },
- { 571, 540 }, { 664, 633 }, { 695, 664 }, { 788, 757 },
- { 819, 788 }, { 912, 881 }, { 943, 912 }, { 541, 510 },
- { 572, 541 }, { 603, 572 }, { 665, 634 }, { 696, 665 },
- { 727, 696 }, { 789, 758 }, { 820, 789 }, { 851, 820 },
- { 913, 882 }, { 944, 913 }, { 975, 944 }, { 542, 511 },
- { 573, 542 }, { 604, 573 }, { 635, 604 }, { 666, 635 },
- { 697, 666 }, { 728, 697 }, { 759, 728 }, { 790, 759 },
- { 821, 790 }, { 852, 821 }, { 883, 852 }, { 914, 883 },
- { 945, 914 }, { 976, 945 }, { 1007, 976 }, { 574, 543 },
- { 605, 574 }, { 636, 605 }, { 698, 667 }, { 729, 698 },
- { 760, 729 }, { 822, 791 }, { 853, 822 }, { 884, 853 },
- { 946, 915 }, { 977, 946 }, { 1008, 977 }, { 606, 575 },
- { 637, 606 }, { 730, 699 }, { 761, 730 }, { 854, 823 },
- { 885, 854 }, { 978, 947 }, { 1009, 978 }, { 638, 607 },
- { 762, 731 }, { 886, 855 }, { 1010, 979 }, { 667, 636 },
- { 791, 760 }, { 915, 884 }, { 668, 637 }, { 699, 668 },
- { 792, 761 }, { 823, 792 }, { 916, 885 }, { 947, 916 },
- { 669, 638 }, { 700, 669 }, { 731, 700 }, { 793, 762 },
- { 824, 793 }, { 855, 824 }, { 917, 886 }, { 948, 917 },
- { 979, 948 }, { 670, 639 }, { 701, 670 }, { 732, 701 },
- { 763, 732 }, { 794, 763 }, { 825, 794 }, { 856, 825 },
- { 887, 856 }, { 918, 887 }, { 949, 918 }, { 980, 949 },
- { 1011, 980 }, { 702, 671 }, { 733, 702 }, { 764, 733 },
- { 826, 795 }, { 857, 826 }, { 888, 857 }, { 950, 919 },
- { 981, 950 }, { 1012, 981 }, { 734, 703 }, { 765, 734 },
- { 858, 827 }, { 889, 858 }, { 982, 951 }, { 1013, 982 },
- { 766, 735 }, { 890, 859 }, { 1014, 983 }, { 795, 764 },
- { 919, 888 }, { 796, 765 }, { 827, 796 }, { 920, 889 },
- { 951, 920 }, { 797, 766 }, { 828, 797 }, { 859, 828 },
- { 921, 890 }, { 952, 921 }, { 983, 952 }, { 798, 767 },
- { 829, 798 }, { 860, 829 }, { 891, 860 }, { 922, 891 },
- { 953, 922 }, { 984, 953 }, { 1015, 984 }, { 830, 799 },
- { 861, 830 }, { 892, 861 }, { 954, 923 }, { 985, 954 },
- { 1016, 985 }, { 862, 831 }, { 893, 862 }, { 986, 955 },
- { 1017, 986 }, { 894, 863 }, { 1018, 987 }, { 923, 892 },
- { 924, 893 }, { 955, 924 }, { 925, 894 }, { 956, 925 },
- { 987, 956 }, { 926, 895 }, { 957, 926 }, { 988, 957 },
- { 1019, 988 }, { 958, 927 }, { 989, 958 }, { 1020, 989 },
- { 990, 959 }, { 1021, 990 }, { 1022, 991 }, { 0, 0 },
-};
-
-const int16_t (*ff_vp9_scans_nb[5][4])[2] = {
- {
- ff_vp9_default_scan_4x4_nb, ff_vp9_col_scan_4x4_nb,
- ff_vp9_row_scan_4x4_nb, ff_vp9_default_scan_4x4_nb
- }, {
- ff_vp9_default_scan_8x8_nb, ff_vp9_col_scan_8x8_nb,
- ff_vp9_row_scan_8x8_nb, ff_vp9_default_scan_8x8_nb
- }, {
- ff_vp9_default_scan_16x16_nb, ff_vp9_col_scan_16x16_nb,
- ff_vp9_row_scan_16x16_nb, ff_vp9_default_scan_16x16_nb
- }, {
- ff_vp9_default_scan_32x32_nb, ff_vp9_default_scan_32x32_nb,
- ff_vp9_default_scan_32x32_nb, ff_vp9_default_scan_32x32_nb
- }, { // lossless
- ff_vp9_default_scan_4x4_nb, ff_vp9_default_scan_4x4_nb,
- ff_vp9_default_scan_4x4_nb, ff_vp9_default_scan_4x4_nb
- }
-};
-
-const uint8_t ff_vp9_model_pareto8[256][8] = {
- { 6, 86, 128, 11, 87, 42, 91, 52 },
- { 3, 86, 128, 6, 86, 23, 88, 29 },
- { 6, 86, 128, 11, 87, 42, 91, 52 },
- { 9, 86, 129, 17, 88, 61, 94, 76 },
- { 12, 86, 129, 22, 88, 77, 97, 93 },
- { 15, 87, 129, 28, 89, 93, 100, 110 },
- { 17, 87, 129, 33, 90, 105, 103, 123 },
- { 20, 88, 130, 38, 91, 118, 106, 136 },
- { 23, 88, 130, 43, 91, 128, 108, 146 },
- { 26, 89, 131, 48, 92, 139, 111, 156 },
- { 28, 89, 131, 53, 93, 147, 114, 163 },
- { 31, 90, 131, 58, 94, 156, 117, 171 },
- { 34, 90, 131, 62, 94, 163, 119, 177 },
- { 37, 90, 132, 66, 95, 171, 122, 184 },
- { 39, 90, 132, 70, 96, 177, 124, 189 },
- { 42, 91, 132, 75, 97, 183, 127, 194 },
- { 44, 91, 132, 79, 97, 188, 129, 198 },
- { 47, 92, 133, 83, 98, 193, 132, 202 },
- { 49, 92, 133, 86, 99, 197, 134, 205 },
- { 52, 93, 133, 90, 100, 201, 137, 208 },
- { 54, 93, 133, 94, 100, 204, 139, 211 },
- { 57, 94, 134, 98, 101, 208, 142, 214 },
- { 59, 94, 134, 101, 102, 211, 144, 216 },
- { 62, 94, 135, 105, 103, 214, 146, 218 },
- { 64, 94, 135, 108, 103, 216, 148, 220 },
- { 66, 95, 135, 111, 104, 219, 151, 222 },
- { 68, 95, 135, 114, 105, 221, 153, 223 },
- { 71, 96, 136, 117, 106, 224, 155, 225 },
- { 73, 96, 136, 120, 106, 225, 157, 226 },
- { 76, 97, 136, 123, 107, 227, 159, 228 },
- { 78, 97, 136, 126, 108, 229, 160, 229 },
- { 80, 98, 137, 129, 109, 231, 162, 231 },
- { 82, 98, 137, 131, 109, 232, 164, 232 },
- { 84, 98, 138, 134, 110, 234, 166, 233 },
- { 86, 98, 138, 137, 111, 235, 168, 234 },
- { 89, 99, 138, 140, 112, 236, 170, 235 },
- { 91, 99, 138, 142, 112, 237, 171, 235 },
- { 93, 100, 139, 145, 113, 238, 173, 236 },
- { 95, 100, 139, 147, 114, 239, 174, 237 },
- { 97, 101, 140, 149, 115, 240, 176, 238 },
- { 99, 101, 140, 151, 115, 241, 177, 238 },
- { 101, 102, 140, 154, 116, 242, 179, 239 },
- { 103, 102, 140, 156, 117, 242, 180, 239 },
- { 105, 103, 141, 158, 118, 243, 182, 240 },
- { 107, 103, 141, 160, 118, 243, 183, 240 },
- { 109, 104, 141, 162, 119, 244, 185, 241 },
- { 111, 104, 141, 164, 119, 244, 186, 241 },
- { 113, 104, 142, 166, 120, 245, 187, 242 },
- { 114, 104, 142, 168, 121, 245, 188, 242 },
- { 116, 105, 143, 170, 122, 246, 190, 243 },
- { 118, 105, 143, 171, 122, 246, 191, 243 },
- { 120, 106, 143, 173, 123, 247, 192, 244 },
- { 121, 106, 143, 175, 124, 247, 193, 244 },
- { 123, 107, 144, 177, 125, 248, 195, 244 },
- { 125, 107, 144, 178, 125, 248, 196, 244 },
- { 127, 108, 145, 180, 126, 249, 197, 245 },
- { 128, 108, 145, 181, 127, 249, 198, 245 },
- { 130, 109, 145, 183, 128, 249, 199, 245 },
- { 132, 109, 145, 184, 128, 249, 200, 245 },
- { 134, 110, 146, 186, 129, 250, 201, 246 },
- { 135, 110, 146, 187, 130, 250, 202, 246 },
- { 137, 111, 147, 189, 131, 251, 203, 246 },
- { 138, 111, 147, 190, 131, 251, 204, 246 },
- { 140, 112, 147, 192, 132, 251, 205, 247 },
- { 141, 112, 147, 193, 132, 251, 206, 247 },
- { 143, 113, 148, 194, 133, 251, 207, 247 },
- { 144, 113, 148, 195, 134, 251, 207, 247 },
- { 146, 114, 149, 197, 135, 252, 208, 248 },
- { 147, 114, 149, 198, 135, 252, 209, 248 },
- { 149, 115, 149, 199, 136, 252, 210, 248 },
- { 150, 115, 149, 200, 137, 252, 210, 248 },
- { 152, 115, 150, 201, 138, 252, 211, 248 },
- { 153, 115, 150, 202, 138, 252, 212, 248 },
- { 155, 116, 151, 204, 139, 253, 213, 249 },
- { 156, 116, 151, 205, 139, 253, 213, 249 },
- { 158, 117, 151, 206, 140, 253, 214, 249 },
- { 159, 117, 151, 207, 141, 253, 215, 249 },
- { 161, 118, 152, 208, 142, 253, 216, 249 },
- { 162, 118, 152, 209, 142, 253, 216, 249 },
- { 163, 119, 153, 210, 143, 253, 217, 249 },
- { 164, 119, 153, 211, 143, 253, 217, 249 },
- { 166, 120, 153, 212, 144, 254, 218, 250 },
- { 167, 120, 153, 212, 145, 254, 219, 250 },
- { 168, 121, 154, 213, 146, 254, 220, 250 },
- { 169, 121, 154, 214, 146, 254, 220, 250 },
- { 171, 122, 155, 215, 147, 254, 221, 250 },
- { 172, 122, 155, 216, 147, 254, 221, 250 },
- { 173, 123, 155, 217, 148, 254, 222, 250 },
- { 174, 123, 155, 217, 149, 254, 222, 250 },
- { 176, 124, 156, 218, 150, 254, 223, 250 },
- { 177, 124, 156, 219, 150, 254, 223, 250 },
- { 178, 125, 157, 220, 151, 254, 224, 251 },
- { 179, 125, 157, 220, 151, 254, 224, 251 },
- { 180, 126, 157, 221, 152, 254, 225, 251 },
- { 181, 126, 157, 221, 152, 254, 225, 251 },
- { 183, 127, 158, 222, 153, 254, 226, 251 },
- { 184, 127, 158, 223, 154, 254, 226, 251 },
- { 185, 128, 159, 224, 155, 255, 227, 251 },
- { 186, 128, 159, 224, 155, 255, 227, 251 },
- { 187, 129, 160, 225, 156, 255, 228, 251 },
- { 188, 130, 160, 225, 156, 255, 228, 251 },
- { 189, 131, 160, 226, 157, 255, 228, 251 },
- { 190, 131, 160, 226, 158, 255, 228, 251 },
- { 191, 132, 161, 227, 159, 255, 229, 251 },
- { 192, 132, 161, 227, 159, 255, 229, 251 },
- { 193, 133, 162, 228, 160, 255, 230, 252 },
- { 194, 133, 162, 229, 160, 255, 230, 252 },
- { 195, 134, 163, 230, 161, 255, 231, 252 },
- { 196, 134, 163, 230, 161, 255, 231, 252 },
- { 197, 135, 163, 231, 162, 255, 231, 252 },
- { 198, 135, 163, 231, 162, 255, 231, 252 },
- { 199, 136, 164, 232, 163, 255, 232, 252 },
- { 200, 136, 164, 232, 164, 255, 232, 252 },
- { 201, 137, 165, 233, 165, 255, 233, 252 },
- { 201, 137, 165, 233, 165, 255, 233, 252 },
- { 202, 138, 166, 233, 166, 255, 233, 252 },
- { 203, 138, 166, 233, 166, 255, 233, 252 },
- { 204, 139, 166, 234, 167, 255, 234, 252 },
- { 205, 139, 166, 234, 167, 255, 234, 252 },
- { 206, 140, 167, 235, 168, 255, 235, 252 },
- { 206, 140, 167, 235, 168, 255, 235, 252 },
- { 207, 141, 168, 236, 169, 255, 235, 252 },
- { 208, 141, 168, 236, 170, 255, 235, 252 },
- { 209, 142, 169, 237, 171, 255, 236, 252 },
- { 209, 143, 169, 237, 171, 255, 236, 252 },
- { 210, 144, 169, 237, 172, 255, 236, 252 },
- { 211, 144, 169, 237, 172, 255, 236, 252 },
- { 212, 145, 170, 238, 173, 255, 237, 252 },
- { 213, 145, 170, 238, 173, 255, 237, 252 },
- { 214, 146, 171, 239, 174, 255, 237, 253 },
- { 214, 146, 171, 239, 174, 255, 237, 253 },
- { 215, 147, 172, 240, 175, 255, 238, 253 },
- { 215, 147, 172, 240, 175, 255, 238, 253 },
- { 216, 148, 173, 240, 176, 255, 238, 253 },
- { 217, 148, 173, 240, 176, 255, 238, 253 },
- { 218, 149, 173, 241, 177, 255, 239, 253 },
- { 218, 149, 173, 241, 178, 255, 239, 253 },
- { 219, 150, 174, 241, 179, 255, 239, 253 },
- { 219, 151, 174, 241, 179, 255, 239, 253 },
- { 220, 152, 175, 242, 180, 255, 240, 253 },
- { 221, 152, 175, 242, 180, 255, 240, 253 },
- { 222, 153, 176, 242, 181, 255, 240, 253 },
- { 222, 153, 176, 242, 181, 255, 240, 253 },
- { 223, 154, 177, 243, 182, 255, 240, 253 },
- { 223, 154, 177, 243, 182, 255, 240, 253 },
- { 224, 155, 178, 244, 183, 255, 241, 253 },
- { 224, 155, 178, 244, 183, 255, 241, 253 },
- { 225, 156, 178, 244, 184, 255, 241, 253 },
- { 225, 157, 178, 244, 184, 255, 241, 253 },
- { 226, 158, 179, 244, 185, 255, 242, 253 },
- { 227, 158, 179, 244, 185, 255, 242, 253 },
- { 228, 159, 180, 245, 186, 255, 242, 253 },
- { 228, 159, 180, 245, 186, 255, 242, 253 },
- { 229, 160, 181, 245, 187, 255, 242, 253 },
- { 229, 160, 181, 245, 187, 255, 242, 253 },
- { 230, 161, 182, 246, 188, 255, 243, 253 },
- { 230, 162, 182, 246, 188, 255, 243, 253 },
- { 231, 163, 183, 246, 189, 255, 243, 253 },
- { 231, 163, 183, 246, 189, 255, 243, 253 },
- { 232, 164, 184, 247, 190, 255, 243, 253 },
- { 232, 164, 184, 247, 190, 255, 243, 253 },
- { 233, 165, 185, 247, 191, 255, 244, 253 },
- { 233, 165, 185, 247, 191, 255, 244, 253 },
- { 234, 166, 185, 247, 192, 255, 244, 253 },
- { 234, 167, 185, 247, 192, 255, 244, 253 },
- { 235, 168, 186, 248, 193, 255, 244, 253 },
- { 235, 168, 186, 248, 193, 255, 244, 253 },
- { 236, 169, 187, 248, 194, 255, 244, 253 },
- { 236, 169, 187, 248, 194, 255, 244, 253 },
- { 236, 170, 188, 248, 195, 255, 245, 253 },
- { 236, 170, 188, 248, 195, 255, 245, 253 },
- { 237, 171, 189, 249, 196, 255, 245, 254 },
- { 237, 172, 189, 249, 196, 255, 245, 254 },
- { 238, 173, 190, 249, 197, 255, 245, 254 },
- { 238, 173, 190, 249, 197, 255, 245, 254 },
- { 239, 174, 191, 249, 198, 255, 245, 254 },
- { 239, 174, 191, 249, 198, 255, 245, 254 },
- { 240, 175, 192, 249, 199, 255, 246, 254 },
- { 240, 176, 192, 249, 199, 255, 246, 254 },
- { 240, 177, 193, 250, 200, 255, 246, 254 },
- { 240, 177, 193, 250, 200, 255, 246, 254 },
- { 241, 178, 194, 250, 201, 255, 246, 254 },
- { 241, 178, 194, 250, 201, 255, 246, 254 },
- { 242, 179, 195, 250, 202, 255, 246, 254 },
- { 242, 180, 195, 250, 202, 255, 246, 254 },
- { 242, 181, 196, 250, 203, 255, 247, 254 },
- { 242, 181, 196, 250, 203, 255, 247, 254 },
- { 243, 182, 197, 251, 204, 255, 247, 254 },
- { 243, 183, 197, 251, 204, 255, 247, 254 },
- { 244, 184, 198, 251, 205, 255, 247, 254 },
- { 244, 184, 198, 251, 205, 255, 247, 254 },
- { 244, 185, 199, 251, 206, 255, 247, 254 },
- { 244, 185, 199, 251, 206, 255, 247, 254 },
- { 245, 186, 200, 251, 207, 255, 247, 254 },
- { 245, 187, 200, 251, 207, 255, 247, 254 },
- { 246, 188, 201, 252, 207, 255, 248, 254 },
- { 246, 188, 201, 252, 207, 255, 248, 254 },
- { 246, 189, 202, 252, 208, 255, 248, 254 },
- { 246, 190, 202, 252, 208, 255, 248, 254 },
- { 247, 191, 203, 252, 209, 255, 248, 254 },
- { 247, 191, 203, 252, 209, 255, 248, 254 },
- { 247, 192, 204, 252, 210, 255, 248, 254 },
- { 247, 193, 204, 252, 210, 255, 248, 254 },
- { 248, 194, 205, 252, 211, 255, 248, 254 },
- { 248, 194, 205, 252, 211, 255, 248, 254 },
- { 248, 195, 206, 252, 212, 255, 249, 254 },
- { 248, 196, 206, 252, 212, 255, 249, 254 },
- { 249, 197, 207, 253, 213, 255, 249, 254 },
- { 249, 197, 207, 253, 213, 255, 249, 254 },
- { 249, 198, 208, 253, 214, 255, 249, 254 },
- { 249, 199, 209, 253, 214, 255, 249, 254 },
- { 250, 200, 210, 253, 215, 255, 249, 254 },
- { 250, 200, 210, 253, 215, 255, 249, 254 },
- { 250, 201, 211, 253, 215, 255, 249, 254 },
- { 250, 202, 211, 253, 215, 255, 249, 254 },
- { 250, 203, 212, 253, 216, 255, 249, 254 },
- { 250, 203, 212, 253, 216, 255, 249, 254 },
- { 251, 204, 213, 253, 217, 255, 250, 254 },
- { 251, 205, 213, 253, 217, 255, 250, 254 },
- { 251, 206, 214, 254, 218, 255, 250, 254 },
- { 251, 206, 215, 254, 218, 255, 250, 254 },
- { 252, 207, 216, 254, 219, 255, 250, 254 },
- { 252, 208, 216, 254, 219, 255, 250, 254 },
- { 252, 209, 217, 254, 220, 255, 250, 254 },
- { 252, 210, 217, 254, 220, 255, 250, 254 },
- { 252, 211, 218, 254, 221, 255, 250, 254 },
- { 252, 212, 218, 254, 221, 255, 250, 254 },
- { 253, 213, 219, 254, 222, 255, 250, 254 },
- { 253, 213, 220, 254, 222, 255, 250, 254 },
- { 253, 214, 221, 254, 223, 255, 250, 254 },
- { 253, 215, 221, 254, 223, 255, 250, 254 },
- { 253, 216, 222, 254, 224, 255, 251, 254 },
- { 253, 217, 223, 254, 224, 255, 251, 254 },
- { 253, 218, 224, 254, 225, 255, 251, 254 },
- { 253, 219, 224, 254, 225, 255, 251, 254 },
- { 254, 220, 225, 254, 225, 255, 251, 254 },
- { 254, 221, 226, 254, 225, 255, 251, 254 },
- { 254, 222, 227, 255, 226, 255, 251, 254 },
- { 254, 223, 227, 255, 226, 255, 251, 254 },
- { 254, 224, 228, 255, 227, 255, 251, 254 },
- { 254, 225, 229, 255, 227, 255, 251, 254 },
- { 254, 226, 230, 255, 228, 255, 251, 254 },
- { 254, 227, 230, 255, 229, 255, 251, 254 },
- { 255, 228, 231, 255, 230, 255, 251, 254 },
- { 255, 229, 232, 255, 230, 255, 251, 254 },
- { 255, 230, 233, 255, 231, 255, 252, 254 },
- { 255, 231, 234, 255, 231, 255, 252, 254 },
- { 255, 232, 235, 255, 232, 255, 252, 254 },
- { 255, 233, 236, 255, 232, 255, 252, 254 },
- { 255, 235, 237, 255, 233, 255, 252, 254 },
- { 255, 236, 238, 255, 234, 255, 252, 254 },
- { 255, 238, 240, 255, 235, 255, 252, 255 },
- { 255, 239, 241, 255, 235, 255, 252, 254 },
- { 255, 241, 243, 255, 236, 255, 252, 254 },
- { 255, 243, 245, 255, 237, 255, 252, 254 },
- { 255, 246, 247, 255, 239, 255, 253, 255 },
-};
-
-const ProbContext ff_vp9_default_probs = {
- { /* y_mode */
- { 65, 32, 18, 144, 162, 194, 41, 51, 98 } /* bsize < 8x8 */,
- { 132, 68, 18, 165, 217, 196, 45, 40, 78 } /* bsize < 16x16 */,
- { 173, 80, 19, 176, 240, 193, 64, 35, 46 } /* bsize < 32x32 */,
- { 221, 135, 38, 194, 248, 121, 96, 85, 29 } /* bsize >= 32x32 */
- }, { /* uv_mode */
- { 48, 12, 154, 155, 139, 90, 34, 117, 119 } /* y = v */,
- { 67, 6, 25, 204, 243, 158, 13, 21, 96 } /* y = h */,
- { 120, 7, 76, 176, 208, 126, 28, 54, 103 } /* y = dc */,
- { 97, 5, 44, 131, 176, 139, 48, 68, 97 } /* y = d45 */,
- { 83, 5, 42, 156, 111, 152, 26, 49, 152 } /* y = d135 */,
- { 80, 5, 58, 178, 74, 83, 33, 62, 145 } /* y = d117 */,
- { 86, 5, 32, 154, 192, 168, 14, 22, 163 } /* y = d153 */,
- { 77, 7, 64, 116, 132, 122, 37, 126, 120 } /* y = d63 */,
- { 85, 5, 32, 156, 216, 148, 19, 29, 73 } /* y = d27 */,
- { 101, 21, 107, 181, 192, 103, 19, 67, 125 } /* y = tm */
- }, { /* filter */
- { 235, 162, },
- { 36, 255, },
- { 34, 3, },
- { 149, 144, },
- }, { /* mv_mode */
- { 2, 173, 34 }, // 0 = both zero mv
- { 7, 145, 85 }, // 1 = one zero mv + one a predicted mv
- { 7, 166, 63 }, // 2 = two predicted mvs
- { 7, 94, 66 }, // 3 = one predicted/zero and one new mv
- { 8, 64, 46 }, // 4 = two new mvs
- { 17, 81, 31 }, // 5 = one intra neighbor + x
- { 25, 29, 30 }, // 6 = two intra neighbors
- }, { /* intra */
- 9, 102, 187, 225
- }, { /* comp */
- 239, 183, 119, 96, 41
- }, { /* single_ref */
- { 33, 16 },
- { 77, 74 },
- { 142, 142 },
- { 172, 170 },
- { 238, 247 }
- }, { /* comp_ref */
- 50, 126, 123, 221, 226
- }, { /* tx32p */
- { 3, 136, 37, },
- { 5, 52, 13, },
- }, { /* tx16p */
- { 20, 152, },
- { 15, 101, },
- }, { /* tx8p */
- 100, 66
- }, { /* skip */
- 192, 128, 64
- }, { /* mv_joint */
- 32, 64, 96
- }, {
- { /* mv vertical component */
- 128, /* sign */
- { 224, 144, 192, 168, 192, 176, 192, 198, 198, 245 }, /* class */
- 216, /* class0 */
- { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }, /* bits */
- { /* class0_fp */
- { 128, 128, 64 },
- { 96, 112, 64 }
- },
- { 64, 96, 64 }, /* fp */
- 160, /* class0_hp bit */
- 128, /* hp */
- }, { /* mv horizontal component */
- 128, /* sign */
- { 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 }, /* class */
- 208, /* class0 */
- { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }, /* bits */
- { /* class0_fp */
- { 128, 128, 64 },
- { 96, 112, 64 }
- },
- { 64, 96, 64 }, /* fp */
- 160, /* class0_hp bit */
- 128, /* hp */
- }
- }, { /* partition */
- { /* 64x64 -> 32x32 */
- { 222, 34, 30 } /* a/l both not split */,
- { 72, 16, 44 } /* a split, l not split */,
- { 58, 32, 12 } /* l split, a not split */,
- { 10, 7, 6 } /* a/l both split */,
- }, { /* 32x32 -> 16x16 */
- { 177, 58, 59 } /* a/l both not split */,
- { 68, 26, 63 } /* a split, l not split */,
- { 52, 79, 25 } /* l split, a not split */,
- { 17, 14, 12 } /* a/l both split */,
- }, { /* 16x16 -> 8x8 */
- { 174, 73, 87 } /* a/l both not split */,
- { 92, 41, 83 } /* a split, l not split */,
- { 82, 99, 50 } /* l split, a not split */,
- { 53, 39, 39 } /* a/l both split */,
- }, { /* 8x8 -> 4x4 */
- { 199, 122, 141 } /* a/l both not split */,
- { 147, 63, 159 } /* a split, l not split */,
- { 148, 133, 118 } /* l split, a not split */,
- { 121, 104, 114 } /* a/l both split */,
- }
- },
-};
-
-const uint8_t ff_vp9_default_coef_probs[4][2][2][6][6][3] = {
- { /* tx = 4x4 */
- { /* block Type 0 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 195, 29, 183 },
- { 84, 49, 136 },
- { 8, 42, 71 }
- }, { /* Coeff Band 1 */
- { 31, 107, 169 },
- { 35, 99, 159 },
- { 17, 82, 140 },
- { 8, 66, 114 },
- { 2, 44, 76 },
- { 1, 19, 32 }
- }, { /* Coeff Band 2 */
- { 40, 132, 201 },
- { 29, 114, 187 },
- { 13, 91, 157 },
- { 7, 75, 127 },
- { 3, 58, 95 },
- { 1, 28, 47 }
- }, { /* Coeff Band 3 */
- { 69, 142, 221 },
- { 42, 122, 201 },
- { 15, 91, 159 },
- { 6, 67, 121 },
- { 1, 42, 77 },
- { 1, 17, 31 }
- }, { /* Coeff Band 4 */
- { 102, 148, 228 },
- { 67, 117, 204 },
- { 17, 82, 154 },
- { 6, 59, 114 },
- { 2, 39, 75 },
- { 1, 15, 29 }
- }, { /* Coeff Band 5 */
- { 156, 57, 233 },
- { 119, 57, 212 },
- { 58, 48, 163 },
- { 29, 40, 124 },
- { 12, 30, 81 },
- { 3, 12, 31 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 191, 107, 226 },
- { 124, 117, 204 },
- { 25, 99, 155 }
- }, { /* Coeff Band 1 */
- { 29, 148, 210 },
- { 37, 126, 194 },
- { 8, 93, 157 },
- { 2, 68, 118 },
- { 1, 39, 69 },
- { 1, 17, 33 }
- }, { /* Coeff Band 2 */
- { 41, 151, 213 },
- { 27, 123, 193 },
- { 3, 82, 144 },
- { 1, 58, 105 },
- { 1, 32, 60 },
- { 1, 13, 26 }
- }, { /* Coeff Band 3 */
- { 59, 159, 220 },
- { 23, 126, 198 },
- { 4, 88, 151 },
- { 1, 66, 114 },
- { 1, 38, 71 },
- { 1, 18, 34 }
- }, { /* Coeff Band 4 */
- { 114, 136, 232 },
- { 51, 114, 207 },
- { 11, 83, 155 },
- { 3, 56, 105 },
- { 1, 33, 65 },
- { 1, 17, 34 }
- }, { /* Coeff Band 5 */
- { 149, 65, 234 },
- { 121, 57, 215 },
- { 61, 49, 166 },
- { 28, 36, 114 },
- { 12, 25, 76 },
- { 3, 16, 42 }
- }
- }
- }, { /* block Type 1 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 214, 49, 220 },
- { 132, 63, 188 },
- { 42, 65, 137 }
- }, { /* Coeff Band 1 */
- { 85, 137, 221 },
- { 104, 131, 216 },
- { 49, 111, 192 },
- { 21, 87, 155 },
- { 2, 49, 87 },
- { 1, 16, 28 }
- }, { /* Coeff Band 2 */
- { 89, 163, 230 },
- { 90, 137, 220 },
- { 29, 100, 183 },
- { 10, 70, 135 },
- { 2, 42, 81 },
- { 1, 17, 33 }
- }, { /* Coeff Band 3 */
- { 108, 167, 237 },
- { 55, 133, 222 },
- { 15, 97, 179 },
- { 4, 72, 135 },
- { 1, 45, 85 },
- { 1, 19, 38 }
- }, { /* Coeff Band 4 */
- { 124, 146, 240 },
- { 66, 124, 224 },
- { 17, 88, 175 },
- { 4, 58, 122 },
- { 1, 36, 75 },
- { 1, 18, 37 }
- }, { /* Coeff Band 5 */
- { 141, 79, 241 },
- { 126, 70, 227 },
- { 66, 58, 182 },
- { 30, 44, 136 },
- { 12, 34, 96 },
- { 2, 20, 47 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 229, 99, 249 },
- { 143, 111, 235 },
- { 46, 109, 192 }
- }, { /* Coeff Band 1 */
- { 82, 158, 236 },
- { 94, 146, 224 },
- { 25, 117, 191 },
- { 9, 87, 149 },
- { 3, 56, 99 },
- { 1, 33, 57 }
- }, { /* Coeff Band 2 */
- { 83, 167, 237 },
- { 68, 145, 222 },
- { 10, 103, 177 },
- { 2, 72, 131 },
- { 1, 41, 79 },
- { 1, 20, 39 }
- }, { /* Coeff Band 3 */
- { 99, 167, 239 },
- { 47, 141, 224 },
- { 10, 104, 178 },
- { 2, 73, 133 },
- { 1, 44, 85 },
- { 1, 22, 47 }
- }, { /* Coeff Band 4 */
- { 127, 145, 243 },
- { 71, 129, 228 },
- { 17, 93, 177 },
- { 3, 61, 124 },
- { 1, 41, 84 },
- { 1, 21, 52 }
- }, { /* Coeff Band 5 */
- { 157, 78, 244 },
- { 140, 72, 231 },
- { 69, 58, 184 },
- { 31, 44, 137 },
- { 14, 38, 105 },
- { 8, 23, 61 }
- }
- }
- }
- }, { /* tx = 8x8 */
- { /* block Type 0 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 125, 34, 187 },
- { 52, 41, 133 },
- { 6, 31, 56 }
- }, { /* Coeff Band 1 */
- { 37, 109, 153 },
- { 51, 102, 147 },
- { 23, 87, 128 },
- { 8, 67, 101 },
- { 1, 41, 63 },
- { 1, 19, 29 }
- }, { /* Coeff Band 2 */
- { 31, 154, 185 },
- { 17, 127, 175 },
- { 6, 96, 145 },
- { 2, 73, 114 },
- { 1, 51, 82 },
- { 1, 28, 45 }
- }, { /* Coeff Band 3 */
- { 23, 163, 200 },
- { 10, 131, 185 },
- { 2, 93, 148 },
- { 1, 67, 111 },
- { 1, 41, 69 },
- { 1, 14, 24 }
- }, { /* Coeff Band 4 */
- { 29, 176, 217 },
- { 12, 145, 201 },
- { 3, 101, 156 },
- { 1, 69, 111 },
- { 1, 39, 63 },
- { 1, 14, 23 }
- }, { /* Coeff Band 5 */
- { 57, 192, 233 },
- { 25, 154, 215 },
- { 6, 109, 167 },
- { 3, 78, 118 },
- { 1, 48, 69 },
- { 1, 21, 29 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 202, 105, 245 },
- { 108, 106, 216 },
- { 18, 90, 144 }
- }, { /* Coeff Band 1 */
- { 33, 172, 219 },
- { 64, 149, 206 },
- { 14, 117, 177 },
- { 5, 90, 141 },
- { 2, 61, 95 },
- { 1, 37, 57 }
- }, { /* Coeff Band 2 */
- { 33, 179, 220 },
- { 11, 140, 198 },
- { 1, 89, 148 },
- { 1, 60, 104 },
- { 1, 33, 57 },
- { 1, 12, 21 }
- }, { /* Coeff Band 3 */
- { 30, 181, 221 },
- { 8, 141, 198 },
- { 1, 87, 145 },
- { 1, 58, 100 },
- { 1, 31, 55 },
- { 1, 12, 20 }
- }, { /* Coeff Band 4 */
- { 32, 186, 224 },
- { 7, 142, 198 },
- { 1, 86, 143 },
- { 1, 58, 100 },
- { 1, 31, 55 },
- { 1, 12, 22 }
- }, { /* Coeff Band 5 */
- { 57, 192, 227 },
- { 20, 143, 204 },
- { 3, 96, 154 },
- { 1, 68, 112 },
- { 1, 42, 69 },
- { 1, 19, 32 }
- }
- }
- }, { /* block Type 1 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 212, 35, 215 },
- { 113, 47, 169 },
- { 29, 48, 105 }
- }, { /* Coeff Band 1 */
- { 74, 129, 203 },
- { 106, 120, 203 },
- { 49, 107, 178 },
- { 19, 84, 144 },
- { 4, 50, 84 },
- { 1, 15, 25 }
- }, { /* Coeff Band 2 */
- { 71, 172, 217 },
- { 44, 141, 209 },
- { 15, 102, 173 },
- { 6, 76, 133 },
- { 2, 51, 89 },
- { 1, 24, 42 }
- }, { /* Coeff Band 3 */
- { 64, 185, 231 },
- { 31, 148, 216 },
- { 8, 103, 175 },
- { 3, 74, 131 },
- { 1, 46, 81 },
- { 1, 18, 30 }
- }, { /* Coeff Band 4 */
- { 65, 196, 235 },
- { 25, 157, 221 },
- { 5, 105, 174 },
- { 1, 67, 120 },
- { 1, 38, 69 },
- { 1, 15, 30 }
- }, { /* Coeff Band 5 */
- { 65, 204, 238 },
- { 30, 156, 224 },
- { 7, 107, 177 },
- { 2, 70, 124 },
- { 1, 42, 73 },
- { 1, 18, 34 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 225, 86, 251 },
- { 144, 104, 235 },
- { 42, 99, 181 }
- }, { /* Coeff Band 1 */
- { 85, 175, 239 },
- { 112, 165, 229 },
- { 29, 136, 200 },
- { 12, 103, 162 },
- { 6, 77, 123 },
- { 2, 53, 84 }
- }, { /* Coeff Band 2 */
- { 75, 183, 239 },
- { 30, 155, 221 },
- { 3, 106, 171 },
- { 1, 74, 128 },
- { 1, 44, 76 },
- { 1, 17, 28 }
- }, { /* Coeff Band 3 */
- { 73, 185, 240 },
- { 27, 159, 222 },
- { 2, 107, 172 },
- { 1, 75, 127 },
- { 1, 42, 73 },
- { 1, 17, 29 }
- }, { /* Coeff Band 4 */
- { 62, 190, 238 },
- { 21, 159, 222 },
- { 2, 107, 172 },
- { 1, 72, 122 },
- { 1, 40, 71 },
- { 1, 18, 32 }
- }, { /* Coeff Band 5 */
- { 61, 199, 240 },
- { 27, 161, 226 },
- { 4, 113, 180 },
- { 1, 76, 129 },
- { 1, 46, 80 },
- { 1, 23, 41 }
- }
- }
- }
- }, { /* tx = 16x16 */
- { /* block Type 0 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 7, 27, 153 },
- { 5, 30, 95 },
- { 1, 16, 30 }
- }, { /* Coeff Band 1 */
- { 50, 75, 127 },
- { 57, 75, 124 },
- { 27, 67, 108 },
- { 10, 54, 86 },
- { 1, 33, 52 },
- { 1, 12, 18 }
- }, { /* Coeff Band 2 */
- { 43, 125, 151 },
- { 26, 108, 148 },
- { 7, 83, 122 },
- { 2, 59, 89 },
- { 1, 38, 60 },
- { 1, 17, 27 }
- }, { /* Coeff Band 3 */
- { 23, 144, 163 },
- { 13, 112, 154 },
- { 2, 75, 117 },
- { 1, 50, 81 },
- { 1, 31, 51 },
- { 1, 14, 23 }
- }, { /* Coeff Band 4 */
- { 18, 162, 185 },
- { 6, 123, 171 },
- { 1, 78, 125 },
- { 1, 51, 86 },
- { 1, 31, 54 },
- { 1, 14, 23 }
- }, { /* Coeff Band 5 */
- { 15, 199, 227 },
- { 3, 150, 204 },
- { 1, 91, 146 },
- { 1, 55, 95 },
- { 1, 30, 53 },
- { 1, 11, 20 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 19, 55, 240 },
- { 19, 59, 196 },
- { 3, 52, 105 }
- }, { /* Coeff Band 1 */
- { 41, 166, 207 },
- { 104, 153, 199 },
- { 31, 123, 181 },
- { 14, 101, 152 },
- { 5, 72, 106 },
- { 1, 36, 52 }
- }, { /* Coeff Band 2 */
- { 35, 176, 211 },
- { 12, 131, 190 },
- { 2, 88, 144 },
- { 1, 60, 101 },
- { 1, 36, 60 },
- { 1, 16, 28 }
- }, { /* Coeff Band 3 */
- { 28, 183, 213 },
- { 8, 134, 191 },
- { 1, 86, 142 },
- { 1, 56, 96 },
- { 1, 30, 53 },
- { 1, 12, 20 }
- }, { /* Coeff Band 4 */
- { 20, 190, 215 },
- { 4, 135, 192 },
- { 1, 84, 139 },
- { 1, 53, 91 },
- { 1, 28, 49 },
- { 1, 11, 20 }
- }, { /* Coeff Band 5 */
- { 13, 196, 216 },
- { 2, 137, 192 },
- { 1, 86, 143 },
- { 1, 57, 99 },
- { 1, 32, 56 },
- { 1, 13, 24 }
- }
- }
- }, { /* block Type 1 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 211, 29, 217 },
- { 96, 47, 156 },
- { 22, 43, 87 }
- }, { /* Coeff Band 1 */
- { 78, 120, 193 },
- { 111, 116, 186 },
- { 46, 102, 164 },
- { 15, 80, 128 },
- { 2, 49, 76 },
- { 1, 18, 28 }
- }, { /* Coeff Band 2 */
- { 71, 161, 203 },
- { 42, 132, 192 },
- { 10, 98, 150 },
- { 3, 69, 109 },
- { 1, 44, 70 },
- { 1, 18, 29 }
- }, { /* Coeff Band 3 */
- { 57, 186, 211 },
- { 30, 140, 196 },
- { 4, 93, 146 },
- { 1, 62, 102 },
- { 1, 38, 65 },
- { 1, 16, 27 }
- }, { /* Coeff Band 4 */
- { 47, 199, 217 },
- { 14, 145, 196 },
- { 1, 88, 142 },
- { 1, 57, 98 },
- { 1, 36, 62 },
- { 1, 15, 26 }
- }, { /* Coeff Band 5 */
- { 26, 219, 229 },
- { 5, 155, 207 },
- { 1, 94, 151 },
- { 1, 60, 104 },
- { 1, 36, 62 },
- { 1, 16, 28 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 233, 29, 248 },
- { 146, 47, 220 },
- { 43, 52, 140 }
- }, { /* Coeff Band 1 */
- { 100, 163, 232 },
- { 179, 161, 222 },
- { 63, 142, 204 },
- { 37, 113, 174 },
- { 26, 89, 137 },
- { 18, 68, 97 }
- }, { /* Coeff Band 2 */
- { 85, 181, 230 },
- { 32, 146, 209 },
- { 7, 100, 164 },
- { 3, 71, 121 },
- { 1, 45, 77 },
- { 1, 18, 30 }
- }, { /* Coeff Band 3 */
- { 65, 187, 230 },
- { 20, 148, 207 },
- { 2, 97, 159 },
- { 1, 68, 116 },
- { 1, 40, 70 },
- { 1, 14, 29 }
- }, { /* Coeff Band 4 */
- { 40, 194, 227 },
- { 8, 147, 204 },
- { 1, 94, 155 },
- { 1, 65, 112 },
- { 1, 39, 66 },
- { 1, 14, 26 }
- }, { /* Coeff Band 5 */
- { 16, 208, 228 },
- { 3, 151, 207 },
- { 1, 98, 160 },
- { 1, 67, 117 },
- { 1, 41, 74 },
- { 1, 17, 31 }
- }
- }
- }
- }, { /* tx = 32x32 */
- { /* block Type 0 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 17, 38, 140 },
- { 7, 34, 80 },
- { 1, 17, 29 }
- }, { /* Coeff Band 1 */
- { 37, 75, 128 },
- { 41, 76, 128 },
- { 26, 66, 116 },
- { 12, 52, 94 },
- { 2, 32, 55 },
- { 1, 10, 16 }
- }, { /* Coeff Band 2 */
- { 50, 127, 154 },
- { 37, 109, 152 },
- { 16, 82, 121 },
- { 5, 59, 85 },
- { 1, 35, 54 },
- { 1, 13, 20 }
- }, { /* Coeff Band 3 */
- { 40, 142, 167 },
- { 17, 110, 157 },
- { 2, 71, 112 },
- { 1, 44, 72 },
- { 1, 27, 45 },
- { 1, 11, 17 }
- }, { /* Coeff Band 4 */
- { 30, 175, 188 },
- { 9, 124, 169 },
- { 1, 74, 116 },
- { 1, 48, 78 },
- { 1, 30, 49 },
- { 1, 11, 18 }
- }, { /* Coeff Band 5 */
- { 10, 222, 223 },
- { 2, 150, 194 },
- { 1, 83, 128 },
- { 1, 48, 79 },
- { 1, 27, 45 },
- { 1, 11, 17 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 36, 41, 235 },
- { 29, 36, 193 },
- { 10, 27, 111 }
- }, { /* Coeff Band 1 */
- { 85, 165, 222 },
- { 177, 162, 215 },
- { 110, 135, 195 },
- { 57, 113, 168 },
- { 23, 83, 120 },
- { 10, 49, 61 }
- }, { /* Coeff Band 2 */
- { 85, 190, 223 },
- { 36, 139, 200 },
- { 5, 90, 146 },
- { 1, 60, 103 },
- { 1, 38, 65 },
- { 1, 18, 30 }
- }, { /* Coeff Band 3 */
- { 72, 202, 223 },
- { 23, 141, 199 },
- { 2, 86, 140 },
- { 1, 56, 97 },
- { 1, 36, 61 },
- { 1, 16, 27 }
- }, { /* Coeff Band 4 */
- { 55, 218, 225 },
- { 13, 145, 200 },
- { 1, 86, 141 },
- { 1, 57, 99 },
- { 1, 35, 61 },
- { 1, 13, 22 }
- }, { /* Coeff Band 5 */
- { 15, 235, 212 },
- { 1, 132, 184 },
- { 1, 84, 139 },
- { 1, 57, 97 },
- { 1, 34, 56 },
- { 1, 14, 23 }
- }
- }
- }, { /* block Type 1 */
- { /* Intra */
- { /* Coeff Band 0 */
- { 181, 21, 201 },
- { 61, 37, 123 },
- { 10, 38, 71 }
- }, { /* Coeff Band 1 */
- { 47, 106, 172 },
- { 95, 104, 173 },
- { 42, 93, 159 },
- { 18, 77, 131 },
- { 4, 50, 81 },
- { 1, 17, 23 }
- }, { /* Coeff Band 2 */
- { 62, 147, 199 },
- { 44, 130, 189 },
- { 28, 102, 154 },
- { 18, 75, 115 },
- { 2, 44, 65 },
- { 1, 12, 19 }
- }, { /* Coeff Band 3 */
- { 55, 153, 210 },
- { 24, 130, 194 },
- { 3, 93, 146 },
- { 1, 61, 97 },
- { 1, 31, 50 },
- { 1, 10, 16 }
- }, { /* Coeff Band 4 */
- { 49, 186, 223 },
- { 17, 148, 204 },
- { 1, 96, 142 },
- { 1, 53, 83 },
- { 1, 26, 44 },
- { 1, 11, 17 }
- }, { /* Coeff Band 5 */
- { 13, 217, 212 },
- { 2, 136, 180 },
- { 1, 78, 124 },
- { 1, 50, 83 },
- { 1, 29, 49 },
- { 1, 14, 23 }
- }
- }, { /* Inter */
- { /* Coeff Band 0 */
- { 197, 13, 247 },
- { 82, 17, 222 },
- { 25, 17, 162 }
- }, { /* Coeff Band 1 */
- { 126, 186, 247 },
- { 234, 191, 243 },
- { 176, 177, 234 },
- { 104, 158, 220 },
- { 66, 128, 186 },
- { 55, 90, 137 }
- }, { /* Coeff Band 2 */
- { 111, 197, 242 },
- { 46, 158, 219 },
- { 9, 104, 171 },
- { 2, 65, 125 },
- { 1, 44, 80 },
- { 1, 17, 91 }
- }, { /* Coeff Band 3 */
- { 104, 208, 245 },
- { 39, 168, 224 },
- { 3, 109, 162 },
- { 1, 79, 124 },
- { 1, 50, 102 },
- { 1, 43, 102 }
- }, { /* Coeff Band 4 */
- { 84, 220, 246 },
- { 31, 177, 231 },
- { 2, 115, 180 },
- { 1, 79, 134 },
- { 1, 55, 77 },
- { 1, 60, 79 }
- }, { /* Coeff Band 5 */
- { 43, 243, 240 },
- { 8, 180, 217 },
- { 1, 115, 166 },
- { 1, 84, 121 },
- { 1, 51, 67 },
- { 1, 16, 6 }
- }
- }
- }
- }
-};
-
-const int8_t ff_vp9_mv_joint_tree[3][2] = {
- { -MV_JOINT_ZERO, 1 }, // '0'
- { -MV_JOINT_H, 2 }, // '10'
- { -MV_JOINT_V, -MV_JOINT_HV }, // '11x'
-};
-
-const int8_t ff_vp9_mv_class_tree[10][2] = {
- { -0, 1 }, // '0'
- { -1, 2 }, // '10'
- { 3, 4 },
- { -2, -3 }, // '110x'
- { 5, 6 },
- { -4, -5 }, // '1110x'
- { -6, 7 }, // '11110'
- { 8, 9 },
- { -7, -8 }, // '111110x'
- { -9, -10 }, // '111111x'
-};
-
-const int8_t ff_vp9_mv_fp_tree[3][2] = {
- { -0, 1 }, // '0'
- { -1, 2 }, // '10'
- { -2, -3 }, // '11x'
-};
diff --git a/libavcodec/vp9data.h b/libavcodec/vp9data.h
index a52cc0a353..4142cea52f 100644
--- a/libavcodec/vp9data.h
+++ b/libavcodec/vp9data.h
@@ -2,20 +2,20 @@
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
* Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,45 +26,2266 @@
#include "vp9.h"
-extern const int8_t ff_vp9_partition_tree[3][2];
-extern const uint8_t ff_vp9_default_kf_partition_probs[4][4][3];
-extern const int8_t ff_vp9_segmentation_tree[7][2];
-extern const int8_t ff_vp9_intramode_tree[9][2];
-extern const uint8_t ff_vp9_default_kf_ymode_probs[10][10][9];
-extern const uint8_t ff_vp9_default_kf_uvmode_probs[10][9];
-extern const int8_t ff_vp9_inter_mode_tree[3][2];
-extern const int8_t ff_vp9_filter_tree[2][2];
-extern const enum FilterMode ff_vp9_filter_lut[3];
-extern const int16_t ff_vp9_dc_qlookup[256];
-extern const int16_t ff_vp9_ac_qlookup[256];
-extern const enum TxfmType ff_vp9_intra_txfm_type[14];
-extern const int16_t ff_vp9_default_scan_4x4[16];
-extern const int16_t ff_vp9_col_scan_4x4[16];
-extern const int16_t ff_vp9_row_scan_4x4[16];
-extern const int16_t ff_vp9_default_scan_8x8[64];
-extern const int16_t ff_vp9_col_scan_8x8[64];
-extern const int16_t ff_vp9_row_scan_8x8[64];
-extern const int16_t ff_vp9_default_scan_16x16[256];
-extern const int16_t ff_vp9_col_scan_16x16[256];
-extern const int16_t ff_vp9_row_scan_16x16[256];
-extern const int16_t ff_vp9_default_scan_32x32[1024];
-extern const int16_t *ff_vp9_scans[5][4];
-extern const int16_t ff_vp9_default_scan_4x4_nb[16][2];
-extern const int16_t ff_vp9_col_scan_4x4_nb[16][2];
-extern const int16_t ff_vp9_row_scan_4x4_nb[16][2];
-extern const int16_t ff_vp9_default_scan_8x8_nb[64][2];
-extern const int16_t ff_vp9_col_scan_8x8_nb[64][2];
-extern const int16_t ff_vp9_row_scan_8x8_nb[64][2];
-extern const int16_t ff_vp9_default_scan_16x16_nb[256][2];
-extern const int16_t ff_vp9_col_scan_16x16_nb[256][2];
-extern const int16_t ff_vp9_row_scan_16x16_nb[256][2];
-extern const int16_t ff_vp9_default_scan_32x32_nb[1024][2];
-extern const int16_t (*ff_vp9_scans_nb[5][4])[2];
-extern const uint8_t ff_vp9_model_pareto8[256][8];
-extern const ProbContext ff_vp9_default_probs;
-extern const uint8_t ff_vp9_default_coef_probs[4][2][2][6][6][3];
-extern const int8_t ff_vp9_mv_joint_tree[3][2];
-extern const int8_t ff_vp9_mv_class_tree[10][2];
-extern const int8_t ff_vp9_mv_fp_tree[3][2];
+enum BlockPartition {
+ PARTITION_NONE, // [ ] <-.
+ PARTITION_H, // [-] |
+ PARTITION_V, // [|] |
+ PARTITION_SPLIT, // [+] --'
+};
+
+static const int8_t vp9_partition_tree[3][2] = {
+ { -PARTITION_NONE, 1 }, // '0'
+ { -PARTITION_H, 2 }, // '10'
+ { -PARTITION_V, -PARTITION_SPLIT }, // '110', '111'
+};
+
+static const uint8_t vp9_default_kf_partition_probs[4][4][3] = {
+ { /* 64x64 -> 32x32 */
+ { 174, 35, 49 } /* a/l both not split */,
+ { 68, 11, 27 } /* a split, l not split */,
+ { 57, 15, 9 } /* l split, a not split */,
+ { 12, 3, 3 } /* a/l both split */
+ }, { /* 32x32 -> 16x16 */
+ { 150, 40, 39 } /* a/l both not split */,
+ { 78, 12, 26 } /* a split, l not split */,
+ { 67, 33, 11 } /* l split, a not split */,
+ { 24, 7, 5 } /* a/l both split */,
+ }, { /* 16x16 -> 8x8 */
+ { 149, 53, 53 } /* a/l both not split */,
+ { 94, 20, 48 } /* a split, l not split */,
+ { 83, 53, 24 } /* l split, a not split */,
+ { 52, 18, 18 } /* a/l both split */,
+ }, { /* 8x8 -> 4x4 */
+ { 158, 97, 94 } /* a/l both not split */,
+ { 93, 24, 99 } /* a split, l not split */,
+ { 85, 119, 44 } /* l split, a not split */,
+ { 62, 59, 67 } /* a/l both split */,
+ },
+};
+
+static const int8_t vp9_segmentation_tree[7][2] = {
+ { 1, 2 },
+ { 3, 4 },
+ { 5, 6 },
+ { -0, -1 }, // '00x'
+ { -2, -3 }, // '01x'
+ { -4, -5 }, // '10x'
+ { -6, -7 }, // '11x'
+};
+
+static const int8_t vp9_intramode_tree[9][2] = {
+ { -DC_PRED, 1 }, // '0'
+ { -TM_VP8_PRED, 2 }, // '10'
+ { -VERT_PRED, 3 }, // '110'
+ { 4, 6 },
+ { -HOR_PRED, 5 }, // '11100'
+ { -DIAG_DOWN_RIGHT_PRED, -VERT_RIGHT_PRED }, // '11101x'
+ { -DIAG_DOWN_LEFT_PRED, 7 }, // '11110'
+ { -VERT_LEFT_PRED, 8 }, // '111110'
+ { -HOR_DOWN_PRED, -HOR_UP_PRED }, // '111111x'
+};
+
+static const uint8_t vp9_default_kf_ymode_probs[10][10][9] = {
+ { /* above = v */
+ { 43, 46, 168, 134, 107, 128, 69, 142, 92 } /* left = v */,
+ { 44, 29, 68, 159, 201, 177, 50, 57, 77 } /* left = h */,
+ { 63, 36, 126, 146, 123, 158, 60, 90, 96 } /* left = dc */,
+ { 58, 38, 76, 114, 97, 172, 78, 133, 92 } /* left = d45 */,
+ { 46, 41, 76, 140, 63, 184, 69, 112, 57 } /* left = d135 */,
+ { 38, 32, 85, 140, 46, 112, 54, 151, 133 } /* left = d117 */,
+ { 39, 27, 61, 131, 110, 175, 44, 75, 136 } /* left = d153 */,
+ { 47, 35, 80, 100, 74, 143, 64, 163, 74 } /* left = d63 */,
+ { 52, 30, 74, 113, 130, 175, 51, 64, 58 } /* left = d27 */,
+ { 36, 61, 116, 114, 128, 162, 80, 125, 82 } /* left = tm */
+ }, { /* above = h */
+ { 55, 44, 68, 166, 179, 192, 57, 57, 108 } /* left = v */,
+ { 42, 26, 11, 199, 241, 228, 23, 15, 85 } /* left = h */,
+ { 82, 26, 26, 171, 208, 204, 44, 32, 105 } /* left = dc */,
+ { 68, 42, 19, 131, 160, 199, 55, 52, 83 } /* left = d45 */,
+ { 58, 50, 25, 139, 115, 232, 39, 52, 118 } /* left = d135 */,
+ { 50, 35, 33, 153, 104, 162, 64, 59, 131 } /* left = d117 */,
+ { 44, 24, 16, 150, 177, 202, 33, 19, 156 } /* left = d153 */,
+ { 53, 49, 21, 110, 116, 168, 59, 80, 76 } /* left = d63 */,
+ { 55, 27, 12, 153, 203, 218, 26, 27, 49 } /* left = d27 */,
+ { 38, 72, 19, 168, 203, 212, 50, 50, 107 } /* left = tm */
+ }, { /* above = dc */
+ { 92, 45, 102, 136, 116, 180, 74, 90, 100 } /* left = v */,
+ { 73, 32, 19, 187, 222, 215, 46, 34, 100 } /* left = h */,
+ { 137, 30, 42, 148, 151, 207, 70, 52, 91 } /* left = dc */,
+ { 91, 30, 32, 116, 121, 186, 93, 86, 94 } /* left = d45 */,
+ { 72, 35, 36, 149, 68, 206, 68, 63, 105 } /* left = d135 */,
+ { 73, 31, 28, 138, 57, 124, 55, 122, 151 } /* left = d117 */,
+ { 67, 23, 21, 140, 126, 197, 40, 37, 171 } /* left = d153 */,
+ { 74, 32, 27, 107, 86, 160, 63, 134, 102 } /* left = d63 */,
+ { 86, 27, 28, 128, 154, 212, 45, 43, 53 } /* left = d27 */,
+ { 59, 67, 44, 140, 161, 202, 78, 67, 119 } /* left = tm */
+ }, { /* above = d45 */
+ { 59, 38, 83, 112, 103, 162, 98, 136, 90 } /* left = v */,
+ { 62, 30, 23, 158, 200, 207, 59, 57, 50 } /* left = h */,
+ { 103, 26, 36, 129, 132, 201, 83, 80, 93 } /* left = dc */,
+ { 67, 30, 29, 84, 86, 191, 102, 91, 59 } /* left = d45 */,
+ { 60, 32, 33, 112, 71, 220, 64, 89, 104 } /* left = d135 */,
+ { 53, 26, 34, 130, 56, 149, 84, 120, 103 } /* left = d117 */,
+ { 53, 21, 23, 133, 109, 210, 56, 77, 172 } /* left = d153 */,
+ { 61, 29, 29, 93, 97, 165, 83, 175, 162 } /* left = d63 */,
+ { 77, 19, 29, 112, 142, 228, 55, 66, 36 } /* left = d27 */,
+ { 47, 47, 43, 114, 137, 181, 100, 99, 95 } /* left = tm */
+ }, { /* above = d135 */
+ { 53, 40, 55, 139, 69, 183, 61, 80, 110 } /* left = v */,
+ { 40, 29, 19, 161, 180, 207, 43, 24, 91 } /* left = h */,
+ { 69, 23, 29, 128, 83, 199, 46, 44, 101 } /* left = dc */,
+ { 60, 34, 19, 105, 61, 198, 53, 64, 89 } /* left = d45 */,
+ { 52, 31, 22, 158, 40, 209, 58, 62, 89 } /* left = d135 */,
+ { 44, 31, 29, 147, 46, 158, 56, 102, 198 } /* left = d117 */,
+ { 35, 19, 12, 135, 87, 209, 41, 45, 167 } /* left = d153 */,
+ { 51, 38, 25, 113, 58, 164, 70, 93, 97 } /* left = d63 */,
+ { 55, 25, 21, 118, 95, 215, 38, 39, 66 } /* left = d27 */,
+ { 47, 54, 34, 146, 108, 203, 72, 103, 151 } /* left = tm */
+ }, { /* above = d117 */
+ { 46, 27, 80, 150, 55, 124, 55, 121, 135 } /* left = v */,
+ { 36, 23, 27, 165, 149, 166, 54, 64, 118 } /* left = h */,
+ { 64, 19, 37, 156, 66, 138, 49, 95, 133 } /* left = dc */,
+ { 53, 21, 36, 131, 63, 163, 60, 109, 81 } /* left = d45 */,
+ { 40, 26, 35, 154, 40, 185, 51, 97, 123 } /* left = d135 */,
+ { 35, 19, 34, 179, 19, 97, 48, 129, 124 } /* left = d117 */,
+ { 36, 20, 26, 136, 62, 164, 33, 77, 154 } /* left = d153 */,
+ { 45, 26, 28, 129, 45, 129, 49, 147, 123 } /* left = d63 */,
+ { 45, 18, 32, 130, 90, 157, 40, 79, 91 } /* left = d27 */,
+ { 38, 44, 51, 136, 74, 162, 57, 97, 121 } /* left = tm */
+ }, { /* above = d153 */
+ { 56, 39, 58, 133, 117, 173, 48, 53, 187 } /* left = v */,
+ { 35, 21, 12, 161, 212, 207, 20, 23, 145 } /* left = h */,
+ { 75, 17, 22, 136, 138, 185, 32, 34, 166 } /* left = dc */,
+ { 56, 29, 19, 117, 109, 181, 55, 68, 112 } /* left = d45 */,
+ { 47, 29, 17, 153, 64, 220, 59, 51, 114 } /* left = d135 */,
+ { 46, 16, 24, 136, 76, 147, 41, 64, 172 } /* left = d117 */,
+ { 34, 17, 11, 108, 152, 187, 13, 15, 209 } /* left = d153 */,
+ { 55, 30, 18, 122, 79, 179, 44, 88, 116 } /* left = d63 */,
+ { 51, 24, 14, 115, 133, 209, 32, 26, 104 } /* left = d27 */,
+ { 37, 49, 25, 129, 168, 164, 41, 54, 148 } /* left = tm */
+ }, { /* above = d63 */
+ { 48, 34, 86, 101, 92, 146, 78, 179, 134 } /* left = v */,
+ { 47, 22, 24, 138, 187, 178, 68, 69, 59 } /* left = h */,
+ { 78, 23, 39, 111, 117, 170, 74, 124, 94 } /* left = dc */,
+ { 56, 25, 33, 105, 112, 187, 95, 177, 129 } /* left = d45 */,
+ { 48, 31, 27, 114, 63, 183, 82, 116, 56 } /* left = d135 */,
+ { 43, 28, 37, 121, 63, 123, 61, 192, 169 } /* left = d117 */,
+ { 42, 17, 24, 109, 97, 177, 56, 76, 122 } /* left = d153 */,
+ { 46, 23, 32, 74, 86, 150, 67, 183, 88 } /* left = d63 */,
+ { 58, 18, 28, 105, 139, 182, 70, 92, 63 } /* left = d27 */,
+ { 36, 38, 48, 92, 122, 165, 88, 137, 91 } /* left = tm */
+ }, { /* above = d27 */
+ { 62, 44, 61, 123, 105, 189, 48, 57, 64 } /* left = v */,
+ { 47, 25, 17, 175, 222, 220, 24, 30, 86 } /* left = h */,
+ { 82, 22, 32, 127, 143, 213, 39, 41, 70 } /* left = dc */,
+ { 68, 36, 17, 106, 102, 206, 59, 74, 74 } /* left = d45 */,
+ { 57, 39, 23, 151, 68, 216, 55, 63, 58 } /* left = d135 */,
+ { 49, 30, 35, 141, 70, 168, 82, 40, 115 } /* left = d117 */,
+ { 51, 25, 15, 136, 129, 202, 38, 35, 139 } /* left = d153 */,
+ { 59, 39, 19, 114, 75, 180, 77, 104, 42 } /* left = d63 */,
+ { 68, 26, 16, 111, 141, 215, 29, 28, 28 } /* left = d27 */,
+ { 40, 61, 26, 126, 152, 206, 61, 59, 93 } /* left = tm */
+ }, { /* above = tm */
+ { 44, 78, 115, 132, 119, 173, 71, 112, 93 } /* left = v */,
+ { 39, 38, 21, 184, 227, 206, 42, 32, 64 } /* left = h */,
+ { 65, 70, 60, 155, 159, 199, 61, 60, 81 } /* left = dc */,
+ { 58, 47, 36, 124, 137, 193, 80, 82, 78 } /* left = d45 */,
+ { 49, 50, 35, 144, 95, 205, 63, 78, 59 } /* left = d135 */,
+ { 41, 53, 52, 148, 71, 142, 65, 128, 51 } /* left = d117 */,
+ { 40, 36, 28, 143, 143, 202, 40, 55, 137 } /* left = d153 */,
+ { 42, 44, 44, 104, 105, 164, 64, 130, 80 } /* left = d63 */,
+ { 52, 34, 29, 129, 183, 227, 42, 35, 43 } /* left = d27 */,
+ { 43, 81, 53, 140, 169, 204, 68, 84, 72 } /* left = tm */
+ }
+};
+
+static const uint8_t vp9_default_kf_uvmode_probs[10][9] = {
+ { 118, 15, 123, 148, 131, 101, 44, 93, 131 } /* y = v */,
+ { 113, 12, 23, 188, 226, 142, 26, 32, 125 } /* y = h */,
+ { 144, 11, 54, 157, 195, 130, 46, 58, 108 } /* y = dc */,
+ { 120, 11, 50, 123, 163, 135, 64, 77, 103 } /* y = d45 */,
+ { 113, 9, 36, 155, 111, 157, 32, 44, 161 } /* y = d135 */,
+ { 116, 9, 55, 176, 76, 96, 37, 61, 149 } /* y = d117 */,
+ { 115, 9, 28, 141, 161, 167, 21, 25, 193 } /* y = d153 */,
+ { 116, 12, 64, 120, 140, 125, 49, 115, 121 } /* y = d63 */,
+ { 120, 12, 32, 145, 195, 142, 32, 38, 86 } /* y = d27 */,
+ { 102, 19, 66, 162, 182, 122, 35, 59, 128 } /* y = tm */
+};
+
+enum InterPredMode {
+ NEARESTMV = 10,
+ NEARMV = 11,
+ ZEROMV = 12,
+ NEWMV = 13,
+};
+
+static const int8_t vp9_inter_mode_tree[3][2] = {
+ { -ZEROMV, 1 }, // '0'
+ { -NEARESTMV, 2 }, // '10'
+ { -NEARMV, -NEWMV }, // '11x'
+};
+
+static const int8_t vp9_filter_tree[2][2] = {
+ { -0, 1 }, // '0'
+ { -1, -2 }, // '1x'
+};
+
+static const enum FilterMode vp9_filter_lut[3] = {
+ FILTER_8TAP_REGULAR,
+ FILTER_8TAP_SMOOTH,
+ FILTER_8TAP_SHARP,
+};
+
+static const int16_t vp9_dc_qlookup[3][256] = {
+ {
+ 4, 8, 8, 9, 10, 11, 12, 12,
+ 13, 14, 15, 16, 17, 18, 19, 19,
+ 20, 21, 22, 23, 24, 25, 26, 26,
+ 27, 28, 29, 30, 31, 32, 32, 33,
+ 34, 35, 36, 37, 38, 38, 39, 40,
+ 41, 42, 43, 43, 44, 45, 46, 47,
+ 48, 48, 49, 50, 51, 52, 53, 53,
+ 54, 55, 56, 57, 57, 58, 59, 60,
+ 61, 62, 62, 63, 64, 65, 66, 66,
+ 67, 68, 69, 70, 70, 71, 72, 73,
+ 74, 74, 75, 76, 77, 78, 78, 79,
+ 80, 81, 81, 82, 83, 84, 85, 85,
+ 87, 88, 90, 92, 93, 95, 96, 98,
+ 99, 101, 102, 104, 105, 107, 108, 110,
+ 111, 113, 114, 116, 117, 118, 120, 121,
+ 123, 125, 127, 129, 131, 134, 136, 138,
+ 140, 142, 144, 146, 148, 150, 152, 154,
+ 156, 158, 161, 164, 166, 169, 172, 174,
+ 177, 180, 182, 185, 187, 190, 192, 195,
+ 199, 202, 205, 208, 211, 214, 217, 220,
+ 223, 226, 230, 233, 237, 240, 243, 247,
+ 250, 253, 257, 261, 265, 269, 272, 276,
+ 280, 284, 288, 292, 296, 300, 304, 309,
+ 313, 317, 322, 326, 330, 335, 340, 344,
+ 349, 354, 359, 364, 369, 374, 379, 384,
+ 389, 395, 400, 406, 411, 417, 423, 429,
+ 435, 441, 447, 454, 461, 467, 475, 482,
+ 489, 497, 505, 513, 522, 530, 539, 549,
+ 559, 569, 579, 590, 602, 614, 626, 640,
+ 654, 668, 684, 700, 717, 736, 755, 775,
+ 796, 819, 843, 869, 896, 925, 955, 988,
+ 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336,
+ }, {
+ 4, 9, 10, 13, 15, 17, 20, 22,
+ 25, 28, 31, 34, 37, 40, 43, 47,
+ 50, 53, 57, 60, 64, 68, 71, 75,
+ 78, 82, 86, 90, 93, 97, 101, 105,
+ 109, 113, 116, 120, 124, 128, 132, 136,
+ 140, 143, 147, 151, 155, 159, 163, 166,
+ 170, 174, 178, 182, 185, 189, 193, 197,
+ 200, 204, 208, 212, 215, 219, 223, 226,
+ 230, 233, 237, 241, 244, 248, 251, 255,
+ 259, 262, 266, 269, 273, 276, 280, 283,
+ 287, 290, 293, 297, 300, 304, 307, 310,
+ 314, 317, 321, 324, 327, 331, 334, 337,
+ 343, 350, 356, 362, 369, 375, 381, 387,
+ 394, 400, 406, 412, 418, 424, 430, 436,
+ 442, 448, 454, 460, 466, 472, 478, 484,
+ 490, 499, 507, 516, 525, 533, 542, 550,
+ 559, 567, 576, 584, 592, 601, 609, 617,
+ 625, 634, 644, 655, 666, 676, 687, 698,
+ 708, 718, 729, 739, 749, 759, 770, 782,
+ 795, 807, 819, 831, 844, 856, 868, 880,
+ 891, 906, 920, 933, 947, 961, 975, 988,
+ 1001, 1015, 1030, 1045, 1061, 1076, 1090, 1105,
+ 1120, 1137, 1153, 1170, 1186, 1202, 1218, 1236,
+ 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379,
+ 1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537,
+ 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717,
+ 1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929,
+ 1958, 1990, 2021, 2054, 2088, 2123, 2159, 2197,
+ 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561,
+ 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102,
+ 3188, 3280, 3375, 3478, 3586, 3702, 3823, 3953,
+ 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347,
+ }, {
+ 4, 12, 18, 25, 33, 41, 50, 60,
+ 70, 80, 91, 103, 115, 127, 140, 153,
+ 166, 180, 194, 208, 222, 237, 251, 266,
+ 281, 296, 312, 327, 343, 358, 374, 390,
+ 405, 421, 437, 453, 469, 484, 500, 516,
+ 532, 548, 564, 580, 596, 611, 627, 643,
+ 659, 674, 690, 706, 721, 737, 752, 768,
+ 783, 798, 814, 829, 844, 859, 874, 889,
+ 904, 919, 934, 949, 964, 978, 993, 1008,
+ 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122,
+ 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234,
+ 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342,
+ 1368, 1393, 1419, 1444, 1469, 1494, 1519, 1544,
+ 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741,
+ 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933,
+ 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199,
+ 2233, 2267, 2300, 2334, 2367, 2400, 2434, 2467,
+ 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788,
+ 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127,
+ 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517,
+ 3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951,
+ 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420,
+ 4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942,
+ 5013, 5083, 5153, 5222, 5291, 5367, 5442, 5517,
+ 5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149,
+ 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867,
+ 6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715,
+ 7832, 7958, 8085, 8214, 8352, 8492, 8635, 8788,
+ 8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245,
+ 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409,
+ 12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812,
+ 16356, 16943, 17575, 18237, 18949, 19718, 20521, 21387,
+ }
+};
+
+static const int16_t vp9_ac_qlookup[3][256] = {
+ {
+ 4, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 120, 122, 124, 126, 128, 130, 132, 134,
+ 136, 138, 140, 142, 144, 146, 148, 150,
+ 152, 155, 158, 161, 164, 167, 170, 173,
+ 176, 179, 182, 185, 188, 191, 194, 197,
+ 200, 203, 207, 211, 215, 219, 223, 227,
+ 231, 235, 239, 243, 247, 251, 255, 260,
+ 265, 270, 275, 280, 285, 290, 295, 300,
+ 305, 311, 317, 323, 329, 335, 341, 347,
+ 353, 359, 366, 373, 380, 387, 394, 401,
+ 408, 416, 424, 432, 440, 448, 456, 465,
+ 474, 483, 492, 501, 510, 520, 530, 540,
+ 550, 560, 571, 582, 593, 604, 615, 627,
+ 639, 651, 663, 676, 689, 702, 715, 729,
+ 743, 757, 771, 786, 801, 816, 832, 848,
+ 864, 881, 898, 915, 933, 951, 969, 988,
+ 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151,
+ 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343,
+ 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567,
+ 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
+ }, {
+ 4, 9, 11, 13, 16, 18, 21, 24,
+ 27, 30, 33, 37, 40, 44, 48, 51,
+ 55, 59, 63, 67, 71, 75, 79, 83,
+ 88, 92, 96, 100, 105, 109, 114, 118,
+ 122, 127, 131, 136, 140, 145, 149, 154,
+ 158, 163, 168, 172, 177, 181, 186, 190,
+ 195, 199, 204, 208, 213, 217, 222, 226,
+ 231, 235, 240, 244, 249, 253, 258, 262,
+ 267, 271, 275, 280, 284, 289, 293, 297,
+ 302, 306, 311, 315, 319, 324, 328, 332,
+ 337, 341, 345, 349, 354, 358, 362, 367,
+ 371, 375, 379, 384, 388, 392, 396, 401,
+ 409, 417, 425, 433, 441, 449, 458, 466,
+ 474, 482, 490, 498, 506, 514, 523, 531,
+ 539, 547, 555, 563, 571, 579, 588, 596,
+ 604, 616, 628, 640, 652, 664, 676, 688,
+ 700, 713, 725, 737, 749, 761, 773, 785,
+ 797, 809, 825, 841, 857, 873, 889, 905,
+ 922, 938, 954, 970, 986, 1002, 1018, 1038,
+ 1058, 1078, 1098, 1118, 1138, 1158, 1178, 1198,
+ 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386,
+ 1411, 1435, 1463, 1491, 1519, 1547, 1575, 1603,
+ 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1859,
+ 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159,
+ 2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507,
+ 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915,
+ 2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391,
+ 3455, 3523, 3591, 3659, 3731, 3803, 3876, 3952,
+ 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604,
+ 4692, 4784, 4876, 4972, 5068, 5168, 5268, 5372,
+ 5476, 5584, 5692, 5804, 5916, 6032, 6148, 6268,
+ 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312,
+ }, {
+ 4, 13, 19, 27, 35, 44, 54, 64,
+ 75, 87, 99, 112, 126, 139, 154, 168,
+ 183, 199, 214, 230, 247, 263, 280, 297,
+ 314, 331, 349, 366, 384, 402, 420, 438,
+ 456, 475, 493, 511, 530, 548, 567, 586,
+ 604, 623, 642, 660, 679, 698, 716, 735,
+ 753, 772, 791, 809, 828, 846, 865, 884,
+ 902, 920, 939, 957, 976, 994, 1012, 1030,
+ 1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175,
+ 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317,
+ 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457,
+ 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595,
+ 1627, 1660, 1693, 1725, 1758, 1791, 1824, 1856,
+ 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118,
+ 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378,
+ 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750,
+ 2798, 2847, 2895, 2943, 2992, 3040, 3088, 3137,
+ 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619,
+ 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149,
+ 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791,
+ 4871, 4967, 5064, 5160, 5256, 5352, 5448, 5544,
+ 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410,
+ 6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435,
+ 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635,
+ 8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028,
+ 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661,
+ 11885, 12109, 12333, 12573, 12813, 13053, 13309, 13565,
+ 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806,
+ 16110, 16414, 16734, 17054, 17390, 17726, 18062, 18414,
+ 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486,
+ 21902, 22334, 22766, 23214, 23662, 24126, 24590, 25070,
+ 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247,
+ }
+};
+
+static const enum TxfmType vp9_intra_txfm_type[14] = {
+ [VERT_PRED] = ADST_DCT,
+ [HOR_PRED] = DCT_ADST,
+ [DC_PRED] = DCT_DCT,
+ [DIAG_DOWN_LEFT_PRED] = DCT_DCT,
+ [DIAG_DOWN_RIGHT_PRED] = ADST_ADST,
+ [VERT_RIGHT_PRED] = ADST_DCT,
+ [HOR_DOWN_PRED] = DCT_ADST,
+ [VERT_LEFT_PRED] = ADST_DCT,
+ [HOR_UP_PRED] = DCT_ADST,
+ [TM_VP8_PRED] = ADST_ADST,
+ [NEARESTMV] = DCT_DCT,
+ [NEARMV] = DCT_DCT,
+ [ZEROMV] = DCT_DCT,
+ [NEWMV] = DCT_DCT,
+};
+
+static const int16_t vp9_default_scan_4x4[16] = {
+ 0, 1, 4, 5,
+ 2, 8, 3, 6,
+ 12, 9, 7, 10,
+ 13, 11, 14, 15,
+};
+
+static const int16_t vp9_col_scan_4x4[16] = {
+ 0, 1, 2, 4,
+ 3, 5, 6, 8,
+ 7, 9, 10, 12,
+ 13, 11, 14, 15,
+};
+
+static const int16_t vp9_row_scan_4x4[16] = {
+ 0, 4, 1, 8,
+ 5, 12, 9, 2,
+ 6, 13, 3, 10,
+ 7, 14, 11, 15,
+};
+
+static const int16_t vp9_default_scan_8x8[64] = {
+ 0, 1, 8, 2, 9, 16, 10, 3,
+ 17, 24, 18, 11, 4, 25, 32, 19,
+ 12, 26, 5, 33, 20, 27, 40, 13,
+ 34, 6, 41, 28, 21, 35, 42, 48,
+ 14, 7, 36, 29, 43, 56, 49, 22,
+ 15, 37, 50, 44, 57, 30, 23, 51,
+ 45, 58, 38, 31, 52, 59, 39, 46,
+ 53, 60, 47, 54, 61, 55, 62, 63,
+};
+
+static const int16_t vp9_col_scan_8x8[64] = {
+ 0, 1, 2, 8, 3, 9, 4, 10,
+ 16, 5, 11, 17, 12, 18, 6, 24,
+ 19, 13, 25, 7, 26, 20, 32, 14,
+ 27, 21, 33, 28, 34, 15, 22, 35,
+ 40, 29, 41, 36, 23, 30, 42, 37,
+ 48, 43, 31, 44, 49, 38, 50, 56,
+ 45, 39, 51, 57, 52, 46, 58, 53,
+ 59, 47, 60, 54, 61, 55, 62, 63,
+};
+
+static const int16_t vp9_row_scan_8x8[64] = {
+ 0, 8, 16, 1, 9, 24, 2, 17,
+ 32, 10, 25, 3, 40, 18, 11, 33,
+ 26, 19, 4, 48, 41, 34, 12, 27,
+ 56, 20, 5, 42, 35, 13, 49, 28,
+ 6, 21, 43, 36, 14, 50, 29, 57,
+ 7, 44, 22, 37, 51, 15, 58, 30,
+ 23, 45, 52, 38, 59, 31, 46, 53,
+ 39, 60, 47, 61, 54, 62, 55, 63,
+};
+
+static const int16_t vp9_default_scan_16x16[256] = {
+ 0, 1, 16, 2, 17, 32, 3, 18, 33, 48, 4, 34, 19, 49, 20, 5,
+ 35, 64, 50, 36, 65, 21, 6, 51, 80, 66, 37, 22, 52, 7, 81, 67,
+ 38, 82, 53, 23, 96, 68, 8, 83, 97, 54, 39, 69, 112, 24, 98, 84,
+ 70, 55, 9, 40, 85, 99, 113, 128, 25, 114, 100, 71, 86, 56, 10, 41,
+ 115, 101, 129, 116, 72, 87, 26, 130, 144, 102, 57, 11, 42, 117, 131, 145,
+ 88, 103, 27, 73, 132, 118, 146, 58, 160, 12, 43, 133, 147, 104, 89, 119,
+ 161, 74, 148, 134, 28, 162, 59, 13, 176, 120, 149, 90, 135, 105, 163, 44,
+ 75, 177, 164, 29, 150, 121, 136, 178, 165, 14, 106, 60, 91, 151, 45, 179,
+ 192, 137, 166, 122, 76, 180, 152, 30, 61, 15, 107, 167, 181, 193, 92, 208,
+ 46, 138, 123, 153, 194, 77, 168, 182, 31, 195, 209, 183, 108, 139, 62, 154,
+ 47, 196, 93, 169, 210, 197, 224, 124, 184, 211, 78, 109, 170, 155, 63, 198,
+ 212, 185, 225, 240, 140, 94, 199, 125, 79, 213, 226, 171, 186, 156, 214, 200,
+ 110, 227, 141, 95, 241, 215, 228, 201, 126, 242, 187, 172, 157, 229, 111, 216,
+ 243, 142, 202, 230, 127, 217, 244, 173, 188, 231, 158, 203, 143, 245, 218, 232,
+ 189, 246, 159, 174, 233, 247, 219, 204, 175, 190, 248, 234, 205, 220, 249, 191,
+ 235, 221, 250, 206, 222, 251, 236, 207, 237, 223, 252, 238, 253, 239, 254, 255,
+};
+
+static const int16_t vp9_col_scan_16x16[256] = {
+ 0, 1, 2, 3, 16, 4, 17, 5, 18, 6, 19, 32, 20, 7, 33, 21,
+ 34, 8, 35, 22, 48, 36, 9, 49, 23, 50, 37, 10, 38, 51, 24, 64,
+ 52, 11, 65, 39, 25, 53, 66, 54, 40, 67, 12, 80, 26, 68, 55, 81,
+ 41, 69, 13, 27, 82, 56, 70, 83, 42, 14, 84, 96, 71, 28, 57, 85,
+ 97, 15, 72, 98, 43, 86, 58, 99, 29, 87, 100, 112, 73, 44, 101, 59,
+ 30, 113, 88, 114, 74, 128, 102, 45, 31, 115, 60, 103, 89, 116, 75, 129,
+ 117, 46, 104, 90, 61, 130, 118, 131, 132, 105, 76, 47, 119, 144, 91, 62,
+ 133, 106, 145, 120, 146, 134, 77, 147, 121, 92, 135, 148, 63, 107, 136, 122,
+ 93, 149, 160, 78, 150, 137, 108, 161, 162, 151, 123, 79, 138, 163, 152, 94,
+ 164, 109, 165, 153, 124, 139, 176, 166, 95, 177, 167, 110, 154, 178, 125, 179,
+ 140, 168, 155, 111, 180, 192, 181, 169, 141, 126, 182, 193, 194, 156, 183, 170,
+ 195, 127, 142, 196, 184, 208, 197, 157, 171, 143, 185, 198, 209, 199, 210, 172,
+ 158, 186, 211, 224, 212, 200, 240, 159, 213, 225, 187, 201, 173, 226, 214, 215,
+ 227, 202, 228, 188, 241, 216, 174, 229, 242, 203, 243, 217, 230, 175, 189, 244,
+ 231, 204, 218, 232, 245, 219, 246, 190, 233, 205, 191, 247, 234, 248, 220, 206,
+ 249, 235, 221, 207, 250, 236, 222, 251, 223, 237, 238, 252, 239, 253, 254, 255,
+};
+
+static const int16_t vp9_row_scan_16x16[256] = {
+ 0, 16, 32, 1, 48, 17, 64, 33, 2, 80, 18, 49, 96, 34, 3, 65,
+ 19, 112, 50, 81, 35, 4, 128, 66, 20, 97, 51, 82, 5, 144, 36, 67,
+ 113, 98, 21, 52, 160, 83, 129, 37, 68, 6, 114, 176, 99, 53, 22, 84,
+ 145, 38, 69, 130, 7, 115, 192, 100, 54, 23, 85, 161, 146, 131, 39, 70,
+ 208, 116, 8, 101, 177, 55, 86, 24, 162, 147, 132, 71, 224, 117, 40, 102,
+ 9, 148, 56, 87, 193, 163, 240, 133, 178, 25, 118, 72, 41, 103, 164, 10,
+ 149, 88, 134, 209, 179, 57, 119, 194, 26, 73, 165, 150, 104, 42, 135, 11,
+ 180, 120, 89, 225, 195, 58, 27, 210, 151, 181, 166, 74, 43, 105, 12, 136,
+ 90, 59, 241, 121, 28, 196, 167, 211, 152, 44, 182, 137, 75, 13, 226, 106,
+ 122, 60, 197, 91, 168, 29, 183, 153, 14, 76, 212, 138, 45, 107, 15, 198,
+ 92, 227, 169, 30, 123, 154, 61, 242, 184, 213, 139, 46, 77, 31, 108, 170,
+ 199, 185, 124, 228, 93, 155, 214, 62, 140, 243, 78, 47, 200, 109, 186, 171,
+ 201, 94, 63, 215, 229, 156, 79, 125, 141, 110, 216, 187, 172, 244, 202, 230,
+ 217, 95, 157, 126, 245, 111, 142, 231, 188, 127, 158, 218, 173, 232, 246, 233,
+ 203, 143, 247, 174, 189, 159, 219, 204, 248, 234, 249, 175, 190, 220, 205, 250,
+ 235, 191, 221, 251, 236, 206, 252, 222, 207, 237, 223, 253, 238, 254, 239, 255,
+};
+
+static const int16_t vp9_default_scan_32x32[1024] = {
+ 0, 1, 32, 2, 33, 64, 3, 34, 65, 4, 96, 35, 66, 5, 36, 97, 67, 128, 98, 68, 37, 6, 129, 99, 7, 160, 69, 38, 130, 100, 161, 131,
+ 39, 70, 8, 101, 162, 132, 192, 71, 40, 9, 102, 163, 133, 193, 72, 224, 103, 41, 164, 10, 194, 134, 165, 73, 104, 135, 225, 42, 195, 11, 256, 166,
+ 226, 196, 74, 105, 136, 43, 12, 167, 197, 227, 257, 75, 106, 137, 228, 44, 198, 168, 258, 288, 13, 229, 76, 107, 199, 138, 259, 169, 289, 45, 230, 260,
+ 200, 108, 14, 170, 139, 320, 290, 77, 231, 261, 46, 201, 140, 291, 109, 232, 321, 262, 171, 78, 292, 15, 322, 202, 263, 352, 172, 293, 233, 141, 323, 110,
+ 47, 203, 264, 234, 294, 353, 324, 16, 79, 204, 265, 295, 325, 173, 354, 142, 235, 384, 48, 296, 111, 266, 355, 326, 80, 17, 205, 236, 174, 356, 385, 327,
+ 143, 297, 267, 357, 386, 112, 49, 328, 298, 206, 416, 237, 358, 387, 81, 175, 18, 329, 359, 388, 299, 330, 389, 113, 417, 238, 360, 50, 207, 418, 390, 331,
+ 19, 448, 361, 82, 419, 391, 239, 51, 362, 420, 114, 449, 480, 421, 83, 363, 450, 422, 512, 451, 423, 115, 452, 481, 453, 482, 454, 544, 483, 455, 513, 484,
+ 514, 485, 515, 486, 545, 576, 487, 546, 547, 608, 577, 578, 579, 609, 610, 611, 20, 144, 268, 392, 516, 640, 21, 52, 145, 176, 269, 300, 393, 424, 517, 548,
+ 641, 672, 22, 53, 84, 146, 177, 208, 270, 301, 332, 394, 425, 456, 518, 549, 580, 642, 673, 704, 23, 54, 85, 116, 147, 178, 209, 240, 271, 302, 333, 364,
+ 395, 426, 457, 488, 519, 550, 581, 612, 643, 674, 705, 736, 55, 86, 117, 179, 210, 241, 303, 334, 365, 427, 458, 489, 551, 582, 613, 675, 706, 737, 87, 118,
+ 211, 242, 335, 366, 459, 490, 583, 614, 707, 738, 119, 243, 367, 491, 615, 739, 24, 148, 272, 396, 520, 644, 768, 25, 56, 149, 180, 273, 304, 397, 428, 521,
+ 552, 645, 676, 769, 800, 26, 57, 88, 150, 181, 212, 274, 305, 336, 398, 429, 460, 522, 553, 584, 646, 677, 708, 770, 801, 832, 27, 58, 89, 120, 151, 182,
+ 213, 244, 275, 306, 337, 368, 399, 430, 461, 492, 523, 554, 585, 616, 647, 678, 709, 740, 771, 802, 833, 864, 59, 90, 121, 183, 214, 245, 307, 338, 369, 431,
+ 462, 493, 555, 586, 617, 679, 710, 741, 803, 834, 865, 91, 122, 215, 246, 339, 370, 463, 494, 587, 618, 711, 742, 835, 866, 123, 247, 371, 495, 619, 743, 867,
+ 28, 152, 276, 400, 524, 648, 772, 896, 29, 60, 153, 184, 277, 308, 401, 432, 525, 556, 649, 680, 773, 804, 897, 928, 30, 61, 92, 154, 185, 216, 278, 309,
+ 340, 402, 433, 464, 526, 557, 588, 650, 681, 712, 774, 805, 836, 898, 929, 960, 31, 62, 93, 124, 155, 186, 217, 248, 279, 310, 341, 372, 403, 434, 465, 496,
+ 527, 558, 589, 620, 651, 682, 713, 744, 775, 806, 837, 868, 899, 930, 961, 992, 63, 94, 125, 187, 218, 249, 311, 342, 373, 435, 466, 497, 559, 590, 621, 683,
+ 714, 745, 807, 838, 869, 931, 962, 993, 95, 126, 219, 250, 343, 374, 467, 498, 591, 622, 715, 746, 839, 870, 963, 994, 127, 251, 375, 499, 623, 747, 871, 995,
+ 156, 280, 404, 528, 652, 776, 900, 157, 188, 281, 312, 405, 436, 529, 560, 653, 684, 777, 808, 901, 932, 158, 189, 220, 282, 313, 344, 406, 437, 468, 530, 561,
+ 592, 654, 685, 716, 778, 809, 840, 902, 933, 964, 159, 190, 221, 252, 283, 314, 345, 376, 407, 438, 469, 500, 531, 562, 593, 624, 655, 686, 717, 748, 779, 810,
+ 841, 872, 903, 934, 965, 996, 191, 222, 253, 315, 346, 377, 439, 470, 501, 563, 594, 625, 687, 718, 749, 811, 842, 873, 935, 966, 997, 223, 254, 347, 378, 471,
+ 502, 595, 626, 719, 750, 843, 874, 967, 998, 255, 379, 503, 627, 751, 875, 999, 284, 408, 532, 656, 780, 904, 285, 316, 409, 440, 533, 564, 657, 688, 781, 812,
+ 905, 936, 286, 317, 348, 410, 441, 472, 534, 565, 596, 658, 689, 720, 782, 813, 844, 906, 937, 968, 287, 318, 349, 380, 411, 442, 473, 504, 535, 566, 597, 628,
+ 659, 690, 721, 752, 783, 814, 845, 876, 907, 938, 969, 1000, 319, 350, 381, 443, 474, 505, 567, 598, 629, 691, 722, 753, 815, 846, 877, 939, 970, 1001, 351, 382,
+ 475, 506, 599, 630, 723, 754, 847, 878, 971, 1002, 383, 507, 631, 755, 879, 1003, 412, 536, 660, 784, 908, 413, 444, 537, 568, 661, 692, 785, 816, 909, 940, 414,
+ 445, 476, 538, 569, 600, 662, 693, 724, 786, 817, 848, 910, 941, 972, 415, 446, 477, 508, 539, 570, 601, 632, 663, 694, 725, 756, 787, 818, 849, 880, 911, 942,
+ 973, 1004, 447, 478, 509, 571, 602, 633, 695, 726, 757, 819, 850, 881, 943, 974, 1005, 479, 510, 603, 634, 727, 758, 851, 882, 975, 1006, 511, 635, 759, 883, 1007,
+ 540, 664, 788, 912, 541, 572, 665, 696, 789, 820, 913, 944, 542, 573, 604, 666, 697, 728, 790, 821, 852, 914, 945, 976, 543, 574, 605, 636, 667, 698, 729, 760,
+ 791, 822, 853, 884, 915, 946, 977, 1008, 575, 606, 637, 699, 730, 761, 823, 854, 885, 947, 978, 1009, 607, 638, 731, 762, 855, 886, 979, 1010, 639, 763, 887, 1011,
+ 668, 792, 916, 669, 700, 793, 824, 917, 948, 670, 701, 732, 794, 825, 856, 918, 949, 980, 671, 702, 733, 764, 795, 826, 857, 888, 919, 950, 981, 1012, 703, 734,
+ 765, 827, 858, 889, 951, 982, 1013, 735, 766, 859, 890, 983, 1014, 767, 891, 1015, 796, 920, 797, 828, 921, 952, 798, 829, 860, 922, 953, 984, 799, 830, 861, 892,
+ 923, 954, 985, 1016, 831, 862, 893, 955, 986, 1017, 863, 894, 987, 1018, 895, 1019, 924, 925, 956, 926, 957, 988, 927, 958, 989, 1020, 959, 990, 1021, 991, 1022, 1023,
+};
+
+static const int16_t * const vp9_scans[5][4] = {
+ {
+ vp9_default_scan_4x4, vp9_col_scan_4x4,
+ vp9_row_scan_4x4, vp9_default_scan_4x4
+ }, {
+ vp9_default_scan_8x8, vp9_col_scan_8x8,
+ vp9_row_scan_8x8, vp9_default_scan_8x8
+ }, {
+ vp9_default_scan_16x16, vp9_col_scan_16x16,
+ vp9_row_scan_16x16, vp9_default_scan_16x16
+ }, {
+ vp9_default_scan_32x32, vp9_default_scan_32x32,
+ vp9_default_scan_32x32, vp9_default_scan_32x32
+ }, { // lossless
+ vp9_default_scan_4x4, vp9_default_scan_4x4,
+ vp9_default_scan_4x4, vp9_default_scan_4x4
+ }
+};
+
+static const int16_t vp9_default_scan_4x4_nb[16][2] = {
+ { 0, 0 }, { 0, 0 }, { 4, 1 }, { 1, 1 },
+ { 4, 4 }, { 2, 2 }, { 5, 2 }, { 8, 8 },
+ { 8, 5 }, { 6, 3 }, { 9, 6 }, { 12, 9 },
+ { 10, 7 }, { 13, 10 }, { 14, 11 }, { 0, 0 },
+};
+
+static const int16_t vp9_col_scan_4x4_nb[16][2] = {
+ { 0, 0 }, { 1, 1 }, { 0, 0 }, { 2, 2 },
+ { 4, 4 }, { 5, 5 }, { 4, 4 }, { 6, 6 },
+ { 8, 8 }, { 9, 9 }, { 8, 8 }, { 12, 12 },
+ { 10, 10 }, { 13, 13 }, { 14, 14 }, { 0, 0 },
+};
+
+static const int16_t vp9_row_scan_4x4_nb[16][2] = {
+ { 0, 0 }, { 0, 0 }, { 4, 4 }, { 1, 1 },
+ { 8, 8 }, { 5, 5 }, { 1, 1 }, { 2, 2 },
+ { 9, 9 }, { 2, 2 }, { 6, 6 }, { 3, 3 },
+ { 10, 10 }, { 7, 7 }, { 11, 11 }, { 0, 0 },
+};
+
+static const int16_t vp9_default_scan_8x8_nb[64][2] = {
+ { 0, 0 }, { 0, 0 }, { 1, 1 }, { 8, 1 },
+ { 8, 8 }, { 9, 2 }, { 2, 2 }, { 16, 9 },
+ { 16, 16 }, { 17, 10 }, { 10, 3 }, { 3, 3 },
+ { 24, 17 }, { 24, 24 }, { 18, 11 }, { 11, 4 },
+ { 25, 18 }, { 4, 4 }, { 32, 25 }, { 19, 12 },
+ { 26, 19 }, { 32, 32 }, { 12, 5 }, { 33, 26 },
+ { 5, 5 }, { 40, 33 }, { 27, 20 }, { 20, 13 },
+ { 34, 27 }, { 41, 34 }, { 40, 40 }, { 13, 6 },
+ { 6, 6 }, { 35, 28 }, { 28, 21 }, { 42, 35 },
+ { 48, 48 }, { 48, 41 }, { 21, 14 }, { 14, 7 },
+ { 36, 29 }, { 49, 42 }, { 43, 36 }, { 56, 49 },
+ { 29, 22 }, { 22, 15 }, { 50, 43 }, { 44, 37 },
+ { 57, 50 }, { 37, 30 }, { 30, 23 }, { 51, 44 },
+ { 58, 51 }, { 38, 31 }, { 45, 38 }, { 52, 45 },
+ { 59, 52 }, { 46, 39 }, { 53, 46 }, { 60, 53 },
+ { 54, 47 }, { 61, 54 }, { 62, 55 }, { 0, 0 },
+};
+
+static const int16_t vp9_col_scan_8x8_nb[64][2] = {
+ { 0, 0 }, { 1, 1 }, { 0, 0 }, { 2, 2 },
+ { 8, 8 }, { 3, 3 }, { 9, 9 }, { 8, 8 },
+ { 4, 4 }, { 10, 10 }, { 16, 16 }, { 11, 11 },
+ { 17, 17 }, { 5, 5 }, { 16, 16 }, { 18, 18 },
+ { 12, 12 }, { 24, 24 }, { 6, 6 }, { 25, 25 },
+ { 19, 19 }, { 24, 24 }, { 13, 13 }, { 26, 26 },
+ { 20, 20 }, { 32, 32 }, { 27, 27 }, { 33, 33 },
+ { 14, 14 }, { 21, 21 }, { 34, 34 }, { 32, 32 },
+ { 28, 28 }, { 40, 40 }, { 35, 35 }, { 22, 22 },
+ { 29, 29 }, { 41, 41 }, { 36, 36 }, { 40, 40 },
+ { 42, 42 }, { 30, 30 }, { 43, 43 }, { 48, 48 },
+ { 37, 37 }, { 49, 49 }, { 48, 48 }, { 44, 44 },
+ { 38, 38 }, { 50, 50 }, { 56, 56 }, { 51, 51 },
+ { 45, 45 }, { 57, 57 }, { 52, 52 }, { 58, 58 },
+ { 46, 46 }, { 59, 59 }, { 53, 53 }, { 60, 60 },
+ { 54, 54 }, { 61, 61 }, { 62, 62 }, { 0, 0 },
+};
+
+static const int16_t vp9_row_scan_8x8_nb[64][2] = {
+ { 0, 0 }, { 8, 8 }, { 0, 0 }, { 1, 1 },
+ { 16, 16 }, { 1, 1 }, { 9, 9 }, { 24, 24 },
+ { 2, 2 }, { 17, 17 }, { 2, 2 }, { 32, 32 },
+ { 10, 10 }, { 3, 3 }, { 25, 25 }, { 18, 18 },
+ { 11, 11 }, { 3, 3 }, { 40, 40 }, { 33, 33 },
+ { 26, 26 }, { 4, 4 }, { 19, 19 }, { 48, 48 },
+ { 12, 12 }, { 4, 4 }, { 34, 34 }, { 27, 27 },
+ { 5, 5 }, { 41, 41 }, { 20, 20 }, { 5, 5 },
+ { 13, 13 }, { 35, 35 }, { 28, 28 }, { 6, 6 },
+ { 42, 42 }, { 21, 21 }, { 49, 49 }, { 6, 6 },
+ { 36, 36 }, { 14, 14 }, { 29, 29 }, { 43, 43 },
+ { 7, 7 }, { 50, 50 }, { 22, 22 }, { 15, 15 },
+ { 37, 37 }, { 44, 44 }, { 30, 30 }, { 51, 51 },
+ { 23, 23 }, { 38, 38 }, { 45, 45 }, { 31, 31 },
+ { 52, 52 }, { 39, 39 }, { 53, 53 }, { 46, 46 },
+ { 54, 54 }, { 47, 47 }, { 55, 55 }, { 0, 0 },
+};
+
+static const int16_t vp9_default_scan_16x16_nb[256][2] = {
+ { 0, 0 }, { 0, 0 }, { 1, 1 }, { 16, 1 },
+ { 16, 16 }, { 2, 2 }, { 17, 2 }, { 32, 17 },
+ { 32, 32 }, { 3, 3 }, { 33, 18 }, { 18, 3 },
+ { 48, 33 }, { 19, 4 }, { 4, 4 }, { 34, 19 },
+ { 48, 48 }, { 49, 34 }, { 35, 20 }, { 64, 49 },
+ { 20, 5 }, { 5, 5 }, { 50, 35 }, { 64, 64 },
+ { 65, 50 }, { 36, 21 }, { 21, 6 }, { 51, 36 },
+ { 6, 6 }, { 80, 65 }, { 66, 51 }, { 37, 22 },
+ { 81, 66 }, { 52, 37 }, { 22, 7 }, { 80, 80 },
+ { 67, 52 }, { 7, 7 }, { 82, 67 }, { 96, 81 },
+ { 53, 38 }, { 38, 23 }, { 68, 53 }, { 96, 96 },
+ { 23, 8 }, { 97, 82 }, { 83, 68 }, { 69, 54 },
+ { 54, 39 }, { 8, 8 }, { 39, 24 }, { 84, 69 },
+ { 98, 83 }, { 112, 97 }, { 112, 112 }, { 24, 9 },
+ { 113, 98 }, { 99, 84 }, { 70, 55 }, { 85, 70 },
+ { 55, 40 }, { 9, 9 }, { 40, 25 }, { 114, 99 },
+ { 100, 85 }, { 128, 113 }, { 115, 100 }, { 71, 56 },
+ { 86, 71 }, { 25, 10 }, { 129, 114 }, { 128, 128 },
+ { 101, 86 }, { 56, 41 }, { 10, 10 }, { 41, 26 },
+ { 116, 101 }, { 130, 115 }, { 144, 129 }, { 87, 72 },
+ { 102, 87 }, { 26, 11 }, { 72, 57 }, { 131, 116 },
+ { 117, 102 }, { 145, 130 }, { 57, 42 }, { 144, 144 },
+ { 11, 11 }, { 42, 27 }, { 132, 117 }, { 146, 131 },
+ { 103, 88 }, { 88, 73 }, { 118, 103 }, { 160, 145 },
+ { 73, 58 }, { 147, 132 }, { 133, 118 }, { 27, 12 },
+ { 161, 146 }, { 58, 43 }, { 12, 12 }, { 160, 160 },
+ { 119, 104 }, { 148, 133 }, { 89, 74 }, { 134, 119 },
+ { 104, 89 }, { 162, 147 }, { 43, 28 }, { 74, 59 },
+ { 176, 161 }, { 163, 148 }, { 28, 13 }, { 149, 134 },
+ { 120, 105 }, { 135, 120 }, { 177, 162 }, { 164, 149 },
+ { 13, 13 }, { 105, 90 }, { 59, 44 }, { 90, 75 },
+ { 150, 135 }, { 44, 29 }, { 178, 163 }, { 176, 176 },
+ { 136, 121 }, { 165, 150 }, { 121, 106 }, { 75, 60 },
+ { 179, 164 }, { 151, 136 }, { 29, 14 }, { 60, 45 },
+ { 14, 14 }, { 106, 91 }, { 166, 151 }, { 180, 165 },
+ { 192, 177 }, { 91, 76 }, { 192, 192 }, { 45, 30 },
+ { 137, 122 }, { 122, 107 }, { 152, 137 }, { 193, 178 },
+ { 76, 61 }, { 167, 152 }, { 181, 166 }, { 30, 15 },
+ { 194, 179 }, { 208, 193 }, { 182, 167 }, { 107, 92 },
+ { 138, 123 }, { 61, 46 }, { 153, 138 }, { 46, 31 },
+ { 195, 180 }, { 92, 77 }, { 168, 153 }, { 209, 194 },
+ { 196, 181 }, { 208, 208 }, { 123, 108 }, { 183, 168 },
+ { 210, 195 }, { 77, 62 }, { 108, 93 }, { 169, 154 },
+ { 154, 139 }, { 62, 47 }, { 197, 182 }, { 211, 196 },
+ { 184, 169 }, { 224, 209 }, { 224, 224 }, { 139, 124 },
+ { 93, 78 }, { 198, 183 }, { 124, 109 }, { 78, 63 },
+ { 212, 197 }, { 225, 210 }, { 170, 155 }, { 185, 170 },
+ { 155, 140 }, { 213, 198 }, { 199, 184 }, { 109, 94 },
+ { 226, 211 }, { 140, 125 }, { 94, 79 }, { 240, 225 },
+ { 214, 199 }, { 227, 212 }, { 200, 185 }, { 125, 110 },
+ { 241, 226 }, { 186, 171 }, { 171, 156 }, { 156, 141 },
+ { 228, 213 }, { 110, 95 }, { 215, 200 }, { 242, 227 },
+ { 141, 126 }, { 201, 186 }, { 229, 214 }, { 126, 111 },
+ { 216, 201 }, { 243, 228 }, { 172, 157 }, { 187, 172 },
+ { 230, 215 }, { 157, 142 }, { 202, 187 }, { 142, 127 },
+ { 244, 229 }, { 217, 202 }, { 231, 216 }, { 188, 173 },
+ { 245, 230 }, { 158, 143 }, { 173, 158 }, { 232, 217 },
+ { 246, 231 }, { 218, 203 }, { 203, 188 }, { 174, 159 },
+ { 189, 174 }, { 247, 232 }, { 233, 218 }, { 204, 189 },
+ { 219, 204 }, { 248, 233 }, { 190, 175 }, { 234, 219 },
+ { 220, 205 }, { 249, 234 }, { 205, 190 }, { 221, 206 },
+ { 250, 235 }, { 235, 220 }, { 206, 191 }, { 236, 221 },
+ { 222, 207 }, { 251, 236 }, { 237, 222 }, { 252, 237 },
+ { 238, 223 }, { 253, 238 }, { 254, 239 }, { 0, 0 },
+};
+
+static const int16_t vp9_col_scan_16x16_nb[256][2] = {
+ { 0, 0 }, { 1, 1 }, { 2, 2 }, { 0, 0 },
+ { 3, 3 }, { 16, 16 }, { 4, 4 }, { 17, 17 },
+ { 5, 5 }, { 18, 18 }, { 16, 16 }, { 19, 19 },
+ { 6, 6 }, { 32, 32 }, { 20, 20 }, { 33, 33 },
+ { 7, 7 }, { 34, 34 }, { 21, 21 }, { 32, 32 },
+ { 35, 35 }, { 8, 8 }, { 48, 48 }, { 22, 22 },
+ { 49, 49 }, { 36, 36 }, { 9, 9 }, { 37, 37 },
+ { 50, 50 }, { 23, 23 }, { 48, 48 }, { 51, 51 },
+ { 10, 10 }, { 64, 64 }, { 38, 38 }, { 24, 24 },
+ { 52, 52 }, { 65, 65 }, { 53, 53 }, { 39, 39 },
+ { 66, 66 }, { 11, 11 }, { 64, 64 }, { 25, 25 },
+ { 67, 67 }, { 54, 54 }, { 80, 80 }, { 40, 40 },
+ { 68, 68 }, { 12, 12 }, { 26, 26 }, { 81, 81 },
+ { 55, 55 }, { 69, 69 }, { 82, 82 }, { 41, 41 },
+ { 13, 13 }, { 83, 83 }, { 80, 80 }, { 70, 70 },
+ { 27, 27 }, { 56, 56 }, { 84, 84 }, { 96, 96 },
+ { 14, 14 }, { 71, 71 }, { 97, 97 }, { 42, 42 },
+ { 85, 85 }, { 57, 57 }, { 98, 98 }, { 28, 28 },
+ { 86, 86 }, { 99, 99 }, { 96, 96 }, { 72, 72 },
+ { 43, 43 }, { 100, 100 }, { 58, 58 }, { 29, 29 },
+ { 112, 112 }, { 87, 87 }, { 113, 113 }, { 73, 73 },
+ { 112, 112 }, { 101, 101 }, { 44, 44 }, { 30, 30 },
+ { 114, 114 }, { 59, 59 }, { 102, 102 }, { 88, 88 },
+ { 115, 115 }, { 74, 74 }, { 128, 128 }, { 116, 116 },
+ { 45, 45 }, { 103, 103 }, { 89, 89 }, { 60, 60 },
+ { 129, 129 }, { 117, 117 }, { 130, 130 }, { 131, 131 },
+ { 104, 104 }, { 75, 75 }, { 46, 46 }, { 118, 118 },
+ { 128, 128 }, { 90, 90 }, { 61, 61 }, { 132, 132 },
+ { 105, 105 }, { 144, 144 }, { 119, 119 }, { 145, 145 },
+ { 133, 133 }, { 76, 76 }, { 146, 146 }, { 120, 120 },
+ { 91, 91 }, { 134, 134 }, { 147, 147 }, { 62, 62 },
+ { 106, 106 }, { 135, 135 }, { 121, 121 }, { 92, 92 },
+ { 148, 148 }, { 144, 144 }, { 77, 77 }, { 149, 149 },
+ { 136, 136 }, { 107, 107 }, { 160, 160 }, { 161, 161 },
+ { 150, 150 }, { 122, 122 }, { 78, 78 }, { 137, 137 },
+ { 162, 162 }, { 151, 151 }, { 93, 93 }, { 163, 163 },
+ { 108, 108 }, { 164, 164 }, { 152, 152 }, { 123, 123 },
+ { 138, 138 }, { 160, 160 }, { 165, 165 }, { 94, 94 },
+ { 176, 176 }, { 166, 166 }, { 109, 109 }, { 153, 153 },
+ { 177, 177 }, { 124, 124 }, { 178, 178 }, { 139, 139 },
+ { 167, 167 }, { 154, 154 }, { 110, 110 }, { 179, 179 },
+ { 176, 176 }, { 180, 180 }, { 168, 168 }, { 140, 140 },
+ { 125, 125 }, { 181, 181 }, { 192, 192 }, { 193, 193 },
+ { 155, 155 }, { 182, 182 }, { 169, 169 }, { 194, 194 },
+ { 126, 126 }, { 141, 141 }, { 195, 195 }, { 183, 183 },
+ { 192, 192 }, { 196, 196 }, { 156, 156 }, { 170, 170 },
+ { 142, 142 }, { 184, 184 }, { 197, 197 }, { 208, 208 },
+ { 198, 198 }, { 209, 209 }, { 171, 171 }, { 157, 157 },
+ { 185, 185 }, { 210, 210 }, { 208, 208 }, { 211, 211 },
+ { 199, 199 }, { 224, 224 }, { 158, 158 }, { 212, 212 },
+ { 224, 224 }, { 186, 186 }, { 200, 200 }, { 172, 172 },
+ { 225, 225 }, { 213, 213 }, { 214, 214 }, { 226, 226 },
+ { 201, 201 }, { 227, 227 }, { 187, 187 }, { 240, 240 },
+ { 215, 215 }, { 173, 173 }, { 228, 228 }, { 241, 241 },
+ { 202, 202 }, { 242, 242 }, { 216, 216 }, { 229, 229 },
+ { 174, 174 }, { 188, 188 }, { 243, 243 }, { 230, 230 },
+ { 203, 203 }, { 217, 217 }, { 231, 231 }, { 244, 244 },
+ { 218, 218 }, { 245, 245 }, { 189, 189 }, { 232, 232 },
+ { 204, 204 }, { 190, 190 }, { 246, 246 }, { 233, 233 },
+ { 247, 247 }, { 219, 219 }, { 205, 205 }, { 248, 248 },
+ { 234, 234 }, { 220, 220 }, { 206, 206 }, { 249, 249 },
+ { 235, 235 }, { 221, 221 }, { 250, 250 }, { 222, 222 },
+ { 236, 236 }, { 237, 237 }, { 251, 251 }, { 238, 238 },
+ { 252, 252 }, { 253, 253 }, { 254, 254 }, { 0, 0 },
+};
+
+static const int16_t vp9_row_scan_16x16_nb[256][2] = {
+ { 0, 0 }, { 16, 16 }, { 0, 0 }, { 32, 32 },
+ { 1, 1 }, { 48, 48 }, { 17, 17 }, { 1, 1 },
+ { 64, 64 }, { 2, 2 }, { 33, 33 }, { 80, 80 },
+ { 18, 18 }, { 2, 2 }, { 49, 49 }, { 3, 3 },
+ { 96, 96 }, { 34, 34 }, { 65, 65 }, { 19, 19 },
+ { 3, 3 }, { 112, 112 }, { 50, 50 }, { 4, 4 },
+ { 81, 81 }, { 35, 35 }, { 66, 66 }, { 4, 4 },
+ { 128, 128 }, { 20, 20 }, { 51, 51 }, { 97, 97 },
+ { 82, 82 }, { 5, 5 }, { 36, 36 }, { 144, 144 },
+ { 67, 67 }, { 113, 113 }, { 21, 21 }, { 52, 52 },
+ { 5, 5 }, { 98, 98 }, { 160, 160 }, { 83, 83 },
+ { 37, 37 }, { 6, 6 }, { 68, 68 }, { 129, 129 },
+ { 22, 22 }, { 53, 53 }, { 114, 114 }, { 6, 6 },
+ { 99, 99 }, { 176, 176 }, { 84, 84 }, { 38, 38 },
+ { 7, 7 }, { 69, 69 }, { 145, 145 }, { 130, 130 },
+ { 115, 115 }, { 23, 23 }, { 54, 54 }, { 192, 192 },
+ { 100, 100 }, { 7, 7 }, { 85, 85 }, { 161, 161 },
+ { 39, 39 }, { 70, 70 }, { 8, 8 }, { 146, 146 },
+ { 131, 131 }, { 116, 116 }, { 55, 55 }, { 208, 208 },
+ { 101, 101 }, { 24, 24 }, { 86, 86 }, { 8, 8 },
+ { 132, 132 }, { 40, 40 }, { 71, 71 }, { 177, 177 },
+ { 147, 147 }, { 224, 224 }, { 117, 117 }, { 162, 162 },
+ { 9, 9 }, { 102, 102 }, { 56, 56 }, { 25, 25 },
+ { 87, 87 }, { 148, 148 }, { 9, 9 }, { 133, 133 },
+ { 72, 72 }, { 118, 118 }, { 193, 193 }, { 163, 163 },
+ { 41, 41 }, { 103, 103 }, { 178, 178 }, { 10, 10 },
+ { 57, 57 }, { 149, 149 }, { 134, 134 }, { 88, 88 },
+ { 26, 26 }, { 119, 119 }, { 10, 10 }, { 164, 164 },
+ { 104, 104 }, { 73, 73 }, { 209, 209 }, { 179, 179 },
+ { 42, 42 }, { 11, 11 }, { 194, 194 }, { 135, 135 },
+ { 165, 165 }, { 150, 150 }, { 58, 58 }, { 27, 27 },
+ { 89, 89 }, { 11, 11 }, { 120, 120 }, { 74, 74 },
+ { 43, 43 }, { 225, 225 }, { 105, 105 }, { 12, 12 },
+ { 180, 180 }, { 151, 151 }, { 195, 195 }, { 136, 136 },
+ { 28, 28 }, { 166, 166 }, { 121, 121 }, { 59, 59 },
+ { 12, 12 }, { 210, 210 }, { 90, 90 }, { 106, 106 },
+ { 44, 44 }, { 181, 181 }, { 75, 75 }, { 152, 152 },
+ { 13, 13 }, { 167, 167 }, { 137, 137 }, { 13, 13 },
+ { 60, 60 }, { 196, 196 }, { 122, 122 }, { 29, 29 },
+ { 91, 91 }, { 14, 14 }, { 182, 182 }, { 76, 76 },
+ { 211, 211 }, { 153, 153 }, { 14, 14 }, { 107, 107 },
+ { 138, 138 }, { 45, 45 }, { 226, 226 }, { 168, 168 },
+ { 197, 197 }, { 123, 123 }, { 30, 30 }, { 61, 61 },
+ { 15, 15 }, { 92, 92 }, { 154, 154 }, { 183, 183 },
+ { 169, 169 }, { 108, 108 }, { 212, 212 }, { 77, 77 },
+ { 139, 139 }, { 198, 198 }, { 46, 46 }, { 124, 124 },
+ { 227, 227 }, { 62, 62 }, { 31, 31 }, { 184, 184 },
+ { 93, 93 }, { 170, 170 }, { 155, 155 }, { 185, 185 },
+ { 78, 78 }, { 47, 47 }, { 199, 199 }, { 213, 213 },
+ { 140, 140 }, { 63, 63 }, { 109, 109 }, { 125, 125 },
+ { 94, 94 }, { 200, 200 }, { 171, 171 }, { 156, 156 },
+ { 228, 228 }, { 186, 186 }, { 214, 214 }, { 201, 201 },
+ { 79, 79 }, { 141, 141 }, { 110, 110 }, { 229, 229 },
+ { 95, 95 }, { 126, 126 }, { 215, 215 }, { 172, 172 },
+ { 111, 111 }, { 142, 142 }, { 202, 202 }, { 157, 157 },
+ { 216, 216 }, { 230, 230 }, { 217, 217 }, { 187, 187 },
+ { 127, 127 }, { 231, 231 }, { 158, 158 }, { 173, 173 },
+ { 143, 143 }, { 203, 203 }, { 188, 188 }, { 232, 232 },
+ { 218, 218 }, { 233, 233 }, { 159, 159 }, { 174, 174 },
+ { 204, 204 }, { 189, 189 }, { 234, 234 }, { 219, 219 },
+ { 175, 175 }, { 205, 205 }, { 235, 235 }, { 220, 220 },
+ { 190, 190 }, { 236, 236 }, { 206, 206 }, { 191, 191 },
+ { 221, 221 }, { 207, 207 }, { 237, 237 }, { 222, 222 },
+ { 238, 238 }, { 223, 223 }, { 239, 239 }, { 0, 0 },
+};
+
+static const int16_t vp9_default_scan_32x32_nb[1024][2] = {
+ { 0, 0 }, { 0, 0 }, { 1, 1 }, { 32, 1 },
+ { 32, 32 }, { 2, 2 }, { 33, 2 }, { 64, 33 },
+ { 3, 3 }, { 64, 64 }, { 34, 3 }, { 65, 34 },
+ { 4, 4 }, { 35, 4 }, { 96, 65 }, { 66, 35 },
+ { 96, 96 }, { 97, 66 }, { 67, 36 }, { 36, 5 },
+ { 5, 5 }, { 128, 97 }, { 98, 67 }, { 6, 6 },
+ { 128, 128 }, { 68, 37 }, { 37, 6 }, { 129, 98 },
+ { 99, 68 }, { 160, 129 }, { 130, 99 }, { 38, 7 },
+ { 69, 38 }, { 7, 7 }, { 100, 69 }, { 161, 130 },
+ { 131, 100 }, { 160, 160 }, { 70, 39 }, { 39, 8 },
+ { 8, 8 }, { 101, 70 }, { 162, 131 }, { 132, 101 },
+ { 192, 161 }, { 71, 40 }, { 192, 192 }, { 102, 71 },
+ { 40, 9 }, { 163, 132 }, { 9, 9 }, { 193, 162 },
+ { 133, 102 }, { 164, 133 }, { 72, 41 }, { 103, 72 },
+ { 134, 103 }, { 224, 193 }, { 41, 10 }, { 194, 163 },
+ { 10, 10 }, { 224, 224 }, { 165, 134 }, { 225, 194 },
+ { 195, 164 }, { 73, 42 }, { 104, 73 }, { 135, 104 },
+ { 42, 11 }, { 11, 11 }, { 166, 135 }, { 196, 165 },
+ { 226, 195 }, { 256, 225 }, { 74, 43 }, { 105, 74 },
+ { 136, 105 }, { 227, 196 }, { 43, 12 }, { 197, 166 },
+ { 167, 136 }, { 257, 226 }, { 256, 256 }, { 12, 12 },
+ { 228, 197 }, { 75, 44 }, { 106, 75 }, { 198, 167 },
+ { 137, 106 }, { 258, 227 }, { 168, 137 }, { 288, 257 },
+ { 44, 13 }, { 229, 198 }, { 259, 228 }, { 199, 168 },
+ { 107, 76 }, { 13, 13 }, { 169, 138 }, { 138, 107 },
+ { 288, 288 }, { 289, 258 }, { 76, 45 }, { 230, 199 },
+ { 260, 229 }, { 45, 14 }, { 200, 169 }, { 139, 108 },
+ { 290, 259 }, { 108, 77 }, { 231, 200 }, { 320, 289 },
+ { 261, 230 }, { 170, 139 }, { 77, 46 }, { 291, 260 },
+ { 14, 14 }, { 321, 290 }, { 201, 170 }, { 262, 231 },
+ { 320, 320 }, { 171, 140 }, { 292, 261 }, { 232, 201 },
+ { 140, 109 }, { 322, 291 }, { 109, 78 }, { 46, 15 },
+ { 202, 171 }, { 263, 232 }, { 233, 202 }, { 293, 262 },
+ { 352, 321 }, { 323, 292 }, { 15, 15 }, { 78, 47 },
+ { 203, 172 }, { 264, 233 }, { 294, 263 }, { 324, 293 },
+ { 172, 141 }, { 353, 322 }, { 141, 110 }, { 234, 203 },
+ { 352, 352 }, { 47, 16 }, { 295, 264 }, { 110, 79 },
+ { 265, 234 }, { 354, 323 }, { 325, 294 }, { 79, 48 },
+ { 16, 16 }, { 204, 173 }, { 235, 204 }, { 173, 142 },
+ { 355, 324 }, { 384, 353 }, { 326, 295 }, { 142, 111 },
+ { 296, 265 }, { 266, 235 }, { 356, 325 }, { 385, 354 },
+ { 111, 80 }, { 48, 17 }, { 327, 296 }, { 297, 266 },
+ { 205, 174 }, { 384, 384 }, { 236, 205 }, { 357, 326 },
+ { 386, 355 }, { 80, 49 }, { 174, 143 }, { 17, 17 },
+ { 328, 297 }, { 358, 327 }, { 387, 356 }, { 298, 267 },
+ { 329, 298 }, { 388, 357 }, { 112, 81 }, { 416, 385 },
+ { 237, 206 }, { 359, 328 }, { 49, 18 }, { 206, 175 },
+ { 417, 386 }, { 389, 358 }, { 330, 299 }, { 18, 18 },
+ { 416, 416 }, { 360, 329 }, { 81, 50 }, { 418, 387 },
+ { 390, 359 }, { 238, 207 }, { 50, 19 }, { 361, 330 },
+ { 419, 388 }, { 113, 82 }, { 448, 417 }, { 448, 448 },
+ { 420, 389 }, { 82, 51 }, { 362, 331 }, { 449, 418 },
+ { 421, 390 }, { 480, 480 }, { 450, 419 }, { 422, 391 },
+ { 114, 83 }, { 451, 420 }, { 480, 449 }, { 452, 421 },
+ { 481, 450 }, { 453, 422 }, { 512, 512 }, { 482, 451 },
+ { 454, 423 }, { 512, 481 }, { 483, 452 }, { 513, 482 },
+ { 484, 453 }, { 514, 483 }, { 485, 454 }, { 544, 513 },
+ { 544, 544 }, { 486, 455 }, { 545, 514 }, { 546, 515 },
+ { 576, 576 }, { 576, 545 }, { 577, 546 }, { 578, 547 },
+ { 608, 577 }, { 609, 578 }, { 610, 579 }, { 19, 19 },
+ { 143, 112 }, { 267, 236 }, { 391, 360 }, { 515, 484 },
+ { 608, 608 }, { 20, 20 }, { 51, 20 }, { 144, 113 },
+ { 175, 144 }, { 268, 237 }, { 299, 268 }, { 392, 361 },
+ { 423, 392 }, { 516, 485 }, { 547, 516 }, { 640, 609 },
+ { 640, 640 }, { 21, 21 }, { 52, 21 }, { 83, 52 },
+ { 145, 114 }, { 176, 145 }, { 207, 176 }, { 269, 238 },
+ { 300, 269 }, { 331, 300 }, { 393, 362 }, { 424, 393 },
+ { 455, 424 }, { 517, 486 }, { 548, 517 }, { 579, 548 },
+ { 641, 610 }, { 672, 641 }, { 672, 672 }, { 22, 22 },
+ { 53, 22 }, { 84, 53 }, { 115, 84 }, { 146, 115 },
+ { 177, 146 }, { 208, 177 }, { 239, 208 }, { 270, 239 },
+ { 301, 270 }, { 332, 301 }, { 363, 332 }, { 394, 363 },
+ { 425, 394 }, { 456, 425 }, { 487, 456 }, { 518, 487 },
+ { 549, 518 }, { 580, 549 }, { 611, 580 }, { 642, 611 },
+ { 673, 642 }, { 704, 673 }, { 704, 704 }, { 54, 23 },
+ { 85, 54 }, { 116, 85 }, { 178, 147 }, { 209, 178 },
+ { 240, 209 }, { 302, 271 }, { 333, 302 }, { 364, 333 },
+ { 426, 395 }, { 457, 426 }, { 488, 457 }, { 550, 519 },
+ { 581, 550 }, { 612, 581 }, { 674, 643 }, { 705, 674 },
+ { 736, 705 }, { 86, 55 }, { 117, 86 }, { 210, 179 },
+ { 241, 210 }, { 334, 303 }, { 365, 334 }, { 458, 427 },
+ { 489, 458 }, { 582, 551 }, { 613, 582 }, { 706, 675 },
+ { 737, 706 }, { 118, 87 }, { 242, 211 }, { 366, 335 },
+ { 490, 459 }, { 614, 583 }, { 738, 707 }, { 23, 23 },
+ { 147, 116 }, { 271, 240 }, { 395, 364 }, { 519, 488 },
+ { 643, 612 }, { 736, 736 }, { 24, 24 }, { 55, 24 },
+ { 148, 117 }, { 179, 148 }, { 272, 241 }, { 303, 272 },
+ { 396, 365 }, { 427, 396 }, { 520, 489 }, { 551, 520 },
+ { 644, 613 }, { 675, 644 }, { 768, 737 }, { 768, 768 },
+ { 25, 25 }, { 56, 25 }, { 87, 56 }, { 149, 118 },
+ { 180, 149 }, { 211, 180 }, { 273, 242 }, { 304, 273 },
+ { 335, 304 }, { 397, 366 }, { 428, 397 }, { 459, 428 },
+ { 521, 490 }, { 552, 521 }, { 583, 552 }, { 645, 614 },
+ { 676, 645 }, { 707, 676 }, { 769, 738 }, { 800, 769 },
+ { 800, 800 }, { 26, 26 }, { 57, 26 }, { 88, 57 },
+ { 119, 88 }, { 150, 119 }, { 181, 150 }, { 212, 181 },
+ { 243, 212 }, { 274, 243 }, { 305, 274 }, { 336, 305 },
+ { 367, 336 }, { 398, 367 }, { 429, 398 }, { 460, 429 },
+ { 491, 460 }, { 522, 491 }, { 553, 522 }, { 584, 553 },
+ { 615, 584 }, { 646, 615 }, { 677, 646 }, { 708, 677 },
+ { 739, 708 }, { 770, 739 }, { 801, 770 }, { 832, 801 },
+ { 832, 832 }, { 58, 27 }, { 89, 58 }, { 120, 89 },
+ { 182, 151 }, { 213, 182 }, { 244, 213 }, { 306, 275 },
+ { 337, 306 }, { 368, 337 }, { 430, 399 }, { 461, 430 },
+ { 492, 461 }, { 554, 523 }, { 585, 554 }, { 616, 585 },
+ { 678, 647 }, { 709, 678 }, { 740, 709 }, { 802, 771 },
+ { 833, 802 }, { 864, 833 }, { 90, 59 }, { 121, 90 },
+ { 214, 183 }, { 245, 214 }, { 338, 307 }, { 369, 338 },
+ { 462, 431 }, { 493, 462 }, { 586, 555 }, { 617, 586 },
+ { 710, 679 }, { 741, 710 }, { 834, 803 }, { 865, 834 },
+ { 122, 91 }, { 246, 215 }, { 370, 339 }, { 494, 463 },
+ { 618, 587 }, { 742, 711 }, { 866, 835 }, { 27, 27 },
+ { 151, 120 }, { 275, 244 }, { 399, 368 }, { 523, 492 },
+ { 647, 616 }, { 771, 740 }, { 864, 864 }, { 28, 28 },
+ { 59, 28 }, { 152, 121 }, { 183, 152 }, { 276, 245 },
+ { 307, 276 }, { 400, 369 }, { 431, 400 }, { 524, 493 },
+ { 555, 524 }, { 648, 617 }, { 679, 648 }, { 772, 741 },
+ { 803, 772 }, { 896, 865 }, { 896, 896 }, { 29, 29 },
+ { 60, 29 }, { 91, 60 }, { 153, 122 }, { 184, 153 },
+ { 215, 184 }, { 277, 246 }, { 308, 277 }, { 339, 308 },
+ { 401, 370 }, { 432, 401 }, { 463, 432 }, { 525, 494 },
+ { 556, 525 }, { 587, 556 }, { 649, 618 }, { 680, 649 },
+ { 711, 680 }, { 773, 742 }, { 804, 773 }, { 835, 804 },
+ { 897, 866 }, { 928, 897 }, { 928, 928 }, { 30, 30 },
+ { 61, 30 }, { 92, 61 }, { 123, 92 }, { 154, 123 },
+ { 185, 154 }, { 216, 185 }, { 247, 216 }, { 278, 247 },
+ { 309, 278 }, { 340, 309 }, { 371, 340 }, { 402, 371 },
+ { 433, 402 }, { 464, 433 }, { 495, 464 }, { 526, 495 },
+ { 557, 526 }, { 588, 557 }, { 619, 588 }, { 650, 619 },
+ { 681, 650 }, { 712, 681 }, { 743, 712 }, { 774, 743 },
+ { 805, 774 }, { 836, 805 }, { 867, 836 }, { 898, 867 },
+ { 929, 898 }, { 960, 929 }, { 960, 960 }, { 62, 31 },
+ { 93, 62 }, { 124, 93 }, { 186, 155 }, { 217, 186 },
+ { 248, 217 }, { 310, 279 }, { 341, 310 }, { 372, 341 },
+ { 434, 403 }, { 465, 434 }, { 496, 465 }, { 558, 527 },
+ { 589, 558 }, { 620, 589 }, { 682, 651 }, { 713, 682 },
+ { 744, 713 }, { 806, 775 }, { 837, 806 }, { 868, 837 },
+ { 930, 899 }, { 961, 930 }, { 992, 961 }, { 94, 63 },
+ { 125, 94 }, { 218, 187 }, { 249, 218 }, { 342, 311 },
+ { 373, 342 }, { 466, 435 }, { 497, 466 }, { 590, 559 },
+ { 621, 590 }, { 714, 683 }, { 745, 714 }, { 838, 807 },
+ { 869, 838 }, { 962, 931 }, { 993, 962 }, { 126, 95 },
+ { 250, 219 }, { 374, 343 }, { 498, 467 }, { 622, 591 },
+ { 746, 715 }, { 870, 839 }, { 994, 963 }, { 155, 124 },
+ { 279, 248 }, { 403, 372 }, { 527, 496 }, { 651, 620 },
+ { 775, 744 }, { 899, 868 }, { 156, 125 }, { 187, 156 },
+ { 280, 249 }, { 311, 280 }, { 404, 373 }, { 435, 404 },
+ { 528, 497 }, { 559, 528 }, { 652, 621 }, { 683, 652 },
+ { 776, 745 }, { 807, 776 }, { 900, 869 }, { 931, 900 },
+ { 157, 126 }, { 188, 157 }, { 219, 188 }, { 281, 250 },
+ { 312, 281 }, { 343, 312 }, { 405, 374 }, { 436, 405 },
+ { 467, 436 }, { 529, 498 }, { 560, 529 }, { 591, 560 },
+ { 653, 622 }, { 684, 653 }, { 715, 684 }, { 777, 746 },
+ { 808, 777 }, { 839, 808 }, { 901, 870 }, { 932, 901 },
+ { 963, 932 }, { 158, 127 }, { 189, 158 }, { 220, 189 },
+ { 251, 220 }, { 282, 251 }, { 313, 282 }, { 344, 313 },
+ { 375, 344 }, { 406, 375 }, { 437, 406 }, { 468, 437 },
+ { 499, 468 }, { 530, 499 }, { 561, 530 }, { 592, 561 },
+ { 623, 592 }, { 654, 623 }, { 685, 654 }, { 716, 685 },
+ { 747, 716 }, { 778, 747 }, { 809, 778 }, { 840, 809 },
+ { 871, 840 }, { 902, 871 }, { 933, 902 }, { 964, 933 },
+ { 995, 964 }, { 190, 159 }, { 221, 190 }, { 252, 221 },
+ { 314, 283 }, { 345, 314 }, { 376, 345 }, { 438, 407 },
+ { 469, 438 }, { 500, 469 }, { 562, 531 }, { 593, 562 },
+ { 624, 593 }, { 686, 655 }, { 717, 686 }, { 748, 717 },
+ { 810, 779 }, { 841, 810 }, { 872, 841 }, { 934, 903 },
+ { 965, 934 }, { 996, 965 }, { 222, 191 }, { 253, 222 },
+ { 346, 315 }, { 377, 346 }, { 470, 439 }, { 501, 470 },
+ { 594, 563 }, { 625, 594 }, { 718, 687 }, { 749, 718 },
+ { 842, 811 }, { 873, 842 }, { 966, 935 }, { 997, 966 },
+ { 254, 223 }, { 378, 347 }, { 502, 471 }, { 626, 595 },
+ { 750, 719 }, { 874, 843 }, { 998, 967 }, { 283, 252 },
+ { 407, 376 }, { 531, 500 }, { 655, 624 }, { 779, 748 },
+ { 903, 872 }, { 284, 253 }, { 315, 284 }, { 408, 377 },
+ { 439, 408 }, { 532, 501 }, { 563, 532 }, { 656, 625 },
+ { 687, 656 }, { 780, 749 }, { 811, 780 }, { 904, 873 },
+ { 935, 904 }, { 285, 254 }, { 316, 285 }, { 347, 316 },
+ { 409, 378 }, { 440, 409 }, { 471, 440 }, { 533, 502 },
+ { 564, 533 }, { 595, 564 }, { 657, 626 }, { 688, 657 },
+ { 719, 688 }, { 781, 750 }, { 812, 781 }, { 843, 812 },
+ { 905, 874 }, { 936, 905 }, { 967, 936 }, { 286, 255 },
+ { 317, 286 }, { 348, 317 }, { 379, 348 }, { 410, 379 },
+ { 441, 410 }, { 472, 441 }, { 503, 472 }, { 534, 503 },
+ { 565, 534 }, { 596, 565 }, { 627, 596 }, { 658, 627 },
+ { 689, 658 }, { 720, 689 }, { 751, 720 }, { 782, 751 },
+ { 813, 782 }, { 844, 813 }, { 875, 844 }, { 906, 875 },
+ { 937, 906 }, { 968, 937 }, { 999, 968 }, { 318, 287 },
+ { 349, 318 }, { 380, 349 }, { 442, 411 }, { 473, 442 },
+ { 504, 473 }, { 566, 535 }, { 597, 566 }, { 628, 597 },
+ { 690, 659 }, { 721, 690 }, { 752, 721 }, { 814, 783 },
+ { 845, 814 }, { 876, 845 }, { 938, 907 }, { 969, 938 },
+ { 1000, 969 }, { 350, 319 }, { 381, 350 }, { 474, 443 },
+ { 505, 474 }, { 598, 567 }, { 629, 598 }, { 722, 691 },
+ { 753, 722 }, { 846, 815 }, { 877, 846 }, { 970, 939 },
+ { 1001, 970 }, { 382, 351 }, { 506, 475 }, { 630, 599 },
+ { 754, 723 }, { 878, 847 }, { 1002, 971 }, { 411, 380 },
+ { 535, 504 }, { 659, 628 }, { 783, 752 }, { 907, 876 },
+ { 412, 381 }, { 443, 412 }, { 536, 505 }, { 567, 536 },
+ { 660, 629 }, { 691, 660 }, { 784, 753 }, { 815, 784 },
+ { 908, 877 }, { 939, 908 }, { 413, 382 }, { 444, 413 },
+ { 475, 444 }, { 537, 506 }, { 568, 537 }, { 599, 568 },
+ { 661, 630 }, { 692, 661 }, { 723, 692 }, { 785, 754 },
+ { 816, 785 }, { 847, 816 }, { 909, 878 }, { 940, 909 },
+ { 971, 940 }, { 414, 383 }, { 445, 414 }, { 476, 445 },
+ { 507, 476 }, { 538, 507 }, { 569, 538 }, { 600, 569 },
+ { 631, 600 }, { 662, 631 }, { 693, 662 }, { 724, 693 },
+ { 755, 724 }, { 786, 755 }, { 817, 786 }, { 848, 817 },
+ { 879, 848 }, { 910, 879 }, { 941, 910 }, { 972, 941 },
+ { 1003, 972 }, { 446, 415 }, { 477, 446 }, { 508, 477 },
+ { 570, 539 }, { 601, 570 }, { 632, 601 }, { 694, 663 },
+ { 725, 694 }, { 756, 725 }, { 818, 787 }, { 849, 818 },
+ { 880, 849 }, { 942, 911 }, { 973, 942 }, { 1004, 973 },
+ { 478, 447 }, { 509, 478 }, { 602, 571 }, { 633, 602 },
+ { 726, 695 }, { 757, 726 }, { 850, 819 }, { 881, 850 },
+ { 974, 943 }, { 1005, 974 }, { 510, 479 }, { 634, 603 },
+ { 758, 727 }, { 882, 851 }, { 1006, 975 }, { 539, 508 },
+ { 663, 632 }, { 787, 756 }, { 911, 880 }, { 540, 509 },
+ { 571, 540 }, { 664, 633 }, { 695, 664 }, { 788, 757 },
+ { 819, 788 }, { 912, 881 }, { 943, 912 }, { 541, 510 },
+ { 572, 541 }, { 603, 572 }, { 665, 634 }, { 696, 665 },
+ { 727, 696 }, { 789, 758 }, { 820, 789 }, { 851, 820 },
+ { 913, 882 }, { 944, 913 }, { 975, 944 }, { 542, 511 },
+ { 573, 542 }, { 604, 573 }, { 635, 604 }, { 666, 635 },
+ { 697, 666 }, { 728, 697 }, { 759, 728 }, { 790, 759 },
+ { 821, 790 }, { 852, 821 }, { 883, 852 }, { 914, 883 },
+ { 945, 914 }, { 976, 945 }, { 1007, 976 }, { 574, 543 },
+ { 605, 574 }, { 636, 605 }, { 698, 667 }, { 729, 698 },
+ { 760, 729 }, { 822, 791 }, { 853, 822 }, { 884, 853 },
+ { 946, 915 }, { 977, 946 }, { 1008, 977 }, { 606, 575 },
+ { 637, 606 }, { 730, 699 }, { 761, 730 }, { 854, 823 },
+ { 885, 854 }, { 978, 947 }, { 1009, 978 }, { 638, 607 },
+ { 762, 731 }, { 886, 855 }, { 1010, 979 }, { 667, 636 },
+ { 791, 760 }, { 915, 884 }, { 668, 637 }, { 699, 668 },
+ { 792, 761 }, { 823, 792 }, { 916, 885 }, { 947, 916 },
+ { 669, 638 }, { 700, 669 }, { 731, 700 }, { 793, 762 },
+ { 824, 793 }, { 855, 824 }, { 917, 886 }, { 948, 917 },
+ { 979, 948 }, { 670, 639 }, { 701, 670 }, { 732, 701 },
+ { 763, 732 }, { 794, 763 }, { 825, 794 }, { 856, 825 },
+ { 887, 856 }, { 918, 887 }, { 949, 918 }, { 980, 949 },
+ { 1011, 980 }, { 702, 671 }, { 733, 702 }, { 764, 733 },
+ { 826, 795 }, { 857, 826 }, { 888, 857 }, { 950, 919 },
+ { 981, 950 }, { 1012, 981 }, { 734, 703 }, { 765, 734 },
+ { 858, 827 }, { 889, 858 }, { 982, 951 }, { 1013, 982 },
+ { 766, 735 }, { 890, 859 }, { 1014, 983 }, { 795, 764 },
+ { 919, 888 }, { 796, 765 }, { 827, 796 }, { 920, 889 },
+ { 951, 920 }, { 797, 766 }, { 828, 797 }, { 859, 828 },
+ { 921, 890 }, { 952, 921 }, { 983, 952 }, { 798, 767 },
+ { 829, 798 }, { 860, 829 }, { 891, 860 }, { 922, 891 },
+ { 953, 922 }, { 984, 953 }, { 1015, 984 }, { 830, 799 },
+ { 861, 830 }, { 892, 861 }, { 954, 923 }, { 985, 954 },
+ { 1016, 985 }, { 862, 831 }, { 893, 862 }, { 986, 955 },
+ { 1017, 986 }, { 894, 863 }, { 1018, 987 }, { 923, 892 },
+ { 924, 893 }, { 955, 924 }, { 925, 894 }, { 956, 925 },
+ { 987, 956 }, { 926, 895 }, { 957, 926 }, { 988, 957 },
+ { 1019, 988 }, { 958, 927 }, { 989, 958 }, { 1020, 989 },
+ { 990, 959 }, { 1021, 990 }, { 1022, 991 }, { 0, 0 },
+};
+
+static const int16_t (* const vp9_scans_nb[5][4])[2] = {
+ {
+ vp9_default_scan_4x4_nb, vp9_col_scan_4x4_nb,
+ vp9_row_scan_4x4_nb, vp9_default_scan_4x4_nb
+ }, {
+ vp9_default_scan_8x8_nb, vp9_col_scan_8x8_nb,
+ vp9_row_scan_8x8_nb, vp9_default_scan_8x8_nb
+ }, {
+ vp9_default_scan_16x16_nb, vp9_col_scan_16x16_nb,
+ vp9_row_scan_16x16_nb, vp9_default_scan_16x16_nb
+ }, {
+ vp9_default_scan_32x32_nb, vp9_default_scan_32x32_nb,
+ vp9_default_scan_32x32_nb, vp9_default_scan_32x32_nb
+ }, { // lossless
+ vp9_default_scan_4x4_nb, vp9_default_scan_4x4_nb,
+ vp9_default_scan_4x4_nb, vp9_default_scan_4x4_nb
+ }
+};
+
+static const uint8_t vp9_model_pareto8[256][8] = {
+ { 6, 86, 128, 11, 87, 42, 91, 52 },
+ { 3, 86, 128, 6, 86, 23, 88, 29 },
+ { 6, 86, 128, 11, 87, 42, 91, 52 },
+ { 9, 86, 129, 17, 88, 61, 94, 76 },
+ { 12, 86, 129, 22, 88, 77, 97, 93 },
+ { 15, 87, 129, 28, 89, 93, 100, 110 },
+ { 17, 87, 129, 33, 90, 105, 103, 123 },
+ { 20, 88, 130, 38, 91, 118, 106, 136 },
+ { 23, 88, 130, 43, 91, 128, 108, 146 },
+ { 26, 89, 131, 48, 92, 139, 111, 156 },
+ { 28, 89, 131, 53, 93, 147, 114, 163 },
+ { 31, 90, 131, 58, 94, 156, 117, 171 },
+ { 34, 90, 131, 62, 94, 163, 119, 177 },
+ { 37, 90, 132, 66, 95, 171, 122, 184 },
+ { 39, 90, 132, 70, 96, 177, 124, 189 },
+ { 42, 91, 132, 75, 97, 183, 127, 194 },
+ { 44, 91, 132, 79, 97, 188, 129, 198 },
+ { 47, 92, 133, 83, 98, 193, 132, 202 },
+ { 49, 92, 133, 86, 99, 197, 134, 205 },
+ { 52, 93, 133, 90, 100, 201, 137, 208 },
+ { 54, 93, 133, 94, 100, 204, 139, 211 },
+ { 57, 94, 134, 98, 101, 208, 142, 214 },
+ { 59, 94, 134, 101, 102, 211, 144, 216 },
+ { 62, 94, 135, 105, 103, 214, 146, 218 },
+ { 64, 94, 135, 108, 103, 216, 148, 220 },
+ { 66, 95, 135, 111, 104, 219, 151, 222 },
+ { 68, 95, 135, 114, 105, 221, 153, 223 },
+ { 71, 96, 136, 117, 106, 224, 155, 225 },
+ { 73, 96, 136, 120, 106, 225, 157, 226 },
+ { 76, 97, 136, 123, 107, 227, 159, 228 },
+ { 78, 97, 136, 126, 108, 229, 160, 229 },
+ { 80, 98, 137, 129, 109, 231, 162, 231 },
+ { 82, 98, 137, 131, 109, 232, 164, 232 },
+ { 84, 98, 138, 134, 110, 234, 166, 233 },
+ { 86, 98, 138, 137, 111, 235, 168, 234 },
+ { 89, 99, 138, 140, 112, 236, 170, 235 },
+ { 91, 99, 138, 142, 112, 237, 171, 235 },
+ { 93, 100, 139, 145, 113, 238, 173, 236 },
+ { 95, 100, 139, 147, 114, 239, 174, 237 },
+ { 97, 101, 140, 149, 115, 240, 176, 238 },
+ { 99, 101, 140, 151, 115, 241, 177, 238 },
+ { 101, 102, 140, 154, 116, 242, 179, 239 },
+ { 103, 102, 140, 156, 117, 242, 180, 239 },
+ { 105, 103, 141, 158, 118, 243, 182, 240 },
+ { 107, 103, 141, 160, 118, 243, 183, 240 },
+ { 109, 104, 141, 162, 119, 244, 185, 241 },
+ { 111, 104, 141, 164, 119, 244, 186, 241 },
+ { 113, 104, 142, 166, 120, 245, 187, 242 },
+ { 114, 104, 142, 168, 121, 245, 188, 242 },
+ { 116, 105, 143, 170, 122, 246, 190, 243 },
+ { 118, 105, 143, 171, 122, 246, 191, 243 },
+ { 120, 106, 143, 173, 123, 247, 192, 244 },
+ { 121, 106, 143, 175, 124, 247, 193, 244 },
+ { 123, 107, 144, 177, 125, 248, 195, 244 },
+ { 125, 107, 144, 178, 125, 248, 196, 244 },
+ { 127, 108, 145, 180, 126, 249, 197, 245 },
+ { 128, 108, 145, 181, 127, 249, 198, 245 },
+ { 130, 109, 145, 183, 128, 249, 199, 245 },
+ { 132, 109, 145, 184, 128, 249, 200, 245 },
+ { 134, 110, 146, 186, 129, 250, 201, 246 },
+ { 135, 110, 146, 187, 130, 250, 202, 246 },
+ { 137, 111, 147, 189, 131, 251, 203, 246 },
+ { 138, 111, 147, 190, 131, 251, 204, 246 },
+ { 140, 112, 147, 192, 132, 251, 205, 247 },
+ { 141, 112, 147, 193, 132, 251, 206, 247 },
+ { 143, 113, 148, 194, 133, 251, 207, 247 },
+ { 144, 113, 148, 195, 134, 251, 207, 247 },
+ { 146, 114, 149, 197, 135, 252, 208, 248 },
+ { 147, 114, 149, 198, 135, 252, 209, 248 },
+ { 149, 115, 149, 199, 136, 252, 210, 248 },
+ { 150, 115, 149, 200, 137, 252, 210, 248 },
+ { 152, 115, 150, 201, 138, 252, 211, 248 },
+ { 153, 115, 150, 202, 138, 252, 212, 248 },
+ { 155, 116, 151, 204, 139, 253, 213, 249 },
+ { 156, 116, 151, 205, 139, 253, 213, 249 },
+ { 158, 117, 151, 206, 140, 253, 214, 249 },
+ { 159, 117, 151, 207, 141, 253, 215, 249 },
+ { 161, 118, 152, 208, 142, 253, 216, 249 },
+ { 162, 118, 152, 209, 142, 253, 216, 249 },
+ { 163, 119, 153, 210, 143, 253, 217, 249 },
+ { 164, 119, 153, 211, 143, 253, 217, 249 },
+ { 166, 120, 153, 212, 144, 254, 218, 250 },
+ { 167, 120, 153, 212, 145, 254, 219, 250 },
+ { 168, 121, 154, 213, 146, 254, 220, 250 },
+ { 169, 121, 154, 214, 146, 254, 220, 250 },
+ { 171, 122, 155, 215, 147, 254, 221, 250 },
+ { 172, 122, 155, 216, 147, 254, 221, 250 },
+ { 173, 123, 155, 217, 148, 254, 222, 250 },
+ { 174, 123, 155, 217, 149, 254, 222, 250 },
+ { 176, 124, 156, 218, 150, 254, 223, 250 },
+ { 177, 124, 156, 219, 150, 254, 223, 250 },
+ { 178, 125, 157, 220, 151, 254, 224, 251 },
+ { 179, 125, 157, 220, 151, 254, 224, 251 },
+ { 180, 126, 157, 221, 152, 254, 225, 251 },
+ { 181, 126, 157, 221, 152, 254, 225, 251 },
+ { 183, 127, 158, 222, 153, 254, 226, 251 },
+ { 184, 127, 158, 223, 154, 254, 226, 251 },
+ { 185, 128, 159, 224, 155, 255, 227, 251 },
+ { 186, 128, 159, 224, 155, 255, 227, 251 },
+ { 187, 129, 160, 225, 156, 255, 228, 251 },
+ { 188, 130, 160, 225, 156, 255, 228, 251 },
+ { 189, 131, 160, 226, 157, 255, 228, 251 },
+ { 190, 131, 160, 226, 158, 255, 228, 251 },
+ { 191, 132, 161, 227, 159, 255, 229, 251 },
+ { 192, 132, 161, 227, 159, 255, 229, 251 },
+ { 193, 133, 162, 228, 160, 255, 230, 252 },
+ { 194, 133, 162, 229, 160, 255, 230, 252 },
+ { 195, 134, 163, 230, 161, 255, 231, 252 },
+ { 196, 134, 163, 230, 161, 255, 231, 252 },
+ { 197, 135, 163, 231, 162, 255, 231, 252 },
+ { 198, 135, 163, 231, 162, 255, 231, 252 },
+ { 199, 136, 164, 232, 163, 255, 232, 252 },
+ { 200, 136, 164, 232, 164, 255, 232, 252 },
+ { 201, 137, 165, 233, 165, 255, 233, 252 },
+ { 201, 137, 165, 233, 165, 255, 233, 252 },
+ { 202, 138, 166, 233, 166, 255, 233, 252 },
+ { 203, 138, 166, 233, 166, 255, 233, 252 },
+ { 204, 139, 166, 234, 167, 255, 234, 252 },
+ { 205, 139, 166, 234, 167, 255, 234, 252 },
+ { 206, 140, 167, 235, 168, 255, 235, 252 },
+ { 206, 140, 167, 235, 168, 255, 235, 252 },
+ { 207, 141, 168, 236, 169, 255, 235, 252 },
+ { 208, 141, 168, 236, 170, 255, 235, 252 },
+ { 209, 142, 169, 237, 171, 255, 236, 252 },
+ { 209, 143, 169, 237, 171, 255, 236, 252 },
+ { 210, 144, 169, 237, 172, 255, 236, 252 },
+ { 211, 144, 169, 237, 172, 255, 236, 252 },
+ { 212, 145, 170, 238, 173, 255, 237, 252 },
+ { 213, 145, 170, 238, 173, 255, 237, 252 },
+ { 214, 146, 171, 239, 174, 255, 237, 253 },
+ { 214, 146, 171, 239, 174, 255, 237, 253 },
+ { 215, 147, 172, 240, 175, 255, 238, 253 },
+ { 215, 147, 172, 240, 175, 255, 238, 253 },
+ { 216, 148, 173, 240, 176, 255, 238, 253 },
+ { 217, 148, 173, 240, 176, 255, 238, 253 },
+ { 218, 149, 173, 241, 177, 255, 239, 253 },
+ { 218, 149, 173, 241, 178, 255, 239, 253 },
+ { 219, 150, 174, 241, 179, 255, 239, 253 },
+ { 219, 151, 174, 241, 179, 255, 239, 253 },
+ { 220, 152, 175, 242, 180, 255, 240, 253 },
+ { 221, 152, 175, 242, 180, 255, 240, 253 },
+ { 222, 153, 176, 242, 181, 255, 240, 253 },
+ { 222, 153, 176, 242, 181, 255, 240, 253 },
+ { 223, 154, 177, 243, 182, 255, 240, 253 },
+ { 223, 154, 177, 243, 182, 255, 240, 253 },
+ { 224, 155, 178, 244, 183, 255, 241, 253 },
+ { 224, 155, 178, 244, 183, 255, 241, 253 },
+ { 225, 156, 178, 244, 184, 255, 241, 253 },
+ { 225, 157, 178, 244, 184, 255, 241, 253 },
+ { 226, 158, 179, 244, 185, 255, 242, 253 },
+ { 227, 158, 179, 244, 185, 255, 242, 253 },
+ { 228, 159, 180, 245, 186, 255, 242, 253 },
+ { 228, 159, 180, 245, 186, 255, 242, 253 },
+ { 229, 160, 181, 245, 187, 255, 242, 253 },
+ { 229, 160, 181, 245, 187, 255, 242, 253 },
+ { 230, 161, 182, 246, 188, 255, 243, 253 },
+ { 230, 162, 182, 246, 188, 255, 243, 253 },
+ { 231, 163, 183, 246, 189, 255, 243, 253 },
+ { 231, 163, 183, 246, 189, 255, 243, 253 },
+ { 232, 164, 184, 247, 190, 255, 243, 253 },
+ { 232, 164, 184, 247, 190, 255, 243, 253 },
+ { 233, 165, 185, 247, 191, 255, 244, 253 },
+ { 233, 165, 185, 247, 191, 255, 244, 253 },
+ { 234, 166, 185, 247, 192, 255, 244, 253 },
+ { 234, 167, 185, 247, 192, 255, 244, 253 },
+ { 235, 168, 186, 248, 193, 255, 244, 253 },
+ { 235, 168, 186, 248, 193, 255, 244, 253 },
+ { 236, 169, 187, 248, 194, 255, 244, 253 },
+ { 236, 169, 187, 248, 194, 255, 244, 253 },
+ { 236, 170, 188, 248, 195, 255, 245, 253 },
+ { 236, 170, 188, 248, 195, 255, 245, 253 },
+ { 237, 171, 189, 249, 196, 255, 245, 254 },
+ { 237, 172, 189, 249, 196, 255, 245, 254 },
+ { 238, 173, 190, 249, 197, 255, 245, 254 },
+ { 238, 173, 190, 249, 197, 255, 245, 254 },
+ { 239, 174, 191, 249, 198, 255, 245, 254 },
+ { 239, 174, 191, 249, 198, 255, 245, 254 },
+ { 240, 175, 192, 249, 199, 255, 246, 254 },
+ { 240, 176, 192, 249, 199, 255, 246, 254 },
+ { 240, 177, 193, 250, 200, 255, 246, 254 },
+ { 240, 177, 193, 250, 200, 255, 246, 254 },
+ { 241, 178, 194, 250, 201, 255, 246, 254 },
+ { 241, 178, 194, 250, 201, 255, 246, 254 },
+ { 242, 179, 195, 250, 202, 255, 246, 254 },
+ { 242, 180, 195, 250, 202, 255, 246, 254 },
+ { 242, 181, 196, 250, 203, 255, 247, 254 },
+ { 242, 181, 196, 250, 203, 255, 247, 254 },
+ { 243, 182, 197, 251, 204, 255, 247, 254 },
+ { 243, 183, 197, 251, 204, 255, 247, 254 },
+ { 244, 184, 198, 251, 205, 255, 247, 254 },
+ { 244, 184, 198, 251, 205, 255, 247, 254 },
+ { 244, 185, 199, 251, 206, 255, 247, 254 },
+ { 244, 185, 199, 251, 206, 255, 247, 254 },
+ { 245, 186, 200, 251, 207, 255, 247, 254 },
+ { 245, 187, 200, 251, 207, 255, 247, 254 },
+ { 246, 188, 201, 252, 207, 255, 248, 254 },
+ { 246, 188, 201, 252, 207, 255, 248, 254 },
+ { 246, 189, 202, 252, 208, 255, 248, 254 },
+ { 246, 190, 202, 252, 208, 255, 248, 254 },
+ { 247, 191, 203, 252, 209, 255, 248, 254 },
+ { 247, 191, 203, 252, 209, 255, 248, 254 },
+ { 247, 192, 204, 252, 210, 255, 248, 254 },
+ { 247, 193, 204, 252, 210, 255, 248, 254 },
+ { 248, 194, 205, 252, 211, 255, 248, 254 },
+ { 248, 194, 205, 252, 211, 255, 248, 254 },
+ { 248, 195, 206, 252, 212, 255, 249, 254 },
+ { 248, 196, 206, 252, 212, 255, 249, 254 },
+ { 249, 197, 207, 253, 213, 255, 249, 254 },
+ { 249, 197, 207, 253, 213, 255, 249, 254 },
+ { 249, 198, 208, 253, 214, 255, 249, 254 },
+ { 249, 199, 209, 253, 214, 255, 249, 254 },
+ { 250, 200, 210, 253, 215, 255, 249, 254 },
+ { 250, 200, 210, 253, 215, 255, 249, 254 },
+ { 250, 201, 211, 253, 215, 255, 249, 254 },
+ { 250, 202, 211, 253, 215, 255, 249, 254 },
+ { 250, 203, 212, 253, 216, 255, 249, 254 },
+ { 250, 203, 212, 253, 216, 255, 249, 254 },
+ { 251, 204, 213, 253, 217, 255, 250, 254 },
+ { 251, 205, 213, 253, 217, 255, 250, 254 },
+ { 251, 206, 214, 254, 218, 255, 250, 254 },
+ { 251, 206, 215, 254, 218, 255, 250, 254 },
+ { 252, 207, 216, 254, 219, 255, 250, 254 },
+ { 252, 208, 216, 254, 219, 255, 250, 254 },
+ { 252, 209, 217, 254, 220, 255, 250, 254 },
+ { 252, 210, 217, 254, 220, 255, 250, 254 },
+ { 252, 211, 218, 254, 221, 255, 250, 254 },
+ { 252, 212, 218, 254, 221, 255, 250, 254 },
+ { 253, 213, 219, 254, 222, 255, 250, 254 },
+ { 253, 213, 220, 254, 222, 255, 250, 254 },
+ { 253, 214, 221, 254, 223, 255, 250, 254 },
+ { 253, 215, 221, 254, 223, 255, 250, 254 },
+ { 253, 216, 222, 254, 224, 255, 251, 254 },
+ { 253, 217, 223, 254, 224, 255, 251, 254 },
+ { 253, 218, 224, 254, 225, 255, 251, 254 },
+ { 253, 219, 224, 254, 225, 255, 251, 254 },
+ { 254, 220, 225, 254, 225, 255, 251, 254 },
+ { 254, 221, 226, 254, 225, 255, 251, 254 },
+ { 254, 222, 227, 255, 226, 255, 251, 254 },
+ { 254, 223, 227, 255, 226, 255, 251, 254 },
+ { 254, 224, 228, 255, 227, 255, 251, 254 },
+ { 254, 225, 229, 255, 227, 255, 251, 254 },
+ { 254, 226, 230, 255, 228, 255, 251, 254 },
+ { 254, 227, 230, 255, 229, 255, 251, 254 },
+ { 255, 228, 231, 255, 230, 255, 251, 254 },
+ { 255, 229, 232, 255, 230, 255, 251, 254 },
+ { 255, 230, 233, 255, 231, 255, 252, 254 },
+ { 255, 231, 234, 255, 231, 255, 252, 254 },
+ { 255, 232, 235, 255, 232, 255, 252, 254 },
+ { 255, 233, 236, 255, 232, 255, 252, 254 },
+ { 255, 235, 237, 255, 233, 255, 252, 254 },
+ { 255, 236, 238, 255, 234, 255, 252, 254 },
+ { 255, 238, 240, 255, 235, 255, 252, 255 },
+ { 255, 239, 241, 255, 235, 255, 252, 254 },
+ { 255, 241, 243, 255, 236, 255, 252, 254 },
+ { 255, 243, 245, 255, 237, 255, 252, 254 },
+ { 255, 246, 247, 255, 239, 255, 253, 255 },
+};
+
+typedef struct {
+ uint8_t y_mode[4][9];
+ uint8_t uv_mode[10][9];
+ uint8_t filter[4][2];
+ uint8_t mv_mode[7][3];
+ uint8_t intra[4];
+ uint8_t comp[5];
+ uint8_t single_ref[5][2];
+ uint8_t comp_ref[5];
+ uint8_t tx32p[2][3];
+ uint8_t tx16p[2][2];
+ uint8_t tx8p[2];
+ uint8_t skip[3];
+ uint8_t mv_joint[3];
+ struct {
+ uint8_t sign;
+ uint8_t classes[10];
+ uint8_t class0;
+ uint8_t bits[10];
+ uint8_t class0_fp[2][3];
+ uint8_t fp[3];
+ uint8_t class0_hp;
+ uint8_t hp;
+ } mv_comp[2];
+ uint8_t partition[4][4][3];
+} prob_context;
+
+static const prob_context vp9_default_probs = {
+ { /* y_mode */
+ { 65, 32, 18, 144, 162, 194, 41, 51, 98 } /* bsize < 8x8 */,
+ { 132, 68, 18, 165, 217, 196, 45, 40, 78 } /* bsize < 16x16 */,
+ { 173, 80, 19, 176, 240, 193, 64, 35, 46 } /* bsize < 32x32 */,
+ { 221, 135, 38, 194, 248, 121, 96, 85, 29 } /* bsize >= 32x32 */
+ }, { /* uv_mode */
+ { 48, 12, 154, 155, 139, 90, 34, 117, 119 } /* y = v */,
+ { 67, 6, 25, 204, 243, 158, 13, 21, 96 } /* y = h */,
+ { 120, 7, 76, 176, 208, 126, 28, 54, 103 } /* y = dc */,
+ { 97, 5, 44, 131, 176, 139, 48, 68, 97 } /* y = d45 */,
+ { 83, 5, 42, 156, 111, 152, 26, 49, 152 } /* y = d135 */,
+ { 80, 5, 58, 178, 74, 83, 33, 62, 145 } /* y = d117 */,
+ { 86, 5, 32, 154, 192, 168, 14, 22, 163 } /* y = d153 */,
+ { 77, 7, 64, 116, 132, 122, 37, 126, 120 } /* y = d63 */,
+ { 85, 5, 32, 156, 216, 148, 19, 29, 73 } /* y = d27 */,
+ { 101, 21, 107, 181, 192, 103, 19, 67, 125 } /* y = tm */
+ }, { /* filter */
+ { 235, 162, },
+ { 36, 255, },
+ { 34, 3, },
+ { 149, 144, },
+ }, { /* mv_mode */
+ { 2, 173, 34}, // 0 = both zero mv
+ { 7, 145, 85}, // 1 = one zero mv + one a predicted mv
+ { 7, 166, 63}, // 2 = two predicted mvs
+ { 7, 94, 66}, // 3 = one predicted/zero and one new mv
+ { 8, 64, 46}, // 4 = two new mvs
+ { 17, 81, 31}, // 5 = one intra neighbour + x
+ { 25, 29, 30}, // 6 = two intra neighbours
+ }, { /* intra */
+ 9, 102, 187, 225
+ }, { /* comp */
+ 239, 183, 119, 96, 41
+ }, { /* single_ref */
+ { 33, 16 },
+ { 77, 74 },
+ { 142, 142 },
+ { 172, 170 },
+ { 238, 247 }
+ }, { /* comp_ref */
+ 50, 126, 123, 221, 226
+ }, { /* tx32p */
+ { 3, 136, 37, },
+ { 5, 52, 13, },
+ }, { /* tx16p */
+ { 20, 152, },
+ { 15, 101, },
+ }, { /* tx8p */
+ 100, 66
+ }, { /* skip */
+ 192, 128, 64
+ }, { /* mv_joint */
+ 32, 64, 96
+ }, {
+ { /* mv vertical component */
+ 128, /* sign */
+ { 224, 144, 192, 168, 192, 176, 192, 198, 198, 245 }, /* class */
+ 216, /* class0 */
+ { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240}, /* bits */
+ { /* class0_fp */
+ { 128, 128, 64 },
+ { 96, 112, 64 }
+ },
+ { 64, 96, 64 }, /* fp */
+ 160, /* class0_hp bit */
+ 128, /* hp */
+ }, { /* mv horizontal component */
+ 128, /* sign */
+ { 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 }, /* class */
+ 208, /* class0 */
+ { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }, /* bits */
+ { /* class0_fp */
+ { 128, 128, 64 },
+ { 96, 112, 64 }
+ },
+ { 64, 96, 64 }, /* fp */
+ 160, /* class0_hp bit */
+ 128, /* hp */
+ }
+ }, { /* partition */
+ { /* 64x64 -> 32x32 */
+ { 222, 34, 30 } /* a/l both not split */,
+ { 72, 16, 44 } /* a split, l not split */,
+ { 58, 32, 12 } /* l split, a not split */,
+ { 10, 7, 6 } /* a/l both split */,
+ }, { /* 32x32 -> 16x16 */
+ { 177, 58, 59 } /* a/l both not split */,
+ { 68, 26, 63 } /* a split, l not split */,
+ { 52, 79, 25 } /* l split, a not split */,
+ { 17, 14, 12 } /* a/l both split */,
+ }, { /* 16x16 -> 8x8 */
+ { 174, 73, 87 } /* a/l both not split */,
+ { 92, 41, 83 } /* a split, l not split */,
+ { 82, 99, 50 } /* l split, a not split */,
+ { 53, 39, 39 } /* a/l both split */,
+ }, { /* 8x8 -> 4x4 */
+ { 199, 122, 141 } /* a/l both not split */,
+ { 147, 63, 159 } /* a split, l not split */,
+ { 148, 133, 118 } /* l split, a not split */,
+ { 121, 104, 114 } /* a/l both split */,
+ }
+ },
+};
+
+static const uint8_t vp9_default_coef_probs[4][2][2][6][6][3] = {
+ { /* tx = 4x4 */
+ { /* block Type 0 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 195, 29, 183 },
+ { 84, 49, 136 },
+ { 8, 42, 71 }
+ }, { /* Coeff Band 1 */
+ { 31, 107, 169 },
+ { 35, 99, 159 },
+ { 17, 82, 140 },
+ { 8, 66, 114 },
+ { 2, 44, 76 },
+ { 1, 19, 32 }
+ }, { /* Coeff Band 2 */
+ { 40, 132, 201 },
+ { 29, 114, 187 },
+ { 13, 91, 157 },
+ { 7, 75, 127 },
+ { 3, 58, 95 },
+ { 1, 28, 47 }
+ }, { /* Coeff Band 3 */
+ { 69, 142, 221 },
+ { 42, 122, 201 },
+ { 15, 91, 159 },
+ { 6, 67, 121 },
+ { 1, 42, 77 },
+ { 1, 17, 31 }
+ }, { /* Coeff Band 4 */
+ { 102, 148, 228 },
+ { 67, 117, 204 },
+ { 17, 82, 154 },
+ { 6, 59, 114 },
+ { 2, 39, 75 },
+ { 1, 15, 29 }
+ }, { /* Coeff Band 5 */
+ { 156, 57, 233 },
+ { 119, 57, 212 },
+ { 58, 48, 163 },
+ { 29, 40, 124 },
+ { 12, 30, 81 },
+ { 3, 12, 31 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 191, 107, 226 },
+ { 124, 117, 204 },
+ { 25, 99, 155 }
+ }, { /* Coeff Band 1 */
+ { 29, 148, 210 },
+ { 37, 126, 194 },
+ { 8, 93, 157 },
+ { 2, 68, 118 },
+ { 1, 39, 69 },
+ { 1, 17, 33 }
+ }, { /* Coeff Band 2 */
+ { 41, 151, 213 },
+ { 27, 123, 193 },
+ { 3, 82, 144 },
+ { 1, 58, 105 },
+ { 1, 32, 60 },
+ { 1, 13, 26 }
+ }, { /* Coeff Band 3 */
+ { 59, 159, 220 },
+ { 23, 126, 198 },
+ { 4, 88, 151 },
+ { 1, 66, 114 },
+ { 1, 38, 71 },
+ { 1, 18, 34 }
+ }, { /* Coeff Band 4 */
+ { 114, 136, 232 },
+ { 51, 114, 207 },
+ { 11, 83, 155 },
+ { 3, 56, 105 },
+ { 1, 33, 65 },
+ { 1, 17, 34 }
+ }, { /* Coeff Band 5 */
+ { 149, 65, 234 },
+ { 121, 57, 215 },
+ { 61, 49, 166 },
+ { 28, 36, 114 },
+ { 12, 25, 76 },
+ { 3, 16, 42 }
+ }
+ }
+ }, { /* block Type 1 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 214, 49, 220 },
+ { 132, 63, 188 },
+ { 42, 65, 137 }
+ }, { /* Coeff Band 1 */
+ { 85, 137, 221 },
+ { 104, 131, 216 },
+ { 49, 111, 192 },
+ { 21, 87, 155 },
+ { 2, 49, 87 },
+ { 1, 16, 28 }
+ }, { /* Coeff Band 2 */
+ { 89, 163, 230 },
+ { 90, 137, 220 },
+ { 29, 100, 183 },
+ { 10, 70, 135 },
+ { 2, 42, 81 },
+ { 1, 17, 33 }
+ }, { /* Coeff Band 3 */
+ { 108, 167, 237 },
+ { 55, 133, 222 },
+ { 15, 97, 179 },
+ { 4, 72, 135 },
+ { 1, 45, 85 },
+ { 1, 19, 38 }
+ }, { /* Coeff Band 4 */
+ { 124, 146, 240 },
+ { 66, 124, 224 },
+ { 17, 88, 175 },
+ { 4, 58, 122 },
+ { 1, 36, 75 },
+ { 1, 18, 37 }
+ }, { /* Coeff Band 5 */
+ { 141, 79, 241 },
+ { 126, 70, 227 },
+ { 66, 58, 182 },
+ { 30, 44, 136 },
+ { 12, 34, 96 },
+ { 2, 20, 47 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 229, 99, 249 },
+ { 143, 111, 235 },
+ { 46, 109, 192 }
+ }, { /* Coeff Band 1 */
+ { 82, 158, 236 },
+ { 94, 146, 224 },
+ { 25, 117, 191 },
+ { 9, 87, 149 },
+ { 3, 56, 99 },
+ { 1, 33, 57 }
+ }, { /* Coeff Band 2 */
+ { 83, 167, 237 },
+ { 68, 145, 222 },
+ { 10, 103, 177 },
+ { 2, 72, 131 },
+ { 1, 41, 79 },
+ { 1, 20, 39 }
+ }, { /* Coeff Band 3 */
+ { 99, 167, 239 },
+ { 47, 141, 224 },
+ { 10, 104, 178 },
+ { 2, 73, 133 },
+ { 1, 44, 85 },
+ { 1, 22, 47 }
+ }, { /* Coeff Band 4 */
+ { 127, 145, 243 },
+ { 71, 129, 228 },
+ { 17, 93, 177 },
+ { 3, 61, 124 },
+ { 1, 41, 84 },
+ { 1, 21, 52 }
+ }, { /* Coeff Band 5 */
+ { 157, 78, 244 },
+ { 140, 72, 231 },
+ { 69, 58, 184 },
+ { 31, 44, 137 },
+ { 14, 38, 105 },
+ { 8, 23, 61 }
+ }
+ }
+ }
+ }, { /* tx = 8x8 */
+ { /* block Type 0 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 125, 34, 187 },
+ { 52, 41, 133 },
+ { 6, 31, 56 }
+ }, { /* Coeff Band 1 */
+ { 37, 109, 153 },
+ { 51, 102, 147 },
+ { 23, 87, 128 },
+ { 8, 67, 101 },
+ { 1, 41, 63 },
+ { 1, 19, 29 }
+ }, { /* Coeff Band 2 */
+ { 31, 154, 185 },
+ { 17, 127, 175 },
+ { 6, 96, 145 },
+ { 2, 73, 114 },
+ { 1, 51, 82 },
+ { 1, 28, 45 }
+ }, { /* Coeff Band 3 */
+ { 23, 163, 200 },
+ { 10, 131, 185 },
+ { 2, 93, 148 },
+ { 1, 67, 111 },
+ { 1, 41, 69 },
+ { 1, 14, 24 }
+ }, { /* Coeff Band 4 */
+ { 29, 176, 217 },
+ { 12, 145, 201 },
+ { 3, 101, 156 },
+ { 1, 69, 111 },
+ { 1, 39, 63 },
+ { 1, 14, 23 }
+ }, { /* Coeff Band 5 */
+ { 57, 192, 233 },
+ { 25, 154, 215 },
+ { 6, 109, 167 },
+ { 3, 78, 118 },
+ { 1, 48, 69 },
+ { 1, 21, 29 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 202, 105, 245 },
+ { 108, 106, 216 },
+ { 18, 90, 144 }
+ }, { /* Coeff Band 1 */
+ { 33, 172, 219 },
+ { 64, 149, 206 },
+ { 14, 117, 177 },
+ { 5, 90, 141 },
+ { 2, 61, 95 },
+ { 1, 37, 57 }
+ }, { /* Coeff Band 2 */
+ { 33, 179, 220 },
+ { 11, 140, 198 },
+ { 1, 89, 148 },
+ { 1, 60, 104 },
+ { 1, 33, 57 },
+ { 1, 12, 21 }
+ }, { /* Coeff Band 3 */
+ { 30, 181, 221 },
+ { 8, 141, 198 },
+ { 1, 87, 145 },
+ { 1, 58, 100 },
+ { 1, 31, 55 },
+ { 1, 12, 20 }
+ }, { /* Coeff Band 4 */
+ { 32, 186, 224 },
+ { 7, 142, 198 },
+ { 1, 86, 143 },
+ { 1, 58, 100 },
+ { 1, 31, 55 },
+ { 1, 12, 22 }
+ }, { /* Coeff Band 5 */
+ { 57, 192, 227 },
+ { 20, 143, 204 },
+ { 3, 96, 154 },
+ { 1, 68, 112 },
+ { 1, 42, 69 },
+ { 1, 19, 32 }
+ }
+ }
+ }, { /* block Type 1 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 212, 35, 215 },
+ { 113, 47, 169 },
+ { 29, 48, 105 }
+ }, { /* Coeff Band 1 */
+ { 74, 129, 203 },
+ { 106, 120, 203 },
+ { 49, 107, 178 },
+ { 19, 84, 144 },
+ { 4, 50, 84 },
+ { 1, 15, 25 }
+ }, { /* Coeff Band 2 */
+ { 71, 172, 217 },
+ { 44, 141, 209 },
+ { 15, 102, 173 },
+ { 6, 76, 133 },
+ { 2, 51, 89 },
+ { 1, 24, 42 }
+ }, { /* Coeff Band 3 */
+ { 64, 185, 231 },
+ { 31, 148, 216 },
+ { 8, 103, 175 },
+ { 3, 74, 131 },
+ { 1, 46, 81 },
+ { 1, 18, 30 }
+ }, { /* Coeff Band 4 */
+ { 65, 196, 235 },
+ { 25, 157, 221 },
+ { 5, 105, 174 },
+ { 1, 67, 120 },
+ { 1, 38, 69 },
+ { 1, 15, 30 }
+ }, { /* Coeff Band 5 */
+ { 65, 204, 238 },
+ { 30, 156, 224 },
+ { 7, 107, 177 },
+ { 2, 70, 124 },
+ { 1, 42, 73 },
+ { 1, 18, 34 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 225, 86, 251 },
+ { 144, 104, 235 },
+ { 42, 99, 181 }
+ }, { /* Coeff Band 1 */
+ { 85, 175, 239 },
+ { 112, 165, 229 },
+ { 29, 136, 200 },
+ { 12, 103, 162 },
+ { 6, 77, 123 },
+ { 2, 53, 84 }
+ }, { /* Coeff Band 2 */
+ { 75, 183, 239 },
+ { 30, 155, 221 },
+ { 3, 106, 171 },
+ { 1, 74, 128 },
+ { 1, 44, 76 },
+ { 1, 17, 28 }
+ }, { /* Coeff Band 3 */
+ { 73, 185, 240 },
+ { 27, 159, 222 },
+ { 2, 107, 172 },
+ { 1, 75, 127 },
+ { 1, 42, 73 },
+ { 1, 17, 29 }
+ }, { /* Coeff Band 4 */
+ { 62, 190, 238 },
+ { 21, 159, 222 },
+ { 2, 107, 172 },
+ { 1, 72, 122 },
+ { 1, 40, 71 },
+ { 1, 18, 32 }
+ }, { /* Coeff Band 5 */
+ { 61, 199, 240 },
+ { 27, 161, 226 },
+ { 4, 113, 180 },
+ { 1, 76, 129 },
+ { 1, 46, 80 },
+ { 1, 23, 41 }
+ }
+ }
+ }
+ }, { /* tx = 16x16 */
+ { /* block Type 0 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 7, 27, 153 },
+ { 5, 30, 95 },
+ { 1, 16, 30 }
+ }, { /* Coeff Band 1 */
+ { 50, 75, 127 },
+ { 57, 75, 124 },
+ { 27, 67, 108 },
+ { 10, 54, 86 },
+ { 1, 33, 52 },
+ { 1, 12, 18 }
+ }, { /* Coeff Band 2 */
+ { 43, 125, 151 },
+ { 26, 108, 148 },
+ { 7, 83, 122 },
+ { 2, 59, 89 },
+ { 1, 38, 60 },
+ { 1, 17, 27 }
+ }, { /* Coeff Band 3 */
+ { 23, 144, 163 },
+ { 13, 112, 154 },
+ { 2, 75, 117 },
+ { 1, 50, 81 },
+ { 1, 31, 51 },
+ { 1, 14, 23 }
+ }, { /* Coeff Band 4 */
+ { 18, 162, 185 },
+ { 6, 123, 171 },
+ { 1, 78, 125 },
+ { 1, 51, 86 },
+ { 1, 31, 54 },
+ { 1, 14, 23 }
+ }, { /* Coeff Band 5 */
+ { 15, 199, 227 },
+ { 3, 150, 204 },
+ { 1, 91, 146 },
+ { 1, 55, 95 },
+ { 1, 30, 53 },
+ { 1, 11, 20 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 19, 55, 240 },
+ { 19, 59, 196 },
+ { 3, 52, 105 }
+ }, { /* Coeff Band 1 */
+ { 41, 166, 207 },
+ { 104, 153, 199 },
+ { 31, 123, 181 },
+ { 14, 101, 152 },
+ { 5, 72, 106 },
+ { 1, 36, 52 }
+ }, { /* Coeff Band 2 */
+ { 35, 176, 211 },
+ { 12, 131, 190 },
+ { 2, 88, 144 },
+ { 1, 60, 101 },
+ { 1, 36, 60 },
+ { 1, 16, 28 }
+ }, { /* Coeff Band 3 */
+ { 28, 183, 213 },
+ { 8, 134, 191 },
+ { 1, 86, 142 },
+ { 1, 56, 96 },
+ { 1, 30, 53 },
+ { 1, 12, 20 }
+ }, { /* Coeff Band 4 */
+ { 20, 190, 215 },
+ { 4, 135, 192 },
+ { 1, 84, 139 },
+ { 1, 53, 91 },
+ { 1, 28, 49 },
+ { 1, 11, 20 }
+ }, { /* Coeff Band 5 */
+ { 13, 196, 216 },
+ { 2, 137, 192 },
+ { 1, 86, 143 },
+ { 1, 57, 99 },
+ { 1, 32, 56 },
+ { 1, 13, 24 }
+ }
+ }
+ }, { /* block Type 1 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 211, 29, 217 },
+ { 96, 47, 156 },
+ { 22, 43, 87 }
+ }, { /* Coeff Band 1 */
+ { 78, 120, 193 },
+ { 111, 116, 186 },
+ { 46, 102, 164 },
+ { 15, 80, 128 },
+ { 2, 49, 76 },
+ { 1, 18, 28 }
+ }, { /* Coeff Band 2 */
+ { 71, 161, 203 },
+ { 42, 132, 192 },
+ { 10, 98, 150 },
+ { 3, 69, 109 },
+ { 1, 44, 70 },
+ { 1, 18, 29 }
+ }, { /* Coeff Band 3 */
+ { 57, 186, 211 },
+ { 30, 140, 196 },
+ { 4, 93, 146 },
+ { 1, 62, 102 },
+ { 1, 38, 65 },
+ { 1, 16, 27 }
+ }, { /* Coeff Band 4 */
+ { 47, 199, 217 },
+ { 14, 145, 196 },
+ { 1, 88, 142 },
+ { 1, 57, 98 },
+ { 1, 36, 62 },
+ { 1, 15, 26 }
+ }, { /* Coeff Band 5 */
+ { 26, 219, 229 },
+ { 5, 155, 207 },
+ { 1, 94, 151 },
+ { 1, 60, 104 },
+ { 1, 36, 62 },
+ { 1, 16, 28 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 233, 29, 248 },
+ { 146, 47, 220 },
+ { 43, 52, 140 }
+ }, { /* Coeff Band 1 */
+ { 100, 163, 232 },
+ { 179, 161, 222 },
+ { 63, 142, 204 },
+ { 37, 113, 174 },
+ { 26, 89, 137 },
+ { 18, 68, 97 }
+ }, { /* Coeff Band 2 */
+ { 85, 181, 230 },
+ { 32, 146, 209 },
+ { 7, 100, 164 },
+ { 3, 71, 121 },
+ { 1, 45, 77 },
+ { 1, 18, 30 }
+ }, { /* Coeff Band 3 */
+ { 65, 187, 230 },
+ { 20, 148, 207 },
+ { 2, 97, 159 },
+ { 1, 68, 116 },
+ { 1, 40, 70 },
+ { 1, 14, 29 }
+ }, { /* Coeff Band 4 */
+ { 40, 194, 227 },
+ { 8, 147, 204 },
+ { 1, 94, 155 },
+ { 1, 65, 112 },
+ { 1, 39, 66 },
+ { 1, 14, 26 }
+ }, { /* Coeff Band 5 */
+ { 16, 208, 228 },
+ { 3, 151, 207 },
+ { 1, 98, 160 },
+ { 1, 67, 117 },
+ { 1, 41, 74 },
+ { 1, 17, 31 }
+ }
+ }
+ }
+ }, { /* tx = 32x32 */
+ { /* block Type 0 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 17, 38, 140 },
+ { 7, 34, 80 },
+ { 1, 17, 29 }
+ }, { /* Coeff Band 1 */
+ { 37, 75, 128 },
+ { 41, 76, 128 },
+ { 26, 66, 116 },
+ { 12, 52, 94 },
+ { 2, 32, 55 },
+ { 1, 10, 16 }
+ }, { /* Coeff Band 2 */
+ { 50, 127, 154 },
+ { 37, 109, 152 },
+ { 16, 82, 121 },
+ { 5, 59, 85 },
+ { 1, 35, 54 },
+ { 1, 13, 20 }
+ }, { /* Coeff Band 3 */
+ { 40, 142, 167 },
+ { 17, 110, 157 },
+ { 2, 71, 112 },
+ { 1, 44, 72 },
+ { 1, 27, 45 },
+ { 1, 11, 17 }
+ }, { /* Coeff Band 4 */
+ { 30, 175, 188 },
+ { 9, 124, 169 },
+ { 1, 74, 116 },
+ { 1, 48, 78 },
+ { 1, 30, 49 },
+ { 1, 11, 18 }
+ }, { /* Coeff Band 5 */
+ { 10, 222, 223 },
+ { 2, 150, 194 },
+ { 1, 83, 128 },
+ { 1, 48, 79 },
+ { 1, 27, 45 },
+ { 1, 11, 17 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 36, 41, 235 },
+ { 29, 36, 193 },
+ { 10, 27, 111 }
+ }, { /* Coeff Band 1 */
+ { 85, 165, 222 },
+ { 177, 162, 215 },
+ { 110, 135, 195 },
+ { 57, 113, 168 },
+ { 23, 83, 120 },
+ { 10, 49, 61 }
+ }, { /* Coeff Band 2 */
+ { 85, 190, 223 },
+ { 36, 139, 200 },
+ { 5, 90, 146 },
+ { 1, 60, 103 },
+ { 1, 38, 65 },
+ { 1, 18, 30 }
+ }, { /* Coeff Band 3 */
+ { 72, 202, 223 },
+ { 23, 141, 199 },
+ { 2, 86, 140 },
+ { 1, 56, 97 },
+ { 1, 36, 61 },
+ { 1, 16, 27 }
+ }, { /* Coeff Band 4 */
+ { 55, 218, 225 },
+ { 13, 145, 200 },
+ { 1, 86, 141 },
+ { 1, 57, 99 },
+ { 1, 35, 61 },
+ { 1, 13, 22 }
+ }, { /* Coeff Band 5 */
+ { 15, 235, 212 },
+ { 1, 132, 184 },
+ { 1, 84, 139 },
+ { 1, 57, 97 },
+ { 1, 34, 56 },
+ { 1, 14, 23 }
+ }
+ }
+ }, { /* block Type 1 */
+ { /* Intra */
+ { /* Coeff Band 0 */
+ { 181, 21, 201 },
+ { 61, 37, 123 },
+ { 10, 38, 71 }
+ }, { /* Coeff Band 1 */
+ { 47, 106, 172 },
+ { 95, 104, 173 },
+ { 42, 93, 159 },
+ { 18, 77, 131 },
+ { 4, 50, 81 },
+ { 1, 17, 23 }
+ }, { /* Coeff Band 2 */
+ { 62, 147, 199 },
+ { 44, 130, 189 },
+ { 28, 102, 154 },
+ { 18, 75, 115 },
+ { 2, 44, 65 },
+ { 1, 12, 19 }
+ }, { /* Coeff Band 3 */
+ { 55, 153, 210 },
+ { 24, 130, 194 },
+ { 3, 93, 146 },
+ { 1, 61, 97 },
+ { 1, 31, 50 },
+ { 1, 10, 16 }
+ }, { /* Coeff Band 4 */
+ { 49, 186, 223 },
+ { 17, 148, 204 },
+ { 1, 96, 142 },
+ { 1, 53, 83 },
+ { 1, 26, 44 },
+ { 1, 11, 17 }
+ }, { /* Coeff Band 5 */
+ { 13, 217, 212 },
+ { 2, 136, 180 },
+ { 1, 78, 124 },
+ { 1, 50, 83 },
+ { 1, 29, 49 },
+ { 1, 14, 23 }
+ }
+ }, { /* Inter */
+ { /* Coeff Band 0 */
+ { 197, 13, 247 },
+ { 82, 17, 222 },
+ { 25, 17, 162 }
+ }, { /* Coeff Band 1 */
+ { 126, 186, 247 },
+ { 234, 191, 243 },
+ { 176, 177, 234 },
+ { 104, 158, 220 },
+ { 66, 128, 186 },
+ { 55, 90, 137 }
+ }, { /* Coeff Band 2 */
+ { 111, 197, 242 },
+ { 46, 158, 219 },
+ { 9, 104, 171 },
+ { 2, 65, 125 },
+ { 1, 44, 80 },
+ { 1, 17, 91 }
+ }, { /* Coeff Band 3 */
+ { 104, 208, 245 },
+ { 39, 168, 224 },
+ { 3, 109, 162 },
+ { 1, 79, 124 },
+ { 1, 50, 102 },
+ { 1, 43, 102 }
+ }, { /* Coeff Band 4 */
+ { 84, 220, 246 },
+ { 31, 177, 231 },
+ { 2, 115, 180 },
+ { 1, 79, 134 },
+ { 1, 55, 77 },
+ { 1, 60, 79 }
+ }, { /* Coeff Band 5 */
+ { 43, 243, 240 },
+ { 8, 180, 217 },
+ { 1, 115, 166 },
+ { 1, 84, 121 },
+ { 1, 51, 67 },
+ { 1, 16, 6 }
+ }
+ }
+ }
+ }
+};
+
+enum MVJoint {
+ MV_JOINT_ZERO,
+ MV_JOINT_H,
+ MV_JOINT_V,
+ MV_JOINT_HV,
+};
+
+static const int8_t vp9_mv_joint_tree[3][2] = {
+ { -MV_JOINT_ZERO, 1 }, // '0'
+ { -MV_JOINT_H, 2 }, // '10'
+ { -MV_JOINT_V, -MV_JOINT_HV }, // '11x'
+};
+
+static const int8_t vp9_mv_class_tree[10][2] = {
+ { -0, 1 }, // '0'
+ { -1, 2 }, // '10'
+ { 3, 4 },
+ { -2, -3 }, // '110x'
+ { 5, 6 },
+ { -4, -5 }, // '1110x'
+ { -6, 7 }, // '11110'
+ { 8, 9 },
+ { -7, -8 }, // '111110x'
+ { -9, -10 }, // '111111x'
+};
+
+static const int8_t vp9_mv_fp_tree[3][2] = {
+ { -0, 1 }, // '0'
+ { -1, 2 }, // '10'
+ { -2, -3 }, // '11x'
+};
#endif /* AVCODEC_VP9DATA_H */
diff --git a/libavcodec/vp9dsp.c b/libavcodec/vp9dsp.c
index c83defeda3..5ff18b471c 100644
--- a/libavcodec/vp9dsp.c
+++ b/libavcodec/vp9dsp.c
@@ -4,2171 +4,37 @@
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
* Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/intreadwrite.h"
+#include "vp9dsp.h"
-#include "rnd_avg.h"
-#include "vp9.h"
-
-// 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,
- const uint8_t *left, const uint8_t *top)
-{
- unsigned p4 = AV_RN32A(top);
-
- AV_WN32A(dst + stride * 0, p4);
- AV_WN32A(dst + stride * 1, p4);
- AV_WN32A(dst + stride * 2, p4);
- AV_WN32A(dst + stride * 3, p4);
-}
-
-static void vert_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t p8 = AV_RN64A(top);
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, p8);
- dst += stride;
- }
-}
-
-static void vert_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t p8a = AV_RN64A(top + 0), p8b = AV_RN64A(top + 8);
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, p8a);
- AV_WN64A(dst + 8, p8b);
- dst += stride;
- }
-}
-
-static void vert_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t p8a = AV_RN64A(top + 0), p8b = AV_RN64A(top + 8),
- p8c = AV_RN64A(top + 16), p8d = AV_RN64A(top + 24);
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, p8a);
- AV_WN64A(dst + 8, p8b);
- AV_WN64A(dst + 16, p8c);
- AV_WN64A(dst + 24, p8d);
- dst += stride;
- }
-}
-
-static void hor_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- AV_WN32A(dst + stride * 0, left[0] * 0x01010101U);
- AV_WN32A(dst + stride * 1, left[1] * 0x01010101U);
- AV_WN32A(dst + stride * 2, left[2] * 0x01010101U);
- AV_WN32A(dst + stride * 3, left[3] * 0x01010101U);
-}
-
-static void hor_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, left[y] * 0x0101010101010101ULL);
- dst += stride;
- }
-}
-
-static void hor_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 16; y++) {
- uint64_t p8 = left[y] * 0x0101010101010101ULL;
-
- AV_WN64A(dst + 0, p8);
- AV_WN64A(dst + 8, p8);
- dst += stride;
- }
-}
-
-static void hor_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 32; y++) {
- uint64_t p8 = left[y] * 0x0101010101010101ULL;
-
- AV_WN64A(dst + 0, p8);
- AV_WN64A(dst + 8, p8);
- AV_WN64A(dst + 16, p8);
- AV_WN64A(dst + 24, p8);
- dst += stride;
- }
-}
-
-static void tm_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y, tl = top[-1];
-
- for (y = 0; y < 4; y++) {
- int l_m_tl = left[y] - tl;
-
- dst[0] = av_clip_uint8(top[0] + l_m_tl);
- dst[1] = av_clip_uint8(top[1] + l_m_tl);
- dst[2] = av_clip_uint8(top[2] + l_m_tl);
- dst[3] = av_clip_uint8(top[3] + l_m_tl);
- dst += stride;
- }
-}
-
-static void tm_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y, tl = top[-1];
-
- for (y = 0; y < 8; y++) {
- int l_m_tl = left[y] - tl;
-
- dst[0] = av_clip_uint8(top[0] + l_m_tl);
- dst[1] = av_clip_uint8(top[1] + l_m_tl);
- dst[2] = av_clip_uint8(top[2] + l_m_tl);
- dst[3] = av_clip_uint8(top[3] + l_m_tl);
- dst[4] = av_clip_uint8(top[4] + l_m_tl);
- dst[5] = av_clip_uint8(top[5] + l_m_tl);
- dst[6] = av_clip_uint8(top[6] + l_m_tl);
- dst[7] = av_clip_uint8(top[7] + l_m_tl);
- dst += stride;
- }
-}
-
-static void tm_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y, tl = top[-1];
-
- for (y = 0; y < 16; y++) {
- int l_m_tl = left[y] - tl;
-
- dst[0] = av_clip_uint8(top[0] + l_m_tl);
- dst[1] = av_clip_uint8(top[1] + l_m_tl);
- dst[2] = av_clip_uint8(top[2] + l_m_tl);
- dst[3] = av_clip_uint8(top[3] + l_m_tl);
- dst[4] = av_clip_uint8(top[4] + l_m_tl);
- dst[5] = av_clip_uint8(top[5] + l_m_tl);
- dst[6] = av_clip_uint8(top[6] + l_m_tl);
- dst[7] = av_clip_uint8(top[7] + l_m_tl);
- dst[8] = av_clip_uint8(top[8] + l_m_tl);
- dst[9] = av_clip_uint8(top[9] + l_m_tl);
- dst[10] = av_clip_uint8(top[10] + l_m_tl);
- dst[11] = av_clip_uint8(top[11] + l_m_tl);
- dst[12] = av_clip_uint8(top[12] + l_m_tl);
- dst[13] = av_clip_uint8(top[13] + l_m_tl);
- dst[14] = av_clip_uint8(top[14] + l_m_tl);
- dst[15] = av_clip_uint8(top[15] + l_m_tl);
- dst += stride;
- }
-}
-
-static void tm_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y, tl = top[-1];
-
- for (y = 0; y < 32; y++) {
- int l_m_tl = left[y] - tl;
-
- dst[0] = av_clip_uint8(top[0] + l_m_tl);
- dst[1] = av_clip_uint8(top[1] + l_m_tl);
- dst[2] = av_clip_uint8(top[2] + l_m_tl);
- dst[3] = av_clip_uint8(top[3] + l_m_tl);
- dst[4] = av_clip_uint8(top[4] + l_m_tl);
- dst[5] = av_clip_uint8(top[5] + l_m_tl);
- dst[6] = av_clip_uint8(top[6] + l_m_tl);
- dst[7] = av_clip_uint8(top[7] + l_m_tl);
- dst[8] = av_clip_uint8(top[8] + l_m_tl);
- dst[9] = av_clip_uint8(top[9] + l_m_tl);
- dst[10] = av_clip_uint8(top[10] + l_m_tl);
- dst[11] = av_clip_uint8(top[11] + l_m_tl);
- dst[12] = av_clip_uint8(top[12] + l_m_tl);
- dst[13] = av_clip_uint8(top[13] + l_m_tl);
- dst[14] = av_clip_uint8(top[14] + l_m_tl);
- dst[15] = av_clip_uint8(top[15] + l_m_tl);
- dst[16] = av_clip_uint8(top[16] + l_m_tl);
- dst[17] = av_clip_uint8(top[17] + l_m_tl);
- dst[18] = av_clip_uint8(top[18] + l_m_tl);
- dst[19] = av_clip_uint8(top[19] + l_m_tl);
- dst[20] = av_clip_uint8(top[20] + l_m_tl);
- dst[21] = av_clip_uint8(top[21] + l_m_tl);
- dst[22] = av_clip_uint8(top[22] + l_m_tl);
- dst[23] = av_clip_uint8(top[23] + l_m_tl);
- dst[24] = av_clip_uint8(top[24] + l_m_tl);
- dst[25] = av_clip_uint8(top[25] + l_m_tl);
- dst[26] = av_clip_uint8(top[26] + l_m_tl);
- dst[27] = av_clip_uint8(top[27] + l_m_tl);
- dst[28] = av_clip_uint8(top[28] + l_m_tl);
- dst[29] = av_clip_uint8(top[29] + l_m_tl);
- dst[30] = av_clip_uint8(top[30] + l_m_tl);
- dst[31] = av_clip_uint8(top[31] + l_m_tl);
- dst += stride;
- }
-}
-
-static void dc_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- unsigned dc = 0x01010101U *
- ((left[0] + left[1] + left[2] + left[3] +
- top[0] + top[1] + top[2] + top[3] + 4) >> 3);
-
- AV_WN32A(dst + stride * 0, dc);
- AV_WN32A(dst + stride * 1, dc);
- AV_WN32A(dst + stride * 2, dc);
- AV_WN32A(dst + stride * 3, dc);
-}
-
-static void dc_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((left[0] + left[1] + left[2] + left[3] +
- left[4] + left[5] + left[6] + left[7] +
- top[0] + top[1] + top[2] + top[3] +
- top[4] + top[5] + top[6] + top[7] + 8) >> 4);
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, dc);
- dst += stride;
- }
-}
-
-static void dc_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((left[0] + left[1] + left[2] + left[3] +
- left[4] + left[5] + left[6] + left[7] +
- left[8] + left[9] + left[10] + left[11] +
- left[12] + left[13] + left[14] + left[15] +
- top[0] + top[1] + top[2] + top[3] +
- top[4] + top[5] + top[6] + top[7] +
- top[8] + top[9] + top[10] + top[11] +
- top[12] + top[13] + top[14] + top[15] + 16) >> 5);
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, dc);
- AV_WN64A(dst + 8, dc);
- dst += stride;
- }
-}
-
-static void dc_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((left[0] + left[1] + left[2] + left[3] +
- left[4] + left[5] + left[6] + left[7] +
- left[8] + left[9] + left[10] + left[11] +
- left[12] + left[13] + left[14] + left[15] +
- left[16] + left[17] + left[18] + left[19] +
- left[20] + left[21] + left[22] + left[23] +
- left[24] + left[25] + left[26] + left[27] +
- left[28] + left[29] + left[30] + left[31] +
- top[0] + top[1] + top[2] + top[3] +
- top[4] + top[5] + top[6] + top[7] +
- top[8] + top[9] + top[10] + top[11] +
- top[12] + top[13] + top[14] + top[15] +
- top[16] + top[17] + top[18] + top[19] +
- top[20] + top[21] + top[22] + top[23] +
- top[24] + top[25] + top[26] + top[27] +
- top[28] + top[29] + top[30] + top[31] + 32) >> 6);
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, dc);
- AV_WN64A(dst + 8, dc);
- AV_WN64A(dst + 16, dc);
- AV_WN64A(dst + 24, dc);
- dst += stride;
- }
-}
-
-static void dc_left_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- unsigned dc = 0x01010101U *
- ((left[0] + left[1] + left[2] + left[3] + 2) >> 2);
-
- AV_WN32A(dst + stride * 0, dc);
- AV_WN32A(dst + stride * 1, dc);
- AV_WN32A(dst + stride * 2, dc);
- AV_WN32A(dst + stride * 3, dc);
-}
-
-static void dc_left_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((left[0] + left[1] + left[2] + left[3] +
- left[4] + left[5] + left[6] + left[7] + 4) >> 3);
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, dc);
- dst += stride;
- }
-}
-
-static void dc_left_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((left[0] + left[1] + left[2] + left[3] +
- left[4] + left[5] + left[6] + left[7] +
- left[8] + left[9] + left[10] + left[11] +
- left[12] + left[13] + left[14] + left[15] + 8) >> 4);
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, dc);
- AV_WN64A(dst + 8, dc);
- dst += stride;
- }
-}
-
-static void dc_left_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((left[0] + left[1] + left[2] + left[3] +
- left[4] + left[5] + left[6] + left[7] +
- left[8] + left[9] + left[10] + left[11] +
- left[12] + left[13] + left[14] + left[15] +
- left[16] + left[17] + left[18] + left[19] +
- left[20] + left[21] + left[22] + left[23] +
- left[24] + left[25] + left[26] + left[27] +
- left[28] + left[29] + left[30] + left[31] + 16) >> 5);
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, dc);
- AV_WN64A(dst + 8, dc);
- AV_WN64A(dst + 16, dc);
- AV_WN64A(dst + 24, dc);
- dst += stride;
- }
-}
-
-static void dc_top_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- unsigned dc = 0x01010101U * ((top[0] + top[1] + top[2] + top[3] + 2) >> 2);
-
- AV_WN32A(dst + stride * 0, dc);
- AV_WN32A(dst + stride * 1, dc);
- AV_WN32A(dst + stride * 2, dc);
- AV_WN32A(dst + stride * 3, dc);
-}
-
-static void dc_top_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((top[0] + top[1] + top[2] + top[3] +
- top[4] + top[5] + top[6] + top[7] + 4) >> 3);
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, dc);
- dst += stride;
- }
-}
-
-static void dc_top_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((top[0] + top[1] + top[2] + top[3] +
- top[4] + top[5] + top[6] + top[7] +
- top[8] + top[9] + top[10] + top[11] +
- top[12] + top[13] + top[14] + top[15] + 8) >> 4);
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, dc);
- AV_WN64A(dst + 8, dc);
- dst += stride;
- }
-}
-
-static void dc_top_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- uint64_t dc = 0x0101010101010101ULL *
- ((top[0] + top[1] + top[2] + top[3] +
- top[4] + top[5] + top[6] + top[7] +
- top[8] + top[9] + top[10] + top[11] +
- top[12] + top[13] + top[14] + top[15] +
- top[16] + top[17] + top[18] + top[19] +
- top[20] + top[21] + top[22] + top[23] +
- top[24] + top[25] + top[26] + top[27] +
- top[28] + top[29] + top[30] + top[31] + 16) >> 5);
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, dc);
- AV_WN64A(dst + 8, dc);
- AV_WN64A(dst + 16, dc);
- AV_WN64A(dst + 24, dc);
- dst += stride;
- }
-}
-
-static void dc_128_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- AV_WN32A(dst + stride * 0, 0x80808080U);
- AV_WN32A(dst + stride * 1, 0x80808080U);
- AV_WN32A(dst + stride * 2, 0x80808080U);
- AV_WN32A(dst + stride * 3, 0x80808080U);
-}
-
-static void dc_128_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, 0x8080808080808080ULL);
- dst += stride;
- }
-}
-
-static void dc_128_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, 0x8080808080808080ULL);
- AV_WN64A(dst + 8, 0x8080808080808080ULL);
- dst += stride;
- }
-}
-
-static void dc_128_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, 0x8080808080808080ULL);
- AV_WN64A(dst + 8, 0x8080808080808080ULL);
- AV_WN64A(dst + 16, 0x8080808080808080ULL);
- AV_WN64A(dst + 24, 0x8080808080808080ULL);
- dst += stride;
- }
-}
-
-static void dc_127_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- AV_WN32A(dst + stride * 0, 0x7F7F7F7FU);
- AV_WN32A(dst + stride * 1, 0x7F7F7F7FU);
- AV_WN32A(dst + stride * 2, 0x7F7F7F7FU);
- AV_WN32A(dst + stride * 3, 0x7F7F7F7FU);
-}
-
-static void dc_127_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, 0x7F7F7F7F7F7F7F7FULL);
- dst += stride;
- }
-}
-
-static void dc_127_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, 0x7F7F7F7F7F7F7F7FULL);
- AV_WN64A(dst + 8, 0x7F7F7F7F7F7F7F7FULL);
- dst += stride;
- }
-}
-
-static void dc_127_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, 0x7F7F7F7F7F7F7F7FULL);
- AV_WN64A(dst + 8, 0x7F7F7F7F7F7F7F7FULL);
- AV_WN64A(dst + 16, 0x7F7F7F7F7F7F7F7FULL);
- AV_WN64A(dst + 24, 0x7F7F7F7F7F7F7F7FULL);
- dst += stride;
- }
-}
-
-static void dc_129_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- AV_WN32A(dst + stride * 0, 0x81818181U);
- AV_WN32A(dst + stride * 1, 0x81818181U);
- AV_WN32A(dst + stride * 2, 0x81818181U);
- AV_WN32A(dst + stride * 3, 0x81818181U);
-}
-
-static void dc_129_8x8_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 8; y++) {
- AV_WN64A(dst, 0x8181818181818181ULL);
- dst += stride;
- }
-}
-
-static void dc_129_16x16_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 16; y++) {
- AV_WN64A(dst + 0, 0x8181818181818181ULL);
- AV_WN64A(dst + 8, 0x8181818181818181ULL);
- dst += stride;
- }
-}
-
-static void dc_129_32x32_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int y;
-
- for (y = 0; y < 32; y++) {
- AV_WN64A(dst + 0, 0x8181818181818181ULL);
- AV_WN64A(dst + 8, 0x8181818181818181ULL);
- AV_WN64A(dst + 16, 0x8181818181818181ULL);
- AV_WN64A(dst + 24, 0x8181818181818181ULL);
- dst += stride;
- }
-}
-
-#define DST(x, y) dst[(x) + (y) * stride]
-
-static void diag_downleft_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
- a4 = top[4], a5 = top[5], a6 = top[6], a7 = top[7];
-
- DST(0, 0) = (a0 + a1 * 2 + a2 + 2) >> 2;
- DST(1, 0) =
- DST(0, 1) = (a1 + a2 * 2 + a3 + 2) >> 2;
- DST(2, 0) =
- DST(1, 1) =
- DST(0, 2) = (a2 + a3 * 2 + a4 + 2) >> 2;
- DST(3, 0) =
- DST(2, 1) =
- DST(1, 2) =
- DST(0, 3) = (a3 + a4 * 2 + a5 + 2) >> 2;
- DST(3, 1) =
- DST(2, 2) =
- DST(1, 3) = (a4 + a5 * 2 + a6 + 2) >> 2;
- DST(3, 2) =
- DST(2, 3) = (a5 + a6 * 2 + a7 + 2) >> 2;
- DST(3, 3) = a7; // note: this is different from vp8 and such
-}
-
-#define def_diag_downleft(size) \
-static void diag_downleft_ ## size ## x ## size ## _c(uint8_t *dst, \
- ptrdiff_t stride, \
- const uint8_t *left, \
- const uint8_t *top) \
-{ \
- int i, j; \
- uint8_t v[size - 1]; \
- \
- for (i = 0; i < size - 2; i++) \
- v[i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
- v[size - 2] = (top[size - 2] + top[size - 1] * 3 + 2) >> 2; \
- \
- for (j = 0; j < size; j++) { \
- memcpy(dst + j * stride, v + j, size - 1 - j); \
- memset(dst + j * stride + size - 1 - j, top[size - 1], j + 1); \
- } \
-}
-
-def_diag_downleft(8)
-def_diag_downleft(16)
-def_diag_downleft(32)
-
-static void diag_downright_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
- l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3];
-
- DST(0, 3) = (l1 + l2 * 2 + l3 + 2) >> 2;
- DST(0, 2) =
- DST(1, 3) = (l0 + l1 * 2 + l2 + 2) >> 2;
- DST(0, 1) =
- DST(1, 2) =
- DST(2, 3) = (tl + l0 * 2 + l1 + 2) >> 2;
- DST(0, 0) =
- DST(1, 1) =
- DST(2, 2) =
- DST(3, 3) = (l0 + tl * 2 + a0 + 2) >> 2;
- DST(1, 0) =
- DST(2, 1) =
- DST(3, 2) = (tl + a0 * 2 + a1 + 2) >> 2;
- DST(2, 0) =
- DST(3, 1) = (a0 + a1 * 2 + a2 + 2) >> 2;
- DST(3, 0) = (a1 + a2 * 2 + a3 + 2) >> 2;
-}
-
-#define def_diag_downright(size) \
-static void diag_downright_ ## size ## x ## size ## _c(uint8_t *dst, \
- ptrdiff_t stride, \
- const uint8_t *left, \
- const uint8_t *top) \
-{ \
- int i, j; \
- uint8_t v[size + size - 1]; \
- \
- for (i = 0; i < size - 2; i++) { \
- v[i] = (left[size - 1 - i] + \
- left[size - 2 - i] * 2 + \
- left[size - 3 - i] + 2) >> 2; \
- v[size + 1 + i] = (top[i] + \
- top[i + 1] * 2 + \
- top[i + 2] + 2) >> 2; \
- } \
- v[size - 2] = (left[1] + left[0] * 2 + top[-1] + 2) >> 2; \
- v[size - 1] = (left[0] + top[-1] * 2 + top[0] + 2) >> 2; \
- v[size] = (top[-1] + top[0] * 2 + top[1] + 2) >> 2; \
- \
- for (j = 0; j < size; j++) \
- memcpy(dst + j * stride, v + size - 1 - j, size); \
-}
-
-def_diag_downright(8)
-def_diag_downright(16)
-def_diag_downright(32)
-
-static void vert_right_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
- l0 = left[0], l1 = left[1], l2 = left[2];
-
- DST(0, 3) = (l0 + l1 * 2 + l2 + 2) >> 2;
- DST(0, 2) = (tl + l0 * 2 + l1 + 2) >> 2;
- DST(0, 0) =
- DST(1, 2) = (tl + a0 + 1) >> 1;
- DST(0, 1) =
- DST(1, 3) = (l0 + tl * 2 + a0 + 2) >> 2;
- DST(1, 0) =
- DST(2, 2) = (a0 + a1 + 1) >> 1;
- DST(1, 1) =
- DST(2, 3) = (tl + a0 * 2 + a1 + 2) >> 2;
- DST(2, 0) =
- DST(3, 2) = (a1 + a2 + 1) >> 1;
- DST(2, 1) =
- DST(3, 3) = (a0 + a1 * 2 + a2 + 2) >> 2;
- DST(3, 0) = (a2 + a3 + 1) >> 1;
- DST(3, 1) = (a1 + a2 * 2 + a3 + 2) >> 2;
-}
-
-#define def_vert_right(size) \
-static void vert_right_ ## size ## x ## size ## _c(uint8_t *dst, \
- ptrdiff_t stride, \
- const uint8_t *left, \
- const uint8_t *top) \
-{ \
- int i, j; \
- uint8_t ve[size + size / 2 - 1], vo[size + size / 2 - 1]; \
- \
- for (i = 0; i < size / 2 - 2; i++) { \
- vo[i] = (left[size - 4 - i * 2] + \
- left[size - 3 - i * 2] * 2 + \
- left[size - 2 - i * 2] + 2) >> 2; \
- ve[i] = (left[size - 5 - i * 2] + \
- left[size - 4 - i * 2] * 2 + \
- left[size - 3 - i * 2] + 2) >> 2; \
- } \
- vo[size / 2 - 2] = (left[0] + left[1] * 2 + left[2] + 2) >> 2; \
- ve[size / 2 - 2] = (top[-1] + left[0] * 2 + left[1] + 2) >> 2; \
- \
- ve[size / 2 - 1] = (top[-1] + top[0] + 1) >> 1; \
- vo[size / 2 - 1] = (left[0] + top[-1] * 2 + top[0] + 2) >> 2; \
- for (i = 0; i < size - 1; i++) { \
- ve[size / 2 + i] = (top[i] + top[i + 1] + 1) >> 1; \
- vo[size / 2 + i] = (top[i - 1] + top[i] * 2 + top[i + 1] + 2) >> 2; \
- } \
- \
- for (j = 0; j < size / 2; j++) { \
- memcpy(dst + j * 2 * stride, ve + size / 2 - 1 - j, size); \
- memcpy(dst + (j * 2 + 1) * stride, vo + size / 2 - 1 - j, size); \
- } \
-}
-
-def_vert_right(8)
-def_vert_right(16)
-def_vert_right(32)
-
-static void hor_down_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3],
- tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2];
-
- DST(2, 0) = (tl + a0 * 2 + a1 + 2) >> 2;
- DST(3, 0) = (a0 + a1 * 2 + a2 + 2) >> 2;
- DST(0, 0) =
- DST(2, 1) = (tl + l0 + 1) >> 1;
- DST(1, 0) =
- DST(3, 1) = (a0 + tl * 2 + l0 + 2) >> 2;
- DST(0, 1) =
- DST(2, 2) = (l0 + l1 + 1) >> 1;
- DST(1, 1) =
- DST(3, 2) = (tl + l0 * 2 + l1 + 2) >> 2;
- DST(0, 2) =
- DST(2, 3) = (l1 + l2 + 1) >> 1;
- DST(1, 2) =
- DST(3, 3) = (l0 + l1 * 2 + l2 + 2) >> 2;
- DST(0, 3) = (l2 + l3 + 1) >> 1;
- DST(1, 3) = (l1 + l2 * 2 + l3 + 2) >> 2;
-}
-
-#define def_hor_down(size) \
-static void hor_down_ ## size ## x ## size ## _c(uint8_t *dst, \
- ptrdiff_t stride, \
- const uint8_t *left, \
- const uint8_t *top) \
-{ \
- int i, j; \
- uint8_t v[size * 3 - 2]; \
- \
- for (i = 0; i < size - 2; i++) { \
- v[i * 2] = (left[size - 2 - i] + \
- left[size - 1 - i] + 1) >> 1; \
- v[i * 2 + 1] = (left[size - 3 - i] + \
- left[size - 2 - i] * 2 + \
- left[size - 1 - i] + 2) >> 2; \
- v[size * 2 + i] = (top[i - 1] + \
- top[i] * 2 + \
- top[i + 1] + 2) >> 2; \
- } \
- v[size * 2 - 2] = (top[-1] + left[0] + 1) >> 1; \
- v[size * 2 - 4] = (left[0] + left[1] + 1) >> 1; \
- v[size * 2 - 1] = (top[0] + top[-1] * 2 + left[0] + 2) >> 2; \
- v[size * 2 - 3] = (top[-1] + left[0] * 2 + left[1] + 2) >> 2; \
- \
- for (j = 0; j < size; j++) \
- memcpy(dst + j * stride, v + size * 2 - 2 - j * 2, size); \
-}
-
-def_hor_down(8)
-def_hor_down(16)
-def_hor_down(32)
-
-static void vert_left_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
- a4 = top[4], a5 = top[5], a6 = top[6];
-
- DST(0, 0) = (a0 + a1 + 1) >> 1;
- DST(0, 1) = (a0 + a1 * 2 + a2 + 2) >> 2;
- DST(1, 0) =
- DST(0, 2) = (a1 + a2 + 1) >> 1;
- DST(1, 1) =
- DST(0, 3) = (a1 + a2 * 2 + a3 + 2) >> 2;
- DST(2, 0) =
- DST(1, 2) = (a2 + a3 + 1) >> 1;
- DST(2, 1) =
- DST(1, 3) = (a2 + a3 * 2 + a4 + 2) >> 2;
- DST(3, 0) =
- DST(2, 2) = (a3 + a4 + 1) >> 1;
- DST(3, 1) =
- DST(2, 3) = (a3 + a4 * 2 + a5 + 2) >> 2;
- DST(3, 2) = (a4 + a5 + 1) >> 1;
- DST(3, 3) = (a4 + a5 * 2 + a6 + 2) >> 2;
-}
-
-#define def_vert_left(size) \
-static void vert_left_ ## size ## x ## size ## _c(uint8_t *dst, \
- ptrdiff_t stride, \
- const uint8_t *left, \
- const uint8_t *top) \
-{ \
- int i, j; \
- uint8_t ve[size - 1], vo[size - 1]; \
- \
- for (i = 0; i < size - 2; i++) { \
- ve[i] = (top[i] + top[i + 1] + 1) >> 1; \
- vo[i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
- } \
- ve[size - 2] = (top[size - 2] + top[size - 1] + 1) >> 1; \
- vo[size - 2] = (top[size - 2] + top[size - 1] * 3 + 2) >> 2; \
- \
- for (j = 0; j < size / 2; j++) { \
- memcpy(dst + j * 2 * stride, ve + j, size - (j + 1)); \
- memset(dst + j * 2 * stride + size - j - 1, \
- top[size - 1], j + 1); \
- memcpy(dst + (j * 2 + 1) * stride, vo + j, size - (j + 1)); \
- memset(dst + (j * 2 + 1) * stride + size - j - 1, \
- top[size - 1], j + 1); \
- } \
-}
-
-def_vert_left(8)
-def_vert_left(16)
-def_vert_left(32)
-
-static void hor_up_4x4_c(uint8_t *dst, ptrdiff_t stride,
- const uint8_t *left, const uint8_t *top)
-{
- int l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3];
-
- DST(0, 0) = (l0 + l1 + 1) >> 1;
- DST(1, 0) = (l0 + l1 * 2 + l2 + 2) >> 2;
- DST(0, 1) =
- DST(2, 0) = (l1 + l2 + 1) >> 1;
- DST(1, 1) =
- DST(3, 0) = (l1 + l2 * 2 + l3 + 2) >> 2;
- DST(0, 2) =
- DST(2, 1) = (l2 + l3 + 1) >> 1;
- DST(1, 2) =
- DST(3, 1) = (l2 + l3 * 3 + 2) >> 2;
- DST(0, 3) =
- DST(1, 3) =
- DST(2, 2) =
- DST(2, 3) =
- DST(3, 2) =
- DST(3, 3) = l3;
-}
-
-#define def_hor_up(size) \
-static void hor_up_ ## size ## x ## size ## _c(uint8_t *dst, \
- ptrdiff_t stride, \
- const uint8_t *left, \
- const uint8_t *top) \
-{ \
- int i, j; \
- uint8_t v[size * 2 - 2]; \
- \
- for (i = 0; i < size - 2; i++) { \
- v[i * 2] = (left[i] + left[i + 1] + 1) >> 1; \
- v[i * 2 + 1] = (left[i] + left[i + 1] * 2 + left[i + 2] + 2) >> 2; \
- } \
- v[size * 2 - 4] = (left[size - 2] + left[size - 1] + 1) >> 1; \
- v[size * 2 - 3] = (left[size - 2] + left[size - 1] * 3 + 2) >> 2; \
- \
- for (j = 0; j < size / 2; j++) \
- memcpy(dst + j * stride, v + j * 2, size); \
- for (j = size / 2; j < size; j++) { \
- memcpy(dst + j * stride, v + j * 2, size * 2 - 2 - j * 2); \
- memset(dst + j * stride + size * 2 - 2 - j * 2, left[size - 1], \
- 2 + j * 2 - size); \
- } \
-}
-
-def_hor_up(8)
-def_hor_up(16)
-def_hor_up(32)
-
-#undef DST
-
-static av_cold void vp9dsp_intrapred_init(VP9DSPContext *dsp)
-{
-#define init_intra_pred(tx, sz) \
- dsp->intra_pred[tx][VERT_PRED] = vert_ ## sz ## _c; \
- dsp->intra_pred[tx][HOR_PRED] = hor_ ## sz ## _c; \
- dsp->intra_pred[tx][DC_PRED] = dc_ ## sz ## _c; \
- dsp->intra_pred[tx][DIAG_DOWN_LEFT_PRED] = diag_downleft_ ## sz ## _c; \
- dsp->intra_pred[tx][DIAG_DOWN_RIGHT_PRED] = diag_downright_ ## sz ## _c; \
- dsp->intra_pred[tx][VERT_RIGHT_PRED] = vert_right_ ## sz ## _c; \
- dsp->intra_pred[tx][HOR_DOWN_PRED] = hor_down_ ## sz ## _c; \
- dsp->intra_pred[tx][VERT_LEFT_PRED] = vert_left_ ## sz ## _c; \
- dsp->intra_pred[tx][HOR_UP_PRED] = hor_up_ ## sz ## _c; \
- dsp->intra_pred[tx][TM_VP8_PRED] = tm_ ## sz ## _c; \
- dsp->intra_pred[tx][LEFT_DC_PRED] = dc_left_ ## sz ## _c; \
- dsp->intra_pred[tx][TOP_DC_PRED] = dc_top_ ## sz ## _c; \
- dsp->intra_pred[tx][DC_128_PRED] = dc_128_ ## sz ## _c; \
- dsp->intra_pred[tx][DC_127_PRED] = dc_127_ ## sz ## _c; \
- dsp->intra_pred[tx][DC_129_PRED] = dc_129_ ## sz ## _c
-
- init_intra_pred(TX_4X4, 4x4);
- init_intra_pred(TX_8X8, 8x8);
- init_intra_pred(TX_16X16, 16x16);
- init_intra_pred(TX_32X32, 32x32);
-
-#undef init_intra_pred
-}
-
-#define itxfm_wrapper(type_a, type_b, sz, bits) \
-static void \
-type_a ## _ ## type_b ## _ ## sz ## x ## sz ## _add_c(uint8_t *dst, \
- ptrdiff_t stride, \
- int16_t *block, \
- int eob) \
-{ \
- int i, j; \
- int16_t tmp[sz * sz], out[sz]; \
- for (i = 0; i < sz; i++) \
- type_a ## sz ## _1d(tmp + i * sz, block + i, sz, 0); \
- memset(block, 0, sz * sz * sizeof(*block)); \
- for (i = 0; i < sz; i++) { \
- type_b ## sz ## _1d(out, tmp + i, sz, 1); \
- for (j = 0; j < sz; j++) \
- dst[j * stride] = \
- av_clip_uint8(dst[j * stride] + \
- (bits ? (out[j] + (1 << (bits - 1))) >> bits \
- : out[j])); \
- dst++; \
- } \
-}
-
-#define itxfm_wrap(sz, bits) \
- itxfm_wrapper(idct, idct, sz, bits) \
- itxfm_wrapper(iadst, idct, sz, bits) \
- itxfm_wrapper(idct, iadst, sz, bits) \
- itxfm_wrapper(iadst, iadst, sz, bits)
-
-#define IN(x) in[x * stride]
-
-static av_always_inline void idct4_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t1, t2, t3;
-
- t0 = ((IN(0) + IN(2)) * 11585 + (1 << 13)) >> 14;
- t1 = ((IN(0) - IN(2)) * 11585 + (1 << 13)) >> 14;
- t2 = (IN(1) * 6270 - IN(3) * 15137 + (1 << 13)) >> 14;
- t3 = (IN(1) * 15137 + IN(3) * 6270 + (1 << 13)) >> 14;
-
- out[0] = t0 + t3;
- out[1] = t1 + t2;
- out[2] = t1 - t2;
- out[3] = t0 - t3;
-}
-
-static av_always_inline void iadst4_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t1, t2, t3;
-
- t0 = 5283 * IN(0) + 15212 * IN(2) + 9929 * IN(3);
- t1 = 9929 * IN(0) - 5283 * IN(2) - 15212 * IN(3);
- t2 = 13377 * (IN(0) - IN(2) + IN(3));
- t3 = 13377 * IN(1);
-
- out[0] = (t0 + t3 + (1 << 13)) >> 14;
- out[1] = (t1 + t3 + (1 << 13)) >> 14;
- out[2] = (t2 + (1 << 13)) >> 14;
- out[3] = (t0 + t1 - t3 + (1 << 13)) >> 14;
-}
-
-itxfm_wrap(4, 4)
-
-static av_always_inline void idct8_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t0a, t1, t1a, t2, t2a, t3, t3a, t4, t4a, t5, t5a, t6, t6a, t7, t7a;
-
- t0a = ((IN(0) + IN(4)) * 11585 + (1 << 13)) >> 14;
- t1a = ((IN(0) - IN(4)) * 11585 + (1 << 13)) >> 14;
- t2a = (IN(2) * 6270 - IN(6) * 15137 + (1 << 13)) >> 14;
- t3a = (IN(2) * 15137 + IN(6) * 6270 + (1 << 13)) >> 14;
- t4a = (IN(1) * 3196 - IN(7) * 16069 + (1 << 13)) >> 14;
- t5a = (IN(5) * 13623 - IN(3) * 9102 + (1 << 13)) >> 14;
- t6a = (IN(5) * 9102 + IN(3) * 13623 + (1 << 13)) >> 14;
- t7a = (IN(1) * 16069 + IN(7) * 3196 + (1 << 13)) >> 14;
-
- t0 = t0a + t3a;
- t1 = t1a + t2a;
- t2 = t1a - t2a;
- t3 = t0a - t3a;
- t4 = t4a + t5a;
- t5a = t4a - t5a;
- t7 = t7a + t6a;
- t6a = t7a - t6a;
-
- t5 = ((t6a - t5a) * 11585 + (1 << 13)) >> 14;
- t6 = ((t6a + t5a) * 11585 + (1 << 13)) >> 14;
-
- out[0] = t0 + t7;
- out[1] = t1 + t6;
- out[2] = t2 + t5;
- out[3] = t3 + t4;
- out[4] = t3 - t4;
- out[5] = t2 - t5;
- out[6] = t1 - t6;
- out[7] = t0 - t7;
-}
-
-static av_always_inline void iadst8_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t0a, t1, t1a, t2, t2a, t3, t3a, t4, t4a, t5, t5a, t6, t6a, t7, t7a;
-
- t0a = 16305 * IN(7) + 1606 * IN(0);
- t1a = 1606 * IN(7) - 16305 * IN(0);
- t2a = 14449 * IN(5) + 7723 * IN(2);
- t3a = 7723 * IN(5) - 14449 * IN(2);
- t4a = 10394 * IN(3) + 12665 * IN(4);
- t5a = 12665 * IN(3) - 10394 * IN(4);
- t6a = 4756 * IN(1) + 15679 * IN(6);
- t7a = 15679 * IN(1) - 4756 * IN(6);
-
- t0 = (t0a + t4a + (1 << 13)) >> 14;
- t1 = (t1a + t5a + (1 << 13)) >> 14;
- t2 = (t2a + t6a + (1 << 13)) >> 14;
- t3 = (t3a + t7a + (1 << 13)) >> 14;
- t4 = (t0a - t4a + (1 << 13)) >> 14;
- t5 = (t1a - t5a + (1 << 13)) >> 14;
- t6 = (t2a - t6a + (1 << 13)) >> 14;
- t7 = (t3a - t7a + (1 << 13)) >> 14;
-
- t4a = 15137 * t4 + 6270 * t5;
- t5a = 6270 * t4 - 15137 * t5;
- t6a = 15137 * t7 - 6270 * t6;
- t7a = 6270 * t7 + 15137 * t6;
-
- out[0] = t0 + t2;
- out[7] = -(t1 + t3);
- t2 = t0 - t2;
- t3 = t1 - t3;
-
- out[1] = -((t4a + t6a + (1 << 13)) >> 14);
- out[6] = (t5a + t7a + (1 << 13)) >> 14;
- t6 = (t4a - t6a + (1 << 13)) >> 14;
- t7 = (t5a - t7a + (1 << 13)) >> 14;
-
- out[3] = -(((t2 + t3) * 11585 + (1 << 13)) >> 14);
- out[4] = ((t2 - t3) * 11585 + (1 << 13)) >> 14;
- out[2] = ((t6 + t7) * 11585 + (1 << 13)) >> 14;
- out[5] = -(((t6 - t7) * 11585 + (1 << 13)) >> 14);
-}
-
-itxfm_wrap(8, 5)
-
-static av_always_inline void idct16_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
- int t0a, t1a, t2a, t3a, t4a, t5a, t6a, t7a;
- int t8a, t9a, t10a, t11a, t12a, t13a, t14a, t15a;
-
- t0a = ((IN(0) + IN(8)) * 11585 + (1 << 13)) >> 14;
- t1a = ((IN(0) - IN(8)) * 11585 + (1 << 13)) >> 14;
- t2a = (IN(4) * 6270 - IN(12) * 15137 + (1 << 13)) >> 14;
- t3a = (IN(4) * 15137 + IN(12) * 6270 + (1 << 13)) >> 14;
- t4a = (IN(2) * 3196 - IN(14) * 16069 + (1 << 13)) >> 14;
- t7a = (IN(2) * 16069 + IN(14) * 3196 + (1 << 13)) >> 14;
- t5a = (IN(10) * 13623 - IN(6) * 9102 + (1 << 13)) >> 14;
- t6a = (IN(10) * 9102 + IN(6) * 13623 + (1 << 13)) >> 14;
- t8a = (IN(1) * 1606 - IN(15) * 16305 + (1 << 13)) >> 14;
- t15a = (IN(1) * 16305 + IN(15) * 1606 + (1 << 13)) >> 14;
- t9a = (IN(9) * 12665 - IN(7) * 10394 + (1 << 13)) >> 14;
- t14a = (IN(9) * 10394 + IN(7) * 12665 + (1 << 13)) >> 14;
- t10a = (IN(5) * 7723 - IN(11) * 14449 + (1 << 13)) >> 14;
- t13a = (IN(5) * 14449 + IN(11) * 7723 + (1 << 13)) >> 14;
- t11a = (IN(13) * 15679 - IN(3) * 4756 + (1 << 13)) >> 14;
- t12a = (IN(13) * 4756 + IN(3) * 15679 + (1 << 13)) >> 14;
-
- t0 = t0a + t3a;
- t1 = t1a + t2a;
- t2 = t1a - t2a;
- t3 = t0a - t3a;
- t4 = t4a + t5a;
- t5 = t4a - t5a;
- t6 = t7a - t6a;
- t7 = t7a + t6a;
- t8 = t8a + t9a;
- t9 = t8a - t9a;
- t10 = t11a - t10a;
- t11 = t11a + t10a;
- t12 = t12a + t13a;
- t13 = t12a - t13a;
- t14 = t15a - t14a;
- t15 = t15a + t14a;
-
- t5a = ((t6 - t5) * 11585 + (1 << 13)) >> 14;
- t6a = ((t6 + t5) * 11585 + (1 << 13)) >> 14;
- t9a = (t14 * 6270 - t9 * 15137 + (1 << 13)) >> 14;
- t14a = (t14 * 15137 + t9 * 6270 + (1 << 13)) >> 14;
- t10a = (-(t13 * 15137 + t10 * 6270) + (1 << 13)) >> 14;
- t13a = (t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
-
- t0a = t0 + t7;
- t1a = t1 + t6a;
- t2a = t2 + t5a;
- t3a = t3 + t4;
- t4 = t3 - t4;
- t5 = t2 - t5a;
- t6 = t1 - t6a;
- t7 = t0 - t7;
- t8a = t8 + t11;
- t9 = t9a + t10a;
- t10 = t9a - t10a;
- t11a = t8 - t11;
- t12a = t15 - t12;
- t13 = t14a - t13a;
- t14 = t14a + t13a;
- t15a = t15 + t12;
-
- t10a = ((t13 - t10) * 11585 + (1 << 13)) >> 14;
- t13a = ((t13 + t10) * 11585 + (1 << 13)) >> 14;
- t11 = ((t12a - t11a) * 11585 + (1 << 13)) >> 14;
- t12 = ((t12a + t11a) * 11585 + (1 << 13)) >> 14;
-
- out[0] = t0a + t15a;
- out[1] = t1a + t14;
- out[2] = t2a + t13a;
- out[3] = t3a + t12;
- out[4] = t4 + t11;
- out[5] = t5 + t10a;
- out[6] = t6 + t9;
- out[7] = t7 + t8a;
- out[8] = t7 - t8a;
- out[9] = t6 - t9;
- out[10] = t5 - t10a;
- out[11] = t4 - t11;
- out[12] = t3a - t12;
- out[13] = t2a - t13a;
- out[14] = t1a - t14;
- out[15] = t0a - t15a;
-}
-
-static av_always_inline void iadst16_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
- int t0a, t1a, t2a, t3a, t4a, t5a, t6a, t7a;
- int t8a, t9a, t10a, t11a, t12a, t13a, t14a, t15a;
-
- t0 = IN(15) * 16364 + IN(0) * 804;
- t1 = IN(15) * 804 - IN(0) * 16364;
- t2 = IN(13) * 15893 + IN(2) * 3981;
- t3 = IN(13) * 3981 - IN(2) * 15893;
- t4 = IN(11) * 14811 + IN(4) * 7005;
- t5 = IN(11) * 7005 - IN(4) * 14811;
- t6 = IN(9) * 13160 + IN(6) * 9760;
- t7 = IN(9) * 9760 - IN(6) * 13160;
- t8 = IN(7) * 11003 + IN(8) * 12140;
- t9 = IN(7) * 12140 - IN(8) * 11003;
- t10 = IN(5) * 8423 + IN(10) * 14053;
- t11 = IN(5) * 14053 - IN(10) * 8423;
- t12 = IN(3) * 5520 + IN(12) * 15426;
- t13 = IN(3) * 15426 - IN(12) * 5520;
- t14 = IN(1) * 2404 + IN(14) * 16207;
- t15 = IN(1) * 16207 - IN(14) * 2404;
-
- t0a = (t0 + t8 + (1 << 13)) >> 14;
- t1a = (t1 + t9 + (1 << 13)) >> 14;
- t2a = (t2 + t10 + (1 << 13)) >> 14;
- t3a = (t3 + t11 + (1 << 13)) >> 14;
- t4a = (t4 + t12 + (1 << 13)) >> 14;
- t5a = (t5 + t13 + (1 << 13)) >> 14;
- t6a = (t6 + t14 + (1 << 13)) >> 14;
- t7a = (t7 + t15 + (1 << 13)) >> 14;
- t8a = (t0 - t8 + (1 << 13)) >> 14;
- t9a = (t1 - t9 + (1 << 13)) >> 14;
- t10a = (t2 - t10 + (1 << 13)) >> 14;
- t11a = (t3 - t11 + (1 << 13)) >> 14;
- t12a = (t4 - t12 + (1 << 13)) >> 14;
- t13a = (t5 - t13 + (1 << 13)) >> 14;
- t14a = (t6 - t14 + (1 << 13)) >> 14;
- t15a = (t7 - t15 + (1 << 13)) >> 14;
-
- t8 = t8a * 16069 + t9a * 3196;
- t9 = t8a * 3196 - t9a * 16069;
- t10 = t10a * 9102 + t11a * 13623;
- t11 = t10a * 13623 - t11a * 9102;
- t12 = t13a * 16069 - t12a * 3196;
- t13 = t13a * 3196 + t12a * 16069;
- t14 = t15a * 9102 - t14a * 13623;
- t15 = t15a * 13623 + t14a * 9102;
-
- t0 = t0a + t4a;
- t1 = t1a + t5a;
- t2 = t2a + t6a;
- t3 = t3a + t7a;
- t4 = t0a - t4a;
- t5 = t1a - t5a;
- t6 = t2a - t6a;
- t7 = t3a - t7a;
- t8a = (t8 + t12 + (1 << 13)) >> 14;
- t9a = (t9 + t13 + (1 << 13)) >> 14;
- t10a = (t10 + t14 + (1 << 13)) >> 14;
- t11a = (t11 + t15 + (1 << 13)) >> 14;
- t12a = (t8 - t12 + (1 << 13)) >> 14;
- t13a = (t9 - t13 + (1 << 13)) >> 14;
- t14a = (t10 - t14 + (1 << 13)) >> 14;
- t15a = (t11 - t15 + (1 << 13)) >> 14;
-
- t4a = t4 * 15137 + t5 * 6270;
- t5a = t4 * 6270 - t5 * 15137;
- t6a = t7 * 15137 - t6 * 6270;
- t7a = t7 * 6270 + t6 * 15137;
- t12 = t12a * 15137 + t13a * 6270;
- t13 = t12a * 6270 - t13a * 15137;
- t14 = t15a * 15137 - t14a * 6270;
- t15 = t15a * 6270 + t14a * 15137;
-
- out[0] = t0 + t2;
- out[15] = -(t1 + t3);
- t2a = t0 - t2;
- t3a = t1 - t3;
- out[3] = -((t4a + t6a + (1 << 13)) >> 14);
- out[12] = (t5a + t7a + (1 << 13)) >> 14;
- t6 = (t4a - t6a + (1 << 13)) >> 14;
- t7 = (t5a - t7a + (1 << 13)) >> 14;
- out[1] = -(t8a + t10a);
- out[14] = t9a + t11a;
- t10 = t8a - t10a;
- t11 = t9a - t11a;
- out[2] = (t12 + t14 + (1 << 13)) >> 14;
- out[13] = -((t13 + t15 + (1 << 13)) >> 14);
- t14a = (t12 - t14 + (1 << 13)) >> 14;
- t15a = (t13 - t15 + (1 << 13)) >> 14;
-
- out[7] = ((t2a + t3a) * -11585 + (1 << 13)) >> 14;
- out[8] = ((t2a - t3a) * 11585 + (1 << 13)) >> 14;
- out[4] = ((t7 + t6) * 11585 + (1 << 13)) >> 14;
- out[11] = ((t7 - t6) * 11585 + (1 << 13)) >> 14;
- out[6] = ((t11 + t10) * 11585 + (1 << 13)) >> 14;
- out[9] = ((t11 - t10) * 11585 + (1 << 13)) >> 14;
- out[5] = ((t14a + t15a) * -11585 + (1 << 13)) >> 14;
- out[10] = ((t14a - t15a) * 11585 + (1 << 13)) >> 14;
-}
-
-itxfm_wrap(16, 6)
-
-static av_always_inline void idct32_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
+av_cold void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp)
{
- int t0a = ((IN(0) + IN(16)) * 11585 + (1 << 13)) >> 14;
- int t1a = ((IN(0) - IN(16)) * 11585 + (1 << 13)) >> 14;
- int t2a = (IN(8) * 6270 - IN(24) * 15137 + (1 << 13)) >> 14;
- int t3a = (IN(8) * 15137 + IN(24) * 6270 + (1 << 13)) >> 14;
- int t4a = (IN(4) * 3196 - IN(28) * 16069 + (1 << 13)) >> 14;
- int t7a = (IN(4) * 16069 + IN(28) * 3196 + (1 << 13)) >> 14;
- int t5a = (IN(20) * 13623 - IN(12) * 9102 + (1 << 13)) >> 14;
- int t6a = (IN(20) * 9102 + IN(12) * 13623 + (1 << 13)) >> 14;
- int t8a = (IN(2) * 1606 - IN(30) * 16305 + (1 << 13)) >> 14;
- int t15a = (IN(2) * 16305 + IN(30) * 1606 + (1 << 13)) >> 14;
- int t9a = (IN(18) * 12665 - IN(14) * 10394 + (1 << 13)) >> 14;
- int t14a = (IN(18) * 10394 + IN(14) * 12665 + (1 << 13)) >> 14;
- int t10a = (IN(10) * 7723 - IN(22) * 14449 + (1 << 13)) >> 14;
- int t13a = (IN(10) * 14449 + IN(22) * 7723 + (1 << 13)) >> 14;
- int t11a = (IN(26) * 15679 - IN(6) * 4756 + (1 << 13)) >> 14;
- int t12a = (IN(26) * 4756 + IN(6) * 15679 + (1 << 13)) >> 14;
- int t16a = (IN(1) * 804 - IN(31) * 16364 + (1 << 13)) >> 14;
- int t31a = (IN(1) * 16364 + IN(31) * 804 + (1 << 13)) >> 14;
- int t17a = (IN(17) * 12140 - IN(15) * 11003 + (1 << 13)) >> 14;
- int t30a = (IN(17) * 11003 + IN(15) * 12140 + (1 << 13)) >> 14;
- int t18a = (IN(9) * 7005 - IN(23) * 14811 + (1 << 13)) >> 14;
- int t29a = (IN(9) * 14811 + IN(23) * 7005 + (1 << 13)) >> 14;
- int t19a = (IN(25) * 15426 - IN(7) * 5520 + (1 << 13)) >> 14;
- int t28a = (IN(25) * 5520 + IN(7) * 15426 + (1 << 13)) >> 14;
- int t20a = (IN(5) * 3981 - IN(27) * 15893 + (1 << 13)) >> 14;
- int t27a = (IN(5) * 15893 + IN(27) * 3981 + (1 << 13)) >> 14;
- int t21a = (IN(21) * 14053 - IN(11) * 8423 + (1 << 13)) >> 14;
- int t26a = (IN(21) * 8423 + IN(11) * 14053 + (1 << 13)) >> 14;
- int t22a = (IN(13) * 9760 - IN(19) * 13160 + (1 << 13)) >> 14;
- int t25a = (IN(13) * 13160 + IN(19) * 9760 + (1 << 13)) >> 14;
- int t23a = (IN(29) * 16207 - IN(3) * 2404 + (1 << 13)) >> 14;
- int t24a = (IN(29) * 2404 + IN(3) * 16207 + (1 << 13)) >> 14;
-
- int t0 = t0a + t3a;
- int t1 = t1a + t2a;
- int t2 = t1a - t2a;
- int t3 = t0a - t3a;
- int t4 = t4a + t5a;
- int t5 = t4a - t5a;
- int t6 = t7a - t6a;
- int t7 = t7a + t6a;
- int t8 = t8a + t9a;
- int t9 = t8a - t9a;
- int t10 = t11a - t10a;
- int t11 = t11a + t10a;
- int t12 = t12a + t13a;
- int t13 = t12a - t13a;
- int t14 = t15a - t14a;
- int t15 = t15a + t14a;
- int t16 = t16a + t17a;
- int t17 = t16a - t17a;
- int t18 = t19a - t18a;
- int t19 = t19a + t18a;
- int t20 = t20a + t21a;
- int t21 = t20a - t21a;
- int t22 = t23a - t22a;
- int t23 = t23a + t22a;
- int t24 = t24a + t25a;
- int t25 = t24a - t25a;
- int t26 = t27a - t26a;
- int t27 = t27a + t26a;
- int t28 = t28a + t29a;
- int t29 = t28a - t29a;
- int t30 = t31a - t30a;
- int t31 = t31a + t30a;
-
- t5a = ((t6 - t5) * 11585 + (1 << 13)) >> 14;
- t6a = ((t6 + t5) * 11585 + (1 << 13)) >> 14;
- t9a = (t14 * 6270 - t9 * 15137 + (1 << 13)) >> 14;
- t14a = (t14 * 15137 + t9 * 6270 + (1 << 13)) >> 14;
- t10a = (-(t13 * 15137 + t10 * 6270) + (1 << 13)) >> 14;
- t13a = (t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
- t17a = (t30 * 3196 - t17 * 16069 + (1 << 13)) >> 14;
- t30a = (t30 * 16069 + t17 * 3196 + (1 << 13)) >> 14;
- t18a = (-(t29 * 16069 + t18 * 3196) + (1 << 13)) >> 14;
- t29a = (t29 * 3196 - t18 * 16069 + (1 << 13)) >> 14;
- t21a = (t26 * 13623 - t21 * 9102 + (1 << 13)) >> 14;
- t26a = (t26 * 9102 + t21 * 13623 + (1 << 13)) >> 14;
- t22a = (-(t25 * 9102 + t22 * 13623) + (1 << 13)) >> 14;
- t25a = (t25 * 13623 - t22 * 9102 + (1 << 13)) >> 14;
-
- t0a = t0 + t7;
- t1a = t1 + t6a;
- t2a = t2 + t5a;
- t3a = t3 + t4;
- t4a = t3 - t4;
- t5 = t2 - t5a;
- t6 = t1 - t6a;
- t7a = t0 - t7;
- t8a = t8 + t11;
- t9 = t9a + t10a;
- t10 = t9a - t10a;
- t11a = t8 - t11;
- t12a = t15 - t12;
- t13 = t14a - t13a;
- t14 = t14a + t13a;
- t15a = t15 + t12;
- t16a = t16 + t19;
- t17 = t17a + t18a;
- t18 = t17a - t18a;
- t19a = t16 - t19;
- t20a = t23 - t20;
- t21 = t22a - t21a;
- t22 = t22a + t21a;
- t23a = t23 + t20;
- t24a = t24 + t27;
- t25 = t25a + t26a;
- t26 = t25a - t26a;
- t27a = t24 - t27;
- t28a = t31 - t28;
- t29 = t30a - t29a;
- t30 = t30a + t29a;
- t31a = t31 + t28;
-
- t10a = ((t13 - t10) * 11585 + (1 << 13)) >> 14;
- t13a = ((t13 + t10) * 11585 + (1 << 13)) >> 14;
- t11 = ((t12a - t11a) * 11585 + (1 << 13)) >> 14;
- t12 = ((t12a + t11a) * 11585 + (1 << 13)) >> 14;
- t18a = (t29 * 6270 - t18 * 15137 + (1 << 13)) >> 14;
- t29a = (t29 * 15137 + t18 * 6270 + (1 << 13)) >> 14;
- t19 = (t28a * 6270 - t19a * 15137 + (1 << 13)) >> 14;
- t28 = (t28a * 15137 + t19a * 6270 + (1 << 13)) >> 14;
- t20 = (-(t27a * 15137 + t20a * 6270) + (1 << 13)) >> 14;
- t27 = (t27a * 6270 - t20a * 15137 + (1 << 13)) >> 14;
- t21a = (-(t26 * 15137 + t21 * 6270) + (1 << 13)) >> 14;
- t26a = (t26 * 6270 - t21 * 15137 + (1 << 13)) >> 14;
-
- t0 = t0a + t15a;
- t1 = t1a + t14;
- t2 = t2a + t13a;
- t3 = t3a + t12;
- t4 = t4a + t11;
- t5a = t5 + t10a;
- t6a = t6 + t9;
- t7 = t7a + t8a;
- t8 = t7a - t8a;
- t9a = t6 - t9;
- t10 = t5 - t10a;
- t11a = t4a - t11;
- t12a = t3a - t12;
- t13 = t2a - t13a;
- t14a = t1a - t14;
- t15 = t0a - t15a;
- t16 = t16a + t23a;
- t17a = t17 + t22;
- t18 = t18a + t21a;
- t19a = t19 + t20;
- t20a = t19 - t20;
- t21 = t18a - t21a;
- t22a = t17 - t22;
- t23 = t16a - t23a;
- t24 = t31a - t24a;
- t25a = t30 - t25;
- t26 = t29a - t26a;
- t27a = t28 - t27;
- t28a = t28 + t27;
- t29 = t29a + t26a;
- t30a = t30 + t25;
- t31 = t31a + t24a;
-
- t20 = ((t27a - t20a) * 11585 + (1 << 13)) >> 14;
- t27 = ((t27a + t20a) * 11585 + (1 << 13)) >> 14;
- t21a = ((t26 - t21) * 11585 + (1 << 13)) >> 14;
- t26a = ((t26 + t21) * 11585 + (1 << 13)) >> 14;
- t22 = ((t25a - t22a) * 11585 + (1 << 13)) >> 14;
- t25 = ((t25a + t22a) * 11585 + (1 << 13)) >> 14;
- t23a = ((t24 - t23) * 11585 + (1 << 13)) >> 14;
- t24a = ((t24 + t23) * 11585 + (1 << 13)) >> 14;
-
- out[0] = t0 + t31;
- out[1] = t1 + t30a;
- out[2] = t2 + t29;
- out[3] = t3 + t28a;
- out[4] = t4 + t27;
- out[5] = t5a + t26a;
- out[6] = t6a + t25;
- out[7] = t7 + t24a;
- out[8] = t8 + t23a;
- out[9] = t9a + t22;
- out[10] = t10 + t21a;
- out[11] = t11a + t20;
- out[12] = t12a + t19a;
- out[13] = t13 + t18;
- out[14] = t14a + t17a;
- out[15] = t15 + t16;
- out[16] = t15 - t16;
- out[17] = t14a - t17a;
- out[18] = t13 - t18;
- out[19] = t12a - t19a;
- out[20] = t11a - t20;
- out[21] = t10 - t21a;
- out[22] = t9a - t22;
- out[23] = t8 - t23a;
- out[24] = t7 - t24a;
- out[25] = t6a - t25;
- out[26] = t5a - t26a;
- out[27] = t4 - t27;
- out[28] = t3 - t28a;
- out[29] = t2 - t29;
- out[30] = t1 - t30a;
- out[31] = t0 - t31;
-}
-
-itxfm_wrapper(idct, idct, 32, 6)
-
-static av_always_inline void iwht4_1d(int16_t *out, const int16_t *in,
- ptrdiff_t stride, int pass)
-{
- int t0, t1, t2, t3, t4;
-
- if (pass == 0) {
- t0 = IN(0) >> 2;
- t1 = IN(3) >> 2;
- t2 = IN(1) >> 2;
- t3 = IN(2) >> 2;
+ if (bpp == 8) {
+ ff_vp9dsp_init_8(dsp);
+ } else if (bpp == 10) {
+ ff_vp9dsp_init_10(dsp);
} else {
- t0 = IN(0);
- t1 = IN(3);
- t2 = IN(1);
- t3 = IN(2);
+ av_assert0(bpp == 12);
+ ff_vp9dsp_init_12(dsp);
}
- t0 += t2;
- t3 -= t1;
- t4 = (t0 - t3) >> 1;
- t1 = t4 - t1;
- t2 = t4 - t2;
- t0 -= t1;
- t3 += t2;
-
- out[0] = t0;
- out[1] = t1;
- out[2] = t2;
- out[3] = t3;
-}
-
-itxfm_wrapper(iwht, iwht, 4, 0)
-
-#undef IN
-#undef itxfm_wrapper
-#undef itxfm_wrap
-
-static av_cold void vp9dsp_itxfm_init(VP9DSPContext *dsp)
-{
-#define init_itxfm(tx, sz) \
- dsp->itxfm_add[tx][DCT_DCT] = idct_idct_ ## sz ## _add_c; \
- dsp->itxfm_add[tx][DCT_ADST] = iadst_idct_ ## sz ## _add_c; \
- dsp->itxfm_add[tx][ADST_DCT] = idct_iadst_ ## sz ## _add_c; \
- dsp->itxfm_add[tx][ADST_ADST] = iadst_iadst_ ## sz ## _add_c
-
-#define init_idct(tx, nm) \
- dsp->itxfm_add[tx][DCT_DCT] = \
- dsp->itxfm_add[tx][ADST_DCT] = \
- dsp->itxfm_add[tx][DCT_ADST] = \
- dsp->itxfm_add[tx][ADST_ADST] = nm ## _add_c
-
- init_itxfm(TX_4X4, 4x4);
- init_itxfm(TX_8X8, 8x8);
- init_itxfm(TX_16X16, 16x16);
- init_idct(TX_32X32, idct_idct_32x32);
- init_idct(4 /* lossless */, iwht_iwht_4x4);
-
-#undef init_itxfm
-#undef init_idct
-}
-
-static av_always_inline void loop_filter(uint8_t *dst, ptrdiff_t stride,
- int E, int I, int H,
- ptrdiff_t stridea, ptrdiff_t strideb,
- int wd)
-{
- int i;
-
- for (i = 0; i < 8; i++, dst += stridea) {
- int p7, p6, p5, p4;
- int p3 = dst[strideb * -4], p2 = dst[strideb * -3];
- int p1 = dst[strideb * -2], p0 = dst[strideb * -1];
- int q0 = dst[strideb * +0], q1 = dst[strideb * +1];
- int q2 = dst[strideb * +2], q3 = dst[strideb * +3];
- int q4, q5, q6, q7;
- int fm = FFABS(p3 - p2) <= I && FFABS(p2 - p1) <= I &&
- FFABS(p1 - p0) <= I && FFABS(q1 - q0) <= I &&
- FFABS(q2 - q1) <= I && FFABS(q3 - q2) <= I &&
- FFABS(p0 - q0) * 2 + (FFABS(p1 - q1) >> 1) <= E;
- int flat8out, flat8in;
-
- if (!fm)
- continue;
-
- if (wd >= 16) {
- p7 = dst[strideb * -8];
- p6 = dst[strideb * -7];
- p5 = dst[strideb * -6];
- p4 = dst[strideb * -5];
- q4 = dst[strideb * +4];
- q5 = dst[strideb * +5];
- q6 = dst[strideb * +6];
- q7 = dst[strideb * +7];
-
- flat8out = FFABS(p7 - p0) <= 1 && FFABS(p6 - p0) <= 1 &&
- FFABS(p5 - p0) <= 1 && FFABS(p4 - p0) <= 1 &&
- FFABS(q4 - q0) <= 1 && FFABS(q5 - q0) <= 1 &&
- FFABS(q6 - q0) <= 1 && FFABS(q7 - q0) <= 1;
- }
-
- if (wd >= 8)
- flat8in = FFABS(p3 - p0) <= 1 && FFABS(p2 - p0) <= 1 &&
- FFABS(p1 - p0) <= 1 && FFABS(q1 - q0) <= 1 &&
- FFABS(q2 - q0) <= 1 && FFABS(q3 - q0) <= 1;
-
- if (wd >= 16 && flat8out && flat8in) {
- dst[strideb * -7] = (p7 + p7 + p7 + p7 + p7 + p7 + p7 + p6 * 2 +
- p5 + p4 + p3 + p2 + p1 + p0 + q0 + 8) >> 4;
- dst[strideb * -6] = (p7 + p7 + p7 + p7 + p7 + p7 + p6 + p5 * 2 +
- p4 + p3 + p2 + p1 + p0 + q0 + q1 + 8) >> 4;
- dst[strideb * -5] = (p7 + p7 + p7 + p7 + p7 + p6 + p5 + p4 * 2 +
- p3 + p2 + p1 + p0 + q0 + q1 + q2 + 8) >> 4;
- dst[strideb * -4] = (p7 + p7 + p7 + p7 + p6 + p5 + p4 + p3 * 2 +
- p2 + p1 + p0 + q0 + q1 + q2 + q3 + 8) >> 4;
- dst[strideb * -3] = (p7 + p7 + p7 + p6 + p5 + p4 + p3 + p2 * 2 +
- p1 + p0 + q0 + q1 + q2 + q3 + q4 + 8) >> 4;
- dst[strideb * -2] = (p7 + p7 + p6 + p5 + p4 + p3 + p2 + p1 * 2 +
- p0 + q0 + q1 + q2 + q3 + q4 + q5 + 8) >> 4;
- dst[strideb * -1] = (p7 + p6 + p5 + p4 + p3 + p2 + p1 + p0 * 2 +
- q0 + q1 + q2 + q3 + q4 + q5 + q6 + 8) >> 4;
- dst[strideb * +0] = (p6 + p5 + p4 + p3 + p2 + p1 + p0 + q0 * 2 +
- q1 + q2 + q3 + q4 + q5 + q6 + q7 + 8) >> 4;
- dst[strideb * +1] = (p5 + p4 + p3 + p2 + p1 + p0 + q0 + q1 * 2 +
- q2 + q3 + q4 + q5 + q6 + q7 + q7 + 8) >> 4;
- dst[strideb * +2] = (p4 + p3 + p2 + p1 + p0 + q0 + q1 + q2 * 2 +
- q3 + q4 + q5 + q6 + q7 + q7 + q7 + 8) >> 4;
- dst[strideb * +3] = (p3 + p2 + p1 + p0 + q0 + q1 + q2 + q3 * 2 +
- q4 + q5 + q6 + q7 + q7 + q7 + q7 + 8) >> 4;
- dst[strideb * +4] = (p2 + p1 + p0 + q0 + q1 + q2 + q3 + q4 * 2 +
- q5 + q6 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
- dst[strideb * +5] = (p1 + p0 + q0 + q1 + q2 + q3 + q4 + q5 * 2 +
- q6 + q7 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
- dst[strideb * +6] = (p0 + q0 + q1 + q2 + q3 + q4 + q5 + q6 * 2 +
- q7 + q7 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
- } else if (wd >= 8 && flat8in) {
- dst[strideb * -3] = (p3 + p3 + p3 + 2 * p2 + p1 + p0 + q0 + 4) >> 3;
- dst[strideb * -2] = (p3 + p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4) >> 3;
- dst[strideb * -1] = (p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3;
- dst[strideb * +0] = (p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3;
- dst[strideb * +1] = (p1 + p0 + q0 + 2 * q1 + q2 + q3 + q3 + 4) >> 3;
- dst[strideb * +2] = (p0 + q0 + q1 + 2 * q2 + q3 + q3 + q3 + 4) >> 3;
- } else {
- int hev = FFABS(p1 - p0) > H || FFABS(q1 - q0) > H;
-
- if (hev) {
- int f = av_clip_int8(3 * (q0 - p0) + av_clip_int8(p1 - q1));
- int f1 = FFMIN(f + 4, 127) >> 3;
- int f2 = FFMIN(f + 3, 127) >> 3;
-
- dst[strideb * -1] = av_clip_uint8(p0 + f2);
- dst[strideb * +0] = av_clip_uint8(q0 - f1);
- } else {
- int f = av_clip_int8(3 * (q0 - p0));
- int f1 = FFMIN(f + 4, 127) >> 3;
- int f2 = FFMIN(f + 3, 127) >> 3;
-
- dst[strideb * -1] = av_clip_uint8(p0 + f2);
- dst[strideb * +0] = av_clip_uint8(q0 - f1);
-
- f = (f1 + 1) >> 1;
- dst[strideb * -2] = av_clip_uint8(p1 + f);
- dst[strideb * +1] = av_clip_uint8(q1 - f);
- }
- }
- }
-}
-
-#define lf_8_fn(dir, wd, stridea, strideb) \
-static void loop_filter_ ## dir ## _ ## wd ## _8_c(uint8_t *dst, \
- ptrdiff_t stride, \
- int E, int I, int H) \
-{ \
- loop_filter(dst, stride, E, I, H, stridea, strideb, wd); \
-}
-
-#define lf_8_fns(wd) \
- lf_8_fn(h, wd, stride, 1) \
- lf_8_fn(v, wd, 1, stride)
-
-lf_8_fns(4)
-lf_8_fns(8)
-lf_8_fns(16)
-
-#undef lf_8_fn
-#undef lf_8_fns
-
-#define lf_16_fn(dir, stridea) \
-static void loop_filter_ ## dir ## _16_16_c(uint8_t *dst, \
- ptrdiff_t stride, \
- int E, int I, int H) \
-{ \
- loop_filter_ ## dir ## _16_8_c(dst, stride, E, I, H); \
- loop_filter_ ## dir ## _16_8_c(dst + 8 * stridea, stride, E, I, H); \
-}
-
-lf_16_fn(h, stride)
-lf_16_fn(v, 1)
-
-#undef lf_16_fn
-
-#define lf_mix_fn(dir, wd1, wd2, stridea) \
-static void loop_filter_ ## dir ## _ ## wd1 ## wd2 ## _16_c(uint8_t *dst, \
- ptrdiff_t stride, \
- int E, int I, \
- int H) \
-{ \
- loop_filter_ ## dir ## _ ## wd1 ## _8_c(dst, stride, E & 0xff, \
- I & 0xff, H & 0xff); \
- loop_filter_ ## dir ## _ ## wd2 ## _8_c(dst + 8 * stridea, stride, \
- E >> 8, I >> 8, H >> 8); \
-}
-
-#define lf_mix_fns(wd1, wd2) \
- lf_mix_fn(h, wd1, wd2, stride) \
- lf_mix_fn(v, wd1, wd2, 1)
-
-lf_mix_fns(4, 4)
-lf_mix_fns(4, 8)
-lf_mix_fns(8, 4)
-lf_mix_fns(8, 8)
-
-#undef lf_mix_fn
-#undef lf_mix_fns
-
-static av_cold void vp9dsp_loopfilter_init(VP9DSPContext *dsp)
-{
- dsp->loop_filter_8[0][0] = loop_filter_h_4_8_c;
- dsp->loop_filter_8[0][1] = loop_filter_v_4_8_c;
- dsp->loop_filter_8[1][0] = loop_filter_h_8_8_c;
- dsp->loop_filter_8[1][1] = loop_filter_v_8_8_c;
- dsp->loop_filter_8[2][0] = loop_filter_h_16_8_c;
- dsp->loop_filter_8[2][1] = loop_filter_v_16_8_c;
-
- dsp->loop_filter_16[0] = loop_filter_h_16_16_c;
- dsp->loop_filter_16[1] = loop_filter_v_16_16_c;
-
- dsp->loop_filter_mix2[0][0][0] = loop_filter_h_44_16_c;
- dsp->loop_filter_mix2[0][0][1] = loop_filter_v_44_16_c;
- dsp->loop_filter_mix2[0][1][0] = loop_filter_h_48_16_c;
- dsp->loop_filter_mix2[0][1][1] = loop_filter_v_48_16_c;
- dsp->loop_filter_mix2[1][0][0] = loop_filter_h_84_16_c;
- dsp->loop_filter_mix2[1][0][1] = loop_filter_v_84_16_c;
- dsp->loop_filter_mix2[1][1][0] = loop_filter_h_88_16_c;
- dsp->loop_filter_mix2[1][1][1] = loop_filter_v_88_16_c;
-}
-
-static av_always_inline void copy_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
- int w, int h)
-{
- do {
- memcpy(dst, src, w);
-
- dst += dst_stride;
- src += src_stride;
- } while (--h);
-}
-
-static av_always_inline void avg_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
- int w, int h)
-{
- do {
- int x;
-
- for (x = 0; x < w; x += 4)
- AV_WN32A(&dst[x], rnd_avg32(AV_RN32A(&dst[x]), AV_RN32(&src[x])));
-
- dst += dst_stride;
- src += src_stride;
- } while (--h);
-}
-
-#define fpel_fn(type, sz) \
-static void type ## sz ## _c(uint8_t *dst, const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my) \
-{ \
- type ## _c(dst, src, dst_stride, src_stride, sz, h); \
-}
-
-#define copy_avg_fn(sz) \
- fpel_fn(copy, sz) \
- fpel_fn(avg, sz)
-
-copy_avg_fn(64)
-copy_avg_fn(32)
-copy_avg_fn(16)
-copy_avg_fn(8)
-copy_avg_fn(4)
-
-#undef fpel_fn
-#undef copy_avg_fn
-
-static const int8_t vp9_subpel_filters[3][15][8] = {
- [FILTER_8TAP_REGULAR] = {
- { 0, 1, -5, 126, 8, -3, 1, 0 },
- { -1, 3, -10, 122, 18, -6, 2, 0 },
- { -1, 4, -13, 118, 27, -9, 3, -1 },
- { -1, 4, -16, 112, 37, -11, 4, -1 },
- { -1, 5, -18, 105, 48, -14, 4, -1 },
- { -1, 5, -19, 97, 58, -16, 5, -1 },
- { -1, 6, -19, 88, 68, -18, 5, -1 },
- { -1, 6, -19, 78, 78, -19, 6, -1 },
- { -1, 5, -18, 68, 88, -19, 6, -1 },
- { -1, 5, -16, 58, 97, -19, 5, -1 },
- { -1, 4, -14, 48, 105, -18, 5, -1 },
- { -1, 4, -11, 37, 112, -16, 4, -1 },
- { -1, 3, -9, 27, 118, -13, 4, -1 },
- { 0, 2, -6, 18, 122, -10, 3, -1 },
- { 0, 1, -3, 8, 126, -5, 1, 0 },
- }, [FILTER_8TAP_SHARP] = {
- { -1, 3, -7, 127, 8, -3, 1, 0 },
- { -2, 5, -13, 125, 17, -6, 3, -1 },
- { -3, 7, -17, 121, 27, -10, 5, -2 },
- { -4, 9, -20, 115, 37, -13, 6, -2 },
- { -4, 10, -23, 108, 48, -16, 8, -3 },
- { -4, 10, -24, 100, 59, -19, 9, -3 },
- { -4, 11, -24, 90, 70, -21, 10, -4 },
- { -4, 11, -23, 80, 80, -23, 11, -4 },
- { -4, 10, -21, 70, 90, -24, 11, -4 },
- { -3, 9, -19, 59, 100, -24, 10, -4 },
- { -3, 8, -16, 48, 108, -23, 10, -4 },
- { -2, 6, -13, 37, 115, -20, 9, -4 },
- { -2, 5, -10, 27, 121, -17, 7, -3 },
- { -1, 3, -6, 17, 125, -13, 5, -2 },
- { 0, 1, -3, 8, 127, -7, 3, -1 },
- }, [FILTER_8TAP_SMOOTH] = {
- { -3, -1, 32, 64, 38, 1, -3, 0 },
- { -2, -2, 29, 63, 41, 2, -3, 0 },
- { -2, -2, 26, 63, 43, 4, -4, 0 },
- { -2, -3, 24, 62, 46, 5, -4, 0 },
- { -2, -3, 21, 60, 49, 7, -4, 0 },
- { -1, -4, 18, 59, 51, 9, -4, 0 },
- { -1, -4, 16, 57, 53, 12, -4, -1 },
- { -1, -4, 14, 55, 55, 14, -4, -1 },
- { -1, -4, 12, 53, 57, 16, -4, -1 },
- { 0, -4, 9, 51, 59, 18, -4, -1 },
- { 0, -4, 7, 49, 60, 21, -3, -2 },
- { 0, -4, 5, 46, 62, 24, -3, -2 },
- { 0, -4, 4, 43, 63, 26, -2, -2 },
- { 0, -3, 2, 41, 63, 29, -2, -2 },
- { 0, -3, 1, 38, 64, 32, -1, -3 },
- }
-};
-
-#define FILTER_8TAP(src, x, F, stride) \
- av_clip_uint8((F[0] * src[x + -3 * stride] + \
- F[1] * src[x + -2 * stride] + \
- F[2] * src[x + -1 * stride] + \
- F[3] * src[x + +0 * stride] + \
- F[4] * src[x + +1 * stride] + \
- F[5] * src[x + +2 * stride] + \
- F[6] * src[x + +3 * stride] + \
- F[7] * src[x + +4 * stride] + 64) >> 7)
-
-static av_always_inline void do_8tap_1d_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
- int w, int h, ptrdiff_t ds,
- const int8_t *filter, int avg)
-{
- do {
- int x;
-
- for (x = 0; x < w; x++)
- if (avg)
- dst[x] = (dst[x] + FILTER_8TAP(src, x, filter, ds) + 1) >> 1;
- else
- dst[x] = FILTER_8TAP(src, x, filter, ds);
-
- dst += dst_stride;
- src += src_stride;
- } while (--h);
-}
-
-#define filter_8tap_1d_fn(opn, opa, dir, ds) \
-static av_noinline void opn ## _8tap_1d_ ## dir ## _c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int w, int h, \
- const int8_t *filter) \
-{ \
- do_8tap_1d_c(dst, src, dst_stride, src_stride, w, h, ds, filter, opa); \
-}
-
-filter_8tap_1d_fn(put, 0, v, src_stride)
-filter_8tap_1d_fn(put, 0, h, 1)
-filter_8tap_1d_fn(avg, 1, v, src_stride)
-filter_8tap_1d_fn(avg, 1, h, 1)
-
-#undef filter_8tap_1d_fn
-
-static av_always_inline void do_8tap_2d_c(uint8_t *dst, const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
- int w, int h, const int8_t *filterx,
- const int8_t *filtery, int avg)
-{
- int tmp_h = h + 7;
- uint8_t tmp[64 * 71], *tmp_ptr = tmp;
-
- src -= src_stride * 3;
- do {
- int x;
-
- for (x = 0; x < w; x++)
- tmp_ptr[x] = FILTER_8TAP(src, x, filterx, 1);
-
- tmp_ptr += 64;
- src += src_stride;
- } while (--tmp_h);
-
- tmp_ptr = tmp + 64 * 3;
- do {
- int x;
-
- for (x = 0; x < w; x++)
- if (avg)
- dst[x] = (dst[x] + FILTER_8TAP(tmp_ptr, x, filtery, 64) + 1) >> 1;
- else
- dst[x] = FILTER_8TAP(tmp_ptr, x, filtery, 64);
-
- tmp_ptr += 64;
- dst += dst_stride;
- } while (--h);
-}
-
-#define filter_8tap_2d_fn(opn, opa) \
-static av_noinline void opn ## _8tap_2d_hv_c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int w, int h, \
- const int8_t *filterx, \
- const int8_t *filtery) \
-{ \
- do_8tap_2d_c(dst, src, dst_stride, src_stride, \
- w, h, filterx, filtery, opa); \
-}
-
-filter_8tap_2d_fn(put, 0)
-filter_8tap_2d_fn(avg, 1)
-
-#undef filter_8tap_2d_fn
-
-#undef FILTER_8TAP
-
-#define filter_fn_1d(sz, dir, dir_m, type, type_idx, avg) \
-static void \
-avg ## _8tap_ ## type ## _ ## sz ## dir ## _c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my) \
-{ \
- avg ## _8tap_1d_ ## dir ## _c(dst, src, dst_stride, src_stride, sz, h, \
- vp9_subpel_filters[type_idx][dir_m - 1]); \
-}
-
-#define filter_fn_2d(sz, type, type_idx, avg) \
-static void avg ## _8tap_ ## type ## _ ## sz ## hv_c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my) \
-{ \
- avg ## _8tap_2d_hv_c(dst, src, dst_stride, src_stride, sz, h, \
- vp9_subpel_filters[type_idx][mx - 1], \
- vp9_subpel_filters[type_idx][my - 1]); \
-}
-
-#define FILTER_BILIN(src, x, mxy, stride) \
- (src[x] + ((mxy * (src[x + stride] - src[x]) + 8) >> 4))
-
-static av_always_inline void do_bilin_1d_c(uint8_t *dst,
- const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
- int w, int h, ptrdiff_t ds,
- int mxy, int avg)
-{
- do {
- int x;
-
- for (x = 0; x < w; x++)
- if (avg)
- dst[x] = (dst[x] + FILTER_BILIN(src, x, mxy, ds) + 1) >> 1;
- else
- dst[x] = FILTER_BILIN(src, x, mxy, ds);
-
- dst += dst_stride;
- src += src_stride;
- } while (--h);
-}
-
-#define bilin_1d_fn(opn, opa, dir, ds) \
-static av_noinline void opn ## _bilin_1d_ ## dir ## _c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int w, int h, int mxy) \
-{ \
- do_bilin_1d_c(dst, src, dst_stride, src_stride, w, h, ds, mxy, opa); \
-}
-
-bilin_1d_fn(put, 0, v, src_stride)
-bilin_1d_fn(put, 0, h, 1)
-bilin_1d_fn(avg, 1, v, src_stride)
-bilin_1d_fn(avg, 1, h, 1)
-
-#undef bilin_1d_fn
-
-static av_always_inline void do_bilin_2d_c(uint8_t *dst,
- const uint8_t *src,
- ptrdiff_t dst_stride,
- ptrdiff_t src_stride,
- int w, int h, int mx, int my,
- int avg)
-{
- uint8_t tmp[64 * 65], *tmp_ptr = tmp;
- int tmp_h = h + 1;
-
- do {
- int x;
-
- for (x = 0; x < w; x++)
- tmp_ptr[x] = FILTER_BILIN(src, x, mx, 1);
-
- tmp_ptr += 64;
- src += src_stride;
- } while (--tmp_h);
-
- tmp_ptr = tmp;
- do {
- int x;
-
- for (x = 0; x < w; x++)
- if (avg)
- dst[x] = (dst[x] + FILTER_BILIN(tmp_ptr, x, my, 64) + 1) >> 1;
- else
- dst[x] = FILTER_BILIN(tmp_ptr, x, my, 64);
-
- tmp_ptr += 64;
- dst += dst_stride;
- } while (--h);
-}
-
-#define bilin_2d_fn(opn, opa) \
-static av_noinline void opn ## _bilin_2d_hv_c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int w, int h, \
- int mx, int my) \
-{ \
- do_bilin_2d_c(dst, src, dst_stride, src_stride, w, h, mx, my, opa); \
-}
-
-bilin_2d_fn(put, 0)
-bilin_2d_fn(avg, 1)
-
-#undef bilin_2d_fn
-
-#undef FILTER_BILIN
-
-#define bilinf_fn_1d(sz, dir, dir_m, avg) \
-static void avg ## _bilin_ ## sz ## dir ## _c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my) \
-{ \
- avg ## _bilin_1d_ ## dir ## _c(dst, src, dst_stride, src_stride, \
- sz, h, dir_m); \
-}
-
-#define bilinf_fn_2d(sz, avg) \
-static void avg ## _bilin_ ## sz ## hv_c(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my) \
-{ \
- avg ## _bilin_2d_hv_c(dst, src, dst_stride, src_stride, \
- sz, h, mx, my); \
-}
-
-#define filter_fn(sz, avg) \
- filter_fn_1d(sz, h, mx, regular, FILTER_8TAP_REGULAR, avg) \
- filter_fn_1d(sz, v, my, regular, FILTER_8TAP_REGULAR, avg) \
- filter_fn_2d(sz, regular, FILTER_8TAP_REGULAR, avg) \
- filter_fn_1d(sz, h, mx, smooth, FILTER_8TAP_SMOOTH, avg) \
- filter_fn_1d(sz, v, my, smooth, FILTER_8TAP_SMOOTH, avg) \
- filter_fn_2d(sz, smooth, FILTER_8TAP_SMOOTH, avg) \
- filter_fn_1d(sz, h, mx, sharp, FILTER_8TAP_SHARP, avg) \
- filter_fn_1d(sz, v, my, sharp, FILTER_8TAP_SHARP, avg) \
- filter_fn_2d(sz, sharp, FILTER_8TAP_SHARP, avg) \
- bilinf_fn_1d(sz, h, mx, avg) \
- bilinf_fn_1d(sz, v, my, avg) \
- bilinf_fn_2d(sz, avg)
-
-#define filter_fn_set(avg) \
- filter_fn(64, avg) \
- filter_fn(32, avg) \
- filter_fn(16, avg) \
- filter_fn(8, avg) \
- filter_fn(4, avg)
-
-filter_fn_set(put)
-filter_fn_set(avg)
-
-#undef filter_fn
-#undef filter_fn_set
-#undef filter_fn_1d
-#undef filter_fn_2d
-#undef bilinf_fn_1d
-#undef bilinf_fn_2d
-
-static av_cold void vp9dsp_mc_init(VP9DSPContext *dsp)
-{
-#define init_fpel(idx1, idx2, sz, type) \
- dsp->mc[idx1][FILTER_8TAP_SMOOTH][idx2][0][0] = type ## sz ## _c; \
- dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = type ## sz ## _c; \
- dsp->mc[idx1][FILTER_8TAP_SHARP][idx2][0][0] = type ## sz ## _c; \
- dsp->mc[idx1][FILTER_BILINEAR][idx2][0][0] = type ## sz ## _c
-
-#define init_copy_avg(idx, sz) \
- init_fpel(idx, 0, sz, copy); \
- init_fpel(idx, 1, sz, avg)
-
- init_copy_avg(0, 64);
- init_copy_avg(1, 32);
- init_copy_avg(2, 16);
- init_copy_avg(3, 8);
- init_copy_avg(4, 4);
-
-#undef init_copy_avg
-#undef init_fpel
-
-#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type) \
- dsp->mc[idx1][FILTER_8TAP_SMOOTH][idx2][idxh][idxv] = type ## _8tap_smooth_ ## sz ## dir ## _c; \
- dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type ## _8tap_regular_ ## sz ## dir ## _c; \
- dsp->mc[idx1][FILTER_8TAP_SHARP][idx2][idxh][idxv] = type ## _8tap_sharp_ ## sz ## dir ## _c; \
- dsp->mc[idx1][FILTER_BILINEAR][idx2][idxh][idxv] = type ## _bilin_ ## sz ## dir ## _c
-
-#define init_subpel2(idx, idxh, idxv, dir, type) \
- init_subpel1(0, idx, idxh, idxv, 64, dir, type); \
- init_subpel1(1, idx, idxh, idxv, 32, dir, type); \
- init_subpel1(2, idx, idxh, idxv, 16, dir, type); \
- init_subpel1(3, idx, idxh, idxv, 8, dir, type); \
- init_subpel1(4, idx, idxh, idxv, 4, dir, type)
-
-#define init_subpel3(idx, type) \
- init_subpel2(idx, 1, 1, hv, type); \
- init_subpel2(idx, 0, 1, v, type); \
- init_subpel2(idx, 1, 0, h, type)
-
- init_subpel3(0, put);
- init_subpel3(1, avg);
-
-#undef init_subpel1
-#undef init_subpel2
-#undef init_subpel3
-}
-
-av_cold void ff_vp9dsp_init(VP9DSPContext *dsp)
-{
- vp9dsp_intrapred_init(dsp);
- vp9dsp_itxfm_init(dsp);
- vp9dsp_loopfilter_init(dsp);
- vp9dsp_mc_init(dsp);
-
- if (ARCH_X86)
- ff_vp9dsp_init_x86(dsp);
+ if (ARCH_X86) ff_vp9dsp_init_x86(dsp, bpp);
}
diff --git a/libavcodec/vp9dsp.h b/libavcodec/vp9dsp.h
new file mode 100644
index 0000000000..beb8926353
--- /dev/null
+++ b/libavcodec/vp9dsp.h
@@ -0,0 +1,131 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_VP9DSP_H
+#define AVCODEC_VP9DSP_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "vp9.h"
+
+typedef void (*vp9_mc_func)(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *ref, ptrdiff_t ref_stride,
+ int h, int mx, int my);
+typedef void (*vp9_scaled_mc_func)(uint8_t *dst, ptrdiff_t dst_stride,
+ const uint8_t *ref, ptrdiff_t ref_stride,
+ int h, int mx, int my, int dx, int dy);
+
+typedef struct VP9DSPContext {
+ /*
+ * dimension 1: 0=4x4, 1=8x8, 2=16x16, 3=32x32
+ * dimension 2: intra prediction modes
+ *
+ * dst/left/top is aligned by transform-size (i.e. 4, 8, 16 or 32 pixels)
+ * stride is aligned by 16 pixels
+ * top[-1] is top/left; top[4,7] is top-right for 4x4
+ */
+ // FIXME(rbultje) maybe replace left/top pointers with HAVE_TOP/
+ // HAVE_LEFT/HAVE_TOPRIGHT flags instead, and then handle it in-place?
+ // also needs to fit in with what h264/vp8/etc do
+ void (*intra_pred[N_TXFM_SIZES][N_INTRA_PRED_MODES])(uint8_t *dst,
+ ptrdiff_t stride,
+ const uint8_t *left,
+ const uint8_t *top);
+
+ /*
+ * dimension 1: 0=4x4, 1=8x8, 2=16x16, 3=32x32, 4=lossless (3-4=dct only)
+ * dimension 2: 0=dct/dct, 1=dct/adst, 2=adst/dct, 3=adst/adst
+ *
+ * dst is aligned by transform-size (i.e. 4, 8, 16 or 32 pixels)
+ * stride is aligned by 16 pixels
+ * block is 16-byte aligned
+ * eob indicates the position (+1) of the last non-zero coefficient,
+ * in scan-order. This can be used to write faster versions, e.g. a
+ * dc-only 4x4/8x8/16x16/32x32, or a 4x4-only (eob<10) 8x8/16x16/32x32,
+ * etc.
+ */
+ // FIXME also write idct_add_block() versions for whole (inter) pred
+ // blocks, so we can do 2 4x4s at once
+ void (*itxfm_add[N_TXFM_SIZES + 1][N_TXFM_TYPES])(uint8_t *dst,
+ ptrdiff_t stride,
+ int16_t *block, int eob);
+
+ /*
+ * dimension 1: width of filter (0=4, 1=8, 2=16)
+ * dimension 2: 0=col-edge filter (h), 1=row-edge filter (v)
+ *
+ * dst/stride are aligned by 8
+ */
+ void (*loop_filter_8[3][2])(uint8_t *dst, ptrdiff_t stride,
+ int mb_lim, int lim, int hev_thr);
+
+ /*
+ * dimension 1: 0=col-edge filter (h), 1=row-edge filter (v)
+ *
+ * The width of filter is assumed to be 16; dst/stride are aligned by 16
+ */
+ void (*loop_filter_16[2])(uint8_t *dst, ptrdiff_t stride,
+ int mb_lim, int lim, int hev_thr);
+
+ /*
+ * dimension 1/2: width of filter (0=4, 1=8) for each filter half
+ * dimension 3: 0=col-edge filter (h), 1=row-edge filter (v)
+ *
+ * dst/stride are aligned by operation size
+ * this basically calls loop_filter[d1][d3][0](), followed by
+ * loop_filter[d2][d3][0]() on the next 8 pixels
+ * mb_lim/lim/hev_thr contain two values in the lowest two bytes of the
+ * integer.
+ */
+ // FIXME perhaps a mix4 that operates on 32px (for AVX2)
+ void (*loop_filter_mix2[2][2][2])(uint8_t *dst, ptrdiff_t stride,
+ int mb_lim, int lim, int hev_thr);
+
+ /*
+ * dimension 1: hsize (0: 64, 1: 32, 2: 16, 3: 8, 4: 4)
+ * dimension 2: filter type (0: smooth, 1: regular, 2: sharp, 3: bilin)
+ * dimension 3: averaging type (0: put, 1: avg)
+ * dimension 4: x subpel interpolation (0: none, 1: 8tap/bilin)
+ * dimension 5: y subpel interpolation (0: none, 1: 8tap/bilin)
+ *
+ * dst/stride are aligned by hsize
+ */
+ vp9_mc_func mc[5][4][2][2][2];
+
+ /*
+ * for scalable MC, first 3 dimensions identical to above, the other two
+ * don't exist since it changes per stepsize.
+ */
+ vp9_scaled_mc_func smc[5][4][2];
+} VP9DSPContext;
+
+void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp);
+
+void ff_vp9dsp_init_8(VP9DSPContext *dsp);
+void ff_vp9dsp_init_10(VP9DSPContext *dsp);
+void ff_vp9dsp_init_12(VP9DSPContext *dsp);
+
+void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp);
+
+#endif /* AVCODEC_VP9DSP_H */
diff --git a/libavcodec/vp9dsp_10bpp.c b/libavcodec/vp9dsp_10bpp.c
new file mode 100644
index 0000000000..62ce182070
--- /dev/null
+++ b/libavcodec/vp9dsp_10bpp.c
@@ -0,0 +1,26 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 BIT_DEPTH 10
+#define dctint int64_t
+#include "vp9dsp_template.c"
diff --git a/libavcodec/vp9dsp_12bpp.c b/libavcodec/vp9dsp_12bpp.c
new file mode 100644
index 0000000000..2f36471c5b
--- /dev/null
+++ b/libavcodec/vp9dsp_12bpp.c
@@ -0,0 +1,26 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 BIT_DEPTH 12
+#define dctint int64_t
+#include "vp9dsp_template.c"
diff --git a/libavcodec/vp9dsp_8bpp.c b/libavcodec/vp9dsp_8bpp.c
new file mode 100644
index 0000000000..4b219b06b0
--- /dev/null
+++ b/libavcodec/vp9dsp_8bpp.c
@@ -0,0 +1,26 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 BIT_DEPTH 8
+#define dctint int
+#include "vp9dsp_template.c"
diff --git a/libavcodec/vp9dsp_template.c b/libavcodec/vp9dsp_template.c
new file mode 100644
index 0000000000..8f10ccf893
--- /dev/null
+++ b/libavcodec/vp9dsp_template.c
@@ -0,0 +1,2601 @@
+/*
+ * VP9 compatible video decoder
+ *
+ * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
+ * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "bit_depth_template.c"
+#include "vp9dsp.h"
+
+#if BIT_DEPTH != 12
+
+// 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,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 p4 = AV_RN4PA(top);
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, p4);
+ AV_WN4PA(dst + stride * 1, p4);
+ AV_WN4PA(dst + stride * 2, p4);
+ AV_WN4PA(dst + stride * 3, p4);
+}
+
+static void vert_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 p4a = AV_RN4PA(top + 0);
+ pixel4 p4b = AV_RN4PA(top + 4);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, p4a);
+ AV_WN4PA(dst + 4, p4b);
+ dst += stride;
+ }
+}
+
+static void vert_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 p4a = AV_RN4PA(top + 0);
+ pixel4 p4b = AV_RN4PA(top + 4);
+ pixel4 p4c = AV_RN4PA(top + 8);
+ pixel4 p4d = AV_RN4PA(top + 12);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, p4a);
+ AV_WN4PA(dst + 4, p4b);
+ AV_WN4PA(dst + 8, p4c);
+ AV_WN4PA(dst + 12, p4d);
+ dst += stride;
+ }
+}
+
+static void vert_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 p4a = AV_RN4PA(top + 0);
+ pixel4 p4b = AV_RN4PA(top + 4);
+ pixel4 p4c = AV_RN4PA(top + 8);
+ pixel4 p4d = AV_RN4PA(top + 12);
+ pixel4 p4e = AV_RN4PA(top + 16);
+ pixel4 p4f = AV_RN4PA(top + 20);
+ pixel4 p4g = AV_RN4PA(top + 24);
+ pixel4 p4h = AV_RN4PA(top + 28);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, p4a);
+ AV_WN4PA(dst + 4, p4b);
+ AV_WN4PA(dst + 8, p4c);
+ AV_WN4PA(dst + 12, p4d);
+ AV_WN4PA(dst + 16, p4e);
+ AV_WN4PA(dst + 20, p4f);
+ AV_WN4PA(dst + 24, p4g);
+ AV_WN4PA(dst + 28, p4h);
+ dst += stride;
+ }
+}
+
+static void hor_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, PIXEL_SPLAT_X4(left[3]));
+ AV_WN4PA(dst + stride * 1, PIXEL_SPLAT_X4(left[2]));
+ AV_WN4PA(dst + stride * 2, PIXEL_SPLAT_X4(left[1]));
+ AV_WN4PA(dst + stride * 3, PIXEL_SPLAT_X4(left[0]));
+}
+
+static void hor_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ pixel4 p4 = PIXEL_SPLAT_X4(left[7 - y]);
+
+ AV_WN4PA(dst + 0, p4);
+ AV_WN4PA(dst + 4, p4);
+ dst += stride;
+ }
+}
+
+static void hor_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ pixel4 p4 = PIXEL_SPLAT_X4(left[15 - y]);
+
+ AV_WN4PA(dst + 0, p4);
+ AV_WN4PA(dst + 4, p4);
+ AV_WN4PA(dst + 8, p4);
+ AV_WN4PA(dst + 12, p4);
+ dst += stride;
+ }
+}
+
+static void hor_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ pixel4 p4 = PIXEL_SPLAT_X4(left[31 - y]);
+
+ AV_WN4PA(dst + 0, p4);
+ AV_WN4PA(dst + 4, p4);
+ AV_WN4PA(dst + 8, p4);
+ AV_WN4PA(dst + 12, p4);
+ AV_WN4PA(dst + 16, p4);
+ AV_WN4PA(dst + 20, p4);
+ AV_WN4PA(dst + 24, p4);
+ AV_WN4PA(dst + 28, p4);
+ dst += stride;
+ }
+}
+
+#endif /* BIT_DEPTH != 12 */
+
+static void tm_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ int y, tl = top[-1];
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 4; y++) {
+ int l_m_tl = left[3 - y] - tl;
+
+ dst[0] = av_clip_pixel(top[0] + l_m_tl);
+ dst[1] = av_clip_pixel(top[1] + l_m_tl);
+ dst[2] = av_clip_pixel(top[2] + l_m_tl);
+ dst[3] = av_clip_pixel(top[3] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void tm_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ int y, tl = top[-1];
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ int l_m_tl = left[7 - y] - tl;
+
+ dst[0] = av_clip_pixel(top[0] + l_m_tl);
+ dst[1] = av_clip_pixel(top[1] + l_m_tl);
+ dst[2] = av_clip_pixel(top[2] + l_m_tl);
+ dst[3] = av_clip_pixel(top[3] + l_m_tl);
+ dst[4] = av_clip_pixel(top[4] + l_m_tl);
+ dst[5] = av_clip_pixel(top[5] + l_m_tl);
+ dst[6] = av_clip_pixel(top[6] + l_m_tl);
+ dst[7] = av_clip_pixel(top[7] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void tm_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ int y, tl = top[-1];
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ int l_m_tl = left[15 - y] - tl;
+
+ dst[ 0] = av_clip_pixel(top[ 0] + l_m_tl);
+ dst[ 1] = av_clip_pixel(top[ 1] + l_m_tl);
+ dst[ 2] = av_clip_pixel(top[ 2] + l_m_tl);
+ dst[ 3] = av_clip_pixel(top[ 3] + l_m_tl);
+ dst[ 4] = av_clip_pixel(top[ 4] + l_m_tl);
+ dst[ 5] = av_clip_pixel(top[ 5] + l_m_tl);
+ dst[ 6] = av_clip_pixel(top[ 6] + l_m_tl);
+ dst[ 7] = av_clip_pixel(top[ 7] + l_m_tl);
+ dst[ 8] = av_clip_pixel(top[ 8] + l_m_tl);
+ dst[ 9] = av_clip_pixel(top[ 9] + l_m_tl);
+ dst[10] = av_clip_pixel(top[10] + l_m_tl);
+ dst[11] = av_clip_pixel(top[11] + l_m_tl);
+ dst[12] = av_clip_pixel(top[12] + l_m_tl);
+ dst[13] = av_clip_pixel(top[13] + l_m_tl);
+ dst[14] = av_clip_pixel(top[14] + l_m_tl);
+ dst[15] = av_clip_pixel(top[15] + l_m_tl);
+ dst += stride;
+ }
+}
+
+static void tm_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ int y, tl = top[-1];
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ int l_m_tl = left[31 - y] - tl;
+
+ dst[ 0] = av_clip_pixel(top[ 0] + l_m_tl);
+ dst[ 1] = av_clip_pixel(top[ 1] + l_m_tl);
+ dst[ 2] = av_clip_pixel(top[ 2] + l_m_tl);
+ dst[ 3] = av_clip_pixel(top[ 3] + l_m_tl);
+ dst[ 4] = av_clip_pixel(top[ 4] + l_m_tl);
+ dst[ 5] = av_clip_pixel(top[ 5] + l_m_tl);
+ dst[ 6] = av_clip_pixel(top[ 6] + l_m_tl);
+ dst[ 7] = av_clip_pixel(top[ 7] + l_m_tl);
+ dst[ 8] = av_clip_pixel(top[ 8] + l_m_tl);
+ dst[ 9] = av_clip_pixel(top[ 9] + l_m_tl);
+ dst[10] = av_clip_pixel(top[10] + l_m_tl);
+ dst[11] = av_clip_pixel(top[11] + l_m_tl);
+ dst[12] = av_clip_pixel(top[12] + l_m_tl);
+ dst[13] = av_clip_pixel(top[13] + l_m_tl);
+ dst[14] = av_clip_pixel(top[14] + l_m_tl);
+ dst[15] = av_clip_pixel(top[15] + l_m_tl);
+ dst[16] = av_clip_pixel(top[16] + l_m_tl);
+ dst[17] = av_clip_pixel(top[17] + l_m_tl);
+ dst[18] = av_clip_pixel(top[18] + l_m_tl);
+ dst[19] = av_clip_pixel(top[19] + l_m_tl);
+ dst[20] = av_clip_pixel(top[20] + l_m_tl);
+ dst[21] = av_clip_pixel(top[21] + l_m_tl);
+ dst[22] = av_clip_pixel(top[22] + l_m_tl);
+ dst[23] = av_clip_pixel(top[23] + l_m_tl);
+ dst[24] = av_clip_pixel(top[24] + l_m_tl);
+ dst[25] = av_clip_pixel(top[25] + l_m_tl);
+ dst[26] = av_clip_pixel(top[26] + l_m_tl);
+ dst[27] = av_clip_pixel(top[27] + l_m_tl);
+ dst[28] = av_clip_pixel(top[28] + l_m_tl);
+ dst[29] = av_clip_pixel(top[29] + l_m_tl);
+ dst[30] = av_clip_pixel(top[30] + l_m_tl);
+ dst[31] = av_clip_pixel(top[31] + l_m_tl);
+ dst += stride;
+ }
+}
+
+#if BIT_DEPTH != 12
+
+static void dc_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4((left[0] + left[1] + left[2] + left[3] +
+ top[0] + top[1] + top[2] + top[3] + 4) >> 3);
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, dc);
+ AV_WN4PA(dst + stride * 1, dc);
+ AV_WN4PA(dst + stride * 2, dc);
+ AV_WN4PA(dst + stride * 3, dc);
+}
+
+static void dc_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] +
+ left[6] + left[7] + top[0] + top[1] + top[2] + top[3] +
+ top[4] + top[5] + top[6] + top[7] + 8) >> 4);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ dst += stride;
+ }
+}
+
+static void dc_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] + left[6] +
+ left[7] + left[8] + left[9] + left[10] + left[11] + left[12] +
+ left[13] + left[14] + left[15] + top[0] + top[1] + top[2] + top[3] +
+ top[4] + top[5] + top[6] + top[7] + top[8] + top[9] + top[10] +
+ top[11] + top[12] + top[13] + top[14] + top[15] + 16) >> 5);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ AV_WN4PA(dst + 8, dc);
+ AV_WN4PA(dst + 12, dc);
+ dst += stride;
+ }
+}
+
+static void dc_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] + left[6] +
+ left[7] + left[8] + left[9] + left[10] + left[11] + left[12] +
+ left[13] + left[14] + left[15] + left[16] + left[17] + left[18] +
+ left[19] + left[20] + left[21] + left[22] + left[23] + left[24] +
+ left[25] + left[26] + left[27] + left[28] + left[29] + left[30] +
+ left[31] + top[0] + top[1] + top[2] + top[3] + top[4] + top[5] +
+ top[6] + top[7] + top[8] + top[9] + top[10] + top[11] + top[12] +
+ top[13] + top[14] + top[15] + top[16] + top[17] + top[18] + top[19] +
+ top[20] + top[21] + top[22] + top[23] + top[24] + top[25] + top[26] +
+ top[27] + top[28] + top[29] + top[30] + top[31] + 32) >> 6);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ AV_WN4PA(dst + 8, dc);
+ AV_WN4PA(dst + 12, dc);
+ AV_WN4PA(dst + 16, dc);
+ AV_WN4PA(dst + 20, dc);
+ AV_WN4PA(dst + 24, dc);
+ AV_WN4PA(dst + 28, dc);
+ dst += stride;
+ }
+}
+
+static void dc_left_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ pixel4 dc = PIXEL_SPLAT_X4((left[0] + left[1] + left[2] + left[3] + 2) >> 2);
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, dc);
+ AV_WN4PA(dst + stride * 1, dc);
+ AV_WN4PA(dst + stride * 2, dc);
+ AV_WN4PA(dst + stride * 3, dc);
+}
+
+static void dc_left_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((left[0] + left[1] + left[2] + left[3] +
+ left[4] + left[5] + left[6] + left[7] + 4) >> 3);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ dst += stride;
+ }
+}
+
+static void dc_left_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] +
+ left[6] + left[7] + left[8] + left[9] + left[10] + left[11] +
+ left[12] + left[13] + left[14] + left[15] + 8) >> 4);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ AV_WN4PA(dst + 8, dc);
+ AV_WN4PA(dst + 12, dc);
+ dst += stride;
+ }
+}
+
+static void dc_left_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((left[0] + left[1] + left[2] + left[3] + left[4] + left[5] +
+ left[6] + left[7] + left[8] + left[9] + left[10] + left[11] +
+ left[12] + left[13] + left[14] + left[15] + left[16] + left[17] +
+ left[18] + left[19] + left[20] + left[21] + left[22] + left[23] +
+ left[24] + left[25] + left[26] + left[27] + left[28] + left[29] +
+ left[30] + left[31] + 16) >> 5);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ AV_WN4PA(dst + 8, dc);
+ AV_WN4PA(dst + 12, dc);
+ AV_WN4PA(dst + 16, dc);
+ AV_WN4PA(dst + 20, dc);
+ AV_WN4PA(dst + 24, dc);
+ AV_WN4PA(dst + 28, dc);
+ dst += stride;
+ }
+}
+
+static void dc_top_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4((top[0] + top[1] + top[2] + top[3] + 2) >> 2);
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, dc);
+ AV_WN4PA(dst + stride * 1, dc);
+ AV_WN4PA(dst + stride * 2, dc);
+ AV_WN4PA(dst + stride * 3, dc);
+}
+
+static void dc_top_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((top[0] + top[1] + top[2] + top[3] +
+ top[4] + top[5] + top[6] + top[7] + 4) >> 3);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ dst += stride;
+ }
+}
+
+static void dc_top_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((top[0] + top[1] + top[2] + top[3] + top[4] + top[5] +
+ top[6] + top[7] + top[8] + top[9] + top[10] + top[11] +
+ top[12] + top[13] + top[14] + top[15] + 8) >> 4);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ AV_WN4PA(dst + 8, dc);
+ AV_WN4PA(dst + 12, dc);
+ dst += stride;
+ }
+}
+
+static void dc_top_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ pixel4 dc = PIXEL_SPLAT_X4
+ ((top[0] + top[1] + top[2] + top[3] + top[4] + top[5] +
+ top[6] + top[7] + top[8] + top[9] + top[10] + top[11] +
+ top[12] + top[13] + top[14] + top[15] + top[16] + top[17] +
+ top[18] + top[19] + top[20] + top[21] + top[22] + top[23] +
+ top[24] + top[25] + top[26] + top[27] + top[28] + top[29] +
+ top[30] + top[31] + 16) >> 5);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, dc);
+ AV_WN4PA(dst + 4, dc);
+ AV_WN4PA(dst + 8, dc);
+ AV_WN4PA(dst + 12, dc);
+ AV_WN4PA(dst + 16, dc);
+ AV_WN4PA(dst + 20, dc);
+ AV_WN4PA(dst + 24, dc);
+ AV_WN4PA(dst + 28, dc);
+ dst += stride;
+ }
+}
+
+#endif /* BIT_DEPTH != 12 */
+
+static void dc_128_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4(128 << (BIT_DEPTH - 8));
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, val);
+ AV_WN4PA(dst + stride * 1, val);
+ AV_WN4PA(dst + stride * 2, val);
+ AV_WN4PA(dst + stride * 3, val);
+}
+
+static void dc_128_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4(128 << (BIT_DEPTH - 8));
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ dst += stride;
+ }
+}
+
+static void dc_128_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4(128 << (BIT_DEPTH - 8));
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ AV_WN4PA(dst + 8, val);
+ AV_WN4PA(dst + 12, val);
+ dst += stride;
+ }
+}
+
+static void dc_128_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4(128 << (BIT_DEPTH - 8));
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ AV_WN4PA(dst + 8, val);
+ AV_WN4PA(dst + 12, val);
+ AV_WN4PA(dst + 16, val);
+ AV_WN4PA(dst + 20, val);
+ AV_WN4PA(dst + 24, val);
+ AV_WN4PA(dst + 28, val);
+ dst += stride;
+ }
+}
+
+static void dc_127_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) - 1);
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, val);
+ AV_WN4PA(dst + stride * 1, val);
+ AV_WN4PA(dst + stride * 2, val);
+ AV_WN4PA(dst + stride * 3, val);}
+
+static void dc_127_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) - 1);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ dst += stride;
+ }
+}
+
+static void dc_127_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) - 1);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ AV_WN4PA(dst + 8, val);
+ AV_WN4PA(dst + 12, val);
+ dst += stride;
+ }
+}
+
+static void dc_127_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) - 1);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ AV_WN4PA(dst + 8, val);
+ AV_WN4PA(dst + 12, val);
+ AV_WN4PA(dst + 16, val);
+ AV_WN4PA(dst + 20, val);
+ AV_WN4PA(dst + 24, val);
+ AV_WN4PA(dst + 28, val);
+ dst += stride;
+ }
+}
+
+static void dc_129_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) + 1);
+
+ stride /= sizeof(pixel);
+ AV_WN4PA(dst + stride * 0, val);
+ AV_WN4PA(dst + stride * 1, val);
+ AV_WN4PA(dst + stride * 2, val);
+ AV_WN4PA(dst + stride * 3, val);
+}
+
+static void dc_129_8x8_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) + 1);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 8; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ dst += stride;
+ }
+}
+
+static void dc_129_16x16_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) + 1);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 16; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ AV_WN4PA(dst + 8, val);
+ AV_WN4PA(dst + 12, val);
+ dst += stride;
+ }
+}
+
+static void dc_129_32x32_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ pixel4 val = PIXEL_SPLAT_X4((128 << (BIT_DEPTH - 8)) + 1);
+ int y;
+
+ stride /= sizeof(pixel);
+ for (y = 0; y < 32; y++) {
+ AV_WN4PA(dst + 0, val);
+ AV_WN4PA(dst + 4, val);
+ AV_WN4PA(dst + 8, val);
+ AV_WN4PA(dst + 12, val);
+ AV_WN4PA(dst + 16, val);
+ AV_WN4PA(dst + 20, val);
+ AV_WN4PA(dst + 24, val);
+ AV_WN4PA(dst + 28, val);
+ dst += stride;
+ }
+}
+
+#if BIT_DEPTH != 12
+
+#if BIT_DEPTH == 8
+#define memset_bpc memset
+#else
+static inline void memset_bpc(uint16_t *dst, int val, int len) {
+ int n;
+ for (n = 0; n < len; n++) {
+ dst[n] = val;
+ }
+}
+#endif
+
+#define DST(x, y) dst[(x) + (y) * stride]
+
+static void diag_downleft_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ int a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ a4 = top[4], a5 = top[5], a6 = top[6], a7 = top[7];
+
+ stride /= sizeof(pixel);
+ DST(0,0) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(1,0) = DST(0,1) = (a1 + a2 * 2 + a3 + 2) >> 2;
+ DST(2,0) = DST(1,1) = DST(0,2) = (a2 + a3 * 2 + a4 + 2) >> 2;
+ DST(3,0) = DST(2,1) = DST(1,2) = DST(0,3) = (a3 + a4 * 2 + a5 + 2) >> 2;
+ DST(3,1) = DST(2,2) = DST(1,3) = (a4 + a5 * 2 + a6 + 2) >> 2;
+ DST(3,2) = DST(2,3) = (a5 + a6 * 2 + a7 + 2) >> 2;
+ DST(3,3) = a7; // note: this is different from vp8 and such
+}
+
+#define def_diag_downleft(size) \
+static void diag_downleft_##size##x##size##_c(uint8_t *_dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *_top) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ const pixel *top = (const pixel *) _top; \
+ int i, j; \
+ pixel v[size - 1]; \
+\
+ stride /= sizeof(pixel); \
+ for (i = 0; i < size - 2; i++) \
+ v[i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
+ v[size - 2] = (top[size - 2] + top[size - 1] * 3 + 2) >> 2; \
+\
+ for (j = 0; j < size; j++) { \
+ memcpy(dst + j*stride, v + j, (size - 1 - j) * sizeof(pixel)); \
+ memset_bpc(dst + j*stride + size - 1 - j, top[size - 1], j + 1); \
+ } \
+}
+
+def_diag_downleft(8)
+def_diag_downleft(16)
+def_diag_downleft(32)
+
+static void diag_downright_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ const pixel *left = (const pixel *) _left;
+ int tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ l0 = left[3], l1 = left[2], l2 = left[1], l3 = left[0];
+
+ stride /= sizeof(pixel);
+ DST(0,3) = (l1 + l2 * 2 + l3 + 2) >> 2;
+ DST(0,2) = DST(1,3) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,1) = DST(1,2) = DST(2,3) = (tl + l0 * 2 + l1 + 2) >> 2;
+ DST(0,0) = DST(1,1) = DST(2,2) = DST(3,3) = (l0 + tl * 2 + a0 + 2) >> 2;
+ DST(1,0) = DST(2,1) = DST(3,2) = (tl + a0 * 2 + a1 + 2) >> 2;
+ DST(2,0) = DST(3,1) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(3,0) = (a1 + a2 * 2 + a3 + 2) >> 2;
+}
+
+#define def_diag_downright(size) \
+static void diag_downright_##size##x##size##_c(uint8_t *_dst, ptrdiff_t stride, \
+ const uint8_t *_left, const uint8_t *_top) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ const pixel *top = (const pixel *) _top; \
+ const pixel *left = (const pixel *) _left; \
+ int i, j; \
+ pixel v[size + size - 1]; \
+\
+ stride /= sizeof(pixel); \
+ for (i = 0; i < size - 2; i++) { \
+ v[i ] = (left[i] + left[i + 1] * 2 + left[i + 2] + 2) >> 2; \
+ v[size + 1 + i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
+ } \
+ v[size - 2] = (left[size - 2] + left[size - 1] * 2 + top[-1] + 2) >> 2; \
+ v[size - 1] = (left[size - 1] + top[-1] * 2 + top[ 0] + 2) >> 2; \
+ v[size ] = (top[-1] + top[0] * 2 + top[ 1] + 2) >> 2; \
+\
+ for (j = 0; j < size; j++) \
+ memcpy(dst + j*stride, v + size - 1 - j, size * sizeof(pixel)); \
+}
+
+def_diag_downright(8)
+def_diag_downright(16)
+def_diag_downright(32)
+
+static void vert_right_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ const pixel *left = (const pixel *) _left;
+ int tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ l0 = left[3], l1 = left[2], l2 = left[1];
+
+ stride /= sizeof(pixel);
+ DST(0,3) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,2) = (tl + l0 * 2 + l1 + 2) >> 2;
+ DST(0,0) = DST(1,2) = (tl + a0 + 1) >> 1;
+ DST(0,1) = DST(1,3) = (l0 + tl * 2 + a0 + 2) >> 2;
+ DST(1,0) = DST(2,2) = (a0 + a1 + 1) >> 1;
+ DST(1,1) = DST(2,3) = (tl + a0 * 2 + a1 + 2) >> 2;
+ DST(2,0) = DST(3,2) = (a1 + a2 + 1) >> 1;
+ DST(2,1) = DST(3,3) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(3,0) = (a2 + a3 + 1) >> 1;
+ DST(3,1) = (a1 + a2 * 2 + a3 + 2) >> 2;
+}
+
+#define def_vert_right(size) \
+static void vert_right_##size##x##size##_c(uint8_t *_dst, ptrdiff_t stride, \
+ const uint8_t *_left, const uint8_t *_top) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ const pixel *top = (const pixel *) _top; \
+ const pixel *left = (const pixel *) _left; \
+ int i, j; \
+ pixel ve[size + size/2 - 1], vo[size + size/2 - 1]; \
+\
+ stride /= sizeof(pixel); \
+ for (i = 0; i < size/2 - 2; i++) { \
+ vo[i] = (left[i*2 + 3] + left[i*2 + 2] * 2 + left[i*2 + 1] + 2) >> 2; \
+ ve[i] = (left[i*2 + 4] + left[i*2 + 3] * 2 + left[i*2 + 2] + 2) >> 2; \
+ } \
+ vo[size/2 - 2] = (left[size - 1] + left[size - 2] * 2 + left[size - 3] + 2) >> 2; \
+ ve[size/2 - 2] = (top[-1] + left[size - 1] * 2 + left[size - 2] + 2) >> 2; \
+\
+ ve[size/2 - 1] = (top[-1] + top[0] + 1) >> 1; \
+ vo[size/2 - 1] = (left[size - 1] + top[-1] * 2 + top[0] + 2) >> 2; \
+ for (i = 0; i < size - 1; i++) { \
+ ve[size/2 + i] = (top[i] + top[i + 1] + 1) >> 1; \
+ vo[size/2 + i] = (top[i - 1] + top[i] * 2 + top[i + 1] + 2) >> 2; \
+ } \
+\
+ for (j = 0; j < size / 2; j++) { \
+ memcpy(dst + j*2 *stride, ve + size/2 - 1 - j, size * sizeof(pixel)); \
+ memcpy(dst + (j*2 + 1)*stride, vo + size/2 - 1 - j, size * sizeof(pixel)); \
+ } \
+}
+
+def_vert_right(8)
+def_vert_right(16)
+def_vert_right(32)
+
+static void hor_down_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ const pixel *left = (const pixel *) _left;
+ int l0 = left[3], l1 = left[2], l2 = left[1], l3 = left[0],
+ tl = top[-1], a0 = top[0], a1 = top[1], a2 = top[2];
+
+ stride /= sizeof(pixel);
+ DST(2,0) = (tl + a0 * 2 + a1 + 2) >> 2;
+ DST(3,0) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(0,0) = DST(2,1) = (tl + l0 + 1) >> 1;
+ DST(1,0) = DST(3,1) = (a0 + tl * 2 + l0 + 2) >> 2;
+ DST(0,1) = DST(2,2) = (l0 + l1 + 1) >> 1;
+ DST(1,1) = DST(3,2) = (tl + l0 * 2 + l1 + 2) >> 2;
+ DST(0,2) = DST(2,3) = (l1 + l2 + 1) >> 1;
+ DST(1,2) = DST(3,3) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,3) = (l2 + l3 + 1) >> 1;
+ DST(1,3) = (l1 + l2 * 2 + l3 + 2) >> 2;
+}
+
+#define def_hor_down(size) \
+static void hor_down_##size##x##size##_c(uint8_t *_dst, ptrdiff_t stride, \
+ const uint8_t *_left, const uint8_t *_top) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ const pixel *top = (const pixel *) _top; \
+ const pixel *left = (const pixel *) _left; \
+ int i, j; \
+ pixel v[size * 3 - 2]; \
+\
+ stride /= sizeof(pixel); \
+ for (i = 0; i < size - 2; i++) { \
+ v[i*2 ] = (left[i + 1] + left[i + 0] + 1) >> 1; \
+ v[i*2 + 1] = (left[i + 2] + left[i + 1] * 2 + left[i + 0] + 2) >> 2; \
+ v[size*2 + i] = (top[i - 1] + top[i] * 2 + top[i + 1] + 2) >> 2; \
+ } \
+ v[size*2 - 2] = (top[-1] + left[size - 1] + 1) >> 1; \
+ v[size*2 - 4] = (left[size - 1] + left[size - 2] + 1) >> 1; \
+ v[size*2 - 1] = (top[0] + top[-1] * 2 + left[size - 1] + 2) >> 2; \
+ v[size*2 - 3] = (top[-1] + left[size - 1] * 2 + left[size - 2] + 2) >> 2; \
+\
+ for (j = 0; j < size; j++) \
+ memcpy(dst + j*stride, v + size*2 - 2 - j*2, size * sizeof(pixel)); \
+}
+
+def_hor_down(8)
+def_hor_down(16)
+def_hor_down(32)
+
+static void vert_left_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *left, const uint8_t *_top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *top = (const pixel *) _top;
+ int a0 = top[0], a1 = top[1], a2 = top[2], a3 = top[3],
+ a4 = top[4], a5 = top[5], a6 = top[6];
+
+ stride /= sizeof(pixel);
+ DST(0,0) = (a0 + a1 + 1) >> 1;
+ DST(0,1) = (a0 + a1 * 2 + a2 + 2) >> 2;
+ DST(1,0) = DST(0,2) = (a1 + a2 + 1) >> 1;
+ DST(1,1) = DST(0,3) = (a1 + a2 * 2 + a3 + 2) >> 2;
+ DST(2,0) = DST(1,2) = (a2 + a3 + 1) >> 1;
+ DST(2,1) = DST(1,3) = (a2 + a3 * 2 + a4 + 2) >> 2;
+ DST(3,0) = DST(2,2) = (a3 + a4 + 1) >> 1;
+ DST(3,1) = DST(2,3) = (a3 + a4 * 2 + a5 + 2) >> 2;
+ DST(3,2) = (a4 + a5 + 1) >> 1;
+ DST(3,3) = (a4 + a5 * 2 + a6 + 2) >> 2;
+}
+
+#define def_vert_left(size) \
+static void vert_left_##size##x##size##_c(uint8_t *_dst, ptrdiff_t stride, \
+ const uint8_t *left, const uint8_t *_top) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ const pixel *top = (const pixel *) _top; \
+ int i, j; \
+ pixel ve[size - 1], vo[size - 1]; \
+\
+ stride /= sizeof(pixel); \
+ for (i = 0; i < size - 2; i++) { \
+ ve[i] = (top[i] + top[i + 1] + 1) >> 1; \
+ vo[i] = (top[i] + top[i + 1] * 2 + top[i + 2] + 2) >> 2; \
+ } \
+ ve[size - 2] = (top[size - 2] + top[size - 1] + 1) >> 1; \
+ vo[size - 2] = (top[size - 2] + top[size - 1] * 3 + 2) >> 2; \
+\
+ for (j = 0; j < size / 2; j++) { \
+ memcpy(dst + j*2 * stride, ve + j, (size - j - 1) * sizeof(pixel)); \
+ memset_bpc(dst + j*2 * stride + size - j - 1, top[size - 1], j + 1); \
+ memcpy(dst + (j*2 + 1) * stride, vo + j, (size - j - 1) * sizeof(pixel)); \
+ memset_bpc(dst + (j*2 + 1) * stride + size - j - 1, top[size - 1], j + 1); \
+ } \
+}
+
+def_vert_left(8)
+def_vert_left(16)
+def_vert_left(32)
+
+static void hor_up_4x4_c(uint8_t *_dst, ptrdiff_t stride,
+ const uint8_t *_left, const uint8_t *top)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *left = (const pixel *) _left;
+ int l0 = left[0], l1 = left[1], l2 = left[2], l3 = left[3];
+
+ stride /= sizeof(pixel);
+ DST(0,0) = (l0 + l1 + 1) >> 1;
+ DST(1,0) = (l0 + l1 * 2 + l2 + 2) >> 2;
+ DST(0,1) = DST(2,0) = (l1 + l2 + 1) >> 1;
+ DST(1,1) = DST(3,0) = (l1 + l2 * 2 + l3 + 2) >> 2;
+ DST(0,2) = DST(2,1) = (l2 + l3 + 1) >> 1;
+ DST(1,2) = DST(3,1) = (l2 + l3 * 3 + 2) >> 2;
+ DST(0,3) = DST(1,3) = DST(2,2) = DST(2,3) = DST(3,2) = DST(3,3) = l3;
+}
+
+#define def_hor_up(size) \
+static void hor_up_##size##x##size##_c(uint8_t *_dst, ptrdiff_t stride, \
+ const uint8_t *_left, const uint8_t *top) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ const pixel *left = (const pixel *) _left; \
+ int i, j; \
+ pixel v[size*2 - 2]; \
+\
+ stride /= sizeof(pixel); \
+ for (i = 0; i < size - 2; i++) { \
+ v[i*2 ] = (left[i] + left[i + 1] + 1) >> 1; \
+ v[i*2 + 1] = (left[i] + left[i + 1] * 2 + left[i + 2] + 2) >> 2; \
+ } \
+ v[size*2 - 4] = (left[size - 2] + left[size - 1] + 1) >> 1; \
+ v[size*2 - 3] = (left[size - 2] + left[size - 1] * 3 + 2) >> 2; \
+\
+ for (j = 0; j < size / 2; j++) \
+ memcpy(dst + j*stride, v + j*2, size * sizeof(pixel)); \
+ for (j = size / 2; j < size; j++) { \
+ memcpy(dst + j*stride, v + j*2, (size*2 - 2 - j*2) * sizeof(pixel)); \
+ memset_bpc(dst + j*stride + size*2 - 2 - j*2, left[size - 1], \
+ 2 + j*2 - size); \
+ } \
+}
+
+def_hor_up(8)
+def_hor_up(16)
+def_hor_up(32)
+
+#undef DST
+
+#endif /* BIT_DEPTH != 12 */
+
+#if BIT_DEPTH != 8
+void vp9dsp_intrapred_init_10(VP9DSPContext *dsp);
+#endif
+#if BIT_DEPTH != 10
+static
+#endif
+av_cold void FUNC(vp9dsp_intrapred_init)(VP9DSPContext *dsp)
+{
+#define init_intra_pred_bd_aware(tx, sz) \
+ dsp->intra_pred[tx][TM_VP8_PRED] = tm_##sz##_c; \
+ dsp->intra_pred[tx][DC_128_PRED] = dc_128_##sz##_c; \
+ dsp->intra_pred[tx][DC_127_PRED] = dc_127_##sz##_c; \
+ dsp->intra_pred[tx][DC_129_PRED] = dc_129_##sz##_c
+
+#if BIT_DEPTH == 12
+ vp9dsp_intrapred_init_10(dsp);
+#define init_intra_pred(tx, sz) \
+ init_intra_pred_bd_aware(tx, sz)
+#else
+ #define init_intra_pred(tx, sz) \
+ dsp->intra_pred[tx][VERT_PRED] = vert_##sz##_c; \
+ dsp->intra_pred[tx][HOR_PRED] = hor_##sz##_c; \
+ dsp->intra_pred[tx][DC_PRED] = dc_##sz##_c; \
+ dsp->intra_pred[tx][DIAG_DOWN_LEFT_PRED] = diag_downleft_##sz##_c; \
+ dsp->intra_pred[tx][DIAG_DOWN_RIGHT_PRED] = diag_downright_##sz##_c; \
+ dsp->intra_pred[tx][VERT_RIGHT_PRED] = vert_right_##sz##_c; \
+ dsp->intra_pred[tx][HOR_DOWN_PRED] = hor_down_##sz##_c; \
+ dsp->intra_pred[tx][VERT_LEFT_PRED] = vert_left_##sz##_c; \
+ dsp->intra_pred[tx][HOR_UP_PRED] = hor_up_##sz##_c; \
+ dsp->intra_pred[tx][LEFT_DC_PRED] = dc_left_##sz##_c; \
+ dsp->intra_pred[tx][TOP_DC_PRED] = dc_top_##sz##_c; \
+ init_intra_pred_bd_aware(tx, sz)
+#endif
+
+ init_intra_pred(TX_4X4, 4x4);
+ init_intra_pred(TX_8X8, 8x8);
+ init_intra_pred(TX_16X16, 16x16);
+ init_intra_pred(TX_32X32, 32x32);
+
+#undef init_intra_pred
+#undef init_intra_pred_bd_aware
+}
+
+#define itxfm_wrapper(type_a, type_b, sz, bits, has_dconly) \
+static void type_a##_##type_b##_##sz##x##sz##_add_c(uint8_t *_dst, \
+ ptrdiff_t stride, \
+ int16_t *_block, int eob) \
+{ \
+ int i, j; \
+ pixel *dst = (pixel *) _dst; \
+ dctcoef *block = (dctcoef *) _block, tmp[sz * sz], out[sz]; \
+\
+ stride /= sizeof(pixel); \
+ if (has_dconly && eob == 1) { \
+ const int t = (((block[0] * 11585 + (1 << 13)) >> 14) \
+ * 11585 + (1 << 13)) >> 14; \
+ block[0] = 0; \
+ for (i = 0; i < sz; i++) { \
+ for (j = 0; j < sz; j++) \
+ dst[j * stride] = av_clip_pixel(dst[j * stride] + \
+ (bits ? \
+ (t + (1 << (bits - 1))) >> bits : \
+ t)); \
+ dst++; \
+ } \
+ return; \
+ } \
+\
+ for (i = 0; i < sz; i++) \
+ type_a##sz##_1d(block + i, sz, tmp + i * sz, 0); \
+ memset(block, 0, sz * sz * sizeof(*block)); \
+ for (i = 0; i < sz; i++) { \
+ type_b##sz##_1d(tmp + i, sz, out, 1); \
+ for (j = 0; j < sz; j++) \
+ dst[j * stride] = av_clip_pixel(dst[j * stride] + \
+ (bits ? \
+ (out[j] + (1 << (bits - 1))) >> bits : \
+ out[j])); \
+ dst++; \
+ } \
+}
+
+#define itxfm_wrap(sz, bits) \
+itxfm_wrapper(idct, idct, sz, bits, 1) \
+itxfm_wrapper(iadst, idct, sz, bits, 0) \
+itxfm_wrapper(idct, iadst, sz, bits, 0) \
+itxfm_wrapper(iadst, iadst, sz, bits, 0)
+
+#define IN(x) ((dctint) in[(x) * stride])
+
+static av_always_inline void idct4_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ dctint t0, t1, t2, t3;
+
+ t0 = ((IN(0) + IN(2)) * 11585 + (1 << 13)) >> 14;
+ t1 = ((IN(0) - IN(2)) * 11585 + (1 << 13)) >> 14;
+ t2 = (IN(1) * 6270 - IN(3) * 15137 + (1 << 13)) >> 14;
+ t3 = (IN(1) * 15137 + IN(3) * 6270 + (1 << 13)) >> 14;
+
+ out[0] = t0 + t3;
+ out[1] = t1 + t2;
+ out[2] = t1 - t2;
+ out[3] = t0 - t3;
+}
+
+static av_always_inline void iadst4_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ int t0, t1, t2, t3;
+
+ t0 = 5283 * IN(0) + 15212 * IN(2) + 9929 * IN(3);
+ t1 = 9929 * IN(0) - 5283 * IN(2) - 15212 * IN(3);
+ t2 = 13377 * (IN(0) - IN(2) + IN(3));
+ t3 = 13377 * IN(1);
+
+ out[0] = (t0 + t3 + (1 << 13)) >> 14;
+ out[1] = (t1 + t3 + (1 << 13)) >> 14;
+ out[2] = (t2 + (1 << 13)) >> 14;
+ out[3] = (t0 + t1 - t3 + (1 << 13)) >> 14;
+}
+
+itxfm_wrap(4, 4)
+
+static av_always_inline void idct8_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ dctint t0, t0a, t1, t1a, t2, t2a, t3, t3a, t4, t4a, t5, t5a, t6, t6a, t7, t7a;
+
+ t0a = ((IN(0) + IN(4)) * 11585 + (1 << 13)) >> 14;
+ t1a = ((IN(0) - IN(4)) * 11585 + (1 << 13)) >> 14;
+ t2a = (IN(2) * 6270 - IN(6) * 15137 + (1 << 13)) >> 14;
+ t3a = (IN(2) * 15137 + IN(6) * 6270 + (1 << 13)) >> 14;
+ t4a = (IN(1) * 3196 - IN(7) * 16069 + (1 << 13)) >> 14;
+ t5a = (IN(5) * 13623 - IN(3) * 9102 + (1 << 13)) >> 14;
+ t6a = (IN(5) * 9102 + IN(3) * 13623 + (1 << 13)) >> 14;
+ t7a = (IN(1) * 16069 + IN(7) * 3196 + (1 << 13)) >> 14;
+
+ t0 = t0a + t3a;
+ t1 = t1a + t2a;
+ t2 = t1a - t2a;
+ t3 = t0a - t3a;
+ t4 = t4a + t5a;
+ t5a = t4a - t5a;
+ t7 = t7a + t6a;
+ t6a = t7a - t6a;
+
+ t5 = ((t6a - t5a) * 11585 + (1 << 13)) >> 14;
+ t6 = ((t6a + t5a) * 11585 + (1 << 13)) >> 14;
+
+ out[0] = t0 + t7;
+ out[1] = t1 + t6;
+ out[2] = t2 + t5;
+ out[3] = t3 + t4;
+ out[4] = t3 - t4;
+ out[5] = t2 - t5;
+ out[6] = t1 - t6;
+ out[7] = t0 - t7;
+}
+
+static av_always_inline void iadst8_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ dctint t0, t0a, t1, t1a, t2, t2a, t3, t3a, t4, t4a, t5, t5a, t6, t6a, t7, t7a;
+
+ t0a = 16305 * IN(7) + 1606 * IN(0);
+ t1a = 1606 * IN(7) - 16305 * IN(0);
+ t2a = 14449 * IN(5) + 7723 * IN(2);
+ t3a = 7723 * IN(5) - 14449 * IN(2);
+ t4a = 10394 * IN(3) + 12665 * IN(4);
+ t5a = 12665 * IN(3) - 10394 * IN(4);
+ t6a = 4756 * IN(1) + 15679 * IN(6);
+ t7a = 15679 * IN(1) - 4756 * IN(6);
+
+ t0 = (t0a + t4a + (1 << 13)) >> 14;
+ t1 = (t1a + t5a + (1 << 13)) >> 14;
+ t2 = (t2a + t6a + (1 << 13)) >> 14;
+ t3 = (t3a + t7a + (1 << 13)) >> 14;
+ t4 = (t0a - t4a + (1 << 13)) >> 14;
+ t5 = (t1a - t5a + (1 << 13)) >> 14;
+ t6 = (t2a - t6a + (1 << 13)) >> 14;
+ t7 = (t3a - t7a + (1 << 13)) >> 14;
+
+ t4a = 15137 * t4 + 6270 * t5;
+ t5a = 6270 * t4 - 15137 * t5;
+ t6a = 15137 * t7 - 6270 * t6;
+ t7a = 6270 * t7 + 15137 * t6;
+
+ out[0] = t0 + t2;
+ out[7] = -(t1 + t3);
+ t2 = t0 - t2;
+ t3 = t1 - t3;
+
+ out[1] = -((t4a + t6a + (1 << 13)) >> 14);
+ out[6] = (t5a + t7a + (1 << 13)) >> 14;
+ t6 = (t4a - t6a + (1 << 13)) >> 14;
+ t7 = (t5a - t7a + (1 << 13)) >> 14;
+
+ out[3] = -(((t2 + t3) * 11585 + (1 << 13)) >> 14);
+ out[4] = ((t2 - t3) * 11585 + (1 << 13)) >> 14;
+ out[2] = ((t6 + t7) * 11585 + (1 << 13)) >> 14;
+ out[5] = -(((t6 - t7) * 11585 + (1 << 13)) >> 14);
+}
+
+itxfm_wrap(8, 5)
+
+static av_always_inline void idct16_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ dctint t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
+ dctint t0a, t1a, t2a, t3a, t4a, t5a, t6a, t7a;
+ dctint t8a, t9a, t10a, t11a, t12a, t13a, t14a, t15a;
+
+ t0a = ((IN(0) + IN(8)) * 11585 + (1 << 13)) >> 14;
+ t1a = ((IN(0) - IN(8)) * 11585 + (1 << 13)) >> 14;
+ t2a = (IN(4) * 6270 - IN(12) * 15137 + (1 << 13)) >> 14;
+ t3a = (IN(4) * 15137 + IN(12) * 6270 + (1 << 13)) >> 14;
+ t4a = (IN(2) * 3196 - IN(14) * 16069 + (1 << 13)) >> 14;
+ t7a = (IN(2) * 16069 + IN(14) * 3196 + (1 << 13)) >> 14;
+ t5a = (IN(10) * 13623 - IN(6) * 9102 + (1 << 13)) >> 14;
+ t6a = (IN(10) * 9102 + IN(6) * 13623 + (1 << 13)) >> 14;
+ t8a = (IN(1) * 1606 - IN(15) * 16305 + (1 << 13)) >> 14;
+ t15a = (IN(1) * 16305 + IN(15) * 1606 + (1 << 13)) >> 14;
+ t9a = (IN(9) * 12665 - IN(7) * 10394 + (1 << 13)) >> 14;
+ t14a = (IN(9) * 10394 + IN(7) * 12665 + (1 << 13)) >> 14;
+ t10a = (IN(5) * 7723 - IN(11) * 14449 + (1 << 13)) >> 14;
+ t13a = (IN(5) * 14449 + IN(11) * 7723 + (1 << 13)) >> 14;
+ t11a = (IN(13) * 15679 - IN(3) * 4756 + (1 << 13)) >> 14;
+ t12a = (IN(13) * 4756 + IN(3) * 15679 + (1 << 13)) >> 14;
+
+ t0 = t0a + t3a;
+ t1 = t1a + t2a;
+ t2 = t1a - t2a;
+ t3 = t0a - t3a;
+ t4 = t4a + t5a;
+ t5 = t4a - t5a;
+ t6 = t7a - t6a;
+ t7 = t7a + t6a;
+ t8 = t8a + t9a;
+ t9 = t8a - t9a;
+ t10 = t11a - t10a;
+ t11 = t11a + t10a;
+ t12 = t12a + t13a;
+ t13 = t12a - t13a;
+ t14 = t15a - t14a;
+ t15 = t15a + t14a;
+
+ t5a = ((t6 - t5) * 11585 + (1 << 13)) >> 14;
+ t6a = ((t6 + t5) * 11585 + (1 << 13)) >> 14;
+ t9a = ( t14 * 6270 - t9 * 15137 + (1 << 13)) >> 14;
+ t14a = ( t14 * 15137 + t9 * 6270 + (1 << 13)) >> 14;
+ t10a = (-(t13 * 15137 + t10 * 6270) + (1 << 13)) >> 14;
+ t13a = ( t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
+
+ t0a = t0 + t7;
+ t1a = t1 + t6a;
+ t2a = t2 + t5a;
+ t3a = t3 + t4;
+ t4 = t3 - t4;
+ t5 = t2 - t5a;
+ t6 = t1 - t6a;
+ t7 = t0 - t7;
+ t8a = t8 + t11;
+ t9 = t9a + t10a;
+ t10 = t9a - t10a;
+ t11a = t8 - t11;
+ t12a = t15 - t12;
+ t13 = t14a - t13a;
+ t14 = t14a + t13a;
+ t15a = t15 + t12;
+
+ t10a = ((t13 - t10) * 11585 + (1 << 13)) >> 14;
+ t13a = ((t13 + t10) * 11585 + (1 << 13)) >> 14;
+ t11 = ((t12a - t11a) * 11585 + (1 << 13)) >> 14;
+ t12 = ((t12a + t11a) * 11585 + (1 << 13)) >> 14;
+
+ out[ 0] = t0a + t15a;
+ out[ 1] = t1a + t14;
+ out[ 2] = t2a + t13a;
+ out[ 3] = t3a + t12;
+ out[ 4] = t4 + t11;
+ out[ 5] = t5 + t10a;
+ out[ 6] = t6 + t9;
+ out[ 7] = t7 + t8a;
+ out[ 8] = t7 - t8a;
+ out[ 9] = t6 - t9;
+ out[10] = t5 - t10a;
+ out[11] = t4 - t11;
+ out[12] = t3a - t12;
+ out[13] = t2a - t13a;
+ out[14] = t1a - t14;
+ out[15] = t0a - t15a;
+}
+
+static av_always_inline void iadst16_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ dctint t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15;
+ dctint t0a, t1a, t2a, t3a, t4a, t5a, t6a, t7a;
+ dctint t8a, t9a, t10a, t11a, t12a, t13a, t14a, t15a;
+
+ t0 = IN(15) * 16364 + IN(0) * 804;
+ t1 = IN(15) * 804 - IN(0) * 16364;
+ t2 = IN(13) * 15893 + IN(2) * 3981;
+ t3 = IN(13) * 3981 - IN(2) * 15893;
+ t4 = IN(11) * 14811 + IN(4) * 7005;
+ t5 = IN(11) * 7005 - IN(4) * 14811;
+ t6 = IN(9) * 13160 + IN(6) * 9760;
+ t7 = IN(9) * 9760 - IN(6) * 13160;
+ t8 = IN(7) * 11003 + IN(8) * 12140;
+ t9 = IN(7) * 12140 - IN(8) * 11003;
+ t10 = IN(5) * 8423 + IN(10) * 14053;
+ t11 = IN(5) * 14053 - IN(10) * 8423;
+ t12 = IN(3) * 5520 + IN(12) * 15426;
+ t13 = IN(3) * 15426 - IN(12) * 5520;
+ t14 = IN(1) * 2404 + IN(14) * 16207;
+ t15 = IN(1) * 16207 - IN(14) * 2404;
+
+ t0a = (t0 + t8 + (1 << 13)) >> 14;
+ t1a = (t1 + t9 + (1 << 13)) >> 14;
+ t2a = (t2 + t10 + (1 << 13)) >> 14;
+ t3a = (t3 + t11 + (1 << 13)) >> 14;
+ t4a = (t4 + t12 + (1 << 13)) >> 14;
+ t5a = (t5 + t13 + (1 << 13)) >> 14;
+ t6a = (t6 + t14 + (1 << 13)) >> 14;
+ t7a = (t7 + t15 + (1 << 13)) >> 14;
+ t8a = (t0 - t8 + (1 << 13)) >> 14;
+ t9a = (t1 - t9 + (1 << 13)) >> 14;
+ t10a = (t2 - t10 + (1 << 13)) >> 14;
+ t11a = (t3 - t11 + (1 << 13)) >> 14;
+ t12a = (t4 - t12 + (1 << 13)) >> 14;
+ t13a = (t5 - t13 + (1 << 13)) >> 14;
+ t14a = (t6 - t14 + (1 << 13)) >> 14;
+ t15a = (t7 - t15 + (1 << 13)) >> 14;
+
+ t8 = t8a * 16069 + t9a * 3196;
+ t9 = t8a * 3196 - t9a * 16069;
+ t10 = t10a * 9102 + t11a * 13623;
+ t11 = t10a * 13623 - t11a * 9102;
+ t12 = t13a * 16069 - t12a * 3196;
+ t13 = t13a * 3196 + t12a * 16069;
+ t14 = t15a * 9102 - t14a * 13623;
+ t15 = t15a * 13623 + t14a * 9102;
+
+ t0 = t0a + t4a;
+ t1 = t1a + t5a;
+ t2 = t2a + t6a;
+ t3 = t3a + t7a;
+ t4 = t0a - t4a;
+ t5 = t1a - t5a;
+ t6 = t2a - t6a;
+ t7 = t3a - t7a;
+ t8a = (t8 + t12 + (1 << 13)) >> 14;
+ t9a = (t9 + t13 + (1 << 13)) >> 14;
+ t10a = (t10 + t14 + (1 << 13)) >> 14;
+ t11a = (t11 + t15 + (1 << 13)) >> 14;
+ t12a = (t8 - t12 + (1 << 13)) >> 14;
+ t13a = (t9 - t13 + (1 << 13)) >> 14;
+ t14a = (t10 - t14 + (1 << 13)) >> 14;
+ t15a = (t11 - t15 + (1 << 13)) >> 14;
+
+ t4a = t4 * 15137 + t5 * 6270;
+ t5a = t4 * 6270 - t5 * 15137;
+ t6a = t7 * 15137 - t6 * 6270;
+ t7a = t7 * 6270 + t6 * 15137;
+ t12 = t12a * 15137 + t13a * 6270;
+ t13 = t12a * 6270 - t13a * 15137;
+ t14 = t15a * 15137 - t14a * 6270;
+ t15 = t15a * 6270 + t14a * 15137;
+
+ out[ 0] = t0 + t2;
+ out[15] = -(t1 + t3);
+ t2a = t0 - t2;
+ t3a = t1 - t3;
+ out[ 3] = -((t4a + t6a + (1 << 13)) >> 14);
+ out[12] = (t5a + t7a + (1 << 13)) >> 14;
+ t6 = (t4a - t6a + (1 << 13)) >> 14;
+ t7 = (t5a - t7a + (1 << 13)) >> 14;
+ out[ 1] = -(t8a + t10a);
+ out[14] = t9a + t11a;
+ t10 = t8a - t10a;
+ t11 = t9a - t11a;
+ out[ 2] = (t12 + t14 + (1 << 13)) >> 14;
+ out[13] = -((t13 + t15 + (1 << 13)) >> 14);
+ t14a = (t12 - t14 + (1 << 13)) >> 14;
+ t15a = (t13 - t15 + (1 << 13)) >> 14;
+
+ out[ 7] = ((t2a + t3a) * -11585 + (1 << 13)) >> 14;
+ out[ 8] = ((t2a - t3a) * 11585 + (1 << 13)) >> 14;
+ out[ 4] = ((t7 + t6) * 11585 + (1 << 13)) >> 14;
+ out[11] = ((t7 - t6) * 11585 + (1 << 13)) >> 14;
+ out[ 6] = ((t11 + t10) * 11585 + (1 << 13)) >> 14;
+ out[ 9] = ((t11 - t10) * 11585 + (1 << 13)) >> 14;
+ out[ 5] = ((t14a + t15a) * -11585 + (1 << 13)) >> 14;
+ out[10] = ((t14a - t15a) * 11585 + (1 << 13)) >> 14;
+}
+
+itxfm_wrap(16, 6)
+
+static av_always_inline void idct32_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ dctint t0a = ((IN(0) + IN(16)) * 11585 + (1 << 13)) >> 14;
+ dctint t1a = ((IN(0) - IN(16)) * 11585 + (1 << 13)) >> 14;
+ dctint t2a = (IN( 8) * 6270 - IN(24) * 15137 + (1 << 13)) >> 14;
+ dctint t3a = (IN( 8) * 15137 + IN(24) * 6270 + (1 << 13)) >> 14;
+ dctint t4a = (IN( 4) * 3196 - IN(28) * 16069 + (1 << 13)) >> 14;
+ dctint t7a = (IN( 4) * 16069 + IN(28) * 3196 + (1 << 13)) >> 14;
+ dctint t5a = (IN(20) * 13623 - IN(12) * 9102 + (1 << 13)) >> 14;
+ dctint t6a = (IN(20) * 9102 + IN(12) * 13623 + (1 << 13)) >> 14;
+ dctint t8a = (IN( 2) * 1606 - IN(30) * 16305 + (1 << 13)) >> 14;
+ dctint t15a = (IN( 2) * 16305 + IN(30) * 1606 + (1 << 13)) >> 14;
+ dctint t9a = (IN(18) * 12665 - IN(14) * 10394 + (1 << 13)) >> 14;
+ dctint t14a = (IN(18) * 10394 + IN(14) * 12665 + (1 << 13)) >> 14;
+ dctint t10a = (IN(10) * 7723 - IN(22) * 14449 + (1 << 13)) >> 14;
+ dctint t13a = (IN(10) * 14449 + IN(22) * 7723 + (1 << 13)) >> 14;
+ dctint t11a = (IN(26) * 15679 - IN( 6) * 4756 + (1 << 13)) >> 14;
+ dctint t12a = (IN(26) * 4756 + IN( 6) * 15679 + (1 << 13)) >> 14;
+ dctint t16a = (IN( 1) * 804 - IN(31) * 16364 + (1 << 13)) >> 14;
+ dctint t31a = (IN( 1) * 16364 + IN(31) * 804 + (1 << 13)) >> 14;
+ dctint t17a = (IN(17) * 12140 - IN(15) * 11003 + (1 << 13)) >> 14;
+ dctint t30a = (IN(17) * 11003 + IN(15) * 12140 + (1 << 13)) >> 14;
+ dctint t18a = (IN( 9) * 7005 - IN(23) * 14811 + (1 << 13)) >> 14;
+ dctint t29a = (IN( 9) * 14811 + IN(23) * 7005 + (1 << 13)) >> 14;
+ dctint t19a = (IN(25) * 15426 - IN( 7) * 5520 + (1 << 13)) >> 14;
+ dctint t28a = (IN(25) * 5520 + IN( 7) * 15426 + (1 << 13)) >> 14;
+ dctint t20a = (IN( 5) * 3981 - IN(27) * 15893 + (1 << 13)) >> 14;
+ dctint t27a = (IN( 5) * 15893 + IN(27) * 3981 + (1 << 13)) >> 14;
+ dctint t21a = (IN(21) * 14053 - IN(11) * 8423 + (1 << 13)) >> 14;
+ dctint t26a = (IN(21) * 8423 + IN(11) * 14053 + (1 << 13)) >> 14;
+ dctint t22a = (IN(13) * 9760 - IN(19) * 13160 + (1 << 13)) >> 14;
+ dctint t25a = (IN(13) * 13160 + IN(19) * 9760 + (1 << 13)) >> 14;
+ dctint t23a = (IN(29) * 16207 - IN( 3) * 2404 + (1 << 13)) >> 14;
+ dctint t24a = (IN(29) * 2404 + IN( 3) * 16207 + (1 << 13)) >> 14;
+
+ dctint t0 = t0a + t3a;
+ dctint t1 = t1a + t2a;
+ dctint t2 = t1a - t2a;
+ dctint t3 = t0a - t3a;
+ dctint t4 = t4a + t5a;
+ dctint t5 = t4a - t5a;
+ dctint t6 = t7a - t6a;
+ dctint t7 = t7a + t6a;
+ dctint t8 = t8a + t9a;
+ dctint t9 = t8a - t9a;
+ dctint t10 = t11a - t10a;
+ dctint t11 = t11a + t10a;
+ dctint t12 = t12a + t13a;
+ dctint t13 = t12a - t13a;
+ dctint t14 = t15a - t14a;
+ dctint t15 = t15a + t14a;
+ dctint t16 = t16a + t17a;
+ dctint t17 = t16a - t17a;
+ dctint t18 = t19a - t18a;
+ dctint t19 = t19a + t18a;
+ dctint t20 = t20a + t21a;
+ dctint t21 = t20a - t21a;
+ dctint t22 = t23a - t22a;
+ dctint t23 = t23a + t22a;
+ dctint t24 = t24a + t25a;
+ dctint t25 = t24a - t25a;
+ dctint t26 = t27a - t26a;
+ dctint t27 = t27a + t26a;
+ dctint t28 = t28a + t29a;
+ dctint t29 = t28a - t29a;
+ dctint t30 = t31a - t30a;
+ dctint t31 = t31a + t30a;
+
+ t5a = ((t6 - t5) * 11585 + (1 << 13)) >> 14;
+ t6a = ((t6 + t5) * 11585 + (1 << 13)) >> 14;
+ t9a = ( t14 * 6270 - t9 * 15137 + (1 << 13)) >> 14;
+ t14a = ( t14 * 15137 + t9 * 6270 + (1 << 13)) >> 14;
+ t10a = (-(t13 * 15137 + t10 * 6270) + (1 << 13)) >> 14;
+ t13a = ( t13 * 6270 - t10 * 15137 + (1 << 13)) >> 14;
+ t17a = ( t30 * 3196 - t17 * 16069 + (1 << 13)) >> 14;
+ t30a = ( t30 * 16069 + t17 * 3196 + (1 << 13)) >> 14;
+ t18a = (-(t29 * 16069 + t18 * 3196) + (1 << 13)) >> 14;
+ t29a = ( t29 * 3196 - t18 * 16069 + (1 << 13)) >> 14;
+ t21a = ( t26 * 13623 - t21 * 9102 + (1 << 13)) >> 14;
+ t26a = ( t26 * 9102 + t21 * 13623 + (1 << 13)) >> 14;
+ t22a = (-(t25 * 9102 + t22 * 13623) + (1 << 13)) >> 14;
+ t25a = ( t25 * 13623 - t22 * 9102 + (1 << 13)) >> 14;
+
+ t0a = t0 + t7;
+ t1a = t1 + t6a;
+ t2a = t2 + t5a;
+ t3a = t3 + t4;
+ t4a = t3 - t4;
+ t5 = t2 - t5a;
+ t6 = t1 - t6a;
+ t7a = t0 - t7;
+ t8a = t8 + t11;
+ t9 = t9a + t10a;
+ t10 = t9a - t10a;
+ t11a = t8 - t11;
+ t12a = t15 - t12;
+ t13 = t14a - t13a;
+ t14 = t14a + t13a;
+ t15a = t15 + t12;
+ t16a = t16 + t19;
+ t17 = t17a + t18a;
+ t18 = t17a - t18a;
+ t19a = t16 - t19;
+ t20a = t23 - t20;
+ t21 = t22a - t21a;
+ t22 = t22a + t21a;
+ t23a = t23 + t20;
+ t24a = t24 + t27;
+ t25 = t25a + t26a;
+ t26 = t25a - t26a;
+ t27a = t24 - t27;
+ t28a = t31 - t28;
+ t29 = t30a - t29a;
+ t30 = t30a + t29a;
+ t31a = t31 + t28;
+
+ t10a = ((t13 - t10) * 11585 + (1 << 13)) >> 14;
+ t13a = ((t13 + t10) * 11585 + (1 << 13)) >> 14;
+ t11 = ((t12a - t11a) * 11585 + (1 << 13)) >> 14;
+ t12 = ((t12a + t11a) * 11585 + (1 << 13)) >> 14;
+ t18a = ( t29 * 6270 - t18 * 15137 + (1 << 13)) >> 14;
+ t29a = ( t29 * 15137 + t18 * 6270 + (1 << 13)) >> 14;
+ t19 = ( t28a * 6270 - t19a * 15137 + (1 << 13)) >> 14;
+ t28 = ( t28a * 15137 + t19a * 6270 + (1 << 13)) >> 14;
+ t20 = (-(t27a * 15137 + t20a * 6270) + (1 << 13)) >> 14;
+ t27 = ( t27a * 6270 - t20a * 15137 + (1 << 13)) >> 14;
+ t21a = (-(t26 * 15137 + t21 * 6270) + (1 << 13)) >> 14;
+ t26a = ( t26 * 6270 - t21 * 15137 + (1 << 13)) >> 14;
+
+ t0 = t0a + t15a;
+ t1 = t1a + t14;
+ t2 = t2a + t13a;
+ t3 = t3a + t12;
+ t4 = t4a + t11;
+ t5a = t5 + t10a;
+ t6a = t6 + t9;
+ t7 = t7a + t8a;
+ t8 = t7a - t8a;
+ t9a = t6 - t9;
+ t10 = t5 - t10a;
+ t11a = t4a - t11;
+ t12a = t3a - t12;
+ t13 = t2a - t13a;
+ t14a = t1a - t14;
+ t15 = t0a - t15a;
+ t16 = t16a + t23a;
+ t17a = t17 + t22;
+ t18 = t18a + t21a;
+ t19a = t19 + t20;
+ t20a = t19 - t20;
+ t21 = t18a - t21a;
+ t22a = t17 - t22;
+ t23 = t16a - t23a;
+ t24 = t31a - t24a;
+ t25a = t30 - t25;
+ t26 = t29a - t26a;
+ t27a = t28 - t27;
+ t28a = t28 + t27;
+ t29 = t29a + t26a;
+ t30a = t30 + t25;
+ t31 = t31a + t24a;
+
+ t20 = ((t27a - t20a) * 11585 + (1 << 13)) >> 14;
+ t27 = ((t27a + t20a) * 11585 + (1 << 13)) >> 14;
+ t21a = ((t26 - t21 ) * 11585 + (1 << 13)) >> 14;
+ t26a = ((t26 + t21 ) * 11585 + (1 << 13)) >> 14;
+ t22 = ((t25a - t22a) * 11585 + (1 << 13)) >> 14;
+ t25 = ((t25a + t22a) * 11585 + (1 << 13)) >> 14;
+ t23a = ((t24 - t23 ) * 11585 + (1 << 13)) >> 14;
+ t24a = ((t24 + t23 ) * 11585 + (1 << 13)) >> 14;
+
+ out[ 0] = t0 + t31;
+ out[ 1] = t1 + t30a;
+ out[ 2] = t2 + t29;
+ out[ 3] = t3 + t28a;
+ out[ 4] = t4 + t27;
+ out[ 5] = t5a + t26a;
+ out[ 6] = t6a + t25;
+ out[ 7] = t7 + t24a;
+ out[ 8] = t8 + t23a;
+ out[ 9] = t9a + t22;
+ out[10] = t10 + t21a;
+ out[11] = t11a + t20;
+ out[12] = t12a + t19a;
+ out[13] = t13 + t18;
+ out[14] = t14a + t17a;
+ out[15] = t15 + t16;
+ out[16] = t15 - t16;
+ out[17] = t14a - t17a;
+ out[18] = t13 - t18;
+ out[19] = t12a - t19a;
+ out[20] = t11a - t20;
+ out[21] = t10 - t21a;
+ out[22] = t9a - t22;
+ out[23] = t8 - t23a;
+ out[24] = t7 - t24a;
+ out[25] = t6a - t25;
+ out[26] = t5a - t26a;
+ out[27] = t4 - t27;
+ out[28] = t3 - t28a;
+ out[29] = t2 - t29;
+ out[30] = t1 - t30a;
+ out[31] = t0 - t31;
+}
+
+itxfm_wrapper(idct, idct, 32, 6, 1)
+
+static av_always_inline void iwht4_1d(const dctcoef *in, ptrdiff_t stride,
+ dctcoef *out, int pass)
+{
+ int t0, t1, t2, t3, t4;
+
+ if (pass == 0) {
+ t0 = IN(0) >> 2;
+ t1 = IN(3) >> 2;
+ t2 = IN(1) >> 2;
+ t3 = IN(2) >> 2;
+ } else {
+ t0 = IN(0);
+ t1 = IN(3);
+ t2 = IN(1);
+ t3 = IN(2);
+ }
+
+ t0 += t2;
+ t3 -= t1;
+ t4 = (t0 - t3) >> 1;
+ t1 = t4 - t1;
+ t2 = t4 - t2;
+ t0 -= t1;
+ t3 += t2;
+
+ out[0] = t0;
+ out[1] = t1;
+ out[2] = t2;
+ out[3] = t3;
+}
+
+itxfm_wrapper(iwht, iwht, 4, 0, 0)
+
+#undef IN
+#undef itxfm_wrapper
+#undef itxfm_wrap
+
+static av_cold void vp9dsp_itxfm_init(VP9DSPContext *dsp)
+{
+#define init_itxfm(tx, sz) \
+ dsp->itxfm_add[tx][DCT_DCT] = idct_idct_##sz##_add_c; \
+ dsp->itxfm_add[tx][DCT_ADST] = iadst_idct_##sz##_add_c; \
+ dsp->itxfm_add[tx][ADST_DCT] = idct_iadst_##sz##_add_c; \
+ dsp->itxfm_add[tx][ADST_ADST] = iadst_iadst_##sz##_add_c
+
+#define init_idct(tx, nm) \
+ dsp->itxfm_add[tx][DCT_DCT] = \
+ dsp->itxfm_add[tx][ADST_DCT] = \
+ dsp->itxfm_add[tx][DCT_ADST] = \
+ dsp->itxfm_add[tx][ADST_ADST] = nm##_add_c
+
+ init_itxfm(TX_4X4, 4x4);
+ init_itxfm(TX_8X8, 8x8);
+ init_itxfm(TX_16X16, 16x16);
+ init_idct(TX_32X32, idct_idct_32x32);
+ init_idct(4 /* lossless */, iwht_iwht_4x4);
+
+#undef init_itxfm
+#undef init_idct
+}
+
+static av_always_inline void loop_filter(pixel *dst, int E, int I, int H,
+ ptrdiff_t stridea, ptrdiff_t strideb,
+ int wd)
+{
+ int i, F = 1 << (BIT_DEPTH - 8);
+
+ E <<= (BIT_DEPTH - 8);
+ I <<= (BIT_DEPTH - 8);
+ H <<= (BIT_DEPTH - 8);
+ for (i = 0; i < 8; i++, dst += stridea) {
+ int p7, p6, p5, p4;
+ int p3 = dst[strideb * -4], p2 = dst[strideb * -3];
+ int p1 = dst[strideb * -2], p0 = dst[strideb * -1];
+ int q0 = dst[strideb * +0], q1 = dst[strideb * +1];
+ int q2 = dst[strideb * +2], q3 = dst[strideb * +3];
+ int q4, q5, q6, q7;
+ int fm = FFABS(p3 - p2) <= I && FFABS(p2 - p1) <= I &&
+ FFABS(p1 - p0) <= I && FFABS(q1 - q0) <= I &&
+ FFABS(q2 - q1) <= I && FFABS(q3 - q2) <= I &&
+ FFABS(p0 - q0) * 2 + (FFABS(p1 - q1) >> 1) <= E;
+ int flat8out, flat8in;
+
+ if (!fm)
+ continue;
+
+ if (wd >= 16) {
+ p7 = dst[strideb * -8];
+ p6 = dst[strideb * -7];
+ p5 = dst[strideb * -6];
+ p4 = dst[strideb * -5];
+ q4 = dst[strideb * +4];
+ q5 = dst[strideb * +5];
+ q6 = dst[strideb * +6];
+ q7 = dst[strideb * +7];
+
+ flat8out = FFABS(p7 - p0) <= F && FFABS(p6 - p0) <= F &&
+ FFABS(p5 - p0) <= F && FFABS(p4 - p0) <= F &&
+ FFABS(q4 - q0) <= F && FFABS(q5 - q0) <= F &&
+ FFABS(q6 - q0) <= F && FFABS(q7 - q0) <= F;
+ }
+
+ if (wd >= 8)
+ flat8in = FFABS(p3 - p0) <= F && FFABS(p2 - p0) <= F &&
+ FFABS(p1 - p0) <= F && FFABS(q1 - q0) <= F &&
+ FFABS(q2 - q0) <= F && FFABS(q3 - q0) <= F;
+
+ if (wd >= 16 && flat8out && flat8in) {
+ dst[strideb * -7] = (p7 + p7 + p7 + p7 + p7 + p7 + p7 + p6 * 2 +
+ p5 + p4 + p3 + p2 + p1 + p0 + q0 + 8) >> 4;
+ dst[strideb * -6] = (p7 + p7 + p7 + p7 + p7 + p7 + p6 + p5 * 2 +
+ p4 + p3 + p2 + p1 + p0 + q0 + q1 + 8) >> 4;
+ dst[strideb * -5] = (p7 + p7 + p7 + p7 + p7 + p6 + p5 + p4 * 2 +
+ p3 + p2 + p1 + p0 + q0 + q1 + q2 + 8) >> 4;
+ dst[strideb * -4] = (p7 + p7 + p7 + p7 + p6 + p5 + p4 + p3 * 2 +
+ p2 + p1 + p0 + q0 + q1 + q2 + q3 + 8) >> 4;
+ dst[strideb * -3] = (p7 + p7 + p7 + p6 + p5 + p4 + p3 + p2 * 2 +
+ p1 + p0 + q0 + q1 + q2 + q3 + q4 + 8) >> 4;
+ dst[strideb * -2] = (p7 + p7 + p6 + p5 + p4 + p3 + p2 + p1 * 2 +
+ p0 + q0 + q1 + q2 + q3 + q4 + q5 + 8) >> 4;
+ dst[strideb * -1] = (p7 + p6 + p5 + p4 + p3 + p2 + p1 + p0 * 2 +
+ q0 + q1 + q2 + q3 + q4 + q5 + q6 + 8) >> 4;
+ dst[strideb * +0] = (p6 + p5 + p4 + p3 + p2 + p1 + p0 + q0 * 2 +
+ q1 + q2 + q3 + q4 + q5 + q6 + q7 + 8) >> 4;
+ dst[strideb * +1] = (p5 + p4 + p3 + p2 + p1 + p0 + q0 + q1 * 2 +
+ q2 + q3 + q4 + q5 + q6 + q7 + q7 + 8) >> 4;
+ dst[strideb * +2] = (p4 + p3 + p2 + p1 + p0 + q0 + q1 + q2 * 2 +
+ q3 + q4 + q5 + q6 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +3] = (p3 + p2 + p1 + p0 + q0 + q1 + q2 + q3 * 2 +
+ q4 + q5 + q6 + q7 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +4] = (p2 + p1 + p0 + q0 + q1 + q2 + q3 + q4 * 2 +
+ q5 + q6 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +5] = (p1 + p0 + q0 + q1 + q2 + q3 + q4 + q5 * 2 +
+ q6 + q7 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
+ dst[strideb * +6] = (p0 + q0 + q1 + q2 + q3 + q4 + q5 + q6 * 2 +
+ q7 + q7 + q7 + q7 + q7 + q7 + q7 + 8) >> 4;
+ } else if (wd >= 8 && flat8in) {
+ dst[strideb * -3] = (p3 + p3 + p3 + 2 * p2 + p1 + p0 + q0 + 4) >> 3;
+ dst[strideb * -2] = (p3 + p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4) >> 3;
+ dst[strideb * -1] = (p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3;
+ dst[strideb * +0] = (p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3;
+ dst[strideb * +1] = (p1 + p0 + q0 + 2 * q1 + q2 + q3 + q3 + 4) >> 3;
+ dst[strideb * +2] = (p0 + q0 + q1 + 2 * q2 + q3 + q3 + q3 + 4) >> 3;
+ } else {
+ int hev = FFABS(p1 - p0) > H || FFABS(q1 - q0) > H;
+
+ if (hev) {
+ int f = av_clip_intp2(p1 - q1, BIT_DEPTH - 1), f1, f2;
+ f = av_clip_intp2(3 * (q0 - p0) + f, BIT_DEPTH - 1);
+
+ f1 = FFMIN(f + 4, (1 << (BIT_DEPTH - 1)) - 1) >> 3;
+ f2 = FFMIN(f + 3, (1 << (BIT_DEPTH - 1)) - 1) >> 3;
+
+ dst[strideb * -1] = av_clip_pixel(p0 + f2);
+ dst[strideb * +0] = av_clip_pixel(q0 - f1);
+ } else {
+ int f = av_clip_intp2(3 * (q0 - p0), BIT_DEPTH - 1), f1, f2;
+
+ f1 = FFMIN(f + 4, (1 << (BIT_DEPTH - 1)) - 1) >> 3;
+ f2 = FFMIN(f + 3, (1 << (BIT_DEPTH - 1)) - 1) >> 3;
+
+ dst[strideb * -1] = av_clip_pixel(p0 + f2);
+ dst[strideb * +0] = av_clip_pixel(q0 - f1);
+
+ f = (f1 + 1) >> 1;
+ dst[strideb * -2] = av_clip_pixel(p1 + f);
+ dst[strideb * +1] = av_clip_pixel(q1 - f);
+ }
+ }
+ }
+}
+
+#define lf_8_fn(dir, wd, stridea, strideb) \
+static void loop_filter_##dir##_##wd##_8_c(uint8_t *_dst, \
+ ptrdiff_t stride, \
+ int E, int I, int H) \
+{ \
+ pixel *dst = (pixel *) _dst; \
+ stride /= sizeof(pixel); \
+ loop_filter(dst, E, I, H, stridea, strideb, wd); \
+}
+
+#define lf_8_fns(wd) \
+lf_8_fn(h, wd, stride, 1) \
+lf_8_fn(v, wd, 1, stride)
+
+lf_8_fns(4)
+lf_8_fns(8)
+lf_8_fns(16)
+
+#undef lf_8_fn
+#undef lf_8_fns
+
+#define lf_16_fn(dir, stridea) \
+static void loop_filter_##dir##_16_16_c(uint8_t *dst, \
+ ptrdiff_t stride, \
+ int E, int I, int H) \
+{ \
+ loop_filter_##dir##_16_8_c(dst, stride, E, I, H); \
+ loop_filter_##dir##_16_8_c(dst + 8 * stridea, stride, E, I, H); \
+}
+
+lf_16_fn(h, stride)
+lf_16_fn(v, sizeof(pixel))
+
+#undef lf_16_fn
+
+#define lf_mix_fn(dir, wd1, wd2, stridea) \
+static void loop_filter_##dir##_##wd1##wd2##_16_c(uint8_t *dst, \
+ ptrdiff_t stride, \
+ int E, int I, int H) \
+{ \
+ loop_filter_##dir##_##wd1##_8_c(dst, stride, E & 0xff, I & 0xff, H & 0xff); \
+ loop_filter_##dir##_##wd2##_8_c(dst + 8 * stridea, stride, E >> 8, I >> 8, H >> 8); \
+}
+
+#define lf_mix_fns(wd1, wd2) \
+lf_mix_fn(h, wd1, wd2, stride) \
+lf_mix_fn(v, wd1, wd2, sizeof(pixel))
+
+lf_mix_fns(4, 4)
+lf_mix_fns(4, 8)
+lf_mix_fns(8, 4)
+lf_mix_fns(8, 8)
+
+#undef lf_mix_fn
+#undef lf_mix_fns
+
+static av_cold void vp9dsp_loopfilter_init(VP9DSPContext *dsp)
+{
+ dsp->loop_filter_8[0][0] = loop_filter_h_4_8_c;
+ dsp->loop_filter_8[0][1] = loop_filter_v_4_8_c;
+ dsp->loop_filter_8[1][0] = loop_filter_h_8_8_c;
+ dsp->loop_filter_8[1][1] = loop_filter_v_8_8_c;
+ dsp->loop_filter_8[2][0] = loop_filter_h_16_8_c;
+ dsp->loop_filter_8[2][1] = loop_filter_v_16_8_c;
+
+ dsp->loop_filter_16[0] = loop_filter_h_16_16_c;
+ dsp->loop_filter_16[1] = loop_filter_v_16_16_c;
+
+ dsp->loop_filter_mix2[0][0][0] = loop_filter_h_44_16_c;
+ dsp->loop_filter_mix2[0][0][1] = loop_filter_v_44_16_c;
+ dsp->loop_filter_mix2[0][1][0] = loop_filter_h_48_16_c;
+ dsp->loop_filter_mix2[0][1][1] = loop_filter_v_48_16_c;
+ dsp->loop_filter_mix2[1][0][0] = loop_filter_h_84_16_c;
+ dsp->loop_filter_mix2[1][0][1] = loop_filter_v_84_16_c;
+ dsp->loop_filter_mix2[1][1][0] = loop_filter_h_88_16_c;
+ dsp->loop_filter_mix2[1][1][1] = loop_filter_v_88_16_c;
+}
+
+#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)
+{
+ do {
+ memcpy(dst, src, w * sizeof(pixel));
+
+ dst += dst_stride;
+ src += src_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)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ do {
+ int x;
+
+ for (x = 0; x < w; x += 4)
+ AV_WN4PA(&dst[x], rnd_avg_pixel4(AV_RN4PA(&dst[x]), AV_RN4P(&src[x])));
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+#define fpel_fn(type, sz) \
+static void type##sz##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ type##_c(dst, dst_stride, src, src_stride, sz, h); \
+}
+
+#define copy_avg_fn(sz) \
+fpel_fn(copy, sz) \
+fpel_fn(avg, sz)
+
+copy_avg_fn(64)
+copy_avg_fn(32)
+copy_avg_fn(16)
+copy_avg_fn(8)
+copy_avg_fn(4)
+
+#undef fpel_fn
+#undef copy_avg_fn
+
+#endif /* BIT_DEPTH != 12 */
+
+static const int16_t vp9_subpel_filters[3][16][8] = {
+ [FILTER_8TAP_REGULAR] = {
+ { 0, 0, 0, 128, 0, 0, 0, 0 },
+ { 0, 1, -5, 126, 8, -3, 1, 0 },
+ { -1, 3, -10, 122, 18, -6, 2, 0 },
+ { -1, 4, -13, 118, 27, -9, 3, -1 },
+ { -1, 4, -16, 112, 37, -11, 4, -1 },
+ { -1, 5, -18, 105, 48, -14, 4, -1 },
+ { -1, 5, -19, 97, 58, -16, 5, -1 },
+ { -1, 6, -19, 88, 68, -18, 5, -1 },
+ { -1, 6, -19, 78, 78, -19, 6, -1 },
+ { -1, 5, -18, 68, 88, -19, 6, -1 },
+ { -1, 5, -16, 58, 97, -19, 5, -1 },
+ { -1, 4, -14, 48, 105, -18, 5, -1 },
+ { -1, 4, -11, 37, 112, -16, 4, -1 },
+ { -1, 3, -9, 27, 118, -13, 4, -1 },
+ { 0, 2, -6, 18, 122, -10, 3, -1 },
+ { 0, 1, -3, 8, 126, -5, 1, 0 },
+ }, [FILTER_8TAP_SHARP] = {
+ { 0, 0, 0, 128, 0, 0, 0, 0 },
+ { -1, 3, -7, 127, 8, -3, 1, 0 },
+ { -2, 5, -13, 125, 17, -6, 3, -1 },
+ { -3, 7, -17, 121, 27, -10, 5, -2 },
+ { -4, 9, -20, 115, 37, -13, 6, -2 },
+ { -4, 10, -23, 108, 48, -16, 8, -3 },
+ { -4, 10, -24, 100, 59, -19, 9, -3 },
+ { -4, 11, -24, 90, 70, -21, 10, -4 },
+ { -4, 11, -23, 80, 80, -23, 11, -4 },
+ { -4, 10, -21, 70, 90, -24, 11, -4 },
+ { -3, 9, -19, 59, 100, -24, 10, -4 },
+ { -3, 8, -16, 48, 108, -23, 10, -4 },
+ { -2, 6, -13, 37, 115, -20, 9, -4 },
+ { -2, 5, -10, 27, 121, -17, 7, -3 },
+ { -1, 3, -6, 17, 125, -13, 5, -2 },
+ { 0, 1, -3, 8, 127, -7, 3, -1 },
+ }, [FILTER_8TAP_SMOOTH] = {
+ { 0, 0, 0, 128, 0, 0, 0, 0 },
+ { -3, -1, 32, 64, 38, 1, -3, 0 },
+ { -2, -2, 29, 63, 41, 2, -3, 0 },
+ { -2, -2, 26, 63, 43, 4, -4, 0 },
+ { -2, -3, 24, 62, 46, 5, -4, 0 },
+ { -2, -3, 21, 60, 49, 7, -4, 0 },
+ { -1, -4, 18, 59, 51, 9, -4, 0 },
+ { -1, -4, 16, 57, 53, 12, -4, -1 },
+ { -1, -4, 14, 55, 55, 14, -4, -1 },
+ { -1, -4, 12, 53, 57, 16, -4, -1 },
+ { 0, -4, 9, 51, 59, 18, -4, -1 },
+ { 0, -4, 7, 49, 60, 21, -3, -2 },
+ { 0, -4, 5, 46, 62, 24, -3, -2 },
+ { 0, -4, 4, 43, 63, 26, -2, -2 },
+ { 0, -3, 2, 41, 63, 29, -2, -2 },
+ { 0, -3, 1, 38, 64, 32, -1, -3 },
+ }
+};
+
+#define FILTER_8TAP(src, x, F, stride) \
+ av_clip_pixel((F[0] * src[x + -3 * stride] + \
+ F[1] * src[x + -2 * stride] + \
+ F[2] * src[x + -1 * stride] + \
+ F[3] * src[x + +0 * stride] + \
+ F[4] * src[x + +1 * stride] + \
+ F[5] * src[x + +2 * stride] + \
+ F[6] * src[x + +3 * stride] + \
+ F[7] * src[x + +4 * stride] + 64) >> 7)
+
+static av_always_inline void do_8tap_1d_c(uint8_t *_dst, ptrdiff_t dst_stride,
+ const uint8_t *_src, ptrdiff_t src_stride,
+ int w, int h, ptrdiff_t ds,
+ const int16_t *filter, int avg)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_8TAP(src, x, filter, ds) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_8TAP(src, x, filter, ds);
+ }
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+#define filter_8tap_1d_fn(opn, opa, dir, ds) \
+static av_noinline void opn##_8tap_1d_##dir##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, const int16_t *filter) \
+{ \
+ do_8tap_1d_c(dst, dst_stride, src, src_stride, w, h, ds, filter, opa); \
+}
+
+filter_8tap_1d_fn(put, 0, v, src_stride / sizeof(pixel))
+filter_8tap_1d_fn(put, 0, h, 1)
+filter_8tap_1d_fn(avg, 1, v, src_stride / sizeof(pixel))
+filter_8tap_1d_fn(avg, 1, h, 1)
+
+#undef filter_8tap_1d_fn
+
+static av_always_inline void do_8tap_2d_c(uint8_t *_dst, ptrdiff_t dst_stride,
+ const uint8_t *_src, ptrdiff_t src_stride,
+ int w, int h, const int16_t *filterx,
+ const int16_t *filtery, int avg)
+{
+ int tmp_h = h + 7;
+ pixel tmp[64 * 71], *tmp_ptr = tmp;
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ src -= src_stride * 3;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ tmp_ptr[x] = FILTER_8TAP(src, x, filterx, 1);
+
+ tmp_ptr += 64;
+ src += src_stride;
+ } while (--tmp_h);
+
+ tmp_ptr = tmp + 64 * 3;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_8TAP(tmp_ptr, x, filtery, 64) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_8TAP(tmp_ptr, x, filtery, 64);
+ }
+
+ tmp_ptr += 64;
+ dst += dst_stride;
+ } while (--h);
+}
+
+#define filter_8tap_2d_fn(opn, opa) \
+static av_noinline void opn##_8tap_2d_hv_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, const int16_t *filterx, \
+ const int16_t *filtery) \
+{ \
+ do_8tap_2d_c(dst, dst_stride, src, src_stride, w, h, filterx, filtery, opa); \
+}
+
+filter_8tap_2d_fn(put, 0)
+filter_8tap_2d_fn(avg, 1)
+
+#undef filter_8tap_2d_fn
+
+#define filter_fn_1d(sz, dir, dir_m, type, type_idx, avg) \
+static void avg##_8tap_##type##_##sz##dir##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ avg##_8tap_1d_##dir##_c(dst, dst_stride, src, src_stride, sz, h, \
+ vp9_subpel_filters[type_idx][dir_m]); \
+}
+
+#define filter_fn_2d(sz, type, type_idx, avg) \
+static void avg##_8tap_##type##_##sz##hv_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ avg##_8tap_2d_hv_c(dst, dst_stride, src, src_stride, sz, h, \
+ vp9_subpel_filters[type_idx][mx], \
+ vp9_subpel_filters[type_idx][my]); \
+}
+
+#if BIT_DEPTH != 12
+
+#define FILTER_BILIN(src, x, mxy, stride) \
+ (src[x] + ((mxy * (src[x + stride] - src[x]) + 8) >> 4))
+
+static av_always_inline void do_bilin_1d_c(uint8_t *_dst, ptrdiff_t dst_stride,
+ const uint8_t *_src, ptrdiff_t src_stride,
+ int w, int h, ptrdiff_t ds, int mxy, int avg)
+{
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_BILIN(src, x, mxy, ds) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_BILIN(src, x, mxy, ds);
+ }
+
+ dst += dst_stride;
+ src += src_stride;
+ } while (--h);
+}
+
+#define bilin_1d_fn(opn, opa, dir, ds) \
+static av_noinline void opn##_bilin_1d_##dir##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, int mxy) \
+{ \
+ do_bilin_1d_c(dst, dst_stride, src, src_stride, w, h, ds, mxy, opa); \
+}
+
+bilin_1d_fn(put, 0, v, src_stride / sizeof(pixel))
+bilin_1d_fn(put, 0, h, 1)
+bilin_1d_fn(avg, 1, v, src_stride / sizeof(pixel))
+bilin_1d_fn(avg, 1, h, 1)
+
+#undef bilin_1d_fn
+
+static av_always_inline void do_bilin_2d_c(uint8_t *_dst, ptrdiff_t dst_stride,
+ const uint8_t *_src, ptrdiff_t src_stride,
+ int w, int h, int mx, int my, int avg)
+{
+ pixel tmp[64 * 65], *tmp_ptr = tmp;
+ int tmp_h = h + 1;
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ tmp_ptr[x] = FILTER_BILIN(src, x, mx, 1);
+
+ tmp_ptr += 64;
+ src += src_stride;
+ } while (--tmp_h);
+
+ tmp_ptr = tmp;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_BILIN(tmp_ptr, x, my, 64) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_BILIN(tmp_ptr, x, my, 64);
+ }
+
+ tmp_ptr += 64;
+ dst += dst_stride;
+ } while (--h);
+}
+
+#define bilin_2d_fn(opn, opa) \
+static av_noinline void opn##_bilin_2d_hv_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, int mx, int my) \
+{ \
+ do_bilin_2d_c(dst, dst_stride, src, src_stride, w, h, mx, my, opa); \
+}
+
+bilin_2d_fn(put, 0)
+bilin_2d_fn(avg, 1)
+
+#undef bilin_2d_fn
+
+#define bilinf_fn_1d(sz, dir, dir_m, avg) \
+static void avg##_bilin_##sz##dir##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ avg##_bilin_1d_##dir##_c(dst, dst_stride, src, src_stride, sz, h, dir_m); \
+}
+
+#define bilinf_fn_2d(sz, avg) \
+static void avg##_bilin_##sz##hv_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ avg##_bilin_2d_hv_c(dst, dst_stride, src, src_stride, sz, h, mx, my); \
+}
+
+#else
+
+#define bilinf_fn_1d(a, b, c, d)
+#define bilinf_fn_2d(a, b)
+
+#endif
+
+#define filter_fn(sz, avg) \
+filter_fn_1d(sz, h, mx, regular, FILTER_8TAP_REGULAR, avg) \
+filter_fn_1d(sz, v, my, regular, FILTER_8TAP_REGULAR, avg) \
+filter_fn_2d(sz, regular, FILTER_8TAP_REGULAR, avg) \
+filter_fn_1d(sz, h, mx, smooth, FILTER_8TAP_SMOOTH, avg) \
+filter_fn_1d(sz, v, my, smooth, FILTER_8TAP_SMOOTH, avg) \
+filter_fn_2d(sz, smooth, FILTER_8TAP_SMOOTH, avg) \
+filter_fn_1d(sz, h, mx, sharp, FILTER_8TAP_SHARP, avg) \
+filter_fn_1d(sz, v, my, sharp, FILTER_8TAP_SHARP, avg) \
+filter_fn_2d(sz, sharp, FILTER_8TAP_SHARP, avg) \
+bilinf_fn_1d(sz, h, mx, avg) \
+bilinf_fn_1d(sz, v, my, avg) \
+bilinf_fn_2d(sz, avg)
+
+#define filter_fn_set(avg) \
+filter_fn(64, avg) \
+filter_fn(32, avg) \
+filter_fn(16, avg) \
+filter_fn(8, avg) \
+filter_fn(4, avg)
+
+filter_fn_set(put)
+filter_fn_set(avg)
+
+#undef filter_fn
+#undef filter_fn_set
+#undef filter_fn_1d
+#undef filter_fn_2d
+#undef bilinf_fn_1d
+#undef bilinf_fn_2d
+
+#if BIT_DEPTH != 8
+void vp9dsp_mc_init_10(VP9DSPContext *dsp);
+#endif
+#if BIT_DEPTH != 10
+static
+#endif
+av_cold void FUNC(vp9dsp_mc_init)(VP9DSPContext *dsp)
+{
+#if BIT_DEPTH == 12
+ vp9dsp_mc_init_10(dsp);
+#else /* BIT_DEPTH == 12 */
+
+#define init_fpel(idx1, idx2, sz, type) \
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = type##sz##_c; \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = type##sz##_c; \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = type##sz##_c; \
+ dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = type##sz##_c
+
+#define init_copy_avg(idx, sz) \
+ init_fpel(idx, 0, sz, copy); \
+ init_fpel(idx, 1, sz, avg)
+
+ init_copy_avg(0, 64);
+ init_copy_avg(1, 32);
+ init_copy_avg(2, 16);
+ init_copy_avg(3, 8);
+ init_copy_avg(4, 4);
+
+#undef init_copy_avg
+#undef init_fpel
+
+#endif /* BIT_DEPTH == 12 */
+
+#define init_subpel1_bd_aware(idx1, idx2, idxh, idxv, sz, dir, type) \
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][idxh][idxv] = type##_8tap_smooth_##sz##dir##_c; \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type##_8tap_regular_##sz##dir##_c; \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][idxh][idxv] = type##_8tap_sharp_##sz##dir##_c
+
+#if BIT_DEPTH == 12
+#define init_subpel1 init_subpel1_bd_aware
+#else
+#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type) \
+ init_subpel1_bd_aware(idx1, idx2, idxh, idxv, sz, dir, type); \
+ dsp->mc[idx1][FILTER_BILINEAR ][idx2][idxh][idxv] = type##_bilin_##sz##dir##_c
+#endif
+
+#define init_subpel2(idx, idxh, idxv, dir, type) \
+ init_subpel1(0, idx, idxh, idxv, 64, dir, type); \
+ init_subpel1(1, idx, idxh, idxv, 32, dir, type); \
+ init_subpel1(2, idx, idxh, idxv, 16, dir, type); \
+ init_subpel1(3, idx, idxh, idxv, 8, dir, type); \
+ init_subpel1(4, idx, idxh, idxv, 4, dir, type)
+
+#define init_subpel3(idx, type) \
+ init_subpel2(idx, 1, 1, hv, type); \
+ init_subpel2(idx, 0, 1, v, type); \
+ init_subpel2(idx, 1, 0, h, type)
+
+ init_subpel3(0, put);
+ init_subpel3(1, avg);
+
+#undef init_subpel1
+#undef init_subpel2
+#undef init_subpel3
+#undef init_subpel1_bd_aware
+}
+
+static av_always_inline void do_scaled_8tap_c(uint8_t *_dst, ptrdiff_t dst_stride,
+ const uint8_t *_src, ptrdiff_t src_stride,
+ int w, int h, int mx, int my,
+ int dx, int dy, int avg,
+ const int16_t (*filters)[8])
+{
+ int tmp_h = (((h - 1) * dy + my) >> 4) + 8;
+ pixel tmp[64 * 135], *tmp_ptr = tmp;
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ src -= src_stride * 3;
+ do {
+ int x;
+ int imx = mx, ioff = 0;
+
+ for (x = 0; x < w; x++) {
+ tmp_ptr[x] = FILTER_8TAP(src, ioff, filters[imx], 1);
+ imx += dx;
+ ioff += imx >> 4;
+ imx &= 0xf;
+ }
+
+ tmp_ptr += 64;
+ src += src_stride;
+ } while (--tmp_h);
+
+ tmp_ptr = tmp + 64 * 3;
+ do {
+ int x;
+ const int16_t *filter = filters[my];
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_8TAP(tmp_ptr, x, filter, 64) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_8TAP(tmp_ptr, x, filter, 64);
+ }
+
+ my += dy;
+ tmp_ptr += (my >> 4) * 64;
+ my &= 0xf;
+ dst += dst_stride;
+ } while (--h);
+}
+
+#define scaled_filter_8tap_fn(opn, opa) \
+static av_noinline void opn##_scaled_8tap_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, int mx, int my, int dx, int dy, \
+ const int16_t (*filters)[8]) \
+{ \
+ do_scaled_8tap_c(dst, dst_stride, src, src_stride, w, h, mx, my, dx, dy, \
+ opa, filters); \
+}
+
+scaled_filter_8tap_fn(put, 0)
+scaled_filter_8tap_fn(avg, 1)
+
+#undef scaled_filter_8tap_fn
+
+#undef FILTER_8TAP
+
+#define scaled_filter_fn(sz, type, type_idx, avg) \
+static void avg##_scaled_##type##_##sz##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my, int dx, int dy) \
+{ \
+ avg##_scaled_8tap_c(dst, dst_stride, src, src_stride, sz, h, mx, my, dx, dy, \
+ vp9_subpel_filters[type_idx]); \
+}
+
+#if BIT_DEPTH != 12
+
+static av_always_inline void do_scaled_bilin_c(uint8_t *_dst, ptrdiff_t dst_stride,
+ const uint8_t *_src, ptrdiff_t src_stride,
+ int w, int h, int mx, int my,
+ int dx, int dy, int avg)
+{
+ pixel tmp[64 * 129], *tmp_ptr = tmp;
+ int tmp_h = (((h - 1) * dy + my) >> 4) + 2;
+ pixel *dst = (pixel *) _dst;
+ const pixel *src = (const pixel *) _src;
+
+ dst_stride /= sizeof(pixel);
+ src_stride /= sizeof(pixel);
+ do {
+ int x;
+ int imx = mx, ioff = 0;
+
+ for (x = 0; x < w; x++) {
+ tmp_ptr[x] = FILTER_BILIN(src, ioff, imx, 1);
+ imx += dx;
+ ioff += imx >> 4;
+ imx &= 0xf;
+ }
+
+ tmp_ptr += 64;
+ src += src_stride;
+ } while (--tmp_h);
+
+ tmp_ptr = tmp;
+ do {
+ int x;
+
+ for (x = 0; x < w; x++)
+ if (avg) {
+ dst[x] = (dst[x] + FILTER_BILIN(tmp_ptr, x, my, 64) + 1) >> 1;
+ } else {
+ dst[x] = FILTER_BILIN(tmp_ptr, x, my, 64);
+ }
+
+ my += dy;
+ tmp_ptr += (my >> 4) * 64;
+ my &= 0xf;
+ dst += dst_stride;
+ } while (--h);
+}
+
+#define scaled_bilin_fn(opn, opa) \
+static av_noinline void opn##_scaled_bilin_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int w, int h, int mx, int my, int dx, int dy) \
+{ \
+ do_scaled_bilin_c(dst, dst_stride, src, src_stride, w, h, mx, my, dx, dy, opa); \
+}
+
+scaled_bilin_fn(put, 0)
+scaled_bilin_fn(avg, 1)
+
+#undef scaled_bilin_fn
+
+#undef FILTER_BILIN
+
+#define scaled_bilinf_fn(sz, avg) \
+static void avg##_scaled_bilin_##sz##_c(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my, int dx, int dy) \
+{ \
+ avg##_scaled_bilin_c(dst, dst_stride, src, src_stride, sz, h, mx, my, dx, dy); \
+}
+
+#else
+
+#define scaled_bilinf_fn(a, b)
+
+#endif
+
+#define scaled_filter_fns(sz, avg) \
+scaled_filter_fn(sz, regular, FILTER_8TAP_REGULAR, avg) \
+scaled_filter_fn(sz, smooth, FILTER_8TAP_SMOOTH, avg) \
+scaled_filter_fn(sz, sharp, FILTER_8TAP_SHARP, avg) \
+scaled_bilinf_fn(sz, avg)
+
+#define scaled_filter_fn_set(avg) \
+scaled_filter_fns(64, avg) \
+scaled_filter_fns(32, avg) \
+scaled_filter_fns(16, avg) \
+scaled_filter_fns(8, avg) \
+scaled_filter_fns(4, avg)
+
+scaled_filter_fn_set(put)
+scaled_filter_fn_set(avg)
+
+#undef scaled_filter_fns
+#undef scaled_filter_fn_set
+#undef scaled_filter_fn
+#undef scaled_bilinf_fn
+
+#if BIT_DEPTH != 8
+void vp9dsp_scaled_mc_init_10(VP9DSPContext *dsp);
+#endif
+#if BIT_DEPTH != 10
+static
+#endif
+av_cold void FUNC(vp9dsp_scaled_mc_init)(VP9DSPContext *dsp)
+{
+#define init_scaled_bd_aware(idx1, idx2, sz, type) \
+ dsp->smc[idx1][FILTER_8TAP_SMOOTH ][idx2] = type##_scaled_smooth_##sz##_c; \
+ dsp->smc[idx1][FILTER_8TAP_REGULAR][idx2] = type##_scaled_regular_##sz##_c; \
+ dsp->smc[idx1][FILTER_8TAP_SHARP ][idx2] = type##_scaled_sharp_##sz##_c
+
+#if BIT_DEPTH == 12
+ vp9dsp_scaled_mc_init_10(dsp);
+#define init_scaled(a,b,c,d) init_scaled_bd_aware(a,b,c,d)
+#else
+#define init_scaled(idx1, idx2, sz, type) \
+ init_scaled_bd_aware(idx1, idx2, sz, type); \
+ dsp->smc[idx1][FILTER_BILINEAR ][idx2] = type##_scaled_bilin_##sz##_c
+#endif
+
+#define init_scaled_put_avg(idx, sz) \
+ init_scaled(idx, 0, sz, put); \
+ init_scaled(idx, 1, sz, avg)
+
+ init_scaled_put_avg(0, 64);
+ init_scaled_put_avg(1, 32);
+ init_scaled_put_avg(2, 16);
+ init_scaled_put_avg(3, 8);
+ init_scaled_put_avg(4, 4);
+
+#undef init_scaled_put_avg
+#undef init_scaled
+#undef init_scaled_bd_aware
+}
+
+av_cold void FUNC(ff_vp9dsp_init)(VP9DSPContext *dsp)
+{
+ FUNC(vp9dsp_intrapred_init)(dsp);
+ vp9dsp_itxfm_init(dsp);
+ vp9dsp_loopfilter_init(dsp);
+ FUNC(vp9dsp_mc_init)(dsp);
+ FUNC(vp9dsp_scaled_mc_init)(dsp);
+}
diff --git a/libavcodec/vp9mvs.c b/libavcodec/vp9mvs.c
deleted file mode 100644
index 1f65aaac0a..0000000000
--- a/libavcodec/vp9mvs.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * VP9 compatible video decoder
- *
- * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
- * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "internal.h"
-#include "vp56.h"
-#include "vp9.h"
-#include "vp9data.h"
-
-static av_always_inline void clamp_mv(VP56mv *dst, const VP56mv *src,
- VP9Context *s)
-{
- dst->x = av_clip(src->x, s->min_mv.x, s->max_mv.x);
- dst->y = av_clip(src->y, s->min_mv.y, s->max_mv.y);
-}
-
-static void find_ref_mvs(VP9Context *s,
- VP56mv *pmv, int ref, int z, int idx, int sb)
-{
- static const int8_t mv_ref_blk_off[N_BS_SIZES][8][2] = {
- [BS_64x64] = { { 3, -1 }, { -1, 3 }, { 4, -1 }, { -1, 4 },
- { -1, -1 }, { 0, -1 }, { -1, 0 }, { 6, -1 } },
- [BS_64x32] = { { 0, -1 }, { -1, 0 }, { 4, -1 }, { -1, 2 },
- { -1, -1 }, { 0, -3 }, { -3, 0 }, { 2, -1 } },
- [BS_32x64] = { { -1, 0 }, { 0, -1 }, { -1, 4 }, { 2, -1 },
- { -1, -1 }, { -3, 0 }, { 0, -3 }, { -1, 2 } },
- [BS_32x32] = { { 1, -1 }, { -1, 1 }, { 2, -1 }, { -1, 2 },
- { -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } },
- [BS_32x16] = { { 0, -1 }, { -1, 0 }, { 2, -1 }, { -1, -1 },
- { -1, 1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } },
- [BS_16x32] = { { -1, 0 }, { 0, -1 }, { -1, 2 }, { -1, -1 },
- { 1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 } },
- [BS_16x16] = { { 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, 1 },
- { -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } },
- [BS_16x8] = { { 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, -1 },
- { 0, -2 }, { -2, 0 }, { -2, -1 }, { -1, -2 } },
- [BS_8x16] = { { -1, 0 }, { 0, -1 }, { -1, 1 }, { -1, -1 },
- { -2, 0 }, { 0, -2 }, { -1, -2 }, { -2, -1 } },
- [BS_8x8] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
- { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
- [BS_8x4] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
- { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
- [BS_4x8] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
- { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
- [BS_4x4] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
- { -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
- };
- VP9Block *const b = &s->b;
- int row = b->row, col = b->col, row7 = b->row7;
- const int8_t (*p)[2] = mv_ref_blk_off[b->bs];
-#define INVALID_MV 0x80008000U
- uint32_t mem = INVALID_MV;
- int i;
-
-#define RETURN_DIRECT_MV(mv) \
- do { \
- uint32_t m = AV_RN32A(&mv); \
- if (!idx) { \
- AV_WN32A(pmv, m); \
- return; \
- } else if (mem == INVALID_MV) { \
- mem = m; \
- } else if (m != mem) { \
- AV_WN32A(pmv, m); \
- return; \
- } \
- } while (0)
-
- if (sb >= 0) {
- if (sb == 2 || sb == 1) {
- RETURN_DIRECT_MV(b->mv[0][z]);
- } else if (sb == 3) {
- RETURN_DIRECT_MV(b->mv[2][z]);
- RETURN_DIRECT_MV(b->mv[1][z]);
- RETURN_DIRECT_MV(b->mv[0][z]);
- }
-
-#define RETURN_MV(mv) \
- do { \
- if (sb > 0) { \
- VP56mv tmp; \
- uint32_t m; \
- clamp_mv(&tmp, &mv, s); \
- m = AV_RN32A(&tmp); \
- if (!idx) { \
- AV_WN32A(pmv, m); \
- return; \
- } else if (mem == INVALID_MV) { \
- mem = m; \
- } else if (m != mem) { \
- AV_WN32A(pmv, m); \
- return; \
- } \
- } else { \
- uint32_t m = AV_RN32A(&mv); \
- if (!idx) { \
- clamp_mv(pmv, &mv, s); \
- return; \
- } else if (mem == INVALID_MV) { \
- mem = m; \
- } else if (m != mem) { \
- clamp_mv(pmv, &mv, s); \
- return; \
- } \
- } \
- } while (0)
-
- if (row > 0) {
- VP9MVRefPair *mv = &s->mv[0][(row - 1) * s->sb_cols * 8 + col];
-
- if (mv->ref[0] == ref)
- RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][0]);
- else if (mv->ref[1] == ref)
- RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][1]);
- }
- if (col > s->tiling.tile_col_start) {
- VP9MVRefPair *mv = &s->mv[0][row * s->sb_cols * 8 + col - 1];
-
- if (mv->ref[0] == ref)
- RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][0]);
- else if (mv->ref[1] == ref)
- RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][1]);
- }
- i = 2;
- } else {
- i = 0;
- }
-
- // previously coded MVs in the neighborhood, using same reference frame
- for (; i < 8; i++) {
- int c = p[i][0] + col, r = p[i][1] + row;
-
- if (c >= s->tiling.tile_col_start && c < s->cols &&
- r >= 0 && r < s->rows) {
- VP9MVRefPair *mv = &s->mv[0][r * s->sb_cols * 8 + c];
-
- if (mv->ref[0] == ref)
- RETURN_MV(mv->mv[0]);
- else if (mv->ref[1] == ref)
- RETURN_MV(mv->mv[1]);
- }
- }
-
- // MV at this position in previous frame, using same reference frame
- if (s->use_last_frame_mvs) {
- VP9MVRefPair *mv = &s->mv[1][row * s->sb_cols * 8 + col];
-
- if (mv->ref[0] == ref)
- RETURN_MV(mv->mv[0]);
- else if (mv->ref[1] == ref)
- RETURN_MV(mv->mv[1]);
- }
-
-#define RETURN_SCALE_MV(mv, scale) \
- do { \
- if (scale) { \
- VP56mv mv_temp = { -mv.x, -mv.y }; \
- RETURN_MV(mv_temp); \
- } else { \
- RETURN_MV(mv); \
- } \
- } while (0)
-
- // previously coded MVs in the neighborhood, using different reference frame
- for (i = 0; i < 8; i++) {
- int c = p[i][0] + col, r = p[i][1] + row;
-
- if (c >= s->tiling.tile_col_start && c < s->cols &&
- r >= 0 && r < s->rows) {
- VP9MVRefPair *mv = &s->mv[0][r * s->sb_cols * 8 + c];
-
- if (mv->ref[0] != ref && mv->ref[0] >= 0)
- RETURN_SCALE_MV(mv->mv[0],
- s->signbias[mv->ref[0]] != s->signbias[ref]);
- if (mv->ref[1] != ref && mv->ref[1] >= 0 &&
- // BUG - libvpx has this condition regardless of whether
- // we used the first ref MV and pre-scaling
- AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) {
- RETURN_SCALE_MV(mv->mv[1],
- s->signbias[mv->ref[1]] != s->signbias[ref]);
- }
- }
- }
-
- // MV at this position in previous frame, using different reference frame
- if (s->use_last_frame_mvs) {
- VP9MVRefPair *mv = &s->mv[1][row * s->sb_cols * 8 + col];
-
- if (mv->ref[0] != ref && mv->ref[0] >= 0)
- RETURN_SCALE_MV(mv->mv[0],
- s->signbias[mv->ref[0]] != s->signbias[ref]);
- if (mv->ref[1] != ref && mv->ref[1] >= 0 &&
- // BUG - libvpx has this condition regardless of whether
- // we used the first ref MV and pre-scaling
- AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) {
- RETURN_SCALE_MV(mv->mv[1],
- s->signbias[mv->ref[1]] != s->signbias[ref]);
- }
- }
-
- AV_ZERO32(pmv);
-#undef INVALID_MV
-#undef RETURN_MV
-#undef RETURN_SCALE_MV
-}
-
-static av_always_inline int read_mv_component(VP9Context *s, int idx, int hp)
-{
- int bit, sign = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].sign);
- int n, c = vp8_rac_get_tree(&s->c, ff_vp9_mv_class_tree,
- s->prob.p.mv_comp[idx].classes);
-
- s->counts.mv_comp[idx].sign[sign]++;
- s->counts.mv_comp[idx].classes[c]++;
- if (c) {
- int m;
-
- for (n = 0, m = 0; m < c; m++) {
- bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].bits[m]);
- n |= bit << m;
- s->counts.mv_comp[idx].bits[m][bit]++;
- }
- n <<= 3;
- bit = vp8_rac_get_tree(&s->c, ff_vp9_mv_fp_tree,
- s->prob.p.mv_comp[idx].fp);
- n |= bit << 1;
- s->counts.mv_comp[idx].fp[bit]++;
- if (hp) {
- bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].hp);
- s->counts.mv_comp[idx].hp[bit]++;
- n |= bit;
- } else {
- n |= 1;
- // bug in libvpx - we count for bw entropy purposes even if the
- // bit wasn't coded
- s->counts.mv_comp[idx].hp[1]++;
- }
- n += 8 << c;
- } else {
- n = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0);
- s->counts.mv_comp[idx].class0[n]++;
- bit = vp8_rac_get_tree(&s->c, ff_vp9_mv_fp_tree,
- s->prob.p.mv_comp[idx].class0_fp[n]);
- s->counts.mv_comp[idx].class0_fp[n][bit]++;
- n = (n << 3) | (bit << 1);
- if (hp) {
- bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0_hp);
- s->counts.mv_comp[idx].class0_hp[bit]++;
- n |= bit;
- } else {
- n |= 1;
- // bug in libvpx - we count for bw entropy purposes even if the
- // bit wasn't coded
- s->counts.mv_comp[idx].class0_hp[1]++;
- }
- }
-
- return sign ? -(n + 1) : (n + 1);
-}
-
-void ff_vp9_fill_mv(VP9Context *s, VP56mv *mv, int mode, int sb)
-{
- VP9Block *const b = &s->b;
-
- if (mode == ZEROMV) {
- memset(mv, 0, sizeof(*mv) * 2);
- } else {
- int hp;
-
- // FIXME cache this value and reuse for other subblocks
- find_ref_mvs(s, &mv[0], b->ref[0], 0, mode == NEARMV,
- mode == NEWMV ? -1 : sb);
- // FIXME maybe move this code into find_ref_mvs()
- if ((mode == NEWMV || sb == -1) &&
- !(hp = s->highprecisionmvs &&
- abs(mv[0].x) < 64 && abs(mv[0].y) < 64)) {
- if (mv[0].y & 1) {
- if (mv[0].y < 0)
- mv[0].y++;
- else
- mv[0].y--;
- }
- if (mv[0].x & 1) {
- if (mv[0].x < 0)
- mv[0].x++;
- else
- mv[0].x--;
- }
- }
- if (mode == NEWMV) {
- enum MVJoint j = vp8_rac_get_tree(&s->c, ff_vp9_mv_joint_tree,
- s->prob.p.mv_joint);
-
- s->counts.mv_joint[j]++;
- if (j >= MV_JOINT_V)
- mv[0].y += read_mv_component(s, 0, hp);
- if (j & 1)
- mv[0].x += read_mv_component(s, 1, hp);
- }
-
- if (b->comp) {
- // FIXME cache this value and reuse for other subblocks
- find_ref_mvs(s, &mv[1], b->ref[1], 1, mode == NEARMV,
- mode == NEWMV ? -1 : sb);
- if ((mode == NEWMV || sb == -1) &&
- !(hp = s->highprecisionmvs &&
- abs(mv[1].x) < 64 && abs(mv[1].y) < 64)) {
- if (mv[1].y & 1) {
- if (mv[1].y < 0)
- mv[1].y++;
- else
- mv[1].y--;
- }
- if (mv[1].x & 1) {
- if (mv[1].x < 0)
- mv[1].x++;
- else
- mv[1].x--;
- }
- }
- if (mode == NEWMV) {
- enum MVJoint j = vp8_rac_get_tree(&s->c, ff_vp9_mv_joint_tree,
- s->prob.p.mv_joint);
-
- s->counts.mv_joint[j]++;
- if (j >= MV_JOINT_V)
- mv[1].y += read_mv_component(s, 0, hp);
- if (j & 1)
- mv[1].x += read_mv_component(s, 1, hp);
- }
- }
- }
-}
diff --git a/libavcodec/vp9prob.c b/libavcodec/vp9prob.c
deleted file mode 100644
index b8a7c22af4..0000000000
--- a/libavcodec/vp9prob.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * VP9 compatible video decoder
- *
- * Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
- * Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "vp56.h"
-#include "vp9.h"
-#include "vp9data.h"
-
-static av_always_inline void adapt_prob(uint8_t *p, unsigned ct0, unsigned ct1,
- int max_count, int update_factor)
-{
- unsigned ct = ct0 + ct1, p2, p1;
-
- if (!ct)
- return;
-
- p1 = *p;
- p2 = ((ct0 << 8) + (ct >> 1)) / ct;
- p2 = av_clip(p2, 1, 255);
- ct = FFMIN(ct, max_count);
- update_factor = FASTDIV(update_factor * ct, max_count);
-
- // (p1 * (256 - update_factor) + p2 * update_factor + 128) >> 8
- *p = p1 + (((p2 - p1) * update_factor + 128) >> 8);
-}
-
-void ff_vp9_adapt_probs(VP9Context *s)
-{
- int i, j, k, l, m;
- ProbContext *p = &s->prob_ctx[s->framectxid].p;
- int uf = (s->keyframe || s->intraonly || !s->last_keyframe) ? 112 : 128;
-
- // coefficients
- for (i = 0; i < 4; i++)
- for (j = 0; j < 2; j++)
- for (k = 0; k < 2; k++)
- for (l = 0; l < 6; l++)
- for (m = 0; m < 6; m++) {
- uint8_t *pp = s->prob_ctx[s->framectxid].coef[i][j][k][l][m];
- unsigned *e = s->counts.eob[i][j][k][l][m];
- unsigned *c = s->counts.coef[i][j][k][l][m];
-
- if (l == 0 && m >= 3) // dc only has 3 pt
- break;
-
- adapt_prob(&pp[0], e[0], e[1], 24, uf);
- adapt_prob(&pp[1], c[0], c[1] + c[2], 24, uf);
- adapt_prob(&pp[2], c[1], c[2], 24, uf);
- }
-
- if (s->keyframe || s->intraonly) {
- memcpy(p->skip, s->prob.p.skip, sizeof(p->skip));
- memcpy(p->tx32p, s->prob.p.tx32p, sizeof(p->tx32p));
- memcpy(p->tx16p, s->prob.p.tx16p, sizeof(p->tx16p));
- memcpy(p->tx8p, s->prob.p.tx8p, sizeof(p->tx8p));
- return;
- }
-
- // skip flag
- for (i = 0; i < 3; i++)
- adapt_prob(&p->skip[i], s->counts.skip[i][0],
- s->counts.skip[i][1], 20, 128);
-
- // intra/inter flag
- for (i = 0; i < 4; i++)
- adapt_prob(&p->intra[i], s->counts.intra[i][0],
- s->counts.intra[i][1], 20, 128);
-
- // comppred flag
- if (s->comppredmode == PRED_SWITCHABLE) {
- for (i = 0; i < 5; i++)
- adapt_prob(&p->comp[i], s->counts.comp[i][0],
- s->counts.comp[i][1], 20, 128);
- }
-
- // reference frames
- if (s->comppredmode != PRED_SINGLEREF) {
- for (i = 0; i < 5; i++)
- adapt_prob(&p->comp_ref[i], s->counts.comp_ref[i][0],
- s->counts.comp_ref[i][1], 20, 128);
- }
-
- if (s->comppredmode != PRED_COMPREF) {
- for (i = 0; i < 5; i++) {
- uint8_t *pp = p->single_ref[i];
- unsigned (*c)[2] = s->counts.single_ref[i];
-
- adapt_prob(&pp[0], c[0][0], c[0][1], 20, 128);
- adapt_prob(&pp[1], c[1][0], c[1][1], 20, 128);
- }
- }
-
- // block partitioning
- for (i = 0; i < 4; i++)
- for (j = 0; j < 4; j++) {
- uint8_t *pp = p->partition[i][j];
- unsigned *c = s->counts.partition[i][j];
-
- adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
- adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
- adapt_prob(&pp[2], c[2], c[3], 20, 128);
- }
-
- // tx size
- if (s->txfmmode == TX_SWITCHABLE) {
- for (i = 0; i < 2; i++) {
- unsigned *c16 = s->counts.tx16p[i], *c32 = s->counts.tx32p[i];
-
- adapt_prob(&p->tx8p[i], s->counts.tx8p[i][0],
- s->counts.tx8p[i][1], 20, 128);
- adapt_prob(&p->tx16p[i][0], c16[0], c16[1] + c16[2], 20, 128);
- adapt_prob(&p->tx16p[i][1], c16[1], c16[2], 20, 128);
- adapt_prob(&p->tx32p[i][0], c32[0], c32[1] + c32[2] + c32[3], 20, 128);
- adapt_prob(&p->tx32p[i][1], c32[1], c32[2] + c32[3], 20, 128);
- adapt_prob(&p->tx32p[i][2], c32[2], c32[3], 20, 128);
- }
- }
-
- // interpolation filter
- if (s->filtermode == FILTER_SWITCHABLE) {
- for (i = 0; i < 4; i++) {
- uint8_t *pp = p->filter[i];
- unsigned *c = s->counts.filter[i];
-
- adapt_prob(&pp[0], c[0], c[1] + c[2], 20, 128);
- adapt_prob(&pp[1], c[1], c[2], 20, 128);
- }
- }
-
- // inter modes
- for (i = 0; i < 7; i++) {
- uint8_t *pp = p->mv_mode[i];
- unsigned *c = s->counts.mv_mode[i];
-
- adapt_prob(&pp[0], c[2], c[1] + c[0] + c[3], 20, 128);
- adapt_prob(&pp[1], c[0], c[1] + c[3], 20, 128);
- adapt_prob(&pp[2], c[1], c[3], 20, 128);
- }
-
- // mv joints
- {
- uint8_t *pp = p->mv_joint;
- unsigned *c = s->counts.mv_joint;
-
- adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
- adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
- adapt_prob(&pp[2], c[2], c[3], 20, 128);
- }
-
- // mv components
- for (i = 0; i < 2; i++) {
- uint8_t *pp;
- unsigned *c, (*c2)[2], sum;
-
- adapt_prob(&p->mv_comp[i].sign, s->counts.mv_comp[i].sign[0],
- s->counts.mv_comp[i].sign[1], 20, 128);
-
- pp = p->mv_comp[i].classes;
- c = s->counts.mv_comp[i].classes;
- sum = c[1] + c[2] + c[3] + c[4] + c[5] +
- c[6] + c[7] + c[8] + c[9] + c[10];
- adapt_prob(&pp[0], c[0], sum, 20, 128);
- sum -= c[1];
- adapt_prob(&pp[1], c[1], sum, 20, 128);
- sum -= c[2] + c[3];
- adapt_prob(&pp[2], c[2] + c[3], sum, 20, 128);
- adapt_prob(&pp[3], c[2], c[3], 20, 128);
- sum -= c[4] + c[5];
- adapt_prob(&pp[4], c[4] + c[5], sum, 20, 128);
- adapt_prob(&pp[5], c[4], c[5], 20, 128);
- sum -= c[6];
- adapt_prob(&pp[6], c[6], sum, 20, 128);
- adapt_prob(&pp[7], c[7] + c[8], c[9] + c[10], 20, 128);
- adapt_prob(&pp[8], c[7], c[8], 20, 128);
- adapt_prob(&pp[9], c[9], c[10], 20, 128);
-
- adapt_prob(&p->mv_comp[i].class0, s->counts.mv_comp[i].class0[0],
- s->counts.mv_comp[i].class0[1], 20, 128);
- pp = p->mv_comp[i].bits;
- c2 = s->counts.mv_comp[i].bits;
- for (j = 0; j < 10; j++)
- adapt_prob(&pp[j], c2[j][0], c2[j][1], 20, 128);
-
- for (j = 0; j < 2; j++) {
- pp = p->mv_comp[i].class0_fp[j];
- c = s->counts.mv_comp[i].class0_fp[j];
- adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
- adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
- adapt_prob(&pp[2], c[2], c[3], 20, 128);
- }
- pp = p->mv_comp[i].fp;
- c = s->counts.mv_comp[i].fp;
- adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
- adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
- adapt_prob(&pp[2], c[2], c[3], 20, 128);
-
- if (s->highprecisionmvs) {
- adapt_prob(&p->mv_comp[i].class0_hp,
- s->counts.mv_comp[i].class0_hp[0],
- s->counts.mv_comp[i].class0_hp[1], 20, 128);
- adapt_prob(&p->mv_comp[i].hp, s->counts.mv_comp[i].hp[0],
- s->counts.mv_comp[i].hp[1], 20, 128);
- }
- }
-
- // y intra modes
- for (i = 0; i < 4; i++) {
- uint8_t *pp = p->y_mode[i];
- unsigned *c = s->counts.y_mode[i], sum, s2;
-
- sum = c[0] + c[1] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9];
- adapt_prob(&pp[0], c[DC_PRED], sum, 20, 128);
- sum -= c[TM_VP8_PRED];
- adapt_prob(&pp[1], c[TM_VP8_PRED], sum, 20, 128);
- sum -= c[VERT_PRED];
- adapt_prob(&pp[2], c[VERT_PRED], sum, 20, 128);
- s2 = c[HOR_PRED] + c[DIAG_DOWN_RIGHT_PRED] + c[VERT_RIGHT_PRED];
- sum -= s2;
- adapt_prob(&pp[3], s2, sum, 20, 128);
- s2 -= c[HOR_PRED];
- adapt_prob(&pp[4], c[HOR_PRED], s2, 20, 128);
- adapt_prob(&pp[5], c[DIAG_DOWN_RIGHT_PRED], c[VERT_RIGHT_PRED],
- 20, 128);
- sum -= c[DIAG_DOWN_LEFT_PRED];
- adapt_prob(&pp[6], c[DIAG_DOWN_LEFT_PRED], sum, 20, 128);
- sum -= c[VERT_LEFT_PRED];
- adapt_prob(&pp[7], c[VERT_LEFT_PRED], sum, 20, 128);
- adapt_prob(&pp[8], c[HOR_DOWN_PRED], c[HOR_UP_PRED], 20, 128);
- }
-
- // uv intra modes
- for (i = 0; i < 10; i++) {
- uint8_t *pp = p->uv_mode[i];
- unsigned *c = s->counts.uv_mode[i], sum, s2;
-
- sum = c[0] + c[1] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9];
- adapt_prob(&pp[0], c[DC_PRED], sum, 20, 128);
- sum -= c[TM_VP8_PRED];
- adapt_prob(&pp[1], c[TM_VP8_PRED], sum, 20, 128);
- sum -= c[VERT_PRED];
- adapt_prob(&pp[2], c[VERT_PRED], sum, 20, 128);
- s2 = c[HOR_PRED] + c[DIAG_DOWN_RIGHT_PRED] + c[VERT_RIGHT_PRED];
- sum -= s2;
- adapt_prob(&pp[3], s2, sum, 20, 128);
- s2 -= c[HOR_PRED];
- adapt_prob(&pp[4], c[HOR_PRED], s2, 20, 128);
- adapt_prob(&pp[5], c[DIAG_DOWN_RIGHT_PRED], c[VERT_RIGHT_PRED],
- 20, 128);
- sum -= c[DIAG_DOWN_LEFT_PRED];
- adapt_prob(&pp[6], c[DIAG_DOWN_LEFT_PRED], sum, 20, 128);
- sum -= c[VERT_LEFT_PRED];
- adapt_prob(&pp[7], c[VERT_LEFT_PRED], sum, 20, 128);
- adapt_prob(&pp[8], c[HOR_DOWN_PRED], c[HOR_UP_PRED], 20, 128);
- }
-}
diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c
index 553929d195..45eb1574f6 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -1,21 +1,21 @@
/*
* Westwood Studios VQA Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -128,7 +128,7 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
/* make sure the extradata made it */
if (s->avctx->extradata_size != VQA_HEADER_SIZE) {
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: expected extradata size of %d\n", VQA_HEADER_SIZE);
+ av_log(s->avctx, AV_LOG_ERROR, "expected extradata size of %d\n", VQA_HEADER_SIZE);
return AVERROR(EINVAL);
}
@@ -162,8 +162,7 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
- if (s->width & (s->vector_width - 1) ||
- s->height & (s->vector_height - 1)) {
+ if (s->width % s->vector_width || s->height % s->vector_height) {
av_log(avctx, AV_LOG_ERROR, "Image size not multiple of block size\n");
return AVERROR_INVALIDDATA;
}
@@ -180,7 +179,7 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx)
/* allocate decode buffer */
s->decode_buffer_size = (s->width / s->vector_width) *
(s->height / s->vector_height) * 2;
- s->decode_buffer = av_malloc(s->decode_buffer_size);
+ s->decode_buffer = av_mallocz(s->decode_buffer_size);
if (!s->decode_buffer)
goto fail;
@@ -208,22 +207,22 @@ fail:
#define CHECK_COUNT() \
if (dest_index + count > dest_size) { \
- av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
- av_log(NULL, AV_LOG_ERROR, " VQA video: current dest_index = %d, count = %d, dest_size = %d\n", \
+ av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \
+ av_log(s->avctx, AV_LOG_ERROR, "current dest_index = %d, count = %d, dest_size = %d\n", \
dest_index, count, dest_size); \
return AVERROR_INVALIDDATA; \
}
#define CHECK_COPY(idx) \
if (idx < 0 || idx + count > dest_size) { \
- av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: next op would overflow dest_index\n"); \
- av_log(NULL, AV_LOG_ERROR, " VQA video: current src_pos = %d, count = %d, dest_size = %d\n", \
+ av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: next op would overflow dest_index\n"); \
+ av_log(s->avctx, AV_LOG_ERROR, "current src_pos = %d, count = %d, dest_size = %d\n", \
src_pos, count, dest_size); \
return AVERROR_INVALIDDATA; \
}
-static int decode_format80(GetByteContext *gb, int src_size,
+static int decode_format80(VqaContext *s, int src_size,
unsigned char *dest, int dest_size, int check_size) {
int dest_index = 0;
@@ -232,26 +231,32 @@ static int decode_format80(GetByteContext *gb, int src_size,
unsigned char color;
int i;
- start = bytestream2_tell(gb);
- while (bytestream2_tell(gb) - start < src_size) {
- opcode = bytestream2_get_byte(gb);
- ff_dlog(NULL, " opcode %02X: ", opcode);
+ if (src_size < 0 || src_size > bytestream2_get_bytes_left(&s->gb)) {
+ av_log(s->avctx, AV_LOG_ERROR, "Chunk size %d is out of range\n",
+ src_size);
+ return AVERROR_INVALIDDATA;
+ }
+
+ start = bytestream2_tell(&s->gb);
+ while (bytestream2_tell(&s->gb) - start < src_size) {
+ opcode = bytestream2_get_byte(&s->gb);
+ ff_tlog(s->avctx, "opcode %02X: ", opcode);
/* 0x80 means that frame is finished */
if (opcode == 0x80)
- return 0;
+ break;
if (dest_index >= dest_size) {
- av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: dest_index (%d) exceeded dest_size (%d)\n",
dest_index, dest_size);
return AVERROR_INVALIDDATA;
}
if (opcode == 0xFF) {
- count = bytestream2_get_le16(gb);
- src_pos = bytestream2_get_le16(gb);
- ff_dlog(NULL, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
+ count = bytestream2_get_le16(&s->gb);
+ src_pos = bytestream2_get_le16(&s->gb);
+ ff_tlog(s->avctx, "(1) copy %X bytes from absolute pos %X\n", count, src_pos);
CHECK_COUNT();
CHECK_COPY(src_pos);
for (i = 0; i < count; i++)
@@ -260,9 +265,9 @@ static int decode_format80(GetByteContext *gb, int src_size,
} else if (opcode == 0xFE) {
- count = bytestream2_get_le16(gb);
- color = bytestream2_get_byte(gb);
- ff_dlog(NULL, "(2) set %X bytes to %02X\n", count, color);
+ count = bytestream2_get_le16(&s->gb);
+ color = bytestream2_get_byte(&s->gb);
+ ff_tlog(s->avctx, "(2) set %X bytes to %02X\n", count, color);
CHECK_COUNT();
memset(&dest[dest_index], color, count);
dest_index += count;
@@ -270,8 +275,8 @@ static int decode_format80(GetByteContext *gb, int src_size,
} else if ((opcode & 0xC0) == 0xC0) {
count = (opcode & 0x3F) + 3;
- src_pos = bytestream2_get_le16(gb);
- ff_dlog(NULL, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
+ src_pos = bytestream2_get_le16(&s->gb);
+ ff_tlog(s->avctx, "(3) copy %X bytes from absolute pos %X\n", count, src_pos);
CHECK_COUNT();
CHECK_COPY(src_pos);
for (i = 0; i < count; i++)
@@ -281,16 +286,16 @@ static int decode_format80(GetByteContext *gb, int src_size,
} else if (opcode > 0x80) {
count = opcode & 0x3F;
- ff_dlog(NULL, "(4) copy %X bytes from source to dest\n", count);
+ ff_tlog(s->avctx, "(4) copy %X bytes from source to dest\n", count);
CHECK_COUNT();
- bytestream2_get_buffer(gb, &dest[dest_index], count);
+ bytestream2_get_buffer(&s->gb, &dest[dest_index], count);
dest_index += count;
} else {
count = ((opcode & 0x70) >> 4) + 3;
- src_pos = bytestream2_get_byte(gb) | ((opcode & 0x0F) << 8);
- ff_dlog(NULL, "(5) copy %X bytes from relpos %X\n", count, src_pos);
+ src_pos = bytestream2_get_byte(&s->gb) | ((opcode & 0x0F) << 8);
+ ff_tlog(s->avctx, "(5) copy %X bytes from relpos %X\n", count, src_pos);
CHECK_COUNT();
CHECK_COPY(dest_index - src_pos);
for (i = 0; i < count; i++)
@@ -304,9 +309,11 @@ static int decode_format80(GetByteContext *gb, int src_size,
* codebook entry; it is not important for compressed codebooks because
* not every entry needs to be filled */
if (check_size)
- if (dest_index < dest_size)
- av_log(NULL, AV_LOG_ERROR, " VQA video: decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
+ if (dest_index < dest_size) {
+ av_log(s->avctx, AV_LOG_ERROR, "decode_format80 problem: decode finished with dest_index (%d) < dest_size (%d)\n",
dest_index, dest_size);
+ memset(dest + dest_index, 0, dest_size - dest_index);
+ }
return 0; // let's display what we decoded anyway
}
@@ -377,7 +384,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
break;
default:
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: Found unknown chunk type: %c%c%c%c (%08X)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "Found unknown chunk type: %c%c%c%c (%08X)\n",
(chunk_type >> 24) & 0xFF,
(chunk_type >> 16) & 0xFF,
(chunk_type >> 8) & 0xFF,
@@ -394,7 +401,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
if ((cpl0_chunk != -1) && (cplz_chunk != -1)) {
/* a chunk should not have both chunk types */
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CPL0 and CPLZ chunks\n");
+ av_log(s->avctx, AV_LOG_ERROR, "problem: found both CPL0 and CPLZ chunks\n");
return AVERROR_INVALIDDATA;
}
@@ -412,7 +419,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
chunk_size = bytestream2_get_be32(&s->gb);
/* sanity check the palette size */
if (chunk_size / 3 > 256 || chunk_size > bytestream2_get_bytes_left(&s->gb)) {
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found a palette chunk with %d colors\n",
+ av_log(s->avctx, AV_LOG_ERROR, "problem: found a palette chunk with %d colors\n",
chunk_size / 3);
return AVERROR_INVALIDDATA;
}
@@ -421,7 +428,8 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
r = bytestream2_get_byteu(&s->gb) * 4;
g = bytestream2_get_byteu(&s->gb) * 4;
b = bytestream2_get_byteu(&s->gb) * 4;
- s->palette[i] = (r << 16) | (g << 8) | (b);
+ s->palette[i] = 0xFFU << 24 | r << 16 | g << 8 | b;
+ s->palette[i] |= s->palette[i] >> 6 & 0x30303;
}
}
@@ -429,7 +437,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
if ((cbf0_chunk != -1) && (cbfz_chunk != -1)) {
/* a chunk should not have both chunk types */
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBF0 and CBFZ chunks\n");
+ av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBF0 and CBFZ chunks\n");
return AVERROR_INVALIDDATA;
}
@@ -438,7 +446,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
bytestream2_seek(&s->gb, cbfz_chunk, SEEK_SET);
chunk_size = bytestream2_get_be32(&s->gb);
- if ((res = decode_format80(&s->gb, chunk_size, s->codebook,
+ if ((res = decode_format80(s, chunk_size, s->codebook,
s->codebook_size, 0)) < 0)
return res;
}
@@ -450,7 +458,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
chunk_size = bytestream2_get_be32(&s->gb);
/* sanity check the full codebook size */
if (chunk_size > MAX_CODEBOOK_SIZE) {
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: CBF0 chunk too large (0x%X bytes)\n",
+ av_log(s->avctx, AV_LOG_ERROR, "problem: CBF0 chunk too large (0x%X bytes)\n",
chunk_size);
return AVERROR_INVALIDDATA;
}
@@ -462,13 +470,13 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
if (vptz_chunk == -1) {
/* something is wrong if there is no VPTZ chunk */
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: no VPTZ chunk found\n");
+ av_log(s->avctx, AV_LOG_ERROR, "problem: no VPTZ chunk found\n");
return AVERROR_INVALIDDATA;
}
bytestream2_seek(&s->gb, vptz_chunk, SEEK_SET);
chunk_size = bytestream2_get_be32(&s->gb);
- if ((res = decode_format80(&s->gb, chunk_size,
+ if ((res = decode_format80(s, chunk_size,
s->decode_buffer, s->decode_buffer_size, 1)) < 0)
return res;
@@ -531,7 +539,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
/* handle partial codebook */
if ((cbp0_chunk != -1) && (cbpz_chunk != -1)) {
/* a chunk should not have both chunk types */
- av_log(s->avctx, AV_LOG_ERROR, " VQA video: problem: found both CBP0 and CBPZ chunks\n");
+ av_log(s->avctx, AV_LOG_ERROR, "problem: found both CBP0 and CBPZ chunks\n");
return AVERROR_INVALIDDATA;
}
@@ -552,7 +560,7 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
s->next_codebook_buffer_index += chunk_size;
s->partial_countdown--;
- if (s->partial_countdown == 0) {
+ if (s->partial_countdown <= 0) {
/* time to replace codebook */
memcpy(s->codebook, s->next_codebook_buffer,
@@ -581,12 +589,10 @@ static int vqa_decode_chunk(VqaContext *s, AVFrame *frame)
s->next_codebook_buffer_index += chunk_size;
s->partial_countdown--;
- if (s->partial_countdown == 0) {
- GetByteContext gb;
-
- bytestream2_init(&gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
+ if (s->partial_countdown <= 0) {
+ bytestream2_init(&s->gb, s->next_codebook_buffer, s->next_codebook_buffer_index);
/* decompress codebook */
- if ((res = decode_format80(&gb, s->next_codebook_buffer_index,
+ if ((res = decode_format80(s, s->next_codebook_buffer_index,
s->codebook, s->codebook_size, 0)) < 0)
return res;
@@ -607,10 +613,8 @@ static int vqa_decode_frame(AVCodecContext *avctx,
AVFrame *frame = data;
int res;
- if ((res = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(s->avctx, AV_LOG_ERROR, " VQA Video: get_buffer() failed\n");
+ if ((res = ff_get_buffer(avctx, frame, 0)) < 0)
return res;
- }
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
if ((res = vqa_decode_chunk(s, frame)) < 0)
diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index cbc5b04d1a..b51a21cc9d 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -2,20 +2,20 @@
* WavPack lossless audio decoder
* Copyright (c) 2006,2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,60 +25,16 @@
#include "avcodec.h"
#include "get_bits.h"
#include "internal.h"
+#include "thread.h"
#include "unary.h"
#include "bytestream.h"
+#include "wavpack.h"
/**
* @file
* WavPack lossless audio decoder
*/
-#define WV_HEADER_SIZE 32
-
-#define WV_MONO 0x00000004
-#define WV_JOINT_STEREO 0x00000010
-#define WV_FALSE_STEREO 0x40000000
-
-#define WV_HYBRID_MODE 0x00000008
-#define WV_HYBRID_SHAPE 0x00000008
-#define WV_HYBRID_BITRATE 0x00000200
-#define WV_HYBRID_BALANCE 0x00000400
-#define WV_INITIAL_BLOCK 0x00000800
-#define WV_FINAL_BLOCK 0x00001000
-
-#define WV_SINGLE_BLOCK (WV_INITIAL_BLOCK | WV_FINAL_BLOCK)
-
-#define WV_FLT_SHIFT_ONES 0x01
-#define WV_FLT_SHIFT_SAME 0x02
-#define WV_FLT_SHIFT_SENT 0x04
-#define WV_FLT_ZERO_SENT 0x08
-#define WV_FLT_ZERO_SIGN 0x10
-
-enum WP_ID_Flags {
- WP_IDF_MASK = 0x3F,
- WP_IDF_IGNORE = 0x20,
- WP_IDF_ODD = 0x40,
- WP_IDF_LONG = 0x80
-};
-
-enum WP_ID {
- WP_ID_DUMMY = 0,
- WP_ID_ENCINFO,
- WP_ID_DECTERMS,
- WP_ID_DECWEIGHTS,
- WP_ID_DECSAMPLES,
- WP_ID_ENTROPY,
- WP_ID_HYBRID,
- WP_ID_SHAPING,
- WP_ID_FLOATINFO,
- WP_ID_INT32INFO,
- WP_ID_DATA,
- WP_ID_CORR,
- WP_ID_EXTRABITS,
- WP_ID_CHANINFO,
- WP_ID_SAMPLE_RATE = 0x27,
-};
-
typedef struct SavedContext {
int offset;
int size;
@@ -86,23 +42,6 @@ typedef struct SavedContext {
uint32_t crc;
} SavedContext;
-#define MAX_TERMS 16
-
-typedef struct Decorr {
- int delta;
- int value;
- int weightA;
- int weightB;
- int samplesA[8];
- int samplesB[8];
-} Decorr;
-
-typedef struct WvChannel {
- int median[3];
- int slow_level, error_limit;
- int bitrate_acc, bitrate_delta;
-} WvChannel;
-
typedef struct WavpackFrameContext {
AVCodecContext *avctx;
int frame_flags;
@@ -144,101 +83,7 @@ typedef struct WavpackContext {
int ch_offset;
} WavpackContext;
-static const int wv_rates[16] = {
- 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
- 32000, 44100, 48000, 64000, 88200, 96000, 192000, 0
-};
-
-// exponent table copied from WavPack source
-static const uint8_t wp_exp2_table[256] = {
- 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
- 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
- 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
- 0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
- 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
- 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
- 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
- 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
- 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
- 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
- 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
- 0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
- 0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
-};
-
-static const uint8_t wp_log2_table [] = {
- 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
- 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
- 0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
- 0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
- 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
- 0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
- 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
- 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
- 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
- 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
- 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
- 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
- 0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
- 0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
- 0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
- 0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
-};
-
-static av_always_inline int wp_exp2(int16_t val)
-{
- int res, neg = 0;
-
- if (val < 0) {
- val = -val;
- neg = 1;
- }
-
- res = wp_exp2_table[val & 0xFF] | 0x100;
- val >>= 8;
- res = (val > 9) ? (res << (val - 9)) : (res >> (9 - val));
- return neg ? -res : res;
-}
-
-static av_always_inline int wp_log2(int32_t val)
-{
- int bits;
-
- if (!val)
- return 0;
- if (val == 1)
- return 256;
- val += val >> 9;
- bits = av_log2(val) + 1;
- if (bits < 9)
- return (bits << 8) + wp_log2_table[(val << (9 - bits)) & 0xFF];
- else
- return (bits << 8) + wp_log2_table[(val >> (bits - 9)) & 0xFF];
-}
-
-#define LEVEL_DECAY(a) ((a + 0x80) >> 8)
-
-// macros for manipulating median values
-#define GET_MED(n) ((c->median[n] >> 4) + 1)
-#define DEC_MED(n) c->median[n] -= ((c->median[n] + (128 >> n) - 2) / (128 >> n)) * 2
-#define INC_MED(n) c->median[n] += ((c->median[n] + (128 >> n) ) / (128 >> n)) * 5
-
-// macros for applying weight
-#define UPDATE_WEIGHT_CLIP(weight, delta, samples, in) \
- if (samples && in) { \
- if ((samples ^ in) < 0) { \
- weight -= delta; \
- if (weight < -1024) \
- weight = -1024; \
- } else { \
- weight += delta; \
- if (weight > 1024) \
- weight = 1024; \
- } \
- }
+#define LEVEL_DECAY(a) (((a) + 0x80) >> 8)
static av_always_inline int get_tail(GetBitContext *gb, int k)
{
@@ -381,6 +226,10 @@ static int wv_get_value(WavpackFrameContext *ctx, GetBitContext *gb,
INC_MED(2);
}
if (!c->error_limit) {
+ if (add >= 0x2000000U) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "k %d is too large\n", add);
+ goto error;
+ }
ret = base + get_tail(gb, add);
if (get_bits_left(gb) <= 0)
goto error;
@@ -404,6 +253,10 @@ static int wv_get_value(WavpackFrameContext *ctx, GetBitContext *gb,
return sign ? ~ret : ret;
error:
+ ret = get_bits_left(gb);
+ if (ret <= 0) {
+ av_log(ctx->avctx, AV_LOG_ERROR, "Too few bits (%d) left\n", ret);
+ }
*last = 1;
return 0;
}
@@ -619,6 +472,14 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb,
s->decorr[i].samplesB[0] = L;
}
}
+
+ if (type == AV_SAMPLE_FMT_S16P) {
+ if (FFABS(L) + FFABS(R) > (1<<19)) {
+ av_log(s->avctx, AV_LOG_ERROR, "sample %d %d too large\n", L, R);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
pos = (pos + 1) & 7;
if (s->joint)
L += (R -= (L >> 1));
@@ -638,6 +499,13 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb,
} while (!last && count < s->samples);
wv_reset_saved_context(s);
+
+ if (last && count < s->samples) {
+ int size = av_get_bytes_per_sample(type);
+ memset((uint8_t*)dst_l + count*size, 0, (s->samples-count)*size);
+ memset((uint8_t*)dst_r + count*size, 0, (s->samples-count)*size);
+ }
+
if ((s->avctx->err_recognition & AV_EF_CRCCHECK) &&
wv_check_crc(s, crc, crc_extra_bits))
return AVERROR_INVALIDDATA;
@@ -699,6 +567,12 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb,
} while (!last && count < s->samples);
wv_reset_saved_context(s);
+
+ if (last && count < s->samples) {
+ int size = av_get_bytes_per_sample(type);
+ memset((uint8_t*)dst + count*size, 0, (s->samples-count)*size);
+ }
+
if (s->avctx->err_recognition & AV_EF_CRCCHECK) {
int ret = wv_check_crc(s, crc, crc_extra_bits);
if (ret < 0 && s->avctx->err_recognition & AV_EF_EXPLODE)
@@ -723,6 +597,13 @@ static av_cold int wv_alloc_frame_context(WavpackContext *c)
return 0;
}
+static int init_thread_copy(AVCodecContext *avctx)
+{
+ WavpackContext *s = avctx->priv_data;
+ s->avctx = avctx;
+ return 0;
+}
+
static av_cold int wavpack_decode_init(AVCodecContext *avctx)
{
WavpackContext *s = avctx->priv_data;
@@ -750,9 +631,10 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
AVFrame *frame, const uint8_t *buf, int buf_size)
{
WavpackContext *wc = avctx->priv_data;
+ ThreadFrame tframe = { .f = frame };
WavpackFrameContext *s;
GetByteContext gb;
- void *samples_l, *samples_r;
+ void *samples_l = NULL, *samples_r = NULL;
int ret;
int got_terms = 0, got_weights = 0, got_samples = 0,
got_entropy = 0, got_bs = 0, got_float = 0, got_hybrid = 0;
@@ -910,7 +792,7 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
case WP_ID_ENTROPY:
if (size != 6 * (s->stereo_in + 1)) {
av_log(avctx, AV_LOG_ERROR,
- "Entropy vars size should be %i, got %i",
+ "Entropy vars size should be %i, got %i.\n",
6 * (s->stereo_in + 1), size);
bytestream2_skip(&gb, ssize);
continue;
@@ -990,7 +872,8 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
case WP_ID_DATA:
s->sc.offset = bytestream2_tell(&gb);
s->sc.size = size * 8;
- init_get_bits(&s->gb, gb.buffer, size * 8);
+ if ((ret = init_get_bits8(&s->gb, gb.buffer, size)) < 0)
+ return ret;
s->data_size = size * 8;
bytestream2_skip(&gb, size);
got_bs = 1;
@@ -1004,7 +887,8 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
}
s->extra_sc.offset = bytestream2_tell(&gb);
s->extra_sc.size = size * 8;
- init_get_bits(&s->gb_extra_bits, gb.buffer, size * 8);
+ if ((ret = init_get_bits8(&s->gb_extra_bits, gb.buffer, size)) < 0)
+ return ret;
s->crc_extra_bits = get_bits_long(&s->gb_extra_bits, 32);
bytestream2_skip(&gb, size);
s->got_extra_bits = 1;
@@ -1027,10 +911,13 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
chmask = bytestream2_get_le24(&gb);
break;
case 3:
- chmask = bytestream2_get_le32(&gb);;
+ chmask = bytestream2_get_le32(&gb);
break;
case 5:
- bytestream2_skip(&gb, 1);
+ size = bytestream2_get_byte(&gb);
+ if (avctx->channels != size)
+ av_log(avctx, AV_LOG_WARNING, "%i channels signalled"
+ " instead of %i.\n", size, avctx->channels);
chan |= (bytestream2_get_byte(&gb) & 0xF) << 8;
chmask = bytestream2_get_le16(&gb);
break;
@@ -1115,11 +1002,10 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
}
/* get output buffer */
- frame->nb_samples = s->samples;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ frame->nb_samples = s->samples + 1;
+ if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0)
return ret;
- }
+ frame->nb_samples = s->samples;
}
if (wc->ch_offset + s->stereo >= avctx->channels) {
@@ -1176,7 +1062,7 @@ static int wavpack_decode_frame(AVCodecContext *avctx, void *data,
/* determine number of samples */
s->samples = AV_RL32(buf + 20);
frame_flags = AV_RL32(buf + 24);
- if (s->samples <= 0) {
+ if (s->samples <= 0 || s->samples > WV_MAX_SAMPLES) {
av_log(avctx, AV_LOG_ERROR, "Invalid number of samples: %d\n",
s->samples);
return AVERROR_INVALIDDATA;
@@ -1234,5 +1120,6 @@ AVCodec ff_wavpack_decoder = {
.close = wavpack_decode_end,
.decode = wavpack_decode_frame,
.flush = wavpack_decode_flush,
- .capabilities = CODEC_CAP_DR1,
+ .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
};
diff --git a/libavcodec/wavpack.h b/libavcodec/wavpack.h
new file mode 100644
index 0000000000..a1b46d5bd7
--- /dev/null
+++ b/libavcodec/wavpack.h
@@ -0,0 +1,194 @@
+/*
+ * WavPack decoder/encoder common code
+ * Copyright (c) 2006,2011 Konstantin Shishkov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_WAVPACK_H
+#define AVCODEC_WAVPACK_H
+
+#include "libavutil/common.h"
+
+#define MAX_TERMS 16
+#define MAX_TERM 8
+
+#define WV_HEADER_SIZE 32
+
+#define WV_MONO 0x00000004
+#define WV_JOINT_STEREO 0x00000010
+#define WV_CROSS_DECORR 0x00000020
+#define WV_FLOAT_DATA 0x00000080
+#define WV_INT32_DATA 0x00000100
+#define WV_FALSE_STEREO 0x40000000
+
+#define WV_HYBRID_MODE 0x00000008
+#define WV_HYBRID_SHAPE 0x00000008
+#define WV_HYBRID_BITRATE 0x00000200
+#define WV_HYBRID_BALANCE 0x00000400
+#define WV_INITIAL_BLOCK 0x00000800
+#define WV_FINAL_BLOCK 0x00001000
+
+#define WV_MONO_DATA (WV_MONO | WV_FALSE_STEREO)
+
+#define WV_SINGLE_BLOCK (WV_INITIAL_BLOCK | WV_FINAL_BLOCK)
+
+#define WV_FLT_SHIFT_ONES 0x01
+#define WV_FLT_SHIFT_SAME 0x02
+#define WV_FLT_SHIFT_SENT 0x04
+#define WV_FLT_ZERO_SENT 0x08
+#define WV_FLT_ZERO_SIGN 0x10
+
+#define WV_MAX_SAMPLES 150000
+
+enum WP_ID_Flags {
+ WP_IDF_MASK = 0x3F,
+ WP_IDF_IGNORE = 0x20,
+ WP_IDF_ODD = 0x40,
+ WP_IDF_LONG = 0x80
+};
+
+enum WP_ID {
+ WP_ID_DUMMY = 0,
+ WP_ID_ENCINFO,
+ WP_ID_DECTERMS,
+ WP_ID_DECWEIGHTS,
+ WP_ID_DECSAMPLES,
+ WP_ID_ENTROPY,
+ WP_ID_HYBRID,
+ WP_ID_SHAPING,
+ WP_ID_FLOATINFO,
+ WP_ID_INT32INFO,
+ WP_ID_DATA,
+ WP_ID_CORR,
+ WP_ID_EXTRABITS,
+ WP_ID_CHANINFO,
+ WP_ID_SAMPLE_RATE = 0x27,
+};
+
+typedef struct Decorr {
+ int delta;
+ int value;
+ int weightA;
+ int weightB;
+ int samplesA[MAX_TERM];
+ int samplesB[MAX_TERM];
+ int sumA;
+ int sumB;
+} Decorr;
+
+typedef struct WvChannel {
+ int median[3];
+ int slow_level, error_limit;
+ int bitrate_acc, bitrate_delta;
+} WvChannel;
+
+// macros for manipulating median values
+#define GET_MED(n) ((c->median[n] >> 4) + 1)
+#define DEC_MED(n) c->median[n] -= ((c->median[n] + (128 >> (n)) - 2) / (128 >> (n))) * 2
+#define INC_MED(n) c->median[n] += ((c->median[n] + (128 >> (n)) ) / (128 >> (n))) * 5
+
+// macros for applying weight
+#define UPDATE_WEIGHT_CLIP(weight, delta, samples, in) \
+ if ((samples) && (in)) { \
+ if (((samples) ^ (in)) < 0) { \
+ (weight) -= (delta); \
+ if ((weight) < -1024) \
+ (weight) = -1024; \
+ } else { \
+ (weight) += (delta); \
+ if ((weight) > 1024) \
+ (weight) = 1024; \
+ } \
+ }
+
+static const int wv_rates[16] = {
+ 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000, 192000, 0
+};
+
+// exponent table copied from WavPack source
+static const uint8_t wp_exp2_table[256] = {
+ 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
+ 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
+ 0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+ 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
+ 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+ 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
+ 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
+ 0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
+ 0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
+};
+
+static const uint8_t wp_log2_table [] = {
+ 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
+ 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
+ 0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
+ 0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
+ 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
+ 0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
+ 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
+ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
+ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
+ 0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
+ 0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
+};
+
+static av_always_inline int wp_exp2(int16_t val)
+{
+ int res, neg = 0;
+
+ if (val < 0) {
+ val = -val;
+ neg = 1;
+ }
+
+ res = wp_exp2_table[val & 0xFF] | 0x100;
+ val >>= 8;
+ res = (val > 9) ? (res << (val - 9)) : (res >> (9 - val));
+ return neg ? -res : res;
+}
+
+static av_always_inline int wp_log2(int32_t val)
+{
+ int bits;
+
+ if (!val)
+ return 0;
+ if (val == 1)
+ return 256;
+ val += val >> 9;
+ bits = av_log2(val) + 1;
+ if (bits < 9)
+ return (bits << 8) + wp_log2_table[(val << (9 - bits)) & 0xFF];
+ else
+ return (bits << 8) + wp_log2_table[(val >> (bits - 9)) & 0xFF];
+}
+
+#endif /* AVCODEC_WAVPACK_H */
diff --git a/libavcodec/wavpackenc.c b/libavcodec/wavpackenc.c
new file mode 100644
index 0000000000..87f1445738
--- /dev/null
+++ b/libavcodec/wavpackenc.c
@@ -0,0 +1,2991 @@
+/*
+ * WavPack lossless audio encoder
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITSTREAM_WRITER_LE
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "put_bits.h"
+#include "bytestream.h"
+#include "wavpackenc.h"
+#include "wavpack.h"
+
+#define UPDATE_WEIGHT(weight, delta, source, result) \
+ if ((source) && (result)) { \
+ int32_t s = (int32_t) ((source) ^ (result)) >> 31; \
+ weight = ((delta) ^ s) + ((weight) - s); \
+ }
+
+#define APPLY_WEIGHT_F(weight, sample) ((((((sample) & 0xffff) * (weight)) >> 9) + \
+ ((((sample) & ~0xffff) >> 9) * (weight)) + 1) >> 1)
+
+#define APPLY_WEIGHT_I(weight, sample) (((weight) * (sample) + 512) >> 10)
+
+#define APPLY_WEIGHT(weight, sample) ((sample) != (short) (sample) ? \
+ APPLY_WEIGHT_F(weight, sample) : APPLY_WEIGHT_I (weight, sample))
+
+#define CLEAR(destin) memset(&destin, 0, sizeof(destin));
+
+#define SHIFT_LSB 13
+#define SHIFT_MASK (0x1FU << SHIFT_LSB)
+
+#define MAG_LSB 18
+#define MAG_MASK (0x1FU << MAG_LSB)
+
+#define SRATE_LSB 23
+#define SRATE_MASK (0xFU << SRATE_LSB)
+
+#define EXTRA_TRY_DELTAS 1
+#define EXTRA_ADJUST_DELTAS 2
+#define EXTRA_SORT_FIRST 4
+#define EXTRA_BRANCHES 8
+#define EXTRA_SORT_LAST 16
+
+typedef struct WavPackExtraInfo {
+ struct Decorr dps[MAX_TERMS];
+ int nterms, log_limit, gt16bit;
+ uint32_t best_bits;
+} WavPackExtraInfo;
+
+typedef struct WavPackWords {
+ int pend_data, holding_one, zeros_acc;
+ int holding_zero, pend_count;
+ WvChannel c[2];
+} WavPackWords;
+
+typedef struct WavPackEncodeContext {
+ AVClass *class;
+ AVCodecContext *avctx;
+ PutBitContext pb;
+ int block_samples;
+ int buffer_size;
+ int sample_index;
+ int stereo, stereo_in;
+ int ch_offset;
+
+ int32_t *samples[2];
+ int samples_size[2];
+
+ int32_t *sampleptrs[MAX_TERMS+2][2];
+ int sampleptrs_size[MAX_TERMS+2][2];
+
+ int32_t *temp_buffer[2][2];
+ int temp_buffer_size[2][2];
+
+ int32_t *best_buffer[2];
+ int best_buffer_size[2];
+
+ int32_t *js_left, *js_right;
+ int js_left_size, js_right_size;
+
+ int32_t *orig_l, *orig_r;
+ int orig_l_size, orig_r_size;
+
+ unsigned extra_flags;
+ int optimize_mono;
+ int decorr_filter;
+ int joint;
+ int num_branches;
+
+ uint32_t flags;
+ uint32_t crc_x;
+ WavPackWords w;
+
+ uint8_t int32_sent_bits, int32_zeros, int32_ones, int32_dups;
+ uint8_t float_flags, float_shift, float_max_exp, max_exp;
+ int32_t shifted_ones, shifted_zeros, shifted_both;
+ int32_t false_zeros, neg_zeros, ordata;
+
+ int num_terms, shift, joint_stereo, false_stereo;
+ int num_decorrs, num_passes, best_decorr, mask_decorr;
+ struct Decorr decorr_passes[MAX_TERMS];
+ const WavPackDecorrSpec *decorr_specs;
+ float delta_decay;
+} WavPackEncodeContext;
+
+static av_cold int wavpack_encode_init(AVCodecContext *avctx)
+{
+ WavPackEncodeContext *s = avctx->priv_data;
+
+ s->avctx = avctx;
+
+ if (!avctx->frame_size) {
+ int block_samples;
+ if (!(avctx->sample_rate & 1))
+ block_samples = avctx->sample_rate / 2;
+ else
+ block_samples = avctx->sample_rate;
+
+ while (block_samples * avctx->channels > WV_MAX_SAMPLES)
+ block_samples /= 2;
+
+ while (block_samples * avctx->channels < 40000)
+ block_samples *= 2;
+ avctx->frame_size = block_samples;
+ } else if (avctx->frame_size && (avctx->frame_size < 128 ||
+ avctx->frame_size > WV_MAX_SAMPLES)) {
+ av_log(avctx, AV_LOG_ERROR, "invalid block size: %d\n", avctx->frame_size);
+ return AVERROR(EINVAL);
+ }
+
+ if (avctx->compression_level != FF_COMPRESSION_DEFAULT) {
+ if (avctx->compression_level >= 3) {
+ s->decorr_filter = 3;
+ s->num_passes = 9;
+ if (avctx->compression_level >= 8) {
+ s->num_branches = 4;
+ s->extra_flags = EXTRA_TRY_DELTAS|EXTRA_ADJUST_DELTAS|EXTRA_SORT_FIRST|EXTRA_SORT_LAST|EXTRA_BRANCHES;
+ } else if (avctx->compression_level >= 7) {
+ s->num_branches = 3;
+ s->extra_flags = EXTRA_TRY_DELTAS|EXTRA_ADJUST_DELTAS|EXTRA_SORT_FIRST|EXTRA_BRANCHES;
+ } else if (avctx->compression_level >= 6) {
+ s->num_branches = 2;
+ s->extra_flags = EXTRA_TRY_DELTAS|EXTRA_ADJUST_DELTAS|EXTRA_SORT_FIRST|EXTRA_BRANCHES;
+ } else if (avctx->compression_level >= 5) {
+ s->num_branches = 1;
+ s->extra_flags = EXTRA_TRY_DELTAS|EXTRA_ADJUST_DELTAS|EXTRA_SORT_FIRST|EXTRA_BRANCHES;
+ } else if (avctx->compression_level >= 4) {
+ s->num_branches = 1;
+ s->extra_flags = EXTRA_TRY_DELTAS|EXTRA_ADJUST_DELTAS|EXTRA_BRANCHES;
+ }
+ } else if (avctx->compression_level == 2) {
+ s->decorr_filter = 2;
+ s->num_passes = 4;
+ } else if (avctx->compression_level == 1) {
+ s->decorr_filter = 1;
+ s->num_passes = 2;
+ } else if (avctx->compression_level < 1) {
+ s->decorr_filter = 0;
+ s->num_passes = 0;
+ }
+ }
+
+ s->num_decorrs = decorr_filter_sizes[s->decorr_filter];
+ s->decorr_specs = decorr_filters[s->decorr_filter];
+
+ s->delta_decay = 2.0;
+
+ return 0;
+}
+
+static void shift_mono(int32_t *samples, int nb_samples, int shift)
+{
+ int i;
+ for (i = 0; i < nb_samples; i++)
+ samples[i] >>= shift;
+}
+
+static void shift_stereo(int32_t *left, int32_t *right,
+ int nb_samples, int shift)
+{
+ int i;
+ for (i = 0; i < nb_samples; i++) {
+ left [i] >>= shift;
+ right[i] >>= shift;
+ }
+}
+
+#define FLOAT_SHIFT_ONES 1
+#define FLOAT_SHIFT_SAME 2
+#define FLOAT_SHIFT_SENT 4
+#define FLOAT_ZEROS_SENT 8
+#define FLOAT_NEG_ZEROS 0x10
+#define FLOAT_EXCEPTIONS 0x20
+
+#define get_mantissa(f) ((f) & 0x7fffff)
+#define get_exponent(f) (((f) >> 23) & 0xff)
+#define get_sign(f) (((f) >> 31) & 0x1)
+
+static void process_float(WavPackEncodeContext *s, int32_t *sample)
+{
+ int32_t shift_count, value, f = *sample;
+
+ if (get_exponent(f) == 255) {
+ s->float_flags |= FLOAT_EXCEPTIONS;
+ value = 0x1000000;
+ shift_count = 0;
+ } else if (get_exponent(f)) {
+ shift_count = s->max_exp - get_exponent(f);
+ value = 0x800000 + get_mantissa(f);
+ } else {
+ shift_count = s->max_exp ? s->max_exp - 1 : 0;
+ value = get_mantissa(f);
+ }
+
+ if (shift_count < 25)
+ value >>= shift_count;
+ else
+ value = 0;
+
+ if (!value) {
+ if (get_exponent(f) || get_mantissa(f))
+ s->false_zeros++;
+ else if (get_sign(f))
+ s->neg_zeros++;
+ } else if (shift_count) {
+ int32_t mask = (1 << shift_count) - 1;
+
+ if (!(get_mantissa(f) & mask))
+ s->shifted_zeros++;
+ else if ((get_mantissa(f) & mask) == mask)
+ s->shifted_ones++;
+ else
+ s->shifted_both++;
+ }
+
+ s->ordata |= value;
+ *sample = get_sign(f) ? -value : value;
+}
+
+static int scan_float(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ uint32_t crc = 0xffffffffu;
+ int i;
+
+ s->shifted_ones = s->shifted_zeros = s->shifted_both = s->ordata = 0;
+ s->float_shift = s->float_flags = 0;
+ s->false_zeros = s->neg_zeros = 0;
+ s->max_exp = 0;
+
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t f = samples_l[i];
+ crc = crc * 27 + get_mantissa(f) * 9 + get_exponent(f) * 3 + get_sign(f);
+
+ if (get_exponent(f) > s->max_exp && get_exponent(f) < 255)
+ s->max_exp = get_exponent(f);
+ }
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t f;
+
+ f = samples_l[i];
+ crc = crc * 27 + get_mantissa(f) * 9 + get_exponent(f) * 3 + get_sign(f);
+ if (get_exponent(f) > s->max_exp && get_exponent(f) < 255)
+ s->max_exp = get_exponent(f);
+
+ f = samples_r[i];
+ crc = crc * 27 + get_mantissa(f) * 9 + get_exponent(f) * 3 + get_sign(f);
+
+ if (get_exponent(f) > s->max_exp && get_exponent(f) < 255)
+ s->max_exp = get_exponent(f);
+ }
+ }
+
+ s->crc_x = crc;
+
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++)
+ process_float(s, &samples_l[i]);
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ process_float(s, &samples_l[i]);
+ process_float(s, &samples_r[i]);
+ }
+ }
+
+ s->float_max_exp = s->max_exp;
+
+ if (s->shifted_both)
+ s->float_flags |= FLOAT_SHIFT_SENT;
+ else if (s->shifted_ones && !s->shifted_zeros)
+ s->float_flags |= FLOAT_SHIFT_ONES;
+ else if (s->shifted_ones && s->shifted_zeros)
+ s->float_flags |= FLOAT_SHIFT_SAME;
+ else if (s->ordata && !(s->ordata & 1)) {
+ do {
+ s->float_shift++;
+ s->ordata >>= 1;
+ } while (!(s->ordata & 1));
+
+ if (s->flags & WV_MONO_DATA)
+ shift_mono(samples_l, nb_samples, s->float_shift);
+ else
+ shift_stereo(samples_l, samples_r, nb_samples, s->float_shift);
+ }
+
+ s->flags &= ~MAG_MASK;
+
+ while (s->ordata) {
+ s->flags += 1 << MAG_LSB;
+ s->ordata >>= 1;
+ }
+
+ if (s->false_zeros || s->neg_zeros)
+ s->float_flags |= FLOAT_ZEROS_SENT;
+
+ if (s->neg_zeros)
+ s->float_flags |= FLOAT_NEG_ZEROS;
+
+ return s->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT |
+ FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME);
+}
+
+static void scan_int23(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0;
+ int i, total_shift = 0;
+
+ s->int32_sent_bits = s->int32_zeros = s->int32_ones = s->int32_dups = 0;
+
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t M = samples_l[i];
+
+ magdata |= (M < 0) ? ~M : M;
+ xordata |= M ^ -(M & 1);
+ anddata &= M;
+ ordata |= M;
+
+ if ((ordata & 1) && !(anddata & 1) && (xordata & 2))
+ return;
+ }
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t L = samples_l[i];
+ int32_t R = samples_r[i];
+
+ magdata |= (L < 0) ? ~L : L;
+ magdata |= (R < 0) ? ~R : R;
+ xordata |= L ^ -(L & 1);
+ xordata |= R ^ -(R & 1);
+ anddata &= L & R;
+ ordata |= L | R;
+
+ if ((ordata & 1) && !(anddata & 1) && (xordata & 2))
+ return;
+ }
+ }
+
+ s->flags &= ~MAG_MASK;
+
+ while (magdata) {
+ s->flags += 1 << MAG_LSB;
+ magdata >>= 1;
+ }
+
+ if (!(s->flags & MAG_MASK))
+ return;
+
+ if (!(ordata & 1)) {
+ do {
+ s->flags -= 1 << MAG_LSB;
+ s->int32_zeros++;
+ total_shift++;
+ ordata >>= 1;
+ } while (!(ordata & 1));
+ } else if (anddata & 1) {
+ do {
+ s->flags -= 1 << MAG_LSB;
+ s->int32_ones++;
+ total_shift++;
+ anddata >>= 1;
+ } while (anddata & 1);
+ } else if (!(xordata & 2)) {
+ do {
+ s->flags -= 1 << MAG_LSB;
+ s->int32_dups++;
+ total_shift++;
+ xordata >>= 1;
+ } while (!(xordata & 2));
+ }
+
+ if (total_shift) {
+ s->flags |= WV_INT32_DATA;
+
+ if (s->flags & WV_MONO_DATA)
+ shift_mono(samples_l, nb_samples, total_shift);
+ else
+ shift_stereo(samples_l, samples_r, nb_samples, total_shift);
+ }
+}
+
+static int scan_int32(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0;
+ uint32_t crc = 0xffffffffu;
+ int i, total_shift = 0;
+
+ s->int32_sent_bits = s->int32_zeros = s->int32_ones = s->int32_dups = 0;
+
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t M = samples_l[i];
+
+ crc = crc * 9 + (M & 0xffff) * 3 + ((M >> 16) & 0xffff);
+ magdata |= (M < 0) ? ~M : M;
+ xordata |= M ^ -(M & 1);
+ anddata &= M;
+ ordata |= M;
+ }
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t L = samples_l[i];
+ int32_t R = samples_r[i];
+
+ crc = crc * 9 + (L & 0xffff) * 3 + ((L >> 16) & 0xffff);
+ crc = crc * 9 + (R & 0xffff) * 3 + ((R >> 16) & 0xffff);
+ magdata |= (L < 0) ? ~L : L;
+ magdata |= (R < 0) ? ~R : R;
+ xordata |= L ^ -(L & 1);
+ xordata |= R ^ -(R & 1);
+ anddata &= L & R;
+ ordata |= L | R;
+ }
+ }
+
+ s->crc_x = crc;
+ s->flags &= ~MAG_MASK;
+
+ while (magdata) {
+ s->flags += 1 << MAG_LSB;
+ magdata >>= 1;
+ }
+
+ if (!((s->flags & MAG_MASK) >> MAG_LSB)) {
+ s->flags &= ~WV_INT32_DATA;
+ return 0;
+ }
+
+ if (!(ordata & 1))
+ do {
+ s->flags -= 1 << MAG_LSB;
+ s->int32_zeros++;
+ total_shift++;
+ ordata >>= 1;
+ } while (!(ordata & 1));
+ else if (anddata & 1)
+ do {
+ s->flags -= 1 << MAG_LSB;
+ s->int32_ones++;
+ total_shift++;
+ anddata >>= 1;
+ } while (anddata & 1);
+ else if (!(xordata & 2))
+ do {
+ s->flags -= 1 << MAG_LSB;
+ s->int32_dups++;
+ total_shift++;
+ xordata >>= 1;
+ } while (!(xordata & 2));
+
+ if (((s->flags & MAG_MASK) >> MAG_LSB) > 23) {
+ s->int32_sent_bits = (uint8_t)(((s->flags & MAG_MASK) >> MAG_LSB) - 23);
+ total_shift += s->int32_sent_bits;
+ s->flags &= ~MAG_MASK;
+ s->flags += 23 << MAG_LSB;
+ }
+
+ if (total_shift) {
+ s->flags |= WV_INT32_DATA;
+
+ if (s->flags & WV_MONO_DATA)
+ shift_mono(samples_l, nb_samples, total_shift);
+ else
+ shift_stereo(samples_l, samples_r, nb_samples, total_shift);
+ }
+
+ return s->int32_sent_bits;
+}
+
+static int8_t store_weight(int weight)
+{
+ weight = av_clip(weight, -1024, 1024);
+ if (weight > 0)
+ weight -= (weight + 64) >> 7;
+
+ return (weight + 4) >> 3;
+}
+
+static int restore_weight(int8_t weight)
+{
+ int result;
+
+ if ((result = (int) weight << 3) > 0)
+ result += (result + 64) >> 7;
+
+ return result;
+}
+
+static int log2s(int32_t value)
+{
+ return (value < 0) ? -wp_log2(-value) : wp_log2(value);
+}
+
+static void decorr_mono(int32_t *in_samples, int32_t *out_samples,
+ int nb_samples, struct Decorr *dpp, int dir)
+{
+ int m = 0, i;
+
+ dpp->sumA = 0;
+
+ if (dir < 0) {
+ out_samples += (nb_samples - 1);
+ in_samples += (nb_samples - 1);
+ }
+
+ dpp->weightA = restore_weight(store_weight(dpp->weightA));
+
+ for (i = 0; i < MAX_TERM; i++)
+ dpp->samplesA[i] = wp_exp2(log2s(dpp->samplesA[i]));
+
+ if (dpp->value > MAX_TERM) {
+ while (nb_samples--) {
+ int32_t left, sam_A;
+
+ sam_A = ((3 - (dpp->value & 1)) * dpp->samplesA[0] - dpp->samplesA[1]) >> !(dpp->value & 1);
+
+ dpp->samplesA[1] = dpp->samplesA[0];
+ dpp->samplesA[0] = left = in_samples[0];
+
+ left -= APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam_A, left);
+ dpp->sumA += dpp->weightA;
+ out_samples[0] = left;
+ in_samples += dir;
+ out_samples += dir;
+ }
+ } else if (dpp->value > 0) {
+ while (nb_samples--) {
+ int k = (m + dpp->value) & (MAX_TERM - 1);
+ int32_t left, sam_A;
+
+ sam_A = dpp->samplesA[m];
+ dpp->samplesA[k] = left = in_samples[0];
+ m = (m + 1) & (MAX_TERM - 1);
+
+ left -= APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam_A, left);
+ dpp->sumA += dpp->weightA;
+ out_samples[0] = left;
+ in_samples += dir;
+ out_samples += dir;
+ }
+ }
+
+ if (m && dpp->value > 0 && dpp->value <= MAX_TERM) {
+ int32_t temp_A[MAX_TERM];
+
+ memcpy(temp_A, dpp->samplesA, sizeof(dpp->samplesA));
+
+ for (i = 0; i < MAX_TERM; i++) {
+ dpp->samplesA[i] = temp_A[m];
+ m = (m + 1) & (MAX_TERM - 1);
+ }
+ }
+}
+
+static void reverse_mono_decorr(struct Decorr *dpp)
+{
+ if (dpp->value > MAX_TERM) {
+ int32_t sam_A;
+
+ if (dpp->value & 1)
+ sam_A = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ else
+ sam_A = (3 * dpp->samplesA[0] - dpp->samplesA[1]) >> 1;
+
+ dpp->samplesA[1] = dpp->samplesA[0];
+ dpp->samplesA[0] = sam_A;
+
+ if (dpp->value & 1)
+ sam_A = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ else
+ sam_A = (3 * dpp->samplesA[0] - dpp->samplesA[1]) >> 1;
+
+ dpp->samplesA[1] = sam_A;
+ } else if (dpp->value > 1) {
+ int i, j, k;
+
+ for (i = 0, j = dpp->value - 1, k = 0; k < dpp->value / 2; i++, j--, k++) {
+ i &= (MAX_TERM - 1);
+ j &= (MAX_TERM - 1);
+ dpp->samplesA[i] ^= dpp->samplesA[j];
+ dpp->samplesA[j] ^= dpp->samplesA[i];
+ dpp->samplesA[i] ^= dpp->samplesA[j];
+ }
+ }
+}
+
+static uint32_t log2sample(uint32_t v, int limit, uint32_t *result)
+{
+ uint32_t dbits;
+
+ if ((v += v >> 9) < (1 << 8)) {
+ dbits = nbits_table[v];
+ *result += (dbits << 8) + wp_log2_table[(v << (9 - dbits)) & 0xff];
+ } else {
+ if (v < (1 << 16))
+ dbits = nbits_table[v >> 8] + 8;
+ else if (v < (1 << 24))
+ dbits = nbits_table[v >> 16] + 16;
+ else
+ dbits = nbits_table[v >> 24] + 24;
+
+ *result += dbits = (dbits << 8) + wp_log2_table[(v >> (dbits - 9)) & 0xff];
+
+ if (limit && dbits >= limit)
+ return 1;
+ }
+
+ return 0;
+}
+
+static uint32_t log2mono(int32_t *samples, int nb_samples, int limit)
+{
+ uint32_t result = 0;
+ while (nb_samples--) {
+ if (log2sample(abs(*samples++), limit, &result))
+ return UINT32_MAX;
+ }
+ return result;
+}
+
+static uint32_t log2stereo(int32_t *samples_l, int32_t *samples_r,
+ int nb_samples, int limit)
+{
+ uint32_t result = 0;
+ while (nb_samples--) {
+ if (log2sample(abs(*samples_l++), limit, &result) ||
+ log2sample(abs(*samples_r++), limit, &result))
+ return UINT32_MAX;
+ }
+ return result;
+}
+
+static void decorr_mono_buffer(int32_t *samples, int32_t *outsamples,
+ int nb_samples, struct Decorr *dpp,
+ int tindex)
+{
+ struct Decorr dp, *dppi = dpp + tindex;
+ int delta = dppi->delta, pre_delta, term = dppi->value;
+
+ if (delta == 7)
+ pre_delta = 7;
+ else if (delta < 2)
+ pre_delta = 3;
+ else
+ pre_delta = delta + 1;
+
+ CLEAR(dp);
+ dp.value = term;
+ dp.delta = pre_delta;
+ decorr_mono(samples, outsamples, FFMIN(2048, nb_samples), &dp, -1);
+ dp.delta = delta;
+
+ if (tindex == 0)
+ reverse_mono_decorr(&dp);
+ else
+ CLEAR(dp.samplesA);
+
+ memcpy(dppi->samplesA, dp.samplesA, sizeof(dp.samplesA));
+ dppi->weightA = dp.weightA;
+
+ if (delta == 0) {
+ dp.delta = 1;
+ decorr_mono(samples, outsamples, nb_samples, &dp, 1);
+ dp.delta = 0;
+ memcpy(dp.samplesA, dppi->samplesA, sizeof(dp.samplesA));
+ dppi->weightA = dp.weightA = dp.sumA / nb_samples;
+ }
+
+ decorr_mono(samples, outsamples, nb_samples, &dp, 1);
+}
+
+static void recurse_mono(WavPackEncodeContext *s, WavPackExtraInfo *info,
+ int depth, int delta, uint32_t input_bits)
+{
+ int term, branches = s->num_branches - depth;
+ int32_t *samples, *outsamples;
+ uint32_t term_bits[22], bits;
+
+ if (branches < 1 || depth + 1 == info->nterms)
+ branches = 1;
+
+ CLEAR(term_bits);
+ samples = s->sampleptrs[depth][0];
+ outsamples = s->sampleptrs[depth + 1][0];
+
+ for (term = 1; term <= 18; term++) {
+ if (term == 17 && branches == 1 && depth + 1 < info->nterms)
+ continue;
+
+ if (term > 8 && term < 17)
+ continue;
+
+ if (!s->extra_flags && (term > 4 && term < 17))
+ continue;
+
+ info->dps[depth].value = term;
+ info->dps[depth].delta = delta;
+ decorr_mono_buffer(samples, outsamples, s->block_samples, info->dps, depth);
+ bits = log2mono(outsamples, s->block_samples, info->log_limit);
+
+ if (bits < info->best_bits) {
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * (depth + 1));
+ memcpy(s->sampleptrs[info->nterms + 1][0],
+ s->sampleptrs[depth + 1][0], s->block_samples * 4);
+ }
+
+ term_bits[term + 3] = bits;
+ }
+
+ while (depth + 1 < info->nterms && branches--) {
+ uint32_t local_best_bits = input_bits;
+ int best_term = 0, i;
+
+ for (i = 0; i < 22; i++)
+ if (term_bits[i] && term_bits[i] < local_best_bits) {
+ local_best_bits = term_bits[i];
+ best_term = i - 3;
+ }
+
+ if (!best_term)
+ break;
+
+ term_bits[best_term + 3] = 0;
+
+ info->dps[depth].value = best_term;
+ info->dps[depth].delta = delta;
+ decorr_mono_buffer(samples, outsamples, s->block_samples, info->dps, depth);
+
+ recurse_mono(s, info, depth + 1, delta, local_best_bits);
+ }
+}
+
+static void sort_mono(WavPackEncodeContext *s, WavPackExtraInfo *info)
+{
+ int reversed = 1;
+ uint32_t bits;
+
+ while (reversed) {
+ int ri, i;
+
+ memcpy(info->dps, s->decorr_passes, sizeof(s->decorr_passes));
+ reversed = 0;
+
+ for (ri = 0; ri < info->nterms && s->decorr_passes[ri].value; ri++) {
+
+ if (ri + 1 >= info->nterms || !s->decorr_passes[ri+1].value)
+ break;
+
+ if (s->decorr_passes[ri].value == s->decorr_passes[ri+1].value) {
+ decorr_mono_buffer(s->sampleptrs[ri][0], s->sampleptrs[ri+1][0],
+ s->block_samples, info->dps, ri);
+ continue;
+ }
+
+ info->dps[ri ] = s->decorr_passes[ri+1];
+ info->dps[ri+1] = s->decorr_passes[ri ];
+
+ for (i = ri; i < info->nterms && s->decorr_passes[i].value; i++)
+ decorr_mono_buffer(s->sampleptrs[i][0], s->sampleptrs[i+1][0],
+ s->block_samples, info->dps, i);
+
+ bits = log2mono(s->sampleptrs[i][0], s->block_samples, info->log_limit);
+ if (bits < info->best_bits) {
+ reversed = 1;
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * i);
+ memcpy(s->sampleptrs[info->nterms + 1][0], s->sampleptrs[i][0],
+ s->block_samples * 4);
+ } else {
+ info->dps[ri ] = s->decorr_passes[ri];
+ info->dps[ri+1] = s->decorr_passes[ri+1];
+ decorr_mono_buffer(s->sampleptrs[ri][0], s->sampleptrs[ri+1][0],
+ s->block_samples, info->dps, ri);
+ }
+ }
+ }
+}
+
+static void delta_mono(WavPackEncodeContext *s, WavPackExtraInfo *info)
+{
+ int lower = 0, delta, d;
+ uint32_t bits;
+
+ if (!s->decorr_passes[0].value)
+ return;
+ delta = s->decorr_passes[0].delta;
+
+ for (d = delta - 1; d >= 0; d--) {
+ int i;
+
+ for (i = 0; i < info->nterms && s->decorr_passes[i].value; i++) {
+ info->dps[i].value = s->decorr_passes[i].value;
+ info->dps[i].delta = d;
+ decorr_mono_buffer(s->sampleptrs[i][0], s->sampleptrs[i+1][0],
+ s->block_samples, info->dps, i);
+ }
+
+ bits = log2mono(s->sampleptrs[i][0], s->block_samples, info->log_limit);
+ if (bits >= info->best_bits)
+ break;
+
+ lower = 1;
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * i);
+ memcpy(s->sampleptrs[info->nterms + 1][0], s->sampleptrs[i][0],
+ s->block_samples * 4);
+ }
+
+ for (d = delta + 1; !lower && d <= 7; d++) {
+ int i;
+
+ for (i = 0; i < info->nterms && s->decorr_passes[i].value; i++) {
+ info->dps[i].value = s->decorr_passes[i].value;
+ info->dps[i].delta = d;
+ decorr_mono_buffer(s->sampleptrs[i][0], s->sampleptrs[i+1][0],
+ s->block_samples, info->dps, i);
+ }
+
+ bits = log2mono(s->sampleptrs[i][0], s->block_samples, info->log_limit);
+ if (bits >= info->best_bits)
+ break;
+
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * i);
+ memcpy(s->sampleptrs[info->nterms + 1][0], s->sampleptrs[i][0],
+ s->block_samples * 4);
+ }
+}
+
+static int allocate_buffers2(WavPackEncodeContext *s, int nterms)
+{
+ int i;
+
+ for (i = 0; i < nterms + 2; i++) {
+ av_fast_padded_malloc(&s->sampleptrs[i][0], &s->sampleptrs_size[i][0],
+ s->block_samples * 4);
+ if (!s->sampleptrs[i][0])
+ return AVERROR(ENOMEM);
+ if (!(s->flags & WV_MONO_DATA)) {
+ av_fast_padded_malloc(&s->sampleptrs[i][1], &s->sampleptrs_size[i][1],
+ s->block_samples * 4);
+ if (!s->sampleptrs[i][1])
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
+
+static int allocate_buffers(WavPackEncodeContext *s)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ av_fast_padded_malloc(&s->best_buffer[0], &s->best_buffer_size[0],
+ s->block_samples * 4);
+ if (!s->best_buffer[0])
+ return AVERROR(ENOMEM);
+
+ av_fast_padded_malloc(&s->temp_buffer[i][0], &s->temp_buffer_size[i][0],
+ s->block_samples * 4);
+ if (!s->temp_buffer[i][0])
+ return AVERROR(ENOMEM);
+ if (!(s->flags & WV_MONO_DATA)) {
+ av_fast_padded_malloc(&s->best_buffer[1], &s->best_buffer_size[1],
+ s->block_samples * 4);
+ if (!s->best_buffer[1])
+ return AVERROR(ENOMEM);
+
+ av_fast_padded_malloc(&s->temp_buffer[i][1], &s->temp_buffer_size[i][1],
+ s->block_samples * 4);
+ if (!s->temp_buffer[i][1])
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ return 0;
+}
+
+static void analyze_mono(WavPackEncodeContext *s, int32_t *samples, int do_samples)
+{
+ WavPackExtraInfo info;
+ int i;
+
+ info.log_limit = (((s->flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
+ info.log_limit = FFMIN(6912, info.log_limit);
+
+ info.nterms = s->num_terms;
+
+ if (allocate_buffers2(s, s->num_terms))
+ return;
+
+ memcpy(info.dps, s->decorr_passes, sizeof(info.dps));
+ memcpy(s->sampleptrs[0][0], samples, s->block_samples * 4);
+
+ for (i = 0; i < info.nterms && info.dps[i].value; i++)
+ decorr_mono(s->sampleptrs[i][0], s->sampleptrs[i + 1][0],
+ s->block_samples, info.dps + i, 1);
+
+ info.best_bits = log2mono(s->sampleptrs[info.nterms][0], s->block_samples, 0) * 1;
+ memcpy(s->sampleptrs[info.nterms + 1][0], s->sampleptrs[i][0], s->block_samples * 4);
+
+ if (s->extra_flags & EXTRA_BRANCHES)
+ recurse_mono(s, &info, 0, (int) floor(s->delta_decay + 0.5),
+ log2mono(s->sampleptrs[0][0], s->block_samples, 0));
+
+ if (s->extra_flags & EXTRA_SORT_FIRST)
+ sort_mono(s, &info);
+
+ if (s->extra_flags & EXTRA_TRY_DELTAS) {
+ delta_mono(s, &info);
+
+ if ((s->extra_flags & EXTRA_ADJUST_DELTAS) && s->decorr_passes[0].value)
+ s->delta_decay = (float)((s->delta_decay * 2.0 + s->decorr_passes[0].delta) / 3.0);
+ else
+ s->delta_decay = 2.0;
+ }
+
+ if (s->extra_flags & EXTRA_SORT_LAST)
+ sort_mono(s, &info);
+
+ if (do_samples)
+ memcpy(samples, s->sampleptrs[info.nterms + 1][0], s->block_samples * 4);
+
+ for (i = 0; i < info.nterms; i++)
+ if (!s->decorr_passes[i].value)
+ break;
+
+ s->num_terms = i;
+}
+
+static void scan_word(WavPackEncodeContext *s, WvChannel *c,
+ int32_t *samples, int nb_samples, int dir)
+{
+ if (dir < 0)
+ samples += nb_samples - 1;
+
+ while (nb_samples--) {
+ uint32_t low, value = labs(samples[0]);
+
+ if (value < GET_MED(0)) {
+ DEC_MED(0);
+ } else {
+ low = GET_MED(0);
+ INC_MED(0);
+
+ if (value - low < GET_MED(1)) {
+ DEC_MED(1);
+ } else {
+ low += GET_MED(1);
+ INC_MED(1);
+
+ if (value - low < GET_MED(2)) {
+ DEC_MED(2);
+ } else {
+ INC_MED(2);
+ }
+ }
+ }
+ samples += dir;
+ }
+}
+
+static int wv_mono(WavPackEncodeContext *s, int32_t *samples,
+ int no_history, int do_samples)
+{
+ struct Decorr temp_decorr_pass, save_decorr_passes[MAX_TERMS] = {{0}};
+ int nb_samples = s->block_samples;
+ int buf_size = sizeof(int32_t) * nb_samples;
+ uint32_t best_size = UINT32_MAX, size;
+ int log_limit, pi, i, ret;
+
+ for (i = 0; i < nb_samples; i++)
+ if (samples[i])
+ break;
+
+ if (i == nb_samples) {
+ CLEAR(s->decorr_passes);
+ CLEAR(s->w);
+ s->num_terms = 0;
+ return 0;
+ }
+
+ log_limit = (((s->flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
+ log_limit = FFMIN(6912, log_limit);
+
+ if ((ret = allocate_buffers(s)) < 0)
+ return ret;
+
+ if (no_history || s->num_passes >= 7)
+ s->best_decorr = s->mask_decorr = 0;
+
+ for (pi = 0; pi < s->num_passes;) {
+ const WavPackDecorrSpec *wpds;
+ int nterms, c, j;
+
+ if (!pi) {
+ c = s->best_decorr;
+ } else {
+ if (s->mask_decorr == 0)
+ c = 0;
+ else
+ c = (s->best_decorr & (s->mask_decorr - 1)) | s->mask_decorr;
+
+ if (c == s->best_decorr) {
+ s->mask_decorr = s->mask_decorr ? ((s->mask_decorr << 1) & (s->num_decorrs - 1)) : 1;
+ continue;
+ }
+ }
+
+ wpds = &s->decorr_specs[c];
+ nterms = decorr_filter_nterms[s->decorr_filter];
+
+ while (1) {
+ memcpy(s->temp_buffer[0][0], samples, buf_size);
+ CLEAR(save_decorr_passes);
+
+ for (j = 0; j < nterms; j++) {
+ CLEAR(temp_decorr_pass);
+ temp_decorr_pass.delta = wpds->delta;
+ temp_decorr_pass.value = wpds->terms[j];
+
+ if (temp_decorr_pass.value < 0)
+ temp_decorr_pass.value = 1;
+
+ decorr_mono(s->temp_buffer[j&1][0], s->temp_buffer[~j&1][0],
+ FFMIN(nb_samples, 2048), &temp_decorr_pass, -1);
+
+ if (j) {
+ CLEAR(temp_decorr_pass.samplesA);
+ } else {
+ reverse_mono_decorr(&temp_decorr_pass);
+ }
+
+ memcpy(save_decorr_passes + j, &temp_decorr_pass, sizeof(struct Decorr));
+ decorr_mono(s->temp_buffer[j&1][0], s->temp_buffer[~j&1][0],
+ nb_samples, &temp_decorr_pass, 1);
+ }
+
+ size = log2mono(s->temp_buffer[j&1][0], nb_samples, log_limit);
+ if (size != UINT32_MAX || !nterms)
+ break;
+ nterms >>= 1;
+ }
+
+ if (size < best_size) {
+ memcpy(s->best_buffer[0], s->temp_buffer[j&1][0], buf_size);
+ memcpy(s->decorr_passes, save_decorr_passes, sizeof(struct Decorr) * MAX_TERMS);
+ s->num_terms = nterms;
+ s->best_decorr = c;
+ best_size = size;
+ }
+
+ if (pi++)
+ s->mask_decorr = s->mask_decorr ? ((s->mask_decorr << 1) & (s->num_decorrs - 1)) : 1;
+ }
+
+ if (s->extra_flags)
+ analyze_mono(s, samples, do_samples);
+ else if (do_samples)
+ memcpy(samples, s->best_buffer[0], buf_size);
+
+ if (no_history || s->extra_flags) {
+ CLEAR(s->w);
+ scan_word(s, &s->w.c[0], s->best_buffer[0], nb_samples, -1);
+ }
+ return 0;
+}
+
+static void decorr_stereo(int32_t *in_left, int32_t *in_right,
+ int32_t *out_left, int32_t *out_right,
+ int nb_samples, struct Decorr *dpp, int dir)
+{
+ int m = 0, i;
+
+ dpp->sumA = dpp->sumB = 0;
+
+ if (dir < 0) {
+ out_left += nb_samples - 1;
+ out_right += nb_samples - 1;
+ in_left += nb_samples - 1;
+ in_right += nb_samples - 1;
+ }
+
+ dpp->weightA = restore_weight(store_weight(dpp->weightA));
+ dpp->weightB = restore_weight(store_weight(dpp->weightB));
+
+ for (i = 0; i < MAX_TERM; i++) {
+ dpp->samplesA[i] = wp_exp2(log2s(dpp->samplesA[i]));
+ dpp->samplesB[i] = wp_exp2(log2s(dpp->samplesB[i]));
+ }
+
+ switch (dpp->value) {
+ case 2:
+ while (nb_samples--) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[0];
+ dpp->samplesA[0] = dpp->samplesA[1];
+ out_left[0] = tmp = (dpp->samplesA[1] = in_left[0]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+ dpp->sumA += dpp->weightA;
+
+ sam = dpp->samplesB[0];
+ dpp->samplesB[0] = dpp->samplesB[1];
+ out_right[0] = tmp = (dpp->samplesB[1] = in_right[0]) - APPLY_WEIGHT(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ dpp->sumB += dpp->weightB;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ }
+ break;
+ case 17:
+ while (nb_samples--) {
+ int32_t sam, tmp;
+
+ sam = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ dpp->samplesA[1] = dpp->samplesA[0];
+ out_left[0] = tmp = (dpp->samplesA[0] = in_left[0]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+ dpp->sumA += dpp->weightA;
+
+ sam = 2 * dpp->samplesB[0] - dpp->samplesB[1];
+ dpp->samplesB[1] = dpp->samplesB[0];
+ out_right[0] = tmp = (dpp->samplesB[0] = in_right[0]) - APPLY_WEIGHT (dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ dpp->sumB += dpp->weightB;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ }
+ break;
+ case 18:
+ while (nb_samples--) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[0] + ((dpp->samplesA[0] - dpp->samplesA[1]) >> 1);
+ dpp->samplesA[1] = dpp->samplesA[0];
+ out_left[0] = tmp = (dpp->samplesA[0] = in_left[0]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+ dpp->sumA += dpp->weightA;
+
+ sam = dpp->samplesB[0] + ((dpp->samplesB[0] - dpp->samplesB[1]) >> 1);
+ dpp->samplesB[1] = dpp->samplesB[0];
+ out_right[0] = tmp = (dpp->samplesB[0] = in_right[0]) - APPLY_WEIGHT(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ dpp->sumB += dpp->weightB;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ }
+ break;
+ default: {
+ int k = dpp->value & (MAX_TERM - 1);
+
+ while (nb_samples--) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[m];
+ out_left[0] = tmp = (dpp->samplesA[k] = in_left[0]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+ dpp->sumA += dpp->weightA;
+
+ sam = dpp->samplesB[m];
+ out_right[0] = tmp = (dpp->samplesB[k] = in_right[0]) - APPLY_WEIGHT(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ dpp->sumB += dpp->weightB;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ m = (m + 1) & (MAX_TERM - 1);
+ k = (k + 1) & (MAX_TERM - 1);
+ }
+
+ if (m) {
+ int32_t temp_A[MAX_TERM], temp_B[MAX_TERM];
+ int k;
+
+ memcpy(temp_A, dpp->samplesA, sizeof(dpp->samplesA));
+ memcpy(temp_B, dpp->samplesB, sizeof(dpp->samplesB));
+
+ for (k = 0; k < MAX_TERM; k++) {
+ dpp->samplesA[k] = temp_A[m];
+ dpp->samplesB[k] = temp_B[m];
+ m = (m + 1) & (MAX_TERM - 1);
+ }
+ }
+ break;
+ }
+ case -1:
+ while (nb_samples--) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ out_left[0] = tmp = (sam_B = in_left[0]) - APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ dpp->sumA += dpp->weightA;
+
+ out_right[0] = tmp = (dpp->samplesA[0] = in_right[0]) - APPLY_WEIGHT(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+ dpp->sumB += dpp->weightB;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ }
+ break;
+ case -2:
+ while (nb_samples--) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_B = dpp->samplesB[0];
+ out_right[0] = tmp = (sam_A = in_right[0]) - APPLY_WEIGHT(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+ dpp->sumB += dpp->weightB;
+
+ out_left[0] = tmp = (dpp->samplesB[0] = in_left[0]) - APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ dpp->sumA += dpp->weightA;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ }
+ break;
+ case -3:
+ while (nb_samples--) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ sam_B = dpp->samplesB[0];
+
+ dpp->samplesA[0] = tmp = in_right[0];
+ out_right[0] = tmp -= APPLY_WEIGHT(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+ dpp->sumB += dpp->weightB;
+
+ dpp->samplesB[0] = tmp = in_left[0];
+ out_left[0] = tmp -= APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ dpp->sumA += dpp->weightA;
+
+ in_left += dir;
+ out_left += dir;
+ in_right += dir;
+ out_right += dir;
+ }
+ break;
+ }
+}
+
+static void reverse_decorr(struct Decorr *dpp)
+{
+ if (dpp->value > MAX_TERM) {
+ int32_t sam_A, sam_B;
+
+ if (dpp->value & 1) {
+ sam_A = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ sam_B = 2 * dpp->samplesB[0] - dpp->samplesB[1];
+ } else {
+ sam_A = (3 * dpp->samplesA[0] - dpp->samplesA[1]) >> 1;
+ sam_B = (3 * dpp->samplesB[0] - dpp->samplesB[1]) >> 1;
+ }
+
+ dpp->samplesA[1] = dpp->samplesA[0];
+ dpp->samplesB[1] = dpp->samplesB[0];
+ dpp->samplesA[0] = sam_A;
+ dpp->samplesB[0] = sam_B;
+
+ if (dpp->value & 1) {
+ sam_A = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ sam_B = 2 * dpp->samplesB[0] - dpp->samplesB[1];
+ } else {
+ sam_A = (3 * dpp->samplesA[0] - dpp->samplesA[1]) >> 1;
+ sam_B = (3 * dpp->samplesB[0] - dpp->samplesB[1]) >> 1;
+ }
+
+ dpp->samplesA[1] = sam_A;
+ dpp->samplesB[1] = sam_B;
+ } else if (dpp->value > 1) {
+ int i, j, k;
+
+ for (i = 0, j = dpp->value - 1, k = 0; k < dpp->value / 2; i++, j--, k++) {
+ i &= (MAX_TERM - 1);
+ j &= (MAX_TERM - 1);
+ dpp->samplesA[i] ^= dpp->samplesA[j];
+ dpp->samplesA[j] ^= dpp->samplesA[i];
+ dpp->samplesA[i] ^= dpp->samplesA[j];
+ dpp->samplesB[i] ^= dpp->samplesB[j];
+ dpp->samplesB[j] ^= dpp->samplesB[i];
+ dpp->samplesB[i] ^= dpp->samplesB[j];
+ }
+ }
+}
+
+static void decorr_stereo_quick(int32_t *in_left, int32_t *in_right,
+ int32_t *out_left, int32_t *out_right,
+ int nb_samples, struct Decorr *dpp)
+{
+ int m = 0, i;
+
+ dpp->weightA = restore_weight(store_weight(dpp->weightA));
+ dpp->weightB = restore_weight(store_weight(dpp->weightB));
+
+ for (i = 0; i < MAX_TERM; i++) {
+ dpp->samplesA[i] = wp_exp2(log2s(dpp->samplesA[i]));
+ dpp->samplesB[i] = wp_exp2(log2s(dpp->samplesB[i]));
+ }
+
+ switch (dpp->value) {
+ case 2:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[0];
+ dpp->samplesA[0] = dpp->samplesA[1];
+ out_left[i] = tmp = (dpp->samplesA[1] = in_left[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[0];
+ dpp->samplesB[0] = dpp->samplesB[1];
+ out_right[i] = tmp = (dpp->samplesB[1] = in_right[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ case 17:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ dpp->samplesA[1] = dpp->samplesA[0];
+ out_left[i] = tmp = (dpp->samplesA[0] = in_left[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = 2 * dpp->samplesB[0] - dpp->samplesB[1];
+ dpp->samplesB[1] = dpp->samplesB[0];
+ out_right[i] = tmp = (dpp->samplesB[0] = in_right[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ case 18:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[0] + ((dpp->samplesA[0] - dpp->samplesA[1]) >> 1);
+ dpp->samplesA[1] = dpp->samplesA[0];
+ out_left[i] = tmp = (dpp->samplesA[0] = in_left[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[0] + ((dpp->samplesB[0] - dpp->samplesB[1]) >> 1);
+ dpp->samplesB[1] = dpp->samplesB[0];
+ out_right[i] = tmp = (dpp->samplesB[0] = in_right[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ default: {
+ int k = dpp->value & (MAX_TERM - 1);
+
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[m];
+ out_left[i] = tmp = (dpp->samplesA[k] = in_left[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[m];
+ out_right[i] = tmp = (dpp->samplesB[k] = in_right[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+
+ m = (m + 1) & (MAX_TERM - 1);
+ k = (k + 1) & (MAX_TERM - 1);
+ }
+
+ if (m) {
+ int32_t temp_A[MAX_TERM], temp_B[MAX_TERM];
+ int k;
+
+ memcpy(temp_A, dpp->samplesA, sizeof(dpp->samplesA));
+ memcpy(temp_B, dpp->samplesB, sizeof(dpp->samplesB));
+
+ for (k = 0; k < MAX_TERM; k++) {
+ dpp->samplesA[k] = temp_A[m];
+ dpp->samplesB[k] = temp_B[m];
+ m = (m + 1) & (MAX_TERM - 1);
+ }
+ }
+ break;
+ }
+ case -1:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ out_left[i] = tmp = (sam_B = in_left[i]) - APPLY_WEIGHT_I(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+
+ out_right[i] = tmp = (dpp->samplesA[0] = in_right[i]) - APPLY_WEIGHT_I(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+ }
+ break;
+ case -2:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_B = dpp->samplesB[0];
+ out_right[i] = tmp = (sam_A = in_right[i]) - APPLY_WEIGHT_I(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+
+ out_left[i] = tmp = (dpp->samplesB[0] = in_left[i]) - APPLY_WEIGHT_I(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ }
+ break;
+ case -3:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ sam_B = dpp->samplesB[0];
+
+ dpp->samplesA[0] = tmp = in_right[i];
+ out_right[i] = tmp -= APPLY_WEIGHT_I(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+
+ dpp->samplesB[0] = tmp = in_left[i];
+ out_left[i] = tmp -= APPLY_WEIGHT_I(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ }
+ break;
+ }
+}
+
+static void decorr_stereo_buffer(WavPackExtraInfo *info,
+ int32_t *in_left, int32_t *in_right,
+ int32_t *out_left, int32_t *out_right,
+ int nb_samples, int tindex)
+{
+ struct Decorr dp = {0}, *dppi = info->dps + tindex;
+ int delta = dppi->delta, pre_delta;
+ int term = dppi->value;
+
+ if (delta == 7)
+ pre_delta = 7;
+ else if (delta < 2)
+ pre_delta = 3;
+ else
+ pre_delta = delta + 1;
+
+ dp.value = term;
+ dp.delta = pre_delta;
+ decorr_stereo(in_left, in_right, out_left, out_right,
+ FFMIN(2048, nb_samples), &dp, -1);
+ dp.delta = delta;
+
+ if (tindex == 0) {
+ reverse_decorr(&dp);
+ } else {
+ CLEAR(dp.samplesA);
+ CLEAR(dp.samplesB);
+ }
+
+ memcpy(dppi->samplesA, dp.samplesA, sizeof(dp.samplesA));
+ memcpy(dppi->samplesB, dp.samplesB, sizeof(dp.samplesB));
+ dppi->weightA = dp.weightA;
+ dppi->weightB = dp.weightB;
+
+ if (delta == 0) {
+ dp.delta = 1;
+ decorr_stereo(in_left, in_right, out_left, out_right, nb_samples, &dp, 1);
+ dp.delta = 0;
+ memcpy(dp.samplesA, dppi->samplesA, sizeof(dp.samplesA));
+ memcpy(dp.samplesB, dppi->samplesB, sizeof(dp.samplesB));
+ dppi->weightA = dp.weightA = dp.sumA / nb_samples;
+ dppi->weightB = dp.weightB = dp.sumB / nb_samples;
+ }
+
+ if (info->gt16bit)
+ decorr_stereo(in_left, in_right, out_left, out_right,
+ nb_samples, &dp, 1);
+ else
+ decorr_stereo_quick(in_left, in_right, out_left, out_right,
+ nb_samples, &dp);
+}
+
+static void sort_stereo(WavPackEncodeContext *s, WavPackExtraInfo *info)
+{
+ int reversed = 1;
+ uint32_t bits;
+
+ while (reversed) {
+ int ri, i;
+
+ memcpy(info->dps, s->decorr_passes, sizeof(s->decorr_passes));
+ reversed = 0;
+
+ for (ri = 0; ri < info->nterms && s->decorr_passes[ri].value; ri++) {
+
+ if (ri + 1 >= info->nterms || !s->decorr_passes[ri+1].value)
+ break;
+
+ if (s->decorr_passes[ri].value == s->decorr_passes[ri+1].value) {
+ decorr_stereo_buffer(info,
+ s->sampleptrs[ri ][0], s->sampleptrs[ri ][1],
+ s->sampleptrs[ri+1][0], s->sampleptrs[ri+1][1],
+ s->block_samples, ri);
+ continue;
+ }
+
+ info->dps[ri ] = s->decorr_passes[ri+1];
+ info->dps[ri+1] = s->decorr_passes[ri ];
+
+ for (i = ri; i < info->nterms && s->decorr_passes[i].value; i++)
+ decorr_stereo_buffer(info,
+ s->sampleptrs[i ][0], s->sampleptrs[i ][1],
+ s->sampleptrs[i+1][0], s->sampleptrs[i+1][1],
+ s->block_samples, i);
+
+ bits = log2stereo(s->sampleptrs[i][0], s->sampleptrs[i][1],
+ s->block_samples, info->log_limit);
+
+ if (bits < info->best_bits) {
+ reversed = 1;
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * i);
+ memcpy(s->sampleptrs[info->nterms + 1][0],
+ s->sampleptrs[i][0], s->block_samples * 4);
+ memcpy(s->sampleptrs[info->nterms + 1][1],
+ s->sampleptrs[i][1], s->block_samples * 4);
+ } else {
+ info->dps[ri ] = s->decorr_passes[ri ];
+ info->dps[ri+1] = s->decorr_passes[ri+1];
+ decorr_stereo_buffer(info,
+ s->sampleptrs[ri ][0], s->sampleptrs[ri ][1],
+ s->sampleptrs[ri+1][0], s->sampleptrs[ri+1][1],
+ s->block_samples, ri);
+ }
+ }
+ }
+}
+
+static void delta_stereo(WavPackEncodeContext *s, WavPackExtraInfo *info)
+{
+ int lower = 0, delta, d, i;
+ uint32_t bits;
+
+ if (!s->decorr_passes[0].value)
+ return;
+ delta = s->decorr_passes[0].delta;
+
+ for (d = delta - 1; d >= 0; d--) {
+ for (i = 0; i < info->nterms && s->decorr_passes[i].value; i++) {
+ info->dps[i].value = s->decorr_passes[i].value;
+ info->dps[i].delta = d;
+ decorr_stereo_buffer(info,
+ s->sampleptrs[i ][0], s->sampleptrs[i ][1],
+ s->sampleptrs[i+1][0], s->sampleptrs[i+1][1],
+ s->block_samples, i);
+ }
+
+ bits = log2stereo(s->sampleptrs[i][0], s->sampleptrs[i][1],
+ s->block_samples, info->log_limit);
+ if (bits >= info->best_bits)
+ break;
+ lower = 1;
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * i);
+ memcpy(s->sampleptrs[info->nterms + 1][0], s->sampleptrs[i][0],
+ s->block_samples * 4);
+ memcpy(s->sampleptrs[info->nterms + 1][1], s->sampleptrs[i][1],
+ s->block_samples * 4);
+ }
+
+ for (d = delta + 1; !lower && d <= 7; d++) {
+ for (i = 0; i < info->nterms && s->decorr_passes[i].value; i++) {
+ info->dps[i].value = s->decorr_passes[i].value;
+ info->dps[i].delta = d;
+ decorr_stereo_buffer(info,
+ s->sampleptrs[i ][0], s->sampleptrs[i ][1],
+ s->sampleptrs[i+1][0], s->sampleptrs[i+1][1],
+ s->block_samples, i);
+ }
+
+ bits = log2stereo(s->sampleptrs[i][0], s->sampleptrs[i][1],
+ s->block_samples, info->log_limit);
+
+ if (bits < info->best_bits) {
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * i);
+ memcpy(s->sampleptrs[info->nterms + 1][0],
+ s->sampleptrs[i][0], s->block_samples * 4);
+ memcpy(s->sampleptrs[info->nterms + 1][1],
+ s->sampleptrs[i][1], s->block_samples * 4);
+ }
+ else
+ break;
+ }
+}
+
+static void recurse_stereo(WavPackEncodeContext *s, WavPackExtraInfo *info,
+ int depth, int delta, uint32_t input_bits)
+{
+ int term, branches = s->num_branches - depth;
+ int32_t *in_left, *in_right, *out_left, *out_right;
+ uint32_t term_bits[22], bits;
+
+ if (branches < 1 || depth + 1 == info->nterms)
+ branches = 1;
+
+ CLEAR(term_bits);
+ in_left = s->sampleptrs[depth ][0];
+ in_right = s->sampleptrs[depth ][1];
+ out_left = s->sampleptrs[depth + 1][0];
+ out_right = s->sampleptrs[depth + 1][1];
+
+ for (term = -3; term <= 18; term++) {
+ if (!term || (term > 8 && term < 17))
+ continue;
+
+ if (term == 17 && branches == 1 && depth + 1 < info->nterms)
+ continue;
+
+ if (term == -1 || term == -2)
+ if (!(s->flags & WV_CROSS_DECORR))
+ continue;
+
+ if (!s->extra_flags && (term > 4 && term < 17))
+ continue;
+
+ info->dps[depth].value = term;
+ info->dps[depth].delta = delta;
+ decorr_stereo_buffer(info, in_left, in_right, out_left, out_right,
+ s->block_samples, depth);
+ bits = log2stereo(out_left, out_right, s->block_samples, info->log_limit);
+
+ if (bits < info->best_bits) {
+ info->best_bits = bits;
+ CLEAR(s->decorr_passes);
+ memcpy(s->decorr_passes, info->dps, sizeof(info->dps[0]) * (depth + 1));
+ memcpy(s->sampleptrs[info->nterms + 1][0], s->sampleptrs[depth + 1][0],
+ s->block_samples * 4);
+ memcpy(s->sampleptrs[info->nterms + 1][1], s->sampleptrs[depth + 1][1],
+ s->block_samples * 4);
+ }
+
+ term_bits[term + 3] = bits;
+ }
+
+ while (depth + 1 < info->nterms && branches--) {
+ uint32_t local_best_bits = input_bits;
+ int best_term = 0, i;
+
+ for (i = 0; i < 22; i++)
+ if (term_bits[i] && term_bits[i] < local_best_bits) {
+ local_best_bits = term_bits[i];
+ best_term = i - 3;
+ }
+
+ if (!best_term)
+ break;
+
+ term_bits[best_term + 3] = 0;
+
+ info->dps[depth].value = best_term;
+ info->dps[depth].delta = delta;
+ decorr_stereo_buffer(info, in_left, in_right, out_left, out_right,
+ s->block_samples, depth);
+
+ recurse_stereo(s, info, depth + 1, delta, local_best_bits);
+ }
+}
+
+static void analyze_stereo(WavPackEncodeContext *s,
+ int32_t *in_left, int32_t *in_right,
+ int do_samples)
+{
+ WavPackExtraInfo info;
+ int i;
+
+ info.gt16bit = ((s->flags & MAG_MASK) >> MAG_LSB) >= 16;
+
+ info.log_limit = (((s->flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
+ info.log_limit = FFMIN(6912, info.log_limit);
+
+ info.nterms = s->num_terms;
+
+ if (allocate_buffers2(s, s->num_terms))
+ return;
+
+ memcpy(info.dps, s->decorr_passes, sizeof(info.dps));
+ memcpy(s->sampleptrs[0][0], in_left, s->block_samples * 4);
+ memcpy(s->sampleptrs[0][1], in_right, s->block_samples * 4);
+
+ for (i = 0; i < info.nterms && info.dps[i].value; i++)
+ if (info.gt16bit)
+ decorr_stereo(s->sampleptrs[i ][0], s->sampleptrs[i ][1],
+ s->sampleptrs[i + 1][0], s->sampleptrs[i + 1][1],
+ s->block_samples, info.dps + i, 1);
+ else
+ decorr_stereo_quick(s->sampleptrs[i ][0], s->sampleptrs[i ][1],
+ s->sampleptrs[i + 1][0], s->sampleptrs[i + 1][1],
+ s->block_samples, info.dps + i);
+
+ info.best_bits = log2stereo(s->sampleptrs[info.nterms][0], s->sampleptrs[info.nterms][1],
+ s->block_samples, 0);
+
+ memcpy(s->sampleptrs[info.nterms + 1][0], s->sampleptrs[i][0], s->block_samples * 4);
+ memcpy(s->sampleptrs[info.nterms + 1][1], s->sampleptrs[i][1], s->block_samples * 4);
+
+ if (s->extra_flags & EXTRA_BRANCHES)
+ recurse_stereo(s, &info, 0, (int) floor(s->delta_decay + 0.5),
+ log2stereo(s->sampleptrs[0][0], s->sampleptrs[0][1],
+ s->block_samples, 0));
+
+ if (s->extra_flags & EXTRA_SORT_FIRST)
+ sort_stereo(s, &info);
+
+ if (s->extra_flags & EXTRA_TRY_DELTAS) {
+ delta_stereo(s, &info);
+
+ if ((s->extra_flags & EXTRA_ADJUST_DELTAS) && s->decorr_passes[0].value)
+ s->delta_decay = (float)((s->delta_decay * 2.0 + s->decorr_passes[0].delta) / 3.0);
+ else
+ s->delta_decay = 2.0;
+ }
+
+ if (s->extra_flags & EXTRA_SORT_LAST)
+ sort_stereo(s, &info);
+
+ if (do_samples) {
+ memcpy(in_left, s->sampleptrs[info.nterms + 1][0], s->block_samples * 4);
+ memcpy(in_right, s->sampleptrs[info.nterms + 1][1], s->block_samples * 4);
+ }
+
+ for (i = 0; i < info.nterms; i++)
+ if (!s->decorr_passes[i].value)
+ break;
+
+ s->num_terms = i;
+}
+
+static int wv_stereo(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ int no_history, int do_samples)
+{
+ struct Decorr temp_decorr_pass, save_decorr_passes[MAX_TERMS] = {{0}};
+ int nb_samples = s->block_samples, ret;
+ int buf_size = sizeof(int32_t) * nb_samples;
+ int log_limit, force_js = 0, force_ts = 0, got_js = 0, pi, i;
+ uint32_t best_size = UINT32_MAX, size;
+
+ for (i = 0; i < nb_samples; i++)
+ if (samples_l[i] || samples_r[i])
+ break;
+
+ if (i == nb_samples) {
+ s->flags &= ~((uint32_t) WV_JOINT_STEREO);
+ CLEAR(s->decorr_passes);
+ CLEAR(s->w);
+ s->num_terms = 0;
+ return 0;
+ }
+
+ log_limit = (((s->flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
+ log_limit = FFMIN(6912, log_limit);
+
+ if (s->joint) {
+ force_js = s->joint > 0;
+ force_ts = s->joint < 0;
+ }
+
+ if ((ret = allocate_buffers(s)) < 0)
+ return ret;
+
+ if (no_history || s->num_passes >= 7)
+ s->best_decorr = s->mask_decorr = 0;
+
+ for (pi = 0; pi < s->num_passes;) {
+ const WavPackDecorrSpec *wpds;
+ int nterms, c, j;
+
+ if (!pi)
+ c = s->best_decorr;
+ else {
+ if (s->mask_decorr == 0)
+ c = 0;
+ else
+ c = (s->best_decorr & (s->mask_decorr - 1)) | s->mask_decorr;
+
+ if (c == s->best_decorr) {
+ s->mask_decorr = s->mask_decorr ? ((s->mask_decorr << 1) & (s->num_decorrs - 1)) : 1;
+ continue;
+ }
+ }
+
+ wpds = &s->decorr_specs[c];
+ nterms = decorr_filter_nterms[s->decorr_filter];
+
+ while (1) {
+ if (force_js || (wpds->joint_stereo && !force_ts)) {
+ if (!got_js) {
+ av_fast_padded_malloc(&s->js_left, &s->js_left_size, buf_size);
+ av_fast_padded_malloc(&s->js_right, &s->js_right_size, buf_size);
+ memcpy(s->js_left, samples_l, buf_size);
+ memcpy(s->js_right, samples_r, buf_size);
+
+ for (i = 0; i < nb_samples; i++)
+ s->js_right[i] += ((s->js_left[i] -= s->js_right[i]) >> 1);
+ got_js = 1;
+ }
+
+ memcpy(s->temp_buffer[0][0], s->js_left, buf_size);
+ memcpy(s->temp_buffer[0][1], s->js_right, buf_size);
+ } else {
+ memcpy(s->temp_buffer[0][0], samples_l, buf_size);
+ memcpy(s->temp_buffer[0][1], samples_r, buf_size);
+ }
+
+ CLEAR(save_decorr_passes);
+
+ for (j = 0; j < nterms; j++) {
+ CLEAR(temp_decorr_pass);
+ temp_decorr_pass.delta = wpds->delta;
+ temp_decorr_pass.value = wpds->terms[j];
+
+ if (temp_decorr_pass.value < 0 && !(s->flags & WV_CROSS_DECORR))
+ temp_decorr_pass.value = -3;
+
+ decorr_stereo(s->temp_buffer[ j&1][0], s->temp_buffer[ j&1][1],
+ s->temp_buffer[~j&1][0], s->temp_buffer[~j&1][1],
+ FFMIN(2048, nb_samples), &temp_decorr_pass, -1);
+
+ if (j) {
+ CLEAR(temp_decorr_pass.samplesA);
+ CLEAR(temp_decorr_pass.samplesB);
+ } else {
+ reverse_decorr(&temp_decorr_pass);
+ }
+
+ memcpy(save_decorr_passes + j, &temp_decorr_pass, sizeof(struct Decorr));
+
+ if (((s->flags & MAG_MASK) >> MAG_LSB) >= 16)
+ decorr_stereo(s->temp_buffer[ j&1][0], s->temp_buffer[ j&1][1],
+ s->temp_buffer[~j&1][0], s->temp_buffer[~j&1][1],
+ nb_samples, &temp_decorr_pass, 1);
+ else
+ decorr_stereo_quick(s->temp_buffer[ j&1][0], s->temp_buffer[ j&1][1],
+ s->temp_buffer[~j&1][0], s->temp_buffer[~j&1][1],
+ nb_samples, &temp_decorr_pass);
+ }
+
+ size = log2stereo(s->temp_buffer[j&1][0], s->temp_buffer[j&1][1],
+ nb_samples, log_limit);
+ if (size != UINT32_MAX || !nterms)
+ break;
+ nterms >>= 1;
+ }
+
+ if (size < best_size) {
+ memcpy(s->best_buffer[0], s->temp_buffer[j&1][0], buf_size);
+ memcpy(s->best_buffer[1], s->temp_buffer[j&1][1], buf_size);
+ memcpy(s->decorr_passes, save_decorr_passes, sizeof(struct Decorr) * MAX_TERMS);
+ s->num_terms = nterms;
+ s->best_decorr = c;
+ best_size = size;
+ }
+
+ if (pi++)
+ s->mask_decorr = s->mask_decorr ? ((s->mask_decorr << 1) & (s->num_decorrs - 1)) : 1;
+ }
+
+ if (force_js || (s->decorr_specs[s->best_decorr].joint_stereo && !force_ts))
+ s->flags |= WV_JOINT_STEREO;
+ else
+ s->flags &= ~((uint32_t) WV_JOINT_STEREO);
+
+ if (s->extra_flags) {
+ if (s->flags & WV_JOINT_STEREO) {
+ analyze_stereo(s, s->js_left, s->js_right, do_samples);
+
+ if (do_samples) {
+ memcpy(samples_l, s->js_left, buf_size);
+ memcpy(samples_r, s->js_right, buf_size);
+ }
+ } else
+ analyze_stereo(s, samples_l, samples_r, do_samples);
+ } else if (do_samples) {
+ memcpy(samples_l, s->best_buffer[0], buf_size);
+ memcpy(samples_r, s->best_buffer[1], buf_size);
+ }
+
+ if (s->extra_flags || no_history ||
+ s->joint_stereo != s->decorr_specs[s->best_decorr].joint_stereo) {
+ s->joint_stereo = s->decorr_specs[s->best_decorr].joint_stereo;
+ CLEAR(s->w);
+ scan_word(s, &s->w.c[0], s->best_buffer[0], nb_samples, -1);
+ scan_word(s, &s->w.c[1], s->best_buffer[1], nb_samples, -1);
+ }
+ return 0;
+}
+
+#define count_bits(av) ( \
+ (av) < (1 << 8) ? nbits_table[av] : \
+ ( \
+ (av) < (1 << 16) ? nbits_table[(av) >> 8] + 8 : \
+ ((av) < (1 << 24) ? nbits_table[(av) >> 16] + 16 : nbits_table[(av) >> 24] + 24) \
+ ) \
+)
+
+static void encode_flush(WavPackEncodeContext *s)
+{
+ WavPackWords *w = &s->w;
+ PutBitContext *pb = &s->pb;
+
+ if (w->zeros_acc) {
+ int cbits = count_bits(w->zeros_acc);
+
+ do {
+ if (cbits > 31) {
+ put_bits(pb, 31, 0x7FFFFFFF);
+ cbits -= 31;
+ } else {
+ put_bits(pb, cbits, (1 << cbits) - 1);
+ cbits = 0;
+ }
+ } while (cbits);
+
+ put_bits(pb, 1, 0);
+
+ while (w->zeros_acc > 1) {
+ put_bits(pb, 1, w->zeros_acc & 1);
+ w->zeros_acc >>= 1;
+ }
+
+ w->zeros_acc = 0;
+ }
+
+ if (w->holding_one) {
+ if (w->holding_one >= 16) {
+ int cbits;
+
+ put_bits(pb, 16, (1 << 16) - 1);
+ put_bits(pb, 1, 0);
+ w->holding_one -= 16;
+ cbits = count_bits(w->holding_one);
+
+ do {
+ if (cbits > 31) {
+ put_bits(pb, 31, 0x7FFFFFFF);
+ cbits -= 31;
+ } else {
+ put_bits(pb, cbits, (1 << cbits) - 1);
+ cbits = 0;
+ }
+ } while (cbits);
+
+ put_bits(pb, 1, 0);
+
+ while (w->holding_one > 1) {
+ put_bits(pb, 1, w->holding_one & 1);
+ w->holding_one >>= 1;
+ }
+
+ w->holding_zero = 0;
+ } else {
+ put_bits(pb, w->holding_one, (1 << w->holding_one) - 1);
+ }
+
+ w->holding_one = 0;
+ }
+
+ if (w->holding_zero) {
+ put_bits(pb, 1, 0);
+ w->holding_zero = 0;
+ }
+
+ if (w->pend_count) {
+ put_bits(pb, w->pend_count, w->pend_data);
+ w->pend_data = w->pend_count = 0;
+ }
+}
+
+static void wavpack_encode_sample(WavPackEncodeContext *s, WvChannel *c, int32_t sample)
+{
+ WavPackWords *w = &s->w;
+ uint32_t ones_count, low, high;
+ int sign = sample < 0;
+
+ if (s->w.c[0].median[0] < 2 && !s->w.holding_zero && s->w.c[1].median[0] < 2) {
+ if (w->zeros_acc) {
+ if (sample)
+ encode_flush(s);
+ else {
+ w->zeros_acc++;
+ return;
+ }
+ } else if (sample) {
+ put_bits(&s->pb, 1, 0);
+ } else {
+ CLEAR(s->w.c[0].median);
+ CLEAR(s->w.c[1].median);
+ w->zeros_acc = 1;
+ return;
+ }
+ }
+
+ if (sign)
+ sample = ~sample;
+
+ if (sample < (int32_t) GET_MED(0)) {
+ ones_count = low = 0;
+ high = GET_MED(0) - 1;
+ DEC_MED(0);
+ } else {
+ low = GET_MED(0);
+ INC_MED(0);
+
+ if (sample - low < GET_MED(1)) {
+ ones_count = 1;
+ high = low + GET_MED(1) - 1;
+ DEC_MED(1);
+ } else {
+ low += GET_MED(1);
+ INC_MED(1);
+
+ if (sample - low < GET_MED(2)) {
+ ones_count = 2;
+ high = low + GET_MED(2) - 1;
+ DEC_MED(2);
+ } else {
+ ones_count = 2 + (sample - low) / GET_MED(2);
+ low += (ones_count - 2) * GET_MED(2);
+ high = low + GET_MED(2) - 1;
+ INC_MED(2);
+ }
+ }
+ }
+
+ if (w->holding_zero) {
+ if (ones_count)
+ w->holding_one++;
+
+ encode_flush(s);
+
+ if (ones_count) {
+ w->holding_zero = 1;
+ ones_count--;
+ } else
+ w->holding_zero = 0;
+ } else
+ w->holding_zero = 1;
+
+ w->holding_one = ones_count * 2;
+
+ if (high != low) {
+ uint32_t maxcode = high - low, code = sample - low;
+ int bitcount = count_bits(maxcode);
+ uint32_t extras = (1 << bitcount) - maxcode - 1;
+
+ if (code < extras) {
+ w->pend_data |= code << w->pend_count;
+ w->pend_count += bitcount - 1;
+ } else {
+ w->pend_data |= ((code + extras) >> 1) << w->pend_count;
+ w->pend_count += bitcount - 1;
+ w->pend_data |= ((code + extras) & 1) << w->pend_count++;
+ }
+ }
+
+ w->pend_data |= ((int32_t) sign << w->pend_count++);
+
+ if (!w->holding_zero)
+ encode_flush(s);
+}
+
+static void pack_int32(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ const int sent_bits = s->int32_sent_bits;
+ PutBitContext *pb = &s->pb;
+ int i, pre_shift;
+
+ pre_shift = s->int32_zeros + s->int32_ones + s->int32_dups;
+
+ if (!sent_bits)
+ return;
+
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++) {
+ put_sbits(pb, sent_bits, samples_l[i] >> pre_shift);
+ }
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ put_sbits(pb, sent_bits, samples_l[i] >> pre_shift);
+ put_sbits(pb, sent_bits, samples_r[i] >> pre_shift);
+ }
+ }
+}
+
+static void pack_float_sample(WavPackEncodeContext *s, int32_t *sample)
+{
+ const int max_exp = s->float_max_exp;
+ PutBitContext *pb = &s->pb;
+ int32_t value, shift_count;
+
+ if (get_exponent(*sample) == 255) {
+ if (get_mantissa(*sample)) {
+ put_bits(pb, 1, 1);
+ put_bits(pb, 23, get_mantissa(*sample));
+ } else {
+ put_bits(pb, 1, 0);
+ }
+
+ value = 0x1000000;
+ shift_count = 0;
+ } else if (get_exponent(*sample)) {
+ shift_count = max_exp - get_exponent(*sample);
+ value = 0x800000 + get_mantissa(*sample);
+ } else {
+ shift_count = max_exp ? max_exp - 1 : 0;
+ value = get_mantissa(*sample);
+ }
+
+ if (shift_count < 25)
+ value >>= shift_count;
+ else
+ value = 0;
+
+ if (!value) {
+ if (s->float_flags & FLOAT_ZEROS_SENT) {
+ if (get_exponent(*sample) || get_mantissa(*sample)) {
+ put_bits(pb, 1, 1);
+ put_bits(pb, 23, get_mantissa(*sample));
+
+ if (max_exp >= 25)
+ put_bits(pb, 8, get_exponent(*sample));
+
+ put_bits(pb, 1, get_sign(*sample));
+ } else {
+ put_bits(pb, 1, 0);
+
+ if (s->float_flags & FLOAT_NEG_ZEROS)
+ put_bits(pb, 1, get_sign(*sample));
+ }
+ }
+ } else if (shift_count) {
+ if (s->float_flags & FLOAT_SHIFT_SENT) {
+ int32_t data = get_mantissa(*sample) & ((1 << shift_count) - 1);
+ put_bits(pb, shift_count, data);
+ } else if (s->float_flags & FLOAT_SHIFT_SAME) {
+ put_bits(pb, 1, get_mantissa(*sample) & 1);
+ }
+ }
+}
+
+static void pack_float(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ int i;
+
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++)
+ pack_float_sample(s, &samples_l[i]);
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ pack_float_sample(s, &samples_l[i]);
+ pack_float_sample(s, &samples_r[i]);
+ }
+ }
+}
+
+static void decorr_stereo_pass2(struct Decorr *dpp,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ int i, m, k;
+
+ switch (dpp->value) {
+ case 17:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ dpp->samplesA[1] = dpp->samplesA[0];
+ samples_l[i] = tmp = (dpp->samplesA[0] = samples_l[i]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = 2 * dpp->samplesB[0] - dpp->samplesB[1];
+ dpp->samplesB[1] = dpp->samplesB[0];
+ samples_r[i] = tmp = (dpp->samplesB[0] = samples_r[i]) - APPLY_WEIGHT(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ case 18:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[0] + ((dpp->samplesA[0] - dpp->samplesA[1]) >> 1);
+ dpp->samplesA[1] = dpp->samplesA[0];
+ samples_l[i] = tmp = (dpp->samplesA[0] = samples_l[i]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[0] + ((dpp->samplesB[0] - dpp->samplesB[1]) >> 1);
+ dpp->samplesB[1] = dpp->samplesB[0];
+ samples_r[i] = tmp = (dpp->samplesB[0] = samples_r[i]) - APPLY_WEIGHT(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ default:
+ for (m = 0, k = dpp->value & (MAX_TERM - 1), i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[m];
+ samples_l[i] = tmp = (dpp->samplesA[k] = samples_l[i]) - APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[m];
+ samples_r[i] = tmp = (dpp->samplesB[k] = samples_r[i]) - APPLY_WEIGHT(dpp->weightB, sam);
+ UPDATE_WEIGHT(dpp->weightB, dpp->delta, sam, tmp);
+
+ m = (m + 1) & (MAX_TERM - 1);
+ k = (k + 1) & (MAX_TERM - 1);
+ }
+ if (m) {
+ int32_t temp_A[MAX_TERM], temp_B[MAX_TERM];
+
+ memcpy(temp_A, dpp->samplesA, sizeof (dpp->samplesA));
+ memcpy(temp_B, dpp->samplesB, sizeof (dpp->samplesB));
+
+ for (k = 0; k < MAX_TERM; k++) {
+ dpp->samplesA[k] = temp_A[m];
+ dpp->samplesB[k] = temp_B[m];
+ m = (m + 1) & (MAX_TERM - 1);
+ }
+ }
+ break;
+ case -1:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ samples_l[i] = tmp = (sam_B = samples_l[i]) - APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+
+ samples_r[i] = tmp = (dpp->samplesA[0] = samples_r[i]) - APPLY_WEIGHT(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+ }
+ break;
+ case -2:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_B = dpp->samplesB[0];
+ samples_r[i] = tmp = (sam_A = samples_r[i]) - APPLY_WEIGHT(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+
+ samples_l[i] = tmp = (dpp->samplesB[0] = samples_l[i]) - APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ }
+ break;
+ case -3:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ sam_B = dpp->samplesB[0];
+
+ dpp->samplesA[0] = tmp = samples_r[i];
+ samples_r[i] = tmp -= APPLY_WEIGHT(dpp->weightB, sam_B);
+ UPDATE_WEIGHT_CLIP(dpp->weightB, dpp->delta, sam_B, tmp);
+
+ dpp->samplesB[0] = tmp = samples_l[i];
+ samples_l[i] = tmp -= APPLY_WEIGHT(dpp->weightA, sam_A);
+ UPDATE_WEIGHT_CLIP(dpp->weightA, dpp->delta, sam_A, tmp);
+ }
+ break;
+ }
+}
+
+#define update_weight_d2(weight, delta, source, result) \
+ if (source && result) \
+ weight -= (((source ^ result) >> 29) & 4) - 2;
+
+#define update_weight_clip_d2(weight, delta, source, result) \
+ if (source && result) { \
+ const int32_t s = (source ^ result) >> 31; \
+ if ((weight = (weight ^ s) + (2 - s)) > 1024) weight = 1024; \
+ weight = (weight ^ s) - s; \
+ }
+
+static void decorr_stereo_pass_id2(struct Decorr *dpp,
+ int32_t *samples_l, int32_t *samples_r,
+ int nb_samples)
+{
+ int i, m, k;
+
+ switch (dpp->value) {
+ case 17:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ dpp->samplesA[1] = dpp->samplesA[0];
+ samples_l[i] = tmp = (dpp->samplesA[0] = samples_l[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ update_weight_d2(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = 2 * dpp->samplesB[0] - dpp->samplesB[1];
+ dpp->samplesB[1] = dpp->samplesB[0];
+ samples_r[i] = tmp = (dpp->samplesB[0] = samples_r[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ update_weight_d2(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ case 18:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[0] + ((dpp->samplesA[0] - dpp->samplesA[1]) >> 1);
+ dpp->samplesA[1] = dpp->samplesA[0];
+ samples_l[i] = tmp = (dpp->samplesA[0] = samples_l[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ update_weight_d2(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[0] + ((dpp->samplesB[0] - dpp->samplesB[1]) >> 1);
+ dpp->samplesB[1] = dpp->samplesB[0];
+ samples_r[i] = tmp = (dpp->samplesB[0] = samples_r[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ update_weight_d2(dpp->weightB, dpp->delta, sam, tmp);
+ }
+ break;
+ default:
+ for (m = 0, k = dpp->value & (MAX_TERM - 1), i = 0; i < nb_samples; i++) {
+ int32_t sam, tmp;
+
+ sam = dpp->samplesA[m];
+ samples_l[i] = tmp = (dpp->samplesA[k] = samples_l[i]) - APPLY_WEIGHT_I(dpp->weightA, sam);
+ update_weight_d2(dpp->weightA, dpp->delta, sam, tmp);
+
+ sam = dpp->samplesB[m];
+ samples_r[i] = tmp = (dpp->samplesB[k] = samples_r[i]) - APPLY_WEIGHT_I(dpp->weightB, sam);
+ update_weight_d2(dpp->weightB, dpp->delta, sam, tmp);
+
+ m = (m + 1) & (MAX_TERM - 1);
+ k = (k + 1) & (MAX_TERM - 1);
+ }
+
+ if (m) {
+ int32_t temp_A[MAX_TERM], temp_B[MAX_TERM];
+
+ memcpy(temp_A, dpp->samplesA, sizeof(dpp->samplesA));
+ memcpy(temp_B, dpp->samplesB, sizeof(dpp->samplesB));
+
+ for (k = 0; k < MAX_TERM; k++) {
+ dpp->samplesA[k] = temp_A[m];
+ dpp->samplesB[k] = temp_B[m];
+ m = (m + 1) & (MAX_TERM - 1);
+ }
+ }
+ break;
+ case -1:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ samples_l[i] = tmp = (sam_B = samples_l[i]) - APPLY_WEIGHT_I(dpp->weightA, sam_A);
+ update_weight_clip_d2(dpp->weightA, dpp->delta, sam_A, tmp);
+
+ samples_r[i] = tmp = (dpp->samplesA[0] = samples_r[i]) - APPLY_WEIGHT_I(dpp->weightB, sam_B);
+ update_weight_clip_d2(dpp->weightB, dpp->delta, sam_B, tmp);
+ }
+ break;
+ case -2:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_B = dpp->samplesB[0];
+ samples_r[i] = tmp = (sam_A = samples_r[i]) - APPLY_WEIGHT_I(dpp->weightB, sam_B);
+ update_weight_clip_d2(dpp->weightB, dpp->delta, sam_B, tmp);
+
+ samples_l[i] = tmp = (dpp->samplesB[0] = samples_l[i]) - APPLY_WEIGHT_I(dpp->weightA, sam_A);
+ update_weight_clip_d2(dpp->weightA, dpp->delta, sam_A, tmp);
+ }
+ break;
+ case -3:
+ for (i = 0; i < nb_samples; i++) {
+ int32_t sam_A, sam_B, tmp;
+
+ sam_A = dpp->samplesA[0];
+ sam_B = dpp->samplesB[0];
+
+ dpp->samplesA[0] = tmp = samples_r[i];
+ samples_r[i] = tmp -= APPLY_WEIGHT_I(dpp->weightB, sam_B);
+ update_weight_clip_d2(dpp->weightB, dpp->delta, sam_B, tmp);
+
+ dpp->samplesB[0] = tmp = samples_l[i];
+ samples_l[i] = tmp -= APPLY_WEIGHT_I(dpp->weightA, sam_A);
+ update_weight_clip_d2(dpp->weightA, dpp->delta, sam_A, tmp);
+ }
+ break;
+ }
+}
+
+static void put_metadata_block(PutByteContext *pb, int flags, int size)
+{
+ if (size & 1)
+ flags |= WP_IDF_ODD;
+
+ bytestream2_put_byte(pb, flags);
+ bytestream2_put_byte(pb, (size + 1) >> 1);
+}
+
+static int wavpack_encode_block(WavPackEncodeContext *s,
+ int32_t *samples_l, int32_t *samples_r,
+ uint8_t *out, int out_size)
+{
+ int block_size, start, end, data_size, tcount, temp, m = 0;
+ int i, j, ret = 0, got_extra = 0, nb_samples = s->block_samples;
+ uint32_t crc = 0xffffffffu;
+ struct Decorr *dpp;
+ PutByteContext pb;
+
+ if (s->flags & WV_MONO_DATA) {
+ CLEAR(s->w);
+ }
+ if (!(s->flags & WV_MONO) && s->optimize_mono) {
+ int32_t lor = 0, diff = 0;
+
+ for (i = 0; i < nb_samples; i++) {
+ lor |= samples_l[i] | samples_r[i];
+ diff |= samples_l[i] - samples_r[i];
+
+ if (lor && diff)
+ break;
+ }
+
+ if (i == nb_samples && lor && !diff) {
+ s->flags &= ~(WV_JOINT_STEREO | WV_CROSS_DECORR);
+ s->flags |= WV_FALSE_STEREO;
+
+ if (!s->false_stereo) {
+ s->false_stereo = 1;
+ s->num_terms = 0;
+ CLEAR(s->w);
+ }
+ } else if (s->false_stereo) {
+ s->false_stereo = 0;
+ s->num_terms = 0;
+ CLEAR(s->w);
+ }
+ }
+
+ if (s->flags & SHIFT_MASK) {
+ int shift = (s->flags & SHIFT_MASK) >> SHIFT_LSB;
+ int mag = (s->flags & MAG_MASK) >> MAG_LSB;
+
+ if (s->flags & WV_MONO_DATA)
+ shift_mono(samples_l, nb_samples, shift);
+ else
+ shift_stereo(samples_l, samples_r, nb_samples, shift);
+
+ if ((mag -= shift) < 0)
+ s->flags &= ~MAG_MASK;
+ else
+ s->flags -= (1 << MAG_LSB) * shift;
+ }
+
+ if ((s->flags & WV_FLOAT_DATA) || (s->flags & MAG_MASK) >> MAG_LSB >= 24) {
+ av_fast_padded_malloc(&s->orig_l, &s->orig_l_size, sizeof(int32_t) * nb_samples);
+ memcpy(s->orig_l, samples_l, sizeof(int32_t) * nb_samples);
+ if (!(s->flags & WV_MONO_DATA)) {
+ av_fast_padded_malloc(&s->orig_r, &s->orig_r_size, sizeof(int32_t) * nb_samples);
+ memcpy(s->orig_r, samples_r, sizeof(int32_t) * nb_samples);
+ }
+
+ if (s->flags & WV_FLOAT_DATA)
+ got_extra = scan_float(s, samples_l, samples_r, nb_samples);
+ else
+ got_extra = scan_int32(s, samples_l, samples_r, nb_samples);
+ s->num_terms = 0;
+ } else {
+ scan_int23(s, samples_l, samples_r, nb_samples);
+ if (s->shift != s->int32_zeros + s->int32_ones + s->int32_dups) {
+ s->shift = s->int32_zeros + s->int32_ones + s->int32_dups;
+ s->num_terms = 0;
+ }
+ }
+
+ if (!s->num_passes && !s->num_terms) {
+ s->num_passes = 1;
+
+ if (s->flags & WV_MONO_DATA)
+ ret = wv_mono(s, samples_l, 1, 0);
+ else
+ ret = wv_stereo(s, samples_l, samples_r, 1, 0);
+
+ s->num_passes = 0;
+ }
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++)
+ crc += (crc << 1) + samples_l[i];
+
+ if (s->num_passes)
+ ret = wv_mono(s, samples_l, !s->num_terms, 1);
+ } else {
+ for (i = 0; i < nb_samples; i++)
+ crc += (crc << 3) + (samples_l[i] << 1) + samples_l[i] + samples_r[i];
+
+ if (s->num_passes)
+ ret = wv_stereo(s, samples_l, samples_r, !s->num_terms, 1);
+ }
+ if (ret < 0)
+ return ret;
+
+ if (!s->ch_offset)
+ s->flags |= WV_INITIAL_BLOCK;
+
+ s->ch_offset += 1 + !(s->flags & WV_MONO);
+
+ if (s->ch_offset == s->avctx->channels)
+ s->flags |= WV_FINAL_BLOCK;
+
+ bytestream2_init_writer(&pb, out, out_size);
+ bytestream2_put_le32(&pb, MKTAG('w', 'v', 'p', 'k'));
+ bytestream2_put_le32(&pb, 0);
+ bytestream2_put_le16(&pb, 0x410);
+ bytestream2_put_le16(&pb, 0);
+ bytestream2_put_le32(&pb, 0);
+ bytestream2_put_le32(&pb, s->sample_index);
+ bytestream2_put_le32(&pb, nb_samples);
+ bytestream2_put_le32(&pb, s->flags);
+ bytestream2_put_le32(&pb, crc);
+
+ if (s->flags & WV_INITIAL_BLOCK &&
+ s->avctx->channel_layout != AV_CH_LAYOUT_MONO &&
+ s->avctx->channel_layout != AV_CH_LAYOUT_STEREO) {
+ put_metadata_block(&pb, WP_ID_CHANINFO, 5);
+ bytestream2_put_byte(&pb, s->avctx->channels);
+ bytestream2_put_le32(&pb, s->avctx->channel_layout);
+ bytestream2_put_byte(&pb, 0);
+ }
+
+ if ((s->flags & SRATE_MASK) == SRATE_MASK) {
+ put_metadata_block(&pb, WP_ID_SAMPLE_RATE, 3);
+ bytestream2_put_le24(&pb, s->avctx->sample_rate);
+ bytestream2_put_byte(&pb, 0);
+ }
+
+ put_metadata_block(&pb, WP_ID_DECTERMS, s->num_terms);
+ for (i = 0; i < s->num_terms; i++) {
+ struct Decorr *dpp = &s->decorr_passes[i];
+ bytestream2_put_byte(&pb, ((dpp->value + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0));
+ }
+ if (s->num_terms & 1)
+ bytestream2_put_byte(&pb, 0);
+
+#define WRITE_DECWEIGHT(type) do { \
+ temp = store_weight(type); \
+ bytestream2_put_byte(&pb, temp); \
+ type = restore_weight(temp); \
+ } while (0)
+
+ bytestream2_put_byte(&pb, WP_ID_DECWEIGHTS);
+ bytestream2_put_byte(&pb, 0);
+ start = bytestream2_tell_p(&pb);
+ for (i = s->num_terms - 1; i >= 0; --i) {
+ struct Decorr *dpp = &s->decorr_passes[i];
+
+ if (store_weight(dpp->weightA) ||
+ (!(s->flags & WV_MONO_DATA) && store_weight(dpp->weightB)))
+ break;
+ }
+ tcount = i + 1;
+ for (i = 0; i < s->num_terms; i++) {
+ struct Decorr *dpp = &s->decorr_passes[i];
+ if (i < tcount) {
+ WRITE_DECWEIGHT(dpp->weightA);
+ if (!(s->flags & WV_MONO_DATA))
+ WRITE_DECWEIGHT(dpp->weightB);
+ } else {
+ dpp->weightA = dpp->weightB = 0;
+ }
+ }
+ end = bytestream2_tell_p(&pb);
+ out[start - 2] = WP_ID_DECWEIGHTS | (((end - start) & 1) ? WP_IDF_ODD: 0);
+ out[start - 1] = (end - start + 1) >> 1;
+ if ((end - start) & 1)
+ bytestream2_put_byte(&pb, 0);
+
+#define WRITE_DECSAMPLE(type) do { \
+ temp = log2s(type); \
+ type = wp_exp2(temp); \
+ bytestream2_put_le16(&pb, temp); \
+ } while (0)
+
+ bytestream2_put_byte(&pb, WP_ID_DECSAMPLES);
+ bytestream2_put_byte(&pb, 0);
+ start = bytestream2_tell_p(&pb);
+ for (i = 0; i < s->num_terms; i++) {
+ struct Decorr *dpp = &s->decorr_passes[i];
+ if (i == 0) {
+ if (dpp->value > MAX_TERM) {
+ WRITE_DECSAMPLE(dpp->samplesA[0]);
+ WRITE_DECSAMPLE(dpp->samplesA[1]);
+ if (!(s->flags & WV_MONO_DATA)) {
+ WRITE_DECSAMPLE(dpp->samplesB[0]);
+ WRITE_DECSAMPLE(dpp->samplesB[1]);
+ }
+ } else if (dpp->value < 0) {
+ WRITE_DECSAMPLE(dpp->samplesA[0]);
+ WRITE_DECSAMPLE(dpp->samplesB[0]);
+ } else {
+ for (j = 0; j < dpp->value; j++) {
+ WRITE_DECSAMPLE(dpp->samplesA[j]);
+ if (!(s->flags & WV_MONO_DATA))
+ WRITE_DECSAMPLE(dpp->samplesB[j]);
+ }
+ }
+ } else {
+ CLEAR(dpp->samplesA);
+ CLEAR(dpp->samplesB);
+ }
+ }
+ end = bytestream2_tell_p(&pb);
+ out[start - 1] = (end - start) >> 1;
+
+#define WRITE_CHAN_ENTROPY(chan) do { \
+ for (i = 0; i < 3; i++) { \
+ temp = wp_log2(s->w.c[chan].median[i]); \
+ bytestream2_put_le16(&pb, temp); \
+ s->w.c[chan].median[i] = wp_exp2(temp); \
+ } \
+ } while (0)
+
+ put_metadata_block(&pb, WP_ID_ENTROPY, 6 * (1 + (!(s->flags & WV_MONO_DATA))));
+ WRITE_CHAN_ENTROPY(0);
+ if (!(s->flags & WV_MONO_DATA))
+ WRITE_CHAN_ENTROPY(1);
+
+ if (s->flags & WV_FLOAT_DATA) {
+ put_metadata_block(&pb, WP_ID_FLOATINFO, 4);
+ bytestream2_put_byte(&pb, s->float_flags);
+ bytestream2_put_byte(&pb, s->float_shift);
+ bytestream2_put_byte(&pb, s->float_max_exp);
+ bytestream2_put_byte(&pb, 127);
+ }
+
+ if (s->flags & WV_INT32_DATA) {
+ put_metadata_block(&pb, WP_ID_INT32INFO, 4);
+ bytestream2_put_byte(&pb, s->int32_sent_bits);
+ bytestream2_put_byte(&pb, s->int32_zeros);
+ bytestream2_put_byte(&pb, s->int32_ones);
+ bytestream2_put_byte(&pb, s->int32_dups);
+ }
+
+ if (s->flags & WV_MONO_DATA && !s->num_passes) {
+ for (i = 0; i < nb_samples; i++) {
+ int32_t code = samples_l[i];
+
+ for (tcount = s->num_terms, dpp = s->decorr_passes; tcount--; dpp++) {
+ int32_t sam;
+
+ if (dpp->value > MAX_TERM) {
+ if (dpp->value & 1)
+ sam = 2 * dpp->samplesA[0] - dpp->samplesA[1];
+ else
+ sam = (3 * dpp->samplesA[0] - dpp->samplesA[1]) >> 1;
+
+ dpp->samplesA[1] = dpp->samplesA[0];
+ dpp->samplesA[0] = code;
+ } else {
+ sam = dpp->samplesA[m];
+ dpp->samplesA[(m + dpp->value) & (MAX_TERM - 1)] = code;
+ }
+
+ code -= APPLY_WEIGHT(dpp->weightA, sam);
+ UPDATE_WEIGHT(dpp->weightA, dpp->delta, sam, code);
+ }
+
+ m = (m + 1) & (MAX_TERM - 1);
+ samples_l[i] = code;
+ }
+ if (m) {
+ for (tcount = s->num_terms, dpp = s->decorr_passes; tcount--; dpp++)
+ if (dpp->value > 0 && dpp->value <= MAX_TERM) {
+ int32_t temp_A[MAX_TERM], temp_B[MAX_TERM];
+ int k;
+
+ memcpy(temp_A, dpp->samplesA, sizeof(dpp->samplesA));
+ memcpy(temp_B, dpp->samplesB, sizeof(dpp->samplesB));
+
+ for (k = 0; k < MAX_TERM; k++) {
+ dpp->samplesA[k] = temp_A[m];
+ dpp->samplesB[k] = temp_B[m];
+ m = (m + 1) & (MAX_TERM - 1);
+ }
+ }
+ }
+ } else if (!s->num_passes) {
+ if (s->flags & WV_JOINT_STEREO) {
+ for (i = 0; i < nb_samples; i++)
+ samples_r[i] += ((samples_l[i] -= samples_r[i]) >> 1);
+ }
+
+ for (i = 0; i < s->num_terms; i++) {
+ struct Decorr *dpp = &s->decorr_passes[i];
+ if (((s->flags & MAG_MASK) >> MAG_LSB) >= 16 || dpp->delta != 2)
+ decorr_stereo_pass2(dpp, samples_l, samples_r, nb_samples);
+ else
+ decorr_stereo_pass_id2(dpp, samples_l, samples_r, nb_samples);
+ }
+ }
+
+ bytestream2_put_byte(&pb, WP_ID_DATA | WP_IDF_LONG);
+ init_put_bits(&s->pb, pb.buffer + 3, bytestream2_get_bytes_left_p(&pb));
+ if (s->flags & WV_MONO_DATA) {
+ for (i = 0; i < nb_samples; i++)
+ wavpack_encode_sample(s, &s->w.c[0], s->samples[0][i]);
+ } else {
+ for (i = 0; i < nb_samples; i++) {
+ wavpack_encode_sample(s, &s->w.c[0], s->samples[0][i]);
+ wavpack_encode_sample(s, &s->w.c[1], s->samples[1][i]);
+ }
+ }
+ encode_flush(s);
+ flush_put_bits(&s->pb);
+ data_size = put_bits_count(&s->pb) >> 3;
+ bytestream2_put_le24(&pb, (data_size + 1) >> 1);
+ bytestream2_skip_p(&pb, data_size);
+ if (data_size & 1)
+ bytestream2_put_byte(&pb, 0);
+
+ if (got_extra) {
+ bytestream2_put_byte(&pb, WP_ID_EXTRABITS | WP_IDF_LONG);
+ init_put_bits(&s->pb, pb.buffer + 7, bytestream2_get_bytes_left_p(&pb));
+ if (s->flags & WV_FLOAT_DATA)
+ pack_float(s, s->orig_l, s->orig_r, nb_samples);
+ else
+ pack_int32(s, s->orig_l, s->orig_r, nb_samples);
+ flush_put_bits(&s->pb);
+ data_size = put_bits_count(&s->pb) >> 3;
+ bytestream2_put_le24(&pb, (data_size + 5) >> 1);
+ bytestream2_put_le32(&pb, s->crc_x);
+ bytestream2_skip_p(&pb, data_size);
+ if (data_size & 1)
+ bytestream2_put_byte(&pb, 0);
+ }
+
+ block_size = bytestream2_tell_p(&pb);
+ AV_WL32(out + 4, block_size - 8);
+
+ av_assert0(!bytestream2_get_eof(&pb));
+
+ return block_size;
+}
+
+static void fill_buffer(WavPackEncodeContext *s,
+ const int8_t *src, int32_t *dst,
+ int nb_samples)
+{
+ int i;
+
+#define COPY_SAMPLES(type, offset, shift) do { \
+ const type *sptr = (const type *)src; \
+ for (i = 0; i < nb_samples; i++) \
+ dst[i] = (sptr[i] - offset) >> shift; \
+ } while (0)
+
+ switch (s->avctx->sample_fmt) {
+ case AV_SAMPLE_FMT_U8P:
+ COPY_SAMPLES(int8_t, 0x80, 0);
+ break;
+ case AV_SAMPLE_FMT_S16P:
+ COPY_SAMPLES(int16_t, 0, 0);
+ break;
+ case AV_SAMPLE_FMT_S32P:
+ if (s->avctx->bits_per_raw_sample <= 24) {
+ COPY_SAMPLES(int32_t, 0, 8);
+ break;
+ }
+ case AV_SAMPLE_FMT_FLTP:
+ memcpy(dst, src, nb_samples * 4);
+ }
+}
+
+static void set_samplerate(WavPackEncodeContext *s)
+{
+ int i;
+
+ for (i = 0; i < 15; i++) {
+ if (wv_rates[i] == s->avctx->sample_rate)
+ break;
+ }
+
+ s->flags = i << SRATE_LSB;
+}
+
+static int wavpack_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
+ const AVFrame *frame, int *got_packet_ptr)
+{
+ WavPackEncodeContext *s = avctx->priv_data;
+ int buf_size, ret;
+ uint8_t *buf;
+
+ s->block_samples = frame->nb_samples;
+ av_fast_padded_malloc(&s->samples[0], &s->samples_size[0],
+ sizeof(int32_t) * s->block_samples);
+ if (!s->samples[0])
+ return AVERROR(ENOMEM);
+ if (avctx->channels > 1) {
+ av_fast_padded_malloc(&s->samples[1], &s->samples_size[1],
+ sizeof(int32_t) * s->block_samples);
+ if (!s->samples[1])
+ return AVERROR(ENOMEM);
+ }
+
+ buf_size = s->block_samples * avctx->channels * 8
+ + 200 /* for headers */;
+ if ((ret = ff_alloc_packet2(avctx, avpkt, buf_size)) < 0)
+ return ret;
+ buf = avpkt->data;
+
+ for (s->ch_offset = 0; s->ch_offset < avctx->channels;) {
+ set_samplerate(s);
+
+ switch (s->avctx->sample_fmt) {
+ case AV_SAMPLE_FMT_S16P: s->flags |= 1; break;
+ case AV_SAMPLE_FMT_S32P: s->flags |= 3 - (s->avctx->bits_per_raw_sample <= 24); break;
+ case AV_SAMPLE_FMT_FLTP: s->flags |= 3 | WV_FLOAT_DATA;
+ }
+
+ fill_buffer(s, frame->extended_data[s->ch_offset], s->samples[0], s->block_samples);
+ if (avctx->channels - s->ch_offset == 1) {
+ s->flags |= WV_MONO;
+ } else {
+ s->flags |= WV_CROSS_DECORR;
+ fill_buffer(s, frame->extended_data[s->ch_offset + 1], s->samples[1], s->block_samples);
+ }
+
+ s->flags += (1 << MAG_LSB) * ((s->flags & 3) * 8 + 7);
+
+ if ((ret = wavpack_encode_block(s, s->samples[0], s->samples[1],
+ buf, buf_size)) < 0)
+ return ret;
+
+ buf += ret;
+ buf_size -= ret;
+ }
+ s->sample_index += frame->nb_samples;
+
+ avpkt->pts = frame->pts;
+ avpkt->size = buf - avpkt->data;
+ avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples);
+ *got_packet_ptr = 1;
+ return 0;
+}
+
+static av_cold int wavpack_encode_close(AVCodecContext *avctx)
+{
+ WavPackEncodeContext *s = avctx->priv_data;
+ int i;
+
+ for (i = 0; i < MAX_TERMS + 2; i++) {
+ av_freep(&s->sampleptrs[i][0]);
+ av_freep(&s->sampleptrs[i][1]);
+ s->sampleptrs_size[i][0] = s->sampleptrs_size[i][1] = 0;
+ }
+
+ for (i = 0; i < 2; i++) {
+ av_freep(&s->samples[i]);
+ s->samples_size[i] = 0;
+
+ av_freep(&s->best_buffer[i]);
+ s->best_buffer_size[i] = 0;
+
+ av_freep(&s->temp_buffer[i][0]);
+ av_freep(&s->temp_buffer[i][1]);
+ s->temp_buffer_size[i][0] = s->temp_buffer_size[i][1] = 0;
+ }
+
+ av_freep(&s->js_left);
+ av_freep(&s->js_right);
+ s->js_left_size = s->js_right_size = 0;
+
+ av_freep(&s->orig_l);
+ av_freep(&s->orig_r);
+ s->orig_l_size = s->orig_r_size = 0;
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(WavPackEncodeContext, x)
+#define FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption options[] = {
+ { "joint_stereo", "", OFFSET(joint), AV_OPT_TYPE_INT, {.i64=0},-1, 1, FLAGS, "joint" },
+ { "on", "mid/side", 0, AV_OPT_TYPE_CONST, {.i64= 1}, 0, 0, FLAGS, "joint"},
+ { "off", "left/right", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "joint"},
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64= 0}, 0, 0, FLAGS, "joint"},
+ { "optimize_mono", "", OFFSET(optimize_mono), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "opt_mono" },
+ { "on", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "opt_mono"},
+ { "off", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "opt_mono"},
+ { NULL },
+};
+
+static const AVClass wavpack_encoder_class = {
+ .class_name = "WavPack encoder",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_wavpack_encoder = {
+ .name = "wavpack",
+ .long_name = NULL_IF_CONFIG_SMALL("WavPack"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_WAVPACK,
+ .priv_data_size = sizeof(WavPackEncodeContext),
+ .priv_class = &wavpack_encoder_class,
+ .init = wavpack_encode_init,
+ .encode2 = wavpack_encode_frame,
+ .close = wavpack_encode_close,
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME,
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_U8P,
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_NONE },
+};
diff --git a/libavcodec/wavpackenc.h b/libavcodec/wavpackenc.h
new file mode 100644
index 0000000000..9dd2a01bbe
--- /dev/null
+++ b/libavcodec/wavpackenc.h
@@ -0,0 +1,664 @@
+/*
+ * WavPack lossless audio encoder
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_WAVPACKENC_H
+#define AVCODEC_WAVPACKENC_H
+
+#include "wavpack.h"
+
+typedef struct WavPackDecorrSpec {
+ int8_t joint_stereo, delta, terms[MAX_TERMS+1];
+} WavPackDecorrSpec;
+
+static const WavPackDecorrSpec fast_specs[] = {
+ { 1, 2, { 18,17 } }, { 1, 1, { 17,17 } }, { 0, 2, { 18,17 } },
+ { 0, 1, { 17,17 } }, { 1, 3, { 1,18 } }, { 1, 1, { 17, 1 } },
+ { 0, 1, { 1,17 } }, { 0, 1, { -2,17 } }, { 0, 2, { -1,17 } },
+ { 1, 1, { 17, 2 } }, { 0, 3, { 18,18 } }, { 0, 1, { 17, 1 } },
+ { 1, 6, { 1, 2 } }, { 1, 1, { 17, 3 } }, { 0, 1, { -2, 3 } },
+ { 0, 1, { 2,17 } }, { 0, 1, { 18,-2 } }, { 0, 1, { -1,17 } },
+ { 0, 1, { 18,17 } }, { 0, 1, { 17, 2 } }, { 1, 2, { 18,-2 } },
+ { 1, 1, { 1,17 } }, { 0, 3, { 18, 2 } }, { 0, 1, { 17,-2 } },
+ { 0, 1, { 18,-2 } }, { 1, 2, { 17,-3 } }, { 0, 1, { 18, 3 } },
+ { 0, 1, { 18,18 } }, { 1, 1, { 1, 3 } }, { 1, 1, { 18, 3 } },
+ { 1, 1, { 1, 3 } }, { 0, 2, { 18,17 } }, { 1, 1, { 1,17 } },
+ { 1, 1, { 17, 3 } }, { 0, 3, { 18,17 } }, { 0, 1, { 18,18 } },
+ { 1, 1, { 1, 3 } }, { 1, 1, { 1,18 } }, { 0, 1, { 18,-2 } },
+ { 0, 2, { 18,17 } }, { 0, 1, { -1,18 } }, { 1, 1, { 17, 3 } },
+ { 0, 1, { 17, 2 } }, { 0, 1, { 17, 3 } }, { 1, 1, { 18, 2 } },
+ { 1, 1, { 17,-2 } }, { 0, 1, { 1,-2 } }, { 0, 2, { 18,17 } },
+ { 0, 1, { 17,-2 } }, { 1, 1, { 17,-2 } }, { 0, 1, { 18, 3 } },
+ { 0, 1, { 2,17 } }, { 1, 2, { 18,-3 } }, { 1, 2, { 1,18 } },
+ { 1, 2, { 18, 2 } }, { 0, 1, { 17,-1 } }, { 0, 1, { 17,-2 } },
+ { 1, 1, { 17,-2 } }, { 1, 1, { 1, 3 } }, { 0, 1, { 1,17 } },
+ { 1, 2, { 18,-2 } }, { 1, 2, { 17,-3 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 1, 1, { 17, 2 } }, { 1, 2, { 18,18 } },
+ { 0, 1, { 17, 2 } }, { 0, 1, { 18,17 } }, { 1, 1, { 1,17 } },
+ { 1, 1, { 17, 2 } }, { 0, 2, { 18,18 } }, { 0, 2, { 18,17 } },
+ { 1, 2, { 17,-3 } }, { 1, 6, { 1, 2 } }, { 0, 3, { 17,17 } },
+ { 0, 1, { 1,18 } }, { 0, 1, { 1,-2 } }, { 1, 1, { 17, 2 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 1, 1, { 18, 3 } },
+ { 1, 2, { 17,-3 } }, { 0, 1, { 17, 2 } }, { 0, 1, { 17, 3 } },
+ { 0, 1, { 18,-2 } }, { 1, 1, { 18,18 } }, { 1, 6, { 1, 2 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 1, { -1,17 } },
+ { 1, 1, { 18, 3 } }, { 0, 1, { 17,18 } }, { 1, 1, { 17, 3 } },
+ { 0, 1, { 18, 3 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 2, { 18, 2 } }, { 0, 1, { -2, 3 } }, { 0, 4, { 18,-1 } },
+ { 0, 2, { 18,18 } }, { 0, 1, { -2, 3 } }, { 1, 1, { 17,-2 } },
+ { 0, 1, { 17, 3 } }, { 0, 2, { 18,17 } }, { 0, 2, { -1,18 } },
+ { 1, 1, { 2,17 } }, { 0, 2, { 17,-2 } }, { 0, 1, { 17, 2 } },
+ { 1, 2, { 18,-3 } }, { 0, 1, { 17,-2 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 1, 1, { 17,-2 } }, { 1, 2, { 17,-3 } },
+ { 1, 1, { 1, 3 } }, { 1, 1, { 2,17 } }, { 1, 2, { 18, 2 } },
+ { 1, 1, { 2,17 } }, { 1, 1, { 18, 2 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 1, { 17,-2 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 17,-1 } }, { 0, 2, { 18,-2 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 1, 1, { 1, 3 } },
+ { 0, 2, { -2,17 } }, { 0, 2, { 18,-2 } }, { 0, 2, { 17,-2 } },
+ { 1, 1, { 2,17 } }, { 1, 1, { 1, 3 } }, { 0, 1, { 2,17 } },
+ { 0, 2, { 18,17 } }, { 0, 3, { -1,17 } }, { 1, 1, { 2,17 } },
+ { 0, 2, { 18,18 } }, { 0, 1, { 17, 2 } }, { 1, 4, { 18,-3 } },
+ { 1, 1, { 18, 1 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 2, { 18,-1 } }, { 0, 1, { -1,18 } }, { 1, 6, { 1, 2 } },
+ { 1, 1, { 17, 2 } }, { 1, 4, { 18, 3 } }, { 0, 1, { 1,17 } },
+ { 0, 1, { 18, 2 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 2, { 17, 2 } }, { 0, 2, { 18,-2 } }, { 0, 1, { 1,18 } },
+ { 1, 2, { 18,-3 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 1, 2, { 18,18 } }, { 1, 3, { 17,17 } },
+ { 0, 1, { -2,17 } }, { 0, 1, { 17,18 } }, { 0, 1, { -1, 3 } },
+ { 1, 1, { 2,17 } }, { 0, 2, { 18,-1 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 1, 1, { 17,-2 } }, { 1, 2, { 17, 2 } },
+ { 1, 1, { 18, 3 } }, { 0, 1, { 18, 2 } }, { 1, 2, { 17,-3 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 1, { -2,17 } },
+ { 0, 1, { 17,-1 } }, { 0, 1, { 18,-1 } }, { 0, 2, { 18,17 } },
+ { 1, 2, { 17,-3 } }, { 1, 1, { 1,18 } }, { 1, 3, { 18, 2 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 3, { 18,18 } }, { 0, 1, { 1,-2 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 2, { 17,-3 } }, { 1, 1, { 18,18 } }, { 0, 2, { 18, 2 } },
+ { 0, 1, { 17,18 } }, { 1, 2, { 18, 2 } }, { 1, 1, { 17,-2 } },
+ { 0, 2, { 17,-1 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 1, { 1,-2 } }, { 0, 1, { 18, 1 } },
+ { 1, 2, { 18,-2 } }, { 0, 1, { 17, 2 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 1, 1, { 17, 3 } }, { 0, 1, { 17,-1 } },
+ { 0, 1, { 18, 2 } }, { 1, 1, { 17, 3 } }, { 1, 1, { 17,-2 } },
+ { 0, 1, { 18,18 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 1, { 17,18 } }, { 0, 1, { -2, 3 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 1, 2, { 18,-3 } },
+ { 0, 2, { 18,17 } }, { 0, 3, { 18, 2 } }, { 0, 1, { 1,18 } },
+ { 0, 2, { 18,17 } }, { 0, 1, { 17,-1 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 1, { -2, 3 } },
+ { 0, 3, { 17,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 1, { 17, 2 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 1, 1, { 17, 2 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18, 2 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } }, { 0, 2, { 18,17 } },
+ { 0, 2, { 18,17 } },
+};
+
+static const WavPackDecorrSpec default_specs[] = {
+ { 1, 2, { 18,18, 2,17, 3 } }, { 0, 2, { 18,17,-1, 3, 2 } },
+ { 1, 1, { 17,18,18,-2, 2 } }, { 0, 2, { 18,17, 3,-2,17 } },
+ { 1, 2, { 18,17, 2,17, 3 } }, { 0, 1, { 18,18,-1, 2,17 } },
+ { 0, 1, { 17,17,-2, 2, 3 } }, { 0, 1, { 18,-2,18, 2,17 } },
+ { 1, 2, { 18,18,-1, 2, 3 } }, { 0, 2, { 18,17, 3, 2, 5 } },
+ { 1, 1, { 18,17,18, 2, 5 } }, { 0, 1, { 17,17,-2, 2, 3 } },
+ { 0, 1, { 18,-2,18, 2, 5 } }, { 0, 1, { 17,-2,17, 2,-3 } },
+ { 1, 1, { 17,-2,17, 1, 2 } }, { 0, 1, { 17,17,-2, 2, 3 } },
+ { 1, 1, { 18, 3, 1, 5, 4 } }, { 1, 4, { 18,18, 2, 3,-2 } },
+ { 0, 1, { 1,-1,-1, 2,17 } }, { 0, 2, { 18,17, 3, 2, 5 } },
+ { 0, 1, { 18,18,18, 2,17 } }, { 0, 1, { 18,17,-1, 2,18 } },
+ { 1, 1, { 17, 3, 2, 1, 7 } }, { 0, 2, { 18,-2,18, 2, 3 } },
+ { 1, 3, { 18,-3,18, 2, 3 } }, { 0, 3, { 18,17, 2, 3,17 } },
+ { 1, 1, { 17,17, 2, 1, 4 } }, { 0, 1, { 17,18,-2, 2,17 } },
+ { 1, 1, { 18,18, 3, 5, 2 } }, { 0, 1, { 17,17, 2,18, 4 } },
+ { 0, 1, { 18,17, 1, 4, 6 } }, { 1, 1, { 3,17,18, 2,17 } },
+ { 1, 1, { 17, 3, 2, 1, 7 } }, { 0, 1, { 18,17,-1, 2, 3 } },
+ { 1, 1, { 17,17, 2, 1, 4 } }, { 1, 2, { 18,17,-1,17, 3 } },
+ { 1, 2, { 18,17, 2, 3,-1 } }, { 0, 2, { 18,18,-2, 2,17 } },
+ { 0, 1, { 17,17, 2,18, 4 } }, { 0, 5, { -2,18,18,18, 2 } },
+ { 1, 1, { 18,18,-1, 6, 3 } }, { 0, 1, { 17,17,-2, 2, 3 } },
+ { 1, 1, { 18,17,18, 2,17 } }, { 0, 1, { 18,17, 4, 3, 1 } },
+ { 0, 1, { -2,18, 2, 2,18 } }, { 1, 2, { 18,18,-2, 2,-1 } },
+ { 1, 1, { 17,17, 2, 1, 4 } }, { 0, 1, { 17,18,-2, 2,17 } },
+ { 1, 1, { 17, 3, 2, 1, 7 } }, { 1, 3, { 18,-3,18, 2, 3 } },
+ { 1, 2, { 18,18,-2, 2,-1 } }, { 1, 1, { 18,18, 3, 5, 2 } },
+ { 0, 2, { 18,18,-1, 2,17 } }, { 0, 1, { 18,-1,17,18, 2 } },
+ { 0, 1, { 17,-1, 2, 3, 6 } }, { 0, 1, { 18,-2,18, 2, 5 } },
+ { 1, 2, { 18,18,-2, 2,-1 } }, { 0, 3, { 18,18, 2, 3,17 } },
+ { 0, 1, { 17,17, 2,18, 4 } }, { 1, 1, { 17,-2,17, 1, 2 } },
+ { 0, 1, { -1, 3, 5, 4, 7 } }, { 0, 3, { 18,18, 3, 2, 5 } },
+ { 0, 1, { 17,17, 2,18, 4 } }, { 0, 1, { 18,17,-2,18, 3 } },
+ { 0, 2, { 18,18,-2, 2,17 } }, { 0, 3, { 18,17,-2, 2, 3 } },
+ { 1, 1, { 18,18,-2, 2,17 } }, { 0, 1, { 18,17, 4, 3, 1 } },
+ { 1, 2, { 3,18,17, 2,17 } }, { 1, 2, { 18,18, 2,-2,18 } },
+ { 1, 2, { 18,18,-1,18, 2 } }, { 0, 2, { 18,18,-2, 2,17 } },
+ { 1, 3, { 18,18, 2, 3,-2 } }, { 0, 3, { 18,18, 3, 2, 5 } },
+ { 0, 1, { 18,-2,18, 2, 5 } }, { 1, 1, { 17, 3, 2, 1, 7 } },
+ { 1, 3, { 18,18,-2, 2,18 } }, { 1, 1, { 17,18,18,-2, 2 } },
+ { 0, 1, { 18,-2,18, 2, 5 } }, { 0, 2, { 18,-2,18, 2, 3 } },
+ { 0, 1, { -1, 3, 4, 5, 7 } }, { 1, 1, { 17,17, 2,-1, 7 } },
+ { 0, 1, { 18,-1,-1, 2,-2 } }, { 0, 2, { 18,17, 2, 3,17 } },
+ { 0, 1, { 18,17, 2,18, 2 } }, { 0, 2, { 18,17,-1, 2,17 } },
+ { 0, 1, { 1,18, 3, 2, 5 } }, { 0, 2, { 18,-2, 4,18, 2 } },
+ { 1, 1, { 18, 3, 1, 5, 4 } }, { 0, 1, { 18,17,18, 2, 5 } },
+ { 1, 1, { 18, 3, 1, 5, 4 } }, { 0, 4, { 18,18,-2, 2,18 } },
+ { 1, 1, { 18,18, 3, 2, 5 } }, { 1, 1, { 17,17, 2, 1, 4 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 1, { 18,18, 2, 1, 3 } }, { 1, 1, { 17,17, 2, 1, 4 } },
+ { 1, 2, { 17,17, 2,18, 3 } }, { 0, 1, { 18,17, 1, 4, 6 } },
+ { 1, 2, { 18,18,-2, 2,-1 } }, { 0, 1, { 18,-2,18, 2, 5 } },
+ { 1, 1, { 17, 2,18, 2,17 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 1, { 18,18, 3, 6,-1 } }, { 0, 1, { 18,17, 2,18, 3 } },
+ { 0, 1, { 18,17,-2, 2,17 } }, { 1, 1, { 3,17,18, 2,17 } },
+ { 1, 3, { 18,-3,18, 2, 3 } }, { 1, 3, { 18,18,-3,18, 2 } },
+ { 1, 1, { 18, 3, 1, 5, 4 } }, { 0, 1, { 17,-2,17, 2,-3 } },
+ { 1, 1, { 18,18, 3, 5, 2 } }, { 1, 2, { 18,18,-2, 2,-1 } },
+ { 0, 1, { 18,-1,-1, 2,-2 } }, { 1, 1, { 18, 3, 1, 5, 4 } },
+ { 0, 3, { 18,17,-1, 2,17 } }, { 1, 3, { 18,17, 2,18,-2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 1, 2, { 18,18,-2, 2,-1 } },
+ { 1, 1, { 18, 3, 1, 5, 4 } }, { 0, 4, { 3,18,18, 2,17 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 1, 1, { 18,17,-1,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 1, { 18,18,18, 3, 2 } }, { 0, 1, { 17,-1, 2, 3, 6 } },
+ { 0, 1, { 17,-1, 2, 3, 6 } }, { 0, 2, { 18,17,-2, 3, 2 } },
+ { 1, 3, { 18,17, 2,-2,18 } }, { 0, 2, { 18,18, 2,17, 3 } },
+ { 0, 1, { 18,18, 2,18,-2 } }, { 0, 2, { 18,-2, 4,18, 2 } },
+ { 0, 1, { -2,18, 2, 2,18 } }, { 0, 2, { 18,17, 3, 6, 2 } },
+ { 0, 1, { 18,17,18, 2, 5 } }, { 0, 3, { 18,18,-2, 3, 2 } },
+ { 1, 1, { 18,18, 2,18, 5 } }, { 0, 1, { 17,-1, 2, 3, 6 } },
+ { 1, 4, { 18,18, 2, 3,-2 } }, { 0, 2, { 18,17,18, 2,-2 } },
+ { 0, 1, { 1,18, 3, 2, 5 } }, { 1, 4, { 18,-2,18, 2, 3 } },
+ { 1, 2, { 18, 2,18, 3,-2 } }, { 0, 2, { 18,18,18, 2, 4 } },
+ { 0, 2, { 3,17,18, 2,17 } }, { 1, 1, { 18,-1,18, 2,17 } },
+ { 1, 2, { 17,17, 2,18, 3 } }, { 0, 2, { 18,17,-2, 3, 2 } },
+ { 0, 1, { 1,-1,-1, 2,17 } }, { 0, 3, { 3,18,18, 2,17 } },
+ { 0, 1, { 18,-1,17,18, 2 } }, { 0, 1, { 18,17, 2,18, 3 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 1, { 18,17, 2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 2, { 17,17, 2,18, 3 } }, { 0, 1, { 18,17,-2, 2, 3 } },
+ { 0, 1, { 18,-2,18, 2, 5 } }, { 1, 4, { 18,-2,18, 2, 3 } },
+ { 1, 3, { 18,17, 2, 3, 6 } }, { 0, 2, { 18,18, 2,17, 3 } },
+ { 0, 2, { 18,17, 2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 1, { 18,18, 3, 5, 2 } }, { 0, 2, { 18,18,-2, 2, 3 } },
+ { 1, 2, { 18,17, 2,17, 3 } }, { 0, 1, { 18,17, 2, 3,18 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 1, 4, { 18,18, 2, 3,-2 } },
+ { 0, 1, { 17,-2,17, 2,-3 } }, { 0, 1, { 17,17, 2,18, 4 } },
+ { 1, 1, { 18,18,18, 2, 4 } }, { 1, 2, { 18, 2,18, 3,-2 } },
+ { 1, 1, { 18,18,-2, 2,17 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18, 2,17, 3 } }, { 0, 2, { 18,18,18, 2, 4 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,17,-2, 3, 2 } },
+ { 0, 1, { 1,-1,-1, 2,17 } }, { 1, 4, { 18,18, 2, 3,-2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 1, { 18,-2,18, 3, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 1, { 18,18,-2, 2,17 } }, { 0, 3, { 18,17, 2, 3,17 } },
+ { 1, 2, { 18,18, 2,-2,18 } }, { 0, 1, { -1, 3, 5, 4, 7 } },
+ { 1, 1, { 18, 3, 1, 5, 4 } }, { 1, 1, { 18,18,-2,18, 3 } },
+ { 0, 2, { 18,17,18, 2,-2 } }, { 0, 2, { 18,18, 2,17, 3 } },
+ { 1, 2, { 18, 2,18, 3,-2 } }, { 1, 4, { 18,18, 2, 3,-2 } },
+ { 1, 3, { 18,17, 2, 3, 6 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 2, { 18,17,-2,-1,17 } }, { 0, 1, { 17,-1, 2, 3, 6 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2, 2, 3 } },
+ { 1, 1, { 18,18,18, 2, 5 } }, { 0, 1, { 17,17,-2, 2, 3 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,17, 3, 6, 2 } },
+ { 0, 2, { 18,17,18, 2, 3 } }, { 0, 3, { 18,17,-3,18, 2 } },
+ { 0, 1, { 18,18,18, 2, 3 } }, { 0, 1, { 18,-2,-3, 2, 6 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 1, 1, { 18,17,18, 2, 5 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 1, { 18,17,18, 2, 5 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 1, { 18,18,18, 2, 3 } }, { 1, 1, { 17,-2,17, 1, 2 } },
+ { 1, 1, { 17,17, 2,-1, 7 } }, { 0, 1, { 18,17, 4, 3, 1 } },
+ { 1, 3, { 18,-3,18, 2, 3 } }, { 0, 1, { 1,18, 3, 2, 5 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 1, { 18,18, 3, 6, 2 } }, { 0, 1, { 17,17, 2,18, 4 } },
+ { 0, 1, { 17,17, 2,18, 4 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 1, 2, { 18,-2,18, 3, 2 } }, { 1, 1, { 17,-2,17, 1, 2 } },
+ { 1, 1, { 18,18, 3, 2, 5 } }, { 0, 1, { 18,18,-1, 2, 3 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 1, { 18,17,18, 2, 5 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 1, { 3,18,18, 2,17 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+ { 0, 2, { 18,18,-2,18, 2 } }, { 0, 2, { 18,18,-2,18, 2 } },
+};
+
+static const WavPackDecorrSpec high_specs[] = {
+ { 1, 2, { 18,18,18,-2, 2, 3, 5,-1,17, 4 } }, { 0, 1, { 18,17,-2, 2,18, 3, 7, 2, 5, 4 } },
+ { 1, 2, { 1,18, 3, 6,-2,18, 2, 3, 4, 5 } }, { 0, 2, { 18,18,-2, 2,18, 3, 6, 2,17, 4 } },
+ { 1, 2, { 18,18, 2,18, 3, 2,-1, 4,18, 5 } }, { 1, 1, { 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 } },
+ { 1, 1, { 17, 3,18, 7, 2, 6, 1, 4, 3, 5 } }, { 1, 1, { -2,18,18,18, 3,-2, 6, 5, 2, 1 } },
+ { 1, 2, { 18,18,-1,18, 2, 3, 6,-2,17, 5 } }, { 0, 1, { 17,17,18, 3, 6, 4, 5, 2,18,-2 } },
+ { 1, 2, { 1,18,-2, 3, 5, 2, 4,-1, 6, 1 } }, { 0, 2, { 18,18, 3, 6,18, 2, 4, 8, 5, 3 } },
+ { 0, 1, { -2, 1,18, 2,-2, 7,18, 2,-1, 5 } }, { 1, 1, { 4, 3, 8, 1, 5, 2, 5, 6, 2, 8 } },
+ { 1, 1, { 17,18, 2, 6, 3, 4,-1, 1, 8, 6 } }, { 0, 1, { 18,18, 3, 6, 3,-2, 2, 5,-1, 1 } },
+ { 0, 1, { 18,18,17,-1, 2,-2,18, 3, 4, 5 } }, { 1, 2, { 18,17, 2,-2,18, 3, 5, 7, 2, 4 } },
+ { 1, 2, { 18,18, 3, 6,-2,18, 2, 5, 8, 3 } }, { 0, 1, { 18,17, 2,18,18, 2, 6, 5,17, 7 } },
+ { 1, 2, { 18,17, 2,18, 3, 2, 6,18,-1, 4 } }, { 1, 1, { 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 } },
+ { 1, 1, { 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 } }, { 0, 1, { -2,18,18,18,-2, 3, 2, 4, 6, 5 } },
+ { 1, 2, { 18,17,-3, 3,-1,18, 2, 3, 6, 5 } }, { 0, 1, { 17,18, 7, 3,-2, 7, 1, 2, 4, 5 } },
+ { 1, 1, { 2,18,18,-2, 2, 4,-1,18, 3, 6 } }, { 0, 3, { 1,18, 4, 3, 5, 2, 4,18, 2, 3 } },
+ { 0, 1, { -2,18, 2,18, 3, 7,18, 2, 6,-2 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 18,18, 5, 4, 6, 4, 5, 1, 4, 3 } }, { 1, 1, { 18, 3, 6, 5, 7, 8, 2, 3, 1,-1 } },
+ { 1, 1, { 18,18,18, 2,-2, 3, 5,18, 2, 8 } }, { 0, 2, { 18,17,-2, 2, 3,18,-3, 5, 2, 7 } },
+ { 1, 1, { 1, 1,-1, 8,17, 3,-2, 2, 6,17 } }, { 0, 2, { 18,18,17, 2,-2, 3, 2, 4,18, 5 } },
+ { 1, 1, { 17,18, 2,-1, 5, 7,18, 3, 4, 6 } }, { 1, 1, { 5, 4, 5,17, 3, 6, 3, 4, 7, 2 } },
+ { 0, 1, { 17, 3, 1, 7, 4, 2, 5,-2,18, 6 } }, { 0, 1, { 17,18, 2,18, 4, 3, 5, 7,-3, 6 } },
+ { 1, 2, { 17,17,-3,-2, 2, 8,18,-1, 3, 5 } }, { 0, 1, { 17,17,18, 2, 3, 6,-2, 8, 1, 7 } },
+ { 1, 1, { 1, 2, 6,-2,18, 2, 5,-3, 7,-2 } }, { 0, 1, { 18,18, 3,18, 6, 8,-2, 2, 3, 5 } },
+ { 0, 1, { 18,17, 2,18,-2, 3, 7, 6, 2, 4 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 18,18, 2,-1, 3, 6, 1, 3, 4, 8 } }, { 0, 1, { 18,18, 3, 6, 5, 3,-2, 2,18,-1 } },
+ { 0, 1, { 18,17,-3,18, 2, 4,-2, 3, 6,17 } }, { 1, 3, { 1, 2,17, 3,18, 7,-1, 5, 2, 4 } },
+ { 1, 1, { 18, 3,18, 6, 8,18,-2, 5, 7, 2 } }, { 0, 1, { 17, 2,18, 6, 3, 2, 5, 4, 8, 1 } },
+ { 0, 1, { 18,17,-1, 2, 3,18,18, 2, 3,17 } }, { 1, 1, { 18, 7, 6, 5, 5, 3, 1, 4, 2, 4 } },
+ { 1, 1, { 6,17, 3, 8, 1, 5, 7,-1, 2, 1 } }, { 1, 1, { 18,-2,18, 3,-2, 2, 7, 4, 6,18 } },
+ { 1, 3, { 18,-3,18, 2, 3,18,-1, 7, 2, 5 } }, { 0, 2, { 18,-2, 7, 1, 3, 2, 4, 6,-3, 7 } },
+ { 1, 1, { 18,-2, 2,-3,18,-2,17,-1, 4, 2 } }, { 0, 3, { 17,17, 2, 5, 3, 7,18, 6, 4, 2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 18,17, 4, 6, 6, 4, 5, 3, 4, 1 } }, { 0, 1, { 18, 5, 3, 6, 2, 3, 8, 1, 3, 7 } },
+ { 1, 2, { 18,17,-2, 2,18, 3, 5, 7,-1, 2 } }, { 0, 1, { 1,18,18, 3, 6,-1, 4, 8, 5, 2 } },
+ { 1, 1, { 1, 5, 3, 4, 1, 1, 3, 5, 7, 3 } }, { 0, 1, { 3,18,18, 2,18,18,-1, 2, 3,18 } },
+ { 1, 2, { 18,18,-1,18, 2, 3, 4, 6,18, 5 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 18, 3, 1, 4, 5, 2, 7, 1, 3, 6 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 2, { 18,18,-1,18, 2, 3, 5,-2, 6, 8 } }, { 1, 1, { 17,18, 4, 8, 3, 2, 5, 2, 7, 6 } },
+ { 1, 4, { 1, 2, 5,18,-2, 2, 3, 7,-1, 4 } }, { 0, 2, { 18,17,-1, 3, 6,18, 2, 3, 7, 5 } },
+ { 0, 1, { -2,18, 2,-3, 6,18, 4, 3,-2, 5 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 17,17, 6, 2, 4, 8, 3, 5,-1,17 } }, { 1, 1, { 18, 3,18, 6, 8,18,-2, 5, 7, 2 } },
+ { 1, 2, { 17,17,-3, 2,18,-2, 8, 3, 6,-1 } }, { 1, 1, { 18,-2,17,18, 2, 3,-2, 6, 5, 4 } },
+ { 1, 2, { 18,17,-1, 3,18, 2, 5, 3, 6,-3 } }, { 0, 1, { 18,17, 2,18, 7,18, 2, 4, 3,17 } },
+ { 1, 3, { 18,18, 5, 6, 4, 3, 4,18, 6, 5 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 } }, { 0, 1, { -2,18,18,18, 3, 6, 4, 2, 5, 2 } },
+ { 0, 3, { 18,17,-3,18, 3, 2, 5,-1,17, 3 } }, { 1, 1, { 17,18, 7, 3, 1, 7, 4, 2, 6, 5 } },
+ { 1, 1, { 18, 2,-2,-1,18, 5, 3,-2, 1, 2 } }, { 0, 3, { 18,18,-1, 3, 2, 7, 5,18, 4, 3 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 17,18, 2,-2, 4, 8,18, 3, 6, 5 } }, { 0, 2, { 18,17, 3, 5,-2, 7, 2,18, 3,-1 } },
+ { 1, 1, { 18, 2,-2,-1,18, 5, 3,-2, 1, 2 } }, { 0, 2, { 3,17,18,18, 2, 5, 7, 6,18, 3 } },
+ { 1, 1, { 17,18,18, 4, 3, 2,18, 7, 8,-1 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 17, 1, 2, 3, 5, 6, 1, 4, 8,17 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { 18,17,-1,18,-3, 2, 8, 3, 6,17 } }, { 1, 1, { 17,17, 1, 2, 4, 5,-1, 2, 1, 6 } },
+ { 1, 1, { 1, 2, 6,-2,18, 2,-3, 3,-2, 5 } }, { 0, 1, { 18, 3,18, 6,18, 5, 2, 4,-1, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 18,18,-1, 2,18, 3, 6, 4,-2, 7 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { -1,18,18,18, 2,-2, 4, 7, 2, 3 } }, { 0, 3, { 3,17,-2, 5, 2, 7,18, 6, 4, 5 } },
+ { 0, 1, { 17, 6,18, 3, 8, 4, 5, 3, 8,18 } }, { 0, 2, { 18, 2, 6, 2,18, 3, 2, 4, 5, 8 } },
+ { 0, 1, { 3,18,18, 2,18,-1, 2,18, 2,17 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 3, 6,17,-2, 5, 1, 2, 7, 4, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 3, { 3,18,17, 5, 6, 2, 7,-2, 8,18 } }, { 1, 1, { 18,-1, 3, 1, 7, 2,-1, 4, 6,17 } },
+ { 1, 1, { 18, 2,-2,-1,18, 5, 3,-2, 1, 2 } }, { 0, 2, { 18, 1, 2,18, 3, 6, 5, 2, 4, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 17,-2, 2,18,18, 8, 5, 3, 2, 6 } }, { 0, 1, { 18,17, 2,18, 3, 2, 7,-2,18, 4 } },
+ { 1, 2, { 1,18, 2, 3,-1, 5, 6, 4, 7,17 } }, { 0, 2, { 18,17, 3, 6,-2, 2, 3, 8, 5,17 } },
+ { 0, 2, { 18,18, 3, 2,18,-1, 2, 4, 3,17 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 2, { 17,-1,18, 2, 3,-2, 5,18, 2, 7 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 2, { 18,-3,18, 2, 3,-2,18, 5, 6,-3 } }, { 0, 2, { 18,17, 3, 5,-2, 7, 2,18, 3,-1 } },
+ { 1, 1, { 1,18,-1, 2, 3, 1,-2, 8, 2, 5 } }, { 0, 1, { 18,18, 3, 6,18, 2, 3, 4, 8, 5 } },
+ { 0, 1, { -2, 1,18, 2,-2, 5, 7,18, 2,-1 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 17,18,-1, 2, 8, 3, 4, 5, 1, 7 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { 18,18,-1, 2,18, 3,-2, 5, 4, 2 } }, { 1, 1, { 18,17, 2,18, 3, 8, 5, 2, 7,17 } },
+ { 0, 1, { 18,18, 3,18, 6, 8,-2, 2, 3, 5 } }, { 0, 1, { 18,18, 2,18, 2, 6,18, 2,17, 7 } },
+ { 1, 3, { 18,17,18, 2, 8,18, 5,-1, 3, 6 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 18, 7, 6, 5, 5, 3, 1, 4, 2, 4 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 2, { 18,17,-1, 3, 6,18, 2, 5, 8, 3 } }, { 0, 1, { 17,18,18, 4, 7, 2, 3,-2,18, 5 } },
+ { 1, 2, { 18, 1, 2, 6, 2, 5,18, 2, 4, 8 } }, { 0, 4, { 18, 4, 1, 2, 3, 5, 4, 1, 2, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 2, { 18,17, 2,-1,18, 3,-3, 5, 2, 4 } },
+ { 0, 1, { 17,17, 3, 6, 3, 5,-2, 2,18,-1 } }, { 0, 2, { 18,18, 3,-2,18, 2,-3, 5, 3, 6 } },
+ { 1, 1, { 17,17, 2, 4, 1, 3, 5, 2, 6,-3 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 17, 1, 3, 2, 7, 1, 6, 3, 4, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 17,-1,18, 2, 1, 5, 3, 8,-1,-2 } }, { 1, 1, { 17,18,-1, 8, 2, 5, 3, 4, 1, 6 } },
+ { 1, 2, { 1,18, 3,-1, 5, 1, 2, 4, 7, 6 } }, { 0, 1, { 18,18, 3, 6, 5, 3,-2, 2,18,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 1,18,-1, 3, 8, 5, 6, 1, 2, 3 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { 18,18, 2, 3, 6,18,-1, 4, 2, 3 } }, { 1, 1, { 1, 3, 5,18, 2, 6, 7, 2, 3, 1 } },
+ { 1, 1, { 1, 3, 8,18, 5, 2, 7, 1, 3,-2 } }, { 0, 2, { 17, 2,18, 3, 6, 2, 4, 5, 8, 3 } },
+ { 0, 1, { 18,17, 2,18, 3, 2, 7,-2,18, 4 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 2, { 18,-3,18,-1, 3,-2, 5, 7, 1, 2 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 3, { 18,18, 2, 6,18, 5,18, 2, 3,17 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 3, { 1,-1, 1, 3,-2, 2, 5, 7,-3,18 } }, { 1, 2, { 18, 7, 3,-3, 2, 8, 2, 5, 4,17 } },
+ { 1, 1, { 1, 4, 5, 1, 3, 4, 6, 7, 8, 3 } }, { 0, 1, { 18,17, 2,18,-1, 2, 3,18, 2, 4 } },
+ { 0, 2, { 18,18,-2,18, 2, 3, 4, 7, 5,17 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 17,18, 2, 1, 3, 2, 5, 1, 2, 3 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { 18,18,-1, 2, 3, 5, 8, 6, 1,-2 } }, { 0, 1, { 17,18, 8, 3, 4, 6, 5, 2, 8, 7 } },
+ { 1, 2, { 1, 3,-2,18, 2, 5, 1, 7,-1,-2 } }, { 0, 3, { 18,17,-1, 3,18, 2, 3, 6, 4,17 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 2, { 18,18, 4,18, 6, 7, 8, 3,18, 2 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { 17,-3,17, 2,-2, 8, 3,18, 4,-3 } }, { 1, 1, { 18,17, 3, 5, 6, 2, 8, 1, 3, 7 } },
+ { 0, 1, { 18,18, 3, 6, 5, 3,-2, 2,18,-1 } }, { 0, 3, { 18,18, 2, 6,18, 5,18, 2, 3,17 } },
+ { 1, 1, { 18,18, 5, 4, 6, 4, 5, 1, 4, 3 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { 3,17,18,-3, 2, 5,18, 6,-1, 7 } }, { 1, 1, { 17,18, 3, 2, 5,-1, 6, 8, 4, 7 } },
+ { 1, 1, { 18, 1,-2, 3, 2, 1, 7, 6, 3, 4 } }, { 0, 3, { 1, 2,17, 3,18, 2, 7, 5, 4,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 17,-2, 2,18,18, 8, 5, 3, 2, 6 } }, { 0, 2, { 18, 5,18, 2, 3, 7,-2, 1, 6, 8 } },
+ { 0, 1, { 2,-1,18,-1, 2, 4,-3, 5,18, 3 } }, { 0, 1, { 3,17,18, 5, 2,18, 7, 3, 6, 5 } },
+ { 1, 4, { 1, 2, 5,18,-2, 2, 3, 7,-1, 4 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 1,18, 2, 1, 3, 4, 1, 5, 2, 7 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { 17,17,18, 2, 4, 5,18,-2, 6, 3 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 2, { 18,18,-1, 3, 5, 6, 8,18, 2, 3 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { 18,18, 4, 6, 8,18, 7, 3, 2, 5 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 2, { -1,18,18,18, 2, 4,-2, 2, 3, 6 } }, { 0, 2, { 18,-2, 7, 1, 3, 2, 4, 6,-3, 7 } },
+ { 1, 1, { 17,18, 8, 3, 4, 6,-2, 5, 3, 8 } }, { 0, 2, { 18, 1, 2, 6, 2, 8, 3,18, 5, 4 } },
+ { 1, 1, { 3,18,18, 2,18, 2,18, 3, 2,18 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 1, 1, { 3,17,18, 5, 2, 6, 7, 1, 4, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } }, { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2, 8 } },
+};
+
+static const WavPackDecorrSpec very_high_specs[] = {
+ { 1, 2, { 18,18, 2, 3,-2,18, 2, 4, 7, 5, 3, 6, 8,-1,18, 2 } },
+ { 0, 1, { 18,18,-1,18, 2, 3, 4, 6, 5, 7,18,-3, 8, 2,-1, 3 } },
+ { 1, 2, { 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 } },
+ { 0, 1, { 17,17, 2, 3, 4,18,-1, 5, 6, 7,18, 2, 8,17, 3,-2 } },
+ { 1, 1, { 18,18, 2,18, 3, 2,18, 4,-1, 3,18, 2, 6, 8,17, 5 } },
+ { 0, 2, { 18,17, 2, 3,-2, 5,18,-3, 2, 4, 7, 3, 6, 8, 5,17 } },
+ { 1, 1, { 18,-2, 2,-3,18, 5,-2,18, 2, 3, 6, 2,17, 4, 7,-1 } },
+ { 1, 1, { 17, 8,18, 3,-2, 2, 5, 4,18, 6, 3, 8, 7, 2, 5, 4 } },
+ { 0, 2, { 18,17,-2, 2,18, 3, 2, 5,-3, 4, 7,18, 3, 8, 6, 2 } },
+ { 1, 1, { 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 } },
+ { 1, 2, { 1,18, 3, 2,-2, 1, 5, 4, 6, 2, 7, 1, 8, 3,-1, 1 } },
+ { 0, 1, { 18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 } },
+ { 0, 1, { -2,18, 2,18, 7, 2, 6,-2, 3, 4,18,18, 2,-3, 8, 5 } },
+ { 0, 2, { 18,18,18, 2, 4, 3,18, 5, 3, 6,-2, 2, 4,18, 8, 7 } },
+ { 0, 1, { -2, 1,18, 2,-2,18,-1, 5, 7, 2, 3, 4,18, 2, 6, 2 } },
+ { 1, 1, { 17,18, 3, 2, 1, 7,-1, 2, 4, 3, 5, 6,-2,18, 7, 8 } },
+ { 1, 1, { 18,18, 2,18, 3, 4, 6,-2,18, 5, 8, 2, 3, 7, 4,-1 } },
+ { 0, 1, { 18,18,18,-1, 2, 3, 4, 6, 8,18, 3, 5, 2, 6, 7, 4 } },
+ { 1, 1, { 17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 } },
+ { 0, 1, { 17,17,18, 2, 3, 6,-2, 8, 1, 7, 5, 2, 3, 1, 4, 8 } },
+ { 1, 1, { 17,17, 3, 2, 7, 1, 4, 3, 6, 2, 5,-2, 8, 7,18, 6 } },
+ { 0, 1, { 18,17,-2, 2,18, 3,-3, 7, 6, 5, 2, 4,-1, 8, 3,17 } },
+ { 1, 1, { 2,18,18,-2, 2, 4,-1, 5,18, 3, 8, 6, 2, 7,17, 4 } },
+ { 0, 1, { 17, 3, 6, 8, 5, 4, 3, 8, 1,18, 7, 2, 4, 5, 6, 3 } },
+ { 1, 2, { 17,18, 4, 8, 3, 2, 5, 7, 6, 8, 2, 7,-2,18, 3, 4 } },
+ { 1, 1, { 6, 5, 5, 3, 4, 7, 3, 2, 4, 6, 3, 7, 1, 5, 2, 4 } },
+ { 1, 1, { 1,18,-1, 2, 1, 3, 8,-2, 2, 5, 6, 3, 8, 7,18, 4 } },
+ { 0, 1, { 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 } },
+ { 0, 1, { 18, 2,18,18, 2,18, 6,-2,18, 7, 5, 4, 3, 2,18,-2 } },
+ { 0, 3, { 1, 4,18, 3, 2, 4, 1, 5, 2, 3, 6,18, 8, 7, 2, 4 } },
+ { 0, 1, { 17,-2, 1,-3, 2,18, 3,-2, 4,18, 3, 6, 7,-3, 2, 8 } },
+ { 1, 1, { 17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 } },
+ { 1, 2, { 18,-1,17,18, 2, 3,-2,18, 5, 8, 2, 4, 3, 7, 6,-1 } },
+ { 1, 1, { 18,18,18,-2, 4, 2, 3,18, 5, 8, 2, 4, 6, 7,-2, 3 } },
+ { 1, 2, { 18,18,-2,18,-1, 3, 2, 5,18,-2, 7, 2, 3, 4, 6, 8 } },
+ { 0, 1, { 17,18,-1, 2, 4,18, 8, 3, 6, 5, 7,-3, 2, 4, 3,17 } },
+ { 1, 1, { 18,18,17, 2,-1,18, 3, 2,18, 6, 5, 4,18, 7, 2,-1 } },
+ { 0, 2, { 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 } },
+ { 1, 1, { 1,17,-2, 2,-3, 6, 3, 5, 1, 2, 7, 6, 8,-2, 4, 1 } },
+ { 0, 1, { 17,-1, 5, 1, 4, 3, 6, 2,-2,18, 3, 2, 4, 5, 8,-1 } },
+ { 0, 2, { 18,18,17, 2, 3,-2, 5,18, 2, 4, 7, 8, 6,17, 3, 5 } },
+ { 1, 1, { 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 } },
+ { 1, 2, { 1,-1, 3, 2,18, 7,-2, 5, 2, 6, 4, 3,-1,18, 8, 7 } },
+ { 0, 2, { 18,17, 3,18, 2, 5, 4, 3, 6, 2, 7, 8,18, 3, 4, 5 } },
+ { 1, 1, { 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 } },
+ { 0, 2, { 18,18, 3,-3,18, 2, 6, 5, 3, 7,18, 4,-2, 8, 2, 3 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 } },
+ { 1, 1, { 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 } },
+ { 0, 1, { 18,18,18, 2, 4,-1,18, 8,-1, 2, 3, 4, 6,-2, 1, 7 } },
+ { 1, 1, { 18,-2,17,18, 2, 6, 3,-2, 5, 4, 7, 1,-3, 8, 2, 6 } },
+ { 0, 1, { 17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 } },
+ { 1, 1, { 18,18, 5, 4, 6, 4, 1, 5, 4, 3, 2, 5, 6, 1, 4, 5 } },
+ { 0, 1, { 18,18,-2,18, 2,-3, 3, 8, 5,18, 6, 4, 3,-1, 7, 2 } },
+ { 1, 1, { 18, 2,-2,-3,18, 5, 2, 3,-2, 4, 6, 1,-3, 2, 7, 8 } },
+ { 0, 1, { 18, 3, 5, 8, 2, 6, 7, 3, 1, 5, 2,-1, 8, 6, 7, 4 } },
+ { 1, 1, { 4, 3, 8, 1, 5, 6, 2, 5, 8,-2, 2, 7, 3,18, 5, 4 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 3,18,18, 7, 2, 4,18, 6, 2, 3,-1, 8, 5,18,-3 } },
+ { 0, 1, { 3,17,18, 2,18, 6, 7,-3,18, 2, 5, 6, 3, 8, 7,-1 } },
+ { 1, 1, { 18,18, 2,18,18, 2,-1, 7, 3,18, 5, 2, 6, 4,-1,18 } },
+ { 0, 3, { 18, 3, 4, 1, 5, 2,18, 4, 2, 3,18, 7, 6, 1, 2, 4 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 1,18, 2, 3, 6, 4, 5, 7,18, 3, 8, 2, 4,-2,17 } },
+ { 1, 2, { 18,17, 2, 3, 5,18, 6,-2, 7, 3, 2, 4,18, 8,-1, 5 } },
+ { 0, 2, { 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 } },
+ { 1, 1, { 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 } },
+ { 0, 1, { 18,18, 2,18, 2,18, 7, 6,18, 2,-2, 3, 5, 4,18, 8 } },
+ { 1, 2, { 18,17, 2, 3,18,-1, 2, 3, 6,18, 5, 4, 3, 7, 2, 8 } },
+ { 1, 2, { 18,18, 3,-2, 4,18, 5, 7, 6, 2, 4,-3, 8, 5,18, 3 } },
+ { 1, 1, { 17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 } },
+ { 1, 1, { 3,17,18, 5, 7, 2, 4, 6, 1, 8,-1, 3, 7, 4, 1, 2 } },
+ { 0, 2, { 1,-2, 2,18, 3, 5, 2, 4, 7,-1, 2, 3, 5,18,-2, 4 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 1, 2,-2, 6,18,-3, 2, 7, 3,-2, 5, 6, 1, 8, 2, 4 } },
+ { 0, 1, { 18,18,18, 3,-2, 6,18, 2, 4, 3, 5, 8, 7, 6, 2,-2 } },
+ { 1, 1, { 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 } },
+ { 0, 1, { 3,17,18, 2, 5,18, 6, 7, 5,-2, 2, 4,18, 3, 6, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 2, { 17,-1,18, 2, 4,-1, 8, 3,18, 7,-3, 4, 5, 1, 2,-2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 } },
+ { 1, 1, { 18,18, 3, 6, 4, 8,-2, 2, 5, 3, 7,18, 6, 8, 4, 2 } },
+ { 1, 1, { 17,18,18,-2, 5, 2, 3, 1, 4,-1, 8, 6, 5, 3, 2,18 } },
+ { 1, 1, { 17,17, 1, 2, 4, 5, 2, 6,-1, 3, 1, 1,-2, 4, 2, 7 } },
+ { 1, 1, { 17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 } },
+ { 0, 1, { 18,17,-2,-3, 1, 2, 3, 2, 5, 4, 7,-3, 6,-2, 2, 1 } },
+ { 1, 1, { 1, 3, 5,18, 1, 2, 7, 3, 6, 2, 5, 8,-1, 1, 4, 7 } },
+ { 1, 1, { 17, 3, 6, 8, 1, 4, 5, 3,-2, 7, 2, 8, 5, 6,18, 3 } },
+ { 1, 1, { 17,18, 2, 4, 8,-2, 3, 1, 5, 6, 7, 1, 2, 3, 4, 7 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 3, 1, 8,18, 5, 2, 3,18, 6, 7,-2, 4, 3, 2, 8,18 } },
+ { 0, 1, { 18,17, 2,18, 3, 4,-1,18, 7, 6, 2, 8, 4,18,18, 5 } },
+ { 0, 1, { 18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 } },
+ { 1, 2, { 18,17,18, 2, 3, 5,-2,18, 6,-1, 2, 3, 7, 4, 8,17 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 } },
+ { 1, 2, { 18,18,-2,17, 2,18, 3, 4,18, 8, 7,-1, 2, 4, 5,17 } },
+ { 0, 2, { 17,-3,17, 3, 2,-2,18, 8, 4,-3, 2,18, 5, 3,-2, 6 } },
+ { 0, 1, { 18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 } },
+ { 0, 2, { 1,18,-1, 3, 5, 2,-3,18, 7, 3,-1, 6, 4, 2,17, 5 } },
+ { 1, 1, { 17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 } },
+ { 1, 1, { 1,18, 1, 3, 5, 8, 6, 2, 3,-1, 7, 1, 4, 8, 5,-3 } },
+ { 0, 2, { 3,18,18, 2,18,-2, 6, 5, 7, 2, 4,18, 3, 6,-3, 5 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 } },
+ { 0, 4, { 18, 2,17, 3,18,-2, 2, 6,18, 2, 7, 3, 5, 4, 8,18 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { 18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 1, 2, 5, 3,-2, 1, 4, 3, 7, 6,-3, 2, 1, 1, 2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 18,18,-2,18,-2, 2, 3, 6,18, 4,-1, 2, 3, 8, 1, 4 } },
+ { 1, 1, { 17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 } },
+ { 0, 1, { 17,17,18, 3, 2,18,18, 6, 8, 2,-2, 3, 5, 4,17,18 } },
+ { 1, 1, { 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 } },
+ { 1, 1, { 1, 3,-3,18,18, 6, 5,18, 2,-1, 3, 8, 7,-3, 4,17 } },
+ { 1, 1, { 18, 1, 2, 1, 3, 8, 7, 4, 1, 5, 2,-1,-3,18, 6, 2 } },
+ { 0, 1, { 18, 3, 5, 2, 6, 8,18, 5, 7, 2, 3,-1, 6, 7, 8, 5 } },
+ { 0, 2, { 18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 3, { 1, 1, 2, 5, 2, 7, 4, 3,-1,18,-2, 8, 2, 1, 6, 7 } },
+ { 0, 1, { 3,17,18, 5, 2, 6, 7,18, 4, 5, 3, 6,18, 2, 7, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { 1,18, 1, 2, 3, 5, 1, 2, 6, 7, 4, 3, 8, 1,17, 5 } },
+ { 1, 2, { 17,-1,18,-2, 2, 3, 5,18, 2, 4, 6, 7, 3,-1, 5, 8 } },
+ { 1, 1, { 18,18,-3,18,-2, 2, 3,-2,18, 6, 4, 5, 8, 3,17,-3 } },
+ { 1, 1, { 18, 7, 6, 5, 5, 3, 1, 4, 2, 7, 3, 4,-3, 6,18, 8 } },
+ { 0, 2, { 18,18, 2, 3, 5,18, 2, 4, 3, 6,18, 7, 8,-1, 5, 2 } },
+ { 0, 1, { 18,17,-1, 2,18, 3, 2,18, 4, 3,18, 2, 6, 5, 8,17 } },
+ { 0, 2, { 18,17, 2, 3,18, 5,-1, 6, 7, 8, 2, 3, 4, 5,18, 6 } },
+ { 1, 2, { 18,-3,18, 2, 3,-2,-3, 5,18, 7, 6, 2, 4, 3, 8,-2 } },
+ { 1, 1, { 17,18,18,-2, 2, 3, 5, 4, 8,18,-1, 5, 3, 6,-2, 7 } },
+ { 1, 2, { 18,17, 2,-2,18, 3,-1, 4,18, 2, 7, 5, 3, 8, 6, 4 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 } },
+ { 0, 2, { 18,18, 3, 3,-2, 2, 5,18, 6, 3,-1, 4, 7,-1, 1, 2 } },
+ { 0, 1, { -2, 1,18, 2,-2, 5, 7,18, 3, 2, 6, 2,-1, 4,-2,17 } },
+ { 0, 2, { 18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17,18,-1, 3, 2, 5, 1, 3, 2, 8, 4, 7, 6, 2,-1, 5 } },
+ { 1, 1, { 17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 } },
+ { 0, 1, { 18,18,-2,18, 2, 3, 4, 5, 6,18, 8, 2, 3, 7,-2, 4 } },
+ { 0, 1, { 18,-2,18,18,-3,-2, 2, 3, 5, 8, 1, 2, 6, 4, 7,-1 } },
+ { 0, 1, { 18,17, 2,18, 3,-2, 2, 7, 6, 4,18, 3, 8, 7, 4, 2 } },
+ { 1, 1, { 17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 } },
+ { 1, 1, { 18,17,18, 2, 5, 3,-2,18, 6, 2, 3, 4, 8, 7, 5,-1 } },
+ { 0, 1, { 2,-1,18,-1, 2, 4,-3,18, 5, 3, 6,18, 2, 4, 7, 8 } },
+ { 1, 1, { 17,18, 8, 3, 6, 4,-1, 5, 2, 7, 3, 8, 6, 5,18, 4 } },
+ { 0, 2, { 18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { 17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 } },
+ { 1, 2, { 18,-1,18, 3,-2,18, 2, 5, 3, 6, 7, 2,-1,18, 8, 4 } },
+ { 1, 2, { 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 } },
+ { 1, 2, { 1,18,-3, 2, 3,18,-1, 5, 6, 2, 8, 3, 4, 1,-2, 7 } },
+ { 0, 1, { 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 } },
+ { 1, 1, { 18,17,18, 4, 3, 5, 1, 2, 6, 3, 4, 7, 1, 8, 5, 2 } },
+ { 0, 1, { 18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 2, { 18,18,18,-2, 2, 5, 3, 7,18, 2, 4,-3, 5, 6, 3, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 3, { 3,18,-1, 5, 2, 7,18, 6, 5, 2, 4, 3,-1, 7,18, 6 } },
+ { 0, 2, { 18,18,18, 4, 3, 2, 6, 4, 8,18, 5, 3, 2, 7,-2, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 2, { 18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18,18, 2, 4, 6,-2, 2, 8, 3, 4,18, 7,-1, 6 } },
+ { 0, 1, { 18, 1,-2, 2, 4, 1, 3,-1, 2, 5, 7, 1, 6, 8,-2,17 } },
+ { 0, 1, { 17,17,18, 2, 5, 4,18, 3, 8, 7, 4, 6, 8, 1, 5, 2 } },
+ { 1, 2, { 18,18, 5, 4, 6, 3, 4,18, 8, 4,-1, 7, 5, 3, 6, 2 } },
+ { 0, 1, { 18,18,-3,18, 3, 6, 2, 5, 7,18, 3, 8,-1, 4, 5, 2 } },
+ { 1, 1, { 18, 2,-2,-3,18, 5, 2,-2, 4, 3, 6,18, 8,-1, 2, 7 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { 17,18, 3,18, 2, 5, 4, 7,-3, 6, 3, 2,18, 4, 7, 3 } },
+ { 1, 1, { 1, 7, 4, 5, 3, 4, 5, 1, 3, 6, 3, 2, 4, 8,-2, 7 } },
+ { 0, 1, { 1,18,-1,-2,18, 3, 2,-1, 6, 7, 4, 5, 3,18, 2,-3 } },
+ { 1, 1, { 18,18,-1, 3, 6,18, 5, 4, 8, 2, 3, 6,18, 7, 4,-2 } },
+ { 0, 2, { 18,18, 2, 6,18, 2,18, 5, 3,18, 2, 4, 7, 8, 3,18 } },
+ { 1, 1, { 3,18,18, 5,18, 6, 2, 4, 7,-2,18, 5, 8, 6, 3, 2 } },
+ { 0, 1, { 18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 } },
+ { 1, 1, { 18,-2,18, 2, 5,18, 3,-2, 4, 7, 2,-1, 8, 6, 5, 1 } },
+ { 1, 1, { 17,17, 5,18, 4, 1, 2, 8, 6, 4,-2, 3, 5,-1, 1, 8 } },
+ { 0, 2, { 1, 2,17, 3, 7,18, 2,-1, 4, 5,18, 2, 7, 3, 6, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 2, { 18,18,18, 2,-2, 3, 6, 4, 8,18, 2, 5, 7, 4, 3, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 18, 1, 8, 3, 5, 6, 4,-1, 8, 3, 7,18, 2, 5, 8, 4 } },
+ { 1, 1, { 17,18, 5, 2, 4, 3, 1, 6,-2, 1, 3, 2, 4, 5,-1,17 } },
+ { 1, 1, { 18,17, 2,18, 3,-3, 7, 2, 6, 4, 3, 5,18, 8, 2,-2 } },
+ { 1, 1, { 18,17,18, 4, 3, 5,-1,18, 2, 7, 8, 4, 6, 3,18, 5 } },
+ { 0, 1, { 18,17,18,-2, 2,-3, 3, 4, 8, 5, 2,18, 6, 3, 7,-2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 17,18, 8, 3, 4, 6,18, 5,-2, 3, 8, 5, 2, 4, 7, 6 } },
+ { 0, 1, { 18,-2, 3, 5, 1, 7, 3, 2, 6,-3, 4, 1, 5, 8, 3,-2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 3,17,18, 5,-1,18, 2, 6, 7,18, 5, 3,-3,-1, 6, 2 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 3, { 18,17,-2, 3,-1,18, 2, 5, 3, 7, 6, 2, 4, 8,18, 5 } },
+ { 0, 1, { 18,-1,18, 2,18, 3, 5,18, 2, 8,18, 5, 4,-1, 6, 2 } },
+ { 1, 2, { 18,-2,18,18, 2, 3, 4,-3, 2, 5,18, 7, 4, 3, 8, 6 } },
+ { 0, 2, { 17,-1,18, 2,-1, 1, 7, 3, 8, 5,-2, 4, 1, 2,-3, 6 } },
+ { 0, 1, { 18,17, 2,18, 2,18, 6, 7, 4, 3,18, 5, 2,-2,17, 8 } },
+ { 0, 3, { 18,17, 2, 3,-3,-1,18, 2, 4, 5,18, 7, 3, 2,-3, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 2, { 3,18,18,18, 2, 6, 5,18, 7, 2, 4, 6,18, 5, 3, 8 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { 18,18, 3, 6, 3,-2, 2,18, 5,-1, 7, 3, 4,-2, 2, 6 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 1, 1, { 18,17,18,18,-2, 2, 3,-3,18, 6, 4, 2,-2, 8, 3, 7 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { 18,18,18, 4, 2, 7, 8,18, 3, 2,-2, 4, 7, 6,17, 5 } },
+ { 1, 1, { 18,18,-1,-2, 8, 3,18, 6, 3, 5, 8, 2, 4, 7, 1, 6 } },
+ { 1, 1, { 1,-3, 3,18,18, 2,-1, 3, 6, 5,18, 4, 7,-2, 8, 3 } },
+ { 1, 1, { 1,18, 4, 2, 5,18, 1, 3,-1, 6, 1, 4, 8, 2, 5, 1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+ { 0, 1, { -1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 } },
+};
+
+static const WavPackDecorrSpec * const decorr_filters[] = {
+ &fast_specs[0], &default_specs[0], &high_specs[0], &very_high_specs[0],
+};
+
+static const uint16_t decorr_filter_sizes[] = {
+ FF_ARRAY_ELEMS(fast_specs),
+ FF_ARRAY_ELEMS(default_specs),
+ FF_ARRAY_ELEMS(high_specs),
+ FF_ARRAY_ELEMS(very_high_specs),
+};
+
+static const uint8_t decorr_filter_nterms[] = { 2, 5, 10, 16 };
+
+static const int8_t nbits_table[] = {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+};
+
+#endif /* AVCODEC_WAVPACKENC_H */
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 62f35f7480..47e9e9e662 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -3,20 +3,20 @@
* Copyright (c) 2013 Aneesh Dogra <aneesh@sugarlabs.org>
* Copyright (c) 2013 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,16 +31,20 @@
* Lossless decoder
* Compressed alpha for lossy
*
+ * @author James Almer <jamrial@gmail.com>
+ * Exif metadata
+ *
* Unimplemented:
* - Animation
* - ICC profile
- * - Exif and XMP metadata
+ * - XMP metadata
*/
#define BITSTREAM_READER_LE
#include "libavutil/imgutils.h"
#include "avcodec.h"
#include "bytestream.h"
+#include "exif.h"
#include "internal.h"
#include "get_bits.h"
#include "thread.h"
@@ -191,6 +195,8 @@ typedef struct WebPContext {
enum AlphaFilter alpha_filter; /* filtering method for alpha chunk */
uint8_t *alpha_data; /* alpha chunk data */
int alpha_data_size; /* alpha chunk data size */
+ int has_exif; /* set after an EXIF chunk has been processed */
+ AVDictionary *exif_metadata; /* EXIF chunk data */
int width; /* image width */
int height; /* image height */
int lossless; /* indicates lossless or lossy */
@@ -303,7 +309,7 @@ static int huff_reader_build_canonical(HuffReader *r, int *code_lengths,
if (max_code_length == 0 || max_code_length > MAX_HUFFMAN_CODE_LENGTH)
return AVERROR(EINVAL);
- codes = av_malloc(alphabet_size * sizeof(*codes));
+ codes = av_malloc_array(alphabet_size, sizeof(*codes));
if (!codes)
return AVERROR(ENOMEM);
@@ -1027,7 +1033,7 @@ static int apply_color_indexing_transform(WebPContext *s)
ImageContext *img;
ImageContext *pal;
int i, x, y;
- uint8_t *p, *pi;
+ uint8_t *p;
img = &s->image[IMAGE_ROLE_ARGB];
pal = &s->image[IMAGE_ROLE_COLOR_INDEXING];
@@ -1060,16 +1066,33 @@ static int apply_color_indexing_transform(WebPContext *s)
av_free(line);
}
- for (y = 0; y < img->frame->height; y++) {
- for (x = 0; x < img->frame->width; x++) {
- p = GET_PIXEL(img->frame, x, y);
- i = p[2];
- if (i >= pal->frame->width) {
- av_log(s->avctx, AV_LOG_ERROR, "invalid palette index %d\n", i);
- return AVERROR_INVALIDDATA;
+ // switch to local palette if it's worth initializing it
+ if (img->frame->height * img->frame->width > 300) {
+ uint8_t palette[256 * 4];
+ const int size = pal->frame->width * 4;
+ av_assert0(size <= 1024U);
+ memcpy(palette, GET_PIXEL(pal->frame, 0, 0), size); // copy palette
+ // set extra entries to transparent black
+ memset(palette + size, 0, 256 * 4 - size);
+ for (y = 0; y < img->frame->height; y++) {
+ for (x = 0; x < img->frame->width; x++) {
+ p = GET_PIXEL(img->frame, x, y);
+ i = p[2];
+ AV_COPY32(p, &palette[i * 4]);
+ }
+ }
+ } else {
+ for (y = 0; y < img->frame->height; y++) {
+ for (x = 0; x < img->frame->width; x++) {
+ p = GET_PIXEL(img->frame, x, y);
+ i = p[2];
+ if (i >= pal->frame->width) {
+ AV_WB32(p, 0x00000000);
+ } else {
+ const uint8_t *pi = GET_PIXEL(pal->frame, i, 0);
+ AV_COPY32(p, pi);
+ }
}
- pi = GET_PIXEL(pal->frame, i, 0);
- AV_COPY32(p, pi);
}
}
@@ -1088,7 +1111,7 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
avctx->pix_fmt = AV_PIX_FMT_ARGB;
}
- ret = init_get_bits(&s->gb, data_start, data_size * 8);
+ ret = init_get_bits8(&s->gb, data_start, data_size);
if (ret < 0)
return ret;
@@ -1134,7 +1157,6 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
used = 0;
while (get_bits1(&s->gb)) {
enum TransformType transform = get_bits(&s->gb, 2);
- s->transforms[s->nb_transforms++] = transform;
if (used & (1 << transform)) {
av_log(avctx, AV_LOG_ERROR, "Transform %d used more than once\n",
transform);
@@ -1142,6 +1164,7 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
goto free_and_return;
}
used |= (1 << transform);
+ s->transforms[s->nb_transforms++] = transform;
switch (transform) {
case PREDICTOR_TRANSFORM:
ret = parse_transform_predictor(s);
@@ -1343,6 +1366,7 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->height = 0;
*got_frame = 0;
s->has_alpha = 0;
+ s->has_exif = 0;
bytestream2_init(&gb, avpkt->data, avpkt->size);
if (bytestream2_get_bytes_left(&gb) < 12)
@@ -1362,6 +1386,7 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
+ av_dict_free(&s->exif_metadata);
while (bytestream2_get_bytes_left(&gb) > 0) {
char chunk_str[5] = { 0 };
@@ -1435,10 +1460,44 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
break;
}
+ case MKTAG('E', 'X', 'I', 'F'): {
+ int le, ifd_offset, exif_offset = bytestream2_tell(&gb);
+ GetByteContext exif_gb;
+
+ if (s->has_exif) {
+ av_log(avctx, AV_LOG_VERBOSE, "Ignoring extra EXIF chunk\n");
+ goto exif_end;
+ }
+ if (!(vp8x_flags & VP8X_FLAG_EXIF_METADATA))
+ av_log(avctx, AV_LOG_WARNING,
+ "EXIF chunk present, but Exif bit not set in the "
+ "VP8X header\n");
+
+ s->has_exif = 1;
+ bytestream2_init(&exif_gb, avpkt->data + exif_offset,
+ avpkt->size - exif_offset);
+ if (ff_tdecode_header(&exif_gb, &le, &ifd_offset) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "invalid TIFF header "
+ "in Exif data\n");
+ goto exif_end;
+ }
+
+ bytestream2_seek(&exif_gb, ifd_offset, SEEK_SET);
+ if (avpriv_exif_decode_ifd(avctx, &exif_gb, le, 0, &s->exif_metadata) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "error decoding Exif data\n");
+ goto exif_end;
+ }
+
+ av_dict_copy(avpriv_frame_get_metadatap(data), s->exif_metadata, 0);
+
+exif_end:
+ av_dict_free(&s->exif_metadata);
+ bytestream2_skip(&gb, chunk_size);
+ break;
+ }
case MKTAG('I', 'C', 'C', 'P'):
case MKTAG('A', 'N', 'I', 'M'):
case MKTAG('A', 'N', 'M', 'F'):
- case MKTAG('E', 'X', 'I', 'F'):
case MKTAG('X', 'M', 'P', ' '):
AV_WL32(chunk_str, chunk_type);
av_log(avctx, AV_LOG_VERBOSE, "skipping unsupported chunk: %s\n",
diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c
new file mode 100644
index 0000000000..1284a172c4
--- /dev/null
+++ b/libavcodec/webvttdec.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * WebVTT subtitle decoder
+ * @see http://dev.w3.org/html5/webvtt/
+ * @todo need to support extended markups and cue settings
+ */
+
+#include "avcodec.h"
+#include "ass.h"
+#include "libavutil/bprint.h"
+
+static const struct {
+ const char *from;
+ const char *to;
+} webvtt_tag_replace[] = {
+ {"<i>", "{\\i1}"}, {"</i>", "{\\i0}"},
+ {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"},
+ {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"},
+ {"{", "\\{"}, {"}", "\\}"}, // escape to avoid ASS markup conflicts
+};
+
+static int webvtt_event_to_ass(AVBPrint *buf, const char *p)
+{
+ int i, skip = 0;
+
+ while (*p) {
+
+ for (i = 0; i < FF_ARRAY_ELEMS(webvtt_tag_replace); i++) {
+ const char *from = webvtt_tag_replace[i].from;
+ const size_t len = strlen(from);
+ if (!strncmp(p, from, len)) {
+ av_bprintf(buf, "%s", webvtt_tag_replace[i].to);
+ p += len;
+ break;
+ }
+ }
+ if (!*p)
+ break;
+
+ if (*p == '<')
+ skip = 1;
+ else if (*p == '>')
+ skip = 0;
+ else if (p[0] == '\n' && p[1])
+ av_bprintf(buf, "\\N");
+ else if (!skip && *p != '\r')
+ av_bprint_chars(buf, *p, 1);
+ p++;
+ }
+ return 0;
+}
+
+static int webvtt_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_sub_ptr, AVPacket *avpkt)
+{
+ int ret = 0;
+ AVSubtitle *sub = data;
+ const char *ptr = avpkt->data;
+ AVBPrint buf;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ if (ptr && avpkt->size > 0 && !webvtt_event_to_ass(&buf, ptr)) {
+ int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
+ int ts_duration = avpkt->duration != -1 ?
+ av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
+ ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
+ }
+ av_bprint_finalize(&buf, NULL);
+ if (ret < 0)
+ return ret;
+ *got_sub_ptr = sub->num_rects > 0;
+ return avpkt->size;
+}
+
+AVCodec ff_webvtt_decoder = {
+ .name = "webvtt",
+ .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_WEBVTT,
+ .decode = webvtt_decode_frame,
+ .init = ff_ass_subtitle_header_default,
+};
diff --git a/libavcodec/webvttenc.c b/libavcodec/webvttenc.c
new file mode 100644
index 0000000000..9f67a2eab6
--- /dev/null
+++ b/libavcodec/webvttenc.c
@@ -0,0 +1,219 @@
+/*
+ * WebVTT subtitle encoder
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ * Copyright (c) 2014 Aman Gupta <ffmpeg@tmm1.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdarg.h>
+#include "avcodec.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "ass_split.h"
+#include "ass.h"
+
+#define WEBVTT_STACK_SIZE 64
+typedef struct {
+ AVCodecContext *avctx;
+ ASSSplitContext *ass_ctx;
+ AVBPrint buffer;
+ unsigned timestamp_end;
+ int count;
+ char stack[WEBVTT_STACK_SIZE];
+ int stack_ptr;
+} WebVTTContext;
+
+#ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+static void webvtt_print(WebVTTContext *s, const char *str, ...)
+{
+ va_list vargs;
+ va_start(vargs, str);
+ av_vbprintf(&s->buffer, str, vargs);
+ va_end(vargs);
+}
+
+static int webvtt_stack_push(WebVTTContext *s, const char c)
+{
+ if (s->stack_ptr >= WEBVTT_STACK_SIZE)
+ return -1;
+ s->stack[s->stack_ptr++] = c;
+ return 0;
+}
+
+static char webvtt_stack_pop(WebVTTContext *s)
+{
+ if (s->stack_ptr <= 0)
+ return 0;
+ return s->stack[--s->stack_ptr];
+}
+
+static int webvtt_stack_find(WebVTTContext *s, const char c)
+{
+ int i;
+ for (i = s->stack_ptr-1; i >= 0; i--)
+ if (s->stack[i] == c)
+ break;
+ return i;
+}
+
+static void webvtt_close_tag(WebVTTContext *s, char tag)
+{
+ webvtt_print(s, "</%c>", tag);
+}
+
+static void webvtt_stack_push_pop(WebVTTContext *s, const char c, int close)
+{
+ if (close) {
+ int i = c ? webvtt_stack_find(s, c) : 0;
+ if (i < 0)
+ return;
+ while (s->stack_ptr != i)
+ webvtt_close_tag(s, webvtt_stack_pop(s));
+ } else if (webvtt_stack_push(s, c) < 0)
+ av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
+}
+
+static void webvtt_style_apply(WebVTTContext *s, const char *style)
+{
+ ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
+ if (st) {
+ if (st->bold != ASS_DEFAULT_BOLD) {
+ webvtt_print(s, "<b>");
+ webvtt_stack_push(s, 'b');
+ }
+ if (st->italic != ASS_DEFAULT_ITALIC) {
+ webvtt_print(s, "<i>");
+ webvtt_stack_push(s, 'i');
+ }
+ if (st->underline != ASS_DEFAULT_UNDERLINE) {
+ webvtt_print(s, "<u>");
+ webvtt_stack_push(s, 'u');
+ }
+ }
+}
+
+static void webvtt_text_cb(void *priv, const char *text, int len)
+{
+ WebVTTContext *s = priv;
+ av_bprint_append_data(&s->buffer, text, len);
+}
+
+static void webvtt_new_line_cb(void *priv, int forced)
+{
+ webvtt_print(priv, "\n");
+}
+
+static void webvtt_style_cb(void *priv, char style, int close)
+{
+ if (style == 's') // strikethrough unsupported
+ return;
+
+ webvtt_stack_push_pop(priv, style, close);
+ if (!close)
+ webvtt_print(priv, "<%c>", style);
+}
+
+static void webvtt_cancel_overrides_cb(void *priv, const char *style)
+{
+ webvtt_stack_push_pop(priv, 0, 1);
+ webvtt_style_apply(priv, style);
+}
+
+static void webvtt_end_cb(void *priv)
+{
+ webvtt_stack_push_pop(priv, 0, 1);
+}
+
+static const ASSCodesCallbacks webvtt_callbacks = {
+ .text = webvtt_text_cb,
+ .new_line = webvtt_new_line_cb,
+ .style = webvtt_style_cb,
+ .color = NULL,
+ .font_name = NULL,
+ .font_size = NULL,
+ .alignment = NULL,
+ .cancel_overrides = webvtt_cancel_overrides_cb,
+ .move = NULL,
+ .end = webvtt_end_cb,
+};
+
+static int webvtt_encode_frame(AVCodecContext *avctx,
+ unsigned char *buf, int bufsize, const AVSubtitle *sub)
+{
+ WebVTTContext *s = avctx->priv_data;
+ ASSDialog *dialog;
+ int i, num;
+
+ av_bprint_clear(&s->buffer);
+
+ for (i=0; i<sub->num_rects; i++) {
+ if (sub->rects[i]->type != SUBTITLE_ASS) {
+ av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+ return AVERROR(ENOSYS);
+ }
+
+ dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
+ for (; dialog && num--; dialog++) {
+ webvtt_style_apply(s, dialog->style);
+ ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
+ }
+ }
+
+ if (!av_bprint_is_complete(&s->buffer))
+ return AVERROR(ENOMEM);
+ if (!s->buffer.len)
+ return 0;
+
+ if (s->buffer.len > bufsize) {
+ av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
+ return -1;
+ }
+ memcpy(buf, s->buffer.str, s->buffer.len);
+
+ return s->buffer.len;
+}
+
+static int webvtt_encode_close(AVCodecContext *avctx)
+{
+ WebVTTContext *s = avctx->priv_data;
+ ff_ass_split_free(s->ass_ctx);
+ av_bprint_finalize(&s->buffer, NULL);
+ return 0;
+}
+
+static av_cold int webvtt_encode_init(AVCodecContext *avctx)
+{
+ WebVTTContext *s = avctx->priv_data;
+ s->avctx = avctx;
+ s->ass_ctx = ff_ass_split(avctx->subtitle_header);
+ av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
+ return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
+}
+
+AVCodec ff_webvtt_encoder = {
+ .name = "webvtt",
+ .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
+ .type = AVMEDIA_TYPE_SUBTITLE,
+ .id = AV_CODEC_ID_WEBVTT,
+ .priv_data_size = sizeof(WebVTTContext),
+ .init = webvtt_encode_init,
+ .encode_sub = webvtt_encode_frame,
+ .close = webvtt_encode_close,
+};
diff --git a/libavcodec/wma.c b/libavcodec/wma.c
index 3fe68a4348..4c1bf00486 100644
--- a/libavcodec/wma.c
+++ b/libavcodec/wma.c
@@ -1,21 +1,21 @@
/*
* WMA compatible codec
- * Copyright (c) 2002-2007 The Libav Project
+ * Copyright (c) 2002-2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,9 +29,6 @@
#include "wma_freqs.h"
#include "wmadata.h"
-#undef NDEBUG
-#include <assert.h>
-
/* XXX: use same run/length optimization as mpeg decoders */
// FIXME maybe split decode / encode or pass flag
static av_cold int init_coef_vlc(VLC *vlc, uint16_t **prun_table,
@@ -48,10 +45,10 @@ static av_cold int init_coef_vlc(VLC *vlc, uint16_t **prun_table,
init_vlc(vlc, VLCBITS, n, table_bits, 1, 1, table_codes, 4, 4, 0);
- run_table = av_malloc(n * sizeof(uint16_t));
- level_table = av_malloc(n * sizeof(uint16_t));
- flevel_table = av_malloc(n * sizeof(*flevel_table));
- int_table = av_malloc(n * sizeof(uint16_t));
+ run_table = av_malloc_array(n, sizeof(uint16_t));
+ level_table = av_malloc_array(n, sizeof(uint16_t));
+ flevel_table = av_malloc_array(n, sizeof(*flevel_table));
+ int_table = av_malloc_array(n, sizeof(uint16_t));
if (!run_table || !level_table || !flevel_table || !int_table) {
av_freep(&run_table);
av_freep(&level_table);
@@ -95,7 +92,6 @@ av_cold int ff_wma_init(AVCodecContext *avctx, int flags2)
avctx->bit_rate <= 0)
return -1;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
if (avctx->codec->id == AV_CODEC_ID_WMAV1)
s->version = 1;
@@ -144,6 +140,10 @@ av_cold int ff_wma_init(AVCodecContext *avctx, int flags2)
bps = (float) avctx->bit_rate /
(float) (avctx->channels * avctx->sample_rate);
s->byte_offset_bits = av_log2((int) (bps * s->frame_len / 8.0 + 0.5)) + 2;
+ if (s->byte_offset_bits + 3 > MIN_CACHE_BITS) {
+ av_log(avctx, AV_LOG_ERROR, "byte_offset_bits %d is too large\n", s->byte_offset_bits);
+ return AVERROR_PATCHWELCOME;
+ }
/* compute high frequency value and choose if noise coding should
* be activated */
@@ -338,6 +338,10 @@ av_cold int ff_wma_init(AVCodecContext *avctx, int flags2)
#endif /* TRACE */
}
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
+
/* choose the VLC tables for the coefficients */
coef_vlc_table = 2;
if (avctx->sample_rate >= 32000) {
@@ -385,10 +389,11 @@ int ff_wma_end(AVCodecContext *avctx)
ff_free_vlc(&s->hgain_vlc);
for (i = 0; i < 2; i++) {
ff_free_vlc(&s->coef_vlc[i]);
- av_free(s->run_table[i]);
- av_free(s->level_table[i]);
- av_free(s->int_table[i]);
+ av_freep(&s->run_table[i]);
+ av_freep(&s->level_table[i]);
+ av_freep(&s->int_table[i]);
}
+ av_freep(&s->fdsp);
return 0;
}
@@ -447,7 +452,7 @@ int ff_wma_run_level_decode(AVCodecContext *avctx, GetBitContext *gb,
/** normal code */
offset += run_table[code];
sign = get_bits1(gb) - 1;
- iptr[offset & coef_mask] = ilvl[code] ^ sign << 31;
+ iptr[offset & coef_mask] = ilvl[code] ^ (sign & 0x80000000);
} else if (code == 1) {
/** EOB */
break;
@@ -479,7 +484,11 @@ int ff_wma_run_level_decode(AVCodecContext *avctx, GetBitContext *gb,
}
/** NOTE: EOB can be omitted */
if (offset > num_coefs) {
- av_log(avctx, AV_LOG_ERROR, "overflow in spectral RLE, ignoring\n");
+ av_log(avctx, AV_LOG_ERROR,
+ "overflow (%d > %d) in spectral RLE, ignoring\n",
+ offset,
+ num_coefs
+ );
return -1;
}
diff --git a/libavcodec/wma.h b/libavcodec/wma.h
index 06386efd2f..cc9d6f9f8a 100644
--- a/libavcodec/wma.h
+++ b/libavcodec/wma.h
@@ -1,21 +1,21 @@
/*
* WMA compatible codec
- * Copyright (c) 2002-2007 The Libav Project
+ * Copyright (c) 2002-2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,7 +42,7 @@
#define NB_LSP_COEFS 10
/* XXX: is it a suitable value ? */
-#define MAX_CODED_SUPERFRAME_SIZE 16384
+#define MAX_CODED_SUPERFRAME_SIZE 32768
#define MAX_CHANNELS 2
@@ -116,7 +116,7 @@ typedef struct WMACodecContext {
DECLARE_ALIGNED(32, float, coefs)[MAX_CHANNELS][BLOCK_MAX_SIZE];
DECLARE_ALIGNED(32, FFTSample, output)[BLOCK_MAX_SIZE * 2];
FFTContext mdct_ctx[BLOCK_NB_SIZES];
- float *windows[BLOCK_NB_SIZES];
+ const float *windows[BLOCK_NB_SIZES];
/* output buffer for one frame and the last for IMDCT windowing */
DECLARE_ALIGNED(32, float, frame_out)[MAX_CHANNELS][BLOCK_MAX_SIZE * 2];
/* last frame info */
@@ -131,7 +131,7 @@ typedef struct WMACodecContext {
float lsp_pow_e_table[256];
float lsp_pow_m_table1[(1 << LSP_POW_BITS)];
float lsp_pow_m_table2[(1 << LSP_POW_BITS)];
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
#ifdef TRACE
int frame_count;
diff --git a/libavcodec/wma_common.c b/libavcodec/wma_common.c
index cf76f5cf52..c01e0f4e70 100644
--- a/libavcodec/wma_common.c
+++ b/libavcodec/wma_common.c
@@ -1,20 +1,20 @@
/*
* common code shared by all WMA variants
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wma_common.h b/libavcodec/wma_common.h
index 61b1a35e02..55404afc45 100644
--- a/libavcodec/wma_common.h
+++ b/libavcodec/wma_common.h
@@ -1,20 +1,20 @@
/*
* common code shared by all WMA variants
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wma_freqs.c b/libavcodec/wma_freqs.c
index 82cef3bfc3..03a283fca5 100644
--- a/libavcodec/wma_freqs.c
+++ b/libavcodec/wma_freqs.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wma_freqs.h b/libavcodec/wma_freqs.h
index 415c83b6c5..85c5f697b7 100644
--- a/libavcodec/wma_freqs.h
+++ b/libavcodec/wma_freqs.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wmadata.h b/libavcodec/wmadata.h
index 58bffedd6e..641cb1813c 100644
--- a/libavcodec/wmadata.h
+++ b/libavcodec/wmadata.h
@@ -1,21 +1,21 @@
/*
* WMA compatible decoder
- * copyright (c) 2002 The Libav Project
+ * copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wmadec.c b/libavcodec/wmadec.c
index 8a907673de..d60cf1febb 100644
--- a/libavcodec/wmadec.c
+++ b/libavcodec/wmadec.c
@@ -1,21 +1,21 @@
/*
* WMA compatible decoder
- * Copyright (c) 2002 The Libav Project
+ * Copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,9 +39,6 @@
#include "internal.h"
#include "wma.h"
-#undef NDEBUG
-#include <assert.h>
-
#define EXPVLCBITS 8
#define EXPMAX ((19 + EXPVLCBITS - 1) / EXPVLCBITS)
@@ -94,6 +91,16 @@ static av_cold int wma_decode_init(AVCodecContext *avctx)
s->use_bit_reservoir = flags2 & 0x0002;
s->use_variable_block_len = flags2 & 0x0004;
+ if (avctx->codec->id == AV_CODEC_ID_WMAV2 && avctx->extradata_size >= 8){
+ if (AV_RL16(extradata+4)==0xd && s->use_variable_block_len){
+ av_log(avctx, AV_LOG_WARNING, "Disabling use_variable_block_len, if this fails contact the ffmpeg developers and send us the file\n");
+ s->use_variable_block_len= 0; // this fixes issue1503
+ }
+ }
+
+ for (i=0; i<MAX_CHANNELS; i++)
+ s->max_exponent[i] = 1.0;
+
if (ff_wma_init(avctx, flags2) < 0)
return -1;
@@ -380,14 +387,14 @@ static void wma_window(WMACodecContext *s, float *out)
block_len = s->block_len;
bsize = s->frame_len_bits - s->block_len_bits;
- s->fdsp.vector_fmul_add(out, in, s->windows[bsize],
+ s->fdsp->vector_fmul_add(out, in, s->windows[bsize],
out, block_len);
} else {
block_len = 1 << s->prev_block_len_bits;
n = (s->block_len - block_len) / 2;
bsize = s->frame_len_bits - s->prev_block_len_bits;
- s->fdsp.vector_fmul_add(out + n, in + n, s->windows[bsize],
+ s->fdsp->vector_fmul_add(out + n, in + n, s->windows[bsize],
out + n, block_len);
memcpy(out + n + block_len, in + n + block_len, n * sizeof(float));
@@ -401,7 +408,7 @@ static void wma_window(WMACodecContext *s, float *out)
block_len = s->block_len;
bsize = s->frame_len_bits - s->block_len_bits;
- s->fdsp.vector_fmul_reverse(out, in, s->windows[bsize], block_len);
+ s->fdsp->vector_fmul_reverse(out, in, s->windows[bsize], block_len);
} else {
block_len = 1 << s->next_block_len_bits;
n = (s->block_len - block_len) / 2;
@@ -409,7 +416,7 @@ static void wma_window(WMACodecContext *s, float *out)
memcpy(out, in, n * sizeof(float));
- s->fdsp.vector_fmul_reverse(out + n, in + n, s->windows[bsize],
+ s->fdsp->vector_fmul_reverse(out + n, in + n, s->windows[bsize],
block_len);
memset(out + n + block_len, 0, n * sizeof(float));
@@ -475,6 +482,11 @@ static int wma_decode_block(WMACodecContext *s)
s->block_len_bits = s->frame_len_bits;
}
+ if (s->frame_len_bits - s->block_len_bits >= s->nb_block_sizes){
+ av_log(s->avctx, AV_LOG_ERROR, "block_len_bits not initialized to a valid value\n");
+ return -1;
+ }
+
/* now check if the block length is coherent with the frame length */
s->block_len = 1 << s->block_len_bits;
if ((s->block_pos + s->block_len) > s->frame_len) {
@@ -502,6 +514,10 @@ static int wma_decode_block(WMACodecContext *s)
* coef escape coding */
total_gain = 1;
for (;;) {
+ if (get_bits_left(&s->gb) < 7) {
+ av_log(s->avctx, AV_LOG_ERROR, "total_gain overread\n");
+ return AVERROR_INVALIDDATA;
+ }
a = get_bits(&s->gb, 7);
total_gain += a;
if (a != 127)
@@ -681,7 +697,7 @@ static int wma_decode_block(WMACodecContext *s)
/* very high freqs : noise */
n = s->block_len - s->coefs_end[bsize];
- mult1 = mult * exponents[((-1 << bsize)) >> esize];
+ mult1 = mult * exponents[(-(1 << bsize)) >> esize];
for (i = 0; i < n; i++) {
*coefs++ = s->noise_table[s->noise_index] * mult1;
s->noise_index = (s->noise_index + 1) & (NOISE_TAB_SIZE - 1);
@@ -719,7 +735,7 @@ static int wma_decode_block(WMACodecContext *s)
s->channel_coded[0] = 1;
}
- s->fdsp.butterflies_float(s->coefs[0], s->coefs[1], s->block_len);
+ s->fdsp->butterflies_float(s->coefs[0], s->coefs[1], s->block_len);
}
next:
@@ -811,7 +827,8 @@ static int wma_decode_superframe(AVCodecContext *avctx, void *data,
buf_size, avctx->block_align);
return AVERROR_INVALIDDATA;
}
- buf_size = avctx->block_align;
+ if (avctx->block_align)
+ buf_size = avctx->block_align;
init_get_bits(&s->gb, buf, buf_size * 8);
@@ -819,15 +836,38 @@ static int wma_decode_superframe(AVCodecContext *avctx, void *data,
/* read super frame header */
skip_bits(&s->gb, 4); /* super frame index */
nb_frames = get_bits(&s->gb, 4) - (s->last_superframe_len <= 0);
+ if (nb_frames <= 0) {
+ int is_error = nb_frames < 0 || get_bits_left(&s->gb) <= 8;
+ av_log(avctx, is_error ? AV_LOG_ERROR : AV_LOG_WARNING,
+ "nb_frames is %d bits left %d\n",
+ nb_frames, get_bits_left(&s->gb));
+ if (is_error)
+ return AVERROR_INVALIDDATA;
+
+ if ((s->last_superframe_len + buf_size - 1) >
+ MAX_CODED_SUPERFRAME_SIZE)
+ goto fail;
+
+ q = s->last_superframe + s->last_superframe_len;
+ len = buf_size - 1;
+ while (len > 0) {
+ *q++ = get_bits (&s->gb, 8);
+ len --;
+ }
+ memset(q, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
+ s->last_superframe_len += 8*buf_size - 8;
+// s->reset_block_lengths = 1; //XXX is this needed ?
+ *got_frame_ptr = 0;
+ return buf_size;
+ }
} else
nb_frames = 1;
/* get output buffer */
frame->nb_samples = nb_frames * s->frame_len;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = (float **) frame->extended_data;
samples_offset = 0;
@@ -904,13 +944,13 @@ static int wma_decode_superframe(AVCodecContext *avctx, void *data,
samples_offset += s->frame_len;
}
- ff_dlog(s->avctx, "%d %d %d %d outbytes:%td eaten:%d\n",
+ ff_dlog(s->avctx, "%d %d %d %d outbytes:%"PTRDIFF_SPECIFIER" eaten:%d\n",
s->frame_len_bits, s->block_len_bits, s->frame_len, s->block_len,
(int8_t *) samples - (int8_t *) data, avctx->block_align);
*got_frame_ptr = 1;
- return avctx->block_align;
+ return buf_size;
fail:
/* when error, we reset the bit reservoir */
@@ -926,6 +966,7 @@ static av_cold void flush(AVCodecContext *avctx)
s->last_superframe_len = 0;
}
+#if CONFIG_WMAV1_DECODER
AVCodec ff_wmav1_decoder = {
.name = "wmav1",
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 1"),
@@ -940,7 +981,8 @@ AVCodec ff_wmav1_decoder = {
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
-
+#endif
+#if CONFIG_WMAV2_DECODER
AVCodec ff_wmav2_decoder = {
.name = "wmav2",
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 2"),
@@ -955,3 +997,4 @@ AVCodec ff_wmav2_decoder = {
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
+#endif
diff --git a/libavcodec/wmaenc.c b/libavcodec/wmaenc.c
index e801663d66..b922acdee8 100644
--- a/libavcodec/wmaenc.c
+++ b/libavcodec/wmaenc.c
@@ -2,20 +2,20 @@
* WMA compatible encoder
* Copyright (c) 2007 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,9 +24,7 @@
#include "avcodec.h"
#include "internal.h"
#include "wma.h"
-
-#undef NDEBUG
-#include <assert.h>
+#include "libavutil/avassert.h"
static av_cold int encode_init(AVCodecContext *avctx)
@@ -39,13 +37,13 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (avctx->channels > MAX_CHANNELS) {
av_log(avctx, AV_LOG_ERROR,
- "too many channels: got %i, need %i or fewer",
+ "too many channels: got %i, need %i or fewer\n",
avctx->channels, MAX_CHANNELS);
return AVERROR(EINVAL);
}
if (avctx->sample_rate > 48000) {
- av_log(avctx, AV_LOG_ERROR, "sample rate is too high: %d > 48kHz",
+ av_log(avctx, AV_LOG_ERROR, "sample rate is too high: %d > 48kHz\n",
avctx->sample_rate);
return AVERROR(EINVAL);
}
@@ -62,16 +60,20 @@ static av_cold int encode_init(AVCodecContext *avctx)
flags2 = 1;
if (avctx->codec->id == AV_CODEC_ID_WMAV1) {
extradata = av_malloc(4);
+ if (!extradata)
+ return AVERROR(ENOMEM);
avctx->extradata_size = 4;
AV_WL16(extradata, flags1);
AV_WL16(extradata + 2, flags2);
} else if (avctx->codec->id == AV_CODEC_ID_WMAV2) {
extradata = av_mallocz(10);
+ if (!extradata)
+ return AVERROR(ENOMEM);
avctx->extradata_size = 10;
AV_WL32(extradata, flags1);
AV_WL16(extradata + 4, flags2);
} else {
- assert(0);
+ av_assert0(0);
}
avctx->extradata = extradata;
s->use_exp_vlc = flags2 & 0x0001;
@@ -90,8 +92,6 @@ static av_cold int encode_init(AVCodecContext *avctx)
(avctx->sample_rate * 8);
block_align = FFMIN(block_align, MAX_CODED_SUPERFRAME_SIZE);
avctx->block_align = block_align;
- avctx->bit_rate = avctx->block_align * 8LL * avctx->sample_rate /
- s->frame_len;
avctx->frame_size = avctx->initial_padding = s->frame_len;
return 0;
@@ -111,10 +111,10 @@ static void apply_window_and_mdct(AVCodecContext *avctx, const AVFrame *frame)
for (ch = 0; ch < avctx->channels; ch++) {
memcpy(s->output, s->frame_out[ch], window_len * sizeof(*s->output));
- s->fdsp.vector_fmul_scalar(s->frame_out[ch], audio[ch], n, len);
- s->fdsp.vector_fmul_reverse(&s->output[window_len], s->frame_out[ch],
+ s->fdsp->vector_fmul_scalar(s->frame_out[ch], audio[ch], n, len);
+ s->fdsp->vector_fmul_reverse(&s->output[window_len], s->frame_out[ch],
win, len);
- s->fdsp.vector_fmul(s->frame_out[ch], s->frame_out[ch], win, len);
+ s->fdsp->vector_fmul(s->frame_out[ch], s->frame_out[ch], win, len);
mdct->mdct_calc(mdct, s->coefs[ch], s->output);
}
}
@@ -153,7 +153,7 @@ static void encode_exp_vlc(WMACodecContext *s, int ch, const int *exp_param)
q_end = q + s->block_len;
if (s->version == 1) {
last_exp = *exp_param++;
- assert(last_exp - 10 >= 0 && last_exp - 10 < 32);
+ av_assert0(last_exp - 10 >= 0 && last_exp - 10 < 32);
put_bits(&s->pb, 5, last_exp - 10);
q += *ptr++;
} else
@@ -161,7 +161,7 @@ static void encode_exp_vlc(WMACodecContext *s, int ch, const int *exp_param)
while (q < q_end) {
int exp = *exp_param++;
int code = exp - last_exp + 60;
- assert(code >= 0 && code < 120);
+ av_assert1(code >= 0 && code < 120);
put_bits(&s->pb, ff_aac_scalefactor_bits[code],
ff_aac_scalefactor_code[code]);
/* XXX: use a table */
@@ -186,7 +186,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
// FIXME remove duplication relative to decoder
if (s->use_variable_block_len) {
- assert(0); // FIXME not implemented
+ av_assert0(0); // FIXME not implemented
} else {
/* fixed block len */
s->next_block_len_bits = s->frame_len_bits;
@@ -195,7 +195,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
}
s->block_len = 1 << s->block_len_bits;
-// assert((s->block_pos + s->block_len) <= s->frame_len);
+// av_assert0((s->block_pos + s->block_len) <= s->frame_len);
bsize = s->frame_len_bits - s->block_len_bits;
// FIXME factor
@@ -231,7 +231,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
mult *= mdct_norm;
coefs = src_coefs[ch];
if (s->use_noise_coding && 0) {
- assert(0); // FIXME not implemented
+ av_assert0(0); // FIXME not implemented
} else {
coefs += s->coefs_start;
n = nb_coefs[ch];
@@ -286,13 +286,13 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
if (s->use_exp_vlc) {
encode_exp_vlc(s, ch, fixed_exp);
} else {
- assert(0); // FIXME not implemented
+ av_assert0(0); // FIXME not implemented
// encode_exp_lsp(s, ch);
}
}
}
} else
- assert(0); // FIXME not implemented
+ av_assert0(0); // FIXME not implemented
for (ch = 0; ch < s->avctx->channels; ch++) {
if (s->channel_coded[ch]) {
@@ -312,7 +312,7 @@ static int encode_block(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
if (run < s->coef_vlcs[tindex]->levels[abs_level - 1])
code = run + s->int_table[tindex][abs_level - 1];
- assert(code < s->coef_vlcs[tindex]->n);
+ av_assert2(code < s->coef_vlcs[tindex]->n);
put_bits(&s->pb, s->coef_vlcs[tindex]->huffbits[code],
s->coef_vlcs[tindex]->huffcodes[code]);
@@ -345,7 +345,7 @@ static int encode_frame(WMACodecContext *s, float (*src_coefs)[BLOCK_MAX_SIZE],
init_put_bits(&s->pb, buf, buf_size);
if (s->use_bit_reservoir)
- assert(0); // FIXME not implemented
+ av_assert0(0); // FIXME not implemented
else if (encode_block(s, src_coefs, total_gain) < 0)
return INT_MAX;
@@ -358,7 +358,7 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
WMACodecContext *s = avctx->priv_data;
- int i, total_gain, ret;
+ int i, total_gain, ret, error;
s->block_len_bits = s->frame_len_bits; // required by non variable block len
s->block_len = 1 << s->block_len_bits;
@@ -377,46 +377,32 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt,
}
}
- if ((ret = ff_alloc_packet(avpkt, 2 * MAX_CODED_SUPERFRAME_SIZE))) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
+ if ((ret = ff_alloc_packet2(avctx, avpkt, 2 * MAX_CODED_SUPERFRAME_SIZE)) < 0)
return ret;
- }
-#if 1
total_gain = 128;
for (i = 64; i; i >>= 1) {
- int error = encode_frame(s, s->coefs, avpkt->data, avpkt->size,
+ error = encode_frame(s, s->coefs, avpkt->data, avpkt->size,
total_gain - i);
- if (error < 0)
- total_gain -= i;
- }
-#else
- total_gain = 90;
- best = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain);
- for (i = 32; i; i >>= 1) {
- int scoreL = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain - i);
- int scoreR = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain + i);
- av_log(NULL, AV_LOG_ERROR, "%d %d %d (%d)\n", scoreL, best, scoreR, total_gain);
- if (scoreL < FFMIN(best, scoreR)) {
- best = scoreL;
+ if (error <= 0)
total_gain -= i;
- } else if (scoreR < best) {
- best = scoreR;
- total_gain += i;
- }
}
-#endif /* 1 */
- if ((i = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain)) >= 0) {
- av_log(avctx, AV_LOG_ERROR, "required frame size too large. please "
- "use a higher bit rate.\n");
+ while(total_gain <= 128 && error > 0)
+ error = encode_frame(s, s->coefs, avpkt->data, avpkt->size, total_gain++);
+ if (error > 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid input data or requested bitrate too low, cannot encode\n");
+ avpkt->size = 0;
return AVERROR(EINVAL);
}
- assert((put_bits_count(&s->pb) & 7) == 0);
- while (i++)
+ av_assert0((put_bits_count(&s->pb) & 7) == 0);
+ i= avctx->block_align - (put_bits_count(&s->pb)+7)/8;
+ av_assert0(i>=0);
+ while(i--)
put_bits(&s->pb, 8, 'N');
flush_put_bits(&s->pb);
+ av_assert0(put_bits_ptr(&s->pb) - s->pb.buf == avctx->block_align);
if (frame->pts != AV_NOPTS_VALUE)
avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding);
@@ -426,6 +412,7 @@ static int encode_superframe(AVCodecContext *avctx, AVPacket *avpkt,
return 0;
}
+#if CONFIG_WMAV1_ENCODER
AVCodec ff_wmav1_encoder = {
.name = "wmav1",
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 1"),
@@ -438,7 +425,8 @@ AVCodec ff_wmav1_encoder = {
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
-
+#endif
+#if CONFIG_WMAV2_ENCODER
AVCodec ff_wmav2_encoder = {
.name = "wmav2",
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 2"),
@@ -451,3 +439,4 @@ AVCodec ff_wmav2_encoder = {
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
};
+#endif
diff --git a/libavcodec/wmalosslessdec.c b/libavcodec/wmalosslessdec.c
index 2a2490431d..843ce90b3a 100644
--- a/libavcodec/wmalosslessdec.c
+++ b/libavcodec/wmalosslessdec.c
@@ -5,20 +5,20 @@
* Copyright (c) 2011 Andreas Ă–man
* Copyright (c) 2011 - 2012 Mashiat Sarker Shakkhar
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "internal.h"
#include "get_bits.h"
#include "put_bits.h"
+#include "lossless_audiodsp.h"
#include "wma.h"
#include "wma_common.h"
@@ -46,6 +47,7 @@
#define WMALL_BLOCK_MAX_SIZE (1 << WMALL_BLOCK_MAX_BITS) ///< maximum block size
#define WMALL_BLOCK_SIZES (WMALL_BLOCK_MAX_BITS - WMALL_BLOCK_MIN_BITS + 1) ///< possible block sizes
+#define WMALL_COEFF_PAD_SIZE 16 ///< pad coef buffers with 0 for use with SIMD
/**
* @brief frame-specific decoder context for a single channel
@@ -69,6 +71,7 @@ typedef struct WmallDecodeCtx {
/* generic decoder variables */
AVCodecContext *avctx;
AVFrame *frame;
+ LLAudDSPContext dsp; ///< accelerated DSP functions
uint8_t frame_data[MAX_FRAMESIZE + FF_INPUT_BUFFER_PADDING_SIZE]; ///< compressed frame data
PutBitContext pb; ///< context for filling the frame_data buffer
@@ -124,8 +127,8 @@ typedef struct WmallDecodeCtx {
int8_t acfilter_order;
int8_t acfilter_scaling;
- int64_t acfilter_coeffs[16];
- int acfilter_prevvalues[2][16];
+ int16_t acfilter_coeffs[16];
+ int acfilter_prevvalues[WMALL_MAX_CHANNELS][16];
int8_t mclms_order;
int8_t mclms_scaling;
@@ -143,35 +146,37 @@ typedef struct WmallDecodeCtx {
int scaling;
int coefsend;
int bitsend;
- int16_t coefs[MAX_ORDER];
- int16_t lms_prevvalues[MAX_ORDER * 2];
- int16_t lms_updates[MAX_ORDER * 2];
+ DECLARE_ALIGNED(16, int16_t, coefs)[MAX_ORDER + WMALL_COEFF_PAD_SIZE/sizeof(int16_t)];
+ DECLARE_ALIGNED(16, int16_t, lms_prevvalues)[MAX_ORDER * 2 + WMALL_COEFF_PAD_SIZE/sizeof(int16_t)];
+ DECLARE_ALIGNED(16, int16_t, lms_updates)[MAX_ORDER * 2 + WMALL_COEFF_PAD_SIZE/sizeof(int16_t)];
int recent;
- } cdlms[2][9];
+ } cdlms[WMALL_MAX_CHANNELS][9];
- int cdlms_ttl[2];
+ int cdlms_ttl[WMALL_MAX_CHANNELS];
int bV3RTM;
- int is_channel_coded[2];
- int update_speed[2];
+ int is_channel_coded[WMALL_MAX_CHANNELS];
+ int update_speed[WMALL_MAX_CHANNELS];
- int transient[2];
- int transient_pos[2];
+ int transient[WMALL_MAX_CHANNELS];
+ int transient_pos[WMALL_MAX_CHANNELS];
int seekable_tile;
- int ave_sum[2];
+ int ave_sum[WMALL_MAX_CHANNELS];
- int channel_residues[2][WMALL_BLOCK_MAX_SIZE];
+ int channel_residues[WMALL_MAX_CHANNELS][WMALL_BLOCK_MAX_SIZE];
- int lpc_coefs[2][40];
+ int lpc_coefs[WMALL_MAX_CHANNELS][40];
int lpc_order;
int lpc_scaling;
int lpc_intbits;
- int channel_coeffs[2][WMALL_BLOCK_MAX_SIZE];
+ int channel_coeffs[WMALL_MAX_CHANNELS][WMALL_BLOCK_MAX_SIZE];
} WmallDecodeCtx;
+/** Get sign of integer (1 for positive, -1 for negative and 0 for zero) */
+#define WMASIGN(x) (((x) > 0) - ((x) < 0))
static av_cold int decode_init(AVCodecContext *avctx)
{
@@ -180,7 +185,13 @@ static av_cold int decode_init(AVCodecContext *avctx)
unsigned int channel_mask;
int i, log2_max_num_subframes;
+ if (!avctx->block_align) {
+ av_log(avctx, AV_LOG_ERROR, "block_align is not set\n");
+ return AVERROR(EINVAL);
+ }
+
s->avctx = avctx;
+ ff_llauddsp_init(&s->dsp);
init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE);
if (avctx->extradata_size >= 18) {
@@ -191,8 +202,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
else if (s->bits_per_sample == 24) {
avctx->sample_fmt = AV_SAMPLE_FMT_S32P;
- avpriv_report_missing_feature(avctx, "Bit-depth higher than 16");
- return AVERROR_PATCHWELCOME;
+ avctx->bits_per_raw_sample = 24;
} else {
av_log(avctx, AV_LOG_ERROR, "Unknown bit-depth: %"PRIu8"\n",
s->bits_per_sample);
@@ -345,11 +355,11 @@ static int decode_tilehdr(WmallDecodeCtx *s)
if (num_samples[c] == min_channel_len) {
if (fixed_channel_layout || channels_for_cur_subframe == 1 ||
(min_channel_len == s->samples_per_frame - s->min_samples_per_subframe)) {
- contains_subframe[c] = in_use = 1;
+ contains_subframe[c] = 1;
} else {
- if (get_bits1(&s->gb))
- contains_subframe[c] = in_use = 1;
+ contains_subframe[c] = get_bits1(&s->gb);
}
+ in_use |= contains_subframe[c];
} else
contains_subframe[c] = 0;
}
@@ -454,6 +464,13 @@ static int decode_cdlms(WmallDecodeCtx *s)
s->cdlms[0][0].order = 0;
return AVERROR_INVALIDDATA;
}
+ if(s->cdlms[c][i].order & 8) {
+ static int warned;
+ if(!warned)
+ avpriv_request_sample(s->avctx, "CDLMS of order %d",
+ s->cdlms[c][i].order);
+ warned = 1;
+ }
}
for (i = 0; i < s->cdlms_ttl[c]; i++)
@@ -479,6 +496,10 @@ static int decode_cdlms(WmallDecodeCtx *s)
(get_bits(&s->gb, s->cdlms[c][i].bitsend) << shift_l) >> shift_r;
}
}
+
+ for (i = 0; i < s->cdlms_ttl[c]; i++)
+ memset(s->cdlms[c][i].coefs + s->cdlms[c][i].order,
+ 0, WMALL_COEFF_PAD_SIZE);
}
return 0;
@@ -505,9 +526,9 @@ static int decode_channel_residues(WmallDecodeCtx *s, int ch, int tile_size)
if (s->seekable_tile) {
if (s->do_inter_ch_decorr)
- s->channel_residues[ch][0] = get_sbits(&s->gb, s->bits_per_sample + 1);
+ s->channel_residues[ch][0] = get_sbits_long(&s->gb, s->bits_per_sample + 1);
else
- s->channel_residues[ch][0] = get_sbits(&s->gb, s->bits_per_sample);
+ s->channel_residues[ch][0] = get_sbits_long(&s->gb, s->bits_per_sample);
i++;
}
for (; i < tile_size; i++) {
@@ -525,17 +546,14 @@ static int decode_channel_residues(WmallDecodeCtx *s, int ch, int tile_size)
residue = quo;
else {
rem_bits = av_ceil_log2(ave_mean);
- rem = rem_bits ? get_bits_long(&s->gb, rem_bits) : 0;
+ rem = get_bits_long(&s->gb, rem_bits);
residue = (quo << rem_bits) + rem;
}
s->ave_sum[ch] = residue + s->ave_sum[ch] -
(s->ave_sum[ch] >> s->movave_scaling);
- if (residue & 1)
- residue = -(residue >> 1) - 1;
- else
- residue = residue >> 1;
+ residue = (residue >> 1) ^ -(residue & 1);
s->channel_residues[ch][i] = residue;
}
@@ -612,47 +630,31 @@ static void mclms_update(WmallDecodeCtx *s, int icoef, int *pred)
for (i = 0; i < order * num_channels; i++)
s->mclms_coeffs[i + ich * order * num_channels] +=
s->mclms_updates[s->mclms_recent + i];
- for (j = 0; j < ich; j++) {
- if (s->channel_residues[j][icoef] > 0)
- s->mclms_coeffs_cur[ich * num_channels + j] += 1;
- else if (s->channel_residues[j][icoef] < 0)
- s->mclms_coeffs_cur[ich * num_channels + j] -= 1;
- }
+ for (j = 0; j < ich; j++)
+ s->mclms_coeffs_cur[ich * num_channels + j] += WMASIGN(s->channel_residues[j][icoef]);
} else if (pred_error < 0) {
for (i = 0; i < order * num_channels; i++)
s->mclms_coeffs[i + ich * order * num_channels] -=
s->mclms_updates[s->mclms_recent + i];
- for (j = 0; j < ich; j++) {
- if (s->channel_residues[j][icoef] > 0)
- s->mclms_coeffs_cur[ich * num_channels + j] -= 1;
- else if (s->channel_residues[j][icoef] < 0)
- s->mclms_coeffs_cur[ich * num_channels + j] += 1;
- }
+ for (j = 0; j < ich; j++)
+ s->mclms_coeffs_cur[ich * num_channels + j] -= WMASIGN(s->channel_residues[j][icoef]);
}
}
for (ich = num_channels - 1; ich >= 0; ich--) {
s->mclms_recent--;
- s->mclms_prevvalues[s->mclms_recent] = s->channel_residues[ich][icoef];
- if (s->channel_residues[ich][icoef] > range - 1)
- s->mclms_prevvalues[s->mclms_recent] = range - 1;
- else if (s->channel_residues[ich][icoef] < -range)
- s->mclms_prevvalues[s->mclms_recent] = -range;
-
- s->mclms_updates[s->mclms_recent] = 0;
- if (s->channel_residues[ich][icoef] > 0)
- s->mclms_updates[s->mclms_recent] = 1;
- else if (s->channel_residues[ich][icoef] < 0)
- s->mclms_updates[s->mclms_recent] = -1;
+ s->mclms_prevvalues[s->mclms_recent] = av_clip(s->channel_residues[ich][icoef],
+ -range, range - 1);
+ s->mclms_updates[s->mclms_recent] = WMASIGN(s->channel_residues[ich][icoef]);
}
if (s->mclms_recent == 0) {
memcpy(&s->mclms_prevvalues[order * num_channels],
s->mclms_prevvalues,
- 2 * order * num_channels);
+ sizeof(int16_t) * order * num_channels);
memcpy(&s->mclms_updates[order * num_channels],
s->mclms_updates,
- 2 * order * num_channels);
+ sizeof(int16_t) * order * num_channels);
s->mclms_recent = num_channels * order;
}
}
@@ -688,58 +690,30 @@ static void revert_mclms(WmallDecodeCtx *s, int tile_size)
}
}
-static int lms_predict(WmallDecodeCtx *s, int ich, int ilms)
-{
- int pred = 0, icoef;
- int recent = s->cdlms[ich][ilms].recent;
-
- for (icoef = 0; icoef < s->cdlms[ich][ilms].order; icoef++)
- pred += s->cdlms[ich][ilms].coefs[icoef] *
- s->cdlms[ich][ilms].lms_prevvalues[icoef + recent];
-
- return pred;
-}
-
-static void lms_update(WmallDecodeCtx *s, int ich, int ilms,
- int input, int residue)
+static void lms_update(WmallDecodeCtx *s, int ich, int ilms, int input)
{
- int icoef;
int recent = s->cdlms[ich][ilms].recent;
int range = 1 << s->bits_per_sample - 1;
-
- if (residue < 0) {
- for (icoef = 0; icoef < s->cdlms[ich][ilms].order; icoef++)
- s->cdlms[ich][ilms].coefs[icoef] -=
- s->cdlms[ich][ilms].lms_updates[icoef + recent];
- } else if (residue > 0) {
- for (icoef = 0; icoef < s->cdlms[ich][ilms].order; icoef++)
- s->cdlms[ich][ilms].coefs[icoef] +=
- s->cdlms[ich][ilms].lms_updates[icoef + recent];
- }
+ int order = s->cdlms[ich][ilms].order;
if (recent)
recent--;
else {
- memcpy(&s->cdlms[ich][ilms].lms_prevvalues[s->cdlms[ich][ilms].order],
- s->cdlms[ich][ilms].lms_prevvalues,
- 2 * s->cdlms[ich][ilms].order);
- memcpy(&s->cdlms[ich][ilms].lms_updates[s->cdlms[ich][ilms].order],
- s->cdlms[ich][ilms].lms_updates,
- 2 * s->cdlms[ich][ilms].order);
- recent = s->cdlms[ich][ilms].order - 1;
+ memcpy(s->cdlms[ich][ilms].lms_prevvalues + order,
+ s->cdlms[ich][ilms].lms_prevvalues, sizeof(*s->cdlms[ich][ilms].lms_prevvalues) * order);
+ memcpy(s->cdlms[ich][ilms].lms_updates + order,
+ s->cdlms[ich][ilms].lms_updates, sizeof(*s->cdlms[ich][ilms].lms_updates) * order);
+ recent = order - 1;
}
s->cdlms[ich][ilms].lms_prevvalues[recent] = av_clip(input, -range, range - 1);
- if (!input)
- s->cdlms[ich][ilms].lms_updates[recent] = 0;
- else if (input < 0)
- s->cdlms[ich][ilms].lms_updates[recent] = -s->update_speed[ich];
- else
- s->cdlms[ich][ilms].lms_updates[recent] = s->update_speed[ich];
+ s->cdlms[ich][ilms].lms_updates[recent] = WMASIGN(input) * s->update_speed[ich];
- s->cdlms[ich][ilms].lms_updates[recent + (s->cdlms[ich][ilms].order >> 4)] >>= 2;
- s->cdlms[ich][ilms].lms_updates[recent + (s->cdlms[ich][ilms].order >> 3)] >>= 1;
+ s->cdlms[ich][ilms].lms_updates[recent + (order >> 4)] >>= 2;
+ s->cdlms[ich][ilms].lms_updates[recent + (order >> 3)] >>= 1;
s->cdlms[ich][ilms].recent = recent;
+ memset(s->cdlms[ich][ilms].lms_updates + recent + order, 0,
+ sizeof(s->cdlms[ich][ilms].lms_updates) - 2*(recent+order));
}
static void use_high_update_speed(WmallDecodeCtx *s, int ich)
@@ -787,12 +761,20 @@ static void revert_cdlms(WmallDecodeCtx *s, int ch,
for (icoef = coef_begin; icoef < coef_end; icoef++) {
pred = 1 << (s->cdlms[ch][ilms].scaling - 1);
residue = s->channel_residues[ch][icoef];
- pred += lms_predict(s, ch, ilms);
+ pred += s->dsp.scalarproduct_and_madd_int16(s->cdlms[ch][ilms].coefs,
+ s->cdlms[ch][ilms].lms_prevvalues
+ + s->cdlms[ch][ilms].recent,
+ s->cdlms[ch][ilms].lms_updates
+ + s->cdlms[ch][ilms].recent,
+ FFALIGN(s->cdlms[ch][ilms].order,
+ WMALL_COEFF_PAD_SIZE),
+ WMASIGN(residue));
input = residue + (pred >> s->cdlms[ch][ilms].scaling);
- lms_update(s, ch, ilms, input, residue);
+ lms_update(s, ch, ilms, input);
s->channel_residues[ch][icoef] = input;
}
}
+ emms_c();
}
static void revert_inter_ch_decorr(WmallDecodeCtx *s, int tile_size)
@@ -811,7 +793,7 @@ static void revert_inter_ch_decorr(WmallDecodeCtx *s, int tile_size)
static void revert_acfilter(WmallDecodeCtx *s, int tile_size)
{
int ich, pred, i, j;
- int64_t *filter_coeffs = s->acfilter_coeffs;
+ int16_t *filter_coeffs = s->acfilter_coeffs;
int scaling = s->acfilter_scaling;
int order = s->acfilter_order;
@@ -955,7 +937,7 @@ static int decode_subframe(WmallDecodeCtx *s)
bits * s->num_channels * subframe_len, get_bits_count(&s->gb));
for (i = 0; i < s->num_channels; i++)
for (j = 0; j < subframe_len; j++)
- s->channel_coeffs[i][j] = get_sbits(&s->gb, bits);
+ s->channel_coeffs[i][j] = get_sbits_long(&s->gb, bits);
} else {
for (i = 0; i < s->num_channels; i++)
if (s->is_channel_coded[i]) {
@@ -991,7 +973,7 @@ static int decode_subframe(WmallDecodeCtx *s)
if (s->bits_per_sample == 16) {
*s->samples_16[c]++ = (int16_t) s->channel_residues[c][j] << padding_zeroes;
} else {
- *s->samples_32[c]++ = s->channel_residues[c][j] << padding_zeroes;
+ *s->samples_32[c]++ = s->channel_residues[c][j] << (padding_zeroes + 8);
}
}
}
@@ -1022,8 +1004,6 @@ static int decode_frame(WmallDecodeCtx *s)
s->frame->nb_samples = s->samples_per_frame;
if ((ret = ff_get_buffer(s->avctx, s->frame, 0)) < 0) {
/* return an error if no frame could be decoded at all */
- av_log(s->avctx, AV_LOG_ERROR,
- "not enough space for the output samples\n");
s->packet_loss = 1;
return ret;
}
@@ -1037,9 +1017,10 @@ static int decode_frame(WmallDecodeCtx *s)
len = get_bits(gb, s->log2_frame_size);
/* decode tile information */
- if (decode_tilehdr(s)) {
+ if ((ret = decode_tilehdr(s))) {
s->packet_loss = 1;
- return 0;
+ av_frame_unref(s->frame);
+ return ret;
}
/* read drc info */
@@ -1074,16 +1055,18 @@ static int decode_frame(WmallDecodeCtx *s)
/* decode all subframes */
while (!s->parsed_all_subframes) {
+ int decoded_samples = s->channel[0].decoded_samples;
if (decode_subframe(s) < 0) {
s->packet_loss = 1;
+ if (s->frame->nb_samples)
+ s->frame->nb_samples = decoded_samples;
return 0;
}
}
ff_dlog(s->avctx, "Frame done\n");
- if (s->skip_frame)
- s->skip_frame = 0;
+ s->skip_frame = 0;
if (s->len_prefix) {
if (len != (get_bits_count(gb) - s->frame_offset) + 2) {
@@ -1182,9 +1165,13 @@ static int decode_packet(AVCodecContext *avctx, void *data, int *got_frame_ptr,
if (s->packet_done || s->packet_loss) {
s->packet_done = 0;
- /* sanity check for the buffer length */
- if (buf_size < avctx->block_align)
+ if (!buf_size)
return 0;
+ /* sanity check for the buffer length */
+ if (buf_size < avctx->block_align) {
+ av_log(avctx, AV_LOG_ERROR, "buf size %d invalid\n", buf_size);
+ return AVERROR_INVALIDDATA;
+ }
s->next_packet_start = buf_size - avctx->block_align;
buf_size = avctx->block_align;
diff --git a/libavcodec/wmaprodata.h b/libavcodec/wmaprodata.h
index f8a52bf4f4..53824799d5 100644
--- a/libavcodec/wmaprodata.h
+++ b/libavcodec/wmaprodata.h
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Baptiste Coudurier, Benjamin Larsson, Ulion
* Copyright (c) 2008 - 2009 Sascha Sommer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c
index 184ae99acb..c319b39836 100644
--- a/libavcodec/wmaprodec.c
+++ b/libavcodec/wmaprodec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Baptiste Coudurier, Benjamin Larsson, Ulion
* Copyright (c) 2008 - 2011 Sascha Sommer, Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -171,13 +171,13 @@ typedef struct WMAProChannelGrp {
typedef struct WMAProDecodeCtx {
/* generic decoder variables */
AVCodecContext* avctx; ///< codec context for av_log
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
uint8_t frame_data[MAX_FRAMESIZE +
FF_INPUT_BUFFER_PADDING_SIZE];///< compressed frame data
PutBitContext pb; ///< context for filling the frame_data buffer
FFTContext mdct_ctx[WMAPRO_BLOCK_SIZES]; ///< MDCT context per block size
DECLARE_ALIGNED(32, float, tmp)[WMAPRO_BLOCK_MAX_SIZE]; ///< IMDCT output buffer
- float* windows[WMAPRO_BLOCK_SIZES]; ///< windows for the different block sizes
+ const float* windows[WMAPRO_BLOCK_SIZES]; ///< windows for the different block sizes
/* frame size dependent frame information (set during initialization) */
uint32_t decode_flags; ///< used compression features
@@ -260,6 +260,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
WMAProDecodeCtx *s = avctx->priv_data;
int i;
+ av_freep(&s->fdsp);
+
for (i = 0; i < WMAPRO_BLOCK_SIZES; i++)
ff_mdct_end(&s->mdct_ctx[i]);
@@ -286,7 +288,9 @@ static av_cold int decode_init(AVCodecContext *avctx)
}
s->avctx = avctx;
- avpriv_float_dsp_init(&s->fdsp, avctx->flags & CODEC_FLAG_BITEXACT);
+ s->fdsp = avpriv_float_dsp_alloc(avctx->flags & CODEC_FLAG_BITEXACT);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE);
@@ -308,6 +312,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
/** generic init */
s->log2_frame_size = av_log2(avctx->block_align) + 4;
+ if (s->log2_frame_size > 25) {
+ avpriv_request_sample(avctx, "Large block align");
+ return AVERROR_PATCHWELCOME;
+ }
/** frame info */
s->skip_frame = 1; /* skip first frame */
@@ -340,8 +348,8 @@ static av_cold int decode_init(AVCodecContext *avctx)
}
if (s->min_samples_per_subframe < WMAPRO_BLOCK_MIN_SIZE) {
- av_log(avctx, AV_LOG_ERROR, "Invalid minimum block size %"PRId8"\n",
- s->max_num_subframes);
+ av_log(avctx, AV_LOG_ERROR, "min_samples_per_subframe of %d too small\n",
+ s->min_samples_per_subframe);
return AVERROR_INVALIDDATA;
}
@@ -418,9 +426,16 @@ static av_cold int decode_init(AVCodecContext *avctx)
offset &= ~3;
if (offset > s->sfb_offsets[i][band - 1])
s->sfb_offsets[i][band++] = offset;
+
+ if (offset >= subframe_len)
+ break;
}
s->sfb_offsets[i][band - 1] = subframe_len;
s->num_sfb[i] = band - 1;
+ if (s->num_sfb[i] <= 0) {
+ av_log(avctx, AV_LOG_ERROR, "num_sfb invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
}
@@ -437,9 +452,10 @@ static av_cold int decode_init(AVCodecContext *avctx)
+ s->sfb_offsets[i][b + 1] - 1) << i) >> 1;
for (x = 0; x < num_possible_block_sizes; x++) {
int v = 0;
- while (s->sfb_offsets[x][v + 1] << x < offset)
- if (++v >= MAX_BANDS)
- return AVERROR_INVALIDDATA;
+ while (s->sfb_offsets[x][v + 1] << x < offset) {
+ v++;
+ av_assert0(v < MAX_BANDS);
+ }
s->sf_offsets[i][x][b] = v;
}
}
@@ -493,6 +509,9 @@ static int decode_subframe_length(WMAProDecodeCtx *s, int offset)
if (offset == s->samples_per_frame - s->min_samples_per_subframe)
return s->min_samples_per_subframe;
+ if (get_bits_left(&s->gb) < 1)
+ return AVERROR_INVALIDDATA;
+
/** 1 bit indicates if the subframe is of maximum length */
if (s->max_subframe_len_bit) {
if (get_bits1(&s->gb))
@@ -671,7 +690,7 @@ static void decode_decorrelation_matrix(WMAProDecodeCtx *s,
/**
*@brief Decode channel transformation parameters
*@param s codec context
- *@return 0 in case of success, < 0 in case of bitstream errors
+ *@return >= 0 in case of success, < 0 in case of bitstream errors
*/
static int decode_channel_transform(WMAProDecodeCtx* s)
{
@@ -1022,10 +1041,10 @@ static void inverse_channel_transform(WMAProDecodeCtx *s)
}
} else if (s->avctx->channels == 2) {
int len = FFMIN(sfb[1], s->subframe_len) - sfb[0];
- s->fdsp.vector_fmul_scalar(ch_data[0] + sfb[0],
+ s->fdsp->vector_fmul_scalar(ch_data[0] + sfb[0],
ch_data[0] + sfb[0],
181.0 / 128, len);
- s->fdsp.vector_fmul_scalar(ch_data[1] + sfb[0],
+ s->fdsp->vector_fmul_scalar(ch_data[1] + sfb[0],
ch_data[1] + sfb[0],
181.0 / 128, len);
}
@@ -1043,7 +1062,7 @@ static void wmapro_window(WMAProDecodeCtx *s)
int i;
for (i = 0; i < s->channels_for_cur_subframe; i++) {
int c = s->channel_indexes_for_cur_subframe[i];
- float* window;
+ const float* window;
int winlen = s->channel[c].prev_block_len;
float* start = s->channel[c].coeffs - (winlen >> 1);
@@ -1056,7 +1075,7 @@ static void wmapro_window(WMAProDecodeCtx *s)
winlen >>= 1;
- s->fdsp.vector_fmul_window(start, start, start + winlen,
+ s->fdsp->vector_fmul_window(start, start, start + winlen,
window, winlen);
s->channel[c].prev_block_len = s->subframe_len;
@@ -1145,7 +1164,7 @@ static int decode_subframe(WMAProDecodeCtx *s)
int num_fill_bits;
if (!(num_fill_bits = get_bits(&s->gb, 2))) {
int len = get_bits(&s->gb, 4);
- num_fill_bits = get_bits(&s->gb, len) + 1;
+ num_fill_bits = (len ? get_bits(&s->gb, len) : 0) + 1;
}
if (num_fill_bits >= 0) {
@@ -1175,6 +1194,7 @@ static int decode_subframe(WMAProDecodeCtx *s)
transmit_coeffs = 1;
}
+ av_assert0(s->subframe_len <= WMAPRO_BLOCK_MAX_SIZE);
if (transmit_coeffs) {
int step;
int quant_step = 90 * s->bits_per_sample >> 4;
@@ -1185,10 +1205,11 @@ static int decode_subframe(WMAProDecodeCtx *s)
for (i = 0; i < s->channels_for_cur_subframe; i++) {
int c = s->channel_indexes_for_cur_subframe[i];
int num_vec_coeffs = get_bits(&s->gb, num_bits) << 2;
- if (num_vec_coeffs + offset > FF_ARRAY_ELEMS(s->channel[c].out)) {
+ if (num_vec_coeffs > s->subframe_len) {
av_log(s->avctx, AV_LOG_ERROR, "num_vec_coeffs %d is too large\n", num_vec_coeffs);
return AVERROR_INVALIDDATA;
}
+ av_assert0(num_vec_coeffs + offset <= FF_ARRAY_ELEMS(s->channel[c].out));
s->channel[c].num_vec_coeffs = num_vec_coeffs;
}
} else {
@@ -1274,7 +1295,7 @@ static int decode_subframe(WMAProDecodeCtx *s)
s->channel[c].scale_factor_step;
const float quant = pow(10.0, exp / 20.0);
int start = s->cur_sfb_offsets[b];
- s->fdsp.vector_fmul_scalar(s->tmp + start,
+ s->fdsp->vector_fmul_scalar(s->tmp + start,
s->channel[c].coeffs + start,
quant, end - start);
}
@@ -1381,7 +1402,6 @@ static int decode_frame(WMAProDecodeCtx *s, AVFrame *frame, int *got_frame_ptr)
/* get output buffer */
frame->nb_samples = s->samples_per_frame;
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
s->packet_loss = 1;
return 0;
}
@@ -1455,7 +1475,7 @@ static void save_bits(WMAProDecodeCtx *s, GetBitContext* gb, int len,
int buflen;
/** when the frame data does not need to be concatenated, the input buffer
- is resetted and additional bits from the previous frame are copyed
+ is reset and additional bits from the previous frame are copied
and skipped later so that a fast byte copy is possible */
if (!append) {
@@ -1464,7 +1484,7 @@ static void save_bits(WMAProDecodeCtx *s, GetBitContext* gb, int len,
init_put_bits(&s->pb, s->frame_data, MAX_FRAMESIZE);
}
- buflen = (s->num_saved_bits + len + 8) >> 3;
+ buflen = (put_bits_count(&s->pb) + len + 8) >> 3;
if (len <= 0 || buflen > MAX_FRAMESIZE) {
avpriv_request_sample(s->avctx, "Too small input buffer");
@@ -1472,13 +1492,7 @@ static void save_bits(WMAProDecodeCtx *s, GetBitContext* gb, int len,
return;
}
- if (len > put_bits_left(&s->pb)) {
- av_log(s->avctx, AV_LOG_ERROR,
- "Cannot append %d bits, only %d bits available.\n",
- len, put_bits_left(&s->pb));
- s->packet_loss = 1;
- return;
- }
+ av_assert0(len <= put_bits_left(&s->pb));
s->num_saved_bits += len;
if (!append) {
@@ -1593,7 +1607,8 @@ static int decode_packet(AVCodecContext *avctx, void *data,
(frame_size = show_bits(gb, s->log2_frame_size)) &&
frame_size <= remaining_bits(s, gb)) {
save_bits(s, gb, frame_size, 0);
- s->packet_done = !decode_frame(s, data, got_frame_ptr);
+ if (!s->packet_loss)
+ s->packet_done = !decode_frame(s, data, got_frame_ptr);
} else if (!s->len_prefix
&& s->num_saved_bits > get_bits_count(&s->gb)) {
/** when the frames do not have a length prefix, we don't know
diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c
index e408166c48..ae88d4ec80 100644
--- a/libavcodec/wmavoice.c
+++ b/libavcodec/wmavoice.c
@@ -2,20 +2,20 @@
* Windows Media Audio Voice decoder.
* Copyright (c) 2009 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,8 +25,6 @@
* @author Ronald S. Bultje <rsbultje@gmail.com>
*/
-#define UNCHECKED_BITSTREAM_READER 1
-
#include <math.h>
#include "libavutil/channel_layout.h"
@@ -520,7 +518,7 @@ static int kalman_smoothen(WMAVoiceContext *s, int pitch,
float optimal_gain = 0, dot;
const float *ptr = &in[-FFMAX(s->min_pitch_val, pitch - 3)],
*end = &in[-FFMIN(s->max_pitch_val, pitch + 3)],
- *best_hist_ptr;
+ *best_hist_ptr = NULL;
/* find best fitting point in history */
do {
@@ -780,7 +778,7 @@ static void postfilter(WMAVoiceContext *s, const float *synth,
*synth_pf = &s->synth_filter_out_buf[MAX_LSPS_ALIGN16],
*synth_filter_in = zero_exc_pf;
- assert(size <= MAX_FRAMESIZE / 2);
+ av_assert0(size <= MAX_FRAMESIZE / 2);
/* generate excitation from input signal */
ff_celp_lp_zero_synthesis_filterf(zero_exc_pf, lpcs, synth, size, s->lsps);
@@ -1249,7 +1247,7 @@ static void synth_block_hardcoded(WMAVoiceContext *s, GetBitContext *gb,
float gain;
int n, r_idx;
- assert(size <= MAX_FRAMESIZE);
+ av_assert0(size <= MAX_FRAMESIZE);
/* Set the offset from which we start reading wmavoice_std_codebook */
if (frame_desc->fcb_type == FCB_TYPE_SILENCE) {
@@ -1285,7 +1283,7 @@ static void synth_block_fcb_acb(WMAVoiceContext *s, GetBitContext *gb,
int n, idx, gain_weight;
AMRFixed fcb;
- assert(size <= MAX_FRAMESIZE / 2);
+ av_assert0(size <= MAX_FRAMESIZE / 2);
memset(pulses, 0, sizeof(*pulses) * size);
fcb.pitch_lag = block_pitch_sh2 >> 2;
@@ -1456,8 +1454,8 @@ static int synth_frame(AVCodecContext *ctx, GetBitContext *gb, int frame_idx,
float *excitation, float *synth)
{
WMAVoiceContext *s = ctx->priv_data;
- int n, n_blocks_x2, log_n_blocks_x2, cur_pitch_val;
- int pitch[MAX_BLOCKS], last_block_pitch;
+ int n, n_blocks_x2, log_n_blocks_x2, av_uninit(cur_pitch_val);
+ int pitch[MAX_BLOCKS], av_uninit(last_block_pitch);
/* Parse frame type ("frame header"), see frame_descs */
int bd_idx = s->vbm_tree[get_vlc2(gb, frame_type_vlc.table, 6, 3)], block_nsamples;
@@ -1674,7 +1672,7 @@ static int check_bits_for_superframe(GetBitContext *orig_gb,
/* initialize a copy */
init_get_bits(gb, orig_gb->buffer, orig_gb->size_in_bits);
skip_bits_long(gb, get_bits_count(orig_gb));
- assert(get_bits_left(gb) == get_bits_left(orig_gb));
+ av_assert1(get_bits_left(gb) == get_bits_left(orig_gb));
/* superframe header */
if (get_bits_left(gb) < 14)
@@ -1820,10 +1818,8 @@ static int synth_superframe(AVCodecContext *ctx, AVFrame *frame,
/* get output buffer */
frame->nb_samples = 480;
- if ((res = ff_get_buffer(ctx, frame, 0)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((res = ff_get_buffer(ctx, frame, 0)) < 0)
return res;
- }
frame->nb_samples = n_samples;
samples = (float *)frame->data[0];
@@ -1955,7 +1951,7 @@ static int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
int size, res, pos;
/* Packets are sometimes a multiple of ctx->block_align, with a packet
- * header at each ctx->block_align bytes. However, Libav's ASF demuxer
+ * header at each ctx->block_align bytes. However, FFmpeg's ASF demuxer
* feeds us ASF packets, which may concatenate multiple "codec" packets
* in a single "muxer" packet, so we artificially emulate that by
* capping the packet size at ctx->block_align. */
@@ -2010,7 +2006,7 @@ static int wmavoice_decode_packet(AVCodecContext *ctx, void *data,
/* rewind bit reader to start of last (incomplete) superframe... */
init_get_bits(gb, avpkt->data, size << 3);
skip_bits_long(gb, (size << 3) - pos);
- assert(get_bits_left(gb) == pos);
+ av_assert1(get_bits_left(gb) == pos);
/* ...and cache it for spillover in next packet */
init_put_bits(&s->pb, s->sframe_cache, SFRAME_CACHE_MAXSIZE);
diff --git a/libavcodec/wmavoice_data.h b/libavcodec/wmavoice_data.h
index 7f14fb8350..cbf65b043e 100644
--- a/libavcodec/wmavoice_data.h
+++ b/libavcodec/wmavoice_data.h
@@ -2,20 +2,20 @@
* Windows Media Voice (WMAVoice) tables.
* Copyright (c) 2009 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wmv2.c b/libavcodec/wmv2.c
index 313906c0d2..1cfb7eb0e4 100644
--- a/libavcodec/wmv2.c
+++ b/libavcodec/wmv2.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2002 The Libav Project
+ * Copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -102,8 +102,8 @@ void ff_mspel_motion(MpegEncContext *s, uint8_t *dest_y,
{
Wmv2Context *const w = (Wmv2Context *) s;
uint8_t *ptr;
- int dxy, offset, mx, my, src_x, src_y, v_edge_pos;
- ptrdiff_t linesize, uvlinesize;
+ int dxy, mx, my, src_x, src_y, v_edge_pos;
+ ptrdiff_t offset, linesize, uvlinesize;
int emu = 0;
dxy = ((motion_y & 1) << 1) | (motion_x & 1);
@@ -143,21 +143,13 @@ void ff_mspel_motion(MpegEncContext *s, uint8_t *dest_y,
if (s->avctx->flags & CODEC_FLAG_GRAY)
return;
- if (s->out_format == FMT_H263) {
- dxy = 0;
- if ((motion_x & 3) != 0)
- dxy |= 1;
- if ((motion_y & 3) != 0)
- dxy |= 2;
- mx = motion_x >> 2;
- my = motion_y >> 2;
- } else {
- mx = motion_x / 2;
- my = motion_y / 2;
- dxy = ((my & 1) << 1) | (mx & 1);
- mx >>= 1;
- my >>= 1;
- }
+ dxy = 0;
+ if ((motion_x & 3) != 0)
+ dxy |= 1;
+ if ((motion_y & 3) != 0)
+ dxy |= 2;
+ mx = motion_x >> 2;
+ my = motion_y >> 2;
src_x = s->mb_x * 8 + mx;
src_y = s->mb_y * 8 + my;
diff --git a/libavcodec/wmv2.h b/libavcodec/wmv2.h
index 03a85147ad..4fa5e9bcec 100644
--- a/libavcodec/wmv2.h
+++ b/libavcodec/wmv2.h
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2002 The Libav Project
+ * Copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,4 +56,15 @@ typedef struct Wmv2Context {
void ff_wmv2_common_init(Wmv2Context *w);
+static av_always_inline int wmv2_get_cbp_table_index(MpegEncContext *s, int cbp_index)
+{
+ static const uint8_t map[3][3] = {
+ { 0, 2, 1 },
+ { 1, 0, 2 },
+ { 2, 1, 0 },
+ };
+
+ return map[(s->qscale > 10) + (s->qscale > 20)][cbp_index];
+}
+
#endif /* AVCODEC_WMV2_H */
diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c
index 6455f2f2ab..d2b9b13053 100644
--- a/libavcodec/wmv2dec.c
+++ b/libavcodec/wmv2dec.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2002 The Libav Project
+ * Copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -174,16 +174,7 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s)
parse_mb_skip(w);
cbp_index = decode012(&s->gb);
- if (s->qscale <= 10) {
- int map[3] = { 0, 2, 1 };
- w->cbp_table_index = map[cbp_index];
- } else if (s->qscale <= 20) {
- int map[3] = { 1, 0, 2 };
- w->cbp_table_index = map[cbp_index];
- } else {
- int map[3] = {2,1,0};
- w->cbp_table_index = map[cbp_index];
- }
+ w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index);
if (w->mspel_bit)
s->mspel = get_bits1(&s->gb);
@@ -462,6 +453,8 @@ static av_cold int wmv2_decode_init(AVCodecContext *avctx)
Wmv2Context *const w = avctx->priv_data;
int ret;
+ avctx->flags |= CODEC_FLAG_EMU_EDGE;
+
if ((ret = ff_msmpeg4_decode_init(avctx)) < 0)
return ret;
diff --git a/libavcodec/wmv2dsp.c b/libavcodec/wmv2dsp.c
index 2e3a3ff552..40e0bef0da 100644
--- a/libavcodec/wmv2dsp.c
+++ b/libavcodec/wmv2dsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wmv2dsp.h b/libavcodec/wmv2dsp.h
index f2f258ed34..0bf9489b07 100644
--- a/libavcodec/wmv2dsp.h
+++ b/libavcodec/wmv2dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/wmv2enc.c b/libavcodec/wmv2enc.c
index e4e51d32f9..55ee089ed0 100644
--- a/libavcodec/wmv2enc.c
+++ b/libavcodec/wmv2enc.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2002 The Libav Project
+ * Copyright (c) 2002 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -62,7 +62,9 @@ static av_cold int wmv2_encode_init(AVCodecContext *avctx)
ff_wmv2_common_init(w);
avctx->extradata_size = 4;
- avctx->extradata = av_mallocz(avctx->extradata_size + 10);
+ avctx->extradata = av_mallocz(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
encode_ext_header(w);
return 0;
@@ -85,10 +87,10 @@ int ff_wmv2_encode_picture_header(MpegEncContext *s, int picture_number)
w->abt_type = 0;
w->j_type = 0;
- assert(s->flipflop_rounding);
+ av_assert0(s->flipflop_rounding);
if (s->pict_type == AV_PICTURE_TYPE_I) {
- assert(s->no_rounding == 1);
+ av_assert0(s->no_rounding == 1);
if (w->j_type_bit)
put_bits(&s->pb, 1, w->j_type);
@@ -109,16 +111,7 @@ int ff_wmv2_encode_picture_header(MpegEncContext *s, int picture_number)
put_bits(&s->pb, 2, SKIP_TYPE_NONE);
ff_msmpeg4_code012(&s->pb, cbp_index = 0);
- if (s->qscale <= 10) {
- int map[3] = { 0, 2, 1 };
- w->cbp_table_index = map[cbp_index];
- } else if (s->qscale <= 20) {
- int map[3] = { 1, 0, 2 };
- w->cbp_table_index = map[cbp_index];
- } else {
- int map[3] = { 2, 1, 0 };
- w->cbp_table_index = map[cbp_index];
- }
+ w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index);
if (w->mspel_bit)
put_bits(&s->pb, 1, s->mspel);
@@ -171,10 +164,12 @@ void ff_wmv2_encode_mb(MpegEncContext *s, int16_t block[6][64],
ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][1],
ff_wmv2_inter_table[w->cbp_table_index][cbp + 64][0]);
+ s->misc_bits += get_bits_diff(s);
/* motion vector */
ff_h263_pred_motion(s, 0, 0, &pred_x, &pred_y);
ff_msmpeg4_encode_motion(s, motion_x - pred_x,
motion_y - pred_y);
+ s->mv_bits += get_bits_diff(s);
} else {
/* compute cbp */
cbp = 0;
@@ -207,12 +202,19 @@ void ff_wmv2_encode_mb(MpegEncContext *s, int16_t block[6][64],
ff_table_inter_intra[s->h263_aic_dir][1],
ff_table_inter_intra[s->h263_aic_dir][0]);
}
+ s->misc_bits += get_bits_diff(s);
}
for (i = 0; i < 6; i++)
ff_msmpeg4_encode_block(s, block[i], i);
+ if (s->mb_intra)
+ s->i_tex_bits += get_bits_diff(s);
+ else
+ s->p_tex_bits += get_bits_diff(s);
}
+FF_MPV_GENERIC_CLASS(wmv2)
+
AVCodec ff_wmv2_encoder = {
.name = "wmv2",
.long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 8"),
@@ -224,4 +226,5 @@ AVCodec ff_wmv2_encoder = {
.close = ff_mpv_encode_end,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P,
AV_PIX_FMT_NONE },
+ .priv_class = &wmv2_class,
};
diff --git a/libavcodec/wnv1.c b/libavcodec/wnv1.c
index 7676c89080..fb9e9cfeef 100644
--- a/libavcodec/wnv1.c
+++ b/libavcodec/wnv1.c
@@ -2,20 +2,20 @@
* Winnov WNV1 codec
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,8 +31,6 @@
typedef struct WNV1Context {
- AVCodecContext *avctx;
-
int shift;
GetBitContext gb;
} WNV1Context;
@@ -70,8 +68,8 @@ static int decode_frame(AVCodecContext *avctx,
int prev_y = 0, prev_u = 0, prev_v = 0;
uint8_t *rbuf;
- if (buf_size < 8) {
- av_log(avctx, AV_LOG_ERROR, "Packet is too short\n");
+ if (buf_size <= 8) {
+ av_log(avctx, AV_LOG_ERROR, "Packet size %d is too small\n", buf_size);
return AVERROR_INVALIDDATA;
}
@@ -80,9 +78,9 @@ static int decode_frame(AVCodecContext *avctx,
av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n");
return AVERROR(ENOMEM);
}
+ memset(rbuf + buf_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
av_free(rbuf);
return ret;
}
@@ -90,7 +88,9 @@ static int decode_frame(AVCodecContext *avctx,
for (i = 8; i < buf_size; i++)
rbuf[i] = ff_reverse[buf[i]];
- init_get_bits(&l->gb, rbuf + 8, (buf_size - 8) * 8);
+
+ if ((ret = init_get_bits8(&l->gb, rbuf + 8, buf_size - 8)) < 0)
+ return ret;
if (buf[2] >> 4 == 6)
l->shift = 2;
@@ -134,10 +134,8 @@ static int decode_frame(AVCodecContext *avctx,
static av_cold int decode_init(AVCodecContext *avctx)
{
- WNV1Context * const l = avctx->priv_data;
static VLC_TYPE code_table[1 << CODE_VLC_BITS][2];
- l->avctx = avctx;
avctx->pix_fmt = AV_PIX_FMT_YUV422P;
code_vlc.table = code_table;
diff --git a/libavcodec/ws-snd1.c b/libavcodec/ws-snd1.c
index fe6f8120e6..6929cbf5e5 100644
--- a/libavcodec/ws-snd1.c
+++ b/libavcodec/ws-snd1.c
@@ -2,20 +2,20 @@
* Westwood SNDx codecs
* Copyright (c) 2005 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -76,15 +76,13 @@ static int ws_snd_decode_frame(AVCodecContext *avctx, void *data,
if (in_size > buf_size) {
av_log(avctx, AV_LOG_ERROR, "Frame data is larger than input buffer\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
/* get output buffer */
frame->nb_samples = out_size;
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
return ret;
- }
samples = frame->data[0];
samples_end = samples + out_size;
diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile
index 09bb6a2fe1..87985f279b 100644
--- a/libavcodec/x86/Makefile
+++ b/libavcodec/x86/Makefile
@@ -3,11 +3,13 @@ OBJS += x86/constants.o \
# subsystems
OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp_init.o
OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp_init.o
-OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp.o
+OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp_init.o
OBJS-$(CONFIG_BSWAPDSP) += x86/bswapdsp_init.o
OBJS-$(CONFIG_DCT) += x86/dct_init.o
OBJS-$(CONFIG_FDCTDSP) += x86/fdctdsp_init.o
OBJS-$(CONFIG_FFT) += x86/fft_init.o
+OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp_init.o
+OBJS-$(CONFIG_FLAC_ENCODER) += x86/flacdsp_init.o
OBJS-$(CONFIG_FMTCONVERT) += x86/fmtconvert_init.o
OBJS-$(CONFIG_H263DSP) += x86/h263dsp_init.o
OBJS-$(CONFIG_H264CHROMA) += x86/h264chroma_init.o
@@ -15,6 +17,8 @@ OBJS-$(CONFIG_H264DSP) += x86/h264dsp_init.o
OBJS-$(CONFIG_H264PRED) += x86/h264_intrapred_init.o
OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel.o
OBJS-$(CONFIG_HPELDSP) += x86/hpeldsp_init.o
+OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp_init.o
+OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp_init.o
OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp_init.o
OBJS-$(CONFIG_HUFFYUVENCDSP) += x86/huffyuvencdsp_mmx.o
OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp_init.o
@@ -33,20 +37,25 @@ OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
# decoders/encoders
OBJS-$(CONFIG_AAC_DECODER) += x86/sbrdsp_init.o
-OBJS-$(CONFIG_APE_DECODER) += x86/apedsp_init.o
+OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp_init.o
+OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp_init.o
+OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp_init.o
OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsdsp.o
OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp_init.o
OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc_init.o
OBJS-$(CONFIG_HEVC_DECODER) += x86/hevcdsp_init.o
-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o
+OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp_init.o
OBJS-$(CONFIG_MPEG4_DECODER) += 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_RV30_DECODER) += x86/rv34dsp_init.o
OBJS-$(CONFIG_RV40_DECODER) += x86/rv34dsp_init.o \
x86/rv40dsp_init.o
-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o
-OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp.o
+OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc_init.o
+OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp_init.o
+OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp_init.o
+OBJS-$(CONFIG_V210_DECODER) += x86/v210-init.o
OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc_init.o
OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp_init.o
OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o
@@ -54,21 +63,18 @@ OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp_init.o
OBJS-$(CONFIG_VP7_DECODER) += x86/vp8dsp_init.o
OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp_init.o
OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp_init.o
+OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp_init.o
# GCC inline assembly optimizations
# subsystems
-MMX-OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp_mmx.o
-MMX-OBJS-$(CONFIG_HPELDSP) += x86/fpel_mmx.o \
- x86/hpeldsp_mmx.o
+MMX-OBJS-$(CONFIG_DIRAC_DECODER) += x86/dirac_dwt.o
MMX-OBJS-$(CONFIG_FDCTDSP) += x86/fdct.o
-MMX-OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp_mmx.o \
- x86/simple_idct.o
-MMX-OBJS-$(CONFIG_QPELDSP) += x86/fpel_mmx.o
+MMX-OBJS-$(CONFIG_IDCTDSP) += x86/simple_idct.o
# decoders/encoders
-MMX-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct_mmx.o \
- x86/xvididct_sse2.o
+MMX-OBJS-$(CONFIG_SNOW_DECODER) += x86/snowdsp.o
+MMX-OBJS-$(CONFIG_SNOW_ENCODER) += x86/snowdsp.o
MMX-OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp_mmx.o
@@ -78,10 +84,17 @@ YASM-OBJS += x86/deinterlace.o \
# subsystems
YASM-OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp.o
YASM-OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp.o
+YASM-OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp.o
YASM-OBJS-$(CONFIG_BSWAPDSP) += x86/bswapdsp.o
YASM-OBJS-$(CONFIG_DCT) += x86/dct32.o
+YASM-OBJS-$(CONFIG_DIRAC_DECODER) += x86/diracdsp_mmx.o x86/diracdsp_yasm.o\
+ x86/dwt_yasm.o
YASM-OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc.o
YASM-OBJS-$(CONFIG_FFT) += x86/fft.o
+YASM-OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp.o
+ifdef CONFIG_GPL
+YASM-OBJS-$(CONFIG_FLAC_ENCODER) += x86/flac_dsp_gpl.o
+endif
YASM-OBJS-$(CONFIG_FMTCONVERT) += x86/fmtconvert.o
YASM-OBJS-$(CONFIG_H263DSP) += x86/h263_loopfilter.o
YASM-OBJS-$(CONFIG_H264CHROMA) += x86/h264_chromamc.o \
@@ -101,6 +114,9 @@ YASM-OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel_8bit.o \
YASM-OBJS-$(CONFIG_HPELDSP) += x86/fpel.o \
x86/hpeldsp.o
YASM-OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp.o
+YASM-OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp.o
+YASM-OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp.o
+YASM-OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp.o
YASM-OBJS-$(CONFIG_ME_CMP) += x86/me_cmp.o
YASM-OBJS-$(CONFIG_MPEGAUDIODSP) += x86/imdct36.o
YASM-OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoencdsp.o
@@ -108,20 +124,33 @@ YASM-OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp.o
YASM-OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp.o \
x86/fpel.o \
x86/qpel.o
-YASM-OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc.o
YASM-OBJS-$(CONFIG_VIDEODSP) += x86/videodsp.o
YASM-OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp.o
# decoders/encoders
YASM-OBJS-$(CONFIG_AAC_DECODER) += x86/sbrdsp.o
-YASM-OBJS-$(CONFIG_APE_DECODER) += x86/apedsp.o
+YASM-OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp.o
+YASM-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp.o
+YASM-OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp.o
YASM-OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp.o
-YASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_deblock.o
+YASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_mc.o \
+ x86/hevc_deblock.o \
+ x86/hevc_idct.o \
+ x86/hevc_res_add.o \
+ x86/hevc_sao.o
+YASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o
+YASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o
YASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o
YASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o
+YASM-OBJS-$(CONFIG_PRORES_LGPL_DECODER) += x86/proresdsp.o
YASM-OBJS-$(CONFIG_RV30_DECODER) += x86/rv34dsp.o
YASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv34dsp.o \
x86/rv40dsp.o
+YASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o
+YASM-OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp.o
+YASM-OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp.o
+YASM-OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc.o
+YASM-OBJS-$(CONFIG_V210_DECODER) += x86/v210.o
YASM-OBJS-$(CONFIG_VC1_DECODER) += x86/vc1dsp.o
YASM-OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp.o
YASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp.o
@@ -129,4 +158,8 @@ YASM-OBJS-$(CONFIG_VP7_DECODER) += x86/vp8dsp.o \
x86/vp8dsp_loopfilter.o
YASM-OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp.o \
x86/vp8dsp_loopfilter.o
-YASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp.o
+YASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9intrapred.o \
+ x86/vp9itxfm.o \
+ x86/vp9lpf.o \
+ x86/vp9mc.o
+YASM-OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp.o
diff --git a/libavcodec/x86/ac3dsp.asm b/libavcodec/x86/ac3dsp.asm
index 817d5a319c..675ade3101 100644
--- a/libavcodec/x86/ac3dsp.asm
+++ b/libavcodec/x86/ac3dsp.asm
@@ -2,20 +2,20 @@
;* x86-optimized AC-3 DSP functions
;* Copyright (c) 2011 Justin Ruggles
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -32,7 +32,7 @@ pw_bap_mul1: dw 21846, 21846, 0, 32768, 21846, 21846, 0, 32768
pw_bap_mul2: dw 5, 7, 0, 7, 5, 7, 0, 7
; used in ff_ac3_extract_exponents()
-pd_1: times 4 dd 1
+cextern pd_1
pd_151: times 4 dd 151
; used in ff_apply_window_int16()
diff --git a/libavcodec/x86/ac3dsp_init.c b/libavcodec/x86/ac3dsp_init.c
index cd638b9228..eea2736bfa 100644
--- a/libavcodec/x86/ac3dsp_init.c
+++ b/libavcodec/x86/ac3dsp_init.c
@@ -2,20 +2,20 @@
* x86-optimized AC-3 DSP functions
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,6 +64,11 @@ void ff_apply_window_int16_ssse3(int16_t *output, const int16_t *input,
void ff_apply_window_int16_ssse3_atom(int16_t *output, const int16_t *input,
const int16_t *window, unsigned int len);
+#if ARCH_X86_32 && defined(__INTEL_COMPILER)
+# undef HAVE_7REGS
+# define HAVE_7REGS 0
+#endif
+
#if HAVE_SSE_INLINE && HAVE_7REGS
#define IF1(x) x
@@ -160,7 +165,7 @@ static void ac3_downmix_sse(float **samples, float (*matrix)[2],
matrix_cmp[3][0] == matrix_cmp[4][0]) {
MIX5(IF1, IF0);
} else {
- DECLARE_ALIGNED(16, float, matrix_simd)[AC3_MAX_CHANNELS][2][4];
+ LOCAL_ALIGNED(16, float, matrix_simd, [AC3_MAX_CHANNELS], [2][4]);
float *samp[AC3_MAX_CHANNELS];
for (j = 0; j < in_ch; j++)
diff --git a/libavcodec/x86/apedsp.asm b/libavcodec/x86/apedsp.asm
deleted file mode 100644
index d721ebda6b..0000000000
--- a/libavcodec/x86/apedsp.asm
+++ /dev/null
@@ -1,167 +0,0 @@
-;******************************************************************************
-;* Copyright (c) 2008 Loren Merritt
-;*
-;* This file is part of Libav.
-;*
-;* Libav is free software; you can redistribute it and/or
-;* modify it under the terms of the GNU Lesser General Public
-;* License as published by the Free Software Foundation; either
-;* version 2.1 of the License, or (at your option) any later version.
-;*
-;* Libav is distributed in the hope that it will be useful,
-;* but WITHOUT ANY WARRANTY; without even the implied warranty of
-;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;* Lesser General Public License for more details.
-;*
-;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
-;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-;******************************************************************************
-
-%include "libavutil/x86/x86util.asm"
-
-SECTION_TEXT
-
-%macro SCALARPRODUCT 0
-; int ff_scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3,
-; int order, int mul)
-cglobal scalarproduct_and_madd_int16, 4,4,8, v1, v2, v3, order, mul
- shl orderq, 1
- movd m7, mulm
-%if mmsize == 16
- pshuflw m7, m7, 0
- punpcklqdq m7, m7
-%else
- pshufw m7, m7, 0
-%endif
- pxor m6, m6
- add v1q, orderq
- add v2q, orderq
- add v3q, orderq
- neg orderq
-.loop:
- movu m0, [v2q + orderq]
- movu m1, [v2q + orderq + mmsize]
- mova m4, [v1q + orderq]
- mova m5, [v1q + orderq + mmsize]
- movu m2, [v3q + orderq]
- movu m3, [v3q + orderq + mmsize]
- pmaddwd m0, m4
- pmaddwd m1, m5
- pmullw m2, m7
- pmullw m3, m7
- paddd m6, m0
- paddd m6, m1
- paddw m2, m4
- paddw m3, m5
- mova [v1q + orderq], m2
- mova [v1q + orderq + mmsize], m3
- add orderq, mmsize*2
- jl .loop
-%if mmsize == 16
- movhlps m0, m6
- paddd m6, m0
- pshuflw m0, m6, 0x4e
-%else
- pshufw m0, m6, 0x4e
-%endif
- paddd m6, m0
- movd eax, m6
- RET
-%endmacro
-
-INIT_MMX mmxext
-SCALARPRODUCT
-INIT_XMM sse2
-SCALARPRODUCT
-
-%macro SCALARPRODUCT_LOOP 1
-align 16
-.loop%1:
- sub orderq, mmsize*2
-%if %1
- mova m1, m4
- mova m4, [v2q + orderq]
- mova m0, [v2q + orderq + mmsize]
- palignr m1, m0, %1
- palignr m0, m4, %1
- mova m3, m5
- mova m5, [v3q + orderq]
- mova m2, [v3q + orderq + mmsize]
- palignr m3, m2, %1
- palignr m2, m5, %1
-%else
- mova m0, [v2q + orderq]
- mova m1, [v2q + orderq + mmsize]
- mova m2, [v3q + orderq]
- mova m3, [v3q + orderq + mmsize]
-%endif
- %define t0 [v1q + orderq]
- %define t1 [v1q + orderq + mmsize]
-%if ARCH_X86_64
- mova m8, t0
- mova m9, t1
- %define t0 m8
- %define t1 m9
-%endif
- pmaddwd m0, t0
- pmaddwd m1, t1
- pmullw m2, m7
- pmullw m3, m7
- paddw m2, t0
- paddw m3, t1
- paddd m6, m0
- paddd m6, m1
- mova [v1q + orderq], m2
- mova [v1q + orderq + mmsize], m3
- jg .loop%1
-%if %1
- jmp .end
-%endif
-%endmacro
-
-; int ff_scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3,
-; int order, int mul)
-INIT_XMM ssse3
-cglobal scalarproduct_and_madd_int16, 4,5,10, v1, v2, v3, order, mul
- shl orderq, 1
- movd m7, mulm
- pshuflw m7, m7, 0
- punpcklqdq m7, m7
- pxor m6, m6
- mov r4d, v2d
- and r4d, 15
- and v2q, ~15
- and v3q, ~15
- mova m4, [v2q + orderq]
- mova m5, [v3q + orderq]
- ; linear is faster than branch tree or jump table, because the branches taken are cyclic (i.e. predictable)
- cmp r4d, 0
- je .loop0
- cmp r4d, 2
- je .loop2
- cmp r4d, 4
- je .loop4
- cmp r4d, 6
- je .loop6
- cmp r4d, 8
- je .loop8
- cmp r4d, 10
- je .loop10
- cmp r4d, 12
- je .loop12
-SCALARPRODUCT_LOOP 14
-SCALARPRODUCT_LOOP 12
-SCALARPRODUCT_LOOP 10
-SCALARPRODUCT_LOOP 8
-SCALARPRODUCT_LOOP 6
-SCALARPRODUCT_LOOP 4
-SCALARPRODUCT_LOOP 2
-SCALARPRODUCT_LOOP 0
-.end:
- movhlps m0, m6
- paddd m6, m0
- pshuflw m0, m6, 0x4e
- paddd m6, m0
- movd eax, m6
- RET
diff --git a/libavcodec/x86/apedsp_init.c b/libavcodec/x86/apedsp_init.c
deleted file mode 100644
index f692c2b9b6..0000000000
--- a/libavcodec/x86/apedsp_init.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; 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/x86/cpu.h"
-#include "libavcodec/apedsp.h"
-
-int32_t ff_scalarproduct_and_madd_int16_mmxext(int16_t *v1, const int16_t *v2,
- const int16_t *v3,
- int order, int mul);
-int32_t ff_scalarproduct_and_madd_int16_sse2(int16_t *v1, const int16_t *v2,
- const int16_t *v3,
- int order, int mul);
-int32_t ff_scalarproduct_and_madd_int16_ssse3(int16_t *v1, const int16_t *v2,
- const int16_t *v3,
- int order, int mul);
-
-av_cold void ff_apedsp_init_x86(APEDSPContext *c)
-{
- int cpu_flags = av_get_cpu_flags();
-
- if (EXTERNAL_MMXEXT(cpu_flags))
- c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_mmxext;
-
- if (EXTERNAL_SSE2(cpu_flags))
- c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_sse2;
-
- if (EXTERNAL_SSSE3(cpu_flags) &&
- !(cpu_flags & (AV_CPU_FLAG_SSE42 | AV_CPU_FLAG_3DNOW))) // cachesplit
- c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_ssse3;
-}
diff --git a/libavcodec/x86/audiodsp.asm b/libavcodec/x86/audiodsp.asm
index f2e831df17..273b9ef660 100644
--- a/libavcodec/x86/audiodsp.asm
+++ b/libavcodec/x86/audiodsp.asm
@@ -2,20 +2,20 @@
;* optimized audio functions
;* Copyright (c) 2008 Loren Merritt
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -40,15 +40,11 @@ cglobal scalarproduct_int16, 3,3,3, v1, v2, order
paddd m2, m1
add orderq, mmsize*2
jl .loop
-%if mmsize == 16
- movhlps m0, m2
- paddd m2, m0
- pshuflw m0, m2, 0x4e
-%else
- pshufw m0, m2, 0x4e
-%endif
- paddd m2, m0
+ HADDD m2, m0
movd eax, m2
+%if mmsize == 8
+ emms
+%endif
RET
%endmacro
@@ -80,17 +76,17 @@ cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len
SPLATD m4
SPLATD m5
.loop:
-%assign %%i 1
+%assign %%i 0
%rep %2
- mova m0, [srcq+mmsize*0*%%i]
- mova m1, [srcq+mmsize*1*%%i]
- mova m2, [srcq+mmsize*2*%%i]
- mova m3, [srcq+mmsize*3*%%i]
+ mova m0, [srcq+mmsize*(0+%%i)]
+ mova m1, [srcq+mmsize*(1+%%i)]
+ mova m2, [srcq+mmsize*(2+%%i)]
+ mova m3, [srcq+mmsize*(3+%%i)]
%if %3
- mova m7, [srcq+mmsize*4*%%i]
- mova m8, [srcq+mmsize*5*%%i]
- mova m9, [srcq+mmsize*6*%%i]
- mova m10, [srcq+mmsize*7*%%i]
+ mova m7, [srcq+mmsize*(4+%%i)]
+ mova m8, [srcq+mmsize*(5+%%i)]
+ mova m9, [srcq+mmsize*(6+%%i)]
+ mova m10, [srcq+mmsize*(7+%%i)]
%endif
CLIPD m0, m4, m5, m6
CLIPD m1, m4, m5, m6
@@ -102,17 +98,17 @@ cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len
CLIPD m9, m4, m5, m6
CLIPD m10, m4, m5, m6
%endif
- mova [dstq+mmsize*0*%%i], m0
- mova [dstq+mmsize*1*%%i], m1
- mova [dstq+mmsize*2*%%i], m2
- mova [dstq+mmsize*3*%%i], m3
+ mova [dstq+mmsize*(0+%%i)], m0
+ mova [dstq+mmsize*(1+%%i)], m1
+ mova [dstq+mmsize*(2+%%i)], m2
+ mova [dstq+mmsize*(3+%%i)], m3
%if %3
- mova [dstq+mmsize*4*%%i], m7
- mova [dstq+mmsize*5*%%i], m8
- mova [dstq+mmsize*6*%%i], m9
- mova [dstq+mmsize*7*%%i], m10
+ mova [dstq+mmsize*(4+%%i)], m7
+ mova [dstq+mmsize*(5+%%i)], m8
+ mova [dstq+mmsize*(6+%%i)], m9
+ mova [dstq+mmsize*(7+%%i)], m10
%endif
-%assign %%i %%i+1
+%assign %%i %%i+4*(%3+1)
%endrep
add srcq, mmsize*4*(%2+%3)
add dstq, mmsize*4*(%2+%3)
@@ -135,3 +131,47 @@ VECTOR_CLIP_INT32 11, 1, 1, 0
%else
VECTOR_CLIP_INT32 6, 1, 0, 0
%endif
+
+;-----------------------------------------------------
+;void ff_vector_clipf(float *dst, const float *src,
+; float min, float max, int len)
+;-----------------------------------------------------
+INIT_XMM sse
+%if UNIX64
+cglobal vector_clipf, 3,3,6, dst, src, len
+%else
+cglobal vector_clipf, 5,5,6, dst, src, min, max, len
+%endif
+%if WIN64
+ SWAP 0, 2
+ SWAP 1, 3
+%elif ARCH_X86_32
+ movss m0, minm
+ movss m1, maxm
+%endif
+ SPLATD m0
+ SPLATD m1
+ shl lend, 2
+ add srcq, lenq
+ add dstq, lenq
+ neg lenq
+.loop:
+ mova m2, [srcq+lenq+mmsize*0]
+ mova m3, [srcq+lenq+mmsize*1]
+ mova m4, [srcq+lenq+mmsize*2]
+ mova m5, [srcq+lenq+mmsize*3]
+ maxps m2, m0
+ maxps m3, m0
+ maxps m4, m0
+ maxps m5, m0
+ minps m2, m1
+ minps m3, m1
+ minps m4, m1
+ minps m5, m1
+ mova [dstq+lenq+mmsize*0], m2
+ mova [dstq+lenq+mmsize*1], m3
+ mova [dstq+lenq+mmsize*2], m4
+ mova [dstq+lenq+mmsize*3], m5
+ add lenq, mmsize*4
+ jl .loop
+ REP_RET
diff --git a/libavcodec/x86/audiodsp.h b/libavcodec/x86/audiodsp.h
deleted file mode 100644
index 321056b8b7..0000000000
--- a/libavcodec/x86/audiodsp.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_X86_AUDIODSP_H
-#define AVCODEC_X86_AUDIODSP_H
-
-void ff_vector_clipf_sse(float *dst, const float *src,
- float min, float max, int len);
-
-#endif /* AVCODEC_X86_AUDIODSP_H */
diff --git a/libavcodec/x86/audiodsp_init.c b/libavcodec/x86/audiodsp_init.c
index 743f5a3699..a2ce231f32 100644
--- a/libavcodec/x86/audiodsp_init.c
+++ b/libavcodec/x86/audiodsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,7 +24,6 @@
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
#include "libavcodec/audiodsp.h"
-#include "audiodsp.h"
int32_t ff_scalarproduct_int16_mmxext(const int16_t *v1, const int16_t *v2,
int order);
@@ -39,6 +38,8 @@ void ff_vector_clip_int32_int_sse2(int32_t *dst, const int32_t *src,
int32_t min, int32_t max, unsigned int len);
void ff_vector_clip_int32_sse4(int32_t *dst, const int32_t *src,
int32_t min, int32_t max, unsigned int len);
+void ff_vector_clipf_sse(float *dst, const float *src,
+ float min, float max, int len);
av_cold void ff_audiodsp_init_x86(AudioDSPContext *c)
{
@@ -50,7 +51,7 @@ av_cold void ff_audiodsp_init_x86(AudioDSPContext *c)
if (EXTERNAL_MMXEXT(cpu_flags))
c->scalarproduct_int16 = ff_scalarproduct_int16_mmxext;
- if (INLINE_SSE(cpu_flags))
+ if (EXTERNAL_SSE(cpu_flags))
c->vector_clipf = ff_vector_clipf_sse;
if (EXTERNAL_SSE2(cpu_flags)) {
diff --git a/libavcodec/x86/audiodsp_mmx.c b/libavcodec/x86/audiodsp_mmx.c
deleted file mode 100644
index cb550598f9..0000000000
--- a/libavcodec/x86/audiodsp_mmx.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#include "libavutil/x86/asm.h"
-#include "audiodsp.h"
-
-#if HAVE_INLINE_ASM
-
-void ff_vector_clipf_sse(float *dst, const float *src,
- float min, float max, int len)
-{
- x86_reg i = (len - 16) * 4;
- __asm__ volatile (
- "movss %3, %%xmm4 \n\t"
- "movss %4, %%xmm5 \n\t"
- "shufps $0, %%xmm4, %%xmm4 \n\t"
- "shufps $0, %%xmm5, %%xmm5 \n\t"
- "1: \n\t"
- "movaps (%2, %0), %%xmm0 \n\t" // 3/1 on intel
- "movaps 16(%2, %0), %%xmm1 \n\t"
- "movaps 32(%2, %0), %%xmm2 \n\t"
- "movaps 48(%2, %0), %%xmm3 \n\t"
- "maxps %%xmm4, %%xmm0 \n\t"
- "maxps %%xmm4, %%xmm1 \n\t"
- "maxps %%xmm4, %%xmm2 \n\t"
- "maxps %%xmm4, %%xmm3 \n\t"
- "minps %%xmm5, %%xmm0 \n\t"
- "minps %%xmm5, %%xmm1 \n\t"
- "minps %%xmm5, %%xmm2 \n\t"
- "minps %%xmm5, %%xmm3 \n\t"
- "movaps %%xmm0, (%1, %0) \n\t"
- "movaps %%xmm1, 16(%1, %0) \n\t"
- "movaps %%xmm2, 32(%1, %0) \n\t"
- "movaps %%xmm3, 48(%1, %0) \n\t"
- "sub $64, %0 \n\t"
- "jge 1b \n\t"
- : "+&r" (i)
- : "r" (dst), "r" (src), "m" (min), "m" (max)
- : "memory");
-}
-
-#endif /* HAVE_INLINE_ASM */
diff --git a/libavcodec/x86/blockdsp.asm b/libavcodec/x86/blockdsp.asm
new file mode 100644
index 0000000000..c793858861
--- /dev/null
+++ b/libavcodec/x86/blockdsp.asm
@@ -0,0 +1,86 @@
+;******************************************************************************
+;* SIMD-optimized clear block functions
+;* Copyright (c) 2002 Michael Niedermayer
+;* Copyright (c) 2008 Loren Merritt
+;* Copyright (c) 2009 Fiona Glaser
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_TEXT
+
+;----------------------------------------
+; void ff_clear_block(int16_t *blocks);
+;----------------------------------------
+; %1 = number of xmm registers used
+; %2 = number of inline store loops
+%macro CLEAR_BLOCK 2
+cglobal clear_block, 1, 1, %1, blocks
+ ZERO m0, m0
+%assign %%i 0
+%rep %2
+ mova [blocksq+mmsize*(0+%%i)], m0
+ mova [blocksq+mmsize*(1+%%i)], m0
+ mova [blocksq+mmsize*(2+%%i)], m0
+ mova [blocksq+mmsize*(3+%%i)], m0
+ mova [blocksq+mmsize*(4+%%i)], m0
+ mova [blocksq+mmsize*(5+%%i)], m0
+ mova [blocksq+mmsize*(6+%%i)], m0
+ mova [blocksq+mmsize*(7+%%i)], m0
+%assign %%i %%i+8
+%endrep
+ RET
+%endmacro
+
+INIT_MMX mmx
+%define ZERO pxor
+CLEAR_BLOCK 0, 2
+INIT_XMM sse
+%define ZERO xorps
+CLEAR_BLOCK 1, 1
+
+;-----------------------------------------
+; void ff_clear_blocks(int16_t *blocks);
+;-----------------------------------------
+; %1 = number of xmm registers used
+%macro CLEAR_BLOCKS 1
+cglobal clear_blocks, 1, 2, %1, blocks, len
+ add blocksq, 768
+ mov lenq, -768
+ ZERO m0, m0
+.loop
+ mova [blocksq+lenq+mmsize*0], m0
+ mova [blocksq+lenq+mmsize*1], m0
+ mova [blocksq+lenq+mmsize*2], m0
+ mova [blocksq+lenq+mmsize*3], m0
+ mova [blocksq+lenq+mmsize*4], m0
+ mova [blocksq+lenq+mmsize*5], m0
+ mova [blocksq+lenq+mmsize*6], m0
+ mova [blocksq+lenq+mmsize*7], m0
+ add lenq, mmsize*8
+ js .loop
+ RET
+%endmacro
+
+INIT_MMX mmx
+%define ZERO pxor
+CLEAR_BLOCKS 0
+INIT_XMM sse
+%define ZERO xorps
+CLEAR_BLOCKS 1
diff --git a/libavcodec/x86/blockdsp.c b/libavcodec/x86/blockdsp.c
deleted file mode 100644
index b5294242ab..0000000000
--- a/libavcodec/x86/blockdsp.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdint.h>
-
-#include "config.h"
-#include "libavutil/attributes.h"
-#include "libavutil/internal.h"
-#include "libavutil/cpu.h"
-#include "libavutil/x86/asm.h"
-#include "libavutil/x86/cpu.h"
-#include "libavcodec/blockdsp.h"
-#include "libavcodec/version.h"
-
-#if HAVE_INLINE_ASM
-
-#define CLEAR_BLOCKS(name, n) \
-static void name(int16_t *blocks) \
-{ \
- __asm__ volatile ( \
- "pxor %%mm7, %%mm7 \n\t" \
- "mov %1, %%"REG_a" \n\t" \
- "1: \n\t" \
- "movq %%mm7, (%0, %%"REG_a") \n\t" \
- "movq %%mm7, 8(%0, %%"REG_a") \n\t" \
- "movq %%mm7, 16(%0, %%"REG_a") \n\t" \
- "movq %%mm7, 24(%0, %%"REG_a") \n\t" \
- "add $32, %%"REG_a" \n\t" \
- "js 1b \n\t" \
- :: "r"(((uint8_t *) blocks) + 128 * n), \
- "i"(-128 * n) \
- : "%"REG_a); \
-}
-CLEAR_BLOCKS(clear_blocks_mmx, 6)
-CLEAR_BLOCKS(clear_block_mmx, 1)
-
-static void clear_block_sse(int16_t *block)
-{
- __asm__ volatile (
- "xorps %%xmm0, %%xmm0 \n"
- "movaps %%xmm0, (%0) \n"
- "movaps %%xmm0, 16(%0) \n"
- "movaps %%xmm0, 32(%0) \n"
- "movaps %%xmm0, 48(%0) \n"
- "movaps %%xmm0, 64(%0) \n"
- "movaps %%xmm0, 80(%0) \n"
- "movaps %%xmm0, 96(%0) \n"
- "movaps %%xmm0, 112(%0) \n"
- :: "r" (block)
- : "memory");
-}
-
-static void clear_blocks_sse(int16_t *blocks)
-{
- __asm__ volatile (
- "xorps %%xmm0, %%xmm0 \n"
- "mov %1, %%"REG_a" \n"
- "1: \n"
- "movaps %%xmm0, (%0, %%"REG_a") \n"
- "movaps %%xmm0, 16(%0, %%"REG_a") \n"
- "movaps %%xmm0, 32(%0, %%"REG_a") \n"
- "movaps %%xmm0, 48(%0, %%"REG_a") \n"
- "movaps %%xmm0, 64(%0, %%"REG_a") \n"
- "movaps %%xmm0, 80(%0, %%"REG_a") \n"
- "movaps %%xmm0, 96(%0, %%"REG_a") \n"
- "movaps %%xmm0, 112(%0, %%"REG_a") \n"
- "add $128, %%"REG_a" \n"
- "js 1b \n"
- :: "r"(((uint8_t *) blocks) + 128 * 6), "i"(-128 * 6)
- : "%"REG_a);
-}
-
-#endif /* HAVE_INLINE_ASM */
-
-#if FF_API_XVMC
-av_cold void ff_blockdsp_init_x86(BlockDSPContext *c, unsigned high_bit_depth,
- AVCodecContext *avctx)
-#else
-av_cold void ff_blockdsp_init_x86(BlockDSPContext *c, unsigned high_bit_depth)
-#endif /* FF_API_XVMC */
-{
-#if HAVE_INLINE_ASM
- int cpu_flags = av_get_cpu_flags();
-
- if (!high_bit_depth) {
- if (INLINE_MMX(cpu_flags)) {
- c->clear_block = clear_block_mmx;
- c->clear_blocks = clear_blocks_mmx;
- }
-
-#if FF_API_XVMC
-FF_DISABLE_DEPRECATION_WARNINGS
- /* XvMCCreateBlocks() may not allocate 16-byte aligned blocks */
- if (CONFIG_MPEG_XVMC_DECODER && avctx->xvmc_acceleration > 1)
- return;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif /* FF_API_XVMC */
-
- if (INLINE_SSE(cpu_flags)) {
- c->clear_block = clear_block_sse;
- c->clear_blocks = clear_blocks_sse;
- }
- }
-#endif /* HAVE_INLINE_ASM */
-}
diff --git a/libavcodec/x86/blockdsp_init.c b/libavcodec/x86/blockdsp_init.c
new file mode 100644
index 0000000000..7780184af6
--- /dev/null
+++ b/libavcodec/x86/blockdsp_init.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdint.h>
+
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/internal.h"
+#include "libavutil/cpu.h"
+#include "libavutil/x86/cpu.h"
+#include "libavcodec/blockdsp.h"
+#include "libavcodec/version.h"
+
+void ff_clear_block_mmx(int16_t *block);
+void ff_clear_block_sse(int16_t *block);
+void ff_clear_blocks_mmx(int16_t *blocks);
+void ff_clear_blocks_sse(int16_t *blocks);
+
+#if FF_API_XVMC
+av_cold void ff_blockdsp_init_x86(BlockDSPContext *c, unsigned high_bit_depth,
+ AVCodecContext *avctx)
+#else
+av_cold void ff_blockdsp_init_x86(BlockDSPContext *c, unsigned high_bit_depth)
+#endif /* FF_API_XVMC */
+{
+#if HAVE_YASM
+ int cpu_flags = av_get_cpu_flags();
+
+ if (!high_bit_depth) {
+ if (EXTERNAL_MMX(cpu_flags)) {
+ c->clear_block = ff_clear_block_mmx;
+ c->clear_blocks = ff_clear_blocks_mmx;
+ }
+
+ /* XvMCCreateBlocks() may not allocate 16-byte aligned blocks */
+ if (CONFIG_XVMC && avctx->hwaccel && avctx->hwaccel->decode_mb)
+ return;
+
+ if (EXTERNAL_SSE(cpu_flags)) {
+ c->clear_block = ff_clear_block_sse;
+ c->clear_blocks = ff_clear_blocks_sse;
+ }
+ }
+#endif /* HAVE_YASM */
+}
diff --git a/libavcodec/x86/bswapdsp.asm b/libavcodec/x86/bswapdsp.asm
index 17a6cb1be3..ec060c93b6 100644
--- a/libavcodec/x86/bswapdsp.asm
+++ b/libavcodec/x86/bswapdsp.asm
@@ -1,21 +1,23 @@
;******************************************************************************
;* optimized bswap buffer functions
;* Copyright (c) 2008 Loren Merritt
+;* Copyright (c) 2003-2013 Michael Niedermayer
+;* Copyright (c) 2013 Daniel Kang
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -24,6 +26,8 @@
SECTION_RODATA
pb_bswap32: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+cextern pb_80
+
SECTION_TEXT
; %1 = aligned/unaligned
@@ -90,6 +94,7 @@ cglobal bswap32_buf, 3,4,3
cglobal bswap32_buf, 3,4,5
mov r3, r1
%endif
+ or r3, r0
and r3, 15
jz .start_align
BSWAP_LOOPS u
diff --git a/libavcodec/x86/bswapdsp_init.c b/libavcodec/x86/bswapdsp_init.c
index ba40f2dbe1..c042e56371 100644
--- a/libavcodec/x86/bswapdsp_init.c
+++ b/libavcodec/x86/bswapdsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/cabac.h b/libavcodec/x86/cabac.h
index d1701bf071..3510336f95 100644
--- a/libavcodec/x86/cabac.h
+++ b/libavcodec/x86/cabac.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,8 +27,28 @@
#include "libavutil/x86/asm.h"
#include "config.h"
+#if (defined(__i386) && defined(__clang__) && (__clang_major__<2 || (__clang_major__==2 && __clang_minor__<10)))\
+ || ( !defined(__clang__) && defined(__llvm__) && __GNUC__==4 && __GNUC_MINOR__==2 && __GNUC_PATCHLEVEL__<=1)\
+ || (defined(__INTEL_COMPILER) && defined(_MSC_VER))
+# define BROKEN_COMPILER 1
+#else
+# define BROKEN_COMPILER 0
+#endif
+
#if HAVE_INLINE_ASM
+#ifndef UNCHECKED_BITSTREAM_READER
+#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER
+#endif
+
+#if UNCHECKED_BITSTREAM_READER
+#define END_CHECK(end) ""
+#else
+#define END_CHECK(end) \
+ "cmp "end" , %%"REG_c" \n\t"\
+ "jge 1f \n\t"
+#endif
+
#ifdef BROKEN_RELOCATIONS
#define TABLES_ARG , "r"(tables)
@@ -73,8 +93,7 @@
"test "lowword" , "lowword" \n\t"\
"jnz 2f \n\t"\
"mov "byte" , %%"REG_c" \n\t"\
- "cmp "end" , %%"REG_c" \n\t"\
- "jge 1f \n\t"\
+ END_CHECK(end)\
"add"OPSIZE" $2 , "byte" \n\t"\
"1: \n\t"\
"movzwl (%%"REG_c") , "tmp" \n\t"\
@@ -92,7 +111,8 @@
"2: \n\t"
#else /* BROKEN_RELOCATIONS */
-#define TABLES_ARG
+#define TABLES_ARG NAMED_CONSTRAINTS_ARRAY_ADD(ff_h264_cabac_tables)
+#define RIP_ARG
#if HAVE_FAST_CMOV
#define BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp)\
@@ -134,8 +154,7 @@
"test "lowword" , "lowword" \n\t"\
" jnz 2f \n\t"\
"mov "byte" , %%"REG_c" \n\t"\
- "cmp "end" , %%"REG_c" \n\t"\
- "jge 1f \n\t"\
+ END_CHECK(end)\
"add"OPSIZE" $2 , "byte" \n\t"\
"1: \n\t"\
"movzwl (%%"REG_c") , "tmp" \n\t"\
@@ -154,8 +173,7 @@
#endif /* BROKEN_RELOCATIONS */
-
-#if HAVE_7REGS
+#if HAVE_7REGS && !BROKEN_COMPILER
#define get_cabac_inline get_cabac_inline_x86
static av_always_inline int get_cabac_inline_x86(CABACContext *c,
uint8_t *const state)
@@ -167,6 +185,7 @@ static av_always_inline int get_cabac_inline_x86(CABACContext *c,
__asm__ volatile(
"lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t"
: "=&r"(tables)
+ : NAMED_CONSTRAINTS_ARRAY(ff_h264_cabac_tables)
);
#endif
@@ -178,17 +197,19 @@ static av_always_inline int get_cabac_inline_x86(CABACContext *c,
AV_STRINGIFY(H264_LPS_RANGE_OFFSET),
AV_STRINGIFY(H264_MLPS_STATE_OFFSET),
"%8")
- : "=&r"(bit), "+&r"(c->low), "+&r"(c->range), "=&q"(tmp)
+ : "=&r"(bit), "=&r"(c->low), "=&r"(c->range), "=&q"(tmp)
: "r"(state), "r"(c),
"i"(offsetof(CABACContext, bytestream)),
"i"(offsetof(CABACContext, bytestream_end))
TABLES_ARG
+ ,"1"(c->low), "2"(c->range)
: "%"REG_c, "memory"
);
return bit & 1;
}
-#endif /* HAVE_7REGS */
+#endif /* HAVE_7REGS && !BROKEN_COMPILER */
+#if !BROKEN_COMPILER
#define get_cabac_bypass_sign get_cabac_bypass_sign_x86
static av_always_inline int get_cabac_bypass_sign_x86(CABACContext *c, int val)
{
@@ -199,7 +220,7 @@ static av_always_inline int get_cabac_bypass_sign_x86(CABACContext *c, int val)
"shl $17, %k1 \n\t"
"add %%eax, %%eax \n\t"
"sub %k1, %%eax \n\t"
- "cltd \n\t"
+ "cdq \n\t"
"and %%edx, %k1 \n\t"
"add %k1, %%eax \n\t"
"xor %%edx, %%ecx \n\t"
@@ -211,10 +232,16 @@ static av_always_inline int get_cabac_bypass_sign_x86(CABACContext *c, int val)
"movzwl (%1), %%edx \n\t"
"bswap %%edx \n\t"
"shrl $15, %%edx \n\t"
+#if UNCHECKED_BITSTREAM_READER
+ "add $2, %1 \n\t"
+ "addl %%edx, %%eax \n\t"
+ "mov %1, %c4(%2) \n\t"
+#else
"addl %%edx, %%eax \n\t"
"cmp %c5(%2), %1 \n\t"
"jge 1f \n\t"
"add"OPSIZE" $2, %c4(%2) \n\t"
+#endif
"1: \n\t"
"movl %%eax, %c3(%2) \n\t"
@@ -240,7 +267,7 @@ static av_always_inline int get_cabac_bypass_x86(CABACContext *c)
"shl $17, %k1 \n\t"
"add %%eax, %%eax \n\t"
"sub %k1, %%eax \n\t"
- "cltd \n\t"
+ "cdq \n\t"
"and %%edx, %k1 \n\t"
"add %k1, %%eax \n\t"
"inc %%edx \n\t"
@@ -268,6 +295,7 @@ static av_always_inline int get_cabac_bypass_x86(CABACContext *c)
);
return res;
}
+#endif /* !BROKEN_COMPILER */
#endif /* HAVE_INLINE_ASM */
#endif /* AVCODEC_X86_CABAC_H */
diff --git a/libavcodec/x86/cavsdsp.c b/libavcodec/x86/cavsdsp.c
index b323a105f2..2ac3bb583a 100644
--- a/libavcodec/x86/cavsdsp.c
+++ b/libavcodec/x86/cavsdsp.c
@@ -5,20 +5,20 @@
* MMX-optimized DSP functions, based on H.264 optimizations by
* Michael Niedermayer and Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -139,11 +139,9 @@ static inline void cavs_idct8_1d(int16_t *block, uint64_t bias)
static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
{
int i;
- DECLARE_ALIGNED(8, int16_t, b2)[64];
+ LOCAL_ALIGNED(16, int16_t, b2, [64]);
for(i=0; i<2; i++){
- DECLARE_ALIGNED(8, uint64_t, tmp);
-
cavs_idct8_1d(block+4*i, ff_pw_4.a);
__asm__ volatile(
@@ -155,19 +153,19 @@ static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
"psraw $3, %%mm2 \n\t"
"psraw $3, %%mm1 \n\t"
"psraw $3, %%mm0 \n\t"
- "movq %%mm7, %0 \n\t"
+ "movq %%mm7, (%0) \n\t"
TRANSPOSE4( %%mm0, %%mm2, %%mm4, %%mm6, %%mm7 )
- "movq %%mm0, 8(%1) \n\t"
- "movq %%mm6, 24(%1) \n\t"
- "movq %%mm7, 40(%1) \n\t"
- "movq %%mm4, 56(%1) \n\t"
- "movq %0, %%mm7 \n\t"
+ "movq %%mm0, 8(%0) \n\t"
+ "movq %%mm6, 24(%0) \n\t"
+ "movq %%mm7, 40(%0) \n\t"
+ "movq %%mm4, 56(%0) \n\t"
+ "movq (%0), %%mm7 \n\t"
TRANSPOSE4( %%mm7, %%mm5, %%mm3, %%mm1, %%mm0 )
- "movq %%mm7, (%1) \n\t"
- "movq %%mm1, 16(%1) \n\t"
- "movq %%mm0, 32(%1) \n\t"
- "movq %%mm3, 48(%1) \n\t"
- : "=m"(tmp)
+ "movq %%mm7, (%0) \n\t"
+ "movq %%mm1, 16(%0) \n\t"
+ "movq %%mm0, 32(%0) \n\t"
+ "movq %%mm3, 48(%0) \n\t"
+ :
: "r"(b2+32*i)
: "memory"
);
@@ -198,7 +196,7 @@ static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
);
}
- ff_add_pixels_clamped_mmx(b2, dst, stride);
+ ff_add_pixels_clamped(b2, dst, stride);
}
#endif /* HAVE_MMX_INLINE */
@@ -212,10 +210,10 @@ static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
****************************************************************************/
/* vertical filter [-1 -2 96 42 -7 0] */
-#define QPEL_CAVSV1(A,B,C,D,E,F,OP,MUL2) \
+#define QPEL_CAVSV1(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \
"movd (%0), "#F" \n\t"\
"movq "#C", %%mm6 \n\t"\
- "pmullw %5, %%mm6 \n\t"\
+ "pmullw "MANGLE(MUL1)", %%mm6\n\t"\
"movq "#D", %%mm7 \n\t"\
"pmullw "MANGLE(MUL2)", %%mm7\n\t"\
"psllw $3, "#E" \n\t"\
@@ -230,35 +228,35 @@ static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
"psubw "#B", %%mm6 \n\t"\
"psraw $1, "#B" \n\t"\
"psubw "#A", %%mm6 \n\t"\
- "paddw %4, %%mm6 \n\t"\
+ "paddw "MANGLE(ADD)", %%mm6 \n\t"\
"psraw $7, %%mm6 \n\t"\
"packuswb %%mm6, %%mm6 \n\t"\
OP(%%mm6, (%1), A, d) \
"add %3, %1 \n\t"
/* vertical filter [ 0 -1 5 5 -1 0] */
-#define QPEL_CAVSV2(A,B,C,D,E,F,OP,MUL2) \
+#define QPEL_CAVSV2(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \
"movd (%0), "#F" \n\t"\
"movq "#C", %%mm6 \n\t"\
"paddw "#D", %%mm6 \n\t"\
- "pmullw %5, %%mm6 \n\t"\
+ "pmullw "MANGLE(MUL1)", %%mm6\n\t"\
"add %2, %0 \n\t"\
"punpcklbw %%mm7, "#F" \n\t"\
"psubw "#B", %%mm6 \n\t"\
"psubw "#E", %%mm6 \n\t"\
- "paddw %4, %%mm6 \n\t"\
+ "paddw "MANGLE(ADD)", %%mm6 \n\t"\
"psraw $3, %%mm6 \n\t"\
"packuswb %%mm6, %%mm6 \n\t"\
OP(%%mm6, (%1), A, d) \
"add %3, %1 \n\t"
/* vertical filter [ 0 -7 42 96 -2 -1] */
-#define QPEL_CAVSV3(A,B,C,D,E,F,OP,MUL2) \
+#define QPEL_CAVSV3(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \
"movd (%0), "#F" \n\t"\
"movq "#C", %%mm6 \n\t"\
"pmullw "MANGLE(MUL2)", %%mm6\n\t"\
"movq "#D", %%mm7 \n\t"\
- "pmullw %5, %%mm7 \n\t"\
+ "pmullw "MANGLE(MUL1)", %%mm7\n\t"\
"psllw $3, "#B" \n\t"\
"psubw "#B", %%mm6 \n\t"\
"psraw $3, "#B" \n\t"\
@@ -271,7 +269,7 @@ static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
"psubw "#E", %%mm6 \n\t"\
"psraw $1, "#E" \n\t"\
"psubw "#F", %%mm6 \n\t"\
- "paddw %4, %%mm6 \n\t"\
+ "paddw "MANGLE(ADD)", %%mm6 \n\t"\
"psraw $7, %%mm6 \n\t"\
"packuswb %%mm6, %%mm6 \n\t"\
OP(%%mm6, (%1), A, d) \
@@ -300,32 +298,34 @@ static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, int stride)
"punpcklbw %%mm7, %%mm2 \n\t"\
"punpcklbw %%mm7, %%mm3 \n\t"\
"punpcklbw %%mm7, %%mm4 \n\t"\
- VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, MUL2)\
- VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, MUL2)\
- VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, MUL2)\
- VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, MUL2)\
- VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, MUL2)\
- VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, MUL2)\
- VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, MUL2)\
- VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, MUL2)\
+ VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\
\
: "+a"(src), "+c"(dst)\
- : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride), "m"(ADD), "m"(MUL1)\
+ : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride)\
+ NAMED_CONSTRAINTS_ADD(ADD,MUL1,MUL2)\
: "memory"\
);\
if(h==16){\
__asm__ volatile(\
- VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, MUL2)\
- VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, MUL2)\
- VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, MUL2)\
- VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, MUL2)\
- VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, MUL2)\
- VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, MUL2)\
- VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, MUL2)\
- VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, MUL2)\
+ VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\
+ VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\
\
: "+a"(src), "+c"(dst)\
- : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride), "m"(ADD), "m"(MUL1)\
+ : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride)\
+ NAMED_CONSTRAINTS_ADD(ADD,MUL1,MUL2)\
: "memory"\
);\
}\
@@ -338,7 +338,7 @@ static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, const uint8_t *src, int
int h=8;\
__asm__ volatile(\
"pxor %%mm7, %%mm7 \n\t"\
- "movq %5, %%mm6 \n\t"\
+ "movq "MANGLE(ff_pw_5)", %%mm6\n\t"\
"1: \n\t"\
"movq (%0), %%mm0 \n\t"\
"movq 1(%0), %%mm2 \n\t"\
@@ -364,7 +364,7 @@ static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, const uint8_t *src, int
"paddw %%mm3, %%mm5 \n\t"\
"psubw %%mm2, %%mm0 \n\t"\
"psubw %%mm5, %%mm1 \n\t"\
- "movq %6, %%mm5 \n\t"\
+ "movq "MANGLE(ff_pw_4)", %%mm5\n\t"\
"paddw %%mm5, %%mm0 \n\t"\
"paddw %%mm5, %%mm1 \n\t"\
"psraw $3, %%mm0 \n\t"\
@@ -376,7 +376,8 @@ static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, const uint8_t *src, int
"decl %2 \n\t"\
" jnz 1b \n\t"\
: "+a"(src), "+c"(dst), "+m"(h)\
- : "d"((x86_reg)srcStride), "S"((x86_reg)dstStride), "m"(ff_pw_5), "m"(ff_pw_4)\
+ : "d"((x86_reg)srcStride), "S"((x86_reg)dstStride)\
+ NAMED_CONSTRAINTS_ADD(ff_pw_4,ff_pw_5)\
: "memory"\
);\
}\
@@ -386,7 +387,7 @@ static inline void OPNAME ## cavs_qpel8or16_v1_ ## MMX(uint8_t *dst, const uint8
}\
\
static inline void OPNAME ## cavs_qpel8or16_v2_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h){\
- QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,ff_pw_5) \
+ QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,ff_pw_42) \
}\
\
static inline void OPNAME ## cavs_qpel8or16_v3_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h){\
@@ -459,7 +460,7 @@ static void OPNAME ## cavs_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uin
#endif /* (HAVE_MMXEXT_INLINE || HAVE_AMD3DNOW_INLINE) */
-#if HAVE_MMX_INLINE
+#if HAVE_MMX_EXTERNAL
static void put_cavs_qpel8_mc00_mmx(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride)
{
@@ -472,6 +473,12 @@ static void avg_cavs_qpel8_mc00_mmx(uint8_t *dst, const uint8_t *src,
ff_avg_pixels8_mmx(dst, src, stride, 8);
}
+static void avg_cavs_qpel8_mc00_mmxext(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride)
+{
+ ff_avg_pixels8_mmxext(dst, src, stride, 8);
+}
+
static void put_cavs_qpel16_mc00_mmx(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride)
{
@@ -484,18 +491,40 @@ static void avg_cavs_qpel16_mc00_mmx(uint8_t *dst, const uint8_t *src,
ff_avg_pixels16_mmx(dst, src, stride, 16);
}
+static void avg_cavs_qpel16_mc00_mmxext(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride)
+{
+ ff_avg_pixels16_mmxext(dst, src, stride, 16);
+}
+
+static void put_cavs_qpel16_mc00_sse2(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride)
+{
+ ff_put_pixels16_sse2(dst, src, stride, 16);
+}
+
+static void avg_cavs_qpel16_mc00_sse2(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride)
+{
+ ff_avg_pixels16_sse2(dst, src, stride, 16);
+}
+#endif
+
static av_cold void cavsdsp_init_mmx(CAVSDSPContext *c,
AVCodecContext *avctx)
{
+#if HAVE_MMX_EXTERNAL
c->put_cavs_qpel_pixels_tab[0][0] = put_cavs_qpel16_mc00_mmx;
c->put_cavs_qpel_pixels_tab[1][0] = put_cavs_qpel8_mc00_mmx;
c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_mmx;
c->avg_cavs_qpel_pixels_tab[1][0] = avg_cavs_qpel8_mc00_mmx;
+#endif
+#if HAVE_MMX_INLINE
c->cavs_idct8_add = cavs_idct8_add_mmx;
c->idct_perm = FF_IDCT_PERM_TRANSPOSE;
-}
#endif /* HAVE_MMX_INLINE */
+}
#define DSPFUNC(PFX, IDX, NUM, EXT) \
c->PFX ## _cavs_qpel_pixels_tab[IDX][ 2] = PFX ## _cavs_qpel ## NUM ## _mc20_ ## EXT; \
@@ -511,15 +540,6 @@ CAVS_MC(put_, 8, mmxext)
CAVS_MC(put_, 16, mmxext)
CAVS_MC(avg_, 8, mmxext)
CAVS_MC(avg_, 16, mmxext)
-
-static av_cold void cavsdsp_init_mmxext(CAVSDSPContext *c,
- AVCodecContext *avctx)
-{
- DSPFUNC(put, 0, 16, mmxext);
- DSPFUNC(put, 1, 8, mmxext);
- DSPFUNC(avg, 0, 16, mmxext);
- DSPFUNC(avg, 1, 8, mmxext);
-}
#endif /* HAVE_MMXEXT_INLINE */
#if HAVE_AMD3DNOW_INLINE
@@ -543,18 +563,31 @@ static av_cold void cavsdsp_init_3dnow(CAVSDSPContext *c,
av_cold void ff_cavsdsp_init_x86(CAVSDSPContext *c, AVCodecContext *avctx)
{
-#if HAVE_MMX_INLINE
int cpu_flags = av_get_cpu_flags();
- if (INLINE_MMX(cpu_flags))
- cavsdsp_init_mmx(c, avctx);
-#endif /* HAVE_MMX_INLINE */
+ cavsdsp_init_mmx(c, avctx);
#if HAVE_AMD3DNOW_INLINE
if (INLINE_AMD3DNOW(cpu_flags))
cavsdsp_init_3dnow(c, avctx);
#endif /* HAVE_AMD3DNOW_INLINE */
#if HAVE_MMXEXT_INLINE
- if (INLINE_MMXEXT(cpu_flags))
- cavsdsp_init_mmxext(c, avctx);
-#endif /* HAVE_MMXEXT_INLINE */
+ if (INLINE_MMXEXT(cpu_flags)) {
+ DSPFUNC(put, 0, 16, mmxext);
+ DSPFUNC(put, 1, 8, mmxext);
+ DSPFUNC(avg, 0, 16, mmxext);
+ DSPFUNC(avg, 1, 8, mmxext);
+ }
+#endif
+#if HAVE_MMX_EXTERNAL
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_mmxext;
+ c->avg_cavs_qpel_pixels_tab[1][0] = avg_cavs_qpel8_mc00_mmxext;
+ }
+#endif
+#if HAVE_SSE2_EXTERNAL
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->put_cavs_qpel_pixels_tab[0][0] = put_cavs_qpel16_mc00_sse2;
+ c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_sse2;
+ }
+#endif
}
diff --git a/libavcodec/x86/constants.c b/libavcodec/x86/constants.c
index 5b8d1b224f..553dd49d4f 100644
--- a/libavcodec/x86/constants.c
+++ b/libavcodec/x86/constants.c
@@ -1,20 +1,20 @@
/*
- * MMX/SSE constants used across x86 dsp optimizations.
+ * MMX/SSE/AVX constants used across x86 dsp optimizations.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,10 +22,10 @@
#include "libavutil/x86/asm.h" // for xmm_reg
#include "constants.h"
-DECLARE_ALIGNED(8, const uint64_t, ff_wtwo) = 0x0002000200020002ULL;
-
-DECLARE_ALIGNED(16, const xmm_reg, ff_pw_1) = { 0x0001000100010001ULL, 0x0001000100010001ULL };
-DECLARE_ALIGNED(16, const xmm_reg, ff_pw_2) = { 0x0002000200020002ULL, 0x0002000200020002ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1) = { 0x0001000100010001ULL, 0x0001000100010001ULL,
+ 0x0001000100010001ULL, 0x0001000100010001ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_2) = { 0x0002000200020002ULL, 0x0002000200020002ULL,
+ 0x0002000200020002ULL, 0x0002000200020002ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0x0003000300030003ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_4) = { 0x0004000400040004ULL, 0x0004000400040004ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL };
@@ -35,19 +35,47 @@ DECLARE_ALIGNED(8, const uint64_t, ff_pw_15) = 0x000F000F000F000FULL;
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_16) = { 0x0010001000100010ULL, 0x0010001000100010ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_17) = { 0x0011001100110011ULL, 0x0011001100110011ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL };
-DECLARE_ALIGNED(8, const uint64_t, ff_pw_20) = 0x0014001400140014ULL;
+DECLARE_ALIGNED(16, const xmm_reg, ff_pw_20) = { 0x0014001400140014ULL, 0x0014001400140014ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_32) = { 0x0020002000200020ULL, 0x0020002000200020ULL };
DECLARE_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL;
DECLARE_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL;
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL };
DECLARE_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL;
DECLARE_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL;
-DECLARE_ALIGNED(8, const uint64_t, ff_pw_255) = 0x00ff00ff00ff00ffULL;
-DECLARE_ALIGNED(16, const xmm_reg, ff_pw_512) = { 0x0200020002000200ULL, 0x0200020002000200ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_255) = { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL,
+ 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_256) = { 0x0100010001000100ULL, 0x0100010001000100ULL,
+ 0x0100010001000100ULL, 0x0100010001000100ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_512) = { 0x0200020002000200ULL, 0x0200020002000200ULL,
+ 0x0200020002000200ULL, 0x0200020002000200ULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pw_1019) = { 0x03FB03FB03FB03FBULL, 0x03FB03FB03FB03FBULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1023) = { 0x03ff03ff03ff03ffULL, 0x03ff03ff03ff03ffULL,
+ 0x03ff03ff03ff03ffULL, 0x03ff03ff03ff03ffULL};
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1024) = { 0x0400040004000400ULL, 0x0400040004000400ULL,
+ 0x0400040004000400ULL, 0x0400040004000400ULL};
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_2048) = { 0x0800080008000800ULL, 0x0800080008000800ULL,
+ 0x0800080008000800ULL, 0x0800080008000800ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_4096) = { 0x1000100010001000ULL, 0x1000100010001000ULL,
+ 0x1000100010001000ULL, 0x1000100010001000ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_8192) = { 0x2000200020002000ULL, 0x2000200020002000ULL,
+ 0x2000200020002000ULL, 0x2000200020002000ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pw_m1) = { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL,
+ 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL };
-DECLARE_ALIGNED(16, const xmm_reg, ff_pb_0) = { 0x0000000000000000ULL, 0x0000000000000000ULL };
-DECLARE_ALIGNED(16, const xmm_reg, ff_pb_1) = { 0x0101010101010101ULL, 0x0101010101010101ULL };
-DECLARE_ALIGNED(16, const xmm_reg, ff_pb_3) = { 0x0303030303030303ULL, 0x0303030303030303ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pb_0) = { 0x0000000000000000ULL, 0x0000000000000000ULL,
+ 0x0000000000000000ULL, 0x0000000000000000ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pb_1) = { 0x0101010101010101ULL, 0x0101010101010101ULL,
+ 0x0101010101010101ULL, 0x0101010101010101ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pb_2) = { 0x0202020202020202ULL, 0x0202020202020202ULL,
+ 0x0202020202020202ULL, 0x0202020202020202ULL };
+DECLARE_ALIGNED(32, const ymm_reg, ff_pb_3) = { 0x0303030303030303ULL, 0x0303030303030303ULL,
+ 0x0303030303030303ULL, 0x0303030303030303ULL };
+DECLARE_ALIGNED(32, const xmm_reg, ff_pb_15) = { 0x0F0F0F0F0F0F0F0FULL, 0x0F0F0F0F0F0F0F0FULL };
DECLARE_ALIGNED(16, const xmm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x8080808080808080ULL };
+DECLARE_ALIGNED(16, const xmm_reg, ff_pb_FE) = { 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL };
DECLARE_ALIGNED(8, const uint64_t, ff_pb_FC) = 0xFCFCFCFCFCFCFCFCULL;
+
+DECLARE_ALIGNED(16, const xmm_reg, ff_ps_neg) = { 0x8000000080000000ULL, 0x8000000080000000ULL };
+
+DECLARE_ALIGNED(32, const ymm_reg, ff_pd_1) = { 0x0000000100000001ULL, 0x0000000100000001ULL,
+ 0x0000000100000001ULL, 0x0000000100000001ULL };
diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h
index f38fbe3425..33dbb650ae 100644
--- a/libavcodec/x86/constants.h
+++ b/libavcodec/x86/constants.h
@@ -1,20 +1,20 @@
/*
* MMX/SSE constants used across x86 dsp optimizations.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,27 +25,42 @@
#include "libavutil/x86/asm.h"
-extern const uint64_t ff_wtwo;
-
+extern const ymm_reg ff_pw_1;
+extern const ymm_reg ff_pw_2;
extern const xmm_reg ff_pw_3;
extern const xmm_reg ff_pw_4;
extern const xmm_reg ff_pw_5;
extern const xmm_reg ff_pw_8;
+extern const xmm_reg ff_pw_9;
extern const uint64_t ff_pw_15;
extern const xmm_reg ff_pw_16;
extern const xmm_reg ff_pw_18;
-extern const uint64_t ff_pw_20;
+extern const xmm_reg ff_pw_20;
extern const xmm_reg ff_pw_32;
extern const uint64_t ff_pw_42;
extern const uint64_t ff_pw_53;
extern const xmm_reg ff_pw_64;
extern const uint64_t ff_pw_96;
extern const uint64_t ff_pw_128;
-extern const uint64_t ff_pw_255;
+extern const ymm_reg ff_pw_255;
+extern const ymm_reg ff_pw_512;
+extern const ymm_reg ff_pw_1023;
+extern const ymm_reg ff_pw_1024;
+extern const ymm_reg ff_pw_2048;
+extern const ymm_reg ff_pw_4096;
+extern const ymm_reg ff_pw_8192;
+extern const ymm_reg ff_pw_m1;
-extern const xmm_reg ff_pb_1;
-extern const xmm_reg ff_pb_3;
-extern const xmm_reg ff_pb_F8;
+extern const ymm_reg ff_pb_0;
+extern const ymm_reg ff_pb_1;
+extern const ymm_reg ff_pb_2;
+extern const ymm_reg ff_pb_3;
+extern const xmm_reg ff_pb_80;
+extern const xmm_reg ff_pb_FE;
extern const uint64_t ff_pb_FC;
+extern const xmm_reg ff_ps_neg;
+
+extern const ymm_reg ff_pd_1;
+
#endif /* AVCODEC_X86_CONSTANTS_H */
diff --git a/libavcodec/x86/dca.h b/libavcodec/x86/dca.h
deleted file mode 100644
index 11d45ae61c..0000000000
--- a/libavcodec/x86/dca.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2012-2014 Christophe Gisquet <christophe.gisquet@gmail.com>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_X86_DCA_H
-#define AVCODEC_X86_DCA_H
-
-#include "config.h"
-
-#if ARCH_X86_64 && HAVE_SSE2_INLINE
-# include "libavutil/x86/asm.h"
-# include "libavutil/mem.h"
-#include "libavcodec/dcadsp.h"
-
-# define int8x8_fmul_int32 int8x8_fmul_int32
-static inline void int8x8_fmul_int32(av_unused DCADSPContext *dsp,
- float *dst, const int8_t *src, int scale)
-{
- DECLARE_ALIGNED(16, static const uint32_t, inverse16) = 0x3D800000;
- __asm__ volatile (
- "cvtsi2ss %2, %%xmm0 \n\t"
- "mulss %3, %%xmm0 \n\t"
- "movq (%1), %%xmm1 \n\t"
- "punpcklbw %%xmm1, %%xmm1 \n\t"
- "movaps %%xmm1, %%xmm2 \n\t"
- "punpcklwd %%xmm1, %%xmm1 \n\t"
- "punpckhwd %%xmm2, %%xmm2 \n\t"
- "psrad $24, %%xmm1 \n\t"
- "psrad $24, %%xmm2 \n\t"
- "shufps $0, %%xmm0, %%xmm0 \n\t"
- "cvtdq2ps %%xmm1, %%xmm1 \n\t"
- "cvtdq2ps %%xmm2, %%xmm2 \n\t"
- "mulps %%xmm0, %%xmm1 \n\t"
- "mulps %%xmm0, %%xmm2 \n\t"
- "movaps %%xmm1, 0(%0) \n\t"
- "movaps %%xmm2, 16(%0) \n\t"
- :: "r"(dst), "r"(src), "m"(scale), "m"(inverse16)
- XMM_CLOBBERS_ONLY("xmm0", "xmm1", "xmm2")
- );
-}
-
-#endif /* ARCH_X86_64 && HAVE_SSE2_INLINE */
-
-#endif /* AVCODEC_X86_DCA_H */
diff --git a/libavcodec/x86/dcadsp.asm b/libavcodec/x86/dcadsp.asm
index c42ee23faf..1ac237885a 100644
--- a/libavcodec/x86/dcadsp.asm
+++ b/libavcodec/x86/dcadsp.asm
@@ -2,20 +2,20 @@
;* SSE-optimized functions for the DCA decoder
;* Copyright (C) 2012-2014 Christophe Gisquet <christophe.gisquet@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -132,11 +132,16 @@ DECODE_HF
mulps va, %2
mulps vb, %2
%if %0 == 3
+%if cpuflag(fma3)
+ fmaddps va, m4, %3, va
+ fmaddps vb, m0, %3, vb
+%else
mulps m4, %3
mulps m0, %3
addps va, m4
addps vb, m0
%endif
+%endif
; va = va1 va2 va3 va4
; vb = vb1 vb2 vb3 vb4
%if %1
@@ -148,7 +153,7 @@ DECODE_HF
addps m4, va ; va1+3 vb1+3 va2+4 vb2+4
movhlps vb, m4 ; va1+3 vb1+3
addps vb, m4 ; va0..4 vb0..4
- movh [outq + count], vb
+ movlps [outq + count], vb
%if %1
sub cf0q, 8*NUM_COEF
%endif
@@ -198,6 +203,10 @@ cglobal dca_lfe_fir%1, 3,3,6-%1, out, in, cf0
INIT_XMM sse
DCA_LFE_FIR 0
DCA_LFE_FIR 1
+%if HAVE_FMA3_EXTERNAL
+INIT_XMM fma3
+DCA_LFE_FIR 0
+%endif
%macro SETZERO 1
%if cpuflag(sse2) && notcpuflag(avx)
diff --git a/libavcodec/x86/dcadsp_init.c b/libavcodec/x86/dcadsp_init.c
index 9acb818c94..bb86c26037 100644
--- a/libavcodec/x86/dcadsp_init.c
+++ b/libavcodec/x86/dcadsp_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012-2014 Christophe Gisquet <christophe.gisquet@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@ void ff_decode_hf_sse4(float dst[DCA_SUBBANDS][8], const int vq_num[DCA_SUBBANDS
int scale[DCA_SUBBANDS][2], intptr_t start, intptr_t end);
void ff_dca_lfe_fir0_sse(float *out, const float *in, const float *coefs);
void ff_dca_lfe_fir1_sse(float *out, const float *in, const float *coefs);
+void ff_dca_lfe_fir0_fma3(float *out, const float *in, const float *coefs);
av_cold void ff_dcadsp_init_x86(DCADSPContext *s)
{
@@ -54,6 +55,10 @@ av_cold void ff_dcadsp_init_x86(DCADSPContext *s)
if (EXTERNAL_SSE4(cpu_flags)) {
s->decode_hf = ff_decode_hf_sse4;
}
+
+ if (EXTERNAL_FMA3(cpu_flags)) {
+ s->lfe_fir[0] = ff_dca_lfe_fir0_fma3;
+ }
}
diff --git a/libavcodec/x86/dct-test.c b/libavcodec/x86/dct-test.c
index 9d4aaf5415..0414381e65 100644
--- a/libavcodec/x86/dct-test.c
+++ b/libavcodec/x86/dct-test.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,6 +22,37 @@
#include "xvididct.h"
#include "simple_idct.h"
+#if (CONFIG_PRORES_DECODER || CONFIG_PRORES_LGPL_DECODER) && ARCH_X86_64 && HAVE_YASM
+void ff_prores_idct_put_10_sse2(uint16_t *dst, int linesize,
+ int16_t *block, int16_t *qmat);
+
+#define PR_WRAP(INSN) \
+static void ff_prores_idct_put_10_##INSN##_wrap(int16_t *dst){ \
+ LOCAL_ALIGNED(16, int16_t, qmat, [64]); \
+ LOCAL_ALIGNED(16, int16_t, tmp, [64]); \
+ int i; \
+ \
+ for(i=0; i<64; i++){ \
+ qmat[i]=4; \
+ tmp[i]= dst[i]; \
+ } \
+ ff_prores_idct_put_10_##INSN (dst, 16, tmp, qmat); \
+ \
+ for(i=0; i<64; i++) { \
+ dst[i] -= 512; \
+ } \
+}
+
+PR_WRAP(sse2)
+
+# if HAVE_AVX_EXTERNAL
+void ff_prores_idct_put_10_avx(uint16_t *dst, int linesize,
+ int16_t *block, int16_t *qmat);
+PR_WRAP(avx)
+# endif
+
+#endif
+
static const struct algo fdct_tab_arch[] = {
#if HAVE_MMX_INLINE
{ "MMX", ff_fdct_mmx, FF_IDCT_PERM_NONE, AV_CPU_FLAG_MMX },
@@ -39,21 +70,25 @@ static const struct algo idct_tab_arch[] = {
#if HAVE_MMX_INLINE
{ "SIMPLE-MMX", ff_simple_idct_mmx, FF_IDCT_PERM_SIMPLE, AV_CPU_FLAG_MMX },
#endif
-#if CONFIG_MPEG4_DECODER
-#if HAVE_MMX_INLINE
+#if CONFIG_MPEG4_DECODER && HAVE_YASM
+#if ARCH_X86_32
{ "XVID-MMX", ff_xvid_idct_mmx, FF_IDCT_PERM_NONE, AV_CPU_FLAG_MMX, 1 },
-#endif
-#if HAVE_MMXEXT_INLINE
{ "XVID-MMXEXT", ff_xvid_idct_mmxext, FF_IDCT_PERM_NONE, AV_CPU_FLAG_MMXEXT, 1 },
#endif
-#if HAVE_SSE2_INLINE
+#if HAVE_SSE2_EXTERNAL
{ "XVID-SSE2", ff_xvid_idct_sse2, FF_IDCT_PERM_SSE2, AV_CPU_FLAG_SSE2, 1 },
#endif
-#endif /* CONFIG_MPEG4_DECODER */
+#endif /* CONFIG_MPEG4_DECODER && HAVE_YASM */
+#if (CONFIG_PRORES_DECODER || CONFIG_PRORES_LGPL_DECODER) && ARCH_X86_64 && HAVE_YASM
+ { "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 },
+# endif
+#endif
{ 0 }
};
-static short idct_simple_mmx_perm[64] = {
+static const uint8_t idct_simple_mmx_perm[64] = {
0x00, 0x08, 0x04, 0x09, 0x01, 0x0C, 0x05, 0x0D,
0x10, 0x18, 0x14, 0x19, 0x11, 0x1C, 0x15, 0x1D,
0x20, 0x28, 0x24, 0x29, 0x21, 0x2C, 0x25, 0x2D,
diff --git a/libavcodec/x86/dct32.asm b/libavcodec/x86/dct32.asm
index 9c147b9c00..c70f6c9c49 100644
--- a/libavcodec/x86/dct32.asm
+++ b/libavcodec/x86/dct32.asm
@@ -2,20 +2,20 @@
;* 32 point SSE-optimized DCT transform
;* Copyright (c) 2010 Vitor Sessak
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -192,6 +192,7 @@ ps_p1p1m1m1: dd 0, 0, 0x80000000, 0x80000000, 0, 0, 0x80000000, 0x80000000
INIT_YMM avx
SECTION_TEXT
+%if HAVE_AVX_EXTERNAL
; void ff_dct32_float_avx(FFTSample *out, const FFTSample *in)
cglobal dct32_float, 2,3,8, out, in, tmp
; pass 1
@@ -264,6 +265,7 @@ cglobal dct32_float, 2,3,8, out, in, tmp
INIT_XMM
PASS6_AND_PERMUTE
RET
+%endif
%if ARCH_X86_64
%define SPILL SWAP
@@ -482,7 +484,9 @@ cglobal dct32_float, 2, 3, 16, out, in, tmp
%endif
%endmacro
+%if ARCH_X86_32
INIT_XMM sse
DCT32_FUNC
+%endif
INIT_XMM sse2
DCT32_FUNC
diff --git a/libavcodec/x86/dct_init.c b/libavcodec/x86/dct_init.c
index 7bda5e81b6..30c8f12bf2 100644
--- a/libavcodec/x86/dct_init.c
+++ b/libavcodec/x86/dct_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,7 @@ av_cold void ff_dct_init_x86(DCTContext *s)
{
int cpu_flags = av_get_cpu_flags();
- if (EXTERNAL_SSE(cpu_flags))
+ if (ARCH_X86_32 && EXTERNAL_SSE(cpu_flags))
s->dct32 = ff_dct32_float_sse;
if (EXTERNAL_SSE2(cpu_flags))
s->dct32 = ff_dct32_float_sse2;
diff --git a/libavcodec/x86/deinterlace.asm b/libavcodec/x86/deinterlace.asm
index 70d000e0db..c421385fbb 100644
--- a/libavcodec/x86/deinterlace.asm
+++ b/libavcodec/x86/deinterlace.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2010 Vitor Sessak
;* Copyright (c) 2002 Michael Niedermayer
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -31,10 +31,10 @@ SECTION .text
%macro DEINTERLACE 1
%ifidn %1, inplace
;void ff_deinterlace_line_inplace_mmx(const uint8_t *lum_m4, const uint8_t *lum_m3, const uint8_t *lum_m2, const uint8_t *lum_m1, const uint8_t *lum, int size)
-cglobal deinterlace_line_inplace_mmx, 6,6,7, lum_m4, lum_m3, lum_m2, lum_m1, lum, size
+cglobal deinterlace_line_inplace, 6,6,7, lum_m4, lum_m3, lum_m2, lum_m1, lum, size
%else
;void ff_deinterlace_line_mmx(uint8_t *dst, const uint8_t *lum_m4, const uint8_t *lum_m3, const uint8_t *lum_m2, const uint8_t *lum_m1, const uint8_t *lum, int size)
-cglobal deinterlace_line_mmx, 7,7,7, dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size
+cglobal deinterlace_line, 7,7,7, dst, lum_m4, lum_m3, lum_m2, lum_m1, lum, size
%endif
pxor mm7, mm7
movq mm6, [pw_4]
@@ -77,6 +77,8 @@ cglobal deinterlace_line_mmx, 7,7,7, dst, lum_m4, lum_m3, lum_m2, lum_m1
REP_RET
%endmacro
+INIT_MMX mmx
+
DEINTERLACE ""
DEINTERLACE inplace
diff --git a/libavcodec/x86/dirac_dwt.c b/libavcodec/x86/dirac_dwt.c
new file mode 100644
index 0000000000..3c51ea6ffa
--- /dev/null
+++ b/libavcodec/x86/dirac_dwt.c
@@ -0,0 +1,202 @@
+/*
+ * MMX optimized discrete wavelet transform
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2010 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "dirac_dwt.h"
+
+#define COMPOSE_VERTICAL(ext, align) \
+void ff_vertical_compose53iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width); \
+void ff_vertical_compose_dirac53iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width); \
+void ff_vertical_compose_dd137iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, int width); \
+void ff_vertical_compose_dd97iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, int width); \
+void ff_vertical_compose_haar##ext(IDWTELEM *b0, IDWTELEM *b1, int width); \
+void ff_horizontal_compose_haar0i##ext(IDWTELEM *b, IDWTELEM *tmp, int w);\
+void ff_horizontal_compose_haar1i##ext(IDWTELEM *b, IDWTELEM *tmp, int w);\
+\
+static void vertical_compose53iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width) \
+{ \
+ int i, width_align = width&~(align-1); \
+\
+ for(i=width_align; i<width; i++) \
+ b1[i] = COMPOSE_53iL0(b0[i], b1[i], b2[i]); \
+\
+ ff_vertical_compose53iL0##ext(b0, b1, b2, width_align); \
+} \
+\
+static void vertical_compose_dirac53iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, int width) \
+{ \
+ int i, width_align = width&~(align-1); \
+\
+ for(i=width_align; i<width; i++) \
+ b1[i] = COMPOSE_DIRAC53iH0(b0[i], b1[i], b2[i]); \
+\
+ ff_vertical_compose_dirac53iH0##ext(b0, b1, b2, width_align); \
+} \
+\
+static void vertical_compose_dd137iL0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, \
+ IDWTELEM *b3, IDWTELEM *b4, int width) \
+{ \
+ int i, width_align = width&~(align-1); \
+\
+ for(i=width_align; i<width; i++) \
+ b2[i] = COMPOSE_DD137iL0(b0[i], b1[i], b2[i], b3[i], b4[i]); \
+\
+ ff_vertical_compose_dd137iL0##ext(b0, b1, b2, b3, b4, width_align); \
+} \
+\
+static void vertical_compose_dd97iH0##ext(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, \
+ IDWTELEM *b3, IDWTELEM *b4, int width) \
+{ \
+ int i, width_align = width&~(align-1); \
+\
+ for(i=width_align; i<width; i++) \
+ b2[i] = COMPOSE_DD97iH0(b0[i], b1[i], b2[i], b3[i], b4[i]); \
+\
+ ff_vertical_compose_dd97iH0##ext(b0, b1, b2, b3, b4, width_align); \
+} \
+static void vertical_compose_haar##ext(IDWTELEM *b0, IDWTELEM *b1, int width) \
+{ \
+ int i, width_align = width&~(align-1); \
+\
+ for(i=width_align; i<width; i++) { \
+ b0[i] = COMPOSE_HAARiL0(b0[i], b1[i]); \
+ b1[i] = COMPOSE_HAARiH0(b1[i], b0[i]); \
+ } \
+\
+ ff_vertical_compose_haar##ext(b0, b1, width_align); \
+} \
+static void horizontal_compose_haar0i##ext(IDWTELEM *b, IDWTELEM *tmp, int w)\
+{\
+ int w2= w>>1;\
+ int x= w2 - (w2&(align-1));\
+ ff_horizontal_compose_haar0i##ext(b, tmp, w);\
+\
+ for (; x < w2; x++) {\
+ b[2*x ] = tmp[x];\
+ b[2*x+1] = COMPOSE_HAARiH0(b[x+w2], tmp[x]);\
+ }\
+}\
+static void horizontal_compose_haar1i##ext(IDWTELEM *b, IDWTELEM *tmp, int w)\
+{\
+ int w2= w>>1;\
+ int x= w2 - (w2&(align-1));\
+ ff_horizontal_compose_haar1i##ext(b, tmp, w);\
+\
+ for (; x < w2; x++) {\
+ b[2*x ] = (tmp[x] + 1)>>1;\
+ b[2*x+1] = (COMPOSE_HAARiH0(b[x+w2], tmp[x]) + 1)>>1;\
+ }\
+}\
+\
+
+#if HAVE_YASM
+#if !ARCH_X86_64
+COMPOSE_VERTICAL(_mmx, 4)
+#endif
+COMPOSE_VERTICAL(_sse2, 8)
+
+
+void ff_horizontal_compose_dd97i_ssse3(IDWTELEM *b, IDWTELEM *tmp, int w);
+
+static void horizontal_compose_dd97i_ssse3(IDWTELEM *b, IDWTELEM *tmp, int w)
+{
+ int w2= w>>1;
+ int x= w2 - (w2&7);
+ ff_horizontal_compose_dd97i_ssse3(b, tmp, w);
+
+ for (; x < w2; x++) {
+ b[2*x ] = (tmp[x] + 1)>>1;
+ b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1;
+ }
+}
+#endif
+
+void ff_spatial_idwt_init_mmx(DWTContext *d, enum dwt_type type)
+{
+#if HAVE_YASM
+ int mm_flags = av_get_cpu_flags();
+
+#if !ARCH_X86_64
+ if (!(mm_flags & AV_CPU_FLAG_MMX))
+ return;
+
+ switch (type) {
+ case DWT_DIRAC_DD9_7:
+ d->vertical_compose_l0 = (void*)vertical_compose53iL0_mmx;
+ d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_mmx;
+ break;
+ case DWT_DIRAC_LEGALL5_3:
+ d->vertical_compose_l0 = (void*)vertical_compose53iL0_mmx;
+ d->vertical_compose_h0 = (void*)vertical_compose_dirac53iH0_mmx;
+ break;
+ case DWT_DIRAC_DD13_7:
+ d->vertical_compose_l0 = (void*)vertical_compose_dd137iL0_mmx;
+ d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_mmx;
+ break;
+ case DWT_DIRAC_HAAR0:
+ d->vertical_compose = (void*)vertical_compose_haar_mmx;
+ d->horizontal_compose = horizontal_compose_haar0i_mmx;
+ break;
+ case DWT_DIRAC_HAAR1:
+ d->vertical_compose = (void*)vertical_compose_haar_mmx;
+ d->horizontal_compose = horizontal_compose_haar1i_mmx;
+ break;
+ }
+#endif
+
+ if (!(mm_flags & AV_CPU_FLAG_SSE2))
+ return;
+
+ switch (type) {
+ case DWT_DIRAC_DD9_7:
+ d->vertical_compose_l0 = (void*)vertical_compose53iL0_sse2;
+ d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_sse2;
+ break;
+ case DWT_DIRAC_LEGALL5_3:
+ d->vertical_compose_l0 = (void*)vertical_compose53iL0_sse2;
+ d->vertical_compose_h0 = (void*)vertical_compose_dirac53iH0_sse2;
+ break;
+ case DWT_DIRAC_DD13_7:
+ d->vertical_compose_l0 = (void*)vertical_compose_dd137iL0_sse2;
+ d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_sse2;
+ break;
+ case DWT_DIRAC_HAAR0:
+ d->vertical_compose = (void*)vertical_compose_haar_sse2;
+ d->horizontal_compose = horizontal_compose_haar0i_sse2;
+ break;
+ case DWT_DIRAC_HAAR1:
+ d->vertical_compose = (void*)vertical_compose_haar_sse2;
+ d->horizontal_compose = horizontal_compose_haar1i_sse2;
+ break;
+ }
+
+ if (!(mm_flags & AV_CPU_FLAG_SSSE3))
+ return;
+
+ switch (type) {
+ case DWT_DIRAC_DD9_7:
+ d->horizontal_compose = horizontal_compose_dd97i_ssse3;
+ break;
+ }
+#endif // HAVE_YASM
+}
diff --git a/libavcodec/x86/dirac_dwt.h b/libavcodec/x86/dirac_dwt.h
new file mode 100644
index 0000000000..126b29029f
--- /dev/null
+++ b/libavcodec/x86/dirac_dwt.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_X86_DIRAC_DWT_H
+#define AVCODEC_X86_DIRAC_DWT_H
+
+#include "libavcodec/dirac_dwt.h"
+
+void ff_horizontal_compose_dd97i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x);
+void ff_horizontal_compose_haar1i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x);
+void ff_horizontal_compose_haar0i_end_c(IDWTELEM *b, IDWTELEM *tmp, int w2, int x);
+
+void ff_spatial_idwt_init_mmx(DWTContext *d, enum dwt_type type);
+
+#endif
diff --git a/libavcodec/x86/diracdsp_mmx.c b/libavcodec/x86/diracdsp_mmx.c
new file mode 100644
index 0000000000..11df5e395e
--- /dev/null
+++ b/libavcodec/x86/diracdsp_mmx.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/cpu.h"
+#include "diracdsp_mmx.h"
+#include "fpel.h"
+
+void ff_put_rect_clamped_mmx(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+void ff_put_rect_clamped_sse2(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+void ff_put_signed_rect_clamped_mmx(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+void ff_put_signed_rect_clamped_sse2(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height);
+
+#define HPEL_FILTER(MMSIZE, EXT) \
+ void ff_dirac_hpel_filter_v_ ## EXT(uint8_t *, const uint8_t *, int, int); \
+ void ff_dirac_hpel_filter_h_ ## EXT(uint8_t *, const uint8_t *, int); \
+ \
+ static void dirac_hpel_filter_ ## EXT(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, \
+ const uint8_t *src, int stride, int width, int height) \
+ { \
+ while( height-- ) \
+ { \
+ ff_dirac_hpel_filter_v_ ## EXT(dstv-MMSIZE, src-MMSIZE, stride, width+MMSIZE+5); \
+ ff_dirac_hpel_filter_h_ ## EXT(dsth, src, width); \
+ ff_dirac_hpel_filter_h_ ## EXT(dstc, dstv, width); \
+ \
+ dsth += stride; \
+ dstv += stride; \
+ dstc += stride; \
+ src += stride; \
+ } \
+ }
+
+#if !ARCH_X86_64
+HPEL_FILTER(8, mmx)
+#endif
+HPEL_FILTER(16, sse2)
+
+#define PIXFUNC(PFX, IDX, EXT) \
+ /*MMXDISABLEDc->PFX ## _dirac_pixels_tab[0][IDX] = ff_ ## PFX ## _dirac_pixels8_ ## EXT;*/ \
+ c->PFX ## _dirac_pixels_tab[1][IDX] = ff_ ## PFX ## _dirac_pixels16_ ## EXT; \
+ c->PFX ## _dirac_pixels_tab[2][IDX] = ff_ ## PFX ## _dirac_pixels32_ ## EXT
+
+#define DIRAC_PIXOP(OPNAME2, OPNAME, EXT)\
+void ff_ ## OPNAME2 ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ if (h&3)\
+ ff_ ## OPNAME2 ## _dirac_pixels8_c(dst, src, stride, h);\
+ else\
+ OPNAME ## _pixels8_ ## EXT(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME2 ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ if (h&3)\
+ ff_ ## OPNAME2 ## _dirac_pixels16_c(dst, src, stride, h);\
+ else\
+ OPNAME ## _pixels16_ ## EXT(dst, src[0], stride, h);\
+}\
+void ff_ ## OPNAME2 ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\
+{\
+ if (h&3) {\
+ ff_ ## OPNAME2 ## _dirac_pixels32_c(dst, src, stride, h);\
+ } else {\
+ OPNAME ## _pixels16_ ## EXT(dst , src[0] , stride, h);\
+ OPNAME ## _pixels16_ ## EXT(dst+16, src[0]+16, stride, h);\
+ }\
+}
+
+DIRAC_PIXOP(put, ff_put, mmx)
+DIRAC_PIXOP(avg, ff_avg, mmx)
+DIRAC_PIXOP(avg, ff_avg, mmxext)
+
+void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+ if (h&3)
+ ff_put_dirac_pixels16_c(dst, src, stride, h);
+ else
+ ff_put_pixels16_sse2(dst, src[0], stride, h);
+}
+void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+ if (h&3)
+ ff_avg_dirac_pixels16_c(dst, src, stride, h);
+ else
+ ff_avg_pixels16_sse2(dst, src[0], stride, h);
+}
+void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+ if (h&3) {
+ ff_put_dirac_pixels32_c(dst, src, stride, h);
+ } else {
+ ff_put_pixels16_sse2(dst , src[0] , stride, h);
+ ff_put_pixels16_sse2(dst+16, src[0]+16, stride, h);
+ }
+}
+void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h)
+{
+ if (h&3) {
+ ff_avg_dirac_pixels32_c(dst, src, stride, h);
+ } else {
+ ff_avg_pixels16_sse2(dst , src[0] , stride, h);
+ ff_avg_pixels16_sse2(dst+16, src[0]+16, stride, h);
+ }
+}
+
+void ff_diracdsp_init_mmx(DiracDSPContext* c)
+{
+ int mm_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMX(mm_flags)) {
+ c->add_dirac_obmc[0] = ff_add_dirac_obmc8_mmx;
+#if !ARCH_X86_64
+ c->add_dirac_obmc[1] = ff_add_dirac_obmc16_mmx;
+ c->add_dirac_obmc[2] = ff_add_dirac_obmc32_mmx;
+ c->dirac_hpel_filter = dirac_hpel_filter_mmx;
+ c->add_rect_clamped = ff_add_rect_clamped_mmx;
+ c->put_signed_rect_clamped = ff_put_signed_rect_clamped_mmx;
+#endif
+ PIXFUNC(put, 0, mmx);
+ PIXFUNC(avg, 0, mmx);
+ }
+
+ if (EXTERNAL_MMXEXT(mm_flags)) {
+ PIXFUNC(avg, 0, mmxext);
+ }
+
+ if (EXTERNAL_SSE2(mm_flags)) {
+ c->dirac_hpel_filter = dirac_hpel_filter_sse2;
+ c->add_rect_clamped = ff_add_rect_clamped_sse2;
+ c->put_signed_rect_clamped = ff_put_signed_rect_clamped_sse2;
+
+ c->add_dirac_obmc[1] = ff_add_dirac_obmc16_sse2;
+ c->add_dirac_obmc[2] = ff_add_dirac_obmc32_sse2;
+
+ c->put_dirac_pixels_tab[1][0] = ff_put_dirac_pixels16_sse2;
+ c->avg_dirac_pixels_tab[1][0] = ff_avg_dirac_pixels16_sse2;
+ c->put_dirac_pixels_tab[2][0] = ff_put_dirac_pixels32_sse2;
+ c->avg_dirac_pixels_tab[2][0] = ff_avg_dirac_pixels32_sse2;
+ }
+}
diff --git a/libavcodec/x86/diracdsp_mmx.h b/libavcodec/x86/diracdsp_mmx.h
new file mode 100644
index 0000000000..89858544f3
--- /dev/null
+++ b/libavcodec/x86/diracdsp_mmx.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_X86_DIRACDSP_H
+#define AVCODEC_X86_DIRACDSP_H
+
+#include "libavcodec/diracdsp.h"
+
+void ff_diracdsp_init_mmx(DiracDSPContext* c);
+
+DECL_DIRAC_PIXOP(put, mmx);
+DECL_DIRAC_PIXOP(avg, mmx);
+DECL_DIRAC_PIXOP(avg, mmxext);
+
+void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h);
+
+void ff_add_rect_clamped_mmx(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int);
+void ff_add_rect_clamped_sse2(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int);
+
+void ff_add_dirac_obmc8_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+void ff_add_dirac_obmc16_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+void ff_add_dirac_obmc32_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+
+void ff_add_dirac_obmc16_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+void ff_add_dirac_obmc32_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen);
+
+#endif
diff --git a/libavcodec/x86/diracdsp_yasm.asm b/libavcodec/x86/diracdsp_yasm.asm
new file mode 100644
index 0000000000..d3cf9f1971
--- /dev/null
+++ b/libavcodec/x86/diracdsp_yasm.asm
@@ -0,0 +1,265 @@
+;******************************************************************************
+;* Copyright (c) 2010 David Conrad
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+pw_7: times 8 dw 7
+
+cextern pw_3
+cextern pw_16
+cextern pw_32
+cextern pb_80
+
+section .text
+
+%macro UNPACK_ADD 6
+ mov%5 %1, %3
+ mov%6 m5, %4
+ mova m4, %1
+ mova %2, m5
+ punpcklbw %1, m7
+ punpcklbw m5, m7
+ punpckhbw m4, m7
+ punpckhbw %2, m7
+ paddw %1, m5
+ paddw %2, m4
+%endmacro
+
+%macro HPEL_FILTER 1
+; dirac_hpel_filter_v_sse2(uint8_t *dst, uint8_t *src, int stride, int width);
+cglobal dirac_hpel_filter_v_%1, 4,6,8, dst, src, stride, width, src0, stridex3
+ mov src0q, srcq
+ lea stridex3q, [3*strideq]
+ sub src0q, stridex3q
+ pxor m7, m7
+.loop:
+ ; 7*(src[0] + src[1])
+ UNPACK_ADD m0, m1, [srcq], [srcq + strideq], a,a
+ pmullw m0, [pw_7]
+ pmullw m1, [pw_7]
+
+ ; 3*( ... + src[-2] + src[3])
+ UNPACK_ADD m2, m3, [src0q + strideq], [srcq + stridex3q], a,a
+ paddw m0, m2
+ paddw m1, m3
+ pmullw m0, [pw_3]
+ pmullw m1, [pw_3]
+
+ ; ... - 7*(src[-1] + src[2])
+ UNPACK_ADD m2, m3, [src0q + strideq*2], [srcq + strideq*2], a,a
+ pmullw m2, [pw_7]
+ pmullw m3, [pw_7]
+ psubw m0, m2
+ psubw m1, m3
+
+ ; ... - (src[-3] + src[4])
+ UNPACK_ADD m2, m3, [src0q], [srcq + strideq*4], a,a
+ psubw m0, m2
+ psubw m1, m3
+
+ paddw m0, [pw_16]
+ paddw m1, [pw_16]
+ psraw m0, 5
+ psraw m1, 5
+ packuswb m0, m1
+ mova [dstq], m0
+ add dstq, mmsize
+ add srcq, mmsize
+ add src0q, mmsize
+ sub widthd, mmsize
+ jg .loop
+ RET
+
+; dirac_hpel_filter_h_sse2(uint8_t *dst, uint8_t *src, int width);
+cglobal dirac_hpel_filter_h_%1, 3,3,8, dst, src, width
+ dec widthd
+ pxor m7, m7
+ and widthd, ~(mmsize-1)
+.loop:
+ ; 7*(src[0] + src[1])
+ UNPACK_ADD m0, m1, [srcq + widthq], [srcq + widthq + 1], u,u
+ pmullw m0, [pw_7]
+ pmullw m1, [pw_7]
+
+ ; 3*( ... + src[-2] + src[3])
+ UNPACK_ADD m2, m3, [srcq + widthq - 2], [srcq + widthq + 3], u,u
+ paddw m0, m2
+ paddw m1, m3
+ pmullw m0, [pw_3]
+ pmullw m1, [pw_3]
+
+ ; ... - 7*(src[-1] + src[2])
+ UNPACK_ADD m2, m3, [srcq + widthq - 1], [srcq + widthq + 2], u,u
+ pmullw m2, [pw_7]
+ pmullw m3, [pw_7]
+ psubw m0, m2
+ psubw m1, m3
+
+ ; ... - (src[-3] + src[4])
+ UNPACK_ADD m2, m3, [srcq + widthq - 3], [srcq + widthq + 4], u,u
+ psubw m0, m2
+ psubw m1, m3
+
+ paddw m0, [pw_16]
+ paddw m1, [pw_16]
+ psraw m0, 5
+ psraw m1, 5
+ packuswb m0, m1
+ mova [dstq + widthq], m0
+ sub widthd, mmsize
+ jge .loop
+ RET
+%endmacro
+
+%macro PUT_RECT 1
+; void put_rect_clamped(uint8_t *dst, int dst_stride, int16_t *src, int src_stride, int width, int height)
+cglobal put_signed_rect_clamped_%1, 5,9,3, dst, dst_stride, src, src_stride, w, dst2, src2
+ mova m0, [pb_80]
+ add wd, (mmsize-1)
+ and wd, ~(mmsize-1)
+
+%if ARCH_X86_64
+ movsxd dst_strideq, dst_strided
+ movsxd src_strideq, src_strided
+ mov r7d, r5m
+ mov r8d, wd
+ %define wspill r8d
+ %define hd r7d
+%else
+ mov r4m, wd
+ %define wspill r4m
+ %define hd r5mp
+%endif
+
+.loopy
+ lea src2q, [srcq+src_strideq*2]
+ lea dst2q, [dstq+dst_strideq]
+.loopx:
+ sub wd, mmsize
+ mova m1, [srcq +2*wq]
+ mova m2, [src2q+2*wq]
+ packsswb m1, [srcq +2*wq+mmsize]
+ packsswb m2, [src2q+2*wq+mmsize]
+ paddb m1, m0
+ paddb m2, m0
+ mova [dstq +wq], m1
+ mova [dst2q+wq], m2
+ jg .loopx
+
+ lea srcq, [srcq+src_strideq*4]
+ lea dstq, [dstq+dst_strideq*2]
+ sub hd, 2
+ mov wd, wspill
+ jg .loopy
+ RET
+%endm
+
+%macro ADD_RECT 1
+; void add_rect_clamped(uint8_t *dst, uint16_t *src, int stride, int16_t *idwt, int idwt_stride, int width, int height)
+cglobal add_rect_clamped_%1, 7,9,3, dst, src, stride, idwt, idwt_stride, w, h
+ mova m0, [pw_32]
+ add wd, (mmsize-1)
+ and wd, ~(mmsize-1)
+
+%if ARCH_X86_64
+ movsxd strideq, strided
+ movsxd idwt_strideq, idwt_strided
+ mov r8d, wd
+ %define wspill r8d
+%else
+ mov r5m, wd
+ %define wspill r5m
+%endif
+
+.loop:
+ sub wd, mmsize
+ movu m1, [srcq +2*wq] ; FIXME: ensure alignment
+ paddw m1, m0
+ psraw m1, 6
+ movu m2, [srcq +2*wq+mmsize] ; FIXME: ensure alignment
+ paddw m2, m0
+ psraw m2, 6
+ paddw m1, [idwtq+2*wq]
+ paddw m2, [idwtq+2*wq+mmsize]
+ packuswb m1, m2
+ mova [dstq +wq], m1
+ jg .loop
+
+ lea srcq, [srcq + 2*strideq]
+ add dstq, strideq
+ lea idwtq, [idwtq+ 2*idwt_strideq]
+ sub hd, 1
+ mov wd, wspill
+ jg .loop
+ RET
+%endm
+
+%macro ADD_OBMC 2
+; void add_obmc(uint16_t *dst, uint8_t *src, int stride, uint8_t *obmc_weight, int yblen)
+cglobal add_dirac_obmc%1_%2, 6,6,5, dst, src, stride, obmc, yblen
+ pxor m4, m4
+.loop:
+%assign i 0
+%rep %1 / mmsize
+ mova m0, [srcq+i]
+ mova m1, m0
+ punpcklbw m0, m4
+ punpckhbw m1, m4
+ mova m2, [obmcq+i]
+ mova m3, m2
+ punpcklbw m2, m4
+ punpckhbw m3, m4
+ pmullw m0, m2
+ pmullw m1, m3
+ movu m2, [dstq+2*i]
+ movu m3, [dstq+2*i+mmsize]
+ paddw m0, m2
+ paddw m1, m3
+ movu [dstq+2*i], m0
+ movu [dstq+2*i+mmsize], m1
+%assign i i+mmsize
+%endrep
+ lea srcq, [srcq+strideq]
+ lea dstq, [dstq+2*strideq]
+ add obmcq, 32
+ sub yblend, 1
+ jg .loop
+ RET
+%endm
+
+INIT_MMX
+%if ARCH_X86_64 == 0
+PUT_RECT mmx
+ADD_RECT mmx
+
+HPEL_FILTER mmx
+ADD_OBMC 32, mmx
+ADD_OBMC 16, mmx
+%endif
+ADD_OBMC 8, mmx
+
+INIT_XMM
+PUT_RECT sse2
+ADD_RECT sse2
+
+HPEL_FILTER sse2
+ADD_OBMC 32, sse2
+ADD_OBMC 16, sse2
diff --git a/libavcodec/x86/dnxhdenc.asm b/libavcodec/x86/dnxhdenc.asm
index d39b07b9f4..9dd6d51ee6 100644
--- a/libavcodec/x86/dnxhdenc.asm
+++ b/libavcodec/x86/dnxhdenc.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
;* Copyright (c) 2014 Tiancheng "Timothy" Gu <timothygu99@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/dnxhdenc_init.c b/libavcodec/x86/dnxhdenc_init.c
index f1ff7bd986..fd6f15005a 100644
--- a/libavcodec/x86/dnxhdenc_init.c
+++ b/libavcodec/x86/dnxhdenc_init.c
@@ -4,20 +4,20 @@
*
* VC-3 encoder funded by the British Broadcasting Corporation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/dwt_yasm.asm b/libavcodec/x86/dwt_yasm.asm
new file mode 100644
index 0000000000..658acc13fc
--- /dev/null
+++ b/libavcodec/x86/dwt_yasm.asm
@@ -0,0 +1,307 @@
+;******************************************************************************
+;* MMX optimized discrete wavelet trasnform
+;* Copyright (c) 2010 David Conrad
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+pw_1991: times 4 dw 9,-1
+
+cextern pw_1
+cextern pw_2
+cextern pw_8
+cextern pw_16
+
+section .text
+
+; %1 -= (%2 + %3 + 2)>>2 %4 is pw_2
+%macro COMPOSE_53iL0 4
+ paddw %2, %3
+ paddw %2, %4
+ psraw %2, 2
+ psubw %1, %2
+%endm
+
+; m1 = %1 + (-m0 + 9*m1 + 9*%2 -%3 + 8)>>4
+; if %4 is supplied, %1 is loaded unaligned from there
+; m2: clobbered m3: pw_8 m4: pw_1991
+%macro COMPOSE_DD97iH0 3-4
+ paddw m0, %3
+ paddw m1, %2
+ psubw m0, m3
+ mova m2, m1
+ punpcklwd m1, m0
+ punpckhwd m2, m0
+ pmaddwd m1, m4
+ pmaddwd m2, m4
+%if %0 > 3
+ movu %1, %4
+%endif
+ psrad m1, 4
+ psrad m2, 4
+ packssdw m1, m2
+ paddw m1, %1
+%endm
+
+%macro COMPOSE_VERTICAL 1
+; void vertical_compose53iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+; int width)
+cglobal vertical_compose53iL0_%1, 4,4,1, b0, b1, b2, width
+ mova m2, [pw_2]
+%if ARCH_X86_64
+ mov widthd, widthd
+%endif
+.loop:
+ sub widthq, mmsize/2
+ mova m1, [b0q+2*widthq]
+ mova m0, [b1q+2*widthq]
+ COMPOSE_53iL0 m0, m1, [b2q+2*widthq], m2
+ mova [b1q+2*widthq], m0
+ jg .loop
+ REP_RET
+
+; void vertical_compose_dirac53iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+; int width)
+cglobal vertical_compose_dirac53iH0_%1, 4,4,1, b0, b1, b2, width
+ mova m1, [pw_1]
+%if ARCH_X86_64
+ mov widthd, widthd
+%endif
+.loop:
+ sub widthq, mmsize/2
+ mova m0, [b0q+2*widthq]
+ paddw m0, [b2q+2*widthq]
+ paddw m0, m1
+ psraw m0, 1
+ paddw m0, [b1q+2*widthq]
+ mova [b1q+2*widthq], m0
+ jg .loop
+ REP_RET
+
+; void vertical_compose_dd97iH0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+; IDWTELEM *b3, IDWTELEM *b4, int width)
+cglobal vertical_compose_dd97iH0_%1, 6,6,5, b0, b1, b2, b3, b4, width
+ mova m3, [pw_8]
+ mova m4, [pw_1991]
+%if ARCH_X86_64
+ mov widthd, widthd
+%endif
+.loop:
+ sub widthq, mmsize/2
+ mova m0, [b0q+2*widthq]
+ mova m1, [b1q+2*widthq]
+ COMPOSE_DD97iH0 [b2q+2*widthq], [b3q+2*widthq], [b4q+2*widthq]
+ mova [b2q+2*widthq], m1
+ jg .loop
+ REP_RET
+
+; void vertical_compose_dd137iL0(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2,
+; IDWTELEM *b3, IDWTELEM *b4, int width)
+cglobal vertical_compose_dd137iL0_%1, 6,6,6, b0, b1, b2, b3, b4, width
+ mova m3, [pw_16]
+ mova m4, [pw_1991]
+%if ARCH_X86_64
+ mov widthd, widthd
+%endif
+.loop:
+ sub widthq, mmsize/2
+ mova m0, [b0q+2*widthq]
+ mova m1, [b1q+2*widthq]
+ mova m5, [b2q+2*widthq]
+ paddw m0, [b4q+2*widthq]
+ paddw m1, [b3q+2*widthq]
+ psubw m0, m3
+ mova m2, m1
+ punpcklwd m1, m0
+ punpckhwd m2, m0
+ pmaddwd m1, m4
+ pmaddwd m2, m4
+ psrad m1, 5
+ psrad m2, 5
+ packssdw m1, m2
+ psubw m5, m1
+ mova [b2q+2*widthq], m5
+ jg .loop
+ REP_RET
+
+; void vertical_compose_haar(IDWTELEM *b0, IDWTELEM *b1, int width)
+cglobal vertical_compose_haar_%1, 3,4,3, b0, b1, width
+ mova m3, [pw_1]
+%if ARCH_X86_64
+ mov widthd, widthd
+%endif
+.loop:
+ sub widthq, mmsize/2
+ mova m1, [b1q+2*widthq]
+ mova m0, [b0q+2*widthq]
+ mova m2, m1
+ paddw m1, m3
+ psraw m1, 1
+ psubw m0, m1
+ mova [b0q+2*widthq], m0
+ paddw m2, m0
+ mova [b1q+2*widthq], m2
+ jg .loop
+ REP_RET
+%endmacro
+
+; extend the left and right edges of the tmp array by %1 and %2 respectively
+%macro EDGE_EXTENSION 3
+ mov %3, [tmpq]
+%assign %%i 1
+%rep %1
+ mov [tmpq-2*%%i], %3
+ %assign %%i %%i+1
+%endrep
+ mov %3, [tmpq+2*w2q-2]
+%assign %%i 0
+%rep %2
+ mov [tmpq+2*w2q+2*%%i], %3
+ %assign %%i %%i+1
+%endrep
+%endmacro
+
+
+%macro HAAR_HORIZONTAL 2
+; void horizontal_compose_haari(IDWTELEM *b, IDWTELEM *tmp, int width)
+cglobal horizontal_compose_haar%2i_%1, 3,6,4, b, tmp, w, x, w2, b_w2
+ mov w2d, wd
+ xor xq, xq
+ shr w2d, 1
+ lea b_w2q, [bq+wq]
+ mova m3, [pw_1]
+.lowpass_loop:
+ movu m1, [b_w2q + 2*xq]
+ mova m0, [bq + 2*xq]
+ paddw m1, m3
+ psraw m1, 1
+ psubw m0, m1
+ mova [tmpq + 2*xq], m0
+ add xq, mmsize/2
+ cmp xq, w2q
+ jl .lowpass_loop
+
+ xor xq, xq
+ and w2q, ~(mmsize/2 - 1)
+ cmp w2q, mmsize/2
+ jl .end
+
+.highpass_loop:
+ movu m1, [b_w2q + 2*xq]
+ mova m0, [tmpq + 2*xq]
+ paddw m1, m0
+
+ ; shift and interleave
+%if %2 == 1
+ paddw m0, m3
+ paddw m1, m3
+ psraw m0, 1
+ psraw m1, 1
+%endif
+ mova m2, m0
+ punpcklwd m0, m1
+ punpckhwd m2, m1
+ mova [bq+4*xq], m0
+ mova [bq+4*xq+mmsize], m2
+
+ add xq, mmsize/2
+ cmp xq, w2q
+ jl .highpass_loop
+.end:
+ REP_RET
+%endmacro
+
+
+INIT_XMM
+; void horizontal_compose_dd97i(IDWTELEM *b, IDWTELEM *tmp, int width)
+cglobal horizontal_compose_dd97i_ssse3, 3,6,8, b, tmp, w, x, w2, b_w2
+ mov w2d, wd
+ xor xd, xd
+ shr w2d, 1
+ lea b_w2q, [bq+wq]
+ movu m4, [bq+wq]
+ mova m7, [pw_2]
+ pslldq m4, 14
+.lowpass_loop:
+ movu m1, [b_w2q + 2*xq]
+ mova m0, [bq + 2*xq]
+ mova m2, m1
+ palignr m1, m4, 14
+ mova m4, m2
+ COMPOSE_53iL0 m0, m1, m2, m7
+ mova [tmpq + 2*xq], m0
+ add xd, mmsize/2
+ cmp xd, w2d
+ jl .lowpass_loop
+
+ EDGE_EXTENSION 1, 2, xw
+ ; leave the last up to 7 (sse) or 3 (mmx) values for C
+ xor xd, xd
+ and w2d, ~(mmsize/2 - 1)
+ cmp w2d, mmsize/2
+ jl .end
+
+ mova m7, [tmpq-mmsize]
+ mova m0, [tmpq]
+ mova m5, [pw_1]
+ mova m3, [pw_8]
+ mova m4, [pw_1991]
+.highpass_loop:
+ mova m6, m0
+ palignr m0, m7, 14
+ mova m7, [tmpq + 2*xq + 16]
+ mova m1, m7
+ mova m2, m7
+ palignr m1, m6, 2
+ palignr m2, m6, 4
+ COMPOSE_DD97iH0 m0, m6, m2, [b_w2q + 2*xq]
+ mova m0, m7
+ mova m7, m6
+
+ ; shift and interleave
+ paddw m6, m5
+ paddw m1, m5
+ psraw m6, 1
+ psraw m1, 1
+ mova m2, m6
+ punpcklwd m6, m1
+ punpckhwd m2, m1
+ mova [bq+4*xq], m6
+ mova [bq+4*xq+mmsize], m2
+
+ add xd, mmsize/2
+ cmp xd, w2d
+ jl .highpass_loop
+.end:
+ REP_RET
+
+
+%if ARCH_X86_64 == 0
+INIT_MMX
+COMPOSE_VERTICAL mmx
+HAAR_HORIZONTAL mmx, 0
+HAAR_HORIZONTAL mmx, 1
+%endif
+
+;;INIT_XMM
+INIT_XMM
+COMPOSE_VERTICAL sse2
+HAAR_HORIZONTAL sse2, 0
+HAAR_HORIZONTAL sse2, 1
diff --git a/libavcodec/x86/fdct.c b/libavcodec/x86/fdct.c
index 6528b57361..112566ded0 100644
--- a/libavcodec/x86/fdct.c
+++ b/libavcodec/x86/fdct.c
@@ -13,20 +13,20 @@
* a page about fdct at http://www.geocities.com/ssavekar/dct.htm
* Skal's fdct at http://skal.planet-d.net/coding/dct.html
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -70,7 +70,7 @@ DECLARE_ALIGNED(16, static const int16_t, fdct_one_corr)[8] = { X8(1) };
DECLARE_ALIGNED(8, static const int32_t, fdct_r_row)[2] = {RND_FRW_ROW, RND_FRW_ROW };
-static struct
+static const struct
{
DECLARE_ALIGNED(16, const int32_t, fdct_r_row_sse2)[4];
} fdct_r_row_sse2 =
@@ -153,7 +153,7 @@ DECLARE_ALIGNED(8, static const int16_t, tab_frw_01234567)[] = { // forward_dct
29692, -12299, 26722, -31521,
};
-static struct
+static const struct
{
DECLARE_ALIGNED(16, const int16_t, tab_frw_01234567_sse2)[256];
} tab_frw_01234567_sse2 =
diff --git a/libavcodec/x86/fdct.h b/libavcodec/x86/fdct.h
index c94a977e8f..648cdc5350 100644
--- a/libavcodec/x86/fdct.h
+++ b/libavcodec/x86/fdct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/fdctdsp_init.c b/libavcodec/x86/fdctdsp_init.c
index 4e8e4eb60d..0cb5fd625b 100644
--- a/libavcodec/x86/fdctdsp_init.c
+++ b/libavcodec/x86/fdctdsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/fft.asm b/libavcodec/x86/fft.asm
index e4744a3b60..877997e7a6 100644
--- a/libavcodec/x86/fft.asm
+++ b/libavcodec/x86/fft.asm
@@ -6,20 +6,20 @@
;* This algorithm (though not any of the implementation details) is
;* based on libdjbfft by D. J. Bernstein.
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -36,6 +36,8 @@
%define pointer resd
%endif
+SECTION_RODATA 32
+
struc FFTContext
.nbits: resd 1
.reverse: resd 1
@@ -51,13 +53,10 @@ struc FFTContext
.imdcthalf:pointer 1
endstruc
-SECTION_RODATA
-
%define M_SQRT1_2 0.70710678118654752440
%define M_COS_PI_1_8 0.923879532511287
%define M_COS_PI_3_8 0.38268343236509
-align 32
ps_cos16_1: dd 1.0, M_COS_PI_1_8, M_SQRT1_2, M_COS_PI_3_8, 1.0, M_COS_PI_1_8, M_SQRT1_2, M_COS_PI_3_8
ps_cos16_2: dd 0, M_COS_PI_3_8, M_SQRT1_2, M_COS_PI_1_8, 0, -M_COS_PI_3_8, -M_SQRT1_2, -M_COS_PI_1_8
@@ -69,9 +68,10 @@ perm1: dd 0x00, 0x02, 0x03, 0x01, 0x03, 0x00, 0x02, 0x01
perm2: dd 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x02, 0x03
ps_p1p1m1p1root2: dd 1.0, 1.0, -1.0, 1.0, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2
ps_m1m1p1m1p1m1m1m1: dd 1<<31, 1<<31, 0, 1<<31, 0, 1<<31, 1<<31, 1<<31
-ps_m1m1m1m1: times 4 dd 1<<31
ps_m1p1: dd 1<<31, 0
+cextern ps_neg
+
%assign i 16
%rep 13
cextern cos_ %+ i
@@ -305,6 +305,7 @@ IF%1 mova Z(1), m5
INIT_YMM avx
+%if HAVE_AVX_EXTERNAL
align 16
fft8_avx:
mova m0, Z(0)
@@ -394,6 +395,8 @@ fft32_interleave_avx:
jg .deint_loop
ret
+%endif
+
INIT_XMM sse
align 16
@@ -537,6 +540,7 @@ DEFINE_ARGS zc, w, n, o1, o3
INIT_YMM avx
+%if HAVE_AVX_EXTERNAL
%macro INTERL_AVX 5
vunpckhps %3, %2, %1
vunpcklps %2, %2, %1
@@ -558,6 +562,7 @@ cglobal fft_calc, 2,5,8
FFT_DISPATCH _interleave %+ SUFFIX, r1
REP_RET
+%endif
INIT_XMM sse
@@ -681,7 +686,7 @@ cglobal imdct_calc, 3,5,3
mov r2, r3
sub r3, mmsize
neg r2
- mova m2, [ps_m1m1m1m1]
+ mova m2, [ps_neg]
.loop:
%if mmsize == 8
PSWAPD m0, [r1 + r3]
@@ -776,9 +781,11 @@ align 8
dispatch_tab %+ fullsuffix: pointer list_of_fft
%endmacro ; DECL_FFT
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
DECL_FFT 6
DECL_FFT 6, _interleave
+%endif
INIT_XMM sse
DECL_FFT 5
DECL_FFT 5, _interleave
@@ -992,7 +999,7 @@ cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *i
sub r4, r3
%endif
%if notcpuflag(3dnowext) && mmsize == 8
- movd m7, [ps_m1m1m1m1]
+ movd m7, [ps_neg]
%endif
.pre:
%if ARCH_X86_64 == 0
@@ -1080,4 +1087,7 @@ DECL_IMDCT POSROTATESHUF_3DNOW
%endif
INIT_YMM avx
+
+%if HAVE_AVX_EXTERNAL
DECL_IMDCT POSROTATESHUF_AVX
+%endif
diff --git a/libavcodec/x86/fft.h b/libavcodec/x86/fft.h
index a604956836..398091eb1f 100644
--- a/libavcodec/x86/fft.h
+++ b/libavcodec/x86/fft.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/fft_init.c b/libavcodec/x86/fft_init.c
index 7ca72c54a4..5682230c8e 100644
--- a/libavcodec/x86/fft_init.c
+++ b/libavcodec/x86/fft_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/flac_dsp_gpl.asm b/libavcodec/x86/flac_dsp_gpl.asm
new file mode 100644
index 0000000000..cedf0837a7
--- /dev/null
+++ b/libavcodec/x86/flac_dsp_gpl.asm
@@ -0,0 +1,101 @@
+;******************************************************************************
+;* FLAC DSP functions
+;*
+;* Copyright (c) 2014 James Darnley <james.darnley@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 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/x86/x86util.asm"
+
+SECTION_TEXT
+
+INIT_XMM sse4
+%if ARCH_X86_64
+ cglobal flac_enc_lpc_16, 5, 7, 8, 0, res, smp, len, order, coefs
+ DECLARE_REG_TMP 5, 6
+ %define length r2d
+
+ movsxd orderq, orderd
+%else
+ cglobal flac_enc_lpc_16, 5, 6, 8, 0, res, smp, len, order, coefs
+ DECLARE_REG_TMP 2, 5
+ %define length r2mp
+%endif
+
+; Here we assume that the maximum order value is 32. This means that we only
+; need to copy a maximum of 32 samples. Therefore we let the preprocessor
+; unroll this loop and copy all 32.
+%assign iter 0
+%rep 32/(mmsize/4)
+ movu m0, [smpq+iter]
+ movu [resq+iter], m0
+ %assign iter iter+mmsize
+%endrep
+
+lea resq, [resq+orderq*4]
+lea smpq, [smpq+orderq*4]
+lea coefsq, [coefsq+orderq*4]
+sub length, orderd
+movd m3, r5m
+neg orderq
+
+%define posj t0q
+%define negj t1q
+
+.looplen:
+ pxor m0, m0
+ pxor m4, m4
+ pxor m6, m6
+ mov posj, orderq
+ xor negj, negj
+
+ .looporder:
+ movd m2, [coefsq+posj*4] ; c = coefs[j]
+ SPLATD m2
+ movu m1, [smpq+negj*4-4] ; s = smp[i-j-1]
+ movu m5, [smpq+negj*4-4+mmsize]
+ movu m7, [smpq+negj*4-4+mmsize*2]
+ pmulld m1, m2
+ pmulld m5, m2
+ pmulld m7, m2
+ paddd m0, m1 ; p += c * s
+ paddd m4, m5
+ paddd m6, m7
+
+ dec negj
+ inc posj
+ jnz .looporder
+
+ psrad m0, m3 ; p >>= shift
+ psrad m4, m3
+ psrad m6, m3
+ movu m1, [smpq]
+ movu m5, [smpq+mmsize]
+ movu m7, [smpq+mmsize*2]
+ psubd m1, m0 ; smp[i] - p
+ psubd m5, m4
+ psubd m7, m6
+ movu [resq], m1 ; res[i] = smp[i] - (p >> shift)
+ movu [resq+mmsize], m5
+ movu [resq+mmsize*2], m7
+
+ add resq, 3*mmsize
+ add smpq, 3*mmsize
+ sub length, (3*mmsize)/4
+jg .looplen
+RET
diff --git a/libavcodec/x86/flacdsp.asm b/libavcodec/x86/flacdsp.asm
new file mode 100644
index 0000000000..901c440ccd
--- /dev/null
+++ b/libavcodec/x86/flacdsp.asm
@@ -0,0 +1,304 @@
+;******************************************************************************
+;* FLAC DSP SIMD optimizations
+;*
+;* Copyright (C) 2014 Loren Merritt
+;* Copyright (C) 2014 James Almer
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION .text
+
+%macro LPC_32 1
+INIT_XMM %1
+cglobal flac_lpc_32, 5,6,5, decoded, coeffs, pred_order, qlevel, len, j
+ sub lend, pred_orderd
+ jle .ret
+ lea decodedq, [decodedq+pred_orderq*4-8]
+ lea coeffsq, [coeffsq+pred_orderq*4]
+ neg pred_orderq
+ movd m4, qlevelm
+ALIGN 16
+.loop_sample:
+ movd m0, [decodedq+pred_orderq*4+8]
+ add decodedq, 8
+ movd m1, [coeffsq+pred_orderq*4]
+ pxor m2, m2
+ pxor m3, m3
+ lea jq, [pred_orderq+1]
+ test jq, jq
+ jz .end_order
+.loop_order:
+ PMACSDQL m2, m0, m1, m2, m0
+ movd m0, [decodedq+jq*4]
+ PMACSDQL m3, m1, m0, m3, m1
+ movd m1, [coeffsq+jq*4]
+ inc jq
+ jl .loop_order
+.end_order:
+ PMACSDQL m2, m0, m1, m2, m0
+ psrlq 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
+ movd m1, [decodedq+4]
+ paddd m1, m3
+ movd [decodedq+4], m1
+ jg .loop_sample
+.ret:
+ REP_RET
+%endmacro
+
+%if HAVE_XOP_EXTERNAL
+LPC_32 xop
+%endif
+LPC_32 sse4
+
+;----------------------------------------------------------------------------------
+;void ff_flac_decorrelate_[lrm]s_16_sse2(uint8_t **out, int32_t **in, int channels,
+; int len, int shift);
+;----------------------------------------------------------------------------------
+%macro FLAC_DECORRELATE_16 3-4
+cglobal flac_decorrelate_%1_16, 2, 4, 4, out, in0, in1, len
+%if ARCH_X86_32
+ mov lend, lenm
+%endif
+ movd m3, r4m
+ shl lend, 2
+ mov in1q, [in0q + gprsize]
+ mov in0q, [in0q]
+ mov outq, [outq]
+ add in1q, lenq
+ add in0q, lenq
+ add outq, lenq
+ neg lenq
+
+align 16
+.loop:
+ mova m0, [in0q + lenq]
+ mova m1, [in1q + lenq]
+%ifidn %1, ms
+ psrad m2, m1, 1
+ psubd m0, m2
+%endif
+%ifnidn %1, indep2
+ p%4d m2, m0, m1
+%endif
+ packssdw m%2, m%2
+ packssdw m%3, m%3
+ punpcklwd m%2, m%3
+ psllw m%2, m3
+ mova [outq + lenq], m%2
+ add lenq, 16
+ jl .loop
+ REP_RET
+%endmacro
+
+INIT_XMM sse2
+FLAC_DECORRELATE_16 ls, 0, 2, sub
+FLAC_DECORRELATE_16 rs, 2, 1, add
+FLAC_DECORRELATE_16 ms, 2, 0, add
+
+;----------------------------------------------------------------------------------
+;void ff_flac_decorrelate_[lrm]s_32_sse2(uint8_t **out, int32_t **in, int channels,
+; int len, int shift);
+;----------------------------------------------------------------------------------
+%macro FLAC_DECORRELATE_32 5
+cglobal flac_decorrelate_%1_32, 2, 4, 4, out, in0, in1, len
+%if ARCH_X86_32
+ mov lend, lenm
+%endif
+ movd m3, r4m
+ mov in1q, [in0q + gprsize]
+ mov in0q, [in0q]
+ mov outq, [outq]
+ sub in1q, in0q
+
+align 16
+.loop:
+ mova m0, [in0q]
+ mova m1, [in0q + in1q]
+%ifidn %1, ms
+ psrad m2, m1, 1
+ psubd m0, m2
+%endif
+ p%5d m2, m0, m1
+ pslld m%2, m3
+ pslld m%3, m3
+
+ SBUTTERFLY dq, %2, %3, %4
+
+ mova [outq ], m%2
+ mova [outq + mmsize], m%3
+
+ add in0q, mmsize
+ add outq, mmsize*2
+ sub lend, mmsize/4
+ jg .loop
+ REP_RET
+%endmacro
+
+INIT_XMM sse2
+FLAC_DECORRELATE_32 ls, 0, 2, 1, sub
+FLAC_DECORRELATE_32 rs, 2, 1, 0, add
+FLAC_DECORRELATE_32 ms, 2, 0, 1, add
+
+;-----------------------------------------------------------------------------------------
+;void ff_flac_decorrelate_indep<ch>_<bps>_<opt>(uint8_t **out, int32_t **in, int channels,
+; int len, int shift);
+;-----------------------------------------------------------------------------------------
+;%1 = bps
+;%2 = channels
+;%3 = last xmm reg used
+;%4 = word/dword (shift instruction)
+%macro FLAC_DECORRELATE_INDEP 4
+%define REPCOUNT %2/(32/%1) ; 16bits = channels / 2; 32bits = channels
+cglobal flac_decorrelate_indep%2_%1, 2, %2+2, %3+1, out, in0, in1, len, in2, in3, in4, in5, in6, in7
+%if ARCH_X86_32
+%if %2 == 6
+ DEFINE_ARGS out, in0, in1, in2, in3, in4, in5
+ %define lend dword r3m
+%else
+ mov lend, lenm
+%endif
+%endif
+ movd m%3, r4m
+
+%assign %%i 1
+%rep %2-1
+ mov in %+ %%i %+ q, [in0q+%%i*gprsize]
+%assign %%i %%i+1
+%endrep
+
+ mov in0q, [in0q]
+ mov outq, [outq]
+
+%assign %%i 1
+%rep %2-1
+ sub in %+ %%i %+ q, in0q
+%assign %%i %%i+1
+%endrep
+
+align 16
+.loop:
+ mova m0, [in0q]
+
+%assign %%i 1
+%rep REPCOUNT-1
+ mova m %+ %%i, [in0q + in %+ %%i %+ q]
+%assign %%i %%i+1
+%endrep
+
+%if %1 == 32
+
+%if %2 == 8
+ TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, 8
+%elif %2 == 6
+ SBUTTERFLY dq, 0, 1, 6
+ SBUTTERFLY dq, 2, 3, 6
+ SBUTTERFLY dq, 4, 5, 6
+
+ punpcklqdq m6, m0, m2
+ punpckhqdq m2, m4
+ shufps m4, m0, 0xe4
+ punpcklqdq m0, m1, m3
+ punpckhqdq m3, m5
+ shufps m5, m1, 0xe4
+ SWAP 0,6,1,4,5,3
+%elif %2 == 4
+ TRANSPOSE4x4D 0, 1, 2, 3, 4
+%else ; %2 == 2
+ SBUTTERFLY dq, 0, 1, 2
+%endif
+
+%else ; %1 == 16
+
+%if %2 == 8
+ packssdw m0, [in0q + in4q]
+ packssdw m1, [in0q + in5q]
+ packssdw m2, [in0q + in6q]
+ packssdw m3, [in0q + in7q]
+ TRANSPOSE2x4x4W 0, 1, 2, 3, 4
+%elif %2 == 6
+ packssdw m0, [in0q + in3q]
+ packssdw m1, [in0q + in4q]
+ packssdw m2, [in0q + in5q]
+ pshufd m3, m0, q1032
+ punpcklwd m0, m1
+ punpckhwd m1, m2
+ punpcklwd m2, m3
+
+ shufps m3, m0, m2, q2020
+ shufps m0, m1, q2031
+ shufps m2, m1, q3131
+ shufps m1, m2, m3, q3120
+ shufps m3, m0, q0220
+ shufps m0, m2, q3113
+ SWAP 2, 0, 3
+%else ; %2 == 4
+ packssdw m0, [in0q + in2q]
+ packssdw m1, [in0q + in3q]
+ SBUTTERFLY wd, 0, 1, 2
+ SBUTTERFLY dq, 0, 1, 2
+%endif
+
+%endif
+
+%assign %%i 0
+%rep REPCOUNT
+ psll%4 m %+ %%i, m%3
+%assign %%i %%i+1
+%endrep
+
+%assign %%i 0
+%rep REPCOUNT
+ mova [outq + %%i*mmsize], m %+ %%i
+%assign %%i %%i+1
+%endrep
+
+ add in0q, mmsize
+ add outq, mmsize*REPCOUNT
+ sub lend, mmsize/4
+ jg .loop
+ REP_RET
+%endmacro
+
+INIT_XMM sse2
+FLAC_DECORRELATE_16 indep2, 0, 1 ; Reuse stereo 16bits macro
+FLAC_DECORRELATE_INDEP 32, 2, 3, d
+FLAC_DECORRELATE_INDEP 16, 4, 3, w
+FLAC_DECORRELATE_INDEP 32, 4, 5, d
+FLAC_DECORRELATE_INDEP 16, 6, 4, w
+FLAC_DECORRELATE_INDEP 32, 6, 7, d
+%if ARCH_X86_64
+FLAC_DECORRELATE_INDEP 16, 8, 5, w
+FLAC_DECORRELATE_INDEP 32, 8, 9, d
+%endif
+
+INIT_XMM avx
+FLAC_DECORRELATE_INDEP 32, 4, 5, d
+FLAC_DECORRELATE_INDEP 32, 6, 7, d
+%if ARCH_X86_64
+FLAC_DECORRELATE_INDEP 16, 8, 5, w
+FLAC_DECORRELATE_INDEP 32, 8, 9, d
+%endif
diff --git a/libavcodec/x86/flacdsp_init.c b/libavcodec/x86/flacdsp_init.c
new file mode 100644
index 0000000000..e28c5c9322
--- /dev/null
+++ b/libavcodec/x86/flacdsp_init.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/flacdsp.h"
+#include "libavutil/x86/cpu.h"
+#include "config.h"
+
+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_enc_lpc_16_sse4(int32_t *, const int32_t *, int, int, const int32_t *,int);
+
+#define DECORRELATE_FUNCS(fmt, opt) \
+void ff_flac_decorrelate_ls_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift); \
+void ff_flac_decorrelate_rs_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift); \
+void ff_flac_decorrelate_ms_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift); \
+void ff_flac_decorrelate_indep2_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift); \
+void ff_flac_decorrelate_indep4_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift); \
+void ff_flac_decorrelate_indep6_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift); \
+void ff_flac_decorrelate_indep8_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \
+ int len, int shift)
+
+DECORRELATE_FUNCS(16, sse2);
+DECORRELATE_FUNCS(16, avx);
+DECORRELATE_FUNCS(32, sse2);
+DECORRELATE_FUNCS(32, avx);
+
+av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int channels,
+ int bps)
+{
+#if HAVE_YASM
+ int cpu_flags = av_get_cpu_flags();
+
+#if CONFIG_FLAC_DECODER
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ if (fmt == AV_SAMPLE_FMT_S16) {
+ if (channels == 2)
+ c->decorrelate[0] = ff_flac_decorrelate_indep2_16_sse2;
+ else if (channels == 4)
+ c->decorrelate[0] = ff_flac_decorrelate_indep4_16_sse2;
+ else if (channels == 6)
+ c->decorrelate[0] = ff_flac_decorrelate_indep6_16_sse2;
+ else if (ARCH_X86_64 && channels == 8)
+ c->decorrelate[0] = ff_flac_decorrelate_indep8_16_sse2;
+ c->decorrelate[1] = ff_flac_decorrelate_ls_16_sse2;
+ c->decorrelate[2] = ff_flac_decorrelate_rs_16_sse2;
+ c->decorrelate[3] = ff_flac_decorrelate_ms_16_sse2;
+ } else if (fmt == AV_SAMPLE_FMT_S32) {
+ if (channels == 2)
+ c->decorrelate[0] = ff_flac_decorrelate_indep2_32_sse2;
+ else if (channels == 4)
+ c->decorrelate[0] = ff_flac_decorrelate_indep4_32_sse2;
+ else if (channels == 6)
+ c->decorrelate[0] = ff_flac_decorrelate_indep6_32_sse2;
+ else if (ARCH_X86_64 && channels == 8)
+ c->decorrelate[0] = ff_flac_decorrelate_indep8_32_sse2;
+ c->decorrelate[1] = ff_flac_decorrelate_ls_32_sse2;
+ c->decorrelate[2] = ff_flac_decorrelate_rs_32_sse2;
+ c->decorrelate[3] = ff_flac_decorrelate_ms_32_sse2;
+ }
+ }
+ if (EXTERNAL_SSE4(cpu_flags)) {
+ c->lpc32 = ff_flac_lpc_32_sse4;
+ }
+ if (EXTERNAL_AVX(cpu_flags)) {
+ if (fmt == AV_SAMPLE_FMT_S16) {
+ if (ARCH_X86_64 && channels == 8)
+ c->decorrelate[0] = ff_flac_decorrelate_indep8_16_avx;
+ } else if (fmt == AV_SAMPLE_FMT_S32) {
+ if (channels == 4)
+ c->decorrelate[0] = ff_flac_decorrelate_indep4_32_avx;
+ else if (channels == 6)
+ c->decorrelate[0] = ff_flac_decorrelate_indep6_32_avx;
+ else if (ARCH_X86_64 && channels == 8)
+ c->decorrelate[0] = ff_flac_decorrelate_indep8_32_avx;
+ }
+ }
+ if (EXTERNAL_XOP(cpu_flags)) {
+ c->lpc32 = ff_flac_lpc_32_xop;
+ }
+#endif
+
+#if CONFIG_FLAC_ENCODER
+ if (EXTERNAL_SSE4(cpu_flags)) {
+ if (CONFIG_GPL)
+ c->lpc16_encode = ff_flac_enc_lpc_16_sse4;
+ }
+#endif
+#endif /* HAVE_YASM */
+}
diff --git a/libavcodec/x86/fmtconvert.asm b/libavcodec/x86/fmtconvert.asm
index e82f14923a..f4fc0c20ef 100644
--- a/libavcodec/x86/fmtconvert.asm
+++ b/libavcodec/x86/fmtconvert.asm
@@ -2,20 +2,20 @@
;* x86 optimized Format Conversion Utils
;* Copyright (c) 2008 Loren Merritt
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -68,3 +68,43 @@ INIT_XMM sse
INT32_TO_FLOAT_FMUL_SCALAR 5
INIT_XMM sse2
INT32_TO_FLOAT_FMUL_SCALAR 3
+
+;------------------------------------------------------------------------------
+; void ff_int32_to_float_fmul_array8(FmtConvertContext *c, float *dst, const int32_t *src,
+; const float *mul, int len);
+;------------------------------------------------------------------------------
+%macro INT32_TO_FLOAT_FMUL_ARRAY8 0
+cglobal int32_to_float_fmul_array8, 5, 5, 5, c, dst, src, mul, len
+ shl lend, 2
+ add srcq, lenq
+ add dstq, lenq
+ neg lenq
+.loop:
+ movss m0, [mulq]
+ SPLATD m0
+%if cpuflag(sse2)
+ cvtdq2ps m1, [srcq+lenq ]
+ cvtdq2ps m2, [srcq+lenq+16]
+%else
+ cvtpi2ps m1, [srcq+lenq ]
+ cvtpi2ps m3, [srcq+lenq+ 8]
+ cvtpi2ps m2, [srcq+lenq+16]
+ cvtpi2ps m4, [srcq+lenq+24]
+ movlhps m1, m3
+ movlhps m2, m4
+%endif
+ mulps m1, m0
+ mulps m2, m0
+ mova [dstq+lenq ], m1
+ mova [dstq+lenq+16], m2
+ add mulq, 4
+ add lenq, 32
+ jl .loop
+ REP_RET
+%endmacro
+
+INIT_XMM sse
+INT32_TO_FLOAT_FMUL_ARRAY8
+INIT_XMM sse2
+INT32_TO_FLOAT_FMUL_ARRAY8
+
diff --git a/libavcodec/x86/fmtconvert_init.c b/libavcodec/x86/fmtconvert_init.c
index 1871b477bb..e4cbadcce7 100644
--- a/libavcodec/x86/fmtconvert_init.c
+++ b/libavcodec/x86/fmtconvert_init.c
@@ -5,20 +5,20 @@
*
* MMX optimization by Nick Kurshev <nickols_k@mail.ru>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,10 @@
void ff_int32_to_float_fmul_scalar_sse (float *dst, const int32_t *src, float mul, int len);
void ff_int32_to_float_fmul_scalar_sse2(float *dst, const int32_t *src, float mul, int len);
+void ff_int32_to_float_fmul_array8_sse (FmtConvertContext *c, float *dst, const int32_t *src,
+ const float *mul, int len);
+void ff_int32_to_float_fmul_array8_sse2(FmtConvertContext *c, float *dst, const int32_t *src,
+ const float *mul, int len);
#endif /* HAVE_YASM */
@@ -42,9 +46,11 @@ av_cold void ff_fmt_convert_init_x86(FmtConvertContext *c, AVCodecContext *avctx
if (EXTERNAL_SSE(cpu_flags)) {
c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_sse;
+ c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_sse;
}
if (EXTERNAL_SSE2(cpu_flags)) {
c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_sse2;
+ c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_sse2;
}
#endif /* HAVE_YASM */
}
diff --git a/libavcodec/x86/fpel.asm b/libavcodec/x86/fpel.asm
index b581471296..0e3b444e2a 100644
--- a/libavcodec/x86/fpel.asm
+++ b/libavcodec/x86/fpel.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2003-2013 Michael Niedermayer
;* Copyright (c) 2013 Daniel Kang
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -25,85 +25,83 @@
SECTION .text
-INIT_MMX mmxext
+%macro PAVGB_MMX 4
+ LOAD %3, %1
+ por %3, %2
+ pxor %2, %1
+ pand %2, %4
+ psrlq %2, 1
+ psubb %3, %2
+ SWAP %2, %3
+%endmacro
+
; void ff_put/avg_pixels(uint8_t *block, const uint8_t *pixels,
; ptrdiff_t line_size, int h)
-%macro PIXELS48 2
-%if %2 == 4
-%define OP movh
+%macro OP_PIXELS 2
+%if %2 == mmsize/2
+%define LOAD movh
+%define SAVE movh
+%define LEN mmsize
%else
-%define OP mova
+%define LOAD movu
+%define SAVE mova
+%define LEN %2
%endif
-cglobal %1_pixels%2, 4,5
+cglobal %1_pixels%2, 4,5,4
movsxdifnidn r2, r2d
lea r4, [r2*3]
+%ifidn %1, avg
+%if notcpuflag(mmxext)
+ pcmpeqd m6, m6
+ paddb m6, m6
+%endif
+%endif
.loop:
- OP m0, [r1]
- OP m1, [r1+r2]
- OP m2, [r1+r2*2]
- OP m3, [r1+r4]
- lea r1, [r1+r2*4]
+%assign %%i 0
+%rep LEN/mmsize
+ LOAD m0, [r1 + %%i]
+ LOAD m1, [r1+r2 + %%i]
+ LOAD m2, [r1+r2*2 + %%i]
+ LOAD m3, [r1+r4 + %%i]
%ifidn %1, avg
- pavgb m0, [r0]
- pavgb m1, [r0+r2]
- pavgb m2, [r0+r2*2]
- pavgb m3, [r0+r4]
+%if notcpuflag(mmxext)
+ PAVGB_MMX [r0 + %%i], m0, m4, m6
+ PAVGB_MMX [r0+r2 + %%i], m1, m5, m6
+ PAVGB_MMX [r0+r2*2 + %%i], m2, m4, m6
+ PAVGB_MMX [r0+r4 + %%i], m3, m5, m6
+%else
+ pavgb m0, [r0 + %%i]
+ pavgb m1, [r0+r2 + %%i]
+ pavgb m2, [r0+r2*2 + %%i]
+ pavgb m3, [r0+r4 + %%i]
+%endif
%endif
- OP [r0], m0
- OP [r0+r2], m1
- OP [r0+r2*2], m2
- OP [r0+r4], m3
+ SAVE [r0 + %%i], m0
+ SAVE [r0+r2 + %%i], m1
+ SAVE [r0+r2*2 + %%i], m2
+ SAVE [r0+r4 + %%i], m3
+%assign %%i %%i+mmsize
+%endrep
sub r3d, 4
+ lea r1, [r1+r2*4]
lea r0, [r0+r2*4]
jne .loop
RET
%endmacro
-PIXELS48 put, 4
-PIXELS48 avg, 4
-PIXELS48 put, 8
-PIXELS48 avg, 8
+INIT_MMX mmx
+OP_PIXELS put, 4
+OP_PIXELS avg, 4
+OP_PIXELS put, 8
+OP_PIXELS avg, 8
+OP_PIXELS put, 16
+OP_PIXELS avg, 16
+INIT_MMX mmxext
+OP_PIXELS avg, 4
+OP_PIXELS avg, 8
+OP_PIXELS avg, 16
INIT_XMM sse2
-; void ff_put_pixels16_sse2(uint8_t *block, const uint8_t *pixels,
-; ptrdiff_t line_size, int h)
-cglobal put_pixels16, 4,5,4
- lea r4, [r2*3]
-.loop:
- movu m0, [r1]
- movu m1, [r1+r2]
- movu m2, [r1+r2*2]
- movu m3, [r1+r4]
- lea r1, [r1+r2*4]
- mova [r0], m0
- mova [r0+r2], m1
- mova [r0+r2*2], m2
- mova [r0+r4], m3
- sub r3d, 4
- lea r0, [r0+r2*4]
- jnz .loop
- REP_RET
-
-; void ff_avg_pixels16_sse2(uint8_t *block, const uint8_t *pixels,
-; ptrdiff_t line_size, int h)
-cglobal avg_pixels16, 4,5,4
- lea r4, [r2*3]
-.loop:
- movu m0, [r1]
- movu m1, [r1+r2]
- movu m2, [r1+r2*2]
- movu m3, [r1+r4]
- lea r1, [r1+r2*4]
- pavgb m0, [r0]
- pavgb m1, [r0+r2]
- pavgb m2, [r0+r2*2]
- pavgb m3, [r0+r4]
- mova [r0], m0
- mova [r0+r2], m1
- mova [r0+r2*2], m2
- mova [r0+r4], m3
- sub r3d, 4
- lea r0, [r0+r2*4]
- jnz .loop
- REP_RET
+OP_PIXELS put, 16
+OP_PIXELS avg, 16
diff --git a/libavcodec/x86/fpel.h b/libavcodec/x86/fpel.h
index 88d1415ade..4d93959a96 100644
--- a/libavcodec/x86/fpel.h
+++ b/libavcodec/x86/fpel.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,8 @@ void ff_avg_pixels8_mmxext(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
void ff_avg_pixels16_mmx(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_avg_pixels16_mmxext(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
void ff_avg_pixels16_sse2(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
void ff_put_pixels8_mmx(uint8_t *block, const uint8_t *pixels,
diff --git a/libavcodec/x86/fpel_mmx.c b/libavcodec/x86/fpel_mmx.c
deleted file mode 100644
index eef05ecc74..0000000000
--- a/libavcodec/x86/fpel_mmx.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * MMX-optimized avg/put pixel routines
- *
- * Copyright (c) 2000, 2001 Fabrice Bellard
- * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "config.h"
-#include "fpel.h"
-#include "inline_asm.h"
-
-#if HAVE_MMX_INLINE
-
-// in case more speed is needed - unrolling would certainly help
-void ff_avg_pixels8_mmx(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h)
-{
- MOVQ_BFE(mm6);
- JUMPALIGN();
- do {
- __asm__ volatile(
- "movq %0, %%mm0 \n\t"
- "movq %1, %%mm1 \n\t"
- PAVGB_MMX(%%mm0, %%mm1, %%mm2, %%mm6)
- "movq %%mm2, %0 \n\t"
- :"+m"(*block)
- :"m"(*pixels)
- :"memory");
- pixels += line_size;
- block += line_size;
- }
- while (--h);
-}
-
-void ff_avg_pixels16_mmx(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h)
-{
- MOVQ_BFE(mm6);
- JUMPALIGN();
- do {
- __asm__ volatile(
- "movq %0, %%mm0 \n\t"
- "movq %1, %%mm1 \n\t"
- PAVGB_MMX(%%mm0, %%mm1, %%mm2, %%mm6)
- "movq %%mm2, %0 \n\t"
- "movq 8%0, %%mm0 \n\t"
- "movq 8%1, %%mm1 \n\t"
- PAVGB_MMX(%%mm0, %%mm1, %%mm2, %%mm6)
- "movq %%mm2, 8%0 \n\t"
- :"+m"(*block)
- :"m"(*pixels)
- :"memory");
- pixels += line_size;
- block += line_size;
- }
- while (--h);
-}
-
-void ff_put_pixels8_mmx(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h)
-{
- __asm__ volatile (
- "lea (%3, %3), %%"REG_a" \n\t"
- ".p2align 3 \n\t"
- "1: \n\t"
- "movq (%1 ), %%mm0 \n\t"
- "movq (%1, %3), %%mm1 \n\t"
- "movq %%mm0, (%2) \n\t"
- "movq %%mm1, (%2, %3) \n\t"
- "add %%"REG_a", %1 \n\t"
- "add %%"REG_a", %2 \n\t"
- "movq (%1 ), %%mm0 \n\t"
- "movq (%1, %3), %%mm1 \n\t"
- "movq %%mm0, (%2) \n\t"
- "movq %%mm1, (%2, %3) \n\t"
- "add %%"REG_a", %1 \n\t"
- "add %%"REG_a", %2 \n\t"
- "subl $4, %0 \n\t"
- "jnz 1b \n\t"
- : "+g"(h), "+r"(pixels), "+r"(block)
- : "r"((x86_reg)line_size)
- : "%"REG_a, "memory"
- );
-}
-
-void ff_put_pixels16_mmx(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h)
-{
- __asm__ volatile (
- "lea (%3, %3), %%"REG_a" \n\t"
- ".p2align 3 \n\t"
- "1: \n\t"
- "movq (%1 ), %%mm0 \n\t"
- "movq 8(%1 ), %%mm4 \n\t"
- "movq (%1, %3), %%mm1 \n\t"
- "movq 8(%1, %3), %%mm5 \n\t"
- "movq %%mm0, (%2) \n\t"
- "movq %%mm4, 8(%2) \n\t"
- "movq %%mm1, (%2, %3) \n\t"
- "movq %%mm5, 8(%2, %3) \n\t"
- "add %%"REG_a", %1 \n\t"
- "add %%"REG_a", %2 \n\t"
- "movq (%1 ), %%mm0 \n\t"
- "movq 8(%1 ), %%mm4 \n\t"
- "movq (%1, %3), %%mm1 \n\t"
- "movq 8(%1, %3), %%mm5 \n\t"
- "movq %%mm0, (%2) \n\t"
- "movq %%mm4, 8(%2) \n\t"
- "movq %%mm1, (%2, %3) \n\t"
- "movq %%mm5, 8(%2, %3) \n\t"
- "add %%"REG_a", %1 \n\t"
- "add %%"REG_a", %2 \n\t"
- "subl $4, %0 \n\t"
- "jnz 1b \n\t"
- : "+g"(h), "+r"(pixels), "+r"(block)
- : "r"((x86_reg)line_size)
- : "%"REG_a, "memory"
- );
-}
-
-#endif /* HAVE_MMX_INLINE */
diff --git a/libavcodec/x86/g722dsp.asm b/libavcodec/x86/g722dsp.asm
new file mode 100644
index 0000000000..807a1bdd0a
--- /dev/null
+++ b/libavcodec/x86/g722dsp.asm
@@ -0,0 +1,54 @@
+;******************************************************************************
+;* SIMD optimized DSP functions for G722 coding
+;*
+;* Copyright (c) 2014 James Almer
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pw_qmf_coeffs: dw 3, -210, -11, -805, -11, 951, 53, 3876
+pw_qmf_coeffs2: dw 12, 3876, -156, 951, 32, -805, 362, -210
+pw_qmf_coeffs3: dw 362, 0 , 32, 0, -156, 0, 12, 0
+pw_qmf_coeffs4: dw 53, 0, -11, 0, -11, 0, 3, 0
+
+SECTION_TEXT
+
+INIT_XMM sse2
+cglobal g722_apply_qmf, 2, 2, 5, prev, out
+ movu m0, [prevq+mmsize*0]
+ movu m1, [prevq+mmsize*1]
+ movu m2, [prevq+mmsize*2]
+ punpcklwd m3, m0, m1
+ punpckhwd m0, m1
+ punpcklwd m4, m2, m2
+ punpckhwd m2, m2
+ pmaddwd m3, [pw_qmf_coeffs ]
+ pmaddwd m0, [pw_qmf_coeffs2]
+ pmaddwd m4, [pw_qmf_coeffs3]
+ pmaddwd m2, [pw_qmf_coeffs4]
+ paddd m0, m3
+ paddd m2, m4
+ paddd m0, m2
+ pshufd m2, m0, q0032
+ paddd m0, m2
+ pshufd m0, m0, q0001
+ movq [outq], m0
+ RET
diff --git a/libavcodec/x86/g722dsp_init.c b/libavcodec/x86/g722dsp_init.c
new file mode 100644
index 0000000000..614695193b
--- /dev/null
+++ b/libavcodec/x86/g722dsp_init.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavutil/x86/cpu.h"
+#include "libavcodec/g722dsp.h"
+
+void ff_g722_apply_qmf_sse2(const int16_t *prev_samples, int xout[2]);
+
+av_cold void ff_g722dsp_init_x86(G722DSPContext *dsp)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_SSE2(cpu_flags))
+ dsp->apply_qmf = ff_g722_apply_qmf_sse2;
+}
diff --git a/libavcodec/x86/h263_loopfilter.asm b/libavcodec/x86/h263_loopfilter.asm
index 673f795daa..2fcd1a26e5 100644
--- a/libavcodec/x86/h263_loopfilter.asm
+++ b/libavcodec/x86/h263_loopfilter.asm
@@ -1,20 +1,22 @@
;******************************************************************************
;* MMX-optimized H.263 loop filter
+;* Copyright (c) 2003-2013 Michael Niedermayer
+;* Copyright (c) 2013 Daniel Kang
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/h263dsp_init.c b/libavcodec/x86/h263dsp_init.c
index d4fab981bf..ab81063233 100644
--- a/libavcodec/x86/h263dsp_init.c
+++ b/libavcodec/x86/h263dsp_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 Diego Biurrun <diego@biurrun.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/h264_chromamc.asm b/libavcodec/x86/h264_chromamc.asm
index cc41f00461..107ae51cbc 100644
--- a/libavcodec/x86/h264_chromamc.asm
+++ b/libavcodec/x86/h264_chromamc.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2005 Zoltan Hidvegi <hzoli -a- hzoli -d- com>,
;* 2005-2008 Loren Merritt
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/h264_chromamc_10bit.asm b/libavcodec/x86/h264_chromamc_10bit.asm
index 7b003515cc..c358482092 100644
--- a/libavcodec/x86/h264_chromamc_10bit.asm
+++ b/libavcodec/x86/h264_chromamc_10bit.asm
@@ -5,20 +5,20 @@
;*
;* Authors: Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -252,8 +252,10 @@ cglobal %1_h264_chroma_mc2_10, 6,7
%define CHROMAMC_AVG NOTHING
INIT_XMM sse2
CHROMA_MC8 put
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CHROMA_MC8 put
+%endif
INIT_MMX mmxext
CHROMA_MC4 put
CHROMA_MC2 put
@@ -261,8 +263,10 @@ CHROMA_MC2 put
%define CHROMAMC_AVG AVG
INIT_XMM sse2
CHROMA_MC8 avg
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CHROMA_MC8 avg
+%endif
INIT_MMX mmxext
CHROMA_MC4 avg
CHROMA_MC2 avg
diff --git a/libavcodec/x86/h264_deblock.asm b/libavcodec/x86/h264_deblock.asm
index d2067c86e7..14c8205bab 100644
--- a/libavcodec/x86/h264_deblock.asm
+++ b/libavcodec/x86/h264_deblock.asm
@@ -7,20 +7,20 @@
;* Fiona Glaser <fiona@x264.com>
;* Oskar Arvidsson <oskar@irock.se>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -384,8 +384,10 @@ cglobal deblock_h_luma_8, 5,9,0,0x60+16*WIN64
INIT_XMM sse2
DEBLOCK_LUMA
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA
+%endif
%else
@@ -499,8 +501,10 @@ INIT_MMX mmxext
DEBLOCK_LUMA v8, 8
INIT_XMM sse2
DEBLOCK_LUMA v, 16
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA v, 16
+%endif
%endif ; ARCH
@@ -772,8 +776,10 @@ cglobal deblock_h_luma_intra_8, 2,4,8,0x80
INIT_XMM sse2
DEBLOCK_LUMA_INTRA v
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA_INTRA v
+%endif
%if ARCH_X86_64 == 0
INIT_MMX mmxext
DEBLOCK_LUMA_INTRA v8
@@ -836,7 +842,11 @@ cglobal deblock_h_chroma_8, 5,7
TRANSPOSE4x8_LOAD bw, wd, dq, PASS8ROWS(t5, r0, r1, t6)
movq buf0, m0
movq buf1, m3
- call ff_chroma_inter_body_mmxext
+ LOAD_MASK r2d, r3d
+ movd m6, [r4] ; tc0
+ punpcklbw m6, m6
+ pand m7, m6
+ DEBLOCK_P0_Q0
movq m0, buf0
movq m3, buf1
TRANSPOSE8x4B_STORE PASS8ROWS(t5, r0, r1, t6)
diff --git a/libavcodec/x86/h264_deblock_10bit.asm b/libavcodec/x86/h264_deblock_10bit.asm
index d049c62bf2..ebf8a3f109 100644
--- a/libavcodec/x86/h264_deblock_10bit.asm
+++ b/libavcodec/x86/h264_deblock_10bit.asm
@@ -7,34 +7,32 @@
;* Loren Merritt <lorenm@u.washington.edu>
;* Fiona Glaser <fiona@x264.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* 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
-
-pw_pixel_max: times 8 dw ((1 << 10)-1)
-
SECTION .text
cextern pw_2
cextern pw_3
cextern pw_4
+cextern pw_1023
+%define pw_pixel_max pw_1023
; out: %4 = |%1-%2|-%3
; clobbers: %5
@@ -418,9 +416,11 @@ cglobal deblock_h_luma_10, 5,7,15
INIT_XMM sse2
DEBLOCK_LUMA_64
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA_64
%endif
+%endif
%macro SWAPMOVA 2
%ifid %1
@@ -715,8 +715,10 @@ cglobal deblock_h_luma_intra_10, 4,7,16
INIT_XMM sse2
DEBLOCK_LUMA_INTRA_64
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA_INTRA_64
+%endif
%endif
@@ -802,10 +804,12 @@ DEBLOCK_LUMA_INTRA
INIT_XMM sse2
DEBLOCK_LUMA
DEBLOCK_LUMA_INTRA
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_LUMA
DEBLOCK_LUMA_INTRA
%endif
+%endif
; in: %1=p0, %2=q0, %3=p1, %4=q1, %5=mask, %6=tmp, %7=tmp
; out: %1=p0', %2=q0'
@@ -918,5 +922,7 @@ DEBLOCK_CHROMA
%endif
INIT_XMM sse2
DEBLOCK_CHROMA
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEBLOCK_CHROMA
+%endif
diff --git a/libavcodec/x86/h264_i386.h b/libavcodec/x86/h264_i386.h
index bb881c35df..49ad0e0fa0 100644
--- a/libavcodec/x86/h264_i386.h
+++ b/libavcodec/x86/h264_i386.h
@@ -2,20 +2,20 @@
* H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,9 +36,15 @@
#if HAVE_INLINE_ASM
+#if ARCH_X86_64
+#define REG64 "r"
+#else
+#define REG64 "m"
+#endif
+
//FIXME use some macros to avoid duplicating get_cabac (cannot be done yet
//as that would make optimization work hard)
-#if HAVE_7REGS
+#if HAVE_7REGS && !BROKEN_COMPILER
#define decode_significance decode_significance_x86
static int decode_significance_x86(CABACContext *c, int max_coeff,
uint8_t *significant_coeff_ctx_base,
@@ -55,6 +61,7 @@ static int decode_significance_x86(CABACContext *c, int max_coeff,
__asm__ volatile(
"lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t"
: "=&r"(tables)
+ : NAMED_CONSTRAINTS_ARRAY(ff_h264_cabac_tables)
);
#endif
@@ -130,6 +137,7 @@ static int decode_significance_8x8_x86(CABACContext *c,
__asm__ volatile(
"lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t"
: "=&r"(tables)
+ : NAMED_CONSTRAINTS_ARRAY(ff_h264_cabac_tables)
);
#endif
@@ -138,7 +146,7 @@ static int decode_significance_8x8_x86(CABACContext *c,
"3: \n\t"
"mov %10, %0 \n\t"
- "movzbl (%0, %6), %k6 \n\t"
+ "movzb (%0, %6), %6 \n\t"
"add %9, %6 \n\t"
BRANCHLESS_GET_CABAC("%4", "%q4", "(%6)", "%3", "%w3",
@@ -149,14 +157,14 @@ static int decode_significance_8x8_x86(CABACContext *c,
AV_STRINGIFY(H264_MLPS_STATE_OFFSET),
"%15")
- "mov %1, %k6 \n\t"
+ "mov %1, %6 \n\t"
"test $1, %4 \n\t"
" jz 4f \n\t"
#ifdef BROKEN_RELOCATIONS
- "movzbl %c14(%15, %q6), %k6\n\t"
+ "movzb %c14(%15, %q6), %6\n\t"
#else
- "movzbl "MANGLE(ff_h264_cabac_tables)"+%c14(%k6), %k6\n\t"
+ "movzb "MANGLE(ff_h264_cabac_tables)"+%c14(%6), %6\n\t"
#endif
"add %11, %6 \n\t"
@@ -169,8 +177,8 @@ static int decode_significance_8x8_x86(CABACContext *c,
"%15")
"mov %2, %0 \n\t"
- "mov %1, %k6 \n\t"
- "movl %k6, (%0) \n\t"
+ "mov %1, %6 \n\t"
+ "mov %k6, (%0) \n\t"
"test $1, %4 \n\t"
" jnz 5f \n\t"
@@ -178,19 +186,19 @@ static int decode_significance_8x8_x86(CABACContext *c,
"add"OPSIZE" $4, %2 \n\t"
"4: \n\t"
- "addl $1, %k6 \n\t"
- "mov %k6, %1 \n\t"
- "cmpl $63, %k6 \n\t"
+ "add $1, %6 \n\t"
+ "mov %6, %1 \n\t"
+ "cmp $63, %6 \n\t"
" jb 3b \n\t"
"mov %2, %0 \n\t"
- "movl %k6, (%0) \n\t"
+ "mov %k6, (%0) \n\t"
"5: \n\t"
"addl %8, %k0 \n\t"
"shr $2, %k0 \n\t"
- : "=&q"(coeff_count), "+m"(last), "+m"(index), "+&r"(c->low),
+ : "=&q"(coeff_count), "+"REG64(last), "+"REG64(index), "+&r"(c->low),
"=&r"(bit), "+&r"(c->range), "=&r"(state)
: "r"(c), "m"(minusindex), "m"(significant_coeff_ctx_base),
- "m"(sig_off), "m"(last_coeff_ctx_base),
+ REG64(sig_off), REG64(last_coeff_ctx_base),
"i"(offsetof(CABACContext, bytestream)),
"i"(offsetof(CABACContext, bytestream_end)),
"i"(H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET) TABLES_ARG
@@ -198,7 +206,7 @@ static int decode_significance_8x8_x86(CABACContext *c,
);
return coeff_count;
}
-#endif /* HAVE_7REGS && !defined(BROKEN_RELOCATIONS) */
+#endif /* HAVE_7REGS && BROKEN_COMPILER */
#endif /* HAVE_INLINE_ASM */
#endif /* AVCODEC_X86_H264_I386_H */
diff --git a/libavcodec/x86/h264_idct.asm b/libavcodec/x86/h264_idct.asm
index 313791a5d9..7fafe195f1 100644
--- a/libavcodec/x86/h264_idct.asm
+++ b/libavcodec/x86/h264_idct.asm
@@ -9,20 +9,20 @@
;* Holger Lubitz <hal@duncan.ol.sub.de>
;* Min Chen <chenm001.163.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;*****************************************************************************
diff --git a/libavcodec/x86/h264_idct_10bit.asm b/libavcodec/x86/h264_idct_10bit.asm
index b7d51051d3..cc115b0ff9 100644
--- a/libavcodec/x86/h264_idct_10bit.asm
+++ b/libavcodec/x86/h264_idct_10bit.asm
@@ -5,20 +5,20 @@
;*
;* Authors: Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -26,11 +26,13 @@
SECTION_RODATA
-pw_pixel_max: times 8 dw ((1 << 10)-1)
pd_32: times 4 dd 32
SECTION .text
+cextern pw_1023
+%define pw_pixel_max pw_1023
+
;-----------------------------------------------------------------------------
; void ff_h264_idct_add_10(pixel *dst, int16_t *block, int stride)
;-----------------------------------------------------------------------------
@@ -83,8 +85,10 @@ cglobal h264_idct_add_10, 3,3
INIT_XMM sse2
IDCT_ADD_10
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT_ADD_10
+%endif
;-----------------------------------------------------------------------------
; void ff_h264_idct_add16_10(pixel *dst, const int *block_offset,
@@ -117,9 +121,11 @@ add4x4_idct %+ SUFFIX:
INIT_XMM sse2
ALIGN 16
ADD4x4IDCT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
ALIGN 16
ADD4x4IDCT
+%endif
%macro ADD16_OP 2
cmp byte [r4+%2], 0
@@ -155,8 +161,10 @@ cglobal h264_idct_add16_10, 5,6
INIT_XMM sse2
IDCT_ADD16_10
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT_ADD16_10
+%endif
;-----------------------------------------------------------------------------
; void ff_h264_idct_dc_add_10(pixel *dst, int16_t *block, int stride)
@@ -220,8 +228,10 @@ cglobal h264_idct8_dc_add_10,3,4,7
INIT_XMM sse2
IDCT8_DC_ADD
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT8_DC_ADD
+%endif
;-----------------------------------------------------------------------------
; void ff_h264_idct_add16intra_10(pixel *dst, const int *block_offset,
@@ -293,8 +303,10 @@ cglobal h264_idct_add16intra_10,5,7,8
INIT_XMM sse2
IDCT_ADD16INTRA_10
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT_ADD16INTRA_10
+%endif
%assign last_block 36
;-----------------------------------------------------------------------------
@@ -330,8 +342,10 @@ cglobal h264_idct_add8_10,5,8,7
INIT_XMM sse2
IDCT_ADD8
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT_ADD8
+%endif
;-----------------------------------------------------------------------------
; void ff_h264_idct8_add_10(pixel *dst, int16_t *block, int stride)
@@ -537,8 +551,10 @@ h264_idct8_add1_10 %+ SUFFIX:
INIT_XMM sse2
IDCT8_ADD
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT8_ADD
+%endif
;-----------------------------------------------------------------------------
; void ff_h264_idct8_add4_10(pixel **dst, const int *block_offset,
@@ -577,5 +593,7 @@ cglobal h264_idct8_add4_10, 0,7,16
INIT_XMM sse2
IDCT8_ADD4
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
IDCT8_ADD4
+%endif
diff --git a/libavcodec/x86/h264_intrapred.asm b/libavcodec/x86/h264_intrapred.asm
index df657a443c..c88d91b49e 100644
--- a/libavcodec/x86/h264_intrapred.asm
+++ b/libavcodec/x86/h264_intrapred.asm
@@ -5,20 +5,20 @@
;* Copyright (c) 2010 Loren Merritt
;* Copyright (c) 2010 Ronald S. Bultje
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -2497,10 +2497,7 @@ cglobal pred4x4_tm_vp8_8, 3,3
pshufb mm3, mm6
pshufb mm4, mm6
pshufb mm5, mm6
- psubw mm2, mm7
- psubw mm3, mm7
- psubw mm4, mm7
- psubw mm5, mm7
+ psubw mm0, mm7
paddw mm2, mm0
paddw mm3, mm0
paddw mm4, mm0
diff --git a/libavcodec/x86/h264_intrapred_10bit.asm b/libavcodec/x86/h264_intrapred_10bit.asm
index 55790a956e..9aeb70242b 100644
--- a/libavcodec/x86/h264_intrapred_10bit.asm
+++ b/libavcodec/x86/h264_intrapred_10bit.asm
@@ -5,20 +5,20 @@
;*
;* Authors: Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -26,6 +26,9 @@
SECTION_RODATA
+cextern pw_1023
+%define pw_pixel_max pw_1023
+cextern pw_512
cextern pw_16
cextern pw_8
cextern pw_4
@@ -34,8 +37,6 @@ cextern pw_1
pw_m32101234: dw -3, -2, -1, 0, 1, 2, 3, 4
pw_m3: times 8 dw -3
-pw_pixel_max: times 8 dw ((1 << 10)-1)
-pw_512: times 8 dw 512
pd_17: times 4 dd 17
pd_16: times 4 dd 16
@@ -82,8 +83,10 @@ INIT_XMM sse2
PRED4x4_DR
INIT_XMM ssse3
PRED4x4_DR
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_DR
+%endif
;------------------------------------------------------------------------------
; void ff_pred4x4_vertical_right(pixel *src, const pixel *topright, int stride)
@@ -119,8 +122,10 @@ INIT_XMM sse2
PRED4x4_VR
INIT_XMM ssse3
PRED4x4_VR
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_VR
+%endif
;-------------------------------------------------------------------------------
; void ff_pred4x4_horizontal_down(pixel *src, const pixel *topright, int stride)
@@ -159,28 +164,14 @@ INIT_XMM sse2
PRED4x4_HD
INIT_XMM ssse3
PRED4x4_HD
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_HD
+%endif
;-----------------------------------------------------------------------------
; void ff_pred4x4_dc(pixel *src, const pixel *topright, int stride)
;-----------------------------------------------------------------------------
-%macro HADDD 2 ; sum junk
-%if mmsize == 16
- movhlps %2, %1
- paddd %1, %2
- pshuflw %2, %1, 0xE
- paddd %1, %2
-%else
- pshufw %2, %1, 0xE
- paddd %1, %2
-%endif
-%endmacro
-
-%macro HADDW 2
- pmaddwd %1, [pw_1]
- HADDD %1, %2
-%endmacro
INIT_MMX mmxext
cglobal pred4x4_dc_10, 3, 3
@@ -228,8 +219,10 @@ cglobal pred4x4_down_left_10, 3, 3
INIT_XMM sse2
PRED4x4_DL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_DL
+%endif
;-----------------------------------------------------------------------------
; void ff_pred4x4_vertical_left(pixel *src, const pixel *topright, int stride)
@@ -255,8 +248,10 @@ cglobal pred4x4_vertical_left_10, 3, 3
INIT_XMM sse2
PRED4x4_VL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED4x4_VL
+%endif
;-----------------------------------------------------------------------------
; void ff_pred4x4_horizontal_up(pixel *src, const pixel *topright, int stride)
@@ -565,8 +560,10 @@ cglobal pred8x8l_top_dc_10, 4, 4, 6
INIT_XMM sse2
PRED8x8L_TOP_DC
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_TOP_DC
+%endif
;-------------------------------------------------------------------------------
; void ff_pred8x8l_dc(pixel *src, int has_topleft, int has_topright, int stride)
@@ -622,8 +619,10 @@ cglobal pred8x8l_dc_10, 4, 6, 6
INIT_XMM sse2
PRED8x8L_DC
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_DC
+%endif
;-----------------------------------------------------------------------------
; void ff_pred8x8l_vertical(pixel *src, int has_topleft, int has_topright,
@@ -656,8 +655,10 @@ cglobal pred8x8l_vertical_10, 4, 4, 6
INIT_XMM sse2
PRED8x8L_VERTICAL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_VERTICAL
+%endif
;-----------------------------------------------------------------------------
; void ff_pred8x8l_horizontal(uint8_t *src, int has_topleft, int has_topright,
@@ -711,8 +712,10 @@ INIT_XMM sse2
PRED8x8L_HORIZONTAL
INIT_XMM ssse3
PRED8x8L_HORIZONTAL
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_HORIZONTAL
+%endif
;-----------------------------------------------------------------------------
; void ff_pred8x8l_down_left(pixel *src, int has_topleft, int has_topright,
@@ -778,8 +781,10 @@ INIT_XMM sse2
PRED8x8L_DOWN_LEFT
INIT_XMM ssse3
PRED8x8L_DOWN_LEFT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_DOWN_LEFT
+%endif
;-----------------------------------------------------------------------------
; void ff_pred8x8l_down_right(pixel *src, int has_topleft, int has_topright,
@@ -851,8 +856,10 @@ INIT_XMM sse2
PRED8x8L_DOWN_RIGHT
INIT_XMM ssse3
PRED8x8L_DOWN_RIGHT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_DOWN_RIGHT
+%endif
;-----------------------------------------------------------------------------
; void ff_pred8x8l_vertical_right(pixel *src, int has_topleft,
@@ -920,8 +927,10 @@ INIT_XMM sse2
PRED8x8L_VERTICAL_RIGHT
INIT_XMM ssse3
PRED8x8L_VERTICAL_RIGHT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_VERTICAL_RIGHT
+%endif
;-----------------------------------------------------------------------------
; void ff_pred8x8l_horizontal_up(pixel *src, int has_topleft,
@@ -980,8 +989,10 @@ INIT_XMM sse2
PRED8x8L_HORIZONTAL_UP
INIT_XMM ssse3
PRED8x8L_HORIZONTAL_UP
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
PRED8x8L_HORIZONTAL_UP
+%endif
;-----------------------------------------------------------------------------
diff --git a/libavcodec/x86/h264_intrapred_init.c b/libavcodec/x86/h264_intrapred_init.c
index 0e572b1226..528b92e497 100644
--- a/libavcodec/x86/h264_intrapred_init.c
+++ b/libavcodec/x86/h264_intrapred_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Fiona Glaser <fiona@x264.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/h264_qpel.c b/libavcodec/x86/h264_qpel.c
index 9ca6d7e644..33a7fb03ba 100644
--- a/libavcodec/x86/h264_qpel.c
+++ b/libavcodec/x86/h264_qpel.c
@@ -2,20 +2,20 @@
* Copyright (c) 2004-2005 Michael Niedermayer, Loren Merritt
* Copyright (c) 2011 Daniel Kang
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,8 +29,8 @@
#include "fpel.h"
#if HAVE_YASM
-void ff_put_pixels4_mmxext(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h);
+void ff_put_pixels4_mmx(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
void ff_avg_pixels4_mmxext(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
void ff_put_pixels4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2,
@@ -49,9 +49,9 @@ void ff_avg_pixels16_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t
#define ff_avg_pixels8_l2_sse2 ff_avg_pixels8_l2_mmxext
#define ff_put_pixels16_l2_sse2 ff_put_pixels16_l2_mmxext
#define ff_avg_pixels16_l2_sse2 ff_avg_pixels16_l2_mmxext
-
-CALL_2X_PIXELS(ff_avg_pixels16_mmxext, ff_avg_pixels8_mmxext, 8)
-CALL_2X_PIXELS(ff_put_pixels16_mmxext, ff_put_pixels8_mmxext, 8)
+#define ff_put_pixels16_mmxext ff_put_pixels16_mmx
+#define ff_put_pixels8_mmxext ff_put_pixels8_mmx
+#define ff_put_pixels4_mmxext ff_put_pixels4_mmx
#define DEF_QPEL(OPNAME)\
void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\
@@ -282,7 +282,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc30_ ## MMX(uint8_t *dst, const uin
#define H264_MC_V(OPNAME, SIZE, MMX, ALIGN) \
static void OPNAME ## h264_qpel ## SIZE ## _mc01_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\
ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\
ff_ ## OPNAME ## pixels ## SIZE ## _l2_ ## MMX(dst, src, temp, stride, stride, SIZE);\
}\
@@ -294,7 +294,7 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc02_ ## MMX(uint8_t *dst, const uin
\
static void OPNAME ## h264_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\
ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\
ff_ ## OPNAME ## pixels ## SIZE ## _l2_ ## MMX(dst, src+stride, temp, stride, stride, SIZE);\
}\
@@ -302,74 +302,74 @@ static void OPNAME ## h264_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uin
#define H264_MC_HV(OPNAME, SIZE, MMX, ALIGN) \
static void OPNAME ## h264_qpel ## SIZE ## _mc11_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\
ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, temp, stride, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc31_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\
ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src+1, SIZE, stride);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, temp, stride, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc13_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\
ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, temp, stride, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc33_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\
ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src+1, SIZE, stride);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, temp, stride, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc22_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint16_t, temp)[SIZE*(SIZE<8?12:24)];\
+ LOCAL_ALIGNED(ALIGN, uint16_t, temp, [SIZE*(SIZE<8?12:24)]);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(dst, temp, src, stride, SIZE, stride);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc21_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\
uint8_t * const halfHV= temp;\
int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\
- assert(((int)temp & 7) == 0);\
+ av_assert2(((int)temp & 7) == 0);\
ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, halfHV, stride, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc23_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\
uint8_t * const halfHV= temp;\
int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\
- assert(((int)temp & 7) == 0);\
+ av_assert2(((int)temp & 7) == 0);\
ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\
ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, halfHV, stride, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc12_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\
uint8_t * const halfHV= temp;\
int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\
- assert(((int)temp & 7) == 0);\
+ av_assert2(((int)temp & 7) == 0);\
ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\
ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_mmxext(dst, halfV+2, halfHV, stride, SIZE, SIZE);\
}\
\
static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\
{\
- DECLARE_ALIGNED(ALIGN, uint8_t, temp)[SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE];\
+ LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\
uint8_t * const halfHV= temp;\
int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\
- assert(((int)temp & 7) == 0);\
+ av_assert2(((int)temp & 7) == 0);\
ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\
ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_mmxext(dst, halfV+3, halfHV, stride, SIZE, SIZE);\
}\
diff --git a/libavcodec/x86/h264_qpel_10bit.asm b/libavcodec/x86/h264_qpel_10bit.asm
index f92c4aab2b..757c425898 100644
--- a/libavcodec/x86/h264_qpel_10bit.asm
+++ b/libavcodec/x86/h264_qpel_10bit.asm
@@ -5,20 +5,20 @@
;*
;* Authors: Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -26,12 +26,12 @@
SECTION_RODATA 32
+cextern pw_1023
+%define pw_pixel_max pw_1023
cextern pw_16
cextern pw_1
cextern pb_0
-pw_pixel_max: times 8 dw ((1 << 10)-1)
-
pad10: times 8 dw 10*1023
pad20: times 8 dw 20*1023
pad30: times 8 dw 30*1023
diff --git a/libavcodec/x86/h264_qpel_8bit.asm b/libavcodec/x86/h264_qpel_8bit.asm
index bc6c72541b..2d287ba443 100644
--- a/libavcodec/x86/h264_qpel_8bit.asm
+++ b/libavcodec/x86/h264_qpel_8bit.asm
@@ -6,20 +6,20 @@
;*
;* Authors: Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/h264_weight.asm b/libavcodec/x86/h264_weight.asm
index d1873af5b4..b4fb9db309 100644
--- a/libavcodec/x86/h264_weight.asm
+++ b/libavcodec/x86/h264_weight.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2004-2005 Michael Niedermayer, Loren Merritt
;* Copyright (C) 2010 Eli Friedman <eli.friedman@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -135,6 +135,13 @@ WEIGHT_FUNC_HALF_MM 8, 8
add off_regd, 1
or off_regd, 1
add r4, 1
+ cmp r5, 128
+ jne .normal
+ sar r5, 1
+ sar r6, 1
+ sar off_regd, 1
+ sub r4, 1
+.normal
%if cpuflag(ssse3)
movd m4, r5d
movd m0, r6d
diff --git a/libavcodec/x86/h264_weight_10bit.asm b/libavcodec/x86/h264_weight_10bit.asm
index 961ec8ca45..f924e55854 100644
--- a/libavcodec/x86/h264_weight_10bit.asm
+++ b/libavcodec/x86/h264_weight_10bit.asm
@@ -5,20 +5,20 @@
;*
;* Authors: Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -26,11 +26,12 @@
SECTION_RODATA 32
-pw_pixel_max: times 8 dw ((1 << 10)-1)
sq_1: dq 1
dq 0
cextern pw_1
+cextern pw_1023
+%define pw_pixel_max pw_1023
SECTION .text
diff --git a/libavcodec/x86/h264chroma_init.c b/libavcodec/x86/h264chroma_init.c
index 8ec8a79aba..e08af2759e 100644
--- a/libavcodec/x86/h264chroma_init.c
+++ b/libavcodec/x86/h264chroma_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/h264dsp_init.c b/libavcodec/x86/h264dsp_init.c
index 134d594ca9..35db20014a 100644
--- a/libavcodec/x86/h264dsp_init.c
+++ b/libavcodec/x86/h264dsp_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2004-2005 Michael Niedermayer, Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -210,6 +210,7 @@ H264_BIWEIGHT_10_SSE(4, 10)
av_cold void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth,
const int chroma_format_idc)
{
+#if HAVE_YASM
int cpu_flags = av_get_cpu_flags();
if (EXTERNAL_MMXEXT(cpu_flags) && chroma_format_idc <= 1)
@@ -365,4 +366,5 @@ av_cold void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth,
#endif /* HAVE_ALIGNED_STACK */
}
}
+#endif
}
diff --git a/libavcodec/x86/hevc_deblock.asm b/libavcodec/x86/hevc_deblock.asm
index 1e895f0aa5..48a597530b 100644
--- a/libavcodec/x86/hevc_deblock.asm
+++ b/libavcodec/x86/hevc_deblock.asm
@@ -5,20 +5,20 @@
;*
;* Authors: Seppo Tomperi <seppo.tomperi@vtt.fi>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -26,13 +26,15 @@
SECTION_RODATA
-pw_pixel_max: times 8 dw ((1 << 10)-1)
-pw_m1: times 8 dw -1
-pw_m2: times 8 dw -2
-pd_1 : times 4 dd 1
+cextern pw_1023
+%define pw_pixel_max_10 pw_1023
+pw_pixel_max_12: times 8 dw ((1 << 12)-1)
+pw_m2: times 8 dw -2
+pd_1 : times 4 dd 1
cextern pw_4
cextern pw_8
+cextern pw_m1
SECTION .text
INIT_XMM sse2
@@ -57,10 +59,10 @@ INIT_XMM sse2
movd m4, %5
movd m6, %6
movd m5, %7
- movd m7, %8
+ movd m3, %8
punpcklbw m4, m6
- punpcklbw m5, m7
+ punpcklbw m5, m3
punpcklwd m4, m5
punpckhdq m2, m0, m4
@@ -76,16 +78,10 @@ INIT_XMM sse2
; in: 4 rows of 8 words in m0..m3
; out: 8 rows of 4 bytes in %1..%8
%macro TRANSPOSE8x4B_STORE 8
- packuswb m0, m0
- packuswb m1, m1
- packuswb m2, m2
- packuswb m3, m3
-
- punpcklbw m0, m1
- punpcklbw m2, m3
-
- punpckhwd m6, m0, m2
- punpcklwd m0, m2
+ packuswb m0, m2
+ packuswb m1, m3
+ SBUTTERFLY bw, 0, 1, 2
+ SBUTTERFLY wd, 0, 1, 2
movd %1, m0
pshufd m0, m0, 0x39
@@ -95,13 +91,13 @@ INIT_XMM sse2
pshufd m0, m0, 0x39
movd %4, m0
- movd %5, m6
- pshufd m6, m6, 0x39
- movd %6, m6
- pshufd m6, m6, 0x39
- movd %7, m6
- pshufd m6, m6, 0x39
- movd %8, m6
+ movd %5, m1
+ pshufd m1, m1, 0x39
+ movd %6, m1
+ pshufd m1, m1, 0x39
+ movd %7, m1
+ pshufd m1, m1, 0x39
+ movd %8, m1
%endmacro
; in: 8 rows of 4 words in %4..%11
@@ -120,10 +116,10 @@ INIT_XMM sse2
movq m4, %5
movq m6, %6
movq m5, %7
- movq m7, %8
+ movq m3, %8
punpcklwd m4, m6
- punpcklwd m5, m7
+ punpcklwd m5, m3
punpckhdq m6, m4, m5
punpckldq m4, m5
@@ -136,32 +132,23 @@ INIT_XMM sse2
; in: 4 rows of 8 words in m0..m3
; out: 8 rows of 4 words in %1..%8
-%macro TRANSPOSE8x4W_STORE 8
- pxor m5, m5; zeros reg
- CLIPW m0, m5, [pw_pixel_max]
- CLIPW m1, m5, [pw_pixel_max]
- CLIPW m2, m5, [pw_pixel_max]
- CLIPW m3, m5, [pw_pixel_max]
+%macro TRANSPOSE8x4W_STORE 9
+ TRANSPOSE4x4W 0, 1, 2, 3, 4
- punpckhwd m4, m0, m1
- punpcklwd m0, m1
- punpckhwd m5, m2, m3
- punpcklwd m2, m3
- punpckhdq m6, m0, m2
- punpckldq m0, m2
+ pxor m5, m5; zeros reg
+ CLIPW m0, m5, %9
+ CLIPW m1, m5, %9
+ CLIPW m2, m5, %9
+ CLIPW m3, m5, %9
movq %1, m0
movhps %2, m0
- movq %3, m6
- movhps %4, m6
-
- punpckhdq m6, m4, m5
- punpckldq m4, m5
-
- movq %5, m4
- movhps %6, m4
- movq %7, m6
- movhps %8, m6
+ movq %3, m1
+ movhps %4, m1
+ movq %5, m2
+ movhps %6, m2
+ movq %7, m3
+ movhps %8, m3
%endmacro
; in: 8 rows of 8 bytes in %1..%8
@@ -212,40 +199,20 @@ INIT_XMM sse2
; in: 8 rows of 8 words in m0..m8
; out: 8 rows of 8 bytes in %1..%8
%macro TRANSPOSE8x8B_STORE 8
- packuswb m0, m0
- packuswb m1, m1
- packuswb m2, m2
- packuswb m3, m3
- packuswb m4, m4
- packuswb m5, m5
- packuswb m6, m6
- packuswb m7, m7
-
- punpcklbw m0, m1
- punpcklbw m2, m3
-
- punpckhwd m8, m0, m2
- punpcklwd m0, m2
-
- punpcklbw m4, m5
- punpcklbw m6, m7
-
- punpckhwd m9, m4, m6
- punpcklwd m4, m6
+ packuswb m0, m4
+ packuswb m1, m5
+ packuswb m2, m6
+ packuswb m3, m7
+ TRANSPOSE2x4x4B 0, 1, 2, 3, 4
- punpckhdq m10, m0, m4; 2, 3
- punpckldq m0, m4; 0, 1
-
- punpckldq m11, m8, m9; 4, 5
- punpckhdq m8, m9; 6, 7
movq %1, m0
movhps %2, m0
- movq %3, m10
- movhps %4, m10
- movq %5, m11
- movhps %6, m11
- movq %7, m8
- movhps %8, m8
+ movq %3, m1
+ movhps %4, m1
+ movq %5, m2
+ movhps %6, m2
+ movq %7, m3
+ movhps %8, m3
%endmacro
; in: 8 rows of 8 words in %1..%8
@@ -264,18 +231,18 @@ INIT_XMM sse2
; in: 8 rows of 8 words in m0..m8
; out: 8 rows of 8 words in %1..%8
-%macro TRANSPOSE8x8W_STORE 8
+%macro TRANSPOSE8x8W_STORE 9
TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, 8
pxor m8, m8
- CLIPW m0, m8, [pw_pixel_max]
- CLIPW m1, m8, [pw_pixel_max]
- CLIPW m2, m8, [pw_pixel_max]
- CLIPW m3, m8, [pw_pixel_max]
- CLIPW m4, m8, [pw_pixel_max]
- CLIPW m5, m8, [pw_pixel_max]
- CLIPW m6, m8, [pw_pixel_max]
- CLIPW m7, m8, [pw_pixel_max]
+ CLIPW m0, m8, %9
+ CLIPW m1, m8, %9
+ CLIPW m2, m8, %9
+ CLIPW m3, m8, %9
+ CLIPW m4, m8, %9
+ CLIPW m5, m8, %9
+ CLIPW m6, m8, %9
+ CLIPW m7, m8, %9
movdqu %1, m0
movdqu %2, m1
@@ -318,13 +285,14 @@ ALIGN 16
paddw m5, m4;
;tc calculations
- movd m6, [r2]; tc0
- add r2, 4;
+ movq m6, [tcq]; tc0
punpcklwd m6, m6
- movd m7, [r2]; tc1
- punpcklwd m7, m7
- shufps m6, m7, 0; tc0, tc1
+ pshufd m6, m6, 0xA0; tc0, tc1
+%if cpuflag(ssse3)
+ psignw m4, m6, [pw_m1]; -tc0, -tc1
+%else
pmullw m4, m6, [pw_m1]; -tc0, -tc1
+%endif
;end tc calculations
paddw m5, [pw_4]; +4
@@ -362,11 +330,11 @@ ALIGN 16
paddw m9, m10, m11; 0d0, 0d3 , 1d0, 1d3
- pshufhw m14, m9, q0033 ;0b00001111; 0d3 0d3 0d0 0d0 in high
- pshuflw m14, m14, q0033 ;0b00001111; 1d3 1d3 1d0 1d0 in low
+ pshufhw m14, m9, 0x0f ;0b00001111; 0d3 0d3 0d0 0d0 in high
+ pshuflw m14, m14, 0x0f ;0b00001111; 1d3 1d3 1d0 1d0 in low
- pshufhw m9, m9, q3300 ;0b11110000; 0d0 0d0 0d3 0d3
- pshuflw m9, m9, q3300 ;0b11110000; 1d0 1d0 1d3 1d3
+ pshufhw m9, m9, 0xf0 ;0b11110000; 0d0 0d0 0d3 0d3
+ pshuflw m9, m9, 0xf0 ;0b11110000; 1d0 1d0 1d3 1d3
paddw m14, m9; 0d0+0d3, 1d0+1d3
@@ -380,7 +348,7 @@ ALIGN 16
psraw m15, m13, 2; beta >> 2
psllw m8, m9, 1;
pcmpgtw m15, m8; (d0 << 1) < beta_2, (d3 << 1) < beta_2
- movmskps r14, m15;
+ movmskps r6, m15;
;end weak / strong decision
; weak filter nd_p/q calculation
@@ -388,19 +356,15 @@ ALIGN 16
psrld m8, 16
paddw m8, m10
movd r7d, m8
- and r7, 0xffff; 1dp0 + 1dp3
pshufd m8, m8, 0x4E
movd r8d, m8
- and r8, 0xffff; 0dp0 + 0dp3
pshufd m8, m11, 0x31
psrld m8, 16
paddw m8, m11
movd r9d, m8
- and r9, 0xffff; 1dq0 + 1dq3
pshufd m8, m8, 0x4E
movd r10d, m8
- and r10, 0xffff; 0dq0 + 0dq3
; end calc for weak filter
; filtering mask
@@ -422,14 +386,13 @@ ALIGN 16
shl r11, %1 - 8
%endif
movd m8, r11d; tc0
- add tcq, 4;
- mov r3d, [tcq];
+ mov r3d, [tcq+4];
%if %1 > 8
shl r3, %1 - 8
%endif
- movd m9, r3d; tc1
add r11d, r3d; tc0 + tc1
jz .bypassluma
+ movd m9, r3d; tc1
punpcklwd m8, m8
punpcklwd m9, m9
shufps m8, m9, 0; tc0, tc1
@@ -453,7 +416,7 @@ ALIGN 16
psraw m13, 3; beta >> 3
pcmpgtw m13, m12;
movmskps r11, m13;
- and r14, r11; strong mask , beta_2 and beta_3 comparisons
+ and r6, r11; strong mask , beta_2 and beta_3 comparisons
;----beta_3 comparison end-----
;----tc25 comparison---
psubw m12, m3, m4; p0 - q0
@@ -464,23 +427,23 @@ ALIGN 16
pcmpgtw m8, m12; tc25 comparisons
movmskps r11, m8;
- and r14, r11; strong mask, beta_2, beta_3 and tc25 comparisons
+ and r6, r11; strong mask, beta_2, beta_3 and tc25 comparisons
;----tc25 comparison end---
- mov r11, r14;
+ mov r11, r6;
shr r11, 1;
- and r14, r11; strong mask, bits 2 and 0
+ and r6, r11; strong mask, bits 2 and 0
pmullw m14, m9, [pw_m2]; -tc * 2
paddw m9, m9
- and r14, 5; 0b101
- mov r11, r14; strong mask
- shr r14, 2;
- movd m12, r14d; store to xmm for mask generation
- shl r14, 1
+ and r6, 5; 0b101
+ mov r11, r6; strong mask
+ shr r6, 2;
+ movd m12, r6d; store to xmm for mask generation
+ shl r6, 1
and r11, 1
movd m10, r11d; store to xmm for mask generation
- or r14, r11; final strong mask, bits 1 and 0
+ or r6, r11; final strong mask, bits 1 and 0
jz .weakfilter
shufps m10, m12, 0
@@ -565,16 +528,16 @@ ALIGN 16
MASKED_COPY m3, m12
.weakfilter:
- not r14; strong mask -> weak mask
- and r14, r13; final weak filtering mask, bits 0 and 1
+ not r6; strong mask -> weak mask
+ and r6, r13; final weak filtering mask, bits 0 and 1
jz .store
; weak filtering mask
- mov r11, r14
+ mov r11, r6
shr r11, 1
movd m12, r11d
- and r14, 1
- movd m11, r14d
+ and r6, 1
+ movd m11, r6d
shufps m11, m12, 0
pcmpeqd m11, [pd_1]; filtering mask
@@ -609,7 +572,11 @@ ALIGN 16
pminsw m12, m9; av_clip(delta0, -tc, tc)
psraw m9, 1; tc -> tc / 2
+%if cpuflag(ssse3)
+ psignw m14, m9, [pw_m1]; -tc / 2
+%else
pmullw m14, m9, [pw_m1]; -tc / 2
+%endif
pavgw m15, m1, m3; (p2 + p0 + 1) >> 1
psubw m15, m2; ((p2 + p0 + 1) >> 1) - p1
@@ -658,117 +625,161 @@ ALIGN 16
MASKED_COPY m4, m8
%endmacro
-INIT_XMM sse2
;-----------------------------------------------------------------------------
-; void ff_hevc_v_loop_filter_chroma(uint8_t *_pix, ptrdiff_t _stride, int *_tc,
+; void ff_hevc_v_loop_filter_chroma(uint8_t *_pix, ptrdiff_t _stride, int32_t *tc,
; uint8_t *_no_p, uint8_t *_no_q);
;-----------------------------------------------------------------------------
-cglobal hevc_v_loop_filter_chroma_8, 3, 6, 8
- sub r0, 2
- lea r5, [3 * r1]
- mov r4, r0
- add r0, r5
- TRANSPOSE4x8B_LOAD PASS8ROWS(r4, r0, r1, r5)
+%macro LOOP_FILTER_CHROMA 0
+cglobal hevc_v_loop_filter_chroma_8, 3, 5, 7, pix, stride, tc, pix0, r3stride
+ sub pixq, 2
+ lea r3strideq, [3*strideq]
+ mov pix0q, pixq
+ add pixq, r3strideq
+ TRANSPOSE4x8B_LOAD PASS8ROWS(pix0q, pixq, strideq, r3strideq)
CHROMA_DEBLOCK_BODY 8
- TRANSPOSE8x4B_STORE PASS8ROWS(r4, r0, r1, r5)
+ TRANSPOSE8x4B_STORE PASS8ROWS(pix0q, pixq, strideq, r3strideq)
RET
-cglobal hevc_v_loop_filter_chroma_10, 3, 6, 8
- sub r0, 4
- lea r5, [3 * r1]
- mov r4, r0
- add r0, r5
- TRANSPOSE4x8W_LOAD PASS8ROWS(r4, r0, r1, r5)
+cglobal hevc_v_loop_filter_chroma_10, 3, 5, 7, pix, stride, tc, pix0, r3stride
+ sub pixq, 4
+ lea r3strideq, [3*strideq]
+ mov pix0q, pixq
+ add pixq, r3strideq
+ TRANSPOSE4x8W_LOAD PASS8ROWS(pix0q, pixq, strideq, r3strideq)
CHROMA_DEBLOCK_BODY 10
- TRANSPOSE8x4W_STORE PASS8ROWS(r4, r0, r1, r5)
+ TRANSPOSE8x4W_STORE PASS8ROWS(pix0q, pixq, strideq, r3strideq), [pw_pixel_max_10]
+ RET
+
+cglobal hevc_v_loop_filter_chroma_12, 3, 5, 7, pix, stride, tc, pix0, r3stride
+ sub pixq, 4
+ lea r3strideq, [3*strideq]
+ mov pix0q, pixq
+ add pixq, r3strideq
+ TRANSPOSE4x8W_LOAD PASS8ROWS(pix0q, pixq, strideq, r3strideq)
+ CHROMA_DEBLOCK_BODY 12
+ TRANSPOSE8x4W_STORE PASS8ROWS(pix0q, pixq, strideq, r3strideq), [pw_pixel_max_12]
RET
;-----------------------------------------------------------------------------
-; void ff_hevc_h_loop_filter_chroma(uint8_t *_pix, ptrdiff_t _stride, int *_tc,
+; void ff_hevc_h_loop_filter_chroma(uint8_t *_pix, ptrdiff_t _stride, int32_t *tc,
; uint8_t *_no_p, uint8_t *_no_q);
;-----------------------------------------------------------------------------
-cglobal hevc_h_loop_filter_chroma_8, 3, 6, 8
- mov r5, r0; pix
- sub r5, r1
- sub r5, r1
- movh m0, [r5]; p1
- movh m1, [r5 + r1]; p0
- movh m2, [r0]; q0
- movh m3, [r0 + r1]; q1
+cglobal hevc_h_loop_filter_chroma_8, 3, 4, 7, pix, stride, tc, pix0
+ mov pix0q, pixq
+ sub pix0q, strideq
+ sub pix0q, strideq
+ movq m0, [pix0q]; p1
+ movq m1, [pix0q+strideq]; p0
+ movq m2, [pixq]; q0
+ movq m3, [pixq+strideq]; q1
pxor m5, m5; zeros reg
punpcklbw m0, m5
punpcklbw m1, m5
punpcklbw m2, m5
punpcklbw m3, m5
CHROMA_DEBLOCK_BODY 8
- packuswb m1, m2
- movh [r5 + r1], m1
- movhps [r0], m1
+ packuswb m1, m2
+ movh[pix0q+strideq], m1
+ movhps [pixq], m1
RET
-cglobal hevc_h_loop_filter_chroma_10, 3, 6, 8
- mov r5, r0; pix
- sub r5, r1
- sub r5, r1
- movdqu m0, [r5]; p1
- movdqu m1, [r5+r1]; p0
- movdqu m2, [r0]; q0
- movdqu m3, [r0 + r1]; q1
+cglobal hevc_h_loop_filter_chroma_10, 3, 4, 7, pix, stride, tc, pix0
+ mov pix0q, pixq
+ sub pix0q, strideq
+ sub pix0q, strideq
+ movu m0, [pix0q]; p1
+ movu m1, [pix0q+strideq]; p0
+ movu m2, [pixq]; q0
+ movu m3, [pixq+strideq]; q1
CHROMA_DEBLOCK_BODY 10
pxor m5, m5; zeros reg
- CLIPW m1, m5, [pw_pixel_max]
- CLIPW m2, m5, [pw_pixel_max]
- movdqu [r5 + r1], m1
- movdqu [r0], m2
+ CLIPW m1, m5, [pw_pixel_max_10]
+ CLIPW m2, m5, [pw_pixel_max_10]
+ movu [pix0q+strideq], m1
+ movu [pixq], m2
+ RET
+
+cglobal hevc_h_loop_filter_chroma_12, 3, 4, 7, pix, stride, tc, pix0
+ mov pix0q, pixq
+ sub pix0q, strideq
+ sub pix0q, strideq
+ movu m0, [pix0q]; p1
+ movu m1, [pix0q+strideq]; p0
+ movu m2, [pixq]; q0
+ movu m3, [pixq+strideq]; q1
+ CHROMA_DEBLOCK_BODY 12
+ pxor m5, m5; zeros reg
+ CLIPW m1, m5, [pw_pixel_max_12]
+ CLIPW m2, m5, [pw_pixel_max_12]
+ movu [pix0q+strideq], m1
+ movu [pixq], m2
RET
+%endmacro
+
+INIT_XMM sse2
+LOOP_FILTER_CHROMA
+INIT_XMM avx
+LOOP_FILTER_CHROMA
%if ARCH_X86_64
-INIT_XMM ssse3
+%macro LOOP_FILTER_LUMA 0
;-----------------------------------------------------------------------------
; void ff_hevc_v_loop_filter_luma(uint8_t *_pix, ptrdiff_t _stride, int beta,
-; int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+; int32_t *tc, uint8_t *_no_p, uint8_t *_no_q);
;-----------------------------------------------------------------------------
-cglobal hevc_v_loop_filter_luma_8, 4, 15, 16, pix, stride, beta, tc
- sub r0, 4
- lea r5, [3 * r1]
- mov r6, r0
- add r0, r5
- TRANSPOSE8x8B_LOAD PASS8ROWS(r6, r0, r1, r5)
+cglobal hevc_v_loop_filter_luma_8, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride
+ sub pixq, 4
+ lea pix0q, [3 * r1]
+ mov src3strideq, pixq
+ add pixq, pix0q
+ TRANSPOSE8x8B_LOAD PASS8ROWS(src3strideq, pixq, r1, pix0q)
LUMA_DEBLOCK_BODY 8, v
.store:
- TRANSPOSE8x8B_STORE PASS8ROWS(r6, r0, r1, r5)
+ TRANSPOSE8x8B_STORE PASS8ROWS(src3strideq, pixq, r1, pix0q)
.bypassluma:
RET
-cglobal hevc_v_loop_filter_luma_10, 4, 15, 16, pix, stride, beta, tc
+cglobal hevc_v_loop_filter_luma_10, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride
sub pixq, 8
- lea r5, [3 * strideq]
- mov r6, pixq
- add pixq, r5
- TRANSPOSE8x8W_LOAD PASS8ROWS(r6, pixq, strideq, r5)
+ lea pix0q, [3 * strideq]
+ mov src3strideq, pixq
+ add pixq, pix0q
+ TRANSPOSE8x8W_LOAD PASS8ROWS(src3strideq, pixq, strideq, pix0q)
LUMA_DEBLOCK_BODY 10, v
.store:
- TRANSPOSE8x8W_STORE PASS8ROWS(r6, r0, r1, r5)
+ TRANSPOSE8x8W_STORE PASS8ROWS(src3strideq, pixq, r1, pix0q), [pw_pixel_max_10]
+.bypassluma:
+ RET
+
+cglobal hevc_v_loop_filter_luma_12, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride
+ sub pixq, 8
+ lea pix0q, [3 * strideq]
+ mov src3strideq, pixq
+ add pixq, pix0q
+ TRANSPOSE8x8W_LOAD PASS8ROWS(src3strideq, pixq, strideq, pix0q)
+ LUMA_DEBLOCK_BODY 12, v
+.store:
+ TRANSPOSE8x8W_STORE PASS8ROWS(src3strideq, pixq, r1, pix0q), [pw_pixel_max_12]
.bypassluma:
RET
;-----------------------------------------------------------------------------
; void ff_hevc_h_loop_filter_luma(uint8_t *_pix, ptrdiff_t _stride, int beta,
-; int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+; int32_t *tc, uint8_t *_no_p, uint8_t *_no_q);
;-----------------------------------------------------------------------------
-cglobal hevc_h_loop_filter_luma_8, 4, 15, 16, pix, stride, beta, tc, count, pix0, src3stride
+cglobal hevc_h_loop_filter_luma_8, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride
lea src3strideq, [3 * strideq]
mov pix0q, pixq
sub pix0q, src3strideq
sub pix0q, strideq
- movdqu m0, [pix0q]; p3
- movdqu m1, [pix0q + strideq]; p2
- movdqu m2, [pix0q + 2 * strideq]; p1
- movdqu m3, [pix0q + src3strideq]; p0
- movdqu m4, [pixq]; q0
- movdqu m5, [pixq + strideq]; q1
- movdqu m6, [pixq + 2 * strideq]; q2
- movdqu m7, [pixq + src3strideq]; q3
+ movq m0, [pix0q]; p3
+ movq m1, [pix0q + strideq]; p2
+ movq m2, [pix0q + 2 * strideq]; p1
+ movq m3, [pix0q + src3strideq]; p0
+ movq m4, [pixq]; q0
+ movq m5, [pixq + strideq]; q1
+ movq m6, [pixq + 2 * strideq]; q2
+ movq m7, [pixq + src3strideq]; q3
pxor m8, m8
punpcklbw m0, m8
punpcklbw m1, m8
@@ -783,16 +794,16 @@ cglobal hevc_h_loop_filter_luma_8, 4, 15, 16, pix, stride, beta, tc, count, pix0
packuswb m1, m2
packuswb m3, m4
packuswb m5, m6
- movh [r5 + r1], m1
- movhps [r5 + 2 * r1], m1
- movh [r5 + r6], m3
- movhps [r0 ], m3
- movh [r0 + r1], m5
- movhps [r0 + 2 * r1], m5
+ movh [pix0q + strideq], m1
+ movhps [pix0q + 2 * strideq], m1
+ movh [pix0q + src3strideq], m3
+ movhps [pixq ], m3
+ movh [pixq + strideq], m5
+ movhps [pixq + 2 * strideq], m5
.bypassluma:
RET
-cglobal hevc_h_loop_filter_luma_10, 4, 15, 16, pix, stride, beta, tc, count, pix0, src3stride
+cglobal hevc_h_loop_filter_luma_10, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride
lea src3strideq, [3 * strideq]
mov pix0q, pixq
sub pix0q, src3strideq
@@ -808,12 +819,43 @@ cglobal hevc_h_loop_filter_luma_10, 4, 15, 16, pix, stride, beta, tc, count, pix
LUMA_DEBLOCK_BODY 10, h
.store:
pxor m8, m8; zeros reg
- CLIPW m1, m8, [pw_pixel_max]
- CLIPW m2, m8, [pw_pixel_max]
- CLIPW m3, m8, [pw_pixel_max]
- CLIPW m4, m8, [pw_pixel_max]
- CLIPW m5, m8, [pw_pixel_max]
- CLIPW m6, m8, [pw_pixel_max]
+ CLIPW m1, m8, [pw_pixel_max_10]
+ CLIPW m2, m8, [pw_pixel_max_10]
+ CLIPW m3, m8, [pw_pixel_max_10]
+ CLIPW m4, m8, [pw_pixel_max_10]
+ CLIPW m5, m8, [pw_pixel_max_10]
+ CLIPW m6, m8, [pw_pixel_max_10]
+ movdqu [pix0q + strideq], m1; p2
+ movdqu [pix0q + 2 * strideq], m2; p1
+ movdqu [pix0q + src3strideq], m3; p0
+ movdqu [pixq ], m4; q0
+ movdqu [pixq + strideq], m5; q1
+ movdqu [pixq + 2 * strideq], m6; q2
+.bypassluma:
+ RET
+
+cglobal hevc_h_loop_filter_luma_12, 4, 14, 16, pix, stride, beta, tc, pix0, src3stride
+ lea src3strideq, [3 * strideq]
+ mov pix0q, pixq
+ sub pix0q, src3strideq
+ sub pix0q, strideq
+ movdqu m0, [pix0q]; p3
+ movdqu m1, [pix0q + strideq]; p2
+ movdqu m2, [pix0q + 2 * strideq]; p1
+ movdqu m3, [pix0q + src3strideq]; p0
+ movdqu m4, [pixq]; q0
+ movdqu m5, [pixq + strideq]; q1
+ movdqu m6, [pixq + 2 * strideq]; q2
+ movdqu m7, [pixq + src3strideq]; q3
+ LUMA_DEBLOCK_BODY 12, h
+.store:
+ pxor m8, m8; zeros reg
+ CLIPW m1, m8, [pw_pixel_max_12]
+ CLIPW m2, m8, [pw_pixel_max_12]
+ CLIPW m3, m8, [pw_pixel_max_12]
+ CLIPW m4, m8, [pw_pixel_max_12]
+ CLIPW m5, m8, [pw_pixel_max_12]
+ CLIPW m6, m8, [pw_pixel_max_12]
movdqu [pix0q + strideq], m1; p2
movdqu [pix0q + 2 * strideq], m2; p1
movdqu [pix0q + src3strideq], m3; p0
@@ -822,4 +864,13 @@ cglobal hevc_h_loop_filter_luma_10, 4, 15, 16, pix, stride, beta, tc, count, pix
movdqu [pixq + 2 * strideq], m6; q2
.bypassluma:
RET
+
+%endmacro
+
+INIT_XMM sse2
+LOOP_FILTER_LUMA
+INIT_XMM ssse3
+LOOP_FILTER_LUMA
+INIT_XMM avx
+LOOP_FILTER_LUMA
%endif
diff --git a/libavcodec/x86/hevc_idct.asm b/libavcodec/x86/hevc_idct.asm
new file mode 100644
index 0000000000..481726d217
--- /dev/null
+++ b/libavcodec/x86/hevc_idct.asm
@@ -0,0 +1,122 @@
+; /*
+; * SIMD optimized idct functions for HEVC decoding
+; * Copyright (c) 2014 Pierre-Edouard LEPERE
+; * Copyright (c) 2014 James Almer
+; *
+; * This file is part of FFmpeg.
+; *
+; * FFmpeg is free software; you can redistribute it and/or
+; * modify it under the terms of the GNU Lesser General Public
+; * License as published by the Free Software Foundation; either
+; * version 2.1 of the License, or (at your option) any later version.
+; *
+; * FFmpeg is distributed in the hope that it will be useful,
+; * but WITHOUT ANY WARRANTY; without even the implied warranty of
+; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; * Lesser General Public License for more details.
+; *
+; * You should have received a copy of the GNU Lesser General Public
+; * License along with FFmpeg; if not, write to the Free Software
+; * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+; */
+%include "libavutil/x86/x86util.asm"
+
+SECTION_TEXT 32
+
+; void ff_hevc_idctHxW_dc_{8,10}_<opt>(int16_t *coeffs)
+; %1 = HxW
+; %2 = number of loops
+; %3 = bitdepth
+%macro IDCT_DC 3
+cglobal hevc_idct%1x%1_dc_%3, 1, 2, 1, coeff, tmp
+ movsx tmpq, word [coeffq]
+ add tmpw, ((1 << 14-%3) + 1)
+ sar tmpw, (15-%3)
+ movd xm0, tmpd
+ SPLATW m0, xm0
+ DEFINE_ARGS coeff, cnt
+ mov cntd, %2
+.loop:
+ mova [coeffq+mmsize*0], m0
+ mova [coeffq+mmsize*1], m0
+ mova [coeffq+mmsize*2], m0
+ mova [coeffq+mmsize*3], m0
+ mova [coeffq+mmsize*4], m0
+ mova [coeffq+mmsize*5], m0
+ mova [coeffq+mmsize*6], m0
+ mova [coeffq+mmsize*7], m0
+ add coeffq, mmsize*8
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+; %1 = HxW
+; %2 = bitdepth
+%macro IDCT_DC_NL 2 ; No loop
+cglobal hevc_idct%1x%1_dc_%2, 1, 2, 1, coeff, tmp
+ movsx tmpq, word [coeffq]
+ add tmpw, ((1 << 14-%2) + 1)
+ sar tmpw, (15-%2)
+ movd m0, tmpd
+ SPLATW m0, xm0
+ mova [coeffq+mmsize*0], m0
+ mova [coeffq+mmsize*1], m0
+ mova [coeffq+mmsize*2], m0
+ mova [coeffq+mmsize*3], m0
+%if mmsize == 16
+ mova [coeffq+mmsize*4], m0
+ mova [coeffq+mmsize*5], m0
+ mova [coeffq+mmsize*6], m0
+ mova [coeffq+mmsize*7], m0
+%endif
+ RET
+%endmacro
+
+; 8-bit
+INIT_MMX mmxext
+IDCT_DC_NL 4, 8
+IDCT_DC 8, 2, 8
+
+INIT_XMM sse2
+IDCT_DC_NL 8, 8
+IDCT_DC 16, 4, 8
+IDCT_DC 32, 16, 8
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+IDCT_DC 16, 2, 8
+IDCT_DC 32, 8, 8
+%endif ;HAVE_AVX2_EXTERNAL
+
+; 10-bit
+INIT_MMX mmxext
+IDCT_DC_NL 4, 10
+IDCT_DC 8, 2, 10
+
+INIT_XMM sse2
+IDCT_DC_NL 8, 10
+IDCT_DC 16, 4, 10
+IDCT_DC 32, 16, 10
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+IDCT_DC 16, 2, 10
+IDCT_DC 32, 8, 10
+%endif ;HAVE_AVX2_EXTERNAL
+
+; 12-bit
+INIT_MMX mmxext
+IDCT_DC_NL 4, 12
+IDCT_DC 8, 2, 12
+
+INIT_XMM sse2
+IDCT_DC_NL 8, 12
+IDCT_DC 16, 4, 12
+IDCT_DC 32, 16, 12
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+IDCT_DC 16, 2, 12
+IDCT_DC 32, 8, 12
+%endif ;HAVE_AVX2_EXTERNAL
diff --git a/libavcodec/x86/hevc_mc.asm b/libavcodec/x86/hevc_mc.asm
new file mode 100644
index 0000000000..986493f20c
--- /dev/null
+++ b/libavcodec/x86/hevc_mc.asm
@@ -0,0 +1,1671 @@
+; /*
+; * Provide SSE luma and chroma mc functions for HEVC decoding
+; * Copyright (c) 2013 Pierre-Edouard LEPERE
+; *
+; * This file is part of FFmpeg.
+; *
+; * FFmpeg is free software; you can redistribute it and/or
+; * modify it under the terms of the GNU Lesser General Public
+; * License as published by the Free Software Foundation; either
+; * version 2.1 of the License, or (at your option) any later version.
+; *
+; * FFmpeg is distributed in the hope that it will be useful,
+; * but WITHOUT ANY WARRANTY; without even the implied warranty of
+; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; * Lesser General Public License for more details.
+; *
+; * You should have received a copy of the GNU Lesser General Public
+; * License along with FFmpeg; if not, write to the Free Software
+; * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+; */
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+cextern pw_255
+cextern pw_512
+cextern pw_2048
+cextern pw_8192
+cextern pw_1023
+cextern pw_1024
+cextern pw_4096
+%define pw_8 pw_512
+%define pw_10 pw_2048
+%define pw_12 pw_8192
+%define pw_bi_10 pw_1024
+%define pw_bi_12 pw_4096
+%define max_pixels_8 pw_255
+%define max_pixels_10 pw_1023
+pw_bi_8: times 16 dw (1 << 8)
+max_pixels_12: times 16 dw ((1 << 12)-1)
+cextern pd_1
+cextern pb_0
+
+SECTION_TEXT 32
+%macro EPEL_TABLE 4
+hevc_epel_filters_%4_%1 times %2 d%3 -2, 58
+ times %2 d%3 10, -2
+ times %2 d%3 -4, 54
+ times %2 d%3 16, -2
+ times %2 d%3 -6, 46
+ times %2 d%3 28, -4
+ times %2 d%3 -4, 36
+ times %2 d%3 36, -4
+ times %2 d%3 -4, 28
+ times %2 d%3 46, -6
+ times %2 d%3 -2, 16
+ times %2 d%3 54, -4
+ times %2 d%3 -2, 10
+ times %2 d%3 58, -2
+%endmacro
+
+
+EPEL_TABLE 8,16, b, avx2
+EPEL_TABLE 10, 8, w, avx2
+
+EPEL_TABLE 8, 8, b, sse4
+EPEL_TABLE 10, 4, w, sse4
+EPEL_TABLE 12, 4, w, sse4
+
+%macro QPEL_TABLE 4
+hevc_qpel_filters_%4_%1 times %2 d%3 -1, 4
+ times %2 d%3 -10, 58
+ times %2 d%3 17, -5
+ times %2 d%3 1, 0
+ times %2 d%3 -1, 4
+ times %2 d%3 -11, 40
+ times %2 d%3 40,-11
+ times %2 d%3 4, -1
+ times %2 d%3 0, 1
+ times %2 d%3 -5, 17
+ times %2 d%3 58,-10
+ times %2 d%3 4, -1
+%endmacro
+
+QPEL_TABLE 8, 8, b, sse4
+QPEL_TABLE 10, 4, w, sse4
+QPEL_TABLE 12, 4, w, sse4
+
+QPEL_TABLE 8,16, b, avx2
+QPEL_TABLE 10, 8, w, avx2
+
+%define MAX_PB_SIZE 64
+
+%define hevc_qpel_filters_sse4_14 hevc_qpel_filters_sse4_10
+
+%define hevc_qpel_filters_avx2_14 hevc_qpel_filters_avx2_10
+
+%if ARCH_X86_64
+
+%macro SIMPLE_BILOAD 4 ;width, tab, r1, r2
+%if %1 <= 4
+ movq %3, [%2] ; load data from source2
+%elif %1 <= 8
+ movdqa %3, [%2] ; load data from source2
+%elif %1 <= 12
+%if cpuflag(avx2)
+ mova %3, [%2]
+%else
+ movdqa %3, [%2] ; load data from source2
+ movq %4, [%2+16] ; load data from source2
+%endif ;avx
+%elif %1 <= 16
+%if cpuflag(avx2)
+ mova %3, [%2]
+%else
+ movdqa %3, [%2] ; load data from source2
+ movdqa %4, [%2+16] ; load data from source2
+%endif ; avx
+%else ; %1 = 32
+ mova %3, [%2]
+ mova %4, [%2+32]
+%endif
+%endmacro
+
+%macro SIMPLE_LOAD 4 ;width, bitd, tab, r1
+%if %1 == 2 || (%2 == 8 && %1 <= 4)
+ movd %4, [%3] ; load data from source
+%elif %1 == 4 || (%2 == 8 && %1 <= 8)
+ movq %4, [%3] ; load data from source
+%elif notcpuflag(avx)
+ movu %4, [%3] ; load data from source
+%elif %1 <= 8 || (%2 == 8 && %1 <= 16)
+ movdqu %4, [%3]
+%else
+ movu %4, [%3]
+%endif
+%endmacro
+
+
+%macro EPEL_FILTER 5 ; bit depth, filter index, xmma, xmmb, gprtmp
+%if cpuflag(avx2)
+%assign %%offset 32
+%ifdef PIC
+ lea %5q, [hevc_epel_filters_avx2_%1]
+ %define FILTER %5q
+%else
+ %define FILTER hevc_epel_filters_avx2_%1
+%endif
+%else
+%assign %%offset 16
+%ifdef PIC
+ lea %5q, [hevc_epel_filters_sse4_%1]
+ %define FILTER %5q
+%else
+ %define FILTER hevc_epel_filters_sse4_%1
+%endif
+%endif ;cpuflag(avx2)
+ sub %2q, 1
+%if cpuflag(avx2)
+ shl %2q, 6 ; multiply by 64
+ %else
+ shl %2q, 5 ; multiply by 32
+%endif
+ mova %3, [FILTER + %2q] ; get 2 first values of filters
+ mova %4, [FILTER + %2q+%%offset] ; get 2 last values of filters
+%endmacro
+
+%macro EPEL_HV_FILTER 1
+%if cpuflag(avx2)
+%assign %%offset 32
+%assign %%shift 6
+%define %%table hevc_epel_filters_avx2_%1
+%else
+%assign %%offset 16
+%assign %%shift 5
+%define %%table hevc_epel_filters_sse4_%1
+%endif
+
+%ifdef PIC
+ lea r3srcq, [%%table]
+ %define FILTER r3srcq
+%else
+ %define FILTER %%table
+%endif
+ sub mxq, 1
+ sub myq, 1
+ shl mxq, %%shift ; multiply by 32
+ shl myq, %%shift ; multiply by 32
+ mova m14, [FILTER + mxq] ; get 2 first values of filters
+ mova m15, [FILTER + mxq+%%offset] ; get 2 last values of filters
+
+%if cpuflag(avx2)
+%define %%table hevc_epel_filters_avx2_10
+%else
+%define %%table hevc_epel_filters_sse4_10
+%endif
+%ifdef PIC
+ lea r3srcq, [%%table]
+ %define FILTER r3srcq
+%else
+ %define FILTER %%table
+%endif
+ mova m12, [FILTER + myq] ; get 2 first values of filters
+ mova m13, [FILTER + myq+%%offset] ; get 2 last values of filters
+ lea r3srcq, [srcstrideq*3]
+%endmacro
+
+%macro QPEL_FILTER 2
+
+%if cpuflag(avx2)
+%assign %%offset 32
+%assign %%shift 7
+%define %%table hevc_qpel_filters_avx2_%1
+%else
+%assign %%offset 16
+%assign %%shift 6
+%define %%table hevc_qpel_filters_sse4_%1
+%endif
+
+%ifdef PIC
+ lea rfilterq, [%%table]
+%else
+ %define rfilterq %%table
+%endif
+ sub %2q, 1
+ shl %2q, %%shift ; multiply by 32
+ mova m12, [rfilterq + %2q] ; get 4 first values of filters
+ mova m13, [rfilterq + %2q + %%offset] ; get 4 first values of filters
+ mova m14, [rfilterq + %2q + 2*%%offset] ; get 4 first values of filters
+ mova m15, [rfilterq + %2q + 3*%%offset] ; get 4 first values of filters
+%endmacro
+
+%macro EPEL_LOAD 4
+%if (%1 == 8 && %4 <= 4)
+%define %%load movd
+%elif (%1 == 8 && %4 <= 8) || (%1 > 8 && %4 <= 4)
+%define %%load movq
+%else
+%define %%load movdqu
+%endif
+
+ %%load m0, [%2q ]
+%ifnum %3
+ %%load m1, [%2q+ %3]
+ %%load m2, [%2q+2*%3]
+ %%load m3, [%2q+3*%3]
+%else
+ %%load m1, [%2q+ %3q]
+ %%load m2, [%2q+2*%3q]
+ %%load m3, [%2q+r3srcq]
+%endif
+%if %1 == 8
+%if %4 > 8
+ SBUTTERFLY bw, 0, 1, 7
+ SBUTTERFLY bw, 2, 3, 7
+%else
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+%endif
+%else
+%if %4 > 4
+ SBUTTERFLY wd, 0, 1, 7
+ SBUTTERFLY wd, 2, 3, 7
+%else
+ punpcklwd m0, m1
+ punpcklwd m2, m3
+%endif
+%endif
+%endmacro
+
+
+%macro QPEL_H_LOAD 4
+%assign %%stride (%1+7)/8
+%if %1 == 8
+%if %3 <= 4
+%define %%load movd
+%elif %3 == 8
+%define %%load movq
+%else
+%define %%load movu
+%endif
+%else
+%if %3 == 2
+%define %%load movd
+%elif %3 == 4
+%define %%load movq
+%else
+%define %%load movu
+%endif
+%endif
+ %%load m0, [%2-3*%%stride] ;load data from source
+ %%load m1, [%2-2*%%stride]
+ %%load m2, [%2-%%stride ]
+ %%load m3, [%2 ]
+ %%load m4, [%2+%%stride ]
+ %%load m5, [%2+2*%%stride]
+ %%load m6, [%2+3*%%stride]
+ %%load m7, [%2+4*%%stride]
+
+%if %1 == 8
+%if %3 > 8
+ SBUTTERFLY wd, 0, 1, %4
+ SBUTTERFLY wd, 2, 3, %4
+ SBUTTERFLY wd, 4, 5, %4
+ SBUTTERFLY wd, 6, 7, %4
+%else
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ punpcklbw m4, m5
+ punpcklbw m6, m7
+%endif
+%else
+%if %3 > 4
+ SBUTTERFLY dq, 0, 1, %4
+ SBUTTERFLY dq, 2, 3, %4
+ SBUTTERFLY dq, 4, 5, %4
+ SBUTTERFLY dq, 6, 7, %4
+%else
+ punpcklwd m0, m1
+ punpcklwd m2, m3
+ punpcklwd m4, m5
+ punpcklwd m6, m7
+%endif
+%endif
+%endmacro
+
+%macro QPEL_V_LOAD 5
+ lea %5q, [%2]
+ sub %5q, r3srcq
+ movu m0, [%5q ] ;load x- 3*srcstride
+ movu m1, [%5q+ %3q ] ;load x- 2*srcstride
+ movu m2, [%5q+ 2*%3q ] ;load x-srcstride
+ movu m3, [%2 ] ;load x
+ movu m4, [%2+ %3q] ;load x+stride
+ movu m5, [%2+ 2*%3q] ;load x+2*stride
+ movu m6, [%2+r3srcq] ;load x+3*stride
+ movu m7, [%2+ 4*%3q] ;load x+4*stride
+%if %1 == 8
+%if %4 > 8
+ SBUTTERFLY bw, 0, 1, 8
+ SBUTTERFLY bw, 2, 3, 8
+ SBUTTERFLY bw, 4, 5, 8
+ SBUTTERFLY bw, 6, 7, 8
+%else
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ punpcklbw m4, m5
+ punpcklbw m6, m7
+%endif
+%else
+%if %4 > 4
+ SBUTTERFLY wd, 0, 1, 8
+ SBUTTERFLY wd, 2, 3, 8
+ SBUTTERFLY wd, 4, 5, 8
+ SBUTTERFLY wd, 6, 7, 8
+%else
+ punpcklwd m0, m1
+ punpcklwd m2, m3
+ punpcklwd m4, m5
+ punpcklwd m6, m7
+%endif
+%endif
+%endmacro
+
+%macro PEL_12STORE2 3
+ movd [%1], %2
+%endmacro
+%macro PEL_12STORE4 3
+ movq [%1], %2
+%endmacro
+%macro PEL_12STORE6 3
+ movq [%1], %2
+ psrldq %2, 8
+ movd [%1+8], %2
+%endmacro
+%macro PEL_12STORE8 3
+ movdqa [%1], %2
+%endmacro
+%macro PEL_12STORE12 3
+ movdqa [%1], %2
+ movq [%1+16], %3
+%endmacro
+%macro PEL_12STORE16 3
+ PEL_12STORE8 %1, %2, %3
+ movdqa [%1+16], %3
+%endmacro
+
+%macro PEL_10STORE2 3
+ movd [%1], %2
+%endmacro
+%macro PEL_10STORE4 3
+ movq [%1], %2
+%endmacro
+%macro PEL_10STORE6 3
+ movq [%1], %2
+ psrldq %2, 8
+ movd [%1+8], %2
+%endmacro
+%macro PEL_10STORE8 3
+ movdqa [%1], %2
+%endmacro
+%macro PEL_10STORE12 3
+ movdqa [%1], %2
+ movq [%1+16], %3
+%endmacro
+%macro PEL_10STORE16 3
+%if cpuflag(avx2)
+ movu [%1], %2
+%else
+ PEL_10STORE8 %1, %2, %3
+ movdqa [%1+16], %3
+%endif
+%endmacro
+
+%macro PEL_10STORE32 3
+ PEL_10STORE16 %1, %2, %3
+ movu [%1+32], %3
+%endmacro
+
+%macro PEL_8STORE2 3
+ pextrw [%1], %2, 0
+%endmacro
+%macro PEL_8STORE4 3
+ movd [%1], %2
+%endmacro
+%macro PEL_8STORE6 3
+ movd [%1], %2
+ pextrw [%1+4], %2, 2
+%endmacro
+%macro PEL_8STORE8 3
+ movq [%1], %2
+%endmacro
+%macro PEL_8STORE12 3
+ movq [%1], %2
+ psrldq %2, 8
+ movd [%1+8], %2
+%endmacro
+%macro PEL_8STORE16 3
+%if cpuflag(avx2)
+ movdqu [%1], %2
+%else
+ mova [%1], %2
+%endif ; avx
+%endmacro
+%macro PEL_8STORE32 3
+ movu [%1], %2
+%endmacro
+
+%macro LOOP_END 3
+ add %1q, 2*MAX_PB_SIZE ; dst += dststride
+ add %2q, %3q ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+%endmacro
+
+
+%macro MC_PIXEL_COMPUTE 2-3 ;width, bitdepth
+%if %2 == 8
+%if cpuflag(avx2) && %0 ==3
+%if %1 > 16
+ vextracti128 xm1, m0, 1
+ pmovzxbw m1, xm1
+ psllw m1, 14-%2
+%endif
+ pmovzxbw m0, xm0
+%else ; not avx
+%if %1 > 8
+ punpckhbw m1, m0, m2
+ psllw m1, 14-%2
+%endif
+ punpcklbw m0, m2
+%endif
+%endif ;avx
+ psllw m0, 14-%2
+%endmacro
+
+%macro EPEL_COMPUTE 4-8 ; bitdepth, width, filter1, filter2, HV/m0, m2, m1, m3
+%if %0 == 8
+%define %%reg0 %5
+%define %%reg2 %6
+%define %%reg1 %7
+%define %%reg3 %8
+%else
+%define %%reg0 m0
+%define %%reg2 m2
+%define %%reg1 m1
+%define %%reg3 m3
+%endif
+%if %1 == 8
+%if cpuflag(avx2) && (%0 == 5)
+%if %2 > 16
+ vperm2i128 m10, m0, m1, q0301
+%endif
+ vinserti128 m0, m0, xm1, 1
+ mova m1, m10
+%if %2 > 16
+ vperm2i128 m10, m2, m3, q0301
+%endif
+ vinserti128 m2, m2, xm3, 1
+ mova m3, m10
+%endif
+ pmaddubsw %%reg0, %3 ;x1*c1+x2*c2
+ pmaddubsw %%reg2, %4 ;x3*c3+x4*c4
+ paddw %%reg0, %%reg2
+%if %2 > 8
+ pmaddubsw %%reg1, %3
+ pmaddubsw %%reg3, %4
+ paddw %%reg1, %%reg3
+%endif
+%else
+ pmaddwd %%reg0, %3
+ pmaddwd %%reg2, %4
+ paddd %%reg0, %%reg2
+%if %2 > 4
+ pmaddwd %%reg1, %3
+ pmaddwd %%reg3, %4
+ paddd %%reg1, %%reg3
+%if %1 != 8
+ psrad %%reg1, %1-8
+%endif
+%endif
+%if %1 != 8
+ psrad %%reg0, %1-8
+%endif
+ packssdw %%reg0, %%reg1
+%endif
+%endmacro
+
+%macro QPEL_HV_COMPUTE 4 ; width, bitdepth, filter idx
+
+%if cpuflag(avx2)
+%assign %%offset 32
+%define %%table hevc_qpel_filters_avx2_%2
+%else
+%assign %%offset 16
+%define %%table hevc_qpel_filters_sse4_%2
+%endif
+
+%ifdef PIC
+ lea rfilterq, [%%table]
+%else
+ %define rfilterq %%table
+%endif
+
+%if %2 == 8
+ pmaddubsw m0, [rfilterq + %3q*8 ] ;x1*c1+x2*c2
+ pmaddubsw m2, [rfilterq + %3q*8+%%offset] ;x3*c3+x4*c4
+ pmaddubsw m4, [rfilterq + %3q*8+2*%%offset] ;x5*c5+x6*c6
+ pmaddubsw m6, [rfilterq + %3q*8+3*%%offset] ;x7*c7+x8*c8
+ paddw m0, m2
+ paddw m4, m6
+ paddw m0, m4
+%else
+ pmaddwd m0, [rfilterq + %3q*8 ]
+ pmaddwd m2, [rfilterq + %3q*8+%%offset]
+ pmaddwd m4, [rfilterq + %3q*8+2*%%offset]
+ pmaddwd m6, [rfilterq + %3q*8+3*%%offset]
+ paddd m0, m2
+ paddd m4, m6
+ paddd m0, m4
+%if %2 != 8
+ psrad m0, %2-8
+%endif
+%if %1 > 4
+ pmaddwd m1, [rfilterq + %3q*8 ]
+ pmaddwd m3, [rfilterq + %3q*8+%%offset]
+ pmaddwd m5, [rfilterq + %3q*8+2*%%offset]
+ pmaddwd m7, [rfilterq + %3q*8+3*%%offset]
+ paddd m1, m3
+ paddd m5, m7
+ paddd m1, m5
+%if %2 != 8
+ psrad m1, %2-8
+%endif
+%endif
+ p%4 m0, m1
+%endif
+%endmacro
+
+%macro QPEL_COMPUTE 2-3 ; width, bitdepth
+%if %2 == 8
+%if cpuflag(avx2) && (%0 == 3)
+
+ vperm2i128 m10, m0, m1, q0301
+ vinserti128 m0, m0, xm1, 1
+ SWAP 1, 10
+
+ vperm2i128 m10, m2, m3, q0301
+ vinserti128 m2, m2, xm3, 1
+ SWAP 3, 10
+
+
+ vperm2i128 m10, m4, m5, q0301
+ vinserti128 m4, m4, xm5, 1
+ SWAP 5, 10
+
+ vperm2i128 m10, m6, m7, q0301
+ vinserti128 m6, m6, xm7, 1
+ SWAP 7, 10
+%endif
+
+ pmaddubsw m0, m12 ;x1*c1+x2*c2
+ pmaddubsw m2, m13 ;x3*c3+x4*c4
+ pmaddubsw m4, m14 ;x5*c5+x6*c6
+ pmaddubsw m6, m15 ;x7*c7+x8*c8
+ paddw m0, m2
+ paddw m4, m6
+ paddw m0, m4
+%if %1 > 8
+ pmaddubsw m1, m12
+ pmaddubsw m3, m13
+ pmaddubsw m5, m14
+ pmaddubsw m7, m15
+ paddw m1, m3
+ paddw m5, m7
+ paddw m1, m5
+%endif
+%else
+ pmaddwd m0, m12
+ pmaddwd m2, m13
+ pmaddwd m4, m14
+ pmaddwd m6, m15
+ paddd m0, m2
+ paddd m4, m6
+ paddd m0, m4
+%if %2 != 8
+ psrad m0, %2-8
+%endif
+%if %1 > 4
+ pmaddwd m1, m12
+ pmaddwd m3, m13
+ pmaddwd m5, m14
+ pmaddwd m7, m15
+ paddd m1, m3
+ paddd m5, m7
+ paddd m1, m5
+%if %2 != 8
+ psrad m1, %2-8
+%endif
+%endif
+%endif
+%endmacro
+
+%macro BI_COMPUTE 7-8 ; width, bitd, src1l, src1h, scr2l, scr2h, pw
+ paddsw %3, %5
+%if %1 > 8
+ paddsw %4, %6
+%endif
+ UNI_COMPUTE %1, %2, %3, %4, %7
+%if %0 == 8 && cpuflag(avx2) && (%2 == 8)
+ vpermq %3, %3, 216
+ vpermq %4, %4, 216
+%endif
+%endmacro
+
+%macro UNI_COMPUTE 5
+ pmulhrsw %3, %5
+%if %1 > 8 || (%2 > 8 && %1 > 4)
+ pmulhrsw %4, %5
+%endif
+%if %2 == 8
+ packuswb %3, %4
+%else
+ CLIPW %3, [pb_0], [max_pixels_%2]
+%if (%1 > 8 && notcpuflag(avx)) || %1 > 16
+ CLIPW %4, [pb_0], [max_pixels_%2]
+%endif
+%endif
+%endmacro
+
+
+; ******************************
+; void put_hevc_mc_pixels(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my)
+; ******************************
+
+%macro HEVC_PUT_HEVC_PEL_PIXELS 2
+HEVC_PEL_PIXELS %1, %2
+HEVC_UNI_PEL_PIXELS %1, %2
+HEVC_BI_PEL_PIXELS %1, %2
+%endmacro
+
+%macro HEVC_PEL_PIXELS 2
+cglobal hevc_put_hevc_pel_pixels%1_%2, 4, 4, 3, dst, src, srcstride,height
+ pxor m2, m2
+.loop
+ SIMPLE_LOAD %1, %2, srcq, m0
+ MC_PIXEL_COMPUTE %1, %2, 1
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+ %endmacro
+
+%macro HEVC_UNI_PEL_PIXELS 2
+cglobal hevc_put_hevc_uni_pel_pixels%1_%2, 5, 5, 2, dst, dststride, src, srcstride,height
+.loop
+ SIMPLE_LOAD %1, %2, srcq, m0
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+%macro HEVC_BI_PEL_PIXELS 2
+cglobal hevc_put_hevc_bi_pel_pixels%1_%2, 6, 6, 6, dst, dststride, src, srcstride, src2, height
+ pxor m2, m2
+ movdqa m5, [pw_bi_%2]
+.loop
+ SIMPLE_LOAD %1, %2, srcq, m0
+ SIMPLE_BILOAD %1, src2q, m3, m4
+ MC_PIXEL_COMPUTE %1, %2, 1
+ BI_COMPUTE %1, %2, m0, m1, m3, m4, m5, 1
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+
+; ******************************
+; void put_hevc_epel_hX(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my, int width);
+; ******************************
+
+
+%macro HEVC_PUT_HEVC_EPEL 2
+%if cpuflag(avx2)
+%define XMM_REGS 11
+%else
+%define XMM_REGS 8
+%endif
+
+cglobal hevc_put_hevc_epel_h%1_%2, 5, 6, XMM_REGS, dst, src, srcstride, height, mx, rfilter
+%assign %%stride ((%2 + 7)/8)
+ EPEL_FILTER %2, mx, m4, m5, rfilter
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m4, m5, 1
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_epel_h%1_%2, 6, 7, XMM_REGS, dst, dststride, src, srcstride, height, mx, rfilter
+%assign %%stride ((%2 + 7)/8)
+ movdqa m6, [pw_%2]
+ EPEL_FILTER %2, mx, m4, m5, rfilter
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m4, m5
+ UNI_COMPUTE %1, %2, m0, m1, m6
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+cglobal hevc_put_hevc_bi_epel_h%1_%2, 7, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, mx, rfilter
+ movdqa m6, [pw_bi_%2]
+ EPEL_FILTER %2, mx, m4, m5, rfilter
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m4, m5, 1
+ SIMPLE_BILOAD %1, src2q, m2, m3
+ BI_COMPUTE %1, %2, m0, m1, m2, m3, m6, 1
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+; ******************************
+; void put_hevc_epel_v(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my, int width)
+; ******************************
+
+cglobal hevc_put_hevc_epel_v%1_%2, 4, 6, XMM_REGS, dst, src, srcstride, height, r3src, my
+ movifnidn myd, mym
+ sub srcq, srcstrideq
+ EPEL_FILTER %2, my, m4, m5, r3src
+ lea r3srcq, [srcstrideq*3]
+.loop
+ EPEL_LOAD %2, srcq, srcstride, %1
+ EPEL_COMPUTE %2, %1, m4, m5, 1
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_epel_v%1_%2, 5, 7, XMM_REGS, dst, dststride, src, srcstride, height, r3src, my
+ movifnidn myd, mym
+ movdqa m6, [pw_%2]
+ sub srcq, srcstrideq
+ EPEL_FILTER %2, my, m4, m5, r3src
+ lea r3srcq, [srcstrideq*3]
+.loop
+ EPEL_LOAD %2, srcq, srcstride, %1
+ EPEL_COMPUTE %2, %1, m4, m5
+ UNI_COMPUTE %1, %2, m0, m1, m6
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+
+cglobal hevc_put_hevc_bi_epel_v%1_%2, 6, 8, XMM_REGS, dst, dststride, src, srcstride, src2, height, r3src, my
+ movifnidn myd, mym
+ movdqa m6, [pw_bi_%2]
+ sub srcq, srcstrideq
+ EPEL_FILTER %2, my, m4, m5, r3src
+ lea r3srcq, [srcstrideq*3]
+.loop
+ EPEL_LOAD %2, srcq, srcstride, %1
+ EPEL_COMPUTE %2, %1, m4, m5, 1
+ SIMPLE_BILOAD %1, src2q, m2, m3
+ BI_COMPUTE %1, %2, m0, m1, m2, m3, m6, 1
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+
+; ******************************
+; void put_hevc_epel_hv(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my, int width)
+; ******************************
+
+%macro HEVC_PUT_HEVC_EPEL_HV 2
+cglobal hevc_put_hevc_epel_hv%1_%2, 6, 7, 16 , dst, src, srcstride, height, mx, my, r3src
+%assign %%stride ((%2 + 7)/8)
+ sub srcq, srcstrideq
+ EPEL_HV_FILTER %2
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m8, m1
+%endif
+ SWAP m4, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m9, m1
+%endif
+ SWAP m5, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m10, m1
+%endif
+ SWAP m6, m0
+ add srcq, srcstrideq
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m11, m1
+%endif
+ SWAP m7, m0
+ punpcklwd m0, m4, m5
+ punpcklwd m2, m6, m7
+%if %1 > 4
+ punpckhwd m1, m4, m5
+ punpckhwd m3, m6, m7
+%endif
+ EPEL_COMPUTE 14, %1, m12, m13
+%if (%1 > 8 && (%2 == 8))
+ punpcklwd m4, m8, m9
+ punpcklwd m2, m10, m11
+ punpckhwd m8, m8, m9
+ punpckhwd m3, m10, m11
+ EPEL_COMPUTE 14, %1, m12, m13, m4, m2, m8, m3
+%if cpuflag(avx2)
+ vinserti128 m2, m0, xm4, 1
+ vperm2i128 m3, m0, m4, q0301
+ PEL_10STORE%1 dstq, m2, m3
+%else
+ PEL_10STORE%1 dstq, m0, m4
+%endif
+%else
+ PEL_10STORE%1 dstq, m0, m1
+%endif
+ movdqa m4, m5
+ movdqa m5, m6
+ movdqa m6, m7
+%if (%1 > 8 && (%2 == 8))
+ mova m8, m9
+ mova m9, m10
+ mova m10, m11
+%endif
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_epel_hv%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, height, mx, my, r3src
+%assign %%stride ((%2 + 7)/8)
+ sub srcq, srcstrideq
+ EPEL_HV_FILTER %2
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m8, m1
+%endif
+ SWAP m4, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m9, m1
+%endif
+ SWAP m5, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m10, m1
+%endif
+ SWAP m6, m0
+ add srcq, srcstrideq
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m11, m1
+%endif
+ mova m7, m0
+ punpcklwd m0, m4, m5
+ punpcklwd m2, m6, m7
+%if %1 > 4
+ punpckhwd m1, m4, m5
+ punpckhwd m3, m6, m7
+%endif
+ EPEL_COMPUTE 14, %1, m12, m13
+%if (%1 > 8 && (%2 == 8))
+ punpcklwd m4, m8, m9
+ punpcklwd m2, m10, m11
+ punpckhwd m8, m8, m9
+ punpckhwd m3, m10, m11
+ EPEL_COMPUTE 14, %1, m12, m13, m4, m2, m8, m3
+ UNI_COMPUTE %1, %2, m0, m4, [pw_%2]
+%else
+ UNI_COMPUTE %1, %2, m0, m1, [pw_%2]
+%endif
+ PEL_%2STORE%1 dstq, m0, m1
+ mova m4, m5
+ mova m5, m6
+ mova m6, m7
+%if (%1 > 8 && (%2 == 8))
+ mova m8, m9
+ mova m9, m10
+ mova m10, m11
+%endif
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+cglobal hevc_put_hevc_bi_epel_hv%1_%2, 8, 9, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src
+%assign %%stride ((%2 + 7)/8)
+ sub srcq, srcstrideq
+ EPEL_HV_FILTER %2
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m8, m1
+%endif
+ SWAP m4, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m9, m1
+%endif
+ SWAP m5, m0
+ add srcq, srcstrideq
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m10, m1
+%endif
+ SWAP m6, m0
+ add srcq, srcstrideq
+.loop
+ EPEL_LOAD %2, srcq-%%stride, %%stride, %1
+ EPEL_COMPUTE %2, %1, m14, m15
+%if (%1 > 8 && (%2 == 8))
+ SWAP m11, m1
+%endif
+ SWAP m7, m0
+ punpcklwd m0, m4, m5
+ punpcklwd m2, m6, m7
+%if %1 > 4
+ punpckhwd m1, m4, m5
+ punpckhwd m3, m6, m7
+%endif
+ EPEL_COMPUTE 14, %1, m12, m13
+%if (%1 > 8 && (%2 == 8))
+ punpcklwd m4, m8, m9
+ punpcklwd m2, m10, m11
+ punpckhwd m8, m8, m9
+ punpckhwd m3, m10, m11
+ EPEL_COMPUTE 14, %1, m12, m13, m4, m2, m8, m3
+ SIMPLE_BILOAD %1, src2q, m8, m3
+%if cpuflag(avx2)
+ vinserti128 m1, m8, xm3, 1
+ vperm2i128 m2, m8, m3, q0301
+ BI_COMPUTE %1, %2, m0, m4, m1, m2, [pw_bi_%2]
+%else
+ BI_COMPUTE %1, %2, m0, m4, m8, m3, [pw_bi_%2]
+%endif
+%else
+ SIMPLE_BILOAD %1, src2q, m8, m9
+ BI_COMPUTE %1, %2, m0, m1, m8, m9, [pw_bi_%2]
+%endif
+ PEL_%2STORE%1 dstq, m0, m4
+ mova m4, m5
+ mova m5, m6
+ mova m6, m7
+%if (%1 > 8 && (%2 == 8))
+ mova m8, m9
+ mova m9, m10
+ mova m10, m11
+%endif
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+; ******************************
+; void put_hevc_qpel_hX_X_X(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my, int width)
+; ******************************
+
+%macro HEVC_PUT_HEVC_QPEL 2
+cglobal hevc_put_hevc_qpel_h%1_%2, 5, 6, 16, dst, src, srcstride, height, mx, rfilter
+ QPEL_FILTER %2, mx
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 10
+ QPEL_COMPUTE %1, %2, 1
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_qpel_h%1_%2, 6, 7, 16 , dst, dststride, src, srcstride, height, mx, rfilter
+ mova m9, [pw_%2]
+ QPEL_FILTER %2, mx
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 10
+ QPEL_COMPUTE %1, %2
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ UNI_COMPUTE %1, %2, m0, m1, m9
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+cglobal hevc_put_hevc_bi_qpel_h%1_%2, 7, 8, 16 , dst, dststride, src, srcstride, src2, height, mx, rfilter
+ movdqa m9, [pw_bi_%2]
+ QPEL_FILTER %2, mx
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 10
+ QPEL_COMPUTE %1, %2, 1
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ SIMPLE_BILOAD %1, src2q, m10, m11
+ BI_COMPUTE %1, %2, m0, m1, m10, m11, m9, 1
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+
+; ******************************
+; void put_hevc_qpel_vX_X_X(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my, int width)
+; ******************************
+
+cglobal hevc_put_hevc_qpel_v%1_%2, 4, 8, 16, dst, src, srcstride, height, r3src, my, rfilter
+ movifnidn myd, mym
+ lea r3srcq, [srcstrideq*3]
+ QPEL_FILTER %2, my
+.loop
+ QPEL_V_LOAD %2, srcq, srcstride, %1, r7
+ QPEL_COMPUTE %1, %2, 1
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ PEL_10STORE%1 dstq, m0, m1
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_qpel_v%1_%2, 5, 9, 16, dst, dststride, src, srcstride, height, r3src, my, rfilter
+ movifnidn myd, mym
+ movdqa m9, [pw_%2]
+ lea r3srcq, [srcstrideq*3]
+ QPEL_FILTER %2, my
+.loop
+ QPEL_V_LOAD %2, srcq, srcstride, %1, r8
+ QPEL_COMPUTE %1, %2
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ UNI_COMPUTE %1, %2, m0, m1, m9
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+cglobal hevc_put_hevc_bi_qpel_v%1_%2, 6, 10, 16, dst, dststride, src, srcstride, src2, height, r3src, my, rfilter
+ movifnidn myd, mym
+ movdqa m9, [pw_bi_%2]
+ lea r3srcq, [srcstrideq*3]
+ QPEL_FILTER %2, my
+.loop
+ QPEL_V_LOAD %2, srcq, srcstride, %1, r9
+ QPEL_COMPUTE %1, %2, 1
+%if %2 > 8
+ packssdw m0, m1
+%endif
+ SIMPLE_BILOAD %1, src2q, m10, m11
+ BI_COMPUTE %1, %2, m0, m1, m10, m11, m9, 1
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+
+; ******************************
+; void put_hevc_qpel_hvX_X(int16_t *dst, ptrdiff_t dststride,
+; uint8_t *_src, ptrdiff_t _srcstride,
+; int height, int mx, int my)
+; ******************************
+%macro HEVC_PUT_HEVC_QPEL_HV 2
+cglobal hevc_put_hevc_qpel_hv%1_%2, 6, 8, 16, dst, src, srcstride, height, mx, my, r3src, rfilter
+%if cpuflag(avx2)
+%assign %%shift 4
+%else
+%assign %%shift 3
+%endif
+ sub mxq, 1
+ sub myq, 1
+ shl mxq, %%shift ; multiply by 32
+ shl myq, %%shift ; multiply by 32
+ lea r3srcq, [srcstrideq*3]
+ sub srcq, r3srcq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m8, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m9, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m10, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m11, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m12, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m13, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m14, m0
+ add srcq, srcstrideq
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m15, m0
+ punpcklwd m0, m8, m9
+ punpcklwd m2, m10, m11
+ punpcklwd m4, m12, m13
+ punpcklwd m6, m14, m15
+%if %1 > 4
+ punpckhwd m1, m8, m9
+ punpckhwd m3, m10, m11
+ punpckhwd m5, m12, m13
+ punpckhwd m7, m14, m15
+%endif
+ QPEL_HV_COMPUTE %1, 14, my, ackssdw
+ PEL_10STORE%1 dstq, m0, m1
+%if %1 <= 4
+ movq m8, m9
+ movq m9, m10
+ movq m10, m11
+ movq m11, m12
+ movq m12, m13
+ movq m13, m14
+ movq m14, m15
+%else
+ movdqa m8, m9
+ movdqa m9, m10
+ movdqa m10, m11
+ movdqa m11, m12
+ movdqa m12, m13
+ movdqa m13, m14
+ movdqa m14, m15
+%endif
+ LOOP_END dst, src, srcstride
+ RET
+
+cglobal hevc_put_hevc_uni_qpel_hv%1_%2, 7, 9, 16 , dst, dststride, src, srcstride, height, mx, my, r3src, rfilter
+%if cpuflag(avx2)
+%assign %%shift 4
+%else
+%assign %%shift 3
+%endif
+ sub mxq, 1
+ sub myq, 1
+ shl mxq, %%shift ; multiply by 32
+ shl myq, %%shift ; multiply by 32
+ lea r3srcq, [srcstrideq*3]
+ sub srcq, r3srcq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m8, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m9, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m10, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m11, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m12, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m13, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m14, m0
+ add srcq, srcstrideq
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m15, m0
+ punpcklwd m0, m8, m9
+ punpcklwd m2, m10, m11
+ punpcklwd m4, m12, m13
+ punpcklwd m6, m14, m15
+%if %1 > 4
+ punpckhwd m1, m8, m9
+ punpckhwd m3, m10, m11
+ punpckhwd m5, m12, m13
+ punpckhwd m7, m14, m15
+%endif
+ QPEL_HV_COMPUTE %1, 14, my, ackusdw
+ UNI_COMPUTE %1, %2, m0, m1, [pw_%2]
+ PEL_%2STORE%1 dstq, m0, m1
+
+%if %1 <= 4
+ movq m8, m9
+ movq m9, m10
+ movq m10, m11
+ movq m11, m12
+ movq m12, m13
+ movq m13, m14
+ movq m14, m15
+%else
+ mova m8, m9
+ mova m9, m10
+ mova m10, m11
+ mova m11, m12
+ mova m12, m13
+ mova m13, m14
+ mova m14, m15
+%endif
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+cglobal hevc_put_hevc_bi_qpel_hv%1_%2, 8, 10, 16, dst, dststride, src, srcstride, src2, height, mx, my, r3src, rfilter
+%if cpuflag(avx2)
+%assign %%shift 4
+%else
+%assign %%shift 3
+%endif
+ sub mxq, 1
+ sub myq, 1
+ shl mxq, %%shift ; multiply by 32
+ shl myq, %%shift ; multiply by 32
+ lea r3srcq, [srcstrideq*3]
+ sub srcq, r3srcq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m8, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m9, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m10, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m11, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m12, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m13, m0
+ add srcq, srcstrideq
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m14, m0
+ add srcq, srcstrideq
+.loop
+ QPEL_H_LOAD %2, srcq, %1, 15
+ QPEL_HV_COMPUTE %1, %2, mx, ackssdw
+ SWAP m15, m0
+ punpcklwd m0, m8, m9
+ punpcklwd m2, m10, m11
+ punpcklwd m4, m12, m13
+ punpcklwd m6, m14, m15
+%if %1 > 4
+ punpckhwd m1, m8, m9
+ punpckhwd m3, m10, m11
+ punpckhwd m5, m12, m13
+ punpckhwd m7, m14, m15
+%endif
+ QPEL_HV_COMPUTE %1, 14, my, ackssdw
+ SIMPLE_BILOAD %1, src2q, m8, m9 ;m9 not used in this case
+ BI_COMPUTE %1, %2, m0, m1, m8, m9, [pw_bi_%2]
+ PEL_%2STORE%1 dstq, m0, m1
+
+%if %1 <= 4
+ movq m8, m9
+ movq m9, m10
+ movq m10, m11
+ movq m11, m12
+ movq m12, m13
+ movq m13, m14
+ movq m14, m15
+%else
+ movdqa m8, m9
+ movdqa m9, m10
+ movdqa m10, m11
+ movdqa m11, m12
+ movdqa m12, m13
+ movdqa m13, m14
+ movdqa m14, m15
+%endif
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+%macro WEIGHTING_FUNCS 2
+%if WIN64 || ARCH_X86_32
+cglobal hevc_put_hevc_uni_w%1_%2, 4, 5, 7, dst, dststride, src, height, denom, wx, ox
+ mov r4d, denomm
+%define SHIFT r4d
+%else
+cglobal hevc_put_hevc_uni_w%1_%2, 6, 6, 7, dst, dststride, src, height, denom, wx, ox
+%define SHIFT denomd
+%endif
+ lea SHIFT, [SHIFT+14-%2] ; shift = 14 - bitd + denom
+%if %1 <= 4
+ pxor m1, m1
+%endif
+ movd m2, wxm ; WX
+ movd m4, SHIFT ; shift
+%if %1 <= 4
+ punpcklwd m2, m1
+%else
+ punpcklwd m2, m2
+%endif
+ dec SHIFT
+ movdqu m5, [pd_1]
+ movd m6, SHIFT
+ pshufd m2, m2, 0
+ mov SHIFT, oxm
+ pslld m5, m6
+%if %2 != 8
+ shl SHIFT, %2-8 ; ox << (bitd - 8)
+%endif
+ movd m3, SHIFT ; OX
+ pshufd m3, m3, 0
+%if WIN64 || ARCH_X86_32
+ mov SHIFT, heightm
+%endif
+.loop
+ SIMPLE_LOAD %1, 10, srcq, m0
+%if %1 <= 4
+ punpcklwd m0, m1
+ pmaddwd m0, m2
+ paddd m0, m5
+ psrad m0, m4
+ paddd m0, m3
+%else
+ pmulhw m6, m0, m2
+ pmullw m0, m2
+ punpckhwd m1, m0, m6
+ punpcklwd m0, m6
+ paddd m0, m5
+ paddd m1, m5
+ psrad m0, m4
+ psrad m1, m4
+ paddd m0, m3
+ paddd m1, m3
+%endif
+ packssdw m0, m1
+%if %2 == 8
+ packuswb m0, m0
+%else
+ CLIPW m0, [pb_0], [max_pixels_%2]
+%endif
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, 2*MAX_PB_SIZE ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ RET
+
+cglobal hevc_put_hevc_bi_w%1_%2, 4, 6, 10, dst, dststride, src, src2, height, denom, wx0, wx1, ox0, ox1
+ movifnidn r5d, denomm
+%if %1 <= 4
+ pxor m1, m1
+%endif
+ movd m2, wx0m ; WX0
+ lea r5d, [r5d+14-%2] ; shift = 14 - bitd + denom
+ movd m3, wx1m ; WX1
+ movd m0, r5d ; shift
+%if %1 <= 4
+ punpcklwd m2, m1
+ punpcklwd m3, m1
+%else
+ punpcklwd m2, m2
+ punpcklwd m3, m3
+%endif
+ inc r5d
+ movd m5, r5d ; shift+1
+ pshufd m2, m2, 0
+ mov r5d, ox0m
+ pshufd m3, m3, 0
+ add r5d, ox1m
+%if %2 != 8
+ shl r5d, %2-8 ; ox << (bitd - 8)
+%endif
+ inc r5d
+ movd m4, r5d ; offset
+ pshufd m4, m4, 0
+%if UNIX64
+%define h heightd
+%else
+ mov r5d, heightm
+%define h r5d
+%endif
+ pslld m4, m0
+
+.loop
+ SIMPLE_LOAD %1, 10, srcq, m0
+ SIMPLE_LOAD %1, 10, src2q, m8
+%if %1 <= 4
+ punpcklwd m0, m1
+ punpcklwd m8, m1
+ pmaddwd m0, m3
+ pmaddwd m8, m2
+ paddd m0, m4
+ paddd m0, m8
+ psrad m0, m5
+%else
+ pmulhw m6, m0, m3
+ pmullw m0, m3
+ pmulhw m7, m8, m2
+ pmullw m8, m2
+ punpckhwd m1, m0, m6
+ punpcklwd m0, m6
+ punpckhwd m9, m8, m7
+ punpcklwd m8, m7
+ paddd m0, m8
+ paddd m1, m9
+ paddd m0, m4
+ paddd m1, m4
+ psrad m0, m5
+ psrad m1, m5
+%endif
+ packssdw m0, m1
+%if %2 == 8
+ packuswb m0, m0
+%else
+ CLIPW m0, [pb_0], [max_pixels_%2]
+%endif
+ PEL_%2STORE%1 dstq, m0, m1
+ add dstq, dststrideq ; dst += dststride
+ add srcq, 2*MAX_PB_SIZE ; src += srcstride
+ add src2q, 2*MAX_PB_SIZE ; src2 += srcstride
+ dec h ; cmp height
+ jnz .loop ; height loop
+ RET
+%endmacro
+
+INIT_XMM sse4 ; adds ff_ and _sse4 to function name
+
+WEIGHTING_FUNCS 2, 8
+WEIGHTING_FUNCS 4, 8
+WEIGHTING_FUNCS 6, 8
+WEIGHTING_FUNCS 8, 8
+
+WEIGHTING_FUNCS 2, 10
+WEIGHTING_FUNCS 4, 10
+WEIGHTING_FUNCS 6, 10
+WEIGHTING_FUNCS 8, 10
+
+WEIGHTING_FUNCS 2, 12
+WEIGHTING_FUNCS 4, 12
+WEIGHTING_FUNCS 6, 12
+WEIGHTING_FUNCS 8, 12
+
+HEVC_PUT_HEVC_PEL_PIXELS 2, 8
+HEVC_PUT_HEVC_PEL_PIXELS 4, 8
+HEVC_PUT_HEVC_PEL_PIXELS 6, 8
+HEVC_PUT_HEVC_PEL_PIXELS 8, 8
+HEVC_PUT_HEVC_PEL_PIXELS 12, 8
+HEVC_PUT_HEVC_PEL_PIXELS 16, 8
+
+HEVC_PUT_HEVC_PEL_PIXELS 2, 10
+HEVC_PUT_HEVC_PEL_PIXELS 4, 10
+HEVC_PUT_HEVC_PEL_PIXELS 6, 10
+HEVC_PUT_HEVC_PEL_PIXELS 8, 10
+
+HEVC_PUT_HEVC_PEL_PIXELS 2, 12
+HEVC_PUT_HEVC_PEL_PIXELS 4, 12
+HEVC_PUT_HEVC_PEL_PIXELS 6, 12
+HEVC_PUT_HEVC_PEL_PIXELS 8, 12
+
+HEVC_PUT_HEVC_EPEL 2, 8
+HEVC_PUT_HEVC_EPEL 4, 8
+HEVC_PUT_HEVC_EPEL 6, 8
+HEVC_PUT_HEVC_EPEL 8, 8
+HEVC_PUT_HEVC_EPEL 12, 8
+HEVC_PUT_HEVC_EPEL 16, 8
+
+
+HEVC_PUT_HEVC_EPEL 2, 10
+HEVC_PUT_HEVC_EPEL 4, 10
+HEVC_PUT_HEVC_EPEL 6, 10
+HEVC_PUT_HEVC_EPEL 8, 10
+
+HEVC_PUT_HEVC_EPEL 2, 12
+HEVC_PUT_HEVC_EPEL 4, 12
+HEVC_PUT_HEVC_EPEL 6, 12
+HEVC_PUT_HEVC_EPEL 8, 12
+
+HEVC_PUT_HEVC_EPEL_HV 2, 8
+HEVC_PUT_HEVC_EPEL_HV 4, 8
+HEVC_PUT_HEVC_EPEL_HV 6, 8
+HEVC_PUT_HEVC_EPEL_HV 8, 8
+HEVC_PUT_HEVC_EPEL_HV 16, 8
+
+HEVC_PUT_HEVC_EPEL_HV 2, 10
+HEVC_PUT_HEVC_EPEL_HV 4, 10
+HEVC_PUT_HEVC_EPEL_HV 6, 10
+HEVC_PUT_HEVC_EPEL_HV 8, 10
+
+HEVC_PUT_HEVC_EPEL_HV 2, 12
+HEVC_PUT_HEVC_EPEL_HV 4, 12
+HEVC_PUT_HEVC_EPEL_HV 6, 12
+HEVC_PUT_HEVC_EPEL_HV 8, 12
+
+HEVC_PUT_HEVC_QPEL 4, 8
+HEVC_PUT_HEVC_QPEL 8, 8
+HEVC_PUT_HEVC_QPEL 12, 8
+HEVC_PUT_HEVC_QPEL 16, 8
+
+HEVC_PUT_HEVC_QPEL 4, 10
+HEVC_PUT_HEVC_QPEL 8, 10
+
+HEVC_PUT_HEVC_QPEL 4, 12
+HEVC_PUT_HEVC_QPEL 8, 12
+
+HEVC_PUT_HEVC_QPEL_HV 2, 8
+HEVC_PUT_HEVC_QPEL_HV 4, 8
+HEVC_PUT_HEVC_QPEL_HV 6, 8
+HEVC_PUT_HEVC_QPEL_HV 8, 8
+
+HEVC_PUT_HEVC_QPEL_HV 2, 10
+HEVC_PUT_HEVC_QPEL_HV 4, 10
+HEVC_PUT_HEVC_QPEL_HV 6, 10
+HEVC_PUT_HEVC_QPEL_HV 8, 10
+
+HEVC_PUT_HEVC_QPEL_HV 2, 12
+HEVC_PUT_HEVC_QPEL_HV 4, 12
+HEVC_PUT_HEVC_QPEL_HV 6, 12
+HEVC_PUT_HEVC_QPEL_HV 8, 12
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2 ; adds ff_ and _avx2 to function name & enables 256b registers : m0 for 256b, xm0 for 128b. cpuflag(avx2) = 1 / notcpuflag(avx) = 0
+
+HEVC_PUT_HEVC_PEL_PIXELS 32, 8
+HEVC_PUT_HEVC_PEL_PIXELS 16, 10
+
+HEVC_PUT_HEVC_EPEL 32, 8
+HEVC_PUT_HEVC_EPEL 16, 10
+
+HEVC_PUT_HEVC_EPEL_HV 16, 10
+HEVC_PUT_HEVC_EPEL_HV 32, 8
+
+HEVC_PUT_HEVC_QPEL 32, 8
+
+HEVC_PUT_HEVC_QPEL 16, 10
+
+HEVC_PUT_HEVC_QPEL_HV 16, 10
+
+%endif ;AVX2
+%endif ; ARCH_X86_64
diff --git a/libavcodec/x86/hevc_res_add.asm b/libavcodec/x86/hevc_res_add.asm
new file mode 100644
index 0000000000..dc3e88a373
--- /dev/null
+++ b/libavcodec/x86/hevc_res_add.asm
@@ -0,0 +1,388 @@
+; /*
+; * Provide SIMD optimizations for transform_add functions for HEVC decoding
+; * Copyright (c) 2014 Pierre-Edouard LEPERE
+; *
+; * This file is part of FFmpeg.
+; *
+; * FFmpeg is free software; you can redistribute it and/or
+; * modify it under the terms of the GNU Lesser General Public
+; * License as published by the Free Software Foundation; either
+; * version 2.1 of the License, or (at your option) any later version.
+; *
+; * FFmpeg is distributed in the hope that it will be useful,
+; * but WITHOUT ANY WARRANTY; without even the implied warranty of
+; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; * Lesser General Public License for more details.
+; *
+; * You should have received a copy of the GNU Lesser General Public
+; * License along with FFmpeg; if not, write to the Free Software
+; * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+; */
+%include "libavutil/x86/x86util.asm"
+
+SECTION .text
+
+cextern pw_1023
+%define max_pixels_10 pw_1023
+
+
+;the tr_add macros and functions were largely inspired by x264 project's code in the h264_idct.asm file
+%macro TR_ADD_MMX_4_8 0
+ mova m2, [r1]
+ mova m4, [r1+8]
+ pxor m3, m3
+ psubw m3, m2
+ packuswb m2, m2
+ packuswb m3, m3
+ pxor m5, m5
+ psubw m5, m4
+ packuswb m4, m4
+ packuswb m5, m5
+
+ movh m0, [r0 ]
+ movh m1, [r0+r2 ]
+ paddusb m0, m2
+ paddusb m1, m4
+ psubusb m0, m3
+ psubusb m1, m5
+ movh [r0 ], m0
+ movh [r0+r2 ], m1
+%endmacro
+
+
+INIT_MMX mmxext
+; void ff_hevc_tranform_add_8_mmxext(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride)
+cglobal hevc_transform_add4_8, 3, 4, 6
+ TR_ADD_MMX_4_8
+ add r1, 16
+ lea r0, [r0+r2*2]
+ TR_ADD_MMX_4_8
+ RET
+
+%macro TR_ADD_SSE_8_8 0
+ pxor m3, m3
+ mova m4, [r1]
+ mova m6, [r1+16]
+ mova m0, [r1+32]
+ mova m2, [r1+48]
+ psubw m5, m3, m4
+ psubw m7, m3, m6
+ psubw m1, m3, m0
+ packuswb m4, m0
+ packuswb m5, m1
+ psubw m3, m2
+ packuswb m6, m2
+ packuswb m7, m3
+
+ movq m0, [r0 ]
+ movq m1, [r0+r2 ]
+ movhps m0, [r0+r2*2]
+ movhps m1, [r0+r3 ]
+ paddusb m0, m4
+ paddusb m1, m6
+ psubusb m0, m5
+ psubusb m1, m7
+ movq [r0 ], m0
+ movq [r0+r2 ], m1
+ movhps [r0+2*r2], m0
+ movhps [r0+r3 ], m1
+%endmacro
+
+%macro TR_ADD_SSE_16_32_8 3
+ mova xm2, [r1+%1 ]
+ mova xm6, [r1+%1+16]
+%if cpuflag(avx2)
+ vinserti128 m2, m2, [r1+%1+32], 1
+ vinserti128 m6, m6, [r1+%1+48], 1
+%endif
+%if cpuflag(avx)
+ psubw m1, m0, m2
+ psubw m5, m0, m6
+%else
+ mova m1, m0
+ mova m5, m0
+ psubw m1, m2
+ psubw m5, m6
+%endif
+ packuswb m2, m6
+ packuswb m1, m5
+
+ mova xm4, [r1+%1+mmsize*2 ]
+ mova xm6, [r1+%1+mmsize*2+16]
+%if cpuflag(avx2)
+ vinserti128 m4, m4, [r1+%1+96 ], 1
+ vinserti128 m6, m6, [r1+%1+112], 1
+%endif
+%if cpuflag(avx)
+ psubw m3, m0, m4
+ psubw m5, m0, m6
+%else
+ mova m3, m0
+ mova m5, m0
+ psubw m3, m4
+ psubw m5, m6
+%endif
+ packuswb m4, m6
+ packuswb m3, m5
+
+ paddusb m2, [%2]
+ paddusb m4, [%3]
+ psubusb m2, m1
+ psubusb m4, m3
+ mova [%2], m2
+ mova [%3], m4
+%endmacro
+
+
+%macro TRANSFORM_ADD_8 0
+; void ff_hevc_transform_add8_8_<opt>(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride)
+cglobal hevc_transform_add8_8, 3, 4, 8
+ lea r3, [r2*3]
+ TR_ADD_SSE_8_8
+ add r1, 64
+ lea r0, [r0+r2*4]
+ TR_ADD_SSE_8_8
+ RET
+
+; void ff_hevc_transform_add16_8_<opt>(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride)
+cglobal hevc_transform_add16_8, 3, 4, 7
+ pxor m0, m0
+ lea r3, [r2*3]
+ TR_ADD_SSE_16_32_8 0, r0, r0+r2
+ TR_ADD_SSE_16_32_8 64, r0+r2*2, r0+r3
+%rep 3
+ add r1, 128
+ lea r0, [r0+r2*4]
+ TR_ADD_SSE_16_32_8 0, r0, r0+r2
+ TR_ADD_SSE_16_32_8 64, r0+r2*2, r0+r3
+%endrep
+ RET
+
+; void ff_hevc_transform_add32_8_<opt>(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride)
+cglobal hevc_transform_add32_8, 3, 4, 7
+ pxor m0, m0
+ TR_ADD_SSE_16_32_8 0, r0, r0+16
+ TR_ADD_SSE_16_32_8 64, r0+r2, r0+r2+16
+%rep 15
+ add r1, 128
+ lea r0, [r0+r2*2]
+ TR_ADD_SSE_16_32_8 0, r0, r0+16
+ TR_ADD_SSE_16_32_8 64, r0+r2, r0+r2+16
+%endrep
+ RET
+%endmacro
+
+INIT_XMM sse2
+TRANSFORM_ADD_8
+INIT_XMM avx
+TRANSFORM_ADD_8
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+; void ff_hevc_transform_add32_8_avx2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride)
+cglobal hevc_transform_add32_8, 3, 4, 7
+ pxor m0, m0
+ lea r3, [r2*3]
+ TR_ADD_SSE_16_32_8 0, r0, r0+r2
+ TR_ADD_SSE_16_32_8 128, r0+r2*2, r0+r3
+%rep 7
+ add r1, 256
+ lea r0, [r0+r2*4]
+ TR_ADD_SSE_16_32_8 0, r0, r0+r2
+ TR_ADD_SSE_16_32_8 128, r0+r2*2, r0+r3
+%endrep
+ RET
+%endif
+
+;-----------------------------------------------------------------------------
+; void ff_hevc_transform_add_10(pixel *dst, int16_t *block, int stride)
+;-----------------------------------------------------------------------------
+%macro TR_ADD_SSE_8_10 4
+ mova m0, [%4]
+ mova m1, [%4+16]
+ mova m2, [%4+32]
+ mova m3, [%4+48]
+ paddw m0, [%1+0 ]
+ paddw m1, [%1+%2 ]
+ paddw m2, [%1+%2*2]
+ paddw m3, [%1+%3 ]
+ CLIPW m0, m4, m5
+ CLIPW m1, m4, m5
+ CLIPW m2, m4, m5
+ CLIPW m3, m4, m5
+ mova [%1+0 ], m0
+ mova [%1+%2 ], m1
+ mova [%1+%2*2], m2
+ mova [%1+%3 ], m3
+%endmacro
+
+%macro TR_ADD_MMX4_10 3
+ mova m0, [%1+0 ]
+ mova m1, [%1+%2 ]
+ paddw m0, [%3]
+ paddw m1, [%3+8]
+ CLIPW m0, m2, m3
+ CLIPW m1, m2, m3
+ mova [%1+0 ], m0
+ mova [%1+%2 ], m1
+%endmacro
+
+%macro TRANS_ADD_SSE_16_10 3
+ mova m0, [%3]
+ mova m1, [%3+16]
+ mova m2, [%3+32]
+ mova m3, [%3+48]
+ paddw m0, [%1 ]
+ paddw m1, [%1+16 ]
+ paddw m2, [%1+%2 ]
+ paddw m3, [%1+%2+16]
+ CLIPW m0, m4, m5
+ CLIPW m1, m4, m5
+ CLIPW m2, m4, m5
+ CLIPW m3, m4, m5
+ mova [%1 ], m0
+ mova [%1+16 ], m1
+ mova [%1+%2 ], m2
+ mova [%1+%2+16], m3
+%endmacro
+
+%macro TRANS_ADD_SSE_32_10 2
+ mova m0, [%2]
+ mova m1, [%2+16]
+ mova m2, [%2+32]
+ mova m3, [%2+48]
+
+ paddw m0, [%1 ]
+ paddw m1, [%1+16]
+ paddw m2, [%1+32]
+ paddw m3, [%1+48]
+ CLIPW m0, m4, m5
+ CLIPW m1, m4, m5
+ CLIPW m2, m4, m5
+ CLIPW m3, m4, m5
+ mova [%1 ], m0
+ mova [%1+16], m1
+ mova [%1+32], m2
+ mova [%1+48], m3
+%endmacro
+
+%macro TRANS_ADD16_AVX2 4
+ mova m0, [%4]
+ mova m1, [%4+32]
+ mova m2, [%4+64]
+ mova m3, [%4+96]
+
+ paddw m0, [%1+0 ]
+ paddw m1, [%1+%2 ]
+ paddw m2, [%1+%2*2]
+ paddw m3, [%1+%3 ]
+
+ CLIPW m0, m4, m5
+ CLIPW m1, m4, m5
+ CLIPW m2, m4, m5
+ CLIPW m3, m4, m5
+ mova [%1+0 ], m0
+ mova [%1+%2 ], m1
+ mova [%1+%2*2], m2
+ mova [%1+%3 ], m3
+%endmacro
+
+%macro TRANS_ADD32_AVX2 3
+ mova m0, [%3]
+ mova m1, [%3+32]
+ mova m2, [%3+64]
+ mova m3, [%3+96]
+
+ paddw m0, [%1 ]
+ paddw m1, [%1+32 ]
+ paddw m2, [%1+%2 ]
+ paddw m3, [%1+%2+32]
+
+ CLIPW m0, m4, m5
+ CLIPW m1, m4, m5
+ CLIPW m2, m4, m5
+ CLIPW m3, m4, m5
+ mova [%1 ], m0
+ mova [%1+32 ], m1
+ mova [%1+%2 ], m2
+ mova [%1+%2+32], m3
+%endmacro
+
+
+INIT_MMX mmxext
+cglobal hevc_transform_add4_10,3,4, 6
+ pxor m2, m2
+ mova m3, [max_pixels_10]
+ TR_ADD_MMX4_10 r0, r2, r1
+ add r1, 16
+ lea r0, [r0+2*r2]
+ TR_ADD_MMX4_10 r0, r2, r1
+ RET
+
+;-----------------------------------------------------------------------------
+; void ff_hevc_transform_add_10(pixel *dst, int16_t *block, int stride)
+;-----------------------------------------------------------------------------
+INIT_XMM sse2
+cglobal hevc_transform_add8_10,3,4,6
+ pxor m4, m4
+ mova m5, [max_pixels_10]
+ lea r3, [r2*3]
+
+ TR_ADD_SSE_8_10 r0, r2, r3, r1
+ lea r0, [r0+r2*4]
+ add r1, 64
+ TR_ADD_SSE_8_10 r0, r2, r3, r1
+ RET
+
+cglobal hevc_transform_add16_10,3,4,6
+ pxor m4, m4
+ mova m5, [max_pixels_10]
+
+ TRANS_ADD_SSE_16_10 r0, r2, r1
+%rep 7
+ lea r0, [r0+r2*2]
+ add r1, 64
+ TRANS_ADD_SSE_16_10 r0, r2, r1
+%endrep
+ RET
+
+cglobal hevc_transform_add32_10,3,4,6
+ pxor m4, m4
+ mova m5, [max_pixels_10]
+
+ TRANS_ADD_SSE_32_10 r0, r1
+%rep 31
+ lea r0, [r0+r2]
+ add r1, 64
+ TRANS_ADD_SSE_32_10 r0, r1
+%endrep
+ RET
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+
+cglobal hevc_transform_add16_10,3,4,6
+ pxor m4, m4
+ mova m5, [max_pixels_10]
+ lea r3, [r2*3]
+
+ TRANS_ADD16_AVX2 r0, r2, r3, r1
+%rep 3
+ lea r0, [r0+r2*4]
+ add r1, 128
+ TRANS_ADD16_AVX2 r0, r2, r3, r1
+%endrep
+ RET
+
+cglobal hevc_transform_add32_10,3,4,6
+ pxor m4, m4
+ mova m5, [max_pixels_10]
+
+ TRANS_ADD32_AVX2 r0, r2, r1
+%rep 15
+ lea r0, [r0+r2*2]
+ add r1, 128
+ TRANS_ADD32_AVX2 r0, r2, r1
+%endrep
+ RET
+%endif ;HAVE_AVX_EXTERNAL
diff --git a/libavcodec/x86/hevc_sao.asm b/libavcodec/x86/hevc_sao.asm
new file mode 100644
index 0000000000..86ef847ba2
--- /dev/null
+++ b/libavcodec/x86/hevc_sao.asm
@@ -0,0 +1,624 @@
+;******************************************************************************
+;* SIMD optimized SAO functions for HEVC decoding
+;*
+;* Copyright (c) 2013 Pierre-Edouard LEPERE
+;* Copyright (c) 2014 James Almer
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+pw_mask10: times 16 dw 0x03FF
+pw_mask12: times 16 dw 0x0FFF
+pw_m2: times 16 dw -2
+pb_edge_shuffle: times 2 db 1, 2, 0, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+pb_eo: db -1, 0, 1, 0, 0, -1, 0, 1, -1, -1, 1, 1, 1, -1, -1, 1
+cextern pw_m1
+cextern pw_1
+cextern pw_2
+cextern pb_1
+cextern pb_2
+
+SECTION_TEXT
+
+%define MAX_PB_SIZE 64
+%define PADDING_SIZE 32 ; FF_INPUT_BUFFER_PADDING_SIZE
+
+;******************************************************************************
+;SAO Band Filter
+;******************************************************************************
+
+%macro HEVC_SAO_BAND_FILTER_INIT 1
+ and leftq, 31
+ movd xm0, leftd
+ add leftq, 1
+ and leftq, 31
+ movd xm1, leftd
+ add leftq, 1
+ and leftq, 31
+ movd xm2, leftd
+ add leftq, 1
+ and leftq, 31
+ movd xm3, leftd
+
+ SPLATW m0, xm0
+ SPLATW m1, xm1
+ SPLATW m2, xm2
+ SPLATW m3, xm3
+%if mmsize > 16
+ SPLATW m4, [offsetq + 2]
+ SPLATW m5, [offsetq + 4]
+ SPLATW m6, [offsetq + 6]
+ SPLATW m7, [offsetq + 8]
+%else
+ movq m7, [offsetq + 2]
+ SPLATW m4, m7, 0
+ SPLATW m5, m7, 1
+ SPLATW m6, m7, 2
+ SPLATW m7, m7, 3
+%endif
+
+%if ARCH_X86_64
+%if %1 > 8
+ mova m13, [pw_mask %+ %1]
+%endif
+ pxor m14, m14
+
+%else ; ARCH_X86_32
+ mova [rsp+mmsize*0], m0
+ mova [rsp+mmsize*1], m1
+ mova [rsp+mmsize*2], m2
+ mova [rsp+mmsize*3], m3
+ mova [rsp+mmsize*4], m4
+ mova [rsp+mmsize*5], m5
+ mova [rsp+mmsize*6], m6
+ pxor m0, m0
+%if %1 > 8
+ mova m1, [pw_mask %+ %1]
+%endif
+ %assign MMSIZE mmsize
+ %define m14 m0
+ %define m13 m1
+ %define m9 m2
+ %define m8 m3
+%endif ; ARCH
+DEFINE_ARGS dst, src, dststride, srcstride, offset, height
+ mov heightd, r7m
+%endmacro
+
+%macro HEVC_SAO_BAND_FILTER_COMPUTE 3
+ psraw %2, %3, %1-5
+%if ARCH_X86_64
+ pcmpeqw m10, %2, m0
+ pcmpeqw m11, %2, m1
+ pcmpeqw m12, %2, m2
+ pcmpeqw %2, m3
+ pand m10, m4
+ pand m11, m5
+ pand m12, m6
+ pand %2, m7
+ por m10, m11
+ por m12, %2
+ por m10, m12
+ paddw %3, m10
+%else ; ARCH_X86_32
+ pcmpeqw m4, %2, [rsp+MMSIZE*0]
+ pcmpeqw m5, %2, [rsp+MMSIZE*1]
+ pcmpeqw m6, %2, [rsp+MMSIZE*2]
+ pcmpeqw %2, [rsp+MMSIZE*3]
+ pand m4, [rsp+MMSIZE*4]
+ pand m5, [rsp+MMSIZE*5]
+ pand m6, [rsp+MMSIZE*6]
+ pand %2, m7
+ por m4, m5
+ por m6, %2
+ por m4, m6
+ paddw %3, m4
+%endif ; ARCH
+%endmacro
+
+;void ff_hevc_sao_band_filter_<width>_8_<opt>(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);
+%macro HEVC_SAO_BAND_FILTER_8 2
+cglobal hevc_sao_band_filter_%1_8, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left
+ HEVC_SAO_BAND_FILTER_INIT 8
+
+align 16
+.loop
+%if %1 == 8
+ movq m8, [srcq]
+ punpcklbw m8, m14
+ HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m8
+ packuswb m8, m14
+ movq [dstq], m8
+%endif ; %1 == 8
+
+%assign i 0
+%rep %2
+ mova m13, [srcq + i]
+ punpcklbw m8, m13, m14
+ HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m8
+ punpckhbw m13, m14
+ HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m13
+ packuswb m8, m13
+ mova [dstq + i], m8
+%assign i i+mmsize
+%endrep
+
+%if %1 == 48
+INIT_XMM cpuname
+
+ mova m13, [srcq + i]
+ punpcklbw m8, m13, m14
+ HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m8
+ punpckhbw m13, m14
+ HEVC_SAO_BAND_FILTER_COMPUTE 8, m9, m13
+ packuswb m8, m13
+ mova [dstq + i], m8
+%if cpuflag(avx2)
+INIT_YMM cpuname
+%endif
+%endif ; %1 == 48
+
+ add dstq, dststrideq ; dst += dststride
+ add srcq, srcstrideq ; src += srcstride
+ dec heightd ; cmp height
+ jnz .loop ; height loop
+ REP_RET
+%endmacro
+
+;void ff_hevc_sao_band_filter_<width>_<depth>_<opt>(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);
+%macro HEVC_SAO_BAND_FILTER_16 3
+cglobal hevc_sao_band_filter_%2_%1, 6, 6, 15, 7*mmsize*ARCH_X86_32, dst, src, dststride, srcstride, offset, left
+ HEVC_SAO_BAND_FILTER_INIT %1
+
+align 16
+.loop
+%if %2 == 8
+ movu m8, [srcq]
+ HEVC_SAO_BAND_FILTER_COMPUTE %1, m9, m8
+ CLIPW m8, m14, m13
+ movu [dstq], m8
+%endif
+
+%assign i 0
+%rep %3
+ mova m8, [srcq + i]
+ HEVC_SAO_BAND_FILTER_COMPUTE %1, m9, m8
+ CLIPW m8, m14, m13
+ mova [dstq + i], m8
+
+ mova m9, [srcq + i + mmsize]
+ HEVC_SAO_BAND_FILTER_COMPUTE %1, m8, m9
+ CLIPW m9, m14, m13
+ mova [dstq + i + mmsize], m9
+%assign i i+mmsize*2
+%endrep
+
+%if %2 == 48
+INIT_XMM cpuname
+ mova m8, [srcq + i]
+ HEVC_SAO_BAND_FILTER_COMPUTE %1, m9, m8
+ CLIPW m8, m14, m13
+ mova [dstq + i], m8
+
+ mova m9, [srcq + i + mmsize]
+ HEVC_SAO_BAND_FILTER_COMPUTE %1, m8, m9
+ CLIPW m9, m14, m13
+ mova [dstq + i + mmsize], m9
+%if cpuflag(avx2)
+INIT_YMM cpuname
+%endif
+%endif ; %1 == 48
+
+ add dstq, dststrideq
+ add srcq, srcstrideq
+ dec heightd
+ jg .loop
+ REP_RET
+%endmacro
+
+%macro HEVC_SAO_BAND_FILTER_FUNCS 0
+HEVC_SAO_BAND_FILTER_8 8, 0
+HEVC_SAO_BAND_FILTER_8 16, 1
+HEVC_SAO_BAND_FILTER_8 32, 2
+HEVC_SAO_BAND_FILTER_8 48, 2
+HEVC_SAO_BAND_FILTER_8 64, 4
+
+HEVC_SAO_BAND_FILTER_16 10, 8, 0
+HEVC_SAO_BAND_FILTER_16 10, 16, 1
+HEVC_SAO_BAND_FILTER_16 10, 32, 2
+HEVC_SAO_BAND_FILTER_16 10, 48, 2
+HEVC_SAO_BAND_FILTER_16 10, 64, 4
+
+HEVC_SAO_BAND_FILTER_16 12, 8, 0
+HEVC_SAO_BAND_FILTER_16 12, 16, 1
+HEVC_SAO_BAND_FILTER_16 12, 32, 2
+HEVC_SAO_BAND_FILTER_16 12, 48, 2
+HEVC_SAO_BAND_FILTER_16 12, 64, 4
+%endmacro
+
+INIT_XMM sse2
+HEVC_SAO_BAND_FILTER_FUNCS
+INIT_XMM avx
+HEVC_SAO_BAND_FILTER_FUNCS
+
+%if HAVE_AVX2_EXTERNAL
+INIT_XMM avx2
+HEVC_SAO_BAND_FILTER_8 8, 0
+HEVC_SAO_BAND_FILTER_8 16, 1
+INIT_YMM avx2
+HEVC_SAO_BAND_FILTER_8 32, 1
+HEVC_SAO_BAND_FILTER_8 48, 1
+HEVC_SAO_BAND_FILTER_8 64, 2
+
+INIT_XMM avx2
+HEVC_SAO_BAND_FILTER_16 10, 8, 0
+HEVC_SAO_BAND_FILTER_16 10, 16, 1
+INIT_YMM avx2
+HEVC_SAO_BAND_FILTER_16 10, 32, 1
+HEVC_SAO_BAND_FILTER_16 10, 48, 1
+HEVC_SAO_BAND_FILTER_16 10, 64, 2
+
+INIT_XMM avx2
+HEVC_SAO_BAND_FILTER_16 12, 8, 0
+HEVC_SAO_BAND_FILTER_16 12, 16, 1
+INIT_YMM avx2
+HEVC_SAO_BAND_FILTER_16 12, 32, 1
+HEVC_SAO_BAND_FILTER_16 12, 48, 1
+HEVC_SAO_BAND_FILTER_16 12, 64, 2
+%endif
+
+;******************************************************************************
+;SAO Edge Filter
+;******************************************************************************
+
+%define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE
+
+%macro HEVC_SAO_EDGE_FILTER_INIT 1
+%if WIN64
+ movsxd eoq, dword eom
+%elif ARCH_X86_64
+ movsxd eoq, eod
+%else
+ mov eoq, r4m
+%endif
+ lea tmp2q, [pb_eo]
+ movsx a_strideq, byte [tmp2q+eoq*4+1]
+ movsx b_strideq, byte [tmp2q+eoq*4+3]
+ imul a_strideq, EDGE_SRCSTRIDE>>%1
+ imul b_strideq, EDGE_SRCSTRIDE>>%1
+ movsx tmpq, byte [tmp2q+eoq*4]
+ add a_strideq, tmpq
+ movsx tmpq, byte [tmp2q+eoq*4+2]
+ add b_strideq, tmpq
+%endmacro
+
+%macro HEVC_SAO_EDGE_FILTER_COMPUTE_8 1
+ pminub m4, m1, m2
+ pminub m5, m1, m3
+ pcmpeqb m2, m4
+ pcmpeqb m3, m5
+ pcmpeqb m4, m1
+ pcmpeqb m5, m1
+ psubb m4, m2
+ psubb m5, m3
+ paddb m4, m6
+ paddb m4, m5
+
+ pshufb m2, m0, m4
+%if %1 > 8
+ punpckhbw m5, m7, m1
+ punpckhbw m4, m2, m7
+ punpcklbw m3, m7, m1
+ punpcklbw m2, m7
+ pmaddubsw m5, m4
+ pmaddubsw m3, m2
+ packuswb m3, m5
+%else
+ punpcklbw m3, m7, m1
+ punpcklbw m2, m7
+ pmaddubsw m3, m2
+ packuswb m3, m3
+%endif
+%endmacro
+
+;void ff_hevc_sao_edge_filter_<width>_8_<opt>(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,
+; int eo, int width, int height);
+%macro HEVC_SAO_EDGE_FILTER_8 2-3
+%if ARCH_X86_64
+cglobal hevc_sao_edge_filter_%1_8, 4, 9, 8, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp
+%define tmp2q heightq
+ HEVC_SAO_EDGE_FILTER_INIT 0
+ mov heightd, r6m
+
+%else ; ARCH_X86_32
+cglobal hevc_sao_edge_filter_%1_8, 1, 6, 8, dst, src, dststride, a_stride, b_stride, height
+%define eoq srcq
+%define tmpq heightq
+%define tmp2q dststrideq
+%define offsetq heightq
+ HEVC_SAO_EDGE_FILTER_INIT 0
+ mov srcq, srcm
+ mov offsetq, r3m
+ mov dststrideq, dststridem
+%endif ; ARCH
+
+%if mmsize > 16
+ vbroadcasti128 m0, [offsetq]
+%else
+ movu m0, [offsetq]
+%endif
+ mova m1, [pb_edge_shuffle]
+ packsswb m0, m0
+ mova m7, [pb_1]
+ pshufb m0, m1
+ mova m6, [pb_2]
+%if ARCH_X86_32
+ mov heightd, r6m
+%endif
+
+align 16
+.loop:
+
+%if %1 == 8
+ movq m1, [srcq]
+ movq m2, [srcq + a_strideq]
+ movq m3, [srcq + b_strideq]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_8 %1
+ movq [dstq], m3
+%endif
+
+%assign i 0
+%rep %2
+ mova m1, [srcq + i]
+ movu m2, [srcq + a_strideq + i]
+ movu m3, [srcq + b_strideq + i]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_8 %1
+ mov%3 [dstq + i], m3
+%assign i i+mmsize
+%endrep
+
+%if %1 == 48
+INIT_XMM cpuname
+
+ mova m1, [srcq + i]
+ movu m2, [srcq + a_strideq + i]
+ movu m3, [srcq + b_strideq + i]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_8 %1
+ mova [dstq + i], m3
+%if cpuflag(avx2)
+INIT_YMM cpuname
+%endif
+%endif
+
+ add dstq, dststrideq
+ add srcq, EDGE_SRCSTRIDE
+ dec heightd
+ jg .loop
+ RET
+%endmacro
+
+%macro PMINUW 4
+%if cpuflag(sse4)
+ pminuw %1, %2, %3
+%else
+ psubusw %4, %2, %3
+ psubw %1, %2, %4
+%endif
+%endmacro
+
+%macro HEVC_SAO_EDGE_FILTER_COMPUTE_10 0
+ PMINUW m4, m1, m2, m6
+ PMINUW m5, m1, m3, m7
+ pcmpeqw m2, m4
+ pcmpeqw m3, m5
+ pcmpeqw m4, m1
+ pcmpeqw m5, m1
+ psubw m4, m2
+ psubw m5, m3
+
+ paddw m4, m5
+ pcmpeqw m2, m4, [pw_m2]
+%if ARCH_X86_64
+ pcmpeqw m3, m4, m13
+ pcmpeqw m5, m4, m0
+ pcmpeqw m6, m4, m14
+ pcmpeqw m7, m4, m15
+ pand m2, m8
+ pand m3, m9
+ pand m5, m10
+ pand m6, m11
+ pand m7, m12
+%else
+ pcmpeqw m3, m4, [pw_m1]
+ pcmpeqw m5, m4, m0
+ pcmpeqw m6, m4, [pw_1]
+ pcmpeqw m7, m4, [pw_2]
+ pand m2, [rsp+MMSIZE*0]
+ pand m3, [rsp+MMSIZE*1]
+ pand m5, [rsp+MMSIZE*2]
+ pand m6, [rsp+MMSIZE*3]
+ pand m7, [rsp+MMSIZE*4]
+%endif
+ paddw m2, m3
+ paddw m5, m6
+ paddw m2, m7
+ paddw m2, m1
+ paddw m2, m5
+%endmacro
+
+;void ff_hevc_sao_edge_filter_<width>_<depth>_<opt>(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,
+; int eo, int width, int height);
+%macro HEVC_SAO_EDGE_FILTER_16 3
+%if ARCH_X86_64
+cglobal hevc_sao_edge_filter_%2_%1, 4, 9, 16, dst, src, dststride, offset, eo, a_stride, b_stride, height, tmp
+%define tmp2q heightq
+ HEVC_SAO_EDGE_FILTER_INIT 1
+ mov heightd, r6m
+ add a_strideq, a_strideq
+ add b_strideq, b_strideq
+
+%else ; ARCH_X86_32
+cglobal hevc_sao_edge_filter_%2_%1, 1, 6, 8, 5*mmsize, dst, src, dststride, a_stride, b_stride, height
+%assign MMSIZE mmsize
+%define eoq srcq
+%define tmpq heightq
+%define tmp2q dststrideq
+%define offsetq heightq
+%define m8 m1
+%define m9 m2
+%define m10 m3
+%define m11 m4
+%define m12 m5
+ HEVC_SAO_EDGE_FILTER_INIT 1
+ mov srcq, srcm
+ mov offsetq, r3m
+ mov dststrideq, dststridem
+ add a_strideq, a_strideq
+ add b_strideq, b_strideq
+
+%endif ; ARCH
+
+%if cpuflag(avx2)
+ SPLATW m8, [offsetq+2]
+ SPLATW m9, [offsetq+4]
+ SPLATW m10, [offsetq+0]
+ SPLATW m11, [offsetq+6]
+ SPLATW m12, [offsetq+8]
+%else
+ movq m10, [offsetq+0]
+ movd m12, [offsetq+6]
+ SPLATW m8, xm10, 1
+ SPLATW m9, xm10, 2
+ SPLATW m10, xm10, 0
+ SPLATW m11, xm12, 0
+ SPLATW m12, xm12, 1
+%endif
+ pxor m0, m0
+%if ARCH_X86_64
+ mova m13, [pw_m1]
+ mova m14, [pw_1]
+ mova m15, [pw_2]
+%else
+ mov heightd, r6m
+ mova [rsp+mmsize*0], m8
+ mova [rsp+mmsize*1], m9
+ mova [rsp+mmsize*2], m10
+ mova [rsp+mmsize*3], m11
+ mova [rsp+mmsize*4], m12
+%endif
+
+align 16
+.loop
+
+%if %2 == 8
+ mova m1, [srcq]
+ movu m2, [srcq+a_strideq]
+ movu m3, [srcq+b_strideq]
+
+ HEVC_SAO_EDGE_FILTER_COMPUTE_10
+ CLIPW m2, m0, [pw_mask %+ %1]
+ movu [dstq], m2
+%endif
+
+%assign i 0
+%rep %3
+ mova m1, [srcq + i]
+ movu m2, [srcq+a_strideq + i]
+ movu m3, [srcq+b_strideq + i]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_10
+ CLIPW m2, m0, [pw_mask %+ %1]
+ mova [dstq + i], m2
+
+ mova m1, [srcq + i + mmsize]
+ movu m2, [srcq+a_strideq + i + mmsize]
+ movu m3, [srcq+b_strideq + i + mmsize]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_10
+ CLIPW m2, m0, [pw_mask %+ %1]
+ mova [dstq + i + mmsize], m2
+%assign i i+mmsize*2
+%endrep
+
+%if %2 == 48
+INIT_XMM cpuname
+ mova m1, [srcq + i]
+ movu m2, [srcq+a_strideq + i]
+ movu m3, [srcq+b_strideq + i]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_10
+ CLIPW m2, m0, [pw_mask %+ %1]
+ mova [dstq + i], m2
+
+ mova m1, [srcq + i + mmsize]
+ movu m2, [srcq+a_strideq + i + mmsize]
+ movu m3, [srcq+b_strideq + i + mmsize]
+ HEVC_SAO_EDGE_FILTER_COMPUTE_10
+ CLIPW m2, m0, [pw_mask %+ %1]
+ mova [dstq + i + mmsize], m2
+%if cpuflag(avx2)
+INIT_YMM cpuname
+%endif
+%endif
+
+ add dstq, dststrideq
+ add srcq, EDGE_SRCSTRIDE
+ dec heightd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM ssse3
+HEVC_SAO_EDGE_FILTER_8 8, 0
+HEVC_SAO_EDGE_FILTER_8 16, 1, a
+HEVC_SAO_EDGE_FILTER_8 32, 2, a
+HEVC_SAO_EDGE_FILTER_8 48, 2, a
+HEVC_SAO_EDGE_FILTER_8 64, 4, a
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+HEVC_SAO_EDGE_FILTER_8 32, 1, a
+HEVC_SAO_EDGE_FILTER_8 48, 1, u
+HEVC_SAO_EDGE_FILTER_8 64, 2, a
+%endif
+
+INIT_XMM sse2
+HEVC_SAO_EDGE_FILTER_16 10, 8, 0
+HEVC_SAO_EDGE_FILTER_16 10, 16, 1
+HEVC_SAO_EDGE_FILTER_16 10, 32, 2
+HEVC_SAO_EDGE_FILTER_16 10, 48, 2
+HEVC_SAO_EDGE_FILTER_16 10, 64, 4
+
+HEVC_SAO_EDGE_FILTER_16 12, 8, 0
+HEVC_SAO_EDGE_FILTER_16 12, 16, 1
+HEVC_SAO_EDGE_FILTER_16 12, 32, 2
+HEVC_SAO_EDGE_FILTER_16 12, 48, 2
+HEVC_SAO_EDGE_FILTER_16 12, 64, 4
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+HEVC_SAO_EDGE_FILTER_16 10, 32, 1
+HEVC_SAO_EDGE_FILTER_16 10, 48, 1
+HEVC_SAO_EDGE_FILTER_16 10, 64, 2
+
+HEVC_SAO_EDGE_FILTER_16 12, 32, 1
+HEVC_SAO_EDGE_FILTER_16 12, 48, 1
+HEVC_SAO_EDGE_FILTER_16 12, 64, 2
+%endif
diff --git a/libavcodec/x86/hevcdsp.h b/libavcodec/x86/hevcdsp.h
new file mode 100644
index 0000000000..ad8168fb5b
--- /dev/null
+++ b/libavcodec/x86/hevcdsp.h
@@ -0,0 +1,261 @@
+/*
+ * HEVC video decoder
+ *
+ * Copyright (C) 2012 - 2013 Guillaume Martres
+ * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere
+ *
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_X86_HEVCDSP_H
+#define AVCODEC_X86_HEVCDSP_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+#define idct_dc_proto(size, bitd, opt) \
+ void ff_hevc_idct##size##_dc_add_##bitd##_##opt(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride)
+
+#define PEL_LINK(dst, idx1, idx2, idx3, name, D, opt) \
+dst[idx1][idx2][idx3] = ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt; \
+dst ## _bi[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt; \
+dst ## _uni[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt; \
+dst ## _uni_w[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt; \
+dst ## _bi_w[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt
+
+
+#define PEL_PROTOTYPE(name, D, opt) \
+void ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); \
+void ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); \
+void ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); \
+void ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width); \
+void ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, int denom, int wx0, int wx1, int ox0, int ox1, intptr_t mx, intptr_t my, int width)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// MC functions
+///////////////////////////////////////////////////////////////////////////////
+
+#define EPEL_PROTOTYPES(fname, bitd, opt) \
+ PEL_PROTOTYPE(fname##4, bitd, opt); \
+ PEL_PROTOTYPE(fname##6, bitd, opt); \
+ PEL_PROTOTYPE(fname##8, bitd, opt); \
+ PEL_PROTOTYPE(fname##12, bitd, opt); \
+ PEL_PROTOTYPE(fname##16, bitd, opt); \
+ PEL_PROTOTYPE(fname##24, bitd, opt); \
+ PEL_PROTOTYPE(fname##32, bitd, opt); \
+ PEL_PROTOTYPE(fname##48, bitd, opt); \
+ PEL_PROTOTYPE(fname##64, bitd, opt)
+
+#define QPEL_PROTOTYPES(fname, bitd, opt) \
+ PEL_PROTOTYPE(fname##4, bitd, opt); \
+ PEL_PROTOTYPE(fname##8, bitd, opt); \
+ PEL_PROTOTYPE(fname##12, bitd, opt); \
+ PEL_PROTOTYPE(fname##16, bitd, opt); \
+ PEL_PROTOTYPE(fname##24, bitd, opt); \
+ PEL_PROTOTYPE(fname##32, bitd, opt); \
+ PEL_PROTOTYPE(fname##48, bitd, opt); \
+ PEL_PROTOTYPE(fname##64, bitd, opt)
+
+#define WEIGHTING_PROTOTYPE(width, bitd, opt) \
+void ff_hevc_put_hevc_uni_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, int16_t *_src, int height, int denom, int _wx, int _ox); \
+void ff_hevc_put_hevc_bi_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, int16_t *_src, int16_t *_src2, int height, int denom, int _wx0, int _wx1, int _ox0, int _ox1)
+
+#define WEIGHTING_PROTOTYPES(bitd, opt) \
+ WEIGHTING_PROTOTYPE(2, bitd, opt); \
+ WEIGHTING_PROTOTYPE(4, bitd, opt); \
+ WEIGHTING_PROTOTYPE(6, bitd, opt); \
+ WEIGHTING_PROTOTYPE(8, bitd, opt); \
+ WEIGHTING_PROTOTYPE(12, bitd, opt); \
+ WEIGHTING_PROTOTYPE(16, bitd, opt); \
+ WEIGHTING_PROTOTYPE(24, bitd, opt); \
+ WEIGHTING_PROTOTYPE(32, bitd, opt); \
+ WEIGHTING_PROTOTYPE(48, bitd, opt); \
+ WEIGHTING_PROTOTYPE(64, bitd, opt)
+
+
+///////////////////////////////////////////////////////////////////////////////
+// QPEL_PIXELS EPEL_PIXELS
+///////////////////////////////////////////////////////////////////////////////
+EPEL_PROTOTYPES(pel_pixels , 8, sse4);
+EPEL_PROTOTYPES(pel_pixels , 10, sse4);
+EPEL_PROTOTYPES(pel_pixels , 12, sse4);
+
+void ff_hevc_put_hevc_pel_pixels16_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels24_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels32_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels48_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels64_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+
+void ff_hevc_put_hevc_pel_pixels16_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels24_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels32_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels48_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_pel_pixels64_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+
+
+
+void ff_hevc_put_hevc_uni_pel_pixels32_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_uni_pel_pixels48_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_uni_pel_pixels64_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);
+void ff_hevc_put_hevc_uni_pel_pixels96_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); //used for 10bit
+void ff_hevc_put_hevc_uni_pel_pixels128_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);//used for 10bit
+
+
+void ff_hevc_put_hevc_bi_pel_pixels16_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels24_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels32_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels48_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels64_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+
+void ff_hevc_put_hevc_bi_pel_pixels16_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels24_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels32_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels48_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+void ff_hevc_put_hevc_bi_pel_pixels64_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width);
+
+///////////////////////////////////////////////////////////////////////////////
+// EPEL
+///////////////////////////////////////////////////////////////////////////////
+EPEL_PROTOTYPES(epel_h , 8, sse4);
+EPEL_PROTOTYPES(epel_h , 10, sse4);
+EPEL_PROTOTYPES(epel_h , 12, sse4);
+
+EPEL_PROTOTYPES(epel_v , 8, sse4);
+EPEL_PROTOTYPES(epel_v , 10, sse4);
+EPEL_PROTOTYPES(epel_v , 12, sse4);
+
+EPEL_PROTOTYPES(epel_hv , 8, sse4);
+EPEL_PROTOTYPES(epel_hv , 10, sse4);
+EPEL_PROTOTYPES(epel_hv , 12, sse4);
+
+PEL_PROTOTYPE(epel_h16, 8, avx2);
+PEL_PROTOTYPE(epel_h24, 8, avx2);
+PEL_PROTOTYPE(epel_h32, 8, avx2);
+PEL_PROTOTYPE(epel_h48, 8, avx2);
+PEL_PROTOTYPE(epel_h64, 8, avx2);
+
+PEL_PROTOTYPE(epel_h16,10, avx2);
+PEL_PROTOTYPE(epel_h24,10, avx2);
+PEL_PROTOTYPE(epel_h32,10, avx2);
+PEL_PROTOTYPE(epel_h48,10, avx2);
+PEL_PROTOTYPE(epel_h64,10, avx2);
+
+PEL_PROTOTYPE(epel_v16, 8, avx2);
+PEL_PROTOTYPE(epel_v24, 8, avx2);
+PEL_PROTOTYPE(epel_v32, 8, avx2);
+PEL_PROTOTYPE(epel_v48, 8, avx2);
+PEL_PROTOTYPE(epel_v64, 8, avx2);
+
+PEL_PROTOTYPE(epel_v16,10, avx2);
+PEL_PROTOTYPE(epel_v24,10, avx2);
+PEL_PROTOTYPE(epel_v32,10, avx2);
+PEL_PROTOTYPE(epel_v48,10, avx2);
+PEL_PROTOTYPE(epel_v64,10, avx2);
+
+PEL_PROTOTYPE(epel_hv16, 8, avx2);
+PEL_PROTOTYPE(epel_hv24, 8, avx2);
+PEL_PROTOTYPE(epel_hv32, 8, avx2);
+PEL_PROTOTYPE(epel_hv48, 8, avx2);
+PEL_PROTOTYPE(epel_hv64, 8, avx2);
+
+PEL_PROTOTYPE(epel_hv16,10, avx2);
+PEL_PROTOTYPE(epel_hv24,10, avx2);
+PEL_PROTOTYPE(epel_hv32,10, avx2);
+PEL_PROTOTYPE(epel_hv48,10, avx2);
+PEL_PROTOTYPE(epel_hv64,10, avx2);
+
+///////////////////////////////////////////////////////////////////////////////
+// QPEL
+///////////////////////////////////////////////////////////////////////////////
+QPEL_PROTOTYPES(qpel_h , 8, sse4);
+QPEL_PROTOTYPES(qpel_h , 10, sse4);
+QPEL_PROTOTYPES(qpel_h , 12, sse4);
+
+QPEL_PROTOTYPES(qpel_v, 8, sse4);
+QPEL_PROTOTYPES(qpel_v, 10, sse4);
+QPEL_PROTOTYPES(qpel_v, 12, sse4);
+
+QPEL_PROTOTYPES(qpel_hv, 8, sse4);
+QPEL_PROTOTYPES(qpel_hv, 10, sse4);
+QPEL_PROTOTYPES(qpel_hv, 12, sse4);
+
+PEL_PROTOTYPE(qpel_h16, 8, avx2);
+PEL_PROTOTYPE(qpel_h24, 8, avx2);
+PEL_PROTOTYPE(qpel_h32, 8, avx2);
+PEL_PROTOTYPE(qpel_h48, 8, avx2);
+PEL_PROTOTYPE(qpel_h64, 8, avx2);
+
+PEL_PROTOTYPE(qpel_h16,10, avx2);
+PEL_PROTOTYPE(qpel_h24,10, avx2);
+PEL_PROTOTYPE(qpel_h32,10, avx2);
+PEL_PROTOTYPE(qpel_h48,10, avx2);
+PEL_PROTOTYPE(qpel_h64,10, avx2);
+
+PEL_PROTOTYPE(qpel_v16, 8, avx2);
+PEL_PROTOTYPE(qpel_v24, 8, avx2);
+PEL_PROTOTYPE(qpel_v32, 8, avx2);
+PEL_PROTOTYPE(qpel_v48, 8, avx2);
+PEL_PROTOTYPE(qpel_v64, 8, avx2);
+
+PEL_PROTOTYPE(qpel_v16,10, avx2);
+PEL_PROTOTYPE(qpel_v24,10, avx2);
+PEL_PROTOTYPE(qpel_v32,10, avx2);
+PEL_PROTOTYPE(qpel_v48,10, avx2);
+PEL_PROTOTYPE(qpel_v64,10, avx2);
+
+PEL_PROTOTYPE(qpel_hv16, 8, avx2);
+PEL_PROTOTYPE(qpel_hv24, 8, avx2);
+PEL_PROTOTYPE(qpel_hv32, 8, avx2);
+PEL_PROTOTYPE(qpel_hv48, 8, avx2);
+PEL_PROTOTYPE(qpel_hv64, 8, avx2);
+
+PEL_PROTOTYPE(qpel_hv16,10, avx2);
+PEL_PROTOTYPE(qpel_hv24,10, avx2);
+PEL_PROTOTYPE(qpel_hv32,10, avx2);
+PEL_PROTOTYPE(qpel_hv48,10, avx2);
+PEL_PROTOTYPE(qpel_hv64,10, avx2);
+
+WEIGHTING_PROTOTYPES(8, sse4);
+WEIGHTING_PROTOTYPES(10, sse4);
+WEIGHTING_PROTOTYPES(12, sse4);
+
+///////////////////////////////////////////////////////////////////////////////
+// TRANSFORM_ADD
+///////////////////////////////////////////////////////////////////////////////
+void ff_hevc_transform_add4_8_mmxext(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add8_8_sse2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add16_8_sse2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add32_8_sse2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+
+void ff_hevc_transform_add8_8_avx(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add16_8_avx(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add32_8_avx(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+
+void ff_hevc_transform_add32_8_avx2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+
+void ff_hevc_transform_add4_10_mmxext(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add8_10_sse2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add16_10_sse2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add32_10_sse2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+
+void ff_hevc_transform_add16_10_avx2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+void ff_hevc_transform_add32_10_avx2(uint8_t *dst, int16_t *coeffs, ptrdiff_t stride);
+
+#endif // AVCODEC_X86_HEVCDSP_H
diff --git a/libavcodec/x86/hevcdsp_init.c b/libavcodec/x86/hevcdsp_init.c
index 04203c22a0..ddc876dfcf 100644
--- a/libavcodec/x86/hevcdsp_init.c
+++ b/libavcodec/x86/hevcdsp_init.c
@@ -2,29 +2,31 @@
* Copyright (c) 2013 Seppo Tomperi
* Copyright (c) 2013 - 2014 Pierre-Edouard Lepere
*
- * This file is part of Libav.
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/cpu.h"
+#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
-
+#include "libavcodec/get_bits.h" /* required for hevcdsp.h GetBitContext */
#include "libavcodec/hevcdsp.h"
+#include "libavcodec/x86/hevcdsp.h"
#define LFC_FUNC(DIR, DEPTH, OPT) \
void ff_hevc_ ## DIR ## _loop_filter_chroma_ ## DEPTH ## _ ## OPT(uint8_t *pix, ptrdiff_t stride, int *tc, uint8_t *no_p, uint8_t *no_q);
@@ -32,40 +34,1081 @@ void ff_hevc_ ## DIR ## _loop_filter_chroma_ ## DEPTH ## _ ## OPT(uint8_t *pix,
#define LFL_FUNC(DIR, DEPTH, OPT) \
void ff_hevc_ ## DIR ## _loop_filter_luma_ ## DEPTH ## _ ## OPT(uint8_t *pix, ptrdiff_t stride, int beta, int *tc, uint8_t *no_p, uint8_t *no_q);
-#define LFC_FUNCS(type, depth) \
- LFC_FUNC(h, depth, sse2) \
- LFC_FUNC(v, depth, sse2)
+#define LFC_FUNCS(type, depth, opt) \
+ LFC_FUNC(h, depth, opt) \
+ LFC_FUNC(v, depth, opt)
+
+#define LFL_FUNCS(type, depth, opt) \
+ LFL_FUNC(h, depth, opt) \
+ LFL_FUNC(v, depth, opt)
+
+LFC_FUNCS(uint8_t, 8, sse2)
+LFC_FUNCS(uint8_t, 10, sse2)
+LFC_FUNCS(uint8_t, 12, sse2)
+LFC_FUNCS(uint8_t, 8, avx)
+LFC_FUNCS(uint8_t, 10, avx)
+LFC_FUNCS(uint8_t, 12, avx)
+LFL_FUNCS(uint8_t, 8, sse2)
+LFL_FUNCS(uint8_t, 10, sse2)
+LFL_FUNCS(uint8_t, 12, sse2)
+LFL_FUNCS(uint8_t, 8, ssse3)
+LFL_FUNCS(uint8_t, 10, ssse3)
+LFL_FUNCS(uint8_t, 12, ssse3)
+LFL_FUNCS(uint8_t, 8, avx)
+LFL_FUNCS(uint8_t, 10, avx)
+LFL_FUNCS(uint8_t, 12, avx)
+
+#define IDCT_FUNCS(W, opt) \
+void ff_hevc_idct##W##_dc_8_##opt(int16_t *coeffs); \
+void ff_hevc_idct##W##_dc_10_##opt(int16_t *coeffs); \
+void ff_hevc_idct##W##_dc_12_##opt(int16_t *coeffs)
+
+IDCT_FUNCS(4x4, mmxext);
+IDCT_FUNCS(8x8, mmxext);
+IDCT_FUNCS(8x8, sse2);
+IDCT_FUNCS(16x16, sse2);
+IDCT_FUNCS(32x32, sse2);
+IDCT_FUNCS(16x16, avx2);
+IDCT_FUNCS(32x32, avx2);
+
+#define mc_rep_func(name, bitd, step, W, opt) \
+void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *_dst, \
+ uint8_t *_src, ptrdiff_t _srcstride, int height, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ int i; \
+ uint8_t *src; \
+ int16_t *dst; \
+ for (i = 0; i < W; i += step) { \
+ src = _src + (i * ((bitd + 7) / 8)); \
+ dst = _dst + i; \
+ ff_hevc_put_hevc_##name##step##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \
+ } \
+}
+#define mc_rep_uni_func(name, bitd, step, W, opt) \
+void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, \
+ uint8_t *_src, ptrdiff_t _srcstride, int height, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ int i; \
+ uint8_t *src; \
+ uint8_t *dst; \
+ for (i = 0; i < W; i += step) { \
+ src = _src + (i * ((bitd + 7) / 8)); \
+ dst = _dst + (i * ((bitd + 7) / 8)); \
+ ff_hevc_put_hevc_uni_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, \
+ height, mx, my, width); \
+ } \
+}
+#define mc_rep_bi_func(name, bitd, step, W, opt) \
+void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, uint8_t *_src, \
+ ptrdiff_t _srcstride, int16_t* _src2, \
+ int height, intptr_t mx, intptr_t my, int width) \
+{ \
+ int i; \
+ uint8_t *src; \
+ uint8_t *dst; \
+ int16_t *src2; \
+ for (i = 0; i < W ; i += step) { \
+ src = _src + (i * ((bitd + 7) / 8)); \
+ dst = _dst + (i * ((bitd + 7) / 8)); \
+ src2 = _src2 + i; \
+ ff_hevc_put_hevc_bi_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, \
+ height, mx, my, width); \
+ } \
+}
+
+#define mc_rep_funcs(name, bitd, step, W, opt) \
+ mc_rep_func(name, bitd, step, W, opt); \
+ mc_rep_uni_func(name, bitd, step, W, opt); \
+ mc_rep_bi_func(name, bitd, step, W, opt)
+
+#define mc_rep_func2(name, bitd, step1, step2, W, opt) \
+void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *dst, \
+ uint8_t *src, ptrdiff_t _srcstride, int height, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_##name##step1##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \
+ ff_hevc_put_hevc_##name##step2##_##bitd##_##opt(dst + step1, src + (step1 * ((bitd + 7) / 8)), \
+ _srcstride, height, mx, my, width); \
+}
+#define mc_rep_uni_func2(name, bitd, step1, step2, W, opt) \
+void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, \
+ uint8_t *src, ptrdiff_t _srcstride, int height, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_uni_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, height, mx, my, width);\
+ ff_hevc_put_hevc_uni_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \
+ src + (step1 * ((bitd + 7) / 8)), _srcstride, \
+ height, mx, my, width); \
+}
+#define mc_rep_bi_func2(name, bitd, step1, step2, W, opt) \
+void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \
+ ptrdiff_t _srcstride, int16_t* src2, \
+ int height, intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_bi_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, height, mx, my, width);\
+ ff_hevc_put_hevc_bi_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \
+ src + (step1 * ((bitd + 7) / 8)), _srcstride, \
+ src2 + step1, height, mx, my, width); \
+}
+
+#define mc_rep_funcs(name, bitd, step, W, opt) \
+ mc_rep_func(name, bitd, step, W, opt); \
+ mc_rep_uni_func(name, bitd, step, W, opt); \
+ mc_rep_bi_func(name, bitd, step, W, opt)
+
+#define mc_rep_funcs2(name, bitd, step1, step2, W, opt) \
+ mc_rep_func2(name, bitd, step1, step2, W, opt); \
+ mc_rep_uni_func2(name, bitd, step1, step2, W, opt); \
+ mc_rep_bi_func2(name, bitd, step1, step2, W, opt)
+
+#if ARCH_X86_64 && HAVE_SSE4_EXTERNAL
+
+#define mc_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \
+void ff_hevc_put_hevc_##name##width1##_10_##opt1(int16_t *dst, uint8_t *src, ptrdiff_t _srcstride, \
+ int height, intptr_t mx, intptr_t my, int width) \
+ \
+{ \
+ ff_hevc_put_hevc_##name##width2##_10_##opt1(dst, src, _srcstride, height, mx, my, width); \
+ ff_hevc_put_hevc_##name##width3##_10_##opt2(dst+ width2, src+ width4, _srcstride, height, mx, my, width); \
+}
+
+#define mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \
+void ff_hevc_put_hevc_bi_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \
+ ptrdiff_t _srcstride, int16_t *src2, \
+ int height, intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_bi_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, src2, \
+ height, mx, my, width); \
+ ff_hevc_put_hevc_bi_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, src2+width2,\
+ height, mx, my, width); \
+}
+
+#define mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \
+void ff_hevc_put_hevc_uni_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, \
+ uint8_t *src, ptrdiff_t _srcstride, int height, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_uni_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, \
+ height, mx, my, width); \
+ ff_hevc_put_hevc_uni_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, \
+ height, mx, my, width); \
+}
+
+#define mc_rep_mixs_10(name, width1, width2, width3, opt1, opt2, width4) \
+mc_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4); \
+mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4); \
+mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4)
+
+#define mc_rep_mix_8(name, width1, width2, width3, opt1, opt2) \
+void ff_hevc_put_hevc_##name##width1##_8_##opt1(int16_t *dst, uint8_t *src, ptrdiff_t _srcstride, \
+ int height, intptr_t mx, intptr_t my, int width) \
+ \
+{ \
+ ff_hevc_put_hevc_##name##width2##_8_##opt1(dst, src, _srcstride, height, mx, my, width); \
+ ff_hevc_put_hevc_##name##width3##_8_##opt2(dst+ width2, src+ width2, _srcstride, height, mx, my, width); \
+}
+
+#define mc_bi_rep_mix_8(name, width1, width2, width3, opt1, opt2) \
+void ff_hevc_put_hevc_bi_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \
+ ptrdiff_t _srcstride, int16_t* src2, \
+ int height, intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_bi_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \
+ src2, height, mx, my, width); \
+ ff_hevc_put_hevc_bi_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \
+ src2+width2, height, mx, my, width); \
+}
+
+#define mc_uni_rep_mix_8(name, width1, width2, width3, opt1, opt2) \
+void ff_hevc_put_hevc_uni_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, \
+ uint8_t *src, ptrdiff_t _srcstride, int height, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ ff_hevc_put_hevc_uni_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \
+ height, mx, my, width); \
+ ff_hevc_put_hevc_uni_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \
+ height, mx, my, width); \
+}
+
+#define mc_rep_mixs_8(name, width1, width2, width3, opt1, opt2) \
+mc_rep_mix_8(name, width1, width2, width3, opt1, opt2); \
+mc_bi_rep_mix_8(name, width1, width2, width3, opt1, opt2); \
+mc_uni_rep_mix_8(name, width1, width2, width3, opt1, opt2)
+
+#if HAVE_AVX2_EXTERNAL
+
+mc_rep_mixs_8(pel_pixels, 48, 32, 16, avx2, sse4);
+mc_rep_mixs_8(epel_hv, 48, 32, 16, avx2, sse4);
+mc_rep_mixs_8(epel_h , 48, 32, 16, avx2, sse4);
+mc_rep_mixs_8(epel_v , 48, 32, 16, avx2, sse4);
+
+mc_rep_mix_10(pel_pixels, 24, 16, 8, avx2, sse4, 32);
+mc_bi_rep_mix_10(pel_pixels,24, 16, 8, avx2, sse4, 32);
+mc_rep_mixs_10(epel_hv, 24, 16, 8, avx2, sse4, 32);
+mc_rep_mixs_10(epel_h , 24, 16, 8, avx2, sse4, 32);
+mc_rep_mixs_10(epel_v , 24, 16, 8, avx2, sse4, 32);
+
+
+mc_rep_mixs_10(qpel_h , 24, 16, 8, avx2, sse4, 32);
+mc_rep_mixs_10(qpel_v , 24, 16, 8, avx2, sse4, 32);
+mc_rep_mixs_10(qpel_hv, 24, 16, 8, avx2, sse4, 32);
+
+
+mc_rep_uni_func(pel_pixels, 8, 64, 128, avx2);//used for 10bit
+mc_rep_uni_func(pel_pixels, 8, 32, 96, avx2); //used for 10bit
+
+mc_rep_funcs(pel_pixels, 8, 32, 64, avx2);
+
+mc_rep_func(pel_pixels, 10, 16, 32, avx2);
+mc_rep_func(pel_pixels, 10, 16, 48, avx2);
+mc_rep_func(pel_pixels, 10, 32, 64, avx2);
+
+mc_rep_bi_func(pel_pixels, 10, 16, 32, avx2);
+mc_rep_bi_func(pel_pixels, 10, 16, 48, avx2);
+mc_rep_bi_func(pel_pixels, 10, 32, 64, avx2);
+
+mc_rep_funcs(epel_h, 8, 32, 64, avx2);
+
+mc_rep_funcs(epel_v, 8, 32, 64, avx2);
+
+mc_rep_funcs(epel_h, 10, 16, 32, avx2);
+mc_rep_funcs(epel_h, 10, 16, 48, avx2);
+mc_rep_funcs(epel_h, 10, 32, 64, avx2);
+
+mc_rep_funcs(epel_v, 10, 16, 32, avx2);
+mc_rep_funcs(epel_v, 10, 16, 48, avx2);
+mc_rep_funcs(epel_v, 10, 32, 64, avx2);
+
+
+mc_rep_funcs(epel_hv, 8, 32, 64, avx2);
+
+mc_rep_funcs(epel_hv, 10, 16, 32, avx2);
+mc_rep_funcs(epel_hv, 10, 16, 48, avx2);
+mc_rep_funcs(epel_hv, 10, 32, 64, avx2);
+
+mc_rep_funcs(qpel_h, 8, 32, 64, avx2);
+mc_rep_mixs_8(qpel_h , 48, 32, 16, avx2, sse4);
+
+mc_rep_funcs(qpel_v, 8, 32, 64, avx2);
+mc_rep_mixs_8(qpel_v, 48, 32, 16, avx2, sse4);
+
+mc_rep_funcs(qpel_h, 10, 16, 32, avx2);
+mc_rep_funcs(qpel_h, 10, 16, 48, avx2);
+mc_rep_funcs(qpel_h, 10, 32, 64, avx2);
+
+mc_rep_funcs(qpel_v, 10, 16, 32, avx2);
+mc_rep_funcs(qpel_v, 10, 16, 48, avx2);
+mc_rep_funcs(qpel_v, 10, 32, 64, avx2);
+
+mc_rep_funcs(qpel_hv, 10, 16, 32, avx2);
+mc_rep_funcs(qpel_hv, 10, 16, 48, avx2);
+mc_rep_funcs(qpel_hv, 10, 32, 64, avx2);
+
+#endif //AVX2
+
+mc_rep_funcs(pel_pixels, 8, 16, 64, sse4);
+mc_rep_funcs(pel_pixels, 8, 16, 48, sse4);
+mc_rep_funcs(pel_pixels, 8, 16, 32, sse4);
+mc_rep_funcs(pel_pixels, 8, 8, 24, sse4);
+mc_rep_funcs(pel_pixels,10, 8, 64, sse4);
+mc_rep_funcs(pel_pixels,10, 8, 48, sse4);
+mc_rep_funcs(pel_pixels,10, 8, 32, sse4);
+mc_rep_funcs(pel_pixels,10, 8, 24, sse4);
+mc_rep_funcs(pel_pixels,10, 8, 16, sse4);
+mc_rep_funcs(pel_pixels,10, 4, 12, sse4);
+mc_rep_funcs(pel_pixels,12, 8, 64, sse4);
+mc_rep_funcs(pel_pixels,12, 8, 48, sse4);
+mc_rep_funcs(pel_pixels,12, 8, 32, sse4);
+mc_rep_funcs(pel_pixels,12, 8, 24, sse4);
+mc_rep_funcs(pel_pixels,12, 8, 16, sse4);
+mc_rep_funcs(pel_pixels,12, 4, 12, sse4);
+
+mc_rep_funcs(epel_h, 8, 16, 64, sse4);
+mc_rep_funcs(epel_h, 8, 16, 48, sse4);
+mc_rep_funcs(epel_h, 8, 16, 32, sse4);
+mc_rep_funcs(epel_h, 8, 8, 24, sse4);
+mc_rep_funcs(epel_h,10, 8, 64, sse4);
+mc_rep_funcs(epel_h,10, 8, 48, sse4);
+mc_rep_funcs(epel_h,10, 8, 32, sse4);
+mc_rep_funcs(epel_h,10, 8, 24, sse4);
+mc_rep_funcs(epel_h,10, 8, 16, sse4);
+mc_rep_funcs(epel_h,10, 4, 12, sse4);
+mc_rep_funcs(epel_h,12, 8, 64, sse4);
+mc_rep_funcs(epel_h,12, 8, 48, sse4);
+mc_rep_funcs(epel_h,12, 8, 32, sse4);
+mc_rep_funcs(epel_h,12, 8, 24, sse4);
+mc_rep_funcs(epel_h,12, 8, 16, sse4);
+mc_rep_funcs(epel_h,12, 4, 12, sse4);
+mc_rep_funcs(epel_v, 8, 16, 64, sse4);
+mc_rep_funcs(epel_v, 8, 16, 48, sse4);
+mc_rep_funcs(epel_v, 8, 16, 32, sse4);
+mc_rep_funcs(epel_v, 8, 8, 24, sse4);
+mc_rep_funcs(epel_v,10, 8, 64, sse4);
+mc_rep_funcs(epel_v,10, 8, 48, sse4);
+mc_rep_funcs(epel_v,10, 8, 32, sse4);
+mc_rep_funcs(epel_v,10, 8, 24, sse4);
+mc_rep_funcs(epel_v,10, 8, 16, sse4);
+mc_rep_funcs(epel_v,10, 4, 12, sse4);
+mc_rep_funcs(epel_v,12, 8, 64, sse4);
+mc_rep_funcs(epel_v,12, 8, 48, sse4);
+mc_rep_funcs(epel_v,12, 8, 32, sse4);
+mc_rep_funcs(epel_v,12, 8, 24, sse4);
+mc_rep_funcs(epel_v,12, 8, 16, sse4);
+mc_rep_funcs(epel_v,12, 4, 12, sse4);
+mc_rep_funcs(epel_hv, 8, 16, 64, sse4);
+mc_rep_funcs(epel_hv, 8, 16, 48, sse4);
+mc_rep_funcs(epel_hv, 8, 16, 32, sse4);
+mc_rep_funcs(epel_hv, 8, 8, 24, sse4);
+mc_rep_funcs2(epel_hv,8, 8, 4, 12, sse4);
+mc_rep_funcs(epel_hv,10, 8, 64, sse4);
+mc_rep_funcs(epel_hv,10, 8, 48, sse4);
+mc_rep_funcs(epel_hv,10, 8, 32, sse4);
+mc_rep_funcs(epel_hv,10, 8, 24, sse4);
+mc_rep_funcs(epel_hv,10, 8, 16, sse4);
+mc_rep_funcs(epel_hv,10, 4, 12, sse4);
+mc_rep_funcs(epel_hv,12, 8, 64, sse4);
+mc_rep_funcs(epel_hv,12, 8, 48, sse4);
+mc_rep_funcs(epel_hv,12, 8, 32, sse4);
+mc_rep_funcs(epel_hv,12, 8, 24, sse4);
+mc_rep_funcs(epel_hv,12, 8, 16, sse4);
+mc_rep_funcs(epel_hv,12, 4, 12, sse4);
+
+mc_rep_funcs(qpel_h, 8, 16, 64, sse4);
+mc_rep_funcs(qpel_h, 8, 16, 48, sse4);
+mc_rep_funcs(qpel_h, 8, 16, 32, sse4);
+mc_rep_funcs(qpel_h, 8, 8, 24, sse4);
+mc_rep_funcs(qpel_h,10, 8, 64, sse4);
+mc_rep_funcs(qpel_h,10, 8, 48, sse4);
+mc_rep_funcs(qpel_h,10, 8, 32, sse4);
+mc_rep_funcs(qpel_h,10, 8, 24, sse4);
+mc_rep_funcs(qpel_h,10, 8, 16, sse4);
+mc_rep_funcs(qpel_h,10, 4, 12, sse4);
+mc_rep_funcs(qpel_h,12, 8, 64, sse4);
+mc_rep_funcs(qpel_h,12, 8, 48, sse4);
+mc_rep_funcs(qpel_h,12, 8, 32, sse4);
+mc_rep_funcs(qpel_h,12, 8, 24, sse4);
+mc_rep_funcs(qpel_h,12, 8, 16, sse4);
+mc_rep_funcs(qpel_h,12, 4, 12, sse4);
+mc_rep_funcs(qpel_v, 8, 16, 64, sse4);
+mc_rep_funcs(qpel_v, 8, 16, 48, sse4);
+mc_rep_funcs(qpel_v, 8, 16, 32, sse4);
+mc_rep_funcs(qpel_v, 8, 8, 24, sse4);
+mc_rep_funcs(qpel_v,10, 8, 64, sse4);
+mc_rep_funcs(qpel_v,10, 8, 48, sse4);
+mc_rep_funcs(qpel_v,10, 8, 32, sse4);
+mc_rep_funcs(qpel_v,10, 8, 24, sse4);
+mc_rep_funcs(qpel_v,10, 8, 16, sse4);
+mc_rep_funcs(qpel_v,10, 4, 12, sse4);
+mc_rep_funcs(qpel_v,12, 8, 64, sse4);
+mc_rep_funcs(qpel_v,12, 8, 48, sse4);
+mc_rep_funcs(qpel_v,12, 8, 32, sse4);
+mc_rep_funcs(qpel_v,12, 8, 24, sse4);
+mc_rep_funcs(qpel_v,12, 8, 16, sse4);
+mc_rep_funcs(qpel_v,12, 4, 12, sse4);
+mc_rep_funcs(qpel_hv, 8, 8, 64, sse4);
+mc_rep_funcs(qpel_hv, 8, 8, 48, sse4);
+mc_rep_funcs(qpel_hv, 8, 8, 32, sse4);
+mc_rep_funcs(qpel_hv, 8, 8, 24, sse4);
+mc_rep_funcs(qpel_hv, 8, 8, 16, sse4);
+mc_rep_funcs2(qpel_hv,8, 8, 4, 12, sse4);
+mc_rep_funcs(qpel_hv,10, 8, 64, sse4);
+mc_rep_funcs(qpel_hv,10, 8, 48, sse4);
+mc_rep_funcs(qpel_hv,10, 8, 32, sse4);
+mc_rep_funcs(qpel_hv,10, 8, 24, sse4);
+mc_rep_funcs(qpel_hv,10, 8, 16, sse4);
+mc_rep_funcs(qpel_hv,10, 4, 12, sse4);
+mc_rep_funcs(qpel_hv,12, 8, 64, sse4);
+mc_rep_funcs(qpel_hv,12, 8, 48, sse4);
+mc_rep_funcs(qpel_hv,12, 8, 32, sse4);
+mc_rep_funcs(qpel_hv,12, 8, 24, sse4);
+mc_rep_funcs(qpel_hv,12, 8, 16, sse4);
+mc_rep_funcs(qpel_hv,12, 4, 12, sse4);
+
+#define mc_rep_uni_w(bitd, step, W, opt) \
+void ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, int16_t *_src, \
+ int height, int denom, int _wx, int _ox) \
+{ \
+ int i; \
+ int16_t *src; \
+ uint8_t *dst; \
+ for (i = 0; i < W; i += step) { \
+ src= _src + i; \
+ dst= _dst + (i * ((bitd + 7) / 8)); \
+ ff_hevc_put_hevc_uni_w##step##_##bitd##_##opt(dst, dststride, src, \
+ height, denom, _wx, _ox); \
+ } \
+}
+
+mc_rep_uni_w(8, 6, 12, sse4);
+mc_rep_uni_w(8, 8, 16, sse4);
+mc_rep_uni_w(8, 8, 24, sse4);
+mc_rep_uni_w(8, 8, 32, sse4);
+mc_rep_uni_w(8, 8, 48, sse4);
+mc_rep_uni_w(8, 8, 64, sse4);
+
+mc_rep_uni_w(10, 6, 12, sse4);
+mc_rep_uni_w(10, 8, 16, sse4);
+mc_rep_uni_w(10, 8, 24, sse4);
+mc_rep_uni_w(10, 8, 32, sse4);
+mc_rep_uni_w(10, 8, 48, sse4);
+mc_rep_uni_w(10, 8, 64, sse4);
+
+mc_rep_uni_w(12, 6, 12, sse4);
+mc_rep_uni_w(12, 8, 16, sse4);
+mc_rep_uni_w(12, 8, 24, sse4);
+mc_rep_uni_w(12, 8, 32, sse4);
+mc_rep_uni_w(12, 8, 48, sse4);
+mc_rep_uni_w(12, 8, 64, sse4);
+
+#define mc_rep_bi_w(bitd, step, W, opt) \
+void ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, int16_t *_src, \
+ int16_t *_src2, int height, \
+ int denom, int _wx0, int _wx1, int _ox0, int _ox1) \
+{ \
+ int i; \
+ int16_t *src; \
+ int16_t *src2; \
+ uint8_t *dst; \
+ for (i = 0; i < W; i += step) { \
+ src = _src + i; \
+ src2 = _src2 + i; \
+ dst = _dst + (i * ((bitd + 7) / 8)); \
+ ff_hevc_put_hevc_bi_w##step##_##bitd##_##opt(dst, dststride, src, src2, \
+ height, denom, _wx0, _wx1, _ox0, _ox1); \
+ } \
+}
+
+mc_rep_bi_w(8, 6, 12, sse4);
+mc_rep_bi_w(8, 8, 16, sse4);
+mc_rep_bi_w(8, 8, 24, sse4);
+mc_rep_bi_w(8, 8, 32, sse4);
+mc_rep_bi_w(8, 8, 48, sse4);
+mc_rep_bi_w(8, 8, 64, sse4);
+
+mc_rep_bi_w(10, 6, 12, sse4);
+mc_rep_bi_w(10, 8, 16, sse4);
+mc_rep_bi_w(10, 8, 24, sse4);
+mc_rep_bi_w(10, 8, 32, sse4);
+mc_rep_bi_w(10, 8, 48, sse4);
+mc_rep_bi_w(10, 8, 64, sse4);
+
+mc_rep_bi_w(12, 6, 12, sse4);
+mc_rep_bi_w(12, 8, 16, sse4);
+mc_rep_bi_w(12, 8, 24, sse4);
+mc_rep_bi_w(12, 8, 32, sse4);
+mc_rep_bi_w(12, 8, 48, sse4);
+mc_rep_bi_w(12, 8, 64, sse4);
+
+#define mc_uni_w_func(name, bitd, W, opt) \
+void ff_hevc_put_hevc_uni_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \
+ uint8_t *_src, ptrdiff_t _srcstride, \
+ int height, int denom, \
+ int _wx, int _ox, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \
+ ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \
+ ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(_dst, _dststride, temp, height, denom, _wx, _ox);\
+}
+
+#define mc_uni_w_funcs(name, bitd, opt) \
+ mc_uni_w_func(name, bitd, 4, opt); \
+ mc_uni_w_func(name, bitd, 8, opt); \
+ mc_uni_w_func(name, bitd, 12, opt); \
+ mc_uni_w_func(name, bitd, 16, opt); \
+ mc_uni_w_func(name, bitd, 24, opt); \
+ mc_uni_w_func(name, bitd, 32, opt); \
+ mc_uni_w_func(name, bitd, 48, opt); \
+ mc_uni_w_func(name, bitd, 64, opt)
+
+mc_uni_w_funcs(pel_pixels, 8, sse4);
+mc_uni_w_func(pel_pixels, 8, 6, sse4);
+mc_uni_w_funcs(epel_h, 8, sse4);
+mc_uni_w_func(epel_h, 8, 6, sse4);
+mc_uni_w_funcs(epel_v, 8, sse4);
+mc_uni_w_func(epel_v, 8, 6, sse4);
+mc_uni_w_funcs(epel_hv, 8, sse4);
+mc_uni_w_func(epel_hv, 8, 6, sse4);
+mc_uni_w_funcs(qpel_h, 8, sse4);
+mc_uni_w_funcs(qpel_v, 8, sse4);
+mc_uni_w_funcs(qpel_hv, 8, sse4);
+
+mc_uni_w_funcs(pel_pixels, 10, sse4);
+mc_uni_w_func(pel_pixels, 10, 6, sse4);
+mc_uni_w_funcs(epel_h, 10, sse4);
+mc_uni_w_func(epel_h, 10, 6, sse4);
+mc_uni_w_funcs(epel_v, 10, sse4);
+mc_uni_w_func(epel_v, 10, 6, sse4);
+mc_uni_w_funcs(epel_hv, 10, sse4);
+mc_uni_w_func(epel_hv, 10, 6, sse4);
+mc_uni_w_funcs(qpel_h, 10, sse4);
+mc_uni_w_funcs(qpel_v, 10, sse4);
+mc_uni_w_funcs(qpel_hv, 10, sse4);
+
+mc_uni_w_funcs(pel_pixels, 12, sse4);
+mc_uni_w_func(pel_pixels, 12, 6, sse4);
+mc_uni_w_funcs(epel_h, 12, sse4);
+mc_uni_w_func(epel_h, 12, 6, sse4);
+mc_uni_w_funcs(epel_v, 12, sse4);
+mc_uni_w_func(epel_v, 12, 6, sse4);
+mc_uni_w_funcs(epel_hv, 12, sse4);
+mc_uni_w_func(epel_hv, 12, 6, sse4);
+mc_uni_w_funcs(qpel_h, 12, sse4);
+mc_uni_w_funcs(qpel_v, 12, sse4);
+mc_uni_w_funcs(qpel_hv, 12, sse4);
+
+#define mc_bi_w_func(name, bitd, W, opt) \
+void ff_hevc_put_hevc_bi_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \
+ uint8_t *_src, ptrdiff_t _srcstride, \
+ int16_t *_src2, \
+ int height, int denom, \
+ int _wx0, int _wx1, int _ox0, int _ox1, \
+ intptr_t mx, intptr_t my, int width) \
+{ \
+ LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \
+ ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \
+ ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(_dst, _dststride, temp, _src2, \
+ height, denom, _wx0, _wx1, _ox0, _ox1); \
+}
+
+#define mc_bi_w_funcs(name, bitd, opt) \
+ mc_bi_w_func(name, bitd, 4, opt); \
+ mc_bi_w_func(name, bitd, 8, opt); \
+ mc_bi_w_func(name, bitd, 12, opt); \
+ mc_bi_w_func(name, bitd, 16, opt); \
+ mc_bi_w_func(name, bitd, 24, opt); \
+ mc_bi_w_func(name, bitd, 32, opt); \
+ mc_bi_w_func(name, bitd, 48, opt); \
+ mc_bi_w_func(name, bitd, 64, opt)
+
+mc_bi_w_funcs(pel_pixels, 8, sse4);
+mc_bi_w_func(pel_pixels, 8, 6, sse4);
+mc_bi_w_funcs(epel_h, 8, sse4);
+mc_bi_w_func(epel_h, 8, 6, sse4);
+mc_bi_w_funcs(epel_v, 8, sse4);
+mc_bi_w_func(epel_v, 8, 6, sse4);
+mc_bi_w_funcs(epel_hv, 8, sse4);
+mc_bi_w_func(epel_hv, 8, 6, sse4);
+mc_bi_w_funcs(qpel_h, 8, sse4);
+mc_bi_w_funcs(qpel_v, 8, sse4);
+mc_bi_w_funcs(qpel_hv, 8, sse4);
+
+mc_bi_w_funcs(pel_pixels, 10, sse4);
+mc_bi_w_func(pel_pixels, 10, 6, sse4);
+mc_bi_w_funcs(epel_h, 10, sse4);
+mc_bi_w_func(epel_h, 10, 6, sse4);
+mc_bi_w_funcs(epel_v, 10, sse4);
+mc_bi_w_func(epel_v, 10, 6, sse4);
+mc_bi_w_funcs(epel_hv, 10, sse4);
+mc_bi_w_func(epel_hv, 10, 6, sse4);
+mc_bi_w_funcs(qpel_h, 10, sse4);
+mc_bi_w_funcs(qpel_v, 10, sse4);
+mc_bi_w_funcs(qpel_hv, 10, sse4);
+
+mc_bi_w_funcs(pel_pixels, 12, sse4);
+mc_bi_w_func(pel_pixels, 12, 6, sse4);
+mc_bi_w_funcs(epel_h, 12, sse4);
+mc_bi_w_func(epel_h, 12, 6, sse4);
+mc_bi_w_funcs(epel_v, 12, sse4);
+mc_bi_w_func(epel_v, 12, 6, sse4);
+mc_bi_w_funcs(epel_hv, 12, sse4);
+mc_bi_w_func(epel_hv, 12, 6, sse4);
+mc_bi_w_funcs(qpel_h, 12, sse4);
+mc_bi_w_funcs(qpel_v, 12, sse4);
+mc_bi_w_funcs(qpel_hv, 12, sse4);
+#endif //ARCH_X86_64 && HAVE_SSE4_EXTERNAL
-#define LFL_FUNCS(type, depth) \
- LFL_FUNC(h, depth, ssse3) \
- LFL_FUNC(v, depth, ssse3)
+#define SAO_BAND_FILTER_FUNCS(bitd, opt) \
+void ff_hevc_sao_band_filter_8_##bitd##_##opt(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); \
+void ff_hevc_sao_band_filter_16_##bitd##_##opt(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); \
+void ff_hevc_sao_band_filter_32_##bitd##_##opt(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); \
+void ff_hevc_sao_band_filter_48_##bitd##_##opt(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); \
+void ff_hevc_sao_band_filter_64_##bitd##_##opt(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)
-LFC_FUNCS(uint8_t, 8)
-LFC_FUNCS(uint8_t, 10)
-LFL_FUNCS(uint8_t, 8)
-LFL_FUNCS(uint8_t, 10)
+SAO_BAND_FILTER_FUNCS(8, sse2);
+SAO_BAND_FILTER_FUNCS(10, sse2);
+SAO_BAND_FILTER_FUNCS(12, sse2);
+SAO_BAND_FILTER_FUNCS(8, avx);
+SAO_BAND_FILTER_FUNCS(10, avx);
+SAO_BAND_FILTER_FUNCS(12, avx);
+SAO_BAND_FILTER_FUNCS(8, avx2);
+SAO_BAND_FILTER_FUNCS(10, avx2);
+SAO_BAND_FILTER_FUNCS(12, avx2);
+
+#define SAO_BAND_INIT(bitd, opt) do { \
+ c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_##bitd##_##opt; \
+ c->sao_band_filter[1] = ff_hevc_sao_band_filter_16_##bitd##_##opt; \
+ c->sao_band_filter[2] = ff_hevc_sao_band_filter_32_##bitd##_##opt; \
+ c->sao_band_filter[3] = ff_hevc_sao_band_filter_48_##bitd##_##opt; \
+ c->sao_band_filter[4] = ff_hevc_sao_band_filter_64_##bitd##_##opt; \
+} while (0)
+
+#define SAO_EDGE_FILTER_FUNCS(bitd, opt) \
+void ff_hevc_sao_edge_filter_8_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \
+ int eo, int width, int height); \
+void ff_hevc_sao_edge_filter_16_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \
+ int eo, int width, int height); \
+void ff_hevc_sao_edge_filter_32_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \
+ int eo, int width, int height); \
+void ff_hevc_sao_edge_filter_48_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \
+ int eo, int width, int height); \
+void ff_hevc_sao_edge_filter_64_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \
+ int eo, int width, int height); \
+
+SAO_EDGE_FILTER_FUNCS(8, ssse3);
+SAO_EDGE_FILTER_FUNCS(8, avx2);
+SAO_EDGE_FILTER_FUNCS(10, sse2);
+SAO_EDGE_FILTER_FUNCS(10, avx2);
+SAO_EDGE_FILTER_FUNCS(12, sse2);
+SAO_EDGE_FILTER_FUNCS(12, avx2);
+
+#define SAO_EDGE_INIT(bitd, opt) do { \
+ c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8_##bitd##_##opt; \
+ c->sao_edge_filter[1] = ff_hevc_sao_edge_filter_16_##bitd##_##opt; \
+ c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_##bitd##_##opt; \
+ c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_48_##bitd##_##opt; \
+ c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_##bitd##_##opt; \
+} while (0)
+
+#define EPEL_LINKS(pointer, my, mx, fname, bitd, opt ) \
+ PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \
+ PEL_LINK(pointer, 2, my , mx , fname##6 , bitd, opt ); \
+ PEL_LINK(pointer, 3, my , mx , fname##8 , bitd, opt ); \
+ PEL_LINK(pointer, 4, my , mx , fname##12, bitd, opt ); \
+ PEL_LINK(pointer, 5, my , mx , fname##16, bitd, opt ); \
+ PEL_LINK(pointer, 6, my , mx , fname##24, bitd, opt ); \
+ PEL_LINK(pointer, 7, my , mx , fname##32, bitd, opt ); \
+ PEL_LINK(pointer, 8, my , mx , fname##48, bitd, opt ); \
+ PEL_LINK(pointer, 9, my , mx , fname##64, bitd, opt )
+#define QPEL_LINKS(pointer, my, mx, fname, bitd, opt) \
+ PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \
+ PEL_LINK(pointer, 3, my , mx , fname##8 , bitd, opt ); \
+ PEL_LINK(pointer, 4, my , mx , fname##12, bitd, opt ); \
+ PEL_LINK(pointer, 5, my , mx , fname##16, bitd, opt ); \
+ PEL_LINK(pointer, 6, my , mx , fname##24, bitd, opt ); \
+ PEL_LINK(pointer, 7, my , mx , fname##32, bitd, opt ); \
+ PEL_LINK(pointer, 8, my , mx , fname##48, bitd, opt ); \
+ PEL_LINK(pointer, 9, my , mx , fname##64, bitd, opt )
void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth)
{
int cpu_flags = av_get_cpu_flags();
if (bit_depth == 8) {
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->idct_dc[0] = ff_hevc_idct4x4_dc_8_mmxext;
+ c->idct_dc[1] = ff_hevc_idct8x8_dc_8_mmxext;
+ c->transform_add[0] = ff_hevc_transform_add4_8_mmxext;
+ }
if (EXTERNAL_SSE2(cpu_flags)) {
c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_sse2;
c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_sse2;
+ if (ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_sse2;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_sse2;
+
+ }
+ SAO_BAND_INIT(8, sse2);
+
+ c->idct_dc[1] = ff_hevc_idct8x8_dc_8_sse2;
+ c->idct_dc[2] = ff_hevc_idct16x16_dc_8_sse2;
+ c->idct_dc[3] = ff_hevc_idct32x32_dc_8_sse2;
+
+ c->transform_add[1] = ff_hevc_transform_add8_8_sse2;
+ c->transform_add[2] = ff_hevc_transform_add16_8_sse2;
+ c->transform_add[3] = ff_hevc_transform_add32_8_sse2;
}
- if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) {
- c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_ssse3;
- c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_ssse3;
+ if (EXTERNAL_SSSE3(cpu_flags)) {
+ if(ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_ssse3;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_ssse3;
+ }
+ SAO_EDGE_INIT(8, ssse3);
+ }
+ if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) {
+
+ EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 8, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 8, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 8, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 1, 1, epel_hv, 8, sse4);
+
+ QPEL_LINKS(c->put_hevc_qpel, 0, 0, pel_pixels, 8, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 0, 1, qpel_h, 8, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 8, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 8, sse4);
+ }
+ if (EXTERNAL_AVX(cpu_flags)) {
+ c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_avx;
+ c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_avx;
+ if (ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_avx;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_avx;
+ }
+ SAO_BAND_INIT(8, avx);
+
+ c->transform_add[1] = ff_hevc_transform_add8_8_avx;
+ c->transform_add[2] = ff_hevc_transform_add16_8_avx;
+ c->transform_add[3] = ff_hevc_transform_add32_8_avx;
+ }
+ if (EXTERNAL_AVX2(cpu_flags)) {
+ c->idct_dc[2] = ff_hevc_idct16x16_dc_8_avx2;
+ c->idct_dc[3] = ff_hevc_idct32x32_dc_8_avx2;
+ if (ARCH_X86_64) {
+ c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2;
+ c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2;
+ c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2;
+
+ c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2;
+ c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2;
+ c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2;
+
+ c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2;
+ c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2;
+ c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2;
+
+ c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2;
+ c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2;
+ c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2;
+
+ c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2;
+ c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2;
+ c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2;
+
+ c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2;
+ c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2;
+ c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2;
+
+ c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_8_avx2;
+ c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_8_avx2;
+ c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_8_avx2;
+
+ c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_8_avx2;
+ c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_8_avx2;
+ c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_8_avx2;
+
+ c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_8_avx2;
+ c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_8_avx2;
+ c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_8_avx2;
+
+ c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_8_avx2;
+ c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_8_avx2;
+ c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_8_avx2;
+
+ c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_8_avx2;
+ c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_8_avx2;
+ c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_8_avx2;
+
+ c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_8_avx2;
+ c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_8_avx2;
+ c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_8_avx2;
+
+ c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_8_avx2;
+ c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_8_avx2;
+ c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_8_avx2;
+
+ c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_8_avx2;
+ c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_8_avx2;
+ c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_8_avx2;
+
+ c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_8_avx2;
+ c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_8_avx2;
+ c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_8_avx2;
+
+ c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_avx2;
+ c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_8_avx2;
+ c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_avx2;
+
+ c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_8_avx2;
+ c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_8_avx2;
+ c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_8_avx2;
+
+ c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_8_avx2;
+ c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_8_avx2;
+ c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_8_avx2;
+
+ c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_8_avx2;
+ c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_8_avx2;
+ c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_8_avx2;
+
+ c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_8_avx2;
+ c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_8_avx2;
+ c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_8_avx2;
+
+ c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_8_avx2;
+ c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_8_avx2;
+ c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_8_avx2;
+ }
+ SAO_BAND_INIT(8, avx2);
+
+ c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_8_avx2;
+ c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_48_8_avx2;
+ c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_8_avx2;
+
+ c->transform_add[3] = ff_hevc_transform_add32_8_avx2;
}
} else if (bit_depth == 10) {
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->transform_add[0] = ff_hevc_transform_add4_10_mmxext;
+ c->idct_dc[0] = ff_hevc_idct4x4_dc_10_mmxext;
+ c->idct_dc[1] = ff_hevc_idct8x8_dc_10_mmxext;
+ }
if (EXTERNAL_SSE2(cpu_flags)) {
c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_sse2;
c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_sse2;
+ if (ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_sse2;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_sse2;
+ }
+ SAO_BAND_INIT(10, sse2);
+ SAO_EDGE_INIT(10, sse2);
+
+ c->idct_dc[1] = ff_hevc_idct8x8_dc_10_sse2;
+ c->idct_dc[2] = ff_hevc_idct16x16_dc_10_sse2;
+ c->idct_dc[3] = ff_hevc_idct32x32_dc_10_sse2;
+
+ c->transform_add[1] = ff_hevc_transform_add8_10_sse2;
+ c->transform_add[2] = ff_hevc_transform_add16_10_sse2;
+ c->transform_add[3] = ff_hevc_transform_add32_10_sse2;
}
if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) {
c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_ssse3;
c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_ssse3;
}
+ if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) {
+ EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 10, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 10, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 10, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 1, 1, epel_hv, 10, sse4);
+
+ QPEL_LINKS(c->put_hevc_qpel, 0, 0, pel_pixels, 10, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 0, 1, qpel_h, 10, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 10, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 10, sse4);
+ }
+ if (EXTERNAL_AVX(cpu_flags)) {
+ c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_avx;
+ c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_avx;
+ if (ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_avx;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_avx;
+ }
+ SAO_BAND_INIT(10, avx);
+ }
+ if (EXTERNAL_AVX2(cpu_flags)) {
+
+ c->idct_dc[2] = ff_hevc_idct16x16_dc_10_avx2;
+ c->idct_dc[3] = ff_hevc_idct32x32_dc_10_avx2;
+ if (ARCH_X86_64) {
+ c->put_hevc_epel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2;
+ c->put_hevc_epel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2;
+ c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2;
+ c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2;
+ c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2;
+
+ c->put_hevc_qpel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2;
+ c->put_hevc_qpel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2;
+ c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2;
+ c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2;
+ c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2;
+
+ c->put_hevc_epel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2;
+ c->put_hevc_epel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2;
+ c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2;
+ c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2;
+ c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2;
+
+ c->put_hevc_qpel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2;
+ c->put_hevc_qpel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2;
+ c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2;
+ c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2;
+ c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2;
+
+ c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2;
+ c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2;
+ c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2;
+ c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2;
+ c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2;
+ c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2;
+ c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2;
+ c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2;
+ c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2;
+ c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2;
+
+ c->put_hevc_epel[5][0][1] = ff_hevc_put_hevc_epel_h16_10_avx2;
+ c->put_hevc_epel[6][0][1] = ff_hevc_put_hevc_epel_h24_10_avx2;
+ c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_10_avx2;
+ c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_10_avx2;
+ c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_10_avx2;
+
+ c->put_hevc_epel_uni[5][0][1] = ff_hevc_put_hevc_uni_epel_h16_10_avx2;
+ c->put_hevc_epel_uni[6][0][1] = ff_hevc_put_hevc_uni_epel_h24_10_avx2;
+ c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_10_avx2;
+ c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_10_avx2;
+ c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_10_avx2;
+
+ c->put_hevc_epel_bi[5][0][1] = ff_hevc_put_hevc_bi_epel_h16_10_avx2;
+ c->put_hevc_epel_bi[6][0][1] = ff_hevc_put_hevc_bi_epel_h24_10_avx2;
+ c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_10_avx2;
+ c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_10_avx2;
+ c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_10_avx2;
+
+ c->put_hevc_epel[5][1][0] = ff_hevc_put_hevc_epel_v16_10_avx2;
+ c->put_hevc_epel[6][1][0] = ff_hevc_put_hevc_epel_v24_10_avx2;
+ c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_10_avx2;
+ c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_10_avx2;
+ c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_10_avx2;
+
+ c->put_hevc_epel_uni[5][1][0] = ff_hevc_put_hevc_uni_epel_v16_10_avx2;
+ c->put_hevc_epel_uni[6][1][0] = ff_hevc_put_hevc_uni_epel_v24_10_avx2;
+ c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_10_avx2;
+ c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_10_avx2;
+ c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_10_avx2;
+
+ c->put_hevc_epel_bi[5][1][0] = ff_hevc_put_hevc_bi_epel_v16_10_avx2;
+ c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_hevc_bi_epel_v24_10_avx2;
+ c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_10_avx2;
+ c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_10_avx2;
+ c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_10_avx2;
+
+ c->put_hevc_epel[5][1][1] = ff_hevc_put_hevc_epel_hv16_10_avx2;
+ c->put_hevc_epel[6][1][1] = ff_hevc_put_hevc_epel_hv24_10_avx2;
+ c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_10_avx2;
+ c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_10_avx2;
+ c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_10_avx2;
+
+ c->put_hevc_epel_uni[5][1][1] = ff_hevc_put_hevc_uni_epel_hv16_10_avx2;
+ c->put_hevc_epel_uni[6][1][1] = ff_hevc_put_hevc_uni_epel_hv24_10_avx2;
+ c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_10_avx2;
+ c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_10_avx2;
+ c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_10_avx2;
+
+ c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_bi_epel_hv16_10_avx2;
+ c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_bi_epel_hv24_10_avx2;
+ c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_10_avx2;
+ c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_10_avx2;
+ c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_10_avx2;
+
+ c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_10_avx2;
+ c->put_hevc_qpel[6][0][1] = ff_hevc_put_hevc_qpel_h24_10_avx2;
+ c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_10_avx2;
+ c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_10_avx2;
+ c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_10_avx2;
+
+ c->put_hevc_qpel_uni[5][0][1] = ff_hevc_put_hevc_uni_qpel_h16_10_avx2;
+ c->put_hevc_qpel_uni[6][0][1] = ff_hevc_put_hevc_uni_qpel_h24_10_avx2;
+ c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_10_avx2;
+ c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_10_avx2;
+ c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_10_avx2;
+
+ c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_hevc_bi_qpel_h16_10_avx2;
+ c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_hevc_bi_qpel_h24_10_avx2;
+ c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_10_avx2;
+ c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_10_avx2;
+ c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_10_avx2;
+
+ c->put_hevc_qpel[5][1][0] = ff_hevc_put_hevc_qpel_v16_10_avx2;
+ c->put_hevc_qpel[6][1][0] = ff_hevc_put_hevc_qpel_v24_10_avx2;
+ c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_10_avx2;
+ c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_10_avx2;
+ c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_10_avx2;
+
+ c->put_hevc_qpel_uni[5][1][0] = ff_hevc_put_hevc_uni_qpel_v16_10_avx2;
+ c->put_hevc_qpel_uni[6][1][0] = ff_hevc_put_hevc_uni_qpel_v24_10_avx2;
+ c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_10_avx2;
+ c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_10_avx2;
+ c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_10_avx2;
+
+ c->put_hevc_qpel_bi[5][1][0] = ff_hevc_put_hevc_bi_qpel_v16_10_avx2;
+ c->put_hevc_qpel_bi[6][1][0] = ff_hevc_put_hevc_bi_qpel_v24_10_avx2;
+ c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_10_avx2;
+ c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_10_avx2;
+ c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_10_avx2;
+
+ c->put_hevc_qpel[5][1][1] = ff_hevc_put_hevc_qpel_hv16_10_avx2;
+ c->put_hevc_qpel[6][1][1] = ff_hevc_put_hevc_qpel_hv24_10_avx2;
+ c->put_hevc_qpel[7][1][1] = ff_hevc_put_hevc_qpel_hv32_10_avx2;
+ c->put_hevc_qpel[8][1][1] = ff_hevc_put_hevc_qpel_hv48_10_avx2;
+ c->put_hevc_qpel[9][1][1] = ff_hevc_put_hevc_qpel_hv64_10_avx2;
+
+ c->put_hevc_qpel_uni[5][1][1] = ff_hevc_put_hevc_uni_qpel_hv16_10_avx2;
+ c->put_hevc_qpel_uni[6][1][1] = ff_hevc_put_hevc_uni_qpel_hv24_10_avx2;
+ c->put_hevc_qpel_uni[7][1][1] = ff_hevc_put_hevc_uni_qpel_hv32_10_avx2;
+ c->put_hevc_qpel_uni[8][1][1] = ff_hevc_put_hevc_uni_qpel_hv48_10_avx2;
+ c->put_hevc_qpel_uni[9][1][1] = ff_hevc_put_hevc_uni_qpel_hv64_10_avx2;
+
+ c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_hevc_bi_qpel_hv16_10_avx2;
+ c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_hevc_bi_qpel_hv24_10_avx2;
+ c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_hevc_bi_qpel_hv32_10_avx2;
+ c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_hevc_bi_qpel_hv48_10_avx2;
+ c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_hevc_bi_qpel_hv64_10_avx2;
+ }
+ SAO_BAND_INIT(10, avx2);
+ c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_10_avx2;
+ c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_48_10_avx2;
+ c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_10_avx2;
+
+ c->transform_add[2] = ff_hevc_transform_add16_10_avx2;
+ c->transform_add[3] = ff_hevc_transform_add32_10_avx2;
+
+ }
+ } else if (bit_depth == 12) {
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->idct_dc[0] = ff_hevc_idct4x4_dc_12_mmxext;
+ c->idct_dc[1] = ff_hevc_idct8x8_dc_12_mmxext;
+ }
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_sse2;
+ c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_sse2;
+ if (ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_sse2;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_sse2;
+ }
+ SAO_BAND_INIT(12, sse2);
+ SAO_EDGE_INIT(12, sse2);
+
+ c->idct_dc[1] = ff_hevc_idct8x8_dc_12_sse2;
+ c->idct_dc[2] = ff_hevc_idct16x16_dc_12_sse2;
+ c->idct_dc[3] = ff_hevc_idct32x32_dc_12_sse2;
+ }
+ if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_ssse3;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_ssse3;
+ }
+ if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) {
+ EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 12, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 12, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 12, sse4);
+ EPEL_LINKS(c->put_hevc_epel, 1, 1, epel_hv, 12, sse4);
+
+ QPEL_LINKS(c->put_hevc_qpel, 0, 0, pel_pixels, 12, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 0, 1, qpel_h, 12, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 12, sse4);
+ QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 12, sse4);
+ }
+ if (EXTERNAL_AVX(cpu_flags)) {
+ c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_avx;
+ c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_avx;
+ if (ARCH_X86_64) {
+ c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_avx;
+ c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_avx;
+ }
+ SAO_BAND_INIT(12, avx);
+ }
+ if (EXTERNAL_AVX2(cpu_flags)) {
+ c->idct_dc[2] = ff_hevc_idct16x16_dc_12_avx2;
+ c->idct_dc[3] = ff_hevc_idct32x32_dc_12_avx2;
+
+ SAO_BAND_INIT(12, avx2);
+ c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_12_avx2;
+ c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_48_12_avx2;
+ c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_12_avx2;
+ }
}
}
diff --git a/libavcodec/x86/hpeldsp.asm b/libavcodec/x86/hpeldsp.asm
index 073f7f908e..2cef8e698c 100644
--- a/libavcodec/x86/hpeldsp.asm
+++ b/libavcodec/x86/hpeldsp.asm
@@ -1,20 +1,27 @@
;******************************************************************************
+;*
+;* Copyright (c) 2000-2001 Fabrice Bellard <fabrice@bellard.org>
+;* Copyright (c) Nick Kurshev <nickols_k@mail.ru>
+;* Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+;* Copyright (c) 2002 Zdenek Kabelac <kabi@informatics.muni.cz>
+;* Copyright (c) 2013 Daniel Kang
+;*
;* SIMD-optimized halfpel functions
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -22,26 +29,49 @@
SECTION_RODATA
cextern pb_1
+cextern pw_2
+pb_interleave16: db 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15
+pb_interleave8: db 0, 4, 1, 5, 2, 6, 3, 7
+
+cextern pw_8192
SECTION_TEXT
; void ff_put_pixels8_x2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
%macro PUT_PIXELS8_X2 0
+%if cpuflag(sse2)
+cglobal put_pixels16_x2, 4,5,4
+%else
cglobal put_pixels8_x2, 4,5
+%endif
lea r4, [r2*2]
.loop:
- mova m0, [r1]
- mova m1, [r1+r2]
- PAVGB m0, [r1+1]
- PAVGB m1, [r1+r2+1]
+ movu m0, [r1+1]
+ movu m1, [r1+r2+1]
+%if cpuflag(sse2)
+ movu m2, [r1]
+ movu m3, [r1+r2]
+ pavgb m0, m2
+ pavgb m1, m3
+%else
+ PAVGB m0, [r1]
+ PAVGB m1, [r1+r2]
+%endif
mova [r0], m0
mova [r0+r2], m1
add r1, r4
add r0, r4
- mova m0, [r1]
- mova m1, [r1+r2]
- PAVGB m0, [r1+1]
- PAVGB m1, [r1+r2+1]
+ movu m0, [r1+1]
+ movu m1, [r1+r2+1]
+%if cpuflag(sse2)
+ movu m2, [r1]
+ movu m3, [r1+r2]
+ pavgb m0, m2
+ pavgb m1, m3
+%else
+ PAVGB m0, [r1]
+ PAVGB m1, [r1+r2]
+%endif
add r1, r4
mova [r0], m0
mova [r0+r2], m1
@@ -99,6 +129,9 @@ INIT_MMX mmxext
PUT_PIXELS_16
INIT_MMX 3dnow
PUT_PIXELS_16
+; The 8_X2 macro can easily be used here
+INIT_XMM sse2
+PUT_PIXELS8_X2
; void ff_put_no_rnd_pixels8_x2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
@@ -191,20 +224,24 @@ PUT_NO_RND_PIXELS8_X2_EXACT
; void ff_put_pixels8_y2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
%macro PUT_PIXELS8_Y2 0
+%if cpuflag(sse2)
+cglobal put_pixels16_y2, 4,5,3
+%else
cglobal put_pixels8_y2, 4,5
+%endif
lea r4, [r2*2]
- mova m0, [r1]
+ movu m0, [r1]
sub r0, r2
.loop:
- mova m1, [r1+r2]
- mova m2, [r1+r4]
+ movu m1, [r1+r2]
+ movu m2, [r1+r4]
add r1, r4
PAVGB m0, m1
PAVGB m1, m2
mova [r0+r2], m0
mova [r0+r4], m1
- mova m1, [r1+r2]
- mova m0, [r1+r4]
+ movu m1, [r1+r2]
+ movu m0, [r1+r4]
add r0, r4
add r1, r4
PAVGB m2, m1
@@ -221,6 +258,9 @@ INIT_MMX mmxext
PUT_PIXELS8_Y2
INIT_MMX 3dnow
PUT_PIXELS8_Y2
+; actually, put_pixels16_y2_sse2
+INIT_XMM sse2
+PUT_PIXELS8_Y2
; void ff_put_no_rnd_pixels8_y2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
@@ -334,26 +374,48 @@ AVG_PIXELS8
; void ff_avg_pixels8_x2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
%macro AVG_PIXELS8_X2 0
+%if cpuflag(sse2)
+cglobal avg_pixels16_x2, 4,5,4
+%else
cglobal avg_pixels8_x2, 4,5
+%endif
lea r4, [r2*2]
+%if notcpuflag(mmxext)
+ pcmpeqd m5, m5
+ paddb m5, m5
+%endif
.loop:
- mova m0, [r1]
- mova m2, [r1+r2]
- PAVGB m0, [r1+1]
- PAVGB m2, [r1+r2+1]
- PAVGB m0, [r0]
- PAVGB m2, [r0+r2]
+ movu m0, [r1]
+ movu m2, [r1+r2]
+%if cpuflag(sse2)
+ movu m1, [r1+1]
+ movu m3, [r1+r2+1]
+ pavgb m0, m1
+ pavgb m2, m3
+%else
+ PAVGB m0, [r1+1], m3, m5
+ PAVGB m2, [r1+r2+1], m4, m5
+%endif
+ PAVGB m0, [r0], m3, m5
+ PAVGB m2, [r0+r2], m4, m5
add r1, r4
mova [r0], m0
mova [r0+r2], m2
- mova m0, [r1]
- mova m2, [r1+r2]
- PAVGB m0, [r1+1]
- PAVGB m2, [r1+r2+1]
+ movu m0, [r1]
+ movu m2, [r1+r2]
+%if cpuflag(sse2)
+ movu m1, [r1+1]
+ movu m3, [r1+r2+1]
+ pavgb m0, m1
+ pavgb m2, m3
+%else
+ PAVGB m0, [r1+1], m3, m5
+ PAVGB m2, [r1+r2+1], m4, m5
+%endif
add r0, r4
add r1, r4
- PAVGB m0, [r0]
- PAVGB m2, [r0+r2]
+ PAVGB m0, [r0], m3, m5
+ PAVGB m2, [r0+r2], m4, m5
mova [r0], m0
mova [r0+r2], m2
add r0, r4
@@ -362,40 +424,45 @@ cglobal avg_pixels8_x2, 4,5
REP_RET
%endmacro
+INIT_MMX mmx
+AVG_PIXELS8_X2
INIT_MMX mmxext
AVG_PIXELS8_X2
INIT_MMX 3dnow
AVG_PIXELS8_X2
+; actually avg_pixels16_x2
+INIT_XMM sse2
+AVG_PIXELS8_X2
; void ff_avg_pixels8_y2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
%macro AVG_PIXELS8_Y2 0
+%if cpuflag(sse2)
+cglobal avg_pixels16_y2, 4,5,3
+%else
cglobal avg_pixels8_y2, 4,5
+%endif
lea r4, [r2*2]
- mova m0, [r1]
+ movu m0, [r1]
sub r0, r2
.loop:
- mova m1, [r1+r2]
- mova m2, [r1+r4]
+ movu m1, [r1+r2]
+ movu m2, [r1+r4]
add r1, r4
PAVGB m0, m1
PAVGB m1, m2
- mova m3, [r0+r2]
- mova m4, [r0+r4]
- PAVGB m0, m3
- PAVGB m1, m4
+ PAVGB m0, [r0+r2]
+ PAVGB m1, [r0+r4]
mova [r0+r2], m0
mova [r0+r4], m1
- mova m1, [r1+r2]
- mova m0, [r1+r4]
+ movu m1, [r1+r2]
+ movu m0, [r1+r4]
PAVGB m2, m1
PAVGB m1, m0
add r0, r4
add r1, r4
- mova m3, [r0+r2]
- mova m4, [r0+r4]
- PAVGB m2, m3
- PAVGB m1, m4
+ PAVGB m2, [r0+r2]
+ PAVGB m1, [r0+r4]
mova [r0+r2], m2
mova [r0+r4], m1
add r0, r4
@@ -408,11 +475,16 @@ INIT_MMX mmxext
AVG_PIXELS8_Y2
INIT_MMX 3dnow
AVG_PIXELS8_Y2
+; actually avg_pixels16_y2
+INIT_XMM sse2
+AVG_PIXELS8_Y2
; void ff_avg_pixels8_xy2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
-%macro AVG_PIXELS8_XY2 0
-cglobal avg_pixels8_xy2, 4,5
+; Note this is not correctly rounded, and is therefore used for
+; not-bitexact output
+%macro AVG_APPROX_PIXELS8_XY2 0
+cglobal avg_approx_pixels8_xy2, 4,5
mova m6, [pb_1]
lea r4, [r2*2]
mova m0, [r1]
@@ -449,6 +521,160 @@ cglobal avg_pixels8_xy2, 4,5
%endmacro
INIT_MMX mmxext
-AVG_PIXELS8_XY2
+AVG_APPROX_PIXELS8_XY2
INIT_MMX 3dnow
-AVG_PIXELS8_XY2
+AVG_APPROX_PIXELS8_XY2
+
+
+; void ff_avg_pixels16_xy2(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
+%macro SET_PIXELS_XY2 1
+%if cpuflag(sse2)
+cglobal %1_pixels16_xy2, 4,5,8
+%else
+cglobal %1_pixels8_xy2, 4,5
+%endif
+ pxor m7, m7
+ mova m6, [pw_2]
+ movu m0, [r1]
+ movu m4, [r1+1]
+ mova m1, m0
+ mova m5, m4
+ punpcklbw m0, m7
+ punpcklbw m4, m7
+ punpckhbw m1, m7
+ punpckhbw m5, m7
+ paddusw m4, m0
+ paddusw m5, m1
+ xor r4, r4
+ add r1, r2
+.loop:
+ movu m0, [r1+r4]
+ movu m2, [r1+r4+1]
+ mova m1, m0
+ mova m3, m2
+ punpcklbw m0, m7
+ punpcklbw m2, m7
+ punpckhbw m1, m7
+ punpckhbw m3, m7
+ paddusw m0, m2
+ paddusw m1, m3
+ paddusw m4, m6
+ paddusw m5, m6
+ paddusw m4, m0
+ paddusw m5, m1
+ psrlw m4, 2
+ psrlw m5, 2
+%ifidn %1, avg
+ mova m3, [r0+r4]
+ packuswb m4, m5
+ PAVGB m4, m3
+%else
+ packuswb m4, m5
+%endif
+ mova [r0+r4], m4
+ add r4, r2
+
+ movu m2, [r1+r4]
+ movu m4, [r1+r4+1]
+ mova m3, m2
+ mova m5, m4
+ punpcklbw m2, m7
+ punpcklbw m4, m7
+ punpckhbw m3, m7
+ punpckhbw m5, m7
+ paddusw m4, m2
+ paddusw m5, m3
+ paddusw m0, m6
+ paddusw m1, m6
+ paddusw m0, m4
+ paddusw m1, m5
+ psrlw m0, 2
+ psrlw m1, 2
+%ifidn %1, avg
+ mova m3, [r0+r4]
+ packuswb m0, m1
+ PAVGB m0, m3
+%else
+ packuswb m0, m1
+%endif
+ mova [r0+r4], m0
+ add r4, r2
+ sub r3d, 2
+ jnz .loop
+ REP_RET
+%endmacro
+
+INIT_MMX mmxext
+SET_PIXELS_XY2 avg
+INIT_MMX 3dnow
+SET_PIXELS_XY2 avg
+INIT_XMM sse2
+SET_PIXELS_XY2 put
+SET_PIXELS_XY2 avg
+
+%macro SSSE3_PIXELS_XY2 1-2
+%if %0 == 2 ; sse2
+cglobal %1_pixels16_xy2, 4,5,%2
+ mova m4, [pb_interleave16]
+%else
+cglobal %1_pixels8_xy2, 4,5
+ mova m4, [pb_interleave8]
+%endif
+ mova m5, [pb_1]
+ movu m0, [r1]
+ movu m1, [r1+1]
+ pmaddubsw m0, m5
+ pmaddubsw m1, m5
+ xor r4, r4
+ add r1, r2
+.loop:
+ movu m2, [r1+r4]
+ movu m3, [r1+r4+1]
+ pmaddubsw m2, m5
+ pmaddubsw m3, m5
+ paddusw m0, m2
+ paddusw m1, m3
+ pmulhrsw m0, [pw_8192]
+ pmulhrsw m1, [pw_8192]
+%ifidn %1, avg
+ mova m6, [r0+r4]
+ packuswb m0, m1
+ pshufb m0, m4
+ pavgb m0, m6
+%else
+ packuswb m0, m1
+ pshufb m0, m4
+%endif
+ mova [r0+r4], m0
+ add r4, r2
+
+ movu m0, [r1+r4]
+ movu m1, [r1+r4+1]
+ pmaddubsw m0, m5
+ pmaddubsw m1, m5
+ paddusw m2, m0
+ paddusw m3, m1
+ pmulhrsw m2, [pw_8192]
+ pmulhrsw m3, [pw_8192]
+%ifidn %1, avg
+ mova m6, [r0+r4]
+ packuswb m2, m3
+ pshufb m2, m4
+ pavgb m2, m6
+%else
+ packuswb m2, m3
+ pshufb m2, m4
+%endif
+ mova [r0+r4], m2
+ add r4, r2
+ sub r3d, 2
+ jnz .loop
+ REP_RET
+%endmacro
+
+INIT_MMX ssse3
+SSSE3_PIXELS_XY2 put
+SSSE3_PIXELS_XY2 avg
+INIT_XMM ssse3
+SSSE3_PIXELS_XY2 put, 6
+SSSE3_PIXELS_XY2 avg, 7
diff --git a/libavcodec/x86/hpeldsp.h b/libavcodec/x86/hpeldsp.h
index 47b0b8b825..5fae990a4f 100644
--- a/libavcodec/x86/hpeldsp.h
+++ b/libavcodec/x86/hpeldsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,12 +27,27 @@ void ff_avg_pixels8_x2_mmx(uint8_t *block, const uint8_t *pixels,
void ff_avg_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_avg_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_avg_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+
void ff_avg_pixels16_xy2_mmx(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_avg_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_avg_pixels16_xy2_ssse3(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
void ff_put_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_put_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
void ff_put_pixels16_xy2_mmx(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_put_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_put_pixels16_xy2_ssse3(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
#endif /* AVCODEC_X86_HPELDSP_H */
diff --git a/libavcodec/x86/hpeldsp_init.c b/libavcodec/x86/hpeldsp_init.c
index 1cc3bacd15..8c0a0e9ab3 100644
--- a/libavcodec/x86/hpeldsp_init.c
+++ b/libavcodec/x86/hpeldsp_init.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* MMX optimization by Nick Kurshev <nickols_k@mail.ru>
@@ -40,6 +40,14 @@ void ff_put_pixels16_x2_mmxext(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
void ff_put_pixels16_x2_3dnow(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_put_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_avg_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_put_pixels16_y2_sse2(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_avg_pixels16_y2_sse2(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
void ff_put_no_rnd_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
void ff_put_no_rnd_pixels8_x2_3dnow(uint8_t *block, const uint8_t *pixels,
@@ -74,10 +82,12 @@ void ff_avg_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
void ff_avg_pixels8_y2_3dnow(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
-void ff_avg_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h);
void ff_avg_pixels8_xy2_3dnow(uint8_t *block, const uint8_t *pixels,
ptrdiff_t line_size, int h);
+void ff_avg_approx_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
+void ff_avg_approx_pixels8_xy2_3dnow(uint8_t *block, const uint8_t *pixels,
+ ptrdiff_t line_size, int h);
#define avg_pixels8_mmx ff_avg_pixels8_mmx
#define avg_pixels8_x2_mmx ff_avg_pixels8_x2_mmx
@@ -156,32 +166,49 @@ CALL_2X_PIXELS_EXPORT(ff_put_pixels16_xy2_mmx, ff_put_pixels8_xy2_mmx, 8)
CALL_2X_PIXELS(avg_pixels16 ## CPUEXT, ff_avg_pixels8 ## CPUEXT, 8) \
CALL_2X_PIXELS(avg_pixels16_x2 ## CPUEXT, ff_avg_pixels8_x2 ## CPUEXT, 8) \
CALL_2X_PIXELS(avg_pixels16_y2 ## CPUEXT, ff_avg_pixels8_y2 ## CPUEXT, 8) \
- CALL_2X_PIXELS(avg_pixels16_xy2 ## CPUEXT, ff_avg_pixels8_xy2 ## CPUEXT, 8)
+ CALL_2X_PIXELS(avg_pixels16_xy2 ## CPUEXT, ff_avg_pixels8_xy2 ## CPUEXT, 8) \
+ CALL_2X_PIXELS(avg_approx_pixels16_xy2## CPUEXT, ff_avg_approx_pixels8_xy2## CPUEXT, 8)
HPELDSP_AVG_PIXELS16(_3dnow)
HPELDSP_AVG_PIXELS16(_mmxext)
#endif /* HAVE_YASM */
+#define SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \
+ if (HAVE_MMX_EXTERNAL) \
+ c->PFX ## _pixels_tab IDX [0] = PFX ## _pixels ## SIZE ## _ ## CPU;
+
+#if HAVE_MMX_INLINE
#define SET_HPEL_FUNCS(PFX, IDX, SIZE, CPU) \
do { \
- c->PFX ## _pixels_tab IDX [0] = PFX ## _pixels ## SIZE ## _ ## CPU; \
+ SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \
c->PFX ## _pixels_tab IDX [1] = PFX ## _pixels ## SIZE ## _x2_ ## CPU; \
c->PFX ## _pixels_tab IDX [2] = PFX ## _pixels ## SIZE ## _y2_ ## CPU; \
c->PFX ## _pixels_tab IDX [3] = PFX ## _pixels ## SIZE ## _xy2_ ## CPU; \
} while (0)
+#else
+#define SET_HPEL_FUNCS(PFX, IDX, SIZE, CPU) \
+ do { \
+ SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \
+ } while (0)
+#endif
static void hpeldsp_init_mmx(HpelDSPContext *c, int flags, int cpu_flags)
{
-#if HAVE_MMX_INLINE
SET_HPEL_FUNCS(put, [0], 16, mmx);
SET_HPEL_FUNCS(put_no_rnd, [0], 16, mmx);
SET_HPEL_FUNCS(avg, [0], 16, mmx);
SET_HPEL_FUNCS(avg_no_rnd, , 16, mmx);
SET_HPEL_FUNCS(put, [1], 8, mmx);
SET_HPEL_FUNCS(put_no_rnd, [1], 8, mmx);
- SET_HPEL_FUNCS(avg, [1], 8, mmx);
-#endif /* HAVE_MMX_INLINE */
+ if (HAVE_MMX_EXTERNAL) {
+ c->avg_pixels_tab[1][0] = ff_avg_pixels8_mmx;
+ c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_mmx;
+ }
+#if HAVE_MMX_INLINE
+ c->avg_pixels_tab[1][2] = avg_pixels8_y2_mmx;
+ c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_mmx;
+#endif
}
static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags, int cpu_flags)
@@ -193,6 +220,7 @@ static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags, int cpu_flags)
c->avg_pixels_tab[0][0] = avg_pixels16_mmxext;
c->avg_pixels_tab[0][1] = avg_pixels16_x2_mmxext;
c->avg_pixels_tab[0][2] = avg_pixels16_y2_mmxext;
+ c->avg_pixels_tab[0][3] = avg_pixels16_xy2_mmxext;
c->put_pixels_tab[1][1] = ff_put_pixels8_x2_mmxext;
c->put_pixels_tab[1][2] = ff_put_pixels8_y2_mmxext;
@@ -200,6 +228,7 @@ static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags, int cpu_flags)
c->avg_pixels_tab[1][0] = ff_avg_pixels8_mmxext;
c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_mmxext;
c->avg_pixels_tab[1][2] = ff_avg_pixels8_y2_mmxext;
+ c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_mmxext;
if (!(flags & CODEC_FLAG_BITEXACT)) {
c->put_no_rnd_pixels_tab[0][1] = put_no_rnd_pixels16_x2_mmxext;
@@ -207,11 +236,11 @@ static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags, int cpu_flags)
c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_mmxext;
c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_mmxext;
- c->avg_pixels_tab[0][3] = avg_pixels16_xy2_mmxext;
- c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_mmxext;
+ c->avg_pixels_tab[0][3] = avg_approx_pixels16_xy2_mmxext;
+ c->avg_pixels_tab[1][3] = ff_avg_approx_pixels8_xy2_mmxext;
}
- if (flags & CODEC_FLAG_BITEXACT && CONFIG_VP3_DECODER) {
+ if (CONFIG_VP3_DECODER && flags & CODEC_FLAG_BITEXACT) {
c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_exact_mmxext;
c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_exact_mmxext;
}
@@ -227,6 +256,7 @@ static void hpeldsp_init_3dnow(HpelDSPContext *c, int flags, int cpu_flags)
c->avg_pixels_tab[0][0] = avg_pixels16_3dnow;
c->avg_pixels_tab[0][1] = avg_pixels16_x2_3dnow;
c->avg_pixels_tab[0][2] = avg_pixels16_y2_3dnow;
+ c->avg_pixels_tab[0][3] = avg_pixels16_xy2_3dnow;
c->put_pixels_tab[1][1] = ff_put_pixels8_x2_3dnow;
c->put_pixels_tab[1][2] = ff_put_pixels8_y2_3dnow;
@@ -234,6 +264,7 @@ static void hpeldsp_init_3dnow(HpelDSPContext *c, int flags, int cpu_flags)
c->avg_pixels_tab[1][0] = ff_avg_pixels8_3dnow;
c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_3dnow;
c->avg_pixels_tab[1][2] = ff_avg_pixels8_y2_3dnow;
+ c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_3dnow;
if (!(flags & CODEC_FLAG_BITEXACT)){
c->put_no_rnd_pixels_tab[0][1] = put_no_rnd_pixels16_x2_3dnow;
@@ -241,11 +272,11 @@ static void hpeldsp_init_3dnow(HpelDSPContext *c, int flags, int cpu_flags)
c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_3dnow;
c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_3dnow;
- c->avg_pixels_tab[0][3] = avg_pixels16_xy2_3dnow;
- c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_3dnow;
+ c->avg_pixels_tab[0][3] = avg_approx_pixels16_xy2_3dnow;
+ c->avg_pixels_tab[1][3] = ff_avg_approx_pixels8_xy2_3dnow;
}
- if (flags & CODEC_FLAG_BITEXACT && CONFIG_VP3_DECODER) {
+ if (CONFIG_VP3_DECODER && flags & CODEC_FLAG_BITEXACT) {
c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_exact_3dnow;
c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_exact_3dnow;
}
@@ -259,11 +290,27 @@ static void hpeldsp_init_sse2(HpelDSPContext *c, int flags, int cpu_flags)
// these functions are slower than mmx on AMD, but faster on Intel
c->put_pixels_tab[0][0] = ff_put_pixels16_sse2;
c->put_no_rnd_pixels_tab[0][0] = ff_put_pixels16_sse2;
+ c->put_pixels_tab[0][1] = ff_put_pixels16_x2_sse2;
+ c->put_pixels_tab[0][2] = ff_put_pixels16_y2_sse2;
+ c->put_pixels_tab[0][3] = ff_put_pixels16_xy2_sse2;
c->avg_pixels_tab[0][0] = ff_avg_pixels16_sse2;
+ c->avg_pixels_tab[0][1] = ff_avg_pixels16_x2_sse2;
+ c->avg_pixels_tab[0][2] = ff_avg_pixels16_y2_sse2;
+ c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_sse2;
}
#endif /* HAVE_SSE2_EXTERNAL */
}
+static void hpeldsp_init_ssse3(HpelDSPContext *c, int flags, int cpu_flags)
+{
+#if HAVE_SSSE3_EXTERNAL
+ c->put_pixels_tab[0][3] = ff_put_pixels16_xy2_ssse3;
+ c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_ssse3;
+ c->put_pixels_tab[1][3] = ff_put_pixels8_xy2_ssse3;
+ c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_ssse3;
+#endif
+}
+
av_cold void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags)
{
int cpu_flags = av_get_cpu_flags();
@@ -279,4 +326,7 @@ av_cold void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags)
if (EXTERNAL_SSE2(cpu_flags))
hpeldsp_init_sse2(c, flags, cpu_flags);
+
+ if (EXTERNAL_SSSE3(cpu_flags))
+ hpeldsp_init_ssse3(c, flags, cpu_flags);
}
diff --git a/libavcodec/x86/hpeldsp_mmx.c b/libavcodec/x86/hpeldsp_mmx.c
deleted file mode 100644
index c93c78e40e..0000000000
--- a/libavcodec/x86/hpeldsp_mmx.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * MMX-optimized avg/put pixel routines
- *
- * Copyright (c) 2001 Fabrice Bellard
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "config.h"
-#include "hpeldsp.h"
-#include "inline_asm.h"
-
-#if HAVE_MMX_INLINE
-
-void ff_avg_pixels8_x2_mmx(uint8_t *block, const uint8_t *pixels,
- ptrdiff_t line_size, int h)
-{
- MOVQ_BFE(mm6);
- JUMPALIGN();
- do {
- __asm__ volatile(
- "movq %1, %%mm0 \n\t"
- "movq 1%1, %%mm1 \n\t"
- "movq %0, %%mm3 \n\t"
- PAVGB_MMX(%%mm0, %%mm1, %%mm2, %%mm6)
- PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6)
- "movq %%mm0, %0 \n\t"
- :"+m"(*block)
- :"m"(*pixels)
- :"memory");
- pixels += line_size;
- block += line_size;
- } while (--h);
-}
-
-#endif /* HAVE_MMX_INLINE */
diff --git a/libavcodec/x86/hpeldsp_rnd_template.c b/libavcodec/x86/hpeldsp_rnd_template.c
index d854e8a2fc..8cbc412e23 100644
--- a/libavcodec/x86/hpeldsp_rnd_template.c
+++ b/libavcodec/x86/hpeldsp_rnd_template.c
@@ -7,20 +7,20 @@
* mostly rewritten by Michael Niedermayer <michaelni@gmx.at>
* and improved by Zdenek Kabelac <kabi@users.sf.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -138,27 +138,28 @@ static void DEF(put, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_
static void DEF(avg, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
{
MOVQ_BFE(mm6);
- JUMPALIGN();
- do {
__asm__ volatile(
- "movq %1, %%mm0 \n\t"
- "movq 1%1, %%mm1 \n\t"
- "movq %0, %%mm3 \n\t"
+ ".p2align 3 \n\t"
+ "1: \n\t"
+ "movq (%1), %%mm0 \n\t"
+ "movq 1(%1), %%mm1 \n\t"
+ "movq (%2), %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6)
- "movq %%mm0, %0 \n\t"
- "movq 8%1, %%mm0 \n\t"
- "movq 9%1, %%mm1 \n\t"
- "movq 8%0, %%mm3 \n\t"
+ "movq %%mm0, (%2) \n\t"
+ "movq 8(%1), %%mm0 \n\t"
+ "movq 9(%1), %%mm1 \n\t"
+ "movq 8(%2), %%mm3 \n\t"
PAVGB(%%mm0, %%mm1, %%mm2, %%mm6)
PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6)
- "movq %%mm0, 8%0 \n\t"
- :"+m"(*block)
- :"m"(*pixels)
+ "movq %%mm0, 8(%2) \n\t"
+ "add %3, %1 \n\t"
+ "add %3, %2 \n\t"
+ "subl $1, %0 \n\t"
+ "jnz 1b \n\t"
+ :"+g"(h), "+S"(pixels), "+D"(block)
+ :"r"((x86_reg)line_size)
:"memory");
- pixels += line_size;
- block += line_size;
- } while (--h);
}
static void DEF(avg, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h)
diff --git a/libavcodec/x86/huffyuvdsp.asm b/libavcodec/x86/huffyuvdsp.asm
index 436abc8b75..85ee56dff2 100644
--- a/libavcodec/x86/huffyuvdsp.asm
+++ b/libavcodec/x86/huffyuvdsp.asm
@@ -1,28 +1,29 @@
;******************************************************************************
;* SIMD-optimized HuffYUV functions
;* Copyright (c) 2008 Loren Merritt
+;* Copyright (c) 2014 Christophe Gisquet
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* 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
-pb_f: times 16 db 15
+cextern pb_15
pb_zzzzzzzz77777777: times 8 db -1
pb_7: times 8 db 7
pb_zzzz3333zzzzbbbb: db -1,-1,-1,-1,3,3,3,3,-1,-1,-1,-1,11,11,11,11
@@ -33,64 +34,72 @@ SECTION_TEXT
; void ff_add_hfyu_median_pred_mmxext(uint8_t *dst, const uint8_t *top,
; const uint8_t *diff, int w,
; int *left, int *left_top)
-INIT_MMX mmxext
-cglobal add_hfyu_median_pred, 6,6,0, dst, top, diff, w, left, left_top
- movq mm0, [topq]
- movq mm2, mm0
- movd mm4, [left_topq]
- psllq mm2, 8
- movq mm1, mm0
- por mm4, mm2
- movd mm3, [leftq]
- psubb mm0, mm4 ; t-tl
+%macro HFYU_MEDIAN 0
+cglobal add_hfyu_median_pred, 6,6,8, dst, top, diff, w, left, left_top
+ movu m0, [topq]
+ mova m2, m0
+ movd m4, [left_topq]
+ LSHIFT m2, 1
+ mova m1, m0
+ por m4, m2
+ movd m3, [leftq]
+ psubb m0, m4 ; t-tl
add dstq, wq
add topq, wq
add diffq, wq
neg wq
jmp .skip
.loop:
- movq mm4, [topq+wq]
- movq mm0, mm4
- psllq mm4, 8
- por mm4, mm1
- movq mm1, mm0 ; t
- psubb mm0, mm4 ; t-tl
+ movu m4, [topq+wq]
+ mova m0, m4
+ LSHIFT m4, 1
+ por m4, m1
+ mova m1, m0 ; t
+ psubb m0, m4 ; t-tl
.skip:
- movq mm2, [diffq+wq]
+ movu m2, [diffq+wq]
%assign i 0
-%rep 8
- movq mm4, mm0
- paddb mm4, mm3 ; t-tl+l
- movq mm5, mm3
- pmaxub mm3, mm1
- pminub mm5, mm1
- pminub mm3, mm4
- pmaxub mm3, mm5 ; median
- paddb mm3, mm2 ; +residual
+%rep mmsize
+ mova m4, m0
+ paddb m4, m3 ; t-tl+l
+ mova m5, m3
+ pmaxub m3, m1
+ pminub m5, m1
+ pminub m3, m4
+ pmaxub m3, m5 ; median
+ paddb m3, m2 ; +residual
%if i==0
- movq mm7, mm3
- psllq mm7, 56
+ mova m7, m3
+ LSHIFT m7, mmsize-1
%else
- movq mm6, mm3
- psrlq mm7, 8
- psllq mm6, 56
- por mm7, mm6
+ mova m6, m3
+ RSHIFT m7, 1
+ LSHIFT m6, mmsize-1
+ por m7, m6
%endif
-%if i<7
- psrlq mm0, 8
- psrlq mm1, 8
- psrlq mm2, 8
+%if i<mmsize-1
+ RSHIFT m0, 1
+ RSHIFT m1, 1
+ RSHIFT m2, 1
%endif
%assign i i+1
%endrep
- movq [dstq+wq], mm7
- add wq, 8
+ movu [dstq+wq], m7
+ add wq, mmsize
jl .loop
movzx r2d, byte [dstq-1]
mov [leftq], r2d
movzx r2d, byte [topq-1]
mov [left_topq], r2d
RET
+%endmacro
+
+%if ARCH_X86_32
+INIT_MMX mmxext
+HFYU_MEDIAN
+%endif
+INIT_XMM sse2
+HFYU_MEDIAN
%macro ADD_HFYU_LEFT_LOOP 2 ; %1 = dst_is_aligned, %2 = src_is_aligned
@@ -148,7 +157,7 @@ cglobal add_hfyu_left_pred, 3,3,7, dst, src, w, left
INIT_XMM sse4
cglobal add_hfyu_left_pred, 3,3,7, dst, src, w, left
- mova m5, [pb_f]
+ mova m5, [pb_15]
mova m6, [pb_zzzzzzzz77777777]
mova m4, [pb_zzzz3333zzzzbbbb]
mova m3, [pb_zz11zz55zz99zzdd]
@@ -163,3 +172,82 @@ cglobal add_hfyu_left_pred, 3,3,7, dst, src, w, left
ADD_HFYU_LEFT_LOOP 0, 1
.src_unaligned:
ADD_HFYU_LEFT_LOOP 0, 0
+
+%macro ADD_BYTES 0
+cglobal add_bytes, 3,4,2, dst, src, w, size
+ mov sizeq, wq
+ and sizeq, -2*mmsize
+ jz .2
+ add dstq, sizeq
+ add srcq, sizeq
+ neg sizeq
+.1:
+ mova m0, [srcq + sizeq]
+ mova m1, [srcq + sizeq + mmsize]
+ paddb m0, [dstq + sizeq]
+ paddb m1, [dstq + sizeq + mmsize]
+ mova [dstq + sizeq], m0
+ mova [dstq + sizeq + mmsize], m1
+ add sizeq, 2*mmsize
+ jl .1
+.2:
+ and wq, 2*mmsize-1
+ jz .end
+ add dstq, wq
+ add srcq, wq
+ neg wq
+.3
+ mov sizeb, [srcq + wq]
+ add [dstq + wq], sizeb
+ inc wq
+ jl .3
+.end:
+ REP_RET
+%endmacro
+
+%if ARCH_X86_32
+INIT_MMX mmx
+ADD_BYTES
+%endif
+INIT_XMM sse2
+ADD_BYTES
+
+; void add_hfyu_left_pred_bgr32(uint8_t *dst, const uint8_t *src,
+; intptr_t w, uint8_t *left)
+%macro LEFT_BGR32 0
+cglobal add_hfyu_left_pred_bgr32, 4,4,3, dst, src, w, left
+ shl wq, 2
+ movd m0, [leftq]
+ lea dstq, [dstq + wq]
+ lea srcq, [srcq + wq]
+ LSHIFT m0, mmsize-4
+ neg wq
+.loop:
+ movu m1, [srcq+wq]
+ mova m2, m1
+%if mmsize == 8
+ punpckhdq m0, m0
+%endif
+ LSHIFT m1, 4
+ paddb m1, m2
+%if mmsize == 16
+ pshufd m0, m0, q3333
+ mova m2, m1
+ LSHIFT m1, 8
+ paddb m1, m2
+%endif
+ paddb m0, m1
+ movu [dstq+wq], m0
+ add wq, mmsize
+ jl .loop
+ movd m0, [dstq-4]
+ movd [leftq], m0
+ REP_RET
+%endmacro
+
+%if ARCH_X86_32
+INIT_MMX mmx
+LEFT_BGR32
+%endif
+INIT_XMM sse2
+LEFT_BGR32
diff --git a/libavcodec/x86/huffyuvdsp_init.c b/libavcodec/x86/huffyuvdsp_init.c
index 75537d7a4c..3ced3c0a1c 100644
--- a/libavcodec/x86/huffyuvdsp_init.c
+++ b/libavcodec/x86/huffyuvdsp_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Loren Merritt <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,20 +25,29 @@
#include "libavutil/x86/cpu.h"
#include "libavcodec/huffyuvdsp.h"
+void ff_add_bytes_mmx(uint8_t *dst, uint8_t *src, intptr_t w);
+void ff_add_bytes_sse2(uint8_t *dst, uint8_t *src, intptr_t w);
+
void ff_add_hfyu_median_pred_mmxext(uint8_t *dst, const uint8_t *top,
- const uint8_t *diff, int w,
+ const uint8_t *diff, intptr_t w,
int *left, int *left_top);
+void ff_add_hfyu_median_pred_sse2(uint8_t *dst, const uint8_t *top,
+ const uint8_t *diff, intptr_t w,
+ int *left, int *left_top);
int ff_add_hfyu_left_pred_ssse3(uint8_t *dst, const uint8_t *src,
- int w, int left);
+ intptr_t w, int left);
int ff_add_hfyu_left_pred_sse4(uint8_t *dst, const uint8_t *src,
- int w, int left);
+ intptr_t w, int left);
-#if HAVE_INLINE_ASM
+void ff_add_hfyu_left_pred_bgr32_mmx(uint8_t *dst, const uint8_t *src,
+ intptr_t w, uint8_t *left);
+void ff_add_hfyu_left_pred_bgr32_sse2(uint8_t *dst, const uint8_t *src,
+ intptr_t w, uint8_t *left);
-#if HAVE_7REGS
+#if HAVE_INLINE_ASM && HAVE_7REGS && ARCH_X86_32
static void add_hfyu_median_pred_cmov(uint8_t *dst, const uint8_t *top,
- const uint8_t *diff, int w,
+ const uint8_t *diff, intptr_t w,
int *left, int *left_top)
{
x86_reg w2 = -w;
@@ -72,56 +81,34 @@ static void add_hfyu_median_pred_cmov(uint8_t *dst, const uint8_t *top,
*left = l;
*left_top = tl;
}
-#endif /* HAVE_7REGS */
-
-static void add_bytes_mmx(uint8_t *dst, uint8_t *src, int w)
-{
- x86_reg i = 0;
-
- __asm__ volatile (
- "jmp 2f \n\t"
- "1: \n\t"
- "movq (%1, %0), %%mm0 \n\t"
- "movq (%2, %0), %%mm1 \n\t"
- "paddb %%mm0, %%mm1 \n\t"
- "movq %%mm1, (%2, %0) \n\t"
- "movq 8(%1, %0), %%mm0 \n\t"
- "movq 8(%2, %0), %%mm1 \n\t"
- "paddb %%mm0, %%mm1 \n\t"
- "movq %%mm1, 8(%2, %0) \n\t"
- "add $16, %0 \n\t"
- "2: \n\t"
- "cmp %3, %0 \n\t"
- "js 1b \n\t"
- : "+r" (i)
- : "r" (src), "r" (dst), "r" ((x86_reg) w - 15));
-
- for (; i < w; i++)
- dst[i + 0] += src[i + 0];
-}
-
-#endif /* HAVE_INLINE_ASM */
+#endif
av_cold void ff_huffyuvdsp_init_x86(HuffYUVDSPContext *c)
{
int cpu_flags = av_get_cpu_flags();
-#if HAVE_INLINE_ASM
-#if HAVE_7REGS
+#if HAVE_INLINE_ASM && HAVE_7REGS && ARCH_X86_32
if (cpu_flags & AV_CPU_FLAG_CMOV)
c->add_hfyu_median_pred = add_hfyu_median_pred_cmov;
-#endif /* HAVE_7REGS */
+#endif
- if (INLINE_MMX(cpu_flags))
- c->add_bytes = add_bytes_mmx;
-#endif /* HAVE_INLINE_ASM */
+ if (ARCH_X86_32 && EXTERNAL_MMX(cpu_flags)) {
+ c->add_bytes = ff_add_bytes_mmx;
+ c->add_hfyu_left_pred_bgr32 = ff_add_hfyu_left_pred_bgr32_mmx;
+ }
- if (EXTERNAL_MMXEXT(cpu_flags)) {
+ if (ARCH_X86_32 && EXTERNAL_MMXEXT(cpu_flags)) {
/* slower than cmov version on AMD */
if (!(cpu_flags & AV_CPU_FLAG_3DNOW))
c->add_hfyu_median_pred = ff_add_hfyu_median_pred_mmxext;
}
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->add_bytes = ff_add_bytes_sse2;
+ c->add_hfyu_median_pred = ff_add_hfyu_median_pred_sse2;
+ c->add_hfyu_left_pred_bgr32 = ff_add_hfyu_left_pred_bgr32_sse2;
+ }
+
if (EXTERNAL_SSSE3(cpu_flags)) {
c->add_hfyu_left_pred = ff_add_hfyu_left_pred_ssse3;
if (cpu_flags & AV_CPU_FLAG_SSE4) // not really SSE4, just slow on Conroe
diff --git a/libavcodec/x86/huffyuvencdsp_mmx.c b/libavcodec/x86/huffyuvencdsp_mmx.c
index 8ffaced37d..63d8e3cc73 100644
--- a/libavcodec/x86/huffyuvencdsp_mmx.c
+++ b/libavcodec/x86/huffyuvencdsp_mmx.c
@@ -5,20 +5,20 @@
*
* MMX optimization by Nick Kurshev <nickols_k@mail.ru>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,10 +31,11 @@
#if HAVE_INLINE_ASM
-static void diff_bytes_mmx(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w)
+static void diff_bytes_mmx(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, int w)
{
x86_reg i = 0;
+ if (w >= 16)
__asm__ volatile (
"1: \n\t"
"movq (%2, %0), %%mm0 \n\t"
diff --git a/libavcodec/x86/idctdsp.asm b/libavcodec/x86/idctdsp.asm
new file mode 100644
index 0000000000..0aa73459e2
--- /dev/null
+++ b/libavcodec/x86/idctdsp.asm
@@ -0,0 +1,183 @@
+;******************************************************************************
+;* SIMD-optimized IDCT-related routines
+;* Copyright (c) 2008 Loren Merritt
+;* Copyright (c) 2003-2013 Michael Niedermayer
+;* Copyright (c) 2013 Daniel Kang
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+cextern pb_80
+
+SECTION_TEXT
+
+;--------------------------------------------------------------------------
+;void ff_put_signed_pixels_clamped(const int16_t *block, uint8_t *pixels,
+; ptrdiff_t line_size)
+;--------------------------------------------------------------------------
+
+%macro PUT_SIGNED_PIXELS_CLAMPED_HALF 1
+ mova m1, [blockq+mmsize*0+%1]
+ mova m2, [blockq+mmsize*2+%1]
+%if mmsize == 8
+ mova m3, [blockq+mmsize*4+%1]
+ mova m4, [blockq+mmsize*6+%1]
+%endif
+ packsswb m1, [blockq+mmsize*1+%1]
+ packsswb m2, [blockq+mmsize*3+%1]
+%if mmsize == 8
+ packsswb m3, [blockq+mmsize*5+%1]
+ packsswb m4, [blockq+mmsize*7+%1]
+%endif
+ paddb m1, m0
+ paddb m2, m0
+%if mmsize == 8
+ paddb m3, m0
+ paddb m4, m0
+ movq [pixelsq+lsizeq*0], m1
+ movq [pixelsq+lsizeq*1], m2
+ movq [pixelsq+lsizeq*2], m3
+ movq [pixelsq+lsize3q ], m4
+%else
+ movq [pixelsq+lsizeq*0], m1
+ movhps [pixelsq+lsizeq*1], m1
+ movq [pixelsq+lsizeq*2], m2
+ movhps [pixelsq+lsize3q ], m2
+%endif
+%endmacro
+
+%macro PUT_SIGNED_PIXELS_CLAMPED 1
+cglobal put_signed_pixels_clamped, 3, 4, %1, block, pixels, lsize, lsize3
+ mova m0, [pb_80]
+ lea lsize3q, [lsizeq*3]
+ PUT_SIGNED_PIXELS_CLAMPED_HALF 0
+ lea pixelsq, [pixelsq+lsizeq*4]
+ PUT_SIGNED_PIXELS_CLAMPED_HALF 64
+ RET
+%endmacro
+
+INIT_MMX mmx
+PUT_SIGNED_PIXELS_CLAMPED 0
+INIT_XMM sse2
+PUT_SIGNED_PIXELS_CLAMPED 3
+
+;--------------------------------------------------------------------------
+; void ff_put_pixels_clamped(const int16_t *block, uint8_t *pixels,
+; ptrdiff_t line_size);
+;--------------------------------------------------------------------------
+; %1 = block offset
+%macro PUT_PIXELS_CLAMPED_HALF 1
+ mova m0, [blockq+mmsize*0+%1]
+ mova m1, [blockq+mmsize*2+%1]
+%if mmsize == 8
+ mova m2, [blockq+mmsize*4+%1]
+ mova m3, [blockq+mmsize*6+%1]
+%endif
+ packuswb m0, [blockq+mmsize*1+%1]
+ packuswb m1, [blockq+mmsize*3+%1]
+%if mmsize == 8
+ packuswb m2, [blockq+mmsize*5+%1]
+ packuswb m3, [blockq+mmsize*7+%1]
+ movq [pixelsq], m0
+ movq [lsizeq+pixelsq], m1
+ movq [2*lsizeq+pixelsq], m2
+ movq [lsize3q+pixelsq], m3
+%else
+ movq [pixelsq], m0
+ movhps [lsizeq+pixelsq], m0
+ movq [2*lsizeq+pixelsq], m1
+ movhps [lsize3q+pixelsq], m1
+%endif
+%endmacro
+
+%macro PUT_PIXELS_CLAMPED 0
+cglobal put_pixels_clamped, 3, 4, 2, block, pixels, lsize, lsize3
+ lea lsize3q, [lsizeq*3]
+ PUT_PIXELS_CLAMPED_HALF 0
+ lea pixelsq, [pixelsq+lsizeq*4]
+ PUT_PIXELS_CLAMPED_HALF 64
+ RET
+%endmacro
+
+INIT_MMX mmx
+PUT_PIXELS_CLAMPED
+INIT_XMM sse2
+PUT_PIXELS_CLAMPED
+
+;--------------------------------------------------------------------------
+; void ff_add_pixels_clamped(const int16_t *block, uint8_t *pixels,
+; ptrdiff_t line_size);
+;--------------------------------------------------------------------------
+; %1 = block offset
+%macro ADD_PIXELS_CLAMPED 1
+ mova m0, [blockq+mmsize*0+%1]
+ mova m1, [blockq+mmsize*1+%1]
+%if mmsize == 8
+ mova m5, [blockq+mmsize*2+%1]
+ mova m6, [blockq+mmsize*3+%1]
+%endif
+ movq m2, [pixelsq]
+ movq m3, [pixelsq+lsizeq]
+%if mmsize == 8
+ mova m7, m2
+ punpcklbw m2, m4
+ punpckhbw m7, m4
+ paddsw m0, m2
+ paddsw m1, m7
+ mova m7, m3
+ punpcklbw m3, m4
+ punpckhbw m7, m4
+ paddsw m5, m3
+ paddsw m6, m7
+%else
+ punpcklbw m2, m4
+ punpcklbw m3, m4
+ paddsw m0, m2
+ paddsw m1, m3
+%endif
+ packuswb m0, m1
+%if mmsize == 8
+ packuswb m5, m6
+ movq [pixelsq], m0
+ movq [pixelsq+lsizeq], m5
+%else
+ movq [pixelsq], m0
+ movhps [pixelsq+lsizeq], m0
+%endif
+%endmacro
+
+%macro ADD_PIXELS_CLAMPED 0
+cglobal add_pixels_clamped, 3, 3, 5, block, pixels, lsize
+ pxor m4, m4
+ ADD_PIXELS_CLAMPED 0
+ lea pixelsq, [pixelsq+lsizeq*2]
+ ADD_PIXELS_CLAMPED 32
+ lea pixelsq, [pixelsq+lsizeq*2]
+ ADD_PIXELS_CLAMPED 64
+ lea pixelsq, [pixelsq+lsizeq*2]
+ ADD_PIXELS_CLAMPED 96
+ RET
+%endmacro
+
+INIT_MMX mmx
+ADD_PIXELS_CLAMPED
+INIT_XMM sse2
+ADD_PIXELS_CLAMPED
diff --git a/libavcodec/x86/idctdsp.h b/libavcodec/x86/idctdsp.h
index 22df3dd758..daa4e798ed 100644
--- a/libavcodec/x86/idctdsp.h
+++ b/libavcodec/x86/idctdsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -20,12 +20,19 @@
#define AVCODEC_X86_IDCTDSP_H
#include <stdint.h>
+#include <stddef.h>
void ff_add_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
- int line_size);
+ ptrdiff_t line_size);
+void ff_add_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels,
+ ptrdiff_t line_size);
void ff_put_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
- int line_size);
+ ptrdiff_t line_size);
+void ff_put_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels,
+ ptrdiff_t line_size);
void ff_put_signed_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
- int line_size);
+ ptrdiff_t line_size);
+void ff_put_signed_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels,
+ ptrdiff_t line_size);
#endif /* AVCODEC_X86_IDCTDSP_H */
diff --git a/libavcodec/x86/idctdsp_init.c b/libavcodec/x86/idctdsp_init.c
index 853c6a3661..2c26a98850 100644
--- a/libavcodec/x86/idctdsp_init.c
+++ b/libavcodec/x86/idctdsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,12 +64,10 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx,
int cpu_flags = av_get_cpu_flags();
if (INLINE_MMX(cpu_flags)) {
- c->put_pixels_clamped = ff_put_pixels_clamped_mmx;
- c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_mmx;
- c->add_pixels_clamped = ff_add_pixels_clamped_mmx;
-
if (!high_bit_depth &&
+ avctx->lowres == 0 &&
(avctx->idct_algo == FF_IDCT_AUTO ||
+ avctx->idct_algo == FF_IDCT_SIMPLEAUTO ||
avctx->idct_algo == FF_IDCT_SIMPLEMMX)) {
c->idct_put = ff_simple_idct_put_mmx;
c->idct_add = ff_simple_idct_add_mmx;
@@ -77,4 +75,14 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx,
c->perm_type = FF_IDCT_PERM_SIMPLE;
}
}
+ if (EXTERNAL_MMX(cpu_flags)) {
+ c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_mmx;
+ c->put_pixels_clamped = ff_put_pixels_clamped_mmx;
+ c->add_pixels_clamped = ff_add_pixels_clamped_mmx;
+ }
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_sse2;
+ c->put_pixels_clamped = ff_put_pixels_clamped_sse2;
+ c->add_pixels_clamped = ff_add_pixels_clamped_sse2;
+ }
}
diff --git a/libavcodec/x86/idctdsp_mmx.c b/libavcodec/x86/idctdsp_mmx.c
deleted file mode 100644
index 7285b1d357..0000000000
--- a/libavcodec/x86/idctdsp_mmx.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * SIMD-optimized IDCT-related routines
- * Copyright (c) 2000, 2001 Fabrice Bellard
- * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
- *
- * MMX optimization by Nick Kurshev <nickols_k@mail.ru>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-#include "libavutil/cpu.h"
-#include "libavutil/x86/asm.h"
-#include "idctdsp.h"
-#include "inline_asm.h"
-
-#if HAVE_INLINE_ASM
-
-void ff_put_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
- int line_size)
-{
- const int16_t *p;
- uint8_t *pix;
-
- /* read the pixels */
- p = block;
- pix = pixels;
- /* unrolled loop */
- __asm__ volatile (
- "movq (%3), %%mm0 \n\t"
- "movq 8(%3), %%mm1 \n\t"
- "movq 16(%3), %%mm2 \n\t"
- "movq 24(%3), %%mm3 \n\t"
- "movq 32(%3), %%mm4 \n\t"
- "movq 40(%3), %%mm5 \n\t"
- "movq 48(%3), %%mm6 \n\t"
- "movq 56(%3), %%mm7 \n\t"
- "packuswb %%mm1, %%mm0 \n\t"
- "packuswb %%mm3, %%mm2 \n\t"
- "packuswb %%mm5, %%mm4 \n\t"
- "packuswb %%mm7, %%mm6 \n\t"
- "movq %%mm0, (%0) \n\t"
- "movq %%mm2, (%0, %1) \n\t"
- "movq %%mm4, (%0, %1, 2) \n\t"
- "movq %%mm6, (%0, %2) \n\t"
- :: "r" (pix), "r" ((x86_reg) line_size), "r" ((x86_reg) line_size * 3),
- "r" (p)
- : "memory");
- pix += line_size * 4;
- p += 32;
-
- // if here would be an exact copy of the code above
- // compiler would generate some very strange code
- // thus using "r"
- __asm__ volatile (
- "movq (%3), %%mm0 \n\t"
- "movq 8(%3), %%mm1 \n\t"
- "movq 16(%3), %%mm2 \n\t"
- "movq 24(%3), %%mm3 \n\t"
- "movq 32(%3), %%mm4 \n\t"
- "movq 40(%3), %%mm5 \n\t"
- "movq 48(%3), %%mm6 \n\t"
- "movq 56(%3), %%mm7 \n\t"
- "packuswb %%mm1, %%mm0 \n\t"
- "packuswb %%mm3, %%mm2 \n\t"
- "packuswb %%mm5, %%mm4 \n\t"
- "packuswb %%mm7, %%mm6 \n\t"
- "movq %%mm0, (%0) \n\t"
- "movq %%mm2, (%0, %1) \n\t"
- "movq %%mm4, (%0, %1, 2) \n\t"
- "movq %%mm6, (%0, %2) \n\t"
- :: "r" (pix), "r" ((x86_reg) line_size), "r" ((x86_reg) line_size * 3),
- "r" (p)
- : "memory");
-}
-
-#define put_signed_pixels_clamped_mmx_half(off) \
- "movq "#off"(%2), %%mm1 \n\t" \
- "movq 16 + "#off"(%2), %%mm2 \n\t" \
- "movq 32 + "#off"(%2), %%mm3 \n\t" \
- "movq 48 + "#off"(%2), %%mm4 \n\t" \
- "packsswb 8 + "#off"(%2), %%mm1 \n\t" \
- "packsswb 24 + "#off"(%2), %%mm2 \n\t" \
- "packsswb 40 + "#off"(%2), %%mm3 \n\t" \
- "packsswb 56 + "#off"(%2), %%mm4 \n\t" \
- "paddb %%mm0, %%mm1 \n\t" \
- "paddb %%mm0, %%mm2 \n\t" \
- "paddb %%mm0, %%mm3 \n\t" \
- "paddb %%mm0, %%mm4 \n\t" \
- "movq %%mm1, (%0) \n\t" \
- "movq %%mm2, (%0, %3) \n\t" \
- "movq %%mm3, (%0, %3, 2) \n\t" \
- "movq %%mm4, (%0, %1) \n\t"
-
-void ff_put_signed_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
- int line_size)
-{
- x86_reg line_skip = line_size;
- x86_reg line_skip3;
-
- __asm__ volatile (
- "movq "MANGLE(ff_pb_80)", %%mm0 \n\t"
- "lea (%3, %3, 2), %1 \n\t"
- put_signed_pixels_clamped_mmx_half(0)
- "lea (%0, %3, 4), %0 \n\t"
- put_signed_pixels_clamped_mmx_half(64)
- : "+&r" (pixels), "=&r" (line_skip3)
- : "r" (block), "r" (line_skip)
- : "memory");
-}
-
-void ff_add_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels,
- int line_size)
-{
- const int16_t *p;
- uint8_t *pix;
- int i;
-
- /* read the pixels */
- p = block;
- pix = pixels;
- MOVQ_ZERO(mm7);
- i = 4;
- do {
- __asm__ volatile (
- "movq (%2), %%mm0 \n\t"
- "movq 8(%2), %%mm1 \n\t"
- "movq 16(%2), %%mm2 \n\t"
- "movq 24(%2), %%mm3 \n\t"
- "movq %0, %%mm4 \n\t"
- "movq %1, %%mm6 \n\t"
- "movq %%mm4, %%mm5 \n\t"
- "punpcklbw %%mm7, %%mm4 \n\t"
- "punpckhbw %%mm7, %%mm5 \n\t"
- "paddsw %%mm4, %%mm0 \n\t"
- "paddsw %%mm5, %%mm1 \n\t"
- "movq %%mm6, %%mm5 \n\t"
- "punpcklbw %%mm7, %%mm6 \n\t"
- "punpckhbw %%mm7, %%mm5 \n\t"
- "paddsw %%mm6, %%mm2 \n\t"
- "paddsw %%mm5, %%mm3 \n\t"
- "packuswb %%mm1, %%mm0 \n\t"
- "packuswb %%mm3, %%mm2 \n\t"
- "movq %%mm0, %0 \n\t"
- "movq %%mm2, %1 \n\t"
- : "+m" (*pix), "+m" (*(pix + line_size))
- : "r" (p)
- : "memory");
- pix += line_size * 2;
- p += 16;
- } while (--i);
-}
-
-#endif /* HAVE_INLINE_ASM */
diff --git a/libavcodec/x86/imdct36.asm b/libavcodec/x86/imdct36.asm
index 633fcd9d59..ce30b42103 100644
--- a/libavcodec/x86/imdct36.asm
+++ b/libavcodec/x86/imdct36.asm
@@ -2,20 +2,20 @@
;* 36 point SSE-optimized IMDCT transform
;* Copyright (c) 2011 Vitor Sessak
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -50,7 +50,7 @@ ps_cosh_sse3: dd 1.0, -0.50190991877167369479, 1.0, -5.73685662283492756461
dd 1.0, -0.51763809020504152469, 1.0, -1.93185165257813657349
dd 1.0, -0.55168895948124587824, -1.0, 1.18310079157624925896
dd 1.0, -0.61038729438072803416, -1.0, 0.87172339781054900991
- dd 1.0, 0.70710678118654752439, 0.0, 0.0
+ dd 1.0, -0.70710678118654752439, 0.0, 0.0
costabs: times 4 dd 0.98480773
times 4 dd 0.93969262
@@ -129,6 +129,19 @@ SECTION_TEXT
%endif
%endmacro
+%macro BUTTERF2 3
+%if cpuflag(sse3)
+ mulps %1, %1, [ps_cosh_sse3 + %3]
+ PSHUFD %2, %1, 0xe1
+ addsubps %1, %1, %2
+%else
+ mulps %1, [ps_cosh + %3]
+ PSHUFD %2, %1, 0xe1
+ xorps %1, [ps_p1m1p1m1]
+ addps %1, %2
+%endif
+%endmacro
+
%macro STORE 4
movhlps %2, %1
movss [%3 ], %1
@@ -279,11 +292,7 @@ cglobal imdct36_float, 4,4,9, out, buf, in, win
BUTTERF m7, m2, 16
BUTTERF m3, m6, 32
BUTTERF m4, m1, 48
-
- mulps m5, m5, [ps_cosh + 64]
- PSHUFD m1, m5, 0xe1
- xorps m5, m5, [ps_p1m1p1m1]
- addps m5, m5, m1
+ BUTTERF2 m5, m1, 64
; permutates:
; m0 0 1 2 3 => 2 6 10 14 m1
@@ -358,8 +367,10 @@ cglobal imdct36_float, 4,4,9, out, buf, in, win
RET
%endmacro
+%if ARCH_X86_32
INIT_XMM sse
DEFINE_IMDCT
+%endif
INIT_XMM sse2
DEFINE_IMDCT
@@ -370,8 +381,10 @@ DEFINE_IMDCT
INIT_XMM ssse3
DEFINE_IMDCT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEFINE_IMDCT
+%endif
INIT_XMM sse
@@ -716,5 +729,7 @@ cglobal four_imdct36_float, 5,5,16, out, buf, in, win, tmp
INIT_XMM sse
DEFINE_FOUR_IMDCT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
DEFINE_FOUR_IMDCT
+%endif
diff --git a/libavcodec/x86/inline_asm.h b/libavcodec/x86/inline_asm.h
index e4affabc87..3e65a76973 100644
--- a/libavcodec/x86/inline_asm.h
+++ b/libavcodec/x86/inline_asm.h
@@ -1,20 +1,20 @@
/*
* inline assembly helper macros
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,7 +37,7 @@
"paddb %%"#regd", %%"#regd" \n\t" ::)
#ifndef PIC
-#define MOVQ_WTWO(regd) __asm__ volatile ("movq %0, %%"#regd" \n\t" :: "m"(ff_wtwo))
+#define MOVQ_WTWO(regd) __asm__ volatile ("movq %0, %%"#regd" \n\t" :: "m"(ff_pw_2))
#else
// for shared library it's better to use this way for accessing constants
// pcmpeqd -> -1
diff --git a/libavcodec/x86/lossless_audiodsp.asm b/libavcodec/x86/lossless_audiodsp.asm
new file mode 100644
index 0000000000..64b769f7d4
--- /dev/null
+++ b/libavcodec/x86/lossless_audiodsp.asm
@@ -0,0 +1,157 @@
+;******************************************************************************
+;* Copyright (c) 2008 Loren Merritt
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_TEXT
+
+%macro SCALARPRODUCT 0
+; int ff_scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3,
+; int order, int mul)
+cglobal scalarproduct_and_madd_int16, 4,4,8, v1, v2, v3, order, mul
+ shl orderq, 1
+ movd m7, mulm
+%if mmsize == 16
+ pshuflw m7, m7, 0
+ punpcklqdq m7, m7
+%else
+ pshufw m7, m7, 0
+%endif
+ pxor m6, m6
+ add v1q, orderq
+ add v2q, orderq
+ add v3q, orderq
+ neg orderq
+.loop:
+ movu m0, [v2q + orderq]
+ movu m1, [v2q + orderq + mmsize]
+ mova m4, [v1q + orderq]
+ mova m5, [v1q + orderq + mmsize]
+ movu m2, [v3q + orderq]
+ movu m3, [v3q + orderq + mmsize]
+ pmaddwd m0, m4
+ pmaddwd m1, m5
+ pmullw m2, m7
+ pmullw m3, m7
+ paddd m6, m0
+ paddd m6, m1
+ paddw m2, m4
+ paddw m3, m5
+ mova [v1q + orderq], m2
+ mova [v1q + orderq + mmsize], m3
+ add orderq, mmsize*2
+ jl .loop
+ HADDD m6, m0
+ movd eax, m6
+ RET
+%endmacro
+
+INIT_MMX mmxext
+SCALARPRODUCT
+INIT_XMM sse2
+SCALARPRODUCT
+
+%macro SCALARPRODUCT_LOOP 1
+align 16
+.loop%1:
+ sub orderq, mmsize*2
+%if %1
+ mova m1, m4
+ mova m4, [v2q + orderq]
+ mova m0, [v2q + orderq + mmsize]
+ palignr m1, m0, %1
+ palignr m0, m4, %1
+ mova m3, m5
+ mova m5, [v3q + orderq]
+ mova m2, [v3q + orderq + mmsize]
+ palignr m3, m2, %1
+ palignr m2, m5, %1
+%else
+ mova m0, [v2q + orderq]
+ mova m1, [v2q + orderq + mmsize]
+ mova m2, [v3q + orderq]
+ mova m3, [v3q + orderq + mmsize]
+%endif
+ %define t0 [v1q + orderq]
+ %define t1 [v1q + orderq + mmsize]
+%if ARCH_X86_64
+ mova m8, t0
+ mova m9, t1
+ %define t0 m8
+ %define t1 m9
+%endif
+ pmaddwd m0, t0
+ pmaddwd m1, t1
+ pmullw m2, m7
+ pmullw m3, m7
+ paddw m2, t0
+ paddw m3, t1
+ paddd m6, m0
+ paddd m6, m1
+ mova [v1q + orderq], m2
+ mova [v1q + orderq + mmsize], m3
+ jg .loop%1
+%if %1
+ jmp .end
+%endif
+%endmacro
+
+; int ff_scalarproduct_and_madd_int16(int16_t *v1, int16_t *v2, int16_t *v3,
+; int order, int mul)
+INIT_XMM ssse3
+cglobal scalarproduct_and_madd_int16, 4,5,10, v1, v2, v3, order, mul
+ shl orderq, 1
+ movd m7, mulm
+ pshuflw m7, m7, 0
+ punpcklqdq m7, m7
+ pxor m6, m6
+ mov r4d, v2d
+ and r4d, 15
+ and v2q, ~15
+ and v3q, ~15
+ mova m4, [v2q + orderq]
+ mova m5, [v3q + orderq]
+ ; linear is faster than branch tree or jump table, because the branches taken are cyclic (i.e. predictable)
+ cmp r4d, 0
+ je .loop0
+ cmp r4d, 2
+ je .loop2
+ cmp r4d, 4
+ je .loop4
+ cmp r4d, 6
+ je .loop6
+ cmp r4d, 8
+ je .loop8
+ cmp r4d, 10
+ je .loop10
+ cmp r4d, 12
+ je .loop12
+SCALARPRODUCT_LOOP 14
+SCALARPRODUCT_LOOP 12
+SCALARPRODUCT_LOOP 10
+SCALARPRODUCT_LOOP 8
+SCALARPRODUCT_LOOP 6
+SCALARPRODUCT_LOOP 4
+SCALARPRODUCT_LOOP 2
+SCALARPRODUCT_LOOP 0
+.end:
+ HADDD m6, m0
+ movd eax, m6
+ RET
diff --git a/libavcodec/x86/lossless_audiodsp_init.c b/libavcodec/x86/lossless_audiodsp_init.c
new file mode 100644
index 0000000000..197173caf4
--- /dev/null
+++ b/libavcodec/x86/lossless_audiodsp_init.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/x86/cpu.h"
+#include "libavcodec/lossless_audiodsp.h"
+
+int32_t ff_scalarproduct_and_madd_int16_mmxext(int16_t *v1, const int16_t *v2,
+ const int16_t *v3,
+ int order, int mul);
+int32_t ff_scalarproduct_and_madd_int16_sse2(int16_t *v1, const int16_t *v2,
+ const int16_t *v3,
+ int order, int mul);
+int32_t ff_scalarproduct_and_madd_int16_ssse3(int16_t *v1, const int16_t *v2,
+ const int16_t *v3,
+ int order, int mul);
+
+av_cold void ff_llauddsp_init_x86(LLAudDSPContext *c)
+{
+#if HAVE_YASM
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMXEXT(cpu_flags))
+ c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_mmxext;
+
+ if (EXTERNAL_SSE2(cpu_flags))
+ c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_sse2;
+
+ if (EXTERNAL_SSSE3(cpu_flags) &&
+ !(cpu_flags & (AV_CPU_FLAG_SSE42 | AV_CPU_FLAG_3DNOW))) // cachesplit
+ c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_ssse3;
+#endif
+}
diff --git a/libavcodec/x86/lossless_videodsp.asm b/libavcodec/x86/lossless_videodsp.asm
new file mode 100644
index 0000000000..e6c23e7985
--- /dev/null
+++ b/libavcodec/x86/lossless_videodsp.asm
@@ -0,0 +1,294 @@
+;******************************************************************************
+;* SIMD lossless video DSP utils
+;* Copyright (c) 2008 Loren Merritt
+;* Copyright (c) 2014 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 "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pb_ef: times 8 db 14,15
+pb_67: times 8 db 6, 7
+pb_zzzz2323zzzzabab: db -1,-1,-1,-1, 2, 3, 2, 3,-1,-1,-1,-1,10,11,10,11
+pb_zzzzzzzz67676767: db -1,-1,-1,-1,-1,-1,-1,-1, 6, 7, 6, 7, 6, 7, 6, 7
+
+SECTION_TEXT
+
+%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub
+ movd m4, maskd
+ SPLATW m4, m4
+ add wd, wd
+ test wq, 2*mmsize - 1
+ jz %%.tomainloop
+ push tmpq
+%%.wordloop:
+ sub wq, 2
+%ifidn %2, add
+ mov tmpw, [srcq+wq]
+ add tmpw, [dstq+wq]
+%else
+ mov tmpw, [src1q+wq]
+ sub tmpw, [src2q+wq]
+%endif
+ and tmpw, maskw
+ mov [dstq+wq], tmpw
+ test wq, 2*mmsize - 1
+ jnz %%.wordloop
+ pop tmpq
+%%.tomainloop:
+%ifidn %2, add
+ add srcq, wq
+%else
+ add src1q, wq
+ add src2q, wq
+%endif
+ add dstq, wq
+ neg wq
+ jz %%.end
+%%.loop:
+%ifidn %2, add
+ mov%1 m0, [srcq+wq]
+ mov%1 m1, [dstq+wq]
+ mov%1 m2, [srcq+wq+mmsize]
+ mov%1 m3, [dstq+wq+mmsize]
+%else
+ mov%1 m0, [src1q+wq]
+ mov%1 m1, [src2q+wq]
+ mov%1 m2, [src1q+wq+mmsize]
+ mov%1 m3, [src2q+wq+mmsize]
+%endif
+ p%2w m0, m1
+ p%2w m2, m3
+ pand m0, m4
+ pand m2, m4
+ mov%1 [dstq+wq] , m0
+ mov%1 [dstq+wq+mmsize], m2
+ add wq, 2*mmsize
+ jl %%.loop
+%%.end:
+ RET
+%endmacro
+
+INIT_MMX mmx
+cglobal add_int16, 4,4,5, dst, src, mask, w, tmp
+ INT16_LOOP a, add
+
+INIT_XMM sse2
+cglobal add_int16, 4,4,5, dst, src, mask, w, tmp
+ test srcq, mmsize-1
+ jnz .unaligned
+ test dstq, mmsize-1
+ jnz .unaligned
+ INT16_LOOP a, add
+.unaligned:
+ INT16_LOOP u, add
+
+INIT_MMX mmx
+cglobal diff_int16, 5,5,5, dst, src1, src2, mask, w, tmp
+ INT16_LOOP a, sub
+
+INIT_XMM sse2
+cglobal diff_int16, 5,5,5, dst, src1, src2, mask, w, tmp
+ test src1q, mmsize-1
+ jnz .unaligned
+ test src2q, mmsize-1
+ jnz .unaligned
+ test dstq, mmsize-1
+ jnz .unaligned
+ INT16_LOOP a, sub
+.unaligned:
+ INT16_LOOP u, sub
+
+
+%macro ADD_HFYU_LEFT_LOOP_INT16 2 ; %1 = dst alignment (a/u), %2 = src alignment (a/u)
+ add wd, wd
+ add srcq, wq
+ add dstq, wq
+ neg wq
+%%.loop:
+ mov%2 m1, [srcq+wq]
+ mova m2, m1
+ pslld m1, 16
+ paddw m1, m2
+ mova m2, m1
+
+ pshufb m1, m3
+ paddw m1, m2
+ pshufb m0, m5
+%if mmsize == 16
+ mova m2, m1
+ pshufb m1, m4
+ paddw m1, m2
+%endif
+ paddw m0, m1
+ pand m0, m7
+%ifidn %1, a
+ mova [dstq+wq], m0
+%else
+ movq [dstq+wq], m0
+ movhps [dstq+wq+8], m0
+%endif
+ add wq, mmsize
+ jl %%.loop
+ mov eax, mmsize-1
+ sub eax, wd
+ mov wd, eax
+ shl wd, 8
+ lea eax, [wd+eax-1]
+ movd m1, eax
+ pshufb m0, m1
+ movd eax, m0
+ RET
+%endmacro
+
+; int add_hfyu_left_pred_int16(uint16_t *dst, const uint16_t *src, unsigned mask, int w, int left)
+INIT_MMX ssse3
+cglobal add_hfyu_left_pred_int16, 4,4,8, dst, src, mask, w, left
+.skip_prologue:
+ mova m5, [pb_67]
+ mova m3, [pb_zzzz2323zzzzabab]
+ movd m0, leftm
+ psllq m0, 48
+ movd m7, maskm
+ SPLATW m7 ,m7
+ ADD_HFYU_LEFT_LOOP_INT16 a, a
+
+INIT_XMM sse4
+cglobal add_hfyu_left_pred_int16, 4,4,8, dst, src, mask, w, left
+ mova m5, [pb_ef]
+ mova m4, [pb_zzzzzzzz67676767]
+ mova m3, [pb_zzzz2323zzzzabab]
+ movd m0, leftm
+ pslldq m0, 14
+ movd m7, maskm
+ SPLATW m7 ,m7
+ test srcq, 15
+ jnz .src_unaligned
+ test dstq, 15
+ jnz .dst_unaligned
+ ADD_HFYU_LEFT_LOOP_INT16 a, a
+.dst_unaligned:
+ ADD_HFYU_LEFT_LOOP_INT16 u, a
+.src_unaligned:
+ ADD_HFYU_LEFT_LOOP_INT16 u, u
+
+; void add_hfyu_median_prediction_mmxext(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int mask, int w, int *left, int *left_top)
+INIT_MMX mmxext
+cglobal add_hfyu_median_pred_int16, 7,7,0, dst, top, diff, mask, w, left, left_top
+ add wd, wd
+ movd mm6, maskd
+ SPLATW mm6, mm6
+ movq mm0, [topq]
+ movq mm2, mm0
+ movd mm4, [left_topq]
+ psllq mm2, 16
+ movq mm1, mm0
+ por mm4, mm2
+ movd mm3, [leftq]
+ psubw mm0, mm4 ; t-tl
+ add dstq, wq
+ add topq, wq
+ add diffq, wq
+ neg wq
+ jmp .skip
+.loop:
+ movq mm4, [topq+wq]
+ movq mm0, mm4
+ psllq mm4, 16
+ por mm4, mm1
+ movq mm1, mm0 ; t
+ psubw mm0, mm4 ; t-tl
+.skip:
+ movq mm2, [diffq+wq]
+%assign i 0
+%rep 4
+ movq mm4, mm0
+ paddw mm4, mm3 ; t-tl+l
+ pand mm4, mm6
+ movq mm5, mm3
+ pmaxsw mm3, mm1
+ pminsw mm5, mm1
+ pminsw mm3, mm4
+ pmaxsw mm3, mm5 ; median
+ paddw mm3, mm2 ; +residual
+ pand mm3, mm6
+%if i==0
+ movq mm7, mm3
+ psllq mm7, 48
+%else
+ movq mm4, mm3
+ psrlq mm7, 16
+ psllq mm4, 48
+ por mm7, mm4
+%endif
+%if i<3
+ psrlq mm0, 16
+ psrlq mm1, 16
+ psrlq mm2, 16
+%endif
+%assign i i+1
+%endrep
+ movq [dstq+wq], mm7
+ add wq, 8
+ jl .loop
+ movzx r2d, word [dstq-2]
+ mov [leftq], r2d
+ movzx r2d, word [topq-2]
+ mov [left_topq], r2d
+ RET
+
+cglobal sub_hfyu_median_pred_int16, 7,7,0, dst, src1, src2, mask, w, left, left_top
+ add wd, wd
+ movd mm7, maskd
+ SPLATW mm7, mm7
+ movq mm0, [src1q]
+ movq mm2, [src2q]
+ psllq mm0, 16
+ psllq mm2, 16
+ movd mm6, [left_topq]
+ por mm0, mm6
+ movd mm6, [leftq]
+ por mm2, mm6
+ xor maskq, maskq
+.loop:
+ movq mm1, [src1q + maskq]
+ movq mm3, [src2q + maskq]
+ movq mm4, mm2
+ psubw mm2, mm0
+ paddw mm2, mm1
+ pand mm2, mm7
+ movq mm5, mm4
+ pmaxsw mm4, mm1
+ pminsw mm1, mm5
+ pminsw mm4, mm2
+ pmaxsw mm4, mm1
+ psubw mm3, mm4
+ pand mm3, mm7
+ movq [dstq + maskq], mm3
+ add maskq, 8
+ movq mm0, [src1q + maskq - 2]
+ movq mm2, [src2q + maskq - 2]
+ cmp maskq, wq
+ jb .loop
+ movzx maskd, word [src1q + wq - 2]
+ mov [left_topq], maskd
+ movzx maskd, word [src2q + wq - 2]
+ mov [leftq], maskd
+ RET
diff --git a/libavcodec/x86/lossless_videodsp_init.c b/libavcodec/x86/lossless_videodsp_init.c
new file mode 100644
index 0000000000..6589024a1a
--- /dev/null
+++ b/libavcodec/x86/lossless_videodsp_init.c
@@ -0,0 +1,62 @@
+/*
+ * Lossless video DSP utils
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "../lossless_videodsp.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/x86/cpu.h"
+
+void ff_add_int16_mmx(uint16_t *dst, const uint16_t *src, unsigned mask, int w);
+void ff_add_int16_sse2(uint16_t *dst, const uint16_t *src, unsigned mask, int w);
+void ff_diff_int16_mmx (uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w);
+void ff_diff_int16_sse2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w);
+int ff_add_hfyu_left_pred_int16_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, int w, unsigned acc);
+int ff_add_hfyu_left_pred_int16_sse4(uint16_t *dst, const uint16_t *src, unsigned mask, int w, unsigned acc);
+void ff_add_hfyu_median_pred_int16_mmxext(uint16_t *dst, const uint16_t *top, const uint16_t *diff, unsigned mask, int w, int *left, int *left_top);
+void ff_sub_hfyu_median_pred_int16_mmxext(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w, int *left, int *left_top);
+
+
+void ff_llviddsp_init_x86(LLVidDSPContext *c, AVCodecContext *avctx)
+{
+ int cpu_flags = av_get_cpu_flags();
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+
+ if (EXTERNAL_MMX(cpu_flags)) {
+ c->add_int16 = ff_add_int16_mmx;
+ c->diff_int16 = ff_diff_int16_mmx;
+ }
+
+ if (EXTERNAL_MMXEXT(cpu_flags) && pix_desc->comp[0].depth_minus1<15) {
+ c->add_hfyu_median_pred_int16 = ff_add_hfyu_median_pred_int16_mmxext;
+ c->sub_hfyu_median_pred_int16 = ff_sub_hfyu_median_pred_int16_mmxext;
+ }
+
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->add_int16 = ff_add_int16_sse2;
+ c->diff_int16 = ff_diff_int16_sse2;
+ }
+
+ if (EXTERNAL_SSSE3(cpu_flags)) {
+ c->add_hfyu_left_pred_int16 = ff_add_hfyu_left_pred_int16_ssse3;
+ }
+
+ if (EXTERNAL_SSE4(cpu_flags)) {
+ c->add_hfyu_left_pred_int16 = ff_add_hfyu_left_pred_int16_sse4;
+ }
+}
diff --git a/libavcodec/x86/lpc.c b/libavcodec/x86/lpc.c
index ea5d2eab56..3a9493f728 100644
--- a/libavcodec/x86/lpc.c
+++ b/libavcodec/x86/lpc.c
@@ -2,26 +2,25 @@
* SIMD-optimized LPC functions
* Copyright (c) 2007 Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/internal.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
@@ -73,6 +72,7 @@ static void lpc_apply_welch_window_sse2(const int32_t *data, int len,
"3: \n\t"
:"+&r"(i), "+&r"(j)
:"r"(w_data+n2), "r"(data+n2), "m"(c), "r"(len)
+ NAMED_CONSTRAINTS_ARRAY_ADD(pd_1,pd_2)
XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3",
"%xmm5", "%xmm6", "%xmm7")
);
@@ -117,6 +117,7 @@ static void lpc_compute_autocorr_sse2(const double *data, int len, int lag,
"movsd %%xmm2, 16(%1) \n\t"
:"+&r"(i)
:"r"(autoc+j), "r"(data+len), "r"(data+len-j)
+ NAMED_CONSTRAINTS_ARRAY_ADD(pd_1)
:"memory"
);
} else {
@@ -140,6 +141,7 @@ static void lpc_compute_autocorr_sse2(const double *data, int len, int lag,
"movsd %%xmm1, %2 \n\t"
:"+&r"(i), "=m"(autoc[j]), "=m"(autoc[j+1])
:"r"(data+len), "r"(data+len-j)
+ NAMED_CONSTRAINTS_ARRAY_ADD(pd_1)
);
}
}
@@ -152,7 +154,7 @@ av_cold void ff_lpc_init_x86(LPCContext *c)
#if HAVE_SSE2_INLINE
int cpu_flags = av_get_cpu_flags();
- if (INLINE_SSE2(cpu_flags) && (cpu_flags & AV_CPU_FLAG_SSE2SLOW)) {
+ if (HAVE_SSE2_INLINE && cpu_flags & (AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_SSE2SLOW)) {
c->lpc_apply_welch_window = lpc_apply_welch_window_sse2;
c->lpc_compute_autocorr = lpc_compute_autocorr_sse2;
}
diff --git a/libavcodec/x86/mathops.h b/libavcodec/x86/mathops.h
index 2c04d9d1bd..6298f5ed19 100644
--- a/libavcodec/x86/mathops.h
+++ b/libavcodec/x86/mathops.h
@@ -2,20 +2,20 @@
* simple math operations
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -105,7 +105,7 @@ __asm__ volatile(\
#endif /* HAVE_I686 */
#define MASK_ABS(mask, level) \
- __asm__ ("cltd \n\t" \
+ __asm__ ("cdq \n\t" \
"xorl %1, %0 \n\t" \
"subl %1, %0 \n\t" \
: "+a"(level), "=&d"(mask))
diff --git a/libavcodec/x86/me_cmp.asm b/libavcodec/x86/me_cmp.asm
index 1a87f37b39..0160dc348f 100644
--- a/libavcodec/x86/me_cmp.asm
+++ b/libavcodec/x86/me_cmp.asm
@@ -4,25 +4,30 @@
;* Copyright (c) 2000, 2001 Fabrice Bellard
;* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;*****************************************************************************
%include "libavutil/x86/x86util.asm"
+SECTION_RODATA
+
+cextern pb_1
+cextern pb_80
+
SECTION .text
%macro DIFF_PIXELS_1 4
@@ -210,7 +215,7 @@ hadamard8_16_wrapper %1, 3
%elif cpuflag(mmx)
ALIGN 16
; int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1,
-; uint8_t *src2, int stride, int h)
+; uint8_t *src2, ptrdiff_t stride, int h)
; r0 = void *s = unused, int h = unused (always 8)
; note how r1, r2 and r3 are not clobbered in this function, so 16x16
; can simply call this 2x2x (and that's why we access rsp+gprsize
@@ -274,19 +279,27 @@ INIT_XMM ssse3
%define ABS_SUM_8x8 ABS_SUM_8x8_64
HADAMARD8_DIFF 9
-INIT_XMM sse2
-; int ff_sse16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
-; int line_size, int h);
-cglobal sse16, 5, 5, 8
- shr r4d, 1
+; int ff_sse*_*(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+; ptrdiff_t line_size, int h)
+
+%macro SUM_SQUARED_ERRORS 1
+cglobal sse%1, 5,5,8, v, pix1, pix2, lsize, h
+%if %1 == mmsize
+ shr hd, 1
+%endif
pxor m0, m0 ; mm0 = 0
pxor m7, m7 ; mm7 holds the sum
.next2lines: ; FIXME why are these unaligned movs? pix1[] is aligned
- movu m1, [r1 ] ; mm1 = pix1[0][0-15]
- movu m2, [r2 ] ; mm2 = pix2[0][0-15]
- movu m3, [r1+r3] ; mm3 = pix1[1][0-15]
- movu m4, [r2+r3] ; mm4 = pix2[1][0-15]
+ movu m1, [pix1q] ; m1 = pix1[0][0-15], [0-7] for mmx
+ movu m2, [pix2q] ; m2 = pix2[0][0-15], [0-7] for mmx
+%if %1 == mmsize
+ movu m3, [pix1q+lsizeq] ; m3 = pix1[1][0-15], [0-7] for mmx
+ movu m4, [pix2q+lsizeq] ; m4 = pix2[1][0-15], [0-7] for mmx
+%else ; %1 / 2 == mmsize; mmx only
+ mova m3, [pix1q+8] ; m3 = pix1[0][8-15]
+ mova m4, [pix2q+8] ; m4 = pix2[0][8-15]
+%endif
; todo: mm1-mm2, mm3-mm4
; algo: subtract mm1 from mm2 with saturation and vice versa
@@ -315,22 +328,607 @@ cglobal sse16, 5, 5, 8
pmaddwd m1, m1
pmaddwd m3, m3
- lea r1, [r1+r3*2] ; pix1 += 2*line_size
- lea r2, [r2+r3*2] ; pix2 += 2*line_size
-
paddd m1, m2
paddd m3, m4
paddd m7, m1
paddd m7, m3
- dec r4
+%if %1 == mmsize
+ lea pix1q, [pix1q + 2*lsizeq]
+ lea pix2q, [pix2q + 2*lsizeq]
+%else
+ add pix1q, lsizeq
+ add pix2q, lsizeq
+%endif
+ dec hd
jnz .next2lines
- mova m1, m7
- psrldq m7, 8 ; shift hi qword to lo
- paddd m7, m1
- mova m1, m7
- psrldq m7, 4 ; shift hi dword to lo
- paddd m7, m1
+ HADDD m7, m1
movd eax, m7 ; return value
RET
+%endmacro
+
+INIT_MMX mmx
+SUM_SQUARED_ERRORS 8
+
+INIT_MMX mmx
+SUM_SQUARED_ERRORS 16
+
+INIT_XMM sse2
+SUM_SQUARED_ERRORS 16
+
+;-----------------------------------------------
+;int ff_sum_abs_dctelem(int16_t *block)
+;-----------------------------------------------
+; %1 = number of xmm registers used
+; %2 = number of inline loops
+
+%macro SUM_ABS_DCTELEM 2
+cglobal sum_abs_dctelem, 1, 1, %1, block
+ pxor m0, m0
+ pxor m1, m1
+%assign %%i 0
+%rep %2
+ mova m2, [blockq+mmsize*(0+%%i)]
+ mova m3, [blockq+mmsize*(1+%%i)]
+ mova m4, [blockq+mmsize*(2+%%i)]
+ mova m5, [blockq+mmsize*(3+%%i)]
+ ABS1_SUM m2, m6, m0
+ ABS1_SUM m3, m6, m1
+ ABS1_SUM m4, m6, m0
+ ABS1_SUM m5, m6, m1
+%assign %%i %%i+4
+%endrep
+ paddusw m0, m1
+ HSUM m0, m1, eax
+ and eax, 0xFFFF
+ RET
+%endmacro
+
+INIT_MMX mmx
+SUM_ABS_DCTELEM 0, 4
+INIT_MMX mmxext
+SUM_ABS_DCTELEM 0, 4
+INIT_XMM sse2
+SUM_ABS_DCTELEM 7, 2
+INIT_XMM ssse3
+SUM_ABS_DCTELEM 6, 2
+
+;------------------------------------------------------------------------------
+; int ff_hf_noise*_mmx(uint8_t *pix1, ptrdiff_t lsize, int h)
+;------------------------------------------------------------------------------
+; %1 = 8/16. %2-5=m#
+%macro HF_NOISE_PART1 5
+ mova m%2, [pix1q]
+%if %1 == 8
+ mova m%3, m%2
+ psllq m%2, 8
+ psrlq m%3, 8
+ psrlq m%2, 8
+%else
+ mova m%3, [pix1q+1]
+%endif
+ mova m%4, m%2
+ mova m%5, m%3
+ punpcklbw m%2, m7
+ punpcklbw m%3, m7
+ punpckhbw m%4, m7
+ punpckhbw m%5, m7
+ psubw m%2, m%3
+ psubw m%4, m%5
+%endmacro
+
+; %1-2 = m#
+%macro HF_NOISE_PART2 4
+ psubw m%1, m%3
+ psubw m%2, m%4
+ pxor m3, m3
+ pxor m1, m1
+ pcmpgtw m3, m%1
+ pcmpgtw m1, m%2
+ pxor m%1, m3
+ pxor m%2, m1
+ psubw m%1, m3
+ psubw m%2, m1
+ paddw m%2, m%1
+ paddw m6, m%2
+%endmacro
+
+; %1 = 8/16
+%macro HF_NOISE 1
+cglobal hf_noise%1, 3,3,0, pix1, lsize, h
+ sub hd, 2
+ pxor m7, m7
+ pxor m6, m6
+ HF_NOISE_PART1 %1, 0, 1, 2, 3
+ add pix1q, lsizeq
+ HF_NOISE_PART1 %1, 4, 1, 5, 3
+ HF_NOISE_PART2 0, 2, 4, 5
+ add pix1q, lsizeq
+.loop:
+ HF_NOISE_PART1 %1, 0, 1, 2, 3
+ HF_NOISE_PART2 4, 5, 0, 2
+ add pix1q, lsizeq
+ HF_NOISE_PART1 %1, 4, 1, 5, 3
+ HF_NOISE_PART2 0, 2, 4, 5
+ add pix1q, lsizeq
+ sub hd, 2
+ jne .loop
+
+ mova m0, m6
+ punpcklwd m0, m7
+ punpckhwd m6, m7
+ paddd m6, m0
+ mova m0, m6
+ psrlq m6, 32
+ paddd m0, m6
+ movd eax, m0 ; eax = result of hf_noise8;
+ REP_RET ; return eax;
+%endmacro
+
+INIT_MMX mmx
+HF_NOISE 8
+HF_NOISE 16
+
+;---------------------------------------------------------------------------------------
+;int ff_sad_<opt>(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t stride, int h);
+;---------------------------------------------------------------------------------------
+;%1 = 8/16
+%macro SAD 1
+cglobal sad%1, 5, 5, 3, v, pix1, pix2, stride, h
+ movu m2, [pix2q]
+ movu m1, [pix2q+strideq]
+ psadbw m2, [pix1q]
+ psadbw m1, [pix1q+strideq]
+ paddw m2, m1
+%if %1 != mmsize
+ movu m0, [pix2q+8]
+ movu m1, [pix2q+strideq+8]
+ psadbw m0, [pix1q+8]
+ psadbw m1, [pix1q+strideq+8]
+ paddw m2, m0
+ paddw m2, m1
+%endif
+ sub hd, 2
+
+align 16
+.loop:
+ lea pix1q, [pix1q+strideq*2]
+ lea pix2q, [pix2q+strideq*2]
+ movu m0, [pix2q]
+ movu m1, [pix2q+strideq]
+ psadbw m0, [pix1q]
+ psadbw m1, [pix1q+strideq]
+ paddw m2, m0
+ paddw m2, m1
+%if %1 != mmsize
+ movu m0, [pix2q+8]
+ movu m1, [pix2q+strideq+8]
+ psadbw m0, [pix1q+8]
+ psadbw m1, [pix1q+strideq+8]
+ paddw m2, m0
+ paddw m2, m1
+%endif
+ sub hd, 2
+ jg .loop
+%if mmsize == 16
+ movhlps m0, m2
+ paddw m2, m0
+%endif
+ movd eax, m2
+ RET
+%endmacro
+
+INIT_MMX mmxext
+SAD 8
+SAD 16
+INIT_XMM sse2
+SAD 16
+
+;------------------------------------------------------------------------------------------
+;int ff_sad_x2_<opt>(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t stride, int h);
+;------------------------------------------------------------------------------------------
+;%1 = 8/16
+%macro SAD_X2 1
+cglobal sad%1_x2, 5, 5, 5, v, pix1, pix2, stride, h
+ movu m0, [pix2q]
+ movu m2, [pix2q+strideq]
+%if mmsize == 16
+ movu m3, [pix2q+1]
+ movu m4, [pix2q+strideq+1]
+ pavgb m0, m3
+ pavgb m2, m4
+%else
+ pavgb m0, [pix2q+1]
+ pavgb m2, [pix2q+strideq+1]
+%endif
+ psadbw m0, [pix1q]
+ psadbw m2, [pix1q+strideq]
+ paddw m0, m2
+%if %1 != mmsize
+ movu m1, [pix2q+8]
+ movu m2, [pix2q+strideq+8]
+ pavgb m1, [pix2q+9]
+ pavgb m2, [pix2q+strideq+9]
+ psadbw m1, [pix1q+8]
+ psadbw m2, [pix1q+strideq+8]
+ paddw m0, m1
+ paddw m0, m2
+%endif
+ sub hd, 2
+
+align 16
+.loop:
+ lea pix1q, [pix1q+2*strideq]
+ lea pix2q, [pix2q+2*strideq]
+ movu m1, [pix2q]
+ movu m2, [pix2q+strideq]
+%if mmsize == 16
+ movu m3, [pix2q+1]
+ movu m4, [pix2q+strideq+1]
+ pavgb m1, m3
+ pavgb m2, m4
+%else
+ pavgb m1, [pix2q+1]
+ pavgb m2, [pix2q+strideq+1]
+%endif
+ psadbw m1, [pix1q]
+ psadbw m2, [pix1q+strideq]
+ paddw m0, m1
+ paddw m0, m2
+%if %1 != mmsize
+ movu m1, [pix2q+8]
+ movu m2, [pix2q+strideq+8]
+ pavgb m1, [pix2q+9]
+ pavgb m2, [pix2q+strideq+9]
+ psadbw m1, [pix1q+8]
+ psadbw m2, [pix1q+strideq+8]
+ paddw m0, m1
+ paddw m0, m2
+%endif
+ sub hd, 2
+ jg .loop
+%if mmsize == 16
+ movhlps m1, m0
+ paddw m0, m1
+%endif
+ movd eax, m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+SAD_X2 8
+SAD_X2 16
+INIT_XMM sse2
+SAD_X2 16
+
+;------------------------------------------------------------------------------------------
+;int ff_sad_y2_<opt>(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t stride, int h);
+;------------------------------------------------------------------------------------------
+;%1 = 8/16
+%macro SAD_Y2 1
+cglobal sad%1_y2, 5, 5, 4, v, pix1, pix2, stride, h
+ movu m1, [pix2q]
+ movu m0, [pix2q+strideq]
+ movu m3, [pix2q+2*strideq]
+ pavgb m1, m0
+ pavgb m0, m3
+ psadbw m1, [pix1q]
+ psadbw m0, [pix1q+strideq]
+ paddw m0, m1
+ mova m1, m3
+%if %1 != mmsize
+ movu m4, [pix2q+8]
+ movu m5, [pix2q+strideq+8]
+ movu m6, [pix2q+2*strideq+8]
+ pavgb m4, m5
+ pavgb m5, m6
+ psadbw m4, [pix1q+8]
+ psadbw m5, [pix1q+strideq+8]
+ paddw m0, m4
+ paddw m0, m5
+ mova m4, m6
+%endif
+ add pix2q, strideq
+ sub hd, 2
+
+align 16
+.loop:
+ lea pix1q, [pix1q+2*strideq]
+ lea pix2q, [pix2q+2*strideq]
+ movu m2, [pix2q]
+ movu m3, [pix2q+strideq]
+ pavgb m1, m2
+ pavgb m2, m3
+ psadbw m1, [pix1q]
+ psadbw m2, [pix1q+strideq]
+ paddw m0, m1
+ paddw m0, m2
+ mova m1, m3
+%if %1 != mmsize
+ movu m5, [pix2q+8]
+ movu m6, [pix2q+strideq+8]
+ pavgb m4, m5
+ pavgb m5, m6
+ psadbw m4, [pix1q+8]
+ psadbw m5, [pix1q+strideq+8]
+ paddw m0, m4
+ paddw m0, m5
+ mova m4, m6
+%endif
+ sub hd, 2
+ jg .loop
+%if mmsize == 16
+ movhlps m1, m0
+ paddw m0, m1
+%endif
+ movd eax, m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+SAD_Y2 8
+SAD_Y2 16
+INIT_XMM sse2
+SAD_Y2 16
+
+;-------------------------------------------------------------------------------------------
+;int ff_sad_approx_xy2_<opt>(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, ptrdiff_t stride, int h);
+;-------------------------------------------------------------------------------------------
+;%1 = 8/16
+%macro SAD_APPROX_XY2 1
+cglobal sad%1_approx_xy2, 5, 5, 7, v, pix1, pix2, stride, h
+ mova m4, [pb_1]
+ movu m1, [pix2q]
+ movu m0, [pix2q+strideq]
+ movu m3, [pix2q+2*strideq]
+%if mmsize == 16
+ movu m5, [pix2q+1]
+ movu m6, [pix2q+strideq+1]
+ movu m2, [pix2q+2*strideq+1]
+ pavgb m1, m5
+ pavgb m0, m6
+ pavgb m3, m2
+%else
+ pavgb m1, [pix2q+1]
+ pavgb m0, [pix2q+strideq+1]
+ pavgb m3, [pix2q+2*strideq+1]
+%endif
+ psubusb m0, m4
+ pavgb m1, m0
+ pavgb m0, m3
+ psadbw m1, [pix1q]
+ psadbw m0, [pix1q+strideq]
+ paddw m0, m1
+ mova m1, m3
+%if %1 != mmsize
+ movu m5, [pix2q+8]
+ movu m6, [pix2q+strideq+8]
+ movu m7, [pix2q+2*strideq+8]
+ pavgb m5, [pix2q+1+8]
+ pavgb m6, [pix2q+strideq+1+8]
+ pavgb m7, [pix2q+2*strideq+1+8]
+ psubusb m6, m4
+ pavgb m5, m6
+ pavgb m6, m7
+ psadbw m5, [pix1q+8]
+ psadbw m6, [pix1q+strideq+8]
+ paddw m0, m5
+ paddw m0, m6
+ mova m5, m7
+%endif
+ add pix2q, strideq
+ sub hd, 2
+
+align 16
+.loop:
+ lea pix1q, [pix1q+2*strideq]
+ lea pix2q, [pix2q+2*strideq]
+ movu m2, [pix2q]
+ movu m3, [pix2q+strideq]
+%if mmsize == 16
+ movu m5, [pix2q+1]
+ movu m6, [pix2q+strideq+1]
+ pavgb m2, m5
+ pavgb m3, m6
+%else
+ pavgb m2, [pix2q+1]
+ pavgb m3, [pix2q+strideq+1]
+%endif
+ psubusb m2, m4
+ pavgb m1, m2
+ pavgb m2, m3
+ psadbw m1, [pix1q]
+ psadbw m2, [pix1q+strideq]
+ paddw m0, m1
+ paddw m0, m2
+ mova m1, m3
+%if %1 != mmsize
+ movu m6, [pix2q+8]
+ movu m7, [pix2q+strideq+8]
+ pavgb m6, [pix2q+8+1]
+ pavgb m7, [pix2q+strideq+8+1]
+ psubusb m6, m4
+ pavgb m5, m6
+ pavgb m6, m7
+ psadbw m5, [pix1q+8]
+ psadbw m6, [pix1q+strideq+8]
+ paddw m0, m5
+ paddw m0, m6
+ mova m5, m7
+%endif
+ sub hd, 2
+ jg .loop
+%if mmsize == 16
+ movhlps m1, m0
+ paddw m0, m1
+%endif
+ movd eax, m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+SAD_APPROX_XY2 8
+SAD_APPROX_XY2 16
+INIT_XMM sse2
+SAD_APPROX_XY2 16
+
+;--------------------------------------------------------------------
+;int ff_vsad_intra(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+; ptrdiff_t line_size, int h);
+;--------------------------------------------------------------------
+; %1 = 8/16
+%macro VSAD_INTRA 1
+cglobal vsad_intra%1, 5, 5, 3, v, pix1, pix2, lsize, h
+ mova m0, [pix1q]
+%if %1 == mmsize
+ mova m2, [pix1q+lsizeq]
+ psadbw m0, m2
+%else
+ mova m2, [pix1q+lsizeq]
+ mova m3, [pix1q+8]
+ mova m4, [pix1q+lsizeq+8]
+ psadbw m0, m2
+ psadbw m3, m4
+ paddw m0, m3
+%endif
+ sub hd, 2
+
+.loop
+ lea pix1q, [pix1q + 2*lsizeq]
+%if %1 == mmsize
+ mova m1, [pix1q]
+ psadbw m2, m1
+ paddw m0, m2
+ mova m2, [pix1q+lsizeq]
+ psadbw m1, m2
+ paddw m0, m1
+%else
+ mova m1, [pix1q]
+ mova m3, [pix1q+8]
+ psadbw m2, m1
+ psadbw m4, m3
+ paddw m0, m2
+ paddw m0, m4
+ mova m2, [pix1q+lsizeq]
+ mova m4, [pix1q+lsizeq+8]
+ psadbw m1, m2
+ psadbw m3, m4
+ paddw m0, m1
+ paddw m0, m3
+%endif
+ sub hd, 2
+ jg .loop
+
+%if mmsize == 16
+ pshufd m1, m0, 0xe
+ paddd m0, m1
+%endif
+ movd eax, m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+VSAD_INTRA 8
+VSAD_INTRA 16
+INIT_XMM sse2
+VSAD_INTRA 16
+
+;---------------------------------------------------------------------
+;int ff_vsad_approx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+; ptrdiff_t line_size, int h);
+;---------------------------------------------------------------------
+; %1 = 8/16
+%macro VSAD_APPROX 1
+cglobal vsad%1_approx, 5, 5, 5, v, pix1, pix2, lsize, h
+ mova m1, [pb_80]
+ mova m0, [pix1q]
+%if %1 == mmsize ; vsad8_mmxext, vsad16_sse2
+ mova m4, [pix1q+lsizeq]
+%if mmsize == 16
+ movu m3, [pix2q]
+ movu m2, [pix2q+lsizeq]
+ psubb m0, m3
+ psubb m4, m2
+%else
+ psubb m0, [pix2q]
+ psubb m4, [pix2q+lsizeq]
+%endif
+ pxor m0, m1
+ pxor m4, m1
+ psadbw m0, m4
+%else ; vsad16_mmxext
+ mova m3, [pix1q+8]
+ psubb m0, [pix2q]
+ psubb m3, [pix2q+8]
+ pxor m0, m1
+ pxor m3, m1
+ mova m4, [pix1q+lsizeq]
+ mova m5, [pix1q+lsizeq+8]
+ psubb m4, [pix2q+lsizeq]
+ psubb m5, [pix2q+lsizeq+8]
+ pxor m4, m1
+ pxor m5, m1
+ psadbw m0, m4
+ psadbw m3, m5
+ paddw m0, m3
+%endif
+ sub hd, 2
+
+.loop
+ lea pix1q, [pix1q + 2*lsizeq]
+ lea pix2q, [pix2q + 2*lsizeq]
+ mova m2, [pix1q]
+%if %1 == mmsize ; vsad8_mmxext, vsad16_sse2
+%if mmsize == 16
+ movu m3, [pix2q]
+ psubb m2, m3
+%else
+ psubb m2, [pix2q]
+%endif
+ pxor m2, m1
+ psadbw m4, m2
+ paddw m0, m4
+ mova m4, [pix1q+lsizeq]
+ movu m3, [pix2q+lsizeq]
+ psubb m4, m3
+ pxor m4, m1
+ psadbw m2, m4
+ paddw m0, m2
+%else ; vsad16_mmxext
+ mova m3, [pix1q+8]
+ psubb m2, [pix2q]
+ psubb m3, [pix2q+8]
+ pxor m2, m1
+ pxor m3, m1
+ psadbw m4, m2
+ psadbw m5, m3
+ paddw m0, m4
+ paddw m0, m5
+ mova m4, [pix1q+lsizeq]
+ mova m5, [pix1q+lsizeq+8]
+ psubb m4, [pix2q+lsizeq]
+ psubb m5, [pix2q+lsizeq+8]
+ pxor m4, m1
+ pxor m5, m1
+ psadbw m2, m4
+ psadbw m3, m5
+ paddw m0, m2
+ paddw m0, m3
+%endif
+ sub hd, 2
+ jg .loop
+
+%if mmsize == 16
+ pshufd m1, m0, 0xe
+ paddd m0, m1
+%endif
+ movd eax, m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+VSAD_APPROX 8
+VSAD_APPROX 16
+INIT_XMM sse2
+VSAD_APPROX 16
diff --git a/libavcodec/x86/me_cmp_init.c b/libavcodec/x86/me_cmp_init.c
index f6c8e5b565..255df5065d 100644
--- a/libavcodec/x86/me_cmp_init.c
+++ b/libavcodec/x86/me_cmp_init.c
@@ -5,20 +5,20 @@
*
* MMX optimization by Nick Kurshev <nickols_k@mail.ru>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,382 +29,67 @@
#include "libavcodec/me_cmp.h"
#include "libavcodec/mpegvideo.h"
-#if HAVE_INLINE_ASM
-
-static int sse8_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
- ptrdiff_t stride, int h)
-{
- int tmp;
-
- __asm__ volatile (
- "movl %4, %%ecx \n"
- "shr $1, %%ecx \n"
- "pxor %%mm0, %%mm0 \n" /* mm0 = 0 */
- "pxor %%mm7, %%mm7 \n" /* mm7 holds the sum */
- "1: \n"
- "movq (%0), %%mm1 \n" /* mm1 = pix1[0][0 - 7] */
- "movq (%1), %%mm2 \n" /* mm2 = pix2[0][0 - 7] */
- "movq (%0, %3), %%mm3 \n" /* mm3 = pix1[1][0 - 7] */
- "movq (%1, %3), %%mm4 \n" /* mm4 = pix2[1][0 - 7] */
-
- /* todo: mm1-mm2, mm3-mm4 */
- /* algo: subtract mm1 from mm2 with saturation and vice versa */
- /* OR the results to get absolute difference */
- "movq %%mm1, %%mm5 \n"
- "movq %%mm3, %%mm6 \n"
- "psubusb %%mm2, %%mm1 \n"
- "psubusb %%mm4, %%mm3 \n"
- "psubusb %%mm5, %%mm2 \n"
- "psubusb %%mm6, %%mm4 \n"
-
- "por %%mm1, %%mm2 \n"
- "por %%mm3, %%mm4 \n"
-
- /* now convert to 16-bit vectors so we can square them */
- "movq %%mm2, %%mm1 \n"
- "movq %%mm4, %%mm3 \n"
-
- "punpckhbw %%mm0, %%mm2 \n"
- "punpckhbw %%mm0, %%mm4 \n"
- "punpcklbw %%mm0, %%mm1 \n" /* mm1 now spread over (mm1, mm2) */
- "punpcklbw %%mm0, %%mm3 \n" /* mm4 now spread over (mm3, mm4) */
-
- "pmaddwd %%mm2, %%mm2 \n"
- "pmaddwd %%mm4, %%mm4 \n"
- "pmaddwd %%mm1, %%mm1 \n"
- "pmaddwd %%mm3, %%mm3 \n"
-
- "lea (%0, %3, 2), %0 \n" /* pix1 += 2 * stride */
- "lea (%1, %3, 2), %1 \n" /* pix2 += 2 * stride */
-
- "paddd %%mm2, %%mm1 \n"
- "paddd %%mm4, %%mm3 \n"
- "paddd %%mm1, %%mm7 \n"
- "paddd %%mm3, %%mm7 \n"
-
- "decl %%ecx \n"
- "jnz 1b \n"
-
- "movq %%mm7, %%mm1 \n"
- "psrlq $32, %%mm7 \n" /* shift hi dword to lo */
- "paddd %%mm7, %%mm1 \n"
- "movd %%mm1, %2 \n"
- : "+r" (pix1), "+r" (pix2), "=r" (tmp)
- : "r" (stride), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-
-static int sse16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
- ptrdiff_t stride, int h)
-{
- int tmp;
-
- __asm__ volatile (
- "movl %4, %%ecx\n"
- "pxor %%mm0, %%mm0\n" /* mm0 = 0 */
- "pxor %%mm7, %%mm7\n" /* mm7 holds the sum */
- "1:\n"
- "movq (%0), %%mm1\n" /* mm1 = pix1[0 - 7] */
- "movq (%1), %%mm2\n" /* mm2 = pix2[0 - 7] */
- "movq 8(%0), %%mm3\n" /* mm3 = pix1[8 - 15] */
- "movq 8(%1), %%mm4\n" /* mm4 = pix2[8 - 15] */
-
- /* todo: mm1-mm2, mm3-mm4 */
- /* algo: subtract mm1 from mm2 with saturation and vice versa */
- /* OR the results to get absolute difference */
- "movq %%mm1, %%mm5\n"
- "movq %%mm3, %%mm6\n"
- "psubusb %%mm2, %%mm1\n"
- "psubusb %%mm4, %%mm3\n"
- "psubusb %%mm5, %%mm2\n"
- "psubusb %%mm6, %%mm4\n"
-
- "por %%mm1, %%mm2\n"
- "por %%mm3, %%mm4\n"
-
- /* now convert to 16-bit vectors so we can square them */
- "movq %%mm2, %%mm1\n"
- "movq %%mm4, %%mm3\n"
-
- "punpckhbw %%mm0, %%mm2\n"
- "punpckhbw %%mm0, %%mm4\n"
- "punpcklbw %%mm0, %%mm1\n" /* mm1 now spread over (mm1, mm2) */
- "punpcklbw %%mm0, %%mm3\n" /* mm4 now spread over (mm3, mm4) */
-
- "pmaddwd %%mm2, %%mm2\n"
- "pmaddwd %%mm4, %%mm4\n"
- "pmaddwd %%mm1, %%mm1\n"
- "pmaddwd %%mm3, %%mm3\n"
-
- "add %3, %0\n"
- "add %3, %1\n"
-
- "paddd %%mm2, %%mm1\n"
- "paddd %%mm4, %%mm3\n"
- "paddd %%mm1, %%mm7\n"
- "paddd %%mm3, %%mm7\n"
-
- "decl %%ecx\n"
- "jnz 1b\n"
-
- "movq %%mm7, %%mm1\n"
- "psrlq $32, %%mm7\n" /* shift hi dword to lo */
- "paddd %%mm7, %%mm1\n"
- "movd %%mm1, %2\n"
- : "+r" (pix1), "+r" (pix2), "=r" (tmp)
- : "r" (stride), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-
-static int hf_noise8_mmx(uint8_t *pix1, ptrdiff_t stride, int h)
-{
- int tmp;
-
- __asm__ volatile (
- "movl %3, %%ecx\n"
- "pxor %%mm7, %%mm7\n"
- "pxor %%mm6, %%mm6\n"
-
- "movq (%0), %%mm0\n"
- "movq %%mm0, %%mm1\n"
- "psllq $8, %%mm0\n"
- "psrlq $8, %%mm1\n"
- "psrlq $8, %%mm0\n"
- "movq %%mm0, %%mm2\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm0\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm2\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm0\n"
- "psubw %%mm3, %%mm2\n"
-
- "add %2, %0\n"
-
- "movq (%0), %%mm4\n"
- "movq %%mm4, %%mm1\n"
- "psllq $8, %%mm4\n"
- "psrlq $8, %%mm1\n"
- "psrlq $8, %%mm4\n"
- "movq %%mm4, %%mm5\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm4\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm5\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm4\n"
- "psubw %%mm3, %%mm5\n"
- "psubw %%mm4, %%mm0\n"
- "psubw %%mm5, %%mm2\n"
- "pxor %%mm3, %%mm3\n"
- "pxor %%mm1, %%mm1\n"
- "pcmpgtw %%mm0, %%mm3\n\t"
- "pcmpgtw %%mm2, %%mm1\n\t"
- "pxor %%mm3, %%mm0\n"
- "pxor %%mm1, %%mm2\n"
- "psubw %%mm3, %%mm0\n"
- "psubw %%mm1, %%mm2\n"
- "paddw %%mm0, %%mm2\n"
- "paddw %%mm2, %%mm6\n"
-
- "add %2, %0\n"
- "1:\n"
-
- "movq (%0), %%mm0\n"
- "movq %%mm0, %%mm1\n"
- "psllq $8, %%mm0\n"
- "psrlq $8, %%mm1\n"
- "psrlq $8, %%mm0\n"
- "movq %%mm0, %%mm2\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm0\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm2\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm0\n"
- "psubw %%mm3, %%mm2\n"
- "psubw %%mm0, %%mm4\n"
- "psubw %%mm2, %%mm5\n"
- "pxor %%mm3, %%mm3\n"
- "pxor %%mm1, %%mm1\n"
- "pcmpgtw %%mm4, %%mm3\n\t"
- "pcmpgtw %%mm5, %%mm1\n\t"
- "pxor %%mm3, %%mm4\n"
- "pxor %%mm1, %%mm5\n"
- "psubw %%mm3, %%mm4\n"
- "psubw %%mm1, %%mm5\n"
- "paddw %%mm4, %%mm5\n"
- "paddw %%mm5, %%mm6\n"
-
- "add %2, %0\n"
-
- "movq (%0), %%mm4\n"
- "movq %%mm4, %%mm1\n"
- "psllq $8, %%mm4\n"
- "psrlq $8, %%mm1\n"
- "psrlq $8, %%mm4\n"
- "movq %%mm4, %%mm5\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm4\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm5\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm4\n"
- "psubw %%mm3, %%mm5\n"
- "psubw %%mm4, %%mm0\n"
- "psubw %%mm5, %%mm2\n"
- "pxor %%mm3, %%mm3\n"
- "pxor %%mm1, %%mm1\n"
- "pcmpgtw %%mm0, %%mm3\n\t"
- "pcmpgtw %%mm2, %%mm1\n\t"
- "pxor %%mm3, %%mm0\n"
- "pxor %%mm1, %%mm2\n"
- "psubw %%mm3, %%mm0\n"
- "psubw %%mm1, %%mm2\n"
- "paddw %%mm0, %%mm2\n"
- "paddw %%mm2, %%mm6\n"
-
- "add %2, %0\n"
- "subl $2, %%ecx\n"
- " jnz 1b\n"
-
- "movq %%mm6, %%mm0\n"
- "punpcklwd %%mm7, %%mm0\n"
- "punpckhwd %%mm7, %%mm6\n"
- "paddd %%mm0, %%mm6\n"
-
- "movq %%mm6, %%mm0\n"
- "psrlq $32, %%mm6\n"
- "paddd %%mm6, %%mm0\n"
- "movd %%mm0, %1\n"
- : "+r" (pix1), "=r" (tmp)
- : "r" (stride), "g" (h - 2)
- : "%ecx");
-
- return tmp;
-}
-
-static int hf_noise16_mmx(uint8_t *pix1, ptrdiff_t stride, int h)
-{
- int tmp;
- uint8_t *pix = pix1;
-
- __asm__ volatile (
- "movl %3, %%ecx\n"
- "pxor %%mm7, %%mm7\n"
- "pxor %%mm6, %%mm6\n"
-
- "movq (%0), %%mm0\n"
- "movq 1(%0), %%mm1\n"
- "movq %%mm0, %%mm2\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm0\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm2\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm0\n"
- "psubw %%mm3, %%mm2\n"
-
- "add %2, %0\n"
-
- "movq (%0), %%mm4\n"
- "movq 1(%0), %%mm1\n"
- "movq %%mm4, %%mm5\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm4\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm5\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm4\n"
- "psubw %%mm3, %%mm5\n"
- "psubw %%mm4, %%mm0\n"
- "psubw %%mm5, %%mm2\n"
- "pxor %%mm3, %%mm3\n"
- "pxor %%mm1, %%mm1\n"
- "pcmpgtw %%mm0, %%mm3\n\t"
- "pcmpgtw %%mm2, %%mm1\n\t"
- "pxor %%mm3, %%mm0\n"
- "pxor %%mm1, %%mm2\n"
- "psubw %%mm3, %%mm0\n"
- "psubw %%mm1, %%mm2\n"
- "paddw %%mm0, %%mm2\n"
- "paddw %%mm2, %%mm6\n"
-
- "add %2, %0\n"
- "1:\n"
-
- "movq (%0), %%mm0\n"
- "movq 1(%0), %%mm1\n"
- "movq %%mm0, %%mm2\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm0\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm2\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm0\n"
- "psubw %%mm3, %%mm2\n"
- "psubw %%mm0, %%mm4\n"
- "psubw %%mm2, %%mm5\n"
- "pxor %%mm3, %%mm3\n"
- "pxor %%mm1, %%mm1\n"
- "pcmpgtw %%mm4, %%mm3\n\t"
- "pcmpgtw %%mm5, %%mm1\n\t"
- "pxor %%mm3, %%mm4\n"
- "pxor %%mm1, %%mm5\n"
- "psubw %%mm3, %%mm4\n"
- "psubw %%mm1, %%mm5\n"
- "paddw %%mm4, %%mm5\n"
- "paddw %%mm5, %%mm6\n"
-
- "add %2, %0\n"
-
- "movq (%0), %%mm4\n"
- "movq 1(%0), %%mm1\n"
- "movq %%mm4, %%mm5\n"
- "movq %%mm1, %%mm3\n"
- "punpcklbw %%mm7, %%mm4\n"
- "punpcklbw %%mm7, %%mm1\n"
- "punpckhbw %%mm7, %%mm5\n"
- "punpckhbw %%mm7, %%mm3\n"
- "psubw %%mm1, %%mm4\n"
- "psubw %%mm3, %%mm5\n"
- "psubw %%mm4, %%mm0\n"
- "psubw %%mm5, %%mm2\n"
- "pxor %%mm3, %%mm3\n"
- "pxor %%mm1, %%mm1\n"
- "pcmpgtw %%mm0, %%mm3\n\t"
- "pcmpgtw %%mm2, %%mm1\n\t"
- "pxor %%mm3, %%mm0\n"
- "pxor %%mm1, %%mm2\n"
- "psubw %%mm3, %%mm0\n"
- "psubw %%mm1, %%mm2\n"
- "paddw %%mm0, %%mm2\n"
- "paddw %%mm2, %%mm6\n"
-
- "add %2, %0\n"
- "subl $2, %%ecx\n"
- " jnz 1b\n"
-
- "movq %%mm6, %%mm0\n"
- "punpcklwd %%mm7, %%mm0\n"
- "punpckhwd %%mm7, %%mm6\n"
- "paddd %%mm0, %%mm6\n"
+int ff_sum_abs_dctelem_mmx(int16_t *block);
+int ff_sum_abs_dctelem_mmxext(int16_t *block);
+int ff_sum_abs_dctelem_sse2(int16_t *block);
+int ff_sum_abs_dctelem_ssse3(int16_t *block);
+int ff_sse8_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sse16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sse16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_hf_noise8_mmx(uint8_t *pix1, ptrdiff_t stride, int h);
+int ff_hf_noise16_mmx(uint8_t *pix1, ptrdiff_t stride, int h);
+int ff_sad8_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad8_x2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_x2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_x2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad8_y2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_y2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_y2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad8_approx_xy2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_approx_xy2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_sad16_approx_xy2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_vsad_intra8_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_vsad_intra16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_vsad_intra16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_vsad8_approx_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_vsad16_approx_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
+int ff_vsad16_approx_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
+ ptrdiff_t stride, int h);
- "movq %%mm6, %%mm0\n"
- "psrlq $32, %%mm6\n"
- "paddd %%mm6, %%mm0\n"
- "movd %%mm0, %1\n"
- : "+r" (pix1), "=r" (tmp)
- : "r" (stride), "g" (h - 2)
- : "%ecx");
+#define hadamard_func(cpu) \
+ int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1, \
+ uint8_t *src2, ptrdiff_t stride, int h); \
+ int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, uint8_t *src1, \
+ uint8_t *src2, ptrdiff_t stride, int h);
- return tmp + hf_noise8_mmx(pix + 8, stride, h);
-}
+hadamard_func(mmx)
+hadamard_func(mmxext)
+hadamard_func(sse2)
+hadamard_func(ssse3)
+#if HAVE_YASM
static int nsse16_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
@@ -413,9 +98,9 @@ static int nsse16_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
if (c)
score1 = c->mecc.sse[0](c, pix1, pix2, stride, h);
else
- score1 = sse16_mmx(c, pix1, pix2, stride, h);
- score2 = hf_noise16_mmx(pix1, stride, h) -
- hf_noise16_mmx(pix2, stride, h);
+ score1 = ff_sse16_mmx(c, pix1, pix2, stride, h);
+ score2 = ff_hf_noise16_mmx(pix1, stride, h) + ff_hf_noise8_mmx(pix1+8, stride, h)
+ - ff_hf_noise16_mmx(pix2, stride, h) - ff_hf_noise8_mmx(pix2+8, stride, h);
if (c)
return score1 + FFABS(score2) * c->avctx->nsse_weight;
@@ -426,9 +111,9 @@ static int nsse16_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
static int nsse8_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
- int score1 = sse8_mmx(c, pix1, pix2, stride, h);
- int score2 = hf_noise8_mmx(pix1, stride, h) -
- hf_noise8_mmx(pix2, stride, h);
+ int score1 = ff_sse8_mmx(c, pix1, pix2, stride, h);
+ int score2 = ff_hf_noise8_mmx(pix1, stride, h) -
+ ff_hf_noise8_mmx(pix2, stride, h);
if (c)
return score1 + FFABS(score2) * c->avctx->nsse_weight;
@@ -436,13 +121,17 @@ static int nsse8_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2,
return score1 + FFABS(score2) * 8;
}
+#endif /* HAVE_YASM */
+
+#if HAVE_INLINE_ASM
+
static int vsad_intra16_mmx(MpegEncContext *v, uint8_t *pix, uint8_t *dummy,
ptrdiff_t stride, int h)
{
int tmp;
- assert((((int) pix) & 7) == 0);
- assert((stride & 7) == 0);
+ av_assert2((((int) pix) & 7) == 0);
+ av_assert2((stride & 7) == 0);
#define SUM(in0, in1, out0, out1) \
"movq (%0), %%mm2\n" \
@@ -500,57 +189,14 @@ static int vsad_intra16_mmx(MpegEncContext *v, uint8_t *pix, uint8_t *dummy,
}
#undef SUM
-static int vsad_intra16_mmxext(MpegEncContext *v, uint8_t *pix, uint8_t *dummy,
- ptrdiff_t stride, int h)
-{
- int tmp;
-
- assert((((int) pix) & 7) == 0);
- assert((stride & 7) == 0);
-
-#define SUM(in0, in1, out0, out1) \
- "movq (%0), " #out0 "\n" \
- "movq 8(%0), " #out1 "\n" \
- "add %2, %0\n" \
- "psadbw " #out0 ", " #in0 "\n" \
- "psadbw " #out1 ", " #in1 "\n" \
- "paddw " #in1 ", " #in0 "\n" \
- "paddw " #in0 ", %%mm6\n"
-
- __asm__ volatile (
- "movl %3, %%ecx\n"
- "pxor %%mm6, %%mm6\n"
- "pxor %%mm7, %%mm7\n"
- "movq (%0), %%mm0\n"
- "movq 8(%0), %%mm1\n"
- "add %2, %0\n"
- "jmp 2f\n"
- "1:\n"
-
- SUM(%%mm4, %%mm5, %%mm0, %%mm1)
- "2:\n"
- SUM(%%mm0, %%mm1, %%mm4, %%mm5)
-
- "subl $2, %%ecx\n"
- "jnz 1b\n"
-
- "movd %%mm6, %1\n"
- : "+r" (pix), "=r" (tmp)
- : "r" (stride), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-#undef SUM
-
static int vsad16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
ptrdiff_t stride, int h)
{
int tmp;
- assert((((int) pix1) & 7) == 0);
- assert((((int) pix2) & 7) == 0);
- assert((stride & 7) == 0);
+ av_assert2((((int) pix1) & 7) == 0);
+ av_assert2((((int) pix2) & 7) == 0);
+ av_assert2((stride & 7) == 0);
#define SUM(in0, in1, out0, out1) \
"movq (%0), %%mm2\n" \
@@ -624,191 +270,16 @@ static int vsad16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
}
#undef SUM
-static int vsad16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
- ptrdiff_t stride, int h)
-{
- int tmp;
-
- assert((((int) pix1) & 7) == 0);
- assert((((int) pix2) & 7) == 0);
- assert((stride & 7) == 0);
-
-#define SUM(in0, in1, out0, out1) \
- "movq (%0), " #out0 "\n" \
- "movq (%1), %%mm2\n" \
- "movq 8(%0), " #out1 "\n" \
- "movq 8(%1), %%mm3\n" \
- "add %3, %0\n" \
- "add %3, %1\n" \
- "psubb %%mm2, " #out0 "\n" \
- "psubb %%mm3, " #out1 "\n" \
- "pxor %%mm7, " #out0 "\n" \
- "pxor %%mm7, " #out1 "\n" \
- "psadbw " #out0 ", " #in0 "\n" \
- "psadbw " #out1 ", " #in1 "\n" \
- "paddw " #in1 ", " #in0 "\n" \
- "paddw " #in0 ", %%mm6\n "
-
- __asm__ volatile (
- "movl %4, %%ecx\n"
- "pxor %%mm6, %%mm6\n"
- "pcmpeqw %%mm7, %%mm7\n"
- "psllw $15, %%mm7\n"
- "packsswb %%mm7, %%mm7\n"
- "movq (%0), %%mm0\n"
- "movq (%1), %%mm2\n"
- "movq 8(%0), %%mm1\n"
- "movq 8(%1), %%mm3\n"
- "add %3, %0\n"
- "add %3, %1\n"
- "psubb %%mm2, %%mm0\n"
- "psubb %%mm3, %%mm1\n"
- "pxor %%mm7, %%mm0\n"
- "pxor %%mm7, %%mm1\n"
- "jmp 2f\n"
- "1:\n"
-
- SUM(%%mm4, %%mm5, %%mm0, %%mm1)
- "2:\n"
- SUM(%%mm0, %%mm1, %%mm4, %%mm5)
-
- "subl $2, %%ecx\n"
- "jnz 1b\n"
-
- "movd %%mm6, %2\n"
- : "+r" (pix1), "+r" (pix2), "=r" (tmp)
- : "r" (stride), "m" (h)
- : "%ecx");
-
- return tmp;
-}
-#undef SUM
-
-#define MMABS_MMX(a,z) \
- "pxor " #z ", " #z " \n\t" \
- "pcmpgtw " #a ", " #z " \n\t" \
- "pxor " #z ", " #a " \n\t" \
- "psubw " #z ", " #a " \n\t"
-
-#define MMABS_MMXEXT(a, z) \
- "pxor " #z ", " #z " \n\t" \
- "psubw " #a ", " #z " \n\t" \
- "pmaxsw " #z ", " #a " \n\t"
-
-#define MMABS_SSSE3(a,z) \
- "pabsw " #a ", " #a " \n\t"
-
-#define MMABS_SUM(a,z, sum) \
- MMABS(a,z) \
- "paddusw " #a ", " #sum " \n\t"
-
-/* FIXME: HSUM_* saturates at 64k, while an 8x8 hadamard or dct block can get
- * up to about 100k on extreme inputs. But that's very unlikely to occur in
- * natural video, and it's even more unlikely to not have any alternative
- * mvs/modes with lower cost. */
-#define HSUM_MMX(a, t, dst) \
- "movq " #a ", " #t " \n\t" \
- "psrlq $32, " #a " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "movq " #a ", " #t " \n\t" \
- "psrlq $16, " #a " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "movd " #a ", " #dst " \n\t" \
-
-#define HSUM_MMXEXT(a, t, dst) \
- "pshufw $0x0E, " #a ", " #t " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "pshufw $0x01, " #a ", " #t " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "movd " #a ", " #dst " \n\t" \
-
-#define HSUM_SSE2(a, t, dst) \
- "movhlps " #a ", " #t " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "pshuflw $0x0E, " #a ", " #t " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "pshuflw $0x01, " #a ", " #t " \n\t" \
- "paddusw " #t ", " #a " \n\t" \
- "movd " #a ", " #dst " \n\t" \
-
-#define DCT_SAD4(m, mm, o) \
- "mov"#m" "#o" + 0(%1), " #mm "2 \n\t" \
- "mov"#m" "#o" + 16(%1), " #mm "3 \n\t" \
- "mov"#m" "#o" + 32(%1), " #mm "4 \n\t" \
- "mov"#m" "#o" + 48(%1), " #mm "5 \n\t" \
- MMABS_SUM(mm ## 2, mm ## 6, mm ## 0) \
- MMABS_SUM(mm ## 3, mm ## 7, mm ## 1) \
- MMABS_SUM(mm ## 4, mm ## 6, mm ## 0) \
- MMABS_SUM(mm ## 5, mm ## 7, mm ## 1) \
-
-#define DCT_SAD_MMX \
- "pxor %%mm0, %%mm0 \n\t" \
- "pxor %%mm1, %%mm1 \n\t" \
- DCT_SAD4(q, %%mm, 0) \
- DCT_SAD4(q, %%mm, 8) \
- DCT_SAD4(q, %%mm, 64) \
- DCT_SAD4(q, %%mm, 72) \
- "paddusw %%mm1, %%mm0 \n\t" \
- HSUM(%%mm0, %%mm1, %0)
-
-#define DCT_SAD_SSE2 \
- "pxor %%xmm0, %%xmm0 \n\t" \
- "pxor %%xmm1, %%xmm1 \n\t" \
- DCT_SAD4(dqa, %%xmm, 0) \
- DCT_SAD4(dqa, %%xmm, 64) \
- "paddusw %%xmm1, %%xmm0 \n\t" \
- HSUM(%%xmm0, %%xmm1, %0)
-
-#define DCT_SAD_FUNC(cpu) \
-static int sum_abs_dctelem_ ## cpu(int16_t *block) \
-{ \
- int sum; \
- __asm__ volatile ( \
- DCT_SAD \
- :"=r"(sum) \
- :"r"(block)); \
- return sum & 0xFFFF; \
-}
-
-#define DCT_SAD DCT_SAD_MMX
-#define HSUM(a, t, dst) HSUM_MMX(a, t, dst)
-#define MMABS(a, z) MMABS_MMX(a, z)
-DCT_SAD_FUNC(mmx)
-#undef MMABS
-#undef HSUM
-
-#define HSUM(a, t, dst) HSUM_MMXEXT(a, t, dst)
-#define MMABS(a, z) MMABS_MMXEXT(a, z)
-DCT_SAD_FUNC(mmxext)
-#undef HSUM
-#undef DCT_SAD
-
-#define DCT_SAD DCT_SAD_SSE2
-#define HSUM(a, t, dst) HSUM_SSE2(a, t, dst)
-DCT_SAD_FUNC(sse2)
-#undef MMABS
-
-#if HAVE_SSSE3_INLINE
-#define MMABS(a, z) MMABS_SSSE3(a, z)
-DCT_SAD_FUNC(ssse3)
-#undef MMABS
-#endif
-#undef HSUM
-#undef DCT_SAD
-
-
DECLARE_ASM_CONST(8, uint64_t, round_tab)[3] = {
0x0000000000000000ULL,
0x0001000100010001ULL,
0x0002000200020002ULL,
};
-DECLARE_ASM_CONST(8, uint64_t, bone) = 0x0101010101010101LL;
-
static inline void sad8_1_mmx(uint8_t *blk1, uint8_t *blk2,
ptrdiff_t stride, int h)
{
- x86_reg len = -(stride * h);
+ x86_reg len = -stride * h;
__asm__ volatile (
".p2align 4 \n\t"
"1: \n\t"
@@ -841,133 +312,10 @@ static inline void sad8_1_mmx(uint8_t *blk1, uint8_t *blk2,
: "r" (blk1 - len), "r" (blk2 - len), "r" (stride));
}
-static inline void sad8_1_mmxext(uint8_t *blk1, uint8_t *blk2,
- ptrdiff_t stride, int h)
-{
- __asm__ volatile (
- ".p2align 4 \n\t"
- "1: \n\t"
- "movq (%1), %%mm0 \n\t"
- "movq (%1, %3), %%mm1 \n\t"
- "psadbw (%2), %%mm0 \n\t"
- "psadbw (%2, %3), %%mm1 \n\t"
- "paddw %%mm0, %%mm6 \n\t"
- "paddw %%mm1, %%mm6 \n\t"
- "lea (%1,%3,2), %1 \n\t"
- "lea (%2,%3,2), %2 \n\t"
- "sub $2, %0 \n\t"
- " jg 1b \n\t"
- : "+r" (h), "+r" (blk1), "+r" (blk2)
- : "r" (stride));
-}
-
-static int sad16_sse2(MpegEncContext *v, uint8_t *blk2, uint8_t *blk1,
- ptrdiff_t stride, int h)
-{
- int ret;
- __asm__ volatile (
- "pxor %%xmm2, %%xmm2 \n\t"
- ".p2align 4 \n\t"
- "1: \n\t"
- "movdqu (%1), %%xmm0 \n\t"
- "movdqu (%1, %4), %%xmm1 \n\t"
- "psadbw (%2), %%xmm0 \n\t"
- "psadbw (%2, %4), %%xmm1 \n\t"
- "paddw %%xmm0, %%xmm2 \n\t"
- "paddw %%xmm1, %%xmm2 \n\t"
- "lea (%1,%4,2), %1 \n\t"
- "lea (%2,%4,2), %2 \n\t"
- "sub $2, %0 \n\t"
- " jg 1b \n\t"
- "movhlps %%xmm2, %%xmm0 \n\t"
- "paddw %%xmm0, %%xmm2 \n\t"
- "movd %%xmm2, %3 \n\t"
- : "+r" (h), "+r" (blk1), "+r" (blk2), "=r" (ret)
- : "r" (stride));
- return ret;
-}
-
-static inline void sad8_x2a_mmxext(uint8_t *blk1, uint8_t *blk2,
- ptrdiff_t stride, int h)
-{
- __asm__ volatile (
- ".p2align 4 \n\t"
- "1: \n\t"
- "movq (%1), %%mm0 \n\t"
- "movq (%1, %3), %%mm1 \n\t"
- "pavgb 1(%1), %%mm0 \n\t"
- "pavgb 1(%1, %3), %%mm1 \n\t"
- "psadbw (%2), %%mm0 \n\t"
- "psadbw (%2, %3), %%mm1 \n\t"
- "paddw %%mm0, %%mm6 \n\t"
- "paddw %%mm1, %%mm6 \n\t"
- "lea (%1,%3,2), %1 \n\t"
- "lea (%2,%3,2), %2 \n\t"
- "sub $2, %0 \n\t"
- " jg 1b \n\t"
- : "+r" (h), "+r" (blk1), "+r" (blk2)
- : "r" (stride));
-}
-
-static inline void sad8_y2a_mmxext(uint8_t *blk1, uint8_t *blk2,
- ptrdiff_t stride, int h)
-{
- __asm__ volatile (
- "movq (%1), %%mm0 \n\t"
- "add %3, %1 \n\t"
- ".p2align 4 \n\t"
- "1: \n\t"
- "movq (%1), %%mm1 \n\t"
- "movq (%1, %3), %%mm2 \n\t"
- "pavgb %%mm1, %%mm0 \n\t"
- "pavgb %%mm2, %%mm1 \n\t"
- "psadbw (%2), %%mm0 \n\t"
- "psadbw (%2, %3), %%mm1 \n\t"
- "paddw %%mm0, %%mm6 \n\t"
- "paddw %%mm1, %%mm6 \n\t"
- "movq %%mm2, %%mm0 \n\t"
- "lea (%1,%3,2), %1 \n\t"
- "lea (%2,%3,2), %2 \n\t"
- "sub $2, %0 \n\t"
- " jg 1b \n\t"
- : "+r" (h), "+r" (blk1), "+r" (blk2)
- : "r" (stride));
-}
-
-static inline void sad8_4_mmxext(uint8_t *blk1, uint8_t *blk2,
- ptrdiff_t stride, int h)
-{
- __asm__ volatile (
- "movq "MANGLE(bone)", %%mm5 \n\t"
- "movq (%1), %%mm0 \n\t"
- "pavgb 1(%1), %%mm0 \n\t"
- "add %3, %1 \n\t"
- ".p2align 4 \n\t"
- "1: \n\t"
- "movq (%1), %%mm1 \n\t"
- "movq (%1,%3), %%mm2 \n\t"
- "pavgb 1(%1), %%mm1 \n\t"
- "pavgb 1(%1,%3), %%mm2 \n\t"
- "psubusb %%mm5, %%mm1 \n\t"
- "pavgb %%mm1, %%mm0 \n\t"
- "pavgb %%mm2, %%mm1 \n\t"
- "psadbw (%2), %%mm0 \n\t"
- "psadbw (%2,%3), %%mm1 \n\t"
- "paddw %%mm0, %%mm6 \n\t"
- "paddw %%mm1, %%mm6 \n\t"
- "movq %%mm2, %%mm0 \n\t"
- "lea (%1,%3,2), %1 \n\t"
- "lea (%2,%3,2), %2 \n\t"
- "sub $2, %0 \n\t"
- " jg 1b \n\t"
- : "+r" (h), "+r" (blk1), "+r" (blk2)
- : "r" (stride));
-}
-
static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2,
ptrdiff_t stride, int h)
{
- x86_reg len = -(stride * h);
+ x86_reg len = -stride * h;
__asm__ volatile (
".p2align 4 \n\t"
"1: \n\t"
@@ -1006,7 +354,7 @@ static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2,
static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2,
ptrdiff_t stride, int h)
{
- x86_reg len = -(stride * h);
+ x86_reg len = -stride * h;
__asm__ volatile (
"movq (%1, %%"REG_a"), %%mm0 \n\t"
"movq 1(%1, %%"REG_a"), %%mm2 \n\t"
@@ -1030,7 +378,7 @@ static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2,
"punpckhbw %%mm7, %%mm5 \n\t"
"paddw %%mm4, %%mm2 \n\t"
"paddw %%mm5, %%mm3 \n\t"
- "movq 16+"MANGLE(round_tab)", %%mm5 \n\t"
+ "movq %5, %%mm5 \n\t"
"paddw %%mm2, %%mm0 \n\t"
"paddw %%mm3, %%mm1 \n\t"
"paddw %%mm5, %%mm0 \n\t"
@@ -1054,7 +402,7 @@ static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2,
" js 1b \n\t"
: "+a" (len)
: "r" (blk1 - len), "r" (blk1 - len + stride), "r" (blk2 - len),
- "r" (stride));
+ "r" (stride), "m" (round_tab[2]));
}
static inline int sum_mmx(void)
@@ -1072,15 +420,6 @@ static inline int sum_mmx(void)
return ret & 0xFFFF;
}
-static inline int sum_mmxext(void)
-{
- int ret;
- __asm__ volatile (
- "movd %%mm6, %0 \n\t"
- : "=r" (ret));
- return ret;
-}
-
static inline void sad8_x2a_mmx(uint8_t *blk1, uint8_t *blk2,
ptrdiff_t stride, int h)
{
@@ -1097,7 +436,7 @@ static inline void sad8_y2a_mmx(uint8_t *blk1, uint8_t *blk2,
static int sad8_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, ptrdiff_t stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1111,7 +450,7 @@ static int sad8_ ## suf(MpegEncContext *v, uint8_t *blk2, \
static int sad8_x2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, ptrdiff_t stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1126,7 +465,7 @@ static int sad8_x2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
static int sad8_y2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, ptrdiff_t stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1141,7 +480,7 @@ static int sad8_y2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
static int sad8_xy2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
uint8_t *blk1, ptrdiff_t stride, int h) \
{ \
- assert(h == 8); \
+ av_assert2(h == 8); \
__asm__ volatile ( \
"pxor %%mm7, %%mm7 \n\t" \
"pxor %%mm6, %%mm6 \n\t" \
@@ -1211,32 +550,15 @@ static int sad16_xy2_ ## suf(MpegEncContext *v, uint8_t *blk2, \
} \
PIX_SAD(mmx)
-PIX_SAD(mmxext)
#endif /* HAVE_INLINE_ASM */
-int ff_sse16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2,
- ptrdiff_t stride, int h);
-
-#define hadamard_func(cpu) \
- int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1, \
- uint8_t *src2, ptrdiff_t stride, int h); \
- int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, uint8_t *src1, \
- uint8_t *src2, ptrdiff_t stride, int h);
-
-hadamard_func(mmx)
-hadamard_func(mmxext)
-hadamard_func(sse2)
-hadamard_func(ssse3)
-
av_cold void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx)
{
int cpu_flags = av_get_cpu_flags();
#if HAVE_INLINE_ASM
if (INLINE_MMX(cpu_flags)) {
- c->sum_abs_dctelem = sum_abs_dctelem_mmx;
-
c->pix_abs[0][0] = sad16_mmx;
c->pix_abs[0][1] = sad16_x2_mmx;
c->pix_abs[0][2] = sad16_y2_mmx;
@@ -1249,77 +571,81 @@ av_cold void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx)
c->sad[0] = sad16_mmx;
c->sad[1] = sad8_mmx;
- c->sse[0] = sse16_mmx;
- c->sse[1] = sse8_mmx;
c->vsad[4] = vsad_intra16_mmx;
- c->nsse[0] = nsse16_mmx;
- c->nsse[1] = nsse8_mmx;
-
if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
c->vsad[0] = vsad16_mmx;
}
}
- if (INLINE_MMXEXT(cpu_flags)) {
- c->sum_abs_dctelem = sum_abs_dctelem_mmxext;
-
- c->vsad[4] = vsad_intra16_mmxext;
-
- c->pix_abs[0][0] = sad16_mmxext;
- c->pix_abs[1][0] = sad8_mmxext;
-
- c->sad[0] = sad16_mmxext;
- c->sad[1] = sad8_mmxext;
-
- if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
- c->pix_abs[0][1] = sad16_x2_mmxext;
- c->pix_abs[0][2] = sad16_y2_mmxext;
- c->pix_abs[0][3] = sad16_xy2_mmxext;
- c->pix_abs[1][1] = sad8_x2_mmxext;
- c->pix_abs[1][2] = sad8_y2_mmxext;
- c->pix_abs[1][3] = sad8_xy2_mmxext;
-
- c->vsad[0] = vsad16_mmxext;
- }
- }
-
- if (INLINE_SSE2(cpu_flags)) {
- c->sum_abs_dctelem = sum_abs_dctelem_sse2;
- }
-
- if (INLINE_SSE2(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_3DNOW)) {
- c->sad[0] = sad16_sse2;
- }
-
-#if HAVE_SSSE3_INLINE
- if (INLINE_SSSE3(cpu_flags)) {
- c->sum_abs_dctelem = sum_abs_dctelem_ssse3;
- }
-#endif
#endif /* HAVE_INLINE_ASM */
if (EXTERNAL_MMX(cpu_flags)) {
c->hadamard8_diff[0] = ff_hadamard8_diff16_mmx;
c->hadamard8_diff[1] = ff_hadamard8_diff_mmx;
+ c->sum_abs_dctelem = ff_sum_abs_dctelem_mmx;
+ c->sse[0] = ff_sse16_mmx;
+ c->sse[1] = ff_sse8_mmx;
+#if HAVE_YASM
+ c->nsse[0] = nsse16_mmx;
+ c->nsse[1] = nsse8_mmx;
+#endif
}
if (EXTERNAL_MMXEXT(cpu_flags)) {
c->hadamard8_diff[0] = ff_hadamard8_diff16_mmxext;
c->hadamard8_diff[1] = ff_hadamard8_diff_mmxext;
+ c->sum_abs_dctelem = ff_sum_abs_dctelem_mmxext;
+
+ c->sad[0] = ff_sad16_mmxext;
+ c->sad[1] = ff_sad8_mmxext;
+
+ c->pix_abs[0][0] = ff_sad16_mmxext;
+ c->pix_abs[0][1] = ff_sad16_x2_mmxext;
+ c->pix_abs[0][2] = ff_sad16_y2_mmxext;
+ c->pix_abs[1][0] = ff_sad8_mmxext;
+ c->pix_abs[1][1] = ff_sad8_x2_mmxext;
+ c->pix_abs[1][2] = ff_sad8_y2_mmxext;
+
+ c->vsad[4] = ff_vsad_intra16_mmxext;
+ c->vsad[5] = ff_vsad_intra8_mmxext;
+
+ if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
+ c->pix_abs[0][3] = ff_sad16_approx_xy2_mmxext;
+ c->pix_abs[1][3] = ff_sad8_approx_xy2_mmxext;
+
+ c->vsad[0] = ff_vsad16_approx_mmxext;
+ c->vsad[1] = ff_vsad8_approx_mmxext;
+ }
}
if (EXTERNAL_SSE2(cpu_flags)) {
c->sse[0] = ff_sse16_sse2;
+ c->sum_abs_dctelem = ff_sum_abs_dctelem_sse2;
#if HAVE_ALIGNED_STACK
c->hadamard8_diff[0] = ff_hadamard8_diff16_sse2;
c->hadamard8_diff[1] = ff_hadamard8_diff_sse2;
#endif
+ if (!(cpu_flags & AV_CPU_FLAG_SSE2SLOW) && avctx->codec_id != AV_CODEC_ID_SNOW) {
+ c->sad[0] = ff_sad16_sse2;
+ c->pix_abs[0][0] = ff_sad16_sse2;
+ c->pix_abs[0][1] = ff_sad16_x2_sse2;
+ c->pix_abs[0][2] = ff_sad16_y2_sse2;
+
+ c->vsad[4] = ff_vsad_intra16_sse2;
+ if (!(avctx->flags & CODEC_FLAG_BITEXACT)) {
+ c->pix_abs[0][3] = ff_sad16_approx_xy2_sse2;
+ c->vsad[0] = ff_vsad16_approx_sse2;
+ }
+ }
}
- if (EXTERNAL_SSSE3(cpu_flags) && HAVE_ALIGNED_STACK) {
+ if (EXTERNAL_SSSE3(cpu_flags)) {
+ c->sum_abs_dctelem = ff_sum_abs_dctelem_ssse3;
+#if HAVE_ALIGNED_STACK
c->hadamard8_diff[0] = ff_hadamard8_diff16_ssse3;
c->hadamard8_diff[1] = ff_hadamard8_diff_ssse3;
+#endif
}
}
diff --git a/libavcodec/x86/mlpdsp.asm b/libavcodec/x86/mlpdsp.asm
new file mode 100644
index 0000000000..ce656af145
--- /dev/null
+++ b/libavcodec/x86/mlpdsp.asm
@@ -0,0 +1,196 @@
+;******************************************************************************
+;* SIMD-optimized MLP DSP functions
+;* Copyright (c) 2014 James Almer <jamrial@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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_TEXT
+
+%if ARCH_X86_64
+
+%macro SHLX 2
+%if cpuflag(bmi2)
+ shlx %1, %1, %2q
+%else
+ shl %1, %2b
+%endif
+%endmacro
+
+%macro REMATRIX 0
+ movdqa m0, [samplesq]
+ movdqa m1, [coeffsq ]
+ pshufd m2, m0, q2301
+ pshufd m3, m1, q2301
+ pmuldq m0, m1
+ pmuldq m3, m2
+ paddq m0, m3
+%if notcpuflag(avx2)
+ movdqa m1, [samplesq + 16]
+ movdqa m2, [coeffsq + 16]
+ pshufd m3, m1, q2301
+ pshufd m4, m2, q2301
+ pmuldq m1, m2
+ pmuldq m4, m3
+ paddq m0, m1
+ paddq m0, m4
+%else
+ vextracti128 xm1, m0, 1
+ paddq xm0, xm1
+%endif
+%endmacro
+
+%macro LOOP_END 0
+ pshufd xm1, xm0, q0032
+ paddq xm0, xm1
+ movq accumq, xm0
+ movzx blsbsd, byte [blsbs_ptrq] ; load *bypassed_lsbs
+ sar accumq, 14 ; accum >>= 14
+ and accumd, maskd ; accum &= mask
+ add accumd, blsbsd ; accum += *bypassed_lsbs
+ mov [samplesq + dest_chq], accumd ; samples[dest_ch] = accum
+ add blsbs_ptrq, 8 ; bypassed_lsbs += MAX_CHANNELS;
+ add samplesq, 32 ; samples += MAX_CHANNELS;
+ cmp blsbs_ptrq, cntq
+%endmacro
+
+%macro LOOP_SHIFT_END 0
+ pshufd xm1, xm0, q0032
+ paddq xm0, xm1
+ movq accumq, xm0
+ and indexd, auspd ; index &= access_unit_size_pow2;
+ movsx noiseq, byte [noise_bufferq + indexq] ; load noise_buffer[index]
+ add indexd, index2d ; index += index2
+ SHLX noiseq, mns ; noise_buffer[index] <<= matrix_noise_shift
+ add accumq, noiseq ; accum += noise_buffer[index]
+ movzx noised, byte [blsbs_ptrq] ; load *bypassed_lsbs (reuse tmp noise register)
+ sar accumq, 14 ; accum >>= 14
+ and accumd, maskd ; accum &= mask
+ add accumd, noised ; accum += *bypassed_lsbs
+ mov [samplesq + dest_chq], accumd ; samples[dest_ch] = accum
+ add blsbs_ptrq, 8 ; bypassed_lsbs += MAX_CHANNELS;
+ add samplesq, 32 ; samples += MAX_CHANNELS;
+ cmp blsbs_ptrq, cntq
+%endmacro
+
+;void ff_mlp_rematrix_channel(int32_t *samples, const int32_t *coeffs,
+; const uint8_t *bypassed_lsbs, const int8_t *noise_buffer,
+; int index, unsigned int dest_ch, uint16_t blockpos,
+; unsigned int maxchan, int matrix_noise_shift,
+; int access_unit_size_pow2, int32_t mask)
+%macro MLP_REMATRIX_CHANNEL 0
+cglobal mlp_rematrix_channel, 0, 13, 5, samples, coeffs, blsbs_ptr, blsbs, \
+ index, dest_ch, blockpos, maxchan, mns, \
+ accum, mask, cnt
+ mov mnsd, mnsm ; load matrix_noise_shift
+ movzx blockposq, word blockposm ; load and zero extend blockpos (16bit)
+ mov maxchand, maxchanm ; load maxchan
+ mov maskd, maskm ; load mask
+%if WIN64
+ mov dest_chd, dest_chm ; load dest_chd (not needed on UNIX64)
+%endif
+ shl dest_chd, 2
+ lea cntq, [blsbs_ptrq + blockposq*8]
+ test mnsd, mnsd ; is matrix_noise_shift != 0?
+ jne .shift ; jump if true
+ cmp maxchand, 4 ; is maxchan < 4?
+ jl .loop4 ; jump if true
+
+align 16
+.loop8:
+ ; Process 5 or more channels
+ REMATRIX
+ LOOP_END
+ jne .loop8
+ RET
+
+align 16
+.loop4:
+ ; Process up to 4 channels
+ movdqa xm0, [samplesq]
+ movdqa xm1, [coeffsq ]
+ pshufd xm2, xm0, q2301
+ pshufd xm3, xm1, q2301
+ pmuldq xm0, xm1
+ pmuldq xm3, xm2
+ paddq xm0, xm3
+ LOOP_END
+ jne .loop4
+ RET
+
+.shift:
+%if WIN64
+ mov indexd, indexm ; load index (not needed on UNIX64)
+%endif
+ mov r9d, r9m ; load access_unit_size_pow2
+%if cpuflag(bmi2)
+ ; bmi2 has shift functions that accept any gpr, not just cl, so keep things in place.
+ DEFINE_ARGS samples, coeffs, blsbs_ptr, noise_buffer, \
+ index, dest_ch, accum, index2, mns, \
+ ausp, mask, cnt, noise
+ add mnsd, 7 ; matrix_noise_shift += 7
+%else ; sse4
+ mov r6, rcx ; move rcx elsewhere so we can use cl for matrix_noise_shift
+%if WIN64
+ ; r0 = rcx
+ DEFINE_ARGS mns, coeffs, blsbs_ptr, noise_buffer, index, dest_ch, samples, \
+ index2, accum, ausp, mask, cnt, noise
+%else ; UNIX64
+ ; r3 = rcx
+ DEFINE_ARGS samples, coeffs, blsbs_ptr, mns, index, dest_ch, noise_buffer, \
+ index2, accum, ausp, mask, cnt, noise
+%endif
+ lea mnsd, [r8 + 7] ; rcx = matrix_noise_shift + 7
+%endif ; cpuflag
+ sub auspd, 1 ; access_unit_size_pow2 -= 1
+ cmp r7d, 4 ; is maxchan < 4?
+ lea index2q, [indexq*2 + 1] ; index2 = 2 * index + 1;
+ jl .loop4_shift ; jump if maxchan < 4
+
+align 16
+.loop8_shift:
+ ; Process 5 or more channels
+ REMATRIX
+ LOOP_SHIFT_END
+ jne .loop8_shift
+ RET
+
+align 16
+.loop4_shift:
+ ; Process up to 4 channels
+ movdqa xm0, [samplesq]
+ movdqa xm1, [coeffsq ]
+ pshufd xm2, xm0, q2301
+ pshufd xm3, xm1, q2301
+ pmuldq xm0, xm1
+ pmuldq xm3, xm2
+ paddq xm0, xm3
+ LOOP_SHIFT_END
+ jne .loop4_shift
+ RET
+%endmacro
+
+INIT_XMM sse4
+MLP_REMATRIX_CHANNEL
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2, bmi2
+MLP_REMATRIX_CHANNEL
+%endif
+
+%endif ; ARCH_X86_64
diff --git a/libavcodec/x86/mlpdsp.c b/libavcodec/x86/mlpdsp.c
deleted file mode 100644
index 72fc637764..0000000000
--- a/libavcodec/x86/mlpdsp.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * MLP DSP functions x86-optimized
- * Copyright (c) 2009 Ramiro Polla
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; 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/internal.h"
-#include "libavutil/cpu.h"
-#include "libavutil/x86/asm.h"
-#include "libavutil/x86/cpu.h"
-#include "libavcodec/mlpdsp.h"
-#include "libavcodec/mlp.h"
-
-#if HAVE_7REGS && HAVE_INLINE_ASM
-
-extern char ff_mlp_firorder_8;
-extern char ff_mlp_firorder_7;
-extern char ff_mlp_firorder_6;
-extern char ff_mlp_firorder_5;
-extern char ff_mlp_firorder_4;
-extern char ff_mlp_firorder_3;
-extern char ff_mlp_firorder_2;
-extern char ff_mlp_firorder_1;
-extern char ff_mlp_firorder_0;
-
-extern char ff_mlp_iirorder_4;
-extern char ff_mlp_iirorder_3;
-extern char ff_mlp_iirorder_2;
-extern char ff_mlp_iirorder_1;
-extern char ff_mlp_iirorder_0;
-
-static const void *firtable[9] = { &ff_mlp_firorder_0, &ff_mlp_firorder_1,
- &ff_mlp_firorder_2, &ff_mlp_firorder_3,
- &ff_mlp_firorder_4, &ff_mlp_firorder_5,
- &ff_mlp_firorder_6, &ff_mlp_firorder_7,
- &ff_mlp_firorder_8 };
-static const void *iirtable[5] = { &ff_mlp_iirorder_0, &ff_mlp_iirorder_1,
- &ff_mlp_iirorder_2, &ff_mlp_iirorder_3,
- &ff_mlp_iirorder_4 };
-
-#if ARCH_X86_64
-
-#define MLPMUL(label, offset, offs, offc) \
- LABEL_MANGLE(label)": \n\t" \
- "movslq "offset"+"offs"(%0), %%rax\n\t" \
- "movslq "offset"+"offc"(%1), %%rdx\n\t" \
- "imul %%rdx, %%rax\n\t" \
- "add %%rax, %%rsi\n\t"
-
-#define FIRMULREG(label, offset, firc)\
- LABEL_MANGLE(label)": \n\t" \
- "movslq "#offset"(%0), %%rax\n\t" \
- "imul %"#firc", %%rax\n\t" \
- "add %%rax, %%rsi\n\t"
-
-#define CLEAR_ACCUM \
- "xor %%rsi, %%rsi\n\t"
-
-#define SHIFT_ACCUM \
- "shr %%cl, %%rsi\n\t"
-
-#define ACCUM "%%rdx"
-#define RESULT "%%rsi"
-#define RESULT32 "%%esi"
-
-#else /* if ARCH_X86_32 */
-
-#define MLPMUL(label, offset, offs, offc) \
- LABEL_MANGLE(label)": \n\t" \
- "mov "offset"+"offs"(%0), %%eax\n\t" \
- "imull "offset"+"offc"(%1) \n\t" \
- "add %%eax , %%esi\n\t" \
- "adc %%edx , %%ecx\n\t"
-
-#define FIRMULREG(label, offset, firc) \
- MLPMUL(label, #offset, "0", "0")
-
-#define CLEAR_ACCUM \
- "xor %%esi, %%esi\n\t" \
- "xor %%ecx, %%ecx\n\t"
-
-#define SHIFT_ACCUM \
- "mov %%ecx, %%edx\n\t" \
- "mov %%esi, %%eax\n\t" \
- "movzbl %7 , %%ecx\n\t" \
- "shrd %%cl, %%edx, %%eax\n\t" \
-
-#define ACCUM "%%edx"
-#define RESULT "%%eax"
-#define RESULT32 "%%eax"
-
-#endif /* !ARCH_X86_64 */
-
-#define BINC AV_STRINGIFY(4* MAX_CHANNELS)
-#define IOFFS AV_STRINGIFY(4*(MAX_FIR_ORDER + MAX_BLOCKSIZE))
-#define IOFFC AV_STRINGIFY(4* MAX_FIR_ORDER)
-
-#define FIRMUL(label, offset) MLPMUL(label, #offset, "0", "0")
-#define IIRMUL(label, offset) MLPMUL(label, #offset, IOFFS, IOFFC)
-
-static void mlp_filter_channel_x86(int32_t *state, const int32_t *coeff,
- int firorder, int iirorder,
- unsigned int filter_shift, int32_t mask,
- int blocksize, int32_t *sample_buffer)
-{
- const void *firjump = firtable[firorder];
- const void *iirjump = iirtable[iirorder];
-
- blocksize = -blocksize;
-
- __asm__ volatile(
- "1: \n\t"
- CLEAR_ACCUM
- "jmp *%5 \n\t"
- FIRMUL (ff_mlp_firorder_8, 0x1c )
- FIRMUL (ff_mlp_firorder_7, 0x18 )
- FIRMUL (ff_mlp_firorder_6, 0x14 )
- FIRMUL (ff_mlp_firorder_5, 0x10 )
- FIRMUL (ff_mlp_firorder_4, 0x0c )
- FIRMULREG(ff_mlp_firorder_3, 0x08,10)
- FIRMULREG(ff_mlp_firorder_2, 0x04, 9)
- FIRMULREG(ff_mlp_firorder_1, 0x00, 8)
- LABEL_MANGLE(ff_mlp_firorder_0)":\n\t"
- "jmp *%6 \n\t"
- IIRMUL (ff_mlp_iirorder_4, 0x0c )
- IIRMUL (ff_mlp_iirorder_3, 0x08 )
- IIRMUL (ff_mlp_iirorder_2, 0x04 )
- IIRMUL (ff_mlp_iirorder_1, 0x00 )
- LABEL_MANGLE(ff_mlp_iirorder_0)":\n\t"
- SHIFT_ACCUM
- "mov "RESULT" ,"ACCUM" \n\t"
- "add (%2) ,"RESULT" \n\t"
- "and %4 ,"RESULT" \n\t"
- "sub $4 , %0 \n\t"
- "mov "RESULT32", (%0) \n\t"
- "mov "RESULT32", (%2) \n\t"
- "add $"BINC" , %2 \n\t"
- "sub "ACCUM" ,"RESULT" \n\t"
- "mov "RESULT32","IOFFS"(%0) \n\t"
- "incl %3 \n\t"
- "js 1b \n\t"
- : /* 0*/"+r"(state),
- /* 1*/"+r"(coeff),
- /* 2*/"+r"(sample_buffer),
-#if ARCH_X86_64
- /* 3*/"+r"(blocksize)
- : /* 4*/"r"((x86_reg)mask), /* 5*/"r"(firjump),
- /* 6*/"r"(iirjump) , /* 7*/"c"(filter_shift)
- , /* 8*/"r"((int64_t)coeff[0])
- , /* 9*/"r"((int64_t)coeff[1])
- , /*10*/"r"((int64_t)coeff[2])
- : "rax", "rdx", "rsi"
-#else /* ARCH_X86_32 */
- /* 3*/"+m"(blocksize)
- : /* 4*/"m"( mask), /* 5*/"m"(firjump),
- /* 6*/"m"(iirjump) , /* 7*/"m"(filter_shift)
- : "eax", "edx", "esi", "ecx"
-#endif /* !ARCH_X86_64 */
- );
-}
-
-#endif /* HAVE_7REGS && HAVE_INLINE_ASM */
-
-av_cold void ff_mlpdsp_init_x86(MLPDSPContext *c)
-{
-#if HAVE_7REGS && HAVE_INLINE_ASM
- int cpu_flags = av_get_cpu_flags();
- if (INLINE_MMX(cpu_flags))
- c->mlp_filter_channel = mlp_filter_channel_x86;
-#endif
-}
diff --git a/libavcodec/x86/mlpdsp_init.c b/libavcodec/x86/mlpdsp_init.c
new file mode 100644
index 0000000000..e9d9b1bf18
--- /dev/null
+++ b/libavcodec/x86/mlpdsp_init.c
@@ -0,0 +1,204 @@
+/*
+ * MLP DSP functions x86-optimized
+ * Copyright (c) 2009 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "libavcodec/mlpdsp.h"
+#include "libavcodec/mlp.h"
+
+#define REMATRIX_CHANNEL_FUNC(opt) \
+void ff_mlp_rematrix_channel_##opt(int32_t *samples, \
+ const int32_t *coeffs, \
+ const uint8_t *bypassed_lsbs, \
+ const int8_t *noise_buffer, \
+ int index, \
+ unsigned int dest_ch, \
+ uint16_t blockpos, \
+ unsigned int maxchan, \
+ int matrix_noise_shift, \
+ int access_unit_size_pow2, \
+ int32_t mask);
+
+REMATRIX_CHANNEL_FUNC(sse4)
+REMATRIX_CHANNEL_FUNC(avx2_bmi2)
+
+#if HAVE_7REGS && HAVE_INLINE_ASM && HAVE_INLINE_ASM_NONLOCAL_LABELS
+
+extern char ff_mlp_firorder_8;
+extern char ff_mlp_firorder_7;
+extern char ff_mlp_firorder_6;
+extern char ff_mlp_firorder_5;
+extern char ff_mlp_firorder_4;
+extern char ff_mlp_firorder_3;
+extern char ff_mlp_firorder_2;
+extern char ff_mlp_firorder_1;
+extern char ff_mlp_firorder_0;
+
+extern char ff_mlp_iirorder_4;
+extern char ff_mlp_iirorder_3;
+extern char ff_mlp_iirorder_2;
+extern char ff_mlp_iirorder_1;
+extern char ff_mlp_iirorder_0;
+
+static const void * const firtable[9] = { &ff_mlp_firorder_0, &ff_mlp_firorder_1,
+ &ff_mlp_firorder_2, &ff_mlp_firorder_3,
+ &ff_mlp_firorder_4, &ff_mlp_firorder_5,
+ &ff_mlp_firorder_6, &ff_mlp_firorder_7,
+ &ff_mlp_firorder_8 };
+static const void * const iirtable[5] = { &ff_mlp_iirorder_0, &ff_mlp_iirorder_1,
+ &ff_mlp_iirorder_2, &ff_mlp_iirorder_3,
+ &ff_mlp_iirorder_4 };
+
+#if ARCH_X86_64
+
+#define MLPMUL(label, offset, offs, offc) \
+ LABEL_MANGLE(label)": \n\t" \
+ "movslq "offset"+"offs"(%0), %%rax\n\t" \
+ "movslq "offset"+"offc"(%1), %%rdx\n\t" \
+ "imul %%rdx, %%rax\n\t" \
+ "add %%rax, %%rsi\n\t"
+
+#define FIRMULREG(label, offset, firc)\
+ LABEL_MANGLE(label)": \n\t" \
+ "movslq "#offset"(%0), %%rax\n\t" \
+ "imul %"#firc", %%rax\n\t" \
+ "add %%rax, %%rsi\n\t"
+
+#define CLEAR_ACCUM \
+ "xor %%rsi, %%rsi\n\t"
+
+#define SHIFT_ACCUM \
+ "shr %%cl, %%rsi\n\t"
+
+#define ACCUM "%%rdx"
+#define RESULT "%%rsi"
+#define RESULT32 "%%esi"
+
+#else /* if ARCH_X86_32 */
+
+#define MLPMUL(label, offset, offs, offc) \
+ LABEL_MANGLE(label)": \n\t" \
+ "mov "offset"+"offs"(%0), %%eax\n\t" \
+ "imull "offset"+"offc"(%1) \n\t" \
+ "add %%eax , %%esi\n\t" \
+ "adc %%edx , %%ecx\n\t"
+
+#define FIRMULREG(label, offset, firc) \
+ MLPMUL(label, #offset, "0", "0")
+
+#define CLEAR_ACCUM \
+ "xor %%esi, %%esi\n\t" \
+ "xor %%ecx, %%ecx\n\t"
+
+#define SHIFT_ACCUM \
+ "mov %%ecx, %%edx\n\t" \
+ "mov %%esi, %%eax\n\t" \
+ "movzbl %7 , %%ecx\n\t" \
+ "shrd %%cl, %%edx, %%eax\n\t" \
+
+#define ACCUM "%%edx"
+#define RESULT "%%eax"
+#define RESULT32 "%%eax"
+
+#endif /* !ARCH_X86_64 */
+
+#define BINC AV_STRINGIFY(4* MAX_CHANNELS)
+#define IOFFS AV_STRINGIFY(4*(MAX_FIR_ORDER + MAX_BLOCKSIZE))
+#define IOFFC AV_STRINGIFY(4* MAX_FIR_ORDER)
+
+#define FIRMUL(label, offset) MLPMUL(label, #offset, "0", "0")
+#define IIRMUL(label, offset) MLPMUL(label, #offset, IOFFS, IOFFC)
+
+static void mlp_filter_channel_x86(int32_t *state, const int32_t *coeff,
+ int firorder, int iirorder,
+ unsigned int filter_shift, int32_t mask,
+ int blocksize, int32_t *sample_buffer)
+{
+ const void *firjump = firtable[firorder];
+ const void *iirjump = iirtable[iirorder];
+
+ blocksize = -blocksize;
+
+ __asm__ volatile(
+ "1: \n\t"
+ CLEAR_ACCUM
+ "jmp *%5 \n\t"
+ FIRMUL (ff_mlp_firorder_8, 0x1c )
+ FIRMUL (ff_mlp_firorder_7, 0x18 )
+ FIRMUL (ff_mlp_firorder_6, 0x14 )
+ FIRMUL (ff_mlp_firorder_5, 0x10 )
+ FIRMUL (ff_mlp_firorder_4, 0x0c )
+ FIRMUL (ff_mlp_firorder_3, 0x08 )
+ FIRMUL (ff_mlp_firorder_2, 0x04 )
+ FIRMULREG(ff_mlp_firorder_1, 0x00, 8)
+ LABEL_MANGLE(ff_mlp_firorder_0)":\n\t"
+ "jmp *%6 \n\t"
+ IIRMUL (ff_mlp_iirorder_4, 0x0c )
+ IIRMUL (ff_mlp_iirorder_3, 0x08 )
+ IIRMUL (ff_mlp_iirorder_2, 0x04 )
+ IIRMUL (ff_mlp_iirorder_1, 0x00 )
+ LABEL_MANGLE(ff_mlp_iirorder_0)":\n\t"
+ SHIFT_ACCUM
+ "mov "RESULT" ,"ACCUM" \n\t"
+ "add (%2) ,"RESULT" \n\t"
+ "and %4 ,"RESULT" \n\t"
+ "sub $4 , %0 \n\t"
+ "mov "RESULT32", (%0) \n\t"
+ "mov "RESULT32", (%2) \n\t"
+ "add $"BINC" , %2 \n\t"
+ "sub "ACCUM" ,"RESULT" \n\t"
+ "mov "RESULT32","IOFFS"(%0) \n\t"
+ "incl %3 \n\t"
+ "js 1b \n\t"
+ : /* 0*/"+r"(state),
+ /* 1*/"+r"(coeff),
+ /* 2*/"+r"(sample_buffer),
+#if ARCH_X86_64
+ /* 3*/"+r"(blocksize)
+ : /* 4*/"r"((x86_reg)mask), /* 5*/"r"(firjump),
+ /* 6*/"r"(iirjump) , /* 7*/"c"(filter_shift)
+ , /* 8*/"r"((int64_t)coeff[0])
+ : "rax", "rdx", "rsi"
+#else /* ARCH_X86_32 */
+ /* 3*/"+m"(blocksize)
+ : /* 4*/"m"( mask), /* 5*/"m"(firjump),
+ /* 6*/"m"(iirjump) , /* 7*/"m"(filter_shift)
+ : "eax", "edx", "esi", "ecx"
+#endif /* !ARCH_X86_64 */
+ );
+}
+
+#endif /* HAVE_7REGS && HAVE_INLINE_ASM */
+
+av_cold void ff_mlpdsp_init_x86(MLPDSPContext *c)
+{
+ int cpu_flags = av_get_cpu_flags();
+#if HAVE_7REGS && HAVE_INLINE_ASM && HAVE_INLINE_ASM_NONLOCAL_LABELS
+ if (INLINE_MMX(cpu_flags))
+ c->mlp_filter_channel = mlp_filter_channel_x86;
+#endif
+ if (ARCH_X86_64 && EXTERNAL_SSE4(cpu_flags))
+ c->mlp_rematrix_channel = ff_mlp_rematrix_channel_sse4;
+ if (ARCH_X86_64 && EXTERNAL_AVX2(cpu_flags) && cpu_flags & AV_CPU_FLAG_BMI2)
+ c->mlp_rematrix_channel = ff_mlp_rematrix_channel_avx2_bmi2;
+}
diff --git a/libavcodec/x86/mpegaudiodsp.c b/libavcodec/x86/mpegaudiodsp.c
index 533b4a7c3f..27231674ae 100644
--- a/libavcodec/x86/mpegaudiodsp.c
+++ b/libavcodec/x86/mpegaudiodsp.c
@@ -2,20 +2,20 @@
* SIMD-optimized MP3 decoding functions
* Copyright (c) 2010 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,11 +26,18 @@
#include "libavutil/x86/cpu.h"
#include "libavcodec/mpegaudiodsp.h"
-void ff_imdct36_float_sse(float *out, float *buf, float *in, float *win);
-void ff_imdct36_float_sse2(float *out, float *buf, float *in, float *win);
-void ff_imdct36_float_sse3(float *out, float *buf, float *in, float *win);
-void ff_imdct36_float_ssse3(float *out, float *buf, float *in, float *win);
-void ff_imdct36_float_avx(float *out, float *buf, float *in, float *win);
+#define DECL(CPU)\
+static void imdct36_blocks_ ## CPU(float *out, float *buf, float *in, int count, int switch_point, int block_type);\
+void ff_imdct36_float_ ## CPU(float *out, float *buf, float *in, float *win);
+
+#if ARCH_X86_32
+DECL(sse)
+#endif
+DECL(sse2)
+DECL(sse3)
+DECL(ssse3)
+DECL(avx)
+
void ff_four_imdct36_float_sse(float *out, float *buf, float *in, float *win,
float *tmpbuf);
void ff_four_imdct36_float_avx(float *out, float *buf, float *in, float *win,
@@ -38,7 +45,7 @@ void ff_four_imdct36_float_avx(float *out, float *buf, float *in, float *win,
DECLARE_ALIGNED(16, static float, mdct_win_sse)[2][4][4*40];
-#if HAVE_SSE2_INLINE
+#if HAVE_6REGS && HAVE_SSE_INLINE
#define MACS(rt, ra, rb) rt+=(ra)*(rb)
#define MLSS(rt, ra, rb) rt-=(ra)*(rb)
@@ -182,7 +189,7 @@ static void apply_window_mp3(float *in, float *win, int *unused, float *out,
*out = sum;
}
-#endif /* HAVE_SSE2_INLINE */
+#endif /* HAVE_6REGS && HAVE_SSE_INLINE */
#if HAVE_YASM
#define DECL_IMDCT_BLOCKS(CPU1, CPU2) \
@@ -217,11 +224,17 @@ static void imdct36_blocks_ ## CPU1(float *out, float *buf, float *in, \
} \
}
+#if HAVE_SSE
+#if ARCH_X86_32
DECL_IMDCT_BLOCKS(sse,sse)
+#endif
DECL_IMDCT_BLOCKS(sse2,sse)
DECL_IMDCT_BLOCKS(sse3,sse)
DECL_IMDCT_BLOCKS(ssse3,sse)
+#endif
+#if HAVE_AVX_EXTERNAL
DECL_IMDCT_BLOCKS(avx,avx)
+#endif
#endif /* HAVE_YASM */
av_cold void ff_mpadsp_init_x86(MPADSPContext *s)
@@ -242,16 +255,19 @@ av_cold void ff_mpadsp_init_x86(MPADSPContext *s)
}
}
-#if HAVE_SSE2_INLINE
- if (INLINE_SSE2(cpu_flags)) {
+#if HAVE_6REGS && HAVE_SSE_INLINE
+ if (INLINE_SSE(cpu_flags)) {
s->apply_window_float = apply_window_mp3;
}
-#endif /* HAVE_SSE2_INLINE */
+#endif /* HAVE_SSE_INLINE */
#if HAVE_YASM
+#if HAVE_SSE
+#if ARCH_X86_32
if (EXTERNAL_SSE(cpu_flags)) {
s->imdct36_blocks_float = imdct36_blocks_sse;
}
+#endif
if (EXTERNAL_SSE2(cpu_flags)) {
s->imdct36_blocks_float = imdct36_blocks_sse2;
}
@@ -261,8 +277,11 @@ av_cold void ff_mpadsp_init_x86(MPADSPContext *s)
if (EXTERNAL_SSSE3(cpu_flags)) {
s->imdct36_blocks_float = imdct36_blocks_ssse3;
}
+#endif
+#if HAVE_AVX_EXTERNAL
if (EXTERNAL_AVX(cpu_flags)) {
s->imdct36_blocks_float = imdct36_blocks_avx;
}
+#endif
#endif /* HAVE_YASM */
}
diff --git a/libavcodec/x86/mpegvideo.c b/libavcodec/x86/mpegvideo.c
index d9fb4d24fd..133ae80a27 100644
--- a/libavcodec/x86/mpegvideo.c
+++ b/libavcodec/x86/mpegvideo.c
@@ -2,20 +2,20 @@
* Optimized for ia32 CPUs by Nick Kurshev <nickols_k@mail.ru>
* h263, mpeg1, mpeg2 dequantizer & draw_edges by Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,7 +26,7 @@
#include "libavcodec/avcodec.h"
#include "libavcodec/mpegvideo.h"
-#if HAVE_INLINE_ASM
+#if HAVE_MMX_INLINE
static void dct_unquantize_h263_intra_mmx(MpegEncContext *s,
int16_t *block, int n, int qscale)
@@ -35,7 +35,7 @@ static void dct_unquantize_h263_intra_mmx(MpegEncContext *s,
qmul = qscale << 1;
- assert(s->block_last_index[n]>=0 || s->h263_aic);
+ av_assert2(s->block_last_index[n]>=0 || s->h263_aic);
if (!s->h263_aic) {
if (n < 4)
@@ -111,7 +111,7 @@ static void dct_unquantize_h263_inter_mmx(MpegEncContext *s,
qmul = qscale << 1;
qadd = (qscale - 1) | 1;
- assert(s->block_last_index[n]>=0 || s->h263_aic);
+ av_assert2(s->block_last_index[n]>=0 || s->h263_aic);
nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ];
@@ -171,7 +171,7 @@ static void dct_unquantize_mpeg1_intra_mmx(MpegEncContext *s,
const uint16_t *quant_matrix;
int block0;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1;
@@ -239,7 +239,7 @@ static void dct_unquantize_mpeg1_inter_mmx(MpegEncContext *s,
x86_reg nCoeffs;
const uint16_t *quant_matrix;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1;
@@ -306,7 +306,7 @@ static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s,
const uint16_t *quant_matrix;
int block0;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
if(s->alternate_scan) nCoeffs= 63; //FIXME
else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
@@ -371,7 +371,7 @@ static void dct_unquantize_mpeg2_inter_mmx(MpegEncContext *s,
x86_reg nCoeffs;
const uint16_t *quant_matrix;
- assert(s->block_last_index[n]>=0);
+ av_assert2(s->block_last_index[n]>=0);
if(s->alternate_scan) nCoeffs= 63; //FIXME
else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ];
@@ -442,11 +442,11 @@ __asm__ volatile(
);
}
-#endif /* HAVE_INLINE_ASM */
+#endif /* HAVE_MMX_INLINE */
av_cold void ff_mpv_common_init_x86(MpegEncContext *s)
{
-#if HAVE_INLINE_ASM
+#if HAVE_MMX_INLINE
int cpu_flags = av_get_cpu_flags();
if (INLINE_MMX(cpu_flags)) {
@@ -458,5 +458,5 @@ av_cold void ff_mpv_common_init_x86(MpegEncContext *s)
s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_mmx;
s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_mmx;
}
-#endif /* HAVE_INLINE_ASM */
+#endif /* HAVE_MMX_INLINE */
}
diff --git a/libavcodec/x86/mpegvideodsp.c b/libavcodec/x86/mpegvideodsp.c
index 0e5dd0f153..941a8e2e4c 100644
--- a/libavcodec/x86/mpegvideodsp.c
+++ b/libavcodec/x86/mpegvideodsp.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,6 +22,7 @@
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
#include "libavcodec/mpegvideodsp.h"
+#include "libavcodec/videodsp.h"
#if HAVE_INLINE_ASM
@@ -43,20 +44,24 @@ static void gmc_mmx(uint8_t *dst, uint8_t *src,
const uint16_t dxy4[4] = { dxys, dxys, dxys, dxys };
const uint16_t dyy4[4] = { dyys, dyys, dyys, dyys };
const uint64_t shift2 = 2 * shift;
+#define MAX_STRIDE 4096U
+#define MAX_H 8U
+ uint8_t edge_buf[(MAX_H + 1) * MAX_STRIDE];
int x, y;
const int dxw = (dxx - (1 << (16 + shift))) * (w - 1);
const int dyh = (dyy - (1 << (16 + shift))) * (h - 1);
const int dxh = dxy * (h - 1);
const int dyw = dyx * (w - 1);
+ int need_emu = (unsigned) ix >= width - w ||
+ (unsigned) iy >= height - h;
if ( // non-constant fullpel offset (3% of blocks)
((ox ^ (ox + dxw)) | (ox ^ (ox + dxh)) | (ox ^ (ox + dxw + dxh)) |
(oy ^ (oy + dyw)) | (oy ^ (oy + dyh)) | (oy ^ (oy + dyw + dyh))) >> (16 + shift) ||
// uses more than 16 bits of subpel mv (only at huge resolution)
(dxx | dxy | dyx | dyy) & 15 ||
- (unsigned) ix >= width - w ||
- (unsigned) iy >= height - h) {
+ (need_emu && (h > MAX_H || stride > MAX_STRIDE))) {
// FIXME could still use mmx for some of the rows
ff_gmc_c(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy,
shift, r, width, height);
@@ -64,6 +69,10 @@ static void gmc_mmx(uint8_t *dst, uint8_t *src,
}
src += ix + iy * stride;
+ if (need_emu) {
+ ff_emulated_edge_mc_8(edge_buf, src, stride, stride, w + 1, h + 1, ix, iy, width, height);
+ src = edge_buf;
+ }
__asm__ volatile (
"movd %0, %%mm6 \n\t"
@@ -150,4 +159,3 @@ av_cold void ff_mpegvideodsp_init_x86(MpegVideoDSPContext *c)
c->gmc = gmc_mmx;
#endif /* HAVE_INLINE_ASM */
}
-
diff --git a/libavcodec/x86/mpegvideoenc.c b/libavcodec/x86/mpegvideoenc.c
index 47349d17ec..b410511c6a 100644
--- a/libavcodec/x86/mpegvideoenc.c
+++ b/libavcodec/x86/mpegvideoenc.c
@@ -2,20 +2,20 @@
* The simplest mpeg encoder (well, it was the simplest!)
* Copyright (c) 2000,2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,8 @@
/* not permutated inverse zigzag_direct + 1 for MMX quantizer */
DECLARE_ALIGNED(16, static uint16_t, inv_zigzag_direct16)[64];
+#if HAVE_6REGS
+
#if HAVE_MMX_INLINE
#define COMPILE_TEMPLATE_MMXEXT 0
#define COMPILE_TEMPLATE_SSE2 0
@@ -81,6 +83,8 @@ DECLARE_ALIGNED(16, static uint16_t, inv_zigzag_direct16)[64];
#include "mpegvideoenc_template.c"
#endif /* HAVE_SSSE3_INLINE */
+#endif /* HAVE_6REGS */
+
#if HAVE_INLINE_ASM
static void denoise_dct_mmx(MpegEncContext *s, int16_t *block){
const int intra= s->mb_intra;
@@ -193,7 +197,7 @@ static void denoise_dct_sse2(MpegEncContext *s, int16_t *block){
}
#endif /* HAVE_INLINE_ASM */
-av_cold void ff_mpv_encode_init_x86(MpegEncContext *s)
+av_cold void ff_dct_encode_init_x86(MpegEncContext *s)
{
const int dct_algo = s->avctx->dct_algo;
int i;
@@ -205,21 +209,25 @@ av_cold void ff_mpv_encode_init_x86(MpegEncContext *s)
#if HAVE_MMX_INLINE
int cpu_flags = av_get_cpu_flags();
if (INLINE_MMX(cpu_flags)) {
+#if HAVE_6REGS
s->dct_quantize = dct_quantize_mmx;
+#endif
s->denoise_dct = denoise_dct_mmx;
}
#endif
-#if HAVE_MMXEXT_INLINE
+#if HAVE_6REGS && HAVE_MMXEXT_INLINE
if (INLINE_MMXEXT(cpu_flags))
s->dct_quantize = dct_quantize_mmxext;
#endif
#if HAVE_SSE2_INLINE
if (INLINE_SSE2(cpu_flags)) {
+#if HAVE_6REGS
s->dct_quantize = dct_quantize_sse2;
+#endif
s->denoise_dct = denoise_dct_sse2;
}
#endif
-#if HAVE_SSSE3_INLINE
+#if HAVE_6REGS && HAVE_SSSE3_INLINE
if (INLINE_SSSE3(cpu_flags))
s->dct_quantize = dct_quantize_ssse3;
#endif
diff --git a/libavcodec/x86/mpegvideoenc_qns_template.c b/libavcodec/x86/mpegvideoenc_qns_template.c
index 8d8d68762a..882d486205 100644
--- a/libavcodec/x86/mpegvideoenc_qns_template.c
+++ b/libavcodec/x86/mpegvideoenc_qns_template.c
@@ -5,26 +5,26 @@
* MMX optimization by Michael Niedermayer <michaelni@gmx.at>
* 3DNow! and SSSE3 optimization by Zuxy Meng <zuxy.meng@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
#include <stdint.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/x86/asm.h"
@@ -36,7 +36,7 @@ static int DEF(try_8x8basis)(int16_t rem[64], int16_t weight[64], int16_t basis[
{
x86_reg i=0;
- assert(FFABS(scale) < MAX_ABS);
+ av_assert2(FFABS(scale) < MAX_ABS);
scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT;
SET_RND(mm6);
diff --git a/libavcodec/x86/mpegvideoenc_template.c b/libavcodec/x86/mpegvideoenc_template.c
index 1274c13e05..1899ba23c6 100644
--- a/libavcodec/x86/mpegvideoenc_template.c
+++ b/libavcodec/x86/mpegvideoenc_template.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -107,7 +107,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
const uint16_t *qmat, *bias;
LOCAL_ALIGNED_16(int16_t, temp_block, [64]);
- assert((7&(int)(&temp_block[0])) == 0); //did gcc align it correctly?
+ av_assert2((7&(int)(&temp_block[0])) == 0); //did gcc align it correctly?
//s->fdct (block);
RENAME_FDCT(ff_fdct)(block); // cannot be anything else ...
@@ -117,10 +117,15 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
if (s->mb_intra) {
int dummy;
- if (n < 4)
+ if (n < 4){
q = s->y_dc_scale;
- else
+ bias = s->q_intra_matrix16[qscale][1];
+ qmat = s->q_intra_matrix16[qscale][0];
+ }else{
q = s->c_dc_scale;
+ bias = s->q_chroma_intra_matrix16[qscale][1];
+ qmat = s->q_chroma_intra_matrix16[qscale][0];
+ }
/* note: block[0] is assumed to be positive */
if (!s->h263_aic) {
__asm__ volatile (
@@ -135,8 +140,6 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
block[0]=0; //avoid fake overflow
// temp_block[0] = (block[0] + (q >> 1)) / q;
last_non_zero_p1 = 1;
- bias = s->q_intra_matrix16[qscale][1];
- qmat = s->q_intra_matrix16[qscale][0];
} else {
last_non_zero_p1 = 0;
bias = s->q_inter_matrix16[qscale][1];
@@ -172,7 +175,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
" js 1b \n\t"
PMAX(MM"3", MM"0")
"movd "MM"3, %%"REG_a" \n\t"
- "movzb %%al, %%"REG_a" \n\t" // last_non_zero_p1
+ "movzbl %%al, %%eax \n\t" // last_non_zero_p1
: "+a" (last_non_zero_p1)
: "r" (block+64), "r" (qmat), "r" (bias),
"r" (inv_zigzag_direct16 + 64), "r" (temp_block + 64)
@@ -206,7 +209,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
" js 1b \n\t"
PMAX(MM"3", MM"0")
"movd "MM"3, %%"REG_a" \n\t"
- "movzb %%al, %%"REG_a" \n\t" // last_non_zero_p1
+ "movzbl %%al, %%eax \n\t" // last_non_zero_p1
: "+a" (last_non_zero_p1)
: "r" (block+64), "r" (qmat+64), "r" (bias+64),
"r" (inv_zigzag_direct16 + 64), "r" (temp_block + 64)
@@ -220,7 +223,7 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
"psubusw "MM"1, "MM"4 \n\t"
"packuswb "MM"4, "MM"4 \n\t"
#if COMPILE_TEMPLATE_SSE2
- "packuswb "MM"4, "MM"4 \n\t"
+ "packsswb "MM"4, "MM"4 \n\t"
#endif
"movd "MM"4, %0 \n\t" // *overflow
: "=g" (*overflow)
@@ -274,6 +277,50 @@ static int RENAME(dct_quantize)(MpegEncContext *s,
block[0x3E] = temp_block[0x3D]; block[0x27] = temp_block[0x36];
block[0x3D] = temp_block[0x2F]; block[0x2F] = temp_block[0x37];
block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F];
+ }else if(s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2){
+ if(last_non_zero_p1 <= 1) goto end;
+ block[0x04] = temp_block[0x01];
+ block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10];
+ if(last_non_zero_p1 <= 4) goto end;
+ block[0x0C] = temp_block[0x09]; block[0x01] = temp_block[0x02];
+ block[0x05] = temp_block[0x03];
+ if(last_non_zero_p1 <= 7) goto end;
+ block[0x09] = temp_block[0x0A]; block[0x14] = temp_block[0x11];
+ block[0x18] = temp_block[0x18]; block[0x20] = temp_block[0x20];
+ if(last_non_zero_p1 <= 11) goto end;
+ block[0x1C] = temp_block[0x19];
+ block[0x11] = temp_block[0x12]; block[0x0D] = temp_block[0x0B];
+ block[0x02] = temp_block[0x04]; block[0x06] = temp_block[0x05];
+ if(last_non_zero_p1 <= 16) goto end;
+ block[0x0A] = temp_block[0x0C]; block[0x15] = temp_block[0x13];
+ block[0x19] = temp_block[0x1A]; block[0x24] = temp_block[0x21];
+ block[0x28] = temp_block[0x28]; block[0x30] = temp_block[0x30];
+ block[0x2C] = temp_block[0x29]; block[0x21] = temp_block[0x22];
+ if(last_non_zero_p1 <= 24) goto end;
+ block[0x1D] = temp_block[0x1B]; block[0x12] = temp_block[0x14];
+ block[0x0E] = temp_block[0x0D]; block[0x03] = temp_block[0x06];
+ block[0x07] = temp_block[0x07]; block[0x0B] = temp_block[0x0E];
+ block[0x16] = temp_block[0x15]; block[0x1A] = temp_block[0x1C];
+ if(last_non_zero_p1 <= 32) goto end;
+ block[0x25] = temp_block[0x23]; block[0x29] = temp_block[0x2A];
+ block[0x34] = temp_block[0x31]; block[0x38] = temp_block[0x38];
+ block[0x3C] = temp_block[0x39]; block[0x31] = temp_block[0x32];
+ block[0x2D] = temp_block[0x2B]; block[0x22] = temp_block[0x24];
+ if(last_non_zero_p1 <= 40) goto end;
+ block[0x1E] = temp_block[0x1D]; block[0x13] = temp_block[0x16];
+ block[0x0F] = temp_block[0x0F]; block[0x17] = temp_block[0x17];
+ block[0x1B] = temp_block[0x1E]; block[0x26] = temp_block[0x25];
+ block[0x2A] = temp_block[0x2C]; block[0x35] = temp_block[0x33];
+ if(last_non_zero_p1 <= 48) goto end;
+ block[0x39] = temp_block[0x3A]; block[0x3D] = temp_block[0x3B];
+ block[0x32] = temp_block[0x34]; block[0x2E] = temp_block[0x2D];
+ block[0x23] = temp_block[0x26]; block[0x1F] = temp_block[0x1F];
+ block[0x27] = temp_block[0x27]; block[0x2B] = temp_block[0x2E];
+ if(last_non_zero_p1 <= 56) goto end;
+ block[0x36] = temp_block[0x35]; block[0x3A] = temp_block[0x3C];
+ block[0x3E] = temp_block[0x3D]; block[0x33] = temp_block[0x36];
+ block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37];
+ block[0x3B] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F];
}else{
if(last_non_zero_p1 <= 1) goto end;
block[0x01] = temp_block[0x01];
diff --git a/libavcodec/x86/mpegvideoencdsp.asm b/libavcodec/x86/mpegvideoencdsp.asm
index 9326ee776d..aec73f82dc 100644
--- a/libavcodec/x86/mpegvideoencdsp.asm
+++ b/libavcodec/x86/mpegvideoencdsp.asm
@@ -4,92 +4,151 @@
;* Copyright (c) 2000, 2001 Fabrice Bellard
;* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;*****************************************************************************
%include "libavutil/x86/x86util.asm"
-SECTION .text
+SECTION_RODATA
-INIT_MMX mmx
+cextern pw_1
+
+SECTION .text
; int ff_pix_sum16_mmx(uint8_t *pix, int line_size)
-cglobal pix_sum16, 2, 3
+; %1 = number of loops
+; %2 = number of GPRs used
+%macro PIX_SUM16 3
+cglobal pix_sum16, 2, %2, 6
movsxdifnidn r1, r1d
- mov r2, r1
- neg r2
- shl r2, 4
- sub r0, r2
- pxor m7, m7
- pxor m6, m6
+ mov r2, %1
+%if mmsize == 16
+ lea r3, [r1*3]
+%endif
+%if notcpuflag(xop)
+ pxor m5, m5
+%endif
+ pxor m4, m4
.loop:
- mova m0, [r0+r2+0]
- mova m1, [r0+r2+0]
- mova m2, [r0+r2+8]
- mova m3, [r0+r2+8]
- punpcklbw m0, m7
- punpckhbw m1, m7
- punpcklbw m2, m7
- punpckhbw m3, m7
+%if cpuflag(xop)
+ vphaddubq m0, [r0]
+ vphaddubq m1, [r0+r1]
+ vphaddubq m2, [r0+r1*2]
+ vphaddubq m3, [r0+r3]
+%else
+ mova m0, [r0]
+%if mmsize == 8
+ mova m1, [r0+8]
+%if cpuflag(mmxext)
+ mova m2, [r0+r1]
+ mova m3, [r0+r1+8]
+%endif
+%else ; sse2
+ mova m1, [r0+r1]
+ mova m2, [r0+r1*2]
+ mova m3, [r0+r3]
+%endif
+%if cpuflag(mmxext)
+ psadbw m0, m5
+ psadbw m1, m5
+ psadbw m2, m5
+ psadbw m3, m5
+%else ; mmx
+ punpckhbw m2, m0, m5
+ punpcklbw m0, m5
+ punpckhbw m3, m1, m5
+ punpcklbw m1, m5
+%endif ; cpuflag(mmxext)
+%endif ; cpuflag(xop)
paddw m1, m0
paddw m3, m2
paddw m3, m1
- paddw m6, m3
- add r2, r1
- js .loop
- mova m5, m6
- psrlq m6, 32
- paddw m6, m5
- mova m5, m6
- psrlq m6, 16
- paddw m6, m5
- movd eax, m6
- and eax, 0xffff
+ paddw m4, m3
+%if cpuflag(mmxext)
+ lea r0, [r0+r1*%3]
+%else
+ add r0, r1
+%endif
+ dec r2
+ jne .loop
+%if mmsize == 16
+ pshufd m0, m4, q0032
+ paddd m4, m0
+%elif notcpuflag(mmxext)
+ HADDW m4, m5
+%endif
+ movd eax, m4
RET
+%endmacro
+%if ARCH_X86_32
INIT_MMX mmx
+PIX_SUM16 16, 3, 0
+INIT_MMX mmxext
+PIX_SUM16 8, 4, 2
+%endif
+INIT_XMM sse2
+PIX_SUM16 4, 4, 4
+%if HAVE_XOP_EXTERNAL
+INIT_XMM xop
+PIX_SUM16 4, 4, 4
+%endif
+
; int ff_pix_norm1_mmx(uint8_t *pix, int line_size)
-cglobal pix_norm1, 2, 4
+; %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, 16
+ mov r2, %2
pxor m0, m0
- pxor m7, m7
+ pxor m5, m5
.loop:
mova m2, [r0+0]
+%if mmsize == 8
mova m3, [r0+8]
- mova m1, m2
- punpckhbw m1, m0
+%else
+ mova m3, [r0+r1]
+%endif
+ punpckhbw m1, m2, m0
punpcklbw m2, m0
- mova m4, m3
- punpckhbw m3, m0
- punpcklbw m4, m0
+ punpckhbw m4, m3, m0
+ punpcklbw m3, m0
pmaddwd m1, m1
pmaddwd m2, m2
pmaddwd m3, m3
pmaddwd m4, m4
paddd m2, m1
paddd m4, m3
- paddd m7, m2
+ paddd m5, m2
+ paddd m5, m4
+%if mmsize == 8
add r0, r1
- paddd m7, m4
+%else
+ lea r0, [r0+r1*2]
+%endif
dec r2
jne .loop
- mova m1, m7
- psrlq m7, 32
- paddd m1, m7
- movd eax, m1
+ HADDD m5, m1
+ movd eax, m5
RET
+%endmacro
+
+INIT_MMX mmx
+PIX_NORM1 0, 16
+INIT_XMM sse2
+PIX_NORM1 6, 8
diff --git a/libavcodec/x86/mpegvideoencdsp_init.c b/libavcodec/x86/mpegvideoencdsp_init.c
index 7732e7307f..2a4db61511 100644
--- a/libavcodec/x86/mpegvideoencdsp_init.c
+++ b/libavcodec/x86/mpegvideoencdsp_init.c
@@ -1,29 +1,34 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avassert.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/mpegvideoencdsp.h"
int ff_pix_sum16_mmx(uint8_t *pix, int line_size);
+int ff_pix_sum16_mmxext(uint8_t *pix, int line_size);
+int ff_pix_sum16_sse2(uint8_t *pix, int line_size);
+int ff_pix_sum16_xop(uint8_t *pix, int line_size);
int ff_pix_norm1_mmx(uint8_t *pix, int line_size);
+int ff_pix_norm1_sse2(uint8_t *pix, int line_size);
#if HAVE_INLINE_ASM
@@ -123,7 +128,7 @@ static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height,
: "+r" (ptr)
: "r" ((x86_reg) wrap), "r" ((x86_reg) width),
"r" (ptr + wrap * height));
- } else {
+ } else if (w == 16) {
__asm__ volatile (
"1: \n\t"
"movd (%0), %%mm0 \n\t"
@@ -141,6 +146,25 @@ static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height,
"add %1, %0 \n\t"
"cmp %3, %0 \n\t"
"jb 1b \n\t"
+ : "+r"(ptr)
+ : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height)
+ );
+ } else {
+ av_assert1(w == 4);
+ __asm__ volatile (
+ "1: \n\t"
+ "movd (%0), %%mm0 \n\t"
+ "punpcklbw %%mm0, %%mm0 \n\t"
+ "punpcklwd %%mm0, %%mm0 \n\t"
+ "movd %%mm0, -4(%0) \n\t"
+ "movd -4(%0, %2), %%mm1 \n\t"
+ "punpcklbw %%mm1, %%mm1 \n\t"
+ "punpckhwd %%mm1, %%mm1 \n\t"
+ "punpckhdq %%mm1, %%mm1 \n\t"
+ "movd %%mm1, (%0, %2) \n\t"
+ "add %1, %0 \n\t"
+ "cmp %3, %0 \n\t"
+ "jb 1b \n\t"
: "+r" (ptr)
: "r" ((x86_reg) wrap), "r" ((x86_reg) width),
"r" (ptr + wrap * height));
@@ -195,11 +219,26 @@ av_cold void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c,
{
int cpu_flags = av_get_cpu_flags();
+#if ARCH_X86_32
if (EXTERNAL_MMX(cpu_flags)) {
c->pix_sum = ff_pix_sum16_mmx;
c->pix_norm1 = ff_pix_norm1_mmx;
}
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->pix_sum = ff_pix_sum16_mmxext;
+ }
+#endif
+
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->pix_sum = ff_pix_sum16_sse2;
+ c->pix_norm1 = ff_pix_norm1_sse2;
+ }
+
+ if (EXTERNAL_XOP(cpu_flags)) {
+ c->pix_sum = ff_pix_sum16_xop;
+ }
+
#if HAVE_INLINE_ASM
if (INLINE_MMX(cpu_flags)) {
diff --git a/libavcodec/x86/pixblockdsp.asm b/libavcodec/x86/pixblockdsp.asm
index c8fd1b24a1..7c5377b2bb 100644
--- a/libavcodec/x86/pixblockdsp.asm
+++ b/libavcodec/x86/pixblockdsp.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2000, 2001 Fabrice Bellard
;* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;*****************************************************************************
@@ -26,9 +26,8 @@
SECTION .text
INIT_MMX mmx
-; void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, int line_size)
+; void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, ptrdiff_t line_size)
cglobal get_pixels, 3,4
- movsxdifnidn r2, r2d
add r0, 128
mov r3, -128
pxor m7, m7
@@ -51,8 +50,7 @@ cglobal get_pixels, 3,4
REP_RET
INIT_XMM sse2
-cglobal get_pixels, 3, 4
- movsxdifnidn r2, r2d
+cglobal get_pixels, 3, 4, 5
lea r3, [r2*3]
pxor m4, m4
movh m0, [r1]
@@ -108,3 +106,28 @@ cglobal diff_pixels, 4,5
add r4, 16
jne .loop
REP_RET
+
+INIT_XMM sse2
+cglobal diff_pixels, 4, 5, 5
+ movsxdifnidn r3, r3d
+ pxor m4, m4
+ add r0, 128
+ mov r4, -128
+.loop:
+ movh m0, [r1]
+ movh m2, [r2]
+ movh m1, [r1+r3]
+ movh m3, [r2+r3]
+ punpcklbw m0, m4
+ punpcklbw m1, m4
+ punpcklbw m2, m4
+ punpcklbw m3, m4
+ psubw m0, m2
+ psubw m1, m3
+ mova [r0+r4+0 ], m0
+ mova [r0+r4+16], m1
+ lea r1, [r1+r3*2]
+ lea r2, [r2+r3*2]
+ add r4, 32
+ jne .loop
+ RET
diff --git a/libavcodec/x86/pixblockdsp_init.c b/libavcodec/x86/pixblockdsp_init.c
index 9582e0b5c2..4d06a44c6d 100644
--- a/libavcodec/x86/pixblockdsp_init.c
+++ b/libavcodec/x86/pixblockdsp_init.c
@@ -1,20 +1,20 @@
/*
* SIMD-optimized pixel operations
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,10 +23,12 @@
#include "libavutil/x86/cpu.h"
#include "libavcodec/pixblockdsp.h"
-void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, int line_size);
-void ff_get_pixels_sse2(int16_t *block, const uint8_t *pixels, int line_size);
+void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, ptrdiff_t line_size);
+void ff_get_pixels_sse2(int16_t *block, const uint8_t *pixels, ptrdiff_t line_size);
void ff_diff_pixels_mmx(int16_t *block, const uint8_t *s1, const uint8_t *s2,
int stride);
+void ff_diff_pixels_sse2(int16_t *block, const uint8_t *s1, const uint8_t *s2,
+ int stride);
av_cold void ff_pixblockdsp_init_x86(PixblockDSPContext *c,
AVCodecContext *avctx,
@@ -43,5 +45,6 @@ av_cold void ff_pixblockdsp_init_x86(PixblockDSPContext *c,
if (EXTERNAL_SSE2(cpu_flags)) {
if (!high_bit_depth)
c->get_pixels = ff_get_pixels_sse2;
+ c->diff_pixels = ff_diff_pixels_sse2;
}
}
diff --git a/libavcodec/x86/pngdsp.asm b/libavcodec/x86/pngdsp.asm
index c05f3da017..7bd1ab5c07 100644
--- a/libavcodec/x86/pngdsp.asm
+++ b/libavcodec/x86/pngdsp.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2008 Loren Merritt <lorenm@u.washington.edu>
;* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -42,12 +42,12 @@ cglobal add_bytes_l2, 4, 6, %1, dst, src1, src2, wa, w, i
and waq, ~(mmsize*2-1)
jmp .end_v
.loop_v:
- mova m0, [src1q+iq]
- mova m1, [src1q+iq+mmsize]
- paddb m0, [src2q+iq]
- paddb m1, [src2q+iq+mmsize]
- mova [dstq+iq ], m0
- mova [dstq+iq+mmsize], m1
+ movu m0, [src2q+iq]
+ movu m1, [src2q+iq+mmsize]
+ paddb m0, [src1q+iq]
+ paddb m1, [src1q+iq+mmsize]
+ movu [dstq+iq ], m0
+ movu [dstq+iq+mmsize], m1
add iq, mmsize*2
.end_v:
cmp iq, waq
@@ -157,7 +157,7 @@ cglobal add_png_paeth_prediction, 5, 7, %1, dst, src, top, w, bpp, end, cntr
movh [dstq], m3
add dstq, bppq
cmp dstq, endq
- jle .loop
+ jl .loop
mov dstq, [rsp]
dec cntrq
diff --git a/libavcodec/x86/pngdsp_init.c b/libavcodec/x86/pngdsp_init.c
index 34a3da36d7..7dca62c675 100644
--- a/libavcodec/x86/pngdsp_init.c
+++ b/libavcodec/x86/pngdsp_init.c
@@ -2,20 +2,20 @@
* x86 PNG optimizations.
* Copyright (c) 2008 Loren Merrit <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/proresdsp.asm b/libavcodec/x86/proresdsp.asm
index a0e97b3951..632ece6ebf 100644
--- a/libavcodec/x86/proresdsp.asm
+++ b/libavcodec/x86/proresdsp.asm
@@ -1,23 +1,24 @@
;******************************************************************************
;* x86-SIMD-optimized IDCT for prores
-;* this is identical to "simple" IDCT except for the clip range
+;* this is identical to "simple" IDCT written by Michael Niedermayer
+;* except for the clip range
;*
;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* 51, Inc., Foundation Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -47,10 +48,10 @@ w1_plus_w5: times 4 dw W1sh2, +W5sh2
w5_min_w1: times 4 dw W5sh2, -W1sh2
w5_plus_w7: times 4 dw W5sh2, +W7sh2
w7_min_w5: times 4 dw W7sh2, -W5sh2
-row_round: times 8 dw (1<<14)
+pw_88: times 8 dw 0x2008
+cextern pw_1
cextern pw_4
-cextern pw_8
cextern pw_512
cextern pw_1019
@@ -91,14 +92,12 @@ section .text align=16
; a2 -= W6 * row[2];
; a3 -= W2 * row[2];
%ifidn %1, col
- paddw m10,[pw_8]
+ paddw m10,[pw_88]
%endif
- SBUTTERFLY3 wd, 0, 1, 10, 8 ; { row[0], row[2] }[0-3]/[4-7]
%ifidn %1, row
- psubw m10,[row_round]
+ paddw m10,[pw_1]
%endif
- SIGNEXTEND m8, m9, m14 ; { row[2] }[0-3] / [4-7]
- SIGNEXTEND m10, m11, m14 ; { row[0] }[0-3] / [4-7]
+ SBUTTERFLY3 wd, 0, 1, 10, 8 ; { row[0], row[2] }[0-3]/[4-7]
pmaddwd m2, m0, [w4_plus_w6]
pmaddwd m3, m1, [w4_plus_w6]
pmaddwd m4, m0, [w4_min_w6]
@@ -107,75 +106,33 @@ section .text align=16
pmaddwd m7, m1, [w4_min_w2]
pmaddwd m0, [w4_plus_w2]
pmaddwd m1, [w4_plus_w2]
- pslld m2, 2
- pslld m3, 2
- pslld m4, 2
- pslld m5, 2
- pslld m6, 2
- pslld m7, 2
- pslld m0, 2
- pslld m1, 2
; a0: -1*row[0]-1*row[2]
; a1: -1*row[0]
; a2: -1*row[0]
; a3: -1*row[0]+1*row[2]
- psubd m2, m10 ; a1[0-3]
- psubd m3, m11 ; a1[4-7]
- psubd m4, m10 ; a2[0-3]
- psubd m5, m11 ; a2[4-7]
- psubd m0, m10
- psubd m1, m11
- psubd m6, m10
- psubd m7, m11
- psubd m0, m8 ; a0[0-3]
- psubd m1, m9 ; a0[4-7]
- paddd m6, m8 ; a3[0-3]
- paddd m7, m9 ; a3[4-7]
; a0 += W4*row[4] + W6*row[6]; i.e. -1*row[4]
; a1 -= W4*row[4] + W2*row[6]; i.e. -1*row[4]-1*row[6]
; a2 -= W4*row[4] - W2*row[6]; i.e. -1*row[4]+1*row[6]
; a3 += W4*row[4] - W6*row[6]; i.e. -1*row[4]
SBUTTERFLY3 wd, 8, 9, 13, 12 ; { row[4], row[6] }[0-3]/[4-7]
- SIGNEXTEND m13, m14, m10 ; { row[4] }[0-3] / [4-7]
pmaddwd m10, m8, [w4_plus_w6]
pmaddwd m11, m9, [w4_plus_w6]
- pslld m10, 2
- pslld m11, 2
- psubd m10, m13
- psubd m11, m14
paddd m0, m10 ; a0[0-3]
paddd m1, m11 ; a0[4-7]
pmaddwd m10, m8, [w4_min_w6]
pmaddwd m11, m9, [w4_min_w6]
- pslld m10, 2
- pslld m11, 2
- psubd m10, m13
- psubd m11, m14
paddd m6, m10 ; a3[0-3]
paddd m7, m11 ; a3[4-7]
pmaddwd m10, m8, [w4_min_w2]
pmaddwd m11, m9, [w4_min_w2]
pmaddwd m8, [w4_plus_w2]
pmaddwd m9, [w4_plus_w2]
- pslld m10, 2
- pslld m11, 2
- pslld m8, 2
- pslld m9, 2
- psubd m10, m13
- psubd m11, m14
- psubd m8, m13
- psubd m9, m14
psubd m4, m10 ; a2[0-3] intermediate
psubd m5, m11 ; a2[4-7] intermediate
psubd m2, m8 ; a1[0-3] intermediate
psubd m3, m9 ; a1[4-7] intermediate
- SIGNEXTEND m12, m13, m10 ; { row[6] }[0-3] / [4-7]
- psubd m4, m12 ; a2[0-3]
- psubd m5, m13 ; a2[4-7]
- paddd m2, m12 ; a1[0-3]
- paddd m3, m13 ; a1[4-7]
; load/store
mova [r2+ 0], m0
@@ -206,8 +163,6 @@ section .text align=16
; b3 = MUL(W7, row[1]);
; MAC(b3, -W5, row[3]);
SBUTTERFLY3 wd, 0, 1, 10, 8 ; { row[1], row[3] }[0-3]/[4-7]
- SIGNEXTEND m10, m11, m12 ; { row[1] }[0-3] / [4-7]
- SIGNEXTEND m8, m9, m12 ; { row[3] }[0-3] / [4-7]
pmaddwd m2, m0, [w3_min_w7]
pmaddwd m3, m1, [w3_min_w7]
pmaddwd m4, m0, [w5_min_w1]
@@ -216,35 +171,11 @@ section .text align=16
pmaddwd m7, m1, [w7_min_w5]
pmaddwd m0, [w1_plus_w3]
pmaddwd m1, [w1_plus_w3]
- pslld m2, 2
- pslld m3, 2
- pslld m4, 2
- pslld m5, 2
- pslld m6, 2
- pslld m7, 2
- pslld m0, 2
- pslld m1, 2
; b0: +1*row[1]+2*row[3]
; b1: +2*row[1]-1*row[3]
; b2: -1*row[1]-1*row[3]
; b3: +1*row[1]+1*row[3]
- psubd m2, m8
- psubd m3, m9
- paddd m0, m8
- paddd m1, m9
- paddd m8, m10 ; { row[1] + row[3] }[0-3]
- paddd m9, m11 ; { row[1] + row[3] }[4-7]
- paddd m10, m10
- paddd m11, m11
- paddd m0, m8 ; b0[0-3]
- paddd m1, m9 ; b0[4-7]
- paddd m2, m10 ; b1[0-3]
- paddd m3, m11 ; b2[4-7]
- psubd m4, m8 ; b2[0-3]
- psubd m5, m9 ; b2[4-7]
- paddd m6, m8 ; b3[0-3]
- paddd m7, m9 ; b3[4-7]
; MAC(b0, W5, row[5]);
; MAC(b0, W7, row[7]);
@@ -255,38 +186,16 @@ section .text align=16
; MAC(b3, W3, row[5]);
; MAC(b3, -W1, row[7]);
SBUTTERFLY3 wd, 8, 9, 13, 14 ; { row[5], row[7] }[0-3]/[4-7]
- SIGNEXTEND m13, m12, m11 ; { row[5] }[0-3] / [4-7]
- SIGNEXTEND m14, m11, m10 ; { row[7] }[0-3] / [4-7]
; b0: -1*row[5]+1*row[7]
; b1: -1*row[5]+1*row[7]
; b2: +1*row[5]+2*row[7]
; b3: +2*row[5]-1*row[7]
- paddd m4, m13
- paddd m5, m12
- paddd m6, m13
- paddd m7, m12
- psubd m13, m14 ; { row[5] - row[7] }[0-3]
- psubd m12, m11 ; { row[5] - row[7] }[4-7]
- paddd m14, m14
- paddd m11, m11
- psubd m0, m13
- psubd m1, m12
- psubd m2, m13
- psubd m3, m12
- paddd m4, m14
- paddd m5, m11
- paddd m6, m13
- paddd m7, m12
pmaddwd m10, m8, [w1_plus_w5]
pmaddwd m11, m9, [w1_plus_w5]
pmaddwd m12, m8, [w5_plus_w7]
pmaddwd m13, m9, [w5_plus_w7]
- pslld m10, 2
- pslld m11, 2
- pslld m12, 2
- pslld m13, 2
psubd m2, m10 ; b1[0-3]
psubd m3, m11 ; b1[4-7]
paddd m0, m12 ; b0[0-3]
@@ -295,10 +204,6 @@ section .text align=16
pmaddwd m13, m9, [w7_plus_w3]
pmaddwd m8, [w3_min_w1]
pmaddwd m9, [w3_min_w1]
- pslld m12, 2
- pslld m13, 2
- pslld m8, 2
- pslld m9, 2
paddd m4, m12 ; b2[0-3]
paddd m5, m13 ; b2[4-7]
paddd m6, m8 ; b3[0-3]
@@ -345,7 +250,7 @@ cglobal prores_idct_put_10, 4, 4, %1
pmullw m13,[r3+64]
pmullw m12,[r3+96]
- IDCT_1D row, 17
+ IDCT_1D row, 15
; transpose for second part of IDCT
TRANSPOSE8x8W 8, 0, 1, 2, 4, 11, 9, 10, 3
@@ -360,20 +265,11 @@ cglobal prores_idct_put_10, 4, 4, %1
; for (i = 0; i < 8; i++)
; idctSparseColAdd(dest + i, line_size, block + i);
- IDCT_1D col, 20
+ IDCT_1D col, 18
; clip/store
- mova m6, [pw_512]
mova m3, [pw_4]
mova m5, [pw_1019]
- paddw m8, m6
- paddw m0, m6
- paddw m1, m6
- paddw m2, m6
- paddw m4, m6
- paddw m11, m6
- paddw m9, m6
- paddw m10, m6
pmaxsw m8, m3
pmaxsw m0, m3
pmaxsw m1, m3
@@ -404,25 +300,11 @@ cglobal prores_idct_put_10, 4, 4, %1
RET
%endmacro
-%macro SIGNEXTEND 2-3
-%if cpuflag(sse4) ; dstlow, dsthigh
- movhlps %2, %1
- pmovsxwd %1, %1
- pmovsxwd %2, %2
-%elif cpuflag(sse2) ; dstlow, dsthigh, tmp
- pxor %3, %3
- pcmpgtw %3, %1
- mova %2, %1
- punpcklwd %1, %3
- punpckhwd %2, %3
-%endif
-%endmacro
-
INIT_XMM sse2
idct_put_fn 16
-INIT_XMM sse4
-idct_put_fn 16
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
idct_put_fn 16
+%endif
%endif
diff --git a/libavcodec/x86/proresdsp_init.c b/libavcodec/x86/proresdsp_init.c
index e82dac0448..ead11ae9c1 100644
--- a/libavcodec/x86/proresdsp_init.c
+++ b/libavcodec/x86/proresdsp_init.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2010-2011 Maxim Poliakovski
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,12 +27,10 @@
void ff_prores_idct_put_10_sse2(uint16_t *dst, int linesize,
int16_t *block, const int16_t *qmat);
-void ff_prores_idct_put_10_sse4(uint16_t *dst, int linesize,
- int16_t *block, const int16_t *qmat);
void ff_prores_idct_put_10_avx (uint16_t *dst, int linesize,
int16_t *block, const int16_t *qmat);
-av_cold void ff_proresdsp_init_x86(ProresDSPContext *dsp)
+av_cold void ff_proresdsp_init_x86(ProresDSPContext *dsp, AVCodecContext *avctx)
{
#if ARCH_X86_64
int cpu_flags = av_get_cpu_flags();
@@ -42,11 +40,6 @@ av_cold void ff_proresdsp_init_x86(ProresDSPContext *dsp)
dsp->idct_put = ff_prores_idct_put_10_sse2;
}
- if (EXTERNAL_SSE4(cpu_flags)) {
- dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE;
- dsp->idct_put = ff_prores_idct_put_10_sse4;
- }
-
if (EXTERNAL_AVX(cpu_flags)) {
dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE;
dsp->idct_put = ff_prores_idct_put_10_avx;
diff --git a/libavcodec/x86/qpel.asm b/libavcodec/x86/qpel.asm
index 27a1c63b8a..4e72d5084f 100644
--- a/libavcodec/x86/qpel.asm
+++ b/libavcodec/x86/qpel.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2003-2013 Michael Niedermayer
;* Copyright (c) 2013 Daniel Kang
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/qpeldsp.asm b/libavcodec/x86/qpeldsp.asm
index 8f65550e60..dc0f900c5b 100644
--- a/libavcodec/x86/qpeldsp.asm
+++ b/libavcodec/x86/qpeldsp.asm
@@ -1,22 +1,23 @@
;******************************************************************************
-;* quarterpel DSP functions
-;*
+;* mpeg4 qpel
+;* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
;* Copyright (c) 2008 Loren Merritt
+;* Copyright (c) 2013 Daniel Kang
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/qpeldsp_init.c b/libavcodec/x86/qpeldsp_init.c
index cdefe50a3c..3268d907ab 100644
--- a/libavcodec/x86/qpeldsp_init.c
+++ b/libavcodec/x86/qpeldsp_init.c
@@ -1,20 +1,22 @@
/*
* quarterpel DSP functions
+ * Copyright (c) 2000, 2001 Fabrice Bellard
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -77,13 +79,13 @@ void ff_avg_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src,
void ff_put_no_rnd_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst,
const uint8_t *src,
int dstStride, int srcStride);
-#define ff_put_no_rnd_pixels16_mmxext ff_put_pixels16_mmxext
-#define ff_put_no_rnd_pixels8_mmxext ff_put_pixels8_mmxext
+#define ff_put_no_rnd_pixels16_mmxext ff_put_pixels16_mmx
+#define ff_put_no_rnd_pixels8_mmxext ff_put_pixels8_mmx
#if HAVE_YASM
-CALL_2X_PIXELS(ff_avg_pixels16_mmxext, ff_avg_pixels8_mmxext, 8)
-CALL_2X_PIXELS(ff_put_pixels16_mmxext, ff_put_pixels8_mmxext, 8)
+#define ff_put_pixels16_mmxext ff_put_pixels16_mmx
+#define ff_put_pixels8_mmxext ff_put_pixels8_mmx
#define QPEL_OP(OPNAME, RND, MMX) \
static void OPNAME ## qpel8_mc00_ ## MMX(uint8_t *dst, \
diff --git a/libavcodec/x86/rnd_template.c b/libavcodec/x86/rnd_template.c
index a9fb13234b..c9fd71eeef 100644
--- a/libavcodec/x86/rnd_template.c
+++ b/libavcodec/x86/rnd_template.c
@@ -7,20 +7,20 @@
* mostly rewritten by Michael Niedermayer <michaelni@gmx.at>
* and improved by Zdenek Kabelac <kabi@users.sf.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/rv34dsp.asm b/libavcodec/x86/rv34dsp.asm
index 4d9c35b600..7732d65b2a 100644
--- a/libavcodec/x86/rv34dsp.asm
+++ b/libavcodec/x86/rv34dsp.asm
@@ -2,20 +2,20 @@
;* MMX/SSE2-optimized functions for the RV30 and RV40 decoders
;* Copyright (C) 2012 Christophe Gisquet <christophe.gisquet@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/rv34dsp_init.c b/libavcodec/x86/rv34dsp_init.c
index 586e4e9a6d..99c56f9d09 100644
--- a/libavcodec/x86/rv34dsp_init.c
+++ b/libavcodec/x86/rv34dsp_init.c
@@ -2,20 +2,20 @@
* RV30/40 MMX/SSE2 optimizations
* Copyright (C) 2012 Christophe Gisquet <christophe.gisquet@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/rv40dsp.asm b/libavcodec/x86/rv40dsp.asm
index 0a242b54e3..fdd81a0a37 100644
--- a/libavcodec/x86/rv40dsp.asm
+++ b/libavcodec/x86/rv40dsp.asm
@@ -4,20 +4,20 @@
;* Copyright (c) 2010 Fiona Glaser <fiona@x264.com>
;* Copyright (C) 2012 Christophe Gisquet <christophe.gisquet@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/rv40dsp_init.c b/libavcodec/x86/rv40dsp_init.c
index e006c76584..bbf9c785f6 100644
--- a/libavcodec/x86/rv40dsp_init.c
+++ b/libavcodec/x86/rv40dsp_init.c
@@ -2,20 +2,20 @@
* RV40 decoder motion compensation functions x86-optimised
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,13 @@
#include "libavutil/x86/cpu.h"
#include "hpeldsp.h"
+#define DEFINE_FN(op, size, insn) \
+static void op##_rv40_qpel##size##_mc33_##insn(uint8_t *dst, const uint8_t *src, \
+ ptrdiff_t stride) \
+{ \
+ ff_##op##_pixels##size##_xy2_##insn(dst, src, stride, size); \
+}
+
#if HAVE_YASM
void ff_put_rv40_chroma_mc8_mmx (uint8_t *dst, uint8_t *src,
int stride, int h, int x, int y);
@@ -75,7 +82,7 @@ static void OP ## rv40_qpel ##SIZE ##_mc ##PH ##PV ##OPT(uint8_t *dst, \
{ \
int i; \
if (PH && PV) { \
- DECLARE_ALIGNED(16, uint8_t, tmp)[SIZE * (SIZE + 5)]; \
+ LOCAL_ALIGNED(16, uint8_t, tmp, [SIZE * (SIZE + 5)]); \
uint8_t *tmpptr = tmp + SIZE * 2; \
src -= stride * 2; \
\
@@ -127,8 +134,8 @@ QPEL_FUNCS_DECL(OP, 3, 2, OPT)
/** @} */
#define LOOPSIZE 8
-#define HCOFF(x) (32 * (x - 1))
-#define VCOFF(x) (32 * (x - 1))
+#define HCOFF(x) (32 * ((x) - 1))
+#define VCOFF(x) (32 * ((x) - 1))
QPEL_MC_DECL(put_, _ssse3)
QPEL_MC_DECL(avg_, _ssse3)
@@ -136,8 +143,8 @@ QPEL_MC_DECL(avg_, _ssse3)
#undef HCOFF
#undef VCOFF
#define LOOPSIZE 8
-#define HCOFF(x) (64 * (x - 1))
-#define VCOFF(x) (64 * (x - 1))
+#define HCOFF(x) (64 * ((x) - 1))
+#define VCOFF(x) (64 * ((x) - 1))
QPEL_MC_DECL(put_, _sse2)
QPEL_MC_DECL(avg_, _sse2)
@@ -146,8 +153,8 @@ QPEL_MC_DECL(avg_, _sse2)
#undef HCOFF
#undef VCOFF
#define LOOPSIZE 4
-#define HCOFF(x) (64 * (x - 1))
-#define VCOFF(x) (64 * (x - 1))
+#define HCOFF(x) (64 * ((x) - 1))
+#define VCOFF(x) (64 * ((x) - 1))
QPEL_MC_DECL(put_, _mmx)
@@ -186,30 +193,24 @@ QPEL_FUNCS_SET (OP, 3, 1, OPT) \
QPEL_FUNCS_SET (OP, 3, 2, OPT)
/** @} */
+DEFINE_FN(put, 8, ssse3)
+
+DEFINE_FN(put, 16, sse2)
+DEFINE_FN(put, 16, ssse3)
+
+DEFINE_FN(avg, 8, mmxext)
+DEFINE_FN(avg, 8, ssse3)
+
+DEFINE_FN(avg, 16, sse2)
+DEFINE_FN(avg, 16, ssse3)
#endif /* HAVE_YASM */
#if HAVE_MMX_INLINE
-static void put_rv40_qpel8_mc33_mmx(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride)
-{
- ff_put_pixels8_xy2_mmx(dst, src, stride, 8);
-}
-static void put_rv40_qpel16_mc33_mmx(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride)
-{
- ff_put_pixels16_xy2_mmx(dst, src, stride, 16);
-}
-static void avg_rv40_qpel8_mc33_mmx(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride)
-{
- ff_avg_pixels8_xy2_mmx(dst, src, stride, 8);
-}
-static void avg_rv40_qpel16_mc33_mmx(uint8_t *dst, const uint8_t *src,
- ptrdiff_t stride)
-{
- ff_avg_pixels16_xy2_mmx(dst, src, stride, 16);
-}
-#endif /* HAVE_MMX_INLINE */
+DEFINE_FN(put, 8, mmx)
+DEFINE_FN(avg, 8, mmx)
+DEFINE_FN(put, 16, mmx)
+DEFINE_FN(avg, 16, mmx)
+#endif
av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c)
{
@@ -240,6 +241,7 @@ av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c)
#endif
}
if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->avg_pixels_tab[1][15] = avg_rv40_qpel8_mc33_mmxext;
c->avg_chroma_pixels_tab[0] = ff_avg_rv40_chroma_mc8_mmxext;
c->avg_chroma_pixels_tab[1] = ff_avg_rv40_chroma_mc4_mmxext;
c->rv40_weight_pixels_tab[0][0] = ff_rv40_weight_func_rnd_16_mmxext;
@@ -251,6 +253,8 @@ av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c)
#endif
}
if (EXTERNAL_SSE2(cpu_flags)) {
+ c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_sse2;
+ c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_sse2;
c->rv40_weight_pixels_tab[0][0] = ff_rv40_weight_func_rnd_16_sse2;
c->rv40_weight_pixels_tab[0][1] = ff_rv40_weight_func_rnd_8_sse2;
c->rv40_weight_pixels_tab[1][0] = ff_rv40_weight_func_nornd_16_sse2;
@@ -259,6 +263,10 @@ av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c)
QPEL_MC_SET(avg_, _sse2)
}
if (EXTERNAL_SSSE3(cpu_flags)) {
+ c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_ssse3;
+ c->put_pixels_tab[1][15] = put_rv40_qpel8_mc33_ssse3;
+ c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_ssse3;
+ c->avg_pixels_tab[1][15] = avg_rv40_qpel8_mc33_ssse3;
c->rv40_weight_pixels_tab[0][0] = ff_rv40_weight_func_rnd_16_ssse3;
c->rv40_weight_pixels_tab[0][1] = ff_rv40_weight_func_rnd_8_ssse3;
c->rv40_weight_pixels_tab[1][0] = ff_rv40_weight_func_nornd_16_ssse3;
diff --git a/libavcodec/x86/sbrdsp.asm b/libavcodec/x86/sbrdsp.asm
index d7164b6496..083461a107 100644
--- a/libavcodec/x86/sbrdsp.asm
+++ b/libavcodec/x86/sbrdsp.asm
@@ -2,20 +2,20 @@
;* AAC Spectral Band Replication decoding functions
;* Copyright (C) 2012 Christophe Gisquet <christophe.gisquet@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -25,7 +25,14 @@ SECTION_RODATA
; mask equivalent for multiply by -1.0 1.0
ps_mask times 2 dd 1<<31, 0
ps_mask2 times 2 dd 0, 1<<31
-ps_neg times 4 dd 1<<31
+ps_mask3 dd 0, 0, 0, 1<<31
+ps_noise0 times 2 dd 1.0, 0.0,
+ps_noise2 times 2 dd -1.0, 0.0
+ps_noise13 dd 0.0, 1.0, 0.0, -1.0
+ dd 0.0, -1.0, 0.0, 1.0
+ dd 0.0, 1.0, 0.0, -1.0
+cextern sbr_noise_table
+cextern ps_neg
SECTION_TEXT
@@ -136,7 +143,6 @@ cglobal sbr_hf_gen, 4,4,8, X_high, X_low, alpha0, alpha1, BW, S, E
mulps m2, bw ; (a1[0] a1[1])*bw*bw = (a0 a1)
mova m3, m1
mova m4, m2
- mova m7, [ps_mask]
; Set pointers
%if ARCH_X86_64 == 0 || WIN64
@@ -156,30 +162,28 @@ cglobal sbr_hf_gen, 4,4,8, X_high, X_low, alpha0, alpha1, BW, S, E
shl start, 3 ; offset from num loops
mova m0, [X_lowq + start]
- movlhps m1, m1 ; (a2 a3 a2 a3)
- movlhps m2, m2 ; (a0 a1 a0 a1)
- shufps m3, m3, q0101 ; (a3 a2 a3 a2)
- shufps m4, m4, q0101 ; (a1 a0 a1 a0)
- xorps m3, m7 ; (-a3 a2 -a3 a2)
- xorps m4, m7 ; (-a1 a0 -a1 a0)
+ shufps m3, m3, q1111
+ shufps m4, m4, q1111
+ xorps m3, [ps_mask]
+ shufps m1, m1, q0000
+ shufps m2, m2, q0000
+ xorps m4, [ps_mask]
.loop2:
- mova m5, m0
+ movu m7, [X_lowq + start + 8] ; BbCc
mova m6, m0
- shufps m0, m0, q2200 ; {Xl[-2][0],",Xl[-1][0],"}
- shufps m5, m5, q3311 ; {Xl[-2][1],",Xl[-1][1],"}
- mulps m0, m2
- mulps m5, m4
- mova m7, m6
- addps m5, m0
- mova m0, [X_lowq + start + 2*2*4]
- shufps m6, m0, q0022 ; {Xl[-1][0],",Xl[0][0],"}
- shufps m7, m0, q1133 ; {Xl[-1][1],",Xl[1][1],"}
- mulps m6, m1
+ mova m5, m7
+ shufps m0, m0, q2301 ; aAbB
+ shufps m7, m7, q2301 ; bBcC
+ mulps m0, m4
mulps m7, m3
- addps m5, m6
+ mulps m6, m2
+ mulps m5, m1
+ addps m7, m0
+ mova m0, [X_lowq + start +16] ; CcDd
addps m7, m0
- addps m5, m7
- mova [X_highq + start], m5
+ addps m6, m5
+ addps m7, m6
+ mova [X_highq + start], m7
add start, 16
jnz .loop2
RET
@@ -246,33 +250,47 @@ cglobal sbr_neg_odd_64, 1,2,4,z
jne .loop
REP_RET
-INIT_XMM sse2
; void ff_sbr_qmf_deint_bfly_sse2(float *v, const float *src0, const float *src1)
+%macro SBR_QMF_DEINT_BFLY 0
cglobal sbr_qmf_deint_bfly, 3,5,8, v,src0,src1,vrev,c
mov cq, 64*4-2*mmsize
lea vrevq, [vq + 64*4]
.loop:
mova m0, [src0q+cq]
mova m1, [src1q]
- mova m2, [src0q+cq+mmsize]
- mova m3, [src1q+mmsize]
- pshufd m4, m0, q0123
- pshufd m5, m1, q0123
- pshufd m6, m2, q0123
- pshufd m7, m3, q0123
- addps m3, m4
+ mova m4, [src0q+cq+mmsize]
+ mova m5, [src1q+mmsize]
+%if cpuflag(sse2)
+ pshufd m2, m0, q0123
+ pshufd m3, m1, q0123
+ pshufd m6, m4, q0123
+ pshufd m7, m5, q0123
+%else
+ shufps m2, m0, m0, q0123
+ shufps m3, m1, m1, q0123
+ shufps m6, m4, m4, q0123
+ shufps m7, m5, m5, q0123
+%endif
+ addps m5, m2
subps m0, m7
addps m1, m6
- subps m2, m5
+ subps m4, m3
mova [vrevq], m1
- mova [vrevq+mmsize], m3
+ mova [vrevq+mmsize], m5
mova [vq+cq], m0
- mova [vq+cq+mmsize], m2
+ mova [vq+cq+mmsize], m4
add src1q, 2*mmsize
add vrevq, 2*mmsize
sub cq, 2*mmsize
jge .loop
REP_RET
+%endmacro
+
+INIT_XMM sse
+SBR_QMF_DEINT_BFLY
+
+INIT_XMM sse2
+SBR_QMF_DEINT_BFLY
INIT_XMM sse2
cglobal sbr_qmf_pre_shuffle, 1,4,6,z
@@ -303,3 +321,243 @@ cglobal sbr_qmf_pre_shuffle, 1,4,6,z
movq m2, [zq]
movq [r2q], m2
REP_RET
+
+%ifdef PIC
+%define NREGS 1
+%if UNIX64
+%define NOISE_TABLE r6q ; r5q is m_max
+%else
+%define NOISE_TABLE r5q
+%endif
+%else
+%define NREGS 0
+%define NOISE_TABLE sbr_noise_table
+%endif
+
+%macro LOAD_NST 1
+%ifdef PIC
+ lea NOISE_TABLE, [%1]
+ mova m0, [kxq + NOISE_TABLE]
+%else
+ mova m0, [kxq + %1]
+%endif
+%endmacro
+
+INIT_XMM sse2
+; sbr_hf_apply_noise_0(float (*Y)[2], const float *s_m,
+; const float *q_filt, int noise,
+; int kx, int m_max)
+cglobal sbr_hf_apply_noise_0, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max
+ mova m0, [ps_noise0]
+ jmp apply_noise_main
+
+; sbr_hf_apply_noise_1(float (*Y)[2], const float *s_m,
+; const float *q_filt, int noise,
+; int kx, int m_max)
+cglobal sbr_hf_apply_noise_1, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max
+ and kxq, 1
+ shl kxq, 4
+ LOAD_NST ps_noise13
+ jmp apply_noise_main
+
+; sbr_hf_apply_noise_2(float (*Y)[2], const float *s_m,
+; const float *q_filt, int noise,
+; int kx, int m_max)
+cglobal sbr_hf_apply_noise_2, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max
+ mova m0, [ps_noise2]
+ jmp apply_noise_main
+
+; sbr_hf_apply_noise_3(float (*Y)[2], const float *s_m,
+; const float *q_filt, int noise,
+; int kx, int m_max)
+cglobal sbr_hf_apply_noise_3, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max
+ and kxq, 1
+ shl kxq, 4
+ LOAD_NST ps_noise13+16
+
+apply_noise_main:
+%if ARCH_X86_64 == 0 || WIN64
+ mov kxd, m_maxm
+%define count kxq
+%else
+%define count m_maxq
+%endif
+ dec noiseq
+ shl count, 2
+%ifdef PIC
+ lea NOISE_TABLE, [sbr_noise_table]
+%endif
+ lea Yq, [Yq + 2*count]
+ add s_mq, count
+ add q_filtq, count
+ shl noiseq, 3
+ pxor m5, m5
+ neg count
+.loop:
+ mova m1, [q_filtq + count]
+ movu m3, [noiseq + NOISE_TABLE + 1*mmsize]
+ movu m4, [noiseq + NOISE_TABLE + 2*mmsize]
+ add noiseq, 2*mmsize
+ and noiseq, 0x1ff<<3
+ punpckhdq m2, m1, m1
+ punpckldq m1, m1
+ mulps m1, m3 ; m2 = q_filt[m] * ff_sbr_noise_table[noise]
+ mulps m2, m4 ; m2 = q_filt[m] * ff_sbr_noise_table[noise]
+ mova m3, [s_mq + count]
+ ; TODO: replace by a vpermd in AVX2
+ punpckhdq m4, m3, m3
+ punpckldq m3, m3
+ pcmpeqd m6, m3, m5 ; m6 == 0
+ pcmpeqd m7, m4, m5 ; m7 == 0
+ mulps m3, m0 ; s_m[m] * phi_sign
+ mulps m4, m0 ; s_m[m] * phi_sign
+ pand m1, m6
+ pand m2, m7
+ movu m6, [Yq + 2*count]
+ movu m7, [Yq + 2*count + mmsize]
+ addps m3, m1
+ addps m4, m2
+ addps m6, m3
+ addps m7, m4
+ movu [Yq + 2*count], m6
+ movu [Yq + 2*count + mmsize], m7
+ add count, mmsize
+ jl .loop
+ RET
+
+INIT_XMM sse
+cglobal sbr_qmf_deint_neg, 2,4,4,v,src,vrev,c
+%define COUNT 32*4
+%define OFFSET 32*4
+ mov cq, -COUNT
+ lea vrevq, [vq + OFFSET + COUNT]
+ add vq, OFFSET-mmsize
+ add srcq, 2*COUNT
+ mova m3, [ps_neg]
+.loop:
+ mova m0, [srcq + 2*cq + 0*mmsize]
+ mova m1, [srcq + 2*cq + 1*mmsize]
+ shufps m2, m0, m1, q2020
+ shufps m1, m0, q1313
+ xorps m2, m3
+ mova [vq], m1
+ mova [vrevq + cq], m2
+ sub vq, mmsize
+ add cq, mmsize
+ jl .loop
+ REP_RET
+
+%macro SBR_AUTOCORRELATE 0
+cglobal sbr_autocorrelate, 2,3,8,32, x, phi, cnt
+ mov cntq, 37*8
+ add xq, cntq
+ neg cntq
+
+%if cpuflag(sse3)
+%define MOVH movsd
+ movddup m5, [xq+cntq]
+%else
+%define MOVH movlps
+ movlps m5, [xq+cntq]
+ movlhps m5, m5
+%endif
+ MOVH m7, [xq+cntq+8 ]
+ MOVH m1, [xq+cntq+16]
+ shufps m7, m7, q0110
+ shufps m1, m1, q0110
+ mulps m3, m5, m7 ; x[0][0] * x[1][0], x[0][1] * x[1][1], x[0][0] * x[1][1], x[0][1] * x[1][0]
+ mulps m4, m5, m5 ; x[0][0] * x[0][0], x[0][1] * x[0][1];
+ mulps m5, m1 ; real_sum2 = x[0][0] * x[2][0], x[0][1] * x[2][1]; imag_sum2 = x[0][0] * x[2][1], x[0][1] * x[2][0]
+ movaps [rsp ], m3
+ movaps [rsp+16], m4
+ add cntq, 8
+
+ MOVH m2, [xq+cntq+16]
+ movlhps m7, m7
+ shufps m2, m2, q0110
+ mulps m6, m7, m1 ; real_sum1 = x[1][0] * x[2][0], x[1][1] * x[2][1]; imag_sum1 += x[1][0] * x[2][1], x[1][1] * x[2][0]
+ mulps m4, m7, m2
+ mulps m7, m7 ; real_sum0 = x[1][0] * x[1][0], x[1][1] * x[1][1];
+ addps m5, m4 ; real_sum2 += x[1][0] * x[3][0], x[1][1] * x[3][1]; imag_sum2 += x[1][0] * x[3][1], x[1][1] * x[3][0]
+
+align 16
+.loop:
+ add cntq, 8
+ MOVH m0, [xq+cntq+16]
+ movlhps m1, m1
+ shufps m0, m0, q0110
+ mulps m3, m1, m2
+ mulps m4, m1, m0
+ mulps m1, m1
+ addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0];
+ addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0];
+ addps m7, m1 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1];
+ add cntq, 8
+ MOVH m1, [xq+cntq+16]
+ movlhps m2, m2
+ shufps m1, m1, q0110
+ mulps m3, m2, m0
+ mulps m4, m2, m1
+ mulps m2, m2
+ addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0];
+ addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0];
+ addps m7, m2 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1];
+ add cntq, 8
+ MOVH m2, [xq+cntq+16]
+ movlhps m0, m0
+ shufps m2, m2, q0110
+ mulps m3, m0, m1
+ mulps m4, m0, m2
+ mulps m0, m0
+ addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0];
+ addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0];
+ addps m7, m0 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1];
+ jl .loop
+
+ movlhps m1, m1
+ mulps m4, m1, m2
+ mulps m1, m1
+ addps m4, m6 ; real_sum1 + x[38][0] * x[39][0], x[38][1] * x[39][1]; imag_sum1 + x[38][0] * x[39][1], x[38][1] * x[39][0];
+ addps m1, m7 ; real_sum0 + x[38][0] * x[38][0], x[38][1] * x[38][1];
+ addps m6, [rsp ] ; real_sum1 + x[ 0][0] * x[ 1][0], x[ 0][1] * x[ 1][1]; imag_sum1 + x[ 0][0] * x[ 1][1], x[ 0][1] * x[ 1][0];
+ addps m7, [rsp+16] ; real_sum0 + x[ 0][0] * x[ 0][0], x[ 0][1] * x[ 0][1];
+
+ xorps m4, [ps_mask3]
+ xorps m5, [ps_mask3]
+ xorps m6, [ps_mask3]
+%if cpuflag(sse3)
+ movshdup m2, m1
+ haddps m4, m5
+ haddps m7, m6
+ addss m1, m2
+%else
+ movaps m3, m4
+ movaps m2, m5
+ movaps m0, m6
+ shufps m3, m3, q0301
+ shufps m2, m2, q0301
+ shufps m0, m0, q0301
+ addps m4, m3
+ addps m5, m2
+ addps m6, m0
+
+ movss m2, m7
+ movss m3, m1
+ shufps m7, m7, q0001
+ shufps m1, m1, q0001
+ addss m7, m2
+ addss m1, m3
+ shufps m4, m5, q2020
+ shufps m7, m6, q2020
+%endif
+ movaps [phiq ], m4
+ movhps [phiq+0x18], m7
+ movss [phiq+0x28], m7
+ movss [phiq+0x10], m1
+ RET
+%endmacro
+
+INIT_XMM sse
+SBR_AUTOCORRELATE
+INIT_XMM sse3
+SBR_AUTOCORRELATE
diff --git a/libavcodec/x86/sbrdsp_init.c b/libavcodec/x86/sbrdsp_init.c
index 9600852163..6911a1a515 100644
--- a/libavcodec/x86/sbrdsp_init.c
+++ b/libavcodec/x86/sbrdsp_init.c
@@ -2,20 +2,20 @@
* AAC Spectral Band Replication decoding functions
* Copyright (c) 2012 Christophe Gisquet <christophe.gisquet@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,9 +34,28 @@ void ff_sbr_hf_gen_sse(float (*X_high)[2], const float (*X_low)[2],
float bw, int start, int end);
void ff_sbr_neg_odd_64_sse(float *z);
void ff_sbr_qmf_post_shuffle_sse(float W[32][2], const float *z);
+void ff_sbr_qmf_deint_bfly_sse(float *v, const float *src0, const float *src1);
void ff_sbr_qmf_deint_bfly_sse2(float *v, const float *src0, const float *src1);
void ff_sbr_qmf_pre_shuffle_sse2(float *z);
+void ff_sbr_hf_apply_noise_0_sse2(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max);
+void ff_sbr_hf_apply_noise_1_sse2(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max);
+void ff_sbr_hf_apply_noise_2_sse2(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max);
+void ff_sbr_hf_apply_noise_3_sse2(float (*Y)[2], const float *s_m,
+ const float *q_filt, int noise,
+ int kx, int m_max);
+
+void ff_sbr_qmf_deint_neg_sse(float *v, const float *src);
+
+void ff_sbr_autocorrelate_sse (const float x[40][2], float phi[3][2][2]);
+void ff_sbr_autocorrelate_sse3(const float x[40][2], float phi[3][2][2]);
+
av_cold void ff_sbrdsp_init_x86(SBRDSPContext *s)
{
int cpu_flags = av_get_cpu_flags();
@@ -48,10 +67,21 @@ av_cold void ff_sbrdsp_init_x86(SBRDSPContext *s)
s->hf_g_filt = ff_sbr_hf_g_filt_sse;
s->hf_gen = ff_sbr_hf_gen_sse;
s->qmf_post_shuffle = ff_sbr_qmf_post_shuffle_sse;
+ s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_sse;
+ s->qmf_deint_neg = ff_sbr_qmf_deint_neg_sse;
+ s->autocorrelate = ff_sbr_autocorrelate_sse;
}
if (EXTERNAL_SSE2(cpu_flags)) {
s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_sse2;
s->qmf_pre_shuffle = ff_sbr_qmf_pre_shuffle_sse2;
+ s->hf_apply_noise[0] = ff_sbr_hf_apply_noise_0_sse2;
+ s->hf_apply_noise[1] = ff_sbr_hf_apply_noise_1_sse2;
+ s->hf_apply_noise[2] = ff_sbr_hf_apply_noise_2_sse2;
+ s->hf_apply_noise[3] = ff_sbr_hf_apply_noise_3_sse2;
+ }
+
+ if (EXTERNAL_SSE3(cpu_flags)) {
+ s->autocorrelate = ff_sbr_autocorrelate_sse3;
}
}
diff --git a/libavcodec/x86/simple_idct.c b/libavcodec/x86/simple_idct.c
index 71763dbf75..1d46212a13 100644
--- a/libavcodec/x86/simple_idct.c
+++ b/libavcodec/x86/simple_idct.c
@@ -3,24 +3,23 @@
*
* Copyright (c) 2001, 2002 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/internal.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
@@ -86,7 +85,7 @@ DECLARE_ALIGNED(8, static const int16_t, coeffs)[]= {
static inline void idct(int16_t *block)
{
- DECLARE_ALIGNED(8, int64_t, align_tmp)[16];
+ LOCAL_ALIGNED_8(int64_t, align_tmp, [16]);
int16_t * const temp= (int16_t*)align_tmp;
__asm__ volatile(
@@ -1148,6 +1147,7 @@ Temp
"9: \n\t"
:: "r" (block), "r" (temp), "r" (coeffs)
+ NAMED_CONSTRAINTS_ADD(wm1010,d40000)
: "%eax"
);
}
diff --git a/libavcodec/x86/simple_idct.h b/libavcodec/x86/simple_idct.h
index 4fc29141b5..4a98732503 100644
--- a/libavcodec/x86/simple_idct.h
+++ b/libavcodec/x86/simple_idct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/snowdsp.c b/libavcodec/x86/snowdsp.c
new file mode 100644
index 0000000000..e2ad511d0a
--- /dev/null
+++ b/libavcodec/x86/snowdsp.c
@@ -0,0 +1,908 @@
+/*
+ * MMX and SSE2 optimized snow DSP utils
+ * Copyright (c) 2005-2006 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/x86/asm.h"
+#include "libavcodec/avcodec.h"
+#include "libavcodec/snow.h"
+#include "libavcodec/snow_dwt.h"
+
+#if HAVE_INLINE_ASM
+
+static void ff_snow_horizontal_compose97i_sse2(IDWTELEM *b, IDWTELEM *temp, int width){
+ const int w2= (width+1)>>1;
+ const int w_l= (width>>1);
+ const int w_r= w2 - 1;
+ int i;
+
+ { // Lift 0
+ IDWTELEM * const ref = b + w2 - 1;
+ IDWTELEM b_0 = b[0]; //By allowing the first entry in b[0] to be calculated twice
+ // (the first time erroneously), we allow the SSE2 code to run an extra pass.
+ // The savings in code and time are well worth having to store this value and
+ // calculate b[0] correctly afterwards.
+
+ i = 0;
+ __asm__ volatile(
+ "pcmpeqd %%xmm7, %%xmm7 \n\t"
+ "pcmpeqd %%xmm3, %%xmm3 \n\t"
+ "psllw $1, %%xmm3 \n\t"
+ "paddw %%xmm7, %%xmm3 \n\t"
+ "psllw $13, %%xmm3 \n\t"
+ ::);
+ for(; i<w_l-15; i+=16){
+ __asm__ volatile(
+ "movdqu (%1), %%xmm1 \n\t"
+ "movdqu 16(%1), %%xmm5 \n\t"
+ "movdqu 2(%1), %%xmm2 \n\t"
+ "movdqu 18(%1), %%xmm6 \n\t"
+ "paddw %%xmm1, %%xmm2 \n\t"
+ "paddw %%xmm5, %%xmm6 \n\t"
+ "paddw %%xmm7, %%xmm2 \n\t"
+ "paddw %%xmm7, %%xmm6 \n\t"
+ "pmulhw %%xmm3, %%xmm2 \n\t"
+ "pmulhw %%xmm3, %%xmm6 \n\t"
+ "paddw (%0), %%xmm2 \n\t"
+ "paddw 16(%0), %%xmm6 \n\t"
+ "movdqa %%xmm2, (%0) \n\t"
+ "movdqa %%xmm6, 16(%0) \n\t"
+ :: "r"(&b[i]), "r"(&ref[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_lift_lead_out(i, b, b, ref, width, w_l, 0, W_DM, W_DO, W_DS);
+ b[0] = b_0 - ((W_DM * 2 * ref[1]+W_DO)>>W_DS);
+ }
+
+ { // Lift 1
+ IDWTELEM * const dst = b+w2;
+
+ i = 0;
+ for(; (((x86_reg)&dst[i]) & 0x1F) && i<w_r; i++){
+ dst[i] = dst[i] - (b[i] + b[i + 1]);
+ }
+ for(; i<w_r-15; i+=16){
+ __asm__ volatile(
+ "movdqu (%1), %%xmm1 \n\t"
+ "movdqu 16(%1), %%xmm5 \n\t"
+ "movdqu 2(%1), %%xmm2 \n\t"
+ "movdqu 18(%1), %%xmm6 \n\t"
+ "paddw %%xmm1, %%xmm2 \n\t"
+ "paddw %%xmm5, %%xmm6 \n\t"
+ "movdqa (%0), %%xmm0 \n\t"
+ "movdqa 16(%0), %%xmm4 \n\t"
+ "psubw %%xmm2, %%xmm0 \n\t"
+ "psubw %%xmm6, %%xmm4 \n\t"
+ "movdqa %%xmm0, (%0) \n\t"
+ "movdqa %%xmm4, 16(%0) \n\t"
+ :: "r"(&dst[i]), "r"(&b[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_lift_lead_out(i, dst, dst, b, width, w_r, 1, W_CM, W_CO, W_CS);
+ }
+
+ { // Lift 2
+ IDWTELEM * const ref = b+w2 - 1;
+ IDWTELEM b_0 = b[0];
+
+ i = 0;
+ __asm__ volatile(
+ "psllw $15, %%xmm7 \n\t"
+ "pcmpeqw %%xmm6, %%xmm6 \n\t"
+ "psrlw $13, %%xmm6 \n\t"
+ "paddw %%xmm7, %%xmm6 \n\t"
+ ::);
+ for(; i<w_l-15; i+=16){
+ __asm__ volatile(
+ "movdqu (%1), %%xmm0 \n\t"
+ "movdqu 16(%1), %%xmm4 \n\t"
+ "movdqu 2(%1), %%xmm1 \n\t"
+ "movdqu 18(%1), %%xmm5 \n\t" //FIXME try aligned reads and shifts
+ "paddw %%xmm6, %%xmm0 \n\t"
+ "paddw %%xmm6, %%xmm4 \n\t"
+ "paddw %%xmm7, %%xmm1 \n\t"
+ "paddw %%xmm7, %%xmm5 \n\t"
+ "pavgw %%xmm1, %%xmm0 \n\t"
+ "pavgw %%xmm5, %%xmm4 \n\t"
+ "psubw %%xmm7, %%xmm0 \n\t"
+ "psubw %%xmm7, %%xmm4 \n\t"
+ "psraw $1, %%xmm0 \n\t"
+ "psraw $1, %%xmm4 \n\t"
+ "movdqa (%0), %%xmm1 \n\t"
+ "movdqa 16(%0), %%xmm5 \n\t"
+ "paddw %%xmm1, %%xmm0 \n\t"
+ "paddw %%xmm5, %%xmm4 \n\t"
+ "psraw $2, %%xmm0 \n\t"
+ "psraw $2, %%xmm4 \n\t"
+ "paddw %%xmm1, %%xmm0 \n\t"
+ "paddw %%xmm5, %%xmm4 \n\t"
+ "movdqa %%xmm0, (%0) \n\t"
+ "movdqa %%xmm4, 16(%0) \n\t"
+ :: "r"(&b[i]), "r"(&ref[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_liftS_lead_out(i, b, b, ref, width, w_l);
+ b[0] = b_0 + ((2 * ref[1] + W_BO-1 + 4 * b_0) >> W_BS);
+ }
+
+ { // Lift 3
+ IDWTELEM * const src = b+w2;
+
+ i = 0;
+ for(; (((x86_reg)&temp[i]) & 0x1F) && i<w_r; i++){
+ temp[i] = src[i] - ((-W_AM*(b[i] + b[i+1]))>>W_AS);
+ }
+ for(; i<w_r-7; i+=8){
+ __asm__ volatile(
+ "movdqu 2(%1), %%xmm2 \n\t"
+ "movdqu 18(%1), %%xmm6 \n\t"
+ "paddw (%1), %%xmm2 \n\t"
+ "paddw 16(%1), %%xmm6 \n\t"
+ "movdqu (%0), %%xmm0 \n\t"
+ "movdqu 16(%0), %%xmm4 \n\t"
+ "paddw %%xmm2, %%xmm0 \n\t"
+ "paddw %%xmm6, %%xmm4 \n\t"
+ "psraw $1, %%xmm2 \n\t"
+ "psraw $1, %%xmm6 \n\t"
+ "paddw %%xmm0, %%xmm2 \n\t"
+ "paddw %%xmm4, %%xmm6 \n\t"
+ "movdqa %%xmm2, (%2) \n\t"
+ "movdqa %%xmm6, 16(%2) \n\t"
+ :: "r"(&src[i]), "r"(&b[i]), "r"(&temp[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_lift_lead_out(i, temp, src, b, width, w_r, 1, -W_AM, W_AO+1, W_AS);
+ }
+
+ {
+ snow_interleave_line_header(&i, width, b, temp);
+
+ for (; (i & 0x3E) != 0x3E; i-=2){
+ b[i+1] = temp[i>>1];
+ b[i] = b[i>>1];
+ }
+ for (i-=62; i>=0; i-=64){
+ __asm__ volatile(
+ "movdqa (%1), %%xmm0 \n\t"
+ "movdqa 16(%1), %%xmm2 \n\t"
+ "movdqa 32(%1), %%xmm4 \n\t"
+ "movdqa 48(%1), %%xmm6 \n\t"
+ "movdqa (%1), %%xmm1 \n\t"
+ "movdqa 16(%1), %%xmm3 \n\t"
+ "movdqa 32(%1), %%xmm5 \n\t"
+ "movdqa 48(%1), %%xmm7 \n\t"
+ "punpcklwd (%2), %%xmm0 \n\t"
+ "punpcklwd 16(%2), %%xmm2 \n\t"
+ "punpcklwd 32(%2), %%xmm4 \n\t"
+ "punpcklwd 48(%2), %%xmm6 \n\t"
+ "movdqa %%xmm0, (%0) \n\t"
+ "movdqa %%xmm2, 32(%0) \n\t"
+ "movdqa %%xmm4, 64(%0) \n\t"
+ "movdqa %%xmm6, 96(%0) \n\t"
+ "punpckhwd (%2), %%xmm1 \n\t"
+ "punpckhwd 16(%2), %%xmm3 \n\t"
+ "punpckhwd 32(%2), %%xmm5 \n\t"
+ "punpckhwd 48(%2), %%xmm7 \n\t"
+ "movdqa %%xmm1, 16(%0) \n\t"
+ "movdqa %%xmm3, 48(%0) \n\t"
+ "movdqa %%xmm5, 80(%0) \n\t"
+ "movdqa %%xmm7, 112(%0) \n\t"
+ :: "r"(&(b)[i]), "r"(&(b)[i>>1]), "r"(&(temp)[i>>1])
+ : "memory"
+ );
+ }
+ }
+}
+
+static void ff_snow_horizontal_compose97i_mmx(IDWTELEM *b, IDWTELEM *temp, int width){
+ const int w2= (width+1)>>1;
+ const int w_l= (width>>1);
+ const int w_r= w2 - 1;
+ int i;
+
+ { // Lift 0
+ IDWTELEM * const ref = b + w2 - 1;
+
+ i = 1;
+ b[0] = b[0] - ((W_DM * 2 * ref[1]+W_DO)>>W_DS);
+ __asm__ volatile(
+ "pcmpeqw %%mm7, %%mm7 \n\t"
+ "pcmpeqw %%mm3, %%mm3 \n\t"
+ "psllw $1, %%mm3 \n\t"
+ "paddw %%mm7, %%mm3 \n\t"
+ "psllw $13, %%mm3 \n\t"
+ ::);
+ for(; i<w_l-7; i+=8){
+ __asm__ volatile(
+ "movq (%1), %%mm2 \n\t"
+ "movq 8(%1), %%mm6 \n\t"
+ "paddw 2(%1), %%mm2 \n\t"
+ "paddw 10(%1), %%mm6 \n\t"
+ "paddw %%mm7, %%mm2 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+ "pmulhw %%mm3, %%mm2 \n\t"
+ "pmulhw %%mm3, %%mm6 \n\t"
+ "paddw (%0), %%mm2 \n\t"
+ "paddw 8(%0), %%mm6 \n\t"
+ "movq %%mm2, (%0) \n\t"
+ "movq %%mm6, 8(%0) \n\t"
+ :: "r"(&b[i]), "r"(&ref[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_lift_lead_out(i, b, b, ref, width, w_l, 0, W_DM, W_DO, W_DS);
+ }
+
+ { // Lift 1
+ IDWTELEM * const dst = b+w2;
+
+ i = 0;
+ for(; i<w_r-7; i+=8){
+ __asm__ volatile(
+ "movq (%1), %%mm2 \n\t"
+ "movq 8(%1), %%mm6 \n\t"
+ "paddw 2(%1), %%mm2 \n\t"
+ "paddw 10(%1), %%mm6 \n\t"
+ "movq (%0), %%mm0 \n\t"
+ "movq 8(%0), %%mm4 \n\t"
+ "psubw %%mm2, %%mm0 \n\t"
+ "psubw %%mm6, %%mm4 \n\t"
+ "movq %%mm0, (%0) \n\t"
+ "movq %%mm4, 8(%0) \n\t"
+ :: "r"(&dst[i]), "r"(&b[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_lift_lead_out(i, dst, dst, b, width, w_r, 1, W_CM, W_CO, W_CS);
+ }
+
+ { // Lift 2
+ IDWTELEM * const ref = b+w2 - 1;
+
+ i = 1;
+ b[0] = b[0] + (((2 * ref[1] + W_BO) + 4 * b[0]) >> W_BS);
+ __asm__ volatile(
+ "psllw $15, %%mm7 \n\t"
+ "pcmpeqw %%mm6, %%mm6 \n\t"
+ "psrlw $13, %%mm6 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+ ::);
+ for(; i<w_l-7; i+=8){
+ __asm__ volatile(
+ "movq (%1), %%mm0 \n\t"
+ "movq 8(%1), %%mm4 \n\t"
+ "movq 2(%1), %%mm1 \n\t"
+ "movq 10(%1), %%mm5 \n\t"
+ "paddw %%mm6, %%mm0 \n\t"
+ "paddw %%mm6, %%mm4 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "paddw %%mm7, %%mm5 \n\t"
+ "pavgw %%mm1, %%mm0 \n\t"
+ "pavgw %%mm5, %%mm4 \n\t"
+ "psubw %%mm7, %%mm0 \n\t"
+ "psubw %%mm7, %%mm4 \n\t"
+ "psraw $1, %%mm0 \n\t"
+ "psraw $1, %%mm4 \n\t"
+ "movq (%0), %%mm1 \n\t"
+ "movq 8(%0), %%mm5 \n\t"
+ "paddw %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm4 \n\t"
+ "psraw $2, %%mm0 \n\t"
+ "psraw $2, %%mm4 \n\t"
+ "paddw %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm4 \n\t"
+ "movq %%mm0, (%0) \n\t"
+ "movq %%mm4, 8(%0) \n\t"
+ :: "r"(&b[i]), "r"(&ref[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_liftS_lead_out(i, b, b, ref, width, w_l);
+ }
+
+ { // Lift 3
+ IDWTELEM * const src = b+w2;
+ i = 0;
+
+ for(; i<w_r-7; i+=8){
+ __asm__ volatile(
+ "movq 2(%1), %%mm2 \n\t"
+ "movq 10(%1), %%mm6 \n\t"
+ "paddw (%1), %%mm2 \n\t"
+ "paddw 8(%1), %%mm6 \n\t"
+ "movq (%0), %%mm0 \n\t"
+ "movq 8(%0), %%mm4 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ "paddw %%mm6, %%mm4 \n\t"
+ "psraw $1, %%mm2 \n\t"
+ "psraw $1, %%mm6 \n\t"
+ "paddw %%mm0, %%mm2 \n\t"
+ "paddw %%mm4, %%mm6 \n\t"
+ "movq %%mm2, (%2) \n\t"
+ "movq %%mm6, 8(%2) \n\t"
+ :: "r"(&src[i]), "r"(&b[i]), "r"(&temp[i])
+ : "memory"
+ );
+ }
+ snow_horizontal_compose_lift_lead_out(i, temp, src, b, width, w_r, 1, -W_AM, W_AO+1, W_AS);
+ }
+
+ {
+ snow_interleave_line_header(&i, width, b, temp);
+
+ for (; (i & 0x1E) != 0x1E; i-=2){
+ b[i+1] = temp[i>>1];
+ b[i] = b[i>>1];
+ }
+ for (i-=30; i>=0; i-=32){
+ __asm__ volatile(
+ "movq (%1), %%mm0 \n\t"
+ "movq 8(%1), %%mm2 \n\t"
+ "movq 16(%1), %%mm4 \n\t"
+ "movq 24(%1), %%mm6 \n\t"
+ "movq (%1), %%mm1 \n\t"
+ "movq 8(%1), %%mm3 \n\t"
+ "movq 16(%1), %%mm5 \n\t"
+ "movq 24(%1), %%mm7 \n\t"
+ "punpcklwd (%2), %%mm0 \n\t"
+ "punpcklwd 8(%2), %%mm2 \n\t"
+ "punpcklwd 16(%2), %%mm4 \n\t"
+ "punpcklwd 24(%2), %%mm6 \n\t"
+ "movq %%mm0, (%0) \n\t"
+ "movq %%mm2, 16(%0) \n\t"
+ "movq %%mm4, 32(%0) \n\t"
+ "movq %%mm6, 48(%0) \n\t"
+ "punpckhwd (%2), %%mm1 \n\t"
+ "punpckhwd 8(%2), %%mm3 \n\t"
+ "punpckhwd 16(%2), %%mm5 \n\t"
+ "punpckhwd 24(%2), %%mm7 \n\t"
+ "movq %%mm1, 8(%0) \n\t"
+ "movq %%mm3, 24(%0) \n\t"
+ "movq %%mm5, 40(%0) \n\t"
+ "movq %%mm7, 56(%0) \n\t"
+ :: "r"(&b[i]), "r"(&b[i>>1]), "r"(&temp[i>>1])
+ : "memory"
+ );
+ }
+ }
+}
+
+#if HAVE_7REGS
+#define snow_vertical_compose_sse2_load_add(op,r,t0,t1,t2,t3)\
+ ""op" ("r",%%"REG_d"), %%"t0" \n\t"\
+ ""op" 16("r",%%"REG_d"), %%"t1" \n\t"\
+ ""op" 32("r",%%"REG_d"), %%"t2" \n\t"\
+ ""op" 48("r",%%"REG_d"), %%"t3" \n\t"
+
+#define snow_vertical_compose_sse2_load(r,t0,t1,t2,t3)\
+ snow_vertical_compose_sse2_load_add("movdqa",r,t0,t1,t2,t3)
+
+#define snow_vertical_compose_sse2_add(r,t0,t1,t2,t3)\
+ snow_vertical_compose_sse2_load_add("paddw",r,t0,t1,t2,t3)
+
+#define snow_vertical_compose_r2r_sub(s0,s1,s2,s3,t0,t1,t2,t3)\
+ "psubw %%"s0", %%"t0" \n\t"\
+ "psubw %%"s1", %%"t1" \n\t"\
+ "psubw %%"s2", %%"t2" \n\t"\
+ "psubw %%"s3", %%"t3" \n\t"
+
+#define snow_vertical_compose_sse2_store(w,s0,s1,s2,s3)\
+ "movdqa %%"s0", ("w",%%"REG_d") \n\t"\
+ "movdqa %%"s1", 16("w",%%"REG_d") \n\t"\
+ "movdqa %%"s2", 32("w",%%"REG_d") \n\t"\
+ "movdqa %%"s3", 48("w",%%"REG_d") \n\t"
+
+#define snow_vertical_compose_sra(n,t0,t1,t2,t3)\
+ "psraw $"n", %%"t0" \n\t"\
+ "psraw $"n", %%"t1" \n\t"\
+ "psraw $"n", %%"t2" \n\t"\
+ "psraw $"n", %%"t3" \n\t"
+
+#define snow_vertical_compose_r2r_add(s0,s1,s2,s3,t0,t1,t2,t3)\
+ "paddw %%"s0", %%"t0" \n\t"\
+ "paddw %%"s1", %%"t1" \n\t"\
+ "paddw %%"s2", %%"t2" \n\t"\
+ "paddw %%"s3", %%"t3" \n\t"
+
+#define snow_vertical_compose_r2r_pmulhw(s0,s1,s2,s3,t0,t1,t2,t3)\
+ "pmulhw %%"s0", %%"t0" \n\t"\
+ "pmulhw %%"s1", %%"t1" \n\t"\
+ "pmulhw %%"s2", %%"t2" \n\t"\
+ "pmulhw %%"s3", %%"t3" \n\t"
+
+#define snow_vertical_compose_sse2_move(s0,s1,s2,s3,t0,t1,t2,t3)\
+ "movdqa %%"s0", %%"t0" \n\t"\
+ "movdqa %%"s1", %%"t1" \n\t"\
+ "movdqa %%"s2", %%"t2" \n\t"\
+ "movdqa %%"s3", %%"t3" \n\t"
+
+static void ff_snow_vertical_compose97i_sse2(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){
+ x86_reg i = width;
+
+ while(i & 0x1F)
+ {
+ i--;
+ b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS;
+ b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS;
+ b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS;
+ b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS;
+ }
+ i+=i;
+
+ __asm__ volatile (
+ "jmp 2f \n\t"
+ "1: \n\t"
+ snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_add("%6","xmm0","xmm2","xmm4","xmm6")
+
+
+ "pcmpeqw %%xmm0, %%xmm0 \n\t"
+ "pcmpeqw %%xmm2, %%xmm2 \n\t"
+ "paddw %%xmm2, %%xmm2 \n\t"
+ "paddw %%xmm0, %%xmm2 \n\t"
+ "psllw $13, %%xmm2 \n\t"
+ snow_vertical_compose_r2r_add("xmm0","xmm0","xmm0","xmm0","xmm1","xmm3","xmm5","xmm7")
+ snow_vertical_compose_r2r_pmulhw("xmm2","xmm2","xmm2","xmm2","xmm1","xmm3","xmm5","xmm7")
+ snow_vertical_compose_sse2_add("%5","xmm1","xmm3","xmm5","xmm7")
+ snow_vertical_compose_sse2_store("%5","xmm1","xmm3","xmm5","xmm7")
+ snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_add("%3","xmm1","xmm3","xmm5","xmm7")
+ snow_vertical_compose_r2r_sub("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_store("%4","xmm0","xmm2","xmm4","xmm6")
+
+ "pcmpeqw %%xmm7, %%xmm7 \n\t"
+ "pcmpeqw %%xmm5, %%xmm5 \n\t"
+ "psllw $15, %%xmm7 \n\t"
+ "psrlw $13, %%xmm5 \n\t"
+ "paddw %%xmm7, %%xmm5 \n\t"
+ snow_vertical_compose_r2r_add("xmm5","xmm5","xmm5","xmm5","xmm0","xmm2","xmm4","xmm6")
+ "movq (%2,%%"REG_d"), %%xmm1 \n\t"
+ "movq 8(%2,%%"REG_d"), %%xmm3 \n\t"
+ "paddw %%xmm7, %%xmm1 \n\t"
+ "paddw %%xmm7, %%xmm3 \n\t"
+ "pavgw %%xmm1, %%xmm0 \n\t"
+ "pavgw %%xmm3, %%xmm2 \n\t"
+ "movq 16(%2,%%"REG_d"), %%xmm1 \n\t"
+ "movq 24(%2,%%"REG_d"), %%xmm3 \n\t"
+ "paddw %%xmm7, %%xmm1 \n\t"
+ "paddw %%xmm7, %%xmm3 \n\t"
+ "pavgw %%xmm1, %%xmm4 \n\t"
+ "pavgw %%xmm3, %%xmm6 \n\t"
+ snow_vertical_compose_r2r_sub("xmm7","xmm7","xmm7","xmm7","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6")
+
+ snow_vertical_compose_sra("2","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_store("%3","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_add("%1","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_move("xmm0","xmm2","xmm4","xmm6","xmm1","xmm3","xmm5","xmm7")
+ snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_r2r_add("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_add("%2","xmm0","xmm2","xmm4","xmm6")
+ snow_vertical_compose_sse2_store("%2","xmm0","xmm2","xmm4","xmm6")
+
+ "2: \n\t"
+ "sub $64, %%"REG_d" \n\t"
+ "jge 1b \n\t"
+ :"+d"(i)
+ :"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5));
+}
+
+#define snow_vertical_compose_mmx_load_add(op,r,t0,t1,t2,t3)\
+ ""op" ("r",%%"REG_d"), %%"t0" \n\t"\
+ ""op" 8("r",%%"REG_d"), %%"t1" \n\t"\
+ ""op" 16("r",%%"REG_d"), %%"t2" \n\t"\
+ ""op" 24("r",%%"REG_d"), %%"t3" \n\t"
+
+#define snow_vertical_compose_mmx_load(r,t0,t1,t2,t3)\
+ snow_vertical_compose_mmx_load_add("movq",r,t0,t1,t2,t3)
+
+#define snow_vertical_compose_mmx_add(r,t0,t1,t2,t3)\
+ snow_vertical_compose_mmx_load_add("paddw",r,t0,t1,t2,t3)
+
+#define snow_vertical_compose_mmx_store(w,s0,s1,s2,s3)\
+ "movq %%"s0", ("w",%%"REG_d") \n\t"\
+ "movq %%"s1", 8("w",%%"REG_d") \n\t"\
+ "movq %%"s2", 16("w",%%"REG_d") \n\t"\
+ "movq %%"s3", 24("w",%%"REG_d") \n\t"
+
+#define snow_vertical_compose_mmx_move(s0,s1,s2,s3,t0,t1,t2,t3)\
+ "movq %%"s0", %%"t0" \n\t"\
+ "movq %%"s1", %%"t1" \n\t"\
+ "movq %%"s2", %%"t2" \n\t"\
+ "movq %%"s3", %%"t3" \n\t"
+
+
+static void ff_snow_vertical_compose97i_mmx(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){
+ x86_reg i = width;
+ while(i & 15)
+ {
+ i--;
+ b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS;
+ b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS;
+ b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS;
+ b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS;
+ }
+ i+=i;
+ __asm__ volatile(
+ "jmp 2f \n\t"
+ "1: \n\t"
+
+ snow_vertical_compose_mmx_load("%4","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_mmx_add("%6","mm1","mm3","mm5","mm7")
+ "pcmpeqw %%mm0, %%mm0 \n\t"
+ "pcmpeqw %%mm2, %%mm2 \n\t"
+ "paddw %%mm2, %%mm2 \n\t"
+ "paddw %%mm0, %%mm2 \n\t"
+ "psllw $13, %%mm2 \n\t"
+ snow_vertical_compose_r2r_add("mm0","mm0","mm0","mm0","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_r2r_pmulhw("mm2","mm2","mm2","mm2","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_mmx_add("%5","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_mmx_store("%5","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_mmx_load("%4","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_add("%3","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_r2r_sub("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_store("%4","mm0","mm2","mm4","mm6")
+ "pcmpeqw %%mm7, %%mm7 \n\t"
+ "pcmpeqw %%mm5, %%mm5 \n\t"
+ "psllw $15, %%mm7 \n\t"
+ "psrlw $13, %%mm5 \n\t"
+ "paddw %%mm7, %%mm5 \n\t"
+ snow_vertical_compose_r2r_add("mm5","mm5","mm5","mm5","mm0","mm2","mm4","mm6")
+ "movq (%2,%%"REG_d"), %%mm1 \n\t"
+ "movq 8(%2,%%"REG_d"), %%mm3 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "paddw %%mm7, %%mm3 \n\t"
+ "pavgw %%mm1, %%mm0 \n\t"
+ "pavgw %%mm3, %%mm2 \n\t"
+ "movq 16(%2,%%"REG_d"), %%mm1 \n\t"
+ "movq 24(%2,%%"REG_d"), %%mm3 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "paddw %%mm7, %%mm3 \n\t"
+ "pavgw %%mm1, %%mm4 \n\t"
+ "pavgw %%mm3, %%mm6 \n\t"
+ snow_vertical_compose_r2r_sub("mm7","mm7","mm7","mm7","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6")
+
+ snow_vertical_compose_sra("2","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_store("%3","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_add("%1","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_move("mm0","mm2","mm4","mm6","mm1","mm3","mm5","mm7")
+ snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_r2r_add("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_add("%2","mm0","mm2","mm4","mm6")
+ snow_vertical_compose_mmx_store("%2","mm0","mm2","mm4","mm6")
+
+ "2: \n\t"
+ "sub $32, %%"REG_d" \n\t"
+ "jge 1b \n\t"
+ :"+d"(i)
+ :"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5));
+}
+#endif //HAVE_7REGS
+
+#if HAVE_6REGS
+#define snow_inner_add_yblock_sse2_header \
+ IDWTELEM * * dst_array = sb->line + src_y;\
+ x86_reg tmp;\
+ __asm__ volatile(\
+ "mov %7, %%"REG_c" \n\t"\
+ "mov %6, %2 \n\t"\
+ "mov %4, %%"REG_S" \n\t"\
+ "pxor %%xmm7, %%xmm7 \n\t" /* 0 */\
+ "pcmpeqd %%xmm3, %%xmm3 \n\t"\
+ "psllw $15, %%xmm3 \n\t"\
+ "psrlw $12, %%xmm3 \n\t" /* FRAC_BITS >> 1 */\
+ "1: \n\t"\
+ "mov %1, %%"REG_D" \n\t"\
+ "mov (%%"REG_D"), %%"REG_D" \n\t"\
+ "add %3, %%"REG_D" \n\t"
+
+#define snow_inner_add_yblock_sse2_start_8(out_reg1, out_reg2, ptr_offset, s_offset)\
+ "mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
+ "movq (%%"REG_d"), %%"out_reg1" \n\t"\
+ "movq (%%"REG_d", %%"REG_c"), %%"out_reg2" \n\t"\
+ "punpcklbw %%xmm7, %%"out_reg1" \n\t"\
+ "punpcklbw %%xmm7, %%"out_reg2" \n\t"\
+ "movq "s_offset"(%%"REG_S"), %%xmm0 \n\t"\
+ "movq "s_offset"+16(%%"REG_S"), %%xmm4 \n\t"\
+ "punpcklbw %%xmm7, %%xmm0 \n\t"\
+ "punpcklbw %%xmm7, %%xmm4 \n\t"\
+ "pmullw %%xmm0, %%"out_reg1" \n\t"\
+ "pmullw %%xmm4, %%"out_reg2" \n\t"
+
+#define snow_inner_add_yblock_sse2_start_16(out_reg1, out_reg2, ptr_offset, s_offset)\
+ "mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
+ "movq (%%"REG_d"), %%"out_reg1" \n\t"\
+ "movq 8(%%"REG_d"), %%"out_reg2" \n\t"\
+ "punpcklbw %%xmm7, %%"out_reg1" \n\t"\
+ "punpcklbw %%xmm7, %%"out_reg2" \n\t"\
+ "movq "s_offset"(%%"REG_S"), %%xmm0 \n\t"\
+ "movq "s_offset"+8(%%"REG_S"), %%xmm4 \n\t"\
+ "punpcklbw %%xmm7, %%xmm0 \n\t"\
+ "punpcklbw %%xmm7, %%xmm4 \n\t"\
+ "pmullw %%xmm0, %%"out_reg1" \n\t"\
+ "pmullw %%xmm4, %%"out_reg2" \n\t"
+
+#define snow_inner_add_yblock_sse2_accum_8(ptr_offset, s_offset) \
+ snow_inner_add_yblock_sse2_start_8("xmm2", "xmm6", ptr_offset, s_offset)\
+ "paddusw %%xmm2, %%xmm1 \n\t"\
+ "paddusw %%xmm6, %%xmm5 \n\t"
+
+#define snow_inner_add_yblock_sse2_accum_16(ptr_offset, s_offset) \
+ snow_inner_add_yblock_sse2_start_16("xmm2", "xmm6", ptr_offset, s_offset)\
+ "paddusw %%xmm2, %%xmm1 \n\t"\
+ "paddusw %%xmm6, %%xmm5 \n\t"
+
+#define snow_inner_add_yblock_sse2_end_common1\
+ "add $32, %%"REG_S" \n\t"\
+ "add %%"REG_c", %0 \n\t"\
+ "add %%"REG_c", "PTR_SIZE"*3(%%"REG_a");\n\t"\
+ "add %%"REG_c", "PTR_SIZE"*2(%%"REG_a");\n\t"\
+ "add %%"REG_c", "PTR_SIZE"*1(%%"REG_a");\n\t"\
+ "add %%"REG_c", (%%"REG_a") \n\t"
+
+#define snow_inner_add_yblock_sse2_end_common2\
+ "jnz 1b \n\t"\
+ :"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\
+ :\
+ "rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"(b_h),"m"(src_stride):\
+ XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", )\
+ "%"REG_c"","%"REG_S"","%"REG_D"","%"REG_d"");
+
+#define snow_inner_add_yblock_sse2_end_8\
+ "sal $1, %%"REG_c" \n\t"\
+ "add"OPSIZE" $"PTR_SIZE"*2, %1 \n\t"\
+ snow_inner_add_yblock_sse2_end_common1\
+ "sar $1, %%"REG_c" \n\t"\
+ "sub $2, %2 \n\t"\
+ snow_inner_add_yblock_sse2_end_common2
+
+#define snow_inner_add_yblock_sse2_end_16\
+ "add"OPSIZE" $"PTR_SIZE"*1, %1 \n\t"\
+ snow_inner_add_yblock_sse2_end_common1\
+ "dec %2 \n\t"\
+ snow_inner_add_yblock_sse2_end_common2
+
+static void inner_add_yblock_bw_8_obmc_16_bh_even_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
+ int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+snow_inner_add_yblock_sse2_header
+snow_inner_add_yblock_sse2_start_8("xmm1", "xmm5", "3", "0")
+snow_inner_add_yblock_sse2_accum_8("2", "8")
+snow_inner_add_yblock_sse2_accum_8("1", "128")
+snow_inner_add_yblock_sse2_accum_8("0", "136")
+
+ "mov %0, %%"REG_d" \n\t"
+ "movdqa (%%"REG_D"), %%xmm0 \n\t"
+ "movdqa %%xmm1, %%xmm2 \n\t"
+
+ "punpckhwd %%xmm7, %%xmm1 \n\t"
+ "punpcklwd %%xmm7, %%xmm2 \n\t"
+ "paddd %%xmm2, %%xmm0 \n\t"
+ "movdqa 16(%%"REG_D"), %%xmm2 \n\t"
+ "paddd %%xmm1, %%xmm2 \n\t"
+ "paddd %%xmm3, %%xmm0 \n\t"
+ "paddd %%xmm3, %%xmm2 \n\t"
+
+ "mov %1, %%"REG_D" \n\t"
+ "mov "PTR_SIZE"(%%"REG_D"), %%"REG_D";\n\t"
+ "add %3, %%"REG_D" \n\t"
+
+ "movdqa (%%"REG_D"), %%xmm4 \n\t"
+ "movdqa %%xmm5, %%xmm6 \n\t"
+ "punpckhwd %%xmm7, %%xmm5 \n\t"
+ "punpcklwd %%xmm7, %%xmm6 \n\t"
+ "paddd %%xmm6, %%xmm4 \n\t"
+ "movdqa 16(%%"REG_D"), %%xmm6 \n\t"
+ "paddd %%xmm5, %%xmm6 \n\t"
+ "paddd %%xmm3, %%xmm4 \n\t"
+ "paddd %%xmm3, %%xmm6 \n\t"
+
+ "psrad $8, %%xmm0 \n\t" /* FRAC_BITS. */
+ "psrad $8, %%xmm2 \n\t" /* FRAC_BITS. */
+ "packssdw %%xmm2, %%xmm0 \n\t"
+ "packuswb %%xmm7, %%xmm0 \n\t"
+ "movq %%xmm0, (%%"REG_d") \n\t"
+
+ "psrad $8, %%xmm4 \n\t" /* FRAC_BITS. */
+ "psrad $8, %%xmm6 \n\t" /* FRAC_BITS. */
+ "packssdw %%xmm6, %%xmm4 \n\t"
+ "packuswb %%xmm7, %%xmm4 \n\t"
+ "movq %%xmm4, (%%"REG_d",%%"REG_c");\n\t"
+snow_inner_add_yblock_sse2_end_8
+}
+
+static void inner_add_yblock_bw_16_obmc_32_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
+ int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+snow_inner_add_yblock_sse2_header
+snow_inner_add_yblock_sse2_start_16("xmm1", "xmm5", "3", "0")
+snow_inner_add_yblock_sse2_accum_16("2", "16")
+snow_inner_add_yblock_sse2_accum_16("1", "512")
+snow_inner_add_yblock_sse2_accum_16("0", "528")
+
+ "mov %0, %%"REG_d" \n\t"
+ "psrlw $4, %%xmm1 \n\t"
+ "psrlw $4, %%xmm5 \n\t"
+ "paddw (%%"REG_D"), %%xmm1 \n\t"
+ "paddw 16(%%"REG_D"), %%xmm5 \n\t"
+ "paddw %%xmm3, %%xmm1 \n\t"
+ "paddw %%xmm3, %%xmm5 \n\t"
+ "psraw $4, %%xmm1 \n\t" /* FRAC_BITS. */
+ "psraw $4, %%xmm5 \n\t" /* FRAC_BITS. */
+ "packuswb %%xmm5, %%xmm1 \n\t"
+
+ "movdqu %%xmm1, (%%"REG_d") \n\t"
+
+snow_inner_add_yblock_sse2_end_16
+}
+
+#define snow_inner_add_yblock_mmx_header \
+ IDWTELEM * * dst_array = sb->line + src_y;\
+ x86_reg tmp;\
+ __asm__ volatile(\
+ "mov %7, %%"REG_c" \n\t"\
+ "mov %6, %2 \n\t"\
+ "mov %4, %%"REG_S" \n\t"\
+ "pxor %%mm7, %%mm7 \n\t" /* 0 */\
+ "pcmpeqd %%mm3, %%mm3 \n\t"\
+ "psllw $15, %%mm3 \n\t"\
+ "psrlw $12, %%mm3 \n\t" /* FRAC_BITS >> 1 */\
+ "1: \n\t"\
+ "mov %1, %%"REG_D" \n\t"\
+ "mov (%%"REG_D"), %%"REG_D" \n\t"\
+ "add %3, %%"REG_D" \n\t"
+
+#define snow_inner_add_yblock_mmx_start(out_reg1, out_reg2, ptr_offset, s_offset, d_offset)\
+ "mov "PTR_SIZE"*"ptr_offset"(%%"REG_a"), %%"REG_d"; \n\t"\
+ "movd "d_offset"(%%"REG_d"), %%"out_reg1" \n\t"\
+ "movd "d_offset"+4(%%"REG_d"), %%"out_reg2" \n\t"\
+ "punpcklbw %%mm7, %%"out_reg1" \n\t"\
+ "punpcklbw %%mm7, %%"out_reg2" \n\t"\
+ "movd "s_offset"(%%"REG_S"), %%mm0 \n\t"\
+ "movd "s_offset"+4(%%"REG_S"), %%mm4 \n\t"\
+ "punpcklbw %%mm7, %%mm0 \n\t"\
+ "punpcklbw %%mm7, %%mm4 \n\t"\
+ "pmullw %%mm0, %%"out_reg1" \n\t"\
+ "pmullw %%mm4, %%"out_reg2" \n\t"
+
+#define snow_inner_add_yblock_mmx_accum(ptr_offset, s_offset, d_offset) \
+ snow_inner_add_yblock_mmx_start("mm2", "mm6", ptr_offset, s_offset, d_offset)\
+ "paddusw %%mm2, %%mm1 \n\t"\
+ "paddusw %%mm6, %%mm5 \n\t"
+
+#define snow_inner_add_yblock_mmx_mix(read_offset, write_offset)\
+ "mov %0, %%"REG_d" \n\t"\
+ "psrlw $4, %%mm1 \n\t"\
+ "psrlw $4, %%mm5 \n\t"\
+ "paddw "read_offset"(%%"REG_D"), %%mm1 \n\t"\
+ "paddw "read_offset"+8(%%"REG_D"), %%mm5 \n\t"\
+ "paddw %%mm3, %%mm1 \n\t"\
+ "paddw %%mm3, %%mm5 \n\t"\
+ "psraw $4, %%mm1 \n\t"\
+ "psraw $4, %%mm5 \n\t"\
+ "packuswb %%mm5, %%mm1 \n\t"\
+ "movq %%mm1, "write_offset"(%%"REG_d") \n\t"
+
+#define snow_inner_add_yblock_mmx_end(s_step)\
+ "add $"s_step", %%"REG_S" \n\t"\
+ "add %%"REG_c", "PTR_SIZE"*3(%%"REG_a");\n\t"\
+ "add %%"REG_c", "PTR_SIZE"*2(%%"REG_a");\n\t"\
+ "add %%"REG_c", "PTR_SIZE"*1(%%"REG_a");\n\t"\
+ "add %%"REG_c", (%%"REG_a") \n\t"\
+ "add"OPSIZE " $"PTR_SIZE"*1, %1 \n\t"\
+ "add %%"REG_c", %0 \n\t"\
+ "dec %2 \n\t"\
+ "jnz 1b \n\t"\
+ :"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\
+ :\
+ "rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"(b_h),"m"(src_stride):\
+ "%"REG_c"","%"REG_S"","%"REG_D"","%"REG_d"");
+
+static void inner_add_yblock_bw_8_obmc_16_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
+ int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+snow_inner_add_yblock_mmx_header
+snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0")
+snow_inner_add_yblock_mmx_accum("2", "8", "0")
+snow_inner_add_yblock_mmx_accum("1", "128", "0")
+snow_inner_add_yblock_mmx_accum("0", "136", "0")
+snow_inner_add_yblock_mmx_mix("0", "0")
+snow_inner_add_yblock_mmx_end("16")
+}
+
+static void inner_add_yblock_bw_16_obmc_32_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h,
+ int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+snow_inner_add_yblock_mmx_header
+snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0")
+snow_inner_add_yblock_mmx_accum("2", "16", "0")
+snow_inner_add_yblock_mmx_accum("1", "512", "0")
+snow_inner_add_yblock_mmx_accum("0", "528", "0")
+snow_inner_add_yblock_mmx_mix("0", "0")
+
+snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "8", "8")
+snow_inner_add_yblock_mmx_accum("2", "24", "8")
+snow_inner_add_yblock_mmx_accum("1", "520", "8")
+snow_inner_add_yblock_mmx_accum("0", "536", "8")
+snow_inner_add_yblock_mmx_mix("16", "8")
+snow_inner_add_yblock_mmx_end("32")
+}
+
+static void ff_snow_inner_add_yblock_sse2(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
+ int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+
+ if (b_w == 16)
+ inner_add_yblock_bw_16_obmc_32_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+ else if (b_w == 8 && obmc_stride == 16) {
+ if (!(b_h & 1))
+ inner_add_yblock_bw_8_obmc_16_bh_even_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+ else
+ inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+ } else
+ ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+}
+
+static void ff_snow_inner_add_yblock_mmx(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h,
+ int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){
+ if (b_w == 16)
+ inner_add_yblock_bw_16_obmc_32_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+ else if (b_w == 8 && obmc_stride == 16)
+ inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+ else
+ ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8);
+}
+#endif /* HAVE_6REGS */
+
+#endif /* HAVE_INLINE_ASM */
+
+av_cold void ff_dwt_init_x86(SnowDWTContext *c)
+{
+#if HAVE_INLINE_ASM
+ int mm_flags = av_get_cpu_flags();
+
+ if (mm_flags & AV_CPU_FLAG_MMX) {
+ if(mm_flags & AV_CPU_FLAG_SSE2 & 0){
+ c->horizontal_compose97i = ff_snow_horizontal_compose97i_sse2;
+#if HAVE_7REGS
+ c->vertical_compose97i = ff_snow_vertical_compose97i_sse2;
+#endif
+#if HAVE_6REGS
+ c->inner_add_yblock = ff_snow_inner_add_yblock_sse2;
+#endif
+ }
+ else{
+ if (mm_flags & AV_CPU_FLAG_MMXEXT) {
+ c->horizontal_compose97i = ff_snow_horizontal_compose97i_mmx;
+#if HAVE_7REGS
+ c->vertical_compose97i = ff_snow_vertical_compose97i_mmx;
+#endif
+ }
+#if HAVE_6REGS
+ c->inner_add_yblock = ff_snow_inner_add_yblock_mmx;
+#endif
+ }
+ }
+#endif /* HAVE_INLINE_ASM */
+}
diff --git a/libavcodec/x86/svq1enc.asm b/libavcodec/x86/svq1enc.asm
new file mode 100644
index 0000000000..24ee70f108
--- /dev/null
+++ b/libavcodec/x86/svq1enc.asm
@@ -0,0 +1,61 @@
+;******************************************************************************
+;* SIMD-optimized SVQ1 encoder functions
+;* Copyright (c) 2007 Loren Merritt
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_TEXT
+
+%macro SSD_INT8_VS_INT16 0
+cglobal ssd_int8_vs_int16, 3, 3, 3, pix1, pix2, size
+ pxor m0, m0
+.loop
+ sub sizeq, 8
+ movq m1, [pix1q + sizeq]
+ mova m2, [pix2q + sizeq*2]
+%if mmsize == 8
+ movq m3, [pix2q + sizeq*2 + mmsize]
+ punpckhbw m4, m1
+ punpcklbw m1, m1
+ psraw m4, 8
+ psraw m1, 8
+ psubw m3, m4
+ psubw m2, m1
+ pmaddwd m3, m3
+ pmaddwd m2, m2
+ paddd m0, m3
+ paddd m0, m2
+%else
+ punpcklbw m1, m1
+ psraw m1, 8
+ psubw m2, m1
+ pmaddwd m2, m2
+ paddd m0, m2
+%endif
+ jg .loop
+ HADDD m0, m1
+ movd eax, m0
+ RET
+%endmacro
+
+INIT_MMX mmx
+SSD_INT8_VS_INT16
+INIT_XMM sse2
+SSD_INT8_VS_INT16
diff --git a/libavcodec/x86/svq1enc.c b/libavcodec/x86/svq1enc.c
deleted file mode 100644
index 02b0a84b8c..0000000000
--- a/libavcodec/x86/svq1enc.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; 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/x86/asm.h"
-#include "libavutil/x86/cpu.h"
-#include "libavcodec/svq1enc.h"
-
-#if HAVE_INLINE_ASM
-
-static int ssd_int8_vs_int16_mmx(const int8_t *pix1, const int16_t *pix2,
- int size)
-{
- int sum;
- x86_reg i = size;
-
- __asm__ volatile (
- "pxor %%mm4, %%mm4 \n"
- "1: \n"
- "sub $8, %0 \n"
- "movq (%2, %0), %%mm2 \n"
- "movq (%3, %0, 2), %%mm0 \n"
- "movq 8(%3, %0, 2), %%mm1 \n"
- "punpckhbw %%mm2, %%mm3 \n"
- "punpcklbw %%mm2, %%mm2 \n"
- "psraw $8, %%mm3 \n"
- "psraw $8, %%mm2 \n"
- "psubw %%mm3, %%mm1 \n"
- "psubw %%mm2, %%mm0 \n"
- "pmaddwd %%mm1, %%mm1 \n"
- "pmaddwd %%mm0, %%mm0 \n"
- "paddd %%mm1, %%mm4 \n"
- "paddd %%mm0, %%mm4 \n"
- "jg 1b \n"
- "movq %%mm4, %%mm3 \n"
- "psrlq $32, %%mm3 \n"
- "paddd %%mm3, %%mm4 \n"
- "movd %%mm4, %1 \n"
- : "+r" (i), "=r" (sum)
- : "r" (pix1), "r" (pix2));
-
- return sum;
-}
-
-#endif /* HAVE_INLINE_ASM */
-
-av_cold void ff_svq1enc_init_x86(SVQ1EncContext *c)
-{
-#if HAVE_INLINE_ASM
- int cpu_flags = av_get_cpu_flags();
-
- if (INLINE_MMX(cpu_flags)) {
- c->ssd_int8_vs_int16 = ssd_int8_vs_int16_mmx;
- }
-#endif /* HAVE_INLINE_ASM */
-}
diff --git a/libavcodec/x86/svq1enc_init.c b/libavcodec/x86/svq1enc_init.c
new file mode 100644
index 0000000000..40b4b0e183
--- /dev/null
+++ b/libavcodec/x86/svq1enc_init.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007 Loren Merritt
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/x86/cpu.h"
+#include "libavcodec/svq1enc.h"
+
+int ff_ssd_int8_vs_int16_mmx(const int8_t *pix1, const int16_t *pix2,
+ intptr_t size);
+int ff_ssd_int8_vs_int16_sse2(const int8_t *pix1, const int16_t *pix2,
+ intptr_t size);
+
+av_cold void ff_svq1enc_init_x86(SVQ1EncContext *c)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMX(cpu_flags)) {
+ c->ssd_int8_vs_int16 = ff_ssd_int8_vs_int16_mmx;
+ }
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->ssd_int8_vs_int16 = ff_ssd_int8_vs_int16_sse2;
+ }
+}
diff --git a/libavcodec/x86/ttadsp.asm b/libavcodec/x86/ttadsp.asm
new file mode 100644
index 0000000000..8f489498a3
--- /dev/null
+++ b/libavcodec/x86/ttadsp.asm
@@ -0,0 +1,119 @@
+;******************************************************************************
+;* TTA DSP SIMD optimizations
+;*
+;* Copyright (C) 2014 James Almer
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pd_n0113: dd ~0, ~1, ~1, ~3
+pd_1224: dd 1, 2, 2, 4
+
+SECTION .text
+
+%macro TTA_FILTER 2
+INIT_XMM %1
+cglobal ttafilter_process_dec, 5,5,%2, qm, dx, dl, error, in, shift, round
+ mova m2, [qmq ]
+ mova m3, [qmq + 0x10]
+ mova m4, [dxq ]
+ mova m5, [dxq + 0x10]
+
+ movd m6, [errorq] ; if (filter->error < 0) {
+ SPLATD m6 ; for (int i = 0; i < 8; i++)
+ psignd m0, m4, m6 ; filter->qm[i] -= filter->dx[i];
+ psignd m1, m5, m6 ; } else if (filter->error > 0) {
+ paddd m2, m0 ; for (int i = 0; i < 8; i++)
+ paddd m3, m1 ; filter->qm[i] += filter->dx[i];
+ mova [qmq ], m2 ; }
+ mova [qmq + 0x10], m3 ;
+
+ mova m0, [dlq ]
+ mova m1, [dlq + 0x10]
+
+%if cpuflag(sse4)
+ pmulld m2, m0
+ pmulld m3, m1
+%else
+ pshufd m6, m0, 0xb1
+ pshufd m7, m2, 0xb1
+ pmuludq m6, m7
+ pshufd m6, m6, 0xd8
+ pmuludq m2, m0
+ pshufd m2, m2, 0xd8
+ punpckldq m2, m6
+
+ pshufd m6, m1, 0xb1
+ pshufd m7, m3, 0xb1
+ pmuludq m6, m7
+ pshufd m6, m6, 0xd8
+ pmuludq m3, m1
+ pshufd m3, m3, 0xd8
+ punpckldq m3, m6
+%endif
+ ; Using horizontal add (phaddd) seems to be slower than shuffling stuff around
+ paddd m2, m3 ; int sum = filter->round +
+ ; filter->dl[0] * filter->qm[0] +
+ pshufd m3, m2, 0xe ; filter->dl[1] * filter->qm[1] +
+ paddd m2, m3 ; filter->dl[2] * filter->qm[2] +
+ ; filter->dl[3] * filter->qm[3] +
+ movd m6, roundm ; filter->dl[4] * filter->qm[4] +
+ paddd m6, m2 ; filter->dl[5] * filter->qm[5] +
+ pshufd m2, m2, 0x1 ; filter->dl[6] * filter->qm[6] +
+ paddd m6, m2 ; filter->dl[7] * filter->qm[7];
+
+ palignr m5, m4, 4 ; filter->dx[0] = filter->dx[1]; filter->dx[1] = filter->dx[2];
+ ; filter->dx[2] = filter->dx[3]; filter->dx[3] = filter->dx[4];
+
+ palignr m2, m1, m0, 4 ; filter->dl[0] = filter->dl[1]; filter->dl[1] = filter->dl[2];
+ ; filter->dl[2] = filter->dl[3]; filter->dl[3] = filter->dl[4];
+
+ psrad m4, m1, 30 ; filter->dx[4] = ((filter->dl[4] >> 30) | 1);
+ por m4, [pd_1224 ] ; filter->dx[5] = ((filter->dl[5] >> 30) | 2) & ~1;
+ pand m4, [pd_n0113] ; filter->dx[6] = ((filter->dl[6] >> 30) | 2) & ~1;
+ ; filter->dx[7] = ((filter->dl[7] >> 30) | 4) & ~3;
+
+ mova [dlq ], m2
+ mova [dxq ], m5
+ mova [dxq + 0x10], m4
+ movd m0, [inq] ; filter->error = *in;
+ movd [errorq], m0 ;
+
+ movd m2, shiftm ; *in += (sum >> filter->shift);
+ psrad m6, m2 ;
+ paddd m0, m6 ;
+ movd [inq], m0 ;
+
+ psrldq m1, 4 ;
+ pslldq m0, 12 ; filter->dl[4] = -filter->dl[5];
+ pshufd m0, m0, 0xf0 ; filter->dl[5] = -filter->dl[6];
+ psubd m0, m1 ; filter->dl[6] = *in - filter->dl[7];
+ psrldq m1, m0, 4 ; filter->dl[7] = *in;
+ pshufd m1, m1, 0xf4 ; filter->dl[5] += filter->dl[6];
+ paddd m0, m1 ; filter->dl[4] += filter->dl[5];
+ psrldq m1, 4 ;
+ paddd m0, m1 ;
+ mova [dlq + 0x10], m0 ;
+ RET
+%endmacro
+
+TTA_FILTER ssse3, 8
+TTA_FILTER sse4, 7
diff --git a/libavcodec/x86/ttadsp_init.c b/libavcodec/x86/ttadsp_init.c
new file mode 100644
index 0000000000..47dc87f6af
--- /dev/null
+++ b/libavcodec/x86/ttadsp_init.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/ttadsp.h"
+#include "libavutil/x86/cpu.h"
+#include "config.h"
+
+void ff_ttafilter_process_dec_ssse3(int32_t *qm, int32_t *dx, int32_t *dl,
+ int32_t *error, int32_t *in, int32_t shift,
+ int32_t round);
+void ff_ttafilter_process_dec_sse4(int32_t *qm, int32_t *dx, int32_t *dl,
+ int32_t *error, int32_t *in, int32_t shift,
+ int32_t round);
+
+av_cold void ff_ttadsp_init_x86(TTADSPContext *c)
+{
+#if HAVE_YASM
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_SSSE3(cpu_flags))
+ c->ttafilter_process_dec = ff_ttafilter_process_dec_ssse3;
+ if (EXTERNAL_SSE4(cpu_flags))
+ c->ttafilter_process_dec = ff_ttafilter_process_dec_sse4;
+#endif
+}
diff --git a/libavcodec/x86/v210-init.c b/libavcodec/x86/v210-init.c
new file mode 100644
index 0000000000..dfdfd2631b
--- /dev/null
+++ b/libavcodec/x86/v210-init.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/cpu.h"
+#include "libavcodec/v210dec.h"
+
+extern void ff_v210_planar_unpack_unaligned_ssse3(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width);
+extern void ff_v210_planar_unpack_unaligned_avx(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width);
+
+extern void ff_v210_planar_unpack_aligned_ssse3(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width);
+extern void ff_v210_planar_unpack_aligned_avx(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width);
+
+av_cold void ff_v210_x86_init(V210DecContext *s)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+#if HAVE_YASM
+ if (s->aligned_input) {
+ if (cpu_flags & AV_CPU_FLAG_SSSE3)
+ s->unpack_frame = ff_v210_planar_unpack_aligned_ssse3;
+
+ if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX)
+ s->unpack_frame = ff_v210_planar_unpack_aligned_avx;
+ }
+ else {
+ if (cpu_flags & AV_CPU_FLAG_SSSE3)
+ s->unpack_frame = ff_v210_planar_unpack_unaligned_ssse3;
+
+ if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX)
+ s->unpack_frame = ff_v210_planar_unpack_unaligned_avx;
+ }
+#endif
+}
diff --git a/libavcodec/x86/v210.asm b/libavcodec/x86/v210.asm
new file mode 100644
index 0000000000..400a1f3f9e
--- /dev/null
+++ b/libavcodec/x86/v210.asm
@@ -0,0 +1,90 @@
+;******************************************************************************
+;* V210 SIMD unpack
+;* Copyright (c) 2011 Loren Merritt <lorenm@u.washington.edu>
+;* Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+v210_mask: times 4 dd 0x3ff
+v210_mult: dw 64,4,64,4,64,4,64,4
+v210_luma_shuf: db 8,9,0,1,2,3,12,13,4,5,6,7,-1,-1,-1,-1
+v210_chroma_shuf: db 0,1,8,9,6,7,-1,-1,2,3,4,5,12,13,-1,-1
+
+SECTION .text
+
+%macro v210_planar_unpack 1
+
+; v210_planar_unpack(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width)
+cglobal v210_planar_unpack_%1, 5, 5, 7
+ movsxdifnidn r4, r4d
+ lea r1, [r1+2*r4]
+ add r2, r4
+ add r3, r4
+ neg r4
+
+ mova m3, [v210_mult]
+ mova m4, [v210_mask]
+ mova m5, [v210_luma_shuf]
+ mova m6, [v210_chroma_shuf]
+.loop
+%ifidn %1, unaligned
+ movu m0, [r0]
+%else
+ mova m0, [r0]
+%endif
+
+ pmullw m1, m0, m3
+ psrld m0, 10
+ psrlw m1, 6 ; u0 v0 y1 y2 v1 u2 y4 y5
+ pand m0, m4 ; y0 __ u1 __ y3 __ v2 __
+
+ shufps m2, m1, m0, 0x8d ; y1 y2 y4 y5 y0 __ y3 __
+ pshufb m2, m5 ; y0 y1 y2 y3 y4 y5 __ __
+ movu [r1+2*r4], m2
+
+ shufps m1, m0, 0xd8 ; u0 v0 v1 u2 u1 __ v2 __
+ pshufb m1, m6 ; u0 u1 u2 __ v0 v1 v2 __
+ movq [r2+r4], m1
+ movhps [r3+r4], m1
+
+ add r0, mmsize
+ add r4, 6
+ jl .loop
+
+ REP_RET
+%endmacro
+
+INIT_XMM ssse3
+v210_planar_unpack unaligned
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+v210_planar_unpack unaligned
+%endif
+
+INIT_XMM ssse3
+v210_planar_unpack aligned
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+v210_planar_unpack aligned
+%endif
diff --git a/libavcodec/x86/v210enc.asm b/libavcodec/x86/v210enc.asm
index 595c8907b3..751675fc5e 100644
--- a/libavcodec/x86/v210enc.asm
+++ b/libavcodec/x86/v210enc.asm
@@ -2,20 +2,20 @@
;* V210 SIMD pack
;* Copyright (c) 2014 Kieran Kunhya <kierank@obe.tv>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -23,7 +23,8 @@
SECTION_RODATA
-v210_enc_min_10: times 8 dw 0x4
+cextern pw_4
+%define v210_enc_min_10 pw_4
v210_enc_max_10: times 8 dw 0x3fb
v210_enc_luma_mult_10: dw 4,1,16,4,1,16,0,0
@@ -32,8 +33,10 @@ v210_enc_luma_shuf_10: db -1,0,1,-1,2,3,4,5,-1,6,7,-1,8,9,10,11
v210_enc_chroma_mult_10: dw 1,4,16,0,16,1,4,0
v210_enc_chroma_shuf_10: db 0,1,8,9,-1,2,3,-1,10,11,4,5,-1,12,13,-1
-v210_enc_min_8: times 16 db 0x1
-v210_enc_max_8: times 16 db 0xfe
+cextern pb_1
+%define v210_enc_min_8 pb_1
+cextern pb_FE
+%define v210_enc_max_8 pb_FE
v210_enc_luma_shuf_8: db 6,-1,7,-1,8,-1,9,-1,10,-1,11,-1,-1,-1,-1,-1
v210_enc_luma_mult_8: dw 16,4,64,16,4,64,0,0
diff --git a/libavcodec/x86/v210enc_init.c b/libavcodec/x86/v210enc_init.c
index 95b999bc05..2afb1b2d7b 100644
--- a/libavcodec/x86/v210enc_init.c
+++ b/libavcodec/x86/v210enc_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/vc1dsp.asm b/libavcodec/x86/vc1dsp.asm
index adf08d7d84..546688cf9d 100644
--- a/libavcodec/x86/vc1dsp.asm
+++ b/libavcodec/x86/vc1dsp.asm
@@ -2,20 +2,20 @@
;* VC1 deblocking optimizations
;* Copyright (c) 2009 David Conrad
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/vc1dsp.h b/libavcodec/x86/vc1dsp.h
index 9b6c8ada26..fdd4de1813 100644
--- a/libavcodec/x86/vc1dsp.h
+++ b/libavcodec/x86/vc1dsp.h
@@ -1,20 +1,20 @@
/*
* VC-1 and WMV3 decoder - X86 DSP init functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/vc1dsp_init.c b/libavcodec/x86/vc1dsp_init.c
index aff4b264e3..2bef5f5fb5 100644
--- a/libavcodec/x86/vc1dsp_init.c
+++ b/libavcodec/x86/vc1dsp_init.c
@@ -27,6 +27,7 @@
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "libavutil/x86/cpu.h"
+#include "libavutil/x86/asm.h"
#include "libavcodec/vc1dsp.h"
#include "fpel.h"
#include "vc1dsp.h"
@@ -62,12 +63,17 @@ static void vc1_h_loop_filter16_sse4(uint8_t *src, int stride, int pq)
ff_vc1_h_loop_filter8_sse4(src, stride, pq);
ff_vc1_h_loop_filter8_sse4(src+8*stride, stride, pq);
}
-
static void avg_vc1_mspel_mc00_mmxext(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride, int rnd)
{
ff_avg_pixels8_mmxext(dst, src, stride, 8);
}
+static void avg_vc1_mspel_mc00_16_sse2(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride, int rnd)
+{
+ ff_avg_pixels16_sse2(dst, src, stride, 16);
+}
+
#endif /* HAVE_YASM */
void ff_put_vc1_chroma_mc8_nornd_mmx (uint8_t *dst, uint8_t *src,
@@ -86,10 +92,10 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp)
{
int cpu_flags = av_get_cpu_flags();
- if (INLINE_MMX(cpu_flags))
+ if (HAVE_6REGS && INLINE_MMX(cpu_flags))
ff_vc1dsp_init_mmx(dsp);
- if (INLINE_MMXEXT(cpu_flags))
+ if (HAVE_6REGS && INLINE_MMXEXT(cpu_flags))
ff_vc1dsp_init_mmxext(dsp);
#define ASSIGN_LF(EXT) \
@@ -111,13 +117,14 @@ av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp)
ASSIGN_LF(mmxext);
dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_nornd_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[0] = avg_vc1_mspel_mc00_mmxext;
+ dsp->avg_vc1_mspel_pixels_tab[1][0] = avg_vc1_mspel_mc00_mmxext;
}
if (EXTERNAL_SSE2(cpu_flags)) {
dsp->vc1_v_loop_filter8 = ff_vc1_v_loop_filter8_sse2;
dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_sse2;
dsp->vc1_v_loop_filter16 = vc1_v_loop_filter16_sse2;
dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_sse2;
+ dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_vc1_mspel_mc00_16_sse2;
}
if (EXTERNAL_SSSE3(cpu_flags)) {
ASSIGN_LF(ssse3);
diff --git a/libavcodec/x86/vc1dsp_mmx.c b/libavcodec/x86/vc1dsp_mmx.c
index 046affbc26..f11170c075 100644
--- a/libavcodec/x86/vc1dsp_mmx.c
+++ b/libavcodec/x86/vc1dsp_mmx.c
@@ -25,7 +25,6 @@
*/
#include "libavutil/cpu.h"
-#include "libavutil/internal.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
@@ -34,7 +33,7 @@
#include "fpel.h"
#include "vc1dsp.h"
-#if HAVE_INLINE_ASM
+#if HAVE_6REGS && HAVE_INLINE_ASM
#define OP_PUT(S,D)
#define OP_AVG(S,D) "pavgb " #S ", " #D " \n\t"
@@ -111,6 +110,7 @@ static void vc1_put_ver_16b_shift2_mmx(int16_t *dst,
: "+r"(src), "+r"(dst)
: "r"(stride), "r"(-2*stride),
"m"(shift), "m"(rnd), "r"(9*stride-4)
+ NAMED_CONSTRAINTS_ADD(ff_pw_9)
: "%"REG_c, "memory"
);
}
@@ -155,6 +155,7 @@ static void OPNAME ## vc1_hor_16b_shift2_mmx(uint8_t *dst, x86_reg stride,\
"jnz 1b \n\t"\
: "+r"(h), "+r" (src), "+r" (dst)\
: "r"(stride), "m"(rnd)\
+ NAMED_CONSTRAINTS_ADD(ff_pw_128,ff_pw_9)\
: "memory"\
);\
}
@@ -213,6 +214,7 @@ static void OPNAME ## vc1_shift2_mmx(uint8_t *dst, const uint8_t *src,\
: "+r"(src), "+r"(dst)\
: "r"(offset), "r"(-2*offset), "g"(stride), "m"(rnd),\
"g"(stride-offset)\
+ NAMED_CONSTRAINTS_ADD(ff_pw_9)\
: "%"REG_c, "memory"\
);\
}
@@ -315,6 +317,7 @@ vc1_put_ver_16b_ ## NAME ## _mmx(int16_t *dst, const uint8_t *src, \
: "+r"(h), "+r" (src), "+r" (dst) \
: "r"(src_stride), "r"(3*src_stride), \
"m"(rnd), "m"(shift) \
+ NAMED_CONSTRAINTS_ADD(ff_pw_3,ff_pw_53,ff_pw_18) \
: "memory" \
); \
}
@@ -352,6 +355,7 @@ OPNAME ## vc1_hor_16b_ ## NAME ## _mmx(uint8_t *dst, x86_reg stride, \
"jnz 1b \n\t" \
: "+r"(h), "+r" (src), "+r" (dst) \
: "r"(stride), "m"(rnd) \
+ NAMED_CONSTRAINTS_ADD(ff_pw_3,ff_pw_18,ff_pw_53,ff_pw_128) \
: "memory" \
); \
}
@@ -387,6 +391,7 @@ OPNAME ## vc1_## NAME ## _mmx(uint8_t *dst, const uint8_t *src, \
"jnz 1b \n\t" \
: "+r"(h), "+r" (src), "+r" (dst) \
: "r"(offset), "r"(3*offset), "g"(stride), "m"(rnd) \
+ NAMED_CONSTRAINTS_ADD(ff_pw_53,ff_pw_18,ff_pw_3) \
: "memory" \
); \
}
@@ -441,7 +446,7 @@ static void OP ## vc1_mspel_mc(uint8_t *dst, const uint8_t *src, int stride,\
static const int shift_value[] = { 0, 5, 1, 5 };\
int shift = (shift_value[hmode]+shift_value[vmode])>>1;\
int r;\
- DECLARE_ALIGNED(16, int16_t, tmp)[12*8];\
+ LOCAL_ALIGNED(16, int16_t, tmp, [12*8]);\
\
r = (1<<(shift-1)) + rnd-1;\
vc1_put_shift_ver_16bits[vmode](tmp, src-1, stride, r, shift);\
@@ -457,6 +462,15 @@ static void OP ## vc1_mspel_mc(uint8_t *dst, const uint8_t *src, int stride,\
\
/* Horizontal mode with no vertical mode */\
vc1_put_shift_8bits[hmode](dst, src, stride, rnd, 1);\
+} \
+static void OP ## vc1_mspel_mc_16(uint8_t *dst, const uint8_t *src, \
+ int stride, int hmode, int vmode, int rnd)\
+{ \
+ OP ## vc1_mspel_mc(dst + 0, src + 0, stride, hmode, vmode, rnd); \
+ OP ## vc1_mspel_mc(dst + 8, src + 8, stride, hmode, vmode, rnd); \
+ dst += 8*stride; src += 8*stride; \
+ OP ## vc1_mspel_mc(dst + 0, src + 0, stride, hmode, vmode, rnd); \
+ OP ## vc1_mspel_mc(dst + 8, src + 8, stride, hmode, vmode, rnd); \
}
VC1_MSPEL_MC(put_)
@@ -477,6 +491,20 @@ static void avg_vc1_mspel_mc ## a ## b ## _mmxext(uint8_t *dst, \
int rnd) \
{ \
avg_vc1_mspel_mc(dst, src, stride, a, b, rnd); \
+}\
+static void put_vc1_mspel_mc ## a ## b ## _16_mmx(uint8_t *dst, \
+ const uint8_t *src, \
+ ptrdiff_t stride, \
+ int rnd) \
+{ \
+ put_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
+}\
+static void avg_vc1_mspel_mc ## a ## b ## _16_mmxext(uint8_t *dst, \
+ const uint8_t *src,\
+ ptrdiff_t stride, \
+ int rnd) \
+{ \
+ avg_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \
}
DECLARE_FUNCTION(0, 1)
@@ -700,59 +728,83 @@ static void vc1_inv_trans_8x8_dc_mmxext(uint8_t *dest, int linesize,
);
}
+#if HAVE_MMX_EXTERNAL
static void put_vc1_mspel_mc00_mmx(uint8_t *dst, const uint8_t *src,
ptrdiff_t stride, int rnd)
{
ff_put_pixels8_mmx(dst, src, stride, 8);
}
+static void put_vc1_mspel_mc00_16_mmx(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride, int rnd)
+{
+ ff_put_pixels16_mmx(dst, src, stride, 16);
+}
+static void avg_vc1_mspel_mc00_mmx(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride, int rnd)
+{
+ ff_avg_pixels8_mmx(dst, src, stride, 8);
+}
+static void avg_vc1_mspel_mc00_16_mmx(uint8_t *dst, const uint8_t *src,
+ ptrdiff_t stride, int rnd)
+{
+ ff_avg_pixels16_mmx(dst, src, stride, 16);
+}
+#endif
+
+#define FN_ASSIGN(OP, X, Y, INSN) \
+ dsp->OP##vc1_mspel_pixels_tab[1][X+4*Y] = OP##vc1_mspel_mc##X##Y##INSN; \
+ dsp->OP##vc1_mspel_pixels_tab[0][X+4*Y] = OP##vc1_mspel_mc##X##Y##_16##INSN
av_cold void ff_vc1dsp_init_mmx(VC1DSPContext *dsp)
{
- dsp->put_vc1_mspel_pixels_tab[ 0] = put_vc1_mspel_mc00_mmx;
- dsp->put_vc1_mspel_pixels_tab[ 4] = put_vc1_mspel_mc01_mmx;
- dsp->put_vc1_mspel_pixels_tab[ 8] = put_vc1_mspel_mc02_mmx;
- dsp->put_vc1_mspel_pixels_tab[12] = put_vc1_mspel_mc03_mmx;
-
- dsp->put_vc1_mspel_pixels_tab[ 1] = put_vc1_mspel_mc10_mmx;
- dsp->put_vc1_mspel_pixels_tab[ 5] = put_vc1_mspel_mc11_mmx;
- dsp->put_vc1_mspel_pixels_tab[ 9] = put_vc1_mspel_mc12_mmx;
- dsp->put_vc1_mspel_pixels_tab[13] = put_vc1_mspel_mc13_mmx;
-
- dsp->put_vc1_mspel_pixels_tab[ 2] = put_vc1_mspel_mc20_mmx;
- dsp->put_vc1_mspel_pixels_tab[ 6] = put_vc1_mspel_mc21_mmx;
- dsp->put_vc1_mspel_pixels_tab[10] = put_vc1_mspel_mc22_mmx;
- dsp->put_vc1_mspel_pixels_tab[14] = put_vc1_mspel_mc23_mmx;
-
- dsp->put_vc1_mspel_pixels_tab[ 3] = put_vc1_mspel_mc30_mmx;
- dsp->put_vc1_mspel_pixels_tab[ 7] = put_vc1_mspel_mc31_mmx;
- dsp->put_vc1_mspel_pixels_tab[11] = put_vc1_mspel_mc32_mmx;
- dsp->put_vc1_mspel_pixels_tab[15] = put_vc1_mspel_mc33_mmx;
+#if HAVE_MMX_EXTERNAL
+ FN_ASSIGN(put_, 0, 0, _mmx);
+ FN_ASSIGN(avg_, 0, 0, _mmx);
+#endif
+ FN_ASSIGN(put_, 0, 1, _mmx);
+ FN_ASSIGN(put_, 0, 2, _mmx);
+ FN_ASSIGN(put_, 0, 3, _mmx);
+
+ FN_ASSIGN(put_, 1, 0, _mmx);
+ FN_ASSIGN(put_, 1, 1, _mmx);
+ FN_ASSIGN(put_, 1, 2, _mmx);
+ FN_ASSIGN(put_, 1, 3, _mmx);
+
+ FN_ASSIGN(put_, 2, 0, _mmx);
+ FN_ASSIGN(put_, 2, 1, _mmx);
+ FN_ASSIGN(put_, 2, 2, _mmx);
+ FN_ASSIGN(put_, 2, 3, _mmx);
+
+ FN_ASSIGN(put_, 3, 0, _mmx);
+ FN_ASSIGN(put_, 3, 1, _mmx);
+ FN_ASSIGN(put_, 3, 2, _mmx);
+ FN_ASSIGN(put_, 3, 3, _mmx);
}
av_cold void ff_vc1dsp_init_mmxext(VC1DSPContext *dsp)
{
- dsp->avg_vc1_mspel_pixels_tab[ 4] = avg_vc1_mspel_mc01_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[ 8] = avg_vc1_mspel_mc02_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[12] = avg_vc1_mspel_mc03_mmxext;
+ FN_ASSIGN(avg_, 0, 1, _mmxext);
+ FN_ASSIGN(avg_, 0, 2, _mmxext);
+ FN_ASSIGN(avg_, 0, 3, _mmxext);
- dsp->avg_vc1_mspel_pixels_tab[ 1] = avg_vc1_mspel_mc10_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[ 5] = avg_vc1_mspel_mc11_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[ 9] = avg_vc1_mspel_mc12_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[13] = avg_vc1_mspel_mc13_mmxext;
+ FN_ASSIGN(avg_, 1, 0, _mmxext);
+ FN_ASSIGN(avg_, 1, 1, _mmxext);
+ FN_ASSIGN(avg_, 1, 2, _mmxext);
+ FN_ASSIGN(avg_, 1, 3, _mmxext);
- dsp->avg_vc1_mspel_pixels_tab[ 2] = avg_vc1_mspel_mc20_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[ 6] = avg_vc1_mspel_mc21_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[10] = avg_vc1_mspel_mc22_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[14] = avg_vc1_mspel_mc23_mmxext;
+ FN_ASSIGN(avg_, 2, 0, _mmxext);
+ FN_ASSIGN(avg_, 2, 1, _mmxext);
+ FN_ASSIGN(avg_, 2, 2, _mmxext);
+ FN_ASSIGN(avg_, 2, 3, _mmxext);
- dsp->avg_vc1_mspel_pixels_tab[ 3] = avg_vc1_mspel_mc30_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[ 7] = avg_vc1_mspel_mc31_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[11] = avg_vc1_mspel_mc32_mmxext;
- dsp->avg_vc1_mspel_pixels_tab[15] = avg_vc1_mspel_mc33_mmxext;
+ FN_ASSIGN(avg_, 3, 0, _mmxext);
+ FN_ASSIGN(avg_, 3, 1, _mmxext);
+ FN_ASSIGN(avg_, 3, 2, _mmxext);
+ FN_ASSIGN(avg_, 3, 3, _mmxext);
dsp->vc1_inv_trans_8x8_dc = vc1_inv_trans_8x8_dc_mmxext;
dsp->vc1_inv_trans_4x8_dc = vc1_inv_trans_4x8_dc_mmxext;
dsp->vc1_inv_trans_8x4_dc = vc1_inv_trans_8x4_dc_mmxext;
dsp->vc1_inv_trans_4x4_dc = vc1_inv_trans_4x4_dc_mmxext;
}
-#endif /* HAVE_INLINE_ASM */
+#endif /* HAVE_6REGS && HAVE_INLINE_ASM */
diff --git a/libavcodec/x86/videodsp.asm b/libavcodec/x86/videodsp.asm
index 53b9e8292c..25d43640ab 100644
--- a/libavcodec/x86/videodsp.asm
+++ b/libavcodec/x86/videodsp.asm
@@ -2,20 +2,20 @@
;* Core video DSP functions
;* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -54,13 +54,13 @@ SECTION .text
; | | <- bottom is copied from last line in body of source
; '----' <- bh
%if ARCH_X86_64
-cglobal emu_edge_vvar, 7, 8, 1, dst, src, dst_stride, src_stride, \
+cglobal emu_edge_vvar, 7, 8, 1, dst, dst_stride, src, src_stride, \
start_y, end_y, bh, w
%else ; x86-32
cglobal emu_edge_vvar, 1, 6, 1, dst, src, start_y, end_y, bh, w
%define src_strideq r3mp
-%define dst_strideq r2mp
- mov srcq, r1mp
+%define dst_strideq r1mp
+ mov srcq, r2mp
mov start_yq, r4mp
mov end_yq, r5mp
mov bhq, r6mp
@@ -97,7 +97,10 @@ cglobal emu_edge_hvar, 5, 6, 1, dst, dst_stride, start_x, n_words, h, w
neg n_wordsq
lea start_xq, [start_xq+n_wordsq*2]
.y_loop: ; do {
- ; FIXME also write a ssse3 version using pshufb
+%if cpuflag(avx2)
+ vpbroadcastb m0, [dstq+start_xq]
+ mov wq, n_wordsq ; initialize w
+%else
movzx wd, byte [dstq+start_xq] ; w = read(1)
imul wd, 0x01010101 ; w *= 0x01010101
movd m0, wd
@@ -107,6 +110,7 @@ cglobal emu_edge_hvar, 5, 6, 1, dst, dst_stride, start_x, n_words, h, w
%else ; mmx
punpckldq m0, m0 ; splat
%endif ; mmx/sse
+%endif ; avx2
.x_loop: ; do {
movu [dstq+wq*2], m0 ; write($reg, $mmsize)
add wq, mmsize/2 ; w -= $mmsize/2
@@ -127,6 +131,11 @@ hvar_fn
INIT_XMM sse2
hvar_fn
+%if HAVE_AVX2_EXTERNAL
+INIT_XMM avx2
+hvar_fn
+%endif
+
; macro to read/write a horizontal number of pixels (%2) to/from registers
; on sse, - fills xmm0-15 for consecutive sets of 16 pixels
; - if (%2 & 8) fills 8 bytes into xmm$next
@@ -262,30 +271,30 @@ hvar_fn
%rep 1+%2-%1
%if %%n <= 3
%if ARCH_X86_64
-cglobal emu_edge_vfix %+ %%n, 6, 8, 0, dst, src, dst_stride, src_stride, \
+cglobal emu_edge_vfix %+ %%n, 6, 8, 0, dst, dst_stride, src, src_stride, \
start_y, end_y, val, bh
mov bhq, r6mp ; r6mp = bhmp
%else ; x86-32
cglobal emu_edge_vfix %+ %%n, 0, 6, 0, val, dst, src, start_y, end_y, bh
mov dstq, r0mp
- mov srcq, r1mp
+ mov srcq, r2mp
mov start_yq, r4mp
mov end_yq, r5mp
mov bhq, r6mp
-%define dst_strideq r2mp
+%define dst_strideq r1mp
%define src_strideq r3mp
%endif ; x86-64/32
%else
%if ARCH_X86_64
-cglobal emu_edge_vfix %+ %%n, 7, 7, 1, dst, src, dst_stride, src_stride, \
+cglobal emu_edge_vfix %+ %%n, 7, 7, 1, dst, dst_stride, src, src_stride, \
start_y, end_y, bh
%else ; x86-32
cglobal emu_edge_vfix %+ %%n, 1, 5, 1, dst, src, start_y, end_y, bh
- mov srcq, r1mp
+ mov srcq, r2mp
mov start_yq, r4mp
mov end_yq, r5mp
mov bhq, r6mp
-%define dst_strideq r2mp
+%define dst_strideq r1mp
%define src_strideq r3mp
%endif ; x86-64/32
%endif
@@ -344,9 +353,8 @@ VERTICAL_EXTEND 16, 22
; obviously not the same on both sides.
%macro READ_V_PIXEL 2
-%if %1 == 2
- movzx valw, byte %2
- imul valw, 0x0101
+%if cpuflag(avx2)
+ vpbroadcastb m0, %2
%else
movzx vald, byte %2
imul vald, 0x01010101
@@ -356,13 +364,16 @@ VERTICAL_EXTEND 16, 22
pshufd m0, m0, q0000
%else
punpckldq m0, m0
-%endif
-%endif ; %1 >= 8
-%endif
+%endif ; mmsize == 16
+%endif ; %1 > 16
+%endif ; avx2
%endmacro ; READ_V_PIXEL
%macro WRITE_V_PIXEL 2
%assign %%off 0
+
+%if %1 >= 8
+
%rep %1/mmsize
movu [%2+%%off], m0
%assign %%off %%off+mmsize
@@ -378,34 +389,44 @@ VERTICAL_EXTEND 16, 22
%assign %%off %%off+8
%endif
%endif ; %1-%%off >= 8
-%endif
+%endif ; mmsize == 16
%if %1-%%off >= 4
%if %1 > 8 && %1-%%off > 4
movq [%2+%1-8], m0
%assign %%off %1
-%elif %1 >= 8 && %1-%%off >= 4
- movd [%2+%%off], m0
-%assign %%off %%off+4
%else
- mov [%2+%%off], vald
+ movd [%2+%%off], m0
%assign %%off %%off+4
%endif
%endif ; %1-%%off >= 4
-%if %1-%%off >= 2
-%if %1 >= 8
- movd [%2+%1-4], m0
+%else ; %1 < 8
+
+%rep %1/4
+ mov [%2+%%off], vald
+%assign %%off %%off+4
+%endrep ; %1/4
+
+%endif ; %1 >=/< 8
+
+%if %1-%%off == 2
+%if cpuflag(avx2)
+ movd [%2+%%off-2], m0
%else
mov [%2+%%off], valw
-%endif
+%endif ; avx2
%endif ; (%1-%%off)/2
%endmacro ; WRITE_V_PIXEL
%macro H_EXTEND 2
%assign %%n %1
%rep 1+(%2-%1)/2
+%if cpuflag(avx2)
+cglobal emu_edge_hfix %+ %%n, 4, 4, 1, dst, dst_stride, start_x, bh
+%else
cglobal emu_edge_hfix %+ %%n, 4, 5, 1, dst, dst_stride, start_x, bh, val
+%endif
.loop_y: ; do {
READ_V_PIXEL %%n, [dstq+start_xq] ; $variable_regs = read($n)
WRITE_V_PIXEL %%n, dstq ; write($variable_regs, $n)
@@ -426,6 +447,11 @@ H_EXTEND 16, 22
INIT_XMM sse2
H_EXTEND 16, 22
+%if HAVE_AVX2_EXTERNAL
+INIT_XMM avx2
+H_EXTEND 8, 22
+%endif
+
%macro PREFETCH_FN 1
cglobal prefetch, 3, 3, 0, buf, stride, h
.loop:
diff --git a/libavcodec/x86/videodsp_init.c b/libavcodec/x86/videodsp_init.c
index 8ee837096a..885cdf1d8c 100644
--- a/libavcodec/x86/videodsp_init.c
+++ b/libavcodec/x86/videodsp_init.c
@@ -1,25 +1,27 @@
/*
+ * Copyright (C) 2002-2012 Michael Niedermayer
* Copyright (C) 2012 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avassert.h"
#include "libavutil/common.h"
#include "libavutil/cpu.h"
#include "libavutil/mem.h"
@@ -28,11 +30,11 @@
#include "libavcodec/videodsp.h"
#if HAVE_YASM
-typedef void emu_edge_vfix_func(uint8_t *dst, const uint8_t *src,
- x86_reg dst_stride, x86_reg src_stride,
+typedef void emu_edge_vfix_func(uint8_t *dst, x86_reg dst_stride,
+ const uint8_t *src, x86_reg src_stride,
x86_reg start_y, x86_reg end_y, x86_reg bh);
-typedef void emu_edge_vvar_func(uint8_t *dst, const uint8_t *src,
- x86_reg dst_stride, x86_reg src_stride,
+typedef void emu_edge_vvar_func(uint8_t *dst, x86_reg dst_stride,
+ const uint8_t *src, x86_reg src_stride,
x86_reg start_y, x86_reg end_y, x86_reg bh,
x86_reg w);
@@ -59,7 +61,7 @@ extern emu_edge_vfix_func ff_emu_edge_vfix20_mmx;
extern emu_edge_vfix_func ff_emu_edge_vfix21_mmx;
extern emu_edge_vfix_func ff_emu_edge_vfix22_mmx;
#if ARCH_X86_32
-static emu_edge_vfix_func *vfixtbl_mmx[22] = {
+static emu_edge_vfix_func * const vfixtbl_mmx[22] = {
&ff_emu_edge_vfix1_mmx, &ff_emu_edge_vfix2_mmx, &ff_emu_edge_vfix3_mmx,
&ff_emu_edge_vfix4_mmx, &ff_emu_edge_vfix5_mmx, &ff_emu_edge_vfix6_mmx,
&ff_emu_edge_vfix7_mmx, &ff_emu_edge_vfix8_mmx, &ff_emu_edge_vfix9_mmx,
@@ -78,7 +80,7 @@ extern emu_edge_vfix_func ff_emu_edge_vfix19_sse;
extern emu_edge_vfix_func ff_emu_edge_vfix20_sse;
extern emu_edge_vfix_func ff_emu_edge_vfix21_sse;
extern emu_edge_vfix_func ff_emu_edge_vfix22_sse;
-static emu_edge_vfix_func *vfixtbl_sse[22] = {
+static emu_edge_vfix_func * const vfixtbl_sse[22] = {
ff_emu_edge_vfix1_mmx, ff_emu_edge_vfix2_mmx, ff_emu_edge_vfix3_mmx,
ff_emu_edge_vfix4_mmx, ff_emu_edge_vfix5_mmx, ff_emu_edge_vfix6_mmx,
ff_emu_edge_vfix7_mmx, ff_emu_edge_vfix8_mmx, ff_emu_edge_vfix9_mmx,
@@ -107,7 +109,7 @@ extern emu_edge_hfix_func ff_emu_edge_hfix18_mmx;
extern emu_edge_hfix_func ff_emu_edge_hfix20_mmx;
extern emu_edge_hfix_func ff_emu_edge_hfix22_mmx;
#if ARCH_X86_32
-static emu_edge_hfix_func *hfixtbl_mmx[11] = {
+static emu_edge_hfix_func * const hfixtbl_mmx[11] = {
ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx,
ff_emu_edge_hfix8_mmx, ff_emu_edge_hfix10_mmx, ff_emu_edge_hfix12_mmx,
ff_emu_edge_hfix14_mmx, ff_emu_edge_hfix16_mmx, ff_emu_edge_hfix18_mmx,
@@ -119,13 +121,30 @@ extern emu_edge_hfix_func ff_emu_edge_hfix16_sse2;
extern emu_edge_hfix_func ff_emu_edge_hfix18_sse2;
extern emu_edge_hfix_func ff_emu_edge_hfix20_sse2;
extern emu_edge_hfix_func ff_emu_edge_hfix22_sse2;
-static emu_edge_hfix_func *hfixtbl_sse2[11] = {
+static emu_edge_hfix_func * const hfixtbl_sse2[11] = {
ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx,
ff_emu_edge_hfix8_mmx, ff_emu_edge_hfix10_mmx, ff_emu_edge_hfix12_mmx,
ff_emu_edge_hfix14_mmx, ff_emu_edge_hfix16_sse2, ff_emu_edge_hfix18_sse2,
ff_emu_edge_hfix20_sse2, ff_emu_edge_hfix22_sse2
};
extern emu_edge_hvar_func ff_emu_edge_hvar_sse2;
+#if HAVE_AVX2_EXTERNAL
+extern emu_edge_hfix_func ff_emu_edge_hfix8_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix10_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix12_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix14_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix16_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix18_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix20_avx2;
+extern emu_edge_hfix_func ff_emu_edge_hfix22_avx2;
+static emu_edge_hfix_func * const hfixtbl_avx2[11] = {
+ ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx,
+ ff_emu_edge_hfix8_avx2, ff_emu_edge_hfix10_avx2, ff_emu_edge_hfix12_avx2,
+ ff_emu_edge_hfix14_avx2, ff_emu_edge_hfix16_avx2, ff_emu_edge_hfix18_avx2,
+ ff_emu_edge_hfix20_avx2, ff_emu_edge_hfix22_avx2
+};
+extern emu_edge_hvar_func ff_emu_edge_hvar_avx2;
+#endif
static av_always_inline void emulated_edge_mc(uint8_t *dst, const uint8_t *src,
ptrdiff_t dst_stride,
@@ -133,22 +152,24 @@ static av_always_inline void emulated_edge_mc(uint8_t *dst, const uint8_t *src,
x86_reg block_w, x86_reg block_h,
x86_reg src_x, x86_reg src_y,
x86_reg w, x86_reg h,
- emu_edge_vfix_func **vfix_tbl,
+ emu_edge_vfix_func * const *vfix_tbl,
emu_edge_vvar_func *v_extend_var,
- emu_edge_hfix_func **hfix_tbl,
+ emu_edge_hfix_func * const *hfix_tbl,
emu_edge_hvar_func *h_extend_var)
{
x86_reg start_y, start_x, end_y, end_x, src_y_add = 0, p;
if (!w || !h)
- return;
+ return;
if (src_y >= h) {
- src -= src_y * src_stride;
- src_y = src_y_add = h - 1;
+ src -= src_y*src_stride;
+ src_y_add = h - 1;
+ src_y = h - 1;
} else if (src_y <= -block_h) {
- src -= src_y*src_stride;
- src_y = src_y_add = 1 - block_h;
+ src -= src_y*src_stride;
+ src_y_add = 1 - block_h;
+ src_y = 1 - block_h;
}
if (src_x >= w) {
src += w - 1 - src_x;
@@ -162,18 +183,17 @@ static av_always_inline void emulated_edge_mc(uint8_t *dst, const uint8_t *src,
start_x = FFMAX(0, -src_x);
end_y = FFMIN(block_h, h-src_y);
end_x = FFMIN(block_w, w-src_x);
- assert(start_x < end_x && block_w > 0);
- assert(start_y < end_y && block_h > 0);
+ av_assert2(start_x < end_x && block_w > 0);
+ av_assert2(start_y < end_y && block_h > 0);
// fill in the to-be-copied part plus all above/below
src += (src_y_add + start_y) * src_stride + start_x;
w = end_x - start_x;
if (w <= 22) {
- vfix_tbl[w - 1](dst + start_x, src,
- dst_stride, src_stride,
+ vfix_tbl[w - 1](dst + start_x, dst_stride, src, src_stride,
start_y, end_y, block_h);
} else {
- v_extend_var(dst + start_x, src, dst_stride, src_stride,
+ v_extend_var(dst + start_x, dst_stride, src, src_stride,
start_y, end_y, block_h, w);
}
@@ -212,7 +232,7 @@ static av_noinline void emulated_edge_mc_mmx(uint8_t *buf, const uint8_t *src,
hfixtbl_mmx, &ff_emu_edge_hvar_mmx);
}
-static av_noinline void emulated_edge_mc_sse(uint8_t * buf,const uint8_t *src,
+static av_noinline void emulated_edge_mc_sse(uint8_t *buf, const uint8_t *src,
ptrdiff_t buf_stride,
ptrdiff_t src_stride,
int block_w, int block_h,
@@ -231,10 +251,24 @@ static av_noinline void emulated_edge_mc_sse2(uint8_t *buf, const uint8_t *src,
int src_x, int src_y, int w,
int h)
{
- emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, src_x,
- src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse,
+ emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h,
+ src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse,
hfixtbl_sse2, &ff_emu_edge_hvar_sse2);
}
+
+#if HAVE_AVX2_EXTERNAL
+static av_noinline void emulated_edge_mc_avx2(uint8_t *buf, const uint8_t *src,
+ ptrdiff_t buf_stride,
+ ptrdiff_t src_stride,
+ int block_w, int block_h,
+ int src_x, int src_y, int w,
+ int h)
+{
+ emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h,
+ src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse,
+ hfixtbl_avx2, &ff_emu_edge_hvar_avx2);
+}
+#endif /* HAVE_AVX2_EXTERNAL */
#endif /* HAVE_YASM */
void ff_prefetch_mmxext(uint8_t *buf, ptrdiff_t stride, int h);
@@ -264,5 +298,10 @@ av_cold void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc)
if (EXTERNAL_SSE2(cpu_flags) && bpc <= 8) {
ctx->emulated_edge_mc = emulated_edge_mc_sse2;
}
+#if HAVE_AVX2_EXTERNAL
+ if (EXTERNAL_AVX2(cpu_flags) && bpc <= 8) {
+ ctx->emulated_edge_mc = emulated_edge_mc_avx2;
+ }
+#endif
#endif /* HAVE_YASM */
}
diff --git a/libavcodec/x86/vorbisdsp.asm b/libavcodec/x86/vorbisdsp.asm
index c54650eef5..b25d838868 100644
--- a/libavcodec/x86/vorbisdsp.asm
+++ b/libavcodec/x86/vorbisdsp.asm
@@ -2,20 +2,20 @@
;* Vorbis x86 optimizations
;* Copyright (C) 2006 Loren Merritt <lorenm@u.washington.edu>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/vorbisdsp_init.c b/libavcodec/x86/vorbisdsp_init.c
index bbd83195cc..bc1cc43a18 100644
--- a/libavcodec/x86/vorbisdsp_init.c
+++ b/libavcodec/x86/vorbisdsp_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2006 Loren Merritt <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/vp3dsp.asm b/libavcodec/x86/vp3dsp.asm
index fc8a047224..ee5a6bf67a 100644
--- a/libavcodec/x86/vp3dsp.asm
+++ b/libavcodec/x86/vp3dsp.asm
@@ -2,20 +2,20 @@
;* MMX/SSE2-optimized functions for the VP3 decoder
;* Copyright (c) 2007 Aurelien Jacobs <aurel@gnuage.org>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -40,6 +40,7 @@ pb_81: times 8 db 0x81
cextern pb_1
cextern pb_3
cextern pb_80
+cextern pb_FE
cextern pw_8
@@ -147,6 +148,49 @@ cglobal vp3_h_loop_filter, 3, 4
STORE_4_WORDS m3
RET
+%macro PAVGB_NO_RND 0
+ mova m4, m0
+ mova m5, m2
+ pand m4, m1
+ pand m5, m3
+ pxor m1, m0
+ pxor m3, m2
+ pand m1, m6
+ pand m3, m6
+ psrlq m1, 1
+ psrlq m3, 1
+ paddb m4, m1
+ paddb m5, m3
+%endmacro
+
+INIT_MMX mmx
+cglobal put_vp_no_rnd_pixels8_l2, 5, 6, 0, dst, src1, src2, stride, h, stride3
+ mova m6, [pb_FE]
+ lea stride3q,[strideq+strideq*2]
+.loop
+ mova m0, [src1q]
+ mova m1, [src2q]
+ mova m2, [src1q+strideq]
+ mova m3, [src2q+strideq]
+ PAVGB_NO_RND
+ mova [dstq], m4
+ mova [dstq+strideq], m5
+
+ mova m0, [src1q+strideq*2]
+ mova m1, [src2q+strideq*2]
+ mova m2, [src1q+stride3q]
+ mova m3, [src2q+stride3q]
+ PAVGB_NO_RND
+ mova [dstq+strideq*2], m4
+ mova [dstq+stride3q], m5
+
+ lea src1q, [src1q+strideq*4]
+ lea src2q, [src2q+strideq*4]
+ lea dstq, [dstq+strideq*4]
+ sub hd, 4
+ jnz .loop
+ RET
+
; from original comments: The Macro does IDct on 4 1-D Dcts
%macro BeginIDCT 0
movq m2, I(3)
diff --git a/libavcodec/x86/vp3dsp_init.c b/libavcodec/x86/vp3dsp_init.c
index ed38a8e4df..354e1a1944 100644
--- a/libavcodec/x86/vp3dsp_init.c
+++ b/libavcodec/x86/vp3dsp_init.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2009 David Conrad <lessen42@gmail.com>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,7 +25,6 @@
#include "libavutil/x86/cpu.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/vp3dsp.h"
-#include "config.h"
void ff_vp3_idct_put_mmx(uint8_t *dest, int line_size, int16_t *block);
void ff_vp3_idct_add_mmx(uint8_t *dest, int line_size, int16_t *block);
@@ -39,16 +40,21 @@ void ff_vp3_v_loop_filter_mmxext(uint8_t *src, int stride,
void ff_vp3_h_loop_filter_mmxext(uint8_t *src, int stride,
int *bounding_values);
+void ff_put_vp_no_rnd_pixels8_l2_mmx(uint8_t *dst, const uint8_t *a,
+ const uint8_t *b, ptrdiff_t stride,
+ int h);
+
av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags)
{
int cpu_flags = av_get_cpu_flags();
-#if ARCH_X86_32
if (EXTERNAL_MMX(cpu_flags)) {
+ c->put_no_rnd_pixels_l2 = ff_put_vp_no_rnd_pixels8_l2_mmx;
+#if ARCH_X86_32
c->idct_put = ff_vp3_idct_put_mmx;
c->idct_add = ff_vp3_idct_add_mmx;
- }
#endif
+ }
if (EXTERNAL_MMXEXT(cpu_flags)) {
c->idct_dc_add = ff_vp3_idct_dc_add_mmxext;
diff --git a/libavcodec/x86/vp56_arith.h b/libavcodec/x86/vp56_arith.h
index 0a693684af..810cc8dcd8 100644
--- a/libavcodec/x86/vp56_arith.h
+++ b/libavcodec/x86/vp56_arith.h
@@ -4,49 +4,46 @@
* Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
* Copyright (C) 2010 Eli Friedman
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_X86_VP56_ARITH_H
#define AVCODEC_X86_VP56_ARITH_H
-#if HAVE_INLINE_ASM && HAVE_FAST_CMOV
+#if HAVE_INLINE_ASM && HAVE_FAST_CMOV && HAVE_6REGS
#define vp56_rac_get_prob vp56_rac_get_prob
static av_always_inline int vp56_rac_get_prob(VP56RangeCoder *c, uint8_t prob)
{
unsigned int code_word = vp56_rac_renorm(c);
- unsigned int high = c->high;
- unsigned int low = 1 + (((high - 1) * prob) >> 8);
+ unsigned int low = 1 + (((c->high - 1) * prob) >> 8);
unsigned int low_shift = low << 16;
int bit = 0;
+ c->code_word = code_word;
__asm__(
"subl %4, %1 \n\t"
"subl %3, %2 \n\t"
- "leal (%2, %3), %3 \n\t"
"setae %b0 \n\t"
"cmovb %4, %1 \n\t"
- "cmovb %3, %2 \n\t"
- : "+q"(bit), "+r"(high), "+r"(code_word), "+r"(low_shift)
- : "r"(low)
+ "cmovb %5, %2 \n\t"
+ : "+q"(bit), "+&r"(c->high), "+&r"(c->code_word)
+ : "r"(low_shift), "r"(low), "r"(code_word)
);
- c->high = high;
- c->code_word = code_word;
return bit;
}
#endif
diff --git a/libavcodec/x86/vp6dsp.asm b/libavcodec/x86/vp6dsp.asm
index 80f8ca5f38..3d874ea62a 100644
--- a/libavcodec/x86/vp6dsp.asm
+++ b/libavcodec/x86/vp6dsp.asm
@@ -3,20 +3,20 @@
;* Copyright (C) 2009 Sebastien Lucas <sebastien.lucas@gmail.com>
;* Copyright (C) 2009 Zuxy Meng <zuxy.meng@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/vp6dsp_init.c b/libavcodec/x86/vp6dsp_init.c
index cd94f3e038..82baee7e97 100644
--- a/libavcodec/x86/vp6dsp_init.c
+++ b/libavcodec/x86/vp6dsp_init.c
@@ -3,20 +3,20 @@
* Copyright (C) 2009 Sebastien Lucas <sebastien.lucas@gmail.com>
* Copyright (C) 2009 Zuxy Meng <zuxy.meng@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/x86/vp8dsp.asm b/libavcodec/x86/vp8dsp.asm
index adc9730dfa..538b3f4a9b 100644
--- a/libavcodec/x86/vp8dsp.asm
+++ b/libavcodec/x86/vp8dsp.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2010 Ronald S. Bultje <rsbultje@gmail.com>
;* Copyright (c) 2010 Fiona Glaser <fiona@x264.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -143,13 +143,13 @@ filter_h6_shuf1: db 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12
filter_h6_shuf2: db 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9
filter_h6_shuf3: db 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11
-pw_256: times 8 dw 256
pw_20091: times 4 dw 20091
pw_17734: times 4 dw 17734
cextern pw_3
cextern pw_4
cextern pw_64
+cextern pw_256
SECTION .text
diff --git a/libavcodec/x86/vp8dsp_init.c b/libavcodec/x86/vp8dsp_init.c
index e5afd493bb..8d5d033744 100644
--- a/libavcodec/x86/vp8dsp_init.c
+++ b/libavcodec/x86/vp8dsp_init.c
@@ -3,20 +3,20 @@
* Copyright (c) 2010 Ronald S. Bultje <rsbultje@gmail.com>
* Copyright (c) 2010 Fiona Glaser <fiona@x264.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -169,7 +169,7 @@ static void ff_put_vp8_epel ## SIZE ## _h ## TAPNUMX ## v ## TAPNUMY ## _ ## OPT
uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \
ptrdiff_t srcstride, int height, int mx, int my) \
{ \
- DECLARE_ALIGNED(ALIGN, uint8_t, tmp)[SIZE * (MAXHEIGHT + TAPNUMY - 1)]; \
+ LOCAL_ALIGNED(ALIGN, uint8_t, tmp, [SIZE * (MAXHEIGHT + TAPNUMY - 1)]); \
uint8_t *tmpptr = tmp + SIZE * (TAPNUMY / 2 - 1); \
src -= srcstride * (TAPNUMY / 2 - 1); \
ff_put_vp8_epel ## SIZE ## _h ## TAPNUMX ## _ ## OPT( \
@@ -214,7 +214,7 @@ static void ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT( \
uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \
ptrdiff_t srcstride, int height, int mx, int my) \
{ \
- DECLARE_ALIGNED(ALIGN, uint8_t, tmp)[SIZE * (MAXHEIGHT + 2)]; \
+ LOCAL_ALIGNED(ALIGN, uint8_t, tmp, [SIZE * (MAXHEIGHT + 2)]); \
ff_put_vp8_bilinear ## SIZE ## _h_ ## OPT( \
tmp, SIZE, src, srcstride, height + 1, mx, my); \
ff_put_vp8_bilinear ## SIZE ## _v_ ## OPT( \
@@ -347,7 +347,7 @@ av_cold void ff_vp78dsp_init_x86(VP8DSPContext *c)
c->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_sse;
}
- if (EXTERNAL_SSE2(cpu_flags) && (cpu_flags & AV_CPU_FLAG_SSE2SLOW)) {
+ if (HAVE_SSE2_EXTERNAL && cpu_flags & (AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_SSE2SLOW)) {
VP8_LUMA_MC_FUNC(0, 16, sse2);
VP8_MC_FUNC(1, 8, sse2);
VP8_BILINEAR_MC_FUNC(0, 16, sse2);
@@ -417,7 +417,7 @@ av_cold void ff_vp8dsp_init_x86(VP8DSPContext *c)
c->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_sse;
}
- if (EXTERNAL_SSE2(cpu_flags) && (cpu_flags & AV_CPU_FLAG_SSE2SLOW)) {
+ if (HAVE_SSE2_EXTERNAL && cpu_flags & (AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_SSE2SLOW)) {
c->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter_simple_sse2;
c->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16y_inner_sse2;
@@ -430,7 +430,7 @@ av_cold void ff_vp8dsp_init_x86(VP8DSPContext *c)
if (EXTERNAL_SSE2(cpu_flags)) {
c->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_sse2;
- c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_sse2;
+ c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_sse2;
c->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16y_inner_sse2;
c->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_sse2;
@@ -455,7 +455,7 @@ av_cold void ff_vp8dsp_init_x86(VP8DSPContext *c)
}
if (EXTERNAL_SSE4(cpu_flags)) {
- c->vp8_idct_dc_add = ff_vp8_idct_dc_add_sse4;
+ c->vp8_idct_dc_add = ff_vp8_idct_dc_add_sse4;
c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_sse4;
c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_sse4;
diff --git a/libavcodec/x86/vp8dsp_loopfilter.asm b/libavcodec/x86/vp8dsp_loopfilter.asm
index 5d792e8207..98bb6696a0 100644
--- a/libavcodec/x86/vp8dsp_loopfilter.asm
+++ b/libavcodec/x86/vp8dsp_loopfilter.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2010 Ronald S. Bultje <rsbultje@gmail.com>
;* Copyright (c) 2010 Fiona Glaser <fiona@x264.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavcodec/x86/vp9dsp.asm b/libavcodec/x86/vp9dsp.asm
deleted file mode 100644
index 6488f3092d..0000000000
--- a/libavcodec/x86/vp9dsp.asm
+++ /dev/null
@@ -1,277 +0,0 @@
-;******************************************************************************
-;* VP9 SIMD optimizations
-;*
-;* Copyright (c) 2013 Ronald S. Bultje <rsbultje gmail com>
-;*
-;* This file is part of Libav.
-;*
-;* Libav is free software; you can redistribute it and/or
-;* modify it under the terms of the GNU Lesser General Public
-;* License as published by the Free Software Foundation; either
-;* version 2.1 of the License, or (at your option) any later version.
-;*
-;* Libav is distributed in the hope that it will be useful,
-;* but WITHOUT ANY WARRANTY; without even the implied warranty of
-;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;* Lesser General Public License for more details.
-;*
-;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; 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
-
-; FIXME share with vp8dsp.asm
-pw_256: times 8 dw 256
-
-%macro F8_TAPS 8
-times 8 db %1, %2
-times 8 db %3, %4
-times 8 db %5, %6
-times 8 db %7, %8
-%endmacro
-; int8_t ff_filters_ssse3[3][15][4][16]
-const filters_ssse3 ; smooth
- F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0
- F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0
- F8_TAPS -2, -2, 26, 63, 43, 4, -4, 0
- F8_TAPS -2, -3, 24, 62, 46, 5, -4, 0
- F8_TAPS -2, -3, 21, 60, 49, 7, -4, 0
- F8_TAPS -1, -4, 18, 59, 51, 9, -4, 0
- F8_TAPS -1, -4, 16, 57, 53, 12, -4, -1
- F8_TAPS -1, -4, 14, 55, 55, 14, -4, -1
- F8_TAPS -1, -4, 12, 53, 57, 16, -4, -1
- F8_TAPS 0, -4, 9, 51, 59, 18, -4, -1
- F8_TAPS 0, -4, 7, 49, 60, 21, -3, -2
- F8_TAPS 0, -4, 5, 46, 62, 24, -3, -2
- F8_TAPS 0, -4, 4, 43, 63, 26, -2, -2
- F8_TAPS 0, -3, 2, 41, 63, 29, -2, -2
- F8_TAPS 0, -3, 1, 38, 64, 32, -1, -3
- ; regular
- F8_TAPS 0, 1, -5, 126, 8, -3, 1, 0
- F8_TAPS -1, 3, -10, 122, 18, -6, 2, 0
- F8_TAPS -1, 4, -13, 118, 27, -9, 3, -1
- F8_TAPS -1, 4, -16, 112, 37, -11, 4, -1
- F8_TAPS -1, 5, -18, 105, 48, -14, 4, -1
- F8_TAPS -1, 5, -19, 97, 58, -16, 5, -1
- F8_TAPS -1, 6, -19, 88, 68, -18, 5, -1
- F8_TAPS -1, 6, -19, 78, 78, -19, 6, -1
- F8_TAPS -1, 5, -18, 68, 88, -19, 6, -1
- F8_TAPS -1, 5, -16, 58, 97, -19, 5, -1
- F8_TAPS -1, 4, -14, 48, 105, -18, 5, -1
- F8_TAPS -1, 4, -11, 37, 112, -16, 4, -1
- F8_TAPS -1, 3, -9, 27, 118, -13, 4, -1
- F8_TAPS 0, 2, -6, 18, 122, -10, 3, -1
- F8_TAPS 0, 1, -3, 8, 126, -5, 1, 0
- ; sharp
- F8_TAPS -1, 3, -7, 127, 8, -3, 1, 0
- F8_TAPS -2, 5, -13, 125, 17, -6, 3, -1
- F8_TAPS -3, 7, -17, 121, 27, -10, 5, -2
- F8_TAPS -4, 9, -20, 115, 37, -13, 6, -2
- F8_TAPS -4, 10, -23, 108, 48, -16, 8, -3
- F8_TAPS -4, 10, -24, 100, 59, -19, 9, -3
- F8_TAPS -4, 11, -24, 90, 70, -21, 10, -4
- F8_TAPS -4, 11, -23, 80, 80, -23, 11, -4
- F8_TAPS -4, 10, -21, 70, 90, -24, 11, -4
- F8_TAPS -3, 9, -19, 59, 100, -24, 10, -4
- F8_TAPS -3, 8, -16, 48, 108, -23, 10, -4
- F8_TAPS -2, 6, -13, 37, 115, -20, 9, -4
- F8_TAPS -2, 5, -10, 27, 121, -17, 7, -3
- F8_TAPS -1, 3, -6, 17, 125, -13, 5, -2
- F8_TAPS 0, 1, -3, 8, 127, -7, 3, -1
-
-SECTION .text
-
-%macro filter_h_fn 1
-%assign %%px mmsize/2
-cglobal %1_8tap_1d_h_ %+ %%px, 6, 6, 11, dst, src, dstride, sstride, h, filtery
- mova m6, [pw_256]
- mova m7, [filteryq+ 0]
-%if ARCH_X86_64 && mmsize > 8
- mova m8, [filteryq+16]
- mova m9, [filteryq+32]
- mova m10, [filteryq+48]
-%endif
-.loop:
- movh m0, [srcq-3]
- movh m1, [srcq-2]
- movh m2, [srcq-1]
- movh m3, [srcq+0]
- movh m4, [srcq+1]
- movh m5, [srcq+2]
- punpcklbw m0, m1
- punpcklbw m2, m3
- movh m1, [srcq+3]
- movh m3, [srcq+4]
- add srcq, sstrideq
- punpcklbw m4, m5
- punpcklbw m1, m3
- pmaddubsw m0, m7
-%if ARCH_X86_64 && mmsize > 8
- pmaddubsw m2, m8
- pmaddubsw m4, m9
- pmaddubsw m1, m10
-%else
- pmaddubsw m2, [filteryq+16]
- pmaddubsw m4, [filteryq+32]
- pmaddubsw m1, [filteryq+48]
-%endif
- paddw m0, m2
- paddw m4, m1
- paddsw m0, m4
- pmulhrsw m0, m6
-%ifidn %1, avg
- movh m1, [dstq]
-%endif
- packuswb m0, m0
-%ifidn %1, avg
- pavgb m0, m1
-%endif
- movh [dstq], m0
- add dstq, dstrideq
- dec hd
- jg .loop
- RET
-%endmacro
-
-INIT_MMX ssse3
-filter_h_fn put
-filter_h_fn avg
-
-INIT_XMM ssse3
-filter_h_fn put
-filter_h_fn avg
-
-%macro filter_v_fn 1
-%assign %%px mmsize/2
-%if ARCH_X86_64
-cglobal %1_8tap_1d_v_ %+ %%px, 6, 8, 11, dst, src, dstride, sstride, h, filtery, src4, sstride3
-%else
-cglobal %1_8tap_1d_v_ %+ %%px, 4, 7, 11, dst, src, dstride, sstride, filtery, src4, sstride3
- mov filteryq, r5mp
-%define hd r4mp
-%endif
- sub srcq, sstrideq
- lea sstride3q, [sstrideq*3]
- sub srcq, sstrideq
- mova m6, [pw_256]
- sub srcq, sstrideq
- mova m7, [filteryq+ 0]
- lea src4q, [srcq+sstrideq*4]
-%if ARCH_X86_64 && mmsize > 8
- mova m8, [filteryq+16]
- mova m9, [filteryq+32]
- mova m10, [filteryq+48]
-%endif
-.loop:
- ; FIXME maybe reuse loads from previous rows, or just more generally
- ; unroll this to prevent multiple loads of the same data?
- movh m0, [srcq]
- movh m1, [srcq+sstrideq]
- movh m2, [srcq+sstrideq*2]
- movh m3, [srcq+sstride3q]
- movh m4, [src4q]
- movh m5, [src4q+sstrideq]
- punpcklbw m0, m1
- punpcklbw m2, m3
- movh m1, [src4q+sstrideq*2]
- movh m3, [src4q+sstride3q]
- add srcq, sstrideq
- add src4q, sstrideq
- punpcklbw m4, m5
- punpcklbw m1, m3
- pmaddubsw m0, m7
-%if ARCH_X86_64 && mmsize > 8
- pmaddubsw m2, m8
- pmaddubsw m4, m9
- pmaddubsw m1, m10
-%else
- pmaddubsw m2, [filteryq+16]
- pmaddubsw m4, [filteryq+32]
- pmaddubsw m1, [filteryq+48]
-%endif
- paddw m0, m2
- paddw m4, m1
- paddsw m0, m4
- pmulhrsw m0, m6
-%ifidn %1, avg
- movh m1, [dstq]
-%endif
- packuswb m0, m0
-%ifidn %1, avg
- pavgb m0, m1
-%endif
- movh [dstq], m0
- add dstq, dstrideq
- dec hd
- jg .loop
- RET
-%endmacro
-
-INIT_MMX ssse3
-filter_v_fn put
-filter_v_fn avg
-
-INIT_XMM ssse3
-filter_v_fn put
-filter_v_fn avg
-
-%macro fpel_fn 6
-%if %2 == 4
-%define %%srcfn movh
-%define %%dstfn movh
-%else
-%define %%srcfn movu
-%define %%dstfn mova
-%endif
-
-%if %2 <= 16
-cglobal %1%2, 5, 7, 4, dst, src, dstride, sstride, h, dstride3, sstride3
- lea sstride3q, [sstrideq*3]
- lea dstride3q, [dstrideq*3]
-%else
-cglobal %1%2, 5, 5, 4, dst, src, dstride, sstride, h
-%endif
-.loop:
- %%srcfn m0, [srcq]
- %%srcfn m1, [srcq+s%3]
- %%srcfn m2, [srcq+s%4]
- %%srcfn m3, [srcq+s%5]
- lea srcq, [srcq+sstrideq*%6]
-%ifidn %1, avg
- pavgb m0, [dstq]
- pavgb m1, [dstq+d%3]
- pavgb m2, [dstq+d%4]
- pavgb m3, [dstq+d%5]
-%endif
- %%dstfn [dstq], m0
- %%dstfn [dstq+d%3], m1
- %%dstfn [dstq+d%4], m2
- %%dstfn [dstq+d%5], m3
- lea dstq, [dstq+dstrideq*%6]
- sub hd, %6
- jnz .loop
- RET
-%endmacro
-
-%define d16 16
-%define s16 16
-INIT_MMX mmx
-fpel_fn put, 4, strideq, strideq*2, stride3q, 4
-fpel_fn put, 8, strideq, strideq*2, stride3q, 4
-INIT_MMX sse
-fpel_fn avg, 4, strideq, strideq*2, stride3q, 4
-fpel_fn avg, 8, strideq, strideq*2, stride3q, 4
-INIT_XMM sse
-fpel_fn put, 16, strideq, strideq*2, stride3q, 4
-fpel_fn put, 32, mmsize, strideq, strideq+mmsize, 2
-fpel_fn put, 64, mmsize, mmsize*2, mmsize*3, 1
-INIT_XMM sse2
-fpel_fn avg, 16, strideq, strideq*2, stride3q, 4
-fpel_fn avg, 32, mmsize, strideq, strideq+mmsize, 2
-fpel_fn avg, 64, mmsize, mmsize*2, mmsize*3, 1
-%undef s16
-%undef d16
diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c
index ce58c08a3b..979bd936ac 100644
--- a/libavcodec/x86/vp9dsp_init.c
+++ b/libavcodec/x86/vp9dsp_init.c
@@ -1,240 +1,509 @@
/*
* VP9 SIMD optimizations
*
- * Copyright (c) 2013 Ronald S. Bultje <rsbultje@gmail.com>
+ * Copyright (c) 2013 Ronald S. Bultje <rsbultje gmail com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/internal.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
-#include "libavcodec/vp9.h"
+#include "libavcodec/vp9dsp.h"
#if HAVE_YASM
-#define fpel_func(avg, sz, opt) \
-void ff_ ## avg ## sz ## _ ## opt(uint8_t *dst, const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my)
-
+#define fpel_func(avg, sz, opt) \
+void ff_vp9_##avg##sz##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my)
fpel_func(put, 4, mmx);
fpel_func(put, 8, mmx);
fpel_func(put, 16, sse);
fpel_func(put, 32, sse);
fpel_func(put, 64, sse);
-fpel_func(avg, 4, sse);
-fpel_func(avg, 8, sse);
+fpel_func(avg, 4, mmxext);
+fpel_func(avg, 8, mmxext);
fpel_func(avg, 16, sse2);
fpel_func(avg, 32, sse2);
fpel_func(avg, 64, sse2);
+fpel_func(put, 32, avx);
+fpel_func(put, 64, avx);
+fpel_func(avg, 32, avx2);
+fpel_func(avg, 64, avx2);
#undef fpel_func
-#define mc_func(avg, sz, dir, opt) \
-void \
-ff_ ## avg ## _8tap_1d_ ## dir ## _ ## sz ## _ ## opt(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, \
- const int8_t (*filter)[16])
-
-#define mc_funcs(sz) \
- mc_func(put, sz, h, ssse3); \
- mc_func(avg, sz, h, ssse3); \
- mc_func(put, sz, v, ssse3); \
- mc_func(avg, sz, v, ssse3)
-
-mc_funcs(4);
-mc_funcs(8);
+#define mc_func(avg, sz, dir, opt, type, f_sz) \
+void ff_vp9_##avg##_8tap_1d_##dir##_##sz##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, const type (*filter)[f_sz])
+#define mc_funcs(sz, opt, type, fsz) \
+mc_func(put, sz, h, opt, type, fsz); \
+mc_func(avg, sz, h, opt, type, fsz); \
+mc_func(put, sz, v, opt, type, fsz); \
+mc_func(avg, sz, v, opt, type, fsz)
+
+mc_funcs(4, mmxext, int16_t, 8);
+mc_funcs(8, sse2, int16_t, 8);
+mc_funcs(4, ssse3, int8_t, 32);
+mc_funcs(8, ssse3, int8_t, 32);
+#if ARCH_X86_64
+mc_funcs(16, ssse3, int8_t, 32);
+mc_funcs(32, avx2, int8_t, 32);
+#endif
#undef mc_funcs
#undef mc_func
-#define mc_rep_func(avg, sz, hsz, dir, opt) \
-static av_always_inline void \
-ff_ ## avg ## _8tap_1d_ ## dir ## _ ## sz ## _ ## opt(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, \
- const int8_t (*filter)[16]) \
-{ \
- ff_ ## avg ## _8tap_1d_ ## dir ## _ ## hsz ## _ ## opt(dst, src, \
- dst_stride, \
- src_stride, \
- h, \
- filter); \
- ff_ ## avg ## _8tap_1d_ ## dir ## _ ## hsz ## _ ## opt(dst + hsz, \
- src + hsz, \
- dst_stride, \
- src_stride, \
- h, filter); \
+#define mc_rep_func(avg, sz, hsz, dir, opt, type, f_sz) \
+static av_always_inline void \
+ff_vp9_##avg##_8tap_1d_##dir##_##sz##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, const type (*filter)[f_sz]) \
+{ \
+ ff_vp9_##avg##_8tap_1d_##dir##_##hsz##_##opt(dst, dst_stride, src, \
+ src_stride, h, filter); \
+ ff_vp9_##avg##_8tap_1d_##dir##_##hsz##_##opt(dst + hsz, dst_stride, src + hsz, \
+ src_stride, h, filter); \
}
-#define mc_rep_funcs(sz, hsz) \
- mc_rep_func(put, sz, hsz, h, ssse3); \
- mc_rep_func(avg, sz, hsz, h, ssse3); \
- mc_rep_func(put, sz, hsz, v, ssse3); \
- mc_rep_func(avg, sz, hsz, v, ssse3)
-
-mc_rep_funcs(16, 8);
-mc_rep_funcs(32, 16);
-mc_rep_funcs(64, 32);
+#define mc_rep_funcs(sz, hsz, opt, type, fsz) \
+mc_rep_func(put, sz, hsz, h, opt, type, fsz); \
+mc_rep_func(avg, sz, hsz, h, opt, type, fsz); \
+mc_rep_func(put, sz, hsz, v, opt, type, fsz); \
+mc_rep_func(avg, sz, hsz, v, opt, type, fsz)
+
+mc_rep_funcs(16, 8, sse2, int16_t, 8);
+#if ARCH_X86_32
+mc_rep_funcs(16, 8, ssse3, int8_t, 32);
+#endif
+mc_rep_funcs(32, 16, sse2, int16_t, 8);
+mc_rep_funcs(32, 16, ssse3, int8_t, 32);
+mc_rep_funcs(64, 32, sse2, int16_t, 8);
+mc_rep_funcs(64, 32, ssse3, int8_t, 32);
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+mc_rep_funcs(64, 32, avx2, int8_t, 32);
+#endif
#undef mc_rep_funcs
#undef mc_rep_func
-extern const int8_t ff_filters_ssse3[3][15][4][16];
-
-#define filter_8tap_2d_fn(op, sz, f, fname) \
-static void \
-op ## _8tap_ ## fname ## _ ## sz ## hv_ssse3(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, int my) \
-{ \
- LOCAL_ALIGNED_16(uint8_t, temp, [71 * 64]); \
- ff_put_8tap_1d_h_ ## sz ## _ssse3(temp, src - 3 * src_stride, \
- 64, src_stride, \
- h + 7, \
- ff_filters_ssse3[f][mx - 1]); \
- ff_ ## op ## _8tap_1d_v_ ## sz ## _ssse3(dst, temp + 3 * 64, \
- dst_stride, 64, \
- h, \
- ff_filters_ssse3[f][my - 1]); \
+extern const int8_t ff_filters_ssse3[3][15][4][32];
+extern const int16_t ff_filters_sse2[3][15][8][8];
+
+#define filter_8tap_2d_fn(op, sz, f, f_opt, fname, align, opt) \
+static void op##_8tap_##fname##_##sz##hv_##opt(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ LOCAL_ALIGNED_##align(uint8_t, temp, [71 * 64]); \
+ ff_vp9_put_8tap_1d_h_##sz##_##opt(temp, 64, src - 3 * src_stride, src_stride, \
+ h + 7, ff_filters_##f_opt[f][mx - 1]); \
+ ff_vp9_##op##_8tap_1d_v_##sz##_##opt(dst, dst_stride, temp + 3 * 64, 64, \
+ h, ff_filters_##f_opt[f][my - 1]); \
}
-#define filters_8tap_2d_fn(op, sz) \
- filter_8tap_2d_fn(op, sz, FILTER_8TAP_REGULAR, regular) \
- filter_8tap_2d_fn(op, sz, FILTER_8TAP_SHARP, sharp) \
- filter_8tap_2d_fn(op, sz, FILTER_8TAP_SMOOTH, smooth)
-
-#define filters_8tap_2d_fn2(op) \
- filters_8tap_2d_fn(op, 64) \
- filters_8tap_2d_fn(op, 32) \
- filters_8tap_2d_fn(op, 16) \
- filters_8tap_2d_fn(op, 8) \
- filters_8tap_2d_fn(op, 4)
-
-filters_8tap_2d_fn2(put)
-filters_8tap_2d_fn2(avg)
+#define filters_8tap_2d_fn(op, sz, align, opt, f_opt) \
+filter_8tap_2d_fn(op, sz, FILTER_8TAP_REGULAR, f_opt, regular, align, opt) \
+filter_8tap_2d_fn(op, sz, FILTER_8TAP_SHARP, f_opt, sharp, align, opt) \
+filter_8tap_2d_fn(op, sz, FILTER_8TAP_SMOOTH, f_opt, smooth, align, opt)
+
+#define filters_8tap_2d_fn2(op, align, opt4, opt8, f_opt) \
+filters_8tap_2d_fn(op, 64, align, opt8, f_opt) \
+filters_8tap_2d_fn(op, 32, align, opt8, f_opt) \
+filters_8tap_2d_fn(op, 16, align, opt8, f_opt) \
+filters_8tap_2d_fn(op, 8, align, opt8, f_opt) \
+filters_8tap_2d_fn(op, 4, align, opt4, f_opt)
+
+filters_8tap_2d_fn2(put, 16, mmxext, sse2, sse2)
+filters_8tap_2d_fn2(avg, 16, mmxext, sse2, sse2)
+filters_8tap_2d_fn2(put, 16, ssse3, ssse3, ssse3)
+filters_8tap_2d_fn2(avg, 16, ssse3, ssse3, ssse3)
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+filters_8tap_2d_fn(put, 64, 32, avx2, ssse3)
+filters_8tap_2d_fn(put, 32, 32, avx2, ssse3)
+filters_8tap_2d_fn(avg, 64, 32, avx2, ssse3)
+filters_8tap_2d_fn(avg, 32, 32, avx2, ssse3)
+#endif
#undef filters_8tap_2d_fn2
#undef filters_8tap_2d_fn
#undef filter_8tap_2d_fn
-#define filter_8tap_1d_fn(op, sz, f, fname, dir, dvar) \
-static void \
-op ## _8tap_ ## fname ## _ ## sz ## dir ## _ssse3(uint8_t *dst, \
- const uint8_t *src, \
- ptrdiff_t dst_stride, \
- ptrdiff_t src_stride, \
- int h, int mx, \
- int my) \
-{ \
- ff_ ## op ## _8tap_1d_ ## dir ## _ ## sz ## _ssse3(dst, src, \
- dst_stride, \
- src_stride, h, \
- ff_filters_ssse3[f][dvar - 1]); \
+#define filter_8tap_1d_fn(op, sz, f, f_opt, fname, dir, dvar, opt) \
+static void op##_8tap_##fname##_##sz##dir##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \
+ const uint8_t *src, ptrdiff_t src_stride, \
+ int h, int mx, int my) \
+{ \
+ ff_vp9_##op##_8tap_1d_##dir##_##sz##_##opt(dst, dst_stride, src, src_stride, \
+ h, ff_filters_##f_opt[f][dvar - 1]); \
}
-#define filters_8tap_1d_fn(op, sz, dir, dvar) \
- filter_8tap_1d_fn(op, sz, FILTER_8TAP_REGULAR, regular, dir, dvar) \
- filter_8tap_1d_fn(op, sz, FILTER_8TAP_SHARP, sharp, dir, dvar) \
- filter_8tap_1d_fn(op, sz, FILTER_8TAP_SMOOTH, smooth, dir, dvar)
-
-#define filters_8tap_1d_fn2(op, sz) \
- filters_8tap_1d_fn(op, sz, h, mx) \
- filters_8tap_1d_fn(op, sz, v, my)
-
-#define filters_8tap_1d_fn3(op) \
- filters_8tap_1d_fn2(op, 64) \
- filters_8tap_1d_fn2(op, 32) \
- filters_8tap_1d_fn2(op, 16) \
- filters_8tap_1d_fn2(op, 8) \
- filters_8tap_1d_fn2(op, 4)
-
-filters_8tap_1d_fn3(put)
-filters_8tap_1d_fn3(avg)
+#define filters_8tap_1d_fn(op, sz, dir, dvar, opt, f_opt) \
+filter_8tap_1d_fn(op, sz, FILTER_8TAP_REGULAR, f_opt, regular, dir, dvar, opt) \
+filter_8tap_1d_fn(op, sz, FILTER_8TAP_SHARP, f_opt, sharp, dir, dvar, opt) \
+filter_8tap_1d_fn(op, sz, FILTER_8TAP_SMOOTH, f_opt, smooth, dir, dvar, opt)
+
+#define filters_8tap_1d_fn2(op, sz, opt, f_opt) \
+filters_8tap_1d_fn(op, sz, h, mx, opt, f_opt) \
+filters_8tap_1d_fn(op, sz, v, my, opt, f_opt)
+
+#define filters_8tap_1d_fn3(op, opt4, opt8, f_opt) \
+filters_8tap_1d_fn2(op, 64, opt8, f_opt) \
+filters_8tap_1d_fn2(op, 32, opt8, f_opt) \
+filters_8tap_1d_fn2(op, 16, opt8, f_opt) \
+filters_8tap_1d_fn2(op, 8, opt8, f_opt) \
+filters_8tap_1d_fn2(op, 4, opt4, f_opt)
+
+filters_8tap_1d_fn3(put, mmxext, sse2, sse2)
+filters_8tap_1d_fn3(avg, mmxext, sse2, sse2)
+filters_8tap_1d_fn3(put, ssse3, ssse3, ssse3)
+filters_8tap_1d_fn3(avg, ssse3, ssse3, ssse3)
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+filters_8tap_1d_fn2(put, 64, avx2, ssse3)
+filters_8tap_1d_fn2(put, 32, avx2, ssse3)
+filters_8tap_1d_fn2(avg, 64, avx2, ssse3)
+filters_8tap_1d_fn2(avg, 32, avx2, ssse3)
+#endif
#undef filters_8tap_1d_fn
#undef filters_8tap_1d_fn2
#undef filters_8tap_1d_fn3
#undef filter_8tap_1d_fn
+#define itxfm_func(typea, typeb, size, opt) \
+void ff_vp9_##typea##_##typeb##_##size##x##size##_add_##opt(uint8_t *dst, ptrdiff_t stride, \
+ int16_t *block, int eob)
+#define itxfm_funcs(size, opt) \
+itxfm_func(idct, idct, size, opt); \
+itxfm_func(iadst, idct, size, opt); \
+itxfm_func(idct, iadst, size, opt); \
+itxfm_func(iadst, iadst, size, opt)
+
+itxfm_func(idct, idct, 4, mmxext);
+itxfm_func(idct, iadst, 4, sse2);
+itxfm_func(iadst, idct, 4, sse2);
+itxfm_func(iadst, iadst, 4, sse2);
+itxfm_funcs(4, ssse3);
+itxfm_funcs(8, sse2);
+itxfm_funcs(8, ssse3);
+itxfm_funcs(8, avx);
+itxfm_funcs(16, sse2);
+itxfm_funcs(16, ssse3);
+itxfm_funcs(16, avx);
+itxfm_func(idct, idct, 32, sse2);
+itxfm_func(idct, idct, 32, ssse3);
+itxfm_func(idct, idct, 32, avx);
+itxfm_func(iwht, iwht, 4, mmx);
+
+#undef itxfm_func
+#undef itxfm_funcs
+
+#define lpf_funcs(size1, size2, opt) \
+void ff_vp9_loop_filter_v_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stride, \
+ int E, int I, int H); \
+void ff_vp9_loop_filter_h_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stride, \
+ int E, int I, int H)
+
+lpf_funcs(16, 16, sse2);
+lpf_funcs(16, 16, ssse3);
+lpf_funcs(16, 16, avx);
+lpf_funcs(44, 16, sse2);
+lpf_funcs(44, 16, ssse3);
+lpf_funcs(44, 16, avx);
+lpf_funcs(84, 16, sse2);
+lpf_funcs(84, 16, ssse3);
+lpf_funcs(84, 16, avx);
+lpf_funcs(48, 16, sse2);
+lpf_funcs(48, 16, ssse3);
+lpf_funcs(48, 16, avx);
+lpf_funcs(88, 16, sse2);
+lpf_funcs(88, 16, ssse3);
+lpf_funcs(88, 16, avx);
+
+#undef lpf_funcs
+
+#define ipred_func(size, type, opt) \
+void ff_vp9_ipred_##type##_##size##x##size##_##opt(uint8_t *dst, ptrdiff_t stride, \
+ const uint8_t *l, const uint8_t *a)
+
+ipred_func(8, v, mmx);
+
+#define ipred_dc_funcs(size, opt) \
+ipred_func(size, dc, opt); \
+ipred_func(size, dc_left, opt); \
+ipred_func(size, dc_top, opt)
+
+ipred_dc_funcs(4, mmxext);
+ipred_dc_funcs(8, mmxext);
+
+#define ipred_dir_tm_funcs(size, opt) \
+ipred_func(size, tm, opt); \
+ipred_func(size, dl, opt); \
+ipred_func(size, dr, opt); \
+ipred_func(size, hd, opt); \
+ipred_func(size, hu, opt); \
+ipred_func(size, vl, opt); \
+ipred_func(size, vr, opt)
+
+ipred_dir_tm_funcs(4, mmxext);
+
+ipred_func(16, v, sse);
+ipred_func(32, v, sse);
+
+ipred_dc_funcs(16, sse2);
+ipred_dc_funcs(32, sse2);
+
+#define ipred_dir_tm_h_funcs(size, opt) \
+ipred_dir_tm_funcs(size, opt); \
+ipred_func(size, h, opt)
+
+ipred_dir_tm_h_funcs(8, sse2);
+ipred_dir_tm_h_funcs(16, sse2);
+ipred_dir_tm_h_funcs(32, sse2);
+
+ipred_func(4, h, sse2);
+
+#define ipred_all_funcs(size, opt) \
+ipred_dc_funcs(size, opt); \
+ipred_dir_tm_h_funcs(size, opt)
+
+// FIXME hd/vl_4x4_ssse3 does not exist
+ipred_all_funcs(4, ssse3);
+ipred_all_funcs(8, ssse3);
+ipred_all_funcs(16, ssse3);
+ipred_all_funcs(32, ssse3);
+
+ipred_dir_tm_h_funcs(8, avx);
+ipred_dir_tm_h_funcs(16, avx);
+ipred_dir_tm_h_funcs(32, avx);
+
+ipred_func(32, v, avx);
+
+ipred_dc_funcs(32, avx2);
+ipred_func(32, h, avx2);
+ipred_func(32, tm, avx2);
+
+#undef ipred_func
+#undef ipred_dir_tm_h_funcs
+#undef ipred_dir_tm_funcs
+#undef ipred_dc_funcs
+
#endif /* HAVE_YASM */
-av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp)
+av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp)
{
#if HAVE_YASM
- int cpu_flags = av_get_cpu_flags();
+ int cpu_flags;
+ if (bpp != 8) return;
-#define init_fpel(idx1, idx2, sz, type, opt) \
- dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \
- dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = \
- dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = \
- dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = ff_ ## type ## sz ## _ ## opt
+ cpu_flags = av_get_cpu_flags();
+#define init_fpel(idx1, idx2, sz, type, opt) \
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = \
+ dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = ff_vp9_##type##sz##_##opt
#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type, opt) \
- dsp->mc[idx1][FILTER_8TAP_SMOOTH][idx2][idxh][idxv] = type ## _8tap_smooth_ ## sz ## dir ## _ ## opt; \
- dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type ## _8tap_regular_ ## sz ## dir ## _ ## opt; \
- dsp->mc[idx1][FILTER_8TAP_SHARP][idx2][idxh][idxv] = type ## _8tap_sharp_ ## sz ## dir ## _ ## opt
-
-#define init_subpel2(idx, idxh, idxv, dir, type, opt) \
- init_subpel1(0, idx, idxh, idxv, 64, dir, type, opt); \
- init_subpel1(1, idx, idxh, idxv, 32, dir, type, opt); \
- init_subpel1(2, idx, idxh, idxv, 16, dir, type, opt); \
- init_subpel1(3, idx, idxh, idxv, 8, dir, type, opt); \
- init_subpel1(4, idx, idxh, idxv, 4, dir, type, opt)
-
-#define init_subpel3(idx, type, opt) \
- init_subpel2(idx, 1, 1, hv, type, opt); \
- init_subpel2(idx, 0, 1, v, type, opt); \
- init_subpel2(idx, 1, 0, h, type, opt)
+ dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][idxh][idxv] = type##_8tap_smooth_##sz##dir##_##opt; \
+ dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type##_8tap_regular_##sz##dir##_##opt; \
+ dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][idxh][idxv] = type##_8tap_sharp_##sz##dir##_##opt
+
+#define init_subpel2(idx1, idx2, sz, type, opt) \
+ init_subpel1(idx1, idx2, 1, 1, sz, hv, type, opt); \
+ init_subpel1(idx1, idx2, 0, 1, sz, v, type, opt); \
+ init_subpel1(idx1, idx2, 1, 0, sz, h, type, opt)
+
+#define init_subpel3_32_64(idx, type, opt) \
+ init_subpel2(0, idx, 64, type, opt); \
+ init_subpel2(1, idx, 32, type, opt)
+
+#define init_subpel3_8to64(idx, type, opt) \
+ init_subpel3_32_64(idx, type, opt); \
+ init_subpel2(2, idx, 16, type, opt); \
+ init_subpel2(3, idx, 8, type, opt)
+
+#define init_subpel3(idx, type, opt) \
+ init_subpel3_8to64(idx, type, opt); \
+ init_subpel2(4, idx, 4, type, opt)
+
+#define init_lpf(opt) do { \
+ dsp->loop_filter_16[0] = ff_vp9_loop_filter_h_16_16_##opt; \
+ dsp->loop_filter_16[1] = ff_vp9_loop_filter_v_16_16_##opt; \
+ dsp->loop_filter_mix2[0][0][0] = ff_vp9_loop_filter_h_44_16_##opt; \
+ dsp->loop_filter_mix2[0][0][1] = ff_vp9_loop_filter_v_44_16_##opt; \
+ dsp->loop_filter_mix2[0][1][0] = ff_vp9_loop_filter_h_48_16_##opt; \
+ dsp->loop_filter_mix2[0][1][1] = ff_vp9_loop_filter_v_48_16_##opt; \
+ dsp->loop_filter_mix2[1][0][0] = ff_vp9_loop_filter_h_84_16_##opt; \
+ dsp->loop_filter_mix2[1][0][1] = ff_vp9_loop_filter_v_84_16_##opt; \
+ dsp->loop_filter_mix2[1][1][0] = ff_vp9_loop_filter_h_88_16_##opt; \
+ dsp->loop_filter_mix2[1][1][1] = ff_vp9_loop_filter_v_88_16_##opt; \
+} while (0)
+
+#define init_ipred(sz, opt, t, e) \
+ dsp->intra_pred[TX_##sz##X##sz][e##_PRED] = ff_vp9_ipred_##t##_##sz##x##sz##_##opt
+
+#define ff_vp9_ipred_hd_4x4_ssse3 ff_vp9_ipred_hd_4x4_mmxext
+#define ff_vp9_ipred_vl_4x4_ssse3 ff_vp9_ipred_vl_4x4_mmxext
+#define init_dir_tm_ipred(sz, opt) do { \
+ init_ipred(sz, opt, dl, DIAG_DOWN_LEFT); \
+ init_ipred(sz, opt, dr, DIAG_DOWN_RIGHT); \
+ init_ipred(sz, opt, hd, HOR_DOWN); \
+ init_ipred(sz, opt, vl, VERT_LEFT); \
+ init_ipred(sz, opt, hu, HOR_UP); \
+ init_ipred(sz, opt, tm, TM_VP8); \
+ init_ipred(sz, opt, vr, VERT_RIGHT); \
+} while (0)
+#define init_dir_tm_h_ipred(sz, opt) do { \
+ init_dir_tm_ipred(sz, opt); \
+ init_ipred(sz, opt, h, HOR); \
+} while (0)
+#define init_dc_ipred(sz, opt) do { \
+ init_ipred(sz, opt, dc, DC); \
+ init_ipred(sz, opt, dc_left, LEFT_DC); \
+ init_ipred(sz, opt, dc_top, TOP_DC); \
+} while (0)
+#define init_all_ipred(sz, opt) do { \
+ init_dc_ipred(sz, opt); \
+ init_dir_tm_h_ipred(sz, opt); \
+} while (0)
if (EXTERNAL_MMX(cpu_flags)) {
init_fpel(4, 0, 4, put, mmx);
init_fpel(3, 0, 8, put, mmx);
+ dsp->itxfm_add[4 /* lossless */][DCT_DCT] =
+ dsp->itxfm_add[4 /* lossless */][ADST_DCT] =
+ dsp->itxfm_add[4 /* lossless */][DCT_ADST] =
+ dsp->itxfm_add[4 /* lossless */][ADST_ADST] = ff_vp9_iwht_iwht_4x4_add_mmx;
+ init_ipred(8, mmx, v, VERT);
+ }
+
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ init_subpel2(4, 0, 4, put, mmxext);
+ init_subpel2(4, 1, 4, avg, mmxext);
+ init_fpel(4, 1, 4, avg, mmxext);
+ init_fpel(3, 1, 8, avg, mmxext);
+ dsp->itxfm_add[TX_4X4][DCT_DCT] = ff_vp9_idct_idct_4x4_add_mmxext;
+ init_dc_ipred(4, mmxext);
+ init_dc_ipred(8, mmxext);
+ init_dir_tm_ipred(4, mmxext);
}
if (EXTERNAL_SSE(cpu_flags)) {
init_fpel(2, 0, 16, put, sse);
init_fpel(1, 0, 32, put, sse);
init_fpel(0, 0, 64, put, sse);
- init_fpel(4, 1, 4, avg, sse);
- init_fpel(3, 1, 8, avg, sse);
+ init_ipred(16, sse, v, VERT);
+ init_ipred(32, sse, v, VERT);
}
if (EXTERNAL_SSE2(cpu_flags)) {
+ init_subpel3_8to64(0, put, sse2);
+ init_subpel3_8to64(1, avg, sse2);
init_fpel(2, 1, 16, avg, sse2);
init_fpel(1, 1, 32, avg, sse2);
init_fpel(0, 1, 64, avg, sse2);
+ init_lpf(sse2);
+ dsp->itxfm_add[TX_4X4][ADST_DCT] = ff_vp9_idct_iadst_4x4_add_sse2;
+ dsp->itxfm_add[TX_4X4][DCT_ADST] = ff_vp9_iadst_idct_4x4_add_sse2;
+ dsp->itxfm_add[TX_4X4][ADST_ADST] = ff_vp9_iadst_iadst_4x4_add_sse2;
+ dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_sse2;
+ dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_sse2;
+ dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_sse2;
+ dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_sse2;
+ dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_sse2;
+ dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_sse2;
+ dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_sse2;
+ dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_sse2;
+ dsp->itxfm_add[TX_32X32][ADST_ADST] =
+ dsp->itxfm_add[TX_32X32][ADST_DCT] =
+ dsp->itxfm_add[TX_32X32][DCT_ADST] =
+ dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_sse2;
+ init_dc_ipred(16, sse2);
+ init_dc_ipred(32, sse2);
+ init_dir_tm_h_ipred(8, sse2);
+ init_dir_tm_h_ipred(16, sse2);
+ init_dir_tm_h_ipred(32, sse2);
+ init_ipred(4, sse2, h, HOR);
}
if (EXTERNAL_SSSE3(cpu_flags)) {
init_subpel3(0, put, ssse3);
init_subpel3(1, avg, ssse3);
+ dsp->itxfm_add[TX_4X4][DCT_DCT] = ff_vp9_idct_idct_4x4_add_ssse3;
+ dsp->itxfm_add[TX_4X4][ADST_DCT] = ff_vp9_idct_iadst_4x4_add_ssse3;
+ dsp->itxfm_add[TX_4X4][DCT_ADST] = ff_vp9_iadst_idct_4x4_add_ssse3;
+ dsp->itxfm_add[TX_4X4][ADST_ADST] = ff_vp9_iadst_iadst_4x4_add_ssse3;
+ dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_ssse3;
+ dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_ssse3;
+ dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_ssse3;
+ dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_ssse3;
+ dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_ssse3;
+ dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_ssse3;
+ dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_ssse3;
+ dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_ssse3;
+ dsp->itxfm_add[TX_32X32][ADST_ADST] =
+ dsp->itxfm_add[TX_32X32][ADST_DCT] =
+ dsp->itxfm_add[TX_32X32][DCT_ADST] =
+ dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_ssse3;
+ init_lpf(ssse3);
+ init_all_ipred(4, ssse3);
+ init_all_ipred(8, ssse3);
+ init_all_ipred(16, ssse3);
+ init_all_ipred(32, ssse3);
+ }
+
+ if (EXTERNAL_AVX(cpu_flags)) {
+ dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_avx;
+ dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_avx;
+ dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_avx;
+ dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_avx;
+ dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx;
+ dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx;
+ dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx;
+ dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_avx;
+ dsp->itxfm_add[TX_32X32][ADST_ADST] =
+ dsp->itxfm_add[TX_32X32][ADST_DCT] =
+ dsp->itxfm_add[TX_32X32][DCT_ADST] =
+ dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx;
+ init_fpel(1, 0, 32, put, avx);
+ init_fpel(0, 0, 64, put, avx);
+ init_lpf(avx);
+ init_dir_tm_h_ipred(8, avx);
+ init_dir_tm_h_ipred(16, avx);
+ init_dir_tm_h_ipred(32, avx);
+ init_ipred(32, avx, v, VERT);
+ }
+
+ if (EXTERNAL_AVX2(cpu_flags)) {
+ init_fpel(1, 1, 32, avg, avx2);
+ init_fpel(0, 1, 64, avg, avx2);
+ if (ARCH_X86_64) {
+#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL
+ init_subpel3_32_64(0, put, avx2);
+ init_subpel3_32_64(1, avg, avx2);
+#endif
+ }
+ init_dc_ipred(32, avx2);
+ init_ipred(32, avx2, h, HOR);
+ init_ipred(32, avx2, tm, TM_VP8);
}
#undef init_fpel
diff --git a/libavcodec/x86/vp9intrapred.asm b/libavcodec/x86/vp9intrapred.asm
new file mode 100644
index 0000000000..31f7d449fd
--- /dev/null
+++ b/libavcodec/x86/vp9intrapred.asm
@@ -0,0 +1,2044 @@
+;******************************************************************************
+;* VP9 Intra prediction SIMD optimizations
+;*
+;* Copyright (c) 2013 Ronald S. Bultje <rsbultje gmail com>
+;*
+;* Parts based on:
+;* H.264 intra prediction asm optimizations
+;* Copyright (c) 2010 Fiona Glaser
+;* Copyright (c) 2010 Holger Lubitz
+;* Copyright (c) 2010 Loren Merritt
+;* Copyright (c) 2010 Ronald S. Bultje
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+pw_m256: times 16 dw -256
+pw_m255: times 16 dw -255
+pw_4096: times 8 dw 4096
+
+pb_4x3_4x2_4x1_4x0: times 4 db 3
+ times 4 db 2
+ times 4 db 1
+ times 4 db 0
+pb_8x1_8x0: times 8 db 1
+ times 8 db 0
+pb_8x3_8x2: times 8 db 3
+ times 8 db 2
+pb_0to5_2x7: db 0, 1, 2, 3, 4, 5, 7, 7
+ times 8 db -1
+pb_0to6_9x7: db 0, 1, 2, 3, 4, 5, 6
+ times 9 db 7
+pb_1to6_10x7: db 1, 2, 3, 4, 5, 6
+ times 10 db 7
+pb_2to6_3x7:
+pb_2to6_11x7: db 2, 3, 4, 5, 6
+ times 11 db 7
+pb_1toE_2xF: db 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15
+pb_2toE_3xF: db 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15
+pb_13456_3xm1: db 1, 3, 4, 5, 6
+ times 3 db -1
+pb_6012_4xm1: db 6, 0, 1, 2
+ times 4 db -1
+pb_6xm1_246_8toE: times 6 db -1
+ db 2, 4, 6, 8, 9, 10, 11, 12, 13, 14
+pb_6xm1_BDF_0to6: times 6 db -1
+ db 11, 13, 15, 0, 1, 2, 3, 4, 5, 6
+pb_02468ACE_13579BDF: db 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15
+
+pb_15x0_1xm1: times 15 db 0
+ db -1
+pb_0to2_5x3: db 0, 1, 2
+ times 5 db 3
+pb_6xm1_2x0: times 6 db -1
+ times 2 db 0
+pb_6x0_2xm1: times 6 db 0
+ times 2 db -1
+
+cextern pb_1
+cextern pb_2
+cextern pb_3
+cextern pb_15
+cextern pw_2
+cextern pw_4
+cextern pw_8
+cextern pw_16
+cextern pw_32
+cextern pw_255
+cextern pw_512
+cextern pw_1024
+cextern pw_2048
+cextern pw_8192
+
+SECTION .text
+
+; dc_NxN(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, const uint8_t *a)
+
+%macro DC_4to8_FUNCS 0
+cglobal vp9_ipred_dc_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [lq]
+ punpckldq m0, [aq]
+ pxor m1, m1
+ psadbw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_4096]
+ pshufb m0, m1
+%else
+ paddw m0, [pw_4]
+ psraw m0, 3
+ punpcklbw m0, m0
+ pshufw m0, m0, q0000
+%endif
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*1], m0
+ lea dstq, [dstq+strideq*2]
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*1], m0
+ RET
+
+cglobal vp9_ipred_dc_8x8, 4, 4, 0, dst, stride, l, a
+ movq m0, [lq]
+ movq m1, [aq]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ pxor m2, m2
+ psadbw m0, m2
+ psadbw m1, m2
+ paddw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_2048]
+ pshufb m0, m2
+%else
+ paddw m0, [pw_8]
+ psraw m0, 4
+ punpcklbw m0, m0
+ pshufw m0, m0, q0000
+%endif
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*1], m0
+ movq [dstq+strideq*2], m0
+ movq [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*1], m0
+ movq [dstq+strideq*2], m0
+ movq [dstq+stride3q ], m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+DC_4to8_FUNCS
+INIT_MMX ssse3
+DC_4to8_FUNCS
+
+%macro DC_16to32_FUNCS 0
+cglobal vp9_ipred_dc_16x16, 4, 4, 3, dst, stride, l, a
+ mova m0, [lq]
+ mova m1, [aq]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pxor m2, m2
+ psadbw m0, m2
+ psadbw m1, m2
+ paddw m0, m1
+ movhlps m1, m0
+ paddw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_1024]
+ pshufb m0, m2
+%else
+ paddw m0, [pw_16]
+ psraw m0, 5
+ punpcklbw m0, m0
+ pshuflw m0, m0, q0000
+ punpcklqdq m0, m0
+%endif
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_dc_32x32, 4, 4, 5, dst, stride, l, a
+ mova m0, [lq]
+ mova m1, [lq+16]
+ mova m2, [aq]
+ mova m3, [aq+16]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pxor m4, m4
+ psadbw m0, m4
+ psadbw m1, m4
+ psadbw m2, m4
+ psadbw m3, m4
+ paddw m0, m1
+ paddw m2, m3
+ paddw m0, m2
+ movhlps m1, m0
+ paddw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_512]
+ pshufb m0, m4
+%else
+ paddw m0, [pw_32]
+ psraw m0, 6
+ punpcklbw m0, m0
+ pshuflw m0, m0, q0000
+ punpcklqdq m0, m0
+%endif
+ mov cntd, 8
+.loop:
+ mova [dstq+strideq*0+ 0], m0
+ mova [dstq+strideq*0+16], m0
+ mova [dstq+strideq*1+ 0], m0
+ mova [dstq+strideq*1+16], m0
+ mova [dstq+strideq*2+ 0], m0
+ mova [dstq+strideq*2+16], m0
+ mova [dstq+stride3q + 0], m0
+ mova [dstq+stride3q +16], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+DC_16to32_FUNCS
+INIT_XMM ssse3
+DC_16to32_FUNCS
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+cglobal vp9_ipred_dc_32x32, 4, 4, 3, dst, stride, l, a
+ mova m0, [lq]
+ mova m1, [aq]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pxor m2, m2
+ psadbw m0, m2
+ psadbw m1, m2
+ paddw m0, m1
+ vextracti128 xm1, m0, 1
+ paddw xm0, xm1
+ movhlps xm1, xm0
+ paddw xm0, xm1
+ pmulhrsw xm0, [pw_512]
+ vpbroadcastb m0, xm0
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+%endif
+
+; dc_top/left_NxN(uint8_t *dst, ptrdiff_t stride, const uint8_t *l, const uint8_t *a)
+
+%macro DC_1D_4to8_FUNCS 2 ; dir (top or left), arg (a or l)
+cglobal vp9_ipred_dc_%1_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [%2q]
+ pxor m1, m1
+ psadbw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_8192]
+ pshufb m0, m1
+%else
+ paddw m0, [pw_2]
+ psraw m0, 2
+ punpcklbw m0, m0
+ pshufw m0, m0, q0000
+%endif
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*1], m0
+ lea dstq, [dstq+strideq*2]
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*1], m0
+ RET
+
+cglobal vp9_ipred_dc_%1_8x8, 4, 4, 0, dst, stride, l, a
+ movq m0, [%2q]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ pxor m1, m1
+ psadbw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_4096]
+ pshufb m0, m1
+%else
+ paddw m0, [pw_4]
+ psraw m0, 3
+ punpcklbw m0, m0
+ pshufw m0, m0, q0000
+%endif
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*1], m0
+ movq [dstq+strideq*2], m0
+ movq [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*1], m0
+ movq [dstq+strideq*2], m0
+ movq [dstq+stride3q ], m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+DC_1D_4to8_FUNCS top, a
+DC_1D_4to8_FUNCS left, l
+INIT_MMX ssse3
+DC_1D_4to8_FUNCS top, a
+DC_1D_4to8_FUNCS left, l
+
+%macro DC_1D_16to32_FUNCS 2; dir (top or left), arg (a or l)
+cglobal vp9_ipred_dc_%1_16x16, 4, 4, 3, dst, stride, l, a
+ mova m0, [%2q]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pxor m2, m2
+ psadbw m0, m2
+ movhlps m1, m0
+ paddw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_2048]
+ pshufb m0, m2
+%else
+ paddw m0, [pw_8]
+ psraw m0, 4
+ punpcklbw m0, m0
+ pshuflw m0, m0, q0000
+ punpcklqdq m0, m0
+%endif
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_dc_%1_32x32, 4, 4, 3, dst, stride, l, a
+ mova m0, [%2q]
+ mova m1, [%2q+16]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pxor m2, m2
+ psadbw m0, m2
+ psadbw m1, m2
+ paddw m0, m1
+ movhlps m1, m0
+ paddw m0, m1
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_1024]
+ pshufb m0, m2
+%else
+ paddw m0, [pw_16]
+ psraw m0, 5
+ punpcklbw m0, m0
+ pshuflw m0, m0, q0000
+ punpcklqdq m0, m0
+%endif
+ mov cntd, 8
+.loop:
+ mova [dstq+strideq*0+ 0], m0
+ mova [dstq+strideq*0+16], m0
+ mova [dstq+strideq*1+ 0], m0
+ mova [dstq+strideq*1+16], m0
+ mova [dstq+strideq*2+ 0], m0
+ mova [dstq+strideq*2+16], m0
+ mova [dstq+stride3q + 0], m0
+ mova [dstq+stride3q +16], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+DC_1D_16to32_FUNCS top, a
+DC_1D_16to32_FUNCS left, l
+INIT_XMM ssse3
+DC_1D_16to32_FUNCS top, a
+DC_1D_16to32_FUNCS left, l
+
+%macro DC_1D_AVX2_FUNCS 2 ; dir (top or left), arg (a or l)
+%if HAVE_AVX2_EXTERNAL
+cglobal vp9_ipred_dc_%1_32x32, 4, 4, 3, dst, stride, l, a
+ mova m0, [%2q]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ pxor m2, m2
+ psadbw m0, m2
+ vextracti128 xm1, m0, 1
+ paddw xm0, xm1
+ movhlps xm1, xm0
+ paddw xm0, xm1
+ pmulhrsw xm0, [pw_1024]
+ vpbroadcastb m0, xm0
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+%endif
+%endmacro
+
+INIT_YMM avx2
+DC_1D_AVX2_FUNCS top, a
+DC_1D_AVX2_FUNCS left, l
+
+; v
+
+INIT_MMX mmx
+cglobal vp9_ipred_v_8x8, 4, 4, 0, dst, stride, l, a
+ movq m0, [aq]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*1], m0
+ movq [dstq+strideq*2], m0
+ movq [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*1], m0
+ movq [dstq+strideq*2], m0
+ movq [dstq+stride3q ], m0
+ RET
+
+INIT_XMM sse
+cglobal vp9_ipred_v_16x16, 4, 4, 1, dst, stride, l, a
+ mova m0, [aq]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+INIT_XMM sse
+cglobal vp9_ipred_v_32x32, 4, 4, 2, dst, stride, l, a
+ mova m0, [aq]
+ mova m1, [aq+16]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ mov cntd, 8
+.loop:
+ mova [dstq+strideq*0+ 0], m0
+ mova [dstq+strideq*0+16], m1
+ mova [dstq+strideq*1+ 0], m0
+ mova [dstq+strideq*1+16], m1
+ mova [dstq+strideq*2+ 0], m0
+ mova [dstq+strideq*2+16], m1
+ mova [dstq+stride3q + 0], m0
+ mova [dstq+stride3q +16], m1
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+INIT_YMM avx
+cglobal vp9_ipred_v_32x32, 4, 4, 1, dst, stride, l, a
+ mova m0, [aq]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m0
+ mova [dstq+strideq*2], m0
+ mova [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+; h
+
+%macro H_XMM_FUNCS 2
+%if notcpuflag(avx)
+cglobal vp9_ipred_h_4x4, 3, 4, 1, dst, stride, l, stride3
+ movd m0, [lq]
+%if cpuflag(ssse3)
+ pshufb m0, [pb_4x3_4x2_4x1_4x0]
+%else
+ punpcklbw m0, m0
+ pshuflw m0, m0, q0123
+ punpcklwd m0, m0
+%endif
+ lea stride3q, [strideq*3]
+ movd [dstq+strideq*0], m0
+ psrldq m0, 4
+ movd [dstq+strideq*1], m0
+ psrldq m0, 4
+ movd [dstq+strideq*2], m0
+ psrldq m0, 4
+ movd [dstq+stride3q ], m0
+ RET
+%endif
+
+cglobal vp9_ipred_h_8x8, 3, 5, %1, dst, stride, l, stride3, cnt
+%if cpuflag(ssse3)
+ mova m2, [pb_8x1_8x0]
+ mova m3, [pb_8x3_8x2]
+%endif
+ lea stride3q, [strideq*3]
+ mov cntq, 1
+.loop:
+ movd m0, [lq+cntq*4]
+%if cpuflag(ssse3)
+ pshufb m1, m0, m3
+ pshufb m0, m2
+%else
+ punpcklbw m0, m0
+ punpcklwd m0, m0
+ pshufd m1, m0, q2233
+ pshufd m0, m0, q0011
+%endif
+ movq [dstq+strideq*0], m1
+ movhps [dstq+strideq*1], m1
+ movq [dstq+strideq*2], m0
+ movhps [dstq+stride3q ], m0
+ lea dstq, [dstq+strideq*4]
+ dec cntq
+ jge .loop
+ RET
+
+cglobal vp9_ipred_h_16x16, 3, 5, %2, dst, stride, l, stride3, cnt
+%if cpuflag(ssse3)
+ mova m5, [pb_1]
+ mova m6, [pb_2]
+ mova m7, [pb_3]
+ pxor m4, m4
+%endif
+ lea stride3q, [strideq*3]
+ mov cntq, 3
+.loop:
+ movd m3, [lq+cntq*4]
+%if cpuflag(ssse3)
+ pshufb m0, m3, m7
+ pshufb m1, m3, m6
+%else
+ punpcklbw m3, m3
+ punpcklwd m3, m3
+ pshufd m0, m3, q3333
+ pshufd m1, m3, q2222
+%endif
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m1
+%if cpuflag(ssse3)
+ pshufb m2, m3, m5
+ pshufb m3, m4
+%else
+ pshufd m2, m3, q1111
+ pshufd m3, m3, q0000
+%endif
+ mova [dstq+strideq*2], m2
+ mova [dstq+stride3q ], m3
+ lea dstq, [dstq+strideq*4]
+ dec cntq
+ jge .loop
+ RET
+
+cglobal vp9_ipred_h_32x32, 3, 5, %2, dst, stride, l, stride3, cnt
+%if cpuflag(ssse3)
+ mova m5, [pb_1]
+ mova m6, [pb_2]
+ mova m7, [pb_3]
+ pxor m4, m4
+%endif
+ lea stride3q, [strideq*3]
+ mov cntq, 7
+.loop:
+ movd m3, [lq+cntq*4]
+%if cpuflag(ssse3)
+ pshufb m0, m3, m7
+ pshufb m1, m3, m6
+%else
+ punpcklbw m3, m3
+ punpcklwd m3, m3
+ pshufd m0, m3, q3333
+ pshufd m1, m3, q2222
+%endif
+ mova [dstq+strideq*0+ 0], m0
+ mova [dstq+strideq*0+16], m0
+ mova [dstq+strideq*1+ 0], m1
+ mova [dstq+strideq*1+16], m1
+%if cpuflag(ssse3)
+ pshufb m2, m3, m5
+ pshufb m3, m4
+%else
+ pshufd m2, m3, q1111
+ pshufd m3, m3, q0000
+%endif
+ mova [dstq+strideq*2+ 0], m2
+ mova [dstq+strideq*2+16], m2
+ mova [dstq+stride3q + 0], m3
+ mova [dstq+stride3q +16], m3
+ lea dstq, [dstq+strideq*4]
+ dec cntq
+ jge .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+H_XMM_FUNCS 2, 4
+INIT_XMM ssse3
+H_XMM_FUNCS 4, 8
+INIT_XMM avx
+H_XMM_FUNCS 4, 8
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+cglobal vp9_ipred_h_32x32, 3, 5, 8, dst, stride, l, stride3, cnt
+ mova m5, [pb_1]
+ mova m6, [pb_2]
+ mova m7, [pb_3]
+ pxor m4, m4
+ lea stride3q, [strideq*3]
+ mov cntq, 7
+.loop:
+ movd xm3, [lq+cntq*4]
+ vinserti128 m3, m3, xm3, 1
+ pshufb m0, m3, m7
+ pshufb m1, m3, m6
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m1
+ pshufb m2, m3, m5
+ pshufb m3, m4
+ mova [dstq+strideq*2], m2
+ mova [dstq+stride3q ], m3
+ lea dstq, [dstq+strideq*4]
+ dec cntq
+ jge .loop
+ RET
+%endif
+
+; tm
+
+%macro TM_MMX_FUNCS 0
+cglobal vp9_ipred_tm_4x4, 4, 4, 0, dst, stride, l, a
+ pxor m1, m1
+ movd m0, [aq]
+ pinsrw m2, [aq-1], 0
+ punpcklbw m0, m1
+ DEFINE_ARGS dst, stride, l, cnt
+%if cpuflag(ssse3)
+ mova m3, [pw_m256]
+ mova m1, [pw_m255]
+ pshufb m2, m3
+%else
+ punpcklbw m2, m1
+ pshufw m2, m2, q0000
+%endif
+ psubw m0, m2
+ mov cntq, 1
+.loop:
+ pinsrw m2, [lq+cntq*2], 0
+%if cpuflag(ssse3)
+ pshufb m4, m2, m1
+ pshufb m2, m3
+%else
+ punpcklbw m2, m1
+ pshufw m4, m2, q1111
+ pshufw m2, m2, q0000
+%endif
+ paddw m4, m0
+ paddw m2, m0
+ packuswb m4, m4
+ packuswb m2, m2
+ movd [dstq+strideq*0], m4
+ movd [dstq+strideq*1], m2
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+%endmacro
+
+INIT_MMX mmxext
+TM_MMX_FUNCS
+INIT_MMX ssse3
+TM_MMX_FUNCS
+
+%macro TM_XMM_FUNCS 0
+cglobal vp9_ipred_tm_8x8, 4, 4, 5, dst, stride, l, a
+ pxor m1, m1
+ movh m0, [aq]
+ pinsrw m2, [aq-1], 0
+ punpcklbw m0, m1
+ DEFINE_ARGS dst, stride, l, cnt
+%if cpuflag(ssse3)
+ mova m3, [pw_m256]
+ mova m1, [pw_m255]
+ pshufb m2, m3
+%else
+ punpcklbw m2, m1
+ punpcklwd m2, m2
+ pshufd m2, m2, q0000
+%endif
+ psubw m0, m2
+ mov cntq, 3
+.loop:
+ pinsrw m2, [lq+cntq*2], 0
+%if cpuflag(ssse3)
+ pshufb m4, m2, m1
+ pshufb m2, m3
+%else
+ punpcklbw m2, m1
+ punpcklwd m2, m2
+ pshufd m4, m2, q1111
+ pshufd m2, m2, q0000
+%endif
+ paddw m4, m0
+ paddw m2, m0
+ packuswb m4, m2
+ movh [dstq+strideq*0], m4
+ movhps [dstq+strideq*1], m4
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+
+cglobal vp9_ipred_tm_16x16, 4, 4, 8, dst, stride, l, a
+ pxor m3, m3
+ mova m0, [aq]
+ pinsrw m2, [aq-1], 0
+ punpckhbw m1, m0, m3
+ punpcklbw m0, m3
+ DEFINE_ARGS dst, stride, l, cnt
+%if cpuflag(ssse3)
+ mova m4, [pw_m256]
+ mova m3, [pw_m255]
+ pshufb m2, m4
+%else
+ punpcklbw m2, m3
+ punpcklwd m2, m2
+ pshufd m2, m2, q0000
+%endif
+ psubw m1, m2
+ psubw m0, m2
+ mov cntq, 7
+.loop:
+ pinsrw m7, [lq+cntq*2], 0
+%if cpuflag(ssse3)
+ pshufb m5, m7, m3
+ pshufb m7, m4
+%else
+ punpcklbw m7, m3
+ punpcklwd m7, m7
+ pshufd m5, m7, q1111
+ pshufd m7, m7, q0000
+%endif
+ paddw m2, m5, m0
+ paddw m5, m1
+ paddw m6, m7, m0
+ paddw m7, m1
+ packuswb m2, m5
+ packuswb m6, m7
+ mova [dstq+strideq*0], m2
+ mova [dstq+strideq*1], m6
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+
+%if ARCH_X86_64
+%define mem 0
+%else
+%define mem 64
+%endif
+cglobal vp9_ipred_tm_32x32, 4, 4, 14, mem, dst, stride, l, a
+ pxor m5, m5
+ pinsrw m4, [aq-1], 0
+ mova m0, [aq]
+ mova m2, [aq+16]
+ DEFINE_ARGS dst, stride, l, cnt
+%if cpuflag(ssse3)
+%if ARCH_X86_64
+ mova m12, [pw_m256]
+ mova m13, [pw_m255]
+%define pw_m256_reg m12
+%define pw_m255_reg m13
+%else
+%define pw_m256_reg [pw_m256]
+%define pw_m255_reg [pw_m255]
+%endif
+ pshufb m4, pw_m256_reg
+%else
+ punpcklbw m4, m5
+ punpcklwd m4, m4
+ pshufd m4, m4, q0000
+%endif
+ punpckhbw m1, m0, m5
+ punpckhbw m3, m2, m5
+ punpcklbw m0, m5
+ punpcklbw m2, m5
+ psubw m1, m4
+ psubw m0, m4
+ psubw m3, m4
+ psubw m2, m4
+%if ARCH_X86_64
+ SWAP 0, 8
+ SWAP 1, 9
+ SWAP 2, 10
+ SWAP 3, 11
+%else
+ mova [rsp+0*16], m0
+ mova [rsp+1*16], m1
+ mova [rsp+2*16], m2
+ mova [rsp+3*16], m3
+%endif
+ mov cntq, 15
+.loop:
+ pinsrw m3, [lq+cntq*2], 0
+%if cpuflag(ssse3)
+ pshufb m7, m3, pw_m255_reg
+ pshufb m3, pw_m256_reg
+%else
+ pxor m7, m7
+ punpcklbw m3, m7
+ punpcklwd m3, m3
+ pshufd m7, m3, q1111
+ pshufd m3, m3, q0000
+%endif
+%if ARCH_X86_64
+ paddw m4, m7, m8
+ paddw m5, m7, m9
+ paddw m6, m7, m10
+ paddw m7, m11
+ paddw m0, m3, m8
+ paddw m1, m3, m9
+ paddw m2, m3, m10
+ paddw m3, m11
+%else
+ paddw m4, m7, [rsp+0*16]
+ paddw m5, m7, [rsp+1*16]
+ paddw m6, m7, [rsp+2*16]
+ paddw m7, [rsp+3*16]
+ paddw m0, m3, [rsp+0*16]
+ paddw m1, m3, [rsp+1*16]
+ paddw m2, m3, [rsp+2*16]
+ paddw m3, [rsp+3*16]
+%endif
+ packuswb m4, m5
+ packuswb m6, m7
+ packuswb m0, m1
+ packuswb m2, m3
+ mova [dstq+strideq*0+ 0], m4
+ mova [dstq+strideq*0+16], m6
+ mova [dstq+strideq*1+ 0], m0
+ mova [dstq+strideq*1+16], m2
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+%undef pw_m256_reg
+%undef pw_m255_reg
+%undef mem
+%endmacro
+
+INIT_XMM sse2
+TM_XMM_FUNCS
+INIT_XMM ssse3
+TM_XMM_FUNCS
+INIT_XMM avx
+TM_XMM_FUNCS
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+cglobal vp9_ipred_tm_32x32, 4, 4, 8, dst, stride, l, a
+ pxor m3, m3
+ pinsrw xm2, [aq-1], 0
+ vinserti128 m2, m2, xm2, 1
+ mova m0, [aq]
+ DEFINE_ARGS dst, stride, l, cnt
+ mova m4, [pw_m256]
+ mova m5, [pw_m255]
+ pshufb m2, m4
+ punpckhbw m1, m0, m3
+ punpcklbw m0, m3
+ psubw m1, m2
+ psubw m0, m2
+ mov cntq, 15
+.loop:
+ pinsrw xm7, [lq+cntq*2], 0
+ vinserti128 m7, m7, xm7, 1
+ pshufb m3, m7, m5
+ pshufb m7, m4
+ paddw m2, m3, m0
+ paddw m3, m1
+ paddw m6, m7, m0
+ paddw m7, m1
+ packuswb m2, m3
+ packuswb m6, m7
+ mova [dstq+strideq*0], m2
+ mova [dstq+strideq*1], m6
+ lea dstq, [dstq+strideq*2]
+ dec cntq
+ jge .loop
+ RET
+%endif
+
+; dl
+
+%macro LOWPASS 4 ; left [dst], center, right, tmp
+ pxor m%4, m%1, m%3
+ pand m%4, [pb_1]
+ pavgb m%1, m%3
+ psubusb m%1, m%4
+ pavgb m%1, m%2
+%endmacro
+
+%macro DL_MMX_FUNCS 0
+cglobal vp9_ipred_dl_4x4, 4, 4, 0, dst, stride, l, a
+ movq m1, [aq]
+%if cpuflag(ssse3)
+ pshufb m0, m1, [pb_0to5_2x7]
+ pshufb m2, m1, [pb_2to6_3x7]
+%else
+ punpckhbw m3, m1, m1 ; 44556677
+ pand m0, m1, [pb_6xm1_2x0] ; 012345__
+ pand m3, [pb_6x0_2xm1] ; ______77
+ psrlq m2, m1, 16 ; 234567__
+ por m0, m3 ; 01234577
+ por m2, m3 ; 23456777
+%endif
+ psrlq m1, 8
+ LOWPASS 0, 1, 2, 3
+
+ pshufw m1, m0, q3321
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*2], m1
+ psrlq m0, 8
+ psrlq m1, 8
+ add dstq, strideq
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*2], m1
+ RET
+%endmacro
+
+INIT_MMX mmxext
+DL_MMX_FUNCS
+INIT_MMX ssse3
+DL_MMX_FUNCS
+
+%macro DL_XMM_FUNCS 0
+cglobal vp9_ipred_dl_8x8, 4, 4, 4, dst, stride, stride5, a
+ movq m0, [aq]
+ lea stride5q, [strideq*5]
+%if cpuflag(ssse3)
+ pshufb m1, m0, [pb_1to6_10x7]
+%else
+ punpcklbw m1, m0, m0 ; 0011223344556677
+ punpckhwd m1, m1 ; 4x4,4x5,4x6,4x7
+%endif
+ shufps m0, m1, q3310
+%if notcpuflag(ssse3)
+ psrldq m1, m0, 1
+ shufps m1, m0, q3210
+%endif
+ psrldq m2, m1, 1
+ LOWPASS 0, 1, 2, 3
+
+ pshufd m1, m0, q3321
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*4], m1
+ psrldq m0, 1
+ psrldq m1, 1
+ movq [dstq+strideq*1], m0
+ movq [dstq+stride5q ], m1
+ lea dstq, [dstq+strideq*2]
+ psrldq m0, 1
+ psrldq m1, 1
+ movq [dstq+strideq*0], m0
+ movq [dstq+strideq*4], m1
+ psrldq m0, 1
+ psrldq m1, 1
+ movq [dstq+strideq*1], m0
+ movq [dstq+stride5q ], m1
+ RET
+
+cglobal vp9_ipred_dl_16x16, 4, 4, 6, dst, stride, l, a
+ mova m0, [aq]
+%if cpuflag(ssse3)
+ mova m5, [pb_1toE_2xF]
+ pshufb m1, m0, m5
+ pshufb m2, m1, m5
+ pshufb m4, m0, [pb_15]
+%else
+ pand m5, m0, [pb_15x0_1xm1] ; _______________F
+ psrldq m1, m0, 1 ; 123456789ABCDEF_
+ por m1, m5 ; 123456789ABCDEFF
+ psrldq m2, m1, 1 ; 23456789ABCDEFF_
+ por m2, m5 ; 23456789ABCDEFFF
+ pshufhw m4, m1, q3333 ; xxxxxxxxFFFFFFFF
+%endif
+ LOWPASS 0, 1, 2, 3
+ DEFINE_ARGS dst, stride, cnt, stride9
+ lea stride9q, [strideq+strideq*8]
+ mov cntd, 4
+
+.loop:
+ movhlps m4, m0
+ mova [dstq+strideq*0], m0
+%if cpuflag(ssse3)
+ pshufb m0, m5
+%else
+ psrldq m0, 1
+ por m0, m5
+%endif
+ mova [dstq+strideq*8], m4
+ movhlps m4, m0
+ mova [dstq+strideq*1], m0
+%if cpuflag(ssse3)
+ pshufb m0, m5
+%else
+ psrldq m0, 1
+ por m0, m5
+%endif
+ mova [dstq+stride9q ], m4
+ lea dstq, [dstq+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_dl_32x32, 4, 5, 8, dst, stride, cnt, a, dst16
+ mova m0, [aq]
+ mova m1, [aq+16]
+ PALIGNR m2, m1, m0, 1, m4
+ PALIGNR m3, m1, m0, 2, m4
+ LOWPASS 0, 2, 3, 4
+%if cpuflag(ssse3)
+ mova m5, [pb_1toE_2xF]
+ pshufb m2, m1, m5
+ pshufb m3, m2, m5
+ pshufb m6, m1, [pb_15]
+ mova m7, m6
+%else
+ pand m5, m1, [pb_15x0_1xm1] ; _______________F
+ psrldq m2, m1, 1 ; 123456789ABCDEF_
+ por m2, m5 ; 123456789ABCDEFF
+ psrldq m3, m2, 1 ; 23456789ABCDEFF_
+ por m3, m5 ; 23456789ABCDEFFF
+ pshufhw m7, m2, q3333 ; xxxxxxxxFFFFFFFF
+ pshufd m6, m7, q3333
+%endif
+ LOWPASS 1, 2, 3, 4
+ lea dst16q, [dstq +strideq*8]
+ mov cntd, 8
+ lea dst16q, [dst16q+strideq*8]
+.loop:
+ movhlps m7, m1
+ mova [dstq +strideq*0+ 0], m0
+ mova [dstq +strideq*0+16], m1
+ movhps [dstq+strideq*8+ 0], m0
+ movq [dstq +strideq*8+ 8], m1
+ mova [dstq +strideq*8+16], m7
+ mova [dst16q+strideq*0+ 0], m1
+ mova [dst16q+strideq*0+16], m6
+ mova [dst16q+strideq*8+ 0], m7
+ mova [dst16q+strideq*8+16], m6
+%if cpuflag(avx)
+ vpalignr m0, m1, m0, 1
+ pshufb m1, m5
+%elif cpuflag(ssse3)
+ palignr m2, m1, m0, 1
+ pshufb m1, m5
+ mova m0, m2
+%else
+ mova m4, m1
+ psrldq m0, 1
+ pslldq m4, 15
+ psrldq m1, 1
+ por m0, m4
+ por m1, m5
+%endif
+ add dstq, strideq
+ add dst16q, strideq
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+DL_XMM_FUNCS
+INIT_XMM ssse3
+DL_XMM_FUNCS
+INIT_XMM avx
+DL_XMM_FUNCS
+
+; dr
+
+%macro DR_MMX_FUNCS 0
+cglobal vp9_ipred_dr_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [lq]
+ punpckldq m0, [aq-1]
+ movd m1, [aq+3]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ PALIGNR m1, m0, 1, m3
+ psrlq m2, m1, 8
+ LOWPASS 0, 1, 2, 3
+
+ movd [dstq+stride3q ], m0
+ psrlq m0, 8
+ movd [dstq+strideq*2], m0
+ psrlq m0, 8
+ movd [dstq+strideq*1], m0
+ psrlq m0, 8
+ movd [dstq+strideq*0], m0
+ RET
+%endmacro
+
+INIT_MMX mmxext
+DR_MMX_FUNCS
+INIT_MMX ssse3
+DR_MMX_FUNCS
+
+%macro DR_XMM_FUNCS 0
+cglobal vp9_ipred_dr_8x8, 4, 4, 4, dst, stride, l, a
+ movq m1, [lq]
+ movhps m1, [aq-1]
+ movd m2, [aq+7]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ pslldq m0, m1, 1
+ PALIGNR m2, m1, 1, m3
+ LOWPASS 0, 1, 2, 3
+
+ movhps [dstq+strideq*0], m0
+ pslldq m0, 1
+ movhps [dstq+strideq*1], m0
+ pslldq m0, 1
+ movhps [dstq+strideq*2], m0
+ pslldq m0, 1
+ movhps [dstq+stride3q ], m0
+ pslldq m0, 1
+ lea dstq, [dstq+strideq*4]
+ movhps [dstq+strideq*0], m0
+ pslldq m0, 1
+ movhps [dstq+strideq*1], m0
+ pslldq m0, 1
+ movhps [dstq+strideq*2], m0
+ pslldq m0, 1
+ movhps [dstq+stride3q ], m0
+ RET
+
+cglobal vp9_ipred_dr_16x16, 4, 4, 6, dst, stride, l, a
+ mova m1, [lq]
+ movu m2, [aq-1]
+ movd m4, [aq+15]
+ DEFINE_ARGS dst, stride, stride9, cnt
+ lea stride9q, [strideq *3]
+ mov cntd, 4
+ lea stride9q, [stride9q*3]
+ PALIGNR m4, m2, 1, m5
+ PALIGNR m3, m2, m1, 15, m5
+ LOWPASS 3, 2, 4, 5
+ pslldq m0, m1, 1
+ PALIGNR m2, m1, 1, m4
+ LOWPASS 0, 1, 2, 4
+
+.loop:
+ mova [dstq+strideq*0 ], m3
+ movhps [dstq+strideq*8+0], m0
+ movq [dstq+strideq*8+8], m3
+ PALIGNR m3, m0, 15, m1
+ pslldq m0, 1
+ mova [dstq+strideq*1 ], m3
+ movhps [dstq+stride9q +0], m0
+ movq [dstq+stride9q +8], m3
+ PALIGNR m3, m0, 15, m1
+ pslldq m0, 1
+ lea dstq, [dstq+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_dr_32x32, 4, 4, 8, dst, stride, l, a
+ mova m1, [lq]
+ mova m2, [lq+16]
+ movu m3, [aq-1]
+ movu m4, [aq+15]
+ movd m5, [aq+31]
+ DEFINE_ARGS dst, stride, stride8, cnt
+ lea stride8q, [strideq*8]
+ PALIGNR m5, m4, 1, m7
+ PALIGNR m6, m4, m3, 15, m7
+ LOWPASS 5, 4, 6, 7
+ PALIGNR m4, m3, 1, m7
+ PALIGNR m6, m3, m2, 15, m7
+ LOWPASS 4, 3, 6, 7
+ PALIGNR m3, m2, 1, m7
+ PALIGNR m6, m2, m1, 15, m7
+ LOWPASS 3, 2, 6, 7
+ PALIGNR m2, m1, 1, m6
+ pslldq m0, m1, 1
+ LOWPASS 2, 1, 0, 6
+ mov cntd, 16
+
+ ; out=m2/m3/m4/m5
+.loop:
+ mova [dstq+stride8q*0+ 0], m4
+ mova [dstq+stride8q*0+16], m5
+ mova [dstq+stride8q*2+ 0], m3
+ mova [dstq+stride8q*2+16], m4
+ PALIGNR m5, m4, 15, m6
+ PALIGNR m4, m3, 15, m6
+ PALIGNR m3, m2, 15, m6
+ pslldq m2, 1
+ add dstq, strideq
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+DR_XMM_FUNCS
+INIT_XMM ssse3
+DR_XMM_FUNCS
+INIT_XMM avx
+DR_XMM_FUNCS
+
+; vl
+
+INIT_MMX mmxext
+cglobal vp9_ipred_vl_4x4, 4, 4, 0, dst, stride, l, a
+ movq m0, [aq]
+ psrlq m1, m0, 8
+ psrlq m2, m1, 8
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+ movd [dstq+strideq*0], m1
+ movd [dstq+strideq*1], m2
+ lea dstq, [dstq+strideq*2]
+ psrlq m1, 8
+ psrlq m2, 8
+ movd [dstq+strideq*0], m1
+ movd [dstq+strideq*1], m2
+ RET
+
+%macro VL_XMM_FUNCS 0
+cglobal vp9_ipred_vl_8x8, 4, 4, 4, dst, stride, l, a
+ movq m0, [aq]
+%if cpuflag(ssse3)
+ pshufb m0, [pb_0to6_9x7]
+%else
+ punpcklbw m1, m0, m0
+ punpckhwd m1, m1
+ shufps m0, m1, q3310
+%endif
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ psrldq m1, m0, 1
+ psrldq m2, m0, 2
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+
+ movq [dstq+strideq*0], m1
+ movq [dstq+strideq*1], m2
+ psrldq m1, 1
+ psrldq m2, 1
+ movq [dstq+strideq*2], m1
+ movq [dstq+stride3q ], m2
+ lea dstq, [dstq+strideq*4]
+ psrldq m1, 1
+ psrldq m2, 1
+ movq [dstq+strideq*0], m1
+ movq [dstq+strideq*1], m2
+ psrldq m1, 1
+ psrldq m2, 1
+ movq [dstq+strideq*2], m1
+ movq [dstq+stride3q ], m2
+ RET
+
+cglobal vp9_ipred_vl_16x16, 4, 4, 5, dst, stride, l, a
+ mova m0, [aq]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+%if cpuflag(ssse3)
+ mova m4, [pb_1toE_2xF]
+ pshufb m1, m0, m4
+ pshufb m2, m1, m4
+%else
+ pand m4, m0, [pb_15x0_1xm1] ; _______________F
+ psrldq m1, m0, 1 ; 123456789ABCDEF_
+ por m1, m4 ; 123456789ABCDEFF
+ psrldq m2, m1, 1 ; 23456789ABCDEFF_
+ por m2, m4 ; 23456789ABCDEFFF
+%endif
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+ mov cntd, 4
+.loop:
+ mova [dstq+strideq*0], m1
+ mova [dstq+strideq*1], m2
+%if cpuflag(ssse3)
+ pshufb m1, m4
+ pshufb m2, m4
+%else
+ psrldq m1, 1
+ psrldq m2, 1
+ por m1, m4
+ por m2, m4
+%endif
+ mova [dstq+strideq*2], m1
+ mova [dstq+stride3q ], m2
+%if cpuflag(ssse3)
+ pshufb m1, m4
+ pshufb m2, m4
+%else
+ psrldq m1, 1
+ psrldq m2, 1
+ por m1, m4
+ por m2, m4
+%endif
+ lea dstq, [dstq+strideq*4]
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_vl_32x32, 4, 4, 7, dst, stride, l, a
+ mova m0, [aq]
+ mova m5, [aq+16]
+ DEFINE_ARGS dst, stride, dst16, cnt
+ PALIGNR m2, m5, m0, 1, m4
+ PALIGNR m3, m5, m0, 2, m4
+ lea dst16q, [dstq +strideq*8]
+ LOWPASS 3, 2, 0, 6
+ pavgb m2, m0
+%if cpuflag(ssse3)
+ mova m4, [pb_1toE_2xF]
+ pshufb m0, m5, m4
+ pshufb m1, m0, m4
+%else
+ pand m4, m5, [pb_15x0_1xm1] ; _______________F
+ psrldq m0, m5, 1 ; 123456789ABCDEF_
+ por m0, m4 ; 123456789ABCDEFF
+ psrldq m1, m0, 1 ; 23456789ABCDEFF_
+ por m1, m4 ; 23456789ABCDEFFF
+%endif
+ lea dst16q, [dst16q+strideq*8]
+ LOWPASS 1, 0, 5, 6
+ pavgb m0, m5
+%if cpuflag(ssse3)
+ pshufb m5, [pb_15]
+%else
+ punpckhbw m5, m4, m4
+ pshufhw m5, m5, q3333
+ punpckhqdq m5, m5
+%endif
+ mov cntd, 8
+
+.loop:
+%macro %%write 3
+ mova [dstq+stride%1+ 0], %2
+ mova [dstq+stride%1+16], %3
+ movhps [dst16q+stride%1 ], %2
+ movu [dst16q+stride%1+ 8], %3
+ movq [dst16q+stride%1+24], m5
+%if cpuflag(avx)
+ palignr %2, %3, %2, 1
+ pshufb %3, m4
+%elif cpuflag(ssse3)
+ palignr m6, %3, %2, 1
+ pshufb %3, m4
+ mova %2, m6
+%else
+ pslldq m6, %3, 15
+ psrldq %3, 1
+ psrldq %2, 1
+ por %3, m4
+ por %2, m6
+%endif
+%endmacro
+
+ %%write q*0, m2, m0
+ %%write q*1, m3, m1
+ lea dstq, [dstq +strideq*2]
+ lea dst16q, [dst16q+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+VL_XMM_FUNCS
+INIT_XMM ssse3
+VL_XMM_FUNCS
+INIT_XMM avx
+VL_XMM_FUNCS
+
+; vr
+
+%macro VR_MMX_FUNCS 0
+cglobal vp9_ipred_vr_4x4, 4, 4, 0, dst, stride, l, a
+ movq m1, [aq-1]
+ punpckldq m2, [lq]
+ movd m0, [aq]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ pavgb m0, m1
+ PALIGNR m1, m2, 5, m3
+ psrlq m2, m1, 8
+ psllq m3, m1, 8
+ LOWPASS 2, 1, 3, 4
+
+ ; ABCD <- for the following predictor:
+ ; EFGH
+ ; IABC | m0 contains ABCDxxxx
+ ; JEFG | m2 contains xJIEFGHx
+
+%if cpuflag(ssse3)
+ punpckldq m0, m2
+ pshufb m2, [pb_13456_3xm1]
+ movd [dstq+strideq*0], m0
+ pshufb m0, [pb_6012_4xm1]
+ movd [dstq+stride3q ], m2
+ psrlq m2, 8
+ movd [dstq+strideq*2], m0
+ movd [dstq+strideq*1], m2
+%else
+ psllq m1, m2, 40
+ psrlq m2, 24
+ movd [dstq+strideq*0], m0
+ movd [dstq+strideq*1], m2
+ PALIGNR m0, m1, 7, m3
+ psllq m1, 8
+ PALIGNR m2, m1, 7, m3
+ movd [dstq+strideq*2], m0
+ movd [dstq+stride3q ], m2
+%endif
+ RET
+%endmacro
+
+INIT_MMX mmxext
+VR_MMX_FUNCS
+INIT_MMX ssse3
+VR_MMX_FUNCS
+
+%macro VR_XMM_FUNCS 1 ; n_xmm_regs for 16x16
+cglobal vp9_ipred_vr_8x8, 4, 4, 5, dst, stride, l, a
+ movu m1, [aq-1]
+ movhps m2, [lq]
+ movq m0, [aq]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ pavgb m0, m1
+ PALIGNR m1, m2, 9, m3
+ pslldq m2, m1, 1
+ pslldq m3, m1, 2
+ LOWPASS 1, 2, 3, 4
+
+ ; ABCDEFGH <- for the following predictor:
+ ; IJKLMNOP
+ ; QABCDEFG | m0 contains ABCDEFGHxxxxxxxx
+ ; RIJKLMNO | m1 contains xxVUTSRQIJKLMNOP
+ ; SQABCDEF
+ ; TRIJKLMN
+ ; USQABCDE
+ ; VTRIJKLM
+
+%if cpuflag(ssse3)
+ punpcklqdq m0, m1 ; ABCDEFGHxxVUTSRQ
+%endif
+ movq [dstq+strideq*0], m0
+ movhps [dstq+strideq*1], m1
+%if cpuflag(ssse3)
+ pshufb m0, [pb_6xm1_BDF_0to6] ; xxxxxxUSQABCDEFG
+ pshufb m1, [pb_6xm1_246_8toE] ; xxxxxxVTRIJKLMNO
+%else
+ psrlw m2, m1, 8 ; x_U_S_Q_xxxxxxxx
+ pand m3, m1, [pw_255] ; x_V_T_R_xxxxxxxx
+ packuswb m3, m2 ; xVTRxxxxxUSQxxxx
+ pslldq m3, 4 ; xxxxxVTRxxxxxUSQ
+ PALIGNR m0, m3, 7, m4 ; xxxxxxUSQABCDEFG
+ psrldq m1, 8
+ pslldq m3, 8
+ PALIGNR m1, m3, 7, m4 ; xxxxxxVTRIJKLMNO
+%endif
+ movhps [dstq+strideq*2], m0
+ movhps [dstq+stride3q ], m1
+ lea dstq, [dstq+strideq*4]
+ pslldq m0, 1
+ pslldq m1, 1
+ movhps [dstq+strideq*0], m0
+ movhps [dstq+strideq*1], m1
+ pslldq m0, 1
+ pslldq m1, 1
+ movhps [dstq+strideq*2], m0
+ movhps [dstq+stride3q ], m1
+ RET
+
+cglobal vp9_ipred_vr_16x16, 4, 4, %1, dst, stride, l, a
+ mova m0, [aq]
+ movu m1, [aq-1]
+ mova m2, [lq]
+ DEFINE_ARGS dst, stride, stride3, cnt
+ lea stride3q, [strideq*3]
+ PALIGNR m3, m1, m2, 15, m6
+ LOWPASS 3, 1, 0, 4
+ pavgb m0, m1
+ PALIGNR m1, m2, 1, m6
+ pslldq m4, m2, 1
+ LOWPASS 1, 2, 4, 5
+%if cpuflag(ssse3)
+ pshufb m1, [pb_02468ACE_13579BDF]
+%else
+ psrlw m5, m1, 8
+ pand m1, [pw_255]
+ packuswb m1, m5
+%endif
+ mov cntd, 4
+
+.loop:
+ movlhps m2, m1
+ mova [dstq+strideq*0], m0
+ mova [dstq+strideq*1], m3
+ PALIGNR m4, m0, m1, 15, m6
+ PALIGNR m5, m3, m2, 15, m6
+ mova [dstq+strideq*2], m4
+ mova [dstq+stride3q ], m5
+ lea dstq, [dstq+strideq*4]
+ PALIGNR m0, m1, 14, m6
+ PALIGNR m3, m2, 14, m6
+ pslldq m1, 2
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_vr_32x32, 4, 4, 9, dst, stride, l, a
+ mova m0, [aq]
+ mova m2, [aq+16]
+ movu m1, [aq-1]
+ PALIGNR m3, m2, m0, 15, m6
+ PALIGNR m4, m2, m0, 14, m6
+ LOWPASS 4, 3, 2, 5
+ pavgb m3, m2
+ mova m2, [lq+16]
+ PALIGNR m5, m1, m2, 15, m6
+ LOWPASS 5, 1, 0, 6
+ pavgb m0, m1
+ mova m6, [lq]
+%if ARCH_X86_64
+ SWAP 0, 8
+%else
+ mova [dstq], m0
+%endif
+ PALIGNR m1, m2, 1, m0
+ PALIGNR m7, m2, m6, 15, m0
+ LOWPASS 1, 2, 7, 0
+ PALIGNR m2, m6, 1, m0
+ pslldq m7, m6, 1
+ LOWPASS 2, 6, 7, 0
+%if cpuflag(ssse3)
+ pshufb m1, [pb_02468ACE_13579BDF]
+ pshufb m2, [pb_02468ACE_13579BDF]
+%else
+ psrlw m0, m1, 8
+ psrlw m6, m2, 8
+ pand m1, [pw_255]
+ pand m2, [pw_255]
+ packuswb m1, m0
+ packuswb m2, m6
+%endif
+ DEFINE_ARGS dst, stride, dst16, cnt
+ lea dst16q, [dstq +strideq*8]
+ lea dst16q, [dst16q+strideq*8]
+ SBUTTERFLY qdq, 2, 1, 6
+%if ARCH_X86_64
+ SWAP 0, 8
+%else
+ mova m0, [dstq]
+%endif
+ mov cntd, 8
+
+.loop:
+ ; even lines (0, 2, 4, ...): m1 | m0, m3
+ ; odd lines (1, 3, 5, ...): m2 | m5, m4
+%macro %%write 4
+ mova [dstq+stride%1+ 0], %3
+ mova [dstq+stride%1+16], %4
+ movhps [dst16q+stride%1 ], %2
+ movu [dst16q+stride%1+ 8], %3
+ movq [dst16q+stride%1+24], %4
+ PALIGNR %4, %3, 15, m6
+ PALIGNR %3, %2, 15, m6
+ pslldq %2, 1
+%endmacro
+
+ %%write q*0, m1, m0, m3
+ %%write q*1, m2, m5, m4
+ lea dstq, [dstq +strideq*2]
+ lea dst16q, [dst16q+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+VR_XMM_FUNCS 7
+INIT_XMM ssse3
+VR_XMM_FUNCS 6
+INIT_XMM avx
+VR_XMM_FUNCS 6
+
+; hd
+
+INIT_MMX mmxext
+cglobal vp9_ipred_hd_4x4, 4, 4, 0, dst, stride, l, a
+ movd m0, [lq]
+ punpckldq m0, [aq-1]
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ psrlq m1, m0, 8
+ psrlq m2, m1, 8
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+
+ ; DHIJ <- for the following predictor:
+ ; CGDH
+ ; BFCG | m1 contains ABCDxxxx
+ ; AEBF | m2 contains EFGHIJxx
+
+ punpcklbw m1, m2
+ punpckhdq m0, m1, m2
+
+ ; m1 contains AEBFCGDH
+ ; m0 contains CGDHIJxx
+
+ movd [dstq+stride3q ], m1
+ movd [dstq+strideq*1], m0
+ psrlq m1, 16
+ psrlq m0, 16
+ movd [dstq+strideq*2], m1
+ movd [dstq+strideq*0], m0
+ RET
+
+%macro HD_XMM_FUNCS 0
+cglobal vp9_ipred_hd_8x8, 4, 4, 5, dst, stride, l, a
+ movq m0, [lq]
+ movhps m0, [aq-1]
+ DEFINE_ARGS dst, stride, stride3, dst4
+ lea stride3q, [strideq*3]
+ lea dst4q, [dstq+strideq*4]
+ psrldq m1, m0, 1
+ psrldq m2, m1, 1
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+
+ ; HPQRSTUV <- for the following predictor
+ ; GOHPQRST
+ ; FNGOHPQR | m1 contains ABCDEFGHxxxxxxxx
+ ; EMFNGOHP | m2 contains IJKLMNOPQRSTUVxx
+ ; DLEMFNGO
+ ; CKDLEMFN
+ ; BJCKDLEM
+ ; AIBJCKDL
+
+ punpcklbw m1, m2
+ movhlps m2, m2
+
+ ; m1 contains AIBJCKDLEMFNGOHP
+ ; m2 contains QRSTUVxxxxxxxxxx
+
+ movhps [dstq +stride3q ], m1
+ movq [dst4q+stride3q ], m1
+ PALIGNR m3, m2, m1, 2, m4
+ movhps [dstq +strideq*2], m3
+ movq [dst4q+strideq*2], m3
+ PALIGNR m3, m2, m1, 4, m4
+ movhps [dstq +strideq*1], m3
+ movq [dst4q+strideq*1], m3
+ PALIGNR m2, m1, 6, m4
+ movhps [dstq +strideq*0], m2
+ movq [dst4q+strideq*0], m2
+ RET
+
+cglobal vp9_ipred_hd_16x16, 4, 6, 7, dst, stride, l, a
+ mova m0, [lq]
+ movu m3, [aq-1]
+ DEFINE_ARGS dst, stride, stride4, dst4, dst8, dst12
+ lea stride4q, [strideq*4]
+ lea dst4q, [dstq +stride4q]
+ lea dst8q, [dst4q+stride4q]
+ lea dst12q, [dst8q+stride4q]
+ psrldq m4, m3, 1
+ psrldq m5, m3, 2
+ LOWPASS 5, 4, 3, 6
+ PALIGNR m1, m3, m0, 1, m6
+ PALIGNR m2, m3, m0, 2, m6
+ LOWPASS 2, 1, 0, 6
+ pavgb m1, m0
+ SBUTTERFLY bw, 1, 2, 6
+
+ ; I PROBABLY INVERTED L0 ad L16 here
+ ; m1, m2, m5
+.loop:
+ sub stride4q, strideq
+ movhps [dstq +stride4q +0], m2
+ movq [dstq +stride4q +8], m5
+ mova [dst4q+stride4q ], m2
+ movhps [dst8q+stride4q +0], m1
+ movq [dst8q+stride4q +8], m2
+ mova [dst12q+stride4q ], m1
+%if cpuflag(avx)
+ palignr m1, m2, m1, 2
+ palignr m2, m5, m2, 2
+%elif cpuflag(ssse3)
+ palignr m3, m2, m1, 2
+ palignr m0, m5, m2, 2
+ mova m1, m3
+ mova m2, m0
+%else
+ ; slightly modified version of PALIGNR
+ mova m6, m2
+ mova m4, m5
+ pslldq m6, 14
+ pslldq m4, 14
+ psrldq m1, 2
+ psrldq m2, 2
+ por m1, m6
+ por m2, m4
+%endif
+ psrldq m5, 2
+ jg .loop
+ RET
+
+cglobal vp9_ipred_hd_32x32, 4, 6, 8, dst, stride, l, a
+ mova m0, [lq]
+ mova m1, [lq+16]
+ movu m2, [aq-1]
+ movu m3, [aq+15]
+ DEFINE_ARGS dst, stride, stride8, dst8, dst16, dst24
+ lea stride8q, [strideq*8]
+ lea dst8q, [dstq +stride8q]
+ lea dst16q, [dst8q +stride8q]
+ lea dst24q, [dst16q+stride8q]
+ psrldq m4, m3, 1
+ psrldq m5, m3, 2
+ LOWPASS 5, 4, 3, 6
+ PALIGNR m4, m3, m2, 2, m6
+ PALIGNR m3, m2, 1, m6
+ LOWPASS 4, 3, 2, 6
+ PALIGNR m3, m2, m1, 2, m6
+ PALIGNR m2, m1, 1, m6
+ LOWPASS 3, 2, 1, 6
+ pavgb m2, m1
+ PALIGNR m6, m1, m0, 1, m7
+ PALIGNR m1, m0, 2, m7
+ LOWPASS 1, 6, 0, 7
+ pavgb m0, m6
+ SBUTTERFLY bw, 2, 3, 6
+ SBUTTERFLY bw, 0, 1, 6
+
+ ; m0, m1, m2, m3, m4, m5
+.loop:
+ sub stride8q, strideq
+ mova [dstq +stride8q+ 0], m3
+ mova [dstq +stride8q+16], m4
+ mova [dst8q +stride8q+ 0], m2
+ mova [dst8q +stride8q+16], m3
+ mova [dst16q+stride8q+ 0], m1
+ mova [dst16q+stride8q+16], m2
+ mova [dst24q+stride8q+ 0], m0
+ mova [dst24q+stride8q+16], m1
+%if cpuflag(avx)
+ palignr m0, m1, m0, 2
+ palignr m1, m2, m1, 2
+ palignr m2, m3, m2, 2
+ palignr m3, m4, m3, 2
+ palignr m4, m5, m4, 2
+ psrldq m5, 2
+%elif cpuflag(ssse3)
+ psrldq m6, m5, 2
+ palignr m5, m4, 2
+ palignr m4, m3, 2
+ palignr m3, m2, 2
+ palignr m2, m1, 2
+ palignr m1, m0, 2
+ mova m0, m1
+ mova m1, m2
+ mova m2, m3
+ mova m3, m4
+ mova m4, m5
+ mova m5, m6
+%else
+ ; sort of a half-integrated version of PALIGNR
+ pslldq m7, m4, 14
+ pslldq m6, m5, 14
+ psrldq m4, 2
+ psrldq m5, 2
+ por m4, m6
+ pslldq m6, m3, 14
+ psrldq m3, 2
+ por m3, m7
+ pslldq m7, m2, 14
+ psrldq m2, 2
+ por m2, m6
+ pslldq m6, m1, 14
+ psrldq m1, 2
+ por m1, m7
+ psrldq m0, 2
+ por m0, m6
+%endif
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+HD_XMM_FUNCS
+INIT_XMM ssse3
+HD_XMM_FUNCS
+INIT_XMM avx
+HD_XMM_FUNCS
+
+%macro HU_MMX_FUNCS 0
+cglobal vp9_ipred_hu_4x4, 3, 3, 0, dst, stride, l
+ movd m0, [lq]
+%if cpuflag(ssse3)
+ pshufb m0, [pb_0to2_5x3]
+%else
+ punpcklbw m1, m0, m0 ; 00112233
+ pshufw m1, m1, q3333 ; 33333333
+ punpckldq m0, m1 ; 01233333
+%endif
+ psrlq m1, m0, 8
+ psrlq m2, m1, 8
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+ DEFINE_ARGS dst, stride, stride3
+ lea stride3q, [strideq*3]
+ SBUTTERFLY bw, 1, 2, 0
+ PALIGNR m2, m1, 2, m0
+ movd [dstq+strideq*0], m1
+ movd [dstq+strideq*1], m2
+ punpckhdq m1, m1
+ punpckhdq m2, m2
+ movd [dstq+strideq*2], m1
+ movd [dstq+stride3q ], m2
+ RET
+%endmacro
+
+INIT_MMX mmxext
+HU_MMX_FUNCS
+INIT_MMX ssse3
+HU_MMX_FUNCS
+
+%macro HU_XMM_FUNCS 1 ; n_xmm_regs in hu_32x32
+cglobal vp9_ipred_hu_8x8, 3, 4, 4, dst, stride, l
+ movq m0, [lq]
+%if cpuflag(ssse3)
+ pshufb m0, [pb_0to6_9x7]
+%else
+ punpcklbw m1, m0, m0 ; 0011223344556677
+ punpckhwd m1, m1 ; 4444555566667777
+ shufps m0, m1, q3310 ; 0123456777777777
+%endif
+ psrldq m1, m0, 1
+ psrldq m2, m1, 1
+ LOWPASS 2, 1, 0, 3
+ pavgb m1, m0
+ DEFINE_ARGS dst, stride, stride3, dst4
+ lea stride3q, [strideq*3]
+ lea dst4q, [dstq+strideq*4]
+ SBUTTERFLY bw, 1, 2, 0
+ movq [dstq +strideq*0], m1
+ movhps [dst4q+strideq*0], m1
+ PALIGNR m0, m2, m1, 2, m3
+ movq [dstq +strideq*1], m0
+ movhps [dst4q+strideq*1], m0
+ PALIGNR m0, m2, m1, 4, m3
+ movq [dstq +strideq*2], m0
+ movhps [dst4q+strideq*2], m0
+ PALIGNR m2, m1, 6, m3
+ movq [dstq +stride3q ], m2
+ movhps [dst4q+stride3q ], m2
+ RET
+
+cglobal vp9_ipred_hu_16x16, 3, 4, 5, dst, stride, l
+ mova m0, [lq]
+%if cpuflag(ssse3)
+ mova m3, [pb_2toE_3xF]
+ pshufb m1, m0, [pb_1toE_2xF]
+ pshufb m2, m0, m3
+%else
+ pand m3, m0, [pb_15x0_1xm1]
+ psrldq m1, m0, 1
+ por m1, m3
+ punpckhbw m3, m3
+ psrldq m2, m0, 2
+ por m2, m3
+%endif
+ LOWPASS 2, 1, 0, 4
+ pavgb m1, m0
+ DEFINE_ARGS dst, stride, stride9, cnt
+ lea stride9q, [strideq*8+strideq]
+ mov cntd, 4
+ SBUTTERFLY bw, 1, 2, 0
+
+.loop:
+ mova [dstq+strideq*0], m1
+ mova [dstq+strideq*8], m2
+ PALIGNR m0, m2, m1, 2, m4
+%if cpuflag(ssse3)
+ pshufb m2, m3
+%else
+ psrldq m2, 2
+ por m2, m3
+%endif
+ mova [dstq+strideq*1], m0
+ mova [dstq+stride9q ], m2
+ PALIGNR m1, m2, m0, 2, m4
+%if cpuflag(ssse3)
+ pshufb m2, m3
+%else
+ psrldq m2, 2
+ por m2, m3
+%endif
+ lea dstq, [dstq+strideq*2]
+ dec cntd
+ jg .loop
+ RET
+
+cglobal vp9_ipred_hu_32x32, 3, 7, %1, dst, stride, l
+ mova m1, [lq]
+ mova m0, [lq+16]
+ PALIGNR m2, m0, m1, 1, m5
+ PALIGNR m3, m0, m1, 2, m5
+ LOWPASS 3, 2, 1, 5
+ pavgb m2, m1
+%if cpuflag(ssse3)
+ mova m4, [pb_2toE_3xF]
+ pshufb m5, m0, [pb_1toE_2xF]
+ pshufb m1, m0, m4
+%else
+ pand m4, m0, [pb_15x0_1xm1]
+ psrldq m5, m0, 1
+ por m5, m4
+ punpckhbw m4, m4
+ psrldq m1, m0, 2
+ por m1, m4
+%endif
+ LOWPASS 1, 5, 0, 6
+ pavgb m0, m5
+ DEFINE_ARGS dst, stride, cnt, stride0, dst8, dst16, dst24
+ mov cntd, 8
+ xor stride0q, stride0q
+ lea dst8q, [dstq +strideq*8]
+ lea dst16q, [dst8q +strideq*8]
+ lea dst24q, [dst16q+strideq*8]
+ SBUTTERFLY bw, 0, 1, 5
+ SBUTTERFLY bw, 2, 3, 5
+%if cpuflag(ssse3)
+ pshufb m6, m1, [pb_15]
+%else
+ pshufhw m6, m4, q3333
+ punpckhqdq m6, m6
+%endif
+
+.loop:
+ mova [dstq +stride0q+ 0], m2
+ mova [dstq +stride0q+16], m3
+ mova [dst8q +stride0q+ 0], m3
+ mova [dst8q +stride0q+16], m0
+ mova [dst16q+stride0q+ 0], m0
+ mova [dst16q+stride0q+16], m1
+ mova [dst24q+stride0q+ 0], m1
+ mova [dst24q+stride0q+16], m6
+%if cpuflag(avx)
+ palignr m2, m3, m2, 2
+ palignr m3, m0, m3, 2
+ palignr m0, m1, m0, 2
+ pshufb m1, m4
+%elif cpuflag(ssse3)
+ pshufb m5, m1, m4
+ palignr m1, m0, 2
+ palignr m0, m3, 2
+ palignr m3, m2, 2
+ mova m2, m3
+ mova m3, m0
+ mova m0, m1
+ mova m1, m5
+%else
+ ; half-integrated version of PALIGNR
+ pslldq m5, m1, 14
+ pslldq m7, m0, 14
+ psrldq m1, 2
+ psrldq m0, 2
+ por m1, m4
+ por m0, m5
+ pslldq m5, m3, 14
+ psrldq m3, 2
+ por m3, m7
+ psrldq m2, 2
+ por m2, m5
+%endif
+ add stride0q, strideq
+ dec cntd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM sse2
+HU_XMM_FUNCS 8
+INIT_XMM ssse3
+HU_XMM_FUNCS 7
+INIT_XMM avx
+HU_XMM_FUNCS 7
+
+; FIXME 127, 128, 129 ?
diff --git a/libavcodec/x86/vp9itxfm.asm b/libavcodec/x86/vp9itxfm.asm
new file mode 100644
index 0000000000..d9fb36f710
--- /dev/null
+++ b/libavcodec/x86/vp9itxfm.asm
@@ -0,0 +1,2723 @@
+;******************************************************************************
+;* VP9 IDCT SIMD optimizations
+;*
+;* Copyright (C) 2013 ClĂ©ment BÅ“sch <u pkh me>
+;* Copyright (C) 2013 Ronald S. Bultje <rsbultje 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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pw_11585x2: times 8 dw 23170
+pw_m11585x2: times 8 dw -23170
+pw_m11585_11585: times 4 dw -11585, 11585
+pw_11585_11585: times 8 dw 11585
+
+%macro VP9_IDCT_COEFFS 2-3 0
+pw_%1x2: times 8 dw %1*2
+pw_m%1x2: times 8 dw -%1*2
+pw_%2x2: times 8 dw %2*2
+pw_m%2x2: times 8 dw -%2*2
+pw_m%1_%2: times 4 dw -%1, %2
+pw_%2_%1: times 4 dw %2, %1
+pw_m%2_m%1: times 4 dw -%2, -%1
+%if %3 == 1
+pw_m%2_%1: times 4 dw -%2, %1
+pw_%1_%2: times 4 dw %1, %2
+%endif
+%endmacro
+
+VP9_IDCT_COEFFS 15137, 6270, 1
+VP9_IDCT_COEFFS 16069, 3196, 1
+VP9_IDCT_COEFFS 9102, 13623, 1
+VP9_IDCT_COEFFS 16305, 1606
+VP9_IDCT_COEFFS 10394, 12665
+VP9_IDCT_COEFFS 14449, 7723
+VP9_IDCT_COEFFS 4756, 15679
+VP9_IDCT_COEFFS 16364, 804
+VP9_IDCT_COEFFS 11003, 12140
+VP9_IDCT_COEFFS 14811, 7005
+VP9_IDCT_COEFFS 5520, 15426
+VP9_IDCT_COEFFS 15893, 3981
+VP9_IDCT_COEFFS 8423, 14053
+VP9_IDCT_COEFFS 13160, 9760
+VP9_IDCT_COEFFS 2404, 16207
+
+pw_5283_13377: times 4 dw 5283, 13377
+pw_9929_13377: times 4 dw 9929, 13377
+pw_15212_m13377: times 4 dw 15212, -13377
+pw_15212_9929: times 4 dw 15212, 9929
+pw_m5283_m15212: times 4 dw -5283, -15212
+pw_13377x2: times 8 dw 13377*2
+pw_13377_m13377: times 4 dw 13377, -13377
+
+pd_8192: times 4 dd 8192
+
+cextern pw_8
+cextern pw_16
+cextern pw_32
+cextern pw_512
+cextern pw_1024
+cextern pw_2048
+cextern pw_m1
+
+SECTION .text
+
+; (a*x + b*y + round) >> shift
+%macro VP9_MULSUB_2W_2X 5 ; dst1, dst2/src, round, coefs1, coefs2
+ pmaddwd m%1, m%2, %4
+ pmaddwd m%2, %5
+ paddd m%1, %3
+ paddd m%2, %3
+ psrad m%1, 14
+ psrad m%2, 14
+%endmacro
+
+%macro VP9_MULSUB_2W_4X 7 ; dst1, dst2, coef1, coef2, rnd, tmp1/src, tmp2
+ VP9_MULSUB_2W_2X %7, %6, %5, [pw_m%3_%4], [pw_%4_%3]
+ VP9_MULSUB_2W_2X %1, %2, %5, [pw_m%3_%4], [pw_%4_%3]
+ packssdw m%1, m%7
+ packssdw m%2, m%6
+%endmacro
+
+%macro VP9_UNPACK_MULSUB_2W_4X 7-9 ; dst1, dst2, (src1, src2,) coef1, coef2, rnd, tmp1, tmp2
+%if %0 == 7
+ punpckhwd m%6, m%2, m%1
+ punpcklwd m%2, m%1
+ VP9_MULSUB_2W_4X %1, %2, %3, %4, %5, %6, %7
+%else
+ punpckhwd m%8, m%4, m%3
+ punpcklwd m%2, m%4, m%3
+ VP9_MULSUB_2W_4X %1, %2, %5, %6, %7, %8, %9
+%endif
+%endmacro
+
+%macro VP9_UNPACK_MULSUB_2D_4X 6 ; dst1 [src1], dst2 [src2], dst3, dst4, mul1, mul2
+ punpckhwd m%4, m%2, m%1
+ punpcklwd m%2, m%1
+ pmaddwd m%3, m%4, [pw_m%5_%6]
+ pmaddwd m%4, [pw_%6_%5]
+ pmaddwd m%1, m%2, [pw_m%5_%6]
+ pmaddwd m%2, [pw_%6_%5]
+%endmacro
+
+%macro VP9_RND_SH_SUMSUB_BA 6 ; dst1 [src1], dst2 [src2], src3, src4, tmp, round
+ SUMSUB_BA d, %1, %2, %5
+ SUMSUB_BA d, %3, %4, %5
+ paddd m%1, %6
+ paddd m%2, %6
+ paddd m%3, %6
+ paddd m%4, %6
+ psrad m%1, 14
+ psrad m%2, 14
+ psrad m%3, 14
+ psrad m%4, 14
+ packssdw m%1, m%3
+ packssdw m%2, m%4
+%endmacro
+
+%macro VP9_STORE_2X 5-6 dstq ; reg1, reg2, tmp1, tmp2, zero, dst
+ movh m%3, [%6]
+ movh m%4, [%6+strideq]
+ punpcklbw m%3, m%5
+ punpcklbw m%4, m%5
+ paddw m%3, m%1
+ paddw m%4, m%2
+ packuswb m%3, m%5
+ packuswb m%4, m%5
+ movh [%6], m%3
+ movh [%6+strideq], m%4
+%endmacro
+
+%macro ZERO_BLOCK 4 ; mem, stride, nnzcpl, zero_reg
+%assign %%y 0
+%rep %3
+%assign %%x 0
+%rep %3*2/mmsize
+ mova [%1+%%y+%%x], %4
+%assign %%x (%%x+mmsize)
+%endrep
+%assign %%y (%%y+%2)
+%endrep
+%endmacro
+
+;-------------------------------------------------------------------------------------------
+; void vp9_iwht_iwht_4x4_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;-------------------------------------------------------------------------------------------
+
+%macro VP9_IWHT4_1D 0
+ SWAP 1, 2, 3
+ paddw m0, m2
+ psubw m3, m1
+ psubw m4, m0, m3
+ psraw m4, 1
+ psubw m5, m4, m1
+ SWAP 5, 1
+ psubw m4, m2
+ SWAP 4, 2
+ psubw m0, m1
+ paddw m3, m2
+ SWAP 3, 2, 1
+%endmacro
+
+INIT_MMX mmx
+cglobal vp9_iwht_iwht_4x4_add, 3, 3, 0, dst, stride, block, eob
+ mova m0, [blockq+0*8]
+ mova m1, [blockq+1*8]
+ mova m2, [blockq+2*8]
+ mova m3, [blockq+3*8]
+ psraw m0, 2
+ psraw m1, 2
+ psraw m2, 2
+ psraw m3, 2
+
+ VP9_IWHT4_1D
+ TRANSPOSE4x4W 0, 1, 2, 3, 4
+ VP9_IWHT4_1D
+
+ pxor m4, m4
+ VP9_STORE_2X 0, 1, 5, 6, 4
+ lea dstq, [dstq+strideq*2]
+ VP9_STORE_2X 2, 3, 5, 6, 4
+ ZERO_BLOCK blockq, 8, 4, m4
+ RET
+
+;-------------------------------------------------------------------------------------------
+; void vp9_idct_idct_4x4_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;-------------------------------------------------------------------------------------------
+
+%macro VP9_IDCT4_1D_FINALIZE 0
+ SUMSUB_BA w, 3, 2, 4 ; m3=t3+t0, m2=-t3+t0
+ SUMSUB_BA w, 1, 0, 4 ; m1=t2+t1, m0=-t2+t1
+ SWAP 0, 3, 2 ; 3102 -> 0123
+%endmacro
+
+%macro VP9_IDCT4_1D 0
+%if cpuflag(ssse3)
+ SUMSUB_BA w, 2, 0, 4 ; m2=IN(0)+IN(2) m0=IN(0)-IN(2)
+ pmulhrsw m2, m6 ; m2=t0
+ pmulhrsw m0, m6 ; m0=t1
+%else ; <= sse2
+ VP9_UNPACK_MULSUB_2W_4X 0, 2, 11585, 11585, m7, 4, 5 ; m0=t1, m1=t0
+%endif
+ VP9_UNPACK_MULSUB_2W_4X 1, 3, 15137, 6270, m7, 4, 5 ; m1=t2, m3=t3
+ VP9_IDCT4_1D_FINALIZE
+%endmacro
+
+; 2x2 top left corner
+%macro VP9_IDCT4_2x2_1D 0
+ pmulhrsw m0, m5 ; m0=t1
+ mova m2, m0 ; m2=t0
+ mova m3, m1
+ pmulhrsw m1, m6 ; m1=t2
+ pmulhrsw m3, m7 ; m3=t3
+ VP9_IDCT4_1D_FINALIZE
+%endmacro
+
+%macro VP9_IDCT4_WRITEOUT 0
+%if cpuflag(ssse3)
+ mova m5, [pw_2048]
+ pmulhrsw m0, m5 ; (x*2048 + (1<<14))>>15 <=> (x+8)>>4
+ pmulhrsw m1, m5
+%else
+ mova m5, [pw_8]
+ paddw m0, m5
+ paddw m1, m5
+ psraw m0, 4
+ psraw m1, 4
+%endif
+ VP9_STORE_2X 0, 1, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+%if cpuflag(ssse3)
+ pmulhrsw m2, m5
+ pmulhrsw m3, m5
+%else
+ paddw m2, m5
+ paddw m3, m5
+ psraw m2, 4
+ psraw m3, 4
+%endif
+ VP9_STORE_2X 2, 3, 6, 7, 4
+%endmacro
+
+%macro IDCT_4x4_FN 1
+INIT_MMX %1
+cglobal vp9_idct_idct_4x4_add, 4, 4, 0, dst, stride, block, eob
+
+%if cpuflag(ssse3)
+ cmp eobd, 4 ; 2x2 or smaller
+ jg .idctfull
+
+ cmp eobd, 1 ; faster path for when only DC is set
+ jne .idct2x2
+%else
+ cmp eobd, 1
+ jg .idctfull
+%endif
+
+%if cpuflag(ssse3)
+ movd m0, [blockq]
+ mova m5, [pw_11585x2]
+ pmulhrsw m0, m5
+ pmulhrsw m0, m5
+%else
+ DEFINE_ARGS dst, stride, block, coef
+ movsx coefd, word [blockq]
+ imul coefd, 11585
+ add coefd, 8192
+ sar coefd, 14
+ imul coefd, 11585
+ add coefd, (8 << 14) + 8192
+ sar coefd, 14 + 4
+ movd m0, coefd
+%endif
+ pshufw m0, m0, 0
+ pxor m4, m4
+ movh [blockq], m4
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_2048] ; (x*2048 + (1<<14))>>15 <=> (x+8)>>4
+%endif
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ RET
+
+%if cpuflag(ssse3)
+; faster path for when only top left 2x2 block is set
+.idct2x2:
+ movd m0, [blockq+0]
+ movd m1, [blockq+8]
+ mova m5, [pw_11585x2]
+ mova m6, [pw_6270x2]
+ mova m7, [pw_15137x2]
+ VP9_IDCT4_2x2_1D
+ ; partial 2x4 transpose
+ punpcklwd m0, m1
+ punpcklwd m2, m3
+ SBUTTERFLY dq, 0, 2, 1
+ SWAP 1, 2
+ VP9_IDCT4_2x2_1D
+ pxor m4, m4 ; used for the block reset, and VP9_STORE_2X
+ movh [blockq+ 0], m4
+ movh [blockq+ 8], m4
+ VP9_IDCT4_WRITEOUT
+ RET
+%endif
+
+.idctfull: ; generic full 4x4 idct/idct
+ mova m0, [blockq+ 0]
+ mova m1, [blockq+ 8]
+ mova m2, [blockq+16]
+ mova m3, [blockq+24]
+%if cpuflag(ssse3)
+ mova m6, [pw_11585x2]
+%endif
+ mova m7, [pd_8192] ; rounding
+ VP9_IDCT4_1D
+ TRANSPOSE4x4W 0, 1, 2, 3, 4
+ VP9_IDCT4_1D
+ pxor m4, m4 ; used for the block reset, and VP9_STORE_2X
+ mova [blockq+ 0], m4
+ mova [blockq+ 8], m4
+ mova [blockq+16], m4
+ mova [blockq+24], m4
+ VP9_IDCT4_WRITEOUT
+ RET
+%endmacro
+
+IDCT_4x4_FN mmxext
+IDCT_4x4_FN ssse3
+
+;-------------------------------------------------------------------------------------------
+; void vp9_iadst_iadst_4x4_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;-------------------------------------------------------------------------------------------
+
+%macro VP9_IADST4_1D 0
+ movq2dq xmm0, m0
+ movq2dq xmm1, m1
+ movq2dq xmm2, m2
+ movq2dq xmm3, m3
+%if cpuflag(ssse3)
+ paddw m3, m0
+%else
+ paddw xmm6, xmm3, xmm0
+ punpcklwd xmm6, xmm2
+%endif
+ punpcklwd xmm0, xmm1
+ punpcklwd xmm2, xmm3
+ pmaddwd xmm1, xmm0, [pw_5283_13377]
+ pmaddwd xmm4, xmm0, [pw_9929_13377]
+ pmaddwd xmm0, [pw_15212_m13377]
+ pmaddwd xmm3, xmm2, [pw_15212_9929]
+ pmaddwd xmm2, [pw_m5283_m15212]
+%if cpuflag(ssse3)
+ psubw m3, m2
+%else
+ pmaddwd xmm6, [pw_13377_m13377]
+%endif
+ paddd xmm0, xmm2
+ paddd xmm3, xmm5
+ paddd xmm2, xmm5
+%if notcpuflag(ssse3)
+ paddd xmm6, xmm5
+%endif
+ paddd xmm1, xmm3
+ paddd xmm0, xmm3
+ paddd xmm4, xmm2
+ psrad xmm1, 14
+ psrad xmm0, 14
+ psrad xmm4, 14
+%if cpuflag(ssse3)
+ pmulhrsw m3, [pw_13377x2] ; out2
+%else
+ psrad xmm6, 14
+%endif
+ packssdw xmm0, xmm0
+ packssdw xmm1, xmm1
+ packssdw xmm4, xmm4
+%if notcpuflag(ssse3)
+ packssdw xmm6, xmm6
+%endif
+ movdq2q m0, xmm0 ; out3
+ movdq2q m1, xmm1 ; out0
+ movdq2q m2, xmm4 ; out1
+%if notcpuflag(ssse3)
+ movdq2q m3, xmm6 ; out2
+%endif
+ SWAP 0, 1, 2, 3
+%endmacro
+
+%macro IADST4_FN 5
+INIT_MMX %5
+cglobal vp9_%1_%3_4x4_add, 3, 3, 6 + notcpuflag(ssse3), dst, stride, block, eob
+%if WIN64 && notcpuflag(ssse3)
+WIN64_SPILL_XMM 7
+%endif
+ movdqa xmm5, [pd_8192]
+ mova m0, [blockq+ 0]
+ mova m1, [blockq+ 8]
+ mova m2, [blockq+16]
+ mova m3, [blockq+24]
+%if cpuflag(ssse3)
+ mova m6, [pw_11585x2]
+%endif
+%ifnidn %1%3, iadstiadst
+ movdq2q m7, xmm5
+%endif
+ VP9_%2_1D
+ TRANSPOSE4x4W 0, 1, 2, 3, 4
+ VP9_%4_1D
+ pxor m4, m4 ; used for the block reset, and VP9_STORE_2X
+ mova [blockq+ 0], m4
+ mova [blockq+ 8], m4
+ mova [blockq+16], m4
+ mova [blockq+24], m4
+ VP9_IDCT4_WRITEOUT
+ RET
+%endmacro
+
+IADST4_FN idct, IDCT4, iadst, IADST4, sse2
+IADST4_FN iadst, IADST4, idct, IDCT4, sse2
+IADST4_FN iadst, IADST4, iadst, IADST4, sse2
+
+IADST4_FN idct, IDCT4, iadst, IADST4, ssse3
+IADST4_FN iadst, IADST4, idct, IDCT4, ssse3
+IADST4_FN iadst, IADST4, iadst, IADST4, ssse3
+
+%macro SCRATCH 3
+%if ARCH_X86_64
+ SWAP %1, %2
+%else
+ mova [%3], m%1
+%endif
+%endmacro
+
+%macro UNSCRATCH 3
+%if ARCH_X86_64
+ SWAP %1, %2
+%else
+ mova m%1, [%3]
+%endif
+%endmacro
+
+;-------------------------------------------------------------------------------------------
+; void vp9_idct_idct_8x8_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;-------------------------------------------------------------------------------------------
+
+%macro VP9_IDCT8_1D_FINALIZE 0
+ SUMSUB_BA w, 3, 6, 5 ; m3=t0+t7, m6=t0-t7
+ SUMSUB_BA w, 1, 2, 5 ; m1=t1+t6, m2=t1-t6
+ SUMSUB_BA w, 7, 0, 5 ; m7=t2+t5, m0=t2-t5
+
+ UNSCRATCH 5, 8, blockq+ 0
+ SCRATCH 2, 8, blockq+ 0
+
+ SUMSUB_BA w, 5, 4, 2 ; m5=t3+t4, m4=t3-t4
+ SWAP 7, 6, 2
+ SWAP 3, 5, 0
+
+%if ARCH_X86_64
+ SWAP 6, 8
+%endif
+%endmacro
+
+; x86-32
+; - in: m0/m4 is in mem
+; - out: m6 is in mem
+; x86-64:
+; - everything is in registers (m0-7)
+%macro VP9_IDCT8_1D 0
+%if ARCH_X86_64
+ SWAP 0, 8
+ SWAP 4, 9
+%endif
+
+ VP9_UNPACK_MULSUB_2W_4X 5, 3, 9102, 13623, D_8192_REG, 0, 4 ; m5=t5a, m3=t6a
+ VP9_UNPACK_MULSUB_2W_4X 1, 7, 16069, 3196, D_8192_REG, 0, 4 ; m1=t4a, m7=t7a
+ SUMSUB_BA w, 5, 1, 0 ; m5=t4a+t5a (t4), m1=t4a-t5a (t5a)
+ SUMSUB_BA w, 3, 7, 0 ; m3=t7a+t6a (t7), m7=t7a-t6a (t6a)
+%if cpuflag(ssse3)
+ SUMSUB_BA w, 1, 7, 0 ; m1=t6a+t5a (t6), m7=t6a-t5a (t5)
+ pmulhrsw m1, W_11585x2_REG ; m1=t6
+ pmulhrsw m7, W_11585x2_REG ; m7=t5
+%else
+ VP9_UNPACK_MULSUB_2W_4X 7, 1, 11585, 11585, D_8192_REG, 0, 4
+%endif
+ VP9_UNPACK_MULSUB_2W_4X 2, 6, 15137, 6270, D_8192_REG, 0, 4 ; m2=t2a, m6=t3a
+
+ UNSCRATCH 0, 8, blockq+ 0 ; IN(0)
+ UNSCRATCH 4, 9, blockq+64 ; IN(4)
+ SCRATCH 5, 8, blockq+ 0
+
+%if cpuflag(ssse3)
+ SUMSUB_BA w, 4, 0, 5 ; m4=IN(0)+IN(4) m0=IN(0)-IN(4)
+ pmulhrsw m4, W_11585x2_REG ; m4=t0a
+ pmulhrsw m0, W_11585x2_REG ; m0=t1a
+%else
+ SCRATCH 7, 9, blockq+64
+ VP9_UNPACK_MULSUB_2W_4X 0, 4, 11585, 11585, D_8192_REG, 5, 7
+ UNSCRATCH 7, 9, blockq+64
+%endif
+ SUMSUB_BA w, 6, 4, 5 ; m6=t0a+t3a (t0), m4=t0a-t3a (t3)
+ SUMSUB_BA w, 2, 0, 5 ; m2=t1a+t2a (t1), m0=t1a-t2a (t2)
+
+ VP9_IDCT8_1D_FINALIZE
+%endmacro
+
+%macro VP9_IDCT8_4x4_1D 0
+ pmulhrsw m0, W_11585x2_REG ; m0=t1a/t0a
+ pmulhrsw m6, m2, [pw_15137x2] ; m6=t3a
+ pmulhrsw m2, [pw_6270x2] ; m2=t2a
+ pmulhrsw m7, m1, [pw_16069x2] ; m7=t7a
+ pmulhrsw m1, [pw_3196x2] ; m1=t4a
+ pmulhrsw m5, m3, [pw_9102x2] ; m5=-t5a
+ pmulhrsw m3, [pw_13623x2] ; m3=t6a
+ SUMSUB_BA w, 5, 1, 4 ; m1=t4a+t5a (t4), m5=t4a-t5a (t5a)
+ SWAP 1, 5
+ SUMSUB_BA w, 3, 7, 4 ; m3=t7a+t6a (t7), m7=t7a-t6a (t6a)
+ SUMSUB_BA w, 1, 7, 4 ; m1=t6a+t5a (t6), m7=t6a-t5a (t5)
+ pmulhrsw m1, W_11585x2_REG ; m1=t6
+ pmulhrsw m7, W_11585x2_REG ; m7=t5
+ psubw m4, m0, m6 ; m4=t0a-t3a (t3)
+ paddw m6, m0 ; m6=t0a+t3a (t0)
+ SCRATCH 5, 8, blockq+ 0
+ SUMSUB_BA w, 2, 0, 5 ; m2=t1a+t2a (t1), m0=t1a-t2a (t2)
+ VP9_IDCT8_1D_FINALIZE
+%endmacro
+
+%macro VP9_IDCT8_2x2_1D 1
+ pmulhrsw m0, W_11585x2_REG ; m0=t0
+ pmulhrsw m3, m1, W_16069x2_REG ; m3=t7
+ pmulhrsw m1, W_3196x2_REG ; m1=t4
+ psubw m7, m3, m1 ; t5 = t7a - t4a
+ paddw m5, m3, m1 ; t6 = t7a + t4a
+ pmulhrsw m7, W_11585x2_REG ; m7=t5
+ pmulhrsw m5, W_11585x2_REG ; m5=t6
+ SWAP 5, 1
+ ; merged VP9_IDCT8_1D_FINALIZE to make register-sharing w/ avx easier
+ psubw m6, m0, m3 ; m6=t0-t7
+ paddw m3, m0 ; m3=t0+t7
+ psubw m2, m0, m1 ; m2=t1-t6
+ paddw m1, m0 ; m1=t1+t6
+%if %1 == 1
+ punpcklwd m3, m1
+%define SCRATCH_REG 1
+%elif ARCH_X86_32
+ mova [blockq+ 0], m2
+%define SCRATCH_REG 2
+%else
+%define SCRATCH_REG 8
+%endif
+ psubw m4, m0, m5 ; m4=t3-t4
+ paddw m5, m0 ; m5=t3+t4
+ SUMSUB_BA w, 7, 0, SCRATCH_REG ; m7=t2+t5, m0=t2-t5
+ SWAP 7, 6, 2
+ SWAP 3, 5, 0
+%undef SCRATCH_REG
+%endmacro
+
+%macro VP9_IDCT8_WRITEx2 6-8 5 ; line1, line2, tmp1, tmp2, zero, pw_1024/pw_16, shift
+%if cpuflag(ssse3)
+ pmulhrsw m%1, %6 ; (x*1024 + (1<<14))>>15 <=> (x+16)>>5
+ pmulhrsw m%2, %6
+%else
+ paddw m%1, %6
+ paddw m%2, %6
+ psraw m%1, %7
+ psraw m%2, %7
+%endif
+%if %0 <= 7
+ VP9_STORE_2X %1, %2, %3, %4, %5
+%else
+ VP9_STORE_2X %1, %2, %3, %4, %5, %8
+%endif
+%endmacro
+
+; x86-32:
+; - m6 is in mem
+; x86-64:
+; - m8 holds m6 (SWAP)
+; m6 holds zero
+%macro VP9_IDCT8_WRITEOUT 0
+%if ARCH_X86_64
+%if cpuflag(ssse3)
+ mova m9, [pw_1024]
+%else
+ mova m9, [pw_16]
+%endif
+%define ROUND_REG m9
+%else
+%if cpuflag(ssse3)
+%define ROUND_REG [pw_1024]
+%else
+%define ROUND_REG [pw_16]
+%endif
+%endif
+ SCRATCH 5, 10, blockq+16
+ SCRATCH 7, 11, blockq+32
+ VP9_IDCT8_WRITEx2 0, 1, 5, 7, 6, ROUND_REG
+ lea dstq, [dstq+2*strideq]
+ VP9_IDCT8_WRITEx2 2, 3, 5, 7, 6, ROUND_REG
+ lea dstq, [dstq+2*strideq]
+ UNSCRATCH 5, 10, blockq+16
+ UNSCRATCH 7, 11, blockq+32
+ VP9_IDCT8_WRITEx2 4, 5, 0, 1, 6, ROUND_REG
+ lea dstq, [dstq+2*strideq]
+ UNSCRATCH 5, 8, blockq+ 0
+ VP9_IDCT8_WRITEx2 5, 7, 0, 1, 6, ROUND_REG
+
+%undef ROUND_REG
+%endmacro
+
+%macro VP9_IDCT_IDCT_8x8_ADD_XMM 2
+INIT_XMM %1
+cglobal vp9_idct_idct_8x8_add, 4, 4, %2, dst, stride, block, eob
+
+%if cpuflag(ssse3)
+%if ARCH_X86_64
+ mova m12, [pw_11585x2] ; often used
+%define W_11585x2_REG m12
+%else
+%define W_11585x2_REG [pw_11585x2]
+%endif
+
+ cmp eobd, 12 ; top left half or less
+ jg .idctfull
+
+ cmp eobd, 3 ; top left corner or less
+ jg .idcthalf
+
+ cmp eobd, 1 ; faster path for when only DC is set
+ jne .idcttopleftcorner
+%else
+ cmp eobd, 1
+ jg .idctfull
+%endif
+
+%if cpuflag(ssse3)
+ movd m0, [blockq]
+ pmulhrsw m0, W_11585x2_REG
+ pmulhrsw m0, W_11585x2_REG
+%else
+ DEFINE_ARGS dst, stride, block, coef
+ movsx coefd, word [blockq]
+ imul coefd, 11585
+ add coefd, 8192
+ sar coefd, 14
+ imul coefd, 11585
+ add coefd, (16 << 14) + 8192
+ sar coefd, 14 + 5
+ movd m0, coefd
+%endif
+ SPLATW m0, m0, 0
+ pxor m4, m4
+ movd [blockq], m4
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_1024] ; (x*1024 + (1<<14))>>15 <=> (x+16)>>5
+%endif
+%rep 3
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ lea dstq, [dstq+2*strideq]
+%endrep
+ VP9_STORE_2X 0, 0, 6, 7, 4
+ RET
+
+%if cpuflag(ssse3)
+; faster path for when only left corner is set (3 input: DC, right to DC, below
+; to DC). Note: also working with a 2x2 block
+.idcttopleftcorner:
+ movd m0, [blockq+0]
+ movd m1, [blockq+16]
+%if ARCH_X86_64
+ mova m10, [pw_3196x2]
+ mova m11, [pw_16069x2]
+%define W_3196x2_REG m10
+%define W_16069x2_REG m11
+%else
+%define W_3196x2_REG [pw_3196x2]
+%define W_16069x2_REG [pw_16069x2]
+%endif
+ VP9_IDCT8_2x2_1D 1
+ ; partial 2x8 transpose
+ ; punpcklwd m0, m1 already done inside idct
+ punpcklwd m2, m3
+ punpcklwd m4, m5
+ punpcklwd m6, m7
+ punpckldq m0, m2
+ punpckldq m4, m6
+ SBUTTERFLY qdq, 0, 4, 1
+ SWAP 1, 4
+ VP9_IDCT8_2x2_1D 2
+%if ARCH_X86_64
+ SWAP 6, 8
+%endif
+ pxor m6, m6 ; used for the block reset, and VP9_STORE_2X
+ VP9_IDCT8_WRITEOUT
+%if ARCH_X86_64
+ movd [blockq+ 0], m6
+ movd [blockq+16], m6
+%else
+ mova [blockq+ 0], m6
+ mova [blockq+16], m6
+ mova [blockq+32], m6
+%endif
+ RET
+
+.idcthalf:
+ movh m0, [blockq + 0]
+ movh m1, [blockq +16]
+ movh m2, [blockq +32]
+ movh m3, [blockq +48]
+ VP9_IDCT8_4x4_1D
+ ; partial 4x8 transpose
+%if ARCH_X86_32
+ mova m6, [blockq+ 0]
+%endif
+ punpcklwd m0, m1
+ punpcklwd m2, m3
+ punpcklwd m4, m5
+ punpcklwd m6, m7
+ SBUTTERFLY dq, 0, 2, 1
+ SBUTTERFLY dq, 4, 6, 5
+ SBUTTERFLY qdq, 0, 4, 1
+ SBUTTERFLY qdq, 2, 6, 5
+ SWAP 1, 4
+ SWAP 3, 6
+ VP9_IDCT8_4x4_1D
+%if ARCH_X86_64
+ SWAP 6, 8
+%endif
+ pxor m6, m6
+ VP9_IDCT8_WRITEOUT
+%if ARCH_X86_64
+ movh [blockq+ 0], m6
+ movh [blockq+16], m6
+ movh [blockq+32], m6
+%else
+ mova [blockq+ 0], m6
+ mova [blockq+16], m6
+ mova [blockq+32], m6
+%endif
+ movh [blockq+48], m6
+ RET
+%endif
+
+.idctfull: ; generic full 8x8 idct/idct
+%if ARCH_X86_64
+ mova m0, [blockq+ 0] ; IN(0)
+%endif
+ mova m1, [blockq+ 16] ; IN(1)
+ mova m2, [blockq+ 32] ; IN(2)
+ mova m3, [blockq+ 48] ; IN(3)
+%if ARCH_X86_64
+ mova m4, [blockq+ 64] ; IN(4)
+%endif
+ mova m5, [blockq+ 80] ; IN(5)
+ mova m6, [blockq+ 96] ; IN(6)
+ mova m7, [blockq+112] ; IN(7)
+%if ARCH_X86_64
+ mova m11, [pd_8192] ; rounding
+%define D_8192_REG m11
+%else
+%define D_8192_REG [pd_8192]
+%endif
+ VP9_IDCT8_1D
+%if ARCH_X86_64
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, 8
+%else
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [blockq+0], [blockq+64], 1
+ mova [blockq+0], m0
+%endif
+ VP9_IDCT8_1D
+
+%if ARCH_X86_64
+ SWAP 6, 8
+%endif
+ pxor m6, m6 ; used for the block reset, and VP9_STORE_2X
+ VP9_IDCT8_WRITEOUT
+ ZERO_BLOCK blockq, 16, 8, m6
+ RET
+%undef W_11585x2_REG
+%endmacro
+
+VP9_IDCT_IDCT_8x8_ADD_XMM sse2, 12
+VP9_IDCT_IDCT_8x8_ADD_XMM ssse3, 13
+VP9_IDCT_IDCT_8x8_ADD_XMM avx, 13
+
+;---------------------------------------------------------------------------------------------
+; void vp9_iadst_iadst_8x8_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;---------------------------------------------------------------------------------------------
+
+; x86-32:
+; - in: m0/3/4/7 are in mem [blockq+N*16]
+; - out: m6 is in mem [blockq+0]
+; x86-64:
+; - everything is in registers
+%macro VP9_IADST8_1D 0 ; input/output=m0/1/2/3/4/5/6/7
+%if ARCH_X86_64
+ SWAP 0, 8
+ SWAP 3, 9
+ SWAP 4, 10
+ SWAP 7, 11
+%endif
+
+ VP9_UNPACK_MULSUB_2D_4X 5, 2, 0, 3, 14449, 7723 ; m5/2=t3[d], m2/4=t2[d]
+ VP9_UNPACK_MULSUB_2D_4X 1, 6, 4, 7, 4756, 15679 ; m1/4=t7[d], m6/7=t6[d]
+ SCRATCH 4, 12, blockq+1*16
+ VP9_RND_SH_SUMSUB_BA 6, 2, 7, 3, 4, D_8192_REG ; m6=t2[w], m2=t6[w]
+ UNSCRATCH 4, 12, blockq+1*16
+ VP9_RND_SH_SUMSUB_BA 1, 5, 4, 0, 3, D_8192_REG ; m1=t3[w], m5=t7[w]
+
+ UNSCRATCH 0, 8, blockq+16*0
+ UNSCRATCH 3, 9, blockq+16*3
+ UNSCRATCH 4, 10, blockq+16*4
+ UNSCRATCH 7, 11, blockq+16*7
+ SCRATCH 1, 8, blockq+16*1
+ SCRATCH 2, 9, blockq+16*2
+ SCRATCH 5, 10, blockq+16*5
+ SCRATCH 6, 11, blockq+16*6
+
+ VP9_UNPACK_MULSUB_2D_4X 7, 0, 1, 2, 16305, 1606 ; m7/1=t1[d], m0/2=t0[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 4, 5, 6, 10394, 12665 ; m3/5=t5[d], m4/6=t4[d]
+ SCRATCH 1, 12, blockq+ 0*16
+ VP9_RND_SH_SUMSUB_BA 4, 0, 6, 2, 1, D_8192_REG ; m4=t0[w], m0=t4[w]
+ UNSCRATCH 1, 12, blockq+ 0*16
+ VP9_RND_SH_SUMSUB_BA 3, 7, 5, 1, 2, D_8192_REG ; m3=t1[w], m7=t5[w]
+
+ UNSCRATCH 2, 9, blockq+16*2
+ UNSCRATCH 5, 10, blockq+16*5
+ SCRATCH 3, 9, blockq+16*3
+ SCRATCH 4, 10, blockq+16*4
+
+ ; m4=t0, m3=t1, m6=t2, m1=t3, m0=t4, m7=t5, m2=t6, m5=t7
+
+ VP9_UNPACK_MULSUB_2D_4X 0, 7, 1, 3, 15137, 6270 ; m0/1=t5[d], m7/3=t4[d]
+ VP9_UNPACK_MULSUB_2D_4X 5, 2, 4, 6, 6270, 15137 ; m5/4=t6[d], m2/6=t7[d]
+ SCRATCH 1, 12, blockq+ 0*16
+ VP9_RND_SH_SUMSUB_BA 5, 7, 4, 3, 1, D_8192_REG
+ UNSCRATCH 1, 12, blockq+ 0*16
+ PSIGNW m5, W_M1_REG ; m5=out1[w], m7=t6[w]
+ VP9_RND_SH_SUMSUB_BA 2, 0, 6, 1, 3, D_8192_REG ; m2=out6[w], m0=t7[w]
+
+ UNSCRATCH 1, 8, blockq+16*1
+ UNSCRATCH 3, 9, blockq+16*3
+ UNSCRATCH 4, 10, blockq+16*4
+ UNSCRATCH 6, 11, blockq+16*6
+ SCRATCH 2, 8, blockq+16*0
+
+ SUMSUB_BA w, 6, 4, 2 ; m6=out0[w], m4=t2[w]
+ SUMSUB_BA w, 1, 3, 2
+ PSIGNW m1, W_M1_REG ; m1=out7[w], m3=t3[w]
+
+ ; m6=out0, m5=out1, m4=t2, m3=t3, m7=t6, m0=t7, m2=out6, m1=out7
+
+ ; unfortunately, the code below overflows in some cases
+%if 0; cpuflag(ssse3)
+ SUMSUB_BA w, 3, 4, 2
+ SUMSUB_BA w, 0, 7, 2
+ pmulhrsw m3, W_11585x2_REG
+ pmulhrsw m7, W_11585x2_REG
+ pmulhrsw m4, W_11585x2_REG ; out4
+ pmulhrsw m0, W_11585x2_REG ; out2
+%else
+ SCRATCH 5, 9, blockq+16*1
+ VP9_UNPACK_MULSUB_2W_4X 4, 3, 11585, 11585, D_8192_REG, 2, 5
+ VP9_UNPACK_MULSUB_2W_4X 7, 0, 11585, 11585, D_8192_REG, 2, 5
+ UNSCRATCH 5, 9, blockq+16*1
+%endif
+ PSIGNW m3, W_M1_REG ; out3
+ PSIGNW m7, W_M1_REG ; out5
+
+ ; m6=out0, m5=out1, m0=out2, m3=out3, m4=out4, m7=out5, m2=out6, m1=out7
+
+%if ARCH_X86_64
+ SWAP 2, 8
+%endif
+ SWAP 0, 6, 2
+ SWAP 7, 1, 5
+%endmacro
+
+%macro IADST8_FN 6
+INIT_XMM %5
+cglobal vp9_%1_%3_8x8_add, 3, 3, %6, dst, stride, block, eob
+
+%ifidn %1, idct
+%define first_is_idct 1
+%else
+%define first_is_idct 0
+%endif
+
+%ifidn %3, idct
+%define second_is_idct 1
+%else
+%define second_is_idct 0
+%endif
+
+%if ARCH_X86_64
+ mova m0, [blockq+ 0] ; IN(0)
+%endif
+ mova m1, [blockq+ 16] ; IN(1)
+ mova m2, [blockq+ 32] ; IN(2)
+%if ARCH_X86_64 || first_is_idct
+ mova m3, [blockq+ 48] ; IN(3)
+%endif
+%if ARCH_X86_64
+ mova m4, [blockq+ 64] ; IN(4)
+%endif
+ mova m5, [blockq+ 80] ; IN(5)
+ mova m6, [blockq+ 96] ; IN(6)
+%if ARCH_X86_64 || first_is_idct
+ mova m7, [blockq+112] ; IN(7)
+%endif
+%if ARCH_X86_64
+%if cpuflag(ssse3)
+ mova m15, [pw_11585x2] ; often used
+%endif
+ mova m13, [pd_8192] ; rounding
+ mova m14, [pw_m1]
+%define W_11585x2_REG m15
+%define D_8192_REG m13
+%define W_M1_REG m14
+%else
+%define W_11585x2_REG [pw_11585x2]
+%define D_8192_REG [pd_8192]
+%define W_M1_REG [pw_m1]
+%endif
+
+ ; note different calling conventions for idct8 vs. iadst8 on x86-32
+ VP9_%2_1D
+%if ARCH_X86_64
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, 8
+%else
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [blockq+0], [blockq+64], 1
+ mova [blockq+ 0], m0
+%if second_is_idct == 0
+ mova [blockq+ 48], m3
+ mova [blockq+112], m7
+%endif
+%endif
+ VP9_%4_1D
+
+%if ARCH_X86_64
+ SWAP 6, 8
+%endif
+ pxor m6, m6 ; used for the block reset, and VP9_STORE_2X
+ VP9_IDCT8_WRITEOUT
+ ZERO_BLOCK blockq, 16, 8, m6
+ RET
+
+%undef W_11585x2_REG
+%undef first_is_idct
+%undef second_is_idct
+
+%endmacro
+
+%define PSIGNW PSIGNW_MMX
+IADST8_FN idct, IDCT8, iadst, IADST8, sse2, 15
+IADST8_FN iadst, IADST8, idct, IDCT8, sse2, 15
+IADST8_FN iadst, IADST8, iadst, IADST8, sse2, 15
+%define PSIGNW PSIGNW_SSSE3
+IADST8_FN idct, IDCT8, iadst, IADST8, ssse3, 16
+IADST8_FN idct, IDCT8, iadst, IADST8, avx, 16
+IADST8_FN iadst, IADST8, idct, IDCT8, ssse3, 16
+IADST8_FN iadst, IADST8, idct, IDCT8, avx, 16
+IADST8_FN iadst, IADST8, iadst, IADST8, ssse3, 16
+IADST8_FN iadst, IADST8, iadst, IADST8, avx, 16
+%undef PSIGNW
+
+;---------------------------------------------------------------------------------------------
+; void vp9_idct_idct_16x16_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;---------------------------------------------------------------------------------------------
+
+; x86-64:
+; at the end of this macro, m7 is stored in [%4+15*%5]
+; everything else (t0-6 and t8-15) is stored in m0-6 and m8-15
+; the following sumsubs have not been done yet:
+; SUMSUB_BA w, 6, 9, 15 ; t6, t9
+; SUMSUB_BA w, 7, 8, 15 ; t7, t8
+; or (x86-32) t0-t5 are in m0-m5, t10-t15 are in x11/9/7/5/3/1,
+; and the following simsubs have not been done yet:
+; SUMSUB_BA w, x13, x14, 7 ; t6, t9
+; SUMSUB_BA w, x15, x12, 7 ; t7, t8
+
+%macro VP9_IDCT16_1D_START 6 ; src, nnzc, stride, scratch, scratch_stride, is_iadst
+%if %2 <= 4
+ mova m3, [%1+ 1*%3] ; IN(1)
+ mova m0, [%1+ 3*%3] ; IN(3)
+
+ pmulhrsw m4, m3, [pw_16305x2] ; t14-15
+ pmulhrsw m3, [pw_1606x2] ; t8-9
+ pmulhrsw m7, m0, [pw_m4756x2] ; t10-11
+ pmulhrsw m0, [pw_15679x2] ; t12-13
+
+ ; m8=t0, m9=t1, m10=t2, m11=t3, m12=t4, m14=t5, m13=t6, m15=t7
+ ; m3=t8, m5=t9, m1=t10, m7=t11, m0=t12, m6=t13, m2=t14, m4=t15
+
+ VP9_UNPACK_MULSUB_2W_4X 2, 5, 4, 3, 15137, 6270, [pd_8192], 1, 6 ; t9, t14
+ SCRATCH 4, 10, %4+ 1*%5
+ SCRATCH 5, 11, %4+ 7*%5
+ VP9_UNPACK_MULSUB_2W_4X 6, 1, 0, 7, 6270, m15137, [pd_8192], 4, 5 ; t10, t13
+ UNSCRATCH 5, 11, %4+ 7*%5
+
+ ; m15=t0, m14=t1, m13=t2, m12=t3, m11=t4, m10=t5, m9=t6, m8=t7
+ ; m7=t8, m6=t9, m2=t10, m3=t11, m4=t12, m5=t13, m1=t14, m0=t15
+%else
+ mova m5, [%1+ 1*%3] ; IN(1)
+ mova m4, [%1+ 7*%3] ; IN(7)
+%if %2 <= 8
+ pmulhrsw m2, m5, [pw_16305x2] ; t15
+ pmulhrsw m5, [pw_1606x2] ; t8
+ pmulhrsw m3, m4, [pw_m10394x2] ; t9
+ pmulhrsw m4, [pw_12665x2] ; t14
+%else
+ mova m3, [%1+ 9*%3] ; IN(9)
+ mova m2, [%1+15*%3] ; IN(15)
+
+ ; m10=in0, m5=in1, m14=in2, m6=in3, m9=in4, m7=in5, m15=in6, m4=in7
+ ; m11=in8, m3=in9, m12=in10 m0=in11, m8=in12, m1=in13, m13=in14, m2=in15
+
+ VP9_UNPACK_MULSUB_2W_4X 5, 2, 16305, 1606, [pd_8192], 0, 1 ; t8, t15
+ VP9_UNPACK_MULSUB_2W_4X 3, 4, 10394, 12665, [pd_8192], 0, 1 ; t9, t14
+%endif
+
+ SUMSUB_BA w, 3, 5, 0 ; t8, t9
+ SUMSUB_BA w, 4, 2, 0 ; t15, t14
+
+ VP9_UNPACK_MULSUB_2W_4X 2, 5, 15137, 6270, [pd_8192], 0, 1 ; t9, t14
+
+ SCRATCH 4, 10, %4+ 1*%5
+ SCRATCH 5, 11, %4+ 7*%5
+
+ mova m6, [%1+ 3*%3] ; IN(3)
+ mova m7, [%1+ 5*%3] ; IN(5)
+%if %2 <= 8
+ pmulhrsw m0, m7, [pw_14449x2] ; t13
+ pmulhrsw m7, [pw_7723x2] ; t10
+ pmulhrsw m1, m6, [pw_m4756x2] ; t11
+ pmulhrsw m6, [pw_15679x2] ; t12
+%else
+ mova m0, [%1+11*%3] ; IN(11)
+ mova m1, [%1+13*%3] ; IN(13)
+
+ VP9_UNPACK_MULSUB_2W_4X 7, 0, 14449, 7723, [pd_8192], 4, 5 ; t10, t13
+ VP9_UNPACK_MULSUB_2W_4X 1, 6, 4756, 15679, [pd_8192], 4, 5 ; t11, t12
+%endif
+
+ ; m11=t0, m10=t1, m9=t2, m8=t3, m14=t4, m12=t5, m15=t6, m13=t7
+ ; m5=t8, m3=t9, m7=t10, m1=t11, m6=t12, m0=t13, m4=t14, m2=t15
+
+ SUMSUB_BA w, 7, 1, 4 ; t11, t10
+ SUMSUB_BA w, 0, 6, 4 ; t12, t13
+
+ ; m8=t0, m9=t1, m10=t2, m11=t3, m12=t4, m14=t5, m13=t6, m15=t7
+ ; m3=t8, m5=t9, m1=t10, m7=t11, m0=t12, m6=t13, m2=t14, m4=t15
+
+ VP9_UNPACK_MULSUB_2W_4X 6, 1, 6270, m15137, [pd_8192], 4, 5 ; t10, t13
+
+ UNSCRATCH 5, 11, %4+ 7*%5
+%endif
+
+ ; m8=t0, m9=t1, m10=t2, m11=t3, m12=t4, m13=t5, m14=t6, m15=t7
+ ; m3=t8, m2=t9, m6=t10, m7=t11, m0=t12, m1=t13, m5=t14, m4=t15
+
+ SUMSUB_BA w, 7, 3, 4 ; t8, t11
+
+ ; backup first register
+ mova [%4+15*%5], m7
+
+ SUMSUB_BA w, 6, 2, 7 ; t9, t10
+ UNSCRATCH 4, 10, %4+ 1*%5
+ SUMSUB_BA w, 0, 4, 7 ; t15, t12
+ SUMSUB_BA w, 1, 5, 7 ; t14. t13
+
+ ; m15=t0, m14=t1, m13=t2, m12=t3, m11=t4, m10=t5, m9=t6, m8=t7
+ ; m7=t8, m6=t9, m2=t10, m3=t11, m4=t12, m5=t13, m1=t14, m0=t15
+
+%if cpuflag(ssse3) && %6 == 0
+ SUMSUB_BA w, 2, 5, 7
+ SUMSUB_BA w, 3, 4, 7
+ pmulhrsw m5, [pw_11585x2] ; t10
+ pmulhrsw m4, [pw_11585x2] ; t11
+ pmulhrsw m3, [pw_11585x2] ; t12
+ pmulhrsw m2, [pw_11585x2] ; t13
+%else
+ SCRATCH 6, 10, %4+ 1*%5
+ VP9_UNPACK_MULSUB_2W_4X 5, 2, 11585, 11585, [pd_8192], 6, 7 ; t10, t13
+ VP9_UNPACK_MULSUB_2W_4X 4, 3, 11585, 11585, [pd_8192], 6, 7 ; t11, t12
+ UNSCRATCH 6, 10, %4+ 1*%5
+%endif
+
+ ; m15=t0, m14=t1, m13=t2, m12=t3, m11=t4, m10=t5, m9=t6, m8=t7
+ ; m7=t8, m6=t9, m5=t10, m4=t11, m3=t12, m2=t13, m1=t14, m0=t15
+
+ SCRATCH 0, 8, %4+ 1*%5
+ SCRATCH 1, 9, %4+ 3*%5
+ SCRATCH 2, 10, %4+ 5*%5
+ SCRATCH 3, 11, %4+ 7*%5
+ SCRATCH 4, 12, %4+ 9*%5
+ SCRATCH 5, 13, %4+11*%5
+ SCRATCH 6, 14, %4+13*%5
+
+ ; even (tx8x8)
+%if %2 <= 4
+ mova m3, [%1+ 0*%3] ; IN(0)
+ mova m4, [%1+ 2*%3] ; IN(2)
+
+ pmulhrsw m3, [pw_11585x2] ; t0-t3
+ pmulhrsw m7, m4, [pw_16069x2] ; t6-7
+ pmulhrsw m4, [pw_3196x2] ; t4-5
+
+ paddw m6, m7, m4
+ psubw m5, m7, m4
+ pmulhrsw m5, [pw_11585x2] ; t5
+ pmulhrsw m6, [pw_11585x2] ; t6
+
+ psubw m0, m3, m7
+ paddw m7, m3
+ psubw m1, m3, m6
+ paddw m6, m3
+ psubw m2, m3, m5
+ paddw m5, m3
+
+%if ARCH_X86_32
+ SWAP 0, 7
+%endif
+ SCRATCH 7, 15, %4+12*%5
+%else
+ mova m6, [%1+ 2*%3] ; IN(2)
+ mova m1, [%1+ 4*%3] ; IN(4)
+ mova m7, [%1+ 6*%3] ; IN(6)
+%if %2 <= 8
+ pmulhrsw m0, m1, [pw_15137x2] ; t3
+ pmulhrsw m1, [pw_6270x2] ; t2
+ pmulhrsw m5, m6, [pw_16069x2] ; t7
+ pmulhrsw m6, [pw_3196x2] ; t4
+ pmulhrsw m4, m7, [pw_m9102x2] ; t5
+ pmulhrsw m7, [pw_13623x2] ; t6
+%else
+ mova m4, [%1+10*%3] ; IN(10)
+ mova m0, [%1+12*%3] ; IN(12)
+ mova m5, [%1+14*%3] ; IN(14)
+
+ VP9_UNPACK_MULSUB_2W_4X 1, 0, 15137, 6270, [pd_8192], 2, 3 ; t2, t3
+ VP9_UNPACK_MULSUB_2W_4X 6, 5, 16069, 3196, [pd_8192], 2, 3 ; t4, t7
+ VP9_UNPACK_MULSUB_2W_4X 4, 7, 9102, 13623, [pd_8192], 2, 3 ; t5, t6
+%endif
+
+ SUMSUB_BA w, 4, 6, 2 ; t4, t5
+ SUMSUB_BA w, 7, 5, 2 ; t7, t6
+
+%if cpuflag(ssse3) && %6 == 0
+ SUMSUB_BA w, 6, 5, 2
+ pmulhrsw m5, [pw_11585x2] ; t5
+ pmulhrsw m6, [pw_11585x2] ; t6
+%else
+ VP9_UNPACK_MULSUB_2W_4X 5, 6, 11585, 11585, [pd_8192], 2, 3 ; t5, t6
+%endif
+
+ SCRATCH 5, 15, %4+10*%5
+ mova m2, [%1+ 0*%3] ; IN(0)
+%if %2 <= 8
+ pmulhrsw m2, [pw_11585x2] ; t0 and t1
+ psubw m3, m2, m0
+ paddw m0, m2
+
+ SUMSUB_BA w, 7, 0, 5 ; t0, t7
+%else
+ mova m3, [%1+ 8*%3] ; IN(8)
+
+ ; from 3 stages back
+%if cpuflag(ssse3) && %6 == 0
+ SUMSUB_BA w, 3, 2, 5
+ pmulhrsw m3, [pw_11585x2] ; t0
+ pmulhrsw m2, [pw_11585x2] ; t1
+%else
+ mova [%1+ 0*%3], m0
+ VP9_UNPACK_MULSUB_2W_4X 2, 3, 11585, 11585, [pd_8192], 5, 0 ; t0, t1
+ mova m0, [%1+ 0*%3]
+%endif
+
+ ; from 2 stages back
+ SUMSUB_BA w, 0, 3, 5 ; t0, t3
+
+ SUMSUB_BA w, 7, 0, 5 ; t0, t7
+%endif
+ UNSCRATCH 5, 15, %4+10*%5
+%if ARCH_X86_32
+ SWAP 0, 7
+%endif
+ SCRATCH 7, 15, %4+12*%5
+ SUMSUB_BA w, 1, 2, 7 ; t1, t2
+
+ ; from 1 stage back
+ SUMSUB_BA w, 6, 1, 7 ; t1, t6
+ SUMSUB_BA w, 5, 2, 7 ; t2, t5
+%endif
+ SUMSUB_BA w, 4, 3, 7 ; t3, t4
+
+%if ARCH_X86_64
+ SWAP 0, 8
+ SWAP 1, 9
+ SWAP 2, 10
+ SWAP 3, 11
+ SWAP 4, 12
+ SWAP 5, 13
+ SWAP 6, 14
+
+ SUMSUB_BA w, 0, 15, 7 ; t0, t15
+ SUMSUB_BA w, 1, 14, 7 ; t1, t14
+ SUMSUB_BA w, 2, 13, 7 ; t2, t13
+ SUMSUB_BA w, 3, 12, 7 ; t3, t12
+ SUMSUB_BA w, 4, 11, 7 ; t4, t11
+ SUMSUB_BA w, 5, 10, 7 ; t5, t10
+%else
+ SWAP 1, 6
+ SWAP 2, 5
+ SWAP 3, 4
+ mova [%4+14*%5], m6
+
+%macro %%SUMSUB_BA_STORE 5 ; reg, from_mem, to_mem, scratch, scratch_stride
+ mova m6, [%4+%2*%5]
+ SUMSUB_BA w, 6, %1, 7
+ SWAP %1, 6
+ mova [%4+%3*%5], m6
+%endmacro
+
+ %%SUMSUB_BA_STORE 0, 1, 1, %4, %5 ; t0, t15
+ %%SUMSUB_BA_STORE 1, 3, 3, %4, %5 ; t1, t14
+ %%SUMSUB_BA_STORE 2, 5, 5, %4, %5 ; t2, t13
+ %%SUMSUB_BA_STORE 3, 7, 7, %4, %5 ; t3, t12
+ %%SUMSUB_BA_STORE 4, 9, 9, %4, %5 ; t4, t11
+ %%SUMSUB_BA_STORE 5, 11, 11, %4, %5 ; t5, t10
+%endif
+%endmacro
+
+%macro VP9_IDCT16_1D 2-4 16, 1 ; src, pass, nnzc, is_iadst
+%if %2 == 1
+ VP9_IDCT16_1D_START %1, %3, 32, tmpq, 16, %4
+
+%if ARCH_X86_64
+ ; backup a different register
+ mova m7, [tmpq+15*16]
+ mova [tmpq+ 1*16], m15
+
+ SUMSUB_BA w, 6, 9, 15 ; t6, t9
+ SUMSUB_BA w, 7, 8, 15 ; t7, t8
+
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, 15
+ mova [tmpq+ 0], m0
+ mova [tmpq+ 32], m1
+ mova [tmpq+ 64], m2
+ mova [tmpq+ 96], m3
+ mova [tmpq+128], m4
+ mova [tmpq+160], m5
+ mova [tmpq+192], m6
+ mova [tmpq+224], m7
+
+ mova m15, [tmpq+ 1*16]
+ TRANSPOSE8x8W 8, 9, 10, 11, 12, 13, 14, 15, 0
+ mova [tmpq+ 16], m8
+ mova [tmpq+ 48], m9
+ mova [tmpq+ 80], m10
+ mova [tmpq+112], m11
+ mova [tmpq+144], m12
+ mova [tmpq+176], m13
+ mova [tmpq+208], m14
+ mova [tmpq+240], m15
+%else
+ mova m6, [tmpq+13*16]
+ mova m7, [tmpq+14*16]
+ SUMSUB_BA w, 6, 7 ; t6, t9
+ mova [tmpq+14*16], m6
+ mova [tmpq+13*16], m7
+ mova m7, [tmpq+15*16]
+ mova m6, [tmpq+12*16]
+ SUMSUB_BA w, 7, 6 ; t7, t8
+ mova [tmpq+15*16], m6
+
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [tmpq+14*16], [tmpq+ 8*16], 1
+ mova [tmpq+ 0*16], m0
+ mova [tmpq+ 2*16], m1
+ mova [tmpq+ 4*16], m2
+ mova [tmpq+ 6*16], m3
+ mova [tmpq+10*16], m5
+ mova [tmpq+12*16], m6
+ mova [tmpq+14*16], m7
+
+ mova m0, [tmpq+15*16]
+ mova m1, [tmpq+13*16]
+ mova m2, [tmpq+11*16]
+ mova m3, [tmpq+ 9*16]
+ mova m4, [tmpq+ 7*16]
+ mova m5, [tmpq+ 5*16]
+ mova m7, [tmpq+ 1*16]
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [tmpq+ 3*16], [tmpq+ 9*16], 1
+ mova [tmpq+ 1*16], m0
+ mova [tmpq+ 3*16], m1
+ mova [tmpq+ 5*16], m2
+ mova [tmpq+ 7*16], m3
+ mova [tmpq+11*16], m5
+ mova [tmpq+13*16], m6
+ mova [tmpq+15*16], m7
+%endif
+%else ; %2 == 2
+ VP9_IDCT16_1D_START %1, %3, 32, %1, 32, %4
+
+%if cpuflag(ssse3)
+%define ROUND_REG [pw_512]
+%else
+%define ROUND_REG [pw_32]
+%endif
+
+ pxor m7, m7
+%if ARCH_X86_64
+ ; backup more registers
+ mova [%1+ 2*32], m8
+ mova [%1+ 3*32], m9
+
+ VP9_IDCT8_WRITEx2 0, 1, 8, 9, 7, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 2, 3, 8, 9, 7, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 4, 5, 8, 9, 7, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ ; restore from cache
+ SWAP 0, 7 ; move zero from m7 to m0
+ mova m7, [%1+15*32]
+ mova m8, [%1+ 2*32]
+ mova m9, [%1+ 3*32]
+
+ SUMSUB_BA w, 6, 9, 3 ; t6, t9
+ SUMSUB_BA w, 7, 8, 3 ; t7, t8
+
+ VP9_IDCT8_WRITEx2 6, 7, 3, 4, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 8, 9, 3, 4, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 10, 11, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 12, 13, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 14, 15, 1, 2, 0, ROUND_REG, 6
+%else
+ mova [tmpq+ 0*32], m5
+
+ VP9_IDCT8_WRITEx2 0, 1, 5, 6, 7, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 2, 3, 5, 6, 7, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ SWAP 0, 7 ; move zero from m7 to m0
+ mova m5, [tmpq+ 0*32]
+
+ VP9_IDCT8_WRITEx2 4, 5, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ mova m4, [tmpq+13*32]
+ mova m7, [tmpq+14*32]
+ mova m5, [tmpq+15*32]
+ mova m6, [tmpq+12*32]
+ SUMSUB_BADC w, 4, 7, 5, 6, 1
+
+ VP9_IDCT8_WRITEx2 4, 5, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 6, 7, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ mova m4, [tmpq+11*32]
+ mova m5, [tmpq+ 9*32]
+ mova m6, [tmpq+ 7*32]
+ mova m7, [tmpq+ 5*32]
+
+ VP9_IDCT8_WRITEx2 4, 5, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 6, 7, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ mova m4, [tmpq+ 3*32]
+ mova m5, [tmpq+ 1*32]
+
+ VP9_IDCT8_WRITEx2 4, 5, 1, 2, 0, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+%endif
+
+%undef ROUND_REG
+%endif ; %2 == 1/2
+%endmacro
+
+%macro VP9_STORE_2XFULL 6-7 strideq; dc, tmp1, tmp2, tmp3, tmp4, zero, stride
+ mova m%3, [dstq]
+ mova m%5, [dstq+%7]
+ punpcklbw m%2, m%3, m%6
+ punpckhbw m%3, m%6
+ punpcklbw m%4, m%5, m%6
+ punpckhbw m%5, m%6
+ paddw m%2, m%1
+ paddw m%3, m%1
+ paddw m%4, m%1
+ paddw m%5, m%1
+ packuswb m%2, m%3
+ packuswb m%4, m%5
+ mova [dstq], m%2
+ mova [dstq+%7], m%4
+%endmacro
+
+%macro VP9_IDCT_IDCT_16x16_ADD_XMM 1
+INIT_XMM %1
+cglobal vp9_idct_idct_16x16_add, 4, 6, 16, 512, dst, stride, block, eob
+%if cpuflag(ssse3)
+ ; 2x2=eob=3, 4x4=eob=10
+ cmp eobd, 38
+ jg .idctfull
+ cmp eobd, 1 ; faster path for when only DC is set
+ jne .idct8x8
+%else
+ cmp eobd, 1 ; faster path for when only DC is set
+ jg .idctfull
+%endif
+
+ ; dc-only
+%if cpuflag(ssse3)
+ movd m0, [blockq]
+ mova m1, [pw_11585x2]
+ pmulhrsw m0, m1
+ pmulhrsw m0, m1
+%else
+ DEFINE_ARGS dst, stride, block, coef
+ movsx coefd, word [blockq]
+ imul coefd, 11585
+ add coefd, 8192
+ sar coefd, 14
+ imul coefd, 11585
+ add coefd, (32 << 14) + 8192
+ sar coefd, 14 + 6
+ movd m0, coefd
+%endif
+ SPLATW m0, m0, q0000
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_512]
+%endif
+ pxor m5, m5
+ movd [blockq], m5
+%rep 7
+ VP9_STORE_2XFULL 0, 1, 2, 3, 4, 5
+ lea dstq, [dstq+2*strideq]
+%endrep
+ VP9_STORE_2XFULL 0, 1, 2, 3, 4, 5
+ RET
+
+ DEFINE_ARGS dst, stride, block, cnt, dst_bak, tmp
+%if cpuflag(ssse3)
+.idct8x8:
+ mov tmpq, rsp
+ VP9_IDCT16_1D blockq, 1, 8, 0
+
+ mov cntd, 2
+ mov dst_bakq, dstq
+.loop2_8x8:
+ VP9_IDCT16_1D tmpq, 2, 8, 0
+ lea dstq, [dst_bakq+8]
+ add tmpq, 16
+ dec cntd
+ jg .loop2_8x8
+
+ ; at the end of the loop, m0 should still be zero
+ ; use that to zero out block coefficients
+ ZERO_BLOCK blockq, 32, 8, m0
+ RET
+%endif
+
+.idctfull:
+ mov cntd, 2
+ mov tmpq, rsp
+.loop1_full:
+ VP9_IDCT16_1D blockq, 1, 16, 0
+ add blockq, 16
+ add tmpq, 256
+ dec cntd
+ jg .loop1_full
+ sub blockq, 32
+
+ mov cntd, 2
+ mov tmpq, rsp
+ mov dst_bakq, dstq
+.loop2_full:
+ VP9_IDCT16_1D tmpq, 2, 16, 0
+ lea dstq, [dst_bakq+8]
+ add tmpq, 16
+ dec cntd
+ jg .loop2_full
+
+ ; at the end of the loop, m0 should still be zero
+ ; use that to zero out block coefficients
+ ZERO_BLOCK blockq, 32, 16, m0
+ RET
+%endmacro
+
+VP9_IDCT_IDCT_16x16_ADD_XMM sse2
+VP9_IDCT_IDCT_16x16_ADD_XMM ssse3
+VP9_IDCT_IDCT_16x16_ADD_XMM avx
+
+;---------------------------------------------------------------------------------------------
+; void vp9_iadst_iadst_16x16_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;---------------------------------------------------------------------------------------------
+
+%macro VP9_IADST16_1D 2 ; src, pass
+%assign %%str 16*%2
+ mova m0, [%1+ 0*32] ; in0
+ mova m1, [%1+15*32] ; in15
+ mova m2, [%1+ 7*32] ; in7
+ mova m3, [%1+ 8*32] ; in8
+
+ VP9_UNPACK_MULSUB_2D_4X 1, 0, 4, 5, 16364, 804 ; m1/4=t1[d], m0/5=t0[d]
+ VP9_UNPACK_MULSUB_2D_4X 2, 3, 7, 6, 11003, 12140 ; m2/7=t9[d], m3/6=t8[d]
+ SCRATCH 4, 8, tmpq+ 0*%%str
+ VP9_RND_SH_SUMSUB_BA 3, 0, 6, 5, 4, [pd_8192] ; m3=t0[w], m0=t8[w]
+ UNSCRATCH 4, 8, tmpq+ 0*%%str
+ VP9_RND_SH_SUMSUB_BA 2, 1, 7, 4, 5, [pd_8192] ; m2=t1[w], m1=t9[w]
+
+ SCRATCH 0, 10, tmpq+ 0*%%str
+ SCRATCH 1, 11, tmpq+15*%%str
+ mova [tmpq+ 7*%%str], m2
+ mova [tmpq+ 8*%%str], m3
+
+ mova m1, [%1+ 2*32] ; in2
+ mova m0, [%1+13*32] ; in13
+ mova m3, [%1+ 5*32] ; in5
+ mova m2, [%1+10*32] ; in10
+
+ VP9_UNPACK_MULSUB_2D_4X 0, 1, 6, 7, 15893, 3981 ; m0/6=t3[d], m1/7=t2[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 4, 5, 8423, 14053 ; m3/4=t11[d], m2/5=t10[d]
+ SCRATCH 4, 12, tmpq+ 2*%%str
+ VP9_RND_SH_SUMSUB_BA 2, 1, 5, 7, 4, [pd_8192] ; m2=t2[w], m1=t10[w]
+ UNSCRATCH 4, 12, tmpq+ 2*%%str
+ VP9_RND_SH_SUMSUB_BA 3, 0, 4, 6, 5, [pd_8192] ; m3=t3[w], m0=t11[w]
+
+ SCRATCH 0, 12, tmpq+ 2*%%str
+ SCRATCH 1, 13, tmpq+13*%%str
+ mova [tmpq+ 5*%%str], m2
+ mova [tmpq+10*%%str], m3
+
+ mova m2, [%1+ 4*32] ; in4
+ mova m3, [%1+11*32] ; in11
+ mova m0, [%1+ 3*32] ; in3
+ mova m1, [%1+12*32] ; in12
+
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 7, 6, 14811, 7005 ; m3/7=t5[d], m2/6=t4[d]
+ VP9_UNPACK_MULSUB_2D_4X 0, 1, 4, 5, 5520, 15426 ; m0/4=t13[d], m1/5=t12[d]
+ SCRATCH 4, 9, tmpq+ 4*%%str
+ VP9_RND_SH_SUMSUB_BA 1, 2, 5, 6, 4, [pd_8192] ; m1=t4[w], m2=t12[w]
+ UNSCRATCH 4, 9, tmpq+ 4*%%str
+ VP9_RND_SH_SUMSUB_BA 0, 3, 4, 7, 6, [pd_8192] ; m0=t5[w], m3=t13[w]
+
+ SCRATCH 0, 8, tmpq+ 4*%%str
+ mova [tmpq+11*%%str], m1 ; t4:m1->r11
+ UNSCRATCH 0, 10, tmpq+ 0*%%str
+ UNSCRATCH 1, 11, tmpq+15*%%str
+
+ ; round 2 interleaved part 1
+ VP9_UNPACK_MULSUB_2D_4X 0, 1, 6, 7, 16069, 3196 ; m1/7=t8[d], m0/6=t9[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 5, 4, 3196, 16069 ; m3/5=t12[d], m2/4=t13[d]
+ SCRATCH 4, 9, tmpq+ 3*%%str
+ VP9_RND_SH_SUMSUB_BA 3, 1, 5, 7, 4, [pd_8192] ; m3=t8[w], m1=t12[w]
+ UNSCRATCH 4, 9, tmpq+ 3*%%str
+ VP9_RND_SH_SUMSUB_BA 2, 0, 4, 6, 5, [pd_8192] ; m2=t9[w], m0=t13[w]
+
+ SCRATCH 0, 10, tmpq+ 0*%%str
+ SCRATCH 1, 11, tmpq+15*%%str
+ SCRATCH 2, 14, tmpq+ 3*%%str
+ SCRATCH 3, 15, tmpq+12*%%str
+
+ mova m2, [%1+ 6*32] ; in6
+ mova m3, [%1+ 9*32] ; in9
+ mova m0, [%1+ 1*32] ; in1
+ mova m1, [%1+14*32] ; in14
+
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 7, 6, 13160, 9760 ; m3/7=t7[d], m2/6=t6[d]
+ VP9_UNPACK_MULSUB_2D_4X 0, 1, 4, 5, 2404, 16207 ; m0/4=t15[d], m1/5=t14[d]
+ SCRATCH 4, 9, tmpq+ 6*%%str
+ VP9_RND_SH_SUMSUB_BA 1, 2, 5, 6, 4, [pd_8192] ; m1=t6[w], m2=t14[w]
+ UNSCRATCH 4, 9, tmpq+ 6*%%str
+ VP9_RND_SH_SUMSUB_BA 0, 3, 4, 7, 6, [pd_8192] ; m0=t7[w], m3=t15[w]
+
+ ; r8=t0, r7=t1, r5=t2, r10=t3, r11=t4, m8|r4=t5, m1=t6, m0=t7
+ ; m10|r0=t8, m11|r15=t9, m13|r13=t10, m12|r2=t11, m14|r3=t12, m15|r12=t13, m2=t14, m3=t15
+
+ UNSCRATCH 4, 12, tmpq+ 2*%%str
+ UNSCRATCH 5, 13, tmpq+13*%%str
+ SCRATCH 0, 12, tmpq+ 1*%%str
+ SCRATCH 1, 13, tmpq+14*%%str
+
+ ; remainder of round 2 (rest of t8-15)
+ VP9_UNPACK_MULSUB_2D_4X 5, 4, 6, 7, 9102, 13623 ; m5/6=t11[d], m4/7=t10[d]
+ VP9_UNPACK_MULSUB_2D_4X 3, 2, 1, 0, 13623, 9102 ; m3/1=t14[d], m2/0=t15[d]
+ SCRATCH 0, 9, tmpq+ 6*%%str
+ VP9_RND_SH_SUMSUB_BA 3, 4, 1, 7, 0, [pd_8192] ; m3=t10[w], m4=t14[w]
+ UNSCRATCH 0, 9, tmpq+ 6*%%str
+ VP9_RND_SH_SUMSUB_BA 2, 5, 0, 6, 1, [pd_8192] ; m2=t11[w], m5=t15[w]
+
+ ; m15|r12=t8, m14|r3=t9, m3=t10, m2=t11, m11|r15=t12, m10|r0=t13, m4=t14, m5=t15
+
+ UNSCRATCH 6, 14, tmpq+ 3*%%str
+ UNSCRATCH 7, 15, tmpq+12*%%str
+
+ SUMSUB_BA w, 3, 7, 1
+ PSIGNW m3, [pw_m1] ; m3=out1[w], m7=t10[w]
+ SUMSUB_BA w, 2, 6, 1 ; m2=out14[w], m6=t11[w]
+
+ ; unfortunately, the code below overflows in some cases, e.g.
+ ; http://downloads.webmproject.org/test_data/libvpx/vp90-2-14-resize-fp-tiles-16-8.webm
+%if 0; cpuflag(ssse3)
+ SUMSUB_BA w, 7, 6, 1
+ pmulhrsw m7, [pw_11585x2] ; m7=out6[w]
+ pmulhrsw m6, [pw_11585x2] ; m6=out9[w]
+%else
+ VP9_UNPACK_MULSUB_2W_4X 6, 7, 11585, 11585, [pd_8192], 1, 0
+%endif
+
+ mova [tmpq+ 3*%%str], m6
+ mova [tmpq+ 6*%%str], m7
+ UNSCRATCH 6, 10, tmpq+ 0*%%str
+ UNSCRATCH 7, 11, tmpq+15*%%str
+ mova [tmpq+13*%%str], m2
+ SCRATCH 3, 11, tmpq+ 9*%%str
+
+ VP9_UNPACK_MULSUB_2D_4X 7, 6, 2, 3, 15137, 6270 ; m6/3=t13[d], m7/2=t12[d]
+ VP9_UNPACK_MULSUB_2D_4X 5, 4, 1, 0, 6270, 15137 ; m5/1=t14[d], m4/0=t15[d]
+ SCRATCH 0, 9, tmpq+ 2*%%str
+ VP9_RND_SH_SUMSUB_BA 5, 6, 1, 3, 0, [pd_8192] ; m5=out2[w], m6=t14[w]
+ UNSCRATCH 0, 9, tmpq+ 2*%%str
+ VP9_RND_SH_SUMSUB_BA 4, 7, 0, 2, 1, [pd_8192]
+ PSIGNW m4, [pw_m1] ; m4=out13[w], m7=t15[w]
+
+ ; unfortunately, the code below overflows in some cases
+%if 0; cpuflag(ssse3)
+ SUMSUB_BA w, 7, 6, 1
+ pmulhrsw m7, [pw_m11585x2] ; m7=out5[w]
+ pmulhrsw m6, [pw_11585x2] ; m6=out10[w]
+%else
+ PSIGNW m7, [pw_m1]
+ VP9_UNPACK_MULSUB_2W_4X 7, 6, 11585, 11585, [pd_8192], 1, 0
+%endif
+
+ ; m11|r13=out1, m5=out2, m7=out5, r15=out6, r3=out9, m6=out10, m4=out13, r2=out14
+
+ mova m2, [tmpq+ 8*%%str]
+ mova m3, [tmpq+ 7*%%str]
+ mova m1, [tmpq+11*%%str]
+ mova [tmpq+ 7*%%str], m6
+ mova [tmpq+11*%%str], m4
+ mova m4, [tmpq+ 5*%%str]
+ SCRATCH 5, 14, tmpq+ 5*%%str
+ SCRATCH 7, 15, tmpq+ 8*%%str
+ UNSCRATCH 6, 8, tmpq+ 4*%%str
+ UNSCRATCH 5, 12, tmpq+ 1*%%str
+ UNSCRATCH 7, 13, tmpq+14*%%str
+
+ ; m2=t0, m3=t1, m9=t2, m0=t3, m1=t4, m8=t5, m13=t6, m12=t7
+ ; m11|r13=out1, m5=out2, m7=out5, r15=out6, r3=out9, r10=out10, r11=out13, r2=out14
+
+ SUMSUB_BA w, 1, 2, 0 ; m1=t0[w], m2=t4[w]
+ mova m0, [tmpq+10*%%str]
+ SCRATCH 1, 12, tmpq+ 1*%%str
+ SUMSUB_BA w, 6, 3, 1 ; m8=t1[w], m3=t5[w]
+ SCRATCH 6, 13, tmpq+ 4*%%str
+ SUMSUB_BA w, 7, 4, 1 ; m13=t2[w], m9=t6[w]
+ SCRATCH 7, 8, tmpq+10*%%str
+ SUMSUB_BA w, 5, 0, 1 ; m12=t3[w], m0=t7[w]
+ SCRATCH 5, 9, tmpq+14*%%str
+
+ VP9_UNPACK_MULSUB_2D_4X 2, 3, 7, 5, 15137, 6270 ; m2/6=t5[d], m3/10=t4[d]
+ VP9_UNPACK_MULSUB_2D_4X 0, 4, 1, 6, 6270, 15137 ; m0/14=t6[d], m9/15=t7[d]
+ SCRATCH 6, 10, tmpq+ 0*%%str
+ VP9_RND_SH_SUMSUB_BA 0, 3, 1, 5, 6, [pd_8192]
+ UNSCRATCH 6, 10, tmpq+ 0*%%str
+ PSIGNW m0, [pw_m1] ; m0=out3[w], m3=t6[w]
+ VP9_RND_SH_SUMSUB_BA 4, 2, 6, 7, 5, [pd_8192] ; m9=out12[w], m2=t7[w]
+
+ UNSCRATCH 1, 8, tmpq+10*%%str
+ UNSCRATCH 5, 9, tmpq+14*%%str
+ UNSCRATCH 6, 12, tmpq+ 1*%%str
+ UNSCRATCH 7, 13, tmpq+ 4*%%str
+ SCRATCH 4, 9, tmpq+14*%%str
+
+ SUMSUB_BA w, 1, 6, 4 ; m13=out0[w], m1=t2[w]
+ SUMSUB_BA w, 5, 7, 4
+ PSIGNW m5, [pw_m1] ; m12=out15[w], m8=t3[w]
+
+ ; unfortunately, the code below overflows in some cases, e.g.
+ ; http://downloads.webmproject.org/test_data/libvpx/vp90-2-14-resize-fp-tiles-16-8-4-2-1.webm
+%if 0 ; cpuflag(ssse3)
+ SUMSUB_BA w, 7, 6, 4
+ pmulhrsw m7, [pw_m11585x2] ; m8=out7[w]
+ pmulhrsw m6, [pw_11585x2] ; m1=out8[w]
+ SUMSUB_BA w, 3, 2, 4
+ pmulhrsw m3, [pw_11585x2] ; m3=out4[w]
+ pmulhrsw m2, [pw_11585x2] ; m2=out11[w]
+%else
+ SCRATCH 5, 8, tmpq+10*%%str
+ PSIGNW m7, [pw_m1]
+ VP9_UNPACK_MULSUB_2W_4X 7, 6, 11585, 11585, [pd_8192], 5, 4
+ VP9_UNPACK_MULSUB_2W_4X 2, 3, 11585, 11585, [pd_8192], 5, 4
+ UNSCRATCH 5, 8, tmpq+10*%%str
+%endif
+
+ ; m13=out0, m0=out3, m3=out4, m8=out7, m1=out8, m2=out11, m9=out12, m12=out15
+ ; m11|r13=out1, m5=out2, m7=out5, r15=out6, r3=out9, r10=out10, r11=out13, r2=out14
+
+%if %2 == 1
+%if ARCH_X86_64
+ mova m13, [tmpq+ 6*%%str]
+ TRANSPOSE8x8W 1, 11, 14, 0, 3, 15, 13, 7, 10
+ mova [tmpq+ 0*16], m1
+ mova [tmpq+ 2*16], m11
+ mova [tmpq+ 4*16], m14
+ mova [tmpq+ 6*16], m0
+ mova m1, [tmpq+ 3*%%str]
+ mova m11, [tmpq+ 7*%%str]
+ mova m14, [tmpq+11*%%str]
+ mova m0, [tmpq+13*%%str]
+ mova [tmpq+ 8*16], m3
+ mova [tmpq+10*16], m15
+ mova [tmpq+12*16], m13
+ mova [tmpq+14*16], m7
+
+ TRANSPOSE8x8W 6, 1, 11, 2, 9, 14, 0, 5, 10
+ mova [tmpq+ 1*16], m6
+ mova [tmpq+ 3*16], m1
+ mova [tmpq+ 5*16], m11
+ mova [tmpq+ 7*16], m2
+ mova [tmpq+ 9*16], m9
+ mova [tmpq+11*16], m14
+ mova [tmpq+13*16], m0
+ mova [tmpq+15*16], m5
+%else
+ mova [tmpq+12*%%str], m2
+ mova [tmpq+ 1*%%str], m5
+ mova [tmpq+15*%%str], m6
+ mova m2, [tmpq+ 9*%%str]
+ mova m5, [tmpq+ 5*%%str]
+ mova m6, [tmpq+ 8*%%str]
+ TRANSPOSE8x8W 1, 2, 5, 0, 3, 6, 4, 7, [tmpq+ 6*%%str], [tmpq+ 8*%%str], 1
+ mova [tmpq+ 0*16], m1
+ mova [tmpq+ 2*16], m2
+ mova [tmpq+ 4*16], m5
+ mova [tmpq+ 6*16], m0
+ mova [tmpq+10*16], m6
+ mova m3, [tmpq+12*%%str]
+ mova [tmpq+12*16], m4
+ mova m4, [tmpq+14*%%str]
+ mova [tmpq+14*16], m7
+
+ mova m0, [tmpq+15*%%str]
+ mova m1, [tmpq+ 3*%%str]
+ mova m2, [tmpq+ 7*%%str]
+ mova m5, [tmpq+11*%%str]
+ mova m7, [tmpq+ 1*%%str]
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [tmpq+13*%%str], [tmpq+ 9*%%str], 1
+ mova [tmpq+ 1*16], m0
+ mova [tmpq+ 3*16], m1
+ mova [tmpq+ 5*16], m2
+ mova [tmpq+ 7*16], m3
+ mova [tmpq+11*16], m5
+ mova [tmpq+13*16], m6
+ mova [tmpq+15*16], m7
+%endif
+%else
+ pxor m4, m4
+
+%if cpuflag(ssse3)
+%define ROUND_REG [pw_512]
+%else
+%define ROUND_REG [pw_32]
+%endif
+
+%if ARCH_X86_64
+ mova m12, [tmpq+ 6*%%str]
+ VP9_IDCT8_WRITEx2 1, 11, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 14, 0, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 3, 15, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 12, 7, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ mova m1, [tmpq+ 3*%%str]
+ mova m11, [tmpq+ 7*%%str]
+ mova m14, [tmpq+11*%%str]
+ mova m0, [tmpq+13*%%str]
+
+ VP9_IDCT8_WRITEx2 6, 1, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 11, 2, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 9, 14, 10, 8, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ VP9_IDCT8_WRITEx2 0, 5, 10, 8, 4, ROUND_REG, 6
+%else
+ mova [tmpq+ 0*%%str], m2
+ mova [tmpq+ 1*%%str], m5
+ mova [tmpq+ 2*%%str], m6
+ mova m2, [tmpq+ 9*%%str]
+ VP9_IDCT8_WRITEx2 1, 2, 5, 6, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ mova m5, [tmpq+ 5*%%str]
+ VP9_IDCT8_WRITEx2 5, 0, 1, 2, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ mova m5, [tmpq+ 8*%%str]
+ VP9_IDCT8_WRITEx2 3, 5, 1, 2, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ mova m5, [tmpq+ 6*%%str]
+ VP9_IDCT8_WRITEx2 5, 7, 1, 2, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+
+ mova m0, [tmpq+ 2*%%str]
+ mova m3, [tmpq+ 3*%%str]
+ VP9_IDCT8_WRITEx2 0, 3, 1, 2, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ mova m0, [tmpq+ 7*%%str]
+ mova m3, [tmpq+ 0*%%str]
+ VP9_IDCT8_WRITEx2 0, 3, 1, 2, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ mova m0, [tmpq+14*%%str]
+ mova m3, [tmpq+11*%%str]
+ VP9_IDCT8_WRITEx2 0, 3, 1, 2, 4, ROUND_REG, 6
+ lea dstq, [dstq+strideq*2]
+ mova m0, [tmpq+13*%%str]
+ mova m3, [tmpq+ 1*%%str]
+ VP9_IDCT8_WRITEx2 0, 3, 1, 2, 4, ROUND_REG, 6
+%endif
+
+ SWAP 0, 4 ; zero
+%undef ROUND_REG
+%endif
+%endmacro
+
+%macro IADST16_FN 5
+INIT_XMM %5
+cglobal vp9_%1_%3_16x16_add, 3, 6, 16, 512, dst, stride, block, cnt, dst_bak, tmp
+ mov cntd, 2
+ mov tmpq, rsp
+.loop1_full:
+ VP9_%2_1D blockq, 1
+ add blockq, 16
+ add tmpq, 256
+ dec cntd
+ jg .loop1_full
+ sub blockq, 32
+
+ mov cntd, 2
+ mov tmpq, rsp
+ mov dst_bakq, dstq
+.loop2_full:
+ VP9_%4_1D tmpq, 2
+ lea dstq, [dst_bakq+8]
+ add tmpq, 16
+ dec cntd
+ jg .loop2_full
+
+ ; at the end of the loop, m0 should still be zero
+ ; use that to zero out block coefficients
+ ZERO_BLOCK blockq, 32, 16, m0
+ RET
+%endmacro
+
+%define PSIGNW PSIGNW_MMX
+IADST16_FN idct, IDCT16, iadst, IADST16, sse2
+IADST16_FN iadst, IADST16, idct, IDCT16, sse2
+IADST16_FN iadst, IADST16, iadst, IADST16, sse2
+%define PSIGNW PSIGNW_SSSE3
+IADST16_FN idct, IDCT16, iadst, IADST16, ssse3
+IADST16_FN iadst, IADST16, idct, IDCT16, ssse3
+IADST16_FN iadst, IADST16, iadst, IADST16, ssse3
+IADST16_FN idct, IDCT16, iadst, IADST16, avx
+IADST16_FN iadst, IADST16, idct, IDCT16, avx
+IADST16_FN iadst, IADST16, iadst, IADST16, avx
+%undef PSIGNW
+
+;---------------------------------------------------------------------------------------------
+; void vp9_idct_idct_32x32_add_<opt>(uint8_t *dst, ptrdiff_t stride, int16_t *block, int eob);
+;---------------------------------------------------------------------------------------------
+
+%macro VP9_IDCT32_1D 2-3 32 ; src, pass, nnzc
+%assign %%str 16*%2*%2
+ ; first do t0-15, this can be done identical to idct16x16
+ VP9_IDCT16_1D_START %1, %3/2, 64*2, tmpq, 2*%%str, 1
+
+ ; store everything on stack to make space available for t16-31
+ ; we store interleaved with the output of the second half (t16-31)
+ ; so we don't need to allocate extra stack space
+ mova [tmpq+ 0*%%str], m0 ; t0
+ mova [tmpq+ 4*%%str], m1 ; t1
+ mova [tmpq+ 8*%%str], m2 ; t2
+ mova [tmpq+12*%%str], m3 ; t3
+ mova [tmpq+16*%%str], m4 ; t4
+ mova [tmpq+20*%%str], m5 ; t5
+%if ARCH_X86_64
+ mova [tmpq+22*%%str], m10 ; t10
+ mova [tmpq+18*%%str], m11 ; t11
+ mova [tmpq+14*%%str], m12 ; t12
+ mova [tmpq+10*%%str], m13 ; t13
+ mova [tmpq+ 6*%%str], m14 ; t14
+ mova [tmpq+ 2*%%str], m15 ; t15
+%endif
+
+ mova m0, [tmpq+ 30*%%str]
+ UNSCRATCH 1, 6, tmpq+26*%%str
+ UNSCRATCH 2, 8, tmpq+24*%%str
+ UNSCRATCH 3, 9, tmpq+28*%%str
+ SUMSUB_BA w, 1, 3, 4 ; t6, t9
+ SUMSUB_BA w, 0, 2, 4 ; t7, t8
+
+ mova [tmpq+24*%%str], m1 ; t6
+ mova [tmpq+28*%%str], m0 ; t7
+ mova [tmpq+30*%%str], m2 ; t8
+ mova [tmpq+26*%%str], m3 ; t9
+
+ ; then, secondly, do t16-31
+%if %3 <= 8
+ mova m4, [%1+ 1*64]
+ mova m7, [%1+ 7*64]
+
+ pmulhrsw m1, m4, [pw_16364x2] ;t31
+ pmulhrsw m4, [pw_804x2] ;t16
+
+ VP9_UNPACK_MULSUB_2W_4X 5, 0, 1, 4, 16069, 3196, [pd_8192], 6, 2 ; t17, t30
+
+ pmulhrsw m3, m7, [pw_m5520x2] ;t19
+ pmulhrsw m7, [pw_15426x2] ;t28
+
+ SCRATCH 4, 13, tmpq+ 1*%%str
+ SCRATCH 5, 12, tmpq+15*%%str
+
+ VP9_UNPACK_MULSUB_2W_4X 2, 6, 7, 3, 3196, m16069, [pd_8192], 4, 5 ; t18, t29
+%else
+ mova m0, [%1+ 1*64]
+ mova m1, [%1+15*64]
+%if %3 <= 16
+ pmulhrsw m5, m0, [pw_16364x2]
+ pmulhrsw m0, [pw_804x2]
+ pmulhrsw m4, m1, [pw_m11003x2]
+ pmulhrsw m1, [pw_12140x2]
+%else
+ mova m4, [%1+17*64]
+ mova m5, [%1+31*64]
+
+ VP9_UNPACK_MULSUB_2W_4X 0, 5, 16364, 804, [pd_8192], 2, 3 ; t16, t31
+ VP9_UNPACK_MULSUB_2W_4X 4, 1, 11003, 12140, [pd_8192], 2, 3 ; t17, t30
+%endif
+ SUMSUB_BA w, 4, 0, 2
+ SUMSUB_BA w, 1, 5, 2
+
+ VP9_UNPACK_MULSUB_2W_4X 5, 0, 16069, 3196, [pd_8192], 2, 3 ; t17, t30
+
+ SCRATCH 4, 13, tmpq+ 1*%%str
+ SCRATCH 5, 12, tmpq+15*%%str
+
+ mova m2, [%1+ 7*64]
+ mova m3, [%1+ 9*64]
+%if %3 <= 16
+ pmulhrsw m7, m3, [pw_14811x2]
+ pmulhrsw m3, [pw_7005x2]
+ pmulhrsw m6, m2, [pw_m5520x2]
+ pmulhrsw m2, [pw_15426x2]
+%else
+ mova m7, [%1+23*64]
+ mova m6, [%1+25*64]
+
+ VP9_UNPACK_MULSUB_2W_4X 3, 7, 14811, 7005, [pd_8192], 4, 5 ; t18, t29
+ VP9_UNPACK_MULSUB_2W_4X 6, 2, 5520, 15426, [pd_8192], 4, 5 ; t19, t28
+%endif
+ SUMSUB_BA w, 3, 6, 4
+ SUMSUB_BA w, 7, 2, 4
+
+ VP9_UNPACK_MULSUB_2W_4X 2, 6, 3196, m16069, [pd_8192], 4, 5 ; t18, t29
+%endif
+
+ UNSCRATCH 5, 12, tmpq+15*%%str
+ SUMSUB_BA w, 6, 0, 4
+ mova [tmpq+25*%%str], m6 ; t19
+ UNSCRATCH 4, 13, tmpq+ 1*%%str
+ SUMSUB_BA w, 7, 1, 6
+ SUMSUB_BA w, 3, 4, 6
+ mova [tmpq+23*%%str], m3 ; t16
+ SUMSUB_BA w, 2, 5, 6
+
+ VP9_UNPACK_MULSUB_2W_4X 0, 5, 15137, 6270, [pd_8192], 6, 3 ; t18, t29
+ VP9_UNPACK_MULSUB_2W_4X 1, 4, 15137, 6270, [pd_8192], 6, 3 ; t19, t28
+
+ SCRATCH 0, 10, tmpq+ 1*%%str
+ SCRATCH 1, 11, tmpq+ 7*%%str
+ SCRATCH 2, 9, tmpq+ 9*%%str
+ SCRATCH 4, 14, tmpq+15*%%str
+ SCRATCH 5, 15, tmpq+17*%%str
+ SCRATCH 7, 13, tmpq+31*%%str
+
+%if %3 <= 8
+ mova m0, [%1+ 5*64]
+ mova m3, [%1+ 3*64]
+
+ pmulhrsw m5, m0, [pw_15893x2] ;t27
+ pmulhrsw m0, [pw_3981x2] ;t20
+
+ VP9_UNPACK_MULSUB_2W_4X 1, 4, 5, 0, 9102, 13623, [pd_8192], 7, 2 ; t21, t26
+
+ pmulhrsw m6, m3, [pw_m2404x2] ;t23
+ pmulhrsw m3, [pw_16207x2] ;t24
+
+ SCRATCH 5, 8, tmpq+ 5*%%str
+ SCRATCH 4, 12, tmpq+11*%%str
+
+ VP9_UNPACK_MULSUB_2W_4X 7, 2, 3, 6, 13623, m9102, [pd_8192], 4, 5 ; t22, t25
+%else
+ mova m4, [%1+ 5*64]
+ mova m5, [%1+11*64]
+%if %3 <= 16
+ pmulhrsw m1, m4, [pw_15893x2]
+ pmulhrsw m4, [pw_3981x2]
+ pmulhrsw m0, m5, [pw_m8423x2]
+ pmulhrsw m5, [pw_14053x2]
+%else
+ mova m0, [%1+21*64]
+ mova m1, [%1+27*64]
+
+ VP9_UNPACK_MULSUB_2W_4X 4, 1, 15893, 3981, [pd_8192], 2, 3 ; t20, t27
+ VP9_UNPACK_MULSUB_2W_4X 0, 5, 8423, 14053, [pd_8192], 2, 3 ; t21, t26
+%endif
+ SUMSUB_BA w, 0, 4, 2
+ SUMSUB_BA w, 5, 1, 2
+
+ VP9_UNPACK_MULSUB_2W_4X 1, 4, 9102, 13623, [pd_8192], 2, 3 ; t21, t26
+
+ SCRATCH 5, 8, tmpq+ 5*%%str
+ SCRATCH 4, 12, tmpq+11*%%str
+
+ mova m7, [%1+ 3*64]
+ mova m6, [%1+13*64]
+%if %3 <= 16
+ pmulhrsw m3, m6, [pw_13160x2]
+ pmulhrsw m6, [pw_9760x2]
+ pmulhrsw m2, m7, [pw_m2404x2]
+ pmulhrsw m7, [pw_16207x2]
+%else
+ mova m2, [%1+29*64]
+ mova m3, [%1+19*64]
+ VP9_UNPACK_MULSUB_2W_4X 6, 3, 13160, 9760, [pd_8192], 4, 5 ; t22, t25
+ VP9_UNPACK_MULSUB_2W_4X 2, 7, 2404, 16207, [pd_8192], 4, 5 ; t23, t24
+%endif
+ SUMSUB_BA w, 6, 2, 4
+ SUMSUB_BA w, 3, 7, 4
+
+ VP9_UNPACK_MULSUB_2W_4X 7, 2, 13623, m9102, [pd_8192], 4, 5 ; t22, t25
+%endif
+
+ ; m4=t16, m5=t17, m9=t18, m8=t19, m0=t20, m1=t21, m13=t22, m12=t23,
+ ; m3=t24, m2=t25, m14=t26, m15=t27, m7=t28, m6=t29, m10=t30, m11=t31
+
+ UNSCRATCH 4, 12, tmpq+11*%%str
+ SUMSUB_BA w, 0, 6, 5
+ SUMSUB_BA w, 4, 2, 5
+ UNSCRATCH 5, 8, tmpq+ 5*%%str
+ SCRATCH 4, 8, tmpq+11*%%str
+ SUMSUB_BA w, 1, 7, 4
+ SUMSUB_BA w, 5, 3, 4
+ SCRATCH 5, 12, tmpq+ 5*%%str
+
+ VP9_UNPACK_MULSUB_2W_4X 3, 6, 6270, m15137, [pd_8192], 4, 5 ; t20, t27
+ VP9_UNPACK_MULSUB_2W_4X 2, 7, 6270, m15137, [pd_8192], 4, 5 ; t21, t26
+
+ ; m8[s]=t16, m9=t17, m5=t18, m4[s]=t19, m12=t20, m13=t21, m1=t22, m0=t23,
+ ; m15=t24, m14=t25, m2=t26, m3=t27, m11=t28, m10=t29, m6=t30, m7=t31
+
+ UNSCRATCH 5, 9, tmpq+ 9*%%str
+ mova m4, [tmpq+23*%%str] ; t16
+%if ARCH_X86_64
+ SUMSUB_BA w, 1, 5, 9
+ SUMSUB_BA w, 0, 4, 9
+%else
+ SUMSUB_BADC w, 1, 5, 0, 4
+%endif
+ mova [tmpq+29*%%str], m1 ; t17
+ mova [tmpq+21*%%str], m0 ; t16
+ UNSCRATCH 0, 10, tmpq+ 1*%%str
+ UNSCRATCH 1, 11, tmpq+ 7*%%str
+%if ARCH_X86_64
+ SUMSUB_BA w, 2, 0, 9
+ SUMSUB_BA w, 3, 1, 9
+%else
+ SUMSUB_BADC w, 2, 0, 3, 1
+%endif
+ mova [tmpq+ 9*%%str], m2 ; t18
+ mova [tmpq+13*%%str], m3 ; t19
+ SCRATCH 0, 10, tmpq+23*%%str
+ SCRATCH 1, 11, tmpq+27*%%str
+
+ UNSCRATCH 2, 14, tmpq+15*%%str
+ UNSCRATCH 3, 15, tmpq+17*%%str
+ SUMSUB_BA w, 6, 2, 0
+ SUMSUB_BA w, 7, 3, 0
+ SCRATCH 6, 14, tmpq+ 3*%%str
+ SCRATCH 7, 15, tmpq+ 7*%%str
+
+ UNSCRATCH 0, 8, tmpq+11*%%str
+ mova m1, [tmpq+25*%%str] ; t19
+ UNSCRATCH 6, 12, tmpq+ 5*%%str
+ UNSCRATCH 7, 13, tmpq+31*%%str
+%if ARCH_X86_64
+ SUMSUB_BA w, 0, 1, 9
+ SUMSUB_BA w, 6, 7, 9
+%else
+ SUMSUB_BADC w, 0, 1, 6, 7
+%endif
+
+ ; m0=t16, m1=t17, m2=t18, m3=t19, m11=t20, m10=t21, m9=t22, m8=t23,
+ ; m7=t24, m6=t25, m5=t26, m4=t27, m12=t28, m13=t29, m14=t30, m15=t31
+
+%if 0; cpuflag(ssse3)
+%if ARCH_X86_64
+ SUMSUB_BA w, 4, 7, 8
+ SUMSUB_BA w, 5, 1, 8
+%else
+ SUMSUB_BADC w, 4, 7, 5, 1
+%endif
+
+ pmulhrsw m7, [pw_11585x2]
+ pmulhrsw m4, [pw_11585x2]
+ pmulhrsw m1, [pw_11585x2]
+ pmulhrsw m5, [pw_11585x2]
+
+ mova [tmpq+ 5*%%str], m7 ; t23
+ SCRATCH 1, 13, tmpq+25*%%str
+ UNSCRATCH 7, 10, tmpq+23*%%str
+ UNSCRATCH 1, 11, tmpq+27*%%str
+
+%if ARCH_X86_64
+ SUMSUB_BA w, 7, 3, 10
+ SUMSUB_BA w, 1, 2, 10
+%else
+ SUMSUB_BADC w, 7, 3, 1, 2
+%endif
+
+ pmulhrsw m3, [pw_11585x2]
+ pmulhrsw m7, [pw_11585x2]
+ pmulhrsw m2, [pw_11585x2]
+ pmulhrsw m1, [pw_11585x2]
+%else
+ SCRATCH 0, 8, tmpq+15*%%str
+ SCRATCH 6, 9, tmpq+17*%%str
+ VP9_UNPACK_MULSUB_2W_4X 7, 4, 11585, 11585, [pd_8192], 0, 6
+ mova [tmpq+ 5*%%str], m7 ; t23
+ UNSCRATCH 7, 10, tmpq+23*%%str
+ VP9_UNPACK_MULSUB_2W_4X 1, 5, 11585, 11585, [pd_8192], 0, 6
+ SCRATCH 1, 13, tmpq+25*%%str
+ UNSCRATCH 1, 11, tmpq+27*%%str
+ VP9_UNPACK_MULSUB_2W_4X 3, 7, 11585, 11585, [pd_8192], 0, 6
+ VP9_UNPACK_MULSUB_2W_4X 2, 1, 11585, 11585, [pd_8192], 0, 6
+ UNSCRATCH 0, 8, tmpq+15*%%str
+ UNSCRATCH 6, 9, tmpq+17*%%str
+%endif
+
+ ; m0=t16, m1=t17, m2=t18, m3=t19, m4=t20, m5=t21, m6=t22, m7=t23,
+ ; m8=t24, m9=t25, m10=t26, m11=t27, m12=t28, m13=t29, m14=t30, m15=t31
+
+ ; then do final pass to sumsub+store the two halves
+%if %2 == 1
+ mova [tmpq+17*%%str], m2 ; t20
+ mova [tmpq+ 1*%%str], m3 ; t21
+%if ARCH_X86_64
+ mova [tmpq+25*%%str], m13 ; t22
+
+ mova m8, [tmpq+ 0*%%str] ; t0
+ mova m9, [tmpq+ 4*%%str] ; t1
+ mova m12, [tmpq+ 8*%%str] ; t2
+ mova m11, [tmpq+12*%%str] ; t3
+ mova m2, [tmpq+16*%%str] ; t4
+ mova m3, [tmpq+20*%%str] ; t5
+ mova m13, [tmpq+24*%%str] ; t6
+
+ SUMSUB_BA w, 6, 8, 10
+ mova [tmpq+ 3*%%str], m8 ; t15
+ mova m10, [tmpq+28*%%str] ; t7
+ SUMSUB_BA w, 0, 9, 8
+ SUMSUB_BA w, 15, 12, 8
+ SUMSUB_BA w, 14, 11, 8
+ SUMSUB_BA w, 1, 2, 8
+ SUMSUB_BA w, 7, 3, 8
+ SUMSUB_BA w, 5, 13, 8
+ SUMSUB_BA w, 4, 10, 8
+
+ TRANSPOSE8x8W 6, 0, 15, 14, 1, 7, 5, 4, 8
+ mova [tmpq+ 0*%%str], m6
+ mova [tmpq+ 4*%%str], m0
+ mova [tmpq+ 8*%%str], m15
+ mova [tmpq+12*%%str], m14
+ mova [tmpq+16*%%str], m1
+ mova [tmpq+20*%%str], m7
+ mova [tmpq+24*%%str], m5
+ mova [tmpq+28*%%str], m4
+
+ mova m8, [tmpq+ 3*%%str] ; t15
+ TRANSPOSE8x8W 10, 13, 3, 2, 11, 12, 9, 8, 0
+ mova [tmpq+ 3*%%str], m10
+ mova [tmpq+ 7*%%str], m13
+ mova [tmpq+11*%%str], m3
+ mova [tmpq+15*%%str], m2
+ mova [tmpq+19*%%str], m11
+ mova [tmpq+23*%%str], m12
+ mova [tmpq+27*%%str], m9
+ mova [tmpq+31*%%str], m8
+
+ mova m15, [tmpq+30*%%str] ; t8
+ mova m14, [tmpq+26*%%str] ; t9
+ mova m13, [tmpq+22*%%str] ; t10
+ mova m12, [tmpq+18*%%str] ; t11
+ mova m11, [tmpq+14*%%str] ; t12
+ mova m10, [tmpq+10*%%str] ; t13
+ mova m9, [tmpq+ 6*%%str] ; t14
+ mova m8, [tmpq+ 2*%%str] ; t15
+ mova m7, [tmpq+21*%%str] ; t16
+ mova m6, [tmpq+29*%%str] ; t17
+ mova m5, [tmpq+ 9*%%str] ; t18
+ mova m4, [tmpq+13*%%str] ; t19
+ mova m3, [tmpq+17*%%str] ; t20
+ mova m2, [tmpq+ 1*%%str] ; t21
+ mova m1, [tmpq+25*%%str] ; t22
+
+ SUMSUB_BA w, 7, 8, 0
+ mova [tmpq+ 2*%%str], m8
+ mova m0, [tmpq+ 5*%%str] ; t23
+ SUMSUB_BA w, 6, 9, 8
+ SUMSUB_BA w, 5, 10, 8
+ SUMSUB_BA w, 4, 11, 8
+ SUMSUB_BA w, 3, 12, 8
+ SUMSUB_BA w, 2, 13, 8
+ SUMSUB_BA w, 1, 14, 8
+ SUMSUB_BA w, 0, 15, 8
+
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, 8
+ mova [tmpq+ 1*%%str], m0
+ mova [tmpq+ 5*%%str], m1
+ mova [tmpq+ 9*%%str], m2
+ mova [tmpq+13*%%str], m3
+ mova [tmpq+17*%%str], m4
+ mova [tmpq+21*%%str], m5
+ mova [tmpq+25*%%str], m6
+ mova [tmpq+29*%%str], m7
+
+ mova m8, [tmpq+ 2*%%str]
+ TRANSPOSE8x8W 8, 9, 10, 11, 12, 13, 14, 15, 0
+ mova [tmpq+ 2*%%str], m8
+ mova [tmpq+ 6*%%str], m9
+ mova [tmpq+10*%%str], m10
+ mova [tmpq+14*%%str], m11
+ mova [tmpq+18*%%str], m12
+ mova [tmpq+22*%%str], m13
+ mova [tmpq+26*%%str], m14
+ mova [tmpq+30*%%str], m15
+%else
+ mova m2, [tmpq+24*%%str] ; t6
+ mova m3, [tmpq+28*%%str] ; t7
+ SUMSUB_BADC w, 5, 2, 4, 3
+ mova [tmpq+24*%%str], m5
+ mova [tmpq+23*%%str], m2
+ mova [tmpq+28*%%str], m4
+ mova [tmpq+19*%%str], m3
+
+ mova m2, [tmpq+16*%%str] ; t4
+ mova m3, [tmpq+20*%%str] ; t5
+ SUMSUB_BA w, 1, 2, 5
+ SUMSUB_BA w, 7, 3, 5
+ mova [tmpq+15*%%str], m2
+ mova [tmpq+11*%%str], m3
+
+ mova m2, [tmpq+ 0*%%str] ; t0
+ mova m3, [tmpq+ 4*%%str] ; t1
+ SUMSUB_BA w, 6, 2, 5
+ SUMSUB_BA w, 0, 3, 5
+ mova [tmpq+31*%%str], m2
+ mova [tmpq+27*%%str], m3
+
+ mova m2, [tmpq+ 8*%%str] ; t2
+ mova m3, [tmpq+12*%%str] ; t3
+ mova m5, [tmpq+ 7*%%str]
+ mova m4, [tmpq+ 3*%%str]
+ SUMSUB_BADC w, 5, 2, 4, 3
+ mova [tmpq+ 7*%%str], m2
+ mova [tmpq+ 3*%%str], m3
+
+ mova m3, [tmpq+28*%%str]
+ TRANSPOSE8x8W 6, 0, 5, 4, 1, 7, 2, 3, [tmpq+24*%%str], [tmpq+16*%%str], 1
+ mova [tmpq+ 0*%%str], m6
+ mova [tmpq+ 4*%%str], m0
+ mova [tmpq+ 8*%%str], m5
+ mova [tmpq+12*%%str], m4
+ mova [tmpq+20*%%str], m7
+ mova [tmpq+24*%%str], m2
+ mova [tmpq+28*%%str], m3
+
+ mova m6, [tmpq+19*%%str]
+ mova m0, [tmpq+23*%%str]
+ mova m5, [tmpq+11*%%str]
+ mova m4, [tmpq+15*%%str]
+ mova m1, [tmpq+ 3*%%str]
+ mova m7, [tmpq+ 7*%%str]
+ mova m3, [tmpq+31*%%str]
+ TRANSPOSE8x8W 6, 0, 5, 4, 1, 7, 2, 3, [tmpq+27*%%str], [tmpq+19*%%str], 1
+ mova [tmpq+ 3*%%str], m6
+ mova [tmpq+ 7*%%str], m0
+ mova [tmpq+11*%%str], m5
+ mova [tmpq+15*%%str], m4
+ mova [tmpq+23*%%str], m7
+ mova [tmpq+27*%%str], m2
+ mova [tmpq+31*%%str], m3
+
+ mova m1, [tmpq+ 6*%%str] ; t14
+ mova m0, [tmpq+ 2*%%str] ; t15
+ mova m7, [tmpq+21*%%str] ; t16
+ mova m6, [tmpq+29*%%str] ; t17
+ SUMSUB_BA w, 7, 0, 2
+ SUMSUB_BA w, 6, 1, 2
+ mova [tmpq+29*%%str], m7
+ mova [tmpq+ 2*%%str], m0
+ mova [tmpq+21*%%str], m6
+ mova [tmpq+ 6*%%str], m1
+
+ mova m1, [tmpq+14*%%str] ; t12
+ mova m0, [tmpq+10*%%str] ; t13
+ mova m5, [tmpq+ 9*%%str] ; t18
+ mova m4, [tmpq+13*%%str] ; t19
+ SUMSUB_BA w, 5, 0, 2
+ SUMSUB_BA w, 4, 1, 2
+ mova [tmpq+10*%%str], m0
+ mova [tmpq+14*%%str], m1
+
+ mova m1, [tmpq+22*%%str] ; t10
+ mova m0, [tmpq+18*%%str] ; t11
+ mova m3, [tmpq+17*%%str] ; t20
+ mova m2, [tmpq+ 1*%%str] ; t21
+ SUMSUB_BA w, 3, 0, 6
+ SUMSUB_BA w, 2, 1, 6
+ mova [tmpq+18*%%str], m0
+ mova [tmpq+22*%%str], m1
+
+ mova m7, [tmpq+30*%%str] ; t8
+ mova m6, [tmpq+26*%%str] ; t9
+ mova m1, [tmpq+25*%%str] ; t22
+ mova m0, [tmpq+ 5*%%str] ; t23
+ SUMSUB_BADC w, 1, 6, 0, 7
+ mova [tmpq+26*%%str], m6
+ mova [tmpq+30*%%str], m7
+
+ mova m7, [tmpq+29*%%str]
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [tmpq+21*%%str], [tmpq+17*%%str], 1
+ mova [tmpq+ 1*%%str], m0
+ mova [tmpq+ 5*%%str], m1
+ mova [tmpq+ 9*%%str], m2
+ mova [tmpq+13*%%str], m3
+ mova [tmpq+21*%%str], m5
+ mova [tmpq+25*%%str], m6
+ mova [tmpq+29*%%str], m7
+
+ mova m0, [tmpq+ 2*%%str]
+ mova m1, [tmpq+ 6*%%str]
+ mova m2, [tmpq+10*%%str]
+ mova m3, [tmpq+14*%%str]
+ mova m4, [tmpq+18*%%str]
+ mova m5, [tmpq+22*%%str]
+ mova m7, [tmpq+30*%%str]
+ TRANSPOSE8x8W 0, 1, 2, 3, 4, 5, 6, 7, [tmpq+26*%%str], [tmpq+18*%%str], 1
+ mova [tmpq+ 2*%%str], m0
+ mova [tmpq+ 6*%%str], m1
+ mova [tmpq+10*%%str], m2
+ mova [tmpq+14*%%str], m3
+ mova [tmpq+22*%%str], m5
+ mova [tmpq+26*%%str], m6
+ mova [tmpq+30*%%str], m7
+%endif
+%else
+ ; t0-7 is in [tmpq+{0,4,8,12,16,20,24,28}*%%str]
+ ; t8-15 is in [tmpq+{2,6,10,14,18,22,26,30}*%%str]
+ ; t16-19 and t23 is in [tmpq+{1,5,9,13,29}*%%str]
+ ; t20-22 is in m4-6
+ ; t24-31 is in m8-15
+
+%if cpuflag(ssse3)
+%define ROUND_REG [pw_512]
+%else
+%define ROUND_REG [pw_32]
+%endif
+
+%macro %%STORE_2X2 7-8 1 ; src[1-4], tmp[1-2], zero, inc_dst_ptrs
+ SUMSUB_BA w, %4, %1, %5
+ SUMSUB_BA w, %3, %2, %5
+ VP9_IDCT8_WRITEx2 %4, %3, %5, %6, %7, ROUND_REG, 6
+%if %8 == 1
+ add dstq, stride2q
+%endif
+ VP9_IDCT8_WRITEx2 %2, %1, %5, %6, %7, ROUND_REG, 6, dst_endq
+%if %8 == 1
+ sub dst_endq, stride2q
+%endif
+%endmacro
+
+%if ARCH_X86_64
+ pxor m10, m10
+
+ ; store t0-1 and t30-31
+ mova m8, [tmpq+ 0*%%str]
+ mova m9, [tmpq+ 4*%%str]
+ %%STORE_2X2 8, 9, 0, 6, 12, 11, 10
+
+ ; store t2-3 and t28-29
+ mova m8, [tmpq+ 8*%%str]
+ mova m9, [tmpq+12*%%str]
+ %%STORE_2X2 8, 9, 14, 15, 12, 11, 10
+
+ ; store t4-5 and t26-27
+ mova m8, [tmpq+16*%%str]
+ mova m9, [tmpq+20*%%str]
+ %%STORE_2X2 8, 9, 7, 1, 12, 11, 10
+
+ ; store t6-7 and t24-25
+ mova m8, [tmpq+24*%%str]
+ mova m9, [tmpq+28*%%str]
+ %%STORE_2X2 8, 9, 4, 5, 12, 11, 10
+
+ ; store t8-9 and t22-23
+ mova m8, [tmpq+30*%%str]
+ mova m9, [tmpq+26*%%str]
+ mova m0, [tmpq+ 5*%%str]
+ %%STORE_2X2 8, 9, 13, 0, 12, 11, 10
+
+ ; store t10-11 and t20-21
+ mova m8, [tmpq+22*%%str]
+ mova m9, [tmpq+18*%%str]
+ %%STORE_2X2 8, 9, 2, 3, 12, 11, 10
+
+ ; store t12-13 and t18-19
+ mova m8, [tmpq+14*%%str]
+ mova m9, [tmpq+10*%%str]
+ mova m5, [tmpq+13*%%str]
+ mova m4, [tmpq+ 9*%%str]
+ %%STORE_2X2 8, 9, 4, 5, 12, 11, 10
+
+ ; store t14-17
+ mova m8, [tmpq+ 6*%%str]
+ mova m9, [tmpq+ 2*%%str]
+ mova m5, [tmpq+29*%%str]
+ mova m4, [tmpq+21*%%str]
+ %%STORE_2X2 8, 9, 4, 5, 12, 11, 10, 0
+
+ SWAP 1, 10 ; zero
+%else
+ mova [tmpq+ 1*%%str], m1
+ mova [tmpq+11*%%str], m2
+ mova [tmpq+15*%%str], m3
+ mova [tmpq+17*%%str], m4
+ mova [tmpq+19*%%str], m5
+ pxor m1, m1
+
+ ; store t0-1 and t30-31
+ mova m2, [tmpq+ 0*%%str]
+ mova m3, [tmpq+ 4*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1
+
+ ; store t2-3 and t28-29
+ mova m2, [tmpq+ 8*%%str]
+ mova m3, [tmpq+12*%%str]
+ mova m0, [tmpq+ 3*%%str]
+ mova m6, [tmpq+ 7*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1
+
+ ; store t4-5 and t26-27
+ mova m2, [tmpq+16*%%str]
+ mova m3, [tmpq+20*%%str]
+ mova m0, [tmpq+ 1*%%str]
+ %%STORE_2X2 2, 3, 7, 0, 4, 5, 1
+
+ ; store t6-7 and t24-25
+ mova m2, [tmpq+24*%%str]
+ mova m3, [tmpq+28*%%str]
+ mova m0, [tmpq+17*%%str]
+ mova m6, [tmpq+19*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1
+
+ ; store t8-9 and t22-23
+ mova m2, [tmpq+30*%%str]
+ mova m3, [tmpq+26*%%str]
+ mova m0, [tmpq+25*%%str]
+ mova m6, [tmpq+ 5*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1
+
+ ; store t10-11 and t20-21
+ mova m2, [tmpq+22*%%str]
+ mova m3, [tmpq+18*%%str]
+ mova m0, [tmpq+11*%%str]
+ mova m6, [tmpq+15*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1
+
+ ; store t12-13 and t18-19
+ mova m2, [tmpq+14*%%str]
+ mova m3, [tmpq+10*%%str]
+ mova m6, [tmpq+13*%%str]
+ mova m0, [tmpq+ 9*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1
+
+ ; store t14-17
+ mova m2, [tmpq+ 6*%%str]
+ mova m3, [tmpq+ 2*%%str]
+ mova m6, [tmpq+29*%%str]
+ mova m0, [tmpq+21*%%str]
+ %%STORE_2X2 2, 3, 0, 6, 4, 5, 1, 0
+%endif
+%undef ROUND_REG
+%endif
+%endmacro
+
+%macro VP9_IDCT_IDCT_32x32_ADD_XMM 1
+INIT_XMM %1
+cglobal vp9_idct_idct_32x32_add, 0, 6 + ARCH_X86_64 * 3, 16, 2048, dst, stride, block, eob
+ movifnidn eobd, dword eobm
+%if cpuflag(ssse3)
+ cmp eobd, 135
+ jg .idctfull
+ cmp eobd, 34
+ jg .idct16x16
+ cmp eobd, 1
+ jg .idct8x8
+%else
+ cmp eobd, 1
+ jg .idctfull
+%endif
+
+ ; dc-only case
+ movifnidn blockq, blockmp
+ movifnidn dstq, dstmp
+ movifnidn strideq, stridemp
+%if cpuflag(ssse3)
+ movd m0, [blockq]
+ mova m1, [pw_11585x2]
+ pmulhrsw m0, m1
+ pmulhrsw m0, m1
+%else
+ DEFINE_ARGS dst, stride, block, coef
+ movsx coefd, word [blockq]
+ imul coefd, 11585
+ add coefd, 8192
+ sar coefd, 14
+ imul coefd, 11585
+ add coefd, (32 << 14) + 8192
+ sar coefd, 14 + 6
+ movd m0, coefd
+%endif
+ SPLATW m0, m0, q0000
+%if cpuflag(ssse3)
+ pmulhrsw m0, [pw_512]
+%endif
+ pxor m5, m5
+ movd [blockq], m5
+%rep 31
+ VP9_STORE_2XFULL 0, 1, 2, 3, 4, 5, mmsize
+ add dstq, strideq
+%endrep
+ VP9_STORE_2XFULL 0, 1, 2, 3, 4, 5, mmsize
+ RET
+
+%if ARCH_X86_64
+ DEFINE_ARGS dst_bak, stride, block, cnt, dst, stride30, dst_end, stride2, tmp
+%else
+%define dst_bakq r0mp
+%endif
+%if cpuflag(ssse3)
+.idct8x8:
+%if ARCH_X86_32
+ DEFINE_ARGS block, u1, u2, u3, u4, tmp
+ mov blockq, r2mp
+%endif
+ mov tmpq, rsp
+ VP9_IDCT32_1D blockq, 1, 8
+
+%if ARCH_X86_32
+ DEFINE_ARGS dst, stride, stride30, dst_end, stride2, tmp
+ mov strideq, r1mp
+%define cntd dword r3m
+%endif
+ mov stride30q, strideq ; stride
+ lea stride2q, [strideq*2] ; stride*2
+ shl stride30q, 5 ; stride*32
+ mov cntd, 4
+ sub stride30q, stride2q ; stride*30
+.loop2_8x8:
+ mov dstq, dst_bakq
+ lea dst_endq, [dstq+stride30q]
+ VP9_IDCT32_1D tmpq, 2, 8
+ add dst_bakq, 8
+ add tmpq, 16
+ dec cntd
+ jg .loop2_8x8
+
+ ; at the end of the loop, m7 should still be zero
+ ; use that to zero out block coefficients
+%if ARCH_X86_32
+ DEFINE_ARGS block
+ mov blockq, r2mp
+%endif
+ ZERO_BLOCK blockq, 64, 8, m1
+ RET
+
+.idct16x16:
+%if ARCH_X86_32
+ DEFINE_ARGS block, tmp, cnt
+ mov blockq, r2mp
+%endif
+ mov cntd, 2
+ mov tmpq, rsp
+.loop1_16x16:
+ VP9_IDCT32_1D blockq, 1, 16
+ add blockq, 16
+ add tmpq, 512
+ dec cntd
+ jg .loop1_16x16
+
+%if ARCH_X86_64
+ sub blockq, 32
+%else
+ DEFINE_ARGS dst, stride, stride30, dst_end, stride2, tmp
+ mov strideq, r1mp
+%define cntd dword r3m
+%endif
+
+ mov stride30q, strideq ; stride
+ lea stride2q, [strideq*2] ; stride*2
+ shl stride30q, 5 ; stride*32
+ mov cntd, 4
+ mov tmpq, rsp
+ sub stride30q, stride2q ; stride*30
+.loop2_16x16:
+ mov dstq, dst_bakq
+ lea dst_endq, [dstq+stride30q]
+ VP9_IDCT32_1D tmpq, 2, 16
+ add dst_bakq, 8
+ add tmpq, 16
+ dec cntd
+ jg .loop2_16x16
+
+ ; at the end of the loop, m7 should still be zero
+ ; use that to zero out block coefficients
+%if ARCH_X86_32
+ DEFINE_ARGS block
+ mov blockq, r2mp
+%endif
+ ZERO_BLOCK blockq, 64, 16, m1
+ RET
+%endif
+
+.idctfull:
+%if ARCH_X86_32
+ DEFINE_ARGS block, tmp, cnt
+ mov blockq, r2mp
+%endif
+ mov cntd, 4
+ mov tmpq, rsp
+.loop1_full:
+ VP9_IDCT32_1D blockq, 1
+ add blockq, 16
+ add tmpq, 512
+ dec cntd
+ jg .loop1_full
+
+%if ARCH_X86_64
+ sub blockq, 64
+%else
+ DEFINE_ARGS dst, stride, stride30, dst_end, stride2, tmp
+ mov strideq, r1mp
+%define cntd dword r3m
+%endif
+
+ mov stride30q, strideq ; stride
+ lea stride2q, [strideq*2] ; stride*2
+ shl stride30q, 5 ; stride*32
+ mov cntd, 4
+ mov tmpq, rsp
+ sub stride30q, stride2q ; stride*30
+.loop2_full:
+ mov dstq, dst_bakq
+ lea dst_endq, [dstq+stride30q]
+ VP9_IDCT32_1D tmpq, 2
+ add dst_bakq, 8
+ add tmpq, 16
+ dec cntd
+ jg .loop2_full
+
+ ; at the end of the loop, m7 should still be zero
+ ; use that to zero out block coefficients
+%if ARCH_X86_32
+ DEFINE_ARGS block
+ mov blockq, r2mp
+%endif
+ ZERO_BLOCK blockq, 64, 32, m1
+ RET
+%endmacro
+
+VP9_IDCT_IDCT_32x32_ADD_XMM sse2
+VP9_IDCT_IDCT_32x32_ADD_XMM ssse3
+VP9_IDCT_IDCT_32x32_ADD_XMM avx
diff --git a/libavcodec/x86/vp9lpf.asm b/libavcodec/x86/vp9lpf.asm
new file mode 100644
index 0000000000..2c4fe214da
--- /dev/null
+++ b/libavcodec/x86/vp9lpf.asm
@@ -0,0 +1,1139 @@
+;******************************************************************************
+;* VP9 loop filter SIMD optimizations
+;*
+;* Copyright (C) 2013-2014 ClĂ©ment BÅ“sch <u pkh me>
+;* Copyright (C) 2014 Ronald S. Bultje <rsbultje@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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+cextern pb_3
+cextern pb_80
+
+pb_4: times 16 db 0x04
+pb_10: times 16 db 0x10
+pb_40: times 16 db 0x40
+pb_81: times 16 db 0x81
+pb_f8: times 16 db 0xf8
+pb_fe: times 16 db 0xfe
+pb_ff: times 16 db 0xff
+
+cextern pw_4
+cextern pw_8
+
+; with mix functions, two 8-bit thresholds are stored in a 16-bit storage,
+; the following mask is used to splat both in the same register
+mask_mix: times 8 db 0
+ times 8 db 1
+
+mask_mix84: times 8 db 0xff
+ times 8 db 0x00
+mask_mix48: times 8 db 0x00
+ times 8 db 0xff
+
+SECTION .text
+
+%macro SCRATCH 3
+%if ARCH_X86_64
+ SWAP %1, %2
+%else
+ mova [%3], m%1
+%endif
+%endmacro
+
+%macro UNSCRATCH 3
+%if ARCH_X86_64
+ SWAP %1, %2
+%else
+ mova m%1, [%3]
+%endif
+%endmacro
+
+; %1 = abs(%2-%3)
+%macro ABSSUB 4 ; dst, src1 (RO), src2 (RO), tmp
+%if ARCH_X86_64
+ psubusb %1, %3, %2
+ psubusb %4, %2, %3
+%else
+ mova %1, %3
+ mova %4, %2
+ psubusb %1, %2
+ psubusb %4, %3
+%endif
+ por %1, %4
+%endmacro
+
+; %1 = %1>%2
+%macro CMP_GT 2-3 ; src/dst, cmp, pb_80
+%if %0 == 3
+ pxor %1, %3
+%endif
+ pcmpgtb %1, %2
+%endmacro
+
+; %1 = abs(%2-%3) > %4
+%macro ABSSUB_GT 5-6 [pb_80]; dst, src1, src2, cmp, tmp, [pb_80]
+ ABSSUB %1, %2, %3, %5 ; dst = abs(src1-src2)
+ CMP_GT %1, %4, %6 ; dst > cmp
+%endmacro
+
+%macro MASK_APPLY 4 ; %1=new_data/dst %2=old_data %3=mask %4=tmp
+ pand %1, %3 ; new &= mask
+ pandn %4, %3, %2 ; tmp = ~mask & old
+ por %1, %4 ; new&mask | old&~mask
+%endmacro
+
+%macro UNPACK 4
+%if ARCH_X86_64
+ punpck%1bw %2, %3, %4
+%else
+ mova %2, %3
+ punpck%1bw %2, %4
+%endif
+%endmacro
+
+%macro FILTER_SUBx2_ADDx2 11 ; %1=dst %2=h/l %3=cache %4=stack_off %5=sub1 %6=sub2 %7=add1
+ ; %8=add2 %9=rshift, [unpack], [unpack_is_mem_on_x86_32]
+ psubw %3, [rsp+%4+%5*32]
+ psubw %3, [rsp+%4+%6*32]
+ paddw %3, [rsp+%4+%7*32]
+%ifnidn %10, ""
+%if %11 == 0
+ punpck%2bw %1, %10, m0
+%else
+ UNPACK %2, %1, %10, m0
+%endif
+ mova [rsp+%4+%8*32], %1
+ paddw %3, %1
+%else
+ paddw %3, [rsp+%4+%8*32]
+%endif
+ psraw %1, %3, %9
+%endmacro
+
+; FIXME interleave l/h better (for instruction pairing)
+%macro FILTER_INIT 9 ; tmp1, tmp2, cacheL, cacheH, dstp, stack_off, filterid, mask, source
+ FILTER%7_INIT %1, l, %3, %6 + 0
+ FILTER%7_INIT %2, h, %4, %6 + 16
+ packuswb %1, %2
+ MASK_APPLY %1, %9, %8, %2
+ mova %5, %1
+%endmacro
+
+
+%macro FILTER_UPDATE 12-16 "", "", "", 0 ; tmp1, tmp2, cacheL, cacheH, dstp, stack_off, -, -, +, +, rshift,
+ ; mask, [source], [unpack + src], [unpack_is_mem_on_x86_32]
+; FIXME interleave this properly with the subx2/addx2
+%ifnidn %15, ""
+%if %16 == 0 || ARCH_X86_64
+ mova %14, %15
+%endif
+%endif
+ FILTER_SUBx2_ADDx2 %1, l, %3, %6 + 0, %7, %8, %9, %10, %11, %14, %16
+ FILTER_SUBx2_ADDx2 %2, h, %4, %6 + 16, %7, %8, %9, %10, %11, %14, %16
+ packuswb %1, %2
+%ifnidn %13, ""
+ MASK_APPLY %1, %13, %12, %2
+%else
+ MASK_APPLY %1, %5, %12, %2
+%endif
+ mova %5, %1
+%endmacro
+
+%macro SRSHIFT3B_2X 4 ; reg1, reg2, [pb_10], tmp
+ mova %4, [pb_f8]
+ pand %1, %4
+ pand %2, %4
+ psrlq %1, 3
+ psrlq %2, 3
+ pxor %1, %3
+ pxor %2, %3
+ psubb %1, %3
+ psubb %2, %3
+%endmacro
+
+%macro EXTRACT_POS_NEG 3 ; i8, neg, pos
+ pxor %3, %3
+ pxor %2, %2
+ pcmpgtb %3, %1 ; i8 < 0 mask
+ psubb %2, %1 ; neg values (only the originally - will be kept)
+ pand %2, %3 ; negative values of i8 (but stored as +)
+ pandn %3, %1 ; positive values of i8
+%endmacro
+
+; clip_u8(u8 + i8)
+%macro SIGN_ADD 4 ; dst, u8, i8, tmp1
+ EXTRACT_POS_NEG %3, %4, %1
+ paddusb %1, %2 ; add the positives
+ psubusb %1, %4 ; sub the negatives
+%endmacro
+
+; clip_u8(u8 - i8)
+%macro SIGN_SUB 4 ; dst, u8, i8, tmp1
+ EXTRACT_POS_NEG %3, %1, %4
+ paddusb %1, %2 ; add the negatives
+ psubusb %1, %4 ; sub the positives
+%endmacro
+
+%macro FILTER6_INIT 4 ; %1=dst %2=h/l %3=cache, %4=stack_off
+ UNPACK %2, %1, rp3, m0 ; p3: B->W
+ mova [rsp+%4+0*32], %1
+ paddw %3, %1, %1 ; p3*2
+ paddw %3, %1 ; p3*3
+ punpck%2bw %1, m1, m0 ; p2: B->W
+ mova [rsp+%4+1*32], %1
+ paddw %3, %1 ; p3*3 + p2
+ paddw %3, %1 ; p3*3 + p2*2
+ UNPACK %2, %1, rp1, m0 ; p1: B->W
+ mova [rsp+%4+2*32], %1
+ paddw %3, %1 ; p3*3 + p2*2 + p1
+ UNPACK %2, %1, rp0, m0 ; p0: B->W
+ mova [rsp+%4+3*32], %1
+ paddw %3, %1 ; p3*3 + p2*2 + p1 + p0
+ UNPACK %2, %1, rq0, m0 ; q0: B->W
+ mova [rsp+%4+4*32], %1
+ paddw %3, %1 ; p3*3 + p2*2 + p1 + p0 + q0
+ paddw %3, [pw_4] ; p3*3 + p2*2 + p1 + p0 + q0 + 4
+ psraw %1, %3, 3 ; (p3*3 + p2*2 + p1 + p0 + q0 + 4) >> 3
+%endmacro
+
+%macro FILTER14_INIT 4 ; %1=dst %2=h/l %3=cache, %4=stack_off
+ punpck%2bw %1, m2, m0 ; p7: B->W
+ mova [rsp+%4+ 8*32], %1
+ psllw %3, %1, 3 ; p7*8
+ psubw %3, %1 ; p7*7
+ punpck%2bw %1, m3, m0 ; p6: B->W
+ mova [rsp+%4+ 9*32], %1
+ paddw %3, %1 ; p7*7 + p6
+ paddw %3, %1 ; p7*7 + p6*2
+ UNPACK %2, %1, rp5, m0 ; p5: B->W
+ mova [rsp+%4+10*32], %1
+ paddw %3, %1 ; p7*7 + p6*2 + p5
+ UNPACK %2, %1, rp4, m0 ; p4: B->W
+ mova [rsp+%4+11*32], %1
+ paddw %3, %1 ; p7*7 + p6*2 + p5 + p4
+ paddw %3, [rsp+%4+ 0*32] ; p7*7 + p6*2 + p5 + p4 + p3
+ paddw %3, [rsp+%4+ 1*32] ; p7*7 + p6*2 + p5 + .. + p2
+ paddw %3, [rsp+%4+ 2*32] ; p7*7 + p6*2 + p5 + .. + p1
+ paddw %3, [rsp+%4+ 3*32] ; p7*7 + p6*2 + p5 + .. + p0
+ paddw %3, [rsp+%4+ 4*32] ; p7*7 + p6*2 + p5 + .. + p0 + q0
+ paddw %3, [pw_8] ; p7*7 + p6*2 + p5 + .. + p0 + q0 + 8
+ psraw %1, %3, 4 ; (p7*7 + p6*2 + p5 + .. + p0 + q0 + 8) >> 4
+%endmacro
+
+%macro TRANSPOSE16x16B 17
+ mova %17, m%16
+ SBUTTERFLY bw, %1, %2, %16
+ SBUTTERFLY bw, %3, %4, %16
+ SBUTTERFLY bw, %5, %6, %16
+ SBUTTERFLY bw, %7, %8, %16
+ SBUTTERFLY bw, %9, %10, %16
+ SBUTTERFLY bw, %11, %12, %16
+ SBUTTERFLY bw, %13, %14, %16
+ mova m%16, %17
+ mova %17, m%14
+ SBUTTERFLY bw, %15, %16, %14
+ SBUTTERFLY wd, %1, %3, %14
+ SBUTTERFLY wd, %2, %4, %14
+ SBUTTERFLY wd, %5, %7, %14
+ SBUTTERFLY wd, %6, %8, %14
+ SBUTTERFLY wd, %9, %11, %14
+ SBUTTERFLY wd, %10, %12, %14
+ SBUTTERFLY wd, %13, %15, %14
+ mova m%14, %17
+ mova %17, m%12
+ SBUTTERFLY wd, %14, %16, %12
+ SBUTTERFLY dq, %1, %5, %12
+ SBUTTERFLY dq, %2, %6, %12
+ SBUTTERFLY dq, %3, %7, %12
+ SBUTTERFLY dq, %4, %8, %12
+ SBUTTERFLY dq, %9, %13, %12
+ SBUTTERFLY dq, %10, %14, %12
+ SBUTTERFLY dq, %11, %15, %12
+ mova m%12, %17
+ mova %17, m%8
+ SBUTTERFLY dq, %12, %16, %8
+ SBUTTERFLY qdq, %1, %9, %8
+ SBUTTERFLY qdq, %2, %10, %8
+ SBUTTERFLY qdq, %3, %11, %8
+ SBUTTERFLY qdq, %4, %12, %8
+ SBUTTERFLY qdq, %5, %13, %8
+ SBUTTERFLY qdq, %6, %14, %8
+ SBUTTERFLY qdq, %7, %15, %8
+ mova m%8, %17
+ mova %17, m%1
+ SBUTTERFLY qdq, %8, %16, %1
+ mova m%1, %17
+ SWAP %2, %9
+ SWAP %3, %5
+ SWAP %4, %13
+ SWAP %6, %11
+ SWAP %8, %15
+ SWAP %12, %14
+%endmacro
+
+%macro TRANSPOSE8x8B 13
+ SBUTTERFLY bw, %1, %2, %7
+ movdq%10 m%7, %9
+ movdqa %11, m%2
+ SBUTTERFLY bw, %3, %4, %2
+ SBUTTERFLY bw, %5, %6, %2
+ SBUTTERFLY bw, %7, %8, %2
+ SBUTTERFLY wd, %1, %3, %2
+ movdqa m%2, %11
+ movdqa %11, m%3
+ SBUTTERFLY wd, %2, %4, %3
+ SBUTTERFLY wd, %5, %7, %3
+ SBUTTERFLY wd, %6, %8, %3
+ SBUTTERFLY dq, %1, %5, %3
+ SBUTTERFLY dq, %2, %6, %3
+ movdqa m%3, %11
+ movh %12, m%2
+ movhps %13, m%2
+ SBUTTERFLY dq, %3, %7, %2
+ SBUTTERFLY dq, %4, %8, %2
+ SWAP %2, %5
+ SWAP %4, %7
+%endmacro
+
+%macro DEFINE_REAL_P7_TO_Q7 0-1 0
+%define P7 dstq + 4*mstrideq + %1
+%define P6 dstq + mstride3q + %1
+%define P5 dstq + 2*mstrideq + %1
+%define P4 dstq + mstrideq + %1
+%define P3 dstq + %1
+%define P2 dstq + strideq + %1
+%define P1 dstq + 2* strideq + %1
+%define P0 dstq + stride3q + %1
+%define Q0 dstq + 4* strideq + %1
+%define Q1 dst2q + mstride3q + %1
+%define Q2 dst2q + 2*mstrideq + %1
+%define Q3 dst2q + mstrideq + %1
+%define Q4 dst2q + %1
+%define Q5 dst2q + strideq + %1
+%define Q6 dst2q + 2* strideq + %1
+%define Q7 dst2q + stride3q + %1
+%endmacro
+
+%macro DEFINE_TRANSPOSED_P7_TO_Q7 0-1 0
+%define P3 rsp + 0 + %1
+%define P2 rsp + 16 + %1
+%define P1 rsp + 32 + %1
+%define P0 rsp + 48 + %1
+%define Q0 rsp + 64 + %1
+%define Q1 rsp + 80 + %1
+%define Q2 rsp + 96 + %1
+%define Q3 rsp + 112 + %1
+%define P7 rsp + 128 + %1
+%define P6 rsp + 144 + %1
+%define P5 rsp + 160 + %1
+%define P4 rsp + 176 + %1
+%define Q4 rsp + 192 + %1
+%define Q5 rsp + 208 + %1
+%define Q6 rsp + 224 + %1
+%define Q7 rsp + 240 + %1
+%endmacro
+
+; ..............AB -> AAAAAAAABBBBBBBB
+%macro SPLATB_MIX 1-2 [mask_mix]
+%if cpuflag(ssse3)
+ pshufb %1, %2
+%else
+ punpcklbw %1, %1
+ punpcklwd %1, %1
+ punpckldq %1, %1
+%endif
+%endmacro
+
+%macro LOOPFILTER 5 ; %1=v/h %2=size1 %3+%4=stack, %5=32bit stack only
+%if UNIX64
+cglobal vp9_loop_filter_%1_%2_16, 5, 9, 16, %3 + %4, dst, stride, E, I, H, mstride, dst2, stride3, mstride3
+%else
+%if WIN64
+cglobal vp9_loop_filter_%1_%2_16, 4, 8, 16, %3 + %4, dst, stride, E, I, mstride, dst2, stride3, mstride3
+%else
+cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, dst2, stride3, mstride3
+%define Ed dword r2m
+%define Id dword r3m
+%endif
+%define Hd dword r4m
+%endif
+
+ mov mstrideq, strideq
+ neg mstrideq
+
+ lea stride3q, [strideq*3]
+ lea mstride3q, [mstrideq*3]
+
+%ifidn %1, h
+%if %2 > 16
+%define movx movh
+ lea dstq, [dstq + 4*strideq - 4]
+%else
+%define movx movu
+ lea dstq, [dstq + 4*strideq - 8] ; go from top center (h pos) to center left (v pos)
+%endif
+ lea dst2q, [dstq + 8*strideq]
+%else
+ lea dstq, [dstq + 4*mstrideq]
+ lea dst2q, [dstq + 8*strideq]
+%endif
+
+ DEFINE_REAL_P7_TO_Q7
+
+%ifidn %1, h
+ movx m0, [P7]
+ movx m1, [P6]
+ movx m2, [P5]
+ movx m3, [P4]
+ movx m4, [P3]
+ movx m5, [P2]
+%if ARCH_X86_64 || %2 != 16
+ movx m6, [P1]
+%endif
+ movx m7, [P0]
+%if ARCH_X86_64
+ movx m8, [Q0]
+ movx m9, [Q1]
+ movx m10, [Q2]
+ movx m11, [Q3]
+ movx m12, [Q4]
+ movx m13, [Q5]
+ movx m14, [Q6]
+ movx m15, [Q7]
+ DEFINE_TRANSPOSED_P7_TO_Q7
+%if %2 == 16
+ TRANSPOSE16x16B 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, [rsp]
+ mova [P7], m0
+ mova [P6], m1
+ mova [P5], m2
+ mova [P4], m3
+%else ; %2 == 44/48/84/88
+ ; 8x16 transpose
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ punpcklbw m4, m5
+ punpcklbw m6, m7
+ punpcklbw m8, m9
+ punpcklbw m10, m11
+ punpcklbw m12, m13
+ punpcklbw m14, m15
+ TRANSPOSE8x8W 0, 2, 4, 6, 8, 10, 12, 14, 15
+ SWAP 0, 4
+ SWAP 2, 5
+ SWAP 0, 6
+ SWAP 0, 7
+ SWAP 10, 9
+ SWAP 12, 10
+ SWAP 14, 11
+%endif ; %2
+ mova [P3], m4
+ mova [P2], m5
+ mova [P1], m6
+ mova [P0], m7
+ mova [Q0], m8
+ mova [Q1], m9
+ mova [Q2], m10
+ mova [Q3], m11
+%if %2 == 16
+ mova [Q4], m12
+ mova [Q5], m13
+ mova [Q6], m14
+ mova [Q7], m15
+%endif ; %2
+%else ; x86-32
+%if %2 == 16
+ TRANSPOSE8x8B 0, 1, 2, 3, 4, 5, 6, 7, [P1], u, [rsp+%3+%4], [rsp+64], [rsp+80]
+ DEFINE_TRANSPOSED_P7_TO_Q7
+ movh [P7], m0
+ movh [P5], m1
+ movh [P3], m2
+ movh [P1], m3
+ movh [Q2], m5
+ movh [Q4], m6
+ movh [Q6], m7
+ movhps [P6], m0
+ movhps [P4], m1
+ movhps [P2], m2
+ movhps [P0], m3
+ movhps [Q3], m5
+ movhps [Q5], m6
+ movhps [Q7], m7
+ DEFINE_REAL_P7_TO_Q7
+ movx m0, [Q0]
+ movx m1, [Q1]
+ movx m2, [Q2]
+ movx m3, [Q3]
+ movx m4, [Q4]
+ movx m5, [Q5]
+ movx m7, [Q7]
+ TRANSPOSE8x8B 0, 1, 2, 3, 4, 5, 6, 7, [Q6], u, [rsp+%3+%4], [rsp+72], [rsp+88]
+ DEFINE_TRANSPOSED_P7_TO_Q7 8
+ movh [P7], m0
+ movh [P5], m1
+ movh [P3], m2
+ movh [P1], m3
+ movh [Q2], m5
+ movh [Q4], m6
+ movh [Q6], m7
+ movhps [P6], m0
+ movhps [P4], m1
+ movhps [P2], m2
+ movhps [P0], m3
+ movhps [Q3], m5
+ movhps [Q5], m6
+ movhps [Q7], m7
+ DEFINE_TRANSPOSED_P7_TO_Q7
+%else ; %2 == 44/48/84/88
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ punpcklbw m4, m5
+ punpcklbw m6, m7
+ movx m1, [Q0]
+ movx m3, [Q1]
+ movx m5, [Q2]
+ movx m7, [Q3]
+ punpcklbw m1, m3
+ punpcklbw m5, m7
+ movx m3, [Q4]
+ movx m7, [Q5]
+ punpcklbw m3, m7
+ mova [rsp], m3
+ movx m3, [Q6]
+ movx m7, [Q7]
+ punpcklbw m3, m7
+ DEFINE_TRANSPOSED_P7_TO_Q7
+ TRANSPOSE8x8W 0, 2, 4, 6, 1, 5, 7, 3, [rsp], [Q0], 1
+ mova [P3], m0
+ mova [P2], m2
+ mova [P1], m4
+ mova [P0], m6
+ mova [Q1], m5
+ mova [Q2], m7
+ mova [Q3], m3
+%endif ; %2
+%endif ; x86-32/64
+%endif ; %1 == h
+
+ ; calc fm mask
+%if %2 == 16
+%if cpuflag(ssse3)
+ pxor m0, m0
+%endif
+ SPLATB_REG m2, I, m0 ; I I I I ...
+ SPLATB_REG m3, E, m0 ; E E E E ...
+%else
+%if cpuflag(ssse3)
+ mova m0, [mask_mix]
+%endif
+ movd m2, Id
+ movd m3, Ed
+ SPLATB_MIX m2, m0
+ SPLATB_MIX m3, m0
+%endif
+ mova m0, [pb_80]
+ pxor m2, m0
+ pxor m3, m0
+%if ARCH_X86_64
+%ifidn %1, v
+ mova m8, [P3]
+ mova m9, [P2]
+ mova m10, [P1]
+ mova m11, [P0]
+ mova m12, [Q0]
+ mova m13, [Q1]
+ mova m14, [Q2]
+ mova m15, [Q3]
+%else
+ ; In case of horizontal, P3..Q3 are already present in some registers due
+ ; to the previous transpose, so we just swap registers.
+ SWAP 8, 4, 12
+ SWAP 9, 5, 13
+ SWAP 10, 6, 14
+ SWAP 11, 7, 15
+%endif
+%define rp3 m8
+%define rp2 m9
+%define rp1 m10
+%define rp0 m11
+%define rq0 m12
+%define rq1 m13
+%define rq2 m14
+%define rq3 m15
+%else
+%define rp3 [P3]
+%define rp2 [P2]
+%define rp1 [P1]
+%define rp0 [P0]
+%define rq0 [Q0]
+%define rq1 [Q1]
+%define rq2 [Q2]
+%define rq3 [Q3]
+%endif
+ ABSSUB_GT m5, rp3, rp2, m2, m7, m0 ; m5 = abs(p3-p2) <= I
+ ABSSUB_GT m1, rp2, rp1, m2, m7, m0 ; m1 = abs(p2-p1) <= I
+ por m5, m1
+ ABSSUB_GT m1, rp1, rp0, m2, m7, m0 ; m1 = abs(p1-p0) <= I
+ por m5, m1
+ ABSSUB_GT m1, rq0, rq1, m2, m7, m0 ; m1 = abs(q1-q0) <= I
+ por m5, m1
+ ABSSUB_GT m1, rq1, rq2, m2, m7, m0 ; m1 = abs(q2-q1) <= I
+ por m5, m1
+ ABSSUB_GT m1, rq2, rq3, m2, m7, m0 ; m1 = abs(q3-q2) <= I
+ por m5, m1
+ ABSSUB m1, rp0, rq0, m7 ; abs(p0-q0)
+ paddusb m1, m1 ; abs(p0-q0) * 2
+ ABSSUB m2, rp1, rq1, m7 ; abs(p1-q1)
+ pand m2, [pb_fe] ; drop lsb so shift can work
+ psrlq m2, 1 ; abs(p1-q1)/2
+ paddusb m1, m2 ; abs(p0-q0)*2 + abs(p1-q1)/2
+ pxor m1, m0
+ pcmpgtb m1, m3
+ por m1, m5 ; fm final value
+ SWAP 1, 3
+ pxor m3, [pb_ff]
+
+ ; (m3: fm, m8..15: p3 p2 p1 p0 q0 q1 q2 q3)
+ ; calc flat8in (if not 44_16) and hev masks
+%if %2 != 44
+ mova m6, [pb_81] ; [1 1 1 1 ...] ^ 0x80
+ ABSSUB_GT m2, rp3, rp0, m6, m5 ; abs(p3 - p0) <= 1
+%if ARCH_X86_64
+ mova m8, [pb_80]
+%define rb80 m8
+%else
+%define rb80 [pb_80]
+%endif
+ ABSSUB_GT m1, rp2, rp0, m6, m5, rb80 ; abs(p2 - p0) <= 1
+ por m2, m1
+ ABSSUB m4, rp1, rp0, m5 ; abs(p1 - p0)
+%if %2 == 16
+%if cpuflag(ssse3)
+ pxor m0, m0
+%endif
+ SPLATB_REG m7, H, m0 ; H H H H ...
+%else
+ movd m7, Hd
+ SPLATB_MIX m7
+%endif
+ pxor m7, rb80
+ pxor m4, rb80
+ pcmpgtb m0, m4, m7 ; abs(p1 - p0) > H (1/2 hev condition)
+ CMP_GT m4, m6 ; abs(p1 - p0) <= 1
+ por m2, m4 ; (flat8in)
+ ABSSUB m4, rq1, rq0, m1 ; abs(q1 - q0)
+ pxor m4, rb80
+ pcmpgtb m5, m4, m7 ; abs(q1 - q0) > H (2/2 hev condition)
+ por m0, m5 ; hev final value
+ CMP_GT m4, m6 ; abs(q1 - q0) <= 1
+ por m2, m4 ; (flat8in)
+ ABSSUB_GT m1, rq2, rq0, m6, m5, rb80 ; abs(q2 - q0) <= 1
+ por m2, m1
+ ABSSUB_GT m1, rq3, rq0, m6, m5, rb80 ; abs(q3 - q0) <= 1
+ por m2, m1 ; flat8in final value
+ pxor m2, [pb_ff]
+%if %2 == 84 || %2 == 48
+ pand m2, [mask_mix%2]
+%endif
+%else
+ mova m6, [pb_80]
+ movd m7, Hd
+ SPLATB_MIX m7
+ pxor m7, m6
+ ABSSUB m4, rp1, rp0, m1 ; abs(p1 - p0)
+ pxor m4, m6
+ pcmpgtb m0, m4, m7 ; abs(p1 - p0) > H (1/2 hev condition)
+ ABSSUB m4, rq1, rq0, m1 ; abs(q1 - q0)
+ pxor m4, m6
+ pcmpgtb m5, m4, m7 ; abs(q1 - q0) > H (2/2 hev condition)
+ por m0, m5 ; hev final value
+%endif
+
+%if %2 == 16
+ ; (m0: hev, m2: flat8in, m3: fm, m6: pb_81, m9..15: p2 p1 p0 q0 q1 q2 q3)
+ ; calc flat8out mask
+%if ARCH_X86_64
+ mova m8, [P7]
+ mova m9, [P6]
+%define rp7 m8
+%define rp6 m9
+%else
+%define rp7 [P7]
+%define rp6 [P6]
+%endif
+ ABSSUB_GT m1, rp7, rp0, m6, m5 ; abs(p7 - p0) <= 1
+ ABSSUB_GT m7, rp6, rp0, m6, m5 ; abs(p6 - p0) <= 1
+ por m1, m7
+%if ARCH_X86_64
+ mova m8, [P5]
+ mova m9, [P4]
+%define rp5 m8
+%define rp4 m9
+%else
+%define rp5 [P5]
+%define rp4 [P4]
+%endif
+ ABSSUB_GT m7, rp5, rp0, m6, m5 ; abs(p5 - p0) <= 1
+ por m1, m7
+ ABSSUB_GT m7, rp4, rp0, m6, m5 ; abs(p4 - p0) <= 1
+ por m1, m7
+%if ARCH_X86_64
+ mova m14, [Q4]
+ mova m15, [Q5]
+%define rq4 m14
+%define rq5 m15
+%else
+%define rq4 [Q4]
+%define rq5 [Q5]
+%endif
+ ABSSUB_GT m7, rq4, rq0, m6, m5 ; abs(q4 - q0) <= 1
+ por m1, m7
+ ABSSUB_GT m7, rq5, rq0, m6, m5 ; abs(q5 - q0) <= 1
+ por m1, m7
+%if ARCH_X86_64
+ mova m14, [Q6]
+ mova m15, [Q7]
+%define rq6 m14
+%define rq7 m15
+%else
+%define rq6 [Q6]
+%define rq7 [Q7]
+%endif
+ ABSSUB_GT m7, rq6, rq0, m6, m5 ; abs(q4 - q0) <= 1
+ por m1, m7
+ ABSSUB_GT m7, rq7, rq0, m6, m5 ; abs(q5 - q0) <= 1
+ por m1, m7 ; flat8out final value
+ pxor m1, [pb_ff]
+%endif
+
+ ; if (fm) {
+ ; if (out && in) filter_14()
+ ; else if (in) filter_6()
+ ; else if (hev) filter_2()
+ ; else filter_4()
+ ; }
+ ;
+ ; f14: fm & out & in
+ ; f6: fm & ~f14 & in => fm & ~(out & in) & in => fm & ~out & in
+ ; f2: fm & ~f14 & ~f6 & hev => fm & ~(out & in) & ~(~out & in) & hev => fm & ~in & hev
+ ; f4: fm & ~f14 & ~f6 & ~f2 => fm & ~(out & in) & ~(~out & in) & ~(~in & hev) => fm & ~in & ~hev
+
+ ; (m0: hev, [m1: flat8out], [m2: flat8in], m3: fm, m8..15: p5 p4 p1 p0 q0 q1 q6 q7)
+ ; filter2()
+%if %2 != 44
+ mova m6, [pb_80] ; already in m6 if 44_16
+ SCRATCH 2, 15, rsp+%3+%4
+%if %2 == 16
+ SCRATCH 1, 8, rsp+%3+%4+16
+%endif
+%endif
+ pxor m2, m6, rq0 ; q0 ^ 0x80
+ pxor m4, m6, rp0 ; p0 ^ 0x80
+ psubsb m2, m4 ; (signed) q0 - p0
+ pxor m4, m6, rp1 ; p1 ^ 0x80
+ pxor m5, m6, rq1 ; q1 ^ 0x80
+ psubsb m4, m5 ; (signed) p1 - q1
+ paddsb m4, m2 ; (q0 - p0) + (p1 - q1)
+ paddsb m4, m2 ; 2*(q0 - p0) + (p1 - q1)
+ paddsb m4, m2 ; 3*(q0 - p0) + (p1 - q1)
+ paddsb m6, m4, [pb_4] ; m6: f1 = clip(f + 4, 127)
+ paddsb m4, [pb_3] ; m4: f2 = clip(f + 3, 127)
+%if ARCH_X86_64
+ mova m14, [pb_10] ; will be reused in filter4()
+%define rb10 m14
+%else
+%define rb10 [pb_10]
+%endif
+ SRSHIFT3B_2X m6, m4, rb10, m7 ; f1 and f2 sign byte shift by 3
+ SIGN_SUB m7, rq0, m6, m5 ; m7 = q0 - f1
+ SIGN_ADD m1, rp0, m4, m5 ; m1 = p0 + f2
+%if %2 != 44
+%if ARCH_X86_64
+ pandn m6, m15, m3 ; ~mask(in) & mask(fm)
+%else
+ mova m6, [rsp+%3+%4]
+ pandn m6, m3
+%endif
+ pand m6, m0 ; (~mask(in) & mask(fm)) & mask(hev)
+%else
+ pand m6, m3, m0
+%endif
+ MASK_APPLY m7, rq0, m6, m5 ; m7 = filter2(q0) & mask / we write it in filter4()
+ MASK_APPLY m1, rp0, m6, m5 ; m1 = filter2(p0) & mask / we write it in filter4()
+
+ ; (m0: hev, m1: p0', m2: q0-p0, m3: fm, m7: q0', [m8: flat8out], m10..13: p1 p0 q0 q1, m14: pb_10, [m15: flat8in], )
+ ; filter4()
+ mova m4, m2
+ paddsb m2, m4 ; 2 * (q0 - p0)
+ paddsb m2, m4 ; 3 * (q0 - p0)
+ paddsb m6, m2, [pb_4] ; m6: f1 = clip(f + 4, 127)
+ paddsb m2, [pb_3] ; m2: f2 = clip(f + 3, 127)
+ SRSHIFT3B_2X m6, m2, rb10, m4 ; f1 and f2 sign byte shift by 3
+%if %2 != 44
+%if ARCH_X86_64
+ pandn m5, m15, m3 ; ~mask(in) & mask(fm)
+%else
+ mova m5, [rsp+%3+%4]
+ pandn m5, m3
+%endif
+ pandn m0, m5 ; ~mask(hev) & (~mask(in) & mask(fm))
+%else
+ pandn m0, m3
+%endif
+ SIGN_SUB m5, rq0, m6, m4 ; q0 - f1
+ MASK_APPLY m5, m7, m0, m4 ; filter4(q0) & mask
+ mova [Q0], m5
+ SIGN_ADD m7, rp0, m2, m4 ; p0 + f2
+ MASK_APPLY m7, m1, m0, m4 ; filter4(p0) & mask
+ mova [P0], m7
+ paddb m6, [pb_80] ;
+ pxor m1, m1 ; f=(f1+1)>>1
+ pavgb m6, m1 ;
+ psubb m6, [pb_40] ;
+ SIGN_ADD m1, rp1, m6, m2 ; p1 + f
+ SIGN_SUB m4, rq1, m6, m2 ; q1 - f
+ MASK_APPLY m1, rp1, m0, m2 ; m1 = filter4(p1)
+ MASK_APPLY m4, rq1, m0, m2 ; m4 = filter4(q1)
+ mova [P1], m1
+ mova [Q1], m4
+
+%if %2 != 44
+ UNSCRATCH 2, 15, rsp+%3+%4
+%endif
+
+ ; ([m1: flat8out], m2: flat8in, m3: fm, m10..13: p1 p0 q0 q1)
+ ; filter6()
+%if %2 != 44
+ pxor m0, m0
+%if %2 > 16
+ pand m3, m2
+%else
+ pand m2, m3 ; mask(fm) & mask(in)
+%if ARCH_X86_64
+ pandn m3, m8, m2 ; ~mask(out) & (mask(fm) & mask(in))
+%else
+ mova m3, [rsp+%3+%4+16]
+ pandn m3, m2
+%endif
+%endif
+%if ARCH_X86_64
+ mova m14, [P3]
+ mova m9, [Q3]
+%define rp3 m14
+%define rq3 m9
+%else
+%define rp3 [P3]
+%define rq3 [Q3]
+%endif
+ mova m1, [P2]
+ FILTER_INIT m4, m5, m6, m7, [P2], %4, 6, m3, m1 ; [p2]
+ mova m1, [Q2]
+ FILTER_UPDATE m4, m5, m6, m7, [P1], %4, 0, 1, 2, 5, 3, m3, "", rq1, "", 1 ; [p1] -p3 -p2 +p1 +q1
+ FILTER_UPDATE m4, m5, m6, m7, [P0], %4, 0, 2, 3, 6, 3, m3, "", m1 ; [p0] -p3 -p1 +p0 +q2
+ FILTER_UPDATE m4, m5, m6, m7, [Q0], %4, 0, 3, 4, 7, 3, m3, "", rq3, "", 1 ; [q0] -p3 -p0 +q0 +q3
+ FILTER_UPDATE m4, m5, m6, m7, [Q1], %4, 1, 4, 5, 7, 3, m3, "" ; [q1] -p2 -q0 +q1 +q3
+ FILTER_UPDATE m4, m5, m6, m7, [Q2], %4, 2, 5, 6, 7, 3, m3, m1 ; [q2] -p1 -q1 +q2 +q3
+%endif
+
+%if %2 == 16
+ UNSCRATCH 1, 8, rsp+%3+%4+16
+%endif
+
+ ; (m0: 0, [m1: flat8out], m2: fm & flat8in, m8..15: q2 q3 p1 p0 q0 q1 p3 p2)
+ ; filter14()
+ ;
+ ; m2 m3 m8 m9 m14 m15 m10 m11 m12 m13
+ ;
+ ; q2 q3 p3 p2 p1 p0 q0 q1
+ ; p6 -7 p7 p6 p5 p4 . . . . .
+ ; p5 -6 -p7 -p6 +p5 +q1 . . . .
+ ; p4 -5 -p7 -p5 +p4 +q2 . . . q2
+ ; p3 -4 -p7 -p4 +p3 +q3 . . . q3
+ ; p2 -3 -p7 -p3 +p2 +q4 . . . q4
+ ; p1 -2 -p7 -p2 +p1 +q5 . . . q5
+ ; p0 -1 -p7 -p1 +p0 +q6 . . . q6
+ ; q0 +0 -p7 -p0 +q0 +q7 . . . q7
+ ; q1 +1 -p6 -q0 +q1 +q7 q1 . . .
+ ; q2 +2 -p5 -q1 +q2 +q7 . q2 . .
+ ; q3 +3 -p4 -q2 +q3 +q7 . q3 . .
+ ; q4 +4 -p3 -q3 +q4 +q7 . q4 . .
+ ; q5 +5 -p2 -q4 +q5 +q7 . q5 . .
+ ; q6 +6 -p1 -q5 +q6 +q7 . q6 . .
+
+%if %2 == 16
+ pand m1, m2 ; mask(out) & (mask(fm) & mask(in))
+ mova m2, [P7]
+ mova m3, [P6]
+%if ARCH_X86_64
+ mova m8, [P5]
+ mova m9, [P4]
+%define rp5 m8
+%define rp4 m9
+%define rp5s m8
+%define rp4s m9
+%define rp3s m14
+%define rq4 m8
+%define rq5 m9
+%define rq6 m14
+%define rq7 m15
+%define rq4s m8
+%define rq5s m9
+%define rq6s m14
+%else
+%define rp5 [P5]
+%define rp4 [P4]
+%define rp5s ""
+%define rp4s ""
+%define rp3s ""
+%define rq4 [Q4]
+%define rq5 [Q5]
+%define rq6 [Q6]
+%define rq7 [Q7]
+%define rq4s ""
+%define rq5s ""
+%define rq6s ""
+%endif
+ FILTER_INIT m4, m5, m6, m7, [P6], %4, 14, m1, m3 ; [p6]
+ FILTER_UPDATE m4, m5, m6, m7, [P5], %4, 8, 9, 10, 5, 4, m1, rp5s ; [p5] -p7 -p6 +p5 +q1
+ FILTER_UPDATE m4, m5, m6, m7, [P4], %4, 8, 10, 11, 6, 4, m1, rp4s ; [p4] -p7 -p5 +p4 +q2
+ FILTER_UPDATE m4, m5, m6, m7, [P3], %4, 8, 11, 0, 7, 4, m1, rp3s ; [p3] -p7 -p4 +p3 +q3
+ FILTER_UPDATE m4, m5, m6, m7, [P2], %4, 8, 0, 1, 12, 4, m1, "", rq4, [Q4], 1 ; [p2] -p7 -p3 +p2 +q4
+ FILTER_UPDATE m4, m5, m6, m7, [P1], %4, 8, 1, 2, 13, 4, m1, "", rq5, [Q5], 1 ; [p1] -p7 -p2 +p1 +q5
+ FILTER_UPDATE m4, m5, m6, m7, [P0], %4, 8, 2, 3, 14, 4, m1, "", rq6, [Q6], 1 ; [p0] -p7 -p1 +p0 +q6
+ FILTER_UPDATE m4, m5, m6, m7, [Q0], %4, 8, 3, 4, 15, 4, m1, "", rq7, [Q7], 1 ; [q0] -p7 -p0 +q0 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q1], %4, 9, 4, 5, 15, 4, m1, "" ; [q1] -p6 -q0 +q1 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q2], %4, 10, 5, 6, 15, 4, m1, "" ; [q2] -p5 -q1 +q2 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q3], %4, 11, 6, 7, 15, 4, m1, "" ; [q3] -p4 -q2 +q3 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q4], %4, 0, 7, 12, 15, 4, m1, rq4s ; [q4] -p3 -q3 +q4 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q5], %4, 1, 12, 13, 15, 4, m1, rq5s ; [q5] -p2 -q4 +q5 +q7
+ FILTER_UPDATE m4, m5, m6, m7, [Q6], %4, 2, 13, 14, 15, 4, m1, rq6s ; [q6] -p1 -q5 +q6 +q7
+%endif
+
+%ifidn %1, h
+%if %2 == 16
+ mova m0, [P7]
+ mova m1, [P6]
+ mova m2, [P5]
+ mova m3, [P4]
+ mova m4, [P3]
+ mova m5, [P2]
+%if ARCH_X86_64
+ mova m6, [P1]
+%endif
+ mova m7, [P0]
+%if ARCH_X86_64
+ mova m8, [Q0]
+ mova m9, [Q1]
+ mova m10, [Q2]
+ mova m11, [Q3]
+ mova m12, [Q4]
+ mova m13, [Q5]
+ mova m14, [Q6]
+ mova m15, [Q7]
+ TRANSPOSE16x16B 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, [rsp]
+ DEFINE_REAL_P7_TO_Q7
+ movu [P7], m0
+ movu [P6], m1
+ movu [P5], m2
+ movu [P4], m3
+ movu [P3], m4
+ movu [P2], m5
+ movu [P1], m6
+ movu [P0], m7
+ movu [Q0], m8
+ movu [Q1], m9
+ movu [Q2], m10
+ movu [Q3], m11
+ movu [Q4], m12
+ movu [Q5], m13
+ movu [Q6], m14
+ movu [Q7], m15
+%else
+ DEFINE_REAL_P7_TO_Q7
+ TRANSPOSE8x8B 0, 1, 2, 3, 4, 5, 6, 7, [rsp+32], a, [rsp+%3+%4], [Q0], [Q1]
+ movh [P7], m0
+ movh [P5], m1
+ movh [P3], m2
+ movh [P1], m3
+ movh [Q2], m5
+ movh [Q4], m6
+ movh [Q6], m7
+ movhps [P6], m0
+ movhps [P4], m1
+ movhps [P2], m2
+ movhps [P0], m3
+ movhps [Q3], m5
+ movhps [Q5], m6
+ movhps [Q7], m7
+ DEFINE_TRANSPOSED_P7_TO_Q7
+ mova m0, [Q0]
+ mova m1, [Q1]
+ mova m2, [Q2]
+ mova m3, [Q3]
+ mova m4, [Q4]
+ mova m5, [Q5]
+ mova m7, [Q7]
+ DEFINE_REAL_P7_TO_Q7 8
+ TRANSPOSE8x8B 0, 1, 2, 3, 4, 5, 6, 7, [rsp+224], a, [rsp+%3+%4], [Q0], [Q1]
+ movh [P7], m0
+ movh [P5], m1
+ movh [P3], m2
+ movh [P1], m3
+ movh [Q2], m5
+ movh [Q4], m6
+ movh [Q6], m7
+ movhps [P6], m0
+ movhps [P4], m1
+ movhps [P2], m2
+ movhps [P0], m3
+ movhps [Q3], m5
+ movhps [Q5], m6
+ movhps [Q7], m7
+%endif
+%elif %2 == 44
+ SWAP 0, 1 ; m0 = p1
+ SWAP 1, 7 ; m1 = p0
+ SWAP 2, 5 ; m2 = q0
+ SWAP 3, 4 ; m3 = q1
+ DEFINE_REAL_P7_TO_Q7 2
+ SBUTTERFLY bw, 0, 1, 4
+ SBUTTERFLY bw, 2, 3, 4
+ SBUTTERFLY wd, 0, 2, 4
+ SBUTTERFLY wd, 1, 3, 4
+ movd [P7], m0
+ movd [P3], m2
+ movd [Q0], m1
+ movd [Q4], m3
+ psrldq m0, 4
+ psrldq m1, 4
+ psrldq m2, 4
+ psrldq m3, 4
+ movd [P6], m0
+ movd [P2], m2
+ movd [Q1], m1
+ movd [Q5], m3
+ psrldq m0, 4
+ psrldq m1, 4
+ psrldq m2, 4
+ psrldq m3, 4
+ movd [P5], m0
+ movd [P1], m2
+ movd [Q2], m1
+ movd [Q6], m3
+ psrldq m0, 4
+ psrldq m1, 4
+ psrldq m2, 4
+ psrldq m3, 4
+ movd [P4], m0
+ movd [P0], m2
+ movd [Q3], m1
+ movd [Q7], m3
+%else
+ ; the following code do a transpose of 8 full lines to 16 half
+ ; lines (high part). It is inlined to avoid the need of a staging area
+ mova m0, [P3]
+ mova m1, [P2]
+ mova m2, [P1]
+ mova m3, [P0]
+ mova m4, [Q0]
+ mova m5, [Q1]
+%if ARCH_X86_64
+ mova m6, [Q2]
+%endif
+ mova m7, [Q3]
+ DEFINE_REAL_P7_TO_Q7
+%if ARCH_X86_64
+ SBUTTERFLY bw, 0, 1, 8
+ SBUTTERFLY bw, 2, 3, 8
+ SBUTTERFLY bw, 4, 5, 8
+ SBUTTERFLY bw, 6, 7, 8
+ SBUTTERFLY wd, 0, 2, 8
+ SBUTTERFLY wd, 1, 3, 8
+ SBUTTERFLY wd, 4, 6, 8
+ SBUTTERFLY wd, 5, 7, 8
+ SBUTTERFLY dq, 0, 4, 8
+ SBUTTERFLY dq, 1, 5, 8
+ SBUTTERFLY dq, 2, 6, 8
+ SBUTTERFLY dq, 3, 7, 8
+%else
+ SBUTTERFLY bw, 0, 1, 6
+ mova [rsp+64], m1
+ mova m6, [rsp+96]
+ SBUTTERFLY bw, 2, 3, 1
+ SBUTTERFLY bw, 4, 5, 1
+ SBUTTERFLY bw, 6, 7, 1
+ SBUTTERFLY wd, 0, 2, 1
+ mova [rsp+96], m2
+ mova m1, [rsp+64]
+ SBUTTERFLY wd, 1, 3, 2
+ SBUTTERFLY wd, 4, 6, 2
+ SBUTTERFLY wd, 5, 7, 2
+ SBUTTERFLY dq, 0, 4, 2
+ SBUTTERFLY dq, 1, 5, 2
+ movh [Q0], m1
+ movhps [Q1], m1
+ mova m2, [rsp+96]
+ SBUTTERFLY dq, 2, 6, 1
+ SBUTTERFLY dq, 3, 7, 1
+%endif
+ SWAP 3, 6
+ SWAP 1, 4
+ movh [P7], m0
+ movhps [P6], m0
+ movh [P5], m1
+ movhps [P4], m1
+ movh [P3], m2
+ movhps [P2], m2
+ movh [P1], m3
+ movhps [P0], m3
+%if ARCH_X86_64
+ movh [Q0], m4
+ movhps [Q1], m4
+%endif
+ movh [Q2], m5
+ movhps [Q3], m5
+ movh [Q4], m6
+ movhps [Q5], m6
+ movh [Q6], m7
+ movhps [Q7], m7
+%endif
+%endif
+
+ RET
+%endmacro
+
+%macro LPF_16_VH 5
+INIT_XMM %5
+LOOPFILTER v, %1, %2, 0, %4
+LOOPFILTER h, %1, %2, %3, %4
+%endmacro
+
+%macro LPF_16_VH_ALL_OPTS 4
+LPF_16_VH %1, %2, %3, %4, sse2
+LPF_16_VH %1, %2, %3, %4, ssse3
+LPF_16_VH %1, %2, %3, %4, avx
+%endmacro
+
+LPF_16_VH_ALL_OPTS 16, 512, 256, 32
+LPF_16_VH_ALL_OPTS 44, 0, 128, 0
+LPF_16_VH_ALL_OPTS 48, 256, 128, 16
+LPF_16_VH_ALL_OPTS 84, 256, 128, 16
+LPF_16_VH_ALL_OPTS 88, 256, 128, 16
diff --git a/libavcodec/x86/vp9mc.asm b/libavcodec/x86/vp9mc.asm
new file mode 100644
index 0000000000..53939579fc
--- /dev/null
+++ b/libavcodec/x86/vp9mc.asm
@@ -0,0 +1,623 @@
+;******************************************************************************
+;* VP9 MC SIMD optimizations
+;*
+;* Copyright (c) 2013 Ronald S. Bultje <rsbultje 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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+cextern pw_256
+cextern pw_64
+
+%macro F8_SSSE3_TAPS 8
+times 16 db %1, %2
+times 16 db %3, %4
+times 16 db %5, %6
+times 16 db %7, %8
+%endmacro
+
+%macro F8_SSE2_TAPS 8
+times 8 dw %1
+times 8 dw %2
+times 8 dw %3
+times 8 dw %4
+times 8 dw %5
+times 8 dw %6
+times 8 dw %7
+times 8 dw %8
+%endmacro
+
+%macro FILTER 1
+const filters_%1 ; smooth
+ F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0
+ F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0
+ F8_TAPS -2, -2, 26, 63, 43, 4, -4, 0
+ F8_TAPS -2, -3, 24, 62, 46, 5, -4, 0
+ F8_TAPS -2, -3, 21, 60, 49, 7, -4, 0
+ F8_TAPS -1, -4, 18, 59, 51, 9, -4, 0
+ F8_TAPS -1, -4, 16, 57, 53, 12, -4, -1
+ F8_TAPS -1, -4, 14, 55, 55, 14, -4, -1
+ F8_TAPS -1, -4, 12, 53, 57, 16, -4, -1
+ F8_TAPS 0, -4, 9, 51, 59, 18, -4, -1
+ F8_TAPS 0, -4, 7, 49, 60, 21, -3, -2
+ F8_TAPS 0, -4, 5, 46, 62, 24, -3, -2
+ F8_TAPS 0, -4, 4, 43, 63, 26, -2, -2
+ F8_TAPS 0, -3, 2, 41, 63, 29, -2, -2
+ F8_TAPS 0, -3, 1, 38, 64, 32, -1, -3
+ ; regular
+ F8_TAPS 0, 1, -5, 126, 8, -3, 1, 0
+ F8_TAPS -1, 3, -10, 122, 18, -6, 2, 0
+ F8_TAPS -1, 4, -13, 118, 27, -9, 3, -1
+ F8_TAPS -1, 4, -16, 112, 37, -11, 4, -1
+ F8_TAPS -1, 5, -18, 105, 48, -14, 4, -1
+ F8_TAPS -1, 5, -19, 97, 58, -16, 5, -1
+ F8_TAPS -1, 6, -19, 88, 68, -18, 5, -1
+ F8_TAPS -1, 6, -19, 78, 78, -19, 6, -1
+ F8_TAPS -1, 5, -18, 68, 88, -19, 6, -1
+ F8_TAPS -1, 5, -16, 58, 97, -19, 5, -1
+ F8_TAPS -1, 4, -14, 48, 105, -18, 5, -1
+ F8_TAPS -1, 4, -11, 37, 112, -16, 4, -1
+ F8_TAPS -1, 3, -9, 27, 118, -13, 4, -1
+ F8_TAPS 0, 2, -6, 18, 122, -10, 3, -1
+ F8_TAPS 0, 1, -3, 8, 126, -5, 1, 0
+ ; sharp
+ F8_TAPS -1, 3, -7, 127, 8, -3, 1, 0
+ F8_TAPS -2, 5, -13, 125, 17, -6, 3, -1
+ F8_TAPS -3, 7, -17, 121, 27, -10, 5, -2
+ F8_TAPS -4, 9, -20, 115, 37, -13, 6, -2
+ F8_TAPS -4, 10, -23, 108, 48, -16, 8, -3
+ F8_TAPS -4, 10, -24, 100, 59, -19, 9, -3
+ F8_TAPS -4, 11, -24, 90, 70, -21, 10, -4
+ F8_TAPS -4, 11, -23, 80, 80, -23, 11, -4
+ F8_TAPS -4, 10, -21, 70, 90, -24, 11, -4
+ F8_TAPS -3, 9, -19, 59, 100, -24, 10, -4
+ F8_TAPS -3, 8, -16, 48, 108, -23, 10, -4
+ F8_TAPS -2, 6, -13, 37, 115, -20, 9, -4
+ F8_TAPS -2, 5, -10, 27, 121, -17, 7, -3
+ F8_TAPS -1, 3, -6, 17, 125, -13, 5, -2
+ F8_TAPS 0, 1, -3, 8, 127, -7, 3, -1
+%endmacro
+
+%define F8_TAPS F8_SSSE3_TAPS
+; int8_t ff_filters_ssse3[3][15][4][32]
+FILTER ssse3
+%define F8_TAPS F8_SSE2_TAPS
+; int16_t ff_filters_sse2[3][15][8][8]
+FILTER sse2
+
+SECTION .text
+
+%macro filter_sse2_h_fn 1
+%assign %%px mmsize/2
+cglobal vp9_%1_8tap_1d_h_ %+ %%px, 6, 6, 15, dst, dstride, src, sstride, h, filtery
+ pxor m5, m5
+ mova m6, [pw_64]
+ mova m7, [filteryq+ 0]
+%if ARCH_X86_64 && mmsize > 8
+ mova m8, [filteryq+ 16]
+ mova m9, [filteryq+ 32]
+ mova m10, [filteryq+ 48]
+ mova m11, [filteryq+ 64]
+ mova m12, [filteryq+ 80]
+ mova m13, [filteryq+ 96]
+ mova m14, [filteryq+112]
+%endif
+.loop:
+ movh m0, [srcq-3]
+ movh m1, [srcq-2]
+ movh m2, [srcq-1]
+ movh m3, [srcq+0]
+ movh m4, [srcq+1]
+ punpcklbw m0, m5
+ punpcklbw m1, m5
+ punpcklbw m2, m5
+ punpcklbw m3, m5
+ punpcklbw m4, m5
+ pmullw m0, m7
+%if ARCH_X86_64 && mmsize > 8
+ pmullw m1, m8
+ pmullw m2, m9
+ pmullw m3, m10
+ pmullw m4, m11
+%else
+ pmullw m1, [filteryq+ 16]
+ pmullw m2, [filteryq+ 32]
+ pmullw m3, [filteryq+ 48]
+ pmullw m4, [filteryq+ 64]
+%endif
+ paddw m0, m1
+ paddw m2, m3
+ paddw m0, m4
+ movh m1, [srcq+2]
+ movh m3, [srcq+3]
+ movh m4, [srcq+4]
+ add srcq, sstrideq
+ punpcklbw m1, m5
+ punpcklbw m3, m5
+ punpcklbw m4, m5
+%if ARCH_X86_64 && mmsize > 8
+ pmullw m1, m12
+ pmullw m3, m13
+ pmullw m4, m14
+%else
+ pmullw m1, [filteryq+ 80]
+ pmullw m3, [filteryq+ 96]
+ pmullw m4, [filteryq+112]
+%endif
+ paddw m0, m1
+ paddw m3, m4
+ paddw m0, m6
+ paddw m2, m3
+ paddsw m0, m2
+ psraw m0, 7
+%ifidn %1, avg
+ movh m1, [dstq]
+%endif
+ packuswb m0, m0
+%ifidn %1, avg
+ pavgb m0, m1
+%endif
+ movh [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_MMX mmxext
+filter_sse2_h_fn put
+filter_sse2_h_fn avg
+
+INIT_XMM sse2
+filter_sse2_h_fn put
+filter_sse2_h_fn avg
+
+%macro filter_h_fn 1
+%assign %%px mmsize/2
+cglobal vp9_%1_8tap_1d_h_ %+ %%px, 6, 6, 11, dst, dstride, src, sstride, h, filtery
+ mova m6, [pw_256]
+ mova m7, [filteryq+ 0]
+%if ARCH_X86_64 && mmsize > 8
+ mova m8, [filteryq+32]
+ mova m9, [filteryq+64]
+ mova m10, [filteryq+96]
+%endif
+.loop:
+ movh m0, [srcq-3]
+ movh m1, [srcq-2]
+ movh m2, [srcq-1]
+ movh m3, [srcq+0]
+ movh m4, [srcq+1]
+ movh m5, [srcq+2]
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ movh m1, [srcq+3]
+ movh m3, [srcq+4]
+ add srcq, sstrideq
+ punpcklbw m4, m5
+ punpcklbw m1, m3
+ pmaddubsw m0, m7
+%if ARCH_X86_64 && mmsize > 8
+ pmaddubsw m2, m8
+ pmaddubsw m4, m9
+ pmaddubsw m1, m10
+%else
+ pmaddubsw m2, [filteryq+32]
+ pmaddubsw m4, [filteryq+64]
+ pmaddubsw m1, [filteryq+96]
+%endif
+ paddw m0, m4
+ paddw m2, m1
+ paddsw m0, m2
+ pmulhrsw m0, m6
+%ifidn %1, avg
+ movh m1, [dstq]
+%endif
+ packuswb m0, m0
+%ifidn %1, avg
+ pavgb m0, m1
+%endif
+ movh [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_MMX ssse3
+filter_h_fn put
+filter_h_fn avg
+
+INIT_XMM ssse3
+filter_h_fn put
+filter_h_fn avg
+
+%if ARCH_X86_64
+%macro filter_hx2_fn 1
+%assign %%px mmsize
+cglobal vp9_%1_8tap_1d_h_ %+ %%px, 6, 6, 14, dst, dstride, src, sstride, h, filtery
+ mova m13, [pw_256]
+ mova m8, [filteryq+ 0]
+ mova m9, [filteryq+32]
+ mova m10, [filteryq+64]
+ mova m11, [filteryq+96]
+.loop:
+ movu m0, [srcq-3]
+ movu m1, [srcq-2]
+ movu m2, [srcq-1]
+ movu m3, [srcq+0]
+ movu m4, [srcq+1]
+ movu m5, [srcq+2]
+ movu m6, [srcq+3]
+ movu m7, [srcq+4]
+ add srcq, sstrideq
+ SBUTTERFLY bw, 0, 1, 12
+ SBUTTERFLY bw, 2, 3, 12
+ SBUTTERFLY bw, 4, 5, 12
+ SBUTTERFLY bw, 6, 7, 12
+ pmaddubsw m0, m8
+ pmaddubsw m1, m8
+ pmaddubsw m2, m9
+ pmaddubsw m3, m9
+ pmaddubsw m4, m10
+ pmaddubsw m5, m10
+ pmaddubsw m6, m11
+ pmaddubsw m7, m11
+ paddw m0, m4
+ paddw m1, m5
+ paddw m2, m6
+ paddw m3, m7
+ paddsw m0, m2
+ paddsw m1, m3
+ pmulhrsw m0, m13
+ pmulhrsw m1, m13
+ packuswb m0, m1
+%ifidn %1, avg
+ pavgb m0, [dstq]
+%endif
+ mova [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM ssse3
+filter_hx2_fn put
+filter_hx2_fn avg
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+filter_hx2_fn put
+filter_hx2_fn avg
+%endif
+
+%endif ; ARCH_X86_64
+
+%macro filter_sse2_v_fn 1
+%assign %%px mmsize/2
+%if ARCH_X86_64
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 6, 8, 15, dst, dstride, src, sstride, h, filtery, src4, sstride3
+%else
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 4, 7, 15, dst, dstride, src, sstride, filtery, src4, sstride3
+ mov filteryq, r5mp
+%define hd r4mp
+%endif
+ pxor m5, m5
+ mova m6, [pw_64]
+ lea sstride3q, [sstrideq*3]
+ lea src4q, [srcq+sstrideq]
+ sub srcq, sstride3q
+ mova m7, [filteryq+ 0]
+%if ARCH_X86_64 && mmsize > 8
+ mova m8, [filteryq+ 16]
+ mova m9, [filteryq+ 32]
+ mova m10, [filteryq+ 48]
+ mova m11, [filteryq+ 64]
+ mova m12, [filteryq+ 80]
+ mova m13, [filteryq+ 96]
+ mova m14, [filteryq+112]
+%endif
+.loop:
+ ; FIXME maybe reuse loads from previous rows, or just
+ ; more generally unroll this to prevent multiple loads of
+ ; the same data?
+ movh m0, [srcq]
+ movh m1, [srcq+sstrideq]
+ movh m2, [srcq+sstrideq*2]
+ movh m3, [srcq+sstride3q]
+ add srcq, sstrideq
+ movh m4, [src4q]
+ punpcklbw m0, m5
+ punpcklbw m1, m5
+ punpcklbw m2, m5
+ punpcklbw m3, m5
+ punpcklbw m4, m5
+ pmullw m0, m7
+%if ARCH_X86_64 && mmsize > 8
+ pmullw m1, m8
+ pmullw m2, m9
+ pmullw m3, m10
+ pmullw m4, m11
+%else
+ pmullw m1, [filteryq+ 16]
+ pmullw m2, [filteryq+ 32]
+ pmullw m3, [filteryq+ 48]
+ pmullw m4, [filteryq+ 64]
+%endif
+ paddw m0, m1
+ paddw m2, m3
+ paddw m0, m4
+ movh m1, [src4q+sstrideq]
+ movh m3, [src4q+sstrideq*2]
+ movh m4, [src4q+sstride3q]
+ add src4q, sstrideq
+ punpcklbw m1, m5
+ punpcklbw m3, m5
+ punpcklbw m4, m5
+%if ARCH_X86_64 && mmsize > 8
+ pmullw m1, m12
+ pmullw m3, m13
+ pmullw m4, m14
+%else
+ pmullw m1, [filteryq+ 80]
+ pmullw m3, [filteryq+ 96]
+ pmullw m4, [filteryq+112]
+%endif
+ paddw m0, m1
+ paddw m3, m4
+ paddw m0, m6
+ paddw m2, m3
+ paddsw m0, m2
+ psraw m0, 7
+%ifidn %1, avg
+ movh m1, [dstq]
+%endif
+ packuswb m0, m0
+%ifidn %1, avg
+ pavgb m0, m1
+%endif
+ movh [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_MMX mmxext
+filter_sse2_v_fn put
+filter_sse2_v_fn avg
+
+INIT_XMM sse2
+filter_sse2_v_fn put
+filter_sse2_v_fn avg
+
+%macro filter_v_fn 1
+%assign %%px mmsize/2
+%if ARCH_X86_64
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 6, 8, 11, dst, dstride, src, sstride, h, filtery, src4, sstride3
+%else
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 4, 7, 11, dst, dstride, src, sstride, filtery, src4, sstride3
+ mov filteryq, r5mp
+%define hd r4mp
+%endif
+ mova m6, [pw_256]
+ lea sstride3q, [sstrideq*3]
+ lea src4q, [srcq+sstrideq]
+ sub srcq, sstride3q
+ mova m7, [filteryq+ 0]
+%if ARCH_X86_64 && mmsize > 8
+ mova m8, [filteryq+32]
+ mova m9, [filteryq+64]
+ mova m10, [filteryq+96]
+%endif
+.loop:
+ ; FIXME maybe reuse loads from previous rows, or just
+ ; more generally unroll this to prevent multiple loads of
+ ; the same data?
+ movh m0, [srcq]
+ movh m1, [srcq+sstrideq]
+ movh m2, [srcq+sstrideq*2]
+ movh m3, [srcq+sstride3q]
+ movh m4, [src4q]
+ movh m5, [src4q+sstrideq]
+ punpcklbw m0, m1
+ punpcklbw m2, m3
+ movh m1, [src4q+sstrideq*2]
+ movh m3, [src4q+sstride3q]
+ add srcq, sstrideq
+ add src4q, sstrideq
+ punpcklbw m4, m5
+ punpcklbw m1, m3
+ pmaddubsw m0, m7
+%if ARCH_X86_64 && mmsize > 8
+ pmaddubsw m2, m8
+ pmaddubsw m4, m9
+ pmaddubsw m1, m10
+%else
+ pmaddubsw m2, [filteryq+32]
+ pmaddubsw m4, [filteryq+64]
+ pmaddubsw m1, [filteryq+96]
+%endif
+ paddw m0, m4
+ paddw m2, m1
+ paddsw m0, m2
+ pmulhrsw m0, m6
+%ifidn %1, avg
+ movh m1, [dstq]
+%endif
+ packuswb m0, m0
+%ifidn %1, avg
+ pavgb m0, m1
+%endif
+ movh [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_MMX ssse3
+filter_v_fn put
+filter_v_fn avg
+
+INIT_XMM ssse3
+filter_v_fn put
+filter_v_fn avg
+
+%if ARCH_X86_64
+
+%macro filter_vx2_fn 1
+%assign %%px mmsize
+cglobal vp9_%1_8tap_1d_v_ %+ %%px, 6, 8, 14, dst, dstride, src, sstride, h, filtery, src4, sstride3
+ mova m13, [pw_256]
+ lea sstride3q, [sstrideq*3]
+ lea src4q, [srcq+sstrideq]
+ sub srcq, sstride3q
+ mova m8, [filteryq+ 0]
+ mova m9, [filteryq+32]
+ mova m10, [filteryq+64]
+ mova m11, [filteryq+96]
+.loop:
+ ; FIXME maybe reuse loads from previous rows, or just
+ ; more generally unroll this to prevent multiple loads of
+ ; the same data?
+ movu m0, [srcq]
+ movu m1, [srcq+sstrideq]
+ movu m2, [srcq+sstrideq*2]
+ movu m3, [srcq+sstride3q]
+ movu m4, [src4q]
+ movu m5, [src4q+sstrideq]
+ movu m6, [src4q+sstrideq*2]
+ movu m7, [src4q+sstride3q]
+ add srcq, sstrideq
+ add src4q, sstrideq
+ SBUTTERFLY bw, 0, 1, 12
+ SBUTTERFLY bw, 2, 3, 12
+ SBUTTERFLY bw, 4, 5, 12
+ SBUTTERFLY bw, 6, 7, 12
+ pmaddubsw m0, m8
+ pmaddubsw m1, m8
+ pmaddubsw m2, m9
+ pmaddubsw m3, m9
+ pmaddubsw m4, m10
+ pmaddubsw m5, m10
+ pmaddubsw m6, m11
+ pmaddubsw m7, m11
+ paddw m0, m4
+ paddw m1, m5
+ paddw m2, m6
+ paddw m3, m7
+ paddsw m0, m2
+ paddsw m1, m3
+ pmulhrsw m0, m13
+ pmulhrsw m1, m13
+ packuswb m0, m1
+%ifidn %1, avg
+ pavgb m0, [dstq]
+%endif
+ mova [dstq], m0
+ add dstq, dstrideq
+ dec hd
+ jg .loop
+ RET
+%endmacro
+
+INIT_XMM ssse3
+filter_vx2_fn put
+filter_vx2_fn avg
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+filter_vx2_fn put
+filter_vx2_fn avg
+%endif
+
+%endif ; ARCH_X86_64
+
+%macro fpel_fn 6
+%if %2 == 4
+%define %%srcfn movh
+%define %%dstfn movh
+%else
+%define %%srcfn movu
+%define %%dstfn mova
+%endif
+
+%if %2 <= mmsize
+cglobal vp9_%1%2, 5, 7, 4, dst, dstride, src, sstride, h, dstride3, sstride3
+ lea sstride3q, [sstrideq*3]
+ lea dstride3q, [dstrideq*3]
+%else
+cglobal vp9_%1%2, 5, 5, 4, dst, dstride, src, sstride, h
+%endif
+.loop:
+ %%srcfn m0, [srcq]
+ %%srcfn m1, [srcq+s%3]
+ %%srcfn m2, [srcq+s%4]
+ %%srcfn m3, [srcq+s%5]
+ lea srcq, [srcq+sstrideq*%6]
+%ifidn %1, avg
+ pavgb m0, [dstq]
+ pavgb m1, [dstq+d%3]
+ pavgb m2, [dstq+d%4]
+ pavgb m3, [dstq+d%5]
+%endif
+ %%dstfn [dstq], m0
+ %%dstfn [dstq+d%3], m1
+ %%dstfn [dstq+d%4], m2
+ %%dstfn [dstq+d%5], m3
+ lea dstq, [dstq+dstrideq*%6]
+ sub hd, %6
+ jnz .loop
+ RET
+%endmacro
+
+%define d16 16
+%define s16 16
+%define d32 32
+%define s32 32
+INIT_MMX mmx
+fpel_fn put, 4, strideq, strideq*2, stride3q, 4
+fpel_fn put, 8, strideq, strideq*2, stride3q, 4
+INIT_MMX mmxext
+fpel_fn avg, 4, strideq, strideq*2, stride3q, 4
+fpel_fn avg, 8, strideq, strideq*2, stride3q, 4
+INIT_XMM sse
+fpel_fn put, 16, strideq, strideq*2, stride3q, 4
+fpel_fn put, 32, mmsize, strideq, strideq+mmsize, 2
+fpel_fn put, 64, mmsize, mmsize*2, mmsize*3, 1
+INIT_XMM sse2
+fpel_fn avg, 16, strideq, strideq*2, stride3q, 4
+fpel_fn avg, 32, mmsize, strideq, strideq+mmsize, 2
+fpel_fn avg, 64, mmsize, mmsize*2, mmsize*3, 1
+INIT_YMM avx
+fpel_fn put, 32, strideq, strideq*2, stride3q, 4
+fpel_fn put, 64, mmsize, strideq, strideq+mmsize, 2
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+fpel_fn avg, 32, strideq, strideq*2, stride3q, 4
+fpel_fn avg, 64, mmsize, strideq, strideq+mmsize, 2
+%endif
+%undef s16
+%undef d16
+%undef s32
+%undef d32
diff --git a/libavcodec/x86/w64xmmtest.c b/libavcodec/x86/w64xmmtest.c
index 2f064cad7b..25e833fef3 100644
--- a/libavcodec/x86/w64xmmtest.c
+++ b/libavcodec/x86/w64xmmtest.c
@@ -2,20 +2,20 @@
* check XMM registers for clobbers on Win64
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,6 +65,13 @@ wrap(avcodec_encode_audio2(AVCodecContext *avctx,
got_packet_ptr);
}
+wrap(avcodec_encode_video(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size,
+ const AVFrame *pict))
+{
+ testxmmclobbers(avcodec_encode_video, avctx, buf, buf_size, pict);
+}
+
wrap(avcodec_encode_subtitle(AVCodecContext *avctx,
uint8_t *buf, int buf_size,
const AVSubtitle *sub))
diff --git a/libavcodec/x86/xvididct.asm b/libavcodec/x86/xvididct.asm
new file mode 100644
index 0000000000..0220885da6
--- /dev/null
+++ b/libavcodec/x86/xvididct.asm
@@ -0,0 +1,983 @@
+; XVID MPEG-4 VIDEO CODEC
+;
+; Conversion from gcc syntax to x264asm syntax with modifications
+; by Christophe Gisquet <christophe.gisquet@gmail.com>
+;
+; =========== SSE2 inverse discrete cosine transform ===========
+;
+; Copyright(C) 2003 Pascal Massimino <skal@planet-d.net>
+;
+; Conversion to gcc syntax with modifications
+; by Alexander Strange <astrange@ithinksw.com>
+;
+; Originally from dct/x86_asm/fdct_sse2_skal.asm in Xvid.
+;
+; Vertical pass is an implementation of the scheme:
+; Loeffler C., Ligtenberg A., and Moschytz C.S.:
+; Practical Fast 1D DCT Algorithm with Eleven Multiplications,
+; Proc. ICASSP 1989, 988-991.
+;
+; Horizontal pass is a double 4x4 vector/matrix multiplication,
+; (see also Intel's Application Note 922:
+; http://developer.intel.com/vtune/cbts/strmsimd/922down.htm
+; Copyright (C) 1999 Intel Corporation)
+;
+; More details at http://skal.planet-d.net/coding/dct.html
+;
+; ======= MMX and XMM forward discrete cosine transform =======
+;
+; Copyright(C) 2001 Peter Ross <pross@xvid.org>
+;
+; Originally provided by Intel at AP-922
+; http://developer.intel.com/vtune/cbts/strmsimd/922down.htm
+; (See more app notes at http://developer.intel.com/vtune/cbts/strmsimd/appnotes.htm)
+; but in a limited edition.
+; New macro implements a column part for precise iDCT
+; The routine precision now satisfies IEEE standard 1180-1990.
+;
+; Copyright(C) 2000-2001 Peter Gubanov <peter@elecard.net.ru>
+; Rounding trick Copyright(C) 2000 Michel Lespinasse <walken@zoy.org>
+;
+; http://www.elecard.com/peter/idct.html
+; http://www.linuxvideo.org/mpeg2dec/
+;
+; These examples contain code fragments for first stage iDCT 8x8
+; (for rows) and first stage DCT 8x8 (for columns)
+;
+; conversion to gcc syntax by Michael Niedermayer
+;
+; ======================================================================
+;
+; This file is part of FFmpeg.
+;
+; FFmpeg is free software; you can redistribute it and/or
+; modify it under the terms of the GNU Lesser General Public
+; License as published by the Free Software Foundation; either
+; version 2.1 of the License, or (at your option) any later version.
+;
+; FFmpeg is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; Lesser General Public License for more details.
+;
+; You should have received a copy of the GNU Lesser General Public License
+; along with FFmpeg; if not, write to the Free Software Foundation,
+; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+; Similar to tg_1_16 in MMX code
+tan1: times 8 dw 13036
+tan2: times 8 dw 27146
+tan3: times 8 dw 43790
+sqrt2: times 8 dw 23170
+
+; SSE2 tables
+iTab1: dw 0x4000, 0x539f, 0xc000, 0xac61, 0x4000, 0xdd5d, 0x4000, 0xdd5d
+ dw 0x4000, 0x22a3, 0x4000, 0x22a3, 0xc000, 0x539f, 0x4000, 0xac61
+ dw 0x3249, 0x11a8, 0x4b42, 0xee58, 0x11a8, 0x4b42, 0x11a8, 0xcdb7
+ dw 0x58c5, 0x4b42, 0xa73b, 0xcdb7, 0x3249, 0xa73b, 0x4b42, 0xa73b
+iTab2: dw 0x58c5, 0x73fc, 0xa73b, 0x8c04, 0x58c5, 0xcff5, 0x58c5, 0xcff5
+ dw 0x58c5, 0x300b, 0x58c5, 0x300b, 0xa73b, 0x73fc, 0x58c5, 0x8c04
+ dw 0x45bf, 0x187e, 0x6862, 0xe782, 0x187e, 0x6862, 0x187e, 0xba41
+ dw 0x7b21, 0x6862, 0x84df, 0xba41, 0x45bf, 0x84df, 0x6862, 0x84df
+iTab3: dw 0x539f, 0x6d41, 0xac61, 0x92bf, 0x539f, 0xd2bf, 0x539f, 0xd2bf
+ dw 0x539f, 0x2d41, 0x539f, 0x2d41, 0xac61, 0x6d41, 0x539f, 0x92bf
+ dw 0x41b3, 0x1712, 0x6254, 0xe8ee, 0x1712, 0x6254, 0x1712, 0xbe4d
+ dw 0x73fc, 0x6254, 0x8c04, 0xbe4d, 0x41b3, 0x8c04, 0x6254, 0x8c04
+iTab4: dw 0x4b42, 0x6254, 0xb4be, 0x9dac, 0x4b42, 0xd746, 0x4b42, 0xd746
+ dw 0x4b42, 0x28ba, 0x4b42, 0x28ba, 0xb4be, 0x6254, 0x4b42, 0x9dac
+ dw 0x3b21, 0x14c3, 0x587e, 0xeb3d, 0x14c3, 0x587e, 0x14c3, 0xc4df
+ dw 0x6862, 0x587e, 0x979e, 0xc4df, 0x3b21, 0x979e, 0x587e, 0x979e
+
+%if ARCH_X86_32
+; -----------------------------------------------------------------------------
+;
+; The first stage iDCT 8x8 - inverse DCTs of rows
+;
+; -----------------------------------------------------------------------------
+; The 8-point inverse DCT direct algorithm
+; -----------------------------------------------------------------------------
+;
+; static const short w[32] = {
+; FIX(cos_4_16), FIX(cos_2_16), FIX(cos_4_16), FIX(cos_6_16),
+; FIX(cos_4_16), FIX(cos_6_16), -FIX(cos_4_16), -FIX(cos_2_16),
+; FIX(cos_4_16), -FIX(cos_6_16), -FIX(cos_4_16), FIX(cos_2_16),
+; FIX(cos_4_16), -FIX(cos_2_16), FIX(cos_4_16), -FIX(cos_6_16),
+; FIX(cos_1_16), FIX(cos_3_16), FIX(cos_5_16), FIX(cos_7_16),
+; FIX(cos_3_16), -FIX(cos_7_16), -FIX(cos_1_16), -FIX(cos_5_16),
+; FIX(cos_5_16), -FIX(cos_1_16), FIX(cos_7_16), FIX(cos_3_16),
+; FIX(cos_7_16), -FIX(cos_5_16), FIX(cos_3_16), -FIX(cos_1_16) };
+;
+; #define DCT_8_INV_ROW(x, y)
+; {
+; int a0, a1, a2, a3, b0, b1, b2, b3;
+;
+; a0 = x[0] * w[0] + x[2] * w[1] + x[4] * w[2] + x[6] * w[3];
+; a1 = x[0] * w[4] + x[2] * w[5] + x[4] * w[6] + x[6] * w[7];
+; a2 = x[0] * w[8] + x[2] * w[9] + x[4] * w[10] + x[6] * w[11];
+; a3 = x[0] * w[12] + x[2] * w[13] + x[4] * w[14] + x[6] * w[15];
+; b0 = x[1] * w[16] + x[3] * w[17] + x[5] * w[18] + x[7] * w[19];
+; b1 = x[1] * w[20] + x[3] * w[21] + x[5] * w[22] + x[7] * w[23];
+; b2 = x[1] * w[24] + x[3] * w[25] + x[5] * w[26] + x[7] * w[27];
+; b3 = x[1] * w[28] + x[3] * w[29] + x[5] * w[30] + x[7] * w[31];
+;
+; y[0] = SHIFT_ROUND(a0 + b0);
+; y[1] = SHIFT_ROUND(a1 + b1);
+; y[2] = SHIFT_ROUND(a2 + b2);
+; y[3] = SHIFT_ROUND(a3 + b3);
+; y[4] = SHIFT_ROUND(a3 - b3);
+; y[5] = SHIFT_ROUND(a2 - b2);
+; y[6] = SHIFT_ROUND(a1 - b1);
+; y[7] = SHIFT_ROUND(a0 - b0);
+; }
+;
+; -----------------------------------------------------------------------------
+;
+; In this implementation the outputs of the iDCT-1D are multiplied
+; for rows 0,4 - by cos_4_16,
+; for rows 1,7 - by cos_1_16,
+; for rows 2,6 - by cos_2_16,
+; for rows 3,5 - by cos_3_16
+; and are shifted to the left for better accuracy.
+;
+; For the constants used,
+; FIX(float_const) = (short) (float_const * (1 << 15) + 0.5)
+;
+; -----------------------------------------------------------------------------
+
+; -----------------------------------------------------------------------------
+; Tables for mmx processors
+; -----------------------------------------------------------------------------
+
+; Table for rows 0,4 - constants are multiplied by cos_4_16
+tab_i_04_mmx: dw 16384, 16384, 16384, -16384
+ dw 21407, 8867, 8867, -21407 ; w07 w05 w03 w01
+ dw 16384, -16384, 16384, 16384 ; w14 w12 w10 w08
+ dw -8867, 21407, -21407, -8867 ; w15 w13 w11 w09
+ dw 22725, 12873, 19266, -22725 ; w22 w20 w18 w16
+ dw 19266, 4520, -4520, -12873 ; w23 w21 w19 w17
+ dw 12873, 4520, 4520, 19266 ; w30 w28 w26 w24
+ dw -22725, 19266, -12873, -22725 ; w31 w29 w27 w25
+; Table for rows 1,7 - constants are multiplied by cos_1_16
+ dw 22725, 22725, 22725, -22725 ; movq-> w06 w04 w02 w00
+ dw 29692, 12299, 12299, -29692 ; w07 w05 w03 w01
+ dw 22725, -22725, 22725, 22725 ; w14 w12 w10 w08
+ dw -12299, 29692, -29692, -12299 ; w15 w13 w11 w09
+ dw 31521, 17855, 26722, -31521 ; w22 w20 w18 w16
+ dw 26722, 6270, -6270, -17855 ; w23 w21 w19 w17
+ dw 17855, 6270, 6270, 26722 ; w30 w28 w26 w24
+ dw -31521, 26722, -17855, -31521 ; w31 w29 w27 w25
+; Table for rows 2,6 - constants are multiplied by cos_2_16
+ dw 21407, 21407, 21407, -21407 ; movq-> w06 w04 w02 w00
+ dw 27969, 11585, 11585, -27969 ; w07 w05 w03 w01
+ dw 21407, -21407, 21407, 21407 ; w14 w12 w10 w08
+ dw -11585, 27969, -27969, -11585 ; w15 w13 w11 w09
+ dw 29692, 16819, 25172, -29692 ; w22 w20 w18 w16
+ dw 25172, 5906, -5906, -16819 ; w23 w21 w19 w17
+ dw 16819, 5906, 5906, 25172 ; w30 w28 w26 w24
+ dw -29692, 25172, -16819, -29692 ; w31 w29 w27 w25
+; Table for rows 3,5 - constants are multiplied by cos_3_16
+ dw 19266, 19266, 19266, -19266 ; movq-> w06 w04 w02 w00
+ dw 25172, 10426, 10426, -25172 ; w07 w05 w03 w01
+ dw 19266, -19266, 19266, 19266 ; w14 w12 w10 w08
+ dw -10426, 25172, -25172, -10426 ; w15 w13 w11 w09
+ dw 26722, 15137, 22654, -26722 ; w22 w20 w18 w16
+ dw 22654, 5315, -5315, -15137 ; w23 w21 w19 w17
+ dw 15137, 5315, 5315, 22654 ; w30 w28 w26 w24
+ dw -26722, 22654, -15137, -26722 ; w31 w29 w27 w25
+
+; -----------------------------------------------------------------------------
+; Tables for xmm processors
+; -----------------------------------------------------------------------------
+
+; %3 for rows 0,4 - constants are multiplied by cos_4_16
+tab_i_04_xmm: dw 16384, 21407, 16384, 8867 ; movq-> w05 w04 w01 w00
+ dw 16384, 8867, -16384, -21407 ; w07 w06 w03 w02
+ dw 16384, -8867, 16384, -21407 ; w13 w12 w09 w08
+ dw -16384, 21407, 16384, -8867 ; w15 w14 w11 w10
+ dw 22725, 19266, 19266, -4520 ; w21 w20 w17 w16
+ dw 12873, 4520, -22725, -12873 ; w23 w22 w19 w18
+ dw 12873, -22725, 4520, -12873 ; w29 w28 w25 w24
+ dw 4520, 19266, 19266, -22725 ; w31 w30 w27 w26
+; %3 for rows 1,7 - constants are multiplied by cos_1_16
+ dw 22725, 29692, 22725, 12299 ; movq-> w05 w04 w01 w00
+ dw 22725, 12299, -22725, -29692 ; w07 w06 w03 w02
+ dw 22725, -12299, 22725, -29692 ; w13 w12 w09 w08
+ dw -22725, 29692, 22725, -12299 ; w15 w14 w11 w10
+ dw 31521, 26722, 26722, -6270 ; w21 w20 w17 w16
+ dw 17855, 6270, -31521, -17855 ; w23 w22 w19 w18
+ dw 17855, -31521, 6270, -17855 ; w29 w28 w25 w24
+ dw 6270, 26722, 26722, -31521 ; w31 w30 w27 w26
+; %3 for rows 2,6 - constants are multiplied by cos_2_16
+ dw 21407, 27969, 21407, 11585 ; movq-> w05 w04 w01 w00
+ dw 21407, 11585, -21407, -27969 ; w07 w06 w03 w02
+ dw 21407, -11585, 21407, -27969 ; w13 w12 w09 w08
+ dw -21407, 27969, 21407, -11585 ; w15 w14 w11 w10
+ dw 29692, 25172, 25172, -5906 ; w21 w20 w17 w16
+ dw 16819, 5906, -29692, -16819 ; w23 w22 w19 w18
+ dw 16819, -29692, 5906, -16819 ; w29 w28 w25 w24
+ dw 5906, 25172, 25172, -29692 ; w31 w30 w27 w26
+; %3 for rows 3,5 - constants are multiplied by cos_3_16
+ dw 19266, 25172, 19266, 10426 ; movq-> w05 w04 w01 w00
+ dw 19266, 10426, -19266, -25172 ; w07 w06 w03 w02
+ dw 19266, -10426, 19266, -25172 ; w13 w12 w09 w08
+ dw -19266, 25172, 19266, -10426 ; w15 w14 w11 w10
+ dw 26722, 22654, 22654, -5315 ; w21 w20 w17 w16
+ dw 15137, 5315, -26722, -15137 ; w23 w22 w19 w18
+ dw 15137, -26722, 5315, -15137 ; w29 w28 w25 w24
+ dw 5315, 22654, 22654, -26722 ; w31 w30 w27 w26
+%endif ; ~ARCH_X86_32
+
+; Similar to rounder_0 in MMX code
+; 4 first similar, then: 4*8->6*16 5*8->4*16 6/7*8->5*16
+walkenIdctRounders: times 4 dd 65536
+ times 4 dd 3597
+ times 4 dd 2260
+ times 4 dd 1203
+ times 4 dd 120
+ times 4 dd 512
+ times 2 dd 0
+
+pb_127: times 8 db 127
+
+SECTION .text
+
+; Temporary storage before the column pass
+%define ROW1 xmm6
+%define ROW3 xmm4
+%define ROW5 xmm5
+%define ROW7 xmm7
+
+%macro CLEAR_ODD 1
+ pxor %1, %1
+%endmacro
+%macro PUT_ODD 1
+ pshufhw %1, xmm2, 0x1B
+%endmacro
+
+%macro MOV32 2
+%if ARCH_X86_32
+ movdqa %2, %1
+%endif
+%endmacro
+
+%macro CLEAR_EVEN 1
+%if ARCH_X86_64
+ CLEAR_ODD %1
+%endif
+%endmacro
+
+%macro PUT_EVEN 1
+%if ARCH_X86_64
+ PUT_ODD %1
+%else
+ pshufhw xmm2, xmm2, 0x1B
+ movdqa %1, xmm2
+%endif
+%endmacro
+
+%if ARCH_X86_64
+%define ROW0 xmm8
+%define REG0 ROW0
+%define ROW2 xmm9
+%define REG2 ROW2
+%define ROW4 xmm10
+%define REG4 ROW4
+%define ROW6 xmm11
+%define REG6 ROW6
+%define XMMS xmm12
+%define SREG2 REG2
+%define TAN3 xmm13
+%define TAN1 xmm14
+%else
+%define ROW0 [BLOCK + 0*16]
+%define REG0 xmm4
+%define ROW2 [BLOCK + 2*16]
+%define REG2 xmm4
+%define ROW4 [BLOCK + 4*16]
+%define REG4 xmm6
+%define ROW6 [BLOCK + 6*16]
+%define REG6 xmm6
+%define XMMS xmm2
+%define SREG2 xmm7
+%define TAN3 xmm0
+%define TAN1 xmm2
+%endif
+
+%macro JZ 2
+ test %1, %1
+ jz .%2
+%endmacro
+
+%macro JNZ 2
+ test %1, %1
+ jnz .%2
+%endmacro
+
+%macro TEST_ONE_ROW 4 ; src, reg, clear, arg
+ %3 %4
+ movq mm1, [%1]
+ por mm1, [%1 + 8]
+ paddusb mm1, mm0
+ pmovmskb %2, mm1
+%endmacro
+
+;row1, row2, reg1, reg2, clear1, arg1, clear2, arg2
+%macro TEST_TWO_ROWS 8
+ %5 %6
+ %7 %8
+ movq mm1, [%1 + 0]
+ por mm1, [%1 + 8]
+ movq mm2, [%2 + 0]
+ por mm2, [%2 + 8]
+ paddusb mm1, mm0
+ paddusb mm2, mm0
+ pmovmskb %3, mm1
+ pmovmskb %4, mm2
+%endmacro
+
+; IDCT pass on rows.
+%macro iMTX_MULT 4-5 ; src, table, put, arg, rounder
+ movdqa xmm3, [%1]
+ movdqa xmm0, xmm3
+ pshufd xmm1, xmm3, 0x11 ; 4602
+ punpcklqdq xmm0, xmm0 ; 0246
+ pmaddwd xmm0, [%2]
+ pmaddwd xmm1, [%2+16]
+ pshufd xmm2, xmm3, 0xBB ; 5713
+ punpckhqdq xmm3, xmm3 ; 1357
+ pmaddwd xmm2, [%2+32]
+ pmaddwd xmm3, [%2+48]
+ paddd xmm0, xmm1
+ paddd xmm2, xmm3
+%if %0 == 5
+ paddd xmm0, [walkenIdctRounders+%5]
+%endif
+ movdqa xmm3, xmm2
+ paddd xmm2, xmm0
+ psubd xmm0, xmm3
+ psrad xmm2, 11
+ psrad xmm0, 11
+ packssdw xmm2, xmm0
+ %3 %4
+%endmacro
+
+%macro iLLM_HEAD 0
+ movdqa TAN3, [tan3]
+ movdqa TAN1, [tan1]
+%endmacro
+
+%macro FIRST_HALF 2 ; %1=dct %2=type(normal,add,put)
+ psraw xmm5, 6
+ psraw REG0, 6
+ psraw TAN3, 6
+ psraw xmm3, 6
+ ; dct coeffs must still be written for AC prediction
+%if %2 == 0
+ movdqa [%1+1*16], TAN3
+ movdqa [%1+2*16], xmm3
+ movdqa [%1+5*16], REG0
+ movdqa [%1+6*16], xmm5
+%else
+ ; Must now load args as gprs are no longer used for masks
+ ; DEST is set to where address of dest was loaded
+ %if ARCH_X86_32
+ %if %2 == 2 ; Not enough xmms, store
+ movdqa [%1+1*16], TAN3
+ movdqa [%1+2*16], xmm3
+ movdqa [%1+5*16], REG0
+ movdqa [%1+6*16], xmm5
+ %endif
+ %xdefine DEST r2q ; BLOCK is r0, stride r1
+ movifnidn DEST, destm
+ movifnidn strideq, stridem
+ %else
+ %xdefine DEST r0q
+ %endif
+ lea r3q, [3*strideq]
+ %if %2 == 1
+ packuswb TAN3, xmm3
+ packuswb xmm5, REG0
+ movq [DEST + strideq], TAN3
+ movhps [DEST + 2*strideq], TAN3
+ ; REG0 and TAN3 are now available (and likely used in second half)
+ %endif
+%endif
+%endmacro
+
+%macro SECOND_HALF 6 ; %1=dct %2=type(normal,add,put) 3-6: xmms
+ psraw %3, 6
+ psraw %4, 6
+ psraw %5, 6
+ psraw %6, 6
+ ; dct coeffs must still be written for AC prediction
+%if %2 == 0
+ movdqa [%1+0*16], %3
+ movdqa [%1+3*16], %5
+ movdqa [%1+4*16], %6
+ movdqa [%1+7*16], %4
+%elif %2 == 1
+ packuswb %3, %5
+ packuswb %6, %4
+ ; address of dest may have been loaded
+ movq [DEST], %3
+ movhps [DEST + r3q], %3
+ lea DEST, [DEST + 4*strideq]
+ movq [DEST], %6
+ movhps [DEST + r3q], %6
+ ; and now write remainder of first half
+ movq [DEST + 2*strideq], xmm5
+ movhps [DEST + strideq], xmm5
+%elif %2 == 2
+ pxor xmm0, xmm0
+ %if ARCH_X86_32
+ ; free: m3 REG0=m4 m5
+ ; input: m1, m7, m2, m6
+ movq xmm3, [DEST+0*strideq]
+ movq xmm4, [DEST+1*strideq]
+ punpcklbw xmm3, xmm0
+ punpcklbw xmm4, xmm0
+ paddsw xmm3, %3
+ paddsw xmm4, [%1 + 1*16]
+ movq %3, [DEST+2*strideq]
+ movq xmm5, [DEST+ r3q]
+ punpcklbw %3, xmm0
+ punpcklbw xmm5, xmm0
+ paddsw %3, [%1 + 2*16]
+ paddsw xmm5, %5
+ packuswb xmm3, xmm4
+ packuswb %3, xmm5
+ movq [DEST+0*strideq], xmm3
+ movhps [DEST+1*strideq], xmm3
+ movq [DEST+2*strideq], %3
+ movhps [DEST+ r3q], %3
+ lea DEST, [DEST+4*strideq]
+ movq xmm3, [DEST+0*strideq]
+ movq xmm4, [DEST+1*strideq]
+ movq %3, [DEST+2*strideq]
+ movq xmm5, [DEST+ r3q]
+ punpcklbw xmm3, xmm0
+ punpcklbw xmm4, xmm0
+ punpcklbw %3, xmm0
+ punpcklbw xmm5, xmm0
+ paddsw xmm3, %6
+ paddsw xmm4, [%1 + 5*16]
+ paddsw %3, [%1 + 6*16]
+ paddsw xmm5, %4
+ packuswb xmm3, xmm4
+ packuswb %3, xmm5
+ movq [DEST+0*strideq], xmm3
+ movhps [DEST+1*strideq], xmm3
+ movq [DEST+2*strideq], %3
+ movhps [DEST+ r3q], %3
+ %else
+ ; l1:TAN3=m13 l2:m3 l5:REG0=m8 l6=m5
+ ; input: m1, m7/SREG2=m9, TAN1=m14, REG4=m10
+ movq xmm2, [DEST+0*strideq]
+ movq xmm4, [DEST+1*strideq]
+ movq xmm12, [DEST+2*strideq]
+ movq xmm11, [DEST+ r3q]
+ punpcklbw xmm2, xmm0
+ punpcklbw xmm4, xmm0
+ punpcklbw xmm12, xmm0
+ punpcklbw xmm11, xmm0
+ paddsw xmm2, %3
+ paddsw xmm4, TAN3
+ paddsw xmm12, xmm3
+ paddsw xmm11, %5
+ packuswb xmm2, xmm4
+ packuswb xmm12, xmm11
+ movq [DEST+0*strideq], xmm2
+ movhps [DEST+1*strideq], xmm2
+ movq [DEST+2*strideq], xmm12
+ movhps [DEST+ r3q], xmm12
+ lea DEST, [DEST+4*strideq]
+ movq xmm2, [DEST+0*strideq]
+ movq xmm4, [DEST+1*strideq]
+ movq xmm12, [DEST+2*strideq]
+ movq xmm11, [DEST+ r3q]
+ punpcklbw xmm2, xmm0
+ punpcklbw xmm4, xmm0
+ punpcklbw xmm12, xmm0
+ punpcklbw xmm11, xmm0
+ paddsw xmm2, %6
+ paddsw xmm4, REG0
+ paddsw xmm12, xmm5
+ paddsw xmm11, %4
+ packuswb xmm2, xmm4
+ packuswb xmm12, xmm11
+ movq [DEST+0*strideq], xmm2
+ movhps [DEST+1*strideq], xmm2
+ movq [DEST+2*strideq], xmm12
+ movhps [DEST+ r3q], xmm12
+ %endif
+%endif
+%endmacro
+
+
+; IDCT pass on columns.
+%macro iLLM_PASS 2 ; %1=dct %2=type(normal,add,put)
+ movdqa xmm1, TAN3
+ movdqa xmm3, TAN1
+ pmulhw TAN3, xmm4
+ pmulhw xmm1, xmm5
+ paddsw TAN3, xmm4
+ paddsw xmm1, xmm5
+ psubsw TAN3, xmm5
+ paddsw xmm1, xmm4
+ pmulhw xmm3, xmm7
+ pmulhw TAN1, xmm6
+ paddsw xmm3, xmm6
+ psubsw TAN1, xmm7
+ movdqa xmm7, xmm3
+ movdqa xmm6, TAN1
+ psubsw xmm3, xmm1
+ psubsw TAN1, TAN3
+ paddsw xmm1, xmm7
+ paddsw TAN3, xmm6
+ movdqa xmm6, xmm3
+ psubsw xmm3, TAN3
+ paddsw TAN3, xmm6
+ movdqa xmm4, [sqrt2]
+ pmulhw xmm3, xmm4
+ pmulhw TAN3, xmm4
+ paddsw TAN3, TAN3
+ paddsw xmm3, xmm3
+ movdqa xmm7, [tan2]
+ MOV32 ROW2, REG2
+ MOV32 ROW6, REG6
+ movdqa xmm5, xmm7
+ pmulhw xmm7, REG6
+ pmulhw xmm5, REG2
+ paddsw xmm7, REG2
+ psubsw xmm5, REG6
+ MOV32 ROW0, REG0
+ MOV32 ROW4, REG4
+ MOV32 TAN1, [BLOCK]
+ movdqa XMMS, REG0
+ psubsw REG0, REG4
+ paddsw REG4, XMMS
+ movdqa XMMS, REG4
+ psubsw REG4, xmm7
+ paddsw xmm7, XMMS
+ movdqa XMMS, REG0
+ psubsw REG0, xmm5
+ paddsw xmm5, XMMS
+ movdqa XMMS, xmm5
+ psubsw xmm5, TAN3
+ paddsw TAN3, XMMS
+ movdqa XMMS, REG0
+ psubsw REG0, xmm3
+ paddsw xmm3, XMMS
+ MOV32 [BLOCK], TAN1
+
+ FIRST_HALF %1, %2
+
+ movdqa xmm0, xmm7
+ movdqa xmm4, REG4
+ psubsw xmm7, xmm1
+ psubsw REG4, TAN1
+ paddsw xmm1, xmm0
+ paddsw TAN1, xmm4
+
+ SECOND_HALF %1, %2, xmm1, xmm7, TAN1, REG4
+%endmacro
+
+; IDCT pass on columns, assuming rows 4-7 are zero
+%macro iLLM_PASS_SPARSE 2 ; %1=dct %2=type(normal,put,add)
+ pmulhw TAN3, xmm4
+ paddsw TAN3, xmm4
+ movdqa xmm3, xmm6
+ pmulhw TAN1, xmm6
+ movdqa xmm1, xmm4
+ psubsw xmm3, xmm1
+ paddsw xmm1, xmm6
+ movdqa xmm6, TAN1
+ psubsw TAN1, TAN3
+ paddsw TAN3, xmm6
+ movdqa xmm6, xmm3
+ psubsw xmm3, TAN3
+ paddsw TAN3, xmm6
+ movdqa xmm4, [sqrt2]
+ pmulhw xmm3, xmm4
+ pmulhw TAN3, xmm4
+ paddsw TAN3, TAN3
+ paddsw xmm3, xmm3
+ movdqa xmm5, [tan2]
+ MOV32 ROW2, SREG2
+ pmulhw xmm5, SREG2
+ MOV32 ROW0, REG0
+ movdqa xmm6, REG0
+ psubsw xmm6, SREG2
+ paddsw SREG2, REG0
+ MOV32 TAN1, [BLOCK]
+ movdqa XMMS, REG0
+ psubsw REG0, xmm5
+ paddsw xmm5, XMMS
+ movdqa XMMS, xmm5
+ psubsw xmm5, TAN3
+ paddsw TAN3, XMMS
+ movdqa XMMS, REG0
+ psubsw REG0, xmm3
+ paddsw xmm3, XMMS
+ MOV32 [BLOCK], TAN1
+
+ FIRST_HALF %1, %2
+
+ movdqa xmm0, SREG2
+ movdqa xmm4, xmm6
+ psubsw SREG2, xmm1
+ psubsw xmm6, TAN1
+ paddsw xmm1, xmm0
+ paddsw TAN1, xmm4
+
+ SECOND_HALF %1, %2, xmm1, SREG2, TAN1, xmm6
+%endmacro
+
+%macro IDCT_SSE2 1 ; 0=normal 1=put 2=add
+%if %1 == 0 || ARCH_X86_32
+ %define GPR0 r1d
+ %define GPR1 r2d
+ %define GPR2 r3d
+ %define GPR3 r4d
+ %define NUM_GPRS 5
+%else
+ %define GPR0 r3d
+ %define GPR1 r4d
+ %define GPR2 r5d
+ %define GPR3 r6d
+ %define NUM_GPRS 7
+%endif
+%if %1 == 0
+cglobal xvid_idct, 1, NUM_GPRS, 8+7*ARCH_X86_64, block
+%xdefine BLOCK blockq
+%else
+ %if %1 == 1
+cglobal xvid_idct_put, 0, NUM_GPRS, 8+7*ARCH_X86_64, dest, stride, block
+ %else
+cglobal xvid_idct_add, 0, NUM_GPRS, 8+7*ARCH_X86_64, dest, stride, block
+ %endif
+ %if ARCH_X86_64
+ %xdefine BLOCK blockq
+ %else
+ mov r0q, blockm
+ %xdefine BLOCK r0q
+ %endif
+%endif
+ movq mm0, [pb_127]
+ iMTX_MULT BLOCK + 0*16, iTab1, PUT_EVEN, ROW0, 0*16
+ iMTX_MULT BLOCK + 1*16, iTab2, PUT_ODD, ROW1, 1*16
+ iMTX_MULT BLOCK + 2*16, iTab3, PUT_EVEN, ROW2, 2*16
+
+ TEST_TWO_ROWS BLOCK + 3*16, BLOCK + 4*16, GPR0, GPR1, CLEAR_ODD, ROW3, CLEAR_EVEN, ROW4 ; a, c
+ JZ GPR0, col1
+ iMTX_MULT BLOCK + 3*16, iTab4, PUT_ODD, ROW3, 3*16
+.col1:
+ TEST_TWO_ROWS BLOCK + 5*16, BLOCK + 6*16, GPR0, GPR2, CLEAR_ODD, ROW5, CLEAR_EVEN, ROW6 ; a, d
+ TEST_ONE_ROW BLOCK + 7*16, GPR3, CLEAR_ODD, ROW7 ; esi
+
+ iLLM_HEAD
+ JNZ GPR1, 2
+ JNZ GPR0, 3
+ JNZ GPR2, 4
+ JNZ GPR3, 5
+ iLLM_PASS_SPARSE BLOCK, %1
+ jmp .6
+.2:
+ iMTX_MULT BLOCK + 4*16, iTab1, PUT_EVEN, ROW4
+.3:
+ iMTX_MULT BLOCK + 5*16, iTab4, PUT_ODD, ROW5, 4*16
+ JZ GPR2, col2
+.4:
+ iMTX_MULT BLOCK + 6*16, iTab3, PUT_EVEN, ROW6, 5*16
+.col2:
+ JZ GPR3, col3
+.5:
+ iMTX_MULT BLOCK + 7*16, iTab2, PUT_ODD, ROW7, 5*16
+.col3:
+%if ARCH_X86_32
+ iLLM_HEAD
+%endif
+ iLLM_PASS BLOCK, %1
+.6:
+ RET
+%endmacro
+
+INIT_XMM sse2
+IDCT_SSE2 0
+IDCT_SSE2 1
+IDCT_SSE2 2
+
+%if ARCH_X86_32
+
+; %1=offset %2=tab_offset
+; %3=rnd_offset where 4*8->6*16 5*8->4*16 6/7*8->5*16
+%macro DCT_8_INV_ROW 3
+ movq mm0, [r0+16*%1+0] ; 0 ; x3 x2 x1 x0
+ movq mm1, [r0+16*%1+8] ; 1 ; x7 x6 x5 x4
+ movq mm2, mm0 ; 2 ; x3 x2 x1 x0
+ movq mm3, [%2+ 0] ; 3 ; w06 w04 w02 w00
+%if cpuflag(mmxext)
+ pshufw mm0, mm0, 0x88 ; x2 x0 x2 x0
+ movq mm4, [%2+ 8] ; 4 ; w07 w06 w03 w02
+ movq mm5, mm1 ; 5 ; x7 x6 x5 x4
+ pmaddwd mm3, mm0 ; x2*w05+x0*w04 x2*w01+x0*w00
+ movq mm6, [%2+32] ; 6 ; w21 w20 w17 w16
+ pshufw mm1, mm1, 0x88 ; x6 x4 x6 x4
+ pmaddwd mm4, mm1 ; x6*w07+x4*w06 x6*w03+x4*w02
+ movq mm7, [%2+40] ; 7; w23 w22 w19 w18
+ pshufw mm2, mm2, 0xdd ; x3 x1 x3 x1
+ pmaddwd mm6, mm2 ; x3*w21+x1*w20 x3*w17+x1*w16
+ pshufw mm5, mm5, 0xdd ; x7 x5 x7 x5
+ pmaddwd mm7, mm5 ; x7*w23+x5*w22 x7*w19+x5*w18
+ paddd mm3, [walkenIdctRounders + %3] ; +%3
+ pmaddwd mm0, [%2+16] ; x2*w13+x0*w12 x2*w09+x0*w08
+ paddd mm3, mm4 ; 4 ; a1=sum(even1) a0=sum(even0)
+ pmaddwd mm1, [%2+24] ; x6*w15+x4*w14 x6*w11+x4*w10
+ movq mm4, mm3 ; 4 ; a1 a0
+ pmaddwd mm2, [%2+48] ; x3*w29+x1*w28 x3*w25+x1*w24
+ paddd mm6, mm7 ; 7 ; b1=sum(odd1) b0=sum(odd0)
+ pmaddwd mm5, [%2+56] ; x7*w31+x5*w30 x7*w27+x5*w26
+ paddd mm3, mm6 ; a1+b1 a0+b0
+ paddd mm0, [walkenIdctRounders + %3] ; +%3
+ psrad mm3, 11 ; y1=a1+b1 y0=a0+b0
+ paddd mm0, mm1 ; 1 ; a3=sum(even3) a2=sum(even2)
+ psubd mm4, mm6 ; 6 ; a1-b1 a0-b0
+ movq mm7, mm0 ; 7 ; a3 a2
+ paddd mm2, mm5 ; 5 ; b3=sum(odd3) b2=sum(odd2)
+ paddd mm0, mm2 ; a3+b3 a2+b2
+ psrad mm4, 11 ; y6=a1-b1 y7=a0-b0
+ psubd mm7, mm2 ; 2 ; a3-b3 a2-b2
+ psrad mm0, 11 ; y3=a3+b3 y2=a2+b2
+ psrad mm7, 11 ; y4=a3-b3 y5=a2-b2
+ packssdw mm3, mm0 ; 0 ; y3 y2 y1 y0
+ packssdw mm7, mm4 ; 4 ; y6 y7 y4 y5
+ movq [r0+16*%1+0], mm3 ; 3 ; save y3 y2 y1 y0
+ pshufw mm7, mm7, 0xb1 ; y7 y6 y5 y4
+%else
+ punpcklwd mm0, mm1 ; x5 x1 x4 x0
+ movq mm5, mm0 ; 5 ; x5 x1 x4 x0
+ punpckldq mm0, mm0 ; x4 x0 x4 x0
+ movq mm4, [%2+ 8] ; 4 ; w07 w05 w03 w01
+ punpckhwd mm2, mm1 ; 1 ; x7 x3 x6 x2
+ pmaddwd mm3, mm0 ; x4*w06+x0*w04 x4*w02+x0*w00
+ movq mm6, mm2 ; 6 ; x7 x3 x6 x2
+ movq mm1, [%2+32] ; 1 ; w22 w20 w18 w16
+ punpckldq mm2, mm2 ; x6 x2 x6 x2
+ pmaddwd mm4, mm2 ; x6*w07+x2*w05 x6*w03+x2*w01
+ punpckhdq mm5, mm5 ; x5 x1 x5 x1
+ pmaddwd mm0, [%2+16] ; x4*w14+x0*w12 x4*w10+x0*w08
+ punpckhdq mm6, mm6 ; x7 x3 x7 x3
+ movq mm7, [%2+40] ; 7 ; w23 w21 w19 w17
+ pmaddwd mm1, mm5 ; x5*w22+x1*w20 x5*w18+x1*w16
+ paddd mm3, [walkenIdctRounders + %3] ; +%3
+ pmaddwd mm7, mm6 ; x7*w23+x3*w21 x7*w19+x3*w17
+ pmaddwd mm2, [%2+24] ; x6*w15+x2*w13 x6*w11+x2*w09
+ paddd mm3, mm4 ; 4 ; a1=sum(even1) a0=sum(even0)
+ pmaddwd mm5, [%2+48] ; x5*w30+x1*w28 x5*w26+x1*w24
+ movq mm4, mm3 ; 4 ; a1 a0
+ pmaddwd mm6, [%2+56] ; x7*w31+x3*w29 x7*w27+x3*w25
+ paddd mm1, mm7 ; 7 ; b1=sum(odd1) b0=sum(odd0)
+ paddd mm0, [walkenIdctRounders + %3] ; +%3
+ psubd mm3, mm1 ; a1-b1 a0-b0
+ psrad mm3, 11 ; y6=a1-b1 y7=a0-b0
+ paddd mm1, mm4 ; 4 ; a1+b1 a0+b0
+ paddd mm0, mm2 ; 2 ; a3=sum(even3) a2=sum(even2)
+ psrad mm1, 11 ; y1=a1+b1 y0=a0+b0
+ paddd mm5, mm6 ; 6 ; b3=sum(odd3) b2=sum(odd2)
+ movq mm4, mm0 ; 4 ; a3 a2
+ paddd mm0, mm5 ; a3+b3 a2+b2
+ psubd mm4, mm5 ; 5 ; a3-b3 a2-b2
+ psrad mm0, 11 ; y3=a3+b3 y2=a2+b2
+ psrad mm4, 11 ; y4=a3-b3 y5=a2-b2
+ packssdw mm1, mm0 ; 0 ; y3 y2 y1 y0
+ packssdw mm4, mm3 ; 3 ; y6 y7 y4 y5
+ movq mm7, mm4 ; 7 ; y6 y7 y4 y5
+ psrld mm4, 16 ; 0 y6 0 y4
+ pslld mm7, 16 ; y7 0 y5 0
+ movq [r0+16*%1+0], mm1 ; 1 ; save y3 y2 y1 y0
+ por mm7, mm4 ; 4 ; y7 y6 y5 y4
+%endif
+ movq [r0+16*%1+8], mm7 ; 7 ; save y7 y6 y5 y4
+%endmacro
+
+; -----------------------------------------------------------------------------
+;
+; The first stage DCT 8x8 - forward DCTs of columns
+;
+; The %2puts are multiplied
+; for rows 0,4 - on cos_4_16,
+; for rows 1,7 - on cos_1_16,
+; for rows 2,6 - on cos_2_16,
+; for rows 3,5 - on cos_3_16
+; and are shifted to the left for rise of accuracy
+;
+; -----------------------------------------------------------------------------
+;
+; The 8-point scaled forward DCT algorithm (26a8m)
+;
+; -----------------------------------------------------------------------------
+;
+;#define DCT_8_FRW_COL(x, y)
+; {
+; short t0, t1, t2, t3, t4, t5, t6, t7;
+; short tp03, tm03, tp12, tm12, tp65, tm65;
+; short tp465, tm465, tp765, tm765;
+;
+; t0 = LEFT_SHIFT(x[0] + x[7]);
+; t1 = LEFT_SHIFT(x[1] + x[6]);
+; t2 = LEFT_SHIFT(x[2] + x[5]);
+; t3 = LEFT_SHIFT(x[3] + x[4]);
+; t4 = LEFT_SHIFT(x[3] - x[4]);
+; t5 = LEFT_SHIFT(x[2] - x[5]);
+; t6 = LEFT_SHIFT(x[1] - x[6]);
+; t7 = LEFT_SHIFT(x[0] - x[7]);
+;
+; tp03 = t0 + t3;
+; tm03 = t0 - t3;
+; tp12 = t1 + t2;
+; tm12 = t1 - t2;
+;
+; y[0] = tp03 + tp12;
+; y[4] = tp03 - tp12;
+;
+; y[2] = tm03 + tm12 * tg_2_16;
+; y[6] = tm03 * tg_2_16 - tm12;
+;
+; tp65 = (t6 + t5) * cos_4_16;
+; tm65 = (t6 - t5) * cos_4_16;
+;
+; tp765 = t7 + tp65;
+; tm765 = t7 - tp65;
+; tp465 = t4 + tm65;
+; tm465 = t4 - tm65;
+;
+; y[1] = tp765 + tp465 * tg_1_16;
+; y[7] = tp765 * tg_1_16 - tp465;
+; y[5] = tm765 * tg_3_16 + tm465;
+; y[3] = tm765 - tm465 * tg_3_16;
+; }
+;
+; -----------------------------------------------------------------------------
+
+; -----------------------------------------------------------------------------
+; DCT_8_INV_COL_4 INP,OUT
+; -----------------------------------------------------------------------------
+%macro DCT_8_INV_COL 1
+ movq mm0, [tan3]
+ movq mm3, [%1+16*3]
+ movq mm1, mm0 ; tg_3_16
+ movq mm5, [%1+16*5]
+ pmulhw mm0, mm3 ; x3*(tg_3_16-1)
+ movq mm4, [tan1]
+ pmulhw mm1, mm5 ; x5*(tg_3_16-1)
+ movq mm7, [%1+16*7]
+ movq mm2, mm4 ; tg_1_16
+ movq mm6, [%1+16*1]
+ pmulhw mm4, mm7 ; x7*tg_1_16
+ paddsw mm0, mm3 ; x3*tg_3_16
+ pmulhw mm2, mm6 ; x1*tg_1_16
+ paddsw mm1, mm3 ; x3+x5*(tg_3_16-1)
+ psubsw mm0, mm5 ; x3*tg_3_16-x5 = tm35
+ movq mm3, [sqrt2]
+ paddsw mm1, mm5 ; x3+x5*tg_3_16 = tp35
+ paddsw mm4, mm6 ; x1+tg_1_16*x7 = tp17
+ psubsw mm2, mm7 ; x1*tg_1_16-x7 = tm17
+ movq mm5, mm4 ; tp17
+ movq mm6, mm2 ; tm17
+ paddsw mm5, mm1 ; tp17+tp35 = b0
+ psubsw mm6, mm0 ; tm17-tm35 = b3
+ psubsw mm4, mm1 ; tp17-tp35 = t1
+ paddsw mm2, mm0 ; tm17+tm35 = t2
+ movq mm7, [tan2]
+ movq mm1, mm4 ; t1
+ movq [%1+3*16], mm5 ; save b0
+ paddsw mm1, mm2 ; t1+t2
+ movq [%1+5*16], mm6 ; save b3
+ psubsw mm4, mm2 ; t1-t2
+ movq mm5, [%1+2*16]
+ movq mm0, mm7 ; tg_2_16
+ movq mm6, [%1+6*16]
+ pmulhw mm0, mm5 ; x2*tg_2_16
+ pmulhw mm7, mm6 ; x6*tg_2_16
+ pmulhw mm1, mm3 ; ocos_4_16*(t1+t2) = b1/2
+ movq mm2, [%1+0*16]
+ pmulhw mm4, mm3 ; ocos_4_16*(t1-t2) = b2/2
+ psubsw mm0, mm6 ; t2*tg_2_16-x6 = tm26
+ movq mm3, mm2 ; x0
+ movq mm6, [%1+4*16]
+ paddsw mm7, mm5 ; x2+x6*tg_2_16 = tp26
+ paddsw mm2, mm6 ; x0+x4 = tp04
+ psubsw mm3, mm6 ; x0-x4 = tm04
+ movq mm5, mm2 ; tp04
+ movq mm6, mm3 ; tm04
+ psubsw mm2, mm7 ; tp04-tp26 = a3
+ paddsw mm3, mm0 ; tm04+tm26 = a1
+ paddsw mm1, mm1 ; b1
+ paddsw mm4, mm4 ; b2
+ paddsw mm5, mm7 ; tp04+tp26 = a0
+ psubsw mm6, mm0 ; tm04-tm26 = a2
+ movq mm7, mm3 ; a1
+ movq mm0, mm6 ; a2
+ paddsw mm3, mm1 ; a1+b1
+ paddsw mm6, mm4 ; a2+b2
+ psraw mm3, 6 ; dst1
+ psubsw mm7, mm1 ; a1-b1
+ psraw mm6, 6 ; dst2
+ psubsw mm0, mm4 ; a2-b2
+ movq mm1, [%1+3*16] ; load b0
+ psraw mm7, 6 ; dst6
+ movq mm4, mm5 ; a0
+ psraw mm0, 6 ; dst5
+ movq [%1+1*16], mm3
+ paddsw mm5, mm1 ; a0+b0
+ movq [%1+2*16], mm6
+ psubsw mm4, mm1 ; a0-b0
+ movq mm3, [%1+5*16] ; load b3
+ psraw mm5, 6 ; dst0
+ movq mm6, mm2 ; a3
+ psraw mm4, 6 ; dst7
+ movq [%1+5*16], mm0
+ paddsw mm2, mm3 ; a3+b3
+ movq [%1+6*16], mm7
+ psubsw mm6, mm3 ; a3-b3
+ movq [%1+0*16], mm5
+ psraw mm2, 6 ; dst3
+ movq [%1+7*16], mm4
+ psraw mm6, 6 ; dst4
+ movq [%1+3*16], mm2
+ movq [%1+4*16], mm6
+%endmacro
+
+%macro XVID_IDCT_MMX 0
+cglobal xvid_idct, 1, 1, 0, block
+%if cpuflag(mmxext)
+%define TAB tab_i_04_xmm
+%else
+%define TAB tab_i_04_mmx
+%endif
+ ; Process each row - beware of rounder offset
+ DCT_8_INV_ROW 0, TAB + 64 * 0, 0*16
+ DCT_8_INV_ROW 1, TAB + 64 * 1, 1*16
+ DCT_8_INV_ROW 2, TAB + 64 * 2, 2*16
+ DCT_8_INV_ROW 3, TAB + 64 * 3, 3*16
+ DCT_8_INV_ROW 4, TAB + 64 * 0, 6*16
+ DCT_8_INV_ROW 5, TAB + 64 * 3, 4*16
+ DCT_8_INV_ROW 6, TAB + 64 * 2, 5*16
+ DCT_8_INV_ROW 7, TAB + 64 * 1, 5*16
+
+ ; Process the columns (4 at a time)
+ DCT_8_INV_COL r0+0
+ DCT_8_INV_COL r0+8
+
+ RET
+%endmacro
+
+INIT_MMX mmx
+XVID_IDCT_MMX
+INIT_MMX mmxext
+XVID_IDCT_MMX
+
+%endif ; ~ARCH_X86_32
diff --git a/libavcodec/x86/xvididct.h b/libavcodec/x86/xvididct.h
index 13a4e85890..573b25c6b5 100644
--- a/libavcodec/x86/xvididct.h
+++ b/libavcodec/x86/xvididct.h
@@ -1,20 +1,20 @@
/*
* XVID MPEG-4 VIDEO CODEC
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,7 +37,7 @@ void ff_xvid_idct_mmxext_put(uint8_t *dest, int line_size, int16_t *block);
void ff_xvid_idct_mmxext_add(uint8_t *dest, int line_size, int16_t *block);
void ff_xvid_idct_sse2(short *block);
-void ff_xvid_idct_sse2_put(uint8_t *dest, int line_size, short *block);
-void ff_xvid_idct_sse2_add(uint8_t *dest, int line_size, short *block);
+void ff_xvid_idct_put_sse2(uint8_t *dest, int line_size, short *block);
+void ff_xvid_idct_add_sse2(uint8_t *dest, int line_size, short *block);
#endif /* AVCODEC_X86_XVIDIDCT_H */
diff --git a/libavcodec/x86/xvididct_init.c b/libavcodec/x86/xvididct_init.c
index e4f7345795..8b9d8de0cd 100644
--- a/libavcodec/x86/xvididct_init.c
+++ b/libavcodec/x86/xvididct_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,9 +26,36 @@
#include "idctdsp.h"
#include "xvididct.h"
+#if ARCH_X86_32 && HAVE_YASM
+static void xvid_idct_mmx_put(uint8_t *dest, int line_size, short *block)
+{
+ ff_xvid_idct_mmx(block);
+ ff_put_pixels_clamped(block, dest, line_size);
+}
+
+static void xvid_idct_mmx_add(uint8_t *dest, int line_size, short *block)
+{
+ ff_xvid_idct_mmx(block);
+ ff_add_pixels_clamped(block, dest, line_size);
+}
+
+static void xvid_idct_mmxext_put(uint8_t *dest, int line_size, short *block)
+{
+ ff_xvid_idct_mmxext(block);
+ ff_put_pixels_clamped(block, dest, line_size);
+}
+
+static void xvid_idct_mmxext_add(uint8_t *dest, int line_size, short *block)
+{
+ ff_xvid_idct_mmxext(block);
+ ff_add_pixels_clamped(block, dest, line_size);
+}
+#endif
+
av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx,
unsigned high_bit_depth)
{
+#if HAVE_YASM
int cpu_flags = av_get_cpu_flags();
if (high_bit_depth ||
@@ -36,24 +63,27 @@ av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx,
avctx->idct_algo == FF_IDCT_XVID))
return;
- if (INLINE_MMX(cpu_flags)) {
- c->idct_put = ff_xvid_idct_mmx_put;
- c->idct_add = ff_xvid_idct_mmx_add;
+#if ARCH_X86_32
+ if (EXTERNAL_MMX(cpu_flags)) {
+ c->idct_put = xvid_idct_mmx_put;
+ c->idct_add = xvid_idct_mmx_add;
c->idct = ff_xvid_idct_mmx;
c->perm_type = FF_IDCT_PERM_NONE;
}
- if (INLINE_MMXEXT(cpu_flags)) {
- c->idct_put = ff_xvid_idct_mmxext_put;
- c->idct_add = ff_xvid_idct_mmxext_add;
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ c->idct_put = xvid_idct_mmxext_put;
+ c->idct_add = xvid_idct_mmxext_add;
c->idct = ff_xvid_idct_mmxext;
c->perm_type = FF_IDCT_PERM_NONE;
}
+#endif
- if (INLINE_SSE2(cpu_flags)) {
- c->idct_put = ff_xvid_idct_sse2_put;
- c->idct_add = ff_xvid_idct_sse2_add;
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ c->idct_put = ff_xvid_idct_put_sse2;
+ c->idct_add = ff_xvid_idct_add_sse2;
c->idct = ff_xvid_idct_sse2;
c->perm_type = FF_IDCT_PERM_SSE2;
}
+#endif /* HAVE_YASM */
}
diff --git a/libavcodec/x86/xvididct_mmx.c b/libavcodec/x86/xvididct_mmx.c
deleted file mode 100644
index e371142974..0000000000
--- a/libavcodec/x86/xvididct_mmx.c
+++ /dev/null
@@ -1,548 +0,0 @@
-/*
- * XVID MPEG-4 VIDEO CODEC
- * - MMX and XMM forward discrete cosine transform -
- *
- * Copyright(C) 2001 Peter Ross <pross@xvid.org>
- *
- * Originally provided by Intel at AP-922
- * http://developer.intel.com/vtune/cbts/strmsimd/922down.htm
- * (See more app notes at http://developer.intel.com/vtune/cbts/strmsimd/appnotes.htm)
- * but in a limited edition.
- * New macro implements a column part for precise iDCT
- * The routine precision now satisfies IEEE standard 1180-1990.
- *
- * Copyright(C) 2000-2001 Peter Gubanov <peter@elecard.net.ru>
- * Rounding trick Copyright(C) 2000 Michel Lespinasse <walken@zoy.org>
- *
- * http://www.elecard.com/peter/idct.html
- * http://www.linuxvideo.org/mpeg2dec/
- *
- * These examples contain code fragments for first stage iDCT 8x8
- * (for rows) and first stage DCT 8x8 (for columns)
- *
- * conversion to gcc syntax by Michael Niedermayer
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Libav; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <inttypes.h>
-
-#include "config.h"
-
-#include "libavutil/mem.h"
-
-#include "libavcodec/avcodec.h"
-
-#include "idctdsp.h"
-#include "xvididct.h"
-
-#if HAVE_MMX_INLINE
-
-// -----------------------------------------------------------------------------
-// Various memory constants (trigonometric values or rounding values)
-// -----------------------------------------------------------------------------
-
-DECLARE_ALIGNED(8, static const int16_t, tg_1_16)[4 * 4] = {
- 13036, 13036, 13036, 13036, // tg * (2 << 16) + 0.5
- 27146, 27146, 27146, 27146, // tg * (2 << 16) + 0.5
- -21746, -21746, -21746, -21746, // tg * (2 << 16) + 0.5
- 23170, 23170, 23170, 23170
-}; // cos * (2 << 15) + 0.5
-
-DECLARE_ALIGNED(8, static const int32_t, rounder_0)[2 * 8] = {
- 65536, 65536,
- 3597, 3597,
- 2260, 2260,
- 1203, 1203,
- 0, 0,
- 120, 120,
- 512, 512,
- 512, 512
-};
-
-// -----------------------------------------------------------------------------
-//
-// The first stage iDCT 8x8 - inverse DCTs of rows
-//
-// -----------------------------------------------------------------------------
-// The 8-point inverse DCT direct algorithm
-// -----------------------------------------------------------------------------
-//
-// static const short w[32] = {
-// FIX(cos_4_16), FIX(cos_2_16), FIX(cos_4_16), FIX(cos_6_16),
-// FIX(cos_4_16), FIX(cos_6_16), -FIX(cos_4_16), -FIX(cos_2_16),
-// FIX(cos_4_16), -FIX(cos_6_16), -FIX(cos_4_16), FIX(cos_2_16),
-// FIX(cos_4_16), -FIX(cos_2_16), FIX(cos_4_16), -FIX(cos_6_16),
-// FIX(cos_1_16), FIX(cos_3_16), FIX(cos_5_16), FIX(cos_7_16),
-// FIX(cos_3_16), -FIX(cos_7_16), -FIX(cos_1_16), -FIX(cos_5_16),
-// FIX(cos_5_16), -FIX(cos_1_16), FIX(cos_7_16), FIX(cos_3_16),
-// FIX(cos_7_16), -FIX(cos_5_16), FIX(cos_3_16), -FIX(cos_1_16) };
-//
-// #define DCT_8_INV_ROW(x, y)
-// {
-// int a0, a1, a2, a3, b0, b1, b2, b3;
-//
-// a0 = x[0] * w[0] + x[2] * w[1] + x[4] * w[2] + x[6] * w[3];
-// a1 = x[0] * w[4] + x[2] * w[5] + x[4] * w[6] + x[6] * w[7];
-// a2 = x[0] * w[8] + x[2] * w[9] + x[4] * w[10] + x[6] * w[11];
-// a3 = x[0] * w[12] + x[2] * w[13] + x[4] * w[14] + x[6] * w[15];
-// b0 = x[1] * w[16] + x[3] * w[17] + x[5] * w[18] + x[7] * w[19];
-// b1 = x[1] * w[20] + x[3] * w[21] + x[5] * w[22] + x[7] * w[23];
-// b2 = x[1] * w[24] + x[3] * w[25] + x[5] * w[26] + x[7] * w[27];
-// b3 = x[1] * w[28] + x[3] * w[29] + x[5] * w[30] + x[7] * w[31];
-//
-// y[0] = SHIFT_ROUND(a0 + b0);
-// y[1] = SHIFT_ROUND(a1 + b1);
-// y[2] = SHIFT_ROUND(a2 + b2);
-// y[3] = SHIFT_ROUND(a3 + b3);
-// y[4] = SHIFT_ROUND(a3 - b3);
-// y[5] = SHIFT_ROUND(a2 - b2);
-// y[6] = SHIFT_ROUND(a1 - b1);
-// y[7] = SHIFT_ROUND(a0 - b0);
-// }
-//
-// -----------------------------------------------------------------------------
-//
-// In this implementation the outputs of the iDCT-1D are multiplied
-// for rows 0,4 - by cos_4_16,
-// for rows 1,7 - by cos_1_16,
-// for rows 2,6 - by cos_2_16,
-// for rows 3,5 - by cos_3_16
-// and are shifted to the left for better accuracy.
-//
-// For the constants used,
-// FIX(float_const) = (short) (float_const * (1 << 15) + 0.5)
-//
-// -----------------------------------------------------------------------------
-
-// -----------------------------------------------------------------------------
-// Tables for mmx processors
-// -----------------------------------------------------------------------------
-
-// Table for rows 0,4 - constants are multiplied by cos_4_16
-DECLARE_ALIGNED(8, static const int16_t, tab_i_04_mmx)[32 * 4] = {
- 16384, 16384, 16384, -16384, // movq-> w06 w04 w02 w00
- 21407, 8867, 8867, -21407, // w07 w05 w03 w01
- 16384, -16384, 16384, 16384, // w14 w12 w10 w08
- -8867, 21407, -21407, -8867, // w15 w13 w11 w09
- 22725, 12873, 19266, -22725, // w22 w20 w18 w16
- 19266, 4520, -4520, -12873, // w23 w21 w19 w17
- 12873, 4520, 4520, 19266, // w30 w28 w26 w24
- -22725, 19266, -12873, -22725, // w31 w29 w27 w25
-// Table for rows 1,7 - constants are multiplied by cos_1_16
- 22725, 22725, 22725, -22725, // movq-> w06 w04 w02 w00
- 29692, 12299, 12299, -29692, // w07 w05 w03 w01
- 22725, -22725, 22725, 22725, // w14 w12 w10 w08
- -12299, 29692, -29692, -12299, // w15 w13 w11 w09
- 31521, 17855, 26722, -31521, // w22 w20 w18 w16
- 26722, 6270, -6270, -17855, // w23 w21 w19 w17
- 17855, 6270, 6270, 26722, // w30 w28 w26 w24
- -31521, 26722, -17855, -31521, // w31 w29 w27 w25
-// Table for rows 2,6 - constants are multiplied by cos_2_16
- 21407, 21407, 21407, -21407, // movq-> w06 w04 w02 w00
- 27969, 11585, 11585, -27969, // w07 w05 w03 w01
- 21407, -21407, 21407, 21407, // w14 w12 w10 w08
- -11585, 27969, -27969, -11585, // w15 w13 w11 w09
- 29692, 16819, 25172, -29692, // w22 w20 w18 w16
- 25172, 5906, -5906, -16819, // w23 w21 w19 w17
- 16819, 5906, 5906, 25172, // w30 w28 w26 w24
- -29692, 25172, -16819, -29692, // w31 w29 w27 w25
-// Table for rows 3,5 - constants are multiplied by cos_3_16
- 19266, 19266, 19266, -19266, // movq-> w06 w04 w02 w00
- 25172, 10426, 10426, -25172, // w07 w05 w03 w01
- 19266, -19266, 19266, 19266, // w14 w12 w10 w08
- -10426, 25172, -25172, -10426, // w15 w13 w11 w09
- 26722, 15137, 22654, -26722, // w22 w20 w18 w16
- 22654, 5315, -5315, -15137, // w23 w21 w19 w17
- 15137, 5315, 5315, 22654, // w30 w28 w26 w24
- -26722, 22654, -15137, -26722, // w31 w29 w27 w25
-};
-// -----------------------------------------------------------------------------
-// Tables for xmm processors
-// -----------------------------------------------------------------------------
-
-// %3 for rows 0,4 - constants are multiplied by cos_4_16
-DECLARE_ALIGNED(8, static const int16_t, tab_i_04_xmm)[32 * 4] = {
- 16384, 21407, 16384, 8867, // movq-> w05 w04 w01 w00
- 16384, 8867, -16384, -21407, // w07 w06 w03 w02
- 16384, -8867, 16384, -21407, // w13 w12 w09 w08
- -16384, 21407, 16384, -8867, // w15 w14 w11 w10
- 22725, 19266, 19266, -4520, // w21 w20 w17 w16
- 12873, 4520, -22725, -12873, // w23 w22 w19 w18
- 12873, -22725, 4520, -12873, // w29 w28 w25 w24
- 4520, 19266, 19266, -22725, // w31 w30 w27 w26
-// %3 for rows 1,7 - constants are multiplied by cos_1_16
- 22725, 29692, 22725, 12299, // movq-> w05 w04 w01 w00
- 22725, 12299, -22725, -29692, // w07 w06 w03 w02
- 22725, -12299, 22725, -29692, // w13 w12 w09 w08
- -22725, 29692, 22725, -12299, // w15 w14 w11 w10
- 31521, 26722, 26722, -6270, // w21 w20 w17 w16
- 17855, 6270, -31521, -17855, // w23 w22 w19 w18
- 17855, -31521, 6270, -17855, // w29 w28 w25 w24
- 6270, 26722, 26722, -31521, // w31 w30 w27 w26
-// %3 for rows 2,6 - constants are multiplied by cos_2_16
- 21407, 27969, 21407, 11585, // movq-> w05 w04 w01 w00
- 21407, 11585, -21407, -27969, // w07 w06 w03 w02
- 21407, -11585, 21407, -27969, // w13 w12 w09 w08
- -21407, 27969, 21407, -11585, // w15 w14 w11 w10
- 29692, 25172, 25172, -5906, // w21 w20 w17 w16
- 16819, 5906, -29692, -16819, // w23 w22 w19 w18
- 16819, -29692, 5906, -16819, // w29 w28 w25 w24
- 5906, 25172, 25172, -29692, // w31 w30 w27 w26
-// %3 for rows 3,5 - constants are multiplied by cos_3_16
- 19266, 25172, 19266, 10426, // movq-> w05 w04 w01 w00
- 19266, 10426, -19266, -25172, // w07 w06 w03 w02
- 19266, -10426, 19266, -25172, // w13 w12 w09 w08
- -19266, 25172, 19266, -10426, // w15 w14 w11 w10
- 26722, 22654, 22654, -5315, // w21 w20 w17 w16
- 15137, 5315, -26722, -15137, // w23 w22 w19 w18
- 15137, -26722, 5315, -15137, // w29 w28 w25 w24
- 5315, 22654, 22654, -26722, // w31 w30 w27 w26
-};
-// =============================================================================
-// Helper macros for the code
-// =============================================================================
-
-// -----------------------------------------------------------------------------
-// DCT_8_INV_ROW_MMX( INP, OUT, TABLE, ROUNDER
-// -----------------------------------------------------------------------------
-
-#define DCT_8_INV_ROW_MMX(A1, A2, A3, A4) \
- "movq "#A1", %%mm0 \n\t" /* 0 ; x3 x2 x1 x0 */ \
- "movq 8+"#A1", %%mm1 \n\t" /* 1 ; x7 x6 x5 x4 */ \
- "movq %%mm0, %%mm2 \n\t" /* 2 ; x3 x2 x1 x0 */ \
- "movq "#A3", %%mm3 \n\t" /* 3 ; w06 w04 w02 w00 */ \
- "punpcklwd %%mm1, %%mm0 \n\t" /* x5 x1 x4 x0 */ \
- "movq %%mm0, %%mm5 \n\t" /* 5 ; x5 x1 x4 x0 */ \
- "punpckldq %%mm0, %%mm0 \n\t" /* x4 x0 x4 x0 */ \
- "movq 8+"#A3", %%mm4 \n\t" /* 4 ; w07 w05 w03 w01 */ \
- "punpckhwd %%mm1, %%mm2 \n\t" /* 1 ; x7 x3 x6 x2 */ \
- "pmaddwd %%mm0, %%mm3 \n\t" /* x4*w06+x0*w04 x4*w02+x0*w00 */ \
- "movq %%mm2, %%mm6 \n\t" /* 6 ; x7 x3 x6 x2 */ \
- "movq 32+"#A3", %%mm1 \n\t" /* 1 ; w22 w20 w18 w16 */ \
- "punpckldq %%mm2, %%mm2 \n\t" /* x6 x2 x6 x2 */ \
- "pmaddwd %%mm2, %%mm4 \n\t" /* x6*w07+x2*w05 x6*w03+x2*w01 */ \
- "punpckhdq %%mm5, %%mm5 \n\t" /* x5 x1 x5 x1 */ \
- "pmaddwd 16+"#A3", %%mm0 \n\t" /* x4*w14+x0*w12 x4*w10+x0*w08 */ \
- "punpckhdq %%mm6, %%mm6 \n\t" /* x7 x3 x7 x3 */ \
- "movq 40+ "#A3", %%mm7 \n\t" /* 7 ; w23 w21 w19 w17 */ \
- "pmaddwd %%mm5, %%mm1 \n\t" /* x5*w22+x1*w20 x5*w18+x1*w16 */ \
- "paddd "#A4", %%mm3 \n\t" /* +%4 */ \
- "pmaddwd %%mm6, %%mm7 \n\t" /* x7*w23+x3*w21 x7*w19+x3*w17 */ \
- "pmaddwd 24+"#A3", %%mm2 \n\t" /* x6*w15+x2*w13 x6*w11+x2*w09 */ \
- "paddd %%mm4, %%mm3 \n\t" /* 4 ; a1=sum(even1) a0=sum(even0) */ \
- "pmaddwd 48+"#A3", %%mm5 \n\t" /* x5*w30+x1*w28 x5*w26+x1*w24 */ \
- "movq %%mm3, %%mm4 \n\t" /* 4 ; a1 a0 */ \
- "pmaddwd 56+"#A3", %%mm6 \n\t" /* x7*w31+x3*w29 x7*w27+x3*w25 */ \
- "paddd %%mm7, %%mm1 \n\t" /* 7 ; b1=sum(odd1) b0=sum(odd0) */ \
- "paddd "#A4", %%mm0 \n\t" /* +%4 */ \
- "psubd %%mm1, %%mm3 \n\t" /* a1-b1 a0-b0 */ \
- "psrad $11, %%mm3 \n\t" /* y6=a1-b1 y7=a0-b0 */ \
- "paddd %%mm4, %%mm1 \n\t" /* 4 ; a1+b1 a0+b0 */ \
- "paddd %%mm2, %%mm0 \n\t" /* 2 ; a3=sum(even3) a2=sum(even2) */ \
- "psrad $11, %%mm1 \n\t" /* y1=a1+b1 y0=a0+b0 */ \
- "paddd %%mm6, %%mm5 \n\t" /* 6 ; b3=sum(odd3) b2=sum(odd2) */ \
- "movq %%mm0, %%mm4 \n\t" /* 4 ; a3 a2 */ \
- "paddd %%mm5, %%mm0 \n\t" /* a3+b3 a2+b2 */ \
- "psubd %%mm5, %%mm4 \n\t" /* 5 ; a3-b3 a2-b2 */ \
- "psrad $11, %%mm0 \n\t" /* y3=a3+b3 y2=a2+b2 */ \
- "psrad $11, %%mm4 \n\t" /* y4=a3-b3 y5=a2-b2 */ \
- "packssdw %%mm0, %%mm1 \n\t" /* 0 ; y3 y2 y1 y0 */ \
- "packssdw %%mm3, %%mm4 \n\t" /* 3 ; y6 y7 y4 y5 */ \
- "movq %%mm4, %%mm7 \n\t" /* 7 ; y6 y7 y4 y5 */ \
- "psrld $16, %%mm4 \n\t" /* 0 y6 0 y4 */ \
- "pslld $16, %%mm7 \n\t" /* y7 0 y5 0 */ \
- "movq %%mm1, "#A2" \n\t" /* 1 ; save y3 y2 y1 y0 */ \
- "por %%mm4, %%mm7 \n\t" /* 4 ; y7 y6 y5 y4 */ \
- "movq %%mm7, 8+"#A2" \n\t" /* 7 ; save y7 y6 y5 y4 */ \
-
-
-// -----------------------------------------------------------------------------
-// DCT_8_INV_ROW_XMM( INP, OUT, TABLE, ROUNDER
-// -----------------------------------------------------------------------------
-
-#define DCT_8_INV_ROW_XMM(A1, A2, A3, A4) \
- "movq "#A1", %%mm0 \n\t" /* 0 ; x3 x2 x1 x0 */ \
- "movq 8+"#A1", %%mm1 \n\t" /* 1 ; x7 x6 x5 x4 */ \
- "movq %%mm0, %%mm2 \n\t" /* 2 ; x3 x2 x1 x0 */ \
- "movq "#A3", %%mm3 \n\t" /* 3 ; w05 w04 w01 w00 */ \
- "pshufw $0x88, %%mm0, %%mm0 \n\t" /* x2 x0 x2 x0 */ \
- "movq 8+"#A3", %%mm4 \n\t" /* 4 ; w07 w06 w03 w02 */ \
- "movq %%mm1, %%mm5 \n\t" /* 5 ; x7 x6 x5 x4 */ \
- "pmaddwd %%mm0, %%mm3 \n\t" /* x2*w05+x0*w04 x2*w01+x0*w00 */ \
- "movq 32+"#A3", %%mm6 \n\t" /* 6 ; w21 w20 w17 w16 */ \
- "pshufw $0x88, %%mm1, %%mm1 \n\t" /* x6 x4 x6 x4 */ \
- "pmaddwd %%mm1, %%mm4 \n\t" /* x6*w07+x4*w06 x6*w03+x4*w02 */ \
- "movq 40+"#A3", %%mm7 \n\t" /* 7; w23 w22 w19 w18 */ \
- "pshufw $0xdd, %%mm2, %%mm2 \n\t" /* x3 x1 x3 x1 */ \
- "pmaddwd %%mm2, %%mm6 \n\t" /* x3*w21+x1*w20 x3*w17+x1*w16 */ \
- "pshufw $0xdd, %%mm5, %%mm5 \n\t" /* x7 x5 x7 x5 */ \
- "pmaddwd %%mm5, %%mm7 \n\t" /* x7*w23+x5*w22 x7*w19+x5*w18 */ \
- "paddd "#A4", %%mm3 \n\t" /* +%4 */ \
- "pmaddwd 16+"#A3", %%mm0 \n\t" /* x2*w13+x0*w12 x2*w09+x0*w08 */ \
- "paddd %%mm4, %%mm3 \n\t" /* 4 ; a1=sum(even1) a0=sum(even0) */ \
- "pmaddwd 24+"#A3", %%mm1 \n\t" /* x6*w15+x4*w14 x6*w11+x4*w10 */ \
- "movq %%mm3, %%mm4 \n\t" /* 4 ; a1 a0 */ \
- "pmaddwd 48+"#A3", %%mm2 \n\t" /* x3*w29+x1*w28 x3*w25+x1*w24 */ \
- "paddd %%mm7, %%mm6 \n\t" /* 7 ; b1=sum(odd1) b0=sum(odd0) */ \
- "pmaddwd 56+"#A3", %%mm5 \n\t" /* x7*w31+x5*w30 x7*w27+x5*w26 */ \
- "paddd %%mm6, %%mm3 \n\t" /* a1+b1 a0+b0 */ \
- "paddd "#A4", %%mm0 \n\t" /* +%4 */ \
- "psrad $11, %%mm3 \n\t" /* y1=a1+b1 y0=a0+b0 */ \
- "paddd %%mm1, %%mm0 \n\t" /* 1 ; a3=sum(even3) a2=sum(even2) */ \
- "psubd %%mm6, %%mm4 \n\t" /* 6 ; a1-b1 a0-b0 */ \
- "movq %%mm0, %%mm7 \n\t" /* 7 ; a3 a2 */ \
- "paddd %%mm5, %%mm2 \n\t" /* 5 ; b3=sum(odd3) b2=sum(odd2) */ \
- "paddd %%mm2, %%mm0 \n\t" /* a3+b3 a2+b2 */ \
- "psrad $11, %%mm4 \n\t" /* y6=a1-b1 y7=a0-b0 */ \
- "psubd %%mm2, %%mm7 \n\t" /* 2 ; a3-b3 a2-b2 */ \
- "psrad $11, %%mm0 \n\t" /* y3=a3+b3 y2=a2+b2 */ \
- "psrad $11, %%mm7 \n\t" /* y4=a3-b3 y5=a2-b2 */ \
- "packssdw %%mm0, %%mm3 \n\t" /* 0 ; y3 y2 y1 y0 */ \
- "packssdw %%mm4, %%mm7 \n\t" /* 4 ; y6 y7 y4 y5 */ \
- "movq %%mm3, "#A2" \n\t" /* 3 ; save y3 y2 y1 y0 */ \
- "pshufw $0xb1, %%mm7, %%mm7 \n\t" /* y7 y6 y5 y4 */ \
- "movq %%mm7, 8+"#A2" \n\t" /* 7 ; save y7 y6 y5 y4 */ \
-
-
-// -----------------------------------------------------------------------------
-//
-// The first stage DCT 8x8 - forward DCTs of columns
-//
-// The %2puts are multiplied
-// for rows 0,4 - on cos_4_16,
-// for rows 1,7 - on cos_1_16,
-// for rows 2,6 - on cos_2_16,
-// for rows 3,5 - on cos_3_16
-// and are shifted to the left for rise of accuracy
-//
-// -----------------------------------------------------------------------------
-//
-// The 8-point scaled forward DCT algorithm (26a8m)
-//
-// -----------------------------------------------------------------------------
-//
-//#define DCT_8_FRW_COL(x, y)
-// {
-// short t0, t1, t2, t3, t4, t5, t6, t7;
-// short tp03, tm03, tp12, tm12, tp65, tm65;
-// short tp465, tm465, tp765, tm765;
-//
-// t0 = LEFT_SHIFT(x[0] + x[7]);
-// t1 = LEFT_SHIFT(x[1] + x[6]);
-// t2 = LEFT_SHIFT(x[2] + x[5]);
-// t3 = LEFT_SHIFT(x[3] + x[4]);
-// t4 = LEFT_SHIFT(x[3] - x[4]);
-// t5 = LEFT_SHIFT(x[2] - x[5]);
-// t6 = LEFT_SHIFT(x[1] - x[6]);
-// t7 = LEFT_SHIFT(x[0] - x[7]);
-//
-// tp03 = t0 + t3;
-// tm03 = t0 - t3;
-// tp12 = t1 + t2;
-// tm12 = t1 - t2;
-//
-// y[0] = tp03 + tp12;
-// y[4] = tp03 - tp12;
-//
-// y[2] = tm03 + tm12 * tg_2_16;
-// y[6] = tm03 * tg_2_16 - tm12;
-//
-// tp65 = (t6 + t5) * cos_4_16;
-// tm65 = (t6 - t5) * cos_4_16;
-//
-// tp765 = t7 + tp65;
-// tm765 = t7 - tp65;
-// tp465 = t4 + tm65;
-// tm465 = t4 - tm65;
-//
-// y[1] = tp765 + tp465 * tg_1_16;
-// y[7] = tp765 * tg_1_16 - tp465;
-// y[5] = tm765 * tg_3_16 + tm465;
-// y[3] = tm765 - tm465 * tg_3_16;
-// }
-//
-// -----------------------------------------------------------------------------
-
-// -----------------------------------------------------------------------------
-// DCT_8_INV_COL_4 INP,OUT
-// -----------------------------------------------------------------------------
-
-#define DCT_8_INV_COL(A1, A2) \
- "movq 2*8(%3), %%mm0 \n\t" \
- "movq 16*3+"#A1", %%mm3 \n\t" \
- "movq %%mm0, %%mm1 \n\t" /* tg_3_16 */ \
- "movq 16*5+"#A1", %%mm5 \n\t" \
- "pmulhw %%mm3, %%mm0 \n\t" /* x3*(tg_3_16-1) */ \
- "movq (%3), %%mm4 \n\t" \
- "pmulhw %%mm5, %%mm1 \n\t" /* x5*(tg_3_16-1) */ \
- "movq 16*7+"#A1", %%mm7 \n\t" \
- "movq %%mm4, %%mm2 \n\t" /* tg_1_16 */ \
- "movq 16*1+"#A1", %%mm6 \n\t" \
- "pmulhw %%mm7, %%mm4 \n\t" /* x7*tg_1_16 */ \
- "paddsw %%mm3, %%mm0 \n\t" /* x3*tg_3_16 */ \
- "pmulhw %%mm6, %%mm2 \n\t" /* x1*tg_1_16 */ \
- "paddsw %%mm3, %%mm1 \n\t" /* x3+x5*(tg_3_16-1) */ \
- "psubsw %%mm5, %%mm0 \n\t" /* x3*tg_3_16-x5 = tm35 */ \
- "movq 3*8(%3), %%mm3 \n\t" \
- "paddsw %%mm5, %%mm1 \n\t" /* x3+x5*tg_3_16 = tp35 */ \
- "paddsw %%mm6, %%mm4 \n\t" /* x1+tg_1_16*x7 = tp17 */ \
- "psubsw %%mm7, %%mm2 \n\t" /* x1*tg_1_16-x7 = tm17 */ \
- "movq %%mm4, %%mm5 \n\t" /* tp17 */ \
- "movq %%mm2, %%mm6 \n\t" /* tm17 */ \
- "paddsw %%mm1, %%mm5 \n\t" /* tp17+tp35 = b0 */ \
- "psubsw %%mm0, %%mm6 \n\t" /* tm17-tm35 = b3 */ \
- "psubsw %%mm1, %%mm4 \n\t" /* tp17-tp35 = t1 */ \
- "paddsw %%mm0, %%mm2 \n\t" /* tm17+tm35 = t2 */ \
- "movq 1*8(%3), %%mm7 \n\t" \
- "movq %%mm4, %%mm1 \n\t" /* t1 */ \
- "movq %%mm5, 3*16+"#A2" \n\t" /* save b0 */ \
- "paddsw %%mm2, %%mm1 \n\t" /* t1+t2 */ \
- "movq %%mm6, 5*16+"#A2" \n\t" /* save b3 */ \
- "psubsw %%mm2, %%mm4 \n\t" /* t1-t2 */ \
- "movq 2*16+"#A1", %%mm5 \n\t" \
- "movq %%mm7, %%mm0 \n\t" /* tg_2_16 */ \
- "movq 6*16+"#A1", %%mm6 \n\t" \
- "pmulhw %%mm5, %%mm0 \n\t" /* x2*tg_2_16 */ \
- "pmulhw %%mm6, %%mm7 \n\t" /* x6*tg_2_16 */ \
- "pmulhw %%mm3, %%mm1 \n\t" /* ocos_4_16*(t1+t2) = b1/2 */ \
- "movq 0*16+"#A1", %%mm2 \n\t" \
- "pmulhw %%mm3, %%mm4 \n\t" /* ocos_4_16*(t1-t2) = b2/2 */ \
- "psubsw %%mm6, %%mm0 \n\t" /* t2*tg_2_16-x6 = tm26 */ \
- "movq %%mm2, %%mm3 \n\t" /* x0 */ \
- "movq 4*16+"#A1", %%mm6 \n\t" \
- "paddsw %%mm5, %%mm7 \n\t" /* x2+x6*tg_2_16 = tp26 */ \
- "paddsw %%mm6, %%mm2 \n\t" /* x0+x4 = tp04 */ \
- "psubsw %%mm6, %%mm3 \n\t" /* x0-x4 = tm04 */ \
- "movq %%mm2, %%mm5 \n\t" /* tp04 */ \
- "movq %%mm3, %%mm6 \n\t" /* tm04 */ \
- "psubsw %%mm7, %%mm2 \n\t" /* tp04-tp26 = a3 */ \
- "paddsw %%mm0, %%mm3 \n\t" /* tm04+tm26 = a1 */ \
- "paddsw %%mm1, %%mm1 \n\t" /* b1 */ \
- "paddsw %%mm4, %%mm4 \n\t" /* b2 */ \
- "paddsw %%mm7, %%mm5 \n\t" /* tp04+tp26 = a0 */ \
- "psubsw %%mm0, %%mm6 \n\t" /* tm04-tm26 = a2 */ \
- "movq %%mm3, %%mm7 \n\t" /* a1 */ \
- "movq %%mm6, %%mm0 \n\t" /* a2 */ \
- "paddsw %%mm1, %%mm3 \n\t" /* a1+b1 */ \
- "paddsw %%mm4, %%mm6 \n\t" /* a2+b2 */ \
- "psraw $6, %%mm3 \n\t" /* dst1 */ \
- "psubsw %%mm1, %%mm7 \n\t" /* a1-b1 */ \
- "psraw $6, %%mm6 \n\t" /* dst2 */ \
- "psubsw %%mm4, %%mm0 \n\t" /* a2-b2 */ \
- "movq 3*16+"#A2", %%mm1 \n\t" /* load b0 */ \
- "psraw $6, %%mm7 \n\t" /* dst6 */ \
- "movq %%mm5, %%mm4 \n\t" /* a0 */ \
- "psraw $6, %%mm0 \n\t" /* dst5 */ \
- "movq %%mm3, 1*16+"#A2" \n\t" \
- "paddsw %%mm1, %%mm5 \n\t" /* a0+b0 */ \
- "movq %%mm6, 2*16+"#A2" \n\t" \
- "psubsw %%mm1, %%mm4 \n\t" /* a0-b0 */ \
- "movq 5*16+"#A2", %%mm3 \n\t" /* load b3 */ \
- "psraw $6, %%mm5 \n\t" /* dst0 */ \
- "movq %%mm2, %%mm6 \n\t" /* a3 */ \
- "psraw $6, %%mm4 \n\t" /* dst7 */ \
- "movq %%mm0, 5*16+"#A2" \n\t" \
- "paddsw %%mm3, %%mm2 \n\t" /* a3+b3 */ \
- "movq %%mm7, 6*16+"#A2" \n\t" \
- "psubsw %%mm3, %%mm6 \n\t" /* a3-b3 */ \
- "movq %%mm5, 0*16+"#A2" \n\t" \
- "psraw $6, %%mm2 \n\t" /* dst3 */ \
- "movq %%mm4, 7*16+"#A2" \n\t" \
- "psraw $6, %%mm6 \n\t" /* dst4 */ \
- "movq %%mm2, 3*16+"#A2" \n\t" \
- "movq %%mm6, 4*16+"#A2" \n\t" \
-
-// =============================================================================
-// Code
-// =============================================================================
-
-// -----------------------------------------------------------------------------
-// void idct_mmx(uint16_t block[64]);
-// -----------------------------------------------------------------------------
-
-void ff_xvid_idct_mmx(short *block)
-{
- __asm__ volatile (
- // # Process each row
- DCT_8_INV_ROW_MMX(0 * 16(%0), 0 * 16(%0), 64 * 0(%2), 8 * 0(%1))
- DCT_8_INV_ROW_MMX(1 * 16(%0), 1 * 16(%0), 64 * 1(%2), 8 * 1(%1))
- DCT_8_INV_ROW_MMX(2 * 16(%0), 2 * 16(%0), 64 * 2(%2), 8 * 2(%1))
- DCT_8_INV_ROW_MMX(3 * 16(%0), 3 * 16(%0), 64 * 3(%2), 8 * 3(%1))
- DCT_8_INV_ROW_MMX(4 * 16(%0), 4 * 16(%0), 64 * 0(%2), 8 * 4(%1))
- DCT_8_INV_ROW_MMX(5 * 16(%0), 5 * 16(%0), 64 * 3(%2), 8 * 5(%1))
- DCT_8_INV_ROW_MMX(6 * 16(%0), 6 * 16(%0), 64 * 2(%2), 8 * 6(%1))
- DCT_8_INV_ROW_MMX(7 * 16(%0), 7 * 16(%0), 64 * 1(%2), 8 * 7(%1))
-
- // # Process the columns (4 at a time)
- DCT_8_INV_COL(0(%0), 0(%0))
- DCT_8_INV_COL(8(%0), 8(%0))
- :: "r" (block), "r" (rounder_0), "r" (tab_i_04_mmx), "r" (tg_1_16));
-}
-
-void ff_xvid_idct_mmx_put(uint8_t *dest, int line_size, int16_t *block)
-{
- ff_xvid_idct_mmx(block);
- ff_put_pixels_clamped_mmx(block, dest, line_size);
-}
-
-void ff_xvid_idct_mmx_add(uint8_t *dest, int line_size, int16_t *block)
-{
- ff_xvid_idct_mmx(block);
- ff_add_pixels_clamped_mmx(block, dest, line_size);
-}
-
-#endif /* HAVE_MMX_INLINE */
-
-#if HAVE_MMXEXT_INLINE
-
-// -----------------------------------------------------------------------------
-// void idct_xmm(uint16_t block[64]);
-// -----------------------------------------------------------------------------
-
-void ff_xvid_idct_mmxext(short *block)
-{
- __asm__ volatile (
- // # Process each row
- DCT_8_INV_ROW_XMM(0 * 16(%0), 0 * 16(%0), 64 * 0(%2), 8 * 0(%1))
- DCT_8_INV_ROW_XMM(1 * 16(%0), 1 * 16(%0), 64 * 1(%2), 8 * 1(%1))
- DCT_8_INV_ROW_XMM(2 * 16(%0), 2 * 16(%0), 64 * 2(%2), 8 * 2(%1))
- DCT_8_INV_ROW_XMM(3 * 16(%0), 3 * 16(%0), 64 * 3(%2), 8 * 3(%1))
- DCT_8_INV_ROW_XMM(4 * 16(%0), 4 * 16(%0), 64 * 0(%2), 8 * 4(%1))
- DCT_8_INV_ROW_XMM(5 * 16(%0), 5 * 16(%0), 64 * 3(%2), 8 * 5(%1))
- DCT_8_INV_ROW_XMM(6 * 16(%0), 6 * 16(%0), 64 * 2(%2), 8 * 6(%1))
- DCT_8_INV_ROW_XMM(7 * 16(%0), 7 * 16(%0), 64 * 1(%2), 8 * 7(%1))
-
- // # Process the columns (4 at a time)
- DCT_8_INV_COL(0(%0), 0(%0))
- DCT_8_INV_COL(8(%0), 8(%0))
- :: "r" (block), "r" (rounder_0), "r" (tab_i_04_xmm), "r" (tg_1_16));
-}
-
-void ff_xvid_idct_mmxext_put(uint8_t *dest, int line_size, int16_t *block)
-{
- ff_xvid_idct_mmxext(block);
- ff_put_pixels_clamped_mmx(block, dest, line_size);
-}
-
-void ff_xvid_idct_mmxext_add(uint8_t *dest, int line_size, int16_t *block)
-{
- ff_xvid_idct_mmxext(block);
- ff_add_pixels_clamped_mmx(block, dest, line_size);
-}
-
-#endif /* HAVE_MMXEXT_INLINE */
diff --git a/libavcodec/x86/xvididct_sse2.c b/libavcodec/x86/xvididct_sse2.c
deleted file mode 100644
index d4f01693ea..0000000000
--- a/libavcodec/x86/xvididct_sse2.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * XVID MPEG-4 VIDEO CODEC
- * - SSE2 inverse discrete cosine transform -
- *
- * Copyright(C) 2003 Pascal Massimino <skal@planet-d.net>
- *
- * Conversion to gcc syntax with modifications
- * by Alexander Strange <astrange@ithinksw.com>
- *
- * Originally from dct/x86_asm/fdct_sse2_skal.asm in Xvid.
- *
- * This file is part of Libav.
- *
- * Vertical pass is an implementation of the scheme:
- * Loeffler C., Ligtenberg A., and Moschytz C.S.:
- * Practical Fast 1D DCT Algorithm with Eleven Multiplications,
- * Proc. ICASSP 1989, 988-991.
- *
- * Horizontal pass is a double 4x4 vector/matrix multiplication,
- * (see also Intel's Application Note 922:
- * http://developer.intel.com/vtune/cbts/strmsimd/922down.htm
- * Copyright (C) 1999 Intel Corporation)
- *
- * More details at http://skal.planet-d.net/coding/dct.html
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Libav; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "libavutil/internal.h"
-#include "libavutil/mem.h"
-#include "libavutil/x86/asm.h"
-
-#include "idctdsp.h"
-#include "xvididct.h"
-
-#if HAVE_SSE2_INLINE
-
-/**
- * @file
- * @brief SSE2 IDCT compatible with the Xvid IDCT
- */
-
-#define X8(x) x, x, x, x, x, x, x, x
-
-DECLARE_ASM_CONST(16, int16_t, tan1)[] = { X8(13036) }; // tan( pi/16)
-DECLARE_ASM_CONST(16, int16_t, tan2)[] = { X8(27146) }; // tan(2pi/16) = sqrt(2)-1
-DECLARE_ASM_CONST(16, int16_t, tan3)[] = { X8(43790) }; // tan(3pi/16)-1
-DECLARE_ASM_CONST(16, int16_t, sqrt2)[] = { X8(23170) }; // 0.5/sqrt(2)
-DECLARE_ASM_CONST(8, uint8_t, m127)[] = { X8(127) };
-
-DECLARE_ASM_CONST(16, int16_t, iTab1)[] = {
- 0x4000, 0x539f, 0xc000, 0xac61, 0x4000, 0xdd5d, 0x4000, 0xdd5d,
- 0x4000, 0x22a3, 0x4000, 0x22a3, 0xc000, 0x539f, 0x4000, 0xac61,
- 0x3249, 0x11a8, 0x4b42, 0xee58, 0x11a8, 0x4b42, 0x11a8, 0xcdb7,
- 0x58c5, 0x4b42, 0xa73b, 0xcdb7, 0x3249, 0xa73b, 0x4b42, 0xa73b
-};
-
-DECLARE_ASM_CONST(16, int16_t, iTab2)[] = {
- 0x58c5, 0x73fc, 0xa73b, 0x8c04, 0x58c5, 0xcff5, 0x58c5, 0xcff5,
- 0x58c5, 0x300b, 0x58c5, 0x300b, 0xa73b, 0x73fc, 0x58c5, 0x8c04,
- 0x45bf, 0x187e, 0x6862, 0xe782, 0x187e, 0x6862, 0x187e, 0xba41,
- 0x7b21, 0x6862, 0x84df, 0xba41, 0x45bf, 0x84df, 0x6862, 0x84df
-};
-
-DECLARE_ASM_CONST(16, int16_t, iTab3)[] = {
- 0x539f, 0x6d41, 0xac61, 0x92bf, 0x539f, 0xd2bf, 0x539f, 0xd2bf,
- 0x539f, 0x2d41, 0x539f, 0x2d41, 0xac61, 0x6d41, 0x539f, 0x92bf,
- 0x41b3, 0x1712, 0x6254, 0xe8ee, 0x1712, 0x6254, 0x1712, 0xbe4d,
- 0x73fc, 0x6254, 0x8c04, 0xbe4d, 0x41b3, 0x8c04, 0x6254, 0x8c04
-};
-
-DECLARE_ASM_CONST(16, int16_t, iTab4)[] = {
- 0x4b42, 0x6254, 0xb4be, 0x9dac, 0x4b42, 0xd746, 0x4b42, 0xd746,
- 0x4b42, 0x28ba, 0x4b42, 0x28ba, 0xb4be, 0x6254, 0x4b42, 0x9dac,
- 0x3b21, 0x14c3, 0x587e, 0xeb3d, 0x14c3, 0x587e, 0x14c3, 0xc4df,
- 0x6862, 0x587e, 0x979e, 0xc4df, 0x3b21, 0x979e, 0x587e, 0x979e
-};
-
-DECLARE_ASM_CONST(16, int32_t, walkenIdctRounders)[] = {
- 65536, 65536, 65536, 65536,
- 3597, 3597, 3597, 3597,
- 2260, 2260, 2260, 2260,
- 1203, 1203, 1203, 1203,
- 120, 120, 120, 120,
- 512, 512, 512, 512
-};
-
-// Temporary storage before the column pass
-#define ROW1 "%%xmm6"
-#define ROW3 "%%xmm4"
-#define ROW5 "%%xmm5"
-#define ROW7 "%%xmm7"
-
-#define CLEAR_ODD(r) "pxor "r","r" \n\t"
-#define PUT_ODD(dst) "pshufhw $0x1B, %%xmm2, "dst" \n\t"
-
-#if ARCH_X86_64
-
-# define ROW0 "%%xmm8"
-# define REG0 ROW0
-# define ROW2 "%%xmm9"
-# define REG2 ROW2
-# define ROW4 "%%xmm10"
-# define REG4 ROW4
-# define ROW6 "%%xmm11"
-# define REG6 ROW6
-# define CLEAR_EVEN(r) CLEAR_ODD(r)
-# define PUT_EVEN(dst) PUT_ODD(dst)
-# define XMMS "%%xmm12"
-# define MOV_32_ONLY "#"
-# define SREG2 REG2
-# define TAN3 "%%xmm13"
-# define TAN1 "%%xmm14"
-
-#else
-
-# define ROW0 "(%0)"
-# define REG0 "%%xmm4"
-# define ROW2 "2*16(%0)"
-# define REG2 "%%xmm4"
-# define ROW4 "4*16(%0)"
-# define REG4 "%%xmm6"
-# define ROW6 "6*16(%0)"
-# define REG6 "%%xmm6"
-# define CLEAR_EVEN(r)
-# define PUT_EVEN(dst) \
- "pshufhw $0x1B, %%xmm2, %%xmm2 \n\t" \
- "movdqa %%xmm2, "dst" \n\t"
-# define XMMS "%%xmm2"
-# define MOV_32_ONLY "movdqa "
-# define SREG2 "%%xmm7"
-# define TAN3 "%%xmm0"
-# define TAN1 "%%xmm2"
-
-#endif
-
-#define ROUND(x) "paddd "MANGLE(x)
-
-#define JZ(reg, to) \
- "testl "reg","reg" \n\t" \
- "jz "to" \n\t"
-
-#define JNZ(reg, to) \
- "testl "reg","reg" \n\t" \
- "jnz "to" \n\t"
-
-#define TEST_ONE_ROW(src, reg, clear) \
- clear \
- "movq "src", %%mm1 \n\t" \
- "por 8+"src", %%mm1 \n\t" \
- "paddusb %%mm0, %%mm1 \n\t" \
- "pmovmskb %%mm1, "reg" \n\t"
-
-#define TEST_TWO_ROWS(row1, row2, reg1, reg2, clear1, clear2) \
- clear1 \
- clear2 \
- "movq "row1", %%mm1 \n\t" \
- "por 8+"row1", %%mm1 \n\t" \
- "movq "row2", %%mm2 \n\t" \
- "por 8+"row2", %%mm2 \n\t" \
- "paddusb %%mm0, %%mm1 \n\t" \
- "paddusb %%mm0, %%mm2 \n\t" \
- "pmovmskb %%mm1, "reg1" \n\t" \
- "pmovmskb %%mm2, "reg2" \n\t"
-
-/// IDCT pass on rows.
-#define iMTX_MULT(src, table, rounder, put) \
- "movdqa "src", %%xmm3 \n\t" \
- "movdqa %%xmm3, %%xmm0 \n\t" \
- "pshufd $0x11, %%xmm3, %%xmm1 \n\t" /* 4602 */ \
- "punpcklqdq %%xmm0, %%xmm0 \n\t" /* 0246 */ \
- "pmaddwd "table", %%xmm0 \n\t" \
- "pmaddwd 16+"table", %%xmm1 \n\t" \
- "pshufd $0xBB, %%xmm3, %%xmm2 \n\t" /* 5713 */ \
- "punpckhqdq %%xmm3, %%xmm3 \n\t" /* 1357 */ \
- "pmaddwd 32+"table", %%xmm2 \n\t" \
- "pmaddwd 48+"table", %%xmm3 \n\t" \
- "paddd %%xmm1, %%xmm0 \n\t" \
- "paddd %%xmm3, %%xmm2 \n\t" \
- rounder", %%xmm0 \n\t" \
- "movdqa %%xmm2, %%xmm3 \n\t" \
- "paddd %%xmm0, %%xmm2 \n\t" \
- "psubd %%xmm3, %%xmm0 \n\t" \
- "psrad $11, %%xmm2 \n\t" \
- "psrad $11, %%xmm0 \n\t" \
- "packssdw %%xmm0, %%xmm2 \n\t" \
- put \
- "1: \n\t"
-
-#define iLLM_HEAD \
- "movdqa "MANGLE(tan3)", "TAN3" \n\t" \
- "movdqa "MANGLE(tan1)", "TAN1" \n\t" \
-
-/// IDCT pass on columns.
-#define iLLM_PASS(dct) \
- "movdqa "TAN3", %%xmm1 \n\t" \
- "movdqa "TAN1", %%xmm3 \n\t" \
- "pmulhw %%xmm4, "TAN3" \n\t" \
- "pmulhw %%xmm5, %%xmm1 \n\t" \
- "paddsw %%xmm4, "TAN3" \n\t" \
- "paddsw %%xmm5, %%xmm1 \n\t" \
- "psubsw %%xmm5, "TAN3" \n\t" \
- "paddsw %%xmm4, %%xmm1 \n\t" \
- "pmulhw %%xmm7, %%xmm3 \n\t" \
- "pmulhw %%xmm6, "TAN1" \n\t" \
- "paddsw %%xmm6, %%xmm3 \n\t" \
- "psubsw %%xmm7, "TAN1" \n\t" \
- "movdqa %%xmm3, %%xmm7 \n\t" \
- "movdqa "TAN1", %%xmm6 \n\t" \
- "psubsw %%xmm1, %%xmm3 \n\t" \
- "psubsw "TAN3", "TAN1" \n\t" \
- "paddsw %%xmm7, %%xmm1 \n\t" \
- "paddsw %%xmm6, "TAN3" \n\t" \
- "movdqa %%xmm3, %%xmm6 \n\t" \
- "psubsw "TAN3", %%xmm3 \n\t" \
- "paddsw %%xmm6, "TAN3" \n\t" \
- "movdqa "MANGLE(sqrt2)", %%xmm4 \n\t" \
- "pmulhw %%xmm4, %%xmm3 \n\t" \
- "pmulhw %%xmm4, "TAN3" \n\t" \
- "paddsw "TAN3", "TAN3" \n\t" \
- "paddsw %%xmm3, %%xmm3 \n\t" \
- "movdqa "MANGLE(tan2)", %%xmm7 \n\t" \
- MOV_32_ONLY ROW2", "REG2" \n\t" \
- MOV_32_ONLY ROW6", "REG6" \n\t" \
- "movdqa %%xmm7, %%xmm5 \n\t" \
- "pmulhw "REG6", %%xmm7 \n\t" \
- "pmulhw "REG2", %%xmm5 \n\t" \
- "paddsw "REG2", %%xmm7 \n\t" \
- "psubsw "REG6", %%xmm5 \n\t" \
- MOV_32_ONLY ROW0", "REG0" \n\t" \
- MOV_32_ONLY ROW4", "REG4" \n\t" \
- MOV_32_ONLY" "TAN1", (%0) \n\t" \
- "movdqa "REG0", "XMMS" \n\t" \
- "psubsw "REG4", "REG0" \n\t" \
- "paddsw "XMMS", "REG4" \n\t" \
- "movdqa "REG4", "XMMS" \n\t" \
- "psubsw %%xmm7, "REG4" \n\t" \
- "paddsw "XMMS", %%xmm7 \n\t" \
- "movdqa "REG0", "XMMS" \n\t" \
- "psubsw %%xmm5, "REG0" \n\t" \
- "paddsw "XMMS", %%xmm5 \n\t" \
- "movdqa %%xmm5, "XMMS" \n\t" \
- "psubsw "TAN3", %%xmm5 \n\t" \
- "paddsw "XMMS", "TAN3" \n\t" \
- "movdqa "REG0", "XMMS" \n\t" \
- "psubsw %%xmm3, "REG0" \n\t" \
- "paddsw "XMMS", %%xmm3 \n\t" \
- MOV_32_ONLY" (%0), "TAN1" \n\t" \
- "psraw $6, %%xmm5 \n\t" \
- "psraw $6, "REG0" \n\t" \
- "psraw $6, "TAN3" \n\t" \
- "psraw $6, %%xmm3 \n\t" \
- "movdqa "TAN3", 1*16("dct") \n\t" \
- "movdqa %%xmm3, 2*16("dct") \n\t" \
- "movdqa "REG0", 5*16("dct") \n\t" \
- "movdqa %%xmm5, 6*16("dct") \n\t" \
- "movdqa %%xmm7, %%xmm0 \n\t" \
- "movdqa "REG4", %%xmm4 \n\t" \
- "psubsw %%xmm1, %%xmm7 \n\t" \
- "psubsw "TAN1", "REG4" \n\t" \
- "paddsw %%xmm0, %%xmm1 \n\t" \
- "paddsw %%xmm4, "TAN1" \n\t" \
- "psraw $6, %%xmm1 \n\t" \
- "psraw $6, %%xmm7 \n\t" \
- "psraw $6, "TAN1" \n\t" \
- "psraw $6, "REG4" \n\t" \
- "movdqa %%xmm1, ("dct") \n\t" \
- "movdqa "TAN1", 3*16("dct") \n\t" \
- "movdqa "REG4", 4*16("dct") \n\t" \
- "movdqa %%xmm7, 7*16("dct") \n\t"
-
-/// IDCT pass on columns, assuming rows 4-7 are zero.
-#define iLLM_PASS_SPARSE(dct) \
- "pmulhw %%xmm4, "TAN3" \n\t" \
- "paddsw %%xmm4, "TAN3" \n\t" \
- "movdqa %%xmm6, %%xmm3 \n\t" \
- "pmulhw %%xmm6, "TAN1" \n\t" \
- "movdqa %%xmm4, %%xmm1 \n\t" \
- "psubsw %%xmm1, %%xmm3 \n\t" \
- "paddsw %%xmm6, %%xmm1 \n\t" \
- "movdqa "TAN1", %%xmm6 \n\t" \
- "psubsw "TAN3", "TAN1" \n\t" \
- "paddsw %%xmm6, "TAN3" \n\t" \
- "movdqa %%xmm3, %%xmm6 \n\t" \
- "psubsw "TAN3", %%xmm3 \n\t" \
- "paddsw %%xmm6, "TAN3" \n\t" \
- "movdqa "MANGLE(sqrt2)", %%xmm4 \n\t" \
- "pmulhw %%xmm4, %%xmm3 \n\t" \
- "pmulhw %%xmm4, "TAN3" \n\t" \
- "paddsw "TAN3", "TAN3" \n\t" \
- "paddsw %%xmm3, %%xmm3 \n\t" \
- "movdqa "MANGLE(tan2)", %%xmm5 \n\t" \
- MOV_32_ONLY ROW2", "SREG2" \n\t" \
- "pmulhw "SREG2", %%xmm5 \n\t" \
- MOV_32_ONLY ROW0", "REG0" \n\t" \
- "movdqa "REG0", %%xmm6 \n\t" \
- "psubsw "SREG2", %%xmm6 \n\t" \
- "paddsw "REG0", "SREG2" \n\t" \
- MOV_32_ONLY" "TAN1", (%0) \n\t" \
- "movdqa "REG0", "XMMS" \n\t" \
- "psubsw %%xmm5, "REG0" \n\t" \
- "paddsw "XMMS", %%xmm5 \n\t" \
- "movdqa %%xmm5, "XMMS" \n\t" \
- "psubsw "TAN3", %%xmm5 \n\t" \
- "paddsw "XMMS", "TAN3" \n\t" \
- "movdqa "REG0", "XMMS" \n\t" \
- "psubsw %%xmm3, "REG0" \n\t" \
- "paddsw "XMMS", %%xmm3 \n\t" \
- MOV_32_ONLY" (%0), "TAN1" \n\t" \
- "psraw $6, %%xmm5 \n\t" \
- "psraw $6, "REG0" \n\t" \
- "psraw $6, "TAN3" \n\t" \
- "psraw $6, %%xmm3 \n\t" \
- "movdqa "TAN3", 1*16("dct") \n\t" \
- "movdqa %%xmm3, 2*16("dct") \n\t" \
- "movdqa "REG0", 5*16("dct") \n\t" \
- "movdqa %%xmm5, 6*16("dct") \n\t" \
- "movdqa "SREG2", %%xmm0 \n\t" \
- "movdqa %%xmm6, %%xmm4 \n\t" \
- "psubsw %%xmm1, "SREG2" \n\t" \
- "psubsw "TAN1", %%xmm6 \n\t" \
- "paddsw %%xmm0, %%xmm1 \n\t" \
- "paddsw %%xmm4, "TAN1" \n\t" \
- "psraw $6, %%xmm1 \n\t" \
- "psraw $6, "SREG2" \n\t" \
- "psraw $6, "TAN1" \n\t" \
- "psraw $6, %%xmm6 \n\t" \
- "movdqa %%xmm1, ("dct") \n\t" \
- "movdqa "TAN1", 3*16("dct") \n\t" \
- "movdqa %%xmm6, 4*16("dct") \n\t" \
- "movdqa "SREG2", 7*16("dct") \n\t"
-
-inline void ff_xvid_idct_sse2(short *block)
-{
- __asm__ volatile (
- "movq "MANGLE (m127) ", %%mm0 \n\t"
- iMTX_MULT("(%0)", MANGLE(iTab1), ROUND(walkenIdctRounders), PUT_EVEN(ROW0))
- iMTX_MULT("1*16(%0)", MANGLE(iTab2), ROUND(walkenIdctRounders + 1 * 16), PUT_ODD(ROW1))
- iMTX_MULT("2*16(%0)", MANGLE(iTab3), ROUND(walkenIdctRounders + 2 * 16), PUT_EVEN(ROW2))
-
- TEST_TWO_ROWS("3*16(%0)", "4*16(%0)", "%%eax", "%%ecx", CLEAR_ODD(ROW3), CLEAR_EVEN(ROW4))
- JZ("%%eax", "1f")
- iMTX_MULT("3*16(%0)", MANGLE(iTab4), ROUND(walkenIdctRounders + 3 * 16), PUT_ODD(ROW3))
-
- TEST_TWO_ROWS("5*16(%0)", "6*16(%0)", "%%eax", "%%edx", CLEAR_ODD(ROW5), CLEAR_EVEN(ROW6))
- TEST_ONE_ROW("7*16(%0)", "%%esi", CLEAR_ODD(ROW7))
- iLLM_HEAD
- ".p2align 4 \n\t"
- JNZ("%%ecx", "2f")
- JNZ("%%eax", "3f")
- JNZ("%%edx", "4f")
- JNZ("%%esi", "5f")
- iLLM_PASS_SPARSE("%0")
- "jmp 6f \n\t"
- "2: \n\t"
- iMTX_MULT("4*16(%0)", MANGLE(iTab1), "#", PUT_EVEN(ROW4))
- "3: \n\t"
- iMTX_MULT("5*16(%0)", MANGLE(iTab4), ROUND(walkenIdctRounders + 4 * 16), PUT_ODD(ROW5))
- JZ("%%edx", "1f")
- "4: \n\t"
- iMTX_MULT("6*16(%0)", MANGLE(iTab3), ROUND(walkenIdctRounders + 5 * 16), PUT_EVEN(ROW6))
- JZ("%%esi", "1f")
- "5: \n\t"
- iMTX_MULT("7*16(%0)", MANGLE(iTab2), ROUND(walkenIdctRounders + 5 * 16), PUT_ODD(ROW7))
-#if ARCH_X86_32
- iLLM_HEAD
-#endif
- iLLM_PASS("%0")
- "6: \n\t"
- : "+r" (block)
- :
- : XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3",
- "%xmm4", "%xmm5", "%xmm6", "%xmm7", )
-#if ARCH_X86_64
- XMM_CLOBBERS("%xmm8", "%xmm9", "%xmm10", "%xmm11",
- "%xmm12", "%xmm13", "%xmm14", )
-#endif
- "%eax", "%ecx", "%edx", "%esi", "memory");
-}
-
-void ff_xvid_idct_sse2_put(uint8_t *dest, int line_size, short *block)
-{
- ff_xvid_idct_sse2(block);
- ff_put_pixels_clamped_mmx(block, dest, line_size);
-}
-
-void ff_xvid_idct_sse2_add(uint8_t *dest, int line_size, short *block)
-{
- ff_xvid_idct_sse2(block);
- ff_add_pixels_clamped_mmx(block, dest, line_size);
-}
-
-#endif /* HAVE_SSE2_INLINE */
diff --git a/libavcodec/xan.c b/libavcodec/xan.c
index 4bf1d87f9d..2c565eed0d 100644
--- a/libavcodec/xan.c
+++ b/libavcodec/xan.c
@@ -1,21 +1,21 @@
/*
* Wing Commander/Xan Video Decoder
- * Copyright (C) 2003 the ffmpeg project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,13 +54,13 @@ typedef struct XanContext {
AVCodecContext *avctx;
AVFrame *last_frame;
- const unsigned char *buf;
+ const uint8_t *buf;
int size;
/* scratch space */
- unsigned char *buffer1;
+ uint8_t *buffer1;
int buffer1_size;
- unsigned char *buffer2;
+ uint8_t *buffer2;
int buffer2_size;
unsigned *palettes;
@@ -113,22 +113,21 @@ static av_cold int xan_decode_init(AVCodecContext *avctx)
return 0;
}
-static int xan_huffman_decode(unsigned char *dest, int dest_len,
- const unsigned char *src, int src_len)
+static int xan_huffman_decode(uint8_t *dest, int dest_len,
+ const uint8_t *src, int src_len)
{
- unsigned char byte = *src++;
- unsigned char ival = byte + 0x16;
- const unsigned char * ptr = src + byte*2;
+ uint8_t byte = *src++;
+ uint8_t ival = byte + 0x16;
+ const uint8_t * ptr = src + byte*2;
int ptr_len = src_len - 1 - byte*2;
- unsigned char val = ival;
- unsigned char *dest_end = dest + dest_len;
- unsigned char *dest_start = dest;
+ uint8_t val = ival;
+ uint8_t *dest_end = dest + dest_len;
+ uint8_t *dest_start = dest;
+ int ret;
GetBitContext gb;
- if (ptr_len < 0)
- return AVERROR_INVALIDDATA;
-
- init_get_bits(&gb, ptr, ptr_len * 8);
+ if ((ret = init_get_bits8(&gb, ptr, ptr_len)) < 0)
+ return ret;
while (val != 0x16) {
unsigned idx = val - 0x17 + get_bits1(&gb) * byte;
@@ -152,13 +151,13 @@ static int xan_huffman_decode(unsigned char *dest, int dest_len,
*
* @param dest destination buffer of dest_len, must be padded with at least 130 bytes
*/
-static void xan_unpack(unsigned char *dest, int dest_len,
- const unsigned char *src, int src_len)
+static void xan_unpack(uint8_t *dest, int dest_len,
+ const uint8_t *src, int src_len)
{
- unsigned char opcode;
+ uint8_t opcode;
int size;
- unsigned char *dest_org = dest;
- unsigned char *dest_end = dest + dest_len;
+ uint8_t *dest_org = dest;
+ uint8_t *dest_end = dest + dest_len;
GetByteContext ctx;
bytestream2_init(&ctx, src, src_len);
@@ -207,14 +206,14 @@ static void xan_unpack(unsigned char *dest, int dest_len,
}
static inline void xan_wc3_output_pixel_run(XanContext *s, AVFrame *frame,
- const unsigned char *pixel_buffer, int x, int y, int pixel_count)
+ const uint8_t *pixel_buffer, int x, int y, int pixel_count)
{
int stride;
int line_inc;
int index;
int current_x;
int width = s->avctx->width;
- unsigned char *palette_plane;
+ uint8_t *palette_plane;
palette_plane = frame->data[0];
stride = frame->linesize[0];
@@ -246,7 +245,7 @@ static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame,
int curframe_index, prevframe_index;
int curframe_x, prevframe_x;
int width = s->avctx->width;
- unsigned char *palette_plane, *prev_palette_plane;
+ uint8_t *palette_plane, *prev_palette_plane;
if (y + motion_y < 0 || y + motion_y >= s->avctx->height ||
x + motion_x < 0 || x + motion_x >= s->avctx->width)
@@ -262,6 +261,12 @@ static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame,
curframe_x = x;
prevframe_index = (y + motion_y) * stride + x + motion_x;
prevframe_x = x + motion_x;
+
+ if (prev_palette_plane == palette_plane && FFABS(curframe_index - prevframe_index) < pixel_count) {
+ avpriv_request_sample(s->avctx, "Overlapping copy\n");
+ return ;
+ }
+
while (pixel_count &&
curframe_index < s->frame_size &&
prevframe_index < s->frame_size) {
@@ -294,22 +299,22 @@ static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
int width = s->avctx->width;
int height = s->avctx->height;
int total_pixels = width * height;
- unsigned char opcode;
- unsigned char flag = 0;
+ uint8_t opcode;
+ uint8_t flag = 0;
int size = 0;
int motion_x, motion_y;
int x, y, ret;
- unsigned char *opcode_buffer = s->buffer1;
- unsigned char *opcode_buffer_end = s->buffer1 + s->buffer1_size;
+ uint8_t *opcode_buffer = s->buffer1;
+ uint8_t *opcode_buffer_end = s->buffer1 + s->buffer1_size;
int opcode_buffer_size = s->buffer1_size;
- const unsigned char *imagedata_buffer = s->buffer2;
+ const uint8_t *imagedata_buffer = s->buffer2;
/* pointers to segments inside the compressed chunk */
- const unsigned char *huffman_segment;
+ const uint8_t *huffman_segment;
GetByteContext size_segment;
GetByteContext vector_segment;
- const unsigned char *imagedata_segment;
+ const uint8_t *imagedata_segment;
int huffman_offset, size_offset, vector_offset, imagedata_offset,
imagedata_size;
@@ -382,16 +387,28 @@ static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
case 9:
case 19:
+ if (bytestream2_get_bytes_left(&size_segment) < 1) {
+ av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
size = bytestream2_get_byte(&size_segment);
break;
case 10:
case 20:
+ if (bytestream2_get_bytes_left(&size_segment) < 2) {
+ av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
size = bytestream2_get_be16(&size_segment);
break;
case 11:
case 21:
+ if (bytestream2_get_bytes_left(&size_segment) < 3) {
+ av_log(s->avctx, AV_LOG_ERROR, "size_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
size = bytestream2_get_be24(&size_segment);
break;
}
@@ -413,8 +430,13 @@ static int xan_wc3_decode_frame(XanContext *s, AVFrame *frame)
imagedata_size -= size;
}
} else {
+ uint8_t vector;
+ if (bytestream2_get_bytes_left(&vector_segment) <= 0) {
+ av_log(s->avctx, AV_LOG_ERROR, "vector_segment overread\n");
+ return AVERROR_INVALIDDATA;
+ }
/* run-based motion compensation from last frame */
- uint8_t vector = bytestream2_get_byte(&vector_segment);
+ vector = bytestream2_get_byte(&vector_segment);
motion_x = sign_extend(vector >> 4, 4);
motion_y = sign_extend(vector & 0xF, 4);
@@ -534,6 +556,10 @@ static int xan_decode_frame(AVCodecContext *avctx,
int i;
tag = bytestream2_get_le32(&ctx);
size = bytestream2_get_be32(&ctx);
+ if (size < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid tag size %d\n", size);
+ return AVERROR_INVALIDDATA;
+ }
size = FFMIN(size, bytestream2_get_bytes_left(&ctx));
switch (tag) {
case PALT_TAG:
@@ -541,8 +567,8 @@ static int xan_decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
if (s->palettes_count >= PALETTES_MAX)
return AVERROR_INVALIDDATA;
- tmpptr = av_realloc(s->palettes,
- (s->palettes_count + 1) * AVPALETTE_SIZE);
+ tmpptr = av_realloc_array(s->palettes,
+ s->palettes_count + 1, AVPALETTE_SIZE);
if (!tmpptr)
return AVERROR(ENOMEM);
s->palettes = tmpptr;
@@ -557,7 +583,7 @@ static int xan_decode_frame(AVCodecContext *avctx,
int g = gamma_lookup[bytestream2_get_byteu(&ctx)];
int b = gamma_lookup[bytestream2_get_byteu(&ctx)];
#endif
- *tmpptr++ = (r << 16) | (g << 8) | b;
+ *tmpptr++ = (0xFFU << 24) | (r << 16) | (g << 8) | b;
}
s->palettes_count++;
break;
@@ -584,10 +610,8 @@ static int xan_decode_frame(AVCodecContext *avctx,
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF))) {
- av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
if (!s->frame_size)
s->frame_size = frame->linesize[0] * s->avctx->height;
diff --git a/libavcodec/xbmdec.c b/libavcodec/xbmdec.c
index c26f3433fd..143e3a2831 100644
--- a/libavcodec/xbmdec.c
+++ b/libavcodec/xbmdec.c
@@ -1,20 +1,22 @@
/*
* XBM image format
*
- * This file is part of Libav.
+ * Copyright (c) 2012 Paul B Mahol
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,43 +26,54 @@
#include "internal.h"
#include "mathops.h"
+static int convert(uint8_t x)
+{
+ if (x >= 'a')
+ x -= 87;
+ else if (x >= 'A')
+ x -= 55;
+ else
+ x -= '0';
+ return x;
+}
+
+static int parse_str_int(const uint8_t *p, int len, const uint8_t *key)
+{
+ const uint8_t *end = p + len;
+
+ for(; p<end - strlen(key); p++) {
+ if (!memcmp(p, key, strlen(key)))
+ break;
+ }
+ p += strlen(key);
+ if (p >= end)
+ return INT_MIN;
+
+ for(; p<end; p++) {
+ char *eptr;
+ int64_t ret = strtol(p, &eptr, 10);
+ if ((const uint8_t *)eptr != p)
+ return ret;
+ }
+ return INT_MIN;
+}
+
static int xbm_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
AVFrame *p = data;
- int ret, linesize, i;
+ int ret, linesize, i, j;
int width = 0;
int height = 0;
- const uint8_t *ptr = avpkt->data;
+ const uint8_t *end, *ptr = avpkt->data;
+ const uint8_t *next;
uint8_t *dst;
avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
- while (!width || !height) {
- ptr += strcspn(ptr, "#");
- if (ptr >= avpkt->data + avpkt->size) {
- av_log(avctx, AV_LOG_ERROR, "End of file reached.\n");
- return AVERROR_INVALIDDATA;
- }
- if (strncmp(ptr, "#define", 7) != 0) {
- av_log(avctx, AV_LOG_ERROR,
- "Unexpected preprocessor directive.\n");
- return AVERROR_INVALIDDATA;
- }
- // skip the name
- ptr += strcspn(ptr, "_") + 1;
- // get width or height
- if (strncmp(ptr, "width", 5) == 0) {
- ptr += strcspn(ptr, " ");
- width = strtol(ptr, NULL, 10);
- } else if (strncmp(ptr, "height", 6) == 0) {
- ptr += strcspn(ptr, " ");
- height = strtol(ptr, NULL, 10);
- } else {
- // skip offset and unknown variables
- av_log(avctx, AV_LOG_VERBOSE,
- "Ignoring preprocessor directive.\n");
- }
- }
+ end = avpkt->data + avpkt->size;
+
+ width = parse_str_int(avpkt->data, avpkt->size, "_width");
+ height = parse_str_int(avpkt->data, avpkt->size, "_height");
if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
return ret;
@@ -68,46 +81,48 @@ static int xbm_decode_frame(AVCodecContext *avctx, void *data,
if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- // go to start of image data
- ptr += strcspn(ptr, "{");
+ // goto start of image data
+ next = memchr(ptr, '{', avpkt->size);
+ if (!next)
+ next = memchr(ptr, '(', avpkt->size);
+ if (!next)
+ return AVERROR_INVALIDDATA;
+ ptr = next + 1;
linesize = (avctx->width + 7) / 8;
for (i = 0; i < avctx->height; i++) {
- int eol = 0, e = 0;
dst = p->data[0] + i * p->linesize[0];
- if (ptr >= avpkt->data + avpkt->size) {
- av_log(avctx, AV_LOG_ERROR, "End of file reached.\n");
- return AVERROR_INVALIDDATA;
- }
- do {
- int val;
- uint8_t *endptr;
+ for (j = 0; j < linesize; j++) {
+ uint8_t val;
- ptr += strcspn(ptr, "x") - 1; // -1 to get 0x
- val = strtol(ptr, (char **)&endptr, 16);
+ while (ptr < end && *ptr != 'x' && *ptr != '$')
+ ptr++;
- if (endptr - ptr == 4) {
- // XBM X11 format
+ ptr ++;
+ if (ptr < end && av_isxdigit(*ptr)) {
+ val = convert(*ptr++);
+ if (av_isxdigit(*ptr))
+ val = (val << 4) + convert(*ptr++);
*dst++ = ff_reverse[val];
- eol = linesize;
- } else if (endptr - ptr == 6) {
- // XBM X10 format
- *dst++ = ff_reverse[val >> 8];
- *dst++ = ff_reverse[val & 0xFF];
- eol = linesize / 2; // 2 bytes read
+ if (av_isxdigit(*ptr) && j+1 < linesize) {
+ j++;
+ val = convert(*ptr++);
+ if (av_isxdigit(*ptr))
+ val = (val << 4) + convert(*ptr++);
+ *dst++ = ff_reverse[val];
+ }
} else {
av_log(avctx, AV_LOG_ERROR,
"Unexpected data at %.8s.\n", ptr);
return AVERROR_INVALIDDATA;
}
- ptr = endptr;
- } while (++e < eol);
+ }
}
p->key_frame = 1;
p->pict_type = AV_PICTURE_TYPE_I;
- *got_frame = 1;
+ *got_frame = 1;
return avpkt->size;
}
diff --git a/libavcodec/xbmenc.c b/libavcodec/xbmenc.c
index 517e569a60..a752bdf2a7 100644
--- a/libavcodec/xbmenc.c
+++ b/libavcodec/xbmenc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,16 +24,6 @@
#include "internal.h"
#include "mathops.h"
-static av_cold int xbm_encode_init(AVCodecContext *avctx)
-{
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
-
- return 0;
-}
-
static int xbm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *p, int *got_packet)
{
@@ -42,10 +32,8 @@ static int xbm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
linesize = (avctx->width + 7) / 8;
size = avctx->height * (linesize * 7 + 2) + 110;
- if ((ret = ff_alloc_packet(pkt, size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, size)) < 0)
return ret;
- }
buf = pkt->data;
ptr = p->data[0];
@@ -67,21 +55,12 @@ static int xbm_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
-static av_cold int xbm_encode_close(AVCodecContext *avctx)
-{
- av_frame_free(&avctx->coded_frame);
-
- return 0;
-}
-
AVCodec ff_xbm_encoder = {
.name = "xbm",
.long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_XBM,
- .init = xbm_encode_init,
.encode2 = xbm_encode_frame,
- .close = xbm_encode_close,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE,
- AV_PIX_FMT_NONE },
+ AV_PIX_FMT_NONE },
};
diff --git a/libavcodec/xface.c b/libavcodec/xface.c
new file mode 100644
index 0000000000..8c0cbfdb84
--- /dev/null
+++ b/libavcodec/xface.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 1990 James Ashton - Sydney University
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * X-Face common data and utilities definition.
+ */
+
+#include "libavutil/avassert.h"
+
+#include "xface.h"
+
+void ff_big_add(BigInt *b, uint8_t a)
+{
+ int i;
+ uint8_t *w;
+ uint16_t c;
+
+ a &= XFACE_WORDMASK;
+ if (a == 0)
+ return;
+ w = b->words;
+ c = a;
+ for (i = 0; i < b->nb_words && c; i++) {
+ c += *w;
+ *w++ = c & XFACE_WORDMASK;
+ c >>= XFACE_BITSPERWORD;
+ }
+ if (i == b->nb_words && c) {
+ av_assert0(b->nb_words < XFACE_MAX_WORDS);
+ b->nb_words++;
+ *w = c & XFACE_WORDMASK;
+ }
+}
+
+void ff_big_div(BigInt *b, uint8_t a, uint8_t *r)
+{
+ int i;
+ uint8_t *w;
+ uint16_t c, d;
+
+ a &= XFACE_WORDMASK;
+ if (a == 1 || b->nb_words == 0) {
+ *r = 0;
+ return;
+ }
+
+ /* treat this as a == WORDCARRY and just shift everything right a WORD */
+ if (a == 0) {
+ i = --b->nb_words;
+ w = b->words;
+ *r = *w;
+ while (i--) {
+ *w = *(w + 1);
+ w++;
+ }
+ *w = 0;
+ return;
+ }
+ i = b->nb_words;
+ w = b->words + i;
+ c = 0;
+ while (i--) {
+ c <<= XFACE_BITSPERWORD;
+ c += *--w;
+ d = c / (uint16_t)a;
+ c = c % (uint16_t)a;
+ *w = d & XFACE_WORDMASK;
+ }
+ *r = c;
+ if (b->words[b->nb_words - 1] == 0)
+ b->nb_words--;
+}
+
+void ff_big_mul(BigInt *b, uint8_t a)
+{
+ int i;
+ uint8_t *w;
+ uint16_t c;
+
+ a &= XFACE_WORDMASK;
+ if (a == 1 || b->nb_words == 0)
+ return;
+ if (a == 0) {
+ /* treat this as a == WORDCARRY and just shift everything left a WORD */
+ av_assert0(b->nb_words < XFACE_MAX_WORDS);
+ i = b->nb_words++;
+ w = b->words + i;
+ while (i--) {
+ *w = *(w - 1);
+ w--;
+ }
+ *w = 0;
+ return;
+ }
+ i = b->nb_words;
+ w = b->words;
+ c = 0;
+ while (i--) {
+ c += (uint16_t)*w * (uint16_t)a;
+ *(w++) = c & XFACE_WORDMASK;
+ c >>= XFACE_BITSPERWORD;
+ }
+ if (c) {
+ av_assert0(b->nb_words < XFACE_MAX_WORDS);
+ b->nb_words++;
+ *w = c & XFACE_WORDMASK;
+ }
+}
+
+const ProbRange ff_xface_probranges_per_level[4][3] = {
+ // black grey white
+ { { 1, 255}, {251, 0}, { 4, 251} }, /* Top of tree almost always grey */
+ { { 1, 255}, {200, 0}, { 55, 200} },
+ { { 33, 223}, {159, 0}, { 64, 159} },
+ { {131, 0}, { 0, 0}, {125, 131} }, /* Grey disallowed at bottom */
+};
+
+const ProbRange ff_xface_probranges_2x2[16] = {
+ { 0, 0}, {38, 0}, {38, 38}, {13, 152},
+ {38, 76}, {13, 165}, {13, 178}, { 6, 230},
+ {38, 114}, {13, 191}, {13, 204}, { 6, 236},
+ {13, 217}, { 6, 242}, { 5, 248}, { 3, 253},
+};
+
+/*
+ * The "guess the next pixel" tables follow. Normally there are 12
+ * neighbour pixels used to give 1<<12 cases as we get closer to the
+ * upper left corner lesser numbers of neighbours are available.
+ *
+ * Each byte in the tables represents 8 boolean values starting from
+ * the most significant bit.
+ */
+
+static const uint8_t g_00[] = {
+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xe3, 0xdf, 0x05, 0x17,
+ 0x05, 0x0f, 0x00, 0x1b, 0x0f, 0xdf, 0x00, 0x04, 0x00, 0x00,
+ 0x0d, 0x0f, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1d,
+ 0x45, 0x2f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x0a, 0xff, 0xff,
+ 0x00, 0x04, 0x00, 0x05, 0x01, 0x3f, 0xcf, 0xff, 0x10, 0x01,
+ 0x80, 0xc9, 0x0f, 0x0f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x1b, 0x1f, 0xff, 0xff, 0x4f, 0x54, 0x07, 0x1f, 0x57, 0x47,
+ 0xd7, 0x3d, 0xff, 0xff, 0x5f, 0x1f, 0x7f, 0xff, 0x7f, 0x7f,
+ 0x05, 0x0f, 0x01, 0x0f, 0x0f, 0x5f, 0x9b, 0xdf, 0x7f, 0xff,
+ 0x5f, 0x1d, 0x5f, 0xff, 0x0f, 0x1f, 0x0f, 0x5f, 0x03, 0x1f,
+ 0x4f, 0x5f, 0xf7, 0x7f, 0x7f, 0xff, 0x0d, 0x0f, 0xfb, 0xff,
+ 0xf7, 0xbf, 0x0f, 0x4f, 0xd7, 0x3f, 0x4f, 0x7f, 0xff, 0xff,
+ 0x67, 0xbf, 0x56, 0x25, 0x1f, 0x7f, 0x9f, 0xff, 0x00, 0x00,
+ 0x00, 0x05, 0x5f, 0x7f, 0x01, 0xdf, 0x14, 0x00, 0x05, 0x0f,
+ 0x07, 0xa2, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5f,
+ 0x18, 0xd7, 0x94, 0x71, 0x00, 0x05, 0x1f, 0xb7, 0x0c, 0x07,
+ 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x1f, 0x84, 0x8f, 0x05, 0x15,
+ 0x05, 0x0f, 0x4f, 0xff, 0x87, 0xdf, 0x05, 0x01, 0x10, 0x00,
+ 0x0f, 0x0f, 0x00, 0x08, 0x05, 0x04, 0x04, 0x01, 0x4f, 0xff,
+ 0x9f, 0x8f, 0x4a, 0x40, 0x5f, 0x5f, 0xff, 0xfe, 0xdf, 0xff,
+ 0x7f, 0xf7, 0xff, 0x7f, 0xff, 0xff, 0x7b, 0xff, 0x0f, 0xfd,
+ 0xd7, 0x5f, 0x4f, 0x7f, 0x7f, 0xdf, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x77, 0xdf, 0x7f, 0x4f, 0xef, 0xff, 0xff, 0x77, 0xff,
+ 0xff, 0xff, 0x6f, 0xff, 0x0f, 0x4f, 0xff, 0xff, 0x9d, 0xff,
+ 0x0f, 0xef, 0xff, 0xdf, 0x6f, 0xff, 0xff, 0xff, 0x4f, 0xff,
+ 0xcd, 0x0f, 0x4f, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x0b,
+ 0x05, 0x02, 0x02, 0x0f, 0x04, 0x00, 0x00, 0x0c, 0x01, 0x06,
+ 0x00, 0x0f, 0x20, 0x03, 0x00, 0x00, 0x05, 0x0f, 0x40, 0x08,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x0c, 0x0f, 0x01, 0x00,
+ 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x14, 0x01, 0x05,
+ 0x01, 0x15, 0xaf, 0x0f, 0x00, 0x01, 0x10, 0x00, 0x08, 0x00,
+ 0x46, 0x0c, 0x20, 0x00, 0x88, 0x00, 0x0f, 0x15, 0xff, 0xdf,
+ 0x02, 0x00, 0x00, 0x0f, 0x7f, 0x5f, 0xdb, 0xff, 0x4f, 0x3e,
+ 0x05, 0x0f, 0x7f, 0xf7, 0x95, 0x4f, 0x0d, 0x0f, 0x01, 0x0f,
+ 0x4f, 0x5f, 0x9f, 0xdf, 0x25, 0x0e, 0x0d, 0x0d, 0x4f, 0x7f,
+ 0x8f, 0x0f, 0x0f, 0xfa, 0x04, 0x4f, 0x4f, 0xff, 0xf7, 0x77,
+ 0x47, 0xed, 0x05, 0x0f, 0xff, 0xff, 0xdf, 0xff, 0x4f, 0x6f,
+ 0xd8, 0x5f, 0x0f, 0x7f, 0xdf, 0x5f, 0x07, 0x0f, 0x94, 0x0d,
+ 0x1f, 0xff, 0xff, 0xff, 0x00, 0x02, 0x00, 0x03, 0x46, 0x57,
+ 0x01, 0x0d, 0x01, 0x08, 0x01, 0x0f, 0x47, 0x6c, 0x0d, 0x0f,
+ 0x02, 0x00, 0x00, 0x00, 0x0b, 0x4f, 0x00, 0x08, 0x05, 0x00,
+ 0x95, 0x01, 0x0f, 0x7f, 0x0c, 0x0f, 0x01, 0x0e, 0x00, 0x00,
+ 0x0f, 0x41, 0x00, 0x00, 0x04, 0x24, 0x0d, 0x0f, 0x0f, 0x7f,
+ 0xcf, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00,
+ 0x06, 0x26, 0xcf, 0x05, 0xcf, 0x7f, 0xdf, 0xdf, 0x00, 0x00,
+ 0x17, 0x5f, 0xff, 0xfd, 0xff, 0xff, 0x46, 0x09, 0x4f, 0x5f,
+ 0x7f, 0xfd, 0xdf, 0xff, 0x0a, 0x88, 0xa7, 0x7f, 0x7f, 0xff,
+ 0xff, 0xff, 0x0f, 0x04, 0xdf, 0x7f, 0x4f, 0xff, 0x9f, 0xff,
+ 0x0e, 0xe6, 0xdf, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x0f, 0xec,
+ 0x8f, 0x4f, 0x7f, 0xff, 0xdf, 0xff, 0x0f, 0xcf, 0xdf, 0xff,
+ 0x6f, 0x7f, 0xff, 0xff, 0x03, 0x0c, 0x9d, 0x0f, 0x7f, 0xff,
+ 0xff, 0xff,
+};
+
+static const uint8_t g_01[] = {
+ 0x37, 0x73, 0x00, 0x19, 0x57, 0x7f, 0xf5, 0xfb, 0x70, 0x33,
+ 0xf0, 0xf9, 0x7f, 0xff, 0xff, 0xff,
+};
+
+static const uint8_t g_02[] = {
+ 0x50,
+};
+
+static const uint8_t g_10[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0xf3, 0x5f, 0x84, 0x04,
+ 0x17, 0x9f, 0x04, 0x23, 0x05, 0xff, 0x00, 0x00, 0x00, 0x02,
+ 0x03, 0x03, 0x33, 0xd7, 0x05, 0x03, 0x5f, 0x3f, 0x17, 0x33,
+ 0xff, 0xff, 0x00, 0x80, 0x02, 0x04, 0x12, 0x00, 0x11, 0x57,
+ 0x05, 0x25, 0x05, 0x03, 0x35, 0xbf, 0x9f, 0xff, 0x07, 0x6f,
+ 0x20, 0x40, 0x17, 0x06, 0xfa, 0xe8, 0x01, 0x07, 0x1f, 0x9f,
+ 0x1f, 0xff, 0xff, 0xff,
+};
+
+static const uint8_t g_20[] = {
+ 0x04, 0x00, 0x01, 0x01, 0x43, 0x2e, 0xff, 0x3f,
+};
+
+static const uint8_t g_30[] = {
+ 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x13, 0x11, 0x11, 0x11,
+ 0x13, 0x11, 0x11, 0x11, 0x33, 0x11, 0x13, 0x11, 0x13, 0x13,
+ 0x13, 0x13, 0x31, 0x31, 0x11, 0x01, 0x11, 0x11, 0x71, 0x11,
+ 0x11, 0x75,
+};
+
+static const uint8_t g_40[] = {
+ 0x00, 0x0f, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0f,
+ 0x00, 0x4e, 0xe4, 0x0d, 0x10, 0x0f, 0x00, 0x0f, 0x44, 0x4f,
+ 0x00, 0x1e, 0x0f, 0x0f, 0xae, 0xaf, 0x45, 0x7f, 0xef, 0xff,
+ 0x0f, 0xff, 0x00, 0x09, 0x01, 0x11, 0x00, 0x01, 0x1c, 0xdd,
+ 0x00, 0x15, 0x00, 0xff, 0x00, 0x10, 0x00, 0xfd, 0x00, 0x0f,
+ 0x4f, 0x5f, 0x3d, 0xff, 0xff, 0xff, 0x4f, 0xff, 0x1c, 0xff,
+ 0xdf, 0xff, 0x8f, 0xff, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x15,
+ 0x01, 0x07, 0x00, 0x01, 0x02, 0x1f, 0x01, 0x11, 0x05, 0x7f,
+ 0x00, 0x1f, 0x41, 0x57, 0x1f, 0xff, 0x05, 0x77, 0x0d, 0x5f,
+ 0x4d, 0xff, 0x4f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x02, 0x05,
+ 0x00, 0x11, 0x05, 0x7d, 0x10, 0x15, 0x2f, 0xff, 0x40, 0x50,
+ 0x0d, 0xfd, 0x04, 0x0f, 0x07, 0x1f, 0x07, 0x7f, 0x0f, 0xbf,
+ 0x0d, 0x7f, 0x0f, 0xff, 0x4d, 0x7d, 0x0f, 0xff,
+};
+
+static const uint8_t g_11[] = {
+ 0x01, 0x13, 0x03, 0x7f,
+};
+
+static const uint8_t g_21[] = {
+ 0x17,
+};
+
+static const uint8_t g_31[] = {
+ 0x55, 0x57, 0x57, 0x7f,
+};
+
+static const uint8_t g_41[] = {
+ 0x01, 0x01, 0x01, 0x1f, 0x03, 0x1f, 0x3f, 0xff,
+};
+
+static const uint8_t g_12[] = {
+ 0x40,
+};
+
+static const uint8_t g_22[] = {
+ 0x00,
+};
+
+static const uint8_t g_32[] = {
+ 0x10,
+};
+
+static const uint8_t g_42[] = {
+ 0x10,
+};
+
+void ff_xface_generate_face(uint8_t *dst, uint8_t * const src)
+{
+ int h, i, j, k, l, m;
+
+ for (j = 0; j < XFACE_HEIGHT; j++) {
+ for (i = 0; i < XFACE_WIDTH; i++) {
+ h = i + j * XFACE_WIDTH;
+ k = 0;
+
+ /*
+ Compute k, encoding the bits *before* the current one, contained in the
+ image buffer. That is, given the grid:
+
+ l i
+ | |
+ v v
+ +--+--+--+--+--+
+ m -> | 1| 2| 3| 4| 5|
+ +--+--+--+--+--+
+ | 6| 7| 8| 9|10|
+ +--+--+--+--+--+
+ j -> |11|12| *| | |
+ +--+--+--+--+--+
+
+ the value k for the pixel marked as "*" will contain the bit encoding of
+ the values in the matrix marked from "1" to "12". In case the pixel is
+ near the border of the grid, the number of values contained within the
+ grid will be lesser than 12.
+ */
+
+ for (l = i - 2; l <= i + 2; l++) {
+ for (m = j - 2; m <= j; m++) {
+ if (l >= i && m == j)
+ continue;
+ if (l > 0 && l <= XFACE_WIDTH && m > 0)
+ k = 2*k + src[l + m * XFACE_WIDTH];
+ }
+ }
+
+ /*
+ Use the guess for the given position and the computed value of k.
+
+ The following table shows the number of digits in k, depending on
+ the position of the pixel, and shows the corresponding guess table
+ to use:
+
+ i=1 i=2 i=3 i=w-1 i=w
+ +----+----+----+ ... +----+----+
+ j=1 | 0 | 1 | 2 | | 2 | 2 |
+ |g22 |g12 |g02 | |g42 |g32 |
+ +----+----+----+ ... +----+----+
+ j=2 | 3 | 5 | 7 | | 6 | 5 |
+ |g21 |g11 |g01 | |g41 |g31 |
+ +----+----+----+ ... +----+----+
+ j=3 | 5 | 9 | 12 | | 10 | 8 |
+ |g20 |g10 |g00 | |g40 |g30 |
+ +----+----+----+ ... +----+----+
+ */
+
+#define GEN(table) dst[h] ^= (table[k>>3]>>(7-(k&7)))&1
+
+ switch (i) {
+ case 1:
+ switch (j) {
+ case 1: GEN(g_22); break;
+ case 2: GEN(g_21); break;
+ default: GEN(g_20); break;
+ }
+ break;
+ case 2:
+ switch (j) {
+ case 1: GEN(g_12); break;
+ case 2: GEN(g_11); break;
+ default: GEN(g_10); break;
+ }
+ break;
+ case XFACE_WIDTH - 1:
+ switch (j) {
+ case 1: GEN(g_42); break;
+ case 2: GEN(g_41); break;
+ default: GEN(g_40); break;
+ }
+ break;
+ case XFACE_WIDTH:
+ switch (j) {
+ case 1: GEN(g_32); break;
+ case 2: GEN(g_31); break;
+ default: GEN(g_30); break;
+ }
+ break;
+ default:
+ switch (j) {
+ case 1: GEN(g_02); break;
+ case 2: GEN(g_01); break;
+ default: GEN(g_00); break;
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/libavcodec/xface.h b/libavcodec/xface.h
new file mode 100644
index 0000000000..0236d713ad
--- /dev/null
+++ b/libavcodec/xface.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1990 James Ashton - Sydney University
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * X-Face common definitions.
+ */
+
+#include <stdint.h>
+
+/* define the face size - 48x48x1 */
+#define XFACE_WIDTH 48
+#define XFACE_HEIGHT 48
+#define XFACE_PIXELS (XFACE_WIDTH * XFACE_HEIGHT)
+
+/* compressed output uses the full range of printable characters.
+ * In ASCII these are in a contiguous block so we just need to know
+ * the first and last. The total number of printables is needed too. */
+#define XFACE_FIRST_PRINT '!'
+#define XFACE_LAST_PRINT '~'
+#define XFACE_PRINTS (XFACE_LAST_PRINT - XFACE_FIRST_PRINT + 1)
+
+/*
+ * Image is encoded as a big integer, using characters from '~' to
+ * '!', for a total of 94 symbols. In order to express
+ * 48x48 pixels with the worst case encoding 666 symbols should
+ * be sufficient.
+ */
+#define XFACE_MAX_DIGITS 666
+
+#define XFACE_BITSPERWORD 8
+#define XFACE_WORDCARRY (1 << XFACE_BITSPERWORD)
+#define XFACE_WORDMASK (XFACE_WORDCARRY - 1)
+
+// This must be larger or equal to log256(94^XFACE_MAX_DIGITS)
+#define XFACE_MAX_WORDS 546
+
+/* Portable, very large unsigned integer arithmetic is needed.
+ * Implementation uses arrays of WORDs. */
+typedef struct {
+ int nb_words;
+ uint8_t words[XFACE_MAX_WORDS];
+} BigInt;
+
+/**
+ * Add a to b storing the result in b.
+ */
+void ff_big_add(BigInt *b, uint8_t a);
+
+/**
+ * Divide b by a storing the result in b and the remainder in the word
+ * pointed to by r.
+ */
+void ff_big_div(BigInt *b, uint8_t a, uint8_t *r);
+
+/**
+ * Multiply a by b storing the result in b.
+ */
+void ff_big_mul(BigInt *b, uint8_t a);
+
+/* Each face is encoded using 9 octrees of 16x16 each. Each level of the
+ * trees has varying probabilities of being white, grey or black.
+ * The table below is based on sampling many faces */
+enum XFaceColor { XFACE_COLOR_BLACK = 0, XFACE_COLOR_GREY, XFACE_COLOR_WHITE };
+
+/* Data of varying probabilities are encoded by a value in the range 0 - 255.
+ * The probability of the data determines the range of possible encodings.
+ * Offset gives the first possible encoding of the range. */
+typedef struct {
+ uint8_t range;
+ uint8_t offset;
+} ProbRange;
+
+extern const ProbRange ff_xface_probranges_per_level[4][3];
+
+extern const ProbRange ff_xface_probranges_2x2[16];
+
+void ff_xface_generate_face(uint8_t *dst, uint8_t * const src);
diff --git a/libavcodec/xfacedec.c b/libavcodec/xfacedec.c
new file mode 100644
index 0000000000..d045cb6ef4
--- /dev/null
+++ b/libavcodec/xfacedec.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1990 James Ashton - Sydney University
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * X-Face decoder, based on libcompface, by James Ashton.
+ */
+
+#include "libavutil/pixdesc.h"
+#include "avcodec.h"
+#include "bytestream.h"
+#include "internal.h"
+#include "xface.h"
+
+static int pop_integer(BigInt *b, const ProbRange *pranges)
+{
+ uint8_t r;
+ int i;
+
+ /* extract the last byte into r, and shift right b by 8 bits */
+ ff_big_div(b, 0, &r);
+
+ i = 0;
+ while (r < pranges->offset || r >= pranges->range + pranges->offset) {
+ pranges++;
+ i++;
+ }
+ ff_big_mul(b, pranges->range);
+ ff_big_add(b, r - pranges->offset);
+ return i;
+}
+
+static void pop_greys(BigInt *b, char *bitmap, int w, int h)
+{
+ if (w > 3) {
+ w /= 2;
+ h /= 2;
+ pop_greys(b, bitmap, w, h);
+ pop_greys(b, bitmap + w, w, h);
+ pop_greys(b, bitmap + XFACE_WIDTH * h, w, h);
+ pop_greys(b, bitmap + XFACE_WIDTH * h + w, w, h);
+ } else {
+ w = pop_integer(b, ff_xface_probranges_2x2);
+ if (w & 1) bitmap[0] = 1;
+ if (w & 2) bitmap[1] = 1;
+ if (w & 4) bitmap[XFACE_WIDTH] = 1;
+ if (w & 8) bitmap[XFACE_WIDTH + 1] = 1;
+ }
+}
+
+static void decode_block(BigInt *b, char *bitmap, int w, int h, int level)
+{
+ switch (pop_integer(b, &ff_xface_probranges_per_level[level][0])) {
+ case XFACE_COLOR_WHITE:
+ return;
+ case XFACE_COLOR_BLACK:
+ pop_greys(b, bitmap, w, h);
+ return;
+ default:
+ w /= 2;
+ h /= 2;
+ level++;
+ decode_block(b, bitmap, w, h, level);
+ decode_block(b, bitmap + w, w, h, level);
+ decode_block(b, bitmap + h * XFACE_WIDTH, w, h, level);
+ decode_block(b, bitmap + w + h * XFACE_WIDTH, w, h, level);
+ return;
+ }
+}
+
+typedef struct XFaceContext {
+ uint8_t bitmap[XFACE_PIXELS]; ///< image used internally for decoding
+} XFaceContext;
+
+static av_cold int xface_decode_init(AVCodecContext *avctx)
+{
+ if (avctx->width || avctx->height) {
+ if (avctx->width != XFACE_WIDTH || avctx->height != XFACE_HEIGHT) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Size value %dx%d not supported, only accepts a size of %dx%d\n",
+ avctx->width, avctx->height, XFACE_WIDTH, XFACE_HEIGHT);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ avctx->width = XFACE_WIDTH;
+ avctx->height = XFACE_HEIGHT;
+ avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
+
+ return 0;
+}
+
+static int xface_decode_frame(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ XFaceContext *xface = avctx->priv_data;
+ int ret, i, j, k;
+ uint8_t byte;
+ BigInt b = {0};
+ char *buf;
+ int64_t c;
+ AVFrame *frame = data;
+
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ for (i = 0, k = 0; avpkt->data[i] && i < avpkt->size; i++) {
+ c = avpkt->data[i];
+
+ /* ignore invalid digits */
+ if (c < XFACE_FIRST_PRINT || c > XFACE_LAST_PRINT)
+ continue;
+
+ if (++k > XFACE_MAX_DIGITS) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Buffer is longer than expected, truncating at byte %d\n", i);
+ break;
+ }
+ ff_big_mul(&b, XFACE_PRINTS);
+ ff_big_add(&b, c - XFACE_FIRST_PRINT);
+ }
+
+ /* decode image and put it in bitmap */
+ memset(xface->bitmap, 0, XFACE_PIXELS);
+ buf = xface->bitmap;
+ decode_block(&b, buf, 16, 16, 0);
+ decode_block(&b, buf + 16, 16, 16, 0);
+ decode_block(&b, buf + 32, 16, 16, 0);
+ decode_block(&b, buf + XFACE_WIDTH * 16, 16, 16, 0);
+ decode_block(&b, buf + XFACE_WIDTH * 16 + 16, 16, 16, 0);
+ decode_block(&b, buf + XFACE_WIDTH * 16 + 32, 16, 16, 0);
+ decode_block(&b, buf + XFACE_WIDTH * 32 , 16, 16, 0);
+ decode_block(&b, buf + XFACE_WIDTH * 32 + 16, 16, 16, 0);
+ decode_block(&b, buf + XFACE_WIDTH * 32 + 32, 16, 16, 0);
+
+ ff_xface_generate_face(xface->bitmap, xface->bitmap);
+
+ /* convert image from 1=black 0=white bitmap to MONOWHITE */
+ buf = frame->data[0];
+ for (i = 0, j = 0, k = 0, byte = 0; i < XFACE_PIXELS; i++) {
+ byte += xface->bitmap[i];
+ if (k == 7) {
+ buf[j++] = byte;
+ byte = k = 0;
+ } else {
+ k++;
+ byte <<= 1;
+ }
+ if (j == XFACE_WIDTH/8) {
+ j = 0;
+ buf += frame->linesize[0];
+ }
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_xface_decoder = {
+ .name = "xface",
+ .long_name = NULL_IF_CONFIG_SMALL("X-face image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_XFACE,
+ .priv_data_size = sizeof(XFaceContext),
+ .init = xface_decode_init,
+ .decode = xface_decode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/xfaceenc.c b/libavcodec/xfaceenc.c
new file mode 100644
index 0000000000..fa6f22734b
--- /dev/null
+++ b/libavcodec/xfaceenc.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1990 James Ashton - Sydney University
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * X-Face encoder, based on libcompface, by James Ashton.
+ */
+
+#include "xface.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+
+typedef struct XFaceContext {
+ AVClass *class;
+ uint8_t bitmap[XFACE_PIXELS]; ///< image used internally for decoding
+ int max_line_len; ///< max line length for compressed data
+ int set_header; ///< set X-Face header in the output
+} XFaceContext;
+
+static int all_same(char *bitmap, int w, int h)
+{
+ char val, *row;
+ int x;
+
+ val = *bitmap;
+ while (h--) {
+ row = bitmap;
+ x = w;
+ while (x--)
+ if (*(row++) != val)
+ return 0;
+ bitmap += XFACE_WIDTH;
+ }
+ return 1;
+}
+
+static int all_black(char *bitmap, int w, int h)
+{
+ if (w > 3) {
+ w /= 2;
+ h /= 2;
+ return (all_black(bitmap, w, h) && all_black(bitmap + w, w, h) &&
+ all_black(bitmap + XFACE_WIDTH * h, w, h) &&
+ all_black(bitmap + XFACE_WIDTH * h + w, w, h));
+ } else {
+ /* at least one pixel in the 2x2 grid is non-zero */
+ return *bitmap || *(bitmap + 1) ||
+ *(bitmap + XFACE_WIDTH) || *(bitmap + XFACE_WIDTH + 1);
+ }
+}
+
+static int all_white(char *bitmap, int w, int h)
+{
+ return *bitmap == 0 && all_same(bitmap, w, h);
+}
+
+typedef struct {
+ ProbRange prob_ranges[XFACE_PIXELS*2];
+ int prob_ranges_idx;
+} ProbRangesQueue;
+
+static inline int pq_push(ProbRangesQueue *pq, const ProbRange *p)
+{
+ if (pq->prob_ranges_idx >= XFACE_PIXELS * 2 - 1)
+ return -1;
+ pq->prob_ranges[pq->prob_ranges_idx++] = *p;
+ return 0;
+}
+
+static void push_greys(ProbRangesQueue *pq, char *bitmap, int w, int h)
+{
+ if (w > 3) {
+ w /= 2;
+ h /= 2;
+ push_greys(pq, bitmap, w, h);
+ push_greys(pq, bitmap + w, w, h);
+ push_greys(pq, bitmap + XFACE_WIDTH * h, w, h);
+ push_greys(pq, bitmap + XFACE_WIDTH * h + w, w, h);
+ } else {
+ const ProbRange *p = ff_xface_probranges_2x2 +
+ *bitmap +
+ 2 * *(bitmap + 1) +
+ 4 * *(bitmap + XFACE_WIDTH) +
+ 8 * *(bitmap + XFACE_WIDTH + 1);
+ pq_push(pq, p);
+ }
+}
+
+static void encode_block(char *bitmap, int w, int h, int level, ProbRangesQueue *pq)
+{
+ if (all_white(bitmap, w, h)) {
+ pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_WHITE]);
+ } else if (all_black(bitmap, w, h)) {
+ pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_BLACK]);
+ push_greys(pq, bitmap, w, h);
+ } else {
+ pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_GREY]);
+ w /= 2;
+ h /= 2;
+ level++;
+ encode_block(bitmap, w, h, level, pq);
+ encode_block(bitmap + w, w, h, level, pq);
+ encode_block(bitmap + h * XFACE_WIDTH, w, h, level, pq);
+ encode_block(bitmap + w + h * XFACE_WIDTH, w, h, level, pq);
+ }
+}
+
+static av_cold int xface_encode_init(AVCodecContext *avctx)
+{
+ avctx->coded_frame = av_frame_alloc();
+ if (!avctx->coded_frame)
+ return AVERROR(ENOMEM);
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ return 0;
+}
+
+static void push_integer(BigInt *b, const ProbRange *prange)
+{
+ uint8_t r;
+
+ ff_big_div(b, prange->range, &r);
+ ff_big_mul(b, 0);
+ ff_big_add(b, r + prange->offset);
+}
+
+static int xface_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ XFaceContext *xface = avctx->priv_data;
+ ProbRangesQueue pq = {{{ 0 }}, 0};
+ uint8_t bitmap_copy[XFACE_PIXELS];
+ BigInt b = {0};
+ int i, j, k, ret = 0;
+ const uint8_t *buf;
+ uint8_t *p;
+ char intbuf[XFACE_MAX_DIGITS];
+
+ if (avctx->width || avctx->height) {
+ if (avctx->width != XFACE_WIDTH || avctx->height != XFACE_HEIGHT) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Size value %dx%d not supported, only accepts a size of %dx%d\n",
+ avctx->width, avctx->height, XFACE_WIDTH, XFACE_HEIGHT);
+ return AVERROR(EINVAL);
+ }
+ }
+ avctx->width = XFACE_WIDTH;
+ avctx->height = XFACE_HEIGHT;
+
+ /* convert image from MONOWHITE to 1=black 0=white bitmap */
+ buf = frame->data[0];
+ i = j = 0;
+ do {
+ for (k = 0; k < 8; k++)
+ xface->bitmap[i++] = (buf[j]>>(7-k))&1;
+ if (++j == XFACE_WIDTH/8) {
+ buf += frame->linesize[0];
+ j = 0;
+ }
+ } while (i < XFACE_PIXELS);
+
+ /* create a copy of bitmap */
+ memcpy(bitmap_copy, xface->bitmap, XFACE_PIXELS);
+ ff_xface_generate_face(xface->bitmap, bitmap_copy);
+
+ encode_block(xface->bitmap, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + 16, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + 32, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + XFACE_WIDTH * 16, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + XFACE_WIDTH * 16 + 16, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + XFACE_WIDTH * 16 + 32, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + XFACE_WIDTH * 32, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + XFACE_WIDTH * 32 + 16, 16, 16, 0, &pq);
+ encode_block(xface->bitmap + XFACE_WIDTH * 32 + 32, 16, 16, 0, &pq);
+
+ while (pq.prob_ranges_idx > 0)
+ push_integer(&b, &pq.prob_ranges[--pq.prob_ranges_idx]);
+
+ /* write the inverted big integer in b to intbuf */
+ i = 0;
+ av_assert0(b.nb_words < XFACE_MAX_WORDS);
+ while (b.nb_words) {
+ uint8_t r;
+ ff_big_div(&b, XFACE_PRINTS, &r);
+ av_assert0(i < sizeof(intbuf));
+ intbuf[i++] = r + XFACE_FIRST_PRINT;
+ }
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, i+2)) < 0)
+ return ret;
+
+ /* revert the number, and close the buffer */
+ p = pkt->data;
+ while (--i >= 0)
+ *(p++) = intbuf[i];
+ *(p++) = '\n';
+ *(p++) = 0;
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+
+ return 0;
+}
+
+static av_cold int xface_encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+AVCodec ff_xface_encoder = {
+ .name = "xface",
+ .long_name = NULL_IF_CONFIG_SMALL("X-face image"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_XFACE,
+ .priv_data_size = sizeof(XFaceContext),
+ .init = xface_encode_init,
+ .close = xface_encode_close,
+ .encode2 = xface_encode_frame,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/xiph.c b/libavcodec/xiph.c
index 7c3c7100c6..d072224b4a 100644
--- a/libavcodec/xiph.c
+++ b/libavcodec/xiph.c
@@ -1,28 +1,28 @@
/*
- * Copyright (C) 2007 Libav Project
+ * Copyright (C) 2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "xiph.h"
-int avpriv_split_xiph_headers(uint8_t *extradata, int extradata_size,
- int first_header_size, uint8_t *header_start[3],
+int avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size,
+ int first_header_size, const uint8_t *header_start[3],
int header_len[3])
{
int i;
diff --git a/libavcodec/xiph.h b/libavcodec/xiph.h
index afaece7cee..1741a51b65 100644
--- a/libavcodec/xiph.h
+++ b/libavcodec/xiph.h
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2007 Libav Project
+ * Copyright (C) 2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,8 +36,8 @@
* @param[out] header_len The sizes of each of the three headers.
* @return On error a negative value is returned, on success zero.
*/
-int avpriv_split_xiph_headers(uint8_t *extradata, int extradata_size,
- int first_header_size, uint8_t *header_start[3],
+int avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size,
+ int first_header_size, const uint8_t *header_start[3],
int header_len[3]);
#endif /* AVCODEC_XIPH_H */
diff --git a/libavcodec/xl.c b/libavcodec/xl.c
index 8e9bdc66f6..2d1da1d255 100644
--- a/libavcodec/xl.c
+++ b/libavcodec/xl.c
@@ -2,20 +2,20 @@
* Miro VideoXL codec
* Copyright (c) 2004 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,19 +50,16 @@ static int decode_frame(AVCodecContext *avctx,
int y0, y1, y2, y3 = 0, c0 = 0, c1 = 0;
if (avctx->width % 4) {
- av_log(avctx, AV_LOG_ERROR, "Width not a multiple of 4.\n");
+ av_log(avctx, AV_LOG_ERROR, "width is not a multiple of 4\n");
return AVERROR_INVALIDDATA;
}
-
if (buf_size < avctx->width * avctx->height) {
av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
return AVERROR_INVALIDDATA;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
diff --git a/libavcodec/xsubdec.c b/libavcodec/xsubdec.c
index d01b410829..1bb90e2b9d 100644
--- a/libavcodec/xsubdec.c
+++ b/libavcodec/xsubdec.c
@@ -2,20 +2,20 @@
* XSUB subtitle decoder
* Copyright (c) 2007 Reimar Döffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,11 +58,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
GetBitContext gb;
int has_alpha = avctx->codec_tag == MKTAG('D','X','S','A');
- memset(sub, 0, sizeof(*sub));
-
// check that at least header fits
if (buf_size < 27 + 7 * 2 + 4 * (3 + has_alpha)) {
- av_log(avctx, AV_LOG_ERROR, "coded frame too small\n");
+ av_log(avctx, AV_LOG_ERROR, "coded frame size %d too small\n", buf_size);
return -1;
}
@@ -95,8 +93,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
// allocate sub and set values
sub->rects = av_mallocz(sizeof(*sub->rects));
+ if (!sub->rects)
+ return AVERROR(ENOMEM);
+
sub->rects[0] = av_mallocz(sizeof(*sub->rects[0]));
- sub->num_rects = 1;
+ if (!sub->rects[0]) {
+ av_freep(&sub->rects);
+ return AVERROR(ENOMEM);
+ }
sub->rects[0]->x = x; sub->rects[0]->y = y;
sub->rects[0]->w = w; sub->rects[0]->h = h;
sub->rects[0]->type = SUBTITLE_BITMAP;
@@ -104,6 +108,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
sub->rects[0]->pict.data[0] = av_malloc(w * h);
sub->rects[0]->nb_colors = 4;
sub->rects[0]->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
+ if (!sub->rects[0]->pict.data[0] || !sub->rects[0]->pict.data[1]) {
+ av_freep(&sub->rects[0]);
+ av_freep(&sub->rects);
+ return AVERROR(ENOMEM);
+
+ }
+ sub->num_rects = 1;
// read palette
for (i = 0; i < sub->rects[0]->nb_colors; i++)
diff --git a/libavcodec/xsubenc.c b/libavcodec/xsubenc.c
index fc46fb8651..707085488c 100644
--- a/libavcodec/xsubenc.c
+++ b/libavcodec/xsubenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2005 DivX, Inc.
* Copyright (c) 2009 Bjorn Axelsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -128,7 +128,7 @@ static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
}
// TODO: support multiple rects
- if (h->num_rects > 1)
+ if (h->num_rects != 1)
av_log(avctx, AV_LOG_WARNING, "Only single rects supported (%d in subtitle.)\n", h->num_rects);
// TODO: render text-based subtitles into bitmaps
@@ -142,7 +142,7 @@ static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
av_log(avctx, AV_LOG_WARNING, "No more than 4 subtitle colors supported (%d found.)\n", h->rects[0]->nb_colors);
// TODO: Palette swapping if color zero is not transparent
- if (((uint32_t *)h->rects[0]->pict.data[1])[0] & 0xff)
+ if (((uint32_t *)h->rects[0]->pict.data[1])[0] & 0xff000000)
av_log(avctx, AV_LOG_WARNING, "Color index 0 is not transparent. Transparency will be messed up.\n");
if (make_tc(startTime, start_tc) || make_tc(endTime, end_tc)) {
@@ -166,8 +166,8 @@ static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
bytestream_put_le16(&hdr, height);
bytestream_put_le16(&hdr, h->rects[0]->x);
bytestream_put_le16(&hdr, h->rects[0]->y);
- bytestream_put_le16(&hdr, h->rects[0]->x + width);
- bytestream_put_le16(&hdr, h->rects[0]->y + height);
+ bytestream_put_le16(&hdr, h->rects[0]->x + width -1);
+ bytestream_put_le16(&hdr, h->rects[0]->y + height -1);
rlelenptr = hdr; // Will store length of first field here later.
hdr+=2;
@@ -190,7 +190,7 @@ static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
h->rects[0]->w, h->rects[0]->h >> 1))
return -1;
- // Enforce total height to be be multiple of 2
+ // Enforce total height to be a multiple of 2
if (h->rects[0]->h & 1) {
put_xsub_rle(&pb, h->rects[0]->w, PADDING_COLOR);
avpriv_align_put_bits(&pb);
@@ -206,6 +206,8 @@ static av_cold int xsub_encoder_init(AVCodecContext *avctx)
if (!avctx->codec_tag)
avctx->codec_tag = MKTAG('D','X','S','B');
+ avctx->bits_per_coded_sample = 4;
+
return 0;
}
diff --git a/libavcodec/xvididct.c b/libavcodec/xvididct.c
index ca89703233..e9fab70cbb 100644
--- a/libavcodec/xvididct.c
+++ b/libavcodec/xvididct.c
@@ -3,20 +3,20 @@
*
* Copyright (C) 2006-2011 Xvid Solutions GmbH
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -334,9 +334,12 @@ av_cold void ff_xvid_idct_init(IDCTDSPContext *c, AVCodecContext *avctx)
{
const unsigned high_bit_depth = avctx->bits_per_raw_sample > 8;
- if (!high_bit_depth &&
- (avctx->idct_algo == FF_IDCT_AUTO ||
- avctx->idct_algo == FF_IDCT_XVID)) {
+ if (high_bit_depth || avctx->lowres ||
+ !(avctx->idct_algo == FF_IDCT_AUTO ||
+ avctx->idct_algo == FF_IDCT_XVID))
+ return;
+
+ if (avctx->idct_algo == FF_IDCT_XVID) {
c->idct_put = xvid_idct_put;
c->idct_add = xvid_idct_add;
c->idct = ff_xvid_idct;
diff --git a/libavcodec/xvididct.h b/libavcodec/xvididct.h
index 499f8190fc..f7dfba4886 100644
--- a/libavcodec/xvididct.h
+++ b/libavcodec/xvididct.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/xvmc.h b/libavcodec/xvmc.h
index 950ed18276..c2e187cc16 100644
--- a/libavcodec/xvmc.h
+++ b/libavcodec/xvmc.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2003 Ivan Kalvachev
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,8 +33,6 @@
#include "version.h"
#include "avcodec.h"
-#if FF_API_XVMC
-
/**
* @defgroup lavc_codec_hwaccel_xvmc XvMC
* @ingroup lavc_codec_hwaccel
@@ -169,6 +167,4 @@ attribute_deprecated struct xvmc_pix_fmt {
* @}
*/
-#endif /* FF_API_XVMC */
-
#endif /* AVCODEC_XVMC_H */
diff --git a/libavcodec/xvmc_internal.h b/libavcodec/xvmc_internal.h
index 9018e4a40a..d365ef0266 100644
--- a/libavcodec/xvmc_internal.h
+++ b/libavcodec/xvmc_internal.h
@@ -1,20 +1,20 @@
/*
* XVideo Motion Compensation internal functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,14 +25,7 @@
#include "mpegvideo.h"
#include "version.h"
-#if FF_API_XVMC
-
void ff_xvmc_init_block(MpegEncContext *s);
void ff_xvmc_pack_pblocks(MpegEncContext *s, int cbp);
-int ff_xvmc_field_start(MpegEncContext*s, AVCodecContext *avctx);
-void ff_xvmc_field_end(MpegEncContext *s);
-void ff_xvmc_decode_mb(MpegEncContext *s);
-
-#endif /* FF_API_XVMC */
#endif /* AVCODEC_XVMC_INTERNAL_H */
diff --git a/libavcodec/xwd.h b/libavcodec/xwd.h
index f41e2cd651..d0460465e0 100644
--- a/libavcodec/xwd.h
+++ b/libavcodec/xwd.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavcodec/xwddec.c b/libavcodec/xwddec.c
index f6ccb96988..62dfdace16 100644
--- a/libavcodec/xwddec.c
+++ b/libavcodec/xwddec.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -147,7 +147,7 @@ static int xwd_decode_frame(AVCodecContext *avctx, void *data,
}
if (pixformat != XWD_Z_PIXMAP) {
- av_log(avctx, AV_LOG_ERROR, "pixmap format %"PRIu32" unsupported\n", pixformat);
+ avpriv_report_missing_feature(avctx, "Pixmap format %"PRIu32, pixformat);
return AVERROR_PATCHWELCOME;
}
@@ -155,10 +155,13 @@ static int xwd_decode_frame(AVCodecContext *avctx, void *data,
switch (vclass) {
case XWD_STATIC_GRAY:
case XWD_GRAY_SCALE:
- if (bpp != 1)
+ if (bpp != 1 && bpp != 8)
return AVERROR_INVALIDDATA;
- if (pixdepth == 1)
+ if (pixdepth == 1) {
avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
+ } else if (pixdepth == 8) {
+ avctx->pix_fmt = AV_PIX_FMT_GRAY8;
+ }
break;
case XWD_STATIC_COLOR:
case XWD_PSEUDO_COLOR:
@@ -204,10 +207,8 @@ static int xwd_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_PATCHWELCOME;
}
- if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
return ret;
- }
p->key_frame = 1;
p->pict_type = AV_PICTURE_TYPE_I;
diff --git a/libavcodec/xwdenc.c b/libavcodec/xwdenc.c
index 54599a08a1..06fa4a0a97 100644
--- a/libavcodec/xwdenc.c
+++ b/libavcodec/xwdenc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,17 +30,8 @@
#define WINDOW_NAME "lavcxwdenc"
#define WINDOW_NAME_SIZE 11
-static av_cold int xwd_encode_init(AVCodecContext *avctx)
-{
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
-
- return 0;
-}
-
static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
- const AVFrame *p, int *got_packet)
+ const AVFrame *pict, int *got_packet)
{
enum AVPixelFormat pix_fmt = avctx->pix_fmt;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -49,6 +40,7 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
uint32_t header_size;
int i, out_size, ret;
uint8_t *ptr, *buf;
+ AVFrame * const p = (AVFrame *)pict;
pixdepth = av_get_bits_per_pixel(desc);
if (desc->flags & AV_PIX_FMT_FLAG_BE)
@@ -133,6 +125,11 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
bpad = 8;
ncolors = 256;
break;
+ case AV_PIX_FMT_GRAY8:
+ bpp = 8;
+ bpad = 8;
+ vclass = XWD_STATIC_GRAY;
+ break;
case AV_PIX_FMT_MONOWHITE:
be = 1;
bitorder = 1;
@@ -141,7 +138,7 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
vclass = XWD_STATIC_GRAY;
break;
default:
- av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n");
+ av_log(avctx, AV_LOG_ERROR, "unsupported pixel format\n");
return AVERROR(EINVAL);
}
@@ -149,14 +146,12 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
header_size = XWD_HEADER_SIZE + WINDOW_NAME_SIZE;
out_size = header_size + ncolors * XWD_CMAP_SIZE + avctx->height * lsize;
- if ((ret = ff_alloc_packet(pkt, out_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "output buffer too small\n");
+ if ((ret = ff_alloc_packet2(avctx, pkt, out_size)) < 0)
return ret;
- }
buf = pkt->data;
- avctx->coded_frame->key_frame = 1;
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ p->key_frame = 1;
+ p->pict_type = AV_PICTURE_TYPE_I;
bytestream_put_be32(&buf, header_size);
bytestream_put_be32(&buf, XWD_VERSION); // file version
@@ -213,21 +208,12 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
return 0;
}
-static av_cold int xwd_encode_close(AVCodecContext *avctx)
-{
- av_freep(&avctx->coded_frame);
-
- return 0;
-}
-
AVCodec ff_xwd_encoder = {
.name = "xwd",
.long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_XWD,
- .init = xwd_encode_init,
.encode2 = xwd_encode_frame,
- .close = xwd_encode_close,
.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGRA,
AV_PIX_FMT_RGBA,
AV_PIX_FMT_ARGB,
@@ -247,6 +233,7 @@ AVCodec ff_xwd_encoder = {
AV_PIX_FMT_RGB4_BYTE,
AV_PIX_FMT_BGR4_BYTE,
AV_PIX_FMT_PAL8,
+ AV_PIX_FMT_GRAY8,
AV_PIX_FMT_MONOWHITE,
AV_PIX_FMT_NONE },
};
diff --git a/libavcodec/xxan.c b/libavcodec/xxan.c
index d77a50fd3f..b261cdfdec 100644
--- a/libavcodec/xxan.c
+++ b/libavcodec/xxan.c
@@ -3,20 +3,20 @@
* Copyright (C) 2011 Konstantin Shishkov
* based on work by Mike Melanson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -73,7 +73,7 @@ static av_cold int xan_decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
s->scratch_buffer = av_malloc(s->buffer_size + 130);
if (!s->scratch_buffer) {
- av_freep(&s->y_buffer);
+ xan_decode_end(avctx);
return AVERROR(ENOMEM);
}
@@ -224,16 +224,18 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off)
if (mode) {
for (j = 0; j < avctx->height >> 1; j++) {
for (i = 0; i < avctx->width >> 1; i++) {
+ if (src_end - src < 1)
+ return 0;
val = *src++;
- if (val && val < table_size) {
+ if (val) {
+ if (val >= table_size)
+ return AVERROR_INVALIDDATA;
val = AV_RL16(table + (val << 1));
uval = (val >> 3) & 0xF8;
vval = (val >> 8) & 0xF8;
U[i] = uval | (uval >> 5);
V[i] = vval | (vval >> 5);
}
- if (src == src_end)
- return 0;
}
U += s->pic->linesize[1];
V += s->pic->linesize[2];
@@ -248,8 +250,12 @@ static int xan_decode_chroma(AVCodecContext *avctx, unsigned chroma_off)
for (j = 0; j < avctx->height >> 2; j++) {
for (i = 0; i < avctx->width >> 1; i += 2) {
+ if (src_end - src < 1)
+ return 0;
val = *src++;
- if (val && val < table_size) {
+ if (val) {
+ if (val >= table_size)
+ return AVERROR_INVALIDDATA;
val = AV_RL16(table + (val << 1));
uval = (val >> 3) & 0xF8;
vval = (val >> 8) & 0xF8;
@@ -288,7 +294,7 @@ static int xan_decode_frame_type0(AVCodecContext *avctx)
if ((ret = xan_decode_chroma(avctx, chroma_off)) != 0)
return ret;
- if (corr_off >= (s->gb.buffer_end - s->gb.buffer_start)) {
+ if (corr_off >= bytestream2_size(&s->gb)) {
av_log(avctx, AV_LOG_WARNING, "Ignoring invalid correction block position\n");
corr_off = 0;
}
@@ -333,6 +339,9 @@ static int xan_decode_frame_type0(AVCodecContext *avctx)
dec_size = xan_unpack(s, s->scratch_buffer, s->buffer_size / 2);
if (dec_size < 0)
dec_size = 0;
+ else
+ dec_size = FFMIN(dec_size, s->buffer_size/2 - 1);
+
for (i = 0; i < dec_size; i++)
s->y_buffer[i*2+1] = (s->y_buffer[i*2+1] + (s->scratch_buffer[i] << 1)) & 0x3F;
}
@@ -402,10 +411,8 @@ static int xan_decode_frame(AVCodecContext *avctx,
int ftype;
int ret;
- if ((ret = ff_reget_buffer(avctx, s->pic))) {
- av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->pic)) < 0)
return ret;
- }
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
ftype = bytestream2_get_le32(&s->gb);
diff --git a/libavcodec/y41pdec.c b/libavcodec/y41pdec.c
new file mode 100644
index 0000000000..22c7d1fd38
--- /dev/null
+++ b/libavcodec/y41pdec.c
@@ -0,0 +1,92 @@
+/*
+ * y41p decoder
+ *
+ * Copyright (c) 2012 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
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int y41p_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUV411P;
+ avctx->bits_per_raw_sample = 12;
+
+ if (avctx->width & 7) {
+ av_log(avctx, AV_LOG_WARNING, "y41p requires width to be divisible by 8.\n");
+ }
+
+ return 0;
+}
+
+static int y41p_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVFrame *pic = data;
+ uint8_t *src = avpkt->data;
+ uint8_t *y, *u, *v;
+ int i, j, ret;
+
+ if (avpkt->size < 3LL * avctx->height * avctx->width / 2) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->key_frame = 1;
+ 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]];
+ v = &pic->data[2][i * pic->linesize[2]];
+ for (j = 0; j < avctx->width; j += 8) {
+ *(u++) = *src++;
+ *(y++) = *src++;
+ *(v++) = *src++;
+ *(y++) = *src++;
+
+ *(u++) = *src++;
+ *(y++) = *src++;
+ *(v++) = *src++;
+ *(y++) = *src++;
+
+ *(y++) = *src++;
+ *(y++) = *src++;
+ *(y++) = *src++;
+ *(y++) = *src++;
+ }
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_y41p_decoder = {
+ .name = "y41p",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_Y41P,
+ .init = y41p_decode_init,
+ .decode = y41p_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/y41penc.c b/libavcodec/y41penc.c
new file mode 100644
index 0000000000..477861880e
--- /dev/null
+++ b/libavcodec/y41penc.c
@@ -0,0 +1,102 @@
+/*
+ * y41p encoder
+ *
+ * Copyright (c) 2012 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
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int y41p_encode_init(AVCodecContext *avctx)
+{
+ if (avctx->width & 7) {
+ av_log(avctx, AV_LOG_ERROR, "y41p requires width to be divisible by 8.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avctx->coded_frame = av_frame_alloc();
+ avctx->bits_per_coded_sample = 12;
+
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static int y41p_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ uint8_t *dst;
+ uint8_t *y, *u, *v;
+ int i, j, ret;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width * avctx->height * 1.5)) < 0)
+ return ret;
+
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+ dst = pkt->data;
+
+ for (i = avctx->height - 1; i >= 0; i--) {
+ y = &pic->data[0][i * pic->linesize[0]];
+ u = &pic->data[1][i * pic->linesize[1]];
+ v = &pic->data[2][i * pic->linesize[2]];
+ for (j = 0; j < avctx->width; j += 8) {
+ *(dst++) = *(u++);
+ *(dst++) = *(y++);
+ *(dst++) = *(v++);
+ *(dst++) = *(y++);
+
+ *(dst++) = *(u++);
+ *(dst++) = *(y++);
+ *(dst++) = *(v++);
+ *(dst++) = *(y++);
+
+ *(dst++) = *(y++);
+ *(dst++) = *(y++);
+ *(dst++) = *(y++);
+ *(dst++) = *(y++);
+ }
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int y41p_encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+AVCodec ff_y41p_encoder = {
+ .name = "y41p",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_Y41P,
+ .init = y41p_encode_init,
+ .encode2 = y41p_encode_frame,
+ .close = y41p_encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/yop.c b/libavcodec/yop.c
index 3434fd9808..c6b19ec795 100644
--- a/libavcodec/yop.c
+++ b/libavcodec/yop.c
@@ -5,20 +5,20 @@
* derived from the code by
* Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
typedef struct YopDecContext {
AVCodecContext *avctx;
+ AVFrame *frame;
int num_pal_colors;
int first_color[2];
@@ -78,6 +79,15 @@ static const int8_t motion_vector[16][2] =
{ 4, -2}, {-2, 0},
};
+static av_cold int yop_decode_close(AVCodecContext *avctx)
+{
+ YopDecContext *s = avctx->priv_data;
+
+ av_frame_free(&s->frame);
+
+ return 0;
+}
+
static av_cold int yop_decode_init(AVCodecContext *avctx)
{
YopDecContext *s = avctx->priv_data;
@@ -103,10 +113,14 @@ static av_cold int yop_decode_init(AVCodecContext *avctx)
if (s->num_pal_colors + s->first_color[0] > 256 ||
s->num_pal_colors + s->first_color[1] > 256) {
av_log(avctx, AV_LOG_ERROR,
- "YOP: palette parameters invalid, header probably corrupt\n");
+ "Palette parameters invalid, header probably corrupt\n");
return AVERROR_INVALIDDATA;
}
+ s->frame = av_frame_alloc();
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+
return 0;
}
@@ -144,8 +158,7 @@ static int yop_copy_previous_block(YopDecContext *s, int linesize, int copy_tag)
bufptr = s->dstptr + motion_vector[copy_tag][0] +
linesize * motion_vector[copy_tag][1];
if (bufptr < s->dstbuf) {
- av_log(s->avctx, AV_LOG_ERROR,
- "YOP: cannot decode, file probably corrupt\n");
+ av_log(s->avctx, AV_LOG_ERROR, "File probably corrupt\n");
return AVERROR_INVALIDDATA;
}
@@ -179,7 +192,7 @@ static int yop_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
AVPacket *avpkt)
{
YopDecContext *s = avctx->priv_data;
- AVFrame *frame = data;
+ AVFrame *frame = s->frame;
int tag, firstcolor, is_odd_frame;
int ret, i, x, y;
uint32_t *palette;
@@ -189,11 +202,8 @@ static int yop_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
return AVERROR_INVALIDDATA;
}
- ret = ff_get_buffer(avctx, frame, 0);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, frame)) < 0)
return ret;
- }
if (!avctx->frame_number)
memset(frame->data[1], 0, AVPALETTE_SIZE);
@@ -205,13 +215,20 @@ static int yop_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->low_nibble = NULL;
is_odd_frame = avpkt->data[0];
+ if(is_odd_frame>1){
+ av_log(avctx, AV_LOG_ERROR, "frame is too odd %d\n", is_odd_frame);
+ return AVERROR_INVALIDDATA;
+ }
firstcolor = s->first_color[is_odd_frame];
palette = (uint32_t *)frame->data[1];
- for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3)
+ for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3) {
palette[i + firstcolor] = (s->srcptr[0] << 18) |
(s->srcptr[1] << 10) |
(s->srcptr[2] << 2);
+ palette[i + firstcolor] |= 0xFFU << 24 |
+ (palette[i + firstcolor] >> 6) & 0x30303;
+ }
frame->palette_has_changed = 1;
@@ -239,6 +256,9 @@ static int yop_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
s->dstptr += 2*frame->linesize[0] - x;
}
+ if ((ret = av_frame_ref(data, s->frame)) < 0)
+ return ret;
+
*got_frame = 1;
return avpkt->size;
}
@@ -250,6 +270,6 @@ AVCodec ff_yop_decoder = {
.id = AV_CODEC_ID_YOP,
.priv_data_size = sizeof(YopDecContext),
.init = yop_decode_init,
+ .close = yop_decode_close,
.decode = yop_decode_frame,
- .capabilities = CODEC_CAP_DR1,
};
diff --git a/libavcodec/yuv4dec.c b/libavcodec/yuv4dec.c
new file mode 100644
index 0000000000..00ccf58120
--- /dev/null
+++ b/libavcodec/yuv4dec.c
@@ -0,0 +1,84 @@
+/*
+ * libquicktime yuv4 decoder
+ *
+ * Copyright (c) 2011 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int yuv4_decode_init(AVCodecContext *avctx)
+{
+ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+
+ return 0;
+}
+
+static int yuv4_decode_frame(AVCodecContext *avctx, void *data,
+ int *got_frame, AVPacket *avpkt)
+{
+ AVFrame *pic = data;
+ const uint8_t *src = avpkt->data;
+ uint8_t *y, *u, *v;
+ int i, j, ret;
+
+ if (avpkt->size < 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1)) {
+ av_log(avctx, AV_LOG_ERROR, "Insufficient input data.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((ret = ff_get_buffer(avctx, pic, 0)) < 0)
+ return ret;
+
+ pic->key_frame = 1;
+ pic->pict_type = AV_PICTURE_TYPE_I;
+
+ y = pic->data[0];
+ u = pic->data[1];
+ v = pic->data[2];
+
+ for (i = 0; i < (avctx->height + 1) >> 1; i++) {
+ for (j = 0; j < (avctx->width + 1) >> 1; j++) {
+ u[j] = *src++ ^ 0x80;
+ v[j] = *src++ ^ 0x80;
+ y[ 2 * j ] = *src++;
+ y[ 2 * j + 1] = *src++;
+ y[pic->linesize[0] + 2 * j ] = *src++;
+ y[pic->linesize[0] + 2 * j + 1] = *src++;
+ }
+
+ y += 2 * pic->linesize[0];
+ u += pic->linesize[1];
+ v += pic->linesize[2];
+ }
+
+ *got_frame = 1;
+
+ return avpkt->size;
+}
+
+AVCodec ff_yuv4_decoder = {
+ .name = "yuv4",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_YUV4,
+ .init = yuv4_decode_init,
+ .decode = yuv4_decode_frame,
+ .capabilities = CODEC_CAP_DR1,
+};
diff --git a/libavcodec/yuv4enc.c b/libavcodec/yuv4enc.c
new file mode 100644
index 0000000000..5ce48467d1
--- /dev/null
+++ b/libavcodec/yuv4enc.c
@@ -0,0 +1,91 @@
+/*
+ * libquicktime yuv4 encoder
+ *
+ * Copyright (c) 2011 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+
+static av_cold int yuv4_encode_init(AVCodecContext *avctx)
+{
+ avctx->coded_frame = av_frame_alloc();
+
+ if (!avctx->coded_frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static int yuv4_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *pic, int *got_packet)
+{
+ uint8_t *dst;
+ uint8_t *y, *u, *v;
+ int i, j, ret;
+
+ if ((ret = ff_alloc_packet2(avctx, pkt, 6 * (avctx->width + 1 >> 1) * (avctx->height + 1 >> 1))) < 0)
+ return ret;
+ dst = pkt->data;
+
+ avctx->coded_frame->key_frame = 1;
+ avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+
+ y = pic->data[0];
+ u = pic->data[1];
+ v = pic->data[2];
+
+ for (i = 0; i < avctx->height + 1 >> 1; i++) {
+ for (j = 0; j < avctx->width + 1 >> 1; j++) {
+ *dst++ = u[j] ^ 0x80;
+ *dst++ = v[j] ^ 0x80;
+ *dst++ = y[ 2 * j ];
+ *dst++ = y[ 2 * j + 1];
+ *dst++ = y[pic->linesize[0] + 2 * j ];
+ *dst++ = y[pic->linesize[0] + 2 * j + 1];
+ }
+ y += 2 * pic->linesize[0];
+ u += pic->linesize[1];
+ v += pic->linesize[2];
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static av_cold int yuv4_encode_close(AVCodecContext *avctx)
+{
+ av_frame_free(&avctx->coded_frame);
+
+ return 0;
+}
+
+AVCodec ff_yuv4_encoder = {
+ .name = "yuv4",
+ .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_YUV4,
+ .init = yuv4_encode_init,
+ .encode2 = yuv4_encode_frame,
+ .close = yuv4_encode_close,
+ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE },
+};
diff --git a/libavcodec/zerocodec.c b/libavcodec/zerocodec.c
index 89c869cc5f..12d8024148 100644
--- a/libavcodec/zerocodec.c
+++ b/libavcodec/zerocodec.c
@@ -59,10 +59,8 @@ static int zerocodec_decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_INVALIDDATA;
}
- if (ff_get_buffer(avctx, pic, AV_GET_BUFFER_FLAG_REF) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
- return AVERROR(ENOMEM);
- }
+ if ((ret = ff_get_buffer(avctx, pic, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
zstream->next_in = avpkt->data;
zstream->avail_in = avpkt->size;
diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c
index f49cbdb014..82ae169ef4 100644
--- a/libavcodec/zmbv.c
+++ b/libavcodec/zmbv.c
@@ -2,20 +2,20 @@
* Zip Motion Blocks Video (ZMBV) decoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "avcodec.h"
#include "internal.h"
@@ -64,6 +65,7 @@ typedef struct ZmbvContext {
int fmt;
int comp;
int flags;
+ int stride;
int bw, bh, bx, by;
int decomp_len;
z_stream zstream;
@@ -143,7 +145,7 @@ static int zmbv_decode_xor_8(ZmbvContext *c)
prev += c->width * c->bh;
}
if (src - c->decomp_buf != c->decomp_len)
- av_log(c->avctx, AV_LOG_ERROR, "Used %ti of %i bytes\n",
+ av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
src-c->decomp_buf, c->decomp_len);
return 0;
}
@@ -217,7 +219,7 @@ static int zmbv_decode_xor_16(ZmbvContext *c)
prev += c->width * c->bh;
}
if (src - c->decomp_buf != c->decomp_len)
- av_log(c->avctx, AV_LOG_ERROR, "Used %ti of %i bytes\n",
+ av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
src-c->decomp_buf, c->decomp_len);
return 0;
}
@@ -375,7 +377,7 @@ static int zmbv_decode_xor_32(ZmbvContext *c)
prev += c->width * c->bh;
}
if (src - c->decomp_buf != c->decomp_len)
- av_log(c->avctx, AV_LOG_ERROR, "Used %ti of %i bytes\n",
+ av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n",
src-c->decomp_buf, c->decomp_len);
return 0;
}
@@ -406,17 +408,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
int zret = Z_OK; // Zlib return code
int len = buf_size;
int hi_ver, lo_ver, ret;
- uint8_t *tmp;
-
- if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
- return ret;
- }
/* parse header */
+ if (len < 1)
+ return AVERROR_INVALIDDATA;
c->flags = buf[0];
buf++; len--;
if (c->flags & ZMBV_KEYFRAME) {
+ void *decode_intra = NULL;
+ c->decode_intra= NULL;
+
+ if (len < 6)
+ return AVERROR_INVALIDDATA;
hi_ver = buf[0];
lo_ver = buf[1];
c->comp = buf[2];
@@ -447,29 +450,39 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
switch (c->fmt) {
case ZMBV_FMT_8BPP:
c->bpp = 8;
- c->decode_intra = zmbv_decode_intra;
+ decode_intra = zmbv_decode_intra;
c->decode_xor = zmbv_decode_xor_8;
+ avctx->pix_fmt = AV_PIX_FMT_PAL8;
+ c->stride = c->width;
break;
case ZMBV_FMT_15BPP:
case ZMBV_FMT_16BPP:
c->bpp = 16;
- c->decode_intra = zmbv_decode_intra;
+ decode_intra = zmbv_decode_intra;
c->decode_xor = zmbv_decode_xor_16;
+ if (c->fmt == ZMBV_FMT_15BPP)
+ avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
+ else
+ avctx->pix_fmt = AV_PIX_FMT_RGB565LE;
+ c->stride = c->width * 2;
break;
#ifdef ZMBV_ENABLE_24BPP
case ZMBV_FMT_24BPP:
c->bpp = 24;
- c->decode_intra = zmbv_decode_intra;
+ decode_intra = zmbv_decode_intra;
c->decode_xor = zmbv_decode_xor_24;
+ avctx->pix_fmt = AV_PIX_FMT_RGB24;
+ c->stride = c->width * 3;
break;
#endif //ZMBV_ENABLE_24BPP
case ZMBV_FMT_32BPP:
c->bpp = 32;
- c->decode_intra = zmbv_decode_intra;
+ decode_intra = zmbv_decode_intra;
c->decode_xor = zmbv_decode_xor_32;
+ avctx->pix_fmt = AV_PIX_FMT_BGR0;
+ c->stride = c->width * 4;
break;
default:
- c->decode_intra = NULL;
c->decode_xor = NULL;
avpriv_request_sample(avctx, "Format %i", c->fmt);
return AVERROR_PATCHWELCOME;
@@ -481,16 +494,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
return AVERROR_UNKNOWN;
}
- tmp = av_realloc(c->cur, avctx->width * avctx->height * (c->bpp / 8));
- if (!tmp)
- return AVERROR(ENOMEM);
- c->cur = tmp;
- tmp = av_realloc(c->prev, avctx->width * avctx->height * (c->bpp / 8));
- if (!tmp)
+ c->cur = av_realloc_f(c->cur, avctx->width * avctx->height, (c->bpp / 8));
+ c->prev = av_realloc_f(c->prev, avctx->width * avctx->height, (c->bpp / 8));
+ c->bx = (c->width + c->bw - 1) / c->bw;
+ c->by = (c->height+ c->bh - 1) / c->bh;
+ if (!c->cur || !c->prev)
return AVERROR(ENOMEM);
- c->prev = tmp;
- c->bx = (c->width + c->bw - 1) / c->bw;
- c->by = (c->height + c->bh - 1) / c->bh;
+ memset(c->cur, 0, avctx->width * avctx->height * (c->bpp / 8));
+ memset(c->prev, 0, avctx->width * avctx->height * (c->bpp / 8));
+ c->decode_intra= decode_intra;
}
if (!c->decode_intra) {
@@ -498,6 +510,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
return AVERROR_INVALIDDATA;
}
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
if (c->comp == 0) { //Uncompressed data
if (c->decomp_size < len) {
av_log(avctx, AV_LOG_ERROR, "Buffer too small\n");
@@ -506,7 +521,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
memcpy(c->decomp_buf, buf, len);
} else { // ZLIB-compressed data
c->zstream.total_in = c->zstream.total_out = 0;
- c->zstream.next_in = buf;
+ c->zstream.next_in = (uint8_t*)buf;
c->zstream.avail_in = len;
c->zstream.next_out = c->decomp_buf;
c->zstream.avail_out = c->decomp_size;
@@ -531,64 +546,22 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
/* update frames */
{
uint8_t *out, *src;
- int i, j;
+ int j;
out = frame->data[0];
src = c->cur;
switch (c->fmt) {
case ZMBV_FMT_8BPP:
- for (j = 0; j < c->height; j++) {
- for (i = 0; i < c->width; i++) {
- out[i * 3 + 0] = c->pal[(*src) * 3 + 0];
- out[i * 3 + 1] = c->pal[(*src) * 3 + 1];
- out[i * 3 + 2] = c->pal[(*src) * 3 + 2];
- src++;
- }
- out += frame->linesize[0];
- }
- break;
+ for (j = 0; j < 256; j++)
+ AV_WN32(&frame->data[1][j * 4], 0xFFU << 24 | AV_RB24(&c->pal[j * 3]));
case ZMBV_FMT_15BPP:
- for (j = 0; j < c->height; j++) {
- for (i = 0; i < c->width; i++) {
- uint16_t tmp = AV_RL16(src);
- src += 2;
- out[i * 3 + 0] = (tmp & 0x7C00) >> 7;
- out[i * 3 + 1] = (tmp & 0x03E0) >> 2;
- out[i * 3 + 2] = (tmp & 0x001F) << 3;
- }
- out += frame->linesize[0];
- }
- break;
case ZMBV_FMT_16BPP:
- for (j = 0; j < c->height; j++) {
- for (i = 0; i < c->width; i++) {
- uint16_t tmp = AV_RL16(src);
- src += 2;
- out[i * 3 + 0] = (tmp & 0xF800) >> 8;
- out[i * 3 + 1] = (tmp & 0x07E0) >> 3;
- out[i * 3 + 2] = (tmp & 0x001F) << 3;
- }
- out += frame->linesize[0];
- }
- break;
#ifdef ZMBV_ENABLE_24BPP
case ZMBV_FMT_24BPP:
- for (j = 0; j < c->height; j++) {
- memcpy(out, src, c->width * 3);
- src += c->width * 3;
- out += frame->linesize[0];
- }
- break;
-#endif //ZMBV_ENABLE_24BPP
+#endif
case ZMBV_FMT_32BPP:
- for (j = 0; j < c->height; j++) {
- for (i = 0; i < c->width; i++) {
- uint32_t tmp = AV_RL32(src);
- src += 4;
- AV_WB24(out+(i*3), tmp);
- }
- out += frame->linesize[0];
- }
+ av_image_copy_plane(out, frame->linesize[0], src, c->stride,
+ c->stride, c->height);
break;
default:
av_log(avctx, AV_LOG_ERROR, "Cannot handle format %i\n", c->fmt);
@@ -616,12 +589,11 @@ static av_cold int decode_init(AVCodecContext *avctx)
// Needed if zlib unused or init aborted before inflateInit
memset(&c->zstream, 0, sizeof(z_stream));
- avctx->pix_fmt = AV_PIX_FMT_RGB24;
c->decomp_size = (avctx->width + 255) * 4 * (avctx->height + 64);
/* Allocate decompression buffer */
if (c->decomp_size) {
- if (!(c->decomp_buf = av_malloc(c->decomp_size))) {
+ if (!(c->decomp_buf = av_mallocz(c->decomp_size))) {
av_log(avctx, AV_LOG_ERROR,
"Can't allocate decompression buffer.\n");
return AVERROR(ENOMEM);
diff --git a/libavcodec/zmbvenc.c b/libavcodec/zmbvenc.c
index d7b518db26..2d56a13e01 100644
--- a/libavcodec/zmbvenc.c
+++ b/libavcodec/zmbvenc.c
@@ -2,20 +2,20 @@
* Zip Motion Blocks Video (ZMBV) encoder
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -227,10 +227,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
}
pkt_size = c->zstream.total_out + 1 + 6*keyframe;
- if ((ret = ff_alloc_packet(pkt, pkt_size)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Error getting packet of size %d.\n", pkt_size);
+ if ((ret = ff_alloc_packet2(avctx, pkt, pkt_size)) < 0)
return ret;
- }
buf = pkt->data;
fl = (keyframe ? ZMBV_KEYFRAME : 0) | (chpal ? ZMBV_DELTAPAL : 0);
diff --git a/libavdevice/Makefile b/libavdevice/Makefile
index dfd56be842..f57ec0bcb1 100644
--- a/libavdevice/Makefile
+++ b/libavdevice/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avdevice
HEADERS = avdevice.h \
@@ -5,23 +7,47 @@ HEADERS = avdevice.h \
OBJS = alldevices.o \
avdevice.o \
+ utils.o \
# input/output devices
-OBJS-$(CONFIG_ALSA_INDEV) += alsa_dec.o alsa.o
+OBJS-$(CONFIG_ALSA_INDEV) += alsa_dec.o alsa.o timefilter.o
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa_enc.o alsa.o
+OBJS-$(CONFIG_AVFOUNDATION_INDEV) += avfoundation.o
OBJS-$(CONFIG_BKTR_INDEV) += bktr.o
+OBJS-$(CONFIG_CACA_OUTDEV) += caca.o
+OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o
+OBJS-$(CONFIG_DECKLINK_INDEV) += decklink_dec.o decklink_dec_c.o decklink_common.o
+OBJS-$(CONFIG_DSHOW_INDEV) += dshow_crossbar.o dshow.o dshow_enummediatypes.o \
+ dshow_enumpins.o dshow_filter.o \
+ dshow_pin.o dshow_common.o
OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o
-OBJS-$(CONFIG_FBDEV_INDEV) += fbdev.o
+OBJS-$(CONFIG_FBDEV_INDEV) += fbdev_dec.o \
+ fbdev_common.o
+OBJS-$(CONFIG_FBDEV_OUTDEV) += fbdev_enc.o \
+ fbdev_common.o
+OBJS-$(CONFIG_GDIGRAB_INDEV) += gdigrab.o
+OBJS-$(CONFIG_IEC61883_INDEV) += iec61883.o
OBJS-$(CONFIG_JACK_INDEV) += jack.o timefilter.o
+OBJS-$(CONFIG_LAVFI_INDEV) += lavfi.o
+OBJS-$(CONFIG_OPENAL_INDEV) += openal-dec.o
+OBJS-$(CONFIG_OPENGL_OUTDEV) += opengl_enc.o
OBJS-$(CONFIG_OSS_INDEV) += oss_dec.o oss.o
OBJS-$(CONFIG_OSS_OUTDEV) += oss_enc.o oss.o
-OBJS-$(CONFIG_PULSE_INDEV) += pulse.o
+OBJS-$(CONFIG_PULSE_INDEV) += pulse_audio_dec.o \
+ pulse_audio_common.o timefilter.o
+OBJS-$(CONFIG_PULSE_OUTDEV) += pulse_audio_enc.o \
+ pulse_audio_common.o
+OBJS-$(CONFIG_QTKIT_INDEV) += qtkit.o
+OBJS-$(CONFIG_SDL_OUTDEV) += sdl.o
OBJS-$(CONFIG_SNDIO_INDEV) += sndio_dec.o sndio.o
OBJS-$(CONFIG_SNDIO_OUTDEV) += sndio_enc.o sndio.o
-OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o
+OBJS-$(CONFIG_V4L2_INDEV) += v4l2.o v4l2-common.o timefilter.o
+OBJS-$(CONFIG_V4L2_OUTDEV) += v4l2enc.o v4l2-common.o
+OBJS-$(CONFIG_V4L_INDEV) += v4l.o
OBJS-$(CONFIG_VFWCAP_INDEV) += vfwcap.o
OBJS-$(CONFIG_X11GRAB_INDEV) += x11grab.o
OBJS-$(CONFIG_X11GRAB_XCB_INDEV) += xcbgrab.o
+OBJS-$(CONFIG_XV_OUTDEV) += xv.o
# external libraries
OBJS-$(CONFIG_LIBCDIO_INDEV) += libcdio.o
@@ -29,6 +55,17 @@ OBJS-$(CONFIG_LIBDC1394_INDEV) += libdc1394.o
OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avdeviceres.o
+
+SKIPHEADERS-$(CONFIG_DECKLINK) += decklink_enc.h decklink_dec.h \
+ decklink_common.h decklink_common_c.h
+SKIPHEADERS-$(CONFIG_DSHOW_INDEV) += dshow_capture.h
+SKIPHEADERS-$(CONFIG_FBDEV_INDEV) += fbdev_common.h
+SKIPHEADERS-$(CONFIG_FBDEV_OUTDEV) += fbdev_common.h
+SKIPHEADERS-$(CONFIG_LIBPULSE) += pulse_audio_common.h
+SKIPHEADERS-$(CONFIG_V4L2_INDEV) += v4l2-common.h
+SKIPHEADERS-$(CONFIG_V4L2_OUTDEV) += v4l2-common.h
SKIPHEADERS-$(HAVE_ALSA_ASOUNDLIB_H) += alsa.h
SKIPHEADERS-$(HAVE_SNDIO_H) += sndio.h
diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
index 5dbe2777ee..26aecf29d9 100644
--- a/libavdevice/alldevices.c
+++ b/libavdevice/alldevices.c
@@ -1,25 +1,24 @@
/*
* Register all the grabbing devices.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "libavformat/avformat.h"
#include "avdevice.h"
#define REGISTER_OUTDEV(X, x) \
@@ -48,17 +47,30 @@ void avdevice_register_all(void)
/* devices */
REGISTER_INOUTDEV(ALSA, alsa);
+ REGISTER_INDEV (AVFOUNDATION, avfoundation);
REGISTER_INDEV (BKTR, bktr);
+ REGISTER_OUTDEV (CACA, caca);
+ REGISTER_INOUTDEV(DECKLINK, decklink);
+ REGISTER_INDEV (DSHOW, dshow);
REGISTER_INDEV (DV1394, dv1394);
- REGISTER_INDEV (FBDEV, fbdev);
+ REGISTER_INOUTDEV(FBDEV, fbdev);
+ REGISTER_INDEV (GDIGRAB, gdigrab);
+ REGISTER_INDEV (IEC61883, iec61883);
REGISTER_INDEV (JACK, jack);
+ REGISTER_INDEV (LAVFI, lavfi);
+ REGISTER_INDEV (OPENAL, openal);
+ REGISTER_OUTDEV (OPENGL, opengl);
REGISTER_INOUTDEV(OSS, oss);
- REGISTER_INDEV (PULSE, pulse);
+ REGISTER_INOUTDEV(PULSE, pulse);
+ REGISTER_INDEV (QTKIT, qtkit);
+ REGISTER_OUTDEV (SDL, sdl);
REGISTER_INOUTDEV(SNDIO, sndio);
- REGISTER_INDEV (V4L2, v4l2);
+ REGISTER_INOUTDEV(V4L2, v4l2);
+// REGISTER_INDEV (V4L, v4l
REGISTER_INDEV (VFWCAP, vfwcap);
REGISTER_INDEV (X11GRAB, x11grab);
REGISTER_INDEV (X11GRAB_XCB, x11grab_xcb);
+ REGISTER_OUTDEV (XV, xv);
/* external libraries */
REGISTER_INDEV (LIBCDIO, libcdio);
diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c
index 6d68267602..27a1655a2a 100644
--- a/libavdevice/alsa.c
+++ b/libavdevice/alsa.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,7 +29,7 @@
*/
#include <alsa/asoundlib.h>
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
@@ -62,48 +62,45 @@ static av_cold snd_pcm_format_t codec_id_to_pcm_format(int codec_id)
}
}
-#define REORDER_OUT_50(NAME, TYPE) \
-static void alsa_reorder_ ## NAME ## _out_50(const void *in_v, void *out_v, int n) \
-{ \
- const TYPE *in = in_v; \
- TYPE *out = out_v; \
-\
- while (n-- > 0) { \
+#define MAKE_REORDER_FUNC(NAME, TYPE, CHANNELS, LAYOUT, MAP) \
+static void alsa_reorder_ ## NAME ## _ ## LAYOUT(const void *in_v, \
+ void *out_v, \
+ int n) \
+{ \
+ const TYPE *in = in_v; \
+ TYPE *out = out_v; \
+ \
+ while (n-- > 0) { \
+ MAP \
+ in += CHANNELS; \
+ out += CHANNELS; \
+ } \
+}
+
+#define MAKE_REORDER_FUNCS(CHANNELS, LAYOUT, MAP) \
+ MAKE_REORDER_FUNC(int8, int8_t, CHANNELS, LAYOUT, MAP) \
+ MAKE_REORDER_FUNC(int16, int16_t, CHANNELS, LAYOUT, MAP) \
+ MAKE_REORDER_FUNC(int32, int32_t, CHANNELS, LAYOUT, MAP) \
+ MAKE_REORDER_FUNC(f32, float, CHANNELS, LAYOUT, MAP)
+
+MAKE_REORDER_FUNCS(5, out_50, \
out[0] = in[0]; \
out[1] = in[1]; \
out[2] = in[3]; \
out[3] = in[4]; \
out[4] = in[2]; \
- in += 5; \
- out += 5; \
- } \
-}
+ );
-#define REORDER_OUT_51(NAME, TYPE) \
-static void alsa_reorder_ ## NAME ## _out_51(const void *in_v, void *out_v, int n) \
-{ \
- const TYPE *in = in_v; \
- TYPE *out = out_v; \
-\
- while (n-- > 0) { \
+MAKE_REORDER_FUNCS(6, out_51, \
out[0] = in[0]; \
out[1] = in[1]; \
out[2] = in[4]; \
out[3] = in[5]; \
out[4] = in[2]; \
out[5] = in[3]; \
- in += 6; \
- out += 6; \
- } \
-}
+ );
-#define REORDER_OUT_71(NAME, TYPE) \
-static void alsa_reorder_ ## NAME ## _out_71(const void *in_v, void *out_v, int n) \
-{ \
- const TYPE *in = in_v; \
- TYPE *out = out_v; \
-\
- while (n-- > 0) { \
+MAKE_REORDER_FUNCS(8, out_71, \
out[0] = in[0]; \
out[1] = in[1]; \
out[2] = in[4]; \
@@ -112,23 +109,7 @@ static void alsa_reorder_ ## NAME ## _out_71(const void *in_v, void *out_v, int
out[5] = in[3]; \
out[6] = in[6]; \
out[7] = in[7]; \
- in += 8; \
- out += 8; \
- } \
-}
-
-REORDER_OUT_50(int8, int8_t)
-REORDER_OUT_51(int8, int8_t)
-REORDER_OUT_71(int8, int8_t)
-REORDER_OUT_50(int16, int16_t)
-REORDER_OUT_51(int16, int16_t)
-REORDER_OUT_71(int16, int16_t)
-REORDER_OUT_50(int32, int32_t)
-REORDER_OUT_51(int32, int32_t)
-REORDER_OUT_71(int32, int32_t)
-REORDER_OUT_50(f32, float)
-REORDER_OUT_51(f32, float)
-REORDER_OUT_71(f32, float)
+ );
#define FORMAT_I8 0
#define FORMAT_I16 1
@@ -299,7 +280,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
}
if (s->reorder_func) {
s->reorder_buf_size = buffer_size;
- s->reorder_buf = av_malloc(s->reorder_buf_size * s->frame_size);
+ s->reorder_buf = av_malloc_array(s->reorder_buf_size, s->frame_size);
if (!s->reorder_buf)
goto fail1;
}
@@ -320,6 +301,8 @@ av_cold int ff_alsa_close(AVFormatContext *s1)
AlsaData *s = s1->priv_data;
av_freep(&s->reorder_buf);
+ if (CONFIG_ALSA_INDEV)
+ ff_timefilter_destroy(s->timefilter);
snd_pcm_close(s->h);
return 0;
}
@@ -353,10 +336,64 @@ int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size)
av_assert0(size != 0);
while (size < min_size)
size *= 2;
- r = av_realloc(s->reorder_buf, size * s->frame_size);
+ r = av_realloc_array(s->reorder_buf, size, s->frame_size);
if (!r)
return AVERROR(ENOMEM);
s->reorder_buf = r;
s->reorder_buf_size = size;
return 0;
}
+
+/* ported from alsa-utils/aplay.c */
+int ff_alsa_get_device_list(AVDeviceInfoList *device_list, snd_pcm_stream_t stream_type)
+{
+ int ret = 0;
+ void **hints, **n;
+ char *name = NULL, *descr = NULL, *io = NULL, *tmp;
+ AVDeviceInfo *new_device = NULL;
+ const char *filter = stream_type == SND_PCM_STREAM_PLAYBACK ? "Output" : "Input";
+
+ if (snd_device_name_hint(-1, "pcm", &hints) < 0)
+ return AVERROR_EXTERNAL;
+ n = hints;
+ while (*n && !ret) {
+ name = snd_device_name_get_hint(*n, "NAME");
+ descr = snd_device_name_get_hint(*n, "DESC");
+ io = snd_device_name_get_hint(*n, "IOID");
+ if (!io || !strcmp(io, filter)) {
+ new_device = av_mallocz(sizeof(AVDeviceInfo));
+ if (!new_device) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ new_device->device_name = av_strdup(name);
+ if ((tmp = strrchr(descr, '\n')) && tmp[1])
+ new_device->device_description = av_strdup(&tmp[1]);
+ else
+ new_device->device_description = av_strdup(descr);
+ if (!new_device->device_description || !new_device->device_name) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ if ((ret = av_dynarray_add_nofree(&device_list->devices,
+ &device_list->nb_devices, new_device)) < 0) {
+ goto fail;
+ }
+ if (!strcmp(new_device->device_name, "default"))
+ device_list->default_device = device_list->nb_devices - 1;
+ new_device = NULL;
+ }
+ fail:
+ free(io);
+ free(name);
+ free(descr);
+ n++;
+ }
+ if (new_device) {
+ av_free(new_device->device_description);
+ av_free(new_device->device_name);
+ av_free(new_device);
+ }
+ snd_device_name_free_hint(hints);
+ return ret;
+}
diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h
index 590b354053..f8b7449cd0 100644
--- a/libavdevice/alsa.h
+++ b/libavdevice/alsa.h
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,26 +32,32 @@
#include <alsa/asoundlib.h>
#include "config.h"
-#include "libavformat/avformat.h"
#include "libavutil/log.h"
+#include "timefilter.h"
+#include "avdevice.h"
/* XXX: we make the assumption that the soundcard accepts this format */
/* XXX: find better solution with "preinit" method, needed also in
other formats */
#define DEFAULT_CODEC_ID AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE)
-#define ALSA_BUFFER_SIZE_MAX 32768
+typedef void (*ff_reorder_func)(const void *, void *, int);
+
+#define ALSA_BUFFER_SIZE_MAX 65536
typedef struct AlsaData {
AVClass *class;
snd_pcm_t *h;
- int frame_size; ///< preferred size for reads and writes
- int period_size; ///< bytes per sample * channels
+ int frame_size; ///< bytes per sample * channels
+ int period_size; ///< preferred size for reads and writes, in frames
int sample_rate; ///< sample rate set by user
int channels; ///< number of channels set by user
+ int last_period;
+ TimeFilter *timefilter;
void (*reorder_func)(const void *, void *, int);
void *reorder_buf;
int reorder_buf_size; ///< in frames
+ int64_t timestamp; ///< current timestamp, without latency applied.
} AlsaData;
/**
@@ -93,4 +99,6 @@ int ff_alsa_xrun_recover(AVFormatContext *s1, int err);
int ff_alsa_extend_reorder_buf(AlsaData *s, int size);
+int ff_alsa_get_device_list(AVDeviceInfoList *device_list, snd_pcm_stream_t stream_type);
+
#endif /* AVDEVICE_ALSA_H */
diff --git a/libavdevice/alsa_dec.c b/libavdevice/alsa_dec.c
index 2cc5b7d574..286af650c7 100644
--- a/libavdevice/alsa_dec.c
+++ b/libavdevice/alsa_dec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,11 +48,13 @@
#include <alsa/asoundlib.h>
#include "libavutil/internal.h"
+#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/time.h"
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
+#include "avdevice.h"
#include "alsa.h"
static av_cold int audio_read_header(AVFormatContext *s1)
@@ -61,7 +63,6 @@ static av_cold int audio_read_header(AVFormatContext *s1)
AVStream *st;
int ret;
enum AVCodecID codec_id;
- snd_pcm_sw_params_t *sw_params;
st = avformat_new_stream(s1, NULL);
if (!st) {
@@ -77,35 +78,18 @@ static av_cold int audio_read_header(AVFormatContext *s1)
return AVERROR(EIO);
}
- if (snd_pcm_type(s->h) != SND_PCM_TYPE_HW)
- av_log(s1, AV_LOG_WARNING,
- "capture with some ALSA plugins, especially dsnoop, "
- "may hang.\n");
-
- ret = snd_pcm_sw_params_malloc(&sw_params);
- if (ret < 0) {
- av_log(s1, AV_LOG_ERROR, "cannot allocate software parameters structure (%s)\n",
- snd_strerror(ret));
- goto fail;
- }
-
- snd_pcm_sw_params_current(s->h, sw_params);
- snd_pcm_sw_params_set_tstamp_mode(s->h, sw_params, SND_PCM_TSTAMP_ENABLE);
-
- ret = snd_pcm_sw_params(s->h, sw_params);
- snd_pcm_sw_params_free(sw_params);
- if (ret < 0) {
- av_log(s1, AV_LOG_ERROR, "cannot install ALSA software parameters (%s)\n",
- snd_strerror(ret));
- goto fail;
- }
-
/* take real parameters */
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = codec_id;
st->codec->sample_rate = s->sample_rate;
st->codec->channels = s->channels;
+ st->codec->frame_size = s->frame_size;
avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+ /* microseconds instead of seconds, MHz instead of Hz */
+ s->timefilter = ff_timefilter_new(1000000.0 / s->sample_rate,
+ s->period_size, 1.5E-6);
+ if (!s->timefilter)
+ goto fail;
return 0;
@@ -117,16 +101,15 @@ fail:
static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
AlsaData *s = s1->priv_data;
- AVStream *st = s1->streams[0];
int res;
- snd_htimestamp_t timestamp;
- snd_pcm_uframes_t ts_delay;
+ int64_t dts;
+ snd_pcm_sframes_t delay = 0;
- if (av_new_packet(pkt, s->period_size) < 0) {
+ if (av_new_packet(pkt, s->period_size * s->frame_size) < 0) {
return AVERROR(EIO);
}
- while ((res = snd_pcm_readi(s->h, pkt->data, pkt->size / s->frame_size)) < 0) {
+ while ((res = snd_pcm_readi(s->h, pkt->data, s->period_size)) < 0) {
if (res == -EAGAIN) {
av_free_packet(pkt);
@@ -139,20 +122,25 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
return AVERROR(EIO);
}
+ ff_timefilter_reset(s->timefilter);
}
- snd_pcm_htimestamp(s->h, &ts_delay, &timestamp);
- ts_delay += res;
- pkt->pts = timestamp.tv_sec * 1000000LL
- + (timestamp.tv_nsec * st->codec->sample_rate
- - (int64_t)ts_delay * 1000000000LL + st->codec->sample_rate * 500LL)
- / (st->codec->sample_rate * 1000LL);
+ dts = av_gettime();
+ snd_pcm_delay(s->h, &delay);
+ dts -= av_rescale(delay + res, 1000000, s->sample_rate);
+ pkt->pts = ff_timefilter_update(s->timefilter, dts, s->last_period);
+ s->last_period = res;
pkt->size = res * s->frame_size;
return 0;
}
+static int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
+{
+ return ff_alsa_get_device_list(device_list, SND_PCM_STREAM_CAPTURE);
+}
+
static const AVOption options[] = {
{ "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
{ "channels", "", offsetof(AlsaData, channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
@@ -164,6 +152,7 @@ static const AVClass alsa_demuxer_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
};
AVInputFormat ff_alsa_demuxer = {
@@ -173,6 +162,7 @@ AVInputFormat ff_alsa_demuxer = {
.read_header = audio_read_header,
.read_packet = audio_read_packet,
.read_close = ff_alsa_close,
+ .get_device_list = audio_get_device_list,
.flags = AVFMT_NOFILE,
.priv_class = &alsa_demuxer_class,
};
diff --git a/libavdevice/alsa_enc.c b/libavdevice/alsa_enc.c
index 30c1719203..fb428f0623 100644
--- a/libavdevice/alsa_enc.c
+++ b/libavdevice/alsa_enc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Luca Abeni ( lucabe72 email it )
* Copyright (c) 2007 Benoit Fouet ( benoit fouet free fr )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,20 +40,27 @@
#include <alsa/asoundlib.h>
#include "libavutil/internal.h"
+#include "libavutil/time.h"
-#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
#include "alsa.h"
static av_cold int audio_write_header(AVFormatContext *s1)
{
AlsaData *s = s1->priv_data;
- AVStream *st;
+ AVStream *st = NULL;
unsigned int sample_rate;
enum AVCodecID codec_id;
int res;
+ if (s1->nb_streams != 1 || s1->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(s1, AV_LOG_ERROR, "Only a single audio stream is supported.\n");
+ return AVERROR(EINVAL);
+ }
st = s1->streams[0];
+
sample_rate = st->codec->sample_rate;
codec_id = st->codec->codec_id;
res = ff_alsa_open(s1, SND_PCM_STREAM_PLAYBACK, &sample_rate,
@@ -64,6 +71,7 @@ static av_cold int audio_write_header(AVFormatContext *s1)
st->codec->sample_rate, sample_rate);
goto fail;
}
+ avpriv_set_pts_info(st, 64, 1, sample_rate);
return res;
@@ -80,6 +88,10 @@ static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt)
uint8_t *buf = pkt->data;
size /= s->frame_size;
+ if (pkt->dts != AV_NOPTS_VALUE)
+ s->timestamp = pkt->dts;
+ s->timestamp += pkt->duration ? pkt->duration : size;
+
if (s->reorder_func) {
if (size > s->reorder_buf_size)
if (ff_alsa_extend_reorder_buf(s, size))
@@ -104,6 +116,47 @@ static int audio_write_packet(AVFormatContext *s1, AVPacket *pkt)
return 0;
}
+static int audio_write_frame(AVFormatContext *s1, int stream_index,
+ AVFrame **frame, unsigned flags)
+{
+ AlsaData *s = s1->priv_data;
+ AVPacket pkt;
+
+ /* ff_alsa_open() should have accepted only supported formats */
+ if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
+ return av_sample_fmt_is_planar(s1->streams[stream_index]->codec->sample_fmt) ?
+ AVERROR(EINVAL) : 0;
+ /* set only used fields */
+ pkt.data = (*frame)->data[0];
+ pkt.size = (*frame)->nb_samples * s->frame_size;
+ pkt.dts = (*frame)->pkt_dts;
+ pkt.duration = av_frame_get_pkt_duration(*frame);
+ return audio_write_packet(s1, &pkt);
+}
+
+static void
+audio_get_output_timestamp(AVFormatContext *s1, int stream,
+ int64_t *dts, int64_t *wall)
+{
+ AlsaData *s = s1->priv_data;
+ snd_pcm_sframes_t delay = 0;
+ *wall = av_gettime();
+ snd_pcm_delay(s->h, &delay);
+ *dts = s->timestamp - delay;
+}
+
+static int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
+{
+ return ff_alsa_get_device_list(device_list, SND_PCM_STREAM_PLAYBACK);
+}
+
+static const AVClass alsa_muxer_class = {
+ .class_name = "ALSA muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+};
+
AVOutputFormat ff_alsa_muxer = {
.name = "alsa",
.long_name = NULL_IF_CONFIG_SMALL("ALSA audio output"),
@@ -113,5 +166,9 @@ AVOutputFormat ff_alsa_muxer = {
.write_header = audio_write_header,
.write_packet = audio_write_packet,
.write_trailer = ff_alsa_close,
+ .write_uncoded_frame = audio_write_frame,
+ .get_device_list = audio_get_device_list,
+ .get_output_timestamp = audio_get_output_timestamp,
.flags = AVFMT_NOFILE,
+ .priv_class = &alsa_muxer_class,
};
diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c
index 5a5c762c8b..01c46924d1 100644
--- a/libavdevice/avdevice.c
+++ b/libavdevice/avdevice.c
@@ -1,36 +1,271 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/samplefmt.h"
+#include "libavutil/pixfmt.h"
+#include "libavcodec/avcodec.h"
#include "avdevice.h"
+#include "internal.h"
#include "config.h"
+#include "libavutil/ffversion.h"
+const char av_device_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
+#define E AV_OPT_FLAG_ENCODING_PARAM
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define V AV_OPT_FLAG_VIDEO_PARAM
+#define OFFSET(x) offsetof(AVDeviceCapabilitiesQuery, x)
+
+const AVOption av_device_capabilities[] = {
+ { "codec", "codec", OFFSET(codec), AV_OPT_TYPE_INT,
+ {.i64 = AV_CODEC_ID_NONE}, AV_CODEC_ID_NONE, INT_MAX, E|D|A|V },
+ { "sample_format", "sample format", OFFSET(sample_format), AV_OPT_TYPE_SAMPLE_FMT,
+ {.i64 = AV_SAMPLE_FMT_NONE}, AV_SAMPLE_FMT_NONE, INT_MAX, E|D|A },
+ { "sample_rate", "sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT,
+ {.i64 = -1}, -1, INT_MAX, E|D|A },
+ { "channels", "channels", OFFSET(channels), AV_OPT_TYPE_INT,
+ {.i64 = -1}, -1, INT_MAX, E|D|A },
+ { "channel_layout", "channel layout", OFFSET(channel_layout), AV_OPT_TYPE_CHANNEL_LAYOUT,
+ {.i64 = -1}, -1, INT_MAX, E|D|A },
+ { "pixel_format", "pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT,
+ {.i64 = AV_PIX_FMT_NONE}, AV_PIX_FMT_NONE, INT_MAX, E|D|V },
+ { "window_size", "window size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE,
+ {.str = NULL}, -1, INT_MAX, E|D|V },
+ { "frame_size", "frame size", OFFSET(frame_width), AV_OPT_TYPE_IMAGE_SIZE,
+ {.str = NULL}, -1, INT_MAX, E|D|V },
+ { "fps", "fps", OFFSET(fps), AV_OPT_TYPE_RATIONAL,
+ {.dbl = -1}, -1, INT_MAX, E|D|V },
+ { NULL }
+};
+
+#undef E
+#undef D
+#undef A
+#undef V
+#undef OFFSET
+
unsigned avdevice_version(void)
{
+ av_assert0(LIBAVDEVICE_VERSION_MICRO >= 100);
return LIBAVDEVICE_VERSION_INT;
}
const char * avdevice_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char * avdevice_license(void)
{
#define LICENSE_PREFIX "libavdevice license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+}
+
+static void *device_next(void *prev, int output,
+ AVClassCategory c1, AVClassCategory c2)
+{
+ const AVClass *pc;
+ AVClassCategory category = AV_CLASS_CATEGORY_NA;
+ do {
+ if (output) {
+ if (!(prev = av_oformat_next(prev)))
+ break;
+ pc = ((AVOutputFormat *)prev)->priv_class;
+ } else {
+ if (!(prev = av_iformat_next(prev)))
+ break;
+ pc = ((AVInputFormat *)prev)->priv_class;
+ }
+ if (!pc)
+ continue;
+ category = pc->category;
+ } while (category != c1 && category != c2);
+ return prev;
+}
+
+AVInputFormat *av_input_audio_device_next(AVInputFormat *d)
+{
+ return device_next(d, 0, AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_INPUT);
+}
+
+AVInputFormat *av_input_video_device_next(AVInputFormat *d)
+{
+ return device_next(d, 0, AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_INPUT);
+}
+
+AVOutputFormat *av_output_audio_device_next(AVOutputFormat *d)
+{
+ return device_next(d, 1, AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_OUTPUT);
+}
+
+AVOutputFormat *av_output_video_device_next(AVOutputFormat *d)
+{
+ return device_next(d, 1, AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_OUTPUT);
+}
+
+int avdevice_app_to_dev_control_message(struct AVFormatContext *s, enum AVAppToDevMessageType type,
+ void *data, size_t data_size)
+{
+ if (!s->oformat || !s->oformat->control_message)
+ return AVERROR(ENOSYS);
+ return s->oformat->control_message(s, type, data, data_size);
+}
+
+int avdevice_dev_to_app_control_message(struct AVFormatContext *s, enum AVDevToAppMessageType type,
+ void *data, size_t data_size)
+{
+ if (!av_format_get_control_message_cb(s))
+ return AVERROR(ENOSYS);
+ return av_format_get_control_message_cb(s)(s, type, data, data_size);
+}
+
+int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s,
+ AVDictionary **device_options)
+{
+ int ret;
+ av_assert0(s && caps);
+ av_assert0(s->iformat || s->oformat);
+ if ((s->oformat && !s->oformat->create_device_capabilities) ||
+ (s->iformat && !s->iformat->create_device_capabilities))
+ return AVERROR(ENOSYS);
+ *caps = av_mallocz(sizeof(**caps));
+ if (!(*caps))
+ return AVERROR(ENOMEM);
+ (*caps)->device_context = s;
+ if (((ret = av_opt_set_dict(s->priv_data, device_options)) < 0))
+ goto fail;
+ if (s->iformat) {
+ if ((ret = s->iformat->create_device_capabilities(s, *caps)) < 0)
+ goto fail;
+ } else {
+ if ((ret = s->oformat->create_device_capabilities(s, *caps)) < 0)
+ goto fail;
+ }
+ av_opt_set_defaults(*caps);
+ return 0;
+ fail:
+ av_freep(caps);
+ return ret;
+}
+
+void avdevice_capabilities_free(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s)
+{
+ if (!s || !caps || !(*caps))
+ return;
+ av_assert0(s->iformat || s->oformat);
+ if (s->iformat) {
+ if (s->iformat->free_device_capabilities)
+ s->iformat->free_device_capabilities(s, *caps);
+ } else {
+ if (s->oformat->free_device_capabilities)
+ s->oformat->free_device_capabilities(s, *caps);
+ }
+ av_freep(caps);
+}
+
+int avdevice_list_devices(AVFormatContext *s, AVDeviceInfoList **device_list)
+{
+ int ret;
+ av_assert0(s);
+ av_assert0(device_list);
+ av_assert0(s->oformat || s->iformat);
+ if ((s->oformat && !s->oformat->get_device_list) ||
+ (s->iformat && !s->iformat->get_device_list)) {
+ *device_list = NULL;
+ return AVERROR(ENOSYS);
+ }
+ *device_list = av_mallocz(sizeof(AVDeviceInfoList));
+ if (!(*device_list))
+ return AVERROR(ENOMEM);
+ /* no default device by default */
+ (*device_list)->default_device = -1;
+ if (s->oformat)
+ ret = s->oformat->get_device_list(s, *device_list);
+ else
+ ret = s->iformat->get_device_list(s, *device_list);
+ if (ret < 0)
+ avdevice_free_list_devices(device_list);
+ return ret;
+}
+
+static int list_devices_for_context(AVFormatContext *s, AVDictionary *options,
+ AVDeviceInfoList **device_list)
+{
+ AVDictionary *tmp = NULL;
+ int ret;
+
+ av_dict_copy(&tmp, options, 0);
+ if ((ret = av_opt_set_dict2(s, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto fail;
+ ret = avdevice_list_devices(s, device_list);
+ fail:
+ av_dict_free(&tmp);
+ avformat_free_context(s);
+ return ret;
+}
+
+int avdevice_list_input_sources(AVInputFormat *device, const char *device_name,
+ AVDictionary *device_options, AVDeviceInfoList **device_list)
+{
+ AVFormatContext *s = NULL;
+ int ret;
+
+ if ((ret = ff_alloc_input_device_context(&s, device, device_name)) < 0)
+ return ret;
+ return list_devices_for_context(s, device_options, device_list);
+}
+
+int avdevice_list_output_sinks(AVOutputFormat *device, const char *device_name,
+ AVDictionary *device_options, AVDeviceInfoList **device_list)
+{
+ AVFormatContext *s = NULL;
+ int ret;
+
+ if ((ret = avformat_alloc_output_context2(&s, device, device_name, NULL)) < 0)
+ return ret;
+ return list_devices_for_context(s, device_options, device_list);
+}
+
+void avdevice_free_list_devices(AVDeviceInfoList **device_list)
+{
+ AVDeviceInfoList *list;
+ AVDeviceInfo *dev;
+ int i;
+
+ av_assert0(device_list);
+ list = *device_list;
+ if (!list)
+ return;
+
+ for (i = 0; i < list->nb_devices; i++) {
+ dev = list->devices[i];
+ if (dev) {
+ av_freep(&dev->device_name);
+ av_freep(&dev->device_description);
+ av_free(dev);
+ }
+ }
+ av_freep(&list->devices);
+ av_freep(device_list);
}
diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h
index 39166a570a..2d675b012d 100644
--- a/libavdevice/avdevice.h
+++ b/libavdevice/avdevice.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,6 +43,11 @@
* @}
*/
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/dict.h"
+#include "libavformat/avformat.h"
+
/**
* Return the LIBAVDEVICE_VERSION_INT constant.
*/
@@ -64,4 +69,441 @@ const char *avdevice_license(void);
*/
void avdevice_register_all(void);
+/**
+ * Audio input devices iterator.
+ *
+ * If d is NULL, returns the first registered input audio/video device,
+ * if d is non-NULL, returns the next registered input audio/video device after d
+ * or NULL if d is the last one.
+ */
+AVInputFormat *av_input_audio_device_next(AVInputFormat *d);
+
+/**
+ * Video input devices iterator.
+ *
+ * If d is NULL, returns the first registered input audio/video device,
+ * if d is non-NULL, returns the next registered input audio/video device after d
+ * or NULL if d is the last one.
+ */
+AVInputFormat *av_input_video_device_next(AVInputFormat *d);
+
+/**
+ * Audio output devices iterator.
+ *
+ * If d is NULL, returns the first registered output audio/video device,
+ * if d is non-NULL, returns the next registered output audio/video device after d
+ * or NULL if d is the last one.
+ */
+AVOutputFormat *av_output_audio_device_next(AVOutputFormat *d);
+
+/**
+ * Video output devices iterator.
+ *
+ * If d is NULL, returns the first registered output audio/video device,
+ * if d is non-NULL, returns the next registered output audio/video device after d
+ * or NULL if d is the last one.
+ */
+AVOutputFormat *av_output_video_device_next(AVOutputFormat *d);
+
+typedef struct AVDeviceRect {
+ int x; /**< x coordinate of top left corner */
+ int y; /**< y coordinate of top left corner */
+ int width; /**< width */
+ int height; /**< height */
+} AVDeviceRect;
+
+/**
+ * Message types used by avdevice_app_to_dev_control_message().
+ */
+enum AVAppToDevMessageType {
+ /**
+ * Dummy message.
+ */
+ AV_APP_TO_DEV_NONE = MKBETAG('N','O','N','E'),
+
+ /**
+ * Window size change message.
+ *
+ * Message is sent to the device every time the application changes the size
+ * of the window device renders to.
+ * Message should also be sent right after window is created.
+ *
+ * data: AVDeviceRect: new window size.
+ */
+ AV_APP_TO_DEV_WINDOW_SIZE = MKBETAG('G','E','O','M'),
+
+ /**
+ * Repaint request message.
+ *
+ * Message is sent to the device when window has to be repainted.
+ *
+ * data: AVDeviceRect: area required to be repainted.
+ * NULL: whole area is required to be repainted.
+ */
+ AV_APP_TO_DEV_WINDOW_REPAINT = MKBETAG('R','E','P','A'),
+
+ /**
+ * Request pause/play.
+ *
+ * Application requests pause/unpause playback.
+ * Mostly usable with devices that have internal buffer.
+ * By default devices are not paused.
+ *
+ * data: NULL
+ */
+ AV_APP_TO_DEV_PAUSE = MKBETAG('P', 'A', 'U', ' '),
+ AV_APP_TO_DEV_PLAY = MKBETAG('P', 'L', 'A', 'Y'),
+ AV_APP_TO_DEV_TOGGLE_PAUSE = MKBETAG('P', 'A', 'U', 'T'),
+
+ /**
+ * Volume control message.
+ *
+ * Set volume level. It may be device-dependent if volume
+ * is changed per stream or system wide. Per stream volume
+ * change is expected when possible.
+ *
+ * data: double: new volume with range of 0.0 - 1.0.
+ */
+ AV_APP_TO_DEV_SET_VOLUME = MKBETAG('S', 'V', 'O', 'L'),
+
+ /**
+ * Mute control messages.
+ *
+ * Change mute state. It may be device-dependent if mute status
+ * is changed per stream or system wide. Per stream mute status
+ * change is expected when possible.
+ *
+ * data: NULL.
+ */
+ AV_APP_TO_DEV_MUTE = MKBETAG(' ', 'M', 'U', 'T'),
+ AV_APP_TO_DEV_UNMUTE = MKBETAG('U', 'M', 'U', 'T'),
+ AV_APP_TO_DEV_TOGGLE_MUTE = MKBETAG('T', 'M', 'U', 'T'),
+
+ /**
+ * Get volume/mute messages.
+ *
+ * Force the device to send AV_DEV_TO_APP_VOLUME_LEVEL_CHANGED or
+ * AV_DEV_TO_APP_MUTE_STATE_CHANGED command respectively.
+ *
+ * data: NULL.
+ */
+ AV_APP_TO_DEV_GET_VOLUME = MKBETAG('G', 'V', 'O', 'L'),
+ AV_APP_TO_DEV_GET_MUTE = MKBETAG('G', 'M', 'U', 'T'),
+};
+
+/**
+ * Message types used by avdevice_dev_to_app_control_message().
+ */
+enum AVDevToAppMessageType {
+ /**
+ * Dummy message.
+ */
+ AV_DEV_TO_APP_NONE = MKBETAG('N','O','N','E'),
+
+ /**
+ * Create window buffer message.
+ *
+ * Device requests to create a window buffer. Exact meaning is device-
+ * and application-dependent. Message is sent before rendering first
+ * frame and all one-shot initializations should be done here.
+ * Application is allowed to ignore preferred window buffer size.
+ *
+ * @note: Application is obligated to inform about window buffer size
+ * with AV_APP_TO_DEV_WINDOW_SIZE message.
+ *
+ * data: AVDeviceRect: preferred size of the window buffer.
+ * NULL: no preferred size of the window buffer.
+ */
+ AV_DEV_TO_APP_CREATE_WINDOW_BUFFER = MKBETAG('B','C','R','E'),
+
+ /**
+ * Prepare window buffer message.
+ *
+ * Device requests to prepare a window buffer for rendering.
+ * Exact meaning is device- and application-dependent.
+ * Message is sent before rendering of each frame.
+ *
+ * data: NULL.
+ */
+ AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER = MKBETAG('B','P','R','E'),
+
+ /**
+ * Display window buffer message.
+ *
+ * Device requests to display a window buffer.
+ * Message is sent when new frame is ready to be displayed.
+ * Usually buffers need to be swapped in handler of this message.
+ *
+ * data: NULL.
+ */
+ AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER = MKBETAG('B','D','I','S'),
+
+ /**
+ * Destroy window buffer message.
+ *
+ * Device requests to destroy a window buffer.
+ * Message is sent when device is about to be destroyed and window
+ * buffer is not required anymore.
+ *
+ * data: NULL.
+ */
+ AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER = MKBETAG('B','D','E','S'),
+
+ /**
+ * Buffer fullness status messages.
+ *
+ * Device signals buffer overflow/underflow.
+ *
+ * data: NULL.
+ */
+ AV_DEV_TO_APP_BUFFER_OVERFLOW = MKBETAG('B','O','F','L'),
+ AV_DEV_TO_APP_BUFFER_UNDERFLOW = MKBETAG('B','U','F','L'),
+
+ /**
+ * Buffer readable/writable.
+ *
+ * Device informs that buffer is readable/writable.
+ * When possible, device informs how many bytes can be read/write.
+ *
+ * @warning Device may not inform when number of bytes than can be read/write changes.
+ *
+ * data: int64_t: amount of bytes available to read/write.
+ * NULL: amount of bytes available to read/write is not known.
+ */
+ AV_DEV_TO_APP_BUFFER_READABLE = MKBETAG('B','R','D',' '),
+ AV_DEV_TO_APP_BUFFER_WRITABLE = MKBETAG('B','W','R',' '),
+
+ /**
+ * Mute state change message.
+ *
+ * Device informs that mute state has changed.
+ *
+ * data: int: 0 for not muted state, non-zero for muted state.
+ */
+ AV_DEV_TO_APP_MUTE_STATE_CHANGED = MKBETAG('C','M','U','T'),
+
+ /**
+ * Volume level change message.
+ *
+ * Device informs that volume level has changed.
+ *
+ * data: double: new volume with range of 0.0 - 1.0.
+ */
+ AV_DEV_TO_APP_VOLUME_LEVEL_CHANGED = MKBETAG('C','V','O','L'),
+};
+
+/**
+ * Send control message from application to device.
+ *
+ * @param s device context.
+ * @param type message type.
+ * @param data message data. Exact type depends on message type.
+ * @param data_size size of message data.
+ * @return >= 0 on success, negative on error.
+ * AVERROR(ENOSYS) when device doesn't implement handler of the message.
+ */
+int avdevice_app_to_dev_control_message(struct AVFormatContext *s,
+ enum AVAppToDevMessageType type,
+ void *data, size_t data_size);
+
+/**
+ * Send control message from device to application.
+ *
+ * @param s device context.
+ * @param type message type.
+ * @param data message data. Can be NULL.
+ * @param data_size size of message data.
+ * @return >= 0 on success, negative on error.
+ * AVERROR(ENOSYS) when application doesn't implement handler of the message.
+ */
+int avdevice_dev_to_app_control_message(struct AVFormatContext *s,
+ enum AVDevToAppMessageType type,
+ void *data, size_t data_size);
+
+/**
+ * Following API allows user to probe device capabilities (supported codecs,
+ * pixel formats, sample formats, resolutions, channel counts, etc).
+ * It is build on top op AVOption API.
+ * Queried capabilities allows to set up converters of video or audio
+ * parameters that fit to the device.
+ *
+ * List of capabilities that can be queried:
+ * - Capabilities valid for both audio and video devices:
+ * - codec: supported audio/video codecs.
+ * type: AV_OPT_TYPE_INT (AVCodecID value)
+ * - Capabilities valid for audio devices:
+ * - sample_format: supported sample formats.
+ * type: AV_OPT_TYPE_INT (AVSampleFormat value)
+ * - sample_rate: supported sample rates.
+ * type: AV_OPT_TYPE_INT
+ * - channels: supported number of channels.
+ * type: AV_OPT_TYPE_INT
+ * - channel_layout: supported channel layouts.
+ * type: AV_OPT_TYPE_INT64
+ * - Capabilities valid for video devices:
+ * - pixel_format: supported pixel formats.
+ * type: AV_OPT_TYPE_INT (AVPixelFormat value)
+ * - window_size: supported window sizes (describes size of the window size presented to the user).
+ * type: AV_OPT_TYPE_IMAGE_SIZE
+ * - frame_size: supported frame sizes (describes size of provided video frames).
+ * type: AV_OPT_TYPE_IMAGE_SIZE
+ * - fps: supported fps values
+ * type: AV_OPT_TYPE_RATIONAL
+ *
+ * Value of the capability may be set by user using av_opt_set() function
+ * and AVDeviceCapabilitiesQuery object. Following queries will
+ * limit results to the values matching already set capabilities.
+ * For example, setting a codec may impact number of formats or fps values
+ * returned during next query. Setting invalid value may limit results to zero.
+ *
+ * Example of the usage basing on opengl output device:
+ *
+ * @code
+ * AVFormatContext *oc = NULL;
+ * AVDeviceCapabilitiesQuery *caps = NULL;
+ * AVOptionRanges *ranges;
+ * int ret;
+ *
+ * if ((ret = avformat_alloc_output_context2(&oc, NULL, "opengl", NULL)) < 0)
+ * goto fail;
+ * if (avdevice_capabilities_create(&caps, oc, NULL) < 0)
+ * goto fail;
+ *
+ * //query codecs
+ * if (av_opt_query_ranges(&ranges, caps, "codec", AV_OPT_MULTI_COMPONENT_RANGE)) < 0)
+ * goto fail;
+ * //pick codec here and set it
+ * av_opt_set(caps, "codec", AV_CODEC_ID_RAWVIDEO, 0);
+ *
+ * //query format
+ * if (av_opt_query_ranges(&ranges, caps, "pixel_format", AV_OPT_MULTI_COMPONENT_RANGE)) < 0)
+ * goto fail;
+ * //pick format here and set it
+ * av_opt_set(caps, "pixel_format", AV_PIX_FMT_YUV420P, 0);
+ *
+ * //query and set more capabilities
+ *
+ * fail:
+ * //clean up code
+ * avdevice_capabilities_free(&query, oc);
+ * avformat_free_context(oc);
+ * @endcode
+ */
+
+/**
+ * Structure describes device capabilities.
+ *
+ * It is used by devices in conjunction with av_device_capabilities AVOption table
+ * to implement capabilities probing API based on AVOption API. Should not be used directly.
+ */
+typedef struct AVDeviceCapabilitiesQuery {
+ const AVClass *av_class;
+ AVFormatContext *device_context;
+ enum AVCodecID codec;
+ enum AVSampleFormat sample_format;
+ enum AVPixelFormat pixel_format;
+ int sample_rate;
+ int channels;
+ int64_t channel_layout;
+ int window_width;
+ int window_height;
+ int frame_width;
+ int frame_height;
+ AVRational fps;
+} AVDeviceCapabilitiesQuery;
+
+/**
+ * AVOption table used by devices to implement device capabilities API. Should not be used by a user.
+ */
+extern const AVOption av_device_capabilities[];
+
+/**
+ * Initialize capabilities probing API based on AVOption API.
+ *
+ * avdevice_capabilities_free() must be called when query capabilities API is
+ * not used anymore.
+ *
+ * @param[out] caps Device capabilities data. Pointer to a NULL pointer must be passed.
+ * @param s Context of the device.
+ * @param device_options An AVDictionary filled with device-private options.
+ * On return this parameter will be destroyed and replaced with a dict
+ * containing options that were not found. May be NULL.
+ * The same options must be passed later to avformat_write_header() for output
+ * devices or avformat_open_input() for input devices, or at any other place
+ * that affects device-private options.
+ *
+ * @return >= 0 on success, negative otherwise.
+ */
+int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s,
+ AVDictionary **device_options);
+
+/**
+ * Free resources created by avdevice_capabilities_create()
+ *
+ * @param caps Device capabilities data to be freed.
+ * @param s Context of the device.
+ */
+void avdevice_capabilities_free(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s);
+
+/**
+ * Structure describes basic parameters of the device.
+ */
+typedef struct AVDeviceInfo {
+ char *device_name; /**< device name, format depends on device */
+ char *device_description; /**< human friendly name */
+} AVDeviceInfo;
+
+/**
+ * List of devices.
+ */
+typedef struct AVDeviceInfoList {
+ AVDeviceInfo **devices; /**< list of autodetected devices */
+ int nb_devices; /**< number of autodetected devices */
+ int default_device; /**< index of default device or -1 if no default */
+} AVDeviceInfoList;
+
+/**
+ * List devices.
+ *
+ * Returns available device names and their parameters.
+ *
+ * @note: Some devices may accept system-dependent device names that cannot be
+ * autodetected. The list returned by this function cannot be assumed to
+ * be always completed.
+ *
+ * @param s device context.
+ * @param[out] device_list list of autodetected devices.
+ * @return count of autodetected devices, negative on error.
+ */
+int avdevice_list_devices(struct AVFormatContext *s, AVDeviceInfoList **device_list);
+
+/**
+ * Convenient function to free result of avdevice_list_devices().
+ *
+ * @param devices device list to be freed.
+ */
+void avdevice_free_list_devices(AVDeviceInfoList **device_list);
+
+/**
+ * List devices.
+ *
+ * Returns available device names and their parameters.
+ * These are convinient wrappers for avdevice_list_devices().
+ * Device context is allocated and deallocated internally.
+ *
+ * @param device device format. May be NULL if device name is set.
+ * @param device_name device name. May be NULL if device format is set.
+ * @param device_options An AVDictionary filled with device-private options. May be NULL.
+ * The same options must be passed later to avformat_write_header() for output
+ * devices or avformat_open_input() for input devices, or at any other place
+ * that affects device-private options.
+ * @param[out] device_list list of autodetected devices
+ * @return count of autodetected devices, negative on error.
+ * @note device argument takes precedence over device_name when both are set.
+ */
+int avdevice_list_input_sources(struct AVInputFormat *device, const char *device_name,
+ AVDictionary *device_options, AVDeviceInfoList **device_list);
+int avdevice_list_output_sinks(struct AVOutputFormat *device, const char *device_name,
+ AVDictionary *device_options, AVDeviceInfoList **device_list);
+
#endif /* AVDEVICE_AVDEVICE_H */
diff --git a/libavdevice/avdeviceres.rc b/libavdevice/avdeviceres.rc
new file mode 100644
index 0000000000..e13e73d57e
--- /dev/null
+++ b/libavdevice/avdeviceres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libavdevice
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libavdevice/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBAVDEVICE_VERSION_MAJOR, LIBAVDEVICE_VERSION_MINOR, LIBAVDEVICE_VERSION_MICRO, 0
+PRODUCTVERSION LIBAVDEVICE_VERSION_MAJOR, LIBAVDEVICE_VERSION_MINOR, LIBAVDEVICE_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg device handling library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBAVDEVICE_VERSION)
+ VALUE "InternalName", "libavdevice"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "avdevice" BUILDSUF "-" AV_STRINGIFY(LIBAVDEVICE_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m
new file mode 100644
index 0000000000..763e675766
--- /dev/null
+++ b/libavdevice/avfoundation.m
@@ -0,0 +1,1049 @@
+/*
+ * AVFoundation input device
+ * Copyright (c) 2014 Thilo Borgmann <thilo.borgmann@mail.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * AVFoundation input device
+ * @author Thilo Borgmann <thilo.borgmann@mail.de>
+ */
+
+#import <AVFoundation/AVFoundation.h>
+#include <pthread.h>
+
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "libavutil/avstring.h"
+#include "libavformat/internal.h"
+#include "libavutil/internal.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/time.h"
+#include "avdevice.h"
+
+static const int avf_time_base = 1000000;
+
+static const AVRational avf_time_base_q = {
+ .num = 1,
+ .den = avf_time_base
+};
+
+struct AVFPixelFormatSpec {
+ enum AVPixelFormat ff_id;
+ OSType avf_id;
+};
+
+static const struct AVFPixelFormatSpec avf_pixel_formats[] = {
+ { AV_PIX_FMT_MONOBLACK, kCVPixelFormatType_1Monochrome },
+ { AV_PIX_FMT_RGB555BE, kCVPixelFormatType_16BE555 },
+ { AV_PIX_FMT_RGB555LE, kCVPixelFormatType_16LE555 },
+ { AV_PIX_FMT_RGB565BE, kCVPixelFormatType_16BE565 },
+ { AV_PIX_FMT_RGB565LE, kCVPixelFormatType_16LE565 },
+ { AV_PIX_FMT_RGB24, kCVPixelFormatType_24RGB },
+ { AV_PIX_FMT_BGR24, kCVPixelFormatType_24BGR },
+ { AV_PIX_FMT_0RGB, kCVPixelFormatType_32ARGB },
+ { AV_PIX_FMT_BGR0, kCVPixelFormatType_32BGRA },
+ { AV_PIX_FMT_0BGR, kCVPixelFormatType_32ABGR },
+ { AV_PIX_FMT_RGB0, kCVPixelFormatType_32RGBA },
+ { AV_PIX_FMT_BGR48BE, kCVPixelFormatType_48RGB },
+ { AV_PIX_FMT_UYVY422, kCVPixelFormatType_422YpCbCr8 },
+ { AV_PIX_FMT_YUVA444P, kCVPixelFormatType_4444YpCbCrA8R },
+ { AV_PIX_FMT_YUVA444P16LE, kCVPixelFormatType_4444AYpCbCr16 },
+ { AV_PIX_FMT_YUV444P, kCVPixelFormatType_444YpCbCr8 },
+ { AV_PIX_FMT_YUV422P16, kCVPixelFormatType_422YpCbCr16 },
+ { AV_PIX_FMT_YUV422P10, kCVPixelFormatType_422YpCbCr10 },
+ { AV_PIX_FMT_YUV444P10, kCVPixelFormatType_444YpCbCr10 },
+ { AV_PIX_FMT_YUV420P, kCVPixelFormatType_420YpCbCr8Planar },
+ { AV_PIX_FMT_NV12, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange },
+ { AV_PIX_FMT_YUYV422, kCVPixelFormatType_422YpCbCr8_yuvs },
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+ { AV_PIX_FMT_GRAY8, kCVPixelFormatType_OneComponent8 },
+#endif
+ { AV_PIX_FMT_NONE, 0 }
+};
+
+typedef struct
+{
+ AVClass* class;
+
+ int frames_captured;
+ int audio_frames_captured;
+ int64_t first_pts;
+ int64_t first_audio_pts;
+ pthread_mutex_t frame_lock;
+ pthread_cond_t frame_wait_cond;
+ id avf_delegate;
+ id avf_audio_delegate;
+
+ AVRational framerate;
+ int width, height;
+
+ int capture_cursor;
+ int capture_mouse_clicks;
+
+ int list_devices;
+ int video_device_index;
+ int video_stream_index;
+ int audio_device_index;
+ int audio_stream_index;
+
+ char *video_filename;
+ char *audio_filename;
+
+ int num_video_devices;
+
+ int audio_channels;
+ int audio_bits_per_sample;
+ int audio_float;
+ int audio_be;
+ int audio_signed_integer;
+ int audio_packed;
+ int audio_non_interleaved;
+
+ int32_t *audio_buffer;
+ int audio_buffer_size;
+
+ enum AVPixelFormat pixel_format;
+
+ AVCaptureSession *capture_session;
+ AVCaptureVideoDataOutput *video_output;
+ AVCaptureAudioDataOutput *audio_output;
+ CMSampleBufferRef current_frame;
+ CMSampleBufferRef current_audio_frame;
+} AVFContext;
+
+static void lock_frames(AVFContext* ctx)
+{
+ pthread_mutex_lock(&ctx->frame_lock);
+}
+
+static void unlock_frames(AVFContext* ctx)
+{
+ pthread_mutex_unlock(&ctx->frame_lock);
+}
+
+/** FrameReciever class - delegate for AVCaptureSession
+ */
+@interface AVFFrameReceiver : NSObject
+{
+ AVFContext* _context;
+}
+
+- (id)initWithContext:(AVFContext*)context;
+
+- (void) captureOutput:(AVCaptureOutput *)captureOutput
+ didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
+ fromConnection:(AVCaptureConnection *)connection;
+
+@end
+
+@implementation AVFFrameReceiver
+
+- (id)initWithContext:(AVFContext*)context
+{
+ if (self = [super init]) {
+ _context = context;
+ }
+ return self;
+}
+
+- (void) captureOutput:(AVCaptureOutput *)captureOutput
+ didOutputSampleBuffer:(CMSampleBufferRef)videoFrame
+ fromConnection:(AVCaptureConnection *)connection
+{
+ lock_frames(_context);
+
+ if (_context->current_frame != nil) {
+ CFRelease(_context->current_frame);
+ }
+
+ _context->current_frame = (CMSampleBufferRef)CFRetain(videoFrame);
+
+ pthread_cond_signal(&_context->frame_wait_cond);
+
+ unlock_frames(_context);
+
+ ++_context->frames_captured;
+}
+
+@end
+
+/** AudioReciever class - delegate for AVCaptureSession
+ */
+@interface AVFAudioReceiver : NSObject
+{
+ AVFContext* _context;
+}
+
+- (id)initWithContext:(AVFContext*)context;
+
+- (void) captureOutput:(AVCaptureOutput *)captureOutput
+ didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
+ fromConnection:(AVCaptureConnection *)connection;
+
+@end
+
+@implementation AVFAudioReceiver
+
+- (id)initWithContext:(AVFContext*)context
+{
+ if (self = [super init]) {
+ _context = context;
+ }
+ return self;
+}
+
+- (void) captureOutput:(AVCaptureOutput *)captureOutput
+ didOutputSampleBuffer:(CMSampleBufferRef)audioFrame
+ fromConnection:(AVCaptureConnection *)connection
+{
+ lock_frames(_context);
+
+ if (_context->current_audio_frame != nil) {
+ CFRelease(_context->current_audio_frame);
+ }
+
+ _context->current_audio_frame = (CMSampleBufferRef)CFRetain(audioFrame);
+
+ pthread_cond_signal(&_context->frame_wait_cond);
+
+ unlock_frames(_context);
+
+ ++_context->audio_frames_captured;
+}
+
+@end
+
+static void destroy_context(AVFContext* ctx)
+{
+ [ctx->capture_session stopRunning];
+
+ [ctx->capture_session release];
+ [ctx->video_output release];
+ [ctx->audio_output release];
+ [ctx->avf_delegate release];
+ [ctx->avf_audio_delegate release];
+
+ ctx->capture_session = NULL;
+ ctx->video_output = NULL;
+ ctx->audio_output = NULL;
+ ctx->avf_delegate = NULL;
+ ctx->avf_audio_delegate = NULL;
+
+ av_freep(&ctx->audio_buffer);
+
+ pthread_mutex_destroy(&ctx->frame_lock);
+ pthread_cond_destroy(&ctx->frame_wait_cond);
+
+ if (ctx->current_frame) {
+ CFRelease(ctx->current_frame);
+ }
+}
+
+static void parse_device_name(AVFormatContext *s)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ char *tmp = av_strdup(s->filename);
+ char *save;
+
+ if (tmp[0] != ':') {
+ ctx->video_filename = av_strtok(tmp, ":", &save);
+ ctx->audio_filename = av_strtok(NULL, ":", &save);
+ } else {
+ ctx->audio_filename = av_strtok(tmp, ":", &save);
+ }
+}
+
+/**
+ * Configure the video device.
+ *
+ * Configure the video device using a run-time approach to access properties
+ * since formats, activeFormat are available since iOS >= 7.0 or OSX >= 10.7
+ * and activeVideoMaxFrameDuration is available since i0S >= 7.0 and OSX >= 10.9.
+ *
+ * The NSUndefinedKeyException must be handled by the caller of this function.
+ *
+ */
+static int configure_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+
+ double framerate = av_q2d(ctx->framerate);
+ NSObject *range = nil;
+ NSObject *format = nil;
+ NSObject *selected_range = nil;
+ NSObject *selected_format = nil;
+
+ for (format in [video_device valueForKey:@"formats"]) {
+ CMFormatDescriptionRef formatDescription;
+ CMVideoDimensions dimensions;
+
+ formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)];
+ dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
+
+ if ((ctx->width == 0 && ctx->height == 0) ||
+ (dimensions.width == ctx->width && dimensions.height == ctx->height)) {
+
+ selected_format = format;
+
+ for (range in [format valueForKey:@"videoSupportedFrameRateRanges"]) {
+ double max_framerate;
+
+ [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
+ if (fabs (framerate - max_framerate) < 0.01) {
+ selected_range = range;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!selected_format) {
+ av_log(s, AV_LOG_ERROR, "Selected video size (%dx%d) is not supported by the device\n",
+ ctx->width, ctx->height);
+ goto unsupported_format;
+ }
+
+ if (!selected_range) {
+ av_log(s, AV_LOG_ERROR, "Selected framerate (%f) is not supported by the device\n",
+ framerate);
+ goto unsupported_format;
+ }
+
+ if ([video_device lockForConfiguration:NULL] == YES) {
+ NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"];
+
+ [video_device setValue:selected_format forKey:@"activeFormat"];
+ [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"];
+ [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"];
+ } else {
+ av_log(s, AV_LOG_ERROR, "Could not lock device for configuration");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+
+unsupported_format:
+
+ av_log(s, AV_LOG_ERROR, "Supported modes:\n");
+ for (format in [video_device valueForKey:@"formats"]) {
+ CMFormatDescriptionRef formatDescription;
+ CMVideoDimensions dimensions;
+
+ formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)];
+ dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription);
+
+ for (range in [format valueForKey:@"videoSupportedFrameRateRanges"]) {
+ double min_framerate;
+ double max_framerate;
+
+ [[range valueForKey:@"minFrameRate"] getValue:&min_framerate];
+ [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate];
+ av_log(s, AV_LOG_ERROR, " %dx%d@[%f %f]fps\n",
+ dimensions.width, dimensions.height,
+ min_framerate, max_framerate);
+ }
+ }
+ return AVERROR(EINVAL);
+}
+
+static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ int ret;
+ NSError *error = nil;
+ AVCaptureInput* capture_input = nil;
+ struct AVFPixelFormatSpec pxl_fmt_spec;
+ NSNumber *pixel_format;
+ NSDictionary *capture_dict;
+ dispatch_queue_t queue;
+
+ if (ctx->video_device_index < ctx->num_video_devices) {
+ capture_input = (AVCaptureInput*) [[[AVCaptureDeviceInput alloc] initWithDevice:video_device error:&error] autorelease];
+ } else {
+ capture_input = (AVCaptureInput*) video_device;
+ }
+
+ if (!capture_input) {
+ av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n",
+ [[error localizedDescription] UTF8String]);
+ return 1;
+ }
+
+ if ([ctx->capture_session canAddInput:capture_input]) {
+ [ctx->capture_session addInput:capture_input];
+ } else {
+ av_log(s, AV_LOG_ERROR, "can't add video input to capture session\n");
+ return 1;
+ }
+
+ // Attaching output
+ ctx->video_output = [[AVCaptureVideoDataOutput alloc] init];
+
+ if (!ctx->video_output) {
+ av_log(s, AV_LOG_ERROR, "Failed to init AV video output\n");
+ return 1;
+ }
+
+ // Configure device framerate and video size
+ @try {
+ if ((ret = configure_video_device(s, video_device)) < 0) {
+ return ret;
+ }
+ } @catch (NSException *exception) {
+ if (![[exception name] isEqualToString:NSUndefinedKeyException]) {
+ av_log (s, AV_LOG_ERROR, "An error occurred: %s", [exception.reason UTF8String]);
+ return AVERROR_EXTERNAL;
+ }
+ }
+
+ // select pixel format
+ pxl_fmt_spec.ff_id = AV_PIX_FMT_NONE;
+
+ for (int i = 0; avf_pixel_formats[i].ff_id != AV_PIX_FMT_NONE; i++) {
+ if (ctx->pixel_format == avf_pixel_formats[i].ff_id) {
+ pxl_fmt_spec = avf_pixel_formats[i];
+ break;
+ }
+ }
+
+ // check if selected pixel format is supported by AVFoundation
+ if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) {
+ av_log(s, AV_LOG_ERROR, "Selected pixel format (%s) is not supported by AVFoundation.\n",
+ av_get_pix_fmt_name(pxl_fmt_spec.ff_id));
+ return 1;
+ }
+
+ // check if the pixel format is available for this device
+ if ([[ctx->video_output availableVideoCVPixelFormatTypes] indexOfObject:[NSNumber numberWithInt:pxl_fmt_spec.avf_id]] == NSNotFound) {
+ av_log(s, AV_LOG_ERROR, "Selected pixel format (%s) is not supported by the input device.\n",
+ av_get_pix_fmt_name(pxl_fmt_spec.ff_id));
+
+ pxl_fmt_spec.ff_id = AV_PIX_FMT_NONE;
+
+ av_log(s, AV_LOG_ERROR, "Supported pixel formats:\n");
+ for (NSNumber *pxl_fmt in [ctx->video_output availableVideoCVPixelFormatTypes]) {
+ struct AVFPixelFormatSpec pxl_fmt_dummy;
+ pxl_fmt_dummy.ff_id = AV_PIX_FMT_NONE;
+ for (int i = 0; avf_pixel_formats[i].ff_id != AV_PIX_FMT_NONE; i++) {
+ if ([pxl_fmt intValue] == avf_pixel_formats[i].avf_id) {
+ pxl_fmt_dummy = avf_pixel_formats[i];
+ break;
+ }
+ }
+
+ if (pxl_fmt_dummy.ff_id != AV_PIX_FMT_NONE) {
+ av_log(s, AV_LOG_ERROR, " %s\n", av_get_pix_fmt_name(pxl_fmt_dummy.ff_id));
+
+ // select first supported pixel format instead of user selected (or default) pixel format
+ if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) {
+ pxl_fmt_spec = pxl_fmt_dummy;
+ }
+ }
+ }
+
+ // fail if there is no appropriate pixel format or print a warning about overriding the pixel format
+ if (pxl_fmt_spec.ff_id == AV_PIX_FMT_NONE) {
+ return 1;
+ } else {
+ av_log(s, AV_LOG_WARNING, "Overriding selected pixel format to use %s instead.\n",
+ av_get_pix_fmt_name(pxl_fmt_spec.ff_id));
+ }
+ }
+
+ ctx->pixel_format = pxl_fmt_spec.ff_id;
+ pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id];
+ capture_dict = [NSDictionary dictionaryWithObject:pixel_format
+ forKey:(id)kCVPixelBufferPixelFormatTypeKey];
+
+ [ctx->video_output setVideoSettings:capture_dict];
+ [ctx->video_output setAlwaysDiscardsLateVideoFrames:YES];
+
+ ctx->avf_delegate = [[AVFFrameReceiver alloc] initWithContext:ctx];
+
+ queue = dispatch_queue_create("avf_queue", NULL);
+ [ctx->video_output setSampleBufferDelegate:ctx->avf_delegate queue:queue];
+ dispatch_release(queue);
+
+ if ([ctx->capture_session canAddOutput:ctx->video_output]) {
+ [ctx->capture_session addOutput:ctx->video_output];
+ } else {
+ av_log(s, AV_LOG_ERROR, "can't add video output to capture session\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int add_audio_device(AVFormatContext *s, AVCaptureDevice *audio_device)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ NSError *error = nil;
+ AVCaptureDeviceInput* audio_dev_input = [[[AVCaptureDeviceInput alloc] initWithDevice:audio_device error:&error] autorelease];
+ dispatch_queue_t queue;
+
+ if (!audio_dev_input) {
+ av_log(s, AV_LOG_ERROR, "Failed to create AV capture input device: %s\n",
+ [[error localizedDescription] UTF8String]);
+ return 1;
+ }
+
+ if ([ctx->capture_session canAddInput:audio_dev_input]) {
+ [ctx->capture_session addInput:audio_dev_input];
+ } else {
+ av_log(s, AV_LOG_ERROR, "can't add audio input to capture session\n");
+ return 1;
+ }
+
+ // Attaching output
+ ctx->audio_output = [[AVCaptureAudioDataOutput alloc] init];
+
+ if (!ctx->audio_output) {
+ av_log(s, AV_LOG_ERROR, "Failed to init AV audio output\n");
+ return 1;
+ }
+
+ ctx->avf_audio_delegate = [[AVFAudioReceiver alloc] initWithContext:ctx];
+
+ queue = dispatch_queue_create("avf_audio_queue", NULL);
+ [ctx->audio_output setSampleBufferDelegate:ctx->avf_audio_delegate queue:queue];
+ dispatch_release(queue);
+
+ if ([ctx->capture_session canAddOutput:ctx->audio_output]) {
+ [ctx->capture_session addOutput:ctx->audio_output];
+ } else {
+ av_log(s, AV_LOG_ERROR, "adding audio output to capture session failed\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int get_video_config(AVFormatContext *s)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ CVImageBufferRef image_buffer;
+ CGSize image_buffer_size;
+ AVStream* stream = avformat_new_stream(s, NULL);
+
+ if (!stream) {
+ return 1;
+ }
+
+ // Take stream info from the first frame.
+ while (ctx->frames_captured < 1) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
+ }
+
+ lock_frames(ctx);
+
+ ctx->video_stream_index = stream->index;
+
+ avpriv_set_pts_info(stream, 64, 1, avf_time_base);
+
+ image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame);
+ image_buffer_size = CVImageBufferGetEncodedSize(image_buffer);
+
+ stream->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ stream->codec->width = (int)image_buffer_size.width;
+ stream->codec->height = (int)image_buffer_size.height;
+ stream->codec->pix_fmt = ctx->pixel_format;
+
+ CFRelease(ctx->current_frame);
+ ctx->current_frame = nil;
+
+ unlock_frames(ctx);
+
+ return 0;
+}
+
+static int get_audio_config(AVFormatContext *s)
+{
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ CMFormatDescriptionRef format_desc;
+ AVStream* stream = avformat_new_stream(s, NULL);
+
+ if (!stream) {
+ return 1;
+ }
+
+ // Take stream info from the first frame.
+ while (ctx->audio_frames_captured < 1) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
+ }
+
+ lock_frames(ctx);
+
+ ctx->audio_stream_index = stream->index;
+
+ avpriv_set_pts_info(stream, 64, 1, avf_time_base);
+
+ format_desc = CMSampleBufferGetFormatDescription(ctx->current_audio_frame);
+ const AudioStreamBasicDescription *basic_desc = CMAudioFormatDescriptionGetStreamBasicDescription(format_desc);
+
+ if (!basic_desc) {
+ av_log(s, AV_LOG_ERROR, "audio format not available\n");
+ return 1;
+ }
+
+ stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ stream->codec->sample_rate = basic_desc->mSampleRate;
+ stream->codec->channels = basic_desc->mChannelsPerFrame;
+ stream->codec->channel_layout = av_get_default_channel_layout(stream->codec->channels);
+
+ ctx->audio_channels = basic_desc->mChannelsPerFrame;
+ ctx->audio_bits_per_sample = basic_desc->mBitsPerChannel;
+ ctx->audio_float = basic_desc->mFormatFlags & kAudioFormatFlagIsFloat;
+ ctx->audio_be = basic_desc->mFormatFlags & kAudioFormatFlagIsBigEndian;
+ ctx->audio_signed_integer = basic_desc->mFormatFlags & kAudioFormatFlagIsSignedInteger;
+ ctx->audio_packed = basic_desc->mFormatFlags & kAudioFormatFlagIsPacked;
+ ctx->audio_non_interleaved = basic_desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved;
+
+ if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ ctx->audio_float &&
+ ctx->audio_bits_per_sample == 32 &&
+ ctx->audio_packed) {
+ stream->codec->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_F32BE : AV_CODEC_ID_PCM_F32LE;
+ } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ ctx->audio_signed_integer &&
+ ctx->audio_bits_per_sample == 16 &&
+ ctx->audio_packed) {
+ stream->codec->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S16BE : AV_CODEC_ID_PCM_S16LE;
+ } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ ctx->audio_signed_integer &&
+ ctx->audio_bits_per_sample == 24 &&
+ ctx->audio_packed) {
+ stream->codec->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
+ } else if (basic_desc->mFormatID == kAudioFormatLinearPCM &&
+ ctx->audio_signed_integer &&
+ ctx->audio_bits_per_sample == 32 &&
+ ctx->audio_packed) {
+ stream->codec->codec_id = ctx->audio_be ? AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE;
+ } else {
+ av_log(s, AV_LOG_ERROR, "audio format is not supported\n");
+ return 1;
+ }
+
+ if (ctx->audio_non_interleaved) {
+ CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame);
+ ctx->audio_buffer_size = CMBlockBufferGetDataLength(block_buffer);
+ ctx->audio_buffer = av_malloc(ctx->audio_buffer_size);
+ if (!ctx->audio_buffer) {
+ av_log(s, AV_LOG_ERROR, "error allocating audio buffer\n");
+ return 1;
+ }
+ }
+
+ CFRelease(ctx->current_audio_frame);
+ ctx->current_audio_frame = nil;
+
+ unlock_frames(ctx);
+
+ return 0;
+}
+
+static int avf_read_header(AVFormatContext *s)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ int capture_screen = 0;
+ uint32_t num_screens = 0;
+ AVFContext *ctx = (AVFContext*)s->priv_data;
+ AVCaptureDevice *video_device = nil;
+ AVCaptureDevice *audio_device = nil;
+ // Find capture device
+ NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
+ ctx->num_video_devices = [devices count];
+
+ ctx->first_pts = av_gettime();
+ ctx->first_audio_pts = av_gettime();
+
+ pthread_mutex_init(&ctx->frame_lock, NULL);
+ pthread_cond_init(&ctx->frame_wait_cond, NULL);
+
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ CGGetActiveDisplayList(0, NULL, &num_screens);
+#endif
+
+ // List devices if requested
+ if (ctx->list_devices) {
+ int index = 0;
+ av_log(ctx, AV_LOG_INFO, "AVFoundation video devices:\n");
+ for (AVCaptureDevice *device in devices) {
+ const char *name = [[device localizedName] UTF8String];
+ index = [devices indexOfObject:device];
+ av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+ index++;
+ }
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ if (num_screens > 0) {
+ CGDirectDisplayID screens[num_screens];
+ CGGetActiveDisplayList(num_screens, screens, &num_screens);
+ for (int i = 0; i < num_screens; i++) {
+ av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", index + i, i);
+ }
+ }
+#endif
+
+ av_log(ctx, AV_LOG_INFO, "AVFoundation audio devices:\n");
+ devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
+ for (AVCaptureDevice *device in devices) {
+ const char *name = [[device localizedName] UTF8String];
+ int index = [devices indexOfObject:device];
+ av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+ }
+ goto fail;
+ }
+
+ // parse input filename for video and audio device
+ parse_device_name(s);
+
+ // check for device index given in filename
+ if (ctx->video_device_index == -1 && ctx->video_filename) {
+ sscanf(ctx->video_filename, "%d", &ctx->video_device_index);
+ }
+ if (ctx->audio_device_index == -1 && ctx->audio_filename) {
+ sscanf(ctx->audio_filename, "%d", &ctx->audio_device_index);
+ }
+
+ if (ctx->video_device_index >= 0) {
+ if (ctx->video_device_index < ctx->num_video_devices) {
+ video_device = [devices objectAtIndex:ctx->video_device_index];
+ } else if (ctx->video_device_index < ctx->num_video_devices + num_screens) {
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ CGDirectDisplayID screens[num_screens];
+ CGGetActiveDisplayList(num_screens, screens, &num_screens);
+ AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[ctx->video_device_index - ctx->num_video_devices]] autorelease];
+
+ if (ctx->framerate.num > 0) {
+ capture_screen_input.minFrameDuration = CMTimeMake(ctx->framerate.den, ctx->framerate.num);
+ }
+
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+ if (ctx->capture_cursor) {
+ capture_screen_input.capturesCursor = YES;
+ } else {
+ capture_screen_input.capturesCursor = NO;
+ }
+#endif
+
+ if (ctx->capture_mouse_clicks) {
+ capture_screen_input.capturesMouseClicks = YES;
+ } else {
+ capture_screen_input.capturesMouseClicks = NO;
+ }
+
+ video_device = (AVCaptureDevice*) capture_screen_input;
+ capture_screen = 1;
+#endif
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Invalid device index\n");
+ goto fail;
+ }
+ } else if (ctx->video_filename &&
+ strncmp(ctx->video_filename, "none", 4)) {
+ if (!strncmp(ctx->video_filename, "default", 7)) {
+ video_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
+ } else {
+ // looking for video inputs
+ for (AVCaptureDevice *device in devices) {
+ if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) {
+ video_device = device;
+ break;
+ }
+ }
+
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+ // looking for screen inputs
+ if (!video_device) {
+ int idx;
+ if(sscanf(ctx->video_filename, "Capture screen %d", &idx) && idx < num_screens) {
+ CGDirectDisplayID screens[num_screens];
+ CGGetActiveDisplayList(num_screens, screens, &num_screens);
+ AVCaptureScreenInput* capture_screen_input = [[[AVCaptureScreenInput alloc] initWithDisplayID:screens[idx]] autorelease];
+ video_device = (AVCaptureDevice*) capture_screen_input;
+ ctx->video_device_index = ctx->num_video_devices + idx;
+ capture_screen = 1;
+
+ if (ctx->framerate.num > 0) {
+ capture_screen_input.minFrameDuration = CMTimeMake(ctx->framerate.den, ctx->framerate.num);
+ }
+
+#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
+ if (ctx->capture_cursor) {
+ capture_screen_input.capturesCursor = YES;
+ } else {
+ capture_screen_input.capturesCursor = NO;
+ }
+#endif
+
+ if (ctx->capture_mouse_clicks) {
+ capture_screen_input.capturesMouseClicks = YES;
+ } else {
+ capture_screen_input.capturesMouseClicks = NO;
+ }
+ }
+ }
+#endif
+ }
+
+ if (!video_device) {
+ av_log(ctx, AV_LOG_ERROR, "Video device not found\n");
+ goto fail;
+ }
+ }
+
+ // get audio device
+ if (ctx->audio_device_index >= 0) {
+ NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
+
+ if (ctx->audio_device_index >= [devices count]) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid audio device index\n");
+ goto fail;
+ }
+
+ audio_device = [devices objectAtIndex:ctx->audio_device_index];
+ } else if (ctx->audio_filename &&
+ strncmp(ctx->audio_filename, "none", 4)) {
+ if (!strncmp(ctx->audio_filename, "default", 7)) {
+ audio_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
+ } else {
+ NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
+
+ for (AVCaptureDevice *device in devices) {
+ if (!strncmp(ctx->audio_filename, [[device localizedName] UTF8String], strlen(ctx->audio_filename))) {
+ audio_device = device;
+ break;
+ }
+ }
+ }
+
+ if (!audio_device) {
+ av_log(ctx, AV_LOG_ERROR, "Audio device not found\n");
+ goto fail;
+ }
+ }
+
+ // Video nor Audio capture device not found, looking for AVMediaTypeVideo/Audio
+ if (!video_device && !audio_device) {
+ av_log(s, AV_LOG_ERROR, "No AV capture device found\n");
+ goto fail;
+ }
+
+ if (video_device) {
+ if (ctx->video_device_index < ctx->num_video_devices) {
+ av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device localizedName] UTF8String]);
+ } else {
+ av_log(s, AV_LOG_DEBUG, "'%s' opened\n", [[video_device description] UTF8String]);
+ }
+ }
+ if (audio_device) {
+ av_log(s, AV_LOG_DEBUG, "audio device '%s' opened\n", [[audio_device localizedName] UTF8String]);
+ }
+
+ // Initialize capture session
+ ctx->capture_session = [[AVCaptureSession alloc] init];
+
+ if (video_device && add_video_device(s, video_device)) {
+ goto fail;
+ }
+ if (audio_device && add_audio_device(s, audio_device)) {
+ }
+
+ [ctx->capture_session startRunning];
+
+ /* Unlock device configuration only after the session is started so it
+ * does not reset the capture formats */
+ if (!capture_screen) {
+ [video_device unlockForConfiguration];
+ }
+
+ if (video_device && get_video_config(s)) {
+ goto fail;
+ }
+
+ // set audio stream
+ if (audio_device && get_audio_config(s)) {
+ goto fail;
+ }
+
+ [pool release];
+ return 0;
+
+fail:
+ [pool release];
+ destroy_context(ctx);
+ return AVERROR(EIO);
+}
+
+static int avf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVFContext* ctx = (AVFContext*)s->priv_data;
+
+ do {
+ CVImageBufferRef image_buffer;
+ lock_frames(ctx);
+
+ image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame);
+
+ if (ctx->current_frame != nil) {
+ void *data;
+ if (av_new_packet(pkt, (int)CVPixelBufferGetDataSize(image_buffer)) < 0) {
+ return AVERROR(EIO);
+ }
+
+ CMItemCount count;
+ CMSampleTimingInfo timing_info;
+
+ if (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_frame, 1, &timing_info, &count) == noErr) {
+ AVRational timebase_q = av_make_q(1, timing_info.presentationTimeStamp.timescale);
+ pkt->pts = pkt->dts = av_rescale_q(timing_info.presentationTimeStamp.value, timebase_q, avf_time_base_q);
+ }
+
+ pkt->stream_index = ctx->video_stream_index;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ CVPixelBufferLockBaseAddress(image_buffer, 0);
+
+ data = CVPixelBufferGetBaseAddress(image_buffer);
+ memcpy(pkt->data, data, pkt->size);
+
+ CVPixelBufferUnlockBaseAddress(image_buffer, 0);
+ CFRelease(ctx->current_frame);
+ ctx->current_frame = nil;
+ } else if (ctx->current_audio_frame != nil) {
+ CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame);
+ int block_buffer_size = CMBlockBufferGetDataLength(block_buffer);
+
+ if (!block_buffer || !block_buffer_size) {
+ return AVERROR(EIO);
+ }
+
+ if (ctx->audio_non_interleaved && block_buffer_size > ctx->audio_buffer_size) {
+ return AVERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (av_new_packet(pkt, block_buffer_size) < 0) {
+ return AVERROR(EIO);
+ }
+
+ CMItemCount count;
+ CMSampleTimingInfo timing_info;
+
+ if (CMSampleBufferGetOutputSampleTimingInfoArray(ctx->current_audio_frame, 1, &timing_info, &count) == noErr) {
+ AVRational timebase_q = av_make_q(1, timing_info.presentationTimeStamp.timescale);
+ pkt->pts = pkt->dts = av_rescale_q(timing_info.presentationTimeStamp.value, timebase_q, avf_time_base_q);
+ }
+
+ pkt->stream_index = ctx->audio_stream_index;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ if (ctx->audio_non_interleaved) {
+ int sample, c, shift, num_samples;
+
+ OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, ctx->audio_buffer);
+ if (ret != kCMBlockBufferNoErr) {
+ return AVERROR(EIO);
+ }
+
+ num_samples = pkt->size / (ctx->audio_channels * (ctx->audio_bits_per_sample >> 3));
+
+ // transform decoded frame into output format
+ #define INTERLEAVE_OUTPUT(bps) \
+ { \
+ int##bps##_t **src; \
+ int##bps##_t *dest; \
+ src = av_malloc(ctx->audio_channels * sizeof(int##bps##_t*)); \
+ if (!src) return AVERROR(EIO); \
+ for (c = 0; c < ctx->audio_channels; c++) { \
+ src[c] = ((int##bps##_t*)ctx->audio_buffer) + c * num_samples; \
+ } \
+ dest = (int##bps##_t*)pkt->data; \
+ shift = bps - ctx->audio_bits_per_sample; \
+ for (sample = 0; sample < num_samples; sample++) \
+ for (c = 0; c < ctx->audio_channels; c++) \
+ *dest++ = src[c][sample] << shift; \
+ av_freep(&src); \
+ }
+
+ if (ctx->audio_bits_per_sample <= 16) {
+ INTERLEAVE_OUTPUT(16)
+ } else {
+ INTERLEAVE_OUTPUT(32)
+ }
+ } else {
+ OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, pkt->data);
+ if (ret != kCMBlockBufferNoErr) {
+ return AVERROR(EIO);
+ }
+ }
+
+ CFRelease(ctx->current_audio_frame);
+ ctx->current_audio_frame = nil;
+ } else {
+ pkt->data = NULL;
+ pthread_cond_wait(&ctx->frame_wait_cond, &ctx->frame_lock);
+ }
+
+ unlock_frames(ctx);
+ } while (!pkt->data);
+
+ return 0;
+}
+
+static int avf_close(AVFormatContext *s)
+{
+ AVFContext* ctx = (AVFContext*)s->priv_data;
+ destroy_context(ctx);
+ return 0;
+}
+
+static const AVOption options[] = {
+ { "list_devices", "list available devices", offsetof(AVFContext, list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ { "video_device_index", "select video device by index for devices with same name (starts at 0)", offsetof(AVFContext, video_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { "audio_device_index", "select audio device by index for devices with same name (starts at 0)", offsetof(AVFContext, audio_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { "pixel_format", "set pixel format", offsetof(AVFContext, pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
+ { "framerate", "set frame rate", offsetof(AVFContext, framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { "video_size", "set video size", offsetof(AVFContext, width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { "capture_cursor", "capture the screen cursor", offsetof(AVFContext, capture_cursor), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+ { "capture_mouse_clicks", "capture the screen mouse clicks", offsetof(AVFContext, capture_mouse_clicks), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+
+ { NULL },
+};
+
+static const AVClass avf_class = {
+ .class_name = "AVFoundation input device",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_avfoundation_demuxer = {
+ .name = "avfoundation",
+ .long_name = NULL_IF_CONFIG_SMALL("AVFoundation input device"),
+ .priv_data_size = sizeof(AVFContext),
+ .read_header = avf_read_header,
+ .read_packet = avf_read_packet,
+ .read_close = avf_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &avf_class,
+};
diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c
index 8042c38011..c8a8953267 100644
--- a/libavdevice/bktr.c
+++ b/libavdevice/bktr.c
@@ -3,28 +3,27 @@
* Copyright (c) 2002 Steve O'Hara-Smith
* based on
* Linux video grab interface
- * Copyright (c) 2000,2001 Gerard Lantau
+ * Copyright (c) 2000, 2001 Fabrice Bellard
* and
* simple_grab.c Copyright (c) 1999 Roger Hardiman
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "libavutil/internal.h"
#include "libavutil/log.h"
@@ -50,6 +49,7 @@
#include <sys/time.h>
#include <signal.h>
#include <stdint.h>
+#include "avdevice.h"
typedef struct VideoData {
AVClass *class;
@@ -58,7 +58,6 @@ typedef struct VideoData {
int width, height;
uint64_t per_frame;
int standard;
- char *video_size; /**< String describing video size, set by a private option. */
char *framerate; /**< Set by a private option. */
} VideoData;
@@ -81,7 +80,7 @@ typedef struct VideoData {
#define VIDEO_FORMAT NTSC
#endif
-static int bktr_dev[] = { METEOR_DEV0, METEOR_DEV1, METEOR_DEV2,
+static const int bktr_dev[] = { METEOR_DEV0, METEOR_DEV1, METEOR_DEV2,
METEOR_DEV3, METEOR_DEV_SVIDEO };
uint8_t *video_buf;
@@ -104,7 +103,7 @@ static av_cold int bktr_init(const char *video_device, int width, int height,
long ioctl_frequency;
char *arg;
int c;
- struct sigaction act = { 0 }, old;
+ struct sigaction act = { {0} }, old;
int ret;
char errbuf[128];
@@ -260,15 +259,9 @@ static int grab_read_header(AVFormatContext *s1)
{
VideoData *s = s1->priv_data;
AVStream *st;
- int width, height;
AVRational framerate;
int ret = 0;
- if ((ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log(s1, AV_LOG_ERROR, "Could not parse video size '%s'.\n", s->video_size);
- goto out;
- }
-
if (!s->framerate)
switch (s->standard) {
case PAL: s->framerate = av_strdup("pal"); break;
@@ -291,20 +284,18 @@ static int grab_read_header(AVFormatContext *s1)
}
avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in use */
- s->width = width;
- s->height = height;
s->per_frame = ((uint64_t)1000000 * framerate.den) / framerate.num;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->pix_fmt = AV_PIX_FMT_YUV420P;
st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
- st->codec->width = width;
- st->codec->height = height;
+ st->codec->width = s->width;
+ st->codec->height = s->height;
st->codec->time_base.den = framerate.num;
st->codec->time_base.num = framerate.den;
- if (bktr_init(s1->filename, width, height, s->standard,
+ if (bktr_init(s1->filename, s->width, s->height, s->standard,
&s->video_fd, &s->tuner_fd, -1, 0.0) < 0) {
ret = AVERROR(EIO);
goto out;
@@ -345,7 +336,7 @@ static const AVOption options[] = {
{ "PALN", "", 0, AV_OPT_TYPE_CONST, {.i64 = PALN}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" },
{ "PALM", "", 0, AV_OPT_TYPE_CONST, {.i64 = PALM}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" },
{ "NTSCJ", "", 0, AV_OPT_TYPE_CONST, {.i64 = NTSCJ}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" },
- { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = "vga"}, 0, 0, DEC },
+ { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "vga"}, 0, 0, DEC },
{ "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
{ NULL },
};
@@ -355,6 +346,7 @@ static const AVClass bktr_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
AVInputFormat ff_bktr_demuxer = {
diff --git a/libavdevice/caca.c b/libavdevice/caca.c
new file mode 100644
index 0000000000..ff54940d31
--- /dev/null
+++ b/libavdevice/caca.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2012 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
+ */
+
+#include <caca.h>
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avdevice.h"
+
+typedef struct CACAContext {
+ AVClass *class;
+ AVFormatContext *ctx;
+ char *window_title;
+ int window_width, window_height;
+
+ caca_canvas_t *canvas;
+ caca_display_t *display;
+ caca_dither_t *dither;
+
+ char *algorithm, *antialias;
+ char *charset, *color;
+ char *driver;
+
+ char *list_dither;
+ int list_drivers;
+} CACAContext;
+
+static int caca_write_trailer(AVFormatContext *s)
+{
+ CACAContext *c = s->priv_data;
+
+ av_freep(&c->window_title);
+
+ if (c->display) {
+ caca_free_display(c->display);
+ c->display = NULL;
+ }
+ if (c->dither) {
+ caca_free_dither(c->dither);
+ c->dither = NULL;
+ }
+ if (c->canvas) {
+ caca_free_canvas(c->canvas);
+ c->canvas = NULL;
+ }
+ return 0;
+}
+
+static void list_drivers(CACAContext *c)
+{
+ const char *const *drivers = caca_get_display_driver_list();
+ int i;
+
+ av_log(c->ctx, AV_LOG_INFO, "Available drivers:\n");
+ for (i = 0; drivers[i]; i += 2)
+ av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", drivers[i], drivers[i + 1]);
+}
+
+#define DEFINE_LIST_DITHER(thing, thing_str) \
+static void list_dither_## thing(CACAContext *c) \
+{ \
+ const char *const *thing = caca_get_dither_## thing ##_list(c->dither); \
+ int i; \
+ \
+ av_log(c->ctx, AV_LOG_INFO, "Available %s:\n", thing_str); \
+ for (i = 0; thing[i]; i += 2) \
+ av_log(c->ctx, AV_LOG_INFO, "%s : %s\n", thing[i], thing[i + 1]); \
+}
+
+DEFINE_LIST_DITHER(color, "colors");
+DEFINE_LIST_DITHER(charset, "charsets");
+DEFINE_LIST_DITHER(algorithm, "algorithms");
+DEFINE_LIST_DITHER(antialias, "antialias");
+
+static int caca_write_header(AVFormatContext *s)
+{
+ CACAContext *c = s->priv_data;
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+ int ret, bpp;
+
+ c->ctx = s;
+ if (c->list_drivers) {
+ list_drivers(c);
+ return AVERROR_EXIT;
+ }
+ if (c->list_dither) {
+ if (!strcmp(c->list_dither, "colors")) {
+ list_dither_color(c);
+ } else if (!strcmp(c->list_dither, "charsets")) {
+ list_dither_charset(c);
+ } else if (!strcmp(c->list_dither, "algorithms")) {
+ list_dither_algorithm(c);
+ } else if (!strcmp(c->list_dither, "antialiases")) {
+ list_dither_antialias(c);
+ } else {
+ av_log(s, AV_LOG_ERROR,
+ "Invalid argument '%s', for 'list_dither' option\n"
+ "Argument must be one of 'algorithms, 'antialiases', 'charsets', 'colors'\n",
+ c->list_dither);
+ return AVERROR(EINVAL);
+ }
+ return AVERROR_EXIT;
+ }
+
+ if ( s->nb_streams > 1
+ || encctx->codec_type != AVMEDIA_TYPE_VIDEO
+ || encctx->codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (encctx->pix_fmt != AV_PIX_FMT_RGB24) {
+ av_log(s, AV_LOG_ERROR,
+ "Unsupported pixel format '%s', choose rgb24\n",
+ av_get_pix_fmt_name(encctx->pix_fmt));
+ return AVERROR(EINVAL);
+ }
+
+ c->canvas = caca_create_canvas(c->window_width, c->window_height);
+ if (!c->canvas) {
+ ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR, "Failed to create canvas\n");
+ goto fail;
+ }
+
+ bpp = av_get_bits_per_pixel(av_pix_fmt_desc_get(encctx->pix_fmt));
+ c->dither = caca_create_dither(bpp, encctx->width, encctx->height,
+ bpp / 8 * encctx->width,
+ 0x0000ff, 0x00ff00, 0xff0000, 0);
+ if (!c->dither) {
+ ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR, "Failed to create dither\n");
+ goto fail;
+ }
+
+#define CHECK_DITHER_OPT(opt) \
+ if (caca_set_dither_##opt(c->dither, c->opt) < 0) { \
+ ret = AVERROR(errno); \
+ av_log(s, AV_LOG_ERROR, "Failed to set value '%s' for option '%s'\n", \
+ c->opt, #opt); \
+ goto fail; \
+ }
+ CHECK_DITHER_OPT(algorithm);
+ CHECK_DITHER_OPT(antialias);
+ CHECK_DITHER_OPT(charset);
+ CHECK_DITHER_OPT(color);
+
+ c->display = caca_create_display_with_driver(c->canvas, c->driver);
+ if (!c->display) {
+ ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR, "Failed to create display\n");
+ list_drivers(c);
+ goto fail;
+ }
+
+ if (!c->window_width || !c->window_height) {
+ c->window_width = caca_get_canvas_width(c->canvas);
+ c->window_height = caca_get_canvas_height(c->canvas);
+ }
+
+ if (!c->window_title)
+ c->window_title = av_strdup(s->filename);
+ caca_set_display_title(c->display, c->window_title);
+ caca_set_display_time(c->display, av_rescale_q(1, st->codec->time_base, AV_TIME_BASE_Q));
+
+ return 0;
+
+fail:
+ caca_write_trailer(s);
+ return ret;
+}
+
+static int caca_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ CACAContext *c = s->priv_data;
+
+ caca_dither_bitmap(c->canvas, 0, 0, c->window_width, c->window_height, c->dither, pkt->data);
+ caca_refresh_display(c->display);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(CACAContext,x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+ { "window_size", "set window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL }, 0, 0, ENC},
+ { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, ENC },
+ { "driver", "set display driver", OFFSET(driver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, ENC },
+ { "algorithm", "set dithering algorithm", OFFSET(algorithm), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC },
+ { "antialias", "set antialias method", OFFSET(antialias), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC },
+ { "charset", "set charset used to render output", OFFSET(charset), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC },
+ { "color", "set color used to render output", OFFSET(color), AV_OPT_TYPE_STRING, {.str = "default" }, 0, 0, ENC },
+ { "list_drivers", "list available drivers", OFFSET(list_drivers), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, ENC, "list_drivers" },
+ { "true", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, ENC, "list_drivers" },
+ { "false", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, ENC, "list_drivers" },
+ { "list_dither", "list available dither options", OFFSET(list_dither), AV_OPT_TYPE_STRING, {.dbl=0}, 0, 1, ENC, "list_dither" },
+ { "algorithms", NULL, 0, AV_OPT_TYPE_CONST, {.str = "algorithms"}, 0, 0, ENC, "list_dither" },
+ { "antialiases", NULL, 0, AV_OPT_TYPE_CONST, {.str = "antialiases"},0, 0, ENC, "list_dither" },
+ { "charsets", NULL, 0, AV_OPT_TYPE_CONST, {.str = "charsets"}, 0, 0, ENC, "list_dither" },
+ { "colors", NULL, 0, AV_OPT_TYPE_CONST, {.str = "colors"}, 0, 0, ENC, "list_dither" },
+ { NULL },
+};
+
+static const AVClass caca_class = {
+ .class_name = "caca_outdev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_caca_muxer = {
+ .name = "caca",
+ .long_name = NULL_IF_CONFIG_SMALL("caca (color ASCII art) output device"),
+ .priv_data_size = sizeof(CACAContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = caca_write_header,
+ .write_packet = caca_write_packet,
+ .write_trailer = caca_write_trailer,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &caca_class,
+};
diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp
new file mode 100644
index 0000000000..ac7964cd17
--- /dev/null
+++ b/libavdevice/decklink_common.cpp
@@ -0,0 +1,241 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2013-2014 Ramiro Polla, Luca Barbato, Deti Fliegl
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <DeckLinkAPI.h>
+#ifdef _WIN32
+#include <DeckLinkAPI_i.c>
+#else
+#include <DeckLinkAPIDispatch.cpp>
+#endif
+
+#include <pthread.h>
+#include <semaphore.h>
+
+extern "C" {
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavutil/imgutils.h"
+}
+
+#include "decklink_common.h"
+
+#ifdef _WIN32
+IDeckLinkIterator *CreateDeckLinkIteratorInstance(void)
+{
+ IDeckLinkIterator *iter;
+
+ if (CoInitialize(NULL) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n");
+ return NULL;
+ }
+
+ if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
+ IID_IDeckLinkIterator, (void**) &iter) != S_OK) {
+ av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n");
+ return NULL;
+ }
+
+ return iter;
+}
+#endif
+
+#ifdef _WIN32
+static char *dup_wchar_to_utf8(wchar_t *w)
+{
+ char *s = NULL;
+ int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
+ s = (char *) av_malloc(l);
+ if (s)
+ WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
+ return s;
+}
+#define DECKLINK_STR OLECHAR *
+#define DECKLINK_STRDUP dup_wchar_to_utf8
+#define DECKLINK_FREE(s) SysFreeString(s)
+#elif defined(__APPLE__)
+static char *dup_cfstring_to_utf8(CFStringRef w)
+{
+ char s[256];
+ CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
+ return av_strdup(s);
+}
+#define DECKLINK_STR const __CFString *
+#define DECKLINK_STRDUP dup_cfstring_to_utf8
+#define DECKLINK_FREE(s) free((void *) s)
+#else
+#define DECKLINK_STR const char *
+#define DECKLINK_STRDUP av_strdup
+/* free() is needed for a string returned by the DeckLink SDL. */
+#define DECKLINK_FREE(s) free((void *) s)
+#endif
+
+HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
+{
+ DECKLINK_STR tmpDisplayName;
+ HRESULT hr = This->GetDisplayName(&tmpDisplayName);
+ if (hr != S_OK)
+ return hr;
+ *displayName = DECKLINK_STRDUP(tmpDisplayName);
+ DECKLINK_FREE(tmpDisplayName);
+ return hr;
+}
+
+int ff_decklink_set_format(AVFormatContext *avctx,
+ int width, int height,
+ int tb_num, int tb_den,
+ decklink_direction_t direction, int num)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
+ BMDDisplayModeSupport support;
+ IDeckLinkDisplayModeIterator *itermode;
+ IDeckLinkDisplayMode *mode;
+ int i = 1;
+ HRESULT res;
+
+ if (direction == DIRECTION_IN) {
+ res = ctx->dli->GetDisplayModeIterator (&itermode);
+ } else {
+ res = ctx->dlo->GetDisplayModeIterator (&itermode);
+ }
+
+ if (res!= S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
+ return AVERROR(EIO);
+ }
+
+
+ if (tb_num == 1) {
+ tb_num *= 1000;
+ tb_den *= 1000;
+ }
+ ctx->bmd_mode = bmdModeUnknown;
+ while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
+ BMDTimeValue bmd_tb_num, bmd_tb_den;
+ int bmd_width = mode->GetWidth();
+ int bmd_height = mode->GetHeight();
+
+ mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
+
+ if ((bmd_width == width && bmd_height == height &&
+ bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) {
+ ctx->bmd_mode = mode->GetDisplayMode();
+ ctx->bmd_width = bmd_width;
+ ctx->bmd_height = bmd_height;
+ ctx->bmd_tb_den = bmd_tb_den;
+ ctx->bmd_tb_num = bmd_tb_num;
+ ctx->bmd_field_dominance = mode->GetFieldDominance();
+ av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n",
+ bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num,
+ (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":"");
+ }
+
+ mode->Release();
+ i++;
+ }
+
+ itermode->Release();
+
+ if (ctx->bmd_mode == bmdModeUnknown)
+ return -1;
+ if (direction == DIRECTION_IN) {
+ if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
+ bmdVideoOutputFlagDefault,
+ &support, NULL) != S_OK)
+ return -1;
+ } else {
+ if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
+ bmdVideoOutputFlagDefault,
+ &support, NULL) != S_OK)
+ return -1;
+ }
+ if (support == bmdDisplayModeSupported)
+ return 0;
+
+ return -1;
+}
+
+int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) {
+ return ff_decklink_set_format(avctx, 0, 0, 0, 0, direction, num);
+}
+
+int ff_decklink_list_devices(AVFormatContext *avctx)
+{
+ IDeckLink *dl = NULL;
+ IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
+ if (!iter) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
+ return AVERROR(EIO);
+ }
+ av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
+ while (iter->Next(&dl) == S_OK) {
+ const char *displayName;
+ ff_decklink_get_display_name(dl, &displayName);
+ av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
+ av_free((void *) displayName);
+ dl->Release();
+ }
+ iter->Release();
+ return 0;
+}
+
+int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
+ IDeckLinkDisplayModeIterator *itermode;
+ IDeckLinkDisplayMode *mode;
+ int i=0;
+ HRESULT res;
+
+ if (direction == DIRECTION_IN) {
+ res = ctx->dli->GetDisplayModeIterator (&itermode);
+ } else {
+ res = ctx->dlo->GetDisplayModeIterator (&itermode);
+ }
+
+ if (res!= S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
+ return AVERROR(EIO);
+ }
+
+ av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n",
+ avctx->filename);
+ while (itermode->Next(&mode) == S_OK) {
+ BMDTimeValue tb_num, tb_den;
+ mode->GetFrameRate(&tb_num, &tb_den);
+ av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps",
+ ++i,mode->GetWidth(), mode->GetHeight(),
+ (int) tb_den, (int) tb_num);
+ switch (mode->GetFieldDominance()) {
+ case bmdLowerFieldFirst:
+ av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break;
+ case bmdUpperFieldFirst:
+ av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
+ }
+ av_log(avctx, AV_LOG_INFO, "\n");
+ mode->Release();
+ }
+
+ itermode->Release();
+
+ return 0;
+}
diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
new file mode 100644
index 0000000000..96912a7c2d
--- /dev/null
+++ b/libavdevice/decklink_common.h
@@ -0,0 +1,97 @@
+/*
+ * Blackmagic DeckLink common code
+ * Copyright (c) 2013-2014 Ramiro Polla, Luca Barbato, Deti Fliegl
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "decklink_common_c.h"
+
+class decklink_output_callback;
+class decklink_input_callback;
+
+typedef struct AVPacketQueue {
+ AVPacketList *first_pkt, *last_pkt;
+ int nb_packets;
+ unsigned long long size;
+ int abort_request;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ AVFormatContext *avctx;
+} AVPacketQueue;
+
+struct decklink_ctx {
+ /* DeckLink SDK interfaces */
+ IDeckLink *dl;
+ IDeckLinkOutput *dlo;
+ IDeckLinkInput *dli;
+ decklink_output_callback *output_callback;
+ decklink_input_callback *input_callback;
+
+ /* DeckLink mode information */
+ BMDTimeValue bmd_tb_den;
+ BMDTimeValue bmd_tb_num;
+ BMDDisplayMode bmd_mode;
+ int bmd_width;
+ int bmd_height;
+ int bmd_field_dominance;
+
+ /* Capture buffer queue */
+ AVPacketQueue queue;
+
+ /* Streams present */
+ int audio;
+ int video;
+
+ /* Status */
+ int playback_started;
+ int capture_started;
+ int64_t last_pts;
+ unsigned long frameCount;
+ unsigned int dropped;
+ AVStream *audio_st;
+ AVStream *video_st;
+
+ /* Options */
+ int list_devices;
+ int list_formats;
+ double preroll;
+
+ int frames_preroll;
+ int frames_buffer;
+
+ sem_t semaphore;
+
+ int channels;
+};
+
+typedef enum { DIRECTION_IN, DIRECTION_OUT} decklink_direction_t;
+
+#ifdef _WIN32
+typedef unsigned long buffercount_type;
+IDeckLinkIterator *CreateDeckLinkIteratorInstance(void);
+#else
+typedef uint32_t buffercount_type;
+#endif
+
+
+HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName);
+int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, decklink_direction_t direction = DIRECTION_OUT, int num = 0);
+int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num);
+int ff_decklink_list_devices(AVFormatContext *avctx);
+int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT);
+
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
new file mode 100644
index 0000000000..fb2b788628
--- /dev/null
+++ b/libavdevice/decklink_common_c.h
@@ -0,0 +1,33 @@
+/*
+ * Blackmagic DeckLink common code
+ * Copyright (c) 2013-2014 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
+ */
+
+struct decklink_cctx {
+ const AVClass *cclass;
+
+ void *ctx;
+
+ /* Options */
+ int list_devices;
+ int list_formats;
+ double preroll;
+ int v210;
+};
+
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
new file mode 100644
index 0000000000..747f47e582
--- /dev/null
+++ b/libavdevice/decklink_dec.cpp
@@ -0,0 +1,541 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2013-2014 Luca Barbato, Deti Fliegl
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <DeckLinkAPI.h>
+
+#include <pthread.h>
+#include <semaphore.h>
+
+extern "C" {
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavutil/imgutils.h"
+}
+
+#include "decklink_common.h"
+#include "decklink_dec.h"
+
+static void avpacket_queue_init(AVFormatContext *avctx, AVPacketQueue *q)
+{
+ memset(q, 0, sizeof(AVPacketQueue));
+ pthread_mutex_init(&q->mutex, NULL);
+ pthread_cond_init(&q->cond, NULL);
+ q->avctx = avctx;
+}
+
+static void avpacket_queue_flush(AVPacketQueue *q)
+{
+ AVPacketList *pkt, *pkt1;
+
+ pthread_mutex_lock(&q->mutex);
+ for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
+ pkt1 = pkt->next;
+ av_free_packet(&pkt->pkt);
+ av_freep(&pkt);
+ }
+ q->last_pkt = NULL;
+ q->first_pkt = NULL;
+ q->nb_packets = 0;
+ q->size = 0;
+ pthread_mutex_unlock(&q->mutex);
+}
+
+static void avpacket_queue_end(AVPacketQueue *q)
+{
+ avpacket_queue_flush(q);
+ pthread_mutex_destroy(&q->mutex);
+ pthread_cond_destroy(&q->cond);
+}
+
+static unsigned long long avpacket_queue_size(AVPacketQueue *q)
+{
+ unsigned long long size;
+ pthread_mutex_lock(&q->mutex);
+ size = q->size;
+ pthread_mutex_unlock(&q->mutex);
+ return size;
+}
+
+static int avpacket_queue_put(AVPacketQueue *q, AVPacket *pkt)
+{
+ AVPacketList *pkt1;
+
+ // Drop Packet if queue size is > 1GB
+ if (avpacket_queue_size(q) > 1024 * 1024 * 1024 ) {
+ av_log(q->avctx, AV_LOG_WARNING, "Decklink input buffer overrun!\n");
+ return -1;
+ }
+ /* duplicate the packet */
+ if (av_dup_packet(pkt) < 0) {
+ return -1;
+ }
+
+ pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));
+ if (!pkt1) {
+ return -1;
+ }
+ pkt1->pkt = *pkt;
+ pkt1->next = NULL;
+
+ pthread_mutex_lock(&q->mutex);
+
+ if (!q->last_pkt) {
+ q->first_pkt = pkt1;
+ } else {
+ q->last_pkt->next = pkt1;
+ }
+
+ q->last_pkt = pkt1;
+ q->nb_packets++;
+ q->size += pkt1->pkt.size + sizeof(*pkt1);
+
+ pthread_cond_signal(&q->cond);
+
+ pthread_mutex_unlock(&q->mutex);
+ return 0;
+}
+
+static int avpacket_queue_get(AVPacketQueue *q, AVPacket *pkt, int block)
+{
+ AVPacketList *pkt1;
+ int ret;
+
+ pthread_mutex_lock(&q->mutex);
+
+ for (;; ) {
+ pkt1 = q->first_pkt;
+ if (pkt1) {
+ q->first_pkt = pkt1->next;
+ if (!q->first_pkt) {
+ q->last_pkt = NULL;
+ }
+ q->nb_packets--;
+ q->size -= pkt1->pkt.size + sizeof(*pkt1);
+ *pkt = pkt1->pkt;
+ av_free(pkt1);
+ ret = 1;
+ break;
+ } else if (!block) {
+ ret = 0;
+ break;
+ } else {
+ pthread_cond_wait(&q->cond, &q->mutex);
+ }
+ }
+ pthread_mutex_unlock(&q->mutex);
+ return ret;
+}
+
+class decklink_input_callback : public IDeckLinkInputCallback
+{
+public:
+ decklink_input_callback(AVFormatContext *_avctx);
+ ~decklink_input_callback();
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags);
+ virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*);
+
+private:
+ ULONG m_refCount;
+ pthread_mutex_t m_mutex;
+ AVFormatContext *avctx;
+ decklink_ctx *ctx;
+ int no_video;
+ int64_t initial_video_pts;
+ int64_t initial_audio_pts;
+};
+
+decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : m_refCount(0)
+{
+ avctx = _avctx;
+ decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ ctx = (struct decklink_ctx *) cctx->ctx;
+ initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE;
+ pthread_mutex_init(&m_mutex, NULL);
+}
+
+decklink_input_callback::~decklink_input_callback()
+{
+ pthread_mutex_destroy(&m_mutex);
+}
+
+ULONG decklink_input_callback::AddRef(void)
+{
+ pthread_mutex_lock(&m_mutex);
+ m_refCount++;
+ pthread_mutex_unlock(&m_mutex);
+
+ return (ULONG)m_refCount;
+}
+
+ULONG decklink_input_callback::Release(void)
+{
+ pthread_mutex_lock(&m_mutex);
+ m_refCount--;
+ pthread_mutex_unlock(&m_mutex);
+
+ if (m_refCount == 0) {
+ delete this;
+ return 0;
+ }
+
+ return (ULONG)m_refCount;
+}
+
+HRESULT decklink_input_callback::VideoInputFrameArrived(
+ IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame)
+{
+ void *frameBytes;
+ void *audioFrameBytes;
+ BMDTimeValue frameTime;
+ BMDTimeValue frameDuration;
+
+ ctx->frameCount++;
+
+ // Handle Video Frame
+ if (videoFrame) {
+ AVPacket pkt;
+ AVCodecContext *c;
+ av_init_packet(&pkt);
+ c = ctx->video_st->codec;
+ if (ctx->frameCount % 25 == 0) {
+ unsigned long long qsize = avpacket_queue_size(&ctx->queue);
+ av_log(avctx, AV_LOG_DEBUG,
+ "Frame received (#%lu) - Valid (%liB) - QSize %fMB\n",
+ ctx->frameCount,
+ videoFrame->GetRowBytes() * videoFrame->GetHeight(),
+ (double)qsize / 1024 / 1024);
+ }
+
+ videoFrame->GetBytes(&frameBytes);
+ videoFrame->GetStreamTime(&frameTime, &frameDuration,
+ ctx->video_st->time_base.den);
+
+ if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {
+ if (videoFrame->GetPixelFormat() == bmdFormat8BitYUV) {
+ unsigned bars[8] = {
+ 0xEA80EA80, 0xD292D210, 0xA910A9A5, 0x90229035,
+ 0x6ADD6ACA, 0x51EF515A, 0x286D28EF, 0x10801080 };
+ int width = videoFrame->GetWidth();
+ int height = videoFrame->GetHeight();
+ unsigned *p = (unsigned *)frameBytes;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x += 2)
+ *p++ = bars[(x * 8) / width];
+ }
+ }
+
+ if (!no_video) {
+ av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - No input signal detected "
+ "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);
+ }
+ no_video = 1;
+ } else {
+ if (no_video) {
+ av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - Input returned "
+ "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);
+ }
+ no_video = 0;
+ }
+
+ pkt.pts = frameTime / ctx->video_st->time_base.num;
+
+ if (initial_video_pts == AV_NOPTS_VALUE) {
+ initial_video_pts = pkt.pts;
+ }
+
+ pkt.pts -= initial_video_pts;
+ pkt.dts = pkt.pts;
+
+ pkt.duration = frameDuration;
+ //To be made sure it still applies
+ pkt.flags |= AV_PKT_FLAG_KEY;
+ pkt.stream_index = ctx->video_st->index;
+ pkt.data = (uint8_t *)frameBytes;
+ pkt.size = videoFrame->GetRowBytes() *
+ videoFrame->GetHeight();
+ //fprintf(stderr,"Video Frame size %d ts %d\n", pkt.size, pkt.pts);
+ c->frame_number++;
+ if (avpacket_queue_put(&ctx->queue, &pkt) < 0) {
+ ++ctx->dropped;
+ }
+ }
+
+ // Handle Audio Frame
+ if (audioFrame) {
+ AVCodecContext *c;
+ AVPacket pkt;
+ BMDTimeValue audio_pts;
+ av_init_packet(&pkt);
+
+ c = ctx->audio_st->codec;
+ //hack among hacks
+ pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codec->channels * (16 / 8);
+ audioFrame->GetBytes(&audioFrameBytes);
+ audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den);
+ pkt.pts = audio_pts / ctx->audio_st->time_base.num;
+
+ if (initial_audio_pts == AV_NOPTS_VALUE) {
+ initial_audio_pts = pkt.pts;
+ }
+
+ pkt.pts -= initial_audio_pts;
+ pkt.dts = pkt.pts;
+
+ //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
+ pkt.flags |= AV_PKT_FLAG_KEY;
+ pkt.stream_index = ctx->audio_st->index;
+ pkt.data = (uint8_t *)audioFrameBytes;
+
+ c->frame_number++;
+ if (avpacket_queue_put(&ctx->queue, &pkt) < 0) {
+ ++ctx->dropped;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT decklink_input_callback::VideoInputFormatChanged(
+ BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode,
+ BMDDetectedVideoInputFormatFlags)
+{
+ return S_OK;
+}
+
+static HRESULT decklink_start_input(AVFormatContext *avctx)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+
+ ctx->input_callback = new decklink_input_callback(avctx);
+ ctx->dli->SetCallback(ctx->input_callback);
+ return ctx->dli->StartStreams();
+}
+
+extern "C" {
+
+av_cold int ff_decklink_read_close(AVFormatContext *avctx)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+
+ if (ctx->capture_started) {
+ ctx->dli->StopStreams();
+ ctx->dli->DisableVideoInput();
+ ctx->dli->DisableAudioInput();
+ }
+
+ if (ctx->dli)
+ ctx->dli->Release();
+ if (ctx->dl)
+ ctx->dl->Release();
+
+ avpacket_queue_end(&ctx->queue);
+
+ av_freep(&cctx->ctx);
+
+ return 0;
+}
+
+av_cold int ff_decklink_read_header(AVFormatContext *avctx)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx;
+ IDeckLinkDisplayModeIterator *itermode;
+ IDeckLinkIterator *iter;
+ IDeckLink *dl = NULL;
+ AVStream *st;
+ HRESULT result;
+ char fname[1024];
+ char *tmp;
+ int mode_num = 0;
+
+ ctx = (struct decklink_ctx *) av_mallocz(sizeof(struct decklink_ctx));
+ if (!ctx)
+ return AVERROR(ENOMEM);
+ ctx->list_devices = cctx->list_devices;
+ ctx->list_formats = cctx->list_formats;
+ ctx->preroll = cctx->preroll;
+ cctx->ctx = ctx;
+
+ iter = CreateDeckLinkIteratorInstance();
+ if (!iter) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
+ return AVERROR(EIO);
+ }
+
+ /* List available devices. */
+ if (ctx->list_devices) {
+ ff_decklink_list_devices(avctx);
+ return AVERROR_EXIT;
+ }
+
+ strcpy (fname, avctx->filename);
+ tmp=strchr (fname, '@');
+ if (tmp != NULL) {
+ mode_num = atoi (tmp+1);
+ *tmp = 0;
+ }
+
+ /* Open device. */
+ while (iter->Next(&dl) == S_OK) {
+ const char *displayName;
+ ff_decklink_get_display_name(dl, &displayName);
+ if (!strcmp(fname, displayName)) {
+ av_free((void *) displayName);
+ ctx->dl = dl;
+ break;
+ }
+ av_free((void *) displayName);
+ dl->Release();
+ }
+ iter->Release();
+ if (!ctx->dl) {
+ av_log(avctx, AV_LOG_ERROR, "Could not open '%s'\n", fname);
+ return AVERROR(EIO);
+ }
+
+ /* Get input device. */
+ if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n",
+ avctx->filename);
+ ctx->dl->Release();
+ return AVERROR(EIO);
+ }
+
+ /* List supported formats. */
+ if (ctx->list_formats) {
+ ff_decklink_list_formats(avctx, DIRECTION_IN);
+ ctx->dli->Release();
+ ctx->dl->Release();
+ return AVERROR_EXIT;
+ }
+
+ if (ctx->dli->GetDisplayModeIterator(&itermode) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
+ ctx->dl->Release();
+ return AVERROR(EIO);
+ }
+
+ if (mode_num > 0) {
+ if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not set mode %d for %s\n", mode_num, fname);
+ goto error;
+ }
+ }
+
+ itermode->Release();
+
+ /* Setup streams. */
+ st = avformat_new_stream(avctx, NULL);
+ if (!st) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot add stream\n");
+ goto error;
+ }
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+ st->codec->sample_rate = bmdAudioSampleRate48kHz;
+ st->codec->channels = 2;
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+ ctx->audio_st=st;
+
+ st = avformat_new_stream(avctx, NULL);
+ if (!st) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot add stream\n");
+ goto error;
+ }
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->width = ctx->bmd_width;
+ st->codec->height = ctx->bmd_height;
+
+ st->codec->time_base.den = ctx->bmd_tb_den;
+ st->codec->time_base.num = ctx->bmd_tb_num;
+ st->codec->bit_rate = avpicture_get_size(st->codec->pix_fmt, ctx->bmd_width, ctx->bmd_height) * 1/av_q2d(st->codec->time_base) * 8;
+
+ if (cctx->v210) {
+ st->codec->codec_id = AV_CODEC_ID_V210;
+ st->codec->codec_tag = MKTAG('V', '2', '1', '0');
+ } else {
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->pix_fmt = AV_PIX_FMT_UYVY422;
+ st->codec->codec_tag = MKTAG('U', 'Y', 'V', 'Y');
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
+ ctx->video_st=st;
+
+ result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2);
+
+ if (result != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot enable audio input\n");
+ goto error;
+ }
+
+ result = ctx->dli->EnableVideoInput(ctx->bmd_mode,
+ cctx->v210 ? bmdFormat10BitYUV : bmdFormat8BitYUV,
+ bmdVideoInputFlagDefault);
+
+ if (result != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot enable video input\n");
+ goto error;
+ }
+
+ avpacket_queue_init (avctx, &ctx->queue);
+
+ if (decklink_start_input (avctx) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot start input stream\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+
+ ctx->dli->Release();
+ ctx->dl->Release();
+
+ return AVERROR(EIO);
+}
+
+int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+ AVFrame *frame = ctx->video_st->codec->coded_frame;
+
+ avpacket_queue_get(&ctx->queue, pkt, 1);
+ if (frame && (ctx->bmd_field_dominance == bmdUpperFieldFirst || ctx->bmd_field_dominance == bmdLowerFieldFirst)) {
+ frame->interlaced_frame = 1;
+ if (ctx->bmd_field_dominance == bmdUpperFieldFirst) {
+ frame->top_field_first = 1;
+ }
+ }
+
+ return 0;
+}
+
+} /* extern "C" */
diff --git a/libavdevice/decklink_dec.h b/libavdevice/decklink_dec.h
new file mode 100644
index 0000000000..6bd9226cd0
--- /dev/null
+++ b/libavdevice/decklink_dec.h
@@ -0,0 +1,32 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2013-2014 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
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ff_decklink_read_header(AVFormatContext *avctx);
+int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt);
+int ff_decklink_read_close(AVFormatContext *avctx);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
new file mode 100644
index 0000000000..b1a65e6877
--- /dev/null
+++ b/libavdevice/decklink_dec_c.c
@@ -0,0 +1,55 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2014 Deti Fliegl
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavformat/avformat.h"
+#include "libavutil/opt.h"
+
+#include "decklink_common_c.h"
+#include "decklink_dec.h"
+
+#define OFFSET(x) offsetof(struct decklink_cctx, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption options[] = {
+ { "list_devices", "list available devices" , OFFSET(list_devices), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, DEC },
+ { "list_formats", "list supported formats" , OFFSET(list_formats), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, DEC },
+ { "bm_v210", "v210 10 bit per channel" , OFFSET(v210), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, DEC },
+ { NULL },
+};
+
+static const AVClass decklink_demuxer_class = {
+ .class_name = "Blackmagic DeckLink demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_decklink_demuxer = {
+ .name = "decklink",
+ .long_name = NULL_IF_CONFIG_SMALL("Blackmagic DeckLink input"),
+ .flags = AVFMT_NOFILE | AVFMT_RAWPICTURE,
+ .priv_class = &decklink_demuxer_class,
+ .priv_data_size = sizeof(struct decklink_cctx),
+ .read_header = ff_decklink_read_header,
+ .read_packet = ff_decklink_read_packet,
+ .read_close = ff_decklink_read_close,
+};
diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp
new file mode 100644
index 0000000000..6c5450f4ec
--- /dev/null
+++ b/libavdevice/decklink_enc.cpp
@@ -0,0 +1,426 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2013-2014 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 <DeckLinkAPI.h>
+
+#include <pthread.h>
+#include <semaphore.h>
+
+extern "C" {
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavutil/imgutils.h"
+}
+
+#include "decklink_common.h"
+#include "decklink_enc.h"
+
+
+/* DeckLink callback class declaration */
+class decklink_frame : public IDeckLinkVideoFrame
+{
+public:
+ decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, long width,
+ long height, void *buffer) :
+ _ctx(ctx), _avframe(avframe), _width(width),
+ _height(height), _buffer(buffer), _refs(0) { }
+
+ virtual long STDMETHODCALLTYPE GetWidth (void) { return _width; }
+ virtual long STDMETHODCALLTYPE GetHeight (void) { return _height; }
+ virtual long STDMETHODCALLTYPE GetRowBytes (void) { return _width<<1; }
+ virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return bmdFormat8BitYUV; }
+ virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags (void) { return bmdVideoOutputFlagDefault; }
+ virtual HRESULT STDMETHODCALLTYPE GetBytes (void **buffer) { *buffer = _buffer; return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE GetTimecode (BMDTimecodeFormat format, IDeckLinkTimecode **timecode) { return S_FALSE; }
+ virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) { return S_FALSE; }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; }
+ virtual ULONG STDMETHODCALLTYPE Release(void) { if (!--_refs) delete this; return _refs; }
+
+ struct decklink_ctx *_ctx;
+ AVFrame *_avframe;
+
+private:
+ long _width;
+ long _height;
+ void *_buffer;
+ int _refs;
+};
+
+class decklink_output_callback : public IDeckLinkVideoOutputCallback
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame *_frame, BMDOutputFrameCompletionResult result)
+ {
+ decklink_frame *frame = static_cast<decklink_frame *>(_frame);
+ struct decklink_ctx *ctx = frame->_ctx;
+ AVFrame *avframe = frame->_avframe;
+
+ av_frame_free(&avframe);
+
+ sem_post(&ctx->semaphore);
+
+ return S_OK;
+ }
+ virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped(void) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
+ virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1; }
+ virtual ULONG STDMETHODCALLTYPE Release(void) { return 1; }
+};
+
+static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+ AVCodecContext *c = st->codec;
+
+ if (ctx->video) {
+ av_log(avctx, AV_LOG_ERROR, "Only one video stream is supported!\n");
+ return -1;
+ }
+
+ if (c->pix_fmt != AV_PIX_FMT_UYVY422) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format!"
+ " Only AV_PIX_FMT_UYVY422 is supported.\n");
+ return -1;
+ }
+ if (ff_decklink_set_format(avctx, c->width, c->height,
+ c->time_base.num, c->time_base.den)) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported video size or framerate!"
+ " Check available formats with -list_formats 1.\n");
+ return -1;
+ }
+ if (ctx->dlo->EnableVideoOutput(ctx->bmd_mode,
+ bmdVideoOutputFlagDefault) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enable video output!\n");
+ return -1;
+ }
+
+ /* Set callback. */
+ ctx->output_callback = new decklink_output_callback();
+ ctx->dlo->SetScheduledFrameCompletionCallback(ctx->output_callback);
+
+ /* Start video semaphore. */
+ ctx->frames_preroll = c->time_base.den * ctx->preroll;
+ if (c->time_base.den > 1000)
+ ctx->frames_preroll /= 1000;
+
+ /* Buffer twice as many frames as the preroll. */
+ ctx->frames_buffer = ctx->frames_preroll * 2;
+ ctx->frames_buffer = FFMIN(ctx->frames_buffer, 60);
+ sem_init(&ctx->semaphore, 0, ctx->frames_buffer);
+
+ /* The device expects the framerate to be fixed. */
+ avpriv_set_pts_info(st, 64, c->time_base.num, c->time_base.den);
+
+ ctx->video = 1;
+
+ return 0;
+}
+
+static int decklink_setup_audio(AVFormatContext *avctx, AVStream *st)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+ AVCodecContext *c = st->codec;
+
+ if (ctx->audio) {
+ av_log(avctx, AV_LOG_ERROR, "Only one audio stream is supported!\n");
+ return -1;
+ }
+ if (c->sample_rate != 48000) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate!"
+ " Only 48kHz is supported.\n");
+ return -1;
+ }
+ if (c->channels != 2 && c->channels != 8) {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported number of channels!"
+ " Only stereo and 7.1 are supported.\n");
+ return -1;
+ }
+ if (ctx->dlo->EnableAudioOutput(bmdAudioSampleRate48kHz,
+ bmdAudioSampleType16bitInteger,
+ c->channels,
+ bmdAudioOutputStreamTimestamped) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enable audio output!\n");
+ return -1;
+ }
+ if (ctx->dlo->BeginAudioPreroll() != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not begin audio preroll!\n");
+ return -1;
+ }
+
+ /* The device expects the sample rate to be fixed. */
+ avpriv_set_pts_info(st, 64, 1, c->sample_rate);
+ ctx->channels = c->channels;
+
+ ctx->audio = 1;
+
+ return 0;
+}
+
+av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+
+ if (ctx->playback_started) {
+ BMDTimeValue actual;
+ ctx->dlo->StopScheduledPlayback(ctx->last_pts * ctx->bmd_tb_num,
+ &actual, ctx->bmd_tb_den);
+ ctx->dlo->DisableVideoOutput();
+ if (ctx->audio)
+ ctx->dlo->DisableAudioOutput();
+ }
+
+ if (ctx->dlo)
+ ctx->dlo->Release();
+ if (ctx->dl)
+ ctx->dl->Release();
+
+ if (ctx->output_callback)
+ delete ctx->output_callback;
+
+ sem_destroy(&ctx->semaphore);
+
+ av_freep(&cctx->ctx);
+
+ return 0;
+}
+
+static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+ AVPicture *avpicture = (AVPicture *) pkt->data;
+ AVFrame *avframe, *tmp;
+ decklink_frame *frame;
+ buffercount_type buffered;
+ HRESULT hr;
+
+ /* HACK while av_uncoded_frame() isn't implemented */
+ int ret;
+
+ tmp = av_frame_alloc();
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ tmp->format = AV_PIX_FMT_UYVY422;
+ tmp->width = ctx->bmd_width;
+ tmp->height = ctx->bmd_height;
+ ret = av_frame_get_buffer(tmp, 32);
+ if (ret < 0) {
+ av_frame_free(&tmp);
+ return ret;
+ }
+ av_image_copy(tmp->data, tmp->linesize, (const uint8_t **) avpicture->data,
+ avpicture->linesize, (AVPixelFormat) tmp->format, tmp->width,
+ tmp->height);
+ avframe = av_frame_clone(tmp);
+ av_frame_free(&tmp);
+ if (!avframe) {
+ av_log(avctx, AV_LOG_ERROR, "Could not clone video frame.\n");
+ return AVERROR(EIO);
+ }
+ /* end HACK */
+
+ frame = new decklink_frame(ctx, avframe, ctx->bmd_width, ctx->bmd_height,
+ (void *) avframe->data[0]);
+ if (!frame) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create new frame.\n");
+ return AVERROR(EIO);
+ }
+
+ /* Always keep at most one second of frames buffered. */
+ sem_wait(&ctx->semaphore);
+
+ /* Schedule frame for playback. */
+ hr = ctx->dlo->ScheduleVideoFrame((struct IDeckLinkVideoFrame *) frame,
+ pkt->pts * ctx->bmd_tb_num,
+ ctx->bmd_tb_num, ctx->bmd_tb_den);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not schedule video frame."
+ " error %08x.\n", (uint32_t) hr);
+ frame->Release();
+ return AVERROR(EIO);
+ }
+
+ ctx->dlo->GetBufferedVideoFrameCount(&buffered);
+ av_log(avctx, AV_LOG_DEBUG, "Buffered video frames: %d.\n", (int) buffered);
+ if (pkt->pts > 2 && buffered <= 2)
+ av_log(avctx, AV_LOG_WARNING, "There are not enough buffered video frames."
+ " Video may misbehave!\n");
+
+ /* Preroll video frames. */
+ if (!ctx->playback_started && pkt->pts > ctx->frames_preroll) {
+ av_log(avctx, AV_LOG_DEBUG, "Ending audio preroll.\n");
+ if (ctx->audio && ctx->dlo->EndAudioPreroll() != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not end audio preroll!\n");
+ return AVERROR(EIO);
+ }
+ av_log(avctx, AV_LOG_DEBUG, "Starting scheduled playback.\n");
+ if (ctx->dlo->StartScheduledPlayback(0, ctx->bmd_tb_den, 1.0) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not start scheduled playback!\n");
+ return AVERROR(EIO);
+ }
+ ctx->playback_started = 1;
+ }
+
+ return 0;
+}
+
+static int decklink_write_audio_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+ int sample_count = pkt->size / (ctx->channels << 1);
+ buffercount_type buffered;
+
+ ctx->dlo->GetBufferedAudioSampleFrameCount(&buffered);
+ if (pkt->pts > 1 && !buffered)
+ av_log(avctx, AV_LOG_WARNING, "There's no buffered audio."
+ " Audio will misbehave!\n");
+
+ if (ctx->dlo->ScheduleAudioSamples(pkt->data, sample_count, pkt->pts,
+ bmdAudioSampleRate48kHz, NULL) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not schedule audio samples.\n");
+ return AVERROR(EIO);
+ }
+
+ return 0;
+}
+
+extern "C" {
+
+av_cold int ff_decklink_write_header(AVFormatContext *avctx)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx;
+ IDeckLinkDisplayModeIterator *itermode;
+ IDeckLinkIterator *iter;
+ IDeckLink *dl = NULL;
+ unsigned int n;
+
+ ctx = (struct decklink_ctx *) av_mallocz(sizeof(struct decklink_ctx));
+ if (!ctx)
+ return AVERROR(ENOMEM);
+ ctx->list_devices = cctx->list_devices;
+ ctx->list_formats = cctx->list_formats;
+ ctx->preroll = cctx->preroll;
+ cctx->ctx = ctx;
+
+ iter = CreateDeckLinkIteratorInstance();
+ if (!iter) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
+ return AVERROR(EIO);
+ }
+
+ /* List available devices. */
+ if (ctx->list_devices) {
+ ff_decklink_list_devices(avctx);
+ return AVERROR_EXIT;
+ }
+
+ /* Open device. */
+ while (iter->Next(&dl) == S_OK) {
+ const char *displayName;
+ ff_decklink_get_display_name(dl, &displayName);
+ if (!strcmp(avctx->filename, displayName)) {
+ av_free((void *) displayName);
+ ctx->dl = dl;
+ break;
+ }
+ av_free((void *) displayName);
+ dl->Release();
+ }
+ iter->Release();
+ if (!ctx->dl) {
+ av_log(avctx, AV_LOG_ERROR, "Could not open '%s'\n", avctx->filename);
+ return AVERROR(EIO);
+ }
+
+ /* Get output device. */
+ if (ctx->dl->QueryInterface(IID_IDeckLinkOutput, (void **) &ctx->dlo) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n",
+ avctx->filename);
+ ctx->dl->Release();
+ return AVERROR(EIO);
+ }
+
+ /* List supported formats. */
+ if (ctx->list_formats) {
+ ff_decklink_list_formats(avctx);
+ ctx->dlo->Release();
+ ctx->dl->Release();
+ return AVERROR_EXIT;
+ }
+
+ if (ctx->dlo->GetDisplayModeIterator(&itermode) != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
+ ctx->dl->Release();
+ return AVERROR(EIO);
+ }
+
+ /* Setup streams. */
+ for (n = 0; n < avctx->nb_streams; n++) {
+ AVStream *st = avctx->streams[n];
+ AVCodecContext *c = st->codec;
+ if (c->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (decklink_setup_audio(avctx, st))
+ goto error;
+ } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (decklink_setup_video(avctx, st))
+ goto error;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Unsupported stream type.\n");
+ goto error;
+ }
+ }
+ itermode->Release();
+
+ return 0;
+
+error:
+
+ ctx->dlo->Release();
+ ctx->dl->Release();
+
+ return AVERROR(EIO);
+}
+
+int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
+ AVStream *st = avctx->streams[pkt->stream_index];
+
+ ctx->last_pts = FFMAX(ctx->last_pts, pkt->pts);
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ return decklink_write_video_packet(avctx, pkt);
+ else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ return decklink_write_audio_packet(avctx, pkt);
+
+ return AVERROR(EIO);
+}
+
+} /* extern "C" */
diff --git a/libavdevice/decklink_enc.h b/libavdevice/decklink_enc.h
new file mode 100644
index 0000000000..6086947e6c
--- /dev/null
+++ b/libavdevice/decklink_enc.h
@@ -0,0 +1,32 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2013-2014 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
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ff_decklink_write_header(AVFormatContext *avctx);
+int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt);
+int ff_decklink_write_trailer(AVFormatContext *avctx);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c
new file mode 100644
index 0000000000..c3c90184f8
--- /dev/null
+++ b/libavdevice/decklink_enc_c.c
@@ -0,0 +1,57 @@
+/*
+ * Blackmagic DeckLink output
+ * Copyright (c) 2013-2014 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 "libavformat/avformat.h"
+#include "libavutil/opt.h"
+
+#include "decklink_common_c.h"
+#include "decklink_enc.h"
+
+#define OFFSET(x) offsetof(struct decklink_cctx, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "list_devices", "list available devices" , OFFSET(list_devices), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, ENC },
+ { "list_formats", "list supported formats" , OFFSET(list_formats), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, ENC },
+ { "preroll" , "video preroll in seconds", OFFSET(preroll ), AV_OPT_TYPE_DOUBLE, { .dbl = 0.5 }, 0, 5, ENC },
+ { NULL },
+};
+
+static const AVClass decklink_muxer_class = {
+ .class_name = "Blackmagic DeckLink muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_decklink_muxer = {
+ .name = "decklink",
+ .long_name = NULL_IF_CONFIG_SMALL("Blackmagic DeckLink output"),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .subtitle_codec = AV_CODEC_ID_NONE,
+ .flags = AVFMT_NOFILE | AVFMT_RAWPICTURE,
+ .priv_class = &decklink_muxer_class,
+ .priv_data_size = sizeof(struct decklink_cctx),
+ .write_header = ff_decklink_write_header,
+ .write_packet = ff_decklink_write_packet,
+ .write_trailer = ff_decklink_write_trailer,
+};
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
new file mode 100644
index 0000000000..62249785cb
--- /dev/null
+++ b/libavdevice/dshow.c
@@ -0,0 +1,1325 @@
+/*
+ * Directshow capture interface
+ * Copyright (c) 2010 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 "dshow_capture.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "libavformat/internal.h"
+#include "libavformat/riff.h"
+#include "avdevice.h"
+#include "libavcodec/raw.h"
+#include "objidl.h"
+#include "shlwapi.h"
+
+
+static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
+{
+ switch(biCompression) {
+ case BI_BITFIELDS:
+ case BI_RGB:
+ switch(biBitCount) { /* 1-8 are untested */
+ case 1:
+ return AV_PIX_FMT_MONOWHITE;
+ case 4:
+ return AV_PIX_FMT_RGB4;
+ case 8:
+ return AV_PIX_FMT_RGB8;
+ case 16:
+ return AV_PIX_FMT_RGB555;
+ case 24:
+ return AV_PIX_FMT_BGR24;
+ case 32:
+ return AV_PIX_FMT_0RGB32;
+ }
+ }
+ return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
+}
+
+static int
+dshow_read_close(AVFormatContext *s)
+{
+ struct dshow_ctx *ctx = s->priv_data;
+ AVPacketList *pktl;
+
+ if (ctx->control) {
+ IMediaControl_Stop(ctx->control);
+ IMediaControl_Release(ctx->control);
+ }
+
+ if (ctx->media_event)
+ IMediaEvent_Release(ctx->media_event);
+
+ if (ctx->graph) {
+ IEnumFilters *fenum;
+ int r;
+ r = IGraphBuilder_EnumFilters(ctx->graph, &fenum);
+ if (r == S_OK) {
+ IBaseFilter *f;
+ IEnumFilters_Reset(fenum);
+ while (IEnumFilters_Next(fenum, 1, &f, NULL) == S_OK) {
+ if (IGraphBuilder_RemoveFilter(ctx->graph, f) == S_OK)
+ IEnumFilters_Reset(fenum); /* When a filter is removed,
+ * the list must be reset. */
+ IBaseFilter_Release(f);
+ }
+ IEnumFilters_Release(fenum);
+ }
+ IGraphBuilder_Release(ctx->graph);
+ }
+
+ if (ctx->capture_pin[VideoDevice])
+ libAVPin_Release(ctx->capture_pin[VideoDevice]);
+ if (ctx->capture_pin[AudioDevice])
+ libAVPin_Release(ctx->capture_pin[AudioDevice]);
+ if (ctx->capture_filter[VideoDevice])
+ libAVFilter_Release(ctx->capture_filter[VideoDevice]);
+ if (ctx->capture_filter[AudioDevice])
+ libAVFilter_Release(ctx->capture_filter[AudioDevice]);
+
+ if (ctx->device_pin[VideoDevice])
+ IPin_Release(ctx->device_pin[VideoDevice]);
+ if (ctx->device_pin[AudioDevice])
+ IPin_Release(ctx->device_pin[AudioDevice]);
+ if (ctx->device_filter[VideoDevice])
+ IBaseFilter_Release(ctx->device_filter[VideoDevice]);
+ if (ctx->device_filter[AudioDevice])
+ IBaseFilter_Release(ctx->device_filter[AudioDevice]);
+
+ if (ctx->device_name[0])
+ av_freep(&ctx->device_name[0]);
+ if (ctx->device_name[1])
+ av_freep(&ctx->device_name[1]);
+
+ if(ctx->mutex)
+ CloseHandle(ctx->mutex);
+ if(ctx->event[0])
+ CloseHandle(ctx->event[0]);
+ if(ctx->event[1])
+ CloseHandle(ctx->event[1]);
+
+ pktl = ctx->pktl;
+ while (pktl) {
+ AVPacketList *next = pktl->next;
+ av_free_packet(&pktl->pkt);
+ av_free(pktl);
+ pktl = next;
+ }
+
+ CoUninitialize();
+
+ return 0;
+}
+
+static char *dup_wchar_to_utf8(wchar_t *w)
+{
+ char *s = NULL;
+ int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
+ s = av_malloc(l);
+ if (s)
+ WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
+ return s;
+}
+
+static int shall_we_drop(AVFormatContext *s, int index, enum dshowDeviceType devtype)
+{
+ struct dshow_ctx *ctx = s->priv_data;
+ static const uint8_t dropscore[] = {62, 75, 87, 100};
+ const int ndropscores = FF_ARRAY_ELEMS(dropscore);
+ unsigned int buffer_fullness = (ctx->curbufsize[index]*100)/s->max_picture_buffer;
+ const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
+
+ if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
+ av_log(s, AV_LOG_ERROR,
+ "real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped!\n",
+ ctx->device_name[devtype], devtypename, buffer_fullness, s->max_picture_buffer);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType devtype)
+{
+ AVFormatContext *s = priv_data;
+ struct dshow_ctx *ctx = s->priv_data;
+ AVPacketList **ppktl, *pktl_next;
+
+// dump_videohdr(s, vdhdr);
+
+ WaitForSingleObject(ctx->mutex, INFINITE);
+
+ if(shall_we_drop(s, index, devtype))
+ goto fail;
+
+ pktl_next = av_mallocz(sizeof(AVPacketList));
+ if(!pktl_next)
+ goto fail;
+
+ if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
+ av_free(pktl_next);
+ goto fail;
+ }
+
+ pktl_next->pkt.stream_index = index;
+ pktl_next->pkt.pts = time;
+ memcpy(pktl_next->pkt.data, buf, buf_size);
+
+ for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
+ *ppktl = pktl_next;
+ ctx->curbufsize[index] += buf_size;
+
+ SetEvent(ctx->event[1]);
+ ReleaseMutex(ctx->mutex);
+
+ return;
+fail:
+ ReleaseMutex(ctx->mutex);
+ return;
+}
+
+/**
+ * Cycle through available devices using the device enumerator devenum,
+ * retrieve the device with type specified by devtype and return the
+ * pointer to the object found in *pfilter.
+ * If pfilter is NULL, list all device names.
+ */
+static int
+dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
+ enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype, IBaseFilter **pfilter)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IBaseFilter *device_filter = NULL;
+ IEnumMoniker *classenum = NULL;
+ IMoniker *m = NULL;
+ const char *device_name = ctx->device_name[devtype];
+ int skip = (devtype == VideoDevice) ? ctx->video_device_number
+ : ctx->audio_device_number;
+ int r;
+
+ const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
+ &CLSID_AudioInputDeviceCategory };
+ const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
+ const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
+
+ r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype],
+ (IEnumMoniker **) &classenum, 0);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n",
+ devtypename);
+ return AVERROR(EIO);
+ }
+
+ while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) {
+ IPropertyBag *bag = NULL;
+ char *friendly_name = NULL;
+ char *unique_name = NULL;
+ VARIANT var;
+ IBindCtx *bind_ctx = NULL;
+ LPOLESTR olestr = NULL;
+ LPMALLOC co_malloc = NULL;
+ int i;
+
+ r = CoGetMalloc(1, &co_malloc);
+ if (r = S_OK)
+ goto fail1;
+ r = CreateBindCtx(0, &bind_ctx);
+ if (r != S_OK)
+ goto fail1;
+ /* GetDisplayname works for both video and audio, DevicePath doesn't */
+ r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr);
+ if (r != S_OK)
+ goto fail1;
+ unique_name = dup_wchar_to_utf8(olestr);
+ /* replace ':' with '_' since we use : to delineate between sources */
+ for (i = 0; i < strlen(unique_name); i++) {
+ if (unique_name[i] == ':')
+ unique_name[i] = '_';
+ }
+
+ r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
+ if (r != S_OK)
+ goto fail1;
+
+ var.vt = VT_BSTR;
+ r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
+ if (r != S_OK)
+ goto fail1;
+ friendly_name = dup_wchar_to_utf8(var.bstrVal);
+
+ if (pfilter) {
+ if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name))
+ goto fail1;
+
+ if (!skip--) {
+ r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name);
+ goto fail1;
+ }
+ }
+ } else {
+ av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name);
+ av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
+ }
+
+fail1:
+ if (olestr && co_malloc)
+ IMalloc_Free(co_malloc, olestr);
+ if (bind_ctx)
+ IBindCtx_Release(bind_ctx);
+ av_free(friendly_name);
+ av_free(unique_name);
+ if (bag)
+ IPropertyBag_Release(bag);
+ IMoniker_Release(m);
+ }
+
+ IEnumMoniker_Release(classenum);
+
+ if (pfilter) {
+ if (!device_filter) {
+ av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n",
+ devtypename, device_name, sourcetypename);
+ return AVERROR(EIO);
+ }
+ *pfilter = device_filter;
+ }
+
+ return 0;
+}
+
+/**
+ * Cycle through available formats using the specified pin,
+ * try to set parameters specified through AVOptions and if successful
+ * return 1 in *pformat_set.
+ * If pformat_set is NULL, list all pin capabilities.
+ */
+static void
+dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
+ IPin *pin, int *pformat_set)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IAMStreamConfig *config = NULL;
+ AM_MEDIA_TYPE *type = NULL;
+ int format_set = 0;
+ void *caps = NULL;
+ int i, n, size, r;
+
+ if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
+ return;
+ if (IAMStreamConfig_GetNumberOfCapabilities(config, &n, &size) != S_OK)
+ goto end;
+
+ caps = av_malloc(size);
+ if (!caps)
+ goto end;
+
+ for (i = 0; i < n && !format_set; i++) {
+ r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps);
+ if (r != S_OK)
+ goto next;
+#if DSHOWDEBUG
+ ff_print_AM_MEDIA_TYPE(type);
+#endif
+
+ if (devtype == VideoDevice) {
+ VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
+ BITMAPINFOHEADER *bih;
+ int64_t *fr;
+ const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
+#if DSHOWDEBUG
+ ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
+#endif
+ if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *v = (void *) type->pbFormat;
+ fr = &v->AvgTimePerFrame;
+ bih = &v->bmiHeader;
+ } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
+ VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
+ fr = &v->AvgTimePerFrame;
+ bih = &v->bmiHeader;
+ } else {
+ goto next;
+ }
+ if (!pformat_set) {
+ enum AVPixelFormat pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
+ if (pix_fmt == AV_PIX_FMT_NONE) {
+ enum AVCodecID codec_id = av_codec_get_id(tags, bih->biCompression);
+ AVCodec *codec = avcodec_find_decoder(codec_id);
+ if (codec_id == AV_CODEC_ID_NONE || !codec) {
+ av_log(avctx, AV_LOG_INFO, " unknown compression type 0x%X", (int) bih->biCompression);
+ } else {
+ av_log(avctx, AV_LOG_INFO, " vcodec=%s", codec->name);
+ }
+ } else {
+ av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt));
+ }
+ av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n",
+ vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
+ 1e7 / vcaps->MaxFrameInterval,
+ vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
+ 1e7 / vcaps->MinFrameInterval);
+ continue;
+ }
+ if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
+ if (ctx->video_codec_id != av_codec_get_id(tags, bih->biCompression))
+ goto next;
+ }
+ if (ctx->pixel_format != AV_PIX_FMT_NONE &&
+ ctx->pixel_format != dshow_pixfmt(bih->biCompression, bih->biBitCount)) {
+ goto next;
+ }
+ if (ctx->framerate) {
+ int64_t framerate = ((int64_t) ctx->requested_framerate.den*10000000)
+ / ctx->requested_framerate.num;
+ if (framerate > vcaps->MaxFrameInterval ||
+ framerate < vcaps->MinFrameInterval)
+ goto next;
+ *fr = framerate;
+ }
+ if (ctx->requested_width && ctx->requested_height) {
+ if (ctx->requested_width > vcaps->MaxOutputSize.cx ||
+ ctx->requested_width < vcaps->MinOutputSize.cx ||
+ ctx->requested_height > vcaps->MaxOutputSize.cy ||
+ ctx->requested_height < vcaps->MinOutputSize.cy)
+ goto next;
+ bih->biWidth = ctx->requested_width;
+ bih->biHeight = ctx->requested_height;
+ }
+ } else {
+ AUDIO_STREAM_CONFIG_CAPS *acaps = caps;
+ WAVEFORMATEX *fx;
+#if DSHOWDEBUG
+ ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps);
+#endif
+ if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
+ fx = (void *) type->pbFormat;
+ } else {
+ goto next;
+ }
+ if (!pformat_set) {
+ av_log(avctx, AV_LOG_INFO, " min ch=%lu bits=%lu rate=%6lu max ch=%lu bits=%lu rate=%6lu\n",
+ acaps->MinimumChannels, acaps->MinimumBitsPerSample, acaps->MinimumSampleFrequency,
+ acaps->MaximumChannels, acaps->MaximumBitsPerSample, acaps->MaximumSampleFrequency);
+ continue;
+ }
+ if (ctx->sample_rate) {
+ if (ctx->sample_rate > acaps->MaximumSampleFrequency ||
+ ctx->sample_rate < acaps->MinimumSampleFrequency)
+ goto next;
+ fx->nSamplesPerSec = ctx->sample_rate;
+ }
+ if (ctx->sample_size) {
+ if (ctx->sample_size > acaps->MaximumBitsPerSample ||
+ ctx->sample_size < acaps->MinimumBitsPerSample)
+ goto next;
+ fx->wBitsPerSample = ctx->sample_size;
+ }
+ if (ctx->channels) {
+ if (ctx->channels > acaps->MaximumChannels ||
+ ctx->channels < acaps->MinimumChannels)
+ goto next;
+ fx->nChannels = ctx->channels;
+ }
+ }
+ if (IAMStreamConfig_SetFormat(config, type) != S_OK)
+ goto next;
+ format_set = 1;
+next:
+ if (type->pbFormat)
+ CoTaskMemFree(type->pbFormat);
+ CoTaskMemFree(type);
+ }
+end:
+ IAMStreamConfig_Release(config);
+ av_free(caps);
+ if (pformat_set)
+ *pformat_set = format_set;
+}
+
+/**
+ * Set audio device buffer size in milliseconds (which can directly impact
+ * latency, depending on the device).
+ */
+static int
+dshow_set_audio_buffer_size(AVFormatContext *avctx, IPin *pin)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IAMBufferNegotiation *buffer_negotiation = NULL;
+ ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
+ IAMStreamConfig *config = NULL;
+ AM_MEDIA_TYPE *type = NULL;
+ int ret = AVERROR(EIO);
+
+ if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
+ goto end;
+ if (IAMStreamConfig_GetFormat(config, &type) != S_OK)
+ goto end;
+ if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx))
+ goto end;
+
+ props.cbBuffer = (((WAVEFORMATEX *) type->pbFormat)->nAvgBytesPerSec)
+ * ctx->audio_buffer_size / 1000;
+
+ if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (void **) &buffer_negotiation) != S_OK)
+ goto end;
+ if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK)
+ goto end;
+
+ ret = 0;
+
+end:
+ if (buffer_negotiation)
+ IAMBufferNegotiation_Release(buffer_negotiation);
+ if (type) {
+ if (type->pbFormat)
+ CoTaskMemFree(type->pbFormat);
+ CoTaskMemFree(type);
+ }
+ if (config)
+ IAMStreamConfig_Release(config);
+
+ return ret;
+}
+
+/**
+ * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
+ */
+void
+dshow_show_filter_properties(IBaseFilter *device_filter, AVFormatContext *avctx) {
+ ISpecifyPropertyPages *property_pages = NULL;
+ IUnknown *device_filter_iunknown = NULL;
+ HRESULT hr;
+ FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
+ CAUUID ca_guid = {0};
+
+ hr = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_WARNING, "requested filter does not have a property page to show");
+ goto end;
+ }
+ hr = IBaseFilter_QueryFilterInfo(device_filter, &filter_info);
+ if (hr != S_OK) {
+ goto fail;
+ }
+ hr = IBaseFilter_QueryInterface(device_filter, &IID_IUnknown, (void **)&device_filter_iunknown);
+ if (hr != S_OK) {
+ goto fail;
+ }
+ hr = ISpecifyPropertyPages_GetPages(property_pages, &ca_guid);
+ if (hr != S_OK) {
+ goto fail;
+ }
+ hr = OleCreatePropertyFrame(NULL, 0, 0, filter_info.achName, 1, &device_filter_iunknown, ca_guid.cElems,
+ ca_guid.pElems, 0, 0, NULL);
+ if (hr != S_OK) {
+ goto fail;
+ }
+ goto end;
+fail:
+ av_log(avctx, AV_LOG_ERROR, "Failure showing property pages for filter");
+end:
+ if (property_pages)
+ ISpecifyPropertyPages_Release(property_pages);
+ if (device_filter_iunknown)
+ IUnknown_Release(device_filter_iunknown);
+ if (filter_info.pGraph)
+ IFilterGraph_Release(filter_info.pGraph);
+ if (ca_guid.pElems)
+ CoTaskMemFree(ca_guid.pElems);
+}
+
+/**
+ * Cycle through available pins using the device_filter device, of type
+ * devtype, retrieve the first output pin and return the pointer to the
+ * object found in *ppin.
+ * If ppin is NULL, cycle through all pins listing audio/video capabilities.
+ */
+static int
+dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
+ enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IEnumPins *pins = 0;
+ IPin *device_pin = NULL;
+ IPin *pin;
+ int r;
+
+ const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
+ const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
+ const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
+
+ int set_format = (devtype == VideoDevice && (ctx->framerate ||
+ (ctx->requested_width && ctx->requested_height) ||
+ ctx->pixel_format != AV_PIX_FMT_NONE ||
+ ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO))
+ || (devtype == AudioDevice && (ctx->channels || ctx->sample_rate));
+ int format_set = 0;
+ int should_show_properties = (devtype == VideoDevice) ? ctx->show_video_device_dialog : ctx->show_audio_device_dialog;
+
+ if (should_show_properties)
+ dshow_show_filter_properties(device_filter, avctx);
+
+ r = IBaseFilter_EnumPins(device_filter, &pins);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
+ return AVERROR(EIO);
+ }
+
+ if (!ppin) {
+ av_log(avctx, AV_LOG_INFO, "DirectShow %s device options (from %s devices)\n",
+ devtypename, sourcetypename);
+ }
+
+ while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
+ IKsPropertySet *p = NULL;
+ IEnumMediaTypes *types = NULL;
+ PIN_INFO info = {0};
+ AM_MEDIA_TYPE *type;
+ GUID category;
+ DWORD r2;
+ char *name_buf = NULL;
+ wchar_t *pin_id = NULL;
+ char *pin_buf = NULL;
+ char *desired_pin_name = devtype == VideoDevice ? ctx->video_pin_name : ctx->audio_pin_name;
+
+ IPin_QueryPinInfo(pin, &info);
+ IBaseFilter_Release(info.pFilter);
+
+ if (info.dir != PINDIR_OUTPUT)
+ goto next;
+ if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
+ goto next;
+ if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
+ NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
+ goto next;
+ if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
+ goto next;
+ name_buf = dup_wchar_to_utf8(info.achName);
+
+ r = IPin_QueryId(pin, &pin_id);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not query pin id\n");
+ return AVERROR(EIO);
+ }
+ pin_buf = dup_wchar_to_utf8(pin_id);
+
+ if (!ppin) {
+ av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
+ dshow_cycle_formats(avctx, devtype, pin, NULL);
+ goto next;
+ }
+
+ if (desired_pin_name) {
+ if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
+ av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n",
+ name_buf, pin_buf, desired_pin_name);
+ goto next;
+ }
+ }
+
+ if (set_format) {
+ dshow_cycle_formats(avctx, devtype, pin, &format_set);
+ if (!format_set) {
+ goto next;
+ }
+ }
+ if (devtype == AudioDevice && ctx->audio_buffer_size) {
+ if (dshow_set_audio_buffer_size(avctx, pin) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "unable to set audio buffer size %d to pin, using pin anyway...", ctx->audio_buffer_size);
+ }
+ }
+
+ if (IPin_EnumMediaTypes(pin, &types) != S_OK)
+ goto next;
+
+ IEnumMediaTypes_Reset(types);
+ /* in case format_set was not called, just verify the majortype */
+ while (!device_pin && IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
+ if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
+ device_pin = pin;
+ av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename);
+ goto next;
+ }
+ CoTaskMemFree(type);
+ }
+
+next:
+ if (types)
+ IEnumMediaTypes_Release(types);
+ if (p)
+ IKsPropertySet_Release(p);
+ if (device_pin != pin)
+ IPin_Release(pin);
+ av_free(name_buf);
+ av_free(pin_buf);
+ if (pin_id)
+ CoTaskMemFree(pin_id);
+ }
+
+ IEnumPins_Release(pins);
+
+ if (ppin) {
+ if (set_format && !format_set) {
+ av_log(avctx, AV_LOG_ERROR, "Could not set %s options\n", devtypename);
+ return AVERROR(EIO);
+ }
+ if (!device_pin) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not find output pin from %s capture device.\n", devtypename);
+ return AVERROR(EIO);
+ }
+ *ppin = device_pin;
+ }
+
+ return 0;
+}
+
+/**
+ * List options for device with type devtype, source filter type sourcetype
+ *
+ * @param devenum device enumerator used for accessing the device
+ */
+static int
+dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
+ enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IBaseFilter *device_filter = NULL;
+ int r;
+
+ if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0)
+ return r;
+ ctx->device_filter[devtype] = device_filter;
+ if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0)
+ return r;
+
+ return 0;
+}
+
+static int
+dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
+ enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IBaseFilter *device_filter = NULL;
+ IGraphBuilder *graph = ctx->graph;
+ IPin *device_pin = NULL;
+ libAVPin *capture_pin = NULL;
+ libAVFilter *capture_filter = NULL;
+ ICaptureGraphBuilder2 *graph_builder2 = NULL;
+ int ret = AVERROR(EIO);
+ int r;
+ IStream *ifile_stream = NULL;
+ IStream *ofile_stream = NULL;
+ IPersistStream *pers_stream = NULL;
+
+ const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
+
+
+ if ( ((ctx->audio_filter_load_file) && (strlen(ctx->audio_filter_load_file)>0) && (sourcetype == AudioSourceDevice)) ||
+ ((ctx->video_filter_load_file) && (strlen(ctx->video_filter_load_file)>0) && (sourcetype == VideoSourceDevice)) ) {
+ HRESULT hr;
+ char *filename = NULL;
+
+ if (sourcetype == AudioSourceDevice)
+ filename = ctx->audio_filter_load_file;
+ else
+ filename = ctx->video_filter_load_file;
+
+ hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_READ, &ifile_stream);
+ if (S_OK != hr) {
+ av_log(avctx, AV_LOG_ERROR, "Could not open capture filter description file.\n");
+ goto error;
+ }
+
+ hr = OleLoadFromStream(ifile_stream, &IID_IBaseFilter, (void **) &device_filter);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not load capture filter from file.\n");
+ goto error;
+ }
+
+ if (sourcetype == AudioSourceDevice)
+ av_log(avctx, AV_LOG_INFO, "Audio-");
+ else
+ av_log(avctx, AV_LOG_INFO, "Video-");
+ av_log(avctx, AV_LOG_INFO, "Capture filter loaded successfully from file \"%s\".\n", filename);
+ } else {
+
+ if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) {
+ ret = r;
+ goto error;
+ }
+ }
+
+ ctx->device_filter [devtype] = device_filter;
+
+ r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
+ goto error;
+ }
+
+ if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) {
+ ret = r;
+ goto error;
+ }
+
+ ctx->device_pin[devtype] = device_pin;
+
+ capture_filter = libAVFilter_Create(avctx, callback, devtype);
+ if (!capture_filter) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
+ goto error;
+ }
+ ctx->capture_filter[devtype] = capture_filter;
+
+ if ( ((ctx->audio_filter_save_file) && (strlen(ctx->audio_filter_save_file)>0) && (sourcetype == AudioSourceDevice)) ||
+ ((ctx->video_filter_save_file) && (strlen(ctx->video_filter_save_file)>0) && (sourcetype == VideoSourceDevice)) ) {
+
+ HRESULT hr;
+ char *filename = NULL;
+
+ if (sourcetype == AudioSourceDevice)
+ filename = ctx->audio_filter_save_file;
+ else
+ filename = ctx->video_filter_save_file;
+
+ hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_CREATE | STGM_READWRITE, &ofile_stream);
+ if (S_OK != hr) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create capture filter description file.\n");
+ goto error;
+ }
+
+ hr = IBaseFilter_QueryInterface(device_filter, &IID_IPersistStream, (void **) &pers_stream);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Query for IPersistStream failed.\n");
+ goto error;
+ }
+
+ hr = OleSaveToStream(pers_stream, ofile_stream);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not save capture filter \n");
+ goto error;
+ }
+
+ hr = IStream_Commit(ofile_stream, STGC_DEFAULT);
+ if (S_OK != hr) {
+ av_log(avctx, AV_LOG_ERROR, "Could not commit capture filter data to file.\n");
+ goto error;
+ }
+
+ if (sourcetype == AudioSourceDevice)
+ av_log(avctx, AV_LOG_INFO, "Audio-");
+ else
+ av_log(avctx, AV_LOG_INFO, "Video-");
+ av_log(avctx, AV_LOG_INFO, "Capture filter saved successfully to file \"%s\".\n", filename);
+ }
+
+ r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
+ filter_name[devtype]);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
+ goto error;
+ }
+
+ libAVPin_AddRef(capture_filter->pin);
+ capture_pin = capture_filter->pin;
+ ctx->capture_pin[devtype] = capture_pin;
+
+ r = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create CaptureGraphBuilder2\n");
+ goto error;
+ }
+ ICaptureGraphBuilder2_SetFiltergraph(graph_builder2, graph);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not set graph for CaptureGraphBuilder2\n");
+ goto error;
+ }
+
+ r = ICaptureGraphBuilder2_RenderStream(graph_builder2, NULL, NULL, (IUnknown *) device_pin, NULL /* no intermediate filter */,
+ (IBaseFilter *) capture_filter); /* connect pins, optionally insert intermediate filters like crossbar if necessary */
+
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not RenderStream to connect pins\n");
+ goto error;
+ }
+
+ r = dshow_try_setup_crossbar_options(graph_builder2, device_filter, devtype, avctx);
+
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not setup CrossBar\n");
+ goto error;
+ }
+
+ ret = 0;
+
+error:
+ if (graph_builder2 != NULL)
+ ICaptureGraphBuilder2_Release(graph_builder2);
+
+ if (pers_stream)
+ IPersistStream_Release(pers_stream);
+
+ if (ifile_stream)
+ IStream_Release(ifile_stream);
+
+ if (ofile_stream)
+ IStream_Release(ofile_stream);
+
+ return ret;
+}
+
+static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
+{
+ switch (sample_fmt) {
+ case AV_SAMPLE_FMT_U8: return AV_CODEC_ID_PCM_U8;
+ case AV_SAMPLE_FMT_S16: return AV_CODEC_ID_PCM_S16LE;
+ case AV_SAMPLE_FMT_S32: return AV_CODEC_ID_PCM_S32LE;
+ default: return AV_CODEC_ID_NONE; /* Should never happen. */
+ }
+}
+
+static enum AVSampleFormat sample_fmt_bits_per_sample(int bits)
+{
+ switch (bits) {
+ case 8: return AV_SAMPLE_FMT_U8;
+ case 16: return AV_SAMPLE_FMT_S16;
+ case 32: return AV_SAMPLE_FMT_S32;
+ default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
+ }
+}
+
+static int
+dshow_add_device(AVFormatContext *avctx,
+ enum dshowDeviceType devtype)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ AM_MEDIA_TYPE type;
+ AVCodecContext *codec;
+ AVStream *st;
+ int ret = AVERROR(EIO);
+
+ st = avformat_new_stream(avctx, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ st->id = devtype;
+
+ ctx->capture_filter[devtype]->stream_index = st->index;
+
+ libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
+
+ codec = st->codec;
+ if (devtype == VideoDevice) {
+ BITMAPINFOHEADER *bih = NULL;
+ AVRational time_base;
+
+ if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *v = (void *) type.pbFormat;
+ time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
+ bih = &v->bmiHeader;
+ } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
+ VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
+ time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
+ bih = &v->bmiHeader;
+ }
+ if (!bih) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
+ goto error;
+ }
+
+ codec->time_base = time_base;
+ codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ codec->width = bih->biWidth;
+ codec->height = bih->biHeight;
+ codec->codec_tag = bih->biCompression;
+ codec->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
+ if (bih->biCompression == MKTAG('H', 'D', 'Y', 'C')) {
+ av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
+ codec->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
+ }
+ if (codec->pix_fmt == AV_PIX_FMT_NONE) {
+ const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
+ codec->codec_id = av_codec_get_id(tags, bih->biCompression);
+ if (codec->codec_id == AV_CODEC_ID_NONE) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
+ "Please report type 0x%X.\n", (int) bih->biCompression);
+ return AVERROR_PATCHWELCOME;
+ }
+ codec->bits_per_coded_sample = bih->biBitCount;
+ } else {
+ codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
+ codec->bits_per_coded_sample = bih->biBitCount;
+ codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (codec->extradata) {
+ codec->extradata_size = 9;
+ memcpy(codec->extradata, "BottomUp", 9);
+ }
+ }
+ }
+ } else {
+ WAVEFORMATEX *fx = NULL;
+
+ if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
+ fx = (void *) type.pbFormat;
+ }
+ if (!fx) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
+ goto error;
+ }
+
+ codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ codec->sample_fmt = sample_fmt_bits_per_sample(fx->wBitsPerSample);
+ codec->codec_id = waveform_codec_id(codec->sample_fmt);
+ codec->sample_rate = fx->nSamplesPerSec;
+ codec->channels = fx->nChannels;
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 10000000);
+
+ ret = 0;
+
+error:
+ return ret;
+}
+
+static int parse_device_name(AVFormatContext *avctx)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ char **device_name = ctx->device_name;
+ char *name = av_strdup(avctx->filename);
+ char *tmp = name;
+ int ret = 1;
+ char *type;
+
+ while ((type = strtok(tmp, "="))) {
+ char *token = strtok(NULL, ":");
+ tmp = NULL;
+
+ if (!strcmp(type, "video")) {
+ device_name[0] = token;
+ } else if (!strcmp(type, "audio")) {
+ device_name[1] = token;
+ } else {
+ device_name[0] = NULL;
+ device_name[1] = NULL;
+ break;
+ }
+ }
+
+ if (!device_name[0] && !device_name[1]) {
+ ret = 0;
+ } else {
+ if (device_name[0])
+ device_name[0] = av_strdup(device_name[0]);
+ if (device_name[1])
+ device_name[1] = av_strdup(device_name[1]);
+ }
+
+ av_free(name);
+ return ret;
+}
+
+static int dshow_read_header(AVFormatContext *avctx)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IGraphBuilder *graph = NULL;
+ ICreateDevEnum *devenum = NULL;
+ IMediaControl *control = NULL;
+ IMediaEvent *media_event = NULL;
+ HANDLE media_event_handle;
+ HANDLE proc;
+ int ret = AVERROR(EIO);
+ int r;
+
+ CoInitialize(0);
+
+ if (!ctx->list_devices && !parse_device_name(avctx)) {
+ av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
+ goto error;
+ }
+
+ ctx->video_codec_id = avctx->video_codec_id ? avctx->video_codec_id
+ : AV_CODEC_ID_RAWVIDEO;
+ if (ctx->pixel_format != AV_PIX_FMT_NONE) {
+ if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(avctx, AV_LOG_ERROR, "Pixel format may only be set when "
+ "video codec is not set or set to rawvideo\n");
+ ret = AVERROR(EINVAL);
+ goto error;
+ }
+ }
+ if (ctx->framerate) {
+ r = av_parse_video_rate(&ctx->requested_framerate, ctx->framerate);
+ if (r < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
+ goto error;
+ }
+ }
+
+ r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IGraphBuilder, (void **) &graph);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
+ goto error;
+ }
+ ctx->graph = graph;
+
+ r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ICreateDevEnum, (void **) &devenum);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
+ goto error;
+ }
+
+ if (ctx->list_devices) {
+ av_log(avctx, AV_LOG_INFO, "DirectShow video devices (some may be both video and audio devices)\n");
+ dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL);
+ av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n");
+ dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL);
+ ret = AVERROR_EXIT;
+ goto error;
+ }
+ if (ctx->list_options) {
+ if (ctx->device_name[VideoDevice])
+ if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) {
+ ret = r;
+ goto error;
+ }
+ if (ctx->device_name[AudioDevice]) {
+ if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice)) {
+ /* show audio options from combined video+audio sources as fallback */
+ if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) {
+ ret = r;
+ goto error;
+ }
+ }
+ }
+ }
+ if (ctx->device_name[VideoDevice]) {
+ if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
+ (r = dshow_add_device(avctx, VideoDevice)) < 0) {
+ ret = r;
+ goto error;
+ }
+ }
+ if (ctx->device_name[AudioDevice]) {
+ if ((r = dshow_open_device(avctx, devenum, AudioDevice, AudioSourceDevice)) < 0 ||
+ (r = dshow_add_device(avctx, AudioDevice)) < 0) {
+ av_log(avctx, AV_LOG_INFO, "Searching for audio device within video devices for %s\n", ctx->device_name[AudioDevice]);
+ /* see if there's a video source with an audio pin with the given audio name */
+ if ((r = dshow_open_device(avctx, devenum, AudioDevice, VideoSourceDevice)) < 0 ||
+ (r = dshow_add_device(avctx, AudioDevice)) < 0) {
+ ret = r;
+ goto error;
+ }
+ }
+ }
+ if (ctx->list_options) {
+ /* allow it to list crossbar options in dshow_open_device */
+ ret = AVERROR_EXIT;
+ goto error;
+ }
+ ctx->curbufsize[0] = 0;
+ ctx->curbufsize[1] = 0;
+ ctx->mutex = CreateMutex(NULL, 0, NULL);
+ if (!ctx->mutex) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
+ goto error;
+ }
+ ctx->event[1] = CreateEvent(NULL, 1, 0, NULL);
+ if (!ctx->event[1]) {
+ av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
+ goto error;
+ }
+
+ r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
+ goto error;
+ }
+ ctx->control = control;
+
+ r = IGraphBuilder_QueryInterface(graph, &IID_IMediaEvent, (void **) &media_event);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get media event.\n");
+ goto error;
+ }
+ ctx->media_event = media_event;
+
+ r = IMediaEvent_GetEventHandle(media_event, (void *) &media_event_handle);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not get media event handle.\n");
+ goto error;
+ }
+ proc = GetCurrentProcess();
+ r = DuplicateHandle(proc, media_event_handle, proc, &ctx->event[0],
+ 0, 0, DUPLICATE_SAME_ACCESS);
+ if (!r) {
+ av_log(avctx, AV_LOG_ERROR, "Could not duplicate media event handle.\n");
+ goto error;
+ }
+
+ r = IMediaControl_Run(control);
+ if (r == S_FALSE) {
+ OAFilterState pfs;
+ r = IMediaControl_GetState(control, 0, &pfs);
+ }
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not run graph (sometimes caused by a device already in use by other application)\n");
+ goto error;
+ }
+
+ ret = 0;
+
+error:
+
+ if (devenum)
+ ICreateDevEnum_Release(devenum);
+
+ if (ret < 0)
+ dshow_read_close(avctx);
+
+ return ret;
+}
+
+/**
+ * Checks media events from DirectShow and returns -1 on error or EOF. Also
+ * purges all events that might be in the event queue to stop the trigger
+ * of event notification.
+ */
+static int dshow_check_event_queue(IMediaEvent *media_event)
+{
+ LONG_PTR p1, p2;
+ long code;
+ int ret = 0;
+
+ while (IMediaEvent_GetEvent(media_event, &code, &p1, &p2, 0) != E_ABORT) {
+ if (code == EC_COMPLETE || code == EC_DEVICE_LOST || code == EC_ERRORABORT)
+ ret = -1;
+ IMediaEvent_FreeEventParams(media_event, code, p1, p2);
+ }
+
+ return ret;
+}
+
+static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ struct dshow_ctx *ctx = s->priv_data;
+ AVPacketList *pktl = NULL;
+
+ while (!ctx->eof && !pktl) {
+ WaitForSingleObject(ctx->mutex, INFINITE);
+ pktl = ctx->pktl;
+ if (pktl) {
+ *pkt = pktl->pkt;
+ ctx->pktl = ctx->pktl->next;
+ av_free(pktl);
+ ctx->curbufsize[pkt->stream_index] -= pkt->size;
+ }
+ ResetEvent(ctx->event[1]);
+ ReleaseMutex(ctx->mutex);
+ if (!pktl) {
+ if (dshow_check_event_queue(ctx->media_event) < 0) {
+ ctx->eof = 1;
+ } else if (s->flags & AVFMT_FLAG_NONBLOCK) {
+ return AVERROR(EAGAIN);
+ } else {
+ WaitForMultipleObjects(2, ctx->event, 0, INFINITE);
+ }
+ }
+ }
+
+ return ctx->eof ? AVERROR(EIO) : pkt->size;
+}
+
+#define OFFSET(x) offsetof(struct dshow_ctx, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "video_size", "set video size given a string such as 640x480 or hd720.", OFFSET(requested_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, -1, INT_MAX, DEC },
+ { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "sample_rate", "set audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
+ { "sample_size", "set audio sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 16, DEC },
+ { "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
+ { "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
+ { "list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, DEC, "list_devices" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_devices" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_devices" },
+ { "list_options", "list available options for specified device", OFFSET(list_options), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, DEC, "list_options" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_options" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_options" },
+ { "video_device_number", "set video device number for devices with same name (starts at 0)", OFFSET(video_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
+ { "audio_device_number", "set audio device number for devices with same name (starts at 0)", OFFSET(audio_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
+ { "video_pin_name", "select video capture pin by name", OFFSET(video_pin_name),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "audio_pin_name", "select audio capture pin by name", OFFSET(audio_pin_name),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "crossbar_video_input_pin_number", "set video input pin number for crossbar device", OFFSET(crossbar_video_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
+ { "crossbar_audio_input_pin_number", "set audio input pin number for crossbar device", OFFSET(crossbar_audio_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
+ { "show_video_device_dialog", "display property dialog for video capture device", OFFSET(show_video_device_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_video_device_dialog" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_video_device_dialog" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_video_device_dialog" },
+ { "show_audio_device_dialog", "display property dialog for audio capture device", OFFSET(show_audio_device_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_audio_device_dialog" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_audio_device_dialog" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_audio_device_dialog" },
+ { "show_video_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on video device", OFFSET(show_video_crossbar_connection_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_video_crossbar_connection_dialog" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_video_crossbar_connection_dialog" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_video_crossbar_connection_dialog" },
+ { "show_audio_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on audio device", OFFSET(show_audio_crossbar_connection_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_audio_crossbar_connection_dialog" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_audio_crossbar_connection_dialog" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_audio_crossbar_connection_dialog" },
+ { "show_analog_tv_tuner_dialog", "display property dialog for analog tuner filter", OFFSET(show_analog_tv_tuner_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_analog_tv_tuner_dialog" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_analog_tv_tuner_dialog" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_analog_tv_tuner_dialog" },
+ { "show_analog_tv_tuner_audio_dialog", "display property dialog for analog tuner audio filter", OFFSET(show_analog_tv_tuner_audio_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_analog_tv_tuner_dialog" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_analog_tv_tuner_audio_dialog" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_analog_tv_tuner_audio_dialog" },
+ { "audio_device_load", "load audio capture filter device (and properties) from file", OFFSET(audio_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "audio_device_save", "save audio capture filter device (and properties) to file", OFFSET(audio_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "video_device_load", "load video capture filter device (and properties) from file", OFFSET(video_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "video_device_save", "save video capture filter device (and properties) to file", OFFSET(video_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { NULL },
+};
+
+static const AVClass dshow_class = {
+ .class_name = "dshow indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_dshow_demuxer = {
+ .name = "dshow",
+ .long_name = NULL_IF_CONFIG_SMALL("DirectShow capture"),
+ .priv_data_size = sizeof(struct dshow_ctx),
+ .read_header = dshow_read_header,
+ .read_packet = dshow_read_packet,
+ .read_close = dshow_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &dshow_class,
+};
diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h
new file mode 100644
index 0000000000..b17da10973
--- /dev/null
+++ b/libavdevice/dshow_capture.h
@@ -0,0 +1,352 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 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
+ */
+
+#ifndef AVDEVICE_DSHOW_H
+#define AVDEVICE_DSHOW_H
+
+#define DSHOWDEBUG 0
+
+#include "avdevice.h"
+
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define NO_DSHOW_STRSAFE
+#include <dshow.h>
+#include <dvdmedia.h>
+
+#include "libavcodec/internal.h"
+
+/* EC_DEVICE_LOST is not defined in MinGW dshow headers. */
+#ifndef EC_DEVICE_LOST
+#define EC_DEVICE_LOST 0x1f
+#endif
+
+long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
+void ff_print_VIDEO_STREAM_CONFIG_CAPS(const VIDEO_STREAM_CONFIG_CAPS *caps);
+void ff_print_AUDIO_STREAM_CONFIG_CAPS(const AUDIO_STREAM_CONFIG_CAPS *caps);
+void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type);
+void ff_printGUID(const GUID *g);
+
+extern const AVClass *ff_dshow_context_class_ptr;
+#define dshowdebug(...) ff_dlog(&ff_dshow_context_class_ptr, __VA_ARGS__)
+
+static inline void nothing(void *foo)
+{
+}
+
+struct GUIDoffset {
+ const GUID *iid;
+ int offset;
+};
+
+enum dshowDeviceType {
+ VideoDevice = 0,
+ AudioDevice = 1,
+};
+
+enum dshowSourceFilterType {
+ VideoSourceDevice = 0,
+ AudioSourceDevice = 1,
+};
+
+#define DECLARE_QUERYINTERFACE(class, ...) \
+long WINAPI \
+class##_QueryInterface(class *this, const GUID *riid, void **ppvObject) \
+{ \
+ struct GUIDoffset ifaces[] = __VA_ARGS__; \
+ int i; \
+ dshowdebug(AV_STRINGIFY(class)"_QueryInterface(%p, %p, %p)\n", this, riid, ppvObject); \
+ ff_printGUID(riid); \
+ if (!ppvObject) \
+ return E_POINTER; \
+ for (i = 0; i < sizeof(ifaces)/sizeof(ifaces[0]); i++) { \
+ if (IsEqualGUID(riid, ifaces[i].iid)) { \
+ void *obj = (void *) ((uint8_t *) this + ifaces[i].offset); \
+ class##_AddRef(this); \
+ dshowdebug("\tfound %d with offset %d\n", i, ifaces[i].offset); \
+ *ppvObject = (void *) obj; \
+ return S_OK; \
+ } \
+ } \
+ dshowdebug("\tE_NOINTERFACE\n"); \
+ *ppvObject = NULL; \
+ return E_NOINTERFACE; \
+}
+#define DECLARE_ADDREF(class) \
+unsigned long WINAPI \
+class##_AddRef(class *this) \
+{ \
+ dshowdebug(AV_STRINGIFY(class)"_AddRef(%p)\t%ld\n", this, this->ref+1); \
+ return InterlockedIncrement(&this->ref); \
+}
+#define DECLARE_RELEASE(class) \
+unsigned long WINAPI \
+class##_Release(class *this) \
+{ \
+ long ref = InterlockedDecrement(&this->ref); \
+ dshowdebug(AV_STRINGIFY(class)"_Release(%p)\t%ld\n", this, ref); \
+ if (!ref) \
+ class##_Destroy(this); \
+ return ref; \
+}
+
+#define DECLARE_DESTROY(class, func) \
+void class##_Destroy(class *this) \
+{ \
+ dshowdebug(AV_STRINGIFY(class)"_Destroy(%p)\n", this); \
+ func(this); \
+ if (this) { \
+ if (this->vtbl) \
+ CoTaskMemFree(this->vtbl); \
+ CoTaskMemFree(this); \
+ } \
+}
+#define DECLARE_CREATE(class, setup, ...) \
+class *class##_Create(__VA_ARGS__) \
+{ \
+ class *this = CoTaskMemAlloc(sizeof(class)); \
+ void *vtbl = CoTaskMemAlloc(sizeof(*this->vtbl)); \
+ dshowdebug(AV_STRINGIFY(class)"_Create(%p)\n", this); \
+ if (!this || !vtbl) \
+ goto fail; \
+ ZeroMemory(this, sizeof(class)); \
+ ZeroMemory(vtbl, sizeof(*this->vtbl)); \
+ this->ref = 1; \
+ this->vtbl = vtbl; \
+ if (!setup) \
+ goto fail; \
+ dshowdebug("created "AV_STRINGIFY(class)" %p\n", this); \
+ return this; \
+fail: \
+ class##_Destroy(this); \
+ dshowdebug("could not create "AV_STRINGIFY(class)"\n"); \
+ return NULL; \
+}
+
+#define SETVTBL(vtbl, class, fn) \
+ do { (vtbl)->fn = (void *) class##_##fn; } while(0)
+
+/*****************************************************************************
+ * Forward Declarations
+ ****************************************************************************/
+typedef struct libAVPin libAVPin;
+typedef struct libAVMemInputPin libAVMemInputPin;
+typedef struct libAVEnumPins libAVEnumPins;
+typedef struct libAVEnumMediaTypes libAVEnumMediaTypes;
+typedef struct libAVFilter libAVFilter;
+
+/*****************************************************************************
+ * libAVPin
+ ****************************************************************************/
+struct libAVPin {
+ IPinVtbl *vtbl;
+ long ref;
+ libAVFilter *filter;
+ IPin *connectedto;
+ AM_MEDIA_TYPE type;
+ IMemInputPinVtbl *imemvtbl;
+};
+
+long WINAPI libAVPin_QueryInterface (libAVPin *, const GUID *, void **);
+unsigned long WINAPI libAVPin_AddRef (libAVPin *);
+unsigned long WINAPI libAVPin_Release (libAVPin *);
+long WINAPI libAVPin_Connect (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
+long WINAPI libAVPin_ReceiveConnection (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
+long WINAPI libAVPin_Disconnect (libAVPin *);
+long WINAPI libAVPin_ConnectedTo (libAVPin *, IPin **);
+long WINAPI libAVPin_ConnectionMediaType (libAVPin *, AM_MEDIA_TYPE *);
+long WINAPI libAVPin_QueryPinInfo (libAVPin *, PIN_INFO *);
+long WINAPI libAVPin_QueryDirection (libAVPin *, PIN_DIRECTION *);
+long WINAPI libAVPin_QueryId (libAVPin *, wchar_t **);
+long WINAPI libAVPin_QueryAccept (libAVPin *, const AM_MEDIA_TYPE *);
+long WINAPI libAVPin_EnumMediaTypes (libAVPin *, IEnumMediaTypes **);
+long WINAPI libAVPin_QueryInternalConnections(libAVPin *, IPin **, unsigned long *);
+long WINAPI libAVPin_EndOfStream (libAVPin *);
+long WINAPI libAVPin_BeginFlush (libAVPin *);
+long WINAPI libAVPin_EndFlush (libAVPin *);
+long WINAPI libAVPin_NewSegment (libAVPin *, REFERENCE_TIME, REFERENCE_TIME, double);
+
+long WINAPI libAVMemInputPin_QueryInterface (libAVMemInputPin *, const GUID *, void **);
+unsigned long WINAPI libAVMemInputPin_AddRef (libAVMemInputPin *);
+unsigned long WINAPI libAVMemInputPin_Release (libAVMemInputPin *);
+long WINAPI libAVMemInputPin_GetAllocator (libAVMemInputPin *, IMemAllocator **);
+long WINAPI libAVMemInputPin_NotifyAllocator (libAVMemInputPin *, IMemAllocator *, BOOL);
+long WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *, ALLOCATOR_PROPERTIES *);
+long WINAPI libAVMemInputPin_Receive (libAVMemInputPin *, IMediaSample *);
+long WINAPI libAVMemInputPin_ReceiveMultiple (libAVMemInputPin *, IMediaSample **, long, long *);
+long WINAPI libAVMemInputPin_ReceiveCanBlock (libAVMemInputPin *);
+
+void libAVPin_Destroy(libAVPin *);
+libAVPin *libAVPin_Create (libAVFilter *filter);
+
+void libAVMemInputPin_Destroy(libAVMemInputPin *);
+
+/*****************************************************************************
+ * libAVEnumPins
+ ****************************************************************************/
+struct libAVEnumPins {
+ IEnumPinsVtbl *vtbl;
+ long ref;
+ int pos;
+ libAVPin *pin;
+ libAVFilter *filter;
+};
+
+long WINAPI libAVEnumPins_QueryInterface(libAVEnumPins *, const GUID *, void **);
+unsigned long WINAPI libAVEnumPins_AddRef (libAVEnumPins *);
+unsigned long WINAPI libAVEnumPins_Release (libAVEnumPins *);
+long WINAPI libAVEnumPins_Next (libAVEnumPins *, unsigned long, IPin **, unsigned long *);
+long WINAPI libAVEnumPins_Skip (libAVEnumPins *, unsigned long);
+long WINAPI libAVEnumPins_Reset (libAVEnumPins *);
+long WINAPI libAVEnumPins_Clone (libAVEnumPins *, libAVEnumPins **);
+
+void libAVEnumPins_Destroy(libAVEnumPins *);
+libAVEnumPins *libAVEnumPins_Create (libAVPin *pin, libAVFilter *filter);
+
+/*****************************************************************************
+ * libAVEnumMediaTypes
+ ****************************************************************************/
+struct libAVEnumMediaTypes {
+ IEnumMediaTypesVtbl *vtbl;
+ long ref;
+ int pos;
+ AM_MEDIA_TYPE type;
+};
+
+long WINAPI libAVEnumMediaTypes_QueryInterface(libAVEnumMediaTypes *, const GUID *, void **);
+unsigned long WINAPI libAVEnumMediaTypes_AddRef (libAVEnumMediaTypes *);
+unsigned long WINAPI libAVEnumMediaTypes_Release (libAVEnumMediaTypes *);
+long WINAPI libAVEnumMediaTypes_Next (libAVEnumMediaTypes *, unsigned long, AM_MEDIA_TYPE **, unsigned long *);
+long WINAPI libAVEnumMediaTypes_Skip (libAVEnumMediaTypes *, unsigned long);
+long WINAPI libAVEnumMediaTypes_Reset (libAVEnumMediaTypes *);
+long WINAPI libAVEnumMediaTypes_Clone (libAVEnumMediaTypes *, libAVEnumMediaTypes **);
+
+void libAVEnumMediaTypes_Destroy(libAVEnumMediaTypes *);
+libAVEnumMediaTypes *libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type);
+
+/*****************************************************************************
+ * libAVFilter
+ ****************************************************************************/
+struct libAVFilter {
+ IBaseFilterVtbl *vtbl;
+ long ref;
+ const wchar_t *name;
+ libAVPin *pin;
+ FILTER_INFO info;
+ FILTER_STATE state;
+ IReferenceClock *clock;
+ enum dshowDeviceType type;
+ void *priv_data;
+ int stream_index;
+ int64_t start_time;
+ void (*callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType type);
+};
+
+long WINAPI libAVFilter_QueryInterface (libAVFilter *, const GUID *, void **);
+unsigned long WINAPI libAVFilter_AddRef (libAVFilter *);
+unsigned long WINAPI libAVFilter_Release (libAVFilter *);
+long WINAPI libAVFilter_GetClassID (libAVFilter *, CLSID *);
+long WINAPI libAVFilter_Stop (libAVFilter *);
+long WINAPI libAVFilter_Pause (libAVFilter *);
+long WINAPI libAVFilter_Run (libAVFilter *, REFERENCE_TIME);
+long WINAPI libAVFilter_GetState (libAVFilter *, DWORD, FILTER_STATE *);
+long WINAPI libAVFilter_SetSyncSource (libAVFilter *, IReferenceClock *);
+long WINAPI libAVFilter_GetSyncSource (libAVFilter *, IReferenceClock **);
+long WINAPI libAVFilter_EnumPins (libAVFilter *, IEnumPins **);
+long WINAPI libAVFilter_FindPin (libAVFilter *, const wchar_t *, IPin **);
+long WINAPI libAVFilter_QueryFilterInfo(libAVFilter *, FILTER_INFO *);
+long WINAPI libAVFilter_JoinFilterGraph(libAVFilter *, IFilterGraph *, const wchar_t *);
+long WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
+
+void libAVFilter_Destroy(libAVFilter *);
+libAVFilter *libAVFilter_Create (void *, void *, enum dshowDeviceType);
+
+/*****************************************************************************
+ * dshow_ctx
+ ****************************************************************************/
+struct dshow_ctx {
+ const AVClass *class;
+
+ IGraphBuilder *graph;
+
+ char *device_name[2];
+ int video_device_number;
+ int audio_device_number;
+
+ int list_options;
+ int list_devices;
+ int audio_buffer_size;
+ int crossbar_video_input_pin_number;
+ int crossbar_audio_input_pin_number;
+ char *video_pin_name;
+ char *audio_pin_name;
+ int show_video_device_dialog;
+ int show_audio_device_dialog;
+ int show_video_crossbar_connection_dialog;
+ int show_audio_crossbar_connection_dialog;
+ int show_analog_tv_tuner_dialog;
+ int show_analog_tv_tuner_audio_dialog;
+ char *audio_filter_load_file;
+ char *audio_filter_save_file;
+ char *video_filter_load_file;
+ char *video_filter_save_file;
+
+ IBaseFilter *device_filter[2];
+ IPin *device_pin[2];
+ libAVFilter *capture_filter[2];
+ libAVPin *capture_pin[2];
+
+ HANDLE mutex;
+ HANDLE event[2]; /* event[0] is set by DirectShow
+ * event[1] is set by callback() */
+ AVPacketList *pktl;
+
+ int eof;
+
+ int64_t curbufsize[2];
+ unsigned int video_frame_num;
+
+ IMediaControl *control;
+ IMediaEvent *media_event;
+
+ enum AVPixelFormat pixel_format;
+ enum AVCodecID video_codec_id;
+ char *framerate;
+
+ int requested_width;
+ int requested_height;
+ AVRational requested_framerate;
+
+ int sample_rate;
+ int sample_size;
+ int channels;
+};
+
+/*****************************************************************************
+ * CrossBar
+ ****************************************************************************/
+HRESULT dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
+ IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx);
+
+void dshow_show_filter_properties(IBaseFilter *pFilter, AVFormatContext *avctx);
+
+#endif /* AVDEVICE_DSHOW_H */
diff --git a/libavdevice/dshow_common.c b/libavdevice/dshow_common.c
new file mode 100644
index 0000000000..f7f0dfbdbb
--- /dev/null
+++ b/libavdevice/dshow_common.c
@@ -0,0 +1,190 @@
+/*
+ * Directshow capture interface
+ * Copyright (c) 2010 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 "dshow_capture.h"
+
+long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src)
+{
+ uint8_t *pbFormat = NULL;
+
+ if (src->cbFormat) {
+ pbFormat = CoTaskMemAlloc(src->cbFormat);
+ if (!pbFormat)
+ return E_OUTOFMEMORY;
+ memcpy(pbFormat, src->pbFormat, src->cbFormat);
+ }
+
+ *dst = *src;
+ dst->pUnk = NULL;
+ dst->pbFormat = pbFormat;
+
+ return S_OK;
+}
+
+void ff_printGUID(const GUID *g)
+{
+#if DSHOWDEBUG
+ const uint32_t *d = (const uint32_t *) &g->Data1;
+ const uint16_t *w = (const uint16_t *) &g->Data2;
+ const uint8_t *c = (const uint8_t *) &g->Data4;
+
+ dshowdebug("0x%08x 0x%04x 0x%04x %02x%02x%02x%02x%02x%02x%02x%02x",
+ d[0], w[0], w[1],
+ c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+#endif
+}
+
+static const char *dshow_context_to_name(void *ptr)
+{
+ return "dshow";
+}
+static const AVClass ff_dshow_context_class = { "DirectShow", dshow_context_to_name };
+const AVClass *ff_dshow_context_class_ptr = &ff_dshow_context_class;
+
+#define dstruct(pctx, sname, var, type) \
+ dshowdebug(" "#var":\t%"type"\n", sname->var)
+
+#if DSHOWDEBUG
+static void dump_bih(void *s, BITMAPINFOHEADER *bih)
+{
+ dshowdebug(" BITMAPINFOHEADER\n");
+ dstruct(s, bih, biSize, "lu");
+ dstruct(s, bih, biWidth, "ld");
+ dstruct(s, bih, biHeight, "ld");
+ dstruct(s, bih, biPlanes, "d");
+ dstruct(s, bih, biBitCount, "d");
+ dstruct(s, bih, biCompression, "lu");
+ dshowdebug(" biCompression:\t\"%.4s\"\n",
+ (char*) &bih->biCompression);
+ dstruct(s, bih, biSizeImage, "lu");
+ dstruct(s, bih, biXPelsPerMeter, "lu");
+ dstruct(s, bih, biYPelsPerMeter, "lu");
+ dstruct(s, bih, biClrUsed, "lu");
+ dstruct(s, bih, biClrImportant, "lu");
+}
+#endif
+
+void ff_print_VIDEO_STREAM_CONFIG_CAPS(const VIDEO_STREAM_CONFIG_CAPS *caps)
+{
+#if DSHOWDEBUG
+ dshowdebug(" VIDEO_STREAM_CONFIG_CAPS\n");
+ dshowdebug(" guid\t");
+ ff_printGUID(&caps->guid);
+ dshowdebug("\n");
+ dshowdebug(" VideoStandard\t%lu\n", caps->VideoStandard);
+ dshowdebug(" InputSize %ld\t%ld\n", caps->InputSize.cx, caps->InputSize.cy);
+ dshowdebug(" MinCroppingSize %ld\t%ld\n", caps->MinCroppingSize.cx, caps->MinCroppingSize.cy);
+ dshowdebug(" MaxCroppingSize %ld\t%ld\n", caps->MaxCroppingSize.cx, caps->MaxCroppingSize.cy);
+ dshowdebug(" CropGranularityX\t%d\n", caps->CropGranularityX);
+ dshowdebug(" CropGranularityY\t%d\n", caps->CropGranularityY);
+ dshowdebug(" CropAlignX\t%d\n", caps->CropAlignX);
+ dshowdebug(" CropAlignY\t%d\n", caps->CropAlignY);
+ dshowdebug(" MinOutputSize %ld\t%ld\n", caps->MinOutputSize.cx, caps->MinOutputSize.cy);
+ dshowdebug(" MaxOutputSize %ld\t%ld\n", caps->MaxOutputSize.cx, caps->MaxOutputSize.cy);
+ dshowdebug(" OutputGranularityX\t%d\n", caps->OutputGranularityX);
+ dshowdebug(" OutputGranularityY\t%d\n", caps->OutputGranularityY);
+ dshowdebug(" StretchTapsX\t%d\n", caps->StretchTapsX);
+ dshowdebug(" StretchTapsY\t%d\n", caps->StretchTapsY);
+ dshowdebug(" ShrinkTapsX\t%d\n", caps->ShrinkTapsX);
+ dshowdebug(" ShrinkTapsY\t%d\n", caps->ShrinkTapsY);
+ dshowdebug(" MinFrameInterval\t%"PRId64"\n", caps->MinFrameInterval);
+ dshowdebug(" MaxFrameInterval\t%"PRId64"\n", caps->MaxFrameInterval);
+ dshowdebug(" MinBitsPerSecond\t%ld\n", caps->MinBitsPerSecond);
+ dshowdebug(" MaxBitsPerSecond\t%ld\n", caps->MaxBitsPerSecond);
+#endif
+}
+
+void ff_print_AUDIO_STREAM_CONFIG_CAPS(const AUDIO_STREAM_CONFIG_CAPS *caps)
+{
+#if DSHOWDEBUG
+ dshowdebug(" AUDIO_STREAM_CONFIG_CAPS\n");
+ dshowdebug(" guid\t");
+ ff_printGUID(&caps->guid);
+ dshowdebug("\n");
+ dshowdebug(" MinimumChannels\t%lu\n", caps->MinimumChannels);
+ dshowdebug(" MaximumChannels\t%lu\n", caps->MaximumChannels);
+ dshowdebug(" ChannelsGranularity\t%lu\n", caps->ChannelsGranularity);
+ dshowdebug(" MinimumBitsPerSample\t%lu\n", caps->MinimumBitsPerSample);
+ dshowdebug(" MaximumBitsPerSample\t%lu\n", caps->MaximumBitsPerSample);
+ dshowdebug(" BitsPerSampleGranularity\t%lu\n", caps->BitsPerSampleGranularity);
+ dshowdebug(" MinimumSampleFrequency\t%lu\n", caps->MinimumSampleFrequency);
+ dshowdebug(" MaximumSampleFrequency\t%lu\n", caps->MaximumSampleFrequency);
+ dshowdebug(" SampleFrequencyGranularity\t%lu\n", caps->SampleFrequencyGranularity);
+#endif
+}
+
+void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
+{
+#if DSHOWDEBUG
+ dshowdebug(" majortype\t");
+ ff_printGUID(&type->majortype);
+ dshowdebug("\n");
+ dshowdebug(" subtype\t");
+ ff_printGUID(&type->subtype);
+ dshowdebug("\n");
+ dshowdebug(" bFixedSizeSamples\t%d\n", type->bFixedSizeSamples);
+ dshowdebug(" bTemporalCompression\t%d\n", type->bTemporalCompression);
+ dshowdebug(" lSampleSize\t%lu\n", type->lSampleSize);
+ dshowdebug(" formattype\t");
+ ff_printGUID(&type->formattype);
+ dshowdebug("\n");
+ dshowdebug(" pUnk\t%p\n", type->pUnk);
+ dshowdebug(" cbFormat\t%lu\n", type->cbFormat);
+ dshowdebug(" pbFormat\t%p\n", type->pbFormat);
+
+ if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *v = (void *) type->pbFormat;
+ dshowdebug(" rcSource: left %ld top %ld right %ld bottom %ld\n",
+ v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
+ dshowdebug(" rcTarget: left %ld top %ld right %ld bottom %ld\n",
+ v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
+ dshowdebug(" dwBitRate: %lu\n", v->dwBitRate);
+ dshowdebug(" dwBitErrorRate: %lu\n", v->dwBitErrorRate);
+ dshowdebug(" AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
+ dump_bih(NULL, &v->bmiHeader);
+ } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
+ VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
+ dshowdebug(" rcSource: left %ld top %ld right %ld bottom %ld\n",
+ v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
+ dshowdebug(" rcTarget: left %ld top %ld right %ld bottom %ld\n",
+ v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
+ dshowdebug(" dwBitRate: %lu\n", v->dwBitRate);
+ dshowdebug(" dwBitErrorRate: %lu\n", v->dwBitErrorRate);
+ dshowdebug(" AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
+ dshowdebug(" dwInterlaceFlags: %lu\n", v->dwInterlaceFlags);
+ dshowdebug(" dwCopyProtectFlags: %lu\n", v->dwCopyProtectFlags);
+ dshowdebug(" dwPictAspectRatioX: %lu\n", v->dwPictAspectRatioX);
+ dshowdebug(" dwPictAspectRatioY: %lu\n", v->dwPictAspectRatioY);
+// dshowdebug(" dwReserved1: %lu\n", v->u.dwReserved1); /* mingw-w64 is buggy and doesn't name unnamed unions */
+ dshowdebug(" dwReserved2: %lu\n", v->dwReserved2);
+ dump_bih(NULL, &v->bmiHeader);
+ } else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
+ WAVEFORMATEX *fx = (void *) type->pbFormat;
+ dshowdebug(" wFormatTag: %u\n", fx->wFormatTag);
+ dshowdebug(" nChannels: %u\n", fx->nChannels);
+ dshowdebug(" nSamplesPerSec: %lu\n", fx->nSamplesPerSec);
+ dshowdebug(" nAvgBytesPerSec: %lu\n", fx->nAvgBytesPerSec);
+ dshowdebug(" nBlockAlign: %u\n", fx->nBlockAlign);
+ dshowdebug(" wBitsPerSample: %u\n", fx->wBitsPerSample);
+ dshowdebug(" cbSize: %u\n", fx->cbSize);
+ }
+#endif
+}
diff --git a/libavdevice/dshow_crossbar.c b/libavdevice/dshow_crossbar.c
new file mode 100644
index 0000000000..c0739da318
--- /dev/null
+++ b/libavdevice/dshow_crossbar.c
@@ -0,0 +1,208 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2015 Roger Pack
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "dshow_capture.h"
+
+static const char *
+GetPhysicalPinName(long pin_type)
+{
+ switch (pin_type)
+ {
+ case PhysConn_Video_Tuner: return "Video Tuner";
+ case PhysConn_Video_Composite: return "Video Composite";
+ case PhysConn_Video_SVideo: return "S-Video";
+ case PhysConn_Video_RGB: return "Video RGB";
+ case PhysConn_Video_YRYBY: return "Video YRYBY";
+ case PhysConn_Video_SerialDigital: return "Video Serial Digital";
+ case PhysConn_Video_ParallelDigital: return "Video Parallel Digital";
+ case PhysConn_Video_SCSI: return "Video SCSI";
+ case PhysConn_Video_AUX: return "Video AUX";
+ case PhysConn_Video_1394: return "Video 1394";
+ case PhysConn_Video_USB: return "Video USB";
+ case PhysConn_Video_VideoDecoder: return "Video Decoder";
+ case PhysConn_Video_VideoEncoder: return "Video Encoder";
+
+ case PhysConn_Audio_Tuner: return "Audio Tuner";
+ case PhysConn_Audio_Line: return "Audio Line";
+ case PhysConn_Audio_Mic: return "Audio Microphone";
+ case PhysConn_Audio_AESDigital: return "Audio AES/EBU Digital";
+ case PhysConn_Audio_SPDIFDigital: return "Audio S/PDIF";
+ case PhysConn_Audio_SCSI: return "Audio SCSI";
+ case PhysConn_Audio_AUX: return "Audio AUX";
+ case PhysConn_Audio_1394: return "Audio 1394";
+ case PhysConn_Audio_USB: return "Audio USB";
+ case PhysConn_Audio_AudioDecoder: return "Audio Decoder";
+ default: return "Unknown Crossbar Pin Type—Please report!";
+ }
+}
+
+static HRESULT
+setup_crossbar_options(IAMCrossbar *cross_bar, enum dshowDeviceType devtype, AVFormatContext *avctx)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ long count_output_pins, count_input_pins;
+ int i;
+ int log_level = ctx->list_options ? AV_LOG_INFO : AV_LOG_DEBUG;
+ int video_input_pin = ctx->crossbar_video_input_pin_number;
+ int audio_input_pin = ctx->crossbar_audio_input_pin_number;
+ const char *device_name = ctx->device_name[devtype];
+ HRESULT hr;
+
+ av_log(avctx, log_level, "Crossbar Switching Information for %s:\n", device_name);
+ hr = IAMCrossbar_get_PinCounts(cross_bar, &count_output_pins, &count_input_pins);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar pin counts\n");
+ return hr;
+ }
+
+ for (i = 0; i < count_output_pins; i++)
+ {
+ int j;
+ long related_pin, pin_type, route_to_pin;
+ hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, FALSE, i, &related_pin, &pin_type);
+ if (pin_type == PhysConn_Video_VideoDecoder) {
+ /* assume there is only one "Video (and one Audio) Decoder" output pin, and it's all we care about routing to...for now */
+ if (video_input_pin != -1) {
+ av_log(avctx, log_level, "Routing video input from pin %d\n", video_input_pin);
+ hr = IAMCrossbar_Route(cross_bar, i, video_input_pin);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to route video input from pin %d\n", video_input_pin);
+ return AVERROR(EIO);
+ }
+ }
+ } else if (pin_type == PhysConn_Audio_AudioDecoder) {
+ if (audio_input_pin != -1) {
+ av_log(avctx, log_level, "Routing audio input from pin %d\n", audio_input_pin);
+ hr = IAMCrossbar_Route(cross_bar, i, audio_input_pin);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to route audio input from pin %d\n", audio_input_pin);
+ return hr;
+ }
+ }
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "Unexpected output pin type, please report the type if you want to use this (%s)", GetPhysicalPinName(pin_type));
+ }
+
+ hr = IAMCrossbar_get_IsRoutedTo(cross_bar, i, &route_to_pin);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar is routed to from pin %d\n", i);
+ return hr;
+ }
+ av_log(avctx, log_level, " Crossbar Output pin %d: \"%s\" related output pin: %ld ", i, GetPhysicalPinName(pin_type), related_pin);
+ av_log(avctx, log_level, "current input pin: %ld ", route_to_pin);
+ av_log(avctx, log_level, "compatible input pins: ");
+
+ for (j = 0; j < count_input_pins; j++)
+ {
+ hr = IAMCrossbar_CanRoute(cross_bar, i, j);
+ if (hr == S_OK)
+ av_log(avctx, log_level ,"%d ", j);
+ }
+ av_log(avctx, log_level, "\n");
+ }
+
+ for (i = 0; i < count_input_pins; i++)
+ {
+ long related_pin, pin_type;
+ hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, TRUE, i, &related_pin, &pin_type);
+ if (hr != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "unable to get crossbar info audio input from pin %d\n", i);
+ return hr;
+ }
+ av_log(avctx, log_level, " Crossbar Input pin %d - \"%s\" ", i, GetPhysicalPinName(pin_type));
+ av_log(avctx, log_level, "related input pin: %ld\n", related_pin);
+ }
+ return S_OK;
+}
+
+/**
+ * Given a fully constructed graph, check if there is a cross bar filter, and configure its pins if so.
+ */
+HRESULT
+dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
+ IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IAMCrossbar *cross_bar = NULL;
+ IBaseFilter *cross_bar_base_filter = NULL;
+ IAMTVTuner *tv_tuner_filter = NULL;
+ IBaseFilter *tv_tuner_base_filter = NULL;
+ IAMAudioInputMixer *tv_audio_filter = NULL;
+ IBaseFilter *tv_audio_base_filter = NULL;
+ HRESULT hr;
+
+ hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, (const GUID *) NULL,
+ device_filter, &IID_IAMCrossbar, (void**) &cross_bar);
+ if (hr != S_OK) {
+ /* no crossbar found */
+ hr = S_OK;
+ goto end;
+ }
+ /* TODO some TV tuners apparently have multiple crossbars? */
+
+ if (devtype == VideoDevice && ctx->show_video_crossbar_connection_dialog ||
+ devtype == AudioDevice && ctx->show_audio_crossbar_connection_dialog) {
+ hr = IAMCrossbar_QueryInterface(cross_bar, &IID_IBaseFilter, (void **) &cross_bar_base_filter);
+ if (hr != S_OK)
+ goto end;
+ dshow_show_filter_properties(cross_bar_base_filter, avctx);
+ }
+
+ if (devtype == VideoDevice && ctx->show_analog_tv_tuner_dialog) {
+ hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, NULL,
+ device_filter, &IID_IAMTVTuner, (void**) &tv_tuner_filter);
+ if (hr == S_OK) {
+ hr = IAMCrossbar_QueryInterface(tv_tuner_filter, &IID_IBaseFilter, (void **) &tv_tuner_base_filter);
+ if (hr != S_OK)
+ goto end;
+ dshow_show_filter_properties(tv_tuner_base_filter, avctx);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "unable to find a tv tuner to display dialog for!");
+ }
+ }
+ if (devtype == AudioDevice && ctx->show_analog_tv_tuner_audio_dialog) {
+ hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, NULL,
+ device_filter, &IID_IAMTVAudio, (void**) &tv_audio_filter);
+ if (hr == S_OK) {
+ hr = IAMCrossbar_QueryInterface(tv_audio_filter, &IID_IBaseFilter, (void **) &tv_audio_base_filter);
+ if (hr != S_OK)
+ goto end;
+ dshow_show_filter_properties(tv_audio_base_filter, avctx);
+ } else {
+ av_log(avctx, AV_LOG_WARNING, "unable to find a tv audio tuner to display dialog for!");
+ }
+ }
+
+ hr = setup_crossbar_options(cross_bar, devtype, avctx);
+ if (hr != S_OK)
+ goto end;
+
+end:
+ if (cross_bar)
+ IAMCrossbar_Release(cross_bar);
+ if (cross_bar_base_filter)
+ IBaseFilter_Release(cross_bar_base_filter);
+ if (tv_tuner_filter)
+ IAMTVTuner_Release(tv_tuner_filter);
+ if (tv_tuner_base_filter)
+ IBaseFilter_Release(tv_tuner_base_filter);
+ return hr;
+}
diff --git a/libavdevice/dshow_enummediatypes.c b/libavdevice/dshow_enummediatypes.c
new file mode 100644
index 0000000000..5b69a5b742
--- /dev/null
+++ b/libavdevice/dshow_enummediatypes.c
@@ -0,0 +1,103 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 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 "dshow_capture.h"
+
+DECLARE_QUERYINTERFACE(libAVEnumMediaTypes,
+ { {&IID_IUnknown,0}, {&IID_IEnumMediaTypes,0} })
+DECLARE_ADDREF(libAVEnumMediaTypes)
+DECLARE_RELEASE(libAVEnumMediaTypes)
+
+long WINAPI
+libAVEnumMediaTypes_Next(libAVEnumMediaTypes *this, unsigned long n,
+ AM_MEDIA_TYPE **types, unsigned long *fetched)
+{
+ int count = 0;
+ dshowdebug("libAVEnumMediaTypes_Next(%p)\n", this);
+ if (!types)
+ return E_POINTER;
+ if (!this->pos && n == 1) {
+ if (!IsEqualGUID(&this->type.majortype, &GUID_NULL)) {
+ AM_MEDIA_TYPE *type = av_malloc(sizeof(AM_MEDIA_TYPE));
+ ff_copy_dshow_media_type(type, &this->type);
+ *types = type;
+ count = 1;
+ }
+ this->pos = 1;
+ }
+ if (fetched)
+ *fetched = count;
+ if (!count)
+ return S_FALSE;
+ return S_OK;
+}
+long WINAPI
+libAVEnumMediaTypes_Skip(libAVEnumMediaTypes *this, unsigned long n)
+{
+ dshowdebug("libAVEnumMediaTypes_Skip(%p)\n", this);
+ if (n) /* Any skip will always fall outside of the only valid type. */
+ return S_FALSE;
+ return S_OK;
+}
+long WINAPI
+libAVEnumMediaTypes_Reset(libAVEnumMediaTypes *this)
+{
+ dshowdebug("libAVEnumMediaTypes_Reset(%p)\n", this);
+ this->pos = 0;
+ return S_OK;
+}
+long WINAPI
+libAVEnumMediaTypes_Clone(libAVEnumMediaTypes *this, libAVEnumMediaTypes **enums)
+{
+ libAVEnumMediaTypes *new;
+ dshowdebug("libAVEnumMediaTypes_Clone(%p)\n", this);
+ if (!enums)
+ return E_POINTER;
+ new = libAVEnumMediaTypes_Create(&this->type);
+ if (!new)
+ return E_OUTOFMEMORY;
+ new->pos = this->pos;
+ *enums = new;
+ return S_OK;
+}
+
+static int
+libAVEnumMediaTypes_Setup(libAVEnumMediaTypes *this, const AM_MEDIA_TYPE *type)
+{
+ IEnumMediaTypesVtbl *vtbl = this->vtbl;
+ SETVTBL(vtbl, libAVEnumMediaTypes, QueryInterface);
+ SETVTBL(vtbl, libAVEnumMediaTypes, AddRef);
+ SETVTBL(vtbl, libAVEnumMediaTypes, Release);
+ SETVTBL(vtbl, libAVEnumMediaTypes, Next);
+ SETVTBL(vtbl, libAVEnumMediaTypes, Skip);
+ SETVTBL(vtbl, libAVEnumMediaTypes, Reset);
+ SETVTBL(vtbl, libAVEnumMediaTypes, Clone);
+
+ if (!type) {
+ this->type.majortype = GUID_NULL;
+ } else {
+ ff_copy_dshow_media_type(&this->type, type);
+ }
+
+ return 1;
+}
+DECLARE_CREATE(libAVEnumMediaTypes, libAVEnumMediaTypes_Setup(this, type), const AM_MEDIA_TYPE *type)
+DECLARE_DESTROY(libAVEnumMediaTypes, nothing)
diff --git a/libavdevice/dshow_enumpins.c b/libavdevice/dshow_enumpins.c
new file mode 100644
index 0000000000..e5c11cb54e
--- /dev/null
+++ b/libavdevice/dshow_enumpins.c
@@ -0,0 +1,105 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 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 "dshow_capture.h"
+
+DECLARE_QUERYINTERFACE(libAVEnumPins,
+ { {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
+DECLARE_ADDREF(libAVEnumPins)
+DECLARE_RELEASE(libAVEnumPins)
+
+long WINAPI
+libAVEnumPins_Next(libAVEnumPins *this, unsigned long n, IPin **pins,
+ unsigned long *fetched)
+{
+ int count = 0;
+ dshowdebug("libAVEnumPins_Next(%p)\n", this);
+ if (!pins)
+ return E_POINTER;
+ if (!this->pos && n == 1) {
+ libAVPin_AddRef(this->pin);
+ *pins = (IPin *) this->pin;
+ count = 1;
+ this->pos = 1;
+ }
+ if (fetched)
+ *fetched = count;
+ if (!count)
+ return S_FALSE;
+ return S_OK;
+}
+long WINAPI
+libAVEnumPins_Skip(libAVEnumPins *this, unsigned long n)
+{
+ dshowdebug("libAVEnumPins_Skip(%p)\n", this);
+ if (n) /* Any skip will always fall outside of the only valid pin. */
+ return S_FALSE;
+ return S_OK;
+}
+long WINAPI
+libAVEnumPins_Reset(libAVEnumPins *this)
+{
+ dshowdebug("libAVEnumPins_Reset(%p)\n", this);
+ this->pos = 0;
+ return S_OK;
+}
+long WINAPI
+libAVEnumPins_Clone(libAVEnumPins *this, libAVEnumPins **pins)
+{
+ libAVEnumPins *new;
+ dshowdebug("libAVEnumPins_Clone(%p)\n", this);
+ if (!pins)
+ return E_POINTER;
+ new = libAVEnumPins_Create(this->pin, this->filter);
+ if (!new)
+ return E_OUTOFMEMORY;
+ new->pos = this->pos;
+ *pins = new;
+ return S_OK;
+}
+
+static int
+libAVEnumPins_Setup(libAVEnumPins *this, libAVPin *pin, libAVFilter *filter)
+{
+ IEnumPinsVtbl *vtbl = this->vtbl;
+ SETVTBL(vtbl, libAVEnumPins, QueryInterface);
+ SETVTBL(vtbl, libAVEnumPins, AddRef);
+ SETVTBL(vtbl, libAVEnumPins, Release);
+ SETVTBL(vtbl, libAVEnumPins, Next);
+ SETVTBL(vtbl, libAVEnumPins, Skip);
+ SETVTBL(vtbl, libAVEnumPins, Reset);
+ SETVTBL(vtbl, libAVEnumPins, Clone);
+
+ this->pin = pin;
+ this->filter = filter;
+ libAVFilter_AddRef(this->filter);
+
+ return 1;
+}
+static int
+libAVEnumPins_Cleanup(libAVEnumPins *this)
+{
+ libAVFilter_Release(this->filter);
+ return 1;
+}
+DECLARE_CREATE(libAVEnumPins, libAVEnumPins_Setup(this, pin, filter),
+ libAVPin *pin, libAVFilter *filter)
+DECLARE_DESTROY(libAVEnumPins, libAVEnumPins_Cleanup)
diff --git a/libavdevice/dshow_filter.c b/libavdevice/dshow_filter.c
new file mode 100644
index 0000000000..7360adcfcd
--- /dev/null
+++ b/libavdevice/dshow_filter.c
@@ -0,0 +1,202 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 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 "dshow_capture.h"
+
+DECLARE_QUERYINTERFACE(libAVFilter,
+ { {&IID_IUnknown,0}, {&IID_IBaseFilter,0} })
+DECLARE_ADDREF(libAVFilter)
+DECLARE_RELEASE(libAVFilter)
+
+long WINAPI
+libAVFilter_GetClassID(libAVFilter *this, CLSID *id)
+{
+ dshowdebug("libAVFilter_GetClassID(%p)\n", this);
+ /* I'm not creating a ClassID just for this. */
+ return E_FAIL;
+}
+long WINAPI
+libAVFilter_Stop(libAVFilter *this)
+{
+ dshowdebug("libAVFilter_Stop(%p)\n", this);
+ this->state = State_Stopped;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_Pause(libAVFilter *this)
+{
+ dshowdebug("libAVFilter_Pause(%p)\n", this);
+ this->state = State_Paused;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_Run(libAVFilter *this, REFERENCE_TIME start)
+{
+ dshowdebug("libAVFilter_Run(%p) %"PRId64"\n", this, start);
+ this->state = State_Running;
+ this->start_time = start;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_GetState(libAVFilter *this, DWORD ms, FILTER_STATE *state)
+{
+ dshowdebug("libAVFilter_GetState(%p)\n", this);
+ if (!state)
+ return E_POINTER;
+ *state = this->state;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_SetSyncSource(libAVFilter *this, IReferenceClock *clock)
+{
+ dshowdebug("libAVFilter_SetSyncSource(%p)\n", this);
+
+ if (this->clock != clock) {
+ if (this->clock)
+ IReferenceClock_Release(this->clock);
+ this->clock = clock;
+ if (clock)
+ IReferenceClock_AddRef(clock);
+ }
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_GetSyncSource(libAVFilter *this, IReferenceClock **clock)
+{
+ dshowdebug("libAVFilter_GetSyncSource(%p)\n", this);
+
+ if (!clock)
+ return E_POINTER;
+ if (this->clock)
+ IReferenceClock_AddRef(this->clock);
+ *clock = this->clock;
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_EnumPins(libAVFilter *this, IEnumPins **enumpin)
+{
+ libAVEnumPins *new;
+ dshowdebug("libAVFilter_EnumPins(%p)\n", this);
+
+ if (!enumpin)
+ return E_POINTER;
+ new = libAVEnumPins_Create(this->pin, this);
+ if (!new)
+ return E_OUTOFMEMORY;
+
+ *enumpin = (IEnumPins *) new;
+ return S_OK;
+}
+long WINAPI
+libAVFilter_FindPin(libAVFilter *this, const wchar_t *id, IPin **pin)
+{
+ libAVPin *found = NULL;
+ dshowdebug("libAVFilter_FindPin(%p)\n", this);
+
+ if (!id || !pin)
+ return E_POINTER;
+ if (!wcscmp(id, L"In")) {
+ found = this->pin;
+ libAVPin_AddRef(found);
+ }
+ *pin = (IPin *) found;
+ if (!found)
+ return VFW_E_NOT_FOUND;
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_QueryFilterInfo(libAVFilter *this, FILTER_INFO *info)
+{
+ dshowdebug("libAVFilter_QueryFilterInfo(%p)\n", this);
+
+ if (!info)
+ return E_POINTER;
+ if (this->info.pGraph)
+ IFilterGraph_AddRef(this->info.pGraph);
+ *info = this->info;
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_JoinFilterGraph(libAVFilter *this, IFilterGraph *graph,
+ const wchar_t *name)
+{
+ dshowdebug("libAVFilter_JoinFilterGraph(%p)\n", this);
+
+ this->info.pGraph = graph;
+ if (name)
+ wcscpy(this->info.achName, name);
+
+ return S_OK;
+}
+long WINAPI
+libAVFilter_QueryVendorInfo(libAVFilter *this, wchar_t **info)
+{
+ dshowdebug("libAVFilter_QueryVendorInfo(%p)\n", this);
+
+ if (!info)
+ return E_POINTER;
+ *info = wcsdup(L"libAV");
+
+ return S_OK;
+}
+
+static int
+libAVFilter_Setup(libAVFilter *this, void *priv_data, void *callback,
+ enum dshowDeviceType type)
+{
+ IBaseFilterVtbl *vtbl = this->vtbl;
+ SETVTBL(vtbl, libAVFilter, QueryInterface);
+ SETVTBL(vtbl, libAVFilter, AddRef);
+ SETVTBL(vtbl, libAVFilter, Release);
+ SETVTBL(vtbl, libAVFilter, GetClassID);
+ SETVTBL(vtbl, libAVFilter, Stop);
+ SETVTBL(vtbl, libAVFilter, Pause);
+ SETVTBL(vtbl, libAVFilter, Run);
+ SETVTBL(vtbl, libAVFilter, GetState);
+ SETVTBL(vtbl, libAVFilter, SetSyncSource);
+ SETVTBL(vtbl, libAVFilter, GetSyncSource);
+ SETVTBL(vtbl, libAVFilter, EnumPins);
+ SETVTBL(vtbl, libAVFilter, FindPin);
+ SETVTBL(vtbl, libAVFilter, QueryFilterInfo);
+ SETVTBL(vtbl, libAVFilter, JoinFilterGraph);
+ SETVTBL(vtbl, libAVFilter, QueryVendorInfo);
+
+ this->pin = libAVPin_Create(this);
+
+ this->priv_data = priv_data;
+ this->callback = callback;
+ this->type = type;
+
+ return 1;
+}
+static int
+libAVFilter_Cleanup(libAVFilter *this)
+{
+ libAVPin_Release(this->pin);
+ return 1;
+}
+DECLARE_CREATE(libAVFilter, libAVFilter_Setup(this, priv_data, callback, type),
+ void *priv_data, void *callback, enum dshowDeviceType type)
+DECLARE_DESTROY(libAVFilter, libAVFilter_Cleanup)
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c
new file mode 100644
index 0000000000..4f719a660e
--- /dev/null
+++ b/libavdevice/dshow_pin.c
@@ -0,0 +1,376 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 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 "dshow_capture.h"
+
+#include <stddef.h>
+#define imemoffset offsetof(libAVPin, imemvtbl)
+
+DECLARE_QUERYINTERFACE(libAVPin,
+ { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
+DECLARE_ADDREF(libAVPin)
+DECLARE_RELEASE(libAVPin)
+
+long WINAPI
+libAVPin_Connect(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
+{
+ dshowdebug("libAVPin_Connect(%p, %p, %p)\n", this, pin, type);
+ /* Input pins receive connections. */
+ return S_FALSE;
+}
+long WINAPI
+libAVPin_ReceiveConnection(libAVPin *this, IPin *pin,
+ const AM_MEDIA_TYPE *type)
+{
+ enum dshowDeviceType devtype = this->filter->type;
+ dshowdebug("libAVPin_ReceiveConnection(%p)\n", this);
+
+ if (!pin)
+ return E_POINTER;
+ if (this->connectedto)
+ return VFW_E_ALREADY_CONNECTED;
+
+ ff_print_AM_MEDIA_TYPE(type);
+ if (devtype == VideoDevice) {
+ if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
+ return VFW_E_TYPE_NOT_ACCEPTED;
+ } else {
+ if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
+ return VFW_E_TYPE_NOT_ACCEPTED;
+ }
+
+ IPin_AddRef(pin);
+ this->connectedto = pin;
+
+ ff_copy_dshow_media_type(&this->type, type);
+
+ return S_OK;
+}
+long WINAPI
+libAVPin_Disconnect(libAVPin *this)
+{
+ dshowdebug("libAVPin_Disconnect(%p)\n", this);
+
+ if (this->filter->state != State_Stopped)
+ return VFW_E_NOT_STOPPED;
+ if (!this->connectedto)
+ return S_FALSE;
+ IPin_Release(this->connectedto);
+ this->connectedto = NULL;
+
+ return S_OK;
+}
+long WINAPI
+libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
+{
+ dshowdebug("libAVPin_ConnectedTo(%p)\n", this);
+
+ if (!pin)
+ return E_POINTER;
+ if (!this->connectedto)
+ return VFW_E_NOT_CONNECTED;
+ IPin_AddRef(this->connectedto);
+ *pin = this->connectedto;
+
+ return S_OK;
+}
+long WINAPI
+libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
+{
+ dshowdebug("libAVPin_ConnectionMediaType(%p)\n", this);
+
+ if (!type)
+ return E_POINTER;
+ if (!this->connectedto)
+ return VFW_E_NOT_CONNECTED;
+
+ return ff_copy_dshow_media_type(type, &this->type);
+}
+long WINAPI
+libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
+{
+ dshowdebug("libAVPin_QueryPinInfo(%p)\n", this);
+
+ if (!info)
+ return E_POINTER;
+
+ if (this->filter)
+ libAVFilter_AddRef(this->filter);
+
+ info->pFilter = (IBaseFilter *) this->filter;
+ info->dir = PINDIR_INPUT;
+ wcscpy(info->achName, L"Capture");
+
+ return S_OK;
+}
+long WINAPI
+libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
+{
+ dshowdebug("libAVPin_QueryDirection(%p)\n", this);
+ if (!dir)
+ return E_POINTER;
+ *dir = PINDIR_INPUT;
+ return S_OK;
+}
+long WINAPI
+libAVPin_QueryId(libAVPin *this, wchar_t **id)
+{
+ dshowdebug("libAVPin_QueryId(%p)\n", this);
+
+ if (!id)
+ return E_POINTER;
+
+ *id = wcsdup(L"libAV Pin");
+
+ return S_OK;
+}
+long WINAPI
+libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
+{
+ dshowdebug("libAVPin_QueryAccept(%p)\n", this);
+ return S_FALSE;
+}
+long WINAPI
+libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
+{
+ const AM_MEDIA_TYPE *type = NULL;
+ libAVEnumMediaTypes *new;
+ dshowdebug("libAVPin_EnumMediaTypes(%p)\n", this);
+
+ if (!enumtypes)
+ return E_POINTER;
+ new = libAVEnumMediaTypes_Create(type);
+ if (!new)
+ return E_OUTOFMEMORY;
+
+ *enumtypes = (IEnumMediaTypes *) new;
+ return S_OK;
+}
+long WINAPI
+libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin,
+ unsigned long *npin)
+{
+ dshowdebug("libAVPin_QueryInternalConnections(%p)\n", this);
+ return E_NOTIMPL;
+}
+long WINAPI
+libAVPin_EndOfStream(libAVPin *this)
+{
+ dshowdebug("libAVPin_EndOfStream(%p)\n", this);
+ /* I don't care. */
+ return S_OK;
+}
+long WINAPI
+libAVPin_BeginFlush(libAVPin *this)
+{
+ dshowdebug("libAVPin_BeginFlush(%p)\n", this);
+ /* I don't care. */
+ return S_OK;
+}
+long WINAPI
+libAVPin_EndFlush(libAVPin *this)
+{
+ dshowdebug("libAVPin_EndFlush(%p)\n", this);
+ /* I don't care. */
+ return S_OK;
+}
+long WINAPI
+libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
+ double rate)
+{
+ dshowdebug("libAVPin_NewSegment(%p)\n", this);
+ /* I don't care. */
+ return S_OK;
+}
+
+static int
+libAVPin_Setup(libAVPin *this, libAVFilter *filter)
+{
+ IPinVtbl *vtbl = this->vtbl;
+ IMemInputPinVtbl *imemvtbl;
+
+ if (!filter)
+ return 0;
+
+ imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
+ if (!imemvtbl)
+ return 0;
+
+ SETVTBL(imemvtbl, libAVMemInputPin, QueryInterface);
+ SETVTBL(imemvtbl, libAVMemInputPin, AddRef);
+ SETVTBL(imemvtbl, libAVMemInputPin, Release);
+ SETVTBL(imemvtbl, libAVMemInputPin, GetAllocator);
+ SETVTBL(imemvtbl, libAVMemInputPin, NotifyAllocator);
+ SETVTBL(imemvtbl, libAVMemInputPin, GetAllocatorRequirements);
+ SETVTBL(imemvtbl, libAVMemInputPin, Receive);
+ SETVTBL(imemvtbl, libAVMemInputPin, ReceiveMultiple);
+ SETVTBL(imemvtbl, libAVMemInputPin, ReceiveCanBlock);
+
+ this->imemvtbl = imemvtbl;
+
+ SETVTBL(vtbl, libAVPin, QueryInterface);
+ SETVTBL(vtbl, libAVPin, AddRef);
+ SETVTBL(vtbl, libAVPin, Release);
+ SETVTBL(vtbl, libAVPin, Connect);
+ SETVTBL(vtbl, libAVPin, ReceiveConnection);
+ SETVTBL(vtbl, libAVPin, Disconnect);
+ SETVTBL(vtbl, libAVPin, ConnectedTo);
+ SETVTBL(vtbl, libAVPin, ConnectionMediaType);
+ SETVTBL(vtbl, libAVPin, QueryPinInfo);
+ SETVTBL(vtbl, libAVPin, QueryDirection);
+ SETVTBL(vtbl, libAVPin, QueryId);
+ SETVTBL(vtbl, libAVPin, QueryAccept);
+ SETVTBL(vtbl, libAVPin, EnumMediaTypes);
+ SETVTBL(vtbl, libAVPin, QueryInternalConnections);
+ SETVTBL(vtbl, libAVPin, EndOfStream);
+ SETVTBL(vtbl, libAVPin, BeginFlush);
+ SETVTBL(vtbl, libAVPin, EndFlush);
+ SETVTBL(vtbl, libAVPin, NewSegment);
+
+ this->filter = filter;
+
+ return 1;
+}
+DECLARE_CREATE(libAVPin, libAVPin_Setup(this, filter), libAVFilter *filter)
+DECLARE_DESTROY(libAVPin, nothing)
+
+/*****************************************************************************
+ * libAVMemInputPin
+ ****************************************************************************/
+long WINAPI
+libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid,
+ void **ppvObject)
+{
+ libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+ dshowdebug("libAVMemInputPin_QueryInterface(%p)\n", this);
+ return libAVPin_QueryInterface(pin, riid, ppvObject);
+}
+unsigned long WINAPI
+libAVMemInputPin_AddRef(libAVMemInputPin *this)
+{
+ libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+ dshowdebug("libAVMemInputPin_AddRef(%p)\n", this);
+ return libAVPin_AddRef(pin);
+}
+unsigned long WINAPI
+libAVMemInputPin_Release(libAVMemInputPin *this)
+{
+ libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+ dshowdebug("libAVMemInputPin_Release(%p)\n", this);
+ return libAVPin_Release(pin);
+}
+long WINAPI
+libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
+{
+ dshowdebug("libAVMemInputPin_GetAllocator(%p)\n", this);
+ return VFW_E_NO_ALLOCATOR;
+}
+long WINAPI
+libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc,
+ BOOL rdwr)
+{
+ dshowdebug("libAVMemInputPin_NotifyAllocator(%p)\n", this);
+ return S_OK;
+}
+long WINAPI
+libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this,
+ ALLOCATOR_PROPERTIES *props)
+{
+ dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this);
+ return E_NOTIMPL;
+}
+long WINAPI
+libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
+{
+ libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+ enum dshowDeviceType devtype = pin->filter->type;
+ void *priv_data;
+ uint8_t *buf;
+ int buf_size; /* todo should be a long? */
+ int index;
+ int64_t curtime;
+ int64_t orig_curtime;
+ const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
+ IReferenceClock *clock = pin->filter->clock;
+ int64_t dummy;
+
+ dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
+
+ if (!sample)
+ return E_POINTER;
+
+ IMediaSample_GetTime(sample, &orig_curtime, &dummy);
+ orig_curtime += pin->filter->start_time;
+ if (devtype == VideoDevice) {
+ /* PTS from video devices is unreliable. */
+ IReferenceClock_GetTime(clock, &curtime);
+ } else {
+ IMediaSample_GetTime(sample, &curtime, &dummy);
+ if(curtime > 400000000000000000LL) {
+ /* initial frames sometimes start < 0 (shown as a very large number here,
+ like 437650244077016960 which FFmpeg doesn't like.
+ TODO figure out math. For now just drop them. */
+ av_log(NULL, AV_LOG_DEBUG,
+ "dshow dropping initial (or ending) audio frame with odd PTS too high %"PRId64"\n", curtime);
+ return S_OK;
+ }
+ curtime += pin->filter->start_time;
+ }
+
+ buf_size = IMediaSample_GetActualDataLength(sample);
+ IMediaSample_GetPointer(sample, &buf);
+ priv_data = pin->filter->priv_data;
+ index = pin->filter->stream_index;
+
+ av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %6d timestamp %"PRId64" orig timestamp %"PRId64"\n",
+ devtypename, buf_size, curtime, orig_curtime);
+ pin->filter->callback(priv_data, index, buf, buf_size, curtime, devtype);
+
+ return S_OK;
+}
+long WINAPI
+libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this,
+ IMediaSample **samples, long n, long *nproc)
+{
+ int i;
+ dshowdebug("libAVMemInputPin_ReceiveMultiple(%p)\n", this);
+
+ for (i = 0; i < n; i++)
+ libAVMemInputPin_Receive(this, samples[i]);
+
+ *nproc = n;
+ return S_OK;
+}
+long WINAPI
+libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
+{
+ dshowdebug("libAVMemInputPin_ReceiveCanBlock(%p)\n", this);
+ /* I swear I will not block. */
+ return S_FALSE;
+}
+
+void
+libAVMemInputPin_Destroy(libAVMemInputPin *this)
+{
+ libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+ dshowdebug("libAVMemInputPin_Destroy(%p)\n", this);
+ libAVPin_Destroy(pin);
+}
diff --git a/libavdevice/dv1394.c b/libavdevice/dv1394.c
index addf1ade67..9f02780e72 100644
--- a/libavdevice/dv1394.c
+++ b/libavdevice/dv1394.c
@@ -2,20 +2,20 @@
* Linux DV1394 interface
* Copyright (c) 2003 Max Krasnyansky <maxk@qualcomm.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,7 @@
#include "libavutil/internal.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavformat/dv.h"
#include "dv1394.h"
@@ -186,7 +186,7 @@ restart_poll:
size = avpriv_dv_produce_packet(dv->dv_demux, pkt,
dv->ring + (dv->index * DV1394_PAL_FRAME_SIZE),
- DV1394_PAL_FRAME_SIZE);
+ DV1394_PAL_FRAME_SIZE, -1);
dv->index = (dv->index + 1) % DV1394_RING_FRAMES;
dv->done++; dv->avail--;
@@ -206,7 +206,7 @@ static int dv1394_close(AVFormatContext * context)
av_log(context, AV_LOG_ERROR, "Failed to munmap DV1394 ring buffer: %s\n", strerror(errno));
close(dv->fd);
- av_free(dv->dv_demux);
+ av_freep(&dv->dv_demux);
return 0;
}
@@ -224,6 +224,7 @@ static const AVClass dv1394_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
AVInputFormat ff_dv1394_demuxer = {
diff --git a/libavdevice/dv1394.h b/libavdevice/dv1394.h
index 9710ff56ea..b76d633ef6 100644
--- a/libavdevice/dv1394.h
+++ b/libavdevice/dv1394.h
@@ -8,20 +8,20 @@
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavdevice/fbdev.c b/libavdevice/fbdev.c
deleted file mode 100644
index 27e2ed30db..0000000000
--- a/libavdevice/fbdev.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (c) 2011 Stefano Sabatini
- * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
- * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * Linux framebuffer input device,
- * inspired by code from fbgrab.c by Gunnar Monell.
- * @see http://linux-fbdev.sourceforge.net/
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <time.h>
-#include <linux/fb.h>
-
-#include "libavutil/internal.h"
-#include "libavutil/log.h"
-#include "libavutil/mem.h"
-#include "libavutil/opt.h"
-#include "libavutil/time.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavformat/avformat.h"
-#include "libavformat/internal.h"
-
-struct rgb_pixfmt_map_entry {
- int bits_per_pixel;
- int red_offset, green_offset, blue_offset, alpha_offset;
- enum AVPixelFormat pixfmt;
-};
-
-static struct rgb_pixfmt_map_entry rgb_pixfmt_map[] = {
- // bpp, red_offset, green_offset, blue_offset, alpha_offset, pixfmt
- { 32, 0, 8, 16, 24, AV_PIX_FMT_RGBA },
- { 32, 16, 8, 0, 24, AV_PIX_FMT_BGRA },
- { 32, 8, 16, 24, 0, AV_PIX_FMT_ARGB },
- { 32, 3, 2, 8, 0, AV_PIX_FMT_ABGR },
- { 24, 0, 8, 16, 0, AV_PIX_FMT_RGB24 },
- { 24, 16, 8, 0, 0, AV_PIX_FMT_BGR24 },
-};
-
-static enum AVPixelFormat get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(rgb_pixfmt_map); i++) {
- struct rgb_pixfmt_map_entry *entry = &rgb_pixfmt_map[i];
- if (entry->bits_per_pixel == varinfo->bits_per_pixel &&
- entry->red_offset == varinfo->red.offset &&
- entry->green_offset == varinfo->green.offset &&
- entry->blue_offset == varinfo->blue.offset)
- return entry->pixfmt;
- }
-
- return AV_PIX_FMT_NONE;
-}
-
-typedef struct FBDevContext {
- AVClass *class; ///< class for private options
- int frame_size; ///< size in bytes of a grabbed frame
- AVRational framerate_q; ///< framerate
- char *framerate; ///< framerate string set by a private option
- int64_t time_frame; ///< time for the next frame to output (in 1/1000000 units)
-
- int fd; ///< framebuffer device file descriptor
- int width, height; ///< assumed frame resolution
- int frame_linesize; ///< linesize of the output frame, it is assumed to be constant
- int bytes_per_pixel;
-
- struct fb_var_screeninfo varinfo; ///< variable info;
- struct fb_fix_screeninfo fixinfo; ///< fixed info;
-
- uint8_t *data; ///< framebuffer data
-} FBDevContext;
-
-static av_cold int fbdev_read_header(AVFormatContext *avctx)
-{
- FBDevContext *fbdev = avctx->priv_data;
- AVStream *st = NULL;
- enum AVPixelFormat pix_fmt;
- int ret, flags = O_RDONLY;
- char errbuf[128];
-
- ret = av_parse_video_rate(&fbdev->framerate_q, fbdev->framerate);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", fbdev->framerate);
- return ret;
- }
-
- if (!(st = avformat_new_stream(avctx, NULL)))
- return AVERROR(ENOMEM);
- avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in microseconds */
-
- /* NONBLOCK is ignored by the fbdev driver, only set for consistency */
- if (avctx->flags & AVFMT_FLAG_NONBLOCK)
- flags |= O_NONBLOCK;
-
- if ((fbdev->fd = avpriv_open(avctx->filename, flags)) == -1) {
- ret = AVERROR(errno);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(avctx, AV_LOG_ERROR,
- "Could not open framebuffer device '%s': %s\n",
- avctx->filename, errbuf);
- return ret;
- }
-
- if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
- ret = AVERROR(errno);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(avctx, AV_LOG_ERROR,
- "FBIOGET_VSCREENINFO: %s\n", errbuf);
- goto fail;
- }
-
- if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->fixinfo) < 0) {
- ret = AVERROR(errno);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(avctx, AV_LOG_ERROR,
- "FBIOGET_FSCREENINFO: %s\n", errbuf);
- goto fail;
- }
-
- pix_fmt = get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
- if (pix_fmt == AV_PIX_FMT_NONE) {
- ret = AVERROR(EINVAL);
- av_log(avctx, AV_LOG_ERROR,
- "Framebuffer pixel format not supported.\n");
- goto fail;
- }
-
- fbdev->width = fbdev->varinfo.xres;
- fbdev->height = fbdev->varinfo.yres;
- fbdev->bytes_per_pixel = (fbdev->varinfo.bits_per_pixel + 7) >> 3;
- fbdev->frame_linesize = fbdev->width * fbdev->bytes_per_pixel;
- fbdev->frame_size = fbdev->frame_linesize * fbdev->height;
- fbdev->time_frame = AV_NOPTS_VALUE;
- fbdev->data = mmap(NULL, fbdev->fixinfo.smem_len, PROT_READ, MAP_SHARED, fbdev->fd, 0);
- if (fbdev->data == MAP_FAILED) {
- ret = AVERROR(errno);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", errbuf);
- goto fail;
- }
-
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
- st->codec->width = fbdev->width;
- st->codec->height = fbdev->height;
- st->codec->pix_fmt = pix_fmt;
- st->codec->time_base = (AVRational){fbdev->framerate_q.den, fbdev->framerate_q.num};
- st->codec->bit_rate =
- fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
-
- av_log(avctx, AV_LOG_INFO,
- "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
- fbdev->width, fbdev->height, fbdev->varinfo.bits_per_pixel,
- av_get_pix_fmt_name(pix_fmt),
- fbdev->framerate_q.num, fbdev->framerate_q.den,
- st->codec->bit_rate);
- return 0;
-
-fail:
- close(fbdev->fd);
- return ret;
-}
-
-static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
-{
- FBDevContext *fbdev = avctx->priv_data;
- int64_t curtime, delay;
- struct timespec ts;
- int i, ret;
- uint8_t *pin, *pout;
-
- if (fbdev->time_frame == AV_NOPTS_VALUE)
- fbdev->time_frame = av_gettime();
-
- /* wait based on the frame rate */
- curtime = av_gettime();
- delay = fbdev->time_frame - curtime;
- av_log(avctx, AV_LOG_TRACE,
- "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
- fbdev->time_frame, curtime, delay);
- if (delay > 0) {
- if (avctx->flags & AVFMT_FLAG_NONBLOCK)
- return AVERROR(EAGAIN);
- ts.tv_sec = delay / 1000000;
- ts.tv_nsec = (delay % 1000000) * 1000;
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
- }
- /* compute the time of the next frame */
- fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->framerate_q);
-
- if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
- return ret;
-
- /* refresh fbdev->varinfo, visible data position may change at each call */
- if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
- char errbuf[128];
- av_strerror(AVERROR(errno), errbuf, sizeof(errbuf));
- av_log(avctx, AV_LOG_WARNING,
- "Error refreshing variable info: %s\n", errbuf);
- }
-
- pkt->pts = curtime;
-
- /* compute visible data offset */
- pin = fbdev->data + fbdev->bytes_per_pixel * fbdev->varinfo.xoffset +
- fbdev->varinfo.yoffset * fbdev->fixinfo.line_length;
- pout = pkt->data;
-
- // TODO it'd be nice if the lines were aligned
- for (i = 0; i < fbdev->height; i++) {
- memcpy(pout, pin, fbdev->frame_linesize);
- pin += fbdev->fixinfo.line_length;
- pout += fbdev->frame_linesize;
- }
-
- return fbdev->frame_size;
-}
-
-static av_cold int fbdev_read_close(AVFormatContext *avctx)
-{
- FBDevContext *fbdev = avctx->priv_data;
-
- munmap(fbdev->data, fbdev->frame_size);
- close(fbdev->fd);
-
- return 0;
-}
-
-#define OFFSET(x) offsetof(FBDevContext, x)
-#define DEC AV_OPT_FLAG_DECODING_PARAM
-static const AVOption options[] = {
- { "framerate","", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
- { NULL },
-};
-
-static const AVClass fbdev_class = {
- .class_name = "fbdev indev",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVInputFormat ff_fbdev_demuxer = {
- .name = "fbdev",
- .long_name = NULL_IF_CONFIG_SMALL("Linux framebuffer"),
- .priv_data_size = sizeof(FBDevContext),
- .read_header = fbdev_read_header,
- .read_packet = fbdev_read_packet,
- .read_close = fbdev_read_close,
- .flags = AVFMT_NOFILE,
- .priv_class = &fbdev_class,
-};
diff --git a/libavdevice/fbdev_common.c b/libavdevice/fbdev_common.c
new file mode 100644
index 0000000000..98f96de2af
--- /dev/null
+++ b/libavdevice/fbdev_common.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
+ * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include "fbdev_common.h"
+#include "libavutil/common.h"
+#include "avdevice.h"
+
+struct rgb_pixfmt_map_entry {
+ int bits_per_pixel;
+ int red_offset, green_offset, blue_offset, alpha_offset;
+ enum AVPixelFormat pixfmt;
+};
+
+static const struct rgb_pixfmt_map_entry rgb_pixfmt_map[] = {
+ // bpp, red_offset, green_offset, blue_offset, alpha_offset, pixfmt
+ { 32, 0, 8, 16, 24, AV_PIX_FMT_RGBA },
+ { 32, 16, 8, 0, 24, AV_PIX_FMT_BGRA },
+ { 32, 8, 16, 24, 0, AV_PIX_FMT_ARGB },
+ { 32, 3, 2, 8, 0, AV_PIX_FMT_ABGR },
+ { 24, 0, 8, 16, 0, AV_PIX_FMT_RGB24 },
+ { 24, 16, 8, 0, 0, AV_PIX_FMT_BGR24 },
+ { 16, 11, 5, 0, 16, AV_PIX_FMT_RGB565 },
+};
+
+enum AVPixelFormat ff_get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo)
+{
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(rgb_pixfmt_map); i++) {
+ const struct rgb_pixfmt_map_entry *entry = &rgb_pixfmt_map[i];
+ if (entry->bits_per_pixel == varinfo->bits_per_pixel &&
+ entry->red_offset == varinfo->red.offset &&
+ entry->green_offset == varinfo->green.offset &&
+ entry->blue_offset == varinfo->blue.offset)
+ return entry->pixfmt;
+ }
+
+ return AV_PIX_FMT_NONE;
+}
+
+const char* ff_fbdev_default_device()
+{
+ const char *dev = getenv("FRAMEBUFFER");
+ if (!dev)
+ dev = "/dev/fb0";
+ return dev;
+}
+
+int ff_fbdev_get_device_list(AVDeviceInfoList *device_list)
+{
+ struct fb_var_screeninfo varinfo;
+ struct fb_fix_screeninfo fixinfo;
+ char device_file[12];
+ AVDeviceInfo *device = NULL;
+ int i, fd, ret = 0;
+ const char *default_device = ff_fbdev_default_device();
+
+ if (!device_list)
+ return AVERROR(EINVAL);
+
+ for (i = 0; i <= 31; i++) {
+ snprintf(device_file, sizeof(device_file), "/dev/fb%d", i);
+
+ if ((fd = avpriv_open(device_file, O_RDWR)) < 0) {
+ int err = AVERROR(errno);
+ if (err != AVERROR(ENOENT))
+ av_log(NULL, AV_LOG_ERROR, "Could not open framebuffer device '%s': %s\n",
+ device_file, av_err2str(err));
+ continue;
+ }
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) == -1)
+ goto fail_device;
+ if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) == -1)
+ goto fail_device;
+
+ device = av_mallocz(sizeof(AVDeviceInfo));
+ if (!device) {
+ ret = AVERROR(ENOMEM);
+ goto fail_device;
+ }
+ device->device_name = av_strdup(device_file);
+ device->device_description = av_strdup(fixinfo.id);
+ if (!device->device_name || !device->device_description) {
+ ret = AVERROR(ENOMEM);
+ goto fail_device;
+ }
+
+ if ((ret = av_dynarray_add_nofree(&device_list->devices,
+ &device_list->nb_devices, device)) < 0)
+ goto fail_device;
+
+ if (default_device && !strcmp(device->device_name, default_device)) {
+ device_list->default_device = device_list->nb_devices - 1;
+ default_device = NULL;
+ }
+ close(fd);
+ continue;
+
+ fail_device:
+ if (device) {
+ av_freep(&device->device_name);
+ av_freep(&device->device_description);
+ av_freep(&device);
+ }
+ if (fd >= 0)
+ close(fd);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
diff --git a/libavdevice/fbdev_common.h b/libavdevice/fbdev_common.h
new file mode 100644
index 0000000000..7b81a8daeb
--- /dev/null
+++ b/libavdevice/fbdev_common.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
+ * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVDEVICE_FBDEV_COMMON_H
+#define AVDEVICE_FBDEV_COMMON_H
+
+#include <features.h>
+#include <linux/fb.h>
+#include "libavutil/pixfmt.h"
+
+struct AVDeviceInfoList;
+
+enum AVPixelFormat ff_get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo);
+
+const char* ff_fbdev_default_device(void);
+
+int ff_fbdev_get_device_list(struct AVDeviceInfoList *device_list);
+
+#endif /* AVDEVICE_FBDEV_COMMON_H */
diff --git a/libavdevice/fbdev_dec.c b/libavdevice/fbdev_dec.c
new file mode 100644
index 0000000000..c1e946a564
--- /dev/null
+++ b/libavdevice/fbdev_dec.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2009 Giliard B. de Freitas <giliarde@gmail.com>
+ * Copyright (C) 2002 Gunnar Monell <gmo@linux.nu>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Linux framebuffer input device,
+ * inspired by code from fbgrab.c by Gunnar Monell.
+ * @see http://linux-fbdev.sourceforge.net/
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <linux/fb.h>
+
+#include "libavutil/internal.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
+#include "fbdev_common.h"
+
+typedef struct FBDevContext {
+ AVClass *class; ///< class for private options
+ int frame_size; ///< size in bytes of a grabbed frame
+ AVRational framerate_q; ///< framerate
+ int64_t time_frame; ///< time for the next frame to output (in 1/1000000 units)
+
+ int fd; ///< framebuffer device file descriptor
+ int width, height; ///< assumed frame resolution
+ int frame_linesize; ///< linesize of the output frame, it is assumed to be constant
+ int bytes_per_pixel;
+
+ struct fb_var_screeninfo varinfo; ///< variable info;
+ struct fb_fix_screeninfo fixinfo; ///< fixed info;
+
+ uint8_t *data; ///< framebuffer data
+} FBDevContext;
+
+static av_cold int fbdev_read_header(AVFormatContext *avctx)
+{
+ FBDevContext *fbdev = avctx->priv_data;
+ AVStream *st = NULL;
+ enum AVPixelFormat pix_fmt;
+ int ret, flags = O_RDONLY;
+ const char* device;
+
+ if (!(st = avformat_new_stream(avctx, NULL)))
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in microseconds */
+
+ /* NONBLOCK is ignored by the fbdev driver, only set for consistency */
+ if (avctx->flags & AVFMT_FLAG_NONBLOCK)
+ flags |= O_NONBLOCK;
+
+ if (avctx->filename[0])
+ device = avctx->filename;
+ else
+ device = ff_fbdev_default_device();
+
+ if ((fbdev->fd = avpriv_open(device, flags)) == -1) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not open framebuffer device '%s': %s\n",
+ device, av_err2str(ret));
+ return ret;
+ }
+
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR,
+ "FBIOGET_VSCREENINFO: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->fixinfo) < 0) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR,
+ "FBIOGET_FSCREENINFO: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ pix_fmt = ff_get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
+ if (pix_fmt == AV_PIX_FMT_NONE) {
+ ret = AVERROR(EINVAL);
+ av_log(avctx, AV_LOG_ERROR,
+ "Framebuffer pixel format not supported.\n");
+ goto fail;
+ }
+
+ fbdev->width = fbdev->varinfo.xres;
+ fbdev->height = fbdev->varinfo.yres;
+ fbdev->bytes_per_pixel = (fbdev->varinfo.bits_per_pixel + 7) >> 3;
+ fbdev->frame_linesize = fbdev->width * fbdev->bytes_per_pixel;
+ fbdev->frame_size = fbdev->frame_linesize * fbdev->height;
+ fbdev->time_frame = AV_NOPTS_VALUE;
+ fbdev->data = mmap(NULL, fbdev->fixinfo.smem_len, PROT_READ, MAP_SHARED, fbdev->fd, 0);
+ if (fbdev->data == MAP_FAILED) {
+ ret = AVERROR(errno);
+ av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->width = fbdev->width;
+ st->codec->height = fbdev->height;
+ st->codec->pix_fmt = pix_fmt;
+ st->codec->time_base = av_inv_q(fbdev->framerate_q);
+ st->codec->bit_rate =
+ fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
+
+ av_log(avctx, AV_LOG_INFO,
+ "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
+ fbdev->width, fbdev->height, fbdev->varinfo.bits_per_pixel,
+ av_get_pix_fmt_name(pix_fmt),
+ fbdev->framerate_q.num, fbdev->framerate_q.den,
+ st->codec->bit_rate);
+ return 0;
+
+fail:
+ close(fbdev->fd);
+ return ret;
+}
+
+static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ FBDevContext *fbdev = avctx->priv_data;
+ int64_t curtime, delay;
+ struct timespec ts;
+ int i, ret;
+ uint8_t *pin, *pout;
+
+ if (fbdev->time_frame == AV_NOPTS_VALUE)
+ fbdev->time_frame = av_gettime();
+
+ /* wait based on the frame rate */
+ while (1) {
+ curtime = av_gettime();
+ delay = fbdev->time_frame - curtime;
+ av_log(avctx, AV_LOG_TRACE,
+ "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
+ fbdev->time_frame, curtime, delay);
+ if (delay <= 0) {
+ fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->framerate_q);
+ break;
+ }
+ if (avctx->flags & AVFMT_FLAG_NONBLOCK)
+ return AVERROR(EAGAIN);
+ ts.tv_sec = delay / 1000000;
+ ts.tv_nsec = (delay % 1000000) * 1000;
+ while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
+ }
+
+ if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
+ return ret;
+
+ /* refresh fbdev->varinfo, visible data position may change at each call */
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
+ av_log(avctx, AV_LOG_WARNING,
+ "Error refreshing variable info: %s\n", av_err2str(AVERROR(errno)));
+ }
+
+ pkt->pts = curtime;
+
+ /* compute visible data offset */
+ pin = fbdev->data + fbdev->bytes_per_pixel * fbdev->varinfo.xoffset +
+ fbdev->varinfo.yoffset * fbdev->fixinfo.line_length;
+ pout = pkt->data;
+
+ for (i = 0; i < fbdev->height; i++) {
+ memcpy(pout, pin, fbdev->frame_linesize);
+ pin += fbdev->fixinfo.line_length;
+ pout += fbdev->frame_linesize;
+ }
+
+ return fbdev->frame_size;
+}
+
+static av_cold int fbdev_read_close(AVFormatContext *avctx)
+{
+ FBDevContext *fbdev = avctx->priv_data;
+
+ munmap(fbdev->data, fbdev->fixinfo.smem_len);
+ close(fbdev->fd);
+
+ return 0;
+}
+
+static int fbdev_get_device_list(AVFormatContext *s, AVDeviceInfoList *device_list)
+{
+ return ff_fbdev_get_device_list(device_list);
+}
+
+#define OFFSET(x) offsetof(FBDevContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "framerate","", OFFSET(framerate_q), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
+ { NULL },
+};
+
+static const AVClass fbdev_class = {
+ .class_name = "fbdev indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_fbdev_demuxer = {
+ .name = "fbdev",
+ .long_name = NULL_IF_CONFIG_SMALL("Linux framebuffer"),
+ .priv_data_size = sizeof(FBDevContext),
+ .read_header = fbdev_read_header,
+ .read_packet = fbdev_read_packet,
+ .read_close = fbdev_read_close,
+ .get_device_list = fbdev_get_device_list,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &fbdev_class,
+};
diff --git a/libavdevice/fbdev_enc.c b/libavdevice/fbdev_enc.c
new file mode 100644
index 0000000000..28efc7131b
--- /dev/null
+++ b/libavdevice/fbdev_enc.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2013 Lukasz Marek
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+#include "libavutil/pixdesc.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavformat/avformat.h"
+#include "fbdev_common.h"
+#include "avdevice.h"
+
+typedef struct {
+ AVClass *class; ///< class for private options
+ int xoffset; ///< x coordinate of top left corner
+ int yoffset; ///< y coordinate of top left corner
+ struct fb_var_screeninfo varinfo; ///< framebuffer variable info
+ struct fb_fix_screeninfo fixinfo; ///< framebuffer fixed info
+ int fd; ///< framebuffer device file descriptor
+ uint8_t *data; ///< framebuffer data
+} FBDevContext;
+
+static av_cold int fbdev_write_header(AVFormatContext *h)
+{
+ FBDevContext *fbdev = h->priv_data;
+ enum AVPixelFormat pix_fmt;
+ int ret, flags = O_RDWR;
+ const char* device;
+
+ if (h->nb_streams != 1 || h->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO) {
+ av_log(fbdev, AV_LOG_ERROR, "Only a single video stream is supported.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (h->filename[0])
+ device = h->filename;
+ else
+ device = ff_fbdev_default_device();
+
+ if ((fbdev->fd = avpriv_open(device, flags)) == -1) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR,
+ "Could not open framebuffer device '%s': %s\n",
+ device, av_err2str(ret));
+ return ret;
+ }
+
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "FBIOGET_VSCREENINFO: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->fixinfo) < 0) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "FBIOGET_FSCREENINFO: %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ pix_fmt = ff_get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
+ if (pix_fmt == AV_PIX_FMT_NONE) {
+ ret = AVERROR(EINVAL);
+ av_log(h, AV_LOG_ERROR, "Framebuffer pixel format not supported.\n");
+ goto fail;
+ }
+
+ fbdev->data = mmap(NULL, fbdev->fixinfo.smem_len, PROT_WRITE, MAP_SHARED, fbdev->fd, 0);
+ if (fbdev->data == MAP_FAILED) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Error in mmap(): %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ return 0;
+ fail:
+ close(fbdev->fd);
+ return ret;
+}
+
+static int fbdev_write_packet(AVFormatContext *h, AVPacket *pkt)
+{
+ FBDevContext *fbdev = h->priv_data;
+ uint8_t *pin, *pout;
+ enum AVPixelFormat fb_pix_fmt;
+ int disp_height;
+ int bytes_to_copy;
+ AVCodecContext *codec_ctx = h->streams[0]->codec;
+ enum AVPixelFormat video_pix_fmt = codec_ctx->pix_fmt;
+ int video_width = codec_ctx->width;
+ int video_height = codec_ctx->height;
+ int bytes_per_pixel = ((codec_ctx->bits_per_coded_sample + 7) >> 3);
+ int src_line_size = video_width * bytes_per_pixel;
+ int i;
+
+ if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0)
+ av_log(h, AV_LOG_WARNING,
+ "Error refreshing variable info: %s\n", av_err2str(AVERROR(errno)));
+
+ fb_pix_fmt = ff_get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
+
+ if (fb_pix_fmt != video_pix_fmt) {
+ av_log(h, AV_LOG_ERROR, "Pixel format %s is not supported, use %s\n",
+ av_get_pix_fmt_name(video_pix_fmt), av_get_pix_fmt_name(fb_pix_fmt));
+ return AVERROR(EINVAL);
+ }
+
+ disp_height = FFMIN(fbdev->varinfo.yres, video_height);
+ bytes_to_copy = FFMIN(fbdev->varinfo.xres, video_width) * bytes_per_pixel;
+
+ pin = pkt->data;
+ pout = fbdev->data +
+ bytes_per_pixel * fbdev->varinfo.xoffset +
+ fbdev->varinfo.yoffset * fbdev->fixinfo.line_length;
+
+ if (fbdev->xoffset) {
+ if (fbdev->xoffset < 0) {
+ if (-fbdev->xoffset >= video_width) //nothing to display
+ return 0;
+ bytes_to_copy += fbdev->xoffset * bytes_per_pixel;
+ pin -= fbdev->xoffset * bytes_per_pixel;
+ } else {
+ int diff = (video_width + fbdev->xoffset) - fbdev->varinfo.xres;
+ if (diff > 0) {
+ if (diff >= video_width) //nothing to display
+ return 0;
+ bytes_to_copy -= diff * bytes_per_pixel;
+ }
+ pout += bytes_per_pixel * fbdev->xoffset;
+ }
+ }
+
+ if (fbdev->yoffset) {
+ if (fbdev->yoffset < 0) {
+ if (-fbdev->yoffset >= video_height) //nothing to display
+ return 0;
+ disp_height += fbdev->yoffset;
+ pin -= fbdev->yoffset * src_line_size;
+ } else {
+ int diff = (video_height + fbdev->yoffset) - fbdev->varinfo.yres;
+ if (diff > 0) {
+ if (diff >= video_height) //nothing to display
+ return 0;
+ disp_height -= diff;
+ }
+ pout += fbdev->yoffset * fbdev->fixinfo.line_length;
+ }
+ }
+
+ for (i = 0; i < disp_height; i++) {
+ memcpy(pout, pin, bytes_to_copy);
+ pout += fbdev->fixinfo.line_length;
+ pin += src_line_size;
+ }
+
+ return 0;
+}
+
+static av_cold int fbdev_write_trailer(AVFormatContext *h)
+{
+ FBDevContext *fbdev = h->priv_data;
+ munmap(fbdev->data, fbdev->fixinfo.smem_len);
+ close(fbdev->fd);
+ return 0;
+}
+
+static int fbdev_get_device_list(AVFormatContext *s, AVDeviceInfoList *device_list)
+{
+ return ff_fbdev_get_device_list(device_list);
+}
+
+#define OFFSET(x) offsetof(FBDevContext, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "xoffset", "set x coordinate of top left corner", OFFSET(xoffset), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, ENC },
+ { "yoffset", "set y coordinate of top left corner", OFFSET(yoffset), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, ENC },
+ { NULL }
+};
+
+static const AVClass fbdev_class = {
+ .class_name = "fbdev outdev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_fbdev_muxer = {
+ .name = "fbdev",
+ .long_name = NULL_IF_CONFIG_SMALL("Linux framebuffer"),
+ .priv_data_size = sizeof(FBDevContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = fbdev_write_header,
+ .write_packet = fbdev_write_packet,
+ .write_trailer = fbdev_write_trailer,
+ .get_device_list = fbdev_get_device_list,
+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
+ .priv_class = &fbdev_class,
+};
diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c
new file mode 100644
index 0000000000..9a185d4c79
--- /dev/null
+++ b/libavdevice/gdigrab.c
@@ -0,0 +1,636 @@
+/*
+ * GDI video grab interface
+ *
+ * This file is part of FFmpeg.
+ *
+ * Copyright (C) 2013 Calvin Walton <calvin.walton@kepstin.ca>
+ * Copyright (C) 2007-2010 Christophe Gisquet <word1.word2@gmail.com>
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * GDI frame device demuxer
+ * @author Calvin Walton <calvin.walton@kepstin.ca>
+ * @author Christophe Gisquet <word1.word2@gmail.com>
+ */
+
+#include "config.h"
+#include "libavformat/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include <windows.h>
+
+/**
+ * GDI Device Demuxer context
+ */
+struct gdigrab {
+ const AVClass *class; /**< Class for private options */
+
+ int frame_size; /**< Size in bytes of the frame pixel data */
+ int header_size; /**< Size in bytes of the DIB header */
+ AVRational time_base; /**< Time base */
+ int64_t time_frame; /**< Current time */
+
+ int draw_mouse; /**< Draw mouse cursor (private option) */
+ int show_region; /**< Draw border (private option) */
+ AVRational framerate; /**< Capture framerate (private option) */
+ int width; /**< Width of the grab frame (private option) */
+ int height; /**< Height of the grab frame (private option) */
+ int offset_x; /**< Capture x offset (private option) */
+ int offset_y; /**< Capture y offset (private option) */
+
+ HWND hwnd; /**< Handle of the window for the grab */
+ HDC source_hdc; /**< Source device context */
+ HDC dest_hdc; /**< Destination, source-compatible DC */
+ BITMAPINFO bmi; /**< Information describing DIB format */
+ HBITMAP hbmp; /**< Information on the bitmap captured */
+ void *buffer; /**< The buffer containing the bitmap image data */
+ RECT clip_rect; /**< The subarea of the screen or window to clip */
+
+ HWND region_hwnd; /**< Handle of the region border window */
+
+ int cursor_error_printed;
+};
+
+#define WIN32_API_ERROR(str) \
+ av_log(s1, AV_LOG_ERROR, str " (error %li)\n", GetLastError())
+
+#define REGION_WND_BORDER 3
+
+/**
+ * Callback to handle Windows messages for the region outline window.
+ *
+ * In particular, this handles painting the frame rectangle.
+ *
+ * @param hwnd The region outline window handle.
+ * @param msg The Windows message.
+ * @param wparam First Windows message parameter.
+ * @param lparam Second Windows message parameter.
+ * @return 0 success, !0 failure
+ */
+static LRESULT CALLBACK
+gdigrab_region_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ PAINTSTRUCT ps;
+ HDC hdc;
+ RECT rect;
+
+ switch (msg) {
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &ps);
+
+ GetClientRect(hwnd, &rect);
+ FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
+
+ rect.left++; rect.top++; rect.right--; rect.bottom--;
+ FrameRect(hdc, &rect, GetStockObject(WHITE_BRUSH));
+
+ rect.left++; rect.top++; rect.right--; rect.bottom--;
+ FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
+
+ EndPaint(hwnd, &ps);
+ break;
+ default:
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+ return 0;
+}
+
+/**
+ * Initialize the region outline window.
+ *
+ * @param s1 The format context.
+ * @param gdigrab gdigrab context.
+ * @return 0 success, !0 failure
+ */
+static int
+gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
+{
+ HWND hwnd;
+ RECT rect = gdigrab->clip_rect;
+ HRGN region = NULL;
+ HRGN region_interior = NULL;
+
+ DWORD style = WS_POPUP | WS_VISIBLE;
+ DWORD ex = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT;
+
+ rect.left -= REGION_WND_BORDER; rect.top -= REGION_WND_BORDER;
+ rect.right += REGION_WND_BORDER; rect.bottom += REGION_WND_BORDER;
+
+ AdjustWindowRectEx(&rect, style, FALSE, ex);
+
+ // Create a window with no owner; use WC_DIALOG instead of writing a custom
+ // window class
+ hwnd = CreateWindowEx(ex, WC_DIALOG, NULL, style, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ NULL, NULL, NULL, NULL);
+ if (!hwnd) {
+ WIN32_API_ERROR("Could not create region display window");
+ goto error;
+ }
+
+ // Set the window shape to only include the border area
+ GetClientRect(hwnd, &rect);
+ region = CreateRectRgn(0, 0,
+ rect.right - rect.left, rect.bottom - rect.top);
+ region_interior = CreateRectRgn(REGION_WND_BORDER, REGION_WND_BORDER,
+ rect.right - rect.left - REGION_WND_BORDER,
+ rect.bottom - rect.top - REGION_WND_BORDER);
+ CombineRgn(region, region, region_interior, RGN_DIFF);
+ if (!SetWindowRgn(hwnd, region, FALSE)) {
+ WIN32_API_ERROR("Could not set window region");
+ goto error;
+ }
+ // The "region" memory is now owned by the window
+ region = NULL;
+ DeleteObject(region_interior);
+
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) gdigrab_region_wnd_proc);
+
+ ShowWindow(hwnd, SW_SHOW);
+
+ gdigrab->region_hwnd = hwnd;
+
+ return 0;
+
+error:
+ if (region)
+ DeleteObject(region);
+ if (region_interior)
+ DeleteObject(region_interior);
+ if (hwnd)
+ DestroyWindow(hwnd);
+ return 1;
+}
+
+/**
+ * Cleanup/free the region outline window.
+ *
+ * @param s1 The format context.
+ * @param gdigrab gdigrab context.
+ */
+static void
+gdigrab_region_wnd_destroy(AVFormatContext *s1, struct gdigrab *gdigrab)
+{
+ if (gdigrab->region_hwnd)
+ DestroyWindow(gdigrab->region_hwnd);
+ gdigrab->region_hwnd = NULL;
+}
+
+/**
+ * Process the Windows message queue.
+ *
+ * This is important to prevent Windows from thinking the window has become
+ * unresponsive. As well, things like WM_PAINT (to actually draw the window
+ * contents) are handled from the message queue context.
+ *
+ * @param s1 The format context.
+ * @param gdigrab gdigrab context.
+ */
+static void
+gdigrab_region_wnd_update(AVFormatContext *s1, struct gdigrab *gdigrab)
+{
+ HWND hwnd = gdigrab->region_hwnd;
+ MSG msg;
+
+ while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
+ DispatchMessage(&msg);
+ }
+}
+
+/**
+ * Initializes the gdi grab device demuxer (public device demuxer API).
+ *
+ * @param s1 Context from avformat core
+ * @return AVERROR_IO error, 0 success
+ */
+static int
+gdigrab_read_header(AVFormatContext *s1)
+{
+ struct gdigrab *gdigrab = s1->priv_data;
+
+ HWND hwnd;
+ HDC source_hdc = NULL;
+ HDC dest_hdc = NULL;
+ BITMAPINFO bmi;
+ HBITMAP hbmp = NULL;
+ void *buffer = NULL;
+
+ const char *filename = s1->filename;
+ const char *name = NULL;
+ AVStream *st = NULL;
+
+ int bpp;
+ RECT virtual_rect;
+ RECT clip_rect;
+ BITMAP bmp;
+ int ret;
+
+ if (!strncmp(filename, "title=", 6)) {
+ name = filename + 6;
+ hwnd = FindWindow(NULL, name);
+ if (!hwnd) {
+ av_log(s1, AV_LOG_ERROR,
+ "Can't find window '%s', aborting.\n", name);
+ ret = AVERROR(EIO);
+ goto error;
+ }
+ if (gdigrab->show_region) {
+ av_log(s1, AV_LOG_WARNING,
+ "Can't show region when grabbing a window.\n");
+ gdigrab->show_region = 0;
+ }
+ } else if (!strcmp(filename, "desktop")) {
+ hwnd = NULL;
+ } else {
+ av_log(s1, AV_LOG_ERROR,
+ "Please use \"desktop\" or \"title=<windowname>\" to specify your target.\n");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ if (hwnd) {
+ GetClientRect(hwnd, &virtual_rect);
+ } else {
+ virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
+ virtual_rect.right = virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ virtual_rect.bottom = virtual_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ }
+
+ /* If no width or height set, use full screen/window area */
+ if (!gdigrab->width || !gdigrab->height) {
+ clip_rect.left = virtual_rect.left;
+ clip_rect.top = virtual_rect.top;
+ clip_rect.right = virtual_rect.right;
+ clip_rect.bottom = virtual_rect.bottom;
+ } else {
+ clip_rect.left = gdigrab->offset_x;
+ clip_rect.top = gdigrab->offset_y;
+ clip_rect.right = gdigrab->width + gdigrab->offset_x;
+ clip_rect.bottom = gdigrab->height + gdigrab->offset_y;
+ }
+
+ if (clip_rect.left < virtual_rect.left ||
+ clip_rect.top < virtual_rect.top ||
+ clip_rect.right > virtual_rect.right ||
+ clip_rect.bottom > virtual_rect.bottom) {
+ av_log(s1, AV_LOG_ERROR,
+ "Capture area (%li,%li),(%li,%li) extends outside window area (%li,%li),(%li,%li)",
+ clip_rect.left, clip_rect.top,
+ clip_rect.right, clip_rect.bottom,
+ virtual_rect.left, virtual_rect.top,
+ virtual_rect.right, virtual_rect.bottom);
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ /* This will get the device context for the selected window, or if
+ * none, the primary screen */
+ source_hdc = GetDC(hwnd);
+ if (!source_hdc) {
+ WIN32_API_ERROR("Couldn't get window device context");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+ bpp = GetDeviceCaps(source_hdc, BITSPIXEL);
+
+ if (name) {
+ av_log(s1, AV_LOG_INFO,
+ "Found window %s, capturing %lix%lix%i at (%li,%li)\n",
+ name,
+ clip_rect.right - clip_rect.left,
+ clip_rect.bottom - clip_rect.top,
+ bpp, clip_rect.left, clip_rect.top);
+ } else {
+ av_log(s1, AV_LOG_INFO,
+ "Capturing whole desktop as %lix%lix%i at (%li,%li)\n",
+ clip_rect.right - clip_rect.left,
+ clip_rect.bottom - clip_rect.top,
+ bpp, clip_rect.left, clip_rect.top);
+ }
+
+ if (clip_rect.right - clip_rect.left <= 0 ||
+ clip_rect.bottom - clip_rect.top <= 0 || bpp%8) {
+ av_log(s1, AV_LOG_ERROR, "Invalid properties, aborting\n");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ dest_hdc = CreateCompatibleDC(source_hdc);
+ if (!dest_hdc) {
+ WIN32_API_ERROR("Screen DC CreateCompatibleDC");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ /* Create a DIB and select it into the dest_hdc */
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = clip_rect.right - clip_rect.left;
+ bmi.bmiHeader.biHeight = -(clip_rect.bottom - clip_rect.top);
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = bpp;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+ hbmp = CreateDIBSection(dest_hdc, &bmi, DIB_RGB_COLORS,
+ &buffer, NULL, 0);
+ if (!hbmp) {
+ WIN32_API_ERROR("Creating DIB Section");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ if (!SelectObject(dest_hdc, hbmp)) {
+ WIN32_API_ERROR("SelectObject");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ /* Get info from the bitmap */
+ GetObject(hbmp, sizeof(BITMAP), &bmp);
+
+ st = avformat_new_stream(s1, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
+ gdigrab->frame_size = bmp.bmWidthBytes * bmp.bmHeight * bmp.bmPlanes;
+ gdigrab->header_size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
+ (bpp <= 8 ? (1 << bpp) : 0) * sizeof(RGBQUAD) /* palette size */;
+ gdigrab->time_base = av_inv_q(gdigrab->framerate);
+ gdigrab->time_frame = av_gettime() / av_q2d(gdigrab->time_base);
+
+ gdigrab->hwnd = hwnd;
+ gdigrab->source_hdc = source_hdc;
+ gdigrab->dest_hdc = dest_hdc;
+ gdigrab->hbmp = hbmp;
+ gdigrab->bmi = bmi;
+ gdigrab->buffer = buffer;
+ gdigrab->clip_rect = clip_rect;
+
+ gdigrab->cursor_error_printed = 0;
+
+ if (gdigrab->show_region) {
+ if (gdigrab_region_wnd_init(s1, gdigrab)) {
+ ret = AVERROR(EIO);
+ goto error;
+ }
+ }
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_BMP;
+ st->codec->time_base = gdigrab->time_base;
+ st->codec->bit_rate = (gdigrab->header_size + gdigrab->frame_size) * 1/av_q2d(gdigrab->time_base) * 8;
+
+ return 0;
+
+error:
+ if (source_hdc)
+ ReleaseDC(hwnd, source_hdc);
+ if (dest_hdc)
+ DeleteDC(dest_hdc);
+ if (hbmp)
+ DeleteObject(hbmp);
+ if (source_hdc)
+ DeleteDC(source_hdc);
+ return ret;
+}
+
+/**
+ * Paints a mouse pointer in a Win32 image.
+ *
+ * @param s1 Context of the log information
+ * @param s Current grad structure
+ */
+static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab)
+{
+ CURSORINFO ci = {0};
+
+#define CURSOR_ERROR(str) \
+ if (!gdigrab->cursor_error_printed) { \
+ WIN32_API_ERROR(str); \
+ gdigrab->cursor_error_printed = 1; \
+ }
+
+ ci.cbSize = sizeof(ci);
+
+ if (GetCursorInfo(&ci)) {
+ HCURSOR icon = CopyCursor(ci.hCursor);
+ ICONINFO info;
+ POINT pos;
+ RECT clip_rect = gdigrab->clip_rect;
+ HWND hwnd = gdigrab->hwnd;
+ info.hbmMask = NULL;
+ info.hbmColor = NULL;
+
+ if (ci.flags != CURSOR_SHOWING)
+ return;
+
+ if (!icon) {
+ /* Use the standard arrow cursor as a fallback.
+ * You'll probably only hit this in Wine, which can't fetch
+ * the current system cursor. */
+ icon = CopyCursor(LoadCursor(NULL, IDC_ARROW));
+ }
+
+ if (!GetIconInfo(icon, &info)) {
+ CURSOR_ERROR("Could not get icon info");
+ goto icon_error;
+ }
+
+ pos.x = ci.ptScreenPos.x - clip_rect.left - info.xHotspot;
+ pos.y = ci.ptScreenPos.y - clip_rect.top - info.yHotspot;
+
+ if (hwnd) {
+ RECT rect;
+
+ if (GetWindowRect(hwnd, &rect)) {
+ pos.x -= rect.left;
+ pos.y -= rect.top;
+ } else {
+ CURSOR_ERROR("Couldn't get window rectangle");
+ goto icon_error;
+ }
+ }
+
+ av_log(s1, AV_LOG_DEBUG, "Cursor pos (%li,%li) -> (%li,%li)\n",
+ ci.ptScreenPos.x, ci.ptScreenPos.y, pos.x, pos.y);
+
+ if (pos.x >= 0 && pos.x <= clip_rect.right - clip_rect.left &&
+ pos.y >= 0 && pos.y <= clip_rect.bottom - clip_rect.top) {
+ if (!DrawIcon(gdigrab->dest_hdc, pos.x, pos.y, icon))
+ CURSOR_ERROR("Couldn't draw icon");
+ }
+
+icon_error:
+ if (info.hbmMask)
+ DeleteObject(info.hbmMask);
+ if (info.hbmColor)
+ DeleteObject(info.hbmColor);
+ if (icon)
+ DestroyCursor(icon);
+ } else {
+ CURSOR_ERROR("Couldn't get cursor info");
+ }
+}
+
+/**
+ * Grabs a frame from gdi (public device demuxer API).
+ *
+ * @param s1 Context from avformat core
+ * @param pkt Packet holding the grabbed frame
+ * @return frame size in bytes
+ */
+static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
+{
+ struct gdigrab *gdigrab = s1->priv_data;
+
+ HDC dest_hdc = gdigrab->dest_hdc;
+ HDC source_hdc = gdigrab->source_hdc;
+ RECT clip_rect = gdigrab->clip_rect;
+ AVRational time_base = gdigrab->time_base;
+ int64_t time_frame = gdigrab->time_frame;
+
+ BITMAPFILEHEADER bfh;
+ int file_size = gdigrab->header_size + gdigrab->frame_size;
+
+ int64_t curtime, delay;
+
+ /* Calculate the time of the next frame */
+ time_frame += INT64_C(1000000);
+
+ /* Run Window message processing queue */
+ if (gdigrab->show_region)
+ gdigrab_region_wnd_update(s1, gdigrab);
+
+ /* wait based on the frame rate */
+ for (;;) {
+ curtime = av_gettime();
+ delay = time_frame * av_q2d(time_base) - curtime;
+ if (delay <= 0) {
+ if (delay < INT64_C(-1000000) * av_q2d(time_base)) {
+ time_frame += INT64_C(1000000);
+ }
+ break;
+ }
+ if (s1->flags & AVFMT_FLAG_NONBLOCK) {
+ return AVERROR(EAGAIN);
+ } else {
+ av_usleep(delay);
+ }
+ }
+
+ if (av_new_packet(pkt, file_size) < 0)
+ return AVERROR(ENOMEM);
+ pkt->pts = curtime;
+
+ /* Blit screen grab */
+ if (!BitBlt(dest_hdc, 0, 0,
+ clip_rect.right - clip_rect.left,
+ clip_rect.bottom - clip_rect.top,
+ source_hdc,
+ clip_rect.left, clip_rect.top, SRCCOPY | CAPTUREBLT)) {
+ WIN32_API_ERROR("Failed to capture image");
+ return AVERROR(EIO);
+ }
+ if (gdigrab->draw_mouse)
+ paint_mouse_pointer(s1, gdigrab);
+
+ /* Copy bits to packet data */
+
+ bfh.bfType = 0x4d42; /* "BM" in little-endian */
+ bfh.bfSize = file_size;
+ bfh.bfReserved1 = 0;
+ bfh.bfReserved2 = 0;
+ bfh.bfOffBits = gdigrab->header_size;
+
+ memcpy(pkt->data, &bfh, sizeof(bfh));
+
+ memcpy(pkt->data + sizeof(bfh), &gdigrab->bmi.bmiHeader, sizeof(gdigrab->bmi.bmiHeader));
+
+ if (gdigrab->bmi.bmiHeader.biBitCount <= 8)
+ GetDIBColorTable(dest_hdc, 0, 1 << gdigrab->bmi.bmiHeader.biBitCount,
+ (RGBQUAD *) (pkt->data + sizeof(bfh) + sizeof(gdigrab->bmi.bmiHeader)));
+
+ memcpy(pkt->data + gdigrab->header_size, gdigrab->buffer, gdigrab->frame_size);
+
+ gdigrab->time_frame = time_frame;
+
+ return gdigrab->header_size + gdigrab->frame_size;
+}
+
+/**
+ * Closes gdi frame grabber (public device demuxer API).
+ *
+ * @param s1 Context from avformat core
+ * @return 0 success, !0 failure
+ */
+static int gdigrab_read_close(AVFormatContext *s1)
+{
+ struct gdigrab *s = s1->priv_data;
+
+ if (s->show_region)
+ gdigrab_region_wnd_destroy(s1, s);
+
+ if (s->source_hdc)
+ ReleaseDC(s->hwnd, s->source_hdc);
+ if (s->dest_hdc)
+ DeleteDC(s->dest_hdc);
+ if (s->hbmp)
+ DeleteObject(s->hbmp);
+ if (s->source_hdc)
+ DeleteDC(s->source_hdc);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(struct gdigrab, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
+ { "show_region", "draw border around capture area", OFFSET(show_region), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
+ { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, 0, DEC },
+ { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
+ { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
+ { NULL },
+};
+
+static const AVClass gdigrab_class = {
+ .class_name = "GDIgrab indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+/** gdi grabber device demuxer declaration */
+AVInputFormat ff_gdigrab_demuxer = {
+ .name = "gdigrab",
+ .long_name = NULL_IF_CONFIG_SMALL("GDI API Windows frame grabber"),
+ .priv_data_size = sizeof(struct gdigrab),
+ .read_header = gdigrab_read_header,
+ .read_packet = gdigrab_read_packet,
+ .read_close = gdigrab_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &gdigrab_class,
+};
diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c
new file mode 100644
index 0000000000..b29aad1d48
--- /dev/null
+++ b/libavdevice/iec61883.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2012 Georg Lippitsch <georg.lippitsch@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * libiec61883 interface
+ */
+
+#include <sys/poll.h>
+#include <libraw1394/raw1394.h>
+#include <libavc1394/avc1394.h>
+#include <libavc1394/rom1394.h>
+#include <libiec61883/iec61883.h>
+#include "libavformat/dv.h"
+#include "libavformat/mpegts.h"
+#include "libavutil/opt.h"
+#include "avdevice.h"
+
+#define THREADS HAVE_PTHREADS
+
+#if THREADS
+#include <pthread.h>
+#endif
+
+#define MOTDCT_SPEC_ID 0x00005068
+#define IEC61883_AUTO 0
+#define IEC61883_DV 1
+#define IEC61883_HDV 2
+
+/**
+ * For DV, one packet corresponds exactly to one frame.
+ * For HDV, these are MPEG2 transport stream packets.
+ * The queue is implemented as linked list.
+ */
+typedef struct DVPacket {
+ uint8_t *buf; ///< actual buffer data
+ int len; ///< size of buffer allocated
+ struct DVPacket *next; ///< next DVPacket
+} DVPacket;
+
+struct iec61883_data {
+ AVClass *class;
+ raw1394handle_t raw1394; ///< handle for libraw1394
+ iec61883_dv_fb_t iec61883_dv; ///< handle for libiec61883 when used with DV
+ iec61883_mpeg2_t iec61883_mpeg2; ///< handle for libiec61883 when used with HDV
+
+ DVDemuxContext *dv_demux; ///< generic DV muxing/demuxing context
+ MpegTSContext *mpeg_demux; ///< generic HDV muxing/demuxing context
+
+ DVPacket *queue_first; ///< first element of packet queue
+ DVPacket *queue_last; ///< last element of packet queue
+
+ char *device_guid; ///< to select one of multiple DV devices
+
+ int packets; ///< Number of packets queued
+ int max_packets; ///< Max. number of packets in queue
+
+ int bandwidth; ///< returned by libiec61883
+ int channel; ///< returned by libiec61883
+ int input_port; ///< returned by libiec61883
+ int type; ///< Stream type, to distinguish DV/HDV
+ int node; ///< returned by libiec61883
+ int output_port; ///< returned by libiec61883
+ int thread_loop; ///< Condition for thread while-loop
+ int receiving; ///< True as soon data from device available
+ int receive_error; ///< Set in receive task in case of error
+ int eof; ///< True as soon as no more data available
+
+ struct pollfd raw1394_poll; ///< to poll for new data from libraw1394
+
+ /** Parse function for DV/HDV differs, so this is set before packets arrive */
+ int (*parse_queue)(struct iec61883_data *dv, AVPacket *pkt);
+
+#if THREADS
+ pthread_t receive_task_thread;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+#endif
+};
+
+static int iec61883_callback(unsigned char *data, int length,
+ int complete, void *callback_data)
+{
+ struct iec61883_data *dv = callback_data;
+ DVPacket *packet;
+ int ret;
+
+#if THREADS
+ pthread_mutex_lock(&dv->mutex);
+#endif
+
+ if (dv->packets >= dv->max_packets) {
+ av_log(NULL, AV_LOG_ERROR, "DV packet queue overrun, dropping.\n");
+ ret = 0;
+ goto exit;
+ }
+
+ packet = av_mallocz(sizeof(*packet));
+ if (!packet) {
+ ret = -1;
+ goto exit;
+ }
+
+ packet->buf = av_malloc(length);
+ if (!packet->buf) {
+ ret = -1;
+ goto exit;
+ }
+ packet->len = length;
+
+ memcpy(packet->buf, data, length);
+
+ if (dv->queue_first) {
+ dv->queue_last->next = packet;
+ dv->queue_last = packet;
+ } else {
+ dv->queue_first = packet;
+ dv->queue_last = packet;
+ }
+ dv->packets++;
+
+ ret = 0;
+
+exit:
+#if THREADS
+ pthread_cond_broadcast(&dv->cond);
+ pthread_mutex_unlock(&dv->mutex);
+#endif
+ return ret;
+}
+
+static void *iec61883_receive_task(void *opaque)
+{
+ struct iec61883_data *dv = (struct iec61883_data *)opaque;
+ int result;
+
+#if THREADS
+ while (dv->thread_loop)
+#endif
+ {
+ while ((result = poll(&dv->raw1394_poll, 1, 200)) < 0) {
+ if (!(errno == EAGAIN || errno == EINTR)) {
+ av_log(NULL, AV_LOG_ERROR, "Raw1394 poll error occurred.\n");
+ dv->receive_error = AVERROR(EIO);
+ return NULL;
+ }
+ }
+ if (result > 0 && ((dv->raw1394_poll.revents & POLLIN)
+ || (dv->raw1394_poll.revents & POLLPRI))) {
+ dv->receiving = 1;
+ raw1394_loop_iterate(dv->raw1394);
+ } else if (dv->receiving) {
+ av_log(NULL, AV_LOG_ERROR, "No more input data available\n");
+#if THREADS
+ pthread_mutex_lock(&dv->mutex);
+ dv->eof = 1;
+ pthread_cond_broadcast(&dv->cond);
+ pthread_mutex_unlock(&dv->mutex);
+#else
+ dv->eof = 1;
+#endif
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+static int iec61883_parse_queue_dv(struct iec61883_data *dv, AVPacket *pkt)
+{
+ DVPacket *packet;
+ int size;
+
+ size = avpriv_dv_get_packet(dv->dv_demux, pkt);
+ if (size > 0)
+ return size;
+
+ packet = dv->queue_first;
+ if (!packet)
+ return -1;
+
+ size = avpriv_dv_produce_packet(dv->dv_demux, pkt,
+ packet->buf, packet->len, -1);
+ pkt->destruct = av_destruct_packet;
+ dv->queue_first = packet->next;
+ av_free(packet);
+ dv->packets--;
+
+ if (size > 0)
+ return size;
+
+ return -1;
+}
+
+static int iec61883_parse_queue_hdv(struct iec61883_data *dv, AVPacket *pkt)
+{
+ DVPacket *packet;
+ int size;
+
+ while (dv->queue_first) {
+ packet = dv->queue_first;
+ size = avpriv_mpegts_parse_packet(dv->mpeg_demux, pkt, packet->buf,
+ packet->len);
+ dv->queue_first = packet->next;
+ av_freep(&packet->buf);
+ av_freep(&packet);
+ dv->packets--;
+
+ if (size > 0)
+ return size;
+ }
+
+ return -1;
+}
+
+static int iec61883_read_header(AVFormatContext *context)
+{
+ struct iec61883_data *dv = context->priv_data;
+ struct raw1394_portinfo pinf[16];
+ rom1394_directory rom_dir;
+ char *endptr;
+ int inport;
+ int nb_ports;
+ int port = -1;
+ int response;
+ int i, j = 0;
+ uint64_t guid = 0;
+
+ dv->input_port = -1;
+ dv->output_port = -1;
+ dv->channel = -1;
+
+ dv->raw1394 = raw1394_new_handle();
+
+ if (!dv->raw1394) {
+ av_log(context, AV_LOG_ERROR, "Failed to open IEEE1394 interface.\n");
+ return AVERROR(EIO);
+ }
+
+ if ((nb_ports = raw1394_get_port_info(dv->raw1394, pinf, 16)) < 0) {
+ av_log(context, AV_LOG_ERROR, "Failed to get number of IEEE1394 ports.\n");
+ goto fail;
+ }
+
+ inport = strtol(context->filename, &endptr, 10);
+ if (endptr != context->filename && *endptr == '\0') {
+ av_log(context, AV_LOG_INFO, "Selecting IEEE1394 port: %d\n", inport);
+ j = inport;
+ nb_ports = inport + 1;
+ } else if (strcmp(context->filename, "auto")) {
+ av_log(context, AV_LOG_ERROR, "Invalid input \"%s\", you should specify "
+ "\"auto\" for auto-detection, or the port number.\n", context->filename);
+ goto fail;
+ }
+
+ if (dv->device_guid) {
+ if (sscanf(dv->device_guid, "%llx", (long long unsigned int *)&guid) != 1) {
+ av_log(context, AV_LOG_INFO, "Invalid dvguid parameter: %s\n",
+ dv->device_guid);
+ goto fail;
+ }
+ }
+
+ for (; j < nb_ports && port==-1; ++j) {
+ raw1394_destroy_handle(dv->raw1394);
+
+ if (!(dv->raw1394 = raw1394_new_handle_on_port(j))) {
+ av_log(context, AV_LOG_ERROR, "Failed setting IEEE1394 port.\n");
+ goto fail;
+ }
+
+ for (i=0; i<raw1394_get_nodecount(dv->raw1394); ++i) {
+
+ /* Select device explicitly by GUID */
+
+ if (guid > 1) {
+ if (guid == rom1394_get_guid(dv->raw1394, i)) {
+ dv->node = i;
+ port = j;
+ break;
+ }
+ } else {
+
+ /* Select first AV/C tape recorder player node */
+
+ if (rom1394_get_directory(dv->raw1394, i, &rom_dir) < 0)
+ continue;
+ if (((rom1394_get_node_type(&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
+ avc1394_check_subunit_type(dv->raw1394, i, AVC1394_SUBUNIT_TYPE_VCR)) ||
+ (rom_dir.unit_spec_id == MOTDCT_SPEC_ID)) {
+ rom1394_free_directory(&rom_dir);
+ dv->node = i;
+ port = j;
+ break;
+ }
+ rom1394_free_directory(&rom_dir);
+ }
+ }
+ }
+
+ if (port == -1) {
+ av_log(context, AV_LOG_ERROR, "No AV/C devices found.\n");
+ goto fail;
+ }
+
+ /* Provide bus sanity for multiple connections */
+
+ iec61883_cmp_normalize_output(dv->raw1394, 0xffc0 | dv->node);
+
+ /* Find out if device is DV or HDV */
+
+ if (dv->type == IEC61883_AUTO) {
+ response = avc1394_transaction(dv->raw1394, dv->node,
+ AVC1394_CTYPE_STATUS |
+ AVC1394_SUBUNIT_TYPE_TAPE_RECORDER |
+ AVC1394_SUBUNIT_ID_0 |
+ AVC1394_VCR_COMMAND_OUTPUT_SIGNAL_MODE |
+ 0xFF, 2);
+ response = AVC1394_GET_OPERAND0(response);
+ dv->type = (response == 0x10 || response == 0x90 || response == 0x1A || response == 0x9A) ?
+ IEC61883_HDV : IEC61883_DV;
+ }
+
+ /* Connect to device, and do initialization */
+
+ dv->channel = iec61883_cmp_connect(dv->raw1394, dv->node, &dv->output_port,
+ raw1394_get_local_id(dv->raw1394),
+ &dv->input_port, &dv->bandwidth);
+
+ if (dv->channel < 0)
+ dv->channel = 63;
+
+ if (!dv->max_packets)
+ dv->max_packets = 100;
+
+ if (CONFIG_MPEGTS_DEMUXER && dv->type == IEC61883_HDV) {
+
+ /* Init HDV receive */
+
+ avformat_new_stream(context, NULL);
+
+ dv->mpeg_demux = avpriv_mpegts_parse_open(context);
+ if (!dv->mpeg_demux)
+ goto fail;
+
+ dv->parse_queue = iec61883_parse_queue_hdv;
+
+ dv->iec61883_mpeg2 = iec61883_mpeg2_recv_init(dv->raw1394,
+ (iec61883_mpeg2_recv_t)iec61883_callback,
+ dv);
+
+ dv->max_packets *= 766;
+ } else {
+
+ /* Init DV receive */
+
+ dv->dv_demux = avpriv_dv_init_demux(context);
+ if (!dv->dv_demux)
+ goto fail;
+
+ dv->parse_queue = iec61883_parse_queue_dv;
+
+ dv->iec61883_dv = iec61883_dv_fb_init(dv->raw1394, iec61883_callback, dv);
+ }
+
+ dv->raw1394_poll.fd = raw1394_get_fd(dv->raw1394);
+ dv->raw1394_poll.events = POLLIN | POLLERR | POLLHUP | POLLPRI;
+
+ /* Actually start receiving */
+
+ if (dv->type == IEC61883_HDV)
+ iec61883_mpeg2_recv_start(dv->iec61883_mpeg2, dv->channel);
+ else
+ iec61883_dv_fb_start(dv->iec61883_dv, dv->channel);
+
+#if THREADS
+ dv->thread_loop = 1;
+ pthread_mutex_init(&dv->mutex, NULL);
+ pthread_cond_init(&dv->cond, NULL);
+ pthread_create(&dv->receive_task_thread, NULL, iec61883_receive_task, dv);
+#endif
+
+ return 0;
+
+fail:
+ raw1394_destroy_handle(dv->raw1394);
+ return AVERROR(EIO);
+}
+
+static int iec61883_read_packet(AVFormatContext *context, AVPacket *pkt)
+{
+ struct iec61883_data *dv = context->priv_data;
+ int size;
+
+ /**
+ * Try to parse frames from queue
+ */
+
+#if THREADS
+ pthread_mutex_lock(&dv->mutex);
+ while ((size = dv->parse_queue(dv, pkt)) == -1)
+ if (!dv->eof)
+ pthread_cond_wait(&dv->cond, &dv->mutex);
+ else
+ break;
+ pthread_mutex_unlock(&dv->mutex);
+#else
+ int result;
+ while ((size = dv->parse_queue(dv, pkt)) == -1) {
+ iec61883_receive_task((void *)dv);
+ if (dv->receive_error)
+ return dv->receive_error;
+ }
+#endif
+
+ return size;
+}
+
+static int iec61883_close(AVFormatContext *context)
+{
+ struct iec61883_data *dv = context->priv_data;
+
+#if THREADS
+ dv->thread_loop = 0;
+ pthread_join(dv->receive_task_thread, NULL);
+ pthread_cond_destroy(&dv->cond);
+ pthread_mutex_destroy(&dv->mutex);
+#endif
+
+ if (CONFIG_MPEGTS_DEMUXER && dv->type == IEC61883_HDV) {
+ iec61883_mpeg2_recv_stop(dv->iec61883_mpeg2);
+ iec61883_mpeg2_close(dv->iec61883_mpeg2);
+ avpriv_mpegts_parse_close(dv->mpeg_demux);
+ } else {
+ iec61883_dv_fb_stop(dv->iec61883_dv);
+ iec61883_dv_fb_close(dv->iec61883_dv);
+ }
+ while (dv->queue_first) {
+ DVPacket *packet = dv->queue_first;
+ dv->queue_first = packet->next;
+ av_freep(&packet->buf);
+ av_freep(&packet);
+ }
+
+ iec61883_cmp_disconnect(dv->raw1394, dv->node, dv->output_port,
+ raw1394_get_local_id(dv->raw1394),
+ dv->input_port, dv->channel, dv->bandwidth);
+
+ raw1394_destroy_handle(dv->raw1394);
+
+ return 0;
+}
+
+static const AVOption options[] = {
+ { "dvtype", "override autodetection of DV/HDV", offsetof(struct iec61883_data, type), AV_OPT_TYPE_INT, {.i64 = IEC61883_AUTO}, IEC61883_AUTO, IEC61883_HDV, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
+ { "auto", "auto detect DV/HDV", 0, AV_OPT_TYPE_CONST, {.i64 = IEC61883_AUTO}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
+ { "dv", "force device being treated as DV device", 0, AV_OPT_TYPE_CONST, {.i64 = IEC61883_DV}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
+ { "hdv" , "force device being treated as HDV device", 0, AV_OPT_TYPE_CONST, {.i64 = IEC61883_HDV}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
+ { "dvbuffer", "set queue buffer size (in packets)", offsetof(struct iec61883_data, max_packets), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { "dvguid", "select one of multiple DV devices by its GUID", offsetof(struct iec61883_data, device_guid), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass iec61883_class = {
+ .class_name = "iec61883 indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_iec61883_demuxer = {
+ .name = "iec61883",
+ .long_name = NULL_IF_CONFIG_SMALL("libiec61883 (new DV1394) A/V input device"),
+ .priv_data_size = sizeof(struct iec61883_data),
+ .read_header = iec61883_read_header,
+ .read_packet = iec61883_read_packet,
+ .read_close = iec61883_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &iec61883_class,
+};
diff --git a/libavdevice/internal.h b/libavdevice/internal.h
new file mode 100644
index 0000000000..3cd1b0686e
--- /dev/null
+++ b/libavdevice/internal.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVDEVICE_INTERNAL_H
+#define AVDEVICE_INTERNAL_H
+
+#include "libavformat/avformat.h"
+
+int ff_alloc_input_device_context(struct AVFormatContext **avctx, struct AVInputFormat *iformat,
+ const char *format);
+
+#endif
diff --git a/libavdevice/jack.c b/libavdevice/jack.c
index 5d000a3cd0..df829ad45a 100644
--- a/libavdevice/jack.c
+++ b/libavdevice/jack.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Samalyse
* Author: Olivier Guilyardi <olivier samalyse com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,7 @@
#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "timefilter.h"
+#include "avdevice.h"
/**
* Size of the internal FIFO buffers as a number of audio packets
@@ -152,7 +153,6 @@ static int start_jack(AVFormatContext *context)
JackData *self = context->priv_data;
jack_status_t status;
int i, test;
- double o, period;
/* Register as a JACK client, using the context filename as client name. */
self->client = jack_client_open(context->filename, JackNullOption, &status);
@@ -164,7 +164,7 @@ static int start_jack(AVFormatContext *context)
sem_init(&self->packet_count, 0, 0);
self->sample_rate = jack_get_sample_rate(self->client);
- self->ports = av_malloc(self->nports * sizeof(*self->ports));
+ self->ports = av_malloc_array(self->nports, sizeof(*self->ports));
if (!self->ports)
return AVERROR(ENOMEM);
self->buffer_size = jack_get_buffer_size(self->client);
@@ -190,18 +190,16 @@ static int start_jack(AVFormatContext *context)
jack_set_xrun_callback(self->client, xrun_callback, self);
/* Create time filter */
- period = (double) self->buffer_size / self->sample_rate;
- o = 2 * M_PI * 1.5 * period; /// bandwidth: 1.5Hz
- self->timefilter = ff_timefilter_new (1.0 / self->sample_rate, sqrt(2 * o), o * o);
+ self->timefilter = ff_timefilter_new (1.0 / self->sample_rate, self->buffer_size, 1.5);
if (!self->timefilter) {
jack_client_close(self->client);
return AVERROR(ENOMEM);
}
/* Create FIFO buffers */
- self->filled_pkts = av_fifo_alloc(FIFO_PACKETS_NUM * sizeof(AVPacket));
+ self->filled_pkts = av_fifo_alloc_array(FIFO_PACKETS_NUM, sizeof(AVPacket));
/* New packets FIFO with one extra packet for safety against underruns */
- self->new_pkts = av_fifo_alloc((FIFO_PACKETS_NUM + 1) * sizeof(AVPacket));
+ self->new_pkts = av_fifo_alloc_array((FIFO_PACKETS_NUM + 1), sizeof(AVPacket));
if ((test = supply_new_packets(self, context))) {
jack_client_close(self->client);
return test;
@@ -211,14 +209,14 @@ static int start_jack(AVFormatContext *context)
}
-static void free_pkt_fifo(AVFifoBuffer *fifo)
+static void free_pkt_fifo(AVFifoBuffer **fifo)
{
AVPacket pkt;
- while (av_fifo_size(fifo)) {
- av_fifo_generic_read(fifo, &pkt, sizeof(pkt), NULL);
+ while (av_fifo_size(*fifo)) {
+ av_fifo_generic_read(*fifo, &pkt, sizeof(pkt), NULL);
av_free_packet(&pkt);
}
- av_fifo_free(fifo);
+ av_fifo_freep(fifo);
}
static void stop_jack(JackData *self)
@@ -229,8 +227,8 @@ static void stop_jack(JackData *self)
jack_client_close(self->client);
}
sem_destroy(&self->packet_count);
- free_pkt_fifo(self->new_pkts);
- free_pkt_fifo(self->filled_pkts);
+ free_pkt_fifo(&self->new_pkts);
+ free_pkt_fifo(&self->filled_pkts);
av_freep(&self->ports);
ff_timefilter_destroy(self->timefilter);
}
@@ -341,6 +339,7 @@ static const AVClass jack_indev_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
};
AVInputFormat ff_jack_demuxer = {
diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c
new file mode 100644
index 0000000000..64db376899
--- /dev/null
+++ b/libavdevice/lavfi.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * libavfilter virtual input device
+ */
+
+/* #define DEBUG */
+
+#include <float.h> /* DBL_MIN, DBL_MAX */
+
+#include "libavutil/bprint.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/file.h"
+#include "libavutil/log.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavfilter/avfilter.h"
+#include "libavfilter/avfiltergraph.h"
+#include "libavfilter/buffersink.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
+
+typedef struct {
+ AVClass *class; ///< class for private options
+ char *graph_str;
+ char *graph_filename;
+ char *dump_graph;
+ AVFilterGraph *graph;
+ AVFilterContext **sinks;
+ int *sink_stream_map;
+ int *sink_eof;
+ int *stream_sink_map;
+ int *sink_stream_subcc_map;
+ AVFrame *decoded_frame;
+ int nb_sinks;
+ AVPacket subcc_packet;
+} LavfiContext;
+
+static int *create_all_formats(int n)
+{
+ int i, j, *fmts, count = 0;
+
+ for (i = 0; i < n; i++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ count++;
+ }
+
+ if (!(fmts = av_malloc((count+1) * sizeof(int))))
+ return NULL;
+ for (j = 0, i = 0; i < n; i++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ fmts[j++] = i;
+ }
+ fmts[j] = -1;
+ return fmts;
+}
+
+av_cold static int lavfi_read_close(AVFormatContext *avctx)
+{
+ LavfiContext *lavfi = avctx->priv_data;
+
+ av_freep(&lavfi->sink_stream_map);
+ av_freep(&lavfi->sink_eof);
+ av_freep(&lavfi->stream_sink_map);
+ av_freep(&lavfi->sink_stream_subcc_map);
+ av_freep(&lavfi->sinks);
+ avfilter_graph_free(&lavfi->graph);
+ av_frame_free(&lavfi->decoded_frame);
+
+ return 0;
+}
+
+static int create_subcc_streams(AVFormatContext *avctx)
+{
+ LavfiContext *lavfi = avctx->priv_data;
+ AVStream *st;
+ int stream_idx, sink_idx;
+
+ for (stream_idx = 0; stream_idx < lavfi->nb_sinks; stream_idx++) {
+ sink_idx = lavfi->stream_sink_map[stream_idx];
+ if (lavfi->sink_stream_subcc_map[sink_idx]) {
+ lavfi->sink_stream_subcc_map[sink_idx] = avctx->nb_streams;
+ if (!(st = avformat_new_stream(avctx, NULL)))
+ return AVERROR(ENOMEM);
+ st->codec->codec_id = AV_CODEC_ID_EIA_608;
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ } else {
+ lavfi->sink_stream_subcc_map[sink_idx] = -1;
+ }
+ }
+ return 0;
+}
+
+av_cold static int lavfi_read_header(AVFormatContext *avctx)
+{
+ LavfiContext *lavfi = avctx->priv_data;
+ AVFilterInOut *input_links = NULL, *output_links = NULL, *inout;
+ AVFilter *buffersink, *abuffersink;
+ int *pix_fmts = create_all_formats(AV_PIX_FMT_NB);
+ enum AVMediaType type;
+ int ret = 0, i, n;
+
+#define FAIL(ERR) { ret = ERR; goto end; }
+
+ if (!pix_fmts)
+ FAIL(AVERROR(ENOMEM));
+
+ avfilter_register_all();
+
+ buffersink = avfilter_get_by_name("buffersink");
+ abuffersink = avfilter_get_by_name("abuffersink");
+
+ if (lavfi->graph_filename && lavfi->graph_str) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Only one of the graph or graph_file options must be specified\n");
+ FAIL(AVERROR(EINVAL));
+ }
+
+ if (lavfi->graph_filename) {
+ AVBPrint graph_file_pb;
+ AVIOContext *avio = NULL;
+ ret = avio_open(&avio, lavfi->graph_filename, AVIO_FLAG_READ);
+ if (ret < 0)
+ goto end;
+ av_bprint_init(&graph_file_pb, 0, AV_BPRINT_SIZE_UNLIMITED);
+ ret = avio_read_to_bprint(avio, &graph_file_pb, INT_MAX);
+ avio_closep(&avio);
+ av_bprint_chars(&graph_file_pb, '\0', 1);
+ if (!ret && !av_bprint_is_complete(&graph_file_pb))
+ ret = AVERROR(ENOMEM);
+ if (ret) {
+ av_bprint_finalize(&graph_file_pb, NULL);
+ goto end;
+ }
+ if ((ret = av_bprint_finalize(&graph_file_pb, &lavfi->graph_str)))
+ goto end;
+ }
+
+ if (!lavfi->graph_str)
+ lavfi->graph_str = av_strdup(avctx->filename);
+
+ /* parse the graph, create a stream for each open output */
+ if (!(lavfi->graph = avfilter_graph_alloc()))
+ FAIL(AVERROR(ENOMEM));
+
+ if ((ret = avfilter_graph_parse_ptr(lavfi->graph, lavfi->graph_str,
+ &input_links, &output_links, avctx)) < 0)
+ goto end;
+
+ if (input_links) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Open inputs in the filtergraph are not acceptable\n");
+ FAIL(AVERROR(EINVAL));
+ }
+
+ /* count the outputs */
+ for (n = 0, inout = output_links; inout; n++, inout = inout->next);
+ lavfi->nb_sinks = n;
+
+ if (!(lavfi->sink_stream_map = av_malloc(sizeof(int) * n)))
+ FAIL(AVERROR(ENOMEM));
+ if (!(lavfi->sink_eof = av_mallocz(sizeof(int) * n)))
+ FAIL(AVERROR(ENOMEM));
+ if (!(lavfi->stream_sink_map = av_malloc(sizeof(int) * n)))
+ FAIL(AVERROR(ENOMEM));
+ if (!(lavfi->sink_stream_subcc_map = av_malloc(sizeof(int) * n)))
+ FAIL(AVERROR(ENOMEM));
+
+ for (i = 0; i < n; i++)
+ lavfi->stream_sink_map[i] = -1;
+
+ /* parse the output link names - they need to be of the form out0, out1, ...
+ * create a mapping between them and the streams */
+ for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
+ int stream_idx = 0, suffix = 0, use_subcc = 0;
+ sscanf(inout->name, "out%n%d%n", &suffix, &stream_idx, &suffix);
+ if (!suffix) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid outpad name '%s'\n", inout->name);
+ FAIL(AVERROR(EINVAL));
+ }
+ if (inout->name[suffix]) {
+ if (!strcmp(inout->name + suffix, "+subcc")) {
+ use_subcc = 1;
+ } else {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid outpad suffix '%s'\n", inout->name);
+ FAIL(AVERROR(EINVAL));
+ }
+ }
+
+ if ((unsigned)stream_idx >= n) {
+ av_log(avctx, AV_LOG_ERROR,
+ "Invalid index was specified in output '%s', "
+ "must be a non-negative value < %d\n",
+ inout->name, n);
+ FAIL(AVERROR(EINVAL));
+ }
+
+ if (lavfi->stream_sink_map[stream_idx] != -1) {
+ av_log(avctx, AV_LOG_ERROR,
+ "An output with stream index %d was already specified\n",
+ stream_idx);
+ FAIL(AVERROR(EINVAL));
+ }
+ lavfi->sink_stream_map[i] = stream_idx;
+ lavfi->stream_sink_map[stream_idx] = i;
+ lavfi->sink_stream_subcc_map[i] = !!use_subcc;
+ }
+
+ /* for each open output create a corresponding stream */
+ for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
+ AVStream *st;
+ if (!(st = avformat_new_stream(avctx, NULL)))
+ FAIL(AVERROR(ENOMEM));
+ st->id = i;
+ }
+
+ /* create a sink for each output and connect them to the graph */
+ lavfi->sinks = av_malloc_array(lavfi->nb_sinks, sizeof(AVFilterContext *));
+ if (!lavfi->sinks)
+ FAIL(AVERROR(ENOMEM));
+
+ for (i = 0, inout = output_links; inout; i++, inout = inout->next) {
+ AVFilterContext *sink;
+
+ type = inout->filter_ctx->output_pads[inout->pad_idx].type;
+
+ if (type == AVMEDIA_TYPE_VIDEO && ! buffersink ||
+ type == AVMEDIA_TYPE_AUDIO && ! abuffersink) {
+ av_log(avctx, AV_LOG_ERROR, "Missing required buffersink filter, aborting.\n");
+ FAIL(AVERROR_FILTER_NOT_FOUND);
+ }
+
+ if (type == AVMEDIA_TYPE_VIDEO) {
+ ret = avfilter_graph_create_filter(&sink, buffersink,
+ inout->name, NULL,
+ NULL, lavfi->graph);
+ if (ret >= 0)
+ ret = av_opt_set_int_list(sink, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0)
+ goto end;
+ } else if (type == AVMEDIA_TYPE_AUDIO) {
+ enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_U8,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_DBL, -1 };
+
+ ret = avfilter_graph_create_filter(&sink, abuffersink,
+ inout->name, NULL,
+ NULL, lavfi->graph);
+ if (ret >= 0)
+ ret = av_opt_set_int_list(sink, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0)
+ goto end;
+ ret = av_opt_set_int(sink, "all_channel_counts", 1,
+ AV_OPT_SEARCH_CHILDREN);
+ if (ret < 0)
+ goto end;
+ } else {
+ av_log(avctx, AV_LOG_ERROR,
+ "Output '%s' is not a video or audio output, not yet supported\n", inout->name);
+ FAIL(AVERROR(EINVAL));
+ }
+
+ lavfi->sinks[i] = sink;
+ if ((ret = avfilter_link(inout->filter_ctx, inout->pad_idx, sink, 0)) < 0)
+ goto end;
+ }
+
+ /* configure the graph */
+ if ((ret = avfilter_graph_config(lavfi->graph, avctx)) < 0)
+ goto end;
+
+ if (lavfi->dump_graph) {
+ char *dump = avfilter_graph_dump(lavfi->graph, lavfi->dump_graph);
+ fputs(dump, stderr);
+ fflush(stderr);
+ av_free(dump);
+ }
+
+ /* fill each stream with the information in the corresponding sink */
+ for (i = 0; i < lavfi->nb_sinks; i++) {
+ AVFilterLink *link = lavfi->sinks[lavfi->stream_sink_map[i]]->inputs[0];
+ AVStream *st = avctx->streams[i];
+ st->codec->codec_type = link->type;
+ avpriv_set_pts_info(st, 64, link->time_base.num, link->time_base.den);
+ if (link->type == AVMEDIA_TYPE_VIDEO) {
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->pix_fmt = link->format;
+ st->codec->time_base = link->time_base;
+ st->codec->width = link->w;
+ st->codec->height = link->h;
+ st ->sample_aspect_ratio =
+ st->codec->sample_aspect_ratio = link->sample_aspect_ratio;
+ avctx->probesize = FFMAX(avctx->probesize,
+ link->w * link->h *
+ av_get_padded_bits_per_pixel(av_pix_fmt_desc_get(link->format)) *
+ 30);
+ } else if (link->type == AVMEDIA_TYPE_AUDIO) {
+ st->codec->codec_id = av_get_pcm_codec(link->format, -1);
+ st->codec->channels = avfilter_link_get_channels(link);
+ st->codec->sample_fmt = link->format;
+ st->codec->sample_rate = link->sample_rate;
+ st->codec->time_base = link->time_base;
+ st->codec->channel_layout = link->channel_layout;
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ av_log(avctx, AV_LOG_ERROR,
+ "Could not find PCM codec for sample format %s.\n",
+ av_get_sample_fmt_name(link->format));
+ }
+ }
+
+ if ((ret = create_subcc_streams(avctx)) < 0)
+ FAIL(ret);
+
+ if (!(lavfi->decoded_frame = av_frame_alloc()))
+ FAIL(AVERROR(ENOMEM));
+
+end:
+ av_free(pix_fmts);
+ avfilter_inout_free(&input_links);
+ avfilter_inout_free(&output_links);
+ if (ret < 0)
+ lavfi_read_close(avctx);
+ return ret;
+}
+
+static int create_subcc_packet(AVFormatContext *avctx, AVFrame *frame,
+ int sink_idx)
+{
+ LavfiContext *lavfi = avctx->priv_data;
+ AVFrameSideData *sd;
+ int stream_idx, i, ret;
+
+ if ((stream_idx = lavfi->sink_stream_subcc_map[sink_idx]) < 0)
+ return 0;
+ for (i = 0; i < frame->nb_side_data; i++)
+ if (frame->side_data[i]->type == AV_FRAME_DATA_A53_CC)
+ break;
+ if (i >= frame->nb_side_data)
+ return 0;
+ sd = frame->side_data[i];
+ if ((ret = av_new_packet(&lavfi->subcc_packet, sd->size)) < 0)
+ return ret;
+ memcpy(lavfi->subcc_packet.data, sd->data, sd->size);
+ lavfi->subcc_packet.stream_index = stream_idx;
+ lavfi->subcc_packet.pts = frame->pts;
+ lavfi->subcc_packet.pos = av_frame_get_pkt_pos(frame);
+ return 0;
+}
+
+static int lavfi_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ LavfiContext *lavfi = avctx->priv_data;
+ double min_pts = DBL_MAX;
+ int stream_idx, min_pts_sink_idx = 0;
+ AVFrame *frame = lavfi->decoded_frame;
+ AVPicture pict;
+ AVDictionary *frame_metadata;
+ int ret, i;
+ int size = 0;
+
+ if (lavfi->subcc_packet.size) {
+ *pkt = lavfi->subcc_packet;
+ av_init_packet(&lavfi->subcc_packet);
+ lavfi->subcc_packet.size = 0;
+ lavfi->subcc_packet.data = NULL;
+ return pkt->size;
+ }
+
+ /* iterate through all the graph sinks. Select the sink with the
+ * minimum PTS */
+ for (i = 0; i < lavfi->nb_sinks; i++) {
+ AVRational tb = lavfi->sinks[i]->inputs[0]->time_base;
+ double d;
+ int ret;
+
+ if (lavfi->sink_eof[i])
+ continue;
+
+ ret = av_buffersink_get_frame_flags(lavfi->sinks[i], frame,
+ AV_BUFFERSINK_FLAG_PEEK);
+ if (ret == AVERROR_EOF) {
+ av_dlog(avctx, "EOF sink_idx:%d\n", i);
+ lavfi->sink_eof[i] = 1;
+ continue;
+ } else if (ret < 0)
+ return ret;
+ d = av_rescale_q(frame->pts, tb, AV_TIME_BASE_Q);
+ av_dlog(avctx, "sink_idx:%d time:%f\n", i, d);
+ av_frame_unref(frame);
+
+ if (d < min_pts) {
+ min_pts = d;
+ min_pts_sink_idx = i;
+ }
+ }
+ if (min_pts == DBL_MAX)
+ return AVERROR_EOF;
+
+ av_dlog(avctx, "min_pts_sink_idx:%i\n", min_pts_sink_idx);
+
+ av_buffersink_get_frame_flags(lavfi->sinks[min_pts_sink_idx], frame, 0);
+ stream_idx = lavfi->sink_stream_map[min_pts_sink_idx];
+
+ if (frame->width /* FIXME best way of testing a video */) {
+ size = avpicture_get_size(frame->format, frame->width, frame->height);
+ if ((ret = av_new_packet(pkt, size)) < 0)
+ return ret;
+
+ memcpy(pict.data, frame->data, 4*sizeof(frame->data[0]));
+ memcpy(pict.linesize, frame->linesize, 4*sizeof(frame->linesize[0]));
+
+ avpicture_layout(&pict, frame->format, frame->width, frame->height,
+ pkt->data, size);
+ } else if (av_frame_get_channels(frame) /* FIXME test audio */) {
+ size = frame->nb_samples * av_get_bytes_per_sample(frame->format) *
+ av_frame_get_channels(frame);
+ if ((ret = av_new_packet(pkt, size)) < 0)
+ return ret;
+ memcpy(pkt->data, frame->data[0], size);
+ }
+
+ frame_metadata = av_frame_get_metadata(frame);
+ if (frame_metadata) {
+ uint8_t *metadata;
+ AVDictionaryEntry *e = NULL;
+ AVBPrint meta_buf;
+
+ av_bprint_init(&meta_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ while ((e = av_dict_get(frame_metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ av_bprintf(&meta_buf, "%s", e->key);
+ av_bprint_chars(&meta_buf, '\0', 1);
+ av_bprintf(&meta_buf, "%s", e->value);
+ av_bprint_chars(&meta_buf, '\0', 1);
+ }
+ if (!av_bprint_is_complete(&meta_buf) ||
+ !(metadata = av_packet_new_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
+ meta_buf.len))) {
+ av_bprint_finalize(&meta_buf, NULL);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(metadata, meta_buf.str, meta_buf.len);
+ av_bprint_finalize(&meta_buf, NULL);
+ }
+
+ if ((ret = create_subcc_packet(avctx, frame, min_pts_sink_idx)) < 0) {
+ av_frame_unref(frame);
+ av_packet_unref(pkt);
+ return ret;
+ }
+
+ pkt->stream_index = stream_idx;
+ pkt->pts = frame->pts;
+ pkt->pos = av_frame_get_pkt_pos(frame);
+ pkt->size = size;
+ av_frame_unref(frame);
+ return size;
+}
+
+#define OFFSET(x) offsetof(LavfiContext, x)
+
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption options[] = {
+ { "graph", "set libavfilter graph", OFFSET(graph_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "graph_file","set libavfilter graph filename", OFFSET(graph_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC},
+ { "dumpgraph", "dump graph to stderr", OFFSET(dump_graph), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { NULL },
+};
+
+static const AVClass lavfi_class = {
+ .class_name = "lavfi indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_INPUT,
+};
+
+AVInputFormat ff_lavfi_demuxer = {
+ .name = "lavfi",
+ .long_name = NULL_IF_CONFIG_SMALL("Libavfilter virtual input device"),
+ .priv_data_size = sizeof(LavfiContext),
+ .read_header = lavfi_read_header,
+ .read_packet = lavfi_read_packet,
+ .read_close = lavfi_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &lavfi_class,
+};
diff --git a/libavdevice/libavdevice.v b/libavdevice/libavdevice.v
index 663af85ba8..de7278c193 100644
--- a/libavdevice/libavdevice.v
+++ b/libavdevice/libavdevice.v
@@ -1,4 +1,4 @@
LIBAVDEVICE_$MAJOR {
- global: avdevice_*;
+ global: avdevice_*; av_*;
local: *;
};
diff --git a/libavdevice/libcdio.c b/libavdevice/libcdio.c
index 06ddb4a784..9e9b0d86f3 100644
--- a/libavdevice/libcdio.c
+++ b/libavdevice/libcdio.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Anton Khirnov <anton@khirnov.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,7 +41,7 @@
#include "libavformat/internal.h"
typedef struct CDIOContext {
- AVClass *class;
+ const AVClass *class;
cdrom_drive_t *drive;
cdrom_paranoia_t *paranoia;
int32_t last_sector;
@@ -164,11 +164,13 @@ static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp,
#define OFFSET(x) offsetof(CDIOContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
- { "speed", "Drive reading speed.", OFFSET(speed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
- { "paranoia_mode", "Error recovery mode.", OFFSET(paranoia_mode), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, DEC, "paranoia_mode" },
- { "verify", "Verify data integrity in overlap area", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_VERIFY }, 0, 0, DEC, "paranoia_mode" },
- { "overlap", "Perform overlapped reads.", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_OVERLAP }, 0, 0, DEC, "paranoia_mode" },
- { "neverskip", "Do not skip failed reads.", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_NEVERSKIP }, 0, 0, DEC, "paranoia_mode" },
+ { "speed", "set drive reading speed", OFFSET(speed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
+ { "paranoia_mode", "set error recovery mode", OFFSET(paranoia_mode), AV_OPT_TYPE_FLAGS, { .i64 = PARANOIA_MODE_DISABLE }, INT_MIN, INT_MAX, DEC, "paranoia_mode" },
+ { "disable", "apply no fixups", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_DISABLE }, 0, 0, DEC, "paranoia_mode" },
+ { "verify", "verify data integrity in overlap area", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_VERIFY }, 0, 0, DEC, "paranoia_mode" },
+ { "overlap", "perform overlapped reads", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_OVERLAP }, 0, 0, DEC, "paranoia_mode" },
+ { "neverskip", "do not skip failed reads", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_NEVERSKIP }, 0, 0, DEC, "paranoia_mode" },
+ { "full", "apply all recovery modes", 0, AV_OPT_TYPE_CONST, { .i64 = PARANOIA_MODE_FULL }, 0, 0, DEC, "paranoia_mode" },
{ NULL },
};
@@ -177,6 +179,7 @@ static const AVClass libcdio_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
};
AVInputFormat ff_libcdio_demuxer = {
diff --git a/libavdevice/libdc1394.c b/libavdevice/libdc1394.c
index 20696f58fc..5f49c5ed02 100644
--- a/libavdevice/libdc1394.c
+++ b/libavdevice/libdc1394.c
@@ -3,20 +3,20 @@
* Copyright (c) 2004 Roman Shaposhnik
* Copyright (c) 2008 Alessandro Sappia
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -116,6 +116,7 @@ static const AVClass libdc1394_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
diff --git a/libavdevice/openal-dec.c b/libavdevice/openal-dec.c
new file mode 100644
index 0000000000..37d321a35d
--- /dev/null
+++ b/libavdevice/openal-dec.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2011 Jonathan Baldwin
+ *
+ * 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.
+ */
+
+/**
+ * @file
+ * OpenAL 1.1 capture device for libavdevice
+ **/
+
+#include <AL/al.h>
+#include <AL/alc.h>
+
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
+
+typedef struct {
+ AVClass *class;
+ /** OpenAL capture device context. **/
+ ALCdevice *device;
+ /** The number of channels in the captured audio. **/
+ int channels;
+ /** The sample rate (in Hz) of the captured audio. **/
+ int sample_rate;
+ /** The sample size (in bits) of the captured audio. **/
+ int sample_size;
+ /** The OpenAL sample format of the captured audio. **/
+ ALCenum sample_format;
+ /** The number of bytes between two consecutive samples of the same channel/component. **/
+ ALCint sample_step;
+ /** If true, print a list of capture devices on this system and exit. **/
+ int list_devices;
+} al_data;
+
+typedef struct {
+ ALCenum al_fmt;
+ enum AVCodecID codec_id;
+ int channels;
+} al_format_info;
+
+#define LOWEST_AL_FORMAT FFMIN(FFMIN(AL_FORMAT_MONO8,AL_FORMAT_MONO16),FFMIN(AL_FORMAT_STEREO8,AL_FORMAT_STEREO16))
+
+/**
+ * Get information about an AL_FORMAT value.
+ * @param al_fmt the AL_FORMAT value to find information about.
+ * @return A pointer to a structure containing information about the AL_FORMAT value.
+ */
+static inline al_format_info* get_al_format_info(ALCenum al_fmt)
+{
+ static al_format_info info_table[] = {
+ [AL_FORMAT_MONO8-LOWEST_AL_FORMAT] = {AL_FORMAT_MONO8, AV_CODEC_ID_PCM_U8, 1},
+ [AL_FORMAT_MONO16-LOWEST_AL_FORMAT] = {AL_FORMAT_MONO16, AV_NE (AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), 1},
+ [AL_FORMAT_STEREO8-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO8, AV_CODEC_ID_PCM_U8, 2},
+ [AL_FORMAT_STEREO16-LOWEST_AL_FORMAT] = {AL_FORMAT_STEREO16, AV_NE (AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE), 2},
+ };
+
+ return &info_table[al_fmt-LOWEST_AL_FORMAT];
+}
+
+/**
+ * Get the OpenAL error code, translated into an av/errno error code.
+ * @param device The ALC device to check for errors.
+ * @param error_msg_ret A pointer to a char* in which to return the error message, or NULL if desired.
+ * @return The error code, or 0 if there is no error.
+ */
+static inline int al_get_error(ALCdevice *device, const char** error_msg_ret)
+{
+ ALCenum error = alcGetError(device);
+ if (error_msg_ret)
+ *error_msg_ret = (const char*) alcGetString(device, error);
+ switch (error) {
+ case ALC_NO_ERROR:
+ return 0;
+ case ALC_INVALID_DEVICE:
+ return AVERROR(ENODEV);
+ break;
+ case ALC_INVALID_CONTEXT:
+ case ALC_INVALID_ENUM:
+ case ALC_INVALID_VALUE:
+ return AVERROR(EINVAL);
+ break;
+ case ALC_OUT_OF_MEMORY:
+ return AVERROR(ENOMEM);
+ break;
+ default:
+ return AVERROR(EIO);
+ }
+}
+
+/**
+ * Print out a list of OpenAL capture devices on this system.
+ */
+static inline void print_al_capture_devices(void *log_ctx)
+{
+ const char *devices;
+
+ if (!(devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER)))
+ return;
+
+ av_log(log_ctx, AV_LOG_INFO, "List of OpenAL capture devices on this system:\n");
+
+ for (; *devices != '\0'; devices += strlen(devices) + 1)
+ av_log(log_ctx, AV_LOG_INFO, " %s\n", devices);
+}
+
+static int read_header(AVFormatContext *ctx)
+{
+ al_data *ad = ctx->priv_data;
+ static const ALCenum sample_formats[2][2] = {
+ { AL_FORMAT_MONO8, AL_FORMAT_STEREO8 },
+ { AL_FORMAT_MONO16, AL_FORMAT_STEREO16 }
+ };
+ int error = 0;
+ const char *error_msg;
+ AVStream *st = NULL;
+ AVCodecContext *codec = NULL;
+
+ if (ad->list_devices) {
+ print_al_capture_devices(ctx);
+ return AVERROR_EXIT;
+ }
+
+ ad->sample_format = sample_formats[ad->sample_size/8-1][ad->channels-1];
+
+ /* Open device for capture */
+ ad->device =
+ alcCaptureOpenDevice(ctx->filename[0] ? ctx->filename : NULL,
+ ad->sample_rate,
+ ad->sample_format,
+ ad->sample_rate); /* Maximum 1 second of sample data to be read at once */
+
+ if (error = al_get_error(ad->device, &error_msg)) goto fail;
+
+ /* Create stream */
+ if (!(st = avformat_new_stream(ctx, NULL))) {
+ error = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ /* We work in microseconds */
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+
+ /* Set codec parameters */
+ codec = st->codec;
+ codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ codec->sample_rate = ad->sample_rate;
+ codec->channels = get_al_format_info(ad->sample_format)->channels;
+ codec->codec_id = get_al_format_info(ad->sample_format)->codec_id;
+
+ /* This is needed to read the audio data */
+ ad->sample_step = (av_get_bits_per_sample(get_al_format_info(ad->sample_format)->codec_id) *
+ get_al_format_info(ad->sample_format)->channels) / 8;
+
+ /* Finally, start the capture process */
+ alcCaptureStart(ad->device);
+
+ return 0;
+
+fail:
+ /* Handle failure */
+ if (ad->device)
+ alcCaptureCloseDevice(ad->device);
+ if (error_msg)
+ av_log(ctx, AV_LOG_ERROR, "Cannot open device: %s\n", error_msg);
+ return error;
+}
+
+static int read_packet(AVFormatContext* ctx, AVPacket *pkt)
+{
+ al_data *ad = ctx->priv_data;
+ int error=0;
+ const char *error_msg;
+ ALCint nb_samples;
+
+ /* Get number of samples available */
+ alcGetIntegerv(ad->device, ALC_CAPTURE_SAMPLES, (ALCsizei) sizeof(ALCint), &nb_samples);
+ if (error = al_get_error(ad->device, &error_msg)) goto fail;
+
+ /* Create a packet of appropriate size */
+ if ((error = av_new_packet(pkt, nb_samples*ad->sample_step)) < 0)
+ goto fail;
+ pkt->pts = av_gettime();
+
+ /* Fill the packet with the available samples */
+ alcCaptureSamples(ad->device, pkt->data, nb_samples);
+ if (error = al_get_error(ad->device, &error_msg)) goto fail;
+
+ return pkt->size;
+fail:
+ /* Handle failure */
+ if (pkt->data)
+ av_destruct_packet(pkt);
+ if (error_msg)
+ av_log(ctx, AV_LOG_ERROR, "Error: %s\n", error_msg);
+ return error;
+}
+
+static int read_close(AVFormatContext* ctx)
+{
+ al_data *ad = ctx->priv_data;
+
+ if (ad->device) {
+ alcCaptureStop(ad->device);
+ alcCaptureCloseDevice(ad->device);
+ }
+ return 0;
+}
+
+#define OFFSET(x) offsetof(al_data, x)
+
+static const AVOption options[] = {
+ {"channels", "set number of channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, AV_OPT_FLAG_DECODING_PARAM },
+ {"sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, 192000, AV_OPT_FLAG_DECODING_PARAM },
+ {"sample_size", "set sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64=16}, 8, 16, AV_OPT_FLAG_DECODING_PARAM },
+ {"list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ {"true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ {"false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ {NULL},
+};
+
+static const AVClass class = {
+ .class_name = "openal",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
+};
+
+AVInputFormat ff_openal_demuxer = {
+ .name = "openal",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenAL audio capture device"),
+ .priv_data_size = sizeof(al_data),
+ .read_probe = NULL,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_close = read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &class
+};
diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c
new file mode 100644
index 0000000000..434ae97a42
--- /dev/null
+++ b/libavdevice/opengl_enc.c
@@ -0,0 +1,1307 @@
+/*
+ * Copyright (c) 2014 Lukasz Marek
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+//TODO: support for more formats
+//TODO: support for more systems.
+//TODO: implement X11, Windows, Mac OS native default window. SDL 1.2 doesn't allow to render to custom thread.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stddef.h>
+
+#include "config.h"
+
+#if HAVE_WINDOWS_H
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+#if HAVE_OPENGL_GL3_H
+#include <OpenGL/gl3.h>
+#elif HAVE_ES2_GL_H
+#include <ES2/gl.h>
+#else
+#include <GL/gl.h>
+#include <GL/glext.h>
+#endif
+#if HAVE_GLXGETPROCADDRESS
+#include <GL/glx.h>
+#endif
+
+#if HAVE_SDL
+#include <SDL.h>
+#endif
+
+#include "libavutil/common.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavdevice/avdevice.h"
+#include "opengl_enc_shaders.h"
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+/* FF_GL_RED_COMPONENT is used for plannar pixel types.
+ * Only red component is sampled in shaders.
+ * On some platforms GL_RED is not available and GL_LUMINANCE have to be used,
+ * but since OpenGL 3.0 GL_LUMINANCE is deprecated.
+ * GL_RED produces RGBA = value, 0, 0, 1.
+ * GL_LUMINANCE produces RGBA = value, value, value, 1.
+ * Note: GL_INTENSITY may also be used which produce RGBA = value, value, value, value. */
+#if defined(GL_RED)
+#define FF_GL_RED_COMPONENT GL_RED
+#elif defined(GL_LUMINANCE)
+#define FF_GL_RED_COMPONENT GL_LUMINANCE
+#else
+#define FF_GL_RED_COMPONENT 0x1903; //GL_RED
+#endif
+
+/* Constants not defined for iOS */
+#define FF_GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define FF_GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define FF_GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define FF_GL_UNPACK_ROW_LENGTH 0x0CF2
+
+/* MinGW exposes only OpenGL 1.1 API */
+#define FF_GL_ARRAY_BUFFER 0x8892
+#define FF_GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define FF_GL_STATIC_DRAW 0x88E4
+#define FF_GL_FRAGMENT_SHADER 0x8B30
+#define FF_GL_VERTEX_SHADER 0x8B31
+#define FF_GL_COMPILE_STATUS 0x8B81
+#define FF_GL_LINK_STATUS 0x8B82
+#define FF_GL_INFO_LOG_LENGTH 0x8B84
+typedef void (APIENTRY *FF_PFNGLACTIVETEXTUREPROC) (GLenum texture);
+typedef void (APIENTRY *FF_PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
+typedef void (APIENTRY *FF_PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
+typedef void (APIENTRY *FF_PFNGLBUFFERDATAPROC) (GLenum target, ptrdiff_t size, const GLvoid *data, GLenum usage);
+typedef void (APIENTRY *FF_PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
+typedef GLint (APIENTRY *FF_PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const char *name);
+typedef void (APIENTRY *FF_PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
+typedef void (APIENTRY *FF_PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t pointer);
+typedef GLint (APIENTRY *FF_PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const char *name);
+typedef void (APIENTRY *FF_PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);
+typedef void (APIENTRY *FF_PFNGLUNIFORM1IPROC) (GLint location, GLint v0);
+typedef void (APIENTRY *FF_PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef GLuint (APIENTRY *FF_PFNGLCREATEPROGRAMPROC) (void);
+typedef void (APIENTRY *FF_PFNGLDELETEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRY *FF_PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRY *FF_PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRY *FF_PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
+typedef void (APIENTRY *FF_PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog);
+typedef void (APIENTRY *FF_PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef GLuint (APIENTRY *FF_PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRY *FF_PFNGLDELETESHADERPROC) (GLuint shader);
+typedef void (APIENTRY *FF_PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef void (APIENTRY *FF_PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const char* *string, const GLint *length);
+typedef void (APIENTRY *FF_PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRY *FF_PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog);
+
+typedef struct FFOpenGLFunctions {
+ FF_PFNGLACTIVETEXTUREPROC glActiveTexture; //Require GL ARB multitexture
+ FF_PFNGLGENBUFFERSPROC glGenBuffers; //Require GL_ARB_vertex_buffer_object
+ FF_PFNGLDELETEBUFFERSPROC glDeleteBuffers; //Require GL_ARB_vertex_buffer_object
+ FF_PFNGLBUFFERDATAPROC glBufferData; //Require GL_ARB_vertex_buffer_object
+ FF_PFNGLBINDBUFFERPROC glBindBuffer; //Require GL_ARB_vertex_buffer_object
+ FF_PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; //Require GL_ARB_vertex_shader
+ FF_PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; //Require GL_ARB_vertex_shader
+ FF_PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; //Require GL_ARB_vertex_shader
+ FF_PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; //Require GL_ARB_shader_objects
+ FF_PFNGLUNIFORM1FPROC glUniform1f; //Require GL_ARB_shader_objects
+ FF_PFNGLUNIFORM1IPROC glUniform1i; //Require GL_ARB_shader_objects
+ FF_PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; //Require GL_ARB_shader_objects
+ FF_PFNGLCREATEPROGRAMPROC glCreateProgram; //Require GL_ARB_shader_objects
+ FF_PFNGLDELETEPROGRAMPROC glDeleteProgram; //Require GL_ARB_shader_objects
+ FF_PFNGLUSEPROGRAMPROC glUseProgram; //Require GL_ARB_shader_objects
+ FF_PFNGLLINKPROGRAMPROC glLinkProgram; //Require GL_ARB_shader_objects
+ FF_PFNGLGETPROGRAMIVPROC glGetProgramiv; //Require GL_ARB_shader_objects
+ FF_PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; //Require GL_ARB_shader_objects
+ FF_PFNGLATTACHSHADERPROC glAttachShader; //Require GL_ARB_shader_objects
+ FF_PFNGLCREATESHADERPROC glCreateShader; //Require GL_ARB_shader_objects
+ FF_PFNGLDELETESHADERPROC glDeleteShader; //Require GL_ARB_shader_objects
+ FF_PFNGLCOMPILESHADERPROC glCompileShader; //Require GL_ARB_shader_objects
+ FF_PFNGLSHADERSOURCEPROC glShaderSource; //Require GL_ARB_shader_objects
+ FF_PFNGLGETSHADERIVPROC glGetShaderiv; //Require GL_ARB_shader_objects
+ FF_PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; //Require GL_ARB_shader_objects
+} FFOpenGLFunctions;
+
+#define OPENGL_ERROR_CHECK(ctx) \
+{\
+ GLenum err_code; \
+ if ((err_code = glGetError()) != GL_NO_ERROR) { \
+ av_log(ctx, AV_LOG_ERROR, "OpenGL error occurred in '%s', line %d: %d\n", __FUNCTION__, __LINE__, err_code); \
+ goto fail; \
+ } \
+}\
+
+typedef struct OpenGLVertexInfo
+{
+ float x, y, z; ///<Position
+ float s0, t0; ///<Texture coords
+} OpenGLVertexInfo;
+
+/* defines 2 triangles to display */
+static const GLushort g_index[6] =
+{
+ 0, 1, 2,
+ 0, 3, 2,
+};
+
+typedef struct OpenGLContext {
+ AVClass *class; ///< class for private options
+
+#if HAVE_SDL
+ SDL_Surface *surface;
+#endif
+ FFOpenGLFunctions glprocs;
+
+ int inited; ///< Set to 1 when write_header was successfully called.
+ uint8_t background[4]; ///< Background color
+ int no_window; ///< 0 for create default window
+ char *window_title; ///< Title of the window
+
+ /* OpenGL implementation limits */
+ GLint max_texture_size; ///< Maximum texture size
+ GLint max_viewport_width; ///< Maximum viewport size
+ GLint max_viewport_height; ///< Maximum viewport size
+ int non_pow_2_textures; ///< 1 when non power of 2 textures are supported
+ int unpack_subimage; ///< 1 when GL_EXT_unpack_subimage is available
+
+ /* Current OpenGL configuration */
+ GLuint program; ///< Shader program
+ GLuint vertex_shader; ///< Vertex shader
+ GLuint fragment_shader; ///< Fragment shader for current pix_pmt
+ GLuint texture_name[4]; ///< Textures' IDs
+ GLuint index_buffer; ///< Index buffer
+ GLuint vertex_buffer; ///< Vertex buffer
+ OpenGLVertexInfo vertex[4]; ///< VBO
+ GLint projection_matrix_location; ///< Uniforms' locations
+ GLint model_view_matrix_location;
+ GLint color_map_location;
+ GLint chroma_div_w_location;
+ GLint chroma_div_h_location;
+ GLint texture_location[4];
+ GLint position_attrib; ///< Attibutes' locations
+ GLint texture_coords_attrib;
+
+ GLfloat projection_matrix[16]; ///< Projection matrix
+ GLfloat model_view_matrix[16]; ///< Modev view matrix
+ GLfloat color_map[16]; ///< RGBA color map matrix
+ GLfloat chroma_div_w; ///< Chroma subsampling w ratio
+ GLfloat chroma_div_h; ///< Chroma subsampling h ratio
+
+ /* Stream information */
+ GLenum format;
+ GLenum type;
+ int width; ///< Stream width
+ int height; ///< Stream height
+ enum AVPixelFormat pix_fmt; ///< Stream pixel format
+ int picture_width; ///< Rendered width
+ int picture_height; ///< Rendered height
+ int window_width;
+ int window_height;
+} OpenGLContext;
+
+static const struct OpenGLFormatDesc {
+ enum AVPixelFormat fixel_format;
+ const char * const * fragment_shader;
+ GLenum format;
+ GLenum type;
+} opengl_format_desc[] = {
+ { AV_PIX_FMT_YUV420P, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUV444P, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUV422P, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUV410P, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUV411P, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUV440P, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUV420P16, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_YUV422P16, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_YUV444P16, &FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_YUVA420P, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUVA444P, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUVA422P, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_YUVA420P16, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_YUVA422P16, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_YUVA444P16, &FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_RGB24, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_BGR24, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_0RGB, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_RGB0, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_0BGR, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_BGR0, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_RGB565, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
+ { AV_PIX_FMT_BGR565, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 },
+ { AV_PIX_FMT_RGB555, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGBA, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV },
+ { AV_PIX_FMT_BGR555, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGBA, FF_GL_UNSIGNED_SHORT_1_5_5_5_REV },
+ { AV_PIX_FMT_RGB8, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, FF_GL_UNSIGNED_BYTE_3_3_2 },
+ { AV_PIX_FMT_BGR8, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, FF_GL_UNSIGNED_BYTE_2_3_3_REV },
+ { AV_PIX_FMT_RGB48, &FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET, GL_RGB, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_ARGB, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_RGBA, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_ABGR, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_BGRA, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_RGBA64, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_BGRA64, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET, GL_RGBA, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_GBRP, &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_GBRP16, &FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_GBRAP, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_GBRAP16, &FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_GRAY8, &FF_OPENGL_FRAGMENT_SHADER_GRAY, FF_GL_RED_COMPONENT, GL_UNSIGNED_BYTE },
+ { AV_PIX_FMT_GRAY16, &FF_OPENGL_FRAGMENT_SHADER_GRAY, FF_GL_RED_COMPONENT, GL_UNSIGNED_SHORT },
+ { AV_PIX_FMT_NONE, NULL }
+};
+
+static av_cold int opengl_prepare_vertex(AVFormatContext *s);
+static int opengl_draw(AVFormatContext *h, void *intput, int repaint, int is_pkt);
+static av_cold int opengl_init_context(OpenGLContext *opengl);
+
+static av_cold void opengl_deinit_context(OpenGLContext *opengl)
+{
+ glDeleteTextures(4, opengl->texture_name);
+ opengl->texture_name[0] = opengl->texture_name[1] =
+ opengl->texture_name[2] = opengl->texture_name[3] = 0;
+ if (opengl->glprocs.glUseProgram)
+ opengl->glprocs.glUseProgram(0);
+ if (opengl->glprocs.glDeleteProgram) {
+ opengl->glprocs.glDeleteProgram(opengl->program);
+ opengl->program = 0;
+ }
+ if (opengl->glprocs.glDeleteShader) {
+ opengl->glprocs.glDeleteShader(opengl->vertex_shader);
+ opengl->glprocs.glDeleteShader(opengl->fragment_shader);
+ opengl->vertex_shader = opengl->fragment_shader = 0;
+ }
+ if (opengl->glprocs.glBindBuffer) {
+ opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0);
+ opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ if (opengl->glprocs.glDeleteBuffers) {
+ opengl->glprocs.glDeleteBuffers(2, &opengl->index_buffer);
+ opengl->vertex_buffer = opengl->index_buffer = 0;
+ }
+}
+
+static int opengl_resize(AVFormatContext *h, int width, int height)
+{
+ int ret = 0;
+ OpenGLContext *opengl = h->priv_data;
+ opengl->window_width = width;
+ opengl->window_height = height;
+ if (opengl->inited) {
+ if (opengl->no_window &&
+ (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
+ goto end;
+ }
+ if ((ret = opengl_prepare_vertex(h)) < 0)
+ goto end;
+ ret = opengl_draw(h, NULL, 1, 0);
+ }
+ end:
+ return ret;
+}
+
+static int opengl_control_message(AVFormatContext *h, int type, void *data, size_t data_size)
+{
+ OpenGLContext *opengl = h->priv_data;
+ switch(type) {
+ case AV_APP_TO_DEV_WINDOW_SIZE:
+ if (data) {
+ AVDeviceRect *message = data;
+ return opengl_resize(h, message->width, message->height);
+ }
+ return AVERROR(EINVAL);
+ case AV_APP_TO_DEV_WINDOW_REPAINT:
+ return opengl_resize(h, opengl->window_width, opengl->window_height);
+ }
+ return AVERROR(ENOSYS);
+}
+
+#if HAVE_SDL
+static int opengl_sdl_recreate_window(OpenGLContext *opengl, int width, int height)
+{
+ opengl->surface = SDL_SetVideoMode(width, height,
+ 32, SDL_OPENGL | SDL_RESIZABLE);
+ if (!opengl->surface) {
+ av_log(opengl, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
+ return AVERROR_EXTERNAL;
+ }
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ return 0;
+}
+
+static int opengl_sdl_process_events(AVFormatContext *h)
+{
+ int ret;
+ OpenGLContext *opengl = h->priv_data;
+ SDL_Event event;
+ SDL_PumpEvents();
+ while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) > 0) {
+ switch (event.type) {
+ case SDL_QUIT:
+ return AVERROR(EIO);
+ case SDL_KEYDOWN:
+ switch (event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ case SDLK_q:
+ return AVERROR(EIO);
+ }
+ return 0;
+ case SDL_VIDEORESIZE: {
+ char buffer[100];
+ int reinit;
+ AVDeviceRect message;
+ /* clean up old context because SDL_SetVideoMode may lose its state. */
+ SDL_VideoDriverName(buffer, sizeof(buffer));
+ reinit = !av_strncasecmp(buffer, "quartz", sizeof(buffer));
+ if (reinit) {
+ opengl_deinit_context(opengl);
+ }
+ if ((ret = opengl_sdl_recreate_window(opengl, event.resize.w, event.resize.h)) < 0)
+ return ret;
+ if (reinit && (ret = opengl_init_context(opengl)) < 0)
+ return ret;
+ message.width = opengl->surface->w;
+ message.height = opengl->surface->h;
+ return opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect));
+ }
+ }
+ }
+ return 0;
+}
+
+static int av_cold opengl_sdl_create_window(AVFormatContext *h)
+{
+ int ret;
+ char buffer[100];
+ OpenGLContext *opengl = h->priv_data;
+ AVDeviceRect message;
+ if (SDL_Init(SDL_INIT_VIDEO)) {
+ av_log(opengl, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
+ return AVERROR_EXTERNAL;
+ }
+ if ((ret = opengl_sdl_recreate_window(opengl, opengl->window_width,
+ opengl->window_height)) < 0)
+ return ret;
+ av_log(opengl, AV_LOG_INFO, "SDL driver: '%s'.\n", SDL_VideoDriverName(buffer, sizeof(buffer)));
+ message.width = opengl->surface->w;
+ message.height = opengl->surface->h;
+ SDL_WM_SetCaption(opengl->window_title, NULL);
+ opengl_control_message(h, AV_APP_TO_DEV_WINDOW_SIZE, &message, sizeof(AVDeviceRect));
+ return 0;
+}
+
+static int av_cold opengl_sdl_load_procedures(OpenGLContext *opengl)
+{
+ FFOpenGLFunctions *procs = &opengl->glprocs;
+
+#define LOAD_OPENGL_FUN(name, type) \
+ procs->name = (type)SDL_GL_GetProcAddress(#name); \
+ if (!procs->name) { \
+ av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
+ return AVERROR(ENOSYS); \
+ }
+
+ LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC)
+ LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC)
+ LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC)
+ LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC)
+ LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC)
+ LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC)
+ LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC)
+ LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC)
+ LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC)
+ LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC)
+ LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC)
+ LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC)
+ LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC)
+ LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC)
+ LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC)
+ LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC)
+ LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC)
+ LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC)
+ LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC)
+ LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC)
+ LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC)
+ LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC)
+ LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC)
+ LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC)
+ LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC)
+
+ return 0;
+
+#undef LOAD_OPENGL_FUN
+}
+#endif /* HAVE_SDL */
+
+#if defined(__APPLE__)
+static int av_cold opengl_load_procedures(OpenGLContext *opengl)
+{
+ FFOpenGLFunctions *procs = &opengl->glprocs;
+
+#if HAVE_SDL
+ if (!opengl->no_window)
+ return opengl_sdl_load_procedures(opengl);
+#endif
+
+ procs->glActiveTexture = glActiveTexture;
+ procs->glGenBuffers = glGenBuffers;
+ procs->glDeleteBuffers = glDeleteBuffers;
+ procs->glBufferData = glBufferData;
+ procs->glBindBuffer = glBindBuffer;
+ procs->glGetAttribLocation = glGetAttribLocation;
+ procs->glGetUniformLocation = glGetUniformLocation;
+ procs->glUniform1f = glUniform1f;
+ procs->glUniform1i = glUniform1i;
+ procs->glUniformMatrix4fv = glUniformMatrix4fv;
+ procs->glCreateProgram = glCreateProgram;
+ procs->glDeleteProgram = glDeleteProgram;
+ procs->glUseProgram = glUseProgram;
+ procs->glLinkProgram = glLinkProgram;
+ procs->glGetProgramiv = glGetProgramiv;
+ procs->glGetProgramInfoLog = glGetProgramInfoLog;
+ procs->glAttachShader = glAttachShader;
+ procs->glCreateShader = glCreateShader;
+ procs->glDeleteShader = glDeleteShader;
+ procs->glCompileShader = glCompileShader;
+ procs->glShaderSource = glShaderSource;
+ procs->glGetShaderiv = glGetShaderiv;
+ procs->glGetShaderInfoLog = glGetShaderInfoLog;
+ procs->glEnableVertexAttribArray = glEnableVertexAttribArray;
+ procs->glVertexAttribPointer = (FF_PFNGLVERTEXATTRIBPOINTERPROC) glVertexAttribPointer;
+ return 0;
+}
+#else
+static int av_cold opengl_load_procedures(OpenGLContext *opengl)
+{
+ FFOpenGLFunctions *procs = &opengl->glprocs;
+
+#if HAVE_GLXGETPROCADDRESS
+#define SelectedGetProcAddress glXGetProcAddress
+#elif HAVE_WGLGETPROCADDRESS
+#define SelectedGetProcAddress wglGetProcAddress
+#endif
+
+#define LOAD_OPENGL_FUN(name, type) \
+ procs->name = (type)SelectedGetProcAddress(#name); \
+ if (!procs->name) { \
+ av_log(opengl, AV_LOG_ERROR, "Cannot load OpenGL function: '%s'\n", #name); \
+ return AVERROR(ENOSYS); \
+ }
+
+#if HAVE_SDL
+ if (!opengl->no_window)
+ return opengl_sdl_load_procedures(opengl);
+#endif
+
+ LOAD_OPENGL_FUN(glActiveTexture, FF_PFNGLACTIVETEXTUREPROC)
+ LOAD_OPENGL_FUN(glGenBuffers, FF_PFNGLGENBUFFERSPROC)
+ LOAD_OPENGL_FUN(glDeleteBuffers, FF_PFNGLDELETEBUFFERSPROC)
+ LOAD_OPENGL_FUN(glBufferData, FF_PFNGLBUFFERDATAPROC)
+ LOAD_OPENGL_FUN(glBindBuffer, FF_PFNGLBINDBUFFERPROC)
+ LOAD_OPENGL_FUN(glGetAttribLocation, FF_PFNGLGETATTRIBLOCATIONPROC)
+ LOAD_OPENGL_FUN(glGetUniformLocation, FF_PFNGLGETUNIFORMLOCATIONPROC)
+ LOAD_OPENGL_FUN(glUniform1f, FF_PFNGLUNIFORM1FPROC)
+ LOAD_OPENGL_FUN(glUniform1i, FF_PFNGLUNIFORM1IPROC)
+ LOAD_OPENGL_FUN(glUniformMatrix4fv, FF_PFNGLUNIFORMMATRIX4FVPROC)
+ LOAD_OPENGL_FUN(glCreateProgram, FF_PFNGLCREATEPROGRAMPROC)
+ LOAD_OPENGL_FUN(glDeleteProgram, FF_PFNGLDELETEPROGRAMPROC)
+ LOAD_OPENGL_FUN(glUseProgram, FF_PFNGLUSEPROGRAMPROC)
+ LOAD_OPENGL_FUN(glLinkProgram, FF_PFNGLLINKPROGRAMPROC)
+ LOAD_OPENGL_FUN(glGetProgramiv, FF_PFNGLGETPROGRAMIVPROC)
+ LOAD_OPENGL_FUN(glGetProgramInfoLog, FF_PFNGLGETPROGRAMINFOLOGPROC)
+ LOAD_OPENGL_FUN(glAttachShader, FF_PFNGLATTACHSHADERPROC)
+ LOAD_OPENGL_FUN(glCreateShader, FF_PFNGLCREATESHADERPROC)
+ LOAD_OPENGL_FUN(glDeleteShader, FF_PFNGLDELETESHADERPROC)
+ LOAD_OPENGL_FUN(glCompileShader, FF_PFNGLCOMPILESHADERPROC)
+ LOAD_OPENGL_FUN(glShaderSource, FF_PFNGLSHADERSOURCEPROC)
+ LOAD_OPENGL_FUN(glGetShaderiv, FF_PFNGLGETSHADERIVPROC)
+ LOAD_OPENGL_FUN(glGetShaderInfoLog, FF_PFNGLGETSHADERINFOLOGPROC)
+ LOAD_OPENGL_FUN(glEnableVertexAttribArray, FF_PFNGLENABLEVERTEXATTRIBARRAYPROC)
+ LOAD_OPENGL_FUN(glVertexAttribPointer, FF_PFNGLVERTEXATTRIBPOINTERPROC)
+
+ return 0;
+
+#undef SelectedGetProcAddress
+#undef LOAD_OPENGL_FUN
+}
+#endif
+
+static void opengl_make_identity(float matrix[16])
+{
+ memset(matrix, 0, 16 * sizeof(float));
+ matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1.0f;
+}
+
+static void opengl_make_ortho(float matrix[16], float left, float right,
+ float bottom, float top, float nearZ, float farZ)
+{
+ float ral = right + left;
+ float rsl = right - left;
+ float tab = top + bottom;
+ float tsb = top - bottom;
+ float fan = farZ + nearZ;
+ float fsn = farZ - nearZ;
+
+ memset(matrix, 0, 16 * sizeof(float));
+ matrix[0] = 2.0f / rsl;
+ matrix[5] = 2.0f / tsb;
+ matrix[10] = -2.0f / fsn;
+ matrix[12] = -ral / rsl;
+ matrix[13] = -tab / tsb;
+ matrix[14] = -fan / fsn;
+ matrix[15] = 1.0f;
+}
+
+static av_cold int opengl_read_limits(OpenGLContext *opengl)
+{
+ static const struct{
+ const char *extension;
+ int major;
+ int minor;
+ } required_extensions[] = {
+ { "GL_ARB_multitexture", 1, 3 },
+ { "GL_ARB_vertex_buffer_object", 1, 5 }, //GLX_ARB_vertex_buffer_object
+ { "GL_ARB_vertex_shader", 2, 0 },
+ { "GL_ARB_fragment_shader", 2, 0 },
+ { "GL_ARB_shader_objects", 2, 0 },
+ { NULL, 0, 0 }
+ };
+ int i, major, minor;
+ const char *extensions, *version;
+
+ version = glGetString(GL_VERSION);
+ extensions = glGetString(GL_EXTENSIONS);
+
+ av_log(opengl, AV_LOG_DEBUG, "OpenGL version: %s\n", version);
+ sscanf(version, "%d.%d", &major, &minor);
+
+ for (i = 0; required_extensions[i].extension; i++) {
+ if (major < required_extensions[i].major &&
+ (major == required_extensions[i].major && minor < required_extensions[i].minor) &&
+ !strstr(extensions, required_extensions[i].extension)) {
+ av_log(opengl, AV_LOG_ERROR, "Required extension %s is not supported.\n",
+ required_extensions[i].extension);
+ av_log(opengl, AV_LOG_DEBUG, "Supported extensions are: %s\n", extensions);
+ return AVERROR(ENOSYS);
+ }
+ }
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &opengl->max_texture_size);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &opengl->max_viewport_width);
+ opengl->non_pow_2_textures = major >= 2 || strstr(extensions, "GL_ARB_texture_non_power_of_two");
+#if defined(GL_ES_VERSION_2_0)
+ opengl->unpack_subimage = !!strstr(extensions, "GL_EXT_unpack_subimage");
+#else
+ opengl->unpack_subimage = 1;
+#endif
+
+ av_log(opengl, AV_LOG_DEBUG, "Non Power of 2 textures support: %s\n", opengl->non_pow_2_textures ? "Yes" : "No");
+ av_log(opengl, AV_LOG_DEBUG, "Unpack Subimage extension support: %s\n", opengl->unpack_subimage ? "Yes" : "No");
+ av_log(opengl, AV_LOG_DEBUG, "Max texture size: %dx%d\n", opengl->max_texture_size, opengl->max_texture_size);
+ av_log(opengl, AV_LOG_DEBUG, "Max viewport size: %dx%d\n",
+ opengl->max_viewport_width, opengl->max_viewport_height);
+
+ OPENGL_ERROR_CHECK(opengl);
+ return 0;
+ fail:
+ return AVERROR_EXTERNAL;
+}
+
+static const char* opengl_get_fragment_shader_code(enum AVPixelFormat format)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) {
+ if (opengl_format_desc[i].fixel_format == format)
+ return *opengl_format_desc[i].fragment_shader;
+ }
+ return NULL;
+}
+
+static int opengl_type_size(GLenum type)
+{
+ switch(type) {
+ case GL_UNSIGNED_SHORT:
+ case FF_GL_UNSIGNED_SHORT_1_5_5_5_REV:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ return 2;
+ case GL_UNSIGNED_BYTE:
+ case FF_GL_UNSIGNED_BYTE_3_3_2:
+ case FF_GL_UNSIGNED_BYTE_2_3_3_REV:
+ default:
+ break;
+ }
+ return 1;
+}
+
+static av_cold void opengl_get_texture_params(OpenGLContext *opengl)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(opengl_format_desc); i++) {
+ if (opengl_format_desc[i].fixel_format == opengl->pix_fmt) {
+ opengl->format = opengl_format_desc[i].format;
+ opengl->type = opengl_format_desc[i].type;
+ break;
+ }
+ }
+}
+
+static void opengl_compute_display_area(AVFormatContext *s)
+{
+ AVRational sar, dar; /* sample and display aspect ratios */
+ OpenGLContext *opengl = s->priv_data;
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+
+ /* compute overlay width and height from the codec context information */
+ sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
+ dar = av_mul_q(sar, (AVRational){ encctx->width, encctx->height });
+
+ /* we suppose the screen has a 1/1 sample aspect ratio */
+ /* fit in the window */
+ if (av_cmp_q(dar, (AVRational){ opengl->window_width, opengl->window_height }) > 0) {
+ /* fit in width */
+ opengl->picture_width = opengl->window_width;
+ opengl->picture_height = av_rescale(opengl->picture_width, dar.den, dar.num);
+ } else {
+ /* fit in height */
+ opengl->picture_height = opengl->window_height;
+ opengl->picture_width = av_rescale(opengl->picture_height, dar.num, dar.den);
+ }
+}
+
+static av_cold void opengl_get_texture_size(OpenGLContext *opengl, int in_width, int in_height,
+ int *out_width, int *out_height)
+{
+ if (opengl->non_pow_2_textures) {
+ *out_width = in_width;
+ *out_height = in_height;
+ } else {
+ int max = FFMIN(FFMAX(in_width, in_height), opengl->max_texture_size);
+ unsigned power_of_2 = 1;
+ while (power_of_2 < max)
+ power_of_2 *= 2;
+ *out_height = power_of_2;
+ *out_width = power_of_2;
+ av_log(opengl, AV_LOG_DEBUG, "Texture size calculated from %dx%d into %dx%d\n",
+ in_width, in_height, *out_width, *out_height);
+ }
+}
+
+static av_cold void opengl_fill_color_map(OpenGLContext *opengl)
+{
+ const AVPixFmtDescriptor *desc;
+ int shift;
+ enum AVPixelFormat pix_fmt = opengl->pix_fmt;
+
+ /* We need order of components, not exact position, some minor HACKs here */
+ if (pix_fmt == AV_PIX_FMT_RGB565 || pix_fmt == AV_PIX_FMT_BGR555 ||
+ pix_fmt == AV_PIX_FMT_BGR8 || pix_fmt == AV_PIX_FMT_RGB8)
+ pix_fmt = AV_PIX_FMT_RGB24;
+ else if (pix_fmt == AV_PIX_FMT_BGR565 || pix_fmt == AV_PIX_FMT_RGB555)
+ pix_fmt = AV_PIX_FMT_BGR24;
+
+ desc = av_pix_fmt_desc_get(pix_fmt);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
+ return;
+
+#define FILL_COMPONENT(i) { \
+ shift = desc->comp[i].depth_minus1 >> 3; \
+ opengl->color_map[(i << 2) + ((desc->comp[i].offset_plus1 - 1) >> shift)] = 1.0; \
+ }
+
+ memset(opengl->color_map, 0, sizeof(opengl->color_map));
+ FILL_COMPONENT(0);
+ FILL_COMPONENT(1);
+ FILL_COMPONENT(2);
+ if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
+ FILL_COMPONENT(3);
+
+#undef FILL_COMPONENT
+}
+
+static av_cold GLuint opengl_load_shader(OpenGLContext *opengl, GLenum type, const char *source)
+{
+ GLuint shader = opengl->glprocs.glCreateShader(type);
+ GLint result;
+ if (!shader) {
+ av_log(opengl, AV_LOG_ERROR, "glCreateShader() failed\n");
+ return 0;
+ }
+ opengl->glprocs.glShaderSource(shader, 1, &source, NULL);
+ opengl->glprocs.glCompileShader(shader);
+
+ opengl->glprocs.glGetShaderiv(shader, FF_GL_COMPILE_STATUS, &result);
+ if (!result) {
+ char *log;
+ opengl->glprocs.glGetShaderiv(shader, FF_GL_INFO_LOG_LENGTH, &result);
+ if (result) {
+ if ((log = av_malloc(result))) {
+ opengl->glprocs.glGetShaderInfoLog(shader, result, NULL, log);
+ av_log(opengl, AV_LOG_ERROR, "Compile error: %s\n", log);
+ av_free(log);
+ }
+ }
+ goto fail;
+ }
+ OPENGL_ERROR_CHECK(opengl);
+ return shader;
+ fail:
+ opengl->glprocs.glDeleteShader(shader);
+ return 0;
+}
+
+static av_cold int opengl_compile_shaders(OpenGLContext *opengl, enum AVPixelFormat pix_fmt)
+{
+ GLint result;
+ const char *fragment_shader_code = opengl_get_fragment_shader_code(pix_fmt);
+
+ if (!fragment_shader_code) {
+ av_log(opengl, AV_LOG_ERROR, "Provided pixel format '%s' is not supported\n",
+ av_get_pix_fmt_name(pix_fmt));
+ return AVERROR(EINVAL);
+ }
+
+ opengl->vertex_shader = opengl_load_shader(opengl, FF_GL_VERTEX_SHADER,
+ FF_OPENGL_VERTEX_SHADER);
+ if (!opengl->vertex_shader) {
+ av_log(opengl, AV_LOG_ERROR, "Vertex shader loading failed.\n");
+ goto fail;
+ }
+ opengl->fragment_shader = opengl_load_shader(opengl, FF_GL_FRAGMENT_SHADER,
+ fragment_shader_code);
+ if (!opengl->fragment_shader) {
+ av_log(opengl, AV_LOG_ERROR, "Fragment shader loading failed.\n");
+ goto fail;
+ }
+
+ opengl->program = opengl->glprocs.glCreateProgram();
+ if (!opengl->program)
+ goto fail;
+
+ opengl->glprocs.glAttachShader(opengl->program, opengl->vertex_shader);
+ opengl->glprocs.glAttachShader(opengl->program, opengl->fragment_shader);
+ opengl->glprocs.glLinkProgram(opengl->program);
+
+ opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_LINK_STATUS, &result);
+ if (!result) {
+ char *log;
+ opengl->glprocs.glGetProgramiv(opengl->program, FF_GL_INFO_LOG_LENGTH, &result);
+ if (result) {
+ log = av_malloc(result);
+ if (!log)
+ goto fail;
+ opengl->glprocs.glGetProgramInfoLog(opengl->program, result, NULL, log);
+ av_log(opengl, AV_LOG_ERROR, "Link error: %s\n", log);
+ av_free(log);
+ }
+ goto fail;
+ }
+
+ opengl->position_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_position");
+ opengl->texture_coords_attrib = opengl->glprocs.glGetAttribLocation(opengl->program, "a_textureCoords");
+ opengl->projection_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_projectionMatrix");
+ opengl->model_view_matrix_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_modelViewMatrix");
+ opengl->color_map_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_colorMap");
+ opengl->texture_location[0] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture0");
+ opengl->texture_location[1] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture1");
+ opengl->texture_location[2] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture2");
+ opengl->texture_location[3] = opengl->glprocs.glGetUniformLocation(opengl->program, "u_texture3");
+ opengl->chroma_div_w_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_w");
+ opengl->chroma_div_h_location = opengl->glprocs.glGetUniformLocation(opengl->program, "u_chroma_div_h");
+
+ OPENGL_ERROR_CHECK(opengl);
+ return 0;
+ fail:
+ opengl->glprocs.glDeleteShader(opengl->vertex_shader);
+ opengl->glprocs.glDeleteShader(opengl->fragment_shader);
+ opengl->glprocs.glDeleteProgram(opengl->program);
+ opengl->fragment_shader = opengl->vertex_shader = opengl->program = 0;
+ return AVERROR_EXTERNAL;
+}
+
+static av_cold int opengl_configure_texture(OpenGLContext *opengl, GLuint texture,
+ GLsizei width, GLsizei height)
+{
+ if (texture) {
+ int new_width, new_height;
+ opengl_get_texture_size(opengl, width, height, &new_width, &new_height);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, opengl->format, new_width, new_height, 0,
+ opengl->format, opengl->type, NULL);
+ OPENGL_ERROR_CHECK(NULL);
+ }
+ return 0;
+ fail:
+ return AVERROR_EXTERNAL;
+}
+
+static av_cold int opengl_prepare_vertex(AVFormatContext *s)
+{
+ OpenGLContext *opengl = s->priv_data;
+ int tex_w, tex_h;
+
+ if (opengl->window_width > opengl->max_viewport_width || opengl->window_height > opengl->max_viewport_height) {
+ opengl->window_width = FFMIN(opengl->window_width, opengl->max_viewport_width);
+ opengl->window_height = FFMIN(opengl->window_height, opengl->max_viewport_height);
+ av_log(opengl, AV_LOG_WARNING, "Too big viewport requested, limited to %dx%d", opengl->window_width, opengl->window_height);
+ }
+ glViewport(0, 0, opengl->window_width, opengl->window_height);
+ opengl_make_ortho(opengl->projection_matrix,
+ - (float)opengl->window_width / 2.0f, (float)opengl->window_width / 2.0f,
+ - (float)opengl->window_height / 2.0f, (float)opengl->window_height / 2.0f,
+ 1.0f, -1.0f);
+ opengl_make_identity(opengl->model_view_matrix);
+
+ opengl_compute_display_area(s);
+
+ opengl->vertex[0].z = opengl->vertex[1].z = opengl->vertex[2].z = opengl->vertex[3].z = 0.0f;
+ opengl->vertex[0].x = opengl->vertex[1].x = - (float)opengl->picture_width / 2.0f;
+ opengl->vertex[2].x = opengl->vertex[3].x = (float)opengl->picture_width / 2.0f;
+ opengl->vertex[1].y = opengl->vertex[2].y = - (float)opengl->picture_height / 2.0f;
+ opengl->vertex[0].y = opengl->vertex[3].y = (float)opengl->picture_height / 2.0f;
+
+ opengl_get_texture_size(opengl, opengl->width, opengl->height, &tex_w, &tex_h);
+
+ opengl->vertex[0].s0 = 0.0f;
+ opengl->vertex[0].t0 = 0.0f;
+ opengl->vertex[1].s0 = 0.0f;
+ opengl->vertex[1].t0 = (float)opengl->height / (float)tex_h;
+ opengl->vertex[2].s0 = (float)opengl->width / (float)tex_w;
+ opengl->vertex[2].t0 = (float)opengl->height / (float)tex_h;
+ opengl->vertex[3].s0 = (float)opengl->width / (float)tex_w;
+ opengl->vertex[3].t0 = 0.0f;
+
+ opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer);
+ opengl->glprocs.glBufferData(FF_GL_ARRAY_BUFFER, sizeof(opengl->vertex), opengl->vertex, FF_GL_STATIC_DRAW);
+ opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, 0);
+ OPENGL_ERROR_CHECK(opengl);
+ return 0;
+ fail:
+ return AVERROR_EXTERNAL;
+}
+
+static int opengl_prepare(OpenGLContext *opengl)
+{
+ int i;
+ opengl->glprocs.glUseProgram(opengl->program);
+ opengl->glprocs.glUniformMatrix4fv(opengl->projection_matrix_location, 1, GL_FALSE, opengl->projection_matrix);
+ opengl->glprocs.glUniformMatrix4fv(opengl->model_view_matrix_location, 1, GL_FALSE, opengl->model_view_matrix);
+ for (i = 0; i < 4; i++)
+ if (opengl->texture_location[i] != -1) {
+ opengl->glprocs.glActiveTexture(GL_TEXTURE0 + i);
+ glBindTexture(GL_TEXTURE_2D, opengl->texture_name[i]);
+ opengl->glprocs.glUniform1i(opengl->texture_location[i], i);
+ }
+ if (opengl->color_map_location != -1)
+ opengl->glprocs.glUniformMatrix4fv(opengl->color_map_location, 1, GL_FALSE, opengl->color_map);
+ if (opengl->chroma_div_h_location != -1)
+ opengl->glprocs.glUniform1f(opengl->chroma_div_h_location, opengl->chroma_div_h);
+ if (opengl->chroma_div_w_location != -1)
+ opengl->glprocs.glUniform1f(opengl->chroma_div_w_location, opengl->chroma_div_w);
+
+ OPENGL_ERROR_CHECK(opengl);
+ return 0;
+ fail:
+ return AVERROR_EXTERNAL;
+}
+
+static int opengl_create_window(AVFormatContext *h)
+{
+ OpenGLContext *opengl = h->priv_data;
+ int ret;
+
+ if (!opengl->no_window) {
+#if HAVE_SDL
+ if ((ret = opengl_sdl_create_window(h)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Cannot create default SDL window.\n");
+ return ret;
+ }
+#else
+ av_log(opengl, AV_LOG_ERROR, "FFmpeg is compiled without SDL. Cannot create default window.\n");
+ return AVERROR(ENOSYS);
+#endif
+ } else {
+ AVDeviceRect message;
+ message.x = message.y = 0;
+ message.width = opengl->window_width;
+ message.height = opengl->window_height;
+ if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_CREATE_WINDOW_BUFFER,
+ &message , sizeof(message))) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to create window buffer.\n");
+ return ret;
+ }
+ if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int opengl_release_window(AVFormatContext *h)
+{
+ int ret;
+ OpenGLContext *opengl = h->priv_data;
+ if (!opengl->no_window) {
+#if HAVE_SDL
+ SDL_Quit();
+#endif
+ } else if ((ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DESTROY_WINDOW_BUFFER, NULL , 0)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to release window buffer.\n");
+ return ret;
+ }
+ return 0;
+}
+
+static av_cold int opengl_write_trailer(AVFormatContext *h)
+{
+ OpenGLContext *opengl = h->priv_data;
+
+ if (opengl->no_window &&
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0) < 0)
+ av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
+
+ opengl_deinit_context(opengl);
+ opengl_release_window(h);
+
+ return 0;
+}
+
+static av_cold int opengl_init_context(OpenGLContext *opengl)
+{
+ int i, ret;
+ const AVPixFmtDescriptor *desc;
+
+ if ((ret = opengl_compile_shaders(opengl, opengl->pix_fmt)) < 0)
+ goto fail;
+
+ desc = av_pix_fmt_desc_get(opengl->pix_fmt);
+ av_assert0(desc->nb_components > 0 && desc->nb_components <= 4);
+ glGenTextures(desc->nb_components, opengl->texture_name);
+
+ opengl->glprocs.glGenBuffers(2, &opengl->index_buffer);
+ if (!opengl->index_buffer || !opengl->vertex_buffer) {
+ av_log(opengl, AV_LOG_ERROR, "Buffer generation failed.\n");
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ opengl_configure_texture(opengl, opengl->texture_name[0], opengl->width, opengl->height);
+ if (desc->nb_components > 1) {
+ int has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA;
+ int num_planes = desc->nb_components - (has_alpha ? 1 : 0);
+ if (opengl->non_pow_2_textures) {
+ opengl->chroma_div_w = 1.0f;
+ opengl->chroma_div_h = 1.0f;
+ } else {
+ opengl->chroma_div_w = 1 << desc->log2_chroma_w;
+ opengl->chroma_div_h = 1 << desc->log2_chroma_h;
+ }
+ for (i = 1; i < num_planes; i++)
+ if (opengl->non_pow_2_textures)
+ opengl_configure_texture(opengl, opengl->texture_name[i],
+ FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w),
+ FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h));
+ else
+ opengl_configure_texture(opengl, opengl->texture_name[i], opengl->width, opengl->height);
+ if (has_alpha)
+ opengl_configure_texture(opengl, opengl->texture_name[3], opengl->width, opengl->height);
+ }
+
+ opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer);
+ opengl->glprocs.glBufferData(FF_GL_ELEMENT_ARRAY_BUFFER, sizeof(g_index), g_index, FF_GL_STATIC_DRAW);
+ opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glClearColor((float)opengl->background[0] / 255.0f, (float)opengl->background[1] / 255.0f,
+ (float)opengl->background[2] / 255.0f, 1.0f);
+
+ ret = AVERROR_EXTERNAL;
+ OPENGL_ERROR_CHECK(opengl);
+
+ return 0;
+ fail:
+ return ret;
+}
+
+static av_cold int opengl_write_header(AVFormatContext *h)
+{
+ OpenGLContext *opengl = h->priv_data;
+ AVStream *st;
+ int ret;
+
+ if (h->nb_streams != 1 ||
+ h->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
+ h->streams[0]->codec->codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(opengl, AV_LOG_ERROR, "Only a single video stream is supported.\n");
+ return AVERROR(EINVAL);
+ }
+ st = h->streams[0];
+ opengl->width = st->codec->width;
+ opengl->height = st->codec->height;
+ opengl->pix_fmt = st->codec->pix_fmt;
+ if (!opengl->window_width)
+ opengl->window_width = opengl->width;
+ if (!opengl->window_height)
+ opengl->window_height = opengl->height;
+
+ if (!opengl->window_title && !opengl->no_window)
+ opengl->window_title = av_strdup(h->filename);
+
+ if ((ret = opengl_create_window(h)))
+ goto fail;
+
+ if ((ret = opengl_read_limits(opengl)) < 0)
+ goto fail;
+
+ if (opengl->width > opengl->max_texture_size || opengl->height > opengl->max_texture_size) {
+ av_log(opengl, AV_LOG_ERROR, "Too big picture %dx%d, max supported size is %dx%d\n",
+ opengl->width, opengl->height, opengl->max_texture_size, opengl->max_texture_size);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ if ((ret = opengl_load_procedures(opengl)) < 0)
+ goto fail;
+
+ opengl_fill_color_map(opengl);
+ opengl_get_texture_params(opengl);
+
+ if ((ret = opengl_init_context(opengl)) < 0)
+ goto fail;
+
+ if ((ret = opengl_prepare_vertex(h)) < 0)
+ goto fail;
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+#if HAVE_SDL
+ if (!opengl->no_window)
+ SDL_GL_SwapBuffers();
+#endif
+ if (opengl->no_window &&
+ (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
+ goto fail;
+ }
+
+ ret = AVERROR_EXTERNAL;
+ OPENGL_ERROR_CHECK(opengl);
+
+ opengl->inited = 1;
+ return 0;
+
+ fail:
+ opengl_write_trailer(h);
+ return ret;
+}
+
+static uint8_t* opengl_get_plane_pointer(OpenGLContext *opengl, AVPacket *pkt, int comp_index,
+ const AVPixFmtDescriptor *desc)
+{
+ uint8_t *data = pkt->data;
+ int wordsize = opengl_type_size(opengl->type);
+ int width_chroma = FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w);
+ int height_chroma = FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h);
+ int plane = desc->comp[comp_index].plane;
+
+ switch(plane) {
+ case 0:
+ break;
+ case 1:
+ data += opengl->width * opengl->height * wordsize;
+ break;
+ case 2:
+ data += opengl->width * opengl->height * wordsize;
+ data += width_chroma * height_chroma * wordsize;
+ break;
+ case 3:
+ data += opengl->width * opengl->height * wordsize;
+ data += 2 * width_chroma * height_chroma * wordsize;
+ break;
+ default:
+ return NULL;
+ }
+ return data;
+}
+
+#define LOAD_TEXTURE_DATA(comp_index, sub) \
+{ \
+ int width = sub ? FF_CEIL_RSHIFT(opengl->width, desc->log2_chroma_w) : opengl->width; \
+ int height = sub ? FF_CEIL_RSHIFT(opengl->height, desc->log2_chroma_h): opengl->height; \
+ uint8_t *data; \
+ int plane = desc->comp[comp_index].plane; \
+ \
+ glBindTexture(GL_TEXTURE_2D, opengl->texture_name[comp_index]); \
+ if (!is_pkt) { \
+ GLint length = ((AVFrame *)input)->linesize[plane]; \
+ int bytes_per_pixel = opengl_type_size(opengl->type); \
+ if (!(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) \
+ bytes_per_pixel *= desc->nb_components; \
+ data = ((AVFrame *)input)->data[plane]; \
+ if (!(length % bytes_per_pixel) && \
+ (opengl->unpack_subimage || ((length / bytes_per_pixel) == width))) { \
+ length /= bytes_per_pixel; \
+ if (length != width) \
+ glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, length); \
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
+ opengl->format, opengl->type, data); \
+ if (length != width) \
+ glPixelStorei(FF_GL_UNPACK_ROW_LENGTH, 0); \
+ } else { \
+ int h; \
+ for (h = 0; h < height; h++) { \
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, h, width, 1, \
+ opengl->format, opengl->type, data); \
+ data += length; \
+ } \
+ } \
+ } else { \
+ data = opengl_get_plane_pointer(opengl, input, comp_index, desc); \
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, \
+ opengl->format, opengl->type, data); \
+ } \
+}
+
+static int opengl_draw(AVFormatContext *h, void *input, int repaint, int is_pkt)
+{
+ OpenGLContext *opengl = h->priv_data;
+ enum AVPixelFormat pix_fmt = h->streams[0]->codec->pix_fmt;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ int ret;
+
+#if HAVE_SDL
+ if (!opengl->no_window && (ret = opengl_sdl_process_events(h)) < 0)
+ goto fail;
+#endif
+ if (opengl->no_window &&
+ (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_PREPARE_WINDOW_BUFFER, NULL , 0)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to prepare window buffer.\n");
+ goto fail;
+ }
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (!repaint) {
+ if (is_pkt)
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ LOAD_TEXTURE_DATA(0, 0)
+ if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
+ LOAD_TEXTURE_DATA(1, 1)
+ LOAD_TEXTURE_DATA(2, 1)
+ if (desc->flags & AV_PIX_FMT_FLAG_ALPHA)
+ LOAD_TEXTURE_DATA(3, 0)
+ }
+ }
+ ret = AVERROR_EXTERNAL;
+ OPENGL_ERROR_CHECK(opengl);
+
+ if ((ret = opengl_prepare(opengl)) < 0)
+ goto fail;
+
+ opengl->glprocs.glBindBuffer(FF_GL_ARRAY_BUFFER, opengl->vertex_buffer);
+ opengl->glprocs.glBindBuffer(FF_GL_ELEMENT_ARRAY_BUFFER, opengl->index_buffer);
+ opengl->glprocs.glVertexAttribPointer(opengl->position_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 0);
+ opengl->glprocs.glEnableVertexAttribArray(opengl->position_attrib);
+ opengl->glprocs.glVertexAttribPointer(opengl->texture_coords_attrib, 2, GL_FLOAT, GL_FALSE, sizeof(OpenGLVertexInfo), 12);
+ opengl->glprocs.glEnableVertexAttribArray(opengl->texture_coords_attrib);
+
+ glDrawElements(GL_TRIANGLES, FF_ARRAY_ELEMS(g_index), GL_UNSIGNED_SHORT, 0);
+
+ ret = AVERROR_EXTERNAL;
+ OPENGL_ERROR_CHECK(opengl);
+
+#if HAVE_SDL
+ if (!opengl->no_window)
+ SDL_GL_SwapBuffers();
+#endif
+ if (opengl->no_window &&
+ (ret = avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_DISPLAY_WINDOW_BUFFER, NULL , 0)) < 0) {
+ av_log(opengl, AV_LOG_ERROR, "Application failed to display window buffer.\n");
+ goto fail;
+ }
+
+ return 0;
+ fail:
+ return ret;
+}
+
+static int opengl_write_packet(AVFormatContext *h, AVPacket *pkt)
+{
+ return opengl_draw(h, pkt, 0, 1);
+}
+
+static int opengl_write_frame(AVFormatContext *h, int stream_index,
+ AVFrame **frame, unsigned flags)
+{
+ if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
+ return 0;
+ return opengl_draw(h, *frame, 0, 0);
+}
+
+#define OFFSET(x) offsetof(OpenGLContext, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "background", "set background color", OFFSET(background), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, ENC },
+ { "no_window", "disable default window", OFFSET(no_window), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, ENC },
+ { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, ENC },
+ { "window_size", "set window size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, ENC },
+ { NULL }
+};
+
+static const AVClass opengl_class = {
+ .class_name = "opengl outdev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_opengl_muxer = {
+ .name = "opengl",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenGL output"),
+ .priv_data_size = sizeof(OpenGLContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = opengl_write_header,
+ .write_packet = opengl_write_packet,
+ .write_uncoded_frame = opengl_write_frame,
+ .write_trailer = opengl_write_trailer,
+ .control_message = opengl_control_message,
+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
+ .priv_class = &opengl_class,
+};
diff --git a/libavdevice/opengl_enc_shaders.h b/libavdevice/opengl_enc_shaders.h
new file mode 100644
index 0000000000..ed8b3d3041
--- /dev/null
+++ b/libavdevice/opengl_enc_shaders.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2014 Lukasz Marek
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVDEVICE_OPENGL_SHADERS_H
+#define AVDEVICE_OPENGL_SHADERS_H
+
+#include "libavutil/pixfmt.h"
+
+static const char * const FF_OPENGL_VERTEX_SHADER =
+ "uniform mat4 u_projectionMatrix;"
+ "uniform mat4 u_modelViewMatrix;"
+
+ "attribute vec4 a_position;"
+ "attribute vec2 a_textureCoords;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "gl_Position = u_projectionMatrix * (a_position * u_modelViewMatrix);"
+ "texture_coordinate = a_textureCoords;"
+ "}";
+
+/**
+ * Fragment shader for packet RGBA formats.
+ */
+static const char * const FF_OPENGL_FRAGMENT_SHADER_RGBA_PACKET =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "uniform mat4 u_colorMap;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "gl_FragColor = texture2D(u_texture0, texture_coordinate) * u_colorMap;"
+ "}";
+
+/**
+ * Fragment shader for packet RGB formats.
+ */
+static const char * const FF_OPENGL_FRAGMENT_SHADER_RGB_PACKET =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "uniform mat4 u_colorMap;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "gl_FragColor = vec4((texture2D(u_texture0, texture_coordinate) * u_colorMap).rgb, 1.0);"
+ "}";
+
+/**
+ * Fragment shader for planar RGBA formats.
+ */
+static const char * const FF_OPENGL_FRAGMENT_SHADER_RGBA_PLANAR =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "uniform sampler2D u_texture1;"
+ "uniform sampler2D u_texture2;"
+ "uniform sampler2D u_texture3;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r,"
+ "texture2D(u_texture1, texture_coordinate).r,"
+ "texture2D(u_texture2, texture_coordinate).r,"
+ "texture2D(u_texture3, texture_coordinate).r);"
+ "}";
+
+/**
+ * Fragment shader for planar RGB formats.
+ */
+static const char * const FF_OPENGL_FRAGMENT_SHADER_RGB_PLANAR =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "uniform sampler2D u_texture1;"
+ "uniform sampler2D u_texture2;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "gl_FragColor = vec4(texture2D(u_texture0, texture_coordinate).r,"
+ "texture2D(u_texture1, texture_coordinate).r,"
+ "texture2D(u_texture2, texture_coordinate).r,"
+ "1.0);"
+ "}";
+
+/**
+ * Fragment shader for planar YUV formats.
+ */
+static const char * const FF_OPENGL_FRAGMENT_SHADER_YUV_PLANAR =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "uniform sampler2D u_texture1;"
+ "uniform sampler2D u_texture2;"
+ "uniform float u_chroma_div_w;"
+ "uniform float u_chroma_div_h;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "vec3 yuv;"
+
+ "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;"
+ "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
+ "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
+
+ "gl_FragColor = clamp(vec4(mat3(1.1643, 1.16430, 1.1643,"
+ "0.0, -0.39173, 2.0170,"
+ "1.5958, -0.81290, 0.0) * yuv, 1.0), 0.0, 1.0);"
+
+ "}";
+
+/**
+ * Fragment shader for planar YUVA formats.
+ */
+static const char * const FF_OPENGL_FRAGMENT_SHADER_YUVA_PLANAR =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "uniform sampler2D u_texture1;"
+ "uniform sampler2D u_texture2;"
+ "uniform sampler2D u_texture3;"
+ "uniform float u_chroma_div_w;"
+ "uniform float u_chroma_div_h;"
+
+ "varying vec2 texture_coordinate;"
+
+ "void main()"
+ "{"
+ "vec3 yuv;"
+
+ "yuv.r = texture2D(u_texture0, texture_coordinate).r - 0.0625;"
+ "yuv.g = texture2D(u_texture1, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
+ "yuv.b = texture2D(u_texture2, vec2(texture_coordinate.x / u_chroma_div_w, texture_coordinate.y / u_chroma_div_h)).r - 0.5;"
+
+ "gl_FragColor = clamp(vec4(mat3(1.1643, 1.16430, 1.1643,"
+ "0.0, -0.39173, 2.0170,"
+ "1.5958, -0.81290, 0.0) * yuv, texture2D(u_texture3, texture_coordinate).r), 0.0, 1.0);"
+ "}";
+
+static const char * const FF_OPENGL_FRAGMENT_SHADER_GRAY =
+#if defined(GL_ES_VERSION_2_0)
+ "precision mediump float;"
+#endif
+ "uniform sampler2D u_texture0;"
+ "varying vec2 texture_coordinate;"
+ "void main()"
+ "{"
+ "float c = texture2D(u_texture0, texture_coordinate).r;"
+ "gl_FragColor = vec4(c, c, c, 1.0);"
+ "}";
+
+#endif /* AVDEVICE_OPENGL_SHADERS_H */
diff --git a/libavdevice/oss.c b/libavdevice/oss.c
index eb8d454422..d74112825b 100644
--- a/libavdevice/oss.c
+++ b/libavdevice/oss.c
@@ -2,20 +2,20 @@
* Linux audio play and grab interface
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,15 +29,16 @@
#include <sys/soundcard.h>
#endif
+#if HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include "libavutil/log.h"
#include "libavcodec/avcodec.h"
-
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "oss.h"
@@ -48,14 +49,13 @@ int ff_oss_audio_open(AVFormatContext *s1, int is_output,
int audio_fd;
int tmp, err;
char *flip = getenv("AUDIO_FLIP_LEFT");
- char errbuff[128];
if (is_output)
audio_fd = avpriv_open(audio_device, O_WRONLY);
else
audio_fd = avpriv_open(audio_device, O_RDONLY);
if (audio_fd < 0) {
- av_log(s1, AV_LOG_ERROR, "%s: %s\n", audio_device, strerror(errno));
+ av_log(s1, AV_LOG_ERROR, "%s: %s\n", audio_device, av_err2str(AVERROR(errno)));
return AVERROR(EIO);
}
@@ -64,15 +64,17 @@ int ff_oss_audio_open(AVFormatContext *s1, int is_output,
}
/* non blocking mode */
- if (!is_output)
- fcntl(audio_fd, F_SETFL, O_NONBLOCK);
+ if (!is_output) {
+ if (fcntl(audio_fd, F_SETFL, O_NONBLOCK) < 0) {
+ av_log(s1, AV_LOG_WARNING, "%s: Could not enable non block mode (%s)\n", audio_device, av_err2str(AVERROR(errno)));
+ }
+ }
s->frame_size = OSS_AUDIO_BLOCK_SIZE;
#define CHECK_IOCTL_ERROR(event) \
if (err < 0) { \
- av_strerror(AVERROR(errno), errbuff, sizeof(errbuff)); \
- av_log(s1, AV_LOG_ERROR, #event ": %s\n", errbuff); \
+ av_log(s1, AV_LOG_ERROR, #event ": %s\n", av_err2str(AVERROR(errno)));\
goto fail; \
}
@@ -80,7 +82,10 @@ int ff_oss_audio_open(AVFormatContext *s1, int is_output,
* We don't CHECK_IOCTL_ERROR here because even if failed OSS still may be
* usable. If OSS is not usable the SNDCTL_DSP_SETFMTS later is going to
* fail anyway. */
- (void) ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp);
+ err = ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &tmp);
+ if (err < 0) {
+ av_log(s1, AV_LOG_WARNING, "SNDCTL_DSP_GETFMTS: %s\n", av_err2str(AVERROR(errno)));
+ }
#if HAVE_BIGENDIAN
if (tmp & AFMT_S16_BE) {
diff --git a/libavdevice/oss.h b/libavdevice/oss.h
index 0fbe14b3ec..1f3f5e4e83 100644
--- a/libavdevice/oss.h
+++ b/libavdevice/oss.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavdevice/oss_dec.c b/libavdevice/oss_dec.c
index 3f786cc356..156d6ae9a6 100644
--- a/libavdevice/oss_dec.c
+++ b/libavdevice/oss_dec.c
@@ -2,20 +2,20 @@
* Linux audio play interface
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,7 +29,9 @@
#include <sys/soundcard.h>
#endif
+#if HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <fcntl.h>
#include <sys/ioctl.h>
@@ -39,7 +41,7 @@
#include "libavcodec/avcodec.h"
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavformat/internal.h"
#include "oss.h"
@@ -132,6 +134,7 @@ static const AVClass oss_demuxer_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
};
AVInputFormat ff_oss_demuxer = {
diff --git a/libavdevice/oss_enc.c b/libavdevice/oss_enc.c
index 2f075589a9..3781eb54e5 100644
--- a/libavdevice/oss_enc.c
+++ b/libavdevice/oss_enc.c
@@ -2,20 +2,20 @@
* Linux audio grab interface
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,9 @@
#include <sys/soundcard.h>
#endif
+#if HAVE_UNISTD_H
#include <unistd.h>
+#endif
#include <fcntl.h>
#include <sys/ioctl.h>
@@ -35,7 +37,7 @@
#include "libavcodec/avcodec.h"
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavformat/internal.h"
#include "oss.h"
@@ -92,6 +94,13 @@ static int audio_write_trailer(AVFormatContext *s1)
return 0;
}
+static const AVClass oss_muxer_class = {
+ .class_name = "OSS muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+};
+
AVOutputFormat ff_oss_muxer = {
.name = "oss",
.long_name = NULL_IF_CONFIG_SMALL("OSS (Open Sound System) playback"),
@@ -105,4 +114,5 @@ AVOutputFormat ff_oss_muxer = {
.write_packet = audio_write_packet,
.write_trailer = audio_write_trailer,
.flags = AVFMT_NOFILE,
+ .priv_class = &oss_muxer_class,
};
diff --git a/libavdevice/pulse.c b/libavdevice/pulse.c
deleted file mode 100644
index aaff4478d4..0000000000
--- a/libavdevice/pulse.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Pulseaudio input
- * Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * PulseAudio input using the simple API.
- * @author Luca Barbato <lu_zero@gentoo.org>
- */
-
-#include <pulse/simple.h>
-#include <pulse/rtclock.h>
-#include <pulse/error.h>
-
-#include "libavutil/internal.h"
-#include "libavutil/opt.h"
-#include "libavutil/time.h"
-
-#include "libavformat/avformat.h"
-#include "libavformat/internal.h"
-
-#define DEFAULT_CODEC_ID AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE)
-
-typedef struct PulseData {
- AVClass *class;
- char *server;
- char *name;
- char *stream_name;
- int sample_rate;
- int channels;
- int frame_size;
- int fragment_size;
- pa_simple *s;
- int64_t pts;
- int64_t frame_duration;
- int wallclock;
-} PulseData;
-
-static pa_sample_format_t codec_id_to_pulse_format(int codec_id) {
- switch (codec_id) {
- case AV_CODEC_ID_PCM_U8: return PA_SAMPLE_U8;
- case AV_CODEC_ID_PCM_ALAW: return PA_SAMPLE_ALAW;
- case AV_CODEC_ID_PCM_MULAW: return PA_SAMPLE_ULAW;
- case AV_CODEC_ID_PCM_S16LE: return PA_SAMPLE_S16LE;
- case AV_CODEC_ID_PCM_S16BE: return PA_SAMPLE_S16BE;
- case AV_CODEC_ID_PCM_F32LE: return PA_SAMPLE_FLOAT32LE;
- case AV_CODEC_ID_PCM_F32BE: return PA_SAMPLE_FLOAT32BE;
- case AV_CODEC_ID_PCM_S32LE: return PA_SAMPLE_S32LE;
- case AV_CODEC_ID_PCM_S32BE: return PA_SAMPLE_S32BE;
- case AV_CODEC_ID_PCM_S24LE: return PA_SAMPLE_S24LE;
- case AV_CODEC_ID_PCM_S24BE: return PA_SAMPLE_S24BE;
- default: return PA_SAMPLE_INVALID;
- }
-}
-
-static av_cold int pulse_read_header(AVFormatContext *s)
-{
- PulseData *pd = s->priv_data;
- AVStream *st;
- char *device = NULL;
- int ret;
- enum AVCodecID codec_id =
- s->audio_codec_id == AV_CODEC_ID_NONE ? DEFAULT_CODEC_ID : s->audio_codec_id;
- const pa_sample_spec ss = { codec_id_to_pulse_format(codec_id),
- pd->sample_rate,
- pd->channels };
-
- pa_buffer_attr attr = { -1 };
-
- st = avformat_new_stream(s, NULL);
-
- if (!st) {
- av_log(s, AV_LOG_ERROR, "Cannot add stream\n");
- return AVERROR(ENOMEM);
- }
-
- attr.fragsize = pd->fragment_size;
-
- if (strcmp(s->filename, "default"))
- device = s->filename;
-
- pd->s = pa_simple_new(pd->server, pd->name,
- PA_STREAM_RECORD,
- device, pd->stream_name, &ss,
- NULL, &attr, &ret);
-
- if (!pd->s) {
- av_log(s, AV_LOG_ERROR, "pa_simple_new failed: %s\n",
- pa_strerror(ret));
- return AVERROR(EIO);
- }
- /* take real parameters */
- st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- st->codec->codec_id = codec_id;
- st->codec->sample_rate = pd->sample_rate;
- st->codec->channels = pd->channels;
- avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
-
- pd->pts = AV_NOPTS_VALUE;
- pd->frame_duration = (pd->frame_size * 1000000LL * 8) /
- (pd->sample_rate * pd->channels * av_get_bits_per_sample(codec_id));
-
- return 0;
-}
-
-static int pulse_read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- PulseData *pd = s->priv_data;
- int res;
- pa_usec_t latency;
-
- if (av_new_packet(pkt, pd->frame_size) < 0) {
- return AVERROR(ENOMEM);
- }
-
- if ((pa_simple_read(pd->s, pkt->data, pkt->size, &res)) < 0) {
- av_log(s, AV_LOG_ERROR, "pa_simple_read failed: %s\n",
- pa_strerror(res));
- av_free_packet(pkt);
- return AVERROR(EIO);
- }
-
- if ((latency = pa_simple_get_latency(pd->s, &res)) == (pa_usec_t) -1) {
- av_log(s, AV_LOG_ERROR, "pa_simple_get_latency() failed: %s\n",
- pa_strerror(res));
- return AVERROR(EIO);
- }
-
- if (pd->pts == AV_NOPTS_VALUE) {
- pd->pts = -latency;
- if (pd->wallclock)
- pd->pts += av_gettime();
- }
-
- pkt->pts = pd->pts;
-
- pd->pts += pd->frame_duration;
-
- return 0;
-}
-
-static av_cold int pulse_close(AVFormatContext *s)
-{
- PulseData *pd = s->priv_data;
- pa_simple_free(pd->s);
- return 0;
-}
-
-#define OFFSET(a) offsetof(PulseData, a)
-#define D AV_OPT_FLAG_DECODING_PARAM
-
-static const AVOption options[] = {
- { "server", "pulse server name", OFFSET(server), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
- { "name", "application name", OFFSET(name), AV_OPT_TYPE_STRING, {.str = "libav"}, 0, 0, D },
- { "stream_name", "stream description", OFFSET(stream_name), AV_OPT_TYPE_STRING, {.str = "record"}, 0, 0, D },
- { "sample_rate", "sample rate in Hz", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, D },
- { "channels", "number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, D },
- { "frame_size", "number of bytes per frame", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, D },
- { "fragment_size", "buffering size, affects latency and cpu usage", OFFSET(fragment_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D },
- { "wallclock", "set the initial pts using the current time", OFFSET(wallclock), AV_OPT_TYPE_INT, {.i64 = 1}, -1, 1, D },
- { NULL },
-};
-
-static const AVClass pulse_demuxer_class = {
- .class_name = "Pulse demuxer",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-AVInputFormat ff_pulse_demuxer = {
- .name = "pulse",
- .long_name = NULL_IF_CONFIG_SMALL("Pulse audio input"),
- .priv_data_size = sizeof(PulseData),
- .read_header = pulse_read_header,
- .read_packet = pulse_read_packet,
- .read_close = pulse_close,
- .flags = AVFMT_NOFILE,
- .priv_class = &pulse_demuxer_class,
-};
diff --git a/libavdevice/pulse_audio_common.c b/libavdevice/pulse_audio_common.c
new file mode 100644
index 0000000000..4046641479
--- /dev/null
+++ b/libavdevice/pulse_audio_common.c
@@ -0,0 +1,249 @@
+/*
+ * Pulseaudio common
+ * Copyright (c) 2014 Lukasz Marek
+ * Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "pulse_audio_common.h"
+#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
+#include "libavutil/mem.h"
+#include "libavutil/avassert.h"
+
+pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id)
+{
+ switch (codec_id) {
+ case AV_CODEC_ID_PCM_U8: return PA_SAMPLE_U8;
+ case AV_CODEC_ID_PCM_ALAW: return PA_SAMPLE_ALAW;
+ case AV_CODEC_ID_PCM_MULAW: return PA_SAMPLE_ULAW;
+ case AV_CODEC_ID_PCM_S16LE: return PA_SAMPLE_S16LE;
+ case AV_CODEC_ID_PCM_S16BE: return PA_SAMPLE_S16BE;
+ case AV_CODEC_ID_PCM_F32LE: return PA_SAMPLE_FLOAT32LE;
+ case AV_CODEC_ID_PCM_F32BE: return PA_SAMPLE_FLOAT32BE;
+ case AV_CODEC_ID_PCM_S32LE: return PA_SAMPLE_S32LE;
+ case AV_CODEC_ID_PCM_S32BE: return PA_SAMPLE_S32BE;
+ case AV_CODEC_ID_PCM_S24LE: return PA_SAMPLE_S24LE;
+ case AV_CODEC_ID_PCM_S24BE: return PA_SAMPLE_S24BE;
+ default: return PA_SAMPLE_INVALID;
+ }
+}
+
+enum PulseAudioContextState {
+ PULSE_CONTEXT_INITIALIZING,
+ PULSE_CONTEXT_READY,
+ PULSE_CONTEXT_FINISHED
+};
+
+typedef struct PulseAudioDeviceList {
+ AVDeviceInfoList *devices;
+ int error_code;
+ int output;
+ char *default_device;
+} PulseAudioDeviceList;
+
+static void pa_state_cb(pa_context *c, void *userdata)
+{
+ enum PulseAudioContextState *context_state = userdata;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ *context_state = PULSE_CONTEXT_FINISHED;
+ break;
+ case PA_CONTEXT_READY:
+ *context_state = PULSE_CONTEXT_READY;
+ break;
+ default:
+ break;
+ }
+}
+
+void ff_pulse_audio_disconnect_context(pa_mainloop **pa_ml, pa_context **pa_ctx)
+{
+ av_assert0(pa_ml);
+ av_assert0(pa_ctx);
+
+ if (*pa_ctx) {
+ pa_context_set_state_callback(*pa_ctx, NULL, NULL);
+ pa_context_disconnect(*pa_ctx);
+ pa_context_unref(*pa_ctx);
+ }
+ if (*pa_ml)
+ pa_mainloop_free(*pa_ml);
+ *pa_ml = NULL;
+ *pa_ctx = NULL;
+}
+
+int ff_pulse_audio_connect_context(pa_mainloop **pa_ml, pa_context **pa_ctx,
+ const char *server, const char *description)
+{
+ int ret;
+ pa_mainloop_api *pa_mlapi = NULL;
+ enum PulseAudioContextState context_state = PULSE_CONTEXT_INITIALIZING;
+
+ av_assert0(pa_ml);
+ av_assert0(pa_ctx);
+
+ *pa_ml = NULL;
+ *pa_ctx = NULL;
+
+ if (!(*pa_ml = pa_mainloop_new()))
+ return AVERROR(ENOMEM);
+ if (!(pa_mlapi = pa_mainloop_get_api(*pa_ml))) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ if (!(*pa_ctx = pa_context_new(pa_mlapi, description))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ pa_context_set_state_callback(*pa_ctx, pa_state_cb, &context_state);
+ if (pa_context_connect(*pa_ctx, server, 0, NULL) < 0) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ while (context_state == PULSE_CONTEXT_INITIALIZING)
+ pa_mainloop_iterate(*pa_ml, 1, NULL);
+ if (context_state == PULSE_CONTEXT_FINISHED) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ return 0;
+
+ fail:
+ ff_pulse_audio_disconnect_context(pa_ml, pa_ctx);
+ return ret;
+}
+
+static void pulse_add_detected_device(PulseAudioDeviceList *info,
+ const char *name, const char *description)
+{
+ int ret;
+ AVDeviceInfo *new_device = NULL;
+
+ if (info->error_code)
+ return;
+
+ new_device = av_mallocz(sizeof(AVDeviceInfo));
+ if (!new_device) {
+ info->error_code = AVERROR(ENOMEM);
+ return;
+ }
+
+ new_device->device_description = av_strdup(description);
+ new_device->device_name = av_strdup(name);
+
+ if (!new_device->device_description || !new_device->device_name) {
+ info->error_code = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if ((ret = av_dynarray_add_nofree(&info->devices->devices,
+ &info->devices->nb_devices, new_device)) < 0) {
+ info->error_code = ret;
+ goto fail;
+ }
+ return;
+
+ fail:
+ av_freep(&new_device->device_description);
+ av_freep(&new_device->device_name);
+ av_free(new_device);
+
+}
+
+static void pulse_audio_source_device_cb(pa_context *c, const pa_source_info *dev,
+ int eol, void *userdata)
+{
+ if (!eol)
+ pulse_add_detected_device(userdata, dev->name, dev->description);
+}
+
+static void pulse_audio_sink_device_cb(pa_context *c, const pa_sink_info *dev,
+ int eol, void *userdata)
+{
+ if (!eol)
+ pulse_add_detected_device(userdata, dev->name, dev->description);
+}
+
+static void pulse_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata)
+{
+ PulseAudioDeviceList *info = userdata;
+ if (info->output)
+ info->default_device = av_strdup(i->default_sink_name);
+ else
+ info->default_device = av_strdup(i->default_source_name);
+ if (!info->default_device)
+ info->error_code = AVERROR(ENOMEM);
+}
+
+int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output)
+{
+ pa_mainloop *pa_ml = NULL;
+ pa_operation *pa_op = NULL;
+ pa_context *pa_ctx = NULL;
+ enum pa_operation_state op_state;
+ PulseAudioDeviceList dev_list = { 0 };
+ int i;
+
+ dev_list.output = output;
+ dev_list.devices = devices;
+ if (!devices)
+ return AVERROR(EINVAL);
+ devices->nb_devices = 0;
+ devices->devices = NULL;
+
+ if ((dev_list.error_code = ff_pulse_audio_connect_context(&pa_ml, &pa_ctx, server, "Query devices")) < 0)
+ goto fail;
+
+ if (output)
+ pa_op = pa_context_get_sink_info_list(pa_ctx, pulse_audio_sink_device_cb, &dev_list);
+ else
+ pa_op = pa_context_get_source_info_list(pa_ctx, pulse_audio_source_device_cb, &dev_list);
+ while ((op_state = pa_operation_get_state(pa_op)) == PA_OPERATION_RUNNING)
+ pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (op_state != PA_OPERATION_DONE)
+ dev_list.error_code = AVERROR_EXTERNAL;
+ pa_operation_unref(pa_op);
+ if (dev_list.error_code < 0)
+ goto fail;
+
+ pa_op = pa_context_get_server_info(pa_ctx, pulse_server_info_cb, &dev_list);
+ while ((op_state = pa_operation_get_state(pa_op)) == PA_OPERATION_RUNNING)
+ pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (op_state != PA_OPERATION_DONE)
+ dev_list.error_code = AVERROR_EXTERNAL;
+ pa_operation_unref(pa_op);
+ if (dev_list.error_code < 0)
+ goto fail;
+
+ devices->default_device = -1;
+ for (i = 0; i < devices->nb_devices; i++) {
+ if (!strcmp(devices->devices[i]->device_name, dev_list.default_device)) {
+ devices->default_device = i;
+ break;
+ }
+ }
+
+ fail:
+ av_free(dev_list.default_device);
+ ff_pulse_audio_disconnect_context(&pa_ml, &pa_ctx);
+ return dev_list.error_code;
+}
diff --git a/libavdevice/pulse_audio_common.h b/libavdevice/pulse_audio_common.h
new file mode 100644
index 0000000000..02534f79a1
--- /dev/null
+++ b/libavdevice/pulse_audio_common.h
@@ -0,0 +1,38 @@
+/*
+ * Pulseaudio input
+ * Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVDEVICE_PULSE_AUDIO_COMMON_H
+#define AVDEVICE_PULSE_AUDIO_COMMON_H
+
+#include <pulse/pulseaudio.h>
+#include "libavcodec/avcodec.h"
+#include "avdevice.h"
+
+pa_sample_format_t ff_codec_id_to_pulse_format(enum AVCodecID codec_id);
+
+int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output);
+
+int ff_pulse_audio_connect_context(pa_mainloop **pa_ml, pa_context **pa_ctx,
+ const char *server, const char *description);
+
+void ff_pulse_audio_disconnect_context(pa_mainloop **pa_ml, pa_context **pa_ctx);
+
+#endif /* AVDEVICE_PULSE_AUDIO_COMMON_H */
diff --git a/libavdevice/pulse_audio_dec.c b/libavdevice/pulse_audio_dec.c
new file mode 100644
index 0000000000..aa0800b40b
--- /dev/null
+++ b/libavdevice/pulse_audio_dec.c
@@ -0,0 +1,376 @@
+/*
+ * Pulseaudio input
+ * Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
+ * Copyright 2004-2006 Lennart Poettering
+ * Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <pulse/rtclock.h>
+#include <pulse/error.h>
+
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "pulse_audio_common.h"
+#include "timefilter.h"
+
+#define DEFAULT_CODEC_ID AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE)
+
+typedef struct PulseData {
+ AVClass *class;
+ char *server;
+ char *name;
+ char *stream_name;
+ int sample_rate;
+ int channels;
+ int frame_size;
+ int fragment_size;
+
+ pa_threaded_mainloop *mainloop;
+ pa_context *context;
+ pa_stream *stream;
+
+ TimeFilter *timefilter;
+ int last_period;
+ int wallclock;
+} PulseData;
+
+
+#define CHECK_SUCCESS_GOTO(rerror, expression, label) \
+ do { \
+ if (!(expression)) { \
+ rerror = AVERROR_EXTERNAL; \
+ goto label; \
+ } \
+ } while (0)
+
+#define CHECK_DEAD_GOTO(p, rerror, label) \
+ do { \
+ if (!(p)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((p)->context)) || \
+ !(p)->stream || !PA_STREAM_IS_GOOD(pa_stream_get_state((p)->stream))) { \
+ rerror = AVERROR_EXTERNAL; \
+ goto label; \
+ } \
+ } while (0)
+
+static void context_state_cb(pa_context *c, void *userdata) {
+ PulseData *p = userdata;
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+ break;
+ }
+}
+
+static void stream_state_cb(pa_stream *s, void * userdata) {
+ PulseData *p = userdata;
+
+ switch (pa_stream_get_state(s)) {
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+ break;
+ }
+}
+
+static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
+ PulseData *p = userdata;
+
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+}
+
+static void stream_latency_update_cb(pa_stream *s, void *userdata) {
+ PulseData *p = userdata;
+
+ pa_threaded_mainloop_signal(p->mainloop, 0);
+}
+
+static av_cold int pulse_close(AVFormatContext *s)
+{
+ PulseData *pd = s->priv_data;
+
+ if (pd->mainloop)
+ pa_threaded_mainloop_stop(pd->mainloop);
+
+ if (pd->stream)
+ pa_stream_unref(pd->stream);
+ pd->stream = NULL;
+
+ if (pd->context) {
+ pa_context_disconnect(pd->context);
+ pa_context_unref(pd->context);
+ }
+ pd->context = NULL;
+
+ if (pd->mainloop)
+ pa_threaded_mainloop_free(pd->mainloop);
+ pd->mainloop = NULL;
+
+ ff_timefilter_destroy(pd->timefilter);
+ pd->timefilter = NULL;
+
+ return 0;
+}
+
+static av_cold int pulse_read_header(AVFormatContext *s)
+{
+ PulseData *pd = s->priv_data;
+ AVStream *st;
+ char *device = NULL;
+ int ret;
+ enum AVCodecID codec_id =
+ s->audio_codec_id == AV_CODEC_ID_NONE ? DEFAULT_CODEC_ID : s->audio_codec_id;
+ const pa_sample_spec ss = { ff_codec_id_to_pulse_format(codec_id),
+ pd->sample_rate,
+ pd->channels };
+
+ pa_buffer_attr attr = { -1 };
+
+ st = avformat_new_stream(s, NULL);
+
+ if (!st) {
+ av_log(s, AV_LOG_ERROR, "Cannot add stream\n");
+ return AVERROR(ENOMEM);
+ }
+
+ attr.fragsize = pd->fragment_size;
+
+ if (s->filename[0] != '\0' && strcmp(s->filename, "default"))
+ device = s->filename;
+
+ if (!(pd->mainloop = pa_threaded_mainloop_new())) {
+ pulse_close(s);
+ return AVERROR_EXTERNAL;
+ }
+
+ if (!(pd->context = pa_context_new(pa_threaded_mainloop_get_api(pd->mainloop), pd->name))) {
+ pulse_close(s);
+ return AVERROR_EXTERNAL;
+ }
+
+ pa_context_set_state_callback(pd->context, context_state_cb, pd);
+
+ if (pa_context_connect(pd->context, pd->server, 0, NULL) < 0) {
+ pulse_close(s);
+ return AVERROR(pa_context_errno(pd->context));
+ }
+
+ pa_threaded_mainloop_lock(pd->mainloop);
+
+ if (pa_threaded_mainloop_start(pd->mainloop) < 0) {
+ ret = -1;
+ goto unlock_and_fail;
+ }
+
+ for (;;) {
+ pa_context_state_t state;
+
+ state = pa_context_get_state(pd->context);
+
+ if (state == PA_CONTEXT_READY)
+ break;
+
+ if (!PA_CONTEXT_IS_GOOD(state)) {
+ ret = AVERROR(pa_context_errno(pd->context));
+ goto unlock_and_fail;
+ }
+
+ /* Wait until the context is ready */
+ pa_threaded_mainloop_wait(pd->mainloop);
+ }
+
+ if (!(pd->stream = pa_stream_new(pd->context, pd->stream_name, &ss, NULL))) {
+ ret = AVERROR(pa_context_errno(pd->context));
+ goto unlock_and_fail;
+ }
+
+ pa_stream_set_state_callback(pd->stream, stream_state_cb, pd);
+ pa_stream_set_read_callback(pd->stream, stream_request_cb, pd);
+ pa_stream_set_write_callback(pd->stream, stream_request_cb, pd);
+ pa_stream_set_latency_update_callback(pd->stream, stream_latency_update_cb, pd);
+
+ ret = pa_stream_connect_record(pd->stream, device, &attr,
+ PA_STREAM_INTERPOLATE_TIMING
+ |PA_STREAM_ADJUST_LATENCY
+ |PA_STREAM_AUTO_TIMING_UPDATE);
+
+ if (ret < 0) {
+ ret = AVERROR(pa_context_errno(pd->context));
+ goto unlock_and_fail;
+ }
+
+ for (;;) {
+ pa_stream_state_t state;
+
+ state = pa_stream_get_state(pd->stream);
+
+ if (state == PA_STREAM_READY)
+ break;
+
+ if (!PA_STREAM_IS_GOOD(state)) {
+ ret = AVERROR(pa_context_errno(pd->context));
+ goto unlock_and_fail;
+ }
+
+ /* Wait until the stream is ready */
+ pa_threaded_mainloop_wait(pd->mainloop);
+ }
+
+ pa_threaded_mainloop_unlock(pd->mainloop);
+
+ /* take real parameters */
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = codec_id;
+ st->codec->sample_rate = pd->sample_rate;
+ st->codec->channels = pd->channels;
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
+ pd->timefilter = ff_timefilter_new(1000000.0 / pd->sample_rate,
+ 1000, 1.5E-6);
+
+ if (!pd->timefilter) {
+ pulse_close(s);
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock(pd->mainloop);
+
+ pulse_close(s);
+ return ret;
+}
+
+static int pulse_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ PulseData *pd = s->priv_data;
+ int ret;
+ size_t read_length;
+ const void *read_data = NULL;
+ int64_t dts;
+ pa_usec_t latency;
+ int negative;
+
+ pa_threaded_mainloop_lock(pd->mainloop);
+
+ CHECK_DEAD_GOTO(pd, ret, unlock_and_fail);
+
+ while (!read_data) {
+ int r;
+
+ r = pa_stream_peek(pd->stream, &read_data, &read_length);
+ CHECK_SUCCESS_GOTO(ret, r == 0, unlock_and_fail);
+
+ if (read_length <= 0) {
+ pa_threaded_mainloop_wait(pd->mainloop);
+ CHECK_DEAD_GOTO(pd, ret, unlock_and_fail);
+ } else if (!read_data) {
+ /* There's a hole in the stream, skip it. We could generate
+ * silence, but that wouldn't work for compressed streams. */
+ r = pa_stream_drop(pd->stream);
+ CHECK_SUCCESS_GOTO(ret, r == 0, unlock_and_fail);
+ }
+ }
+
+ if (av_new_packet(pkt, read_length) < 0) {
+ ret = AVERROR(ENOMEM);
+ goto unlock_and_fail;
+ }
+
+ dts = av_gettime();
+ pa_operation_unref(pa_stream_update_timing_info(pd->stream, NULL, NULL));
+
+ if (pa_stream_get_latency(pd->stream, &latency, &negative) >= 0) {
+ enum AVCodecID codec_id =
+ s->audio_codec_id == AV_CODEC_ID_NONE ? DEFAULT_CODEC_ID : s->audio_codec_id;
+ int frame_size = ((av_get_bits_per_sample(codec_id) >> 3) * pd->channels);
+ int frame_duration = read_length / frame_size;
+
+
+ if (negative) {
+ dts += latency;
+ } else
+ dts -= latency;
+ if (pd->wallclock)
+ pkt->pts = ff_timefilter_update(pd->timefilter, dts, pd->last_period);
+
+ pd->last_period = frame_duration;
+ } else {
+ av_log(s, AV_LOG_WARNING, "pa_stream_get_latency() failed\n");
+ }
+
+ memcpy(pkt->data, read_data, read_length);
+ pa_stream_drop(pd->stream);
+
+ pa_threaded_mainloop_unlock(pd->mainloop);
+ return 0;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock(pd->mainloop);
+ return ret;
+}
+
+static int pulse_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
+{
+ PulseData *s = h->priv_data;
+ return ff_pulse_audio_get_devices(device_list, s->server, 0);
+}
+
+#define OFFSET(a) offsetof(PulseData, a)
+#define D AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption options[] = {
+ { "server", "set PulseAudio server", OFFSET(server), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D },
+ { "name", "set application name", OFFSET(name), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, D },
+ { "stream_name", "set stream description", OFFSET(stream_name), AV_OPT_TYPE_STRING, {.str = "record"}, 0, 0, D },
+ { "sample_rate", "set sample rate in Hz", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, D },
+ { "channels", "set number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, D },
+ { "frame_size", "set number of bytes per frame", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, D },
+ { "fragment_size", "set buffering size, affects latency and cpu usage", OFFSET(fragment_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D },
+ { "wallclock", "set the initial pts using the current time", OFFSET(wallclock), AV_OPT_TYPE_INT, {.i64 = 1}, -1, 1, D },
+ { NULL },
+};
+
+static const AVClass pulse_demuxer_class = {
+ .class_name = "Pulse demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
+};
+
+AVInputFormat ff_pulse_demuxer = {
+ .name = "pulse",
+ .long_name = NULL_IF_CONFIG_SMALL("Pulse audio input"),
+ .priv_data_size = sizeof(PulseData),
+ .read_header = pulse_read_header,
+ .read_packet = pulse_read_packet,
+ .read_close = pulse_close,
+ .get_device_list = pulse_get_device_list,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &pulse_demuxer_class,
+};
diff --git a/libavdevice/pulse_audio_enc.c b/libavdevice/pulse_audio_enc.c
new file mode 100644
index 0000000000..bc4d1f0516
--- /dev/null
+++ b/libavdevice/pulse_audio_enc.c
@@ -0,0 +1,796 @@
+/*
+ * Copyright (c) 2013 Lukasz Marek <lukasz.m.luki@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
+ */
+
+#include <math.h>
+#include <pulse/pulseaudio.h>
+#include <pulse/error.h>
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/log.h"
+#include "libavutil/attributes.h"
+#include "pulse_audio_common.h"
+
+typedef struct PulseData {
+ AVClass *class;
+ const char *server;
+ const char *name;
+ const char *stream_name;
+ const char *device;
+ int64_t timestamp;
+ int buffer_size; /**< Buffer size in bytes */
+ int buffer_duration; /**< Buffer size in ms, recalculated to buffer_size */
+ int prebuf;
+ int minreq;
+ int last_result;
+ pa_threaded_mainloop *mainloop;
+ pa_context *ctx;
+ pa_stream *stream;
+ int nonblocking;
+ int mute;
+ pa_volume_t base_volume;
+ pa_volume_t last_volume;
+} PulseData;
+
+static void pulse_audio_sink_device_cb(pa_context *ctx, const pa_sink_info *dev,
+ int eol, void *userdata)
+{
+ PulseData *s = userdata;
+
+ if (s->ctx != ctx)
+ return;
+
+ if (eol) {
+ pa_threaded_mainloop_signal(s->mainloop, 0);
+ } else {
+ if (dev->flags & PA_SINK_FLAT_VOLUME)
+ s->base_volume = dev->base_volume;
+ else
+ s->base_volume = PA_VOLUME_NORM;
+ av_log(s, AV_LOG_DEBUG, "base volume: %u\n", s->base_volume);
+ }
+}
+
+/* Mainloop must be locked before calling this function as it uses pa_threaded_mainloop_wait. */
+static int pulse_update_sink_info(AVFormatContext *h)
+{
+ PulseData *s = h->priv_data;
+ pa_operation *op;
+ if (!(op = pa_context_get_sink_info_by_name(s->ctx, s->device,
+ pulse_audio_sink_device_cb, s))) {
+ av_log(s, AV_LOG_ERROR, "pa_context_get_sink_info_by_name failed.\n");
+ return AVERROR_EXTERNAL;
+ }
+ while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
+ pa_threaded_mainloop_wait(s->mainloop);
+ pa_operation_unref(op);
+ return 0;
+}
+
+static void pulse_audio_sink_input_cb(pa_context *ctx, const pa_sink_input_info *i,
+ int eol, void *userdata)
+{
+ AVFormatContext *h = userdata;
+ PulseData *s = h->priv_data;
+
+ if (s->ctx != ctx)
+ return;
+
+ if (!eol) {
+ double val;
+ pa_volume_t vol = pa_cvolume_avg(&i->volume);
+ if (s->mute < 0 || (s->mute && !i->mute) || (!s->mute && i->mute)) {
+ s->mute = i->mute;
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_MUTE_STATE_CHANGED, &s->mute, sizeof(s->mute));
+ }
+
+ vol = pa_sw_volume_divide(vol, s->base_volume);
+ if (s->last_volume != vol) {
+ val = (double)vol / PA_VOLUME_NORM;
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_VOLUME_LEVEL_CHANGED, &val, sizeof(val));
+ s->last_volume = vol;
+ }
+ }
+}
+
+/* This function creates new loop so may be called from PA callbacks.
+ Mainloop must be locked before calling this function as it operates on streams. */
+static int pulse_update_sink_input_info(AVFormatContext *h)
+{
+ PulseData *s = h->priv_data;
+ pa_operation *op;
+ enum pa_operation_state op_state;
+ pa_mainloop *ml = NULL;
+ pa_context *ctx = NULL;
+ int ret = 0;
+
+ if ((ret = ff_pulse_audio_connect_context(&ml, &ctx, s->server, "Update sink input information")) < 0)
+ return ret;
+
+ if (!(op = pa_context_get_sink_input_info(ctx, pa_stream_get_index(s->stream),
+ pulse_audio_sink_input_cb, h))) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ while ((op_state = pa_operation_get_state(op)) == PA_OPERATION_RUNNING)
+ pa_mainloop_iterate(ml, 1, NULL);
+ pa_operation_unref(op);
+ if (op_state != PA_OPERATION_DONE) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ fail:
+ ff_pulse_audio_disconnect_context(&ml, &ctx);
+ if (ret)
+ av_log(s, AV_LOG_ERROR, "pa_context_get_sink_input_info failed.\n");
+ return ret;
+}
+
+static void pulse_event(pa_context *ctx, pa_subscription_event_type_t t,
+ uint32_t idx, void *userdata)
+{
+ AVFormatContext *h = userdata;
+ PulseData *s = h->priv_data;
+
+ if (s->ctx != ctx)
+ return;
+
+ if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE)
+ // Calling from mainloop callback. No need to lock mainloop.
+ pulse_update_sink_input_info(h);
+ }
+}
+
+static void pulse_stream_writable(pa_stream *stream, size_t nbytes, void *userdata)
+{
+ AVFormatContext *h = userdata;
+ PulseData *s = h->priv_data;
+ int64_t val = nbytes;
+
+ if (stream != s->stream)
+ return;
+
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_BUFFER_WRITABLE, &val, sizeof(val));
+ pa_threaded_mainloop_signal(s->mainloop, 0);
+}
+
+static void pulse_overflow(pa_stream *stream, void *userdata)
+{
+ AVFormatContext *h = userdata;
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_BUFFER_OVERFLOW, NULL, 0);
+}
+
+static void pulse_underflow(pa_stream *stream, void *userdata)
+{
+ AVFormatContext *h = userdata;
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_BUFFER_UNDERFLOW, NULL, 0);
+}
+
+static void pulse_stream_state(pa_stream *stream, void *userdata)
+{
+ PulseData *s = userdata;
+
+ if (stream != s->stream)
+ return;
+
+ switch (pa_stream_get_state(s->stream)) {
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal(s->mainloop, 0);
+ default:
+ break;
+ }
+}
+
+static int pulse_stream_wait(PulseData *s)
+{
+ pa_stream_state_t state;
+
+ while ((state = pa_stream_get_state(s->stream)) != PA_STREAM_READY) {
+ if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
+ return AVERROR_EXTERNAL;
+ pa_threaded_mainloop_wait(s->mainloop);
+ }
+ return 0;
+}
+
+static void pulse_context_state(pa_context *ctx, void *userdata)
+{
+ PulseData *s = userdata;
+
+ if (s->ctx != ctx)
+ return;
+
+ switch (pa_context_get_state(ctx)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ pa_threaded_mainloop_signal(s->mainloop, 0);
+ default:
+ break;
+ }
+}
+
+static int pulse_context_wait(PulseData *s)
+{
+ pa_context_state_t state;
+
+ while ((state = pa_context_get_state(s->ctx)) != PA_CONTEXT_READY) {
+ if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
+ return AVERROR_EXTERNAL;
+ pa_threaded_mainloop_wait(s->mainloop);
+ }
+ return 0;
+}
+
+static void pulse_stream_result(pa_stream *stream, int success, void *userdata)
+{
+ PulseData *s = userdata;
+
+ if (stream != s->stream)
+ return;
+
+ s->last_result = success ? 0 : AVERROR_EXTERNAL;
+ pa_threaded_mainloop_signal(s->mainloop, 0);
+}
+
+static int pulse_finish_stream_operation(PulseData *s, pa_operation *op, const char *name)
+{
+ if (!op) {
+ pa_threaded_mainloop_unlock(s->mainloop);
+ av_log(s, AV_LOG_ERROR, "%s failed.\n", name);
+ return AVERROR_EXTERNAL;
+ }
+ s->last_result = 2;
+ while (s->last_result == 2)
+ pa_threaded_mainloop_wait(s->mainloop);
+ pa_operation_unref(op);
+ pa_threaded_mainloop_unlock(s->mainloop);
+ if (s->last_result != 0)
+ av_log(s, AV_LOG_ERROR, "%s failed.\n", name);
+ return s->last_result;
+}
+
+static int pulse_set_pause(PulseData *s, int pause)
+{
+ pa_operation *op;
+ pa_threaded_mainloop_lock(s->mainloop);
+ op = pa_stream_cork(s->stream, pause, pulse_stream_result, s);
+ return pulse_finish_stream_operation(s, op, "pa_stream_cork");
+}
+
+static int pulse_flash_stream(PulseData *s)
+{
+ pa_operation *op;
+ pa_threaded_mainloop_lock(s->mainloop);
+ op = pa_stream_flush(s->stream, pulse_stream_result, s);
+ return pulse_finish_stream_operation(s, op, "pa_stream_flush");
+}
+
+static void pulse_context_result(pa_context *ctx, int success, void *userdata)
+{
+ PulseData *s = userdata;
+
+ if (s->ctx != ctx)
+ return;
+
+ s->last_result = success ? 0 : AVERROR_EXTERNAL;
+ pa_threaded_mainloop_signal(s->mainloop, 0);
+}
+
+static int pulse_finish_context_operation(PulseData *s, pa_operation *op, const char *name)
+{
+ if (!op) {
+ pa_threaded_mainloop_unlock(s->mainloop);
+ av_log(s, AV_LOG_ERROR, "%s failed.\n", name);
+ return AVERROR_EXTERNAL;
+ }
+ s->last_result = 2;
+ while (s->last_result == 2)
+ pa_threaded_mainloop_wait(s->mainloop);
+ pa_operation_unref(op);
+ pa_threaded_mainloop_unlock(s->mainloop);
+ if (s->last_result != 0)
+ av_log(s, AV_LOG_ERROR, "%s failed.\n", name);
+ return s->last_result;
+}
+
+static int pulse_set_mute(PulseData *s)
+{
+ pa_operation *op;
+ pa_threaded_mainloop_lock(s->mainloop);
+ op = pa_context_set_sink_input_mute(s->ctx, pa_stream_get_index(s->stream),
+ s->mute, pulse_context_result, s);
+ return pulse_finish_context_operation(s, op, "pa_context_set_sink_input_mute");
+}
+
+static int pulse_set_volume(PulseData *s, double volume)
+{
+ pa_operation *op;
+ pa_cvolume cvol;
+ pa_volume_t vol;
+ const pa_sample_spec *ss = pa_stream_get_sample_spec(s->stream);
+
+ vol = pa_sw_volume_multiply(lround(volume * PA_VOLUME_NORM), s->base_volume);
+ pa_cvolume_set(&cvol, ss->channels, PA_VOLUME_NORM);
+ pa_sw_cvolume_multiply_scalar(&cvol, &cvol, vol);
+ pa_threaded_mainloop_lock(s->mainloop);
+ op = pa_context_set_sink_input_volume(s->ctx, pa_stream_get_index(s->stream),
+ &cvol, pulse_context_result, s);
+ return pulse_finish_context_operation(s, op, "pa_context_set_sink_input_volume");
+}
+
+static int pulse_subscribe_events(PulseData *s)
+{
+ pa_operation *op;
+
+ pa_threaded_mainloop_lock(s->mainloop);
+ op = pa_context_subscribe(s->ctx, PA_SUBSCRIPTION_MASK_SINK_INPUT, pulse_context_result, s);
+ return pulse_finish_context_operation(s, op, "pa_context_subscribe");
+}
+
+static void pulse_map_channels_to_pulse(int64_t channel_layout, pa_channel_map *channel_map)
+{
+ channel_map->channels = 0;
+ if (channel_layout & AV_CH_FRONT_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ if (channel_layout & AV_CH_FRONT_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ if (channel_layout & AV_CH_FRONT_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
+ if (channel_layout & AV_CH_LOW_FREQUENCY)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_LFE;
+ if (channel_layout & AV_CH_BACK_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
+ if (channel_layout & AV_CH_BACK_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
+ if (channel_layout & AV_CH_FRONT_LEFT_OF_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
+ if (channel_layout & AV_CH_FRONT_RIGHT_OF_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
+ if (channel_layout & AV_CH_BACK_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
+ if (channel_layout & AV_CH_SIDE_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
+ if (channel_layout & AV_CH_SIDE_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
+ if (channel_layout & AV_CH_TOP_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_CENTER;
+ if (channel_layout & AV_CH_TOP_FRONT_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
+ if (channel_layout & AV_CH_TOP_FRONT_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
+ if (channel_layout & AV_CH_TOP_FRONT_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
+ if (channel_layout & AV_CH_TOP_BACK_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_REAR_LEFT;
+ if (channel_layout & AV_CH_TOP_BACK_CENTER)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_REAR_CENTER;
+ if (channel_layout & AV_CH_TOP_BACK_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
+ if (channel_layout & AV_CH_STEREO_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
+ if (channel_layout & AV_CH_STEREO_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
+ if (channel_layout & AV_CH_WIDE_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_AUX0;
+ if (channel_layout & AV_CH_WIDE_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_AUX1;
+ if (channel_layout & AV_CH_SURROUND_DIRECT_LEFT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_AUX2;
+ if (channel_layout & AV_CH_SURROUND_DIRECT_RIGHT)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_AUX3;
+ if (channel_layout & AV_CH_LOW_FREQUENCY_2)
+ channel_map->map[channel_map->channels++] = PA_CHANNEL_POSITION_LFE;
+}
+
+static av_cold int pulse_write_trailer(AVFormatContext *h)
+{
+ PulseData *s = h->priv_data;
+
+ if (s->mainloop) {
+ pa_threaded_mainloop_lock(s->mainloop);
+ if (s->stream) {
+ pa_stream_disconnect(s->stream);
+ pa_stream_set_state_callback(s->stream, NULL, NULL);
+ pa_stream_set_write_callback(s->stream, NULL, NULL);
+ pa_stream_set_overflow_callback(s->stream, NULL, NULL);
+ pa_stream_set_underflow_callback(s->stream, NULL, NULL);
+ pa_stream_unref(s->stream);
+ s->stream = NULL;
+ }
+ if (s->ctx) {
+ pa_context_disconnect(s->ctx);
+ pa_context_set_state_callback(s->ctx, NULL, NULL);
+ pa_context_set_subscribe_callback(s->ctx, NULL, NULL);
+ pa_context_unref(s->ctx);
+ s->ctx = NULL;
+ }
+ pa_threaded_mainloop_unlock(s->mainloop);
+ pa_threaded_mainloop_stop(s->mainloop);
+ pa_threaded_mainloop_free(s->mainloop);
+ s->mainloop = NULL;
+ }
+
+ return 0;
+}
+
+static av_cold int pulse_write_header(AVFormatContext *h)
+{
+ PulseData *s = h->priv_data;
+ AVStream *st = NULL;
+ int ret;
+ pa_sample_spec sample_spec;
+ pa_buffer_attr buffer_attributes = { -1, -1, -1, -1, -1 };
+ pa_channel_map channel_map;
+ pa_mainloop_api *mainloop_api;
+ const char *stream_name = s->stream_name;
+ static const pa_stream_flags_t stream_flags = PA_STREAM_INTERPOLATE_TIMING |
+ PA_STREAM_AUTO_TIMING_UPDATE |
+ PA_STREAM_NOT_MONOTONIC;
+
+ if (h->nb_streams != 1 || h->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(s, AV_LOG_ERROR, "Only a single audio stream is supported.\n");
+ return AVERROR(EINVAL);
+ }
+ st = h->streams[0];
+
+ if (!stream_name) {
+ if (h->filename[0])
+ stream_name = h->filename;
+ else
+ stream_name = "Playback";
+ }
+ s->nonblocking = (h->flags & AVFMT_FLAG_NONBLOCK);
+
+ if (s->buffer_duration) {
+ int64_t bytes = s->buffer_duration;
+ bytes *= st->codec->channels * st->codec->sample_rate *
+ av_get_bytes_per_sample(st->codec->sample_fmt);
+ bytes /= 1000;
+ buffer_attributes.tlength = FFMAX(s->buffer_size, av_clip64(bytes, 0, UINT32_MAX - 1));
+ av_log(s, AV_LOG_DEBUG,
+ "Buffer duration: %ums recalculated into %"PRId64" bytes buffer.\n",
+ s->buffer_duration, bytes);
+ av_log(s, AV_LOG_DEBUG, "Real buffer length is %u bytes\n", buffer_attributes.tlength);
+ } else if (s->buffer_size)
+ buffer_attributes.tlength = s->buffer_size;
+ if (s->prebuf)
+ buffer_attributes.prebuf = s->prebuf;
+ if (s->minreq)
+ buffer_attributes.minreq = s->minreq;
+
+ sample_spec.format = ff_codec_id_to_pulse_format(st->codec->codec_id);
+ sample_spec.rate = st->codec->sample_rate;
+ sample_spec.channels = st->codec->channels;
+ if (!pa_sample_spec_valid(&sample_spec)) {
+ av_log(s, AV_LOG_ERROR, "Invalid sample spec.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (sample_spec.channels == 1) {
+ channel_map.channels = 1;
+ channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
+ } else if (st->codec->channel_layout) {
+ if (av_get_channel_layout_nb_channels(st->codec->channel_layout) != st->codec->channels)
+ return AVERROR(EINVAL);
+ pulse_map_channels_to_pulse(st->codec->channel_layout, &channel_map);
+ /* Unknown channel is present in channel_layout, let PulseAudio use its default. */
+ if (channel_map.channels != sample_spec.channels) {
+ av_log(s, AV_LOG_WARNING, "Unknown channel. Using defaul channel map.\n");
+ channel_map.channels = 0;
+ }
+ } else
+ channel_map.channels = 0;
+
+ if (!channel_map.channels)
+ av_log(s, AV_LOG_WARNING, "Using PulseAudio's default channel map.\n");
+ else if (!pa_channel_map_valid(&channel_map)) {
+ av_log(s, AV_LOG_ERROR, "Invalid channel map.\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* start main loop */
+ s->mainloop = pa_threaded_mainloop_new();
+ if (!s->mainloop) {
+ av_log(s, AV_LOG_ERROR, "Cannot create threaded mainloop.\n");
+ return AVERROR(ENOMEM);
+ }
+ if ((ret = pa_threaded_mainloop_start(s->mainloop)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Cannot start threaded mainloop: %s.\n", pa_strerror(ret));
+ pa_threaded_mainloop_free(s->mainloop);
+ s->mainloop = NULL;
+ return AVERROR_EXTERNAL;
+ }
+
+ pa_threaded_mainloop_lock(s->mainloop);
+
+ mainloop_api = pa_threaded_mainloop_get_api(s->mainloop);
+ if (!mainloop_api) {
+ av_log(s, AV_LOG_ERROR, "Cannot get mainloop API.\n");
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ s->ctx = pa_context_new(mainloop_api, s->name);
+ if (!s->ctx) {
+ av_log(s, AV_LOG_ERROR, "Cannot create context.\n");
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ pa_context_set_state_callback(s->ctx, pulse_context_state, s);
+ pa_context_set_subscribe_callback(s->ctx, pulse_event, h);
+
+ if ((ret = pa_context_connect(s->ctx, s->server, 0, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Cannot connect context: %s.\n", pa_strerror(ret));
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ if ((ret = pulse_context_wait(s)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Context failed.\n");
+ goto fail;
+ }
+
+ s->stream = pa_stream_new(s->ctx, stream_name, &sample_spec,
+ channel_map.channels ? &channel_map : NULL);
+
+ if ((ret = pulse_update_sink_info(h)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Updating sink info failed.\n");
+ goto fail;
+ }
+
+ if (!s->stream) {
+ av_log(s, AV_LOG_ERROR, "Cannot create stream.\n");
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ pa_stream_set_state_callback(s->stream, pulse_stream_state, s);
+ pa_stream_set_write_callback(s->stream, pulse_stream_writable, h);
+ pa_stream_set_overflow_callback(s->stream, pulse_overflow, h);
+ pa_stream_set_underflow_callback(s->stream, pulse_underflow, h);
+
+ if ((ret = pa_stream_connect_playback(s->stream, s->device, &buffer_attributes,
+ stream_flags, NULL, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "pa_stream_connect_playback failed: %s.\n", pa_strerror(ret));
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ if ((ret = pulse_stream_wait(s)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Stream failed.\n");
+ goto fail;
+ }
+
+ /* read back buffer attributes for future use */
+ buffer_attributes = *pa_stream_get_buffer_attr(s->stream);
+ s->buffer_size = buffer_attributes.tlength;
+ s->prebuf = buffer_attributes.prebuf;
+ s->minreq = buffer_attributes.minreq;
+ av_log(s, AV_LOG_DEBUG, "Real buffer attributes: size: %d, prebuf: %d, minreq: %d\n",
+ s->buffer_size, s->prebuf, s->minreq);
+
+ pa_threaded_mainloop_unlock(s->mainloop);
+
+ if ((ret = pulse_subscribe_events(s)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Event subscription failed.\n");
+ /* a bit ugly but the simplest to lock here*/
+ pa_threaded_mainloop_lock(s->mainloop);
+ goto fail;
+ }
+
+ /* force control messages */
+ s->mute = -1;
+ s->last_volume = PA_VOLUME_INVALID;
+ pa_threaded_mainloop_lock(s->mainloop);
+ if ((ret = pulse_update_sink_input_info(h)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Updating sink input info failed.\n");
+ goto fail;
+ }
+ pa_threaded_mainloop_unlock(s->mainloop);
+
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
+ return 0;
+ fail:
+ pa_threaded_mainloop_unlock(s->mainloop);
+ pulse_write_trailer(h);
+ return ret;
+}
+
+static int pulse_write_packet(AVFormatContext *h, AVPacket *pkt)
+{
+ PulseData *s = h->priv_data;
+ int ret;
+ int64_t writable_size;
+
+ if (!pkt)
+ return pulse_flash_stream(s);
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ s->timestamp = pkt->dts;
+
+ if (pkt->duration) {
+ s->timestamp += pkt->duration;
+ } else {
+ AVStream *st = h->streams[0];
+ AVCodecContext *codec_ctx = st->codec;
+ AVRational r = { 1, codec_ctx->sample_rate };
+ int64_t samples = pkt->size / (av_get_bytes_per_sample(codec_ctx->sample_fmt) * codec_ctx->channels);
+ s->timestamp += av_rescale_q(samples, r, st->time_base);
+ }
+
+ pa_threaded_mainloop_lock(s->mainloop);
+ if (!PA_STREAM_IS_GOOD(pa_stream_get_state(s->stream))) {
+ av_log(s, AV_LOG_ERROR, "PulseAudio stream is in invalid state.\n");
+ goto fail;
+ }
+ while (pa_stream_writable_size(s->stream) < s->minreq) {
+ if (s->nonblocking) {
+ pa_threaded_mainloop_unlock(s->mainloop);
+ return AVERROR(EAGAIN);
+ } else
+ pa_threaded_mainloop_wait(s->mainloop);
+ }
+
+ if ((ret = pa_stream_write(s->stream, pkt->data, pkt->size, NULL, 0, PA_SEEK_RELATIVE)) < 0) {
+ av_log(s, AV_LOG_ERROR, "pa_stream_write failed: %s\n", pa_strerror(ret));
+ goto fail;
+ }
+ if ((writable_size = pa_stream_writable_size(s->stream)) >= s->minreq)
+ avdevice_dev_to_app_control_message(h, AV_DEV_TO_APP_BUFFER_WRITABLE, &writable_size, sizeof(writable_size));
+
+ pa_threaded_mainloop_unlock(s->mainloop);
+
+ return 0;
+ fail:
+ pa_threaded_mainloop_unlock(s->mainloop);
+ return AVERROR_EXTERNAL;
+}
+
+static int pulse_write_frame(AVFormatContext *h, int stream_index,
+ AVFrame **frame, unsigned flags)
+{
+ AVPacket pkt;
+
+ /* Planar formats are not supported yet. */
+ if (flags & AV_WRITE_UNCODED_FRAME_QUERY)
+ return av_sample_fmt_is_planar(h->streams[stream_index]->codec->sample_fmt) ?
+ AVERROR(EINVAL) : 0;
+
+ pkt.data = (*frame)->data[0];
+ pkt.size = (*frame)->nb_samples * av_get_bytes_per_sample((*frame)->format) * av_frame_get_channels(*frame);
+ pkt.dts = (*frame)->pkt_dts;
+ pkt.duration = av_frame_get_pkt_duration(*frame);
+ return pulse_write_packet(h, &pkt);
+}
+
+
+static void pulse_get_output_timestamp(AVFormatContext *h, int stream, int64_t *dts, int64_t *wall)
+{
+ PulseData *s = h->priv_data;
+ pa_usec_t latency;
+ int neg;
+ pa_threaded_mainloop_lock(s->mainloop);
+ pa_stream_get_latency(s->stream, &latency, &neg);
+ pa_threaded_mainloop_unlock(s->mainloop);
+ if (wall)
+ *wall = av_gettime();
+ if (dts)
+ *dts = s->timestamp - (neg ? -latency : latency);
+}
+
+static int pulse_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
+{
+ PulseData *s = h->priv_data;
+ return ff_pulse_audio_get_devices(device_list, s->server, 1);
+}
+
+static int pulse_control_message(AVFormatContext *h, int type,
+ void *data, size_t data_size)
+{
+ PulseData *s = h->priv_data;
+ int ret;
+
+ switch(type) {
+ case AV_APP_TO_DEV_PAUSE:
+ return pulse_set_pause(s, 1);
+ case AV_APP_TO_DEV_PLAY:
+ return pulse_set_pause(s, 0);
+ case AV_APP_TO_DEV_TOGGLE_PAUSE:
+ return pulse_set_pause(s, !pa_stream_is_corked(s->stream));
+ case AV_APP_TO_DEV_MUTE:
+ if (!s->mute) {
+ s->mute = 1;
+ return pulse_set_mute(s);
+ }
+ return 0;
+ case AV_APP_TO_DEV_UNMUTE:
+ if (s->mute) {
+ s->mute = 0;
+ return pulse_set_mute(s);
+ }
+ return 0;
+ case AV_APP_TO_DEV_TOGGLE_MUTE:
+ s->mute = !s->mute;
+ return pulse_set_mute(s);
+ case AV_APP_TO_DEV_SET_VOLUME:
+ return pulse_set_volume(s, *(double *)data);
+ case AV_APP_TO_DEV_GET_VOLUME:
+ s->last_volume = PA_VOLUME_INVALID;
+ pa_threaded_mainloop_lock(s->mainloop);
+ ret = pulse_update_sink_input_info(h);
+ pa_threaded_mainloop_unlock(s->mainloop);
+ return ret;
+ case AV_APP_TO_DEV_GET_MUTE:
+ s->mute = -1;
+ pa_threaded_mainloop_lock(s->mainloop);
+ ret = pulse_update_sink_input_info(h);
+ pa_threaded_mainloop_unlock(s->mainloop);
+ return ret;
+ default:
+ break;
+ }
+ return AVERROR(ENOSYS);
+}
+
+#define OFFSET(a) offsetof(PulseData, a)
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "server", "set PulseAudio server", OFFSET(server), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "name", "set application name", OFFSET(name), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, E },
+ { "stream_name", "set stream description", OFFSET(stream_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "device", "set device name", OFFSET(device), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "buffer_size", "set buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "buffer_duration", "set buffer duration in millisecs", OFFSET(buffer_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "prebuf", "set pre-buffering size", OFFSET(prebuf), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "minreq", "set minimum request size", OFFSET(minreq), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { NULL }
+};
+
+static const AVClass pulse_muxer_class = {
+ .class_name = "PulseAudio muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+};
+
+AVOutputFormat ff_pulse_muxer = {
+ .name = "pulse",
+ .long_name = NULL_IF_CONFIG_SMALL("Pulse audio output"),
+ .priv_data_size = sizeof(PulseData),
+ .audio_codec = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE),
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = pulse_write_header,
+ .write_packet = pulse_write_packet,
+ .write_uncoded_frame = pulse_write_frame,
+ .write_trailer = pulse_write_trailer,
+ .get_output_timestamp = pulse_get_output_timestamp,
+ .get_device_list = pulse_get_device_list,
+ .control_message = pulse_control_message,
+ .flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
+ .priv_class = &pulse_muxer_class,
+};
diff --git a/libavdevice/qtkit.m b/libavdevice/qtkit.m
new file mode 100644
index 0000000000..22a94ca561
--- /dev/null
+++ b/libavdevice/qtkit.m
@@ -0,0 +1,362 @@
+/*
+ * QTKit input device
+ * Copyright (c) 2013 Vadim Kalinsky <vadim@kalinsky.ru>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * QTKit input device
+ * @author Vadim Kalinsky <vadim@kalinsky.ru>
+ */
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+#import <QTKit/QTKit.h>
+#include <pthread.h>
+
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "libavformat/internal.h"
+#include "libavutil/internal.h"
+#include "libavutil/time.h"
+#include "avdevice.h"
+
+#define QTKIT_TIMEBASE 100
+
+static const AVRational kQTKitTimeBase_q = {
+ .num = 1,
+ .den = QTKIT_TIMEBASE
+};
+
+typedef struct
+{
+ AVClass* class;
+
+ float frame_rate;
+ int frames_captured;
+ int64_t first_pts;
+ pthread_mutex_t frame_lock;
+ pthread_cond_t frame_wait_cond;
+ id qt_delegate;
+
+ int list_devices;
+ int video_device_index;
+
+ QTCaptureSession* capture_session;
+ QTCaptureDecompressedVideoOutput* video_output;
+ CVImageBufferRef current_frame;
+} CaptureContext;
+
+static void lock_frames(CaptureContext* ctx)
+{
+ pthread_mutex_lock(&ctx->frame_lock);
+}
+
+static void unlock_frames(CaptureContext* ctx)
+{
+ pthread_mutex_unlock(&ctx->frame_lock);
+}
+
+/** FrameReciever class - delegate for QTCaptureSession
+ */
+@interface FFMPEG_FrameReceiver : NSObject
+{
+ CaptureContext* _context;
+}
+
+- (id)initWithContext:(CaptureContext*)context;
+
+- (void)captureOutput:(QTCaptureOutput *)captureOutput
+ didOutputVideoFrame:(CVImageBufferRef)videoFrame
+ withSampleBuffer:(QTSampleBuffer *)sampleBuffer
+ fromConnection:(QTCaptureConnection *)connection;
+
+@end
+
+@implementation FFMPEG_FrameReceiver
+
+- (id)initWithContext:(CaptureContext*)context
+{
+ if (self = [super init]) {
+ _context = context;
+ }
+ return self;
+}
+
+- (void)captureOutput:(QTCaptureOutput *)captureOutput
+ didOutputVideoFrame:(CVImageBufferRef)videoFrame
+ withSampleBuffer:(QTSampleBuffer *)sampleBuffer
+ fromConnection:(QTCaptureConnection *)connection
+{
+ lock_frames(_context);
+ if (_context->current_frame != nil) {
+ CVBufferRelease(_context->current_frame);
+ }
+
+ _context->current_frame = CVBufferRetain(videoFrame);
+
+ pthread_cond_signal(&_context->frame_wait_cond);
+
+ unlock_frames(_context);
+
+ ++_context->frames_captured;
+}
+
+@end
+
+static void destroy_context(CaptureContext* ctx)
+{
+ [ctx->capture_session stopRunning];
+
+ [ctx->capture_session release];
+ [ctx->video_output release];
+ [ctx->qt_delegate release];
+
+ ctx->capture_session = NULL;
+ ctx->video_output = NULL;
+ ctx->qt_delegate = NULL;
+
+ pthread_mutex_destroy(&ctx->frame_lock);
+ pthread_cond_destroy(&ctx->frame_wait_cond);
+
+ if (ctx->current_frame)
+ CVBufferRelease(ctx->current_frame);
+}
+
+static int qtkit_read_header(AVFormatContext *s)
+{
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ CaptureContext* ctx = (CaptureContext*)s->priv_data;
+
+ ctx->first_pts = av_gettime();
+
+ pthread_mutex_init(&ctx->frame_lock, NULL);
+ pthread_cond_init(&ctx->frame_wait_cond, NULL);
+
+ // List devices if requested
+ if (ctx->list_devices) {
+ av_log(ctx, AV_LOG_INFO, "QTKit video devices:\n");
+ NSArray *devices = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
+ for (QTCaptureDevice *device in devices) {
+ const char *name = [[device localizedDisplayName] UTF8String];
+ int index = [devices indexOfObject:device];
+ av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name);
+ }
+ goto fail;
+ }
+
+ // Find capture device
+ QTCaptureDevice *video_device = nil;
+
+ // check for device index given in filename
+ if (ctx->video_device_index == -1) {
+ sscanf(s->filename, "%d", &ctx->video_device_index);
+ }
+
+ if (ctx->video_device_index >= 0) {
+ NSArray *devices = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
+
+ if (ctx->video_device_index >= [devices count]) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid device index\n");
+ goto fail;
+ }
+
+ video_device = [devices objectAtIndex:ctx->video_device_index];
+ } else if (strncmp(s->filename, "", 1) &&
+ strncmp(s->filename, "default", 7)) {
+ NSArray *devices = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
+
+ for (QTCaptureDevice *device in devices) {
+ if (!strncmp(s->filename, [[device localizedDisplayName] UTF8String], strlen(s->filename))) {
+ video_device = device;
+ break;
+ }
+ }
+ if (!video_device) {
+ av_log(ctx, AV_LOG_ERROR, "Video device not found\n");
+ goto fail;
+ }
+ } else {
+ video_device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeMuxed];
+ }
+
+ BOOL success = [video_device open:nil];
+
+ // Video capture device not found, looking for QTMediaTypeVideo
+ if (!success) {
+ video_device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
+ success = [video_device open:nil];
+
+ if (!success) {
+ av_log(s, AV_LOG_ERROR, "No QT capture device found\n");
+ goto fail;
+ }
+ }
+
+ NSString* dev_display_name = [video_device localizedDisplayName];
+ av_log (s, AV_LOG_DEBUG, "'%s' opened\n", [dev_display_name UTF8String]);
+
+ // Initialize capture session
+ ctx->capture_session = [[QTCaptureSession alloc] init];
+
+ QTCaptureDeviceInput* capture_dev_input = [[[QTCaptureDeviceInput alloc] initWithDevice:video_device] autorelease];
+ success = [ctx->capture_session addInput:capture_dev_input error:nil];
+
+ if (!success) {
+ av_log (s, AV_LOG_ERROR, "Failed to add QT capture device to session\n");
+ goto fail;
+ }
+
+ // Attaching output
+ // FIXME: Allow for a user defined pixel format
+ ctx->video_output = [[QTCaptureDecompressedVideoOutput alloc] init];
+
+ NSDictionary *captureDictionary = [NSDictionary dictionaryWithObject:
+ [NSNumber numberWithUnsignedInt:kCVPixelFormatType_24RGB]
+ forKey:(id)kCVPixelBufferPixelFormatTypeKey];
+
+ [ctx->video_output setPixelBufferAttributes:captureDictionary];
+
+ ctx->qt_delegate = [[FFMPEG_FrameReceiver alloc] initWithContext:ctx];
+
+ [ctx->video_output setDelegate:ctx->qt_delegate];
+ [ctx->video_output setAutomaticallyDropsLateVideoFrames:YES];
+ [ctx->video_output setMinimumVideoFrameInterval:1.0/ctx->frame_rate];
+
+ success = [ctx->capture_session addOutput:ctx->video_output error:nil];
+
+ if (!success) {
+ av_log (s, AV_LOG_ERROR, "can't add video output to capture session\n");
+ goto fail;
+ }
+
+ [ctx->capture_session startRunning];
+
+ // Take stream info from the first frame.
+ while (ctx->frames_captured < 1) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, YES);
+ }
+
+ lock_frames(ctx);
+
+ AVStream* stream = avformat_new_stream(s, NULL);
+
+ if (!stream) {
+ goto fail;
+ }
+
+ avpriv_set_pts_info(stream, 64, 1, QTKIT_TIMEBASE);
+
+ stream->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ stream->codec->width = (int)CVPixelBufferGetWidth (ctx->current_frame);
+ stream->codec->height = (int)CVPixelBufferGetHeight(ctx->current_frame);
+ stream->codec->pix_fmt = AV_PIX_FMT_RGB24;
+
+ CVBufferRelease(ctx->current_frame);
+ ctx->current_frame = nil;
+
+ unlock_frames(ctx);
+
+ [pool release];
+
+ return 0;
+
+fail:
+ [pool release];
+
+ destroy_context(ctx);
+
+ return AVERROR(EIO);
+}
+
+static int qtkit_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ CaptureContext* ctx = (CaptureContext*)s->priv_data;
+
+ do {
+ lock_frames(ctx);
+
+ if (ctx->current_frame != nil) {
+ if (av_new_packet(pkt, (int)CVPixelBufferGetDataSize(ctx->current_frame)) < 0) {
+ return AVERROR(EIO);
+ }
+
+ pkt->pts = pkt->dts = av_rescale_q(av_gettime() - ctx->first_pts, AV_TIME_BASE_Q, kQTKitTimeBase_q);
+ pkt->stream_index = 0;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ CVPixelBufferLockBaseAddress(ctx->current_frame, 0);
+
+ void* data = CVPixelBufferGetBaseAddress(ctx->current_frame);
+ memcpy(pkt->data, data, pkt->size);
+
+ CVPixelBufferUnlockBaseAddress(ctx->current_frame, 0);
+ CVBufferRelease(ctx->current_frame);
+ ctx->current_frame = nil;
+ } else {
+ pkt->data = NULL;
+ pthread_cond_wait(&ctx->frame_wait_cond, &ctx->frame_lock);
+ }
+
+ unlock_frames(ctx);
+ } while (!pkt->data);
+
+ return 0;
+}
+
+static int qtkit_close(AVFormatContext *s)
+{
+ CaptureContext* ctx = (CaptureContext*)s->priv_data;
+
+ destroy_context(ctx);
+
+ return 0;
+}
+
+static const AVOption options[] = {
+ { "frame_rate", "set frame rate", offsetof(CaptureContext, frame_rate), AV_OPT_TYPE_FLOAT, { .dbl = 30.0 }, 0.1, 30.0, AV_OPT_TYPE_VIDEO_RATE, NULL },
+ { "list_devices", "list available devices", offsetof(CaptureContext, list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" },
+ { "video_device_index", "select video device by index for devices with same name (starts at 0)", offsetof(CaptureContext, video_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass qtkit_class = {
+ .class_name = "QTKit input device",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_qtkit_demuxer = {
+ .name = "qtkit",
+ .long_name = NULL_IF_CONFIG_SMALL("QTKit input device"),
+ .priv_data_size = sizeof(CaptureContext),
+ .read_header = qtkit_read_header,
+ .read_packet = qtkit_read_packet,
+ .read_close = qtkit_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &qtkit_class,
+};
diff --git a/libavdevice/sdl.c b/libavdevice/sdl.c
new file mode 100644
index 0000000000..b98aae5eeb
--- /dev/null
+++ b/libavdevice/sdl.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * libSDL output device
+ */
+
+#include <SDL.h>
+#include <SDL_thread.h>
+
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/time.h"
+#include "avdevice.h"
+
+typedef struct {
+ AVClass *class;
+ SDL_Surface *surface;
+ SDL_Overlay *overlay;
+ char *window_title;
+ char *icon_title;
+ int window_width, window_height; /**< size of the window */
+ int window_fullscreen;
+
+ SDL_Rect overlay_rect;
+ int overlay_fmt;
+
+ int sdl_was_already_inited;
+ SDL_Thread *event_thread;
+ SDL_mutex *mutex;
+ SDL_cond *init_cond;
+ int init_ret; /* return code used to signal initialization errors */
+ int inited;
+ int quit;
+} SDLContext;
+
+static const struct sdl_overlay_pix_fmt_entry {
+ enum AVPixelFormat pix_fmt; int overlay_fmt;
+} sdl_overlay_pix_fmt_map[] = {
+ { AV_PIX_FMT_YUV420P, SDL_IYUV_OVERLAY },
+ { AV_PIX_FMT_YUYV422, SDL_YUY2_OVERLAY },
+ { AV_PIX_FMT_UYVY422, SDL_UYVY_OVERLAY },
+ { AV_PIX_FMT_NONE, 0 },
+};
+
+static int sdl_write_trailer(AVFormatContext *s)
+{
+ SDLContext *sdl = s->priv_data;
+
+ sdl->quit = 1;
+
+ if (sdl->overlay)
+ SDL_FreeYUVOverlay(sdl->overlay);
+ sdl->overlay = NULL;
+ if (sdl->event_thread)
+ SDL_WaitThread(sdl->event_thread, NULL);
+ sdl->event_thread = NULL;
+ if (sdl->mutex)
+ SDL_DestroyMutex(sdl->mutex);
+ sdl->mutex = NULL;
+ if (sdl->init_cond)
+ SDL_DestroyCond(sdl->init_cond);
+ sdl->init_cond = NULL;
+
+ if (!sdl->sdl_was_already_inited)
+ SDL_Quit();
+
+ return 0;
+}
+
+static void compute_overlay_rect(AVFormatContext *s)
+{
+ AVRational sar, dar; /* sample and display aspect ratios */
+ SDLContext *sdl = s->priv_data;
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+ SDL_Rect *overlay_rect = &sdl->overlay_rect;
+
+ /* compute overlay width and height from the codec context information */
+ sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
+ dar = av_mul_q(sar, (AVRational){ encctx->width, encctx->height });
+
+ /* we suppose the screen has a 1/1 sample aspect ratio */
+ if (sdl->window_width && sdl->window_height) {
+ /* fit in the window */
+ if (av_cmp_q(dar, (AVRational){ sdl->window_width, sdl->window_height }) > 0) {
+ /* fit in width */
+ overlay_rect->w = sdl->window_width;
+ overlay_rect->h = av_rescale(overlay_rect->w, dar.den, dar.num);
+ } else {
+ /* fit in height */
+ overlay_rect->h = sdl->window_height;
+ overlay_rect->w = av_rescale(overlay_rect->h, dar.num, dar.den);
+ }
+ } else {
+ if (sar.num > sar.den) {
+ overlay_rect->w = encctx->width;
+ overlay_rect->h = av_rescale(overlay_rect->w, dar.den, dar.num);
+ } else {
+ overlay_rect->h = encctx->height;
+ overlay_rect->w = av_rescale(overlay_rect->h, dar.num, dar.den);
+ }
+ sdl->window_width = overlay_rect->w;
+ sdl->window_height = overlay_rect->h;
+ }
+
+ overlay_rect->x = (sdl->window_width - overlay_rect->w) / 2;
+ overlay_rect->y = (sdl->window_height - overlay_rect->h) / 2;
+}
+
+#define SDL_BASE_FLAGS (SDL_SWSURFACE|SDL_RESIZABLE)
+
+static int event_thread(void *arg)
+{
+ AVFormatContext *s = arg;
+ SDLContext *sdl = s->priv_data;
+ int flags = SDL_BASE_FLAGS | (sdl->window_fullscreen ? SDL_FULLSCREEN : 0);
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+
+ /* initialization */
+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to initialize SDL: %s\n", SDL_GetError());
+ sdl->init_ret = AVERROR(EINVAL);
+ goto init_end;
+ }
+
+ SDL_WM_SetCaption(sdl->window_title, sdl->icon_title);
+ sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height,
+ 24, flags);
+ if (!sdl->surface) {
+ av_log(sdl, AV_LOG_ERROR, "Unable to set video mode: %s\n", SDL_GetError());
+ sdl->init_ret = AVERROR(EINVAL);
+ goto init_end;
+ }
+
+ sdl->overlay = SDL_CreateYUVOverlay(encctx->width, encctx->height,
+ sdl->overlay_fmt, sdl->surface);
+ if (!sdl->overlay || sdl->overlay->pitches[0] < encctx->width) {
+ av_log(s, AV_LOG_ERROR,
+ "SDL does not support an overlay with size of %dx%d pixels\n",
+ encctx->width, encctx->height);
+ sdl->init_ret = AVERROR(EINVAL);
+ goto init_end;
+ }
+
+ sdl->init_ret = 0;
+ av_log(s, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d\n",
+ encctx->width, encctx->height, av_get_pix_fmt_name(encctx->pix_fmt),
+ sdl->overlay_rect.w, sdl->overlay_rect.h);
+
+init_end:
+ SDL_LockMutex(sdl->mutex);
+ sdl->inited = 1;
+ SDL_UnlockMutex(sdl->mutex);
+ SDL_CondSignal(sdl->init_cond);
+
+ if (sdl->init_ret < 0)
+ return sdl->init_ret;
+
+ /* event loop */
+ while (!sdl->quit) {
+ int ret;
+ SDL_Event event;
+ SDL_PumpEvents();
+ ret = SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Error when getting SDL event: %s\n", SDL_GetError());
+ continue;
+ }
+ if (ret == 0) {
+ SDL_Delay(10);
+ continue;
+ }
+
+ switch (event.type) {
+ case SDL_KEYDOWN:
+ switch (event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ case SDLK_q:
+ sdl->quit = 1;
+ break;
+ }
+ break;
+ case SDL_QUIT:
+ sdl->quit = 1;
+ break;
+
+ case SDL_VIDEORESIZE:
+ sdl->window_width = event.resize.w;
+ sdl->window_height = event.resize.h;
+
+ SDL_LockMutex(sdl->mutex);
+ sdl->surface = SDL_SetVideoMode(sdl->window_width, sdl->window_height, 24, SDL_BASE_FLAGS);
+ if (!sdl->surface) {
+ av_log(s, AV_LOG_ERROR, "Failed to set SDL video mode: %s\n", SDL_GetError());
+ sdl->quit = 1;
+ } else {
+ compute_overlay_rect(s);
+ }
+ SDL_UnlockMutex(sdl->mutex);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int sdl_write_header(AVFormatContext *s)
+{
+ SDLContext *sdl = s->priv_data;
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+ int i, ret;
+
+ if (!sdl->window_title)
+ sdl->window_title = av_strdup(s->filename);
+ if (!sdl->icon_title)
+ sdl->icon_title = av_strdup(sdl->window_title);
+
+ if (SDL_WasInit(SDL_INIT_VIDEO)) {
+ av_log(s, AV_LOG_ERROR,
+ "SDL video subsystem was already inited, aborting\n");
+ sdl->sdl_was_already_inited = 1;
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ if ( s->nb_streams > 1
+ || encctx->codec_type != AVMEDIA_TYPE_VIDEO
+ || encctx->codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ for (i = 0; sdl_overlay_pix_fmt_map[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
+ if (sdl_overlay_pix_fmt_map[i].pix_fmt == encctx->pix_fmt) {
+ sdl->overlay_fmt = sdl_overlay_pix_fmt_map[i].overlay_fmt;
+ break;
+ }
+ }
+
+ if (!sdl->overlay_fmt) {
+ av_log(s, AV_LOG_ERROR,
+ "Unsupported pixel format '%s', choose one of yuv420p, yuyv422, or uyvy422\n",
+ av_get_pix_fmt_name(encctx->pix_fmt));
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ /* compute overlay width and height from the codec context information */
+ compute_overlay_rect(s);
+
+ sdl->init_cond = SDL_CreateCond();
+ if (!sdl->init_cond) {
+ av_log(s, AV_LOG_ERROR, "Could not create SDL condition variable: %s\n", SDL_GetError());
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ sdl->mutex = SDL_CreateMutex();
+ if (!sdl->mutex) {
+ av_log(s, AV_LOG_ERROR, "Could not create SDL mutex: %s\n", SDL_GetError());
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ sdl->event_thread = SDL_CreateThread(event_thread, s);
+ if (!sdl->event_thread) {
+ av_log(s, AV_LOG_ERROR, "Could not create SDL event thread: %s\n", SDL_GetError());
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ /* wait until the video system has been inited */
+ SDL_LockMutex(sdl->mutex);
+ while (!sdl->inited) {
+ SDL_CondWait(sdl->init_cond, sdl->mutex);
+ }
+ SDL_UnlockMutex(sdl->mutex);
+ if (sdl->init_ret < 0) {
+ ret = sdl->init_ret;
+ goto fail;
+ }
+ return 0;
+
+fail:
+ sdl_write_trailer(s);
+ return ret;
+}
+
+static int sdl_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ SDLContext *sdl = s->priv_data;
+ AVCodecContext *encctx = s->streams[0]->codec;
+ AVPicture pict;
+ int i;
+
+ if (sdl->quit) {
+ sdl_write_trailer(s);
+ return AVERROR(EIO);
+ }
+ avpicture_fill(&pict, pkt->data, encctx->pix_fmt, encctx->width, encctx->height);
+
+ SDL_LockMutex(sdl->mutex);
+ SDL_FillRect(sdl->surface, &sdl->surface->clip_rect,
+ SDL_MapRGB(sdl->surface->format, 0, 0, 0));
+ SDL_LockYUVOverlay(sdl->overlay);
+ for (i = 0; i < 3; i++) {
+ sdl->overlay->pixels [i] = pict.data [i];
+ sdl->overlay->pitches[i] = pict.linesize[i];
+ }
+ SDL_DisplayYUVOverlay(sdl->overlay, &sdl->overlay_rect);
+ SDL_UnlockYUVOverlay(sdl->overlay);
+
+ SDL_UpdateRect(sdl->surface,
+ sdl->overlay_rect.x, sdl->overlay_rect.y,
+ sdl->overlay_rect.w, sdl->overlay_rect.h);
+ SDL_UnlockMutex(sdl->mutex);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(SDLContext,x)
+
+static const AVOption options[] = {
+ { "window_title", "set SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "icon_title", "set SDL iconified window title", OFFSET(icon_title) , AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_size", "set SDL window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_fullscreen", "set SDL window fullscreen", OFFSET(window_fullscreen), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+static const AVClass sdl_class = {
+ .class_name = "sdl outdev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_sdl_muxer = {
+ .name = "sdl",
+ .long_name = NULL_IF_CONFIG_SMALL("SDL output device"),
+ .priv_data_size = sizeof(SDLContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = sdl_write_header,
+ .write_packet = sdl_write_packet,
+ .write_trailer = sdl_write_trailer,
+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
+ .priv_class = &sdl_class,
+};
diff --git a/libavdevice/sndio.c b/libavdevice/sndio.c
index 739551b841..46f287588d 100644
--- a/libavdevice/sndio.c
+++ b/libavdevice/sndio.c
@@ -2,27 +2,27 @@
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <sndio.h>
-#include "libavformat/avformat.h"
+#include "avdevice.h"
#include "libavdevice/sndio.h"
diff --git a/libavdevice/sndio.h b/libavdevice/sndio.h
index cd5c55ecc5..54a5ec3353 100644
--- a/libavdevice/sndio.h
+++ b/libavdevice/sndio.h
@@ -2,20 +2,20 @@
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,8 +25,8 @@
#include <stdint.h>
#include <sndio.h>
-#include "libavformat/avformat.h"
#include "libavutil/log.h"
+#include "avdevice.h"
typedef struct SndioData {
AVClass *class;
diff --git a/libavdevice/sndio_dec.c b/libavdevice/sndio_dec.c
index 7ebb8c3ccc..f815b377fb 100644
--- a/libavdevice/sndio_dec.c
+++ b/libavdevice/sndio_dec.c
@@ -2,20 +2,20 @@
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -106,6 +106,7 @@ static const AVClass sndio_demuxer_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
};
AVInputFormat ff_sndio_demuxer = {
diff --git a/libavdevice/sndio_enc.c b/libavdevice/sndio_enc.c
index fad361062b..52b9060ef6 100644
--- a/libavdevice/sndio_enc.c
+++ b/libavdevice/sndio_enc.c
@@ -2,20 +2,20 @@
* sndio play and grab interface
* Copyright (c) 2010 Jacob Meuser
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,8 +24,8 @@
#include "libavutil/internal.h"
-#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
#include "libavdevice/sndio.h"
static av_cold int audio_write_header(AVFormatContext *s1)
@@ -79,6 +79,13 @@ static int audio_write_trailer(AVFormatContext *s1)
return 0;
}
+static const AVClass sndio_muxer_class = {
+ .class_name = "sndio outdev",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+};
+
AVOutputFormat ff_sndio_muxer = {
.name = "sndio",
.long_name = NULL_IF_CONFIG_SMALL("sndio audio playback"),
@@ -92,4 +99,5 @@ AVOutputFormat ff_sndio_muxer = {
.write_packet = audio_write_packet,
.write_trailer = audio_write_trailer,
.flags = AVFMT_NOFILE,
+ .priv_class = &sndio_muxer_class,
};
diff --git a/libavdevice/timefilter.c b/libavdevice/timefilter.c
index a49735158c..9d38f93b96 100644
--- a/libavdevice/timefilter.c
+++ b/libavdevice/timefilter.c
@@ -5,20 +5,20 @@
* Author: Olivier Guilyardi <olivier samalyse com>
* Michael Niedermayer <michaelni gmx at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,18 +37,25 @@ struct TimeFilter {
int count;
};
-TimeFilter *ff_timefilter_new(double clock_period,
- double feedback2_factor,
- double feedback3_factor)
+/* 1 - exp(-x) using a 3-order power series */
+static double qexpneg(double x)
{
- TimeFilter *self = av_mallocz(sizeof(TimeFilter));
+ return 1 - 1 / (1 + x * (1 + x / 2 * (1 + x / 3)));
+}
+
+TimeFilter *ff_timefilter_new(double time_base,
+ double period,
+ double bandwidth)
+{
+ TimeFilter *self = av_mallocz(sizeof(TimeFilter));
+ double o = 2 * M_PI * bandwidth * period * time_base;
if (!self)
return NULL;
- self->clock_period = clock_period;
- self->feedback2_factor = feedback2_factor;
- self->feedback3_factor = feedback3_factor;
+ self->clock_period = time_base;
+ self->feedback2_factor = qexpneg(M_SQRT2 * o);
+ self->feedback3_factor = qexpneg(o * o) / period;
return self;
}
@@ -73,11 +80,16 @@ double ff_timefilter_update(TimeFilter *self, double system_time, double period)
loop_error = system_time - self->cycle_time;
self->cycle_time += FFMAX(self->feedback2_factor, 1.0 / self->count) * loop_error;
- self->clock_period += self->feedback3_factor * loop_error / period;
+ self->clock_period += self->feedback3_factor * loop_error;
}
return self->cycle_time;
}
+double ff_timefilter_eval(TimeFilter *self, double delta)
+{
+ return self->cycle_time + self->clock_period * delta;
+}
+
#ifdef TEST
#include "libavutil/lfg.h"
#define LFG_MAX ((1LL << 32) - 1)
@@ -89,17 +101,21 @@ int main(void)
#define SAMPLES 1000
double ideal[SAMPLES];
double samples[SAMPLES];
+ double samplet[SAMPLES];
for (n0 = 0; n0 < 40; n0 = 2 * n0 + 1) {
for (n1 = 0; n1 < 10; n1 = 2 * n1 + 1) {
double best_error = 1000000000;
- double bestpar0 = 1;
- double bestpar1 = 0.001;
+ double bestpar0 = n0 ? 1 : 100000;
+ double bestpar1 = 1;
int better, i;
av_lfg_init(&prng, 123);
for (i = 0; i < SAMPLES; i++) {
- ideal[i] = 10 + i + n1 * i / (1000);
+ samplet[i] = 10 + i + (av_lfg_get(&prng) < LFG_MAX/2 ? 0 : 0.999);
+ ideal[i] = samplet[i] + n1 * i / (1000);
samples[i] = ideal[i] + n0 * (av_lfg_get(&prng) - LFG_MAX / 2) / (LFG_MAX * 10LL);
+ if(i && samples[i]<samples[i-1])
+ samples[i]=samples[i-1]+0.001;
}
do {
@@ -115,7 +131,9 @@ int main(void)
}
for (i = 0; i < SAMPLES; i++) {
double filtered;
- filtered = ff_timefilter_update(tf, samples[i], 1);
+ filtered = ff_timefilter_update(tf, samples[i], i ? (samplet[i] - samplet[i-1]) : 1);
+ if(filtered < 0 || filtered > 1000000000)
+ printf("filter is unstable\n");
error += (filtered - ideal[i]) * (filtered - ideal[i]);
}
ff_timefilter_destroy(tf);
@@ -140,7 +158,7 @@ int main(void)
}
ff_timefilter_destroy(tf);
#else
- printf(" [%f %f %9f]", bestpar0, bestpar1, best_error);
+ printf(" [%12f %11f %9f]", bestpar0, bestpar1, best_error);
#endif
}
printf("\n");
diff --git a/libavdevice/timefilter.h b/libavdevice/timefilter.h
index 2235db60e3..cb3d0a788f 100644
--- a/libavdevice/timefilter.h
+++ b/libavdevice/timefilter.h
@@ -5,20 +5,20 @@
* Author: Olivier Guilyardi <olivier samalyse com>
* Michael Niedermayer <michaelni gmx at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,16 +45,18 @@ typedef struct TimeFilter TimeFilter;
*
* Unless you know what you are doing, you should set these as follow:
*
- * o = 2 * M_PI * bandwidth * period
- * feedback2_factor = sqrt(2 * o)
+ * o = 2 * M_PI * bandwidth * period_in_seconds
+ * feedback2_factor = sqrt(2) * o
* feedback3_factor = o * o
*
* Where bandwidth is up to you to choose. Smaller values will filter out more
* of the jitter, but also take a longer time for the loop to settle. A good
* starting point is something between 0.3 and 3 Hz.
*
- * @param clock_period period of the hardware clock in seconds
- * (for example 1.0/44100)
+ * @param time_base period of the hardware clock in seconds
+ * (for example 1.0/44100)
+ * @param period expected update interval, in input units
+ * @param brandwidth filtering bandwidth, in Hz
*
* @return a pointer to a TimeFilter struct, or NULL on error
*
@@ -82,6 +84,15 @@ TimeFilter * ff_timefilter_new(double clock_period, double feedback2_factor, dou
double ff_timefilter_update(TimeFilter *self, double system_time, double period);
/**
+ * Evaluate the filter at a specified time
+ *
+ * @param delta difference between the requested time and the current time
+ * (last call to ff_timefilter_update).
+ * @return the filtered time
+ */
+double ff_timefilter_eval(TimeFilter *self, double delta);
+
+/**
* Reset the filter
*
* This function should mainly be called in case of XRUN.
diff --git a/libavdevice/utils.c b/libavdevice/utils.c
new file mode 100644
index 0000000000..ccd7318012
--- /dev/null
+++ b/libavdevice/utils.c
@@ -0,0 +1,59 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "internal.h"
+#include "libavutil/opt.h"
+#include "libavformat/avformat.h"
+
+int ff_alloc_input_device_context(AVFormatContext **avctx, AVInputFormat *iformat, const char *format)
+{
+ AVFormatContext *s;
+ int ret = 0;
+
+ *avctx = NULL;
+ if (!iformat && !format)
+ return AVERROR(EINVAL);
+ if (!(s = avformat_alloc_context()))
+ return AVERROR(ENOMEM);
+
+ if (!iformat)
+ iformat = av_find_input_format(format);
+ if (!iformat || !iformat->priv_class || !AV_IS_INPUT_DEVICE(iformat->priv_class->category)) {
+ ret = AVERROR(EINVAL);
+ goto error;
+ }
+ s->iformat = iformat;
+ if (s->iformat->priv_data_size > 0) {
+ s->priv_data = av_mallocz(s->iformat->priv_data_size);
+ if (!s->priv_data) {
+ ret = AVERROR(ENOMEM);
+ goto error;
+ }
+ if (s->iformat->priv_class) {
+ *(const AVClass**)s->priv_data= s->iformat->priv_class;
+ av_opt_set_defaults(s->priv_data);
+ }
+ } else
+ s->priv_data = NULL;
+
+ *avctx = s;
+ return 0;
+ error:
+ avformat_free_context(s);
+ return ret;
+}
diff --git a/libavdevice/v4l.c b/libavdevice/v4l.c
new file mode 100644
index 0000000000..d33f7142a0
--- /dev/null
+++ b/libavdevice/v4l.c
@@ -0,0 +1,363 @@
+/*
+ * Linux video grab interface
+ * Copyright (c) 2000,2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avdevice.h"
+
+#undef __STRICT_ANSI__ //workaround due to broken kernel headers
+#include "config.h"
+#include "libavutil/rational.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavformat/internal.h"
+#include "libavcodec/dsputil.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#define _LINUX_TIME_H 1
+#include <linux/videodev.h>
+#include <time.h>
+
+typedef struct {
+ AVClass *class;
+ int fd;
+ int frame_format; /* see VIDEO_PALETTE_xxx */
+ int use_mmap;
+ AVRational time_base;
+ int64_t time_frame;
+ int frame_size;
+ struct video_capability video_cap;
+ struct video_audio audio_saved;
+ struct video_window video_win;
+ uint8_t *video_buf;
+ struct video_mbuf gb_buffers;
+ struct video_mmap gb_buf;
+ int gb_frame;
+ int standard;
+} VideoData;
+
+static const struct {
+ int palette;
+ int depth;
+ enum AVPixelFormat pix_fmt;
+} video_formats [] = {
+ {.palette = VIDEO_PALETTE_YUV420P, .depth = 12, .pix_fmt = AV_PIX_FMT_YUV420P },
+ {.palette = VIDEO_PALETTE_YUV422, .depth = 16, .pix_fmt = AV_PIX_FMT_YUYV422 },
+ {.palette = VIDEO_PALETTE_UYVY, .depth = 16, .pix_fmt = AV_PIX_FMT_UYVY422 },
+ {.palette = VIDEO_PALETTE_YUYV, .depth = 16, .pix_fmt = AV_PIX_FMT_YUYV422 },
+ /* NOTE: v4l uses BGR24, not RGB24 */
+ {.palette = VIDEO_PALETTE_RGB24, .depth = 24, .pix_fmt = AV_PIX_FMT_BGR24 },
+ {.palette = VIDEO_PALETTE_RGB565, .depth = 16, .pix_fmt = AV_PIX_FMT_BGR565 },
+ {.palette = VIDEO_PALETTE_GREY, .depth = 8, .pix_fmt = AV_PIX_FMT_GRAY8 },
+};
+
+
+static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
+{
+ VideoData *s = s1->priv_data;
+ AVStream *st;
+ int video_fd;
+ int desired_palette, desired_depth;
+ struct video_tuner tuner;
+ struct video_audio audio;
+ struct video_picture pict;
+ int j;
+ int vformat_num = FF_ARRAY_ELEMS(video_formats);
+
+ av_log(s1, AV_LOG_WARNING, "V4L input device is deprecated and will be removed in the next release.");
+
+ if (ap->time_base.den <= 0) {
+ av_log(s1, AV_LOG_ERROR, "Wrong time base (%d)\n", ap->time_base.den);
+ return -1;
+ }
+ s->time_base = ap->time_base;
+
+ s->video_win.width = ap->width;
+ s->video_win.height = ap->height;
+
+ st = avformat_new_stream(s1, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
+ video_fd = open(s1->filename, O_RDWR);
+ if (video_fd < 0) {
+ av_log(s1, AV_LOG_ERROR, "%s: %s\n", s1->filename, strerror(errno));
+ goto fail;
+ }
+
+ if (ioctl(video_fd, VIDIOCGCAP, &s->video_cap) < 0) {
+ av_log(s1, AV_LOG_ERROR, "VIDIOCGCAP: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ if (!(s->video_cap.type & VID_TYPE_CAPTURE)) {
+ av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not handle capture\n");
+ goto fail;
+ }
+
+ /* no values set, autodetect them */
+ if (s->video_win.width <= 0 || s->video_win.height <= 0) {
+ if (ioctl(video_fd, VIDIOCGWIN, &s->video_win, sizeof(s->video_win)) < 0) {
+ av_log(s1, AV_LOG_ERROR, "VIDIOCGWIN: %s\n", strerror(errno));
+ goto fail;
+ }
+ }
+
+ if(av_image_check_size(s->video_win.width, s->video_win.height, 0, s1) < 0)
+ return -1;
+
+ desired_palette = -1;
+ desired_depth = -1;
+ for (j = 0; j < vformat_num; j++) {
+ if (ap->pix_fmt == video_formats[j].pix_fmt) {
+ desired_palette = video_formats[j].palette;
+ desired_depth = video_formats[j].depth;
+ break;
+ }
+ }
+
+ /* set tv standard */
+ if (!ioctl(video_fd, VIDIOCGTUNER, &tuner)) {
+ tuner.mode = s->standard;
+ ioctl(video_fd, VIDIOCSTUNER, &tuner);
+ }
+
+ /* unmute audio */
+ audio.audio = 0;
+ ioctl(video_fd, VIDIOCGAUDIO, &audio);
+ memcpy(&s->audio_saved, &audio, sizeof(audio));
+ audio.flags &= ~VIDEO_AUDIO_MUTE;
+ ioctl(video_fd, VIDIOCSAUDIO, &audio);
+
+ ioctl(video_fd, VIDIOCGPICT, &pict);
+ av_dlog(s1, "v4l: colour=%d hue=%d brightness=%d constrast=%d whiteness=%d\n",
+ pict.colour, pict.hue, pict.brightness, pict.contrast, pict.whiteness);
+ /* try to choose a suitable video format */
+ pict.palette = desired_palette;
+ pict.depth= desired_depth;
+ if (desired_palette == -1 || ioctl(video_fd, VIDIOCSPICT, &pict) < 0) {
+ for (j = 0; j < vformat_num; j++) {
+ pict.palette = video_formats[j].palette;
+ pict.depth = video_formats[j].depth;
+ if (-1 != ioctl(video_fd, VIDIOCSPICT, &pict))
+ break;
+ }
+ if (j >= vformat_num)
+ goto fail1;
+ }
+
+ if (ioctl(video_fd, VIDIOCGMBUF, &s->gb_buffers) < 0) {
+ /* try to use read based access */
+ int val;
+
+ s->video_win.x = 0;
+ s->video_win.y = 0;
+ s->video_win.chromakey = -1;
+ s->video_win.flags = 0;
+
+ if (ioctl(video_fd, VIDIOCSWIN, s->video_win) < 0) {
+ av_log(s1, AV_LOG_ERROR, "VIDIOCSWIN: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ s->frame_format = pict.palette;
+
+ val = 1;
+ if (ioctl(video_fd, VIDIOCCAPTURE, &val) < 0) {
+ av_log(s1, AV_LOG_ERROR, "VIDIOCCAPTURE: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ s->time_frame = av_gettime() * s->time_base.den / s->time_base.num;
+ s->use_mmap = 0;
+ } else {
+ s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, 0);
+ if ((unsigned char*)-1 == s->video_buf) {
+ s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_PRIVATE, video_fd, 0);
+ if ((unsigned char*)-1 == s->video_buf) {
+ av_log(s1, AV_LOG_ERROR, "mmap: %s\n", strerror(errno));
+ goto fail;
+ }
+ }
+ s->gb_frame = 0;
+ s->time_frame = av_gettime() * s->time_base.den / s->time_base.num;
+
+ /* start to grab the first frame */
+ s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames;
+ s->gb_buf.height = s->video_win.height;
+ s->gb_buf.width = s->video_win.width;
+ s->gb_buf.format = pict.palette;
+
+ if (ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) {
+ if (errno != EAGAIN) {
+ fail1:
+ av_log(s1, AV_LOG_ERROR, "VIDIOCMCAPTURE: %s\n", strerror(errno));
+ } else {
+ av_log(s1, AV_LOG_ERROR, "Fatal: grab device does not receive any video signal\n");
+ }
+ goto fail;
+ }
+ for (j = 1; j < s->gb_buffers.frames; j++) {
+ s->gb_buf.frame = j;
+ ioctl(video_fd, VIDIOCMCAPTURE, &s->gb_buf);
+ }
+ s->frame_format = s->gb_buf.format;
+ s->use_mmap = 1;
+ }
+
+ for (j = 0; j < vformat_num; j++) {
+ if (s->frame_format == video_formats[j].palette) {
+ s->frame_size = s->video_win.width * s->video_win.height * video_formats[j].depth / 8;
+ st->codec->pix_fmt = video_formats[j].pix_fmt;
+ break;
+ }
+ }
+
+ if (j >= vformat_num)
+ goto fail;
+
+ s->fd = video_fd;
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->width = s->video_win.width;
+ st->codec->height = s->video_win.height;
+ st->codec->time_base = s->time_base;
+ st->codec->bit_rate = s->frame_size * 1/av_q2d(st->codec->time_base) * 8;
+
+ return 0;
+ fail:
+ if (video_fd >= 0)
+ close(video_fd);
+ return AVERROR(EIO);
+}
+
+static int v4l_mm_read_picture(VideoData *s, uint8_t *buf)
+{
+ uint8_t *ptr;
+
+ while (ioctl(s->fd, VIDIOCSYNC, &s->gb_frame) < 0 &&
+ (errno == EAGAIN || errno == EINTR));
+
+ ptr = s->video_buf + s->gb_buffers.offsets[s->gb_frame];
+ memcpy(buf, ptr, s->frame_size);
+
+ /* Setup to capture the next frame */
+ s->gb_buf.frame = s->gb_frame;
+ if (ioctl(s->fd, VIDIOCMCAPTURE, &s->gb_buf) < 0) {
+ if (errno == EAGAIN)
+ av_log(NULL, AV_LOG_ERROR, "Cannot Sync\n");
+ else
+ av_log(NULL, AV_LOG_ERROR, "VIDIOCMCAPTURE: %s\n", strerror(errno));
+ return AVERROR(EIO);
+ }
+
+ /* This is now the grabbing frame */
+ s->gb_frame = (s->gb_frame + 1) % s->gb_buffers.frames;
+
+ return s->frame_size;
+}
+
+static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
+{
+ VideoData *s = s1->priv_data;
+ int64_t curtime, delay;
+ struct timespec ts;
+
+ /* Calculate the time of the next frame */
+ s->time_frame += INT64_C(1000000);
+
+ /* wait based on the frame rate */
+ for(;;) {
+ curtime = av_gettime();
+ delay = s->time_frame * s->time_base.num / s->time_base.den - curtime;
+ if (delay <= 0) {
+ if (delay < INT64_C(-1000000) * s->time_base.num / s->time_base.den) {
+ /* printf("grabbing is %d frames late (dropping)\n", (int) -(delay / 16666)); */
+ s->time_frame += INT64_C(1000000);
+ }
+ break;
+ }
+ ts.tv_sec = delay / 1000000;
+ ts.tv_nsec = (delay % 1000000) * 1000;
+ nanosleep(&ts, NULL);
+ }
+
+ if (av_new_packet(pkt, s->frame_size) < 0)
+ return AVERROR(EIO);
+
+ pkt->pts = curtime;
+
+ /* read one frame */
+ if (s->use_mmap) {
+ return v4l_mm_read_picture(s, pkt->data);
+ } else {
+ if (read(s->fd, pkt->data, pkt->size) != pkt->size)
+ return AVERROR(EIO);
+ return s->frame_size;
+ }
+}
+
+static int grab_read_close(AVFormatContext *s1)
+{
+ VideoData *s = s1->priv_data;
+
+ if (s->use_mmap)
+ munmap(s->video_buf, s->gb_buffers.size);
+
+ /* mute audio. we must force it because the BTTV driver does not
+ return its state correctly */
+ s->audio_saved.flags |= VIDEO_AUDIO_MUTE;
+ ioctl(s->fd, VIDIOCSAUDIO, &s->audio_saved);
+
+ close(s->fd);
+ return 0;
+}
+
+static const AVOption options[] = {
+ { "standard", "", offsetof(VideoData, standard), AV_OPT_TYPE_INT, {.i64 = VIDEO_MODE_NTSC}, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, AV_OPT_FLAG_DECODING_PARAM, "standard" },
+ { "PAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_MODE_PAL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" },
+ { "SECAM", "", 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_MODE_SECAM}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" },
+ { "NTSC", "", 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_MODE_NTSC}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "standard" },
+ { NULL },
+};
+
+static const AVClass v4l_class = {
+ .class_name = "V4L indev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+};
+
+AVInputFormat ff_v4l_demuxer = {
+ .name = "video4linux,v4l",
+ .long_name = NULL_IF_CONFIG_SMALL("Video4Linux device grab"),
+ .priv_data_size = sizeof(VideoData),
+ .read_header = grab_read_header,
+ .read_packet = grab_read_packet,
+ .read_close = grab_read_close,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &v4l_class,
+};
diff --git a/libavdevice/v4l2-common.c b/libavdevice/v4l2-common.c
new file mode 100644
index 0000000000..196c09b7fc
--- /dev/null
+++ b/libavdevice/v4l2-common.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 Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "v4l2-common.h"
+
+const struct fmt_map ff_fmt_conversion_table[] = {
+ //ff_fmt codec_id v4l2_fmt
+ { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420 },
+ { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU420 },
+ { AV_PIX_FMT_YUV422P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV422P },
+ { AV_PIX_FMT_YUYV422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUYV },
+ { AV_PIX_FMT_UYVY422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_UYVY },
+ { AV_PIX_FMT_YUV411P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV411P },
+ { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV410 },
+ { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU410 },
+ { AV_PIX_FMT_RGB555LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555 },
+ { AV_PIX_FMT_RGB555BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555X },
+ { AV_PIX_FMT_RGB565LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565 },
+ { AV_PIX_FMT_RGB565BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565X },
+ { AV_PIX_FMT_BGR24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR24 },
+ { AV_PIX_FMT_RGB24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB24 },
+ { AV_PIX_FMT_BGR0, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32 },
+ { AV_PIX_FMT_0RGB, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB32 },
+ { AV_PIX_FMT_GRAY8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_GREY },
+#ifdef V4L2_PIX_FMT_Y16
+ { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Y16 },
+#endif
+ { AV_PIX_FMT_NV12, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12 },
+ { 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
+ { AV_PIX_FMT_NONE, AV_CODEC_ID_H264, V4L2_PIX_FMT_H264 },
+#endif
+#ifdef V4L2_PIX_FMT_MPEG4
+ { AV_PIX_FMT_NONE, AV_CODEC_ID_MPEG4, V4L2_PIX_FMT_MPEG4 },
+#endif
+#ifdef V4L2_PIX_FMT_CPIA1
+ { AV_PIX_FMT_NONE, AV_CODEC_ID_CPIA, V4L2_PIX_FMT_CPIA1 },
+#endif
+#ifdef V4L2_PIX_FMT_SRGGB8
+ { AV_PIX_FMT_BAYER_BGGR8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SBGGR8 },
+ { AV_PIX_FMT_BAYER_GBRG8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SGBRG8 },
+ { AV_PIX_FMT_BAYER_GRBG8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SGRBG8 },
+ { AV_PIX_FMT_BAYER_RGGB8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SRGGB8 },
+#endif
+ { AV_PIX_FMT_NONE, AV_CODEC_ID_NONE, 0 },
+};
+
+uint32_t ff_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id)
+{
+ int i;
+
+ for (i = 0; ff_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if ((codec_id == AV_CODEC_ID_NONE ||
+ ff_fmt_conversion_table[i].codec_id == codec_id) &&
+ (pix_fmt == AV_PIX_FMT_NONE ||
+ ff_fmt_conversion_table[i].ff_fmt == pix_fmt)) {
+ return ff_fmt_conversion_table[i].v4l2_fmt;
+ }
+ }
+
+ return 0;
+}
+
+enum AVPixelFormat ff_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id)
+{
+ int i;
+
+ for (i = 0; ff_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if (ff_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt &&
+ ff_fmt_conversion_table[i].codec_id == codec_id) {
+ return ff_fmt_conversion_table[i].ff_fmt;
+ }
+ }
+
+ return AV_PIX_FMT_NONE;
+}
+
+enum AVCodecID ff_fmt_v4l2codec(uint32_t v4l2_fmt)
+{
+ int i;
+
+ for (i = 0; ff_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if (ff_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt) {
+ return ff_fmt_conversion_table[i].codec_id;
+ }
+ }
+
+ return AV_CODEC_ID_NONE;
+}
diff --git a/libavdevice/v4l2-common.h b/libavdevice/v4l2-common.h
new file mode 100644
index 0000000000..40c716489f
--- /dev/null
+++ b/libavdevice/v4l2-common.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVDEVICE_V4L2_COMMON_H
+#define AVDEVICE_V4L2_COMMON_H
+
+#undef __STRICT_ANSI__ //workaround due to broken kernel headers
+#include "config.h"
+#include "libavformat/internal.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#if HAVE_SYS_VIDEOIO_H
+#include <sys/videoio.h>
+#else
+#if HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+#include <linux/videodev2.h>
+#endif
+#include "libavutil/atomic.h"
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "avdevice.h"
+#include "timefilter.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/time.h"
+#include "libavutil/avstring.h"
+
+struct fmt_map {
+ enum AVPixelFormat ff_fmt;
+ enum AVCodecID codec_id;
+ uint32_t v4l2_fmt;
+};
+
+extern const struct fmt_map ff_fmt_conversion_table[];
+
+uint32_t ff_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id);
+enum AVPixelFormat ff_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id);
+enum AVCodecID ff_fmt_v4l2codec(uint32_t v4l2_fmt);
+
+#endif /* AVDEVICE_V4L2_COMMON_H */
diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index 3631c1f240..64ac09c1c7 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -1,57 +1,41 @@
/*
- * Video4Linux2 grab interface
* Copyright (c) 2000,2001 Fabrice Bellard
* Copyright (c) 2006 Luca Abeni
*
- * Part of this file is based on the V4L2 video capture example
- * (http://v4l2spec.bytesex.org/v4l2spec/capture.c)
- *
- * Thanks to Michael Niedermayer for providing the mapping between
- * V4L2_PIX_FMT_* and AV_PIX_FMT_*
+ * This file is part of FFmpeg.
*
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#undef __STRICT_ANSI__ //workaround due to broken kernel headers
-#include "config.h"
-#include "libavformat/avformat.h"
-#include "libavformat/internal.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <poll.h>
-#if HAVE_SYS_VIDEOIO_H
-#include <sys/videoio.h>
-#else
-#include <linux/videodev2.h>
+/**
+ * @file
+ * Video4Linux2 grab interface
+ *
+ * Part of this file is based on the V4L2 video capture example
+ * (http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html)
+ *
+ * Thanks to Michael Niedermayer for providing the mapping between
+ * V4L2_PIX_FMT_* and AV_PIX_FMT_*
+ */
+
+#include "v4l2-common.h"
+#include <dirent.h>
+
+#if CONFIG_LIBV4L2
+#include <libv4l2.h>
#endif
-#include "libavutil/atomic.h"
-#include "libavutil/avassert.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/internal.h"
-#include "libavutil/log.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/avstring.h"
-#include "libavutil/mathematics.h"
static const int desired_video_buffers = 256;
@@ -59,103 +43,129 @@ static const int desired_video_buffers = 256;
#define V4L_RAWFORMATS 1
#define V4L_COMPFORMATS 2
+/**
+ * Return timestamps to the user exactly as returned by the kernel
+ */
+#define V4L_TS_DEFAULT 0
+/**
+ * Autodetect the kind of timestamps returned by the kernel and convert to
+ * absolute (wall clock) timestamps.
+ */
+#define V4L_TS_ABS 1
+/**
+ * Assume kernel timestamps are from the monotonic clock and convert to
+ * absolute timestamps.
+ */
+#define V4L_TS_MONO2ABS 2
+
+/**
+ * Once the kind of timestamps returned by the kernel have been detected,
+ * the value of the timefilter (NULL or not) determines whether a conversion
+ * takes place.
+ */
+#define V4L_TS_CONVERT_READY V4L_TS_DEFAULT
+
struct video_data {
AVClass *class;
int fd;
- int frame_format; /* V4L2_PIX_FMT_* */
+ int pixelformat; /* V4L2_PIX_FMT_* */
int width, height;
int frame_size;
- int timeout;
int interlaced;
int top_field_first;
+ int ts_mode;
+ TimeFilter *timefilter;
+ int64_t last_time_m;
int buffers;
volatile int buffers_queued;
void **buf_start;
unsigned int *buf_len;
char *standard;
+ v4l2_std_id std_id;
int channel;
- char *video_size; /**< String describing video size,
- set by a private option. */
char *pixel_format; /**< Set by a private option. */
int list_format; /**< Set by a private option. */
+ int list_standard; /**< Set by a private option. */
char *framerate; /**< Set by a private option. */
+
+ int use_libv4l2;
+ int (*open_f)(const char *file, int oflag, ...);
+ int (*close_f)(int fd);
+ int (*dup_f)(int fd);
+ int (*ioctl_f)(int fd, unsigned long int request, ...);
+ ssize_t (*read_f)(int fd, void *buffer, size_t n);
+ void *(*mmap_f)(void *start, size_t length, int prot, int flags, int fd, int64_t offset);
+ int (*munmap_f)(void *_start, size_t length);
};
struct buff_data {
struct video_data *s;
int index;
- int fd;
-};
-
-struct fmt_map {
- enum AVPixelFormat ff_fmt;
- enum AVCodecID codec_id;
- uint32_t v4l2_fmt;
-};
-
-static struct fmt_map fmt_conversion_table[] = {
- //ff_fmt codec_id v4l2_fmt
- { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420 },
- { AV_PIX_FMT_YUV422P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV422P },
- { AV_PIX_FMT_YUYV422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUYV },
- { AV_PIX_FMT_UYVY422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_UYVY },
- { AV_PIX_FMT_YUV411P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV411P },
- { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV410 },
- { AV_PIX_FMT_RGB555, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555 },
- { AV_PIX_FMT_RGB565, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565 },
- { AV_PIX_FMT_BGR24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR24 },
- { AV_PIX_FMT_RGB24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB24 },
- { AV_PIX_FMT_BGRA, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32 },
- { AV_PIX_FMT_GRAY8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_GREY },
- { AV_PIX_FMT_NV12, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12 },
- { 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
- { AV_PIX_FMT_NONE, AV_CODEC_ID_H264, V4L2_PIX_FMT_H264 },
-#endif
};
static int device_open(AVFormatContext *ctx)
{
+ struct video_data *s = ctx->priv_data;
struct v4l2_capability cap;
int fd;
- int res, err;
+ int err;
int flags = O_RDWR;
- char errbuf[128];
+
+#define SET_WRAPPERS(prefix) do { \
+ s->open_f = prefix ## open; \
+ s->close_f = prefix ## close; \
+ s->dup_f = prefix ## dup; \
+ s->ioctl_f = prefix ## ioctl; \
+ s->read_f = prefix ## read; \
+ s->mmap_f = prefix ## mmap; \
+ s->munmap_f = prefix ## munmap; \
+} while (0)
+
+ if (s->use_libv4l2) {
+#if CONFIG_LIBV4L2
+ SET_WRAPPERS(v4l2_);
+#else
+ av_log(ctx, AV_LOG_ERROR, "libavdevice is not build with libv4l2 support.\n");
+ return AVERROR(EINVAL);
+#endif
+ } else {
+ SET_WRAPPERS();
+ }
+
+#define v4l2_open s->open_f
+#define v4l2_close s->close_f
+#define v4l2_dup s->dup_f
+#define v4l2_ioctl s->ioctl_f
+#define v4l2_read s->read_f
+#define v4l2_mmap s->mmap_f
+#define v4l2_munmap s->munmap_f
if (ctx->flags & AVFMT_FLAG_NONBLOCK) {
flags |= O_NONBLOCK;
}
- fd = avpriv_open(ctx->filename, flags);
+ fd = v4l2_open(ctx->filename, flags, 0);
if (fd < 0) {
err = AVERROR(errno);
- av_strerror(err, errbuf, sizeof(errbuf));
-
- av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s : %s\n",
- ctx->filename, errbuf);
-
+ av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s: %s\n",
+ ctx->filename, av_err2str(err));
return err;
}
- res = ioctl(fd, VIDIOC_QUERYCAP, &cap);
- if (res < 0) {
+ if (v4l2_ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
err = AVERROR(errno);
- av_strerror(err, errbuf, sizeof(errbuf));
av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n",
- errbuf);
-
+ av_err2str(err));
goto fail;
}
- av_log(ctx, AV_LOG_VERBOSE, "[%d]Capabilities: %x\n",
+ av_log(ctx, AV_LOG_VERBOSE, "fd:%d capabilities:%x\n",
fd, cap.capabilities);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
av_log(ctx, AV_LOG_ERROR, "Not a video capture device.\n");
err = AVERROR(ENODEV);
-
goto fail;
}
@@ -163,33 +173,32 @@ static int device_open(AVFormatContext *ctx)
av_log(ctx, AV_LOG_ERROR,
"The device does not support the streaming I/O method.\n");
err = AVERROR(ENOSYS);
-
goto fail;
}
return fd;
fail:
- close(fd);
+ v4l2_close(fd);
return err;
}
static int device_init(AVFormatContext *ctx, int *width, int *height,
- uint32_t pix_fmt)
+ uint32_t pixelformat)
{
struct video_data *s = ctx->priv_data;
- int fd = s->fd;
struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
- struct v4l2_pix_format *pix = &fmt.fmt.pix;
-
- int res;
+ int res = 0;
- pix->width = *width;
- pix->height = *height;
- pix->pixelformat = pix_fmt;
- pix->field = V4L2_FIELD_ANY;
+ fmt.fmt.pix.width = *width;
+ fmt.fmt.pix.height = *height;
+ fmt.fmt.pix.pixelformat = pixelformat;
+ fmt.fmt.pix.field = V4L2_FIELD_ANY;
- res = ioctl(fd, VIDIOC_S_FMT, &fmt);
+ /* Some drivers will fail and return EINVAL when the pixelformat
+ is not supported (even if type field is valid and supported) */
+ if (v4l2_ioctl(s->fd, VIDIOC_S_FMT, &fmt) < 0)
+ res = AVERROR(errno);
if ((*width != fmt.fmt.pix.width) || (*height != fmt.fmt.pix.height)) {
av_log(ctx, AV_LOG_INFO,
@@ -199,87 +208,44 @@ static int device_init(AVFormatContext *ctx, int *width, int *height,
*height = fmt.fmt.pix.height;
}
- if (pix_fmt != fmt.fmt.pix.pixelformat) {
+ if (pixelformat != fmt.fmt.pix.pixelformat) {
av_log(ctx, AV_LOG_DEBUG,
"The V4L2 driver changed the pixel format "
"from 0x%08X to 0x%08X\n",
- pix_fmt, fmt.fmt.pix.pixelformat);
- res = -1;
+ pixelformat, fmt.fmt.pix.pixelformat);
+ res = AVERROR(EINVAL);
}
if (fmt.fmt.pix.field == V4L2_FIELD_INTERLACED) {
- av_log(ctx, AV_LOG_DEBUG, "The V4L2 driver using the interlaced mode");
+ av_log(ctx, AV_LOG_DEBUG,
+ "The V4L2 driver is using the interlaced mode\n");
s->interlaced = 1;
}
return res;
}
-static int first_field(int fd)
+static int first_field(const struct video_data *s)
{
int res;
v4l2_std_id std;
- res = ioctl(fd, VIDIOC_G_STD, &std);
- if (res < 0) {
+ res = v4l2_ioctl(s->fd, VIDIOC_G_STD, &std);
+ if (res < 0)
return 0;
- }
- if (std & V4L2_STD_NTSC) {
+ if (std & V4L2_STD_NTSC)
return 0;
- }
return 1;
}
-static uint32_t fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if ((codec_id == AV_CODEC_ID_NONE ||
- fmt_conversion_table[i].codec_id == codec_id) &&
- (pix_fmt == AV_PIX_FMT_NONE ||
- fmt_conversion_table[i].ff_fmt == pix_fmt)) {
- return fmt_conversion_table[i].v4l2_fmt;
- }
- }
-
- return 0;
-}
-
-static enum AVPixelFormat fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if (fmt_conversion_table[i].v4l2_fmt == v4l2_fmt &&
- fmt_conversion_table[i].codec_id == codec_id) {
- return fmt_conversion_table[i].ff_fmt;
- }
- }
-
- return AV_PIX_FMT_NONE;
-}
-
-static enum AVCodecID fmt_v4l2codec(uint32_t v4l2_fmt)
-{
- int i;
-
- for (i = 0; i < FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if (fmt_conversion_table[i].v4l2_fmt == v4l2_fmt) {
- return fmt_conversion_table[i].codec_id;
- }
- }
-
- return AV_CODEC_ID_NONE;
-}
-
#if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE
-static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat)
+static void list_framesizes(AVFormatContext *ctx, uint32_t pixelformat)
{
+ const struct video_data *s = ctx->priv_data;
struct v4l2_frmsizeenum vfse = { .pixel_format = pixelformat };
- while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
+ while(!v4l2_ioctl(s->fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
switch (vfse.type) {
case V4L2_FRMSIZE_TYPE_DISCRETE:
av_log(ctx, AV_LOG_INFO, " %ux%u",
@@ -300,26 +266,27 @@ static void list_framesizes(AVFormatContext *ctx, int fd, uint32_t pixelformat)
}
#endif
-static void list_formats(AVFormatContext *ctx, int fd, int type)
+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 };
- while(!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
- enum AVCodecID codec_id = fmt_v4l2codec(vfd.pixelformat);
- enum AVPixelFormat pix_fmt = fmt_v4l2ff(vfd.pixelformat, codec_id);
+ while(!v4l2_ioctl(s->fd, VIDIOC_ENUM_FMT, &vfd)) {
+ enum AVCodecID codec_id = ff_fmt_v4l2codec(vfd.pixelformat);
+ enum AVPixelFormat pix_fmt = ff_fmt_v4l2ff(vfd.pixelformat, codec_id);
vfd.index++;
if (!(vfd.flags & V4L2_FMT_FLAG_COMPRESSED) &&
type & V4L_RAWFORMATS) {
const char *fmt_name = av_get_pix_fmt_name(pix_fmt);
- av_log(ctx, AV_LOG_INFO, "R : %9s : %20s :",
+ av_log(ctx, AV_LOG_INFO, "Raw : %11s : %20s :",
fmt_name ? fmt_name : "Unsupported",
vfd.description);
} else if (vfd.flags & V4L2_FMT_FLAG_COMPRESSED &&
type & V4L_COMPFORMATS) {
const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id);
- av_log(ctx, AV_LOG_INFO, "C : %9s : %20s :",
+ av_log(ctx, AV_LOG_INFO, "Compressed: %11s : %20s :",
desc ? desc->name : "Unsupported",
vfd.description);
} else {
@@ -327,18 +294,40 @@ static void list_formats(AVFormatContext *ctx, int fd, int type)
}
#ifdef V4L2_FMT_FLAG_EMULATED
- if (vfd.flags & V4L2_FMT_FLAG_EMULATED) {
- av_log(ctx, AV_LOG_WARNING, "%s", "Emulated");
- continue;
- }
+ if (vfd.flags & V4L2_FMT_FLAG_EMULATED)
+ av_log(ctx, AV_LOG_INFO, " Emulated :");
#endif
#if HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE
- list_framesizes(ctx, fd, vfd.pixelformat);
+ list_framesizes(ctx, vfd.pixelformat);
#endif
av_log(ctx, AV_LOG_INFO, "\n");
}
}
+static void list_standards(AVFormatContext *ctx)
+{
+ int ret;
+ struct video_data *s = ctx->priv_data;
+ struct v4l2_standard standard;
+
+ if (s->std_id == 0)
+ return;
+
+ for (standard.index = 0; ; standard.index++) {
+ if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) {
+ ret = AVERROR(errno);
+ if (ret == AVERROR(EINVAL)) {
+ break;
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", av_err2str(ret));
+ return;
+ }
+ }
+ av_log(ctx, AV_LOG_INFO, "%2d, %16"PRIx64", %s\n",
+ standard.index, (uint64_t)standard.id, standard.name);
+ }
+}
+
static int mmap_init(AVFormatContext *ctx)
{
int i, res;
@@ -349,35 +338,26 @@ static int mmap_init(AVFormatContext *ctx)
.memory = V4L2_MEMORY_MMAP
};
- res = ioctl(s->fd, VIDIOC_REQBUFS, &req);
- if (res < 0) {
+ if (v4l2_ioctl(s->fd, VIDIOC_REQBUFS, &req) < 0) {
res = AVERROR(errno);
- if (res == AVERROR(EINVAL)) {
- av_log(ctx, AV_LOG_ERROR, "Device does not support mmap\n");
- } else {
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_REQBUFS)\n");
- }
-
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_REQBUFS): %s\n", av_err2str(res));
return res;
}
if (req.count < 2) {
av_log(ctx, AV_LOG_ERROR, "Insufficient buffer memory\n");
-
return AVERROR(ENOMEM);
}
s->buffers = req.count;
- s->buf_start = av_malloc(sizeof(void *) * s->buffers);
+ s->buf_start = av_malloc_array(s->buffers, sizeof(void *));
if (!s->buf_start) {
av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer pointers\n");
-
return AVERROR(ENOMEM);
}
- s->buf_len = av_malloc(sizeof(unsigned int) * s->buffers);
+ s->buf_len = av_malloc_array(s->buffers, sizeof(unsigned int));
if (!s->buf_len) {
av_log(ctx, AV_LOG_ERROR, "Cannot allocate buffer sizes\n");
- av_free(s->buf_start);
-
+ av_freep(&s->buf_start);
return AVERROR(ENOMEM);
}
@@ -387,33 +367,26 @@ static int mmap_init(AVFormatContext *ctx)
.index = i,
.memory = V4L2_MEMORY_MMAP
};
-
- res = ioctl(s->fd, VIDIOC_QUERYBUF, &buf);
- if (res < 0) {
+ if (v4l2_ioctl(s->fd, VIDIOC_QUERYBUF, &buf) < 0) {
res = AVERROR(errno);
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF)\n");
-
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYBUF): %s\n", av_err2str(res));
return res;
}
s->buf_len[i] = buf.length;
if (s->frame_size > 0 && s->buf_len[i] < s->frame_size) {
av_log(ctx, AV_LOG_ERROR,
- "Buffer len [%d] = %d != %d\n",
+ "buf_len[%d] = %d < expected frame size %d\n",
i, s->buf_len[i], s->frame_size);
-
- return -1;
+ return AVERROR(ENOMEM);
}
- s->buf_start[i] = mmap(NULL, buf.length,
+ s->buf_start[i] = v4l2_mmap(NULL, buf.length,
PROT_READ | PROT_WRITE, MAP_SHARED,
s->fd, buf.m.offset);
if (s->buf_start[i] == MAP_FAILED) {
- char errbuf[128];
res = AVERROR(errno);
- av_strerror(res, errbuf, sizeof(errbuf));
- av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", errbuf);
-
+ av_log(ctx, AV_LOG_ERROR, "mmap: %s\n", av_err2str(res));
return res;
}
}
@@ -428,27 +401,93 @@ static void dummy_release_buffer(AVPacket *pkt)
}
#endif
+static int enqueue_buffer(struct video_data *s, struct v4l2_buffer *buf)
+{
+ int res = 0;
+
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, buf) < 0) {
+ res = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n", av_err2str(res));
+ } else {
+ avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
+ }
+
+ return res;
+}
+
static void mmap_release_buffer(void *opaque, uint8_t *data)
{
struct v4l2_buffer buf = { 0 };
- int res, fd;
struct buff_data *buf_descriptor = opaque;
struct video_data *s = buf_descriptor->s;
- char errbuf[128];
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = buf_descriptor->index;
- fd = buf_descriptor->fd;
av_free(buf_descriptor);
- res = ioctl(fd, VIDIOC_QBUF, &buf);
- if (res < 0) {
- av_strerror(AVERROR(errno), errbuf, sizeof(errbuf));
- av_log(NULL, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n",
- errbuf);
+ enqueue_buffer(s, &buf);
+}
+
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+static int64_t av_gettime_monotonic(void)
+{
+ return av_gettime_relative();
+}
+#endif
+
+static int init_convert_timestamp(AVFormatContext *ctx, int64_t ts)
+{
+ struct video_data *s = ctx->priv_data;
+ int64_t now;
+
+ now = av_gettime();
+ if (s->ts_mode == V4L_TS_ABS &&
+ ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE) {
+ av_log(ctx, AV_LOG_INFO, "Detected absolute timestamps\n");
+ s->ts_mode = V4L_TS_CONVERT_READY;
+ return 0;
+ }
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+ if (ctx->streams[0]->avg_frame_rate.num) {
+ now = av_gettime_monotonic();
+ if (s->ts_mode == V4L_TS_MONO2ABS ||
+ (ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE)) {
+ AVRational tb = {AV_TIME_BASE, 1};
+ int64_t period = av_rescale_q(1, tb, ctx->streams[0]->avg_frame_rate);
+ av_log(ctx, AV_LOG_INFO, "Detected monotonic timestamps, converting\n");
+ /* microseconds instead of seconds, MHz instead of Hz */
+ s->timefilter = ff_timefilter_new(1, period, 1.0E-6);
+ if (!s->timefilter)
+ return AVERROR(ENOMEM);
+ s->ts_mode = V4L_TS_CONVERT_READY;
+ return 0;
+ }
}
- avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
+#endif
+ av_log(ctx, AV_LOG_ERROR, "Unknown timestamps\n");
+ return AVERROR(EIO);
+}
+
+static int convert_timestamp(AVFormatContext *ctx, int64_t *ts)
+{
+ struct video_data *s = ctx->priv_data;
+
+ if (s->ts_mode) {
+ int r = init_convert_timestamp(ctx, *ts);
+ if (r < 0)
+ return r;
+ }
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+ if (s->timefilter) {
+ int64_t nowa = av_gettime();
+ int64_t nowm = av_gettime_monotonic();
+ ff_timefilter_update(s->timefilter, nowa, nowm - s->last_time_m);
+ s->last_time_m = nowm;
+ *ts = ff_timefilter_eval(s->timefilter, *ts - nowm);
+ }
+#endif
+ return 0;
}
static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
@@ -458,30 +497,19 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.memory = V4L2_MEMORY_MMAP
};
- struct pollfd p = { .fd = s->fd, .events = POLLIN };
int res;
- res = poll(&p, 1, s->timeout);
- if (res < 0)
- return AVERROR(errno);
-
- if (!(p.revents & (POLLIN | POLLERR | POLLHUP)))
- return AVERROR(EAGAIN);
+ pkt->size = 0;
/* FIXME: Some special treatment might be needed in case of loss of signal... */
- while ((res = ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && (errno == EINTR));
+ while ((res = v4l2_ioctl(s->fd, VIDIOC_DQBUF, &buf)) < 0 && (errno == EINTR));
if (res < 0) {
- char errbuf[128];
- if (errno == EAGAIN) {
- pkt->size = 0;
-
+ if (errno == EAGAIN)
return AVERROR(EAGAIN);
- }
+
res = AVERROR(errno);
- av_strerror(res, errbuf, sizeof(errbuf));
av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_DQBUF): %s\n",
- errbuf);
-
+ av_err2str(res));
return res;
}
@@ -493,12 +521,27 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
// always keep at least one buffer queued
av_assert0(avpriv_atomic_int_get(&s->buffers_queued) >= 1);
- if (s->frame_size > 0 && buf.bytesused != s->frame_size) {
- av_log(ctx, AV_LOG_ERROR,
- "The v4l2 frame is %d bytes, but %d bytes are expected\n",
- buf.bytesused, s->frame_size);
+#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;
+ } 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;
- return AVERROR_INVALIDDATA;
+ if (s->frame_size > 0 && buf.bytesused != s->frame_size) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Dequeued v4l2 buffer contains %d bytes, but %d were expected. Flags: 0x%08X.\n",
+ buf.bytesused, s->frame_size, buf.flags);
+ enqueue_buffer(s, &buf);
+ return AVERROR_INVALIDDATA;
+ }
}
/* Image is at s->buff_start[buf.index] */
@@ -507,18 +550,16 @@ static int mmap_read_frame(AVFormatContext *ctx, AVPacket *pkt)
res = av_new_packet(pkt, buf.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);
- res = ioctl(s->fd, VIDIOC_QBUF, &buf);
- if (res < 0) {
- res = AVERROR(errno);
- av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF)\n");
+ res = enqueue_buffer(s, &buf);
+ if (res) {
av_free_packet(pkt);
return res;
}
- avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
} else {
struct buff_data *buf_descriptor;
@@ -536,32 +577,33 @@ FF_ENABLE_DEPRECATION_WARNINGS
* allocate a buffer for memcpying into it
*/
av_log(ctx, AV_LOG_ERROR, "Failed to allocate a buffer descriptor\n");
- res = ioctl(s->fd, VIDIOC_QBUF, &buf);
+ enqueue_buffer(s, &buf);
return AVERROR(ENOMEM);
}
- buf_descriptor->fd = s->fd;
buf_descriptor->index = buf.index;
buf_descriptor->s = s;
pkt->buf = av_buffer_create(pkt->data, pkt->size, mmap_release_buffer,
buf_descriptor, 0);
if (!pkt->buf) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to create a buffer\n");
+ enqueue_buffer(s, &buf);
av_freep(&buf_descriptor);
return AVERROR(ENOMEM);
}
}
pkt->pts = buf.timestamp.tv_sec * INT64_C(1000000) + buf.timestamp.tv_usec;
+ convert_timestamp(ctx, &pkt->pts);
- return s->buf_len[buf.index];
+ return pkt->size;
}
static int mmap_start(AVFormatContext *ctx)
{
struct video_data *s = ctx->priv_data;
enum v4l2_buf_type type;
- int i, res, err;
- char errbuf[128];
+ int i, res;
for (i = 0; i < s->buffers; i++) {
struct v4l2_buffer buf = {
@@ -570,27 +612,21 @@ static int mmap_start(AVFormatContext *ctx)
.memory = V4L2_MEMORY_MMAP
};
- res = ioctl(s->fd, VIDIOC_QBUF, &buf);
- if (res < 0) {
- err = AVERROR(errno);
- av_strerror(err, errbuf, sizeof(errbuf));
+ if (v4l2_ioctl(s->fd, VIDIOC_QBUF, &buf) < 0) {
+ res = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QBUF): %s\n",
- errbuf);
-
- return err;
+ av_err2str(res));
+ return res;
}
}
s->buffers_queued = s->buffers;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- res = ioctl(s->fd, VIDIOC_STREAMON, &type);
- if (res < 0) {
- err = AVERROR(errno);
- av_strerror(err, errbuf, sizeof(errbuf));
+ if (v4l2_ioctl(s->fd, VIDIOC_STREAMON, &type) < 0) {
+ res = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_STREAMON): %s\n",
- errbuf);
-
- return err;
+ av_err2str(res));
+ return res;
}
return 0;
@@ -605,272 +641,357 @@ static void mmap_close(struct video_data *s)
/* We do not check for the result, because we could
* not do anything about it anyway...
*/
- ioctl(s->fd, VIDIOC_STREAMOFF, &type);
+ v4l2_ioctl(s->fd, VIDIOC_STREAMOFF, &type);
for (i = 0; i < s->buffers; i++) {
- munmap(s->buf_start[i], s->buf_len[i]);
+ v4l2_munmap(s->buf_start[i], s->buf_len[i]);
}
- av_free(s->buf_start);
- av_free(s->buf_len);
+ av_freep(&s->buf_start);
+ av_freep(&s->buf_len);
}
-static int v4l2_set_parameters(AVFormatContext *s1)
+static int v4l2_set_parameters(AVFormatContext *ctx)
{
- struct video_data *s = s1->priv_data;
- struct v4l2_input input = { 0 };
+ struct video_data *s = ctx->priv_data;
struct v4l2_standard standard = { 0 };
struct v4l2_streamparm streamparm = { 0 };
- struct v4l2_fract *tpf = &streamparm.parm.capture.timeperframe;
+ struct v4l2_fract *tpf;
AVRational framerate_q = { 0 };
int i, ret;
- streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
if (s->framerate &&
(ret = av_parse_video_rate(&framerate_q, s->framerate)) < 0) {
- av_log(s1, AV_LOG_ERROR, "Could not parse framerate '%s'.\n",
+ av_log(ctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n",
s->framerate);
return ret;
}
- /* set tv video input */
- input.index = s->channel;
- if (ioctl(s->fd, VIDIOC_ENUMINPUT, &input) < 0) {
- av_log(s1, AV_LOG_ERROR, "The V4L2 driver ioctl enum input failed:\n");
- return AVERROR(EIO);
- }
+ if (s->standard) {
+ if (s->std_id) {
+ ret = 0;
+ av_log(ctx, AV_LOG_DEBUG, "Setting standard: %s\n", s->standard);
+ /* set tv standard */
+ for (i = 0; ; i++) {
+ standard.index = i;
+ if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) {
+ ret = AVERROR(errno);
+ break;
+ }
+ if (!av_strcasecmp(standard.name, s->standard))
+ break;
+ }
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Unknown or unsupported standard '%s'\n", s->standard);
+ return ret;
+ }
- av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set input_id: %d, input: %s\n",
- s->channel, input.name);
- if (ioctl(s->fd, VIDIOC_S_INPUT, &input.index) < 0) {
- av_log(s1, AV_LOG_ERROR,
- "The V4L2 driver ioctl set input(%d) failed\n",
- s->channel);
- return AVERROR(EIO);
+ if (v4l2_ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) {
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_S_STD): %s\n", av_err2str(ret));
+ return ret;
+ }
+ } else {
+ av_log(ctx, AV_LOG_WARNING,
+ "This device does not support any standard\n");
+ }
}
- if (s->standard) {
- av_log(s1, AV_LOG_DEBUG, "The V4L2 driver set standard: %s\n",
- s->standard);
- /* set tv standard */
- for(i=0;;i++) {
+ /* get standard */
+ if (v4l2_ioctl(s->fd, VIDIOC_G_STD, &s->std_id) == 0) {
+ tpf = &standard.frameperiod;
+ for (i = 0; ; i++) {
standard.index = i;
- if (ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) {
- av_log(s1, AV_LOG_ERROR,
- "The V4L2 driver ioctl set standard(%s) failed\n",
- s->standard);
- return AVERROR(EIO);
+ if (v4l2_ioctl(s->fd, VIDIOC_ENUMSTD, &standard) < 0) {
+ ret = AVERROR(errno);
+ if (ret == AVERROR(EINVAL)
+#ifdef ENODATA
+ || ret == AVERROR(ENODATA)
+#endif
+ ) {
+ tpf = &streamparm.parm.capture.timeperframe;
+ break;
+ }
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMSTD): %s\n", av_err2str(ret));
+ return ret;
}
-
- if (!av_strcasecmp(standard.name, s->standard)) {
+ if (standard.id == s->std_id) {
+ av_log(ctx, AV_LOG_DEBUG,
+ "Current standard: %s, id: %"PRIx64", frameperiod: %d/%d\n",
+ standard.name, (uint64_t)standard.id, tpf->numerator, tpf->denominator);
break;
}
}
+ } else {
+ tpf = &streamparm.parm.capture.timeperframe;
+ }
- av_log(s1, AV_LOG_DEBUG,
- "The V4L2 driver set standard: %s, id: %"PRIu64"\n",
- s->standard, (uint64_t)standard.id);
- if (ioctl(s->fd, VIDIOC_S_STD, &standard.id) < 0) {
- av_log(s1, AV_LOG_ERROR,
- "The V4L2 driver ioctl set standard(%s) failed\n",
- s->standard);
- return AVERROR(EIO);
- }
+ streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (v4l2_ioctl(s->fd, VIDIOC_G_PARM, &streamparm) < 0) {
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_G_PARM): %s\n", av_err2str(ret));
+ return ret;
}
if (framerate_q.num && framerate_q.den) {
- av_log(s1, AV_LOG_DEBUG, "Setting time per frame to %d/%d\n",
- framerate_q.den, framerate_q.num);
- tpf->numerator = framerate_q.den;
- tpf->denominator = framerate_q.num;
-
- if (ioctl(s->fd, VIDIOC_S_PARM, &streamparm) != 0) {
- av_log(s1, AV_LOG_ERROR,
- "ioctl set time per frame(%d/%d) failed\n",
+ if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
+ tpf = &streamparm.parm.capture.timeperframe;
+
+ av_log(ctx, AV_LOG_DEBUG, "Setting time per frame to %d/%d\n",
framerate_q.den, framerate_q.num);
- return AVERROR(EIO);
- }
+ tpf->numerator = framerate_q.den;
+ tpf->denominator = framerate_q.num;
+
+ if (v4l2_ioctl(s->fd, VIDIOC_S_PARM, &streamparm) < 0) {
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_S_PARM): %s\n",
+ av_err2str(ret));
+ return ret;
+ }
- if (framerate_q.num != tpf->denominator ||
- framerate_q.den != tpf->numerator) {
- av_log(s1, AV_LOG_INFO,
- "The driver changed the time per frame from "
- "%d/%d to %d/%d\n",
- framerate_q.den, framerate_q.num,
- tpf->numerator, tpf->denominator);
- }
- } else {
- if (ioctl(s->fd, VIDIOC_G_PARM, &streamparm) != 0) {
- char errbuf[128];
- ret = AVERROR(errno);
- av_strerror(ret, errbuf, sizeof(errbuf));
- av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_PARM): %s\n",
- errbuf);
- return ret;
+ if (framerate_q.num != tpf->denominator ||
+ framerate_q.den != tpf->numerator) {
+ av_log(ctx, AV_LOG_INFO,
+ "The driver changed the time per frame from "
+ "%d/%d to %d/%d\n",
+ framerate_q.den, framerate_q.num,
+ tpf->numerator, tpf->denominator);
+ }
+ } else {
+ av_log(ctx, AV_LOG_WARNING,
+ "The driver does not permit changing the time per frame\n");
}
}
- s1->streams[0]->avg_frame_rate.num = tpf->denominator;
- s1->streams[0]->avg_frame_rate.den = tpf->numerator;
-
- s->timeout = 100 +
- av_rescale_q(1, s1->streams[0]->avg_frame_rate,
- (AVRational){1, 1000});
+ if (tpf->denominator > 0 && tpf->numerator > 0) {
+ ctx->streams[0]->avg_frame_rate.num = tpf->denominator;
+ ctx->streams[0]->avg_frame_rate.den = tpf->numerator;
+ ctx->streams[0]->r_frame_rate = ctx->streams[0]->avg_frame_rate;
+ } else
+ av_log(ctx, AV_LOG_WARNING, "Time per frame unknown\n");
return 0;
}
-static uint32_t device_try_init(AVFormatContext *s1,
- enum AVPixelFormat pix_fmt,
- int *width,
- int *height,
- enum AVCodecID *codec_id)
+static int device_try_init(AVFormatContext *ctx,
+ enum AVPixelFormat pix_fmt,
+ int *width,
+ int *height,
+ uint32_t *desired_format,
+ enum AVCodecID *codec_id)
{
- uint32_t desired_format = fmt_ff2v4l(pix_fmt, s1->video_codec_id);
-
- if (desired_format == 0 ||
- device_init(s1, width, height, desired_format) < 0) {
- int i;
-
- desired_format = 0;
- for (i = 0; i<FF_ARRAY_ELEMS(fmt_conversion_table); i++) {
- if (s1->video_codec_id == AV_CODEC_ID_NONE ||
- fmt_conversion_table[i].codec_id == s1->video_codec_id) {
- desired_format = fmt_conversion_table[i].v4l2_fmt;
- if (device_init(s1, width, height, desired_format) >= 0) {
+ int ret, i;
+
+ *desired_format = ff_fmt_ff2v4l(pix_fmt, ctx->video_codec_id);
+
+ if (*desired_format) {
+ ret = device_init(ctx, width, height, *desired_format);
+ if (ret < 0) {
+ *desired_format = 0;
+ if (ret != AVERROR(EINVAL))
+ return ret;
+ }
+ }
+
+ if (!*desired_format) {
+ for (i = 0; ff_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+ if (ctx->video_codec_id == AV_CODEC_ID_NONE ||
+ ff_fmt_conversion_table[i].codec_id == ctx->video_codec_id) {
+ av_log(ctx, AV_LOG_DEBUG, "Trying to set codec:%s pix_fmt:%s\n",
+ avcodec_get_name(ff_fmt_conversion_table[i].codec_id),
+ (char *)av_x_if_null(av_get_pix_fmt_name(ff_fmt_conversion_table[i].ff_fmt), "none"));
+
+ *desired_format = ff_fmt_conversion_table[i].v4l2_fmt;
+ ret = device_init(ctx, width, height, *desired_format);
+ if (ret >= 0)
break;
- }
- desired_format = 0;
+ else if (ret != AVERROR(EINVAL))
+ return ret;
+ *desired_format = 0;
}
}
- }
- if (desired_format != 0) {
- *codec_id = fmt_v4l2codec(desired_format);
- assert(*codec_id != AV_CODEC_ID_NONE);
+ if (*desired_format == 0) {
+ av_log(ctx, AV_LOG_ERROR, "Cannot find a proper format for "
+ "codec '%s' (id %d), pixel format '%s' (id %d)\n",
+ avcodec_get_name(ctx->video_codec_id), ctx->video_codec_id,
+ (char *)av_x_if_null(av_get_pix_fmt_name(pix_fmt), "none"), pix_fmt);
+ ret = AVERROR(EINVAL);
+ }
}
- return desired_format;
+ *codec_id = ff_fmt_v4l2codec(*desired_format);
+ av_assert0(*codec_id != AV_CODEC_ID_NONE);
+ return ret;
+}
+
+static int v4l2_read_probe(AVProbeData *p)
+{
+ if (av_strstart(p->filename, "/dev/video", NULL))
+ return AVPROBE_SCORE_MAX - 1;
+ return 0;
}
-static int v4l2_read_header(AVFormatContext *s1)
+static int v4l2_read_header(AVFormatContext *ctx)
{
- struct video_data *s = s1->priv_data;
+ struct video_data *s = ctx->priv_data;
AVStream *st;
int res = 0;
uint32_t desired_format;
- enum AVCodecID codec_id;
+ enum AVCodecID codec_id = AV_CODEC_ID_NONE;
enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
+ struct v4l2_input input = { 0 };
- st = avformat_new_stream(s1, NULL);
+ st = avformat_new_stream(ctx, NULL);
if (!st)
return AVERROR(ENOMEM);
- s->fd = device_open(s1);
+#if CONFIG_LIBV4L2
+ /* silence libv4l2 logging. if fopen() fails v4l2_log_file will be NULL
+ and errors will get sent to stderr */
+ if (s->use_libv4l2)
+ v4l2_log_file = fopen("/dev/null", "w");
+#endif
+
+ s->fd = device_open(ctx);
if (s->fd < 0)
return s->fd;
- if (s->list_format) {
- list_formats(s1, s->fd, s->list_format);
- return AVERROR_EXIT;
+ if (s->channel != -1) {
+ /* set video input */
+ av_log(ctx, AV_LOG_DEBUG, "Selecting input_channel: %d\n", s->channel);
+ if (v4l2_ioctl(s->fd, VIDIOC_S_INPUT, &s->channel) < 0) {
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_S_INPUT): %s\n", av_err2str(res));
+ goto fail;
+ }
+ } else {
+ /* get current video input */
+ if (v4l2_ioctl(s->fd, VIDIOC_G_INPUT, &s->channel) < 0) {
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_G_INPUT): %s\n", av_err2str(res));
+ goto fail;
+ }
}
- avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+ /* enum input */
+ input.index = s->channel;
+ if (v4l2_ioctl(s->fd, VIDIOC_ENUMINPUT, &input) < 0) {
+ res = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_ENUMINPUT): %s\n", av_err2str(res));
+ goto fail;
+ }
+ s->std_id = input.std;
+ av_log(ctx, AV_LOG_DEBUG, "Current input_channel: %d, input_name: %s, input_std: %"PRIx64"\n",
+ s->channel, input.name, (uint64_t)input.std);
- if (s->video_size &&
- (res = av_parse_video_size(&s->width, &s->height, s->video_size)) < 0) {
- av_log(s1, AV_LOG_ERROR, "Could not parse video size '%s'.\n",
- s->video_size);
- return res;
+ if (s->list_format) {
+ list_formats(ctx, s->list_format);
+ res = AVERROR_EXIT;
+ goto fail;
}
+ if (s->list_standard) {
+ list_standards(ctx);
+ res = AVERROR_EXIT;
+ goto fail;
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
+
if (s->pixel_format) {
AVCodec *codec = avcodec_find_decoder_by_name(s->pixel_format);
- if (codec) {
- s1->video_codec_id = codec->id;
- st->need_parsing = AVSTREAM_PARSE_HEADERS;
- }
+ if (codec)
+ ctx->video_codec_id = codec->id;
pix_fmt = av_get_pix_fmt(s->pixel_format);
if (pix_fmt == AV_PIX_FMT_NONE && !codec) {
- av_log(s1, AV_LOG_ERROR, "No such input format: %s.\n",
+ av_log(ctx, AV_LOG_ERROR, "No such input format: %s.\n",
s->pixel_format);
- return AVERROR(EINVAL);
+ res = AVERROR(EINVAL);
+ goto fail;
}
}
if (!s->width && !s->height) {
- struct v4l2_format fmt;
+ struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
- av_log(s1, AV_LOG_VERBOSE,
+ av_log(ctx, AV_LOG_VERBOSE,
"Querying the device for the current frame size\n");
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) {
- char errbuf[128];
+ if (v4l2_ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) {
res = AVERROR(errno);
- av_strerror(res, errbuf, sizeof(errbuf));
- av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n",
- errbuf);
- return res;
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n",
+ av_err2str(res));
+ goto fail;
}
s->width = fmt.fmt.pix.width;
s->height = fmt.fmt.pix.height;
- av_log(s1, AV_LOG_VERBOSE,
+ av_log(ctx, AV_LOG_VERBOSE,
"Setting frame size to %dx%d\n", s->width, s->height);
}
- desired_format = device_try_init(s1, pix_fmt, &s->width, &s->height,
- &codec_id);
- if (desired_format == 0) {
- av_log(s1, AV_LOG_ERROR, "Cannot find a proper format for "
- "codec_id %d, pix_fmt %d.\n", s1->video_codec_id, pix_fmt);
- close(s->fd);
+ res = device_try_init(ctx, pix_fmt, &s->width, &s->height, &desired_format, &codec_id);
+ if (res < 0)
+ goto fail;
- return AVERROR(EIO);
- }
+ /* If no pixel_format was specified, the codec_id was not known up
+ * until now. Set video_codec_id in the context, as codec_id will
+ * not be available outside this function
+ */
+ if (codec_id != AV_CODEC_ID_NONE && ctx->video_codec_id == AV_CODEC_ID_NONE)
+ ctx->video_codec_id = codec_id;
- if ((res = av_image_check_size(s->width, s->height, 0, s1) < 0))
- return res;
+ if ((res = av_image_check_size(s->width, s->height, 0, ctx)) < 0)
+ goto fail;
- s->frame_format = desired_format;
+ s->pixelformat = desired_format;
- if ((res = v4l2_set_parameters(s1) < 0))
- return res;
+ if ((res = v4l2_set_parameters(ctx)) < 0)
+ goto fail;
- st->codec->pix_fmt = fmt_v4l2ff(desired_format, codec_id);
+ st->codec->pix_fmt = ff_fmt_v4l2ff(desired_format, codec_id);
s->frame_size =
avpicture_get_size(st->codec->pix_fmt, s->width, s->height);
- if ((res = mmap_init(s1)) ||
- (res = mmap_start(s1)) < 0) {
- close(s->fd);
- return res;
- }
+ if ((res = mmap_init(ctx)) ||
+ (res = mmap_start(ctx)) < 0)
+ goto fail;
- s->top_field_first = first_field(s->fd);
+ s->top_field_first = first_field(s);
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = codec_id;
if (codec_id == AV_CODEC_ID_RAWVIDEO)
st->codec->codec_tag =
avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ else if (codec_id == AV_CODEC_ID_H264) {
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ }
+ if (desired_format == V4L2_PIX_FMT_YVU420)
+ st->codec->codec_tag = MKTAG('Y', 'V', '1', '2');
+ else if (desired_format == V4L2_PIX_FMT_YVU410)
+ st->codec->codec_tag = MKTAG('Y', 'V', 'U', '9');
st->codec->width = s->width;
st->codec->height = s->height;
- st->codec->bit_rate = s->frame_size * av_q2d(st->avg_frame_rate) * 8;
+ if (st->avg_frame_rate.den)
+ st->codec->bit_rate = s->frame_size * av_q2d(st->avg_frame_rate) * 8;
return 0;
+
+fail:
+ v4l2_close(s->fd);
+ return res;
}
-static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt)
+static int v4l2_read_packet(AVFormatContext *ctx, AVPacket *pkt)
{
- struct video_data *s = s1->priv_data;
- AVFrame *frame = s1->streams[0]->codec->coded_frame;
+ struct video_data *s = ctx->priv_data;
+ AVFrame *frame = ctx->streams[0]->codec->coded_frame;
int res;
av_init_packet(pkt);
- if ((res = mmap_read_frame(s1, pkt)) < 0) {
+ if ((res = mmap_read_frame(ctx, pkt)) < 0) {
return res;
}
@@ -882,33 +1003,120 @@ static int v4l2_read_packet(AVFormatContext *s1, AVPacket *pkt)
return pkt->size;
}
-static int v4l2_read_close(AVFormatContext *s1)
+static int v4l2_read_close(AVFormatContext *ctx)
{
- struct video_data *s = s1->priv_data;
+ struct video_data *s = ctx->priv_data;
if (avpriv_atomic_int_get(&s->buffers_queued) != s->buffers)
- av_log(s1, AV_LOG_WARNING, "Some buffers are still owned by the caller on "
+ av_log(ctx, AV_LOG_WARNING, "Some buffers are still owned by the caller on "
"close.\n");
mmap_close(s);
- close(s->fd);
+ v4l2_close(s->fd);
return 0;
}
+static int v4l2_is_v4l_dev(const char *name)
+{
+ return !strncmp(name, "video", 5) ||
+ !strncmp(name, "radio", 5) ||
+ !strncmp(name, "vbi", 3) ||
+ !strncmp(name, "v4l-subdev", 10);
+}
+
+static int v4l2_get_device_list(AVFormatContext *ctx, AVDeviceInfoList *device_list)
+{
+ struct video_data *s = ctx->priv_data;
+ DIR *dir;
+ struct dirent *entry;
+ AVDeviceInfo *device = NULL;
+ struct v4l2_capability cap;
+ int ret = 0;
+
+ if (!device_list)
+ return AVERROR(EINVAL);
+
+ dir = opendir("/dev");
+ if (!dir) {
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "Couldn't open the directory: %s\n", av_err2str(ret));
+ return ret;
+ }
+ while ((entry = readdir(dir))) {
+ if (!v4l2_is_v4l_dev(entry->d_name))
+ continue;
+
+ snprintf(ctx->filename, sizeof(ctx->filename), "/dev/%s", entry->d_name);
+ if ((s->fd = device_open(ctx)) < 0)
+ continue;
+
+ if (v4l2_ioctl(s->fd, VIDIOC_QUERYCAP, &cap) < 0) {
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "ioctl(VIDIOC_QUERYCAP): %s\n", av_err2str(ret));
+ goto fail;
+ }
+
+ device = av_mallocz(sizeof(AVDeviceInfo));
+ if (!device) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ device->device_name = av_strdup(ctx->filename);
+ device->device_description = av_strdup(cap.card);
+ if (!device->device_name || !device->device_description) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if ((ret = av_dynarray_add_nofree(&device_list->devices,
+ &device_list->nb_devices, device)) < 0)
+ goto fail;
+
+ v4l2_close(s->fd);
+ s->fd = -1;
+ continue;
+
+ fail:
+ if (device) {
+ av_freep(&device->device_name);
+ av_freep(&device->device_description);
+ av_freep(&device);
+ }
+ if (s->fd >= 0)
+ v4l2_close(s->fd);
+ s->fd = -1;
+ break;
+ }
+ closedir(dir);
+ return ret;
+}
+
#define OFFSET(x) offsetof(struct video_data, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
+
static const AVOption options[] = {
- { "standard", "TV standard, used only by analog frame grabber", OFFSET(standard), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC },
- { "channel", "TV channel, used only by frame grabber", OFFSET(channel), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC },
- { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "pixel_format", "Preferred pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "input_format", "Preferred pixel format (for raw video) or codec name", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "list_formats", "List available formats and exit", OFFSET(list_format), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC, "list_formats" },
- { "all", "Show all available formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_ALLFORMATS }, 0, INT_MAX, DEC, "list_formats" },
- { "raw", "Show only non-compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_RAWFORMATS }, 0, INT_MAX, DEC, "list_formats" },
- { "compressed", "Show only compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_COMPFORMATS }, 0, INT_MAX, DEC, "list_formats" },
+ { "standard", "set TV standard, used only by analog frame grabber", OFFSET(standard), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC },
+ { "channel", "set TV channel, used only by frame grabber", OFFSET(channel), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, DEC },
+ { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "pixel_format", "set preferred pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "input_format", "set preferred pixel format (for raw video) or codec name", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+
+ { "list_formats", "list available formats and exit", OFFSET(list_format), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC, "list_formats" },
+ { "all", "show all available formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_ALLFORMATS }, 0, INT_MAX, DEC, "list_formats" },
+ { "raw", "show only non-compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_RAWFORMATS }, 0, INT_MAX, DEC, "list_formats" },
+ { "compressed", "show only compressed formats", OFFSET(list_format), AV_OPT_TYPE_CONST, {.i64 = V4L_COMPFORMATS }, 0, INT_MAX, DEC, "list_formats" },
+
+ { "list_standards", "list supported standards and exit", OFFSET(list_standard), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC, "list_standards" },
+ { "all", "show all supported standards", OFFSET(list_standard), AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, DEC, "list_standards" },
+
+ { "timestamps", "set type of timestamps for grabbed frames", OFFSET(ts_mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "timestamps" },
+ { "ts", "set type of timestamps for grabbed frames", OFFSET(ts_mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "timestamps" },
+ { "default", "use timestamps from the kernel", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_DEFAULT }, 0, 2, DEC, "timestamps" },
+ { "abs", "use absolute timestamps (wall clock)", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_ABS }, 0, 2, DEC, "timestamps" },
+ { "mono2abs", "force conversion from monotonic to absolute timestamps", OFFSET(ts_mode), AV_OPT_TYPE_CONST, {.i64 = V4L_TS_MONO2ABS }, 0, 2, DEC, "timestamps" },
+ { "use_libv4l2", "use libv4l2 (v4l-utils) conversion functions", OFFSET(use_libv4l2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
{ NULL },
};
@@ -917,15 +1125,18 @@ static const AVClass v4l2_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
AVInputFormat ff_v4l2_demuxer = {
- .name = "video4linux2",
+ .name = "video4linux2,v4l2",
.long_name = NULL_IF_CONFIG_SMALL("Video4Linux2 device grab"),
.priv_data_size = sizeof(struct video_data),
+ .read_probe = v4l2_read_probe,
.read_header = v4l2_read_header,
.read_packet = v4l2_read_packet,
.read_close = v4l2_read_close,
+ .get_device_list = v4l2_get_device_list,
.flags = AVFMT_NOFILE,
.priv_class = &v4l2_class,
};
diff --git a/libavdevice/v4l2enc.c b/libavdevice/v4l2enc.c
new file mode 100644
index 0000000000..ac4068cbd4
--- /dev/null
+++ b/libavdevice/v4l2enc.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "v4l2-common.h"
+#include "avdevice.h"
+
+typedef struct {
+ AVClass *class;
+ int fd;
+} V4L2Context;
+
+static av_cold int write_header(AVFormatContext *s1)
+{
+ int res = 0, flags = O_RDWR;
+ struct v4l2_format fmt = {
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT
+ };
+ V4L2Context *s = s1->priv_data;
+ AVCodecContext *enc_ctx;
+ uint32_t v4l2_pixfmt;
+
+ if (s1->flags & AVFMT_FLAG_NONBLOCK)
+ flags |= O_NONBLOCK;
+
+ s->fd = open(s1->filename, flags);
+ if (s->fd < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "Unable to open V4L2 device '%s'\n", s1->filename);
+ return res;
+ }
+
+ if (s1->nb_streams != 1 ||
+ s1->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
+ s1->streams[0]->codec->codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(s1, AV_LOG_ERROR,
+ "V4L2 output device supports only a single raw video stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ enc_ctx = s1->streams[0]->codec;
+
+ v4l2_pixfmt = ff_fmt_ff2v4l(enc_ctx->pix_fmt, AV_CODEC_ID_RAWVIDEO);
+ if (!v4l2_pixfmt) { // XXX: try to force them one by one?
+ av_log(s1, AV_LOG_ERROR, "Unknown V4L2 pixel format equivalent for %s\n",
+ av_get_pix_fmt_name(enc_ctx->pix_fmt));
+ return AVERROR(EINVAL);
+ }
+
+ if (ioctl(s->fd, VIDIOC_G_FMT, &fmt) < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_G_FMT): %s\n", av_err2str(res));
+ return res;
+ }
+
+ fmt.fmt.pix.width = enc_ctx->width;
+ fmt.fmt.pix.height = enc_ctx->height;
+ fmt.fmt.pix.pixelformat = v4l2_pixfmt;
+ fmt.fmt.pix.sizeimage = av_image_get_buffer_size(enc_ctx->pix_fmt, enc_ctx->width, enc_ctx->height, 1);
+
+ if (ioctl(s->fd, VIDIOC_S_FMT, &fmt) < 0) {
+ res = AVERROR(errno);
+ av_log(s1, AV_LOG_ERROR, "ioctl(VIDIOC_S_FMT): %s\n", av_err2str(res));
+ return res;
+ }
+
+ return res;
+}
+
+static int write_packet(AVFormatContext *s1, AVPacket *pkt)
+{
+ const V4L2Context *s = s1->priv_data;
+ if (write(s->fd, pkt->data, pkt->size) == -1)
+ return AVERROR(errno);
+ return 0;
+}
+
+static int write_trailer(AVFormatContext *s1)
+{
+ const V4L2Context *s = s1->priv_data;
+ close(s->fd);
+ return 0;
+}
+
+static const AVClass v4l2_class = {
+ .class_name = "V4L2 outdev",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_v4l2_muxer = {
+ .name = "v4l2",
+ .long_name = NULL_IF_CONFIG_SMALL("Video4Linux2 output device"),
+ .priv_data_size = sizeof(V4L2Context),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = write_header,
+ .write_packet = write_packet,
+ .write_trailer = write_trailer,
+ .flags = AVFMT_NOFILE,
+ .priv_class = &v4l2_class,
+};
diff --git a/libavdevice/version.h b/libavdevice/version.h
index 9453234bf8..8de07f08b2 100644
--- a/libavdevice/version.h
+++ b/libavdevice/version.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,9 +27,9 @@
#include "libavutil/version.h"
-#define LIBAVDEVICE_VERSION_MAJOR 55
-#define LIBAVDEVICE_VERSION_MINOR 1
-#define LIBAVDEVICE_VERSION_MICRO 0
+#define LIBAVDEVICE_VERSION_MAJOR 56
+#define LIBAVDEVICE_VERSION_MINOR 4
+#define LIBAVDEVICE_VERSION_MICRO 100
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \
@@ -39,6 +39,8 @@
LIBAVDEVICE_VERSION_MICRO)
#define LIBAVDEVICE_BUILD LIBAVDEVICE_VERSION_INT
+#define LIBAVDEVICE_IDENT "Lavd" AV_STRINGIFY(LIBAVDEVICE_VERSION)
+
/**
* FF_API_* defines may be placed below to indicate public API that will be
* dropped at a future version bump. The defines themselves are not part of
diff --git a/libavdevice/vfwcap.c b/libavdevice/vfwcap.c
index 5e2ba844ef..10e6c69dcb 100644
--- a/libavdevice/vfwcap.c
+++ b/libavdevice/vfwcap.c
@@ -2,20 +2,20 @@
* VFW capture interface
* Copyright (c) 2006-2008 Ramiro Polla
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,7 +24,6 @@
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
// windows.h must no be included before winsock2.h, and libavformat internal
@@ -33,6 +32,8 @@
// windows.h needs to be included before vfw.h
#include <vfw.h>
+#include "avdevice.h"
+
/* Some obsolete versions of MinGW32 before 4.0.0 lack this. */
#ifndef HWND_MESSAGE
#define HWND_MESSAGE ((HWND) -3)
@@ -160,7 +161,7 @@ static void dump_bih(AVFormatContext *s, BITMAPINFOHEADER *bih)
static int shall_we_drop(AVFormatContext *s)
{
struct vfw_ctx *ctx = s->priv_data;
- const uint8_t dropscore[] = {62, 75, 87, 100};
+ static const uint8_t dropscore[] = {62, 75, 87, 100};
const int ndropscores = FF_ARRAY_ELEMS(dropscore);
unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer;
@@ -248,7 +249,7 @@ static int vfw_read_header(AVFormatContext *s)
AVStream *st;
int devnum;
int bisize;
- BITMAPINFO *bi;
+ BITMAPINFO *bi = NULL;
CAPTUREPARMS cparms;
DWORD biCompression;
WORD biBitCount;
@@ -294,7 +295,7 @@ static int vfw_read_header(AVFormatContext *s)
(LPARAM) videostream_cb);
if(!ret) {
av_log(s, AV_LOG_ERROR, "Could not set video stream callback.\n");
- goto fail_io;
+ goto fail;
}
SetWindowLongPtr(ctx->hwnd, GWLP_USERDATA, (LONG_PTR) s);
@@ -308,7 +309,7 @@ static int vfw_read_header(AVFormatContext *s)
/* Set video format */
bisize = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, 0, 0);
if(!bisize)
- goto fail_io;
+ goto fail;
bi = av_malloc(bisize);
if(!bi) {
vfw_read_close(s);
@@ -316,16 +317,21 @@ static int vfw_read_header(AVFormatContext *s)
}
ret = SendMessage(ctx->hwnd, WM_CAP_GET_VIDEOFORMAT, bisize, (LPARAM) bi);
if(!ret)
- goto fail_bi;
+ goto fail;
dump_bih(s, &bi->bmiHeader);
+ ret = av_parse_video_rate(&framerate_q, ctx->framerate);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
+ goto fail;
+ }
if (ctx->video_size) {
ret = av_parse_video_size(&bi->bmiHeader.biWidth, &bi->bmiHeader.biHeight, ctx->video_size);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Couldn't parse video size.\n");
- goto fail_bi;
+ goto fail;
}
}
@@ -344,19 +350,17 @@ static int vfw_read_header(AVFormatContext *s)
ret = SendMessage(ctx->hwnd, WM_CAP_SET_VIDEOFORMAT, bisize, (LPARAM) bi);
if(!ret) {
av_log(s, AV_LOG_ERROR, "Could not set Video Format.\n");
- goto fail_bi;
+ goto fail;
}
biCompression = bi->bmiHeader.biCompression;
biBitCount = bi->bmiHeader.biBitCount;
- av_free(bi);
-
/* Set sequence setup */
ret = SendMessage(ctx->hwnd, WM_CAP_GET_SEQUENCE_SETUP, sizeof(cparms),
(LPARAM) &cparms);
if(!ret)
- goto fail_io;
+ goto fail;
dump_captureparms(s, &cparms);
@@ -371,10 +375,10 @@ static int vfw_read_header(AVFormatContext *s)
ret = SendMessage(ctx->hwnd, WM_CAP_SET_SEQUENCE_SETUP, sizeof(cparms),
(LPARAM) &cparms);
if(!ret)
- goto fail_io;
+ goto fail;
codec = st->codec;
- codec->time_base = (AVRational){framerate_q.den, framerate_q.num};
+ codec->time_base = av_inv_q(framerate_q);
codec->codec_type = AVMEDIA_TYPE_VIDEO;
codec->width = bi->bmiHeader.biWidth;
codec->height = bi->bmiHeader.biHeight;
@@ -400,31 +404,31 @@ static int vfw_read_header(AVFormatContext *s)
}
}
+ av_freep(&bi);
+
avpriv_set_pts_info(st, 32, 1, 1000);
ctx->mutex = CreateMutex(NULL, 0, NULL);
if(!ctx->mutex) {
av_log(s, AV_LOG_ERROR, "Could not create Mutex.\n" );
- goto fail_io;
+ goto fail;
}
ctx->event = CreateEvent(NULL, 1, 0, NULL);
if(!ctx->event) {
av_log(s, AV_LOG_ERROR, "Could not create Event.\n" );
- goto fail_io;
+ goto fail;
}
ret = SendMessage(ctx->hwnd, WM_CAP_SEQUENCE_NOFILE, 0, 0);
if(!ret) {
av_log(s, AV_LOG_ERROR, "Could not start capture sequence.\n" );
- goto fail_io;
+ goto fail;
}
return 0;
-fail_bi:
- av_free(bi);
-
-fail_io:
+fail:
+ av_freep(&bi);
vfw_read_close(s);
return AVERROR(EIO);
}
@@ -471,6 +475,7 @@ static const AVClass vfw_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
};
AVInputFormat ff_vfwcap_demuxer = {
diff --git a/libavdevice/x11grab.c b/libavdevice/x11grab.c
index b2721ae8c6..d3b0b02e91 100644
--- a/libavdevice/x11grab.c
+++ b/libavdevice/x11grab.c
@@ -1,9 +1,9 @@
/*
* X11 video grab interface
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav integration:
+ * FFmpeg integration:
* Copyright (C) 2006 Clemens Fruhwirth <clemens@endorphin.org>
* Edouard Gomez <ed.gomez@free.fr>
*
@@ -14,18 +14,18 @@
* Copyright (C) 1997-1998 Rasca, Berlin
* 2003-2004 Karl H. Beckers, Frankfurt
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software
+ * along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,6 +41,7 @@
#include <time.h>
#include <sys/shm.h>
+#include <X11/cursorfont.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xlibint.h>
@@ -57,9 +58,10 @@
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
-#include "libavformat/avformat.h"
#include "libavformat/internal.h"
+#include "avdevice.h"
+
/** X11 device demuxer context */
typedef struct X11GrabContext {
const AVClass *class; /**< Class for private options. */
@@ -67,9 +69,8 @@ typedef struct X11GrabContext {
AVRational time_base; /**< Time base */
int64_t time_frame; /**< Current time */
- char *video_size; /**< String describing video size, set by a private option. */
- int height; /**< Height of the grab frame */
int width; /**< Width of the grab frame */
+ int height; /**< Height of the grab frame */
int x_off; /**< Horizontal top-left corner coordinate */
int y_off; /**< Vertical top-left corner coordinate */
@@ -80,8 +81,11 @@ typedef struct X11GrabContext {
int draw_mouse; /**< Set by a private option. */
int follow_mouse; /**< Set by a private option. */
int show_region; /**< set by a private option. */
- char *framerate; /**< Set by a private option. */
+ AVRational framerate; /**< Set by a private option. */
+ int palette_changed;
+ uint32_t palette[256];
+ Cursor c;
Window region_win; /**< This is used by show_region option. */
} X11GrabContext;
@@ -191,6 +195,8 @@ static int pixfmt_from_image(AVFormatContext *s, XImage *image, int *pix_fmt)
image->blue_mask,
image->bits_per_pixel);
+ *pix_fmt = AV_PIX_FMT_NONE;
+
switch (image->bits_per_pixel) {
case 8:
*pix_fmt = AV_PIX_FMT_PAL8;
@@ -218,9 +224,14 @@ static int pixfmt_from_image(AVFormatContext *s, XImage *image, int *pix_fmt)
}
break;
case 32:
- *pix_fmt = AV_PIX_FMT_RGB32;
+ if (image->red_mask == 0xff0000 &&
+ image->green_mask == 0x00ff00 &&
+ image->blue_mask == 0x0000ff ) {
+ *pix_fmt = AV_PIX_FMT_0RGB32;
+ }
break;
- default:
+ }
+ if (*pix_fmt == AV_PIX_FMT_NONE) {
av_log(s, AV_LOG_ERROR,
"XImages with RGB mask 0x%.6lx 0x%.6lx 0x%.6lx and depth %i "
"are currently not supported.\n",
@@ -251,39 +262,34 @@ static int x11grab_read_header(AVFormatContext *s1)
Display *dpy;
AVStream *st = NULL;
XImage *image;
- int x_off = 0, y_off = 0, ret = 0, screen, use_shm;
- char *param, *offset;
- AVRational framerate;
-
- param = av_strdup(s1->filename);
- if (!param)
+ int x_off = 0, y_off = 0, ret = 0, screen, use_shm = 0;
+ char *dpyname, *offset;
+ Colormap color_map;
+ XColor color[256];
+ int i;
+
+ dpyname = av_strdup(s1->filename);
+ if (!dpyname)
goto out;
- offset = strchr(param, '+');
+ offset = strchr(dpyname, '+');
if (offset) {
sscanf(offset, "%d,%d", &x_off, &y_off);
- x11grab->draw_mouse = !strstr(offset, "nomouse");
+ if (strstr(offset, "nomouse")) {
+ av_log(s1, AV_LOG_WARNING,
+ "'nomouse' specification in argument is deprecated: "
+ "use 'draw_mouse' option with value 0 instead\n");
+ x11grab->draw_mouse = 0;
+ }
*offset = 0;
}
- ret = av_parse_video_size(&x11grab->width, &x11grab->height,
- x11grab->video_size);
- if (ret < 0) {
- av_log(s1, AV_LOG_ERROR, "Couldn't parse video size.\n");
- goto out;
- }
-
- ret = av_parse_video_rate(&framerate, x11grab->framerate);
- if (ret < 0) {
- av_log(s1, AV_LOG_ERROR, "Could not parse framerate: %s.\n",
- x11grab->framerate);
- goto out;
- }
av_log(s1, AV_LOG_INFO,
"device: %s -> display: %s x: %d y: %d width: %d height: %d\n",
- s1->filename, param, x_off, y_off, x11grab->width, x11grab->height);
+ s1->filename, dpyname, x_off, y_off, x11grab->width, x11grab->height);
- dpy = XOpenDisplay(param);
+ dpy = XOpenDisplay(dpyname);
+ av_freep(&dpyname);
if (!dpy) {
av_log(s1, AV_LOG_ERROR, "Could not open X display.\n");
ret = AVERROR(EIO);
@@ -316,9 +322,11 @@ static int x11grab_read_header(AVFormatContext *s1)
x_off, y_off);
}
- use_shm = XShmQueryExtension(dpy);
- av_log(s1, AV_LOG_INFO,
- "shared memory extension %sfound\n", use_shm ? "" : "not ");
+ if (x11grab->use_shm) {
+ use_shm = XShmQueryExtension(dpy);
+ av_log(s1, AV_LOG_INFO,
+ "shared memory extension %sfound\n", use_shm ? "" : "not ");
+ }
if (use_shm && setup_shm(s1, dpy, &image) < 0) {
av_log(s1, AV_LOG_WARNING, "Falling back to XGetImage\n");
@@ -340,7 +348,7 @@ static int x11grab_read_header(AVFormatContext *s1)
x11grab->frame_size = x11grab->width * x11grab->height * image->bits_per_pixel / 8;
x11grab->dpy = dpy;
- x11grab->time_base = (AVRational) { framerate.den, framerate.num };
+ x11grab->time_base = av_inv_q(x11grab->framerate);
x11grab->time_frame = av_gettime() / av_q2d(x11grab->time_base);
x11grab->x_off = x_off;
x11grab->y_off = y_off;
@@ -351,6 +359,19 @@ static int x11grab_read_header(AVFormatContext *s1)
if (ret < 0)
goto out;
+ if (st->codec->pix_fmt == AV_PIX_FMT_PAL8) {
+ color_map = DefaultColormap(dpy, screen);
+ for (i = 0; i < 256; ++i)
+ color[i].pixel = i;
+ XQueryColors(dpy, color_map, color, 256);
+ for (i = 0; i < 256; ++i)
+ x11grab->palette[i] = (color[i].red & 0xFF00) << 8 |
+ (color[i].green & 0xFF00) |
+ (color[i].blue & 0xFF00) >> 8;
+ x11grab->palette_changed = 1;
+ }
+
+
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
st->codec->width = x11grab->width;
@@ -359,7 +380,7 @@ static int x11grab_read_header(AVFormatContext *s1)
st->codec->bit_rate = x11grab->frame_size * 1 / av_q2d(x11grab->time_base) * 8;
out:
- av_free(param);
+ av_free(dpyname);
return ret;
}
@@ -370,8 +391,9 @@ out:
* @param s context used to retrieve original grabbing rectangle
* coordinates
*/
-static void paint_mouse_pointer(XImage *image, X11GrabContext *s)
+static void paint_mouse_pointer(XImage *image, AVFormatContext *s1)
{
+ X11GrabContext *s = s1->priv_data;
int x_off = s->x_off;
int y_off = s->y_off;
int width = s->width;
@@ -387,14 +409,25 @@ static void paint_mouse_pointer(XImage *image, X11GrabContext *s)
* Anyone who performs further investigation of the xlib API likely risks
* permanent brain damage. */
uint8_t *pix = image->data;
+ Window root;
+ XSetWindowAttributes attr;
/* Code doesn't currently support 16-bit or PAL8 */
if (image->bits_per_pixel != 24 && image->bits_per_pixel != 32)
return;
+ if (!s->c)
+ s->c = XCreateFontCursor(dpy, XC_left_ptr);
+ root = DefaultRootWindow(dpy);
+ attr.cursor = s->c;
+ XChangeWindowAttributes(dpy, root, CWCursor, &attr);
+
xcim = XFixesGetCursorImage(dpy);
- if (!xcim)
+ if (!xcim) {
+ av_log(s1, AV_LOG_WARNING,
+ "XFixesGetCursorImage failed\n");
return;
+ }
x = xcim->x - xcim->xhot;
y = xcim->y - xcim->yhot;
@@ -514,6 +547,16 @@ static int x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
pkt->data = image->data;
pkt->size = s->frame_size;
pkt->pts = curtime;
+ if (s->palette_changed) {
+ uint8_t *pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE,
+ AVPALETTE_SIZE);
+ if (!pal) {
+ av_log(s, AV_LOG_ERROR, "Cannot append palette to packet\n");
+ } else {
+ memcpy(pal, s->palette, AVPALETTE_SIZE);
+ s->palette_changed = 0;
+ }
+ }
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
@@ -576,7 +619,7 @@ static int x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
}
if (s->draw_mouse && same_screen)
- paint_mouse_pointer(image, s);
+ paint_mouse_pointer(image, s1);
return s->frame_size;
}
@@ -617,13 +660,17 @@ static int x11grab_read_close(AVFormatContext *s1)
static const AVOption options[] = {
{ "grab_x", "Initial x coordinate.", OFFSET(x_off), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
{ "grab_y", "Initial y coordinate.", OFFSET(y_off), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, DEC },
- { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = "vga"}, 0, 0, DEC },
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC },
- { "draw_mouse", "Draw the mouse pointer.", OFFSET(draw_mouse), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, DEC },
- { "follow_mouse", "Move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region.",
- OFFSET(follow_mouse), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT_MAX, DEC, "follow_mouse" },
- { "centered", "Keep the mouse pointer at the center of grabbing region when following.", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, INT_MIN, INT_MAX, DEC, "follow_mouse" },
- { "show_region", "Show the grabbing region.", OFFSET(show_region), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC },
+ { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
+
+ { "follow_mouse", "move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region",
+ OFFSET(follow_mouse), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, DEC, "follow_mouse" },
+ { "centered", "keep the mouse pointer at the center of grabbing region when following",
+ 0, AV_OPT_TYPE_CONST, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "follow_mouse" },
+
+ { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, 0, DEC },
+ { "show_region", "show the grabbing region", OFFSET(show_region), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
+ { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "vga"}, 0, 0, DEC },
+ { "use_shm", "use MIT-SHM extension", OFFSET(use_shm), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
{ NULL },
};
@@ -632,6 +679,7 @@ static const AVClass x11_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
/** x11 grabber device demuxer declaration */
diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c
index 96cad8f3f2..166575c9c2 100644
--- a/libavdevice/xcbgrab.c
+++ b/libavdevice/xcbgrab.c
@@ -2,20 +2,20 @@
* XCB input grabber
* Copyright (C) 2014 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,10 @@
#include <xcb/shm.h>
#endif
+#if CONFIG_LIBXCB_SHAPE
+#include <xcb/shape.h>
+#endif
+
#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -96,6 +100,7 @@ static const AVClass xcbgrab_class = {
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
};
static int xcbgrab_reposition(AVFormatContext *s,
@@ -468,11 +473,11 @@ static int pixfmt_from_pixmap_format(AVFormatContext *s, int depth,
switch (depth) {
case 32:
if (fmt->bits_per_pixel == 32)
- *pix_fmt = AV_PIX_FMT_ARGB;
+ *pix_fmt = AV_PIX_FMT_0RGB;
break;
case 24:
if (fmt->bits_per_pixel == 32)
- *pix_fmt = AV_PIX_FMT_RGB32;
+ *pix_fmt = AV_PIX_FMT_0RGB32;
else if (fmt->bits_per_pixel == 24)
*pix_fmt = AV_PIX_FMT_RGB24;
break;
@@ -602,11 +607,13 @@ static void setup_window(AVFormatContext *s)
XCB_COPY_FROM_PARENT,
mask, values);
+#if CONFIG_LIBXCB_SHAPE
xcb_shape_rectangles(c->conn, XCB_SHAPE_SO_SUBTRACT,
XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
c->window,
c->region_border, c->region_border,
1, &rect);
+#endif
xcb_map_window(c->conn, c->window);
@@ -618,30 +625,25 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s)
XCBGrabContext *c = s->priv_data;
int screen_num, ret;
const xcb_setup_t *setup;
- char *host = s->filename[0] ? s->filename : NULL;
- const char *opts = strchr(s->filename, '+');
-
- if (opts) {
- sscanf(opts, "%d,%d", &c->x, &c->y);
- host = av_strdup(s->filename);
- if (!host)
- return AVERROR(ENOMEM);
- host[opts - s->filename] = '\0';
+ char *display_name = av_strdup(s->filename);
+
+ if (!display_name)
+ return AVERROR(ENOMEM);
+
+ if (!sscanf(s->filename, "%[^+]+%d,%d", display_name, &c->x, &c->y)) {
+ *display_name = 0;
+ sscanf(s->filename, "+%d,%d", &c->x, &c->y);
}
- c->conn = xcb_connect(host, &screen_num);
+ c->conn = xcb_connect(display_name[0] ? display_name : NULL, &screen_num);
+ av_freep(&display_name);
if ((ret = xcb_connection_has_error(c->conn))) {
av_log(s, AV_LOG_ERROR, "Cannot open display %s, error %d.\n",
- s->filename[0] ? host : "default", ret);
- if (opts)
- av_freep(&host);
+ s->filename[0] ? s->filename : "default", ret);
return AVERROR(EIO);
}
- if (opts)
- av_freep(&host);
-
setup = xcb_get_setup(c->conn);
c->screen = get_screen(setup, screen_num);
diff --git a/libavdevice/xv.c b/libavdevice/xv.c
new file mode 100644
index 0000000000..c19c15c234
--- /dev/null
+++ b/libavdevice/xv.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2013 Jeff Moguillansky
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * XVideo output device
+ *
+ * TODO:
+ * - add support to more formats
+ */
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xvlib.h>
+#include <sys/shm.h>
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/imgutils.h"
+#include "libavformat/internal.h"
+#include "avdevice.h"
+
+typedef struct {
+ AVClass *class;
+ GC gc;
+
+ Window window;
+ int64_t window_id;
+ char *window_title;
+ int window_width, window_height;
+ int window_x, window_y;
+ int dest_x, dest_y; /**< display area position */
+ unsigned int dest_w, dest_h; /**< display area dimensions */
+
+ Display* display;
+ char *display_name;
+
+ XvImage* yuv_image;
+ enum AVPixelFormat image_format;
+ int image_width, image_height;
+ XShmSegmentInfo yuv_shminfo;
+ int xv_port;
+ Atom wm_delete_message;
+} XVContext;
+
+typedef struct XVTagFormatMap
+{
+ int tag;
+ enum AVPixelFormat format;
+} XVTagFormatMap;
+
+static const XVTagFormatMap tag_codec_map[] = {
+ { MKTAG('I','4','2','0'), AV_PIX_FMT_YUV420P },
+ { MKTAG('U','Y','V','Y'), AV_PIX_FMT_UYVY422 },
+ { MKTAG('Y','U','Y','2'), AV_PIX_FMT_YUYV422 },
+ { 0, AV_PIX_FMT_NONE }
+};
+
+static int xv_get_tag_from_format(enum AVPixelFormat format)
+{
+ const XVTagFormatMap *m = tag_codec_map;
+ int i;
+ for (i = 0; m->tag; m = &tag_codec_map[++i]) {
+ if (m->format == format)
+ return m->tag;
+ }
+ return 0;
+}
+
+static int xv_write_trailer(AVFormatContext *s)
+{
+ XVContext *xv = s->priv_data;
+ if (xv->display) {
+ XShmDetach(xv->display, &xv->yuv_shminfo);
+ if (xv->yuv_image)
+ shmdt(xv->yuv_image->data);
+ XFree(xv->yuv_image);
+ if (xv->gc)
+ XFreeGC(xv->display, xv->gc);
+ XCloseDisplay(xv->display);
+ }
+ return 0;
+}
+
+static int xv_write_header(AVFormatContext *s)
+{
+ XVContext *xv = s->priv_data;
+ unsigned int num_adaptors;
+ XvAdaptorInfo *ai;
+ XvImageFormatValues *fv;
+ XColor fgcolor;
+ XWindowAttributes window_attrs;
+ int num_formats = 0, j, tag, ret;
+ AVCodecContext *encctx = s->streams[0]->codec;
+
+ if ( s->nb_streams > 1
+ || encctx->codec_type != AVMEDIA_TYPE_VIDEO
+ || encctx->codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(s, AV_LOG_ERROR, "Only supports one rawvideo stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!(tag = xv_get_tag_from_format(encctx->pix_fmt))) {
+ av_log(s, AV_LOG_ERROR,
+ "Unsupported pixel format '%s', only yuv420p, uyvy422, yuyv422 are currently supported\n",
+ av_get_pix_fmt_name(encctx->pix_fmt));
+ return AVERROR_PATCHWELCOME;
+ }
+ xv->image_format = encctx->pix_fmt;
+
+ xv->display = XOpenDisplay(xv->display_name);
+ if (!xv->display) {
+ av_log(s, AV_LOG_ERROR, "Could not open the X11 display '%s'\n", xv->display_name);
+ return AVERROR(EINVAL);
+ }
+
+ xv->image_width = encctx->width;
+ xv->image_height = encctx->height;
+ if (!xv->window_width && !xv->window_height) {
+ AVRational sar = encctx->sample_aspect_ratio;
+ xv->window_width = encctx->width;
+ xv->window_height = encctx->height;
+ if (sar.num) {
+ if (sar.num > sar.den)
+ xv->window_width = av_rescale(xv->window_width, sar.num, sar.den);
+ if (sar.num < sar.den)
+ xv->window_height = av_rescale(xv->window_height, sar.den, sar.num);
+ }
+ }
+ if (!xv->window_id) {
+ xv->window = XCreateSimpleWindow(xv->display, DefaultRootWindow(xv->display),
+ xv->window_x, xv->window_y,
+ xv->window_width, xv->window_height,
+ 0, 0, 0);
+ if (!xv->window_title) {
+ if (!(xv->window_title = av_strdup(s->filename))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ XStoreName(xv->display, xv->window, xv->window_title);
+ xv->wm_delete_message = XInternAtom(xv->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(xv->display, xv->window, &xv->wm_delete_message, 1);
+ XMapWindow(xv->display, xv->window);
+ } else
+ xv->window = xv->window_id;
+
+ if (XvQueryAdaptors(xv->display, DefaultRootWindow(xv->display), &num_adaptors, &ai) != Success) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ if (!num_adaptors) {
+ av_log(s, AV_LOG_ERROR, "No X-Video adaptors present\n");
+ return AVERROR(ENODEV);
+ }
+ xv->xv_port = ai[0].base_id;
+ XvFreeAdaptorInfo(ai);
+
+ fv = XvListImageFormats(xv->display, xv->xv_port, &num_formats);
+ if (!fv) {
+ ret = AVERROR_EXTERNAL;
+ goto fail;
+ }
+ for (j = 0; j < num_formats; j++) {
+ if (fv[j].id == tag) {
+ break;
+ }
+ }
+ XFree(fv);
+
+ if (j >= num_formats) {
+ av_log(s, AV_LOG_ERROR,
+ "Device does not support pixel format %s, aborting\n",
+ av_get_pix_fmt_name(encctx->pix_fmt));
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ xv->gc = XCreateGC(xv->display, xv->window, 0, 0);
+ xv->image_width = encctx->width;
+ xv->image_height = encctx->height;
+ xv->yuv_image = XvShmCreateImage(xv->display, xv->xv_port, tag, 0,
+ xv->image_width, xv->image_height, &xv->yuv_shminfo);
+ xv->yuv_shminfo.shmid = shmget(IPC_PRIVATE, xv->yuv_image->data_size,
+ IPC_CREAT | 0777);
+ xv->yuv_shminfo.shmaddr = (char *)shmat(xv->yuv_shminfo.shmid, 0, 0);
+ xv->yuv_image->data = xv->yuv_shminfo.shmaddr;
+ xv->yuv_shminfo.readOnly = False;
+
+ XShmAttach(xv->display, &xv->yuv_shminfo);
+ XSync(xv->display, False);
+ shmctl(xv->yuv_shminfo.shmid, IPC_RMID, 0);
+
+ XGetWindowAttributes(xv->display, xv->window, &window_attrs);
+ fgcolor.red = fgcolor.green = fgcolor.blue = 0;
+ fgcolor.flags = DoRed | DoGreen | DoBlue;
+ XAllocColor(xv->display, window_attrs.colormap, &fgcolor);
+ XSetForeground(xv->display, xv->gc, fgcolor.pixel);
+ //force display area recalculation at first frame
+ xv->window_width = xv->window_height = 0;
+
+ return 0;
+ fail:
+ xv_write_trailer(s);
+ return ret;
+}
+
+static void compute_display_area(AVFormatContext *s)
+{
+ XVContext *xv = s->priv_data;
+ AVRational sar, dar; /* sample and display aspect ratios */
+ AVStream *st = s->streams[0];
+ AVCodecContext *encctx = st->codec;
+
+ /* compute overlay width and height from the codec context information */
+ sar = st->sample_aspect_ratio.num ? st->sample_aspect_ratio : (AVRational){ 1, 1 };
+ dar = av_mul_q(sar, (AVRational){ encctx->width, encctx->height });
+
+ /* we suppose the screen has a 1/1 sample aspect ratio */
+ /* fit in the window */
+ if (av_cmp_q(dar, (AVRational){ xv->dest_w, xv->dest_h }) > 0) {
+ /* fit in width */
+ xv->dest_y = xv->dest_h;
+ xv->dest_x = 0;
+ xv->dest_h = av_rescale(xv->dest_w, dar.den, dar.num);
+ xv->dest_y -= xv->dest_h;
+ xv->dest_y /= 2;
+ } else {
+ /* fit in height */
+ xv->dest_x = xv->dest_w;
+ xv->dest_y = 0;
+ xv->dest_w = av_rescale(xv->dest_h, dar.num, dar.den);
+ xv->dest_x -= xv->dest_w;
+ xv->dest_x /= 2;
+ }
+}
+
+static int xv_repaint(AVFormatContext *s)
+{
+ XVContext *xv = s->priv_data;
+ XWindowAttributes window_attrs;
+
+ XGetWindowAttributes(xv->display, xv->window, &window_attrs);
+ if (window_attrs.width != xv->window_width || window_attrs.height != xv->window_height) {
+ XRectangle rect[2];
+ xv->dest_w = window_attrs.width;
+ xv->dest_h = window_attrs.height;
+ compute_display_area(s);
+ if (xv->dest_x) {
+ rect[0].width = rect[1].width = xv->dest_x;
+ rect[0].height = rect[1].height = window_attrs.height;
+ rect[0].y = rect[1].y = 0;
+ rect[0].x = 0;
+ rect[1].x = xv->dest_w + xv->dest_x;
+ XFillRectangles(xv->display, xv->window, xv->gc, rect, 2);
+ }
+ if (xv->dest_y) {
+ rect[0].width = rect[1].width = window_attrs.width;
+ rect[0].height = rect[1].height = xv->dest_y;
+ rect[0].x = rect[1].x = 0;
+ rect[0].y = 0;
+ rect[1].y = xv->dest_h + xv->dest_y;
+ XFillRectangles(xv->display, xv->window, xv->gc, rect, 2);
+ }
+ }
+
+ if (XvShmPutImage(xv->display, xv->xv_port, xv->window, xv->gc,
+ xv->yuv_image, 0, 0, xv->image_width, xv->image_height,
+ xv->dest_x, xv->dest_y, xv->dest_w, xv->dest_h, True) != Success) {
+ av_log(s, AV_LOG_ERROR, "Could not copy image to XV shared memory buffer\n");
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+static int write_picture(AVFormatContext *s, AVPicture *pict)
+{
+ XVContext *xv = s->priv_data;
+ XvImage *img = xv->yuv_image;
+ uint8_t *data[3] = {
+ img->data + img->offsets[0],
+ img->data + img->offsets[1],
+ img->data + img->offsets[2]
+ };
+
+ /* Check messages. Window might get closed. */
+ if (!xv->window_id) {
+ XEvent event;
+ while (XPending(xv->display)) {
+ XNextEvent(xv->display, &event);
+ if (event.type == ClientMessage && event.xclient.data.l[0] == xv->wm_delete_message) {
+ av_log(xv, AV_LOG_DEBUG, "Window close event.\n");
+ return AVERROR(EPIPE);
+ }
+ }
+ }
+
+ av_image_copy(data, img->pitches, (const uint8_t **)pict->data, pict->linesize,
+ xv->image_format, img->width, img->height);
+ return xv_repaint(s);
+}
+
+static int xv_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVPicture pict;
+ AVCodecContext *ctx = s->streams[0]->codec;
+
+ avpicture_fill(&pict, pkt->data, ctx->pix_fmt, ctx->width, ctx->height);
+ return write_picture(s, &pict);
+}
+
+static int xv_write_frame(AVFormatContext *s, int stream_index, AVFrame **frame,
+ unsigned flags)
+{
+ /* xv_write_header() should have accepted only supported formats */
+ if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
+ return 0;
+ return write_picture(s, (AVPicture *)*frame);
+}
+
+static int xv_control_message(AVFormatContext *s, int type, void *data, size_t data_size)
+{
+ switch(type) {
+ case AV_APP_TO_DEV_WINDOW_REPAINT:
+ return xv_repaint(s);
+ default:
+ break;
+ }
+ return AVERROR(ENOSYS);
+}
+
+#define OFFSET(x) offsetof(XVContext, x)
+static const AVOption options[] = {
+ { "display_name", "set display name", OFFSET(display_name), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_id", "set existing window id", OFFSET(window_id), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_size", "set window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_title", "set window title", OFFSET(window_title), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_x", "set window x offset", OFFSET(window_x), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "window_y", "set window y offset", OFFSET(window_y), AV_OPT_TYPE_INT, {.i64 = 0 }, -INT_MAX, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL }
+
+};
+
+static const AVClass xv_class = {
+ .class_name = "xvideo outdev",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT,
+};
+
+AVOutputFormat ff_xv_muxer = {
+ .name = "xv",
+ .long_name = NULL_IF_CONFIG_SMALL("XV (XVideo) output device"),
+ .priv_data_size = sizeof(XVContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = xv_write_header,
+ .write_packet = xv_write_packet,
+ .write_uncoded_frame = xv_write_frame,
+ .write_trailer = xv_write_trailer,
+ .control_message = xv_control_message,
+ .flags = AVFMT_NOFILE | AVFMT_VARIABLE_FPS | AVFMT_NOTIMESTAMPS,
+ .priv_class = &xv_class,
+};
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 7b94f2252a..bf5a54982e 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -1,6 +1,10 @@
+include $(SUBDIR)../config.mak
+
NAME = avfilter
-HEADERS = avfilter.h \
+HEADERS = asrc_abuffer.h \
+ avcodec.h \
+ avfilter.h \
avfiltergraph.h \
buffersink.h \
buffersrc.h \
@@ -16,83 +20,245 @@ OBJS = allfilters.o \
drawutils.o \
fifo.o \
formats.o \
+ graphdump.o \
graphparser.o \
+ opencl_allkernels.o \
+ transform.o \
video.o \
+
+OBJS-$(CONFIG_AVCODEC) += avcodec.o
+
+OBJS-$(CONFIG_ADELAY_FILTER) += af_adelay.o
+OBJS-$(CONFIG_AECHO_FILTER) += af_aecho.o
+OBJS-$(CONFIG_AEVAL_FILTER) += aeval.o
+OBJS-$(CONFIG_AFADE_FILTER) += af_afade.o
OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o
+OBJS-$(CONFIG_AINTERLEAVE_FILTER) += f_interleave.o
+OBJS-$(CONFIG_ALLPASS_FILTER) += af_biquads.o
+OBJS-$(CONFIG_AMERGE_FILTER) += af_amerge.o
OBJS-$(CONFIG_AMIX_FILTER) += af_amix.o
OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o
+OBJS-$(CONFIG_APAD_FILTER) += af_apad.o
+OBJS-$(CONFIG_APERMS_FILTER) += f_perms.o
+OBJS-$(CONFIG_APHASER_FILTER) += af_aphaser.o generate_wave_table.o
+OBJS-$(CONFIG_ARESAMPLE_FILTER) += af_aresample.o
+OBJS-$(CONFIG_ASELECT_FILTER) += f_select.o
+OBJS-$(CONFIG_ASENDCMD_FILTER) += f_sendcmd.o
+OBJS-$(CONFIG_ASETNSAMPLES_FILTER) += af_asetnsamples.o
OBJS-$(CONFIG_ASETPTS_FILTER) += setpts.o
+OBJS-$(CONFIG_ASETRATE_FILTER) += af_asetrate.o
OBJS-$(CONFIG_ASETTB_FILTER) += settb.o
OBJS-$(CONFIG_ASHOWINFO_FILTER) += af_ashowinfo.o
OBJS-$(CONFIG_ASPLIT_FILTER) += split.o
+OBJS-$(CONFIG_ASTATS_FILTER) += af_astats.o
+OBJS-$(CONFIG_ASTREAMSYNC_FILTER) += af_astreamsync.o
OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o
+OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o
OBJS-$(CONFIG_ATRIM_FILTER) += trim.o
+OBJS-$(CONFIG_AZMQ_FILTER) += f_zmq.o
+OBJS-$(CONFIG_BANDPASS_FILTER) += af_biquads.o
+OBJS-$(CONFIG_BANDREJECT_FILTER) += af_biquads.o
+OBJS-$(CONFIG_BASS_FILTER) += af_biquads.o
+OBJS-$(CONFIG_BIQUAD_FILTER) += af_biquads.o
OBJS-$(CONFIG_BS2B_FILTER) += af_bs2b.o
OBJS-$(CONFIG_CHANNELMAP_FILTER) += af_channelmap.o
OBJS-$(CONFIG_CHANNELSPLIT_FILTER) += af_channelsplit.o
+OBJS-$(CONFIG_CHORUS_FILTER) += af_chorus.o generate_wave_table.o
OBJS-$(CONFIG_COMPAND_FILTER) += af_compand.o
+OBJS-$(CONFIG_DCSHIFT_FILTER) += af_dcshift.o
+OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o
+OBJS-$(CONFIG_EBUR128_FILTER) += f_ebur128.o
+OBJS-$(CONFIG_EQUALIZER_FILTER) += af_biquads.o
+OBJS-$(CONFIG_FLANGER_FILTER) += af_flanger.o generate_wave_table.o
+OBJS-$(CONFIG_HIGHPASS_FILTER) += af_biquads.o
OBJS-$(CONFIG_JOIN_FILTER) += af_join.o
+OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o
+OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o
+OBJS-$(CONFIG_PAN_FILTER) += af_pan.o
+OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o
OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o
+OBJS-$(CONFIG_SILENCEDETECT_FILTER) += af_silencedetect.o
+OBJS-$(CONFIG_SILENCEREMOVE_FILTER) += af_silenceremove.o
+OBJS-$(CONFIG_TREBLE_FILTER) += af_biquads.o
OBJS-$(CONFIG_VOLUME_FILTER) += af_volume.o
+OBJS-$(CONFIG_VOLUMEDETECT_FILTER) += af_volumedetect.o
+OBJS-$(CONFIG_AEVALSRC_FILTER) += aeval.o
OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o
+OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o
+OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o
OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o
+OBJS-$(CONFIG_ASS_FILTER) += vf_subtitles.o
+OBJS-$(CONFIG_ALPHAEXTRACT_FILTER) += vf_extractplanes.o
+OBJS-$(CONFIG_ALPHAMERGE_FILTER) += vf_alphamerge.o
+OBJS-$(CONFIG_BBOX_FILTER) += bbox.o vf_bbox.o
+OBJS-$(CONFIG_BLACKDETECT_FILTER) += vf_blackdetect.o
OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o
+OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o dualinput.o framesync.o
OBJS-$(CONFIG_BOXBLUR_FILTER) += vf_boxblur.o
+OBJS-$(CONFIG_CODECVIEW_FILTER) += vf_codecview.o
+OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o
+OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o
+OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o
+OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o
OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o
+OBJS-$(CONFIG_COVER_RECT_FILTER) += vf_cover_rect.o lavfutils.o
OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o
OBJS-$(CONFIG_CROPDETECT_FILTER) += vf_cropdetect.o
+OBJS-$(CONFIG_CURVES_FILTER) += vf_curves.o
+OBJS-$(CONFIG_DCTDNOIZ_FILTER) += vf_dctdnoiz.o
+OBJS-$(CONFIG_DECIMATE_FILTER) += vf_decimate.o
+OBJS-$(CONFIG_DEJUDDER_FILTER) += vf_dejudder.o
OBJS-$(CONFIG_DELOGO_FILTER) += vf_delogo.o
+OBJS-$(CONFIG_DESHAKE_FILTER) += vf_deshake.o
+OBJS-$(CONFIG_DETELECINE_FILTER) += vf_detelecine.o
OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o
+OBJS-$(CONFIG_DRAWGRID_FILTER) += vf_drawbox.o
OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o
+OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o
+OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o
+OBJS-$(CONFIG_EQ_FILTER) += vf_eq.o
+OBJS-$(CONFIG_EXTRACTPLANES_FILTER) += vf_extractplanes.o
OBJS-$(CONFIG_FADE_FILTER) += vf_fade.o
+OBJS-$(CONFIG_FFTFILT_FILTER) += vf_fftfilt.o
+OBJS-$(CONFIG_FIELD_FILTER) += vf_field.o
+OBJS-$(CONFIG_FIELDMATCH_FILTER) += vf_fieldmatch.o
OBJS-$(CONFIG_FIELDORDER_FILTER) += vf_fieldorder.o
+OBJS-$(CONFIG_FIND_RECT_FILTER) += vf_find_rect.o lavfutils.o
OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o
+OBJS-$(CONFIG_FRAMESTEP_FILTER) += vf_framestep.o
OBJS-$(CONFIG_FPS_FILTER) += vf_fps.o
OBJS-$(CONFIG_FRAMEPACK_FILTER) += vf_framepack.o
OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o
+OBJS-$(CONFIG_FSPP_FILTER) += vf_fspp.o
+OBJS-$(CONFIG_GEQ_FILTER) += vf_geq.o
OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o
+OBJS-$(CONFIG_HALDCLUT_FILTER) += vf_lut3d.o dualinput.o framesync.o
OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o
+OBJS-$(CONFIG_HISTEQ_FILTER) += vf_histeq.o
+OBJS-$(CONFIG_HISTOGRAM_FILTER) += vf_histogram.o
OBJS-$(CONFIG_HQDN3D_FILTER) += vf_hqdn3d.o
+OBJS-$(CONFIG_HQX_FILTER) += vf_hqx.o
+OBJS-$(CONFIG_HUE_FILTER) += vf_hue.o
+OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o
+OBJS-$(CONFIG_IL_FILTER) += vf_il.o
OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o
+OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o
+OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o
+OBJS-$(CONFIG_LENSCORRECTION_FILTER) += vf_lenscorrection.o
+OBJS-$(CONFIG_LUT3D_FILTER) += vf_lut3d.o
OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o
OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o
OBJS-$(CONFIG_LUTYUV_FILTER) += vf_lut.o
+OBJS-$(CONFIG_MCDEINT_FILTER) += vf_mcdeint.o
+OBJS-$(CONFIG_MERGEPLANES_FILTER) += vf_mergeplanes.o framesync.o
+OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o
OBJS-$(CONFIG_NEGATE_FILTER) += vf_lut.o
OBJS-$(CONFIG_NOFORMAT_FILTER) += vf_format.o
+OBJS-$(CONFIG_NOISE_FILTER) += vf_noise.o
OBJS-$(CONFIG_NULL_FILTER) += vf_null.o
OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o
-OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o
+OBJS-$(CONFIG_OPENCL) += deshake_opencl.o unsharp_opencl.o
+OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o dualinput.o framesync.o
+OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o
OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o
+OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o
+OBJS-$(CONFIG_PALETTEUSE_FILTER) += vf_paletteuse.o dualinput.o framesync.o
+OBJS-$(CONFIG_PERMS_FILTER) += f_perms.o
+OBJS-$(CONFIG_PERSPECTIVE_FILTER) += vf_perspective.o
+OBJS-$(CONFIG_PHASE_FILTER) += vf_phase.o
OBJS-$(CONFIG_PIXDESCTEST_FILTER) += vf_pixdesctest.o
+OBJS-$(CONFIG_PP_FILTER) += vf_pp.o
+OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o
+OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o dualinput.o framesync.o
+OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o
+OBJS-$(CONFIG_QP_FILTER) += vf_qp.o
+OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o
+OBJS-$(CONFIG_REPEATFIELDS_FILTER) += vf_repeatfields.o
+OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o
+OBJS-$(CONFIG_SEPARATEFIELDS_FILTER) += vf_separatefields.o
+OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o
OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o
-OBJS-$(CONFIG_SELECT_FILTER) += vf_select.o
+OBJS-$(CONFIG_SELECT_FILTER) += f_select.o
+OBJS-$(CONFIG_SENDCMD_FILTER) += f_sendcmd.o
OBJS-$(CONFIG_SETDAR_FILTER) += vf_aspect.o
+OBJS-$(CONFIG_SETFIELD_FILTER) += vf_setfield.o
OBJS-$(CONFIG_SETPTS_FILTER) += setpts.o
OBJS-$(CONFIG_SETSAR_FILTER) += vf_aspect.o
OBJS-$(CONFIG_SETTB_FILTER) += settb.o
OBJS-$(CONFIG_SHOWINFO_FILTER) += vf_showinfo.o
+OBJS-$(CONFIG_SHOWPALETTE_FILTER) += vf_showpalette.o
OBJS-$(CONFIG_SHUFFLEPLANES_FILTER) += vf_shuffleplanes.o
+OBJS-$(CONFIG_SIGNALSTATS_FILTER) += vf_signalstats.o
+OBJS-$(CONFIG_SMARTBLUR_FILTER) += vf_smartblur.o
OBJS-$(CONFIG_SPLIT_FILTER) += split.o
+OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o
+OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o
+OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_subtitles.o
+OBJS-$(CONFIG_SUPER2XSAI_FILTER) += vf_super2xsai.o
+OBJS-$(CONFIG_SWAPUV_FILTER) += vf_swapuv.o
+OBJS-$(CONFIG_TBLEND_FILTER) += vf_blend.o dualinput.o framesync.o
+OBJS-$(CONFIG_TELECINE_FILTER) += vf_telecine.o
+OBJS-$(CONFIG_THUMBNAIL_FILTER) += vf_thumbnail.o
+OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o
+OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o
OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o
OBJS-$(CONFIG_TRIM_FILTER) += trim.o
OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o
+OBJS-$(CONFIG_USPP_FILTER) += vf_uspp.o
OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o
+OBJS-$(CONFIG_VIDSTABDETECT_FILTER) += vidstabutils.o vf_vidstabdetect.o
+OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += vidstabutils.o vf_vidstabtransform.o
+OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o
+OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o
+OBJS-$(CONFIG_XBR_FILTER) += vf_xbr.o
OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o
+OBJS-$(CONFIG_ZMQ_FILTER) += f_zmq.o
+OBJS-$(CONFIG_ZOOMPAN_FILTER) += vf_zoompan.o
-OBJS-$(CONFIG_COLOR_FILTER) += vsrc_color.o
+OBJS-$(CONFIG_CELLAUTO_FILTER) += vsrc_cellauto.o
+OBJS-$(CONFIG_COLOR_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_FREI0R_SRC_FILTER) += vf_frei0r.o
-OBJS-$(CONFIG_MOVIE_FILTER) += vsrc_movie.o
-OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_nullsrc.o
+OBJS-$(CONFIG_HALDCLUTSRC_FILTER) += vsrc_testsrc.o
+OBJS-$(CONFIG_LIFE_FILTER) += vsrc_life.o
+OBJS-$(CONFIG_MANDELBROT_FILTER) += vsrc_mandelbrot.o
+OBJS-$(CONFIG_MPTESTSRC_FILTER) += vsrc_mptestsrc.o
+OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o
+OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o
+OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_TESTSRC_FILTER) += vsrc_testsrc.o
OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o
+# multimedia filters
+OBJS-$(CONFIG_AVECTORSCOPE_FILTER) += avf_avectorscope.o
+OBJS-$(CONFIG_CONCAT_FILTER) += avf_concat.o
+OBJS-$(CONFIG_SHOWCQT_FILTER) += avf_showcqt.o
+OBJS-$(CONFIG_SHOWSPECTRUM_FILTER) += avf_showspectrum.o
+OBJS-$(CONFIG_SHOWWAVES_FILTER) += avf_showwaves.o
+OBJS-$(CONFIG_SHOWWAVESPIC_FILTER) += avf_showwaves.o
+
+# multimedia sources
+OBJS-$(CONFIG_AMOVIE_FILTER) += src_movie.o
+OBJS-$(CONFIG_MOVIE_FILTER) += src_movie.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avfilterres.o
+
+SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h
+SKIPHEADERS-$(CONFIG_OPENCL) += opencl_internal.h deshake_opencl_kernel.h unsharp_opencl_kernel.h
+
OBJS-$(HAVE_THREADS) += pthread.o
+OBJS-$(CONFIG_SHARED) += log2_tab.o
TOOLS = graph2dot
-TESTPROGS = filtfmts
+TESTPROGS = drawutils filtfmts formats
+
+TOOLS-$(CONFIG_LIBZMQ) += zmqsend
+
+clean::
+ $(RM) $(CLEANSUFFIXES:%=libavfilter/libmpcodecs/%)
diff --git a/libavfilter/aeval.c b/libavfilter/aeval.c
new file mode 100644
index 0000000000..b6c420a4a9
--- /dev/null
+++ b/libavfilter/aeval.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * eval audio source
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+static const char * const var_names[] = {
+ "ch", ///< the value of the current channel
+ "n", ///< number of frame
+ "nb_in_channels",
+ "nb_out_channels",
+ "t", ///< timestamp expressed in seconds
+ "s", ///< sample rate
+ NULL
+};
+
+enum var_name {
+ VAR_CH,
+ VAR_N,
+ VAR_NB_IN_CHANNELS,
+ VAR_NB_OUT_CHANNELS,
+ VAR_T,
+ VAR_S,
+ VAR_VARS_NB
+};
+
+typedef struct {
+ const AVClass *class;
+ char *sample_rate_str;
+ int sample_rate;
+ int64_t chlayout;
+ char *chlayout_str;
+ int nb_channels; ///< number of output channels
+ int nb_in_channels; ///< number of input channels
+ int same_chlayout; ///< set output as input channel layout
+ int64_t pts;
+ AVExpr **expr;
+ char *exprs;
+ int nb_samples; ///< number of samples per requested frame
+ int64_t duration;
+ uint64_t n;
+ double var_values[VAR_VARS_NB];
+ double *channel_values;
+ int64_t out_channel_layout;
+} EvalContext;
+
+static double val(void *priv, double ch)
+{
+ EvalContext *eval = priv;
+ return eval->channel_values[FFMIN((int)ch, eval->nb_in_channels-1)];
+}
+
+static double (* const aeval_func1[])(void *, double) = { val, NULL };
+static const char * const aeval_func1_names[] = { "val", NULL };
+
+#define OFFSET(x) offsetof(EvalContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption aevalsrc_options[]= {
+ { "exprs", "set the '|'-separated list of channels expressions", OFFSET(exprs), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
+ { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 0, INT_MAX, FLAGS },
+ { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 0, INT_MAX, FLAGS },
+ { "sample_rate", "set the sample rate", OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "s", "set the sample rate", OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
+ { "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
+ { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "c", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(aevalsrc);
+
+static int parse_channel_expressions(AVFilterContext *ctx,
+ int expected_nb_channels)
+{
+ EvalContext *eval = ctx->priv;
+ char *args1 = av_strdup(eval->exprs);
+ char *expr, *last_expr = NULL, *buf;
+ double (* const *func1)(void *, double) = NULL;
+ const char * const *func1_names = NULL;
+ int i, ret = 0;
+
+ if (!args1)
+ return AVERROR(ENOMEM);
+
+ if (!eval->exprs) {
+ av_log(ctx, AV_LOG_ERROR, "Channels expressions list is empty\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!strcmp(ctx->filter->name, "aeval")) {
+ func1 = aeval_func1;
+ func1_names = aeval_func1_names;
+ }
+
+#define ADD_EXPRESSION(expr_) do { \
+ if (!av_dynarray2_add((void **)&eval->expr, &eval->nb_channels, \
+ sizeof(*eval->expr), NULL)) { \
+ ret = AVERROR(ENOMEM); \
+ goto end; \
+ } \
+ eval->expr[eval->nb_channels-1] = NULL; \
+ ret = av_expr_parse(&eval->expr[eval->nb_channels - 1], expr_, \
+ var_names, func1_names, func1, \
+ NULL, NULL, 0, ctx); \
+ if (ret < 0) \
+ goto end; \
+ } while (0)
+
+ /* reset expressions */
+ for (i = 0; i < eval->nb_channels; i++) {
+ av_expr_free(eval->expr[i]);
+ eval->expr[i] = NULL;
+ }
+ av_freep(&eval->expr);
+ eval->nb_channels = 0;
+
+ buf = args1;
+ while (expr = av_strtok(buf, "|", &buf)) {
+ ADD_EXPRESSION(expr);
+ last_expr = expr;
+ }
+
+ if (expected_nb_channels > eval->nb_channels)
+ for (i = eval->nb_channels; i < expected_nb_channels; i++)
+ ADD_EXPRESSION(last_expr);
+
+ if (expected_nb_channels > 0 && eval->nb_channels != expected_nb_channels) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Mismatch between the specified number of channel expressions '%d' "
+ "and the number of expected output channels '%d' for the specified channel layout\n",
+ eval->nb_channels, expected_nb_channels);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+end:
+ av_free(args1);
+ return ret;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ EvalContext *eval = ctx->priv;
+ int ret = 0;
+
+ if (eval->chlayout_str) {
+ if (!strcmp(eval->chlayout_str, "same") && !strcmp(ctx->filter->name, "aeval")) {
+ eval->same_chlayout = 1;
+ } else {
+ ret = ff_parse_channel_layout(&eval->chlayout, NULL, eval->chlayout_str, ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = parse_channel_expressions(ctx, av_get_channel_layout_nb_channels(eval->chlayout));
+ if (ret < 0)
+ return ret;
+ }
+ } else {
+ /* guess channel layout from nb expressions/channels */
+ if ((ret = parse_channel_expressions(ctx, -1)) < 0)
+ return ret;
+
+ eval->chlayout = av_get_default_channel_layout(eval->nb_channels);
+ if (!eval->chlayout && eval->nb_channels <= 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid number of channels '%d' provided\n",
+ eval->nb_channels);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ if (eval->sample_rate_str)
+ if ((ret = ff_parse_sample_rate(&eval->sample_rate, eval->sample_rate_str, ctx)))
+ return ret;
+ eval->n = 0;
+
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ EvalContext *eval = ctx->priv;
+ int i;
+
+ for (i = 0; i < eval->nb_channels; i++) {
+ av_expr_free(eval->expr[i]);
+ eval->expr[i] = NULL;
+ }
+ av_freep(&eval->expr);
+ av_freep(&eval->channel_values);
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ EvalContext *eval = outlink->src->priv;
+ char buf[128];
+
+ outlink->time_base = (AVRational){1, eval->sample_rate};
+ outlink->sample_rate = eval->sample_rate;
+
+ eval->var_values[VAR_S] = eval->sample_rate;
+ eval->var_values[VAR_NB_IN_CHANNELS] = NAN;
+ eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
+
+ av_get_channel_layout_string(buf, sizeof(buf), 0, eval->chlayout);
+
+ av_log(outlink->src, AV_LOG_VERBOSE,
+ "sample_rate:%d chlayout:%s duration:%"PRId64"\n",
+ eval->sample_rate, buf, eval->duration);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ EvalContext *eval = ctx->priv;
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE };
+ int64_t chlayouts[] = { eval->chlayout ? eval->chlayout : FF_COUNT2LAYOUT(eval->nb_channels) , -1 };
+ int sample_rates[] = { eval->sample_rate, -1 };
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ int ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats (ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ layouts = avfilter_make_format64_list(chlayouts);
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_rates);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ EvalContext *eval = outlink->src->priv;
+ AVFrame *samplesref;
+ int i, j;
+ int64_t t = av_rescale(eval->n, AV_TIME_BASE, eval->sample_rate);
+
+ if (eval->duration >= 0 && t >= eval->duration)
+ return AVERROR_EOF;
+
+ samplesref = ff_get_audio_buffer(outlink, eval->nb_samples);
+ if (!samplesref)
+ return AVERROR(ENOMEM);
+
+ /* evaluate expression for each single sample and for each channel */
+ for (i = 0; i < eval->nb_samples; i++, eval->n++) {
+ eval->var_values[VAR_N] = eval->n;
+ eval->var_values[VAR_T] = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
+
+ for (j = 0; j < eval->nb_channels; j++) {
+ *((double *) samplesref->extended_data[j] + i) =
+ av_expr_eval(eval->expr[j], eval->var_values, NULL);
+ }
+ }
+
+ samplesref->pts = eval->pts;
+ samplesref->sample_rate = eval->sample_rate;
+ eval->pts += eval->nb_samples;
+
+ return ff_filter_frame(outlink, samplesref);
+}
+
+#if CONFIG_AEVALSRC_FILTER
+static const AVFilterPad aevalsrc_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_props,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_asrc_aevalsrc = {
+ .name = "aevalsrc",
+ .description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."),
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(EvalContext),
+ .inputs = NULL,
+ .outputs = aevalsrc_outputs,
+ .priv_class = &aevalsrc_class,
+};
+
+#endif /* CONFIG_AEVALSRC_FILTER */
+
+#define OFFSET(x) offsetof(EvalContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption aeval_options[]= {
+ { "exprs", "set the '|'-separated list of channels expressions", OFFSET(exprs), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
+ { "channel_layout", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "c", "set channel layout", OFFSET(chlayout_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(aeval);
+
+static int aeval_query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ EvalContext *eval = ctx->priv;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE
+ };
+
+ // inlink supports any channel layout
+ layouts = ff_all_channel_counts();
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+
+ if (eval->same_chlayout) {
+ layouts = ff_all_channel_counts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, layouts);
+ } else {
+ // outlink supports only requested output channel layout
+ layouts = NULL;
+ ff_add_channel_layout(&layouts,
+ eval->out_channel_layout ? eval->out_channel_layout :
+ FF_COUNT2LAYOUT(eval->nb_channels));
+ ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
+ }
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_set_common_formats(ctx, formats);
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_set_common_samplerates(ctx, formats);
+
+ return 0;
+}
+
+static int aeval_config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ EvalContext *eval = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ int ret;
+
+ if (eval->same_chlayout) {
+ eval->chlayout = inlink->channel_layout;
+
+ if ((ret = parse_channel_expressions(ctx, inlink->channels)) < 0)
+ return ret;
+ }
+
+ eval->n = 0;
+ eval->nb_in_channels = eval->var_values[VAR_NB_IN_CHANNELS] = inlink->channels;
+ eval->var_values[VAR_NB_OUT_CHANNELS] = outlink->channels;
+ eval->var_values[VAR_S] = inlink->sample_rate;
+ eval->var_values[VAR_T] = NAN;
+
+ eval->channel_values = av_realloc_f(eval->channel_values,
+ inlink->channels, sizeof(*eval->channel_values));
+ if (!eval->channel_values)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)*av_q2d(tb))
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ EvalContext *eval = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int nb_samples = in->nb_samples;
+ AVFrame *out;
+ double t0;
+ int i, j;
+
+ /* do volume scaling in-place if input buffer is writable */
+ out = ff_get_audio_buffer(outlink, nb_samples);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out, in);
+
+ t0 = TS2T(in->pts, inlink->time_base);
+
+ /* evaluate expression for each single sample and for each channel */
+ for (i = 0; i < nb_samples; i++, eval->n++) {
+ eval->var_values[VAR_N] = eval->n;
+ eval->var_values[VAR_T] = t0 + i * (double)1/inlink->sample_rate;
+
+ for (j = 0; j < inlink->channels; j++)
+ eval->channel_values[j] = *((double *) in->extended_data[j] + i);
+
+ for (j = 0; j < outlink->channels; j++) {
+ eval->var_values[VAR_CH] = j;
+ *((double *) out->extended_data[j] + i) =
+ av_expr_eval(eval->expr[j], eval->var_values, eval);
+ }
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+#if CONFIG_AEVAL_FILTER
+
+static const AVFilterPad aeval_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad aeval_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = aeval_config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aeval = {
+ .name = "aeval",
+ .description = NULL_IF_CONFIG_SMALL("Filter audio signal according to a specified expression."),
+ .query_formats = aeval_query_formats,
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(EvalContext),
+ .inputs = aeval_inputs,
+ .outputs = aeval_outputs,
+ .priv_class = &aeval_class,
+};
+
+#endif /* CONFIG_AEVAL_FILTER */
diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c
new file mode 100644
index 0000000000..ca141ce3b0
--- /dev/null
+++ b/libavfilter/af_adelay.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct ChanDelay {
+ int delay;
+ unsigned delay_index;
+ unsigned index;
+ uint8_t *samples;
+} ChanDelay;
+
+typedef struct AudioDelayContext {
+ const AVClass *class;
+ char *delays;
+ ChanDelay *chandelay;
+ int nb_delays;
+ int block_align;
+ unsigned max_delay;
+ int64_t next_pts;
+
+ void (*delay_channel)(ChanDelay *d, int nb_samples,
+ const uint8_t *src, uint8_t *dst);
+} AudioDelayContext;
+
+#define OFFSET(x) offsetof(AudioDelayContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption adelay_options[] = {
+ { "delays", "set list of delays for each channel", OFFSET(delays), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(adelay);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterChannelLayouts *layouts;
+ AVFilterFormats *formats;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+#define DELAY(name, type, fill) \
+static void delay_channel_## name ##p(ChanDelay *d, int nb_samples, \
+ const uint8_t *ssrc, uint8_t *ddst) \
+{ \
+ const type *src = (type *)ssrc; \
+ type *dst = (type *)ddst; \
+ type *samples = (type *)d->samples; \
+ \
+ while (nb_samples) { \
+ if (d->delay_index < d->delay) { \
+ const int len = FFMIN(nb_samples, d->delay - d->delay_index); \
+ \
+ memcpy(&samples[d->delay_index], src, len * sizeof(type)); \
+ memset(dst, fill, len * sizeof(type)); \
+ d->delay_index += len; \
+ src += len; \
+ dst += len; \
+ nb_samples -= len; \
+ } else { \
+ *dst = samples[d->index]; \
+ samples[d->index] = *src; \
+ nb_samples--; \
+ d->index++; \
+ src++, dst++; \
+ d->index = d->index >= d->delay ? 0 : d->index; \
+ } \
+ } \
+}
+
+DELAY(u8, uint8_t, 0x80)
+DELAY(s16, int16_t, 0)
+DELAY(s32, int32_t, 0)
+DELAY(flt, float, 0)
+DELAY(dbl, double, 0)
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AudioDelayContext *s = ctx->priv;
+ char *p, *arg, *saveptr = NULL;
+ int i;
+
+ s->chandelay = av_calloc(inlink->channels, sizeof(*s->chandelay));
+ if (!s->chandelay)
+ return AVERROR(ENOMEM);
+ s->nb_delays = inlink->channels;
+ s->block_align = av_get_bytes_per_sample(inlink->format);
+
+ p = s->delays;
+ for (i = 0; i < s->nb_delays; i++) {
+ ChanDelay *d = &s->chandelay[i];
+ float delay;
+
+ if (!(arg = av_strtok(p, "|", &saveptr)))
+ break;
+
+ p = NULL;
+ sscanf(arg, "%f", &delay);
+
+ d->delay = delay * inlink->sample_rate / 1000.0;
+ if (d->delay < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Delay must be non negative number.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ for (i = 0; i < s->nb_delays; i++) {
+ ChanDelay *d = &s->chandelay[i];
+
+ if (!d->delay)
+ continue;
+
+ d->samples = av_malloc_array(d->delay, s->block_align);
+ if (!d->samples)
+ return AVERROR(ENOMEM);
+
+ s->max_delay = FFMAX(s->max_delay, d->delay);
+ }
+
+ if (!s->max_delay) {
+ av_log(ctx, AV_LOG_ERROR, "At least one delay >0 must be specified.\n");
+ return AVERROR(EINVAL);
+ }
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_U8P : s->delay_channel = delay_channel_u8p ; break;
+ case AV_SAMPLE_FMT_S16P: s->delay_channel = delay_channel_s16p; break;
+ case AV_SAMPLE_FMT_S32P: s->delay_channel = delay_channel_s32p; break;
+ case AV_SAMPLE_FMT_FLTP: s->delay_channel = delay_channel_fltp; break;
+ case AV_SAMPLE_FMT_DBLP: s->delay_channel = delay_channel_dblp; break;
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AudioDelayContext *s = ctx->priv;
+ AVFrame *out_frame;
+ int i;
+
+ if (ctx->is_disabled || !s->delays)
+ return ff_filter_frame(ctx->outputs[0], frame);
+
+ out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
+ if (!out_frame)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_frame, frame);
+
+ for (i = 0; i < s->nb_delays; i++) {
+ ChanDelay *d = &s->chandelay[i];
+ const uint8_t *src = frame->extended_data[i];
+ uint8_t *dst = out_frame->extended_data[i];
+
+ if (!d->delay)
+ memcpy(dst, src, frame->nb_samples * s->block_align);
+ else
+ s->delay_channel(d, frame->nb_samples, src, dst);
+ }
+
+ s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
+ av_frame_free(&frame);
+ return ff_filter_frame(ctx->outputs[0], out_frame);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AudioDelayContext *s = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+ if (ret == AVERROR_EOF && !ctx->is_disabled && s->max_delay) {
+ int nb_samples = FFMIN(s->max_delay, 2048);
+ AVFrame *frame;
+
+ frame = ff_get_audio_buffer(outlink, nb_samples);
+ if (!frame)
+ return AVERROR(ENOMEM);
+ s->max_delay -= nb_samples;
+
+ av_samples_set_silence(frame->extended_data, 0,
+ frame->nb_samples,
+ outlink->channels,
+ frame->format);
+
+ frame->pts = s->next_pts;
+ if (s->next_pts != AV_NOPTS_VALUE)
+ s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ ret = filter_frame(ctx->inputs[0], frame);
+ }
+
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AudioDelayContext *s = ctx->priv;
+ int i;
+
+ for (i = 0; i < s->nb_delays; i++)
+ av_freep(&s->chandelay[i].samples);
+ av_freep(&s->chandelay);
+}
+
+static const AVFilterPad adelay_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad adelay_outputs[] = {
+ {
+ .name = "default",
+ .request_frame = request_frame,
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_adelay = {
+ .name = "adelay",
+ .description = NULL_IF_CONFIG_SMALL("Delay one or more audio channels."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(AudioDelayContext),
+ .priv_class = &adelay_class,
+ .uninit = uninit,
+ .inputs = adelay_inputs,
+ .outputs = adelay_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c
new file mode 100644
index 0000000000..8e7a39ecd0
--- /dev/null
+++ b/libavfilter/af_aecho.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct AudioEchoContext {
+ const AVClass *class;
+ float in_gain, out_gain;
+ char *delays, *decays;
+ float *delay, *decay;
+ int nb_echoes;
+ int delay_index;
+ uint8_t **delayptrs;
+ int max_samples, fade_out;
+ int *samples;
+ int64_t next_pts;
+
+ void (*echo_samples)(struct AudioEchoContext *ctx, uint8_t **delayptrs,
+ uint8_t * const *src, uint8_t **dst,
+ int nb_samples, int channels);
+} AudioEchoContext;
+
+#define OFFSET(x) offsetof(AudioEchoContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption aecho_options[] = {
+ { "in_gain", "set signal input gain", OFFSET(in_gain), AV_OPT_TYPE_FLOAT, {.dbl=0.6}, 0, 1, A },
+ { "out_gain", "set signal output gain", OFFSET(out_gain), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, A },
+ { "delays", "set list of signal delays", OFFSET(delays), AV_OPT_TYPE_STRING, {.str="1000"}, 0, 0, A },
+ { "decays", "set list of signal decays", OFFSET(decays), AV_OPT_TYPE_STRING, {.str="0.5"}, 0, 0, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(aecho);
+
+static void count_items(char *item_str, int *nb_items)
+{
+ char *p;
+
+ *nb_items = 1;
+ for (p = item_str; *p; p++) {
+ if (*p == '|')
+ (*nb_items)++;
+ }
+
+}
+
+static void fill_items(char *item_str, int *nb_items, float *items)
+{
+ char *p, *saveptr = NULL;
+ int i, new_nb_items = 0;
+
+ p = item_str;
+ for (i = 0; i < *nb_items; i++) {
+ char *tstr = av_strtok(p, "|", &saveptr);
+ p = NULL;
+ new_nb_items += sscanf(tstr, "%f", &items[i]) == 1;
+ }
+
+ *nb_items = new_nb_items;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AudioEchoContext *s = ctx->priv;
+
+ av_freep(&s->delay);
+ av_freep(&s->decay);
+ av_freep(&s->samples);
+
+ if (s->delayptrs)
+ av_freep(&s->delayptrs[0]);
+ av_freep(&s->delayptrs);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AudioEchoContext *s = ctx->priv;
+ int nb_delays, nb_decays, i;
+
+ if (!s->delays || !s->decays) {
+ av_log(ctx, AV_LOG_ERROR, "Missing delays and/or decays.\n");
+ return AVERROR(EINVAL);
+ }
+
+ count_items(s->delays, &nb_delays);
+ count_items(s->decays, &nb_decays);
+
+ s->delay = av_realloc_f(s->delay, nb_delays, sizeof(*s->delay));
+ s->decay = av_realloc_f(s->decay, nb_decays, sizeof(*s->decay));
+ if (!s->delay || !s->decay)
+ return AVERROR(ENOMEM);
+
+ fill_items(s->delays, &nb_delays, s->delay);
+ fill_items(s->decays, &nb_decays, s->decay);
+
+ if (nb_delays != nb_decays) {
+ av_log(ctx, AV_LOG_ERROR, "Number of delays %d differs from number of decays %d.\n", nb_delays, nb_decays);
+ return AVERROR(EINVAL);
+ }
+
+ s->nb_echoes = nb_delays;
+ if (!s->nb_echoes) {
+ av_log(ctx, AV_LOG_ERROR, "At least one decay & delay must be set.\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->samples = av_realloc_f(s->samples, nb_delays, sizeof(*s->samples));
+ if (!s->samples)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < nb_delays; i++) {
+ if (s->delay[i] <= 0 || s->delay[i] > 90000) {
+ av_log(ctx, AV_LOG_ERROR, "delay[%d]: %f is out of allowed range: (0, 90000]\n", i, s->delay[i]);
+ return AVERROR(EINVAL);
+ }
+ if (s->decay[i] <= 0 || s->decay[i] > 1) {
+ av_log(ctx, AV_LOG_ERROR, "decay[%d]: %f is out of allowed range: (0, 1]\n", i, s->decay[i]);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ s->next_pts = AV_NOPTS_VALUE;
+
+ av_log(ctx, AV_LOG_DEBUG, "nb_echoes:%d\n", s->nb_echoes);
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterChannelLayouts *layouts;
+ AVFilterFormats *formats;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
+
+#define ECHO(name, type, min, max) \
+static void echo_samples_## name ##p(AudioEchoContext *ctx, \
+ uint8_t **delayptrs, \
+ uint8_t * const *src, uint8_t **dst, \
+ int nb_samples, int channels) \
+{ \
+ const double out_gain = ctx->out_gain; \
+ const double in_gain = ctx->in_gain; \
+ const int nb_echoes = ctx->nb_echoes; \
+ const int max_samples = ctx->max_samples; \
+ int i, j, chan, av_uninit(index); \
+ \
+ av_assert1(channels > 0); /* would corrupt delay_index */ \
+ \
+ for (chan = 0; chan < channels; chan++) { \
+ const type *s = (type *)src[chan]; \
+ type *d = (type *)dst[chan]; \
+ type *dbuf = (type *)delayptrs[chan]; \
+ \
+ index = ctx->delay_index; \
+ for (i = 0; i < nb_samples; i++, s++, d++) { \
+ double out, in; \
+ \
+ in = *s; \
+ out = in * in_gain; \
+ for (j = 0; j < nb_echoes; j++) { \
+ int ix = index + max_samples - ctx->samples[j]; \
+ ix = MOD(ix, max_samples); \
+ out += dbuf[ix] * ctx->decay[j]; \
+ } \
+ out *= out_gain; \
+ \
+ *d = av_clipd(out, min, max); \
+ dbuf[index] = in; \
+ \
+ index = MOD(index + 1, max_samples); \
+ } \
+ } \
+ ctx->delay_index = index; \
+}
+
+ECHO(dbl, double, -1.0, 1.0 )
+ECHO(flt, float, -1.0, 1.0 )
+ECHO(s16, int16_t, INT16_MIN, INT16_MAX)
+ECHO(s32, int32_t, INT32_MIN, INT32_MAX)
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AudioEchoContext *s = ctx->priv;
+ float volume = 1.0;
+ int i;
+
+ for (i = 0; i < s->nb_echoes; i++) {
+ s->samples[i] = s->delay[i] * outlink->sample_rate / 1000.0;
+ s->max_samples = FFMAX(s->max_samples, s->samples[i]);
+ volume += s->decay[i];
+ }
+
+ if (s->max_samples <= 0) {
+ av_log(ctx, AV_LOG_ERROR, "Nothing to echo - missing delay samples.\n");
+ return AVERROR(EINVAL);
+ }
+ s->fade_out = s->max_samples;
+
+ if (volume * s->in_gain * s->out_gain > 1.0)
+ av_log(ctx, AV_LOG_WARNING,
+ "out_gain %f can cause saturation of output\n", s->out_gain);
+
+ switch (outlink->format) {
+ case AV_SAMPLE_FMT_DBLP: s->echo_samples = echo_samples_dblp; break;
+ case AV_SAMPLE_FMT_FLTP: s->echo_samples = echo_samples_fltp; break;
+ case AV_SAMPLE_FMT_S16P: s->echo_samples = echo_samples_s16p; break;
+ case AV_SAMPLE_FMT_S32P: s->echo_samples = echo_samples_s32p; break;
+ }
+
+
+ if (s->delayptrs)
+ av_freep(&s->delayptrs[0]);
+ av_freep(&s->delayptrs);
+
+ return av_samples_alloc_array_and_samples(&s->delayptrs, NULL,
+ outlink->channels,
+ s->max_samples,
+ outlink->format, 0);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AudioEchoContext *s = ctx->priv;
+ AVFrame *out_frame;
+
+ if (av_frame_is_writable(frame)) {
+ out_frame = frame;
+ } else {
+ out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
+ if (!out_frame)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_frame, frame);
+ }
+
+ s->echo_samples(s, s->delayptrs, frame->extended_data, out_frame->extended_data,
+ frame->nb_samples, inlink->channels);
+
+ s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
+
+ if (frame != out_frame)
+ av_frame_free(&frame);
+
+ return ff_filter_frame(ctx->outputs[0], out_frame);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AudioEchoContext *s = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+
+ if (ret == AVERROR_EOF && !ctx->is_disabled && s->fade_out) {
+ int nb_samples = FFMIN(s->fade_out, 2048);
+ AVFrame *frame;
+
+ frame = ff_get_audio_buffer(outlink, nb_samples);
+ if (!frame)
+ return AVERROR(ENOMEM);
+ s->fade_out -= nb_samples;
+
+ av_samples_set_silence(frame->extended_data, 0,
+ frame->nb_samples,
+ outlink->channels,
+ frame->format);
+
+ s->echo_samples(s, s->delayptrs, frame->extended_data, frame->extended_data,
+ frame->nb_samples, outlink->channels);
+
+ frame->pts = s->next_pts;
+ if (s->next_pts != AV_NOPTS_VALUE)
+ s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ return ff_filter_frame(outlink, frame);
+ }
+
+ return ret;
+}
+
+static const AVFilterPad aecho_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad aecho_outputs[] = {
+ {
+ .name = "default",
+ .request_frame = request_frame,
+ .config_props = config_output,
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aecho = {
+ .name = "aecho",
+ .description = NULL_IF_CONFIG_SMALL("Add echoing to the audio."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(AudioEchoContext),
+ .priv_class = &aecho_class,
+ .init = init,
+ .uninit = uninit,
+ .inputs = aecho_inputs,
+ .outputs = aecho_outputs,
+};
diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c
new file mode 100644
index 0000000000..8b69cefbde
--- /dev/null
+++ b/libavfilter/af_afade.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * fade audio filter
+ */
+
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int type;
+ int curve;
+ int nb_samples;
+ int64_t start_sample;
+ int64_t duration;
+ int64_t start_time;
+
+ void (*fade_samples)(uint8_t **dst, uint8_t * const *src,
+ int nb_samples, int channels, int direction,
+ int64_t start, int range, int curve);
+} AudioFadeContext;
+
+enum CurveType { TRI, QSIN, ESIN, HSIN, LOG, PAR, QUA, CUB, SQU, CBR };
+
+#define OFFSET(x) offsetof(AudioFadeContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption afade_options[] = {
+ { "type", "set the fade direction", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS, "type" },
+ { "t", "set the fade direction", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS, "type" },
+ { "in", "fade-in", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "type" },
+ { "out", "fade-out", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "type" },
+ { "start_sample", "set number of first sample to start fading", OFFSET(start_sample), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, FLAGS },
+ { "ss", "set number of first sample to start fading", OFFSET(start_sample), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, FLAGS },
+ { "nb_samples", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX, FLAGS },
+ { "ns", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX, FLAGS },
+ { "start_time", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "st", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "duration", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "d", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "curve", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, TRI, CBR, FLAGS, "curve" },
+ { "c", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, TRI, CBR, FLAGS, "curve" },
+ { "tri", "linear slope", 0, AV_OPT_TYPE_CONST, {.i64 = TRI }, 0, 0, FLAGS, "curve" },
+ { "qsin", "quarter of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = QSIN }, 0, 0, FLAGS, "curve" },
+ { "esin", "exponential sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = ESIN }, 0, 0, FLAGS, "curve" },
+ { "hsin", "half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = HSIN }, 0, 0, FLAGS, "curve" },
+ { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64 = LOG }, 0, 0, FLAGS, "curve" },
+ { "par", "inverted parabola", 0, AV_OPT_TYPE_CONST, {.i64 = PAR }, 0, 0, FLAGS, "curve" },
+ { "qua", "quadratic", 0, AV_OPT_TYPE_CONST, {.i64 = QUA }, 0, 0, FLAGS, "curve" },
+ { "cub", "cubic", 0, AV_OPT_TYPE_CONST, {.i64 = CUB }, 0, 0, FLAGS, "curve" },
+ { "squ", "square root", 0, AV_OPT_TYPE_CONST, {.i64 = SQU }, 0, 0, FLAGS, "curve" },
+ { "cbr", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64 = CBR }, 0, 0, FLAGS, "curve" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(afade);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AudioFadeContext *s = ctx->priv;
+
+ if (INT64_MAX - s->nb_samples < s->start_sample)
+ return AVERROR(EINVAL);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ static const enum AVSampleFormat sample_fmts[] = {
+ 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,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static double fade_gain(int curve, int64_t index, int range)
+{
+ double gain;
+
+ gain = FFMAX(0.0, FFMIN(1.0, 1.0 * index / range));
+
+ switch (curve) {
+ case QSIN:
+ gain = sin(gain * M_PI / 2.0);
+ break;
+ case ESIN:
+ gain = 1.0 - cos(M_PI / 4.0 * (pow(2.0*gain - 1, 3) + 1));
+ break;
+ case HSIN:
+ gain = (1.0 - cos(gain * M_PI)) / 2.0;
+ break;
+ case LOG:
+ gain = pow(0.1, (1 - gain) * 5.0);
+ break;
+ case PAR:
+ gain = (1 - (1 - gain) * (1 - gain));
+ break;
+ case QUA:
+ gain *= gain;
+ break;
+ case CUB:
+ gain = gain * gain * gain;
+ break;
+ case SQU:
+ gain = sqrt(gain);
+ break;
+ case CBR:
+ gain = cbrt(gain);
+ break;
+ }
+
+ return gain;
+}
+
+#define FADE_PLANAR(name, type) \
+static void fade_samples_## name ##p(uint8_t **dst, uint8_t * const *src, \
+ int nb_samples, int channels, int dir, \
+ int64_t start, int range, int curve) \
+{ \
+ int i, c; \
+ \
+ for (i = 0; i < nb_samples; i++) { \
+ double gain = fade_gain(curve, start + i * dir, range); \
+ for (c = 0; c < channels; c++) { \
+ type *d = (type *)dst[c]; \
+ const type *s = (type *)src[c]; \
+ \
+ d[i] = s[i] * gain; \
+ } \
+ } \
+}
+
+#define FADE(name, type) \
+static void fade_samples_## name (uint8_t **dst, uint8_t * const *src, \
+ int nb_samples, int channels, int dir, \
+ int64_t start, int range, int curve) \
+{ \
+ type *d = (type *)dst[0]; \
+ const type *s = (type *)src[0]; \
+ int i, c, k = 0; \
+ \
+ for (i = 0; i < nb_samples; i++) { \
+ double gain = fade_gain(curve, start + i * dir, range); \
+ for (c = 0; c < channels; c++, k++) \
+ d[k] = s[k] * gain; \
+ } \
+}
+
+FADE_PLANAR(dbl, double)
+FADE_PLANAR(flt, float)
+FADE_PLANAR(s16, int16_t)
+FADE_PLANAR(s32, int32_t)
+
+FADE(dbl, double)
+FADE(flt, float)
+FADE(s16, int16_t)
+FADE(s32, int32_t)
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AudioFadeContext *s = ctx->priv;
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_DBL: s->fade_samples = fade_samples_dbl; break;
+ case AV_SAMPLE_FMT_DBLP: s->fade_samples = fade_samples_dblp; break;
+ case AV_SAMPLE_FMT_FLT: s->fade_samples = fade_samples_flt; break;
+ case AV_SAMPLE_FMT_FLTP: s->fade_samples = fade_samples_fltp; break;
+ case AV_SAMPLE_FMT_S16: s->fade_samples = fade_samples_s16; break;
+ case AV_SAMPLE_FMT_S16P: s->fade_samples = fade_samples_s16p; break;
+ case AV_SAMPLE_FMT_S32: s->fade_samples = fade_samples_s32; break;
+ case AV_SAMPLE_FMT_S32P: s->fade_samples = fade_samples_s32p; break;
+ }
+
+ if (s->duration)
+ s->nb_samples = av_rescale(s->duration, inlink->sample_rate, AV_TIME_BASE);
+ if (s->start_time)
+ s->start_sample = av_rescale(s->start_time, inlink->sample_rate, AV_TIME_BASE);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ AudioFadeContext *s = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int nb_samples = buf->nb_samples;
+ AVFrame *out_buf;
+ int64_t cur_sample = av_rescale_q(buf->pts, inlink->time_base, (AVRational){1, inlink->sample_rate});
+
+ if ((!s->type && (s->start_sample + s->nb_samples < cur_sample)) ||
+ ( s->type && (cur_sample + s->nb_samples < s->start_sample)))
+ return ff_filter_frame(outlink, buf);
+
+ if (av_frame_is_writable(buf)) {
+ out_buf = buf;
+ } else {
+ out_buf = ff_get_audio_buffer(inlink, nb_samples);
+ if (!out_buf)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_buf, buf);
+ }
+
+ if ((!s->type && (cur_sample + nb_samples < s->start_sample)) ||
+ ( s->type && (s->start_sample + s->nb_samples < cur_sample))) {
+ av_samples_set_silence(out_buf->extended_data, 0, nb_samples,
+ av_frame_get_channels(out_buf), out_buf->format);
+ } else {
+ int64_t start;
+
+ if (!s->type)
+ start = cur_sample - s->start_sample;
+ else
+ start = s->start_sample + s->nb_samples - cur_sample;
+
+ s->fade_samples(out_buf->extended_data, buf->extended_data,
+ nb_samples, av_frame_get_channels(buf),
+ s->type ? -1 : 1, start,
+ s->nb_samples, s->curve);
+ }
+
+ if (buf != out_buf)
+ av_frame_free(&buf);
+
+ return ff_filter_frame(outlink, out_buf);
+}
+
+static const AVFilterPad avfilter_af_afade_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_af_afade_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_afade = {
+ .name = "afade",
+ .description = NULL_IF_CONFIG_SMALL("Fade in/out input audio."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(AudioFadeContext),
+ .init = init,
+ .inputs = avfilter_af_afade_inputs,
+ .outputs = avfilter_af_afade_outputs,
+ .priv_class = &afade_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/af_aformat.c b/libavfilter/af_aformat.c
index f0746737dc..4fdcb09d2d 100644
--- a/libavfilter/af_aformat.c
+++ b/libavfilter/af_aformat.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mina Nagy Zaki
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,19 +47,15 @@ typedef struct AFormatContext {
#define OFFSET(x) offsetof(AFormatContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
-static const AVOption options[] = {
- { "sample_fmts", "A comma-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A },
- { "sample_rates", "A comma-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A },
- { "channel_layouts", "A comma-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A },
- { NULL },
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption aformat_options[] = {
+ { "sample_fmts", "A comma-separated list of sample formats.", OFFSET(formats_str), AV_OPT_TYPE_STRING, .flags = A|F },
+ { "sample_rates", "A comma-separated list of sample rates.", OFFSET(sample_rates_str), AV_OPT_TYPE_STRING, .flags = A|F },
+ { "channel_layouts", "A comma-separated list of channel layouts.", OFFSET(channel_layouts_str), AV_OPT_TYPE_STRING, .flags = A|F },
+ { NULL }
};
-static const AVClass aformat_class = {
- .class_name = "aformat filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(aformat);
#define PARSE_FORMATS(str, type, list, add_to_list, get_fmt, none, desc) \
do { \
@@ -112,15 +108,18 @@ static av_cold int init(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
AFormatContext *s = ctx->priv;
+ int ret;
- ff_set_common_formats(ctx, s->formats ? s->formats :
+ ret = ff_set_common_formats(ctx, s->formats ? s->formats :
ff_all_formats(AVMEDIA_TYPE_AUDIO));
- ff_set_common_samplerates(ctx, s->sample_rates ? s->sample_rates :
+ if (ret < 0)
+ return ret;
+ ret = ff_set_common_samplerates(ctx, s->sample_rates ? s->sample_rates :
ff_all_samplerates());
- ff_set_common_channel_layouts(ctx, s->channel_layouts ? s->channel_layouts :
- ff_all_channel_layouts());
-
- return 0;
+ if (ret < 0)
+ return ret;
+ return ff_set_common_channel_layouts(ctx, s->channel_layouts ? s->channel_layouts :
+ ff_all_channel_counts());
}
static const AVFilterPad avfilter_af_aformat_inputs[] = {
@@ -146,7 +145,6 @@ AVFilter ff_af_aformat = {
.query_formats = query_formats,
.priv_size = sizeof(AFormatContext),
.priv_class = &aformat_class,
-
.inputs = avfilter_af_aformat_inputs,
.outputs = avfilter_af_aformat_outputs,
};
diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c
new file mode 100644
index 0000000000..0a0a79fd29
--- /dev/null
+++ b/libavfilter/af_amerge.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Audio merging filter
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "bufferqueue.h"
+#include "internal.h"
+
+#define SWR_CH_MAX 32
+
+typedef struct {
+ const AVClass *class;
+ int nb_inputs;
+ int route[SWR_CH_MAX]; /**< channels routing, see copy_samples */
+ int bps;
+ struct amerge_input {
+ struct FFBufQueue queue;
+ int nb_ch; /**< number of channels for the input */
+ int nb_samples;
+ int pos;
+ } *in;
+} AMergeContext;
+
+#define OFFSET(x) offsetof(AMergeContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption amerge_options[] = {
+ { "inputs", "specify the number of inputs", OFFSET(nb_inputs),
+ AV_OPT_TYPE_INT, { .i64 = 2 }, 2, SWR_CH_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(amerge);
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AMergeContext *am = ctx->priv;
+ int i;
+
+ for (i = 0; i < am->nb_inputs; i++) {
+ if (am->in)
+ ff_bufqueue_discard_all(&am->in[i].queue);
+ if (ctx->input_pads)
+ av_freep(&ctx->input_pads[i].name);
+ }
+ av_freep(&am->in);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AMergeContext *am = ctx->priv;
+ int64_t inlayout[SWR_CH_MAX], outlayout = 0;
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ int i, overlap = 0, nb_ch = 0;
+
+ for (i = 0; i < am->nb_inputs; i++) {
+ if (!ctx->inputs[i]->in_channel_layouts ||
+ !ctx->inputs[i]->in_channel_layouts->nb_channel_layouts) {
+ av_log(ctx, AV_LOG_WARNING,
+ "No channel layout for input %d\n", i + 1);
+ return AVERROR(EAGAIN);
+ }
+ inlayout[i] = ctx->inputs[i]->in_channel_layouts->channel_layouts[0];
+ if (ctx->inputs[i]->in_channel_layouts->nb_channel_layouts > 1) {
+ char buf[256];
+ av_get_channel_layout_string(buf, sizeof(buf), 0, inlayout[i]);
+ av_log(ctx, AV_LOG_INFO, "Using \"%s\" for input %d\n", buf, i + 1);
+ }
+ am->in[i].nb_ch = av_get_channel_layout_nb_channels(inlayout[i]);
+ if (outlayout & inlayout[i])
+ overlap++;
+ outlayout |= inlayout[i];
+ nb_ch += am->in[i].nb_ch;
+ }
+ if (nb_ch > SWR_CH_MAX) {
+ av_log(ctx, AV_LOG_ERROR, "Too many channels (max %d)\n", SWR_CH_MAX);
+ return AVERROR(EINVAL);
+ }
+ if (overlap) {
+ av_log(ctx, AV_LOG_WARNING,
+ "Input channel layouts overlap: "
+ "output layout will be determined by the number of distinct input channels\n");
+ for (i = 0; i < nb_ch; i++)
+ am->route[i] = i;
+ outlayout = av_get_default_channel_layout(nb_ch);
+ if (!outlayout)
+ outlayout = ((int64_t)1 << nb_ch) - 1;
+ } else {
+ int *route[SWR_CH_MAX];
+ int c, out_ch_number = 0;
+
+ route[0] = am->route;
+ for (i = 1; i < am->nb_inputs; i++)
+ route[i] = route[i - 1] + am->in[i - 1].nb_ch;
+ for (c = 0; c < 64; c++)
+ for (i = 0; i < am->nb_inputs; i++)
+ if ((inlayout[i] >> c) & 1)
+ *(route[i]++) = out_ch_number++;
+ }
+ formats = ff_make_format_list(ff_packed_sample_fmts_array);
+ ff_set_common_formats(ctx, formats);
+ for (i = 0; i < am->nb_inputs; i++) {
+ layouts = NULL;
+ ff_add_channel_layout(&layouts, inlayout[i]);
+ ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
+ }
+ layouts = NULL;
+ ff_add_channel_layout(&layouts, outlayout);
+ ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
+ ff_set_common_samplerates(ctx, ff_all_samplerates());
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AMergeContext *am = ctx->priv;
+ AVBPrint bp;
+ int i;
+
+ for (i = 1; i < am->nb_inputs; i++) {
+ if (ctx->inputs[i]->sample_rate != ctx->inputs[0]->sample_rate) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Inputs must have the same sample rate "
+ "%d for in%d vs %d\n",
+ ctx->inputs[i]->sample_rate, i, ctx->inputs[0]->sample_rate);
+ return AVERROR(EINVAL);
+ }
+ }
+ am->bps = av_get_bytes_per_sample(ctx->outputs[0]->format);
+ outlink->sample_rate = ctx->inputs[0]->sample_rate;
+ outlink->time_base = ctx->inputs[0]->time_base;
+
+ av_bprint_init(&bp, 0, 1);
+ for (i = 0; i < am->nb_inputs; i++) {
+ av_bprintf(&bp, "%sin%d:", i ? " + " : "", i);
+ av_bprint_channel_layout(&bp, -1, ctx->inputs[i]->channel_layout);
+ }
+ av_bprintf(&bp, " -> out:");
+ av_bprint_channel_layout(&bp, -1, ctx->outputs[0]->channel_layout);
+ av_log(ctx, AV_LOG_VERBOSE, "%s\n", bp.str);
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AMergeContext *am = ctx->priv;
+ int i, ret;
+
+ for (i = 0; i < am->nb_inputs; i++)
+ if (!am->in[i].nb_samples)
+ if ((ret = ff_request_frame(ctx->inputs[i])) < 0)
+ return ret;
+ return 0;
+}
+
+/**
+ * Copy samples from several input streams to one output stream.
+ * @param nb_inputs number of inputs
+ * @param in inputs; used only for the nb_ch field;
+ * @param route routing values;
+ * input channel i goes to output channel route[i];
+ * i < in[0].nb_ch are the channels from the first output;
+ * i >= in[0].nb_ch are the channels from the second output
+ * @param ins pointer to the samples of each inputs, in packed format;
+ * will be left at the end of the copied samples
+ * @param outs pointer to the samples of the output, in packet format;
+ * must point to a buffer big enough;
+ * will be left at the end of the copied samples
+ * @param ns number of samples to copy
+ * @param bps bytes per sample
+ */
+static inline void copy_samples(int nb_inputs, struct amerge_input in[],
+ int *route, uint8_t *ins[],
+ uint8_t **outs, int ns, int bps)
+{
+ int *route_cur;
+ int i, c, nb_ch = 0;
+
+ for (i = 0; i < nb_inputs; i++)
+ nb_ch += in[i].nb_ch;
+ while (ns--) {
+ route_cur = route;
+ for (i = 0; i < nb_inputs; i++) {
+ for (c = 0; c < in[i].nb_ch; c++) {
+ memcpy((*outs) + bps * *(route_cur++), ins[i], bps);
+ ins[i] += bps;
+ }
+ }
+ *outs += nb_ch * bps;
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AMergeContext *am = ctx->priv;
+ AVFilterLink *const outlink = ctx->outputs[0];
+ int input_number;
+ int nb_samples, ns, i;
+ AVFrame *outbuf, *inbuf[SWR_CH_MAX];
+ uint8_t *ins[SWR_CH_MAX], *outs;
+
+ for (input_number = 0; input_number < am->nb_inputs; input_number++)
+ if (inlink == ctx->inputs[input_number])
+ break;
+ av_assert1(input_number < am->nb_inputs);
+ if (ff_bufqueue_is_full(&am->in[input_number].queue)) {
+ av_frame_free(&insamples);
+ return AVERROR(ENOMEM);
+ }
+ ff_bufqueue_add(ctx, &am->in[input_number].queue, av_frame_clone(insamples));
+ am->in[input_number].nb_samples += insamples->nb_samples;
+ av_frame_free(&insamples);
+ nb_samples = am->in[0].nb_samples;
+ for (i = 1; i < am->nb_inputs; i++)
+ nb_samples = FFMIN(nb_samples, am->in[i].nb_samples);
+ if (!nb_samples)
+ return 0;
+
+ outbuf = ff_get_audio_buffer(ctx->outputs[0], nb_samples);
+ if (!outbuf)
+ return AVERROR(ENOMEM);
+ outs = outbuf->data[0];
+ for (i = 0; i < am->nb_inputs; i++) {
+ inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0);
+ ins[i] = inbuf[i]->data[0] +
+ am->in[i].pos * am->in[i].nb_ch * am->bps;
+ }
+ av_frame_copy_props(outbuf, inbuf[0]);
+ outbuf->pts = inbuf[0]->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
+ inbuf[0]->pts +
+ av_rescale_q(am->in[0].pos,
+ av_make_q(1, ctx->inputs[0]->sample_rate),
+ ctx->outputs[0]->time_base);
+
+ outbuf->nb_samples = nb_samples;
+ outbuf->channel_layout = outlink->channel_layout;
+ av_frame_set_channels(outbuf, outlink->channels);
+
+ while (nb_samples) {
+ ns = nb_samples;
+ for (i = 0; i < am->nb_inputs; i++)
+ ns = FFMIN(ns, inbuf[i]->nb_samples - am->in[i].pos);
+ /* Unroll the most common sample formats: speed +~350% for the loop,
+ +~13% overall (including two common decoders) */
+ switch (am->bps) {
+ case 1:
+ copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, 1);
+ break;
+ case 2:
+ copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, 2);
+ break;
+ case 4:
+ copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, 4);
+ break;
+ default:
+ copy_samples(am->nb_inputs, am->in, am->route, ins, &outs, ns, am->bps);
+ break;
+ }
+
+ nb_samples -= ns;
+ for (i = 0; i < am->nb_inputs; i++) {
+ am->in[i].nb_samples -= ns;
+ am->in[i].pos += ns;
+ if (am->in[i].pos == inbuf[i]->nb_samples) {
+ am->in[i].pos = 0;
+ av_frame_free(&inbuf[i]);
+ ff_bufqueue_get(&am->in[i].queue);
+ inbuf[i] = ff_bufqueue_peek(&am->in[i].queue, 0);
+ ins[i] = inbuf[i] ? inbuf[i]->data[0] : NULL;
+ }
+ }
+ }
+ return ff_filter_frame(ctx->outputs[0], outbuf);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AMergeContext *am = ctx->priv;
+ int i;
+
+ am->in = av_calloc(am->nb_inputs, sizeof(*am->in));
+ if (!am->in)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < am->nb_inputs; i++) {
+ char *name = av_asprintf("in%d", i);
+ AVFilterPad pad = {
+ .name = name,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ };
+ if (!name)
+ return AVERROR(ENOMEM);
+ ff_insert_inpad(ctx, i, &pad);
+ }
+ return 0;
+}
+
+static const AVFilterPad amerge_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_amerge = {
+ .name = "amerge",
+ .description = NULL_IF_CONFIG_SMALL("Merge two or more audio streams into "
+ "a single multi-channel stream."),
+ .priv_size = sizeof(AMergeContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = amerge_outputs,
+ .priv_class = &amerge_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c
index bfba1504ea..9a3cbd4dcd 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -2,20 +2,20 @@
* Audio Mix Filter
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -110,7 +110,7 @@ static void frame_list_remove_samples(FrameList *frame_list, int nb_samples)
int samples = nb_samples;
while (samples > 0) {
FrameInfo *info = frame_list->list;
- av_assert0(info != NULL);
+ av_assert0(info);
if (info->nb_samples <= samples) {
samples -= info->nb_samples;
frame_list->list = info->next;
@@ -142,7 +142,7 @@ static int frame_list_add_frame(FrameList *frame_list, int nb_samples, int64_t p
frame_list->list = info;
frame_list->end = info;
} else {
- av_assert0(frame_list->end != NULL);
+ av_assert0(frame_list->end);
frame_list->end->next = info;
frame_list->end = info;
}
@@ -155,7 +155,7 @@ static int frame_list_add_frame(FrameList *frame_list, int nb_samples, int64_t p
typedef struct MixContext {
const AVClass *class; /**< class for AVOptions */
- AVFloatDSPContext fdsp;
+ AVFloatDSPContext *fdsp;
int nb_inputs; /**< number of inputs */
int active_inputs; /**< number of input currently active */
@@ -175,27 +175,22 @@ typedef struct MixContext {
#define OFFSET(x) offsetof(MixContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
-static const AVOption options[] = {
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption amix_options[] = {
{ "inputs", "Number of inputs.",
- OFFSET(nb_inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 32, A },
+ OFFSET(nb_inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 32, A|F },
{ "duration", "How to determine the end-of-stream.",
- OFFSET(duration_mode), AV_OPT_TYPE_INT, { .i64 = DURATION_LONGEST }, 0, 2, A, "duration" },
- { "longest", "Duration of longest input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_LONGEST }, INT_MIN, INT_MAX, A, "duration" },
- { "shortest", "Duration of shortest input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_SHORTEST }, INT_MIN, INT_MAX, A, "duration" },
- { "first", "Duration of first input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_FIRST }, INT_MIN, INT_MAX, A, "duration" },
+ OFFSET(duration_mode), AV_OPT_TYPE_INT, { .i64 = DURATION_LONGEST }, 0, 2, A|F, "duration" },
+ { "longest", "Duration of longest input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_LONGEST }, INT_MIN, INT_MAX, A|F, "duration" },
+ { "shortest", "Duration of shortest input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_SHORTEST }, INT_MIN, INT_MAX, A|F, "duration" },
+ { "first", "Duration of first input.", 0, AV_OPT_TYPE_CONST, { .i64 = DURATION_FIRST }, INT_MIN, INT_MAX, A|F, "duration" },
{ "dropout_transition", "Transition time, in seconds, for volume "
"renormalization when an input stream ends.",
- OFFSET(dropout_transition), AV_OPT_TYPE_FLOAT, { .dbl = 2.0 }, 0, INT_MAX, A },
- { NULL },
-};
-
-static const AVClass amix_class = {
- .class_name = "amix filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ OFFSET(dropout_transition), AV_OPT_TYPE_FLOAT, { .dbl = 2.0 }, 0, INT_MAX, A|F },
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(amix);
/**
* Update the scaling factors to apply to each input during mixing.
@@ -237,7 +232,7 @@ static int config_output(AVFilterLink *outlink)
if (!s->frame_list)
return AVERROR(ENOMEM);
- s->fifos = av_mallocz(s->nb_inputs * sizeof(*s->fifos));
+ s->fifos = av_mallocz_array(s->nb_inputs, sizeof(*s->fifos));
if (!s->fifos)
return AVERROR(ENOMEM);
@@ -254,7 +249,7 @@ static int config_output(AVFilterLink *outlink)
memset(s->input_state, INPUT_ON, s->nb_inputs);
s->active_inputs = s->nb_inputs;
- s->input_scale = av_mallocz(s->nb_inputs * sizeof(*s->input_scale));
+ s->input_scale = av_mallocz_array(s->nb_inputs, sizeof(*s->input_scale));
if (!s->input_scale)
return AVERROR(ENOMEM);
s->scale_norm = s->active_inputs;
@@ -303,7 +298,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples)
plane_size = FFALIGN(plane_size, 16);
for (p = 0; p < planes; p++) {
- s->fdsp.vector_fmac_scalar((float *)out_buf->extended_data[p],
+ s->fdsp->vector_fmac_scalar((float *)out_buf->extended_data[p],
(float *) in_buf->extended_data[p],
s->input_scale[i], plane_size);
}
@@ -501,12 +496,16 @@ static av_cold int init(AVFilterContext *ctx)
snprintf(name, sizeof(name), "input%d", i);
pad.type = AVMEDIA_TYPE_AUDIO;
pad.name = av_strdup(name);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
pad.filter_frame = filter_frame;
ff_insert_inpad(ctx, i, &pad);
}
- avpriv_float_dsp_init(&s->fdsp, 0);
+ s->fdsp = avpriv_float_dsp_alloc(0);
+ if (!s->fdsp)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -525,6 +524,7 @@ static av_cold void uninit(AVFilterContext *ctx)
av_freep(&s->frame_list);
av_freep(&s->input_state);
av_freep(&s->input_scale);
+ av_freep(&s->fdsp);
for (i = 0; i < ctx->nb_inputs; i++)
av_freep(&ctx->input_pads[i].name);
@@ -533,12 +533,23 @@ static av_cold void uninit(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts;
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+
+ if (!layouts)
+ return AVERROR(ENOMEM);
+
ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
ff_add_format(&formats, AV_SAMPLE_FMT_FLTP);
- ff_set_common_formats(ctx, formats);
- ff_set_common_channel_layouts(ctx, ff_all_channel_layouts());
- ff_set_common_samplerates(ctx, ff_all_samplerates());
- return 0;
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+ return ff_set_common_samplerates(ctx, ff_all_samplerates());
}
static const AVFilterPad avfilter_af_amix_outputs[] = {
@@ -552,17 +563,14 @@ static const AVFilterPad avfilter_af_amix_outputs[] = {
};
AVFilter ff_af_amix = {
- .name = "amix",
- .description = NULL_IF_CONFIG_SMALL("Audio mixing."),
- .priv_size = sizeof(MixContext),
- .priv_class = &amix_class,
-
+ .name = "amix",
+ .description = NULL_IF_CONFIG_SMALL("Audio mixing."),
+ .priv_size = sizeof(MixContext),
+ .priv_class = &amix_class,
.init = init,
.uninit = uninit,
.query_formats = query_formats,
-
- .inputs = NULL,
- .outputs = avfilter_af_amix_outputs,
-
- .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+ .inputs = NULL,
+ .outputs = avfilter_af_amix_outputs,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
};
diff --git a/libavfilter/af_anull.c b/libavfilter/af_anull.c
index 6d7caf3f4e..fff456e8ea 100644
--- a/libavfilter/af_anull.c
+++ b/libavfilter/af_anull.c
@@ -1,18 +1,19 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,9 +29,8 @@
static const AVFilterPad avfilter_af_anull_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
},
{ NULL }
};
@@ -44,12 +44,9 @@ static const AVFilterPad avfilter_af_anull_outputs[] = {
};
AVFilter ff_af_anull = {
- .name = "anull",
- .description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
-
- .priv_size = 0,
-
- .inputs = avfilter_af_anull_inputs,
-
- .outputs = avfilter_af_anull_outputs,
+ .name = "anull",
+ .description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
+ .query_formats = ff_query_formats_all,
+ .inputs = avfilter_af_anull_inputs,
+ .outputs = avfilter_af_anull_outputs,
};
diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c
new file mode 100644
index 0000000000..eafc7050e8
--- /dev/null
+++ b/libavfilter/af_apad.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2012 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio pad filter.
+ *
+ * Based on af_aresample.c
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+#include "libavutil/avassert.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int64_t next_pts;
+
+ int packet_size;
+ int64_t pad_len, pad_len_left;
+ int64_t whole_len, whole_len_left;
+} APadContext;
+
+#define OFFSET(x) offsetof(APadContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption apad_options[] = {
+ { "packet_size", "set silence packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, { .i64 = 4096 }, 0, INT_MAX, A },
+ { "pad_len", "set number of samples of silence to add", OFFSET(pad_len), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, A },
+ { "whole_len", "set minimum target number of samples in the audio stream", OFFSET(whole_len), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(apad);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ APadContext *apad = ctx->priv;
+
+ apad->next_pts = AV_NOPTS_VALUE;
+ if (apad->whole_len >= 0 && apad->pad_len >= 0) {
+ av_log(ctx, AV_LOG_ERROR, "Both whole and pad length are set, this is not possible\n");
+ return AVERROR(EINVAL);
+ }
+ apad->pad_len_left = apad->pad_len;
+ apad->whole_len_left = apad->whole_len;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ APadContext *apad = ctx->priv;
+
+ if (apad->whole_len >= 0) {
+ apad->whole_len_left = FFMAX(apad->whole_len_left - frame->nb_samples, 0);
+ av_log(ctx, AV_LOG_DEBUG,
+ "n_out:%d whole_len_left:%"PRId64"\n", frame->nb_samples, apad->whole_len_left);
+ }
+
+ apad->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
+ return ff_filter_frame(ctx->outputs[0], frame);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ APadContext *apad = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+
+ if (ret == AVERROR_EOF && !ctx->is_disabled) {
+ int n_out = apad->packet_size;
+ AVFrame *outsamplesref;
+
+ if (apad->whole_len >= 0 && apad->pad_len < 0) {
+ apad->pad_len = apad->pad_len_left = apad->whole_len_left;
+ }
+ if (apad->pad_len >=0 || apad->whole_len >= 0) {
+ n_out = FFMIN(n_out, apad->pad_len_left);
+ apad->pad_len_left -= n_out;
+ av_log(ctx, AV_LOG_DEBUG,
+ "padding n_out:%d pad_len_left:%"PRId64"\n", n_out, apad->pad_len_left);
+ }
+
+ if (!n_out)
+ return AVERROR_EOF;
+
+ outsamplesref = ff_get_audio_buffer(outlink, n_out);
+ if (!outsamplesref)
+ return AVERROR(ENOMEM);
+
+ av_assert0(outsamplesref->sample_rate == outlink->sample_rate);
+ av_assert0(outsamplesref->nb_samples == n_out);
+
+ av_samples_set_silence(outsamplesref->extended_data, 0,
+ n_out,
+ av_frame_get_channels(outsamplesref),
+ outsamplesref->format);
+
+ outsamplesref->pts = apad->next_pts;
+ if (apad->next_pts != AV_NOPTS_VALUE)
+ apad->next_pts += av_rescale_q(n_out, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ return ff_filter_frame(outlink, outsamplesref);
+ }
+ return ret;
+}
+
+static const AVFilterPad apad_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad apad_outputs[] = {
+ {
+ .name = "default",
+ .request_frame = request_frame,
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_apad = {
+ .name = "apad",
+ .description = NULL_IF_CONFIG_SMALL("Pad audio with silence."),
+ .init = init,
+ .priv_size = sizeof(APadContext),
+ .inputs = apad_inputs,
+ .outputs = apad_outputs,
+ .priv_class = &apad_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c
new file mode 100644
index 0000000000..582f6e7981
--- /dev/null
+++ b/libavfilter/af_aphaser.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * phaser audio filter
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "generate_wave_table.h"
+
+typedef struct AudioPhaserContext {
+ const AVClass *class;
+ double in_gain, out_gain;
+ double delay;
+ double decay;
+ double speed;
+
+ int type;
+
+ int delay_buffer_length;
+ double *delay_buffer;
+
+ int modulation_buffer_length;
+ int32_t *modulation_buffer;
+
+ int delay_pos, modulation_pos;
+
+ void (*phaser)(struct AudioPhaserContext *p,
+ uint8_t * const *src, uint8_t **dst,
+ int nb_samples, int channels);
+} AudioPhaserContext;
+
+#define OFFSET(x) offsetof(AudioPhaserContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption aphaser_options[] = {
+ { "in_gain", "set input gain", OFFSET(in_gain), AV_OPT_TYPE_DOUBLE, {.dbl=.4}, 0, 1, FLAGS },
+ { "out_gain", "set output gain", OFFSET(out_gain), AV_OPT_TYPE_DOUBLE, {.dbl=.74}, 0, 1e9, FLAGS },
+ { "delay", "set delay in milliseconds", OFFSET(delay), AV_OPT_TYPE_DOUBLE, {.dbl=3.}, 0, 5, FLAGS },
+ { "decay", "set decay", OFFSET(decay), AV_OPT_TYPE_DOUBLE, {.dbl=.4}, 0, .99, FLAGS },
+ { "speed", "set modulation speed", OFFSET(speed), AV_OPT_TYPE_DOUBLE, {.dbl=.5}, .1, 2, FLAGS },
+ { "type", "set modulation type", OFFSET(type), AV_OPT_TYPE_INT, {.i64=WAVE_TRI}, 0, WAVE_NB-1, FLAGS, "type" },
+ { "triangular", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_TRI}, 0, 0, FLAGS, "type" },
+ { "t", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_TRI}, 0, 0, FLAGS, "type" },
+ { "sinusoidal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_SIN}, 0, 0, FLAGS, "type" },
+ { "s", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_SIN}, 0, 0, FLAGS, "type" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(aphaser);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AudioPhaserContext *p = ctx->priv;
+
+ if (p->in_gain > (1 - p->decay * p->decay))
+ av_log(ctx, AV_LOG_WARNING, "in_gain may cause clipping\n");
+ if (p->in_gain / (1 - p->decay) > 1 / p->out_gain)
+ av_log(ctx, AV_LOG_WARNING, "out_gain may cause clipping\n");
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
+
+#define PHASER_PLANAR(name, type) \
+static void phaser_## name ##p(AudioPhaserContext *p, \
+ uint8_t * const *src, uint8_t **dst, \
+ int nb_samples, int channels) \
+{ \
+ int i, c, delay_pos, modulation_pos; \
+ \
+ av_assert0(channels > 0); \
+ for (c = 0; c < channels; c++) { \
+ type *s = (type *)src[c]; \
+ type *d = (type *)dst[c]; \
+ double *buffer = p->delay_buffer + \
+ c * p->delay_buffer_length; \
+ \
+ delay_pos = p->delay_pos; \
+ modulation_pos = p->modulation_pos; \
+ \
+ for (i = 0; i < nb_samples; i++, s++, d++) { \
+ double v = *s * p->in_gain + buffer[ \
+ MOD(delay_pos + p->modulation_buffer[ \
+ modulation_pos], \
+ p->delay_buffer_length)] * p->decay; \
+ \
+ modulation_pos = MOD(modulation_pos + 1, \
+ p->modulation_buffer_length); \
+ delay_pos = MOD(delay_pos + 1, p->delay_buffer_length); \
+ buffer[delay_pos] = v; \
+ \
+ *d = v * p->out_gain; \
+ } \
+ } \
+ \
+ p->delay_pos = delay_pos; \
+ p->modulation_pos = modulation_pos; \
+}
+
+#define PHASER(name, type) \
+static void phaser_## name (AudioPhaserContext *p, \
+ uint8_t * const *src, uint8_t **dst, \
+ int nb_samples, int channels) \
+{ \
+ int i, c, delay_pos, modulation_pos; \
+ type *s = (type *)src[0]; \
+ type *d = (type *)dst[0]; \
+ double *buffer = p->delay_buffer; \
+ \
+ delay_pos = p->delay_pos; \
+ modulation_pos = p->modulation_pos; \
+ \
+ for (i = 0; i < nb_samples; i++) { \
+ int pos = MOD(delay_pos + p->modulation_buffer[modulation_pos], \
+ p->delay_buffer_length) * channels; \
+ int npos; \
+ \
+ delay_pos = MOD(delay_pos + 1, p->delay_buffer_length); \
+ npos = delay_pos * channels; \
+ for (c = 0; c < channels; c++, s++, d++) { \
+ double v = *s * p->in_gain + buffer[pos + c] * p->decay; \
+ \
+ buffer[npos + c] = v; \
+ \
+ *d = v * p->out_gain; \
+ } \
+ \
+ modulation_pos = MOD(modulation_pos + 1, \
+ p->modulation_buffer_length); \
+ } \
+ \
+ p->delay_pos = delay_pos; \
+ p->modulation_pos = modulation_pos; \
+}
+
+PHASER_PLANAR(dbl, double)
+PHASER_PLANAR(flt, float)
+PHASER_PLANAR(s16, int16_t)
+PHASER_PLANAR(s32, int32_t)
+
+PHASER(dbl, double)
+PHASER(flt, float)
+PHASER(s16, int16_t)
+PHASER(s32, int32_t)
+
+static int config_output(AVFilterLink *outlink)
+{
+ AudioPhaserContext *p = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+
+ p->delay_buffer_length = p->delay * 0.001 * inlink->sample_rate + 0.5;
+ if (p->delay_buffer_length <= 0) {
+ av_log(outlink->src, AV_LOG_ERROR, "delay is too small\n");
+ return AVERROR(EINVAL);
+ }
+ p->delay_buffer = av_calloc(p->delay_buffer_length, sizeof(*p->delay_buffer) * inlink->channels);
+ p->modulation_buffer_length = inlink->sample_rate / p->speed + 0.5;
+ p->modulation_buffer = av_malloc_array(p->modulation_buffer_length, sizeof(*p->modulation_buffer));
+
+ if (!p->modulation_buffer || !p->delay_buffer)
+ return AVERROR(ENOMEM);
+
+ ff_generate_wave_table(p->type, AV_SAMPLE_FMT_S32,
+ p->modulation_buffer, p->modulation_buffer_length,
+ 1., p->delay_buffer_length, M_PI / 2.0);
+
+ p->delay_pos = p->modulation_pos = 0;
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_DBL: p->phaser = phaser_dbl; break;
+ case AV_SAMPLE_FMT_DBLP: p->phaser = phaser_dblp; break;
+ case AV_SAMPLE_FMT_FLT: p->phaser = phaser_flt; break;
+ case AV_SAMPLE_FMT_FLTP: p->phaser = phaser_fltp; break;
+ case AV_SAMPLE_FMT_S16: p->phaser = phaser_s16; break;
+ case AV_SAMPLE_FMT_S16P: p->phaser = phaser_s16p; break;
+ case AV_SAMPLE_FMT_S32: p->phaser = phaser_s32; break;
+ case AV_SAMPLE_FMT_S32P: p->phaser = phaser_s32p; break;
+ default: av_assert0(0);
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inbuf)
+{
+ AudioPhaserContext *p = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outbuf;
+
+ if (av_frame_is_writable(inbuf)) {
+ outbuf = inbuf;
+ } else {
+ outbuf = ff_get_audio_buffer(inlink, inbuf->nb_samples);
+ if (!outbuf)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(outbuf, inbuf);
+ }
+
+ p->phaser(p, inbuf->extended_data, outbuf->extended_data,
+ outbuf->nb_samples, av_frame_get_channels(outbuf));
+
+ if (inbuf != outbuf)
+ av_frame_free(&inbuf);
+
+ return ff_filter_frame(outlink, outbuf);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AudioPhaserContext *p = ctx->priv;
+
+ av_freep(&p->delay_buffer);
+ av_freep(&p->modulation_buffer);
+}
+
+static const AVFilterPad aphaser_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad aphaser_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aphaser = {
+ .name = "aphaser",
+ .description = NULL_IF_CONFIG_SMALL("Add a phasing effect to the audio."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(AudioPhaserContext),
+ .init = init,
+ .uninit = uninit,
+ .inputs = aphaser_inputs,
+ .outputs = aphaser_outputs,
+ .priv_class = &aphaser_class,
+};
diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c
new file mode 100644
index 0000000000..57ac3978be
--- /dev/null
+++ b/libavfilter/af_aresample.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2011 Mina Nagy Zaki
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * resampling audio filter
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+#include "libavutil/avassert.h"
+#include "libswresample/swresample.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int sample_rate_arg;
+ double ratio;
+ struct SwrContext *swr;
+ int64_t next_pts;
+ int req_fullfilled;
+ int more_data;
+} AResampleContext;
+
+static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts)
+{
+ AResampleContext *aresample = ctx->priv;
+ int ret = 0;
+
+ aresample->next_pts = AV_NOPTS_VALUE;
+ aresample->swr = swr_alloc();
+ if (!aresample->swr) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ if (opts) {
+ AVDictionaryEntry *e = NULL;
+
+ while ((e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = av_opt_set(aresample->swr, e->key, e->value, 0)) < 0)
+ goto end;
+ }
+ av_dict_free(opts);
+ }
+ if (aresample->sample_rate_arg > 0)
+ av_opt_set_int(aresample->swr, "osr", aresample->sample_rate_arg, 0);
+end:
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AResampleContext *aresample = ctx->priv;
+ swr_free(&aresample->swr);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AResampleContext *aresample = ctx->priv;
+ int out_rate = av_get_int(aresample->swr, "osr", NULL);
+ uint64_t out_layout = av_get_int(aresample->swr, "ocl", NULL);
+ enum AVSampleFormat out_format = av_get_int(aresample->swr, "osf", NULL);
+
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ AVFilterFormats *in_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
+ AVFilterFormats *out_formats;
+ AVFilterFormats *in_samplerates = ff_all_samplerates();
+ AVFilterFormats *out_samplerates;
+ AVFilterChannelLayouts *in_layouts = ff_all_channel_counts();
+ AVFilterChannelLayouts *out_layouts;
+
+ ff_formats_ref (in_formats, &inlink->out_formats);
+ ff_formats_ref (in_samplerates, &inlink->out_samplerates);
+ ff_channel_layouts_ref(in_layouts, &inlink->out_channel_layouts);
+
+ if(out_rate > 0) {
+ int ratelist[] = { out_rate, -1 };
+ out_samplerates = ff_make_format_list(ratelist);
+ } else {
+ out_samplerates = ff_all_samplerates();
+ }
+ if (!out_samplerates) {
+ av_log(ctx, AV_LOG_ERROR, "Cannot allocate output samplerates.\n");
+ return AVERROR(ENOMEM);
+ }
+
+ ff_formats_ref(out_samplerates, &outlink->in_samplerates);
+
+ if(out_format != AV_SAMPLE_FMT_NONE) {
+ int formatlist[] = { out_format, -1 };
+ out_formats = ff_make_format_list(formatlist);
+ } else
+ out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
+ ff_formats_ref(out_formats, &outlink->in_formats);
+
+ if(out_layout) {
+ int64_t layout_list[] = { out_layout, -1 };
+ out_layouts = avfilter_make_format64_list(layout_list);
+ } else
+ out_layouts = ff_all_channel_counts();
+ ff_channel_layouts_ref(out_layouts, &outlink->in_channel_layouts);
+
+ return 0;
+}
+
+
+static int config_output(AVFilterLink *outlink)
+{
+ int ret;
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AResampleContext *aresample = ctx->priv;
+ int out_rate;
+ uint64_t out_layout;
+ enum AVSampleFormat out_format;
+ char inchl_buf[128], outchl_buf[128];
+
+ aresample->swr = swr_alloc_set_opts(aresample->swr,
+ outlink->channel_layout, outlink->format, outlink->sample_rate,
+ inlink->channel_layout, inlink->format, inlink->sample_rate,
+ 0, ctx);
+ if (!aresample->swr)
+ return AVERROR(ENOMEM);
+ if (!inlink->channel_layout)
+ av_opt_set_int(aresample->swr, "ich", inlink->channels, 0);
+ if (!outlink->channel_layout)
+ av_opt_set_int(aresample->swr, "och", outlink->channels, 0);
+
+ ret = swr_init(aresample->swr);
+ if (ret < 0)
+ return ret;
+
+ out_rate = av_get_int(aresample->swr, "osr", NULL);
+ out_layout = av_get_int(aresample->swr, "ocl", NULL);
+ out_format = av_get_int(aresample->swr, "osf", NULL);
+ outlink->time_base = (AVRational) {1, out_rate};
+
+ av_assert0(outlink->sample_rate == out_rate);
+ av_assert0(outlink->channel_layout == out_layout || !outlink->channel_layout);
+ av_assert0(outlink->format == out_format);
+
+ aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate;
+
+ av_get_channel_layout_string(inchl_buf, sizeof(inchl_buf), inlink ->channels, inlink ->channel_layout);
+ av_get_channel_layout_string(outchl_buf, sizeof(outchl_buf), outlink->channels, outlink->channel_layout);
+
+ av_log(ctx, AV_LOG_VERBOSE, "ch:%d chl:%s fmt:%s r:%dHz -> ch:%d chl:%s fmt:%s r:%dHz\n",
+ inlink ->channels, inchl_buf, av_get_sample_fmt_name(inlink->format), inlink->sample_rate,
+ outlink->channels, outchl_buf, av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamplesref)
+{
+ AResampleContext *aresample = inlink->dst->priv;
+ const int n_in = insamplesref->nb_samples;
+ int64_t delay;
+ int n_out = n_in * aresample->ratio + 32;
+ AVFilterLink *const outlink = inlink->dst->outputs[0];
+ AVFrame *outsamplesref;
+ int ret;
+
+ delay = swr_get_delay(aresample->swr, outlink->sample_rate);
+ if (delay > 0)
+ n_out += FFMIN(delay, FFMAX(4096, n_out));
+
+ outsamplesref = ff_get_audio_buffer(outlink, n_out);
+
+ if(!outsamplesref)
+ return AVERROR(ENOMEM);
+
+ av_frame_copy_props(outsamplesref, insamplesref);
+ outsamplesref->format = outlink->format;
+ av_frame_set_channels(outsamplesref, outlink->channels);
+ outsamplesref->channel_layout = outlink->channel_layout;
+ outsamplesref->sample_rate = outlink->sample_rate;
+
+ if(insamplesref->pts != AV_NOPTS_VALUE) {
+ int64_t inpts = av_rescale(insamplesref->pts, inlink->time_base.num * (int64_t)outlink->sample_rate * inlink->sample_rate, inlink->time_base.den);
+ int64_t outpts= swr_next_pts(aresample->swr, inpts);
+ aresample->next_pts =
+ outsamplesref->pts = ROUNDED_DIV(outpts, inlink->sample_rate);
+ } else {
+ outsamplesref->pts = AV_NOPTS_VALUE;
+ }
+ n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out,
+ (void *)insamplesref->extended_data, n_in);
+ if (n_out <= 0) {
+ av_frame_free(&outsamplesref);
+ av_frame_free(&insamplesref);
+ return 0;
+ }
+
+ aresample->more_data = outsamplesref->nb_samples == n_out; // Indicate that there is probably more data in our buffers
+
+ outsamplesref->nb_samples = n_out;
+
+ ret = ff_filter_frame(outlink, outsamplesref);
+ aresample->req_fullfilled= 1;
+ av_frame_free(&insamplesref);
+ return ret;
+}
+
+static int flush_frame(AVFilterLink *outlink, int final, AVFrame **outsamplesref_ret)
+{
+ AVFilterContext *ctx = outlink->src;
+ AResampleContext *aresample = ctx->priv;
+ AVFilterLink *const inlink = outlink->src->inputs[0];
+ AVFrame *outsamplesref;
+ int n_out = 4096;
+ int64_t pts;
+
+ outsamplesref = ff_get_audio_buffer(outlink, n_out);
+ *outsamplesref_ret = outsamplesref;
+ if (!outsamplesref)
+ return AVERROR(ENOMEM);
+
+ pts = swr_next_pts(aresample->swr, INT64_MIN);
+ pts = ROUNDED_DIV(pts, inlink->sample_rate);
+
+ n_out = swr_convert(aresample->swr, outsamplesref->extended_data, n_out, final ? NULL : (void*)outsamplesref->extended_data, 0);
+ if (n_out <= 0) {
+ av_frame_free(&outsamplesref);
+ return (n_out == 0) ? AVERROR_EOF : n_out;
+ }
+
+ outsamplesref->sample_rate = outlink->sample_rate;
+ outsamplesref->nb_samples = n_out;
+
+ outsamplesref->pts = pts;
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AResampleContext *aresample = ctx->priv;
+ int ret;
+
+ // First try to get data from the internal buffers
+ if (aresample->more_data) {
+ AVFrame *outsamplesref;
+
+ if (flush_frame(outlink, 0, &outsamplesref) >= 0) {
+ return ff_filter_frame(outlink, outsamplesref);
+ }
+ }
+ aresample->more_data = 0;
+
+ // Second request more data from the input
+ aresample->req_fullfilled = 0;
+ do{
+ ret = ff_request_frame(ctx->inputs[0]);
+ }while(!aresample->req_fullfilled && ret>=0);
+
+ // Third if we hit the end flush
+ if (ret == AVERROR_EOF) {
+ AVFrame *outsamplesref;
+
+ if ((ret = flush_frame(outlink, 1, &outsamplesref)) < 0)
+ return ret;
+
+ return ff_filter_frame(outlink, outsamplesref);
+ }
+ return ret;
+}
+
+static const AVClass *resample_child_class_next(const AVClass *prev)
+{
+ return prev ? NULL : swr_get_class();
+}
+
+static void *resample_child_next(void *obj, void *prev)
+{
+ AResampleContext *s = obj;
+ return prev ? NULL : s->swr;
+}
+
+#define OFFSET(x) offsetof(AResampleContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption options[] = {
+ {"sample_rate", NULL, OFFSET(sample_rate_arg), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+ {NULL}
+};
+
+static const AVClass aresample_class = {
+ .class_name = "aresample",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .child_class_next = resample_child_class_next,
+ .child_next = resample_child_next,
+};
+
+static const AVFilterPad aresample_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad aresample_outputs[] = {
+ {
+ .name = "default",
+ .config_props = config_output,
+ .request_frame = request_frame,
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aresample = {
+ .name = "aresample",
+ .description = NULL_IF_CONFIG_SMALL("Resample audio data."),
+ .init_dict = init_dict,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(AResampleContext),
+ .priv_class = &aresample_class,
+ .inputs = aresample_inputs,
+ .outputs = aresample_outputs,
+};
diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c
new file mode 100644
index 0000000000..e830643115
--- /dev/null
+++ b/libavfilter/af_asetnsamples.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2012 Andrey Utkin
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Filter that changes number of samples on single output operation
+ */
+
+#include "libavutil/audio_fifo.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+#include "formats.h"
+
+typedef struct {
+ const AVClass *class;
+ int nb_out_samples; ///< how many samples to output
+ AVAudioFifo *fifo; ///< samples are queued here
+ int64_t next_out_pts;
+ int pad;
+} ASNSContext;
+
+#define OFFSET(x) offsetof(ASNSContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption asetnsamples_options[] = {
+ { "nb_out_samples", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
+ { "n", "set the number of per-frame output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
+ { "pad", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { "p", "pad last frame with zeros", OFFSET(pad), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(asetnsamples);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ASNSContext *asns = ctx->priv;
+
+ asns->next_out_pts = AV_NOPTS_VALUE;
+ av_log(ctx, AV_LOG_VERBOSE, "nb_out_samples:%d pad:%d\n", asns->nb_out_samples, asns->pad);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ASNSContext *asns = ctx->priv;
+ av_audio_fifo_free(asns->fifo);
+}
+
+static int config_props_output(AVFilterLink *outlink)
+{
+ ASNSContext *asns = outlink->src->priv;
+
+ asns->fifo = av_audio_fifo_alloc(outlink->format, outlink->channels, asns->nb_out_samples);
+ if (!asns->fifo)
+ return AVERROR(ENOMEM);
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return 0;
+}
+
+static int push_samples(AVFilterLink *outlink)
+{
+ ASNSContext *asns = outlink->src->priv;
+ AVFrame *outsamples = NULL;
+ int ret, nb_out_samples, nb_pad_samples;
+
+ if (asns->pad) {
+ nb_out_samples = av_audio_fifo_size(asns->fifo) ? asns->nb_out_samples : 0;
+ nb_pad_samples = nb_out_samples - FFMIN(nb_out_samples, av_audio_fifo_size(asns->fifo));
+ } else {
+ nb_out_samples = FFMIN(asns->nb_out_samples, av_audio_fifo_size(asns->fifo));
+ nb_pad_samples = 0;
+ }
+
+ if (!nb_out_samples)
+ return 0;
+
+ outsamples = ff_get_audio_buffer(outlink, nb_out_samples);
+ if (!outsamples)
+ return AVERROR(ENOMEM);
+
+ av_audio_fifo_read(asns->fifo,
+ (void **)outsamples->extended_data, nb_out_samples);
+
+ if (nb_pad_samples)
+ av_samples_set_silence(outsamples->extended_data, nb_out_samples - nb_pad_samples,
+ nb_pad_samples, outlink->channels,
+ outlink->format);
+ outsamples->nb_samples = nb_out_samples;
+ outsamples->channel_layout = outlink->channel_layout;
+ outsamples->sample_rate = outlink->sample_rate;
+ outsamples->pts = asns->next_out_pts;
+
+ if (asns->next_out_pts != AV_NOPTS_VALUE)
+ asns->next_out_pts += av_rescale_q(nb_out_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ ret = ff_filter_frame(outlink, outsamples);
+ if (ret < 0)
+ return ret;
+ return nb_out_samples;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ASNSContext *asns = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int ret;
+ int nb_samples = insamples->nb_samples;
+
+ if (av_audio_fifo_space(asns->fifo) < nb_samples) {
+ av_log(ctx, AV_LOG_DEBUG, "No space for %d samples, stretching audio fifo\n", nb_samples);
+ ret = av_audio_fifo_realloc(asns->fifo, av_audio_fifo_size(asns->fifo) + nb_samples);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Stretching audio fifo failed, discarded %d samples\n", nb_samples);
+ return -1;
+ }
+ }
+ av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples);
+ if (asns->next_out_pts == AV_NOPTS_VALUE)
+ asns->next_out_pts = insamples->pts;
+ av_frame_free(&insamples);
+
+ while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples)
+ push_samples(outlink);
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ int ret;
+
+ ret = ff_request_frame(inlink);
+ if (ret == AVERROR_EOF) {
+ ret = push_samples(outlink);
+ return ret < 0 ? ret : ret > 0 ? 0 : AVERROR_EOF;
+ }
+
+ return ret;
+}
+
+static const AVFilterPad asetnsamples_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad asetnsamples_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = request_frame,
+ .config_props = config_props_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_asetnsamples = {
+ .name = "asetnsamples",
+ .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."),
+ .priv_size = sizeof(ASNSContext),
+ .priv_class = &asetnsamples_class,
+ .init = init,
+ .uninit = uninit,
+ .inputs = asetnsamples_inputs,
+ .outputs = asetnsamples_outputs,
+};
diff --git a/libavfilter/af_asetrate.c b/libavfilter/af_asetrate.c
new file mode 100644
index 0000000000..409c48fd14
--- /dev/null
+++ b/libavfilter/af_asetrate.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int sample_rate;
+ int rescale_pts;
+} ASetRateContext;
+
+#define CONTEXT ASetRateContext
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#define OPT_GENERIC(name, field, def, min, max, descr, type, deffield, ...) \
+ { name, descr, offsetof(CONTEXT, field), AV_OPT_TYPE_ ## type, \
+ { .deffield = def }, min, max, FLAGS, __VA_ARGS__ }
+
+#define OPT_INT(name, field, def, min, max, descr, ...) \
+ OPT_GENERIC(name, field, def, min, max, descr, INT, i64, __VA_ARGS__)
+
+static const AVOption asetrate_options[] = {
+ OPT_INT("sample_rate", sample_rate, 44100, 1, INT_MAX, "set the sample rate"),
+ OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate"),
+ {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(asetrate);
+
+static av_cold int query_formats(AVFilterContext *ctx)
+{
+ ASetRateContext *sr = ctx->priv;
+ int sample_rates[] = { sr->sample_rate, -1 };
+
+ return ff_formats_ref(ff_make_format_list(sample_rates),
+ &ctx->outputs[0]->in_samplerates);
+}
+
+static av_cold int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ASetRateContext *sr = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVRational intb = ctx->inputs[0]->time_base;
+ int inrate = inlink->sample_rate;
+
+ if (intb.num == 1 && intb.den == inrate) {
+ outlink->time_base.num = 1;
+ outlink->time_base.den = outlink->sample_rate;
+ } else {
+ outlink->time_base = intb;
+ sr->rescale_pts = 1;
+ if (av_q2d(intb) > 1.0 / FFMAX(inrate, outlink->sample_rate))
+ av_log(ctx, AV_LOG_WARNING, "Time base is inaccurate\n");
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ASetRateContext *sr = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ frame->sample_rate = outlink->sample_rate;
+ if (sr->rescale_pts)
+ frame->pts = av_rescale(frame->pts, inlink->sample_rate,
+ outlink->sample_rate);
+ return ff_filter_frame(outlink, frame);
+}
+
+static const AVFilterPad asetrate_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad asetrate_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_asetrate = {
+ .name = "asetrate",
+ .description = NULL_IF_CONFIG_SMALL("Change the sample rate without "
+ "altering the data."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(ASetRateContext),
+ .inputs = asetrate_inputs,
+ .outputs = asetrate_outputs,
+ .priv_class = &asetrate_class,
+};
diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c
index 5f0e2549ff..ca33add335 100644
--- a/libavfilter/af_ashowinfo.c
+++ b/libavfilter/af_ashowinfo.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "libavutil/replaygain.h"
+#include "libavutil/timestamp.h"
#include "libavutil/samplefmt.h"
#include "libavcodec/avcodec.h"
@@ -47,24 +48,8 @@ typedef struct AShowInfoContext {
* Scratch space for individual plane checksums for planar audio
*/
uint32_t *plane_checksums;
-
- /**
- * Frame counter
- */
- uint64_t frame;
} AShowInfoContext;
-static int config_input(AVFilterLink *inlink)
-{
- AShowInfoContext *s = inlink->dst->priv;
- int channels = av_get_channel_layout_nb_channels(inlink->channel_layout);
- s->plane_checksums = av_malloc(channels * sizeof(*s->plane_checksums));
- if (!s->plane_checksums)
- return AVERROR(ENOMEM);
-
- return 0;
-}
-
static av_cold void uninit(AVFilterContext *ctx)
{
AShowInfoContext *s = ctx->priv;
@@ -194,12 +179,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
AShowInfoContext *s = ctx->priv;
char chlayout_str[128];
uint32_t checksum = 0;
- int channels = av_get_channel_layout_nb_channels(buf->channel_layout);
+ int channels = inlink->channels;
int planar = av_sample_fmt_is_planar(buf->format);
int block_align = av_get_bytes_per_sample(buf->format) * (planar ? 1 : channels);
int data_size = buf->nb_samples * block_align;
int planes = planar ? channels : 1;
int i;
+ void *tmp_ptr = av_realloc_array(s->plane_checksums, channels, sizeof(*s->plane_checksums));
+
+ if (!tmp_ptr)
+ return AVERROR(ENOMEM);
+ s->plane_checksums = tmp_ptr;
for (i = 0; i < planes; i++) {
uint8_t *data = buf->extended_data[i];
@@ -213,11 +203,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
buf->channel_layout);
av_log(ctx, AV_LOG_INFO,
- "n:%"PRIu64" pts:%"PRId64" pts_time:%f "
- "fmt:%s chlayout:%s rate:%d nb_samples:%d "
+ "n:%"PRId64" pts:%s pts_time:%s pos:%"PRId64" "
+ "fmt:%s channels:%d chlayout:%s rate:%d nb_samples:%d "
"checksum:%08"PRIX32" ",
- s->frame, buf->pts, buf->pts * av_q2d(inlink->time_base),
- av_get_sample_fmt_name(buf->format), chlayout_str,
+ inlink->frame_count,
+ av_ts2str(buf->pts), av_ts2timestr(buf->pts, &inlink->time_base),
+ av_frame_get_pkt_pos(buf),
+ av_get_sample_fmt_name(buf->format), av_frame_get_channels(buf), chlayout_str,
buf->sample_rate, buf->nb_samples,
checksum);
@@ -241,19 +233,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
av_log(ctx, AV_LOG_INFO, "\n");
}
- s->frame++;
return ff_filter_frame(inlink->dst->outputs[0], buf);
}
static const AVFilterPad inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
- .config_props = config_input,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
},
- { NULL },
+ { NULL }
};
static const AVFilterPad outputs[] = {
@@ -261,7 +250,7 @@ static const AVFilterPad outputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
},
- { NULL },
+ { NULL }
};
AVFilter ff_af_ashowinfo = {
diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c
new file mode 100644
index 0000000000..5780fb900a
--- /dev/null
+++ b/libavfilter/af_astats.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2009 Rob Sykes <robs@users.sourceforge.net>
+ * Copyright (c) 2013 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
+ */
+
+#include <float.h>
+
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct ChannelStats {
+ double last;
+ double sigma_x, sigma_x2;
+ double avg_sigma_x2, min_sigma_x2, max_sigma_x2;
+ double min, max;
+ double min_run, max_run;
+ double min_runs, max_runs;
+ uint64_t min_count, max_count;
+ uint64_t nb_samples;
+} ChannelStats;
+
+typedef struct {
+ const AVClass *class;
+ ChannelStats *chstats;
+ int nb_channels;
+ uint64_t tc_samples;
+ double time_constant;
+ double mult;
+} AudioStatsContext;
+
+#define OFFSET(x) offsetof(AudioStatsContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption astats_options[] = {
+ { "length", "set the window length", OFFSET(time_constant), AV_OPT_TYPE_DOUBLE, {.dbl=.05}, .01, 10, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(astats);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AudioStatsContext *s = outlink->src->priv;
+ int c;
+
+ s->chstats = av_calloc(sizeof(*s->chstats), outlink->channels);
+ if (!s->chstats)
+ return AVERROR(ENOMEM);
+ s->nb_channels = outlink->channels;
+ s->mult = exp((-1 / s->time_constant / outlink->sample_rate));
+ s->tc_samples = 5 * s->time_constant * outlink->sample_rate + .5;
+
+ for (c = 0; c < s->nb_channels; c++) {
+ ChannelStats *p = &s->chstats[c];
+
+ p->min = p->min_sigma_x2 = DBL_MAX;
+ p->max = p->max_sigma_x2 = DBL_MIN;
+ }
+
+ return 0;
+}
+
+static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d)
+{
+ if (d < p->min) {
+ p->min = d;
+ p->min_run = 1;
+ p->min_runs = 0;
+ p->min_count = 1;
+ } else if (d == p->min) {
+ p->min_count++;
+ p->min_run = d == p->last ? p->min_run + 1 : 1;
+ } else if (p->last == p->min) {
+ p->min_runs += p->min_run * p->min_run;
+ }
+
+ if (d > p->max) {
+ p->max = d;
+ p->max_run = 1;
+ p->max_runs = 0;
+ p->max_count = 1;
+ } else if (d == p->max) {
+ p->max_count++;
+ p->max_run = d == p->last ? p->max_run + 1 : 1;
+ } else if (p->last == p->max) {
+ p->max_runs += p->max_run * p->max_run;
+ }
+
+ p->sigma_x += d;
+ p->sigma_x2 += d * d;
+ p->avg_sigma_x2 = p->avg_sigma_x2 * s->mult + (1.0 - s->mult) * d * d;
+ p->last = d;
+
+ if (p->nb_samples >= s->tc_samples) {
+ p->max_sigma_x2 = FFMAX(p->max_sigma_x2, p->avg_sigma_x2);
+ p->min_sigma_x2 = FFMIN(p->min_sigma_x2, p->avg_sigma_x2);
+ }
+ p->nb_samples++;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ AudioStatsContext *s = inlink->dst->priv;
+ const int channels = s->nb_channels;
+ const double *src;
+ int i, c;
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_DBLP:
+ for (c = 0; c < channels; c++) {
+ ChannelStats *p = &s->chstats[c];
+ src = (const double *)buf->extended_data[c];
+
+ for (i = 0; i < buf->nb_samples; i++, src++)
+ update_stat(s, p, *src);
+ }
+ break;
+ case AV_SAMPLE_FMT_DBL:
+ src = (const double *)buf->extended_data[0];
+
+ for (i = 0; i < buf->nb_samples; i++) {
+ for (c = 0; c < channels; c++, src++)
+ update_stat(s, &s->chstats[c], *src);
+ }
+ break;
+ }
+
+ return ff_filter_frame(inlink->dst->outputs[0], buf);
+}
+
+#define LINEAR_TO_DB(x) (log10(x) * 20)
+
+static void print_stats(AVFilterContext *ctx)
+{
+ AudioStatsContext *s = ctx->priv;
+ uint64_t min_count = 0, max_count = 0, nb_samples = 0;
+ double min_runs = 0, max_runs = 0,
+ min = DBL_MAX, max = DBL_MIN,
+ max_sigma_x = 0,
+ sigma_x = 0,
+ sigma_x2 = 0,
+ min_sigma_x2 = DBL_MAX,
+ max_sigma_x2 = DBL_MIN;
+ int c;
+
+ for (c = 0; c < s->nb_channels; c++) {
+ ChannelStats *p = &s->chstats[c];
+
+ if (p->nb_samples < s->tc_samples)
+ p->min_sigma_x2 = p->max_sigma_x2 = p->sigma_x2 / p->nb_samples;
+
+ min = FFMIN(min, p->min);
+ max = FFMAX(max, p->max);
+ min_sigma_x2 = FFMIN(min_sigma_x2, p->min_sigma_x2);
+ max_sigma_x2 = FFMAX(max_sigma_x2, p->max_sigma_x2);
+ sigma_x += p->sigma_x;
+ sigma_x2 += p->sigma_x2;
+ min_count += p->min_count;
+ max_count += p->max_count;
+ min_runs += p->min_runs;
+ max_runs += p->max_runs;
+ nb_samples += p->nb_samples;
+ if (fabs(p->sigma_x) > fabs(max_sigma_x))
+ max_sigma_x = p->sigma_x;
+
+ av_log(ctx, AV_LOG_INFO, "Channel: %d\n", c + 1);
+ av_log(ctx, AV_LOG_INFO, "DC offset: %f\n", p->sigma_x / p->nb_samples);
+ av_log(ctx, AV_LOG_INFO, "Min level: %f\n", p->min);
+ av_log(ctx, AV_LOG_INFO, "Max level: %f\n", p->max);
+ av_log(ctx, AV_LOG_INFO, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-p->min, p->max)));
+ av_log(ctx, AV_LOG_INFO, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(p->sigma_x2 / p->nb_samples)));
+ av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(p->max_sigma_x2)));
+ if (p->min_sigma_x2 != 1)
+ av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2)));
+ av_log(ctx, AV_LOG_INFO, "Crest factor: %f\n", p->sigma_x2 ? FFMAX(-p->min, p->max) / sqrt(p->sigma_x2 / p->nb_samples) : 1);
+ av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((p->min_runs + p->max_runs) / (p->min_count + p->max_count)));
+ av_log(ctx, AV_LOG_INFO, "Peak count: %"PRId64"\n", p->min_count + p->max_count);
+ }
+
+ av_log(ctx, AV_LOG_INFO, "Overall\n");
+ av_log(ctx, AV_LOG_INFO, "DC offset: %f\n", max_sigma_x / (nb_samples / s->nb_channels));
+ av_log(ctx, AV_LOG_INFO, "Min level: %f\n", min);
+ av_log(ctx, AV_LOG_INFO, "Max level: %f\n", max);
+ av_log(ctx, AV_LOG_INFO, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-min, max)));
+ av_log(ctx, AV_LOG_INFO, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(sigma_x2 / nb_samples)));
+ av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(max_sigma_x2)));
+ if (min_sigma_x2 != 1)
+ av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2)));
+ av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count)));
+ av_log(ctx, AV_LOG_INFO, "Peak count: %f\n", (min_count + max_count) / (double)s->nb_channels);
+ av_log(ctx, AV_LOG_INFO, "Number of samples: %"PRId64"\n", nb_samples / s->nb_channels);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AudioStatsContext *s = ctx->priv;
+
+ if (s->nb_channels)
+ print_stats(ctx);
+ av_freep(&s->chstats);
+}
+
+static const AVFilterPad astats_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad astats_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_astats = {
+ .name = "astats",
+ .description = NULL_IF_CONFIG_SMALL("Show time domain statistics about audio frames."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(AudioStatsContext),
+ .priv_class = &astats_class,
+ .uninit = uninit,
+ .inputs = astats_inputs,
+ .outputs = astats_outputs,
+};
diff --git a/libavfilter/af_astreamsync.c b/libavfilter/af_astreamsync.c
new file mode 100644
index 0000000000..becfe34074
--- /dev/null
+++ b/libavfilter/af_astreamsync.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Stream (de)synchronization filter
+ */
+
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+#define QUEUE_SIZE 16
+
+static const char * const var_names[] = {
+ "b1", "b2",
+ "s1", "s2",
+ "t1", "t2",
+ NULL
+};
+
+enum var_name {
+ VAR_B1, VAR_B2,
+ VAR_S1, VAR_S2,
+ VAR_T1, VAR_T2,
+ VAR_NB
+};
+
+typedef struct {
+ const AVClass *class;
+ AVExpr *expr;
+ char *expr_str;
+ double var_values[VAR_NB];
+ struct buf_queue {
+ AVFrame *buf[QUEUE_SIZE];
+ unsigned tail, nb;
+ /* buf[tail] is the oldest,
+ buf[(tail + nb) % QUEUE_SIZE] is where the next is added */
+ } queue[2];
+ int req[2];
+ int next_out;
+ int eof; /* bitmask, one bit for each stream */
+} AStreamSyncContext;
+
+#define OFFSET(x) offsetof(AStreamSyncContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption astreamsync_options[] = {
+ { "expr", "set stream selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "t1-t2" }, .flags = FLAGS },
+ { "e", "set stream selection expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "t1-t2" }, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(astreamsync);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AStreamSyncContext *as = ctx->priv;
+ int r, i;
+
+ r = av_expr_parse(&as->expr, as->expr_str, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (r < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error in expression \"%s\"\n", as->expr_str);
+ return r;
+ }
+ for (i = 0; i < 42; i++)
+ av_expr_eval(as->expr, as->var_values, NULL); /* exercize prng */
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ int i;
+ AVFilterFormats *formats, *rates;
+ AVFilterChannelLayouts *layouts;
+
+ for (i = 0; i < 2; i++) {
+ formats = ctx->inputs[i]->in_formats;
+ ff_formats_ref(formats, &ctx->inputs[i]->out_formats);
+ ff_formats_ref(formats, &ctx->outputs[i]->in_formats);
+ rates = ff_all_samplerates();
+ ff_formats_ref(rates, &ctx->inputs[i]->out_samplerates);
+ ff_formats_ref(rates, &ctx->outputs[i]->in_samplerates);
+ layouts = ctx->inputs[i]->in_channel_layouts;
+ ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
+ ff_channel_layouts_ref(layouts, &ctx->outputs[i]->in_channel_layouts);
+ }
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ int id = outlink == ctx->outputs[1];
+
+ outlink->sample_rate = ctx->inputs[id]->sample_rate;
+ outlink->time_base = ctx->inputs[id]->time_base;
+ return 0;
+}
+
+static int send_out(AVFilterContext *ctx, int out_id)
+{
+ AStreamSyncContext *as = ctx->priv;
+ struct buf_queue *queue = &as->queue[out_id];
+ AVFrame *buf = queue->buf[queue->tail];
+ int ret;
+
+ queue->buf[queue->tail] = NULL;
+ as->var_values[VAR_B1 + out_id]++;
+ as->var_values[VAR_S1 + out_id] += buf->nb_samples;
+ if (buf->pts != AV_NOPTS_VALUE)
+ as->var_values[VAR_T1 + out_id] =
+ av_q2d(ctx->outputs[out_id]->time_base) * buf->pts;
+ as->var_values[VAR_T1 + out_id] += buf->nb_samples /
+ (double)ctx->inputs[out_id]->sample_rate;
+ ret = ff_filter_frame(ctx->outputs[out_id], buf);
+ queue->nb--;
+ queue->tail = (queue->tail + 1) % QUEUE_SIZE;
+ if (as->req[out_id])
+ as->req[out_id]--;
+ return ret;
+}
+
+static void send_next(AVFilterContext *ctx)
+{
+ AStreamSyncContext *as = ctx->priv;
+ int i;
+
+ while (1) {
+ if (!as->queue[as->next_out].nb)
+ break;
+ send_out(ctx, as->next_out);
+ if (!as->eof)
+ as->next_out = av_expr_eval(as->expr, as->var_values, NULL) >= 0;
+ }
+ for (i = 0; i < 2; i++)
+ if (as->queue[i].nb == QUEUE_SIZE)
+ send_out(ctx, i);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AStreamSyncContext *as = ctx->priv;
+ int id = outlink == ctx->outputs[1];
+
+ as->req[id]++;
+ while (as->req[id] && !(as->eof & (1 << id))) {
+ if (as->queue[as->next_out].nb) {
+ send_next(ctx);
+ } else {
+ as->eof |= 1 << as->next_out;
+ ff_request_frame(ctx->inputs[as->next_out]);
+ if (as->eof & (1 << as->next_out))
+ as->next_out = !as->next_out;
+ }
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AStreamSyncContext *as = ctx->priv;
+ int id = inlink == ctx->inputs[1];
+
+ as->queue[id].buf[(as->queue[id].tail + as->queue[id].nb++) % QUEUE_SIZE] =
+ insamples;
+ as->eof &= ~(1 << id);
+ send_next(ctx);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AStreamSyncContext *as = ctx->priv;
+
+ av_expr_free(as->expr);
+ as->expr = NULL;
+}
+
+static const AVFilterPad astreamsync_inputs[] = {
+ {
+ .name = "in1",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },{
+ .name = "in2",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad astreamsync_outputs[] = {
+ {
+ .name = "out1",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },{
+ .name = "out2",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_astreamsync = {
+ .name = "astreamsync",
+ .description = NULL_IF_CONFIG_SMALL("Copy two streams of audio data "
+ "in a configurable order."),
+ .priv_size = sizeof(AStreamSyncContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = astreamsync_inputs,
+ .outputs = astreamsync_outputs,
+ .priv_class = &astreamsync_class,
+};
diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c
index e662c842ac..5f8e1f61cc 100644
--- a/libavfilter/af_asyncts.c
+++ b/libavfilter/af_asyncts.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,21 +51,17 @@ typedef struct ASyncContext {
#define OFFSET(x) offsetof(ASyncContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
-static const AVOption options[] = {
- { "compensate", "Stretch/squeeze the data to make it match the timestamps", OFFSET(resample), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, A },
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption asyncts_options[] = {
+ { "compensate", "Stretch/squeeze the data to make it match the timestamps", OFFSET(resample), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, A|F },
{ "min_delta", "Minimum difference between timestamps and audio data "
- "(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A },
- { "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A },
- { "first_pts", "Assume the first pts should be this value.", OFFSET(first_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A },
- { NULL },
+ "(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A|F },
+ { "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A|F },
+ { "first_pts", "Assume the first pts should be this value.", OFFSET(first_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A|F },
+ { NULL }
};
-static const AVClass async_class = {
- .class_name = "asyncts filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(asyncts);
static av_cold int init(AVFilterContext *ctx)
{
@@ -298,9 +294,9 @@ fail:
static const AVFilterPad avfilter_af_asyncts_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame
},
{ NULL }
};
@@ -318,13 +314,10 @@ static const AVFilterPad avfilter_af_asyncts_outputs[] = {
AVFilter ff_af_asyncts = {
.name = "asyncts",
.description = NULL_IF_CONFIG_SMALL("Sync audio data to timestamps"),
-
.init = init,
.uninit = uninit,
-
.priv_size = sizeof(ASyncContext),
- .priv_class = &async_class,
-
+ .priv_class = &asyncts_class,
.inputs = avfilter_af_asyncts_inputs,
.outputs = avfilter_af_asyncts_outputs,
};
diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c
new file mode 100644
index 0000000000..49d49ee2a9
--- /dev/null
+++ b/libavfilter/af_atempo.c
@@ -0,0 +1,1205 @@
+/*
+ * Copyright (c) 2012 Pavel Koshevoy <pkoshevoy at gmail dot 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
+ * tempo scaling audio filter -- an implementation of WSOLA algorithm
+ *
+ * Based on MIT licensed yaeAudioTempoFilter.h and yaeAudioFragment.h
+ * from Apprentice Video player by Pavel Koshevoy.
+ * https://sourceforge.net/projects/apprenticevideo/
+ *
+ * An explanation of SOLA algorithm is available at
+ * http://www.surina.net/article/time-and-pitch-scaling.html
+ *
+ * WSOLA is very similar to SOLA, only one major difference exists between
+ * these algorithms. SOLA shifts audio fragments along the output stream,
+ * where as WSOLA shifts audio fragments along the input stream.
+ *
+ * The advantage of WSOLA algorithm is that the overlap region size is
+ * always the same, therefore the blending function is constant and
+ * can be precomputed.
+ */
+
+#include <float.h>
+#include "libavcodec/avfft.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+/**
+ * A fragment of audio waveform
+ */
+typedef struct {
+ // index of the first sample of this fragment in the overall waveform;
+ // 0: input sample position
+ // 1: output sample position
+ int64_t position[2];
+
+ // original packed multi-channel samples:
+ uint8_t *data;
+
+ // number of samples in this fragment:
+ int nsamples;
+
+ // rDFT transform of the down-mixed mono fragment, used for
+ // fast waveform alignment via correlation in frequency domain:
+ FFTSample *xdat;
+} AudioFragment;
+
+/**
+ * Filter state machine states
+ */
+typedef enum {
+ YAE_LOAD_FRAGMENT,
+ YAE_ADJUST_POSITION,
+ YAE_RELOAD_FRAGMENT,
+ YAE_OUTPUT_OVERLAP_ADD,
+ YAE_FLUSH_OUTPUT,
+} FilterState;
+
+/**
+ * Filter state machine
+ */
+typedef struct {
+ const AVClass *class;
+
+ // ring-buffer of input samples, necessary because some times
+ // input fragment position may be adjusted backwards:
+ uint8_t *buffer;
+
+ // ring-buffer maximum capacity, expressed in sample rate time base:
+ int ring;
+
+ // ring-buffer house keeping:
+ int size;
+ int head;
+ int tail;
+
+ // 0: input sample position corresponding to the ring buffer tail
+ // 1: output sample position
+ int64_t position[2];
+
+ // sample format:
+ enum AVSampleFormat format;
+
+ // number of channels:
+ int channels;
+
+ // row of bytes to skip from one sample to next, across multple channels;
+ // stride = (number-of-channels * bits-per-sample-per-channel) / 8
+ int stride;
+
+ // fragment window size, power-of-two integer:
+ int window;
+
+ // Hann window coefficients, for feathering
+ // (blending) the overlapping fragment region:
+ float *hann;
+
+ // tempo scaling factor:
+ double tempo;
+
+ // a snapshot of previous fragment input and output position values
+ // captured when the tempo scale factor was set most recently:
+ int64_t origin[2];
+
+ // current/previous fragment ring-buffer:
+ AudioFragment frag[2];
+
+ // current fragment index:
+ uint64_t nfrag;
+
+ // current state:
+ FilterState state;
+
+ // for fast correlation calculation in frequency domain:
+ RDFTContext *real_to_complex;
+ RDFTContext *complex_to_real;
+ FFTSample *correlation;
+
+ // for managing AVFilterPad.request_frame and AVFilterPad.filter_frame
+ AVFrame *dst_buffer;
+ uint8_t *dst;
+ uint8_t *dst_end;
+ uint64_t nsamples_in;
+ uint64_t nsamples_out;
+} ATempoContext;
+
+#define OFFSET(x) offsetof(ATempoContext, x)
+
+static const AVOption atempo_options[] = {
+ { "tempo", "set tempo scale factor",
+ OFFSET(tempo), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 0.5, 2.0,
+ AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(atempo);
+
+inline static AudioFragment *yae_curr_frag(ATempoContext *atempo)
+{
+ return &atempo->frag[atempo->nfrag % 2];
+}
+
+inline static AudioFragment *yae_prev_frag(ATempoContext *atempo)
+{
+ return &atempo->frag[(atempo->nfrag + 1) % 2];
+}
+
+/**
+ * Reset filter to initial state, do not deallocate existing local buffers.
+ */
+static void yae_clear(ATempoContext *atempo)
+{
+ atempo->size = 0;
+ atempo->head = 0;
+ atempo->tail = 0;
+
+ atempo->nfrag = 0;
+ atempo->state = YAE_LOAD_FRAGMENT;
+
+ atempo->position[0] = 0;
+ atempo->position[1] = 0;
+
+ atempo->origin[0] = 0;
+ atempo->origin[1] = 0;
+
+ atempo->frag[0].position[0] = 0;
+ atempo->frag[0].position[1] = 0;
+ atempo->frag[0].nsamples = 0;
+
+ atempo->frag[1].position[0] = 0;
+ atempo->frag[1].position[1] = 0;
+ atempo->frag[1].nsamples = 0;
+
+ // shift left position of 1st fragment by half a window
+ // so that no re-normalization would be required for
+ // the left half of the 1st fragment:
+ atempo->frag[0].position[0] = -(int64_t)(atempo->window / 2);
+ atempo->frag[0].position[1] = -(int64_t)(atempo->window / 2);
+
+ av_frame_free(&atempo->dst_buffer);
+ atempo->dst = NULL;
+ atempo->dst_end = NULL;
+
+ atempo->nsamples_in = 0;
+ atempo->nsamples_out = 0;
+}
+
+/**
+ * Reset filter to initial state and deallocate all buffers.
+ */
+static void yae_release_buffers(ATempoContext *atempo)
+{
+ yae_clear(atempo);
+
+ av_freep(&atempo->frag[0].data);
+ av_freep(&atempo->frag[1].data);
+ av_freep(&atempo->frag[0].xdat);
+ av_freep(&atempo->frag[1].xdat);
+
+ av_freep(&atempo->buffer);
+ av_freep(&atempo->hann);
+ av_freep(&atempo->correlation);
+
+ av_rdft_end(atempo->real_to_complex);
+ atempo->real_to_complex = NULL;
+
+ av_rdft_end(atempo->complex_to_real);
+ atempo->complex_to_real = NULL;
+}
+
+/* av_realloc is not aligned enough; fortunately, the data does not need to
+ * be preserved */
+#define RE_MALLOC_OR_FAIL(field, field_size) \
+ do { \
+ av_freep(&field); \
+ field = av_malloc(field_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.
+ */
+static int yae_reset(ATempoContext *atempo,
+ enum AVSampleFormat format,
+ int sample_rate,
+ int channels)
+{
+ const int sample_size = av_get_bytes_per_sample(format);
+ uint32_t nlevels = 0;
+ uint32_t pot;
+ int i;
+
+ atempo->format = format;
+ atempo->channels = channels;
+ atempo->stride = sample_size * channels;
+
+ // pick a segment window size:
+ atempo->window = sample_rate / 24;
+
+ // adjust window size to be a power-of-two integer:
+ nlevels = av_log2(atempo->window);
+ pot = 1 << nlevels;
+ av_assert0(pot <= atempo->window);
+
+ if (pot < atempo->window) {
+ atempo->window = pot * 2;
+ nlevels++;
+ }
+
+ // 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, atempo->window * sizeof(FFTComplex));
+ RE_MALLOC_OR_FAIL(atempo->frag[1].xdat, atempo->window * sizeof(FFTComplex));
+
+ // initialize rDFT contexts:
+ av_rdft_end(atempo->real_to_complex);
+ atempo->real_to_complex = NULL;
+
+ av_rdft_end(atempo->complex_to_real);
+ atempo->complex_to_real = NULL;
+
+ atempo->real_to_complex = av_rdft_init(nlevels + 1, DFT_R2C);
+ if (!atempo->real_to_complex) {
+ yae_release_buffers(atempo);
+ return AVERROR(ENOMEM);
+ }
+
+ atempo->complex_to_real = av_rdft_init(nlevels + 1, IDFT_C2R);
+ if (!atempo->complex_to_real) {
+ yae_release_buffers(atempo);
+ return AVERROR(ENOMEM);
+ }
+
+ RE_MALLOC_OR_FAIL(atempo->correlation, atempo->window * sizeof(FFTComplex));
+
+ atempo->ring = atempo->window * 3;
+ RE_MALLOC_OR_FAIL(atempo->buffer, atempo->ring * atempo->stride);
+
+ // initialize the Hann window function:
+ RE_MALLOC_OR_FAIL(atempo->hann, atempo->window * sizeof(float));
+
+ for (i = 0; i < atempo->window; i++) {
+ double t = (double)i / (double)(atempo->window - 1);
+ double h = 0.5 * (1.0 - cos(2.0 * M_PI * t));
+ atempo->hann[i] = (float)h;
+ }
+
+ yae_clear(atempo);
+ return 0;
+}
+
+static int yae_set_tempo(AVFilterContext *ctx, const char *arg_tempo)
+{
+ const AudioFragment *prev;
+ ATempoContext *atempo = ctx->priv;
+ char *tail = NULL;
+ double tempo = av_strtod(arg_tempo, &tail);
+
+ if (tail && *tail) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid tempo value '%s'\n", arg_tempo);
+ return AVERROR(EINVAL);
+ }
+
+ if (tempo < 0.5 || tempo > 2.0) {
+ av_log(ctx, AV_LOG_ERROR, "Tempo value %f exceeds [0.5, 2.0] range\n",
+ tempo);
+ return AVERROR(EINVAL);
+ }
+
+ prev = yae_prev_frag(atempo);
+ atempo->origin[0] = prev->position[0] + atempo->window / 2;
+ atempo->origin[1] = prev->position[1] + atempo->window / 2;
+ atempo->tempo = tempo;
+ return 0;
+}
+
+/**
+ * A helper macro for initializing complex data buffer with scalar data
+ * of a given type.
+ */
+#define yae_init_xdat(scalar_type, scalar_max) \
+ do { \
+ const uint8_t *src_end = src + \
+ frag->nsamples * atempo->channels * sizeof(scalar_type); \
+ \
+ FFTSample *xdat = frag->xdat; \
+ scalar_type tmp; \
+ \
+ if (atempo->channels == 1) { \
+ for (; src < src_end; xdat++) { \
+ tmp = *(const scalar_type *)src; \
+ src += sizeof(scalar_type); \
+ \
+ *xdat = (FFTSample)tmp; \
+ } \
+ } else { \
+ FFTSample s, max, ti, si; \
+ int i; \
+ \
+ for (; src < src_end; xdat++) { \
+ tmp = *(const scalar_type *)src; \
+ src += sizeof(scalar_type); \
+ \
+ max = (FFTSample)tmp; \
+ s = FFMIN((FFTSample)scalar_max, \
+ (FFTSample)fabsf(max)); \
+ \
+ for (i = 1; i < atempo->channels; i++) { \
+ tmp = *(const scalar_type *)src; \
+ src += sizeof(scalar_type); \
+ \
+ ti = (FFTSample)tmp; \
+ si = FFMIN((FFTSample)scalar_max, \
+ (FFTSample)fabsf(ti)); \
+ \
+ if (s < si) { \
+ s = si; \
+ max = ti; \
+ } \
+ } \
+ \
+ *xdat = max; \
+ } \
+ } \
+ } while (0)
+
+/**
+ * Initialize complex data buffer of a given audio fragment
+ * with down-mixed mono data of appropriate scalar type.
+ */
+static void yae_downmix(ATempoContext *atempo, AudioFragment *frag)
+{
+ // shortcuts:
+ const uint8_t *src = frag->data;
+
+ // init complex data buffer used for FFT and Correlation:
+ memset(frag->xdat, 0, sizeof(FFTComplex) * atempo->window);
+
+ if (atempo->format == AV_SAMPLE_FMT_U8) {
+ yae_init_xdat(uint8_t, 127);
+ } else if (atempo->format == AV_SAMPLE_FMT_S16) {
+ yae_init_xdat(int16_t, 32767);
+ } else if (atempo->format == AV_SAMPLE_FMT_S32) {
+ yae_init_xdat(int, 2147483647);
+ } else if (atempo->format == AV_SAMPLE_FMT_FLT) {
+ yae_init_xdat(float, 1);
+ } else if (atempo->format == AV_SAMPLE_FMT_DBL) {
+ yae_init_xdat(double, 1);
+ }
+}
+
+/**
+ * Populate the internal data buffer on as-needed basis.
+ *
+ * @return
+ * 0 if requested data was already available or was successfully loaded,
+ * AVERROR(EAGAIN) if more input data is required.
+ */
+static int yae_load_data(ATempoContext *atempo,
+ const uint8_t **src_ref,
+ const uint8_t *src_end,
+ int64_t stop_here)
+{
+ // shortcut:
+ const uint8_t *src = *src_ref;
+ const int read_size = stop_here - atempo->position[0];
+
+ if (stop_here <= atempo->position[0]) {
+ return 0;
+ }
+
+ // samples are not expected to be skipped:
+ av_assert0(read_size <= atempo->ring);
+
+ while (atempo->position[0] < stop_here && src < src_end) {
+ int src_samples = (src_end - src) / atempo->stride;
+
+ // load data piece-wise, in order to avoid complicating the logic:
+ int nsamples = FFMIN(read_size, src_samples);
+ int na;
+ int nb;
+
+ nsamples = FFMIN(nsamples, atempo->ring);
+ na = FFMIN(nsamples, atempo->ring - atempo->tail);
+ nb = FFMIN(nsamples - na, atempo->ring);
+
+ if (na) {
+ uint8_t *a = atempo->buffer + atempo->tail * atempo->stride;
+ memcpy(a, src, na * atempo->stride);
+
+ src += na * atempo->stride;
+ atempo->position[0] += na;
+
+ atempo->size = FFMIN(atempo->size + na, atempo->ring);
+ atempo->tail = (atempo->tail + na) % atempo->ring;
+ atempo->head =
+ atempo->size < atempo->ring ?
+ atempo->tail - atempo->size :
+ atempo->tail;
+ }
+
+ if (nb) {
+ uint8_t *b = atempo->buffer;
+ memcpy(b, src, nb * atempo->stride);
+
+ src += nb * atempo->stride;
+ atempo->position[0] += nb;
+
+ atempo->size = FFMIN(atempo->size + nb, atempo->ring);
+ atempo->tail = (atempo->tail + nb) % atempo->ring;
+ atempo->head =
+ atempo->size < atempo->ring ?
+ atempo->tail - atempo->size :
+ atempo->tail;
+ }
+ }
+
+ // pass back the updated source buffer pointer:
+ *src_ref = src;
+
+ // sanity check:
+ av_assert0(atempo->position[0] <= stop_here);
+
+ return atempo->position[0] == stop_here ? 0 : AVERROR(EAGAIN);
+}
+
+/**
+ * Populate current audio fragment data buffer.
+ *
+ * @return
+ * 0 when the fragment is ready,
+ * AVERROR(EAGAIN) if more input data is required.
+ */
+static int yae_load_frag(ATempoContext *atempo,
+ const uint8_t **src_ref,
+ const uint8_t *src_end)
+{
+ // shortcuts:
+ AudioFragment *frag = yae_curr_frag(atempo);
+ uint8_t *dst;
+ int64_t missing, start, zeros;
+ uint32_t nsamples;
+ const uint8_t *a, *b;
+ int i0, i1, n0, n1, na, nb;
+
+ int64_t stop_here = frag->position[0] + atempo->window;
+ if (src_ref && yae_load_data(atempo, src_ref, src_end, stop_here) != 0) {
+ return AVERROR(EAGAIN);
+ }
+
+ // calculate the number of samples we don't have:
+ missing =
+ stop_here > atempo->position[0] ?
+ stop_here - atempo->position[0] : 0;
+
+ nsamples =
+ missing < (int64_t)atempo->window ?
+ (uint32_t)(atempo->window - missing) : 0;
+
+ // setup the output buffer:
+ frag->nsamples = nsamples;
+ dst = frag->data;
+
+ start = atempo->position[0] - atempo->size;
+ zeros = 0;
+
+ if (frag->position[0] < start) {
+ // what we don't have we substitute with zeros:
+ zeros = FFMIN(start - frag->position[0], (int64_t)nsamples);
+ av_assert0(zeros != nsamples);
+
+ memset(dst, 0, zeros * atempo->stride);
+ dst += zeros * atempo->stride;
+ }
+
+ if (zeros == nsamples) {
+ return 0;
+ }
+
+ // get the remaining data from the ring buffer:
+ na = (atempo->head < atempo->tail ?
+ atempo->tail - atempo->head :
+ atempo->ring - atempo->head);
+
+ nb = atempo->head < atempo->tail ? 0 : atempo->tail;
+
+ // sanity check:
+ av_assert0(nsamples <= zeros + na + nb);
+
+ a = atempo->buffer + atempo->head * atempo->stride;
+ b = atempo->buffer;
+
+ i0 = frag->position[0] + zeros - start;
+ i1 = i0 < na ? 0 : i0 - na;
+
+ n0 = i0 < na ? FFMIN(na - i0, (int)(nsamples - zeros)) : 0;
+ n1 = nsamples - zeros - n0;
+
+ if (n0) {
+ memcpy(dst, a + i0 * atempo->stride, n0 * atempo->stride);
+ dst += n0 * atempo->stride;
+ }
+
+ if (n1) {
+ memcpy(dst, b + i1 * atempo->stride, n1 * atempo->stride);
+ }
+
+ return 0;
+}
+
+/**
+ * Prepare for loading next audio fragment.
+ */
+static void yae_advance_to_next_frag(ATempoContext *atempo)
+{
+ const double fragment_step = atempo->tempo * (double)(atempo->window / 2);
+
+ const AudioFragment *prev;
+ AudioFragment *frag;
+
+ atempo->nfrag++;
+ prev = yae_prev_frag(atempo);
+ frag = yae_curr_frag(atempo);
+
+ frag->position[0] = prev->position[0] + (int64_t)fragment_step;
+ frag->position[1] = prev->position[1] + atempo->window / 2;
+ frag->nsamples = 0;
+}
+
+/**
+ * Calculate cross-correlation via rDFT.
+ *
+ * Multiply two vectors of complex numbers (result of real_to_complex rDFT)
+ * and transform back via complex_to_real rDFT.
+ */
+static void yae_xcorr_via_rdft(FFTSample *xcorr,
+ RDFTContext *complex_to_real,
+ const FFTComplex *xa,
+ const FFTComplex *xb,
+ const int window)
+{
+ FFTComplex *xc = (FFTComplex *)xcorr;
+ int i;
+
+ // NOTE: first element requires special care -- Given Y = rDFT(X),
+ // Im(Y[0]) and Im(Y[N/2]) are always zero, therefore av_rdft_calc
+ // stores Re(Y[N/2]) in place of Im(Y[0]).
+
+ xc->re = xa->re * xb->re;
+ xc->im = xa->im * xb->im;
+ xa++;
+ xb++;
+ xc++;
+
+ for (i = 1; i < window; i++, xa++, xb++, xc++) {
+ xc->re = (xa->re * xb->re + xa->im * xb->im);
+ xc->im = (xa->im * xb->re - xa->re * xb->im);
+ }
+
+ // apply inverse rDFT:
+ av_rdft_calc(complex_to_real, xcorr);
+}
+
+/**
+ * Calculate alignment offset for given fragment
+ * relative to the previous fragment.
+ *
+ * @return alignment offset of current fragment relative to previous.
+ */
+static int yae_align(AudioFragment *frag,
+ const AudioFragment *prev,
+ const int window,
+ const int delta_max,
+ const int drift,
+ FFTSample *correlation,
+ RDFTContext *complex_to_real)
+{
+ int best_offset = -drift;
+ FFTSample best_metric = -FLT_MAX;
+ FFTSample *xcorr;
+
+ int i0;
+ int i1;
+ int i;
+
+ yae_xcorr_via_rdft(correlation,
+ complex_to_real,
+ (const FFTComplex *)prev->xdat,
+ (const FFTComplex *)frag->xdat,
+ window);
+
+ // identify search window boundaries:
+ i0 = FFMAX(window / 2 - delta_max - drift, 0);
+ i0 = FFMIN(i0, window);
+
+ i1 = FFMIN(window / 2 + delta_max - drift, window - window / 16);
+ i1 = FFMAX(i1, 0);
+
+ // identify cross-correlation peaks within search window:
+ xcorr = correlation + i0;
+
+ for (i = i0; i < i1; i++, xcorr++) {
+ FFTSample metric = *xcorr;
+
+ // normalize:
+ FFTSample drifti = (FFTSample)(drift + i);
+ metric *= drifti * (FFTSample)(i - i0) * (FFTSample)(i1 - i);
+
+ if (metric > best_metric) {
+ best_metric = metric;
+ best_offset = i - window / 2;
+ }
+ }
+
+ return best_offset;
+}
+
+/**
+ * Adjust current fragment position for better alignment
+ * with previous fragment.
+ *
+ * @return alignment correction.
+ */
+static int yae_adjust_position(ATempoContext *atempo)
+{
+ const AudioFragment *prev = yae_prev_frag(atempo);
+ AudioFragment *frag = yae_curr_frag(atempo);
+
+ const double prev_output_position =
+ (double)(prev->position[1] - atempo->origin[1] + atempo->window / 2);
+
+ const double ideal_output_position =
+ (double)(prev->position[0] - atempo->origin[0] + atempo->window / 2) /
+ atempo->tempo;
+
+ const int drift = (int)(prev_output_position - ideal_output_position);
+
+ const int delta_max = atempo->window / 2;
+ const int correction = yae_align(frag,
+ prev,
+ atempo->window,
+ delta_max,
+ drift,
+ atempo->correlation,
+ atempo->complex_to_real);
+
+ if (correction) {
+ // adjust fragment position:
+ frag->position[0] -= correction;
+
+ // clear so that the fragment can be reloaded:
+ frag->nsamples = 0;
+ }
+
+ return correction;
+}
+
+/**
+ * A helper macro for blending the overlap region of previous
+ * and current audio fragment.
+ */
+#define yae_blend(scalar_type) \
+ do { \
+ const scalar_type *aaa = (const scalar_type *)a; \
+ const scalar_type *bbb = (const scalar_type *)b; \
+ \
+ scalar_type *out = (scalar_type *)dst; \
+ scalar_type *out_end = (scalar_type *)dst_end; \
+ int64_t i; \
+ \
+ for (i = 0; i < overlap && out < out_end; \
+ i++, atempo->position[1]++, wa++, wb++) { \
+ float w0 = *wa; \
+ float w1 = *wb; \
+ int j; \
+ \
+ for (j = 0; j < atempo->channels; \
+ j++, aaa++, bbb++, out++) { \
+ float t0 = (float)*aaa; \
+ float t1 = (float)*bbb; \
+ \
+ *out = \
+ frag->position[0] + i < 0 ? \
+ *aaa : \
+ (scalar_type)(t0 * w0 + t1 * w1); \
+ } \
+ } \
+ dst = (uint8_t *)out; \
+ } while (0)
+
+/**
+ * Blend the overlap region of previous and current audio fragment
+ * and output the results to the given destination buffer.
+ *
+ * @return
+ * 0 if the overlap region was completely stored in the dst buffer,
+ * AVERROR(EAGAIN) if more destination buffer space is required.
+ */
+static int yae_overlap_add(ATempoContext *atempo,
+ uint8_t **dst_ref,
+ uint8_t *dst_end)
+{
+ // shortcuts:
+ const AudioFragment *prev = yae_prev_frag(atempo);
+ const AudioFragment *frag = yae_curr_frag(atempo);
+
+ const int64_t start_here = FFMAX(atempo->position[1],
+ frag->position[1]);
+
+ const int64_t stop_here = FFMIN(prev->position[1] + prev->nsamples,
+ frag->position[1] + frag->nsamples);
+
+ const int64_t overlap = stop_here - start_here;
+
+ const int64_t ia = start_here - prev->position[1];
+ const int64_t ib = start_here - frag->position[1];
+
+ const float *wa = atempo->hann + ia;
+ const float *wb = atempo->hann + ib;
+
+ const uint8_t *a = prev->data + ia * atempo->stride;
+ const uint8_t *b = frag->data + ib * atempo->stride;
+
+ uint8_t *dst = *dst_ref;
+
+ av_assert0(start_here <= stop_here &&
+ frag->position[1] <= start_here &&
+ overlap <= frag->nsamples);
+
+ if (atempo->format == AV_SAMPLE_FMT_U8) {
+ yae_blend(uint8_t);
+ } else if (atempo->format == AV_SAMPLE_FMT_S16) {
+ yae_blend(int16_t);
+ } else if (atempo->format == AV_SAMPLE_FMT_S32) {
+ yae_blend(int);
+ } else if (atempo->format == AV_SAMPLE_FMT_FLT) {
+ yae_blend(float);
+ } else if (atempo->format == AV_SAMPLE_FMT_DBL) {
+ yae_blend(double);
+ }
+
+ // pass-back the updated destination buffer pointer:
+ *dst_ref = dst;
+
+ return atempo->position[1] == stop_here ? 0 : AVERROR(EAGAIN);
+}
+
+/**
+ * Feed as much data to the filter as it is able to consume
+ * and receive as much processed data in the destination buffer
+ * as it is able to produce or store.
+ */
+static void
+yae_apply(ATempoContext *atempo,
+ const uint8_t **src_ref,
+ const uint8_t *src_end,
+ uint8_t **dst_ref,
+ uint8_t *dst_end)
+{
+ while (1) {
+ if (atempo->state == YAE_LOAD_FRAGMENT) {
+ // load additional data for the current fragment:
+ if (yae_load_frag(atempo, src_ref, src_end) != 0) {
+ break;
+ }
+
+ // down-mix to mono:
+ yae_downmix(atempo, yae_curr_frag(atempo));
+
+ // apply rDFT:
+ av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat);
+
+ // must load the second fragment before alignment can start:
+ if (!atempo->nfrag) {
+ yae_advance_to_next_frag(atempo);
+ continue;
+ }
+
+ atempo->state = YAE_ADJUST_POSITION;
+ }
+
+ if (atempo->state == YAE_ADJUST_POSITION) {
+ // adjust position for better alignment:
+ if (yae_adjust_position(atempo)) {
+ // reload the fragment at the corrected position, so that the
+ // Hann window blending would not require normalization:
+ atempo->state = YAE_RELOAD_FRAGMENT;
+ } else {
+ atempo->state = YAE_OUTPUT_OVERLAP_ADD;
+ }
+ }
+
+ if (atempo->state == YAE_RELOAD_FRAGMENT) {
+ // load additional data if necessary due to position adjustment:
+ if (yae_load_frag(atempo, src_ref, src_end) != 0) {
+ break;
+ }
+
+ // down-mix to mono:
+ yae_downmix(atempo, yae_curr_frag(atempo));
+
+ // apply rDFT:
+ av_rdft_calc(atempo->real_to_complex, yae_curr_frag(atempo)->xdat);
+
+ atempo->state = YAE_OUTPUT_OVERLAP_ADD;
+ }
+
+ if (atempo->state == YAE_OUTPUT_OVERLAP_ADD) {
+ // overlap-add and output the result:
+ if (yae_overlap_add(atempo, dst_ref, dst_end) != 0) {
+ break;
+ }
+
+ // advance to the next fragment, repeat:
+ yae_advance_to_next_frag(atempo);
+ atempo->state = YAE_LOAD_FRAGMENT;
+ }
+ }
+}
+
+/**
+ * Flush any buffered data from the filter.
+ *
+ * @return
+ * 0 if all data was completely stored in the dst buffer,
+ * AVERROR(EAGAIN) if more destination buffer space is required.
+ */
+static int yae_flush(ATempoContext *atempo,
+ uint8_t **dst_ref,
+ uint8_t *dst_end)
+{
+ AudioFragment *frag = yae_curr_frag(atempo);
+ int64_t overlap_end;
+ int64_t start_here;
+ int64_t stop_here;
+ int64_t offset;
+
+ const uint8_t *src;
+ uint8_t *dst;
+
+ int src_size;
+ int dst_size;
+ int nbytes;
+
+ atempo->state = YAE_FLUSH_OUTPUT;
+
+ if (atempo->position[0] == frag->position[0] + frag->nsamples &&
+ atempo->position[1] == frag->position[1] + frag->nsamples) {
+ // the current fragment is already flushed:
+ return 0;
+ }
+
+ if (frag->position[0] + frag->nsamples < atempo->position[0]) {
+ // finish loading the current (possibly partial) fragment:
+ yae_load_frag(atempo, NULL, NULL);
+
+ if (atempo->nfrag) {
+ // down-mix to mono:
+ yae_downmix(atempo, frag);
+
+ // apply rDFT:
+ av_rdft_calc(atempo->real_to_complex, frag->xdat);
+
+ // align current fragment to previous fragment:
+ if (yae_adjust_position(atempo)) {
+ // reload the current fragment due to adjusted position:
+ yae_load_frag(atempo, NULL, NULL);
+ }
+ }
+ }
+
+ // flush the overlap region:
+ overlap_end = frag->position[1] + FFMIN(atempo->window / 2,
+ frag->nsamples);
+
+ while (atempo->position[1] < overlap_end) {
+ if (yae_overlap_add(atempo, dst_ref, dst_end) != 0) {
+ return AVERROR(EAGAIN);
+ }
+ }
+
+ // check whether all of the input samples have been consumed:
+ if (frag->position[0] + frag->nsamples < atempo->position[0]) {
+ yae_advance_to_next_frag(atempo);
+ return AVERROR(EAGAIN);
+ }
+
+ // flush the remainder of the current fragment:
+ start_here = FFMAX(atempo->position[1], overlap_end);
+ stop_here = frag->position[1] + frag->nsamples;
+ offset = start_here - frag->position[1];
+ av_assert0(start_here <= stop_here && frag->position[1] <= start_here);
+
+ src = frag->data + offset * atempo->stride;
+ dst = (uint8_t *)*dst_ref;
+
+ src_size = (int)(stop_here - start_here) * atempo->stride;
+ dst_size = dst_end - dst;
+ nbytes = FFMIN(src_size, dst_size);
+
+ memcpy(dst, src, nbytes);
+ dst += nbytes;
+
+ atempo->position[1] += (nbytes / atempo->stride);
+
+ // pass-back the updated destination buffer pointer:
+ *dst_ref = (uint8_t *)dst;
+
+ return atempo->position[1] == stop_here ? 0 : AVERROR(EAGAIN);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ATempoContext *atempo = ctx->priv;
+ atempo->format = AV_SAMPLE_FMT_NONE;
+ atempo->state = YAE_LOAD_FRAGMENT;
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ATempoContext *atempo = ctx->priv;
+ yae_release_buffers(atempo);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterChannelLayouts *layouts = NULL;
+ AVFilterFormats *formats = NULL;
+
+ // 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
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts) {
+ return AVERROR(ENOMEM);
+ }
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats) {
+ return AVERROR(ENOMEM);
+ }
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats) {
+ return AVERROR(ENOMEM);
+ }
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ATempoContext *atempo = ctx->priv;
+
+ enum AVSampleFormat format = inlink->format;
+ int sample_rate = (int)inlink->sample_rate;
+ int channels = av_get_channel_layout_nb_channels(inlink->channel_layout);
+
+ ctx->outputs[0]->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return yae_reset(atempo, format, sample_rate, channels);
+}
+
+static int push_samples(ATempoContext *atempo,
+ AVFilterLink *outlink,
+ int n_out)
+{
+ int ret;
+
+ atempo->dst_buffer->sample_rate = outlink->sample_rate;
+ atempo->dst_buffer->nb_samples = n_out;
+
+ // adjust the PTS:
+ atempo->dst_buffer->pts =
+ av_rescale_q(atempo->nsamples_out,
+ (AVRational){ 1, outlink->sample_rate },
+ outlink->time_base);
+
+ ret = ff_filter_frame(outlink, atempo->dst_buffer);
+ atempo->dst_buffer = NULL;
+ atempo->dst = NULL;
+ atempo->dst_end = NULL;
+ if (ret < 0)
+ return ret;
+
+ atempo->nsamples_out += n_out;
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *src_buffer)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ATempoContext *atempo = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ int ret = 0;
+ int n_in = src_buffer->nb_samples;
+ int n_out = (int)(0.5 + ((double)n_in) / atempo->tempo);
+
+ const uint8_t *src = src_buffer->data[0];
+ const uint8_t *src_end = src + n_in * atempo->stride;
+
+ while (src < src_end) {
+ if (!atempo->dst_buffer) {
+ atempo->dst_buffer = ff_get_audio_buffer(outlink, n_out);
+ if (!atempo->dst_buffer)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(atempo->dst_buffer, src_buffer);
+
+ atempo->dst = atempo->dst_buffer->data[0];
+ atempo->dst_end = atempo->dst + n_out * atempo->stride;
+ }
+
+ yae_apply(atempo, &src, src_end, &atempo->dst, atempo->dst_end);
+
+ if (atempo->dst == atempo->dst_end) {
+ int n_samples = ((atempo->dst - atempo->dst_buffer->data[0]) /
+ atempo->stride);
+ ret = push_samples(atempo, outlink, n_samples);
+ if (ret < 0)
+ goto end;
+ }
+ }
+
+ atempo->nsamples_in += n_in;
+end:
+ av_frame_free(&src_buffer);
+ return ret;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ATempoContext *atempo = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+
+ if (ret == AVERROR_EOF) {
+ // flush the filter:
+ int n_max = atempo->ring;
+ int n_out;
+ int err = AVERROR(EAGAIN);
+
+ while (err == AVERROR(EAGAIN)) {
+ if (!atempo->dst_buffer) {
+ atempo->dst_buffer = ff_get_audio_buffer(outlink, n_max);
+ if (!atempo->dst_buffer)
+ return AVERROR(ENOMEM);
+
+ atempo->dst = atempo->dst_buffer->data[0];
+ atempo->dst_end = atempo->dst + n_max * atempo->stride;
+ }
+
+ err = yae_flush(atempo, &atempo->dst, atempo->dst_end);
+
+ n_out = ((atempo->dst - atempo->dst_buffer->data[0]) /
+ atempo->stride);
+
+ if (n_out) {
+ ret = push_samples(atempo, outlink, n_out);
+ }
+ }
+
+ av_frame_free(&atempo->dst_buffer);
+ atempo->dst = NULL;
+ atempo->dst_end = NULL;
+
+ return AVERROR_EOF;
+ }
+
+ return ret;
+}
+
+static int process_command(AVFilterContext *ctx,
+ const char *cmd,
+ const char *arg,
+ char *res,
+ int res_len,
+ int flags)
+{
+ return !strcmp(cmd, "tempo") ? yae_set_tempo(ctx, arg) : AVERROR(ENOSYS);
+}
+
+static const AVFilterPad atempo_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad atempo_outputs[] = {
+ {
+ .name = "default",
+ .request_frame = request_frame,
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_atempo = {
+ .name = "atempo",
+ .description = NULL_IF_CONFIG_SMALL("Adjust audio tempo."),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .process_command = process_command,
+ .priv_size = sizeof(ATempoContext),
+ .priv_class = &atempo_class,
+ .inputs = atempo_inputs,
+ .outputs = atempo_outputs,
+};
diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c
new file mode 100644
index 0000000000..118a0c0b75
--- /dev/null
+++ b/libavfilter/af_biquads.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2013 Paul B Mahol
+ * Copyright (c) 2006-2008 Rob Sykes <robs@users.sourceforge.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * 2-pole filters designed by Robert Bristow-Johnson <rbj@audioimagination.com>
+ * see http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ *
+ * 1-pole filters based on code (c) 2000 Chris Bagwell <cbagwell@sprynet.com>
+ * Algorithms: Recursive single pole low/high pass filter
+ * Reference: The Scientist and Engineer's Guide to Digital Signal Processing
+ *
+ * low-pass: output[N] = input[N] * A + output[N-1] * B
+ * X = exp(-2.0 * pi * Fc)
+ * A = 1 - X
+ * B = X
+ * Fc = cutoff freq / sample rate
+ *
+ * Mimics an RC low-pass filter:
+ *
+ * ---/\/\/\/\----------->
+ * |
+ * --- C
+ * ---
+ * |
+ * |
+ * V
+ *
+ * high-pass: output[N] = A0 * input[N] + A1 * input[N-1] + B1 * output[N-1]
+ * X = exp(-2.0 * pi * Fc)
+ * A0 = (1 + X) / 2
+ * A1 = -(1 + X) / 2
+ * B1 = X
+ * Fc = cutoff freq / sample rate
+ *
+ * Mimics an RC high-pass filter:
+ *
+ * || C
+ * ----||--------->
+ * || |
+ * <
+ * > R
+ * <
+ * |
+ * V
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+enum FilterType {
+ biquad,
+ equalizer,
+ bass,
+ treble,
+ band,
+ bandpass,
+ bandreject,
+ allpass,
+ highpass,
+ lowpass,
+};
+
+enum WidthType {
+ NONE,
+ HERTZ,
+ OCTAVE,
+ QFACTOR,
+ SLOPE,
+};
+
+typedef struct ChanCache {
+ double i1, i2;
+ double o1, o2;
+} ChanCache;
+
+typedef struct {
+ const AVClass *class;
+
+ enum FilterType filter_type;
+ int width_type;
+ int poles;
+ int csg;
+
+ double gain;
+ double frequency;
+ double width;
+
+ double a0, a1, a2;
+ double b0, b1, b2;
+
+ ChanCache *cache;
+
+ void (*filter)(const void *ibuf, void *obuf, int len,
+ double *i1, double *i2, double *o1, double *o2,
+ double b0, double b1, double b2, double a1, double a2);
+} BiquadsContext;
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ BiquadsContext *s = ctx->priv;
+
+ if (s->filter_type != biquad) {
+ if (s->frequency <= 0 || s->width <= 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid frequency %f and/or width %f <= 0\n",
+ s->frequency, s->width);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+#define BIQUAD_FILTER(name, type, min, max, need_clipping) \
+static void biquad_## name (const void *input, void *output, int len, \
+ double *in1, double *in2, \
+ double *out1, double *out2, \
+ double b0, double b1, double b2, \
+ double a1, double a2) \
+{ \
+ const type *ibuf = input; \
+ type *obuf = output; \
+ double i1 = *in1; \
+ double i2 = *in2; \
+ double o1 = *out1; \
+ double o2 = *out2; \
+ int i; \
+ a1 = -a1; \
+ a2 = -a2; \
+ \
+ for (i = 0; i+1 < len; i++) { \
+ o2 = i2 * b2 + i1 * b1 + ibuf[i] * b0 + o2 * a2 + o1 * a1; \
+ i2 = ibuf[i]; \
+ if (need_clipping && o2 < min) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = min; \
+ } else if (need_clipping && o2 > max) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = max; \
+ } else { \
+ obuf[i] = o2; \
+ } \
+ i++; \
+ o1 = i1 * b2 + i2 * b1 + ibuf[i] * b0 + o1 * a2 + o2 * a1; \
+ i1 = ibuf[i]; \
+ if (need_clipping && o1 < min) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = min; \
+ } else if (need_clipping && o1 > max) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = max; \
+ } else { \
+ obuf[i] = o1; \
+ } \
+ } \
+ if (i < len) { \
+ double o0 = ibuf[i] * b0 + i1 * b1 + i2 * b2 + o1 * a1 + o2 * a2; \
+ i2 = i1; \
+ i1 = ibuf[i]; \
+ o2 = o1; \
+ o1 = o0; \
+ if (need_clipping && o0 < min) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = min; \
+ } else if (need_clipping && o0 > max) { \
+ av_log(NULL, AV_LOG_WARNING, "clipping\n"); \
+ obuf[i] = max; \
+ } else { \
+ obuf[i] = o0; \
+ } \
+ } \
+ *in1 = i1; \
+ *in2 = i2; \
+ *out1 = o1; \
+ *out2 = o2; \
+}
+
+BIQUAD_FILTER(s16, int16_t, INT16_MIN, INT16_MAX, 1)
+BIQUAD_FILTER(s32, int32_t, INT32_MIN, INT32_MAX, 1)
+BIQUAD_FILTER(flt, float, -1., 1., 0)
+BIQUAD_FILTER(dbl, double, -1., 1., 0)
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ BiquadsContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ double A = exp(s->gain / 40 * log(10.));
+ double w0 = 2 * M_PI * s->frequency / inlink->sample_rate;
+ double alpha;
+
+ if (w0 > M_PI) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid frequency %f. Frequency must be less than half the sample-rate %d.\n",
+ s->frequency, inlink->sample_rate);
+ return AVERROR(EINVAL);
+ }
+
+ switch (s->width_type) {
+ case NONE:
+ alpha = 0.0;
+ break;
+ case HERTZ:
+ alpha = sin(w0) / (2 * s->frequency / s->width);
+ break;
+ case OCTAVE:
+ alpha = sin(w0) * sinh(log(2.) / 2 * s->width * w0 / sin(w0));
+ break;
+ case QFACTOR:
+ alpha = sin(w0) / (2 * s->width);
+ break;
+ case SLOPE:
+ alpha = sin(w0) / 2 * sqrt((A + 1 / A) * (1 / s->width - 1) + 2);
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ switch (s->filter_type) {
+ case biquad:
+ break;
+ case equalizer:
+ s->a0 = 1 + alpha / A;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha / A;
+ s->b0 = 1 + alpha * A;
+ s->b1 = -2 * cos(w0);
+ s->b2 = 1 - alpha * A;
+ break;
+ case bass:
+ s->a0 = (A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha;
+ s->a1 = -2 * ((A - 1) + (A + 1) * cos(w0));
+ s->a2 = (A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha;
+ s->b0 = A * ((A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha);
+ s->b1 = 2 * A * ((A - 1) - (A + 1) * cos(w0));
+ s->b2 = A * ((A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha);
+ break;
+ case treble:
+ s->a0 = (A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha;
+ s->a1 = 2 * ((A - 1) - (A + 1) * cos(w0));
+ s->a2 = (A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha;
+ s->b0 = A * ((A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha);
+ s->b1 =-2 * A * ((A - 1) + (A + 1) * cos(w0));
+ s->b2 = A * ((A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha);
+ break;
+ case bandpass:
+ if (s->csg) {
+ s->a0 = 1 + alpha;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha;
+ s->b0 = sin(w0) / 2;
+ s->b1 = 0;
+ s->b2 = -sin(w0) / 2;
+ } else {
+ s->a0 = 1 + alpha;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha;
+ s->b0 = alpha;
+ s->b1 = 0;
+ s->b2 = -alpha;
+ }
+ break;
+ case bandreject:
+ s->a0 = 1 + alpha;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha;
+ s->b0 = 1;
+ s->b1 = -2 * cos(w0);
+ s->b2 = 1;
+ break;
+ case lowpass:
+ if (s->poles == 1) {
+ s->a0 = 1;
+ s->a1 = -exp(-w0);
+ s->a2 = 0;
+ s->b0 = 1 + s->a1;
+ s->b1 = 0;
+ s->b2 = 0;
+ } else {
+ s->a0 = 1 + alpha;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha;
+ s->b0 = (1 - cos(w0)) / 2;
+ s->b1 = 1 - cos(w0);
+ s->b2 = (1 - cos(w0)) / 2;
+ }
+ break;
+ case highpass:
+ if (s->poles == 1) {
+ s->a0 = 1;
+ s->a1 = -exp(-w0);
+ s->a2 = 0;
+ s->b0 = (1 - s->a1) / 2;
+ s->b1 = -s->b0;
+ s->b2 = 0;
+ } else {
+ s->a0 = 1 + alpha;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha;
+ s->b0 = (1 + cos(w0)) / 2;
+ s->b1 = -(1 + cos(w0));
+ s->b2 = (1 + cos(w0)) / 2;
+ }
+ break;
+ case allpass:
+ s->a0 = 1 + alpha;
+ s->a1 = -2 * cos(w0);
+ s->a2 = 1 - alpha;
+ s->b0 = 1 - alpha;
+ s->b1 = -2 * cos(w0);
+ s->b2 = 1 + alpha;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ s->a1 /= s->a0;
+ s->a2 /= s->a0;
+ s->b0 /= s->a0;
+ s->b1 /= s->a0;
+ s->b2 /= s->a0;
+
+ s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->channels);
+ if (!s->cache)
+ return AVERROR(ENOMEM);
+ memset(s->cache, 0, sizeof(ChanCache) * inlink->channels);
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_S16P: s->filter = biquad_s16; break;
+ case AV_SAMPLE_FMT_S32P: s->filter = biquad_s32; break;
+ case AV_SAMPLE_FMT_FLTP: s->filter = biquad_flt; break;
+ case AV_SAMPLE_FMT_DBLP: s->filter = biquad_dbl; break;
+ default: av_assert0(0);
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ BiquadsContext *s = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out_buf;
+ int nb_samples = buf->nb_samples;
+ int ch;
+
+ if (av_frame_is_writable(buf)) {
+ out_buf = buf;
+ } else {
+ out_buf = ff_get_audio_buffer(inlink, nb_samples);
+ if (!out_buf)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_buf, buf);
+ }
+
+ for (ch = 0; ch < av_frame_get_channels(buf); ch++)
+ s->filter(buf->extended_data[ch],
+ out_buf->extended_data[ch], nb_samples,
+ &s->cache[ch].i1, &s->cache[ch].i2,
+ &s->cache[ch].o1, &s->cache[ch].o2,
+ s->b0, s->b1, s->b2, s->a1, s->a2);
+
+ if (buf != out_buf)
+ av_frame_free(&buf);
+
+ return ff_filter_frame(outlink, out_buf);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ BiquadsContext *s = ctx->priv;
+
+ av_freep(&s->cache);
+}
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+#define OFFSET(x) offsetof(BiquadsContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#define DEFINE_BIQUAD_FILTER(name_, description_) \
+AVFILTER_DEFINE_CLASS(name_); \
+static av_cold int name_##_init(AVFilterContext *ctx) \
+{ \
+ BiquadsContext *s = ctx->priv; \
+ s->class = &name_##_class; \
+ s->filter_type = name_; \
+ return init(ctx); \
+} \
+ \
+AVFilter ff_af_##name_ = { \
+ .name = #name_, \
+ .description = NULL_IF_CONFIG_SMALL(description_), \
+ .priv_size = sizeof(BiquadsContext), \
+ .init = name_##_init, \
+ .uninit = uninit, \
+ .query_formats = query_formats, \
+ .inputs = inputs, \
+ .outputs = outputs, \
+ .priv_class = &name_##_class, \
+}
+
+#if CONFIG_EQUALIZER_FILTER
+static const AVOption equalizer_options[] = {
+ {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 999999, FLAGS},
+ {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 999, FLAGS},
+ {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 999, FLAGS},
+ {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
+ {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(equalizer, "Apply two-pole peaking equalization (EQ) filter.");
+#endif /* CONFIG_EQUALIZER_FILTER */
+#if CONFIG_BASS_FILTER
+static const AVOption bass_options[] = {
+ {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS},
+ {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS},
+ {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS},
+ {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
+ {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(bass, "Boost or cut lower frequencies.");
+#endif /* CONFIG_BASS_FILTER */
+#if CONFIG_TREBLE_FILTER
+static const AVOption treble_options[] = {
+ {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS},
+ {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS},
+ {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
+ {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(treble, "Boost or cut upper frequencies.");
+#endif /* CONFIG_TREBLE_FILTER */
+#if CONFIG_BANDPASS_FILTER
+static const AVOption bandpass_options[] = {
+ {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS},
+ {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS},
+ {"csg", "use constant skirt gain", OFFSET(csg), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(bandpass, "Apply a two-pole Butterworth band-pass filter.");
+#endif /* CONFIG_BANDPASS_FILTER */
+#if CONFIG_BANDREJECT_FILTER
+static const AVOption bandreject_options[] = {
+ {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS},
+ {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(bandreject, "Apply a two-pole Butterworth band-reject filter.");
+#endif /* CONFIG_BANDREJECT_FILTER */
+#if CONFIG_LOWPASS_FILTER
+static const AVOption lowpass_options[] = {
+ {"frequency", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=500}, 0, 999999, FLAGS},
+ {"f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=500}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS},
+ {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS},
+ {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS},
+ {"p", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(lowpass, "Apply a low-pass filter with 3dB point frequency.");
+#endif /* CONFIG_LOWPASS_FILTER */
+#if CONFIG_HIGHPASS_FILTER
+static const AVOption highpass_options[] = {
+ {"frequency", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS},
+ {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS},
+ {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS},
+ {"p", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(highpass, "Apply a high-pass filter with 3dB point frequency.");
+#endif /* CONFIG_HIGHPASS_FILTER */
+#if CONFIG_ALLPASS_FILTER
+static const AVOption allpass_options[] = {
+ {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS},
+ {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, SLOPE, FLAGS, "width_type"},
+ {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"},
+ {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"},
+ {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"},
+ {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"},
+ {"width", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS},
+ {"w", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(allpass, "Apply a two-pole all-pass filter.");
+#endif /* CONFIG_ALLPASS_FILTER */
+#if CONFIG_BIQUAD_FILTER
+static const AVOption biquad_options[] = {
+ {"a0", NULL, OFFSET(a0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS},
+ {"a1", NULL, OFFSET(a1), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS},
+ {"a2", NULL, OFFSET(a2), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS},
+ {"b0", NULL, OFFSET(b0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS},
+ {"b1", NULL, OFFSET(b1), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS},
+ {"b2", NULL, OFFSET(b2), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS},
+ {NULL}
+};
+
+DEFINE_BIQUAD_FILTER(biquad, "Apply a biquad IIR filter with the given coefficients.");
+#endif /* CONFIG_BIQUAD_FILTER */
diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c
index 25e786761f..592fdec3d7 100644
--- a/libavfilter/af_bs2b.c
+++ b/libavfilter/af_bs2b.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -106,22 +106,25 @@ static int query_formats(AVFilterContext *ctx)
AV_SAMPLE_FMT_DBL,
AV_SAMPLE_FMT_NONE,
};
+ int ret;
if (ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO) != 0)
return AVERROR(ENOMEM);
- ff_set_common_channel_layouts(ctx, layouts);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
formats = ff_make_format_list(sample_fmts);
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_formats(ctx, formats);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
formats = ff_all_samplerates();
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_samplerates(ctx, formats);
-
- return 0;
+ return ff_set_common_samplerates(ctx, formats);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
@@ -168,16 +171,16 @@ static int config_output(AVFilterLink *outlink)
bs2b->filter = bs2b_cross_feed_u8;
break;
case AV_SAMPLE_FMT_S16:
- bs2b->filter = bs2b_cross_feed_s16;
+ bs2b->filter = (void*)bs2b_cross_feed_s16;
break;
case AV_SAMPLE_FMT_S32:
- bs2b->filter = bs2b_cross_feed_s32;
+ bs2b->filter = (void*)bs2b_cross_feed_s32;
break;
case AV_SAMPLE_FMT_FLT:
- bs2b->filter = bs2b_cross_feed_f;
+ bs2b->filter = (void*)bs2b_cross_feed_f;
break;
case AV_SAMPLE_FMT_DBL:
- bs2b->filter = bs2b_cross_feed_d;
+ bs2b->filter = (void*)bs2b_cross_feed_d;
break;
default:
return AVERROR_BUG;
diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c
index 3035405f5d..f8289ccf5e 100644
--- a/libavfilter/af_channelmap.c
+++ b/libavfilter/af_channelmap.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Google, Inc.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -68,20 +68,16 @@ typedef struct ChannelMapContext {
#define OFFSET(x) offsetof(ChannelMapContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
-static const AVOption options[] = {
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption channelmap_options[] = {
{ "map", "A comma-separated list of input channel numbers in output order.",
- OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A },
+ OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A|F },
{ "channel_layout", "Output channel layout.",
- OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
- { NULL },
+ OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A|F },
+ { NULL }
};
-static const AVClass channelmap_class = {
- .class_name = "channel map filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(channelmap);
static char* split(char *message, char delim) {
char *next = strchr(message, delim);
@@ -92,9 +88,12 @@ static char* split(char *message, char delim) {
static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
{
- char *next = split(*map, delim);
+ char *next;
int len;
int n = 0;
+ if (!*map)
+ return AVERROR(EINVAL);
+ next = split(*map, delim);
if (!next && delim == '-')
return AVERROR(EINVAL);
len = strlen(*map);
@@ -291,10 +290,16 @@ static av_cold int channelmap_init(AVFilterContext *ctx)
static int channelmap_query_formats(AVFilterContext *ctx)
{
ChannelMapContext *s = ctx->priv;
+ AVFilterChannelLayouts *layouts;
ff_set_common_formats(ctx, ff_planar_sample_fmts());
ff_set_common_samplerates(ctx, ff_all_samplerates());
- ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts);
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+
+ ff_channel_layouts_ref(layouts, &ctx->inputs[0]->out_channel_layouts);
ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts);
return 0;
@@ -316,7 +321,7 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
if (nch_out > nch_in) {
if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
uint8_t **new_extended_data =
- av_mallocz(nch_out * sizeof(*buf->extended_data));
+ av_mallocz_array(nch_out, sizeof(*buf->extended_data));
if (!new_extended_data) {
av_frame_free(&buf);
return AVERROR(ENOMEM);
@@ -343,6 +348,7 @@ static int channelmap_filter_frame(AVFilterLink *inlink, AVFrame *buf)
FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
buf->channel_layout = outlink->channel_layout;
+ av_frame_set_channels(buf, outlink->channels);
return ff_filter_frame(outlink, buf);
}
@@ -389,7 +395,8 @@ static const AVFilterPad avfilter_af_channelmap_inputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = channelmap_filter_frame,
- .config_props = channelmap_config_input
+ .config_props = channelmap_config_input,
+ .needs_writable = 1,
},
{ NULL }
};
@@ -409,7 +416,6 @@ AVFilter ff_af_channelmap = {
.query_formats = channelmap_query_formats,
.priv_size = sizeof(ChannelMapContext),
.priv_class = &channelmap_class,
-
.inputs = avfilter_af_channelmap_inputs,
.outputs = avfilter_af_channelmap_outputs,
};
diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c
index 5b410fd87c..b3756e2be9 100644
--- a/libavfilter/af_channelsplit.c
+++ b/libavfilter/af_channelsplit.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,17 +42,13 @@ typedef struct ChannelSplitContext {
#define OFFSET(x) offsetof(ChannelSplitContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
-static const AVOption options[] = {
- { "channel_layout", "Input channel layout.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, { .str = "stereo" }, .flags = A },
- { NULL },
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption channelsplit_options[] = {
+ { "channel_layout", "Input channel layout.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, { .str = "stereo" }, .flags = A|F },
+ { NULL }
};
-static const AVClass channelsplit_class = {
- .class_name = "channelsplit filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(channelsplit);
static av_cold int init(AVFilterContext *ctx)
{
@@ -121,6 +117,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[i];
buf_out->channel_layout =
av_channel_layout_extract_channel(buf->channel_layout, i);
+ av_frame_set_channels(buf_out, 1);
ret = ff_filter_frame(ctx->outputs[i], buf_out);
if (ret < 0)
@@ -132,24 +129,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
static const AVFilterPad avfilter_af_channelsplit_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
AVFilter ff_af_channelsplit = {
.name = "channelsplit",
- .description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams"),
+ .description = NULL_IF_CONFIG_SMALL("Split audio into per-channel streams."),
.priv_size = sizeof(ChannelSplitContext),
.priv_class = &channelsplit_class,
-
.init = init,
.query_formats = query_formats,
-
- .inputs = avfilter_af_channelsplit_inputs,
- .outputs = NULL,
-
- .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+ .inputs = avfilter_af_channelsplit_inputs,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
};
diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c
new file mode 100644
index 0000000000..93fb36b6ba
--- /dev/null
+++ b/libavfilter/af_chorus.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1998 Juergen Mueller And Sundry Contributors
+ * This source code is freely redistributable and may be used for
+ * any purpose. This copyright notice must be maintained.
+ * Juergen Mueller And Sundry Contributors are not responsible for
+ * the consequences of using this software.
+ *
+ * Copyright (c) 2015 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * chorus audio filter
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "generate_wave_table.h"
+
+typedef struct ChorusContext {
+ const AVClass *class;
+ float in_gain, out_gain;
+ char *delays_str;
+ char *decays_str;
+ char *speeds_str;
+ char *depths_str;
+ float *delays;
+ float *decays;
+ float *speeds;
+ float *depths;
+ uint8_t **chorusbuf;
+ int **phase;
+ int *length;
+ int32_t **lookup_table;
+ int *counter;
+ int num_chorus;
+ int max_samples;
+ int channels;
+ int modulation;
+ int fade_out;
+ int64_t next_pts;
+} ChorusContext;
+
+#define OFFSET(x) offsetof(ChorusContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption chorus_options[] = {
+ { "in_gain", "set input gain", OFFSET(in_gain), AV_OPT_TYPE_FLOAT, {.dbl=.4}, 0, 1, A },
+ { "out_gain", "set output gain", OFFSET(out_gain), AV_OPT_TYPE_FLOAT, {.dbl=.4}, 0, 1, A },
+ { "delays", "set delays", OFFSET(delays_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { "decays", "set decays", OFFSET(decays_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { "speeds", "set speeds", OFFSET(speeds_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { "depths", "set depths", OFFSET(depths_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(chorus);
+
+static void count_items(char *item_str, int *nb_items)
+{
+ char *p;
+
+ *nb_items = 1;
+ for (p = item_str; *p; p++) {
+ if (*p == '|')
+ (*nb_items)++;
+ }
+
+}
+
+static void fill_items(char *item_str, int *nb_items, float *items)
+{
+ char *p, *saveptr = NULL;
+ int i, new_nb_items = 0;
+
+ p = item_str;
+ for (i = 0; i < *nb_items; i++) {
+ char *tstr = av_strtok(p, "|", &saveptr);
+ p = NULL;
+ new_nb_items += sscanf(tstr, "%f", &items[i]) == 1;
+ }
+
+ *nb_items = new_nb_items;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ChorusContext *s = ctx->priv;
+ int nb_delays, nb_decays, nb_speeds, nb_depths;
+
+ if (!s->delays_str || !s->decays_str || !s->speeds_str || !s->depths_str) {
+ av_log(ctx, AV_LOG_ERROR, "Both delays & decays & speeds & depths must be set.\n");
+ return AVERROR(EINVAL);
+ }
+
+ count_items(s->delays_str, &nb_delays);
+ count_items(s->decays_str, &nb_decays);
+ count_items(s->speeds_str, &nb_speeds);
+ count_items(s->depths_str, &nb_depths);
+
+ s->delays = av_realloc_f(s->delays, nb_delays, sizeof(*s->delays));
+ s->decays = av_realloc_f(s->decays, nb_decays, sizeof(*s->decays));
+ s->speeds = av_realloc_f(s->speeds, nb_speeds, sizeof(*s->speeds));
+ s->depths = av_realloc_f(s->depths, nb_depths, sizeof(*s->depths));
+
+ if (!s->delays || !s->decays || !s->speeds || !s->depths)
+ return AVERROR(ENOMEM);
+
+ fill_items(s->delays_str, &nb_delays, s->delays);
+ fill_items(s->decays_str, &nb_decays, s->decays);
+ fill_items(s->speeds_str, &nb_speeds, s->speeds);
+ fill_items(s->depths_str, &nb_depths, s->depths);
+
+ if (nb_delays != nb_decays && nb_delays != nb_speeds && nb_delays != nb_depths) {
+ av_log(ctx, AV_LOG_ERROR, "Number of delays & decays & speeds & depths given must be same.\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->num_chorus = nb_delays;
+
+ if (s->num_chorus < 1) {
+ av_log(ctx, AV_LOG_ERROR, "At least one delay & decay & speed & depth must be set.\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->length = av_calloc(s->num_chorus, sizeof(*s->length));
+ s->lookup_table = av_calloc(s->num_chorus, sizeof(*s->lookup_table));
+
+ if (!s->length || !s->lookup_table)
+ return AVERROR(ENOMEM);
+
+ s->next_pts = AV_NOPTS_VALUE;
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ChorusContext *s = ctx->priv;
+ float sum_in_volume = 1.0;
+ int n;
+
+ s->channels = outlink->channels;
+
+ for (n = 0; n < s->num_chorus; n++) {
+ int samples = (int) ((s->delays[n] + s->depths[n]) * outlink->sample_rate / 1000.0);
+ int depth_samples = (int) (s->depths[n] * outlink->sample_rate / 1000.0);
+
+ s->length[n] = outlink->sample_rate / s->speeds[n];
+
+ s->lookup_table[n] = av_malloc(sizeof(int32_t) * s->length[n]);
+ if (!s->lookup_table[n])
+ return AVERROR(ENOMEM);
+
+ ff_generate_wave_table(WAVE_SIN, AV_SAMPLE_FMT_S32, s->lookup_table[n],
+ s->length[n], 0., depth_samples, 0);
+ s->max_samples = FFMAX(s->max_samples, samples);
+ }
+
+ for (n = 0; n < s->num_chorus; n++)
+ sum_in_volume += s->decays[n];
+
+ if (s->in_gain * (sum_in_volume) > 1.0 / s->out_gain)
+ av_log(ctx, AV_LOG_WARNING, "output gain can cause saturation or clipping of output\n");
+
+ s->counter = av_calloc(outlink->channels, sizeof(*s->counter));
+ if (!s->counter)
+ return AVERROR(ENOMEM);
+
+ s->phase = av_calloc(outlink->channels, sizeof(*s->phase));
+ if (!s->phase)
+ return AVERROR(ENOMEM);
+
+ for (n = 0; n < outlink->channels; n++) {
+ s->phase[n] = av_calloc(s->num_chorus, sizeof(int));
+ if (!s->phase[n])
+ return AVERROR(ENOMEM);
+ }
+
+ s->fade_out = s->max_samples;
+
+ return av_samples_alloc_array_and_samples(&s->chorusbuf, NULL,
+ outlink->channels,
+ s->max_samples,
+ outlink->format, 0);
+}
+
+#define MOD(a, b) (((a) >= (b)) ? (a) - (b) : (a))
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ChorusContext *s = ctx->priv;
+ AVFrame *out_frame;
+ int c, i, n;
+
+ if (av_frame_is_writable(frame)) {
+ out_frame = frame;
+ } else {
+ out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
+ if (!out_frame)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_frame, frame);
+ }
+
+ for (c = 0; c < inlink->channels; c++) {
+ const float *src = (const float *)frame->extended_data[c];
+ float *dst = (float *)out_frame->extended_data[c];
+ float *chorusbuf = (float *)s->chorusbuf[c];
+ int *phase = s->phase[c];
+
+ for (i = 0; i < frame->nb_samples; i++) {
+ float out, in = src[i];
+
+ out = in * s->in_gain;
+
+ for (n = 0; n < s->num_chorus; n++) {
+ out += chorusbuf[MOD(s->max_samples + s->counter[c] -
+ s->lookup_table[n][phase[n]],
+ s->max_samples)] * s->decays[n];
+ phase[n] = MOD(phase[n] + 1, s->length[n]);
+ }
+
+ out *= s->out_gain;
+
+ dst[i] = out;
+
+ chorusbuf[s->counter[c]] = in;
+ s->counter[c] = MOD(s->counter[c] + 1, s->max_samples);
+ }
+ }
+
+ s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
+
+ if (frame != out_frame)
+ av_frame_free(&frame);
+
+ return ff_filter_frame(ctx->outputs[0], out_frame);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ChorusContext *s = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+
+ if (ret == AVERROR_EOF && !ctx->is_disabled && s->fade_out) {
+ int nb_samples = FFMIN(s->fade_out, 2048);
+ AVFrame *frame;
+
+ frame = ff_get_audio_buffer(outlink, nb_samples);
+ if (!frame)
+ return AVERROR(ENOMEM);
+ s->fade_out -= nb_samples;
+
+ av_samples_set_silence(frame->extended_data, 0,
+ frame->nb_samples,
+ outlink->channels,
+ frame->format);
+
+ frame->pts = s->next_pts;
+ if (s->next_pts != AV_NOPTS_VALUE)
+ s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
+
+ ret = filter_frame(ctx->inputs[0], frame);
+ }
+
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ChorusContext *s = ctx->priv;
+ int n;
+
+ av_freep(&s->delays);
+ av_freep(&s->decays);
+ av_freep(&s->speeds);
+ av_freep(&s->depths);
+
+ if (s->chorusbuf)
+ av_freep(&s->chorusbuf[0]);
+ av_freep(&s->chorusbuf);
+
+ if (s->phase)
+ for (n = 0; n < s->channels; n++)
+ av_freep(&s->phase[n]);
+ av_freep(&s->phase);
+
+ av_freep(&s->counter);
+ av_freep(&s->length);
+
+ if (s->lookup_table)
+ for (n = 0; n < s->num_chorus; n++)
+ av_freep(&s->lookup_table[n]);
+ av_freep(&s->lookup_table);
+}
+
+static const AVFilterPad chorus_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad chorus_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = request_frame,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_chorus = {
+ .name = "chorus",
+ .description = NULL_IF_CONFIG_SMALL("Add a chorus effect to the audio."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(ChorusContext),
+ .priv_class = &chorus_class,
+ .init = init,
+ .uninit = uninit,
+ .inputs = chorus_inputs,
+ .outputs = chorus_outputs,
+};
diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c
index f21c861e06..55ad98a15d 100644
--- a/libavfilter/af_compand.c
+++ b/libavfilter/af_compand.c
@@ -5,20 +5,20 @@
* Copyright (c) 2013 Paul B Mahol
* Copyright (c) 2014 Andrew Kelley
*
- * This file is part of libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,39 +27,33 @@
* audio compand filter
*/
-#include <string.h>
-
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
-#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 "formats.h"
#include "internal.h"
typedef struct ChanParam {
- float attack;
- float decay;
- float volume;
+ double attack;
+ double decay;
+ double volume;
} ChanParam;
typedef struct CompandSegment {
- float x, y;
- float a, b;
+ double x, y;
+ double a, b;
} CompandSegment;
typedef struct CompandContext {
const AVClass *class;
- int nb_channels;
int nb_segments;
char *attacks, *decays, *points;
CompandSegment *segments;
ChanParam *channels;
- float in_min_lin;
- float out_min_lin;
+ double in_min_lin;
+ double out_min_lin;
double curve_dB;
double gain_dB;
double initial_volume;
@@ -71,12 +65,10 @@ typedef struct CompandContext {
int64_t pts;
int (*compand)(AVFilterContext *ctx, AVFrame *frame);
- /* set by filter_frame() to signal an output frame to request_frame() */
- int got_output;
} CompandContext;
#define OFFSET(x) offsetof(CompandContext, x)
-#define A AV_OPT_FLAG_AUDIO_PARAM
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption compand_options[] = {
{ "attacks", "set time over which increase of volume is determined", OFFSET(attacks), AV_OPT_TYPE_STRING, { .str = "0.3" }, 0, 0, A },
@@ -89,12 +81,7 @@ static const AVOption compand_options[] = {
{ NULL }
};
-static const AVClass compand_class = {
- .class_name = "compand filter",
- .item_name = av_default_item_name,
- .option = compand_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(compand);
static av_cold int init(AVFilterContext *ctx)
{
@@ -117,26 +104,29 @@ static int query_formats(AVFilterContext *ctx)
AVFilterChannelLayouts *layouts;
AVFilterFormats *formats;
static const enum AVSampleFormat sample_fmts[] = {
- AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_DBLP,
AV_SAMPLE_FMT_NONE
};
+ int ret;
layouts = ff_all_channel_layouts();
if (!layouts)
return AVERROR(ENOMEM);
- ff_set_common_channel_layouts(ctx, layouts);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
formats = ff_make_format_list(sample_fmts);
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_formats(ctx, formats);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
formats = ff_all_samplerates();
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_samplerates(ctx, formats);
-
- return 0;
+ return ff_set_common_samplerates(ctx, formats);
}
static void count_items(char *item_str, int *nb_items)
@@ -145,14 +135,14 @@ static void count_items(char *item_str, int *nb_items)
*nb_items = 1;
for (p = item_str; *p; p++) {
- if (*p == '|')
+ if (*p == ' ' || *p == '|')
(*nb_items)++;
}
}
-static void update_volume(ChanParam *cp, float in)
+static void update_volume(ChanParam *cp, double in)
{
- float delta = in - cp->volume;
+ double delta = in - cp->volume;
if (delta > 0.0)
cp->volume += delta * cp->attack;
@@ -160,16 +150,16 @@ static void update_volume(ChanParam *cp, float in)
cp->volume += delta * cp->decay;
}
-static float get_volume(CompandContext *s, float in_lin)
+static double get_volume(CompandContext *s, double in_lin)
{
CompandSegment *cs;
- float in_log, out_log;
+ double in_log, out_log;
int i;
if (in_lin < s->in_min_lin)
return s->out_min_lin;
- in_log = logf(in_lin);
+ in_log = log(in_lin);
for (i = 1; i < s->nb_segments; i++)
if (in_log <= s->segments[i].x)
@@ -178,14 +168,14 @@ static float get_volume(CompandContext *s, float in_lin)
in_log -= cs->x;
out_log = cs->y + in_log * (cs->a * in_log + cs->b);
- return expf(out_log);
+ return exp(out_log);
}
static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
{
CompandContext *s = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
- const int channels = s->nb_channels;
+ const int channels = inlink->channels;
const int nb_samples = frame->nb_samples;
AVFrame *out_frame;
int chan, i;
@@ -208,14 +198,14 @@ static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame)
}
for (chan = 0; chan < channels; chan++) {
- const float *src = (float *)frame->extended_data[chan];
- float *dst = (float *)out_frame->extended_data[chan];
+ const double *src = (double *)frame->extended_data[chan];
+ double *dst = (double *)out_frame->extended_data[chan];
ChanParam *cp = &s->channels[chan];
for (i = 0; i < nb_samples; i++) {
update_volume(cp, fabs(src[i]));
- dst[i] = av_clipf(src[i] * get_volume(s, cp->volume), -1.0f, 1.0f);
+ dst[i] = av_clipd(src[i] * get_volume(s, cp->volume), -1, 1);
}
}
@@ -231,9 +221,9 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
{
CompandContext *s = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
- const int channels = s->nb_channels;
+ const int channels = inlink->channels;
const int nb_samples = frame->nb_samples;
- int chan, i, dindex = 0, oindex, count = 0;
+ int chan, i, av_uninit(dindex), oindex, av_uninit(count);
AVFrame *out_frame = NULL;
int err;
@@ -241,17 +231,19 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
s->pts = (frame->pts == AV_NOPTS_VALUE) ? 0 : frame->pts;
}
+ av_assert1(channels > 0); /* would corrupt delay_count and delay_index */
+
for (chan = 0; chan < channels; chan++) {
AVFrame *delay_frame = s->delay_frame;
- const float *src = (float *)frame->extended_data[chan];
- float *dbuf = (float *)delay_frame->extended_data[chan];
+ const double *src = (double *)frame->extended_data[chan];
+ double *dbuf = (double *)delay_frame->extended_data[chan];
ChanParam *cp = &s->channels[chan];
- float *dst;
+ double *dst;
count = s->delay_count;
dindex = s->delay_index;
for (i = 0, oindex = 0; i < nb_samples; i++) {
- const float in = src[i];
+ const double in = src[i];
update_volume(cp, fabs(in));
if (count >= s->delay_samples) {
@@ -273,9 +265,9 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
inlink->time_base);
}
- dst = (float *)out_frame->extended_data[chan];
- dst[oindex++] = av_clipf(dbuf[dindex] *
- get_volume(s, cp->volume), -1.0f, 1.0f);
+ dst = (double *)out_frame->extended_data[chan];
+ dst[oindex++] = av_clipd(dbuf[dindex] *
+ get_volume(s, cp->volume), -1, 1);
} else {
count++;
}
@@ -292,8 +284,6 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame)
if (out_frame) {
err = ff_filter_frame(ctx->outputs[0], out_frame);
- if (err >= 0)
- s->got_output = 1;
return err;
}
@@ -304,7 +294,7 @@ static int compand_drain(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
CompandContext *s = ctx->priv;
- const int channels = s->nb_channels;
+ const int channels = outlink->channels;
AVFrame *frame = NULL;
int chan, i, dindex;
@@ -316,16 +306,17 @@ static int compand_drain(AVFilterLink *outlink)
s->pts += av_rescale_q(frame->nb_samples,
(AVRational){ 1, outlink->sample_rate }, outlink->time_base);
+ av_assert0(channels > 0);
for (chan = 0; chan < channels; chan++) {
AVFrame *delay_frame = s->delay_frame;
- float *dbuf = (float *)delay_frame->extended_data[chan];
- float *dst = (float *)frame->extended_data[chan];
+ double *dbuf = (double *)delay_frame->extended_data[chan];
+ double *dst = (double *)frame->extended_data[chan];
ChanParam *cp = &s->channels[chan];
dindex = s->delay_index;
for (i = 0; i < frame->nb_samples; i++) {
- dst[i] = av_clipf(dbuf[dindex] * get_volume(s, cp->volume),
- -1.0f, 1.0f);
+ dst[i] = av_clipd(dbuf[dindex] * get_volume(s, cp->volume),
+ -1, 1);
dindex = MOD(dindex + 1, s->delay_samples);
}
}
@@ -341,9 +332,8 @@ static int config_output(AVFilterLink *outlink)
CompandContext *s = ctx->priv;
const int sample_rate = outlink->sample_rate;
double radius = s->curve_dB * M_LN10 / 20.0;
- const char *p;
- const int channels =
- av_get_channel_layout_nb_channels(outlink->channel_layout);
+ char *p, *saveptr = NULL;
+ const int channels = outlink->channels;
int nb_attacks, nb_decays, nb_points;
int new_nb_items, num;
int i;
@@ -367,7 +357,6 @@ static int config_output(AVFilterLink *outlink)
uninit(ctx);
- s->nb_channels = channels;
s->channels = av_mallocz_array(channels, sizeof(*s->channels));
s->nb_segments = (nb_points + 4) * 2;
s->segments = av_mallocz_array(s->nb_segments, sizeof(*s->segments));
@@ -379,34 +368,25 @@ static int config_output(AVFilterLink *outlink)
p = s->attacks;
for (i = 0, new_nb_items = 0; i < nb_attacks; i++) {
- char *tstr = av_get_token(&p, "|");
- if (!tstr)
- return AVERROR(ENOMEM);
-
- new_nb_items += sscanf(tstr, "%f", &s->channels[i].attack) == 1;
- av_freep(&tstr);
+ char *tstr = av_strtok(p, " |", &saveptr);
+ p = NULL;
+ new_nb_items += sscanf(tstr, "%lf", &s->channels[i].attack) == 1;
if (s->channels[i].attack < 0) {
uninit(ctx);
return AVERROR(EINVAL);
}
- if (*p)
- p++;
}
nb_attacks = new_nb_items;
p = s->decays;
for (i = 0, new_nb_items = 0; i < nb_decays; i++) {
- char *tstr = av_get_token(&p, "|");
- if (!tstr)
- return AVERROR(ENOMEM);
- new_nb_items += sscanf(tstr, "%f", &s->channels[i].decay) == 1;
- av_freep(&tstr);
+ char *tstr = av_strtok(p, " |", &saveptr);
+ p = NULL;
+ new_nb_items += sscanf(tstr, "%lf", &s->channels[i].decay) == 1;
if (s->channels[i].decay < 0) {
uninit(ctx);
return AVERROR(EINVAL);
}
- if (*p)
- p++;
}
nb_decays = new_nb_items;
@@ -421,13 +401,9 @@ static int config_output(AVFilterLink *outlink)
#define S(x) s->segments[2 * ((x) + 1)]
p = s->points;
for (i = 0, new_nb_items = 0; i < nb_points; i++) {
- char *tstr = av_get_token(&p, "|");
- if (!tstr)
- return AVERROR(ENOMEM);
-
- err = sscanf(tstr, "%f/%f", &S(i).x, &S(i).y);
- av_freep(&tstr);
- if (err != 2) {
+ char *tstr = av_strtok(p, " |", &saveptr);
+ p = NULL;
+ if (sscanf(tstr, "%lf/%lf", &S(i).x, &S(i).y) != 2) {
av_log(ctx, AV_LOG_ERROR,
"Invalid and/or missing input/output value.\n");
uninit(ctx);
@@ -442,8 +418,6 @@ static int config_output(AVFilterLink *outlink)
S(i).y -= S(i).x;
av_log(ctx, AV_LOG_DEBUG, "%d: x=%f y=%f\n", i, S(i).x, S(i).y);
new_nb_items++;
- if (*p)
- p++;
}
num = new_nb_items;
@@ -464,7 +438,6 @@ static int config_output(AVFilterLink *outlink)
double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x);
int j;
- /* here we purposefully lose precision so that we can compare floats */
if (fabs(g1 - g2))
continue;
num--;
@@ -553,6 +526,7 @@ static int config_output(AVFilterLink *outlink)
if (err)
return err;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
s->compand = compand_delay;
return 0;
}
@@ -571,11 +545,9 @@ static int request_frame(AVFilterLink *outlink)
CompandContext *s = ctx->priv;
int ret = 0;
- s->got_output = 0;
- while (ret >= 0 && !s->got_output)
- ret = ff_request_frame(ctx->inputs[0]);
+ ret = ff_request_frame(ctx->inputs[0]);
- if (ret == AVERROR_EOF && s->delay_count)
+ if (ret == AVERROR_EOF && !ctx->is_disabled && s->delay_count)
ret = compand_drain(outlink);
return ret;
diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c
new file mode 100644
index 0000000000..eb981568f1
--- /dev/null
+++ b/libavfilter/af_dcshift.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2000 Chris Ausbrooks <weed@bucket.pp.ualr.edu>
+ * Copyright (c) 2000 Fabien COELHO <fabien@coelho.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/samplefmt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+
+typedef struct DCShiftContext {
+ const AVClass *class;
+ double dcshift;
+ double limiterthreshhold;
+ double limitergain;
+} DCShiftContext;
+
+#define OFFSET(x) offsetof(DCShiftContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption dcshift_options[] = {
+ { "shift", "set DC shift", OFFSET(dcshift), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, A },
+ { "limitergain", "set limiter gain", OFFSET(limitergain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, A },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(dcshift);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ DCShiftContext *s = ctx->priv;
+
+ s->limiterthreshhold = INT32_MAX * (1.0 - (fabs(s->dcshift) - s->limitergain));
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterChannelLayouts *layouts;
+ AVFilterFormats *formats;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out = ff_get_audio_buffer(inlink, in->nb_samples);
+ DCShiftContext *s = ctx->priv;
+ int i, j;
+ double dcshift = s->dcshift;
+
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ if (s->limitergain > 0) {
+ for (i = 0; i < inlink->channels; i++) {
+ const int32_t *src = (int32_t *)in->extended_data[i];
+ int32_t *dst = (int32_t *)out->extended_data[i];
+
+ for (j = 0; j < in->nb_samples; j++) {
+ double d;
+
+ d = src[j];
+
+ if (d > s->limiterthreshhold && dcshift > 0) {
+ d = (d - s->limiterthreshhold) * s->limitergain /
+ (INT32_MAX - s->limiterthreshhold) +
+ s->limiterthreshhold + dcshift;
+ } else if (d < -s->limiterthreshhold && dcshift < 0) {
+ d = (d + s->limiterthreshhold) * s->limitergain /
+ (INT32_MAX - s->limiterthreshhold) -
+ s->limiterthreshhold + dcshift;
+ } else {
+ d = dcshift * INT32_MAX + d;
+ }
+
+ dst[j] = av_clipl_int32(d);
+ }
+ }
+ } else {
+ for (i = 0; i < inlink->channels; i++) {
+ const int32_t *src = (int32_t *)in->extended_data[i];
+ int32_t *dst = (int32_t *)out->extended_data[i];
+
+ for (j = 0; j < in->nb_samples; j++) {
+ double d = dcshift * (INT32_MAX + 1.) + src[j];
+
+ dst[j] = av_clipl_int32(d);
+ }
+ }
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+static const AVFilterPad dcshift_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad dcshift_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_dcshift = {
+ .name = "dcshift",
+ .description = NULL_IF_CONFIG_SMALL("Apply a DC shift to the audio."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(DCShiftContext),
+ .priv_class = &dcshift_class,
+ .init = init,
+ .inputs = dcshift_inputs,
+ .outputs = dcshift_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c
new file mode 100644
index 0000000000..c3109976f8
--- /dev/null
+++ b/libavfilter/af_earwax.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 Mina Nagy Zaki
+ * Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
+ * This source code is freely redistributable and may be used for any purpose.
+ * This copyright notice must be maintained. Edward Beingessner And Sundry
+ * Contributors are not responsible for the consequences of using this
+ * software.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Stereo Widening Effect. Adds audio cues to move stereo image in
+ * front of the listener. Adapted from the libsox earwax effect.
+ */
+
+#include "libavutil/channel_layout.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "formats.h"
+
+#define NUMTAPS 64
+
+static const int8_t filt[NUMTAPS] = {
+/* 30° 330° */
+ 4, -6, /* 32 tap stereo FIR filter. */
+ 4, -11, /* One side filters as if the */
+ -1, -5, /* signal was from 30 degrees */
+ 3, 3, /* from the ear, the other as */
+ -2, 5, /* if 330 degrees. */
+ -5, 0,
+ 9, 1,
+ 6, 3, /* Input */
+ -4, -1, /* Left Right */
+ -5, -3, /* __________ __________ */
+ -2, -5, /* | | | | */
+ -7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */
+ 6, -7, /* / |__________| |__________| \ */
+ 30, -29, /* / \ / \ */
+ 12, -3, /* / X \ */
+ -11, 4, /* / / \ \ */
+ -3, 7, /* ____V_____ __________V V__________ _____V____ */
+ -20, 23, /* | | | | | | | | */
+ 2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */
+ 1, -6, /* |__________| |__________| |__________| |__________| */
+ -14, -5, /* \ ___ / \ ___ / */
+ 15, -18, /* \ / \ / _____ \ / \ / */
+ 6, 7, /* `->| + |<--' / \ `-->| + |<-' */
+ 15, -10, /* \___/ _/ \_ \___/ */
+ -14, 22, /* \ / \ / \ / */
+ -7, -2, /* `--->| | | |<---' */
+ -4, 9, /* \_/ \_/ */
+ 6, -12, /* */
+ 6, -6, /* Headphones */
+ 0, -11,
+ 0, -5,
+ 4, 0};
+
+typedef struct {
+ int16_t taps[NUMTAPS * 2];
+} EarwaxContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const int sample_rates[] = { 44100, -1 };
+
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layout = NULL;
+
+ ff_add_format(&formats, AV_SAMPLE_FMT_S16);
+ ff_set_common_formats(ctx, formats);
+ ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
+ ff_set_common_channel_layouts(ctx, layout);
+ ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
+
+ return 0;
+}
+
+//FIXME: replace with DSPContext.scalarproduct_int16
+static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, int16_t *out)
+{
+ int32_t sample;
+ int16_t j;
+
+ while (in < endin) {
+ sample = 0;
+ for (j = 0; j < NUMTAPS; j++)
+ sample += in[j] * filt[j];
+ *out = av_clip_int16(sample >> 6);
+ out++;
+ in++;
+ }
+
+ return out;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int16_t *taps, *endin, *in, *out;
+ AVFrame *outsamples = ff_get_audio_buffer(inlink, insamples->nb_samples);
+ int len;
+
+ if (!outsamples) {
+ av_frame_free(&insamples);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outsamples, insamples);
+
+ taps = ((EarwaxContext *)inlink->dst->priv)->taps;
+ out = (int16_t *)outsamples->data[0];
+ in = (int16_t *)insamples ->data[0];
+
+ len = FFMIN(NUMTAPS, 2*insamples->nb_samples);
+ // copy part of new input and process with saved input
+ memcpy(taps+NUMTAPS, in, len * sizeof(*taps));
+ out = scalarproduct(taps, taps + len, out);
+
+ // process current input
+ if (2*insamples->nb_samples >= NUMTAPS ){
+ endin = in + insamples->nb_samples * 2 - NUMTAPS;
+ scalarproduct(in, endin, out);
+
+ // save part of input for next round
+ memcpy(taps, endin, NUMTAPS * sizeof(*taps));
+ } else
+ memmove(taps, taps + 2*insamples->nb_samples, NUMTAPS * sizeof(*taps));
+
+ av_frame_free(&insamples);
+ return ff_filter_frame(outlink, outsamples);
+}
+
+static const AVFilterPad earwax_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad earwax_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_earwax = {
+ .name = "earwax",
+ .description = NULL_IF_CONFIG_SMALL("Widen the stereo image."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(EarwaxContext),
+ .inputs = earwax_inputs,
+ .outputs = earwax_outputs,
+};
diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c
new file mode 100644
index 0000000000..106e6f73f8
--- /dev/null
+++ b/libavfilter/af_flanger.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2006 Rob Sykes <robs@users.sourceforge.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/samplefmt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "internal.h"
+#include "generate_wave_table.h"
+
+#define INTERPOLATION_LINEAR 0
+#define INTERPOLATION_QUADRATIC 1
+
+typedef struct FlangerContext {
+ const AVClass *class;
+ double delay_min;
+ double delay_depth;
+ double feedback_gain;
+ double delay_gain;
+ double speed;
+ int wave_shape;
+ double channel_phase;
+ int interpolation;
+ double in_gain;
+ int max_samples;
+ uint8_t **delay_buffer;
+ int delay_buf_pos;
+ double *delay_last;
+ float *lfo;
+ int lfo_length;
+ int lfo_pos;
+} FlangerContext;
+
+#define OFFSET(x) offsetof(FlangerContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption flanger_options[] = {
+ { "delay", "base delay in milliseconds", OFFSET(delay_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 30, A },
+ { "depth", "added swept delay in milliseconds", OFFSET(delay_depth), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, 10, A },
+ { "regen", "percentage regeneration (delayed signal feedback)", OFFSET(feedback_gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -95, 95, A },
+ { "width", "percentage of delayed signal mixed with original", OFFSET(delay_gain), AV_OPT_TYPE_DOUBLE, {.dbl=71}, 0, 100, A },
+ { "speed", "sweeps per second (Hz)", OFFSET(speed), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0.1, 10, A },
+ { "shape", "swept wave shape", OFFSET(wave_shape), AV_OPT_TYPE_INT, {.i64=WAVE_SIN}, WAVE_SIN, WAVE_NB-1, A, "type" },
+ { "triangular", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_TRI}, 0, 0, A, "type" },
+ { "t", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_TRI}, 0, 0, A, "type" },
+ { "sinusoidal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_SIN}, 0, 0, A, "type" },
+ { "s", NULL, 0, AV_OPT_TYPE_CONST, {.i64=WAVE_SIN}, 0, 0, A, "type" },
+ { "phase", "swept wave percentage phase-shift for multi-channel", OFFSET(channel_phase), AV_OPT_TYPE_DOUBLE, {.dbl=25}, 0, 100, A },
+ { "interp", "delay-line interpolation", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A, "itype" },
+ { "linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATION_LINEAR}, 0, 0, A, "itype" },
+ { "quadratic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATION_QUADRATIC}, 0, 0, A, "itype" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(flanger);
+
+static int init(AVFilterContext *ctx)
+{
+ FlangerContext *s = ctx->priv;
+
+ s->feedback_gain /= 100;
+ s->delay_gain /= 100;
+ s->channel_phase /= 100;
+ s->delay_min /= 1000;
+ s->delay_depth /= 1000;
+ s->in_gain = 1 / (1 + s->delay_gain);
+ s->delay_gain /= 1 + s->delay_gain;
+ s->delay_gain *= 1 - fabs(s->feedback_gain);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterChannelLayouts *layouts;
+ AVFilterFormats *formats;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ FlangerContext *s = ctx->priv;
+
+ s->max_samples = (s->delay_min + s->delay_depth) * inlink->sample_rate + 2.5;
+ s->lfo_length = inlink->sample_rate / s->speed;
+ s->delay_last = av_calloc(inlink->channels, sizeof(*s->delay_last));
+ s->lfo = av_calloc(s->lfo_length, sizeof(*s->lfo));
+ if (!s->lfo || !s->delay_last)
+ return AVERROR(ENOMEM);
+
+ ff_generate_wave_table(s->wave_shape, AV_SAMPLE_FMT_FLT, s->lfo, s->lfo_length,
+ floor(s->delay_min * inlink->sample_rate + 0.5),
+ s->max_samples - 2., 3 * M_PI_2);
+
+ return av_samples_alloc_array_and_samples(&s->delay_buffer, NULL,
+ inlink->channels, s->max_samples,
+ inlink->format, 0);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ FlangerContext *s = ctx->priv;
+ AVFrame *out_frame;
+ int chan, i;
+
+ if (av_frame_is_writable(frame)) {
+ out_frame = frame;
+ } else {
+ out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
+ if (!out_frame)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out_frame, frame);
+ }
+
+ for (i = 0; i < frame->nb_samples; i++) {
+
+ s->delay_buf_pos = (s->delay_buf_pos + s->max_samples - 1) % s->max_samples;
+
+ for (chan = 0; chan < inlink->channels; chan++) {
+ double *src = (double *)frame->extended_data[chan];
+ double *dst = (double *)out_frame->extended_data[chan];
+ double delayed_0, delayed_1;
+ double delayed;
+ double in, out;
+ int channel_phase = chan * s->lfo_length * s->channel_phase + .5;
+ double delay = s->lfo[(s->lfo_pos + channel_phase) % s->lfo_length];
+ int int_delay = (int)delay;
+ double frac_delay = modf(delay, &delay);
+ double *delay_buffer = (double *)s->delay_buffer[chan];
+
+ in = src[i];
+ delay_buffer[s->delay_buf_pos] = in + s->delay_last[chan] *
+ s->feedback_gain;
+ delayed_0 = delay_buffer[(s->delay_buf_pos + int_delay++) % s->max_samples];
+ delayed_1 = delay_buffer[(s->delay_buf_pos + int_delay++) % s->max_samples];
+
+ if (s->interpolation == INTERPOLATION_LINEAR) {
+ delayed = delayed_0 + (delayed_1 - delayed_0) * frac_delay;
+ } else {
+ double a, b;
+ double delayed_2 = delay_buffer[(s->delay_buf_pos + int_delay++) % s->max_samples];
+ delayed_2 -= delayed_0;
+ delayed_1 -= delayed_0;
+ a = delayed_2 * .5 - delayed_1;
+ b = delayed_1 * 2 - delayed_2 *.5;
+ delayed = delayed_0 + (a * frac_delay + b) * frac_delay;
+ }
+
+ s->delay_last[chan] = delayed;
+ out = in * s->in_gain + delayed * s->delay_gain;
+ dst[i] = out;
+ }
+ s->lfo_pos = (s->lfo_pos + 1) % s->lfo_length;
+ }
+
+ if (frame != out_frame)
+ av_frame_free(&frame);
+
+ return ff_filter_frame(ctx->outputs[0], out_frame);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ FlangerContext *s = ctx->priv;
+
+ av_freep(&s->lfo);
+ av_freep(&s->delay_last);
+
+ if (s->delay_buffer)
+ av_freep(&s->delay_buffer[0]);
+ av_freep(&s->delay_buffer);
+}
+
+static const AVFilterPad flanger_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad flanger_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_flanger = {
+ .name = "flanger",
+ .description = NULL_IF_CONFIG_SMALL("Apply a flanging effect to the audio."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(FlangerContext),
+ .priv_class = &flanger_class,
+ .init = init,
+ .uninit = uninit,
+ .inputs = flanger_inputs,
+ .outputs = flanger_outputs,
+};
diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c
index e684cb9ff9..4c1f6a075c 100644
--- a/libavfilter/af_join.c
+++ b/libavfilter/af_join.c
@@ -1,19 +1,18 @@
/*
+ * This file is part of FFmpeg.
*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,22 +65,18 @@ typedef struct JoinContext {
#define OFFSET(x) offsetof(JoinContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
+#define F AV_OPT_FLAG_FILTERING_PARAM
static const AVOption join_options[] = {
- { "inputs", "Number of input streams.", OFFSET(inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, A },
+ { "inputs", "Number of input streams.", OFFSET(inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, A|F },
{ "channel_layout", "Channel layout of the "
- "output stream.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A },
+ "output stream.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A|F },
{ "map", "A comma-separated list of channels maps in the format "
"'input_stream.input_channel-output_channel.",
- OFFSET(map), AV_OPT_TYPE_STRING, .flags = A },
- { NULL },
+ OFFSET(map), AV_OPT_TYPE_STRING, .flags = A|F },
+ { NULL }
};
-static const AVClass join_class = {
- .class_name = "join filter",
- .item_name = av_default_item_name,
- .option = join_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(join);
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
@@ -194,18 +189,15 @@ static av_cold int join_init(AVFilterContext *ctx)
if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
s->channel_layout_str);
- ret = AVERROR(EINVAL);
- goto fail;
+ return AVERROR(EINVAL);
}
s->nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
- s->channels = av_mallocz(sizeof(*s->channels) * s->nb_channels);
- s->buffers = av_mallocz(sizeof(*s->buffers) * s->nb_channels);
- s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs);
- if (!s->channels || !s->buffers|| !s->input_frames) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
+ s->channels = av_mallocz_array(s->nb_channels, sizeof(*s->channels));
+ s->buffers = av_mallocz_array(s->nb_channels, sizeof(*s->buffers));
+ s->input_frames = av_mallocz_array(s->inputs, sizeof(*s->input_frames));
+ if (!s->channels || !s->buffers|| !s->input_frames)
+ return AVERROR(ENOMEM);
for (i = 0; i < s->nb_channels; i++) {
s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
@@ -213,7 +205,7 @@ static av_cold int join_init(AVFilterContext *ctx)
}
if ((ret = parse_maps(ctx)) < 0)
- goto fail;
+ return ret;
for (i = 0; i < s->inputs; i++) {
char name[32];
@@ -222,6 +214,8 @@ static av_cold int join_init(AVFilterContext *ctx)
snprintf(name, sizeof(name), "input%d", i);
pad.type = AVMEDIA_TYPE_AUDIO;
pad.name = av_strdup(name);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
pad.filter_frame = filter_frame;
pad.needs_fifo = 1;
@@ -229,9 +223,7 @@ static av_cold int join_init(AVFilterContext *ctx)
ff_insert_inpad(ctx, i, &pad);
}
-fail:
- av_opt_free(s);
- return ret;
+ return 0;
}
static av_cold void join_uninit(AVFilterContext *ctx)
@@ -258,9 +250,12 @@ static int join_query_formats(AVFilterContext *ctx)
ff_add_channel_layout(&layouts, s->channel_layout);
ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
- for (i = 0; i < ctx->nb_inputs; i++)
- ff_channel_layouts_ref(ff_all_channel_layouts(),
- &ctx->inputs[i]->out_channel_layouts);
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts);
+ }
ff_set_common_formats (ctx, ff_planar_sample_fmts());
ff_set_common_samplerates(ctx, ff_all_samplerates());
@@ -313,7 +308,7 @@ static int join_config_output(AVFilterLink *outlink)
int i, ret = 0;
/* initialize inputs to user-specified mappings */
- if (!(inputs = av_mallocz(sizeof(*inputs) * ctx->nb_inputs)))
+ if (!(inputs = av_mallocz_array(ctx->nb_inputs, sizeof(*inputs))))
return AVERROR(ENOMEM);
for (i = 0; i < s->nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
@@ -419,7 +414,7 @@ static int join_request_frame(AVFilterLink *outlink)
if (!frame)
return AVERROR(ENOMEM);
if (s->nb_channels > FF_ARRAY_ELEMS(frame->data)) {
- frame->extended_data = av_mallocz(s->nb_channels *
+ frame->extended_data = av_mallocz_array(s->nb_channels,
sizeof(*frame->extended_data));
if (!frame->extended_data) {
ret = AVERROR(ENOMEM);
@@ -453,8 +448,8 @@ static int join_request_frame(AVFilterLink *outlink)
/* create references to the buffers we copied to output */
if (nb_buffers > FF_ARRAY_ELEMS(frame->buf)) {
frame->nb_extended_buf = nb_buffers - FF_ARRAY_ELEMS(frame->buf);
- frame->extended_buf = av_mallocz(sizeof(*frame->extended_buf) *
- frame->nb_extended_buf);
+ frame->extended_buf = av_mallocz_array(frame->nb_extended_buf,
+ sizeof(*frame->extended_buf));
if (!frame->extended_buf) {
frame->nb_extended_buf = 0;
ret = AVERROR(ENOMEM);
@@ -479,6 +474,7 @@ static int join_request_frame(AVFilterLink *outlink)
frame->nb_samples = nb_samples;
frame->channel_layout = outlink->channel_layout;
+ av_frame_set_channels(frame, outlink->channels);
frame->sample_rate = outlink->sample_rate;
frame->format = outlink->format;
frame->pts = s->input_frames[0]->pts;
@@ -513,16 +509,13 @@ static const AVFilterPad avfilter_af_join_outputs[] = {
AVFilter ff_af_join = {
.name = "join",
.description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into "
- "multi-channel output"),
+ "multi-channel output."),
.priv_size = sizeof(JoinContext),
.priv_class = &join_class,
-
.init = join_init,
.uninit = join_uninit,
.query_formats = join_query_formats,
-
- .inputs = NULL,
- .outputs = avfilter_af_join_outputs,
-
- .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+ .inputs = NULL,
+ .outputs = avfilter_af_join_outputs,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
};
diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c
new file mode 100644
index 0000000000..2057e6d0ef
--- /dev/null
+++ b/libavfilter/af_ladspa.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (c) 2013 Paul B Mahol
+ * Copyright (c) 2011 Mina Nagy Zaki
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * LADSPA wrapper
+ */
+
+#include <dlfcn.h>
+#include <ladspa.h>
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct LADSPAContext {
+ const AVClass *class;
+ char *dl_name;
+ char *plugin;
+ char *options;
+ void *dl_handle;
+
+ unsigned long nb_inputs;
+ unsigned long *ipmap; /* map input number to port number */
+
+ unsigned long nb_inputcontrols;
+ unsigned long *icmap; /* map input control number to port number */
+ LADSPA_Data *ictlv; /* input controls values */
+
+ unsigned long nb_outputs;
+ unsigned long *opmap; /* map output number to port number */
+
+ unsigned long nb_outputcontrols;
+ unsigned long *ocmap; /* map output control number to port number */
+ LADSPA_Data *octlv; /* output controls values */
+
+ const LADSPA_Descriptor *desc;
+ int *ctl_needs_value;
+ int nb_handles;
+ LADSPA_Handle *handles;
+
+ int sample_rate;
+ int nb_samples;
+ int64_t pts;
+ int64_t duration;
+} LADSPAContext;
+
+#define OFFSET(x) offsetof(LADSPAContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption ladspa_options[] = {
+ { "file", "set library name or full path", OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "f", "set library name or full path", OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "plugin", "set plugin name", OFFSET(plugin), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "p", "set plugin name", OFFSET(plugin), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "controls", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "c", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS },
+ { "s", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS },
+ { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
+ { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
+ { "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS },
+ { "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(ladspa);
+
+static void print_ctl_info(AVFilterContext *ctx, int level,
+ LADSPAContext *s, int ctl, unsigned long *map,
+ LADSPA_Data *values, int print)
+{
+ const LADSPA_PortRangeHint *h = s->desc->PortRangeHints + map[ctl];
+
+ av_log(ctx, level, "c%i: %s [", ctl, s->desc->PortNames[map[ctl]]);
+
+ if (LADSPA_IS_HINT_TOGGLED(h->HintDescriptor)) {
+ av_log(ctx, level, "toggled (1 or 0)");
+
+ if (LADSPA_IS_HINT_HAS_DEFAULT(h->HintDescriptor))
+ av_log(ctx, level, " (default %i)", (int)values[ctl]);
+ } else {
+ if (LADSPA_IS_HINT_INTEGER(h->HintDescriptor)) {
+ av_log(ctx, level, "<int>");
+
+ if (LADSPA_IS_HINT_BOUNDED_BELOW(h->HintDescriptor))
+ av_log(ctx, level, ", min: %i", (int)h->LowerBound);
+
+ if (LADSPA_IS_HINT_BOUNDED_ABOVE(h->HintDescriptor))
+ av_log(ctx, level, ", max: %i", (int)h->UpperBound);
+
+ if (print)
+ av_log(ctx, level, " (value %d)", (int)values[ctl]);
+ else if (LADSPA_IS_HINT_HAS_DEFAULT(h->HintDescriptor))
+ av_log(ctx, level, " (default %d)", (int)values[ctl]);
+ } else {
+ av_log(ctx, level, "<float>");
+
+ if (LADSPA_IS_HINT_BOUNDED_BELOW(h->HintDescriptor))
+ av_log(ctx, level, ", min: %f", h->LowerBound);
+
+ if (LADSPA_IS_HINT_BOUNDED_ABOVE(h->HintDescriptor))
+ av_log(ctx, level, ", max: %f", h->UpperBound);
+
+ if (print)
+ av_log(ctx, level, " (value %f)", values[ctl]);
+ else if (LADSPA_IS_HINT_HAS_DEFAULT(h->HintDescriptor))
+ av_log(ctx, level, " (default %f)", values[ctl]);
+ }
+
+ if (LADSPA_IS_HINT_SAMPLE_RATE(h->HintDescriptor))
+ av_log(ctx, level, ", multiple of sample rate");
+
+ if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor))
+ av_log(ctx, level, ", logarithmic scale");
+ }
+
+ av_log(ctx, level, "]\n");
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ LADSPAContext *s = ctx->priv;
+ AVFrame *out;
+ int i, h;
+
+ if (!s->nb_outputs ||
+ (av_frame_is_writable(in) && s->nb_inputs == s->nb_outputs &&
+ !(s->desc->Properties & LADSPA_PROPERTY_INPLACE_BROKEN))) {
+ out = in;
+ } else {
+ out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ for (h = 0; h < s->nb_handles; h++) {
+ for (i = 0; i < s->nb_inputs; i++) {
+ s->desc->connect_port(s->handles[h], s->ipmap[i],
+ (LADSPA_Data*)in->extended_data[i]);
+ }
+
+ for (i = 0; i < s->nb_outputs; i++) {
+ s->desc->connect_port(s->handles[h], s->opmap[i],
+ (LADSPA_Data*)out->extended_data[i]);
+ }
+
+ s->desc->run(s->handles[h], in->nb_samples);
+ }
+
+ for (i = 0; i < s->nb_outputcontrols; i++)
+ print_ctl_info(ctx, AV_LOG_VERBOSE, s, i, s->ocmap, s->octlv, 1);
+
+ if (out != in)
+ av_frame_free(&in);
+
+ return ff_filter_frame(ctx->outputs[0], out);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ LADSPAContext *s = ctx->priv;
+ AVFrame *out;
+ int64_t t;
+ int i;
+
+ if (ctx->nb_inputs)
+ return ff_request_frame(ctx->inputs[0]);
+
+ t = av_rescale(s->pts, AV_TIME_BASE, s->sample_rate);
+ if (s->duration >= 0 && t >= s->duration)
+ return AVERROR_EOF;
+
+ out = ff_get_audio_buffer(outlink, s->nb_samples);
+ if (!out)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->nb_outputs; i++)
+ s->desc->connect_port(s->handles[0], s->opmap[i],
+ (LADSPA_Data*)out->extended_data[i]);
+
+ s->desc->run(s->handles[0], s->nb_samples);
+
+ for (i = 0; i < s->nb_outputcontrols; i++)
+ print_ctl_info(ctx, AV_LOG_INFO, s, i, s->ocmap, s->octlv, 1);
+
+ out->sample_rate = s->sample_rate;
+ out->pts = s->pts;
+ s->pts += s->nb_samples;
+
+ return ff_filter_frame(outlink, out);
+}
+
+static void set_default_ctl_value(LADSPAContext *s, int ctl,
+ unsigned long *map, LADSPA_Data *values)
+{
+ const LADSPA_PortRangeHint *h = s->desc->PortRangeHints + map[ctl];
+ const LADSPA_Data lower = h->LowerBound;
+ const LADSPA_Data upper = h->UpperBound;
+
+ if (LADSPA_IS_HINT_DEFAULT_MINIMUM(h->HintDescriptor)) {
+ values[ctl] = lower;
+ } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(h->HintDescriptor)) {
+ values[ctl] = upper;
+ } else if (LADSPA_IS_HINT_DEFAULT_0(h->HintDescriptor)) {
+ values[ctl] = 0.0;
+ } else if (LADSPA_IS_HINT_DEFAULT_1(h->HintDescriptor)) {
+ values[ctl] = 1.0;
+ } else if (LADSPA_IS_HINT_DEFAULT_100(h->HintDescriptor)) {
+ values[ctl] = 100.0;
+ } else if (LADSPA_IS_HINT_DEFAULT_440(h->HintDescriptor)) {
+ values[ctl] = 440.0;
+ } else if (LADSPA_IS_HINT_DEFAULT_LOW(h->HintDescriptor)) {
+ if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor))
+ values[ctl] = exp(log(lower) * 0.75 + log(upper) * 0.25);
+ else
+ values[ctl] = lower * 0.75 + upper * 0.25;
+ } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(h->HintDescriptor)) {
+ if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor))
+ values[ctl] = exp(log(lower) * 0.5 + log(upper) * 0.5);
+ else
+ values[ctl] = lower * 0.5 + upper * 0.5;
+ } else if (LADSPA_IS_HINT_DEFAULT_HIGH(h->HintDescriptor)) {
+ if (LADSPA_IS_HINT_LOGARITHMIC(h->HintDescriptor))
+ values[ctl] = exp(log(lower) * 0.25 + log(upper) * 0.75);
+ else
+ values[ctl] = lower * 0.25 + upper * 0.75;
+ }
+}
+
+static int connect_ports(AVFilterContext *ctx, AVFilterLink *link)
+{
+ LADSPAContext *s = ctx->priv;
+ int i, j;
+
+ s->nb_handles = s->nb_inputs == 1 && s->nb_outputs == 1 ? link->channels : 1;
+ s->handles = av_calloc(s->nb_handles, sizeof(*s->handles));
+ if (!s->handles)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->nb_handles; i++) {
+ s->handles[i] = s->desc->instantiate(s->desc, link->sample_rate);
+ if (!s->handles[i]) {
+ av_log(ctx, AV_LOG_ERROR, "Could not instantiate plugin.\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ // Connect the input control ports
+ for (j = 0; j < s->nb_inputcontrols; j++)
+ s->desc->connect_port(s->handles[i], s->icmap[j], s->ictlv + j);
+
+ // Connect the output control ports
+ for (j = 0; j < s->nb_outputcontrols; j++)
+ s->desc->connect_port(s->handles[i], s->ocmap[j], &s->octlv[j]);
+
+ if (s->desc->activate)
+ s->desc->activate(s->handles[i]);
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "handles: %d\n", s->nb_handles);
+
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+
+ return connect_ports(ctx, inlink);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ int ret;
+
+ if (ctx->nb_inputs) {
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ outlink->format = inlink->format;
+ outlink->sample_rate = inlink->sample_rate;
+
+ ret = 0;
+ } else {
+ LADSPAContext *s = ctx->priv;
+
+ outlink->sample_rate = s->sample_rate;
+ outlink->time_base = (AVRational){1, s->sample_rate};
+
+ ret = connect_ports(ctx, outlink);
+ }
+
+ return ret;
+}
+
+static void count_ports(const LADSPA_Descriptor *desc,
+ unsigned long *nb_inputs, unsigned long *nb_outputs)
+{
+ LADSPA_PortDescriptor pd;
+ int i;
+
+ for (i = 0; i < desc->PortCount; i++) {
+ pd = desc->PortDescriptors[i];
+
+ if (LADSPA_IS_PORT_AUDIO(pd)) {
+ if (LADSPA_IS_PORT_INPUT(pd)) {
+ (*nb_inputs)++;
+ } else if (LADSPA_IS_PORT_OUTPUT(pd)) {
+ (*nb_outputs)++;
+ }
+ }
+ }
+}
+
+static void *try_load(const char *dir, const char *soname)
+{
+ char *path = av_asprintf("%s/%s.so", dir, soname);
+ void *ret = NULL;
+
+ if (path) {
+ ret = dlopen(path, RTLD_LOCAL|RTLD_NOW);
+ av_free(path);
+ }
+
+ return ret;
+}
+
+static int set_control(AVFilterContext *ctx, unsigned long port, LADSPA_Data value)
+{
+ LADSPAContext *s = ctx->priv;
+ const char *label = s->desc->Label;
+ LADSPA_PortRangeHint *h = (LADSPA_PortRangeHint *)s->desc->PortRangeHints +
+ s->icmap[port];
+
+ if (port >= s->nb_inputcontrols) {
+ av_log(ctx, AV_LOG_ERROR, "Control c%ld is out of range [0 - %lu].\n",
+ port, s->nb_inputcontrols);
+ return AVERROR(EINVAL);
+ }
+
+ if (LADSPA_IS_HINT_BOUNDED_BELOW(h->HintDescriptor) &&
+ value < h->LowerBound) {
+ av_log(ctx, AV_LOG_ERROR,
+ "%s: input control c%ld is below lower boundary of %0.4f.\n",
+ label, port, h->LowerBound);
+ return AVERROR(EINVAL);
+ }
+
+ if (LADSPA_IS_HINT_BOUNDED_ABOVE(h->HintDescriptor) &&
+ value > h->UpperBound) {
+ av_log(ctx, AV_LOG_ERROR,
+ "%s: input control c%ld is above upper boundary of %0.4f.\n",
+ label, port, h->UpperBound);
+ return AVERROR(EINVAL);
+ }
+
+ s->ictlv[port] = value;
+
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ LADSPAContext *s = ctx->priv;
+ LADSPA_Descriptor_Function descriptor_fn;
+ const LADSPA_Descriptor *desc;
+ LADSPA_PortDescriptor pd;
+ AVFilterPad pad = { NULL };
+ char *p, *arg, *saveptr = NULL;
+ unsigned long nb_ports;
+ int i;
+
+ if (!s->dl_name) {
+ av_log(ctx, AV_LOG_ERROR, "No plugin name provided\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (s->dl_name[0] == '/' || s->dl_name[0] == '.') {
+ // argument is a path
+ s->dl_handle = dlopen(s->dl_name, RTLD_LOCAL|RTLD_NOW);
+ } else {
+ // argument is a shared object name
+ char *paths = av_strdup(getenv("LADSPA_PATH"));
+ const char *separator = ":";
+
+ if (paths) {
+ p = paths;
+ while ((arg = av_strtok(p, separator, &saveptr)) && !s->dl_handle) {
+ s->dl_handle = try_load(arg, s->dl_name);
+ p = NULL;
+ }
+ }
+
+ av_free(paths);
+ if (!s->dl_handle && (paths = av_asprintf("%s/.ladspa/lib", getenv("HOME")))) {
+ s->dl_handle = try_load(paths, s->dl_name);
+ av_free(paths);
+ }
+
+ if (!s->dl_handle)
+ s->dl_handle = try_load("/usr/local/lib/ladspa", s->dl_name);
+
+ if (!s->dl_handle)
+ s->dl_handle = try_load("/usr/lib/ladspa", s->dl_name);
+ }
+ if (!s->dl_handle) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to load '%s'\n", s->dl_name);
+ return AVERROR(EINVAL);
+ }
+
+ descriptor_fn = dlsym(s->dl_handle, "ladspa_descriptor");
+ if (!descriptor_fn) {
+ av_log(ctx, AV_LOG_ERROR, "Could not find ladspa_descriptor: %s\n", dlerror());
+ return AVERROR(EINVAL);
+ }
+
+ // Find the requested plugin, or list plugins
+ if (!s->plugin) {
+ av_log(ctx, AV_LOG_INFO, "The '%s' library contains the following plugins:\n", s->dl_name);
+ av_log(ctx, AV_LOG_INFO, "I = Input Channels\n");
+ av_log(ctx, AV_LOG_INFO, "O = Output Channels\n");
+ av_log(ctx, AV_LOG_INFO, "I:O %-25s %s\n", "Plugin", "Description");
+ av_log(ctx, AV_LOG_INFO, "\n");
+ for (i = 0; desc = descriptor_fn(i); i++) {
+ unsigned long inputs = 0, outputs = 0;
+
+ count_ports(desc, &inputs, &outputs);
+ av_log(ctx, AV_LOG_INFO, "%lu:%lu %-25s %s\n", inputs, outputs, desc->Label,
+ (char *)av_x_if_null(desc->Name, "?"));
+ av_log(ctx, AV_LOG_VERBOSE, "Maker: %s\n",
+ (char *)av_x_if_null(desc->Maker, "?"));
+ av_log(ctx, AV_LOG_VERBOSE, "Copyright: %s\n",
+ (char *)av_x_if_null(desc->Copyright, "?"));
+ }
+ return AVERROR_EXIT;
+ } else {
+ for (i = 0;; i++) {
+ desc = descriptor_fn(i);
+ if (!desc) {
+ av_log(ctx, AV_LOG_ERROR, "Could not find plugin: %s\n", s->plugin);
+ return AVERROR(EINVAL);
+ }
+
+ if (desc->Label && !strcmp(desc->Label, s->plugin))
+ break;
+ }
+ }
+
+ s->desc = desc;
+ nb_ports = desc->PortCount;
+
+ s->ipmap = av_calloc(nb_ports, sizeof(*s->ipmap));
+ s->opmap = av_calloc(nb_ports, sizeof(*s->opmap));
+ s->icmap = av_calloc(nb_ports, sizeof(*s->icmap));
+ s->ocmap = av_calloc(nb_ports, sizeof(*s->ocmap));
+ s->ictlv = av_calloc(nb_ports, sizeof(*s->ictlv));
+ s->octlv = av_calloc(nb_ports, sizeof(*s->octlv));
+ s->ctl_needs_value = av_calloc(nb_ports, sizeof(*s->ctl_needs_value));
+ if (!s->ipmap || !s->opmap || !s->icmap ||
+ !s->ocmap || !s->ictlv || !s->octlv || !s->ctl_needs_value)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < nb_ports; i++) {
+ pd = desc->PortDescriptors[i];
+
+ if (LADSPA_IS_PORT_AUDIO(pd)) {
+ if (LADSPA_IS_PORT_INPUT(pd)) {
+ s->ipmap[s->nb_inputs] = i;
+ s->nb_inputs++;
+ } else if (LADSPA_IS_PORT_OUTPUT(pd)) {
+ s->opmap[s->nb_outputs] = i;
+ s->nb_outputs++;
+ }
+ } else if (LADSPA_IS_PORT_CONTROL(pd)) {
+ if (LADSPA_IS_PORT_INPUT(pd)) {
+ s->icmap[s->nb_inputcontrols] = i;
+
+ if (LADSPA_IS_HINT_HAS_DEFAULT(desc->PortRangeHints[i].HintDescriptor))
+ set_default_ctl_value(s, s->nb_inputcontrols, s->icmap, s->ictlv);
+ else
+ s->ctl_needs_value[s->nb_inputcontrols] = 1;
+
+ s->nb_inputcontrols++;
+ } else if (LADSPA_IS_PORT_OUTPUT(pd)) {
+ s->ocmap[s->nb_outputcontrols] = i;
+ s->nb_outputcontrols++;
+ }
+ }
+ }
+
+ // List Control Ports if "help" is specified
+ if (s->options && !strcmp(s->options, "help")) {
+ if (!s->nb_inputcontrols) {
+ av_log(ctx, AV_LOG_INFO,
+ "The '%s' plugin does not have any input controls.\n",
+ desc->Label);
+ } else {
+ av_log(ctx, AV_LOG_INFO,
+ "The '%s' plugin has the following input controls:\n",
+ desc->Label);
+ for (i = 0; i < s->nb_inputcontrols; i++)
+ print_ctl_info(ctx, AV_LOG_INFO, s, i, s->icmap, s->ictlv, 0);
+ }
+ return AVERROR_EXIT;
+ }
+
+ // Parse control parameters
+ p = s->options;
+ while (s->options) {
+ LADSPA_Data val;
+ int ret;
+
+ if (!(arg = av_strtok(p, "|", &saveptr)))
+ break;
+ p = NULL;
+
+ if (sscanf(arg, "c%d=%f", &i, &val) != 2) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid syntax.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((ret = set_control(ctx, i, val)) < 0)
+ return ret;
+ s->ctl_needs_value[i] = 0;
+ }
+
+ // Check if any controls are not set
+ for (i = 0; i < s->nb_inputcontrols; i++) {
+ if (s->ctl_needs_value[i]) {
+ av_log(ctx, AV_LOG_ERROR, "Control c%d must be set.\n", i);
+ print_ctl_info(ctx, AV_LOG_ERROR, s, i, s->icmap, s->ictlv, 0);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ pad.type = AVMEDIA_TYPE_AUDIO;
+
+ if (s->nb_inputs) {
+ pad.name = av_asprintf("in0:%s%lu", desc->Label, s->nb_inputs);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+
+ pad.filter_frame = filter_frame;
+ pad.config_props = config_input;
+ if (ff_insert_inpad(ctx, ctx->nb_inputs, &pad) < 0) {
+ av_freep(&pad.name);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "ports: %lu\n", nb_ports);
+ av_log(ctx, AV_LOG_DEBUG, "inputs: %lu outputs: %lu\n",
+ s->nb_inputs, s->nb_outputs);
+ av_log(ctx, AV_LOG_DEBUG, "input controls: %lu output controls: %lu\n",
+ s->nb_inputcontrols, s->nb_outputcontrols);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ LADSPAContext *s = ctx->priv;
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE };
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_set_common_formats(ctx, formats);
+
+ if (s->nb_inputs) {
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+
+ ff_set_common_samplerates(ctx, formats);
+ } else {
+ int sample_rates[] = { s->sample_rate, -1 };
+
+ ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates));
+ }
+
+ if (s->nb_inputs == 1 && s->nb_outputs == 1) {
+ // We will instantiate multiple LADSPA_Handle, one over each channel
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+
+ ff_set_common_channel_layouts(ctx, layouts);
+ } else {
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ if (s->nb_inputs >= 1) {
+ AVFilterLink *inlink = ctx->inputs[0];
+ int64_t inlayout = FF_COUNT2LAYOUT(s->nb_inputs);
+
+ layouts = NULL;
+ ff_add_channel_layout(&layouts, inlayout);
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+
+ if (!s->nb_outputs)
+ ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
+ }
+
+ if (s->nb_outputs >= 1) {
+ int64_t outlayout = FF_COUNT2LAYOUT(s->nb_outputs);
+
+ layouts = NULL;
+ ff_add_channel_layout(&layouts, outlayout);
+ ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
+ }
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ LADSPAContext *s = ctx->priv;
+ int i;
+
+ for (i = 0; i < s->nb_handles; i++) {
+ if (s->desc->deactivate)
+ s->desc->deactivate(s->handles[i]);
+ if (s->desc->cleanup)
+ s->desc->cleanup(s->handles[i]);
+ }
+
+ if (s->dl_handle)
+ dlclose(s->dl_handle);
+
+ av_freep(&s->ipmap);
+ av_freep(&s->opmap);
+ av_freep(&s->icmap);
+ av_freep(&s->ocmap);
+ av_freep(&s->ictlv);
+ av_freep(&s->octlv);
+ av_freep(&s->handles);
+ av_freep(&s->ctl_needs_value);
+
+ if (ctx->nb_inputs)
+ av_freep(&ctx->input_pads[0].name);
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ LADSPA_Data value;
+ unsigned long port;
+
+ if (sscanf(cmd, "c%ld", &port) + sscanf(args, "%f", &value) != 2)
+ return AVERROR(EINVAL);
+
+ return set_control(ctx, port, value);
+}
+
+static const AVFilterPad ladspa_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_ladspa = {
+ .name = "ladspa",
+ .description = NULL_IF_CONFIG_SMALL("Apply LADSPA effect."),
+ .priv_size = sizeof(LADSPAContext),
+ .priv_class = &ladspa_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .process_command = process_command,
+ .inputs = 0,
+ .outputs = ladspa_outputs,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c
new file mode 100644
index 0000000000..4ba77a7366
--- /dev/null
+++ b/libavfilter/af_pan.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2002 Anders Johansson <ajh@atri.curtin.edu.au>
+ * Copyright (c) 2011 ClĂ©ment BÅ“sch <u pkh me>
+ * Copyright (c) 2011 Nicolas George <nicolas.george@normalesup.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Audio panning filter (channels mixing)
+ * Original code written by Anders Johansson for MPlayer,
+ * reimplemented for FFmpeg.
+ */
+
+#include <stdio.h>
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libswresample/swresample.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+#define MAX_CHANNELS 63
+
+typedef struct PanContext {
+ const AVClass *class;
+ char *args;
+ int64_t out_channel_layout;
+ double gain[MAX_CHANNELS][MAX_CHANNELS];
+ int64_t need_renorm;
+ int need_renumber;
+ int nb_output_channels;
+
+ int pure_gains;
+ /* channel mapping specific */
+ int channel_map[MAX_CHANNELS];
+ struct SwrContext *swr;
+} PanContext;
+
+static void skip_spaces(char **arg)
+{
+ int len = 0;
+
+ sscanf(*arg, " %n", &len);
+ *arg += len;
+}
+
+static int parse_channel_name(char **arg, int *rchannel, int *rnamed)
+{
+ char buf[8];
+ int len, i, channel_id = 0;
+ int64_t layout, layout0;
+
+ skip_spaces(arg);
+ /* try to parse a channel name, e.g. "FL" */
+ if (sscanf(*arg, "%7[A-Z]%n", buf, &len)) {
+ layout0 = layout = av_get_channel_layout(buf);
+ /* channel_id <- first set bit in layout */
+ for (i = 32; i > 0; i >>= 1) {
+ if (layout >= (int64_t)1 << i) {
+ channel_id += i;
+ layout >>= i;
+ }
+ }
+ /* reject layouts that are not a single channel */
+ if (channel_id >= MAX_CHANNELS || layout0 != (int64_t)1 << channel_id)
+ return AVERROR(EINVAL);
+ *rchannel = channel_id;
+ *rnamed = 1;
+ *arg += len;
+ return 0;
+ }
+ /* try to parse a channel number, e.g. "c2" */
+ if (sscanf(*arg, "c%d%n", &channel_id, &len) &&
+ channel_id >= 0 && channel_id < MAX_CHANNELS) {
+ *rchannel = channel_id;
+ *rnamed = 0;
+ *arg += len;
+ return 0;
+ }
+ return AVERROR(EINVAL);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ PanContext *const pan = ctx->priv;
+ char *arg, *arg0, *tokenizer, *args = av_strdup(pan->args);
+ int out_ch_id, in_ch_id, len, named, ret;
+ int nb_in_channels[2] = { 0, 0 }; // number of unnamed and named input channels
+ double gain;
+
+ if (!pan->args) {
+ av_log(ctx, AV_LOG_ERROR,
+ "pan filter needs a channel layout and a set "
+ "of channels definitions as parameter\n");
+ return AVERROR(EINVAL);
+ }
+ if (!args)
+ return AVERROR(ENOMEM);
+ arg = av_strtok(args, "|", &tokenizer);
+ ret = ff_parse_channel_layout(&pan->out_channel_layout,
+ &pan->nb_output_channels, arg, ctx);
+ if (ret < 0)
+ goto fail;
+
+ /* parse channel specifications */
+ while ((arg = arg0 = av_strtok(NULL, "|", &tokenizer))) {
+ /* channel name */
+ if (parse_channel_name(&arg, &out_ch_id, &named)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Expected out channel name, got \"%.8s\"\n", arg);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ if (named) {
+ if (!((pan->out_channel_layout >> out_ch_id) & 1)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Channel \"%.8s\" does not exist in the chosen layout\n", arg0);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ /* get the channel number in the output channel layout:
+ * out_channel_layout & ((1 << out_ch_id) - 1) are all the
+ * channels that come before out_ch_id,
+ * so their count is the index of out_ch_id */
+ out_ch_id = av_get_channel_layout_nb_channels(pan->out_channel_layout & (((int64_t)1 << out_ch_id) - 1));
+ }
+ if (out_ch_id < 0 || out_ch_id >= pan->nb_output_channels) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid out channel name \"%.8s\"\n", arg0);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ skip_spaces(&arg);
+ if (*arg == '=') {
+ arg++;
+ } else if (*arg == '<') {
+ pan->need_renorm |= (int64_t)1 << out_ch_id;
+ arg++;
+ } else {
+ av_log(ctx, AV_LOG_ERROR,
+ "Syntax error after channel name in \"%.8s\"\n", arg0);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ /* gains */
+ while (1) {
+ gain = 1;
+ if (sscanf(arg, "%lf%n *%n", &gain, &len, &len))
+ arg += len;
+ if (parse_channel_name(&arg, &in_ch_id, &named)){
+ av_log(ctx, AV_LOG_ERROR,
+ "Expected in channel name, got \"%.8s\"\n", arg);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ nb_in_channels[named]++;
+ if (nb_in_channels[!named]) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Can not mix named and numbered channels\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ pan->gain[out_ch_id][in_ch_id] = gain;
+ skip_spaces(&arg);
+ if (!*arg)
+ break;
+ if (*arg != '+') {
+ av_log(ctx, AV_LOG_ERROR, "Syntax error near \"%.8s\"\n", arg);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ arg++;
+ }
+ }
+ pan->need_renumber = !!nb_in_channels[1];
+
+ ret = 0;
+fail:
+ av_free(args);
+ return ret;
+}
+
+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 int query_formats(AVFilterContext *ctx)
+{
+ PanContext *pan = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts;
+
+ pan->pure_gains = are_gains_pure(pan);
+ /* libswr supports any sample and packing formats */
+ ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO));
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_set_common_samplerates(ctx, formats);
+
+ // inlink supports any channel layout
+ layouts = ff_all_channel_counts();
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+
+ // outlink supports only requested output channel layout
+ layouts = NULL;
+ ff_add_channel_layout(&layouts,
+ pan->out_channel_layout ? pan->out_channel_layout :
+ FF_COUNT2LAYOUT(pan->nb_output_channels));
+ ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
+ return 0;
+}
+
+static int config_props(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->dst;
+ PanContext *pan = ctx->priv;
+ char buf[1024], *cur;
+ int i, j, k, r;
+ double t;
+
+ if (pan->need_renumber) {
+ // input channels were given by their name: renumber them
+ for (i = j = 0; i < MAX_CHANNELS; i++) {
+ if ((link->channel_layout >> i) & 1) {
+ for (k = 0; k < pan->nb_output_channels; k++)
+ pan->gain[k][j] = pan->gain[k][i];
+ j++;
+ }
+ }
+ }
+
+ // sanity check; can't be done in query_formats since the inlink
+ // channel layout is unknown at that time
+ if (link->channels > MAX_CHANNELS ||
+ pan->nb_output_channels > MAX_CHANNELS) {
+ av_log(ctx, AV_LOG_ERROR,
+ "af_pan support a maximum of %d channels. "
+ "Feel free to ask for a higher limit.\n", MAX_CHANNELS);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ // init libswresample context
+ pan->swr = swr_alloc_set_opts(pan->swr,
+ pan->out_channel_layout, link->format, link->sample_rate,
+ link->channel_layout, link->format, link->sample_rate,
+ 0, ctx);
+ if (!pan->swr)
+ return AVERROR(ENOMEM);
+ if (!link->channel_layout) {
+ if (av_opt_set_int(pan->swr, "ich", link->channels, 0) < 0)
+ return AVERROR(EINVAL);
+ }
+ if (!pan->out_channel_layout) {
+ if (av_opt_set_int(pan->swr, "och", pan->nb_output_channels, 0) < 0)
+ return AVERROR(EINVAL);
+ }
+
+ // gains are pure, init the channel mapping
+ if (pan->pure_gains) {
+
+ // get channel map from the pure gains
+ for (i = 0; i < pan->nb_output_channels; i++) {
+ int ch_id = -1;
+ for (j = 0; j < link->channels; j++) {
+ if (pan->gain[i][j]) {
+ ch_id = j;
+ break;
+ }
+ }
+ pan->channel_map[i] = ch_id;
+ }
+
+ av_opt_set_int(pan->swr, "icl", pan->out_channel_layout, 0);
+ av_opt_set_int(pan->swr, "uch", pan->nb_output_channels, 0);
+ swr_set_channel_mapping(pan->swr, pan->channel_map);
+ } else {
+ // renormalize
+ for (i = 0; i < pan->nb_output_channels; i++) {
+ if (!((pan->need_renorm >> i) & 1))
+ continue;
+ t = 0;
+ for (j = 0; j < link->channels; j++)
+ t += pan->gain[i][j];
+ if (t > -1E-5 && t < 1E-5) {
+ // t is almost 0 but not exactly, this is probably a mistake
+ if (t)
+ av_log(ctx, AV_LOG_WARNING,
+ "Degenerate coefficients while renormalizing\n");
+ continue;
+ }
+ for (j = 0; j < link->channels; j++)
+ pan->gain[i][j] /= t;
+ }
+ av_opt_set_int(pan->swr, "icl", link->channel_layout, 0);
+ av_opt_set_int(pan->swr, "ocl", pan->out_channel_layout, 0);
+ swr_set_matrix(pan->swr, pan->gain[0], pan->gain[1] - pan->gain[0]);
+ }
+
+ r = swr_init(pan->swr);
+ if (r < 0)
+ return r;
+
+ // summary
+ for (i = 0; i < pan->nb_output_channels; i++) {
+ cur = buf;
+ for (j = 0; j < link->channels; j++) {
+ r = snprintf(cur, buf + sizeof(buf) - cur, "%s%.3g i%d",
+ j ? " + " : "", pan->gain[i][j], j);
+ cur += FFMIN(buf + sizeof(buf) - cur, r);
+ }
+ av_log(ctx, AV_LOG_VERBOSE, "o%d = %s\n", i, buf);
+ }
+ // add channel mapping summary if possible
+ if (pan->pure_gains) {
+ av_log(ctx, AV_LOG_INFO, "Pure channel mapping detected:");
+ for (i = 0; i < pan->nb_output_channels; i++)
+ if (pan->channel_map[i] < 0)
+ av_log(ctx, AV_LOG_INFO, " M");
+ else
+ av_log(ctx, AV_LOG_INFO, " %d", pan->channel_map[i]);
+ av_log(ctx, AV_LOG_INFO, "\n");
+ return 0;
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ int ret;
+ int n = insamples->nb_samples;
+ AVFilterLink *const outlink = inlink->dst->outputs[0];
+ AVFrame *outsamples = ff_get_audio_buffer(outlink, n);
+ PanContext *pan = inlink->dst->priv;
+
+ if (!outsamples)
+ return AVERROR(ENOMEM);
+ swr_convert(pan->swr, outsamples->extended_data, n,
+ (void *)insamples->extended_data, n);
+ av_frame_copy_props(outsamples, insamples);
+ outsamples->channel_layout = outlink->channel_layout;
+ av_frame_set_channels(outsamples, outlink->channels);
+
+ ret = ff_filter_frame(outlink, outsamples);
+ av_frame_free(&insamples);
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ PanContext *pan = ctx->priv;
+ swr_free(&pan->swr);
+}
+
+#define OFFSET(x) offsetof(PanContext, x)
+
+static const AVOption pan_options[] = {
+ { "args", NULL, OFFSET(args), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(pan);
+
+static const AVFilterPad pan_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_props,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad pan_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_pan = {
+ .name = "pan",
+ .description = NULL_IF_CONFIG_SMALL("Remix channels with coefficients (panning)."),
+ .priv_size = sizeof(PanContext),
+ .priv_class = &pan_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = pan_inputs,
+ .outputs = pan_outputs,
+};
diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c
new file mode 100644
index 0000000000..c41985787d
--- /dev/null
+++ b/libavfilter/af_replaygain.c
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 1998 - 2009 Conifer Software
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * ReplayGain scanner
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#define HISTOGRAM_SLOTS 12000
+#define BUTTER_ORDER 2
+#define YULE_ORDER 10
+
+typedef struct ReplayGainFreqInfo {
+ int sample_rate;
+ double BYule[YULE_ORDER + 1];
+ double AYule[YULE_ORDER + 1];
+ double BButter[BUTTER_ORDER + 1];
+ double AButter[BUTTER_ORDER + 1];
+} ReplayGainFreqInfo;
+
+static const ReplayGainFreqInfo freqinfos[] =
+{
+ {
+ 192000,
+ { 0.01184742123123, -0.04631092400086, 0.06584226961238,
+ -0.02165588522478, -0.05656260778952, 0.08607493592760,
+ -0.03375544339786, -0.04216579932754, 0.06416711490648,
+ -0.03444708260844, 0.00697275872241 },
+ { 1.00000000000000, -5.24727318348167, 10.60821585192244,
+ -8.74127665810413, -1.33906071371683, 8.07972882096606,
+ -5.46179918950847, 0.54318070652536, 0.87450969224280,
+ -0.34656083539754, 0.03034796843589 },
+ { 0.99653501465135, -1.99307002930271, 0.99653501465135 },
+ { 1.00000000000000, -1.99305802314321, 0.99308203546221 },
+ },
+ {
+ 176400,
+ { 0.00268568524529, -0.00852379426080, 0.00852704191347,
+ 0.00146116310295, -0.00950855828762, 0.00625449515499,
+ 0.00116183868722, -0.00362461417136, 0.00203961000134,
+ -0.00050664587933, 0.00004327455427 },
+ { 1.00000000000000, -5.57512782763045, 12.44291056065794,
+ -12.87462799681221, 3.08554846961576, 6.62493459880692,
+ -7.07662766313248, 2.51175542736441, 0.06731510802735,
+ -0.24567753819213, 0.03961404162376 },
+ { 0.99622916581118, -1.99245833162236, 0.99622916581118 },
+ { 1.00000000000000, -1.99244411238133, 0.99247255086339 },
+ },
+ {
+ 144000,
+ { 0.00639682359450, -0.02556437970955, 0.04230854400938,
+ -0.03722462201267, 0.01718514827295, 0.00610592243009,
+ -0.03065965747365, 0.04345745003539, -0.03298592681309,
+ 0.01320937236809, -0.00220304127757 },
+ { 1.00000000000000, -6.14814623523425, 15.80002457141566,
+ -20.78487587686937, 11.98848552310315, 3.36462015062606,
+ -10.22419868359470, 6.65599702146473, -1.67141861110485,
+ -0.05417956536718, 0.07374767867406 },
+ { 0.99538268958706, -1.99076537917413, 0.99538268958706 },
+ { 1.00000000000000, -1.99074405950505, 0.99078669884321 },
+ },
+ {
+ 128000,
+ { 0.00553120584305, -0.02112620545016, 0.03549076243117,
+ -0.03362498312306, 0.01425867248183, 0.01344686928787,
+ -0.03392770787836, 0.03464136459530, -0.02039116051549,
+ 0.00667420794705, -0.00093763762995 },
+ { 1.00000000000000, -6.14581710839925, 16.04785903675838,
+ -22.19089131407749, 15.24756471580286, -0.52001440400238,
+ -8.00488641699940, 6.60916094768855, -2.37856022810923,
+ 0.33106947986101, 0.00459820832036 },
+ { 0.99480702681278, -1.98961405362557, 0.99480702681278 },
+ { 1.00000000000000, -1.98958708647324, 0.98964102077790 },
+ },
+ {
+ 112000,
+ { 0.00528778718259, -0.01893240907245, 0.03185982561867,
+ -0.02926260297838, 0.00715743034072, 0.01985743355827,
+ -0.03222614850941, 0.02565681978192, -0.01210662313473,
+ 0.00325436284541, -0.00044173593001 },
+ { 1.00000000000000, -6.24932108456288, 17.42344320538476,
+ -27.86819709054896, 26.79087344681326,-13.43711081485123,
+ -0.66023612948173, 6.03658091814935, -4.24926577030310,
+ 1.40829268709186, -0.19480852628112 },
+ { 0.99406737810867, -1.98813475621734, 0.99406737810867 },
+ { 1.00000000000000, -1.98809955990514, 0.98816995252954 },
+ },
+ {
+ 96000,
+ { 0.00588138296683, -0.01613559730421, 0.02184798954216,
+ -0.01742490405317, 0.00464635643780, 0.01117772513205,
+ -0.02123865824368, 0.01959354413350, -0.01079720643523,
+ 0.00352183686289, -0.00063124341421 },
+ { 1.00000000000000, -5.97808823642008, 16.21362507964068,
+ -25.72923730652599, 25.40470663139513,-14.66166287771134,
+ 2.81597484359752, 2.51447125969733, -2.23575306985286,
+ 0.75788151036791, -0.10078025199029 },
+ { 0.99308203517541, -1.98616407035082, 0.99308203517541 },
+ { 1.00000000000000, -1.98611621154089, 0.98621192916075 },
+ },
+ {
+ 88200,
+ { 0.02667482047416, -0.11377479336097, 0.23063167910965,
+ -0.30726477945593, 0.33188520686529, -0.33862680249063,
+ 0.31807161531340, -0.23730796929880, 0.12273894790371,
+ -0.03840017967282, 0.00549673387936 },
+ { 1.00000000000000, -6.31836451657302, 18.31351310801799,
+ -31.88210014815921, 36.53792146976740,-28.23393036467559,
+ 14.24725258227189, -4.04670980012854, 0.18865757280515,
+ 0.25420333563908, -0.06012333531065 },
+ { 0.99247255046129, -1.98494510092259, 0.99247255046129 },
+ { 1.00000000000000, -1.98488843762335, 0.98500176422183 },
+ },
+ {
+ 64000,
+ { 0.02613056568174, -0.08128786488109, 0.14937282347325,
+ -0.21695711675126, 0.25010286673402, -0.23162283619278,
+ 0.17424041833052, -0.10299599216680, 0.04258696481981,
+ -0.00977952936493, 0.00105325558889 },
+ { 1.00000000000000, -5.73625477092119, 16.15249794355035,
+ -29.68654912464508, 39.55706155674083,-39.82524556246253,
+ 30.50605345013009,-17.43051772821245, 7.05154573908017,
+ -1.80783839720514, 0.22127840210813 },
+ { 0.98964101933472, -1.97928203866944, 0.98964101933472 },
+ { 1.00000000000000, -1.97917472731009, 0.97938935002880 },
+ },
+ {
+ 56000,
+ { 0.03144914734085, -0.06151729206963, 0.08066788708145,
+ -0.09737939921516, 0.08943210803999, -0.06989984672010,
+ 0.04926972841044, -0.03161257848451, 0.01456837493506,
+ -0.00316015108496, 0.00132807215875 },
+ { 1.00000000000000, -4.87377313090032, 12.03922160140209,
+ -20.10151118381395, 25.10388534415171,-24.29065560815903,
+ 18.27158469090663,-10.45249552560593, 4.30319491872003,
+ -1.13716992070185, 0.14510733527035 },
+ { 0.98816995007392, -1.97633990014784, 0.98816995007392 },
+ { 1.00000000000000, -1.97619994516973, 0.97647985512594 },
+ },
+ {
+ 48000,
+ { 0.03857599435200, -0.02160367184185, -0.00123395316851,
+ -0.00009291677959, -0.01655260341619, 0.02161526843274,
+ -0.02074045215285, 0.00594298065125, 0.00306428023191,
+ 0.00012025322027, 0.00288463683916 },
+ { 1.00000000000000, -3.84664617118067, 7.81501653005538,
+ -11.34170355132042, 13.05504219327545,-12.28759895145294,
+ 9.48293806319790, -5.87257861775999, 2.75465861874613,
+ -0.86984376593551, 0.13919314567432 },
+ { 0.98621192462708, -1.97242384925416, 0.98621192462708 },
+ { 1.00000000000000, -1.97223372919527, 0.97261396931306 },
+ },
+ {
+ 44100,
+ { 0.05418656406430, -0.02911007808948, -0.00848709379851,
+ -0.00851165645469, -0.00834990904936, 0.02245293253339,
+ -0.02596338512915, 0.01624864962975, -0.00240879051584,
+ 0.00674613682247, -0.00187763777362 },
+ { 1.00000000000000, -3.47845948550071, 6.36317777566148,
+ -8.54751527471874, 9.47693607801280, -8.81498681370155,
+ 6.85401540936998, -4.39470996079559, 2.19611684890774,
+ -0.75104302451432, 0.13149317958808 },
+ { 0.98500175787242, -1.97000351574484, 0.98500175787242 },
+ { 1.00000000000000, -1.96977855582618, 0.97022847566350 },
+ },
+ {
+ 37800,
+ { 0.08717879977844, -0.01000374016172, -0.06265852122368,
+ -0.01119328800950, -0.00114279372960, 0.02081333954769,
+ -0.01603261863207, 0.01936763028546, 0.00760044736442,
+ -0.00303979112271, -0.00075088605788 },
+ { 1.00000000000000, -2.62816311472146, 3.53734535817992,
+ -3.81003448678921, 3.91291636730132, -3.53518605896288,
+ 2.71356866157873, -1.86723311846592, 1.12075382367659,
+ -0.48574086886890, 0.11330544663849 },
+ { 0.98252400815195, -1.96504801630391, 0.98252400815195 },
+ { 1.00000000000000, -1.96474258269041, 0.96535344991740 },
+ },
+ {
+ 32000,
+ { 0.15457299681924, -0.09331049056315, -0.06247880153653,
+ 0.02163541888798, -0.05588393329856, 0.04781476674921,
+ 0.00222312597743, 0.03174092540049, -0.01390589421898,
+ 0.00651420667831, -0.00881362733839 },
+ { 1.00000000000000, -2.37898834973084, 2.84868151156327,
+ -2.64577170229825, 2.23697657451713, -1.67148153367602,
+ 1.00595954808547, -0.45953458054983, 0.16378164858596,
+ -0.05032077717131, 0.02347897407020 },
+ { 0.97938932735214, -1.95877865470428, 0.97938932735214 },
+ { 1.00000000000000, -1.95835380975398, 0.95920349965459 },
+ },
+ {
+ 24000,
+ { 0.30296907319327, -0.22613988682123, -0.08587323730772,
+ 0.03282930172664, -0.00915702933434, -0.02364141202522,
+ -0.00584456039913, 0.06276101321749, -0.00000828086748,
+ 0.00205861885564, -0.02950134983287 },
+ { 1.00000000000000, -1.61273165137247, 1.07977492259970,
+ -0.25656257754070, -0.16276719120440, -0.22638893773906,
+ 0.39120800788284, -0.22138138954925, 0.04500235387352,
+ 0.02005851806501, 0.00302439095741 },
+ { 0.97531843204928, -1.95063686409857, 0.97531843204928 },
+ { 1.00000000000000, -1.95002759149878, 0.95124613669835 },
+ },
+ {
+ 22050,
+ { 0.33642304856132, -0.25572241425570, -0.11828570177555,
+ 0.11921148675203, -0.07834489609479, -0.00469977914380,
+ -0.00589500224440, 0.05724228140351, 0.00832043980773,
+ -0.01635381384540, -0.01760176568150 },
+ { 1.00000000000000, -1.49858979367799, 0.87350271418188,
+ 0.12205022308084, -0.80774944671438, 0.47854794562326,
+ -0.12453458140019, -0.04067510197014, 0.08333755284107,
+ -0.04237348025746, 0.02977207319925 },
+ { 0.97316523498161, -1.94633046996323, 0.97316523498161 },
+ { 1.00000000000000, -1.94561023566527, 0.94705070426118 },
+ },
+ {
+ 18900,
+ { 0.38524531015142, -0.27682212062067, -0.09980181488805,
+ 0.09951486755646, -0.08934020156622, -0.00322369330199,
+ -0.00110329090689, 0.03784509844682, 0.01683906213303,
+ -0.01147039862572, -0.01941767987192 },
+ { 1.00000000000000, -1.29708918404534, 0.90399339674203,
+ -0.29613799017877, -0.42326645916207, 0.37934887402200,
+ -0.37919795944938, 0.23410283284785, -0.03892971758879,
+ 0.00403009552351, 0.03640166626278 },
+ { 0.96535326815829, -1.93070653631658, 0.96535326815829 },
+ { 1.00000000000000, -1.92950577983524, 0.93190729279793 },
+ },
+ {
+ 16000,
+ { 0.44915256608450, -0.14351757464547, -0.22784394429749,
+ -0.01419140100551, 0.04078262797139, -0.12398163381748,
+ 0.04097565135648, 0.10478503600251, -0.01863887810927,
+ -0.03193428438915, 0.00541907748707 },
+ { 1.00000000000000, -0.62820619233671, 0.29661783706366,
+ -0.37256372942400, 0.00213767857124, -0.42029820170918,
+ 0.22199650564824, 0.00613424350682, 0.06747620744683,
+ 0.05784820375801, 0.03222754072173 },
+ { 0.96454515552826, -1.92909031105652, 0.96454515552826 },
+ { 1.00000000000000, -1.92783286977036, 0.93034775234268 },
+ },
+ {
+ 12000,
+ { 0.56619470757641, -0.75464456939302, 0.16242137742230,
+ 0.16744243493672, -0.18901604199609, 0.30931782841830,
+ -0.27562961986224, 0.00647310677246, 0.08647503780351,
+ -0.03788984554840, -0.00588215443421 },
+ { 1.00000000000000, -1.04800335126349, 0.29156311971249,
+ -0.26806001042947, 0.00819999645858, 0.45054734505008,
+ -0.33032403314006, 0.06739368333110, -0.04784254229033,
+ 0.01639907836189, 0.01807364323573 },
+ { 0.96009142950541, -1.92018285901082, 0.96009142950541 },
+ { 1.00000000000000, -1.91858953033784, 0.92177618768381 },
+ },
+ {
+ 11025,
+ { 0.58100494960553, -0.53174909058578, -0.14289799034253,
+ 0.17520704835522, 0.02377945217615, 0.15558449135573,
+ -0.25344790059353, 0.01628462406333, 0.06920467763959,
+ -0.03721611395801, -0.00749618797172 },
+ { 1.00000000000000, -0.51035327095184, -0.31863563325245,
+ -0.20256413484477, 0.14728154134330, 0.38952639978999,
+ -0.23313271880868, -0.05246019024463, -0.02505961724053,
+ 0.02442357316099, 0.01818801111503 },
+ { 0.95856916599601, -1.91713833199203, 0.95856916599601 },
+ { 1.00000000000000, -1.91542108074780, 0.91885558323625 },
+ },
+ {
+ 8000,
+ { 0.53648789255105, -0.42163034350696, -0.00275953611929,
+ 0.04267842219415, -0.10214864179676, 0.14590772289388,
+ -0.02459864859345, -0.11202315195388, -0.04060034127000,
+ 0.04788665548180, -0.02217936801134 },
+ { 1.00000000000000, -0.25049871956020, -0.43193942311114,
+ -0.03424681017675, -0.04678328784242, 0.26408300200955,
+ 0.15113130533216, -0.17556493366449, -0.18823009262115,
+ 0.05477720428674, 0.04704409688120 },
+ { 0.94597685600279, -1.89195371200558, 0.94597685600279 },
+ { 1.00000000000000, -1.88903307939452, 0.89487434461664 },
+ },
+};
+
+typedef struct ReplayGainContext {
+ uint32_t histogram[HISTOGRAM_SLOTS];
+ float peak;
+ int yule_hist_i, butter_hist_i;
+ const double *yule_coeff_a;
+ const double *yule_coeff_b;
+ const double *butter_coeff_a;
+ const double *butter_coeff_b;
+ float yule_hist_a[256];
+ float yule_hist_b[256];
+ float butter_hist_a[256];
+ float butter_hist_b[256];
+} ReplayGainContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layout = NULL;
+ int i;
+
+ ff_add_format(&formats, AV_SAMPLE_FMT_FLT);
+ ff_set_common_formats(ctx, formats);
+ ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
+ ff_set_common_channel_layouts(ctx, layout);
+
+ formats = NULL;
+ for (i = 0; i < FF_ARRAY_ELEMS(freqinfos); i++)
+ ff_add_format(&formats, freqinfos[i].sample_rate);
+ ff_set_common_samplerates(ctx, formats);
+
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ReplayGainContext *s = ctx->priv;
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(freqinfos); i++) {
+ if (freqinfos[i].sample_rate == inlink->sample_rate)
+ break;
+ }
+ av_assert0(i < FF_ARRAY_ELEMS(freqinfos));
+
+ s->yule_coeff_a = freqinfos[i].AYule;
+ s->yule_coeff_b = freqinfos[i].BYule;
+ s->butter_coeff_a = freqinfos[i].AButter;
+ s->butter_coeff_b = freqinfos[i].BButter;
+
+ s->yule_hist_i = 20;
+ s->butter_hist_i = 4;
+ inlink->partial_buf_size =
+ inlink->min_samples =
+ inlink->max_samples = inlink->sample_rate / 20;
+
+ return 0;
+}
+
+/*
+ * Update largest absolute sample value.
+ */
+static void calc_stereo_peak(const float *samples, int nb_samples,
+ float *peak_p)
+{
+ float peak = 0.0;
+
+ while (nb_samples--) {
+ if (samples[0] > peak)
+ peak = samples[0];
+ else if (-samples[0] > peak)
+ peak = -samples[0];
+
+ if (samples[1] > peak)
+ peak = samples[1];
+ else if (-samples[1] > peak)
+ peak = -samples[1];
+
+ samples += 2;
+ }
+
+ *peak_p = FFMAX(peak, *peak_p);
+}
+
+/*
+ * Calculate stereo RMS level. Minimum value is about -100 dB for
+ * digital silence. The 90 dB offset is to compensate for the
+ * normalized float range and 3 dB is for stereo samples.
+ */
+static double calc_stereo_rms(const float *samples, int nb_samples)
+{
+ int count = nb_samples;
+ double sum = 1e-16;
+
+ while (count--) {
+ sum += samples[0] * samples[0] + samples[1] * samples[1];
+ samples += 2;
+ }
+
+ return 10 * log10 (sum / nb_samples) + 90.0 - 3.0;
+}
+
+/*
+ * Optimized implementation of 2nd-order IIR stereo filter.
+ */
+static void butter_filter_stereo_samples(ReplayGainContext *s,
+ float *samples, int nb_samples)
+{
+ const double *coeff_a = s->butter_coeff_a;
+ const double *coeff_b = s->butter_coeff_b;
+ float *hist_a = s->butter_hist_a;
+ float *hist_b = s->butter_hist_b;
+ double left, right;
+ int i, j;
+
+ i = s->butter_hist_i;
+
+ // If filter history is very small magnitude, clear it completely
+ // to prevent denormals from rattling around in there forever
+ // (slowing us down).
+
+ for (j = -4; j < 0; ++j)
+ if (fabs(hist_a[i + j]) > 1e-10 || fabs(hist_b[i + j]) > 1e-10)
+ break;
+
+ if (!j) {
+ memset(s->butter_hist_a, 0, sizeof(s->butter_hist_a));
+ memset(s->butter_hist_b, 0, sizeof(s->butter_hist_b));
+ }
+
+ while (nb_samples--) {
+ left = (hist_b[i ] = samples[0]) * coeff_b[0];
+ right = (hist_b[i + 1] = samples[1]) * coeff_b[0];
+ left += hist_b[i - 2] * coeff_b[1] - hist_a[i - 2] * coeff_a[1];
+ right += hist_b[i - 1] * coeff_b[1] - hist_a[i - 1] * coeff_a[1];
+ left += hist_b[i - 4] * coeff_b[2] - hist_a[i - 4] * coeff_a[2];
+ right += hist_b[i - 3] * coeff_b[2] - hist_a[i - 3] * coeff_a[2];
+ samples[0] = hist_a[i ] = (float) left;
+ samples[1] = hist_a[i + 1] = (float) right;
+ samples += 2;
+
+ if ((i += 2) == 256) {
+ memcpy(hist_a, hist_a + 252, sizeof(*hist_a) * 4);
+ memcpy(hist_b, hist_b + 252, sizeof(*hist_b) * 4);
+ i = 4;
+ }
+ }
+
+ s->butter_hist_i = i;
+}
+
+/*
+ * Optimized implementation of 10th-order IIR stereo filter.
+ */
+static void yule_filter_stereo_samples(ReplayGainContext *s, const float *src,
+ float *dst, int nb_samples)
+{
+ const double *coeff_a = s->yule_coeff_a;
+ const double *coeff_b = s->yule_coeff_b;
+ float *hist_a = s->yule_hist_a;
+ float *hist_b = s->yule_hist_b;
+ double left, right;
+ int i, j;
+
+ i = s->yule_hist_i;
+
+ // If filter history is very small magnitude, clear it completely to
+ // prevent denormals from rattling around in there forever
+ // (slowing us down).
+
+ for (j = -20; j < 0; ++j)
+ if (fabs(hist_a[i + j]) > 1e-10 || fabs(hist_b[i + j]) > 1e-10)
+ break;
+
+ if (!j) {
+ memset(s->yule_hist_a, 0, sizeof(s->yule_hist_a));
+ memset(s->yule_hist_b, 0, sizeof(s->yule_hist_b));
+ }
+
+ while (nb_samples--) {
+ left = (hist_b[i] = src[0]) * coeff_b[0];
+ right = (hist_b[i + 1] = src[1]) * coeff_b[0];
+ left += hist_b[i - 2] * coeff_b[ 1] - hist_a[i - 2] * coeff_a[1 ];
+ right += hist_b[i - 1] * coeff_b[ 1] - hist_a[i - 1] * coeff_a[1 ];
+ left += hist_b[i - 4] * coeff_b[ 2] - hist_a[i - 4] * coeff_a[2 ];
+ right += hist_b[i - 3] * coeff_b[ 2] - hist_a[i - 3] * coeff_a[2 ];
+ left += hist_b[i - 6] * coeff_b[ 3] - hist_a[i - 6] * coeff_a[3 ];
+ right += hist_b[i - 5] * coeff_b[ 3] - hist_a[i - 5] * coeff_a[3 ];
+ left += hist_b[i - 8] * coeff_b[ 4] - hist_a[i - 8] * coeff_a[4 ];
+ right += hist_b[i - 7] * coeff_b[ 4] - hist_a[i - 7] * coeff_a[4 ];
+ left += hist_b[i - 10] * coeff_b[ 5] - hist_a[i - 10] * coeff_a[5 ];
+ right += hist_b[i - 9] * coeff_b[ 5] - hist_a[i - 9] * coeff_a[5 ];
+ left += hist_b[i - 12] * coeff_b[ 6] - hist_a[i - 12] * coeff_a[6 ];
+ right += hist_b[i - 11] * coeff_b[ 6] - hist_a[i - 11] * coeff_a[6 ];
+ left += hist_b[i - 14] * coeff_b[ 7] - hist_a[i - 14] * coeff_a[7 ];
+ right += hist_b[i - 13] * coeff_b[ 7] - hist_a[i - 13] * coeff_a[7 ];
+ left += hist_b[i - 16] * coeff_b[ 8] - hist_a[i - 16] * coeff_a[8 ];
+ right += hist_b[i - 15] * coeff_b[ 8] - hist_a[i - 15] * coeff_a[8 ];
+ left += hist_b[i - 18] * coeff_b[ 9] - hist_a[i - 18] * coeff_a[9 ];
+ right += hist_b[i - 17] * coeff_b[ 9] - hist_a[i - 17] * coeff_a[9 ];
+ left += hist_b[i - 20] * coeff_b[10] - hist_a[i - 20] * coeff_a[10];
+ right += hist_b[i - 19] * coeff_b[10] - hist_a[i - 19] * coeff_a[10];
+ dst[0] = hist_a[i ] = (float)left;
+ dst[1] = hist_a[i + 1] = (float)right;
+ src += 2;
+ dst += 2;
+
+ if ((i += 2) == 256) {
+ memcpy(hist_a, hist_a + 236, sizeof(*hist_a) * 20);
+ memcpy(hist_b, hist_b + 236, sizeof(*hist_b) * 20);
+ i = 20;
+ }
+ }
+
+ s->yule_hist_i = i;
+}
+
+/*
+ * Calculate the ReplayGain value from the specified loudness histogram;
+ * clip to -24 / +64 dB.
+ */
+static float calc_replaygain(uint32_t *histogram)
+{
+ uint32_t loud_count = 0, total_windows = 0;
+ float gain;
+ int i;
+
+ for (i = 0; i < HISTOGRAM_SLOTS; i++)
+ total_windows += histogram [i];
+
+ while (i--)
+ if ((loud_count += histogram [i]) * 20 >= total_windows)
+ break;
+
+ gain = (float)(64.54 - i / 100.0);
+
+ return av_clipf(gain, -24.0, 64.0);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ReplayGainContext *s = ctx->priv;
+ uint32_t level;
+ AVFrame *out;
+
+ out = ff_get_audio_buffer(inlink, in->nb_samples);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+
+ calc_stereo_peak((float *)in->data[0],
+ in->nb_samples, &s->peak);
+ yule_filter_stereo_samples(s, (const float *)in->data[0],
+ (float *)out->data[0],
+ out->nb_samples);
+ butter_filter_stereo_samples(s, (float *)out->data[0],
+ out->nb_samples);
+ level = (uint32_t)floor(100 * calc_stereo_rms((float *)out->data[0],
+ out->nb_samples));
+ level = av_clip(level, 0, HISTOGRAM_SLOTS - 1);
+
+ s->histogram[level]++;
+
+ av_frame_free(&out);
+ return ff_filter_frame(outlink, in);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ReplayGainContext *s = ctx->priv;
+ float gain = calc_replaygain(s->histogram);
+
+ av_log(ctx, AV_LOG_INFO, "track_gain = %+.2f dB\n", gain);
+ av_log(ctx, AV_LOG_INFO, "track_peak = %.6f\n", s->peak);
+}
+
+static const AVFilterPad replaygain_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad replaygain_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_replaygain = {
+ .name = "replaygain",
+ .description = NULL_IF_CONFIG_SMALL("ReplayGain scanner."),
+ .query_formats = query_formats,
+ .uninit = uninit,
+ .priv_size = sizeof(ReplayGainContext),
+ .inputs = replaygain_inputs,
+ .outputs = replaygain_outputs,
+};
diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c
index fbe61056e3..d65d4bc64a 100644
--- a/libavfilter/af_resample.c
+++ b/libavfilter/af_resample.c
@@ -1,19 +1,18 @@
/*
+ * This file is part of FFmpeg.
*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -312,9 +311,9 @@ static const AVClass resample_class = {
static const AVFilterPad avfilter_af_resample_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -334,11 +333,9 @@ AVFilter ff_af_resample = {
.description = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."),
.priv_size = sizeof(ResampleContext),
.priv_class = &resample_class,
-
- .init_dict = init,
- .uninit = uninit,
- .query_formats = query_formats,
-
- .inputs = avfilter_af_resample_inputs,
- .outputs = avfilter_af_resample_outputs,
+ .init_dict = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = avfilter_af_resample_inputs,
+ .outputs = avfilter_af_resample_outputs,
};
diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c
new file mode 100644
index 0000000000..b048d63738
--- /dev/null
+++ b/libavfilter/af_silencedetect.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Audio silence detector
+ */
+
+#include <float.h> /* DBL_MAX */
+
+#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
+#include "audio.h"
+#include "formats.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct SilenceDetectContext {
+ const AVClass *class;
+ double noise; ///< noise amplitude ratio
+ double duration; ///< minimum duration of silence until notification
+ int64_t nb_null_samples; ///< current number of continuous zero samples
+ int64_t start; ///< if silence is detected, this value contains the time of the first zero sample
+ int last_sample_rate; ///< last sample rate to check for sample rate changes
+
+ void (*silencedetect)(struct SilenceDetectContext *s, AVFrame *insamples,
+ int nb_samples, int64_t nb_samples_notify,
+ AVRational time_base);
+} SilenceDetectContext;
+
+#define OFFSET(x) offsetof(SilenceDetectContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption silencedetect_options[] = {
+ { "n", "set noise tolerance", OFFSET(noise), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0, DBL_MAX, FLAGS },
+ { "noise", "set noise tolerance", OFFSET(noise), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0, DBL_MAX, FLAGS },
+ { "d", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS },
+ { "duration", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(silencedetect);
+
+static char *get_metadata_val(AVFrame *insamples, const char *key)
+{
+ AVDictionaryEntry *e = av_dict_get(insamples->metadata, key, NULL, 0);
+ return e && e->value ? e->value : NULL;
+}
+
+static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples,
+ int is_silence, int64_t nb_samples_notify,
+ AVRational time_base)
+{
+ if (is_silence) {
+ if (!s->start) {
+ s->nb_null_samples++;
+ if (s->nb_null_samples >= nb_samples_notify) {
+ s->start = insamples->pts - (int64_t)(s->duration / av_q2d(time_base) + .5);
+ av_dict_set(&insamples->metadata, "lavfi.silence_start",
+ av_ts2timestr(s->start, &time_base), 0);
+ av_log(s, AV_LOG_INFO, "silence_start: %s\n",
+ get_metadata_val(insamples, "lavfi.silence_start"));
+ }
+ }
+ } else {
+ if (s->start) {
+ av_dict_set(&insamples->metadata, "lavfi.silence_end",
+ av_ts2timestr(insamples->pts, &time_base), 0);
+ av_dict_set(&insamples->metadata, "lavfi.silence_duration",
+ av_ts2timestr(insamples->pts - s->start, &time_base), 0);
+ av_log(s, AV_LOG_INFO,
+ "silence_end: %s | silence_duration: %s\n",
+ get_metadata_val(insamples, "lavfi.silence_end"),
+ get_metadata_val(insamples, "lavfi.silence_duration"));
+ }
+ s->nb_null_samples = s->start = 0;
+ }
+}
+
+#define SILENCE_DETECT(name, type) \
+static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, \
+ int nb_samples, int64_t nb_samples_notify, \
+ AVRational time_base) \
+{ \
+ const type *p = (const type *)insamples->data[0]; \
+ const type noise = s->noise; \
+ int i; \
+ \
+ for (i = 0; i < nb_samples; i++, p++) \
+ update(s, insamples, *p < noise && *p > -noise, \
+ nb_samples_notify, time_base); \
+}
+
+SILENCE_DETECT(dbl, double)
+SILENCE_DETECT(flt, float)
+SILENCE_DETECT(s32, int32_t)
+SILENCE_DETECT(s16, int16_t)
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SilenceDetectContext *s = ctx->priv;
+
+ switch (inlink->format) {
+ case AV_SAMPLE_FMT_DBL: s->silencedetect = silencedetect_dbl; break;
+ case AV_SAMPLE_FMT_FLT: s->silencedetect = silencedetect_flt; break;
+ case AV_SAMPLE_FMT_S32:
+ s->noise *= INT32_MAX;
+ s->silencedetect = silencedetect_s32;
+ break;
+ case AV_SAMPLE_FMT_S16:
+ s->noise *= INT16_MAX;
+ s->silencedetect = silencedetect_s16;
+ break;
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ SilenceDetectContext *s = inlink->dst->priv;
+ const int nb_channels = inlink->channels;
+ const int srate = inlink->sample_rate;
+ const int nb_samples = insamples->nb_samples * nb_channels;
+ const int64_t nb_samples_notify = srate * s->duration * nb_channels;
+
+ // scale number of null samples to the new sample rate
+ if (s->last_sample_rate && s->last_sample_rate != srate)
+ s->nb_null_samples = srate * s->nb_null_samples / s->last_sample_rate;
+ s->last_sample_rate = srate;
+
+ // TODO: document metadata
+ s->silencedetect(s, insamples, nb_samples, nb_samples_notify,
+ inlink->time_base);
+
+ return ff_filter_frame(inlink->dst->outputs[0], insamples);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBL,
+ AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static const AVFilterPad silencedetect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad silencedetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_silencedetect = {
+ .name = "silencedetect",
+ .description = NULL_IF_CONFIG_SMALL("Detect silence."),
+ .priv_size = sizeof(SilenceDetectContext),
+ .query_formats = query_formats,
+ .inputs = silencedetect_inputs,
+ .outputs = silencedetect_outputs,
+ .priv_class = &silencedetect_class,
+};
diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c
new file mode 100644
index 0000000000..cd1e0384d3
--- /dev/null
+++ b/libavfilter/af_silenceremove.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2001 Heikki Leinonen
+ * Copyright (c) 2001 Chris Bagwell
+ * Copyright (c) 2003 Donnie Smith
+ * Copyright (c) 2014 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
+ */
+
+#include <float.h> /* DBL_MAX */
+
+#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
+#include "audio.h"
+#include "formats.h"
+#include "avfilter.h"
+#include "internal.h"
+
+enum SilenceMode {
+ SILENCE_TRIM,
+ SILENCE_TRIM_FLUSH,
+ SILENCE_COPY,
+ SILENCE_COPY_FLUSH,
+ SILENCE_STOP
+};
+
+typedef struct SilenceRemoveContext {
+ const AVClass *class;
+
+ enum SilenceMode mode;
+
+ int start_periods;
+ int64_t start_duration;
+ double start_threshold;
+
+ int stop_periods;
+ int64_t stop_duration;
+ double stop_threshold;
+
+ double *start_holdoff;
+ size_t start_holdoff_offset;
+ size_t start_holdoff_end;
+ int start_found_periods;
+
+ double *stop_holdoff;
+ size_t stop_holdoff_offset;
+ size_t stop_holdoff_end;
+ int stop_found_periods;
+
+ double *window;
+ double *window_current;
+ double *window_end;
+ int window_size;
+ double rms_sum;
+
+ int leave_silence;
+ int restart;
+ int64_t next_pts;
+} SilenceRemoveContext;
+
+#define OFFSET(x) offsetof(SilenceRemoveContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM
+static const AVOption silenceremove_options[] = {
+ { "start_periods", NULL, OFFSET(start_periods), AV_OPT_TYPE_INT, {.i64=0}, 0, 9000, FLAGS },
+ { "start_duration", NULL, OFFSET(start_duration), AV_OPT_TYPE_DURATION, {.i64=0}, 0, 9000, FLAGS },
+ { "start_threshold", NULL, OFFSET(start_threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, DBL_MAX, FLAGS },
+ { "stop_periods", NULL, OFFSET(stop_periods), AV_OPT_TYPE_INT, {.i64=0}, -9000, 9000, FLAGS },
+ { "stop_duration", NULL, OFFSET(stop_duration), AV_OPT_TYPE_DURATION, {.i64=0}, 0, 9000, FLAGS },
+ { "stop_threshold", NULL, OFFSET(stop_threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, DBL_MAX, FLAGS },
+ { "leave_silence", NULL, OFFSET(leave_silence), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(silenceremove);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ SilenceRemoveContext *s = ctx->priv;
+
+ if (s->stop_periods < 0) {
+ s->stop_periods = -s->stop_periods;
+ s->restart = 1;
+ }
+
+ return 0;
+}
+
+static void clear_rms(SilenceRemoveContext *s)
+{
+ memset(s->window, 0, s->window_size * sizeof(*s->window));
+
+ s->window_current = s->window;
+ s->window_end = s->window + s->window_size;
+ s->rms_sum = 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SilenceRemoveContext *s = ctx->priv;
+
+ s->window_size = (inlink->sample_rate / 50) * inlink->channels;
+ s->window = av_malloc_array(s->window_size, sizeof(*s->window));
+ if (!s->window)
+ return AVERROR(ENOMEM);
+
+ clear_rms(s);
+
+ s->start_duration = av_rescale(s->start_duration, inlink->sample_rate,
+ AV_TIME_BASE);
+ s->stop_duration = av_rescale(s->stop_duration, inlink->sample_rate,
+ AV_TIME_BASE);
+
+ s->start_holdoff = av_malloc_array(FFMAX(s->start_duration, 1),
+ sizeof(*s->start_holdoff) *
+ inlink->channels);
+ if (!s->start_holdoff)
+ return AVERROR(ENOMEM);
+
+ s->start_holdoff_offset = 0;
+ s->start_holdoff_end = 0;
+ s->start_found_periods = 0;
+
+ s->stop_holdoff = av_malloc_array(FFMAX(s->stop_duration, 1),
+ sizeof(*s->stop_holdoff) *
+ inlink->channels);
+ if (!s->stop_holdoff)
+ return AVERROR(ENOMEM);
+
+ s->stop_holdoff_offset = 0;
+ s->stop_holdoff_end = 0;
+ s->stop_found_periods = 0;
+
+ if (s->start_periods)
+ s->mode = SILENCE_TRIM;
+ else
+ s->mode = SILENCE_COPY;
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return 0;
+}
+
+static double compute_rms(SilenceRemoveContext *s, double sample)
+{
+ double new_sum;
+
+ new_sum = s->rms_sum;
+ new_sum -= *s->window_current;
+ new_sum += sample * sample;
+
+ return sqrt(new_sum / s->window_size);
+}
+
+static void update_rms(SilenceRemoveContext *s, double sample)
+{
+ s->rms_sum -= *s->window_current;
+ *s->window_current = sample * sample;
+ s->rms_sum += *s->window_current;
+
+ s->window_current++;
+ if (s->window_current >= s->window_end)
+ s->window_current = s->window;
+}
+
+static void flush(AVFrame *out, AVFilterLink *outlink,
+ int *nb_samples_written, int *ret)
+{
+ if (*nb_samples_written) {
+ out->nb_samples = *nb_samples_written / outlink->channels;
+ *ret = ff_filter_frame(outlink, out);
+ *nb_samples_written = 0;
+ } else {
+ av_frame_free(&out);
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ SilenceRemoveContext *s = ctx->priv;
+ int i, j, threshold, ret = 0;
+ int nbs, nb_samples_read, nb_samples_written;
+ double *obuf, *ibuf = (double *)in->data[0];
+ AVFrame *out;
+
+ nb_samples_read = nb_samples_written = 0;
+
+ switch (s->mode) {
+ case SILENCE_TRIM:
+silence_trim:
+ nbs = in->nb_samples - nb_samples_read / inlink->channels;
+ if (!nbs)
+ break;
+
+ for (i = 0; i < nbs; i++) {
+ threshold = 0;
+ for (j = 0; j < inlink->channels; j++) {
+ threshold |= compute_rms(s, ibuf[j]) > s->start_threshold;
+ }
+
+ if (threshold) {
+ for (j = 0; j < inlink->channels; j++) {
+ update_rms(s, *ibuf);
+ s->start_holdoff[s->start_holdoff_end++] = *ibuf++;
+ nb_samples_read++;
+ }
+
+ if (s->start_holdoff_end >= s->start_duration * inlink->channels) {
+ if (++s->start_found_periods >= s->start_periods) {
+ s->mode = SILENCE_TRIM_FLUSH;
+ goto silence_trim_flush;
+ }
+
+ s->start_holdoff_offset = 0;
+ s->start_holdoff_end = 0;
+ }
+ } else {
+ s->start_holdoff_end = 0;
+
+ for (j = 0; j < inlink->channels; j++)
+ update_rms(s, ibuf[j]);
+
+ ibuf += inlink->channels;
+ nb_samples_read += inlink->channels;
+ }
+ }
+ break;
+
+ case SILENCE_TRIM_FLUSH:
+silence_trim_flush:
+ nbs = s->start_holdoff_end - s->start_holdoff_offset;
+ nbs -= nbs % inlink->channels;
+ if (!nbs)
+ break;
+
+ out = ff_get_audio_buffer(inlink, nbs / inlink->channels);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+
+ memcpy(out->data[0], &s->start_holdoff[s->start_holdoff_offset],
+ nbs * sizeof(double));
+ s->start_holdoff_offset += nbs;
+
+ ret = ff_filter_frame(outlink, out);
+
+ if (s->start_holdoff_offset == s->start_holdoff_end) {
+ s->start_holdoff_offset = 0;
+ s->start_holdoff_end = 0;
+ s->mode = SILENCE_COPY;
+ goto silence_copy;
+ }
+ break;
+
+ case SILENCE_COPY:
+silence_copy:
+ nbs = in->nb_samples - nb_samples_read / inlink->channels;
+ if (!nbs)
+ break;
+
+ out = ff_get_audio_buffer(inlink, nbs);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ obuf = (double *)out->data[0];
+
+ if (s->stop_periods) {
+ for (i = 0; i < nbs; i++) {
+ threshold = 1;
+ for (j = 0; j < inlink->channels; j++)
+ threshold &= compute_rms(s, ibuf[j]) > s->stop_threshold;
+
+ if (threshold && s->stop_holdoff_end && !s->leave_silence) {
+ s->mode = SILENCE_COPY_FLUSH;
+ flush(out, outlink, &nb_samples_written, &ret);
+ goto silence_copy_flush;
+ } else if (threshold) {
+ for (j = 0; j < inlink->channels; j++) {
+ update_rms(s, *ibuf);
+ *obuf++ = *ibuf++;
+ nb_samples_read++;
+ nb_samples_written++;
+ }
+ } else if (!threshold) {
+ for (j = 0; j < inlink->channels; j++) {
+ update_rms(s, *ibuf);
+ if (s->leave_silence) {
+ *obuf++ = *ibuf;
+ nb_samples_written++;
+ }
+
+ s->stop_holdoff[s->stop_holdoff_end++] = *ibuf++;
+ nb_samples_read++;
+ }
+
+ if (s->stop_holdoff_end >= s->stop_duration * inlink->channels) {
+ if (++s->stop_found_periods >= s->stop_periods) {
+ s->stop_holdoff_offset = 0;
+ s->stop_holdoff_end = 0;
+
+ if (!s->restart) {
+ s->mode = SILENCE_STOP;
+ flush(out, outlink, &nb_samples_written, &ret);
+ goto silence_stop;
+ } else {
+ s->stop_found_periods = 0;
+ s->start_found_periods = 0;
+ s->start_holdoff_offset = 0;
+ s->start_holdoff_end = 0;
+ clear_rms(s);
+ s->mode = SILENCE_TRIM;
+ flush(out, outlink, &nb_samples_written, &ret);
+ goto silence_trim;
+ }
+ }
+ s->mode = SILENCE_COPY_FLUSH;
+ flush(out, outlink, &nb_samples_written, &ret);
+ goto silence_copy_flush;
+ }
+ }
+ }
+ flush(out, outlink, &nb_samples_written, &ret);
+ } else {
+ memcpy(obuf, ibuf, sizeof(double) * nbs * inlink->channels);
+ ret = ff_filter_frame(outlink, out);
+ }
+ break;
+
+ case SILENCE_COPY_FLUSH:
+silence_copy_flush:
+ nbs = s->stop_holdoff_end - s->stop_holdoff_offset;
+ nbs -= nbs % inlink->channels;
+ if (!nbs)
+ break;
+
+ out = ff_get_audio_buffer(inlink, nbs / inlink->channels);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+
+ memcpy(out->data[0], &s->stop_holdoff[s->stop_holdoff_offset],
+ nbs * sizeof(double));
+ s->stop_holdoff_offset += nbs;
+
+ ret = ff_filter_frame(outlink, out);
+
+ if (s->stop_holdoff_offset == s->stop_holdoff_end) {
+ s->stop_holdoff_offset = 0;
+ s->stop_holdoff_end = 0;
+ s->mode = SILENCE_COPY;
+ goto silence_copy;
+ }
+ break;
+ case SILENCE_STOP:
+silence_stop:
+ break;
+ }
+
+ av_frame_free(&in);
+
+ return ret;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ SilenceRemoveContext *s = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+ if (ret == AVERROR_EOF && (s->mode == SILENCE_COPY_FLUSH ||
+ s->mode == SILENCE_COPY)) {
+ int nbs = s->stop_holdoff_end - s->stop_holdoff_offset;
+ if (nbs) {
+ AVFrame *frame;
+
+ frame = ff_get_audio_buffer(outlink, nbs / outlink->channels);
+ if (!frame)
+ return AVERROR(ENOMEM);
+
+ memcpy(frame->data[0], &s->stop_holdoff[s->stop_holdoff_offset],
+ nbs * sizeof(double));
+ ret = ff_filter_frame(ctx->inputs[0], frame);
+ }
+ s->mode = SILENCE_STOP;
+ }
+ return ret;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE
+ };
+ int ret;
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SilenceRemoveContext *s = ctx->priv;
+
+ av_freep(&s->start_holdoff);
+ av_freep(&s->stop_holdoff);
+ av_freep(&s->window);
+}
+
+static const AVFilterPad silenceremove_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad silenceremove_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_silenceremove = {
+ .name = "silenceremove",
+ .description = NULL_IF_CONFIG_SMALL("Remove silence."),
+ .priv_size = sizeof(SilenceRemoveContext),
+ .priv_class = &silenceremove_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = silenceremove_inputs,
+ .outputs = silenceremove_outputs,
+};
diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c
index 11d85a17eb..54bffa6015 100644
--- a/libavfilter/af_volume.c
+++ b/libavfilter/af_volume.c
@@ -2,20 +2,20 @@
* Copyright (c) 2011 Stefano Sabatini
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,21 +38,41 @@
#include "internal.h"
#include "af_volume.h"
-static const char *precision_str[] = {
+static const char * const precision_str[] = {
"fixed", "float", "double"
};
+static const char *const var_names[] = {
+ "n", ///< frame number (starting at zero)
+ "nb_channels", ///< number of channels
+ "nb_consumed_samples", ///< number of samples consumed by the filter
+ "nb_samples", ///< number of samples in the current frame
+ "pos", ///< position in the file of the frame
+ "pts", ///< frame presentation timestamp
+ "sample_rate", ///< sample rate
+ "startpts", ///< PTS at start of stream
+ "startt", ///< time at start of stream
+ "t", ///< time in the file of the frame
+ "tb", ///< timebase
+ "volume", ///< last set value
+ NULL
+};
+
#define OFFSET(x) offsetof(VolumeContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
-
-static const AVOption options[] = {
- { "volume", "Volume adjustment.",
- OFFSET(volume), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 0, 0x7fffff, A },
- { "precision", "Mathematical precision.",
- OFFSET(precision), AV_OPT_TYPE_INT, { .i64 = PRECISION_FLOAT }, PRECISION_FIXED, PRECISION_DOUBLE, A, "precision" },
- { "fixed", "8-bit fixed-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FIXED }, INT_MIN, INT_MAX, A, "precision" },
- { "float", "32-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FLOAT }, INT_MIN, INT_MAX, A, "precision" },
- { "double", "64-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_DOUBLE }, INT_MIN, INT_MAX, A, "precision" },
+#define F AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption volume_options[] = {
+ { "volume", "set volume adjustment expression",
+ OFFSET(volume_expr), AV_OPT_TYPE_STRING, { .str = "1.0" }, .flags = A|F },
+ { "precision", "select mathematical precision",
+ OFFSET(precision), AV_OPT_TYPE_INT, { .i64 = PRECISION_FLOAT }, PRECISION_FIXED, PRECISION_DOUBLE, A|F, "precision" },
+ { "fixed", "select 8-bit fixed-point", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FIXED }, INT_MIN, INT_MAX, A|F, "precision" },
+ { "float", "select 32-bit floating-point", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FLOAT }, INT_MIN, INT_MAX, A|F, "precision" },
+ { "double", "select 64-bit floating-point", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_DOUBLE }, INT_MIN, INT_MAX, A|F, "precision" },
+ { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_ONCE}, 0, EVAL_MODE_NB-1, .flags = A|F, "eval" },
+ { "once", "eval volume expression once", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_ONCE}, .flags = A|F, .unit = "eval" },
+ { "frame", "eval volume expression per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = A|F, .unit = "eval" },
{ "replaygain", "Apply replaygain side data when present",
OFFSET(replaygain), AV_OPT_TYPE_INT, { .i64 = REPLAYGAIN_DROP }, REPLAYGAIN_DROP, REPLAYGAIN_ALBUM, A, "replaygain" },
{ "drop", "replaygain side data is dropped", 0, AV_OPT_TYPE_CONST, { .i64 = REPLAYGAIN_DROP }, 0, 0, A, "replaygain" },
@@ -66,29 +86,45 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass volume_class = {
- .class_name = "volume filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(volume);
+
+static int set_expr(AVExpr **pexpr, const char *expr, void *log_ctx)
+{
+ int ret;
+ AVExpr *old = NULL;
+
+ if (*pexpr)
+ old = *pexpr;
+ ret = av_expr_parse(pexpr, expr, var_names,
+ NULL, NULL, NULL, NULL, 0, log_ctx);
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Error when evaluating the volume expression '%s'\n", expr);
+ *pexpr = old;
+ return ret;
+ }
+
+ av_expr_free(old);
+ return 0;
+}
static av_cold int init(AVFilterContext *ctx)
{
VolumeContext *vol = ctx->priv;
- if (vol->precision == PRECISION_FIXED) {
- vol->volume_i = (int)(vol->volume * 256 + 0.5);
- vol->volume = vol->volume_i / 256.0;
- av_log(ctx, AV_LOG_VERBOSE, "volume:(%d/256)(%f)(%1.2fdB) precision:fixed\n",
- vol->volume_i, vol->volume, 20.0*log(vol->volume)/M_LN10);
- } else {
- av_log(ctx, AV_LOG_VERBOSE, "volume:(%f)(%1.2fdB) precision:%s\n",
- vol->volume, 20.0*log(vol->volume)/M_LN10,
- precision_str[vol->precision]);
- }
+ vol->fdsp = avpriv_float_dsp_alloc(0);
+ if (!vol->fdsp)
+ return AVERROR(ENOMEM);
- return 0;
+ return set_expr(&vol->volume_pexpr, vol->volume_expr, ctx);
+}
+
+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)
@@ -97,8 +133,7 @@ static int query_formats(AVFilterContext *ctx)
AVFilterFormats *formats = NULL;
AVFilterChannelLayouts *layouts;
static const enum AVSampleFormat sample_fmts[][7] = {
- /* PRECISION_FIXED */
- {
+ [PRECISION_FIXED] = {
AV_SAMPLE_FMT_U8,
AV_SAMPLE_FMT_U8P,
AV_SAMPLE_FMT_S16,
@@ -107,36 +142,37 @@ static int query_formats(AVFilterContext *ctx)
AV_SAMPLE_FMT_S32P,
AV_SAMPLE_FMT_NONE
},
- /* PRECISION_FLOAT */
- {
+ [PRECISION_FLOAT] = {
AV_SAMPLE_FMT_FLT,
AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE
},
- /* PRECISION_DOUBLE */
- {
+ [PRECISION_DOUBLE] = {
AV_SAMPLE_FMT_DBL,
AV_SAMPLE_FMT_DBLP,
AV_SAMPLE_FMT_NONE
}
};
+ int ret;
- layouts = ff_all_channel_layouts();
+ layouts = ff_all_channel_counts();
if (!layouts)
return AVERROR(ENOMEM);
- ff_set_common_channel_layouts(ctx, layouts);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
formats = ff_make_format_list(sample_fmts[vol->precision]);
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_formats(ctx, formats);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
formats = ff_all_samplerates();
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_samplerates(ctx, formats);
-
- return 0;
+ return ff_set_common_samplerates(ctx, formats);
}
static inline void scale_samples_u8(uint8_t *dst, const uint8_t *src,
@@ -185,8 +221,6 @@ static inline void scale_samples_s32(uint8_t *dst, const uint8_t *src,
smp_dst[i] = av_clipl_int32((((int64_t)smp_src[i] * volume + 128) >> 8));
}
-
-
static av_cold void volume_init(VolumeContext *vol)
{
vol->samples_align = 1;
@@ -208,11 +242,9 @@ static av_cold void volume_init(VolumeContext *vol)
vol->scale_samples = scale_samples_s32;
break;
case AV_SAMPLE_FMT_FLT:
- avpriv_float_dsp_init(&vol->fdsp, 0);
vol->samples_align = 4;
break;
case AV_SAMPLE_FMT_DBL:
- avpriv_float_dsp_init(&vol->fdsp, 0);
vol->samples_align = 8;
break;
}
@@ -221,6 +253,38 @@ static av_cold void volume_init(VolumeContext *vol)
ff_volume_init_x86(vol);
}
+static int set_volume(AVFilterContext *ctx)
+{
+ VolumeContext *vol = ctx->priv;
+
+ vol->volume = av_expr_eval(vol->volume_pexpr, vol->var_values, NULL);
+ if (isnan(vol->volume)) {
+ if (vol->eval_mode == EVAL_MODE_ONCE) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid value NaN for volume\n");
+ return AVERROR(EINVAL);
+ } else {
+ av_log(ctx, AV_LOG_WARNING, "Invalid value NaN for volume, setting to 0\n");
+ vol->volume = 0;
+ }
+ }
+ vol->var_values[VAR_VOLUME] = vol->volume;
+
+ av_log(ctx, AV_LOG_VERBOSE, "n:%f t:%f pts:%f precision:%s ",
+ vol->var_values[VAR_N], vol->var_values[VAR_T], vol->var_values[VAR_PTS],
+ precision_str[vol->precision]);
+
+ if (vol->precision == PRECISION_FIXED) {
+ vol->volume_i = (int)(vol->volume * 256 + 0.5);
+ vol->volume = vol->volume_i / 256.0;
+ av_log(ctx, AV_LOG_VERBOSE, "volume_i:%d/255 ", vol->volume_i);
+ }
+ av_log(ctx, AV_LOG_VERBOSE, "volume:%f volume_dB:%f\n",
+ vol->volume, 20.0*log(vol->volume)/M_LN10);
+
+ volume_init(vol);
+ return 0;
+}
+
static int config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
@@ -228,20 +292,59 @@ static int config_output(AVFilterLink *outlink)
AVFilterLink *inlink = ctx->inputs[0];
vol->sample_fmt = inlink->format;
- vol->channels = av_get_channel_layout_nb_channels(inlink->channel_layout);
+ vol->channels = inlink->channels;
vol->planes = av_sample_fmt_is_planar(inlink->format) ? vol->channels : 1;
- volume_init(vol);
+ vol->var_values[VAR_N] =
+ vol->var_values[VAR_NB_CONSUMED_SAMPLES] =
+ vol->var_values[VAR_NB_SAMPLES] =
+ vol->var_values[VAR_POS] =
+ vol->var_values[VAR_PTS] =
+ vol->var_values[VAR_STARTPTS] =
+ vol->var_values[VAR_STARTT] =
+ vol->var_values[VAR_T] =
+ vol->var_values[VAR_VOLUME] = NAN;
+
+ vol->var_values[VAR_NB_CHANNELS] = inlink->channels;
+ vol->var_values[VAR_TB] = av_q2d(inlink->time_base);
+ vol->var_values[VAR_SAMPLE_RATE] = inlink->sample_rate;
+
+ av_log(inlink->src, AV_LOG_VERBOSE, "tb:%f sample_rate:%f nb_channels:%f\n",
+ vol->var_values[VAR_TB],
+ vol->var_values[VAR_SAMPLE_RATE],
+ vol->var_values[VAR_NB_CHANNELS]);
+
+ return set_volume(ctx);
+}
- return 0;
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ VolumeContext *vol = ctx->priv;
+ int ret = AVERROR(ENOSYS);
+
+ if (!strcmp(cmd, "volume")) {
+ if ((ret = set_expr(&vol->volume_pexpr, args, ctx)) < 0)
+ return ret;
+ if (vol->eval_mode == EVAL_MODE_ONCE)
+ set_volume(ctx);
+ }
+
+ return ret;
}
+#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))
+
static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
{
+ AVFilterContext *ctx = inlink->dst;
VolumeContext *vol = inlink->dst->priv;
AVFilterLink *outlink = inlink->dst->outputs[0];
int nb_samples = buf->nb_samples;
AVFrame *out_buf;
+ int64_t pos;
AVFrameSideData *sd = av_frame_get_side_data(buf, AV_FRAME_DATA_REPLAYGAIN);
int ret;
@@ -283,11 +386,27 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
av_frame_remove_side_data(buf, AV_FRAME_DATA_REPLAYGAIN);
}
- if (vol->volume == 1.0 || vol->volume_i == 256)
- return ff_filter_frame(outlink, buf);
+ if (isnan(vol->var_values[VAR_STARTPTS])) {
+ vol->var_values[VAR_STARTPTS] = TS2D(buf->pts);
+ vol->var_values[VAR_STARTT ] = TS2T(buf->pts, inlink->time_base);
+ }
+ 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;
+
+ pos = av_frame_get_pkt_pos(buf);
+ vol->var_values[VAR_POS] = pos == -1 ? NAN : pos;
+ if (vol->eval_mode == EVAL_MODE_FRAME)
+ set_volume(ctx);
+
+ if (vol->volume == 1.0 || vol->volume_i == 256) {
+ out_buf = buf;
+ goto end;
+ }
/* do volume scaling in-place if input buffer is writable */
- if (av_frame_is_writable(buf)) {
+ if (av_frame_is_writable(buf)
+ && (vol->precision != PRECISION_FIXED || vol->volume_i > 0)) {
out_buf = buf;
} else {
out_buf = ff_get_audio_buffer(inlink, nb_samples);
@@ -317,13 +436,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
}
} else if (av_get_packed_sample_fmt(vol->sample_fmt) == AV_SAMPLE_FMT_FLT) {
for (p = 0; p < vol->planes; p++) {
- vol->fdsp.vector_fmul_scalar((float *)out_buf->extended_data[p],
+ vol->fdsp->vector_fmul_scalar((float *)out_buf->extended_data[p],
(const float *)buf->extended_data[p],
vol->volume, plane_samples);
}
} else {
for (p = 0; p < vol->planes; p++) {
- vol->fdsp.vector_dmul_scalar((double *)out_buf->extended_data[p],
+ vol->fdsp->vector_dmul_scalar((double *)out_buf->extended_data[p],
(const double *)buf->extended_data[p],
vol->volume, plane_samples);
}
@@ -335,6 +454,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
if (buf != out_buf)
av_frame_free(&buf);
+end:
+ vol->var_values[VAR_NB_CONSUMED_SAMPLES] += out_buf->nb_samples;
return ff_filter_frame(outlink, out_buf);
}
@@ -363,6 +484,9 @@ AVFilter ff_af_volume = {
.priv_size = sizeof(VolumeContext),
.priv_class = &volume_class,
.init = init,
+ .uninit = uninit,
.inputs = avfilter_af_volume_inputs,
.outputs = avfilter_af_volume_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+ .process_command = process_command,
};
diff --git a/libavfilter/af_volume.h b/libavfilter/af_volume.h
index 6bd89acc4d..aff75267fe 100644
--- a/libavfilter/af_volume.h
+++ b/libavfilter/af_volume.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
#define AVFILTER_AF_VOLUME_H
#include "libavutil/common.h"
+#include "libavutil/eval.h"
#include "libavutil/float_dsp.h"
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"
@@ -35,6 +36,28 @@ enum PrecisionType {
PRECISION_DOUBLE,
};
+enum EvalMode {
+ EVAL_MODE_ONCE,
+ EVAL_MODE_FRAME,
+ EVAL_MODE_NB
+};
+
+enum VolumeVarName {
+ VAR_N,
+ VAR_NB_CHANNELS,
+ VAR_NB_CONSUMED_SAMPLES,
+ VAR_NB_SAMPLES,
+ VAR_POS,
+ VAR_PTS,
+ VAR_SAMPLE_RATE,
+ VAR_STARTPTS,
+ VAR_STARTT,
+ VAR_T,
+ VAR_TB,
+ VAR_VOLUME,
+ VAR_VARS_NB
+};
+
enum ReplayGainType {
REPLAYGAIN_DROP,
REPLAYGAIN_IGNORE,
@@ -44,9 +67,14 @@ enum ReplayGainType {
typedef struct VolumeContext {
const AVClass *class;
- AVFloatDSPContext fdsp;
- enum PrecisionType precision;
- enum ReplayGainType replaygain;
+ AVFloatDSPContext *fdsp;
+ int precision;
+ int eval_mode;
+ const char *volume_expr;
+ AVExpr *volume_pexpr;
+ double var_values[VAR_VARS_NB];
+
+ int replaygain;
double replaygain_preamp;
int replaygain_noclip;
double volume;
diff --git a/libavfilter/af_volumedetect.c b/libavfilter/af_volumedetect.c
new file mode 100644
index 0000000000..01f24baea0
--- /dev/null
+++ b/libavfilter/af_volumedetect.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/avassert.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ /**
+ * Number of samples at each PCM value.
+ * histogram[0x8000 + i] is the number of samples at value i.
+ * The extra element is there for symmetry.
+ */
+ uint64_t histogram[0x10001];
+} VolDetectContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_NONE
+ };
+ AVFilterFormats *formats;
+
+ if (!(formats = ff_make_format_list(sample_fmts)))
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, formats);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *samples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ VolDetectContext *vd = ctx->priv;
+ int64_t layout = samples->channel_layout;
+ int nb_samples = samples->nb_samples;
+ int nb_channels = av_get_channel_layout_nb_channels(layout);
+ int nb_planes = nb_channels;
+ int plane, i;
+ int16_t *pcm;
+
+ if (!av_sample_fmt_is_planar(samples->format)) {
+ nb_samples *= nb_channels;
+ nb_planes = 1;
+ }
+ for (plane = 0; plane < nb_planes; plane++) {
+ pcm = (int16_t *)samples->extended_data[plane];
+ for (i = 0; i < nb_samples; i++)
+ vd->histogram[pcm[i] + 0x8000]++;
+ }
+
+ return ff_filter_frame(inlink->dst->outputs[0], samples);
+}
+
+#define MAX_DB 91
+
+static inline double logdb(uint64_t v)
+{
+ double d = v / (double)(0x8000 * 0x8000);
+ if (!v)
+ return MAX_DB;
+ return log(d) * -4.3429448190325182765112891891660508229; /* -10/log(10) */
+}
+
+static void print_stats(AVFilterContext *ctx)
+{
+ VolDetectContext *vd = ctx->priv;
+ int i, max_volume, shift;
+ uint64_t nb_samples = 0, power = 0, nb_samples_shift = 0, sum = 0;
+ uint64_t histdb[MAX_DB + 1] = { 0 };
+
+ for (i = 0; i < 0x10000; i++)
+ nb_samples += vd->histogram[i];
+ av_log(ctx, AV_LOG_INFO, "n_samples: %"PRId64"\n", nb_samples);
+ if (!nb_samples)
+ return;
+
+ /* If nb_samples > 1<<34, there is a risk of overflow in the
+ multiplication or the sum: shift all histogram values to avoid that.
+ The total number of samples must be recomputed to avoid rounding
+ errors. */
+ shift = av_log2(nb_samples >> 33);
+ for (i = 0; i < 0x10000; i++) {
+ nb_samples_shift += vd->histogram[i] >> shift;
+ power += (i - 0x8000) * (i - 0x8000) * (vd->histogram[i] >> shift);
+ }
+ if (!nb_samples_shift)
+ return;
+ power = (power + nb_samples_shift / 2) / nb_samples_shift;
+ av_assert0(power <= 0x8000 * 0x8000);
+ av_log(ctx, AV_LOG_INFO, "mean_volume: %.1f dB\n", -logdb(power));
+
+ max_volume = 0x8000;
+ while (max_volume > 0 && !vd->histogram[0x8000 + max_volume] &&
+ !vd->histogram[0x8000 - max_volume])
+ max_volume--;
+ av_log(ctx, AV_LOG_INFO, "max_volume: %.1f dB\n", -logdb(max_volume * max_volume));
+
+ for (i = 0; i < 0x10000; i++)
+ histdb[(int)logdb((i - 0x8000) * (i - 0x8000))] += vd->histogram[i];
+ for (i = 0; i <= MAX_DB && !histdb[i]; i++);
+ for (; i <= MAX_DB && sum < nb_samples / 1000; i++) {
+ av_log(ctx, AV_LOG_INFO, "histogram_%ddb: %"PRId64"\n", i, histdb[i]);
+ sum += histdb[i];
+ }
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ print_stats(ctx);
+}
+
+static const AVFilterPad volumedetect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad volumedetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_volumedetect = {
+ .name = "volumedetect",
+ .description = NULL_IF_CONFIG_SMALL("Detect audio volume."),
+ .priv_size = sizeof(VolDetectContext),
+ .query_formats = query_formats,
+ .uninit = uninit,
+ .inputs = volumedetect_inputs,
+ .outputs = volumedetect_outputs,
+};
diff --git a/libavfilter/all_channel_layouts.inc b/libavfilter/all_channel_layouts.inc
new file mode 100644
index 0000000000..878e1f5f8e
--- /dev/null
+++ b/libavfilter/all_channel_layouts.inc
@@ -0,0 +1,68 @@
+AV_CH_FRONT_CENTER,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER,
+AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_CENTER|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_LOW_FREQUENCY|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
+AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT|AV_CH_FRONT_CENTER|AV_CH_BACK_CENTER|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT|AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT,
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 67a298d5fc..0244585a14 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -2,25 +2,26 @@
* filter registration
* Copyright (c) 2008 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avfilter.h"
#include "config.h"
+#include "opencl_allkernels.h"
#define REGISTER_FILTER(X, x, y) \
@@ -44,79 +45,227 @@ void avfilter_register_all(void)
return;
initialized = 1;
+ REGISTER_FILTER(ADELAY, adelay, af);
+ REGISTER_FILTER(AECHO, aecho, af);
+ REGISTER_FILTER(AEVAL, aeval, af);
+ REGISTER_FILTER(AFADE, afade, af);
REGISTER_FILTER(AFORMAT, aformat, af);
+ REGISTER_FILTER(AINTERLEAVE, ainterleave, af);
+ REGISTER_FILTER(ALLPASS, allpass, af);
+ REGISTER_FILTER(AMERGE, amerge, af);
REGISTER_FILTER(AMIX, amix, af);
REGISTER_FILTER(ANULL, anull, af);
+ REGISTER_FILTER(APAD, apad, af);
+ REGISTER_FILTER(APERMS, aperms, af);
+ REGISTER_FILTER(APHASER, aphaser, af);
+ REGISTER_FILTER(ARESAMPLE, aresample, af);
+ REGISTER_FILTER(ASELECT, aselect, af);
+ REGISTER_FILTER(ASENDCMD, asendcmd, af);
+ REGISTER_FILTER(ASETNSAMPLES, asetnsamples, af);
REGISTER_FILTER(ASETPTS, asetpts, af);
+ REGISTER_FILTER(ASETRATE, asetrate, af);
REGISTER_FILTER(ASETTB, asettb, af);
REGISTER_FILTER(ASHOWINFO, ashowinfo, af);
REGISTER_FILTER(ASPLIT, asplit, af);
+ REGISTER_FILTER(ASTATS, astats, af);
+ REGISTER_FILTER(ASTREAMSYNC, astreamsync, af);
REGISTER_FILTER(ASYNCTS, asyncts, af);
+ REGISTER_FILTER(ATEMPO, atempo, af);
REGISTER_FILTER(ATRIM, atrim, af);
+ REGISTER_FILTER(AZMQ, azmq, af);
+ REGISTER_FILTER(BANDPASS, bandpass, af);
+ REGISTER_FILTER(BANDREJECT, bandreject, af);
+ REGISTER_FILTER(BASS, bass, af);
+ REGISTER_FILTER(BIQUAD, biquad, af);
REGISTER_FILTER(BS2B, bs2b, af);
REGISTER_FILTER(CHANNELMAP, channelmap, af);
REGISTER_FILTER(CHANNELSPLIT, channelsplit, af);
+ REGISTER_FILTER(CHORUS, chorus, af);
REGISTER_FILTER(COMPAND, compand, af);
+ REGISTER_FILTER(DCSHIFT, dcshift, af);
+ REGISTER_FILTER(EARWAX, earwax, af);
+ REGISTER_FILTER(EBUR128, ebur128, af);
+ REGISTER_FILTER(EQUALIZER, equalizer, af);
+ REGISTER_FILTER(FLANGER, flanger, af);
+ REGISTER_FILTER(HIGHPASS, highpass, af);
REGISTER_FILTER(JOIN, join, af);
+ REGISTER_FILTER(LADSPA, ladspa, af);
+ REGISTER_FILTER(LOWPASS, lowpass, af);
+ REGISTER_FILTER(PAN, pan, af);
+ REGISTER_FILTER(REPLAYGAIN, replaygain, af);
REGISTER_FILTER(RESAMPLE, resample, af);
+ REGISTER_FILTER(SILENCEDETECT, silencedetect, af);
+ REGISTER_FILTER(SILENCEREMOVE, silenceremove, af);
+ REGISTER_FILTER(TREBLE, treble, af);
REGISTER_FILTER(VOLUME, volume, af);
+ REGISTER_FILTER(VOLUMEDETECT, volumedetect, af);
+ REGISTER_FILTER(AEVALSRC, aevalsrc, asrc);
REGISTER_FILTER(ANULLSRC, anullsrc, asrc);
+ REGISTER_FILTER(FLITE, flite, asrc);
+ REGISTER_FILTER(SINE, sine, asrc);
REGISTER_FILTER(ANULLSINK, anullsink, asink);
+ REGISTER_FILTER(ALPHAEXTRACT, alphaextract, vf);
+ REGISTER_FILTER(ALPHAMERGE, alphamerge, vf);
+ REGISTER_FILTER(ASS, ass, vf);
+ REGISTER_FILTER(BBOX, bbox, vf);
+ REGISTER_FILTER(BLACKDETECT, blackdetect, vf);
REGISTER_FILTER(BLACKFRAME, blackframe, vf);
+ REGISTER_FILTER(BLEND, blend, vf);
REGISTER_FILTER(BOXBLUR, boxblur, vf);
+ REGISTER_FILTER(CODECVIEW, codecview, vf);
+ REGISTER_FILTER(COLORBALANCE, colorbalance, vf);
+ REGISTER_FILTER(COLORCHANNELMIXER, colorchannelmixer, vf);
+ REGISTER_FILTER(COLORLEVELS, colorlevels, vf);
+ REGISTER_FILTER(COLORMATRIX, colormatrix, vf);
REGISTER_FILTER(COPY, copy, vf);
+ REGISTER_FILTER(COVER_RECT, cover_rect, vf);
REGISTER_FILTER(CROP, crop, vf);
REGISTER_FILTER(CROPDETECT, cropdetect, vf);
+ REGISTER_FILTER(CURVES, curves, vf);
+ REGISTER_FILTER(DCTDNOIZ, dctdnoiz, vf);
+ REGISTER_FILTER(DECIMATE, decimate, vf);
+ REGISTER_FILTER(DEJUDDER, dejudder, vf);
REGISTER_FILTER(DELOGO, delogo, vf);
+ REGISTER_FILTER(DESHAKE, deshake, vf);
+ REGISTER_FILTER(DETELECINE, detelecine, vf);
REGISTER_FILTER(DRAWBOX, drawbox, vf);
+ REGISTER_FILTER(DRAWGRID, drawgrid, vf);
REGISTER_FILTER(DRAWTEXT, drawtext, vf);
+ REGISTER_FILTER(EDGEDETECT, edgedetect, vf);
+ REGISTER_FILTER(ELBG, elbg, vf);
+ REGISTER_FILTER(EQ, eq, vf);
+ REGISTER_FILTER(EXTRACTPLANES, extractplanes, vf);
REGISTER_FILTER(FADE, fade, vf);
+ REGISTER_FILTER(FFTFILT, fftfilt, vf);
+ REGISTER_FILTER(FIELD, field, vf);
+ REGISTER_FILTER(FIELDMATCH, fieldmatch, vf);
REGISTER_FILTER(FIELDORDER, fieldorder, vf);
+ REGISTER_FILTER(FIND_RECT, find_rect, vf);
REGISTER_FILTER(FORMAT, format, vf);
REGISTER_FILTER(FPS, fps, vf);
REGISTER_FILTER(FRAMEPACK, framepack, vf);
+ REGISTER_FILTER(FRAMESTEP, framestep, vf);
REGISTER_FILTER(FREI0R, frei0r, vf);
+ REGISTER_FILTER(FSPP, fspp, vf);
+ REGISTER_FILTER(GEQ, geq, vf);
REGISTER_FILTER(GRADFUN, gradfun, vf);
+ REGISTER_FILTER(HALDCLUT, haldclut, vf);
REGISTER_FILTER(HFLIP, hflip, vf);
+ REGISTER_FILTER(HISTEQ, histeq, vf);
+ REGISTER_FILTER(HISTOGRAM, histogram, vf);
REGISTER_FILTER(HQDN3D, hqdn3d, vf);
+ REGISTER_FILTER(HQX, hqx, vf);
+ REGISTER_FILTER(HUE, hue, vf);
+ REGISTER_FILTER(IDET, idet, vf);
+ REGISTER_FILTER(IL, il, vf);
REGISTER_FILTER(INTERLACE, interlace, vf);
+ REGISTER_FILTER(INTERLEAVE, interleave, vf);
+ REGISTER_FILTER(KERNDEINT, kerndeint, vf);
+ REGISTER_FILTER(LENSCORRECTION, lenscorrection, vf);
+ REGISTER_FILTER(LUT3D, lut3d, vf);
REGISTER_FILTER(LUT, lut, vf);
REGISTER_FILTER(LUTRGB, lutrgb, vf);
REGISTER_FILTER(LUTYUV, lutyuv, vf);
+ REGISTER_FILTER(MCDEINT, mcdeint, vf);
+ REGISTER_FILTER(MERGEPLANES, mergeplanes, vf);
+ REGISTER_FILTER(MPDECIMATE, mpdecimate, vf);
REGISTER_FILTER(NEGATE, negate, vf);
REGISTER_FILTER(NOFORMAT, noformat, vf);
+ REGISTER_FILTER(NOISE, noise, vf);
REGISTER_FILTER(NULL, null, vf);
REGISTER_FILTER(OCV, ocv, vf);
REGISTER_FILTER(OVERLAY, overlay, vf);
+ REGISTER_FILTER(OWDENOISE, owdenoise, vf);
REGISTER_FILTER(PAD, pad, vf);
+ REGISTER_FILTER(PALETTEGEN, palettegen, vf);
+ REGISTER_FILTER(PALETTEUSE, paletteuse, vf);
+ REGISTER_FILTER(PERMS, perms, vf);
+ REGISTER_FILTER(PERSPECTIVE, perspective, vf);
+ REGISTER_FILTER(PHASE, phase, vf);
REGISTER_FILTER(PIXDESCTEST, pixdesctest, vf);
+ REGISTER_FILTER(PP, pp, vf);
+ REGISTER_FILTER(PP7, pp7, vf);
+ REGISTER_FILTER(PSNR, psnr, vf);
+ REGISTER_FILTER(PULLUP, pullup, vf);
+ REGISTER_FILTER(QP, qp, vf);
+ REGISTER_FILTER(REMOVELOGO, removelogo, vf);
+ REGISTER_FILTER(REPEATFIELDS, repeatfields, vf);
+ REGISTER_FILTER(ROTATE, rotate, vf);
+ REGISTER_FILTER(SAB, sab, vf);
REGISTER_FILTER(SCALE, scale, vf);
REGISTER_FILTER(SELECT, select, vf);
+ REGISTER_FILTER(SENDCMD, sendcmd, vf);
+ REGISTER_FILTER(SEPARATEFIELDS, separatefields, vf);
REGISTER_FILTER(SETDAR, setdar, vf);
+ REGISTER_FILTER(SETFIELD, setfield, vf);
REGISTER_FILTER(SETPTS, setpts, vf);
REGISTER_FILTER(SETSAR, setsar, vf);
REGISTER_FILTER(SETTB, settb, vf);
REGISTER_FILTER(SHOWINFO, showinfo, vf);
+ REGISTER_FILTER(SHOWPALETTE, showpalette, vf);
REGISTER_FILTER(SHUFFLEPLANES, shuffleplanes, vf);
+ REGISTER_FILTER(SIGNALSTATS, signalstats, vf);
+ REGISTER_FILTER(SMARTBLUR, smartblur, vf);
REGISTER_FILTER(SPLIT, split, vf);
+ REGISTER_FILTER(SPP, spp, vf);
+ REGISTER_FILTER(STEREO3D, stereo3d, vf);
+ REGISTER_FILTER(SUBTITLES, subtitles, vf);
+ REGISTER_FILTER(SUPER2XSAI, super2xsai, vf);
+ REGISTER_FILTER(SWAPUV, swapuv, vf);
+ REGISTER_FILTER(TBLEND, tblend, vf);
+ REGISTER_FILTER(TELECINE, telecine, vf);
+ REGISTER_FILTER(THUMBNAIL, thumbnail, vf);
+ REGISTER_FILTER(TILE, tile, vf);
+ REGISTER_FILTER(TINTERLACE, tinterlace, vf);
REGISTER_FILTER(TRANSPOSE, transpose, vf);
REGISTER_FILTER(TRIM, trim, vf);
REGISTER_FILTER(UNSHARP, unsharp, vf);
+ REGISTER_FILTER(USPP, uspp, vf);
REGISTER_FILTER(VFLIP, vflip, vf);
+ REGISTER_FILTER(VIDSTABDETECT, vidstabdetect, vf);
+ REGISTER_FILTER(VIDSTABTRANSFORM, vidstabtransform, vf);
+ REGISTER_FILTER(VIGNETTE, vignette, vf);
+ REGISTER_FILTER(W3FDIF, w3fdif, vf);
+ REGISTER_FILTER(XBR, xbr, vf);
REGISTER_FILTER(YADIF, yadif, vf);
+ REGISTER_FILTER(ZMQ, zmq, vf);
+ REGISTER_FILTER(ZOOMPAN, zoompan, vf);
+ REGISTER_FILTER(CELLAUTO, cellauto, vsrc);
REGISTER_FILTER(COLOR, color, vsrc);
REGISTER_FILTER(FREI0R, frei0r_src, vsrc);
- REGISTER_FILTER(MOVIE, movie, vsrc);
+ REGISTER_FILTER(HALDCLUTSRC, haldclutsrc, vsrc);
+ REGISTER_FILTER(LIFE, life, vsrc);
+ REGISTER_FILTER(MANDELBROT, mandelbrot, vsrc);
+ REGISTER_FILTER(MPTESTSRC, mptestsrc, vsrc);
REGISTER_FILTER(NULLSRC, nullsrc, vsrc);
REGISTER_FILTER(RGBTESTSRC, rgbtestsrc, vsrc);
+ REGISTER_FILTER(SMPTEBARS, smptebars, vsrc);
+ REGISTER_FILTER(SMPTEHDBARS, smptehdbars, vsrc);
REGISTER_FILTER(TESTSRC, testsrc, vsrc);
REGISTER_FILTER(NULLSINK, nullsink, vsink);
+ /* multimedia filters */
+ REGISTER_FILTER(AVECTORSCOPE, avectorscope, avf);
+ REGISTER_FILTER(CONCAT, concat, avf);
+ REGISTER_FILTER(SHOWCQT, showcqt, avf);
+ REGISTER_FILTER(SHOWSPECTRUM, showspectrum, avf);
+ REGISTER_FILTER(SHOWWAVES, showwaves, avf);
+ REGISTER_FILTER(SHOWWAVESPIC, showwavespic, avf);
+
+ /* multimedia sources */
+ REGISTER_FILTER(AMOVIE, amovie, avsrc);
+ REGISTER_FILTER(MOVIE, movie, avsrc);
+
+#if FF_API_AVFILTERBUFFER
+ REGISTER_FILTER_UNCONDITIONAL(vsink_ffbuffersink);
+ REGISTER_FILTER_UNCONDITIONAL(asink_ffabuffersink);
+#endif
+
/* those filters are part of public or internal API => registered
* unconditionally */
REGISTER_FILTER_UNCONDITIONAL(asrc_abuffer);
@@ -125,4 +274,5 @@ void avfilter_register_all(void)
REGISTER_FILTER_UNCONDITIONAL(vsink_buffer);
REGISTER_FILTER_UNCONDITIONAL(af_afifo);
REGISTER_FILTER_UNCONDITIONAL(vf_fifo);
+ ff_opencl_register_filter_kernel_code_all();
}
diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c
index 44f547d6ee..9b53d3fbc2 100644
--- a/libavfilter/asink_anullsink.c
+++ b/libavfilter/asink_anullsink.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2010 S.N. Hemanth Meenakshisundaram <smeenaks@ucsd.edu>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavfilter/asrc_abuffer.h b/libavfilter/asrc_abuffer.h
new file mode 100644
index 0000000000..aa3446166f
--- /dev/null
+++ b/libavfilter/asrc_abuffer.h
@@ -0,0 +1,91 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_ASRC_ABUFFER_H
+#define AVFILTER_ASRC_ABUFFER_H
+
+#include "avfilter.h"
+
+/**
+ * @file
+ * memory buffer source for audio
+ *
+ * @deprecated use buffersrc.h instead.
+ */
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * @param abuffersrc audio source buffer context
+ * @param data pointers to the samples planes
+ * @param linesize linesizes of each audio buffer plane
+ * @param nb_samples number of samples per channel
+ * @param sample_fmt sample format of the audio data
+ * @param ch_layout channel layout of the audio data
+ * @param planar flag to indicate if audio data is planar or packed
+ * @param pts presentation timestamp of the audio buffer
+ * @param flags unused
+ *
+ * @deprecated use av_buffersrc_add_ref() instead.
+ */
+attribute_deprecated
+int av_asrc_buffer_add_samples(AVFilterContext *abuffersrc,
+ uint8_t *data[8], int linesize[8],
+ int nb_samples, int sample_rate,
+ int sample_fmt, int64_t ch_layout, int planar,
+ int64_t pts, int av_unused flags);
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * This is similar to av_asrc_buffer_add_samples(), but the samples
+ * are stored in a buffer with known size.
+ *
+ * @param abuffersrc audio source buffer context
+ * @param buf pointer to the samples data, packed is assumed
+ * @param size the size in bytes of the buffer, it must contain an
+ * integer number of samples
+ * @param sample_fmt sample format of the audio data
+ * @param ch_layout channel layout of the audio data
+ * @param pts presentation timestamp of the audio buffer
+ * @param flags unused
+ *
+ * @deprecated use av_buffersrc_add_ref() instead.
+ */
+attribute_deprecated
+int av_asrc_buffer_add_buffer(AVFilterContext *abuffersrc,
+ uint8_t *buf, int buf_size,
+ int sample_rate,
+ int sample_fmt, int64_t ch_layout, int planar,
+ int64_t pts, int av_unused flags);
+
+/**
+ * Queue an audio buffer to the audio buffer source.
+ *
+ * @param abuffersrc audio source buffer context
+ * @param samplesref buffer ref to queue
+ * @param flags unused
+ *
+ * @deprecated use av_buffersrc_add_ref() instead.
+ */
+attribute_deprecated
+int av_asrc_buffer_add_audio_buffer_ref(AVFilterContext *abuffersrc,
+ AVFilterBufferRef *samplesref,
+ int av_unused flags);
+
+#endif /* AVFILTER_ASRC_ABUFFER_H */
diff --git a/libavfilter/asrc_anullsrc.c b/libavfilter/asrc_anullsrc.c
index b1a449cdbe..28d4500a25 100644
--- a/libavfilter/asrc_anullsrc.c
+++ b/libavfilter/asrc_anullsrc.c
@@ -1,18 +1,21 @@
/*
- * This file is part of Libav.
+ * Copyright 2010 S.N. Hemanth Meenakshisundaram <smeenaks ucsd edu>
+ * Copyright 2010 Stefano Sabatini <stefano.sabatini-lala poste it>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,28 +29,118 @@
#include "libavutil/channel_layout.h"
#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+#include "audio.h"
#include "avfilter.h"
#include "internal.h"
-static int request_frame(AVFilterLink *link)
+typedef struct {
+ const AVClass *class;
+ char *channel_layout_str;
+ uint64_t channel_layout;
+ char *sample_rate_str;
+ int sample_rate;
+ int nb_samples; ///< number of samples per requested frame
+ int64_t pts;
+} ANullContext;
+
+#define OFFSET(x) offsetof(ANullContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption anullsrc_options[]= {
+ { "channel_layout", "set channel_layout", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, FLAGS },
+ { "cl", "set channel_layout", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, FLAGS },
+ { "sample_rate", "set sample rate", OFFSET(sample_rate_str) , AV_OPT_TYPE_STRING, {.str = "44100"}, 0, 0, FLAGS },
+ { "r", "set sample rate", OFFSET(sample_rate_str) , AV_OPT_TYPE_STRING, {.str = "44100"}, 0, 0, FLAGS },
+ { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 0, INT_MAX, FLAGS },
+ { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 0, INT_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(anullsrc);
+
+static av_cold int init(AVFilterContext *ctx)
{
- return AVERROR_EOF;
+ ANullContext *null = ctx->priv;
+ int ret;
+
+ if ((ret = ff_parse_sample_rate(&null->sample_rate,
+ null->sample_rate_str, ctx)) < 0)
+ return ret;
+
+ if ((ret = ff_parse_channel_layout(&null->channel_layout, NULL,
+ null->channel_layout_str, ctx)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ ANullContext *null = ctx->priv;
+ int64_t chlayouts[] = { null->channel_layout, -1 };
+ int sample_rates[] = { null->sample_rate, -1 };
+
+ ff_set_common_formats (ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO));
+ ff_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts));
+ ff_set_common_samplerates (ctx, ff_make_format_list(sample_rates));
+
+ return 0;
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ ANullContext *null = outlink->src->priv;
+ char buf[128];
+
+ av_get_channel_layout_string(buf, sizeof(buf), 0, null->channel_layout);
+ av_log(outlink->src, AV_LOG_VERBOSE,
+ "sample_rate:%d channel_layout:'%s' nb_samples:%d\n",
+ null->sample_rate, buf, null->nb_samples);
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ int ret;
+ ANullContext *null = outlink->src->priv;
+ AVFrame *samplesref;
+
+ samplesref = ff_get_audio_buffer(outlink, null->nb_samples);
+ if (!samplesref)
+ return AVERROR(ENOMEM);
+
+ samplesref->pts = null->pts;
+ samplesref->channel_layout = null->channel_layout;
+ samplesref->sample_rate = outlink->sample_rate;
+
+ ret = ff_filter_frame(outlink, av_frame_clone(samplesref));
+ av_frame_free(&samplesref);
+ if (ret < 0)
+ return ret;
+
+ null->pts += null->nb_samples;
+ return ret;
}
static const AVFilterPad avfilter_asrc_anullsrc_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_props,
.request_frame = request_frame,
},
{ NULL }
};
AVFilter ff_asrc_anullsrc = {
- .name = "anullsrc",
- .description = NULL_IF_CONFIG_SMALL("Null audio source, never return audio frames."),
-
- .inputs = NULL,
-
- .outputs = avfilter_asrc_anullsrc_outputs,
+ .name = "anullsrc",
+ .description = NULL_IF_CONFIG_SMALL("Null audio source, return empty audio frames."),
+ .init = init,
+ .query_formats = query_formats,
+ .priv_size = sizeof(ANullContext),
+ .inputs = NULL,
+ .outputs = avfilter_asrc_anullsrc_outputs,
+ .priv_class = &anullsrc_class,
};
diff --git a/libavfilter/asrc_flite.c b/libavfilter/asrc_flite.c
new file mode 100644
index 0000000000..098a1dd134
--- /dev/null
+++ b/libavfilter/asrc_flite.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * flite voice synth source
+ */
+
+#include <flite/flite.h>
+#include "libavutil/channel_layout.h"
+#include "libavutil/file.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "formats.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ char *voice_str;
+ char *textfile;
+ char *text;
+ cst_wave *wave;
+ int16_t *wave_samples;
+ int wave_nb_samples;
+ int list_voices;
+ cst_voice *voice;
+ struct voice_entry *voice_entry;
+ int64_t pts;
+ int frame_nb_samples; ///< number of samples per frame
+} FliteContext;
+
+#define OFFSET(x) offsetof(FliteContext, x)
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption flite_options[] = {
+ { "list_voices", "list voices and exit", OFFSET(list_voices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "nb_samples", "set number of samples per frame", OFFSET(frame_nb_samples), AV_OPT_TYPE_INT, {.i64=512}, 0, INT_MAX, FLAGS },
+ { "n", "set number of samples per frame", OFFSET(frame_nb_samples), AV_OPT_TYPE_INT, {.i64=512}, 0, INT_MAX, FLAGS },
+ { "text", "set text to speak", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "textfile", "set filename of the text to speak", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "v", "set voice", OFFSET(voice_str), AV_OPT_TYPE_STRING, {.str="kal"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "voice", "set voice", OFFSET(voice_str), AV_OPT_TYPE_STRING, {.str="kal"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(flite);
+
+static volatile int flite_inited = 0;
+
+/* declare functions for all the supported voices */
+#define DECLARE_REGISTER_VOICE_FN(name) \
+ cst_voice *register_cmu_us_## name(const char *); \
+ void unregister_cmu_us_## name(cst_voice *);
+DECLARE_REGISTER_VOICE_FN(awb);
+DECLARE_REGISTER_VOICE_FN(kal);
+DECLARE_REGISTER_VOICE_FN(kal16);
+DECLARE_REGISTER_VOICE_FN(rms);
+DECLARE_REGISTER_VOICE_FN(slt);
+
+struct voice_entry {
+ const char *name;
+ cst_voice * (*register_fn)(const char *);
+ void (*unregister_fn)(cst_voice *);
+ cst_voice *voice;
+ unsigned usage_count;
+} voice_entry;
+
+#define MAKE_VOICE_STRUCTURE(voice_name) { \
+ .name = #voice_name, \
+ .register_fn = register_cmu_us_ ## voice_name, \
+ .unregister_fn = unregister_cmu_us_ ## voice_name, \
+}
+static struct voice_entry voice_entries[] = {
+ MAKE_VOICE_STRUCTURE(awb),
+ MAKE_VOICE_STRUCTURE(kal),
+ MAKE_VOICE_STRUCTURE(kal16),
+ MAKE_VOICE_STRUCTURE(rms),
+ MAKE_VOICE_STRUCTURE(slt),
+};
+
+static void list_voices(void *log_ctx, const char *sep)
+{
+ int i, n = FF_ARRAY_ELEMS(voice_entries);
+ for (i = 0; i < n; i++)
+ av_log(log_ctx, AV_LOG_INFO, "%s%s",
+ voice_entries[i].name, i < (n-1) ? sep : "\n");
+}
+
+static int select_voice(struct voice_entry **entry_ret, const char *voice_name, void *log_ctx)
+{
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(voice_entries); i++) {
+ struct voice_entry *entry = &voice_entries[i];
+ if (!strcmp(entry->name, voice_name)) {
+ if (!entry->voice)
+ entry->voice = entry->register_fn(NULL);
+ if (!entry->voice) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Could not register voice '%s'\n", voice_name);
+ return AVERROR_UNKNOWN;
+ }
+ entry->usage_count++;
+ *entry_ret = entry;
+ return 0;
+ }
+ }
+
+ av_log(log_ctx, AV_LOG_ERROR, "Could not find voice '%s'\n", voice_name);
+ av_log(log_ctx, AV_LOG_INFO, "Choose between the voices: ");
+ list_voices(log_ctx, ", ");
+
+ return AVERROR(EINVAL);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ FliteContext *flite = ctx->priv;
+ int ret = 0;
+
+ if (flite->list_voices) {
+ list_voices(ctx, "\n");
+ return AVERROR_EXIT;
+ }
+
+ if (!flite_inited) {
+ if (flite_init() < 0) {
+ av_log(ctx, AV_LOG_ERROR, "flite initialization failed\n");
+ return AVERROR_UNKNOWN;
+ }
+ flite_inited++;
+ }
+
+ if ((ret = select_voice(&flite->voice_entry, flite->voice_str, ctx)) < 0)
+ return ret;
+ flite->voice = flite->voice_entry->voice;
+
+ if (flite->textfile && flite->text) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Both text and textfile options set: only one must be specified\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (flite->textfile) {
+ uint8_t *textbuf;
+ size_t textbuf_size;
+
+ if ((ret = av_file_map(flite->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "The text file '%s' could not be read: %s\n",
+ flite->textfile, av_err2str(ret));
+ return ret;
+ }
+
+ if (!(flite->text = av_malloc(textbuf_size+1)))
+ return AVERROR(ENOMEM);
+ memcpy(flite->text, textbuf, textbuf_size);
+ flite->text[textbuf_size] = 0;
+ av_file_unmap(textbuf, textbuf_size);
+ }
+
+ if (!flite->text) {
+ av_log(ctx, AV_LOG_ERROR,
+ "No speech text specified, specify the 'text' or 'textfile' option\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* synth all the file data in block */
+ flite->wave = flite_text_to_wave(flite->text, flite->voice);
+ flite->wave_samples = flite->wave->samples;
+ flite->wave_nb_samples = flite->wave->num_samples;
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ FliteContext *flite = ctx->priv;
+
+ if (!--flite->voice_entry->usage_count)
+ flite->voice_entry->unregister_fn(flite->voice);
+ flite->voice = NULL;
+ flite->voice_entry = NULL;
+ delete_wave(flite->wave);
+ flite->wave = NULL;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ FliteContext *flite = ctx->priv;
+
+ AVFilterChannelLayouts *chlayouts = NULL;
+ int64_t chlayout = av_get_default_channel_layout(flite->wave->num_channels);
+ AVFilterFormats *sample_formats = NULL;
+ AVFilterFormats *sample_rates = NULL;
+
+ ff_add_channel_layout(&chlayouts, chlayout);
+ ff_set_common_channel_layouts(ctx, chlayouts);
+ ff_add_format(&sample_formats, AV_SAMPLE_FMT_S16);
+ ff_set_common_formats(ctx, sample_formats);
+ ff_add_format(&sample_rates, flite->wave->sample_rate);
+ ff_set_common_samplerates (ctx, sample_rates);
+
+ return 0;
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ FliteContext *flite = ctx->priv;
+
+ outlink->sample_rate = flite->wave->sample_rate;
+ outlink->time_base = (AVRational){1, flite->wave->sample_rate};
+
+ av_log(ctx, AV_LOG_VERBOSE, "voice:%s fmt:%s sample_rate:%d\n",
+ flite->voice_str,
+ av_get_sample_fmt_name(outlink->format), outlink->sample_rate);
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFrame *samplesref;
+ FliteContext *flite = outlink->src->priv;
+ int nb_samples = FFMIN(flite->wave_nb_samples, flite->frame_nb_samples);
+
+ if (!nb_samples)
+ return AVERROR_EOF;
+
+ samplesref = ff_get_audio_buffer(outlink, nb_samples);
+ if (!samplesref)
+ return AVERROR(ENOMEM);
+
+ memcpy(samplesref->data[0], flite->wave_samples,
+ nb_samples * flite->wave->num_channels * 2);
+ samplesref->pts = flite->pts;
+ av_frame_set_pkt_pos(samplesref, -1);
+ av_frame_set_sample_rate(samplesref, flite->wave->sample_rate);
+ flite->pts += nb_samples;
+ flite->wave_samples += nb_samples * flite->wave->num_channels;
+ flite->wave_nb_samples -= nb_samples;
+
+ return ff_filter_frame(outlink, samplesref);
+}
+
+static const AVFilterPad flite_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_props,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_asrc_flite = {
+ .name = "flite",
+ .description = NULL_IF_CONFIG_SMALL("Synthesize voice from text using libflite."),
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(FliteContext),
+ .inputs = NULL,
+ .outputs = flite_outputs,
+ .priv_class = &flite_class,
+};
diff --git a/libavfilter/asrc_sine.c b/libavfilter/asrc_sine.c
new file mode 100644
index 0000000000..6aa01d5ec5
--- /dev/null
+++ b/libavfilter/asrc_sine.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2013 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <float.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "audio.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ double frequency;
+ double beep_factor;
+ int samples_per_frame;
+ int sample_rate;
+ int64_t duration;
+ int16_t *sin;
+ int64_t pts;
+ uint32_t phi; ///< current phase of the sine (2pi = 1<<32)
+ uint32_t dphi; ///< phase increment between two samples
+ unsigned beep_period;
+ unsigned beep_index;
+ unsigned beep_length;
+ uint32_t phi_beep; ///< current phase of the beep
+ uint32_t dphi_beep; ///< phase increment of the beep
+} SineContext;
+
+#define CONTEXT SineContext
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#define OPT_GENERIC(name, field, def, min, max, descr, type, deffield, ...) \
+ { name, descr, offsetof(CONTEXT, field), AV_OPT_TYPE_ ## type, \
+ { .deffield = def }, min, max, FLAGS, __VA_ARGS__ }
+
+#define OPT_INT(name, field, def, min, max, descr, ...) \
+ OPT_GENERIC(name, field, def, min, max, descr, INT, i64, __VA_ARGS__)
+
+#define OPT_DBL(name, field, def, min, max, descr, ...) \
+ OPT_GENERIC(name, field, def, min, max, descr, DOUBLE, dbl, __VA_ARGS__)
+
+#define OPT_DUR(name, field, def, min, max, descr, ...) \
+ OPT_GENERIC(name, field, def, min, max, descr, DURATION, str, __VA_ARGS__)
+
+static const AVOption sine_options[] = {
+ OPT_DBL("frequency", frequency, 440, 0, DBL_MAX, "set the sine frequency"),
+ OPT_DBL("f", frequency, 440, 0, DBL_MAX, "set the sine frequency"),
+ OPT_DBL("beep_factor", beep_factor, 0, 0, DBL_MAX, "set the beep fequency factor"),
+ OPT_DBL("b", beep_factor, 0, 0, DBL_MAX, "set the beep fequency factor"),
+ OPT_INT("sample_rate", sample_rate, 44100, 1, INT_MAX, "set the sample rate"),
+ OPT_INT("r", sample_rate, 44100, 1, INT_MAX, "set the sample rate"),
+ OPT_DUR("duration", duration, 0, 0, INT64_MAX, "set the audio duration"),
+ OPT_DUR("d", duration, 0, 0, INT64_MAX, "set the audio duration"),
+ OPT_INT("samples_per_frame", samples_per_frame, 1024, 0, INT_MAX, "set the number of samples per frame"),
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(sine);
+
+#define LOG_PERIOD 15
+#define AMPLITUDE 4095
+#define AMPLITUDE_SHIFT 3
+
+static void make_sin_table(int16_t *sin)
+{
+ unsigned half_pi = 1 << (LOG_PERIOD - 2);
+ unsigned ampls = AMPLITUDE << AMPLITUDE_SHIFT;
+ uint64_t unit2 = (uint64_t)(ampls * ampls) << 32;
+ unsigned step, i, c, s, k, new_k, n2;
+
+ /* Principle: if u = exp(i*a1) and v = exp(i*a2), then
+ exp(i*(a1+a2)/2) = (u+v) / length(u+v) */
+ sin[0] = 0;
+ sin[half_pi] = ampls;
+ for (step = half_pi; step > 1; step /= 2) {
+ /* k = (1 << 16) * amplitude / length(u+v)
+ In exact values, k is constant at a given step */
+ k = 0x10000;
+ for (i = 0; i < half_pi / 2; i += step) {
+ s = sin[i] + sin[i + step];
+ c = sin[half_pi - i] + sin[half_pi - i - step];
+ n2 = s * s + c * c;
+ /* Newton's method to solve n² * k² = unit² */
+ while (1) {
+ new_k = (k + unit2 / ((uint64_t)k * n2) + 1) >> 1;
+ if (k == new_k)
+ break;
+ k = new_k;
+ }
+ sin[i + step / 2] = (k * s + 0x7FFF) >> 16;
+ sin[half_pi - i - step / 2] = (k * c + 0x8000) >> 16;
+ }
+ }
+ /* Unshift amplitude */
+ for (i = 0; i <= half_pi; i++)
+ sin[i] = (sin[i] + (1 << (AMPLITUDE_SHIFT - 1))) >> AMPLITUDE_SHIFT;
+ /* Use symmetries to fill the other three quarters */
+ for (i = 0; i < half_pi; i++)
+ sin[half_pi * 2 - i] = sin[i];
+ for (i = 0; i < 2 * half_pi; i++)
+ sin[i + 2 * half_pi] = -sin[i];
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ SineContext *sine = ctx->priv;
+
+ if (!(sine->sin = av_malloc(sizeof(*sine->sin) << LOG_PERIOD)))
+ return AVERROR(ENOMEM);
+ sine->dphi = ldexp(sine->frequency, 32) / sine->sample_rate + 0.5;
+ make_sin_table(sine->sin);
+
+ if (sine->beep_factor) {
+ sine->beep_period = sine->sample_rate;
+ sine->beep_length = sine->beep_period / 25;
+ sine->dphi_beep = ldexp(sine->beep_factor * sine->frequency, 32) /
+ sine->sample_rate + 0.5;
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SineContext *sine = ctx->priv;
+
+ av_freep(&sine->sin);
+}
+
+static av_cold int query_formats(AVFilterContext *ctx)
+{
+ SineContext *sine = ctx->priv;
+ static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
+ int sample_rates[] = { sine->sample_rate, -1 };
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_NONE };
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ int ret;
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats (ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ layouts = avfilter_make_format64_list(chlayouts);
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_channel_layouts(ctx, layouts);
+ if (ret < 0)
+ return ret;
+
+ formats = ff_make_format_list(sample_rates);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ return ff_set_common_samplerates(ctx, formats);
+}
+
+static av_cold int config_props(AVFilterLink *outlink)
+{
+ SineContext *sine = outlink->src->priv;
+ sine->duration = av_rescale(sine->duration, sine->sample_rate, AV_TIME_BASE);
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ SineContext *sine = outlink->src->priv;
+ AVFrame *frame;
+ int i, nb_samples = sine->samples_per_frame;
+ int16_t *samples;
+
+ if (sine->duration) {
+ nb_samples = FFMIN(nb_samples, sine->duration - sine->pts);
+ av_assert1(nb_samples >= 0);
+ if (!nb_samples)
+ return AVERROR_EOF;
+ }
+ if (!(frame = ff_get_audio_buffer(outlink, nb_samples)))
+ return AVERROR(ENOMEM);
+ samples = (int16_t *)frame->data[0];
+
+ for (i = 0; i < nb_samples; i++) {
+ samples[i] = sine->sin[sine->phi >> (32 - LOG_PERIOD)];
+ sine->phi += sine->dphi;
+ if (sine->beep_index < sine->beep_length) {
+ samples[i] += sine->sin[sine->phi_beep >> (32 - LOG_PERIOD)] << 1;
+ sine->phi_beep += sine->dphi_beep;
+ }
+ if (++sine->beep_index == sine->beep_period)
+ sine->beep_index = 0;
+ }
+
+ frame->pts = sine->pts;
+ sine->pts += nb_samples;
+ return ff_filter_frame(outlink, frame);
+}
+
+static const AVFilterPad sine_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_asrc_sine = {
+ .name = "sine",
+ .description = NULL_IF_CONFIG_SMALL("Generate sine wave audio signal."),
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(SineContext),
+ .inputs = NULL,
+ .outputs = sine_outputs,
+ .priv_class = &sine_class,
+};
diff --git a/libavfilter/audio.c b/libavfilter/audio.c
index b332e9e43c..1e1d8e04df 100644
--- a/libavfilter/audio.c
+++ b/libavfilter/audio.c
@@ -1,28 +1,38 @@
/*
- * This file is part of Libav.
+ * Copyright (c) Stefano Sabatini | stefasab at gmail.com
+ * Copyright (c) S.N. Hemanth Meenakshisundaram | smeenaks at ucsd.edu
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/channel_layout.h"
#include "libavutil/common.h"
+#include "libavcodec/avcodec.h"
#include "audio.h"
#include "avfilter.h"
#include "internal.h"
+int avfilter_ref_get_channels(AVFilterBufferRef *ref)
+{
+ return ref->audio ? ref->audio->channels : 0;
+}
+
AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples)
{
return ff_get_audio_buffer(link->dst->outputs[0], nb_samples);
@@ -31,14 +41,17 @@ AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples)
AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples)
{
AVFrame *frame = av_frame_alloc();
- int channels = av_get_channel_layout_nb_channels(link->channel_layout);
+ int channels = link->channels;
int ret;
+ av_assert0(channels == av_get_channel_layout_nb_channels(link->channel_layout) || !av_get_channel_layout_nb_channels(link->channel_layout));
+
if (!frame)
return NULL;
frame->nb_samples = nb_samples;
frame->format = link->format;
+ av_frame_set_channels(frame, link->channels);
frame->channel_layout = link->channel_layout;
frame->sample_rate = link->sample_rate;
ret = av_frame_get_buffer(frame, 0);
@@ -68,11 +81,12 @@ AVFrame *ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
}
#if FF_API_AVFILTERBUFFER
-AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
- int linesize,int perms,
- int nb_samples,
- enum AVSampleFormat sample_fmt,
- uint64_t channel_layout)
+AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays_channels(uint8_t **data,
+ int linesize,int perms,
+ int nb_samples,
+ enum AVSampleFormat sample_fmt,
+ int channels,
+ uint64_t channel_layout)
{
int planes;
AVFilterBuffer *samples = av_mallocz(sizeof(*samples));
@@ -81,6 +95,10 @@ AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
if (!samples || !samplesref)
goto fail;
+ av_assert0(channels);
+ av_assert0(channel_layout == 0 ||
+ channels == av_get_channel_layout_nb_channels(channel_layout));
+
samplesref->buf = samples;
samplesref->buf->free = ff_avfilter_default_free_buffer;
if (!(samplesref->audio = av_mallocz(sizeof(*samplesref->audio))))
@@ -88,9 +106,9 @@ AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
samplesref->audio->nb_samples = nb_samples;
samplesref->audio->channel_layout = channel_layout;
- samplesref->audio->planar = av_sample_fmt_is_planar(sample_fmt);
+ samplesref->audio->channels = channels;
- planes = samplesref->audio->planar ? av_get_channel_layout_nb_channels(channel_layout) : 1;
+ planes = av_sample_fmt_is_planar(sample_fmt) ? channels : 1;
/* make sure the buffer gets read permission or it's useless for output */
samplesref->perms = perms | AV_PERM_READ;
@@ -106,9 +124,9 @@ AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
samples->linesize[0] = samplesref->linesize[0] = linesize;
if (planes > FF_ARRAY_ELEMS(samples->data)) {
- samples-> extended_data = av_mallocz(sizeof(*samples->extended_data) *
+ samples-> extended_data = av_mallocz_array(sizeof(*samples->extended_data),
planes);
- samplesref->extended_data = av_mallocz(sizeof(*samplesref->extended_data) *
+ samplesref->extended_data = av_mallocz_array(sizeof(*samplesref->extended_data),
planes);
if (!samples->extended_data || !samplesref->extended_data)
@@ -137,4 +155,16 @@ fail:
av_freep(&samples);
return NULL;
}
+
+AVFilterBufferRef* avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
+ int linesize,int perms,
+ int nb_samples,
+ enum AVSampleFormat sample_fmt,
+ uint64_t channel_layout)
+{
+ int channels = av_get_channel_layout_nb_channels(channel_layout);
+ return avfilter_get_audio_buffer_ref_from_arrays_channels(data, linesize, perms,
+ nb_samples, sample_fmt,
+ channels, channel_layout);
+}
#endif
diff --git a/libavfilter/audio.h b/libavfilter/audio.h
index 4684b6ce60..3335c96eca 100644
--- a/libavfilter/audio.h
+++ b/libavfilter/audio.h
@@ -1,18 +1,21 @@
/*
- * This file is part of Libav.
+ * Copyright (c) Stefano Sabatini | stefasab at gmail.com
+ * Copyright (c) S.N. Hemanth Meenakshisundaram | smeenaks at ucsd.edu
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -20,6 +23,25 @@
#define AVFILTER_AUDIO_H
#include "avfilter.h"
+#include "internal.h"
+
+static const enum AVSampleFormat ff_packed_sample_fmts_array[] = {
+ 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 const enum AVSampleFormat ff_planar_sample_fmts_array[] = {
+ AV_SAMPLE_FMT_U8P,
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_NONE
+};
/** default handler for get_audio_buffer() for audio inputs */
AVFrame *ff_default_get_audio_buffer(AVFilterLink *link, int nb_samples);
@@ -38,4 +60,24 @@ AVFrame *ff_null_get_audio_buffer(AVFilterLink *link, int nb_samples);
*/
AVFrame *ff_get_audio_buffer(AVFilterLink *link, int nb_samples);
+/**
+ * Send a buffer of audio samples to the next filter.
+ *
+ * @param link the output link over which the audio samples are being sent
+ * @param samplesref a reference to the buffer of audio samples 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 samplesref in case of error.
+ */
+int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
+
+/**
+ * Send a buffer of audio samples to the next link, without checking
+ * min_samples.
+ */
+int ff_filter_samples_framed(AVFilterLink *link,
+ AVFilterBufferRef *samplesref);
+
#endif /* AVFILTER_AUDIO_H */
diff --git a/libavfilter/avcodec.c b/libavfilter/avcodec.c
new file mode 100644
index 0000000000..def735f84d
--- /dev/null
+++ b/libavfilter/avcodec.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2011 Stefano Sabatini | stefasab at 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
+ * libavcodec/libavfilter gluing utilities
+ */
+
+#include "avcodec.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+
+#if FF_API_AVFILTERBUFFER
+AVFilterBufferRef *avfilter_get_video_buffer_ref_from_frame(const AVFrame *frame,
+ int perms)
+{
+ AVFilterBufferRef *picref =
+ avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize, perms,
+ frame->width, frame->height,
+ frame->format);
+ if (!picref)
+ return NULL;
+ if (avfilter_copy_frame_props(picref, frame) < 0) {
+ picref->buf->data[0] = NULL;
+ avfilter_unref_bufferp(&picref);
+ }
+ return picref;
+}
+
+AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_frame(const AVFrame *frame,
+ int perms)
+{
+ AVFilterBufferRef *samplesref;
+ int channels = av_frame_get_channels(frame);
+ int64_t layout = av_frame_get_channel_layout(frame);
+
+ if (layout && av_get_channel_layout_nb_channels(layout) != av_frame_get_channels(frame)) {
+ av_log(NULL, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
+ return NULL;
+ }
+
+ samplesref = avfilter_get_audio_buffer_ref_from_arrays_channels(
+ (uint8_t **)frame->extended_data, frame->linesize[0], perms,
+ frame->nb_samples, frame->format, channels, layout);
+ if (!samplesref)
+ return NULL;
+ if (avfilter_copy_frame_props(samplesref, frame) < 0) {
+ samplesref->buf->data[0] = NULL;
+ avfilter_unref_bufferp(&samplesref);
+ }
+ return samplesref;
+}
+
+AVFilterBufferRef *avfilter_get_buffer_ref_from_frame(enum AVMediaType type,
+ const AVFrame *frame,
+ int perms)
+{
+ switch (type) {
+ case AVMEDIA_TYPE_VIDEO:
+ return avfilter_get_video_buffer_ref_from_frame(frame, perms);
+ case AVMEDIA_TYPE_AUDIO:
+ return avfilter_get_audio_buffer_ref_from_frame(frame, perms);
+ default:
+ return NULL;
+ }
+}
+
+int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src)
+{
+ int planes, nb_channels;
+
+ if (!dst)
+ return AVERROR(EINVAL);
+ /* abort in case the src is NULL and dst is not, avoid inconsistent state in dst */
+ av_assert0(src);
+
+ memcpy(dst->data, src->data, sizeof(dst->data));
+ memcpy(dst->linesize, src->linesize, sizeof(dst->linesize));
+
+ dst->pts = src->pts;
+ dst->format = src->format;
+ av_frame_set_pkt_pos(dst, src->pos);
+
+ switch (src->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ av_assert0(src->video);
+ dst->width = src->video->w;
+ dst->height = src->video->h;
+ dst->sample_aspect_ratio = src->video->sample_aspect_ratio;
+ dst->interlaced_frame = src->video->interlaced;
+ dst->top_field_first = src->video->top_field_first;
+ dst->key_frame = src->video->key_frame;
+ dst->pict_type = src->video->pict_type;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ av_assert0(src->audio);
+ nb_channels = av_get_channel_layout_nb_channels(src->audio->channel_layout);
+ planes = av_sample_fmt_is_planar(src->format) ? nb_channels : 1;
+
+ if (planes > FF_ARRAY_ELEMS(dst->data)) {
+ dst->extended_data = av_mallocz_array(planes, sizeof(*dst->extended_data));
+ if (!dst->extended_data)
+ return AVERROR(ENOMEM);
+ memcpy(dst->extended_data, src->extended_data,
+ planes * sizeof(*dst->extended_data));
+ } else
+ dst->extended_data = dst->data;
+ dst->nb_samples = src->audio->nb_samples;
+ av_frame_set_sample_rate (dst, src->audio->sample_rate);
+ av_frame_set_channel_layout(dst, src->audio->channel_layout);
+ av_frame_set_channels (dst, src->audio->channels);
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+#endif
diff --git a/libavfilter/avcodec.h b/libavfilter/avcodec.h
new file mode 100644
index 0000000000..d3d0e20e71
--- /dev/null
+++ b/libavfilter/avcodec.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_AVCODEC_H
+#define AVFILTER_AVCODEC_H
+
+/**
+ * @file
+ * libavcodec/libavfilter gluing utilities
+ *
+ * This should be included in an application ONLY if the installed
+ * libavfilter has been compiled with libavcodec support, otherwise
+ * symbols defined below will not be available.
+ */
+
+#include "avfilter.h"
+
+#if FF_API_AVFILTERBUFFER
+/**
+ * Create and return a picref reference from the data and properties
+ * contained in frame.
+ *
+ * @param perms permissions to assign to the new buffer reference
+ * @deprecated avfilter APIs work natively with AVFrame instead.
+ */
+attribute_deprecated
+AVFilterBufferRef *avfilter_get_video_buffer_ref_from_frame(const AVFrame *frame, int perms);
+
+
+/**
+ * Create and return a picref reference from the data and properties
+ * contained in frame.
+ *
+ * @param perms permissions to assign to the new buffer reference
+ * @deprecated avfilter APIs work natively with AVFrame instead.
+ */
+attribute_deprecated
+AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_frame(const AVFrame *frame,
+ int perms);
+
+/**
+ * Create and return a buffer reference from the data and properties
+ * contained in frame.
+ *
+ * @param perms permissions to assign to the new buffer reference
+ * @deprecated avfilter APIs work natively with AVFrame instead.
+ */
+attribute_deprecated
+AVFilterBufferRef *avfilter_get_buffer_ref_from_frame(enum AVMediaType type,
+ const AVFrame *frame,
+ int perms);
+#endif
+
+#endif /* AVFILTER_AVCODEC_H */
diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c
new file mode 100644
index 0000000000..3027de37fc
--- /dev/null
+++ b/libavfilter/avf_avectorscope.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio to video multimedia vectorscope filter
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "audio.h"
+#include "video.h"
+#include "internal.h"
+
+enum VectorScopeMode {
+ LISSAJOUS,
+ LISSAJOUS_XY,
+ MODE_NB,
+};
+
+typedef struct AudioVectorScopeContext {
+ const AVClass *class;
+ AVFrame *outpicref;
+ int w, h;
+ int hw, hh;
+ int mode;
+ int contrast[3];
+ int fade[3];
+ double zoom;
+ AVRational frame_rate;
+} AudioVectorScopeContext;
+
+#define OFFSET(x) offsetof(AudioVectorScopeContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption avectorscope_options[] = {
+ { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=LISSAJOUS}, 0, MODE_NB-1, FLAGS, "mode" },
+ { "m", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=LISSAJOUS}, 0, MODE_NB-1, FLAGS, "mode" },
+ { "lissajous", "", 0, AV_OPT_TYPE_CONST, {.i64=LISSAJOUS}, 0, 0, FLAGS, "mode" },
+ { "lissajous_xy", "", 0, AV_OPT_TYPE_CONST, {.i64=LISSAJOUS_XY}, 0, 0, FLAGS, "mode" },
+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS },
+ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS },
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="400x400"}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="400x400"}, 0, 0, FLAGS },
+ { "rc", "set red contrast", OFFSET(contrast[0]), AV_OPT_TYPE_INT, {.i64=40}, 0, 255, FLAGS },
+ { "gc", "set green contrast", OFFSET(contrast[1]), AV_OPT_TYPE_INT, {.i64=160}, 0, 255, FLAGS },
+ { "bc", "set blue contrast", OFFSET(contrast[2]), AV_OPT_TYPE_INT, {.i64=80}, 0, 255, FLAGS },
+ { "rf", "set red fade", OFFSET(fade[0]), AV_OPT_TYPE_INT, {.i64=15}, 0, 255, FLAGS },
+ { "gf", "set green fade", OFFSET(fade[1]), AV_OPT_TYPE_INT, {.i64=10}, 0, 255, FLAGS },
+ { "bf", "set blue fade", OFFSET(fade[2]), AV_OPT_TYPE_INT, {.i64=5}, 0, 255, FLAGS },
+ { "zoom", "set zoom factor", OFFSET(zoom), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 1, 10, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(avectorscope);
+
+static void draw_dot(AudioVectorScopeContext *s, unsigned x, unsigned y)
+{
+ const int linesize = s->outpicref->linesize[0];
+ uint8_t *dst;
+
+ if (s->zoom > 1) {
+ if (y >= s->h || x >= s->w)
+ return;
+ } else {
+ y = FFMIN(y, s->h - 1);
+ x = FFMIN(x, s->w - 1);
+ }
+
+ dst = &s->outpicref->data[0][y * linesize + x * 4];
+ dst[0] = FFMIN(dst[0] + s->contrast[0], 255);
+ dst[1] = FFMIN(dst[1] + s->contrast[1], 255);
+ dst[2] = FFMIN(dst[2] + s->contrast[2], 255);
+}
+
+static void fade(AudioVectorScopeContext *s)
+{
+ const int linesize = s->outpicref->linesize[0];
+ int i, j;
+
+ if (s->fade[0] || s->fade[1] || s->fade[2]) {
+ uint8_t *d = s->outpicref->data[0];
+ for (i = 0; i < s->h; i++) {
+ for (j = 0; j < s->w*4; j+=4) {
+ d[j+0] = FFMAX(d[j+0] - s->fade[0], 0);
+ d[j+1] = FFMAX(d[j+1] - s->fade[1], 0);
+ d[j+2] = FFMAX(d[j+2] - s->fade[2], 0);
+ }
+ d += linesize;
+ }
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layout = NULL;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE };
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE };
+
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_formats);
+
+ ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
+ ff_channel_layouts_ref(layout, &inlink->out_channel_layouts);
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_samplerates);
+
+ formats = ff_make_format_list(pix_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &outlink->in_formats);
+
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AudioVectorScopeContext *s = ctx->priv;
+ int nb_samples;
+
+ nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5);
+ inlink->partial_buf_size =
+ inlink->min_samples =
+ inlink->max_samples = nb_samples;
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AudioVectorScopeContext *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;
+
+ s->hw = s->w / 2;
+ s->hh = s->h / 2;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AudioVectorScopeContext *s = ctx->priv;
+ const int hw = s->hw;
+ const int hh = s->hh;
+ unsigned x, y;
+ const double zoom = s->zoom;
+ int i;
+
+ if (!s->outpicref || s->outpicref->width != outlink->w ||
+ s->outpicref->height != outlink->h) {
+ av_frame_free(&s->outpicref);
+ s->outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!s->outpicref) {
+ av_frame_free(&insamples);
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < outlink->h; i++)
+ memset(s->outpicref->data[0] + i * s->outpicref->linesize[0], 0, outlink->w * 4);
+ }
+ s->outpicref->pts = insamples->pts;
+
+ fade(s);
+
+ switch (insamples->format) {
+ case AV_SAMPLE_FMT_S16:
+ for (i = 0; i < insamples->nb_samples; i++) {
+ int16_t *src = (int16_t *)insamples->data[0] + i * 2;
+
+ if (s->mode == LISSAJOUS) {
+ x = ((src[1] - src[0]) * zoom / (float)(UINT16_MAX) + 1) * hw;
+ y = (1.0 - (src[0] + src[1]) * zoom / (float)UINT16_MAX) * hh;
+ } else {
+ x = (src[1] * zoom / (float)INT16_MAX + 1) * hw;
+ y = (src[0] * zoom / (float)INT16_MAX + 1) * hh;
+ }
+
+ draw_dot(s, x, y);
+ }
+ break;
+ case AV_SAMPLE_FMT_FLT:
+ for (i = 0; i < insamples->nb_samples; i++) {
+ float *src = (float *)insamples->data[0] + i * 2;
+
+ if (s->mode == LISSAJOUS) {
+ x = ((src[1] - src[0]) * zoom / 2 + 1) * hw;
+ y = (1.0 - (src[0] + src[1]) * zoom / 2) * hh;
+ } else {
+ x = (src[1] * zoom + 1) * hw;
+ y = (src[0] * zoom + 1) * hh;
+ }
+
+ draw_dot(s, x, y);
+ }
+ break;
+ }
+
+ av_frame_free(&insamples);
+
+ return ff_filter_frame(outlink, av_frame_clone(s->outpicref));
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AudioVectorScopeContext *s = ctx->priv;
+
+ av_frame_free(&s->outpicref);
+}
+
+static const AVFilterPad audiovectorscope_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad audiovectorscope_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_avf_avectorscope = {
+ .name = "avectorscope",
+ .description = NULL_IF_CONFIG_SMALL("Convert input audio to vectorscope video output."),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(AudioVectorScopeContext),
+ .inputs = audiovectorscope_inputs,
+ .outputs = audiovectorscope_outputs,
+ .priv_class = &avectorscope_class,
+};
diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c
new file mode 100644
index 0000000000..088d782d46
--- /dev/null
+++ b/libavfilter/avf_concat.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * concat audio-video filter
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#define FF_BUFQUEUE_SIZE 256
+#include "bufferqueue.h"
+#include "internal.h"
+#include "video.h"
+#include "audio.h"
+
+#define TYPE_ALL 2
+
+typedef struct {
+ const AVClass *class;
+ unsigned nb_streams[TYPE_ALL]; /**< number of out streams of each type */
+ unsigned nb_segments;
+ unsigned cur_idx; /**< index of the first input of current segment */
+ int64_t delta_ts; /**< timestamp to add to produce output timestamps */
+ unsigned nb_in_active; /**< number of active inputs in current segment */
+ unsigned unsafe;
+ struct concat_in {
+ int64_t pts;
+ int64_t nb_frames;
+ unsigned eof;
+ struct FFBufQueue queue;
+ } *in;
+} ConcatContext;
+
+#define OFFSET(x) offsetof(ConcatContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define F AV_OPT_FLAG_FILTERING_PARAM
+#define V AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption concat_options[] = {
+ { "n", "specify the number of segments", OFFSET(nb_segments),
+ AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, V|A|F},
+ { "v", "specify the number of video streams",
+ OFFSET(nb_streams[AVMEDIA_TYPE_VIDEO]),
+ AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, V|F },
+ { "a", "specify the number of audio streams",
+ OFFSET(nb_streams[AVMEDIA_TYPE_AUDIO]),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A|F},
+ { "unsafe", "enable unsafe mode",
+ OFFSET(unsafe),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V|A|F},
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(concat);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ ConcatContext *cat = ctx->priv;
+ unsigned type, nb_str, idx0 = 0, idx, str, seg;
+ AVFilterFormats *formats, *rates = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+
+ for (type = 0; type < TYPE_ALL; type++) {
+ nb_str = cat->nb_streams[type];
+ for (str = 0; str < nb_str; str++) {
+ idx = idx0;
+
+ /* Set the output formats */
+ formats = ff_all_formats(type);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &ctx->outputs[idx]->in_formats);
+ if (type == AVMEDIA_TYPE_AUDIO) {
+ rates = ff_all_samplerates();
+ if (!rates)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(rates, &ctx->outputs[idx]->in_samplerates);
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_channel_layouts_ref(layouts, &ctx->outputs[idx]->in_channel_layouts);
+ }
+
+ /* Set the same formats for each corresponding input */
+ for (seg = 0; seg < cat->nb_segments; seg++) {
+ ff_formats_ref(formats, &ctx->inputs[idx]->out_formats);
+ if (type == AVMEDIA_TYPE_AUDIO) {
+ ff_formats_ref(rates, &ctx->inputs[idx]->out_samplerates);
+ ff_channel_layouts_ref(layouts, &ctx->inputs[idx]->out_channel_layouts);
+ }
+ idx += ctx->nb_outputs;
+ }
+
+ idx0++;
+ }
+ }
+ return 0;
+}
+
+static int config_output(AVFilterLink *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];
+
+ /* enhancement: find a common one */
+ outlink->time_base = AV_TIME_BASE_Q;
+ outlink->w = inlink->w;
+ outlink->h = inlink->h;
+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+ outlink->format = inlink->format;
+ for (seg = 1; seg < cat->nb_segments; seg++) {
+ inlink = ctx->inputs[in_no += ctx->nb_outputs];
+ if (!outlink->sample_aspect_ratio.num)
+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+ /* possible enhancement: unsafe mode, do not check */
+ if (outlink->w != inlink->w ||
+ outlink->h != inlink->h ||
+ outlink->sample_aspect_ratio.num != inlink->sample_aspect_ratio.num &&
+ inlink->sample_aspect_ratio.num ||
+ outlink->sample_aspect_ratio.den != inlink->sample_aspect_ratio.den) {
+ av_log(ctx, AV_LOG_ERROR, "Input link %s parameters "
+ "(size %dx%d, SAR %d:%d) do not match the corresponding "
+ "output link %s parameters (%dx%d, SAR %d:%d)\n",
+ ctx->input_pads[in_no].name, inlink->w, inlink->h,
+ inlink->sample_aspect_ratio.num,
+ inlink->sample_aspect_ratio.den,
+ ctx->input_pads[out_no].name, outlink->w, outlink->h,
+ outlink->sample_aspect_ratio.num,
+ outlink->sample_aspect_ratio.den);
+ if (!cat->unsafe)
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return 0;
+}
+
+static int push_frame(AVFilterContext *ctx, unsigned in_no, AVFrame *buf)
+{
+ ConcatContext *cat = ctx->priv;
+ unsigned out_no = in_no % ctx->nb_outputs;
+ AVFilterLink * inlink = ctx-> inputs[ in_no];
+ AVFilterLink *outlink = ctx->outputs[out_no];
+ struct concat_in *in = &cat->in[in_no];
+
+ buf->pts = av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
+ in->pts = buf->pts;
+ in->nb_frames++;
+ /* add duration to input PTS */
+ if (inlink->sample_rate)
+ /* use number of audio samples */
+ in->pts += av_rescale_q(buf->nb_samples,
+ av_make_q(1, inlink->sample_rate),
+ outlink->time_base);
+ else if (in->nb_frames >= 2)
+ /* use mean duration */
+ in->pts = av_rescale(in->pts, in->nb_frames, in->nb_frames - 1);
+
+ buf->pts += cat->delta_ts;
+ return ff_filter_frame(outlink, buf);
+}
+
+static int process_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ConcatContext *cat = ctx->priv;
+ unsigned in_no = FF_INLINK_IDX(inlink);
+
+ if (in_no < cat->cur_idx) {
+ av_log(ctx, AV_LOG_ERROR, "Frame after EOF on input %s\n",
+ ctx->input_pads[in_no].name);
+ av_frame_free(&buf);
+ } else if (in_no >= cat->cur_idx + ctx->nb_outputs) {
+ ff_bufqueue_add(ctx, &cat->in[in_no].queue, buf);
+ } else {
+ return push_frame(ctx, in_no, buf);
+ }
+ return 0;
+}
+
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
+{
+ AVFilterContext *ctx = inlink->dst;
+ unsigned in_no = FF_INLINK_IDX(inlink);
+ AVFilterLink *outlink = ctx->outputs[in_no % ctx->nb_outputs];
+
+ return ff_get_video_buffer(outlink, w, h);
+}
+
+static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ unsigned in_no = FF_INLINK_IDX(inlink);
+ AVFilterLink *outlink = ctx->outputs[in_no % ctx->nb_outputs];
+
+ return ff_get_audio_buffer(outlink, nb_samples);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ return process_frame(inlink, buf);
+}
+
+static void close_input(AVFilterContext *ctx, unsigned in_no)
+{
+ ConcatContext *cat = ctx->priv;
+
+ cat->in[in_no].eof = 1;
+ cat->nb_in_active--;
+ av_log(ctx, AV_LOG_VERBOSE, "EOF on %s, %d streams left in segment.\n",
+ ctx->input_pads[in_no].name, cat->nb_in_active);
+}
+
+static void find_next_delta_ts(AVFilterContext *ctx, int64_t *seg_delta)
+{
+ ConcatContext *cat = ctx->priv;
+ unsigned i = cat->cur_idx;
+ unsigned imax = i + ctx->nb_outputs;
+ int64_t pts;
+
+ pts = cat->in[i++].pts;
+ for (; i < imax; i++)
+ pts = FFMAX(pts, cat->in[i].pts);
+ cat->delta_ts += pts;
+ *seg_delta = pts;
+}
+
+static int send_silence(AVFilterContext *ctx, unsigned in_no, unsigned out_no,
+ int64_t seg_delta)
+{
+ ConcatContext *cat = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[out_no];
+ int64_t base_pts = cat->in[in_no].pts + cat->delta_ts - seg_delta;
+ int64_t nb_samples, sent = 0;
+ int frame_nb_samples, ret;
+ AVRational rate_tb = { 1, ctx->inputs[in_no]->sample_rate };
+ AVFrame *buf;
+ int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
+
+ if (!rate_tb.den)
+ return AVERROR_BUG;
+ nb_samples = av_rescale_q(seg_delta - cat->in[in_no].pts,
+ outlink->time_base, rate_tb);
+ frame_nb_samples = FFMAX(9600, rate_tb.den / 5); /* arbitrary */
+ while (nb_samples) {
+ frame_nb_samples = FFMIN(frame_nb_samples, nb_samples);
+ buf = ff_get_audio_buffer(outlink, frame_nb_samples);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ av_samples_set_silence(buf->extended_data, 0, frame_nb_samples,
+ nb_channels, outlink->format);
+ buf->pts = base_pts + av_rescale_q(sent, rate_tb, outlink->time_base);
+ ret = ff_filter_frame(outlink, buf);
+ if (ret < 0)
+ return ret;
+ sent += frame_nb_samples;
+ nb_samples -= frame_nb_samples;
+ }
+ return 0;
+}
+
+static int flush_segment(AVFilterContext *ctx)
+{
+ int ret;
+ ConcatContext *cat = ctx->priv;
+ unsigned str, str_max;
+ int64_t seg_delta;
+
+ find_next_delta_ts(ctx, &seg_delta);
+ cat->cur_idx += ctx->nb_outputs;
+ cat->nb_in_active = ctx->nb_outputs;
+ av_log(ctx, AV_LOG_VERBOSE, "Segment finished at pts=%"PRId64"\n",
+ cat->delta_ts);
+
+ if (cat->cur_idx < ctx->nb_inputs) {
+ /* pad audio streams with silence */
+ str = cat->nb_streams[AVMEDIA_TYPE_VIDEO];
+ str_max = str + cat->nb_streams[AVMEDIA_TYPE_AUDIO];
+ for (; str < str_max; str++) {
+ ret = send_silence(ctx, cat->cur_idx - ctx->nb_outputs + str, str,
+ seg_delta);
+ if (ret < 0)
+ return ret;
+ }
+ /* flush queued buffers */
+ /* possible enhancement: flush in PTS order */
+ str_max = cat->cur_idx + ctx->nb_outputs;
+ for (str = cat->cur_idx; str < str_max; str++) {
+ while (cat->in[str].queue.available) {
+ ret = push_frame(ctx, str, ff_bufqueue_get(&cat->in[str].queue));
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ConcatContext *cat = ctx->priv;
+ unsigned out_no = FF_OUTLINK_IDX(outlink);
+ unsigned in_no = out_no + cat->cur_idx;
+ unsigned str, str_max;
+ int ret;
+
+ while (1) {
+ if (in_no >= ctx->nb_inputs)
+ return AVERROR_EOF;
+ if (!cat->in[in_no].eof) {
+ ret = ff_request_frame(ctx->inputs[in_no]);
+ if (ret != AVERROR_EOF)
+ return ret;
+ close_input(ctx, in_no);
+ }
+ /* cycle on all inputs to finish the segment */
+ /* possible enhancement: request in PTS order */
+ str_max = cat->cur_idx + ctx->nb_outputs - 1;
+ for (str = cat->cur_idx; cat->nb_in_active;
+ str = str == str_max ? cat->cur_idx : str + 1) {
+ if (cat->in[str].eof)
+ continue;
+ ret = ff_request_frame(ctx->inputs[str]);
+ if (ret == AVERROR_EOF)
+ close_input(ctx, str);
+ else if (ret < 0)
+ return ret;
+ }
+ ret = flush_segment(ctx);
+ if (ret < 0)
+ return ret;
+ in_no += ctx->nb_outputs;
+ }
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ConcatContext *cat = ctx->priv;
+ unsigned seg, type, str;
+
+ /* create input pads */
+ for (seg = 0; seg < cat->nb_segments; seg++) {
+ for (type = 0; type < TYPE_ALL; type++) {
+ for (str = 0; str < cat->nb_streams[type]; str++) {
+ AVFilterPad pad = {
+ .type = type,
+ .get_video_buffer = get_video_buffer,
+ .get_audio_buffer = get_audio_buffer,
+ .filter_frame = filter_frame,
+ };
+ pad.name = av_asprintf("in%d:%c%d", seg, "va"[type], str);
+ ff_insert_inpad(ctx, ctx->nb_inputs, &pad);
+ }
+ }
+ }
+ /* create output pads */
+ for (type = 0; type < TYPE_ALL; type++) {
+ for (str = 0; str < cat->nb_streams[type]; str++) {
+ AVFilterPad pad = {
+ .type = type,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ };
+ pad.name = av_asprintf("out:%c%d", "va"[type], str);
+ ff_insert_outpad(ctx, ctx->nb_outputs, &pad);
+ }
+ }
+
+ cat->in = av_calloc(ctx->nb_inputs, sizeof(*cat->in));
+ if (!cat->in)
+ return AVERROR(ENOMEM);
+ cat->nb_in_active = ctx->nb_outputs;
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ConcatContext *cat = ctx->priv;
+ unsigned i;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ av_freep(&ctx->input_pads[i].name);
+ ff_bufqueue_discard_all(&cat->in[i].queue);
+ }
+ for (i = 0; i < ctx->nb_outputs; i++)
+ av_freep(&ctx->output_pads[i].name);
+ av_freep(&cat->in);
+}
+
+AVFilter ff_avf_concat = {
+ .name = "concat",
+ .description = NULL_IF_CONFIG_SMALL("Concatenate audio and video streams."),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(ConcatContext),
+ .inputs = NULL,
+ .outputs = NULL,
+ .priv_class = &concat_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
diff --git a/libavfilter/avf_showcqt.c b/libavfilter/avf_showcqt.c
new file mode 100644
index 0000000000..85f9ea97fa
--- /dev/null
+++ b/libavfilter/avf_showcqt.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (c) 2014 Muhammad Faiz <mfcc64@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
+ */
+
+#include "config.h"
+#include "libavcodec/avfft.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/xga_font_data.h"
+#include "libavutil/qsort.h"
+#include "libavutil/time.h"
+#include "libavutil/eval.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#if CONFIG_LIBFREETYPE
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#endif
+
+/* this filter is designed to do 16 bins/semitones constant Q transform with Brown-Puckette algorithm
+ * start from E0 to D#10 (10 octaves)
+ * so there are 16 bins/semitones * 12 semitones/octaves * 10 octaves = 1920 bins
+ * match with full HD resolution */
+
+#define VIDEO_WIDTH 1920
+#define VIDEO_HEIGHT 1080
+#define FONT_HEIGHT 32
+#define SPECTOGRAM_HEIGHT ((VIDEO_HEIGHT-FONT_HEIGHT)/2)
+#define SPECTOGRAM_START (VIDEO_HEIGHT-SPECTOGRAM_HEIGHT)
+#define BASE_FREQ 20.051392800492
+#define COEFF_CLAMP 1.0e-4
+#define TLENGTH_MIN 0.001
+#define TLENGTH_DEFAULT "384/f*tc/(384/f+tc)"
+#define VOLUME_MIN 1e-10
+#define VOLUME_MAX 100.0
+#define FONTCOLOR_DEFAULT "st(0, (midi(f)-59.5)/12);" \
+ "st(1, if(between(ld(0),0,1), 0.5-0.5*cos(2*PI*ld(0)), 0));" \
+ "r(1-ld(1)) + b(ld(1))"
+
+typedef struct {
+ FFTSample value;
+ int index;
+} SparseCoeff;
+
+typedef struct {
+ const AVClass *class;
+ AVFrame *outpicref;
+ FFTContext *fft_context;
+ FFTComplex *fft_data;
+ FFTComplex *fft_result_left;
+ FFTComplex *fft_result_right;
+ uint8_t *spectogram;
+ SparseCoeff *coeff_sort;
+ SparseCoeff *coeffs[VIDEO_WIDTH];
+ uint8_t *font_alpha;
+ char *fontfile; /* using freetype */
+ int coeffs_len[VIDEO_WIDTH];
+ uint8_t fontcolor_value[VIDEO_WIDTH*3]; /* result of fontcolor option */
+ int64_t frame_count;
+ int spectogram_count;
+ int spectogram_index;
+ int fft_bits;
+ int req_fullfilled;
+ int remaining_fill;
+ char *tlength;
+ char *volume;
+ char *fontcolor;
+ double timeclamp; /* lower timeclamp, time-accurate, higher timeclamp, freq-accurate (at low freq)*/
+ float coeffclamp; /* lower coeffclamp, more precise, higher coeffclamp, faster */
+ int fullhd; /* if true, output video is at full HD resolution, otherwise it will be halved */
+ float gamma; /* lower gamma, more contrast, higher gamma, more range */
+ float gamma2; /* gamma of bargraph */
+ int fps; /* the required fps is so strict, so it's enough to be int, but 24000/1001 etc cannot be encoded */
+ int count; /* fps * count = transform rate */
+} ShowCQTContext;
+
+#define OFFSET(x) offsetof(ShowCQTContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption showcqt_options[] = {
+ { "volume", "set volume", OFFSET(volume), AV_OPT_TYPE_STRING, { .str = "16" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "tlength", "set transform length", OFFSET(tlength), AV_OPT_TYPE_STRING, { .str = TLENGTH_DEFAULT }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "timeclamp", "set timeclamp", OFFSET(timeclamp), AV_OPT_TYPE_DOUBLE, { .dbl = 0.17 }, 0.1, 1.0, FLAGS },
+ { "coeffclamp", "set coeffclamp", OFFSET(coeffclamp), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, 0.1, 10, FLAGS },
+ { "gamma", "set gamma", OFFSET(gamma), AV_OPT_TYPE_FLOAT, { .dbl = 3 }, 1, 7, FLAGS },
+ { "gamma2", "set gamma of bargraph", OFFSET(gamma2), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, 1, 7, FLAGS },
+ { "fullhd", "set full HD resolution", OFFSET(fullhd), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
+ { "fps", "set video fps", OFFSET(fps), AV_OPT_TYPE_INT, { .i64 = 25 }, 10, 100, FLAGS },
+ { "count", "set number of transform per frame", OFFSET(count), AV_OPT_TYPE_INT, { .i64 = 6 }, 1, 30, FLAGS },
+ { "fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "fontcolor", "set font color", OFFSET(fontcolor), AV_OPT_TYPE_STRING, { .str = FONTCOLOR_DEFAULT }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(showcqt);
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int k;
+
+ ShowCQTContext *s = ctx->priv;
+ av_fft_end(s->fft_context);
+ s->fft_context = NULL;
+ for (k = 0; k < VIDEO_WIDTH; k++)
+ av_freep(&s->coeffs[k]);
+ av_freep(&s->fft_data);
+ av_freep(&s->fft_result_left);
+ av_freep(&s->fft_result_right);
+ av_freep(&s->coeff_sort);
+ av_freep(&s->spectogram);
+ av_freep(&s->font_alpha);
+ av_frame_free(&s->outpicref);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE };
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
+ static const int64_t channel_layouts[] = { AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_STEREO_DOWNMIX, -1 };
+ static const int samplerates[] = { 44100, 48000, -1 };
+
+ /* set input audio formats */
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_formats);
+
+ layouts = avfilter_make_format64_list(channel_layouts);
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+
+ formats = ff_make_format_list(samplerates);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_samplerates);
+
+ /* set output video format */
+ formats = ff_make_format_list(pix_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &outlink->in_formats);
+
+ return 0;
+}
+
+#if CONFIG_LIBFREETYPE
+static void load_freetype_font(AVFilterContext *ctx)
+{
+ static const char str[] = "EF G A BC D ";
+ ShowCQTContext *s = ctx->priv;
+ FT_Library lib = NULL;
+ FT_Face face = NULL;
+ int video_scale = s->fullhd ? 2 : 1;
+ int video_width = (VIDEO_WIDTH/2) * video_scale;
+ int font_height = (FONT_HEIGHT/2) * video_scale;
+ int font_width = 8 * video_scale;
+ int font_repeat = font_width * 12;
+ int linear_hori_advance = font_width * 65536;
+ int non_monospace_warning = 0;
+ int x;
+
+ s->font_alpha = NULL;
+
+ if (!s->fontfile)
+ return;
+
+ if (FT_Init_FreeType(&lib))
+ goto fail;
+
+ if (FT_New_Face(lib, s->fontfile, 0, &face))
+ goto fail;
+
+ if (FT_Set_Char_Size(face, 16*64, 0, 0, 0))
+ goto fail;
+
+ if (FT_Load_Char(face, 'A', FT_LOAD_RENDER))
+ goto fail;
+
+ if (FT_Set_Char_Size(face, 16*64 * linear_hori_advance / face->glyph->linearHoriAdvance, 0, 0, 0))
+ goto fail;
+
+ s->font_alpha = av_malloc_array(font_height, video_width);
+ if (!s->font_alpha)
+ goto fail;
+
+ memset(s->font_alpha, 0, font_height * video_width);
+
+ for (x = 0; x < 12; x++) {
+ int sx, sy, rx, bx, by, dx, dy;
+
+ if (str[x] == ' ')
+ continue;
+
+ if (FT_Load_Char(face, str[x], FT_LOAD_RENDER))
+ goto fail;
+
+ if (face->glyph->advance.x != font_width*64 && !non_monospace_warning) {
+ av_log(ctx, AV_LOG_WARNING, "Font is not monospace\n");
+ non_monospace_warning = 1;
+ }
+
+ sy = font_height - 4*video_scale - face->glyph->bitmap_top;
+ for (rx = 0; rx < 10; rx++) {
+ sx = rx * font_repeat + x * font_width + face->glyph->bitmap_left;
+ for (by = 0; by < face->glyph->bitmap.rows; by++) {
+ dy = by + sy;
+ if (dy < 0)
+ continue;
+ if (dy >= font_height)
+ break;
+
+ for (bx = 0; bx < face->glyph->bitmap.width; bx++) {
+ dx = bx + sx;
+ if (dx < 0)
+ continue;
+ if (dx >= video_width)
+ break;
+ s->font_alpha[dy*video_width+dx] = face->glyph->bitmap.buffer[by*face->glyph->bitmap.width+bx];
+ }
+ }
+ }
+ }
+
+ FT_Done_Face(face);
+ FT_Done_FreeType(lib);
+ return;
+
+ fail:
+ av_log(ctx, AV_LOG_WARNING, "Error while loading freetype font, using default font instead\n");
+ FT_Done_Face(face);
+ FT_Done_FreeType(lib);
+ av_freep(&s->font_alpha);
+ return;
+}
+#endif
+
+static double a_weighting(void *p, double f)
+{
+ double ret = 12200.0*12200.0 * (f*f*f*f);
+ ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) *
+ sqrt((f*f + 107.7*107.7) * (f*f + 737.9*737.9));
+ return ret;
+}
+
+static double b_weighting(void *p, double f)
+{
+ double ret = 12200.0*12200.0 * (f*f*f);
+ ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0) * sqrt(f*f + 158.5*158.5);
+ return ret;
+}
+
+static double c_weighting(void *p, double f)
+{
+ double ret = 12200.0*12200.0 * (f*f);
+ ret /= (f*f + 20.6*20.6) * (f*f + 12200.0*12200.0);
+ return ret;
+}
+
+static double midi(void *p, double f)
+{
+ return log2(f/440.0) * 12.0 + 69.0;
+}
+
+static double r_func(void *p, double x)
+{
+ x = av_clipd(x, 0.0, 1.0);
+ return (int)(x*255.0+0.5) << 16;
+}
+
+static double g_func(void *p, double x)
+{
+ x = av_clipd(x, 0.0, 1.0);
+ return (int)(x*255.0+0.5) << 8;
+}
+
+static double b_func(void *p, double x)
+{
+ x = av_clipd(x, 0.0, 1.0);
+ return (int)(x*255.0+0.5);
+}
+
+static inline int qsort_sparsecoeff(const SparseCoeff *a, const SparseCoeff *b)
+{
+ if (fabsf(a->value) >= fabsf(b->value))
+ return 1;
+ else
+ return -1;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ShowCQTContext *s = ctx->priv;
+ AVExpr *tlength_expr = NULL, *volume_expr = NULL, *fontcolor_expr = NULL;
+ uint8_t *fontcolor_value = s->fontcolor_value;
+ static const char * const expr_vars[] = { "timeclamp", "tc", "frequency", "freq", "f", NULL };
+ static const char * const expr_func_names[] = { "a_weighting", "b_weighting", "c_weighting", NULL };
+ static const char * const expr_fontcolor_func_names[] = { "midi", "r", "g", "b", NULL };
+ static double (* const expr_funcs[])(void *, double) = { a_weighting, b_weighting, c_weighting, NULL };
+ static double (* const expr_fontcolor_funcs[])(void *, double) = { midi, r_func, g_func, b_func, NULL };
+ int fft_len, k, x, y, ret;
+ int num_coeffs = 0;
+ int rate = inlink->sample_rate;
+ double max_len = rate * (double) s->timeclamp;
+ int64_t start_time, end_time;
+ int video_scale = s->fullhd ? 2 : 1;
+ int video_width = (VIDEO_WIDTH/2) * video_scale;
+ int video_height = (VIDEO_HEIGHT/2) * video_scale;
+ int spectogram_height = (SPECTOGRAM_HEIGHT/2) * video_scale;
+
+ s->fft_bits = ceil(log2(max_len));
+ fft_len = 1 << s->fft_bits;
+
+ if (rate % (s->fps * s->count)) {
+ av_log(ctx, AV_LOG_ERROR, "Rate (%u) is not divisible by fps*count (%u*%u)\n", rate, s->fps, s->count);
+ return AVERROR(EINVAL);
+ }
+
+ s->fft_data = av_malloc_array(fft_len, sizeof(*s->fft_data));
+ s->coeff_sort = av_malloc_array(fft_len, sizeof(*s->coeff_sort));
+ s->fft_result_left = av_malloc_array(fft_len, sizeof(*s->fft_result_left));
+ s->fft_result_right = av_malloc_array(fft_len, sizeof(*s->fft_result_right));
+ s->fft_context = av_fft_init(s->fft_bits, 0);
+
+ if (!s->fft_data || !s->coeff_sort || !s->fft_result_left || !s->fft_result_right || !s->fft_context)
+ return AVERROR(ENOMEM);
+
+#if CONFIG_LIBFREETYPE
+ load_freetype_font(ctx);
+#else
+ if (s->fontfile)
+ av_log(ctx, AV_LOG_WARNING, "Freetype is not available, ignoring fontfile option\n");
+ s->font_alpha = NULL;
+#endif
+
+ av_log(ctx, AV_LOG_INFO, "Calculating spectral kernel, please wait\n");
+ start_time = av_gettime_relative();
+ ret = av_expr_parse(&tlength_expr, s->tlength, expr_vars, NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ goto eval_error;
+
+ ret = av_expr_parse(&volume_expr, s->volume, expr_vars, expr_func_names,
+ expr_funcs, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ goto eval_error;
+
+ ret = av_expr_parse(&fontcolor_expr, s->fontcolor, expr_vars, expr_fontcolor_func_names,
+ expr_fontcolor_funcs, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ goto eval_error;
+
+ for (k = 0; k < VIDEO_WIDTH; k++) {
+ int hlen = fft_len >> 1;
+ float total = 0;
+ float partial = 0;
+ double freq = BASE_FREQ * exp2(k * (1.0/192.0));
+ double tlen, tlength, volume;
+ double expr_vars_val[] = { s->timeclamp, s->timeclamp, freq, freq, freq, 0 };
+ /* a window function from Albert H. Nuttall,
+ * "Some Windows with Very Good Sidelobe Behavior"
+ * -93.32 dB peak sidelobe and 18 dB/octave asymptotic decay
+ * coefficient normalized to a0 = 1 */
+ double a0 = 0.355768;
+ double a1 = 0.487396/a0;
+ double a2 = 0.144232/a0;
+ double a3 = 0.012604/a0;
+ double sv_step, cv_step, sv, cv;
+ double sw_step, cw_step, sw, cw, w;
+
+ tlength = av_expr_eval(tlength_expr, expr_vars_val, NULL);
+ if (isnan(tlength)) {
+ av_log(ctx, AV_LOG_WARNING, "at freq %g: tlength is nan, setting it to %g\n", freq, s->timeclamp);
+ tlength = s->timeclamp;
+ } else if (tlength < TLENGTH_MIN) {
+ av_log(ctx, AV_LOG_WARNING, "at freq %g: tlength is %g, setting it to %g\n", freq, tlength, TLENGTH_MIN);
+ tlength = TLENGTH_MIN;
+ } else if (tlength > s->timeclamp) {
+ av_log(ctx, AV_LOG_WARNING, "at freq %g: tlength is %g, setting it to %g\n", freq, tlength, s->timeclamp);
+ tlength = s->timeclamp;
+ }
+
+ volume = FFABS(av_expr_eval(volume_expr, expr_vars_val, NULL));
+ if (isnan(volume)) {
+ av_log(ctx, AV_LOG_WARNING, "at freq %g: volume is nan, setting it to 0\n", freq);
+ volume = VOLUME_MIN;
+ } else if (volume < VOLUME_MIN) {
+ volume = VOLUME_MIN;
+ } else if (volume > VOLUME_MAX) {
+ av_log(ctx, AV_LOG_WARNING, "at freq %g: volume is %g, setting it to %g\n", freq, volume, VOLUME_MAX);
+ volume = VOLUME_MAX;
+ }
+
+ if (s->fullhd || !(k & 1)) {
+ int fontcolor = av_expr_eval(fontcolor_expr, expr_vars_val, NULL);
+ fontcolor_value[0] = (fontcolor >> 16) & 0xFF;
+ fontcolor_value[1] = (fontcolor >> 8) & 0xFF;
+ fontcolor_value[2] = fontcolor & 0xFF;
+ fontcolor_value += 3;
+ }
+
+ tlen = tlength * rate;
+ s->fft_data[0].re = 0;
+ s->fft_data[0].im = 0;
+ s->fft_data[hlen].re = (1.0 + a1 + a2 + a3) * (1.0/tlen) * volume * (1.0/fft_len);
+ s->fft_data[hlen].im = 0;
+ sv_step = sv = sin(2.0*M_PI*freq*(1.0/rate));
+ cv_step = cv = cos(2.0*M_PI*freq*(1.0/rate));
+ /* also optimizing window func */
+ sw_step = sw = sin(2.0*M_PI*(1.0/tlen));
+ cw_step = cw = cos(2.0*M_PI*(1.0/tlen));
+ for (x = 1; x < 0.5 * tlen; x++) {
+ double cv_tmp, cw_tmp;
+ double cw2, cw3, sw2;
+
+ cw2 = cw * cw - sw * sw;
+ sw2 = cw * sw + sw * cw;
+ cw3 = cw * cw2 - sw * sw2;
+ w = (1.0 + a1 * cw + a2 * cw2 + a3 * cw3) * (1.0/tlen) * volume * (1.0/fft_len);
+ s->fft_data[hlen + x].re = w * cv;
+ s->fft_data[hlen + x].im = w * sv;
+ s->fft_data[hlen - x].re = s->fft_data[hlen + x].re;
+ s->fft_data[hlen - x].im = -s->fft_data[hlen + x].im;
+
+ cv_tmp = cv * cv_step - sv * sv_step;
+ sv = sv * cv_step + cv * sv_step;
+ cv = cv_tmp;
+ cw_tmp = cw * cw_step - sw * sw_step;
+ sw = sw * cw_step + cw * sw_step;
+ cw = cw_tmp;
+ }
+ for (; x < hlen; x++) {
+ s->fft_data[hlen + x].re = 0;
+ s->fft_data[hlen + x].im = 0;
+ s->fft_data[hlen - x].re = 0;
+ s->fft_data[hlen - x].im = 0;
+ }
+ av_fft_permute(s->fft_context, s->fft_data);
+ av_fft_calc(s->fft_context, s->fft_data);
+
+ for (x = 0; x < fft_len; x++) {
+ s->coeff_sort[x].index = x;
+ s->coeff_sort[x].value = s->fft_data[x].re;
+ }
+
+ AV_QSORT(s->coeff_sort, fft_len, SparseCoeff, qsort_sparsecoeff);
+ for (x = 0; x < fft_len; x++)
+ total += fabsf(s->coeff_sort[x].value);
+
+ for (x = 0; x < fft_len; x++) {
+ partial += fabsf(s->coeff_sort[x].value);
+ if (partial > total * s->coeffclamp * COEFF_CLAMP) {
+ s->coeffs_len[k] = fft_len - x;
+ num_coeffs += s->coeffs_len[k];
+ s->coeffs[k] = av_malloc_array(s->coeffs_len[k], sizeof(*s->coeffs[k]));
+ if (!s->coeffs[k]) {
+ ret = AVERROR(ENOMEM);
+ goto eval_error;
+ }
+ for (y = 0; y < s->coeffs_len[k]; y++)
+ s->coeffs[k][y] = s->coeff_sort[x+y];
+ break;
+ }
+ }
+ }
+ av_expr_free(fontcolor_expr);
+ av_expr_free(volume_expr);
+ av_expr_free(tlength_expr);
+ end_time = av_gettime_relative();
+ av_log(ctx, AV_LOG_INFO, "Elapsed time %.6f s (fft_len=%u, num_coeffs=%u)\n", 1e-6 * (end_time-start_time), fft_len, num_coeffs);
+
+ outlink->w = video_width;
+ outlink->h = video_height;
+
+ s->req_fullfilled = 0;
+ s->spectogram_index = 0;
+ s->frame_count = 0;
+ s->spectogram_count = 0;
+ s->remaining_fill = fft_len >> 1;
+ memset(s->fft_data, 0, fft_len * sizeof(*s->fft_data));
+
+ s->outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!s->outpicref)
+ return AVERROR(ENOMEM);
+
+ s->spectogram = av_calloc(spectogram_height, s->outpicref->linesize[0]);
+ if (!s->spectogram)
+ return AVERROR(ENOMEM);
+
+ outlink->sample_aspect_ratio = av_make_q(1, 1);
+ outlink->time_base = av_make_q(1, s->fps);
+ outlink->frame_rate = av_make_q(s->fps, 1);
+ return 0;
+
+eval_error:
+ av_expr_free(fontcolor_expr);
+ av_expr_free(volume_expr);
+ av_expr_free(tlength_expr);
+ return ret;
+}
+
+static int plot_cqt(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ShowCQTContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int fft_len = 1 << s->fft_bits;
+ FFTSample result[VIDEO_WIDTH][4];
+ int x, y, ret = 0;
+ int linesize = s->outpicref->linesize[0];
+ int video_scale = s->fullhd ? 2 : 1;
+ int video_width = (VIDEO_WIDTH/2) * video_scale;
+ int spectogram_height = (SPECTOGRAM_HEIGHT/2) * video_scale;
+ int spectogram_start = (SPECTOGRAM_START/2) * video_scale;
+ int font_height = (FONT_HEIGHT/2) * video_scale;
+
+ /* real part contains left samples, imaginary part contains right samples */
+ memcpy(s->fft_result_left, s->fft_data, fft_len * sizeof(*s->fft_data));
+ av_fft_permute(s->fft_context, s->fft_result_left);
+ av_fft_calc(s->fft_context, s->fft_result_left);
+
+ /* separate left and right, (and multiply by 2.0) */
+ s->fft_result_right[0].re = 2.0f * s->fft_result_left[0].im;
+ s->fft_result_right[0].im = 0;
+ s->fft_result_left[0].re = 2.0f * s->fft_result_left[0].re;
+ s->fft_result_left[0].im = 0;
+ for (x = 1; x <= fft_len >> 1; x++) {
+ FFTSample tmpy = s->fft_result_left[fft_len-x].im - s->fft_result_left[x].im;
+
+ s->fft_result_right[x].re = s->fft_result_left[x].im + s->fft_result_left[fft_len-x].im;
+ s->fft_result_right[x].im = s->fft_result_left[x].re - s->fft_result_left[fft_len-x].re;
+ s->fft_result_right[fft_len-x].re = s->fft_result_right[x].re;
+ s->fft_result_right[fft_len-x].im = -s->fft_result_right[x].im;
+
+ s->fft_result_left[x].re = s->fft_result_left[x].re + s->fft_result_left[fft_len-x].re;
+ s->fft_result_left[x].im = tmpy;
+ s->fft_result_left[fft_len-x].re = s->fft_result_left[x].re;
+ s->fft_result_left[fft_len-x].im = -s->fft_result_left[x].im;
+ }
+
+ /* calculating cqt */
+ for (x = 0; x < VIDEO_WIDTH; x++) {
+ int u;
+ FFTComplex l = {0,0};
+ FFTComplex r = {0,0};
+
+ for (u = 0; u < s->coeffs_len[x]; u++) {
+ FFTSample value = s->coeffs[x][u].value;
+ int index = s->coeffs[x][u].index;
+ l.re += value * s->fft_result_left[index].re;
+ l.im += value * s->fft_result_left[index].im;
+ r.re += value * s->fft_result_right[index].re;
+ r.im += value * s->fft_result_right[index].im;
+ }
+ /* result is power, not amplitude */
+ result[x][0] = l.re * l.re + l.im * l.im;
+ result[x][2] = r.re * r.re + r.im * r.im;
+ result[x][1] = 0.5f * (result[x][0] + result[x][2]);
+
+ if (s->gamma2 == 1.0f)
+ result[x][3] = result[x][1];
+ else if (s->gamma2 == 2.0f)
+ result[x][3] = sqrtf(result[x][1]);
+ else if (s->gamma2 == 3.0f)
+ result[x][3] = cbrtf(result[x][1]);
+ else if (s->gamma2 == 4.0f)
+ result[x][3] = sqrtf(sqrtf(result[x][1]));
+ else
+ result[x][3] = expf(logf(result[x][1]) * (1.0f / s->gamma2));
+
+ result[x][0] = FFMIN(1.0f, result[x][0]);
+ result[x][1] = FFMIN(1.0f, result[x][1]);
+ result[x][2] = FFMIN(1.0f, result[x][2]);
+ if (s->gamma == 1.0f) {
+ result[x][0] = 255.0f * result[x][0];
+ result[x][1] = 255.0f * result[x][1];
+ result[x][2] = 255.0f * result[x][2];
+ } else if (s->gamma == 2.0f) {
+ result[x][0] = 255.0f * sqrtf(result[x][0]);
+ result[x][1] = 255.0f * sqrtf(result[x][1]);
+ result[x][2] = 255.0f * sqrtf(result[x][2]);
+ } else if (s->gamma == 3.0f) {
+ result[x][0] = 255.0f * cbrtf(result[x][0]);
+ result[x][1] = 255.0f * cbrtf(result[x][1]);
+ result[x][2] = 255.0f * cbrtf(result[x][2]);
+ } else if (s->gamma == 4.0f) {
+ result[x][0] = 255.0f * sqrtf(sqrtf(result[x][0]));
+ result[x][1] = 255.0f * sqrtf(sqrtf(result[x][1]));
+ result[x][2] = 255.0f * sqrtf(sqrtf(result[x][2]));
+ } else {
+ result[x][0] = 255.0f * expf(logf(result[x][0]) * (1.0f / s->gamma));
+ result[x][1] = 255.0f * expf(logf(result[x][1]) * (1.0f / s->gamma));
+ result[x][2] = 255.0f * expf(logf(result[x][2]) * (1.0f / s->gamma));
+ }
+ }
+
+ if (!s->fullhd) {
+ for (x = 0; x < video_width; x++) {
+ result[x][0] = 0.5f * (result[2*x][0] + result[2*x+1][0]);
+ result[x][1] = 0.5f * (result[2*x][1] + result[2*x+1][1]);
+ result[x][2] = 0.5f * (result[2*x][2] + result[2*x+1][2]);
+ result[x][3] = 0.5f * (result[2*x][3] + result[2*x+1][3]);
+ }
+ }
+
+ for (x = 0; x < video_width; x++) {
+ s->spectogram[s->spectogram_index*linesize + 3*x] = result[x][0] + 0.5f;
+ s->spectogram[s->spectogram_index*linesize + 3*x + 1] = result[x][1] + 0.5f;
+ s->spectogram[s->spectogram_index*linesize + 3*x + 2] = result[x][2] + 0.5f;
+ }
+
+ /* drawing */
+ if (!s->spectogram_count) {
+ uint8_t *data = (uint8_t*) s->outpicref->data[0];
+ float rcp_result[VIDEO_WIDTH];
+ int total_length = linesize * spectogram_height;
+ int back_length = linesize * s->spectogram_index;
+
+ for (x = 0; x < video_width; x++)
+ rcp_result[x] = 1.0f / (result[x][3]+0.0001f);
+
+ /* drawing bar */
+ for (y = 0; y < spectogram_height; y++) {
+ float height = (spectogram_height - y) * (1.0f/spectogram_height);
+ uint8_t *lineptr = data + y * linesize;
+ for (x = 0; x < video_width; x++) {
+ float mul;
+ if (result[x][3] <= height) {
+ *lineptr++ = 0;
+ *lineptr++ = 0;
+ *lineptr++ = 0;
+ } else {
+ mul = (result[x][3] - height) * rcp_result[x];
+ *lineptr++ = mul * result[x][0] + 0.5f;
+ *lineptr++ = mul * result[x][1] + 0.5f;
+ *lineptr++ = mul * result[x][2] + 0.5f;
+ }
+ }
+ }
+
+ /* drawing font */
+ if (s->font_alpha) {
+ for (y = 0; y < font_height; y++) {
+ uint8_t *lineptr = data + (spectogram_height + y) * linesize;
+ uint8_t *spectogram_src = s->spectogram + s->spectogram_index * linesize;
+ uint8_t *fontcolor_value = s->fontcolor_value;
+ for (x = 0; x < video_width; x++) {
+ uint8_t alpha = s->font_alpha[y*video_width+x];
+ lineptr[3*x] = (spectogram_src[3*x] * (255-alpha) + fontcolor_value[0] * alpha + 255) >> 8;
+ lineptr[3*x+1] = (spectogram_src[3*x+1] * (255-alpha) + fontcolor_value[1] * alpha + 255) >> 8;
+ lineptr[3*x+2] = (spectogram_src[3*x+2] * (255-alpha) + fontcolor_value[2] * alpha + 255) >> 8;
+ fontcolor_value += 3;
+ }
+ }
+ } else {
+ for (y = 0; y < font_height; y++) {
+ uint8_t *lineptr = data + (spectogram_height + y) * linesize;
+ memcpy(lineptr, s->spectogram + s->spectogram_index * linesize, video_width*3);
+ }
+ for (x = 0; x < video_width; x += video_width/10) {
+ int u;
+ static const char str[] = "EF G A BC D ";
+ uint8_t *startptr = data + spectogram_height * linesize + x * 3;
+ for (u = 0; str[u]; u++) {
+ int v;
+ for (v = 0; v < 16; v++) {
+ uint8_t *p = startptr + v * linesize * video_scale + 8 * 3 * u * video_scale;
+ int ux = x + 8 * u * video_scale;
+ int mask;
+ for (mask = 0x80; mask; mask >>= 1) {
+ if (mask & avpriv_vga16_font[str[u] * 16 + v]) {
+ p[0] = s->fontcolor_value[3*ux];
+ p[1] = s->fontcolor_value[3*ux+1];
+ p[2] = s->fontcolor_value[3*ux+2];
+ if (video_scale == 2) {
+ p[linesize] = p[0];
+ p[linesize+1] = p[1];
+ p[linesize+2] = p[2];
+ p[3] = p[linesize+3] = s->fontcolor_value[3*ux+3];
+ p[4] = p[linesize+4] = s->fontcolor_value[3*ux+4];
+ p[5] = p[linesize+5] = s->fontcolor_value[3*ux+5];
+ }
+ }
+ p += 3 * video_scale;
+ ux += video_scale;
+ }
+ }
+ }
+ }
+ }
+
+ /* drawing spectogram/sonogram */
+ data += spectogram_start * linesize;
+ memcpy(data, s->spectogram + s->spectogram_index*linesize, total_length - back_length);
+
+ data += total_length - back_length;
+ if (back_length)
+ memcpy(data, s->spectogram, back_length);
+
+ s->outpicref->pts = s->frame_count;
+ ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref));
+ s->req_fullfilled = 1;
+ s->frame_count++;
+ }
+ s->spectogram_count = (s->spectogram_count + 1) % s->count;
+ s->spectogram_index = (s->spectogram_index + spectogram_height - 1) % spectogram_height;
+ return ret;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ShowCQTContext *s = ctx->priv;
+ int step = inlink->sample_rate / (s->fps * s->count);
+ int fft_len = 1 << s->fft_bits;
+ int remaining;
+ float *audio_data;
+
+ if (!insamples) {
+ while (s->remaining_fill < (fft_len >> 1)) {
+ int ret, x;
+ memset(&s->fft_data[fft_len - s->remaining_fill], 0, sizeof(*s->fft_data) * s->remaining_fill);
+ ret = plot_cqt(inlink);
+ if (ret < 0)
+ return ret;
+ for (x = 0; x < (fft_len-step); x++)
+ s->fft_data[x] = s->fft_data[x+step];
+ s->remaining_fill += step;
+ }
+ return AVERROR_EOF;
+ }
+
+ remaining = insamples->nb_samples;
+ audio_data = (float*) insamples->data[0];
+
+ while (remaining) {
+ if (remaining >= s->remaining_fill) {
+ int i = insamples->nb_samples - remaining;
+ int j = fft_len - s->remaining_fill;
+ int m, ret;
+ for (m = 0; m < s->remaining_fill; m++) {
+ s->fft_data[j+m].re = audio_data[2*(i+m)];
+ s->fft_data[j+m].im = audio_data[2*(i+m)+1];
+ }
+ ret = plot_cqt(inlink);
+ if (ret < 0) {
+ av_frame_free(&insamples);
+ return ret;
+ }
+ remaining -= s->remaining_fill;
+ for (m = 0; m < fft_len-step; m++)
+ s->fft_data[m] = s->fft_data[m+step];
+ s->remaining_fill = step;
+ } else {
+ int i = insamples->nb_samples - remaining;
+ int j = fft_len - s->remaining_fill;
+ int m;
+ for (m = 0; m < remaining; m++) {
+ s->fft_data[m+j].re = audio_data[2*(i+m)];
+ s->fft_data[m+j].im = audio_data[2*(i+m)+1];
+ }
+ s->remaining_fill -= remaining;
+ remaining = 0;
+ }
+ }
+ av_frame_free(&insamples);
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ ShowCQTContext *s = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ int ret;
+
+ s->req_fullfilled = 0;
+ do {
+ ret = ff_request_frame(inlink);
+ } while (!s->req_fullfilled && ret >= 0);
+
+ if (ret == AVERROR_EOF && s->outpicref)
+ filter_frame(inlink, NULL);
+ return ret;
+}
+
+static const AVFilterPad showcqt_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad showcqt_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_avf_showcqt = {
+ .name = "showcqt",
+ .description = NULL_IF_CONFIG_SMALL("Convert input audio to a CQT (Constant Q Transform) spectrum video output."),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(ShowCQTContext),
+ .inputs = showcqt_inputs,
+ .outputs = showcqt_outputs,
+ .priv_class = &showcqt_class,
+};
diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
new file mode 100644
index 0000000000..49491b6646
--- /dev/null
+++ b/libavfilter/avf_showspectrum.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2012-2013 ClĂ©ment BÅ“sch
+ * Copyright (c) 2013 Rudolf Polzer <divverent@xonotic.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio to spectrum (video) transmedia filter, based on ffplay rdft showmode
+ * (by Michael Niedermayer) and lavfi/avf_showwaves (by Stefano Sabatini).
+ */
+
+#include <math.h>
+
+#include "libavcodec/avfft.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+
+enum DisplayMode { COMBINED, SEPARATE, NB_MODES };
+enum DisplayScale { LINEAR, SQRT, CBRT, LOG, NB_SCALES };
+enum ColorMode { CHANNEL, INTENSITY, NB_CLMODES };
+enum WindowFunc { WFUNC_NONE, WFUNC_HANN, WFUNC_HAMMING, WFUNC_BLACKMAN, NB_WFUNC };
+enum SlideMode { REPLACE, SCROLL, FULLFRAME, NB_SLIDES };
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ AVFrame *outpicref;
+ int req_fullfilled;
+ int nb_display_channels;
+ int channel_height;
+ int sliding; ///< 1 if sliding mode, 0 otherwise
+ int mode; ///< channel display mode
+ int color_mode; ///< display color scheme
+ int scale;
+ float saturation; ///< color saturation multiplier
+ int xpos; ///< x position (current column)
+ RDFTContext *rdft; ///< Real Discrete Fourier Transform context
+ int rdft_bits; ///< number of bits (RDFT window size = 1<<rdft_bits)
+ FFTSample **rdft_data; ///< bins holder for each (displayed) channels
+ float *window_func_lut; ///< Window function LUT
+ int win_func;
+ float *combine_buffer; ///< color combining buffer (3 * h items)
+} ShowSpectrumContext;
+
+#define OFFSET(x) offsetof(ShowSpectrumContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption showspectrum_options[] = {
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x512"}, 0, 0, FLAGS },
+ { "slide", "set sliding mode", OFFSET(sliding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NB_SLIDES, FLAGS, "slide" },
+ { "replace", "replace old columns with new", 0, AV_OPT_TYPE_CONST, {.i64=REPLACE}, 0, 0, FLAGS, "slide" },
+ { "scroll", "scroll from right to left", 0, AV_OPT_TYPE_CONST, {.i64=SCROLL}, 0, 0, FLAGS, "slide" },
+ { "fullframe", "return full frames", 0, AV_OPT_TYPE_CONST, {.i64=FULLFRAME}, 0, 0, FLAGS, "slide" },
+ { "mode", "set channel display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=COMBINED}, COMBINED, NB_MODES-1, FLAGS, "mode" },
+ { "combined", "combined mode", 0, AV_OPT_TYPE_CONST, {.i64=COMBINED}, 0, 0, FLAGS, "mode" },
+ { "separate", "separate mode", 0, AV_OPT_TYPE_CONST, {.i64=SEPARATE}, 0, 0, FLAGS, "mode" },
+ { "color", "set channel coloring", OFFSET(color_mode), AV_OPT_TYPE_INT, {.i64=CHANNEL}, CHANNEL, NB_CLMODES-1, FLAGS, "color" },
+ { "channel", "separate color for each channel", 0, AV_OPT_TYPE_CONST, {.i64=CHANNEL}, 0, 0, FLAGS, "color" },
+ { "intensity", "intensity based coloring", 0, AV_OPT_TYPE_CONST, {.i64=INTENSITY}, 0, 0, FLAGS, "color" },
+ { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=SQRT}, LINEAR, NB_SCALES-1, FLAGS, "scale" },
+ { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" },
+ { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" },
+ { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" },
+ { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" },
+ { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS },
+ { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANN}, 0, NB_WFUNC-1, FLAGS, "win_func" },
+ { "hann", "Hann window", 0, AV_OPT_TYPE_CONST, {.i64 = WFUNC_HANN}, 0, 0, FLAGS, "win_func" },
+ { "hamming", "Hamming window", 0, AV_OPT_TYPE_CONST, {.i64 = WFUNC_HAMMING}, 0, 0, FLAGS, "win_func" },
+ { "blackman", "Blackman window", 0, AV_OPT_TYPE_CONST, {.i64 = WFUNC_BLACKMAN}, 0, 0, FLAGS, "win_func" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(showspectrum);
+
+static const struct {
+ float a, y, u, v;
+} intensity_color_table[] = {
+ { 0, 0, 0, 0 },
+ { 0.13, .03587126228984074, .1573300977624594, -.02548747583751842 },
+ { 0.30, .18572281794568020, .1772436246393981, .17475554840414750 },
+ { 0.60, .28184980583656130, -.1593064119945782, .47132074554608920 },
+ { 0.73, .65830621175547810, -.3716070802232764, .24352759331252930 },
+ { 0.78, .76318535758242900, -.4307467689263783, .16866496622310430 },
+ { 0.91, .95336363636363640, -.2045454545454546, .03313636363636363 },
+ { 1, 1, 0, 0 }
+};
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ShowSpectrumContext *s = ctx->priv;
+ int i;
+
+ av_freep(&s->combine_buffer);
+ av_rdft_end(s->rdft);
+ for (i = 0; i < s->nb_display_channels; i++)
+ av_freep(&s->rdft_data[i]);
+ av_freep(&s->rdft_data);
+ av_freep(&s->window_func_lut);
+ av_frame_free(&s->outpicref);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_NONE };
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE };
+
+ /* set input audio formats */
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_formats);
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_samplerates);
+
+ /* set output video format */
+ formats = ff_make_format_list(pix_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &outlink->in_formats);
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ShowSpectrumContext *s = ctx->priv;
+ int i, rdft_bits, win_size, h;
+
+ outlink->w = s->w;
+ outlink->h = s->h;
+
+ h = (s->mode == COMBINED) ? outlink->h : outlink->h / inlink->channels;
+ s->channel_height = h;
+
+ /* RDFT window size (precision) according to the requested output frame height */
+ for (rdft_bits = 1; 1 << rdft_bits < 2 * h; rdft_bits++);
+ win_size = 1 << rdft_bits;
+
+ /* (re-)configuration if the video output changed (or first init) */
+ if (rdft_bits != s->rdft_bits) {
+ size_t rdft_size, rdft_listsize;
+ AVFrame *outpicref;
+
+ av_rdft_end(s->rdft);
+ s->rdft = av_rdft_init(rdft_bits, DFT_R2C);
+ if (!s->rdft) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to create RDFT context. "
+ "The window size might be too high.\n");
+ return AVERROR(EINVAL);
+ }
+ s->rdft_bits = rdft_bits;
+
+ /* RDFT buffers: x2 for each (display) channel buffer.
+ * Note: we use free and malloc instead of a realloc-like function to
+ * make sure the buffer is aligned in memory for the FFT functions. */
+ for (i = 0; i < s->nb_display_channels; i++)
+ av_freep(&s->rdft_data[i]);
+ av_freep(&s->rdft_data);
+ s->nb_display_channels = inlink->channels;
+
+ if (av_size_mult(sizeof(*s->rdft_data),
+ s->nb_display_channels, &rdft_listsize) < 0)
+ return AVERROR(EINVAL);
+ if (av_size_mult(sizeof(**s->rdft_data),
+ win_size, &rdft_size) < 0)
+ return AVERROR(EINVAL);
+ s->rdft_data = av_malloc(rdft_listsize);
+ if (!s->rdft_data)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < s->nb_display_channels; i++) {
+ s->rdft_data[i] = av_malloc(rdft_size);
+ if (!s->rdft_data[i])
+ return AVERROR(ENOMEM);
+ }
+
+ /* pre-calc windowing function */
+ s->window_func_lut =
+ av_realloc_f(s->window_func_lut, win_size,
+ sizeof(*s->window_func_lut));
+ if (!s->window_func_lut)
+ return AVERROR(ENOMEM);
+ switch (s->win_func) {
+ case WFUNC_NONE:
+ for (i = 0; i < win_size; i++)
+ s->window_func_lut[i] = 1.;
+ break;
+ case WFUNC_HANN:
+ for (i = 0; i < win_size; i++)
+ s->window_func_lut[i] = .5f * (1 - cos(2*M_PI*i / (win_size-1)));
+ break;
+ case WFUNC_HAMMING:
+ for (i = 0; i < win_size; i++)
+ s->window_func_lut[i] = .54f - .46f * cos(2*M_PI*i / (win_size-1));
+ break;
+ case WFUNC_BLACKMAN: {
+ for (i = 0; i < win_size; i++)
+ s->window_func_lut[i] = .42f - .5f*cos(2*M_PI*i / (win_size-1)) + .08f*cos(4*M_PI*i / (win_size-1));
+ break;
+ }
+ default:
+ av_assert0(0);
+ }
+
+ /* prepare the initial picref buffer (black frame) */
+ av_frame_free(&s->outpicref);
+ s->outpicref = outpicref =
+ ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpicref)
+ return AVERROR(ENOMEM);
+ outlink->sample_aspect_ratio = (AVRational){1,1};
+ for (i = 0; i < outlink->h; i++) {
+ memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w);
+ memset(outpicref->data[1] + i * outpicref->linesize[1], 128, outlink->w);
+ memset(outpicref->data[2] + i * outpicref->linesize[2], 128, outlink->w);
+ }
+ }
+
+ if (s->xpos >= outlink->w)
+ s->xpos = 0;
+
+ outlink->frame_rate = av_make_q(inlink->sample_rate, win_size);
+ if (s->sliding == FULLFRAME)
+ outlink->frame_rate.den *= outlink->w;
+
+ inlink->min_samples = inlink->max_samples = inlink->partial_buf_size =
+ win_size;
+
+ s->combine_buffer =
+ av_realloc_f(s->combine_buffer, outlink->h * 3,
+ sizeof(*s->combine_buffer));
+
+ av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d RDFT window size:%d\n",
+ s->w, s->h, win_size);
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ ShowSpectrumContext *s = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ unsigned i;
+ int ret;
+
+ s->req_fullfilled = 0;
+ do {
+ ret = ff_request_frame(inlink);
+ if (ret == AVERROR_EOF && s->sliding == FULLFRAME && s->xpos > 0 &&
+ s->outpicref) {
+ for (i = 0; i < outlink->h; i++) {
+ memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos);
+ memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos);
+ memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos);
+ }
+ ret = ff_filter_frame(outlink, s->outpicref);
+ s->outpicref = NULL;
+ s->req_fullfilled = 1;
+ }
+ } while (!s->req_fullfilled && ret >= 0);
+
+ return ret;
+}
+
+static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
+{
+ int ret;
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ShowSpectrumContext *s = ctx->priv;
+ AVFrame *outpicref = s->outpicref;
+
+ /* nb_freq contains the power of two superior or equal to the output image
+ * height (or half the RDFT window size) */
+ const int nb_freq = 1 << (s->rdft_bits - 1);
+ const int win_size = nb_freq << 1;
+ const double w = 1. / (sqrt(nb_freq) * 32768.);
+ int h = s->channel_height;
+
+ int ch, plane, n, y;
+
+ av_assert0(insamples->nb_samples == win_size);
+
+ /* fill RDFT input with the number of samples available */
+ for (ch = 0; ch < s->nb_display_channels; ch++) {
+ const int16_t *p = (int16_t *)insamples->extended_data[ch];
+
+ for (n = 0; n < win_size; n++)
+ s->rdft_data[ch][n] = p[n] * s->window_func_lut[n];
+ }
+
+ /* TODO reindent */
+
+ /* run RDFT on each samples set */
+ for (ch = 0; ch < s->nb_display_channels; ch++)
+ av_rdft_calc(s->rdft, s->rdft_data[ch]);
+
+ /* fill a new spectrum column */
+#define RE(y, ch) s->rdft_data[ch][2 * (y) + 0]
+#define IM(y, ch) s->rdft_data[ch][2 * (y) + 1]
+#define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch))
+
+ /* initialize buffer for combining to black */
+ for (y = 0; y < outlink->h; y++) {
+ s->combine_buffer[3 * y ] = 0;
+ s->combine_buffer[3 * y + 1] = 127.5;
+ s->combine_buffer[3 * y + 2] = 127.5;
+ }
+
+ for (ch = 0; ch < s->nb_display_channels; ch++) {
+ float yf, uf, vf;
+
+ /* decide color range */
+ switch (s->mode) {
+ case COMBINED:
+ // reduce range by channel count
+ yf = 256.0f / s->nb_display_channels;
+ switch (s->color_mode) {
+ case INTENSITY:
+ uf = yf;
+ vf = yf;
+ break;
+ case CHANNEL:
+ /* adjust saturation for mixed UV coloring */
+ /* this factor is correct for infinite channels, an approximation otherwise */
+ uf = yf * M_PI;
+ vf = yf * M_PI;
+ break;
+ default:
+ av_assert0(0);
+ }
+ break;
+ case SEPARATE:
+ // full range
+ yf = 256.0f;
+ uf = 256.0f;
+ vf = 256.0f;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ if (s->color_mode == CHANNEL) {
+ if (s->nb_display_channels > 1) {
+ uf *= 0.5 * sin((2 * M_PI * ch) / s->nb_display_channels);
+ vf *= 0.5 * cos((2 * M_PI * ch) / s->nb_display_channels);
+ } else {
+ uf = 0.0f;
+ vf = 0.0f;
+ }
+ }
+ uf *= s->saturation;
+ vf *= s->saturation;
+
+ /* draw the channel */
+ for (y = 0; y < h; y++) {
+ int row = (s->mode == COMBINED) ? y : ch * h + y;
+ float *out = &s->combine_buffer[3 * row];
+
+ /* get magnitude */
+ float a = w * MAGNITUDE(y, ch);
+
+ /* apply scale */
+ switch (s->scale) {
+ case LINEAR:
+ break;
+ case SQRT:
+ a = sqrt(a);
+ break;
+ case CBRT:
+ a = cbrt(a);
+ break;
+ case LOG:
+ a = 1 - log(FFMAX(FFMIN(1, a), 1e-6)) / log(1e-6); // zero = -120dBFS
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ if (s->color_mode == INTENSITY) {
+ float y, u, v;
+ int i;
+
+ for (i = 1; i < sizeof(intensity_color_table) / sizeof(*intensity_color_table) - 1; i++)
+ if (intensity_color_table[i].a >= a)
+ break;
+ // i now is the first item >= the color
+ // now we know to interpolate between item i - 1 and i
+ if (a <= intensity_color_table[i - 1].a) {
+ y = intensity_color_table[i - 1].y;
+ u = intensity_color_table[i - 1].u;
+ v = intensity_color_table[i - 1].v;
+ } else if (a >= intensity_color_table[i].a) {
+ y = intensity_color_table[i].y;
+ u = intensity_color_table[i].u;
+ v = intensity_color_table[i].v;
+ } else {
+ float start = intensity_color_table[i - 1].a;
+ float end = intensity_color_table[i].a;
+ float lerpfrac = (a - start) / (end - start);
+ y = intensity_color_table[i - 1].y * (1.0f - lerpfrac)
+ + intensity_color_table[i].y * lerpfrac;
+ u = intensity_color_table[i - 1].u * (1.0f - lerpfrac)
+ + intensity_color_table[i].u * lerpfrac;
+ v = intensity_color_table[i - 1].v * (1.0f - lerpfrac)
+ + intensity_color_table[i].v * lerpfrac;
+ }
+
+ out[0] += y * yf;
+ out[1] += u * uf;
+ out[2] += v * vf;
+ } else {
+ out[0] += a * yf;
+ out[1] += a * uf;
+ out[2] += a * vf;
+ }
+ }
+ }
+
+ /* copy to output */
+ if (s->sliding == SCROLL) {
+ for (plane = 0; plane < 3; plane++) {
+ for (y = 0; y < outlink->h; y++) {
+ uint8_t *p = outpicref->data[plane] +
+ y * outpicref->linesize[plane];
+ memmove(p, p + 1, outlink->w - 1);
+ }
+ }
+ s->xpos = outlink->w - 1;
+ }
+ for (plane = 0; plane < 3; plane++) {
+ uint8_t *p = outpicref->data[plane] +
+ (outlink->h - 1) * outpicref->linesize[plane] +
+ s->xpos;
+ for (y = 0; y < outlink->h; y++) {
+ *p = rint(FFMAX(0, FFMIN(s->combine_buffer[3 * y + plane], 255)));
+ p -= outpicref->linesize[plane];
+ }
+ }
+
+ if (s->sliding != FULLFRAME || s->xpos == 0)
+ outpicref->pts = insamples->pts;
+
+ s->xpos++;
+ if (s->xpos >= outlink->w)
+ s->xpos = 0;
+ if (s->sliding != FULLFRAME || s->xpos == 0) {
+ s->req_fullfilled = 1;
+ ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref));
+ if (ret < 0)
+ return ret;
+ }
+
+ return win_size;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ShowSpectrumContext *s = ctx->priv;
+ unsigned win_size = 1 << s->rdft_bits;
+ int ret = 0;
+
+ av_assert0(insamples->nb_samples <= win_size);
+ if (insamples->nb_samples == win_size)
+ ret = plot_spectrum_column(inlink, insamples);
+
+ av_frame_free(&insamples);
+ return ret;
+}
+
+static const AVFilterPad showspectrum_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad showspectrum_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_avf_showspectrum = {
+ .name = "showspectrum",
+ .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spectrum video output."),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(ShowSpectrumContext),
+ .inputs = showspectrum_inputs,
+ .outputs = showspectrum_outputs,
+ .priv_class = &showspectrum_class,
+};
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
new file mode 100644
index 0000000000..57a6b2e149
--- /dev/null
+++ b/libavfilter/avf_showwaves.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio to video multimedia filter
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "audio.h"
+#include "video.h"
+#include "internal.h"
+
+enum ShowWavesMode {
+ MODE_POINT,
+ MODE_LINE,
+ MODE_P2P,
+ MODE_CENTERED_LINE,
+ MODE_NB,
+};
+
+struct frame_node {
+ AVFrame *frame;
+ struct frame_node *next;
+};
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ AVRational rate;
+ int buf_idx;
+ int16_t *buf_idy; /* y coordinate of previous sample for each channel */
+ AVFrame *outpicref;
+ int req_fullfilled;
+ int n;
+ int sample_count_mod;
+ int mode; ///< ShowWavesMode
+ int split_channels;
+ void (*draw_sample)(uint8_t *buf, int height, int linesize,
+ int16_t sample, int16_t *prev_y, int intensity);
+
+ /* single picture */
+ int single_pic;
+ struct frame_node *audio_frames;
+ struct frame_node *last_frame;
+ int64_t total_samples;
+ int64_t *sum; /* abs sum of the samples per channel */
+} ShowWavesContext;
+
+#define OFFSET(x) offsetof(ShowWavesContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption showwaves_options[] = {
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
+ { "mode", "select display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_POINT}, 0, MODE_NB-1, FLAGS, "mode"},
+ { "point", "draw a point for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_POINT}, .flags=FLAGS, .unit="mode"},
+ { "line", "draw a line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_LINE}, .flags=FLAGS, .unit="mode"},
+ { "p2p", "draw a line between samples", 0, AV_OPT_TYPE_CONST, {.i64=MODE_P2P}, .flags=FLAGS, .unit="mode"},
+ { "cline", "draw a centered line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_CENTERED_LINE}, .flags=FLAGS, .unit="mode"},
+ { "n", "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
+ { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "r", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "split_channels", "draw channels separately", OFFSET(split_channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(showwaves);
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ShowWavesContext *showwaves = ctx->priv;
+
+ av_frame_free(&showwaves->outpicref);
+ av_freep(&showwaves->buf_idy);
+
+ if (showwaves->single_pic) {
+ struct frame_node *node = showwaves->audio_frames;
+ while (node) {
+ struct frame_node *tmp = node;
+
+ node = node->next;
+ av_frame_free(&tmp->frame);
+ av_freep(&tmp);
+ }
+ av_freep(&showwaves->sum);
+ showwaves->last_frame = NULL;
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
+
+ /* set input audio formats */
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_formats);
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+
+ formats = ff_all_samplerates();
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_samplerates);
+
+ /* set output video format */
+ formats = ff_make_format_list(pix_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &outlink->in_formats);
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ShowWavesContext *showwaves = ctx->priv;
+ int nb_channels = inlink->channels;
+
+ if (!showwaves->n)
+ showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5);
+
+ showwaves->buf_idx = 0;
+ if (!(showwaves->buf_idy = av_mallocz_array(nb_channels, sizeof(*showwaves->buf_idy)))) {
+ av_log(ctx, AV_LOG_ERROR, "Could not allocate showwaves buffer\n");
+ return AVERROR(ENOMEM);
+ }
+ outlink->w = showwaves->w;
+ outlink->h = showwaves->h;
+ outlink->sample_aspect_ratio = (AVRational){1,1};
+
+ outlink->frame_rate = av_div_q((AVRational){inlink->sample_rate,showwaves->n},
+ (AVRational){showwaves->w,1});
+
+ av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%d\n",
+ showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n);
+ return 0;
+}
+
+inline static int push_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ShowWavesContext *showwaves = outlink->src->priv;
+ int nb_channels = inlink->channels;
+ int ret, i;
+
+ if ((ret = ff_filter_frame(outlink, showwaves->outpicref)) >= 0)
+ showwaves->req_fullfilled = 1;
+ showwaves->outpicref = NULL;
+ showwaves->buf_idx = 0;
+ for (i = 0; i < nb_channels; i++)
+ showwaves->buf_idy[i] = 0;
+ return ret;
+}
+
+static int push_single_pic(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ShowWavesContext *showwaves = ctx->priv;
+ int64_t n = 0, max_samples = showwaves->total_samples / outlink->w;
+ AVFrame *out = showwaves->outpicref;
+ struct frame_node *node;
+ const int nb_channels = inlink->channels;
+ const int x = 255 / (showwaves->split_channels ? 1 : nb_channels);
+ const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h;
+ const int linesize = out->linesize[0];
+ int col = 0;
+ int64_t *sum = showwaves->sum;
+
+ av_log(ctx, AV_LOG_DEBUG, "Create frame averaging %"PRId64" samples per column\n", max_samples);
+
+ memset(sum, 0, nb_channels);
+
+ for (node = showwaves->audio_frames; node; node = node->next) {
+ int i;
+ const AVFrame *frame = node->frame;
+ const int16_t *p = (const int16_t *)frame->data[0];
+
+ for (i = 0; i < frame->nb_samples; i++) {
+ int ch;
+
+ for (ch = 0; ch < nb_channels; ch++)
+ sum[ch] += abs(p[ch + i*nb_channels]) << 1;
+ if (n++ == max_samples) {
+ for (ch = 0; ch < nb_channels; ch++) {
+ int16_t sample = sum[ch] / max_samples;
+ uint8_t *buf = out->data[0] + col;
+ if (showwaves->split_channels)
+ buf += ch*ch_height*linesize;
+ av_assert0(col < outlink->w);
+ showwaves->draw_sample(buf, ch_height, linesize, sample, &showwaves->buf_idy[ch], x);
+ sum[ch] = 0;
+ }
+ col++;
+ n = 0;
+ }
+ }
+ }
+
+ return push_frame(outlink);
+}
+
+
+static int request_frame(AVFilterLink *outlink)
+{
+ ShowWavesContext *showwaves = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ int ret;
+
+ showwaves->req_fullfilled = 0;
+ do {
+ ret = ff_request_frame(inlink);
+ } while (!showwaves->req_fullfilled && ret >= 0);
+
+ if (ret == AVERROR_EOF && showwaves->outpicref) {
+ if (showwaves->single_pic)
+ push_single_pic(outlink);
+ else
+ push_frame(outlink);
+ }
+
+ return ret;
+}
+
+static void draw_sample_point(uint8_t *buf, int height, int linesize,
+ int16_t sample, int16_t *prev_y, int intensity)
+{
+ const int h = height/2 - av_rescale(sample, height/2, INT16_MAX);
+ if (h >= 0 && h < height)
+ buf[h * linesize] += intensity;
+}
+
+static void draw_sample_line(uint8_t *buf, int height, int linesize,
+ int16_t sample, int16_t *prev_y, int intensity)
+{
+ int k;
+ const int h = height/2 - av_rescale(sample, height/2, INT16_MAX);
+ int start = height/2;
+ int end = av_clip(h, 0, height-1);
+ if (start > end)
+ FFSWAP(int16_t, start, end);
+ for (k = start; k < end; k++)
+ buf[k * linesize] += intensity;
+}
+
+static void draw_sample_p2p(uint8_t *buf, int height, int linesize,
+ int16_t sample, int16_t *prev_y, int intensity)
+{
+ int k;
+ const int h = height/2 - av_rescale(sample, height/2, INT16_MAX);
+ if (h >= 0 && h < height) {
+ buf[h * linesize] += intensity;
+ if (*prev_y && h != *prev_y) {
+ int start = *prev_y;
+ int end = av_clip(h, 0, height-1);
+ if (start > end)
+ FFSWAP(int16_t, start, end);
+ for (k = start + 1; k < end; k++)
+ buf[k * linesize] += intensity;
+ }
+ }
+ *prev_y = h;
+}
+
+static void draw_sample_cline(uint8_t *buf, int height, int linesize,
+ int16_t sample, int16_t *prev_y, int intensity)
+{
+ int k;
+ const int h = av_rescale(abs(sample), height, INT16_MAX);
+ const int start = (height - h) / 2;
+ const int end = start + h;
+ for (k = start; k < end; k++)
+ buf[k * linesize] += intensity;
+}
+
+static int alloc_out_frame(ShowWavesContext *showwaves, const int16_t *p,
+ const AVFilterLink *inlink, AVFilterLink *outlink,
+ const AVFrame *in)
+{
+ if (!showwaves->outpicref) {
+ int j;
+ AVFrame *out = showwaves->outpicref =
+ ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ out->width = outlink->w;
+ out->height = outlink->h;
+ out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->channels,
+ av_make_q(1, inlink->sample_rate),
+ outlink->time_base);
+ for (j = 0; j < outlink->h; j++)
+ memset(out->data[0] + j*out->linesize[0], 0, outlink->w);
+ }
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ShowWavesContext *showwaves = ctx->priv;
+
+ if (!strcmp(ctx->filter->name, "showwavespic")) {
+ showwaves->single_pic = 1;
+ showwaves->mode = MODE_CENTERED_LINE;
+ }
+
+ switch (showwaves->mode) {
+ case MODE_POINT: showwaves->draw_sample = draw_sample_point; break;
+ case MODE_LINE: showwaves->draw_sample = draw_sample_line; break;
+ case MODE_P2P: showwaves->draw_sample = draw_sample_p2p; break;
+ case MODE_CENTERED_LINE: showwaves->draw_sample = draw_sample_cline; break;
+ default:
+ return AVERROR_BUG;
+ }
+ return 0;
+}
+
+#if CONFIG_SHOWWAVES_FILTER
+
+static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ShowWavesContext *showwaves = ctx->priv;
+ const int nb_samples = insamples->nb_samples;
+ AVFrame *outpicref = showwaves->outpicref;
+ int16_t *p = (int16_t *)insamples->data[0];
+ int nb_channels = inlink->channels;
+ int i, j, ret = 0;
+ const int n = showwaves->n;
+ const int x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * n); /* multiplication factor, pre-computed to avoid in-loop divisions */
+ const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h;
+
+ /* draw data in the buffer */
+ for (i = 0; i < nb_samples; i++) {
+
+ ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples);
+ if (ret < 0)
+ goto end;
+ outpicref = showwaves->outpicref;
+
+ for (j = 0; j < nb_channels; j++) {
+ uint8_t *buf = outpicref->data[0] + showwaves->buf_idx;
+ const int linesize = outpicref->linesize[0];
+ if (showwaves->split_channels)
+ buf += j*ch_height*linesize;
+ showwaves->draw_sample(buf, ch_height, linesize, *p++,
+ &showwaves->buf_idy[j], x);
+ }
+
+ showwaves->sample_count_mod++;
+ if (showwaves->sample_count_mod == n) {
+ showwaves->sample_count_mod = 0;
+ showwaves->buf_idx++;
+ }
+ if (showwaves->buf_idx == showwaves->w)
+ if ((ret = push_frame(outlink)) < 0)
+ break;
+ outpicref = showwaves->outpicref;
+ }
+
+end:
+ av_frame_free(&insamples);
+ return ret;
+}
+
+static const AVFilterPad showwaves_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = showwaves_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad showwaves_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_avf_showwaves = {
+ .name = "showwaves",
+ .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(ShowWavesContext),
+ .inputs = showwaves_inputs,
+ .outputs = showwaves_outputs,
+ .priv_class = &showwaves_class,
+};
+
+#endif // CONFIG_SHOWWAVES_FILTER
+
+#if CONFIG_SHOWWAVESPIC_FILTER
+
+#define OFFSET(x) offsetof(ShowWavesContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption showwavespic_options[] = {
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
+ { "split_channels", "draw channels separately", OFFSET(split_channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(showwavespic);
+
+static int showwavespic_config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ShowWavesContext *showwaves = ctx->priv;
+
+ if (showwaves->single_pic) {
+ showwaves->sum = av_mallocz_array(inlink->channels, sizeof(*showwaves->sum));
+ if (!showwaves->sum)
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static int showwavespic_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ShowWavesContext *showwaves = ctx->priv;
+ int16_t *p = (int16_t *)insamples->data[0];
+ int ret = 0;
+
+ if (showwaves->single_pic) {
+ struct frame_node *f;
+
+ ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples);
+ if (ret < 0)
+ goto end;
+
+ /* queue the audio frame */
+ f = av_malloc(sizeof(*f));
+ if (!f) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ f->frame = insamples;
+ f->next = NULL;
+ if (!showwaves->last_frame) {
+ showwaves->audio_frames =
+ showwaves->last_frame = f;
+ } else {
+ showwaves->last_frame->next = f;
+ showwaves->last_frame = f;
+ }
+ showwaves->total_samples += insamples->nb_samples;
+
+ return 0;
+ }
+
+end:
+ av_frame_free(&insamples);
+ return ret;
+}
+
+static const AVFilterPad showwavespic_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = showwavespic_config_input,
+ .filter_frame = showwavespic_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad showwavespic_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_avf_showwavespic = {
+ .name = "showwavespic",
+ .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(ShowWavesContext),
+ .inputs = showwavespic_inputs,
+ .outputs = showwavespic_outputs,
+ .priv_class = &showwavespic_class,
+};
+
+#endif // CONFIG_SHOWWAVESPIC_FILTER
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 8ede145686..bcf8d3f91f 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -2,26 +2,29 @@
* filter layer
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/atomic.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
+#include "libavutil/eval.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
@@ -33,34 +36,85 @@
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
-#include "video.h"
+
+#include "libavutil/ffversion.h"
+const char av_filter_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
+static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame);
+
+void ff_tlog_ref(void *ctx, AVFrame *ref, int end)
+{
+ av_unused char buf[16];
+ ff_tlog(ctx,
+ "ref[%p buf:%p data:%p linesize[%d, %d, %d, %d] pts:%"PRId64" pos:%"PRId64,
+ ref, ref->buf, ref->data[0],
+ ref->linesize[0], ref->linesize[1], ref->linesize[2], ref->linesize[3],
+ ref->pts, av_frame_get_pkt_pos(ref));
+
+ if (ref->width) {
+ ff_tlog(ctx, " a:%d/%d s:%dx%d i:%c iskey:%d type:%c",
+ ref->sample_aspect_ratio.num, ref->sample_aspect_ratio.den,
+ ref->width, ref->height,
+ !ref->interlaced_frame ? 'P' : /* Progressive */
+ ref->top_field_first ? 'T' : 'B', /* Top / Bottom */
+ ref->key_frame,
+ av_get_picture_type_char(ref->pict_type));
+ }
+ if (ref->nb_samples) {
+ ff_tlog(ctx, " cl:%"PRId64"d n:%d r:%d",
+ ref->channel_layout,
+ ref->nb_samples,
+ ref->sample_rate);
+ }
+
+ ff_tlog(ctx, "]%s", end ? "\n" : "");
+}
unsigned avfilter_version(void)
{
+ av_assert0(LIBAVFILTER_VERSION_MICRO >= 100);
return LIBAVFILTER_VERSION_INT;
}
const char *avfilter_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char *avfilter_license(void)
{
#define LICENSE_PREFIX "libavfilter license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+}
+
+void ff_command_queue_pop(AVFilterContext *filter)
+{
+ AVFilterCommand *c= filter->command_queue;
+ av_freep(&c->arg);
+ av_freep(&c->command);
+ filter->command_queue= c->next;
+ av_free(c);
}
-void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
+int ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
AVFilterPad **pads, AVFilterLink ***links,
AVFilterPad *newpad)
{
+ AVFilterLink **newlinks;
+ AVFilterPad *newpads;
unsigned i;
idx = FFMIN(idx, *count);
- *pads = av_realloc(*pads, sizeof(AVFilterPad) * (*count + 1));
- *links = av_realloc(*links, sizeof(AVFilterLink*) * (*count + 1));
+ newpads = av_realloc_array(*pads, *count + 1, sizeof(AVFilterPad));
+ newlinks = av_realloc_array(*links, *count + 1, sizeof(AVFilterLink*));
+ if (newpads)
+ *pads = newpads;
+ if (newlinks)
+ *links = newlinks;
+ if (!newpads || !newlinks)
+ return AVERROR(ENOMEM);
+
memmove(*pads + idx + 1, *pads + idx, sizeof(AVFilterPad) * (*count - idx));
memmove(*links + idx + 1, *links + idx, sizeof(AVFilterLink*) * (*count - idx));
memcpy(*pads + idx, newpad, sizeof(AVFilterPad));
@@ -68,8 +122,10 @@ void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
(*count)++;
for (i = idx + 1; i < *count; i++)
- if (*links[i])
- (*(unsigned *)((uint8_t *) *links[i] + padidx_off))++;
+ if ((*links)[i])
+ (*(unsigned *)((uint8_t *) (*links)[i] + padidx_off))++;
+
+ return 0;
}
int avfilter_link(AVFilterContext *src, unsigned srcpad,
@@ -83,8 +139,9 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad,
if (src->output_pads[srcpad].type != dst->input_pads[dstpad].type) {
av_log(src, AV_LOG_ERROR,
- "Media type mismatch between the '%s' filter output pad %d and the '%s' filter input pad %d\n",
- src->name, srcpad, dst->name, dstpad);
+ "Media type mismatch between the '%s' filter output pad %d (%s) and the '%s' filter input pad %d (%s)\n",
+ src->name, srcpad, (char *)av_x_if_null(av_get_media_type_string(src->output_pads[srcpad].type), "?"),
+ dst->name, dstpad, (char *)av_x_if_null(av_get_media_type_string(dst-> input_pads[dstpad].type), "?"));
return AVERROR(EINVAL);
}
@@ -99,12 +156,32 @@ 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;
- assert(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
+ av_assert0(AV_PIX_FMT_NONE == -1 && AV_SAMPLE_FMT_NONE == -1);
link->format = -1;
return 0;
}
+void avfilter_link_free(AVFilterLink **link)
+{
+ if (!*link)
+ return;
+
+ av_frame_free(&(*link)->partial_buf);
+
+ av_freep(link);
+}
+
+int avfilter_link_get_channels(AVFilterLink *link)
+{
+ return link->channels;
+}
+
+void avfilter_link_set_closed(AVFilterLink *link, int closed)
+{
+ link->closed = closed;
+}
+
int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
unsigned filt_srcpad_idx, unsigned filt_dstpad_idx)
{
@@ -150,6 +227,7 @@ int avfilter_config_links(AVFilterContext *filter)
for (i = 0; i < filter->nb_inputs; i ++) {
AVFilterLink *link = filter->inputs[i];
+ AVFilterLink *inlink;
if (!link) continue;
if (!link->src || !link->dst) {
@@ -158,6 +236,9 @@ int avfilter_config_links(AVFilterContext *filter)
return AVERROR(EINVAL);
}
+ inlink = link->src->nb_inputs ? link->src->inputs[0] : NULL;
+ link->current_pts = AV_NOPTS_VALUE;
+
switch (link->init_state) {
case AVLINK_INIT:
continue;
@@ -185,26 +266,39 @@ int avfilter_config_links(AVFilterContext *filter)
return ret;
}
- if (link->time_base.num == 0 && link->time_base.den == 0)
- link->time_base = link->src->nb_inputs ?
- link->src->inputs[0]->time_base : AV_TIME_BASE_Q;
+ switch (link->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = inlink ? inlink->time_base : AV_TIME_BASE_Q;
- if (link->type == AVMEDIA_TYPE_VIDEO) {
if (!link->sample_aspect_ratio.num && !link->sample_aspect_ratio.den)
- link->sample_aspect_ratio = link->src->nb_inputs ?
- link->src->inputs[0]->sample_aspect_ratio : (AVRational){1,1};
+ link->sample_aspect_ratio = inlink ?
+ inlink->sample_aspect_ratio : (AVRational){1,1};
- if (link->src->nb_inputs) {
+ if (inlink && !link->frame_rate.num && !link->frame_rate.den)
+ link->frame_rate = inlink->frame_rate;
+
+ if (inlink) {
if (!link->w)
- link->w = link->src->inputs[0]->w;
+ link->w = inlink->w;
if (!link->h)
- link->h = link->src->inputs[0]->h;
+ link->h = inlink->h;
} else if (!link->w || !link->h) {
av_log(link->src, AV_LOG_ERROR,
"Video source filters must set their output link's "
"width and height\n");
return AVERROR(EINVAL);
}
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ if (inlink) {
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = inlink->time_base;
+ }
+
+ if (!link->time_base.num && !link->time_base.den)
+ link->time_base = (AVRational) {1, link->sample_rate};
}
if ((config_link = link->dstpad->config_props))
@@ -222,11 +316,11 @@ int avfilter_config_links(AVFilterContext *filter)
return 0;
}
-void ff_dlog_link(void *ctx, AVFilterLink *link, int end)
+void ff_tlog_link(void *ctx, AVFilterLink *link, int end)
{
if (link->type == AVMEDIA_TYPE_VIDEO) {
- av_log(ctx, AV_LOG_TRACE,
- "link[%p s:%dx%d fmt:%-16s %-16s->%-16s]%s",
+ ff_tlog(ctx,
+ "link[%p s:%dx%d fmt:%s %s->%s]%s",
link, link->w, link->h,
av_get_pix_fmt_name(link->format),
link->src ? link->src->filter->name : "",
@@ -236,9 +330,9 @@ void ff_dlog_link(void *ctx, AVFilterLink *link, int end)
char buf[128];
av_get_channel_layout_string(buf, sizeof(buf), -1, link->channel_layout);
- av_log(ctx, AV_LOG_TRACE,
- "link[%p r:%d cl:%s fmt:%-16s %-16s->%-16s]%s",
- link, link->sample_rate, buf,
+ ff_tlog(ctx,
+ "link[%p r:%d cl:%s fmt:%s %s->%s]%s",
+ link, (int)link->sample_rate, buf,
av_get_sample_fmt_name(link->format),
link->src ? link->src->filter->name : "",
link->dst ? link->dst->filter->name : "",
@@ -248,14 +342,33 @@ void ff_dlog_link(void *ctx, AVFilterLink *link, int end)
int ff_request_frame(AVFilterLink *link)
{
- FF_DPRINTF_START(NULL, request_frame); ff_dlog_link(NULL, link, 1);
-
- if (link->srcpad->request_frame)
- return link->srcpad->request_frame(link);
- else if (link->src->inputs[0])
- return ff_request_frame(link->src->inputs[0]);
- else
- return AVERROR(EINVAL);
+ int ret = -1;
+ FF_TPRINTF_START(NULL, request_frame); ff_tlog_link(NULL, link, 1);
+
+ if (link->closed)
+ return AVERROR_EOF;
+ av_assert0(!link->frame_requested);
+ link->frame_requested = 1;
+ while (link->frame_requested) {
+ if (link->srcpad->request_frame)
+ ret = link->srcpad->request_frame(link);
+ else if (link->src->inputs[0])
+ ret = ff_request_frame(link->src->inputs[0]);
+ if (ret == AVERROR_EOF && link->partial_buf) {
+ AVFrame *pbuf = link->partial_buf;
+ link->partial_buf = NULL;
+ ret = ff_filter_frame_framed(link, pbuf);
+ }
+ if (ret < 0) {
+ link->frame_requested = 0;
+ if (ret == AVERROR_EOF)
+ link->closed = 1;
+ } else {
+ av_assert0(!link->frame_requested ||
+ link->flags & FF_LINK_FLAG_REQUEST_LOOP);
+ }
+ }
+ return ret;
}
int ff_poll_frame(AVFilterLink *link)
@@ -276,7 +389,97 @@ int ff_poll_frame(AVFilterLink *link)
return min;
}
+static const char *const var_names[] = {
+ "t",
+ "n",
+ "pos",
+ "w",
+ "h",
+ NULL
+};
+
+enum {
+ VAR_T,
+ VAR_N,
+ VAR_POS,
+ VAR_W,
+ VAR_H,
+ VAR_VARS_NB
+};
+
+static int set_enable_expr(AVFilterContext *ctx, const char *expr)
+{
+ int ret;
+ char *expr_dup;
+ AVExpr *old = ctx->enable;
+
+ if (!(ctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE)) {
+ av_log(ctx, AV_LOG_ERROR, "Timeline ('enable' option) not supported "
+ "with filter '%s'\n", ctx->filter->name);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ expr_dup = av_strdup(expr);
+ if (!expr_dup)
+ return AVERROR(ENOMEM);
+
+ if (!ctx->var_values) {
+ ctx->var_values = av_calloc(VAR_VARS_NB, sizeof(*ctx->var_values));
+ if (!ctx->var_values) {
+ av_free(expr_dup);
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ ret = av_expr_parse((AVExpr**)&ctx->enable, expr_dup, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx->priv);
+ if (ret < 0) {
+ av_log(ctx->priv, AV_LOG_ERROR,
+ "Error when evaluating the expression '%s' for enable\n",
+ expr_dup);
+ av_free(expr_dup);
+ return ret;
+ }
+
+ av_expr_free(old);
+ av_free(ctx->enable_str);
+ ctx->enable_str = expr_dup;
+ return 0;
+}
+
+void ff_update_link_current_pts(AVFilterLink *link, int64_t pts)
+{
+ if (pts == AV_NOPTS_VALUE)
+ return;
+ link->current_pts = av_rescale_q(pts, link->time_base, AV_TIME_BASE_Q);
+ /* TODO use duration */
+ if (link->graph && link->age_index >= 0)
+ ff_avfilter_graph_update_heap(link->graph, link);
+}
+
+int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags)
+{
+ if(!strcmp(cmd, "ping")){
+ char local_res[256] = {0};
+
+ if (!res) {
+ res = local_res;
+ res_len = sizeof(local_res);
+ }
+ av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name);
+ if (res == local_res)
+ av_log(filter, AV_LOG_INFO, "%s", res);
+ return 0;
+ }else if(!strcmp(cmd, "enable")) {
+ return set_enable_expr(filter, arg);
+ }else if(filter->filter->process_command) {
+ return filter->filter->process_command(filter, cmd, arg, res, res_len, flags);
+ }
+ return AVERROR(ENOSYS);
+}
+
static AVFilter *first_filter;
+static AVFilter **last_filter = &first_filter;
#if !FF_API_NOCONST_GET_NAME
const
@@ -290,18 +493,31 @@ AVFilter *avfilter_get_by_name(const char *name)
while ((f = avfilter_next(f)))
if (!strcmp(f->name, name))
- return f;
+ return (AVFilter *)f;
return NULL;
}
int avfilter_register(AVFilter *filter)
{
- AVFilter **f = &first_filter;
- while (*f)
- f = &(*f)->next;
- *f = filter;
+ AVFilter **f = last_filter;
+ int i;
+
+ /* the filter must select generic or internal exclusively */
+ av_assert0((filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) != AVFILTER_FLAG_SUPPORT_TIMELINE);
+
+ for(i=0; filter->inputs && filter->inputs[i].name; i++) {
+ const AVFilterPad *input = &filter->inputs[i];
+ av_assert0( !input->filter_frame
+ || (!input->start_frame && !input->end_frame));
+ }
+
filter->next = NULL;
+
+ while(*f || avpriv_atomic_ptr_cas((void * volatile *)f, NULL, filter))
+ f = &(*f)->next;
+ last_filter = &filter->next;
+
return 0;
}
@@ -333,10 +549,10 @@ int avfilter_pad_count(const AVFilterPad *pads)
return count;
}
-static const char *filter_name(void *p)
+static const char *default_filter_name(void *filter_ctx)
{
- AVFilterContext *filter = p;
- return filter->filter->name;
+ AVFilterContext *ctx = filter_ctx;
+ return ctx->name ? ctx->name : ctx->filter->name;
}
static void *filter_child_next(void *obj, void *prev)
@@ -351,10 +567,16 @@ static const AVClass *filter_child_class_next(const AVClass *prev)
{
const AVFilter *f = NULL;
+ /* find the filter that corresponds to prev */
while (prev && (f = avfilter_next(f)))
if (f->priv_class == prev)
break;
+ /* could not find filter corresponding to prev */
+ if (prev && !f)
+ return NULL;
+
+ /* find next filter with specific options */
while ((f = avfilter_next(f)))
if (f->priv_class)
return f->priv_class;
@@ -363,18 +585,20 @@ static const AVClass *filter_child_class_next(const AVClass *prev)
}
#define OFFSET(x) offsetof(AVFilterContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM
static const AVOption avfilter_options[] = {
{ "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,
{ .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" },
{ "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .unit = "thread_type" },
+ { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
{ NULL },
};
static const AVClass avfilter_class = {
.class_name = "AVFilter",
- .item_name = filter_name,
+ .item_name = default_filter_name,
.version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
.child_next = filter_child_next,
.child_class_next = filter_child_class_next,
.option = avfilter_options,
@@ -426,22 +650,22 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name)
ret->nb_inputs = avfilter_pad_count(filter->inputs);
if (ret->nb_inputs ) {
- ret->input_pads = av_malloc(sizeof(AVFilterPad) * ret->nb_inputs);
+ ret->input_pads = av_malloc_array(ret->nb_inputs, sizeof(AVFilterPad));
if (!ret->input_pads)
goto err;
memcpy(ret->input_pads, filter->inputs, sizeof(AVFilterPad) * ret->nb_inputs);
- ret->inputs = av_mallocz(sizeof(AVFilterLink*) * ret->nb_inputs);
+ ret->inputs = av_mallocz_array(ret->nb_inputs, sizeof(AVFilterLink*));
if (!ret->inputs)
goto err;
}
ret->nb_outputs = avfilter_pad_count(filter->outputs);
if (ret->nb_outputs) {
- ret->output_pads = av_malloc(sizeof(AVFilterPad) * ret->nb_outputs);
+ ret->output_pads = av_malloc_array(ret->nb_outputs, sizeof(AVFilterPad));
if (!ret->output_pads)
goto err;
memcpy(ret->output_pads, filter->outputs, sizeof(AVFilterPad) * ret->nb_outputs);
- ret->outputs = av_mallocz(sizeof(AVFilterLink*) * ret->nb_outputs);
+ ret->outputs = av_mallocz_array(ret->nb_outputs, sizeof(AVFilterLink*));
if (!ret->outputs)
goto err;
}
@@ -491,13 +715,16 @@ static void free_link(AVFilterLink *link)
ff_formats_unref(&link->out_samplerates);
ff_channel_layouts_unref(&link->in_channel_layouts);
ff_channel_layouts_unref(&link->out_channel_layouts);
- av_freep(&link);
+ avfilter_link_free(&link);
}
void avfilter_free(AVFilterContext *filter)
{
int i;
+ if (!filter)
+ return;
+
if (filter->graph)
ff_filter_graph_remove_filter(filter->graph, filter);
@@ -520,41 +747,93 @@ void avfilter_free(AVFilterContext *filter)
av_freep(&filter->inputs);
av_freep(&filter->outputs);
av_freep(&filter->priv);
+ while(filter->command_queue){
+ ff_command_queue_pop(filter);
+ }
+ av_opt_free(filter);
+ av_expr_free(filter->enable);
+ filter->enable = NULL;
+ av_freep(&filter->var_values);
av_freep(&filter->internal);
av_free(filter);
}
-/* process a list of value1:value2:..., each value corresponding
- * to subsequent AVOption, in the order they are declared */
-static int process_unnamed_options(AVFilterContext *ctx, AVDictionary **options,
- const char *args)
+static int process_options(AVFilterContext *ctx, AVDictionary **options,
+ const char *args)
{
const AVOption *o = NULL;
- const char *p = args;
- char *val;
+ int ret, count = 0;
+ char *av_uninit(parsed_key), *av_uninit(value);
+ const char *key;
+ int offset= -1;
+
+ if (!args)
+ return 0;
+
+ while (*args) {
+ const char *shorthand = NULL;
- while (*p) {
o = av_opt_next(ctx->priv, o);
- if (!o) {
- av_log(ctx, AV_LOG_ERROR, "More options provided than "
- "this filter supports.\n");
- return AVERROR(EINVAL);
+ if (o) {
+ if (o->type == AV_OPT_TYPE_CONST || o->offset == offset)
+ continue;
+ offset = o->offset;
+ shorthand = o->name;
}
- if (o->type == AV_OPT_TYPE_CONST)
- continue;
- val = av_get_token(&p, ":");
- if (!val)
- return AVERROR(ENOMEM);
+ ret = av_opt_get_key_value(&args, "=", ":",
+ shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0,
+ &parsed_key, &value);
+ if (ret < 0) {
+ if (ret == AVERROR(EINVAL))
+ av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", args);
+ else
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", args,
+ av_err2str(ret));
+ return ret;
+ }
+ if (*args)
+ args++;
+ if (parsed_key) {
+ key = parsed_key;
+ while ((o = av_opt_next(ctx->priv, o))); /* discard all remaining shorthand */
+ } else {
+ key = shorthand;
+ }
- av_dict_set(options, o->name, val, 0);
+ av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
+
+ if (av_opt_find(ctx, key, NULL, 0, 0)) {
+ ret = av_opt_set(ctx, key, value, 0);
+ if (ret < 0) {
+ av_free(value);
+ av_free(parsed_key);
+ return ret;
+ }
+ } else {
+ av_dict_set(options, key, value, 0);
+ if ((ret = av_opt_set(ctx->priv, key, value, 0)) < 0) {
+ if (!av_opt_find(ctx->priv, key, NULL, 0, AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ)) {
+ if (ret == AVERROR_OPTION_NOT_FOUND)
+ av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
+ av_free(value);
+ av_free(parsed_key);
+ return ret;
+ }
+ }
+ }
- av_freep(&val);
- if (*p)
- p++;
+ av_free(value);
+ av_free(parsed_key);
+ count++;
}
- return 0;
+ if (ctx->enable_str) {
+ ret = set_enable_expr(ctx, ctx->enable_str);
+ if (ret < 0)
+ return ret;
+ }
+ return count;
}
#if FF_API_AVFILTER_INIT_FILTER
@@ -591,7 +870,9 @@ int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options)
}
}
- if (ctx->filter->init)
+ if (ctx->filter->init_opaque)
+ ret = ctx->filter->init_opaque(ctx, NULL);
+ else if (ctx->filter->init)
ret = ctx->filter->init(ctx);
else if (ctx->filter->init_dict)
ret = ctx->filter->init_dict(ctx, options);
@@ -613,51 +894,20 @@ int avfilter_init_str(AVFilterContext *filter, const char *args)
}
#if FF_API_OLD_FILTER_OPTS
- if (!strcmp(filter->filter->name, "scale") &&
- strchr(args, ':') && strchr(args, ':') < strchr(args, '=')) {
- /* old w:h:flags=<flags> syntax */
- char *copy = av_strdup(args);
- char *p;
-
- av_log(filter, AV_LOG_WARNING, "The <w>:<h>:flags=<flags> option "
- "syntax is deprecated. Use either <w>:<h>:<flags> or "
- "w=<w>:h=<h>:flags=<flags>.\n");
-
- if (!copy) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
-
- p = strrchr(copy, ':');
- if (p) {
- *p++ = 0;
- ret = av_dict_parse_string(&options, p, "=", ":", 0);
- }
- if (ret >= 0)
- ret = process_unnamed_options(filter, &options, copy);
- av_freep(&copy);
-
- if (ret < 0)
- goto fail;
- } else
-#endif
-
- if (strchr(args, '=')) {
- /* assume a list of key1=value1:key2=value2:... */
- ret = av_dict_parse_string(&options, args, "=", ":", 0);
- if (ret < 0)
- goto fail;
-#if FF_API_OLD_FILTER_OPTS
- } else if (!strcmp(filter->filter->name, "format") ||
+ if ( !strcmp(filter->filter->name, "format") ||
!strcmp(filter->filter->name, "noformat") ||
!strcmp(filter->filter->name, "frei0r") ||
!strcmp(filter->filter->name, "frei0r_src") ||
- !strcmp(filter->filter->name, "ocv")) {
+ !strcmp(filter->filter->name, "ocv") ||
+ !strcmp(filter->filter->name, "pan") ||
+ !strcmp(filter->filter->name, "pp") ||
+ !strcmp(filter->filter->name, "aevalsrc")) {
/* a hack for compatibility with the old syntax
* replace colons with |s */
char *copy = av_strdup(args);
char *p = copy;
int nb_leading = 0; // number of leading colons to skip
+ int deprecated = 0;
if (!copy) {
ret = AVERROR(ENOMEM);
@@ -679,22 +929,43 @@ int avfilter_init_str(AVFilterContext *filter, const char *args)
p++;
}
- if (strchr(p, ':')) {
- av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use "
- "'|' to separate the list items.\n");
- }
-
+ deprecated = strchr(p, ':') != NULL;
+
+ if (!strcmp(filter->filter->name, "aevalsrc")) {
+ deprecated = 0;
+ while ((p = strchr(p, ':')) && p[1] != ':') {
+ const char *epos = strchr(p + 1, '=');
+ const char *spos = strchr(p + 1, ':');
+ const int next_token_is_opt = epos && (!spos || epos < spos);
+ if (next_token_is_opt) {
+ p++;
+ break;
+ }
+ /* next token does not contain a '=', assume a channel expression */
+ deprecated = 1;
+ *p++ = '|';
+ }
+ if (p && *p == ':') { // double sep '::' found
+ deprecated = 1;
+ memmove(p, p + 1, strlen(p));
+ }
+ } else
while ((p = strchr(p, ':')))
*p++ = '|';
- ret = process_unnamed_options(filter, &options, copy);
+ if (deprecated)
+ av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use "
+ "'|' to separate the list items.\n");
+
+ av_log(filter, AV_LOG_DEBUG, "compat: called with args=[%s]\n", copy);
+ ret = process_options(filter, &options, copy);
av_freep(&copy);
if (ret < 0)
goto fail;
#endif
} else {
- ret = process_unnamed_options(filter, &options, args);
+ ret = process_options(filter, &options, args);
if (ret < 0)
goto fail;
}
@@ -731,15 +1002,20 @@ static int default_filter_frame(AVFilterLink *link, AVFrame *frame)
return ff_filter_frame(link->dst->outputs[0], frame);
}
-int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
+static int ff_filter_frame_framed(AVFilterLink *link, AVFrame *frame)
{
int (*filter_frame)(AVFilterLink *, AVFrame *);
+ AVFilterContext *dstctx = link->dst;
AVFilterPad *dst = link->dstpad;
AVFrame *out = NULL;
int ret;
+ AVFilterCommand *cmd= link->dst->command_queue;
+ int64_t pts;
- FF_DPRINTF_START(NULL, filter_frame);
- ff_dlog_link(NULL, link, 1);
+ if (link->closed) {
+ av_frame_free(&frame);
+ return AVERROR_EOF;
+ }
if (!(filter_frame = dst->filter_frame))
filter_frame = default_filter_frame;
@@ -748,6 +1024,7 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
if (dst->needs_writable && !av_frame_is_writable(frame)) {
av_log(link->dst, AV_LOG_DEBUG, "Copying data in avfilter.\n");
+ /* Maybe use ff_copy_buffer_ref instead? */
switch (link->type) {
case AVMEDIA_TYPE_VIDEO:
out = ff_get_video_buffer(link, link->w, link->h);
@@ -770,7 +1047,7 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
switch (link->type) {
case AVMEDIA_TYPE_VIDEO:
- av_image_copy(out->data, out->linesize, frame->data, frame->linesize,
+ av_image_copy(out->data, out->linesize, (const uint8_t **)frame->data, frame->linesize,
frame->format, frame->width, frame->height);
break;
case AVMEDIA_TYPE_AUDIO:
@@ -788,7 +1065,34 @@ int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
} else
out = frame;
- return filter_frame(link, out);
+ while(cmd && cmd->time <= out->pts * av_q2d(link->time_base)){
+ av_log(link->dst, AV_LOG_DEBUG,
+ "Processing command time:%f command:%s arg:%s\n",
+ cmd->time, cmd->command, cmd->arg);
+ avfilter_process_command(link->dst, cmd->command, cmd->arg, 0, 0, cmd->flags);
+ ff_command_queue_pop(link->dst);
+ cmd= link->dst->command_queue;
+ }
+
+ pts = out->pts;
+ if (dstctx->enable_str) {
+ int64_t pos = av_frame_get_pkt_pos(out);
+ dstctx->var_values[VAR_N] = link->frame_count;
+ 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;
+ dstctx->var_values[VAR_POS] = pos == -1 ? NAN : pos;
+
+ dstctx->is_disabled = fabs(av_expr_eval(dstctx->enable, dstctx->var_values, NULL)) < 0.5;
+ if (dstctx->is_disabled &&
+ (dstctx->filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC))
+ filter_frame = default_filter_frame;
+ }
+ ret = filter_frame(link, out);
+ link->frame_count++;
+ link->frame_requested = 0;
+ ff_update_link_current_pts(link, pts);
+ return ret;
fail:
av_frame_free(&out);
@@ -796,6 +1100,79 @@ fail:
return ret;
}
+static int ff_filter_frame_needs_framing(AVFilterLink *link, AVFrame *frame)
+{
+ int insamples = frame->nb_samples, inpos = 0, nb_samples;
+ AVFrame *pbuf = link->partial_buf;
+ int nb_channels = av_frame_get_channels(frame);
+ int ret = 0;
+
+ link->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ /* Handle framing (min_samples, max_samples) */
+ while (insamples) {
+ if (!pbuf) {
+ AVRational samples_tb = { 1, link->sample_rate };
+ pbuf = ff_get_audio_buffer(link, link->partial_buf_size);
+ if (!pbuf) {
+ av_log(link->dst, AV_LOG_WARNING,
+ "Samples dropped due to memory allocation failure.\n");
+ return 0;
+ }
+ av_frame_copy_props(pbuf, frame);
+ pbuf->pts = frame->pts;
+ if (pbuf->pts != AV_NOPTS_VALUE)
+ pbuf->pts += av_rescale_q(inpos, samples_tb, link->time_base);
+ pbuf->nb_samples = 0;
+ }
+ nb_samples = FFMIN(insamples,
+ link->partial_buf_size - pbuf->nb_samples);
+ av_samples_copy(pbuf->extended_data, frame->extended_data,
+ pbuf->nb_samples, inpos,
+ nb_samples, nb_channels, link->format);
+ inpos += nb_samples;
+ insamples -= nb_samples;
+ pbuf->nb_samples += nb_samples;
+ if (pbuf->nb_samples >= link->min_samples) {
+ ret = ff_filter_frame_framed(link, pbuf);
+ pbuf = NULL;
+ }
+ }
+ av_frame_free(&frame);
+ link->partial_buf = pbuf;
+ return ret;
+}
+
+int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
+{
+ FF_TPRINTF_START(NULL, filter_frame); ff_tlog_link(NULL, link, 1); ff_tlog(NULL, " "); ff_tlog_ref(NULL, frame, 1);
+
+ /* Consistency checks */
+ if (link->type == AVMEDIA_TYPE_VIDEO) {
+ if (strcmp(link->dst->filter->name, "scale") &&
+ strcmp(link->dst->filter->name, "idet")) {
+ av_assert1(frame->format == link->format);
+ av_assert1(frame->width == link->w);
+ av_assert1(frame->height == link->h);
+ }
+ } else {
+ av_assert1(frame->format == link->format);
+ av_assert1(av_frame_get_channels(frame) == link->channels);
+ av_assert1(frame->channel_layout == link->channel_layout);
+ av_assert1(frame->sample_rate == link->sample_rate);
+ }
+
+ /* Go directly to actual filtering if possible */
+ if (link->type == AVMEDIA_TYPE_AUDIO &&
+ link->min_samples &&
+ (link->partial_buf ||
+ frame->nb_samples < link->min_samples ||
+ frame->nb_samples > link->max_samples)) {
+ return ff_filter_frame_needs_framing(link, frame);
+ } else {
+ return ff_filter_frame_framed(link, frame);
+ }
+}
+
const AVClass *avfilter_get_class(void)
{
return &avfilter_class;
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 57aa86d6b1..296f2d3c9a 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -2,20 +2,20 @@
* filter layer
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,16 +33,17 @@
* @{
*/
+#include <stddef.h>
+
#include "libavutil/attributes.h"
#include "libavutil/avutil.h"
+#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/samplefmt.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
-#include <stddef.h>
-
#include "libavfilter/version.h"
/**
@@ -60,7 +61,6 @@ const char *avfilter_configuration(void);
*/
const char *avfilter_license(void);
-
typedef struct AVFilterContext AVFilterContext;
typedef struct AVFilterLink AVFilterLink;
typedef struct AVFilterPad AVFilterPad;
@@ -113,6 +113,9 @@ typedef struct AVFilterBuffer {
#define AV_PERM_REUSE 0x08 ///< can output the buffer multiple times, with the same contents each time
#define AV_PERM_REUSE2 0x10 ///< can output the buffer multiple times, modified each time
#define AV_PERM_NEG_LINESIZES 0x20 ///< the buffer requested can have negative linesizes
+#define AV_PERM_ALIGN 0x40 ///< the buffer must be aligned
+
+#define AVFILTER_ALIGN 16 //not part of ABI
/**
* Audio specific properties in a reference to an AVFilterBuffer. Since
@@ -121,9 +124,9 @@ typedef struct AVFilterBuffer {
*/
typedef struct AVFilterBufferRefAudioProps {
uint64_t channel_layout; ///< channel layout of audio buffer
- int nb_samples; ///< number of audio samples
+ int nb_samples; ///< number of audio samples per channel
int sample_rate; ///< audio buffer sample rate
- int planar; ///< audio buffer - planar or packed
+ int channels; ///< number of channels (do not access directly)
} AVFilterBufferRefAudioProps;
/**
@@ -134,11 +137,14 @@ typedef struct AVFilterBufferRefAudioProps {
typedef struct AVFilterBufferRefVideoProps {
int w; ///< image width
int h; ///< image height
- AVRational pixel_aspect; ///< pixel aspect ratio
+ AVRational sample_aspect_ratio; ///< sample aspect ratio
int interlaced; ///< is frame interlaced
int top_field_first; ///< field order
enum AVPictureType pict_type; ///< picture type of the frame
int key_frame; ///< 1 -> keyframe, 0-> not
+ int qp_table_linesize; ///< qp_table stride
+ int qp_table_size; ///< qp_table size
+ int8_t *qp_table; ///< array of Quantization Parameters
} AVFilterBufferRefVideoProps;
/**
@@ -185,13 +191,15 @@ typedef struct AVFilterBufferRef {
int perms; ///< permissions, see the AV_PERM_* flags
enum AVMediaType type; ///< media type of buffer data
+
+ AVDictionary *metadata; ///< dictionary containing metadata key=value tags
} AVFilterBufferRef;
/**
* Copy properties of src to dst, without copying the actual data
*/
attribute_deprecated
-void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *src);
+void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, const AVFilterBufferRef *src);
/**
* Add a new reference to a buffer.
@@ -228,11 +236,19 @@ attribute_deprecated
void avfilter_unref_bufferp(AVFilterBufferRef **ref);
#endif
+/**
+ * Get the number of channels of a buffer reference.
+ */
+attribute_deprecated
+int avfilter_ref_get_channels(AVFilterBufferRef *ref);
+
#if FF_API_AVFILTERPAD_PUBLIC
/**
* A filter pad used for either input or output.
*
- * @warning this struct will be removed from public API.
+ * See doc/filter_design.txt for details on how to implement the methods.
+ *
+ * @warning this struct might be removed from public API.
* users should call avfilter_pad_get_name() and avfilter_pad_get_type()
* to access the name and type fields; there should be no need to access
* any other fields from outside of libavfilter.
@@ -251,22 +267,29 @@ struct AVFilterPad {
enum AVMediaType type;
/**
+ * Input pads:
* Minimum required permissions on incoming buffers. Any buffer with
* insufficient permissions will be automatically copied by the filter
* system to a new buffer which provides the needed access permissions.
*
- * Input pads only.
+ * Output pads:
+ * Guaranteed permissions on outgoing buffers. Any buffer pushed on the
+ * link must have at least these permissions; this fact is checked by
+ * asserts. It can be used to optimize buffer allocation.
*/
attribute_deprecated int min_perms;
/**
+ * Input pads:
* Permissions which are not accepted on incoming buffers. Any buffer
* which has any of these permissions set will be automatically copied
* by the filter system to a new buffer which does not have those
* permissions. This can be used to easily disallow buffers with
* AV_PERM_REUSE.
*
- * Input pads only.
+ * Output pads:
+ * Permissions which are automatically removed on outgoing buffers. It
+ * can be used to optimize buffer allocation.
*/
attribute_deprecated int rej_perms;
@@ -277,7 +300,7 @@ struct AVFilterPad {
/**
* Callback function to get a video buffer. If NULL, the filter system will
- * use avfilter_default_get_video_buffer().
+ * use ff_default_get_video_buffer().
*
* Input video pads only.
*/
@@ -285,7 +308,7 @@ struct AVFilterPad {
/**
* Callback function to get an audio buffer. If NULL, the filter system will
- * use avfilter_default_get_audio_buffer().
+ * use ff_default_get_audio_buffer().
*
* Input audio pads only.
*/
@@ -308,7 +331,7 @@ struct AVFilterPad {
* Input pads only.
*
* @return >= 0 on success, a negative AVERROR on error. This function
- * must ensure that samplesref is properly unreferenced on error if it
+ * 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);
@@ -328,6 +351,8 @@ struct AVFilterPad {
* Frame request callback. A call to this should result in at least one
* frame being output over the given link. This should return zero on
* success, and another value on error.
+ * See ff_request_frame() for the error codes with a specific
+ * meaning.
*
* Output pads only.
*/
@@ -336,15 +361,18 @@ struct AVFilterPad {
/**
* 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
+ * For output pads, this should set the following link properties:
+ * video: width, height, sample_aspect_ratio, time_base
+ * audio: sample_rate.
+ *
+ * This should NOT set properties such as format, channel_layout, etc which
+ * are 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,
+ * For both input and output pads, this should return zero on success,
* and another value on error.
*/
int (*config_props)(AVFilterLink *link);
@@ -412,6 +440,28 @@ enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx);
* and processing them concurrently.
*/
#define AVFILTER_FLAG_SLICE_THREADS (1 << 2)
+/**
+ * Some filters support a generic "enable" expression option that can be used
+ * to enable or disable a filter in the timeline. Filters supporting this
+ * option have this flag set. When the enable expression is false, the default
+ * no-op filter_frame() function is called in place of the filter_frame()
+ * callback defined on each input pad, thus the frame is passed unchanged to
+ * the next filters.
+ */
+#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC (1 << 16)
+/**
+ * Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will
+ * have its filter_frame() callback(s) called as usual even when the enable
+ * expression is false. The filter will disable filtering within the
+ * filter_frame() callback(s) itself, for example executing code depending on
+ * the AVFilterContext->is_disabled value.
+ */
+#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL (1 << 17)
+/**
+ * Handy mask to test whether the filter supports or no the timeline feature
+ * (internally or generically).
+ */
+#define AVFILTER_FLAG_SUPPORT_TIMELINE (AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL)
/**
* Filter definition. This defines the pads a filter contains, and all the
@@ -549,6 +599,27 @@ typedef struct AVFilter {
* code.
*/
struct AVFilter *next;
+
+ /**
+ * Make the filter instance process a command.
+ *
+ * @param cmd the command to process, for handling simplicity all commands must be alphanumeric only
+ * @param arg the argument for the command
+ * @param res a buffer with size res_size where the filter(s) can return a response. This must not change when the command is not supported.
+ * @param flags if AVFILTER_CMD_FLAG_FAST is set and the command would be
+ * time consuming then a filter should treat it like an unsupported command
+ *
+ * @returns >=0 on success otherwise an error code.
+ * AVERROR(ENOSYS) on unsupported commands
+ */
+ int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags);
+
+ /**
+ * Filter initialization function, alternative to the init()
+ * callback. Args contains the user-supplied parameters, opaque is
+ * used for providing binary data.
+ */
+ int (*init_opaque)(AVFilterContext *ctx, void *opaque);
} AVFilter;
/**
@@ -560,7 +631,7 @@ typedef struct AVFilterInternal AVFilterInternal;
/** An instance of a filter */
struct AVFilterContext {
- const AVClass *av_class; ///< needed for av_log()
+ const AVClass *av_class; ///< needed for av_log() and filters common options
const AVFilter *filter; ///< the AVFilter of which this is an instance
@@ -597,7 +668,7 @@ struct AVFilterContext {
* allowed threading types. I.e. a threading type needs to be set in both
* to be allowed.
*
- * After the filter is initialzed, libavfilter sets this field to the
+ * After the filter is initialized, libavfilter sets this field to the
* threading type that is actually used (0 for no multithreading).
*/
int thread_type;
@@ -606,6 +677,13 @@ struct AVFilterContext {
* An opaque struct for libavfilter internal use.
*/
AVFilterInternal *internal;
+
+ struct AVFilterCommand *command_queue;
+
+ char *enable_str; ///< enable expression string
+ void *enable; ///< parsed expression (AVExpr*)
+ double *var_values; ///< variable values for the enable expression
+ int is_disabled; ///< the enabled state from the last expression evaluation
};
/**
@@ -628,7 +706,7 @@ struct AVFilterLink {
int w; ///< agreed upon image width
int h; ///< agreed upon image height
AVRational sample_aspect_ratio; ///< agreed upon sample aspect ratio
- /* These two parameters apply only to audio */
+ /* These parameters apply only to audio */
uint64_t channel_layout; ///< channel layout of current buffer (see libavutil/channel_layout.h)
int sample_rate; ///< samples per second
@@ -651,9 +729,11 @@ struct AVFilterLink {
*****************************************************************
*/
/**
- * Lists of formats supported by the input and output filters respectively.
- * These lists are used for negotiating the format to actually be used,
- * which will be loaded into the format member, above, when chosen.
+ * Lists of formats and channel layouts supported by the input and output
+ * filters respectively. These lists are used for negotiating the format
+ * to actually be used, which will be loaded into the format and
+ * channel_layout members, above, when chosen.
+ *
*/
AVFilterFormats *in_formats;
AVFilterFormats *out_formats;
@@ -682,6 +762,104 @@ struct AVFilterLink {
AVLINK_STARTINIT, ///< started, but incomplete
AVLINK_INIT ///< complete
} init_state;
+
+ struct AVFilterPool *pool;
+
+ /**
+ * Graph the filter belongs to.
+ */
+ struct AVFilterGraph *graph;
+
+ /**
+ * Current timestamp of the link, as defined by the most recent
+ * frame(s), in AV_TIME_BASE units.
+ */
+ int64_t current_pts;
+
+ /**
+ * Index in the age array.
+ */
+ int age_index;
+
+ /**
+ * Frame rate of the stream on the link, or 1/0 if unknown;
+ * if left to 0/0, will be automatically be 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.
+ * 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;
+
+ /**
+ * Buffer partially filled with samples to achieve a fixed/minimum size.
+ */
+ AVFrame *partial_buf;
+
+ /**
+ * Size of the partial buffer to allocate.
+ * Must be between min_samples and max_samples.
+ */
+ int partial_buf_size;
+
+ /**
+ * Minimum number of samples to filter at once. If filter_frame() is
+ * called with fewer samples, it will accumulate them in partial_buf.
+ * 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;
+
+ /**
+ * The buffer reference currently being received across the link by the
+ * destination filter. This is used internally by the filter system to
+ * allow automatic copying of buffers which do not have sufficient
+ * permissions for the destination. This should not be accessed directly
+ * by the filters.
+ */
+ AVFilterBufferRef *cur_buf_copy;
+
+ /**
+ * True if the link is closed.
+ * If set, all attempts of start_frame, filter_frame or request_frame
+ * will fail with AVERROR_EOF, and if necessary the reference will be
+ * destroyed.
+ * If request_frame returns AVERROR_EOF, this flag is set on the
+ * corresponding link.
+ * It can be set also be set by either the source or the destination
+ * filter.
+ */
+ int closed;
+
+ /**
+ * Number of channels.
+ */
+ int channels;
+
+ /**
+ * True if a frame is being requested on the link.
+ * Used internally by the framework.
+ */
+ unsigned frame_requested;
+
+ /**
+ * Link processing flags.
+ */
+ unsigned flags;
+
+ /**
+ * Number of past frames sent through the link.
+ */
+ int64_t frame_count;
};
/**
@@ -697,6 +875,21 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad,
AVFilterContext *dst, unsigned dstpad);
/**
+ * Free the link in *link, and set its pointer to NULL.
+ */
+void avfilter_link_free(AVFilterLink **link);
+
+/**
+ * Get the number of channels of a link.
+ */
+int avfilter_link_get_channels(AVFilterLink *link);
+
+/**
+ * Set the closed field of a link.
+ */
+void avfilter_link_set_closed(AVFilterLink *link, int closed);
+
+/**
* Negotiate the media format, dimensions, etc of all inputs to a filter.
*
* @param filter the filter to negotiate the properties for its inputs
@@ -718,13 +911,16 @@ int avfilter_config_links(AVFilterContext *filter);
*/
attribute_deprecated
AVFilterBufferRef *
-avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int perms,
+avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int linesize[4], int perms,
int w, int h, enum AVPixelFormat format);
/**
* Create an audio buffer reference wrapped around an already
* allocated samples buffer.
*
+ * See avfilter_get_audio_buffer_ref_from_arrays_channels() for a version
+ * that can handle unknown channel layouts.
+ *
* @param data pointers to the samples plane buffers
* @param linesize linesize for the samples plane buffers
* @param perms the required access permissions
@@ -739,8 +935,40 @@ AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays(uint8_t **data,
int nb_samples,
enum AVSampleFormat sample_fmt,
uint64_t channel_layout);
+/**
+ * Create an audio buffer reference wrapped around an already
+ * allocated samples buffer.
+ *
+ * @param data pointers to the samples plane buffers
+ * @param linesize linesize for the samples plane buffers
+ * @param perms the required access permissions
+ * @param nb_samples number of samples per channel
+ * @param sample_fmt the format of each sample in the buffer to allocate
+ * @param channels the number of channels of the buffer
+ * @param channel_layout the channel layout of the buffer,
+ * must be either 0 or consistent with channels
+ */
+attribute_deprecated
+AVFilterBufferRef *avfilter_get_audio_buffer_ref_from_arrays_channels(uint8_t **data,
+ int linesize,
+ int perms,
+ int nb_samples,
+ enum AVSampleFormat sample_fmt,
+ int channels,
+ uint64_t channel_layout);
+
#endif
+
+#define AVFILTER_CMD_FLAG_ONE 1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically
+#define AVFILTER_CMD_FLAG_FAST 2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw)
+
+/**
+ * Make the filter instance process a command.
+ * It is recommended to use avfilter_graph_send_command().
+ */
+int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags);
+
/** Initialize the filter system. Register all builtin filters. */
void avfilter_register_all(void);
@@ -757,7 +985,7 @@ void avfilter_uninit(void);
* is not registered.
*
* @param filter the filter to register
- * @return 0 if the registration was succesfull, a negative value
+ * @return 0 if the registration was successful, a negative value
* otherwise
*/
int avfilter_register(AVFilter *filter);
@@ -940,7 +1168,7 @@ typedef struct AVFilterGraph {
const AVClass *av_class;
#if FF_API_FOO_COUNT
attribute_deprecated
- unsigned filter_count;
+ unsigned filter_count_unused;
#endif
AVFilterContext **filters;
#if !FF_API_FOO_COUNT
@@ -999,6 +1227,20 @@ typedef struct AVFilterGraph {
* platform and build options.
*/
avfilter_execute_func *execute;
+
+ char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions
+
+ /**
+ * Private fields
+ *
+ * The following fields are for internal use only.
+ * Their type, offset, number and semantic can change without notice.
+ */
+
+ AVFilterLink **sink_links;
+ int sink_links_count;
+
+ unsigned disable_auto_convert;
} AVFilterGraph;
/**
@@ -1020,19 +1262,21 @@ AVFilterGraph *avfilter_graph_alloc(void);
*
* @return the context of the newly created filter instance (note that it is
* also retrievable directly through AVFilterGraph.filters or with
- * avfilter_graph_get_filter()) on success or NULL or failure.
+ * avfilter_graph_get_filter()) on success or NULL on failure.
*/
AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
const AVFilter *filter,
const char *name);
/**
- * Get a filter instance with name name from graph.
+ * Get a filter instance identified by instance name from graph.
*
+ * @param graph filter graph to search through.
+ * @param name filter instance name (should be unique in the graph).
* @return the pointer to the found filter instance or NULL if it
* cannot be found.
*/
-AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name);
+AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name);
#if FF_API_AVFILTER_OPEN
/**
@@ -1066,11 +1310,26 @@ int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *fil
AVFilterGraph *graph_ctx);
/**
+ * Enable or disable automatic format conversion inside the graph.
+ *
+ * Note that format conversion can still happen inside explicitly inserted
+ * scale and aresample filters.
+ *
+ * @param flags any of the AVFILTER_AUTO_CONVERT_* constants
+ */
+void avfilter_graph_set_auto_convert(AVFilterGraph *graph, unsigned flags);
+
+enum {
+ AVFILTER_AUTO_CONVERT_ALL = 0, /**< all automatic conversions enabled */
+ AVFILTER_AUTO_CONVERT_NONE = -1, /**< all automatic conversions disabled */
+};
+
+/**
* Check validity and configure all the links and formats in the graph.
*
* @param graphctx the filter graph
* @param log_ctx context used for logging
- * @return 0 in case of success, a negative AVERROR code otherwise
+ * @return >= 0 in case of success, a negative AVERROR code otherwise
*/
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx);
@@ -1116,9 +1375,19 @@ AVFilterInOut *avfilter_inout_alloc(void);
*/
void avfilter_inout_free(AVFilterInOut **inout);
+#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI || !FF_API_OLD_GRAPH_PARSE
/**
* Add a graph described by a string to a graph.
*
+ * @note The caller must provide the lists of inputs and outputs,
+ * which therefore must be known before calling the function.
+ *
+ * @note The inputs parameter describes inputs of the already existing
+ * part of the graph; i.e. from the point of view of the newly created
+ * part, they are outputs. Similarly the outputs parameter describes
+ * outputs of the already existing filters, which are provided as
+ * inputs to the parsed filters.
+ *
* @param graph the filter graph where to link the parsed graph context
* @param filters string to be parsed
* @param inputs linked list to the inputs of the graph
@@ -1128,6 +1397,47 @@ void avfilter_inout_free(AVFilterInOut **inout);
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
AVFilterInOut *inputs, AVFilterInOut *outputs,
void *log_ctx);
+#else
+/**
+ * Add a graph described by a string to a graph.
+ *
+ * @param graph the filter graph where to link the parsed graph context
+ * @param filters string to be parsed
+ * @param inputs pointer to a linked list to the inputs of the graph, may be NULL.
+ * If non-NULL, *inputs is updated to contain the list of open inputs
+ * after the parsing, should be freed with avfilter_inout_free().
+ * @param outputs pointer to a linked list to the outputs of the graph, may be NULL.
+ * If non-NULL, *outputs is updated to contain the list of open outputs
+ * after the parsing, should be freed with avfilter_inout_free().
+ * @return non negative on success, a negative AVERROR code on error
+ * @deprecated Use avfilter_graph_parse_ptr() instead.
+ */
+attribute_deprecated
+int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut **inputs, AVFilterInOut **outputs,
+ void *log_ctx);
+#endif
+
+/**
+ * Add a graph described by a string to a graph.
+ *
+ * In the graph filters description, if the input label of the first
+ * filter is not specified, "in" is assumed; if the output label of
+ * the last filter is not specified, "out" is assumed.
+ *
+ * @param graph the filter graph where to link the parsed graph context
+ * @param filters string to be parsed
+ * @param inputs pointer to a linked list to the inputs of the graph, may be NULL.
+ * If non-NULL, *inputs is updated to contain the list of open inputs
+ * after the parsing, should be freed with avfilter_inout_free().
+ * @param outputs pointer to a linked list to the outputs of the graph, may be NULL.
+ * If non-NULL, *outputs is updated to contain the list of open outputs
+ * after the parsing, should be freed with avfilter_inout_free().
+ * @return non negative on success, a negative AVERROR code on error
+ */
+int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut **inputs, AVFilterInOut **outputs,
+ void *log_ctx);
/**
* Add a graph described by a string to a graph.
@@ -1142,21 +1452,13 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
* caller using avfilter_inout_free().
* @return zero on success, a negative AVERROR code on error
*
- * @note the difference between avfilter_graph_parse2() and
- * avfilter_graph_parse() is that in avfilter_graph_parse(), the caller provides
- * the lists of inputs and outputs, which therefore must be known before calling
- * the function. On the other hand, avfilter_graph_parse2() \em returns the
- * inputs and outputs that are left unlinked after parsing the graph and the
- * caller then deals with them. Another difference is that in
- * avfilter_graph_parse(), the inputs parameter describes inputs of the
- * <em>already existing</em> part of the graph; i.e. from the point of view of
- * the newly created part, they are outputs. Similarly the outputs parameter
- * describes outputs of the already existing filters, which are provided as
- * inputs to the parsed filters.
- * avfilter_graph_parse2() takes the opposite approach -- it makes no reference
- * whatsoever to already existing parts of the graph and the inputs parameter
- * will on return contain inputs of the newly parsed part of the graph.
- * Analogously the outputs parameter will contain outputs of the newly created
+ * @note This function returns the inputs and outputs that are left
+ * unlinked after parsing the graph and the caller then deals with
+ * them.
+ * @note This function makes no reference whatsoever to already
+ * existing parts of the graph and the inputs parameter will on return
+ * contain inputs of the newly parsed part of the graph. Analogously
+ * the outputs parameter will contain outputs of the newly created
* filters.
*/
int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
@@ -1164,6 +1466,71 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
AVFilterInOut **outputs);
/**
+ * Send a command to one or more filter instances.
+ *
+ * @param graph the filter graph
+ * @param target the filter(s) to which the command should be sent
+ * "all" sends to all filters
+ * otherwise it can be a filter or filter instance name
+ * which will send the command to all matching filters.
+ * @param cmd the command to send, for handling simplicity all commands must be alphanumeric only
+ * @param arg the argument for the command
+ * @param res a buffer with size res_size where the filter(s) can return a response.
+ *
+ * @returns >=0 on success otherwise an error code.
+ * AVERROR(ENOSYS) on unsupported commands
+ */
+int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags);
+
+/**
+ * Queue a command for one or more filter instances.
+ *
+ * @param graph the filter graph
+ * @param target the filter(s) to which the command should be sent
+ * "all" sends to all filters
+ * otherwise it can be a filter or filter instance name
+ * which will send the command to all matching filters.
+ * @param cmd the command to sent, for handling simplicity all commands must be alphanumeric only
+ * @param arg the argument for the command
+ * @param ts time at which the command should be sent to the filter
+ *
+ * @note As this executes commands after this function returns, no return code
+ * from the filter is provided, also AVFILTER_CMD_FLAG_ONE is not supported.
+ */
+int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, int flags, double ts);
+
+
+/**
+ * Dump a graph into a human-readable string representation.
+ *
+ * @param graph the graph to dump
+ * @param options formatting options; currently ignored
+ * @return a string, or NULL in case of memory allocation failure;
+ * the string must be freed using av_free
+ */
+char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
+
+/**
+ * Request a frame on the oldest sink link.
+ *
+ * If the request returns AVERROR_EOF, try the next.
+ *
+ * Note that this function is not meant to be the sole scheduling mechanism
+ * of a filtergraph, only a convenience function to help drain a filtergraph
+ * in a balanced way under normal circumstances.
+ *
+ * Also note that AVERROR_EOF does not mean that frames did not arrive on
+ * some of the sinks during the process.
+ * When there are multiple sink links, in case the requested link
+ * returns an EOF, this may cause a filter to flush pending frames
+ * which are sent to another sink link, although unrequested.
+ *
+ * @return the return value of ff_request_frame(),
+ * or AVERROR_EOF if all links returned AVERROR_EOF
+ */
+int avfilter_graph_request_oldest(AVFilterGraph *graph);
+
+/**
* @}
*/
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 0fc385c3a6..bac0da18a4 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Vitor Sessak
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,11 +26,11 @@
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
-#include "libavutil/common.h"
#include "libavutil/internal.h"
-#include "libavutil/log.h"
#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
#include "avfilter.h"
#include "formats.h"
@@ -38,13 +38,17 @@
#include "thread.h"
#define OFFSET(x) offsetof(AVFilterGraph, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption filtergraph_options[] = {
{ "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS,
{ .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" },
{ "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = FLAGS, .unit = "thread_type" },
{ "threads", "Maximum number of threads", OFFSET(nb_threads),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ {"scale_sws_opts" , "default scale filter options" , OFFSET(scale_sws_opts) ,
+ AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ {"aresample_swr_opts" , "default aresample filter options" , OFFSET(aresample_swr_opts) ,
+ AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
{ NULL },
};
@@ -53,6 +57,7 @@ static const AVClass filtergraph_class = {
.item_name = av_default_item_name,
.version = LIBAVUTIL_VERSION_INT,
.option = filtergraph_options,
+ .category = AV_CLASS_CATEGORY_FILTER,
};
#if !HAVE_THREADS
@@ -109,7 +114,10 @@ void avfilter_graph_free(AVFilterGraph **graph)
ff_graph_thread_free(*graph);
+ av_freep(&(*graph)->sink_links);
+
av_freep(&(*graph)->scale_sws_opts);
+ av_freep(&(*graph)->aresample_swr_opts);
av_freep(&(*graph)->resample_lavr_opts);
av_freep(&(*graph)->filters);
av_freep(&(*graph)->internal);
@@ -129,7 +137,7 @@ int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter)
#if FF_API_FOO_COUNT
FF_DISABLE_DEPRECATION_WARNINGS
- graph->filter_count = graph->nb_filters;
+ graph->filter_count_unused = graph->nb_filters;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
@@ -162,6 +170,11 @@ fail:
return ret;
}
+void avfilter_graph_set_auto_convert(AVFilterGraph *graph, unsigned flags)
+{
+ graph->disable_auto_convert = flags;
+}
+
AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
const AVFilter *filter,
const char *name)
@@ -195,7 +208,7 @@ AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph,
#if FF_API_FOO_COUNT
FF_DISABLE_DEPRECATION_WARNINGS
- graph->filter_count = graph->nb_filters;
+ graph->filter_count_unused = graph->nb_filters;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
@@ -210,7 +223,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
* A graph is considered valid if all its input and output pads are
* connected.
*
- * @return 0 in case of success, a negative value otherwise
+ * @return >= 0 in case of success, a negative value otherwise
*/
static int graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
{
@@ -218,22 +231,25 @@ static int graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
int i, j;
for (i = 0; i < graph->nb_filters; i++) {
+ const AVFilterPad *pad;
filt = graph->filters[i];
for (j = 0; j < filt->nb_inputs; j++) {
if (!filt->inputs[j] || !filt->inputs[j]->src) {
+ pad = &filt->input_pads[j];
av_log(log_ctx, AV_LOG_ERROR,
- "Input pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any source\n",
- filt->input_pads[j].name, filt->name, filt->filter->name);
+ "Input pad \"%s\" with type %s of the filter instance \"%s\" of %s not connected to any source\n",
+ pad->name, av_get_media_type_string(pad->type), filt->name, filt->filter->name);
return AVERROR(EINVAL);
}
}
for (j = 0; j < filt->nb_outputs; j++) {
if (!filt->outputs[j] || !filt->outputs[j]->dst) {
+ pad = &filt->output_pads[j];
av_log(log_ctx, AV_LOG_ERROR,
- "Output pad \"%s\" for the filter \"%s\" of type \"%s\" not connected to any destination\n",
- filt->output_pads[j].name, filt->name, filt->filter->name);
+ "Output pad \"%s\" with type %s of the filter instance \"%s\" of %s not connected to any destination\n",
+ pad->name, av_get_media_type_string(pad->type), filt->name, filt->filter->name);
return AVERROR(EINVAL);
}
}
@@ -245,7 +261,7 @@ static int graph_check_validity(AVFilterGraph *graph, AVClass *log_ctx)
/**
* Configure all the links of graphctx.
*
- * @return 0 in case of success, a negative value otherwise
+ * @return >= 0 in case of success, a negative value otherwise
*/
static int graph_config_links(AVFilterGraph *graph, AVClass *log_ctx)
{
@@ -264,7 +280,7 @@ static int graph_config_links(AVFilterGraph *graph, AVClass *log_ctx)
return 0;
}
-AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name)
+AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name)
{
int i;
@@ -275,17 +291,169 @@ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, char *name)
return NULL;
}
+static void sanitize_channel_layouts(void *log, AVFilterChannelLayouts *l)
+{
+ if (!l)
+ return;
+ if (l->nb_channel_layouts) {
+ if (l->all_layouts || l->all_counts)
+ av_log(log, AV_LOG_WARNING, "All layouts set on non-empty list\n");
+ l->all_layouts = l->all_counts = 0;
+ } else {
+ if (l->all_counts && !l->all_layouts)
+ av_log(log, AV_LOG_WARNING, "All counts without all layouts\n");
+ l->all_layouts = 1;
+ }
+}
+
+static int filter_query_formats(AVFilterContext *ctx)
+{
+ int ret, i;
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *chlayouts;
+ AVFilterFormats *samplerates;
+ enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :
+ ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
+ AVMEDIA_TYPE_VIDEO;
+
+ if ((ret = ctx->filter->query_formats(ctx)) < 0) {
+ if (ret != AVERROR(EAGAIN))
+ av_log(ctx, AV_LOG_ERROR, "Query format failed for '%s': %s\n",
+ ctx->name, av_err2str(ret));
+ return ret;
+ }
+
+ for (i = 0; i < ctx->nb_inputs; i++)
+ sanitize_channel_layouts(ctx, ctx->inputs[i]->out_channel_layouts);
+ for (i = 0; i < ctx->nb_outputs; i++)
+ sanitize_channel_layouts(ctx, ctx->outputs[i]->in_channel_layouts);
+
+ formats = ff_all_formats(type);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_set_common_formats(ctx, formats);
+ if (type == AVMEDIA_TYPE_AUDIO) {
+ samplerates = ff_all_samplerates();
+ if (!samplerates)
+ return AVERROR(ENOMEM);
+ ff_set_common_samplerates(ctx, samplerates);
+ chlayouts = ff_all_channel_layouts();
+ if (!chlayouts)
+ return AVERROR(ENOMEM);
+ ff_set_common_channel_layouts(ctx, chlayouts);
+ }
+ return 0;
+}
+
+static int formats_declared(AVFilterContext *f)
+{
+ int i;
+
+ for (i = 0; i < f->nb_inputs; i++) {
+ if (!f->inputs[i]->out_formats)
+ return 0;
+ if (f->inputs[i]->type == AVMEDIA_TYPE_AUDIO &&
+ !(f->inputs[i]->out_samplerates &&
+ f->inputs[i]->out_channel_layouts))
+ return 0;
+ }
+ for (i = 0; i < f->nb_outputs; i++) {
+ if (!f->outputs[i]->in_formats)
+ return 0;
+ if (f->outputs[i]->type == AVMEDIA_TYPE_AUDIO &&
+ !(f->outputs[i]->in_samplerates &&
+ f->outputs[i]->in_channel_layouts))
+ return 0;
+ }
+ return 1;
+}
+
+static AVFilterFormats *clone_filter_formats(AVFilterFormats *arg)
+{
+ AVFilterFormats *a = av_memdup(arg, sizeof(*arg));
+ if (a) {
+ a->refcount = 0;
+ a->refs = NULL;
+ a->formats = av_memdup(a->formats, sizeof(*a->formats) * a->nb_formats);
+ if (!a->formats && arg->formats)
+ av_freep(&a);
+ }
+ return a;
+}
+
+static int can_merge_formats(AVFilterFormats *a_arg,
+ AVFilterFormats *b_arg,
+ enum AVMediaType type,
+ int is_sample_rate)
+{
+ AVFilterFormats *a, *b, *ret;
+ if (a_arg == b_arg)
+ return 1;
+ a = clone_filter_formats(a_arg);
+ b = clone_filter_formats(b_arg);
+
+ if (!a || !b) {
+ if (a)
+ av_freep(&a->formats);
+ if (b)
+ av_freep(&b->formats);
+
+ av_freep(&a);
+ av_freep(&b);
+
+ return 0;
+ }
+
+ if (is_sample_rate) {
+ ret = ff_merge_samplerates(a, b);
+ } else {
+ ret = ff_merge_formats(a, b, type);
+ }
+ if (ret) {
+ av_freep(&ret->formats);
+ av_freep(&ret->refs);
+ av_freep(&ret);
+ return 1;
+ } else {
+ av_freep(&a->formats);
+ av_freep(&b->formats);
+ av_freep(&a);
+ av_freep(&b);
+ return 0;
+ }
+}
+
+/**
+ * Perform one round of query_formats() and merging formats lists on the
+ * filter graph.
+ * @return >=0 if all links formats lists could be queried and merged;
+ * AVERROR(EAGAIN) some progress was made in the queries or merging
+ * and a later call may succeed;
+ * AVERROR(EIO) (may be changed) plus a log message if no progress
+ * was made and the negotiation is stuck;
+ * a negative error code if some other error happened
+ */
static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
{
int i, j, ret;
int scaler_count = 0, resampler_count = 0;
+ int count_queried = 0; /* successful calls to query_formats() */
+ int count_merged = 0; /* successful merge of formats lists */
+ int count_already_merged = 0; /* lists already merged */
+ int count_delayed = 0; /* lists that need to be merged later */
- /* ask all the sub-filters for their supported media formats */
for (i = 0; i < graph->nb_filters; i++) {
- if (graph->filters[i]->filter->query_formats)
- graph->filters[i]->filter->query_formats(graph->filters[i]);
+ AVFilterContext *f = graph->filters[i];
+ if (formats_declared(f))
+ continue;
+ if (f->filter->query_formats)
+ ret = filter_query_formats(f);
else
- ff_default_query_formats(graph->filters[i]);
+ ret = ff_default_query_formats(f);
+ if (ret < 0 && ret != AVERROR(EAGAIN))
+ return ret;
+ /* note: EAGAIN could indicate a partial success, not counted yet */
+ count_queried += ret >= 0;
}
/* go through and merge as many format lists as possible */
@@ -299,21 +467,49 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
if (!link)
continue;
- if (link->in_formats != link->out_formats &&
- !ff_merge_formats(link->in_formats,
- link->out_formats))
- convert_needed = 1;
- if (link->type == AVMEDIA_TYPE_AUDIO) {
- if (link->in_channel_layouts != link->out_channel_layouts &&
- !ff_merge_channel_layouts(link->in_channel_layouts,
- link->out_channel_layouts))
- convert_needed = 1;
- if (link->in_samplerates != link->out_samplerates &&
- !ff_merge_samplerates(link->in_samplerates,
- link->out_samplerates))
+ if (link->in_formats != link->out_formats
+ && link->in_formats && link->out_formats)
+ if (!can_merge_formats(link->in_formats, link->out_formats,
+ link->type, 0))
convert_needed = 1;
+ if (link->type == AVMEDIA_TYPE_AUDIO) {
+ if (link->in_samplerates != link->out_samplerates
+ && link->in_samplerates && link->out_samplerates)
+ if (!can_merge_formats(link->in_samplerates,
+ link->out_samplerates,
+ 0, 1))
+ convert_needed = 1;
+ }
+
+#define MERGE_DISPATCH(field, statement) \
+ if (!(link->in_ ## field && link->out_ ## field)) { \
+ count_delayed++; \
+ } else if (link->in_ ## field == link->out_ ## field) { \
+ count_already_merged++; \
+ } else if (!convert_needed) { \
+ count_merged++; \
+ statement \
}
+ if (link->type == AVMEDIA_TYPE_AUDIO) {
+ MERGE_DISPATCH(channel_layouts,
+ if (!ff_merge_channel_layouts(link->in_channel_layouts,
+ link->out_channel_layouts))
+ convert_needed = 1;
+ )
+ MERGE_DISPATCH(samplerates,
+ if (!ff_merge_samplerates(link->in_samplerates,
+ link->out_samplerates))
+ convert_needed = 1;
+ )
+ }
+ MERGE_DISPATCH(formats,
+ if (!ff_merge_formats(link->in_formats, link->out_formats,
+ link->type))
+ convert_needed = 1;
+ )
+#undef MERGE_DISPATCH
+
if (convert_needed) {
AVFilterContext *convert;
AVFilter *filter;
@@ -339,8 +535,8 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
return ret;
break;
case AVMEDIA_TYPE_AUDIO:
- if (!(filter = avfilter_get_by_name("resample"))) {
- av_log(log_ctx, AV_LOG_ERROR, "'resample' filter "
+ if (!(filter = avfilter_get_by_name("aresample"))) {
+ av_log(log_ctx, AV_LOG_ERROR, "'aresample' filter "
"not present, cannot convert audio formats.\n");
return AVERROR(EINVAL);
}
@@ -348,11 +544,11 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
snprintf(inst_name, sizeof(inst_name), "auto-inserted resampler %d",
resampler_count++);
scale_args[0] = '\0';
- if (graph->resample_lavr_opts)
+ if (graph->aresample_swr_opts)
snprintf(scale_args, sizeof(scale_args), "%s",
- graph->resample_lavr_opts);
+ graph->aresample_swr_opts);
if ((ret = avfilter_graph_create_filter(&convert, filter,
- inst_name, scale_args,
+ inst_name, graph->aresample_swr_opts,
NULL, graph)) < 0)
return ret;
break;
@@ -363,24 +559,40 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0)
return ret;
- convert->filter->query_formats(convert);
+ if ((ret = filter_query_formats(convert)) < 0)
+ return ret;
+
inlink = convert->inputs[0];
outlink = convert->outputs[0];
- if (!ff_merge_formats( inlink->in_formats, inlink->out_formats) ||
- !ff_merge_formats(outlink->in_formats, outlink->out_formats))
- ret |= AVERROR(ENOSYS);
+ av_assert0( inlink-> in_formats->refcount > 0);
+ av_assert0( inlink->out_formats->refcount > 0);
+ av_assert0(outlink-> in_formats->refcount > 0);
+ av_assert0(outlink->out_formats->refcount > 0);
+ if (outlink->type == AVMEDIA_TYPE_AUDIO) {
+ av_assert0( inlink-> in_samplerates->refcount > 0);
+ av_assert0( inlink->out_samplerates->refcount > 0);
+ av_assert0(outlink-> in_samplerates->refcount > 0);
+ av_assert0(outlink->out_samplerates->refcount > 0);
+ av_assert0( inlink-> in_channel_layouts->refcount > 0);
+ av_assert0( inlink->out_channel_layouts->refcount > 0);
+ av_assert0(outlink-> in_channel_layouts->refcount > 0);
+ av_assert0(outlink->out_channel_layouts->refcount > 0);
+ }
+ if (!ff_merge_formats( inlink->in_formats, inlink->out_formats, inlink->type) ||
+ !ff_merge_formats(outlink->in_formats, outlink->out_formats, outlink->type))
+ ret = AVERROR(ENOSYS);
if (inlink->type == AVMEDIA_TYPE_AUDIO &&
(!ff_merge_samplerates(inlink->in_samplerates,
inlink->out_samplerates) ||
!ff_merge_channel_layouts(inlink->in_channel_layouts,
inlink->out_channel_layouts)))
- ret |= AVERROR(ENOSYS);
+ ret = AVERROR(ENOSYS);
if (outlink->type == AVMEDIA_TYPE_AUDIO &&
(!ff_merge_samplerates(outlink->in_samplerates,
outlink->out_samplerates) ||
!ff_merge_channel_layouts(outlink->in_channel_layouts,
outlink->out_channel_layouts)))
- ret |= AVERROR(ENOSYS);
+ ret = AVERROR(ENOSYS);
if (ret < 0) {
av_log(log_ctx, AV_LOG_ERROR,
@@ -392,14 +604,54 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
}
}
+ av_log(graph, AV_LOG_DEBUG, "query_formats: "
+ "%d queried, %d merged, %d already done, %d delayed\n",
+ count_queried, count_merged, count_already_merged, count_delayed);
+ if (count_delayed) {
+ AVBPrint bp;
+
+ /* if count_queried > 0, one filter at least did set its formats,
+ that will give additional information to its neighbour;
+ if count_merged > 0, one pair of formats lists at least was merged,
+ that will give additional information to all connected filters;
+ in both cases, progress was made and a new round must be done */
+ if (count_queried || count_merged)
+ return AVERROR(EAGAIN);
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ for (i = 0; i < graph->nb_filters; i++)
+ if (!formats_declared(graph->filters[i]))
+ av_bprintf(&bp, "%s%s", bp.len ? ", " : "",
+ graph->filters[i]->name);
+ av_log(graph, AV_LOG_ERROR,
+ "The following filters could not choose their formats: %s\n"
+ "Consider inserting the (a)format filter near their input or "
+ "output.\n", bp.str);
+ return AVERROR(EIO);
+ }
return 0;
}
-static int pick_format(AVFilterLink *link)
+static int pick_format(AVFilterLink *link, AVFilterLink *ref)
{
if (!link || !link->in_formats)
return 0;
+ if (link->type == AVMEDIA_TYPE_VIDEO) {
+ if(ref && ref->type == AVMEDIA_TYPE_VIDEO){
+ int has_alpha= av_pix_fmt_desc_get(ref->format)->nb_components % 2 == 0;
+ enum AVPixelFormat best= AV_PIX_FMT_NONE;
+ int i;
+ for (i=0; i<link->in_formats->nb_formats; i++) {
+ enum AVPixelFormat p = link->in_formats->formats[i];
+ best= av_find_best_pix_fmt_of_2(best, p, ref->format, has_alpha, NULL);
+ }
+ av_log(link->src,AV_LOG_DEBUG, "picking %s out of %d ref:%s alpha:%d\n",
+ av_get_pix_fmt_name(best), link->in_formats->nb_formats,
+ av_get_pix_fmt_name(ref->format), has_alpha);
+ link->in_formats->formats[0] = best;
+ }
+ }
+
link->in_formats->nb_formats = 1;
link->format = link->in_formats->formats[0];
@@ -413,14 +665,22 @@ static int pick_format(AVFilterLink *link)
link->in_samplerates->nb_formats = 1;
link->sample_rate = link->in_samplerates->formats[0];
- if (!link->in_channel_layouts->nb_channel_layouts) {
+ if (link->in_channel_layouts->all_layouts) {
av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for"
- "the link between filters %s and %s.\n", link->src->name,
+ " the link between filters %s and %s.\n", link->src->name,
link->dst->name);
+ if (!link->in_channel_layouts->all_counts)
+ av_log(link->src, AV_LOG_ERROR, "Unknown channel layouts not "
+ "supported, try specifying a channel layout using "
+ "'aformat=channel_layouts=something'.\n");
return AVERROR(EINVAL);
}
link->in_channel_layouts->nb_channel_layouts = 1;
link->channel_layout = link->in_channel_layouts->channel_layouts[0];
+ if ((link->channels = FF_LAYOUT2COUNT(link->channel_layout)))
+ link->channel_layout = 0;
+ else
+ link->channels = av_get_channel_layout_nb_channels(link->channel_layout);
}
ff_formats_unref(&link->in_formats);
@@ -454,6 +714,7 @@ do { \
\
if (!out_link->in_ ## list->nb) { \
add_format(&out_link->in_ ##list, fmt); \
+ ret = 1; \
break; \
} \
\
@@ -476,8 +737,43 @@ static int reduce_formats_on_filter(AVFilterContext *filter)
nb_formats, ff_add_format);
REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats,
nb_formats, ff_add_format);
- REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts,
- channel_layouts, nb_channel_layouts, ff_add_channel_layout);
+
+ /* reduce channel layouts */
+ for (i = 0; i < filter->nb_inputs; i++) {
+ AVFilterLink *inlink = filter->inputs[i];
+ uint64_t fmt;
+
+ if (!inlink->out_channel_layouts ||
+ inlink->out_channel_layouts->nb_channel_layouts != 1)
+ continue;
+ fmt = inlink->out_channel_layouts->channel_layouts[0];
+
+ for (j = 0; j < filter->nb_outputs; j++) {
+ AVFilterLink *outlink = filter->outputs[j];
+ AVFilterChannelLayouts *fmts;
+
+ fmts = outlink->in_channel_layouts;
+ if (inlink->type != outlink->type || fmts->nb_channel_layouts == 1)
+ continue;
+
+ if (fmts->all_layouts &&
+ (!FF_LAYOUT2COUNT(fmt) || fmts->all_counts)) {
+ /* Turn the infinite list into a singleton */
+ fmts->all_layouts = fmts->all_counts = 0;
+ ff_add_channel_layout(&outlink->in_channel_layouts, fmt);
+ break;
+ }
+
+ for (k = 0; k < outlink->in_channel_layouts->nb_channel_layouts; k++) {
+ if (fmts->channel_layouts[k] == fmt) {
+ fmts->channel_layouts[0] = fmt;
+ fmts->nb_channel_layouts = 1;
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
return ret;
}
@@ -605,7 +901,23 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter)
int out_channels = av_get_channel_layout_nb_channels(out_chlayout);
int count_diff = out_channels - in_channels;
int matched_channels, extra_channels;
- int score = 0;
+ int score = 100000;
+
+ if (FF_LAYOUT2COUNT(in_chlayout) || FF_LAYOUT2COUNT(out_chlayout)) {
+ /* Compute score in case the input or output layout encodes
+ a channel count; in this case the score is not altered by
+ the computation afterwards, as in_chlayout and
+ out_chlayout have both been set to 0 */
+ if (FF_LAYOUT2COUNT(in_chlayout))
+ in_channels = FF_LAYOUT2COUNT(in_chlayout);
+ if (FF_LAYOUT2COUNT(out_chlayout))
+ out_channels = FF_LAYOUT2COUNT(out_chlayout);
+ score -= 10000 + FFABS(out_channels - in_channels) +
+ (in_channels > out_channels ? 10000 : 0);
+ in_chlayout = out_chlayout = 0;
+ /* Let the remaining computation run, even if the score
+ value is not altered */
+ }
/* channel substitution */
for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) {
@@ -728,15 +1040,50 @@ static void swap_sample_fmts(AVFilterGraph *graph)
static int pick_formats(AVFilterGraph *graph)
{
int i, j, ret;
+ int change;
+
+ do{
+ change = 0;
+ for (i = 0; i < graph->nb_filters; i++) {
+ AVFilterContext *filter = graph->filters[i];
+ if (filter->nb_inputs){
+ for (j = 0; j < filter->nb_inputs; j++){
+ if(filter->inputs[j]->in_formats && filter->inputs[j]->in_formats->nb_formats == 1) {
+ if ((ret = pick_format(filter->inputs[j], NULL)) < 0)
+ return ret;
+ change = 1;
+ }
+ }
+ }
+ if (filter->nb_outputs){
+ for (j = 0; j < filter->nb_outputs; j++){
+ if(filter->outputs[j]->in_formats && filter->outputs[j]->in_formats->nb_formats == 1) {
+ if ((ret = pick_format(filter->outputs[j], NULL)) < 0)
+ return ret;
+ change = 1;
+ }
+ }
+ }
+ if (filter->nb_inputs && filter->nb_outputs && filter->inputs[0]->format>=0) {
+ for (j = 0; j < filter->nb_outputs; j++) {
+ if(filter->outputs[j]->format<0) {
+ if ((ret = pick_format(filter->outputs[j], filter->inputs[0])) < 0)
+ return ret;
+ change = 1;
+ }
+ }
+ }
+ }
+ }while(change);
for (i = 0; i < graph->nb_filters; i++) {
AVFilterContext *filter = graph->filters[i];
for (j = 0; j < filter->nb_inputs; j++)
- if ((ret = pick_format(filter->inputs[j])) < 0)
+ if ((ret = pick_format(filter->inputs[j], NULL)) < 0)
return ret;
for (j = 0; j < filter->nb_outputs; j++)
- if ((ret = pick_format(filter->outputs[j])) < 0)
+ if ((ret = pick_format(filter->outputs[j], NULL)) < 0)
return ret;
}
return 0;
@@ -750,7 +1097,9 @@ static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
int ret;
/* find supported formats from sub-filters, and merge along links */
- if ((ret = query_formats(graph, log_ctx)) < 0)
+ while ((ret = query_formats(graph, log_ctx)) == AVERROR(EAGAIN))
+ av_log(graph, AV_LOG_DEBUG, "query_formats not finished\n");
+ if (ret < 0)
return ret;
/* Once everything is merged, it's possible that we'll still have
@@ -770,6 +1119,48 @@ static int graph_config_formats(AVFilterGraph *graph, AVClass *log_ctx)
return 0;
}
+static int graph_config_pointers(AVFilterGraph *graph,
+ AVClass *log_ctx)
+{
+ unsigned i, j;
+ int sink_links_count = 0, n = 0;
+ AVFilterContext *f;
+ AVFilterLink **sinks;
+
+ 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;
+ f->inputs[j]->age_index = -1;
+ }
+ for (j = 0; j < f->nb_outputs; j++) {
+ f->outputs[j]->graph = graph;
+ f->outputs[j]->age_index= -1;
+ }
+ if (!f->nb_outputs) {
+ if (f->nb_inputs > INT_MAX - sink_links_count)
+ return AVERROR(EINVAL);
+ sink_links_count += f->nb_inputs;
+ }
+ }
+ sinks = av_calloc(sink_links_count, sizeof(*sinks));
+ if (!sinks)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < graph->nb_filters; i++) {
+ f = graph->filters[i];
+ if (!f->nb_outputs) {
+ for (j = 0; j < f->nb_inputs; j++) {
+ sinks[n] = f->inputs[j];
+ f->inputs[j]->age_index = n++;
+ }
+ }
+ }
+ av_assert0(n == sink_links_count);
+ graph->sink_links = sinks;
+ graph->sink_links_count = sink_links_count;
+ return 0;
+}
+
static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx)
{
AVFilterContext *f;
@@ -820,6 +1211,135 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
return ret;
if ((ret = graph_config_links(graphctx, log_ctx)))
return ret;
+ if ((ret = graph_config_pointers(graphctx, log_ctx)))
+ return ret;
+
+ return 0;
+}
+
+int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags)
+{
+ int i, r = AVERROR(ENOSYS);
+
+ if (!graph)
+ return r;
+
+ if ((flags & AVFILTER_CMD_FLAG_ONE) && !(flags & AVFILTER_CMD_FLAG_FAST)) {
+ r = avfilter_graph_send_command(graph, target, cmd, arg, res, res_len, flags | AVFILTER_CMD_FLAG_FAST);
+ if (r != AVERROR(ENOSYS))
+ return r;
+ }
+
+ if (res_len && res)
+ res[0] = 0;
+
+ for (i = 0; i < graph->nb_filters; i++) {
+ AVFilterContext *filter = graph->filters[i];
+ if (!strcmp(target, "all") || (filter->name && !strcmp(target, filter->name)) || !strcmp(target, filter->filter->name)) {
+ r = avfilter_process_command(filter, cmd, arg, res, res_len, flags);
+ if (r != AVERROR(ENOSYS)) {
+ if ((flags & AVFILTER_CMD_FLAG_ONE) || r < 0)
+ return r;
+ }
+ }
+ }
+
+ return r;
+}
+
+int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *command, const char *arg, int flags, double ts)
+{
+ int i;
+
+ if(!graph)
+ return 0;
+
+ for (i = 0; i < graph->nb_filters; i++) {
+ AVFilterContext *filter = graph->filters[i];
+ if(filter && (!strcmp(target, "all") || !strcmp(target, filter->name) || !strcmp(target, filter->filter->name))){
+ AVFilterCommand **queue = &filter->command_queue, *next;
+ while (*queue && (*queue)->time <= ts)
+ queue = &(*queue)->next;
+ next = *queue;
+ *queue = av_mallocz(sizeof(AVFilterCommand));
+ (*queue)->command = av_strdup(command);
+ (*queue)->arg = av_strdup(arg);
+ (*queue)->time = ts;
+ (*queue)->flags = flags;
+ (*queue)->next = next;
+ if(flags & AVFILTER_CMD_FLAG_ONE)
+ return 0;
+ }
+ }
return 0;
}
+
+static void heap_bubble_up(AVFilterGraph *graph,
+ AVFilterLink *link, int index)
+{
+ AVFilterLink **links = graph->sink_links;
+
+ av_assert0(index >= 0);
+
+ while (index) {
+ int parent = (index - 1) >> 1;
+ if (links[parent]->current_pts >= link->current_pts)
+ break;
+ links[index] = links[parent];
+ links[index]->age_index = index;
+ index = parent;
+ }
+ links[index] = link;
+ link->age_index = index;
+}
+
+static void heap_bubble_down(AVFilterGraph *graph,
+ AVFilterLink *link, int index)
+{
+ AVFilterLink **links = graph->sink_links;
+
+ av_assert0(index >= 0);
+
+ while (1) {
+ int child = 2 * index + 1;
+ if (child >= graph->sink_links_count)
+ break;
+ if (child + 1 < graph->sink_links_count &&
+ links[child + 1]->current_pts < links[child]->current_pts)
+ child++;
+ if (link->current_pts < links[child]->current_pts)
+ break;
+ links[index] = links[child];
+ links[index]->age_index = index;
+ index = child;
+ }
+ links[index] = link;
+ link->age_index = index;
+}
+
+void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link)
+{
+ heap_bubble_up (graph, link, link->age_index);
+ heap_bubble_down(graph, link, link->age_index);
+}
+
+
+int avfilter_graph_request_oldest(AVFilterGraph *graph)
+{
+ while (graph->sink_links_count) {
+ AVFilterLink *oldest = graph->sink_links[0];
+ int r = ff_request_frame(oldest);
+ if (r != AVERROR_EOF)
+ return r;
+ av_log(oldest->dst, AV_LOG_DEBUG, "EOF on sink link %s:%s.\n",
+ oldest->dst ? oldest->dst->name : "unknown",
+ oldest->dstpad ? oldest->dstpad->name : "unknown");
+ /* EOF: remove the link from the heap */
+ if (oldest->age_index < --graph->sink_links_count)
+ heap_bubble_down(graph, graph->sink_links[graph->sink_links_count],
+ oldest->age_index);
+ oldest->age_index = -1;
+ }
+ return AVERROR_EOF;
+}
diff --git a/libavfilter/avfiltergraph.h b/libavfilter/avfiltergraph.h
index 47174efc6c..b31d581ca0 100644
--- a/libavfilter/avfiltergraph.h
+++ b/libavfilter/avfiltergraph.h
@@ -2,20 +2,20 @@
* Filter graphs
* copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,5 +25,4 @@
#include "avfilter.h"
#include "libavutil/log.h"
-
#endif /* AVFILTER_AVFILTERGRAPH_H */
diff --git a/libavfilter/avfilterres.rc b/libavfilter/avfilterres.rc
new file mode 100644
index 0000000000..8be62473e2
--- /dev/null
+++ b/libavfilter/avfilterres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libavfilter
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libavfilter/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBAVFILTER_VERSION_MAJOR, LIBAVFILTER_VERSION_MINOR, LIBAVFILTER_VERSION_MICRO, 0
+PRODUCTVERSION LIBAVFILTER_VERSION_MAJOR, LIBAVFILTER_VERSION_MINOR, LIBAVFILTER_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg audio/video filtering library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBAVFILTER_VERSION)
+ VALUE "InternalName", "libavfilter"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "avfilter" BUILDSUF "-" AV_STRINGIFY(LIBAVFILTER_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libavfilter/bbox.c b/libavfilter/bbox.c
new file mode 100644
index 0000000000..be9b2e6b73
--- /dev/null
+++ b/libavfilter/bbox.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "bbox.h"
+
+int ff_calculate_bounding_box(FFBoundingBox *bbox,
+ const uint8_t *data, int linesize, int w, int h,
+ int min_val)
+{
+ int x, y;
+ int start_x;
+ int start_y;
+ int end_x;
+ int end_y;
+ const uint8_t *line;
+
+ /* left bound */
+ for (start_x = 0; start_x < w; start_x++)
+ for (y = 0; y < h; y++)
+ if ((data[y * linesize + start_x] > min_val))
+ goto outl;
+outl:
+ if (start_x == w) /* no points found */
+ return 0;
+
+ /* right bound */
+ for (end_x = w - 1; end_x >= start_x; end_x--)
+ for (y = 0; y < h; y++)
+ if ((data[y * linesize + end_x] > min_val))
+ goto outr;
+outr:
+
+ /* top bound */
+ line = data;
+ for (start_y = 0; start_y < h; start_y++) {
+ for (x = 0; x < w; x++)
+ if (line[x] > min_val)
+ goto outt;
+ line += linesize;
+ }
+outt:
+
+ /* bottom bound */
+ line = data + (h-1)*linesize;
+ for (end_y = h - 1; end_y >= start_y; end_y--) {
+ for (x = 0; x < w; x++)
+ if (line[x] > min_val)
+ goto outb;
+ line -= linesize;
+ }
+outb:
+
+ bbox->x1 = start_x;
+ bbox->y1 = start_y;
+ bbox->x2 = end_x;
+ bbox->y2 = end_y;
+ return 1;
+}
diff --git a/libavfilter/bbox.h b/libavfilter/bbox.h
new file mode 100644
index 0000000000..eb73154c14
--- /dev/null
+++ b/libavfilter/bbox.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_BBOX_H
+#define AVFILTER_BBOX_H
+
+#include <stdint.h>
+
+typedef struct {
+ int x1, x2, y1, y2;
+} FFBoundingBox;
+
+/**
+ * Calculate the smallest rectangle that will encompass the
+ * region with values > min_val.
+ *
+ * @param bbox bounding box structure which is updated with the found values.
+ * If no pixels could be found with value > min_val, the
+ * structure is not modified.
+ * @return 1 in case at least one pixel with value > min_val was found,
+ * 0 otherwise
+ */
+int ff_calculate_bounding_box(FFBoundingBox *bbox,
+ const uint8_t *data, int linesize,
+ int w, int h, int min_val);
+
+#endif /* AVFILTER_BBOX_H */
diff --git a/libavfilter/buffer.c b/libavfilter/buffer.c
index fd0b18fb76..a5b3b1dbaf 100644
--- a/libavfilter/buffer.c
+++ b/libavfilter/buffer.c
@@ -1,53 +1,79 @@
/*
- * This file is part of Libav.
+ * Copyright Stefano Sabatini <stefasab gmail com>
+ * Copyright Anton Khirnov <anton khirnov net>
+ * Copyright Michael Niedermayer <michaelni gmx at>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/channel_layout.h"
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavcodec/avcodec.h"
#include "avfilter.h"
#include "internal.h"
+#include "audio.h"
+#include "avcodec.h"
#include "version.h"
#if FF_API_AVFILTERBUFFER
-/* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */
void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr)
{
if (ptr->extended_data != ptr->data)
av_freep(&ptr->extended_data);
- av_free(ptr->data[0]);
+ av_freep(&ptr->data[0]);
av_free(ptr);
}
+static int copy_video_props(AVFilterBufferRefVideoProps *dst, AVFilterBufferRefVideoProps *src) {
+ *dst = *src;
+ if (src->qp_table) {
+ int qsize = src->qp_table_size;
+ dst->qp_table = av_malloc(qsize);
+ if (!dst->qp_table) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to allocate qp_table\n");
+ dst->qp_table_size = 0;
+ return AVERROR(ENOMEM);
+ }
+ memcpy(dst->qp_table, src->qp_table, qsize);
+ }
+ return 0;
+}
+
AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask)
{
AVFilterBufferRef *ret = av_malloc(sizeof(AVFilterBufferRef));
if (!ret)
return NULL;
*ret = *ref;
+
+ ret->metadata = NULL;
+ av_dict_copy(&ret->metadata, ref->metadata, 0);
+
if (ref->type == AVMEDIA_TYPE_VIDEO) {
ret->video = av_malloc(sizeof(AVFilterBufferRefVideoProps));
if (!ret->video) {
av_free(ret);
return NULL;
}
- *ret->video = *ref->video;
+ copy_video_props(ret->video, ref->video);
ret->extended_data = ret->data;
} else if (ref->type == AVMEDIA_TYPE_AUDIO) {
ret->audio = av_malloc(sizeof(AVFilterBufferRefAudioProps));
@@ -57,9 +83,9 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask)
}
*ret->audio = *ref->audio;
- if (ref->extended_data != ref->data) {
+ if (ref->extended_data && ref->extended_data != ref->data) {
int nb_channels = av_get_channel_layout_nb_channels(ref->audio->channel_layout);
- if (!(ret->extended_data = av_malloc(sizeof(*ret->extended_data) *
+ if (!(ret->extended_data = av_malloc_array(sizeof(*ret->extended_data),
nb_channels))) {
av_freep(&ret->audio);
av_freep(&ret);
@@ -79,12 +105,16 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref)
{
if (!ref)
return;
+ av_assert0(ref->buf->refcount > 0);
if (!(--ref->buf->refcount))
ref->buf->free(ref->buf);
if (ref->extended_data != ref->data)
av_freep(&ref->extended_data);
- av_free(ref->video);
- av_free(ref->audio);
+ if (ref->video)
+ av_freep(&ref->video->qp_table);
+ av_freep(&ref->video);
+ av_freep(&ref->audio);
+ av_dict_free(&ref->metadata);
av_free(ref);
}
@@ -99,13 +129,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src)
{
dst->pts = src->pts;
+ dst->pos = av_frame_get_pkt_pos(src);
dst->format = src->format;
+ av_dict_free(&dst->metadata);
+ av_dict_copy(&dst->metadata, av_frame_get_metadata(src), 0);
+
switch (dst->type) {
case AVMEDIA_TYPE_VIDEO:
dst->video->w = src->width;
dst->video->h = src->height;
- dst->video->pixel_aspect = src->sample_aspect_ratio;
+ dst->video->sample_aspect_ratio = src->sample_aspect_ratio;
dst->video->interlaced = src->interlaced_frame;
dst->video->top_field_first = src->top_field_first;
dst->video->key_frame = src->key_frame;
@@ -122,60 +156,24 @@ int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src)
return 0;
}
-int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src)
-{
- int planes, nb_channels;
-
- memcpy(dst->data, src->data, sizeof(dst->data));
- memcpy(dst->linesize, src->linesize, sizeof(dst->linesize));
-
- dst->pts = src->pts;
- dst->format = src->format;
-
- switch (src->type) {
- case AVMEDIA_TYPE_VIDEO:
- dst->width = src->video->w;
- dst->height = src->video->h;
- dst->sample_aspect_ratio = src->video->pixel_aspect;
- dst->interlaced_frame = src->video->interlaced;
- dst->top_field_first = src->video->top_field_first;
- dst->key_frame = src->video->key_frame;
- dst->pict_type = src->video->pict_type;
- break;
- case AVMEDIA_TYPE_AUDIO:
- nb_channels = av_get_channel_layout_nb_channels(src->audio->channel_layout);
- planes = av_sample_fmt_is_planar(src->format) ? nb_channels : 1;
-
- if (planes > FF_ARRAY_ELEMS(dst->data)) {
- dst->extended_data = av_mallocz(planes * sizeof(*dst->extended_data));
- if (!dst->extended_data)
- return AVERROR(ENOMEM);
- memcpy(dst->extended_data, src->extended_data,
- planes * sizeof(*dst->extended_data));
- } else
- dst->extended_data = dst->data;
-
- dst->sample_rate = src->audio->sample_rate;
- dst->channel_layout = src->audio->channel_layout;
- dst->nb_samples = src->audio->nb_samples;
- break;
- default:
- return AVERROR(EINVAL);
- }
-
- return 0;
-}
-
-void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, AVFilterBufferRef *src)
+void avfilter_copy_buffer_ref_props(AVFilterBufferRef *dst, const AVFilterBufferRef *src)
{
// copy common properties
dst->pts = src->pts;
dst->pos = src->pos;
switch (src->type) {
- case AVMEDIA_TYPE_VIDEO: *dst->video = *src->video; break;
+ case AVMEDIA_TYPE_VIDEO: {
+ if (dst->video->qp_table)
+ av_freep(&dst->video->qp_table);
+ copy_video_props(dst->video, src->video);
+ break;
+ }
case AVMEDIA_TYPE_AUDIO: *dst->audio = *src->audio; break;
default: break;
}
+
+ av_dict_free(&dst->metadata);
+ av_dict_copy(&dst->metadata, src->metadata, 0);
}
#endif /* FF_API_AVFILTERBUFFER */
diff --git a/libavfilter/bufferqueue.h b/libavfilter/bufferqueue.h
new file mode 100644
index 0000000000..f5e5df2d72
--- /dev/null
+++ b/libavfilter/bufferqueue.h
@@ -0,0 +1,121 @@
+/*
+ * Generic buffer queue
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_BUFFERQUEUE_H
+#define AVFILTER_BUFFERQUEUE_H
+
+/**
+ * FFBufQueue: simple AVFrame queue API
+ *
+ * Note: this API is not thread-safe. Concurrent access to the same queue
+ * must be protected by a mutex or any synchronization mechanism.
+ */
+
+/**
+ * Maximum size of the queue.
+ *
+ * This value can be overridden by definying it before including this
+ * header.
+ * Powers of 2 are recommended.
+ */
+#ifndef FF_BUFQUEUE_SIZE
+#define FF_BUFQUEUE_SIZE 64
+#endif
+
+#include "avfilter.h"
+#include "libavutil/avassert.h"
+
+/**
+ * Structure holding the queue
+ */
+struct FFBufQueue {
+ AVFrame *queue[FF_BUFQUEUE_SIZE];
+ unsigned short head;
+ unsigned short available; /**< number of available buffers */
+};
+
+#define BUCKET(i) queue->queue[(queue->head + (i)) % FF_BUFQUEUE_SIZE]
+
+/**
+ * Test if a buffer queue is full.
+ */
+static inline int ff_bufqueue_is_full(struct FFBufQueue *queue)
+{
+ return queue->available == FF_BUFQUEUE_SIZE;
+}
+
+/**
+ * Add a buffer to the queue.
+ *
+ * If the queue is already full, then the current last buffer is dropped
+ * (and unrefed) with a warning before adding the new buffer.
+ */
+static inline void ff_bufqueue_add(void *log, struct FFBufQueue *queue,
+ AVFrame *buf)
+{
+ if (ff_bufqueue_is_full(queue)) {
+ av_log(log, AV_LOG_WARNING, "Buffer queue overflow, dropping.\n");
+ av_frame_free(&BUCKET(--queue->available));
+ }
+ BUCKET(queue->available++) = buf;
+}
+
+/**
+ * Get a buffer from the queue without altering it.
+ *
+ * Buffer with index 0 is the first buffer in the queue.
+ * Return NULL if the queue has not enough buffers.
+ */
+static inline AVFrame *ff_bufqueue_peek(struct FFBufQueue *queue,
+ unsigned index)
+{
+ return index < queue->available ? BUCKET(index) : NULL;
+}
+
+/**
+ * Get the first buffer from the queue and remove it.
+ *
+ * Do not use on an empty queue.
+ */
+static inline AVFrame *ff_bufqueue_get(struct FFBufQueue *queue)
+{
+ AVFrame *ret = queue->queue[queue->head];
+ av_assert0(queue->available);
+ queue->available--;
+ queue->queue[queue->head] = NULL;
+ queue->head = (queue->head + 1) % FF_BUFQUEUE_SIZE;
+ return ret;
+}
+
+/**
+ * Unref and remove all buffers from the queue.
+ */
+static inline void ff_bufqueue_discard_all(struct FFBufQueue *queue)
+{
+ while (queue->available) {
+ AVFrame *buf = ff_bufqueue_get(queue);
+ av_frame_free(&buf);
+ }
+}
+
+#undef BUCKET
+
+#endif /* AVFILTER_BUFFERQUEUE_H */
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 2894a5b0a4..b145e35c3f 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@
#include "libavutil/common.h"
#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
#include "audio.h"
#include "avfilter.h"
@@ -36,44 +37,121 @@
#include "internal.h"
typedef struct BufferSinkContext {
- AVFrame *cur_frame; ///< last frame delivered on the sink
+ const AVClass *class;
+ AVFifoBuffer *fifo; ///< FIFO buffer of video frame references
+ unsigned warning_limit;
+
+ /* only used for video */
+ enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1
+ int pixel_fmts_size;
+
+ /* only used for audio */
+ enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
+ int sample_fmts_size;
+ int64_t *channel_layouts; ///< list of accepted channel layouts, terminated by -1
+ int channel_layouts_size;
+ int *channel_counts; ///< list of accepted channel counts, terminated by -1
+ int channel_counts_size;
+ int all_channel_counts;
+ int *sample_rates; ///< list of accepted sample rates, terminated by -1
+ int sample_rates_size;
+
+ /* only used for compat API */
AVAudioFifo *audio_fifo; ///< FIFO for audio samples
int64_t next_pts; ///< interpolating audio pts
} BufferSinkContext;
+#define NB_ITEMS(list) (list ## _size / sizeof(*list))
+
static av_cold void uninit(AVFilterContext *ctx)
{
BufferSinkContext *sink = ctx->priv;
+ AVFrame *frame;
if (sink->audio_fifo)
av_audio_fifo_free(sink->audio_fifo);
+
+ if (sink->fifo) {
+ while (av_fifo_size(sink->fifo) >= sizeof(AVFilterBufferRef *)) {
+ av_fifo_generic_read(sink->fifo, &frame, sizeof(frame), NULL);
+ av_frame_free(&frame);
+ }
+ av_fifo_freep(&sink->fifo);
+ }
}
-static int filter_frame(AVFilterLink *link, AVFrame *frame)
+static int add_buffer_ref(AVFilterContext *ctx, AVFrame *ref)
{
- BufferSinkContext *s = link->dst->priv;
-
- av_assert0(!s->cur_frame);
- s->cur_frame = frame;
+ BufferSinkContext *buf = ctx->priv;
+
+ if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
+ /* realloc fifo size */
+ if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Cannot buffer more frames. Consume some available frames "
+ "before adding new ones.\n");
+ return AVERROR(ENOMEM);
+ }
+ }
+ /* cache frame */
+ av_fifo_generic_write(buf->fifo, &ref, sizeof(AVFilterBufferRef *), NULL);
return 0;
}
-int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx,
- AVFrame *frame)
+static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
- BufferSinkContext *s = ctx->priv;
- AVFilterLink *link = ctx->inputs[0];
+ AVFilterContext *ctx = link->dst;
+ BufferSinkContext *buf = link->dst->priv;
int ret;
- if ((ret = ff_request_frame(link)) < 0)
+ if ((ret = add_buffer_ref(ctx, frame)) < 0)
return ret;
+ if (buf->warning_limit &&
+ av_fifo_size(buf->fifo) / sizeof(AVFilterBufferRef *) >= buf->warning_limit) {
+ av_log(ctx, AV_LOG_WARNING,
+ "%d buffers queued in %s, something may be wrong.\n",
+ buf->warning_limit,
+ (char *)av_x_if_null(ctx->name, ctx->filter->name));
+ buf->warning_limit *= 10;
+ }
+ return 0;
+}
- if (!s->cur_frame)
+int attribute_align_arg av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame)
+{
+ return av_buffersink_get_frame_flags(ctx, frame, 0);
+}
+
+int attribute_align_arg av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
+{
+ BufferSinkContext *buf = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ int ret;
+ AVFrame *cur_frame;
+
+ /* no picref available, fetch it from the filterchain */
+ if (!av_fifo_size(buf->fifo)) {
+ if (inlink->closed)
+ return AVERROR_EOF;
+ if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
+ return AVERROR(EAGAIN);
+ if ((ret = ff_request_frame(inlink)) < 0)
+ return ret;
+ }
+
+ if (!av_fifo_size(buf->fifo))
return AVERROR(EINVAL);
- av_frame_move_ref(frame, s->cur_frame);
- av_frame_free(&s->cur_frame);
+ if (flags & AV_BUFFERSINK_FLAG_PEEK) {
+ cur_frame = *((AVFrame **)av_fifo_peek2(buf->fifo, 0));
+ if ((ret = av_frame_ref(frame, cur_frame)) < 0)
+ return ret;
+ } else {
+ av_fifo_generic_read(buf->fifo, &cur_frame, sizeof(cur_frame), NULL);
+ av_frame_move_ref(frame, cur_frame);
+ av_frame_free(&cur_frame);
+ }
return 0;
}
@@ -90,8 +168,9 @@ static int read_from_fifo(AVFilterContext *ctx, AVFrame *frame,
av_audio_fifo_read(s->audio_fifo, (void**)tmp->extended_data, nb_samples);
tmp->pts = s->next_pts;
- s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate},
- link->time_base);
+ if (s->next_pts != AV_NOPTS_VALUE)
+ s->next_pts += av_rescale_q(nb_samples, (AVRational){1, link->sample_rate},
+ link->time_base);
av_frame_move_ref(frame, tmp);
av_frame_free(&tmp);
@@ -104,10 +183,11 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
{
BufferSinkContext *s = ctx->priv;
AVFilterLink *link = ctx->inputs[0];
+ AVFrame *cur_frame;
int ret = 0;
if (!s->audio_fifo) {
- int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
+ int nb_channels = link->channels;
if (!(s->audio_fifo = av_audio_fifo_alloc(link->format, nb_channels, nb_samples)))
return AVERROR(ENOMEM);
}
@@ -116,27 +196,76 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
if (av_audio_fifo_size(s->audio_fifo) >= nb_samples)
return read_from_fifo(ctx, frame, nb_samples);
- ret = ff_request_frame(link);
- if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo))
+ if (!(cur_frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ ret = av_buffersink_get_frame_flags(ctx, cur_frame, 0);
+ if (ret == AVERROR_EOF && av_audio_fifo_size(s->audio_fifo)) {
+ av_frame_free(&cur_frame);
return read_from_fifo(ctx, frame, av_audio_fifo_size(s->audio_fifo));
- else if (ret < 0)
+ } else if (ret < 0) {
+ av_frame_free(&cur_frame);
return ret;
+ }
- if (s->cur_frame->pts != AV_NOPTS_VALUE) {
- s->next_pts = s->cur_frame->pts -
+ if (cur_frame->pts != AV_NOPTS_VALUE) {
+ s->next_pts = cur_frame->pts -
av_rescale_q(av_audio_fifo_size(s->audio_fifo),
(AVRational){ 1, link->sample_rate },
link->time_base);
}
- ret = av_audio_fifo_write(s->audio_fifo, (void**)s->cur_frame->extended_data,
- s->cur_frame->nb_samples);
- av_frame_free(&s->cur_frame);
+ ret = av_audio_fifo_write(s->audio_fifo, (void**)cur_frame->extended_data,
+ cur_frame->nb_samples);
+ av_frame_free(&cur_frame);
}
return ret;
}
+AVBufferSinkParams *av_buffersink_params_alloc(void)
+{
+ static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
+ AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
+ if (!params)
+ return NULL;
+
+ params->pixel_fmts = pixel_fmts;
+ return params;
+}
+
+AVABufferSinkParams *av_abuffersink_params_alloc(void)
+{
+ AVABufferSinkParams *params = av_mallocz(sizeof(AVABufferSinkParams));
+
+ if (!params)
+ return NULL;
+ return params;
+}
+
+#define FIFO_INIT_SIZE 8
+
+static av_cold int common_init(AVFilterContext *ctx)
+{
+ BufferSinkContext *buf = ctx->priv;
+
+ buf->fifo = av_fifo_alloc_array(FIFO_INIT_SIZE, sizeof(AVFilterBufferRef *));
+ if (!buf->fifo) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
+ return AVERROR(ENOMEM);
+ }
+ buf->warning_limit = 100;
+ buf->next_pts = AV_NOPTS_VALUE;
+ return 0;
+}
+
+void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size)
+{
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ inlink->min_samples = inlink->max_samples =
+ inlink->partial_buf_size = frame_size;
+}
+
#if FF_API_AVFILTERBUFFER
FF_DISABLE_DEPRECATION_WARNINGS
static void compat_free_buffer(AVFilterBuffer *buf)
@@ -147,7 +276,7 @@ static void compat_free_buffer(AVFilterBuffer *buf)
}
static int compat_read(AVFilterContext *ctx,
- AVFilterBufferRef **pbuf, int nb_samples)
+ AVFilterBufferRef **pbuf, int nb_samples, int flags)
{
AVFilterBufferRef *buf;
AVFrame *frame;
@@ -161,13 +290,14 @@ static int compat_read(AVFilterContext *ctx,
return AVERROR(ENOMEM);
if (!nb_samples)
- ret = av_buffersink_get_frame(ctx, frame);
+ ret = av_buffersink_get_frame_flags(ctx, frame, flags);
else
ret = av_buffersink_get_samples(ctx, frame, nb_samples);
if (ret < 0)
goto fail;
+ AV_NOWARN_DEPRECATED(
if (ctx->inputs[0]->type == AVMEDIA_TYPE_VIDEO) {
buf = avfilter_get_video_buffer_ref_from_arrays(frame->data, frame->linesize,
AV_PERM_READ,
@@ -186,6 +316,7 @@ static int compat_read(AVFilterContext *ctx,
}
avfilter_copy_frame_props(buf, frame);
+ )
buf->buf->priv = frame;
buf->buf->free = compat_free_buffer;
@@ -200,23 +331,245 @@ fail:
int attribute_align_arg av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
{
- return compat_read(ctx, buf, 0);
+ return compat_read(ctx, buf, 0, 0);
}
int attribute_align_arg av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
int nb_samples)
{
- return compat_read(ctx, buf, nb_samples);
+ return compat_read(ctx, buf, nb_samples, 0);
+}
+
+int attribute_align_arg av_buffersink_get_buffer_ref(AVFilterContext *ctx,
+ AVFilterBufferRef **bufref, int flags)
+{
+ *bufref = NULL;
+
+ av_assert0( !strcmp(ctx->filter->name, "buffersink")
+ || !strcmp(ctx->filter->name, "abuffersink")
+ || !strcmp(ctx->filter->name, "ffbuffersink")
+ || !strcmp(ctx->filter->name, "ffabuffersink"));
+
+ return compat_read(ctx, bufref, 0, flags);
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif
+AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx)
+{
+ av_assert0( !strcmp(ctx->filter->name, "buffersink")
+ || !strcmp(ctx->filter->name, "ffbuffersink"));
+
+ return ctx->inputs[0]->frame_rate;
+}
+
+int attribute_align_arg av_buffersink_poll_frame(AVFilterContext *ctx)
+{
+ BufferSinkContext *buf = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ av_assert0( !strcmp(ctx->filter->name, "buffersink")
+ || !strcmp(ctx->filter->name, "abuffersink")
+ || !strcmp(ctx->filter->name, "ffbuffersink")
+ || !strcmp(ctx->filter->name, "ffabuffersink"));
+
+ return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + ff_poll_frame(inlink);
+}
+
+static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
+{
+ BufferSinkContext *buf = ctx->priv;
+ AVBufferSinkParams *params = opaque;
+ int ret;
+
+ if (params) {
+ if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
+ return ret;
+ }
+
+ return common_init(ctx);
+}
+
+#define CHECK_LIST_SIZE(field) \
+ if (buf->field ## _size % sizeof(*buf->field)) { \
+ av_log(ctx, AV_LOG_ERROR, "Invalid size for " #field ": %d, " \
+ "should be multiple of %d\n", \
+ buf->field ## _size, (int)sizeof(*buf->field)); \
+ return AVERROR(EINVAL); \
+ }
+static int vsink_query_formats(AVFilterContext *ctx)
+{
+ BufferSinkContext *buf = ctx->priv;
+ AVFilterFormats *formats = NULL;
+ unsigned i;
+ int ret;
+
+ CHECK_LIST_SIZE(pixel_fmts)
+ if (buf->pixel_fmts_size) {
+ for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
+ if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0) {
+ ff_formats_unref(&formats);
+ return ret;
+ }
+ ff_set_common_formats(ctx, formats);
+ } else {
+ ff_default_query_formats(ctx);
+ }
+
+ return 0;
+}
+
+static av_cold int asink_init(AVFilterContext *ctx, void *opaque)
+{
+ BufferSinkContext *buf = ctx->priv;
+ AVABufferSinkParams *params = opaque;
+ int ret;
+
+ if (params) {
+ if ((ret = av_opt_set_int_list(buf, "sample_fmts", params->sample_fmts, AV_SAMPLE_FMT_NONE, 0)) < 0 ||
+ (ret = av_opt_set_int_list(buf, "sample_rates", params->sample_rates, -1, 0)) < 0 ||
+ (ret = av_opt_set_int_list(buf, "channel_layouts", params->channel_layouts, -1, 0)) < 0 ||
+ (ret = av_opt_set_int_list(buf, "channel_counts", params->channel_counts, -1, 0)) < 0 ||
+ (ret = av_opt_set_int(buf, "all_channel_counts", params->all_channel_counts, 0)) < 0)
+ return ret;
+ }
+ return common_init(ctx);
+}
+
+static int asink_query_formats(AVFilterContext *ctx)
+{
+ BufferSinkContext *buf = ctx->priv;
+ AVFilterFormats *formats = NULL;
+ AVFilterChannelLayouts *layouts = NULL;
+ unsigned i;
+ int ret;
+
+ CHECK_LIST_SIZE(sample_fmts)
+ CHECK_LIST_SIZE(sample_rates)
+ CHECK_LIST_SIZE(channel_layouts)
+ CHECK_LIST_SIZE(channel_counts)
+
+ if (buf->sample_fmts_size) {
+ for (i = 0; i < NB_ITEMS(buf->sample_fmts); i++)
+ if ((ret = ff_add_format(&formats, buf->sample_fmts[i])) < 0) {
+ ff_formats_unref(&formats);
+ return ret;
+ }
+ ff_set_common_formats(ctx, formats);
+ }
+
+ if (buf->channel_layouts_size || buf->channel_counts_size ||
+ buf->all_channel_counts) {
+ for (i = 0; i < NB_ITEMS(buf->channel_layouts); i++)
+ if ((ret = ff_add_channel_layout(&layouts, buf->channel_layouts[i])) < 0) {
+ ff_channel_layouts_unref(&layouts);
+ return ret;
+ }
+ for (i = 0; i < NB_ITEMS(buf->channel_counts); i++)
+ if ((ret = ff_add_channel_layout(&layouts, FF_COUNT2LAYOUT(buf->channel_counts[i]))) < 0) {
+ ff_channel_layouts_unref(&layouts);
+ return ret;
+ }
+ if (buf->all_channel_counts) {
+ if (layouts)
+ av_log(ctx, AV_LOG_WARNING,
+ "Conflicting all_channel_counts and list in options\n");
+ else if (!(layouts = ff_all_channel_counts()))
+ return AVERROR(ENOMEM);
+ }
+ ff_set_common_channel_layouts(ctx, layouts);
+ }
+
+ if (buf->sample_rates_size) {
+ formats = NULL;
+ for (i = 0; i < NB_ITEMS(buf->sample_rates); i++)
+ if ((ret = ff_add_format(&formats, buf->sample_rates[i])) < 0) {
+ ff_formats_unref(&formats);
+ return ret;
+ }
+ ff_set_common_samplerates(ctx, formats);
+ }
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(BufferSinkContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption buffersink_options[] = {
+ { "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+ { NULL },
+};
+#undef FLAGS
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption abuffersink_options[] = {
+ { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+ { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+ { "channel_layouts", "set the supported channel layouts", OFFSET(channel_layouts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+ { "channel_counts", "set the supported channel counts", OFFSET(channel_counts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+ { "all_channel_counts", "accept all channel counts", OFFSET(all_channel_counts), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { NULL },
+};
+#undef FLAGS
+
+AVFILTER_DEFINE_CLASS(buffersink);
+AVFILTER_DEFINE_CLASS(abuffersink);
+
+#if FF_API_AVFILTERBUFFER
+
+#define ffbuffersink_options buffersink_options
+#define ffabuffersink_options abuffersink_options
+AVFILTER_DEFINE_CLASS(ffbuffersink);
+AVFILTER_DEFINE_CLASS(ffabuffersink);
+
+static const AVFilterPad ffbuffersink_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL },
+};
+
+AVFilter ff_vsink_ffbuffersink = {
+ .name = "ffbuffersink",
+ .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
+ .priv_size = sizeof(BufferSinkContext),
+ .priv_class = &ffbuffersink_class,
+ .init_opaque = vsink_init,
+ .uninit = uninit,
+
+ .query_formats = vsink_query_formats,
+ .inputs = ffbuffersink_inputs,
+ .outputs = NULL,
+};
+
+static const AVFilterPad ffabuffersink_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL },
+};
+
+AVFilter ff_asink_ffabuffersink = {
+ .name = "ffabuffersink",
+ .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
+ .init_opaque = asink_init,
+ .uninit = uninit,
+ .priv_size = sizeof(BufferSinkContext),
+ .priv_class = &ffabuffersink_class,
+ .query_formats = asink_query_formats,
+ .inputs = ffabuffersink_inputs,
+ .outputs = NULL,
+};
+#endif /* FF_API_AVFILTERBUFFER */
+
static const AVFilterPad avfilter_vsink_buffer_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
- .needs_fifo = 1
},
{ NULL }
};
@@ -225,8 +578,11 @@ AVFilter ff_vsink_buffer = {
.name = "buffersink",
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
.priv_size = sizeof(BufferSinkContext),
+ .priv_class = &buffersink_class,
+ .init_opaque = vsink_init,
.uninit = uninit,
+ .query_formats = vsink_query_formats,
.inputs = avfilter_vsink_buffer_inputs,
.outputs = NULL,
};
@@ -236,7 +592,6 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_frame = filter_frame,
- .needs_fifo = 1
},
{ NULL }
};
@@ -244,9 +599,12 @@ static const AVFilterPad avfilter_asink_abuffer_inputs[] = {
AVFilter ff_asink_abuffer = {
.name = "abuffersink",
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
+ .priv_class = &abuffersink_class,
.priv_size = sizeof(BufferSinkContext),
+ .init_opaque = asink_init,
.uninit = uninit,
+ .query_formats = asink_query_formats,
.inputs = avfilter_asink_abuffer_inputs,
.outputs = NULL,
};
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index 83a8bd9471..24cd2feac7 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,7 +22,7 @@
/**
* @file
* @ingroup lavfi_buffersink
- * memory buffer sink API
+ * memory buffer sink API for audio and video
*/
#include "avfilter.h"
@@ -35,6 +35,26 @@
#if FF_API_AVFILTERBUFFER
/**
+ * Get an audio/video buffer data from buffer_sink and put it in bufref.
+ *
+ * This function works with both audio and video buffer sinks.
+ *
+ * @param buffer_sink pointer to a buffersink or abuffersink context
+ * @param flags a combination of AV_BUFFERSINK_FLAG_* flags
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ * failure
+ */
+attribute_deprecated
+int av_buffersink_get_buffer_ref(AVFilterContext *buffer_sink,
+ AVFilterBufferRef **bufref, int flags);
+
+/**
+ * Get the number of immediately available frames.
+ */
+attribute_deprecated
+int av_buffersink_poll_frame(AVFilterContext *ctx);
+
+/**
* Get a buffer with filtered data from sink and put it in buf.
*
* @param ctx pointer to a context of a buffersink or abuffersink AVFilter.
@@ -73,6 +93,78 @@ int av_buffersink_read_samples(AVFilterContext *ctx, AVFilterBufferRef **buf,
/**
* Get a frame with filtered data from sink and put it in frame.
*
+ * @param ctx pointer to a buffersink or abuffersink filter context.
+ * @param frame pointer to an allocated frame that will be filled with data.
+ * The data must be freed using av_frame_unref() / av_frame_free()
+ * @param flags a combination of AV_BUFFERSINK_FLAG_* flags
+ *
+ * @return >= 0 in for success, a negative AVERROR code for failure.
+ */
+int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags);
+
+/**
+ * Tell av_buffersink_get_buffer_ref() to read video/samples buffer
+ * reference, but not remove it from the buffer. This is useful if you
+ * need only to read a video/samples buffer, without to fetch it.
+ */
+#define AV_BUFFERSINK_FLAG_PEEK 1
+
+/**
+ * Tell av_buffersink_get_buffer_ref() not to request a frame from its input.
+ * If a frame is already buffered, it is read (and removed from the buffer),
+ * but if no frame is present, return AVERROR(EAGAIN).
+ */
+#define AV_BUFFERSINK_FLAG_NO_REQUEST 2
+
+/**
+ * Struct to use for initializing a buffersink context.
+ */
+typedef struct {
+ const enum AVPixelFormat *pixel_fmts; ///< list of allowed pixel formats, terminated by AV_PIX_FMT_NONE
+} AVBufferSinkParams;
+
+/**
+ * Create an AVBufferSinkParams structure.
+ *
+ * Must be freed with av_free().
+ */
+AVBufferSinkParams *av_buffersink_params_alloc(void);
+
+/**
+ * Struct to use for initializing an abuffersink context.
+ */
+typedef struct {
+ const enum AVSampleFormat *sample_fmts; ///< list of allowed sample formats, terminated by AV_SAMPLE_FMT_NONE
+ const int64_t *channel_layouts; ///< list of allowed channel layouts, terminated by -1
+ const int *channel_counts; ///< list of allowed channel counts, terminated by -1
+ int all_channel_counts; ///< if not 0, accept any channel count or layout
+ int *sample_rates; ///< list of allowed sample rates, terminated by -1
+} AVABufferSinkParams;
+
+/**
+ * Create an AVABufferSinkParams structure.
+ *
+ * Must be freed with av_free().
+ */
+AVABufferSinkParams *av_abuffersink_params_alloc(void);
+
+/**
+ * Set the frame size for an audio buffer sink.
+ *
+ * All calls to av_buffersink_get_buffer_ref will return a buffer with
+ * exactly the specified number of samples, or AVERROR(EAGAIN) if there is
+ * not enough. The last buffer at EOF will be padded with 0.
+ */
+void av_buffersink_set_frame_size(AVFilterContext *ctx, unsigned frame_size);
+
+/**
+ * Get the frame rate of the input.
+ */
+AVRational av_buffersink_get_frame_rate(AVFilterContext *ctx);
+
+/**
+ * Get a frame with filtered data from sink and put it in frame.
+ *
* @param ctx pointer to a context of a buffersink or abuffersink AVFilter.
* @param frame pointer to an allocated frame that will be filled with data.
* The data must be freed using av_frame_unref() / av_frame_free()
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 8f7032f993..bf77b88fec 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,22 +39,26 @@
#include "formats.h"
#include "internal.h"
#include "video.h"
+#include "avcodec.h"
typedef struct BufferSourceContext {
const AVClass *class;
AVFifoBuffer *fifo;
AVRational time_base; ///< time_base to set in the output link
+ AVRational frame_rate; ///< frame_rate to set in the output link
+ unsigned nb_failed_requests;
+ unsigned warning_limit;
/* video only */
- int h, w;
+ int w, h;
enum AVPixelFormat pix_fmt;
- char *pix_fmt_str;
AVRational pixel_aspect;
+ char *sws_param;
/* audio only */
int sample_rate;
enum AVSampleFormat sample_fmt;
- char *sample_fmt_str;
+ int channels;
uint64_t channel_layout;
char *channel_layout_str;
@@ -63,39 +67,63 @@ typedef struct BufferSourceContext {
#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\
if (c->w != width || c->h != height || c->pix_fmt != format) {\
- av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
- return AVERROR(EINVAL);\
+ av_log(s, AV_LOG_INFO, "Changing frame properties on the fly is not supported by all filters.\n");\
}
-#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, format)\
+#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, ch_count, format)\
if (c->sample_fmt != format || c->sample_rate != srate ||\
- c->channel_layout != ch_layout) {\
+ c->channel_layout != ch_layout || c->channels != ch_count) {\
av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
return AVERROR(EINVAL);\
}
int attribute_align_arg av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame)
{
- AVFrame *copy;
+ return av_buffersrc_add_frame_flags(ctx, (AVFrame *)frame,
+ AV_BUFFERSRC_FLAG_KEEP_REF);
+}
+
+int attribute_align_arg av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame)
+{
+ return av_buffersrc_add_frame_flags(ctx, frame, 0);
+}
+
+static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
+ AVFrame *frame, int flags);
+
+int attribute_align_arg av_buffersrc_add_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flags)
+{
+ AVFrame *copy = NULL;
int ret = 0;
+ if (frame && frame->channel_layout &&
+ av_get_channel_layout_nb_channels(frame->channel_layout) != av_frame_get_channels(frame)) {
+ av_log(ctx, AV_LOG_ERROR, "Layout indicates a different number of channels than actually present\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!(flags & AV_BUFFERSRC_FLAG_KEEP_REF) || !frame)
+ return av_buffersrc_add_frame_internal(ctx, frame, flags);
+
if (!(copy = av_frame_alloc()))
return AVERROR(ENOMEM);
ret = av_frame_ref(copy, frame);
if (ret >= 0)
- ret = av_buffersrc_add_frame(ctx, copy);
+ ret = av_buffersrc_add_frame_internal(ctx, copy, flags);
av_frame_free(&copy);
return ret;
}
-int attribute_align_arg av_buffersrc_add_frame(AVFilterContext *ctx,
- AVFrame *frame)
+static int av_buffersrc_add_frame_internal(AVFilterContext *ctx,
+ AVFrame *frame, int flags)
{
BufferSourceContext *s = ctx->priv;
AVFrame *copy;
int refcounted, ret;
+ s->nb_failed_requests = 0;
+
if (!frame) {
s->eof = 1;
return 0;
@@ -104,19 +132,26 @@ int attribute_align_arg av_buffersrc_add_frame(AVFilterContext *ctx,
refcounted = !!frame->buf[0];
+ if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) {
+
switch (ctx->outputs[0]->type) {
case AVMEDIA_TYPE_VIDEO:
CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height,
frame->format);
break;
case AVMEDIA_TYPE_AUDIO:
+ /* For layouts unknown on input but known on link after negotiation. */
+ if (!frame->channel_layout)
+ frame->channel_layout = s->channel_layout;
CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout,
- frame->format);
+ av_frame_get_channels(frame), frame->format);
break;
default:
return AVERROR(EINVAL);
}
+ }
+
if (!av_fifo_space(s->fifo) &&
(ret = av_fifo_realloc2(s->fifo, av_fifo_size(s->fifo) +
sizeof(copy))) < 0)
@@ -142,6 +177,10 @@ int attribute_align_arg av_buffersrc_add_frame(AVFilterContext *ctx,
return ret;
}
+ if ((flags & AV_BUFFERSRC_FLAG_PUSH))
+ if ((ret = ctx->output_pads[0].request_frame(ctx->outputs[0])) < 0)
+ return ret;
+
return 0;
}
@@ -150,16 +189,21 @@ FF_DISABLE_DEPRECATION_WARNINGS
static void compat_free_buffer(void *opaque, uint8_t *data)
{
AVFilterBufferRef *buf = opaque;
+ AV_NOWARN_DEPRECATED(
avfilter_unref_buffer(buf);
+ )
}
static void compat_unref_buffer(void *opaque, uint8_t *data)
{
AVBufferRef *buf = opaque;
+ AV_NOWARN_DEPRECATED(
av_buffer_unref(&buf);
+ )
}
-int av_buffersrc_buffer(AVFilterContext *ctx, AVFilterBufferRef *buf)
+int av_buffersrc_add_ref(AVFilterContext *ctx, AVFilterBufferRef *buf,
+ int flags)
{
BufferSourceContext *s = ctx->priv;
AVFrame *frame = NULL;
@@ -176,14 +220,17 @@ int av_buffersrc_buffer(AVFilterContext *ctx, AVFilterBufferRef *buf)
if (!frame)
return AVERROR(ENOMEM);
- dummy_buf = av_buffer_create(NULL, 0, compat_free_buffer, buf, 0);
+ dummy_buf = av_buffer_create(NULL, 0, compat_free_buffer, buf,
+ (buf->perms & AV_PERM_WRITE) ? 0 : AV_BUFFER_FLAG_READONLY);
if (!dummy_buf) {
ret = AVERROR(ENOMEM);
goto fail;
}
+ AV_NOWARN_DEPRECATED(
if ((ret = avfilter_copy_buf_props(frame, buf)) < 0)
goto fail;
+ )
#define WRAP_PLANE(ref_out, data, data_size) \
do { \
@@ -193,7 +240,7 @@ do { \
goto fail; \
} \
ref_out = av_buffer_create(data, data_size, compat_unref_buffer, \
- dummy_ref, 0); \
+ dummy_ref, (buf->perms & AV_PERM_WRITE) ? 0 : AV_BUFFER_FLAG_READONLY); \
if (!ref_out) { \
av_buffer_unref(&dummy_ref); \
av_frame_unref(frame); \
@@ -225,7 +272,7 @@ do { \
if (planes > FF_ARRAY_ELEMS(frame->buf)) {
frame->nb_extended_buf = planes - FF_ARRAY_ELEMS(frame->buf);
- frame->extended_buf = av_mallocz(sizeof(*frame->extended_buf) *
+ frame->extended_buf = av_mallocz_array(sizeof(*frame->extended_buf),
frame->nb_extended_buf);
if (!frame->extended_buf) {
ret = AVERROR(ENOMEM);
@@ -242,7 +289,7 @@ do { \
frame->linesize[0]);
}
- ret = av_buffersrc_add_frame(ctx, frame);
+ ret = av_buffersrc_add_frame_flags(ctx, frame, flags);
fail:
av_buffer_unref(&dummy_buf);
@@ -251,41 +298,47 @@ fail:
return ret;
}
FF_ENABLE_DEPRECATION_WARNINGS
+
+int av_buffersrc_buffer(AVFilterContext *ctx, AVFilterBufferRef *buf)
+{
+ return av_buffersrc_add_ref(ctx, buf, 0);
+}
#endif
static av_cold int init_video(AVFilterContext *ctx)
{
BufferSourceContext *c = ctx->priv;
- if (!c->pix_fmt_str || !c->w || !c->h || av_q2d(c->time_base) <= 0) {
+ if (c->pix_fmt == AV_PIX_FMT_NONE || !c->w || !c->h || av_q2d(c->time_base) <= 0) {
av_log(ctx, AV_LOG_ERROR, "Invalid parameters provided.\n");
return AVERROR(EINVAL);
}
- if ((c->pix_fmt = av_get_pix_fmt(c->pix_fmt_str)) == AV_PIX_FMT_NONE) {
- char *tail;
- c->pix_fmt = strtol(c->pix_fmt_str, &tail, 10);
- if (*tail || c->pix_fmt < 0 || !av_pix_fmt_desc_get(c->pix_fmt)) {
- av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", c->pix_fmt_str);
- return AVERROR(EINVAL);
- }
- }
-
if (!(c->fifo = av_fifo_alloc(sizeof(AVFrame*))))
return AVERROR(ENOMEM);
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_get_pix_fmt_name(c->pix_fmt));
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d sws_param:%s\n",
+ c->w, c->h, av_get_pix_fmt_name(c->pix_fmt),
+ c->time_base.num, c->time_base.den, c->frame_rate.num, c->frame_rate.den,
+ c->pixel_aspect.num, c->pixel_aspect.den, (char *)av_x_if_null(c->sws_param, ""));
+ c->warning_limit = 100;
return 0;
}
+unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src)
+{
+ return ((BufferSourceContext *)buffer_src->priv)->nb_failed_requests;
+}
+
#define OFFSET(x) offsetof(BufferSourceContext, x)
-#define A AV_OPT_FLAG_AUDIO_PARAM
-#define V AV_OPT_FLAG_VIDEO_PARAM
+#define A AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM
+#define V AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption video_options[] = {
+static const AVOption buffer_options[] = {
{ "width", NULL, OFFSET(w), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V },
+ { "video_size", NULL, OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, .flags = V },
{ "height", NULL, OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V },
- { "pix_fmt", NULL, OFFSET(pix_fmt_str), AV_OPT_TYPE_STRING, .flags = V },
+ { "pix_fmt", NULL, OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, .min = AV_PIX_FMT_NONE, .max = INT_MAX, .flags = V },
#if FF_API_OLD_FILTER_OPTS
/* those 4 are for compatibility with the old option passing system where each filter
* did its own parsing */
@@ -295,48 +348,59 @@ static const AVOption video_options[] = {
{ "sar_den", "deprecated, do not use", OFFSET(pixel_aspect.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V },
#endif
{ "sar", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 1 }, 0, DBL_MAX, V },
+ { "pixel_aspect", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 1 }, 0, DBL_MAX, V },
{ "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V },
+ { "frame_rate", NULL, OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V },
+ { "sws_param", NULL, OFFSET(sws_param), AV_OPT_TYPE_STRING, .flags = V },
{ NULL },
};
-static const AVClass buffer_class = {
- .class_name = "buffer source",
- .item_name = av_default_item_name,
- .option = video_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(buffer);
-static const AVOption audio_options[] = {
+static const AVOption abuffer_options[] = {
{ "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, INT_MAX, A },
{ "sample_rate", NULL, OFFSET(sample_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A },
- { "sample_fmt", NULL, OFFSET(sample_fmt_str), AV_OPT_TYPE_STRING, .flags = A },
+ { "sample_fmt", NULL, OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, { .i64 = AV_SAMPLE_FMT_NONE }, .min = AV_SAMPLE_FMT_NONE, .max = INT_MAX, .flags = A },
{ "channel_layout", NULL, OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
+ { "channels", NULL, OFFSET(channels), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, A },
{ NULL },
};
-static const AVClass abuffer_class = {
- .class_name = "abuffer source",
- .item_name = av_default_item_name,
- .option = audio_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(abuffer);
static av_cold int init_audio(AVFilterContext *ctx)
{
BufferSourceContext *s = ctx->priv;
int ret = 0;
- s->sample_fmt = av_get_sample_fmt(s->sample_fmt_str);
if (s->sample_fmt == AV_SAMPLE_FMT_NONE) {
- av_log(ctx, AV_LOG_ERROR, "Invalid sample format %s.\n",
- s->sample_fmt_str);
+ av_log(ctx, AV_LOG_ERROR, "Sample format was not set or was invalid\n");
return AVERROR(EINVAL);
}
- s->channel_layout = av_get_channel_layout(s->channel_layout_str);
- if (!s->channel_layout) {
- av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
- s->channel_layout_str);
+ if (s->channel_layout_str) {
+ int n;
+
+ s->channel_layout = av_get_channel_layout(s->channel_layout_str);
+ if (!s->channel_layout) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid channel layout %s.\n",
+ s->channel_layout_str);
+ return AVERROR(EINVAL);
+ }
+ n = av_get_channel_layout_nb_channels(s->channel_layout);
+ if (s->channels) {
+ if (n != s->channels) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Mismatching channel count %d and layout '%s' "
+ "(%d channels)\n",
+ s->channels, s->channel_layout_str, n);
+ return AVERROR(EINVAL);
+ }
+ }
+ s->channels = n;
+ } else if (!s->channels) {
+ av_log(ctx, AV_LOG_ERROR, "Neither number of channels nor "
+ "channel layout specified\n");
return AVERROR(EINVAL);
}
@@ -346,9 +410,11 @@ static av_cold int init_audio(AVFilterContext *ctx)
if (!s->time_base.num)
s->time_base = (AVRational){1, s->sample_rate};
- av_log(ctx, AV_LOG_VERBOSE, "tb:%d/%d samplefmt:%s samplerate: %d "
- "ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str,
+ av_log(ctx, AV_LOG_VERBOSE,
+ "tb:%d/%d samplefmt:%s samplerate:%d chlayout:%s\n",
+ s->time_base.num, s->time_base.den, av_get_sample_fmt_name(s->sample_fmt),
s->sample_rate, s->channel_layout_str);
+ s->warning_limit = 100;
return ret;
}
@@ -361,8 +427,7 @@ static av_cold void uninit(AVFilterContext *ctx)
av_fifo_generic_read(s->fifo, &frame, sizeof(frame), NULL);
av_frame_free(&frame);
}
- av_fifo_free(s->fifo);
- s->fifo = NULL;
+ av_fifo_freep(&s->fifo);
}
static int query_formats(AVFilterContext *ctx)
@@ -384,7 +449,9 @@ static int query_formats(AVFilterContext *ctx)
ff_add_format(&samplerates, c->sample_rate);
ff_set_common_samplerates(ctx, samplerates);
- ff_add_channel_layout(&channel_layouts, c->channel_layout);
+ ff_add_channel_layout(&channel_layouts,
+ c->channel_layout ? c->channel_layout :
+ FF_COUNT2LAYOUT(c->channels));
ff_set_common_channel_layouts(ctx, channel_layouts);
break;
default:
@@ -405,14 +472,15 @@ static int config_props(AVFilterLink *link)
link->sample_aspect_ratio = c->pixel_aspect;
break;
case AVMEDIA_TYPE_AUDIO:
- link->channel_layout = c->channel_layout;
- link->sample_rate = c->sample_rate;
+ if (!c->channel_layout)
+ c->channel_layout = link->channel_layout;
break;
default:
return AVERROR(EINVAL);
}
link->time_base = c->time_base;
+ link->frame_rate = c->frame_rate;
return 0;
}
@@ -420,18 +488,16 @@ static int request_frame(AVFilterLink *link)
{
BufferSourceContext *c = link->src->priv;
AVFrame *frame;
- int ret = 0;
if (!av_fifo_size(c->fifo)) {
if (c->eof)
return AVERROR_EOF;
+ c->nb_failed_requests++;
return AVERROR(EAGAIN);
}
av_fifo_generic_read(c->fifo, &frame, sizeof(frame), NULL);
- ff_filter_frame(link, frame);
-
- return ret;
+ return ff_filter_frame(link, frame);
}
static int poll_frame(AVFilterLink *link)
@@ -458,7 +524,6 @@ AVFilter ff_vsrc_buffer = {
.name = "buffer",
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
.priv_size = sizeof(BufferSourceContext),
- .priv_class = &buffer_class,
.query_formats = query_formats,
.init = init_video,
@@ -466,6 +531,7 @@ AVFilter ff_vsrc_buffer = {
.inputs = NULL,
.outputs = avfilter_vsrc_buffer_outputs,
+ .priv_class = &buffer_class,
};
static const AVFilterPad avfilter_asrc_abuffer_outputs[] = {
@@ -483,7 +549,6 @@ AVFilter ff_asrc_abuffer = {
.name = "abuffer",
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them accessible to the filterchain."),
.priv_size = sizeof(BufferSourceContext),
- .priv_class = &abuffer_class,
.query_formats = query_formats,
.init = init_audio,
@@ -491,4 +556,5 @@ AVFilter ff_asrc_abuffer = {
.inputs = NULL,
.outputs = avfilter_asrc_abuffer_outputs,
+ .priv_class = &abuffer_class,
};
diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h
index 0ca4d963a6..ea34c04ee9 100644
--- a/libavfilter/buffersrc.h
+++ b/libavfilter/buffersrc.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
* Memory buffer source API.
*/
+#include "libavcodec/avcodec.h"
#include "avfilter.h"
/**
@@ -34,6 +35,55 @@
* @{
*/
+enum {
+
+ /**
+ * Do not check for format changes.
+ */
+ AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT = 1,
+
+#if FF_API_AVFILTERBUFFER
+ /**
+ * Ignored
+ */
+ AV_BUFFERSRC_FLAG_NO_COPY = 2,
+#endif
+
+ /**
+ * Immediately push the frame to the output.
+ */
+ AV_BUFFERSRC_FLAG_PUSH = 4,
+
+ /**
+ * Keep a reference to the frame.
+ * If the frame if reference-counted, create a new reference; otherwise
+ * copy the frame data.
+ */
+ AV_BUFFERSRC_FLAG_KEEP_REF = 8,
+
+};
+
+/**
+ * Add buffer data in picref to buffer_src.
+ *
+ * @param buffer_src pointer to a buffer source context
+ * @param picref a buffer reference, or NULL to mark EOF
+ * @param flags a combination of AV_BUFFERSRC_FLAG_*
+ * @return >= 0 in case of success, a negative AVERROR code
+ * in case of failure
+ */
+int av_buffersrc_add_ref(AVFilterContext *buffer_src,
+ AVFilterBufferRef *picref, int flags);
+
+/**
+ * Get the number of failed requests.
+ *
+ * A failed request is when the request_frame method is called while no
+ * frame is present in the buffer.
+ * The number is reset when a frame is added.
+ */
+unsigned av_buffersrc_get_nb_failed_requests(AVFilterContext *buffer_src);
+
#if FF_API_AVFILTERBUFFER
/**
* Add a buffer to a filtergraph.
@@ -58,6 +108,9 @@ int av_buffersrc_buffer(AVFilterContext *ctx, AVFilterBufferRef *buf);
* copied.
*
* @return 0 on success, a negative AVERROR on error
+ *
+ * This function is equivalent to av_buffersrc_add_frame_flags() with the
+ * AV_BUFFERSRC_FLAG_KEEP_REF flag.
*/
int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame);
@@ -75,10 +128,32 @@ int av_buffersrc_write_frame(AVFilterContext *ctx, const AVFrame *frame);
* @note the difference between this function and av_buffersrc_write_frame() is
* that av_buffersrc_write_frame() creates a new reference to the input frame,
* while this function takes ownership of the reference passed to it.
+ *
+ * This function is equivalent to av_buffersrc_add_frame_flags() without the
+ * AV_BUFFERSRC_FLAG_KEEP_REF flag.
*/
int av_buffersrc_add_frame(AVFilterContext *ctx, AVFrame *frame);
/**
+ * Add a frame to the buffer source.
+ *
+ * By default, if the frame is reference-counted, this function will take
+ * ownership of the reference(s) and reset the frame. This can be controlled
+ * using the flags.
+ *
+ * If this function returns an error, the input frame is not touched.
+ *
+ * @param buffer_src pointer to a buffer source context
+ * @param frame a frame, or NULL to mark EOF
+ * @param flags a combination of AV_BUFFERSRC_FLAG_*
+ * @return >= 0 in case of success, a negative AVERROR code
+ * in case of failure
+ */
+int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src,
+ AVFrame *frame, int flags);
+
+
+/**
* @}
*/
diff --git a/libavfilter/deshake.h b/libavfilter/deshake.h
new file mode 100644
index 0000000000..becd6c248b
--- /dev/null
+++ b/libavfilter/deshake.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ * 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_DESHAKE_H
+#define AVFILTER_DESHAKE_H
+
+#include "config.h"
+#include "avfilter.h"
+#include "transform.h"
+#include "libavutil/pixelutils.h"
+#if CONFIG_OPENCL
+#include "libavutil/opencl.h"
+#endif
+
+
+enum SearchMethod {
+ EXHAUSTIVE, ///< Search all possible positions
+ SMART_EXHAUSTIVE, ///< Search most possible positions (faster)
+ SEARCH_COUNT
+};
+
+typedef struct {
+ int x; ///< Horizontal shift
+ int y; ///< Vertical shift
+} IntMotionVector;
+
+typedef struct {
+ double x; ///< Horizontal shift
+ double y; ///< Vertical shift
+} MotionVector;
+
+typedef struct {
+ MotionVector vec; ///< Motion vector
+ double angle; ///< Angle of rotation
+ double zoom; ///< Zoom percentage
+} Transform;
+
+#if CONFIG_OPENCL
+
+typedef struct {
+ cl_command_queue command_queue;
+ cl_program program;
+ cl_kernel kernel_luma;
+ cl_kernel kernel_chroma;
+ int in_plane_size[8];
+ int out_plane_size[8];
+ int plane_num;
+ cl_mem cl_inbuf;
+ size_t cl_inbuf_size;
+ cl_mem cl_outbuf;
+ size_t cl_outbuf_size;
+} DeshakeOpenclContext;
+
+#endif
+
+#define MAX_R 64
+
+typedef struct {
+ const AVClass *class;
+ int counts[2*MAX_R+1][2*MAX_R+1]; /// < Scratch buffer for motion search
+ double *angles; ///< Scratch buffer for block angles
+ unsigned angles_size;
+ AVFrame *ref; ///< Previous frame
+ int rx; ///< Maximum horizontal shift
+ int ry; ///< Maximum vertical shift
+ int edge; ///< Edge fill method
+ int blocksize; ///< Size of blocks to compare
+ int contrast; ///< Contrast threshold
+ int search; ///< Motion search method
+ av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function
+ Transform last; ///< Transform from last frame
+ int refcount; ///< Number of reference frames (defines averaging window)
+ FILE *fp;
+ Transform avg;
+ int cw; ///< Crop motion search to this box
+ int ch;
+ int cx;
+ int cy;
+ char *filename; ///< Motion search detailed log filename
+ int opencl;
+#if CONFIG_OPENCL
+ DeshakeOpenclContext opencl_ctx;
+#endif
+ int (* transform)(AVFilterContext *ctx, int width, int height, int cw, int ch,
+ const float *matrix_y, const float *matrix_uv, enum InterpolateMethod interpolate,
+ enum FillMethod fill, AVFrame *in, AVFrame *out);
+} DeshakeContext;
+
+#endif /* AVFILTER_DESHAKE_H */
diff --git a/libavfilter/deshake_opencl.c b/libavfilter/deshake_opencl.c
new file mode 100644
index 0000000000..2821248218
--- /dev/null
+++ b/libavfilter/deshake_opencl.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ * Copyright (C) 2013 Lenny Wang
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * transform input video
+ */
+
+#include "libavutil/common.h"
+#include "libavutil/dict.h"
+#include "libavutil/pixdesc.h"
+#include "deshake_opencl.h"
+#include "libavutil/opencl_internal.h"
+
+#define PLANE_NUM 3
+#define ROUND_TO_16(a) (((((a) - 1)/16)+1)*16)
+
+int ff_opencl_transform(AVFilterContext *ctx,
+ int width, int height, int cw, int ch,
+ const float *matrix_y, const float *matrix_uv,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill, AVFrame *in, AVFrame *out)
+{
+ int ret = 0;
+ cl_int status;
+ DeshakeContext *deshake = ctx->priv;
+ float4 packed_matrix_lu = {matrix_y[0], matrix_y[1], matrix_y[2], matrix_y[5]};
+ float4 packed_matrix_ch = {matrix_uv[0], matrix_uv[1], matrix_uv[2], matrix_uv[5]};
+ size_t global_worksize_lu[2] = {(size_t)ROUND_TO_16(width), (size_t)ROUND_TO_16(height)};
+ size_t global_worksize_ch[2] = {(size_t)ROUND_TO_16(cw), (size_t)(2*ROUND_TO_16(ch))};
+ size_t local_worksize[2] = {16, 16};
+ FFOpenclParam param_lu = {0};
+ FFOpenclParam param_ch = {0};
+ param_lu.ctx = param_ch.ctx = ctx;
+ param_lu.kernel = deshake->opencl_ctx.kernel_luma;
+ param_ch.kernel = deshake->opencl_ctx.kernel_chroma;
+
+ if ((unsigned int)interpolate > INTERPOLATE_BIQUADRATIC) {
+ av_log(ctx, AV_LOG_ERROR, "Selected interpolate method is invalid\n");
+ return AVERROR(EINVAL);
+ }
+ ret = avpriv_opencl_set_parameter(&param_lu,
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf),
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf),
+ FF_OPENCL_PARAM_INFO(packed_matrix_lu),
+ FF_OPENCL_PARAM_INFO(interpolate),
+ FF_OPENCL_PARAM_INFO(fill),
+ FF_OPENCL_PARAM_INFO(in->linesize[0]),
+ FF_OPENCL_PARAM_INFO(out->linesize[0]),
+ FF_OPENCL_PARAM_INFO(height),
+ FF_OPENCL_PARAM_INFO(width),
+ NULL);
+ if (ret < 0)
+ return ret;
+ ret = avpriv_opencl_set_parameter(&param_ch,
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf),
+ FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf),
+ FF_OPENCL_PARAM_INFO(packed_matrix_ch),
+ FF_OPENCL_PARAM_INFO(interpolate),
+ FF_OPENCL_PARAM_INFO(fill),
+ FF_OPENCL_PARAM_INFO(in->linesize[0]),
+ FF_OPENCL_PARAM_INFO(out->linesize[0]),
+ FF_OPENCL_PARAM_INFO(in->linesize[1]),
+ FF_OPENCL_PARAM_INFO(out->linesize[1]),
+ FF_OPENCL_PARAM_INFO(height),
+ FF_OPENCL_PARAM_INFO(width),
+ FF_OPENCL_PARAM_INFO(ch),
+ FF_OPENCL_PARAM_INFO(cw),
+ NULL);
+ if (ret < 0)
+ return ret;
+ status = clEnqueueNDRangeKernel(deshake->opencl_ctx.command_queue,
+ deshake->opencl_ctx.kernel_luma, 2, NULL,
+ global_worksize_lu, local_worksize, 0, NULL, NULL);
+ status |= clEnqueueNDRangeKernel(deshake->opencl_ctx.command_queue,
+ deshake->opencl_ctx.kernel_chroma, 2, NULL,
+ global_worksize_ch, local_worksize, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ ret = av_opencl_buffer_read_image(out->data, deshake->opencl_ctx.out_plane_size,
+ deshake->opencl_ctx.plane_num, deshake->opencl_ctx.cl_outbuf,
+ deshake->opencl_ctx.cl_outbuf_size);
+ if (ret < 0)
+ return ret;
+ return ret;
+}
+
+int ff_opencl_deshake_init(AVFilterContext *ctx)
+{
+ int ret = 0;
+ DeshakeContext *deshake = ctx->priv;
+ ret = av_opencl_init(NULL);
+ if (ret < 0)
+ return ret;
+ deshake->opencl_ctx.plane_num = PLANE_NUM;
+ deshake->opencl_ctx.command_queue = av_opencl_get_command_queue();
+ if (!deshake->opencl_ctx.command_queue) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to get OpenCL command queue in filter 'deshake'\n");
+ return AVERROR(EINVAL);
+ }
+ deshake->opencl_ctx.program = av_opencl_compile("avfilter_transform", NULL);
+ if (!deshake->opencl_ctx.program) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to compile program 'avfilter_transform'\n");
+ return AVERROR(EINVAL);
+ }
+ if (!deshake->opencl_ctx.kernel_luma) {
+ deshake->opencl_ctx.kernel_luma = clCreateKernel(deshake->opencl_ctx.program,
+ "avfilter_transform_luma", &ret);
+ if (ret != CL_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'avfilter_transform_luma'\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ if (!deshake->opencl_ctx.kernel_chroma) {
+ deshake->opencl_ctx.kernel_chroma = clCreateKernel(deshake->opencl_ctx.program,
+ "avfilter_transform_chroma", &ret);
+ if (ret != CL_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'avfilter_transform_chroma'\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ return ret;
+}
+
+void ff_opencl_deshake_uninit(AVFilterContext *ctx)
+{
+ DeshakeContext *deshake = ctx->priv;
+ av_opencl_buffer_release(&deshake->opencl_ctx.cl_inbuf);
+ av_opencl_buffer_release(&deshake->opencl_ctx.cl_outbuf);
+ clReleaseKernel(deshake->opencl_ctx.kernel_luma);
+ clReleaseKernel(deshake->opencl_ctx.kernel_chroma);
+ clReleaseProgram(deshake->opencl_ctx.program);
+ deshake->opencl_ctx.command_queue = NULL;
+ av_opencl_uninit();
+}
+
+int ff_opencl_deshake_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out)
+{
+ int ret = 0;
+ AVFilterLink *link = ctx->inputs[0];
+ DeshakeContext *deshake = ctx->priv;
+ const int hshift = av_pix_fmt_desc_get(link->format)->log2_chroma_h;
+ int chroma_height = FF_CEIL_RSHIFT(link->h, hshift);
+
+ if ((!deshake->opencl_ctx.cl_inbuf) || (!deshake->opencl_ctx.cl_outbuf)) {
+ deshake->opencl_ctx.in_plane_size[0] = (in->linesize[0] * in->height);
+ deshake->opencl_ctx.in_plane_size[1] = (in->linesize[1] * chroma_height);
+ deshake->opencl_ctx.in_plane_size[2] = (in->linesize[2] * chroma_height);
+ deshake->opencl_ctx.out_plane_size[0] = (out->linesize[0] * out->height);
+ deshake->opencl_ctx.out_plane_size[1] = (out->linesize[1] * chroma_height);
+ deshake->opencl_ctx.out_plane_size[2] = (out->linesize[2] * chroma_height);
+ deshake->opencl_ctx.cl_inbuf_size = deshake->opencl_ctx.in_plane_size[0] +
+ deshake->opencl_ctx.in_plane_size[1] +
+ deshake->opencl_ctx.in_plane_size[2];
+ deshake->opencl_ctx.cl_outbuf_size = deshake->opencl_ctx.out_plane_size[0] +
+ deshake->opencl_ctx.out_plane_size[1] +
+ deshake->opencl_ctx.out_plane_size[2];
+ if (!deshake->opencl_ctx.cl_inbuf) {
+ ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_inbuf,
+ deshake->opencl_ctx.cl_inbuf_size,
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ }
+ if (!deshake->opencl_ctx.cl_outbuf) {
+ ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_outbuf,
+ deshake->opencl_ctx.cl_outbuf_size,
+ CL_MEM_READ_WRITE, NULL);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ ret = av_opencl_buffer_write_image(deshake->opencl_ctx.cl_inbuf,
+ deshake->opencl_ctx.cl_inbuf_size,
+ 0, in->data,deshake->opencl_ctx.in_plane_size,
+ deshake->opencl_ctx.plane_num);
+ if(ret < 0)
+ return ret;
+ return ret;
+}
diff --git a/libavfilter/deshake_opencl.h b/libavfilter/deshake_opencl.h
new file mode 100644
index 0000000000..5b0a2414b8
--- /dev/null
+++ b/libavfilter/deshake_opencl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_DESHAKE_OPENCL_H
+#define AVFILTER_DESHAKE_OPENCL_H
+
+#include "deshake.h"
+
+typedef struct {
+ float x;
+ float y;
+ float z;
+ float w;
+} float4;
+
+int ff_opencl_deshake_init(AVFilterContext *ctx);
+
+void ff_opencl_deshake_uninit(AVFilterContext *ctx);
+
+int ff_opencl_deshake_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out);
+
+int ff_opencl_transform(AVFilterContext *ctx,
+ int width, int height, int cw, int ch,
+ const float *matrix_y, const float *matrix_uv,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill, AVFrame *in, AVFrame *out);
+
+#endif /* AVFILTER_DESHAKE_OPENCL_H */
diff --git a/libavfilter/deshake_opencl_kernel.h b/libavfilter/deshake_opencl_kernel.h
new file mode 100644
index 0000000000..dd45d6f60b
--- /dev/null
+++ b/libavfilter/deshake_opencl_kernel.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ * 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_DESHAKE_OPENCL_KERNEL_H
+#define AVFILTER_DESHAKE_OPENCL_KERNEL_H
+
+#include "libavutil/opencl.h"
+
+const char *ff_kernel_deshake_opencl = AV_OPENCL_KERNEL(
+inline unsigned char pixel(global const unsigned char *src, int x, int y,
+ int w, int h,int stride, unsigned char def)
+{
+ return (x < 0 || y < 0 || x >= w || y >= h) ? def : src[x + y * stride];
+}
+
+unsigned char interpolate_nearest(float x, float y, global const unsigned char *src,
+ int width, int height, int stride, unsigned char def)
+{
+ return pixel(src, (int)(x + 0.5f), (int)(y + 0.5f), width, height, stride, def);
+}
+
+unsigned char interpolate_bilinear(float x, float y, global const unsigned char *src,
+ int width, int height, int stride, unsigned char def)
+{
+ int x_c, x_f, y_c, y_f;
+ int v1, v2, v3, v4;
+ x_f = (int)x;
+ y_f = (int)y;
+ x_c = x_f + 1;
+ y_c = y_f + 1;
+
+ if (x_f < -1 || x_f > width || y_f < -1 || y_f > height) {
+ return def;
+ } else {
+ v4 = pixel(src, x_f, y_f, width, height, stride, def);
+ v2 = pixel(src, x_c, y_f, width, height, stride, def);
+ v3 = pixel(src, x_f, y_c, width, height, stride, def);
+ v1 = pixel(src, x_c, y_c, width, height, stride, def);
+ return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) +
+ v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y)));
+ }
+}
+
+unsigned char interpolate_biquadratic(float x, float y, global const unsigned char *src,
+ int width, int height, int stride, unsigned char def)
+{
+ int x_c, x_f, y_c, y_f;
+ unsigned char v1, v2, v3, v4;
+ float f1, f2, f3, f4;
+ x_f = (int)x;
+ y_f = (int)y;
+ x_c = x_f + 1;
+ y_c = y_f + 1;
+
+ if (x_f < - 1 || x_f > width || y_f < -1 || y_f > height)
+ return def;
+ else {
+ v4 = pixel(src, x_f, y_f, width, height, stride, def);
+ v2 = pixel(src, x_c, y_f, width, height, stride, def);
+ v3 = pixel(src, x_f, y_c, width, height, stride, def);
+ v1 = pixel(src, x_c, y_c, width, height, stride, def);
+
+ f1 = 1 - sqrt((x_c - x) * (y_c - y));
+ f2 = 1 - sqrt((x_c - x) * (y - y_f));
+ f3 = 1 - sqrt((x - x_f) * (y_c - y));
+ f4 = 1 - sqrt((x - x_f) * (y - y_f));
+ return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4);
+ }
+}
+
+inline const float clipf(float a, float amin, float amax)
+{
+ if (a < amin) return amin;
+ else if (a > amax) return amax;
+ else return a;
+}
+
+inline int mirror(int v, int m)
+{
+ while ((unsigned)v > (unsigned)m) {
+ v = -v;
+ if (v < 0)
+ v += 2 * m;
+ }
+ return v;
+}
+
+kernel void avfilter_transform_luma(global unsigned char *src,
+ global unsigned char *dst,
+ float4 matrix,
+ int interpolate,
+ int fill,
+ int src_stride_lu,
+ int dst_stride_lu,
+ int height,
+ int width)
+{
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+ int idx_dst = y * dst_stride_lu + x;
+ unsigned char def = 0;
+ float x_s = x * matrix.x + y * matrix.y + matrix.z;
+ float y_s = x * (-matrix.y) + y * matrix.x + matrix.w;
+
+ if (x < width && y < height) {
+ switch (fill) {
+ case 0: //FILL_BLANK
+ def = 0;
+ break;
+ case 1: //FILL_ORIGINAL
+ def = src[y*src_stride_lu + x];
+ break;
+ case 2: //FILL_CLAMP
+ y_s = clipf(y_s, 0, height - 1);
+ x_s = clipf(x_s, 0, width - 1);
+ def = src[(int)y_s * src_stride_lu + (int)x_s];
+ break;
+ case 3: //FILL_MIRROR
+ y_s = mirror(y_s, height - 1);
+ x_s = mirror(x_s, width - 1);
+ def = src[(int)y_s * src_stride_lu + (int)x_s];
+ break;
+ }
+ switch (interpolate) {
+ case 0: //INTERPOLATE_NEAREST
+ dst[idx_dst] = interpolate_nearest(x_s, y_s, src, width, height, src_stride_lu, def);
+ break;
+ case 1: //INTERPOLATE_BILINEAR
+ dst[idx_dst] = interpolate_bilinear(x_s, y_s, src, width, height, src_stride_lu, def);
+ break;
+ case 2: //INTERPOLATE_BIQUADRATIC
+ dst[idx_dst] = interpolate_biquadratic(x_s, y_s, src, width, height, src_stride_lu, def);
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+kernel void avfilter_transform_chroma(global unsigned char *src,
+ global unsigned char *dst,
+ float4 matrix,
+ int interpolate,
+ int fill,
+ int src_stride_lu,
+ int dst_stride_lu,
+ int src_stride_ch,
+ int dst_stride_ch,
+ int height,
+ int width,
+ int ch,
+ int cw)
+{
+
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+ int pad_ch = get_global_size(1)>>1;
+ global unsigned char *dst_u = dst + height * dst_stride_lu;
+ global unsigned char *src_u = src + height * src_stride_lu;
+ global unsigned char *dst_v = dst_u + ch * dst_stride_ch;
+ global unsigned char *src_v = src_u + ch * src_stride_ch;
+ src = y < pad_ch ? src_u : src_v;
+ dst = y < pad_ch ? dst_u : dst_v;
+ y = select(y - pad_ch, y, y < pad_ch);
+ float x_s = x * matrix.x + y * matrix.y + matrix.z;
+ float y_s = x * (-matrix.y) + y * matrix.x + matrix.w;
+ int idx_dst = y * dst_stride_ch + x;
+ unsigned char def;
+
+ if (x < cw && y < ch) {
+ switch (fill) {
+ case 0: //FILL_BLANK
+ def = 0;
+ break;
+ case 1: //FILL_ORIGINAL
+ def = src[y*src_stride_ch + x];
+ break;
+ case 2: //FILL_CLAMP
+ y_s = clipf(y_s, 0, ch - 1);
+ x_s = clipf(x_s, 0, cw - 1);
+ def = src[(int)y_s * src_stride_ch + (int)x_s];
+ break;
+ case 3: //FILL_MIRROR
+ y_s = mirror(y_s, ch - 1);
+ x_s = mirror(x_s, cw - 1);
+ def = src[(int)y_s * src_stride_ch + (int)x_s];
+ break;
+ }
+ switch (interpolate) {
+ case 0: //INTERPOLATE_NEAREST
+ dst[idx_dst] = interpolate_nearest(x_s, y_s, src, cw, ch, src_stride_ch, def);
+ break;
+ case 1: //INTERPOLATE_BILINEAR
+ dst[idx_dst] = interpolate_bilinear(x_s, y_s, src, cw, ch, src_stride_ch, def);
+ break;
+ case 2: //INTERPOLATE_BIQUADRATIC
+ dst[idx_dst] = interpolate_biquadratic(x_s, y_s, src, cw, ch, src_stride_ch, def);
+ break;
+ default:
+ return;
+ }
+ }
+}
+);
+
+#endif /* AVFILTER_DESHAKE_OPENCL_KERNEL_H */
diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c
index e837760459..0b2f17e52a 100644
--- a/libavfilter/drawutils.c
+++ b/libavfilter/drawutils.c
@@ -1,18 +1,21 @@
/*
- * This file is part of Libav.
+ * Copyright 2011 Stefano Sabatini <stefano.sabatini-lala poste it>
+ * Copyright 2012 Nicolas George <nicolas.george normalesup org>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,36 +26,58 @@
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
#include "drawutils.h"
+#include "formats.h"
enum { RED = 0, GREEN, BLUE, ALPHA };
-int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t dst_color[4],
- enum AVPixelFormat pix_fmt, uint8_t rgba_color[4],
- int *is_packed_rgba, uint8_t rgba_map_ptr[4])
+int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
{
- uint8_t rgba_map[4] = {0};
- int i;
- const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt);
- int hsub = pix_desc->log2_chroma_w;
-
- *is_packed_rgba = 1;
switch (pix_fmt) {
+ case AV_PIX_FMT_0RGB:
case AV_PIX_FMT_ARGB: rgba_map[ALPHA] = 0; rgba_map[RED ] = 1; rgba_map[GREEN] = 2; rgba_map[BLUE ] = 3; break;
+ case AV_PIX_FMT_0BGR:
case AV_PIX_FMT_ABGR: rgba_map[ALPHA] = 0; rgba_map[BLUE ] = 1; rgba_map[GREEN] = 2; rgba_map[RED ] = 3; break;
+ case AV_PIX_FMT_RGB48LE:
+ case AV_PIX_FMT_RGB48BE:
+ case AV_PIX_FMT_RGBA64BE:
+ case AV_PIX_FMT_RGBA64LE:
+ case AV_PIX_FMT_RGB0:
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_RGB24: rgba_map[RED ] = 0; rgba_map[GREEN] = 1; rgba_map[BLUE ] = 2; rgba_map[ALPHA] = 3; break;
+ case AV_PIX_FMT_BGR48LE:
+ case AV_PIX_FMT_BGR48BE:
+ case AV_PIX_FMT_BGRA64BE:
+ case AV_PIX_FMT_BGRA64LE:
case AV_PIX_FMT_BGRA:
+ case AV_PIX_FMT_BGR0:
case AV_PIX_FMT_BGR24: rgba_map[BLUE ] = 0; rgba_map[GREEN] = 1; rgba_map[RED ] = 2; rgba_map[ALPHA] = 3; break;
- default:
- *is_packed_rgba = 0;
+ case AV_PIX_FMT_GBRAP:
+ case AV_PIX_FMT_GBRP: rgba_map[GREEN] = 0; rgba_map[BLUE ] = 1; rgba_map[RED ] = 2; rgba_map[ALPHA] = 3; break;
+ default: /* unsupported */
+ return AVERROR(EINVAL);
}
+ return 0;
+}
+
+int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t dst_color[4],
+ enum AVPixelFormat pix_fmt, uint8_t rgba_color[4],
+ int *is_packed_rgba, uint8_t rgba_map_ptr[4])
+{
+ uint8_t rgba_map[4] = {0};
+ int i;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt);
+ int hsub = pix_desc->log2_chroma_w;
+
+ *is_packed_rgba = ff_fill_rgba_map(rgba_map, pix_fmt) >= 0;
if (*is_packed_rgba) {
pixel_step[0] = (av_get_bits_per_pixel(pix_desc))>>3;
for (i = 0; i < 4; i++)
dst_color[rgba_map[i]] = rgba_color[i];
- line[0] = av_malloc(w * pixel_step[0]);
+ line[0] = av_malloc_array(w, pixel_step[0]);
+ if (!line[0])
+ return AVERROR(ENOMEM);
for (i = 0; i < w; i++)
memcpy(line[0] + i * pixel_step[0], dst_color, pixel_step[0]);
if (rgba_map_ptr)
@@ -70,8 +95,13 @@ int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t
int hsub1 = (plane == 1 || plane == 2) ? hsub : 0;
pixel_step[plane] = 1;
- line_size = (w >> hsub1) * pixel_step[plane];
+ line_size = FF_CEIL_RSHIFT(w, hsub1) * pixel_step[plane];
line[plane] = av_malloc(line_size);
+ if (!line[plane]) {
+ while(plane && line[plane-1])
+ av_freep(&line[--plane]);
+ return AVERROR(ENOMEM);
+ }
memset(line[plane], dst_color[plane], line_size);
}
}
@@ -89,11 +119,13 @@ void ff_draw_rectangle(uint8_t *dst[4], int dst_linesize[4],
for (plane = 0; plane < 4 && dst[plane]; plane++) {
int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
+ int width = FF_CEIL_RSHIFT(w, hsub1);
+ int height = FF_CEIL_RSHIFT(h, vsub1);
p = dst[plane] + (y >> vsub1) * dst_linesize[plane];
- for (i = 0; i < (h >> vsub1); i++) {
+ for (i = 0; i < height; i++) {
memcpy(p + (x >> hsub1) * pixelstep[plane],
- src[plane], (w >> hsub1) * pixelstep[plane]);
+ src[plane], width * pixelstep[plane]);
p += dst_linesize[plane];
}
}
@@ -109,12 +141,435 @@ void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
for (plane = 0; plane < 4 && dst[plane]; plane++) {
int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
+ int width = FF_CEIL_RSHIFT(w, hsub1);
+ int height = FF_CEIL_RSHIFT(h, vsub1);
p = dst[plane] + (y >> vsub1) * dst_linesize[plane];
- for (i = 0; i < (h >> vsub1); i++) {
+ for (i = 0; i < height; i++) {
memcpy(p + (x >> hsub1) * pixelstep[plane],
- src[plane] + src_linesize[plane]*(i+(y2>>vsub1)), (w >> hsub1) * pixelstep[plane]);
+ src[plane] + src_linesize[plane]*(i+(y2>>vsub1)), width * pixelstep[plane]);
+ p += dst_linesize[plane];
+ }
+ }
+}
+
+int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
+ const AVComponentDescriptor *c;
+ unsigned i, nb_planes = 0;
+ int pixelstep[MAX_PLANES] = { 0 };
+
+ if (!desc->name)
+ return AVERROR(EINVAL);
+ if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA))
+ return AVERROR(ENOSYS);
+ for (i = 0; i < desc->nb_components; i++) {
+ c = &desc->comp[i];
+ /* for now, only 8-bits formats */
+ if (c->depth_minus1 != 8 - 1)
+ return AVERROR(ENOSYS);
+ if (c->plane >= MAX_PLANES)
+ return AVERROR(ENOSYS);
+ /* strange interleaving */
+ if (pixelstep[c->plane] != 0 &&
+ pixelstep[c->plane] != c->step_minus1 + 1)
+ return AVERROR(ENOSYS);
+ pixelstep[c->plane] = c->step_minus1 + 1;
+ if (pixelstep[c->plane] >= 8)
+ return AVERROR(ENOSYS);
+ nb_planes = FFMAX(nb_planes, c->plane + 1);
+ }
+ if ((desc->log2_chroma_w || desc->log2_chroma_h) && nb_planes < 3)
+ return AVERROR(ENOSYS); /* exclude NV12 and NV21 */
+ memset(draw, 0, sizeof(*draw));
+ draw->desc = desc;
+ draw->format = format;
+ draw->nb_planes = nb_planes;
+ memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
+ draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
+ draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
+ for (i = 0; i < ((desc->nb_components - 1) | 1); i++)
+ draw->comp_mask[desc->comp[i].plane] |=
+ 1 << (desc->comp[i].offset_plus1 - 1);
+ return 0;
+}
+
+void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
+{
+ unsigned i;
+ uint8_t rgba_map[4];
+
+ if (rgba != color->rgba)
+ memcpy(color->rgba, rgba, sizeof(color->rgba));
+ if ((draw->desc->flags & AV_PIX_FMT_FLAG_RGB) &&
+ ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
+ if (draw->nb_planes == 1) {
+ for (i = 0; i < 4; i++)
+ color->comp[0].u8[rgba_map[i]] = rgba[i];
+ } else {
+ for (i = 0; i < 4; i++)
+ color->comp[rgba_map[i]].u8[0] = rgba[i];
+ }
+ } else if (draw->nb_planes == 3 || draw->nb_planes == 4) {
+ /* assume YUV */
+ color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
+ color->comp[1].u8[0] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
+ color->comp[2].u8[0] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
+ color->comp[3].u8[0] = rgba[3];
+ } else if (draw->format == AV_PIX_FMT_GRAY8 || draw->format == AV_PIX_FMT_GRAY8A) {
+ color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
+ color->comp[1].u8[0] = rgba[3];
+ } else {
+ av_log(NULL, AV_LOG_WARNING,
+ "Color conversion not implemented for %s\n", draw->desc->name);
+ memset(color, 128, sizeof(*color));
+ }
+}
+
+static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
+ int plane, int x, int y)
+{
+ return data[plane] +
+ (y >> draw->vsub[plane]) * linesize[plane] +
+ (x >> draw->hsub[plane]) * draw->pixelstep[plane];
+}
+
+void ff_copy_rectangle2(FFDrawContext *draw,
+ uint8_t *dst[], int dst_linesize[],
+ uint8_t *src[], int src_linesize[],
+ int dst_x, int dst_y, int src_x, int src_y,
+ int w, int h)
+{
+ int plane, y, wp, hp;
+ uint8_t *p, *q;
+
+ for (plane = 0; plane < draw->nb_planes; plane++) {
+ p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
+ q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
+ wp = FF_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
+ hp = FF_CEIL_RSHIFT(h, draw->vsub[plane]);
+ for (y = 0; y < hp; y++) {
+ memcpy(q, p, wp);
+ p += src_linesize[plane];
+ q += dst_linesize[plane];
+ }
+ }
+}
+
+void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[],
+ int dst_x, int dst_y, int w, int h)
+{
+ int plane, x, y, wp, hp;
+ uint8_t *p0, *p;
+
+ for (plane = 0; plane < draw->nb_planes; plane++) {
+ p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
+ wp = FF_CEIL_RSHIFT(w, draw->hsub[plane]);
+ hp = FF_CEIL_RSHIFT(h, draw->vsub[plane]);
+ if (!hp)
+ return;
+ p = p0;
+ /* copy first line from color */
+ for (x = 0; x < wp; x++) {
+ memcpy(p, color->comp[plane].u8, draw->pixelstep[plane]);
+ p += draw->pixelstep[plane];
+ }
+ wp *= draw->pixelstep[plane];
+ /* copy next lines from first line */
+ p = p0 + dst_linesize[plane];
+ for (y = 1; y < hp; y++) {
+ memcpy(p, p0, wp);
p += dst_linesize[plane];
}
}
}
+
+/**
+ * Clip interval [x; x+w[ within [0; wmax[.
+ * The resulting w may be negative if the final interval is empty.
+ * dx, if not null, return the difference between in and out value of x.
+ */
+static void clip_interval(int wmax, int *x, int *w, int *dx)
+{
+ if (dx)
+ *dx = 0;
+ if (*x < 0) {
+ if (dx)
+ *dx = -*x;
+ *w += *x;
+ *x = 0;
+ }
+ if (*x + *w > wmax)
+ *w = wmax - *x;
+}
+
+/**
+ * Decompose w pixels starting at x
+ * into start + (w starting at x) + end
+ * with x and w aligned on multiples of 1<<sub.
+ */
+static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
+{
+ int mask = (1 << sub) - 1;
+
+ *start = (-*x) & mask;
+ *x += *start;
+ *start = FFMIN(*start, *w);
+ *w -= *start;
+ *end = *w & mask;
+ *w >>= sub;
+}
+
+static int component_used(FFDrawContext *draw, int plane, int comp)
+{
+ return (draw->comp_mask[plane] >> comp) & 1;
+}
+
+/* If alpha is in the [ 0 ; 0x1010101 ] range,
+ then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range,
+ and >> 24 gives a correct rounding. */
+static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
+ int dx, int w, unsigned hsub, int left, int right)
+{
+ unsigned asrc = alpha * src;
+ unsigned tau = 0x1010101 - alpha;
+ int x;
+
+ if (left) {
+ unsigned suba = (left * alpha) >> hsub;
+ *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
+ dst += dx;
+ }
+ for (x = 0; x < w; x++) {
+ *dst = (*dst * tau + asrc) >> 24;
+ dst += dx;
+ }
+ if (right) {
+ unsigned suba = (right * alpha) >> hsub;
+ *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
+ }
+}
+
+void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[],
+ int dst_w, int dst_h,
+ int x0, int y0, int w, int h)
+{
+ unsigned alpha, nb_planes, nb_comp, plane, comp;
+ int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
+ uint8_t *p0, *p;
+
+ /* TODO optimize if alpha = 0xFF */
+ clip_interval(dst_w, &x0, &w, NULL);
+ clip_interval(dst_h, &y0, &h, NULL);
+ if (w <= 0 || h <= 0 || !color->rgba[3])
+ return;
+ /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
+ alpha = 0x10203 * color->rgba[3] + 0x2;
+ nb_planes = (draw->nb_planes - 1) | 1; /* eliminate alpha */
+ for (plane = 0; plane < nb_planes; plane++) {
+ nb_comp = draw->pixelstep[plane];
+ p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
+ w_sub = w;
+ h_sub = h;
+ x_sub = x0;
+ y_sub = y0;
+ subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
+ subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
+ for (comp = 0; comp < nb_comp; comp++) {
+ if (!component_used(draw, plane, comp))
+ continue;
+ p = p0 + comp;
+ if (top) {
+ blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
+ draw->pixelstep[plane], w_sub,
+ draw->hsub[plane], left, right);
+ p += dst_linesize[plane];
+ }
+ for (y = 0; y < h_sub; y++) {
+ blend_line(p, color->comp[plane].u8[comp], alpha,
+ draw->pixelstep[plane], w_sub,
+ draw->hsub[plane], left, right);
+ p += dst_linesize[plane];
+ }
+ if (bottom)
+ blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
+ draw->pixelstep[plane], w_sub,
+ draw->hsub[plane], left, right);
+ }
+ }
+}
+
+static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
+ uint8_t *mask, int mask_linesize, int l2depth,
+ unsigned w, unsigned h, unsigned shift, unsigned xm0)
+{
+ unsigned xm, x, y, t = 0;
+ unsigned xmshf = 3 - l2depth;
+ unsigned xmmod = 7 >> l2depth;
+ unsigned mbits = (1 << (1 << l2depth)) - 1;
+ unsigned mmult = 255 / mbits;
+
+ for (y = 0; y < h; y++) {
+ xm = xm0;
+ for (x = 0; x < w; x++) {
+ t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
+ * mmult;
+ xm++;
+ }
+ mask += mask_linesize;
+ }
+ alpha = (t >> shift) * alpha;
+ *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
+}
+
+static void blend_line_hv(uint8_t *dst, int dst_delta,
+ unsigned src, unsigned alpha,
+ uint8_t *mask, int mask_linesize, int l2depth, int w,
+ unsigned hsub, unsigned vsub,
+ int xm, int left, int right, int hband)
+{
+ int x;
+
+ if (left) {
+ blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
+ left, hband, hsub + vsub, xm);
+ dst += dst_delta;
+ xm += left;
+ }
+ for (x = 0; x < w; x++) {
+ blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
+ 1 << hsub, hband, hsub + vsub, xm);
+ dst += dst_delta;
+ xm += 1 << hsub;
+ }
+ if (right)
+ blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
+ right, hband, hsub + vsub, xm);
+}
+
+void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
+ uint8_t *mask, int mask_linesize, int mask_w, int mask_h,
+ int l2depth, unsigned endianness, int x0, int y0)
+{
+ unsigned alpha, nb_planes, nb_comp, plane, comp;
+ int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
+ uint8_t *p0, *p, *m;
+
+ clip_interval(dst_w, &x0, &mask_w, &xm0);
+ clip_interval(dst_h, &y0, &mask_h, &ym0);
+ mask += ym0 * mask_linesize;
+ if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
+ return;
+ /* alpha is in the [ 0 ; 0x10203 ] range,
+ alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
+ alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
+ nb_planes = (draw->nb_planes - 1) | 1; /* eliminate alpha */
+ for (plane = 0; plane < nb_planes; plane++) {
+ nb_comp = draw->pixelstep[plane];
+ p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
+ w_sub = mask_w;
+ h_sub = mask_h;
+ x_sub = x0;
+ y_sub = y0;
+ subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
+ subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
+ for (comp = 0; comp < nb_comp; comp++) {
+ if (!component_used(draw, plane, comp))
+ continue;
+ p = p0 + comp;
+ m = mask;
+ if (top) {
+ blend_line_hv(p, draw->pixelstep[plane],
+ color->comp[plane].u8[comp], alpha,
+ m, mask_linesize, l2depth, w_sub,
+ draw->hsub[plane], draw->vsub[plane],
+ xm0, left, right, top);
+ p += dst_linesize[plane];
+ m += top * mask_linesize;
+ }
+ for (y = 0; y < h_sub; y++) {
+ blend_line_hv(p, draw->pixelstep[plane],
+ color->comp[plane].u8[comp], alpha,
+ m, mask_linesize, l2depth, w_sub,
+ draw->hsub[plane], draw->vsub[plane],
+ xm0, left, right, 1 << draw->vsub[plane]);
+ p += dst_linesize[plane];
+ m += mask_linesize << draw->vsub[plane];
+ }
+ if (bottom)
+ blend_line_hv(p, draw->pixelstep[plane],
+ color->comp[plane].u8[comp], alpha,
+ m, mask_linesize, l2depth, w_sub,
+ draw->hsub[plane], draw->vsub[plane],
+ xm0, left, right, bottom);
+ }
+ }
+}
+
+int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
+ int value)
+{
+ unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
+
+ if (!shift)
+ return value;
+ if (round_dir >= 0)
+ value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
+ return (value >> shift) << shift;
+}
+
+AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
+{
+ enum AVPixelFormat i;
+ FFDrawContext draw;
+ AVFilterFormats *fmts = NULL;
+
+ for (i = 0; av_pix_fmt_desc_get(i); i++)
+ if (ff_draw_init(&draw, i, flags) >= 0)
+ ff_add_format(&fmts, i);
+ return fmts;
+}
+
+#ifdef TEST
+
+#undef printf
+
+int main(void)
+{
+ enum AVPixelFormat f;
+ const AVPixFmtDescriptor *desc;
+ FFDrawContext draw;
+ FFDrawColor color;
+ int r, i;
+
+ for (f = 0; av_pix_fmt_desc_get(f); f++) {
+ desc = av_pix_fmt_desc_get(f);
+ if (!desc->name)
+ continue;
+ printf("Testing %s...%*s", desc->name,
+ (int)(16 - strlen(desc->name)), "");
+ r = ff_draw_init(&draw, f, 0);
+ if (r < 0) {
+ char buf[128];
+ av_strerror(r, buf, sizeof(buf));
+ printf("no: %s\n", buf);
+ continue;
+ }
+ ff_draw_color(&draw, &color, (uint8_t[]) { 1, 0, 0, 1 });
+ for (i = 0; i < sizeof(color); i++)
+ if (((uint8_t *)&color)[i] != 128)
+ break;
+ if (i == sizeof(color)) {
+ printf("fallback color\n");
+ continue;
+ }
+ printf("ok\n");
+ }
+ return 0;
+}
+
+#endif
diff --git a/libavfilter/drawutils.h b/libavfilter/drawutils.h
index 73f482e83e..5ffffe77c1 100644
--- a/libavfilter/drawutils.h
+++ b/libavfilter/drawutils.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,8 +25,11 @@
*/
#include <stdint.h>
+#include "avfilter.h"
#include "libavutil/pixfmt.h"
+int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt);
+
int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w,
uint8_t dst_color[4],
enum AVPixelFormat pix_fmt, uint8_t rgba_color[4],
@@ -40,4 +43,113 @@ void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
uint8_t *src[4], int src_linesize[4], int pixelstep[4],
int hsub, int vsub, int x, int y, int y2, int w, int h);
+#define MAX_PLANES 4
+
+typedef struct FFDrawContext {
+ const struct AVPixFmtDescriptor *desc;
+ enum AVPixelFormat format;
+ unsigned nb_planes;
+ int pixelstep[MAX_PLANES]; /*< offset between pixels */
+ uint8_t comp_mask[MAX_PLANES]; /*< bitmask of used non-alpha components */
+ uint8_t hsub[MAX_PLANES]; /*< horizontal subsampling */
+ uint8_t vsub[MAX_PLANES]; /*< vertical subsampling */
+ uint8_t hsub_max;
+ uint8_t vsub_max;
+} FFDrawContext;
+
+typedef struct FFDrawColor {
+ uint8_t rgba[4];
+ union {
+ uint32_t u32;
+ uint16_t u16;
+ uint8_t u8[4];
+ } comp[MAX_PLANES];
+} FFDrawColor;
+
+/**
+ * Init a draw context.
+ *
+ * Only a limited number of pixel formats are supported, if format is not
+ * supported the function will return an error.
+ * No flags currently defined.
+ * @return 0 for success, < 0 for error
+ */
+int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags);
+
+/**
+ * Prepare a color.
+ */
+void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4]);
+
+/**
+ * Copy a rectangle from an image to another.
+ *
+ * The coordinates must be as even as the subsampling requires.
+ */
+void ff_copy_rectangle2(FFDrawContext *draw,
+ uint8_t *dst[], int dst_linesize[],
+ uint8_t *src[], int src_linesize[],
+ int dst_x, int dst_y, int src_x, int src_y,
+ int w, int h);
+
+/**
+ * Fill a rectangle with an uniform color.
+ *
+ * The coordinates must be as even as the subsampling requires.
+ * The color needs to be inited with ff_draw_color.
+ */
+void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[],
+ int dst_x, int dst_y, int w, int h);
+
+/**
+ * Blend a rectangle with an uniform color.
+ */
+void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[],
+ int dst_w, int dst_h,
+ int x0, int y0, int w, int h);
+
+/**
+ * Blend an alpha mask with an uniform color.
+ *
+ * @param draw draw context
+ * @param color color for the overlay;
+ * @param dst destination image
+ * @param dst_linesize line stride of the destination
+ * @param dst_w width of the destination image
+ * @param dst_h height of the destination image
+ * @param mask mask
+ * @param mask_linesize line stride of the mask
+ * @param mask_w width of the mask
+ * @param mask_h height of the mask
+ * @param l2depth log2 of depth of the mask (0 for 1bpp, 3 for 8bpp)
+ * @param endianness bit order of the mask (0: MSB to the left)
+ * @param x0 horizontal position of the overlay
+ * @param y0 vertical position of the overlay
+ */
+void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
+ uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
+ uint8_t *mask, int mask_linesize, int mask_w, int mask_h,
+ int l2depth, unsigned endianness, int x0, int y0);
+
+/**
+ * Round a dimension according to subsampling.
+ *
+ * @param draw draw context
+ * @param sub_dir 0 for horizontal, 1 for vertical
+ * @param round_dir 0 nearest, -1 round down, +1 round up
+ * @param value value to round
+ * @return the rounded value
+ */
+int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
+ int value);
+
+/**
+ * Return the list of pixel formats supported by the draw functions.
+ *
+ * The flags are the same as ff_draw_init, i.e., none currently.
+ */
+AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags);
+
#endif /* AVFILTER_DRAWUTILS_H */
diff --git a/libavfilter/dualinput.c b/libavfilter/dualinput.c
new file mode 100644
index 0000000000..45f681078d
--- /dev/null
+++ b/libavfilter/dualinput.c
@@ -0,0 +1,83 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dualinput.h"
+#include "libavutil/timestamp.h"
+
+static int process_frame(FFFrameSync *fs)
+{
+ AVFilterContext *ctx = fs->parent;
+ FFDualInputContext *s = fs->opaque;
+ AVFrame *mainpic = NULL, *secondpic = NULL;
+ int ret = 0;
+
+ if ((ret = ff_framesync_get_frame(&s->fs, 0, &mainpic, 1)) < 0 ||
+ (ret = ff_framesync_get_frame(&s->fs, 1, &secondpic, 0)) < 0) {
+ av_frame_free(&mainpic);
+ return ret;
+ }
+ av_assert0(mainpic);
+ mainpic->pts = av_rescale_q(mainpic->pts, s->fs.time_base, ctx->outputs[0]->time_base);
+ if (secondpic && !ctx->is_disabled)
+ mainpic = s->process(ctx, mainpic, secondpic);
+ ret = ff_filter_frame(ctx->outputs[0], mainpic);
+ av_assert1(ret != AVERROR(EAGAIN));
+ return ret;
+}
+
+int ff_dualinput_init(AVFilterContext *ctx, FFDualInputContext *s)
+{
+ FFFrameSyncIn *in = s->fs.in;
+
+ ff_framesync_init(&s->fs, ctx, 2);
+ s->fs.opaque = s;
+ s->fs.on_event = process_frame;
+ in[0].time_base = ctx->inputs[0]->time_base;
+ in[1].time_base = ctx->inputs[1]->time_base;
+ in[0].sync = 2;
+ in[0].before = EXT_STOP;
+ in[0].after = EXT_INFINITY;
+ in[1].sync = 1;
+ in[1].before = EXT_NULL;
+ in[1].after = EXT_INFINITY;
+
+ if (s->shortest)
+ in[0].after = in[1].after = EXT_STOP;
+ if (!s->repeatlast) {
+ in[1].after = EXT_NULL;
+ in[1].sync = 0;
+ }
+
+ return ff_framesync_configure(&s->fs);
+}
+
+int ff_dualinput_filter_frame(FFDualInputContext *s,
+ AVFilterLink *inlink, AVFrame *in)
+{
+ return ff_framesync_filter_frame(&s->fs, inlink, in);
+}
+
+int ff_dualinput_request_frame(FFDualInputContext *s, AVFilterLink *outlink)
+{
+ return ff_framesync_request_frame(&s->fs, outlink);
+}
+
+void ff_dualinput_uninit(FFDualInputContext *s)
+{
+ ff_framesync_uninit(&s->fs);
+}
diff --git a/libavfilter/dualinput.h b/libavfilter/dualinput.h
new file mode 100644
index 0000000000..0ec0ea7350
--- /dev/null
+++ b/libavfilter/dualinput.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Double input streams helper for filters
+ */
+
+#ifndef AVFILTER_DUALINPUT_H
+#define AVFILTER_DUALINPUT_H
+
+#include <stdint.h>
+#include "bufferqueue.h"
+#include "framesync.h"
+#include "internal.h"
+
+typedef struct {
+ FFFrameSync fs;
+ FFFrameSyncIn second_input; /* must be immediately after fs */
+
+ AVFrame *(*process)(AVFilterContext *ctx, AVFrame *main, const AVFrame *second);
+ int shortest; ///< terminate stream when the second input terminates
+ int repeatlast; ///< repeat last second frame
+} FFDualInputContext;
+
+int ff_dualinput_init(AVFilterContext *ctx, FFDualInputContext *s);
+int ff_dualinput_filter_frame(FFDualInputContext *s, AVFilterLink *inlink, AVFrame *in);
+int ff_dualinput_request_frame(FFDualInputContext *s, AVFilterLink *outlink);
+void ff_dualinput_uninit(FFDualInputContext *s);
+
+#endif /* AVFILTER_DUALINPUT_H */
diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c
new file mode 100644
index 0000000000..c18ae79915
--- /dev/null
+++ b/libavfilter/f_ebur128.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ * EBU R.128 implementation
+ * @see http://tech.ebu.ch/loudness
+ * @see https://www.youtube.com/watch?v=iuEtQqC-Sqo "EBU R128 Introduction - Florian Camerer"
+ * @todo implement start/stop/reset through filter command injection
+ * @todo support other frequencies to avoid resampling
+ */
+
+#include <math.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/dict.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 "formats.h"
+#include "internal.h"
+
+#define MAX_CHANNELS 63
+
+/* pre-filter coefficients */
+#define PRE_B0 1.53512485958697
+#define PRE_B1 -2.69169618940638
+#define PRE_B2 1.19839281085285
+#define PRE_A1 -1.69065929318241
+#define PRE_A2 0.73248077421585
+
+/* RLB-filter coefficients */
+#define RLB_B0 1.0
+#define RLB_B1 -2.0
+#define RLB_B2 1.0
+#define RLB_A1 -1.99004745483398
+#define RLB_A2 0.99007225036621
+
+#define ABS_THRES -70 ///< silence gate: we discard anything below this absolute (LUFS) threshold
+#define ABS_UP_THRES 10 ///< upper loud limit to consider (ABS_THRES being the minimum)
+#define HIST_GRAIN 100 ///< defines histogram precision
+#define HIST_SIZE ((ABS_UP_THRES - ABS_THRES) * HIST_GRAIN + 1)
+
+/**
+ * A histogram is an array of HIST_SIZE hist_entry storing all the energies
+ * recorded (with an accuracy of 1/HIST_GRAIN) of the loudnesses from ABS_THRES
+ * (at 0) to ABS_UP_THRES (at HIST_SIZE-1).
+ * This fixed-size system avoids the need of a list of energies growing
+ * infinitely over the time and is thus more scalable.
+ */
+struct hist_entry {
+ int count; ///< how many times the corresponding value occurred
+ double energy; ///< E = 10^((L + 0.691) / 10)
+ double loudness; ///< L = -0.691 + 10 * log10(E)
+};
+
+struct integrator {
+ double *cache[MAX_CHANNELS]; ///< window of filtered samples (N ms)
+ int cache_pos; ///< focus on the last added bin in the cache array
+ double sum[MAX_CHANNELS]; ///< sum of the last N ms filtered samples (cache content)
+ int filled; ///< 1 if the cache is completely filled, 0 otherwise
+ double rel_threshold; ///< relative threshold
+ double sum_kept_powers; ///< sum of the powers (weighted sums) above absolute threshold
+ int nb_kept_powers; ///< number of sum above absolute threshold
+ struct hist_entry *histogram; ///< histogram of the powers, used to compute LRA and I
+};
+
+struct rect { int x, y, w, h; };
+
+typedef struct {
+ const AVClass *class; ///< AVClass context for log and options purpose
+
+ /* peak metering */
+ int peak_mode; ///< enabled peak modes
+ double *true_peaks; ///< true peaks per channel
+ double *sample_peaks; ///< sample peaks per channel
+ double *true_peaks_per_frame; ///< true peaks in a frame per channel
+#if CONFIG_SWRESAMPLE
+ SwrContext *swr_ctx; ///< over-sampling context for true peak metering
+ double *swr_buf; ///< resampled audio data for true peak metering
+ int swr_linesize;
+#endif
+
+ /* video */
+ int do_video; ///< 1 if video output enabled, 0 otherwise
+ int w, h; ///< size of the video output
+ struct rect text; ///< rectangle for the LU legend on the left
+ struct rect graph; ///< rectangle for the main graph in the center
+ struct rect gauge; ///< rectangle for the gauge on the right
+ AVFrame *outpicref; ///< output picture reference, updated regularly
+ int meter; ///< select a EBU mode between +9 and +18
+ int scale_range; ///< the range of LU values according to the meter
+ int y_zero_lu; ///< the y value (pixel position) for 0 LU
+ int *y_line_ref; ///< y reference values for drawing the LU lines in the graph and the gauge
+
+ /* audio */
+ int nb_channels; ///< number of channels in the input
+ double *ch_weighting; ///< channel weighting mapping
+ int sample_count; ///< sample count used for refresh frequency, reset at refresh
+
+ /* Filter caches.
+ * The mult by 3 in the following is for X[i], X[i-1] and X[i-2] */
+ double x[MAX_CHANNELS * 3]; ///< 3 input samples cache for each channel
+ double y[MAX_CHANNELS * 3]; ///< 3 pre-filter samples cache for each channel
+ double z[MAX_CHANNELS * 3]; ///< 3 RLB-filter samples cache for each channel
+
+#define I400_BINS (48000 * 4 / 10)
+#define I3000_BINS (48000 * 3)
+ struct integrator i400; ///< 400ms integrator, used for Momentary loudness (M), and Integrated loudness (I)
+ struct integrator i3000; ///< 3s integrator, used for Short term loudness (S), and Loudness Range (LRA)
+
+ /* I and LRA specific */
+ double integrated_loudness; ///< integrated loudness in LUFS (I)
+ double loudness_range; ///< loudness range in LU (LRA)
+ double lra_low, lra_high; ///< low and high LRA values
+
+ /* misc */
+ int loglevel; ///< log level for frame logging
+ int metadata; ///< whether or not to inject loudness results in frames
+} EBUR128Context;
+
+enum {
+ PEAK_MODE_NONE = 0,
+ PEAK_MODE_SAMPLES_PEAKS = 1<<1,
+ PEAK_MODE_TRUE_PEAKS = 1<<2,
+};
+
+#define OFFSET(x) offsetof(EBUR128Context, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define V AV_OPT_FLAG_VIDEO_PARAM
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption ebur128_options[] = {
+ { "video", "set video output", OFFSET(do_video), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, V|F },
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "640x480"}, 0, 0, V|F },
+ { "meter", "set scale meter (+9 to +18)", OFFSET(meter), AV_OPT_TYPE_INT, {.i64 = 9}, 9, 18, V|F },
+ { "framelog", "force frame logging level", OFFSET(loglevel), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, A|V|F, "level" },
+ { "info", "information logging level", 0, AV_OPT_TYPE_CONST, {.i64 = AV_LOG_INFO}, INT_MIN, INT_MAX, A|V|F, "level" },
+ { "verbose", "verbose logging level", 0, AV_OPT_TYPE_CONST, {.i64 = AV_LOG_VERBOSE}, INT_MIN, INT_MAX, A|V|F, "level" },
+ { "metadata", "inject metadata in the filtergraph", OFFSET(metadata), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, A|V|F },
+ { "peak", "set peak mode", OFFSET(peak_mode), AV_OPT_TYPE_FLAGS, {.i64 = PEAK_MODE_NONE}, 0, INT_MAX, A|F, "mode" },
+ { "none", "disable any peak mode", 0, AV_OPT_TYPE_CONST, {.i64 = PEAK_MODE_NONE}, INT_MIN, INT_MAX, A|F, "mode" },
+ { "sample", "enable peak-sample mode", 0, AV_OPT_TYPE_CONST, {.i64 = PEAK_MODE_SAMPLES_PEAKS}, INT_MIN, INT_MAX, A|F, "mode" },
+ { "true", "enable true-peak mode", 0, AV_OPT_TYPE_CONST, {.i64 = PEAK_MODE_TRUE_PEAKS}, INT_MIN, INT_MAX, A|F, "mode" },
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(ebur128);
+
+static const uint8_t graph_colors[] = {
+ 0xdd, 0x66, 0x66, // value above 0LU non reached
+ 0x66, 0x66, 0xdd, // value below 0LU non reached
+ 0x96, 0x33, 0x33, // value above 0LU reached
+ 0x33, 0x33, 0x96, // value below 0LU reached
+ 0xdd, 0x96, 0x96, // value above 0LU line non reached
+ 0x96, 0x96, 0xdd, // value below 0LU line non reached
+ 0xdd, 0x33, 0x33, // value above 0LU line reached
+ 0x33, 0x33, 0xdd, // value below 0LU line reached
+};
+
+static const uint8_t *get_graph_color(const EBUR128Context *ebur128, int v, int y)
+{
+ const int below0 = y > ebur128->y_zero_lu;
+ const int reached = y >= v;
+ const int line = ebur128->y_line_ref[y] || y == ebur128->y_zero_lu;
+ const int colorid = 4*line + 2*reached + below0;
+ return graph_colors + 3*colorid;
+}
+
+static inline int lu_to_y(const EBUR128Context *ebur128, double v)
+{
+ v += 2 * ebur128->meter; // make it in range [0;...]
+ v = av_clipf(v, 0, ebur128->scale_range); // make sure it's in the graph scale
+ v = ebur128->scale_range - v; // invert value (y=0 is on top)
+ return v * ebur128->graph.h / ebur128->scale_range; // rescale from scale range to px height
+}
+
+#define FONT8 0
+#define FONT16 1
+
+static const uint8_t font_colors[] = {
+ 0xdd, 0xdd, 0x00,
+ 0x00, 0x96, 0x96,
+};
+
+static void drawtext(AVFrame *pic, int x, int y, int ftid, const uint8_t *color, const char *fmt, ...)
+{
+ int i;
+ char buf[128] = {0};
+ const uint8_t *font;
+ int font_height;
+ va_list vl;
+
+ if (ftid == FONT16) font = avpriv_vga16_font, font_height = 16;
+ else if (ftid == FONT8) font = avpriv_cga_font, font_height = 8;
+ else return;
+
+ va_start(vl, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, vl);
+ va_end(vl);
+
+ for (i = 0; buf[i]; i++) {
+ int char_y, mask;
+ uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8)*3;
+
+ for (char_y = 0; char_y < font_height; char_y++) {
+ for (mask = 0x80; mask; mask >>= 1) {
+ if (font[buf[i] * font_height + char_y] & mask)
+ memcpy(p, color, 3);
+ else
+ memcpy(p, "\x00\x00\x00", 3);
+ p += 3;
+ }
+ p += pic->linesize[0] - 8*3;
+ }
+ }
+}
+
+static void drawline(AVFrame *pic, int x, int y, int len, int step)
+{
+ int i;
+ uint8_t *p = pic->data[0] + y*pic->linesize[0] + x*3;
+
+ for (i = 0; i < len; i++) {
+ memcpy(p, "\x00\xff\x00", 3);
+ p += step;
+ }
+}
+
+static int config_video_output(AVFilterLink *outlink)
+{
+ int i, x, y;
+ uint8_t *p;
+ AVFilterContext *ctx = outlink->src;
+ EBUR128Context *ebur128 = ctx->priv;
+ AVFrame *outpicref;
+
+ /* check if there is enough space to represent everything decently */
+ if (ebur128->w < 640 || ebur128->h < 480) {
+ av_log(ctx, AV_LOG_ERROR, "Video size %dx%d is too small, "
+ "minimum size is 640x480\n", ebur128->w, ebur128->h);
+ return AVERROR(EINVAL);
+ }
+ outlink->w = ebur128->w;
+ outlink->h = ebur128->h;
+
+#define PAD 8
+
+ /* configure text area position and size */
+ ebur128->text.x = PAD;
+ ebur128->text.y = 40;
+ ebur128->text.w = 3 * 8; // 3 characters
+ ebur128->text.h = ebur128->h - PAD - ebur128->text.y;
+
+ /* configure gauge position and size */
+ ebur128->gauge.w = 20;
+ ebur128->gauge.h = ebur128->text.h;
+ ebur128->gauge.x = ebur128->w - PAD - ebur128->gauge.w;
+ ebur128->gauge.y = ebur128->text.y;
+
+ /* configure graph position and size */
+ ebur128->graph.x = ebur128->text.x + ebur128->text.w + PAD;
+ ebur128->graph.y = ebur128->gauge.y;
+ ebur128->graph.w = ebur128->gauge.x - ebur128->graph.x - PAD;
+ ebur128->graph.h = ebur128->gauge.h;
+
+ /* graph and gauge share the LU-to-pixel code */
+ av_assert0(ebur128->graph.h == ebur128->gauge.h);
+
+ /* prepare the initial picref buffer */
+ av_frame_free(&ebur128->outpicref);
+ ebur128->outpicref = outpicref =
+ ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpicref)
+ return AVERROR(ENOMEM);
+ outlink->sample_aspect_ratio = (AVRational){1,1};
+
+ /* init y references values (to draw LU lines) */
+ ebur128->y_line_ref = av_calloc(ebur128->graph.h + 1, sizeof(*ebur128->y_line_ref));
+ if (!ebur128->y_line_ref)
+ return AVERROR(ENOMEM);
+
+ /* black background */
+ memset(outpicref->data[0], 0, ebur128->h * outpicref->linesize[0]);
+
+ /* draw LU legends */
+ drawtext(outpicref, PAD, PAD+16, FONT8, font_colors+3, " LU");
+ for (i = ebur128->meter; i >= -ebur128->meter * 2; i--) {
+ y = lu_to_y(ebur128, i);
+ x = PAD + (i < 10 && i > -10) * 8;
+ ebur128->y_line_ref[y] = i;
+ y -= 4; // -4 to center vertically
+ drawtext(outpicref, x, y + ebur128->graph.y, FONT8, font_colors+3,
+ "%c%d", i < 0 ? '-' : i > 0 ? '+' : ' ', FFABS(i));
+ }
+
+ /* draw graph */
+ ebur128->y_zero_lu = lu_to_y(ebur128, 0);
+ p = outpicref->data[0] + ebur128->graph.y * outpicref->linesize[0]
+ + ebur128->graph.x * 3;
+ for (y = 0; y < ebur128->graph.h; y++) {
+ const uint8_t *c = get_graph_color(ebur128, INT_MAX, y);
+
+ for (x = 0; x < ebur128->graph.w; x++)
+ memcpy(p + x*3, c, 3);
+ p += outpicref->linesize[0];
+ }
+
+ /* draw fancy rectangles around the graph and the gauge */
+#define DRAW_RECT(r) do { \
+ drawline(outpicref, r.x, r.y - 1, r.w, 3); \
+ drawline(outpicref, r.x, r.y + r.h, r.w, 3); \
+ drawline(outpicref, r.x - 1, r.y, r.h, outpicref->linesize[0]); \
+ drawline(outpicref, r.x + r.w, r.y, r.h, outpicref->linesize[0]); \
+} while (0)
+ DRAW_RECT(ebur128->graph);
+ DRAW_RECT(ebur128->gauge);
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return 0;
+}
+
+static int config_audio_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ EBUR128Context *ebur128 = ctx->priv;
+
+ /* Force 100ms framing in case of metadata injection: the frames must have
+ * a granularity of the window overlap to be accurately exploited.
+ * As for the true peaks mode, it just simplifies the resampling buffer
+ * allocation and the lookup in it (since sample buffers differ in size, it
+ * can be more complex to integrate in the one-sample loop of
+ * filter_frame()). */
+ if (ebur128->metadata || (ebur128->peak_mode & PEAK_MODE_TRUE_PEAKS))
+ inlink->min_samples =
+ inlink->max_samples =
+ inlink->partial_buf_size = inlink->sample_rate / 10;
+ return 0;
+}
+
+static int config_audio_output(AVFilterLink *outlink)
+{
+ int i;
+ AVFilterContext *ctx = outlink->src;
+ EBUR128Context *ebur128 = ctx->priv;
+ const int nb_channels = av_get_channel_layout_nb_channels(outlink->channel_layout);
+
+#define BACK_MASK (AV_CH_BACK_LEFT |AV_CH_BACK_CENTER |AV_CH_BACK_RIGHT| \
+ AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_BACK_RIGHT| \
+ AV_CH_SIDE_LEFT |AV_CH_SIDE_RIGHT| \
+ AV_CH_SURROUND_DIRECT_LEFT |AV_CH_SURROUND_DIRECT_RIGHT)
+
+ ebur128->nb_channels = nb_channels;
+ ebur128->ch_weighting = av_calloc(nb_channels, sizeof(*ebur128->ch_weighting));
+ if (!ebur128->ch_weighting)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < nb_channels; i++) {
+ /* channel weighting */
+ const uint16_t chl = av_channel_layout_extract_channel(outlink->channel_layout, i);
+ if (chl & (AV_CH_LOW_FREQUENCY|AV_CH_LOW_FREQUENCY_2)) {
+ ebur128->ch_weighting[i] = 0;
+ } else if (chl & BACK_MASK) {
+ ebur128->ch_weighting[i] = 1.41;
+ } else {
+ ebur128->ch_weighting[i] = 1.0;
+ }
+
+ if (!ebur128->ch_weighting[i])
+ continue;
+
+ /* bins buffer for the two integration window (400ms and 3s) */
+ ebur128->i400.cache[i] = av_calloc(I400_BINS, sizeof(*ebur128->i400.cache[0]));
+ ebur128->i3000.cache[i] = av_calloc(I3000_BINS, sizeof(*ebur128->i3000.cache[0]));
+ if (!ebur128->i400.cache[i] || !ebur128->i3000.cache[i])
+ return AVERROR(ENOMEM);
+ }
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+#if CONFIG_SWRESAMPLE
+ if (ebur128->peak_mode & PEAK_MODE_TRUE_PEAKS) {
+ int ret;
+
+ ebur128->swr_buf = av_malloc_array(nb_channels, 19200 * sizeof(double));
+ ebur128->true_peaks = av_calloc(nb_channels, sizeof(*ebur128->true_peaks));
+ ebur128->true_peaks_per_frame = av_calloc(nb_channels, sizeof(*ebur128->true_peaks_per_frame));
+ ebur128->swr_ctx = swr_alloc();
+ if (!ebur128->swr_buf || !ebur128->true_peaks ||
+ !ebur128->true_peaks_per_frame || !ebur128->swr_ctx)
+ return AVERROR(ENOMEM);
+
+ av_opt_set_int(ebur128->swr_ctx, "in_channel_layout", outlink->channel_layout, 0);
+ av_opt_set_int(ebur128->swr_ctx, "in_sample_rate", outlink->sample_rate, 0);
+ av_opt_set_sample_fmt(ebur128->swr_ctx, "in_sample_fmt", outlink->format, 0);
+
+ av_opt_set_int(ebur128->swr_ctx, "out_channel_layout", outlink->channel_layout, 0);
+ av_opt_set_int(ebur128->swr_ctx, "out_sample_rate", 192000, 0);
+ av_opt_set_sample_fmt(ebur128->swr_ctx, "out_sample_fmt", outlink->format, 0);
+
+ ret = swr_init(ebur128->swr_ctx);
+ if (ret < 0)
+ return ret;
+ }
+#endif
+
+ if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS) {
+ ebur128->sample_peaks = av_calloc(nb_channels, sizeof(*ebur128->sample_peaks));
+ if (!ebur128->sample_peaks)
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+#define ENERGY(loudness) (pow(10, ((loudness) + 0.691) / 10.))
+#define LOUDNESS(energy) (-0.691 + 10 * log10(energy))
+#define DBFS(energy) (20 * log10(energy))
+
+static struct hist_entry *get_histogram(void)
+{
+ int i;
+ struct hist_entry *h = av_calloc(HIST_SIZE, sizeof(*h));
+
+ if (!h)
+ return NULL;
+ for (i = 0; i < HIST_SIZE; i++) {
+ h[i].loudness = i / (double)HIST_GRAIN + ABS_THRES;
+ h[i].energy = ENERGY(h[i].loudness);
+ }
+ return h;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ EBUR128Context *ebur128 = ctx->priv;
+ AVFilterPad pad;
+
+ if (ebur128->loglevel != AV_LOG_INFO &&
+ ebur128->loglevel != AV_LOG_VERBOSE) {
+ if (ebur128->do_video || ebur128->metadata)
+ ebur128->loglevel = AV_LOG_VERBOSE;
+ else
+ ebur128->loglevel = AV_LOG_INFO;
+ }
+
+ if (!CONFIG_SWRESAMPLE && (ebur128->peak_mode & PEAK_MODE_TRUE_PEAKS)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "True-peak mode requires libswresample to be performed\n");
+ return AVERROR(EINVAL);
+ }
+
+ // if meter is +9 scale, scale range is from -18 LU to +9 LU (or 3*9)
+ // if meter is +18 scale, scale range is from -36 LU to +18 LU (or 3*18)
+ ebur128->scale_range = 3 * ebur128->meter;
+
+ ebur128->i400.histogram = get_histogram();
+ ebur128->i3000.histogram = get_histogram();
+ if (!ebur128->i400.histogram || !ebur128->i3000.histogram)
+ return AVERROR(ENOMEM);
+
+ ebur128->integrated_loudness = ABS_THRES;
+ ebur128->loudness_range = 0;
+
+ /* insert output pads */
+ if (ebur128->do_video) {
+ pad = (AVFilterPad){
+ .name = av_strdup("out0"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_video_output,
+ };
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ ff_insert_outpad(ctx, 0, &pad);
+ }
+ pad = (AVFilterPad){
+ .name = av_asprintf("out%d", ebur128->do_video),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_audio_output,
+ };
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ ff_insert_outpad(ctx, ebur128->do_video, &pad);
+
+ /* summary */
+ av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter);
+
+ return 0;
+}
+
+#define HIST_POS(power) (int)(((power) - ABS_THRES) * HIST_GRAIN)
+
+/* loudness and power should be set such as loudness = -0.691 +
+ * 10*log10(power), we just avoid doing that calculus two times */
+static int gate_update(struct integrator *integ, double power,
+ double loudness, int gate_thres)
+{
+ int ipower;
+ double relative_threshold;
+ int gate_hist_pos;
+
+ /* update powers histograms by incrementing current power count */
+ ipower = av_clip(HIST_POS(loudness), 0, HIST_SIZE - 1);
+ integ->histogram[ipower].count++;
+
+ /* compute relative threshold and get its position in the histogram */
+ integ->sum_kept_powers += power;
+ integ->nb_kept_powers++;
+ relative_threshold = integ->sum_kept_powers / integ->nb_kept_powers;
+ if (!relative_threshold)
+ relative_threshold = 1e-12;
+ integ->rel_threshold = LOUDNESS(relative_threshold) + gate_thres;
+ gate_hist_pos = av_clip(HIST_POS(integ->rel_threshold), 0, HIST_SIZE - 1);
+
+ return gate_hist_pos;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
+{
+ int i, ch, idx_insample;
+ AVFilterContext *ctx = inlink->dst;
+ EBUR128Context *ebur128 = ctx->priv;
+ const int nb_channels = ebur128->nb_channels;
+ const int nb_samples = insamples->nb_samples;
+ const double *samples = (double *)insamples->data[0];
+ AVFrame *pic = ebur128->outpicref;
+
+#if CONFIG_SWRESAMPLE
+ if (ebur128->peak_mode & PEAK_MODE_TRUE_PEAKS) {
+ const double *swr_samples = ebur128->swr_buf;
+ int ret = swr_convert(ebur128->swr_ctx, (uint8_t**)&ebur128->swr_buf, 19200,
+ (const uint8_t **)insamples->data, nb_samples);
+ if (ret < 0)
+ return ret;
+ for (ch = 0; ch < nb_channels; ch++)
+ ebur128->true_peaks_per_frame[ch] = 0.0;
+ for (idx_insample = 0; idx_insample < ret; idx_insample++) {
+ for (ch = 0; ch < nb_channels; ch++) {
+ ebur128->true_peaks[ch] = FFMAX(ebur128->true_peaks[ch], FFABS(*swr_samples));
+ ebur128->true_peaks_per_frame[ch] = FFMAX(ebur128->true_peaks_per_frame[ch],
+ FFABS(*swr_samples));
+ swr_samples++;
+ }
+ }
+ }
+#endif
+
+ for (idx_insample = 0; idx_insample < nb_samples; idx_insample++) {
+ const int bin_id_400 = ebur128->i400.cache_pos;
+ const int bin_id_3000 = ebur128->i3000.cache_pos;
+
+#define MOVE_TO_NEXT_CACHED_ENTRY(time) do { \
+ ebur128->i##time.cache_pos++; \
+ if (ebur128->i##time.cache_pos == I##time##_BINS) { \
+ ebur128->i##time.filled = 1; \
+ ebur128->i##time.cache_pos = 0; \
+ } \
+} while (0)
+
+ MOVE_TO_NEXT_CACHED_ENTRY(400);
+ MOVE_TO_NEXT_CACHED_ENTRY(3000);
+
+ for (ch = 0; ch < nb_channels; ch++) {
+ double bin;
+
+ if (ebur128->peak_mode & PEAK_MODE_SAMPLES_PEAKS)
+ ebur128->sample_peaks[ch] = FFMAX(ebur128->sample_peaks[ch], FFABS(*samples));
+
+ ebur128->x[ch * 3] = *samples++; // set X[i]
+
+ if (!ebur128->ch_weighting[ch])
+ continue;
+
+ /* Y[i] = X[i]*b0 + X[i-1]*b1 + X[i-2]*b2 - Y[i-1]*a1 - Y[i-2]*a2 */
+#define FILTER(Y, X, name) do { \
+ double *dst = ebur128->Y + ch*3; \
+ double *src = ebur128->X + ch*3; \
+ dst[2] = dst[1]; \
+ dst[1] = dst[0]; \
+ dst[0] = src[0]*name##_B0 + src[1]*name##_B1 + src[2]*name##_B2 \
+ - dst[1]*name##_A1 - dst[2]*name##_A2; \
+} while (0)
+
+ // TODO: merge both filters in one?
+ FILTER(y, x, PRE); // apply pre-filter
+ ebur128->x[ch * 3 + 2] = ebur128->x[ch * 3 + 1];
+ ebur128->x[ch * 3 + 1] = ebur128->x[ch * 3 ];
+ FILTER(z, y, RLB); // apply RLB-filter
+
+ bin = ebur128->z[ch * 3] * ebur128->z[ch * 3];
+
+ /* add the new value, and limit the sum to the cache size (400ms or 3s)
+ * by removing the oldest one */
+ ebur128->i400.sum [ch] = ebur128->i400.sum [ch] + bin - ebur128->i400.cache [ch][bin_id_400];
+ ebur128->i3000.sum[ch] = ebur128->i3000.sum[ch] + bin - ebur128->i3000.cache[ch][bin_id_3000];
+
+ /* override old cache entry with the new value */
+ ebur128->i400.cache [ch][bin_id_400 ] = bin;
+ ebur128->i3000.cache[ch][bin_id_3000] = bin;
+ }
+
+ /* For integrated loudness, gating blocks are 400ms long with 75%
+ * overlap (see BS.1770-2 p5), so a re-computation is needed each 100ms
+ * (4800 samples at 48kHz). */
+ if (++ebur128->sample_count == 4800) {
+ double loudness_400, loudness_3000;
+ double power_400 = 1e-12, power_3000 = 1e-12;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const int64_t pts = insamples->pts +
+ av_rescale_q(idx_insample, (AVRational){ 1, inlink->sample_rate },
+ outlink->time_base);
+
+ ebur128->sample_count = 0;
+
+#define COMPUTE_LOUDNESS(m, time) do { \
+ if (ebur128->i##time.filled) { \
+ /* weighting sum of the last <time> ms */ \
+ for (ch = 0; ch < nb_channels; ch++) \
+ power_##time += ebur128->ch_weighting[ch] * ebur128->i##time.sum[ch]; \
+ power_##time /= I##time##_BINS; \
+ } \
+ loudness_##time = LOUDNESS(power_##time); \
+} while (0)
+
+ COMPUTE_LOUDNESS(M, 400);
+ COMPUTE_LOUDNESS(S, 3000);
+
+ /* Integrated loudness */
+#define I_GATE_THRES -10 // initially defined to -8 LU in the first EBU standard
+
+ if (loudness_400 >= ABS_THRES) {
+ double integrated_sum = 0;
+ int nb_integrated = 0;
+ int gate_hist_pos = gate_update(&ebur128->i400, power_400,
+ loudness_400, I_GATE_THRES);
+
+ /* compute integrated loudness by summing the histogram values
+ * above the relative threshold */
+ for (i = gate_hist_pos; i < HIST_SIZE; i++) {
+ const int nb_v = ebur128->i400.histogram[i].count;
+ nb_integrated += nb_v;
+ integrated_sum += nb_v * ebur128->i400.histogram[i].energy;
+ }
+ if (nb_integrated)
+ ebur128->integrated_loudness = LOUDNESS(integrated_sum / nb_integrated);
+ }
+
+ /* LRA */
+#define LRA_GATE_THRES -20
+#define LRA_LOWER_PRC 10
+#define LRA_HIGHER_PRC 95
+
+ /* XXX: example code in EBU 3342 is ">=" but formula in BS.1770
+ * specs is ">" */
+ if (loudness_3000 >= ABS_THRES) {
+ int nb_powers = 0;
+ int gate_hist_pos = gate_update(&ebur128->i3000, power_3000,
+ loudness_3000, LRA_GATE_THRES);
+
+ for (i = gate_hist_pos; i < HIST_SIZE; i++)
+ nb_powers += ebur128->i3000.histogram[i].count;
+ if (nb_powers) {
+ int n, nb_pow;
+
+ /* get lower loudness to consider */
+ n = 0;
+ nb_pow = LRA_LOWER_PRC * nb_powers / 100. + 0.5;
+ for (i = gate_hist_pos; i < HIST_SIZE; i++) {
+ n += ebur128->i3000.histogram[i].count;
+ if (n >= nb_pow) {
+ ebur128->lra_low = ebur128->i3000.histogram[i].loudness;
+ break;
+ }
+ }
+
+ /* get higher loudness to consider */
+ n = nb_powers;
+ nb_pow = LRA_HIGHER_PRC * nb_powers / 100. + 0.5;
+ for (i = HIST_SIZE - 1; i >= 0; i--) {
+ n -= ebur128->i3000.histogram[i].count;
+ if (n < nb_pow) {
+ ebur128->lra_high = ebur128->i3000.histogram[i].loudness;
+ break;
+ }
+ }
+
+ // XXX: show low & high on the graph?
+ ebur128->loudness_range = ebur128->lra_high - ebur128->lra_low;
+ }
+ }
+
+#define LOG_FMT "M:%6.1f S:%6.1f I:%6.1f LUFS LRA:%6.1f LU"
+
+ /* push one video frame */
+ if (ebur128->do_video) {
+ int x, y, ret;
+ uint8_t *p;
+
+ const int y_loudness_lu_graph = lu_to_y(ebur128, loudness_3000 + 23);
+ const int y_loudness_lu_gauge = lu_to_y(ebur128, loudness_400 + 23);
+
+ /* draw the graph using the short-term loudness */
+ p = pic->data[0] + ebur128->graph.y*pic->linesize[0] + ebur128->graph.x*3;
+ for (y = 0; y < ebur128->graph.h; y++) {
+ const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_graph, y);
+
+ memmove(p, p + 3, (ebur128->graph.w - 1) * 3);
+ memcpy(p + (ebur128->graph.w - 1) * 3, c, 3);
+ p += pic->linesize[0];
+ }
+
+ /* draw the gauge using the momentary loudness */
+ p = pic->data[0] + ebur128->gauge.y*pic->linesize[0] + ebur128->gauge.x*3;
+ for (y = 0; y < ebur128->gauge.h; y++) {
+ const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_gauge, y);
+
+ for (x = 0; x < ebur128->gauge.w; x++)
+ memcpy(p + x*3, c, 3);
+ p += pic->linesize[0];
+ }
+
+ /* draw textual info */
+ drawtext(pic, PAD, PAD - PAD/2, FONT16, font_colors,
+ LOG_FMT " ", // padding to erase trailing characters
+ loudness_400, loudness_3000,
+ ebur128->integrated_loudness, ebur128->loudness_range);
+
+ /* set pts and push frame */
+ pic->pts = pts;
+ ret = ff_filter_frame(outlink, av_frame_clone(pic));
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ebur128->metadata) { /* happens only once per filter_frame call */
+ char metabuf[128];
+#define META_PREFIX "lavfi.r128."
+
+#define SET_META(name, var) do { \
+ snprintf(metabuf, sizeof(metabuf), "%.3f", var); \
+ av_dict_set(&insamples->metadata, name, metabuf, 0); \
+} while (0)
+
+#define SET_META_PEAK(name, ptype) do { \
+ if (ebur128->peak_mode & PEAK_MODE_ ## ptype ## _PEAKS) { \
+ char key[64]; \
+ for (ch = 0; ch < nb_channels; ch++) { \
+ snprintf(key, sizeof(key), \
+ META_PREFIX AV_STRINGIFY(name) "_peaks_ch%d", ch); \
+ SET_META(key, ebur128->name##_peaks[ch]); \
+ } \
+ } \
+} while (0)
+
+ SET_META(META_PREFIX "M", loudness_400);
+ SET_META(META_PREFIX "S", loudness_3000);
+ SET_META(META_PREFIX "I", ebur128->integrated_loudness);
+ SET_META(META_PREFIX "LRA", ebur128->loudness_range);
+ SET_META(META_PREFIX "LRA.low", ebur128->lra_low);
+ SET_META(META_PREFIX "LRA.high", ebur128->lra_high);
+
+ SET_META_PEAK(sample, SAMPLES);
+ SET_META_PEAK(true, TRUE);
+ }
+
+ av_log(ctx, ebur128->loglevel, "t: %-10s " LOG_FMT,
+ av_ts2timestr(pts, &outlink->time_base),
+ loudness_400, loudness_3000,
+ ebur128->integrated_loudness, ebur128->loudness_range);
+
+#define PRINT_PEAKS(str, sp, ptype) do { \
+ if (ebur128->peak_mode & PEAK_MODE_ ## ptype ## _PEAKS) { \
+ av_log(ctx, ebur128->loglevel, " " str ":"); \
+ for (ch = 0; ch < nb_channels; ch++) \
+ av_log(ctx, ebur128->loglevel, " %5.1f", DBFS(sp[ch])); \
+ av_log(ctx, ebur128->loglevel, " dBFS"); \
+ } \
+} while (0)
+
+ PRINT_PEAKS("SPK", ebur128->sample_peaks, SAMPLES);
+ PRINT_PEAKS("FTPK", ebur128->true_peaks_per_frame, TRUE);
+ PRINT_PEAKS("TPK", ebur128->true_peaks, TRUE);
+ av_log(ctx, ebur128->loglevel, "\n");
+ }
+ }
+
+ return ff_filter_frame(ctx->outputs[ebur128->do_video], insamples);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ EBUR128Context *ebur128 = ctx->priv;
+ AVFilterFormats *formats;
+ AVFilterChannelLayouts *layouts;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE };
+ static const int input_srate[] = {48000, -1}; // ITU-R BS.1770 provides coeff only for 48kHz
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
+
+ /* set optional output video format */
+ if (ebur128->do_video) {
+ formats = ff_make_format_list(pix_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &outlink->in_formats);
+ outlink = ctx->outputs[1];
+ }
+
+ /* set input and output audio formats
+ * Note: ff_set_common_* functions are not used because they affect all the
+ * links, and thus break the video format negotiation */
+ formats = ff_make_format_list(sample_fmts);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_formats);
+ ff_formats_ref(formats, &outlink->in_formats);
+
+ layouts = ff_all_channel_layouts();
+ if (!layouts)
+ return AVERROR(ENOMEM);
+ ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
+ ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts);
+
+ formats = ff_make_format_list(input_srate);
+ if (!formats)
+ return AVERROR(ENOMEM);
+ ff_formats_ref(formats, &inlink->out_samplerates);
+ ff_formats_ref(formats, &outlink->in_samplerates);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i;
+ EBUR128Context *ebur128 = ctx->priv;
+
+ av_log(ctx, AV_LOG_INFO, "Summary:\n\n"
+ " Integrated loudness:\n"
+ " I: %5.1f LUFS\n"
+ " Threshold: %5.1f LUFS\n\n"
+ " Loudness range:\n"
+ " LRA: %5.1f LU\n"
+ " Threshold: %5.1f LUFS\n"
+ " LRA low: %5.1f LUFS\n"
+ " LRA high: %5.1f LUFS",
+ ebur128->integrated_loudness, ebur128->i400.rel_threshold,
+ ebur128->loudness_range, ebur128->i3000.rel_threshold,
+ ebur128->lra_low, ebur128->lra_high);
+
+#define PRINT_PEAK_SUMMARY(str, sp, ptype) do { \
+ int ch; \
+ double maxpeak; \
+ maxpeak = 0.0; \
+ if (ebur128->peak_mode & PEAK_MODE_ ## ptype ## _PEAKS) { \
+ for (ch = 0; ch < ebur128->nb_channels; ch++) \
+ maxpeak = FFMAX(maxpeak, sp[ch]); \
+ av_log(ctx, AV_LOG_INFO, "\n\n " str " peak:\n" \
+ " Peak: %5.1f dBFS", \
+ DBFS(maxpeak)); \
+ } \
+} while (0)
+
+ PRINT_PEAK_SUMMARY("Sample", ebur128->sample_peaks, SAMPLES);
+ PRINT_PEAK_SUMMARY("True", ebur128->true_peaks, TRUE);
+ av_log(ctx, AV_LOG_INFO, "\n");
+
+ av_freep(&ebur128->y_line_ref);
+ av_freep(&ebur128->ch_weighting);
+ av_freep(&ebur128->true_peaks);
+ av_freep(&ebur128->sample_peaks);
+ av_freep(&ebur128->true_peaks_per_frame);
+ av_freep(&ebur128->i400.histogram);
+ av_freep(&ebur128->i3000.histogram);
+ for (i = 0; i < ebur128->nb_channels; i++) {
+ av_freep(&ebur128->i400.cache[i]);
+ av_freep(&ebur128->i3000.cache[i]);
+ }
+ for (i = 0; i < ctx->nb_outputs; i++)
+ av_freep(&ctx->output_pads[i].name);
+ av_frame_free(&ebur128->outpicref);
+#if CONFIG_SWRESAMPLE
+ av_freep(&ebur128->swr_buf);
+ swr_free(&ebur128->swr_ctx);
+#endif
+}
+
+static const AVFilterPad ebur128_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ .config_props = config_audio_input,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_ebur128 = {
+ .name = "ebur128",
+ .description = NULL_IF_CONFIG_SMALL("EBU R128 scanner."),
+ .priv_size = sizeof(EBUR128Context),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = ebur128_inputs,
+ .outputs = NULL,
+ .priv_class = &ebur128_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
diff --git a/libavfilter/f_interleave.c b/libavfilter/f_interleave.c
new file mode 100644
index 0000000000..95401cfb80
--- /dev/null
+++ b/libavfilter/f_interleave.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio and video interleaver
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "bufferqueue.h"
+#include "formats.h"
+#include "internal.h"
+#include "audio.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int nb_inputs;
+ struct FFBufQueue *queues;
+} InterleaveContext;
+
+#define OFFSET(x) offsetof(InterleaveContext, x)
+
+#define DEFINE_OPTIONS(filt_name, flags_) \
+static const AVOption filt_name##_options[] = { \
+ { "nb_inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, .flags = flags_ }, \
+ { "n", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, .flags = flags_ }, \
+ { NULL } \
+}
+
+inline static int push_frame(AVFilterContext *ctx)
+{
+ InterleaveContext *s = ctx->priv;
+ AVFrame *frame;
+ int i, queue_idx = -1;
+ int64_t pts_min = INT64_MAX;
+
+ /* look for oldest frame */
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ struct FFBufQueue *q = &s->queues[i];
+
+ if (!q->available && !ctx->inputs[i]->closed)
+ return 0;
+ if (q->available) {
+ frame = ff_bufqueue_peek(q, 0);
+ if (frame->pts < pts_min) {
+ pts_min = frame->pts;
+ queue_idx = i;
+ }
+ }
+ }
+
+ /* all inputs are closed */
+ if (queue_idx < 0)
+ return AVERROR_EOF;
+
+ frame = ff_bufqueue_get(&s->queues[queue_idx]);
+ av_log(ctx, AV_LOG_DEBUG, "queue:%d -> frame time:%f\n",
+ queue_idx, frame->pts * av_q2d(AV_TIME_BASE_Q));
+ return ff_filter_frame(ctx->outputs[0], frame);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ InterleaveContext *s = ctx->priv;
+ unsigned in_no = FF_INLINK_IDX(inlink);
+
+ if (frame->pts == AV_NOPTS_VALUE) {
+ av_log(ctx, AV_LOG_WARNING,
+ "NOPTS value for input frame cannot be accepted, frame discarded\n");
+ av_frame_free(&frame);
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* queue frame */
+ frame->pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q);
+ av_log(ctx, AV_LOG_DEBUG, "frame pts:%f -> queue idx:%d available:%d\n",
+ frame->pts * av_q2d(AV_TIME_BASE_Q), in_no, s->queues[in_no].available);
+ ff_bufqueue_add(ctx, &s->queues[in_no], frame);
+
+ return push_frame(ctx);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ InterleaveContext *s = ctx->priv;
+ const AVFilterPad *outpad = &ctx->filter->outputs[0];
+ int i;
+
+ s->queues = av_calloc(s->nb_inputs, sizeof(s->queues[0]));
+ if (!s->queues)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < s->nb_inputs; i++) {
+ AVFilterPad inpad = { 0 };
+
+ inpad.name = av_asprintf("input%d", i);
+ if (!inpad.name)
+ return AVERROR(ENOMEM);
+ inpad.type = outpad->type;
+ inpad.filter_frame = filter_frame;
+
+ switch (outpad->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ inpad.get_video_buffer = ff_null_get_video_buffer; break;
+ case AVMEDIA_TYPE_AUDIO:
+ inpad.get_audio_buffer = ff_null_get_audio_buffer; break;
+ default:
+ av_assert0(0);
+ }
+ ff_insert_inpad(ctx, i, &inpad);
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ InterleaveContext *s = ctx->priv;
+ int i;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ ff_bufqueue_discard_all(&s->queues[i]);
+ av_freep(&s->queues[i]);
+ av_freep(&ctx->input_pads[i].name);
+ }
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink0 = ctx->inputs[0];
+ int i;
+
+ if (outlink->type == AVMEDIA_TYPE_VIDEO) {
+ outlink->time_base = AV_TIME_BASE_Q;
+ outlink->w = inlink0->w;
+ outlink->h = inlink0->h;
+ outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
+ outlink->format = inlink0->format;
+ outlink->frame_rate = (AVRational) {1, 0};
+ for (i = 1; i < ctx->nb_inputs; i++) {
+ AVFilterLink *inlink = ctx->inputs[i];
+
+ if (outlink->w != inlink->w ||
+ outlink->h != inlink->h ||
+ outlink->sample_aspect_ratio.num != inlink->sample_aspect_ratio.num ||
+ outlink->sample_aspect_ratio.den != inlink->sample_aspect_ratio.den) {
+ av_log(ctx, AV_LOG_ERROR, "Parameters for input link %s "
+ "(size %dx%d, SAR %d:%d) do not match the corresponding "
+ "output link parameters (%dx%d, SAR %d:%d)\n",
+ ctx->input_pads[i].name, inlink->w, inlink->h,
+ inlink->sample_aspect_ratio.num,
+ inlink->sample_aspect_ratio.den,
+ outlink->w, outlink->h,
+ outlink->sample_aspect_ratio.num,
+ outlink->sample_aspect_ratio.den);
+ return AVERROR(EINVAL);
+ }
+ }
+ }
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ InterleaveContext *s = ctx->priv;
+ int i, ret;
+
+ for (i = 0; i < ctx->nb_inputs; i++) {
+ if (!s->queues[i].available && !ctx->inputs[i]->closed) {
+ ret = ff_request_frame(ctx->inputs[i]);
+ if (ret != AVERROR_EOF)
+ return ret;
+ }
+ }
+
+ return push_frame(ctx);
+}
+
+#if CONFIG_INTERLEAVE_FILTER
+
+DEFINE_OPTIONS(interleave, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM);
+AVFILTER_DEFINE_CLASS(interleave);
+
+static const AVFilterPad interleave_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_interleave = {
+ .name = "interleave",
+ .description = NULL_IF_CONFIG_SMALL("Temporally interleave video inputs."),
+ .priv_size = sizeof(InterleaveContext),
+ .init = init,
+ .uninit = uninit,
+ .outputs = interleave_outputs,
+ .priv_class = &interleave_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
+
+#endif
+
+#if CONFIG_AINTERLEAVE_FILTER
+
+DEFINE_OPTIONS(ainterleave, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM);
+AVFILTER_DEFINE_CLASS(ainterleave);
+
+static const AVFilterPad ainterleave_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_ainterleave = {
+ .name = "ainterleave",
+ .description = NULL_IF_CONFIG_SMALL("Temporally interleave audio inputs."),
+ .priv_size = sizeof(InterleaveContext),
+ .init = init,
+ .uninit = uninit,
+ .outputs = ainterleave_outputs,
+ .priv_class = &ainterleave_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
+
+#endif
diff --git a/libavfilter/f_perms.c b/libavfilter/f_perms.c
new file mode 100644
index 0000000000..abe2e4f46f
--- /dev/null
+++ b/libavfilter/f_perms.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/lfg.h"
+#include "libavutil/opt.h"
+#include "libavutil/random_seed.h"
+#include "audio.h"
+#include "video.h"
+
+enum mode {
+ MODE_NONE,
+ MODE_RO,
+ MODE_RW,
+ MODE_TOGGLE,
+ MODE_RANDOM,
+ NB_MODES
+};
+
+typedef struct {
+ const AVClass *class;
+ AVLFG lfg;
+ int64_t random_seed;
+ int mode;
+} PermsContext;
+
+#define OFFSET(x) offsetof(PermsContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption options[] = {
+ { "mode", "select permissions mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_NONE}, MODE_NONE, NB_MODES-1, FLAGS, "mode" },
+ { "none", "do nothing", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_NONE}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "ro", "set all output frames read-only", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_RO}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "rw", "set all output frames writable", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_RW}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "toggle", "switch permissions", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_TOGGLE}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "random", "set permissions randomly", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_RANDOM}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "seed", "set the seed for the random mode", OFFSET(random_seed), AV_OPT_TYPE_INT64, {.i64 = -1}, -1, UINT32_MAX, FLAGS },
+ { NULL }
+};
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ PermsContext *perms = ctx->priv;
+
+ if (perms->mode == MODE_RANDOM) {
+ uint32_t seed;
+
+ if (perms->random_seed == -1)
+ perms->random_seed = av_get_random_seed();
+ seed = perms->random_seed;
+ av_log(ctx, AV_LOG_INFO, "random seed: 0x%08x\n", seed);
+ av_lfg_init(&perms->lfg, seed);
+ }
+
+ return 0;
+}
+
+enum perm { RO, RW };
+static const char * const perm_str[2] = { "RO", "RW" };
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ int ret;
+ AVFilterContext *ctx = inlink->dst;
+ PermsContext *perms = ctx->priv;
+ AVFrame *out = frame;
+ enum perm in_perm = av_frame_is_writable(frame) ? RW : RO;
+ enum perm out_perm;
+
+ switch (perms->mode) {
+ case MODE_TOGGLE: out_perm = in_perm == RO ? RW : RO; break;
+ case MODE_RANDOM: out_perm = av_lfg_get(&perms->lfg) & 1 ? RW : RO; break;
+ case MODE_RO: out_perm = RO; break;
+ case MODE_RW: out_perm = RW; break;
+ default: out_perm = in_perm; break;
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE, "%s -> %s%s\n",
+ perm_str[in_perm], perm_str[out_perm],
+ in_perm == out_perm ? " (no-op)" : "");
+
+ if (in_perm == RO && out_perm == RW) {
+ if ((ret = av_frame_make_writable(frame)) < 0)
+ return ret;
+ } else if (in_perm == RW && out_perm == RO) {
+ out = av_frame_clone(frame);
+ if (!out)
+ return AVERROR(ENOMEM);
+ }
+
+ ret = ff_filter_frame(ctx->outputs[0], out);
+
+ if (in_perm == RW && out_perm == RO)
+ av_frame_free(&frame);
+ return ret;
+}
+
+#if CONFIG_APERMS_FILTER
+
+#define aperms_options options
+AVFILTER_DEFINE_CLASS(aperms);
+
+static const AVFilterPad aperms_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad aperms_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aperms = {
+ .name = "aperms",
+ .description = NULL_IF_CONFIG_SMALL("Set permissions for the output audio frame."),
+ .init = init,
+ .priv_size = sizeof(PermsContext),
+ .inputs = aperms_inputs,
+ .outputs = aperms_outputs,
+ .priv_class = &aperms_class,
+};
+#endif /* CONFIG_APERMS_FILTER */
+
+#if CONFIG_PERMS_FILTER
+
+#define perms_options options
+AVFILTER_DEFINE_CLASS(perms);
+
+static const AVFilterPad perms_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad perms_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_perms = {
+ .name = "perms",
+ .description = NULL_IF_CONFIG_SMALL("Set permissions for the output video frame."),
+ .init = init,
+ .priv_size = sizeof(PermsContext),
+ .inputs = perms_inputs,
+ .outputs = perms_outputs,
+ .priv_class = &perms_class,
+};
+#endif /* CONFIG_PERMS_FILTER */
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
new file mode 100644
index 0000000000..3e7cf782ed
--- /dev/null
+++ b/libavfilter/f_select.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * filter for selecting which frame passes in the filterchain
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/eval.h"
+#include "libavutil/fifo.h"
+#include "libavutil/internal.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixelutils.h"
+#include "avfilter.h"
+#include "audio.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+static const char *const var_names[] = {
+ "TB", ///< timebase
+
+ "pts", ///< original pts in the file of the frame
+ "start_pts", ///< first PTS in the stream, expressed in TB units
+ "prev_pts", ///< previous frame PTS
+ "prev_selected_pts", ///< previous selected frame PTS
+
+ "t", ///< timestamp expressed in seconds
+ "start_t", ///< first PTS in the stream, expressed in seconds
+ "prev_t", ///< previous frame time
+ "prev_selected_t", ///< previously selected time
+
+ "pict_type", ///< the type of picture in the movie
+ "I",
+ "P",
+ "B",
+ "S",
+ "SI",
+ "SP",
+ "BI",
+ "PICT_TYPE_I",
+ "PICT_TYPE_P",
+ "PICT_TYPE_B",
+ "PICT_TYPE_S",
+ "PICT_TYPE_SI",
+ "PICT_TYPE_SP",
+ "PICT_TYPE_BI",
+
+ "interlace_type", ///< the frame interlace type
+ "PROGRESSIVE",
+ "TOPFIRST",
+ "BOTTOMFIRST",
+
+ "consumed_samples_n",///< number of samples consumed by the filter (only audio)
+ "samples_n", ///< number of samples in the current frame (only audio)
+ "sample_rate", ///< sample rate (only audio)
+
+ "n", ///< frame number (starting from zero)
+ "selected_n", ///< selected frame number (starting from zero)
+ "prev_selected_n", ///< number of the last selected frame
+
+ "key", ///< tell if the frame is a key frame
+ "pos", ///< original position in the file of the frame
+
+ "scene",
+
+ NULL
+};
+
+enum var_name {
+ VAR_TB,
+
+ VAR_PTS,
+ VAR_START_PTS,
+ VAR_PREV_PTS,
+ VAR_PREV_SELECTED_PTS,
+
+ VAR_T,
+ VAR_START_T,
+ VAR_PREV_T,
+ VAR_PREV_SELECTED_T,
+
+ VAR_PICT_TYPE,
+ VAR_I,
+ VAR_P,
+ VAR_B,
+ VAR_S,
+ VAR_SI,
+ VAR_SP,
+ VAR_BI,
+ VAR_PICT_TYPE_I,
+ VAR_PICT_TYPE_P,
+ VAR_PICT_TYPE_B,
+ VAR_PICT_TYPE_S,
+ VAR_PICT_TYPE_SI,
+ VAR_PICT_TYPE_SP,
+ VAR_PICT_TYPE_BI,
+
+ VAR_INTERLACE_TYPE,
+ VAR_INTERLACE_TYPE_P,
+ VAR_INTERLACE_TYPE_T,
+ VAR_INTERLACE_TYPE_B,
+
+ VAR_CONSUMED_SAMPLES_N,
+ VAR_SAMPLES_N,
+ VAR_SAMPLE_RATE,
+
+ VAR_N,
+ VAR_SELECTED_N,
+ VAR_PREV_SELECTED_N,
+
+ VAR_KEY,
+ VAR_POS,
+
+ VAR_SCENE,
+
+ VAR_VARS_NB
+};
+
+typedef struct SelectContext {
+ const AVClass *class;
+ char *expr_str;
+ AVExpr *expr;
+ double var_values[VAR_VARS_NB];
+ int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise
+ av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only)
+ double prev_mafd; ///< previous MAFD (scene detect only)
+ AVFrame *prev_picref; ///< previous frame (scene detect only)
+ double select;
+ int select_out; ///< mark the selected output pad index
+ int nb_outputs;
+} SelectContext;
+
+#define OFFSET(x) offsetof(SelectContext, x)
+#define DEFINE_OPTIONS(filt_name, FLAGS) \
+static const AVOption filt_name##_options[] = { \
+ { "expr", "set an expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags=FLAGS }, \
+ { "e", "set an expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags=FLAGS }, \
+ { "outputs", "set the number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, .flags=FLAGS }, \
+ { "n", "set the number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, .flags=FLAGS }, \
+ { NULL } \
+}
+
+static int request_frame(AVFilterLink *outlink);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ SelectContext *select = ctx->priv;
+ int i, ret;
+
+ if ((ret = av_expr_parse(&select->expr, select->expr_str,
+ var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n",
+ select->expr_str);
+ return ret;
+ }
+ select->do_scene_detect = !!strstr(select->expr_str, "scene");
+
+ for (i = 0; i < select->nb_outputs; i++) {
+ AVFilterPad pad = { 0 };
+
+ pad.name = av_asprintf("output%d", i);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ pad.type = ctx->filter->inputs[0].type;
+ pad.request_frame = request_frame;
+ ff_insert_outpad(ctx, i, &pad);
+ }
+
+ return 0;
+}
+
+#define INTERLACE_TYPE_P 0
+#define INTERLACE_TYPE_T 1
+#define INTERLACE_TYPE_B 2
+
+static int config_input(AVFilterLink *inlink)
+{
+ SelectContext *select = inlink->dst->priv;
+
+ select->var_values[VAR_N] = 0.0;
+ select->var_values[VAR_SELECTED_N] = 0.0;
+
+ select->var_values[VAR_TB] = av_q2d(inlink->time_base);
+
+ select->var_values[VAR_PREV_PTS] = NAN;
+ select->var_values[VAR_PREV_SELECTED_PTS] = NAN;
+ select->var_values[VAR_PREV_SELECTED_T] = NAN;
+ select->var_values[VAR_PREV_T] = NAN;
+ select->var_values[VAR_START_PTS] = NAN;
+ select->var_values[VAR_START_T] = NAN;
+
+ select->var_values[VAR_I] = AV_PICTURE_TYPE_I;
+ select->var_values[VAR_P] = AV_PICTURE_TYPE_P;
+ select->var_values[VAR_B] = AV_PICTURE_TYPE_B;
+ select->var_values[VAR_SI] = AV_PICTURE_TYPE_SI;
+ select->var_values[VAR_SP] = AV_PICTURE_TYPE_SP;
+ select->var_values[VAR_BI] = AV_PICTURE_TYPE_BI;
+ select->var_values[VAR_PICT_TYPE_I] = AV_PICTURE_TYPE_I;
+ select->var_values[VAR_PICT_TYPE_P] = AV_PICTURE_TYPE_P;
+ select->var_values[VAR_PICT_TYPE_B] = AV_PICTURE_TYPE_B;
+ select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI;
+ select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP;
+ select->var_values[VAR_PICT_TYPE_BI] = AV_PICTURE_TYPE_BI;
+
+ select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P;
+ select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T;
+ select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B;
+
+ select->var_values[VAR_PICT_TYPE] = NAN;
+ select->var_values[VAR_INTERLACE_TYPE] = NAN;
+ select->var_values[VAR_SCENE] = NAN;
+ select->var_values[VAR_CONSUMED_SAMPLES_N] = NAN;
+ select->var_values[VAR_SAMPLES_N] = NAN;
+
+ select->var_values[VAR_SAMPLE_RATE] =
+ inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN;
+
+ if (select->do_scene_detect) {
+ select->sad = av_pixelutils_get_sad_fn(3, 3, 2, select); // 8x8 both sources aligned
+ if (!select->sad)
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static double get_scene_score(AVFilterContext *ctx, AVFrame *frame)
+{
+ double ret = 0;
+ SelectContext *select = ctx->priv;
+ AVFrame *prev_picref = select->prev_picref;
+
+ if (prev_picref &&
+ frame->height == prev_picref->height &&
+ frame->width == prev_picref->width) {
+ int x, y, nb_sad = 0;
+ int64_t sad = 0;
+ double mafd, diff;
+ uint8_t *p1 = frame->data[0];
+ uint8_t *p2 = prev_picref->data[0];
+ const int p1_linesize = frame->linesize[0];
+ const int p2_linesize = prev_picref->linesize[0];
+
+ for (y = 0; y < frame->height - 7; y += 8) {
+ for (x = 0; x < frame->width*3 - 7; x += 8) {
+ sad += select->sad(p1 + x, p1_linesize, p2 + x, p2_linesize);
+ nb_sad += 8 * 8;
+ }
+ p1 += 8 * p1_linesize;
+ p2 += 8 * p2_linesize;
+ }
+ emms_c();
+ mafd = nb_sad ? (double)sad / nb_sad : 0;
+ diff = fabs(mafd - select->prev_mafd);
+ ret = av_clipf(FFMIN(mafd, diff) / 100., 0, 1);
+ select->prev_mafd = mafd;
+ av_frame_free(&prev_picref);
+ }
+ select->prev_picref = av_frame_clone(frame);
+ return ret;
+}
+
+#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
+#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
+
+static void select_frame(AVFilterContext *ctx, AVFrame *frame)
+{
+ SelectContext *select = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ double res;
+
+ if (isnan(select->var_values[VAR_START_PTS]))
+ select->var_values[VAR_START_PTS] = TS2D(frame->pts);
+ 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;
+ select->var_values[VAR_PTS] = TS2D(frame->pts);
+ select->var_values[VAR_T ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
+ select->var_values[VAR_POS] = av_frame_get_pkt_pos(frame) == -1 ? NAN : av_frame_get_pkt_pos(frame);
+ select->var_values[VAR_KEY] = frame->key_frame;
+
+ switch (inlink->type) {
+ case AVMEDIA_TYPE_AUDIO:
+ select->var_values[VAR_SAMPLES_N] = frame->nb_samples;
+ break;
+
+ case AVMEDIA_TYPE_VIDEO:
+ select->var_values[VAR_INTERLACE_TYPE] =
+ !frame->interlaced_frame ? INTERLACE_TYPE_P :
+ frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
+ select->var_values[VAR_PICT_TYPE] = frame->pict_type;
+ if (select->do_scene_detect) {
+ char buf[32];
+ select->var_values[VAR_SCENE] = get_scene_score(ctx, frame);
+ // TODO: document metadata
+ snprintf(buf, sizeof(buf), "%f", select->var_values[VAR_SCENE]);
+ av_dict_set(avpriv_frame_get_metadatap(frame), "lavfi.scene_score", buf, 0);
+ }
+ break;
+ }
+
+ select->select = res = av_expr_eval(select->expr, select->var_values, NULL);
+ av_log(inlink->dst, AV_LOG_DEBUG,
+ "n:%f pts:%f t:%f key:%d",
+ select->var_values[VAR_N],
+ select->var_values[VAR_PTS],
+ select->var_values[VAR_T],
+ frame->key_frame);
+
+ switch (inlink->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c scene:%f",
+ (!frame->interlaced_frame) ? 'P' :
+ frame->top_field_first ? 'T' : 'B',
+ av_get_picture_type_char(frame->pict_type),
+ select->var_values[VAR_SCENE]);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ av_log(inlink->dst, AV_LOG_DEBUG, " samples_n:%d consumed_samples_n:%f",
+ frame->nb_samples,
+ select->var_values[VAR_CONSUMED_SAMPLES_N]);
+ break;
+ }
+
+ if (res == 0) {
+ select->select_out = -1; /* drop */
+ } else if (isnan(res) || res < 0) {
+ select->select_out = 0; /* first output */
+ } else {
+ select->select_out = FFMIN(ceilf(res)-1, select->nb_outputs-1); /* other outputs */
+ }
+
+ av_log(inlink->dst, AV_LOG_DEBUG, " -> select:%f select_out:%d\n", res, select->select_out);
+
+ if (res) {
+ select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N];
+ select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS];
+ select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T];
+ select->var_values[VAR_SELECTED_N] += 1.0;
+ if (inlink->type == AVMEDIA_TYPE_AUDIO)
+ select->var_values[VAR_CONSUMED_SAMPLES_N] += frame->nb_samples;
+ }
+
+ select->var_values[VAR_PREV_PTS] = select->var_values[VAR_PTS];
+ select->var_values[VAR_PREV_T] = select->var_values[VAR_T];
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SelectContext *select = ctx->priv;
+
+ select_frame(ctx, frame);
+ if (select->select)
+ return ff_filter_frame(ctx->outputs[select->select_out], frame);
+
+ av_frame_free(&frame);
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ SelectContext *select = ctx->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ int out_no = FF_OUTLINK_IDX(outlink);
+
+ do {
+ int ret = ff_request_frame(inlink);
+ if (ret < 0)
+ return ret;
+ } while (select->select_out != out_no);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SelectContext *select = ctx->priv;
+ int i;
+
+ av_expr_free(select->expr);
+ select->expr = NULL;
+
+ for (i = 0; i < ctx->nb_outputs; i++)
+ av_freep(&ctx->output_pads[i].name);
+
+ if (select->do_scene_detect) {
+ av_frame_free(&select->prev_picref);
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ SelectContext *select = ctx->priv;
+
+ if (!select->do_scene_detect) {
+ return ff_default_query_formats(ctx);
+ } else {
+ int ret;
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ ret = ff_set_common_formats(ctx, fmts_list);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+#if CONFIG_ASELECT_FILTER
+
+DEFINE_OPTIONS(aselect, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM);
+AVFILTER_DEFINE_CLASS(aselect);
+
+static av_cold int aselect_init(AVFilterContext *ctx)
+{
+ SelectContext *select = ctx->priv;
+ int ret;
+
+ if ((ret = init(ctx)) < 0)
+ return ret;
+
+ if (select->do_scene_detect) {
+ av_log(ctx, AV_LOG_ERROR, "Scene detection is ignored in aselect filter\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static const AVFilterPad avfilter_af_aselect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_aselect = {
+ .name = "aselect",
+ .description = NULL_IF_CONFIG_SMALL("Select audio frames to pass in output."),
+ .init = aselect_init,
+ .uninit = uninit,
+ .priv_size = sizeof(SelectContext),
+ .inputs = avfilter_af_aselect_inputs,
+ .priv_class = &aselect_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
+#endif /* CONFIG_ASELECT_FILTER */
+
+#if CONFIG_SELECT_FILTER
+
+DEFINE_OPTIONS(select, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM);
+AVFILTER_DEFINE_CLASS(select);
+
+static av_cold int select_init(AVFilterContext *ctx)
+{
+ int ret;
+
+ if ((ret = init(ctx)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static const AVFilterPad avfilter_vf_select_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_select = {
+ .name = "select",
+ .description = NULL_IF_CONFIG_SMALL("Select video frames to pass in output."),
+ .init = select_init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(SelectContext),
+ .priv_class = &select_class,
+ .inputs = avfilter_vf_select_inputs,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
+#endif /* CONFIG_SELECT_FILTER */
diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c
new file mode 100644
index 0000000000..7cb958b789
--- /dev/null
+++ b/libavfilter/f_sendcmd.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * send commands filter
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/file.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "avfiltergraph.h"
+#include "audio.h"
+#include "video.h"
+
+#define COMMAND_FLAG_ENTER 1
+#define COMMAND_FLAG_LEAVE 2
+
+static inline char *make_command_flags_str(AVBPrint *pbuf, int flags)
+{
+ static const char * const flag_strings[] = { "enter", "leave" };
+ int i, is_first = 1;
+
+ av_bprint_init(pbuf, 0, AV_BPRINT_SIZE_AUTOMATIC);
+ for (i = 0; i < FF_ARRAY_ELEMS(flag_strings); i++) {
+ if (flags & 1<<i) {
+ if (!is_first)
+ av_bprint_chars(pbuf, '+', 1);
+ av_bprintf(pbuf, "%s", flag_strings[i]);
+ is_first = 0;
+ }
+ }
+
+ return pbuf->str;
+}
+
+typedef struct {
+ int flags;
+ char *target, *command, *arg;
+ int index;
+} Command;
+
+typedef struct {
+ int64_t start_ts; ///< start timestamp expressed as microseconds units
+ int64_t end_ts; ///< end timestamp expressed as microseconds units
+ int index; ///< unique index for these interval commands
+ Command *commands;
+ int nb_commands;
+ int enabled; ///< current time detected inside this interval
+} Interval;
+
+typedef struct {
+ const AVClass *class;
+ Interval *intervals;
+ int nb_intervals;
+
+ char *commands_filename;
+ char *commands_str;
+} SendCmdContext;
+
+#define OFFSET(x) offsetof(SendCmdContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption options[] = {
+ { "commands", "set commands", OFFSET(commands_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "c", "set commands", OFFSET(commands_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "filename", "set commands file", OFFSET(commands_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "f", "set commands file", OFFSET(commands_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { NULL }
+};
+
+#define SPACES " \f\t\n\r"
+
+static void skip_comments(const char **buf)
+{
+ while (**buf) {
+ /* skip leading spaces */
+ *buf += strspn(*buf, SPACES);
+ if (**buf != '#')
+ break;
+
+ (*buf)++;
+
+ /* skip comment until the end of line */
+ *buf += strcspn(*buf, "\n");
+ if (**buf)
+ (*buf)++;
+ }
+}
+
+#define COMMAND_DELIMS " \f\t\n\r,;"
+
+static int parse_command(Command *cmd, int cmd_count, int interval_count,
+ const char **buf, void *log_ctx)
+{
+ int ret;
+
+ memset(cmd, 0, sizeof(Command));
+ cmd->index = cmd_count;
+
+ /* format: [FLAGS] target command arg */
+ *buf += strspn(*buf, SPACES);
+
+ /* parse flags */
+ if (**buf == '[') {
+ (*buf)++; /* skip "[" */
+
+ while (**buf) {
+ int len = strcspn(*buf, "|+]");
+
+ if (!strncmp(*buf, "enter", strlen("enter"))) cmd->flags |= COMMAND_FLAG_ENTER;
+ else if (!strncmp(*buf, "leave", strlen("leave"))) cmd->flags |= COMMAND_FLAG_LEAVE;
+ else {
+ char flag_buf[64];
+ av_strlcpy(flag_buf, *buf, sizeof(flag_buf));
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Unknown flag '%s' in interval #%d, command #%d\n",
+ flag_buf, interval_count, cmd_count);
+ return AVERROR(EINVAL);
+ }
+ *buf += len;
+ if (**buf == ']')
+ break;
+ if (!strspn(*buf, "+|")) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid flags char '%c' in interval #%d, command #%d\n",
+ **buf, interval_count, cmd_count);
+ return AVERROR(EINVAL);
+ }
+ if (**buf)
+ (*buf)++;
+ }
+
+ if (**buf != ']') {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Missing flag terminator or extraneous data found at the end of flags "
+ "in interval #%d, command #%d\n", interval_count, cmd_count);
+ return AVERROR(EINVAL);
+ }
+ (*buf)++; /* skip "]" */
+ } else {
+ cmd->flags = COMMAND_FLAG_ENTER;
+ }
+
+ *buf += strspn(*buf, SPACES);
+ cmd->target = av_get_token(buf, COMMAND_DELIMS);
+ if (!cmd->target || !cmd->target[0]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "No target specified in interval #%d, command #%d\n",
+ interval_count, cmd_count);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ *buf += strspn(*buf, SPACES);
+ cmd->command = av_get_token(buf, COMMAND_DELIMS);
+ if (!cmd->command || !cmd->command[0]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "No command specified in interval #%d, command #%d\n",
+ interval_count, cmd_count);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ *buf += strspn(*buf, SPACES);
+ cmd->arg = av_get_token(buf, COMMAND_DELIMS);
+
+ return 1;
+
+fail:
+ av_freep(&cmd->target);
+ av_freep(&cmd->command);
+ av_freep(&cmd->arg);
+ return ret;
+}
+
+static int parse_commands(Command **cmds, int *nb_cmds, int interval_count,
+ const char **buf, void *log_ctx)
+{
+ int cmd_count = 0;
+ int ret, n = 0;
+ AVBPrint pbuf;
+
+ *cmds = NULL;
+ *nb_cmds = 0;
+
+ while (**buf) {
+ Command cmd;
+
+ if ((ret = parse_command(&cmd, cmd_count, interval_count, buf, log_ctx)) < 0)
+ return ret;
+ cmd_count++;
+
+ /* (re)allocate commands array if required */
+ if (*nb_cmds == n) {
+ n = FFMAX(16, 2*n); /* first allocation = 16, or double the number */
+ *cmds = av_realloc_f(*cmds, n, 2*sizeof(Command));
+ if (!*cmds) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Could not (re)allocate command array\n");
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ (*cmds)[(*nb_cmds)++] = cmd;
+
+ *buf += strspn(*buf, SPACES);
+ if (**buf && **buf != ';' && **buf != ',') {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Missing separator or extraneous data found at the end of "
+ "interval #%d, in command #%d\n",
+ interval_count, cmd_count);
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Command was parsed as: flags:[%s] target:%s command:%s arg:%s\n",
+ make_command_flags_str(&pbuf, cmd.flags), cmd.target, cmd.command, cmd.arg);
+ return AVERROR(EINVAL);
+ }
+ if (**buf == ';')
+ break;
+ if (**buf == ',')
+ (*buf)++;
+ }
+
+ return 0;
+}
+
+#define DELIMS " \f\t\n\r,;"
+
+static int parse_interval(Interval *interval, int interval_count,
+ const char **buf, void *log_ctx)
+{
+ char *intervalstr;
+ int ret;
+
+ *buf += strspn(*buf, SPACES);
+ if (!**buf)
+ return 0;
+
+ /* reset data */
+ memset(interval, 0, sizeof(Interval));
+ interval->index = interval_count;
+
+ /* format: INTERVAL COMMANDS */
+
+ /* parse interval */
+ intervalstr = av_get_token(buf, DELIMS);
+ if (intervalstr && intervalstr[0]) {
+ char *start, *end;
+
+ start = av_strtok(intervalstr, "-", &end);
+ if ((ret = av_parse_time(&interval->start_ts, start, 1)) < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid start time specification '%s' in interval #%d\n",
+ start, interval_count);
+ goto end;
+ }
+
+ if (end) {
+ if ((ret = av_parse_time(&interval->end_ts, end, 1)) < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid end time specification '%s' in interval #%d\n",
+ end, interval_count);
+ goto end;
+ }
+ } else {
+ interval->end_ts = INT64_MAX;
+ }
+ if (interval->end_ts < interval->start_ts) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid end time '%s' in interval #%d: "
+ "cannot be lesser than start time '%s'\n",
+ end, interval_count, start);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ } else {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "No interval specified for interval #%d\n", interval_count);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ /* parse commands */
+ ret = parse_commands(&interval->commands, &interval->nb_commands,
+ interval_count, buf, log_ctx);
+
+end:
+ av_free(intervalstr);
+ return ret;
+}
+
+static int parse_intervals(Interval **intervals, int *nb_intervals,
+ const char *buf, void *log_ctx)
+{
+ int interval_count = 0;
+ int ret, n = 0;
+
+ *intervals = NULL;
+ *nb_intervals = 0;
+
+ if (!buf)
+ return 0;
+
+ while (1) {
+ Interval interval;
+
+ skip_comments(&buf);
+ if (!(*buf))
+ break;
+
+ if ((ret = parse_interval(&interval, interval_count, &buf, log_ctx)) < 0)
+ return ret;
+
+ buf += strspn(buf, SPACES);
+ if (*buf) {
+ if (*buf != ';') {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Missing terminator or extraneous data found at the end of interval #%d\n",
+ interval_count);
+ return AVERROR(EINVAL);
+ }
+ buf++; /* skip ';' */
+ }
+ interval_count++;
+
+ /* (re)allocate commands array if required */
+ if (*nb_intervals == n) {
+ n = FFMAX(16, 2*n); /* first allocation = 16, or double the number */
+ *intervals = av_realloc_f(*intervals, n, 2*sizeof(Interval));
+ if (!*intervals) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Could not (re)allocate intervals array\n");
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ (*intervals)[(*nb_intervals)++] = interval;
+ }
+
+ return 0;
+}
+
+static int cmp_intervals(const void *a, const void *b)
+{
+ const Interval *i1 = a;
+ const Interval *i2 = b;
+ int64_t ts_diff = i1->start_ts - i2->start_ts;
+ int ret;
+
+ ret = ts_diff > 0 ? 1 : ts_diff < 0 ? -1 : 0;
+ return ret == 0 ? i1->index - i2->index : ret;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ SendCmdContext *sendcmd = ctx->priv;
+ int ret, i, j;
+
+ if ((!!sendcmd->commands_filename + !!sendcmd->commands_str) != 1) {
+ av_log(ctx, AV_LOG_ERROR,
+ "One and only one of the filename or commands options must be specified\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (sendcmd->commands_filename) {
+ uint8_t *file_buf, *buf;
+ size_t file_bufsize;
+ ret = av_file_map(sendcmd->commands_filename,
+ &file_buf, &file_bufsize, 0, ctx);
+ if (ret < 0)
+ return ret;
+
+ /* create a 0-terminated string based on the read file */
+ buf = av_malloc(file_bufsize + 1);
+ if (!buf) {
+ av_file_unmap(file_buf, file_bufsize);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, file_buf, file_bufsize);
+ buf[file_bufsize] = 0;
+ av_file_unmap(file_buf, file_bufsize);
+ sendcmd->commands_str = buf;
+ }
+
+ if ((ret = parse_intervals(&sendcmd->intervals, &sendcmd->nb_intervals,
+ sendcmd->commands_str, ctx)) < 0)
+ return ret;
+
+ if (sendcmd->nb_intervals == 0) {
+ av_log(ctx, AV_LOG_ERROR, "No commands were specified\n");
+ return AVERROR(EINVAL);
+ }
+
+ qsort(sendcmd->intervals, sendcmd->nb_intervals, sizeof(Interval), cmp_intervals);
+
+ av_log(ctx, AV_LOG_DEBUG, "Parsed commands:\n");
+ for (i = 0; i < sendcmd->nb_intervals; i++) {
+ AVBPrint pbuf;
+ Interval *interval = &sendcmd->intervals[i];
+ av_log(ctx, AV_LOG_VERBOSE, "start_time:%f end_time:%f index:%d\n",
+ (double)interval->start_ts/1000000, (double)interval->end_ts/1000000, interval->index);
+ for (j = 0; j < interval->nb_commands; j++) {
+ Command *cmd = &interval->commands[j];
+ av_log(ctx, AV_LOG_VERBOSE,
+ " [%s] target:%s command:%s arg:%s index:%d\n",
+ make_command_flags_str(&pbuf, cmd->flags), cmd->target, cmd->command, cmd->arg, cmd->index);
+ }
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SendCmdContext *sendcmd = ctx->priv;
+ int i, j;
+
+ for (i = 0; i < sendcmd->nb_intervals; i++) {
+ Interval *interval = &sendcmd->intervals[i];
+ for (j = 0; j < interval->nb_commands; j++) {
+ Command *cmd = &interval->commands[j];
+ av_freep(&cmd->target);
+ av_freep(&cmd->command);
+ av_freep(&cmd->arg);
+ }
+ av_freep(&interval->commands);
+ }
+ av_freep(&sendcmd->intervals);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SendCmdContext *sendcmd = ctx->priv;
+ int64_t ts;
+ int i, j, ret;
+
+ if (ref->pts == AV_NOPTS_VALUE)
+ goto end;
+
+ ts = av_rescale_q(ref->pts, inlink->time_base, AV_TIME_BASE_Q);
+
+#define WITHIN_INTERVAL(ts, start_ts, end_ts) ((ts) >= (start_ts) && (ts) < (end_ts))
+
+ for (i = 0; i < sendcmd->nb_intervals; i++) {
+ Interval *interval = &sendcmd->intervals[i];
+ int flags = 0;
+
+ if (!interval->enabled && WITHIN_INTERVAL(ts, interval->start_ts, interval->end_ts)) {
+ flags += COMMAND_FLAG_ENTER;
+ interval->enabled = 1;
+ }
+ if (interval->enabled && !WITHIN_INTERVAL(ts, interval->start_ts, interval->end_ts)) {
+ flags += COMMAND_FLAG_LEAVE;
+ interval->enabled = 0;
+ }
+
+ if (flags) {
+ AVBPrint pbuf;
+ av_log(ctx, AV_LOG_VERBOSE,
+ "[%s] interval #%d start_ts:%f end_ts:%f ts:%f\n",
+ make_command_flags_str(&pbuf, flags), interval->index,
+ (double)interval->start_ts/1000000, (double)interval->end_ts/1000000,
+ (double)ts/1000000);
+
+ for (j = 0; flags && j < interval->nb_commands; j++) {
+ Command *cmd = &interval->commands[j];
+ char buf[1024];
+
+ if (cmd->flags & flags) {
+ 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,
+ cmd->target, cmd->command, cmd->arg,
+ buf, sizeof(buf),
+ AVFILTER_CMD_FLAG_ONE);
+ av_log(ctx, AV_LOG_VERBOSE,
+ "Command reply for command #%d: ret:%s res:%s\n",
+ cmd->index, av_err2str(ret), buf);
+ }
+ }
+ }
+ }
+
+end:
+ switch (inlink->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_AUDIO:
+ return ff_filter_frame(inlink->dst->outputs[0], ref);
+ }
+
+ return AVERROR(ENOSYS);
+}
+
+#if CONFIG_SENDCMD_FILTER
+
+#define sendcmd_options options
+AVFILTER_DEFINE_CLASS(sendcmd);
+
+static const AVFilterPad sendcmd_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad sendcmd_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_sendcmd = {
+ .name = "sendcmd",
+ .description = NULL_IF_CONFIG_SMALL("Send commands to filters."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(SendCmdContext),
+ .inputs = sendcmd_inputs,
+ .outputs = sendcmd_outputs,
+ .priv_class = &sendcmd_class,
+};
+
+#endif
+
+#if CONFIG_ASENDCMD_FILTER
+
+#define asendcmd_options options
+AVFILTER_DEFINE_CLASS(asendcmd);
+
+static const AVFilterPad asendcmd_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad asendcmd_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_asendcmd = {
+ .name = "asendcmd",
+ .description = NULL_IF_CONFIG_SMALL("Send commands to filters."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(SendCmdContext),
+ .inputs = asendcmd_inputs,
+ .outputs = asendcmd_outputs,
+ .priv_class = &asendcmd_class,
+};
+
+#endif
diff --git a/libavfilter/f_zmq.c b/libavfilter/f_zmq.c
new file mode 100644
index 0000000000..d6c3c65da4
--- /dev/null
+++ b/libavfilter/f_zmq.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * receive commands through libzeromq and broker them to filters
+ */
+
+#include <zmq.h>
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "avfiltergraph.h"
+#include "audio.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ void *zmq;
+ void *responder;
+ char *bind_address;
+ int command_count;
+} ZMQContext;
+
+#define OFFSET(x) offsetof(ZMQContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption options[] = {
+ { "bind_address", "set bind address", OFFSET(bind_address), AV_OPT_TYPE_STRING, {.str = "tcp://*:5555"}, 0, 0, FLAGS },
+ { "b", "set bind address", OFFSET(bind_address), AV_OPT_TYPE_STRING, {.str = "tcp://*:5555"}, 0, 0, FLAGS },
+ { NULL }
+};
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ZMQContext *zmq = ctx->priv;
+
+ zmq->zmq = zmq_ctx_new();
+ if (!zmq->zmq) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Could not create ZMQ context: %s\n", zmq_strerror(errno));
+ return AVERROR_EXTERNAL;
+ }
+
+ zmq->responder = zmq_socket(zmq->zmq, ZMQ_REP);
+ if (!zmq->responder) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Could not create ZMQ socket: %s\n", zmq_strerror(errno));
+ return AVERROR_EXTERNAL;
+ }
+
+ if (zmq_bind(zmq->responder, zmq->bind_address) == -1) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Could not bind ZMQ socket to address '%s': %s\n",
+ zmq->bind_address, zmq_strerror(errno));
+ return AVERROR_EXTERNAL;
+ }
+
+ zmq->command_count = -1;
+ return 0;
+}
+
+static void av_cold uninit(AVFilterContext *ctx)
+{
+ ZMQContext *zmq = ctx->priv;
+
+ zmq_close(zmq->responder);
+ zmq_ctx_destroy(zmq->zmq);
+}
+
+typedef struct {
+ char *target, *command, *arg;
+} Command;
+
+#define SPACES " \f\t\n\r"
+
+static int parse_command(Command *cmd, const char *command_str, void *log_ctx)
+{
+ const char **buf = &command_str;
+
+ cmd->target = av_get_token(buf, SPACES);
+ if (!cmd->target || !cmd->target[0]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "No target specified in command '%s'\n", command_str);
+ return AVERROR(EINVAL);
+ }
+
+ cmd->command = av_get_token(buf, SPACES);
+ if (!cmd->command || !cmd->command[0]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "No command specified in command '%s'\n", command_str);
+ return AVERROR(EINVAL);
+ }
+
+ cmd->arg = av_get_token(buf, SPACES);
+ return 0;
+}
+
+static int recv_msg(AVFilterContext *ctx, char **buf, int *buf_size)
+{
+ ZMQContext *zmq = ctx->priv;
+ zmq_msg_t msg;
+ int ret = 0;
+
+ if (zmq_msg_init(&msg) == -1) {
+ av_log(ctx, AV_LOG_WARNING,
+ "Could not initialize receive message: %s\n", zmq_strerror(errno));
+ return AVERROR_EXTERNAL;
+ }
+
+ if (zmq_msg_recv(&msg, zmq->responder, ZMQ_DONTWAIT) == -1) {
+ if (errno != EAGAIN)
+ av_log(ctx, AV_LOG_WARNING,
+ "Could not receive message: %s\n", zmq_strerror(errno));
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+
+ *buf_size = zmq_msg_size(&msg) + 1;
+ *buf = av_malloc(*buf_size);
+ if (!*buf) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ memcpy(*buf, zmq_msg_data(&msg), *buf_size);
+ (*buf)[*buf_size-1] = 0;
+
+end:
+ zmq_msg_close(&msg);
+ return ret;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ZMQContext *zmq = ctx->priv;
+
+ while (1) {
+ char cmd_buf[1024];
+ char *recv_buf, *send_buf;
+ int recv_buf_size;
+ Command cmd = {0};
+ int ret;
+
+ /* receive command */
+ if (recv_msg(ctx, &recv_buf, &recv_buf_size) < 0)
+ break;
+ zmq->command_count++;
+
+ /* parse command */
+ if (parse_command(&cmd, recv_buf, ctx) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Could not parse command #%d\n", zmq->command_count);
+ goto end;
+ }
+
+ /* process command */
+ 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,
+ cmd.target, cmd.command, cmd.arg,
+ cmd_buf, sizeof(cmd_buf),
+ AVFILTER_CMD_FLAG_ONE);
+ send_buf = av_asprintf("%d %s%s%s",
+ -ret, av_err2str(ret), cmd_buf[0] ? "\n" : "", cmd_buf);
+ if (!send_buf) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ av_log(ctx, AV_LOG_VERBOSE,
+ "Sending command reply for command #%d:\n%s\n",
+ zmq->command_count, send_buf);
+ if (zmq_send(zmq->responder, send_buf, strlen(send_buf), 0) == -1)
+ av_log(ctx, AV_LOG_ERROR, "Failed to send reply for command #%d: %s\n",
+ zmq->command_count, zmq_strerror(ret));
+
+ end:
+ av_freep(&send_buf);
+ av_freep(&recv_buf);
+ recv_buf_size = 0;
+ av_freep(&cmd.target);
+ av_freep(&cmd.command);
+ av_freep(&cmd.arg);
+ }
+
+ return ff_filter_frame(ctx->outputs[0], ref);
+}
+
+#if CONFIG_ZMQ_FILTER
+
+#define zmq_options options
+AVFILTER_DEFINE_CLASS(zmq);
+
+static const AVFilterPad zmq_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad zmq_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_zmq = {
+ .name = "zmq",
+ .description = NULL_IF_CONFIG_SMALL("Receive commands through ZMQ and broker them to filters."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(ZMQContext),
+ .inputs = zmq_inputs,
+ .outputs = zmq_outputs,
+ .priv_class = &zmq_class,
+};
+
+#endif
+
+#if CONFIG_AZMQ_FILTER
+
+#define azmq_options options
+AVFILTER_DEFINE_CLASS(azmq);
+
+static const AVFilterPad azmq_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad azmq_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_azmq = {
+ .name = "azmq",
+ .description = NULL_IF_CONFIG_SMALL("Receive commands through ZMQ and broker them to filters."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(ZMQContext),
+ .inputs = azmq_inputs,
+ .outputs = azmq_outputs,
+ .priv_class = &azmq_class,
+};
+
+#endif
diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c
index a414585ece..e477cff4cd 100644
--- a/libavfilter/fifo.c
+++ b/libavfilter/fifo.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -201,6 +201,7 @@ static int return_audio_frame(AVFilterContext *ctx)
break;
} else if (ret < 0)
return ret;
+ av_assert0(s->root.next); // If ff_request_frame() succeeded then we should have a frame
}
head = s->root.next->frame;
@@ -236,6 +237,7 @@ static int request_frame(AVFilterLink *outlink)
return return_audio_frame(outlink->src);
return ret;
}
+ av_assert0(fifo->root.next);
}
if (outlink->request_samples) {
@@ -252,7 +254,6 @@ static const AVFilterPad avfilter_vf_fifo_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
.filter_frame = add_to_queue,
},
{ NULL }
@@ -284,7 +285,6 @@ static const AVFilterPad avfilter_af_afifo_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
.filter_frame = add_to_queue,
},
{ NULL }
diff --git a/libavfilter/filtfmts.c b/libavfilter/filtfmts.c
index cc04654222..46a2d9447d 100644
--- a/libavfilter/filtfmts.c
+++ b/libavfilter/filtfmts.c
@@ -1,31 +1,72 @@
/*
* Copyright (c) 2009 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
+#include "libavutil/channel_layout.h"
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/samplefmt.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/formats.h"
+static void print_formats(AVFilterContext *filter_ctx)
+{
+ int i, j;
+
+#define PRINT_FMTS(inout, outin, INOUT) \
+ for (i = 0; i < filter_ctx->nb_##inout##puts; i++) { \
+ if (filter_ctx->inout##puts[i]->type == AVMEDIA_TYPE_VIDEO) { \
+ AVFilterFormats *fmts = \
+ filter_ctx->inout##puts[i]->outin##_formats; \
+ for (j = 0; j < fmts->nb_formats; j++) \
+ if(av_get_pix_fmt_name(fmts->formats[j])) \
+ printf(#INOUT "PUT[%d] %s: fmt:%s\n", \
+ i, avfilter_pad_get_name(filter_ctx->inout##put_pads, i), \
+ av_get_pix_fmt_name(fmts->formats[j])); \
+ } else if (filter_ctx->inout##puts[i]->type == AVMEDIA_TYPE_AUDIO) { \
+ AVFilterFormats *fmts; \
+ AVFilterChannelLayouts *layouts; \
+ \
+ fmts = filter_ctx->inout##puts[i]->outin##_formats; \
+ for (j = 0; j < fmts->nb_formats; j++) \
+ printf(#INOUT "PUT[%d] %s: fmt:%s\n", \
+ i, avfilter_pad_get_name(filter_ctx->inout##put_pads, i), \
+ av_get_sample_fmt_name(fmts->formats[j])); \
+ \
+ layouts = filter_ctx->inout##puts[i]->outin##_channel_layouts; \
+ for (j = 0; j < layouts->nb_channel_layouts; j++) { \
+ char buf[256]; \
+ av_get_channel_layout_string(buf, sizeof(buf), -1, \
+ layouts->channel_layouts[j]); \
+ printf(#INOUT "PUT[%d] %s: chlayout:%s\n", \
+ i, avfilter_pad_get_name(filter_ctx->inout##put_pads, i), buf); \
+ } \
+ } \
+ } \
+
+ PRINT_FMTS(in, out, IN);
+ PRINT_FMTS(out, in, OUT);
+}
+
int main(int argc, char **argv)
{
AVFilter *filter;
@@ -33,17 +74,18 @@ int main(int argc, char **argv)
AVFilterGraph *graph_ctx;
const char *filter_name;
const char *filter_args = NULL;
- int i, j, ret = 0;
+ int i;
+ int ret = 0;
av_log_set_level(AV_LOG_DEBUG);
- if (!argv[1]) {
+ if (argc < 2) {
fprintf(stderr, "Missing filter name as argument\n");
return 1;
}
filter_name = argv[1];
- if (argv[2])
+ if (argc > 2)
filter_args = argv[2];
/* allocate graph */
@@ -79,7 +121,7 @@ int main(int argc, char **argv)
ret = 1;
goto fail;
}
- link->type = avfilter_pad_get_type(filter_ctx->filter->inputs, i);
+ link->type = avfilter_pad_get_type(filter_ctx->input_pads, i);
filter_ctx->inputs[i] = link;
}
for (i = 0; i < filter_ctx->nb_outputs; i++) {
@@ -89,7 +131,7 @@ int main(int argc, char **argv)
ret = 1;
goto fail;
}
- link->type = avfilter_pad_get_type(filter_ctx->filter->outputs, i);
+ link->type = avfilter_pad_get_type(filter_ctx->output_pads, i);
filter_ctx->outputs[i] = link;
}
@@ -98,23 +140,7 @@ int main(int argc, char **argv)
else
ff_default_query_formats(filter_ctx);
- /* print the supported formats in input */
- for (i = 0; i < filter_ctx->nb_inputs; i++) {
- AVFilterFormats *fmts = filter_ctx->inputs[i]->out_formats;
- for (j = 0; j < fmts->nb_formats; j++)
- printf("INPUT[%d] %s: %s\n",
- i, avfilter_pad_get_name(filter_ctx->filter->inputs, i),
- av_get_pix_fmt_name(fmts->formats[j]));
- }
-
- /* print the supported formats in output */
- for (i = 0; i < filter_ctx->nb_outputs; i++) {
- AVFilterFormats *fmts = filter_ctx->outputs[i]->in_formats;
- for (j = 0; j < fmts->nb_formats; j++)
- printf("OUTPUT[%d] %s: %s\n",
- i, avfilter_pad_get_name(filter_ctx->filter->outputs, i),
- av_get_pix_fmt_name(fmts->formats[j]));
- }
+ print_formats(filter_ctx);
fail:
avfilter_free(filter_ctx);
diff --git a/libavfilter/formats.c b/libavfilter/formats.c
index 4b6b3aa3b7..4f9773bd15 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -2,29 +2,35 @@
* Filter layer - format negotiation
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/channel_layout.h"
#include "libavutil/common.h"
+#include "libavutil/eval.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/parseutils.h"
#include "avfilter.h"
#include "internal.h"
#include "formats.h"
+#define KNOWN(l) (!FF_LAYOUT2COUNT(l)) /* for readability */
+
/**
* Add all refs from a to ret and destroy a.
*/
@@ -33,8 +39,8 @@ do { \
type ***tmp; \
int i; \
\
- if (!(tmp = av_realloc(ret->refs, \
- sizeof(*tmp) * (ret->refcount + a->refcount)))) \
+ if (!(tmp = av_realloc_array(ret->refs, ret->refcount + a->refcount, \
+ sizeof(*tmp)))) \
goto fail; \
ret->refs = tmp; \
\
@@ -60,15 +66,21 @@ do {
goto fail; \
\
if (count) { \
- if (!(ret->fmts = av_malloc(sizeof(*ret->fmts) * count))) \
+ if (!(ret->fmts = av_malloc_array(count, sizeof(*ret->fmts)))) \
goto fail; \
for (i = 0; i < a->nb; i++) \
for (j = 0; j < b->nb; j++) \
- if (a->fmts[i] == b->fmts[j]) \
+ if (a->fmts[i] == b->fmts[j]) { \
+ if(k >= FFMIN(a->nb, b->nb)){ \
+ av_log(NULL, AV_LOG_ERROR, "Duplicate formats in avfilter_merge_formats() detected\n"); \
+ av_free(ret->fmts); \
+ av_free(ret); \
+ return NULL; \
+ } \
ret->fmts[k++] = a->fmts[i]; \
- \
- ret->nb = k; \
+ } \
} \
+ ret->nb = k; \
/* check that there was at least one common format */ \
if (!ret->nb) \
goto fail; \
@@ -77,13 +89,41 @@ do {
MERGE_REF(ret, b, fmts, type, fail); \
} while (0)
-AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b)
+AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b,
+ enum AVMediaType type)
{
AVFilterFormats *ret = NULL;
+ int i, j;
+ int alpha1=0, alpha2=0;
+ int chroma1=0, chroma2=0;
if (a == b)
return a;
+ /* Do not lose chroma or alpha in merging.
+ It happens if both lists have formats with chroma (resp. alpha), but
+ the only formats in common do not have it (e.g. YUV+gray vs.
+ RGB+gray): in that case, the merging would select the gray format,
+ possibly causing a lossy conversion elsewhere in the graph.
+ To avoid that, pretend that there are no common formats to force the
+ insertion of a conversion filter. */
+ if (type == AVMEDIA_TYPE_VIDEO)
+ for (i = 0; i < a->nb_formats; i++)
+ for (j = 0; j < b->nb_formats; j++) {
+ const AVPixFmtDescriptor *adesc = av_pix_fmt_desc_get(a->formats[i]);
+ const AVPixFmtDescriptor *bdesc = av_pix_fmt_desc_get(b->formats[j]);
+ alpha2 |= adesc->flags & bdesc->flags & AV_PIX_FMT_FLAG_ALPHA;
+ chroma2|= adesc->nb_components > 1 && bdesc->nb_components > 1;
+ if (a->formats[i] == b->formats[j]) {
+ alpha1 |= adesc->flags & AV_PIX_FMT_FLAG_ALPHA;
+ chroma1|= adesc->nb_components > 1;
+ }
+ }
+
+ // If chroma or alpha can be lost through merging then do not merge
+ if (alpha2 > alpha1 || chroma2 > chroma1)
+ return NULL;
+
MERGE_FORMATS(ret, a, b, formats, nb_formats, AVFilterFormats, fail);
return ret;
@@ -127,21 +167,81 @@ AVFilterChannelLayouts *ff_merge_channel_layouts(AVFilterChannelLayouts *a,
AVFilterChannelLayouts *b)
{
AVFilterChannelLayouts *ret = NULL;
+ unsigned a_all = a->all_layouts + a->all_counts;
+ unsigned b_all = b->all_layouts + b->all_counts;
+ int ret_max, ret_nb = 0, i, j, round;
if (a == b) return a;
- if (a->nb_channel_layouts && b->nb_channel_layouts) {
- MERGE_FORMATS(ret, a, b, channel_layouts, nb_channel_layouts,
- AVFilterChannelLayouts, fail);
- } else if (a->nb_channel_layouts) {
- MERGE_REF(a, b, channel_layouts, AVFilterChannelLayouts, fail);
- ret = a;
- } else {
+ /* Put the most generic set in a, to avoid doing everything twice */
+ if (a_all < b_all) {
+ FFSWAP(AVFilterChannelLayouts *, a, b);
+ FFSWAP(unsigned, a_all, b_all);
+ }
+ if (a_all) {
+ if (a_all == 1 && !b_all) {
+ /* keep only known layouts in b; works also for b_all = 1 */
+ for (i = j = 0; i < b->nb_channel_layouts; i++)
+ if (KNOWN(b->channel_layouts[i]))
+ b->channel_layouts[j++] = b->channel_layouts[i];
+ /* Not optimal: the unknown layouts of b may become known after
+ another merge. */
+ if (!j)
+ return NULL;
+ b->nb_channel_layouts = j;
+ }
MERGE_REF(b, a, channel_layouts, AVFilterChannelLayouts, fail);
- ret = b;
+ return b;
}
+ ret_max = a->nb_channel_layouts + b->nb_channel_layouts;
+ if (!(ret = av_mallocz(sizeof(*ret))) ||
+ !(ret->channel_layouts = av_malloc_array(ret_max,
+ sizeof(*ret->channel_layouts))))
+ goto fail;
+
+ /* a[known] intersect b[known] */
+ for (i = 0; i < a->nb_channel_layouts; i++) {
+ if (!KNOWN(a->channel_layouts[i]))
+ continue;
+ for (j = 0; j < b->nb_channel_layouts; j++) {
+ if (a->channel_layouts[i] == b->channel_layouts[j]) {
+ ret->channel_layouts[ret_nb++] = a->channel_layouts[i];
+ a->channel_layouts[i] = b->channel_layouts[j] = 0;
+ }
+ }
+ }
+ /* 1st round: a[known] intersect b[generic]
+ 2nd round: a[generic] intersect b[known] */
+ for (round = 0; round < 2; round++) {
+ for (i = 0; i < a->nb_channel_layouts; i++) {
+ uint64_t fmt = a->channel_layouts[i], bfmt;
+ if (!fmt || !KNOWN(fmt))
+ continue;
+ bfmt = FF_COUNT2LAYOUT(av_get_channel_layout_nb_channels(fmt));
+ for (j = 0; j < b->nb_channel_layouts; j++)
+ if (b->channel_layouts[j] == bfmt)
+ ret->channel_layouts[ret_nb++] = a->channel_layouts[i];
+ }
+ /* 1st round: swap to prepare 2nd round; 2nd round: put it back */
+ FFSWAP(AVFilterChannelLayouts *, a, b);
+ }
+ /* a[generic] intersect b[generic] */
+ for (i = 0; i < a->nb_channel_layouts; i++) {
+ if (KNOWN(a->channel_layouts[i]))
+ continue;
+ for (j = 0; j < b->nb_channel_layouts; j++)
+ if (a->channel_layouts[i] == b->channel_layouts[j])
+ ret->channel_layouts[ret_nb++] = a->channel_layouts[i];
+ }
+
+ ret->nb_channel_layouts = ret_nb;
+ if (!ret->nb_channel_layouts)
+ goto fail;
+ MERGE_REF(ret, a, channel_layouts, AVFilterChannelLayouts, fail);
+ MERGE_REF(ret, b, channel_layouts, AVFilterChannelLayouts, fail);
return ret;
+
fail:
if (ret) {
av_freep(&ret->refs);
@@ -155,33 +255,47 @@ int ff_fmt_is_in(int fmt, const int *fmts)
{
const int *p;
- for (p = fmts; *p != AV_PIX_FMT_NONE; p++) {
+ for (p = fmts; *p != -1; p++) {
if (fmt == *p)
return 1;
}
return 0;
}
+#define MAKE_FORMAT_LIST(type, field, count_field) \
+ type *formats; \
+ int count = 0; \
+ if (fmts) \
+ for (count = 0; fmts[count] != -1; count++) \
+ ; \
+ formats = av_mallocz(sizeof(*formats)); \
+ if (!formats) \
+ return NULL; \
+ formats->count_field = count; \
+ if (count) { \
+ formats->field = av_malloc_array(count, sizeof(*formats->field)); \
+ if (!formats->field) { \
+ av_freep(&formats); \
+ return NULL; \
+ } \
+ }
+
AVFilterFormats *ff_make_format_list(const int *fmts)
{
- AVFilterFormats *formats;
- int count;
+ MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
+ while (count--)
+ formats->formats[count] = fmts[count];
- for (count = 0; fmts[count] != -1; count++)
- ;
+ return formats;
+}
- formats = av_mallocz(sizeof(*formats));
- if (!formats)
- return NULL;
- if (count) {
- formats->formats = av_malloc(sizeof(*formats->formats) * count);
- if (!formats->formats) {
- av_freep(&formats);
- return NULL;
- }
- }
- formats->nb_formats = count;
- memcpy(formats->formats, fmts, sizeof(*formats->formats) * count);
+AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts)
+{
+ MAKE_FORMAT_LIST(AVFilterChannelLayouts,
+ channel_layouts, nb_channel_layouts);
+ if (count)
+ memcpy(formats->channel_layouts, fmts,
+ sizeof(*formats->channel_layouts) * count);
return formats;
}
@@ -189,30 +303,34 @@ AVFilterFormats *ff_make_format_list(const int *fmts)
#define ADD_FORMAT(f, fmt, type, list, nb) \
do { \
type *fmts; \
+ void *oldf = *f; \
\
if (!(*f) && !(*f = av_mallocz(sizeof(**f)))) \
return AVERROR(ENOMEM); \
\
- fmts = av_realloc((*f)->list, \
- sizeof(*(*f)->list) * ((*f)->nb + 1));\
+ fmts = av_realloc_array((*f)->list, (*f)->nb + 1, \
+ sizeof(*(*f)->list)); \
if (!fmts) { \
- av_freep(&f); \
+ if (!oldf) \
+ av_freep(f); \
return AVERROR(ENOMEM); \
} \
\
(*f)->list = fmts; \
(*f)->list[(*f)->nb++] = fmt; \
- return 0; \
} while (0)
-int ff_add_format(AVFilterFormats **avff, int fmt)
+int ff_add_format(AVFilterFormats **avff, int64_t fmt)
{
ADD_FORMAT(avff, fmt, int, formats, nb_formats);
+ return 0;
}
int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
{
+ av_assert1(!(*l && (*l)->all_layouts));
ADD_FORMAT(l, channel_layout, uint64_t, channel_layouts, nb_channel_layouts);
+ return 0;
}
AVFilterFormats *ff_all_formats(enum AVMediaType type)
@@ -236,12 +354,22 @@ AVFilterFormats *ff_all_formats(enum AVMediaType type)
return ret;
}
+const int64_t avfilter_all_channel_layouts[] = {
+#include "all_channel_layouts.inc"
+ -1
+};
+
+// AVFilterFormats *avfilter_make_all_channel_layouts(void)
+// {
+// return avfilter_make_format64_list(avfilter_all_channel_layouts);
+// }
+
AVFilterFormats *ff_planar_sample_fmts(void)
{
AVFilterFormats *ret = NULL;
int fmt;
- for (fmt = 0; fmt < AV_SAMPLE_FMT_NB; fmt++)
+ for (fmt = 0; av_get_bytes_per_sample(fmt)>0; fmt++)
if (av_sample_fmt_is_planar(fmt))
ff_add_format(&ret, fmt);
@@ -257,24 +385,41 @@ AVFilterFormats *ff_all_samplerates(void)
AVFilterChannelLayouts *ff_all_channel_layouts(void)
{
AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
+ if (!ret)
+ return NULL;
+ ret->all_layouts = 1;
return ret;
}
-#define FORMATS_REF(f, ref) \
-do { \
- *ref = f; \
- f->refs = av_realloc(f->refs, sizeof(*f->refs) * ++f->refcount); \
- if (!f->refs) \
- return; \
- f->refs[f->refcount-1] = ref; \
-} while (0)
+AVFilterChannelLayouts *ff_all_channel_counts(void)
+{
+ AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
+ if (!ret)
+ return NULL;
+ ret->all_layouts = ret->all_counts = 1;
+ return ret;
+}
-void ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
+#define FORMATS_REF(f, ref) \
+ void *tmp; \
+ \
+ if (!ref) \
+ return AVERROR_BUG; \
+ \
+ tmp = av_realloc_array(f->refs, sizeof(*f->refs), f->refcount + 1); \
+ if (!tmp) \
+ return AVERROR(ENOMEM); \
+ f->refs = tmp; \
+ f->refs[f->refcount++] = ref; \
+ *ref = f; \
+ return 0
+
+int ff_channel_layouts_ref(AVFilterChannelLayouts *f, AVFilterChannelLayouts **ref)
{
FORMATS_REF(f, ref);
}
-void ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
+int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
{
FORMATS_REF(f, ref);
}
@@ -345,18 +490,24 @@ void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref)
}
#define SET_COMMON_FORMATS(ctx, fmts, in_fmts, out_fmts, ref, list) \
-{ \
int count = 0, i; \
\
+ if (!fmts) \
+ return AVERROR_BUG; \
+ \
for (i = 0; i < ctx->nb_inputs; i++) { \
- if (ctx->inputs[i]) { \
- ref(fmts, &ctx->inputs[i]->out_fmts); \
+ if (ctx->inputs[i] && !ctx->inputs[i]->out_fmts) { \
+ int ret = ref(fmts, &ctx->inputs[i]->out_fmts); \
+ if (ret < 0) \
+ return ret; \
count++; \
} \
} \
for (i = 0; i < ctx->nb_outputs; i++) { \
- if (ctx->outputs[i]) { \
- ref(fmts, &ctx->outputs[i]->in_fmts); \
+ if (ctx->outputs[i] && !ctx->outputs[i]->in_fmts) { \
+ int ret = ref(fmts, &ctx->outputs[i]->in_fmts); \
+ if (ret < 0) \
+ return ret; \
count++; \
} \
} \
@@ -366,17 +517,18 @@ void ff_formats_changeref(AVFilterFormats **oldref, AVFilterFormats **newref)
av_freep(&fmts->refs); \
av_freep(&fmts); \
} \
-}
+ \
+ return 0;
-void ff_set_common_channel_layouts(AVFilterContext *ctx,
- AVFilterChannelLayouts *layouts)
+int ff_set_common_channel_layouts(AVFilterContext *ctx,
+ AVFilterChannelLayouts *layouts)
{
SET_COMMON_FORMATS(ctx, layouts, in_channel_layouts, out_channel_layouts,
ff_channel_layouts_ref, channel_layouts);
}
-void ff_set_common_samplerates(AVFilterContext *ctx,
- AVFilterFormats *samplerates)
+int ff_set_common_samplerates(AVFilterContext *ctx,
+ AVFilterFormats *samplerates)
{
SET_COMMON_FORMATS(ctx, samplerates, in_samplerates, out_samplerates,
ff_formats_ref, formats);
@@ -387,23 +539,144 @@ void ff_set_common_samplerates(AVFilterContext *ctx,
* formats. If there are no links hooked to this filter, the list of formats is
* freed.
*/
-void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
+int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{
SET_COMMON_FORMATS(ctx, formats, in_formats, out_formats,
ff_formats_ref, formats);
}
-int ff_default_query_formats(AVFilterContext *ctx)
+static int default_query_formats_common(AVFilterContext *ctx,
+ AVFilterChannelLayouts *(layouts)(void))
{
+ int ret;
enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :
ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
AVMEDIA_TYPE_VIDEO;
- ff_set_common_formats(ctx, ff_all_formats(type));
+ ret = ff_set_common_formats(ctx, ff_all_formats(type));
+ if (ret < 0)
+ return ret;
if (type == AVMEDIA_TYPE_AUDIO) {
- ff_set_common_channel_layouts(ctx, ff_all_channel_layouts());
- ff_set_common_samplerates(ctx, ff_all_samplerates());
+ ret = ff_set_common_channel_layouts(ctx, layouts());
+ if (ret < 0)
+ return ret;
+ ret = ff_set_common_samplerates(ctx, ff_all_samplerates());
+ if (ret < 0)
+ return ret;
}
return 0;
}
+
+int ff_default_query_formats(AVFilterContext *ctx)
+{
+ return default_query_formats_common(ctx, ff_all_channel_layouts);
+}
+
+int ff_query_formats_all(AVFilterContext *ctx)
+{
+ return default_query_formats_common(ctx, ff_all_channel_counts);
+}
+
+/* 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_format(int *ret, const char *arg, void *log_ctx)
+{
+ char *tail;
+ int sfmt = av_get_sample_fmt(arg);
+ if (sfmt == AV_SAMPLE_FMT_NONE) {
+ sfmt = strtol(arg, &tail, 0);
+ if (*tail || av_get_bytes_per_sample(sfmt)<=0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid sample format '%s'\n", arg);
+ return AVERROR(EINVAL);
+ }
+ }
+ *ret = sfmt;
+ return 0;
+}
+
+int ff_parse_time_base(AVRational *ret, const char *arg, void *log_ctx)
+{
+ AVRational r;
+ if(av_parse_ratio(&r, arg, INT_MAX, 0, log_ctx) < 0 ||r.num<=0 ||r.den<=0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid time base '%s'\n", arg);
+ return AVERROR(EINVAL);
+ }
+ *ret = r;
+ 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(int64_t *ret, int *nret, const char *arg,
+ void *log_ctx)
+{
+ char *tail;
+ int64_t chlayout, count;
+
+ if (nret) {
+ count = strtol(arg, &tail, 10);
+ if (*tail == 'c' && !tail[1] && count > 0 && count < 63) {
+ *nret = count;
+ *ret = 0;
+ return 0;
+ }
+ }
+ chlayout = av_get_channel_layout(arg);
+ if (chlayout == 0) {
+ chlayout = strtol(arg, &tail, 10);
+ if (*tail || chlayout == 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg);
+ return AVERROR(EINVAL);
+ }
+ }
+ *ret = chlayout;
+ if (nret)
+ *nret = av_get_channel_layout_nb_channels(chlayout);
+ return 0;
+}
+
+#ifdef TEST
+
+#undef printf
+
+int main(void)
+{
+ const int64_t *cl;
+ char buf[512];
+
+ for (cl = avfilter_all_channel_layouts; *cl != -1; cl++) {
+ av_get_channel_layout_string(buf, sizeof(buf), -1, *cl);
+ printf("%s\n", buf);
+ }
+
+ return 0;
+}
+
+#endif
+
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index 2e44792f3c..5a8ee5ed2f 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,15 +69,46 @@ struct AVFilterFormats {
struct AVFilterFormats ***refs; ///< references to this list
};
+/**
+ * A list of supported channel layouts.
+ *
+ * The list works the same as AVFilterFormats, except for the following
+ * differences:
+ * - A list with all_layouts = 1 means all channel layouts with a known
+ * disposition; nb_channel_layouts must then be 0.
+ * - A list with all_counts = 1 means all channel counts, with a known or
+ * unknown disposition; nb_channel_layouts must then be 0 and all_layouts 1.
+ * - The list must not contain a layout with a known disposition and a
+ * channel count with unknown disposition with the same number of channels
+ * (e.g. AV_CH_LAYOUT_STEREO and FF_COUNT2LAYOUT(2).
+ */
typedef struct AVFilterChannelLayouts {
uint64_t *channel_layouts; ///< list of channel layouts
int nb_channel_layouts; ///< number of channel layouts
+ char all_layouts; ///< accept any known channel layout
+ char all_counts; ///< accept any channel layout or count
unsigned refcount; ///< number of references to this list
struct AVFilterChannelLayouts ***refs; ///< references to this list
} AVFilterChannelLayouts;
/**
+ * Encode a channel count as a channel layout.
+ * FF_COUNT2LAYOUT(c) means any channel layout with c channels, with a known
+ * or unknown disposition.
+ * The result is only valid inside AVFilterChannelLayouts and immediately
+ * related functions.
+ */
+#define FF_COUNT2LAYOUT(c) (0x8000000000000000ULL | (c))
+
+/**
+ * Decode a channel count encoded as a channel layout.
+ * Return 0 if the channel layout was a real one.
+ */
+#define FF_LAYOUT2COUNT(l) (((l) & 0x8000000000000000ULL) ? \
+ (int)((l) & 0x7FFFFFFF) : 0)
+
+/**
* Return a channel layouts/samplerates list which contains the intersection of
* the layouts/samplerates of a and b. Also, all the references of a, all the
* references of b, and a and b themselves will be deallocated.
@@ -92,35 +123,44 @@ AVFilterFormats *ff_merge_samplerates(AVFilterFormats *a,
/**
* Construct an empty AVFilterChannelLayouts/AVFilterFormats struct --
- * representing any channel layout/sample rate.
+ * representing any channel layout (with known disposition)/sample rate.
*/
AVFilterChannelLayouts *ff_all_channel_layouts(void);
AVFilterFormats *ff_all_samplerates(void);
/**
+ * Construct an AVFilterChannelLayouts coding for any channel layout, with
+ * known or unknown disposition.
+ */
+AVFilterChannelLayouts *ff_all_channel_counts(void);
+
+AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts);
+
+
+/**
* A helper for query_formats() which sets all links to the same list of channel
* layouts/sample rates. If there are no links hooked to this filter, the list
* is freed.
*/
-void ff_set_common_channel_layouts(AVFilterContext *ctx,
- AVFilterChannelLayouts *layouts);
-void ff_set_common_samplerates(AVFilterContext *ctx,
- AVFilterFormats *samplerates);
+int ff_set_common_channel_layouts(AVFilterContext *ctx,
+ AVFilterChannelLayouts *layouts);
+int ff_set_common_samplerates(AVFilterContext *ctx,
+ AVFilterFormats *samplerates);
/**
* A helper for query_formats() which sets all links to the same list of
* formats. If there are no links hooked to this filter, the list of formats is
* freed.
*/
-void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
+int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
/**
* Add *ref as a new reference to f.
*/
-void ff_channel_layouts_ref(AVFilterChannelLayouts *f,
- AVFilterChannelLayouts **ref);
+int ff_channel_layouts_ref(AVFilterChannelLayouts *f,
+ AVFilterChannelLayouts **ref);
/**
* Remove a reference to a channel layouts list.
@@ -132,6 +172,14 @@ void ff_channel_layouts_changeref(AVFilterChannelLayouts **oldref,
int ff_default_query_formats(AVFilterContext *ctx);
+/**
+ * Set the formats list to all existing formats.
+ * This function behaves like ff_default_query_formats(), except it also
+ * accepts channel layouts with unknown disposition. It should only be used
+ * with audio filters.
+ */
+int ff_query_formats_all(AVFilterContext *ctx);
+
/**
* Create a list of supported formats. This is intended for use in
@@ -150,10 +198,10 @@ AVFilterFormats *ff_make_format_list(const int *fmts);
* @return a non negative value in case of success, or a negative
* value corresponding to an AVERROR code in case of error
*/
-int ff_add_format(AVFilterFormats **avff, int fmt);
+int ff_add_format(AVFilterFormats **avff, int64_t fmt);
/**
- * Return a list of all formats supported by Libav for the given media type.
+ * Return a list of all formats supported by FFmpeg for the given media type.
*/
AVFilterFormats *ff_all_formats(enum AVMediaType type);
@@ -170,7 +218,8 @@ AVFilterFormats *ff_planar_sample_fmts(void);
* If a and b do not share any common formats, neither is modified, and NULL
* is returned.
*/
-AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b);
+AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b,
+ enum AVMediaType type);
/**
* Add *ref as a new reference to formats.
@@ -184,7 +233,7 @@ AVFilterFormats *ff_merge_formats(AVFilterFormats *a, AVFilterFormats *b);
* | |____| | | |____|
* |________| |________________________
*/
-void ff_formats_ref(AVFilterFormats *formats, AVFilterFormats **ref);
+int ff_formats_ref(AVFilterFormats *formats, AVFilterFormats **ref);
/**
* If *ref is non-NULL, remove *ref as a reference to the format list
diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c
new file mode 100644
index 0000000000..12db50cb77
--- /dev/null
+++ b/libavfilter/framesync.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2013 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "avfilter.h"
+#include "bufferqueue.h"
+#include "framesync.h"
+#include "internal.h"
+
+#define OFFSET(member) offsetof(FFFrameSync, member)
+
+static const char *framesync_name(void *ptr)
+{
+ return "framesync";
+}
+
+static const AVClass framesync_class = {
+ .version = LIBAVUTIL_VERSION_INT,
+ .class_name = "framesync",
+ .item_name = framesync_name,
+ .category = AV_CLASS_CATEGORY_FILTER,
+ .option = NULL,
+ .parent_log_context_offset = OFFSET(parent),
+};
+
+enum {
+ STATE_BOF,
+ STATE_RUN,
+ STATE_EOF,
+};
+
+void ff_framesync_init(FFFrameSync *fs, void *parent, unsigned nb_in)
+{
+ fs->class = &framesync_class;
+ fs->parent = parent;
+ fs->nb_in = nb_in;
+}
+
+static void framesync_sync_level_update(FFFrameSync *fs)
+{
+ unsigned i, level = 0;
+
+ for (i = 0; i < fs->nb_in; i++)
+ if (fs->in[i].state != STATE_EOF)
+ level = FFMAX(level, fs->in[i].sync);
+ av_assert0(level <= fs->sync_level);
+ if (level < fs->sync_level)
+ av_log(fs, AV_LOG_VERBOSE, "Sync level %u\n", level);
+ if (level)
+ fs->sync_level = level;
+ else
+ fs->eof = 1;
+}
+
+int ff_framesync_configure(FFFrameSync *fs)
+{
+ unsigned i;
+ int64_t gcd, lcm;
+
+ if (!fs->time_base.num) {
+ for (i = 0; i < fs->nb_in; i++) {
+ if (fs->in[i].sync) {
+ if (fs->time_base.num) {
+ gcd = av_gcd(fs->time_base.den, fs->in[i].time_base.den);
+ lcm = (fs->time_base.den / gcd) * fs->in[i].time_base.den;
+ if (lcm < AV_TIME_BASE / 2) {
+ fs->time_base.den = lcm;
+ fs->time_base.num = av_gcd(fs->time_base.num,
+ fs->in[i].time_base.num);
+ } else {
+ fs->time_base.num = 1;
+ fs->time_base.den = AV_TIME_BASE;
+ break;
+ }
+ } else {
+ fs->time_base = fs->in[i].time_base;
+ }
+ }
+ }
+ if (!fs->time_base.num) {
+ av_log(fs, AV_LOG_ERROR, "Impossible to set time base\n");
+ return AVERROR(EINVAL);
+ }
+ av_log(fs, AV_LOG_VERBOSE, "Selected %d/%d time base\n",
+ fs->time_base.num, fs->time_base.den);
+ }
+
+ 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);
+
+ return 0;
+}
+
+static void framesync_advance(FFFrameSync *fs)
+{
+ int latest;
+ unsigned i;
+ int64_t pts;
+
+ if (fs->eof)
+ return;
+ while (!fs->frame_ready) {
+ latest = -1;
+ for (i = 0; i < fs->nb_in; i++) {
+ if (!fs->in[i].have_next) {
+ if (latest < 0 || fs->in[i].pts < fs->in[latest].pts)
+ latest = i;
+ }
+ }
+ if (latest >= 0) {
+ fs->in_request = latest;
+ break;
+ }
+
+ pts = fs->in[0].pts_next;
+ for (i = 1; i < fs->nb_in; i++)
+ if (fs->in[i].pts_next < pts)
+ pts = fs->in[i].pts_next;
+ if (pts == INT64_MAX) {
+ fs->eof = 1;
+ break;
+ }
+ for (i = 0; i < fs->nb_in; i++) {
+ if (fs->in[i].pts_next == pts ||
+ (fs->in[i].before == EXT_INFINITY &&
+ fs->in[i].state == STATE_BOF)) {
+ av_frame_free(&fs->in[i].frame);
+ fs->in[i].frame = fs->in[i].frame_next;
+ fs->in[i].pts = fs->in[i].pts_next;
+ fs->in[i].frame_next = NULL;
+ fs->in[i].pts_next = AV_NOPTS_VALUE;
+ fs->in[i].have_next = 0;
+ fs->in[i].state = fs->in[i].frame ? STATE_RUN : STATE_EOF;
+ if (fs->in[i].sync == fs->sync_level && fs->in[i].frame)
+ fs->frame_ready = 1;
+ if (fs->in[i].state == STATE_EOF &&
+ fs->in[i].after == EXT_STOP)
+ fs->eof = 1;
+ }
+ }
+ if (fs->eof)
+ fs->frame_ready = 0;
+ if (fs->frame_ready)
+ for (i = 0; i < fs->nb_in; i++)
+ if ((fs->in[i].state == STATE_BOF &&
+ fs->in[i].before == EXT_STOP))
+ fs->frame_ready = 0;
+ fs->pts = pts;
+ }
+}
+
+static int64_t framesync_pts_extrapolate(FFFrameSync *fs, unsigned in,
+ int64_t pts)
+{
+ /* Possible enhancement: use the link's frame rate */
+ return pts + 1;
+}
+
+static void framesync_inject_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
+{
+ int64_t pts;
+
+ av_assert0(!fs->in[in].have_next);
+ if (frame) {
+ pts = av_rescale_q(frame->pts, fs->in[in].time_base, fs->time_base);
+ frame->pts = pts;
+ } else {
+ 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);
+ }
+ fs->in[in].frame_next = frame;
+ fs->in[in].pts_next = pts;
+ fs->in[in].have_next = 1;
+}
+
+int ff_framesync_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame)
+{
+ av_assert1(in < fs->nb_in);
+ if (!fs->in[in].have_next)
+ framesync_inject_frame(fs, in, frame);
+ else
+ ff_bufqueue_add(fs, &fs->in[in].queue, frame);
+ return 0;
+}
+
+void ff_framesync_next(FFFrameSync *fs)
+{
+ unsigned i;
+
+ av_assert0(!fs->frame_ready);
+ for (i = 0; i < fs->nb_in; i++)
+ if (!fs->in[i].have_next && fs->in[i].queue.available)
+ framesync_inject_frame(fs, i, ff_bufqueue_get(&fs->in[i].queue));
+ fs->frame_ready = 0;
+ framesync_advance(fs);
+}
+
+void ff_framesync_drop(FFFrameSync *fs)
+{
+ fs->frame_ready = 0;
+}
+
+int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
+ unsigned get)
+{
+ AVFrame *frame;
+ unsigned need_copy = 0, i;
+ int64_t pts_next;
+ int ret;
+
+ if (!fs->in[in].frame) {
+ *rframe = NULL;
+ return 0;
+ }
+ frame = fs->in[in].frame;
+ if (get) {
+ /* Find out if we need to copy the frame: is there another sync
+ stream, and do we know if its current frame will outlast this one? */
+ pts_next = fs->in[in].have_next ? fs->in[in].pts_next : INT64_MAX;
+ for (i = 0; i < fs->nb_in && !need_copy; i++)
+ if (i != in && fs->in[i].sync &&
+ (!fs->in[i].have_next || fs->in[i].pts_next < pts_next))
+ need_copy = 1;
+ if (need_copy) {
+ if (!(frame = av_frame_clone(frame)))
+ return AVERROR(ENOMEM);
+ if ((ret = av_frame_make_writable(frame)) < 0) {
+ av_frame_free(&frame);
+ return ret;
+ }
+ } else {
+ fs->in[in].frame = NULL;
+ }
+ fs->frame_ready = 0;
+ }
+ *rframe = frame;
+ return 0;
+}
+
+void ff_framesync_uninit(FFFrameSync *fs)
+{
+ unsigned i;
+
+ for (i = 0; i < fs->nb_in; i++) {
+ av_frame_free(&fs->in[i].frame);
+ av_frame_free(&fs->in[i].frame_next);
+ ff_bufqueue_discard_all(&fs->in[i].queue);
+ }
+}
+
+int ff_framesync_process_frame(FFFrameSync *fs, unsigned all)
+{
+ int ret, count = 0;
+
+ av_assert0(fs->on_event);
+ while (1) {
+ ff_framesync_next(fs);
+ if (fs->eof || !fs->frame_ready)
+ break;
+ if ((ret = fs->on_event(fs)) < 0)
+ return ret;
+ ff_framesync_drop(fs);
+ count++;
+ if (!all)
+ break;
+ }
+ if (!count && fs->eof)
+ return AVERROR_EOF;
+ return count;
+}
+
+int ff_framesync_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
+ AVFrame *in)
+{
+ int ret;
+
+ if ((ret = ff_framesync_process_frame(fs, 1)) < 0)
+ return ret;
+ if ((ret = ff_framesync_add_frame(fs, FF_INLINK_IDX(inlink), in)) < 0)
+ return ret;
+ if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
+ return ret;
+ return 0;
+}
+
+int ff_framesync_request_frame(FFFrameSync *fs, AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ int input, ret;
+
+ if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
+ return ret;
+ if (ret > 0)
+ return 0;
+ if (fs->eof)
+ return AVERROR_EOF;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ input = fs->in_request;
+ ret = ff_request_frame(ctx->inputs[input]);
+ if (ret == AVERROR_EOF) {
+ if ((ret = ff_framesync_add_frame(fs, input, NULL)) < 0)
+ return ret;
+ if ((ret = ff_framesync_process_frame(fs, 0)) < 0)
+ return ret;
+ ret = 0;
+ }
+ return ret;
+}
diff --git a/libavfilter/framesync.h b/libavfilter/framesync.h
new file mode 100644
index 0000000000..2072781054
--- /dev/null
+++ b/libavfilter/framesync.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2013 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_FRAMESYNC_H
+#define AVFILTER_FRAMESYNC_H
+
+#include "bufferqueue.h"
+
+/*
+ * TODO
+ * Callback-based API similar to dualinput.
+ * Export convenient options.
+ */
+
+/**
+ * This API is intended as a helper for filters that have several video
+ * input and need to combine them somehow. If the inputs have different or
+ * variable frame rate, getting the input frames to match requires a rather
+ * complex logic and a few user-tunable options.
+ *
+ * In this API, when a set of synchronized input frames is ready to be
+ * procesed is called a frame event. Frame event can be generated in
+ * response to input frames on any or all inputs and the handling of
+ * situations where some stream extend beyond the beginning or the end of
+ * others can be configured.
+ *
+ * The basic working of this API is the following:
+ *
+ * - When a frame is available on any input, add it using
+ * ff_framesync_add_frame().
+ *
+ * - When a frame event is ready to be processed (i.e. after adding a frame
+ * or when requested on input):
+ * - call ff_framesync_next();
+ * - if fs->frame_ready is true, process the frames;
+ * - call ff_framesync_drop().
+ */
+
+/**
+ * Stream extrapolation mode
+ *
+ * Describe how the frames of a stream are extrapolated before the first one
+ * and after EOF to keep sync with possibly longer other streams.
+ */
+enum FFFrameSyncExtMode {
+
+ /**
+ * Completely stop all streams with this one.
+ */
+ EXT_STOP,
+
+ /**
+ * Ignore this stream and continue processing the other ones.
+ */
+ EXT_NULL,
+
+ /**
+ * Extend the frame to infinity.
+ */
+ EXT_INFINITY,
+};
+
+/**
+ * Input stream structure
+ */
+typedef struct FFFrameSyncIn {
+
+ /**
+ * Queue of incoming AVFrame, and NULL to mark EOF
+ */
+ struct FFBufQueue queue;
+
+ /**
+ * Extrapolation mode for timestamps before the first frame
+ */
+ enum FFFrameSyncExtMode before;
+
+ /**
+ * Extrapolation mode for timestamps after the last frame
+ */
+ enum FFFrameSyncExtMode after;
+
+ /**
+ * Time base for the incoming frames
+ */
+ AVRational time_base;
+
+ /**
+ * Current frame, may be NULL before the first one or after EOF
+ */
+ AVFrame *frame;
+
+ /**
+ * Next frame, for internal use
+ */
+ AVFrame *frame_next;
+
+ /**
+ * PTS of the current frame
+ */
+ int64_t pts;
+
+ /**
+ * PTS of the next frame, for internal use
+ */
+ int64_t pts_next;
+
+ /**
+ * Boolean flagging the next frame, for internal use
+ */
+ uint8_t have_next;
+
+ /**
+ * State: before first, in stream or after EOF, for internal use
+ */
+ uint8_t state;
+
+ /**
+ * Synchronization level: frames on input at the highest sync level will
+ * generate output frame events.
+ *
+ * For example, if inputs #0 and #1 have sync level 2 and input #2 has
+ * sync level 1, then a frame on either input #0 or #1 will generate a
+ * frame event, but not a frame on input #2 until both inputs #0 and #1
+ * have reached EOF.
+ *
+ * If sync is 0, no frame event will be generated.
+ */
+ unsigned sync;
+
+} FFFrameSyncIn;
+
+/**
+ * Frame sync structure.
+ */
+typedef struct FFFrameSync {
+ const AVClass *class;
+ void *parent;
+
+ /**
+ * Number of input streams
+ */
+ unsigned nb_in;
+
+ /**
+ * Time base for the output events
+ */
+ AVRational time_base;
+
+ /**
+ * Timestamp of the current event
+ */
+ int64_t pts;
+
+ /**
+ * Callback called when a frame event is ready
+ */
+ int (*on_event)(struct FFFrameSync *fs);
+
+ /**
+ * Opaque pointer, not used by the API
+ */
+ void *opaque;
+
+ /**
+ * Index of the input that requires a request
+ */
+ unsigned in_request;
+
+ /**
+ * Synchronization level: only inputs with the same sync level are sync
+ * sources.
+ */
+ unsigned sync_level;
+
+ /**
+ * Flag indicating that a frame event is ready
+ */
+ uint8_t frame_ready;
+
+ /**
+ * Flag indicating that output has reached EOF.
+ */
+ uint8_t eof;
+
+ /**
+ * Array of inputs; all inputs must be in consecutive memory
+ */
+ FFFrameSyncIn in[1]; /* must be the last field */
+
+} FFFrameSync;
+
+/**
+ * Initialize a frame sync structure.
+ *
+ * The entire structure is expected to be already set to 0.
+ *
+ * @param fs frame sync structure to initialize
+ * @param parent parent object, used for logging
+ * @param nb_in number of inputs
+ */
+void ff_framesync_init(FFFrameSync *fs, void *parent, unsigned nb_in);
+
+/**
+ * Configure a frame sync structure.
+ *
+ * Must be called after all options are set but before all use.
+ *
+ * @return >= 0 for success or a negative error code
+ */
+int ff_framesync_configure(FFFrameSync *fs);
+
+/**
+ * Free all memory currently allocated.
+ */
+void ff_framesync_uninit(FFFrameSync *fs);
+
+/**
+ * Add a frame to an input
+ *
+ * Typically called from the filter_frame() method.
+ *
+ * @param fs frame sync structure
+ * @param in index of the input
+ * @param frame input frame, or NULL for EOF
+ */
+int ff_framesync_add_frame(FFFrameSync *fs, unsigned in, AVFrame *frame);
+
+/**
+ * Prepare the next frame event.
+ *
+ * The status of the operation can be found in fs->frame_ready and fs->eof.
+ */
+void ff_framesync_next(FFFrameSync *fs);
+
+/**
+ * Drop the current frame event.
+ */
+void ff_framesync_drop(FFFrameSync *fs);
+
+/**
+ * Get the current frame in an input.
+ *
+ * @param fs frame sync structure
+ * @param in index of the input
+ * @param rframe used to return the current frame (or NULL)
+ * @param get if not zero, the calling code needs to get ownership of
+ * the returned frame; the current frame will either be
+ * duplicated or removed from the framesync structure
+ */
+int ff_framesync_get_frame(FFFrameSync *fs, unsigned in, AVFrame **rframe,
+ unsigned get);
+
+/**
+ * Process one or several frame using the on_event callback.
+ *
+ * @return number of frames processed or negative error code
+ */
+int ff_framesync_process_frame(FFFrameSync *fs, unsigned all);
+
+
+/**
+ * Accept a frame on a filter input.
+ *
+ * This function can be the complete implementation of all filter_frame
+ * methods of a filter using framesync.
+ */
+int ff_framesync_filter_frame(FFFrameSync *fs, AVFilterLink *inlink,
+ AVFrame *in);
+
+/**
+ * Request a frame on the filter output.
+ *
+ * This function can be the complete implementation of all filter_frame
+ * methods of a filter using framesync if it has only one output.
+ */
+int ff_framesync_request_frame(FFFrameSync *fs, AVFilterLink *outlink);
+
+#endif /* AVFILTER_FRAMESYNC_H */
diff --git a/libavfilter/generate_wave_table.c b/libavfilter/generate_wave_table.c
new file mode 100644
index 0000000000..bee9c0098a
--- /dev/null
+++ b/libavfilter/generate_wave_table.c
@@ -0,0 +1,84 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+#include "libavutil/avassert.h"
+#include "avfilter.h"
+#include "generate_wave_table.h"
+
+void ff_generate_wave_table(enum WaveType wave_type,
+ enum AVSampleFormat sample_fmt,
+ void *table, int table_size,
+ double min, double max, double phase)
+{
+ uint32_t i, phase_offset = phase / M_PI / 2 * table_size + 0.5;
+
+ for (i = 0; i < table_size; i++) {
+ uint32_t point = (i + phase_offset) % table_size;
+ double d;
+
+ switch (wave_type) {
+ case WAVE_SIN:
+ d = (sin((double)point / table_size * 2 * M_PI) + 1) / 2;
+ break;
+ case WAVE_TRI:
+ d = (double)point * 2 / table_size;
+ switch (4 * point / table_size) {
+ case 0: d = d + 0.5; break;
+ case 1:
+ case 2: d = 1.5 - d; break;
+ case 3: d = d - 1.5; break;
+ }
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ d = d * (max - min) + min;
+ switch (sample_fmt) {
+ case AV_SAMPLE_FMT_FLT: {
+ float *fp = (float *)table;
+ *fp++ = (float)d;
+ table = fp;
+ continue; }
+ case AV_SAMPLE_FMT_DBL: {
+ double *dp = (double *)table;
+ *dp++ = d;
+ table = dp;
+ continue; }
+ }
+
+ d += d < 0 ? -0.5 : 0.5;
+ switch (sample_fmt) {
+ case AV_SAMPLE_FMT_S16: {
+ int16_t *sp = table;
+ *sp++ = (int16_t)d;
+ table = sp;
+ continue; }
+ case AV_SAMPLE_FMT_S32: {
+ int32_t *ip = table;
+ *ip++ = (int32_t)d;
+ table = ip;
+ continue; }
+ default:
+ av_assert0(0);
+ }
+ }
+}
+
+
diff --git a/libavfilter/generate_wave_table.h b/libavfilter/generate_wave_table.h
new file mode 100644
index 0000000000..5fe297e94d
--- /dev/null
+++ b/libavfilter/generate_wave_table.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_GENERATE_WAVE_TABLE_H
+#define AVFILTER_GENERATE_WAVE_TABLE_H
+
+#include "libavutil/samplefmt.h"
+
+enum WaveType {
+ WAVE_SIN,
+ WAVE_TRI,
+ WAVE_NB,
+};
+
+void ff_generate_wave_table(enum WaveType wave_type,
+ enum AVSampleFormat sample_fmt,
+ void *table, int table_size,
+ double min, double max, double phase);
+
+#endif /* AVFILTER_GENERATE_WAVE_TABLE_H */
diff --git a/libavfilter/gradfun.h b/libavfilter/gradfun.h
index f6f7311d1d..eb1f1eb090 100644
--- a/libavfilter/gradfun.h
+++ b/libavfilter/gradfun.h
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Nolan Lum <nol888@gmail.com>
* Copyright (c) 2009 Loren Merritt <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,13 +35,13 @@ typedef struct GradFunContext {
int chroma_r; ///< blur radius for the chroma planes
uint16_t *buf; ///< holds image data for blur algorithm passed into filter.
/// DSP functions.
- void (*filter_line) (uint8_t *dst, uint8_t *src, uint16_t *dc, int width, int thresh, const uint16_t *dithers);
- void (*blur_line) (uint16_t *dc, uint16_t *buf, uint16_t *buf1, uint8_t *src, int src_linesize, int width);
+ void (*filter_line) (uint8_t *dst, const uint8_t *src, const uint16_t *dc, int width, int thresh, const uint16_t *dithers);
+ void (*blur_line) (uint16_t *dc, uint16_t *buf, const uint16_t *buf1, const uint8_t *src, int src_linesize, int width);
} GradFunContext;
void ff_gradfun_init_x86(GradFunContext *gf);
-void ff_gradfun_filter_line_c(uint8_t *dst, uint8_t *src, uint16_t *dc, int width, int thresh, const uint16_t *dithers);
-void ff_gradfun_blur_line_c(uint16_t *dc, uint16_t *buf, uint16_t *buf1, uint8_t *src, int src_linesize, int width);
+void ff_gradfun_filter_line_c(uint8_t *dst, const uint8_t *src, const uint16_t *dc, int width, int thresh, const uint16_t *dithers);
+void ff_gradfun_blur_line_c(uint16_t *dc, uint16_t *buf, const uint16_t *buf1, const uint8_t *src, int src_linesize, int width);
#endif /* AVFILTER_GRADFUN_H */
diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c
new file mode 100644
index 0000000000..3d702c6af5
--- /dev/null
+++ b/libavfilter/graphdump.c
@@ -0,0 +1,165 @@
+/*
+ * Filter graphs to bad ASCII-art
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/bprint.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "avfiltergraph.h"
+
+static int print_link_prop(AVBPrint *buf, AVFilterLink *link)
+{
+ char *format;
+ char layout[64];
+ AVBPrint dummy_buffer = { 0 };
+
+ if (!buf)
+ buf = &dummy_buffer;
+ switch (link->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ format = av_x_if_null(av_get_pix_fmt_name(link->format), "?");
+ av_bprintf(buf, "[%dx%d %d:%d %s]", link->w, link->h,
+ link->sample_aspect_ratio.num,
+ link->sample_aspect_ratio.den,
+ format);
+ break;
+
+ case AVMEDIA_TYPE_AUDIO:
+ av_get_channel_layout_string(layout, sizeof(layout),
+ link->channels, link->channel_layout);
+ format = av_x_if_null(av_get_sample_fmt_name(link->format), "?");
+ av_bprintf(buf, "[%dHz %s:%s]",
+ (int)link->sample_rate, format, layout);
+ break;
+
+ default:
+ av_bprintf(buf, "?");
+ break;
+ }
+ return buf->len;
+}
+
+static void avfilter_graph_dump_to_buf(AVBPrint *buf, AVFilterGraph *graph)
+{
+ unsigned i, j, x, e;
+
+ for (i = 0; i < graph->nb_filters; i++) {
+ AVFilterContext *filter = graph->filters[i];
+ unsigned max_src_name = 0, max_dst_name = 0;
+ unsigned max_in_name = 0, max_out_name = 0;
+ unsigned max_in_fmt = 0, max_out_fmt = 0;
+ unsigned width, height, in_indent;
+ unsigned lname = strlen(filter->name);
+ unsigned ltype = strlen(filter->filter->name);
+
+ for (j = 0; j < filter->nb_inputs; j++) {
+ AVFilterLink *l = filter->inputs[j];
+ unsigned ln = strlen(l->src->name) + 1 + strlen(l->srcpad->name);
+ max_src_name = FFMAX(max_src_name, ln);
+ max_in_name = FFMAX(max_in_name, strlen(l->dstpad->name));
+ max_in_fmt = FFMAX(max_in_fmt, print_link_prop(NULL, l));
+ }
+ for (j = 0; j < filter->nb_outputs; j++) {
+ AVFilterLink *l = filter->outputs[j];
+ unsigned ln = strlen(l->dst->name) + 1 + strlen(l->dstpad->name);
+ max_dst_name = FFMAX(max_dst_name, ln);
+ max_out_name = FFMAX(max_out_name, strlen(l->srcpad->name));
+ max_out_fmt = FFMAX(max_out_fmt, print_link_prop(NULL, l));
+ }
+ in_indent = max_src_name + max_in_name + max_in_fmt;
+ in_indent += in_indent ? 4 : 0;
+ width = FFMAX(lname + 2, ltype + 4);
+ height = FFMAX3(2, filter->nb_inputs, filter->nb_outputs);
+ av_bprint_chars(buf, ' ', in_indent);
+ av_bprintf(buf, "+");
+ av_bprint_chars(buf, '-', width);
+ av_bprintf(buf, "+\n");
+ for (j = 0; j < height; j++) {
+ unsigned in_no = j - (height - filter->nb_inputs ) / 2;
+ unsigned out_no = j - (height - filter->nb_outputs) / 2;
+
+ /* Input link */
+ if (in_no < filter->nb_inputs) {
+ AVFilterLink *l = filter->inputs[in_no];
+ e = buf->len + max_src_name + 2;
+ av_bprintf(buf, "%s:%s", l->src->name, l->srcpad->name);
+ av_bprint_chars(buf, '-', e - buf->len);
+ e = buf->len + max_in_fmt + 2 +
+ max_in_name - strlen(l->dstpad->name);
+ print_link_prop(buf, l);
+ av_bprint_chars(buf, '-', e - buf->len);
+ av_bprintf(buf, "%s", l->dstpad->name);
+ } else {
+ av_bprint_chars(buf, ' ', in_indent);
+ }
+
+ /* Filter */
+ av_bprintf(buf, "|");
+ if (j == (height - 2) / 2) {
+ x = (width - lname) / 2;
+ av_bprintf(buf, "%*s%-*s", x, "", width - x, filter->name);
+ } else if (j == (height - 2) / 2 + 1) {
+ x = (width - ltype - 2) / 2;
+ av_bprintf(buf, "%*s(%s)%*s", x, "", filter->filter->name,
+ width - ltype - 2 - x, "");
+ } else {
+ av_bprint_chars(buf, ' ', width);
+ }
+ av_bprintf(buf, "|");
+
+ /* Output link */
+ if (out_no < filter->nb_outputs) {
+ AVFilterLink *l = filter->outputs[out_no];
+ unsigned ln = strlen(l->dst->name) + 1 +
+ strlen(l->dstpad->name);
+ e = buf->len + max_out_name + 2;
+ av_bprintf(buf, "%s", l->srcpad->name);
+ av_bprint_chars(buf, '-', e - buf->len);
+ e = buf->len + max_out_fmt + 2 +
+ max_dst_name - ln;
+ print_link_prop(buf, l);
+ av_bprint_chars(buf, '-', e - buf->len);
+ av_bprintf(buf, "%s:%s", l->dst->name, l->dstpad->name);
+ }
+ av_bprintf(buf, "\n");
+ }
+ av_bprint_chars(buf, ' ', in_indent);
+ av_bprintf(buf, "+");
+ av_bprint_chars(buf, '-', width);
+ av_bprintf(buf, "+\n");
+ av_bprintf(buf, "\n");
+ }
+}
+
+char *avfilter_graph_dump(AVFilterGraph *graph, const char *options)
+{
+ AVBPrint buf;
+ char *dump;
+
+ av_bprint_init(&buf, 0, 0);
+ avfilter_graph_dump_to_buf(&buf, graph);
+ av_bprint_init(&buf, buf.len + 1, buf.len + 1);
+ avfilter_graph_dump_to_buf(&buf, graph);
+ av_bprint_finalize(&buf, &dump);
+ return dump;
+}
diff --git a/libavfilter/graphparser.c b/libavfilter/graphparser.c
index d79215bf4a..dd331d12c0 100644
--- a/libavfilter/graphparser.c
+++ b/libavfilter/graphparser.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Vitor Sessak
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -91,17 +91,17 @@ static char *parse_link_name(const char **buf, void *log_ctx)
* @param filt_name the name of the filter to create
* @param args the arguments provided to the filter during its initialization
* @param log_ctx the log context to use
- * @return 0 in case of success, a negative AVERROR code otherwise
+ * @return >= 0 in case of success, a negative AVERROR code otherwise
*/
static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int index,
const char *filt_name, const char *args, void *log_ctx)
{
AVFilter *filt;
char inst_name[30];
- char tmp_args[256];
+ char *tmp_args = NULL;
int ret;
- snprintf(inst_name, sizeof(inst_name), "Parsed filter %d %s", index, filt_name);
+ snprintf(inst_name, sizeof(inst_name), "Parsed_%s_%d", filt_name, index);
filt = avfilter_get_by_name(filt_name);
@@ -120,8 +120,10 @@ static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int ind
if (!strcmp(filt_name, "scale") && args && !strstr(args, "flags") &&
ctx->scale_sws_opts) {
- snprintf(tmp_args, sizeof(tmp_args), "%s:%s",
+ tmp_args = av_asprintf("%s:%s",
args, ctx->scale_sws_opts);
+ if (!tmp_args)
+ return AVERROR(ENOMEM);
args = tmp_args;
}
@@ -133,10 +135,11 @@ static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int ind
av_log(log_ctx, AV_LOG_ERROR, " with args '%s'", args);
av_log(log_ctx, AV_LOG_ERROR, "\n");
avfilter_free(*filt_ctx);
- return ret;
+ *filt_ctx = NULL;
}
- return 0;
+ av_free(tmp_args);
+ return ret;
}
/**
@@ -153,7 +156,7 @@ static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int ind
* @param index an index which is assigned to the created filter
* instance, and which is supposed to be unique for each filter
* instance added to the filtergraph
- * @return 0 in case of success, a negative AVERROR code otherwise
+ * @return >= 0 in case of success, a negative AVERROR code otherwise
*/
static int parse_filter(AVFilterContext **filt_ctx, const char **buf, AVFilterGraph *graph,
int index, void *log_ctx)
@@ -240,8 +243,8 @@ static int link_filter_inouts(AVFilterContext *filt_ctx,
if (p->filter_ctx) {
ret = link_filter(p->filter_ctx, p->pad_idx, filt_ctx, pad, log_ctx);
- av_free(p->name);
- av_free(p);
+ av_freep(&p->name);
+ av_freep(&p);
if (ret < 0)
return ret;
} else {
@@ -343,10 +346,10 @@ static int parse_outputs(const char **buf, AVFilterInOut **curr_inputs,
av_free(name);
return ret;
}
- av_free(match->name);
- av_free(name);
- av_free(match);
- av_free(input);
+ av_freep(&match->name);
+ av_freep(&name);
+ av_freep(&match);
+ av_freep(&input);
} else {
/* Not in the list, so add the first input as a open_output */
input->name = name;
@@ -386,7 +389,7 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
AVFilterInOut **inputs,
AVFilterInOut **outputs)
{
- int index = 0, ret;
+ int index = 0, ret = 0;
char chr = 0;
AVFilterInOut *curr_inputs = NULL, *open_inputs = NULL, *open_outputs = NULL;
@@ -401,18 +404,17 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
filters += strspn(filters, WHITESPACES);
if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, graph)) < 0)
- goto fail;
-
+ goto end;
if ((ret = parse_filter(&filter, &filters, graph, index, graph)) < 0)
- goto fail;
+ goto end;
if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, graph)) < 0)
- goto fail;
+ goto end;
if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
graph)) < 0)
- goto fail;
+ goto end;
filters += strspn(filters, WHITESPACES);
chr = *filters++;
@@ -427,16 +429,17 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
"Unable to parse graph description substring: \"%s\"\n",
filters - 1);
ret = AVERROR(EINVAL);
- goto fail;
+ goto end;
}
append_inout(&open_outputs, &curr_inputs);
+
*inputs = open_inputs;
*outputs = open_outputs;
return 0;
- fail:
+ fail:end:
while (graph->nb_filters)
avfilter_free(graph->filters[0]);
av_freep(&graph->filters);
@@ -450,6 +453,7 @@ int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters,
return ret;
}
+#if HAVE_INCOMPATIBLE_LIBAV_ABI || !FF_API_OLD_GRAPH_PARSE
int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
AVFilterInOut *open_inputs,
AVFilterInOut *open_outputs, void *log_ctx)
@@ -511,4 +515,95 @@ int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
avfilter_inout_free(&open_inputs);
avfilter_inout_free(&open_outputs);
return ret;
+#else
+int avfilter_graph_parse(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut **inputs, AVFilterInOut **outputs,
+ void *log_ctx)
+{
+ return avfilter_graph_parse_ptr(graph, filters, inputs, outputs, log_ctx);
+#endif
+}
+
+int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters,
+ AVFilterInOut **open_inputs_ptr, AVFilterInOut **open_outputs_ptr,
+ void *log_ctx)
+{
+ int index = 0, ret = 0;
+ char chr = 0;
+
+ AVFilterInOut *curr_inputs = NULL;
+ AVFilterInOut *open_inputs = open_inputs_ptr ? *open_inputs_ptr : NULL;
+ AVFilterInOut *open_outputs = open_outputs_ptr ? *open_outputs_ptr : NULL;
+
+ if ((ret = parse_sws_flags(&filters, graph)) < 0)
+ goto end;
+
+ do {
+ AVFilterContext *filter;
+ const char *filterchain = filters;
+ filters += strspn(filters, WHITESPACES);
+
+ if ((ret = parse_inputs(&filters, &curr_inputs, &open_outputs, log_ctx)) < 0)
+ goto end;
+
+ if ((ret = parse_filter(&filter, &filters, graph, index, log_ctx)) < 0)
+ goto end;
+
+ if (filter->nb_inputs == 1 && !curr_inputs && !index) {
+ /* First input pad, assume it is "[in]" if not specified */
+ const char *tmp = "[in]";
+ if ((ret = parse_inputs(&tmp, &curr_inputs, &open_outputs, log_ctx)) < 0)
+ goto end;
+ }
+
+ if ((ret = link_filter_inouts(filter, &curr_inputs, &open_inputs, log_ctx)) < 0)
+ goto end;
+
+ if ((ret = parse_outputs(&filters, &curr_inputs, &open_inputs, &open_outputs,
+ log_ctx)) < 0)
+ goto end;
+
+ filters += strspn(filters, WHITESPACES);
+ chr = *filters++;
+
+ if (chr == ';' && curr_inputs) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid filterchain containing an unlabelled output pad: \"%s\"\n",
+ filterchain);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ index++;
+ } while (chr == ',' || chr == ';');
+
+ if (chr) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Unable to parse graph description substring: \"%s\"\n",
+ filters - 1);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ if (curr_inputs) {
+ /* Last output pad, assume it is "[out]" if not specified */
+ const char *tmp = "[out]";
+ if ((ret = parse_outputs(&tmp, &curr_inputs, &open_inputs, &open_outputs,
+ log_ctx)) < 0)
+ goto end;
+ }
+
+end:
+ /* clear open_in/outputs only if not passed as parameters */
+ if (open_inputs_ptr) *open_inputs_ptr = open_inputs;
+ else avfilter_inout_free(&open_inputs);
+ if (open_outputs_ptr) *open_outputs_ptr = open_outputs;
+ else avfilter_inout_free(&open_outputs);
+ avfilter_inout_free(&curr_inputs);
+
+ if (ret < 0) {
+ while (graph->nb_filters)
+ avfilter_free(graph->filters[0]);
+ av_freep(&graph->filters);
+ }
+ return ret;
}
diff --git a/libavfilter/interlace.h b/libavfilter/interlace.h
index 2d470508f4..44f1e06b39 100644
--- a/libavfilter/interlace.h
+++ b/libavfilter/interlace.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -49,7 +49,6 @@ typedef struct InterlaceContext {
enum ScanMode scan; // top or bottom field first scanning
int lowpass; // enable or disable low pass filterning
AVFrame *cur, *next; // the two frames from which the new one is obtained
- int got_output; // signal an output frame is reday to request_frame()
void (*lowpass_line)(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp,
const uint8_t *srcp_above, const uint8_t *srcp_below);
} InterlaceContext;
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index 4ddedbb4b3..a7ec751a0f 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,33 @@
#include "libavutil/internal.h"
#include "avfilter.h"
+#include "avfiltergraph.h"
+#include "formats.h"
#include "thread.h"
#include "version.h"
+#include "video.h"
+#include "libavcodec/avcodec.h"
+
+#define POOL_SIZE 32
+typedef struct AVFilterPool {
+ AVFilterBufferRef *pic[POOL_SIZE];
+ int count;
+ int refcount;
+ int draining;
+} AVFilterPool;
+
+typedef struct AVFilterCommand {
+ double time; ///< time expressed in seconds
+ char *command; ///< command
+ char *arg; ///< optional argument for the command
+ int flags;
+ struct AVFilterCommand *next;
+} AVFilterCommand;
+
+/**
+ * Update the position of a link in the age heap.
+ */
+void ff_avfilter_graph_update_heap(AVFilterGraph *graph, AVFilterLink *link);
#if !FF_API_AVFILTERPAD_PUBLIC
/**
@@ -48,7 +73,7 @@ struct AVFilterPad {
/**
* Callback function to get a video buffer. If NULL, the filter system will
- * use avfilter_default_get_video_buffer().
+ * use ff_default_get_video_buffer().
*
* Input video pads only.
*/
@@ -56,7 +81,7 @@ struct AVFilterPad {
/**
* Callback function to get an audio buffer. If NULL, the filter system will
- * use avfilter_default_get_audio_buffer().
+ * use ff_default_get_audio_buffer().
*
* Input audio pads only.
*/
@@ -145,9 +170,82 @@ void ff_avfilter_default_free_buffer(AVFilterBuffer *buf);
/** Tell is a format is contained in the provided list terminated by -1. */
int ff_fmt_is_in(int fmt, const int *fmts);
-#define FF_DPRINTF_START(ctx, func) av_log(NULL, AV_LOG_TRACE, "%-16s: ", #func)
+/* 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
+ */
+int ff_parse_pixel_format(enum AVPixelFormat *ret, const char *arg, void *log_ctx);
-void ff_dlog_link(void *ctx, AVFilterLink *link, int end);
+/**
+ * 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
+ */
+int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx);
+
+/**
+ * Parse a time base.
+ *
+ * @param ret unsigned AVRational 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
+ */
+int ff_parse_time_base(AVRational *ret, const char *arg, void *log_ctx);
+
+/**
+ * Parse a sample format name or a corresponding integer representation.
+ *
+ * @param ret 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
+ */
+int ff_parse_sample_format(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
+ */
+int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
+ void *log_ctx);
+
+void ff_update_link_current_pts(AVFilterLink *link, int64_t pts);
+
+void ff_command_queue_pop(AVFilterContext *filter);
+
+/* misc trace functions */
+
+/* #define FF_AVFILTER_TRACE */
+
+#ifdef FF_AVFILTER_TRACE
+# define ff_tlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__)
+#else
+# define ff_tlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0)
+#endif
+
+#define FF_TPRINTF_START(ctx, func) ff_tlog(NULL, "%-16s: ", #func)
+
+char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms);
+
+void ff_tlog_ref(void *ctx, AVFrame *ref, int end);
+
+void ff_tlog_link(void *ctx, AVFilterLink *link, int end);
/**
* Insert a new pad.
@@ -161,35 +259,38 @@ void ff_dlog_link(void *ctx, AVFilterLink *link, int end);
* @param pads Pointer to the pointer to the beginning of the list of pads
* @param links Pointer to the pointer to the beginning of the list of links
* @param newpad The new pad to add. A copy is made when adding.
+ * @return >= 0 in case of success, a negative AVERROR code on error
*/
-void ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
+int ff_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
AVFilterPad **pads, AVFilterLink ***links,
AVFilterPad *newpad);
/** Insert a new input pad for the filter. */
-static inline void ff_insert_inpad(AVFilterContext *f, unsigned index,
+static inline int ff_insert_inpad(AVFilterContext *f, unsigned index,
AVFilterPad *p)
{
- ff_insert_pad(index, &f->nb_inputs, offsetof(AVFilterLink, dstpad),
+ int ret = ff_insert_pad(index, &f->nb_inputs, offsetof(AVFilterLink, dstpad),
&f->input_pads, &f->inputs, p);
#if FF_API_FOO_COUNT
FF_DISABLE_DEPRECATION_WARNINGS
f->input_count = f->nb_inputs;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
+ return ret;
}
/** Insert a new output pad for the filter. */
-static inline void ff_insert_outpad(AVFilterContext *f, unsigned index,
+static inline int ff_insert_outpad(AVFilterContext *f, unsigned index,
AVFilterPad *p)
{
- ff_insert_pad(index, &f->nb_outputs, offsetof(AVFilterLink, srcpad),
+ int ret = ff_insert_pad(index, &f->nb_outputs, offsetof(AVFilterLink, srcpad),
&f->output_pads, &f->outputs, p);
#if FF_API_FOO_COUNT
FF_DISABLE_DEPRECATION_WARNINGS
f->output_count = f->nb_outputs;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
+ return ret;
}
/**
@@ -209,6 +310,29 @@ int ff_poll_frame(AVFilterLink *link);
*/
int ff_request_frame(AVFilterLink *link);
+#define AVFILTER_DEFINE_CLASS(fname) \
+ static const AVClass fname##_class = { \
+ .class_name = #fname, \
+ .item_name = av_default_item_name, \
+ .option = fname##_options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+ .category = AV_CLASS_CATEGORY_FILTER, \
+ }
+
+AVFilterBufferRef *ff_copy_buffer_ref(AVFilterLink *outlink,
+ AVFilterBufferRef *ref);
+
+/**
+ * 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))
+
+int ff_buffersink_read_compat(AVFilterContext *ctx, AVFilterBufferRef **buf);
+int ff_buffersink_read_samples_compat(AVFilterContext *ctx, AVFilterBufferRef **pbuf,
+ int nb_samples);
/**
* Send a frame of data to the next filter.
*
@@ -223,6 +347,20 @@ int ff_request_frame(AVFilterLink *link);
int ff_filter_frame(AVFilterLink *link, AVFrame *frame);
/**
+ * Flags for AVFilterLink.flags.
+ */
+enum {
+
+ /**
+ * Frame requests may need to loop in order to be fulfilled.
+ * A filter must set this flags on an output link if it may return 0 in
+ * request_frame() without filtering a frame.
+ */
+ FF_LINK_FLAG_REQUEST_LOOP = 1,
+
+};
+
+/**
* Allocate a new filter context and return it.
*
* @param filter what filter to create an instance of
@@ -237,4 +375,20 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name);
*/
void ff_filter_graph_remove_filter(AVFilterGraph *graph, AVFilterContext *filter);
+/**
+ * Normalize the qscale factor
+ * FIXME the H264 qscale is a log based scale, mpeg1/2 is not, the code below
+ * cannot be optimal
+ */
+static inline int ff_norm_qscale(int qscale, int type)
+{
+ switch (type) {
+ case FF_QSCALE_TYPE_MPEG1: return qscale;
+ case FF_QSCALE_TYPE_MPEG2: return qscale >> 1;
+ case FF_QSCALE_TYPE_H264: return qscale >> 2;
+ case FF_QSCALE_TYPE_VP56: return (63 - qscale + 2) >> 2;
+ }
+ return qscale;
+}
+
#endif /* AVFILTER_INTERNAL_H */
diff --git a/libavfilter/lavfutils.c b/libavfilter/lavfutils.c
new file mode 100644
index 0000000000..9952e6eab6
--- /dev/null
+++ b/libavfilter/lavfutils.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012 Stefano Sabatini <stefasab 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
+ */
+
+#include "libavutil/imgutils.h"
+#include "lavfutils.h"
+
+int ff_load_image(uint8_t *data[4], int linesize[4],
+ int *w, int *h, enum AVPixelFormat *pix_fmt,
+ const char *filename, void *log_ctx)
+{
+ AVInputFormat *iformat = NULL;
+ AVFormatContext *format_ctx = NULL;
+ AVCodec *codec;
+ AVCodecContext *codec_ctx;
+ AVFrame *frame;
+ int frame_decoded, ret = 0;
+ AVPacket pkt;
+ AVDictionary *opt=NULL;
+
+ av_init_packet(&pkt);
+
+ av_register_all();
+
+ iformat = av_find_input_format("image2");
+ if ((ret = avformat_open_input(&format_ctx, filename, iformat, NULL)) < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Failed to open input file '%s'\n", filename);
+ return ret;
+ }
+
+ if ((ret = avformat_find_stream_info(format_ctx, NULL)) < 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Find stream info failed\n");
+ return ret;
+ }
+
+ codec_ctx = format_ctx->streams[0]->codec;
+ codec = avcodec_find_decoder(codec_ctx->codec_id);
+ if (!codec) {
+ av_log(log_ctx, AV_LOG_ERROR, "Failed to find codec\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ av_dict_set(&opt, "thread_type", "slice", 0);
+ if ((ret = avcodec_open2(codec_ctx, codec, &opt)) < 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Failed to open codec\n");
+ goto end;
+ }
+
+ if (!(frame = av_frame_alloc()) ) {
+ av_log(log_ctx, AV_LOG_ERROR, "Failed to alloc frame\n");
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ ret = av_read_frame(format_ctx, &pkt);
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Failed to read frame from file\n");
+ goto end;
+ }
+
+ ret = avcodec_decode_video2(codec_ctx, frame, &frame_decoded, &pkt);
+ if (ret < 0 || !frame_decoded) {
+ av_log(log_ctx, AV_LOG_ERROR, "Failed to decode image from file\n");
+ if (ret >= 0)
+ ret = -1;
+ goto end;
+ }
+
+ *w = frame->width;
+ *h = frame->height;
+ *pix_fmt = frame->format;
+
+ if ((ret = av_image_alloc(data, linesize, *w, *h, *pix_fmt, 16)) < 0)
+ goto end;
+ ret = 0;
+
+ av_image_copy(data, linesize, (const uint8_t **)frame->data, frame->linesize, *pix_fmt, *w, *h);
+
+end:
+ av_free_packet(&pkt);
+ avcodec_close(codec_ctx);
+ avformat_close_input(&format_ctx);
+ av_frame_free(&frame);
+ av_dict_free(&opt);
+
+ if (ret < 0)
+ av_log(log_ctx, AV_LOG_ERROR, "Error loading image file '%s'\n", filename);
+ return ret;
+}
diff --git a/libavfilter/lavfutils.h b/libavfilter/lavfutils.h
new file mode 100644
index 0000000000..2d5308f79c
--- /dev/null
+++ b/libavfilter/lavfutils.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Miscellaneous utilities which make use of the libavformat library
+ */
+
+#ifndef AVFILTER_LAVFUTILS_H
+#define AVFILTER_LAVFUTILS_H
+
+#include "libavformat/avformat.h"
+
+/**
+ * Load image from filename and put the resulting image in data.
+ *
+ * @param w pointer to the width of the loaded image
+ * @param h pointer to the height of the loaded image
+ * @param pix_fmt pointer to the pixel format of the loaded image
+ * @param filename the name of the image file to load
+ * @param log_ctx log context
+ * @return >= 0 in case of success, a negative error code otherwise.
+ */
+int ff_load_image(uint8_t *data[4], int linesize[4],
+ int *w, int *h, enum AVPixelFormat *pix_fmt,
+ const char *filename, void *log_ctx);
+
+#endif /* AVFILTER_LAVFUTILS_H */
diff --git a/libavfilter/log2_tab.c b/libavfilter/log2_tab.c
new file mode 100644
index 0000000000..47a1df03b7
--- /dev/null
+++ b/libavfilter/log2_tab.c
@@ -0,0 +1 @@
+#include "libavutil/log2_tab.c"
diff --git a/libavfilter/lswsutils.c b/libavfilter/lswsutils.c
new file mode 100644
index 0000000000..ebb4f93be0
--- /dev/null
+++ b/libavfilter/lswsutils.c
@@ -0,0 +1,50 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/imgutils.h"
+#include "lswsutils.h"
+
+int ff_scale_image(uint8_t *dst_data[4], int dst_linesize[4],
+ int dst_w, int dst_h, enum AVPixelFormat dst_pix_fmt,
+ uint8_t * const src_data[4], int src_linesize[4],
+ int src_w, int src_h, enum AVPixelFormat src_pix_fmt,
+ void *log_ctx)
+{
+ int ret;
+ struct SwsContext *sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt,
+ dst_w, dst_h, dst_pix_fmt,
+ 0, NULL, NULL, NULL);
+ if (!sws_ctx) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Impossible to create scale context for the conversion "
+ "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n",
+ av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
+ av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ if ((ret = av_image_alloc(dst_data, dst_linesize, dst_w, dst_h, dst_pix_fmt, 16)) < 0)
+ goto end;
+ ret = 0;
+ sws_scale(sws_ctx, (const uint8_t * const*)src_data, src_linesize, 0, src_h, dst_data, dst_linesize);
+
+end:
+ sws_freeContext(sws_ctx);
+ return ret;
+}
diff --git a/libavfilter/lswsutils.h b/libavfilter/lswsutils.h
new file mode 100644
index 0000000000..f5f5320247
--- /dev/null
+++ b/libavfilter/lswsutils.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Miscellaneous utilities which make use of the libswscale library
+ */
+
+#ifndef AVFILTER_LSWSUTILS_H
+#define AVFILTER_LSWSUTILS_H
+
+#include "libswscale/swscale.h"
+
+/**
+ * Scale image using libswscale.
+ */
+int ff_scale_image(uint8_t *dst_data[4], int dst_linesize[4],
+ int dst_w, int dst_h, enum AVPixelFormat dst_pix_fmt,
+ uint8_t *const src_data[4], int src_linesize[4],
+ int src_w, int src_h, enum AVPixelFormat src_pix_fmt,
+ void *log_ctx);
+
+#endif /* AVFILTER_LSWSUTILS_H */
diff --git a/libavfilter/opencl_allkernels.c b/libavfilter/opencl_allkernels.c
new file mode 100644
index 0000000000..6d80fa8598
--- /dev/null
+++ b/libavfilter/opencl_allkernels.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.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
+ */
+
+#include "opencl_allkernels.h"
+#if CONFIG_OPENCL
+#include "libavutil/opencl.h"
+#include "deshake_opencl_kernel.h"
+#include "unsharp_opencl_kernel.h"
+#endif
+
+#define OPENCL_REGISTER_KERNEL_CODE(X, x) \
+ { \
+ if (CONFIG_##X##_FILTER) { \
+ av_opencl_register_kernel_code(ff_kernel_##x##_opencl); \
+ } \
+ }
+
+void ff_opencl_register_filter_kernel_code_all(void)
+{
+ #if CONFIG_OPENCL
+ OPENCL_REGISTER_KERNEL_CODE(DESHAKE, deshake);
+ OPENCL_REGISTER_KERNEL_CODE(UNSHARP, unsharp);
+ #endif
+}
diff --git a/libavfilter/opencl_allkernels.h b/libavfilter/opencl_allkernels.h
new file mode 100644
index 0000000000..aca02e0456
--- /dev/null
+++ b/libavfilter/opencl_allkernels.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_OPENCL_ALLKERNEL_H
+#define AVFILTER_OPENCL_ALLKERNEL_H
+
+#include "avfilter.h"
+#include "config.h"
+
+void ff_opencl_register_filter_kernel_code_all(void);
+
+#endif /* AVFILTER_OPENCL_ALLKERNEL_H */
diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c
index dd3b174b1b..070b3bded5 100644
--- a/libavfilter/pthread.c
+++ b/libavfilter/pthread.c
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,8 @@
#if HAVE_PTHREADS
#include <pthread.h>
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#elif HAVE_W32THREADS
#include "compat/w32pthreads.h"
#endif
@@ -157,7 +159,6 @@ static int thread_init_internal(ThreadContext *c, int nb_threads)
if (!nb_threads) {
int nb_cpus = av_cpu_count();
- av_log(c->graph, AV_LOG_DEBUG, "Detected %d logical cores.\n", nb_cpus);
// use number of cores + 1 as thread count if there is more than one
if (nb_cpus > 1)
nb_threads = nb_cpus + 1;
@@ -169,7 +170,7 @@ static int thread_init_internal(ThreadContext *c, int nb_threads)
return 1;
c->nb_threads = nb_threads;
- c->workers = av_mallocz(sizeof(*c->workers) * nb_threads);
+ c->workers = av_mallocz_array(sizeof(*c->workers), nb_threads);
if (!c->workers)
return AVERROR(ENOMEM);
diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c
index 98bafc284a..dbfd88d218 100644
--- a/libavfilter/setpts.c
+++ b/libavfilter/setpts.c
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Stefano Sabatini
* Copyright (c) 2008 Victor Paesa
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,24 +31,27 @@
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
-
#include "audio.h"
#include "avfilter.h"
#include "internal.h"
#include "video.h"
-#include "config.h"
-
static const char *const var_names[] = {
- "E", ///< Euler number
+ "FRAME_RATE", ///< defined only for constant frame-rate video
"INTERLACED", ///< tell if the current frame is interlaced
"N", ///< frame / sample number (starting at zero)
- "PHI", ///< golden ratio
- "PI", ///< greek pi
+ "NB_CONSUMED_SAMPLES", ///< number of samples consumed by the filter (only audio)
+ "NB_SAMPLES", ///< number of samples in the current frame (only audio)
+ "POS", ///< original position in the file of the frame
"PREV_INPTS", ///< previous input PTS
+ "PREV_INT", ///< previous input time in seconds
"PREV_OUTPTS", ///< previous output PTS
+ "PREV_OUTT", ///< previous output time in seconds
"PTS", ///< original pts in the file of the frame
+ "SAMPLE_RATE", ///< sample rate (only audio)
"STARTPTS", ///< PTS at start of movie
+ "STARTT", ///< time at start of movie
+ "T", ///< original time in the file of the frame
"TB", ///< timebase
"RTCTIME", ///< wallclock (RTC) time in micro seconds
"RTCSTART", ///< wallclock (RTC) time at the start of the movie in micro seconds
@@ -58,15 +61,21 @@ static const char *const var_names[] = {
};
enum var_name {
- VAR_E,
+ VAR_FRAME_RATE,
VAR_INTERLACED,
VAR_N,
- VAR_PHI,
- VAR_PI,
+ VAR_NB_CONSUMED_SAMPLES,
+ VAR_NB_SAMPLES,
+ VAR_POS,
VAR_PREV_INPTS,
+ VAR_PREV_INT,
VAR_PREV_OUTPTS,
+ VAR_PREV_OUTT,
VAR_PTS,
+ VAR_SAMPLE_RATE,
VAR_STARTPTS,
+ VAR_STARTT,
+ VAR_T,
VAR_TB,
VAR_RTCTIME,
VAR_RTCSTART,
@@ -80,6 +89,7 @@ typedef struct SetPTSContext {
char *expr_str;
AVExpr *expr;
double var_values[VAR_VARS_NB];
+ enum AVMediaType type;
} SetPTSContext;
static av_cold int init(AVFilterContext *ctx)
@@ -93,34 +103,54 @@ static av_cold int init(AVFilterContext *ctx)
return ret;
}
- setpts->var_values[VAR_E] = M_E;
setpts->var_values[VAR_N] = 0.0;
setpts->var_values[VAR_S] = 0.0;
- setpts->var_values[VAR_PHI] = M_PHI;
- setpts->var_values[VAR_PI] = M_PI;
setpts->var_values[VAR_PREV_INPTS] = NAN;
+ setpts->var_values[VAR_PREV_INT] = NAN;
setpts->var_values[VAR_PREV_OUTPTS] = NAN;
+ setpts->var_values[VAR_PREV_OUTT] = NAN;
setpts->var_values[VAR_STARTPTS] = NAN;
+ setpts->var_values[VAR_STARTT] = NAN;
return 0;
}
static int config_input(AVFilterLink *inlink)
{
- SetPTSContext *setpts = inlink->dst->priv;
+ AVFilterContext *ctx = inlink->dst;
+ SetPTSContext *setpts = ctx->priv;
+ setpts->type = inlink->type;
setpts->var_values[VAR_TB] = av_q2d(inlink->time_base);
setpts->var_values[VAR_RTCSTART] = av_gettime();
- if (inlink->type == AVMEDIA_TYPE_AUDIO) {
- setpts->var_values[VAR_SR] = inlink->sample_rate;
- }
+ setpts->var_values[VAR_SR] =
+ setpts->var_values[VAR_SAMPLE_RATE] =
+ setpts->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN;
+
+ setpts->var_values[VAR_FRAME_RATE] = inlink->frame_rate.num && inlink->frame_rate.den ?
+ av_q2d(inlink->frame_rate) : NAN;
- av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f\n", setpts->var_values[VAR_TB]);
+ av_log(inlink->src, AV_LOG_VERBOSE, "TB:%f FRAME_RATE:%f SAMPLE_RATE:%f\n",
+ setpts->var_values[VAR_TB],
+ setpts->var_values[VAR_FRAME_RATE],
+ setpts->var_values[VAR_SAMPLE_RATE]);
return 0;
}
#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))
+
+#define BUF_SIZE 64
+
+static inline char *double2int64str(char *buf, double v)
+{
+ if (isnan(v)) snprintf(buf, BUF_SIZE, "nan");
+ else snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)v);
+ return buf;
+}
+
+#define d2istr(v) double2int64str((char[BUF_SIZE]){0}, v)
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
@@ -128,27 +158,43 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
int64_t in_pts = frame->pts;
double d;
- if (isnan(setpts->var_values[VAR_STARTPTS]))
+ if (isnan(setpts->var_values[VAR_STARTPTS])) {
setpts->var_values[VAR_STARTPTS] = TS2D(frame->pts);
-
+ setpts->var_values[VAR_STARTT ] = TS2T(frame->pts, inlink->time_base);
+ }
setpts->var_values[VAR_PTS ] = TS2D(frame->pts);
+ setpts->var_values[VAR_T ] = TS2T(frame->pts, inlink->time_base);
+ setpts->var_values[VAR_POS ] = av_frame_get_pkt_pos(frame) == -1 ? NAN : av_frame_get_pkt_pos(frame);
setpts->var_values[VAR_RTCTIME ] = av_gettime();
if (inlink->type == AVMEDIA_TYPE_VIDEO) {
setpts->var_values[VAR_INTERLACED] = frame->interlaced_frame;
- } else {
+ } else if (inlink->type == AVMEDIA_TYPE_AUDIO) {
setpts->var_values[VAR_S] = frame->nb_samples;
+ setpts->var_values[VAR_NB_SAMPLES] = frame->nb_samples;
}
d = av_expr_eval(setpts->expr, setpts->var_values, NULL);
frame->pts = D2TS(d);
av_log(inlink->dst, AV_LOG_TRACE,
- "n:%"PRId64" interlaced:%d pts:%"PRId64" t:%f -> pts:%"PRId64" t:%f\n",
+ "N:%"PRId64" PTS:%s T:%f POS:%s",
(int64_t)setpts->var_values[VAR_N],
- (int)setpts->var_values[VAR_INTERLACED],
- in_pts, in_pts * av_q2d(inlink->time_base),
- frame->pts, frame->pts * av_q2d(inlink->time_base));
+ d2istr(setpts->var_values[VAR_PTS]),
+ setpts->var_values[VAR_T],
+ d2istr(setpts->var_values[VAR_POS]));
+ switch (inlink->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ av_log(inlink->dst, AV_LOG_TRACE, " INTERLACED:%"PRId64,
+ (int64_t)setpts->var_values[VAR_INTERLACED]);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ av_log(inlink->dst, AV_LOG_TRACE, " NB_SAMPLES:%"PRId64" NB_CONSUMED_SAMPLES:%"PRId64,
+ (int64_t)setpts->var_values[VAR_NB_SAMPLES],
+ (int64_t)setpts->var_values[VAR_NB_CONSUMED_SAMPLES]);
+ break;
+ }
+ av_log(inlink->dst, AV_LOG_TRACE, " -> PTS:%s T:%f\n", d2istr(d), TS2T(d, inlink->time_base));
if (inlink->type == AVMEDIA_TYPE_VIDEO) {
setpts->var_values[VAR_N] += 1.0;
@@ -157,7 +203,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
setpts->var_values[VAR_PREV_INPTS ] = TS2D(in_pts);
+ setpts->var_values[VAR_PREV_INT ] = TS2T(in_pts, inlink->time_base);
setpts->var_values[VAR_PREV_OUTPTS] = TS2D(frame->pts);
+ setpts->var_values[VAR_PREV_OUTT] = TS2T(frame->pts, inlink->time_base);
+ if (setpts->type == AVMEDIA_TYPE_AUDIO) {
+ setpts->var_values[VAR_NB_CONSUMED_SAMPLES] += frame->nb_samples;
+ }
return ff_filter_frame(inlink->dst->outputs[0], frame);
}
@@ -169,27 +220,22 @@ static av_cold void uninit(AVFilterContext *ctx)
}
#define OFFSET(x) offsetof(SetPTSContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption options[] = {
{ "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = FLAGS },
- { NULL },
+ { NULL }
};
#if CONFIG_SETPTS_FILTER
-static const AVClass setpts_class = {
- .class_name = "setpts",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+#define setpts_options options
+AVFILTER_DEFINE_CLASS(setpts);
static const AVFilterPad avfilter_vf_setpts_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .config_props = config_input,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -214,23 +260,19 @@ AVFilter ff_vf_setpts = {
.inputs = avfilter_vf_setpts_inputs,
.outputs = avfilter_vf_setpts_outputs,
};
-#endif
+#endif /* CONFIG_SETPTS_FILTER */
#if CONFIG_ASETPTS_FILTER
-static const AVClass asetpts_class = {
- .class_name = "asetpts",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+
+#define asetpts_options options
+AVFILTER_DEFINE_CLASS(asetpts);
static const AVFilterPad asetpts_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
- .config_props = config_input,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -248,11 +290,9 @@ AVFilter ff_af_asetpts = {
.description = NULL_IF_CONFIG_SMALL("Set PTS for the output audio frame."),
.init = init,
.uninit = uninit,
-
- .priv_size = sizeof(SetPTSContext),
- .priv_class = &asetpts_class,
-
- .inputs = asetpts_inputs,
- .outputs = asetpts_outputs,
+ .priv_size = sizeof(SetPTSContext),
+ .priv_class = &asetpts_class,
+ .inputs = asetpts_inputs,
+ .outputs = asetpts_outputs,
};
-#endif
+#endif /* CONFIG_ASETPTS_FILTER */
diff --git a/libavfilter/settb.c b/libavfilter/settb.c
index 169037f321..83616c1361 100644
--- a/libavfilter/settb.c
+++ b/libavfilter/settb.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,9 +38,6 @@
#include "video.h"
static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
"AVTB", /* default timebase 1/AV_TIME_BASE */
"intb", /* input timebase */
"sr", /* sample rate */
@@ -48,9 +45,6 @@ static const char *const var_names[] = {
};
enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
VAR_AVTB,
VAR_INTB,
VAR_SR,
@@ -63,6 +57,16 @@ typedef struct SetTBContext {
double var_values[VAR_VARS_NB];
} SetTBContext;
+#define OFFSET(x) offsetof(SetTBContext, x)
+#define DEFINE_OPTIONS(filt_name, filt_type) \
+static const AVOption filt_name##_options[] = { \
+ { "expr", "set expression determining the output timebase", OFFSET(tb_expr), AV_OPT_TYPE_STRING, {.str="intb"}, \
+ .flags=AV_OPT_FLAG_##filt_type##_PARAM|AV_OPT_FLAG_FILTERING_PARAM }, \
+ { "tb", "set expression determining the output timebase", OFFSET(tb_expr), AV_OPT_TYPE_STRING, {.str="intb"}, \
+ .flags=AV_OPT_FLAG_##filt_type##_PARAM|AV_OPT_FLAG_FILTERING_PARAM }, \
+ { NULL } \
+}
+
static int config_output_props(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
@@ -72,9 +76,6 @@ static int config_output_props(AVFilterLink *outlink)
int ret;
double res;
- settb->var_values[VAR_E] = M_E;
- settb->var_values[VAR_PHI] = M_PHI;
- settb->var_values[VAR_PI] = M_PI;
settb->var_values[VAR_AVTB] = av_q2d(AV_TIME_BASE_Q);
settb->var_values[VAR_INTB] = av_q2d(inlink->time_base);
settb->var_values[VAR_SR] = inlink->sample_rate;
@@ -119,27 +120,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
return ff_filter_frame(outlink, frame);
}
-#define OFFSET(x) offsetof(SetTBContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM
-static const AVOption options[] = {
- { "expr", "Expression determining the output timebase", OFFSET(tb_expr), AV_OPT_TYPE_STRING, { .str = "intb" }, .flags = FLAGS },
- { NULL },
-};
-
#if CONFIG_SETTB_FILTER
-static const AVClass settb_class = {
- .class_name = "settb",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+
+DEFINE_OPTIONS(settb, VIDEO);
+AVFILTER_DEFINE_CLASS(settb);
static const AVFilterPad avfilter_vf_settb_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -154,31 +144,24 @@ static const AVFilterPad avfilter_vf_settb_outputs[] = {
};
AVFilter ff_vf_settb = {
- .name = "settb",
+ .name = "settb",
.description = NULL_IF_CONFIG_SMALL("Set timebase for the video output link."),
-
- .priv_size = sizeof(SetTBContext),
- .priv_class = &settb_class,
-
- .inputs = avfilter_vf_settb_inputs,
-
- .outputs = avfilter_vf_settb_outputs,
+ .priv_size = sizeof(SetTBContext),
+ .priv_class = &settb_class,
+ .inputs = avfilter_vf_settb_inputs,
+ .outputs = avfilter_vf_settb_outputs,
};
#endif /* CONFIG_SETTB_FILTER */
#if CONFIG_ASETTB_FILTER
-static const AVClass asettb_class = {
- .class_name = "asettb",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+
+DEFINE_OPTIONS(asettb, AUDIO);
+AVFILTER_DEFINE_CLASS(asettb);
static const AVFilterPad avfilter_af_asettb_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
.filter_frame = filter_frame,
},
{ NULL }
diff --git a/libavfilter/split.c b/libavfilter/split.c
index 41395e7f48..7353810677 100644
--- a/libavfilter/split.c
+++ b/libavfilter/split.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,6 +52,8 @@ static av_cold int split_init(AVFilterContext *ctx)
snprintf(name, sizeof(name), "output%d", i);
pad.type = ctx->filter->inputs[0].type;
pad.name = av_strdup(name);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
ff_insert_outpad(ctx, i, &pad);
}
@@ -70,10 +72,14 @@ static av_cold void split_uninit(AVFilterContext *ctx)
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
- int i, ret = 0;
+ int i, ret = AVERROR_EOF;
for (i = 0; i < ctx->nb_outputs; i++) {
- AVFrame *buf_out = av_frame_clone(frame);
+ AVFrame *buf_out;
+
+ if (ctx->outputs[i]->closed)
+ continue;
+ buf_out = av_frame_clone(frame);
if (!buf_out) {
ret = AVERROR(ENOMEM);
break;
@@ -90,56 +96,42 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
#define OFFSET(x) offsetof(SplitContext, x)
#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
static const AVOption options[] = {
- { "outputs", "Number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS },
- { NULL },
+ { "outputs", "set number of outputs", OFFSET(nb_outputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS },
+ { NULL }
};
-static const AVClass split_class = {
- .class_name = "split",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+#define split_options options
+AVFILTER_DEFINE_CLASS(split);
-static const AVClass asplit_class = {
- .class_name = "asplit",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+#define asplit_options options
+AVFILTER_DEFINE_CLASS(asplit);
static const AVFilterPad avfilter_vf_split_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
AVFilter ff_vf_split = {
- .name = "split",
+ .name = "split",
.description = NULL_IF_CONFIG_SMALL("Pass on the input to N video outputs."),
-
- .priv_size = sizeof(SplitContext),
- .priv_class = &split_class,
-
- .init = split_init,
- .uninit = split_uninit,
-
- .inputs = avfilter_vf_split_inputs,
- .outputs = NULL,
-
- .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+ .priv_size = sizeof(SplitContext),
+ .priv_class = &split_class,
+ .init = split_init,
+ .uninit = split_uninit,
+ .inputs = avfilter_vf_split_inputs,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
};
static const AVFilterPad avfilter_af_asplit_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .get_audio_buffer = ff_null_get_audio_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -147,15 +139,11 @@ static const AVFilterPad avfilter_af_asplit_inputs[] = {
AVFilter ff_af_asplit = {
.name = "asplit",
.description = NULL_IF_CONFIG_SMALL("Pass on the audio input to N audio outputs."),
-
- .priv_size = sizeof(SplitContext),
- .priv_class = &asplit_class,
-
- .init = split_init,
- .uninit = split_uninit,
-
- .inputs = avfilter_af_asplit_inputs,
- .outputs = NULL,
-
- .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+ .priv_size = sizeof(SplitContext),
+ .priv_class = &asplit_class,
+ .init = split_init,
+ .uninit = split_uninit,
+ .inputs = avfilter_af_asplit_inputs,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
};
diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c
new file mode 100644
index 0000000000..908c03e1d3
--- /dev/null
+++ b/libavfilter/src_movie.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2010 Stefano Sabatini
+ * Copyright (c) 2008 Victor Paesa
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * movie video source
+ *
+ * @todo use direct rendering (no allocation of a new frame)
+ * @todo support a PTS correction mechanism
+ */
+
+#include <float.h>
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/timestamp.h"
+#include "libavformat/avformat.h"
+#include "audio.h"
+#include "avcodec.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct MovieStream {
+ AVStream *st;
+ int done;
+} MovieStream;
+
+typedef struct MovieContext {
+ /* common A/V fields */
+ const AVClass *class;
+ int64_t seek_point; ///< seekpoint in microseconds
+ double seek_point_d;
+ char *format_name;
+ char *file_name;
+ char *stream_specs; /**< user-provided list of streams, separated by + */
+ int stream_index; /**< for compatibility */
+ int loop_count;
+
+ AVFormatContext *format_ctx;
+ int eof;
+ AVPacket pkt, pkt0;
+
+ int max_stream_index; /**< max stream # actually used for output */
+ MovieStream *st; /**< array of all streams, one per output */
+ int *out_index; /**< stream number -> output number map, or -1 */
+} MovieContext;
+
+#define OFFSET(x) offsetof(MovieContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption movie_options[]= {
+ { "filename", NULL, OFFSET(file_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "format_name", "set format name", OFFSET(format_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "f", "set format name", OFFSET(format_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "stream_index", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
+ { "si", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
+ { "seek_point", "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, (INT64_MAX-1) / 1000000, FLAGS },
+ { "sp", "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, (INT64_MAX-1) / 1000000, FLAGS },
+ { "streams", "set streams", OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str = 0}, CHAR_MAX, CHAR_MAX, FLAGS },
+ { "s", "set streams", OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str = 0}, CHAR_MAX, CHAR_MAX, FLAGS },
+ { "loop", "set loop count", OFFSET(loop_count), AV_OPT_TYPE_INT, {.i64 = 1}, 0, INT_MAX, FLAGS },
+ { NULL },
+};
+
+static int movie_config_output_props(AVFilterLink *outlink);
+static int movie_request_frame(AVFilterLink *outlink);
+
+static AVStream *find_stream(void *log, AVFormatContext *avf, const char *spec)
+{
+ int i, ret, already = 0, stream_id = -1;
+ char type_char[2], dummy;
+ AVStream *found = NULL;
+ enum AVMediaType type;
+
+ ret = sscanf(spec, "d%1[av]%d%c", type_char, &stream_id, &dummy);
+ if (ret >= 1 && ret <= 2) {
+ type = type_char[0] == 'v' ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO;
+ ret = av_find_best_stream(avf, type, stream_id, -1, NULL, 0);
+ if (ret < 0) {
+ av_log(log, AV_LOG_ERROR, "No %s stream with index '%d' found\n",
+ av_get_media_type_string(type), stream_id);
+ return NULL;
+ }
+ return avf->streams[ret];
+ }
+ for (i = 0; i < avf->nb_streams; i++) {
+ ret = avformat_match_stream_specifier(avf, avf->streams[i], spec);
+ if (ret < 0) {
+ av_log(log, AV_LOG_ERROR,
+ "Invalid stream specifier \"%s\"\n", spec);
+ return NULL;
+ }
+ if (!ret)
+ continue;
+ if (avf->streams[i]->discard != AVDISCARD_ALL) {
+ already++;
+ continue;
+ }
+ if (found) {
+ av_log(log, AV_LOG_WARNING,
+ "Ambiguous stream specifier \"%s\", using #%d\n", spec, i);
+ break;
+ }
+ found = avf->streams[i];
+ }
+ if (!found) {
+ av_log(log, AV_LOG_WARNING, "Stream specifier \"%s\" %s\n", spec,
+ already ? "matched only already used streams" :
+ "did not match any stream");
+ return NULL;
+ }
+ if (found->codec->codec_type != AVMEDIA_TYPE_VIDEO &&
+ found->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ av_log(log, AV_LOG_ERROR, "Stream specifier \"%s\" matched a %s stream,"
+ "currently unsupported by libavfilter\n", spec,
+ av_get_media_type_string(found->codec->codec_type));
+ return NULL;
+ }
+ return found;
+}
+
+static int open_stream(void *log, MovieStream *st)
+{
+ AVCodec *codec;
+ int ret;
+
+ codec = avcodec_find_decoder(st->st->codec->codec_id);
+ if (!codec) {
+ av_log(log, AV_LOG_ERROR, "Failed to find any codec\n");
+ return AVERROR(EINVAL);
+ }
+
+ st->st->codec->refcounted_frames = 1;
+
+ if ((ret = avcodec_open2(st->st->codec, codec, NULL)) < 0) {
+ av_log(log, AV_LOG_ERROR, "Failed to open codec\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int guess_channel_layout(MovieStream *st, int st_index, void *log_ctx)
+{
+ AVCodecContext *dec_ctx = st->st->codec;
+ char buf[256];
+ int64_t chl = av_get_default_channel_layout(dec_ctx->channels);
+
+ if (!chl) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Channel layout is not set in stream %d, and could not "
+ "be guessed from the number of channels (%d)\n",
+ st_index, dec_ctx->channels);
+ return AVERROR(EINVAL);
+ }
+
+ av_get_channel_layout_string(buf, sizeof(buf), dec_ctx->channels, chl);
+ av_log(log_ctx, AV_LOG_WARNING,
+ "Channel layout is not set in output stream %d, "
+ "guessed channel layout is '%s'\n",
+ st_index, buf);
+ dec_ctx->channel_layout = chl;
+ return 0;
+}
+
+static av_cold int movie_common_init(AVFilterContext *ctx)
+{
+ MovieContext *movie = ctx->priv;
+ AVInputFormat *iformat = NULL;
+ int64_t timestamp;
+ int nb_streams = 1, ret, i;
+ char default_streams[16], *stream_specs, *spec, *cursor;
+ char name[16];
+ AVStream *st;
+
+ if (!movie->file_name) {
+ av_log(ctx, AV_LOG_ERROR, "No filename provided!\n");
+ return AVERROR(EINVAL);
+ }
+
+ movie->seek_point = movie->seek_point_d * 1000000 + 0.5;
+
+ stream_specs = movie->stream_specs;
+ if (!stream_specs) {
+ snprintf(default_streams, sizeof(default_streams), "d%c%d",
+ !strcmp(ctx->filter->name, "amovie") ? 'a' : 'v',
+ movie->stream_index);
+ stream_specs = default_streams;
+ }
+ for (cursor = stream_specs; *cursor; cursor++)
+ if (*cursor == '+')
+ nb_streams++;
+
+ if (movie->loop_count != 1 && nb_streams != 1) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Loop with several streams is currently unsupported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ av_register_all();
+
+ // Try to find the movie format (container)
+ iformat = movie->format_name ? av_find_input_format(movie->format_name) : NULL;
+
+ movie->format_ctx = NULL;
+ if ((ret = avformat_open_input(&movie->format_ctx, movie->file_name, iformat, NULL)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Failed to avformat_open_input '%s'\n", movie->file_name);
+ return ret;
+ }
+ if ((ret = avformat_find_stream_info(movie->format_ctx, NULL)) < 0)
+ av_log(ctx, AV_LOG_WARNING, "Failed to find stream info\n");
+
+ // if seeking requested, we execute it
+ if (movie->seek_point > 0) {
+ timestamp = movie->seek_point;
+ // add the stream start time, should it exist
+ if (movie->format_ctx->start_time != AV_NOPTS_VALUE) {
+ if (timestamp > INT64_MAX - movie->format_ctx->start_time) {
+ av_log(ctx, AV_LOG_ERROR,
+ "%s: seek value overflow with start_time:%"PRId64" seek_point:%"PRId64"\n",
+ movie->file_name, movie->format_ctx->start_time, movie->seek_point);
+ return AVERROR(EINVAL);
+ }
+ timestamp += movie->format_ctx->start_time;
+ }
+ if ((ret = av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "%s: could not seek to position %"PRId64"\n",
+ movie->file_name, timestamp);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < movie->format_ctx->nb_streams; i++)
+ movie->format_ctx->streams[i]->discard = AVDISCARD_ALL;
+
+ movie->st = av_calloc(nb_streams, sizeof(*movie->st));
+ if (!movie->st)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < nb_streams; i++) {
+ spec = av_strtok(stream_specs, "+", &cursor);
+ if (!spec)
+ return AVERROR_BUG;
+ stream_specs = NULL; /* for next strtok */
+ st = find_stream(ctx, movie->format_ctx, spec);
+ if (!st)
+ return AVERROR(EINVAL);
+ st->discard = AVDISCARD_DEFAULT;
+ movie->st[i].st = st;
+ movie->max_stream_index = FFMAX(movie->max_stream_index, st->index);
+ }
+ if (av_strtok(NULL, "+", &cursor))
+ return AVERROR_BUG;
+
+ movie->out_index = av_calloc(movie->max_stream_index + 1,
+ sizeof(*movie->out_index));
+ if (!movie->out_index)
+ return AVERROR(ENOMEM);
+ for (i = 0; i <= movie->max_stream_index; i++)
+ movie->out_index[i] = -1;
+ for (i = 0; i < nb_streams; i++) {
+ AVFilterPad pad = { 0 };
+ movie->out_index[movie->st[i].st->index] = i;
+ snprintf(name, sizeof(name), "out%d", i);
+ pad.type = movie->st[i].st->codec->codec_type;
+ pad.name = av_strdup(name);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ pad.config_props = movie_config_output_props;
+ pad.request_frame = movie_request_frame;
+ ff_insert_outpad(ctx, i, &pad);
+ ret = open_stream(ctx, &movie->st[i]);
+ if (ret < 0)
+ return ret;
+ if ( movie->st[i].st->codec->codec->type == AVMEDIA_TYPE_AUDIO &&
+ !movie->st[i].st->codec->channel_layout) {
+ ret = guess_channel_layout(&movie->st[i], i, ctx);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE, "seek_point:%"PRIi64" format_name:%s file_name:%s stream_index:%d\n",
+ movie->seek_point, movie->format_name, movie->file_name,
+ movie->stream_index);
+
+ return 0;
+}
+
+static av_cold void movie_uninit(AVFilterContext *ctx)
+{
+ MovieContext *movie = ctx->priv;
+ int i;
+
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ av_freep(&ctx->output_pads[i].name);
+ if (movie->st[i].st)
+ avcodec_close(movie->st[i].st->codec);
+ }
+ av_freep(&movie->st);
+ av_freep(&movie->out_index);
+ if (movie->format_ctx)
+ avformat_close_input(&movie->format_ctx);
+}
+
+static int movie_query_formats(AVFilterContext *ctx)
+{
+ MovieContext *movie = ctx->priv;
+ int list[] = { 0, -1 };
+ int64_t list64[] = { 0, -1 };
+ int i;
+
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ MovieStream *st = &movie->st[i];
+ AVCodecContext *c = st->st->codec;
+ AVFilterLink *outlink = ctx->outputs[i];
+
+ switch (c->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ list[0] = c->pix_fmt;
+ ff_formats_ref(ff_make_format_list(list), &outlink->in_formats);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ list[0] = c->sample_fmt;
+ ff_formats_ref(ff_make_format_list(list), &outlink->in_formats);
+ list[0] = c->sample_rate;
+ ff_formats_ref(ff_make_format_list(list), &outlink->in_samplerates);
+ list64[0] = c->channel_layout;
+ ff_channel_layouts_ref(avfilter_make_format64_list(list64),
+ &outlink->in_channel_layouts);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int movie_config_output_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ MovieContext *movie = ctx->priv;
+ unsigned out_id = FF_OUTLINK_IDX(outlink);
+ MovieStream *st = &movie->st[out_id];
+ AVCodecContext *c = st->st->codec;
+
+ outlink->time_base = st->st->time_base;
+
+ switch (c->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ outlink->w = c->width;
+ outlink->h = c->height;
+ outlink->frame_rate = st->st->r_frame_rate;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ break;
+ }
+
+ return 0;
+}
+
+static char *describe_frame_to_str(char *dst, size_t dst_size,
+ AVFrame *frame, enum AVMediaType frame_type,
+ AVFilterLink *link)
+{
+ switch (frame_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ snprintf(dst, dst_size,
+ "video pts:%s time:%s size:%dx%d aspect:%d/%d",
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &link->time_base),
+ frame->width, frame->height,
+ frame->sample_aspect_ratio.num,
+ frame->sample_aspect_ratio.den);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ snprintf(dst, dst_size,
+ "audio pts:%s time:%s samples:%d",
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &link->time_base),
+ frame->nb_samples);
+ break;
+ default:
+ snprintf(dst, dst_size, "%s BUG", av_get_media_type_string(frame_type));
+ break;
+ }
+ return dst;
+}
+
+static int rewind_file(AVFilterContext *ctx)
+{
+ MovieContext *movie = ctx->priv;
+ int64_t timestamp = movie->seek_point;
+ int ret, i;
+
+ if (movie->format_ctx->start_time != AV_NOPTS_VALUE)
+ timestamp += movie->format_ctx->start_time;
+ ret = av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to loop: %s\n", av_err2str(ret));
+ movie->loop_count = 1; /* do not try again */
+ return ret;
+ }
+
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ avcodec_flush_buffers(movie->st[i].st->codec);
+ movie->st[i].done = 0;
+ }
+ movie->eof = 0;
+ return 0;
+}
+
+/**
+ * Try to push a frame to the requested output.
+ *
+ * @param ctx filter context
+ * @param out_id number of output where a frame is wanted;
+ * if the frame is read from file, used to set the return value;
+ * if the codec is being flushed, flush the corresponding stream
+ * @return 1 if a frame was pushed on the requested output,
+ * 0 if another attempt is possible,
+ * <0 AVERROR code
+ */
+static int movie_push_frame(AVFilterContext *ctx, unsigned out_id)
+{
+ MovieContext *movie = ctx->priv;
+ AVPacket *pkt = &movie->pkt;
+ enum AVMediaType frame_type;
+ MovieStream *st;
+ int ret, got_frame = 0, pkt_out_id;
+ AVFilterLink *outlink;
+ AVFrame *frame;
+
+ if (!pkt->size) {
+ if (movie->eof) {
+ if (movie->st[out_id].done) {
+ if (movie->loop_count != 1) {
+ ret = rewind_file(ctx);
+ if (ret < 0)
+ return ret;
+ movie->loop_count -= movie->loop_count > 1;
+ av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n");
+ return 0; /* retry */
+ }
+ return AVERROR_EOF;
+ }
+ pkt->stream_index = movie->st[out_id].st->index;
+ /* packet is already ready for flushing */
+ } else {
+ ret = av_read_frame(movie->format_ctx, &movie->pkt0);
+ if (ret < 0) {
+ av_init_packet(&movie->pkt0); /* ready for flushing */
+ *pkt = movie->pkt0;
+ if (ret == AVERROR_EOF) {
+ movie->eof = 1;
+ return 0; /* start flushing */
+ }
+ return ret;
+ }
+ *pkt = movie->pkt0;
+ }
+ }
+
+ pkt_out_id = pkt->stream_index > movie->max_stream_index ? -1 :
+ movie->out_index[pkt->stream_index];
+ if (pkt_out_id < 0) {
+ av_free_packet(&movie->pkt0);
+ pkt->size = 0; /* ready for next run */
+ pkt->data = NULL;
+ return 0;
+ }
+ st = &movie->st[pkt_out_id];
+ outlink = ctx->outputs[pkt_out_id];
+
+ frame = av_frame_alloc();
+ if (!frame)
+ return AVERROR(ENOMEM);
+
+ frame_type = st->st->codec->codec_type;
+ switch (frame_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ ret = avcodec_decode_video2(st->st->codec, frame, &got_frame, pkt);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ ret = avcodec_decode_audio4(st->st->codec, frame, &got_frame, pkt);
+ break;
+ default:
+ ret = AVERROR(ENOSYS);
+ break;
+ }
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_WARNING, "Decode error: %s\n", av_err2str(ret));
+ av_frame_free(&frame);
+ av_free_packet(&movie->pkt0);
+ movie->pkt.size = 0;
+ movie->pkt.data = NULL;
+ return 0;
+ }
+ if (!ret || st->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ ret = pkt->size;
+
+ pkt->data += ret;
+ pkt->size -= ret;
+ if (pkt->size <= 0) {
+ av_free_packet(&movie->pkt0);
+ pkt->size = 0; /* ready for next run */
+ pkt->data = NULL;
+ }
+ if (!got_frame) {
+ if (!ret)
+ st->done = 1;
+ av_frame_free(&frame);
+ return 0;
+ }
+
+ frame->pts = av_frame_get_best_effort_timestamp(frame);
+ av_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name,
+ describe_frame_to_str((char[1024]){0}, 1024, frame, frame_type, outlink));
+
+ if (st->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (frame->format != outlink->format) {
+ av_log(ctx, AV_LOG_ERROR, "Format changed %s -> %s, discarding frame\n",
+ av_get_pix_fmt_name(outlink->format),
+ av_get_pix_fmt_name(frame->format)
+ );
+ av_frame_free(&frame);
+ return 0;
+ }
+ }
+ ret = ff_filter_frame(outlink, frame);
+
+ if (ret < 0)
+ return ret;
+ return pkt_out_id == out_id;
+}
+
+static int movie_request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ unsigned out_id = FF_OUTLINK_IDX(outlink);
+ int ret;
+
+ while (1) {
+ ret = movie_push_frame(ctx, out_id);
+ if (ret)
+ return FFMIN(ret, 0);
+ }
+}
+
+#if CONFIG_MOVIE_FILTER
+
+AVFILTER_DEFINE_CLASS(movie);
+
+AVFilter ff_avsrc_movie = {
+ .name = "movie",
+ .description = NULL_IF_CONFIG_SMALL("Read from a movie source."),
+ .priv_size = sizeof(MovieContext),
+ .priv_class = &movie_class,
+ .init = movie_common_init,
+ .uninit = movie_uninit,
+ .query_formats = movie_query_formats,
+
+ .inputs = NULL,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
+
+#endif /* CONFIG_MOVIE_FILTER */
+
+#if CONFIG_AMOVIE_FILTER
+
+#define amovie_options movie_options
+AVFILTER_DEFINE_CLASS(amovie);
+
+AVFilter ff_avsrc_amovie = {
+ .name = "amovie",
+ .description = NULL_IF_CONFIG_SMALL("Read audio from a movie source."),
+ .priv_size = sizeof(MovieContext),
+ .init = movie_common_init,
+ .uninit = movie_uninit,
+ .query_formats = movie_query_formats,
+
+ .inputs = NULL,
+ .outputs = NULL,
+ .priv_class = &amovie_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
+
+#endif /* CONFIG_AMOVIE_FILTER */
diff --git a/libavfilter/thread.h b/libavfilter/thread.h
index 1cfea3e7ba..5f347e8521 100644
--- a/libavfilter/thread.h
+++ b/libavfilter/thread.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
new file mode 100644
index 0000000000..d80a6e2179
--- /dev/null
+++ b/libavfilter/tinterlace.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2010 Baptiste Coudurier
+ * Copyright (c) 2003 Michael Zucchi <notzed@ximian.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 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
+ * temporal field interlace filter, ported from MPlayer/libmpcodecs
+ */
+#ifndef AVFILTER_TINTERLACE_H
+#define AVFILTER_TINTERLACE_H
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+
+enum TInterlaceMode {
+ MODE_MERGE = 0,
+ MODE_DROP_EVEN,
+ MODE_DROP_ODD,
+ MODE_PAD,
+ MODE_INTERLEAVE_TOP,
+ MODE_INTERLEAVE_BOTTOM,
+ MODE_INTERLACEX2,
+ MODE_NB,
+};
+
+typedef struct {
+ const AVClass *class;
+ int mode; ///< TInterlaceMode, interlace mode selected
+ AVRational preout_time_base;
+ int flags; ///< flags affecting interlacing algorithm
+ int frame; ///< number of the output frame
+ int vsub; ///< chroma vertical subsampling
+ AVFrame *cur;
+ AVFrame *next;
+ uint8_t *black_data[4]; ///< buffer used to fill padded lines
+ int black_linesize[4];
+ void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
+ const uint8_t *srcp_above, const uint8_t *srcp_below);
+} TInterlaceContext;
+
+void ff_tinterlace_init_x86(TInterlaceContext *interlace);
+
+#endif /* AVFILTER_TINTERLACE_H */
diff --git a/libavfilter/transform.c b/libavfilter/transform.c
new file mode 100644
index 0000000000..f92fc4d42f
--- /dev/null
+++ b/libavfilter/transform.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * transform input video
+ */
+
+#include "libavutil/common.h"
+#include "libavutil/avassert.h"
+
+#include "transform.h"
+
+#define INTERPOLATE_METHOD(name) \
+ static uint8_t name(float x, float y, const uint8_t *src, \
+ int width, int height, int stride, uint8_t def)
+
+#define PIXEL(img, x, y, w, h, stride, def) \
+ ((x) < 0 || (y) < 0) ? (def) : \
+ (((x) >= (w) || (y) >= (h)) ? (def) : \
+ img[(x) + (y) * (stride)])
+
+/**
+ * Nearest neighbor interpolation
+ */
+INTERPOLATE_METHOD(interpolate_nearest)
+{
+ return PIXEL(src, (int)(x + 0.5), (int)(y + 0.5), width, height, stride, def);
+}
+
+/**
+ * Bilinear interpolation
+ */
+INTERPOLATE_METHOD(interpolate_bilinear)
+{
+ int x_c, x_f, y_c, y_f;
+ int v1, v2, v3, v4;
+
+ if (x < -1 || x > width || y < -1 || y > height) {
+ return def;
+ } else {
+ x_f = (int)x;
+ x_c = x_f + 1;
+
+ y_f = (int)y;
+ y_c = y_f + 1;
+
+ v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
+ v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
+ v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
+ v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
+
+ return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) +
+ v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y)));
+ }
+}
+
+/**
+ * Biquadratic interpolation
+ */
+INTERPOLATE_METHOD(interpolate_biquadratic)
+{
+ int x_c, x_f, y_c, y_f;
+ uint8_t v1, v2, v3, v4;
+ float f1, f2, f3, f4;
+
+ if (x < - 1 || x > width || y < -1 || y > height)
+ return def;
+ else {
+ x_f = (int)x;
+ x_c = x_f + 1;
+ y_f = (int)y;
+ y_c = y_f + 1;
+
+ v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
+ v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
+ v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
+ v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
+
+ f1 = 1 - sqrt((x_c - x) * (y_c - y));
+ f2 = 1 - sqrt((x_c - x) * (y - y_f));
+ f3 = 1 - sqrt((x - x_f) * (y_c - y));
+ f4 = 1 - sqrt((x - x_f) * (y - y_f));
+ return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4);
+ }
+}
+
+void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix) {
+ matrix[0] = zoom * cos(angle);
+ matrix[1] = -sin(angle);
+ matrix[2] = x_shift;
+ matrix[3] = -matrix[1];
+ matrix[4] = matrix[0];
+ matrix[5] = y_shift;
+ matrix[6] = 0;
+ matrix[7] = 0;
+ matrix[8] = 1;
+}
+
+void avfilter_add_matrix(const float *m1, const float *m2, float *result)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ result[i] = m1[i] + m2[i];
+}
+
+void avfilter_sub_matrix(const float *m1, const float *m2, float *result)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ result[i] = m1[i] - m2[i];
+}
+
+void avfilter_mul_matrix(const float *m1, float scalar, float *result)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ result[i] = m1[i] * scalar;
+}
+
+int avfilter_transform(const uint8_t *src, uint8_t *dst,
+ int src_stride, int dst_stride,
+ int width, int height, const float *matrix,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill)
+{
+ int x, y;
+ float x_s, y_s;
+ uint8_t def = 0;
+ uint8_t (*func)(float, float, const uint8_t *, int, int, int, uint8_t) = NULL;
+
+ switch(interpolate) {
+ case INTERPOLATE_NEAREST:
+ func = interpolate_nearest;
+ break;
+ case INTERPOLATE_BILINEAR:
+ func = interpolate_bilinear;
+ break;
+ case INTERPOLATE_BIQUADRATIC:
+ func = interpolate_biquadratic;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ for (y = 0; y < height; y++) {
+ for(x = 0; x < width; x++) {
+ x_s = x * matrix[0] + y * matrix[1] + matrix[2];
+ y_s = x * matrix[3] + y * matrix[4] + matrix[5];
+
+ switch(fill) {
+ case FILL_ORIGINAL:
+ def = src[y * src_stride + x];
+ break;
+ case FILL_CLAMP:
+ y_s = av_clipf(y_s, 0, height - 1);
+ x_s = av_clipf(x_s, 0, width - 1);
+ def = src[(int)y_s * src_stride + (int)x_s];
+ break;
+ case FILL_MIRROR:
+ x_s = avpriv_mirror(x_s, width-1);
+ y_s = avpriv_mirror(y_s, height-1);
+
+ av_assert2(x_s >= 0 && y_s >= 0);
+ av_assert2(x_s < width && y_s < height);
+ def = src[(int)y_s * src_stride + (int)x_s];
+ }
+
+ dst[y * dst_stride + x] = func(x_s, y_s, src, width, height, src_stride, def);
+ }
+ }
+ return 0;
+}
diff --git a/libavfilter/transform.h b/libavfilter/transform.h
new file mode 100644
index 0000000000..07436bfccb
--- /dev/null
+++ b/libavfilter/transform.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_TRANSFORM_H
+#define AVFILTER_TRANSFORM_H
+
+#include <stdint.h>
+
+/**
+ * @file
+ * transform input video
+ *
+ * All matrices are defined as a single 9-item block of contiguous memory. For
+ * example, the identity matrix would be:
+ *
+ * float *matrix = {1, 0, 0,
+ * 0, 1, 0,
+ * 0, 0, 1};
+ */
+
+enum InterpolateMethod {
+ INTERPOLATE_NEAREST, //< Nearest-neighbor (fast)
+ INTERPOLATE_BILINEAR, //< Bilinear
+ INTERPOLATE_BIQUADRATIC, //< Biquadratic (best)
+ INTERPOLATE_COUNT, //< Number of interpolation methods
+};
+
+// Shortcuts for the fastest and best interpolation methods
+#define INTERPOLATE_DEFAULT INTERPOLATE_BILINEAR
+#define INTERPOLATE_FAST INTERPOLATE_NEAREST
+#define INTERPOLATE_BEST INTERPOLATE_BIQUADRATIC
+
+enum FillMethod {
+ FILL_BLANK, //< Fill zeroes at blank locations
+ FILL_ORIGINAL, //< Original image at blank locations
+ FILL_CLAMP, //< Extruded edge value at blank locations
+ FILL_MIRROR, //< Mirrored edge at blank locations
+ FILL_COUNT, //< Number of edge fill methods
+};
+
+// Shortcuts for fill methods
+#define FILL_DEFAULT FILL_ORIGINAL
+
+/**
+ * Get an affine transformation matrix from a given translation, rotation, and
+ * zoom factor. The matrix will look like:
+ *
+ * [ zoom * cos(angle), -sin(angle), x_shift,
+ * sin(angle), zoom * cos(angle), y_shift,
+ * 0, 0, 1 ]
+ *
+ * @param x_shift horizontal translation
+ * @param y_shift vertical translation
+ * @param angle rotation in radians
+ * @param zoom scale percent (1.0 = 100%)
+ * @param matrix 9-item affine transformation matrix
+ */
+void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix);
+
+/**
+ * Add two matrices together. result = m1 + m2.
+ *
+ * @param m1 9-item transformation matrix
+ * @param m2 9-item transformation matrix
+ * @param result 9-item transformation matrix
+ */
+void avfilter_add_matrix(const float *m1, const float *m2, float *result);
+
+/**
+ * Subtract one matrix from another. result = m1 - m2.
+ *
+ * @param m1 9-item transformation matrix
+ * @param m2 9-item transformation matrix
+ * @param result 9-item transformation matrix
+ */
+void avfilter_sub_matrix(const float *m1, const float *m2, float *result);
+
+/**
+ * Multiply a matrix by a scalar value. result = m1 * scalar.
+ *
+ * @param m1 9-item transformation matrix
+ * @param scalar a number
+ * @param result 9-item transformation matrix
+ */
+void avfilter_mul_matrix(const float *m1, float scalar, float *result);
+
+/**
+ * Do an affine transformation with the given interpolation method. This
+ * multiplies each vector [x,y,1] by the matrix and then interpolates to
+ * get the final value.
+ *
+ * @param src source image
+ * @param dst destination image
+ * @param src_stride source image line size in bytes
+ * @param dst_stride destination image line size in bytes
+ * @param width image width in pixels
+ * @param height image height in pixels
+ * @param matrix 9-item affine transformation matrix
+ * @param interpolate pixel interpolation method
+ * @param fill edge fill method
+ * @return negative on error
+ */
+int avfilter_transform(const uint8_t *src, uint8_t *dst,
+ int src_stride, int dst_stride,
+ int width, int height, const float *matrix,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill);
+
+#endif /* AVFILTER_TRANSFORM_H */
diff --git a/libavfilter/trim.c b/libavfilter/trim.c
index 2b57540460..468dc03ca1 100644
--- a/libavfilter/trim.c
+++ b/libavfilter/trim.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,9 +40,12 @@ typedef struct TrimContext {
/*
* AVOptions
*/
- double duration;
- double start_time, end_time;
+ int64_t duration;
+ int64_t start_time, end_time;
int64_t start_frame, end_frame;
+
+ double duration_dbl;
+ double start_time_dbl, end_time_dbl;
/*
* in the link timebase for video,
* in 1/samplerate for audio
@@ -70,10 +73,9 @@ typedef struct TrimContext {
int64_t next_pts;
int eof;
- int got_output;
} TrimContext;
-static int init(AVFilterContext *ctx)
+static av_cold int init(AVFilterContext *ctx)
{
TrimContext *s = ctx->priv;
@@ -89,52 +91,53 @@ static int config_input(AVFilterLink *inlink)
AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ?
inlink->time_base : (AVRational){ 1, inlink->sample_rate };
- if (s->start_time != DBL_MAX) {
- int64_t start_pts = lrintf(s->start_time / av_q2d(tb));
+ if (s->start_time_dbl != DBL_MAX)
+ s->start_time = s->start_time_dbl * 1e6;
+ if (s->end_time_dbl != DBL_MAX)
+ s->end_time = s->end_time_dbl * 1e6;
+ if (s->duration_dbl != 0)
+ s->duration = s->duration_dbl * 1e6;
+
+ if (s->start_time != INT64_MAX) {
+ int64_t start_pts = av_rescale_q(s->start_time, AV_TIME_BASE_Q, tb);
if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts)
s->start_pts = start_pts;
}
- if (s->end_time != DBL_MAX) {
- int64_t end_pts = lrintf(s->end_time / av_q2d(tb));
+ if (s->end_time != INT64_MAX) {
+ int64_t end_pts = av_rescale_q(s->end_time, AV_TIME_BASE_Q, tb);
if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts)
s->end_pts = end_pts;
}
if (s->duration)
- s->duration_tb = lrintf(s->duration / av_q2d(tb));
+ s->duration_tb = av_rescale_q(s->duration, AV_TIME_BASE_Q, tb);
return 0;
}
-static int request_frame(AVFilterLink *outlink)
+static int config_output(AVFilterLink *outlink)
{
- AVFilterContext *ctx = outlink->src;
- TrimContext *s = ctx->priv;
- int ret;
-
- s->got_output = 0;
- while (!s->got_output) {
- if (s->eof)
- return AVERROR_EOF;
-
- ret = ff_request_frame(ctx->inputs[0]);
- if (ret < 0)
- return ret;
- }
-
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
return 0;
}
#define OFFSET(x) offsetof(TrimContext, x)
#define COMMON_OPTS \
- { "start", "Timestamp in seconds of the first frame that " \
- "should be passed", OFFSET(start_time), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, \
- { "end", "Timestamp in seconds of the first frame that " \
- "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, \
+ { "starti", "Timestamp of the first frame that " \
+ "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \
+ { "endi", "Timestamp of the first frame that " \
+ "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \
{ "start_pts", "Timestamp of the first frame that should be " \
" passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \
{ "end_pts", "Timestamp of the first frame that should be " \
"dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \
- { "duration", "Maximum duration of the output in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, DBL_MAX, FLAGS },
+ { "durationi", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS },
+
+#define COMPAT_OPTS \
+ { "start", "Timestamp in seconds of the first frame that " \
+ "should be passed", OFFSET(start_time_dbl),AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, \
+ { "end", "Timestamp in seconds of the first frame that " \
+ "should be dropped again", OFFSET(end_time_dbl), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS }, \
+ { "duration", "Maximum duration of the output in seconds", OFFSET(duration_dbl), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, DBL_MAX, FLAGS },
#if CONFIG_TRIM_FILTER
@@ -177,13 +180,12 @@ static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
drop = 0;
if (drop) {
- s->eof = 1;
+ s->eof = inlink->closed = 1;
goto drop;
}
}
s->nb_frames++;
- s->got_output = 1;
return ff_filter_frame(ctx->outputs[0], frame);
@@ -193,23 +195,19 @@ drop:
return 0;
}
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption trim_options[] = {
COMMON_OPTS
{ "start_frame", "Number of the first frame that should be passed "
"to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS },
{ "end_frame", "Number of the first frame that should be dropped "
"again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS },
- { NULL },
+ COMPAT_OPTS
+ { NULL }
};
#undef FLAGS
-static const AVClass trim_class = {
- .class_name = "trim",
- .item_name = av_default_item_name,
- .option = trim_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(trim);
static const AVFilterPad trim_inputs[] = {
{
@@ -223,9 +221,9 @@ static const AVFilterPad trim_inputs[] = {
static const AVFilterPad trim_outputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .request_frame = request_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
},
{ NULL }
};
@@ -233,12 +231,9 @@ static const AVFilterPad trim_outputs[] = {
AVFilter ff_vf_trim = {
.name = "trim",
.description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."),
-
.init = init,
-
.priv_size = sizeof(TrimContext),
.priv_class = &trim_class,
-
.inputs = trim_inputs,
.outputs = trim_outputs,
};
@@ -249,7 +244,7 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
TrimContext *s = ctx->priv;
- int64_t start_sample, end_sample = frame->nb_samples;
+ int64_t start_sample, end_sample;
int64_t pts;
int drop;
@@ -317,7 +312,7 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
if (drop) {
- s->eof = 1;
+ s->eof = inlink->closed = 1;
goto drop;
}
}
@@ -325,7 +320,7 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
s->nb_samples += frame->nb_samples;
start_sample = FFMAX(0, start_sample);
end_sample = FFMIN(frame->nb_samples, end_sample);
- av_assert0(start_sample < end_sample);
+ av_assert0(start_sample < end_sample || (start_sample == end_sample && !frame->nb_samples));
if (start_sample) {
AVFrame *out = ff_get_audio_buffer(ctx->outputs[0], end_sample - start_sample);
@@ -336,7 +331,7 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
av_frame_copy_props(out, frame);
av_samples_copy(out->extended_data, frame->extended_data, 0, start_sample,
- out->nb_samples, av_get_channel_layout_nb_channels(frame->channel_layout),
+ out->nb_samples, inlink->channels,
frame->format);
if (out->pts != AV_NOPTS_VALUE)
out->pts += av_rescale_q(start_sample, (AVRational){ 1, out->sample_rate },
@@ -347,7 +342,6 @@ static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
} else
frame->nb_samples = end_sample;
- s->got_output = 1;
return ff_filter_frame(ctx->outputs[0], frame);
drop:
@@ -356,23 +350,19 @@ drop:
return 0;
}
-#define FLAGS AV_OPT_FLAG_AUDIO_PARAM
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption atrim_options[] = {
COMMON_OPTS
{ "start_sample", "Number of the first audio sample that should be "
"passed to the output", OFFSET(start_sample), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS },
{ "end_sample", "Number of the first audio sample that should be "
"dropped again", OFFSET(end_sample), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS },
- { NULL },
+ COMPAT_OPTS
+ { NULL }
};
#undef FLAGS
-static const AVClass atrim_class = {
- .class_name = "atrim",
- .item_name = av_default_item_name,
- .option = atrim_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(atrim);
static const AVFilterPad atrim_inputs[] = {
{
@@ -386,9 +376,9 @@ static const AVFilterPad atrim_inputs[] = {
static const AVFilterPad atrim_outputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_AUDIO,
- .request_frame = request_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
},
{ NULL }
};
@@ -396,12 +386,9 @@ static const AVFilterPad atrim_outputs[] = {
AVFilter ff_af_atrim = {
.name = "atrim",
.description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."),
-
.init = init,
-
.priv_size = sizeof(TrimContext),
.priv_class = &atrim_class,
-
.inputs = atrim_inputs,
.outputs = atrim_outputs,
};
diff --git a/libavfilter/unsharp.h b/libavfilter/unsharp.h
new file mode 100644
index 0000000000..fc651c0654
--- /dev/null
+++ b/libavfilter/unsharp.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ * 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"
+#if CONFIG_OPENCL
+#include "libavutil/opencl.h"
+#endif
+
+#define MIN_MATRIX_SIZE 3
+#define MAX_MATRIX_SIZE 63
+
+#if CONFIG_OPENCL
+
+typedef struct {
+ cl_command_queue command_queue;
+ cl_program program;
+ cl_kernel kernel_default;
+ cl_kernel kernel_luma;
+ cl_kernel kernel_chroma;
+ cl_mem cl_luma_mask;
+ cl_mem cl_chroma_mask;
+ cl_mem cl_luma_mask_x;
+ cl_mem cl_chroma_mask_x;
+ cl_mem cl_luma_mask_y;
+ cl_mem cl_chroma_mask_y;
+ int in_plane_size[8];
+ int out_plane_size[8];
+ int plane_num;
+ cl_mem cl_inbuf;
+ size_t cl_inbuf_size;
+ cl_mem cl_outbuf;
+ size_t cl_outbuf_size;
+ int use_fast_kernels;
+} UnsharpOpenclContext;
+
+#endif
+
+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 *sc[MAX_MATRIX_SIZE - 1]; ///< finite state machine storage
+} UnsharpFilterParam;
+
+typedef struct UnsharpContext {
+ const AVClass *class;
+ int lmsize_x, lmsize_y, cmsize_x, cmsize_y;
+ float lamount, camount;
+ UnsharpFilterParam luma; ///< luma parameters (width, height, amount)
+ UnsharpFilterParam chroma; ///< chroma parameters (width, height, amount)
+ int hsub, vsub;
+ int opencl;
+#if CONFIG_OPENCL
+ UnsharpOpenclContext opencl_ctx;
+#endif
+ int (* apply_unsharp)(AVFilterContext *ctx, AVFrame *in, AVFrame *out);
+} UnsharpContext;
+
+#endif /* AVFILTER_UNSHARP_H */
diff --git a/libavfilter/unsharp_opencl.c b/libavfilter/unsharp_opencl.c
new file mode 100644
index 0000000000..2cc0704afa
--- /dev/null
+++ b/libavfilter/unsharp_opencl.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ * Copyright (C) 2013 Lenny Wang
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * unsharp input video
+ */
+
+#include "unsharp_opencl.h"
+#include "libavutil/common.h"
+#include "libavutil/opencl_internal.h"
+
+#define PLANE_NUM 3
+#define ROUND_TO_16(a) (((((a) - 1)/16)+1)*16)
+
+static inline void add_mask_counter(uint32_t *dst, uint32_t *counter1, uint32_t *counter2, int len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ dst[i] = counter1[i] + counter2[i];
+ }
+}
+
+static int compute_mask(int step, uint32_t *mask)
+{
+ int i, z, ret = 0;
+ int counter_size = sizeof(uint32_t) * (2 * step + 1);
+ uint32_t *temp1_counter, *temp2_counter, **counter;
+ temp1_counter = av_mallocz(counter_size);
+ if (!temp1_counter) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ temp2_counter = av_mallocz(counter_size);
+ if (!temp2_counter) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ counter = av_mallocz_array(2 * step + 1, sizeof(uint32_t *));
+ if (!counter) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ for (i = 0; i < 2 * step + 1; i++) {
+ counter[i] = av_mallocz(counter_size);
+ if (!counter[i]) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ }
+ for (i = 0; i < 2 * step + 1; i++) {
+ memset(temp1_counter, 0, counter_size);
+ temp1_counter[i] = 1;
+ for (z = 0; z < step * 2; z += 2) {
+ add_mask_counter(temp2_counter, counter[z], temp1_counter, step * 2);
+ memcpy(counter[z], temp1_counter, counter_size);
+ add_mask_counter(temp1_counter, counter[z + 1], temp2_counter, step * 2);
+ memcpy(counter[z + 1], temp2_counter, counter_size);
+ }
+ }
+ memcpy(mask, temp1_counter, counter_size);
+end:
+ av_freep(&temp1_counter);
+ av_freep(&temp2_counter);
+ for (i = 0; i < 2 * step + 1; i++) {
+ av_freep(&counter[i]);
+ }
+ av_freep(&counter);
+ return ret;
+}
+
+static int copy_separable_masks(cl_mem cl_mask_x, cl_mem cl_mask_y, int step_x, int step_y)
+{
+ int ret = 0;
+ uint32_t *mask_x, *mask_y;
+ size_t size_mask_x = sizeof(uint32_t) * (2 * step_x + 1);
+ size_t size_mask_y = sizeof(uint32_t) * (2 * step_y + 1);
+ mask_x = av_mallocz_array(2 * step_x + 1, sizeof(uint32_t));
+ if (!mask_x) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ mask_y = av_mallocz_array(2 * step_y + 1, sizeof(uint32_t));
+ if (!mask_y) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ ret = compute_mask(step_x, mask_x);
+ if (ret < 0)
+ goto end;
+ ret = compute_mask(step_y, mask_y);
+ if (ret < 0)
+ goto end;
+
+ ret = av_opencl_buffer_write(cl_mask_x, (uint8_t *)mask_x, size_mask_x);
+ ret = av_opencl_buffer_write(cl_mask_y, (uint8_t *)mask_y, size_mask_y);
+end:
+ av_freep(&mask_x);
+ av_freep(&mask_y);
+
+ return ret;
+}
+
+static int generate_mask(AVFilterContext *ctx)
+{
+ cl_mem masks[4];
+ cl_mem mask_matrix[2];
+ int i, ret = 0, step_x[2], step_y[2];
+
+ UnsharpContext *unsharp = ctx->priv;
+ mask_matrix[0] = unsharp->opencl_ctx.cl_luma_mask;
+ mask_matrix[1] = unsharp->opencl_ctx.cl_chroma_mask;
+ masks[0] = unsharp->opencl_ctx.cl_luma_mask_x;
+ masks[1] = unsharp->opencl_ctx.cl_luma_mask_y;
+ masks[2] = unsharp->opencl_ctx.cl_chroma_mask_x;
+ masks[3] = unsharp->opencl_ctx.cl_chroma_mask_y;
+ step_x[0] = unsharp->luma.steps_x;
+ step_x[1] = unsharp->chroma.steps_x;
+ step_y[0] = unsharp->luma.steps_y;
+ step_y[1] = unsharp->chroma.steps_y;
+
+ /* use default kernel if any matrix dim larger than 8 due to limited local mem size */
+ if (step_x[0]>8 || step_x[1]>8 || step_y[0]>8 || step_y[1]>8)
+ unsharp->opencl_ctx.use_fast_kernels = 0;
+ else
+ unsharp->opencl_ctx.use_fast_kernels = 1;
+
+ if (!masks[0] || !masks[1] || !masks[2] || !masks[3]) {
+ av_log(ctx, AV_LOG_ERROR, "Luma mask and chroma mask should not be NULL\n");
+ return AVERROR(EINVAL);
+ }
+ if (!mask_matrix[0] || !mask_matrix[1]) {
+ av_log(ctx, AV_LOG_ERROR, "Luma mask and chroma mask should not be NULL\n");
+ return AVERROR(EINVAL);
+ }
+ for (i = 0; i < 2; i++) {
+ ret = copy_separable_masks(masks[2*i], masks[2*i+1], step_x[i], step_y[i]);
+ if (ret < 0)
+ return ret;
+ }
+ return ret;
+}
+
+int ff_opencl_apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out)
+{
+ int ret;
+ AVFilterLink *link = ctx->inputs[0];
+ UnsharpContext *unsharp = ctx->priv;
+ cl_int status;
+ FFOpenclParam kernel1 = {0};
+ FFOpenclParam kernel2 = {0};
+ int width = link->w;
+ int height = link->h;
+ int cw = FF_CEIL_RSHIFT(link->w, unsharp->hsub);
+ int ch = FF_CEIL_RSHIFT(link->h, unsharp->vsub);
+ size_t globalWorkSize1d = width * height + 2 * ch * cw;
+ size_t globalWorkSize2dLuma[2];
+ size_t globalWorkSize2dChroma[2];
+ size_t localWorkSize2d[2] = {16, 16};
+
+ if (unsharp->opencl_ctx.use_fast_kernels) {
+ globalWorkSize2dLuma[0] = (size_t)ROUND_TO_16(width);
+ globalWorkSize2dLuma[1] = (size_t)ROUND_TO_16(height);
+ globalWorkSize2dChroma[0] = (size_t)ROUND_TO_16(cw);
+ globalWorkSize2dChroma[1] = (size_t)(2*ROUND_TO_16(ch));
+
+ kernel1.ctx = ctx;
+ kernel1.kernel = unsharp->opencl_ctx.kernel_luma;
+ ret = avpriv_opencl_set_parameter(&kernel1,
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask_x),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask_y),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.amount),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.scalebits),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.halfscale),
+ FF_OPENCL_PARAM_INFO(in->linesize[0]),
+ FF_OPENCL_PARAM_INFO(out->linesize[0]),
+ FF_OPENCL_PARAM_INFO(width),
+ FF_OPENCL_PARAM_INFO(height),
+ NULL);
+ if (ret < 0)
+ return ret;
+
+ kernel2.ctx = ctx;
+ kernel2.kernel = unsharp->opencl_ctx.kernel_chroma;
+ ret = avpriv_opencl_set_parameter(&kernel2,
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask_x),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask_y),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.amount),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.scalebits),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.halfscale),
+ FF_OPENCL_PARAM_INFO(in->linesize[0]),
+ FF_OPENCL_PARAM_INFO(in->linesize[1]),
+ FF_OPENCL_PARAM_INFO(out->linesize[0]),
+ FF_OPENCL_PARAM_INFO(out->linesize[1]),
+ FF_OPENCL_PARAM_INFO(link->w),
+ FF_OPENCL_PARAM_INFO(link->h),
+ FF_OPENCL_PARAM_INFO(cw),
+ FF_OPENCL_PARAM_INFO(ch),
+ NULL);
+ if (ret < 0)
+ return ret;
+ status = clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue,
+ unsharp->opencl_ctx.kernel_luma, 2, NULL,
+ globalWorkSize2dLuma, localWorkSize2d, 0, NULL, NULL);
+ status |=clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue,
+ unsharp->opencl_ctx.kernel_chroma, 2, NULL,
+ globalWorkSize2dChroma, localWorkSize2d, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ } else { /* use default kernel */
+ kernel1.ctx = ctx;
+ kernel1.kernel = unsharp->opencl_ctx.kernel_default;
+
+ ret = avpriv_opencl_set_parameter(&kernel1,
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask),
+ FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.amount),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.amount),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.steps_x),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.steps_y),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.steps_x),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.steps_y),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.scalebits),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.scalebits),
+ FF_OPENCL_PARAM_INFO(unsharp->luma.halfscale),
+ FF_OPENCL_PARAM_INFO(unsharp->chroma.halfscale),
+ FF_OPENCL_PARAM_INFO(in->linesize[0]),
+ FF_OPENCL_PARAM_INFO(in->linesize[1]),
+ FF_OPENCL_PARAM_INFO(out->linesize[0]),
+ FF_OPENCL_PARAM_INFO(out->linesize[1]),
+ FF_OPENCL_PARAM_INFO(link->h),
+ FF_OPENCL_PARAM_INFO(link->w),
+ FF_OPENCL_PARAM_INFO(ch),
+ FF_OPENCL_PARAM_INFO(cw),
+ NULL);
+ if (ret < 0)
+ return ret;
+ status = clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue,
+ unsharp->opencl_ctx.kernel_default, 1, NULL,
+ &globalWorkSize1d, NULL, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ }
+ //blocking map is suffficient, no need for clFinish
+ //clFinish(unsharp->opencl_ctx.command_queue);
+
+ return av_opencl_buffer_read_image(out->data, unsharp->opencl_ctx.out_plane_size,
+ unsharp->opencl_ctx.plane_num, unsharp->opencl_ctx.cl_outbuf,
+ unsharp->opencl_ctx.cl_outbuf_size);
+}
+
+int ff_opencl_unsharp_init(AVFilterContext *ctx)
+{
+ int ret = 0;
+ char build_opts[96];
+ UnsharpContext *unsharp = ctx->priv;
+ ret = av_opencl_init(NULL);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask,
+ sizeof(uint32_t) * (2 * unsharp->luma.steps_x + 1) * (2 * unsharp->luma.steps_y + 1),
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask,
+ sizeof(uint32_t) * (2 * unsharp->chroma.steps_x + 1) * (2 * unsharp->chroma.steps_y + 1),
+ CL_MEM_READ_ONLY, NULL);
+ // separable filters
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask_x,
+ sizeof(uint32_t) * (2 * unsharp->luma.steps_x + 1),
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask_y,
+ sizeof(uint32_t) * (2 * unsharp->luma.steps_y + 1),
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask_x,
+ sizeof(uint32_t) * (2 * unsharp->chroma.steps_x + 1),
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask_y,
+ sizeof(uint32_t) * (2 * unsharp->chroma.steps_y + 1),
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ ret = generate_mask(ctx);
+ if (ret < 0)
+ return ret;
+ unsharp->opencl_ctx.plane_num = PLANE_NUM;
+ unsharp->opencl_ctx.command_queue = av_opencl_get_command_queue();
+ if (!unsharp->opencl_ctx.command_queue) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to get OpenCL command queue in filter 'unsharp'\n");
+ return AVERROR(EINVAL);
+ }
+ snprintf(build_opts, 96, "-D LU_RADIUS_X=%d -D LU_RADIUS_Y=%d -D CH_RADIUS_X=%d -D CH_RADIUS_Y=%d",
+ 2*unsharp->luma.steps_x+1, 2*unsharp->luma.steps_y+1, 2*unsharp->chroma.steps_x+1, 2*unsharp->chroma.steps_y+1);
+ unsharp->opencl_ctx.program = av_opencl_compile("unsharp", build_opts);
+ if (!unsharp->opencl_ctx.program) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to compile program 'unsharp'\n");
+ return AVERROR(EINVAL);
+ }
+ if (unsharp->opencl_ctx.use_fast_kernels) {
+ if (!unsharp->opencl_ctx.kernel_luma) {
+ unsharp->opencl_ctx.kernel_luma = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_luma", &ret);
+ if (ret != CL_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_luma'\n");
+ return ret;
+ }
+ }
+ if (!unsharp->opencl_ctx.kernel_chroma) {
+ unsharp->opencl_ctx.kernel_chroma = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_chroma", &ret);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_chroma'\n");
+ return ret;
+ }
+ }
+ }
+ else {
+ if (!unsharp->opencl_ctx.kernel_default) {
+ unsharp->opencl_ctx.kernel_default = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_default", &ret);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_default'\n");
+ return ret;
+ }
+ }
+ }
+ return ret;
+}
+
+void ff_opencl_unsharp_uninit(AVFilterContext *ctx)
+{
+ UnsharpContext *unsharp = ctx->priv;
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_inbuf);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_outbuf);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask_x);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask_x);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask_y);
+ av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask_y);
+ clReleaseKernel(unsharp->opencl_ctx.kernel_default);
+ clReleaseKernel(unsharp->opencl_ctx.kernel_luma);
+ clReleaseKernel(unsharp->opencl_ctx.kernel_chroma);
+ clReleaseProgram(unsharp->opencl_ctx.program);
+ unsharp->opencl_ctx.command_queue = NULL;
+ av_opencl_uninit();
+}
+
+int ff_opencl_unsharp_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out)
+{
+ int ret = 0;
+ AVFilterLink *link = ctx->inputs[0];
+ UnsharpContext *unsharp = ctx->priv;
+ int ch = FF_CEIL_RSHIFT(link->h, unsharp->vsub);
+
+ if ((!unsharp->opencl_ctx.cl_inbuf) || (!unsharp->opencl_ctx.cl_outbuf)) {
+ unsharp->opencl_ctx.in_plane_size[0] = (in->linesize[0] * in->height);
+ unsharp->opencl_ctx.in_plane_size[1] = (in->linesize[1] * ch);
+ unsharp->opencl_ctx.in_plane_size[2] = (in->linesize[2] * ch);
+ unsharp->opencl_ctx.out_plane_size[0] = (out->linesize[0] * out->height);
+ unsharp->opencl_ctx.out_plane_size[1] = (out->linesize[1] * ch);
+ unsharp->opencl_ctx.out_plane_size[2] = (out->linesize[2] * ch);
+ unsharp->opencl_ctx.cl_inbuf_size = unsharp->opencl_ctx.in_plane_size[0] +
+ unsharp->opencl_ctx.in_plane_size[1] +
+ unsharp->opencl_ctx.in_plane_size[2];
+ unsharp->opencl_ctx.cl_outbuf_size = unsharp->opencl_ctx.out_plane_size[0] +
+ unsharp->opencl_ctx.out_plane_size[1] +
+ unsharp->opencl_ctx.out_plane_size[2];
+ if (!unsharp->opencl_ctx.cl_inbuf) {
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_inbuf,
+ unsharp->opencl_ctx.cl_inbuf_size,
+ CL_MEM_READ_ONLY, NULL);
+ if (ret < 0)
+ return ret;
+ }
+ if (!unsharp->opencl_ctx.cl_outbuf) {
+ ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_outbuf,
+ unsharp->opencl_ctx.cl_outbuf_size,
+ CL_MEM_READ_WRITE, NULL);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ return av_opencl_buffer_write_image(unsharp->opencl_ctx.cl_inbuf,
+ unsharp->opencl_ctx.cl_inbuf_size,
+ 0, in->data, unsharp->opencl_ctx.in_plane_size,
+ unsharp->opencl_ctx.plane_num);
+}
diff --git a/libavfilter/unsharp_opencl.h b/libavfilter/unsharp_opencl.h
new file mode 100644
index 0000000000..3aefab62e0
--- /dev/null
+++ b/libavfilter/unsharp_opencl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_UNSHARP_OPENCL_H
+#define AVFILTER_UNSHARP_OPENCL_H
+
+#include "unsharp.h"
+
+int ff_opencl_unsharp_init(AVFilterContext *ctx);
+
+void ff_opencl_unsharp_uninit(AVFilterContext *ctx);
+
+int ff_opencl_unsharp_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out);
+
+int ff_opencl_apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out);
+
+#endif /* AVFILTER_UNSHARP_OPENCL_H */
diff --git a/libavfilter/unsharp_opencl_kernel.h b/libavfilter/unsharp_opencl_kernel.h
new file mode 100644
index 0000000000..307d0f1814
--- /dev/null
+++ b/libavfilter/unsharp_opencl_kernel.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2013 Wei Gao <weigao@multicorewareinc.com>
+ * 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_OPENCL_KERNEL_H
+#define AVFILTER_UNSHARP_OPENCL_KERNEL_H
+
+#include "libavutil/opencl.h"
+
+const char *ff_kernel_unsharp_opencl = AV_OPENCL_KERNEL(
+inline unsigned char clip_uint8(int a)
+{
+ if (a & (~0xFF))
+ return (-a)>>31;
+ else
+ return a;
+}
+
+kernel void unsharp_luma(
+ global unsigned char *src,
+ global unsigned char *dst,
+ global int *mask_x,
+ global int *mask_y,
+ int amount,
+ int scalebits,
+ int halfscale,
+ int src_stride,
+ int dst_stride,
+ int width,
+ int height)
+{
+ int2 threadIdx, blockIdx, globalIdx;
+ threadIdx.x = get_local_id(0);
+ threadIdx.y = get_local_id(1);
+ blockIdx.x = get_group_id(0);
+ blockIdx.y = get_group_id(1);
+ globalIdx.x = get_global_id(0);
+ globalIdx.y = get_global_id(1);
+
+ if (!amount) {
+ if (globalIdx.x < width && globalIdx.y < height)
+ dst[globalIdx.x + globalIdx.y*dst_stride] = src[globalIdx.x + globalIdx.y*src_stride];
+ return;
+ }
+
+ local unsigned int l[32][32];
+ local unsigned int lcx[LU_RADIUS_X];
+ local unsigned int lcy[LU_RADIUS_Y];
+ int indexIx, indexIy, i, j;
+
+ //load up tile: actual workspace + halo of 8 points in x and y \n
+ for(i = 0; i <= 1; i++) {
+ indexIy = -8 + (blockIdx.y + i) * 16 + threadIdx.y;
+ indexIy = indexIy < 0 ? 0 : indexIy;
+ indexIy = indexIy >= height ? height - 1: indexIy;
+ for(j = 0; j <= 1; j++) {
+ indexIx = -8 + (blockIdx.x + j) * 16 + threadIdx.x;
+ indexIx = indexIx < 0 ? 0 : indexIx;
+ indexIx = indexIx >= width ? width - 1: indexIx;
+ l[i*16 + threadIdx.y][j*16 + threadIdx.x] = src[indexIy*src_stride + indexIx];
+ }
+ }
+
+ int indexL = threadIdx.y*16 + threadIdx.x;
+ if (indexL < LU_RADIUS_X)
+ lcx[indexL] = mask_x[indexL];
+ if (indexL < LU_RADIUS_Y)
+ lcy[indexL] = mask_y[indexL];
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ //needed for unsharp mask application in the end \n
+ int orig_value = (int)l[threadIdx.y + 8][threadIdx.x + 8];
+
+ int idx, idy, maskIndex;
+ int temp[2] = {0};
+ int steps_x = (LU_RADIUS_X-1)/2;
+ int steps_y = (LU_RADIUS_Y-1)/2;
+
+ // compute the actual workspace + left&right halos \n
+ \n#pragma unroll\n
+ for (j = 0; j <=1; j++) {
+ //extra work to cover left and right halos \n
+ idx = 16*j + threadIdx.x;
+ \n#pragma unroll\n
+ for (i = -steps_y; i <= steps_y; i++) {
+ idy = 8 + i + threadIdx.y;
+ maskIndex = (i + steps_y);
+ temp[j] += (int)l[idy][idx] * lcy[maskIndex];
+ }
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+ //save results from the vertical filter in local memory \n
+ idy = 8 + threadIdx.y;
+ \n#pragma unroll\n
+ for (j = 0; j <=1; j++) {
+ idx = 16*j + threadIdx.x;
+ l[idy][idx] = temp[j];
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ //compute results with the horizontal filter \n
+ int sum = 0;
+ idy = 8 + threadIdx.y;
+ \n#pragma unroll\n
+ for (j = -steps_x; j <= steps_x; j++) {
+ idx = 8 + j + threadIdx.x;
+ maskIndex = j + steps_x;
+ sum += (int)l[idy][idx] * lcx[maskIndex];
+ }
+
+ int res = orig_value + (((orig_value - (int)((sum + halfscale) >> scalebits)) * amount) >> 16);
+
+ if (globalIdx.x < width && globalIdx.y < height)
+ dst[globalIdx.x + globalIdx.y*dst_stride] = clip_uint8(res);
+}
+
+kernel void unsharp_chroma(
+ global unsigned char *src_y,
+ global unsigned char *dst_y,
+ global int *mask_x,
+ global int *mask_y,
+ int amount,
+ int scalebits,
+ int halfscale,
+ int src_stride_lu,
+ int src_stride_ch,
+ int dst_stride_lu,
+ int dst_stride_ch,
+ int width,
+ int height,
+ int cw,
+ int ch)
+{
+ global unsigned char *dst_u = dst_y + height * dst_stride_lu;
+ global unsigned char *dst_v = dst_u + ch * dst_stride_ch;
+ global unsigned char *src_u = src_y + height * src_stride_lu;
+ global unsigned char *src_v = src_u + ch * src_stride_ch;
+ int2 threadIdx, blockIdx, globalIdx;
+ threadIdx.x = get_local_id(0);
+ threadIdx.y = get_local_id(1);
+ blockIdx.x = get_group_id(0);
+ blockIdx.y = get_group_id(1);
+ globalIdx.x = get_global_id(0);
+ globalIdx.y = get_global_id(1);
+ int padch = get_global_size(1)/2;
+ global unsigned char *src = globalIdx.y>=padch ? src_v : src_u;
+ global unsigned char *dst = globalIdx.y>=padch ? dst_v : dst_u;
+
+ blockIdx.y = globalIdx.y>=padch ? blockIdx.y - get_num_groups(1)/2 : blockIdx.y;
+ globalIdx.y = globalIdx.y>=padch ? globalIdx.y - padch : globalIdx.y;
+
+ if (!amount) {
+ if (globalIdx.x < cw && globalIdx.y < ch)
+ dst[globalIdx.x + globalIdx.y*dst_stride_ch] = src[globalIdx.x + globalIdx.y*src_stride_ch];
+ return;
+ }
+
+ local unsigned int l[32][32];
+ local unsigned int lcx[CH_RADIUS_X];
+ local unsigned int lcy[CH_RADIUS_Y];
+ int indexIx, indexIy, i, j;
+ for(i = 0; i <= 1; i++) {
+ indexIy = -8 + (blockIdx.y + i) * 16 + threadIdx.y;
+ indexIy = indexIy < 0 ? 0 : indexIy;
+ indexIy = indexIy >= ch ? ch - 1: indexIy;
+ for(j = 0; j <= 1; j++) {
+ indexIx = -8 + (blockIdx.x + j) * 16 + threadIdx.x;
+ indexIx = indexIx < 0 ? 0 : indexIx;
+ indexIx = indexIx >= cw ? cw - 1: indexIx;
+ l[i*16 + threadIdx.y][j*16 + threadIdx.x] = src[indexIy * src_stride_ch + indexIx];
+ }
+ }
+
+ int indexL = threadIdx.y*16 + threadIdx.x;
+ if (indexL < CH_RADIUS_X)
+ lcx[indexL] = mask_x[indexL];
+ if (indexL < CH_RADIUS_Y)
+ lcy[indexL] = mask_y[indexL];
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ int orig_value = (int)l[threadIdx.y + 8][threadIdx.x + 8];
+
+ int idx, idy, maskIndex;
+ int steps_x = CH_RADIUS_X/2;
+ int steps_y = CH_RADIUS_Y/2;
+ int temp[2] = {0,0};
+
+ \n#pragma unroll\n
+ for (j = 0; j <= 1; j++) {
+ idx = 16*j + threadIdx.x;
+ \n#pragma unroll\n
+ for (i = -steps_y; i <= steps_y; i++) {
+ idy = 8 + i + threadIdx.y;
+ maskIndex = i + steps_y;
+ temp[j] += (int)l[idy][idx] * lcy[maskIndex];
+ }
+ }
+
+ barrier(CLK_LOCAL_MEM_FENCE);
+ idy = 8 + threadIdx.y;
+ \n#pragma unroll\n
+ for (j = 0; j <= 1; j++) {
+ idx = 16*j + threadIdx.x;
+ l[idy][idx] = temp[j];
+ }
+ barrier(CLK_LOCAL_MEM_FENCE);
+
+ //compute results with the horizontal filter \n
+ int sum = 0;
+ idy = 8 + threadIdx.y;
+ \n#pragma unroll\n
+ for (j = -steps_x; j <= steps_x; j++) {
+ idx = 8 + j + threadIdx.x;
+ maskIndex = j + steps_x;
+ sum += (int)l[idy][idx] * lcx[maskIndex];
+ }
+
+ int res = orig_value + (((orig_value - (int)((sum + halfscale) >> scalebits)) * amount) >> 16);
+
+ if (globalIdx.x < cw && globalIdx.y < ch)
+ dst[globalIdx.x + globalIdx.y*dst_stride_ch] = clip_uint8(res);
+}
+
+kernel void unsharp_default(global unsigned char *src,
+ global unsigned char *dst,
+ const global unsigned int *mask_lu,
+ const global unsigned int *mask_ch,
+ int amount_lu,
+ int amount_ch,
+ int step_x_lu,
+ int step_y_lu,
+ int step_x_ch,
+ int step_y_ch,
+ int scalebits_lu,
+ int scalebits_ch,
+ int halfscale_lu,
+ int halfscale_ch,
+ int src_stride_lu,
+ int src_stride_ch,
+ int dst_stride_lu,
+ int dst_stride_ch,
+ int height,
+ int width,
+ int ch,
+ int cw)
+{
+ global unsigned char *dst_y = dst;
+ global unsigned char *dst_u = dst_y + height * dst_stride_lu;
+ global unsigned char *dst_v = dst_u + ch * dst_stride_ch;
+
+ global unsigned char *src_y = src;
+ global unsigned char *src_u = src_y + height * src_stride_lu;
+ global unsigned char *src_v = src_u + ch * src_stride_ch;
+
+ global unsigned char *temp_dst;
+ global unsigned char *temp_src;
+ const global unsigned int *temp_mask;
+ int global_id = get_global_id(0);
+ int i, j, x, y, temp_src_stride, temp_dst_stride, temp_height, temp_width, temp_steps_x, temp_steps_y,
+ temp_amount, temp_scalebits, temp_halfscale, sum, idx_x, idx_y, temp, res;
+ if (global_id < width * height) {
+ y = global_id / width;
+ x = global_id % width;
+ temp_dst = dst_y;
+ temp_src = src_y;
+ temp_src_stride = src_stride_lu;
+ temp_dst_stride = dst_stride_lu;
+ temp_height = height;
+ temp_width = width;
+ temp_steps_x = step_x_lu;
+ temp_steps_y = step_y_lu;
+ temp_mask = mask_lu;
+ temp_amount = amount_lu;
+ temp_scalebits = scalebits_lu;
+ temp_halfscale = halfscale_lu;
+ } else if ((global_id >= width * height) && (global_id < width * height + ch * cw)) {
+ y = (global_id - width * height) / cw;
+ x = (global_id - width * height) % cw;
+ temp_dst = dst_u;
+ temp_src = src_u;
+ temp_src_stride = src_stride_ch;
+ temp_dst_stride = dst_stride_ch;
+ temp_height = ch;
+ temp_width = cw;
+ temp_steps_x = step_x_ch;
+ temp_steps_y = step_y_ch;
+ temp_mask = mask_ch;
+ temp_amount = amount_ch;
+ temp_scalebits = scalebits_ch;
+ temp_halfscale = halfscale_ch;
+ } else {
+ y = (global_id - width * height - ch * cw) / cw;
+ x = (global_id - width * height - ch * cw) % cw;
+ temp_dst = dst_v;
+ temp_src = src_v;
+ temp_src_stride = src_stride_ch;
+ temp_dst_stride = dst_stride_ch;
+ temp_height = ch;
+ temp_width = cw;
+ temp_steps_x = step_x_ch;
+ temp_steps_y = step_y_ch;
+ temp_mask = mask_ch;
+ temp_amount = amount_ch;
+ temp_scalebits = scalebits_ch;
+ temp_halfscale = halfscale_ch;
+ }
+ if (temp_amount) {
+ sum = 0;
+ for (j = 0; j <= 2 * temp_steps_y; j++) {
+ idx_y = (y - temp_steps_y + j) <= 0 ? 0 : (y - temp_steps_y + j) >= temp_height ? temp_height-1 : y - temp_steps_y + j;
+ for (i = 0; i <= 2 * temp_steps_x; i++) {
+ idx_x = (x - temp_steps_x + i) <= 0 ? 0 : (x - temp_steps_x + i) >= temp_width ? temp_width-1 : x - temp_steps_x + i;
+ sum += temp_mask[i + j * (2 * temp_steps_x + 1)] * temp_src[idx_x + idx_y * temp_src_stride];
+ }
+ }
+ temp = (int)temp_src[x + y * temp_src_stride];
+ res = temp + (((temp - (int)((sum + temp_halfscale) >> temp_scalebits)) * temp_amount) >> 16);
+ temp_dst[x + y * temp_dst_stride] = clip_uint8(res);
+ } else {
+ temp_dst[x + y * temp_dst_stride] = temp_src[x + y * temp_src_stride];
+ }
+}
+);
+
+#endif /* AVFILTER_UNSHARP_OPENCL_KERNEL_H */
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 70b08e5215..bf7275f7b9 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -1,20 +1,20 @@
/*
* Version macros.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,8 +30,8 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 5
-#define LIBAVFILTER_VERSION_MINOR 0
-#define LIBAVFILTER_VERSION_MICRO 0
+#define LIBAVFILTER_VERSION_MINOR 16
+#define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \
@@ -41,6 +41,8 @@
LIBAVFILTER_VERSION_MICRO)
#define LIBAVFILTER_BUILD LIBAVFILTER_VERSION_INT
+#define LIBAVFILTER_IDENT "Lavfi" AV_STRINGIFY(LIBAVFILTER_VERSION)
+
/**
* FF_API_* defines may be placed below to indicate public API that will be
* dropped at a future version bump. The defines themselves are not part of
@@ -68,6 +70,9 @@
#ifndef FF_API_OLD_FILTER_REGISTER
#define FF_API_OLD_FILTER_REGISTER (LIBAVFILTER_VERSION_MAJOR < 6)
#endif
+#ifndef FF_API_OLD_GRAPH_PARSE
+#define FF_API_OLD_GRAPH_PARSE (LIBAVFILTER_VERSION_MAJOR < 5)
+#endif
#ifndef FF_API_NOCONST_GET_NAME
#define FF_API_NOCONST_GET_NAME (LIBAVFILTER_VERSION_MAJOR < 6)
#endif
diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c
new file mode 100644
index 0000000000..5f0da35eba
--- /dev/null
+++ b/libavfilter/vf_alphamerge.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012 Steven Robertson
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * copy an alpha component from another video's luma
+ */
+
+#include <string.h>
+
+#include "libavutil/pixfmt.h"
+#include "avfilter.h"
+#include "bufferqueue.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum { Y, U, V, A };
+
+typedef struct {
+ int frame_requested;
+ int is_packed_rgb;
+ uint8_t rgba_map[4];
+ struct FFBufQueue queue_main;
+ struct FFBufQueue queue_alpha;
+} AlphaMergeContext;
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AlphaMergeContext *merge = ctx->priv;
+ ff_bufqueue_discard_all(&merge->queue_main);
+ ff_bufqueue_discard_all(&merge->queue_alpha);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat main_fmts[] = {
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat alpha_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
+ AVFilterFormats *main_formats = ff_make_format_list(main_fmts);
+ AVFilterFormats *alpha_formats = ff_make_format_list(alpha_fmts);
+ ff_formats_ref(main_formats, &ctx->inputs[0]->out_formats);
+ ff_formats_ref(alpha_formats, &ctx->inputs[1]->out_formats);
+ ff_formats_ref(main_formats, &ctx->outputs[0]->in_formats);
+ return 0;
+}
+
+static int config_input_main(AVFilterLink *inlink)
+{
+ AlphaMergeContext *merge = inlink->dst->priv;
+ merge->is_packed_rgb =
+ ff_fill_rgba_map(merge->rgba_map, inlink->format) >= 0;
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *mainlink = ctx->inputs[0];
+ AVFilterLink *alphalink = ctx->inputs[1];
+ if (mainlink->w != alphalink->w || mainlink->h != alphalink->h) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Input frame sizes do not match (%dx%d vs %dx%d).\n",
+ mainlink->w, mainlink->h,
+ alphalink->w, alphalink->h);
+ return AVERROR(EINVAL);
+ }
+
+ outlink->w = mainlink->w;
+ outlink->h = mainlink->h;
+ outlink->time_base = mainlink->time_base;
+ outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
+ outlink->frame_rate = mainlink->frame_rate;
+ return 0;
+}
+
+static void draw_frame(AVFilterContext *ctx,
+ AVFrame *main_buf,
+ AVFrame *alpha_buf)
+{
+ AlphaMergeContext *merge = ctx->priv;
+ int h = main_buf->height;
+
+ if (merge->is_packed_rgb) {
+ int x, y;
+ uint8_t *pin, *pout;
+ for (y = 0; y < h; y++) {
+ pin = alpha_buf->data[0] + y * alpha_buf->linesize[0];
+ pout = main_buf->data[0] + y * main_buf->linesize[0] + merge->rgba_map[A];
+ for (x = 0; x < main_buf->width; x++) {
+ *pout = *pin;
+ pin += 1;
+ pout += 4;
+ }
+ }
+ } else {
+ int y;
+ const int main_linesize = main_buf->linesize[A];
+ const int alpha_linesize = alpha_buf->linesize[Y];
+ for (y = 0; y < h && y < alpha_buf->height; y++) {
+ memcpy(main_buf->data[A] + y * main_linesize,
+ alpha_buf->data[Y] + y * alpha_linesize,
+ FFMIN(main_linesize, alpha_linesize));
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AlphaMergeContext *merge = ctx->priv;
+
+ int ret = 0;
+ int is_alpha = (inlink == ctx->inputs[1]);
+ struct FFBufQueue *queue =
+ (is_alpha ? &merge->queue_alpha : &merge->queue_main);
+ ff_bufqueue_add(ctx, queue, buf);
+
+ do {
+ AVFrame *main_buf, *alpha_buf;
+
+ if (!ff_bufqueue_peek(&merge->queue_main, 0) ||
+ !ff_bufqueue_peek(&merge->queue_alpha, 0)) break;
+
+ main_buf = ff_bufqueue_get(&merge->queue_main);
+ alpha_buf = ff_bufqueue_get(&merge->queue_alpha);
+
+ merge->frame_requested = 0;
+ draw_frame(ctx, main_buf, alpha_buf);
+ ret = ff_filter_frame(ctx->outputs[0], main_buf);
+ av_frame_free(&alpha_buf);
+ } while (ret >= 0);
+ return ret;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AlphaMergeContext *merge = ctx->priv;
+ int in, ret;
+
+ merge->frame_requested = 1;
+ while (merge->frame_requested) {
+ in = ff_bufqueue_peek(&merge->queue_main, 0) ? 1 : 0;
+ ret = ff_request_frame(ctx->inputs[in]);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static const AVFilterPad alphamerge_inputs[] = {
+ {
+ .name = "main",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input_main,
+ .filter_frame = filter_frame,
+ .needs_writable = 1,
+ },{
+ .name = "alpha",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad alphamerge_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_alphamerge = {
+ .name = "alphamerge",
+ .description = NULL_IF_CONFIG_SMALL("Copy the luma value of the second "
+ "input into the alpha channel of the first input."),
+ .uninit = uninit,
+ .priv_size = sizeof(AlphaMergeContext),
+ .query_formats = query_formats,
+ .inputs = alphamerge_inputs,
+ .outputs = alphamerge_outputs,
+};
diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c
index 2c2821318e..84dbee95d5 100644
--- a/libavfilter/vf_aspect.c
+++ b/libavfilter/vf_aspect.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Bobby Bingham
-
- * This file is part of Libav.
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,9 +37,6 @@
#include "video.h"
static const char *const var_names[] = {
- "PI",
- "PHI",
- "E",
"w",
"h",
"a", "dar",
@@ -50,9 +47,6 @@ static const char *const var_names[] = {
};
enum var_name {
- VAR_PI,
- VAR_PHI,
- VAR_E,
VAR_W,
VAR_H,
VAR_A, VAR_DAR,
@@ -66,26 +60,35 @@ typedef struct AspectContext {
const AVClass *class;
AVRational dar;
AVRational sar;
+ int max;
#if FF_API_OLD_FILTER_OPTS
- float aspect_num, aspect_den;
+ float aspect_den;
#endif
char *ratio_expr;
} AspectContext;
-#if FF_API_OLD_FILTER_OPTS
static av_cold int init(AVFilterContext *ctx)
{
AspectContext *s = ctx->priv;
+ int ret;
- if (s->aspect_num > 0 && s->aspect_den > 0) {
- av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use "
- "dar=<number> or dar=num/den.\n");
- s->sar = s->dar = av_d2q(s->aspect_num / s->aspect_den, INT_MAX);
+#if FF_API_OLD_FILTER_OPTS
+ if (s->ratio_expr && s->aspect_den > 0) {
+ double num;
+ av_log(ctx, AV_LOG_WARNING,
+ "num:den syntax is deprecated, please use num/den or named options instead\n");
+ ret = av_expr_parse_and_eval(&num, s->ratio_expr, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse ratio numerator \"%s\"\n", s->ratio_expr);
+ return AVERROR(EINVAL);
+ }
+ s->sar = s->dar = av_d2q(num / s->aspect_den, s->max);
}
+#endif
return 0;
}
-#endif
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
@@ -96,7 +99,16 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
}
#define OFFSET(x) offsetof(AspectContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static inline void compute_dar(AVRational *dar, AVRational sar, int w, int h)
+{
+ if (sar.num && sar.den) {
+ av_reduce(&dar->num, &dar->den, sar.num * w, sar.den * h, INT_MAX);
+ } else {
+ av_reduce(&dar->num, &dar->den, w, h, INT_MAX);
+ }
+}
static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio)
{
@@ -106,9 +118,6 @@ static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio)
double var_values[VARS_NB], res;
int ret;
- var_values[VAR_PI] = M_PI;
- var_values[VAR_PHI] = M_PHI;
- var_values[VAR_E] = M_E;
var_values[VAR_W] = inlink->w;
var_values[VAR_H] = inlink->h;
var_values[VAR_A] = (double) inlink->w / inlink->h;
@@ -119,27 +128,39 @@ static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio)
var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
/* evaluate new aspect ratio*/
- if ((ret = av_expr_parse_and_eval(&res, s->ratio_expr,
+ ret = av_expr_parse_and_eval(&res, s->ratio_expr,
var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
- av_log(NULL, AV_LOG_ERROR,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0) {
+ ret = av_parse_ratio(aspect_ratio, s->ratio_expr, s->max, 0, ctx);
+ } else
+ *aspect_ratio = av_d2q(res, s->max);
+
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR,
"Error when evaluating the expression '%s'\n", s->ratio_expr);
return ret;
}
- *aspect_ratio = av_d2q(res, INT_MAX);
+ if (aspect_ratio->num < 0 || aspect_ratio->den <= 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid string '%s' for aspect ratio\n", s->ratio_expr);
+ return AVERROR(EINVAL);
+ }
return 0;
}
#if CONFIG_SETDAR_FILTER
-/* for setdar filter, convert from frame aspect ratio to pixel aspect ratio */
+
static int setdar_config_props(AVFilterLink *inlink)
{
AspectContext *s = inlink->dst->priv;
AVRational dar;
+ AVRational old_dar;
+ AVRational old_sar = inlink->sample_aspect_ratio;
int ret;
#if FF_API_OLD_FILTER_OPTS
- if (!(s->aspect_num > 0 && s->aspect_den > 0)) {
+ if (!(s->ratio_expr && s->aspect_den > 0)) {
#endif
if ((ret = get_aspect_ratio(inlink, &s->dar)))
return ret;
@@ -150,7 +171,7 @@ static int setdar_config_props(AVFilterLink *inlink)
if (s->dar.num && s->dar.den) {
av_reduce(&s->sar.num, &s->sar.den,
s->dar.num * inlink->h,
- s->dar.den * inlink->w, 100);
+ s->dar.den * inlink->w, INT_MAX);
inlink->sample_aspect_ratio = s->sar;
dar = s->dar;
} else {
@@ -158,36 +179,33 @@ static int setdar_config_props(AVFilterLink *inlink)
dar = (AVRational){ inlink->w, inlink->h };
}
- av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d -> dar:%d/%d sar:%d/%d\n",
- inlink->w, inlink->h, dar.num, dar.den,
- inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den);
+ compute_dar(&old_dar, old_sar, inlink->w, inlink->h);
+ av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d dar:%d/%d sar:%d/%d -> dar:%d/%d sar:%d/%d\n",
+ inlink->w, inlink->h, old_dar.num, old_dar.den, old_sar.num, old_sar.den,
+ dar.num, dar.den, inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den);
return 0;
}
static const AVOption setdar_options[] = {
+ { "dar", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
+ { "ratio", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
+ { "r", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
#if FF_API_OLD_FILTER_OPTS
- { "dar_num", NULL, OFFSET(aspect_num), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS },
{ "dar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS },
#endif
- { "dar", "display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
- { NULL },
+ { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS },
+ { NULL }
};
-static const AVClass setdar_class = {
- .class_name = "setdar",
- .item_name = av_default_item_name,
- .option = setdar_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(setdar);
static const AVFilterPad avfilter_vf_setdar_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = setdar_config_props,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = setdar_config_props,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -201,31 +219,28 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = {
};
AVFilter ff_vf_setdar = {
- .name = "setdar",
+ .name = "setdar",
.description = NULL_IF_CONFIG_SMALL("Set the frame display aspect ratio."),
-
-#if FF_API_OLD_FILTER_OPTS
- .init = init,
-#endif
-
- .priv_size = sizeof(AspectContext),
- .priv_class = &setdar_class,
-
- .inputs = avfilter_vf_setdar_inputs,
-
- .outputs = avfilter_vf_setdar_outputs,
+ .init = init,
+ .priv_size = sizeof(AspectContext),
+ .priv_class = &setdar_class,
+ .inputs = avfilter_vf_setdar_inputs,
+ .outputs = avfilter_vf_setdar_outputs,
};
+
#endif /* CONFIG_SETDAR_FILTER */
#if CONFIG_SETSAR_FILTER
-/* for setdar filter, convert from frame aspect ratio to pixel aspect ratio */
+
static int setsar_config_props(AVFilterLink *inlink)
{
AspectContext *s = inlink->dst->priv;
+ AVRational old_sar = inlink->sample_aspect_ratio;
+ AVRational old_dar, dar;
int ret;
#if FF_API_OLD_FILTER_OPTS
- if (!(s->aspect_num > 0 && s->aspect_den > 0)) {
+ if (!(s->ratio_expr && s->aspect_den > 0)) {
#endif
if ((ret = get_aspect_ratio(inlink, &s->sar)))
return ret;
@@ -235,32 +250,34 @@ static int setsar_config_props(AVFilterLink *inlink)
inlink->sample_aspect_ratio = s->sar;
+ compute_dar(&old_dar, old_sar, inlink->w, inlink->h);
+ compute_dar(&dar, s->sar, inlink->w, inlink->h);
+ av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d dar:%d/%d -> sar:%d/%d dar:%d/%d\n",
+ inlink->w, inlink->h, old_sar.num, old_sar.den, old_dar.num, old_dar.den,
+ inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, dar.num, dar.den);
+
return 0;
}
static const AVOption setsar_options[] = {
+ { "sar", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
+ { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
+ { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
#if FF_API_OLD_FILTER_OPTS
- { "sar_num", NULL, OFFSET(aspect_num), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS },
{ "sar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS },
#endif
- { "sar", "sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
- { NULL },
+ { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS },
+ { NULL }
};
-static const AVClass setsar_class = {
- .class_name = "setsar",
- .item_name = av_default_item_name,
- .option = setsar_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(setsar);
static const AVFilterPad avfilter_vf_setsar_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = setsar_config_props,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = setsar_config_props,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -274,18 +291,13 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = {
};
AVFilter ff_vf_setsar = {
- .name = "setsar",
+ .name = "setsar",
.description = NULL_IF_CONFIG_SMALL("Set the pixel sample aspect ratio."),
-
-#if FF_API_OLD_FILTER_OPTS
- .init = init,
-#endif
-
- .priv_size = sizeof(AspectContext),
- .priv_class = &setsar_class,
-
- .inputs = avfilter_vf_setsar_inputs,
-
- .outputs = avfilter_vf_setsar_outputs,
+ .init = init,
+ .priv_size = sizeof(AspectContext),
+ .priv_class = &setsar_class,
+ .inputs = avfilter_vf_setsar_inputs,
+ .outputs = avfilter_vf_setsar_outputs,
};
+
#endif /* CONFIG_SETSAR_FILTER */
diff --git a/libavfilter/vf_bbox.c b/libavfilter/vf_bbox.c
new file mode 100644
index 0000000000..e92c3b477f
--- /dev/null
+++ b/libavfilter/vf_bbox.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * bounding box detection filter
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "bbox.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int min_val;
+} BBoxContext;
+
+#define OFFSET(x) offsetof(BBoxContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption bbox_options[] = {
+ { "min_val", "set minimum luminance value for bounding box", OFFSET(min_val), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 254, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(bbox);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_NONE,
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+#define SET_META(key, value) \
+ av_dict_set_int(metadata, key, value, 0);
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ BBoxContext *bbox = ctx->priv;
+ FFBoundingBox box;
+ int has_bbox, w, h;
+
+ has_bbox =
+ ff_calculate_bounding_box(&box,
+ frame->data[0], frame->linesize[0],
+ inlink->w, inlink->h, bbox->min_val);
+ w = box.x2 - box.x1 + 1;
+ h = box.y2 - box.y1 + 1;
+
+ av_log(ctx, AV_LOG_INFO,
+ "n:%"PRId64" pts:%s pts_time:%s", inlink->frame_count,
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base));
+
+ if (has_bbox) {
+ AVDictionary **metadata = avpriv_frame_get_metadatap(frame);
+
+ SET_META("lavfi.bbox.x1", box.x1)
+ SET_META("lavfi.bbox.x2", box.x2)
+ SET_META("lavfi.bbox.y1", box.y1)
+ SET_META("lavfi.bbox.y2", box.y2)
+ SET_META("lavfi.bbox.w", w)
+ SET_META("lavfi.bbox.h", h)
+
+ av_log(ctx, AV_LOG_INFO,
+ " x1:%d x2:%d y1:%d y2:%d w:%d h:%d"
+ " crop=%d:%d:%d:%d drawbox=%d:%d:%d:%d",
+ box.x1, box.x2, box.y1, box.y2, w, h,
+ w, h, box.x1, box.y1, /* crop params */
+ box.x1, box.y1, w, h); /* drawbox params */
+ }
+ av_log(ctx, AV_LOG_INFO, "\n");
+
+ return ff_filter_frame(inlink->dst->outputs[0], frame);
+}
+
+static const AVFilterPad bbox_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad bbox_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_bbox = {
+ .name = "bbox",
+ .description = NULL_IF_CONFIG_SMALL("Compute bounding box for each frame."),
+ .priv_size = sizeof(BBoxContext),
+ .priv_class = &bbox_class,
+ .query_formats = query_formats,
+ .inputs = bbox_inputs,
+ .outputs = bbox_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
new file mode 100644
index 0000000000..fbe3d108db
--- /dev/null
+++ b/libavfilter/vf_blackdetect.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Video black detector, loosely based on blackframe with extended
+ * syntax and features
+ */
+
+#include <float.h>
+#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ double black_min_duration_time; ///< minimum duration of detected black, in seconds
+ int64_t black_min_duration; ///< minimum duration of detected black, expressed in timebase units
+ int64_t black_start; ///< pts start time of the first black picture
+ int64_t black_end; ///< pts end time of the last black picture
+ int64_t last_picref_pts; ///< pts of the last input picture
+ int black_started;
+
+ double picture_black_ratio_th;
+ double pixel_black_th;
+ unsigned int pixel_black_th_i;
+
+ unsigned int nb_black_pixels; ///< number of black pixels counted so far
+} BlackDetectContext;
+
+#define OFFSET(x) offsetof(BlackDetectContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption blackdetect_options[] = {
+ { "d", "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX, FLAGS },
+ { "black_min_duration", "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX, FLAGS },
+ { "picture_black_ratio_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1, FLAGS },
+ { "pic_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1, FLAGS },
+ { "pixel_black_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1, FLAGS },
+ { "pix_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(blackdetect);
+
+#define YUVJ_FORMATS \
+ AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
+
+static const enum AVPixelFormat yuvj_formats[] = {
+ YUVJ_FORMATS, AV_PIX_FMT_NONE
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_NV12, AV_PIX_FMT_NV21,
+ YUVJ_FORMATS,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ BlackDetectContext *blackdetect = ctx->priv;
+
+ blackdetect->black_min_duration =
+ blackdetect->black_min_duration_time / av_q2d(inlink->time_base);
+
+ blackdetect->pixel_black_th_i = ff_fmt_is_in(inlink->format, yuvj_formats) ?
+ // luminance_minimum_value + pixel_black_th * luminance_range_size
+ blackdetect->pixel_black_th * 255 :
+ 16 + blackdetect->pixel_black_th * (235 - 16);
+
+ av_log(blackdetect, AV_LOG_VERBOSE,
+ "black_min_duration:%s pixel_black_th:%f pixel_black_th_i:%d picture_black_ratio_th:%f\n",
+ av_ts2timestr(blackdetect->black_min_duration, &inlink->time_base),
+ blackdetect->pixel_black_th, blackdetect->pixel_black_th_i,
+ blackdetect->picture_black_ratio_th);
+ return 0;
+}
+
+static void check_black_end(AVFilterContext *ctx)
+{
+ BlackDetectContext *blackdetect = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ if ((blackdetect->black_end - blackdetect->black_start) >= blackdetect->black_min_duration) {
+ av_log(blackdetect, AV_LOG_INFO,
+ "black_start:%s black_end:%s black_duration:%s\n",
+ av_ts2timestr(blackdetect->black_start, &inlink->time_base),
+ av_ts2timestr(blackdetect->black_end, &inlink->time_base),
+ av_ts2timestr(blackdetect->black_end - blackdetect->black_start, &inlink->time_base));
+ }
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ BlackDetectContext *blackdetect = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ int ret = ff_request_frame(inlink);
+
+ if (ret == AVERROR_EOF && blackdetect->black_started) {
+ // FIXME: black_end should be set to last_picref_pts + last_picref_duration
+ blackdetect->black_end = blackdetect->last_picref_pts;
+ check_black_end(ctx);
+ }
+ return ret;
+}
+
+// TODO: document metadata
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ BlackDetectContext *blackdetect = ctx->priv;
+ double picture_black_ratio = 0;
+ const uint8_t *p = picref->data[0];
+ int x, i;
+
+ for (i = 0; i < inlink->h; i++) {
+ for (x = 0; x < inlink->w; x++)
+ blackdetect->nb_black_pixels += p[x] <= blackdetect->pixel_black_th_i;
+ p += picref->linesize[0];
+ }
+
+ picture_black_ratio = (double)blackdetect->nb_black_pixels / (inlink->w * inlink->h);
+
+ av_log(ctx, AV_LOG_DEBUG,
+ "frame:%"PRId64" picture_black_ratio:%f pts:%s t:%s type:%c\n",
+ inlink->frame_count, picture_black_ratio,
+ av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
+ av_get_picture_type_char(picref->pict_type));
+
+ if (picture_black_ratio >= blackdetect->picture_black_ratio_th) {
+ if (!blackdetect->black_started) {
+ /* black starts here */
+ blackdetect->black_started = 1;
+ blackdetect->black_start = picref->pts;
+ av_dict_set(avpriv_frame_get_metadatap(picref), "lavfi.black_start",
+ av_ts2timestr(blackdetect->black_start, &inlink->time_base), 0);
+ }
+ } else if (blackdetect->black_started) {
+ /* black ends here */
+ blackdetect->black_started = 0;
+ blackdetect->black_end = picref->pts;
+ check_black_end(ctx);
+ av_dict_set(avpriv_frame_get_metadatap(picref), "lavfi.black_end",
+ av_ts2timestr(blackdetect->black_end, &inlink->time_base), 0);
+ }
+
+ blackdetect->last_picref_pts = picref->pts;
+ blackdetect->nb_black_pixels = 0;
+ return ff_filter_frame(inlink->dst->outputs[0], picref);
+}
+
+static const AVFilterPad blackdetect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad blackdetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_blackdetect = {
+ .name = "blackdetect",
+ .description = NULL_IF_CONFIG_SMALL("Detect video intervals that are (almost) black."),
+ .priv_size = sizeof(BlackDetectContext),
+ .query_formats = query_formats,
+ .inputs = blackdetect_inputs,
+ .outputs = blackdetect_outputs,
+ .priv_class = &blackdetect_class,
+};
diff --git a/libavfilter/vf_blackframe.c b/libavfilter/vf_blackframe.c
index 8cbcc005a4..ad6d488b3a 100644
--- a/libavfilter/vf_blackframe.c
+++ b/libavfilter/vf_blackframe.c
@@ -4,20 +4,20 @@
* Copyright (c) 2006 Julian Hall
* Copyright (c) 2002-2003 Brian J. Murrell
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -32,7 +32,6 @@
#include "libavutil/internal.h"
#include "libavutil/opt.h"
-
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
@@ -44,6 +43,7 @@ typedef struct BlackFrameContext {
int bthresh; ///< black threshold
unsigned int frame; ///< frame number
unsigned int nblack; ///< number of black pixels counted so far
+ unsigned int last_keyframe; ///< frame number of the last received key-frame
} BlackFrameContext;
static int query_formats(AVFilterContext *ctx)
@@ -54,10 +54,16 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_NONE
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
+#define SET_META(key, format, value) \
+ snprintf(buf, sizeof(buf), format, value); \
+ av_dict_set(metadata, key, buf, 0)
+
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
@@ -65,6 +71,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
int x, i;
int pblack = 0;
uint8_t *p = frame->data[0];
+ AVDictionary **metadata;
+ char buf[32];
for (i = 0; i < frame->height; i++) {
for (x = 0; x < inlink->w; x++)
@@ -72,11 +80,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
p += frame->linesize[0];
}
+ if (frame->key_frame)
+ s->last_keyframe = s->frame;
+
pblack = s->nblack * 100 / (inlink->w * inlink->h);
- if (pblack >= s->bamount)
- av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pts:%"PRId64" t:%f\n",
+ if (pblack >= s->bamount) {
+ metadata = avpriv_frame_get_metadatap(frame);
+
+ av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pts:%"PRId64" t:%f "
+ "type:%c last_keyframe:%d\n",
s->frame, pblack, frame->pts,
- frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base));
+ frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base),
+ av_get_picture_type_char(frame->pict_type), s->last_keyframe);
+
+ SET_META("lavfi.blackframe.pblack", "%u", pblack);
+ }
s->frame++;
s->nblack = 0;
@@ -84,28 +102,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
#define OFFSET(x) offsetof(BlackFrameContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption blackframe_options[] = {
{ "amount", "Percentage of the pixels that have to be below the threshold "
"for the frame to be considered black.", OFFSET(bamount), AV_OPT_TYPE_INT, { .i64 = 98 }, 0, 100, FLAGS },
{ "threshold", "threshold below which a pixel value is considered black",
- OFFSET(bthresh), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, INT_MAX, FLAGS },
- { NULL },
+ OFFSET(bthresh), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 255, FLAGS },
+ { "thresh", "threshold below which a pixel value is considered black",
+ OFFSET(bthresh), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 255, FLAGS },
+ { NULL }
};
-static const AVClass blackframe_class = {
- .class_name = "blackframe",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(blackframe);
static const AVFilterPad avfilter_vf_blackframe_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -119,15 +133,11 @@ static const AVFilterPad avfilter_vf_blackframe_outputs[] = {
};
AVFilter ff_vf_blackframe = {
- .name = "blackframe",
- .description = NULL_IF_CONFIG_SMALL("Detect frames that are (almost) black."),
-
- .priv_size = sizeof(BlackFrameContext),
- .priv_class = &blackframe_class,
-
+ .name = "blackframe",
+ .description = NULL_IF_CONFIG_SMALL("Detect frames that are (almost) black."),
+ .priv_size = sizeof(BlackFrameContext),
+ .priv_class = &blackframe_class,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_blackframe_inputs,
-
- .outputs = avfilter_vf_blackframe_outputs,
+ .inputs = avfilter_vf_blackframe_inputs,
+ .outputs = avfilter_vf_blackframe_outputs,
};
diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c
new file mode 100644
index 0000000000..5fe704610d
--- /dev/null
+++ b/libavfilter/vf_blend.c
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixfmt.h"
+#include "avfilter.h"
+#include "bufferqueue.h"
+#include "formats.h"
+#include "internal.h"
+#include "dualinput.h"
+#include "video.h"
+
+#define TOP 0
+#define BOTTOM 1
+
+enum BlendMode {
+ BLEND_UNSET = -1,
+ BLEND_NORMAL,
+ BLEND_ADDITION,
+ BLEND_AND,
+ BLEND_AVERAGE,
+ BLEND_BURN,
+ BLEND_DARKEN,
+ BLEND_DIFFERENCE,
+ BLEND_DIFFERENCE128,
+ BLEND_DIVIDE,
+ BLEND_DODGE,
+ BLEND_EXCLUSION,
+ BLEND_HARDLIGHT,
+ BLEND_LIGHTEN,
+ BLEND_MULTIPLY,
+ BLEND_NEGATION,
+ BLEND_OR,
+ BLEND_OVERLAY,
+ BLEND_PHOENIX,
+ BLEND_PINLIGHT,
+ BLEND_REFLECT,
+ BLEND_SCREEN,
+ BLEND_SOFTLIGHT,
+ BLEND_SUBTRACT,
+ BLEND_VIVIDLIGHT,
+ BLEND_XOR,
+ BLEND_NB
+};
+
+static const char *const var_names[] = { "X", "Y", "W", "H", "SW", "SH", "T", "N", "A", "B", "TOP", "BOTTOM", NULL };
+enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_SW, VAR_SH, VAR_T, VAR_N, VAR_A, VAR_B, VAR_TOP, VAR_BOTTOM, VAR_VARS_NB };
+
+typedef struct FilterParams {
+ enum BlendMode mode;
+ double opacity;
+ AVExpr *e;
+ char *expr_str;
+ void (*blend)(const uint8_t *top, int top_linesize,
+ const uint8_t *bottom, int bottom_linesize,
+ uint8_t *dst, int dst_linesize,
+ int width, int start, int end,
+ struct FilterParams *param, double *values);
+} FilterParams;
+
+typedef struct ThreadData {
+ const AVFrame *top, *bottom;
+ AVFrame *dst;
+ AVFilterLink *inlink;
+ int plane;
+ int w, h;
+ FilterParams *param;
+} ThreadData;
+
+typedef struct {
+ const AVClass *class;
+ FFDualInputContext dinput;
+ int hsub, vsub; ///< chroma subsampling values
+ int nb_planes;
+ char *all_expr;
+ enum BlendMode all_mode;
+ double all_opacity;
+
+ FilterParams params[4];
+ int tblend;
+ AVFrame *prev_frame; /* only used with tblend */
+} BlendContext;
+
+#define COMMON_OPTIONS \
+ { "c0_mode", "set component #0 blend mode", OFFSET(params[0].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
+ { "c1_mode", "set component #1 blend mode", OFFSET(params[1].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
+ { "c2_mode", "set component #2 blend mode", OFFSET(params[2].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
+ { "c3_mode", "set component #3 blend mode", OFFSET(params[3].mode), AV_OPT_TYPE_INT, {.i64=0}, 0, BLEND_NB-1, FLAGS, "mode"},\
+ { "all_mode", "set blend mode for all components", OFFSET(all_mode), AV_OPT_TYPE_INT, {.i64=-1},-1, BLEND_NB-1, FLAGS, "mode"},\
+ { "addition", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_ADDITION}, 0, 0, FLAGS, "mode" },\
+ { "and", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AND}, 0, 0, FLAGS, "mode" },\
+ { "average", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_AVERAGE}, 0, 0, FLAGS, "mode" },\
+ { "burn", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_BURN}, 0, 0, FLAGS, "mode" },\
+ { "darken", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DARKEN}, 0, 0, FLAGS, "mode" },\
+ { "difference", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE}, 0, 0, FLAGS, "mode" },\
+ { "difference128", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIFFERENCE128}, 0, 0, FLAGS, "mode" },\
+ { "divide", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DIVIDE}, 0, 0, FLAGS, "mode" },\
+ { "dodge", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_DODGE}, 0, 0, FLAGS, "mode" },\
+ { "exclusion", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_EXCLUSION}, 0, 0, FLAGS, "mode" },\
+ { "hardlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_HARDLIGHT}, 0, 0, FLAGS, "mode" },\
+ { "lighten", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_LIGHTEN}, 0, 0, FLAGS, "mode" },\
+ { "multiply", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_MULTIPLY}, 0, 0, FLAGS, "mode" },\
+ { "negation", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NEGATION}, 0, 0, FLAGS, "mode" },\
+ { "normal", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_NORMAL}, 0, 0, FLAGS, "mode" },\
+ { "or", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OR}, 0, 0, FLAGS, "mode" },\
+ { "overlay", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_OVERLAY}, 0, 0, FLAGS, "mode" },\
+ { "phoenix", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PHOENIX}, 0, 0, FLAGS, "mode" },\
+ { "pinlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_PINLIGHT}, 0, 0, FLAGS, "mode" },\
+ { "reflect", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_REFLECT}, 0, 0, FLAGS, "mode" },\
+ { "screen", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SCREEN}, 0, 0, FLAGS, "mode" },\
+ { "softlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SOFTLIGHT}, 0, 0, FLAGS, "mode" },\
+ { "subtract", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_SUBTRACT}, 0, 0, FLAGS, "mode" },\
+ { "vividlight", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_VIVIDLIGHT}, 0, 0, FLAGS, "mode" },\
+ { "xor", "", 0, AV_OPT_TYPE_CONST, {.i64=BLEND_XOR}, 0, 0, FLAGS, "mode" },\
+ { "c0_expr", "set color component #0 expression", OFFSET(params[0].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
+ { "c1_expr", "set color component #1 expression", OFFSET(params[1].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
+ { "c2_expr", "set color component #2 expression", OFFSET(params[2].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
+ { "c3_expr", "set color component #3 expression", OFFSET(params[3].expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
+ { "all_expr", "set expression for all color components", OFFSET(all_expr), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },\
+ { "c0_opacity", "set color component #0 opacity", OFFSET(params[0].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
+ { "c1_opacity", "set color component #1 opacity", OFFSET(params[1].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
+ { "c2_opacity", "set color component #2 opacity", OFFSET(params[2].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
+ { "c3_opacity", "set color component #3 opacity", OFFSET(params[3].opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },\
+ { "all_opacity", "set opacity for all color components", OFFSET(all_opacity), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}
+
+#define OFFSET(x) offsetof(BlendContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption blend_options[] = {
+ COMMON_OPTIONS,
+ { "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "repeatlast", "repeat last bottom frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(blend);
+
+static void blend_normal(const uint8_t *top, int top_linesize,
+ const uint8_t *bottom, int bottom_linesize,
+ uint8_t *dst, int dst_linesize,
+ int width, int start, int end,
+ FilterParams *param, double *values)
+{
+ av_image_copy_plane(dst, dst_linesize, top, top_linesize, width, end - start);
+}
+
+#define DEFINE_BLEND(name, expr) \
+static void blend_## name(const uint8_t *top, int top_linesize, \
+ const uint8_t *bottom, int bottom_linesize, \
+ uint8_t *dst, int dst_linesize, \
+ int width, int start, int end, \
+ FilterParams *param, double *values) \
+{ \
+ double opacity = param->opacity; \
+ int i, j; \
+ \
+ for (i = start; i < end; i++) { \
+ for (j = 0; j < width; j++) { \
+ dst[j] = top[j] + ((expr) - top[j]) * opacity; \
+ } \
+ dst += dst_linesize; \
+ top += top_linesize; \
+ bottom += bottom_linesize; \
+ } \
+}
+
+#define A top[j]
+#define B bottom[j]
+
+#define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / 255))
+#define SCREEN(x, a, b) (255 - (x) * ((255 - (a)) * (255 - (b)) / 255))
+#define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, 255 - ((255 - (b)) << 8) / (a)))
+#define DODGE(a, b) (((a) == 255) ? (a) : FFMIN(255, (((b) << 8) / (255 - (a)))))
+
+DEFINE_BLEND(addition, FFMIN(255, A + B))
+DEFINE_BLEND(average, (A + B) / 2)
+DEFINE_BLEND(subtract, FFMAX(0, A - B))
+DEFINE_BLEND(multiply, MULTIPLY(1, A, B))
+DEFINE_BLEND(negation, 255 - FFABS(255 - A - B))
+DEFINE_BLEND(difference, FFABS(A - B))
+DEFINE_BLEND(difference128, av_clip_uint8(128 + A - B))
+DEFINE_BLEND(screen, SCREEN(1, A, B))
+DEFINE_BLEND(overlay, (A < 128) ? MULTIPLY(2, A, B) : SCREEN(2, A, B))
+DEFINE_BLEND(hardlight, (B < 128) ? MULTIPLY(2, B, A) : SCREEN(2, B, A))
+DEFINE_BLEND(darken, FFMIN(A, B))
+DEFINE_BLEND(lighten, FFMAX(A, B))
+DEFINE_BLEND(divide, ((float)A / ((float)B) * 255))
+DEFINE_BLEND(dodge, DODGE(A, B))
+DEFINE_BLEND(burn, BURN(A, B))
+DEFINE_BLEND(softlight, (A > 127) ? B + (255 - B) * (A - 127.5) / 127.5 * (0.5 - FFABS(B - 127.5) / 255): B - B * ((127.5 - A) / 127.5) * (0.5 - FFABS(B - 127.5)/255))
+DEFINE_BLEND(exclusion, A + B - 2 * A * B / 255)
+DEFINE_BLEND(pinlight, (B < 128) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - 128)))
+DEFINE_BLEND(phoenix, FFMIN(A, B) - FFMAX(A, B) + 255)
+DEFINE_BLEND(reflect, (B == 255) ? B : FFMIN(255, (A * A / (255 - B))))
+DEFINE_BLEND(and, A & B)
+DEFINE_BLEND(or, A | B)
+DEFINE_BLEND(xor, A ^ B)
+DEFINE_BLEND(vividlight, (B < 128) ? BURN(A, 2 * B) : DODGE(A, 2 * (B - 128)))
+
+static void blend_expr(const uint8_t *top, int top_linesize,
+ const uint8_t *bottom, int bottom_linesize,
+ uint8_t *dst, int dst_linesize,
+ int width, int start, int end,
+ FilterParams *param, double *values)
+{
+ AVExpr *e = param->e;
+ int y, x;
+
+ for (y = start; y < end; y++) {
+ values[VAR_Y] = y;
+ for (x = 0; x < width; x++) {
+ values[VAR_X] = x;
+ values[VAR_TOP] = values[VAR_A] = top[x];
+ values[VAR_BOTTOM] = values[VAR_B] = bottom[x];
+ dst[x] = av_expr_eval(e, values, NULL);
+ }
+ dst += dst_linesize;
+ top += top_linesize;
+ bottom += bottom_linesize;
+ }
+}
+
+static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ ThreadData *td = arg;
+ int slice_start = (td->h * jobnr ) / nb_jobs;
+ int slice_end = (td->h * (jobnr+1)) / 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];
+ double values[VAR_VARS_NB];
+
+ values[VAR_N] = td->inlink->frame_count;
+ 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;
+ values[VAR_SW] = td->w / (double)td->dst->width;
+ values[VAR_SH] = td->h / (double)td->dst->height;
+
+ td->param->blend(top + slice_start * td->top->linesize[td->plane],
+ td->top->linesize[td->plane],
+ bottom + slice_start * td->bottom->linesize[td->plane],
+ td->bottom->linesize[td->plane],
+ dst + slice_start * td->dst->linesize[td->plane],
+ td->dst->linesize[td->plane],
+ td->w, slice_start, slice_end, td->param, &values[0]);
+ return 0;
+}
+
+static AVFrame *blend_frame(AVFilterContext *ctx, AVFrame *top_buf,
+ const AVFrame *bottom_buf)
+{
+ BlendContext *b = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *dst_buf;
+ int plane;
+
+ dst_buf = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!dst_buf)
+ return top_buf;
+ av_frame_copy_props(dst_buf, top_buf);
+
+ for (plane = 0; plane < b->nb_planes; plane++) {
+ int hsub = plane == 1 || plane == 2 ? b->hsub : 0;
+ int vsub = plane == 1 || plane == 2 ? b->vsub : 0;
+ int outw = FF_CEIL_RSHIFT(dst_buf->width, hsub);
+ int outh = FF_CEIL_RSHIFT(dst_buf->height, vsub);
+ FilterParams *param = &b->params[plane];
+ ThreadData td = { .top = top_buf, .bottom = bottom_buf, .dst = dst_buf,
+ .w = outw, .h = outh, .param = param, .plane = plane,
+ .inlink = inlink };
+
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads));
+ }
+
+ if (!b->tblend)
+ av_frame_free(&top_buf);
+
+ return dst_buf;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ BlendContext *b = ctx->priv;
+ int ret, plane;
+
+ b->tblend = !strcmp(ctx->filter->name, "tblend");
+
+ for (plane = 0; plane < FF_ARRAY_ELEMS(b->params); plane++) {
+ FilterParams *param = &b->params[plane];
+
+ if (b->all_mode >= 0)
+ param->mode = b->all_mode;
+ if (b->all_opacity < 1)
+ param->opacity = b->all_opacity;
+
+ switch (param->mode) {
+ case BLEND_ADDITION: param->blend = blend_addition; break;
+ case BLEND_AND: param->blend = blend_and; break;
+ case BLEND_AVERAGE: param->blend = blend_average; break;
+ case BLEND_BURN: param->blend = blend_burn; break;
+ case BLEND_DARKEN: param->blend = blend_darken; break;
+ case BLEND_DIFFERENCE: param->blend = blend_difference; break;
+ case BLEND_DIFFERENCE128: param->blend = blend_difference128; break;
+ case BLEND_DIVIDE: param->blend = blend_divide; break;
+ case BLEND_DODGE: param->blend = blend_dodge; break;
+ case BLEND_EXCLUSION: param->blend = blend_exclusion; break;
+ case BLEND_HARDLIGHT: param->blend = blend_hardlight; break;
+ case BLEND_LIGHTEN: param->blend = blend_lighten; break;
+ case BLEND_MULTIPLY: param->blend = blend_multiply; break;
+ case BLEND_NEGATION: param->blend = blend_negation; break;
+ case BLEND_NORMAL: param->blend = blend_normal; break;
+ case BLEND_OR: param->blend = blend_or; break;
+ case BLEND_OVERLAY: param->blend = blend_overlay; break;
+ case BLEND_PHOENIX: param->blend = blend_phoenix; break;
+ case BLEND_PINLIGHT: param->blend = blend_pinlight; break;
+ case BLEND_REFLECT: param->blend = blend_reflect; break;
+ case BLEND_SCREEN: param->blend = blend_screen; break;
+ case BLEND_SOFTLIGHT: param->blend = blend_softlight; break;
+ case BLEND_SUBTRACT: param->blend = blend_subtract; break;
+ case BLEND_VIVIDLIGHT: param->blend = blend_vividlight; break;
+ case BLEND_XOR: param->blend = blend_xor; break;
+ }
+
+ if (b->all_expr && !param->expr_str) {
+ param->expr_str = av_strdup(b->all_expr);
+ if (!param->expr_str)
+ return AVERROR(ENOMEM);
+ }
+ if (param->expr_str) {
+ ret = av_expr_parse(&param->e, param->expr_str, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ return ret;
+ param->blend = blend_expr;
+ }
+ }
+
+ b->dinput.process = blend_frame;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ BlendContext *b = ctx->priv;
+ int i;
+
+ ff_dualinput_uninit(&b->dinput);
+ av_frame_free(&b->prev_frame);
+
+ for (i = 0; i < FF_ARRAY_ELEMS(b->params); i++)
+ av_expr_free(b->params[i].e);
+}
+
+#if CONFIG_BLEND_FILTER
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *toplink = ctx->inputs[TOP];
+ AVFilterLink *bottomlink = ctx->inputs[BOTTOM];
+ BlendContext *b = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(toplink->format);
+ int ret;
+
+ if (toplink->format != bottomlink->format) {
+ av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
+ return AVERROR(EINVAL);
+ }
+ if (toplink->w != bottomlink->w ||
+ toplink->h != bottomlink->h ||
+ toplink->sample_aspect_ratio.num != bottomlink->sample_aspect_ratio.num ||
+ toplink->sample_aspect_ratio.den != bottomlink->sample_aspect_ratio.den) {
+ av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
+ "(size %dx%d, SAR %d:%d) do not match the corresponding "
+ "second input link %s parameters (%dx%d, SAR %d:%d)\n",
+ ctx->input_pads[TOP].name, toplink->w, toplink->h,
+ toplink->sample_aspect_ratio.num,
+ toplink->sample_aspect_ratio.den,
+ ctx->input_pads[BOTTOM].name, bottomlink->w, bottomlink->h,
+ bottomlink->sample_aspect_ratio.num,
+ bottomlink->sample_aspect_ratio.den);
+ return AVERROR(EINVAL);
+ }
+
+ outlink->w = toplink->w;
+ outlink->h = toplink->h;
+ outlink->time_base = toplink->time_base;
+ outlink->sample_aspect_ratio = toplink->sample_aspect_ratio;
+ outlink->frame_rate = toplink->frame_rate;
+
+ b->hsub = pix_desc->log2_chroma_w;
+ b->vsub = pix_desc->log2_chroma_h;
+ b->nb_planes = av_pix_fmt_count_planes(toplink->format);
+
+ if ((ret = ff_dualinput_init(ctx, &b->dinput)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ BlendContext *b = outlink->src->priv;
+ return ff_dualinput_request_frame(&b->dinput, outlink);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
+{
+ BlendContext *b = inlink->dst->priv;
+ return ff_dualinput_filter_frame(&b->dinput, inlink, buf);
+}
+
+static const AVFilterPad blend_inputs[] = {
+ {
+ .name = "top",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },{
+ .name = "bottom",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad blend_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_blend = {
+ .name = "blend",
+ .description = NULL_IF_CONFIG_SMALL("Blend two video frames into each other."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(BlendContext),
+ .query_formats = query_formats,
+ .inputs = blend_inputs,
+ .outputs = blend_outputs,
+ .priv_class = &blend_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
+};
+
+#endif
+
+#if CONFIG_TBLEND_FILTER
+
+static int tblend_config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ BlendContext *b = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+
+ b->hsub = pix_desc->log2_chroma_w;
+ b->vsub = pix_desc->log2_chroma_h;
+ b->nb_planes = av_pix_fmt_count_planes(inlink->format);
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return 0;
+}
+
+static int tblend_filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ BlendContext *b = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+
+ if (b->prev_frame) {
+ AVFrame *out = blend_frame(inlink->dst, frame, b->prev_frame);
+ av_frame_free(&b->prev_frame);
+ b->prev_frame = frame;
+ return ff_filter_frame(outlink, out);
+ }
+ b->prev_frame = frame;
+ return 0;
+}
+
+static const AVOption tblend_options[] = {
+ COMMON_OPTIONS,
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(tblend);
+
+static const AVFilterPad tblend_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = tblend_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad tblend_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = tblend_config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_tblend = {
+ .name = "tblend",
+ .description = NULL_IF_CONFIG_SMALL("Blend successive frames."),
+ .priv_size = sizeof(BlendContext),
+ .priv_class = &tblend_class,
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .inputs = tblend_inputs,
+ .outputs = tblend_outputs,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
+};
+
+#endif
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c
index 4cbfe2cc0f..17db949bc6 100644
--- a/libavfilter/vf_boxblur.c
+++ b/libavfilter/vf_boxblur.c
@@ -2,20 +2,20 @@
* Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2011 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -58,6 +58,7 @@ enum var_name {
typedef struct FilterParam {
int radius;
int power;
+ char *radius_expr;
} FilterParam;
typedef struct BoxBlurContext {
@@ -65,9 +66,6 @@ typedef struct BoxBlurContext {
FilterParam luma_param;
FilterParam chroma_param;
FilterParam alpha_param;
- char *luma_radius_expr;
- char *chroma_radius_expr;
- char *alpha_radius_expr;
int hsub, vsub;
int radius[4];
@@ -84,23 +82,27 @@ static av_cold int init(AVFilterContext *ctx)
{
BoxBlurContext *s = ctx->priv;
- if (!s->luma_radius_expr) {
+ if (!s->luma_param.radius_expr) {
av_log(ctx, AV_LOG_ERROR, "Luma radius expression is not set.\n");
return AVERROR(EINVAL);
}
- if (!s->chroma_radius_expr) {
- s->chroma_radius_expr = av_strdup(s->luma_radius_expr);
- if (!s->chroma_radius_expr)
+ /* fill missing params */
+ if (!s->chroma_param.radius_expr) {
+ s->chroma_param.radius_expr = av_strdup(s->luma_param.radius_expr);
+ if (!s->chroma_param.radius_expr)
return AVERROR(ENOMEM);
- s->chroma_param.power = s->luma_param.power;
}
- if (!s->alpha_radius_expr) {
- s->alpha_radius_expr = av_strdup(s->luma_radius_expr);
- if (!s->alpha_radius_expr)
+ if (s->chroma_param.power < 0)
+ s->chroma_param.power = s->luma_param.power;
+
+ if (!s->alpha_param.radius_expr) {
+ s->alpha_param.radius_expr = av_strdup(s->luma_param.radius_expr);
+ if (!s->alpha_param.radius_expr)
return AVERROR(ENOMEM);
- s->alpha_param.power = s->luma_param.power;
}
+ if (s->alpha_param.power < 0)
+ s->alpha_param.power = s->luma_param.power;
return 0;
}
@@ -115,17 +117,18 @@ static av_cold void uninit(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
- 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_YUVA420P,
- AV_PIX_FMT_YUV440P, AV_PIX_FMT_GRAY8,
- AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
- AV_PIX_FMT_YUVJ440P,
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *formats = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & (AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_PAL)) &&
+ (desc->flags & AV_PIX_FMT_FLAG_PLANAR || desc->nb_components == 1) &&
+ (!(desc->flags & AV_PIX_FMT_FLAG_BE) == !HAVE_BIGENDIAN || desc->comp[0].depth_minus1 == 7))
+ ff_add_format(&formats, fmt);
+ }
+
+ return ff_set_common_formats(ctx, formats);
}
static int config_input(AVFilterLink *inlink)
@@ -139,14 +142,9 @@ static int config_input(AVFilterLink *inlink)
char *expr;
int ret;
- av_freep(&s->temp[0]);
- av_freep(&s->temp[1]);
- if (!(s->temp[0] = av_malloc(FFMAX(w, h))))
- return AVERROR(ENOMEM);
- if (!(s->temp[1] = av_malloc(FFMAX(w, h)))) {
- av_freep(&s->temp[0]);
+ if (!(s->temp[0] = av_malloc(2*FFMAX(w, h))) ||
+ !(s->temp[1] = av_malloc(2*FFMAX(w, h))))
return AVERROR(ENOMEM);
- }
s->hsub = desc->log2_chroma_w;
s->vsub = desc->log2_chroma_h;
@@ -159,7 +157,7 @@ static int config_input(AVFilterLink *inlink)
var_values[VAR_VSUB] = 1<<s->vsub;
#define EVAL_RADIUS_EXPR(comp) \
- expr = s->comp##_radius_expr; \
+ expr = s->comp##_param.radius_expr; \
ret = av_expr_parse_and_eval(&res, expr, var_names, var_values, \
NULL, NULL, NULL, NULL, NULL, 0, ctx); \
s->comp##_param.radius = res; \
@@ -172,7 +170,7 @@ static int config_input(AVFilterLink *inlink)
EVAL_RADIUS_EXPR(chroma);
EVAL_RADIUS_EXPR(alpha);
- av_log(ctx, AV_LOG_DEBUG,
+ av_log(ctx, AV_LOG_VERBOSE,
"luma_radius:%d luma_power:%d "
"chroma_radius:%d chroma_power:%d "
"alpha_radius:%d alpha_power:%d "
@@ -205,7 +203,7 @@ static int config_input(AVFilterLink *inlink)
return 0;
}
-static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_step,
+static inline void blur8(uint8_t *dst, int dst_step, const uint8_t *src, int src_step,
int len, int radius)
{
/* Naive boxblur would sum source pixels from x-radius .. x+radius
@@ -224,56 +222,100 @@ static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_
*/
const int length = radius*2 + 1;
const int inv = ((1<<16) + length/2)/length;
- int x, sum = 0;
+ int x, sum = src[radius*src_step];
+
+ for (x = 0; x < radius; x++)
+ sum += src[x*src_step]<<1;
+
+ sum = sum*inv + (1<<15);
+
+ for (x = 0; x <= radius; x++) {
+ sum += (src[(radius+x)*src_step] - src[(radius-x)*src_step])*inv;
+ dst[x*dst_step] = sum>>16;
+ }
+
+ for (; x < len-radius; x++) {
+ sum += (src[(radius+x)*src_step] - src[(x-radius-1)*src_step])*inv;
+ dst[x*dst_step] = sum >>16;
+ }
+
+ for (; x < len; x++) {
+ sum += (src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step])*inv;
+ dst[x*dst_step] = sum>>16;
+ }
+}
+
+static inline void blur16(uint16_t *dst, int dst_step, const uint16_t *src, int src_step,
+ int len, int radius)
+{
+ const int length = radius*2 + 1;
+ const int inv = ((1<<16) + length/2)/length;
+ int x, sum = src[radius*src_step];
for (x = 0; x < radius; x++)
sum += src[x*src_step]<<1;
- sum += src[radius*src_step];
+
+ sum = sum*inv + (1<<15);
for (x = 0; x <= radius; x++) {
- sum += src[(radius+x)*src_step] - src[(radius-x)*src_step];
- dst[x*dst_step] = (sum*inv + (1<<15))>>16;
+ sum += (src[(radius+x)*src_step] - src[(radius-x)*src_step])*inv;
+ dst[x*dst_step] = sum>>16;
}
for (; x < len-radius; x++) {
- sum += src[(radius+x)*src_step] - src[(x-radius-1)*src_step];
- dst[x*dst_step] = (sum*inv + (1<<15))>>16;
+ sum += (src[(radius+x)*src_step] - src[(x-radius-1)*src_step])*inv;
+ dst[x*dst_step] = sum >>16;
}
for (; x < len; x++) {
- sum += src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step];
- dst[x*dst_step] = (sum*inv + (1<<15))>>16;
+ sum += (src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step])*inv;
+ dst[x*dst_step] = sum>>16;
}
}
+static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_step,
+ int len, int radius, int pixsize)
+{
+ if (pixsize == 1) blur8 (dst, dst_step , src, src_step , len, radius);
+ else blur16((uint16_t*)dst, dst_step>>1, (const uint16_t*)src, src_step>>1, len, radius);
+}
+
static inline void blur_power(uint8_t *dst, int dst_step, const uint8_t *src, int src_step,
- int len, int radius, int power, uint8_t *temp[2])
+ int len, int radius, int power, uint8_t *temp[2], int pixsize)
{
uint8_t *a = temp[0], *b = temp[1];
if (radius && power) {
- blur(a, 1, src, src_step, len, radius);
+ blur(a, pixsize, src, src_step, len, radius, pixsize);
for (; power > 2; power--) {
uint8_t *c;
- blur(b, 1, a, 1, len, radius);
+ blur(b, pixsize, a, pixsize, len, radius, pixsize);
c = a; a = b; b = c;
}
if (power > 1) {
- blur(dst, dst_step, a, 1, len, radius);
+ blur(dst, dst_step, a, pixsize, len, radius, pixsize);
} else {
int i;
- for (i = 0; i < len; i++)
- dst[i*dst_step] = a[i];
+ if (pixsize == 1) {
+ for (i = 0; i < len; i++)
+ dst[i*dst_step] = a[i];
+ } else
+ for (i = 0; i < len; i++)
+ *(uint16_t*)(dst + i*dst_step) = ((uint16_t*)a)[i];
}
} else {
int i;
- for (i = 0; i < len; i++)
- dst[i*dst_step] = src[i*src_step];
+ if (pixsize == 1) {
+ for (i = 0; i < len; i++)
+ dst[i*dst_step] = src[i*src_step];
+ } else
+ for (i = 0; i < len; i++)
+ *(uint16_t*)(dst + i*dst_step) = *(uint16_t*)(src + i*src_step);
}
}
static void hblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize,
- int w, int h, int radius, int power, uint8_t *temp[2])
+ int w, int h, int radius, int power, uint8_t *temp[2], int pixsize)
{
int y;
@@ -281,12 +323,12 @@ static void hblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li
return;
for (y = 0; y < h; y++)
- blur_power(dst + y*dst_linesize, 1, src + y*src_linesize, 1,
- w, radius, power, temp);
+ blur_power(dst + y*dst_linesize, pixsize, src + y*src_linesize, pixsize,
+ w, radius, power, temp, pixsize);
}
static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize,
- int w, int h, int radius, int power, uint8_t *temp[2])
+ int w, int h, int radius, int power, uint8_t *temp[2], int pixsize)
{
int x;
@@ -294,8 +336,8 @@ static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li
return;
for (x = 0; x < w; x++)
- blur_power(dst + x, dst_linesize, src + x, src_linesize,
- h, radius, power, temp);
+ blur_power(dst + x*pixsize, dst_linesize, src + x*pixsize, src_linesize,
+ h, radius, power, temp, pixsize);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
@@ -305,9 +347,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
AVFilterLink *outlink = inlink->dst->outputs[0];
AVFrame *out;
int plane;
- int cw = inlink->w >> s->hsub, ch = in->height >> s->vsub;
+ int cw = FF_CEIL_RSHIFT(inlink->w, s->hsub), ch = FF_CEIL_RSHIFT(in->height, s->vsub);
int w[4] = { inlink->w, cw, cw, inlink->w };
int h[4] = { in->height, ch, ch, in->height };
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const int depth = desc->comp[0].depth_minus1 + 1;
+ const int pixsize = (depth+7)/8;
out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
if (!out) {
@@ -316,17 +361,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
av_frame_copy_props(out, in);
- for (plane = 0; in->data[plane] && plane < 4; plane++)
+ for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++)
hblur(out->data[plane], out->linesize[plane],
in ->data[plane], in ->linesize[plane],
w[plane], h[plane], s->radius[plane], s->power[plane],
- s->temp);
+ s->temp, pixsize);
- for (plane = 0; in->data[plane] && plane < 4; plane++)
+ for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++)
vblur(out->data[plane], out->linesize[plane],
out->data[plane], out->linesize[plane],
w[plane], h[plane], s->radius[plane], s->power[plane],
- s->temp);
+ s->temp, pixsize);
av_frame_free(&in);
@@ -334,27 +379,29 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(BoxBlurContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "luma_radius", "Radius of the luma blurring box", OFFSET(luma_radius_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "luma_power", "How many times should the boxblur be applied to luma",
- OFFSET(luma_param.power), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS },
- { "chroma_radius", "Radius of the chroma blurring box", OFFSET(chroma_radius_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "chroma_power", "How many times should the boxblur be applied to chroma",
- OFFSET(chroma_param.power), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS },
- { "alpha_radius", "Radius of the alpha blurring box", OFFSET(alpha_radius_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "alpha_power", "How many times should the boxblur be applied to alpha",
- OFFSET(alpha_param.power), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS },
- { NULL },
-};
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption boxblur_options[] = {
+ { "luma_radius", "Radius of the luma blurring box", OFFSET(luma_param.radius_expr), AV_OPT_TYPE_STRING, {.str="2"}, .flags = FLAGS },
+ { "lr", "Radius of the luma blurring box", OFFSET(luma_param.radius_expr), AV_OPT_TYPE_STRING, {.str="2"}, .flags = FLAGS },
+ { "luma_power", "How many times should the boxblur be applied to luma", OFFSET(luma_param.power), AV_OPT_TYPE_INT, {.i64=2}, 0, INT_MAX, .flags = FLAGS },
+ { "lp", "How many times should the boxblur be applied to luma", OFFSET(luma_param.power), AV_OPT_TYPE_INT, {.i64=2}, 0, INT_MAX, .flags = FLAGS },
-static const AVClass boxblur_class = {
- .class_name = "boxblur",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "chroma_radius", "Radius of the chroma blurring box", OFFSET(chroma_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "cr", "Radius of the chroma blurring box", OFFSET(chroma_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "chroma_power", "How many times should the boxblur be applied to chroma", OFFSET(chroma_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "cp", "How many times should the boxblur be applied to chroma", OFFSET(chroma_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+
+ { "alpha_radius", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "ar", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "alpha_power", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "ap", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(boxblur);
+
static const AVFilterPad avfilter_vf_boxblur_inputs[] = {
{
.name = "default",
@@ -381,7 +428,7 @@ AVFilter ff_vf_boxblur = {
.init = init,
.uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_boxblur_inputs,
- .outputs = avfilter_vf_boxblur_outputs,
+ .inputs = avfilter_vf_boxblur_inputs,
+ .outputs = avfilter_vf_boxblur_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_codecview.c b/libavfilter/vf_codecview.c
new file mode 100644
index 0000000000..27fac3fa97
--- /dev/null
+++ b/libavfilter/vf_codecview.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2014 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Codec debug viewer filter.
+ *
+ * All the MV drawing code from Michael Niedermayer is extracted from
+ * libavcodec/mpegvideo.c.
+ *
+ * TODO: segmentation
+ * TODO: quantization
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/motion_vector.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#define MV_P_FOR (1<<0)
+#define MV_B_FOR (1<<1)
+#define MV_B_BACK (1<<2)
+
+typedef struct {
+ const AVClass *class;
+ unsigned mv;
+} CodecViewContext;
+
+#define OFFSET(x) offsetof(CodecViewContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption codecview_options[] = {
+ { "mv", "set motion vectors to visualize", OFFSET(mv), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, INT_MAX, FLAGS, "mv" },
+ {"pf", "forward predicted MVs of P-frames", 0, AV_OPT_TYPE_CONST, {.i64 = MV_P_FOR }, INT_MIN, INT_MAX, FLAGS, "mv"},
+ {"bf", "forward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = MV_B_FOR }, INT_MIN, INT_MAX, FLAGS, "mv"},
+ {"bb", "backward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = MV_B_BACK }, INT_MIN, INT_MAX, FLAGS, "mv"},
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(codecview);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ // TODO: we can probably add way more pixel formats without any other
+ // changes; anything with 8-bit luma in first plane should be working
+ static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int clip_line(int *sx, int *sy, int *ex, int *ey, int maxx)
+{
+ if(*sx > *ex)
+ return clip_line(ex, ey, sx, sy, maxx);
+
+ if (*sx < 0) {
+ if (*ex < 0)
+ return 1;
+ *sy = *ey + (*sy - *ey) * (int64_t)*ex / (*ex - *sx);
+ *sx = 0;
+ }
+
+ if (*ex > maxx) {
+ if (*sx > maxx)
+ return 1;
+ *ey = *sy + (*ey - *sy) * (int64_t)(maxx - *sx) / (*ex - *sx);
+ *ex = maxx;
+ }
+ return 0;
+}
+
+/**
+ * Draw a line from (ex, ey) -> (sx, sy).
+ * @param w width of the image
+ * @param h height of the image
+ * @param stride stride/linesize of the image
+ * @param color color of the arrow
+ */
+static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey,
+ int w, int h, int stride, int color)
+{
+ int x, y, fr, f;
+
+ if (clip_line(&sx, &sy, &ex, &ey, w - 1))
+ return;
+ if (clip_line(&sy, &sx, &ey, &ex, h - 1))
+ return;
+
+ sx = av_clip(sx, 0, w - 1);
+ sy = av_clip(sy, 0, h - 1);
+ ex = av_clip(ex, 0, w - 1);
+ ey = av_clip(ey, 0, h - 1);
+
+ buf[sy * stride + sx] += color;
+
+ if (FFABS(ex - sx) > FFABS(ey - sy)) {
+ if (sx > ex) {
+ FFSWAP(int, sx, ex);
+ FFSWAP(int, sy, ey);
+ }
+ buf += sx + sy * stride;
+ ex -= sx;
+ f = ((ey - sy) << 16) / ex;
+ for (x = 0; x <= ex; x++) {
+ y = (x * f) >> 16;
+ fr = (x * f) & 0xFFFF;
+ buf[ y * stride + x] += (color * (0x10000 - fr)) >> 16;
+ if(fr) buf[(y + 1) * stride + x] += (color * fr ) >> 16;
+ }
+ } else {
+ if (sy > ey) {
+ FFSWAP(int, sx, ex);
+ FFSWAP(int, sy, ey);
+ }
+ buf += sx + sy * stride;
+ ey -= sy;
+ if (ey)
+ f = ((ex - sx) << 16) / ey;
+ else
+ f = 0;
+ for(y= 0; y <= ey; y++){
+ x = (y*f) >> 16;
+ fr = (y*f) & 0xFFFF;
+ buf[y * stride + x ] += (color * (0x10000 - fr)) >> 16;
+ if(fr) buf[y * stride + x + 1] += (color * fr ) >> 16;
+ }
+ }
+}
+
+/**
+ * Draw an arrow from (ex, ey) -> (sx, sy).
+ * @param w width of the image
+ * @param h height of the image
+ * @param stride stride/linesize of the image
+ * @param color color of the arrow
+ */
+static void draw_arrow(uint8_t *buf, int sx, int sy, int ex,
+ int ey, int w, int h, int stride, int color, int tail, int direction)
+{
+ int dx,dy;
+
+ if (direction) {
+ FFSWAP(int, sx, ex);
+ FFSWAP(int, sy, ey);
+ }
+
+ sx = av_clip(sx, -100, w + 100);
+ sy = av_clip(sy, -100, h + 100);
+ ex = av_clip(ex, -100, w + 100);
+ ey = av_clip(ey, -100, h + 100);
+
+ dx = ex - sx;
+ dy = ey - sy;
+
+ if (dx * dx + dy * dy > 3 * 3) {
+ int rx = dx + dy;
+ int ry = -dx + dy;
+ int length = sqrt((rx * rx + ry * ry) << 8);
+
+ // FIXME subpixel accuracy
+ rx = ROUNDED_DIV(rx * 3 << 4, length);
+ ry = ROUNDED_DIV(ry * 3 << 4, length);
+
+ if (tail) {
+ rx = -rx;
+ ry = -ry;
+ }
+
+ draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, stride, color);
+ draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, stride, color);
+ }
+ draw_line(buf, sx, sy, ex, ey, w, h, stride, color);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ CodecViewContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MOTION_VECTORS);
+ if (sd) {
+ int i;
+ const AVMotionVector *mvs = (const AVMotionVector *)sd->data;
+ for (i = 0; i < sd->size / sizeof(*mvs); i++) {
+ const AVMotionVector *mv = &mvs[i];
+ const int direction = mv->source > 0;
+ if ((direction == 0 && (s->mv & MV_P_FOR) && frame->pict_type == AV_PICTURE_TYPE_P) ||
+ (direction == 0 && (s->mv & MV_B_FOR) && frame->pict_type == AV_PICTURE_TYPE_B) ||
+ (direction == 1 && (s->mv & MV_B_BACK) && frame->pict_type == AV_PICTURE_TYPE_B))
+ draw_arrow(frame->data[0], mv->dst_x, mv->dst_y, mv->src_x, mv->src_y,
+ frame->width, frame->height, frame->linesize[0],
+ 100, 0, mv->source > 0);
+ }
+ }
+ return ff_filter_frame(outlink, frame);
+}
+
+static const AVFilterPad codecview_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .needs_writable = 1,
+ },
+ { NULL }
+};
+
+static const AVFilterPad codecview_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_codecview = {
+ .name = "codecview",
+ .description = NULL_IF_CONFIG_SMALL("Visualize information about some codecs"),
+ .priv_size = sizeof(CodecViewContext),
+ .query_formats = query_formats,
+ .inputs = codecview_inputs,
+ .outputs = codecview_outputs,
+ .priv_class = &codecview_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_colorbalance.c b/libavfilter/vf_colorbalance.c
new file mode 100644
index 0000000000..e37f1995ca
--- /dev/null
+++ b/libavfilter/vf_colorbalance.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+typedef struct {
+ double shadows;
+ double midtones;
+ double highlights;
+} Range;
+
+typedef struct {
+ const AVClass *class;
+ Range cyan_red;
+ Range magenta_green;
+ Range yellow_blue;
+
+ uint8_t lut[3][256];
+
+ uint8_t rgba_map[4];
+ int step;
+} ColorBalanceContext;
+
+#define OFFSET(x) offsetof(ColorBalanceContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption colorbalance_options[] = {
+ { "rs", "set red shadows", OFFSET(cyan_red.shadows), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "gs", "set green shadows", OFFSET(magenta_green.shadows), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "bs", "set blue shadows", OFFSET(yellow_blue.shadows), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "rm", "set red midtones", OFFSET(cyan_red.midtones), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "gm", "set green midtones", OFFSET(magenta_green.midtones), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "bm", "set blue midtones", OFFSET(yellow_blue.midtones), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "rh", "set red highlights", OFFSET(cyan_red.highlights), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "gh", "set green highlights", OFFSET(magenta_green.highlights), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "bh", "set blue highlights", OFFSET(yellow_blue.highlights), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(colorbalance);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ABGR, AV_PIX_FMT_ARGB,
+ AV_PIX_FMT_0BGR, AV_PIX_FMT_0RGB,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ColorBalanceContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
+ double *shadows, *midtones, *highlights, *buffer;
+ int i, r, g, b;
+
+ buffer = av_malloc(256 * 3 * sizeof(*buffer));
+ if (!buffer)
+ return AVERROR(ENOMEM);
+
+ shadows = buffer + 256 * 0;
+ midtones = buffer + 256 * 1;
+ highlights = buffer + 256 * 2;
+
+ for (i = 0; i < 256; i++) {
+ double low = av_clipd((i - 85.0) / -64.0 + 0.5, 0, 1) * 178.5;
+ double mid = av_clipd((i - 85.0) / 64.0 + 0.5, 0, 1) *
+ av_clipd((i + 85.0 - 255.0) / -64.0 + 0.5, 0, 1) * 178.5;
+
+ shadows[i] = low;
+ midtones[i] = mid;
+ highlights[255 - i] = low;
+ }
+
+ for (i = 0; i < 256; i++) {
+ r = g = b = i;
+
+ r = av_clip_uint8(r + s->cyan_red.shadows * shadows[r]);
+ r = av_clip_uint8(r + s->cyan_red.midtones * midtones[r]);
+ r = av_clip_uint8(r + s->cyan_red.highlights * highlights[r]);
+
+ g = av_clip_uint8(g + s->magenta_green.shadows * shadows[g]);
+ g = av_clip_uint8(g + s->magenta_green.midtones * midtones[g]);
+ g = av_clip_uint8(g + s->magenta_green.highlights * highlights[g]);
+
+ b = av_clip_uint8(b + s->yellow_blue.shadows * shadows[b]);
+ b = av_clip_uint8(b + s->yellow_blue.midtones * midtones[b]);
+ b = av_clip_uint8(b + s->yellow_blue.highlights * highlights[b]);
+
+ s->lut[R][i] = r;
+ s->lut[G][i] = g;
+ s->lut[B][i] = b;
+ }
+
+ av_free(buffer);
+
+ ff_fill_rgba_map(s->rgba_map, outlink->format);
+ s->step = av_get_padded_bits_per_pixel(desc) >> 3;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorBalanceContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const uint8_t roffset = s->rgba_map[R];
+ const uint8_t goffset = s->rgba_map[G];
+ const uint8_t boffset = s->rgba_map[B];
+ const uint8_t aoffset = s->rgba_map[A];
+ const int step = s->step;
+ const uint8_t *srcrow = in->data[0];
+ uint8_t *dstrow;
+ AVFrame *out;
+ int i, j;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ dstrow = out->data[0];
+ for (i = 0; i < outlink->h; i++) {
+ const uint8_t *src = srcrow;
+ uint8_t *dst = dstrow;
+
+ for (j = 0; j < outlink->w * step; j += step) {
+ dst[j + roffset] = s->lut[R][src[j + roffset]];
+ dst[j + goffset] = s->lut[G][src[j + goffset]];
+ dst[j + boffset] = s->lut[B][src[j + boffset]];
+ if (in != out && step == 4)
+ dst[j + aoffset] = src[j + aoffset];
+ }
+
+ srcrow += in->linesize[0];
+ dstrow += out->linesize[0];
+ }
+
+ if (in != out)
+ av_frame_free(&in);
+ return ff_filter_frame(ctx->outputs[0], out);
+}
+
+static const AVFilterPad colorbalance_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad colorbalance_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_colorbalance = {
+ .name = "colorbalance",
+ .description = NULL_IF_CONFIG_SMALL("Adjust the color balance."),
+ .priv_size = sizeof(ColorBalanceContext),
+ .priv_class = &colorbalance_class,
+ .query_formats = query_formats,
+ .inputs = colorbalance_inputs,
+ .outputs = colorbalance_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_colorchannelmixer.c b/libavfilter/vf_colorchannelmixer.c
new file mode 100644
index 0000000000..0fffd341c5
--- /dev/null
+++ b/libavfilter/vf_colorchannelmixer.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+typedef struct {
+ const AVClass *class;
+ double rr, rg, rb, ra;
+ double gr, gg, gb, ga;
+ double br, bg, bb, ba;
+ double ar, ag, ab, aa;
+
+ int *lut[4][4];
+
+ int *buffer;
+
+ uint8_t rgba_map[4];
+} ColorChannelMixerContext;
+
+#define OFFSET(x) offsetof(ColorChannelMixerContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption colorchannelmixer_options[] = {
+ { "rr", "set the red gain for the red channel", OFFSET(rr), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
+ { "rg", "set the green gain for the red channel", OFFSET(rg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "rb", "set the blue gain for the red channel", OFFSET(rb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "ra", "set the alpha gain for the red channel", OFFSET(ra), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "gr", "set the red gain for the green channel", OFFSET(gr), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "gg", "set the green gain for the green channel", OFFSET(gg), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
+ { "gb", "set the blue gain for the green channel", OFFSET(gb), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "ga", "set the alpha gain for the green channel", OFFSET(ga), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "br", "set the red gain for the blue channel", OFFSET(br), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "bg", "set the green gain for the blue channel", OFFSET(bg), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "bb", "set the blue gain for the blue channel", OFFSET(bb), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
+ { "ba", "set the alpha gain for the blue channel", OFFSET(ba), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "ar", "set the red gain for the alpha channel", OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "ag", "set the green gain for the alpha channel", OFFSET(ag), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "ab", "set the blue gain for the alpha channel", OFFSET(ab), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -2, 2, FLAGS },
+ { "aa", "set the alpha gain for the alpha channel", OFFSET(aa), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -2, 2, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(colorchannelmixer);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48,
+ AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ColorChannelMixerContext *s = ctx->priv;
+ int i, j, size, *buffer;
+
+ ff_fill_rgba_map(s->rgba_map, outlink->format);
+
+ switch (outlink->format) {
+ case AV_PIX_FMT_RGB48:
+ case AV_PIX_FMT_BGR48:
+ case AV_PIX_FMT_RGBA64:
+ case AV_PIX_FMT_BGRA64:
+ size = 65536;
+ break;
+ default:
+ size = 256;
+ }
+
+ s->buffer = buffer = av_malloc(16 * size * sizeof(*s->buffer));
+ if (!s->buffer)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++, buffer += size)
+ s->lut[i][j] = buffer;
+
+ for (i = 0; i < size; i++) {
+ s->lut[R][R][i] = round(i * s->rr);
+ s->lut[R][G][i] = round(i * s->rg);
+ s->lut[R][B][i] = round(i * s->rb);
+ s->lut[R][A][i] = round(i * s->ra);
+
+ s->lut[G][R][i] = round(i * s->gr);
+ s->lut[G][G][i] = round(i * s->gg);
+ s->lut[G][B][i] = round(i * s->gb);
+ s->lut[G][A][i] = round(i * s->ga);
+
+ s->lut[B][R][i] = round(i * s->br);
+ s->lut[B][G][i] = round(i * s->bg);
+ s->lut[B][B][i] = round(i * s->bb);
+ s->lut[B][A][i] = round(i * s->ba);
+
+ s->lut[A][R][i] = round(i * s->ar);
+ s->lut[A][G][i] = round(i * s->ag);
+ s->lut[A][B][i] = round(i * s->ab);
+ s->lut[A][A][i] = round(i * s->aa);
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorChannelMixerContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const uint8_t roffset = s->rgba_map[R];
+ const uint8_t goffset = s->rgba_map[G];
+ const uint8_t boffset = s->rgba_map[B];
+ const uint8_t aoffset = s->rgba_map[A];
+ const uint8_t *srcrow = in->data[0];
+ uint8_t *dstrow;
+ AVFrame *out;
+ int i, j;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ dstrow = out->data[0];
+ switch (outlink->format) {
+ case AV_PIX_FMT_BGR24:
+ case AV_PIX_FMT_RGB24:
+ for (i = 0; i < outlink->h; i++) {
+ const uint8_t *src = srcrow;
+ uint8_t *dst = dstrow;
+
+ for (j = 0; j < outlink->w * 3; j += 3) {
+ const uint8_t rin = src[j + roffset];
+ const uint8_t gin = src[j + goffset];
+ const uint8_t bin = src[j + boffset];
+
+ dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] +
+ s->lut[R][G][gin] +
+ s->lut[R][B][bin]);
+ dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] +
+ s->lut[G][G][gin] +
+ s->lut[G][B][bin]);
+ dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] +
+ s->lut[B][G][gin] +
+ s->lut[B][B][bin]);
+ }
+
+ srcrow += in->linesize[0];
+ dstrow += out->linesize[0];
+ }
+ break;
+ case AV_PIX_FMT_0BGR:
+ case AV_PIX_FMT_0RGB:
+ case AV_PIX_FMT_BGR0:
+ case AV_PIX_FMT_RGB0:
+ for (i = 0; i < outlink->h; i++) {
+ const uint8_t *src = srcrow;
+ uint8_t *dst = dstrow;
+
+ for (j = 0; j < outlink->w * 4; j += 4) {
+ const uint8_t rin = src[j + roffset];
+ const uint8_t gin = src[j + goffset];
+ const uint8_t bin = src[j + boffset];
+
+ dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] +
+ s->lut[R][G][gin] +
+ s->lut[R][B][bin]);
+ dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] +
+ s->lut[G][G][gin] +
+ s->lut[G][B][bin]);
+ dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] +
+ s->lut[B][G][gin] +
+ s->lut[B][B][bin]);
+ if (in != out)
+ dst[j + aoffset] = 0;
+ }
+
+ srcrow += in->linesize[0];
+ dstrow += out->linesize[0];
+ }
+ break;
+ case AV_PIX_FMT_ABGR:
+ case AV_PIX_FMT_ARGB:
+ case AV_PIX_FMT_BGRA:
+ case AV_PIX_FMT_RGBA:
+ for (i = 0; i < outlink->h; i++) {
+ const uint8_t *src = srcrow;
+ uint8_t *dst = dstrow;
+
+ for (j = 0; j < outlink->w * 4; j += 4) {
+ const uint8_t rin = src[j + roffset];
+ const uint8_t gin = src[j + goffset];
+ const uint8_t bin = src[j + boffset];
+ const uint8_t ain = src[j + aoffset];
+
+ dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] +
+ s->lut[R][G][gin] +
+ s->lut[R][B][bin] +
+ s->lut[R][A][ain]);
+ dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] +
+ s->lut[G][G][gin] +
+ s->lut[G][B][bin] +
+ s->lut[G][A][ain]);
+ dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] +
+ s->lut[B][G][gin] +
+ s->lut[B][B][bin] +
+ s->lut[B][A][ain]);
+ dst[j + aoffset] = av_clip_uint8(s->lut[A][R][rin] +
+ s->lut[A][G][gin] +
+ s->lut[A][B][bin] +
+ s->lut[A][A][ain]);
+ }
+
+ srcrow += in->linesize[0];
+ dstrow += out->linesize[0];
+ }
+ break;
+ case AV_PIX_FMT_BGR48:
+ case AV_PIX_FMT_RGB48:
+ for (i = 0; i < outlink->h; i++) {
+ const uint16_t *src = (const uint16_t *)srcrow;
+ uint16_t *dst = (uint16_t *)dstrow;
+
+ for (j = 0; j < outlink->w * 3; j += 3) {
+ const uint16_t rin = src[j + roffset];
+ const uint16_t gin = src[j + goffset];
+ const uint16_t bin = src[j + boffset];
+
+ dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] +
+ s->lut[R][G][gin] +
+ s->lut[R][B][bin]);
+ dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] +
+ s->lut[G][G][gin] +
+ s->lut[G][B][bin]);
+ dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] +
+ s->lut[B][G][gin] +
+ s->lut[B][B][bin]);
+ }
+
+ srcrow += in->linesize[0];
+ dstrow += out->linesize[0];
+ }
+ break;
+ case AV_PIX_FMT_BGRA64:
+ case AV_PIX_FMT_RGBA64:
+ for (i = 0; i < outlink->h; i++) {
+ const uint16_t *src = (const uint16_t *)srcrow;
+ uint16_t *dst = (uint16_t *)dstrow;
+
+ for (j = 0; j < outlink->w * 4; j += 4) {
+ const uint16_t rin = src[j + roffset];
+ const uint16_t gin = src[j + goffset];
+ const uint16_t bin = src[j + boffset];
+ const uint16_t ain = src[j + aoffset];
+
+ dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] +
+ s->lut[R][G][gin] +
+ s->lut[R][B][bin] +
+ s->lut[R][A][ain]);
+ dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] +
+ s->lut[G][G][gin] +
+ s->lut[G][B][bin] +
+ s->lut[G][A][ain]);
+ dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] +
+ s->lut[B][G][gin] +
+ s->lut[B][B][bin] +
+ s->lut[B][A][ain]);
+ dst[j + aoffset] = av_clip_uint16(s->lut[A][R][rin] +
+ s->lut[A][G][gin] +
+ s->lut[A][B][bin] +
+ s->lut[A][A][ain]);
+ }
+
+ srcrow += in->linesize[0];
+ dstrow += out->linesize[0];
+ }
+ }
+
+ if (in != out)
+ av_frame_free(&in);
+ return ff_filter_frame(ctx->outputs[0], out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ColorChannelMixerContext *s = ctx->priv;
+
+ av_freep(&s->buffer);
+}
+
+static const AVFilterPad colorchannelmixer_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad colorchannelmixer_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_colorchannelmixer = {
+ .name = "colorchannelmixer",
+ .description = NULL_IF_CONFIG_SMALL("Adjust colors by mixing color channels."),
+ .priv_size = sizeof(ColorChannelMixerContext),
+ .priv_class = &colorchannelmixer_class,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = colorchannelmixer_inputs,
+ .outputs = colorchannelmixer_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_colorlevels.c b/libavfilter/vf_colorlevels.c
new file mode 100644
index 0000000000..7157c9138a
--- /dev/null
+++ b/libavfilter/vf_colorlevels.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+typedef struct {
+ double in_min, in_max;
+ double out_min, out_max;
+} Range;
+
+typedef struct {
+ const AVClass *class;
+ Range range[4];
+ int nb_comp;
+ int bpp;
+ int step;
+ uint8_t rgba_map[4];
+ int linesize;
+} ColorLevelsContext;
+
+#define OFFSET(x) offsetof(ColorLevelsContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption colorlevels_options[] = {
+ { "rimin", "set input red black point", OFFSET(range[R].in_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "gimin", "set input green black point", OFFSET(range[G].in_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "bimin", "set input blue black point", OFFSET(range[B].in_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "aimin", "set input alpha black point", OFFSET(range[A].in_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS },
+ { "rimax", "set input red white point", OFFSET(range[R].in_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS },
+ { "gimax", "set input green white point", OFFSET(range[G].in_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS },
+ { "bimax", "set input blue white point", OFFSET(range[B].in_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS },
+ { "aimax", "set input alpha white point", OFFSET(range[A].in_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS },
+ { "romin", "set output red black point", OFFSET(range[R].out_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS },
+ { "gomin", "set output green black point", OFFSET(range[G].out_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS },
+ { "bomin", "set output blue black point", OFFSET(range[B].out_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS },
+ { "aomin", "set output alpha black point", OFFSET(range[A].out_min), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS },
+ { "romax", "set output red white point", OFFSET(range[R].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
+ { "gomax", "set output green white point", OFFSET(range[G].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
+ { "bomax", "set output blue white point", OFFSET(range[B].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
+ { "aomax", "set output alpha white point", OFFSET(range[A].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(colorlevels);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48,
+ AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorLevelsContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ s->nb_comp = desc->nb_components;
+ s->bpp = (desc->comp[0].depth_minus1 + 1) >> 3;
+ s->step = (av_get_padded_bits_per_pixel(desc) >> 3) / s->bpp;
+ s->linesize = inlink->w * s->step;
+ ff_fill_rgba_map(s->rgba_map, inlink->format);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorLevelsContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const int step = s->step;
+ AVFrame *out;
+ int x, y, i;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ switch (s->bpp) {
+ case 1:
+ for (i = 0; i < s->nb_comp; i++) {
+ Range *r = &s->range[i];
+ const uint8_t offset = s->rgba_map[i];
+ const uint8_t *srcrow = in->data[0];
+ uint8_t *dstrow = out->data[0];
+ int imin = round(r->in_min * UINT8_MAX);
+ int imax = round(r->in_max * UINT8_MAX);
+ int omin = round(r->out_min * UINT8_MAX);
+ int omax = round(r->out_max * UINT8_MAX);
+ double coeff;
+
+ if (imin < 0) {
+ imin = UINT8_MAX;
+ for (y = 0; y < inlink->h; y++) {
+ const uint8_t *src = srcrow;
+
+ for (x = 0; x < s->linesize; x += step)
+ imin = FFMIN(imin, src[x + offset]);
+ srcrow += in->linesize[0];
+ }
+ }
+ if (imax < 0) {
+ srcrow = in->data[0];
+ imax = 0;
+ for (y = 0; y < inlink->h; y++) {
+ const uint8_t *src = srcrow;
+
+ for (x = 0; x < s->linesize; x += step)
+ imax = FFMAX(imax, src[x + offset]);
+ srcrow += in->linesize[0];
+ }
+ }
+
+ srcrow = in->data[0];
+ coeff = (omax - omin) / (double)(imax - imin);
+ for (y = 0; y < inlink->h; y++) {
+ const uint8_t *src = srcrow;
+ uint8_t *dst = dstrow;
+
+ for (x = 0; x < s->linesize; x += step)
+ dst[x + offset] = av_clip_uint8((src[x + offset] - imin) * coeff + omin);
+ dstrow += out->linesize[0];
+ srcrow += in->linesize[0];
+ }
+ }
+ break;
+ case 2:
+ for (i = 0; i < s->nb_comp; i++) {
+ Range *r = &s->range[i];
+ const uint8_t offset = s->rgba_map[i];
+ const uint8_t *srcrow = in->data[0];
+ uint8_t *dstrow = out->data[0];
+ int imin = round(r->in_min * UINT16_MAX);
+ int imax = round(r->in_max * UINT16_MAX);
+ int omin = round(r->out_min * UINT16_MAX);
+ int omax = round(r->out_max * UINT16_MAX);
+ double coeff;
+
+ if (imin < 0) {
+ imin = UINT16_MAX;
+ for (y = 0; y < inlink->h; y++) {
+ const uint16_t *src = (const uint16_t *)srcrow;
+
+ for (x = 0; x < s->linesize; x += step)
+ imin = FFMIN(imin, src[x + offset]);
+ srcrow += in->linesize[0];
+ }
+ }
+ if (imax < 0) {
+ srcrow = in->data[0];
+ imax = 0;
+ for (y = 0; y < inlink->h; y++) {
+ const uint16_t *src = (const uint16_t *)srcrow;
+
+ for (x = 0; x < s->linesize; x += step)
+ imax = FFMAX(imax, src[x + offset]);
+ srcrow += in->linesize[0];
+ }
+ }
+
+ srcrow = in->data[0];
+ coeff = (omax - omin) / (double)(imax - imin);
+ for (y = 0; y < inlink->h; y++) {
+ const uint16_t *src = (const uint16_t*)srcrow;
+ uint16_t *dst = (uint16_t *)dstrow;
+
+ for (x = 0; x < s->linesize; x += step)
+ dst[x + offset] = av_clip_uint16((src[x + offset] - imin) * coeff + omin);
+ dstrow += out->linesize[0];
+ srcrow += in->linesize[0];
+ }
+ }
+ }
+
+ if (in != out)
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad colorlevels_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad colorlevels_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_colorlevels = {
+ .name = "colorlevels",
+ .description = NULL_IF_CONFIG_SMALL("Adjust the color levels."),
+ .priv_size = sizeof(ColorLevelsContext),
+ .priv_class = &colorlevels_class,
+ .query_formats = query_formats,
+ .inputs = colorlevels_inputs,
+ .outputs = colorlevels_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_colormatrix.c b/libavfilter/vf_colormatrix.c
new file mode 100644
index 0000000000..fde4b897fd
--- /dev/null
+++ b/libavfilter/vf_colormatrix.c
@@ -0,0 +1,456 @@
+/*
+ * ColorMatrix v2.2 for Avisynth 2.5.x
+ *
+ * Copyright (C) 2006-2007 Kevin Stone
+ *
+ * ColorMatrix 1.x is Copyright (C) Wilbert Dijkhof
+ *
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * OUT 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * ColorMatrix 2.0 is based on the original ColorMatrix filter by Wilbert
+ * Dijkhof. It adds the ability to convert between any of: Rec.709, FCC,
+ * Rec.601, and SMPTE 240M. It also makes pre and post clipping optional,
+ * adds an option to use scaled or non-scaled coefficients, and more...
+ */
+
+#include <float.h>
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/avstring.h"
+
+#define NS(n) ((n) < 0 ? (int)((n)*65536.0-0.5+DBL_EPSILON) : (int)((n)*65536.0+0.5))
+#define CB(n) av_clip_uint8(n)
+
+static const double yuv_coeff[4][3][3] = {
+ { { +0.7152, +0.0722, +0.2126 }, // Rec.709 (0)
+ { -0.3850, +0.5000, -0.1150 },
+ { -0.4540, -0.0460, +0.5000 } },
+ { { +0.5900, +0.1100, +0.3000 }, // FCC (1)
+ { -0.3310, +0.5000, -0.1690 },
+ { -0.4210, -0.0790, +0.5000 } },
+ { { +0.5870, +0.1140, +0.2990 }, // Rec.601 (ITU-R BT.470-2/SMPTE 170M) (2)
+ { -0.3313, +0.5000, -0.1687 },
+ { -0.4187, -0.0813, +0.5000 } },
+ { { +0.7010, +0.0870, +0.2120 }, // SMPTE 240M (3)
+ { -0.3840, +0.5000, -0.1160 },
+ { -0.4450, -0.0550, +0.5000 } },
+};
+
+enum ColorMode {
+ COLOR_MODE_NONE = -1,
+ COLOR_MODE_BT709,
+ COLOR_MODE_FCC,
+ COLOR_MODE_BT601,
+ COLOR_MODE_SMPTE240M,
+ COLOR_MODE_COUNT
+};
+
+typedef struct {
+ const AVClass *class;
+ int yuv_convert[16][3][3];
+ int interlaced;
+ int source, dest; ///< ColorMode
+ int mode;
+ int hsub, vsub;
+} ColorMatrixContext;
+
+typedef struct ThreadData {
+ AVFrame *dst;
+ const AVFrame *src;
+ int c2;
+ int c3;
+ int c4;
+ int c5;
+ int c6;
+ int c7;
+} ThreadData;
+
+#define OFFSET(x) offsetof(ColorMatrixContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption colormatrix_options[] = {
+ { "src", "set source color matrix", OFFSET(source), AV_OPT_TYPE_INT, {.i64=COLOR_MODE_NONE}, COLOR_MODE_NONE, COLOR_MODE_COUNT-1, .flags=FLAGS, .unit="color_mode" },
+ { "dst", "set destination color matrix", OFFSET(dest), AV_OPT_TYPE_INT, {.i64=COLOR_MODE_NONE}, COLOR_MODE_NONE, COLOR_MODE_COUNT-1, .flags=FLAGS, .unit="color_mode" },
+ { "bt709", "set BT.709 colorspace", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_BT709}, .flags=FLAGS, .unit="color_mode" },
+ { "fcc", "set FCC colorspace ", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_FCC}, .flags=FLAGS, .unit="color_mode" },
+ { "bt601", "set BT.601 colorspace", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_BT601}, .flags=FLAGS, .unit="color_mode" },
+ { "bt470", "set BT.470 colorspace", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_BT601}, .flags=FLAGS, .unit="color_mode" },
+ { "smpte170m", "set SMTPE-170M colorspace", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_BT601}, .flags=FLAGS, .unit="color_mode" },
+ { "smpte240m", "set SMPTE-240M colorspace", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_MODE_SMPTE240M}, .flags=FLAGS, .unit="color_mode" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(colormatrix);
+
+#define ma m[0][0]
+#define mb m[0][1]
+#define mc m[0][2]
+#define md m[1][0]
+#define me m[1][1]
+#define mf m[1][2]
+#define mg m[2][0]
+#define mh m[2][1]
+#define mi m[2][2]
+
+#define ima im[0][0]
+#define imb im[0][1]
+#define imc im[0][2]
+#define imd im[1][0]
+#define ime im[1][1]
+#define imf im[1][2]
+#define img im[2][0]
+#define imh im[2][1]
+#define imi im[2][2]
+
+static void inverse3x3(double im[3][3], const double m[3][3])
+{
+ double det = ma * (me * mi - mf * mh) - mb * (md * mi - mf * mg) + mc * (md * mh - me * mg);
+ det = 1.0 / det;
+ ima = det * (me * mi - mf * mh);
+ imb = det * (mc * mh - mb * mi);
+ imc = det * (mb * mf - mc * me);
+ imd = det * (mf * mg - md * mi);
+ ime = det * (ma * mi - mc * mg);
+ imf = det * (mc * md - ma * mf);
+ img = det * (md * mh - me * mg);
+ imh = det * (mb * mg - ma * mh);
+ imi = det * (ma * me - mb * md);
+}
+
+static void solve_coefficients(double cm[3][3], double rgb[3][3], const double yuv[3][3])
+{
+ int i, j;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ cm[i][j] = yuv[i][0] * rgb[0][j] + yuv[i][1] * rgb[1][j] + yuv[i][2] * rgb[2][j];
+}
+
+static void calc_coefficients(AVFilterContext *ctx)
+{
+ ColorMatrixContext *color = ctx->priv;
+ double rgb_coeffd[4][3][3];
+ double yuv_convertd[16][3][3];
+ int v = 0;
+ int i, j, k;
+
+ for (i = 0; i < 4; i++)
+ inverse3x3(rgb_coeffd[i], yuv_coeff[i]);
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ solve_coefficients(yuv_convertd[v], rgb_coeffd[i], yuv_coeff[j]);
+ for (k = 0; k < 3; k++) {
+ color->yuv_convert[v][k][0] = NS(yuv_convertd[v][k][0]);
+ color->yuv_convert[v][k][1] = NS(yuv_convertd[v][k][1]);
+ color->yuv_convert[v][k][2] = NS(yuv_convertd[v][k][2]);
+ }
+ if (color->yuv_convert[v][0][0] != 65536 || color->yuv_convert[v][1][0] != 0 ||
+ color->yuv_convert[v][2][0] != 0) {
+ av_log(ctx, AV_LOG_ERROR, "error calculating conversion coefficients\n");
+ }
+ v++;
+ }
+ }
+}
+
+static const char * const color_modes[] = {"bt709", "fcc", "bt601", "smpte240m"};
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ColorMatrixContext *color = ctx->priv;
+
+ if (color->dest == COLOR_MODE_NONE) {
+ av_log(ctx, AV_LOG_ERROR, "Unspecified destination color space\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (color->source == color->dest) {
+ av_log(ctx, AV_LOG_ERROR, "Source and destination color space must not be identical\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int process_slice_uyvy422(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ const ThreadData *td = arg;
+ const AVFrame *src = td->src;
+ AVFrame *dst = td->dst;
+ const int height = src->height;
+ const int width = src->width*2;
+ const int src_pitch = src->linesize[0];
+ const int dst_pitch = dst->linesize[0];
+ const int slice_start = (height * jobnr ) / nb_jobs;
+ const int slice_end = (height * (jobnr+1)) / nb_jobs;
+ const unsigned char *srcp = src->data[0] + slice_start * src_pitch;
+ unsigned char *dstp = dst->data[0] + slice_start * dst_pitch;
+ const int c2 = td->c2;
+ const int c3 = td->c3;
+ const int c4 = td->c4;
+ const int c5 = td->c5;
+ const int c6 = td->c6;
+ const int c7 = td->c7;
+ int x, y;
+
+ for (y = slice_start; y < slice_end; y++) {
+ for (x = 0; x < width; x += 4) {
+ const int u = srcp[x + 0] - 128;
+ const int v = srcp[x + 2] - 128;
+ const int uvval = c2 * u + c3 * v + 1081344;
+ dstp[x + 0] = CB((c4 * u + c5 * v + 8421376) >> 16);
+ dstp[x + 1] = CB((65536 * (srcp[x + 1] - 16) + uvval) >> 16);
+ dstp[x + 2] = CB((c6 * u + c7 * v + 8421376) >> 16);
+ dstp[x + 3] = CB((65536 * (srcp[x + 3] - 16) + uvval) >> 16);
+ }
+ srcp += src_pitch;
+ dstp += dst_pitch;
+ }
+
+ return 0;
+}
+
+static int process_slice_yuv422p(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ const ThreadData *td = arg;
+ const AVFrame *src = td->src;
+ AVFrame *dst = td->dst;
+ const int height = src->height;
+ const int width = src->width;
+ const int slice_start = (height * jobnr ) / nb_jobs;
+ const int slice_end = (height * (jobnr+1)) / nb_jobs;
+ const int src_pitchY = src->linesize[0];
+ const int src_pitchUV = src->linesize[1];
+ const unsigned char *srcpU = src->data[1] + slice_start * src_pitchUV;
+ const unsigned char *srcpV = src->data[2] + slice_start * src_pitchUV;
+ const unsigned char *srcpY = src->data[0] + slice_start * src_pitchY;
+ const int dst_pitchY = dst->linesize[0];
+ const int dst_pitchUV = dst->linesize[1];
+ unsigned char *dstpU = dst->data[1] + slice_start * dst_pitchUV;
+ unsigned char *dstpV = dst->data[2] + slice_start * dst_pitchUV;
+ unsigned char *dstpY = dst->data[0] + slice_start * dst_pitchY;
+ const int c2 = td->c2;
+ const int c3 = td->c3;
+ const int c4 = td->c4;
+ const int c5 = td->c5;
+ const int c6 = td->c6;
+ const int c7 = td->c7;
+ int x, y;
+
+ for (y = slice_start; y < slice_end; y++) {
+ for (x = 0; x < width; x += 2) {
+ const int u = srcpU[x >> 1] - 128;
+ const int v = srcpV[x >> 1] - 128;
+ const int uvval = c2 * u + c3 * v + 1081344;
+ dstpY[x + 0] = CB((65536 * (srcpY[x + 0] - 16) + uvval) >> 16);
+ dstpY[x + 1] = CB((65536 * (srcpY[x + 1] - 16) + uvval) >> 16);
+ dstpU[x >> 1] = CB((c4 * u + c5 * v + 8421376) >> 16);
+ dstpV[x >> 1] = CB((c6 * u + c7 * v + 8421376) >> 16);
+ }
+ srcpY += src_pitchY;
+ dstpY += dst_pitchY;
+ srcpU += src_pitchUV;
+ srcpV += src_pitchUV;
+ dstpU += dst_pitchUV;
+ dstpV += dst_pitchUV;
+ }
+
+ return 0;
+}
+
+static int process_slice_yuv420p(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ const ThreadData *td = arg;
+ const AVFrame *src = td->src;
+ AVFrame *dst = td->dst;
+ const int height = FFALIGN(src->height, 2) >> 1;
+ const int width = src->width;
+ const int slice_start = ((height * jobnr ) / nb_jobs) << 1;
+ const int slice_end = ((height * (jobnr+1)) / nb_jobs) << 1;
+ const int src_pitchY = src->linesize[0];
+ const int src_pitchUV = src->linesize[1];
+ const int dst_pitchY = dst->linesize[0];
+ const int dst_pitchUV = dst->linesize[1];
+ const unsigned char *srcpY = src->data[0] + src_pitchY * slice_start;
+ const unsigned char *srcpU = src->data[1] + src_pitchUV * (slice_start >> 1);
+ const unsigned char *srcpV = src->data[2] + src_pitchUV * (slice_start >> 1);
+ const unsigned char *srcpN = src->data[0] + src_pitchY * (slice_start + 1);
+ unsigned char *dstpU = dst->data[1] + dst_pitchUV * (slice_start >> 1);
+ unsigned char *dstpV = dst->data[2] + dst_pitchUV * (slice_start >> 1);
+ unsigned char *dstpY = dst->data[0] + dst_pitchY * slice_start;
+ unsigned char *dstpN = dst->data[0] + dst_pitchY * (slice_start + 1);
+ const int c2 = td->c2;
+ const int c3 = td->c3;
+ const int c4 = td->c4;
+ const int c5 = td->c5;
+ const int c6 = td->c6;
+ const int c7 = td->c7;
+ int x, y;
+
+ for (y = slice_start; y < slice_end; y += 2) {
+ for (x = 0; x < width; x += 2) {
+ const int u = srcpU[x >> 1] - 128;
+ const int v = srcpV[x >> 1] - 128;
+ const int uvval = c2 * u + c3 * v + 1081344;
+ dstpY[x + 0] = CB((65536 * (srcpY[x + 0] - 16) + uvval) >> 16);
+ dstpY[x + 1] = CB((65536 * (srcpY[x + 1] - 16) + uvval) >> 16);
+ dstpN[x + 0] = CB((65536 * (srcpN[x + 0] - 16) + uvval) >> 16);
+ dstpN[x + 1] = CB((65536 * (srcpN[x + 1] - 16) + uvval) >> 16);
+ dstpU[x >> 1] = CB((c4 * u + c5 * v + 8421376) >> 16);
+ dstpV[x >> 1] = CB((c6 * u + c7 * v + 8421376) >> 16);
+ }
+ srcpY += src_pitchY << 1;
+ dstpY += dst_pitchY << 1;
+ srcpN += src_pitchY << 1;
+ dstpN += dst_pitchY << 1;
+ srcpU += src_pitchUV;
+ srcpV += src_pitchUV;
+ dstpU += dst_pitchUV;
+ dstpV += dst_pitchUV;
+ }
+
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ColorMatrixContext *color = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+
+ color->hsub = pix_desc->log2_chroma_w;
+ color->vsub = pix_desc->log2_chroma_h;
+
+ av_log(ctx, AV_LOG_VERBOSE, "%s -> %s\n",
+ color_modes[color->source], color_modes[color->dest]);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_UYVY422,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int filter_frame(AVFilterLink *link, AVFrame *in)
+{
+ AVFilterContext *ctx = link->dst;
+ ColorMatrixContext *color = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ ThreadData td = {0};
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ if (color->source == COLOR_MODE_NONE) {
+ enum AVColorSpace cs = av_frame_get_colorspace(in);
+ enum ColorMode source;
+
+ switch(cs) {
+ case AVCOL_SPC_BT709 : source = COLOR_MODE_BT709 ; break;
+ case AVCOL_SPC_FCC : source = COLOR_MODE_FCC ; break;
+ case AVCOL_SPC_SMPTE240M : source = COLOR_MODE_SMPTE240M ; break;
+ case AVCOL_SPC_BT470BG : source = COLOR_MODE_BT601 ; break;
+ case AVCOL_SPC_SMPTE170M : source = COLOR_MODE_BT601 ; break;
+ default :
+ av_log(ctx, AV_LOG_ERROR, "Input frame does not specify a supported colorspace, and none has been specified as source either\n");
+ av_frame_free(&out);
+ return AVERROR(EINVAL);
+ }
+ color->mode = source * 4 + color->dest;
+ } else
+ color->mode = color->source * 4 + color->dest;
+
+ switch(color->dest) {
+ case COLOR_MODE_BT709 : av_frame_set_colorspace(out, AVCOL_SPC_BT709) ; break;
+ case COLOR_MODE_FCC : av_frame_set_colorspace(out, AVCOL_SPC_FCC) ; break;
+ case COLOR_MODE_SMPTE240M: av_frame_set_colorspace(out, AVCOL_SPC_SMPTE240M); break;
+ case COLOR_MODE_BT601 : av_frame_set_colorspace(out, AVCOL_SPC_BT470BG) ; break;
+ }
+
+ calc_coefficients(ctx);
+
+ td.src = in;
+ td.dst = out;
+ td.c2 = color->yuv_convert[color->mode][0][1];
+ td.c3 = color->yuv_convert[color->mode][0][2];
+ td.c4 = color->yuv_convert[color->mode][1][1];
+ td.c5 = color->yuv_convert[color->mode][1][2];
+ td.c6 = color->yuv_convert[color->mode][2][1];
+ td.c7 = color->yuv_convert[color->mode][2][2];
+
+ if (in->format == AV_PIX_FMT_YUV422P)
+ ctx->internal->execute(ctx, process_slice_yuv422p, &td, NULL,
+ FFMIN(in->height, ctx->graph->nb_threads));
+ else if (in->format == AV_PIX_FMT_YUV420P)
+ ctx->internal->execute(ctx, process_slice_yuv420p, &td, NULL,
+ FFMIN(in->height / 2, ctx->graph->nb_threads));
+ else
+ ctx->internal->execute(ctx, process_slice_uyvy422, &td, NULL,
+ FFMIN(in->height, ctx->graph->nb_threads));
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad colormatrix_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad colormatrix_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_colormatrix = {
+ .name = "colormatrix",
+ .description = NULL_IF_CONFIG_SMALL("Convert color matrix."),
+ .priv_size = sizeof(ColorMatrixContext),
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = colormatrix_inputs,
+ .outputs = colormatrix_outputs,
+ .priv_class = &colormatrix_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_copy.c b/libavfilter/vf_copy.c
index 5e60f2082e..fb9a906048 100644
--- a/libavfilter/vf_copy.c
+++ b/libavfilter/vf_copy.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,10 +44,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static const AVFilterPad avfilter_vf_copy_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -61,9 +60,8 @@ static const AVFilterPad avfilter_vf_copy_outputs[] = {
};
AVFilter ff_vf_copy = {
- .name = "copy",
+ .name = "copy",
.description = NULL_IF_CONFIG_SMALL("Copy the input video unchanged to the output."),
-
- .inputs = avfilter_vf_copy_inputs,
- .outputs = avfilter_vf_copy_outputs,
+ .inputs = avfilter_vf_copy_inputs,
+ .outputs = avfilter_vf_copy_outputs,
};
diff --git a/libavfilter/vf_cover_rect.c b/libavfilter/vf_cover_rect.c
new file mode 100644
index 0000000000..c2020bb392
--- /dev/null
+++ b/libavfilter/vf_cover_rect.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2014-2015 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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.
+ */
+
+/**
+ * @todo switch to dualinput
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+
+#include "lavfutils.h"
+
+enum mode {
+ MODE_COVER,
+ MODE_BLUR,
+ NB_MODES
+};
+
+typedef struct CoverContext {
+ AVClass *class;
+ int mode;
+ char *cover_filename;
+ AVFrame *cover_frame;
+ int width, height;
+} CoverContext;
+
+#define OFFSET(x) offsetof(CoverContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption cover_rect_options[] = {
+ { "cover", "cover bitmap filename", OFFSET(cover_filename), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
+ { "mode", "set removal mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_BLUR}, 0, NB_MODES - 1, FLAGS, "mode" },
+ { "cover", "cover area with bitmap", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_COVER}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "blur", "blur area", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_BLUR}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { NULL }
+};
+
+static const AVClass cover_rect_class = {
+ .class_name = "cover_rect",
+ .item_name = av_default_item_name,
+ .option = cover_rect_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_NONE
+ };
+
+ return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ return 0;
+}
+
+static void cover_rect(CoverContext *cover, AVFrame *in, int offx, int offy)
+{
+ int x, y, p;
+
+ for (p = 0; p < 3; p++) {
+ uint8_t *data = in->data[p] + (offx>>!!p) + (offy>>!!p) * in->linesize[p];
+ const uint8_t *src = cover->cover_frame->data[p];
+ int w = FF_CEIL_RSHIFT(cover->cover_frame->width , !!p);
+ int h = FF_CEIL_RSHIFT(cover->cover_frame->height, !!p);
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ data[x] = src[x];
+ }
+ data += in->linesize[p];
+ src += cover->cover_frame->linesize[p];
+ }
+ }
+}
+static void blur(CoverContext *cover, AVFrame *in, int offx, int offy)
+{
+ int x, y, p;
+
+ for (p=0; p<3; p++) {
+ int ox = offx>>!!p;
+ int oy = offy>>!!p;
+ int stride = in->linesize[p];
+ uint8_t *data = in->data[p] + ox + oy * stride;
+ int w = FF_CEIL_RSHIFT(cover->width , !!p);
+ int h = FF_CEIL_RSHIFT(cover->height, !!p);
+ int iw = FF_CEIL_RSHIFT(in->width , !!p);
+ int ih = FF_CEIL_RSHIFT(in->height, !!p);
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int c = 0;
+ int s = 0;
+ if (ox) {
+ int scale = 65536 / (x + 1);
+ s += data[-1 + y*stride] * scale;
+ c += scale;
+ }
+ if (oy) {
+ int scale = 65536 / (y + 1);
+ s += data[x - stride] * scale;
+ c += scale;
+ }
+ if (ox + w < iw) {
+ int scale = 65536 / (w - x);
+ s += data[w + y*stride] * scale;
+ c += scale;
+ }
+ if (oy + h < ih) {
+ int scale = 65536 / (h - y);
+ s += data[x + h*stride] * scale;
+ c += scale;
+ }
+ data[x + y*stride] = c ? (s + (c>>1)) / c : 0;
+ }
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ CoverContext *cover = ctx->priv;
+ AVDictionaryEntry *ex, *ey, *ew, *eh;
+ int x = -1, y = -1, w = -1, h = -1;
+ char *xendptr = NULL, *yendptr = NULL, *wendptr = NULL, *hendptr = NULL;
+
+ ex = av_dict_get(in->metadata, "lavfi.rect.x", NULL, AV_DICT_MATCH_CASE);
+ ey = av_dict_get(in->metadata, "lavfi.rect.y", NULL, AV_DICT_MATCH_CASE);
+ ew = av_dict_get(in->metadata, "lavfi.rect.w", NULL, AV_DICT_MATCH_CASE);
+ eh = av_dict_get(in->metadata, "lavfi.rect.h", NULL, AV_DICT_MATCH_CASE);
+ if (ex && ey && ew && eh) {
+ x = strtol(ex->value, &xendptr, 10);
+ y = strtol(ey->value, &yendptr, 10);
+ w = strtol(ew->value, &wendptr, 10);
+ h = strtol(eh->value, &hendptr, 10);
+ }
+
+ if (!xendptr || *xendptr || !yendptr || *yendptr ||
+ !wendptr || *wendptr || !hendptr || !hendptr
+ ) {
+ return ff_filter_frame(ctx->outputs[0], in);
+ }
+
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+ w = FFMIN(w, in->width - x);
+ h = FFMIN(h, in->height - y);
+
+ if (w > in->width || h > in->height || w <= 0 || h <= 0)
+ return AVERROR(EINVAL);
+
+ if (cover->cover_frame) {
+ if (w != cover->cover_frame->width || h != cover->cover_frame->height)
+ return AVERROR(EINVAL);
+ }
+
+ cover->width = w;
+ cover->height = h;
+
+ x = av_clip(x, 0, in->width - w);
+ y = av_clip(y, 0, in->height - h);
+
+ av_frame_make_writable(in);
+
+ if (cover->mode == MODE_BLUR) {
+ blur (cover, in, x, y);
+ } else {
+ cover_rect(cover, in, x, y);
+ }
+ return ff_filter_frame(ctx->outputs[0], in);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ CoverContext *cover = ctx->priv;
+
+ if (cover->cover_frame)
+ av_freep(&cover->cover_frame->data[0]);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ CoverContext *cover = ctx->priv;
+ int ret;
+
+ if (cover->mode == MODE_COVER) {
+ if (!cover->cover_filename) {
+ av_log(ctx, AV_LOG_ERROR, "cover filename not set\n");
+ return AVERROR(EINVAL);
+ }
+
+ cover->cover_frame = av_frame_alloc();
+ if (!cover->cover_frame)
+ return AVERROR(ENOMEM);
+
+ if ((ret = ff_load_image(cover->cover_frame->data, cover->cover_frame->linesize,
+ &cover->cover_frame->width, &cover->cover_frame->height,
+ &cover->cover_frame->format, cover->cover_filename, ctx)) < 0)
+ return ret;
+
+ if (cover->cover_frame->format != AV_PIX_FMT_YUV420P && cover->cover_frame->format != AV_PIX_FMT_YUVJ420P) {
+ av_log(ctx, AV_LOG_ERROR, "cover image is not a YUV420 image\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ return 0;
+}
+
+static const AVFilterPad cover_rect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad cover_rect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_cover_rect = {
+ .name = "cover_rect",
+ .description = NULL_IF_CONFIG_SMALL("Find and cover a user specified object"),
+ .priv_size = sizeof(CoverContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = cover_rect_inputs,
+ .outputs = cover_rect_outputs,
+ .priv_class = &cover_rect_class,
+};
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index 4122d52f88..f58a7ae80f 100644
--- a/libavfilter/vf_crop.c
+++ b/libavfilter/vf_crop.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,13 +38,15 @@
#include "libavutil/opt.h"
static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
"in_w", "iw", ///< width of the input video
"in_h", "ih", ///< height of the input video
"out_w", "ow", ///< width of the cropped video
"out_h", "oh", ///< height of the cropped video
+ "a",
+ "sar",
+ "dar",
+ "hsub",
+ "vsub",
"x",
"y",
"n", ///< number of frame
@@ -54,16 +56,19 @@ static const char *const var_names[] = {
};
enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
VAR_IN_W, VAR_IW,
VAR_IN_H, VAR_IH,
VAR_OUT_W, VAR_OW,
VAR_OUT_H, VAR_OH,
+ VAR_A,
+ VAR_SAR,
+ VAR_DAR,
+ VAR_HSUB,
+ VAR_VSUB,
VAR_X,
VAR_Y,
VAR_N,
+ VAR_POS,
VAR_T,
VAR_VARS_NB
};
@@ -75,44 +80,29 @@ typedef struct CropContext {
int w; ///< width of the cropped area
int h; ///< height of the cropped area
+ AVRational out_sar; ///< output sample aspect ratio
+ int keep_aspect; ///< keep display aspect ratio when cropping
+
int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes
int hsub, vsub; ///< chroma subsampling
- char *x_expr, *y_expr, *ow_expr, *oh_expr;
+ char *x_expr, *y_expr, *w_expr, *h_expr;
AVExpr *x_pexpr, *y_pexpr; /* parsed expressions for x and y */
double var_values[VAR_VARS_NB];
} CropContext;
static int query_formats(AVFilterContext *ctx)
{
- static const enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGB48LE,
- AV_PIX_FMT_BGR48BE, AV_PIX_FMT_BGR48LE,
- AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
- AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
- AV_PIX_FMT_RGB565BE, AV_PIX_FMT_RGB565LE,
- AV_PIX_FMT_RGB555BE, AV_PIX_FMT_RGB555LE,
- AV_PIX_FMT_BGR565BE, AV_PIX_FMT_BGR565LE,
- AV_PIX_FMT_BGR555BE, AV_PIX_FMT_BGR555LE,
- AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE,
- AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUV420P16BE,
- AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUV422P16BE,
- AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUV444P16BE,
- 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
- AV_PIX_FMT_YUVA420P,
- AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8,
- AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
- AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8,
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+ AVFilterFormats *formats = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & (AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM)) &&
+ !((desc->log2_chroma_w || desc->log2_chroma_h) && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)))
+ ff_add_format(&formats, fmt);
+ }
- return 0;
+ return ff_set_common_formats(ctx, formats);
}
static av_cold void uninit(AVFilterContext *ctx)
@@ -149,34 +139,37 @@ static int config_input(AVFilterLink *link)
const char *expr;
double res;
- s->var_values[VAR_E] = M_E;
- s->var_values[VAR_PHI] = M_PHI;
- s->var_values[VAR_PI] = M_PI;
s->var_values[VAR_IN_W] = s->var_values[VAR_IW] = ctx->inputs[0]->w;
s->var_values[VAR_IN_H] = s->var_values[VAR_IH] = ctx->inputs[0]->h;
+ s->var_values[VAR_A] = (float) link->w / link->h;
+ s->var_values[VAR_SAR] = link->sample_aspect_ratio.num ? av_q2d(link->sample_aspect_ratio) : 1;
+ s->var_values[VAR_DAR] = s->var_values[VAR_A] * s->var_values[VAR_SAR];
+ s->var_values[VAR_HSUB] = 1<<pix_desc->log2_chroma_w;
+ s->var_values[VAR_VSUB] = 1<<pix_desc->log2_chroma_h;
s->var_values[VAR_X] = NAN;
s->var_values[VAR_Y] = NAN;
s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = NAN;
s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = NAN;
s->var_values[VAR_N] = 0;
s->var_values[VAR_T] = NAN;
+ s->var_values[VAR_POS] = NAN;
av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc);
s->hsub = pix_desc->log2_chroma_w;
s->vsub = pix_desc->log2_chroma_h;
- if ((ret = av_expr_parse_and_eval(&res, (expr = s->ow_expr),
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
var_names, s->var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
goto fail_expr;
s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = res;
- if ((ret = av_expr_parse_and_eval(&res, (expr = s->oh_expr),
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->h_expr),
var_names, s->var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
goto fail_expr;
s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = res;
/* evaluate again ow as it may depend on oh */
- if ((ret = av_expr_parse_and_eval(&res, (expr = s->ow_expr),
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
var_names, s->var_values,
NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
goto fail_expr;
@@ -187,7 +180,7 @@ static int config_input(AVFilterLink *link)
av_log(ctx, AV_LOG_ERROR,
"Too big value or invalid expression for out_w/ow or out_h/oh. "
"Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
- s->ow_expr, s->oh_expr);
+ s->w_expr, s->h_expr);
return AVERROR(EINVAL);
}
s->w &= ~((1 << s->hsub) - 1);
@@ -202,8 +195,17 @@ static int config_input(AVFilterLink *link)
NULL, NULL, NULL, NULL, 0, ctx)) < 0)
return AVERROR(EINVAL);
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d\n",
- link->w, link->h, s->w, s->h);
+ if (s->keep_aspect) {
+ 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);
+ } else
+ s->out_sar = link->sample_aspect_ratio;
+
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d -> w:%d h:%d sar:%d/%d\n",
+ link->w, link->h, link->sample_aspect_ratio.num, link->sample_aspect_ratio.den,
+ s->w, s->h, s->out_sar.num, s->out_sar.den);
if (s->w <= 0 || s->h <= 0 ||
s->w > link->w || s->h > link->h) {
@@ -231,6 +233,7 @@ static int config_output(AVFilterLink *link)
link->w = s->w;
link->h = s->h;
+ link->sample_aspect_ratio = s->out_sar;
return 0;
}
@@ -245,8 +248,11 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
frame->width = s->w;
frame->height = s->h;
+ s->var_values[VAR_N] = link->frame_count;
s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
NAN : frame->pts * av_q2d(link->time_base);
+ s->var_values[VAR_POS] = av_frame_get_pkt_pos(frame) == -1 ?
+ NAN : av_frame_get_pkt_pos(frame);
s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL);
s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, NULL);
s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL);
@@ -265,9 +271,9 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
s->x &= ~((1 << s->hsub) - 1);
s->y &= ~((1 << s->vsub) - 1);
- av_log(ctx, AV_LOG_TRACE, "n:%d t:%f x:%d y:%d x+w:%d y+h:%d\n",
- (int)s->var_values[VAR_N], s->var_values[VAR_T], s->x,
- s->y, s->x+s->w, s->y+s->h);
+ av_log(ctx, AV_LOG_TRACE, "n:%d t:%f pos:%f x:%d y:%d x+w:%d y+h:%d\n",
+ (int)s->var_values[VAR_N], s->var_values[VAR_T], s->var_values[VAR_POS],
+ s->x, s->y, s->x+s->w, s->y+s->h);
frame->data[0] += s->y * frame->linesize[0];
frame->data[0] += s->x * s->max_step[0];
@@ -287,37 +293,31 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
frame->data[3] += s->x * s->max_step[3];
}
- s->var_values[VAR_N] += 1.0;
-
return ff_filter_frame(link->dst->outputs[0], frame);
}
#define OFFSET(x) offsetof(CropContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "out_w", "Output video width", OFFSET(ow_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
- { "out_h", "Output video height", OFFSET(oh_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
- { "x", "Horizontal position in the input video of the left edge of the cropped output video",
- OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str = "(in_w - out_w) / 2" }, .flags = FLAGS },
- { "y", "Vertical position in the input video of the top edge of the cropped output video",
- OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str = "(in_h - out_h) / 2" }, .flags = FLAGS },
- { NULL },
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption crop_options[] = {
+ { "out_w", "set the width crop area expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "w", "set the width crop area expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "out_h", "set the height crop area expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "h", "set the height crop area expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "x", "set the x crop area expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "(in_w-out_w)/2"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "y", "set the y crop area expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "(in_h-out_h)/2"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "keep_aspect", "keep aspect ratio", OFFSET(keep_aspect), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { NULL }
};
-static const AVClass crop_class = {
- .class_name = "crop",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(crop);
static const AVFilterPad avfilter_vf_crop_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .filter_frame = filter_frame,
- .get_video_buffer = ff_null_get_video_buffer,
- .config_props = config_input,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
},
{ NULL }
};
@@ -332,15 +332,12 @@ static const AVFilterPad avfilter_vf_crop_outputs[] = {
};
AVFilter ff_vf_crop = {
- .name = "crop",
- .description = NULL_IF_CONFIG_SMALL("Crop the input video to width:height:x:y."),
-
- .priv_size = sizeof(CropContext),
- .priv_class = &crop_class,
-
+ .name = "crop",
+ .description = NULL_IF_CONFIG_SMALL("Crop the input video."),
+ .priv_size = sizeof(CropContext),
+ .priv_class = &crop_class,
.query_formats = query_formats,
.uninit = uninit,
-
- .inputs = avfilter_vf_crop_inputs,
- .outputs = avfilter_vf_crop_outputs,
+ .inputs = avfilter_vf_crop_inputs,
+ .outputs = avfilter_vf_crop_outputs,
};
diff --git a/libavfilter/vf_cropdetect.c b/libavfilter/vf_cropdetect.c
index 14c26c748f..7fa965160f 100644
--- a/libavfilter/vf_cropdetect.c
+++ b/libavfilter/vf_cropdetect.c
@@ -1,19 +1,19 @@
/*
* Copyright (c) 2002 A'rpi
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -23,8 +23,6 @@
* Ported from MPlayer libmpcodecs/vf_cropdetect.c.
*/
-#include <stdio.h>
-
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
@@ -37,11 +35,12 @@
typedef struct CropDetectContext {
const AVClass *class;
int x1, y1, x2, y2;
- int limit;
+ float limit;
int round;
int reset_count;
int frame_nb;
int max_pixsteps[4];
+ int max_outliers;
} CropDetectContext;
static int query_formats(AVFilterContext *ctx)
@@ -51,28 +50,66 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P,
AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
AV_PIX_FMT_YUV411P, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV420P9 , AV_PIX_FMT_YUV422P9 , AV_PIX_FMT_YUV444P9,
+ AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12,
+ AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
+ AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
AV_PIX_FMT_NV12, AV_PIX_FMT_NV21,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
AV_PIX_FMT_NONE
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static int checkline(void *ctx, const unsigned char *src, int stride, int len, int bpp)
{
int total = 0;
int div = len;
+ const uint16_t *src16 = (const uint16_t *)src;
switch (bpp) {
case 1:
+ while (len >= 8) {
+ total += src[ 0] + src[ stride] + src[2*stride] + src[3*stride]
+ + src[4*stride] + src[5*stride] + src[6*stride] + src[7*stride];
+ src += 8*stride;
+ len -= 8;
+ }
while (--len >= 0) {
total += src[0];
src += stride;
}
break;
+ case 2:
+ stride >>= 1;
+ while (len >= 8) {
+ total += src16[ 0] + src16[ stride] + src16[2*stride] + src16[3*stride]
+ + src16[4*stride] + src16[5*stride] + src16[6*stride] + src16[7*stride];
+ src16 += 8*stride;
+ len -= 8;
+ }
+ while (--len >= 0) {
+ total += src16[0];
+ src16 += stride;
+ }
+ break;
case 3:
case 4:
+ while (len >= 4) {
+ total += src[0] + src[1 ] + src[2 ]
+ + src[ stride] + src[1+ stride] + src[2+ stride]
+ + src[2*stride] + src[1+2*stride] + src[2+2*stride]
+ + src[3*stride] + src[1+3*stride] + src[2+3*stride];
+ src += 4*stride;
+ len -= 4;
+ }
while (--len >= 0) {
total += src[0] + src[1] + src[2];
src += stride;
@@ -92,7 +129,7 @@ static av_cold int init(AVFilterContext *ctx)
s->frame_nb = -2;
- av_log(ctx, AV_LOG_VERBOSE, "limit:%d round:%d reset_count:%d\n",
+ av_log(ctx, AV_LOG_VERBOSE, "limit:%f round:%d reset_count:%d\n",
s->limit, s->round, s->reset_count);
return 0;
@@ -102,9 +139,12 @@ static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
CropDetectContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ av_image_fill_max_pixsteps(s->max_pixsteps, NULL, desc);
- av_image_fill_max_pixsteps(s->max_pixsteps, NULL,
- av_pix_fmt_desc_get(inlink->format));
+ if (s->limit < 1.0)
+ s->limit *= (1 << (desc->comp[0].depth_minus1 + 1)) - 1;
s->x1 = inlink->w - 1;
s->y1 = inlink->h - 1;
@@ -114,15 +154,23 @@ static int config_input(AVFilterLink *inlink)
return 0;
}
+#define SET_META(key, value) \
+ av_dict_set_int(metadata, key, value, 0)
+
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
CropDetectContext *s = ctx->priv;
int bpp = s->max_pixsteps[0];
int w, h, x, y, shrink_by;
+ AVDictionary **metadata;
+ int outliers, last_y;
+ int limit = round(s->limit);
// ignore first 2 frames - they may be empty
if (++s->frame_nb > 0) {
+ metadata = avpriv_frame_get_metadatap(frame);
+
// Reset the crop area every reset_count frames, if reset_count is > 0
if (s->reset_count > 0 && s->frame_nb > s->reset_count) {
s->x1 = frame->width - 1;
@@ -132,33 +180,23 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
s->frame_nb = 1;
}
- for (y = 0; y < s->y1; y++) {
- if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > s->limit) {
- s->y1 = y;
- break;
- }
+#define FIND(DST, FROM, NOEND, INC, STEP0, STEP1, LEN) \
+ outliers = 0;\
+ for (last_y = y = FROM; NOEND; y = y INC) {\
+ if (checkline(ctx, frame->data[0] + STEP0 * y, STEP1, LEN, bpp) > limit) {\
+ if (++outliers > s->max_outliers) { \
+ DST = last_y;\
+ break;\
+ }\
+ } else\
+ last_y = y INC;\
}
- for (y = frame->height - 1; y > s->y2; y--) {
- if (checkline(ctx, frame->data[0] + frame->linesize[0] * y, bpp, frame->width, bpp) > s->limit) {
- s->y2 = y;
- break;
- }
- }
+ FIND(s->y1, 0, y < s->y1, +1, frame->linesize[0], bpp, frame->width);
+ FIND(s->y2, frame->height - 1, y > FFMAX(s->y2, s->y1), -1, frame->linesize[0], bpp, frame->width);
+ FIND(s->x1, 0, y < s->x1, +1, bpp, frame->linesize[0], frame->height);
+ FIND(s->x2, frame->width - 1, y > FFMAX(s->x2, s->x1), -1, bpp, frame->linesize[0], frame->height);
- for (y = 0; y < s->x1; y++) {
- if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > s->limit) {
- s->x1 = y;
- break;
- }
- }
-
- for (y = frame->width - 1; y > s->x2; y--) {
- if (checkline(ctx, frame->data[0] + bpp*y, frame->linesize[0], frame->height, bpp) > s->limit) {
- s->x2 = y;
- break;
- }
- }
// round x and y (up), important for yuv colorspaces
// make sure they stay rounded!
@@ -183,6 +221,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
h -= shrink_by;
y += (shrink_by/2 + 1) & ~1;
+ SET_META("lavfi.cropdetect.x1", s->x1);
+ SET_META("lavfi.cropdetect.x2", s->x2);
+ SET_META("lavfi.cropdetect.y1", s->y1);
+ SET_META("lavfi.cropdetect.y2", s->y2);
+ SET_META("lavfi.cropdetect.w", w);
+ SET_META("lavfi.cropdetect.h", h);
+ SET_META("lavfi.cropdetect.x", x);
+ SET_META("lavfi.cropdetect.y", y);
+
av_log(ctx, AV_LOG_INFO,
"x1:%d x2:%d y1:%d y2:%d w:%d h:%d x:%d y:%d pts:%"PRId64" t:%f crop=%d:%d:%d:%d\n",
s->x1, s->x2, s->y1, s->y2, w, h, x, y, frame->pts,
@@ -194,28 +241,25 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
#define OFFSET(x) offsetof(CropDetectContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "limit", "Threshold below which the pixel is considered black", OFFSET(limit), AV_OPT_TYPE_INT, { .i64 = 24 }, 0, INT_MAX, FLAGS },
- { "round", "Value by which the width/height should be divisible", OFFSET(round), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption cropdetect_options[] = {
+ { "limit", "Threshold below which the pixel is considered black", OFFSET(limit), AV_OPT_TYPE_FLOAT, { .dbl = 24.0/255 }, 0, 65535, FLAGS },
+ { "round", "Value by which the width/height should be divisible", OFFSET(round), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, FLAGS },
{ "reset", "Recalculate the crop area after this many frames", OFFSET(reset_count), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
- { NULL },
+ { "reset_count", "Recalculate the crop area after this many frames",OFFSET(reset_count),AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "max_outliers", "Threshold count of outliers", OFFSET(max_outliers),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { NULL }
};
-static const AVClass cropdetect_class = {
- .class_name = "cropdetect",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(cropdetect);
static const AVFilterPad avfilter_vf_cropdetect_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_input,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -229,16 +273,13 @@ static const AVFilterPad avfilter_vf_cropdetect_outputs[] = {
};
AVFilter ff_vf_cropdetect = {
- .name = "cropdetect",
- .description = NULL_IF_CONFIG_SMALL("Auto-detect crop size."),
-
- .priv_size = sizeof(CropDetectContext),
- .priv_class = &cropdetect_class,
- .init = init,
-
+ .name = "cropdetect",
+ .description = NULL_IF_CONFIG_SMALL("Auto-detect crop size."),
+ .priv_size = sizeof(CropDetectContext),
+ .priv_class = &cropdetect_class,
+ .init = init,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_cropdetect_inputs,
-
- .outputs = avfilter_vf_cropdetect_outputs,
+ .inputs = avfilter_vf_cropdetect_inputs,
+ .outputs = avfilter_vf_cropdetect_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c
new file mode 100644
index 0000000000..1c51c1baf7
--- /dev/null
+++ b/libavfilter/vf_curves.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/bprint.h"
+#include "libavutil/eval.h"
+#include "libavutil/file.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+struct keypoint {
+ double x, y;
+ struct keypoint *next;
+};
+
+#define NB_COMP 3
+
+enum preset {
+ PRESET_NONE,
+ PRESET_COLOR_NEGATIVE,
+ PRESET_CROSS_PROCESS,
+ PRESET_DARKER,
+ PRESET_INCREASE_CONTRAST,
+ PRESET_LIGHTER,
+ PRESET_LINEAR_CONTRAST,
+ PRESET_MEDIUM_CONTRAST,
+ PRESET_NEGATIVE,
+ PRESET_STRONG_CONTRAST,
+ PRESET_VINTAGE,
+ NB_PRESETS,
+};
+
+typedef struct {
+ const AVClass *class;
+ int preset;
+ char *comp_points_str[NB_COMP + 1];
+ char *comp_points_str_all;
+ uint8_t graph[NB_COMP + 1][256];
+ char *psfile;
+ uint8_t rgba_map[4];
+ int step;
+} CurvesContext;
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
+
+#define OFFSET(x) offsetof(CurvesContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption curves_options[] = {
+ { "preset", "select a color curves preset", OFFSET(preset), AV_OPT_TYPE_INT, {.i64=PRESET_NONE}, PRESET_NONE, NB_PRESETS-1, FLAGS, "preset_name" },
+ { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NONE}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "color_negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_COLOR_NEGATIVE}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "cross_process", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_CROSS_PROCESS}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "darker", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_DARKER}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "increase_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_INCREASE_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "lighter", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LIGHTER}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "linear_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_LINEAR_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "medium_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_MEDIUM_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "negative", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_NEGATIVE}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "strong_contrast", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_STRONG_CONTRAST}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "vintage", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PRESET_VINTAGE}, INT_MIN, INT_MAX, FLAGS, "preset_name" },
+ { "master","set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "m", "set master points coordinates",OFFSET(comp_points_str[NB_COMP]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "red", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "r", "set red points coordinates", OFFSET(comp_points_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "green", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "g", "set green points coordinates", OFFSET(comp_points_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "blue", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "b", "set blue points coordinates", OFFSET(comp_points_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "all", "set points coordinates for all components", OFFSET(comp_points_str_all), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "psfile", "set Photoshop curves file name", OFFSET(psfile), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(curves);
+
+static const struct {
+ const char *r;
+ const char *g;
+ const char *b;
+ const char *master;
+} curves_presets[] = {
+ [PRESET_COLOR_NEGATIVE] = {
+ "0/1 0.129/1 0.466/0.498 0.725/0 1/0",
+ "0/1 0.109/1 0.301/0.498 0.517/0 1/0",
+ "0/1 0.098/1 0.235/0.498 0.423/0 1/0",
+ },
+ [PRESET_CROSS_PROCESS] = {
+ "0.25/0.156 0.501/0.501 0.686/0.745",
+ "0.25/0.188 0.38/0.501 0.745/0.815 1/0.815",
+ "0.231/0.094 0.709/0.874",
+ },
+ [PRESET_DARKER] = { .master = "0.5/0.4" },
+ [PRESET_INCREASE_CONTRAST] = { .master = "0.149/0.066 0.831/0.905 0.905/0.98" },
+ [PRESET_LIGHTER] = { .master = "0.4/0.5" },
+ [PRESET_LINEAR_CONTRAST] = { .master = "0.305/0.286 0.694/0.713" },
+ [PRESET_MEDIUM_CONTRAST] = { .master = "0.286/0.219 0.639/0.643" },
+ [PRESET_NEGATIVE] = { .master = "0/1 1/0" },
+ [PRESET_STRONG_CONTRAST] = { .master = "0.301/0.196 0.592/0.6 0.686/0.737" },
+ [PRESET_VINTAGE] = {
+ "0/0.11 0.42/0.51 1/0.95",
+ "0.50/0.48",
+ "0/0.22 0.49/0.44 1/0.8",
+ }
+};
+
+static struct keypoint *make_point(double x, double y, struct keypoint *next)
+{
+ struct keypoint *point = av_mallocz(sizeof(*point));
+
+ if (!point)
+ return NULL;
+ point->x = x;
+ point->y = y;
+ point->next = next;
+ return point;
+}
+
+static int parse_points_str(AVFilterContext *ctx, struct keypoint **points, const char *s)
+{
+ char *p = (char *)s; // strtod won't alter the string
+ struct keypoint *last = NULL;
+
+ /* construct a linked list based on the key points string */
+ while (p && *p) {
+ struct keypoint *point = make_point(0, 0, NULL);
+ if (!point)
+ return AVERROR(ENOMEM);
+ point->x = av_strtod(p, &p); if (p && *p) p++;
+ point->y = av_strtod(p, &p); if (p && *p) p++;
+ 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);
+ return AVERROR(EINVAL);
+ }
+ if (!*points)
+ *points = point;
+ if (last) {
+ if ((int)(last->x * 255) >= (int)(point->x * 255)) {
+ 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);
+ return AVERROR(EINVAL);
+ }
+ last->next = point;
+ }
+ last = point;
+ }
+
+ /* auto insert first key point if missing at x=0 */
+ if (!*points) {
+ last = make_point(0, 0, NULL);
+ if (!last)
+ return AVERROR(ENOMEM);
+ last->x = last->y = 0;
+ *points = last;
+ } else if ((*points)->x != 0.) {
+ struct keypoint *newfirst = make_point(0, 0, *points);
+ if (!newfirst)
+ return AVERROR(ENOMEM);
+ *points = newfirst;
+ }
+
+ av_assert0(last);
+
+ /* auto insert last key point if missing at x=1 */
+ if (last->x != 1.) {
+ struct keypoint *point = make_point(1, 1, NULL);
+ if (!point)
+ return AVERROR(ENOMEM);
+ last->next = point;
+ }
+
+ return 0;
+}
+
+static int get_nb_points(const struct keypoint *d)
+{
+ int n = 0;
+ while (d) {
+ n++;
+ d = d->next;
+ }
+ return n;
+}
+
+/**
+ * Natural cubic spline interpolation
+ * Finding curves using Cubic Splines notes by Steven Rauch and John Stockie.
+ * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf
+ */
+static int interpolate(AVFilterContext *ctx, uint8_t *y, const struct keypoint *points)
+{
+ int i, ret = 0;
+ const struct keypoint *point;
+ double xprev = 0;
+
+ int n = get_nb_points(points); // number of splines
+
+ double (*matrix)[3] = av_calloc(n, sizeof(*matrix));
+ double *h = av_malloc((n - 1) * sizeof(*h));
+ double *r = av_calloc(n, sizeof(*r));
+
+ if (!matrix || !h || !r) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* h(i) = x(i+1) - x(i) */
+ i = -1;
+ for (point = points; point; point = point->next) {
+ if (i != -1)
+ h[i] = point->x - xprev;
+ xprev = point->x;
+ i++;
+ }
+
+ /* right-side of the polynomials, will be modified to contains the solution */
+ point = points;
+ for (i = 1; i < n - 1; i++) {
+ double yp = point->y,
+ yc = point->next->y,
+ yn = point->next->next->y;
+ r[i] = 6 * ((yn-yc)/h[i] - (yc-yp)/h[i-1]);
+ point = point->next;
+ }
+
+#define BD 0 /* sub diagonal (below main) */
+#define MD 1 /* main diagonal (center) */
+#define AD 2 /* sup diagonal (above main) */
+
+ /* left side of the polynomials into a tridiagonal matrix. */
+ matrix[0][MD] = matrix[n - 1][MD] = 1;
+ for (i = 1; i < n - 1; i++) {
+ matrix[i][BD] = h[i-1];
+ matrix[i][MD] = 2 * (h[i-1] + h[i]);
+ matrix[i][AD] = h[i];
+ }
+
+ /* tridiagonal solving of the linear system */
+ for (i = 1; i < n; i++) {
+ double den = matrix[i][MD] - matrix[i][BD] * matrix[i-1][AD];
+ double k = den ? 1./den : 1.;
+ matrix[i][AD] *= k;
+ r[i] = (r[i] - matrix[i][BD] * r[i - 1]) * k;
+ }
+ for (i = n - 2; i >= 0; i--)
+ r[i] = r[i] - matrix[i][AD] * r[i + 1];
+
+ /* compute the graph with x=[0..255] */
+ i = 0;
+ point = points;
+ av_assert0(point->next); // always at least 2 key points
+ while (point->next) {
+ double yc = point->y;
+ double yn = point->next->y;
+
+ double a = yc;
+ double b = (yn-yc)/h[i] - h[i]*r[i]/2. - h[i]*(r[i+1]-r[i])/6.;
+ double c = r[i] / 2.;
+ double d = (r[i+1] - r[i]) / (6.*h[i]);
+
+ int x;
+ int x_start = point->x * 255;
+ int x_end = point->next->x * 255;
+
+ av_assert0(x_start >= 0 && x_start <= 255 &&
+ x_end >= 0 && x_end <= 255);
+
+ for (x = x_start; x <= x_end; x++) {
+ double xx = (x - x_start) * 1/255.;
+ double yy = a + b*xx + c*xx*xx + d*xx*xx*xx;
+ y[x] = av_clipf(yy, 0, 1) * 255;
+ av_log(ctx, AV_LOG_DEBUG, "f(%f)=%f -> y[%d]=%d\n", xx, yy, x, y[x]);
+ }
+
+ point = point->next;
+ i++;
+ }
+
+end:
+ av_free(matrix);
+ av_free(h);
+ av_free(r);
+ return ret;
+}
+
+static int parse_psfile(AVFilterContext *ctx, const char *fname)
+{
+ CurvesContext *curves = ctx->priv;
+ uint8_t *buf;
+ size_t size;
+ int i, ret, av_unused(version), nb_curves;
+ AVBPrint ptstr;
+ static const int comp_ids[] = {3, 0, 1, 2};
+
+ av_bprint_init(&ptstr, 0, AV_BPRINT_SIZE_AUTOMATIC);
+
+ ret = av_file_map(fname, &buf, &size, 0, NULL);
+ if (ret < 0)
+ return ret;
+
+#define READ16(dst) do { \
+ if (size < 2) { \
+ ret = AVERROR_INVALIDDATA; \
+ goto end; \
+ } \
+ dst = AV_RB16(buf); \
+ buf += 2; \
+ size -= 2; \
+} while (0)
+
+ READ16(version);
+ READ16(nb_curves);
+ for (i = 0; i < FFMIN(nb_curves, FF_ARRAY_ELEMS(comp_ids)); i++) {
+ int nb_points, n;
+ av_bprint_clear(&ptstr);
+ READ16(nb_points);
+ for (n = 0; n < nb_points; n++) {
+ int y, x;
+ READ16(y);
+ READ16(x);
+ av_bprintf(&ptstr, "%f/%f ", x / 255., y / 255.);
+ }
+ if (*ptstr.str) {
+ char **pts = &curves->comp_points_str[comp_ids[i]];
+ if (!*pts) {
+ *pts = av_strdup(ptstr.str);
+ av_log(ctx, AV_LOG_DEBUG, "curves %d (intid=%d) [%d points]: [%s]\n",
+ i, comp_ids[i], nb_points, *pts);
+ if (!*pts) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ }
+ }
+ }
+end:
+ av_bprint_finalize(&ptstr, NULL);
+ av_file_unmap(buf, size);
+ return ret;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ int i, j, ret;
+ CurvesContext *curves = ctx->priv;
+ struct keypoint *comp_points[NB_COMP + 1] = {0};
+ char **pts = curves->comp_points_str;
+ const char *allp = curves->comp_points_str_all;
+
+ //if (!allp && curves->preset != PRESET_NONE && curves_presets[curves->preset].all)
+ // allp = curves_presets[curves->preset].all;
+
+ if (allp) {
+ for (i = 0; i < NB_COMP; i++) {
+ if (!pts[i])
+ pts[i] = av_strdup(allp);
+ if (!pts[i])
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (curves->psfile) {
+ ret = parse_psfile(ctx, curves->psfile);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (curves->preset != PRESET_NONE) {
+#define SET_COMP_IF_NOT_SET(n, name) do { \
+ if (!pts[n] && curves_presets[curves->preset].name) { \
+ pts[n] = av_strdup(curves_presets[curves->preset].name); \
+ if (!pts[n]) \
+ return AVERROR(ENOMEM); \
+ } \
+} while (0)
+ SET_COMP_IF_NOT_SET(0, r);
+ SET_COMP_IF_NOT_SET(1, g);
+ SET_COMP_IF_NOT_SET(2, b);
+ SET_COMP_IF_NOT_SET(3, master);
+ }
+
+ for (i = 0; i < NB_COMP + 1; i++) {
+ ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i]);
+ if (ret < 0)
+ return ret;
+ ret = interpolate(ctx, curves->graph[i], comp_points[i]);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (pts[NB_COMP]) {
+ for (i = 0; i < NB_COMP; i++)
+ for (j = 0; j < 256; j++)
+ curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]];
+ }
+
+ if (av_log_get_level() >= AV_LOG_VERBOSE) {
+ for (i = 0; i < NB_COMP; i++) {
+ struct keypoint *point = comp_points[i];
+ av_log(ctx, AV_LOG_VERBOSE, "#%d points:", i);
+ while (point) {
+ av_log(ctx, AV_LOG_VERBOSE, " (%f;%f)", point->x, point->y);
+ point = point->next;
+ }
+ av_log(ctx, AV_LOG_VERBOSE, "\n");
+ av_log(ctx, AV_LOG_VERBOSE, "#%d values:", i);
+ for (j = 0; j < 256; j++)
+ av_log(ctx, AV_LOG_VERBOSE, " %02X", curves->graph[i][j]);
+ av_log(ctx, AV_LOG_VERBOSE, "\n");
+ }
+ }
+
+ for (i = 0; i < NB_COMP + 1; i++) {
+ struct keypoint *point = comp_points[i];
+ while (point) {
+ struct keypoint *next = point->next;
+ av_free(point);
+ point = next;
+ }
+ }
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ CurvesContext *curves = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ ff_fill_rgba_map(curves->rgba_map, inlink->format);
+ curves->step = av_get_padded_bits_per_pixel(desc) >> 3;
+
+ return 0;
+}
+
+static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ int x, y;
+ const CurvesContext *curves = ctx->priv;
+ const ThreadData *td = arg;
+ const AVFrame *in = td->in;
+ const AVFrame *out = td->out;
+ const int direct = out == in;
+ const int step = curves->step;
+ const uint8_t r = curves->rgba_map[R];
+ const uint8_t g = curves->rgba_map[G];
+ const uint8_t b = curves->rgba_map[B];
+ const uint8_t a = curves->rgba_map[A];
+ const int slice_start = (in->height * jobnr ) / nb_jobs;
+ const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
+ uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
+ const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
+
+ for (y = slice_start; y < slice_end; y++) {
+ for (x = 0; x < in->width * step; x += step) {
+ dst[x + r] = curves->graph[R][src[x + r]];
+ dst[x + g] = curves->graph[G][src[x + g]];
+ dst[x + b] = curves->graph[B][src[x + b]];
+ if (!direct && step == 4)
+ dst[x + a] = src[x + a];
+ }
+ dst += out->linesize[0];
+ src += in ->linesize[0];
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ ThreadData td;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ td.in = in;
+ td.out = out;
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
+
+ if (out != in)
+ av_frame_free(&in);
+
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad curves_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad curves_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_curves = {
+ .name = "curves",
+ .description = NULL_IF_CONFIG_SMALL("Adjust components curves."),
+ .priv_size = sizeof(CurvesContext),
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = curves_inputs,
+ .outputs = curves_outputs,
+ .priv_class = &curves_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_dctdnoiz.c b/libavfilter/vf_dctdnoiz.c
new file mode 100644
index 0000000000..37306bb582
--- /dev/null
+++ b/libavfilter/vf_dctdnoiz.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (c) 2013-2014 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * A simple, relatively efficient and slow DCT image denoiser.
+ *
+ * @see http://www.ipol.im/pub/art/2011/ys-dct/
+ *
+ * The DCT factorization used is based on "Fast and numerically stable
+ * algorithms for discrete cosine transforms" from Gerlind Plonkaa & Manfred
+ * Tasche (DOI: 10.1016/j.laa.2004.07.015).
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+
+static const char *const var_names[] = { "c", NULL };
+enum { VAR_C, VAR_VARS_NB };
+
+#define MAX_THREADS 8
+
+typedef struct DCTdnoizContext {
+ const AVClass *class;
+
+ /* coefficient factor expression */
+ char *expr_str;
+ AVExpr *expr[MAX_THREADS];
+ double var_values[MAX_THREADS][VAR_VARS_NB];
+
+ int nb_threads;
+ int pr_width, pr_height; // width and height to process
+ float sigma; // used when no expression are st
+ float th; // threshold (3*sigma)
+ float *cbuf[2][3]; // two planar rgb color buffers
+ float *slices[MAX_THREADS]; // slices buffers (1 slice buffer per thread)
+ float *weights; // dct coeff are cumulated with overlapping; these values are used for averaging
+ int p_linesize; // line sizes for color and weights
+ int overlap; // number of block overlapping pixels
+ int step; // block step increment (blocksize - overlap)
+ int n; // 1<<n is the block size
+ int bsize; // block size, 1<<n
+ void (*filter_freq_func)(struct DCTdnoizContext *s,
+ const float *src, int src_linesize,
+ float *dst, int dst_linesize,
+ int thread_id);
+ void (*color_decorrelation)(float **dst, int dst_linesize,
+ const uint8_t *src, int src_linesize,
+ int w, int h);
+ void (*color_correlation)(uint8_t *dst, int dst_linesize,
+ float **src, int src_linesize,
+ int w, int h);
+} DCTdnoizContext;
+
+#define MIN_NBITS 3 /* blocksize = 1<<3 = 8 */
+#define MAX_NBITS 4 /* blocksize = 1<<4 = 16 */
+#define DEFAULT_NBITS 3
+
+#define OFFSET(x) offsetof(DCTdnoizContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption dctdnoiz_options[] = {
+ { "sigma", "set noise sigma constant", OFFSET(sigma), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 999, .flags = FLAGS },
+ { "s", "set noise sigma constant", OFFSET(sigma), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 999, .flags = FLAGS },
+ { "overlap", "set number of block overlapping pixels", OFFSET(overlap), AV_OPT_TYPE_INT, {.i64=-1}, -1, (1<<MAX_NBITS)-1, .flags = FLAGS },
+ { "expr", "set coefficient factor expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "e", "set coefficient factor expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "n", "set the block size, expressed in bits", OFFSET(n), AV_OPT_TYPE_INT, {.i64=DEFAULT_NBITS}, MIN_NBITS, MAX_NBITS, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(dctdnoiz);
+
+static void av_always_inline fdct8_1d(float *dst, const float *src,
+ int dst_stridea, int dst_strideb,
+ int src_stridea, int src_strideb)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ const float x00 = src[0*src_stridea] + src[7*src_stridea];
+ const float x01 = src[1*src_stridea] + src[6*src_stridea];
+ const float x02 = src[2*src_stridea] + src[5*src_stridea];
+ const float x03 = src[3*src_stridea] + src[4*src_stridea];
+ const float x04 = src[0*src_stridea] - src[7*src_stridea];
+ const float x05 = src[1*src_stridea] - src[6*src_stridea];
+ const float x06 = src[2*src_stridea] - src[5*src_stridea];
+ const float x07 = src[3*src_stridea] - src[4*src_stridea];
+ const float x08 = x00 + x03;
+ const float x09 = x01 + x02;
+ const float x0a = x00 - x03;
+ const float x0b = x01 - x02;
+ const float x0c = 1.38703984532215f*x04 + 0.275899379282943f*x07;
+ const float x0d = 1.17587560241936f*x05 + 0.785694958387102f*x06;
+ const float x0e = -0.785694958387102f*x05 + 1.17587560241936f*x06;
+ const float x0f = 0.275899379282943f*x04 - 1.38703984532215f*x07;
+ const float x10 = 0.353553390593274f * (x0c - x0d);
+ const float x11 = 0.353553390593274f * (x0e - x0f);
+ dst[0*dst_stridea] = 0.353553390593274f * (x08 + x09);
+ dst[1*dst_stridea] = 0.353553390593274f * (x0c + x0d);
+ dst[2*dst_stridea] = 0.461939766255643f*x0a + 0.191341716182545f*x0b;
+ dst[3*dst_stridea] = 0.707106781186547f * (x10 - x11);
+ dst[4*dst_stridea] = 0.353553390593274f * (x08 - x09);
+ dst[5*dst_stridea] = 0.707106781186547f * (x10 + x11);
+ dst[6*dst_stridea] = 0.191341716182545f*x0a - 0.461939766255643f*x0b;
+ dst[7*dst_stridea] = 0.353553390593274f * (x0e + x0f);
+ dst += dst_strideb;
+ src += src_strideb;
+ }
+}
+
+static void av_always_inline idct8_1d(float *dst, const float *src,
+ int dst_stridea, int dst_strideb,
+ int src_stridea, int src_strideb,
+ int add)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ const float x00 = 1.4142135623731f *src[0*src_stridea];
+ const float x01 = 1.38703984532215f *src[1*src_stridea] + 0.275899379282943f*src[7*src_stridea];
+ const float x02 = 1.30656296487638f *src[2*src_stridea] + 0.541196100146197f*src[6*src_stridea];
+ const float x03 = 1.17587560241936f *src[3*src_stridea] + 0.785694958387102f*src[5*src_stridea];
+ const float x04 = 1.4142135623731f *src[4*src_stridea];
+ const float x05 = -0.785694958387102f*src[3*src_stridea] + 1.17587560241936f*src[5*src_stridea];
+ const float x06 = 0.541196100146197f*src[2*src_stridea] - 1.30656296487638f*src[6*src_stridea];
+ const float x07 = -0.275899379282943f*src[1*src_stridea] + 1.38703984532215f*src[7*src_stridea];
+ const float x09 = x00 + x04;
+ const float x0a = x01 + x03;
+ const float x0b = 1.4142135623731f*x02;
+ const float x0c = x00 - x04;
+ const float x0d = x01 - x03;
+ const float x0e = 0.353553390593274f * (x09 - x0b);
+ const float x0f = 0.353553390593274f * (x0c + x0d);
+ const float x10 = 0.353553390593274f * (x0c - x0d);
+ const float x11 = 1.4142135623731f*x06;
+ const float x12 = x05 + x07;
+ const float x13 = x05 - x07;
+ const float x14 = 0.353553390593274f * (x11 + x12);
+ const float x15 = 0.353553390593274f * (x11 - x12);
+ const float x16 = 0.5f*x13;
+ dst[0*dst_stridea] = (add ? dst[ 0*dst_stridea] : 0) + 0.25f * (x09 + x0b) + 0.353553390593274f*x0a;
+ dst[1*dst_stridea] = (add ? dst[ 1*dst_stridea] : 0) + 0.707106781186547f * (x0f + x15);
+ dst[2*dst_stridea] = (add ? dst[ 2*dst_stridea] : 0) + 0.707106781186547f * (x0f - x15);
+ dst[3*dst_stridea] = (add ? dst[ 3*dst_stridea] : 0) + 0.707106781186547f * (x0e + x16);
+ dst[4*dst_stridea] = (add ? dst[ 4*dst_stridea] : 0) + 0.707106781186547f * (x0e - x16);
+ dst[5*dst_stridea] = (add ? dst[ 5*dst_stridea] : 0) + 0.707106781186547f * (x10 - x14);
+ dst[6*dst_stridea] = (add ? dst[ 6*dst_stridea] : 0) + 0.707106781186547f * (x10 + x14);
+ dst[7*dst_stridea] = (add ? dst[ 7*dst_stridea] : 0) + 0.25f * (x09 + x0b) - 0.353553390593274f*x0a;
+ dst += dst_strideb;
+ src += src_strideb;
+ }
+}
+
+
+static void av_always_inline fdct16_1d(float *dst, const float *src,
+ int dst_stridea, int dst_strideb,
+ int src_stridea, int src_strideb)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ const float x00 = src[ 0*src_stridea] + src[15*src_stridea];
+ const float x01 = src[ 1*src_stridea] + src[14*src_stridea];
+ const float x02 = src[ 2*src_stridea] + src[13*src_stridea];
+ const float x03 = src[ 3*src_stridea] + src[12*src_stridea];
+ const float x04 = src[ 4*src_stridea] + src[11*src_stridea];
+ const float x05 = src[ 5*src_stridea] + src[10*src_stridea];
+ const float x06 = src[ 6*src_stridea] + src[ 9*src_stridea];
+ const float x07 = src[ 7*src_stridea] + src[ 8*src_stridea];
+ const float x08 = src[ 0*src_stridea] - src[15*src_stridea];
+ const float x09 = src[ 1*src_stridea] - src[14*src_stridea];
+ const float x0a = src[ 2*src_stridea] - src[13*src_stridea];
+ const float x0b = src[ 3*src_stridea] - src[12*src_stridea];
+ const float x0c = src[ 4*src_stridea] - src[11*src_stridea];
+ const float x0d = src[ 5*src_stridea] - src[10*src_stridea];
+ const float x0e = src[ 6*src_stridea] - src[ 9*src_stridea];
+ const float x0f = src[ 7*src_stridea] - src[ 8*src_stridea];
+ const float x10 = x00 + x07;
+ const float x11 = x01 + x06;
+ const float x12 = x02 + x05;
+ const float x13 = x03 + x04;
+ const float x14 = x00 - x07;
+ const float x15 = x01 - x06;
+ const float x16 = x02 - x05;
+ const float x17 = x03 - x04;
+ const float x18 = x10 + x13;
+ const float x19 = x11 + x12;
+ const float x1a = x10 - x13;
+ const float x1b = x11 - x12;
+ const float x1c = 1.38703984532215f*x14 + 0.275899379282943f*x17;
+ const float x1d = 1.17587560241936f*x15 + 0.785694958387102f*x16;
+ const float x1e = -0.785694958387102f*x15 + 1.17587560241936f *x16;
+ const float x1f = 0.275899379282943f*x14 - 1.38703984532215f *x17;
+ const float x20 = 0.25f * (x1c - x1d);
+ const float x21 = 0.25f * (x1e - x1f);
+ const float x22 = 1.40740373752638f *x08 + 0.138617169199091f*x0f;
+ const float x23 = 1.35331800117435f *x09 + 0.410524527522357f*x0e;
+ const float x24 = 1.24722501298667f *x0a + 0.666655658477747f*x0d;
+ const float x25 = 1.09320186700176f *x0b + 0.897167586342636f*x0c;
+ const float x26 = -0.897167586342636f*x0b + 1.09320186700176f *x0c;
+ const float x27 = 0.666655658477747f*x0a - 1.24722501298667f *x0d;
+ const float x28 = -0.410524527522357f*x09 + 1.35331800117435f *x0e;
+ const float x29 = 0.138617169199091f*x08 - 1.40740373752638f *x0f;
+ const float x2a = x22 + x25;
+ const float x2b = x23 + x24;
+ const float x2c = x22 - x25;
+ const float x2d = x23 - x24;
+ const float x2e = 0.25f * (x2a - x2b);
+ const float x2f = 0.326640741219094f*x2c + 0.135299025036549f*x2d;
+ const float x30 = 0.135299025036549f*x2c - 0.326640741219094f*x2d;
+ const float x31 = x26 + x29;
+ const float x32 = x27 + x28;
+ const float x33 = x26 - x29;
+ const float x34 = x27 - x28;
+ const float x35 = 0.25f * (x31 - x32);
+ const float x36 = 0.326640741219094f*x33 + 0.135299025036549f*x34;
+ const float x37 = 0.135299025036549f*x33 - 0.326640741219094f*x34;
+ dst[ 0*dst_stridea] = 0.25f * (x18 + x19);
+ dst[ 1*dst_stridea] = 0.25f * (x2a + x2b);
+ dst[ 2*dst_stridea] = 0.25f * (x1c + x1d);
+ dst[ 3*dst_stridea] = 0.707106781186547f * (x2f - x37);
+ dst[ 4*dst_stridea] = 0.326640741219094f*x1a + 0.135299025036549f*x1b;
+ dst[ 5*dst_stridea] = 0.707106781186547f * (x2f + x37);
+ dst[ 6*dst_stridea] = 0.707106781186547f * (x20 - x21);
+ dst[ 7*dst_stridea] = 0.707106781186547f * (x2e + x35);
+ dst[ 8*dst_stridea] = 0.25f * (x18 - x19);
+ dst[ 9*dst_stridea] = 0.707106781186547f * (x2e - x35);
+ dst[10*dst_stridea] = 0.707106781186547f * (x20 + x21);
+ dst[11*dst_stridea] = 0.707106781186547f * (x30 - x36);
+ dst[12*dst_stridea] = 0.135299025036549f*x1a - 0.326640741219094f*x1b;
+ dst[13*dst_stridea] = 0.707106781186547f * (x30 + x36);
+ dst[14*dst_stridea] = 0.25f * (x1e + x1f);
+ dst[15*dst_stridea] = 0.25f * (x31 + x32);
+ dst += dst_strideb;
+ src += src_strideb;
+ }
+}
+
+static void av_always_inline idct16_1d(float *dst, const float *src,
+ int dst_stridea, int dst_strideb,
+ int src_stridea, int src_strideb,
+ int add)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ const float x00 = 1.4142135623731f *src[ 0*src_stridea];
+ const float x01 = 1.40740373752638f *src[ 1*src_stridea] + 0.138617169199091f*src[15*src_stridea];
+ const float x02 = 1.38703984532215f *src[ 2*src_stridea] + 0.275899379282943f*src[14*src_stridea];
+ const float x03 = 1.35331800117435f *src[ 3*src_stridea] + 0.410524527522357f*src[13*src_stridea];
+ const float x04 = 1.30656296487638f *src[ 4*src_stridea] + 0.541196100146197f*src[12*src_stridea];
+ const float x05 = 1.24722501298667f *src[ 5*src_stridea] + 0.666655658477747f*src[11*src_stridea];
+ const float x06 = 1.17587560241936f *src[ 6*src_stridea] + 0.785694958387102f*src[10*src_stridea];
+ const float x07 = 1.09320186700176f *src[ 7*src_stridea] + 0.897167586342636f*src[ 9*src_stridea];
+ const float x08 = 1.4142135623731f *src[ 8*src_stridea];
+ const float x09 = -0.897167586342636f*src[ 7*src_stridea] + 1.09320186700176f*src[ 9*src_stridea];
+ const float x0a = 0.785694958387102f*src[ 6*src_stridea] - 1.17587560241936f*src[10*src_stridea];
+ const float x0b = -0.666655658477747f*src[ 5*src_stridea] + 1.24722501298667f*src[11*src_stridea];
+ const float x0c = 0.541196100146197f*src[ 4*src_stridea] - 1.30656296487638f*src[12*src_stridea];
+ const float x0d = -0.410524527522357f*src[ 3*src_stridea] + 1.35331800117435f*src[13*src_stridea];
+ const float x0e = 0.275899379282943f*src[ 2*src_stridea] - 1.38703984532215f*src[14*src_stridea];
+ const float x0f = -0.138617169199091f*src[ 1*src_stridea] + 1.40740373752638f*src[15*src_stridea];
+ const float x12 = x00 + x08;
+ const float x13 = x01 + x07;
+ const float x14 = x02 + x06;
+ const float x15 = x03 + x05;
+ const float x16 = 1.4142135623731f*x04;
+ const float x17 = x00 - x08;
+ const float x18 = x01 - x07;
+ const float x19 = x02 - x06;
+ const float x1a = x03 - x05;
+ const float x1d = x12 + x16;
+ const float x1e = x13 + x15;
+ const float x1f = 1.4142135623731f*x14;
+ const float x20 = x12 - x16;
+ const float x21 = x13 - x15;
+ const float x22 = 0.25f * (x1d - x1f);
+ const float x23 = 0.25f * (x20 + x21);
+ const float x24 = 0.25f * (x20 - x21);
+ const float x25 = 1.4142135623731f*x17;
+ const float x26 = 1.30656296487638f*x18 + 0.541196100146197f*x1a;
+ const float x27 = 1.4142135623731f*x19;
+ const float x28 = -0.541196100146197f*x18 + 1.30656296487638f*x1a;
+ const float x29 = 0.176776695296637f * (x25 + x27) + 0.25f*x26;
+ const float x2a = 0.25f * (x25 - x27);
+ const float x2b = 0.176776695296637f * (x25 + x27) - 0.25f*x26;
+ const float x2c = 0.353553390593274f*x28;
+ const float x1b = 0.707106781186547f * (x2a - x2c);
+ const float x1c = 0.707106781186547f * (x2a + x2c);
+ const float x2d = 1.4142135623731f*x0c;
+ const float x2e = x0b + x0d;
+ const float x2f = x0a + x0e;
+ const float x30 = x09 + x0f;
+ const float x31 = x09 - x0f;
+ const float x32 = x0a - x0e;
+ const float x33 = x0b - x0d;
+ const float x37 = 1.4142135623731f*x2d;
+ const float x38 = 1.30656296487638f*x2e + 0.541196100146197f*x30;
+ const float x39 = 1.4142135623731f*x2f;
+ const float x3a = -0.541196100146197f*x2e + 1.30656296487638f*x30;
+ const float x3b = 0.176776695296637f * (x37 + x39) + 0.25f*x38;
+ const float x3c = 0.25f * (x37 - x39);
+ const float x3d = 0.176776695296637f * (x37 + x39) - 0.25f*x38;
+ const float x3e = 0.353553390593274f*x3a;
+ const float x34 = 0.707106781186547f * (x3c - x3e);
+ const float x35 = 0.707106781186547f * (x3c + x3e);
+ const float x3f = 1.4142135623731f*x32;
+ const float x40 = x31 + x33;
+ const float x41 = x31 - x33;
+ const float x42 = 0.25f * (x3f + x40);
+ const float x43 = 0.25f * (x3f - x40);
+ const float x44 = 0.353553390593274f*x41;
+ dst[ 0*dst_stridea] = (add ? dst[ 0*dst_stridea] : 0) + 0.176776695296637f * (x1d + x1f) + 0.25f*x1e;
+ dst[ 1*dst_stridea] = (add ? dst[ 1*dst_stridea] : 0) + 0.707106781186547f * (x29 + x3d);
+ dst[ 2*dst_stridea] = (add ? dst[ 2*dst_stridea] : 0) + 0.707106781186547f * (x29 - x3d);
+ dst[ 3*dst_stridea] = (add ? dst[ 3*dst_stridea] : 0) + 0.707106781186547f * (x23 - x43);
+ dst[ 4*dst_stridea] = (add ? dst[ 4*dst_stridea] : 0) + 0.707106781186547f * (x23 + x43);
+ dst[ 5*dst_stridea] = (add ? dst[ 5*dst_stridea] : 0) + 0.707106781186547f * (x1b - x35);
+ dst[ 6*dst_stridea] = (add ? dst[ 6*dst_stridea] : 0) + 0.707106781186547f * (x1b + x35);
+ dst[ 7*dst_stridea] = (add ? dst[ 7*dst_stridea] : 0) + 0.707106781186547f * (x22 + x44);
+ dst[ 8*dst_stridea] = (add ? dst[ 8*dst_stridea] : 0) + 0.707106781186547f * (x22 - x44);
+ dst[ 9*dst_stridea] = (add ? dst[ 9*dst_stridea] : 0) + 0.707106781186547f * (x1c + x34);
+ dst[10*dst_stridea] = (add ? dst[10*dst_stridea] : 0) + 0.707106781186547f * (x1c - x34);
+ dst[11*dst_stridea] = (add ? dst[11*dst_stridea] : 0) + 0.707106781186547f * (x24 + x42);
+ dst[12*dst_stridea] = (add ? dst[12*dst_stridea] : 0) + 0.707106781186547f * (x24 - x42);
+ dst[13*dst_stridea] = (add ? dst[13*dst_stridea] : 0) + 0.707106781186547f * (x2b - x3b);
+ dst[14*dst_stridea] = (add ? dst[14*dst_stridea] : 0) + 0.707106781186547f * (x2b + x3b);
+ dst[15*dst_stridea] = (add ? dst[15*dst_stridea] : 0) + 0.176776695296637f * (x1d + x1f) - 0.25f*x1e;
+ dst += dst_strideb;
+ src += src_strideb;
+ }
+}
+
+#define DEF_FILTER_FREQ_FUNCS(bsize) \
+static av_always_inline void filter_freq_##bsize(const float *src, int src_linesize, \
+ float *dst, int dst_linesize, \
+ AVExpr *expr, double *var_values, \
+ int sigma_th) \
+{ \
+ unsigned i; \
+ DECLARE_ALIGNED(32, float, tmp_block1)[bsize * bsize]; \
+ DECLARE_ALIGNED(32, float, tmp_block2)[bsize * bsize]; \
+ \
+ /* forward DCT */ \
+ fdct##bsize##_1d(tmp_block1, src, 1, bsize, 1, src_linesize); \
+ fdct##bsize##_1d(tmp_block2, tmp_block1, bsize, 1, bsize, 1); \
+ \
+ for (i = 0; i < bsize*bsize; i++) { \
+ float *b = &tmp_block2[i]; \
+ /* frequency filtering */ \
+ if (expr) { \
+ var_values[VAR_C] = FFABS(*b); \
+ *b *= av_expr_eval(expr, var_values, NULL); \
+ } else { \
+ if (FFABS(*b) < sigma_th) \
+ *b = 0; \
+ } \
+ } \
+ \
+ /* inverse DCT */ \
+ idct##bsize##_1d(tmp_block1, tmp_block2, 1, bsize, 1, bsize, 0); \
+ idct##bsize##_1d(dst, tmp_block1, dst_linesize, 1, bsize, 1, 1); \
+} \
+ \
+static void filter_freq_sigma_##bsize(DCTdnoizContext *s, \
+ const float *src, int src_linesize, \
+ float *dst, int dst_linesize, int thread_id) \
+{ \
+ filter_freq_##bsize(src, src_linesize, dst, dst_linesize, NULL, NULL, s->th); \
+} \
+ \
+static void filter_freq_expr_##bsize(DCTdnoizContext *s, \
+ const float *src, int src_linesize, \
+ float *dst, int dst_linesize, int thread_id) \
+{ \
+ filter_freq_##bsize(src, src_linesize, dst, dst_linesize, \
+ s->expr[thread_id], s->var_values[thread_id], 0); \
+}
+
+DEF_FILTER_FREQ_FUNCS(8)
+DEF_FILTER_FREQ_FUNCS(16)
+
+#define DCT3X3_0_0 0.5773502691896258f /* 1/sqrt(3) */
+#define DCT3X3_0_1 0.5773502691896258f /* 1/sqrt(3) */
+#define DCT3X3_0_2 0.5773502691896258f /* 1/sqrt(3) */
+#define DCT3X3_1_0 0.7071067811865475f /* 1/sqrt(2) */
+#define DCT3X3_1_2 -0.7071067811865475f /* -1/sqrt(2) */
+#define DCT3X3_2_0 0.4082482904638631f /* 1/sqrt(6) */
+#define DCT3X3_2_1 -0.8164965809277261f /* -2/sqrt(6) */
+#define DCT3X3_2_2 0.4082482904638631f /* 1/sqrt(6) */
+
+static av_always_inline void color_decorrelation(float **dst, int dst_linesize,
+ const uint8_t *src, int src_linesize,
+ int w, int h,
+ int r, int g, int b)
+{
+ int x, y;
+ float *dstp_r = dst[0];
+ float *dstp_g = dst[1];
+ float *dstp_b = dst[2];
+
+ for (y = 0; y < h; y++) {
+ const uint8_t *srcp = src;
+
+ for (x = 0; x < w; x++) {
+ dstp_r[x] = srcp[r] * DCT3X3_0_0 + srcp[g] * DCT3X3_0_1 + srcp[b] * DCT3X3_0_2;
+ dstp_g[x] = srcp[r] * DCT3X3_1_0 + srcp[b] * DCT3X3_1_2;
+ dstp_b[x] = srcp[r] * DCT3X3_2_0 + srcp[g] * DCT3X3_2_1 + srcp[b] * DCT3X3_2_2;
+ srcp += 3;
+ }
+ src += src_linesize;
+ dstp_r += dst_linesize;
+ dstp_g += dst_linesize;
+ dstp_b += dst_linesize;
+ }
+}
+
+static av_always_inline void color_correlation(uint8_t *dst, int dst_linesize,
+ float **src, int src_linesize,
+ int w, int h,
+ int r, int g, int b)
+{
+ int x, y;
+ const float *src_r = src[0];
+ const float *src_g = src[1];
+ const float *src_b = src[2];
+
+ for (y = 0; y < h; y++) {
+ uint8_t *dstp = dst;
+
+ for (x = 0; x < w; x++) {
+ dstp[r] = av_clip_uint8(src_r[x] * DCT3X3_0_0 + src_g[x] * DCT3X3_1_0 + src_b[x] * DCT3X3_2_0);
+ dstp[g] = av_clip_uint8(src_r[x] * DCT3X3_0_1 + src_b[x] * DCT3X3_2_1);
+ dstp[b] = av_clip_uint8(src_r[x] * DCT3X3_0_2 + src_g[x] * DCT3X3_1_2 + src_b[x] * DCT3X3_2_2);
+ dstp += 3;
+ }
+ dst += dst_linesize;
+ src_r += src_linesize;
+ src_g += src_linesize;
+ src_b += src_linesize;
+ }
+}
+
+#define DECLARE_COLOR_FUNCS(name, r, g, b) \
+static void color_decorrelation_##name(float **dst, int dst_linesize, \
+ const uint8_t *src, int src_linesize, \
+ int w, int h) \
+{ \
+ color_decorrelation(dst, dst_linesize, src, src_linesize, w, h, r, g, b); \
+} \
+ \
+static void color_correlation_##name(uint8_t *dst, int dst_linesize, \
+ float **src, int src_linesize, \
+ int w, int h) \
+{ \
+ color_correlation(dst, dst_linesize, src, src_linesize, w, h, r, g, b); \
+}
+
+DECLARE_COLOR_FUNCS(rgb, 0, 1, 2)
+DECLARE_COLOR_FUNCS(bgr, 2, 1, 0)
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ DCTdnoizContext *s = ctx->priv;
+ int i, x, y, bx, by, linesize, *iweights, max_slice_h, slice_h;
+ const int bsize = 1 << s->n;
+
+ switch (inlink->format) {
+ case AV_PIX_FMT_BGR24:
+ s->color_decorrelation = color_decorrelation_bgr;
+ s->color_correlation = color_correlation_bgr;
+ break;
+ case AV_PIX_FMT_RGB24:
+ s->color_decorrelation = color_decorrelation_rgb;
+ s->color_correlation = color_correlation_rgb;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ s->pr_width = inlink->w - (inlink->w - bsize) % s->step;
+ s->pr_height = inlink->h - (inlink->h - bsize) % s->step;
+ if (s->pr_width != inlink->w)
+ av_log(ctx, AV_LOG_WARNING, "The last %d horizontal pixels won't be denoised\n",
+ inlink->w - s->pr_width);
+ if (s->pr_height != inlink->h)
+ av_log(ctx, AV_LOG_WARNING, "The last %d vertical pixels won't be denoised\n",
+ inlink->h - s->pr_height);
+
+ max_slice_h = s->pr_height / ((s->bsize - 1) * 2);
+ s->nb_threads = FFMIN3(MAX_THREADS, ctx->graph->nb_threads, max_slice_h);
+ av_log(ctx, AV_LOG_DEBUG, "threads: [max=%d hmax=%d user=%d] => %d\n",
+ MAX_THREADS, max_slice_h, ctx->graph->nb_threads, s->nb_threads);
+
+ s->p_linesize = linesize = FFALIGN(s->pr_width, 32);
+ for (i = 0; i < 2; i++) {
+ s->cbuf[i][0] = av_malloc_array(linesize * s->pr_height, sizeof(*s->cbuf[i][0]));
+ s->cbuf[i][1] = av_malloc_array(linesize * s->pr_height, sizeof(*s->cbuf[i][1]));
+ s->cbuf[i][2] = av_malloc_array(linesize * s->pr_height, sizeof(*s->cbuf[i][2]));
+ if (!s->cbuf[i][0] || !s->cbuf[i][1] || !s->cbuf[i][2])
+ return AVERROR(ENOMEM);
+ }
+
+ /* eval expressions are probably not thread safe when the eval internal
+ * state can be changed (typically through load & store operations) */
+ if (s->expr_str) {
+ for (i = 0; i < s->nb_threads; i++) {
+ int ret = av_expr_parse(&s->expr[i], s->expr_str, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ /* each slice will need to (pre & re)process the top and bottom block of
+ * the previous one in in addition to its processing area. This is because
+ * each pixel is averaged by all the surrounding blocks */
+ slice_h = (int)ceilf(s->pr_height / (float)s->nb_threads) + (s->bsize - 1) * 2;
+ for (i = 0; i < s->nb_threads; i++) {
+ s->slices[i] = av_malloc_array(linesize, slice_h * sizeof(*s->slices[i]));
+ if (!s->slices[i])
+ return AVERROR(ENOMEM);
+ }
+
+ s->weights = av_malloc(s->pr_height * linesize * sizeof(*s->weights));
+ if (!s->weights)
+ return AVERROR(ENOMEM);
+ iweights = av_calloc(s->pr_height, linesize * sizeof(*iweights));
+ if (!iweights)
+ return AVERROR(ENOMEM);
+ for (y = 0; y < s->pr_height - bsize + 1; y += s->step)
+ for (x = 0; x < s->pr_width - bsize + 1; x += s->step)
+ for (by = 0; by < bsize; by++)
+ for (bx = 0; bx < bsize; bx++)
+ iweights[(y + by)*linesize + x + bx]++;
+ for (y = 0; y < s->pr_height; y++)
+ for (x = 0; x < s->pr_width; x++)
+ s->weights[y*linesize + x] = 1. / iweights[y*linesize + x];
+ av_free(iweights);
+
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ DCTdnoizContext *s = ctx->priv;
+
+ s->bsize = 1 << s->n;
+ if (s->overlap == -1)
+ s->overlap = s->bsize - 1;
+
+ if (s->overlap > s->bsize - 1) {
+ av_log(s, AV_LOG_ERROR, "Overlap value can not except %d "
+ "with a block size of %dx%d\n",
+ s->bsize - 1, s->bsize, s->bsize);
+ return AVERROR(EINVAL);
+ }
+
+ if (s->expr_str) {
+ switch (s->n) {
+ case 3: s->filter_freq_func = filter_freq_expr_8; break;
+ case 4: s->filter_freq_func = filter_freq_expr_16; break;
+ default: av_assert0(0);
+ }
+ } else {
+ switch (s->n) {
+ case 3: s->filter_freq_func = filter_freq_sigma_8; break;
+ case 4: s->filter_freq_func = filter_freq_sigma_16; break;
+ default: av_assert0(0);
+ }
+ }
+
+ s->th = s->sigma * 3.;
+ s->step = s->bsize - s->overlap;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_BGR24, AV_PIX_FMT_RGB24,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+typedef struct ThreadData {
+ float *src, *dst;
+} ThreadData;
+
+static int filter_slice(AVFilterContext *ctx,
+ void *arg, int jobnr, int nb_jobs)
+{
+ int x, y;
+ DCTdnoizContext *s = ctx->priv;
+ const ThreadData *td = arg;
+ const int w = s->pr_width;
+ const int h = s->pr_height;
+ const int slice_start = (h * jobnr ) / nb_jobs;
+ const int slice_end = (h * (jobnr+1)) / nb_jobs;
+ const int slice_start_ctx = FFMAX(slice_start - s->bsize + 1, 0);
+ const int slice_end_ctx = FFMIN(slice_end, h - s->bsize + 1);
+ const int slice_h = slice_end_ctx - slice_start_ctx;
+ const int src_linesize = s->p_linesize;
+ const int dst_linesize = s->p_linesize;
+ const int slice_linesize = s->p_linesize;
+ float *dst;
+ const float *src = td->src + slice_start_ctx * src_linesize;
+ const float *weights = s->weights + slice_start * dst_linesize;
+ float *slice = s->slices[jobnr];
+
+ // reset block sums
+ memset(slice, 0, (slice_h + s->bsize - 1) * dst_linesize * sizeof(*slice));
+
+ // block dct sums
+ for (y = 0; y < slice_h; y += s->step) {
+ for (x = 0; x < w - s->bsize + 1; x += s->step)
+ s->filter_freq_func(s, src + x, src_linesize,
+ slice + x, slice_linesize,
+ jobnr);
+ src += s->step * src_linesize;
+ slice += s->step * slice_linesize;
+ }
+
+ // average blocks
+ slice = s->slices[jobnr] + (slice_start - slice_start_ctx) * slice_linesize;
+ dst = td->dst + slice_start * dst_linesize;
+ for (y = slice_start; y < slice_end; y++) {
+ for (x = 0; x < w; x++)
+ dst[x] = slice[x] * weights[x];
+ slice += slice_linesize;
+ dst += dst_linesize;
+ weights += dst_linesize;
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ DCTdnoizContext *s = ctx->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int direct, plane;
+ AVFrame *out;
+
+ if (av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ direct = 0;
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ s->color_decorrelation(s->cbuf[0], s->p_linesize,
+ in->data[0], in->linesize[0],
+ s->pr_width, s->pr_height);
+ for (plane = 0; plane < 3; plane++) {
+ ThreadData td = {
+ .src = s->cbuf[0][plane],
+ .dst = s->cbuf[1][plane],
+ };
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, s->nb_threads);
+ }
+ s->color_correlation(out->data[0], out->linesize[0],
+ s->cbuf[1], s->p_linesize,
+ s->pr_width, s->pr_height);
+
+ if (!direct) {
+ int y;
+ uint8_t *dst = out->data[0];
+ const uint8_t *src = in->data[0];
+ const int dst_linesize = out->linesize[0];
+ const int src_linesize = in->linesize[0];
+ const int hpad = (inlink->w - s->pr_width) * 3;
+ const int vpad = (inlink->h - s->pr_height);
+
+ if (hpad) {
+ uint8_t *dstp = dst + s->pr_width * 3;
+ const uint8_t *srcp = src + s->pr_width * 3;
+
+ for (y = 0; y < s->pr_height; y++) {
+ memcpy(dstp, srcp, hpad);
+ dstp += dst_linesize;
+ srcp += src_linesize;
+ }
+ }
+ if (vpad) {
+ uint8_t *dstp = dst + s->pr_height * dst_linesize;
+ const uint8_t *srcp = src + s->pr_height * src_linesize;
+
+ for (y = 0; y < vpad; y++) {
+ memcpy(dstp, srcp, inlink->w * 3);
+ dstp += dst_linesize;
+ srcp += src_linesize;
+ }
+ }
+
+ av_frame_free(&in);
+ }
+
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i;
+ DCTdnoizContext *s = ctx->priv;
+
+ av_freep(&s->weights);
+ for (i = 0; i < 2; i++) {
+ av_freep(&s->cbuf[i][0]);
+ av_freep(&s->cbuf[i][1]);
+ av_freep(&s->cbuf[i][2]);
+ }
+ for (i = 0; i < s->nb_threads; i++) {
+ av_freep(&s->slices[i]);
+ av_expr_free(s->expr[i]);
+ }
+}
+
+static const AVFilterPad dctdnoiz_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad dctdnoiz_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_dctdnoiz = {
+ .name = "dctdnoiz",
+ .description = NULL_IF_CONFIG_SMALL("Denoise frames using 2D DCT."),
+ .priv_size = sizeof(DCTdnoizContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = dctdnoiz_inputs,
+ .outputs = dctdnoiz_outputs,
+ .priv_class = &dctdnoiz_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_decimate.c b/libavfilter/vf_decimate.c
new file mode 100644
index 0000000000..70357ea8e2
--- /dev/null
+++ b/libavfilter/vf_decimate.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2012 Fredrik Mellbin
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#define INPUT_MAIN 0
+#define INPUT_CLEANSRC 1
+
+struct qitem {
+ AVFrame *frame;
+ int64_t maxbdiff;
+ int64_t totdiff;
+};
+
+typedef struct {
+ const AVClass *class;
+ struct qitem *queue; ///< window of cycle frames and the associated data diff
+ int fid; ///< current frame id in the queue
+ int filled; ///< 1 if the queue is filled, 0 otherwise
+ AVFrame *last; ///< last frame from the previous queue
+ AVFrame **clean_src; ///< frame queue for the clean source
+ int got_frame[2]; ///< frame request flag for each input stream
+ double ts_unit; ///< timestamp units for the output frames
+ int64_t start_pts; ///< base for output timestamps
+ uint32_t eof; ///< bitmask for end of stream
+ int hsub, vsub; ///< chroma subsampling values
+ int depth;
+ int nxblocks, nyblocks;
+ int bdiffsize;
+ int64_t *bdiffs;
+
+ /* options */
+ int cycle;
+ double dupthresh_flt;
+ double scthresh_flt;
+ int64_t dupthresh;
+ int64_t scthresh;
+ int blockx, blocky;
+ int ppsrc;
+ int chroma;
+} DecimateContext;
+
+#define OFFSET(x) offsetof(DecimateContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption decimate_options[] = {
+ { "cycle", "set the number of frame from which one will be dropped", OFFSET(cycle), AV_OPT_TYPE_INT, {.i64 = 5}, 2, 25, FLAGS },
+ { "dupthresh", "set duplicate threshold", OFFSET(dupthresh_flt), AV_OPT_TYPE_DOUBLE, {.dbl = 1.1}, 0, 100, FLAGS },
+ { "scthresh", "set scene change threshold", OFFSET(scthresh_flt), AV_OPT_TYPE_DOUBLE, {.dbl = 15.0}, 0, 100, FLAGS },
+ { "blockx", "set the size of the x-axis blocks used during metric calculations", OFFSET(blockx), AV_OPT_TYPE_INT, {.i64 = 32}, 4, 1<<9, FLAGS },
+ { "blocky", "set the size of the y-axis blocks used during metric calculations", OFFSET(blocky), AV_OPT_TYPE_INT, {.i64 = 32}, 4, 1<<9, FLAGS },
+ { "ppsrc", "mark main input as a pre-processed input and activate clean source input stream", OFFSET(ppsrc), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "chroma", "set whether or not chroma is considered in the metric calculations", OFFSET(chroma), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(decimate);
+
+static void calc_diffs(const DecimateContext *dm, struct qitem *q,
+ const AVFrame *f1, const AVFrame *f2)
+{
+ int64_t maxdiff = -1;
+ int64_t *bdiffs = dm->bdiffs;
+ int plane, i, j;
+
+ memset(bdiffs, 0, dm->bdiffsize * sizeof(*bdiffs));
+
+ for (plane = 0; plane < (dm->chroma && f1->data[2] ? 3 : 1); plane++) {
+ int x, y, xl;
+ const int linesize1 = f1->linesize[plane];
+ const int linesize2 = f2->linesize[plane];
+ const uint8_t *f1p = f1->data[plane];
+ const uint8_t *f2p = f2->data[plane];
+ int width = plane ? FF_CEIL_RSHIFT(f1->width, dm->hsub) : f1->width;
+ int height = plane ? FF_CEIL_RSHIFT(f1->height, dm->vsub) : f1->height;
+ int hblockx = dm->blockx / 2;
+ int hblocky = dm->blocky / 2;
+
+ if (plane) {
+ hblockx >>= dm->hsub;
+ hblocky >>= dm->vsub;
+ }
+
+ for (y = 0; y < height; y++) {
+ int ydest = y / hblocky;
+ int xdest = 0;
+
+#define CALC_DIFF(nbits) do { \
+ for (x = 0; x < width; x += hblockx) { \
+ int64_t acc = 0; \
+ int m = FFMIN(width, x + hblockx); \
+ for (xl = x; xl < m; xl++) \
+ acc += abs(((const uint##nbits##_t *)f1p)[xl] - \
+ ((const uint##nbits##_t *)f2p)[xl]); \
+ bdiffs[ydest * dm->nxblocks + xdest] += acc; \
+ xdest++; \
+ } \
+} while (0)
+ if (dm->depth == 8) CALC_DIFF(8);
+ else CALC_DIFF(16);
+
+ f1p += linesize1;
+ f2p += linesize2;
+ }
+ }
+
+ for (i = 0; i < dm->nyblocks - 1; i++) {
+ for (j = 0; j < dm->nxblocks - 1; j++) {
+ int64_t tmp = bdiffs[ i * dm->nxblocks + j ]
+ + bdiffs[ i * dm->nxblocks + j + 1]
+ + bdiffs[(i + 1) * dm->nxblocks + j ]
+ + bdiffs[(i + 1) * dm->nxblocks + j + 1];
+ if (tmp > maxdiff)
+ maxdiff = tmp;
+ }
+ }
+
+ q->totdiff = 0;
+ for (i = 0; i < dm->bdiffsize; i++)
+ q->totdiff += bdiffs[i];
+ q->maxbdiff = maxdiff;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ int scpos = -1, duppos = -1;
+ int drop = INT_MIN, i, lowest = 0, ret;
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ DecimateContext *dm = ctx->priv;
+ AVFrame *prv;
+
+ /* update frames queue(s) */
+ if (FF_INLINK_IDX(inlink) == INPUT_MAIN) {
+ dm->queue[dm->fid].frame = in;
+ dm->got_frame[INPUT_MAIN] = 1;
+ } else {
+ dm->clean_src[dm->fid] = in;
+ dm->got_frame[INPUT_CLEANSRC] = 1;
+ }
+ if (!dm->got_frame[INPUT_MAIN] || (dm->ppsrc && !dm->got_frame[INPUT_CLEANSRC]))
+ return 0;
+ dm->got_frame[INPUT_MAIN] = dm->got_frame[INPUT_CLEANSRC] = 0;
+
+ if (in) {
+ /* update frame metrics */
+ prv = dm->fid ? dm->queue[dm->fid - 1].frame : dm->last;
+ if (!prv)
+ prv = in;
+ calc_diffs(dm, &dm->queue[dm->fid], prv, in);
+ if (++dm->fid != dm->cycle)
+ return 0;
+ av_frame_free(&dm->last);
+ dm->last = av_frame_clone(in);
+ dm->fid = 0;
+
+ /* we have a complete cycle, select the frame to drop */
+ lowest = 0;
+ for (i = 0; i < dm->cycle; i++) {
+ if (dm->queue[i].totdiff > dm->scthresh)
+ scpos = i;
+ if (dm->queue[i].maxbdiff < dm->queue[lowest].maxbdiff)
+ lowest = i;
+ }
+ if (dm->queue[lowest].maxbdiff < dm->dupthresh)
+ duppos = lowest;
+ drop = scpos >= 0 && duppos < 0 ? scpos : lowest;
+ }
+
+ /* metrics debug */
+ if (av_log_get_level() >= AV_LOG_DEBUG) {
+ av_log(ctx, AV_LOG_DEBUG, "1/%d frame drop:\n", dm->cycle);
+ for (i = 0; i < dm->cycle && dm->queue[i].frame; i++) {
+ av_log(ctx, AV_LOG_DEBUG," #%d: totdiff=%08"PRIx64" maxbdiff=%08"PRIx64"%s%s%s%s\n",
+ i + 1, dm->queue[i].totdiff, dm->queue[i].maxbdiff,
+ i == scpos ? " sc" : "",
+ i == duppos ? " dup" : "",
+ i == lowest ? " lowest" : "",
+ i == drop ? " [DROP]" : "");
+ }
+ }
+
+ /* push all frames except the drop */
+ ret = 0;
+ for (i = 0; i < dm->cycle && dm->queue[i].frame; i++) {
+ if (i == drop) {
+ if (dm->ppsrc)
+ av_frame_free(&dm->clean_src[i]);
+ av_frame_free(&dm->queue[i].frame);
+ } else {
+ AVFrame *frame = dm->queue[i].frame;
+ if (frame->pts != AV_NOPTS_VALUE && dm->start_pts == AV_NOPTS_VALUE)
+ dm->start_pts = frame->pts;
+ if (dm->ppsrc) {
+ av_frame_free(&frame);
+ frame = dm->clean_src[i];
+ }
+ frame->pts = outlink->frame_count * dm->ts_unit +
+ (dm->start_pts == AV_NOPTS_VALUE ? 0 : dm->start_pts);
+ ret = ff_filter_frame(outlink, frame);
+ if (ret < 0)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ int max_value;
+ AVFilterContext *ctx = inlink->dst;
+ DecimateContext *dm = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+ const int w = inlink->w;
+ const int h = inlink->h;
+
+ dm->hsub = pix_desc->log2_chroma_w;
+ dm->vsub = pix_desc->log2_chroma_h;
+ dm->depth = pix_desc->comp[0].depth_minus1 + 1;
+ max_value = (1 << dm->depth) - 1;
+ dm->scthresh = (int64_t)(((int64_t)max_value * w * h * dm->scthresh_flt) / 100);
+ dm->dupthresh = (int64_t)(((int64_t)max_value * dm->blockx * dm->blocky * dm->dupthresh_flt) / 100);
+ dm->nxblocks = (w + dm->blockx/2 - 1) / (dm->blockx/2);
+ dm->nyblocks = (h + dm->blocky/2 - 1) / (dm->blocky/2);
+ dm->bdiffsize = dm->nxblocks * dm->nyblocks;
+ dm->bdiffs = av_malloc_array(dm->bdiffsize, sizeof(*dm->bdiffs));
+ dm->queue = av_calloc(dm->cycle, sizeof(*dm->queue));
+
+ if (!dm->bdiffs || !dm->queue)
+ return AVERROR(ENOMEM);
+
+ if (dm->ppsrc) {
+ dm->clean_src = av_calloc(dm->cycle, sizeof(*dm->clean_src));
+ if (!dm->clean_src)
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static av_cold int decimate_init(AVFilterContext *ctx)
+{
+ DecimateContext *dm = ctx->priv;
+ AVFilterPad pad = {
+ .name = av_strdup("main"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ };
+
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ ff_insert_inpad(ctx, INPUT_MAIN, &pad);
+
+ if (dm->ppsrc) {
+ pad.name = av_strdup("clean_src");
+ pad.config_props = NULL;
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ ff_insert_inpad(ctx, INPUT_CLEANSRC, &pad);
+ }
+
+ if ((dm->blockx & (dm->blockx - 1)) ||
+ (dm->blocky & (dm->blocky - 1))) {
+ av_log(ctx, AV_LOG_ERROR, "blockx and blocky settings must be power of two\n");
+ return AVERROR(EINVAL);
+ }
+
+ dm->start_pts = AV_NOPTS_VALUE;
+
+ return 0;
+}
+
+static av_cold void decimate_uninit(AVFilterContext *ctx)
+{
+ int i;
+ DecimateContext *dm = ctx->priv;
+
+ av_frame_free(&dm->last);
+ av_freep(&dm->bdiffs);
+ av_freep(&dm->queue);
+ av_freep(&dm->clean_src);
+ for (i = 0; i < ctx->nb_inputs; i++)
+ av_freep(&ctx->input_pads[i].name);
+}
+
+static int request_inlink(AVFilterContext *ctx, int lid)
+{
+ int ret = 0;
+ DecimateContext *dm = ctx->priv;
+
+ if (!dm->got_frame[lid]) {
+ AVFilterLink *inlink = ctx->inputs[lid];
+ ret = ff_request_frame(inlink);
+ if (ret == AVERROR_EOF) { // flushing
+ dm->eof |= 1 << lid;
+ ret = filter_frame(inlink, NULL);
+ }
+ }
+ return ret;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ int ret;
+ AVFilterContext *ctx = outlink->src;
+ DecimateContext *dm = ctx->priv;
+ const uint32_t eof_mask = 1<<INPUT_MAIN | dm->ppsrc<<INPUT_CLEANSRC;
+
+ if ((dm->eof & eof_mask) == eof_mask) // flush done?
+ return AVERROR_EOF;
+ if ((ret = request_inlink(ctx, INPUT_MAIN)) < 0)
+ return ret;
+ if (dm->ppsrc && (ret = request_inlink(ctx, INPUT_CLEANSRC)) < 0)
+ return ret;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+#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_GRAY8, AV_PIX_FMT_GRAY16,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ DecimateContext *dm = ctx->priv;
+ const AVFilterLink *inlink =
+ ctx->inputs[dm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN];
+ AVRational fps = inlink->frame_rate;
+
+ if (!fps.num || !fps.den) {
+ av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
+ "current rate of %d/%d is invalid\n", fps.num, fps.den);
+ return AVERROR(EINVAL);
+ }
+ fps = av_mul_q(fps, (AVRational){dm->cycle - 1, dm->cycle});
+ av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
+ inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den);
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ outlink->time_base = inlink->time_base;
+ outlink->frame_rate = fps;
+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+ outlink->w = inlink->w;
+ outlink->h = inlink->h;
+ dm->ts_unit = av_q2d(av_inv_q(av_mul_q(fps, outlink->time_base)));
+ return 0;
+}
+
+static const AVFilterPad decimate_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_decimate = {
+ .name = "decimate",
+ .description = NULL_IF_CONFIG_SMALL("Decimate frames (post field matching filter)."),
+ .init = decimate_init,
+ .uninit = decimate_uninit,
+ .priv_size = sizeof(DecimateContext),
+ .query_formats = query_formats,
+ .outputs = decimate_outputs,
+ .priv_class = &decimate_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
diff --git a/libavfilter/vf_dejudder.c b/libavfilter/vf_dejudder.c
new file mode 100644
index 0000000000..ab525b666c
--- /dev/null
+++ b/libavfilter/vf_dejudder.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014 Nicholas Robbins
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * remove judder in video stream
+ *
+ * Algorithm:
+ * - If the old packets had PTS of old_pts[i]. Replace these with new
+ * value based on the running average of the last n=cycle frames. So
+ *
+ * new_pts[i] = Sum(k=i-n+1, i, old_pts[k])/n
+ * + (old_pts[i]-old_pts[i-n])*(n-1)/2n
+ *
+ * For any repeating pattern of length n of judder this will produce
+ * an even progression of PTS's.
+ *
+ * - In order to avoid calculating this sum ever frame, a running tally
+ * is maintained in ctx->new_pts. Each frame the new term at the start
+ * of the sum is added, the one and the end is removed, and the offset
+ * terms (second line in formula above) are recalculated.
+ *
+ * - To aid in this a ringbuffer of the last n-2 PTS's is maintained in
+ * ctx->ringbuff. With the indices of the first two and last two entries
+ * stored in i1, i2, i3, & i4.
+ *
+ * - To ensure that the new PTS's are integers, time_base is divided
+ * by 2n. This removes the division in the new_pts calculation.
+ *
+ * - frame_rate is also multiplied by 2n to allow the frames to fall
+ * where they may in what may now be a VFR output. This produces more
+ * even output then setting frame_rate=1/0 in practice.
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/mathematics.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int64_t *ringbuff;
+ int i1, i2, i3, i4;
+ int64_t new_pts;
+ int start_count;
+
+ /* options */
+ int cycle;
+} DejudderContext;
+
+#define OFFSET(x) offsetof(DejudderContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption dejudder_options[] = {
+ {"cycle", "set the length of the cycle to use for dejuddering",
+ OFFSET(cycle), AV_OPT_TYPE_INT, {.i64 = 4}, 2, 240, .flags = FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(dejudder);
+
+static int config_out_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ DejudderContext *dj = ctx->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+
+ outlink->time_base = av_mul_q(inlink->time_base, av_make_q(1, 2 * dj->cycle));
+ outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(2 * dj->cycle, 1));
+
+ av_log(ctx, AV_LOG_VERBOSE, "cycle:%d\n", dj->cycle);
+
+ return 0;
+}
+
+static av_cold int dejudder_init(AVFilterContext *ctx)
+{
+ DejudderContext *dj = ctx->priv;
+
+ dj->ringbuff = av_mallocz_array(dj->cycle+2, sizeof(*dj->ringbuff));
+ if (!dj->ringbuff)
+ return AVERROR(ENOMEM);
+
+ dj->new_pts = 0;
+ dj->i1 = 0;
+ dj->i2 = 1;
+ dj->i3 = 2;
+ dj->i4 = 3;
+ dj->start_count = dj->cycle + 2;
+
+ return 0;
+}
+
+static av_cold void dejudder_uninit(AVFilterContext *ctx)
+{
+ DejudderContext *dj = ctx->priv;
+
+ av_freep(&(dj->ringbuff));
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ int k;
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ DejudderContext *dj = ctx->priv;
+ int64_t *judbuff = dj->ringbuff;
+ int64_t next_pts = frame->pts;
+ int64_t offset;
+
+ if (next_pts == AV_NOPTS_VALUE)
+ return ff_filter_frame(outlink, frame);
+
+ if (dj->start_count) {
+ dj->start_count--;
+ dj->new_pts = next_pts * 2 * dj->cycle;
+ } else {
+ if (next_pts < judbuff[dj->i2]) {
+ offset = next_pts + judbuff[dj->i3] - judbuff[dj->i4] - judbuff[dj->i1];
+ for (k = 0; k < dj->cycle + 2; k++)
+ judbuff[k] += offset;
+ }
+ dj->new_pts += (dj->cycle - 1) * (judbuff[dj->i3] - judbuff[dj->i1])
+ + (dj->cycle + 1) * (next_pts - judbuff[dj->i4]);
+ }
+
+ judbuff[dj->i2] = next_pts;
+ dj->i1 = dj->i2;
+ dj->i2 = dj->i3;
+ dj->i3 = dj->i4;
+ dj->i4 = (dj->i4 + 1) % (dj->cycle + 2);
+
+ frame->pts = dj->new_pts;
+
+ for (k = 0; k < dj->cycle + 2; k++)
+ av_log(ctx, AV_LOG_DEBUG, "%"PRId64"\t", judbuff[k]);
+ av_log(ctx, AV_LOG_DEBUG, "next=%"PRId64", new=%"PRId64"\n", next_pts, frame->pts);
+
+ return ff_filter_frame(outlink, frame);
+}
+
+static const AVFilterPad dejudder_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad dejudder_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_out_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_dejudder = {
+ .name = "dejudder",
+ .description = NULL_IF_CONFIG_SMALL("Remove judder produced by pullup."),
+ .priv_size = sizeof(DejudderContext),
+ .priv_class = &dejudder_class,
+ .inputs = dejudder_inputs,
+ .outputs = dejudder_outputs,
+ .init = dejudder_init,
+ .uninit = dejudder_uninit,
+};
diff --git a/libavfilter/vf_delogo.c b/libavfilter/vf_delogo.c
index dc58078d04..50a548b83c 100644
--- a/libavfilter/vf_delogo.c
+++ b/libavfilter/vf_delogo.c
@@ -1,28 +1,30 @@
/*
* Copyright (c) 2002 Jindrich Makovicka <makovick@gmail.com>
* Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2013 Jean Delvare <khali@linux-fr.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/**
* @file
* A very simple tv station logo remover
- * Ported from MPlayer libmpcodecs/vf_delogo.c.
+ * Originally imported from MPlayer libmpcodecs/vf_delogo.c,
+ * the algorithm was later improved.
*/
#include "libavutil/common.h"
@@ -35,8 +37,8 @@
#include "video.h"
/**
- * Apply a simple delogo algorithm to the image in dst and put the
- * result in src.
+ * Apply a simple delogo algorithm to the image in src and put the
+ * result in dst.
*
* The algorithm is only applied to the region specified by the logo
* parameters.
@@ -54,15 +56,16 @@
*/
static void apply_delogo(uint8_t *dst, int dst_linesize,
uint8_t *src, int src_linesize,
- int w, int h,
+ int w, int h, AVRational sar,
int logo_x, int logo_y, int logo_w, int logo_h,
- int band, int show, int direct)
+ unsigned int band, int show, int direct)
{
int x, y;
- int interp, dist;
+ uint64_t interp, weightl, weightr, weightt, weightb;
uint8_t *xdst, *xsrc;
uint8_t *topleft, *botleft, *topright;
+ unsigned int left_sample, right_sample;
int xclipl, xclipr, yclipt, yclipb;
int logo_x1, logo_x2, logo_y1, logo_y2;
@@ -87,28 +90,43 @@ static void apply_delogo(uint8_t *dst, int dst_linesize,
src += (logo_y1 + 1) * src_linesize;
for (y = logo_y1+1; y < logo_y2-1; y++) {
+ left_sample = topleft[src_linesize*(y-logo_y1)] +
+ topleft[src_linesize*(y-logo_y1-1)] +
+ topleft[src_linesize*(y-logo_y1+1)];
+ right_sample = topright[src_linesize*(y-logo_y1)] +
+ topright[src_linesize*(y-logo_y1-1)] +
+ topright[src_linesize*(y-logo_y1+1)];
+
for (x = logo_x1+1,
xdst = dst+logo_x1+1,
xsrc = src+logo_x1+1; x < logo_x2-1; x++, xdst++, xsrc++) {
- interp = (topleft[src_linesize*(y-logo_y -yclipt)] +
- topleft[src_linesize*(y-logo_y-1-yclipt)] +
- topleft[src_linesize*(y-logo_y+1-yclipt)]) * (logo_w-(x-logo_x))/logo_w
- + (topright[src_linesize*(y-logo_y-yclipt)] +
- topright[src_linesize*(y-logo_y-1-yclipt)] +
- topright[src_linesize*(y-logo_y+1-yclipt)]) * (x-logo_x)/logo_w
- + (topleft[x-logo_x-xclipl] +
- topleft[x-logo_x-1-xclipl] +
- topleft[x-logo_x+1-xclipl]) * (logo_h-(y-logo_y))/logo_h
- + (botleft[x-logo_x-xclipl] +
- botleft[x-logo_x-1-xclipl] +
- botleft[x-logo_x+1-xclipl]) * (y-logo_y)/logo_h;
- interp /= 6;
+
+ /* Weighted interpolation based on relative distances, taking SAR into account */
+ weightl = (uint64_t) (logo_x2-1-x) * (y-logo_y1) * (logo_y2-1-y) * sar.den;
+ weightr = (uint64_t)(x-logo_x1) * (y-logo_y1) * (logo_y2-1-y) * sar.den;
+ weightt = (uint64_t)(x-logo_x1) * (logo_x2-1-x) * (logo_y2-1-y) * sar.num;
+ weightb = (uint64_t)(x-logo_x1) * (logo_x2-1-x) * (y-logo_y1) * sar.num;
+
+ interp =
+ left_sample * weightl
+ +
+ right_sample * weightr
+ +
+ (topleft[x-logo_x1] +
+ topleft[x-logo_x1-1] +
+ topleft[x-logo_x1+1]) * weightt
+ +
+ (botleft[x-logo_x1] +
+ botleft[x-logo_x1-1] +
+ botleft[x-logo_x1+1]) * weightb;
+ interp /= (weightl + weightr + weightt + weightb) * 3U;
if (y >= logo_y+band && y < logo_y+logo_h-band &&
x >= logo_x+band && x < logo_x+logo_w-band) {
*xdst = interp;
} else {
- dist = 0;
+ unsigned dist = 0;
+
if (x < logo_x+band)
dist = FFMAX(dist, logo_x-x+band);
else if (x >= logo_x+logo_w-band)
@@ -136,41 +154,33 @@ typedef struct DelogoContext {
} DelogoContext;
#define OFFSET(x) offsetof(DelogoContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
static const AVOption delogo_options[]= {
{ "x", "set logo x position", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
{ "y", "set logo y position", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
{ "w", "set logo width", OFFSET(w), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
{ "h", "set logo height", OFFSET(h), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
- { "band", "set delogo area band size", OFFSET(band), AV_OPT_TYPE_INT, { .i64 = 4 }, -1, INT_MAX, FLAGS },
- { "t", "set delogo area band size", OFFSET(band), AV_OPT_TYPE_INT, { .i64 = 4 }, -1, INT_MAX, FLAGS },
+ { "band", "set delogo area band size", OFFSET(band), AV_OPT_TYPE_INT, { .i64 = 4 }, 1, INT_MAX, FLAGS },
+ { "t", "set delogo area band size", OFFSET(band), AV_OPT_TYPE_INT, { .i64 = 4 }, 1, INT_MAX, FLAGS },
{ "show", "show delogo area", OFFSET(show), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
- { NULL },
+ { NULL }
};
-static const char *delogo_get_name(void *ctx)
-{
- return "delogo";
-}
-
-static const AVClass delogo_class = {
- .class_name = "DelogoContext",
- .item_name = delogo_get_name,
- .option = delogo_options,
-};
+AVFILTER_DEFINE_CLASS(delogo);
static int query_formats(AVFilterContext *ctx)
{
- enum AVPixelFormat pix_fmts[] = {
+ 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_YUVA420P, AV_PIX_FMT_GRAY8,
AV_PIX_FMT_NONE
};
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static av_cold int init(AVFilterContext *ctx)
@@ -187,10 +197,7 @@ static av_cold int init(AVFilterContext *ctx)
CHECK_UNSET_OPT(w);
CHECK_UNSET_OPT(h);
- if (s->show)
- s->band = 4;
-
- av_log(ctx, AV_LOG_DEBUG, "x:%d y:%d, w:%d h:%d band:%d show:%d\n",
+ av_log(ctx, AV_LOG_VERBOSE, "x:%d y:%d, w:%d h:%d band:%d show:%d\n",
s->x, s->y, s->w, s->h, s->band, s->show);
s->w += s->band*2;
@@ -211,6 +218,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
int vsub0 = desc->log2_chroma_h;
int direct = 0;
int plane;
+ AVRational sar;
if (av_frame_is_writable(in)) {
direct = 1;
@@ -223,19 +231,26 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
av_frame_copy_props(out, in);
- out->width = outlink->w;
- out->height = outlink->h;
}
- for (plane = 0; plane < 4 && in->data[plane]; plane++) {
+ sar = in->sample_aspect_ratio;
+ /* Assume square pixels if SAR is unknown */
+ if (!sar.num)
+ sar.num = sar.den = 1;
+
+ for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) {
int hsub = plane == 1 || plane == 2 ? hsub0 : 0;
int vsub = plane == 1 || plane == 2 ? vsub0 : 0;
apply_delogo(out->data[plane], out->linesize[plane],
in ->data[plane], in ->linesize[plane],
- inlink->w>>hsub, inlink->h>>vsub,
- s->x>>hsub, s->y>>vsub,
- s->w>>hsub, s->h>>vsub,
+ FF_CEIL_RSHIFT(inlink->w, hsub),
+ FF_CEIL_RSHIFT(inlink->h, vsub),
+ sar, s->x>>hsub, s->y>>vsub,
+ /* Up and left borders were rounded down, inject lost bits
+ * into width and height to avoid error accumulation */
+ FF_CEIL_RSHIFT(s->w + (s->x & ((1<<hsub)-1)), hsub),
+ FF_CEIL_RSHIFT(s->h + (s->y & ((1<<vsub)-1)), vsub),
s->band>>FFMIN(hsub, vsub),
s->show, direct);
}
@@ -248,10 +263,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
static const AVFilterPad avfilter_vf_delogo_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -271,7 +285,7 @@ AVFilter ff_vf_delogo = {
.priv_class = &delogo_class,
.init = init,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_delogo_inputs,
- .outputs = avfilter_vf_delogo_outputs,
+ .inputs = avfilter_vf_delogo_inputs,
+ .outputs = avfilter_vf_delogo_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c
new file mode 100644
index 0000000000..cd06ee7dde
--- /dev/null
+++ b/libavfilter/vf_deshake.c
@@ -0,0 +1,575 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius@web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan@programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * fast deshake / depan video filter
+ *
+ * SAD block-matching motion compensation to fix small changes in
+ * horizontal and/or vertical shift. This filter helps remove camera shake
+ * from hand-holding a camera, bumping a tripod, moving on a vehicle, etc.
+ *
+ * Algorithm:
+ * - For each frame with one previous reference frame
+ * - For each block in the frame
+ * - If contrast > threshold then find likely motion vector
+ * - For all found motion vectors
+ * - Find most common, store as global motion vector
+ * - Find most likely rotation angle
+ * - Transform image along global motion
+ *
+ * TODO:
+ * - Fill frame edges based on previous/next reference frames
+ * - Fill frame edges by stretching image near the edges?
+ * - Can this be done quickly and look decent?
+ *
+ * Dark Shikari links to http://wiki.videolan.org/SoC_x264_2010#GPU_Motion_Estimation_2
+ * for an algorithm similar to what could be used here to get the gmv
+ * It requires only a couple diamond searches + fast downscaling
+ *
+ * Special thanks to Jason Kotenko for his help with the algorithm and my
+ * inability to see simple errors in C code.
+ */
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "libavutil/common.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "deshake.h"
+#include "deshake_opencl.h"
+
+#define CHROMA_WIDTH(link) (-((-(link)->w) >> av_pix_fmt_desc_get((link)->format)->log2_chroma_w))
+#define CHROMA_HEIGHT(link) (-((-(link)->h) >> av_pix_fmt_desc_get((link)->format)->log2_chroma_h))
+
+#define OFFSET(x) offsetof(DeshakeContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption deshake_options[] = {
+ { "x", "set x for the rectangular search area", OFFSET(cx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "y", "set y for the rectangular search area", OFFSET(cy), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "w", "set width for the rectangular search area", OFFSET(cw), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "h", "set height for the rectangular search area", OFFSET(ch), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS },
+ { "rx", "set x for the rectangular search area", OFFSET(rx), AV_OPT_TYPE_INT, {.i64=16}, 0, MAX_R, .flags = FLAGS },
+ { "ry", "set y for the rectangular search area", OFFSET(ry), AV_OPT_TYPE_INT, {.i64=16}, 0, MAX_R, .flags = FLAGS },
+ { "edge", "set edge mode", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=FILL_MIRROR}, FILL_BLANK, FILL_COUNT-1, FLAGS, "edge"},
+ { "blank", "fill zeroes at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_BLANK}, INT_MIN, INT_MAX, FLAGS, "edge" },
+ { "original", "original image at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_ORIGINAL}, INT_MIN, INT_MAX, FLAGS, "edge" },
+ { "clamp", "extruded edge value at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_CLAMP}, INT_MIN, INT_MAX, FLAGS, "edge" },
+ { "mirror", "mirrored edge at blank locations", 0, AV_OPT_TYPE_CONST, {.i64=FILL_MIRROR}, INT_MIN, INT_MAX, FLAGS, "edge" },
+ { "blocksize", "set motion search blocksize", OFFSET(blocksize), AV_OPT_TYPE_INT, {.i64=8}, 4, 128, .flags = FLAGS },
+ { "contrast", "set contrast threshold for blocks", OFFSET(contrast), AV_OPT_TYPE_INT, {.i64=125}, 1, 255, .flags = FLAGS },
+ { "search", "set search strategy", OFFSET(search), AV_OPT_TYPE_INT, {.i64=EXHAUSTIVE}, EXHAUSTIVE, SEARCH_COUNT-1, FLAGS, "smode" },
+ { "exhaustive", "exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" },
+ { "less", "less exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=SMART_EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" },
+ { "filename", "set motion search detailed log file name", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "opencl", "use OpenCL filtering capabilities", OFFSET(opencl), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(deshake);
+
+static int cmp(const double *a, const double *b)
+{
+ return *a < *b ? -1 : ( *a > *b ? 1 : 0 );
+}
+
+/**
+ * Cleaned mean (cuts off 20% of values to remove outliers and then averages)
+ */
+static double clean_mean(double *values, int count)
+{
+ double mean = 0;
+ int cut = count / 5;
+ int x;
+
+ qsort(values, count, sizeof(double), (void*)cmp);
+
+ for (x = cut; x < count - cut; x++) {
+ mean += values[x];
+ }
+
+ return mean / (count - cut * 2);
+}
+
+/**
+ * Find the most likely shift in motion between two frames for a given
+ * macroblock. Test each block against several shifts given by the rx
+ * and ry attributes. Searches using a simple matrix of those shifts and
+ * chooses the most likely shift by the smallest difference in blocks.
+ */
+static void find_block_motion(DeshakeContext *deshake, uint8_t *src1,
+ uint8_t *src2, int cx, int cy, int stride,
+ IntMotionVector *mv)
+{
+ int x, y;
+ int diff;
+ int smallest = INT_MAX;
+ int tmp, tmp2;
+
+ #define CMP(i, j) deshake->sad(src1 + cy * stride + cx, stride,\
+ src2 + (j) * stride + (i), stride)
+
+ if (deshake->search == EXHAUSTIVE) {
+ // Compare every possible position - this is sloooow!
+ for (y = -deshake->ry; y <= deshake->ry; y++) {
+ for (x = -deshake->rx; x <= deshake->rx; x++) {
+ diff = CMP(cx - x, cy - y);
+ if (diff < smallest) {
+ smallest = diff;
+ mv->x = x;
+ mv->y = y;
+ }
+ }
+ }
+ } else if (deshake->search == SMART_EXHAUSTIVE) {
+ // Compare every other possible position and find the best match
+ for (y = -deshake->ry + 1; y < deshake->ry; y += 2) {
+ for (x = -deshake->rx + 1; x < deshake->rx; x += 2) {
+ diff = CMP(cx - x, cy - y);
+ if (diff < smallest) {
+ smallest = diff;
+ mv->x = x;
+ mv->y = y;
+ }
+ }
+ }
+
+ // Hone in on the specific best match around the match we found above
+ tmp = mv->x;
+ tmp2 = mv->y;
+
+ for (y = tmp2 - 1; y <= tmp2 + 1; y++) {
+ for (x = tmp - 1; x <= tmp + 1; x++) {
+ if (x == tmp && y == tmp2)
+ continue;
+
+ diff = CMP(cx - x, cy - y);
+ if (diff < smallest) {
+ smallest = diff;
+ mv->x = x;
+ mv->y = y;
+ }
+ }
+ }
+ }
+
+ if (smallest > 512) {
+ mv->x = -1;
+ mv->y = -1;
+ }
+ emms_c();
+ //av_log(NULL, AV_LOG_ERROR, "%d\n", smallest);
+ //av_log(NULL, AV_LOG_ERROR, "Final: (%d, %d) = %d x %d\n", cx, cy, mv->x, mv->y);
+}
+
+/**
+ * Find the contrast of a given block. When searching for global motion we
+ * really only care about the high contrast blocks, so using this method we
+ * can actually skip blocks we don't care much about.
+ */
+static int block_contrast(uint8_t *src, int x, int y, int stride, int blocksize)
+{
+ int highest = 0;
+ int lowest = 255;
+ int i, j, pos;
+
+ for (i = 0; i <= blocksize * 2; i++) {
+ // We use a width of 16 here to match the sad function
+ for (j = 0; j <= 15; j++) {
+ pos = (y - i) * stride + (x - j);
+ if (src[pos] < lowest)
+ lowest = src[pos];
+ else if (src[pos] > highest) {
+ highest = src[pos];
+ }
+ }
+ }
+
+ return highest - lowest;
+}
+
+/**
+ * Find the rotation for a given block.
+ */
+static double block_angle(int x, int y, int cx, int cy, IntMotionVector *shift)
+{
+ double a1, a2, diff;
+
+ a1 = atan2(y - cy, x - cx);
+ a2 = atan2(y - cy + shift->y, x - cx + shift->x);
+
+ diff = a2 - a1;
+
+ return (diff > M_PI) ? diff - 2 * M_PI :
+ (diff < -M_PI) ? diff + 2 * M_PI :
+ diff;
+}
+
+/**
+ * Find the estimated global motion for a scene given the most likely shift
+ * for each block in the frame. The global motion is estimated to be the
+ * same as the motion from most blocks in the frame, so if most blocks
+ * move one pixel to the right and two pixels down, this would yield a
+ * motion vector (1, -2).
+ */
+static void find_motion(DeshakeContext *deshake, uint8_t *src1, uint8_t *src2,
+ int width, int height, int stride, Transform *t)
+{
+ int x, y;
+ IntMotionVector mv = {0, 0};
+ int count_max_value = 0;
+ int contrast;
+
+ int pos;
+ int center_x = 0, center_y = 0;
+ double p_x, p_y;
+
+ av_fast_malloc(&deshake->angles, &deshake->angles_size, width * height / (16 * deshake->blocksize) * sizeof(*deshake->angles));
+
+ // Reset counts to zero
+ for (x = 0; x < deshake->rx * 2 + 1; x++) {
+ for (y = 0; y < deshake->ry * 2 + 1; y++) {
+ deshake->counts[x][y] = 0;
+ }
+ }
+
+ pos = 0;
+ // Find motion for every block and store the motion vector in the counts
+ for (y = deshake->ry; y < height - deshake->ry - (deshake->blocksize * 2); y += deshake->blocksize * 2) {
+ // We use a width of 16 here to match the sad function
+ for (x = deshake->rx; x < width - deshake->rx - 16; x += 16) {
+ // If the contrast is too low, just skip this block as it probably
+ // won't be very useful to us.
+ contrast = block_contrast(src2, x, y, stride, deshake->blocksize);
+ if (contrast > deshake->contrast) {
+ //av_log(NULL, AV_LOG_ERROR, "%d\n", contrast);
+ find_block_motion(deshake, src1, src2, x, y, stride, &mv);
+ if (mv.x != -1 && mv.y != -1) {
+ deshake->counts[mv.x + deshake->rx][mv.y + deshake->ry] += 1;
+ if (x > deshake->rx && y > deshake->ry)
+ deshake->angles[pos++] = block_angle(x, y, 0, 0, &mv);
+
+ center_x += mv.x;
+ center_y += mv.y;
+ }
+ }
+ }
+ }
+
+ if (pos) {
+ center_x /= pos;
+ center_y /= pos;
+ t->angle = clean_mean(deshake->angles, pos);
+ if (t->angle < 0.001)
+ t->angle = 0;
+ } else {
+ t->angle = 0;
+ }
+
+ // Find the most common motion vector in the frame and use it as the gmv
+ for (y = deshake->ry * 2; y >= 0; y--) {
+ for (x = 0; x < deshake->rx * 2 + 1; x++) {
+ //av_log(NULL, AV_LOG_ERROR, "%5d ", deshake->counts[x][y]);
+ if (deshake->counts[x][y] > count_max_value) {
+ t->vec.x = x - deshake->rx;
+ t->vec.y = y - deshake->ry;
+ count_max_value = deshake->counts[x][y];
+ }
+ }
+ //av_log(NULL, AV_LOG_ERROR, "\n");
+ }
+
+ p_x = (center_x - width / 2.0);
+ p_y = (center_y - height / 2.0);
+ t->vec.x += (cos(t->angle)-1)*p_x - sin(t->angle)*p_y;
+ t->vec.y += sin(t->angle)*p_x + (cos(t->angle)-1)*p_y;
+
+ // Clamp max shift & rotation?
+ t->vec.x = av_clipf(t->vec.x, -deshake->rx * 2, deshake->rx * 2);
+ t->vec.y = av_clipf(t->vec.y, -deshake->ry * 2, deshake->ry * 2);
+ t->angle = av_clipf(t->angle, -0.1, 0.1);
+
+ //av_log(NULL, AV_LOG_ERROR, "%d x %d\n", avg->x, avg->y);
+}
+
+static int deshake_transform_c(AVFilterContext *ctx,
+ int width, int height, int cw, int ch,
+ const float *matrix_y, const float *matrix_uv,
+ enum InterpolateMethod interpolate,
+ enum FillMethod fill, AVFrame *in, AVFrame *out)
+{
+ int i = 0, ret = 0;
+ const float *matrixs[3];
+ int plane_w[3], plane_h[3];
+ matrixs[0] = matrix_y;
+ matrixs[1] = matrixs[2] = matrix_uv;
+ plane_w[0] = width;
+ plane_w[1] = plane_w[2] = cw;
+ plane_h[0] = height;
+ plane_h[1] = plane_h[2] = ch;
+
+ for (i = 0; i < 3; i++) {
+ // Transform the luma and chroma planes
+ ret = avfilter_transform(in->data[i], out->data[i], in->linesize[i], out->linesize[i],
+ plane_w[i], plane_h[i], matrixs[i], interpolate, fill);
+ if (ret < 0)
+ return ret;
+ }
+ return ret;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ int ret;
+ DeshakeContext *deshake = ctx->priv;
+
+ deshake->sad = av_pixelutils_get_sad_fn(4, 4, 1, deshake); // 16x16, 2nd source unaligned
+ if (!deshake->sad)
+ return AVERROR(EINVAL);
+
+ deshake->refcount = 20; // XXX: add to options?
+ deshake->blocksize /= 2;
+ deshake->blocksize = av_clip(deshake->blocksize, 4, 128);
+
+ if (deshake->rx % 16) {
+ av_log(ctx, AV_LOG_ERROR, "rx must be a multiple of 16\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (deshake->filename)
+ deshake->fp = fopen(deshake->filename, "w");
+ if (deshake->fp)
+ fwrite("Ori x, Avg x, Fin x, Ori y, Avg y, Fin y, Ori angle, Avg angle, Fin angle, Ori zoom, Avg zoom, Fin zoom\n", sizeof(char), 104, deshake->fp);
+
+ // Quadword align left edge of box for MMX code, adjust width if necessary
+ // to keep right margin
+ if (deshake->cx > 0) {
+ deshake->cw += deshake->cx - (deshake->cx & ~15);
+ deshake->cx &= ~15;
+ }
+ deshake->transform = deshake_transform_c;
+ if (!CONFIG_OPENCL && deshake->opencl) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL support was not enabled in this build, cannot be selected\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (CONFIG_OPENCL && deshake->opencl) {
+ deshake->transform = ff_opencl_transform;
+ ret = ff_opencl_deshake_init(ctx);
+ if (ret < 0)
+ return ret;
+ }
+ av_log(ctx, AV_LOG_VERBOSE, "cx: %d, cy: %d, cw: %d, ch: %d, rx: %d, ry: %d, edge: %d blocksize: %d contrast: %d search: %d\n",
+ deshake->cx, deshake->cy, deshake->cw, deshake->ch,
+ deshake->rx, deshake->ry, deshake->edge, deshake->blocksize * 2, deshake->contrast, deshake->search);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_props(AVFilterLink *link)
+{
+ DeshakeContext *deshake = link->dst->priv;
+
+ deshake->ref = NULL;
+ deshake->last.vec.x = 0;
+ deshake->last.vec.y = 0;
+ deshake->last.angle = 0;
+ deshake->last.zoom = 0;
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ DeshakeContext *deshake = ctx->priv;
+ if (CONFIG_OPENCL && deshake->opencl) {
+ ff_opencl_deshake_uninit(ctx);
+ }
+ av_frame_free(&deshake->ref);
+ av_freep(&deshake->angles);
+ deshake->angles_size = 0;
+ if (deshake->fp)
+ fclose(deshake->fp);
+}
+
+static int filter_frame(AVFilterLink *link, AVFrame *in)
+{
+ DeshakeContext *deshake = link->dst->priv;
+ AVFilterLink *outlink = link->dst->outputs[0];
+ AVFrame *out;
+ Transform t = {{0},0}, orig = {{0},0};
+ float matrix_y[9], matrix_uv[9];
+ float alpha = 2.0 / deshake->refcount;
+ char tmp[256];
+ int ret = 0;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ if (CONFIG_OPENCL && deshake->opencl) {
+ ret = ff_opencl_deshake_process_inout_buf(link->dst,in, out);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (deshake->cx < 0 || deshake->cy < 0 || deshake->cw < 0 || deshake->ch < 0) {
+ // Find the most likely global motion for the current frame
+ find_motion(deshake, (deshake->ref == NULL) ? in->data[0] : deshake->ref->data[0], in->data[0], link->w, link->h, in->linesize[0], &t);
+ } else {
+ uint8_t *src1 = (deshake->ref == NULL) ? in->data[0] : deshake->ref->data[0];
+ uint8_t *src2 = in->data[0];
+
+ deshake->cx = FFMIN(deshake->cx, link->w);
+ deshake->cy = FFMIN(deshake->cy, link->h);
+
+ if ((unsigned)deshake->cx + (unsigned)deshake->cw > link->w) deshake->cw = link->w - deshake->cx;
+ if ((unsigned)deshake->cy + (unsigned)deshake->ch > link->h) deshake->ch = link->h - deshake->cy;
+
+ // Quadword align right margin
+ deshake->cw &= ~15;
+
+ src1 += deshake->cy * in->linesize[0] + deshake->cx;
+ src2 += deshake->cy * in->linesize[0] + deshake->cx;
+
+ find_motion(deshake, src1, src2, deshake->cw, deshake->ch, in->linesize[0], &t);
+ }
+
+
+ // Copy transform so we can output it later to compare to the smoothed value
+ orig.vec.x = t.vec.x;
+ orig.vec.y = t.vec.y;
+ orig.angle = t.angle;
+ orig.zoom = t.zoom;
+
+ // Generate a one-sided moving exponential average
+ deshake->avg.vec.x = alpha * t.vec.x + (1.0 - alpha) * deshake->avg.vec.x;
+ deshake->avg.vec.y = alpha * t.vec.y + (1.0 - alpha) * deshake->avg.vec.y;
+ deshake->avg.angle = alpha * t.angle + (1.0 - alpha) * deshake->avg.angle;
+ deshake->avg.zoom = alpha * t.zoom + (1.0 - alpha) * deshake->avg.zoom;
+
+ // Remove the average from the current motion to detect the motion that
+ // is not on purpose, just as jitter from bumping the camera
+ t.vec.x -= deshake->avg.vec.x;
+ t.vec.y -= deshake->avg.vec.y;
+ t.angle -= deshake->avg.angle;
+ t.zoom -= deshake->avg.zoom;
+
+ // Invert the motion to undo it
+ t.vec.x *= -1;
+ t.vec.y *= -1;
+ t.angle *= -1;
+
+ // Write statistics to file
+ if (deshake->fp) {
+ snprintf(tmp, 256, "%f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f\n", orig.vec.x, deshake->avg.vec.x, t.vec.x, orig.vec.y, deshake->avg.vec.y, t.vec.y, orig.angle, deshake->avg.angle, t.angle, orig.zoom, deshake->avg.zoom, t.zoom);
+ fwrite(tmp, sizeof(char), strlen(tmp), deshake->fp);
+ }
+
+ // Turn relative current frame motion into absolute by adding it to the
+ // last absolute motion
+ t.vec.x += deshake->last.vec.x;
+ t.vec.y += deshake->last.vec.y;
+ t.angle += deshake->last.angle;
+ t.zoom += deshake->last.zoom;
+
+ // Shrink motion by 10% to keep things centered in the camera frame
+ t.vec.x *= 0.9;
+ t.vec.y *= 0.9;
+ t.angle *= 0.9;
+
+ // Store the last absolute motion information
+ deshake->last.vec.x = t.vec.x;
+ deshake->last.vec.y = t.vec.y;
+ deshake->last.angle = t.angle;
+ deshake->last.zoom = t.zoom;
+
+ // Generate a luma transformation matrix
+ avfilter_get_matrix(t.vec.x, t.vec.y, t.angle, 1.0 + t.zoom / 100.0, matrix_y);
+ // Generate a chroma transformation matrix
+ avfilter_get_matrix(t.vec.x / (link->w / CHROMA_WIDTH(link)), t.vec.y / (link->h / CHROMA_HEIGHT(link)), t.angle, 1.0 + t.zoom / 100.0, matrix_uv);
+ // Transform the luma and chroma planes
+ ret = deshake->transform(link->dst, link->w, link->h, CHROMA_WIDTH(link), CHROMA_HEIGHT(link),
+ matrix_y, matrix_uv, INTERPOLATE_BILINEAR, deshake->edge, in, out);
+
+ // Cleanup the old reference frame
+ av_frame_free(&deshake->ref);
+
+ if (ret < 0)
+ return ret;
+
+ // Store the current frame as the reference frame for calculating the
+ // motion of the next frame
+ deshake->ref = in;
+
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad deshake_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad deshake_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_deshake = {
+ .name = "deshake",
+ .description = NULL_IF_CONFIG_SMALL("Stabilize shaky video."),
+ .priv_size = sizeof(DeshakeContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = deshake_inputs,
+ .outputs = deshake_outputs,
+ .priv_class = &deshake_class,
+};
diff --git a/libavfilter/vf_detelecine.c b/libavfilter/vf_detelecine.c
new file mode 100644
index 0000000000..44379a3ec7
--- /dev/null
+++ b/libavfilter/vf_detelecine.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2015 Himangi Saraogi <himangi774@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 detelecine filter.
+ */
+
+
+#include "libavutil/avstring.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int first_field;
+ char *pattern;
+ int start_frame;
+ unsigned int pattern_pos;
+ unsigned int nskip_fields;
+ int64_t start_time;
+
+ AVRational pts;
+ AVRational ts_unit;
+ int occupied;
+
+ int nb_planes;
+ int planeheight[4];
+ int stride[4];
+
+ AVFrame *frame;
+ AVFrame *temp;
+} DetelecineContext;
+
+#define OFFSET(x) offsetof(DetelecineContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption detelecine_options[] = {
+ {"first_field", "select first field", OFFSET(first_field), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "field"},
+ {"top", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
+ {"t", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
+ {"bottom", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
+ {"b", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
+ {"pattern", "pattern that describe for how many fields a frame is to be displayed", OFFSET(pattern), AV_OPT_TYPE_STRING, {.str="23"}, 0, 0, FLAGS},
+ {"start_frame", "position of first frame with respect to the pattern if stream is cut", OFFSET(start_frame), AV_OPT_TYPE_INT, {.i64=0}, 0, 13, FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(detelecine);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ DetelecineContext *s = ctx->priv;
+ const char *p;
+ int max = 0;
+
+ if (!strlen(s->pattern)) {
+ av_log(ctx, AV_LOG_ERROR, "No pattern provided.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (p = s->pattern; *p; p++) {
+ if (!av_isdigit(*p)) {
+ av_log(ctx, AV_LOG_ERROR, "Provided pattern includes non-numeric characters.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ max = FFMAX(*p - '0', max);
+ s->pts.num += *p - '0';
+ s->pts.den += 2;
+ }
+
+ s->nskip_fields = 0;
+ s->pattern_pos = 0;
+ s->start_time = AV_NOPTS_VALUE;
+
+ if (s->start_frame != 0) {
+ int nfields = 0;
+ for (p = s->pattern; *p; p++) {
+ nfields += *p - '0';
+ s->pattern_pos++;
+ if (nfields >= 2*s->start_frame) {
+ s->nskip_fields = nfields - 2*s->start_frame;
+ break;
+ }
+ }
+ }
+
+ av_log(ctx, AV_LOG_INFO, "Detelecine pattern %s removes up to %d frames per frame, pts advance factor: %d/%d\n",
+ s->pattern, (max + 1) / 2, s->pts.num, s->pts.den);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *pix_fmts = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
+ desc->flags & AV_PIX_FMT_FLAG_PAL ||
+ desc->flags & AV_PIX_FMT_FLAG_BITSTREAM))
+ ff_add_format(&pix_fmts, fmt);
+ }
+
+ return ff_set_common_formats(ctx, pix_fmts);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ DetelecineContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ s->temp = ff_get_video_buffer(inlink, inlink->w, inlink->h);
+ if (!s->temp)
+ return AVERROR(ENOMEM);
+
+ s->frame = ff_get_video_buffer(inlink, inlink->w, inlink->h);
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+
+ if ((ret = av_image_fill_linesizes(s->stride, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ DetelecineContext *s = ctx->priv;
+ const AVFilterLink *inlink = ctx->inputs[0];
+ AVRational fps = inlink->frame_rate;
+
+ if (!fps.num || !fps.den) {
+ av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
+ "current rate of %d/%d is invalid\n", fps.num, fps.den);
+ return AVERROR(EINVAL);
+ }
+ 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);
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ outlink->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);
+
+ s->ts_unit = av_inv_q(av_mul_q(fps, outlink->time_base));
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ DetelecineContext *s = ctx->priv;
+ int i, len = 0, ret = 0, out = 0;
+
+ if (s->start_time == AV_NOPTS_VALUE)
+ s->start_time = inpicref->pts;
+
+ if (s->nskip_fields >= 2) {
+ s->nskip_fields -= 2;
+ return 0;
+ } else if (s->nskip_fields >= 1) {
+ if (s->occupied) {
+ s->occupied = 0;
+ s->nskip_fields--;
+ }
+ else {
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ s->stride[i],
+ s->planeheight[i]);
+ }
+ s->occupied = 1;
+ s->nskip_fields--;
+ return 0;
+ }
+ }
+
+ if (s->nskip_fields == 0) {
+ while(!len && s->pattern[s->pattern_pos]) {
+ len = s->pattern[s->pattern_pos] - '0';
+ s->pattern_pos++;
+ }
+
+ if (!s->pattern[s->pattern_pos])
+ s->pattern_pos = 0;
+
+ if(!len) { // do not output any field as the entire pattern is zero
+ av_frame_free(&inpicref);
+ return 0;
+ }
+
+ if (s->occupied) {
+ for (i = 0; i < s->nb_planes; i++) {
+ // fill in the EARLIER field from the new pic
+ av_image_copy_plane(s->frame->data[i] + s->frame->linesize[i] * s->first_field,
+ s->frame->linesize[i] * 2,
+ inpicref->data[i] + inpicref->linesize[i] * s->first_field,
+ inpicref->linesize[i] * 2,
+ s->stride[i],
+ (s->planeheight[i] - s->first_field + 1) / 2);
+ // fill in the LATER field from the buffered pic
+ av_image_copy_plane(s->frame->data[i] + s->frame->linesize[i] * !s->first_field,
+ s->frame->linesize[i] * 2,
+ s->temp->data[i] + s->temp->linesize[i] * !s->first_field,
+ s->temp->linesize[i] * 2,
+ s->stride[i],
+ (s->planeheight[i] - !s->first_field + 1) / 2);
+ }
+ len -= 2;
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ s->stride[i],
+ s->planeheight[i]);
+ }
+ s->occupied = 1;
+ out = 1;
+ } else {
+ if (len >= 2) {
+ // output THIS image as-is
+ for (i = 0; i < s->nb_planes; i++)
+ av_image_copy_plane(s->frame->data[i], s->frame->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ s->stride[i],
+ s->planeheight[i]);
+ len -= 2;
+ out = 1;
+ } else if (len == 1) {
+ // fill in the EARLIER field from the new pic
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(s->frame->data[i] +
+ s->frame->linesize[i] * s->first_field,
+ s->frame->linesize[i] * 2,
+ inpicref->data[i] +
+ inpicref->linesize[i] * s->first_field,
+ inpicref->linesize[i] * 2, s->stride[i],
+ (s->planeheight[i] - s->first_field + 1) / 2);
+ }
+
+ // TODO: not sure about the other field
+
+ len--;
+ out = 1;
+ }
+ }
+
+ if (len == 1 && s->occupied)
+ {
+ len--;
+ s->occupied = 0;
+ }
+ }
+ s->nskip_fields = len;
+
+ if (out) {
+ AVFrame *frame = av_frame_clone(s->frame);
+
+ if (!frame) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+
+ av_frame_copy_props(frame, inpicref);
+ frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) +
+ av_rescale(outlink->frame_count, s->ts_unit.num,
+ s->ts_unit.den);
+ ret = ff_filter_frame(outlink, frame);
+ }
+
+ av_frame_free(&inpicref);
+
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ DetelecineContext *s = ctx->priv;
+
+ av_frame_free(&s->temp);
+ av_frame_free(&s->frame);
+}
+
+static const AVFilterPad detelecine_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad detelecine_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_detelecine = {
+ .name = "detelecine",
+ .description = NULL_IF_CONFIG_SMALL("Apply an inverse telecine pattern."),
+ .priv_size = sizeof(DetelecineContext),
+ .priv_class = &detelecine_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = detelecine_inputs,
+ .outputs = detelecine_outputs,
+};
diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c
index ab14af2e12..35a08e8f2e 100644
--- a/libavfilter/vf_drawbox.c
+++ b/libavfilter/vf_drawbox.c
@@ -1,32 +1,34 @@
/*
* Copyright (c) 2008 Affine Systems, Inc (Michael Sullivan, Bobby Impollonia)
+ * Copyright (c) 2013 Andrey Utkin <andrey.krieger.utkin gmail com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * Box drawing filter. Also a nice template for a filter that needs to
- * write in the input frame.
+ * Box and grid drawing filters. Also a nice template for a filter
+ * that needs to write in the input frame.
*/
#include "libavutil/colorspace.h"
#include "libavutil/common.h"
#include "libavutil/opt.h"
+#include "libavutil/eval.h"
#include "libavutil/pixdesc.h"
#include "libavutil/parseutils.h"
#include "avfilter.h"
@@ -34,62 +36,172 @@
#include "internal.h"
#include "video.h"
+static const char *const var_names[] = {
+ "dar",
+ "hsub", "vsub",
+ "in_h", "ih", ///< height of the input video
+ "in_w", "iw", ///< width of the input video
+ "sar",
+ "x",
+ "y",
+ "h", ///< height of the rendered box
+ "w", ///< width of the rendered box
+ "t",
+ "max",
+ NULL
+};
+
enum { Y, U, V, A };
+enum var_name {
+ VAR_DAR,
+ VAR_HSUB, VAR_VSUB,
+ VAR_IN_H, VAR_IH,
+ VAR_IN_W, VAR_IW,
+ VAR_SAR,
+ VAR_X,
+ VAR_Y,
+ VAR_H,
+ VAR_W,
+ VAR_T,
+ VAR_MAX,
+ VARS_NB
+};
+
typedef struct DrawBoxContext {
const AVClass *class;
- int x, y, w_opt, h_opt, w, h;
+ int x, y, w, h;
+ int thickness;
char *color_str;
unsigned char yuv_color[4];
+ int invert_color; ///< invert luma color
int vsub, hsub; ///< chroma subsampling
+ char *x_expr, *y_expr; ///< expression for x and y
+ char *w_expr, *h_expr; ///< expression for width and height
+ char *t_expr; ///< expression for thickness
} DrawBoxContext;
+static const int NUM_EXPR_EVALS = 5;
+
static av_cold int init(AVFilterContext *ctx)
{
DrawBoxContext *s = ctx->priv;
uint8_t rgba_color[4];
- if (av_parse_color(rgba_color, s->color_str, -1, ctx) < 0)
+ if (!strcmp(s->color_str, "invert"))
+ s->invert_color = 1;
+ else if (av_parse_color(rgba_color, s->color_str, -1, ctx) < 0)
return AVERROR(EINVAL);
- s->yuv_color[Y] = RGB_TO_Y_CCIR(rgba_color[0], rgba_color[1], rgba_color[2]);
- s->yuv_color[U] = RGB_TO_U_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
- s->yuv_color[V] = RGB_TO_V_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
- s->yuv_color[A] = rgba_color[3];
+ if (!s->invert_color) {
+ s->yuv_color[Y] = RGB_TO_Y_CCIR(rgba_color[0], rgba_color[1], rgba_color[2]);
+ s->yuv_color[U] = RGB_TO_U_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
+ s->yuv_color[V] = RGB_TO_V_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
+ s->yuv_color[A] = rgba_color[3];
+ }
return 0;
}
static int query_formats(AVFilterContext *ctx)
{
- enum AVPixelFormat pix_fmts[] = {
+ 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_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P,
AV_PIX_FMT_NONE
};
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static int config_input(AVFilterLink *inlink)
{
- DrawBoxContext *s = inlink->dst->priv;
+ AVFilterContext *ctx = inlink->dst;
+ DrawBoxContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ double var_values[VARS_NB], res;
+ char *expr;
+ int ret;
+ int i;
s->hsub = desc->log2_chroma_w;
s->vsub = desc->log2_chroma_h;
- s->w = (s->w_opt > 0) ? s->w_opt : inlink->w;
- s->h = (s->h_opt > 0) ? s->h_opt : inlink->h;
+ var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h;
+ var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w;
+ var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
+ var_values[VAR_DAR] = (double)inlink->w / inlink->h * var_values[VAR_SAR];
+ var_values[VAR_HSUB] = s->hsub;
+ var_values[VAR_VSUB] = s->vsub;
+ 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 = s->x_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
+ goto fail;
+ s->x = var_values[VAR_X] = res;
+
+ var_values[VAR_MAX] = inlink->h;
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->y_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
+ goto fail;
+ s->y = var_values[VAR_Y] = res;
+
+ var_values[VAR_MAX] = inlink->w - s->x;
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
+ goto fail;
+ s->w = var_values[VAR_W] = res;
+
+ var_values[VAR_MAX] = inlink->h - s->y;
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->h_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
+ goto fail;
+ s->h = var_values[VAR_H] = res;
+
+ var_values[VAR_MAX] = INT_MAX;
+ if ((ret = av_expr_parse_and_eval(&res, (expr = s->t_expr),
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0 && i == NUM_EXPR_EVALS)
+ goto fail;
+ s->thickness = var_values[VAR_T] = res;
+ }
+
+ /* if w or h are zero, use the input w/h */
+ s->w = (s->w > 0) ? s->w : inlink->w;
+ s->h = (s->h > 0) ? s->h : inlink->h;
- av_log(inlink->dst, AV_LOG_VERBOSE, "x:%d y:%d w:%d h:%d color:0x%02X%02X%02X%02X\n",
- s->w, s->y, s->w, s->h,
+ /* sanity check width and height */
+ if (s->w < 0 || s->h < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Size values less than 0 are not acceptable.\n");
+ return AVERROR(EINVAL);
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE, "x:%d y:%d w:%d h:%d color:0x%02X%02X%02X%02X\n",
+ s->x, s->y, s->w, s->h,
s->yuv_color[Y], s->yuv_color[U], s->yuv_color[V], s->yuv_color[A]);
return 0;
+
+fail:
+ av_log(ctx, AV_LOG_ERROR,
+ "Error when evaluating the expression '%s'.\n",
+ expr);
+ return ret;
}
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
@@ -105,14 +217,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
row[plane] = frame->data[plane] +
frame->linesize[plane] * (y >> s->vsub);
- for (x = FFMAX(xb, 0); x < (xb + s->w) && x < frame->width; x++) {
- double alpha = (double)s->yuv_color[A] / 255;
+ if (s->invert_color) {
+ for (x = FFMAX(xb, 0); x < xb + s->w && x < frame->width; x++)
+ if ((y - yb < s->thickness) || (yb + s->h - 1 - y < s->thickness) ||
+ (x - xb < s->thickness) || (xb + s->w - 1 - x < s->thickness))
+ row[0][x] = 0xff - row[0][x];
+ } else {
+ for (x = FFMAX(xb, 0); x < xb + s->w && x < frame->width; x++) {
+ double alpha = (double)s->yuv_color[A] / 255;
- if ((y - yb < 3) || (yb + s->h - y < 4) ||
- (x - xb < 3) || (xb + s->w - x < 4)) {
- row[0][x ] = (1 - alpha) * row[0][x ] + alpha * s->yuv_color[Y];
- row[1][x >> s->hsub] = (1 - alpha) * row[1][x >> s->hsub] + alpha * s->yuv_color[U];
- row[2][x >> s->hsub] = (1 - alpha) * row[2][x >> s->hsub] + alpha * s->yuv_color[V];
+ if ((y - yb < s->thickness) || (yb + s->h - 1 - y < s->thickness) ||
+ (x - xb < s->thickness) || (xb + s->w - 1 - x < s->thickness)) {
+ row[0][x ] = (1 - alpha) * row[0][x ] + alpha * s->yuv_color[Y];
+ row[1][x >> s->hsub] = (1 - alpha) * row[1][x >> s->hsub] + alpha * s->yuv_color[U];
+ row[2][x >> s->hsub] = (1 - alpha) * row[2][x >> s->hsub] + alpha * s->yuv_color[V];
+ }
}
}
}
@@ -121,36 +240,38 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
}
#define OFFSET(x) offsetof(DrawBoxContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "x", "Horizontal position of the left box edge", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
- { "y", "Vertical position of the top box edge", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
- { "width", "Width of the box", OFFSET(w_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
- { "height", "Height of the box", OFFSET(h_opt), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
- { "color", "Color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
- { NULL },
-};
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#if CONFIG_DRAWBOX_FILTER
-static const AVClass drawbox_class = {
- .class_name = "drawbox",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+static const AVOption drawbox_options[] = {
+ { "x", "set horizontal position of the left box edge", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "y", "set vertical position of the top box edge", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "width", "set width of the box", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "w", "set width of the box", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "height", "set height of the box", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "h", "set height of the box", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "color", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "c", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "thickness", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "t", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { NULL }
};
-static const AVFilterPad avfilter_vf_drawbox_inputs[] = {
+AVFILTER_DEFINE_CLASS(drawbox);
+
+static const AVFilterPad drawbox_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_input,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
- .needs_writable = 1,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ .needs_writable = 1,
},
{ NULL }
};
-static const AVFilterPad avfilter_vf_drawbox_outputs[] = {
+static const AVFilterPad drawbox_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
@@ -159,13 +280,121 @@ static const AVFilterPad avfilter_vf_drawbox_outputs[] = {
};
AVFilter ff_vf_drawbox = {
- .name = "drawbox",
- .description = NULL_IF_CONFIG_SMALL("Draw a colored box on the input video."),
- .priv_size = sizeof(DrawBoxContext),
- .priv_class = &drawbox_class,
- .init = init,
-
- .query_formats = query_formats,
- .inputs = avfilter_vf_drawbox_inputs,
- .outputs = avfilter_vf_drawbox_outputs,
+ .name = "drawbox",
+ .description = NULL_IF_CONFIG_SMALL("Draw a colored box on the input video."),
+ .priv_size = sizeof(DrawBoxContext),
+ .priv_class = &drawbox_class,
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = drawbox_inputs,
+ .outputs = drawbox_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
+#endif /* CONFIG_DRAWBOX_FILTER */
+
+#if CONFIG_DRAWGRID_FILTER
+static av_pure av_always_inline int pixel_belongs_to_grid(DrawBoxContext *drawgrid, int x, int y)
+{
+ // x is horizontal (width) coord,
+ // y is vertical (height) coord
+ int x_modulo;
+ int y_modulo;
+
+ // Abstract from the offset
+ x -= drawgrid->x;
+ y -= drawgrid->y;
+
+ x_modulo = x % drawgrid->w;
+ y_modulo = y % drawgrid->h;
+
+ // If x or y got negative, fix values to preserve logics
+ if (x_modulo < 0)
+ x_modulo += drawgrid->w;
+ if (y_modulo < 0)
+ y_modulo += drawgrid->h;
+
+ return x_modulo < drawgrid->thickness // Belongs to vertical line
+ || y_modulo < drawgrid->thickness; // Belongs to horizontal line
+}
+
+static int drawgrid_filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ DrawBoxContext *drawgrid = inlink->dst->priv;
+ int plane, x, y;
+ uint8_t *row[4];
+
+ for (y = 0; y < frame->height; y++) {
+ row[0] = frame->data[0] + y * frame->linesize[0];
+
+ for (plane = 1; plane < 3; plane++)
+ row[plane] = frame->data[plane] +
+ frame->linesize[plane] * (y >> drawgrid->vsub);
+
+ if (drawgrid->invert_color) {
+ for (x = 0; x < frame->width; x++)
+ if (pixel_belongs_to_grid(drawgrid, x, y))
+ row[0][x] = 0xff - row[0][x];
+ } else {
+ for (x = 0; x < frame->width; x++) {
+ double alpha = (double)drawgrid->yuv_color[A] / 255;
+
+ if (pixel_belongs_to_grid(drawgrid, x, y)) {
+ row[0][x ] = (1 - alpha) * row[0][x ] + alpha * drawgrid->yuv_color[Y];
+ row[1][x >> drawgrid->hsub] = (1 - alpha) * row[1][x >> drawgrid->hsub] + alpha * drawgrid->yuv_color[U];
+ row[2][x >> drawgrid->hsub] = (1 - alpha) * row[2][x >> drawgrid->hsub] + alpha * drawgrid->yuv_color[V];
+ }
+ }
+ }
+ }
+
+ return ff_filter_frame(inlink->dst->outputs[0], frame);
+}
+
+static const AVOption drawgrid_options[] = {
+ { "x", "set horizontal offset", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "y", "set vertical offset", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "width", "set width of grid cell", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "w", "set width of grid cell", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "height", "set height of grid cell", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "h", "set height of grid cell", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str="0" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "color", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "c", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "thickness", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "t", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { NULL }
};
+
+AVFILTER_DEFINE_CLASS(drawgrid);
+
+static const AVFilterPad drawgrid_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = drawgrid_filter_frame,
+ .needs_writable = 1,
+ },
+ { NULL }
+};
+
+static const AVFilterPad drawgrid_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_drawgrid = {
+ .name = "drawgrid",
+ .description = NULL_IF_CONFIG_SMALL("Draw a colored grid on the input video."),
+ .priv_size = sizeof(DrawBoxContext),
+ .priv_class = &drawgrid_class,
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = drawgrid_inputs,
+ .outputs = drawgrid_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
+
+#endif /* CONFIG_DRAWGRID_FILTER */
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index 97d44c61f9..16e3383db0 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -3,20 +3,20 @@
* Copyright (c) 2010 S.N. Hemanth Meenakshisundaram
* Copyright (c) 2003 Gustavo Sverzut Barbieri <gsbarbieri@yahoo.com.br>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,25 +28,30 @@
#include "config.h"
-#include <sys/types.h>
+#if HAVE_SYS_TIME_H
#include <sys/time.h>
+#endif
+#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
+#if HAVE_UNISTD_H
#include <unistd.h>
+#endif
+#include <fenv.h>
#if CONFIG_LIBFONTCONFIG
#include <fontconfig/fontconfig.h>
#endif
-#include "libavutil/colorspace.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/common.h"
#include "libavutil/file.h"
#include "libavutil/eval.h"
#include "libavutil/opt.h"
-#include "libavutil/mathematics.h"
#include "libavutil/random_seed.h"
#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
+#include "libavutil/timecode.h"
#include "libavutil/time_internal.h"
#include "libavutil/tree.h"
#include "libavutil/lfg.h"
@@ -56,22 +61,33 @@
#include "internal.h"
#include "video.h"
+#if CONFIG_LIBFRIBIDI
+#include <fribidi.h>
+#endif
+
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_STROKER_H
static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
- "main_w", "W", ///< width of the main video
- "main_h", "H", ///< height of the main video
- "text_w", "w", ///< width of the overlay text
- "text_h", "h", ///< height of the overlay text
+ "dar",
+ "hsub", "vsub",
+ "line_h", "lh", ///< line height, same as max_glyph_h
+ "main_h", "h", "H", ///< height of the input video
+ "main_w", "w", "W", ///< width of the input video
+ "max_glyph_a", "ascent", ///< max glyph ascent
+ "max_glyph_d", "descent", ///< min glyph descent
+ "max_glyph_h", ///< max glyph height
+ "max_glyph_w", ///< max glyph width
+ "n", ///< number of frame
+ "sar",
+ "t", ///< timestamp expressed in seconds
+ "text_h", "th", ///< height of the rendered text
+ "text_w", "tw", ///< width of the rendered text
"x",
"y",
- "n", ///< number of processed frames
- "t", ///< timestamp expressed in seconds
+ "pict_type",
NULL
};
@@ -92,99 +108,140 @@ static const eval_func2 fun2[] = {
};
enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
- VAR_MAIN_W, VAR_MW,
- VAR_MAIN_H, VAR_MH,
- VAR_TEXT_W, VAR_TW,
+ VAR_DAR,
+ VAR_HSUB, VAR_VSUB,
+ VAR_LINE_H, VAR_LH,
+ VAR_MAIN_H, VAR_h, VAR_H,
+ VAR_MAIN_W, VAR_w, VAR_W,
+ VAR_MAX_GLYPH_A, VAR_ASCENT,
+ VAR_MAX_GLYPH_D, VAR_DESCENT,
+ VAR_MAX_GLYPH_H,
+ VAR_MAX_GLYPH_W,
+ VAR_N,
+ VAR_SAR,
+ VAR_T,
VAR_TEXT_H, VAR_TH,
+ VAR_TEXT_W, VAR_TW,
VAR_X,
VAR_Y,
- VAR_N,
- VAR_T,
+ VAR_PICT_TYPE,
VAR_VARS_NB
};
+enum expansion_mode {
+ EXP_NONE,
+ EXP_NORMAL,
+ EXP_STRFTIME,
+};
+
typedef struct DrawTextContext {
const AVClass *class;
+ int exp_mode; ///< expansion mode to use for the text
+ int reinit; ///< tells if the filter is being reinited
#if CONFIG_LIBFONTCONFIG
uint8_t *font; ///< font to be used
#endif
uint8_t *fontfile; ///< font to be used
uint8_t *text; ///< text to be drawn
- uint8_t *expanded_text; ///< used to contain the strftime()-expanded text
- size_t expanded_text_size; ///< size in bytes of the expanded_text buffer
+ AVBPrint expanded_text; ///< used to contain the expanded text
+ uint8_t *fontcolor_expr; ///< fontcolor expression to evaluate
+ AVBPrint expanded_fontcolor; ///< used to contain the expanded fontcolor spec
int ft_load_flags; ///< flags used for loading fonts, see FT_LOAD_*
FT_Vector *positions; ///< positions for each element in the text
size_t nb_positions; ///< number of elements of positions array
char *textfile; ///< file with text to be drawn
- int x, y; ///< position to start drawing text
- int w, h; ///< dimension of the text block
+ int x; ///< x position to start drawing text
+ int y; ///< y position to start drawing text
+ int max_glyph_w; ///< max glyph width
+ int max_glyph_h; ///< max glyph height
int shadowx, shadowy;
+ int borderw; ///< border width
unsigned int fontsize; ///< font size to use
- char *fontcolor_string; ///< font color as string
- char *boxcolor_string; ///< box color as string
- char *shadowcolor_string; ///< shadow color as string
- uint8_t fontcolor[4]; ///< foreground color
- uint8_t boxcolor[4]; ///< background color
- uint8_t shadowcolor[4]; ///< shadow color
- uint8_t fontcolor_rgba[4]; ///< foreground color in RGBA
- uint8_t boxcolor_rgba[4]; ///< background color in RGBA
- uint8_t shadowcolor_rgba[4]; ///< shadow color in RGBA
short int draw_box; ///< draw box around text - true or false
+ int boxborderw; ///< box border width
int use_kerning; ///< font kerning is used - true/false
int tabsize; ///< tab size
int fix_bounds; ///< do we let it go out of frame bounds - t/f
+ FFDrawContext dc;
+ FFDrawColor fontcolor; ///< foreground color
+ FFDrawColor shadowcolor; ///< shadow color
+ FFDrawColor bordercolor; ///< border color
+ FFDrawColor boxcolor; ///< background color
+
FT_Library library; ///< freetype font library handle
FT_Face face; ///< freetype font face handle
+ FT_Stroker stroker; ///< freetype stroker handle
struct AVTreeNode *glyphs; ///< rendered glyphs, stored using the UTF-32 char code
- int hsub, vsub; ///< chroma subsampling values
- int is_packed_rgb;
- int pixel_step[4]; ///< distance in bytes between the component of each pixel
- uint8_t rgba_map[4]; ///< map RGBA offsets to the positions in the packed RGBA format
- uint8_t *box_line[4]; ///< line used for filling the box background
- char *x_expr, *y_expr;
+ char *x_expr; ///< expression for x position
+ char *y_expr; ///< expression for y position
AVExpr *x_pexpr, *y_pexpr; ///< parsed expressions for x and y
+ int64_t basetime; ///< base pts time in the real world for display
double var_values[VAR_VARS_NB];
- char *d_expr;
- AVExpr *d_pexpr;
- int draw; ///< set to zero to prevent drawing
char *a_expr;
AVExpr *a_pexpr;
int alpha;
AVLFG prng; ///< random
+ char *tc_opt_string; ///< specified timecode option string
+ AVRational tc_rate; ///< frame rate for timecode
+ AVTimecode tc; ///< timecode context
+ int tc24hmax; ///< 1 if timecode is wrapped to 24 hours, 0 otherwise
+ int reload; ///< reload text file for each frame
+ int start_number; ///< starting frame number for n/frame_num var
+#if CONFIG_LIBFRIBIDI
+ int text_shaping; ///< 1 to shape the text before drawing it
+#endif
+ AVDictionary *metadata;
} DrawTextContext;
#define OFFSET(x) offsetof(DrawTextContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
static const AVOption drawtext_options[]= {
+ {"fontfile", "set font file", OFFSET(fontfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"text", "set text", OFFSET(text), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"fontcolor_expr", "set foreground color expression", OFFSET(fontcolor_expr), AV_OPT_TYPE_STRING, {.str=""}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 , FLAGS},
+ {"boxborderw", "set box border width", OFFSET(boxborderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
+ {"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX , FLAGS},
+ {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"shadowx", "set x", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
+ {"shadowy", "set y", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
+ {"borderw", "set border width", OFFSET(borderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
+ {"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX , FLAGS},
+ {"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX , FLAGS},
#if CONFIG_LIBFONTCONFIG
{ "font", "Font name", OFFSET(font), AV_OPT_TYPE_STRING, { .str = "Sans" }, .flags = FLAGS },
#endif
- { "fontfile", NULL, OFFSET(fontfile), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "text", NULL, OFFSET(text), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "textfile", NULL, OFFSET(textfile), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "fontcolor", NULL, OFFSET(fontcolor_string), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
- { "boxcolor", NULL, OFFSET(boxcolor_string), AV_OPT_TYPE_STRING, { .str = "white" }, .flags = FLAGS },
- { "shadowcolor", NULL, OFFSET(shadowcolor_string), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
- { "box", NULL, OFFSET(draw_box), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
- { "fontsize", NULL, OFFSET(fontsize), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, 1024, FLAGS },
- { "x", NULL, OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
- { "y", NULL, OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
- { "shadowx", NULL, OFFSET(shadowx), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
- { "shadowy", NULL, OFFSET(shadowy), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
- { "tabsize", NULL, OFFSET(tabsize), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, INT_MAX, FLAGS },
- { "draw", "if false do not draw", OFFSET(d_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
+
+ {"expansion", "set the expansion mode", OFFSET(exp_mode), AV_OPT_TYPE_INT, {.i64=EXP_NORMAL}, 0, 2, FLAGS, "expansion"},
+ {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"},
+ {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"},
+ {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"},
+
+ {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"timecode_rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
+ {"r", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
+ {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS},
+ {"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
{ "alpha", "apply alpha while rendering", OFFSET(a_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
- { "fix_bounds", "if true, check and fix text coords to avoid clipping",
- OFFSET(fix_bounds), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
+ {"fix_bounds", "if true, check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
+ {"start_number", "start frame number for n/frame_num variable", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
+
+#if CONFIG_LIBFRIBIDI
+ {"text_shaping", "attempt to shape text before drawing", OFFSET(text_shaping), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS},
+#endif
/* FT_LOAD_* flags */
- { "ft_load_flags", "set font loading flags for libfreetype", OFFSET(ft_load_flags), AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT | FT_LOAD_RENDER}, 0, INT_MAX, FLAGS, "ft_load_flags" },
+ { "ft_load_flags", "set font loading flags for libfreetype", OFFSET(ft_load_flags), AV_OPT_TYPE_FLAGS, { .i64 = FT_LOAD_DEFAULT }, 0, INT_MAX, FLAGS, "ft_load_flags" },
{ "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_DEFAULT }, .flags = FLAGS, .unit = "ft_load_flags" },
{ "no_scale", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_SCALE }, .flags = FLAGS, .unit = "ft_load_flags" },
{ "no_hinting", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_HINTING }, .flags = FLAGS, .unit = "ft_load_flags" },
@@ -200,38 +257,31 @@ static const AVOption drawtext_options[]= {
{ "monochrome", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_MONOCHROME }, .flags = FLAGS, .unit = "ft_load_flags" },
{ "linear_design", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_LINEAR_DESIGN }, .flags = FLAGS, .unit = "ft_load_flags" },
{ "no_autohint", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FT_LOAD_NO_AUTOHINT }, .flags = FLAGS, .unit = "ft_load_flags" },
- { NULL},
+ { NULL }
};
-static const char *drawtext_get_name(void *ctx)
-{
- return "drawtext";
-}
-
-static const AVClass drawtext_class = {
- "DrawTextContext",
- drawtext_get_name,
- drawtext_options
-};
+AVFILTER_DEFINE_CLASS(drawtext);
#undef __FTERRORS_H__
#define FT_ERROR_START_LIST {
#define FT_ERRORDEF(e, v, s) { (e), (s) },
#define FT_ERROR_END_LIST { 0, NULL } };
-struct ft_error
+static const struct ft_error
{
int err;
const char *err_msg;
-} static ft_errors[] =
+} ft_errors[] =
#include FT_ERRORS_H
#define FT_ERRMSG(e) ft_errors[e].err_msg
typedef struct Glyph {
- FT_Glyph *glyph;
+ FT_Glyph glyph;
+ FT_Glyph border_glyph;
uint32_t code;
FT_Bitmap bitmap; ///< array holding bitmaps of font
+ FT_Bitmap border_bitmap; ///< array holding bitmaps of font border
FT_BBox bbox;
int advance;
int bitmap_left;
@@ -251,6 +301,7 @@ static int glyph_cmp(void *key, const void *b)
static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
{
DrawTextContext *s = ctx->priv;
+ FT_BitmapGlyph bitmapglyph;
Glyph *glyph;
struct AVTreeNode *node = NULL;
int ret;
@@ -259,26 +310,40 @@ static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
if (FT_Load_Char(s->face, code, s->ft_load_flags))
return AVERROR(EINVAL);
- /* save glyph */
- if (!(glyph = av_mallocz(sizeof(*glyph))) ||
- !(glyph->glyph = av_mallocz(sizeof(*glyph->glyph)))) {
+ glyph = av_mallocz(sizeof(*glyph));
+ if (!glyph) {
ret = AVERROR(ENOMEM);
goto error;
}
glyph->code = code;
- if (FT_Get_Glyph(s->face->glyph, glyph->glyph)) {
+ if (FT_Get_Glyph(s->face->glyph, &glyph->glyph)) {
ret = AVERROR(EINVAL);
goto error;
}
+ if (s->borderw) {
+ glyph->border_glyph = glyph->glyph;
+ if (FT_Glyph_StrokeBorder(&glyph->border_glyph, s->stroker, 0, 0) ||
+ FT_Glyph_To_Bitmap(&glyph->border_glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
+ ret = AVERROR_EXTERNAL;
+ goto error;
+ }
+ bitmapglyph = (FT_BitmapGlyph) glyph->border_glyph;
+ glyph->border_bitmap = bitmapglyph->bitmap;
+ }
+ if (FT_Glyph_To_Bitmap(&glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
+ ret = AVERROR_EXTERNAL;
+ goto error;
+ }
+ bitmapglyph = (FT_BitmapGlyph) glyph->glyph;
- glyph->bitmap = s->face->glyph->bitmap;
- glyph->bitmap_left = s->face->glyph->bitmap_left;
- glyph->bitmap_top = s->face->glyph->bitmap_top;
+ glyph->bitmap = bitmapglyph->bitmap;
+ glyph->bitmap_left = bitmapglyph->left;
+ glyph->bitmap_top = bitmapglyph->top;
glyph->advance = s->face->glyph->advance.x >> 6;
/* measure text height to calculate text_height (or the maximum text height) */
- FT_Glyph_Get_CBox(*glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
+ FT_Glyph_Get_CBox(glyph->glyph, ft_glyph_bbox_pixels, &glyph->bbox);
/* cache the newly created glyph */
if (!(node = av_tree_node_alloc())) {
@@ -294,147 +359,281 @@ static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
error:
if (glyph)
av_freep(&glyph->glyph);
+
av_freep(&glyph);
av_freep(&node);
return ret;
}
-static int parse_font(AVFilterContext *ctx)
+static int load_font_file(AVFilterContext *ctx, const char *path, int index)
{
DrawTextContext *s = ctx->priv;
-#if !CONFIG_LIBFONTCONFIG
- if (!s->fontfile) {
- av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
+ int err;
+
+ err = FT_New_Face(s->library, path, index, &s->face);
+ if (err) {
+ av_log(ctx, AV_LOG_ERROR, "Could not load font \"%s\": %s\n",
+ s->fontfile, FT_ERRMSG(err));
return AVERROR(EINVAL);
}
-
return 0;
-#else
+}
+
+#if CONFIG_LIBFONTCONFIG
+static int load_font_fontconfig(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ FcConfig *fontconfig;
FcPattern *pat, *best;
FcResult result = FcResultMatch;
-
- FcBool fc_bool;
- FcChar8* fc_string;
+ FcChar8 *filename;
+ int index;
+ double size;
int err = AVERROR(ENOENT);
- if (s->fontfile)
- return 0;
-
- if (!FcInit())
+ fontconfig = FcInitLoadConfigAndFonts();
+ if (!fontconfig) {
+ av_log(ctx, AV_LOG_ERROR, "impossible to init fontconfig\n");
return AVERROR_UNKNOWN;
-
- if (!(pat = FcPatternCreate()))
- return AVERROR(ENOMEM);
+ }
+ pat = FcNameParse(s->fontfile ? s->fontfile :
+ (uint8_t *)(intptr_t)"default");
+ if (!pat) {
+ av_log(ctx, AV_LOG_ERROR, "could not parse fontconfig pat");
+ return AVERROR(EINVAL);
+ }
FcPatternAddString(pat, FC_FAMILY, s->font);
- FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
- FcPatternAddDouble(pat, FC_SIZE, (double)s->fontsize);
+ if (s->fontsize)
+ FcPatternAddDouble(pat, FC_SIZE, (double)s->fontsize);
FcDefaultSubstitute(pat);
- if (!FcConfigSubstitute(NULL, pat, FcMatchPattern)) {
+ if (!FcConfigSubstitute(fontconfig, pat, FcMatchPattern)) {
+ av_log(ctx, AV_LOG_ERROR, "could not substitue fontconfig options"); /* very unlikely */
FcPatternDestroy(pat);
return AVERROR(ENOMEM);
}
- best = FcFontMatch(NULL, pat, &result);
+ best = FcFontMatch(fontconfig, pat, &result);
FcPatternDestroy(pat);
- if (!best || result == FcResultNoMatch) {
- av_log(ctx, AV_LOG_ERROR,
- "Cannot find a valid font for the family %s\n",
- s->font);
- goto fail;
- }
-
- if (FcPatternGetBool(best, FC_OUTLINE, 0, &fc_bool) != FcResultMatch ||
- !fc_bool) {
- av_log(ctx, AV_LOG_ERROR, "Outline not available for %s\n",
+ if (!best || result != FcResultMatch) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Cannot find a valid font for the family %s\n",
s->font);
goto fail;
}
- if (FcPatternGetString(best, FC_FAMILY, 0, &fc_string) != FcResultMatch) {
- av_log(ctx, AV_LOG_ERROR, "No matches for %s\n",
- s->font);
- goto fail;
+ if (
+ FcPatternGetInteger(best, FC_INDEX, 0, &index ) != FcResultMatch ||
+ FcPatternGetDouble (best, FC_SIZE, 0, &size ) != FcResultMatch) {
+ av_log(ctx, AV_LOG_ERROR, "impossible to find font information");
+ return AVERROR(EINVAL);
}
- if (FcPatternGetString(best, FC_FILE, 0, &fc_string) != FcResultMatch) {
+ if (FcPatternGetString(best, FC_FILE, 0, &filename) != FcResultMatch) {
av_log(ctx, AV_LOG_ERROR, "No file path for %s\n",
s->font);
goto fail;
}
- s->fontfile = av_strdup(fc_string);
- if (!s->fontfile)
- err = AVERROR(ENOMEM);
- else
- err = 0;
+ av_log(ctx, AV_LOG_INFO, "Using \"%s\"\n", filename);
+ if (!s->fontsize)
+ s->fontsize = size + 0.5;
+ err = load_font_file(ctx, filename, index);
+ if (err)
+ return err;
+ FcConfigDestroy(fontconfig);
fail:
FcPatternDestroy(best);
return err;
+}
+#endif
+
+static int load_font(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ int err;
+
+ /* load the face, and set up the encoding, which is by default UTF-8 */
+ err = load_font_file(ctx, s->fontfile, 0);
+ if (!err)
+ return 0;
+#if CONFIG_LIBFONTCONFIG
+ err = load_font_fontconfig(ctx);
+ if (!err)
+ return 0;
#endif
+ return err;
+}
+
+static int load_textfile(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ int err;
+ uint8_t *textbuf;
+ uint8_t *tmp;
+ size_t textbuf_size;
+
+ if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "The text file '%s' could not be read or is empty\n",
+ s->textfile);
+ return err;
+ }
+
+ if (textbuf_size > SIZE_MAX - 1 || !(tmp = av_realloc(s->text, textbuf_size + 1))) {
+ av_file_unmap(textbuf, textbuf_size);
+ return AVERROR(ENOMEM);
+ }
+ s->text = tmp;
+ memcpy(s->text, textbuf, textbuf_size);
+ s->text[textbuf_size] = 0;
+ av_file_unmap(textbuf, textbuf_size);
+
+ return 0;
+}
+
+static inline int is_newline(uint32_t c)
+{
+ return c == '\n' || c == '\r' || c == '\f' || c == '\v';
}
+#if CONFIG_LIBFRIBIDI
+static int shape_text(AVFilterContext *ctx)
+{
+ DrawTextContext *s = ctx->priv;
+ uint8_t *tmp;
+ int ret = AVERROR(ENOMEM);
+ static const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT |
+ FRIBIDI_FLAGS_ARABIC;
+ FriBidiChar *unicodestr = NULL;
+ FriBidiStrIndex len;
+ FriBidiParType direction = FRIBIDI_PAR_LTR;
+ FriBidiStrIndex line_start = 0;
+ FriBidiStrIndex line_end = 0;
+ FriBidiLevel *embedding_levels = NULL;
+ FriBidiArabicProp *ar_props = NULL;
+ FriBidiCharType *bidi_types = NULL;
+ FriBidiStrIndex i,j;
+
+ len = strlen(s->text);
+ if (!(unicodestr = av_malloc_array(len, sizeof(*unicodestr)))) {
+ goto out;
+ }
+ len = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8,
+ s->text, len, unicodestr);
+
+ bidi_types = av_malloc_array(len, sizeof(*bidi_types));
+ if (!bidi_types) {
+ goto out;
+ }
+
+ fribidi_get_bidi_types(unicodestr, len, bidi_types);
+
+ embedding_levels = av_malloc_array(len, sizeof(*embedding_levels));
+ if (!embedding_levels) {
+ goto out;
+ }
+
+ if (!fribidi_get_par_embedding_levels(bidi_types, len, &direction,
+ embedding_levels)) {
+ goto out;
+ }
+
+ ar_props = av_malloc_array(len, sizeof(*ar_props));
+ if (!ar_props) {
+ goto out;
+ }
+
+ fribidi_get_joining_types(unicodestr, len, ar_props);
+ fribidi_join_arabic(bidi_types, len, embedding_levels, ar_props);
+ fribidi_shape(flags, embedding_levels, len, ar_props, unicodestr);
+
+ for (line_end = 0, line_start = 0; line_end < len; line_end++) {
+ if (is_newline(unicodestr[line_end]) || line_end == len - 1) {
+ if (!fribidi_reorder_line(flags, bidi_types,
+ line_end - line_start + 1, line_start,
+ direction, embedding_levels, unicodestr,
+ NULL)) {
+ goto out;
+ }
+ line_start = line_end + 1;
+ }
+ }
+
+ /* Remove zero-width fill chars put in by libfribidi */
+ for (i = 0, j = 0; i < len; i++)
+ if (unicodestr[i] != FRIBIDI_CHAR_FILL)
+ unicodestr[j++] = unicodestr[i];
+ len = j;
+
+ if (!(tmp = av_realloc(s->text, (len * 4 + 1) * sizeof(*s->text)))) {
+ /* Use len * 4, as a unicode character can be up to 4 bytes in UTF-8 */
+ goto out;
+ }
+
+ s->text = tmp;
+ len = fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8,
+ unicodestr, len, s->text);
+ ret = 0;
+
+out:
+ av_free(unicodestr);
+ av_free(embedding_levels);
+ av_free(ar_props);
+ av_free(bidi_types);
+ return ret;
+}
+#endif
+
static av_cold int init(AVFilterContext *ctx)
{
int err;
DrawTextContext *s = ctx->priv;
Glyph *glyph;
- if ((err = parse_font(ctx)) < 0)
- return err;
+ if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
+ av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
+ return AVERROR(EINVAL);
+ }
if (s->textfile) {
- uint8_t *textbuf;
- size_t textbuf_size;
-
if (s->text) {
av_log(ctx, AV_LOG_ERROR,
"Both text and text file provided. Please provide only one\n");
return AVERROR(EINVAL);
}
- if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
- av_log(ctx, AV_LOG_ERROR,
- "The text file '%s' could not be read or is empty\n",
- s->textfile);
+ if ((err = load_textfile(ctx)) < 0)
return err;
- }
-
- if (textbuf_size > SIZE_MAX - 1 ||
- !(s->text = av_malloc(textbuf_size + 1))) {
- av_file_unmap(textbuf, textbuf_size);
- return AVERROR(ENOMEM);
- }
- memcpy(s->text, textbuf, textbuf_size);
- s->text[textbuf_size] = 0;
- av_file_unmap(textbuf, textbuf_size);
}
- if (!s->text) {
- av_log(ctx, AV_LOG_ERROR,
- "Either text or a valid file must be provided\n");
- return AVERROR(EINVAL);
- }
+#if CONFIG_LIBFRIBIDI
+ if (s->text_shaping)
+ if ((err = shape_text(ctx)) < 0)
+ return err;
+#endif
- if ((err = av_parse_color(s->fontcolor_rgba, s->fontcolor_string, -1, ctx))) {
- av_log(ctx, AV_LOG_ERROR,
- "Invalid font color '%s'\n", s->fontcolor_string);
- return err;
- }
+ if (s->reload && !s->textfile)
+ av_log(ctx, AV_LOG_WARNING, "No file to reload\n");
- if ((err = av_parse_color(s->boxcolor_rgba, s->boxcolor_string, -1, ctx))) {
- av_log(ctx, AV_LOG_ERROR,
- "Invalid box color '%s'\n", s->boxcolor_string);
- return err;
+ if (s->tc_opt_string) {
+ int ret = av_timecode_init_from_string(&s->tc, s->tc_rate,
+ s->tc_opt_string, ctx);
+ if (ret < 0)
+ return ret;
+ if (s->tc24hmax)
+ s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX;
+ if (!s->text)
+ s->text = av_strdup("");
}
- if ((err = av_parse_color(s->shadowcolor_rgba, s->shadowcolor_string, -1, ctx))) {
+ if (!s->text) {
av_log(ctx, AV_LOG_ERROR,
- "Invalid shadow color '%s'\n", s->shadowcolor_string);
- return err;
+ "Either text, a valid file or a timecode must be provided\n");
+ return AVERROR(EINVAL);
}
if ((err = FT_Init_FreeType(&(s->library)))) {
@@ -443,55 +642,59 @@ static av_cold int init(AVFilterContext *ctx)
return AVERROR(EINVAL);
}
- /* load the face, and set up the encoding, which is by default UTF-8 */
- if ((err = FT_New_Face(s->library, s->fontfile, 0, &s->face))) {
- av_log(ctx, AV_LOG_ERROR, "Could not load fontface from file '%s': %s\n",
- s->fontfile, FT_ERRMSG(err));
- return AVERROR(EINVAL);
- }
+ err = load_font(ctx);
+ if (err)
+ return err;
+ if (!s->fontsize)
+ s->fontsize = 16;
if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) {
av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
s->fontsize, FT_ERRMSG(err));
return AVERROR(EINVAL);
}
+ if (s->borderw) {
+ if (FT_Stroker_New(s->library, &s->stroker)) {
+ av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
+ return AVERROR_EXTERNAL;
+ }
+ FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
+ FT_STROKER_LINEJOIN_ROUND, 0);
+ }
+
s->use_kerning = FT_HAS_KERNING(s->face);
/* load the fallback glyph with code 0 */
load_glyph(ctx, NULL, 0);
/* set the tabsize in pixels */
- if ((err = load_glyph(ctx, &glyph, ' ') < 0)) {
+ if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
return err;
}
s->tabsize *= glyph->advance;
-#if !HAVE_LOCALTIME_R
- av_log(ctx, AV_LOG_WARNING, "strftime() expansion unavailable!\n");
-#endif
+ if (s->exp_mode == EXP_STRFTIME &&
+ (strchr(s->text, '%') || strchr(s->text, '\\')))
+ av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");
+
+ av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);
return 0;
}
static int query_formats(AVFilterContext *ctx)
{
- static const enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
- AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P,
- AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P,
- AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P,
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
}
static int glyph_enu_free(void *opaque, void *elem)
{
+ Glyph *glyph = elem;
+
+ FT_Done_Glyph(glyph->glyph);
+ FT_Done_Glyph(glyph->border_glyph);
av_free(elem);
return 0;
}
@@ -499,332 +702,373 @@ static int glyph_enu_free(void *opaque, void *elem)
static av_cold void uninit(AVFilterContext *ctx)
{
DrawTextContext *s = ctx->priv;
- int i;
av_expr_free(s->x_pexpr);
av_expr_free(s->y_pexpr);
- av_expr_free(s->d_pexpr);
- s->x_pexpr = s->y_pexpr = s->d_pexpr = NULL;
- av_freep(&s->expanded_text);
+ s->x_pexpr = s->y_pexpr = NULL;
av_freep(&s->positions);
+ s->nb_positions = 0;
+
+
av_tree_enumerate(s->glyphs, NULL, NULL, glyph_enu_free);
av_tree_destroy(s->glyphs);
- s->glyphs = 0;
+ s->glyphs = NULL;
+
FT_Done_Face(s->face);
+ FT_Stroker_Done(s->stroker);
FT_Done_FreeType(s->library);
- for (i = 0; i < 4; i++) {
- av_freep(&s->box_line[i]);
- s->pixel_step[i] = 0;
- }
-
-}
-
-static inline int is_newline(uint32_t c)
-{
- return c == '\n' || c == '\r' || c == '\f' || c == '\v';
+ av_bprint_finalize(&s->expanded_text, NULL);
+ av_bprint_finalize(&s->expanded_fontcolor, NULL);
}
-static int dtext_prepare_text(AVFilterContext *ctx)
+static int config_input(AVFilterLink *inlink)
{
+ AVFilterContext *ctx = inlink->dst;
DrawTextContext *s = ctx->priv;
- uint32_t code = 0, prev_code = 0;
- int x = 0, y = 0, i = 0, ret;
- int text_height, baseline;
- char *text = s->text;
- uint8_t *p;
- int str_w = 0, len;
- int y_min = 32000, y_max = -32000;
- FT_Vector delta;
- Glyph *glyph = NULL, *prev_glyph = NULL;
- Glyph dummy = { 0 };
- int width = ctx->inputs[0]->w;
- int height = ctx->inputs[0]->h;
- time_t now = time(0);
- struct tm ltime;
- uint8_t *buf = s->expanded_text;
- int buf_size = s->expanded_text_size;
+ int ret;
- if (!buf)
- buf_size = 2*strlen(s->text)+1;
+ ff_draw_init(&s->dc, inlink->format, 0);
+ ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
+ ff_draw_color(&s->dc, &s->shadowcolor, s->shadowcolor.rgba);
+ ff_draw_color(&s->dc, &s->bordercolor, s->bordercolor.rgba);
+ ff_draw_color(&s->dc, &s->boxcolor, s->boxcolor.rgba);
+
+ s->var_values[VAR_w] = s->var_values[VAR_W] = s->var_values[VAR_MAIN_W] = inlink->w;
+ s->var_values[VAR_h] = s->var_values[VAR_H] = s->var_values[VAR_MAIN_H] = inlink->h;
+ s->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ? av_q2d(inlink->sample_aspect_ratio) : 1;
+ s->var_values[VAR_DAR] = (double)inlink->w / inlink->h * s->var_values[VAR_SAR];
+ s->var_values[VAR_HSUB] = 1 << s->dc.hsub_max;
+ s->var_values[VAR_VSUB] = 1 << s->dc.vsub_max;
+ s->var_values[VAR_X] = NAN;
+ s->var_values[VAR_Y] = NAN;
+ s->var_values[VAR_T] = NAN;
- localtime_r(&now, &ltime);
+ av_lfg_init(&s->prng, av_get_random_seed());
- while ((buf = av_realloc(buf, buf_size))) {
- *buf = 1;
- if (strftime(buf, buf_size, s->text, &ltime) != 0 || *buf == 0)
- break;
- buf_size *= 2;
- }
+ av_expr_free(s->x_pexpr);
+ av_expr_free(s->y_pexpr);
+ s->x_pexpr = s->y_pexpr = NULL;
- if (!buf)
- return AVERROR(ENOMEM);
- text = s->expanded_text = buf;
- s->expanded_text_size = buf_size;
-
- if ((len = strlen(text)) > s->nb_positions) {
- FT_Vector *p = av_realloc(s->positions,
- len * sizeof(*s->positions));
- if (!p) {
- av_freep(s->positions);
- s->nb_positions = 0;
- return AVERROR(ENOMEM);
- } else {
- s->positions = p;
- s->nb_positions = len;
- }
- }
+ if ((ret = av_expr_parse(&s->x_pexpr, s->x_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
+ (ret = av_expr_parse(&s->y_pexpr, s->y_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
+ (ret = av_expr_parse(&s->a_pexpr, s->a_expr, var_names,
+ NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
- /* load and cache glyphs */
- for (i = 0, p = text; *p; i++) {
- GET_UTF8(code, *p++, continue;);
+ return AVERROR(EINVAL);
- /* get glyph */
- dummy.code = code;
- glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
- if (!glyph) {
- ret = load_glyph(ctx, &glyph, code);
- if (ret)
- return ret;
- }
+ return 0;
+}
- y_min = FFMIN(glyph->bbox.yMin, y_min);
- y_max = FFMAX(glyph->bbox.yMax, y_max);
+static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
+{
+ DrawTextContext *s = ctx->priv;
+
+ if (!strcmp(cmd, "reinit")) {
+ int ret;
+ uninit(ctx);
+ s->reinit = 1;
+ if ((ret = av_set_options_string(ctx, arg, "=", ":")) < 0)
+ return ret;
+ if ((ret = init(ctx)) < 0)
+ return ret;
+ return config_input(ctx->inputs[0]);
}
- text_height = y_max - y_min;
- baseline = y_max;
- /* compute and save position for each glyph */
- glyph = NULL;
- for (i = 0, p = text; *p; i++) {
- GET_UTF8(code, *p++, continue;);
+ return AVERROR(ENOSYS);
+}
- /* skip the \n in the sequence \r\n */
- if (prev_code == '\r' && code == '\n')
- continue;
+static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
- prev_code = code;
- if (is_newline(code)) {
- str_w = FFMAX(str_w, x - s->x);
- y += text_height;
- x = 0;
- continue;
- }
+ av_bprintf(bp, "%c", av_get_picture_type_char(s->var_values[VAR_PICT_TYPE]));
+ return 0;
+}
- /* get glyph */
- prev_glyph = glyph;
- dummy.code = code;
- glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
+static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
+ const char *fmt;
+ double pts = s->var_values[VAR_T];
+ int ret;
- /* kerning */
- if (s->use_kerning && prev_glyph && glyph->code) {
- FT_Get_Kerning(s->face, prev_glyph->code, glyph->code,
- ft_kerning_default, &delta);
- x += delta.x >> 6;
+ fmt = argc >= 1 ? argv[0] : "flt";
+ if (argc >= 2) {
+ int64_t delta;
+ if ((ret = av_parse_time(&delta, argv[1], 1)) < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid delta '%s'\n", argv[1]);
+ return ret;
}
-
- if (x + glyph->bbox.xMax >= width) {
- str_w = FFMAX(str_w, x);
- y += text_height;
- x = 0;
+ pts += (double)delta / AV_TIME_BASE;
+ }
+ if (!strcmp(fmt, "flt")) {
+ av_bprintf(bp, "%.6f", s->var_values[VAR_T]);
+ } else if (!strcmp(fmt, "hms")) {
+ if (isnan(pts)) {
+ av_bprintf(bp, " ??:??:??.???");
+ } else {
+ int64_t ms = round(pts * 1000);
+ char sign = ' ';
+ if (ms < 0) {
+ sign = '-';
+ ms = -ms;
+ }
+ av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign,
+ (int)(ms / (60 * 60 * 1000)),
+ (int)(ms / (60 * 1000)) % 60,
+ (int)(ms / 1000) % 60,
+ (int)ms % 1000);
}
-
- /* save position */
- s->positions[i].x = x + glyph->bitmap_left;
- s->positions[i].y = y - glyph->bitmap_top + baseline;
- if (code == '\t') x = (x / s->tabsize + 1)*s->tabsize;
- else x += glyph->advance;
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Invalid format '%s'\n", fmt);
+ return AVERROR(EINVAL);
}
+ return 0;
+}
- str_w = FFMIN(width - 1, FFMAX(str_w, x));
- y = FFMIN(y + text_height, height - 1);
+static int func_frame_num(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
+
+ av_bprintf(bp, "%d", (int)s->var_values[VAR_N]);
+ return 0;
+}
- s->w = str_w;
- s->var_values[VAR_TEXT_W] = s->var_values[VAR_TW] = s->w;
- s->h = y;
- s->var_values[VAR_TEXT_H] = s->var_values[VAR_TH] = s->h;
+static int func_metadata(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
+ AVDictionaryEntry *e = av_dict_get(s->metadata, argv[0], NULL, 0);
+ if (e && e->value)
+ av_bprintf(bp, "%s", e->value);
return 0;
}
+static int func_strftime(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ const char *fmt = argc ? argv[0] : "%Y-%m-%d %H:%M:%S";
+ time_t now;
+ struct tm tm;
-static int config_input(AVFilterLink *inlink)
+ time(&now);
+ if (tag == 'L')
+ localtime_r(&now, &tm);
+ else
+ tm = *gmtime_r(&now, &tm);
+ av_bprint_strftime(bp, fmt, &tm);
+ return 0;
+}
+
+static int func_eval_expr(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
{
- AVFilterContext *ctx = inlink->dst;
DrawTextContext *s = ctx->priv;
- const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+ double res;
int ret;
- s->hsub = pix_desc->log2_chroma_w;
- s->vsub = pix_desc->log2_chroma_h;
+ ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
+ NULL, NULL, fun2_names, fun2,
+ &s->prng, 0, ctx);
+ if (ret < 0)
+ av_log(ctx, AV_LOG_ERROR,
+ "Expression '%s' for the expr text expansion function is not valid\n",
+ argv[0]);
+ else
+ av_bprintf(bp, "%f", res);
- s->var_values[VAR_E ] = M_E;
- s->var_values[VAR_PHI] = M_PHI;
- s->var_values[VAR_PI ] = M_PI;
+ return ret;
+}
- s->var_values[VAR_MAIN_W] =
- s->var_values[VAR_MW] = ctx->inputs[0]->w;
- s->var_values[VAR_MAIN_H] =
- s->var_values[VAR_MH] = ctx->inputs[0]->h;
+static int func_eval_expr_int_format(AVFilterContext *ctx, AVBPrint *bp,
+ char *fct, unsigned argc, char **argv, int tag)
+{
+ DrawTextContext *s = ctx->priv;
+ double res;
+ int intval;
+ int ret;
+ unsigned int positions = 0;
+ char fmt_str[30] = "%";
+
+ /*
+ * argv[0] expression to be converted to `int`
+ * argv[1] format: 'x', 'X', 'd' or 'u'
+ * argv[2] positions printed (optional)
+ */
+
+ ret = av_expr_parse_and_eval(&res, argv[0], var_names, s->var_values,
+ NULL, NULL, fun2_names, fun2,
+ &s->prng, 0, ctx);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Expression '%s' for the expr text expansion function is not valid\n",
+ argv[0]);
+ return ret;
+ }
- s->var_values[VAR_X] = 0;
- s->var_values[VAR_Y] = 0;
- s->var_values[VAR_T] = NAN;
+ if (!strchr("xXdu", argv[1][0])) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid format '%c' specified,"
+ " allowed values: 'x', 'X', 'd', 'u'\n", argv[1][0]);
+ return AVERROR(EINVAL);
+ }
- av_lfg_init(&s->prng, av_get_random_seed());
+ if (argc == 3) {
+ ret = sscanf(argv[2], "%u", &positions);
+ if (ret != 1) {
+ av_log(ctx, AV_LOG_ERROR, "expr_int_format(): Invalid number of positions"
+ " to print: '%s'\n", argv[2]);
+ return AVERROR(EINVAL);
+ }
+ }
- av_expr_free(s->x_pexpr);
- av_expr_free(s->y_pexpr);
- av_expr_free(s->d_pexpr);
- s->x_pexpr = s->y_pexpr = s->d_pexpr = NULL;
- if ((ret = av_expr_parse(&s->x_pexpr, s->x_expr, var_names,
- NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
- (ret = av_expr_parse(&s->y_pexpr, s->y_expr, var_names,
- NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
- (ret = av_expr_parse(&s->d_pexpr, s->d_expr, var_names,
- NULL, NULL, fun2_names, fun2, 0, ctx)) < 0 ||
- (ret = av_expr_parse(&s->a_pexpr, s->a_expr, var_names,
- NULL, NULL, fun2_names, fun2, 0, ctx)) < 0)
+ feclearexcept(FE_ALL_EXCEPT);
+ intval = res;
+ if ((ret = fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW))) {
+ av_log(ctx, AV_LOG_ERROR, "Conversion of floating-point result to int failed. Control register: 0x%08x. Conversion result: %d\n", ret, intval);
return AVERROR(EINVAL);
+ }
- if ((ret =
- ff_fill_line_with_color(s->box_line, s->pixel_step,
- inlink->w, s->boxcolor,
- inlink->format, s->boxcolor_rgba,
- &s->is_packed_rgb, s->rgba_map)) < 0)
- return ret;
+ if (argc == 3)
+ av_strlcatf(fmt_str, sizeof(fmt_str), "0%u", positions);
+ av_strlcatf(fmt_str, sizeof(fmt_str), "%c", argv[1][0]);
- if (!s->is_packed_rgb) {
- uint8_t *rgba = s->fontcolor_rgba;
- s->fontcolor[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
- s->fontcolor[1] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
- s->fontcolor[2] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
- s->fontcolor[3] = rgba[3];
- rgba = s->shadowcolor_rgba;
- s->shadowcolor[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
- s->shadowcolor[1] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
- s->shadowcolor[2] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
- s->shadowcolor[3] = rgba[3];
- }
+ av_log(ctx, AV_LOG_DEBUG, "Formatting value %f (expr '%s') with spec '%s'\n",
+ res, argv[0], fmt_str);
- s->draw = 1;
+ av_bprintf(bp, fmt_str, intval);
- return dtext_prepare_text(ctx);
+ return 0;
}
-#define GET_BITMAP_VAL(r, c) \
- bitmap->pixel_mode == FT_PIXEL_MODE_MONO ? \
- (bitmap->buffer[(r) * bitmap->pitch + ((c)>>3)] & (0x80 >> ((c)&7))) * 255 : \
- bitmap->buffer[(r) * bitmap->pitch + (c)]
-
-#define SET_PIXEL_YUV(frame, yuva_color, val, x, y, hsub, vsub) { \
- luma_pos = ((x) ) + ((y) ) * frame->linesize[0]; \
- alpha = yuva_color[3] * alpha_mul * (val) * 129 / 255; \
- frame->data[0][luma_pos] = (alpha * yuva_color[0] + (255*255*129 - alpha) * frame->data[0][luma_pos] ) >> 23; \
- if (((x) & ((1<<(hsub)) - 1)) == 0 && ((y) & ((1<<(vsub)) - 1)) == 0) {\
- chroma_pos1 = ((x) >> (hsub)) + ((y) >> (vsub)) * frame->linesize[1]; \
- chroma_pos2 = ((x) >> (hsub)) + ((y) >> (vsub)) * frame->linesize[2]; \
- frame->data[1][chroma_pos1] = (alpha * yuva_color[1] + (255*255*129 - alpha) * frame->data[1][chroma_pos1]) >> 23; \
- frame->data[2][chroma_pos2] = (alpha * yuva_color[2] + (255*255*129 - alpha) * frame->data[2][chroma_pos2]) >> 23; \
- }\
-}
+static const struct drawtext_function {
+ const char *name;
+ unsigned argc_min, argc_max;
+ int tag; /**< opaque argument to func */
+ int (*func)(AVFilterContext *, AVBPrint *, char *, unsigned, char **, int);
+} functions[] = {
+ { "expr", 1, 1, 0, func_eval_expr },
+ { "e", 1, 1, 0, func_eval_expr },
+ { "expr_int_format", 2, 3, 0, func_eval_expr_int_format },
+ { "eif", 2, 3, 0, func_eval_expr_int_format },
+ { "pict_type", 0, 0, 0, func_pict_type },
+ { "pts", 0, 2, 0, func_pts },
+ { "gmtime", 0, 1, 'G', func_strftime },
+ { "localtime", 0, 1, 'L', func_strftime },
+ { "frame_num", 0, 0, 0, func_frame_num },
+ { "n", 0, 0, 0, func_frame_num },
+ { "metadata", 1, 1, 0, func_metadata },
+};
-static inline int draw_glyph_yuv(AVFrame *frame, FT_Bitmap *bitmap, unsigned int x,
- unsigned int y, unsigned int width, unsigned int height,
- const uint8_t yuva_color[4], int hsub, int vsub,
- int alpha_mul)
+static int eval_function(AVFilterContext *ctx, AVBPrint *bp, char *fct,
+ unsigned argc, char **argv)
{
- int r, c, alpha;
- unsigned int luma_pos, chroma_pos1, chroma_pos2;
- uint8_t src_val;
-
- for (r = 0; r < bitmap->rows && r+y < height; r++) {
- for (c = 0; c < bitmap->width && c+x < width; c++) {
- /* get intensity value in the glyph bitmap (source) */
- src_val = GET_BITMAP_VAL(r, c);
- if (!src_val)
- continue;
-
- SET_PIXEL_YUV(frame, yuva_color, src_val, c+x, y+r, hsub, vsub);
+ unsigned i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(functions); i++) {
+ if (strcmp(fct, functions[i].name))
+ continue;
+ if (argc < functions[i].argc_min) {
+ av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at least %d arguments\n",
+ fct, functions[i].argc_min);
+ return AVERROR(EINVAL);
}
+ if (argc > functions[i].argc_max) {
+ av_log(ctx, AV_LOG_ERROR, "%%{%s} requires at most %d arguments\n",
+ fct, functions[i].argc_max);
+ return AVERROR(EINVAL);
+ }
+ break;
}
-
- return 0;
-}
-
-#define SET_PIXEL_RGB(frame, rgba_color, val, x, y, pixel_step, r_off, g_off, b_off, a_off) { \
- p = frame->data[0] + (x) * pixel_step + ((y) * frame->linesize[0]); \
- alpha = rgba_color[3] * alpha_mul * (val) * 129 / 255; \
- *(p+r_off) = (alpha * rgba_color[0] + (255*255*129 - alpha) * *(p+r_off)) >> 23; \
- *(p+g_off) = (alpha * rgba_color[1] + (255*255*129 - alpha) * *(p+g_off)) >> 23; \
- *(p+b_off) = (alpha * rgba_color[2] + (255*255*129 - alpha) * *(p+b_off)) >> 23; \
+ if (i >= FF_ARRAY_ELEMS(functions)) {
+ av_log(ctx, AV_LOG_ERROR, "%%{%s} is not known\n", fct);
+ return AVERROR(EINVAL);
+ }
+ return functions[i].func(ctx, bp, fct, argc, argv, functions[i].tag);
}
-static inline int draw_glyph_rgb(AVFrame *frame, FT_Bitmap *bitmap,
- unsigned int x, unsigned int y,
- unsigned int width, unsigned int height, int pixel_step,
- const uint8_t rgba_color[4], const uint8_t rgba_map[4],
- int alpha_mul)
+static int expand_function(AVFilterContext *ctx, AVBPrint *bp, char **rtext)
{
- int r, c, alpha;
- uint8_t *p;
- uint8_t src_val;
-
- for (r = 0; r < bitmap->rows && r+y < height; r++) {
- for (c = 0; c < bitmap->width && c+x < width; c++) {
- /* get intensity value in the glyph bitmap (source) */
- src_val = GET_BITMAP_VAL(r, c);
- if (!src_val)
- continue;
+ const char *text = *rtext;
+ char *argv[16] = { NULL };
+ unsigned argc = 0, i;
+ int ret;
- SET_PIXEL_RGB(frame, rgba_color, src_val, c+x, y+r, pixel_step,
- rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
+ if (*text != '{') {
+ av_log(ctx, AV_LOG_ERROR, "Stray %% near '%s'\n", text);
+ return AVERROR(EINVAL);
+ }
+ text++;
+ while (1) {
+ if (!(argv[argc++] = av_get_token(&text, ":}"))) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ if (!*text) {
+ av_log(ctx, AV_LOG_ERROR, "Unterminated %%{} near '%s'\n", *rtext);
+ ret = AVERROR(EINVAL);
+ goto end;
}
+ if (argc == FF_ARRAY_ELEMS(argv))
+ av_freep(&argv[--argc]); /* error will be caught later */
+ if (*text == '}')
+ break;
+ text++;
}
- return 0;
+ if ((ret = eval_function(ctx, bp, argv[0], argc - 1, argv + 1)) < 0)
+ goto end;
+ ret = 0;
+ *rtext = (char *)text + 1;
+
+end:
+ for (i = 0; i < argc; i++)
+ av_freep(&argv[i]);
+ return ret;
}
-static inline void drawbox(AVFrame *frame, unsigned int x, unsigned int y,
- unsigned int width, unsigned int height,
- uint8_t *line[4], int pixel_step[4], uint8_t color[4],
- int hsub, int vsub, int is_rgba_packed, uint8_t rgba_map[4],
- int alpha_mul)
+static int expand_text(AVFilterContext *ctx, char *text, AVBPrint *bp)
{
- int i, j, alpha;
-
- if (color[3] != 0xFF || alpha_mul != 0xFF) {
- if (is_rgba_packed) {
- uint8_t *p;
- for (j = 0; j < height; j++)
- for (i = 0; i < width; i++)
- SET_PIXEL_RGB(frame, color, 255, i+x, y+j, pixel_step[0],
- rgba_map[0], rgba_map[1], rgba_map[2], rgba_map[3]);
+ int ret;
+
+ av_bprint_clear(bp);
+ while (*text) {
+ if (*text == '\\' && text[1]) {
+ av_bprint_chars(bp, text[1], 1);
+ text += 2;
+ } else if (*text == '%') {
+ text++;
+ if ((ret = expand_function(ctx, bp, &text)) < 0)
+ return ret;
} else {
- unsigned int luma_pos, chroma_pos1, chroma_pos2;
- for (j = 0; j < height; j++)
- for (i = 0; i < width; i++)
- SET_PIXEL_YUV(frame, color, 255, i+x, y+j, hsub, vsub);
+ av_bprint_chars(bp, *text, 1);
+ text++;
}
- } else {
- ff_draw_rectangle(frame->data, frame->linesize,
- line, pixel_step, hsub, vsub,
- x, y, width, height);
}
+ if (!av_bprint_is_complete(bp))
+ return AVERROR(ENOMEM);
+ return 0;
}
static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
int width, int height,
- const uint8_t rgbcolor[4], const uint8_t yuvcolor[4],
- int x, int y)
+ FFDrawColor *color,
+ int x, int y, int borderw)
{
- char *text = HAVE_LOCALTIME_R ? s->expanded_text : s->text;
+ char *text = s->expanded_text.str;
uint32_t code = 0;
- int i;
+ int i, x1, y1;
uint8_t *p;
Glyph *glyph = NULL;
for (i = 0, p = text; *p; i++) {
+ FT_Bitmap bitmap;
Glyph dummy = { 0 };
GET_UTF8(code, *p++, continue;);
@@ -835,69 +1079,32 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
dummy.code = code;
glyph = av_tree_find(s->glyphs, &dummy, (void *)glyph_cmp, NULL);
+ bitmap = borderw ? glyph->border_bitmap : glyph->bitmap;
+
if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
return AVERROR(EINVAL);
- if (s->is_packed_rgb) {
- draw_glyph_rgb(frame, &glyph->bitmap,
- s->positions[i].x+x, s->positions[i].y+y, width, height,
- s->pixel_step[0], rgbcolor, s->rgba_map, s->alpha);
- } else {
- draw_glyph_yuv(frame, &glyph->bitmap,
- s->positions[i].x+x, s->positions[i].y+y, width, height,
- yuvcolor, s->hsub, s->vsub, s->alpha);
- }
- }
-
- return 0;
-}
-
-static int draw_text(AVFilterContext *ctx, AVFrame *frame,
- int width, int height)
-{
- DrawTextContext *s = ctx->priv;
- int ret;
+ x1 = s->positions[i].x+s->x+x - borderw;
+ y1 = s->positions[i].y+s->y+y - borderw;
- /* draw box */
- if (s->draw_box)
- drawbox(frame, s->x, s->y, s->w, s->h,
- s->box_line, s->pixel_step, s->boxcolor,
- s->hsub, s->vsub, s->is_packed_rgb,
- s->rgba_map, s->alpha);
-
- if (s->shadowx || s->shadowy) {
- if ((ret = draw_glyphs(s, frame, width, height,
- s->shadowcolor_rgba,
- s->shadowcolor,
- s->x + s->shadowx,
- s->y + s->shadowy)) < 0)
- return ret;
+ ff_blend_mask(&s->dc, color,
+ frame->data, frame->linesize, width, height,
+ bitmap.buffer, bitmap.pitch,
+ bitmap.width, bitmap.rows,
+ bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
+ 0, x1, y1);
}
- if ((ret = draw_glyphs(s, frame, width, height,
- s->fontcolor_rgba,
- s->fontcolor,
- s->x,
- s->y)) < 0)
- return ret;
-
return 0;
}
-static inline int normalize_double(int *n, double d)
-{
- int ret = 0;
- if (isnan(d)) {
- ret = AVERROR(EINVAL);
- } else if (d > INT_MAX || d < INT_MIN) {
- *n = d > INT_MAX ? INT_MAX : INT_MIN;
- ret = AVERROR(EINVAL);
- } else
- *n = round(d);
-
- return ret;
+static void update_color_with_alpha(DrawTextContext *s, FFDrawColor *color, const FFDrawColor incolor)
+{
+ *color = incolor;
+ color->rgba[3] = (color->rgba[3] * s->alpha) / 255;
+ ff_draw_color(&s->dc, color, color->rgba);
}
static void update_alpha(DrawTextContext *s)
@@ -915,66 +1122,237 @@ static void update_alpha(DrawTextContext *s)
s->alpha = 256 * alpha;
}
-static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+static int draw_text(AVFilterContext *ctx, AVFrame *frame,
+ int width, int height)
{
- AVFilterContext *ctx = inlink->dst;
DrawTextContext *s = ctx->priv;
- int ret = 0;
+ AVFilterLink *inlink = ctx->inputs[0];
- if ((ret = dtext_prepare_text(ctx)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Can't draw text\n");
- av_frame_free(&frame);
- return ret;
+ uint32_t code = 0, prev_code = 0;
+ int x = 0, y = 0, i = 0, ret;
+ int max_text_line_w = 0, len;
+ int box_w, box_h;
+ char *text;
+ uint8_t *p;
+ int y_min = 32000, y_max = -32000;
+ int x_min = 32000, x_max = -32000;
+ FT_Vector delta;
+ Glyph *glyph = NULL, *prev_glyph = NULL;
+ Glyph dummy = { 0 };
+
+ time_t now = time(0);
+ struct tm ltime;
+ AVBPrint *bp = &s->expanded_text;
+
+ FFDrawColor fontcolor;
+ FFDrawColor shadowcolor;
+ FFDrawColor bordercolor;
+ FFDrawColor boxcolor;
+
+ av_bprint_clear(bp);
+
+ if(s->basetime != AV_NOPTS_VALUE)
+ now= frame->pts*av_q2d(ctx->inputs[0]->time_base) + s->basetime/1000000;
+
+ switch (s->exp_mode) {
+ case EXP_NONE:
+ av_bprintf(bp, "%s", s->text);
+ break;
+ case EXP_NORMAL:
+ if ((ret = expand_text(ctx, s->text, &s->expanded_text)) < 0)
+ return ret;
+ break;
+ case EXP_STRFTIME:
+ localtime_r(&now, &ltime);
+ av_bprint_strftime(bp, s->text, &ltime);
+ break;
}
- s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
- NAN : frame->pts * av_q2d(inlink->time_base);
- s->var_values[VAR_X] =
- av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
- s->var_values[VAR_Y] =
- av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
- s->var_values[VAR_X] =
- av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
+ if (s->tc_opt_string) {
+ char tcbuf[AV_TIMECODE_STR_SIZE];
+ av_timecode_make_string(&s->tc, tcbuf, inlink->frame_count);
+ av_bprint_clear(bp);
+ av_bprintf(bp, "%s%s", s->text, tcbuf);
+ }
+
+ if (!av_bprint_is_complete(bp))
+ return AVERROR(ENOMEM);
+ text = s->expanded_text.str;
+ if ((len = s->expanded_text.len) > s->nb_positions) {
+ if (!(s->positions =
+ av_realloc(s->positions, len*sizeof(*s->positions))))
+ return AVERROR(ENOMEM);
+ s->nb_positions = len;
+ }
+
+ if (s->fontcolor_expr[0]) {
+ /* If expression is set, evaluate and replace the static value */
+ av_bprint_clear(&s->expanded_fontcolor);
+ if ((ret = expand_text(ctx, s->fontcolor_expr, &s->expanded_fontcolor)) < 0)
+ return ret;
+ if (!av_bprint_is_complete(&s->expanded_fontcolor))
+ return AVERROR(ENOMEM);
+ av_log(s, AV_LOG_DEBUG, "Evaluated fontcolor is '%s'\n", s->expanded_fontcolor.str);
+ ret = av_parse_color(s->fontcolor.rgba, s->expanded_fontcolor.str, -1, s);
+ if (ret)
+ return ret;
+ ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
+ }
+
+ x = 0;
+ y = 0;
+
+ /* load and cache glyphs */
+ for (i = 0, p = text; *p; i++) {
+ GET_UTF8(code, *p++, continue;);
+
+ /* get glyph */
+ dummy.code = code;
+ glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
+ if (!glyph) {
+ load_glyph(ctx, &glyph, code);
+ }
+
+ y_min = FFMIN(glyph->bbox.yMin, y_min);
+ y_max = FFMAX(glyph->bbox.yMax, y_max);
+ x_min = FFMIN(glyph->bbox.xMin, x_min);
+ x_max = FFMAX(glyph->bbox.xMax, x_max);
+ }
+ s->max_glyph_h = y_max - y_min;
+ s->max_glyph_w = x_max - x_min;
+
+ /* compute and save position for each glyph */
+ glyph = NULL;
+ for (i = 0, p = text; *p; i++) {
+ GET_UTF8(code, *p++, continue;);
+
+ /* skip the \n in the sequence \r\n */
+ if (prev_code == '\r' && code == '\n')
+ continue;
+
+ prev_code = code;
+ if (is_newline(code)) {
- s->draw = av_expr_eval(s->d_pexpr, s->var_values, &s->prng);
+ max_text_line_w = FFMAX(max_text_line_w, x);
+ y += s->max_glyph_h;
+ x = 0;
+ continue;
+ }
+
+ /* get glyph */
+ prev_glyph = glyph;
+ dummy.code = code;
+ glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
+
+ /* kerning */
+ if (s->use_kerning && prev_glyph && glyph->code) {
+ FT_Get_Kerning(s->face, prev_glyph->code, glyph->code,
+ ft_kerning_default, &delta);
+ x += delta.x >> 6;
+ }
+
+ /* save position */
+ s->positions[i].x = x + glyph->bitmap_left;
+ s->positions[i].y = y - glyph->bitmap_top + y_max;
+ if (code == '\t') x = (x / s->tabsize + 1)*s->tabsize;
+ else x += glyph->advance;
+ }
+
+ max_text_line_w = FFMAX(x, max_text_line_w);
+
+ s->var_values[VAR_TW] = s->var_values[VAR_TEXT_W] = max_text_line_w;
+ s->var_values[VAR_TH] = s->var_values[VAR_TEXT_H] = y + s->max_glyph_h;
+
+ s->var_values[VAR_MAX_GLYPH_W] = s->max_glyph_w;
+ s->var_values[VAR_MAX_GLYPH_H] = s->max_glyph_h;
+ s->var_values[VAR_MAX_GLYPH_A] = s->var_values[VAR_ASCENT ] = y_max;
+ s->var_values[VAR_MAX_GLYPH_D] = s->var_values[VAR_DESCENT] = y_min;
+
+ s->var_values[VAR_LINE_H] = s->var_values[VAR_LH] = s->max_glyph_h;
+
+ s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
+ s->y = s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, &s->prng);
+ s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng);
update_alpha(s);
+ update_color_with_alpha(s, &fontcolor , s->fontcolor );
+ update_color_with_alpha(s, &shadowcolor, s->shadowcolor);
+ update_color_with_alpha(s, &bordercolor, s->bordercolor);
+ update_color_with_alpha(s, &boxcolor , s->boxcolor );
+
+ box_w = FFMIN(width - 1 , max_text_line_w);
+ box_h = FFMIN(height - 1, y + s->max_glyph_h);
- normalize_double(&s->x, s->var_values[VAR_X]);
- normalize_double(&s->y, s->var_values[VAR_Y]);
+ /* draw box */
+ if (s->draw_box)
+ ff_blend_rectangle(&s->dc, &boxcolor,
+ frame->data, frame->linesize, width, height,
+ s->x - s->boxborderw, s->y - s->boxborderw,
+ box_w + s->boxborderw * 2, box_h + s->boxborderw * 2);
- if (s->fix_bounds) {
- if (s->x < 0) s->x = 0;
- if (s->y < 0) s->y = 0;
- if ((unsigned)s->x + (unsigned)s->w > inlink->w)
- s->x = inlink->w - s->w;
- if ((unsigned)s->y + (unsigned)s->h > inlink->h)
- s->y = inlink->h - s->h;
+ if (s->shadowx || s->shadowy) {
+ if ((ret = draw_glyphs(s, frame, width, height,
+ &shadowcolor, s->shadowx, s->shadowy, 0)) < 0)
+ return ret;
}
- s->x &= ~((1 << s->hsub) - 1);
- s->y &= ~((1 << s->vsub) - 1);
+ if (s->borderw) {
+ if ((ret = draw_glyphs(s, frame, width, height,
+ &bordercolor, 0, 0, s->borderw)) < 0)
+ return ret;
+ }
+ if ((ret = draw_glyphs(s, frame, width, height,
+ &fontcolor, 0, 0, 0)) < 0)
+ return ret;
- av_log(ctx, AV_LOG_TRACE, "n:%d t:%f x:%d y:%d x+w:%d y+h:%d\n",
- (int)s->var_values[VAR_N], s->var_values[VAR_T],
- s->x, s->y, s->x+s->w, s->y+s->h);
+ return 0;
+}
- if (s->draw)
- draw_text(inlink->dst, frame, frame->width, frame->height);
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ DrawTextContext *s = ctx->priv;
+ int ret;
+
+ if (s->reload) {
+ if ((ret = load_textfile(ctx)) < 0) {
+ av_frame_free(&frame);
+ return ret;
+ }
+#if CONFIG_LIBFRIBIDI
+ if (s->text_shaping)
+ if ((ret = shape_text(ctx)) < 0) {
+ av_frame_free(&frame);
+ return ret;
+ }
+#endif
+ }
+
+ s->var_values[VAR_N] = inlink->frame_count+s->start_number;
+ s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ?
+ NAN : frame->pts * av_q2d(inlink->time_base);
- s->var_values[VAR_N] += 1.0;
+ s->var_values[VAR_PICT_TYPE] = frame->pict_type;
+ s->metadata = av_frame_get_metadata(frame);
- return ff_filter_frame(inlink->dst->outputs[0], frame);
+ draw_text(ctx, frame, frame->width, frame->height);
+
+ av_log(ctx, AV_LOG_DEBUG, "n:%d t:%f text_w:%d text_h:%d x:%d y:%d\n",
+ (int)s->var_values[VAR_N], s->var_values[VAR_T],
+ (int)s->var_values[VAR_TEXT_W], (int)s->var_values[VAR_TEXT_H],
+ s->x, s->y);
+
+ return ff_filter_frame(outlink, frame);
}
static const AVFilterPad avfilter_vf_drawtext_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
- .config_props = config_input,
- .needs_writable = 1,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ .needs_writable = 1,
},
{ NULL }
};
@@ -995,7 +1373,8 @@ AVFilter ff_vf_drawtext = {
.init = init,
.uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_drawtext_inputs,
- .outputs = avfilter_vf_drawtext_outputs,
+ .inputs = avfilter_vf_drawtext_inputs,
+ .outputs = avfilter_vf_drawtext_outputs,
+ .process_command = command,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
new file mode 100644
index 0000000000..ac88e02a11
--- /dev/null
+++ b/libavfilter/vf_edgedetect.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2012-2014 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Edge detection filter
+ *
+ * @see https://en.wikipedia.org/wiki/Canny_edge_detector
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum FilterMode {
+ MODE_WIRES,
+ MODE_COLORMIX,
+ NB_MODE
+};
+
+struct plane_info {
+ uint8_t *tmpbuf;
+ uint16_t *gradients;
+ char *directions;
+};
+
+typedef struct {
+ const AVClass *class;
+ struct plane_info planes[3];
+ int nb_planes;
+ double low, high;
+ uint8_t low_u8, high_u8;
+ int mode;
+} EdgeDetectContext;
+
+#define OFFSET(x) offsetof(EdgeDetectContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption edgedetect_options[] = {
+ { "high", "set high threshold", OFFSET(high), AV_OPT_TYPE_DOUBLE, {.dbl=50/255.}, 0, 1, FLAGS },
+ { "low", "set low threshold", OFFSET(low), AV_OPT_TYPE_DOUBLE, {.dbl=20/255.}, 0, 1, FLAGS },
+ { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_WIRES}, 0, NB_MODE-1, FLAGS, "mode" },
+ { "wires", "white/gray wires on black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_WIRES}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "colormix", "mix colors", 0, AV_OPT_TYPE_CONST, {.i64=MODE_COLORMIX}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(edgedetect);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ EdgeDetectContext *edgedetect = ctx->priv;
+
+ edgedetect->low_u8 = edgedetect->low * 255. + .5;
+ edgedetect->high_u8 = edgedetect->high * 255. + .5;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ const EdgeDetectContext *edgedetect = ctx->priv;
+ static const enum AVPixelFormat wires_pix_fmts[] = {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE};
+ static const enum AVPixelFormat colormix_pix_fmts[] = {AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE};
+ AVFilterFormats *fmts_list;
+ const enum AVPixelFormat *pix_fmts = NULL;
+
+ if (edgedetect->mode == MODE_WIRES) {
+ pix_fmts = wires_pix_fmts;
+ } else if (edgedetect->mode == MODE_COLORMIX) {
+ pix_fmts = colormix_pix_fmts;
+ } else {
+ av_assert0(0);
+ }
+ fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ int p;
+ AVFilterContext *ctx = inlink->dst;
+ EdgeDetectContext *edgedetect = ctx->priv;
+
+ edgedetect->nb_planes = inlink->format == AV_PIX_FMT_GRAY8 ? 1 : 3;
+ for (p = 0; p < edgedetect->nb_planes; p++) {
+ struct plane_info *plane = &edgedetect->planes[p];
+
+ plane->tmpbuf = av_malloc(inlink->w * inlink->h);
+ plane->gradients = av_calloc(inlink->w * inlink->h, sizeof(*plane->gradients));
+ plane->directions = av_malloc(inlink->w * inlink->h);
+ if (!plane->tmpbuf || !plane->gradients || !plane->directions)
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+}
+
+static void gaussian_blur(AVFilterContext *ctx, int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+
+ memcpy(dst, src, w); dst += dst_linesize; src += src_linesize;
+ memcpy(dst, src, w); dst += dst_linesize; src += src_linesize;
+ for (j = 2; j < h - 2; j++) {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ for (i = 2; i < w - 2; i++) {
+ /* Gaussian mask of size 5x5 with sigma = 1.4 */
+ dst[i] = ((src[-2*src_linesize + i-2] + src[2*src_linesize + i-2]) * 2
+ + (src[-2*src_linesize + i-1] + src[2*src_linesize + i-1]) * 4
+ + (src[-2*src_linesize + i ] + src[2*src_linesize + i ]) * 5
+ + (src[-2*src_linesize + i+1] + src[2*src_linesize + i+1]) * 4
+ + (src[-2*src_linesize + i+2] + src[2*src_linesize + i+2]) * 2
+
+ + (src[ -src_linesize + i-2] + src[ src_linesize + i-2]) * 4
+ + (src[ -src_linesize + i-1] + src[ src_linesize + i-1]) * 9
+ + (src[ -src_linesize + i ] + src[ src_linesize + i ]) * 12
+ + (src[ -src_linesize + i+1] + src[ src_linesize + i+1]) * 9
+ + (src[ -src_linesize + i+2] + src[ src_linesize + i+2]) * 4
+
+ + src[i-2] * 5
+ + src[i-1] * 12
+ + src[i ] * 15
+ + src[i+1] * 12
+ + src[i+2] * 5) / 159;
+ }
+ dst[i ] = src[i ];
+ dst[i + 1] = src[i + 1];
+
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+ memcpy(dst, src, w); dst += dst_linesize; src += src_linesize;
+ memcpy(dst, src, w);
+}
+
+enum {
+ DIRECTION_45UP,
+ DIRECTION_45DOWN,
+ DIRECTION_HORIZONTAL,
+ DIRECTION_VERTICAL,
+};
+
+static int get_rounded_direction(int gx, int gy)
+{
+ /* reference angles:
+ * tan( pi/8) = sqrt(2)-1
+ * tan(3pi/8) = sqrt(2)+1
+ * Gy/Gx is the tangent of the angle (theta), so Gy/Gx is compared against
+ * <ref-angle>, or more simply Gy against <ref-angle>*Gx
+ *
+ * Gx and Gy bounds = [-1020;1020], using 16-bit arithmetic:
+ * round((sqrt(2)-1) * (1<<16)) = 27146
+ * round((sqrt(2)+1) * (1<<16)) = 158218
+ */
+ if (gx) {
+ int tanpi8gx, tan3pi8gx;
+
+ if (gx < 0)
+ gx = -gx, gy = -gy;
+ gy <<= 16;
+ tanpi8gx = 27146 * gx;
+ tan3pi8gx = 158218 * gx;
+ if (gy > -tan3pi8gx && gy < -tanpi8gx) return DIRECTION_45UP;
+ if (gy > -tanpi8gx && gy < tanpi8gx) return DIRECTION_HORIZONTAL;
+ if (gy > tanpi8gx && gy < tan3pi8gx) return DIRECTION_45DOWN;
+ }
+ return DIRECTION_VERTICAL;
+}
+
+static void sobel(int w, int h,
+ uint16_t *dst, int dst_linesize,
+ int8_t *dir, int dir_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+
+ for (j = 1; j < h - 1; j++) {
+ dst += dst_linesize;
+ dir += dir_linesize;
+ src += src_linesize;
+ for (i = 1; i < w - 1; i++) {
+ const int gx =
+ -1*src[-src_linesize + i-1] + 1*src[-src_linesize + i+1]
+ -2*src[ i-1] + 2*src[ i+1]
+ -1*src[ src_linesize + i-1] + 1*src[ src_linesize + i+1];
+ const int gy =
+ -1*src[-src_linesize + i-1] + 1*src[ src_linesize + i-1]
+ -2*src[-src_linesize + i ] + 2*src[ src_linesize + i ]
+ -1*src[-src_linesize + i+1] + 1*src[ src_linesize + i+1];
+
+ dst[i] = FFABS(gx) + FFABS(gy);
+ dir[i] = get_rounded_direction(gx, gy);
+ }
+ }
+}
+
+static void non_maximum_suppression(int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const int8_t *dir, int dir_linesize,
+ const uint16_t *src, int src_linesize)
+{
+ int i, j;
+
+#define COPY_MAXIMA(ay, ax, by, bx) do { \
+ if (src[i] > src[(ay)*src_linesize + i+(ax)] && \
+ src[i] > src[(by)*src_linesize + i+(bx)]) \
+ dst[i] = av_clip_uint8(src[i]); \
+} while (0)
+
+ for (j = 1; j < h - 1; j++) {
+ dst += dst_linesize;
+ dir += dir_linesize;
+ src += src_linesize;
+ for (i = 1; i < w - 1; i++) {
+ switch (dir[i]) {
+ case DIRECTION_45UP: COPY_MAXIMA( 1, -1, -1, 1); break;
+ case DIRECTION_45DOWN: COPY_MAXIMA(-1, -1, 1, 1); break;
+ case DIRECTION_HORIZONTAL: COPY_MAXIMA( 0, -1, 0, 1); break;
+ case DIRECTION_VERTICAL: COPY_MAXIMA(-1, 0, 1, 0); break;
+ }
+ }
+ }
+}
+
+static void double_threshold(int low, int high, int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w; i++) {
+ if (src[i] > high) {
+ dst[i] = src[i];
+ continue;
+ }
+
+ if ((!i || i == w - 1 || !j || j == h - 1) &&
+ src[i] > low &&
+ (src[-src_linesize + i-1] > high ||
+ src[-src_linesize + i ] > high ||
+ src[-src_linesize + i+1] > high ||
+ src[ i-1] > high ||
+ src[ i+1] > high ||
+ src[ src_linesize + i-1] > high ||
+ src[ src_linesize + i ] > high ||
+ src[ src_linesize + i+1] > high))
+ dst[i] = src[i];
+ else
+ dst[i] = 0;
+ }
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+}
+
+static void color_mix(int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize)
+{
+ int i, j;
+
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w; i++)
+ dst[i] = (dst[i] + src[i]) >> 1;
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ EdgeDetectContext *edgedetect = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int p, direct = 0;
+ AVFrame *out;
+
+ if (edgedetect->mode != MODE_COLORMIX && av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ for (p = 0; p < edgedetect->nb_planes; p++) {
+ struct plane_info *plane = &edgedetect->planes[p];
+ uint8_t *tmpbuf = plane->tmpbuf;
+ uint16_t *gradients = plane->gradients;
+ int8_t *directions = plane->directions;
+
+ /* gaussian filter to reduce noise */
+ gaussian_blur(ctx, inlink->w, inlink->h,
+ tmpbuf, inlink->w,
+ in->data[p], in->linesize[p]);
+
+ /* compute the 16-bits gradients and directions for the next step */
+ sobel(inlink->w, inlink->h,
+ gradients, inlink->w,
+ directions,inlink->w,
+ tmpbuf, inlink->w);
+
+ /* non_maximum_suppression() will actually keep & clip what's necessary and
+ * ignore the rest, so we need a clean output buffer */
+ memset(tmpbuf, 0, inlink->w * inlink->h);
+ non_maximum_suppression(inlink->w, inlink->h,
+ tmpbuf, inlink->w,
+ directions,inlink->w,
+ gradients, inlink->w);
+
+ /* keep high values, or low values surrounded by high values */
+ double_threshold(edgedetect->low_u8, edgedetect->high_u8,
+ inlink->w, inlink->h,
+ out->data[p], out->linesize[p],
+ tmpbuf, inlink->w);
+
+ if (edgedetect->mode == MODE_COLORMIX) {
+ color_mix(inlink->w, inlink->h,
+ out->data[p], out->linesize[p],
+ in->data[p], in->linesize[p]);
+ }
+ }
+
+ if (!direct)
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int p;
+ EdgeDetectContext *edgedetect = ctx->priv;
+
+ for (p = 0; p < edgedetect->nb_planes; p++) {
+ struct plane_info *plane = &edgedetect->planes[p];
+ av_freep(&plane->tmpbuf);
+ av_freep(&plane->gradients);
+ av_freep(&plane->directions);
+ }
+}
+
+static const AVFilterPad edgedetect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad edgedetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_edgedetect = {
+ .name = "edgedetect",
+ .description = NULL_IF_CONFIG_SMALL("Detect and draw edge."),
+ .priv_size = sizeof(EdgeDetectContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = edgedetect_inputs,
+ .outputs = edgedetect_outputs,
+ .priv_class = &edgedetect_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_elbg.c b/libavfilter/vf_elbg.c
new file mode 100644
index 0000000000..86560708af
--- /dev/null
+++ b/libavfilter/vf_elbg.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * video quantizer filter based on ELBG
+ */
+
+#include "libavcodec/elbg.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/random_seed.h"
+
+#include "avfilter.h"
+#include "drawutils.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct ColorContext {
+ const AVClass *class;
+ AVLFG lfg;
+ unsigned int lfg_seed;
+ int max_steps_nb;
+ int *codeword;
+ int codeword_length;
+ int *codeword_closest_codebook_idxs;
+ int *codebook;
+ int codebook_length;
+ const AVPixFmtDescriptor *pix_desc;
+ uint8_t rgba_map[4];
+} ELBGContext;
+
+#define OFFSET(x) offsetof(ELBGContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption elbg_options[] = {
+ { "codebook_length", "set codebook length", OFFSET(codebook_length), AV_OPT_TYPE_INT, { .i64 = 256 }, 1, INT_MAX, FLAGS },
+ { "l", "set codebook length", OFFSET(codebook_length), AV_OPT_TYPE_INT, { .i64 = 256 }, 1, INT_MAX, FLAGS },
+ { "nb_steps", "set max number of steps used to compute the mapping", OFFSET(max_steps_nb), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
+ { "n", "set max number of steps used to compute the mapping", OFFSET(max_steps_nb), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
+ { "seed", "set the random seed", OFFSET(lfg_seed), AV_OPT_TYPE_INT, {.i64 = -1}, -1, UINT32_MAX, FLAGS },
+ { "s", "set the random seed", OFFSET(lfg_seed), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT32_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(elbg);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ELBGContext *elbg = ctx->priv;
+
+ if (elbg->lfg_seed == -1)
+ elbg->lfg_seed = av_get_random_seed();
+
+ av_lfg_init(&elbg->lfg, elbg->lfg_seed);
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+#define NB_COMPONENTS 3
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ELBGContext *elbg = ctx->priv;
+
+ elbg->pix_desc = av_pix_fmt_desc_get(inlink->format);
+ elbg->codeword_length = inlink->w * inlink->h;
+ elbg->codeword = av_realloc_f(elbg->codeword, elbg->codeword_length,
+ NB_COMPONENTS * sizeof(*elbg->codeword));
+ if (!elbg->codeword)
+ return AVERROR(ENOMEM);
+
+ elbg->codeword_closest_codebook_idxs =
+ av_realloc_f(elbg->codeword_closest_codebook_idxs, elbg->codeword_length,
+ sizeof(*elbg->codeword_closest_codebook_idxs));
+ if (!elbg->codeword_closest_codebook_idxs)
+ return AVERROR(ENOMEM);
+
+ elbg->codebook = av_realloc_f(elbg->codebook, elbg->codebook_length,
+ NB_COMPONENTS * sizeof(*elbg->codebook));
+ if (!elbg->codebook)
+ return AVERROR(ENOMEM);
+
+ ff_fill_rgba_map(elbg->rgba_map, inlink->format);
+
+ return 0;
+}
+
+#define R 0
+#define G 1
+#define B 2
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ ELBGContext *elbg = inlink->dst->priv;
+ int i, j, k;
+ uint8_t *p, *p0;
+
+ const uint8_t r_idx = elbg->rgba_map[R];
+ const uint8_t g_idx = elbg->rgba_map[G];
+ const uint8_t b_idx = elbg->rgba_map[B];
+
+ /* build the codeword */
+ p0 = frame->data[0];
+ k = 0;
+ for (i = 0; i < inlink->h; i++) {
+ p = p0;
+ for (j = 0; j < inlink->w; j++) {
+ elbg->codeword[k++] = p[r_idx];
+ elbg->codeword[k++] = p[g_idx];
+ elbg->codeword[k++] = p[b_idx];
+ p += elbg->pix_desc->nb_components;
+ }
+ p0 += frame->linesize[0];
+ }
+
+ /* compute the codebook */
+ avpriv_init_elbg(elbg->codeword, NB_COMPONENTS, elbg->codeword_length,
+ elbg->codebook, elbg->codebook_length, elbg->max_steps_nb,
+ elbg->codeword_closest_codebook_idxs, &elbg->lfg);
+ avpriv_do_elbg(elbg->codeword, NB_COMPONENTS, elbg->codeword_length,
+ elbg->codebook, elbg->codebook_length, elbg->max_steps_nb,
+ elbg->codeword_closest_codebook_idxs, &elbg->lfg);
+
+ /* fill the output with the codebook values */
+ p0 = frame->data[0];
+
+ k = 0;
+ for (i = 0; i < inlink->h; i++) {
+ p = p0;
+ for (j = 0; j < inlink->w; j++) {
+ int cb_idx = NB_COMPONENTS * elbg->codeword_closest_codebook_idxs[k++];
+ p[r_idx] = elbg->codebook[cb_idx];
+ p[g_idx] = elbg->codebook[cb_idx+1];
+ p[b_idx] = elbg->codebook[cb_idx+2];
+ p += elbg->pix_desc->nb_components;
+ }
+ p0 += frame->linesize[0];
+ }
+
+ return ff_filter_frame(inlink->dst->outputs[0], frame);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ELBGContext *elbg = ctx->priv;
+
+ av_freep(&elbg->codebook);
+ av_freep(&elbg->codeword);
+ av_freep(&elbg->codeword_closest_codebook_idxs);
+}
+
+static const AVFilterPad elbg_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ .needs_writable = 1,
+ },
+ { NULL }
+};
+
+static const AVFilterPad elbg_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_elbg = {
+ .name = "elbg",
+ .description = NULL_IF_CONFIG_SMALL("Apply posterize effect, using the ELBG algorithm."),
+ .priv_size = sizeof(ELBGContext),
+ .priv_class = &elbg_class,
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .inputs = elbg_inputs,
+ .outputs = elbg_outputs,
+};
diff --git a/libavfilter/vf_eq.c b/libavfilter/vf_eq.c
new file mode 100644
index 0000000000..f8b816038d
--- /dev/null
+++ b/libavfilter/vf_eq.c
@@ -0,0 +1,388 @@
+/*
+ * Original MPlayer filters by Richard Felker, Hampa Hug, Daniel Moreno,
+ * and Michael Niedermeyer.
+ *
+ * Copyright (c) 2014 James Darnley <james.darnley@gmail.com>
+ * Copyright (c) 2015 Arwa Arif <arwaarif1994@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 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
+ * very simple video equalizer
+ */
+
+#include "libavfilter/internal.h"
+#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "vf_eq.h"
+
+static void create_lut(EQParameters *param)
+{
+ int i;
+ double g = 1.0 / param->gamma;
+ double lw = 1.0 - param->gamma_weight;
+
+ for (i = 0; i < 256; i++) {
+ double v = i / 255.0;
+ v = param->contrast * (v - 0.5) + 0.5 + param->brightness;
+
+ if (v <= 0.0) {
+ param->lut[i] = 0;
+ } else {
+ v = v * lw + pow(v, g) * param->gamma_weight;
+
+ if (v >= 1.0)
+ param->lut[i] = 255;
+ else
+ param->lut[i] = 256.0 * v;
+ }
+ }
+
+ param->lut_clean = 1;
+}
+
+static void apply_lut(EQParameters *param, uint8_t *dst, int dst_stride,
+ const uint8_t *src, int src_stride, int w, int h)
+{
+ int x, y;
+
+ if (!param->lut_clean)
+ create_lut(param);
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ dst[y * dst_stride + x] = param->lut[src[y * src_stride + x]];
+ }
+ }
+}
+
+static void process_c(EQParameters *param, uint8_t *dst, int dst_stride,
+ const uint8_t *src, int src_stride, int w, int h)
+{
+ int x, y, pel;
+
+ int contrast = (int) (param->contrast * 256 * 16);
+ int brightness = ((int) (100.0 * param->brightness + 100.0) * 511) / 200 - 128 - contrast / 32;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ pel = ((src[y * src_stride + x] * contrast) >> 12) + brightness;
+
+ if (pel & ~255)
+ pel = (-pel) >> 31;
+
+ dst[y * dst_stride + x] = pel;
+ }
+ }
+}
+
+static void check_values(EQParameters *param, EQContext *eq)
+{
+ if (param->contrast == 1.0 && param->brightness == 0.0 && param->gamma == 1.0)
+ param->adjust = NULL;
+ else if (param->gamma == 1.0)
+ param->adjust = eq->process;
+ else
+ param->adjust = apply_lut;
+}
+
+static void set_contrast(EQContext *eq)
+{
+ eq->contrast = av_clipf(av_expr_eval(eq->contrast_pexpr, eq->var_values, eq), -2.0, 2.0);
+ eq->param[0].contrast = eq->contrast;
+ eq->param[0].lut_clean = 0;
+ check_values(&eq->param[0], eq);
+}
+
+static void set_brightness(EQContext *eq)
+{
+ eq->brightness = av_clipf(av_expr_eval(eq->brightness_pexpr, eq->var_values, eq), -1.0, 1.0);
+ eq->param[0].brightness = eq->brightness;
+ eq->param[0].lut_clean = 0;
+ check_values(&eq->param[0], eq);
+}
+
+static void set_gamma(EQContext *eq)
+{
+ int i;
+
+ eq->gamma = av_clipf(av_expr_eval(eq->gamma_pexpr, eq->var_values, eq), 0.1, 10.0);
+ eq->gamma_r = av_clipf(av_expr_eval(eq->gamma_r_pexpr, eq->var_values, eq), 0.1, 10.0);
+ eq->gamma_g = av_clipf(av_expr_eval(eq->gamma_g_pexpr, eq->var_values, eq), 0.1, 10.0);
+ eq->gamma_b = av_clipf(av_expr_eval(eq->gamma_b_pexpr, eq->var_values, eq), 0.1, 10.0);
+ eq->gamma_weight = av_clipf(av_expr_eval(eq->gamma_weight_pexpr, eq->var_values, eq), 0.0, 1.0);
+
+ eq->param[0].gamma = eq->gamma * eq->gamma_g;
+ eq->param[1].gamma = sqrt(eq->gamma_b / eq->gamma_g);
+ eq->param[2].gamma = sqrt(eq->gamma_r / eq->gamma_g);
+
+ for (i = 0; i < 3; i++) {
+ eq->param[i].gamma_weight = eq->gamma_weight;
+ eq->param[i].lut_clean = 0;
+ check_values(&eq->param[i], eq);
+ }
+}
+
+static void set_saturation(EQContext *eq)
+{
+ int i;
+
+ eq->saturation = av_clipf(av_expr_eval(eq->saturation_pexpr, eq->var_values, eq), 0.0, 3.0);
+
+ for (i = 1; i < 3; i++) {
+ eq->param[i].contrast = eq->saturation;
+ eq->param[i].lut_clean = 0;
+ check_values(&eq->param[i], eq);
+ }
+}
+
+static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx)
+{
+ int ret;
+ AVExpr *old = NULL;
+
+ if (*pexpr)
+ old = *pexpr;
+ ret = av_expr_parse(pexpr, expr, var_names, NULL, NULL, NULL, NULL, 0, log_ctx);
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Error when parsing the expression '%s' for %s\n",
+ expr, option);
+ *pexpr = old;
+ return ret;
+ }
+
+ av_expr_free(old);
+ return 0;
+}
+
+static int initialize(AVFilterContext *ctx)
+{
+ EQContext *eq = ctx->priv;
+ int ret;
+
+ eq->process = process_c;
+
+ if ((ret = set_expr(&eq->contrast_pexpr, eq->contrast_expr, "contrast", ctx)) < 0 ||
+ (ret = set_expr(&eq->brightness_pexpr, eq->brightness_expr, "brightness", ctx)) < 0 ||
+ (ret = set_expr(&eq->saturation_pexpr, eq->saturation_expr, "saturation", ctx)) < 0 ||
+ (ret = set_expr(&eq->gamma_pexpr, eq->gamma_expr, "gamma", ctx)) < 0 ||
+ (ret = set_expr(&eq->gamma_r_pexpr, eq->gamma_r_expr, "gamma_r", ctx)) < 0 ||
+ (ret = set_expr(&eq->gamma_g_pexpr, eq->gamma_g_expr, "gamma_g", ctx)) < 0 ||
+ (ret = set_expr(&eq->gamma_b_pexpr, eq->gamma_b_expr, "gamma_b", ctx)) < 0 ||
+ (ret = set_expr(&eq->gamma_weight_pexpr, eq->gamma_weight_expr, "gamma_weight", ctx)) < 0 )
+ return ret;
+
+ if (ARCH_X86)
+ ff_eq_init_x86(eq);
+
+ if (eq->eval_mode == EVAL_MODE_INIT) {
+ set_gamma(eq);
+ set_contrast(eq);
+ set_brightness(eq);
+ set_saturation(eq);
+ }
+
+ return 0;
+}
+
+static void uninit(AVFilterContext *ctx)
+{
+ EQContext *eq = ctx->priv;
+
+ av_expr_free(eq->contrast_pexpr); eq->contrast_pexpr = NULL;
+ av_expr_free(eq->brightness_pexpr); eq->brightness_pexpr = NULL;
+ av_expr_free(eq->saturation_pexpr); eq->saturation_pexpr = NULL;
+ av_expr_free(eq->gamma_pexpr); eq->gamma_pexpr = NULL;
+ av_expr_free(eq->gamma_weight_pexpr); eq->gamma_weight_pexpr = NULL;
+ av_expr_free(eq->gamma_r_pexpr); eq->gamma_r_pexpr = NULL;
+ av_expr_free(eq->gamma_g_pexpr); eq->gamma_g_pexpr = NULL;
+ av_expr_free(eq->gamma_b_pexpr); eq->gamma_b_pexpr = NULL;
+}
+
+static int config_props(AVFilterLink *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);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pixel_fmts_eq[] = {
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pixel_fmts_eq);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ EQContext *eq = ctx->priv;
+ AVFrame *out;
+ int64_t pos = av_frame_get_pkt_pos(in);
+ const AVPixFmtDescriptor *desc;
+ int i;
+
+ out = ff_get_video_buffer(outlink, inlink->w, inlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+
+ av_frame_copy_props(out, in);
+ desc = av_pix_fmt_desc_get(inlink->format);
+
+ eq->var_values[VAR_N] = inlink->frame_count;
+ eq->var_values[VAR_POS] = pos == -1 ? NAN : pos;
+ eq->var_values[VAR_T] = TS2T(in->pts, inlink->time_base);
+
+ if (eq->eval_mode == EVAL_MODE_FRAME) {
+ set_gamma(eq);
+ set_contrast(eq);
+ set_brightness(eq);
+ set_saturation(eq);
+ }
+
+ for (i = 0; i < desc->nb_components; i++) {
+ int w = inlink->w;
+ int h = inlink->h;
+
+ if (i == 1 || i == 2) {
+ w = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
+ h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
+ }
+
+ if (eq->param[i].adjust)
+ eq->param[i].adjust(&eq->param[i], out->data[i], out->linesize[i],
+ in->data[i], in->linesize[i], w, h);
+ else
+ av_image_copy_plane(out->data[i], out->linesize[i],
+ in->data[i], in->linesize[i], w, h);
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static inline int set_param(AVExpr **pexpr, const char *args, const char *cmd,
+ void (*set_fn)(EQContext *eq), AVFilterContext *ctx)
+{
+ EQContext *eq = ctx->priv;
+ int ret;
+ if ((ret = set_expr(pexpr, args, cmd, ctx)) < 0)
+ return ret;
+ if (eq->eval_mode == EVAL_MODE_INIT)
+ set_fn(eq);
+ return 0;
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ EQContext *eq = ctx->priv;
+
+#define SET_PARAM(param_name, set_fn_name) \
+ if (!strcmp(cmd, #param_name)) return set_param(&eq->param_name##_pexpr, args, cmd, set_##set_fn_name, ctx);
+
+ SET_PARAM(contrast, contrast)
+ else SET_PARAM(brightness, brightness)
+ else SET_PARAM(saturation, saturation)
+ else SET_PARAM(gamma, gamma)
+ else SET_PARAM(gamma_r, gamma)
+ else SET_PARAM(gamma_g, gamma)
+ else SET_PARAM(gamma_b, gamma)
+ else SET_PARAM(gamma_weight, gamma)
+ else return AVERROR(ENOSYS);
+}
+
+static const AVFilterPad eq_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad eq_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+#define OFFSET(x) offsetof(EQContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption eq_options[] = {
+ { "contrast", "set the contrast adjustment, negative values give a negative image",
+ OFFSET(contrast_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "brightness", "set the brightness adjustment",
+ OFFSET(brightness_expr), AV_OPT_TYPE_STRING, {.str = "0.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "saturation", "set the saturation adjustment",
+ OFFSET(saturation_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "gamma", "set the initial gamma value",
+ OFFSET(gamma_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "gamma_r", "gamma value for red",
+ OFFSET(gamma_r_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "gamma_g", "gamma value for green",
+ OFFSET(gamma_g_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "gamma_b", "gamma value for blue",
+ OFFSET(gamma_b_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "gamma_weight", "set the gamma weight which reduces the effect of gamma on bright areas",
+ OFFSET(gamma_weight_expr), AV_OPT_TYPE_STRING, {.str = "1.0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
+ { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
+ { "frame", "eval expressions per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(eq);
+
+AVFilter ff_vf_eq = {
+ .name = "eq",
+ .description = NULL_IF_CONFIG_SMALL("Adjust brightness, contrast, gamma, and saturation."),
+ .priv_size = sizeof(EQContext),
+ .priv_class = &eq_class,
+ .inputs = eq_inputs,
+ .outputs = eq_outputs,
+ .process_command = process_command,
+ .query_formats = query_formats,
+ .init = initialize,
+ .uninit = uninit,
+};
diff --git a/libavfilter/vf_eq.h b/libavfilter/vf_eq.h
new file mode 100644
index 0000000000..8525048b3f
--- /dev/null
+++ b/libavfilter/vf_eq.h
@@ -0,0 +1,105 @@
+/*
+ * Original MPlayer filters by Richard Felker, Hampa Hug, Daniel Moreno,
+ * and Michael Niedermeyer.
+ *
+ * Copyright (c) 2014 James Darnley <james.darnley@gmail.com>
+ * Copyright (c) 2015 Arwa Arif <arwaarif1994@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 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.
+ */
+
+#ifndef AVFILTER_EQ_H
+#define AVFILTER_EQ_H
+
+#include "avfilter.h"
+#include "libavutil/eval.h"
+
+static const char *const var_names[] = {
+ "n", // frame count
+ "pos", // frame position
+ "r", // frame rate
+ "t", // timestamp expressed in seconds
+ NULL
+};
+
+enum var_name {
+ VAR_N,
+ VAR_POS,
+ VAR_R,
+ VAR_T,
+ VAR_NB
+};
+
+typedef struct EQParameters {
+ void (*adjust)(struct EQParameters *eq, uint8_t *dst, int dst_stride,
+ const uint8_t *src, int src_stride, int w, int h);
+
+ uint8_t lut[256];
+
+ double brightness, contrast, gamma, gamma_weight;
+ int lut_clean;
+
+} EQParameters;
+
+typedef struct {
+ const AVClass *class;
+
+ EQParameters param[3];
+
+ char *contrast_expr;
+ AVExpr *contrast_pexpr;
+ double contrast;
+
+ char *brightness_expr;
+ AVExpr *brightness_pexpr;
+ double brightness;
+
+ char *saturation_expr;
+ AVExpr *saturation_pexpr;
+ double saturation;
+
+ char *gamma_expr;
+ AVExpr *gamma_pexpr;
+ double gamma;
+
+ char *gamma_weight_expr;
+ AVExpr *gamma_weight_pexpr;
+ double gamma_weight;
+
+ char *gamma_r_expr;
+ AVExpr *gamma_r_pexpr;
+ double gamma_r;
+
+ char *gamma_g_expr;
+ AVExpr *gamma_g_pexpr;
+ double gamma_g;
+
+ char *gamma_b_expr;
+ AVExpr *gamma_b_pexpr;
+ double gamma_b;
+
+ double var_values[VAR_NB];
+
+ void (*process)(struct EQParameters *par, uint8_t *dst, int dst_stride,
+ const uint8_t *src, int src_stride, int w, int h);
+
+ enum EvalMode { EVAL_MODE_INIT, EVAL_MODE_FRAME, EVAL_MODE_NB } eval_mode;
+} EQContext;
+
+void ff_eq_init_x86(EQContext *eq);
+
+#endif /* AVFILTER_EQ_H */
diff --git a/libavfilter/vf_extractplanes.c b/libavfilter/vf_extractplanes.c
new file mode 100644
index 0000000000..b0fa1bb292
--- /dev/null
+++ b/libavfilter/vf_extractplanes.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "internal.h"
+
+#define PLANE_R 0x01
+#define PLANE_G 0x02
+#define PLANE_B 0x04
+#define PLANE_A 0x08
+#define PLANE_Y 0x10
+#define PLANE_U 0x20
+#define PLANE_V 0x40
+
+typedef struct {
+ const AVClass *class;
+ int requested_planes;
+ int map[4];
+ int linesize[4];
+ int is_packed_rgb;
+ int depth;
+ int step;
+} ExtractPlanesContext;
+
+#define OFFSET(x) offsetof(ExtractPlanesContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption extractplanes_options[] = {
+ { "planes", "set planes", OFFSET(requested_planes), AV_OPT_TYPE_FLAGS, {.i64=1}, 1, 0xff, FLAGS, "flags"},
+ { "y", "set luma plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_Y}, 0, 0, FLAGS, "flags"},
+ { "u", "set u plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_U}, 0, 0, FLAGS, "flags"},
+ { "v", "set v plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_V}, 0, 0, FLAGS, "flags"},
+ { "r", "set red plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_R}, 0, 0, FLAGS, "flags"},
+ { "g", "set green plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_G}, 0, 0, FLAGS, "flags"},
+ { "b", "set blue plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_B}, 0, 0, FLAGS, "flags"},
+ { "a", "set alpha plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_A}, 0, 0, FLAGS, "flags"},
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(extractplanes);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat in_pixfmts[] = {
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUVA420P16LE,
+ AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUVA420P16BE,
+ AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUVA422P16LE,
+ AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUVA422P16BE,
+ AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUVA444P16LE,
+ AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUVA444P16BE,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
+ AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_RGB48LE, AV_PIX_FMT_BGR48LE,
+ AV_PIX_FMT_RGB48BE, AV_PIX_FMT_BGR48BE,
+ AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_BGRA64LE,
+ AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_BGRA64BE,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_GBRP16LE, AV_PIX_FMT_GBRP16BE,
+ AV_PIX_FMT_GBRAP16LE, AV_PIX_FMT_GBRAP16BE,
+ AV_PIX_FMT_NONE,
+ };
+ static const enum AVPixelFormat out8_pixfmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
+ static const enum AVPixelFormat out16le_pixfmts[] = { AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_NONE };
+ static const enum AVPixelFormat out16be_pixfmts[] = { AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE };
+ const enum AVPixelFormat *out_pixfmts;
+ const AVPixFmtDescriptor *desc;
+ AVFilterFormats *avff;
+ int i, depth = 0, be = 0;
+
+ if (!ctx->inputs[0]->in_formats ||
+ !ctx->inputs[0]->in_formats->nb_formats) {
+ return AVERROR(EAGAIN);
+ }
+
+ if (!ctx->inputs[0]->out_formats)
+ ff_formats_ref(ff_make_format_list(in_pixfmts), &ctx->inputs[0]->out_formats);
+
+ avff = ctx->inputs[0]->in_formats;
+ desc = av_pix_fmt_desc_get(avff->formats[0]);
+ depth = desc->comp[0].depth_minus1;
+ be = desc->flags & AV_PIX_FMT_FLAG_BE;
+ for (i = 1; i < avff->nb_formats; i++) {
+ desc = av_pix_fmt_desc_get(avff->formats[i]);
+ if (depth != desc->comp[0].depth_minus1 ||
+ be != (desc->flags & AV_PIX_FMT_FLAG_BE)) {
+ return AVERROR(EAGAIN);
+ }
+ }
+
+ if (depth == 7)
+ out_pixfmts = out8_pixfmts;
+ else if (be)
+ out_pixfmts = out16be_pixfmts;
+ else
+ out_pixfmts = out16le_pixfmts;
+
+ for (i = 0; i < ctx->nb_outputs; i++)
+ ff_formats_ref(ff_make_format_list(out_pixfmts), &ctx->outputs[i]->in_formats);
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ExtractPlanesContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int plane_avail, ret, i;
+ uint8_t rgba_map[4];
+
+ plane_avail = ((desc->flags & AV_PIX_FMT_FLAG_RGB) ? PLANE_R|PLANE_G|PLANE_B :
+ PLANE_Y |
+ ((desc->nb_components > 2) ? PLANE_U|PLANE_V : 0)) |
+ ((desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? PLANE_A : 0);
+ if (s->requested_planes & ~plane_avail) {
+ av_log(ctx, AV_LOG_ERROR, "Requested planes not available.\n");
+ return AVERROR(EINVAL);
+ }
+ if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->depth = (desc->comp[0].depth_minus1 + 1) >> 3;
+ s->step = av_get_padded_bits_per_pixel(desc) >> 3;
+ s->is_packed_rgb = !(desc->flags & AV_PIX_FMT_FLAG_PLANAR);
+ if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
+ ff_fill_rgba_map(rgba_map, inlink->format);
+ for (i = 0; i < 4; i++)
+ s->map[i] = rgba_map[s->map[i]];
+ }
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ ExtractPlanesContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const int output = outlink->srcpad - ctx->output_pads;
+
+ if (s->map[output] == 1 || s->map[output] == 2) {
+ outlink->h = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ outlink->w = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
+ }
+
+ return 0;
+}
+
+static void extract_from_packed(uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize,
+ int width, int height,
+ int depth, int step, int comp)
+{
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ switch (depth) {
+ case 1:
+ for (x = 0; x < width; x++)
+ dst[x] = src[x * step + comp];
+ break;
+ case 2:
+ for (x = 0; x < width; x++) {
+ dst[x * 2 ] = src[x * step + comp * 2 ];
+ dst[x * 2 + 1] = src[x * step + comp * 2 + 1];
+ }
+ break;
+ }
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ExtractPlanesContext *s = ctx->priv;
+ int i, eof = 0, ret = 0;
+
+ for (i = 0; i < ctx->nb_outputs; i++) {
+ AVFilterLink *outlink = ctx->outputs[i];
+ const int idx = s->map[i];
+ AVFrame *out;
+
+ if (outlink->closed)
+ continue;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ ret = AVERROR(ENOMEM);
+ break;
+ }
+ av_frame_copy_props(out, frame);
+
+ if (s->is_packed_rgb) {
+ extract_from_packed(out->data[0], out->linesize[0],
+ frame->data[0], frame->linesize[0],
+ outlink->w, outlink->h,
+ s->depth,
+ s->step, idx);
+ } else {
+ av_image_copy_plane(out->data[0], out->linesize[0],
+ frame->data[idx], frame->linesize[idx],
+ s->linesize[idx], outlink->h);
+ }
+
+ ret = ff_filter_frame(outlink, out);
+ if (ret == AVERROR_EOF)
+ eof++;
+ else if (ret < 0)
+ break;
+ }
+ av_frame_free(&frame);
+
+ if (eof == ctx->nb_outputs)
+ ret = AVERROR_EOF;
+ else if (ret == AVERROR_EOF)
+ ret = 0;
+ return ret;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ExtractPlanesContext *s = ctx->priv;
+ int planes = (s->requested_planes & 0xf) | (s->requested_planes >> 4);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ char *name;
+ AVFilterPad pad = { 0 };
+
+ if (!(planes & (1 << i)))
+ continue;
+
+ name = av_asprintf("out%d", ctx->nb_outputs);
+ if (!name)
+ return AVERROR(ENOMEM);
+ s->map[ctx->nb_outputs] = i;
+ pad.name = name;
+ pad.type = AVMEDIA_TYPE_VIDEO;
+ pad.config_props = config_output;
+
+ ff_insert_outpad(ctx, ctx->nb_outputs, &pad);
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->nb_outputs; i++)
+ av_freep(&ctx->output_pads[i].name);
+}
+
+static const AVFilterPad extractplanes_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_extractplanes = {
+ .name = "extractplanes",
+ .description = NULL_IF_CONFIG_SMALL("Extract planes as grayscale frames."),
+ .priv_size = sizeof(ExtractPlanesContext),
+ .priv_class = &extractplanes_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = extractplanes_inputs,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
+
+#if CONFIG_ALPHAEXTRACT_FILTER
+
+static av_cold int init_alphaextract(AVFilterContext *ctx)
+{
+ ExtractPlanesContext *s = ctx->priv;
+
+ s->requested_planes = PLANE_A;
+
+ return init(ctx);
+}
+
+AVFilter ff_vf_alphaextract = {
+ .name = "alphaextract",
+ .description = NULL_IF_CONFIG_SMALL("Extract an alpha channel as a "
+ "grayscale image component."),
+ .priv_size = sizeof(ExtractPlanesContext),
+ .init = init_alphaextract,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = extractplanes_inputs,
+ .outputs = NULL,
+ .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
+};
+#endif /* CONFIG_ALPHAEXTRACT_FILTER */
diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
index eac0c2c9a9..ab2dccf85b 100644
--- a/libavfilter/vf_fade.c
+++ b/libavfilter/vf_fade.c
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Brandon Mintern
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,14 +25,27 @@
* based heavily on vf_negate.c by Bobby Bingham
*/
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
#include "libavutil/common.h"
+#include "libavutil/eval.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avfilter.h"
+#include "drawutils.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+#define Y 0
+#define U 1
+#define V 2
+
#define FADE_IN 0
#define FADE_OUT 1
@@ -41,8 +54,15 @@ typedef struct FadeContext {
int type;
int factor, fade_per_frame;
int start_frame, nb_frames;
- unsigned int frame_index, stop_frame;
int hsub, vsub, bpp;
+ unsigned int black_level, black_level_scaled;
+ uint8_t is_packed_rgb;
+ uint8_t rgba_map[4];
+ int alpha;
+ uint64_t start_time, duration;
+ enum {VF_FADE_WAITING=0, VF_FADE_FADING, VF_FADE_DONE} fade_state;
+ uint8_t color_rgba[4]; ///< fade color
+ int black_fade; ///< if color_rgba is black
} FadeContext;
static av_cold int init(AVFilterContext *ctx)
@@ -50,36 +70,69 @@ static av_cold int init(AVFilterContext *ctx)
FadeContext *s = ctx->priv;
s->fade_per_frame = (1 << 16) / s->nb_frames;
- if (s->type == FADE_IN) {
- s->factor = 0;
- } else if (s->type == FADE_OUT) {
- s->fade_per_frame = -s->fade_per_frame;
- s->factor = (1 << 16);
+ s->fade_state = VF_FADE_WAITING;
+
+ if (s->duration != 0) {
+ // If duration (seconds) is non-zero, assume that we are not fading based on frames
+ s->nb_frames = 0; // Mostly to clean up logging
}
- s->stop_frame = s->start_frame + s->nb_frames;
- av_log(ctx, AV_LOG_VERBOSE,
- "type:%s start_frame:%d nb_frames:%d\n",
- s->type == FADE_IN ? "in" : "out", s->start_frame,
- s->nb_frames);
+ // Choose what to log. If both time-based and frame-based options, both lines will be in the log
+ if (s->start_frame || s->nb_frames) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "type:%s start_frame:%d nb_frames:%d alpha:%d\n",
+ s->type == FADE_IN ? "in" : "out", s->start_frame,
+ s->nb_frames,s->alpha);
+ }
+ if (s->start_time || s->duration) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "type:%s start_time:%f duration:%f alpha:%d\n",
+ s->type == FADE_IN ? "in" : "out", (s->start_time / (double)AV_TIME_BASE),
+ (s->duration / (double)AV_TIME_BASE),s->alpha);
+ }
+
+ s->black_fade = !memcmp(s->color_rgba, "\x00\x00\x00\xff", 4);
return 0;
}
static int query_formats(AVFilterContext *ctx)
{
+ const FadeContext *s = ctx->priv;
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_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat pix_fmts_rgb[] = {
AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
AV_PIX_FMT_NONE
};
+ AVFilterFormats *fmts_list;
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ if (s->black_fade)
+ fmts_list = ff_make_format_list(pix_fmts);
+ else
+ fmts_list = ff_make_format_list(pix_fmts_rgb);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
+const static enum AVPixelFormat studio_level_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_NONE
+};
+
static int config_props(AVFilterLink *inlink)
{
FadeContext *s = inlink->dst->priv;
@@ -88,7 +141,59 @@ static int config_props(AVFilterLink *inlink)
s->hsub = pixdesc->log2_chroma_w;
s->vsub = pixdesc->log2_chroma_h;
- s->bpp = av_get_bits_per_pixel(pixdesc) >> 3;
+ s->bpp = pixdesc->flags & AV_PIX_FMT_FLAG_PLANAR ?
+ 1 :
+ av_get_bits_per_pixel(pixdesc) >> 3;
+ s->alpha &= !!(pixdesc->flags & AV_PIX_FMT_FLAG_ALPHA);
+ s->is_packed_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0;
+
+ /* use CCIR601/709 black level for studio-level pixel non-alpha components */
+ s->black_level =
+ ff_fmt_is_in(inlink->format, studio_level_pix_fmts) && !s->alpha ? 16 : 0;
+ /* 32768 = 1 << 15, it is an integer representation
+ * of 0.5 and is for rounding. */
+ s->black_level_scaled = (s->black_level << 16) + 32768;
+ return 0;
+}
+
+static av_always_inline void filter_rgb(FadeContext *s, const AVFrame *frame,
+ int slice_start, int slice_end,
+ int do_alpha, int step)
+{
+ int i, j;
+ const uint8_t r_idx = s->rgba_map[R];
+ const uint8_t g_idx = s->rgba_map[G];
+ const uint8_t b_idx = s->rgba_map[B];
+ const uint8_t a_idx = s->rgba_map[A];
+ const uint8_t *c = s->color_rgba;
+
+ for (i = slice_start; i < slice_end; i++) {
+ uint8_t *p = frame->data[0] + i * frame->linesize[0];
+ for (j = 0; j < frame->width; j++) {
+#define INTERP(c_name, c_idx) av_clip_uint8(((c[c_idx]<<16) + ((int)p[c_name] - (int)c[c_idx]) * s->factor + (1<<15)) >> 16)
+ p[r_idx] = INTERP(r_idx, 0);
+ p[g_idx] = INTERP(g_idx, 1);
+ p[b_idx] = INTERP(b_idx, 2);
+ if (do_alpha)
+ p[a_idx] = INTERP(a_idx, 3);
+ p += step;
+ }
+ }
+}
+
+static int filter_slice_rgb(AVFilterContext *ctx, void *arg, int jobnr,
+ int nb_jobs)
+{
+ FadeContext *s = ctx->priv;
+ AVFrame *frame = arg;
+ int slice_start = (frame->height * jobnr ) / nb_jobs;
+ int slice_end = (frame->height * (jobnr+1)) / nb_jobs;
+
+ if (s->alpha) filter_rgb(s, frame, slice_start, slice_end, 1, 4);
+ else if (s->bpp == 3) filter_rgb(s, frame, slice_start, slice_end, 0, 3);
+ else if (s->bpp == 4) filter_rgb(s, frame, slice_start, slice_end, 0, 4);
+ else av_assert0(0);
+
return 0;
}
@@ -97,9 +202,8 @@ static int filter_slice_luma(AVFilterContext *ctx, void *arg, int jobnr,
{
FadeContext *s = ctx->priv;
AVFrame *frame = arg;
- int slice_h = frame->height / nb_jobs;
- int slice_start = jobnr * slice_h;
- int slice_end = (jobnr == nb_jobs - 1) ? frame->height : (jobnr + 1) * slice_h;
+ int slice_start = (frame->height * jobnr ) / nb_jobs;
+ int slice_end = (frame->height * (jobnr+1)) / nb_jobs;
int i, j;
for (i = slice_start; i < slice_end; i++) {
@@ -108,7 +212,7 @@ static int filter_slice_luma(AVFilterContext *ctx, void *arg, int jobnr,
/* s->factor is using 16 lower-order bits for decimal
* places. 32768 = 1 << 15, it is an integer representation
* of 0.5 and is for rounding. */
- *p = (*p * s->factor + 32768) >> 16;
+ *p = ((*p - s->black_level) * s->factor + s->black_level_scaled) >> 16;
p++;
}
}
@@ -121,15 +225,16 @@ static int filter_slice_chroma(AVFilterContext *ctx, void *arg, int jobnr,
{
FadeContext *s = ctx->priv;
AVFrame *frame = arg;
- int slice_h = FFALIGN(frame->height / nb_jobs, 1 << s->vsub);
- int slice_start = jobnr * slice_h;
- int slice_end = (jobnr == nb_jobs - 1) ? frame->height : (jobnr + 1) * slice_h;
int i, j, plane;
+ const int width = FF_CEIL_RSHIFT(frame->width, s->hsub);
+ const int height= FF_CEIL_RSHIFT(frame->height, s->vsub);
+ int slice_start = (height * jobnr ) / nb_jobs;
+ int slice_end = (height * (jobnr+1)) / nb_jobs;
for (plane = 1; plane < 3; plane++) {
for (i = slice_start; i < slice_end; i++) {
- uint8_t *p = frame->data[plane] + (i >> s->vsub) * frame->linesize[plane];
- for (j = 0; j < frame->width >> s->hsub; j++) {
+ uint8_t *p = frame->data[plane] + i * frame->linesize[plane];
+ for (j = 0; j < width; j++) {
/* 8421367 = ((128 << 1) + 1) << 15. It is an integer
* representation of 128.5. The .5 is for rounding
* purposes. */
@@ -142,60 +247,148 @@ static int filter_slice_chroma(AVFilterContext *ctx, void *arg, int jobnr,
return 0;
}
+static int filter_slice_alpha(AVFilterContext *ctx, void *arg, int jobnr,
+ int nb_jobs)
+{
+ FadeContext *s = ctx->priv;
+ AVFrame *frame = arg;
+ int plane = s->is_packed_rgb ? 0 : A;
+ int slice_start = (frame->height * jobnr ) / nb_jobs;
+ int slice_end = (frame->height * (jobnr+1)) / nb_jobs;
+ int i, j;
+
+ for (i = slice_start; i < slice_end; i++) {
+ uint8_t *p = frame->data[plane] + i * frame->linesize[plane] + s->is_packed_rgb*s->rgba_map[A];
+ int step = s->is_packed_rgb ? 4 : 1;
+ for (j = 0; j < frame->width; j++) {
+ /* s->factor is using 16 lower-order bits for decimal
+ * places. 32768 = 1 << 15, it is an integer representation
+ * of 0.5 and is for rounding. */
+ *p = ((*p - s->black_level) * s->factor + s->black_level_scaled) >> 16;
+ p += step;
+ }
+ }
+
+ return 0;
+}
+
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
FadeContext *s = ctx->priv;
+ double frame_timestamp = frame->pts == AV_NOPTS_VALUE ? -1 : frame->pts * av_q2d(inlink->time_base);
- if (s->factor < UINT16_MAX) {
- /* luma or rgb plane */
- ctx->internal->execute(ctx, filter_slice_luma, frame, NULL,
- FFMIN(frame->height, ctx->graph->nb_threads));
+ // Calculate Fade assuming this is a Fade In
+ if (s->fade_state == VF_FADE_WAITING) {
+ s->factor=0;
+ if (frame_timestamp >= s->start_time/(double)AV_TIME_BASE
+ && inlink->frame_count >= s->start_frame) {
+ // Time to start fading
+ s->fade_state = VF_FADE_FADING;
- if (frame->data[1] && frame->data[2]) {
- /* chroma planes */
- ctx->internal->execute(ctx, filter_slice_chroma, frame, NULL,
- FFMIN(frame->height, ctx->graph->nb_threads));
+ // Save start time in case we are starting based on frames and fading based on time
+ if (s->start_time == 0 && s->start_frame != 0) {
+ s->start_time = frame_timestamp*(double)AV_TIME_BASE;
+ }
+
+ // Save start frame in case we are starting based on time and fading based on frames
+ if (s->start_time != 0 && s->start_frame == 0) {
+ s->start_frame = inlink->frame_count;
+ }
}
}
+ if (s->fade_state == VF_FADE_FADING) {
+ if (s->duration == 0) {
+ // Fading based on frame count
+ s->factor = (inlink->frame_count - s->start_frame) * s->fade_per_frame;
+ if (inlink->frame_count > s->start_frame + s->nb_frames) {
+ s->fade_state = VF_FADE_DONE;
+ }
+
+ } else {
+ // Fading based on duration
+ s->factor = (frame_timestamp - s->start_time/(double)AV_TIME_BASE)
+ * (float) UINT16_MAX / (s->duration/(double)AV_TIME_BASE);
+ if (frame_timestamp > s->start_time/(double)AV_TIME_BASE
+ + s->duration/(double)AV_TIME_BASE) {
+ s->fade_state = VF_FADE_DONE;
+ }
+ }
+ }
+ if (s->fade_state == VF_FADE_DONE) {
+ s->factor=UINT16_MAX;
+ }
- if (s->frame_index >= s->start_frame &&
- s->frame_index <= s->stop_frame)
- s->factor += s->fade_per_frame;
s->factor = av_clip_uint16(s->factor);
- s->frame_index++;
+
+ // Invert fade_factor if Fading Out
+ if (s->type == FADE_OUT) {
+ s->factor=UINT16_MAX-s->factor;
+ }
+
+ if (s->factor < UINT16_MAX) {
+ if (s->alpha) {
+ ctx->internal->execute(ctx, filter_slice_alpha, frame, NULL,
+ FFMIN(frame->height, ctx->graph->nb_threads));
+ } else if (s->is_packed_rgb && !s->black_fade) {
+ ctx->internal->execute(ctx, filter_slice_rgb, frame, NULL,
+ FFMIN(frame->height, ctx->graph->nb_threads));
+ } else {
+ /* luma, or rgb plane in case of black */
+ ctx->internal->execute(ctx, filter_slice_luma, frame, NULL,
+ FFMIN(frame->height, ctx->graph->nb_threads));
+
+ if (frame->data[1] && frame->data[2]) {
+ /* chroma planes */
+ ctx->internal->execute(ctx, filter_slice_chroma, frame, NULL,
+ FFMIN(frame->height, ctx->graph->nb_threads));
+ }
+ }
+ }
return ff_filter_frame(inlink->dst->outputs[0], frame);
}
+
#define OFFSET(x) offsetof(FadeContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption fade_options[] = {
{ "type", "'in' or 'out' for fade-in/fade-out", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = FADE_IN }, FADE_IN, FADE_OUT, FLAGS, "type" },
+ { "t", "'in' or 'out' for fade-in/fade-out", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = FADE_IN }, FADE_IN, FADE_OUT, FLAGS, "type" },
{ "in", "fade-in", 0, AV_OPT_TYPE_CONST, { .i64 = FADE_IN }, .unit = "type" },
{ "out", "fade-out", 0, AV_OPT_TYPE_CONST, { .i64 = FADE_OUT }, .unit = "type" },
{ "start_frame", "Number of the first frame to which to apply the effect.",
OFFSET(start_frame), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "s", "Number of the first frame to which to apply the effect.",
+ OFFSET(start_frame), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
{ "nb_frames", "Number of frames to which the effect should be applied.",
- OFFSET(nb_frames), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS },
- { NULL },
+ OFFSET(nb_frames), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, FLAGS },
+ { "n", "Number of frames to which the effect should be applied.",
+ OFFSET(nb_frames), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, FLAGS },
+ { "alpha", "fade alpha if it is available on the input", OFFSET(alpha), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS },
+ { "start_time", "Number of seconds of the beginning of the effect.",
+ OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "st", "Number of seconds of the beginning of the effect.",
+ OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "duration", "Duration of the effect in seconds.",
+ OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "d", "Duration of the effect in seconds.",
+ OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS },
+ { "color", "set color", OFFSET(color_rgba), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "c", "set color", OFFSET(color_rgba), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { NULL }
};
-static const AVClass fade_class = {
- .class_name = "fade",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(fade);
static const AVFilterPad avfilter_vf_fade_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_props,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
- .needs_writable = 1,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ .filter_frame = filter_frame,
+ .needs_writable = 1,
},
{ NULL }
};
@@ -210,13 +403,12 @@ static const AVFilterPad avfilter_vf_fade_outputs[] = {
AVFilter ff_vf_fade = {
.name = "fade",
- .description = NULL_IF_CONFIG_SMALL("Fade in/out input video"),
+ .description = NULL_IF_CONFIG_SMALL("Fade in/out input video."),
.init = init,
.priv_size = sizeof(FadeContext),
.priv_class = &fade_class,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_fade_inputs,
- .outputs = avfilter_vf_fade_outputs,
- .flags = AVFILTER_FLAG_SLICE_THREADS,
+ .inputs = avfilter_vf_fade_inputs,
+ .outputs = avfilter_vf_fade_outputs,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
};
diff --git a/libavfilter/vf_fftfilt.c b/libavfilter/vf_fftfilt.c
new file mode 100644
index 0000000000..c914ed01e4
--- /dev/null
+++ b/libavfilter/vf_fftfilt.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2015 Arwa Arif <arwaarif1994@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
+ * FFT domain filtering.
+ */
+
+#include "libavfilter/internal.h"
+#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavcodec/avfft.h"
+#include "libavutil/eval.h"
+
+#define MAX_PLANES 4
+
+typedef struct {
+ const AVClass *class;
+
+ RDFTContext *rdft;
+ int rdft_hbits[MAX_PLANES];
+ int rdft_vbits[MAX_PLANES];
+ size_t rdft_hlen[MAX_PLANES];
+ size_t rdft_vlen[MAX_PLANES];
+ FFTSample *rdft_hdata[MAX_PLANES];
+ FFTSample *rdft_vdata[MAX_PLANES];
+
+ int dc[MAX_PLANES];
+ char *weight_str[MAX_PLANES];
+ AVExpr *weight_expr[MAX_PLANES];
+ double *weight[MAX_PLANES];
+
+} FFTFILTContext;
+
+static const char *const var_names[] = { "X", "Y", "W", "H", NULL };
+enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_VARS_NB };
+
+enum { Y = 0, U, V };
+
+#define OFFSET(x) offsetof(FFTFILTContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption fftfilt_options[] = {
+ { "dc_Y", "adjust gain in Y plane", OFFSET(dc[Y]), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1000, FLAGS },
+ { "dc_U", "adjust gain in U plane", OFFSET(dc[U]), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1000, FLAGS },
+ { "dc_V", "adjust gain in V plane", OFFSET(dc[V]), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1000, FLAGS },
+ { "weight_Y", "set luminance expression in Y plane", OFFSET(weight_str[Y]), AV_OPT_TYPE_STRING, {.str = "1"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "weight_U", "set chrominance expression in U plane", OFFSET(weight_str[U]), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "weight_V", "set chrominance expression in V plane", OFFSET(weight_str[V]), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(fftfilt);
+
+static inline double lum(void *priv, double x, double y, int plane)
+{
+ FFTFILTContext *fftfilt = priv;
+ return fftfilt->rdft_vdata[plane][(int)x * fftfilt->rdft_vlen[plane] + (int)y];
+}
+
+static double weight_Y(void *priv, double x, double y) { return lum(priv, x, y, Y); }
+static double weight_U(void *priv, double x, double y) { return lum(priv, x, y, U); }
+static double weight_V(void *priv, double x, double y) { return lum(priv, x, y, V); }
+
+static void copy_rev (FFTSample *dest, int w, int w2)
+{
+ int i;
+
+ for (i = w; i < w + (w2-w)/2; i++)
+ dest[i] = dest[2*w - i - 1];
+
+ for (; i < w2; i++)
+ dest[i] = dest[w2 - i];
+}
+
+/*Horizontal pass - RDFT*/
+static void rdft_horizontal(FFTFILTContext *fftfilt, AVFrame *in, int w, int h, int plane)
+{
+ int i, j;
+ fftfilt->rdft = av_rdft_init(fftfilt->rdft_hbits[plane], DFT_R2C);
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++)
+ fftfilt->rdft_hdata[plane][i * fftfilt->rdft_hlen[plane] + j] = *(in->data[plane] + in->linesize[plane] * i + j);
+
+ copy_rev(fftfilt->rdft_hdata[plane] + i * fftfilt->rdft_hlen[plane], w, fftfilt->rdft_hlen[plane]);
+ }
+
+ for (i = 0; i < h; i++)
+ av_rdft_calc(fftfilt->rdft, fftfilt->rdft_hdata[plane] + i * fftfilt->rdft_hlen[plane]);
+
+ av_rdft_end(fftfilt->rdft);
+}
+
+/*Vertical pass - RDFT*/
+static void rdft_vertical(FFTFILTContext *fftfilt, int h, int plane)
+{
+ int i, j;
+ fftfilt->rdft = av_rdft_init(fftfilt->rdft_vbits[plane], DFT_R2C);
+
+ for (i = 0; i < fftfilt->rdft_hlen[plane]; i++) {
+ for (j = 0; j < h; j++)
+ fftfilt->rdft_vdata[plane][i * fftfilt->rdft_vlen[plane] + j] =
+ fftfilt->rdft_hdata[plane][j * fftfilt->rdft_hlen[plane] + i];
+ copy_rev(fftfilt->rdft_vdata[plane] + i * fftfilt->rdft_vlen[plane], h, fftfilt->rdft_vlen[plane]);
+ }
+
+ for (i = 0; i < fftfilt->rdft_hlen[plane]; i++)
+ av_rdft_calc(fftfilt->rdft, fftfilt->rdft_vdata[plane] + i * fftfilt->rdft_vlen[plane]);
+
+ av_rdft_end(fftfilt->rdft);
+}
+/*Vertical pass - IRDFT*/
+static void irdft_vertical(FFTFILTContext *fftfilt, int h, int plane)
+{
+ int i, j;
+ fftfilt->rdft = av_rdft_init(fftfilt->rdft_vbits[plane], IDFT_C2R);
+ for (i = 0; i < fftfilt->rdft_hlen[plane]; i++)
+ av_rdft_calc(fftfilt->rdft, fftfilt->rdft_vdata[plane] + i * fftfilt->rdft_vlen[plane]);
+
+ for (i = 0; i < fftfilt->rdft_hlen[plane]; i++)
+ for (j = 0; j < h; j++)
+ fftfilt->rdft_hdata[plane][j * fftfilt->rdft_hlen[plane] + i] =
+ fftfilt->rdft_vdata[plane][i * fftfilt->rdft_vlen[plane] + j];
+
+ av_rdft_end(fftfilt->rdft);
+}
+
+/*Horizontal pass - IRDFT*/
+static void irdft_horizontal(FFTFILTContext *fftfilt, AVFrame *out, int w, int h, int plane)
+{
+ int i, j;
+ fftfilt->rdft = av_rdft_init(fftfilt->rdft_hbits[plane], IDFT_C2R);
+ for (i = 0; i < h; i++)
+ av_rdft_calc(fftfilt->rdft, fftfilt->rdft_hdata[plane] + i * fftfilt->rdft_hlen[plane]);
+
+ for (i = 0; i < h; i++)
+ for (j = 0; j < w; j++)
+ *(out->data[plane] + out->linesize[plane] * i + j) = av_clip(fftfilt->rdft_hdata[plane][i
+ *fftfilt->rdft_hlen[plane] + j] * 4 /
+ (fftfilt->rdft_hlen[plane] *
+ fftfilt->rdft_vlen[plane]), 0, 255);
+
+ av_rdft_end(fftfilt->rdft);
+}
+
+static av_cold int initialize(AVFilterContext *ctx)
+{
+ FFTFILTContext *fftfilt = ctx->priv;
+ int ret = 0, plane;
+
+ if (!fftfilt->dc[U] && !fftfilt->dc[V]) {
+ fftfilt->dc[U] = fftfilt->dc[Y];
+ fftfilt->dc[V] = fftfilt->dc[Y];
+ } else {
+ if (!fftfilt->dc[U]) fftfilt->dc[U] = fftfilt->dc[V];
+ if (!fftfilt->dc[V]) fftfilt->dc[V] = fftfilt->dc[U];
+ }
+
+ if (!fftfilt->weight_str[U] && !fftfilt->weight_str[V]) {
+ fftfilt->weight_str[U] = av_strdup(fftfilt->weight_str[Y]);
+ fftfilt->weight_str[V] = av_strdup(fftfilt->weight_str[Y]);
+ } else {
+ if (!fftfilt->weight_str[U]) fftfilt->weight_str[U] = av_strdup(fftfilt->weight_str[V]);
+ if (!fftfilt->weight_str[V]) fftfilt->weight_str[V] = av_strdup(fftfilt->weight_str[U]);
+ }
+
+ for (plane = 0; plane < 3; plane++) {
+ static double (*p[])(void *, double, double) = { weight_Y, weight_U, weight_V };
+ const char *const func2_names[] = {"weight_Y", "weight_U", "weight_V", NULL };
+ double (*func2[])(void *, double, double) = { weight_Y, weight_U, weight_V, p[plane], NULL };
+
+ ret = av_expr_parse(&fftfilt->weight_expr[plane], fftfilt->weight_str[plane], var_names,
+ NULL, NULL, func2_names, func2, 0, ctx);
+ if (ret < 0)
+ break;
+ }
+ return ret;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ FFTFILTContext *fftfilt = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc;
+ int rdft_hbits, rdft_vbits, i, j, plane;
+ double values[VAR_VARS_NB];
+
+ desc = av_pix_fmt_desc_get(inlink->format);
+ for (i = 0; i < desc->nb_components; i++) {
+ int w = inlink->w;
+ int h = inlink->h;
+
+ /* RDFT - Array initialization for Horizontal pass*/
+ for (rdft_hbits = 1; 1 << rdft_hbits < w*10/9; rdft_hbits++);
+ fftfilt->rdft_hbits[i] = rdft_hbits;
+ fftfilt->rdft_hlen[i] = 1 << rdft_hbits;
+ if (!(fftfilt->rdft_hdata[i] = av_malloc_array(h, fftfilt->rdft_hlen[i] * sizeof(FFTSample))))
+ return AVERROR(ENOMEM);
+
+ /* RDFT - Array initialization for Vertical pass*/
+ for (rdft_vbits = 1; 1 << rdft_vbits < h*10/9; rdft_vbits++);
+ fftfilt->rdft_vbits[i] = rdft_vbits;
+ fftfilt->rdft_vlen[i] = 1 << rdft_vbits;
+ if (!(fftfilt->rdft_vdata[i] = av_malloc_array(fftfilt->rdft_hlen[i], fftfilt->rdft_vlen[i] * sizeof(FFTSample))))
+ return AVERROR(ENOMEM);
+ }
+
+ /*Luminance value - Array initialization*/
+ values[VAR_W] = inlink->w;
+ values[VAR_H] = inlink->h;
+ for (plane = 0; plane < 3; plane++)
+ {
+ if(!(fftfilt->weight[plane] = av_malloc_array(fftfilt->rdft_hlen[plane], fftfilt->rdft_vlen[plane] * sizeof(double))))
+ return AVERROR(ENOMEM);
+ for (i = 0; i < fftfilt->rdft_hlen[plane]; i++)
+ {
+ values[VAR_X] = i;
+ for (j = 0; j < fftfilt->rdft_vlen[plane]; j++)
+ {
+ values[VAR_Y] = j;
+ fftfilt->weight[plane][i * fftfilt->rdft_vlen[plane] + j] =
+ av_expr_eval(fftfilt->weight_expr[plane], values, fftfilt);
+ }
+ }
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ const AVPixFmtDescriptor *desc;
+ FFTFILTContext *fftfilt = ctx->priv;
+ AVFrame *out;
+ int i, j, plane;
+
+ out = ff_get_video_buffer(outlink, inlink->w, inlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+
+ av_frame_copy_props(out, in);
+
+ desc = av_pix_fmt_desc_get(inlink->format);
+ for (plane = 0; plane < desc->nb_components; plane++) {
+ int w = inlink->w;
+ int h = inlink->h;
+
+ if (plane == 1 || plane == 2) {
+ w = FF_CEIL_RSHIFT(w, desc->log2_chroma_w);
+ h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
+ }
+
+ rdft_horizontal(fftfilt, in, w, h, plane);
+ rdft_vertical(fftfilt, h, plane);
+
+ /*Change user defined parameters*/
+ for (i = 0; i < fftfilt->rdft_hlen[plane]; i++)
+ for (j = 0; j < fftfilt->rdft_vlen[plane]; j++)
+ fftfilt->rdft_vdata[plane][i * fftfilt->rdft_vlen[plane] + j] *=
+ fftfilt->weight[plane][i * fftfilt->rdft_vlen[plane] + j];
+
+ fftfilt->rdft_vdata[plane][0] += fftfilt->rdft_hlen[plane] * fftfilt->rdft_vlen[plane] * fftfilt->dc[plane];
+
+ irdft_vertical(fftfilt, h, plane);
+ irdft_horizontal(fftfilt, out, w, h, plane);
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ FFTFILTContext *fftfilt = ctx->priv;
+ int i;
+ for (i = 0; i < MAX_PLANES; i++) {
+ av_free(fftfilt->rdft_hdata[i]);
+ av_free(fftfilt->rdft_vdata[i]);
+ av_expr_free(fftfilt->weight_expr[i]);
+ av_free(fftfilt->weight[i]);
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pixel_fmts_fftfilt[] = {
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pixel_fmts_fftfilt);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static const AVFilterPad fftfilt_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad fftfilt_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_fftfilt = {
+ .name = "fftfilt",
+ .description = NULL_IF_CONFIG_SMALL("Apply arbitrary expressions to samples in frequency domain"),
+ .priv_size = sizeof(FFTFILTContext),
+ .priv_class = &fftfilt_class,
+ .inputs = fftfilt_inputs,
+ .outputs = fftfilt_outputs,
+ .query_formats = query_formats,
+ .init = initialize,
+ .uninit = uninit,
+};
diff --git a/libavfilter/vf_field.c b/libavfilter/vf_field.c
new file mode 100644
index 0000000000..72cabdb929
--- /dev/null
+++ b/libavfilter/vf_field.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003 Rich Felker
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * field filter, based on libmpcodecs/vf_field.c by Rich Felker
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+
+enum FieldType { FIELD_TYPE_TOP = 0, FIELD_TYPE_BOTTOM };
+
+typedef struct {
+ const AVClass *class;
+ int type; ///< FieldType
+ int nb_planes; ///< number of planes of the current format
+} FieldContext;
+
+#define OFFSET(x) offsetof(FieldContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption field_options[] = {
+ {"type", "set field type (top or bottom)", OFFSET(type), AV_OPT_TYPE_INT, {.i64=FIELD_TYPE_TOP}, 0, 1, FLAGS, "field_type" },
+ {"top", "select top field", 0, AV_OPT_TYPE_CONST, {.i64=FIELD_TYPE_TOP}, INT_MIN, INT_MAX, FLAGS, "field_type"},
+ {"bottom", "select bottom field", 0, AV_OPT_TYPE_CONST, {.i64=FIELD_TYPE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "field_type"},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(field);
+
+static int config_props_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ FieldContext *field = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ field->nb_planes = av_pix_fmt_count_planes(outlink->format);
+
+ outlink->w = inlink->w;
+ outlink->h = (inlink->h + (field->type == FIELD_TYPE_TOP)) / 2;
+
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d type:%s -> w:%d h:%d\n",
+ inlink->w, inlink->h, field->type == FIELD_TYPE_BOTTOM ? "bottom" : "top",
+ outlink->w, outlink->h);
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ FieldContext *field = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int i;
+
+ inpicref->height = outlink->h;
+ inpicref->interlaced_frame = 0;
+
+ for (i = 0; i < field->nb_planes; i++) {
+ if (field->type == FIELD_TYPE_BOTTOM)
+ inpicref->data[i] = inpicref->data[i] + inpicref->linesize[i];
+ inpicref->linesize[i] = 2 * inpicref->linesize[i];
+ }
+ return ff_filter_frame(outlink, inpicref);
+}
+
+static const AVFilterPad field_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad field_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_field = {
+ .name = "field",
+ .description = NULL_IF_CONFIG_SMALL("Extract a field from the input video."),
+ .priv_size = sizeof(FieldContext),
+ .inputs = field_inputs,
+ .outputs = field_outputs,
+ .priv_class = &field_class,
+};
diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c
new file mode 100644
index 0000000000..c01af6681c
--- /dev/null
+++ b/libavfilter/vf_fieldmatch.c
@@ -0,0 +1,986 @@
+/*
+ * Copyright (c) 2012 Fredrik Mellbin
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Fieldmatching filter, ported from VFM filter (VapourSynth) by Clément.
+ * Fredrik Mellbin is the author of the VIVTC/VFM filter, which is itself a
+ * light clone of the TIVTC/TFM (AviSynth) filter written by Kevin Stone
+ * (tritical), the original author.
+ *
+ * @see http://bengal.missouri.edu/~kes25c/
+ * @see http://www.vapoursynth.com/about/
+ */
+
+#include <inttypes.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#define INPUT_MAIN 0
+#define INPUT_CLEANSRC 1
+
+enum fieldmatch_parity {
+ FM_PARITY_AUTO = -1,
+ FM_PARITY_BOTTOM = 0,
+ FM_PARITY_TOP = 1,
+};
+
+enum matching_mode {
+ MODE_PC,
+ MODE_PC_N,
+ MODE_PC_U,
+ MODE_PC_N_UB,
+ MODE_PCN,
+ MODE_PCN_UB,
+ NB_MODE
+};
+
+enum comb_matching_mode {
+ COMBMATCH_NONE,
+ COMBMATCH_SC,
+ COMBMATCH_FULL,
+ NB_COMBMATCH
+};
+
+enum comb_dbg {
+ COMBDBG_NONE,
+ COMBDBG_PCN,
+ COMBDBG_PCNUB,
+ NB_COMBDBG
+};
+
+typedef struct {
+ const AVClass *class;
+
+ AVFrame *prv, *src, *nxt; ///< main sliding window of 3 frames
+ AVFrame *prv2, *src2, *nxt2; ///< sliding window of the optional second stream
+ int got_frame[2]; ///< frame request flag for each input stream
+ int hsub, vsub; ///< chroma subsampling values
+ uint32_t eof; ///< bitmask for end of stream
+ int64_t lastscdiff;
+ int64_t lastn;
+
+ /* options */
+ int order;
+ int ppsrc;
+ int mode; ///< matching_mode
+ int field;
+ int mchroma;
+ int y0, y1;
+ int64_t scthresh;
+ double scthresh_flt;
+ int combmatch; ///< comb_matching_mode
+ int combdbg;
+ int cthresh;
+ int chroma;
+ int blockx, blocky;
+ int combpel;
+
+ /* misc buffers */
+ uint8_t *map_data[4];
+ int map_linesize[4];
+ uint8_t *cmask_data[4];
+ int cmask_linesize[4];
+ int *c_array;
+ int tpitchy, tpitchuv;
+ uint8_t *tbuffer;
+} FieldMatchContext;
+
+#define OFFSET(x) offsetof(FieldMatchContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption fieldmatch_options[] = {
+ { "order", "specify the assumed field order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=FM_PARITY_AUTO}, -1, 1, FLAGS, "order" },
+ { "auto", "auto detect parity", 0, AV_OPT_TYPE_CONST, {.i64=FM_PARITY_AUTO}, INT_MIN, INT_MAX, FLAGS, "order" },
+ { "bff", "assume bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=FM_PARITY_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "order" },
+ { "tff", "assume top field first", 0, AV_OPT_TYPE_CONST, {.i64=FM_PARITY_TOP}, INT_MIN, INT_MAX, FLAGS, "order" },
+ { "mode", "set the matching mode or strategy to use", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_PC_N}, MODE_PC, NB_MODE-1, FLAGS, "mode" },
+ { "pc", "2-way match (p/c)", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PC}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "pc_n", "2-way match + 3rd match on combed (p/c + u)", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PC_N}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "pc_u", "2-way match + 3rd match (same order) on combed (p/c + u)", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PC_U}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "pc_n_ub", "2-way match + 3rd match on combed + 4th/5th matches if still combed (p/c + u + u/b)", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PC_N_UB}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "pcn", "3-way match (p/c/n)", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PCN}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "pcn_ub", "3-way match + 4th/5th matches on combed (p/c/n + u/b)", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PCN_UB}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "ppsrc", "mark main input as a pre-processed input and activate clean source input stream", OFFSET(ppsrc), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "field", "set the field to match from", OFFSET(field), AV_OPT_TYPE_INT, {.i64=FM_PARITY_AUTO}, -1, 1, FLAGS, "field" },
+ { "auto", "automatic (same value as 'order')", 0, AV_OPT_TYPE_CONST, {.i64=FM_PARITY_AUTO}, INT_MIN, INT_MAX, FLAGS, "field" },
+ { "bottom", "bottom field", 0, AV_OPT_TYPE_CONST, {.i64=FM_PARITY_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "field" },
+ { "top", "top field", 0, AV_OPT_TYPE_CONST, {.i64=FM_PARITY_TOP}, INT_MIN, INT_MAX, FLAGS, "field" },
+ { "mchroma", "set whether or not chroma is included during the match comparisons", OFFSET(mchroma), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { "y0", "define an exclusion band which excludes the lines between y0 and y1 from the field matching decision", OFFSET(y0), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+ { "y1", "define an exclusion band which excludes the lines between y0 and y1 from the field matching decision", OFFSET(y1), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS },
+ { "scthresh", "set scene change detection threshold", OFFSET(scthresh_flt), AV_OPT_TYPE_DOUBLE, {.dbl=12}, 0, 100, FLAGS },
+ { "combmatch", "set combmatching mode", OFFSET(combmatch), AV_OPT_TYPE_INT, {.i64=COMBMATCH_SC}, COMBMATCH_NONE, NB_COMBMATCH-1, FLAGS, "combmatching" },
+ { "none", "disable combmatching", 0, AV_OPT_TYPE_CONST, {.i64=COMBMATCH_NONE}, INT_MIN, INT_MAX, FLAGS, "combmatching" },
+ { "sc", "enable combmatching only on scene change", 0, AV_OPT_TYPE_CONST, {.i64=COMBMATCH_SC}, INT_MIN, INT_MAX, FLAGS, "combmatching" },
+ { "full", "enable combmatching all the time", 0, AV_OPT_TYPE_CONST, {.i64=COMBMATCH_FULL}, INT_MIN, INT_MAX, FLAGS, "combmatching" },
+ { "combdbg", "enable comb debug", OFFSET(combdbg), AV_OPT_TYPE_INT, {.i64=COMBDBG_NONE}, COMBDBG_NONE, NB_COMBDBG-1, FLAGS, "dbglvl" },
+ { "none", "no forced calculation", 0, AV_OPT_TYPE_CONST, {.i64=COMBDBG_NONE}, INT_MIN, INT_MAX, FLAGS, "dbglvl" },
+ { "pcn", "calculate p/c/n", 0, AV_OPT_TYPE_CONST, {.i64=COMBDBG_PCN}, INT_MIN, INT_MAX, FLAGS, "dbglvl" },
+ { "pcnub", "calculate p/c/n/u/b", 0, AV_OPT_TYPE_CONST, {.i64=COMBDBG_PCNUB}, INT_MIN, INT_MAX, FLAGS, "dbglvl" },
+ { "cthresh", "set the area combing threshold used for combed frame detection", OFFSET(cthresh), AV_OPT_TYPE_INT, {.i64= 9}, -1, 0xff, FLAGS },
+ { "chroma", "set whether or not chroma is considered in the combed frame decision", OFFSET(chroma), AV_OPT_TYPE_INT, {.i64= 0}, 0, 1, FLAGS },
+ { "blockx", "set the x-axis size of the window used during combed frame detection", OFFSET(blockx), AV_OPT_TYPE_INT, {.i64=16}, 4, 1<<9, FLAGS },
+ { "blocky", "set the y-axis size of the window used during combed frame detection", OFFSET(blocky), AV_OPT_TYPE_INT, {.i64=16}, 4, 1<<9, FLAGS },
+ { "combpel", "set the number of combed pixels inside any of the blocky by blockx size blocks on the frame for the frame to be detected as combed", OFFSET(combpel), AV_OPT_TYPE_INT, {.i64=80}, 0, INT_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(fieldmatch);
+
+static int get_width(const FieldMatchContext *fm, const AVFrame *f, int plane)
+{
+ return plane ? FF_CEIL_RSHIFT(f->width, fm->hsub) : f->width;
+}
+
+static int get_height(const FieldMatchContext *fm, const AVFrame *f, int plane)
+{
+ return plane ? FF_CEIL_RSHIFT(f->height, fm->vsub) : f->height;
+}
+
+static int64_t luma_abs_diff(const AVFrame *f1, const AVFrame *f2)
+{
+ int x, y;
+ const uint8_t *srcp1 = f1->data[0];
+ const uint8_t *srcp2 = f2->data[0];
+ const int src1_linesize = f1->linesize[0];
+ const int src2_linesize = f2->linesize[0];
+ const int width = f1->width;
+ const int height = f1->height;
+ int64_t acc = 0;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ acc += abs(srcp1[x] - srcp2[x]);
+ srcp1 += src1_linesize;
+ srcp2 += src2_linesize;
+ }
+ return acc;
+}
+
+static void fill_buf(uint8_t *data, int w, int h, int linesize, uint8_t v)
+{
+ int y;
+
+ for (y = 0; y < h; y++) {
+ memset(data, v, w);
+ data += linesize;
+ }
+}
+
+static int calc_combed_score(const FieldMatchContext *fm, const AVFrame *src)
+{
+ int x, y, plane, max_v = 0;
+ const int cthresh = fm->cthresh;
+ const int cthresh6 = cthresh * 6;
+
+ for (plane = 0; plane < (fm->chroma ? 3 : 1); plane++) {
+ const uint8_t *srcp = src->data[plane];
+ const int src_linesize = src->linesize[plane];
+ const int width = get_width (fm, src, plane);
+ const int height = get_height(fm, src, plane);
+ uint8_t *cmkp = fm->cmask_data[plane];
+ const int cmk_linesize = fm->cmask_linesize[plane];
+
+ if (cthresh < 0) {
+ fill_buf(cmkp, width, height, cmk_linesize, 0xff);
+ continue;
+ }
+ fill_buf(cmkp, width, height, cmk_linesize, 0);
+
+ /* [1 -3 4 -3 1] vertical filter */
+#define FILTER(xm2, xm1, xp1, xp2) \
+ abs( 4 * srcp[x] \
+ -3 * (srcp[x + (xm1)*src_linesize] + srcp[x + (xp1)*src_linesize]) \
+ + (srcp[x + (xm2)*src_linesize] + srcp[x + (xp2)*src_linesize])) > cthresh6
+
+ /* first line */
+ for (x = 0; x < width; x++) {
+ const int s1 = abs(srcp[x] - srcp[x + src_linesize]);
+ if (s1 > cthresh && FILTER(2, 1, 1, 2))
+ cmkp[x] = 0xff;
+ }
+ srcp += src_linesize;
+ cmkp += cmk_linesize;
+
+ /* second line */
+ for (x = 0; x < width; x++) {
+ const int s1 = abs(srcp[x] - srcp[x - src_linesize]);
+ const int s2 = abs(srcp[x] - srcp[x + src_linesize]);
+ if (s1 > cthresh && s2 > cthresh && FILTER(2, -1, 1, 2))
+ cmkp[x] = 0xff;
+ }
+ srcp += src_linesize;
+ cmkp += cmk_linesize;
+
+ /* all lines minus first two and last two */
+ for (y = 2; y < height-2; y++) {
+ for (x = 0; x < width; x++) {
+ const int s1 = abs(srcp[x] - srcp[x - src_linesize]);
+ const int s2 = abs(srcp[x] - srcp[x + src_linesize]);
+ if (s1 > cthresh && s2 > cthresh && FILTER(-2, -1, 1, 2))
+ cmkp[x] = 0xff;
+ }
+ srcp += src_linesize;
+ cmkp += cmk_linesize;
+ }
+
+ /* before-last line */
+ for (x = 0; x < width; x++) {
+ const int s1 = abs(srcp[x] - srcp[x - src_linesize]);
+ const int s2 = abs(srcp[x] - srcp[x + src_linesize]);
+ if (s1 > cthresh && s2 > cthresh && FILTER(-2, -1, 1, -2))
+ cmkp[x] = 0xff;
+ }
+ srcp += src_linesize;
+ cmkp += cmk_linesize;
+
+ /* last line */
+ for (x = 0; x < width; x++) {
+ const int s1 = abs(srcp[x] - srcp[x - src_linesize]);
+ if (s1 > cthresh && FILTER(-2, -1, -1, -2))
+ cmkp[x] = 0xff;
+ }
+ }
+
+ if (fm->chroma) {
+ uint8_t *cmkp = fm->cmask_data[0];
+ uint8_t *cmkpU = fm->cmask_data[1];
+ uint8_t *cmkpV = fm->cmask_data[2];
+ const int width = FF_CEIL_RSHIFT(src->width, fm->hsub);
+ const int height = FF_CEIL_RSHIFT(src->height, fm->vsub);
+ const int cmk_linesize = fm->cmask_linesize[0] << 1;
+ const int cmk_linesizeUV = fm->cmask_linesize[2];
+ uint8_t *cmkpp = cmkp - (cmk_linesize>>1);
+ uint8_t *cmkpn = cmkp + (cmk_linesize>>1);
+ uint8_t *cmkpnn = cmkp + cmk_linesize;
+ for (y = 1; y < height - 1; y++) {
+ cmkpp += cmk_linesize;
+ cmkp += cmk_linesize;
+ cmkpn += cmk_linesize;
+ cmkpnn += cmk_linesize;
+ cmkpV += cmk_linesizeUV;
+ cmkpU += cmk_linesizeUV;
+ for (x = 1; x < width - 1; x++) {
+#define HAS_FF_AROUND(p, lz) (p[(x)-1 - (lz)] == 0xff || p[(x) - (lz)] == 0xff || p[(x)+1 - (lz)] == 0xff || \
+ p[(x)-1 ] == 0xff || p[(x)+1 ] == 0xff || \
+ p[(x)-1 + (lz)] == 0xff || p[(x) + (lz)] == 0xff || p[(x)+1 + (lz)] == 0xff)
+ if ((cmkpV[x] == 0xff && HAS_FF_AROUND(cmkpV, cmk_linesizeUV)) ||
+ (cmkpU[x] == 0xff && HAS_FF_AROUND(cmkpU, cmk_linesizeUV))) {
+ ((uint16_t*)cmkp)[x] = 0xffff;
+ ((uint16_t*)cmkpn)[x] = 0xffff;
+ if (y&1) ((uint16_t*)cmkpp)[x] = 0xffff;
+ else ((uint16_t*)cmkpnn)[x] = 0xffff;
+ }
+ }
+ }
+ }
+
+ {
+ const int blockx = fm->blockx;
+ const int blocky = fm->blocky;
+ const int xhalf = blockx/2;
+ const int yhalf = blocky/2;
+ const int cmk_linesize = fm->cmask_linesize[0];
+ const uint8_t *cmkp = fm->cmask_data[0] + cmk_linesize;
+ const int width = src->width;
+ const int height = src->height;
+ const int xblocks = ((width+xhalf)/blockx) + 1;
+ const int xblocks4 = xblocks<<2;
+ const int yblocks = ((height+yhalf)/blocky) + 1;
+ int *c_array = fm->c_array;
+ const int arraysize = (xblocks*yblocks)<<2;
+ int heighta = (height/(blocky/2))*(blocky/2);
+ const int widtha = (width /(blockx/2))*(blockx/2);
+ if (heighta == height)
+ heighta = height - yhalf;
+ memset(c_array, 0, arraysize * sizeof(*c_array));
+
+#define C_ARRAY_ADD(v) do { \
+ const int box1 = (x / blockx) * 4; \
+ const int box2 = ((x + xhalf) / blockx) * 4; \
+ c_array[temp1 + box1 ] += v; \
+ c_array[temp1 + box2 + 1] += v; \
+ c_array[temp2 + box1 + 2] += v; \
+ c_array[temp2 + box2 + 3] += v; \
+} while (0)
+
+#define VERTICAL_HALF(y_start, y_end) do { \
+ for (y = y_start; y < y_end; y++) { \
+ const int temp1 = (y / blocky) * xblocks4; \
+ const int temp2 = ((y + yhalf) / blocky) * xblocks4; \
+ for (x = 0; x < width; x++) \
+ if (cmkp[x - cmk_linesize] == 0xff && \
+ cmkp[x ] == 0xff && \
+ cmkp[x + cmk_linesize] == 0xff) \
+ C_ARRAY_ADD(1); \
+ cmkp += cmk_linesize; \
+ } \
+} while (0)
+
+ VERTICAL_HALF(1, yhalf);
+
+ for (y = yhalf; y < heighta; y += yhalf) {
+ const int temp1 = (y / blocky) * xblocks4;
+ const int temp2 = ((y + yhalf) / blocky) * xblocks4;
+
+ for (x = 0; x < widtha; x += xhalf) {
+ const uint8_t *cmkp_tmp = cmkp + x;
+ int u, v, sum = 0;
+ for (u = 0; u < yhalf; u++) {
+ for (v = 0; v < xhalf; v++)
+ if (cmkp_tmp[v - cmk_linesize] == 0xff &&
+ cmkp_tmp[v ] == 0xff &&
+ cmkp_tmp[v + cmk_linesize] == 0xff)
+ sum++;
+ cmkp_tmp += cmk_linesize;
+ }
+ if (sum)
+ C_ARRAY_ADD(sum);
+ }
+
+ for (x = widtha; x < width; x++) {
+ const uint8_t *cmkp_tmp = cmkp + x;
+ int u, sum = 0;
+ for (u = 0; u < yhalf; u++) {
+ if (cmkp_tmp[-cmk_linesize] == 0xff &&
+ cmkp_tmp[ 0] == 0xff &&
+ cmkp_tmp[ cmk_linesize] == 0xff)
+ sum++;
+ cmkp_tmp += cmk_linesize;
+ }
+ if (sum)
+ C_ARRAY_ADD(sum);
+ }
+
+ cmkp += cmk_linesize * yhalf;
+ }
+
+ VERTICAL_HALF(heighta, height - 1);
+
+ for (x = 0; x < arraysize; x++)
+ if (c_array[x] > max_v)
+ max_v = c_array[x];
+ }
+ return max_v;
+}
+
+// the secret is that tbuffer is an interlaced, offset subset of all the lines
+static void build_abs_diff_mask(const uint8_t *prvp, int prv_linesize,
+ const uint8_t *nxtp, int nxt_linesize,
+ uint8_t *tbuffer, int tbuf_linesize,
+ int width, int height)
+{
+ int y, x;
+
+ prvp -= prv_linesize;
+ nxtp -= nxt_linesize;
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++)
+ tbuffer[x] = FFABS(prvp[x] - nxtp[x]);
+ prvp += prv_linesize;
+ nxtp += nxt_linesize;
+ tbuffer += tbuf_linesize;
+ }
+}
+
+/**
+ * Build a map over which pixels differ a lot/a little
+ */
+static void build_diff_map(FieldMatchContext *fm,
+ const uint8_t *prvp, int prv_linesize,
+ const uint8_t *nxtp, int nxt_linesize,
+ uint8_t *dstp, int dst_linesize, int height,
+ int width, int plane)
+{
+ int x, y, u, diff, count;
+ int tpitch = plane ? fm->tpitchuv : fm->tpitchy;
+ const uint8_t *dp = fm->tbuffer + tpitch;
+
+ build_abs_diff_mask(prvp, prv_linesize, nxtp, nxt_linesize,
+ fm->tbuffer, tpitch, width, height>>1);
+
+ for (y = 2; y < height - 2; y += 2) {
+ for (x = 1; x < width - 1; x++) {
+ diff = dp[x];
+ if (diff > 3) {
+ for (count = 0, u = x-1; u < x+2 && count < 2; u++) {
+ count += dp[u-tpitch] > 3;
+ count += dp[u ] > 3;
+ count += dp[u+tpitch] > 3;
+ }
+ if (count > 1) {
+ dstp[x] = 1;
+ if (diff > 19) {
+ int upper = 0, lower = 0;
+ for (count = 0, u = x-1; u < x+2 && count < 6; u++) {
+ if (dp[u-tpitch] > 19) { count++; upper = 1; }
+ if (dp[u ] > 19) count++;
+ if (dp[u+tpitch] > 19) { count++; lower = 1; }
+ }
+ if (count > 3) {
+ if (upper && lower) {
+ dstp[x] |= 1<<1;
+ } else {
+ int upper2 = 0, lower2 = 0;
+ for (u = FFMAX(x-4,0); u < FFMIN(x+5,width); u++) {
+ if (y != 2 && dp[u-2*tpitch] > 19) upper2 = 1;
+ if ( dp[u- tpitch] > 19) upper = 1;
+ if ( dp[u+ tpitch] > 19) lower = 1;
+ if (y != height-4 && dp[u+2*tpitch] > 19) lower2 = 1;
+ }
+ if ((upper && (lower || upper2)) ||
+ (lower && (upper || lower2)))
+ dstp[x] |= 1<<1;
+ else if (count > 5)
+ dstp[x] |= 1<<2;
+ }
+ }
+ }
+ }
+ }
+ }
+ dp += tpitch;
+ dstp += dst_linesize;
+ }
+}
+
+enum { mP, mC, mN, mB, mU };
+
+static int get_field_base(int match, int field)
+{
+ return match < 3 ? 2 - field : 1 + field;
+}
+
+static AVFrame *select_frame(FieldMatchContext *fm, int match)
+{
+ if (match == mP || match == mB) return fm->prv;
+ else if (match == mN || match == mU) return fm->nxt;
+ else /* match == mC */ return fm->src;
+}
+
+static int compare_fields(FieldMatchContext *fm, int match1, int match2, int field)
+{
+ int plane, ret;
+ uint64_t accumPc = 0, accumPm = 0, accumPml = 0;
+ uint64_t accumNc = 0, accumNm = 0, accumNml = 0;
+ int norm1, norm2, mtn1, mtn2;
+ float c1, c2, mr;
+ const AVFrame *src = fm->src;
+
+ for (plane = 0; plane < (fm->mchroma ? 3 : 1); plane++) {
+ int x, y, temp1, temp2, fbase;
+ const AVFrame *prev, *next;
+ uint8_t *mapp = fm->map_data[plane];
+ int map_linesize = fm->map_linesize[plane];
+ const uint8_t *srcp = src->data[plane];
+ const int src_linesize = src->linesize[plane];
+ const int srcf_linesize = src_linesize << 1;
+ int prv_linesize, nxt_linesize;
+ int prvf_linesize, nxtf_linesize;
+ const int width = get_width (fm, src, plane);
+ const int height = get_height(fm, src, plane);
+ const int y0a = fm->y0 >> (plane != 0);
+ const int y1a = fm->y1 >> (plane != 0);
+ const int startx = (plane == 0 ? 8 : 4);
+ const int stopx = width - startx;
+ const uint8_t *srcpf, *srcf, *srcnf;
+ const uint8_t *prvpf, *prvnf, *nxtpf, *nxtnf;
+
+ fill_buf(mapp, width, height, map_linesize, 0);
+
+ /* match1 */
+ fbase = get_field_base(match1, field);
+ srcf = srcp + (fbase + 1) * src_linesize;
+ srcpf = srcf - srcf_linesize;
+ srcnf = srcf + srcf_linesize;
+ mapp = mapp + fbase * map_linesize;
+ prev = select_frame(fm, match1);
+ prv_linesize = prev->linesize[plane];
+ prvf_linesize = prv_linesize << 1;
+ prvpf = prev->data[plane] + fbase * prv_linesize; // previous frame, previous field
+ prvnf = prvpf + prvf_linesize; // previous frame, next field
+
+ /* match2 */
+ fbase = get_field_base(match2, field);
+ next = select_frame(fm, match2);
+ nxt_linesize = next->linesize[plane];
+ nxtf_linesize = nxt_linesize << 1;
+ nxtpf = next->data[plane] + fbase * nxt_linesize; // next frame, previous field
+ nxtnf = nxtpf + nxtf_linesize; // next frame, next field
+
+ map_linesize <<= 1;
+ if ((match1 >= 3 && field == 1) || (match1 < 3 && field != 1))
+ build_diff_map(fm, prvpf, prvf_linesize, nxtpf, nxtf_linesize,
+ mapp, map_linesize, height, width, plane);
+ else
+ build_diff_map(fm, prvnf, prvf_linesize, nxtnf, nxtf_linesize,
+ mapp + map_linesize, map_linesize, height, width, plane);
+
+ for (y = 2; y < height - 2; y += 2) {
+ if (y0a == y1a || y < y0a || y > y1a) {
+ for (x = startx; x < stopx; x++) {
+ if (mapp[x] > 0 || mapp[x + map_linesize] > 0) {
+ temp1 = srcpf[x] + (srcf[x] << 2) + srcnf[x]; // [1 4 1]
+
+ temp2 = abs(3 * (prvpf[x] + prvnf[x]) - temp1);
+ if (temp2 > 23 && ((mapp[x]&1) || (mapp[x + map_linesize]&1)))
+ accumPc += temp2;
+ if (temp2 > 42) {
+ if ((mapp[x]&2) || (mapp[x + map_linesize]&2))
+ accumPm += temp2;
+ if ((mapp[x]&4) || (mapp[x + map_linesize]&4))
+ accumPml += temp2;
+ }
+
+ temp2 = abs(3 * (nxtpf[x] + nxtnf[x]) - temp1);
+ if (temp2 > 23 && ((mapp[x]&1) || (mapp[x + map_linesize]&1)))
+ accumNc += temp2;
+ if (temp2 > 42) {
+ if ((mapp[x]&2) || (mapp[x + map_linesize]&2))
+ accumNm += temp2;
+ if ((mapp[x]&4) || (mapp[x + map_linesize]&4))
+ accumNml += temp2;
+ }
+ }
+ }
+ }
+ prvpf += prvf_linesize;
+ prvnf += prvf_linesize;
+ srcpf += srcf_linesize;
+ srcf += srcf_linesize;
+ srcnf += srcf_linesize;
+ nxtpf += nxtf_linesize;
+ nxtnf += nxtf_linesize;
+ mapp += map_linesize;
+ }
+ }
+
+ if (accumPm < 500 && accumNm < 500 && (accumPml >= 500 || accumNml >= 500) &&
+ FFMAX(accumPml,accumNml) > 3*FFMIN(accumPml,accumNml)) {
+ accumPm = accumPml;
+ accumNm = accumNml;
+ }
+
+ norm1 = (int)((accumPc / 6.0f) + 0.5f);
+ norm2 = (int)((accumNc / 6.0f) + 0.5f);
+ mtn1 = (int)((accumPm / 6.0f) + 0.5f);
+ mtn2 = (int)((accumNm / 6.0f) + 0.5f);
+ c1 = ((float)FFMAX(norm1,norm2)) / ((float)FFMAX(FFMIN(norm1,norm2),1));
+ c2 = ((float)FFMAX(mtn1, mtn2)) / ((float)FFMAX(FFMIN(mtn1, mtn2), 1));
+ mr = ((float)FFMAX(mtn1, mtn2)) / ((float)FFMAX(FFMAX(norm1,norm2),1));
+ if (((mtn1 >= 500 || mtn2 >= 500) && (mtn1*2 < mtn2*1 || mtn2*2 < mtn1*1)) ||
+ ((mtn1 >= 1000 || mtn2 >= 1000) && (mtn1*3 < mtn2*2 || mtn2*3 < mtn1*2)) ||
+ ((mtn1 >= 2000 || mtn2 >= 2000) && (mtn1*5 < mtn2*4 || mtn2*5 < mtn1*4)) ||
+ ((mtn1 >= 4000 || mtn2 >= 4000) && c2 > c1))
+ ret = mtn1 > mtn2 ? match2 : match1;
+ else if (mr > 0.005 && FFMAX(mtn1, mtn2) > 150 && (mtn1*2 < mtn2*1 || mtn2*2 < mtn1*1))
+ ret = mtn1 > mtn2 ? match2 : match1;
+ else
+ ret = norm1 > norm2 ? match2 : match1;
+ return ret;
+}
+
+static void copy_fields(const FieldMatchContext *fm, AVFrame *dst,
+ const AVFrame *src, int field)
+{
+ int plane;
+ for (plane = 0; plane < 4 && src->data[plane] && src->linesize[plane]; plane++)
+ av_image_copy_plane(dst->data[plane] + field*dst->linesize[plane], dst->linesize[plane] << 1,
+ src->data[plane] + field*src->linesize[plane], src->linesize[plane] << 1,
+ get_width(fm, src, plane), get_height(fm, src, plane) / 2);
+}
+
+static AVFrame *create_weave_frame(AVFilterContext *ctx, int match, int field,
+ const AVFrame *prv, AVFrame *src, const AVFrame *nxt)
+{
+ AVFrame *dst;
+ FieldMatchContext *fm = ctx->priv;
+
+ if (match == mC) {
+ dst = av_frame_clone(src);
+ } else {
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!dst)
+ return NULL;
+ av_frame_copy_props(dst, src);
+
+ switch (match) {
+ case mP: copy_fields(fm, dst, src, 1-field); copy_fields(fm, dst, prv, field); break;
+ case mN: copy_fields(fm, dst, src, 1-field); copy_fields(fm, dst, nxt, field); break;
+ case mB: copy_fields(fm, dst, src, field); copy_fields(fm, dst, prv, 1-field); break;
+ case mU: copy_fields(fm, dst, src, field); copy_fields(fm, dst, nxt, 1-field); break;
+ default: av_assert0(0);
+ }
+ }
+ return dst;
+}
+
+static int checkmm(AVFilterContext *ctx, int *combs, int m1, int m2,
+ AVFrame **gen_frames, int field)
+{
+ const FieldMatchContext *fm = ctx->priv;
+
+#define LOAD_COMB(mid) do { \
+ if (combs[mid] < 0) { \
+ if (!gen_frames[mid]) \
+ gen_frames[mid] = create_weave_frame(ctx, mid, field, \
+ fm->prv, fm->src, fm->nxt); \
+ combs[mid] = calc_combed_score(fm, gen_frames[mid]); \
+ } \
+} while (0)
+
+ LOAD_COMB(m1);
+ LOAD_COMB(m2);
+
+ if ((combs[m2] * 3 < combs[m1] || (combs[m2] * 2 < combs[m1] && combs[m1] > fm->combpel)) &&
+ abs(combs[m2] - combs[m1]) >= 30 && combs[m2] < fm->combpel)
+ return m2;
+ else
+ return m1;
+}
+
+static const int fxo0m[] = { mP, mC, mN, mB, mU };
+static const int fxo1m[] = { mN, mC, mP, mU, mB };
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ FieldMatchContext *fm = ctx->priv;
+ int combs[] = { -1, -1, -1, -1, -1 };
+ int order, field, i, match, sc = 0;
+ const int *fxo;
+ AVFrame *gen_frames[] = { NULL, NULL, NULL, NULL, NULL };
+ AVFrame *dst;
+
+ /* update frames queue(s) */
+#define SLIDING_FRAME_WINDOW(prv, src, nxt) do { \
+ if (prv != src) /* 2nd loop exception (1st has prv==src and we don't want to loose src) */ \
+ av_frame_free(&prv); \
+ prv = src; \
+ src = nxt; \
+ if (in) \
+ nxt = in; \
+ if (!prv) \
+ prv = src; \
+ if (!prv) /* received only one frame at that point */ \
+ return 0; \
+ av_assert0(prv && src && nxt); \
+} while (0)
+ if (FF_INLINK_IDX(inlink) == INPUT_MAIN) {
+ SLIDING_FRAME_WINDOW(fm->prv, fm->src, fm->nxt);
+ fm->got_frame[INPUT_MAIN] = 1;
+ } else {
+ SLIDING_FRAME_WINDOW(fm->prv2, fm->src2, fm->nxt2);
+ fm->got_frame[INPUT_CLEANSRC] = 1;
+ }
+ if (!fm->got_frame[INPUT_MAIN] || (fm->ppsrc && !fm->got_frame[INPUT_CLEANSRC]))
+ return 0;
+ fm->got_frame[INPUT_MAIN] = fm->got_frame[INPUT_CLEANSRC] = 0;
+ in = fm->src;
+
+ /* parity */
+ order = fm->order != FM_PARITY_AUTO ? fm->order : (in->interlaced_frame ? in->top_field_first : 1);
+ field = fm->field != FM_PARITY_AUTO ? fm->field : order;
+ av_assert0(order == 0 || order == 1 || field == 0 || field == 1);
+ fxo = field ^ order ? fxo1m : fxo0m;
+
+ /* debug mode: we generate all the fields combinations and their associated
+ * combed score. XXX: inject as frame metadata? */
+ if (fm->combdbg) {
+ for (i = 0; i < FF_ARRAY_ELEMS(combs); i++) {
+ if (i > mN && fm->combdbg == COMBDBG_PCN)
+ break;
+ gen_frames[i] = create_weave_frame(ctx, i, field, fm->prv, fm->src, fm->nxt);
+ if (!gen_frames[i])
+ return AVERROR(ENOMEM);
+ combs[i] = calc_combed_score(fm, gen_frames[i]);
+ }
+ av_log(ctx, AV_LOG_INFO, "COMBS: %3d %3d %3d %3d %3d\n",
+ combs[0], combs[1], combs[2], combs[3], combs[4]);
+ } else {
+ gen_frames[mC] = av_frame_clone(fm->src);
+ if (!gen_frames[mC])
+ return AVERROR(ENOMEM);
+ }
+
+ /* p/c selection and optional 3-way p/c/n matches */
+ match = compare_fields(fm, fxo[mC], fxo[mP], field);
+ if (fm->mode == MODE_PCN || fm->mode == MODE_PCN_UB)
+ match = compare_fields(fm, match, fxo[mN], field);
+
+ /* scene change check */
+ if (fm->combmatch == COMBMATCH_SC) {
+ if (fm->lastn == outlink->frame_count - 1) {
+ if (fm->lastscdiff > fm->scthresh)
+ sc = 1;
+ } else if (luma_abs_diff(fm->prv, fm->src) > fm->scthresh) {
+ sc = 1;
+ }
+
+ if (!sc) {
+ fm->lastn = outlink->frame_count;
+ fm->lastscdiff = luma_abs_diff(fm->src, fm->nxt);
+ sc = fm->lastscdiff > fm->scthresh;
+ }
+ }
+
+ if (fm->combmatch == COMBMATCH_FULL || (fm->combmatch == COMBMATCH_SC && sc)) {
+ switch (fm->mode) {
+ /* 2-way p/c matches */
+ case MODE_PC:
+ match = checkmm(ctx, combs, match, match == fxo[mP] ? fxo[mC] : fxo[mP], gen_frames, field);
+ break;
+ case MODE_PC_N:
+ match = checkmm(ctx, combs, match, fxo[mN], gen_frames, field);
+ break;
+ case MODE_PC_U:
+ match = checkmm(ctx, combs, match, fxo[mU], gen_frames, field);
+ break;
+ case MODE_PC_N_UB:
+ match = checkmm(ctx, combs, match, fxo[mN], gen_frames, field);
+ match = checkmm(ctx, combs, match, fxo[mU], gen_frames, field);
+ match = checkmm(ctx, combs, match, fxo[mB], gen_frames, field);
+ break;
+ /* 3-way p/c/n matches */
+ case MODE_PCN:
+ match = checkmm(ctx, combs, match, match == fxo[mP] ? fxo[mC] : fxo[mP], gen_frames, field);
+ break;
+ case MODE_PCN_UB:
+ match = checkmm(ctx, combs, match, fxo[mU], gen_frames, field);
+ match = checkmm(ctx, combs, match, fxo[mB], gen_frames, field);
+ break;
+ default:
+ av_assert0(0);
+ }
+ }
+
+ /* get output frame and drop the others */
+ if (fm->ppsrc) {
+ /* field matching was based on a filtered/post-processed input, we now
+ * pick the untouched fields from the clean source */
+ dst = create_weave_frame(ctx, match, field, fm->prv2, fm->src2, fm->nxt2);
+ } else {
+ if (!gen_frames[match]) { // XXX: is that possible?
+ dst = create_weave_frame(ctx, match, field, fm->prv, fm->src, fm->nxt);
+ } else {
+ dst = gen_frames[match];
+ gen_frames[match] = NULL;
+ }
+ }
+ if (!dst)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < FF_ARRAY_ELEMS(gen_frames); i++)
+ av_frame_free(&gen_frames[i]);
+
+ /* mark the frame we are unable to match properly as interlaced so a proper
+ * de-interlacer can take the relay */
+ dst->interlaced_frame = combs[match] >= fm->combpel;
+ if (dst->interlaced_frame) {
+ av_log(ctx, AV_LOG_WARNING, "Frame #%"PRId64" at %s is still interlaced\n",
+ outlink->frame_count, av_ts2timestr(in->pts, &inlink->time_base));
+ dst->top_field_first = field;
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "SC:%d | COMBS: %3d %3d %3d %3d %3d (combpel=%d)"
+ " match=%d combed=%s\n", sc, combs[0], combs[1], combs[2], combs[3], combs[4],
+ fm->combpel, match, dst->interlaced_frame ? "YES" : "NO");
+
+ return ff_filter_frame(outlink, dst);
+}
+
+static int request_inlink(AVFilterContext *ctx, int lid)
+{
+ int ret = 0;
+ FieldMatchContext *fm = ctx->priv;
+
+ if (!fm->got_frame[lid]) {
+ AVFilterLink *inlink = ctx->inputs[lid];
+ ret = ff_request_frame(inlink);
+ if (ret == AVERROR_EOF) { // flushing
+ fm->eof |= 1 << lid;
+ ret = filter_frame(inlink, NULL);
+ }
+ }
+ return ret;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ int ret;
+ AVFilterContext *ctx = outlink->src;
+ FieldMatchContext *fm = ctx->priv;
+ const uint32_t eof_mask = 1<<INPUT_MAIN | fm->ppsrc<<INPUT_CLEANSRC;
+
+ if ((fm->eof & eof_mask) == eof_mask) // flush done?
+ return AVERROR_EOF;
+ if ((ret = request_inlink(ctx, INPUT_MAIN)) < 0)
+ return ret;
+ if (fm->ppsrc && (ret = request_inlink(ctx, INPUT_CLEANSRC)) < 0)
+ return ret;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ // TODO: second input source can support >8bit depth
+ 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_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ int ret;
+ AVFilterContext *ctx = inlink->dst;
+ FieldMatchContext *fm = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+ const int w = inlink->w;
+ const int h = inlink->h;
+
+ fm->scthresh = (int64_t)((w * h * 255.0 * fm->scthresh_flt) / 100.0);
+
+ if ((ret = av_image_alloc(fm->map_data, fm->map_linesize, w, h, inlink->format, 32)) < 0 ||
+ (ret = av_image_alloc(fm->cmask_data, fm->cmask_linesize, w, h, inlink->format, 32)) < 0)
+ return ret;
+
+ fm->hsub = pix_desc->log2_chroma_w;
+ fm->vsub = pix_desc->log2_chroma_h;
+
+ fm->tpitchy = FFALIGN(w, 16);
+ fm->tpitchuv = FFALIGN(w >> 1, 16);
+
+ fm->tbuffer = av_malloc(h/2 * fm->tpitchy);
+ fm->c_array = av_malloc((((w + fm->blockx/2)/fm->blockx)+1) *
+ (((h + fm->blocky/2)/fm->blocky)+1) *
+ 4 * sizeof(*fm->c_array));
+ if (!fm->tbuffer || !fm->c_array)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static av_cold int fieldmatch_init(AVFilterContext *ctx)
+{
+ const FieldMatchContext *fm = ctx->priv;
+ AVFilterPad pad = {
+ .name = av_strdup("main"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ };
+
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ ff_insert_inpad(ctx, INPUT_MAIN, &pad);
+
+ if (fm->ppsrc) {
+ pad.name = av_strdup("clean_src");
+ pad.config_props = NULL;
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ ff_insert_inpad(ctx, INPUT_CLEANSRC, &pad);
+ }
+
+ if ((fm->blockx & (fm->blockx - 1)) ||
+ (fm->blocky & (fm->blocky - 1))) {
+ av_log(ctx, AV_LOG_ERROR, "blockx and blocky settings must be power of two\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (fm->combpel > fm->blockx * fm->blocky) {
+ av_log(ctx, AV_LOG_ERROR, "Combed pixel should not be larger than blockx x blocky\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static av_cold void fieldmatch_uninit(AVFilterContext *ctx)
+{
+ int i;
+ FieldMatchContext *fm = ctx->priv;
+
+ if (fm->prv != fm->src)
+ av_frame_free(&fm->prv);
+ if (fm->nxt != fm->src)
+ av_frame_free(&fm->nxt);
+ av_frame_free(&fm->src);
+ av_freep(&fm->map_data[0]);
+ av_freep(&fm->cmask_data[0]);
+ av_freep(&fm->tbuffer);
+ av_freep(&fm->c_array);
+ for (i = 0; i < ctx->nb_inputs; i++)
+ av_freep(&ctx->input_pads[i].name);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ const FieldMatchContext *fm = ctx->priv;
+ const AVFilterLink *inlink =
+ ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN];
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ outlink->time_base = inlink->time_base;
+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+ outlink->frame_rate = inlink->frame_rate;
+ outlink->w = inlink->w;
+ outlink->h = inlink->h;
+ return 0;
+}
+
+static const AVFilterPad fieldmatch_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_fieldmatch = {
+ .name = "fieldmatch",
+ .description = NULL_IF_CONFIG_SMALL("Field matching for inverse telecine."),
+ .query_formats = query_formats,
+ .priv_size = sizeof(FieldMatchContext),
+ .init = fieldmatch_init,
+ .uninit = fieldmatch_uninit,
+ .inputs = NULL,
+ .outputs = fieldmatch_outputs,
+ .priv_class = &fieldmatch_class,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
diff --git a/libavfilter/vf_fieldorder.c b/libavfilter/vf_fieldorder.c
index dd4f8cc694..d0d68071fd 100644
--- a/libavfilter/vf_fieldorder.c
+++ b/libavfilter/vf_fieldorder.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mark Himsley
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,9 +23,6 @@
* video field order filter, heavily influenced by vf_pad.c
*/
-#include <stdio.h>
-#include <string.h>
-
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/opt.h"
@@ -55,6 +52,7 @@ static int query_formats(AVFilterContext *ctx)
while ((desc = av_pix_fmt_desc_next(desc))) {
pix_fmt = av_pix_fmt_desc_get_id(desc);
if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
+ desc->flags & AV_PIX_FMT_FLAG_PAL ||
desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) &&
desc->nb_components && !desc->log2_chroma_h &&
(ret = ff_add_format(&formats, pix_fmt)) < 0) {
@@ -73,16 +71,8 @@ static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
FieldOrderContext *s = ctx->priv;
- int plane;
-
- /** full an array with the number of bytes that the video
- * data occupies per line for each plane of the input video */
- for (plane = 0; plane < 4; plane++) {
- s->line_size[plane] = av_image_get_linesize(inlink->format, inlink->w,
- plane);
- }
- return 0;
+ return av_image_fill_linesizes(s->line_size, inlink->format, inlink->w);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
@@ -90,8 +80,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
AVFilterContext *ctx = inlink->dst;
FieldOrderContext *s = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0];
- int h, plane, line_step, line_size, line;
- uint8_t *data;
+ int h, plane, src_line_step, dst_line_step, line_size, line;
+ uint8_t *dst, *src;
+ AVFrame *out;
if (!frame->interlaced_frame ||
frame->top_field_first == s->dst_tff) {
@@ -102,14 +93,27 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
return ff_filter_frame(outlink, frame);
}
+ if (av_frame_is_writable(frame)) {
+ out = frame;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&frame);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, frame);
+ }
+
av_log(ctx, AV_LOG_TRACE,
"picture will move %s one line\n",
s->dst_tff ? "up" : "down");
h = frame->height;
- for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
- line_step = frame->linesize[plane];
+ for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) {
+ dst_line_step = out->linesize[plane];
+ src_line_step = frame->linesize[plane];
line_size = s->line_size[plane];
- data = frame->data[plane];
+ dst = out->data[plane];
+ src = frame->data[plane];
if (s->dst_tff) {
/** Move every line up one line, working from
* the top to the bottom of the frame.
@@ -118,11 +122,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
* penultimate line from that field. */
for (line = 0; line < h; line++) {
if (1 + line < frame->height) {
- memcpy(data, data + line_step, line_size);
+ memcpy(dst, src + src_line_step, line_size);
} else {
- memcpy(data, data - line_step - line_step, line_size);
+ memcpy(dst, src - 2 * src_line_step, line_size);
}
- data += line_step;
+ dst += dst_line_step;
+ src += src_line_step;
}
} else {
/** Move every line down one line, working from
@@ -130,45 +135,44 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
* The original bottom line is lost.
* The new first line is created as a copy of the
* second line from that field. */
- data += (h - 1) * line_step;
+ dst += (h - 1) * dst_line_step;
+ src += (h - 1) * src_line_step;
for (line = h - 1; line >= 0 ; line--) {
if (line > 0) {
- memcpy(data, data - line_step, line_size);
+ memcpy(dst, src - src_line_step, line_size);
} else {
- memcpy(data, data + line_step + line_step, line_size);
+ memcpy(dst, src + 2 * src_line_step, line_size);
}
- data -= line_step;
+ dst -= dst_line_step;
+ src -= src_line_step;
}
}
}
- frame->top_field_first = s->dst_tff;
+ out->top_field_first = s->dst_tff;
- return ff_filter_frame(outlink, frame);
+ if (frame != out)
+ av_frame_free(&frame);
+ return ff_filter_frame(outlink, out);
}
#define OFFSET(x) offsetof(FieldOrderContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption fieldorder_options[] = {
{ "order", "output field order", OFFSET(dst_tff), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS, "order" },
- { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .unit = "order" },
- { "tff", "top field first", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .unit = "order" },
- { NULL },
+ { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .flags=FLAGS, .unit = "order" },
+ { "tff", "top field first", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .flags=FLAGS, .unit = "order" },
+ { NULL }
};
-static const AVClass fieldorder_class = {
- .class_name = "fieldorder",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(fieldorder);
static const AVFilterPad avfilter_vf_fieldorder_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_input,
- .filter_frame = filter_frame,
- .needs_writable = 1,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -189,4 +193,5 @@ AVFilter ff_vf_fieldorder = {
.query_formats = query_formats,
.inputs = avfilter_vf_fieldorder_inputs,
.outputs = avfilter_vf_fieldorder_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_find_rect.c b/libavfilter/vf_find_rect.c
new file mode 100644
index 0000000000..a4631deed4
--- /dev/null
+++ b/libavfilter/vf_find_rect.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2014-2015 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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.
+ */
+
+/**
+ * @todo switch to dualinput
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+
+#include "lavfutils.h"
+
+#define MAX_MIPMAPS 5
+
+typedef struct FOCContext {
+ AVClass *class;
+ float threshold;
+ int mipmaps;
+ int xmin, ymin, xmax, ymax;
+ char *obj_filename;
+ int last_x, last_y;
+ AVFrame *obj_frame;
+ AVFrame *needle_frame[MAX_MIPMAPS];
+ AVFrame *haystack_frame[MAX_MIPMAPS];
+} FOCContext;
+
+#define OFFSET(x) offsetof(FOCContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption foc_options[] = {
+ { "object", "object bitmap filename", OFFSET(obj_filename), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
+ { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_FLOAT, {.dbl = 0.5}, 0, 1.0, FLAGS },
+ { "mipmaps", "set mipmaps", OFFSET(mipmaps), AV_OPT_TYPE_INT, {.i64 = 3}, 1, MAX_MIPMAPS, FLAGS },
+ { "xmin", "", OFFSET(xmin), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
+ { "ymin", "", OFFSET(ymin), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
+ { "xmax", "", OFFSET(xmax), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
+ { "ymax", "", OFFSET(ymax), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
+ { NULL }
+};
+
+static const AVClass foc_class = {
+ .class_name = "find_rect",
+ .item_name = av_default_item_name,
+ .option = foc_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_NONE
+ };
+
+ return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
+}
+
+static AVFrame *downscale(AVFrame *in)
+{
+ int x, y;
+ AVFrame *frame = av_frame_alloc();
+ uint8_t *src, *dst;
+ if (!frame)
+ return NULL;
+
+ frame->format = in->format;
+ frame->width = (in->width + 1) / 2;
+ frame->height = (in->height+ 1) / 2;
+
+ if (av_frame_get_buffer(frame, 32) < 0) {
+ av_frame_free(&frame);
+ return NULL;
+ }
+ src = in ->data[0];
+ dst = frame->data[0];
+
+ for(y = 0; y < frame->height; y++) {
+ for(x = 0; x < frame->width; x++) {
+ dst[x] = ( src[2*x+0]
+ + src[2*x+1]
+ + src[2*x+0 + in->linesize[0]]
+ + src[2*x+1 + in->linesize[0]]
+ + 2) >> 2;
+ }
+ src += 2*in->linesize[0];
+ dst += frame->linesize[0];
+ }
+ return frame;
+}
+
+static float compare(const AVFrame *haystack, const AVFrame *obj, int offx, int offy)
+{
+ int x,y;
+ int o_sum_v = 0;
+ int h_sum_v = 0;
+ int64_t oo_sum_v = 0;
+ int64_t hh_sum_v = 0;
+ int64_t oh_sum_v = 0;
+ float c;
+ int n = obj->height * obj->width;
+ const uint8_t *odat = obj ->data[0];
+ const uint8_t *hdat = haystack->data[0] + offx + offy * haystack->linesize[0];
+ int64_t o_sigma, h_sigma;
+
+ for(y = 0; y < obj->height; y++) {
+ for(x = 0; x < obj->width; x++) {
+ int o_v = odat[x];
+ int h_v = hdat[x];
+ o_sum_v += o_v;
+ h_sum_v += h_v;
+ oo_sum_v += o_v * o_v;
+ hh_sum_v += h_v * h_v;
+ oh_sum_v += o_v * h_v;
+ }
+ odat += obj->linesize[0];
+ hdat += haystack->linesize[0];
+ }
+ o_sigma = n*oo_sum_v - o_sum_v*(int64_t)o_sum_v;
+ h_sigma = n*hh_sum_v - h_sum_v*(int64_t)h_sum_v;
+
+ if (o_sigma == 0 || h_sigma == 0)
+ return 1.0;
+
+ c = (n*oh_sum_v - o_sum_v*(int64_t)h_sum_v) / (sqrt(o_sigma)*sqrt(h_sigma));
+
+ return 1 - fabs(c);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ FOCContext *foc = ctx->priv;
+
+ if (foc->xmax <= 0)
+ foc->xmax = inlink->w - foc->obj_frame->width;
+ if (foc->ymax <= 0)
+ foc->ymax = inlink->h - foc->obj_frame->height;
+
+ return 0;
+}
+
+static float search(FOCContext *foc, int pass, int maxpass, int xmin, int xmax, int ymin, int ymax, int *best_x, int *best_y, float best_score)
+{
+ int x, y;
+
+ if (pass + 1 <= maxpass) {
+ int sub_x, sub_y;
+ search(foc, pass+1, maxpass, xmin>>1, (xmax+1)>>1, ymin>>1, (ymax+1)>>1, &sub_x, &sub_y, 1.0);
+ xmin = FFMAX(xmin, 2*sub_x - 4);
+ xmax = FFMIN(xmax, 2*sub_x + 4);
+ ymin = FFMAX(ymin, 2*sub_y - 4);
+ ymax = FFMIN(ymax, 2*sub_y + 4);
+ }
+
+ for (y = ymin; y <= ymax; y++) {
+ for (x = xmin; x <= xmax; x++) {
+ float score = compare(foc->haystack_frame[pass], foc->needle_frame[pass], x, y);
+ av_assert0(score != 0);
+ if (score < best_score) {
+ best_score = score;
+ *best_x = x;
+ *best_y = y;
+ }
+ }
+ }
+ return best_score;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ FOCContext *foc = ctx->priv;
+ float best_score;
+ int best_x, best_y;
+ int i;
+
+ foc->haystack_frame[0] = av_frame_clone(in);
+ for (i=1; i<foc->mipmaps; i++) {
+ foc->haystack_frame[i] = downscale(foc->haystack_frame[i-1]);
+ }
+
+ best_score = search(foc, 0, 0,
+ FFMAX(foc->xmin, foc->last_x - 8),
+ FFMIN(foc->xmax, foc->last_x + 8),
+ FFMAX(foc->ymin, foc->last_y - 8),
+ FFMIN(foc->ymax, foc->last_y + 8),
+ &best_x, &best_y, 1.0);
+
+ best_score = search(foc, 0, foc->mipmaps - 1, foc->xmin, foc->xmax, foc->ymin, foc->ymax,
+ &best_x, &best_y, best_score);
+
+ for (i=0; i<MAX_MIPMAPS; i++) {
+ av_frame_free(&foc->haystack_frame[i]);
+ }
+
+ if (best_score > foc->threshold) {
+ return ff_filter_frame(ctx->outputs[0], in);
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "Found at %d %d score %f\n", best_x, best_y, best_score);
+ foc->last_x = best_x;
+ foc->last_y = best_y;
+
+ av_frame_make_writable(in);
+
+ av_dict_set_int(&in->metadata, "lavfi.rect.w", foc->obj_frame->width, 0);
+ av_dict_set_int(&in->metadata, "lavfi.rect.h", foc->obj_frame->height, 0);
+ av_dict_set_int(&in->metadata, "lavfi.rect.x", best_x, 0);
+ av_dict_set_int(&in->metadata, "lavfi.rect.y", best_y, 0);
+
+ return ff_filter_frame(ctx->outputs[0], in);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ FOCContext *foc = ctx->priv;
+ int i;
+
+ for (i = 0; i < MAX_MIPMAPS; i++) {
+ av_frame_free(&foc->needle_frame[i]);
+ av_frame_free(&foc->haystack_frame[i]);
+ }
+
+ if (foc->obj_frame)
+ av_freep(&foc->obj_frame->data[0]);
+ av_frame_free(&foc->obj_frame);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ FOCContext *foc = ctx->priv;
+ int ret, i;
+
+ if (!foc->obj_filename) {
+ av_log(ctx, AV_LOG_ERROR, "object filename not set\n");
+ return AVERROR(EINVAL);
+ }
+
+ foc->obj_frame = av_frame_alloc();
+ if (!foc->obj_frame)
+ return AVERROR(ENOMEM);
+
+ if ((ret = ff_load_image(foc->obj_frame->data, foc->obj_frame->linesize,
+ &foc->obj_frame->width, &foc->obj_frame->height,
+ &foc->obj_frame->format, foc->obj_filename, ctx)) < 0)
+ return ret;
+
+ if (foc->obj_frame->format != AV_PIX_FMT_GRAY8) {
+ av_log(ctx, AV_LOG_ERROR, "object image is not a grayscale image\n");
+ return AVERROR(EINVAL);
+ }
+
+ foc->needle_frame[0] = av_frame_clone(foc->obj_frame);
+ for (i = 1; i < foc->mipmaps; i++) {
+ foc->needle_frame[i] = downscale(foc->needle_frame[i-1]);
+ if (!foc->needle_frame[i])
+ return AVERROR(ENOMEM);
+ }
+
+ return 0;
+}
+
+static const AVFilterPad foc_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad foc_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_find_rect = {
+ .name = "find_rect",
+ .description = NULL_IF_CONFIG_SMALL("Find a user specified object"),
+ .priv_size = sizeof(FOCContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = foc_inputs,
+ .outputs = foc_outputs,
+ .priv_class = &foc_class,
+};
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index 914089deab..1fb3442af1 100644
--- a/libavfilter/vf_format.c
+++ b/libavfilter/vf_format.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,6 +58,7 @@ static av_cold int init(AVFilterContext *ctx)
char *cur, *sep;
int nb_formats = 1;
int i;
+ int ret;
if (!s->pix_fmts) {
av_log(ctx, AV_LOG_ERROR, "Empty output format string.\n");
@@ -83,11 +84,8 @@ static av_cold int init(AVFilterContext *ctx)
if (sep)
*sep++ = 0;
- s->formats[i] = av_get_pix_fmt(cur);
- if (s->formats[i] == AV_PIX_FMT_NONE) {
- av_log(ctx, AV_LOG_ERROR, "Unknown pixel format: %s\n", cur);
- return AVERROR(EINVAL);
- }
+ if ((ret = ff_parse_pixel_format(&s->formats[i], cur, ctx)) < 0)
+ return ret;
cur = sep;
}
@@ -96,7 +94,7 @@ static av_cold int init(AVFilterContext *ctx)
if (!strcmp(ctx->filter->name, "noformat")) {
const AVPixFmtDescriptor *desc = NULL;
enum AVPixelFormat *formats_allowed;
- int nb_formats_lavu = 0, nb_formats_allowed = 0;;
+ int nb_formats_lavu = 0, nb_formats_allowed = 0;
/* count the formats known to lavu */
while ((desc = av_pix_fmt_desc_next(desc)))
@@ -136,24 +134,20 @@ static int query_formats(AVFilterContext *ctx)
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_formats(ctx, formats);
- return 0;
+ return ff_set_common_formats(ctx, formats);
}
#define OFFSET(x) offsetof(FormatContext, x)
static const AVOption options[] = {
{ "pix_fmts", "A '|'-separated list of pixel formats", OFFSET(pix_fmts), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM },
- { NULL },
+ { NULL }
};
#if CONFIG_FORMAT_FILTER
-static const AVClass format_class = {
- .class_name = "format",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+
+#define format_options options
+AVFILTER_DEFINE_CLASS(format);
static const AVFilterPad avfilter_vf_format_inputs[] = {
{
@@ -173,29 +167,26 @@ static const AVFilterPad avfilter_vf_format_outputs[] = {
};
AVFilter ff_vf_format = {
- .name = "format",
- .description = NULL_IF_CONFIG_SMALL("Convert the input video to one of the specified pixel formats."),
+ .name = "format",
+ .description = NULL_IF_CONFIG_SMALL("Convert the input video to one of the specified pixel formats."),
- .init = init,
- .uninit = uninit,
+ .init = init,
+ .uninit = uninit,
.query_formats = query_formats,
- .priv_size = sizeof(FormatContext),
- .priv_class = &format_class,
+ .priv_size = sizeof(FormatContext),
+ .priv_class = &format_class,
- .inputs = avfilter_vf_format_inputs,
- .outputs = avfilter_vf_format_outputs,
+ .inputs = avfilter_vf_format_inputs,
+ .outputs = avfilter_vf_format_outputs,
};
#endif /* CONFIG_FORMAT_FILTER */
#if CONFIG_NOFORMAT_FILTER
-static const AVClass noformat_class = {
- .class_name = "noformat",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+
+#define noformat_options options
+AVFILTER_DEFINE_CLASS(noformat);
static const AVFilterPad avfilter_vf_noformat_inputs[] = {
{
@@ -215,18 +206,18 @@ static const AVFilterPad avfilter_vf_noformat_outputs[] = {
};
AVFilter ff_vf_noformat = {
- .name = "noformat",
- .description = NULL_IF_CONFIG_SMALL("Force libavfilter not to use any of the specified pixel formats for the input to the next filter."),
+ .name = "noformat",
+ .description = NULL_IF_CONFIG_SMALL("Force libavfilter not to use any of the specified pixel formats for the input to the next filter."),
- .init = init,
- .uninit = uninit,
+ .init = init,
+ .uninit = uninit,
.query_formats = query_formats,
- .priv_size = sizeof(FormatContext),
- .priv_class = &noformat_class,
+ .priv_size = sizeof(FormatContext),
+ .priv_class = &noformat_class,
- .inputs = avfilter_vf_noformat_inputs,
- .outputs = avfilter_vf_noformat_outputs,
+ .inputs = avfilter_vf_noformat_inputs,
+ .outputs = avfilter_vf_noformat_outputs,
};
#endif /* CONFIG_NOFORMAT_FILTER */
diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c
index ea22d37b54..6154f6d43e 100644
--- a/libavfilter/vf_fps.c
+++ b/libavfilter/vf_fps.c
@@ -1,18 +1,22 @@
/*
- * This file is part of Libav.
+ * Copyright 2007 Bobby Bingham
+ * Copyright 2012 Robert Nagy <ronag89 gmail com>
+ * Copyright 2012 Anton Khirnov <anton khirnov net>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,12 +45,11 @@ typedef struct FPSContext {
/* timestamps in input timebase */
int64_t first_pts; ///< pts of the first frame that arrived on this filter
- int64_t pts; ///< pts of the first frame currently in the fifo
double start_time; ///< pts, in seconds, of the expected first frame
AVRational framerate; ///< target framerate
- char *fps; ///< a string describing target framerate
+ int rounding; ///< AVRounding method for timestamps
/* statistics */
int frames_in; ///< number of frames on input
@@ -57,33 +60,28 @@ typedef struct FPSContext {
#define OFFSET(x) offsetof(FPSContext, x)
#define V AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "fps", "A string describing desired output framerate", OFFSET(fps), AV_OPT_TYPE_STRING, { .str = "25" }, .flags = V },
+#define F AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption fps_options[] = {
+ { "fps", "A string describing desired output framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, .flags = V|F },
{ "start_time", "Assume the first PTS should be this value.", OFFSET(start_time), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX}, -DBL_MAX, DBL_MAX, V },
- { NULL },
+ { "round", "set rounding method for timestamps", OFFSET(rounding), AV_OPT_TYPE_INT, { .i64 = AV_ROUND_NEAR_INF }, 0, 5, V|F, "round" },
+ { "zero", "round towards 0", OFFSET(rounding), AV_OPT_TYPE_CONST, { .i64 = AV_ROUND_ZERO }, 0, 5, V|F, "round" },
+ { "inf", "round away from 0", OFFSET(rounding), AV_OPT_TYPE_CONST, { .i64 = AV_ROUND_INF }, 0, 5, V|F, "round" },
+ { "down", "round towards -infty", OFFSET(rounding), AV_OPT_TYPE_CONST, { .i64 = AV_ROUND_DOWN }, 0, 5, V|F, "round" },
+ { "up", "round towards +infty", OFFSET(rounding), AV_OPT_TYPE_CONST, { .i64 = AV_ROUND_UP }, 0, 5, V|F, "round" },
+ { "near", "round to nearest", OFFSET(rounding), AV_OPT_TYPE_CONST, { .i64 = AV_ROUND_NEAR_INF }, 0, 5, V|F, "round" },
+ { NULL }
};
-static const AVClass class = {
- .class_name = "FPS filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(fps);
static av_cold int init(AVFilterContext *ctx)
{
FPSContext *s = ctx->priv;
- int ret;
-
- if ((ret = av_parse_video_rate(&s->framerate, s->fps)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error parsing framerate %s.\n", s->fps);
- return ret;
- }
- if (!(s->fifo = av_fifo_alloc(2*sizeof(AVFrame*))))
+ if (!(s->fifo = av_fifo_alloc_array(2, sizeof(AVFrame*))))
return AVERROR(ENOMEM);
- s->pts = AV_NOPTS_VALUE;
s->first_pts = AV_NOPTS_VALUE;
av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", s->framerate.num, s->framerate.den);
@@ -105,7 +103,7 @@ static av_cold void uninit(AVFilterContext *ctx)
if (s->fifo) {
s->drop += av_fifo_size(s->fifo) / sizeof(AVFrame*);
flush_fifo(s->fifo);
- av_fifo_free(s->fifo);
+ av_fifo_freep(&s->fifo);
}
av_log(ctx, AV_LOG_VERBOSE, "%d frames in, %d frames out; %d frames dropped, "
@@ -116,7 +114,8 @@ static int config_props(AVFilterLink* link)
{
FPSContext *s = link->src->priv;
- link->time_base = (AVRational){ s->framerate.den, s->framerate.num };
+ link->time_base = av_inv_q(s->framerate);
+ link->frame_rate= s->framerate;
link->w = link->src->inputs[0]->w;
link->h = link->src->inputs[0]->h;
@@ -178,22 +177,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
s->frames_in++;
/* discard frames until we get the first timestamp */
- if (s->pts == AV_NOPTS_VALUE) {
+ if (s->first_pts == AV_NOPTS_VALUE) {
if (buf->pts != AV_NOPTS_VALUE) {
ret = write_to_fifo(s->fifo, buf);
if (ret < 0)
return ret;
- if (s->start_time != DBL_MAX) {
+ if (s->start_time != DBL_MAX && s->start_time != AV_NOPTS_VALUE) {
double first_pts = s->start_time * AV_TIME_BASE;
first_pts = FFMIN(FFMAX(first_pts, INT64_MIN), INT64_MAX);
- s->first_pts = s->pts = av_rescale_q(first_pts, AV_TIME_BASE_Q,
+ s->first_pts = av_rescale_q(first_pts, AV_TIME_BASE_Q,
inlink->time_base);
av_log(ctx, AV_LOG_VERBOSE, "Set first pts to (in:%"PRId64" out:%"PRId64")\n",
s->first_pts, av_rescale_q(first_pts, AV_TIME_BASE_Q,
outlink->time_base));
} else {
- s->first_pts = s->pts = buf->pts;
+ s->first_pts = buf->pts;
}
} else {
av_log(ctx, AV_LOG_WARNING, "Discarding initial frame(s) with no "
@@ -205,27 +204,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
}
/* now wait for the next timestamp */
- if (buf->pts == AV_NOPTS_VALUE) {
+ if (buf->pts == AV_NOPTS_VALUE || av_fifo_size(s->fifo) <= 0) {
return write_to_fifo(s->fifo, buf);
}
/* number of output frames */
- delta = av_rescale_q(buf->pts - s->pts, inlink->time_base,
- outlink->time_base);
+ delta = av_rescale_q_rnd(buf->pts - s->first_pts, inlink->time_base,
+ outlink->time_base, s->rounding) - s->frames_out ;
if (delta < 1) {
- /* drop the frame and everything buffered except the first */
- AVFrame *tmp;
+ /* drop everything buffered except the last */
int drop = av_fifo_size(s->fifo)/sizeof(AVFrame*);
av_log(ctx, AV_LOG_DEBUG, "Dropping %d frame(s).\n", drop);
s->drop += drop;
- av_fifo_generic_read(s->fifo, &tmp, sizeof(tmp), NULL);
flush_fifo(s->fifo);
- ret = write_to_fifo(s->fifo, tmp);
+ ret = write_to_fifo(s->fifo, buf);
- av_frame_free(&buf);
return ret;
}
@@ -266,15 +262,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
flush_fifo(s->fifo);
ret = write_to_fifo(s->fifo, buf);
- s->pts = s->first_pts + av_rescale_q(s->frames_out, outlink->time_base, inlink->time_base);
return ret;
}
static const AVFilterPad avfilter_vf_fps_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
},
{ NULL }
@@ -292,14 +287,11 @@ static const AVFilterPad avfilter_vf_fps_outputs[] = {
AVFilter ff_vf_fps = {
.name = "fps",
- .description = NULL_IF_CONFIG_SMALL("Force constant framerate"),
-
- .init = init,
- .uninit = uninit,
-
- .priv_size = sizeof(FPSContext),
- .priv_class = &class,
-
- .inputs = avfilter_vf_fps_inputs,
- .outputs = avfilter_vf_fps_outputs,
+ .description = NULL_IF_CONFIG_SMALL("Force constant framerate."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(FPSContext),
+ .priv_class = &fps_class,
+ .inputs = avfilter_vf_fps_inputs,
+ .outputs = avfilter_vf_fps_outputs,
};
diff --git a/libavfilter/vf_framepack.c b/libavfilter/vf_framepack.c
index f5c761a66d..e9b9ed1362 100644
--- a/libavfilter/vf_framepack.c
+++ b/libavfilter/vf_framepack.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 Vittorio Giovara
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,8 +61,10 @@ static const enum AVPixelFormat formats_supported[] = {
static int query_formats(AVFilterContext *ctx)
{
// this will ensure that formats are the same on all pads
- ff_set_common_formats(ctx, ff_make_format_list(formats_supported));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(formats_supported);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static av_cold void framepack_uninit(AVFilterContext *ctx)
@@ -82,6 +84,7 @@ static int config_output(AVFilterLink *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;
// check size and fps match on the other input
if (width != ctx->inputs[RIGHT]->w ||
@@ -93,11 +96,18 @@ static int config_output(AVFilterLink *outlink)
return AVERROR_INVALIDDATA;
} else if (av_cmp_q(time_base, ctx->inputs[RIGHT]->time_base) != 0) {
av_log(ctx, AV_LOG_ERROR,
- "Left and right framerates differ (%d/%d vs %d/%d).\n",
+ "Left and right time bases differ (%d/%d vs %d/%d).\n",
time_base.num, time_base.den,
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) {
+ 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);
+ return AVERROR_INVALIDDATA;
}
s->pix_desc = av_pix_fmt_desc_get(outlink->format);
@@ -108,6 +118,8 @@ static int config_output(AVFilterLink *outlink)
switch (s->format) {
case AV_STEREO3D_FRAMESEQUENCE:
time_base.den *= 2;
+ frame_rate.num *= 2;
+
s->double_pts = AV_NOPTS_VALUE;
break;
case AV_STEREO3D_COLUMNS:
@@ -126,6 +138,7 @@ static int config_output(AVFilterLink *outlink)
outlink->w = width;
outlink->h = height;
outlink->time_base = time_base;
+ outlink->frame_rate= frame_rate;
return 0;
}
@@ -144,8 +157,8 @@ static void horizontal_frame_pack(FramepackContext *s,
uint8_t *dstp = dst->data[plane];
if (plane == 1 || plane == 2) {
- length = -(-(dst->width / 2) >> s->pix_desc->log2_chroma_w);
- lines = -(-(dst->height) >> s->pix_desc->log2_chroma_h);
+ length = FF_CEIL_RSHIFT(dst->width / 2, s->pix_desc->log2_chroma_w);
+ lines = FF_CEIL_RSHIFT(dst->height, s->pix_desc->log2_chroma_h);
}
if (interleaved) {
diff --git a/libavfilter/vf_framestep.c b/libavfilter/vf_framestep.c
new file mode 100644
index 0000000000..09945e17ae
--- /dev/null
+++ b/libavfilter/vf_framestep.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 framestep filter, inspired on libmpcodecs/vf_framestep.c by
+ * Daniele Fornighieri <guru AT digitalfantasy it>.
+ */
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct NullContext {
+ const AVClass *class;
+ int frame_step;
+} FrameStepContext;
+
+#define OFFSET(x) offsetof(FrameStepContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption framestep_options[] = {
+ { "step", "set frame step", OFFSET(frame_step), AV_OPT_TYPE_INT, {.i64=1}, 1, INT_MAX, FLAGS},
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(framestep);
+
+static int config_output_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ FrameStepContext *framestep = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ outlink->frame_rate =
+ av_div_q(inlink->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));
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *ref)
+{
+ FrameStepContext *framestep = inlink->dst->priv;
+
+ if (!(inlink->frame_count % framestep->frame_step)) {
+ return ff_filter_frame(inlink->dst->outputs[0], ref);
+ } else {
+ av_frame_free(&ref);
+ return 0;
+ }
+}
+
+static const AVFilterPad framestep_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad framestep_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_framestep = {
+ .name = "framestep",
+ .description = NULL_IF_CONFIG_SMALL("Select one frame every N frames."),
+ .priv_size = sizeof(FrameStepContext),
+ .priv_class = &framestep_class,
+ .inputs = framestep_inputs,
+ .outputs = framestep_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index 0122b8d905..bbefe51c0f 100644
--- a/libavfilter/vf_frei0r.c
+++ b/libavfilter/vf_frei0r.c
@@ -1,19 +1,19 @@
/*
* Copyright (c) 2010 Stefano Sabatini
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include "config.h"
#include "libavutil/avstring.h"
+#include "libavutil/common.h"
#include "libavutil/imgutils.h"
#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
@@ -67,8 +68,7 @@ typedef struct Frei0rContext {
char *dl_name;
char *params;
- char *size;
- char *framerate;
+ AVRational framerate;
/* only used by the source */
int w, h;
@@ -139,6 +139,9 @@ static int set_params(AVFilterContext *ctx, const char *params)
Frei0rContext *s = ctx->priv;
int i;
+ if (!params)
+ return 0;
+
for (i = 0; i < s->plugin_info.num_params; i++) {
f0r_param_info_t info;
char *param;
@@ -172,7 +175,7 @@ static int set_params(AVFilterContext *ctx, const char *params)
switch (info.type) {
void *v;
double d;
- char s[128];
+ char str[128];
f0r_param_color_t col;
f0r_param_position_t pos;
@@ -197,9 +200,9 @@ static int set_params(AVFilterContext *ctx, const char *params)
av_log(ctx, AV_LOG_DEBUG, "%f/%f", pos.x, pos.y);
break;
default: /* F0R_PARAM_STRING */
- v = s;
+ v = str;
s->get_param_value(s->instance, v, i);
- av_log(ctx, AV_LOG_DEBUG, "'%s'", s);
+ av_log(ctx, AV_LOG_DEBUG, "'%s'", str);
break;
}
#endif
@@ -209,13 +212,15 @@ static int set_params(AVFilterContext *ctx, const char *params)
return 0;
}
-static void *load_path(AVFilterContext *ctx, const char *prefix, const char *name)
+static int load_path(AVFilterContext *ctx, void **handle_ptr, const char *prefix, const char *name)
{
- char path[1024];
-
- snprintf(path, sizeof(path), "%s%s%s", prefix, name, SLIBSUF);
+ char *path = av_asprintf("%s%s%s", prefix, name, SLIBSUF);
+ if (!path)
+ return AVERROR(ENOMEM);
av_log(ctx, AV_LOG_DEBUG, "Looking for frei0r effect in '%s'.\n", path);
- return dlopen(path, RTLD_NOW|RTLD_LOCAL);
+ *handle_ptr = dlopen(path, RTLD_NOW|RTLD_LOCAL);
+ av_free(path);
+ return 0;
}
static av_cold int frei0r_init(AVFilterContext *ctx,
@@ -226,35 +231,62 @@ static av_cold int frei0r_init(AVFilterContext *ctx,
f0r_get_plugin_info_f f0r_get_plugin_info;
f0r_plugin_info_t *pi;
char *path;
+ int ret = 0;
+ int i;
+ static const char* const frei0r_pathlist[] = {
+ "/usr/local/lib/frei0r-1/",
+ "/usr/lib/frei0r-1/",
+ "/usr/local/lib64/frei0r-1/",
+ "/usr/lib64/frei0r-1/"
+ };
if (!dl_name) {
av_log(ctx, AV_LOG_ERROR, "No filter name provided.\n");
return AVERROR(EINVAL);
}
- /* see: http://piksel.org/frei0r/1.2/spec/1.2/spec/group__pluglocations.html */
- if (path = getenv("FREI0R_PATH")) {
- while(*path) {
- char *ptr = av_get_token((const char **)&path, ":");
- if (!ptr)
- return AVERROR(ENOMEM);
- s->dl_handle = load_path(ctx, ptr, dl_name);
- av_freep(&ptr);
+ /* see: http://frei0r.dyne.org/codedoc/html/group__pluglocations.html */
+ if ((path = av_strdup(getenv("FREI0R_PATH")))) {
+#ifdef _WIN32
+ const char *separator = ";";
+#else
+ const char *separator = ":";
+#endif
+ char *p, *ptr = NULL;
+ for (p = path; p = av_strtok(p, separator, &ptr); p = NULL) {
+ /* add additional trailing slash in case it is missing */
+ char *p1 = av_asprintf("%s/", p);
+ if (!p1) {
+ ret = AVERROR(ENOMEM);
+ goto check_path_end;
+ }
+ ret = load_path(ctx, &s->dl_handle, p1, dl_name);
+ av_free(p1);
+ if (ret < 0)
+ goto check_path_end;
if (s->dl_handle)
- break; /* found */
- if (*path)
- path++; /* skip ':' */
+ break;
}
+
+ check_path_end:
+ av_free(path);
+ if (ret < 0)
+ return ret;
}
if (!s->dl_handle && (path = getenv("HOME"))) {
- char prefix[1024];
- snprintf(prefix, sizeof(prefix), "%s/.frei0r-1/lib/", path);
- s->dl_handle = load_path(ctx, prefix, dl_name);
+ char *prefix = av_asprintf("%s/.frei0r-1/lib/", path);
+ if (!prefix)
+ return AVERROR(ENOMEM);
+ ret = load_path(ctx, &s->dl_handle, prefix, dl_name);
+ av_free(prefix);
+ if (ret < 0)
+ return ret;
+ }
+ for (i = 0; !s->dl_handle && i < FF_ARRAY_ELEMS(frei0r_pathlist); i++) {
+ ret = load_path(ctx, &s->dl_handle, frei0r_pathlist[i], dl_name);
+ if (ret < 0)
+ return ret;
}
- if (!s->dl_handle)
- s->dl_handle = load_path(ctx, "/usr/local/lib/frei0r-1/", dl_name);
- if (!s->dl_handle)
- s->dl_handle = load_path(ctx, "/usr/lib/frei0r-1/", dl_name);
if (!s->dl_handle) {
av_log(ctx, AV_LOG_ERROR, "Could not find module '%s'.\n", dl_name);
return AVERROR(EINVAL);
@@ -353,8 +385,7 @@ static int query_formats(AVFilterContext *ctx)
if (!formats)
return AVERROR(ENOMEM);
- ff_set_common_formats(ctx, formats);
- return 0;
+ return ff_set_common_formats(ctx, formats);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
@@ -380,19 +411,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(Frei0rContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption filter_options[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption frei0r_options[] = {
{ "filter_name", NULL, OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { NULL },
+ { NULL }
};
-static const AVClass filter_class = {
- .class_name = "frei0r",
- .item_name = av_default_item_name,
- .option = filter_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(frei0r);
static const AVFilterPad avfilter_vf_frei0r_inputs[] = {
{
@@ -413,38 +439,23 @@ static const AVFilterPad avfilter_vf_frei0r_outputs[] = {
};
AVFilter ff_vf_frei0r = {
- .name = "frei0r",
- .description = NULL_IF_CONFIG_SMALL("Apply a frei0r effect."),
-
+ .name = "frei0r",
+ .description = NULL_IF_CONFIG_SMALL("Apply a frei0r effect."),
.query_formats = query_formats,
- .init = filter_init,
- .uninit = uninit,
-
- .priv_size = sizeof(Frei0rContext),
- .priv_class = &filter_class,
-
- .inputs = avfilter_vf_frei0r_inputs,
-
- .outputs = avfilter_vf_frei0r_outputs,
+ .init = filter_init,
+ .uninit = uninit,
+ .priv_size = sizeof(Frei0rContext),
+ .priv_class = &frei0r_class,
+ .inputs = avfilter_vf_frei0r_inputs,
+ .outputs = avfilter_vf_frei0r_outputs,
};
static av_cold int source_init(AVFilterContext *ctx)
{
Frei0rContext *s = ctx->priv;
- AVRational frame_rate_q;
-
- if (av_parse_video_size(&s->w, &s->h, s->size) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'.\n", s->size);
- return AVERROR(EINVAL);
- }
- if (av_parse_video_rate(&frame_rate_q, s->framerate) < 0 ||
- frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'.\n", s->framerate);
- return AVERROR(EINVAL);
- }
- s->time_base.num = frame_rate_q.den;
- s->time_base.den = frame_rate_q.num;
+ s->time_base.num = s->framerate.den;
+ s->time_base.den = s->framerate.num;
return frei0r_init(ctx, s->dl_name, F0R_PLUGIN_TYPE_SOURCE);
}
@@ -459,6 +470,8 @@ 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);
+ outlink->sample_aspect_ratio = (AVRational){1,1};
if (s->destruct && s->instance)
s->destruct(s->instance);
@@ -491,20 +504,15 @@ static int source_request_frame(AVFilterLink *outlink)
return ff_filter_frame(outlink, frame);
}
-static const AVOption src_options[] = {
- { "size", "Dimensions of the generated video.", OFFSET(size), AV_OPT_TYPE_STRING, { .str = "" }, .flags = FLAGS },
- { "framerate", NULL, OFFSET(framerate), AV_OPT_TYPE_STRING, { .str = "25" }, .flags = FLAGS },
+static const AVOption frei0r_src_options[] = {
+ { "size", "Dimensions of the generated video.", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, { .str = "320x240" }, .flags = FLAGS },
+ { "framerate", NULL, OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, .flags = FLAGS },
{ "filter_name", NULL, OFFSET(dl_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ NULL },
};
-static const AVClass src_class = {
- .class_name = "frei0r_src",
- .item_name = av_default_item_name,
- .option = src_options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(frei0r_src);
static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = {
{
@@ -517,17 +525,13 @@ static const AVFilterPad avfilter_vsrc_frei0r_src_outputs[] = {
};
AVFilter ff_vsrc_frei0r_src = {
- .name = "frei0r_src",
- .description = NULL_IF_CONFIG_SMALL("Generate a frei0r source."),
-
- .priv_size = sizeof(Frei0rContext),
- .priv_class = &src_class,
- .init = source_init,
- .uninit = uninit,
-
+ .name = "frei0r_src",
+ .description = NULL_IF_CONFIG_SMALL("Generate a frei0r source."),
+ .priv_size = sizeof(Frei0rContext),
+ .priv_class = &frei0r_src_class,
+ .init = source_init,
+ .uninit = uninit,
.query_formats = query_formats,
-
- .inputs = NULL,
-
- .outputs = avfilter_vsrc_frei0r_src_outputs,
+ .inputs = NULL,
+ .outputs = avfilter_vsrc_frei0r_src_outputs,
};
diff --git a/libavfilter/vf_fspp.c b/libavfilter/vf_fspp.c
new file mode 100644
index 0000000000..7bdaa91b06
--- /dev/null
+++ b/libavfilter/vf_fspp.c
@@ -0,0 +1,693 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2005 Nikolaj Poroshin <porosh3@psu.ru>
+ * Copyright (c) 2014 Arwa Arif <arwaarif1994@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 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
+ * Fast Simple Post-processing filter
+ * This implementation is based on an algorithm described in
+ * "Aria Nosratinia Embedded Post-Processing for
+ * Enhancement of Compressed Images (1999)"
+ * (http://www.utdallas.edu/~aria/papers/vlsisp99.pdf)
+ * Further, with splitting (I)DCT into horizontal/vertical passes, one of
+ * them can be performed once per block, not per pixel. This allows for much
+ * higher speed.
+ *
+ * Originally written by Michael Niedermayer and Nikolaj for the MPlayer
+ * project, and ported by Arwa Arif for FFmpeg.
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+#include "vf_fspp.h"
+
+#define OFFSET(x) offsetof(FSPPContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption fspp_options[] = {
+ { "quality", "set quality", OFFSET(log2_count), AV_OPT_TYPE_INT, {.i64 = 4}, 4, MAX_LEVEL, FLAGS },
+ { "qp", "force a constant quantizer parameter", OFFSET(qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 64, FLAGS },
+ { "strength", "set filter strength", OFFSET(strength), AV_OPT_TYPE_INT, {.i64 = 0}, -15, 32, FLAGS },
+ { "use_bframe_qp", "use B-frames' QP", OFFSET(use_bframe_qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(fspp);
+
+DECLARE_ALIGNED(32, static const uint8_t, dither)[8][8] = {
+ { 0, 48, 12, 60, 3, 51, 15, 63, },
+ { 32, 16, 44, 28, 35, 19, 47, 31, },
+ { 8, 56, 4, 52, 11, 59, 7, 55, },
+ { 40, 24, 36, 20, 43, 27, 39, 23, },
+ { 2, 50, 14, 62, 1, 49, 13, 61, },
+ { 34, 18, 46, 30, 33, 17, 45, 29, },
+ { 10, 58, 6, 54, 9, 57, 5, 53, },
+ { 42, 26, 38, 22, 41, 25, 37, 21, },
+};
+
+static const short custom_threshold[64] = {
+// values (296) can't be too high
+// -it causes too big quant dependence
+// or maybe overflow(check), which results in some flashing
+ 71, 296, 295, 237, 71, 40, 38, 19,
+ 245, 193, 185, 121, 102, 73, 53, 27,
+ 158, 129, 141, 107, 97, 73, 50, 26,
+ 102, 116, 109, 98, 82, 66, 45, 23,
+ 71, 94, 95, 81, 70, 56, 38, 20,
+ 56, 77, 74, 66, 56, 44, 30, 15,
+ 38, 53, 50, 45, 38, 30, 21, 11,
+ 20, 27, 26, 23, 20, 15, 11, 5
+};
+
+//This func reads from 1 slice, 1 and clears 0 & 1
+static void store_slice_c(uint8_t *dst, int16_t *src,
+ ptrdiff_t dst_stride, ptrdiff_t src_stride,
+ ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale)
+{
+ int y, x;
+#define STORE(pos) \
+ temp = (src[x + pos] + (d[pos] >> log2_scale)) >> (6 - log2_scale); \
+ src[x + pos] = src[x + pos - 8 * src_stride] = 0; \
+ if (temp & 0x100) temp = ~(temp >> 31); \
+ dst[x + pos] = temp;
+
+ for (y = 0; y < height; y++) {
+ const uint8_t *d = dither[y];
+ for (x = 0; x < width; x += 8) {
+ int temp;
+ STORE(0);
+ STORE(1);
+ STORE(2);
+ STORE(3);
+ STORE(4);
+ STORE(5);
+ STORE(6);
+ STORE(7);
+ }
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+//This func reads from 2 slices, 0 & 2 and clears 2-nd
+static void store_slice2_c(uint8_t *dst, int16_t *src,
+ ptrdiff_t dst_stride, ptrdiff_t src_stride,
+ ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale)
+{
+ int y, x;
+#define STORE2(pos) \
+ temp = (src[x + pos] + src[x + pos + 16 * src_stride] + (d[pos] >> log2_scale)) >> (6 - log2_scale); \
+ src[x + pos + 16 * src_stride] = 0; \
+ if (temp & 0x100) temp = ~(temp >> 31); \
+ dst[x + pos] = temp;
+
+ for (y = 0; y < height; y++) {
+ const uint8_t *d = dither[y];
+ for (x = 0; x < width; x += 8) {
+ int temp;
+ STORE2(0);
+ STORE2(1);
+ STORE2(2);
+ STORE2(3);
+ STORE2(4);
+ STORE2(5);
+ STORE2(6);
+ STORE2(7);
+ }
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+static void mul_thrmat_c(int16_t *thr_adr_noq, int16_t *thr_adr, int q)
+{
+ int a;
+ for (a = 0; a < 64; a++)
+ thr_adr[a] = q * thr_adr_noq[a];
+}
+
+static void filter(FSPPContext *p, uint8_t *dst, uint8_t *src,
+ int dst_stride, int src_stride,
+ int width, int height,
+ uint8_t *qp_store, int qp_stride, int is_luma)
+{
+ int x, x0, y, es, qy, t;
+
+ const int stride = is_luma ? p->temp_stride : (width + 16);
+ const int step = 6 - p->log2_count;
+ const int qpsh = 4 - p->hsub * !is_luma;
+ const int qpsv = 4 - p->vsub * !is_luma;
+
+ DECLARE_ALIGNED(32, int32_t, block_align)[4 * 8 * BLOCKSZ + 4 * 8 * BLOCKSZ];
+ int16_t *block = (int16_t *)block_align;
+ int16_t *block3 = (int16_t *)(block_align + 4 * 8 * BLOCKSZ);
+
+ memset(block3, 0, 4 * 8 * BLOCKSZ);
+
+ if (!src || !dst) return;
+
+ for (y = 0; y < height; y++) {
+ int index = 8 + 8 * stride + y * stride;
+ memcpy(p->src + index, src + y * src_stride, width);
+ for (x = 0; x < 8; x++) {
+ p->src[index - x - 1] = p->src[index + x ];
+ p->src[index + width + x ] = p->src[index + width - x - 1];
+ }
+ }
+
+ for (y = 0; y < 8; y++) {
+ memcpy(p->src + ( 7 - y ) * stride, p->src + ( y + 8 ) * stride, stride);
+ memcpy(p->src + (height + 8 + y) * stride, p->src + (height - y + 7) * stride, stride);
+ }
+ //FIXME (try edge emu)
+
+ for (y = 8; y < 24; y++)
+ memset(p->temp + 8 + y * stride, 0, width * sizeof(int16_t));
+
+ for (y = step; y < height + 8; y += step) { //step= 1,2
+ const int y1 = y - 8 + step; //l5-7 l4-6;
+ qy = y - 4;
+
+ if (qy > height - 1) qy = height - 1;
+ if (qy < 0) qy = 0;
+
+ qy = (qy >> qpsv) * qp_stride;
+ p->row_fdct(block, p->src + y * stride + 2 - (y&1), stride, 2);
+
+ for (x0 = 0; x0 < width + 8 - 8 * (BLOCKSZ - 1); x0 += 8 * (BLOCKSZ - 1)) {
+ p->row_fdct(block + 8 * 8, p->src + y * stride + 8 + x0 + 2 - (y&1), stride, 2 * (BLOCKSZ - 1));
+
+ if (p->qp)
+ p->column_fidct((int16_t *)(&p->threshold_mtx[0]), block + 0 * 8, block3 + 0 * 8, 8 * (BLOCKSZ - 1)); //yes, this is a HOTSPOT
+ else
+ for (x = 0; x < 8 * (BLOCKSZ - 1); x += 8) {
+ t = x + x0 - 2; //correct t=x+x0-2-(y&1), but its the same
+
+ if (t < 0) t = 0; //t always < width-2
+
+ t = qp_store[qy + (t >> qpsh)];
+ t = ff_norm_qscale(t, p->qscale_type);
+
+ if (t != p->prev_q) p->prev_q = t, p->mul_thrmat((int16_t *)(&p->threshold_mtx_noq[0]), (int16_t *)(&p->threshold_mtx[0]), t);
+ p->column_fidct((int16_t *)(&p->threshold_mtx[0]), block + x * 8, block3 + x * 8, 8); //yes, this is a HOTSPOT
+ }
+ p->row_idct(block3 + 0 * 8, p->temp + (y & 15) * stride + x0 + 2 - (y & 1), stride, 2 * (BLOCKSZ - 1));
+ memmove(block, block + (BLOCKSZ - 1) * 64, 8 * 8 * sizeof(int16_t)); //cycling
+ memmove(block3, block3 + (BLOCKSZ - 1) * 64, 6 * 8 * sizeof(int16_t));
+ }
+
+ es = width + 8 - x0; // 8, ...
+ if (es > 8)
+ p->row_fdct(block + 8 * 8, p->src + y * stride + 8 + x0 + 2 - (y & 1), stride, (es - 4) >> 2);
+
+ p->column_fidct((int16_t *)(&p->threshold_mtx[0]), block, block3, es&(~1));
+ if (es > 3)
+ p->row_idct(block3 + 0 * 8, p->temp + (y & 15) * stride + x0 + 2 - (y & 1), stride, es >> 2);
+
+ if (!(y1 & 7) && y1) {
+ if (y1 & 8)
+ p->store_slice(dst + (y1 - 8) * dst_stride, p->temp + 8 + 8 * stride,
+ dst_stride, stride, width, 8, 5 - p->log2_count);
+ else
+ p->store_slice2(dst + (y1 - 8) * dst_stride, p->temp + 8 + 0 * stride,
+ dst_stride, stride, width, 8, 5 - p->log2_count);
+ }
+ }
+
+ if (y & 7) { // height % 8 != 0
+ if (y & 8)
+ p->store_slice(dst + ((y - 8) & ~7) * dst_stride, p->temp + 8 + 8 * stride,
+ dst_stride, stride, width, y&7, 5 - p->log2_count);
+ else
+ p->store_slice2(dst + ((y - 8) & ~7) * dst_stride, p->temp + 8 + 0 * stride,
+ dst_stride, stride, width, y&7, 5 - p->log2_count);
+ }
+}
+
+static void column_fidct_c(int16_t *thr_adr, int16_t *data, int16_t *output, int cnt)
+{
+ int_simd16_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ int_simd16_t tmp10, tmp11, tmp12, tmp13;
+ int_simd16_t z1,z2,z3,z4,z5, z10, z11, z12, z13;
+ int_simd16_t d0, d1, d2, d3, d4, d5, d6, d7;
+
+ int16_t *dataptr;
+ int16_t *wsptr;
+ int16_t *threshold;
+ int ctr;
+
+ dataptr = data;
+ wsptr = output;
+
+ for (; cnt > 0; cnt -= 2) { //start positions
+ threshold = (int16_t *)thr_adr;//threshold_mtx
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ // Process columns from input, add to output.
+ tmp0 = dataptr[DCTSIZE * 0] + dataptr[DCTSIZE * 7];
+ tmp7 = dataptr[DCTSIZE * 0] - dataptr[DCTSIZE * 7];
+
+ tmp1 = dataptr[DCTSIZE * 1] + dataptr[DCTSIZE * 6];
+ tmp6 = dataptr[DCTSIZE * 1] - dataptr[DCTSIZE * 6];
+
+ tmp2 = dataptr[DCTSIZE * 2] + dataptr[DCTSIZE * 5];
+ tmp5 = dataptr[DCTSIZE * 2] - dataptr[DCTSIZE * 5];
+
+ tmp3 = dataptr[DCTSIZE * 3] + dataptr[DCTSIZE * 4];
+ tmp4 = dataptr[DCTSIZE * 3] - dataptr[DCTSIZE * 4];
+
+ // Even part of FDCT
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ d0 = tmp10 + tmp11;
+ d4 = tmp10 - tmp11;
+
+ z1 = MULTIPLY16H((tmp12 + tmp13) << 2, FIX_0_707106781);
+ d2 = tmp13 + z1;
+ d6 = tmp13 - z1;
+
+ // Even part of IDCT
+
+ THRESHOLD(tmp0, d0, threshold[0 * 8]);
+ THRESHOLD(tmp1, d2, threshold[2 * 8]);
+ THRESHOLD(tmp2, d4, threshold[4 * 8]);
+ THRESHOLD(tmp3, d6, threshold[6 * 8]);
+ tmp0 += 2;
+ tmp10 = (tmp0 + tmp2) >> 2;
+ tmp11 = (tmp0 - tmp2) >> 2;
+
+ tmp13 = (tmp1 + tmp3) >>2; //+2 ! (psnr decides)
+ tmp12 = MULTIPLY16H((tmp1 - tmp3), FIX_1_414213562_A) - tmp13; //<<2
+
+ tmp0 = tmp10 + tmp13; //->temps
+ tmp3 = tmp10 - tmp13; //->temps
+ tmp1 = tmp11 + tmp12; //->temps
+ tmp2 = tmp11 - tmp12; //->temps
+
+ // Odd part of FDCT
+
+ tmp10 = tmp4 + tmp5;
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ z5 = MULTIPLY16H((tmp10 - tmp12) << 2, FIX_0_382683433);
+ z2 = MULTIPLY16H(tmp10 << 2, FIX_0_541196100) + z5;
+ z4 = MULTIPLY16H(tmp12 << 2, FIX_1_306562965) + z5;
+ z3 = MULTIPLY16H(tmp11 << 2, FIX_0_707106781);
+
+ z11 = tmp7 + z3;
+ z13 = tmp7 - z3;
+
+ d5 = z13 + z2;
+ d3 = z13 - z2;
+ d1 = z11 + z4;
+ d7 = z11 - z4;
+
+ // Odd part of IDCT
+
+ THRESHOLD(tmp4, d1, threshold[1 * 8]);
+ THRESHOLD(tmp5, d3, threshold[3 * 8]);
+ THRESHOLD(tmp6, d5, threshold[5 * 8]);
+ THRESHOLD(tmp7, d7, threshold[7 * 8]);
+
+ //Simd version uses here a shortcut for the tmp5,tmp6,tmp7 == 0
+ z13 = tmp6 + tmp5;
+ z10 = (tmp6 - tmp5) << 1;
+ z11 = tmp4 + tmp7;
+ z12 = (tmp4 - tmp7) << 1;
+
+ tmp7 = (z11 + z13) >> 2; //+2 !
+ tmp11 = MULTIPLY16H((z11 - z13) << 1, FIX_1_414213562);
+ z5 = MULTIPLY16H(z10 + z12, FIX_1_847759065);
+ tmp10 = MULTIPLY16H(z12, FIX_1_082392200) - z5;
+ tmp12 = MULTIPLY16H(z10, FIX_2_613125930) + z5; // - !!
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[DCTSIZE * 0] += (tmp0 + tmp7);
+ wsptr[DCTSIZE * 1] += (tmp1 + tmp6);
+ wsptr[DCTSIZE * 2] += (tmp2 + tmp5);
+ wsptr[DCTSIZE * 3] += (tmp3 - tmp4);
+ wsptr[DCTSIZE * 4] += (tmp3 + tmp4);
+ wsptr[DCTSIZE * 5] += (tmp2 - tmp5);
+ wsptr[DCTSIZE * 6] = (tmp1 - tmp6);
+ wsptr[DCTSIZE * 7] = (tmp0 - tmp7);
+ //
+ dataptr++; //next column
+ wsptr++;
+ threshold++;
+ }
+ dataptr += 8; //skip each second start pos
+ wsptr += 8;
+ }
+}
+
+static void row_idct_c(int16_t *workspace, int16_t *output_adr, ptrdiff_t output_stride, int cnt)
+{
+ int_simd16_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ int_simd16_t tmp10, tmp11, tmp12, tmp13;
+ int_simd16_t z5, z10, z11, z12, z13;
+ int16_t *outptr;
+ int16_t *wsptr;
+
+ cnt *= 4;
+ wsptr = workspace;
+ outptr = output_adr;
+ for (; cnt > 0; cnt--) {
+ // Even part
+ //Simd version reads 4x4 block and transposes it
+ tmp10 = wsptr[2] + wsptr[3];
+ tmp11 = wsptr[2] - wsptr[3];
+
+ tmp13 = wsptr[0] + wsptr[1];
+ tmp12 = (MULTIPLY16H(wsptr[0] - wsptr[1], FIX_1_414213562_A) << 2) - tmp13;//this shift order to avoid overflow
+
+ tmp0 = tmp10 + tmp13; //->temps
+ tmp3 = tmp10 - tmp13; //->temps
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ // Odd part
+ //Also transpose, with previous:
+ // ---- ---- ||||
+ // ---- ---- idct ||||
+ // ---- ---- ---> ||||
+ // ---- ---- ||||
+ z13 = wsptr[4] + wsptr[5];
+ z10 = wsptr[4] - wsptr[5];
+ z11 = wsptr[6] + wsptr[7];
+ z12 = wsptr[6] - wsptr[7];
+
+ tmp7 = z11 + z13;
+ tmp11 = MULTIPLY16H(z11 - z13, FIX_1_414213562);
+
+ z5 = MULTIPLY16H(z10 + z12, FIX_1_847759065);
+ tmp10 = MULTIPLY16H(z12, FIX_1_082392200) - z5;
+ tmp12 = MULTIPLY16H(z10, FIX_2_613125930) + z5; // - FIX_
+
+ tmp6 = (tmp12 << 3) - tmp7;
+ tmp5 = (tmp11 << 3) - tmp6;
+ tmp4 = (tmp10 << 3) + tmp5;
+
+ // Final output stage: descale and write column
+ outptr[0 * output_stride] += DESCALE(tmp0 + tmp7, 3);
+ outptr[1 * output_stride] += DESCALE(tmp1 + tmp6, 3);
+ outptr[2 * output_stride] += DESCALE(tmp2 + tmp5, 3);
+ outptr[3 * output_stride] += DESCALE(tmp3 - tmp4, 3);
+ outptr[4 * output_stride] += DESCALE(tmp3 + tmp4, 3);
+ outptr[5 * output_stride] += DESCALE(tmp2 - tmp5, 3);
+ outptr[6 * output_stride] += DESCALE(tmp1 - tmp6, 3); //no += ?
+ outptr[7 * output_stride] += DESCALE(tmp0 - tmp7, 3); //no += ?
+ outptr++;
+
+ wsptr += DCTSIZE; // advance pointer to next row
+ }
+}
+
+static void row_fdct_c(int16_t *data, const uint8_t *pixels, ptrdiff_t line_size, int cnt)
+{
+ int_simd16_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ int_simd16_t tmp10, tmp11, tmp12, tmp13;
+ int_simd16_t z1, z2, z3, z4, z5, z11, z13;
+ int16_t *dataptr;
+
+ cnt *= 4;
+ // Pass 1: process rows.
+
+ dataptr = data;
+ for (; cnt > 0; cnt--) {
+ tmp0 = pixels[line_size * 0] + pixels[line_size * 7];
+ tmp7 = pixels[line_size * 0] - pixels[line_size * 7];
+ tmp1 = pixels[line_size * 1] + pixels[line_size * 6];
+ tmp6 = pixels[line_size * 1] - pixels[line_size * 6];
+ tmp2 = pixels[line_size * 2] + pixels[line_size * 5];
+ tmp5 = pixels[line_size * 2] - pixels[line_size * 5];
+ tmp3 = pixels[line_size * 3] + pixels[line_size * 4];
+ tmp4 = pixels[line_size * 3] - pixels[line_size * 4];
+
+ // Even part
+
+ tmp10 = tmp0 + tmp3;
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+ //Even columns are written first, this leads to different order of columns
+ //in column_fidct(), but they are processed independently, so all ok.
+ //Later in the row_idct() columns readed at the same order.
+ dataptr[2] = tmp10 + tmp11;
+ dataptr[3] = tmp10 - tmp11;
+
+ z1 = MULTIPLY16H((tmp12 + tmp13) << 2, FIX_0_707106781);
+ dataptr[0] = tmp13 + z1;
+ dataptr[1] = tmp13 - z1;
+
+ // Odd part
+
+ tmp10 = (tmp4 + tmp5) << 2;
+ tmp11 = (tmp5 + tmp6) << 2;
+ tmp12 = (tmp6 + tmp7) << 2;
+
+ z5 = MULTIPLY16H(tmp10 - tmp12, FIX_0_382683433);
+ z2 = MULTIPLY16H(tmp10, FIX_0_541196100) + z5;
+ z4 = MULTIPLY16H(tmp12, FIX_1_306562965) + z5;
+ z3 = MULTIPLY16H(tmp11, FIX_0_707106781);
+
+ z11 = tmp7 + z3;
+ z13 = tmp7 - z3;
+
+ dataptr[4] = z13 + z2;
+ dataptr[5] = z13 - z2;
+ dataptr[6] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ pixels++; // advance pointer to next column
+ dataptr += DCTSIZE;
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ FSPPContext *fspp = ctx->priv;
+ const int h = FFALIGN(inlink->h + 16, 16);
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ fspp->hsub = desc->log2_chroma_w;
+ fspp->vsub = desc->log2_chroma_h;
+
+ fspp->temp_stride = FFALIGN(inlink->w + 16, 16);
+ fspp->temp = av_malloc_array(fspp->temp_stride, h * sizeof(*fspp->temp));
+ fspp->src = av_malloc_array(fspp->temp_stride, h * sizeof(*fspp->src));
+
+ if (!fspp->temp || !fspp->src)
+ return AVERROR(ENOMEM);
+
+ if (!fspp->use_bframe_qp && !fspp->qp) {
+ fspp->non_b_qp_alloc_size = FF_CEIL_RSHIFT(inlink->w, 4) * FF_CEIL_RSHIFT(inlink->h, 4);
+ fspp->non_b_qp_table = av_calloc(fspp->non_b_qp_alloc_size, sizeof(*fspp->non_b_qp_table));
+ if (!fspp->non_b_qp_table)
+ return AVERROR(ENOMEM);
+ }
+
+ fspp->store_slice = store_slice_c;
+ fspp->store_slice2 = store_slice2_c;
+ fspp->mul_thrmat = mul_thrmat_c;
+ fspp->column_fidct = column_fidct_c;
+ fspp->row_idct = row_idct_c;
+ fspp->row_fdct = row_fdct_c;
+
+ if (ARCH_X86)
+ ff_fspp_init_x86(fspp);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ FSPPContext *fspp = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out = in;
+
+ int qp_stride = 0;
+ uint8_t *qp_table = NULL;
+ int i, bias;
+ int custom_threshold_m[64];
+
+ bias = (1 << 4) + fspp->strength;
+
+ for (i = 0; i < 64; i++) //FIXME: tune custom_threshold[] and remove this !
+ custom_threshold_m[i] = (int)(custom_threshold[i] * (bias / 71.0) + 0.5);
+
+ for (i = 0; i < 8; i++) {
+ fspp->threshold_mtx_noq[2 * i] = (uint64_t)custom_threshold_m[i * 8 + 2]
+ |(((uint64_t)custom_threshold_m[i * 8 + 6]) << 16)
+ |(((uint64_t)custom_threshold_m[i * 8 + 0]) << 32)
+ |(((uint64_t)custom_threshold_m[i * 8 + 4]) << 48);
+
+ fspp->threshold_mtx_noq[2 * i + 1] = (uint64_t)custom_threshold_m[i * 8 + 5]
+ |(((uint64_t)custom_threshold_m[i * 8 + 3]) << 16)
+ |(((uint64_t)custom_threshold_m[i * 8 + 1]) << 32)
+ |(((uint64_t)custom_threshold_m[i * 8 + 7]) << 48);
+ }
+
+ if (fspp->qp)
+ fspp->prev_q = fspp->qp, fspp->mul_thrmat((int16_t *)(&fspp->threshold_mtx_noq[0]), (int16_t *)(&fspp->threshold_mtx[0]), fspp->qp);
+
+ /* if we are not in a constant user quantizer mode and we don't want to use
+ * the quantizers from the B-frames (B-frames often have a higher QP), we
+ * need to save the qp table from the last non B-frame; this is what the
+ * following code block does */
+ if (!fspp->qp) {
+ qp_table = av_frame_get_qp_table(in, &qp_stride, &fspp->qscale_type);
+
+ if (qp_table && !fspp->use_bframe_qp && in->pict_type != AV_PICTURE_TYPE_B) {
+ int w, h;
+
+ /* if the qp stride is not set, it means the QP are only defined on
+ * a line basis */
+ if (!qp_stride) {
+ w = FF_CEIL_RSHIFT(inlink->w, 4);
+ h = 1;
+ } else {
+ w = qp_stride;
+ h = FF_CEIL_RSHIFT(inlink->h, 4);
+ }
+ if (w * h > fspp->non_b_qp_alloc_size) {
+ int ret = av_reallocp_array(&fspp->non_b_qp_table, w, h);
+ if (ret < 0) {
+ fspp->non_b_qp_alloc_size = 0;
+ return ret;
+ }
+ fspp->non_b_qp_alloc_size = w * h;
+ }
+
+ av_assert0(w * h <= fspp->non_b_qp_alloc_size);
+ memcpy(fspp->non_b_qp_table, qp_table, w * h);
+ }
+ }
+
+ if (fspp->log2_count && !ctx->is_disabled) {
+ if (!fspp->use_bframe_qp && fspp->non_b_qp_table)
+ qp_table = fspp->non_b_qp_table;
+
+ if (qp_table || fspp->qp) {
+ const int cw = FF_CEIL_RSHIFT(inlink->w, fspp->hsub);
+ const int ch = FF_CEIL_RSHIFT(inlink->h, fspp->vsub);
+
+ /* get a new frame if in-place is not possible or if the dimensions
+ * are not multiple of 8 */
+ if (!av_frame_is_writable(in) || (inlink->w & 7) || (inlink->h & 7)) {
+ const int aligned_w = FFALIGN(inlink->w, 8);
+ const int aligned_h = FFALIGN(inlink->h, 8);
+
+ out = ff_get_video_buffer(outlink, aligned_w, aligned_h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ out->width = in->width;
+ out->height = in->height;
+ }
+
+ filter(fspp, out->data[0], in->data[0], out->linesize[0], in->linesize[0],
+ inlink->w, inlink->h, qp_table, qp_stride, 1);
+ filter(fspp, out->data[1], in->data[1], out->linesize[1], in->linesize[1],
+ cw, ch, qp_table, qp_stride, 0);
+ filter(fspp, out->data[2], in->data[2], out->linesize[2], in->linesize[2],
+ cw, ch, qp_table, qp_stride, 0);
+ emms_c();
+ }
+ }
+
+ if (in != out) {
+ if (in->data[3])
+ av_image_copy_plane(out->data[3], out->linesize[3],
+ in ->data[3], in ->linesize[3],
+ inlink->w, inlink->h);
+ av_frame_free(&in);
+ }
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ FSPPContext *fspp = ctx->priv;
+ av_freep(&fspp->temp);
+ av_freep(&fspp->src);
+ av_freep(&fspp->non_b_qp_table);
+}
+
+static const AVFilterPad fspp_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad fspp_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_fspp = {
+ .name = "fspp",
+ .description = NULL_IF_CONFIG_SMALL("Apply Fast Simple Post-processing filter."),
+ .priv_size = sizeof(FSPPContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = fspp_inputs,
+ .outputs = fspp_outputs,
+ .priv_class = &fspp_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_fspp.h b/libavfilter/vf_fspp.h
new file mode 100644
index 0000000000..237ffb1dcf
--- /dev/null
+++ b/libavfilter/vf_fspp.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2005 Nikolaj Poroshin <porosh3@psu.ru>
+ * Copyright (c) 2014 Arwa Arif <arwaarif1994@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 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.
+ */
+
+#ifndef AVFILTER_FSPP_H
+#define AVFILTER_FSPP_H
+
+#include "avfilter.h"
+
+#define BLOCKSZ 12
+#define MAX_LEVEL 5
+
+#define DCTSIZE 8
+#define DCTSIZE_S "8"
+
+#define FIX(x,s) ((int) ((x) * (1 << s) + 0.5) & 0xffff)
+#define C64(x) ((uint64_t)((x) | (x) << 16)) <<32 | (uint64_t)(x) | (uint64_t)(x) << 16
+#define FIX64(x,s) C64(FIX(x,s))
+
+#define MULTIPLY16H(x,k) (((x) * (k)) >> 16)
+#define THRESHOLD(r,x,t) \
+ if(((unsigned)((x) + t)) > t * 2) r = (x); \
+ else r = 0;
+#define DESCALE(x,n) (((x) + (1 << ((n) - 1))) >> n)
+
+typedef int32_t int_simd16_t;
+static const int16_t FIX_0_382683433 = FIX(0.382683433, 14);
+static const int16_t FIX_0_541196100 = FIX(0.541196100, 14);
+static const int16_t FIX_0_707106781 = FIX(0.707106781, 14);
+static const int16_t FIX_1_306562965 = FIX(1.306562965, 14);
+static const int16_t FIX_1_414213562_A = FIX(1.414213562, 14);
+static const int16_t FIX_1_847759065 = FIX(1.847759065, 13);
+static const int16_t FIX_2_613125930 = FIX(-2.613125930, 13);
+static const int16_t FIX_1_414213562 = FIX(1.414213562, 13);
+static const int16_t FIX_1_082392200 = FIX(1.082392200, 13);
+
+typedef struct FSPPContext {
+ AVClass *class;
+ uint64_t threshold_mtx_noq[8 * 2];
+ uint64_t threshold_mtx[8 * 2]; //used in both C & MMX (& later SSE2) versions
+
+ int log2_count;
+ int strength;
+ int hsub;
+ int vsub;
+ int temp_stride;
+ int qp;
+ int qscale_type;
+ int prev_q;
+ uint8_t *src;
+ int16_t *temp;
+ uint8_t *non_b_qp_table;
+ int non_b_qp_alloc_size;
+ int use_bframe_qp;
+
+ void (*store_slice)(uint8_t *dst, int16_t *src,
+ ptrdiff_t dst_stride, ptrdiff_t src_stride,
+ ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale);
+
+ void (*store_slice2)(uint8_t *dst, int16_t *src,
+ ptrdiff_t dst_stride, ptrdiff_t src_stride,
+ ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale);
+
+ void (*mul_thrmat)(int16_t *thr_adr_noq, int16_t *thr_adr, int q);
+
+ void (*column_fidct)(int16_t *thr_adr, int16_t *data,
+ int16_t *output, int cnt);
+
+ void (*row_idct)(int16_t *workspace, int16_t *output_adr,
+ ptrdiff_t output_stride, int cnt);
+
+ void (*row_fdct)(int16_t *data, const uint8_t *pixels,
+ ptrdiff_t line_size, int cnt);
+
+} FSPPContext;
+
+void ff_fspp_init_x86(FSPPContext *fspp);
+
+#endif /* AVFILTER_FSPP_H */
diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c
new file mode 100644
index 0000000000..887594f866
--- /dev/null
+++ b/libavfilter/vf_geq.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2012 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * 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
+ * Generic equation change filter
+ * Originally written by Michael Niedermayer for the MPlayer project, and
+ * ported by ClĂ©ment BÅ“sch for FFmpeg.
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ AVExpr *e[4]; ///< expressions for each plane
+ char *expr_str[4+3]; ///< expression strings for each plane
+ AVFrame *picref; ///< current input buffer
+ int hsub, vsub; ///< chroma subsampling
+ int planes; ///< number of planes
+ int is_rgb;
+} GEQContext;
+
+enum { Y = 0, U, V, A, G, B, R };
+
+#define OFFSET(x) offsetof(GEQContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption geq_options[] = {
+ { "lum_expr", "set luminance expression", OFFSET(expr_str[Y]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "lum", "set luminance expression", OFFSET(expr_str[Y]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "cb_expr", "set chroma blue expression", OFFSET(expr_str[U]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "cb", "set chroma blue expression", OFFSET(expr_str[U]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "cr_expr", "set chroma red expression", OFFSET(expr_str[V]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "cr", "set chroma red expression", OFFSET(expr_str[V]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "alpha_expr", "set alpha expression", OFFSET(expr_str[A]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "a", "set alpha expression", OFFSET(expr_str[A]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "red_expr", "set red expression", OFFSET(expr_str[R]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "r", "set red expression", OFFSET(expr_str[R]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "green_expr", "set green expression", OFFSET(expr_str[G]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "g", "set green expression", OFFSET(expr_str[G]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "blue_expr", "set blue expression", OFFSET(expr_str[B]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "b", "set blue expression", OFFSET(expr_str[B]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(geq);
+
+static inline double getpix(void *priv, double x, double y, int plane)
+{
+ int xi, yi;
+ GEQContext *geq = priv;
+ AVFrame *picref = geq->picref;
+ const uint8_t *src = picref->data[plane];
+ const int linesize = picref->linesize[plane];
+ const int w = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(picref->width, geq->hsub) : picref->width;
+ const int h = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(picref->height, geq->vsub) : picref->height;
+
+ if (!src)
+ return 0;
+
+ xi = x = av_clipf(x, 0, w - 2);
+ yi = y = av_clipf(y, 0, h - 2);
+
+ x -= xi;
+ y -= yi;
+
+ 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]);
+}
+
+//TODO: cubic interpolate
+//TODO: keep the last few frames
+static double lum(void *priv, double x, double y) { return getpix(priv, x, y, 0); }
+static double cb(void *priv, double x, double y) { return getpix(priv, x, y, 1); }
+static double cr(void *priv, double x, double y) { return getpix(priv, x, y, 2); }
+static double alpha(void *priv, double x, double y) { return getpix(priv, x, y, 3); }
+
+static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL };
+enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB };
+
+static av_cold int geq_init(AVFilterContext *ctx)
+{
+ GEQContext *geq = ctx->priv;
+ int plane, ret = 0;
+
+ if (!geq->expr_str[Y] && !geq->expr_str[G] && !geq->expr_str[B] && !geq->expr_str[R]) {
+ av_log(ctx, AV_LOG_ERROR, "A luminance or RGB expression is mandatory\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ geq->is_rgb = !geq->expr_str[Y];
+
+ if ((geq->expr_str[Y] || geq->expr_str[U] || geq->expr_str[V]) && (geq->expr_str[G] || geq->expr_str[B] || geq->expr_str[R])) {
+ av_log(ctx, AV_LOG_ERROR, "Either YCbCr or RGB but not both must be specified\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ if (!geq->expr_str[U] && !geq->expr_str[V]) {
+ /* No chroma at all: fallback on luma */
+ geq->expr_str[U] = av_strdup(geq->expr_str[Y]);
+ geq->expr_str[V] = av_strdup(geq->expr_str[Y]);
+ } else {
+ /* One chroma unspecified, fallback on the other */
+ if (!geq->expr_str[U]) geq->expr_str[U] = av_strdup(geq->expr_str[V]);
+ if (!geq->expr_str[V]) geq->expr_str[V] = av_strdup(geq->expr_str[U]);
+ }
+
+ if (!geq->expr_str[A])
+ geq->expr_str[A] = av_strdup("255");
+ if (!geq->expr_str[G])
+ geq->expr_str[G] = av_strdup("g(X,Y)");
+ if (!geq->expr_str[B])
+ geq->expr_str[B] = av_strdup("b(X,Y)");
+ if (!geq->expr_str[R])
+ geq->expr_str[R] = av_strdup("r(X,Y)");
+
+ if (geq->is_rgb ?
+ (!geq->expr_str[G] || !geq->expr_str[B] || !geq->expr_str[R])
+ :
+ (!geq->expr_str[U] || !geq->expr_str[V] || !geq->expr_str[A])) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ for (plane = 0; plane < 4; plane++) {
+ static double (*p[])(void *, double, double) = { lum, cb, cr, alpha };
+ static const char *const func2_yuv_names[] = { "lum", "cb", "cr", "alpha", "p", NULL };
+ static const char *const func2_rgb_names[] = { "g", "b", "r", "alpha", "p", NULL };
+ const char *const *func2_names = geq->is_rgb ? func2_rgb_names : func2_yuv_names;
+ double (*func2[])(void *, double, double) = { lum, cb, cr, alpha, p[plane], NULL };
+
+ ret = av_expr_parse(&geq->e[plane], geq->expr_str[plane < 3 && geq->is_rgb ? plane+4 : plane], var_names,
+ NULL, NULL, func2_names, func2, 0, ctx);
+ if (ret < 0)
+ break;
+ }
+
+end:
+ return ret;
+}
+
+static int geq_query_formats(AVFilterContext *ctx)
+{
+ GEQContext *geq = ctx->priv;
+ static const enum AVPixelFormat yuv_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_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat rgb_pix_fmts[] = {
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list;
+
+ if (geq->is_rgb) {
+ fmts_list = ff_make_format_list(rgb_pix_fmts);
+ } else
+ fmts_list = ff_make_format_list(yuv_pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int geq_config_props(AVFilterLink *inlink)
+{
+ GEQContext *geq = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ geq->hsub = desc->log2_chroma_w;
+ geq->vsub = desc->log2_chroma_h;
+ geq->planes = desc->nb_components;
+ return 0;
+}
+
+static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ int plane;
+ GEQContext *geq = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out;
+ double values[VAR_VARS_NB] = {
+ [VAR_N] = inlink->frame_count,
+ [VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base),
+ };
+
+ geq->picref = in;
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ for (plane = 0; plane < geq->planes && out->data[plane]; plane++) {
+ int x, y;
+ uint8_t *dst = out->data[plane];
+ const int linesize = out->linesize[plane];
+ const int w = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->w, geq->hsub) : inlink->w;
+ const int h = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->h, geq->vsub) : inlink->h;
+
+ values[VAR_W] = w;
+ values[VAR_H] = h;
+ values[VAR_SW] = w / (double)inlink->w;
+ values[VAR_SH] = h / (double)inlink->h;
+
+ for (y = 0; y < h; y++) {
+ values[VAR_Y] = y;
+ for (x = 0; x < w; x++) {
+ values[VAR_X] = x;
+ dst[x] = av_expr_eval(geq->e[plane], values, geq);
+ }
+ dst += linesize;
+ }
+ }
+
+ av_frame_free(&geq->picref);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void geq_uninit(AVFilterContext *ctx)
+{
+ int i;
+ GEQContext *geq = ctx->priv;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(geq->e); i++)
+ av_expr_free(geq->e[i]);
+}
+
+static const AVFilterPad geq_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = geq_config_props,
+ .filter_frame = geq_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad geq_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_geq = {
+ .name = "geq",
+ .description = NULL_IF_CONFIG_SMALL("Apply generic equation to each pixel."),
+ .priv_size = sizeof(GEQContext),
+ .init = geq_init,
+ .uninit = geq_uninit,
+ .query_formats = geq_query_formats,
+ .inputs = geq_inputs,
+ .outputs = geq_outputs,
+ .priv_class = &geq_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_gradfun.c b/libavfilter/vf_gradfun.c
index f7c4372dd3..8c11bda457 100644
--- a/libavfilter/vf_gradfun.c
+++ b/libavfilter/vf_gradfun.c
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Nolan Lum <nol888@gmail.com>
* Copyright (c) 2009 Loren Merritt <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,7 +54,7 @@ DECLARE_ALIGNED(16, static const uint16_t, dither)[8][8] = {
{0x54,0x34,0x4C,0x2C,0x52,0x32,0x4A,0x2A},
};
-void ff_gradfun_filter_line_c(uint8_t *dst, uint8_t *src, uint16_t *dc, int width, int thresh, const uint16_t *dithers)
+void ff_gradfun_filter_line_c(uint8_t *dst, const uint8_t *src, const uint16_t *dc, int width, int thresh, const uint16_t *dithers)
{
int x;
for (x = 0; x < width; dc += x & 1, x++) {
@@ -68,7 +68,7 @@ void ff_gradfun_filter_line_c(uint8_t *dst, uint8_t *src, uint16_t *dc, int widt
}
}
-void ff_gradfun_blur_line_c(uint16_t *dc, uint16_t *buf, uint16_t *buf1, uint8_t *src, int src_linesize, int width)
+void ff_gradfun_blur_line_c(uint16_t *dc, uint16_t *buf, const uint16_t *buf1, const uint8_t *src, int src_linesize, int width)
{
int x, v, old;
for (x = 0; x < width; x++) {
@@ -79,7 +79,7 @@ void ff_gradfun_blur_line_c(uint16_t *dc, uint16_t *buf, uint16_t *buf1, uint8_t
}
}
-static void filter(GradFunContext *ctx, uint8_t *dst, uint8_t *src, int width, int height, int dst_linesize, int src_linesize, int r)
+static void filter(GradFunContext *ctx, uint8_t *dst, const uint8_t *src, int width, int height, int dst_linesize, int src_linesize, int r)
{
int bstride = FFALIGN(width, 16) / 2;
int y;
@@ -126,9 +126,9 @@ static av_cold int init(AVFilterContext *ctx)
GradFunContext *s = ctx->priv;
s->thresh = (1 << 15) / s->strength;
- s->radius &= ~1;
+ s->radius = av_clip((s->radius + 1) & ~1, 4, 32);
- s->blur_line = ff_gradfun_blur_line_c;
+ s->blur_line = ff_gradfun_blur_line_c;
s->filter_line = ff_gradfun_filter_line_c;
if (ARCH_X86)
@@ -149,15 +149,16 @@ static int query_formats(AVFilterContext *ctx)
{
static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV420P,
- AV_PIX_FMT_GRAY8, AV_PIX_FMT_NV12,
- AV_PIX_FMT_NV21, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUV444P,
AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_GBRP,
AV_PIX_FMT_NONE
};
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
-
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static int config_input(AVFilterLink *inlink)
@@ -168,12 +169,12 @@ static int config_input(AVFilterLink *inlink)
int vsub = desc->log2_chroma_h;
av_freep(&s->buf);
- s->buf = av_mallocz((FFALIGN(inlink->w, 16) * (s->radius + 1) / 2 + 32) * sizeof(uint16_t));
+ s->buf = av_calloc((FFALIGN(inlink->w, 16) * (s->radius + 1) / 2 + 32), sizeof(*s->buf));
if (!s->buf)
return AVERROR(ENOMEM);
- s->chroma_w = -((-inlink->w) >> hsub);
- s->chroma_h = -((-inlink->h) >> vsub);
+ s->chroma_w = FF_CEIL_RSHIFT(inlink->w, hsub);
+ s->chroma_h = FF_CEIL_RSHIFT(inlink->h, vsub);
s->chroma_r = av_clip(((((s->radius >> hsub) + (s->radius >> vsub)) / 2 ) + 1) & ~1, 4, 32);
return 0;
@@ -196,13 +197,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
av_frame_free(&in);
return AVERROR(ENOMEM);
}
-
av_frame_copy_props(out, in);
- out->width = outlink->w;
- out->height = outlink->h;
}
- for (p = 0; p < 4 && in->data[p]; p++) {
+ for (p = 0; p < 4 && in->data[p] && in->linesize[p]; p++) {
int w = inlink->w;
int h = inlink->h;
int r = s->radius;
@@ -225,19 +223,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(GradFunContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption gradfun_options[] = {
{ "strength", "The maximum amount by which the filter will change any one pixel.", OFFSET(strength), AV_OPT_TYPE_FLOAT, { .dbl = 1.2 }, 0.51, 64, FLAGS },
{ "radius", "The neighborhood to fit the gradient to.", OFFSET(radius), AV_OPT_TYPE_INT, { .i64 = 16 }, 4, 32, FLAGS },
- { NULL },
+ { NULL }
};
-static const AVClass gradfun_class = {
- .class_name = "gradfun",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(gradfun);
static const AVFilterPad avfilter_vf_gradfun_inputs[] = {
{
@@ -265,7 +259,7 @@ AVFilter ff_vf_gradfun = {
.init = init,
.uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_gradfun_inputs,
- .outputs = avfilter_vf_gradfun_outputs,
+ .inputs = avfilter_vf_gradfun_inputs,
+ .outputs = avfilter_vf_gradfun_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c
index 1eb8d698d1..362bd013a9 100644
--- a/libavfilter/vf_hflip.c
+++ b/libavfilter/vf_hflip.c
@@ -2,20 +2,20 @@
* Copyright (c) 2007 Benoit Fouet
* Copyright (c) 2010 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,80 +37,70 @@
typedef struct FlipContext {
int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes
- int hsub, vsub; ///< chroma subsampling
+ int planewidth[4]; ///< width of each plane
+ int planeheight[4]; ///< height of each plane
} FlipContext;
static int query_formats(AVFilterContext *ctx)
{
- static const enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGB48LE,
- AV_PIX_FMT_BGR48BE, AV_PIX_FMT_BGR48LE,
- AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
- AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
- AV_PIX_FMT_RGB565BE, AV_PIX_FMT_RGB565LE,
- AV_PIX_FMT_RGB555BE, AV_PIX_FMT_RGB555LE,
- AV_PIX_FMT_BGR565BE, AV_PIX_FMT_BGR565LE,
- AV_PIX_FMT_BGR555BE, AV_PIX_FMT_BGR555LE,
- AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE,
- AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUV420P16BE,
- AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUV422P16BE,
- AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUV444P16BE,
- 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
- AV_PIX_FMT_YUVA420P,
- AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8,
- AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
- AV_PIX_FMT_PAL8, AV_PIX_FMT_GRAY8,
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *pix_fmts = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
+ desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ||
+ (desc->log2_chroma_w != desc->log2_chroma_h &&
+ desc->comp[0].plane == desc->comp[1].plane)))
+ ff_add_format(&pix_fmts, fmt);
+ }
+
+ return ff_set_common_formats(ctx, pix_fmts);
}
static int config_props(AVFilterLink *inlink)
{
FlipContext *s = inlink->dst->priv;
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+ const int hsub = pix_desc->log2_chroma_w;
+ const int vsub = pix_desc->log2_chroma_h;
av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc);
- s->hsub = pix_desc->log2_chroma_w;
- s->vsub = pix_desc->log2_chroma_h;
+ s->planewidth[0] = s->planewidth[3] = inlink->w;
+ s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, hsub);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, vsub);
return 0;
}
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
+
+static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs)
{
- AVFilterContext *ctx = inlink->dst;
- FlipContext *s = ctx->priv;
- AVFilterLink *outlink = ctx->outputs[0];
- AVFrame *out;
+ FlipContext *s = ctx->priv;
+ ThreadData *td = arg;
+ AVFrame *in = td->in;
+ AVFrame *out = td->out;
uint8_t *inrow, *outrow;
- int i, j, plane, step, hsub, vsub;
+ int i, j, plane, step;
- out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
- if (!out) {
- av_frame_free(&in);
- return AVERROR(ENOMEM);
- }
- av_frame_copy_props(out, in);
+ for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) {
+ const int width = s->planewidth[plane];
+ const int height = s->planeheight[plane];
+ const int start = (height * job ) / nb_jobs;
+ const int end = (height * (job+1)) / nb_jobs;
- for (plane = 0; plane < 4 && in->data[plane]; plane++) {
step = s->max_step[plane];
- hsub = (plane == 1 || plane == 2) ? s->hsub : 0;
- vsub = (plane == 1 || plane == 2) ? s->vsub : 0;
- outrow = out->data[plane];
- inrow = in ->data[plane] + ((inlink->w >> hsub) - 1) * step;
- for (i = 0; i < in->height >> vsub; i++) {
+ outrow = out->data[plane] + start * out->linesize[plane];
+ inrow = in ->data[plane] + start * in->linesize[plane] + (width - 1) * step;
+ for (i = start; i < end; i++) {
switch (step) {
case 1:
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
outrow[j] = inrow[-j];
break;
@@ -118,7 +108,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
uint16_t *outrow16 = (uint16_t *)outrow;
uint16_t * inrow16 = (uint16_t *) inrow;
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
outrow16[j] = inrow16[-j];
}
break;
@@ -127,7 +117,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
uint8_t *in = inrow;
uint8_t *out = outrow;
- for (j = 0; j < (inlink->w >> hsub); j++, out += 3, in -= 3) {
+ for (j = 0; j < width; j++, out += 3, in -= 3) {
int32_t v = AV_RB24(in);
AV_WB24(out, v);
}
@@ -138,13 +128,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
uint32_t *outrow32 = (uint32_t *)outrow;
uint32_t * inrow32 = (uint32_t *) inrow;
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
outrow32[j] = inrow32[-j];
}
break;
default:
- for (j = 0; j < (inlink->w >> hsub); j++)
+ for (j = 0; j < width; j++)
memcpy(outrow + j*step, inrow - j*step, step);
}
@@ -153,6 +143,30 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
}
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ThreadData td;
+ AVFrame *out;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ /* copy palette if required */
+ if (av_pix_fmt_desc_get(inlink->format)->flags & AV_PIX_FMT_FLAG_PAL)
+ memcpy(out->data[1], in->data[1], AVPALETTE_SIZE);
+
+ td.in = in, td.out = out;
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
+
av_frame_free(&in);
return ff_filter_frame(outlink, out);
}
@@ -176,11 +190,11 @@ static const AVFilterPad avfilter_vf_hflip_outputs[] = {
};
AVFilter ff_vf_hflip = {
- .name = "hflip",
- .description = NULL_IF_CONFIG_SMALL("Horizontally flip the input video."),
- .priv_size = sizeof(FlipContext),
+ .name = "hflip",
+ .description = NULL_IF_CONFIG_SMALL("Horizontally flip the input video."),
+ .priv_size = sizeof(FlipContext),
.query_formats = query_formats,
-
- .inputs = avfilter_vf_hflip_inputs,
- .outputs = avfilter_vf_hflip_outputs,
+ .inputs = avfilter_vf_hflip_inputs,
+ .outputs = avfilter_vf_hflip_outputs,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
};
diff --git a/libavfilter/vf_histeq.c b/libavfilter/vf_histeq.c
new file mode 100644
index 0000000000..ce28afdad6
--- /dev/null
+++ b/libavfilter/vf_histeq.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2012 Jeremy Tran
+ * Copyright (c) 2001 Donald A. Graft
+ *
+ * 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
+ * Histogram equalization filter, based on the VirtualDub filter by
+ * Donald A. Graft <neuron2 AT home DOT com>.
+ * Implements global automatic contrast adjustment by means of
+ * histogram equalization.
+ */
+
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+// #define DEBUG
+
+// Linear Congruential Generator, see "Numerical Recipes"
+#define LCG_A 4096
+#define LCG_C 150889
+#define LCG_M 714025
+#define LCG(x) (((x) * LCG_A + LCG_C) % LCG_M)
+#define LCG_SEED 739187
+
+enum HisteqAntibanding {
+ HISTEQ_ANTIBANDING_NONE = 0,
+ HISTEQ_ANTIBANDING_WEAK = 1,
+ HISTEQ_ANTIBANDING_STRONG = 2,
+ HISTEQ_ANTIBANDING_NB,
+};
+
+typedef struct {
+ const AVClass *class;
+ float strength;
+ float intensity;
+ int antibanding; ///< HisteqAntibanding
+ int in_histogram [256]; ///< input histogram
+ int out_histogram[256]; ///< output histogram
+ int LUT[256]; ///< lookup table derived from histogram[]
+ uint8_t rgba_map[4]; ///< components position
+ int bpp; ///< bytes per pixel
+} HisteqContext;
+
+#define OFFSET(x) offsetof(HisteqContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
+
+static const AVOption histeq_options[] = {
+ { "strength", "set the strength", OFFSET(strength), AV_OPT_TYPE_FLOAT, {.dbl=0.2}, 0, 1, FLAGS },
+ { "intensity", "set the intensity", OFFSET(intensity), AV_OPT_TYPE_FLOAT, {.dbl=0.21}, 0, 1, FLAGS },
+ { "antibanding", "set the antibanding level", OFFSET(antibanding), AV_OPT_TYPE_INT, {.i64=HISTEQ_ANTIBANDING_NONE}, 0, HISTEQ_ANTIBANDING_NB-1, FLAGS, "antibanding" },
+ CONST("none", "apply no antibanding", HISTEQ_ANTIBANDING_NONE, "antibanding"),
+ CONST("weak", "apply weak antibanding", HISTEQ_ANTIBANDING_WEAK, "antibanding"),
+ CONST("strong", "apply strong antibanding", HISTEQ_ANTIBANDING_STRONG, "antibanding"),
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(histeq);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ HisteqContext *histeq = ctx->priv;
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "strength:%0.3f intensity:%0.3f antibanding:%d\n",
+ histeq->strength, histeq->intensity, histeq->antibanding);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ HisteqContext *histeq = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+
+ histeq->bpp = av_get_bits_per_pixel(pix_desc) / 8;
+ ff_fill_rgba_map(histeq->rgba_map, inlink->format);
+
+ return 0;
+}
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+#define GET_RGB_VALUES(r, g, b, src, map) do { \
+ r = src[x + map[R]]; \
+ g = src[x + map[G]]; \
+ b = src[x + map[B]]; \
+} while (0)
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ AVFilterContext *ctx = inlink->dst;
+ HisteqContext *histeq = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int strength = histeq->strength * 1000;
+ int intensity = histeq->intensity * 1000;
+ int x, y, i, luthi, lutlo, lut, luma, oluma, m;
+ AVFrame *outpic;
+ unsigned int r, g, b, jran;
+ uint8_t *src, *dst;
+
+ outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpic) {
+ av_frame_free(&inpic);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpic, inpic);
+
+ /* Seed random generator for antibanding. */
+ jran = LCG_SEED;
+
+ /* Calculate and store the luminance and calculate the global histogram
+ based on the luminance. */
+ memset(histeq->in_histogram, 0, sizeof(histeq->in_histogram));
+ src = inpic->data[0];
+ dst = outpic->data[0];
+ for (y = 0; y < inlink->h; y++) {
+ for (x = 0; x < inlink->w * histeq->bpp; x += histeq->bpp) {
+ GET_RGB_VALUES(r, g, b, src, histeq->rgba_map);
+ luma = (55 * r + 182 * g + 19 * b) >> 8;
+ dst[x + histeq->rgba_map[A]] = luma;
+ histeq->in_histogram[luma]++;
+ }
+ src += inpic->linesize[0];
+ dst += outpic->linesize[0];
+ }
+
+#ifdef DEBUG
+ for (x = 0; x < 256; x++)
+ av_dlog(ctx, "in[%d]: %u\n", x, histeq->in_histogram[x]);
+#endif
+
+ /* Calculate the lookup table. */
+ histeq->LUT[0] = histeq->in_histogram[0];
+ /* Accumulate */
+ for (x = 1; x < 256; x++)
+ histeq->LUT[x] = histeq->LUT[x-1] + histeq->in_histogram[x];
+
+ /* Normalize */
+ for (x = 0; x < 256; x++)
+ histeq->LUT[x] = (histeq->LUT[x] * intensity) / (inlink->h * inlink->w);
+
+ /* Adjust the LUT based on the selected strength. This is an alpha
+ mix of the calculated LUT and a linear LUT with gain 1. */
+ for (x = 0; x < 256; x++)
+ histeq->LUT[x] = (strength * histeq->LUT[x]) / 255 +
+ ((255 - strength) * x) / 255;
+
+ /* Output the equalized frame. */
+ memset(histeq->out_histogram, 0, sizeof(histeq->out_histogram));
+
+ src = inpic->data[0];
+ dst = outpic->data[0];
+ for (y = 0; y < inlink->h; y++) {
+ for (x = 0; x < inlink->w * histeq->bpp; x += histeq->bpp) {
+ luma = dst[x + histeq->rgba_map[A]];
+ if (luma == 0) {
+ for (i = 0; i < histeq->bpp; ++i)
+ dst[x + i] = 0;
+ histeq->out_histogram[0]++;
+ } else {
+ lut = histeq->LUT[luma];
+ if (histeq->antibanding != HISTEQ_ANTIBANDING_NONE) {
+ if (luma > 0) {
+ lutlo = histeq->antibanding == HISTEQ_ANTIBANDING_WEAK ?
+ (histeq->LUT[luma] + histeq->LUT[luma - 1]) / 2 :
+ histeq->LUT[luma - 1];
+ } else
+ lutlo = lut;
+
+ if (luma < 255) {
+ luthi = (histeq->antibanding == HISTEQ_ANTIBANDING_WEAK) ?
+ (histeq->LUT[luma] + histeq->LUT[luma + 1]) / 2 :
+ histeq->LUT[luma + 1];
+ } else
+ luthi = lut;
+
+ if (lutlo != luthi) {
+ jran = LCG(jran);
+ lut = lutlo + ((luthi - lutlo + 1) * jran) / LCG_M;
+ }
+ }
+
+ GET_RGB_VALUES(r, g, b, src, histeq->rgba_map);
+ if (((m = FFMAX3(r, g, b)) * lut) / luma > 255) {
+ r = (r * 255) / m;
+ g = (g * 255) / m;
+ b = (b * 255) / m;
+ } else {
+ r = (r * lut) / luma;
+ g = (g * lut) / luma;
+ b = (b * lut) / luma;
+ }
+ dst[x + histeq->rgba_map[R]] = r;
+ dst[x + histeq->rgba_map[G]] = g;
+ dst[x + histeq->rgba_map[B]] = b;
+ oluma = av_clip_uint8((55 * r + 182 * g + 19 * b) >> 8);
+ histeq->out_histogram[oluma]++;
+ }
+ }
+ src += inpic->linesize[0];
+ dst += outpic->linesize[0];
+ }
+#ifdef DEBUG
+ for (x = 0; x < 256; x++)
+ av_dlog(ctx, "out[%d]: %u\n", x, histeq->out_histogram[x]);
+#endif
+
+ av_frame_free(&inpic);
+ return ff_filter_frame(outlink, outpic);
+}
+
+static const AVFilterPad histeq_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad histeq_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_histeq = {
+ .name = "histeq",
+ .description = NULL_IF_CONFIG_SMALL("Apply global color histogram equalization."),
+ .priv_size = sizeof(HisteqContext),
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = histeq_inputs,
+ .outputs = histeq_outputs,
+ .priv_class = &histeq_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_histogram.c b/libavfilter/vf_histogram.c
new file mode 100644
index 0000000000..31004b71db
--- /dev/null
+++ b/libavfilter/vf_histogram.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012-2013 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
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum HistogramMode {
+ MODE_LEVELS,
+ MODE_WAVEFORM,
+ MODE_COLOR,
+ MODE_COLOR2,
+ MODE_NB
+};
+
+typedef struct HistogramContext {
+ const AVClass *class; ///< AVClass context for log and options purpose
+ int mode; ///< HistogramMode
+ unsigned histogram[256];
+ int ncomp;
+ const uint8_t *bg_color;
+ const uint8_t *fg_color;
+ int level_height;
+ int scale_height;
+ int step;
+ int waveform_mode;
+ int waveform_mirror;
+ int display_mode;
+ int levels_mode;
+ const AVPixFmtDescriptor *desc;
+} HistogramContext;
+
+#define OFFSET(x) offsetof(HistogramContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption histogram_options[] = {
+ { "mode", "set histogram mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_LEVELS}, 0, MODE_NB-1, FLAGS, "mode"},
+ { "levels", "standard histogram", 0, AV_OPT_TYPE_CONST, {.i64=MODE_LEVELS}, 0, 0, FLAGS, "mode" },
+ { "waveform", "per row/column luminance graph", 0, AV_OPT_TYPE_CONST, {.i64=MODE_WAVEFORM}, 0, 0, FLAGS, "mode" },
+ { "color", "chroma values in vectorscope", 0, AV_OPT_TYPE_CONST, {.i64=MODE_COLOR}, 0, 0, FLAGS, "mode" },
+ { "color2", "chroma values in vectorscope", 0, AV_OPT_TYPE_CONST, {.i64=MODE_COLOR2}, 0, 0, FLAGS, "mode" },
+ { "level_height", "set level height", OFFSET(level_height), AV_OPT_TYPE_INT, {.i64=200}, 50, 2048, FLAGS},
+ { "scale_height", "set scale height", OFFSET(scale_height), AV_OPT_TYPE_INT, {.i64=12}, 0, 40, FLAGS},
+ { "step", "set waveform step value", OFFSET(step), AV_OPT_TYPE_INT, {.i64=10}, 1, 255, FLAGS},
+ { "waveform_mode", "set waveform mode", OFFSET(waveform_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "waveform_mode"},
+ { "row", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "waveform_mode" },
+ { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "waveform_mode" },
+ { "waveform_mirror", "set waveform mirroring", OFFSET(waveform_mirror), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "waveform_mirror"},
+ { "display_mode", "set display mode", OFFSET(display_mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "display_mode"},
+ { "parade", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "display_mode" },
+ { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "display_mode" },
+ { "levels_mode", "set levels mode", OFFSET(levels_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "levels_mode"},
+ { "linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "levels_mode" },
+ { "logarithmic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "levels_mode" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(histogram);
+
+static const enum AVPixelFormat color_pix_fmts[] = {
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_NONE
+};
+
+static const enum AVPixelFormat levels_pix_fmts[] = {
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_NONE
+};
+
+static const enum AVPixelFormat waveform_pix_fmts[] = {
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ HistogramContext *h = ctx->priv;
+ const enum AVPixelFormat *pix_fmts;
+ AVFilterFormats *fmts_list;
+
+ switch (h->mode) {
+ case MODE_WAVEFORM:
+ pix_fmts = waveform_pix_fmts;
+ break;
+ case MODE_LEVELS:
+ pix_fmts = levels_pix_fmts;
+ break;
+ case MODE_COLOR:
+ case MODE_COLOR2:
+ pix_fmts = color_pix_fmts;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
+static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
+static const uint8_t white_yuva_color[4] = { 255, 127, 127, 255 };
+static const uint8_t white_gbrp_color[4] = { 255, 255, 255, 255 };
+
+static int config_input(AVFilterLink *inlink)
+{
+ HistogramContext *h = inlink->dst->priv;
+
+ h->desc = av_pix_fmt_desc_get(inlink->format);
+ h->ncomp = h->desc->nb_components;
+
+ switch (inlink->format) {
+ case AV_PIX_FMT_GBRAP:
+ case AV_PIX_FMT_GBRP:
+ h->bg_color = black_gbrp_color;
+ h->fg_color = white_gbrp_color;
+ break;
+ default:
+ h->bg_color = black_yuva_color;
+ h->fg_color = white_yuva_color;
+ }
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ HistogramContext *h = ctx->priv;
+
+ switch (h->mode) {
+ case MODE_LEVELS:
+ outlink->w = 256;
+ outlink->h = (h->level_height + h->scale_height) * FFMAX(h->ncomp * h->display_mode, 1);
+ break;
+ case MODE_WAVEFORM:
+ if (h->waveform_mode)
+ outlink->h = 256 * FFMAX(h->ncomp * h->display_mode, 1);
+ else
+ outlink->w = 256 * FFMAX(h->ncomp * h->display_mode, 1);
+ break;
+ case MODE_COLOR:
+ case MODE_COLOR2:
+ outlink->h = outlink->w = 256;
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ outlink->sample_aspect_ratio = (AVRational){1,1};
+
+ return 0;
+}
+
+static void gen_waveform(HistogramContext *h, AVFrame *inpicref, AVFrame *outpicref,
+ int component, int intensity, int offset, int col_mode)
+{
+ const int plane = h->desc->comp[component].plane;
+ const int mirror = h->waveform_mirror;
+ const int is_chroma = (component == 1 || component == 2);
+ const int shift_w = (is_chroma ? h->desc->log2_chroma_w : 0);
+ const int shift_h = (is_chroma ? h->desc->log2_chroma_h : 0);
+ const int src_linesize = inpicref->linesize[plane];
+ const int dst_linesize = outpicref->linesize[plane];
+ const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
+ uint8_t *src_data = inpicref->data[plane];
+ uint8_t *dst_data = outpicref->data[plane] + (col_mode ? (offset >> shift_h) * dst_linesize : offset >> shift_w);
+ uint8_t * const dst_bottom_line = dst_data + dst_linesize * ((256 >> shift_h) - 1);
+ uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
+ const uint8_t max = 255 - intensity;
+ const int src_h = FF_CEIL_RSHIFT(inpicref->height, shift_h);
+ const int src_w = FF_CEIL_RSHIFT(inpicref->width, shift_w);
+ uint8_t *dst, *p;
+ int y;
+
+ if (!col_mode && mirror)
+ dst_data += 256 >> shift_w;
+ for (y = 0; y < src_h; y++) {
+ const uint8_t *src_data_end = src_data + src_w;
+ dst = dst_line;
+ for (p = src_data; p < src_data_end; p++) {
+ uint8_t *target;
+ if (col_mode) {
+ target = dst++ + dst_signed_linesize * (*p >> shift_h);
+ } else {
+ if (mirror)
+ target = dst_data - (*p >> shift_w);
+ else
+ target = dst_data + (*p >> shift_w);
+ }
+ if (*target <= max)
+ *target += intensity;
+ else
+ *target = 255;
+ }
+ src_data += src_linesize;
+ dst_data += dst_linesize;
+ }
+}
+
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ HistogramContext *h = inlink->dst->priv;
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ const uint8_t *src;
+ uint8_t *dst;
+ int i, j, k, l;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+
+ out->pts = in->pts;
+
+ for (k = 0; k < h->ncomp; k++) {
+ const int is_chroma = (k == 1 || k == 2);
+ const int dst_h = FF_CEIL_RSHIFT(outlink->h, (is_chroma ? h->desc->log2_chroma_h : 0));
+ const int dst_w = FF_CEIL_RSHIFT(outlink->w, (is_chroma ? h->desc->log2_chroma_w : 0));
+ for (i = 0; i < dst_h ; i++)
+ memset(out->data[h->desc->comp[k].plane] +
+ i * out->linesize[h->desc->comp[k].plane],
+ h->bg_color[k], dst_w);
+ }
+
+ switch (h->mode) {
+ case MODE_LEVELS:
+ for (k = 0; k < h->ncomp; k++) {
+ const int p = h->desc->comp[k].plane;
+ const int start = k * (h->level_height + h->scale_height) * h->display_mode;
+ double max_hval_log;
+ unsigned max_hval = 0;
+
+ for (i = 0; i < in->height; i++) {
+ src = in->data[p] + i * in->linesize[p];
+ for (j = 0; j < in->width; j++)
+ h->histogram[src[j]]++;
+ }
+
+ for (i = 0; i < 256; i++)
+ max_hval = FFMAX(max_hval, h->histogram[i]);
+ max_hval_log = log2(max_hval + 1);
+
+ for (i = 0; i < outlink->w; i++) {
+ int col_height;
+
+ if (h->levels_mode)
+ col_height = round(h->level_height * (1. - (log2(h->histogram[i] + 1) / max_hval_log)));
+ else
+ col_height = h->level_height - (h->histogram[i] * (int64_t)h->level_height + max_hval - 1) / max_hval;
+
+ for (j = h->level_height - 1; j >= col_height; j--) {
+ if (h->display_mode) {
+ for (l = 0; l < h->ncomp; l++)
+ out->data[l][(j + start) * out->linesize[l] + i] = h->fg_color[l];
+ } else {
+ out->data[p][(j + start) * out->linesize[p] + i] = 255;
+ }
+ }
+ for (j = h->level_height + h->scale_height - 1; j >= h->level_height; j--)
+ out->data[p][(j + start) * out->linesize[p] + i] = i;
+ }
+
+ memset(h->histogram, 0, 256 * sizeof(unsigned));
+ }
+ break;
+ case MODE_WAVEFORM:
+ for (k = 0; k < h->ncomp; k++) {
+ const int offset = k * 256 * h->display_mode;
+ gen_waveform(h, in, out, k, h->step, offset, h->waveform_mode);
+ }
+ break;
+ case MODE_COLOR:
+ for (i = 0; i < inlink->h; i++) {
+ const int iw1 = i * in->linesize[1];
+ const int iw2 = i * in->linesize[2];
+ for (j = 0; j < inlink->w; j++) {
+ const int pos = in->data[1][iw1 + j] * out->linesize[0] + in->data[2][iw2 + j];
+ if (out->data[0][pos] < 255)
+ out->data[0][pos]++;
+ }
+ }
+ for (i = 0; i < 256; i++) {
+ dst = out->data[0] + i * out->linesize[0];
+ for (j = 0; j < 256; j++) {
+ if (!dst[j]) {
+ out->data[1][i * out->linesize[0] + j] = i;
+ out->data[2][i * out->linesize[0] + j] = j;
+ }
+ }
+ }
+ break;
+ case MODE_COLOR2:
+ for (i = 0; i < inlink->h; i++) {
+ const int iw1 = i * in->linesize[1];
+ const int iw2 = i * in->linesize[2];
+ for (j = 0; j < inlink->w; j++) {
+ const int u = in->data[1][iw1 + j];
+ const int v = in->data[2][iw2 + j];
+ const int pos = u * out->linesize[0] + v;
+ if (!out->data[0][pos])
+ out->data[0][pos] = FFABS(128 - u) + FFABS(128 - v);
+ out->data[1][pos] = u;
+ out->data[2][pos] = v;
+ }
+ }
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_histogram = {
+ .name = "histogram",
+ .description = NULL_IF_CONFIG_SMALL("Compute and draw a histogram."),
+ .priv_size = sizeof(HistogramContext),
+ .query_formats = query_formats,
+ .inputs = inputs,
+ .outputs = outputs,
+ .priv_class = &histogram_class,
+};
diff --git a/libavfilter/vf_hqdn3d.c b/libavfilter/vf_hqdn3d.c
index 7f47a56a0b..f862014a7d 100644
--- a/libavfilter/vf_hqdn3d.c
+++ b/libavfilter/vf_hqdn3d.c
@@ -3,20 +3,20 @@
* Copyright (c) 2010 Baptiste Coudurier
* Copyright (c) 2012 Loren Merritt
*
- * This file is part of Libav, ported from MPlayer.
+ * This file is part of FFmpeg, ported from MPlayer.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -133,7 +133,7 @@ static int denoise_depth(HQDN3DContext *s,
uint16_t *frame_ant = *frame_ant_ptr;
if (!frame_ant) {
uint8_t *frame_src = src;
- *frame_ant_ptr = frame_ant = av_malloc(w*h*sizeof(uint16_t));
+ *frame_ant_ptr = frame_ant = av_malloc_array(w, h*sizeof(uint16_t));
if (!frame_ant)
return AVERROR(ENOMEM);
for (y = 0; y < h; y++, src += sstride, frame_ant += w)
@@ -155,7 +155,7 @@ static int denoise_depth(HQDN3DContext *s,
#define denoise(...) \
do { \
- int ret = AVERROR_INVALIDDATA; \
+ int ret = AVERROR_BUG; \
switch (s->depth) { \
case 8: ret = denoise_depth(__VA_ARGS__, 8); break; \
case 9: ret = denoise_depth(__VA_ARGS__, 9); break; \
@@ -242,21 +242,21 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_YUVJ422P,
AV_PIX_FMT_YUVJ444P,
AV_PIX_FMT_YUVJ440P,
- AV_NE( AV_PIX_FMT_YUV420P9BE, AV_PIX_FMT_YUV420P9LE ),
- AV_NE( AV_PIX_FMT_YUV422P9BE, AV_PIX_FMT_YUV422P9LE ),
- AV_NE( AV_PIX_FMT_YUV444P9BE, AV_PIX_FMT_YUV444P9LE ),
- AV_NE( AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUV420P10LE ),
- AV_NE( AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUV422P10LE ),
- AV_NE( AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUV444P10LE ),
- AV_NE( AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUV420P16LE ),
- AV_NE( AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUV422P16LE ),
- AV_NE( AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUV444P16LE ),
+ AV_PIX_FMT_YUV420P9,
+ AV_PIX_FMT_YUV422P9,
+ AV_PIX_FMT_YUV444P9,
+ AV_PIX_FMT_YUV420P10,
+ AV_PIX_FMT_YUV422P10,
+ AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUV420P16,
+ AV_PIX_FMT_YUV422P16,
+ AV_PIX_FMT_YUV444P16,
AV_PIX_FMT_NONE
};
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
-
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static int config_input(AVFilterLink *inlink)
@@ -271,7 +271,7 @@ static int config_input(AVFilterLink *inlink)
s->vsub = desc->log2_chroma_h;
s->depth = desc->comp[0].depth_minus1+1;
- s->line = av_malloc(inlink->w * sizeof(*s->line));
+ s->line = av_malloc_array(inlink->w, sizeof(*s->line));
if (!s->line)
return AVERROR(ENOMEM);
@@ -289,10 +289,12 @@ static int config_input(AVFilterLink *inlink)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{
- HQDN3DContext *s = inlink->dst->priv;
- AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFilterContext *ctx = inlink->dst;
+ HQDN3DContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+
AVFrame *out;
- int c, direct = av_frame_is_writable(in);
+ int c, direct = av_frame_is_writable(in) && !ctx->is_disabled;
if (direct) {
out = in;
@@ -304,17 +306,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
av_frame_copy_props(out, in);
- out->width = outlink->w;
- out->height = outlink->h;
}
for (c = 0; c < 3; c++) {
denoise(s, in->data[c], out->data[c],
s->line, &s->frame_prev[c],
- in->width >> (!!c * s->hsub),
- in->height >> (!!c * s->vsub),
+ FF_CEIL_RSHIFT(in->width, (!!c * s->hsub)),
+ FF_CEIL_RSHIFT(in->height, (!!c * s->vsub)),
in->linesize[c], out->linesize[c],
- s->coefs[c?2:0], s->coefs[c?3:1]);
+ s->coefs[c ? CHROMA_SPATIAL : LUMA_SPATIAL],
+ s->coefs[c ? CHROMA_TMP : LUMA_TMP]);
+ }
+
+ if (ctx->is_disabled) {
+ av_frame_free(&out);
+ return ff_filter_frame(outlink, in);
}
if (!direct)
@@ -324,21 +330,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(HQDN3DContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption hqdn3d_options[] = {
{ "luma_spatial", "spatial luma strength", OFFSET(strength[LUMA_SPATIAL]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS },
{ "chroma_spatial", "spatial chroma strength", OFFSET(strength[CHROMA_SPATIAL]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS },
{ "luma_tmp", "temporal luma strength", OFFSET(strength[LUMA_TMP]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS },
{ "chroma_tmp", "temporal chroma strength", OFFSET(strength[CHROMA_TMP]), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, 0, DBL_MAX, FLAGS },
- { NULL },
+ { NULL }
};
-static const AVClass hqdn3d_class = {
- .class_name = "hqdn3d",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(hqdn3d);
static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
{
@@ -350,6 +351,7 @@ static const AVFilterPad avfilter_vf_hqdn3d_inputs[] = {
{ NULL }
};
+
static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = {
{
.name = "default",
@@ -361,14 +363,12 @@ static const AVFilterPad avfilter_vf_hqdn3d_outputs[] = {
AVFilter ff_vf_hqdn3d = {
.name = "hqdn3d",
.description = NULL_IF_CONFIG_SMALL("Apply a High Quality 3D Denoiser."),
-
.priv_size = sizeof(HQDN3DContext),
.priv_class = &hqdn3d_class,
.init = init,
.uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_hqdn3d_inputs,
-
- .outputs = avfilter_vf_hqdn3d_outputs,
+ .inputs = avfilter_vf_hqdn3d_inputs,
+ .outputs = avfilter_vf_hqdn3d_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
};
diff --git a/libavfilter/vf_hqdn3d.h b/libavfilter/vf_hqdn3d.h
index a3445188b1..be55400f01 100644
--- a/libavfilter/vf_hqdn3d.h
+++ b/libavfilter/vf_hqdn3d.h
@@ -1,18 +1,22 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2003 Daniel Moreno <comac AT comac DOT darktech DOT org>
+ * Copyright (c) 2010 Baptiste Coudurier
+ * Copyright (c) 2012 Loren Merritt
*
- * Libav is free software; you can redistribute it and/or modify
+ * This file is part of FFmpeg, ported from MPlayer.
+ *
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
diff --git a/libavfilter/vf_hqx.c b/libavfilter/vf_hqx.c
new file mode 100644
index 0000000000..fa15d9c5c8
--- /dev/null
+++ b/libavfilter/vf_hqx.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2014 ClĂ©ment BÅ“sch
+ *
+ * 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.
+ */
+
+/**
+ * @file
+ * hqx magnification filters (hq2x, hq3x, hq4x)
+ *
+ * Originally designed by Maxim Stephin.
+ *
+ * @see http://en.wikipedia.org/wiki/Hqx
+ * @see http://web.archive.org/web/20131114143602/http://www.hiend3d.com/hq3x.html
+ * @see http://blog.pkh.me/p/19-butchering-hqx-scaling-filters.html
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+
+typedef int (*hqxfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
+
+typedef struct {
+ const AVClass *class;
+ int n;
+ hqxfunc_t func;
+ uint32_t rgbtoyuv[1<<24];
+} HQXContext;
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+ const uint32_t *rgbtoyuv;
+} ThreadData;
+
+#define OFFSET(x) offsetof(HQXContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption hqx_options[] = {
+ { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 4, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(hqx);
+
+static av_always_inline uint32_t rgb2yuv(const uint32_t *r2y, uint32_t c)
+{
+ return r2y[c & 0xffffff];
+}
+
+static av_always_inline int yuv_diff(uint32_t yuv1, uint32_t yuv2)
+{
+#define YMASK 0xff0000
+#define UMASK 0x00ff00
+#define VMASK 0x0000ff
+ return abs((yuv1 & YMASK) - (yuv2 & YMASK)) > (48 << 16) ||
+ abs((yuv1 & UMASK) - (yuv2 & UMASK)) > ( 7 << 8) ||
+ abs((yuv1 & VMASK) - (yuv2 & VMASK)) > ( 6 << 0);
+}
+
+/* (c1*w1 + c2*w2) >> s */
+static av_always_inline uint32_t interp_2px(uint32_t c1, int w1, uint32_t c2, int w2, int s)
+{
+ return (((((c1 & 0xff00ff00) >> 8) * w1 + ((c2 & 0xff00ff00) >> 8) * w2) << (8 - s)) & 0xff00ff00) |
+ (((((c1 & 0x00ff00ff) ) * w1 + ((c2 & 0x00ff00ff) ) * w2) >> s ) & 0x00ff00ff);
+}
+
+/* (c1*w1 + c2*w2 + c3*w3) >> s */
+static av_always_inline uint32_t interp_3px(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s)
+{
+ return (((((c1 & 0xff00ff00) >> 8) * w1 + ((c2 & 0xff00ff00) >> 8) * w2 + ((c3 & 0xff00ff00) >> 8) * w3) << (8 - s)) & 0xff00ff00) |
+ (((((c1 & 0x00ff00ff) ) * w1 + ((c2 & 0x00ff00ff) ) * w2 + ((c3 & 0x00ff00ff) ) * w3) >> s ) & 0x00ff00ff);
+}
+
+/* m is the mask of diff with the center pixel that matters in the pattern, and
+ * r is the expected result (bit set to 1 if there is difference with the
+ * center, 0 otherwise) */
+#define P(m, r) ((k_shuffled & (m)) == (r))
+
+/* adjust 012345678 to 01235678: the mask doesn't contain the (null) diff
+ * between the center/current pixel and itself */
+#define DROP4(z) ((z) > 4 ? (z)-1 : (z))
+
+/* shuffle the input mask: move bit n (4-adjusted) to position stored in p<n> */
+#define SHF(x, rot, n) (((x) >> ((rot) ? 7-DROP4(n) : DROP4(n)) & 1) << DROP4(p##n))
+
+/* used to check if there is YUV difference between 2 pixels */
+#define WDIFF(c1, c2) yuv_diff(rgb2yuv(r2y, c1), rgb2yuv(r2y, c2))
+
+/* bootstrap template for every interpolation code. It defines the shuffled
+ * masks and surrounding pixels. The rot flag is used to indicate if it's a
+ * rotation; its basic effect is to shuffle k using p8..p0 instead of p0..p8 */
+#define INTERP_BOOTSTRAP(rot) \
+ const int k_shuffled = SHF(k,rot,0) | SHF(k,rot,1) | SHF(k,rot,2) \
+ | SHF(k,rot,3) | 0 | SHF(k,rot,5) \
+ | SHF(k,rot,6) | SHF(k,rot,7) | SHF(k,rot,8); \
+ \
+ const uint32_t w0 = w[p0], w1 = w[p1], \
+ w3 = w[p3], w4 = w[p4], w5 = w[p5], \
+ w7 = w[p7]
+
+/* Assuming p0..p8 is mapped to pixels 0..8, this function interpolates the
+ * top-left pixel in the total of the 2x2 pixels to interpolates. The function
+ * is also used for the 3 other pixels */
+static av_always_inline uint32_t hq2x_interp_1x1(const uint32_t *r2y, int k,
+ const uint32_t *w,
+ int p0, int p1, int p2,
+ int p3, int p4, int p5,
+ int p6, int p7, int p8)
+{
+ INTERP_BOOTSTRAP(0);
+
+ if ((P(0xbf,0x37) || P(0xdb,0x13)) && WDIFF(w1, w5))
+ return interp_2px(w4, 3, w3, 1, 2);
+ if ((P(0xdb,0x49) || P(0xef,0x6d)) && WDIFF(w7, w3))
+ return interp_2px(w4, 3, w1, 1, 2);
+ if ((P(0x0b,0x0b) || P(0xfe,0x4a) || P(0xfe,0x1a)) && WDIFF(w3, w1))
+ return w4;
+ if ((P(0x6f,0x2a) || P(0x5b,0x0a) || P(0xbf,0x3a) || P(0xdf,0x5a) ||
+ P(0x9f,0x8a) || P(0xcf,0x8a) || P(0xef,0x4e) || P(0x3f,0x0e) ||
+ P(0xfb,0x5a) || P(0xbb,0x8a) || P(0x7f,0x5a) || P(0xaf,0x8a) ||
+ P(0xeb,0x8a)) && WDIFF(w3, w1))
+ return interp_2px(w4, 3, w0, 1, 2);
+ if (P(0x0b,0x08))
+ return interp_3px(w4, 2, w0, 1, w1, 1, 2);
+ if (P(0x0b,0x02))
+ return interp_3px(w4, 2, w0, 1, w3, 1, 2);
+ if (P(0x2f,0x2f))
+ return interp_3px(w4, 14, w3, 1, w1, 1, 4);
+ if (P(0xbf,0x37) || P(0xdb,0x13))
+ return interp_3px(w4, 5, w1, 2, w3, 1, 3);
+ if (P(0xdb,0x49) || P(0xef,0x6d))
+ return interp_3px(w4, 5, w3, 2, w1, 1, 3);
+ if (P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) || P(0x6b,0x43))
+ return interp_2px(w4, 3, w3, 1, 2);
+ if (P(0x4b,0x09) || P(0x8b,0x89) || P(0x1f,0x19) || P(0x3b,0x19))
+ return interp_2px(w4, 3, w1, 1, 2);
+ if (P(0x7e,0x2a) || P(0xef,0xab) || P(0xbf,0x8f) || P(0x7e,0x0e))
+ return interp_3px(w4, 2, w3, 3, w1, 3, 3);
+ if (P(0xfb,0x6a) || P(0x6f,0x6e) || P(0x3f,0x3e) || P(0xfb,0xfa) ||
+ P(0xdf,0xde) || P(0xdf,0x1e))
+ return interp_2px(w4, 3, w0, 1, 2);
+ if (P(0x0a,0x00) || P(0x4f,0x4b) || P(0x9f,0x1b) || P(0x2f,0x0b) ||
+ P(0xbe,0x0a) || P(0xee,0x0a) || P(0x7e,0x0a) || P(0xeb,0x4b) ||
+ P(0x3b,0x1b))
+ return interp_3px(w4, 2, w3, 1, w1, 1, 2);
+ return interp_3px(w4, 6, w3, 1, w1, 1, 3);
+}
+
+/* Assuming p0..p8 is mapped to pixels 0..8, this function interpolates the
+ * top-left and top-center pixel in the total of the 3x3 pixels to
+ * interpolates. The function is also used for the 3 other couples of pixels
+ * defining the outline. The center pixel is not defined through this function,
+ * since it's just the same as the original value. */
+static av_always_inline void hq3x_interp_2x1(uint32_t *dst, int dst_linesize,
+ const uint32_t *r2y, int k,
+ const uint32_t *w,
+ int pos00, int pos01,
+ int p0, int p1, int p2,
+ int p3, int p4, int p5,
+ int p6, int p7, int p8,
+ int rotate)
+{
+ INTERP_BOOTSTRAP(rotate);
+
+ uint32_t *dst00 = &dst[dst_linesize*(pos00>>1) + (pos00&1)];
+ uint32_t *dst01 = &dst[dst_linesize*(pos01>>1) + (pos01&1)];
+
+ if ((P(0xdb,0x49) || P(0xef,0x6d)) && WDIFF(w7, w3))
+ *dst00 = interp_2px(w4, 3, w1, 1, 2);
+ else if ((P(0xbf,0x37) || P(0xdb,0x13)) && WDIFF(w1, w5))
+ *dst00 = interp_2px(w4, 3, w3, 1, 2);
+ else if ((P(0x0b,0x0b) || P(0xfe,0x4a) || P(0xfe,0x1a)) && WDIFF(w3, w1))
+ *dst00 = w4;
+ else if ((P(0x6f,0x2a) || P(0x5b,0x0a) || P(0xbf,0x3a) || P(0xdf,0x5a) ||
+ P(0x9f,0x8a) || P(0xcf,0x8a) || P(0xef,0x4e) || P(0x3f,0x0e) ||
+ P(0xfb,0x5a) || P(0xbb,0x8a) || P(0x7f,0x5a) || P(0xaf,0x8a) ||
+ P(0xeb,0x8a)) && WDIFF(w3, w1))
+ *dst00 = interp_2px(w4, 3, w0, 1, 2);
+ else if (P(0x4b,0x09) || P(0x8b,0x89) || P(0x1f,0x19) || P(0x3b,0x19))
+ *dst00 = interp_2px(w4, 3, w1, 1, 2);
+ else if (P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) || P(0x6b,0x43))
+ *dst00 = interp_2px(w4, 3, w3, 1, 2);
+ else if (P(0x7e,0x2a) || P(0xef,0xab) || P(0xbf,0x8f) || P(0x7e,0x0e))
+ *dst00 = interp_2px(w3, 1, w1, 1, 1);
+ else if (P(0x4f,0x4b) || P(0x9f,0x1b) || P(0x2f,0x0b) || P(0xbe,0x0a) ||
+ P(0xee,0x0a) || P(0x7e,0x0a) || P(0xeb,0x4b) || P(0x3b,0x1b))
+ *dst00 = interp_3px(w4, 2, w3, 7, w1, 7, 4);
+ else if (P(0x0b,0x08) || P(0xf9,0x68) || P(0xf3,0x62) || P(0x6d,0x6c) ||
+ P(0x67,0x66) || P(0x3d,0x3c) || P(0x37,0x36) || P(0xf9,0xf8) ||
+ P(0xdd,0xdc) || P(0xf3,0xf2) || P(0xd7,0xd6) || P(0xdd,0x1c) ||
+ P(0xd7,0x16) || P(0x0b,0x02))
+ *dst00 = interp_2px(w4, 3, w0, 1, 2);
+ else
+ *dst00 = interp_3px(w4, 2, w3, 1, w1, 1, 2);
+
+ if ((P(0xfe,0xde) || P(0x9e,0x16) || P(0xda,0x12) || P(0x17,0x16) ||
+ P(0x5b,0x12) || P(0xbb,0x12)) && WDIFF(w1, w5))
+ *dst01 = w4;
+ else if ((P(0x0f,0x0b) || P(0x5e,0x0a) || P(0xfb,0x7b) || P(0x3b,0x0b) ||
+ P(0xbe,0x0a) || P(0x7a,0x0a)) && WDIFF(w3, w1))
+ *dst01 = w4;
+ else if (P(0xbf,0x8f) || P(0x7e,0x0e) || P(0xbf,0x37) || P(0xdb,0x13))
+ *dst01 = interp_2px(w1, 3, w4, 1, 2);
+ else if (P(0x02,0x00) || P(0x7c,0x28) || P(0xed,0xa9) || P(0xf5,0xb4) ||
+ P(0xd9,0x90))
+ *dst01 = interp_2px(w4, 3, w1, 1, 2);
+ else if (P(0x4f,0x4b) || P(0xfb,0x7b) || P(0xfe,0x7e) || P(0x9f,0x1b) ||
+ P(0x2f,0x0b) || P(0xbe,0x0a) || P(0x7e,0x0a) || P(0xfb,0x4b) ||
+ P(0xfb,0xdb) || P(0xfe,0xde) || P(0xfe,0x56) || P(0x57,0x56) ||
+ P(0x97,0x16) || P(0x3f,0x1e) || P(0xdb,0x12) || P(0xbb,0x12))
+ *dst01 = interp_2px(w4, 7, w1, 1, 3);
+ else
+ *dst01 = w4;
+}
+
+/* Assuming p0..p8 is mapped to pixels 0..8, this function interpolates the
+ * top-left block of 2x2 pixels in the total of the 4x4 pixels (or 4 blocks) to
+ * interpolates. The function is also used for the 3 other blocks of 2x2
+ * pixels. */
+static av_always_inline void hq4x_interp_2x2(uint32_t *dst, int dst_linesize,
+ const uint32_t *r2y, int k,
+ const uint32_t *w,
+ int pos00, int pos01,
+ int pos10, int pos11,
+ int p0, int p1, int p2,
+ int p3, int p4, int p5,
+ int p6, int p7, int p8)
+{
+ INTERP_BOOTSTRAP(0);
+
+ uint32_t *dst00 = &dst[dst_linesize*(pos00>>1) + (pos00&1)];
+ uint32_t *dst01 = &dst[dst_linesize*(pos01>>1) + (pos01&1)];
+ uint32_t *dst10 = &dst[dst_linesize*(pos10>>1) + (pos10&1)];
+ uint32_t *dst11 = &dst[dst_linesize*(pos11>>1) + (pos11&1)];
+
+ const int cond00 = (P(0xbf,0x37) || P(0xdb,0x13)) && WDIFF(w1, w5);
+ const int cond01 = (P(0xdb,0x49) || P(0xef,0x6d)) && WDIFF(w7, w3);
+ const int cond02 = (P(0x6f,0x2a) || P(0x5b,0x0a) || P(0xbf,0x3a) ||
+ P(0xdf,0x5a) || P(0x9f,0x8a) || P(0xcf,0x8a) ||
+ P(0xef,0x4e) || P(0x3f,0x0e) || P(0xfb,0x5a) ||
+ P(0xbb,0x8a) || P(0x7f,0x5a) || P(0xaf,0x8a) ||
+ P(0xeb,0x8a)) && WDIFF(w3, w1);
+ const int cond03 = P(0xdb,0x49) || P(0xef,0x6d);
+ const int cond04 = P(0xbf,0x37) || P(0xdb,0x13);
+ const int cond05 = P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) ||
+ P(0x6b,0x43);
+ const int cond06 = P(0x4b,0x09) || P(0x8b,0x89) || P(0x1f,0x19) ||
+ P(0x3b,0x19);
+ const int cond07 = P(0x0b,0x08) || P(0xf9,0x68) || P(0xf3,0x62) ||
+ P(0x6d,0x6c) || P(0x67,0x66) || P(0x3d,0x3c) ||
+ P(0x37,0x36) || P(0xf9,0xf8) || P(0xdd,0xdc) ||
+ P(0xf3,0xf2) || P(0xd7,0xd6) || P(0xdd,0x1c) ||
+ P(0xd7,0x16) || P(0x0b,0x02);
+ const int cond08 = (P(0x0f,0x0b) || P(0x2b,0x0b) || P(0xfe,0x4a) ||
+ P(0xfe,0x1a)) && WDIFF(w3, w1);
+ const int cond09 = P(0x2f,0x2f);
+ const int cond10 = P(0x0a,0x00);
+ const int cond11 = P(0x0b,0x09);
+ const int cond12 = P(0x7e,0x2a) || P(0xef,0xab);
+ const int cond13 = P(0xbf,0x8f) || P(0x7e,0x0e);
+ const int cond14 = P(0x4f,0x4b) || P(0x9f,0x1b) || P(0x2f,0x0b) ||
+ P(0xbe,0x0a) || P(0xee,0x0a) || P(0x7e,0x0a) ||
+ P(0xeb,0x4b) || P(0x3b,0x1b);
+ const int cond15 = P(0x0b,0x03);
+
+ if (cond00)
+ *dst00 = interp_2px(w4, 5, w3, 3, 3);
+ else if (cond01)
+ *dst00 = interp_2px(w4, 5, w1, 3, 3);
+ else if ((P(0x0b,0x0b) || P(0xfe,0x4a) || P(0xfe,0x1a)) && WDIFF(w3, w1))
+ *dst00 = w4;
+ else if (cond02)
+ *dst00 = interp_2px(w4, 5, w0, 3, 3);
+ else if (cond03)
+ *dst00 = interp_2px(w4, 3, w3, 1, 2);
+ else if (cond04)
+ *dst00 = interp_2px(w4, 3, w1, 1, 2);
+ else if (cond05)
+ *dst00 = interp_2px(w4, 5, w3, 3, 3);
+ else if (cond06)
+ *dst00 = interp_2px(w4, 5, w1, 3, 3);
+ else if (P(0x0f,0x0b) || P(0x5e,0x0a) || P(0x2b,0x0b) || P(0xbe,0x0a) ||
+ P(0x7a,0x0a) || P(0xee,0x0a))
+ *dst00 = interp_2px(w1, 1, w3, 1, 1);
+ else if (cond07)
+ *dst00 = interp_2px(w4, 5, w0, 3, 3);
+ else
+ *dst00 = interp_3px(w4, 2, w1, 1, w3, 1, 2);
+
+ if (cond00)
+ *dst01 = interp_2px(w4, 7, w3, 1, 3);
+ else if (cond08)
+ *dst01 = w4;
+ else if (cond02)
+ *dst01 = interp_2px(w4, 3, w0, 1, 2);
+ else if (cond09)
+ *dst01 = w4;
+ else if (cond10)
+ *dst01 = interp_3px(w4, 5, w1, 2, w3, 1, 3);
+ else if (P(0x0b,0x08))
+ *dst01 = interp_3px(w4, 5, w1, 2, w0, 1, 3);
+ else if (cond11)
+ *dst01 = interp_2px(w4, 5, w1, 3, 3);
+ else if (cond04)
+ *dst01 = interp_2px(w1, 3, w4, 1, 2);
+ else if (cond12)
+ *dst01 = interp_3px(w1, 2, w4, 1, w3, 1, 2);
+ else if (cond13)
+ *dst01 = interp_2px(w1, 5, w3, 3, 3);
+ else if (cond05)
+ *dst01 = interp_2px(w4, 7, w3, 1, 3);
+ else if (P(0xf3,0x62) || P(0x67,0x66) || P(0x37,0x36) || P(0xf3,0xf2) ||
+ P(0xd7,0xd6) || P(0xd7,0x16) || P(0x0b,0x02))
+ *dst01 = interp_2px(w4, 3, w0, 1, 2);
+ else if (cond14)
+ *dst01 = interp_2px(w1, 1, w4, 1, 1);
+ else
+ *dst01 = interp_2px(w4, 3, w1, 1, 2);
+
+ if (cond01)
+ *dst10 = interp_2px(w4, 7, w1, 1, 3);
+ else if (cond08)
+ *dst10 = w4;
+ else if (cond02)
+ *dst10 = interp_2px(w4, 3, w0, 1, 2);
+ else if (cond09)
+ *dst10 = w4;
+ else if (cond10)
+ *dst10 = interp_3px(w4, 5, w3, 2, w1, 1, 3);
+ else if (P(0x0b,0x02))
+ *dst10 = interp_3px(w4, 5, w3, 2, w0, 1, 3);
+ else if (cond15)
+ *dst10 = interp_2px(w4, 5, w3, 3, 3);
+ else if (cond03)
+ *dst10 = interp_2px(w3, 3, w4, 1, 2);
+ else if (cond13)
+ *dst10 = interp_3px(w3, 2, w4, 1, w1, 1, 2);
+ else if (cond12)
+ *dst10 = interp_2px(w3, 5, w1, 3, 3);
+ else if (cond06)
+ *dst10 = interp_2px(w4, 7, w1, 1, 3);
+ else if (P(0x0b,0x08) || P(0xf9,0x68) || P(0x6d,0x6c) || P(0x3d,0x3c) ||
+ P(0xf9,0xf8) || P(0xdd,0xdc) || P(0xdd,0x1c))
+ *dst10 = interp_2px(w4, 3, w0, 1, 2);
+ else if (cond14)
+ *dst10 = interp_2px(w3, 1, w4, 1, 1);
+ else
+ *dst10 = interp_2px(w4, 3, w3, 1, 2);
+
+ if ((P(0x7f,0x2b) || P(0xef,0xab) || P(0xbf,0x8f) || P(0x7f,0x0f)) &&
+ WDIFF(w3, w1))
+ *dst11 = w4;
+ else if (cond02)
+ *dst11 = interp_2px(w4, 7, w0, 1, 3);
+ else if (cond15)
+ *dst11 = interp_2px(w4, 7, w3, 1, 3);
+ else if (cond11)
+ *dst11 = interp_2px(w4, 7, w1, 1, 3);
+ else if (P(0x0a,0x00) || P(0x7e,0x2a) || P(0xef,0xab) || P(0xbf,0x8f) ||
+ P(0x7e,0x0e))
+ *dst11 = interp_3px(w4, 6, w3, 1, w1, 1, 3);
+ else if (cond07)
+ *dst11 = interp_2px(w4, 7, w0, 1, 3);
+ else
+ *dst11 = w4;
+}
+
+static av_always_inline void hqx_filter(const ThreadData *td, int jobnr, int nb_jobs, int n)
+{
+ int x, y;
+ AVFrame *in = td->in, *out = td->out;
+ const uint32_t *r2y = td->rgbtoyuv;
+ const int height = in->height;
+ const int width = in->width;
+ const int slice_start = (height * jobnr ) / nb_jobs;
+ const int slice_end = (height * (jobnr+1)) / nb_jobs;
+ const int dst_linesize = out->linesize[0];
+ const int src_linesize = in->linesize[0];
+ uint8_t *dst = out->data[0] + slice_start * dst_linesize * n;
+ const uint8_t *src = in->data[0] + slice_start * src_linesize;
+
+ const int dst32_linesize = dst_linesize >> 2;
+ const int src32_linesize = src_linesize >> 2;
+
+ for (y = slice_start; y < slice_end; y++) {
+ const uint32_t *src32 = (const uint32_t *)src;
+ uint32_t *dst32 = (uint32_t *)dst;
+ const int prevline = y > 0 ? -src32_linesize : 0;
+ const int nextline = y < height - 1 ? src32_linesize : 0;
+
+ for (x = 0; x < width; x++) {
+ const int prevcol = x > 0 ? -1 : 0;
+ const int nextcol = x < width -1 ? 1 : 0;
+ const uint32_t w[3*3] = {
+ src32[prevcol + prevline], src32[prevline], src32[prevline + nextcol],
+ src32[prevcol ], src32[ 0], src32[ nextcol],
+ src32[prevcol + nextline], src32[nextline], src32[nextline + nextcol]
+ };
+ const uint32_t yuv1 = rgb2yuv(r2y, w[4]);
+ const int pattern = (w[4] != w[0] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[0]))) : 0)
+ | (w[4] != w[1] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[1]))) : 0) << 1
+ | (w[4] != w[2] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[2]))) : 0) << 2
+ | (w[4] != w[3] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[3]))) : 0) << 3
+ | (w[4] != w[5] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[5]))) : 0) << 4
+ | (w[4] != w[6] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[6]))) : 0) << 5
+ | (w[4] != w[7] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[7]))) : 0) << 6
+ | (w[4] != w[8] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[8]))) : 0) << 7;
+
+ if (n == 2) {
+ dst32[dst32_linesize*0 + 0] = hq2x_interp_1x1(r2y, pattern, w, 0,1,2,3,4,5,6,7,8); // 00
+ dst32[dst32_linesize*0 + 1] = hq2x_interp_1x1(r2y, pattern, w, 2,1,0,5,4,3,8,7,6); // 01 (vert mirrored)
+ dst32[dst32_linesize*1 + 0] = hq2x_interp_1x1(r2y, pattern, w, 6,7,8,3,4,5,0,1,2); // 10 (horiz mirrored)
+ dst32[dst32_linesize*1 + 1] = hq2x_interp_1x1(r2y, pattern, w, 8,7,6,5,4,3,2,1,0); // 11 (center mirrored)
+ } else if (n == 3) {
+ hq3x_interp_2x1(dst32, dst32_linesize, r2y, pattern, w, 0,1, 0,1,2,3,4,5,6,7,8, 0); // 00 01
+ hq3x_interp_2x1(dst32 + 1, dst32_linesize, r2y, pattern, w, 1,3, 2,5,8,1,4,7,0,3,6, 1); // 02 12 (rotated to the right)
+ hq3x_interp_2x1(dst32 + 1*dst32_linesize, dst32_linesize, r2y, pattern, w, 2,0, 6,3,0,7,4,1,8,5,2, 1); // 20 10 (rotated to the left)
+ hq3x_interp_2x1(dst32 + 1*dst32_linesize + 1, dst32_linesize, r2y, pattern, w, 3,2, 8,7,6,5,4,3,2,1,0, 0); // 22 21 (center mirrored)
+ dst32[dst32_linesize + 1] = w[4]; // 11
+ } else if (n == 4) {
+ hq4x_interp_2x2(dst32, dst32_linesize, r2y, pattern, w, 0,1,2,3, 0,1,2,3,4,5,6,7,8); // 00 01 10 11
+ hq4x_interp_2x2(dst32 + 2, dst32_linesize, r2y, pattern, w, 1,0,3,2, 2,1,0,5,4,3,8,7,6); // 02 03 12 13 (vert mirrored)
+ hq4x_interp_2x2(dst32 + 2*dst32_linesize, dst32_linesize, r2y, pattern, w, 2,3,0,1, 6,7,8,3,4,5,0,1,2); // 20 21 30 31 (horiz mirrored)
+ hq4x_interp_2x2(dst32 + 2*dst32_linesize + 2, dst32_linesize, r2y, pattern, w, 3,2,1,0, 8,7,6,5,4,3,2,1,0); // 22 23 32 33 (center mirrored)
+ } else {
+ av_assert0(0);
+ }
+
+ src32 += 1;
+ dst32 += n;
+ }
+
+ src += src_linesize;
+ dst += dst_linesize * n;
+ }
+}
+
+#define HQX_FUNC(size) \
+static int hq##size##x(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
+{ \
+ hqx_filter(arg, jobnr, nb_jobs, size); \
+ return 0; \
+}
+
+HQX_FUNC(2)
+HQX_FUNC(3)
+HQX_FUNC(4)
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ HQXContext *hqx = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ outlink->w = inlink->w * hqx->n;
+ outlink->h = inlink->h * hqx->n;
+ av_log(inlink->dst, AV_LOG_VERBOSE, "fmt:%s size:%dx%d -> size:%dx%d\n",
+ av_get_pix_fmt_name(inlink->format),
+ inlink->w, inlink->h, outlink->w, outlink->h);
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ HQXContext *hqx = ctx->priv;
+ ThreadData td;
+ AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ out->width = outlink->w;
+ out->height = outlink->h;
+
+ td.in = in;
+ td.out = out;
+ td.rgbtoyuv = hqx->rgbtoyuv;
+ ctx->internal->execute(ctx, hqx->func, &td, NULL, FFMIN(inlink->h, ctx->graph->nb_threads));
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ HQXContext *hqx = ctx->priv;
+ static const hqxfunc_t hqxfuncs[] = {hq2x, hq3x, hq4x};
+
+ uint32_t c;
+ int bg, rg, g;
+
+ for (bg=-255; bg<256; bg++) {
+ for (rg=-255; rg<256; rg++) {
+ const uint32_t u = (uint32_t)((-169*rg + 500*bg)/1000) + 128;
+ const uint32_t v = (uint32_t)(( 500*rg - 81*bg)/1000) + 128;
+ int startg = FFMAX3(-bg, -rg, 0);
+ int endg = FFMIN3(255-bg, 255-rg, 255);
+ uint32_t y = (uint32_t)(( 299*rg + 1000*startg + 114*bg)/1000);
+ c = bg + (rg<<16) + 0x010101 * startg;
+ for (g = startg; g <= endg; g++) {
+ hqx->rgbtoyuv[c] = ((y++) << 16) + (u << 8) + v;
+ c+= 0x010101;
+ }
+ }
+ }
+
+ hqx->func = hqxfuncs[hqx->n - 2];
+ return 0;
+}
+
+static const AVFilterPad hqx_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad hqx_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_hqx = {
+ .name = "hqx",
+ .description = NULL_IF_CONFIG_SMALL("Scale the input by 2, 3 or 4 using the hq*x magnification algorithm."),
+ .priv_size = sizeof(HQXContext),
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = hqx_inputs,
+ .outputs = hqx_outputs,
+ .priv_class = &hqx_class,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c
new file mode 100644
index 0000000000..2c1b34ee50
--- /dev/null
+++ b/libavfilter/vf_hue.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer
+ * Copyright (c) 2012 Jeremy Tran
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Apply a hue/saturation filter to the input video
+ * Ported from MPlayer libmpcodecs/vf_hue.c.
+ */
+
+#include <float.h>
+#include "libavutil/eval.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define SAT_MIN_VAL -10
+#define SAT_MAX_VAL 10
+
+static const char *const var_names[] = {
+ "n", // frame count
+ "pts", // presentation timestamp expressed in AV_TIME_BASE units
+ "r", // frame rate
+ "t", // timestamp expressed in seconds
+ "tb", // timebase
+ NULL
+};
+
+enum var_name {
+ VAR_N,
+ VAR_PTS,
+ VAR_R,
+ VAR_T,
+ VAR_TB,
+ VAR_NB
+};
+
+typedef struct {
+ const AVClass *class;
+ float hue_deg; /* hue expressed in degrees */
+ float hue; /* hue expressed in radians */
+ char *hue_deg_expr;
+ char *hue_expr;
+ AVExpr *hue_deg_pexpr;
+ AVExpr *hue_pexpr;
+ float saturation;
+ char *saturation_expr;
+ AVExpr *saturation_pexpr;
+ float brightness;
+ char *brightness_expr;
+ AVExpr *brightness_pexpr;
+ int hsub;
+ int vsub;
+ int is_first;
+ int32_t hue_sin;
+ int32_t hue_cos;
+ double var_values[VAR_NB];
+ uint8_t lut_l[256];
+ uint8_t lut_u[256][256];
+ uint8_t lut_v[256][256];
+} HueContext;
+
+#define OFFSET(x) offsetof(HueContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption hue_options[] = {
+ { "h", "set the hue angle degrees expression", OFFSET(hue_deg_expr), AV_OPT_TYPE_STRING,
+ { .str = NULL }, .flags = FLAGS },
+ { "s", "set the saturation expression", OFFSET(saturation_expr), AV_OPT_TYPE_STRING,
+ { .str = "1" }, .flags = FLAGS },
+ { "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
+ { .str = NULL }, .flags = FLAGS },
+ { "b", "set the brightness expression", OFFSET(brightness_expr), AV_OPT_TYPE_STRING,
+ { .str = "0" }, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(hue);
+
+static inline void compute_sin_and_cos(HueContext *hue)
+{
+ /*
+ * Scale the value to the norm of the resulting (U,V) vector, that is
+ * the saturation.
+ * This will be useful in the apply_lut function.
+ */
+ hue->hue_sin = rint(sin(hue->hue) * (1 << 16) * hue->saturation);
+ hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
+}
+
+static inline void create_luma_lut(HueContext *h)
+{
+ const float b = h->brightness;
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ h->lut_l[i] = av_clip_uint8(i + b * 25.5);
+ }
+}
+
+static inline void create_chrominance_lut(HueContext *h, const int32_t c,
+ const int32_t s)
+{
+ int32_t i, j, u, v, new_u, new_v;
+
+ /*
+ * If we consider U and V as the components of a 2D vector then its angle
+ * is the hue and the norm is the saturation
+ */
+ for (i = 0; i < 256; i++) {
+ for (j = 0; j < 256; j++) {
+ /* Normalize the components from range [16;140] to [-112;112] */
+ u = i - 128;
+ v = j - 128;
+ /*
+ * Apply the rotation of the vector : (c * u) - (s * v)
+ * (s * u) + (c * v)
+ * De-normalize the components (without forgetting to scale 128
+ * by << 16)
+ * Finally scale back the result by >> 16
+ */
+ new_u = ((c * u) - (s * v) + (1 << 15) + (128 << 16)) >> 16;
+ new_v = ((s * u) + (c * v) + (1 << 15) + (128 << 16)) >> 16;
+
+ /* Prevent a potential overflow */
+ h->lut_u[i][j] = av_clip_uint8(new_u);
+ h->lut_v[i][j] = av_clip_uint8(new_v);
+ }
+ }
+}
+
+static int set_expr(AVExpr **pexpr_ptr, char **expr_ptr,
+ const char *expr, const char *option, void *log_ctx)
+{
+ int ret;
+ AVExpr *new_pexpr;
+ char *new_expr;
+
+ new_expr = av_strdup(expr);
+ if (!new_expr)
+ return AVERROR(ENOMEM);
+ ret = av_expr_parse(&new_pexpr, expr, var_names,
+ NULL, NULL, NULL, NULL, 0, log_ctx);
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Error when evaluating the expression '%s' for %s\n",
+ expr, option);
+ av_free(new_expr);
+ return ret;
+ }
+
+ if (*pexpr_ptr)
+ av_expr_free(*pexpr_ptr);
+ *pexpr_ptr = new_pexpr;
+ av_freep(expr_ptr);
+ *expr_ptr = new_expr;
+
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ HueContext *hue = ctx->priv;
+ int ret;
+
+ if (hue->hue_expr && hue->hue_deg_expr) {
+ av_log(ctx, AV_LOG_ERROR,
+ "H and h options are incompatible and cannot be specified "
+ "at the same time\n");
+ return AVERROR(EINVAL);
+ }
+
+#define SET_EXPR(expr, option) \
+ if (hue->expr##_expr) do { \
+ ret = set_expr(&hue->expr##_pexpr, &hue->expr##_expr, \
+ hue->expr##_expr, option, ctx); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+ SET_EXPR(brightness, "b");
+ SET_EXPR(saturation, "s");
+ SET_EXPR(hue_deg, "h");
+ SET_EXPR(hue, "H");
+#undef SET_EXPR
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "H_expr:%s h_deg_expr:%s s_expr:%s b_expr:%s\n",
+ hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr, hue->brightness_expr);
+ compute_sin_and_cos(hue);
+ hue->is_first = 1;
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ HueContext *hue = ctx->priv;
+
+ av_expr_free(hue->brightness_pexpr);
+ av_expr_free(hue->hue_deg_pexpr);
+ av_expr_free(hue->hue_pexpr);
+ av_expr_free(hue->saturation_pexpr);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVA444P, AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ HueContext *hue = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ hue->hsub = desc->log2_chroma_w;
+ hue->vsub = desc->log2_chroma_h;
+
+ 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);
+
+ return 0;
+}
+
+static void apply_luma_lut(HueContext *s,
+ uint8_t *ldst, const int dst_linesize,
+ uint8_t *lsrc, const int src_linesize,
+ int w, int h)
+{
+ int i;
+
+ while (h--) {
+ for (i = 0; i < w; i++)
+ ldst[i] = s->lut_l[lsrc[i]];
+
+ lsrc += src_linesize;
+ ldst += dst_linesize;
+ }
+}
+
+static void apply_lut(HueContext *s,
+ uint8_t *udst, uint8_t *vdst, const int dst_linesize,
+ uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
+ int w, int h)
+{
+ int i;
+
+ while (h--) {
+ for (i = 0; i < w; i++) {
+ const int u = usrc[i];
+ const int v = vsrc[i];
+
+ udst[i] = s->lut_u[u][v];
+ vdst[i] = s->lut_v[u][v];
+ }
+
+ usrc += src_linesize;
+ vsrc += src_linesize;
+ udst += dst_linesize;
+ vdst += dst_linesize;
+ }
+}
+
+#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ HueContext *hue = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpic;
+ const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos;
+ const float old_brightness = hue->brightness;
+ int direct = 0;
+
+ if (av_frame_is_writable(inpic)) {
+ direct = 1;
+ outpic = inpic;
+ } else {
+ outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpic) {
+ av_frame_free(&inpic);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpic, inpic);
+ }
+
+ hue->var_values[VAR_N] = inlink->frame_count;
+ hue->var_values[VAR_T] = TS2T(inpic->pts, inlink->time_base);
+ hue->var_values[VAR_PTS] = TS2D(inpic->pts);
+
+ if (hue->saturation_expr) {
+ hue->saturation = av_expr_eval(hue->saturation_pexpr, hue->var_values, NULL);
+
+ if (hue->saturation < SAT_MIN_VAL || hue->saturation > SAT_MAX_VAL) {
+ hue->saturation = av_clip(hue->saturation, SAT_MIN_VAL, SAT_MAX_VAL);
+ av_log(inlink->dst, AV_LOG_WARNING,
+ "Saturation value not in range [%d,%d]: clipping value to %0.1f\n",
+ SAT_MIN_VAL, SAT_MAX_VAL, hue->saturation);
+ }
+ }
+
+ if (hue->brightness_expr) {
+ hue->brightness = av_expr_eval(hue->brightness_pexpr, hue->var_values, NULL);
+
+ if (hue->brightness < -10 || hue->brightness > 10) {
+ hue->brightness = av_clipf(hue->brightness, -10, 10);
+ av_log(inlink->dst, AV_LOG_WARNING,
+ "Brightness value not in range [%d,%d]: clipping value to %0.1f\n",
+ -10, 10, hue->brightness);
+ }
+ }
+
+ if (hue->hue_deg_expr) {
+ hue->hue_deg = av_expr_eval(hue->hue_deg_pexpr, hue->var_values, NULL);
+ hue->hue = hue->hue_deg * M_PI / 180;
+ } else if (hue->hue_expr) {
+ hue->hue = av_expr_eval(hue->hue_pexpr, hue->var_values, NULL);
+ hue->hue_deg = hue->hue * 180 / M_PI;
+ }
+
+ av_log(inlink->dst, AV_LOG_DEBUG,
+ "H:%0.1f*PI h:%0.1f s:%0.1f b:%0.f t:%0.1f n:%d\n",
+ hue->hue/M_PI, hue->hue_deg, hue->saturation, hue->brightness,
+ hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
+
+ compute_sin_and_cos(hue);
+ if (hue->is_first || (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos))
+ create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin);
+
+ if (hue->is_first || (old_brightness != hue->brightness && hue->brightness))
+ create_luma_lut(hue);
+
+ if (!direct) {
+ if (!hue->brightness)
+ av_image_copy_plane(outpic->data[0], outpic->linesize[0],
+ inpic->data[0], inpic->linesize[0],
+ inlink->w, inlink->h);
+ if (inpic->data[3])
+ av_image_copy_plane(outpic->data[3], outpic->linesize[3],
+ inpic->data[3], inpic->linesize[3],
+ inlink->w, inlink->h);
+ }
+
+ apply_lut(hue, outpic->data[1], outpic->data[2], outpic->linesize[1],
+ inpic->data[1], inpic->data[2], inpic->linesize[1],
+ FF_CEIL_RSHIFT(inlink->w, hue->hsub),
+ FF_CEIL_RSHIFT(inlink->h, hue->vsub));
+ if (hue->brightness)
+ apply_luma_lut(hue, outpic->data[0], outpic->linesize[0],
+ inpic->data[0], inpic->linesize[0], inlink->w, inlink->h);
+
+ if (!direct)
+ av_frame_free(&inpic);
+
+ hue->is_first = 0;
+ return ff_filter_frame(outlink, outpic);
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ HueContext *hue = ctx->priv;
+ int ret;
+
+#define SET_EXPR(expr, option) \
+ do { \
+ ret = set_expr(&hue->expr##_pexpr, &hue->expr##_expr, \
+ args, option, ctx); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+
+ if (!strcmp(cmd, "h")) {
+ SET_EXPR(hue_deg, "h");
+ av_freep(&hue->hue_expr);
+ } else if (!strcmp(cmd, "H")) {
+ SET_EXPR(hue, "H");
+ av_freep(&hue->hue_deg_expr);
+ } else if (!strcmp(cmd, "s")) {
+ SET_EXPR(saturation, "s");
+ } else if (!strcmp(cmd, "b")) {
+ SET_EXPR(brightness, "b");
+ } else
+ return AVERROR(ENOSYS);
+
+ return 0;
+}
+
+static const AVFilterPad hue_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad hue_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_hue = {
+ .name = "hue",
+ .description = NULL_IF_CONFIG_SMALL("Adjust the hue and saturation of the input video."),
+ .priv_size = sizeof(HueContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .process_command = process_command,
+ .inputs = hue_inputs,
+ .outputs = hue_outputs,
+ .priv_class = &hue_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c
new file mode 100644
index 0000000000..eb1303a310
--- /dev/null
+++ b/libavfilter/vf_idet.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <float.h> /* FLT_MAX */
+
+#include "libavutil/cpu.h"
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+#include "vf_idet.h"
+
+#define OFFSET(x) offsetof(IDETContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption idet_options[] = {
+ { "intl_thres", "set interlacing threshold", OFFSET(interlace_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 1.04}, -1, FLT_MAX, FLAGS },
+ { "prog_thres", "set progressive threshold", OFFSET(progressive_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 1.5}, -1, FLT_MAX, FLAGS },
+ { "rep_thres", "set repeat threshold", OFFSET(repeat_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 3.0}, -1, FLT_MAX, FLAGS },
+ { "half_life", "half life of cumulative statistics", OFFSET(half_life), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, -1, INT_MAX, FLAGS },
+ { "analyze_interlaced_flag", "set number of frames to use to determine if the interlace flag is accurate", OFFSET(analyze_interlaced_flag), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(idet);
+
+static const char *type2str(Type type)
+{
+ switch(type) {
+ case TFF : return "tff";
+ case BFF : return "bff";
+ case PROGRESSIVE : return "progressive";
+ case UNDETERMINED : return "undetermined";
+ }
+ return NULL;
+}
+
+#define PRECISION 1048576
+
+static uint64_t uintpow(uint64_t b,unsigned int e)
+{
+ uint64_t r=1;
+ while(e--) r*=b;
+ return r;
+}
+
+static int av_dict_set_fxp(AVDictionary **pm, const char *key, uint64_t value, unsigned int digits,
+ int flags)
+{
+ char valuestr[44];
+ uint64_t print_precision = uintpow(10, digits);
+
+ value = av_rescale(value, print_precision, PRECISION);
+
+ snprintf(valuestr, sizeof(valuestr), "%"PRId64".%0*"PRId64,
+ value / print_precision, digits, value % print_precision);
+
+ return av_dict_set(pm, key, valuestr, flags);
+}
+
+static const char *rep2str(RepeatedField repeated_field)
+{
+ switch(repeated_field) {
+ case REPEAT_NONE : return "neither";
+ case REPEAT_TOP : return "top";
+ case REPEAT_BOTTOM : return "bottom";
+ }
+ return NULL;
+}
+
+int ff_idet_filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w)
+{
+ int x;
+ int ret=0;
+
+ for(x=0; x<w; x++){
+ int v = (*a++ + *c++) - 2 * *b++;
+ ret += FFABS(v);
+ }
+
+ return ret;
+}
+
+int ff_idet_filter_line_c_16bit(const uint16_t *a, const uint16_t *b, const uint16_t *c, int w)
+{
+ int x;
+ int ret=0;
+
+ for(x=0; x<w; x++){
+ int v = (*a++ + *c++) - 2 * *b++;
+ ret += FFABS(v);
+ }
+
+ return ret;
+}
+
+static void filter(AVFilterContext *ctx)
+{
+ IDETContext *idet = ctx->priv;
+ int y, i;
+ int64_t alpha[2]={0};
+ int64_t delta=0;
+ int64_t gamma[2]={0};
+ Type type, best_type;
+ RepeatedField repeat;
+ int match = 0;
+ AVDictionary **metadata = avpriv_frame_get_metadatap(idet->cur);
+
+ for (i = 0; i < idet->csp->nb_components; i++) {
+ int w = idet->cur->width;
+ int h = idet->cur->height;
+ int refs = idet->cur->linesize[i];
+
+ if (i && i<3) {
+ w = FF_CEIL_RSHIFT(w, idet->csp->log2_chroma_w);
+ h = FF_CEIL_RSHIFT(h, idet->csp->log2_chroma_h);
+ }
+
+ for (y = 2; y < h - 2; y++) {
+ uint8_t *prev = &idet->prev->data[i][y*refs];
+ uint8_t *cur = &idet->cur ->data[i][y*refs];
+ uint8_t *next = &idet->next->data[i][y*refs];
+ alpha[ y &1] += idet->filter_line(cur-refs, prev, cur+refs, w);
+ alpha[(y^1)&1] += idet->filter_line(cur-refs, next, cur+refs, w);
+ delta += idet->filter_line(cur-refs, cur, cur+refs, w);
+ gamma[(y^1)&1] += idet->filter_line(cur , prev, cur , w);
+ }
+ }
+
+ if (alpha[0] > idet->interlace_threshold * alpha[1]){
+ type = TFF;
+ }else if(alpha[1] > idet->interlace_threshold * alpha[0]){
+ type = BFF;
+ }else if(alpha[1] > idet->progressive_threshold * delta){
+ type = PROGRESSIVE;
+ }else{
+ type = UNDETERMINED;
+ }
+
+ if ( gamma[0] > idet->repeat_threshold * gamma[1] ){
+ repeat = REPEAT_TOP;
+ } else if ( gamma[1] > idet->repeat_threshold * gamma[0] ){
+ repeat = REPEAT_BOTTOM;
+ } else {
+ repeat = REPEAT_NONE;
+ }
+
+ memmove(idet->history+1, idet->history, HIST_SIZE-1);
+ idet->history[0] = type;
+ best_type = UNDETERMINED;
+ for(i=0; i<HIST_SIZE; i++){
+ if(idet->history[i] != UNDETERMINED){
+ if(best_type == UNDETERMINED)
+ best_type = idet->history[i];
+
+ if(idet->history[i] == best_type) {
+ match++;
+ }else{
+ match=0;
+ break;
+ }
+ }
+ }
+ if(idet->last_type == UNDETERMINED){
+ if(match ) idet->last_type = best_type;
+ }else{
+ if(match>2) idet->last_type = best_type;
+ }
+
+ if (idet->last_type == TFF){
+ idet->cur->top_field_first = 1;
+ idet->cur->interlaced_frame = 1;
+ }else if(idet->last_type == BFF){
+ idet->cur->top_field_first = 0;
+ idet->cur->interlaced_frame = 1;
+ }else if(idet->last_type == PROGRESSIVE){
+ idet->cur->interlaced_frame = 0;
+ }
+
+ for(i=0; i<3; i++)
+ idet->repeats[i] = av_rescale(idet->repeats [i], idet->decay_coefficient, PRECISION);
+
+ for(i=0; i<4; i++){
+ idet->prestat [i] = av_rescale(idet->prestat [i], idet->decay_coefficient, PRECISION);
+ idet->poststat[i] = av_rescale(idet->poststat[i], idet->decay_coefficient, PRECISION);
+ }
+
+ idet->total_repeats [ repeat] ++;
+ idet->repeats [ repeat] += PRECISION;
+
+ idet->total_prestat [ type] ++;
+ idet->prestat [ type] += PRECISION;
+
+ idet->total_poststat[idet->last_type] ++;
+ idet->poststat [idet->last_type] += PRECISION;
+
+ av_log(ctx, AV_LOG_DEBUG, "Repeated Field:%12s, Single frame:%12s, Multi frame:%12s\n",
+ rep2str(repeat), type2str(type), type2str(idet->last_type));
+
+ av_dict_set (metadata, "lavfi.idet.repeated.current_frame", rep2str(repeat), 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.repeated.neither", idet->repeats[REPEAT_NONE], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.repeated.top", idet->repeats[REPEAT_TOP], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.repeated.bottom", idet->repeats[REPEAT_BOTTOM], 2, 0);
+
+ av_dict_set (metadata, "lavfi.idet.single.current_frame", type2str(type), 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.single.tff", idet->prestat[TFF], 2 , 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.single.bff", idet->prestat[BFF], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.single.progressive", idet->prestat[PROGRESSIVE], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.single.undetermined", idet->prestat[UNDETERMINED], 2, 0);
+
+ av_dict_set (metadata, "lavfi.idet.multiple.current_frame", type2str(idet->last_type), 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.multiple.tff", idet->poststat[TFF], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.multiple.bff", idet->poststat[BFF], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.multiple.progressive", idet->poststat[PROGRESSIVE], 2, 0);
+ av_dict_set_fxp(metadata, "lavfi.idet.multiple.undetermined", idet->poststat[UNDETERMINED], 2, 0);
+}
+
+static int filter_frame(AVFilterLink *link, AVFrame *picref)
+{
+ AVFilterContext *ctx = link->dst;
+ IDETContext *idet = ctx->priv;
+
+ // initial frame(s) and not interlaced, just pass through for
+ // the analyze_interlaced_flag mode
+ if (idet->analyze_interlaced_flag &&
+ !picref->interlaced_frame &&
+ !idet->next) {
+ return ff_filter_frame(ctx->outputs[0], picref);
+ }
+ if (idet->analyze_interlaced_flag_done) {
+ if (picref->interlaced_frame && idet->interlaced_flag_accuracy < 0)
+ picref->interlaced_frame = 0;
+ return ff_filter_frame(ctx->outputs[0], picref);
+ }
+
+ av_frame_free(&idet->prev);
+
+ if( picref->width != link->w
+ || picref->height != link->h
+ || picref->format != link->format) {
+ link->dst->inputs[0]->format = picref->format;
+ link->dst->inputs[0]->w = picref->width;
+ link->dst->inputs[0]->h = picref->height;
+
+ av_frame_free(&idet->cur );
+ av_frame_free(&idet->next);
+ }
+
+ idet->prev = idet->cur;
+ idet->cur = idet->next;
+ idet->next = picref;
+
+ if (!idet->cur &&
+ !(idet->cur = av_frame_clone(idet->next)))
+ return AVERROR(ENOMEM);
+
+ if (!idet->prev)
+ return 0;
+
+ if (!idet->csp)
+ idet->csp = av_pix_fmt_desc_get(link->format);
+ if (idet->csp->comp[0].depth_minus1 / 8 == 1){
+ idet->filter_line = (ff_idet_filter_func)ff_idet_filter_line_c_16bit;
+ if (ARCH_X86)
+ ff_idet_init_x86(idet, 1);
+ }
+
+ if (idet->analyze_interlaced_flag) {
+ if (idet->cur->interlaced_frame) {
+ idet->cur->interlaced_frame = 0;
+ filter(ctx);
+ if (idet->last_type == PROGRESSIVE) {
+ idet->interlaced_flag_accuracy --;
+ idet->analyze_interlaced_flag --;
+ } else if (idet->last_type != UNDETERMINED) {
+ idet->interlaced_flag_accuracy ++;
+ idet->analyze_interlaced_flag --;
+ }
+ if (idet->analyze_interlaced_flag == 1) {
+ ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->cur));
+
+ if (idet->next->interlaced_frame && idet->interlaced_flag_accuracy < 0)
+ idet->next->interlaced_frame = 0;
+ idet->analyze_interlaced_flag_done = 1;
+ av_log(ctx, AV_LOG_INFO, "Final flag accuracy %d\n", idet->interlaced_flag_accuracy);
+ return ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->next));
+ }
+ }
+ } else {
+ filter(ctx);
+ }
+
+ return ff_filter_frame(ctx->outputs[0], av_frame_clone(idet->cur));
+}
+
+static int request_frame(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->src;
+ IDETContext *idet = ctx->priv;
+
+ do {
+ int ret;
+
+ if (idet->eof)
+ return AVERROR_EOF;
+
+ ret = ff_request_frame(link->src->inputs[0]);
+
+ if (ret == AVERROR_EOF && idet->cur && !idet->analyze_interlaced_flag_done) {
+ AVFrame *next = av_frame_clone(idet->next);
+
+ if (!next)
+ return AVERROR(ENOMEM);
+
+ filter_frame(link->src->inputs[0], next);
+ idet->eof = 1;
+ } else if (ret < 0) {
+ return ret;
+ }
+ } while (link->frame_requested);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ IDETContext *idet = ctx->priv;
+ int level = strncmp(ctx->name, "auto-inserted", 13) ? AV_LOG_INFO : AV_LOG_DEBUG;
+
+ av_log(ctx, level, "Repeated Fields: Neither:%6"PRId64" Top:%6"PRId64" Bottom:%6"PRId64"\n",
+ idet->total_repeats[REPEAT_NONE],
+ idet->total_repeats[REPEAT_TOP],
+ idet->total_repeats[REPEAT_BOTTOM]
+ );
+ av_log(ctx, level, "Single frame detection: TFF:%6"PRId64" BFF:%6"PRId64" Progressive:%6"PRId64" Undetermined:%6"PRId64"\n",
+ idet->total_prestat[TFF],
+ idet->total_prestat[BFF],
+ idet->total_prestat[PROGRESSIVE],
+ idet->total_prestat[UNDETERMINED]
+ );
+ av_log(ctx, level, "Multi frame detection: TFF:%6"PRId64" BFF:%6"PRId64" Progressive:%6"PRId64" Undetermined:%6"PRId64"\n",
+ idet->total_poststat[TFF],
+ idet->total_poststat[BFF],
+ idet->total_poststat[PROGRESSIVE],
+ idet->total_poststat[UNDETERMINED]
+ );
+
+ av_frame_free(&idet->prev);
+ av_frame_free(&idet->cur );
+ av_frame_free(&idet->next);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_GRAY16,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUV420P9,
+ AV_PIX_FMT_YUV422P9,
+ AV_PIX_FMT_YUV444P9,
+ AV_PIX_FMT_YUV420P10,
+ AV_PIX_FMT_YUV422P10,
+ AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUV420P12,
+ AV_PIX_FMT_YUV422P12,
+ AV_PIX_FMT_YUV444P12,
+ AV_PIX_FMT_YUV420P14,
+ AV_PIX_FMT_YUV422P14,
+ AV_PIX_FMT_YUV444P14,
+ AV_PIX_FMT_YUV420P16,
+ AV_PIX_FMT_YUV422P16,
+ AV_PIX_FMT_YUV444P16,
+ AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ IDETContext *idet = ctx->priv;
+
+ idet->eof = 0;
+ idet->last_type = UNDETERMINED;
+ memset(idet->history, UNDETERMINED, HIST_SIZE);
+
+ if( idet->half_life > 0 )
+ idet->decay_coefficient = (uint64_t) round( PRECISION * exp2(-1.0 / idet->half_life) );
+ else
+ idet->decay_coefficient = PRECISION;
+
+ idet->filter_line = ff_idet_filter_line_c;
+
+ if (ARCH_X86)
+ ff_idet_init_x86(idet, 0);
+
+ return 0;
+}
+
+static const AVFilterPad idet_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad idet_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_idet = {
+ .name = "idet",
+ .description = NULL_IF_CONFIG_SMALL("Interlace detect Filter."),
+ .priv_size = sizeof(IDETContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = idet_inputs,
+ .outputs = idet_outputs,
+ .priv_class = &idet_class,
+};
diff --git a/libavfilter/vf_idet.h b/libavfilter/vf_idet.h
new file mode 100644
index 0000000000..47e3d9ce81
--- /dev/null
+++ b/libavfilter/vf_idet.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_IDET_H
+#define AVFILTER_IDET_H
+
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+
+#define HIST_SIZE 4
+
+typedef int (*ff_idet_filter_func)(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w);
+
+typedef enum {
+ TFF,
+ BFF,
+ PROGRESSIVE,
+ UNDETERMINED,
+} Type;
+
+typedef enum {
+ REPEAT_NONE,
+ REPEAT_TOP,
+ REPEAT_BOTTOM,
+} RepeatedField;
+
+typedef struct {
+ const AVClass *class;
+ float interlace_threshold;
+ float progressive_threshold;
+ float repeat_threshold;
+ float half_life;
+ uint64_t decay_coefficient;
+
+ Type last_type;
+
+ uint64_t repeats[3];
+ uint64_t prestat[4];
+ uint64_t poststat[4];
+ uint64_t total_repeats[3];
+ uint64_t total_prestat[4];
+ uint64_t total_poststat[4];
+
+ uint8_t history[HIST_SIZE];
+
+ AVFrame *cur;
+ AVFrame *next;
+ AVFrame *prev;
+ ff_idet_filter_func filter_line;
+
+ int interlaced_flag_accuracy;
+ int analyze_interlaced_flag;
+ int analyze_interlaced_flag_done;
+
+ const AVPixFmtDescriptor *csp;
+ int eof;
+} IDETContext;
+
+void ff_idet_init_x86(IDETContext *idet, int for_16b);
+
+/* main fall-back for left-over */
+int ff_idet_filter_line_c(const uint8_t *a, const uint8_t *b, const uint8_t *c, int w);
+int ff_idet_filter_line_c_16bit(const uint16_t *a, const uint16_t *b, const uint16_t *c, int w);
+
+#endif
diff --git a/libavfilter/vf_il.c b/libavfilter/vf_il.c
new file mode 100644
index 0000000000..edb58d0324
--- /dev/null
+++ b/libavfilter/vf_il.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * (de)interleave fields filter
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+
+enum FilterMode {
+ MODE_NONE,
+ MODE_INTERLEAVE,
+ MODE_DEINTERLEAVE
+};
+
+typedef struct {
+ const AVClass *class;
+ int luma_mode, chroma_mode, alpha_mode; ///<FilterMode
+ int luma_swap, chroma_swap, alpha_swap;
+ int nb_planes;
+ int linesize[4], chroma_height;
+ int has_alpha;
+} IlContext;
+
+#define OFFSET(x) offsetof(IlContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption il_options[] = {
+ {"luma_mode", "select luma mode", OFFSET(luma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "luma_mode"},
+ {"l", "select luma mode", OFFSET(luma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "luma_mode"},
+ {"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_NONE}, 0, 0, FLAGS, "luma_mode"},
+ {"interleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
+ {"i", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
+ {"deinterleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
+ {"d", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "luma_mode"},
+ {"chroma_mode", "select chroma mode", OFFSET(chroma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "chroma_mode"},
+ {"c", "select chroma mode", OFFSET(chroma_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "chroma_mode"},
+ {"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_NONE}, 0, 0, FLAGS, "chroma_mode"},
+ {"interleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
+ {"i", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
+ {"deinterleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
+ {"d", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "chroma_mode"},
+ {"alpha_mode", "select alpha mode", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "alpha_mode"},
+ {"a", "select alpha mode", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64=MODE_NONE}, MODE_NONE, MODE_DEINTERLEAVE, FLAGS, "alpha_mode"},
+ {"none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_NONE}, 0, 0, FLAGS, "alpha_mode"},
+ {"interleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
+ {"i", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
+ {"deinterleave", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
+ {"d", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_DEINTERLEAVE}, 0, 0, FLAGS, "alpha_mode"},
+ {"luma_swap", "swap luma fields", OFFSET(luma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"ls", "swap luma fields", OFFSET(luma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"chroma_swap", "swap chroma fields", OFFSET(chroma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"cs", "swap chroma fields", OFFSET(chroma_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"alpha_swap", "swap alpha fields", OFFSET(alpha_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {"as", "swap alpha fields", OFFSET(alpha_swap), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(il);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_PAL) && !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
+ ff_add_format(&formats, fmt);
+ }
+
+ return ff_set_common_formats(ctx, formats);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ IlContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ s->has_alpha = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA);
+ if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->chroma_height = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+
+ return 0;
+}
+
+static void interleave(uint8_t *dst, uint8_t *src, int w, int h,
+ int dst_linesize, int src_linesize,
+ enum FilterMode mode, int swap)
+{
+ const int a = swap;
+ const int b = 1 - a;
+ const int m = h >> 1;
+ int y;
+
+ switch (mode) {
+ case MODE_DEINTERLEAVE:
+ for (y = 0; y < m; y++) {
+ memcpy(dst + dst_linesize * y , src + src_linesize * (y * 2 + a), w);
+ memcpy(dst + dst_linesize * (y + m), src + src_linesize * (y * 2 + b), w);
+ }
+ break;
+ case MODE_NONE:
+ for (y = 0; y < m; y++) {
+ memcpy(dst + dst_linesize * y * 2 , src + src_linesize * (y * 2 + a), w);
+ memcpy(dst + dst_linesize * (y * 2 + 1), src + src_linesize * (y * 2 + b), w);
+ }
+ break;
+ case MODE_INTERLEAVE:
+ for (y = 0; y < m; y++) {
+ memcpy(dst + dst_linesize * (y * 2 + a), src + src_linesize * y , w);
+ memcpy(dst + dst_linesize * (y * 2 + b), src + src_linesize * (y + m), w);
+ }
+ break;
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ IlContext *s = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out;
+ int comp;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, inpicref);
+
+ interleave(out->data[0], inpicref->data[0],
+ s->linesize[0], inlink->h,
+ out->linesize[0], inpicref->linesize[0],
+ s->luma_mode, s->luma_swap);
+
+ for (comp = 1; comp < (s->nb_planes - s->has_alpha); comp++) {
+ interleave(out->data[comp], inpicref->data[comp],
+ s->linesize[comp], s->chroma_height,
+ out->linesize[comp], inpicref->linesize[comp],
+ s->chroma_mode, s->chroma_swap);
+ }
+
+ if (s->has_alpha) {
+ comp = s->nb_planes - 1;
+ interleave(out->data[comp], inpicref->data[comp],
+ s->linesize[comp], inlink->h,
+ out->linesize[comp], inpicref->linesize[comp],
+ s->alpha_mode, s->alpha_swap);
+ }
+
+ av_frame_free(&inpicref);
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_il = {
+ .name = "il",
+ .description = NULL_IF_CONFIG_SMALL("Deinterleave or interleave fields."),
+ .priv_size = sizeof(IlContext),
+ .query_formats = query_formats,
+ .inputs = inputs,
+ .outputs = outputs,
+ .priv_class = &il_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_interlace.c b/libavfilter/vf_interlace.c
index 8ef58e4e89..a520776f57 100644
--- a/libavfilter/vf_interlace.c
+++ b/libavfilter/vf_interlace.c
@@ -1,18 +1,23 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
+ * Copyright (c) 2010 Baptiste Coudurier
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
@@ -34,7 +39,7 @@
#define OFFSET(x) offsetof(InterlaceContext, x)
#define V AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+static const AVOption interlace_options[] = {
{ "scan", "scanning mode", OFFSET(scan),
AV_OPT_TYPE_INT, {.i64 = MODE_TFF }, 0, 1, .flags = V, .unit = "scan" },
{ "tff", "top field first", 0,
@@ -46,12 +51,7 @@ static const AVOption options[] = {
{ NULL }
};
-static const AVClass class = {
- .class_name = "interlace filter",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(interlace);
static void lowpass_line_c(uint8_t *dstp, ptrdiff_t linesize,
const uint8_t *srcp,
@@ -76,8 +76,10 @@ static const enum AVPixelFormat formats_supported[] = {
static int query_formats(AVFilterContext *ctx)
{
- ff_set_common_formats(ctx, ff_make_format_list(formats_supported));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(formats_supported);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static av_cold void uninit(AVFilterContext *ctx)
@@ -86,8 +88,6 @@ static av_cold void uninit(AVFilterContext *ctx)
av_frame_free(&s->cur);
av_frame_free(&s->next);
-
- av_opt_free(s);
}
static int config_out_props(AVFilterLink *outlink)
@@ -109,8 +109,11 @@ static int config_out_props(AVFilterLink *outlink)
outlink->w = inlink->w;
outlink->h = inlink->h;
outlink->time_base = inlink->time_base;
+ outlink->frame_rate = inlink->frame_rate;
// half framerate
outlink->time_base.num *= 2;
+ outlink->frame_rate.den *= 2;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
if (s->lowpass) {
@@ -137,7 +140,7 @@ static void copy_picture_field(InterlaceContext *s,
for (plane = 0; plane < desc->nb_components; plane++) {
int cols = (plane == 1 || plane == 2) ? -(-inlink->w) >> hsub : inlink->w;
- int lines = (plane == 1 || plane == 2) ? -(-inlink->h) >> vsub : inlink->h;
+ int lines = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->h, vsub) : inlink->h;
uint8_t *dstp = dst_frame->data[plane];
const uint8_t *srcp = src_frame->data[plane];
@@ -194,7 +197,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
return AVERROR(ENOMEM);
out->pts /= 2; // adjust pts to new framerate
ret = ff_filter_frame(outlink, out);
- s->got_output = 1;
return ret;
}
@@ -217,20 +219,6 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
av_frame_free(&s->next);
ret = ff_filter_frame(outlink, out);
- s->got_output = 1;
-
- return ret;
-}
-
-static int request_frame(AVFilterLink *outlink)
-{
- AVFilterContext *ctx = outlink->src;
- InterlaceContext *s = ctx->priv;
- int ret = 0;
-
- s->got_output = 0;
- while (ret >= 0 && !s->got_output)
- ret = ff_request_frame(ctx->inputs[0]);
return ret;
}
@@ -246,10 +234,9 @@ static const AVFilterPad inputs[] = {
static const AVFilterPad outputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_out_props,
- .request_frame = request_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_out_props,
},
{ NULL }
};
@@ -258,12 +245,9 @@ AVFilter ff_vf_interlace = {
.name = "interlace",
.description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
.uninit = uninit,
-
- .priv_class = &class,
+ .priv_class = &interlace_class,
.priv_size = sizeof(InterlaceContext),
.query_formats = query_formats,
-
.inputs = inputs,
.outputs = outputs,
};
-
diff --git a/libavfilter/vf_kerndeint.c b/libavfilter/vf_kerndeint.c
new file mode 100644
index 0000000000..0e2417ad59
--- /dev/null
+++ b/libavfilter/vf_kerndeint.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2012 Jeremy Tran
+ * Copyright (c) 2004 Tobias Diedrich
+ * Copyright (c) 2003 Donald A. Graft
+ *
+ * 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
+ * Kernel Deinterlacer
+ * Ported from MPlayer libmpcodecs/vf_kerndeint.c.
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ int frame; ///< frame count, starting from 0
+ int thresh, map, order, sharp, twoway;
+ int vsub;
+ int is_packed_rgb;
+ uint8_t *tmp_data [4]; ///< temporary plane data buffer
+ int tmp_linesize[4]; ///< temporary plane byte linesize
+ int tmp_bwidth [4]; ///< temporary plane byte width
+} KerndeintContext;
+
+#define OFFSET(x) offsetof(KerndeintContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption kerndeint_options[] = {
+ { "thresh", "set the threshold", OFFSET(thresh), AV_OPT_TYPE_INT, {.i64=10}, 0, 255, FLAGS },
+ { "map", "set the map", OFFSET(map), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "order", "set the order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "sharp", "enable sharpening", OFFSET(sharp), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "twoway", "enable twoway", OFFSET(twoway), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(kerndeint);
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ KerndeintContext *kerndeint = ctx->priv;
+
+ av_freep(&kerndeint->tmp_data[0]);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUYV422,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_0RGB,
+ AV_PIX_FMT_ABGR, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB0,
+ AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ KerndeintContext *kerndeint = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ kerndeint->is_packed_rgb = av_pix_fmt_desc_get(inlink->format)->flags & AV_PIX_FMT_FLAG_RGB;
+ kerndeint->vsub = desc->log2_chroma_h;
+
+ ret = av_image_alloc(kerndeint->tmp_data, kerndeint->tmp_linesize,
+ inlink->w, inlink->h, inlink->format, 16);
+ if (ret < 0)
+ return ret;
+ memset(kerndeint->tmp_data[0], 0, ret);
+
+ if ((ret = av_image_fill_linesizes(kerndeint->tmp_bwidth, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ KerndeintContext *kerndeint = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpic;
+ const uint8_t *prvp; ///< Previous field's pixel line number n
+ const uint8_t *prvpp; ///< Previous field's pixel line number (n - 1)
+ const uint8_t *prvpn; ///< Previous field's pixel line number (n + 1)
+ const uint8_t *prvppp; ///< Previous field's pixel line number (n - 2)
+ const uint8_t *prvpnn; ///< Previous field's pixel line number (n + 2)
+ const uint8_t *prvp4p; ///< Previous field's pixel line number (n - 4)
+ const uint8_t *prvp4n; ///< Previous field's pixel line number (n + 4)
+
+ const uint8_t *srcp; ///< Current field's pixel line number n
+ const uint8_t *srcpp; ///< Current field's pixel line number (n - 1)
+ const uint8_t *srcpn; ///< Current field's pixel line number (n + 1)
+ const uint8_t *srcppp; ///< Current field's pixel line number (n - 2)
+ const uint8_t *srcpnn; ///< Current field's pixel line number (n + 2)
+ const uint8_t *srcp3p; ///< Current field's pixel line number (n - 3)
+ const uint8_t *srcp3n; ///< Current field's pixel line number (n + 3)
+ const uint8_t *srcp4p; ///< Current field's pixel line number (n - 4)
+ const uint8_t *srcp4n; ///< Current field's pixel line number (n + 4)
+
+ uint8_t *dstp, *dstp_saved;
+ const uint8_t *srcp_saved;
+
+ int src_linesize, psrc_linesize, dst_linesize, bwidth;
+ int x, y, plane, val, hi, lo, g, h, n = kerndeint->frame++;
+ double valf;
+
+ const int thresh = kerndeint->thresh;
+ const int order = kerndeint->order;
+ const int map = kerndeint->map;
+ const int sharp = kerndeint->sharp;
+ const int twoway = kerndeint->twoway;
+
+ const int is_packed_rgb = kerndeint->is_packed_rgb;
+
+ outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpic) {
+ av_frame_free(&inpic);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpic, inpic);
+ outpic->interlaced_frame = 0;
+
+ for (plane = 0; plane < 4 && inpic->data[plane] && inpic->linesize[plane]; plane++) {
+ h = plane == 0 ? inlink->h : FF_CEIL_RSHIFT(inlink->h, kerndeint->vsub);
+ bwidth = kerndeint->tmp_bwidth[plane];
+
+ srcp_saved = inpic->data[plane];
+ src_linesize = inpic->linesize[plane];
+ psrc_linesize = kerndeint->tmp_linesize[plane];
+ dstp_saved = outpic->data[plane];
+ dst_linesize = outpic->linesize[plane];
+ srcp = srcp_saved + (1 - order) * src_linesize;
+ dstp = dstp_saved + (1 - order) * dst_linesize;
+
+ for (y = 0; y < h; y += 2) {
+ memcpy(dstp, srcp, bwidth);
+ srcp += 2 * src_linesize;
+ dstp += 2 * dst_linesize;
+ }
+
+ // Copy through the lines that will be missed below.
+ memcpy(dstp_saved + order * dst_linesize, srcp_saved + (1 - order) * src_linesize, bwidth);
+ memcpy(dstp_saved + (2 + order ) * dst_linesize, srcp_saved + (3 - order) * src_linesize, bwidth);
+ memcpy(dstp_saved + (h - 2 + order) * dst_linesize, srcp_saved + (h - 1 - order) * src_linesize, bwidth);
+ memcpy(dstp_saved + (h - 4 + order) * dst_linesize, srcp_saved + (h - 3 - order) * src_linesize, bwidth);
+
+ /* For the other field choose adaptively between using the previous field
+ or the interpolant from the current field. */
+ prvp = kerndeint->tmp_data[plane] + 5 * psrc_linesize - (1 - order) * psrc_linesize;
+ prvpp = prvp - psrc_linesize;
+ prvppp = prvp - 2 * psrc_linesize;
+ prvp4p = prvp - 4 * psrc_linesize;
+ prvpn = prvp + psrc_linesize;
+ prvpnn = prvp + 2 * psrc_linesize;
+ prvp4n = prvp + 4 * psrc_linesize;
+
+ srcp = srcp_saved + 5 * src_linesize - (1 - order) * src_linesize;
+ srcpp = srcp - src_linesize;
+ srcppp = srcp - 2 * src_linesize;
+ srcp3p = srcp - 3 * src_linesize;
+ srcp4p = srcp - 4 * src_linesize;
+
+ srcpn = srcp + src_linesize;
+ srcpnn = srcp + 2 * src_linesize;
+ srcp3n = srcp + 3 * src_linesize;
+ srcp4n = srcp + 4 * src_linesize;
+
+ dstp = dstp_saved + 5 * dst_linesize - (1 - order) * dst_linesize;
+
+ for (y = 5 - (1 - order); y <= h - 5 - (1 - order); y += 2) {
+ for (x = 0; x < bwidth; x++) {
+ if (thresh == 0 || n == 0 ||
+ (abs((int)prvp[x] - (int)srcp[x]) > thresh) ||
+ (abs((int)prvpp[x] - (int)srcpp[x]) > thresh) ||
+ (abs((int)prvpn[x] - (int)srcpn[x]) > thresh)) {
+ if (map) {
+ g = x & ~3;
+
+ if (is_packed_rgb) {
+ AV_WB32(dstp + g, 0xffffffff);
+ x = g + 3;
+ } else if (inlink->format == AV_PIX_FMT_YUYV422) {
+ // y <- 235, u <- 128, y <- 235, v <- 128
+ AV_WB32(dstp + g, 0xeb80eb80);
+ x = g + 3;
+ } else {
+ dstp[x] = plane == 0 ? 235 : 128;
+ }
+ } else {
+ if (is_packed_rgb) {
+ hi = 255;
+ lo = 0;
+ } else if (inlink->format == AV_PIX_FMT_YUYV422) {
+ hi = x & 1 ? 240 : 235;
+ lo = 16;
+ } else {
+ hi = plane == 0 ? 235 : 240;
+ lo = 16;
+ }
+
+ if (sharp) {
+ if (twoway) {
+ valf = + 0.526 * ((int)srcpp[x] + (int)srcpn[x])
+ + 0.170 * ((int)srcp[x] + (int)prvp[x])
+ - 0.116 * ((int)srcppp[x] + (int)srcpnn[x] + (int)prvppp[x] + (int)prvpnn[x])
+ - 0.026 * ((int)srcp3p[x] + (int)srcp3n[x])
+ + 0.031 * ((int)srcp4p[x] + (int)srcp4n[x] + (int)prvp4p[x] + (int)prvp4n[x]);
+ } else {
+ valf = + 0.526 * ((int)srcpp[x] + (int)srcpn[x])
+ + 0.170 * ((int)prvp[x])
+ - 0.116 * ((int)prvppp[x] + (int)prvpnn[x])
+ - 0.026 * ((int)srcp3p[x] + (int)srcp3n[x])
+ + 0.031 * ((int)prvp4p[x] + (int)prvp4p[x]);
+ }
+ dstp[x] = av_clip(valf, lo, hi);
+ } else {
+ if (twoway) {
+ val = (8 * ((int)srcpp[x] + (int)srcpn[x]) + 2 * ((int)srcp[x] + (int)prvp[x])
+ - (int)(srcppp[x]) - (int)(srcpnn[x])
+ - (int)(prvppp[x]) - (int)(prvpnn[x])) >> 4;
+ } else {
+ val = (8 * ((int)srcpp[x] + (int)srcpn[x]) + 2 * ((int)prvp[x])
+ - (int)(prvppp[x]) - (int)(prvpnn[x])) >> 4;
+ }
+ dstp[x] = av_clip(val, lo, hi);
+ }
+ }
+ } else {
+ dstp[x] = srcp[x];
+ }
+ }
+ prvp += 2 * psrc_linesize;
+ prvpp += 2 * psrc_linesize;
+ prvppp += 2 * psrc_linesize;
+ prvpn += 2 * psrc_linesize;
+ prvpnn += 2 * psrc_linesize;
+ prvp4p += 2 * psrc_linesize;
+ prvp4n += 2 * psrc_linesize;
+ srcp += 2 * src_linesize;
+ srcpp += 2 * src_linesize;
+ srcppp += 2 * src_linesize;
+ srcp3p += 2 * src_linesize;
+ srcp4p += 2 * src_linesize;
+ srcpn += 2 * src_linesize;
+ srcpnn += 2 * src_linesize;
+ srcp3n += 2 * src_linesize;
+ srcp4n += 2 * src_linesize;
+ dstp += 2 * dst_linesize;
+ }
+
+ srcp = inpic->data[plane];
+ dstp = kerndeint->tmp_data[plane];
+ av_image_copy_plane(dstp, psrc_linesize, srcp, src_linesize, bwidth, h);
+ }
+
+ av_frame_free(&inpic);
+ return ff_filter_frame(outlink, outpic);
+}
+
+static const AVFilterPad kerndeint_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad kerndeint_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+
+AVFilter ff_vf_kerndeint = {
+ .name = "kerndeint",
+ .description = NULL_IF_CONFIG_SMALL("Apply kernel deinterlacing to the input."),
+ .priv_size = sizeof(KerndeintContext),
+ .priv_class = &kerndeint_class,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = kerndeint_inputs,
+ .outputs = kerndeint_outputs,
+};
diff --git a/libavfilter/vf_lenscorrection.c b/libavfilter/vf_lenscorrection.c
new file mode 100644
index 0000000000..9db483dd36
--- /dev/null
+++ b/libavfilter/vf_lenscorrection.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2007 Richard Spindler (author of frei0r plugin from which this was derived)
+ * Copyright (C) 2014 Daniel Oberhoff
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Lenscorrection filter, algorithm from the frei0r plugin with the same name
+*/
+#include <stdlib.h>
+#include <math.h>
+
+#include "libavutil/opt.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct LenscorrectionCtx {
+ const AVClass *av_class;
+ unsigned int width;
+ unsigned int height;
+ int hsub, vsub;
+ int nb_planes;
+ double cx, cy, k1, k2;
+ int32_t *correction[4];
+} LenscorrectionCtx;
+
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption lenscorrection_options[] = {
+ { "cx", "set relative center x", offsetof(LenscorrectionCtx, cx), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, .flags=FLAGS },
+ { "cy", "set relative center y", offsetof(LenscorrectionCtx, cy), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, .flags=FLAGS },
+ { "k1", "set quadratic distortion factor", offsetof(LenscorrectionCtx, k1), AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, -1, 1, .flags=FLAGS },
+ { "k2", "set double quadratic distortion factor", offsetof(LenscorrectionCtx, k2), AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, -1, 1, .flags=FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(lenscorrection);
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+ int w, h;
+ int plane;
+ int xcenter, ycenter;
+ int32_t *correction;
+} ThreadData;
+
+static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs)
+{
+ ThreadData *td = (ThreadData*)arg;
+ AVFrame *in = td->in;
+ AVFrame *out = td->out;
+
+ const int w = td->w, h = td->h;
+ const int xcenter = td->xcenter;
+ const int ycenter = td->ycenter;
+ const int start = (h * job ) / nb_jobs;
+ const int end = (h * (job+1)) / nb_jobs;
+ const int plane = td->plane;
+ const int inlinesize = in->linesize[plane];
+ const int outlinesize = out->linesize[plane];
+ const uint8_t *indata = in->data[plane];
+ uint8_t *outrow = out->data[plane] + start * outlinesize;
+ int i;
+ for (i = start; i < end; i++, outrow += outlinesize) {
+ const int off_y = i - ycenter;
+ uint8_t *out = outrow;
+ int j;
+ for (j = 0; j < w; j++) {
+ const int off_x = j - xcenter;
+ const int64_t radius_mult = td->correction[j + i*w];
+ const int x = xcenter + ((radius_mult * off_x + (1<<23))>>24);
+ const int y = ycenter + ((radius_mult * off_y + (1<<23))>>24);
+ const char isvalid = x > 0 && x < w - 1 && y > 0 && y < h - 1;
+ *out++ = isvalid ? indata[y * inlinesize + x] : 0;
+ }
+ }
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ LenscorrectionCtx *rect = ctx->priv;
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(rect->correction); i++) {
+ av_freep(&rect->correction[i]);
+ }
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ LenscorrectionCtx *rect = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(inlink->format);
+ rect->hsub = pixdesc->log2_chroma_w;
+ rect->vsub = pixdesc->log2_chroma_h;
+ outlink->w = rect->width = inlink->w;
+ outlink->h = rect->height = inlink->h;
+ rect->nb_planes = av_pix_fmt_count_planes(inlink->format);
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ LenscorrectionCtx *rect = (LenscorrectionCtx*)ctx->priv;
+ AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ int plane;
+
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+
+ av_frame_copy_props(out, in);
+
+ for (plane = 0; plane < rect->nb_planes; ++plane) {
+ int hsub = plane == 1 || plane == 2 ? rect->hsub : 0;
+ int vsub = plane == 1 || plane == 2 ? rect->vsub : 0;
+ int hdiv = 1 << hsub;
+ int vdiv = 1 << vsub;
+ int w = rect->width / hdiv;
+ int h = rect->height / vdiv;
+ int xcenter = rect->cx * w;
+ int ycenter = rect->cy * h;
+ int k1 = rect->k1 * (1<<24);
+ int k2 = rect->k2 * (1<<24);
+ ThreadData td = {
+ .in = in,
+ .out = out,
+ .w = w,
+ .h = h,
+ .xcenter = xcenter,
+ .ycenter = ycenter,
+ .plane = plane};
+
+ if (!rect->correction[plane]) {
+ int i,j;
+ const int64_t r2inv = (4LL<<60) / (w * w + h * h);
+
+ rect->correction[plane] = av_malloc_array(w, h * sizeof(**rect->correction));
+ if (!rect->correction[plane])
+ return AVERROR(ENOMEM);
+ for (j = 0; j < h; j++) {
+ const int off_y = j - ycenter;
+ const int off_y2 = off_y * off_y;
+ for (i = 0; i < w; i++) {
+ const int off_x = i - xcenter;
+ const int64_t r2 = ((off_x * off_x + off_y2) * r2inv + (1LL<<31)) >> 32;
+ const int64_t r4 = (r2 * r2 + (1<<27)) >> 28;
+ const int radius_mult = (r2 * k1 + r4 * k2 + (1LL<<27) + (1LL<<52))>>28;
+ rect->correction[plane][j * w + i] = radius_mult;
+ }
+ }
+ }
+
+ td.correction = rect->correction[plane];
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(h, ctx->graph->nb_threads));
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad lenscorrection_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad lenscorrection_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_lenscorrection = {
+ .name = "lenscorrection",
+ .description = NULL_IF_CONFIG_SMALL("Rectify the image by correcting for lens distortion."),
+ .priv_size = sizeof(LenscorrectionCtx),
+ .query_formats = query_formats,
+ .inputs = lenscorrection_inputs,
+ .outputs = lenscorrection_outputs,
+ .priv_class = &lenscorrection_class,
+ .uninit = uninit,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_libopencv.c b/libavfilter/vf_libopencv.c
index 50d02f84a8..be27552995 100644
--- a/libavfilter/vf_libopencv.c
+++ b/libavfilter/vf_libopencv.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -63,9 +63,10 @@ static int query_formats(AVFilterContext *ctx)
static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
};
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
typedef struct OCVContext {
@@ -166,7 +167,7 @@ static int read_shape_from_file(int *cols, int *rows, int **values, const char *
*rows, *cols);
return AVERROR_INVALIDDATA;
}
- if (!(*values = av_mallocz(sizeof(int) * *rows * *cols)))
+ if (!(*values = av_mallocz_array(sizeof(int) * *rows, *cols)))
return AVERROR(ENOMEM);
/* fill *values */
@@ -265,10 +266,9 @@ static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
const char *buf = args;
int ret;
- dilate->nb_iterations = 1;
-
if (args) {
kernel_str = av_get_token(&buf, "|");
+
if (!kernel_str)
return AVERROR(ENOMEM);
}
@@ -281,7 +281,8 @@ static av_cold int dilate_init(AVFilterContext *ctx, const char *args)
if (ret < 0)
return ret;
- sscanf(buf, "|%d", &dilate->nb_iterations);
+ if (!buf || sscanf(buf, "|%d", &dilate->nb_iterations) != 1)
+ dilate->nb_iterations = 1;
av_log(ctx, AV_LOG_VERBOSE, "iterations_nb:%d\n", dilate->nb_iterations);
if (dilate->nb_iterations <= 0) {
av_log(ctx, AV_LOG_ERROR, "Invalid non-positive value '%d' for nb_iterations\n",
@@ -321,7 +322,7 @@ typedef struct OCVFilterEntry {
void (*end_frame_filter)(AVFilterContext *ctx, IplImage *inimg, IplImage *outimg);
} OCVFilterEntry;
-static OCVFilterEntry ocv_filter_entries[] = {
+static const OCVFilterEntry ocv_filter_entries[] = {
{ "dilate", sizeof(DilateContext), dilate_init, dilate_uninit, dilate_end_frame_filter },
{ "erode", sizeof(DilateContext), dilate_init, dilate_uninit, erode_end_frame_filter },
{ "smooth", sizeof(SmoothContext), smooth_init, NULL, smooth_end_frame_filter },
@@ -332,8 +333,12 @@ static av_cold int init(AVFilterContext *ctx)
OCVContext *s = ctx->priv;
int i;
+ if (!s->name) {
+ av_log(ctx, AV_LOG_ERROR, "No libopencv filter name specified\n");
+ return AVERROR(EINVAL);
+ }
for (i = 0; i < FF_ARRAY_ELEMS(ocv_filter_entries); i++) {
- OCVFilterEntry *entry = &ocv_filter_entries[i];
+ const OCVFilterEntry *entry = &ocv_filter_entries[i];
if (!strcmp(s->name, entry->name)) {
s->init = entry->init;
s->uninit = entry->uninit;
@@ -355,7 +360,7 @@ static av_cold void uninit(AVFilterContext *ctx)
if (s->uninit)
s->uninit(ctx);
- av_free(s->priv);
+ av_freep(&s->priv);
}
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
@@ -384,24 +389,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(OCVContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption ocv_options[] = {
{ "filter_name", NULL, OFFSET(name), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ "filter_params", NULL, OFFSET(params), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { NULL },
+ { NULL }
};
-static const AVClass ocv_class = {
- .class_name = "ocv",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(ocv);
static const AVFilterPad avfilter_vf_ocv_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
},
{ NULL }
@@ -416,17 +416,13 @@ static const AVFilterPad avfilter_vf_ocv_outputs[] = {
};
AVFilter ff_vf_ocv = {
- .name = "ocv",
- .description = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
-
- .priv_size = sizeof(OCVContext),
- .priv_class = &ocv_class,
-
+ .name = "ocv",
+ .description = NULL_IF_CONFIG_SMALL("Apply transform using libopencv."),
+ .priv_size = sizeof(OCVContext),
+ .priv_class = &ocv_class,
.query_formats = query_formats,
- .init = init,
- .uninit = uninit,
-
- .inputs = avfilter_vf_ocv_inputs,
-
- .outputs = avfilter_vf_ocv_outputs,
+ .init = init,
+ .uninit = uninit,
+ .inputs = avfilter_vf_ocv_inputs,
+ .outputs = avfilter_vf_ocv_outputs,
};
diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c
index 9299d4019a..93b18a82cb 100644
--- a/libavfilter/vf_lut.c
+++ b/libavfilter/vf_lut.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,18 +27,15 @@
#include "libavutil/attributes.h"
#include "libavutil/common.h"
#include "libavutil/eval.h"
-#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avfilter.h"
+#include "drawutils.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
"w", ///< width of the input video
"h", ///< height of the input video
"val", ///< input value for the pixel
@@ -50,9 +47,6 @@ static const char *const var_names[] = {
};
enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
VAR_W,
VAR_H,
VAR_VAL,
@@ -71,7 +65,6 @@ typedef struct LutContext {
int hsub, vsub;
double var_values[VAR_VARS_NB];
int is_rgb, is_yuv;
- int rgba_map[4];
int step;
int negate_alpha; /* only used by negate */
} LutContext;
@@ -85,9 +78,9 @@ typedef struct LutContext {
#define A 3
#define OFFSET(x) offsetof(LutContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption lut_options[] = {
+static const AVOption options[] = {
{ "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "val" }, .flags = FLAGS },
{ "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "val" }, .flags = FLAGS },
{ "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "val" }, .flags = FLAGS },
@@ -99,23 +92,9 @@ static const AVOption lut_options[] = {
{ "g", "set G expression", OFFSET(comp_expr_str[G]), AV_OPT_TYPE_STRING, { .str = "val" }, .flags = FLAGS },
{ "b", "set B expression", OFFSET(comp_expr_str[B]), AV_OPT_TYPE_STRING, { .str = "val" }, .flags = FLAGS },
{ "a", "set A expression", OFFSET(comp_expr_str[A]), AV_OPT_TYPE_STRING, { .str = "val" }, .flags = FLAGS },
- { NULL },
+ { NULL }
};
-static av_cold int init(AVFilterContext *ctx)
-{
- LutContext *s = ctx->priv;
-
- s->var_values[VAR_PHI] = M_PHI;
- s->var_values[VAR_PI] = M_PI;
- s->var_values[VAR_E ] = M_E;
-
- s->is_rgb = !strcmp(ctx->filter->name, "lutrgb");
- s->is_yuv = !strcmp(ctx->filter->name, "lutyuv");
-
- return 0;
-}
-
static av_cold void uninit(AVFilterContext *ctx)
{
LutContext *s = ctx->priv;
@@ -131,7 +110,7 @@ static av_cold void uninit(AVFilterContext *ctx)
#define YUV_FORMATS \
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_YUVA420P, \
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, \
AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, \
AV_PIX_FMT_YUVJ440P
@@ -151,9 +130,10 @@ static int query_formats(AVFilterContext *ctx)
const enum AVPixelFormat *pix_fmts = s->is_rgb ? rgb_pix_fmts :
s->is_yuv ? yuv_pix_fmts :
all_pix_fmts;
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
/**
@@ -182,15 +162,32 @@ static double compute_gammaval(void *opaque, double gamma)
return pow((val-minval)/(maxval-minval), gamma) * (maxval-minval)+minval;
}
+/**
+ * Compute ITU Rec.709 gamma correction of value val.
+ */
+static double compute_gammaval709(void *opaque, double gamma)
+{
+ LutContext *s = opaque;
+ double val = s->var_values[VAR_CLIPVAL];
+ double minval = s->var_values[VAR_MINVAL];
+ double maxval = s->var_values[VAR_MAXVAL];
+ double level = (val - minval) / (maxval - minval);
+ level = level < 0.018 ? 4.5 * level
+ : 1.099 * pow(level, 1.0 / gamma) - 0.099;
+ return level * (maxval - minval) + minval;
+}
+
static double (* const funcs1[])(void *, double) = {
- clip,
- compute_gammaval,
+ (void *)clip,
+ (void *)compute_gammaval,
+ (void *)compute_gammaval709,
NULL
};
static const char * const funcs1_names[] = {
"clip",
"gammaval",
+ "gammaval709",
NULL
};
@@ -199,8 +196,9 @@ static int config_props(AVFilterLink *inlink)
AVFilterContext *ctx = inlink->dst;
LutContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ uint8_t rgba_map[4]; /* component index -> RGBA color index map */
int min[4], max[4];
- int val, comp, ret;
+ int val, color, ret;
s->hsub = desc->log2_chroma_w;
s->vsub = desc->log2_chroma_h;
@@ -216,6 +214,8 @@ static int config_props(AVFilterLink *inlink)
case AV_PIX_FMT_YUV440P:
case AV_PIX_FMT_YUV444P:
case AV_PIX_FMT_YUVA420P:
+ case AV_PIX_FMT_YUVA422P:
+ case AV_PIX_FMT_YUVA444P:
min[Y] = min[U] = min[V] = 16;
max[Y] = 235;
max[U] = max[V] = 240;
@@ -231,51 +231,45 @@ static int config_props(AVFilterLink *inlink)
else if (ff_fmt_is_in(inlink->format, rgb_pix_fmts)) s->is_rgb = 1;
if (s->is_rgb) {
- switch (inlink->format) {
- case AV_PIX_FMT_ARGB: s->rgba_map[A] = 0; s->rgba_map[R] = 1; s->rgba_map[G] = 2; s->rgba_map[B] = 3; break;
- case AV_PIX_FMT_ABGR: s->rgba_map[A] = 0; s->rgba_map[B] = 1; s->rgba_map[G] = 2; s->rgba_map[R] = 3; break;
- case AV_PIX_FMT_RGBA:
- case AV_PIX_FMT_RGB24: s->rgba_map[R] = 0; s->rgba_map[G] = 1; s->rgba_map[B] = 2; s->rgba_map[A] = 3; break;
- case AV_PIX_FMT_BGRA:
- case AV_PIX_FMT_BGR24: s->rgba_map[B] = 0; s->rgba_map[G] = 1; s->rgba_map[R] = 2; s->rgba_map[A] = 3; break;
- }
+ ff_fill_rgba_map(rgba_map, inlink->format);
s->step = av_get_bits_per_pixel(desc) >> 3;
}
- for (comp = 0; comp < desc->nb_components; comp++) {
+ for (color = 0; color < desc->nb_components; color++) {
double res;
+ int comp = s->is_rgb ? rgba_map[color] : color;
/* create the parsed expression */
- av_expr_free(s->comp_expr[comp]);
- s->comp_expr[comp] = NULL;
- ret = av_expr_parse(&s->comp_expr[comp], s->comp_expr_str[comp],
+ av_expr_free(s->comp_expr[color]);
+ s->comp_expr[color] = NULL;
+ ret = av_expr_parse(&s->comp_expr[color], s->comp_expr_str[color],
var_names, funcs1_names, funcs1, NULL, NULL, 0, ctx);
if (ret < 0) {
av_log(ctx, AV_LOG_ERROR,
- "Error when parsing the expression '%s' for the component %d.\n",
- s->comp_expr_str[comp], comp);
+ "Error when parsing the expression '%s' for the component %d and color %d.\n",
+ s->comp_expr_str[comp], comp, color);
return AVERROR(EINVAL);
}
- /* compute the s */
- s->var_values[VAR_MAXVAL] = max[comp];
- s->var_values[VAR_MINVAL] = min[comp];
+ /* compute the lut */
+ s->var_values[VAR_MAXVAL] = max[color];
+ s->var_values[VAR_MINVAL] = min[color];
for (val = 0; val < 256; val++) {
s->var_values[VAR_VAL] = val;
- s->var_values[VAR_CLIPVAL] = av_clip(val, min[comp], max[comp]);
+ s->var_values[VAR_CLIPVAL] = av_clip(val, min[color], max[color]);
s->var_values[VAR_NEGVAL] =
- av_clip(min[comp] + max[comp] - s->var_values[VAR_VAL],
- min[comp], max[comp]);
+ av_clip(min[color] + max[color] - s->var_values[VAR_VAL],
+ min[color], max[color]);
- res = av_expr_eval(s->comp_expr[comp], s->var_values, s);
+ res = av_expr_eval(s->comp_expr[color], s->var_values, s);
if (isnan(res)) {
av_log(ctx, AV_LOG_ERROR,
- "Error when evaluating the expression '%s' for the value %d for the component #%d.\n",
- s->comp_expr_str[comp], val, comp);
+ "Error when evaluating the expression '%s' for the value %d for the component %d.\n",
+ s->comp_expr_str[color], val, comp);
return AVERROR(EINVAL);
}
- s->lut[comp][val] = av_clip((int)res, min[comp], max[comp]);
+ s->lut[comp][val] = av_clip((int)res, min[color], max[color]);
av_log(ctx, AV_LOG_DEBUG, "val[%d][%d] = %d\n", comp, val, s->lut[comp][val]);
}
}
@@ -290,105 +284,162 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
AVFilterLink *outlink = ctx->outputs[0];
AVFrame *out;
uint8_t *inrow, *outrow, *inrow0, *outrow0;
- int i, j, k, plane;
+ int i, j, plane, direct = 0;
- out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
- if (!out) {
- av_frame_free(&in);
- return AVERROR(ENOMEM);
+ if (av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
}
- av_frame_copy_props(out, in);
if (s->is_rgb) {
/* packed */
+ const int w = inlink->w;
+ const int h = in->height;
+ const uint8_t (*tab)[256] = (const uint8_t (*)[256])s->lut;
+ const int in_linesize = in->linesize[0];
+ const int out_linesize = out->linesize[0];
+ const int step = s->step;
+
inrow0 = in ->data[0];
outrow0 = out->data[0];
- for (i = 0; i < in->height; i ++) {
+ for (i = 0; i < h; i ++) {
inrow = inrow0;
outrow = outrow0;
- for (j = 0; j < inlink->w; j++) {
- for (k = 0; k < s->step; k++)
- outrow[k] = s->lut[s->rgba_map[k]][inrow[k]];
- outrow += s->step;
- inrow += s->step;
+ for (j = 0; j < w; j++) {
+ switch (step) {
+ case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through
+ case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through
+ case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through
+ default: outrow[0] = tab[0][inrow[0]];
+ }
+ outrow += step;
+ inrow += step;
}
- inrow0 += in ->linesize[0];
- outrow0 += out->linesize[0];
+ inrow0 += in_linesize;
+ outrow0 += out_linesize;
}
} else {
/* planar */
- for (plane = 0; plane < 4 && in->data[plane]; plane++) {
+ for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) {
int vsub = plane == 1 || plane == 2 ? s->vsub : 0;
int hsub = plane == 1 || plane == 2 ? s->hsub : 0;
+ int h = FF_CEIL_RSHIFT(inlink->h, vsub);
+ int w = FF_CEIL_RSHIFT(inlink->w, hsub);
+ const uint8_t *tab = s->lut[plane];
+ const int in_linesize = in->linesize[plane];
+ const int out_linesize = out->linesize[plane];
inrow = in ->data[plane];
outrow = out->data[plane];
- for (i = 0; i < in->height >> vsub; i ++) {
- for (j = 0; j < inlink->w>>hsub; j++)
- outrow[j] = s->lut[plane][inrow[j]];
- inrow += in ->linesize[plane];
- outrow += out->linesize[plane];
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++)
+ outrow[j] = tab[inrow[j]];
+ inrow += in_linesize;
+ outrow += out_linesize;
}
}
}
- av_frame_free(&in);
+ if (!direct)
+ av_frame_free(&in);
+
return ff_filter_frame(outlink, out);
}
static const AVFilterPad inputs[] = {
- { .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .filter_frame = filter_frame,
- .config_props = config_props,
+ { .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
},
- { .name = NULL}
+ { NULL }
};
static const AVFilterPad outputs[] = {
- { .name = "default",
- .type = AVMEDIA_TYPE_VIDEO, },
- { .name = NULL}
+ { .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
};
-#define DEFINE_LUT_FILTER(name_, description_, init_, options) \
- static const AVClass name_ ## _class = { \
- .class_name = #name_, \
- .item_name = av_default_item_name, \
- .option = options, \
- .version = LIBAVUTIL_VERSION_INT, \
- }; \
+
+#define DEFINE_LUT_FILTER(name_, description_) \
AVFilter ff_vf_##name_ = { \
.name = #name_, \
.description = NULL_IF_CONFIG_SMALL(description_), \
.priv_size = sizeof(LutContext), \
.priv_class = &name_ ## _class, \
- \
- .init = init_, \
+ .init = name_##_init, \
.uninit = uninit, \
.query_formats = query_formats, \
- \
.inputs = inputs, \
.outputs = outputs, \
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, \
}
#if CONFIG_LUT_FILTER
-DEFINE_LUT_FILTER(lut, "Compute and apply a lookup table to the RGB/YUV input video.", init, lut_options);
+
+#define lut_options options
+AVFILTER_DEFINE_CLASS(lut);
+
+static int lut_init(AVFilterContext *ctx)
+{
+ return 0;
+}
+
+DEFINE_LUT_FILTER(lut, "Compute and apply a lookup table to the RGB/YUV input video.");
#endif
+
#if CONFIG_LUTYUV_FILTER
-DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video.", init, lut_options);
+
+#define lutyuv_options options
+AVFILTER_DEFINE_CLASS(lutyuv);
+
+static av_cold int lutyuv_init(AVFilterContext *ctx)
+{
+ LutContext *s = ctx->priv;
+
+ s->is_yuv = 1;
+
+ return 0;
+}
+
+DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video.");
#endif
+
#if CONFIG_LUTRGB_FILTER
-DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video.", init, lut_options);
+
+#define lutrgb_options options
+AVFILTER_DEFINE_CLASS(lutrgb);
+
+static av_cold int lutrgb_init(AVFilterContext *ctx)
+{
+ LutContext *s = ctx->priv;
+
+ s->is_rgb = 1;
+
+ return 0;
+}
+
+DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video.");
#endif
#if CONFIG_NEGATE_FILTER
static const AVOption negate_options[] = {
- { "negate_alpha", NULL, OFFSET(negate_alpha), AV_OPT_TYPE_INT, { .i64 = 0 }, .flags = FLAGS },
- { NULL },
+ { "negate_alpha", NULL, OFFSET(negate_alpha), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(negate);
+
static av_cold int negate_init(AVFilterContext *ctx)
{
LutContext *s = ctx->priv;
@@ -397,7 +448,7 @@ static av_cold int negate_init(AVFilterContext *ctx)
av_log(ctx, AV_LOG_DEBUG, "negate_alpha:%d\n", s->negate_alpha);
for (i = 0; i < 4; i++) {
- s->comp_expr_str[i] = av_strdup((i == 3 && s->negate_alpha) ?
+ s->comp_expr_str[i] = av_strdup((i == 3 && !s->negate_alpha) ?
"val" : "negval");
if (!s->comp_expr_str[i]) {
uninit(ctx);
@@ -405,9 +456,9 @@ static av_cold int negate_init(AVFilterContext *ctx)
}
}
- return init(ctx);
+ return 0;
}
-DEFINE_LUT_FILTER(negate, "Negate input video.", negate_init, negate_options);
+DEFINE_LUT_FILTER(negate, "Negate input video.");
#endif
diff --git a/libavfilter/vf_lut3d.c b/libavfilter/vf_lut3d.c
new file mode 100644
index 0000000000..3ef31ce6c2
--- /dev/null
+++ b/libavfilter/vf_lut3d.c
@@ -0,0 +1,817 @@
+/*
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * 3D Lookup table filter
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/file.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/avstring.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "dualinput.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+enum interp_mode {
+ INTERPOLATE_NEAREST,
+ INTERPOLATE_TRILINEAR,
+ INTERPOLATE_TETRAHEDRAL,
+ NB_INTERP_MODE
+};
+
+struct rgbvec {
+ float r, g, b;
+};
+
+/* 3D LUT don't often go up to level 32, but it is common to have a Hald CLUT
+ * of 512x512 (64x64x64) */
+#define MAX_LEVEL 64
+
+typedef struct LUT3DContext {
+ const AVClass *class;
+ int interpolation; ///<interp_mode
+ char *file;
+ uint8_t rgba_map[4];
+ int step;
+ avfilter_action_func *interp;
+ struct rgbvec lut[MAX_LEVEL][MAX_LEVEL][MAX_LEVEL];
+ int lutsize;
+#if CONFIG_HALDCLUT_FILTER
+ uint8_t clut_rgba_map[4];
+ int clut_step;
+ int clut_is16bit;
+ int clut_width;
+ FFDualInputContext dinput;
+#endif
+} LUT3DContext;
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
+
+#define OFFSET(x) offsetof(LUT3DContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+#define COMMON_OPTIONS \
+ { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_TETRAHEDRAL}, 0, NB_INTERP_MODE-1, FLAGS, "interp_mode" }, \
+ { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
+ { "trilinear", "interpolate values using the 8 points defining a cube", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TRILINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
+ { "tetrahedral", "interpolate values using a tetrahedron", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_TETRAHEDRAL}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, \
+ { NULL }
+
+static inline float lerpf(float v0, float v1, float f)
+{
+ return v0 + (v1 - v0) * f;
+}
+
+static inline struct rgbvec lerp(const struct rgbvec *v0, const struct rgbvec *v1, float f)
+{
+ struct rgbvec v = {
+ lerpf(v0->r, v1->r, f), lerpf(v0->g, v1->g, f), lerpf(v0->b, v1->b, f)
+ };
+ return v;
+}
+
+#define NEAR(x) ((int)((x) + .5))
+#define PREV(x) ((int)(x))
+#define NEXT(x) (FFMIN((int)(x) + 1, lut3d->lutsize - 1))
+
+/**
+ * Get the nearest defined point
+ */
+static inline struct rgbvec interp_nearest(const LUT3DContext *lut3d,
+ const struct rgbvec *s)
+{
+ return lut3d->lut[NEAR(s->r)][NEAR(s->g)][NEAR(s->b)];
+}
+
+/**
+ * Interpolate using the 8 vertices of a cube
+ * @see https://en.wikipedia.org/wiki/Trilinear_interpolation
+ */
+static inline struct rgbvec interp_trilinear(const LUT3DContext *lut3d,
+ const struct rgbvec *s)
+{
+ const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
+ const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
+ const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
+ const struct rgbvec c000 = lut3d->lut[prev[0]][prev[1]][prev[2]];
+ const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
+ const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
+ const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
+ const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
+ const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
+ const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
+ const struct rgbvec c111 = lut3d->lut[next[0]][next[1]][next[2]];
+ const struct rgbvec c00 = lerp(&c000, &c100, d.r);
+ const struct rgbvec c10 = lerp(&c010, &c110, d.r);
+ const struct rgbvec c01 = lerp(&c001, &c101, d.r);
+ const struct rgbvec c11 = lerp(&c011, &c111, d.r);
+ const struct rgbvec c0 = lerp(&c00, &c10, d.g);
+ const struct rgbvec c1 = lerp(&c01, &c11, d.g);
+ const struct rgbvec c = lerp(&c0, &c1, d.b);
+ return c;
+}
+
+/**
+ * Tetrahedral interpolation. Based on code found in Truelight Software Library paper.
+ * @see http://www.filmlight.ltd.uk/pdf/whitepapers/FL-TL-TN-0057-SoftwareLib.pdf
+ */
+static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d,
+ const struct rgbvec *s)
+{
+ const int prev[] = {PREV(s->r), PREV(s->g), PREV(s->b)};
+ const int next[] = {NEXT(s->r), NEXT(s->g), NEXT(s->b)};
+ const struct rgbvec d = {s->r - prev[0], s->g - prev[1], s->b - prev[2]};
+ const struct rgbvec c000 = lut3d->lut[prev[0]][prev[1]][prev[2]];
+ const struct rgbvec c111 = lut3d->lut[next[0]][next[1]][next[2]];
+ struct rgbvec c;
+ if (d.r > d.g) {
+ if (d.g > d.b) {
+ const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
+ const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
+ c.r = (1-d.r) * c000.r + (d.r-d.g) * c100.r + (d.g-d.b) * c110.r + (d.b) * c111.r;
+ c.g = (1-d.r) * c000.g + (d.r-d.g) * c100.g + (d.g-d.b) * c110.g + (d.b) * c111.g;
+ c.b = (1-d.r) * c000.b + (d.r-d.g) * c100.b + (d.g-d.b) * c110.b + (d.b) * c111.b;
+ } else if (d.r > d.b) {
+ const struct rgbvec c100 = lut3d->lut[next[0]][prev[1]][prev[2]];
+ const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
+ c.r = (1-d.r) * c000.r + (d.r-d.b) * c100.r + (d.b-d.g) * c101.r + (d.g) * c111.r;
+ c.g = (1-d.r) * c000.g + (d.r-d.b) * c100.g + (d.b-d.g) * c101.g + (d.g) * c111.g;
+ c.b = (1-d.r) * c000.b + (d.r-d.b) * c100.b + (d.b-d.g) * c101.b + (d.g) * c111.b;
+ } else {
+ const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
+ const struct rgbvec c101 = lut3d->lut[next[0]][prev[1]][next[2]];
+ c.r = (1-d.b) * c000.r + (d.b-d.r) * c001.r + (d.r-d.g) * c101.r + (d.g) * c111.r;
+ c.g = (1-d.b) * c000.g + (d.b-d.r) * c001.g + (d.r-d.g) * c101.g + (d.g) * c111.g;
+ c.b = (1-d.b) * c000.b + (d.b-d.r) * c001.b + (d.r-d.g) * c101.b + (d.g) * c111.b;
+ }
+ } else {
+ if (d.b > d.g) {
+ const struct rgbvec c001 = lut3d->lut[prev[0]][prev[1]][next[2]];
+ const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
+ c.r = (1-d.b) * c000.r + (d.b-d.g) * c001.r + (d.g-d.r) * c011.r + (d.r) * c111.r;
+ c.g = (1-d.b) * c000.g + (d.b-d.g) * c001.g + (d.g-d.r) * c011.g + (d.r) * c111.g;
+ c.b = (1-d.b) * c000.b + (d.b-d.g) * c001.b + (d.g-d.r) * c011.b + (d.r) * c111.b;
+ } else if (d.b > d.r) {
+ const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
+ const struct rgbvec c011 = lut3d->lut[prev[0]][next[1]][next[2]];
+ c.r = (1-d.g) * c000.r + (d.g-d.b) * c010.r + (d.b-d.r) * c011.r + (d.r) * c111.r;
+ c.g = (1-d.g) * c000.g + (d.g-d.b) * c010.g + (d.b-d.r) * c011.g + (d.r) * c111.g;
+ c.b = (1-d.g) * c000.b + (d.g-d.b) * c010.b + (d.b-d.r) * c011.b + (d.r) * c111.b;
+ } else {
+ const struct rgbvec c010 = lut3d->lut[prev[0]][next[1]][prev[2]];
+ const struct rgbvec c110 = lut3d->lut[next[0]][next[1]][prev[2]];
+ c.r = (1-d.g) * c000.r + (d.g-d.r) * c010.r + (d.r-d.b) * c110.r + (d.b) * c111.r;
+ c.g = (1-d.g) * c000.g + (d.g-d.r) * c010.g + (d.r-d.b) * c110.g + (d.b) * c111.g;
+ c.b = (1-d.g) * c000.b + (d.g-d.r) * c010.b + (d.r-d.b) * c110.b + (d.b) * c111.b;
+ }
+ }
+ return c;
+}
+
+#define DEFINE_INTERP_FUNC(name, nbits) \
+static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
+{ \
+ int x, y; \
+ const LUT3DContext *lut3d = ctx->priv; \
+ const ThreadData *td = arg; \
+ const AVFrame *in = td->in; \
+ const AVFrame *out = td->out; \
+ const int direct = out == in; \
+ const int step = lut3d->step; \
+ const uint8_t r = lut3d->rgba_map[R]; \
+ const uint8_t g = lut3d->rgba_map[G]; \
+ const uint8_t b = lut3d->rgba_map[B]; \
+ const uint8_t a = lut3d->rgba_map[A]; \
+ const int slice_start = (in->height * jobnr ) / nb_jobs; \
+ const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \
+ uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \
+ const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \
+ const float scale = (1. / ((1<<nbits) - 1)) * (lut3d->lutsize - 1); \
+ \
+ for (y = slice_start; y < slice_end; y++) { \
+ uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \
+ const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \
+ for (x = 0; x < in->width * step; x += step) { \
+ const struct rgbvec scaled_rgb = {src[x + r] * scale, \
+ src[x + g] * scale, \
+ src[x + b] * scale}; \
+ struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \
+ dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<<nbits) - 1)); \
+ dst[x + g] = av_clip_uint##nbits(vec.g * (float)((1<<nbits) - 1)); \
+ dst[x + b] = av_clip_uint##nbits(vec.b * (float)((1<<nbits) - 1)); \
+ if (!direct && step == 4) \
+ dst[x + a] = src[x + a]; \
+ } \
+ dstrow += out->linesize[0]; \
+ srcrow += in ->linesize[0]; \
+ } \
+ return 0; \
+}
+
+DEFINE_INTERP_FUNC(nearest, 8)
+DEFINE_INTERP_FUNC(trilinear, 8)
+DEFINE_INTERP_FUNC(tetrahedral, 8)
+
+DEFINE_INTERP_FUNC(nearest, 16)
+DEFINE_INTERP_FUNC(trilinear, 16)
+DEFINE_INTERP_FUNC(tetrahedral, 16)
+
+#define MAX_LINE_SIZE 512
+
+static int skip_line(const char *p)
+{
+ while (*p && av_isspace(*p))
+ p++;
+ return !*p || *p == '#';
+}
+
+#define NEXT_LINE(loop_cond) do { \
+ if (!fgets(line, sizeof(line), f)) { \
+ av_log(ctx, AV_LOG_ERROR, "Unexpected EOF\n"); \
+ return AVERROR_INVALIDDATA; \
+ } \
+} while (loop_cond)
+
+/* Basically r g and b float values on each line, with a facultative 3DLUTSIZE
+ * directive; seems to be generated by Davinci */
+static int parse_dat(AVFilterContext *ctx, FILE *f)
+{
+ LUT3DContext *lut3d = ctx->priv;
+ char line[MAX_LINE_SIZE];
+ int i, j, k, size;
+
+ lut3d->lutsize = size = 33;
+
+ NEXT_LINE(skip_line(line));
+ if (!strncmp(line, "3DLUTSIZE ", 10)) {
+ size = strtol(line + 10, NULL, 0);
+ if (size < 2 || size > MAX_LEVEL) {
+ av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
+ return AVERROR(EINVAL);
+ }
+ lut3d->lutsize = size;
+ NEXT_LINE(skip_line(line));
+ }
+ for (k = 0; k < size; k++) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
+ struct rgbvec *vec = &lut3d->lut[k][j][i];
+ if (k != 0 || j != 0 || i != 0)
+ NEXT_LINE(skip_line(line));
+ if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Iridas format */
+static int parse_cube(AVFilterContext *ctx, FILE *f)
+{
+ LUT3DContext *lut3d = ctx->priv;
+ char line[MAX_LINE_SIZE];
+ float min[3] = {0.0, 0.0, 0.0};
+ float max[3] = {1.0, 1.0, 1.0};
+
+ while (fgets(line, sizeof(line), f)) {
+ if (!strncmp(line, "LUT_3D_SIZE ", 12)) {
+ int i, j, k;
+ const int size = strtol(line + 12, NULL, 0);
+
+ if (size < 2 || size > MAX_LEVEL) {
+ av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n");
+ return AVERROR(EINVAL);
+ }
+ lut3d->lutsize = size;
+ for (k = 0; k < size; k++) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
+ struct rgbvec *vec = &lut3d->lut[i][j][k];
+
+ do {
+ NEXT_LINE(0);
+ if (!strncmp(line, "DOMAIN_", 7)) {
+ float *vals = NULL;
+ if (!strncmp(line + 7, "MIN ", 4)) vals = min;
+ else if (!strncmp(line + 7, "MAX ", 4)) vals = max;
+ if (!vals)
+ return AVERROR_INVALIDDATA;
+ sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2);
+ av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n",
+ min[0], min[1], min[2], max[0], max[1], max[2]);
+ continue;
+ }
+ } while (skip_line(line));
+ if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3)
+ return AVERROR_INVALIDDATA;
+ vec->r *= max[0] - min[0];
+ vec->g *= max[1] - min[1];
+ vec->b *= max[2] - min[2];
+ }
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Assume 17x17x17 LUT with a 16-bit depth
+ * FIXME: it seems there are various 3dl formats */
+static int parse_3dl(AVFilterContext *ctx, FILE *f)
+{
+ char line[MAX_LINE_SIZE];
+ LUT3DContext *lut3d = ctx->priv;
+ int i, j, k;
+ const int size = 17;
+ const float scale = 16*16*16;
+
+ lut3d->lutsize = size;
+ NEXT_LINE(skip_line(line));
+ for (k = 0; k < size; k++) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
+ int r, g, b;
+ struct rgbvec *vec = &lut3d->lut[k][j][i];
+
+ NEXT_LINE(skip_line(line));
+ if (sscanf(line, "%d %d %d", &r, &g, &b) != 3)
+ return AVERROR_INVALIDDATA;
+ vec->r = r / scale;
+ vec->g = g / scale;
+ vec->b = b / scale;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Pandora format */
+static int parse_m3d(AVFilterContext *ctx, FILE *f)
+{
+ LUT3DContext *lut3d = ctx->priv;
+ float scale;
+ int i, j, k, size, in = -1, out = -1;
+ char line[MAX_LINE_SIZE];
+ uint8_t rgb_map[3] = {0, 1, 2};
+
+ while (fgets(line, sizeof(line), f)) {
+ if (!strncmp(line, "in", 2)) in = strtol(line + 2, NULL, 0);
+ else if (!strncmp(line, "out", 3)) out = strtol(line + 3, NULL, 0);
+ else if (!strncmp(line, "values", 6)) {
+ const char *p = line + 6;
+#define SET_COLOR(id) do { \
+ while (av_isspace(*p)) \
+ p++; \
+ switch (*p) { \
+ case 'r': rgb_map[id] = 0; break; \
+ case 'g': rgb_map[id] = 1; break; \
+ case 'b': rgb_map[id] = 2; break; \
+ } \
+ while (*p && !av_isspace(*p)) \
+ p++; \
+} while (0)
+ SET_COLOR(0);
+ SET_COLOR(1);
+ SET_COLOR(2);
+ break;
+ }
+ }
+
+ if (in == -1 || out == -1) {
+ av_log(ctx, AV_LOG_ERROR, "in and out must be defined\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (in < 2 || out < 2 ||
+ in > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL ||
+ out > MAX_LEVEL*MAX_LEVEL*MAX_LEVEL) {
+ av_log(ctx, AV_LOG_ERROR, "invalid in (%d) or out (%d)\n", in, out);
+ return AVERROR_INVALIDDATA;
+ }
+ for (size = 1; size*size*size < in; size++);
+ lut3d->lutsize = size;
+ scale = 1. / (out - 1);
+
+ for (k = 0; k < size; k++) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
+ struct rgbvec *vec = &lut3d->lut[k][j][i];
+ float val[3];
+
+ NEXT_LINE(0);
+ if (sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3)
+ return AVERROR_INVALIDDATA;
+ vec->r = val[rgb_map[0]] * scale;
+ vec->g = val[rgb_map[1]] * scale;
+ vec->b = val[rgb_map[2]] * scale;
+ }
+ }
+ }
+ return 0;
+}
+
+static void set_identity_matrix(LUT3DContext *lut3d, int size)
+{
+ int i, j, k;
+ const float c = 1. / (size - 1);
+
+ lut3d->lutsize = size;
+ for (k = 0; k < size; k++) {
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < size; i++) {
+ struct rgbvec *vec = &lut3d->lut[k][j][i];
+ vec->r = k * c;
+ vec->g = j * c;
+ vec->b = i * c;
+ }
+ }
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48,
+ AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ int is16bit = 0;
+ LUT3DContext *lut3d = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ switch (inlink->format) {
+ case AV_PIX_FMT_RGB48:
+ case AV_PIX_FMT_BGR48:
+ case AV_PIX_FMT_RGBA64:
+ case AV_PIX_FMT_BGRA64:
+ is16bit = 1;
+ }
+
+ ff_fill_rgba_map(lut3d->rgba_map, inlink->format);
+ lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
+
+#define SET_FUNC(name) do { \
+ if (is16bit) lut3d->interp = interp_16_##name; \
+ else lut3d->interp = interp_8_##name; \
+} while (0)
+
+ switch (lut3d->interpolation) {
+ case INTERPOLATE_NEAREST: SET_FUNC(nearest); break;
+ case INTERPOLATE_TRILINEAR: SET_FUNC(trilinear); break;
+ case INTERPOLATE_TETRAHEDRAL: SET_FUNC(tetrahedral); break;
+ default:
+ av_assert0(0);
+ }
+
+ return 0;
+}
+
+static AVFrame *apply_lut(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ LUT3DContext *lut3d = ctx->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out;
+ ThreadData td;
+
+ if (av_frame_is_writable(in)) {
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return NULL;
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ td.in = in;
+ td.out = out;
+ ctx->internal->execute(ctx, lut3d->interp, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
+
+ if (out != in)
+ av_frame_free(&in);
+
+ return out;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *out = apply_lut(inlink, in);
+ if (!out)
+ return AVERROR(ENOMEM);
+ return ff_filter_frame(outlink, out);
+}
+
+#if CONFIG_LUT3D_FILTER
+static const AVOption lut3d_options[] = {
+ { "file", "set 3D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ COMMON_OPTIONS
+};
+
+AVFILTER_DEFINE_CLASS(lut3d);
+
+static av_cold int lut3d_init(AVFilterContext *ctx)
+{
+ int ret;
+ FILE *f;
+ const char *ext;
+ LUT3DContext *lut3d = ctx->priv;
+
+ if (!lut3d->file) {
+ set_identity_matrix(lut3d, 32);
+ return 0;
+ }
+
+ f = fopen(lut3d->file, "r");
+ if (!f) {
+ ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut3d->file, av_err2str(ret));
+ return ret;
+ }
+
+ ext = strrchr(lut3d->file, '.');
+ if (!ext) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+ ext++;
+
+ if (!av_strcasecmp(ext, "dat")) {
+ ret = parse_dat(ctx, f);
+ } else if (!av_strcasecmp(ext, "3dl")) {
+ ret = parse_3dl(ctx, f);
+ } else if (!av_strcasecmp(ext, "cube")) {
+ ret = parse_cube(ctx, f);
+ } else if (!av_strcasecmp(ext, "m3d")) {
+ ret = parse_m3d(ctx, f);
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext);
+ ret = AVERROR(EINVAL);
+ }
+
+ if (!ret && !lut3d->lutsize) {
+ av_log(ctx, AV_LOG_ERROR, "3D LUT is empty\n");
+ ret = AVERROR_INVALIDDATA;
+ }
+
+end:
+ fclose(f);
+ return ret;
+}
+
+static const AVFilterPad lut3d_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad lut3d_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_lut3d = {
+ .name = "lut3d",
+ .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 3D LUT."),
+ .priv_size = sizeof(LUT3DContext),
+ .init = lut3d_init,
+ .query_formats = query_formats,
+ .inputs = lut3d_inputs,
+ .outputs = lut3d_outputs,
+ .priv_class = &lut3d_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
+#endif
+
+#if CONFIG_HALDCLUT_FILTER
+
+static void update_clut(LUT3DContext *lut3d, const AVFrame *frame)
+{
+ const uint8_t *data = frame->data[0];
+ const int linesize = frame->linesize[0];
+ const int w = lut3d->clut_width;
+ const int step = lut3d->clut_step;
+ const uint8_t *rgba_map = lut3d->clut_rgba_map;
+ const int level = lut3d->lutsize;
+
+#define LOAD_CLUT(nbits) do { \
+ int i, j, k, x = 0, y = 0; \
+ \
+ for (k = 0; k < level; k++) { \
+ for (j = 0; j < level; j++) { \
+ for (i = 0; i < level; i++) { \
+ const uint##nbits##_t *src = (const uint##nbits##_t *) \
+ (data + y*linesize + x*step); \
+ struct rgbvec *vec = &lut3d->lut[i][j][k]; \
+ vec->r = src[rgba_map[0]] / (float)((1<<(nbits)) - 1); \
+ vec->g = src[rgba_map[1]] / (float)((1<<(nbits)) - 1); \
+ vec->b = src[rgba_map[2]] / (float)((1<<(nbits)) - 1); \
+ if (++x == w) { \
+ x = 0; \
+ y++; \
+ } \
+ } \
+ } \
+ } \
+} while (0)
+
+ if (!lut3d->clut_is16bit) LOAD_CLUT(8);
+ else LOAD_CLUT(16);
+}
+
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ LUT3DContext *lut3d = ctx->priv;
+ int ret;
+
+ outlink->w = ctx->inputs[0]->w;
+ outlink->h = ctx->inputs[0]->h;
+ outlink->time_base = ctx->inputs[0]->time_base;
+ if ((ret = ff_dualinput_init(ctx, &lut3d->dinput)) < 0)
+ return ret;
+ return 0;
+}
+
+static int filter_frame_hald(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ LUT3DContext *s = inlink->dst->priv;
+ return ff_dualinput_filter_frame(&s->dinput, inlink, inpicref);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ LUT3DContext *s = outlink->src->priv;
+ return ff_dualinput_request_frame(&s->dinput, outlink);
+}
+
+static int config_clut(AVFilterLink *inlink)
+{
+ int size, level, w, h;
+ AVFilterContext *ctx = inlink->dst;
+ LUT3DContext *lut3d = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ lut3d->clut_is16bit = 0;
+ switch (inlink->format) {
+ case AV_PIX_FMT_RGB48:
+ case AV_PIX_FMT_BGR48:
+ case AV_PIX_FMT_RGBA64:
+ case AV_PIX_FMT_BGRA64:
+ lut3d->clut_is16bit = 1;
+ }
+
+ lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3;
+ ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format);
+
+ if (inlink->w > inlink->h)
+ av_log(ctx, AV_LOG_INFO, "Padding on the right (%dpx) of the "
+ "Hald CLUT will be ignored\n", inlink->w - inlink->h);
+ else if (inlink->w < inlink->h)
+ av_log(ctx, AV_LOG_INFO, "Padding at the bottom (%dpx) of the "
+ "Hald CLUT will be ignored\n", inlink->h - inlink->w);
+ lut3d->clut_width = w = h = FFMIN(inlink->w, inlink->h);
+
+ for (level = 1; level*level*level < w; level++);
+ size = level*level*level;
+ if (size != w) {
+ av_log(ctx, AV_LOG_WARNING, "The Hald CLUT width does not match the level\n");
+ return AVERROR_INVALIDDATA;
+ }
+ av_assert0(w == h && w == size);
+ level *= level;
+ if (level > MAX_LEVEL) {
+ const int max_clut_level = sqrt(MAX_LEVEL);
+ const int max_clut_size = max_clut_level*max_clut_level*max_clut_level;
+ av_log(ctx, AV_LOG_ERROR, "Too large Hald CLUT "
+ "(maximum level is %d, or %dx%d CLUT)\n",
+ max_clut_level, max_clut_size, max_clut_size);
+ return AVERROR(EINVAL);
+ }
+ lut3d->lutsize = level;
+
+ return 0;
+}
+
+static AVFrame *update_apply_clut(AVFilterContext *ctx, AVFrame *main,
+ const AVFrame *second)
+{
+ AVFilterLink *inlink = ctx->inputs[0];
+ update_clut(ctx->priv, second);
+ return apply_lut(inlink, main);
+}
+
+static av_cold int haldclut_init(AVFilterContext *ctx)
+{
+ LUT3DContext *lut3d = ctx->priv;
+ lut3d->dinput.process = update_apply_clut;
+ return 0;
+}
+
+static av_cold void haldclut_uninit(AVFilterContext *ctx)
+{
+ LUT3DContext *lut3d = ctx->priv;
+ ff_dualinput_uninit(&lut3d->dinput);
+}
+
+static const AVOption haldclut_options[] = {
+ { "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+ { "repeatlast", "continue applying the last clut after eos", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS },
+ COMMON_OPTIONS
+};
+
+AVFILTER_DEFINE_CLASS(haldclut);
+
+static const AVFilterPad haldclut_inputs[] = {
+ {
+ .name = "main",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame_hald,
+ .config_props = config_input,
+ },{
+ .name = "clut",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame_hald,
+ .config_props = config_clut,
+ },
+ { NULL }
+};
+
+static const AVFilterPad haldclut_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_haldclut = {
+ .name = "haldclut",
+ .description = NULL_IF_CONFIG_SMALL("Adjust colors using a Hald CLUT."),
+ .priv_size = sizeof(LUT3DContext),
+ .init = haldclut_init,
+ .uninit = haldclut_uninit,
+ .query_formats = query_formats,
+ .inputs = haldclut_inputs,
+ .outputs = haldclut_outputs,
+ .priv_class = &haldclut_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
+};
+#endif
diff --git a/libavfilter/vf_mcdeint.c b/libavfilter/vf_mcdeint.c
new file mode 100644
index 0000000000..b0070d8253
--- /dev/null
+++ b/libavfilter/vf_mcdeint.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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
+ * Motion Compensation Deinterlacer
+ * Ported from MPlayer libmpcodecs/vf_mcdeint.c.
+ *
+ * Known Issues:
+ *
+ * The motion estimation is somewhat at the mercy of the input, if the
+ * input frames are created purely based on spatial interpolation then
+ * for example a thin black line or another random and not
+ * interpolateable pattern will cause problems.
+ * Note: completely ignoring the "unavailable" lines during motion
+ * estimation did not look any better, so the most obvious solution
+ * would be to improve tfields or penalize problematic motion vectors.
+ *
+ * If non iterative ME is used then snow currently ignores the OBMC
+ * window and as a result sometimes creates artifacts.
+ *
+ * Only past frames are used, we should ideally use future frames too,
+ * something like filtering the whole movie in forward and then
+ * backward direction seems like a interesting idea but the current
+ * filter framework is FAR from supporting such things.
+ *
+ * Combining the motion compensated image with the input image also is
+ * not as trivial as it seems, simple blindly taking even lines from
+ * one and odd ones from the other does not work at all as ME/MC
+ * sometimes has nothing in the previous frames which matches the
+ * current. The current algorithm has been found by trial and error
+ * and almost certainly can be improved...
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavcodec/avcodec.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+enum MCDeintMode {
+ MODE_FAST = 0,
+ MODE_MEDIUM,
+ MODE_SLOW,
+ MODE_EXTRA_SLOW,
+ MODE_NB,
+};
+
+enum MCDeintParity {
+ PARITY_TFF = 0, ///< top field first
+ PARITY_BFF = 1, ///< bottom field first
+};
+
+typedef struct {
+ const AVClass *class;
+ int mode; ///< MCDeintMode
+ int parity; ///< MCDeintParity
+ int qp;
+ AVCodecContext *enc_ctx;
+} MCDeintContext;
+
+#define OFFSET(x) offsetof(MCDeintContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
+
+static const AVOption mcdeint_options[] = {
+ { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_FAST}, 0, MODE_NB-1, FLAGS, .unit="mode" },
+ CONST("fast", NULL, MODE_FAST, "mode"),
+ CONST("medium", NULL, MODE_MEDIUM, "mode"),
+ CONST("slow", NULL, MODE_SLOW, "mode"),
+ CONST("extra_slow", NULL, MODE_EXTRA_SLOW, "mode"),
+
+ { "parity", "set the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=PARITY_BFF}, -1, 1, FLAGS, "parity" },
+ CONST("tff", "assume top field first", PARITY_TFF, "parity"),
+ CONST("bff", "assume bottom field first", PARITY_BFF, "parity"),
+
+ { "qp", "set qp", OFFSET(qp), AV_OPT_TYPE_INT, {.i64=1}, INT_MIN, INT_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(mcdeint);
+
+static int config_props(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ MCDeintContext *mcdeint = ctx->priv;
+ AVCodec *enc;
+ AVCodecContext *enc_ctx;
+ AVDictionary *opts = NULL;
+ int ret;
+
+ if (!(enc = avcodec_find_encoder(AV_CODEC_ID_SNOW))) {
+ av_log(ctx, AV_LOG_ERROR, "Snow encoder is not enabled in libavcodec\n");
+ return AVERROR(EINVAL);
+ }
+
+ mcdeint->enc_ctx = avcodec_alloc_context3(enc);
+ if (!mcdeint->enc_ctx)
+ return AVERROR(ENOMEM);
+ enc_ctx = mcdeint->enc_ctx;
+ enc_ctx->width = inlink->w;
+ enc_ctx->height = inlink->h;
+ enc_ctx->time_base = (AVRational){1,25}; // meaningless
+ enc_ctx->gop_size = INT_MAX;
+ enc_ctx->max_b_frames = 0;
+ enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
+ enc_ctx->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
+ enc_ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+ enc_ctx->global_quality = 1;
+ enc_ctx->me_cmp = enc_ctx->me_sub_cmp = FF_CMP_SAD;
+ enc_ctx->mb_cmp = FF_CMP_SSE;
+ av_dict_set(&opts, "memc_only", "1", 0);
+ av_dict_set(&opts, "no_bitstream", "1", 0);
+
+ switch (mcdeint->mode) {
+ case MODE_EXTRA_SLOW:
+ enc_ctx->refs = 3;
+ case MODE_SLOW:
+ enc_ctx->me_method = ME_ITER;
+ case MODE_MEDIUM:
+ enc_ctx->flags |= CODEC_FLAG_4MV;
+ enc_ctx->dia_size = 2;
+ case MODE_FAST:
+ enc_ctx->flags |= CODEC_FLAG_QPEL;
+ }
+
+ ret = avcodec_open2(enc_ctx, enc, &opts);
+ av_dict_free(&opts);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ MCDeintContext *mcdeint = ctx->priv;
+
+ if (mcdeint->enc_ctx) {
+ avcodec_close(mcdeint->enc_ctx);
+ av_freep(&mcdeint->enc_ctx);
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ MCDeintContext *mcdeint = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpic, *frame_dec;
+ AVPacket pkt = {0};
+ int x, y, i, ret, got_frame = 0;
+
+ outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpic) {
+ av_frame_free(&inpic);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpic, inpic);
+ inpic->quality = mcdeint->qp * FF_QP2LAMBDA;
+
+ av_init_packet(&pkt);
+
+ ret = avcodec_encode_video2(mcdeint->enc_ctx, &pkt, inpic, &got_frame);
+ if (ret < 0)
+ goto end;
+
+ frame_dec = mcdeint->enc_ctx->coded_frame;
+
+ for (i = 0; i < 3; i++) {
+ int is_chroma = !!i;
+ int w = FF_CEIL_RSHIFT(inlink->w, is_chroma);
+ int h = FF_CEIL_RSHIFT(inlink->h, is_chroma);
+ int fils = frame_dec->linesize[i];
+ int srcs = inpic ->linesize[i];
+ int dsts = outpic ->linesize[i];
+
+ for (y = 0; y < h; y++) {
+ if ((y ^ mcdeint->parity) & 1) {
+ for (x = 0; x < w; x++) {
+ uint8_t *filp = &frame_dec->data[i][x + y*fils];
+ uint8_t *srcp = &inpic ->data[i][x + y*srcs];
+ uint8_t *dstp = &outpic ->data[i][x + y*dsts];
+
+ if (y > 0 && y < h-1){
+ int is_edge = x < 3 || x > w-4;
+ int diff0 = filp[-fils] - srcp[-srcs];
+ int diff1 = filp[+fils] - srcp[+srcs];
+ int temp = filp[0];
+
+#define DELTA(j) av_clip(j, -x, w-1-x)
+
+#define GET_SCORE_EDGE(j)\
+ FFABS(srcp[-srcs+DELTA(-1+(j))] - srcp[+srcs+DELTA(-1-(j))])+\
+ FFABS(srcp[-srcs+DELTA(j) ] - srcp[+srcs+DELTA( -(j))])+\
+ FFABS(srcp[-srcs+DELTA(1+(j)) ] - srcp[+srcs+DELTA( 1-(j))])
+
+#define GET_SCORE(j)\
+ FFABS(srcp[-srcs-1+(j)] - srcp[+srcs-1-(j)])+\
+ FFABS(srcp[-srcs +(j)] - srcp[+srcs -(j)])+\
+ FFABS(srcp[-srcs+1+(j)] - srcp[+srcs+1-(j)])
+
+#define CHECK_EDGE(j)\
+ { int score = GET_SCORE_EDGE(j);\
+ if (score < spatial_score){\
+ spatial_score = score;\
+ diff0 = filp[-fils+DELTA(j)] - srcp[-srcs+DELTA(j)];\
+ diff1 = filp[+fils+DELTA(-(j))] - srcp[+srcs+DELTA(-(j))];\
+
+#define CHECK(j)\
+ { int score = GET_SCORE(j);\
+ if (score < spatial_score){\
+ spatial_score= score;\
+ diff0 = filp[-fils+(j)] - srcp[-srcs+(j)];\
+ diff1 = filp[+fils-(j)] - srcp[+srcs-(j)];\
+
+ if (is_edge) {
+ int spatial_score = GET_SCORE_EDGE(0) - 1;
+ CHECK_EDGE(-1) CHECK_EDGE(-2) }} }}
+ CHECK_EDGE( 1) CHECK_EDGE( 2) }} }}
+ } else {
+ int spatial_score = GET_SCORE(0) - 1;
+ CHECK(-1) CHECK(-2) }} }}
+ CHECK( 1) CHECK( 2) }} }}
+ }
+
+
+ if (diff0 + diff1 > 0)
+ temp -= (diff0 + diff1 - FFABS(FFABS(diff0) - FFABS(diff1)) / 2) / 2;
+ else
+ temp -= (diff0 + diff1 + FFABS(FFABS(diff0) - FFABS(diff1)) / 2) / 2;
+ *filp = *dstp = temp > 255U ? ~(temp>>31) : temp;
+ } else {
+ *dstp = *filp;
+ }
+ }
+ }
+ }
+
+ for (y = 0; y < h; y++) {
+ if (!((y ^ mcdeint->parity) & 1)) {
+ for (x = 0; x < w; x++) {
+ frame_dec->data[i][x + y*fils] =
+ outpic ->data[i][x + y*dsts] = inpic->data[i][x + y*srcs];
+ }
+ }
+ }
+ }
+ mcdeint->parity ^= 1;
+
+end:
+ av_free_packet(&pkt);
+ av_frame_free(&inpic);
+ if (ret < 0) {
+ av_frame_free(&outpic);
+ return ret;
+ }
+ return ff_filter_frame(outlink, outpic);
+}
+
+static const AVFilterPad mcdeint_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad mcdeint_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_mcdeint = {
+ .name = "mcdeint",
+ .description = NULL_IF_CONFIG_SMALL("Apply motion compensating deinterlacing."),
+ .priv_size = sizeof(MCDeintContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = mcdeint_inputs,
+ .outputs = mcdeint_outputs,
+ .priv_class = &mcdeint_class,
+};
diff --git a/libavfilter/vf_mergeplanes.c b/libavfilter/vf_mergeplanes.c
new file mode 100644
index 0000000000..c76e82a419
--- /dev/null
+++ b/libavfilter/vf_mergeplanes.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "framesync.h"
+
+typedef struct InputParam {
+ int depth[4];
+ int nb_planes;
+ int planewidth[4];
+ int planeheight[4];
+} InputParam;
+
+typedef struct MergePlanesContext {
+ const AVClass *class;
+ int64_t mapping;
+ const enum AVPixelFormat out_fmt;
+ int nb_inputs;
+ int nb_planes;
+ int planewidth[4];
+ int planeheight[4];
+ int map[4][2];
+ const AVPixFmtDescriptor *outdesc;
+
+ FFFrameSync fs;
+ FFFrameSyncIn fsin[3]; /* must be immediately after fs */
+} MergePlanesContext;
+
+#define OFFSET(x) offsetof(MergePlanesContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption mergeplanes_options[] = {
+ { "mapping", "set input to output plane mapping", OFFSET(mapping), AV_OPT_TYPE_INT, {.i64=0}, 0, 0x33333333, FLAGS },
+ { "format", "set output pixel format", OFFSET(out_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64=AV_PIX_FMT_YUVA444P}, 0, INT_MAX, .flags=FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(mergeplanes);
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ MergePlanesContext *s = inlink->dst->priv;
+ return ff_framesync_filter_frame(&s->fs, inlink, in);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ MergePlanesContext *s = ctx->priv;
+ int64_t m = s->mapping;
+ int i, ret;
+
+ s->outdesc = av_pix_fmt_desc_get(s->out_fmt);
+ if (!(s->outdesc->flags & AV_PIX_FMT_FLAG_PLANAR) ||
+ s->outdesc->nb_components < 2) {
+ av_log(ctx, AV_LOG_ERROR, "Only planar formats with more than one component are supported.\n");
+ return AVERROR(EINVAL);
+ }
+ s->nb_planes = av_pix_fmt_count_planes(s->out_fmt);
+
+ for (i = s->nb_planes - 1; i >= 0; i--) {
+ s->map[i][0] = m & 0xf;
+ m >>= 4;
+ s->map[i][1] = m & 0xf;
+ m >>= 4;
+
+ if (s->map[i][0] > 3 || s->map[i][1] > 3) {
+ av_log(ctx, AV_LOG_ERROR, "Mapping with out of range input and/or plane number.\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->nb_inputs = FFMAX(s->nb_inputs, s->map[i][1] + 1);
+ }
+
+ av_assert0(s->nb_inputs && s->nb_inputs <= 4);
+
+ for (i = 0; i < s->nb_inputs; i++) {
+ AVFilterPad pad = { 0 };
+
+ pad.type = AVMEDIA_TYPE_VIDEO;
+ pad.name = av_asprintf("in%d", i);
+ if (!pad.name)
+ return AVERROR(ENOMEM);
+ pad.filter_frame = filter_frame;
+
+ if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0){
+ av_freep(&pad.name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ MergePlanesContext *s = ctx->priv;
+ AVFilterFormats *formats = NULL;
+ int i;
+
+ s->outdesc = av_pix_fmt_desc_get(s->out_fmt);
+ for (i = 0; av_pix_fmt_desc_get(i); i++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
+ if (desc->comp[0].depth_minus1 == s->outdesc->comp[0].depth_minus1 &&
+ av_pix_fmt_count_planes(i) == desc->nb_components)
+ ff_add_format(&formats, i);
+ }
+
+ for (i = 0; i < s->nb_inputs; i++)
+ ff_formats_ref(formats, &ctx->inputs[i]->out_formats);
+
+ formats = NULL;
+ ff_add_format(&formats, s->out_fmt);
+ ff_formats_ref(formats, &ctx->outputs[0]->in_formats);
+
+ return 0;
+}
+
+static int process_frame(FFFrameSync *fs)
+{
+ AVFilterContext *ctx = fs->parent;
+ AVFilterLink *outlink = ctx->outputs[0];
+ MergePlanesContext *s = fs->opaque;
+ AVFrame *in[4] = { NULL };
+ AVFrame *out;
+ int i, ret;
+
+ for (i = 0; i < s->nb_inputs; i++) {
+ if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], 0)) < 0)
+ return ret;
+ }
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base);
+
+ for (i = 0; i < s->nb_planes; i++) {
+ const int input = s->map[i][1];
+ const int plane = s->map[i][0];
+
+ av_image_copy_plane(out->data[i], out->linesize[i],
+ in[input]->data[plane], in[input]->linesize[plane],
+ s->planewidth[i], s->planeheight[i]);
+ }
+
+ return ff_filter_frame(outlink, out);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ MergePlanesContext *s = ctx->priv;
+ InputParam inputsp[4];
+ FFFrameSyncIn *in;
+ int i;
+
+ ff_framesync_init(&s->fs, ctx, s->nb_inputs);
+ in = s->fs.in;
+ s->fs.opaque = s;
+ s->fs.on_event = process_frame;
+
+ 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;
+ outlink->sample_aspect_ratio = ctx->inputs[0]->sample_aspect_ratio;
+
+ s->planewidth[1] =
+ s->planewidth[2] = FF_CEIL_RSHIFT(outlink->w, s->outdesc->log2_chroma_w);
+ s->planewidth[0] =
+ s->planewidth[3] = outlink->w;
+ s->planeheight[1] =
+ s->planeheight[2] = FF_CEIL_RSHIFT(outlink->h, s->outdesc->log2_chroma_h);
+ s->planeheight[0] =
+ s->planeheight[3] = outlink->h;
+
+ for (i = 0; i < s->nb_inputs; i++) {
+ InputParam *inputp = &inputsp[i];
+ AVFilterLink *inlink = ctx->inputs[i];
+ const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(inlink->format);
+ int j;
+
+ if (outlink->sample_aspect_ratio.num != inlink->sample_aspect_ratio.num ||
+ outlink->sample_aspect_ratio.den != inlink->sample_aspect_ratio.den) {
+ av_log(ctx, AV_LOG_ERROR, "input #%d link %s SAR %d:%d "
+ "does not match output link %s SAR %d:%d\n",
+ i, ctx->input_pads[i].name,
+ inlink->sample_aspect_ratio.num,
+ inlink->sample_aspect_ratio.den,
+ ctx->output_pads[0].name,
+ outlink->sample_aspect_ratio.num,
+ outlink->sample_aspect_ratio.den);
+ return AVERROR(EINVAL);
+ }
+
+ inputp->planewidth[1] =
+ inputp->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, indesc->log2_chroma_w);
+ inputp->planewidth[0] =
+ inputp->planewidth[3] = inlink->w;
+ inputp->planeheight[1] =
+ inputp->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, indesc->log2_chroma_h);
+ inputp->planeheight[0] =
+ inputp->planeheight[3] = inlink->h;
+ inputp->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ for (j = 0; j < inputp->nb_planes; j++)
+ inputp->depth[j] = indesc->comp[j].depth_minus1 + 1;
+
+ in[i].time_base = inlink->time_base;
+ in[i].sync = 1;
+ in[i].before = EXT_STOP;
+ in[i].after = EXT_STOP;
+ }
+
+ for (i = 0; i < s->nb_planes; i++) {
+ const int input = s->map[i][1];
+ const int plane = s->map[i][0];
+ InputParam *inputp = &inputsp[input];
+
+ if (plane + 1 > inputp->nb_planes) {
+ av_log(ctx, AV_LOG_ERROR, "input %d does not have %d plane\n",
+ input, plane);
+ goto fail;
+ }
+ if (s->outdesc->comp[i].depth_minus1 + 1 != inputp->depth[plane]) {
+ av_log(ctx, AV_LOG_ERROR, "output plane %d depth %d does not "
+ "match input %d plane %d depth %d\n",
+ i, s->outdesc->comp[i].depth_minus1 + 1,
+ input, plane, inputp->depth[plane]);
+ goto fail;
+ }
+ if (s->planewidth[i] != inputp->planewidth[plane]) {
+ av_log(ctx, AV_LOG_ERROR, "output plane %d width %d does not "
+ "match input %d plane %d width %d\n",
+ i, s->planewidth[i],
+ input, plane, inputp->planewidth[plane]);
+ goto fail;
+ }
+ if (s->planeheight[i] != inputp->planeheight[plane]) {
+ av_log(ctx, AV_LOG_ERROR, "output plane %d height %d does not "
+ "match input %d plane %d height %d\n",
+ i, s->planeheight[i],
+ input, plane, inputp->planeheight[plane]);
+ goto fail;
+ }
+ }
+
+ return ff_framesync_configure(&s->fs);
+fail:
+ return AVERROR(EINVAL);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ MergePlanesContext *s = outlink->src->priv;
+ return ff_framesync_request_frame(&s->fs, outlink);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ MergePlanesContext *s = ctx->priv;
+ int i;
+
+ ff_framesync_uninit(&s->fs);
+
+ for (i = 0; i < ctx->nb_inputs; i++)
+ av_freep(&ctx->input_pads[i].name);
+}
+
+static const AVFilterPad mergeplanes_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_mergeplanes = {
+ .name = "mergeplanes",
+ .description = NULL_IF_CONFIG_SMALL("Merge planes."),
+ .priv_size = sizeof(MergePlanesContext),
+ .priv_class = &mergeplanes_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = mergeplanes_outputs,
+ .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
+};
diff --git a/libavfilter/vf_mpdecimate.c b/libavfilter/vf_mpdecimate.c
new file mode 100644
index 0000000000..5504ffebd6
--- /dev/null
+++ b/libavfilter/vf_mpdecimate.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2003 Rich Felker
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * 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 mpdecimate filter, ported from libmpcodecs/vf_decimate.c by
+ * Rich Felker.
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/pixelutils.h"
+#include "libavutil/timestamp.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "formats.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int lo, hi; ///< lower and higher threshold number of differences
+ ///< values for 8x8 blocks
+
+ float frac; ///< threshold of changed pixels over the total fraction
+
+ int max_drop_count; ///< if positive: maximum number of sequential frames to drop
+ ///< if negative: minimum number of frames between two drops
+
+ int drop_count; ///< if positive: number of frames sequentially dropped
+ ///< if negative: number of sequential frames which were not dropped
+
+ int hsub, vsub; ///< chroma subsampling values
+ AVFrame *ref; ///< reference picture
+ av_pixelutils_sad_fn sad; ///< sum of absolute difference function
+} DecimateContext;
+
+#define OFFSET(x) offsetof(DecimateContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption mpdecimate_options[] = {
+ { "max", "set the maximum number of consecutive dropped frames (positive), or the minimum interval between dropped frames (negative)",
+ OFFSET(max_drop_count), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS },
+ { "hi", "set high dropping threshold", OFFSET(hi), AV_OPT_TYPE_INT, {.i64=64*12}, INT_MIN, INT_MAX, FLAGS },
+ { "lo", "set low dropping threshold", OFFSET(lo), AV_OPT_TYPE_INT, {.i64=64*5}, INT_MIN, INT_MAX, FLAGS },
+ { "frac", "set fraction dropping threshold", OFFSET(frac), AV_OPT_TYPE_FLOAT, {.dbl=0.33}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(mpdecimate);
+
+/**
+ * Return 1 if the two planes are different, 0 otherwise.
+ */
+static int diff_planes(AVFilterContext *ctx,
+ uint8_t *cur, int cur_linesize,
+ uint8_t *ref, int ref_linesize,
+ int w, int h)
+{
+ DecimateContext *decimate = ctx->priv;
+
+ int x, y;
+ int d, c = 0;
+ int t = (w/16)*(h/16)*decimate->frac;
+
+ /* compute difference for blocks of 8x8 bytes */
+ for (y = 0; y < h-7; y += 4) {
+ for (x = 8; x < w-7; x += 4) {
+ d = decimate->sad(cur + y*cur_linesize + x, cur_linesize,
+ ref + y*ref_linesize + x, ref_linesize);
+ if (d > decimate->hi)
+ return 1;
+ if (d > decimate->lo) {
+ c++;
+ if (c > t)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Tell if the frame should be decimated, for example if it is no much
+ * different with respect to the reference frame ref.
+ */
+static int decimate_frame(AVFilterContext *ctx,
+ AVFrame *cur, AVFrame *ref)
+{
+ DecimateContext *decimate = ctx->priv;
+ int plane;
+
+ if (decimate->max_drop_count > 0 &&
+ decimate->drop_count >= decimate->max_drop_count)
+ return 0;
+ if (decimate->max_drop_count < 0 &&
+ (decimate->drop_count-1) > decimate->max_drop_count)
+ return 0;
+
+ for (plane = 0; ref->data[plane] && ref->linesize[plane]; plane++) {
+ int vsub = plane == 1 || plane == 2 ? decimate->vsub : 0;
+ int hsub = plane == 1 || plane == 2 ? decimate->hsub : 0;
+ if (diff_planes(ctx,
+ cur->data[plane], cur->linesize[plane],
+ ref->data[plane], ref->linesize[plane],
+ FF_CEIL_RSHIFT(ref->width, hsub),
+ FF_CEIL_RSHIFT(ref->height, vsub)))
+ return 0;
+ }
+
+ return 1;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ DecimateContext *decimate = ctx->priv;
+
+ decimate->sad = av_pixelutils_get_sad_fn(3, 3, 0, decimate); // 8x8, not aligned on blocksize
+ if (!decimate->sad)
+ return AVERROR(EINVAL);
+
+ av_log(ctx, AV_LOG_VERBOSE, "max_drop_count:%d hi:%d lo:%d frac:%f\n",
+ decimate->max_drop_count, decimate->hi, decimate->lo, decimate->frac);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ DecimateContext *decimate = ctx->priv;
+ av_frame_free(&decimate->ref);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ DecimateContext *decimate = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+ decimate->hsub = pix_desc->log2_chroma_w;
+ decimate->vsub = pix_desc->log2_chroma_h;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *cur)
+{
+ DecimateContext *decimate = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int ret;
+
+ if (decimate->ref && decimate_frame(inlink->dst, cur, decimate->ref)) {
+ decimate->drop_count = FFMAX(1, decimate->drop_count+1);
+ } else {
+ av_frame_free(&decimate->ref);
+ decimate->ref = cur;
+ decimate->drop_count = FFMIN(-1, decimate->drop_count-1);
+
+ if ((ret = ff_filter_frame(outlink, av_frame_clone(cur))) < 0)
+ return ret;
+ }
+
+ av_log(inlink->dst, AV_LOG_DEBUG,
+ "%s pts:%s pts_time:%s drop_count:%d\n",
+ decimate->drop_count > 0 ? "drop" : "keep",
+ av_ts2str(cur->pts), av_ts2timestr(cur->pts, &inlink->time_base),
+ decimate->drop_count);
+
+ if (decimate->drop_count > 0)
+ av_frame_free(&cur);
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ DecimateContext *decimate = outlink->src->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ int ret;
+
+ do {
+ ret = ff_request_frame(inlink);
+ } while (decimate->drop_count > 0 && ret >= 0);
+
+ return ret;
+}
+
+static const AVFilterPad mpdecimate_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad mpdecimate_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_mpdecimate = {
+ .name = "mpdecimate",
+ .description = NULL_IF_CONFIG_SMALL("Remove near-duplicate frames."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(DecimateContext),
+ .priv_class = &mpdecimate_class,
+ .query_formats = query_formats,
+ .inputs = mpdecimate_inputs,
+ .outputs = mpdecimate_outputs,
+};
diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
new file mode 100644
index 0000000000..861ac09087
--- /dev/null
+++ b/libavfilter/vf_noise.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * noise generator
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/lfg.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "vf_noise.h"
+#include "video.h"
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
+
+#define OFFSET(x) offsetof(NoiseContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+#define NOISE_PARAMS(name, x, param) \
+ {#name"_seed", "set component #"#x" noise seed", OFFSET(param.seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS}, \
+ {#name"_strength", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS}, \
+ {#name"s", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS}, \
+ {#name"_flags", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
+ {#name"f", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
+ {"a", "averaged noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_AVERAGED}, 0, 0, FLAGS, #name"_flags"}, \
+ {"p", "(semi)regular pattern", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_PATTERN}, 0, 0, FLAGS, #name"_flags"}, \
+ {"t", "temporal noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_TEMPORAL}, 0, 0, FLAGS, #name"_flags"}, \
+ {"u", "uniform noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_UNIFORM}, 0, 0, FLAGS, #name"_flags"},
+
+static const AVOption noise_options[] = {
+ NOISE_PARAMS(all, 0, all)
+ NOISE_PARAMS(c0, 0, param[0])
+ NOISE_PARAMS(c1, 1, param[1])
+ NOISE_PARAMS(c2, 2, param[2])
+ NOISE_PARAMS(c3, 3, param[3])
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(noise);
+
+static const int8_t patt[4] = { -1, 0, 1, 0 };
+
+#define RAND_N(range) ((int) ((double) range * av_lfg_get(lfg) / (UINT_MAX + 1.0)))
+static av_cold int init_noise(NoiseContext *n, int comp)
+{
+ int8_t *noise = av_malloc(MAX_NOISE * sizeof(int8_t));
+ FilterParams *fp = &n->param[comp];
+ AVLFG *lfg = &n->param[comp].lfg;
+ int strength = fp->strength;
+ int flags = fp->flags;
+ int i, j;
+
+ if (!noise)
+ return AVERROR(ENOMEM);
+
+ av_lfg_init(&fp->lfg, fp->seed + comp*31415U);
+
+ for (i = 0, j = 0; i < MAX_NOISE; i++, j++) {
+ if (flags & NOISE_UNIFORM) {
+ if (flags & NOISE_AVERAGED) {
+ if (flags & NOISE_PATTERN) {
+ noise[i] = (RAND_N(strength) - strength / 2) / 6
+ + patt[j % 4] * strength * 0.25 / 3;
+ } else {
+ noise[i] = (RAND_N(strength) - strength / 2) / 3;
+ }
+ } else {
+ if (flags & NOISE_PATTERN) {
+ noise[i] = (RAND_N(strength) - strength / 2) / 2
+ + patt[j % 4] * strength * 0.25;
+ } else {
+ noise[i] = RAND_N(strength) - strength / 2;
+ }
+ }
+ } else {
+ double x1, x2, w, y1;
+ do {
+ x1 = 2.0 * av_lfg_get(lfg) / (float)UINT_MAX - 1.0;
+ x2 = 2.0 * av_lfg_get(lfg) / (float)UINT_MAX - 1.0;
+ w = x1 * x1 + x2 * x2;
+ } while (w >= 1.0);
+
+ w = sqrt((-2.0 * log(w)) / w);
+ y1 = x1 * w;
+ y1 *= strength / sqrt(3.0);
+ if (flags & NOISE_PATTERN) {
+ y1 /= 2;
+ y1 += patt[j % 4] * strength * 0.35;
+ }
+ y1 = av_clipf(y1, -128, 127);
+ if (flags & NOISE_AVERAGED)
+ y1 /= 3.0;
+ noise[i] = (int)y1;
+ }
+ if (RAND_N(6) == 0)
+ j--;
+ }
+
+ for (i = 0; i < MAX_RES; i++)
+ for (j = 0; j < 3; j++)
+ fp->prev_shift[i][j] = noise + (av_lfg_get(lfg) & (MAX_SHIFT - 1));
+
+ fp->noise = noise;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (desc->flags & AV_PIX_FMT_FLAG_PLANAR && !((desc->comp[0].depth_minus1 + 1) & 7))
+ ff_add_format(&formats, fmt);
+ }
+
+ return ff_set_common_formats(ctx, formats);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ NoiseContext *n = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ n->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ if ((ret = av_image_fill_linesizes(n->bytewidth, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ n->height[1] = n->height[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ n->height[0] = n->height[3] = inlink->h;
+
+ return 0;
+}
+
+void ff_line_noise_c(uint8_t *dst, const uint8_t *src, const int8_t *noise,
+ int len, int shift)
+{
+ int i;
+
+ noise += shift;
+ for (i = 0; i < len; i++) {
+ int v = src[i] + noise[i];
+
+ dst[i] = av_clip_uint8(v);
+ }
+}
+
+void ff_line_noise_avg_c(uint8_t *dst, const uint8_t *src,
+ int len, const int8_t * const *shift)
+{
+ int i;
+ const int8_t *src2 = (const int8_t*)src;
+
+ for (i = 0; i < len; i++) {
+ const int n = shift[0][i] + shift[1][i] + shift[2][i];
+ dst[i] = src2[i] + ((n * src2[i]) >> 7);
+ }
+}
+
+static void noise(uint8_t *dst, const uint8_t *src,
+ int dst_linesize, int src_linesize,
+ int width, int start, int end, NoiseContext *n, int comp)
+{
+ FilterParams *p = &n->param[comp];
+ int8_t *noise = p->noise;
+ const int flags = p->flags;
+ int y;
+
+ if (!noise) {
+ if (dst != src)
+ av_image_copy_plane(dst, dst_linesize, src, src_linesize, width, end - start);
+ return;
+ }
+
+ for (y = start; y < end; y++) {
+ const int ix = y & (MAX_RES - 1);
+ int x;
+ for (x=0; x < width; x+= MAX_RES) {
+ int w = FFMIN(width - x, MAX_RES);
+ int shift = p->rand_shift[ix];
+
+ if (flags & NOISE_AVERAGED) {
+ n->line_noise_avg(dst + x, src + x, w, (const int8_t**)p->prev_shift[ix]);
+ p->prev_shift[ix][shift & 3] = noise + shift;
+ } else {
+ n->line_noise(dst + x, src + x, noise, w, shift);
+ }
+ }
+ dst += dst_linesize;
+ src += src_linesize;
+ }
+}
+
+static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ NoiseContext *s = ctx->priv;
+ ThreadData *td = arg;
+ int plane;
+
+ for (plane = 0; plane < s->nb_planes; plane++) {
+ const int height = s->height[plane];
+ const int start = (height * jobnr ) / nb_jobs;
+ const int end = (height * (jobnr+1)) / nb_jobs;
+ noise(td->out->data[plane] + start * td->out->linesize[plane],
+ td->in->data[plane] + start * td->in->linesize[plane],
+ td->out->linesize[plane], td->in->linesize[plane],
+ s->bytewidth[plane], start, end, s, plane);
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ NoiseContext *n = ctx->priv;
+ ThreadData td;
+ AVFrame *out;
+ int comp, i;
+
+ if (av_frame_is_writable(inpicref)) {
+ out = inpicref;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, inpicref);
+ }
+
+ for (comp = 0; comp < 4; comp++) {
+ FilterParams *fp = &n->param[comp];
+
+ if ((!fp->rand_shift_init || (fp->flags & NOISE_TEMPORAL)) && fp->strength) {
+
+ for (i = 0; i < MAX_RES; i++) {
+ fp->rand_shift[i] = av_lfg_get(&fp->lfg) & (MAX_SHIFT - 1);
+ }
+ fp->rand_shift_init = 1;
+ }
+ }
+
+ td.in = inpicref; td.out = out;
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(n->height[0], ctx->graph->nb_threads));
+ emms_c();
+
+ if (inpicref != out)
+ av_frame_free(&inpicref);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ NoiseContext *n = ctx->priv;
+ int ret, i;
+
+ for (i = 0; i < 4; i++) {
+ if (n->all.seed >= 0)
+ n->param[i].seed = n->all.seed;
+ else
+ n->param[i].seed = 123457;
+ if (n->all.strength)
+ n->param[i].strength = n->all.strength;
+ if (n->all.flags)
+ n->param[i].flags = n->all.flags;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (n->param[i].strength && ((ret = init_noise(n, i)) < 0))
+ return ret;
+ }
+
+ n->line_noise = ff_line_noise_c;
+ n->line_noise_avg = ff_line_noise_avg_c;
+
+ if (ARCH_X86)
+ ff_noise_init_x86(n);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ NoiseContext *n = ctx->priv;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ av_freep(&n->param[i].noise);
+}
+
+static const AVFilterPad noise_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad noise_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_noise = {
+ .name = "noise",
+ .description = NULL_IF_CONFIG_SMALL("Add noise."),
+ .priv_size = sizeof(NoiseContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = noise_inputs,
+ .outputs = noise_outputs,
+ .priv_class = &noise_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_noise.h b/libavfilter/vf_noise.h
new file mode 100644
index 0000000000..2207ed961f
--- /dev/null
+++ b/libavfilter/vf_noise.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 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_NOISE_H
+#define AVFILTER_NOISE_H
+
+#include "libavutil/lfg.h"
+#include "avfilter.h"
+
+#define MAX_NOISE 5120
+#define MAX_SHIFT 1024
+#define MAX_RES (MAX_NOISE-MAX_SHIFT)
+
+#define NOISE_UNIFORM 1
+#define NOISE_TEMPORAL 2
+#define NOISE_AVERAGED 8
+#define NOISE_PATTERN 16
+
+typedef struct {
+ int strength;
+ unsigned flags;
+ AVLFG lfg;
+ int seed;
+ int8_t *noise;
+ int8_t *prev_shift[MAX_RES][3];
+ int rand_shift[MAX_RES];
+ int rand_shift_init;
+} FilterParams;
+
+typedef struct {
+ const AVClass *class;
+ int nb_planes;
+ int bytewidth[4];
+ int height[4];
+ FilterParams all;
+ FilterParams param[4];
+ void (*line_noise)(uint8_t *dst, const uint8_t *src, const int8_t *noise, int len, int shift);
+ void (*line_noise_avg)(uint8_t *dst, const uint8_t *src, int len, const int8_t * const *shift);
+} NoiseContext;
+
+void ff_line_noise_c(uint8_t *dst, const uint8_t *src, const int8_t *noise, int len, int shift);
+void ff_line_noise_avg_c(uint8_t *dst, const uint8_t *src, int len, const int8_t * const *shift);
+
+void ff_noise_init_x86(NoiseContext *n);
+
+#endif /* AVFILTER_NOISE_H */
diff --git a/libavfilter/vf_null.c b/libavfilter/vf_null.c
index f87258707d..2355615229 100644
--- a/libavfilter/vf_null.c
+++ b/libavfilter/vf_null.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,9 +28,8 @@
static const AVFilterPad avfilter_vf_null_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
},
{ NULL }
};
@@ -44,12 +43,8 @@ static const AVFilterPad avfilter_vf_null_outputs[] = {
};
AVFilter ff_vf_null = {
- .name = "null",
+ .name = "null",
.description = NULL_IF_CONFIG_SMALL("Pass the source unchanged to the output."),
-
- .priv_size = 0,
-
- .inputs = avfilter_vf_null_inputs,
-
- .outputs = avfilter_vf_null_outputs,
+ .inputs = avfilter_vf_null_inputs,
+ .outputs = avfilter_vf_null_outputs,
};
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index 11e0a6fbac..788c1d94a2 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -3,20 +3,20 @@
* Copyright (c) 2010 Baptiste Coudurier
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,33 +30,43 @@
#include "libavutil/common.h"
#include "libavutil/eval.h"
#include "libavutil/avstring.h"
-#include "libavutil/avassert.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
#include "internal.h"
+#include "dualinput.h"
+#include "drawutils.h"
#include "video.h"
static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
"main_w", "W", ///< width of the main video
"main_h", "H", ///< height of the main video
"overlay_w", "w", ///< width of the overlay video
"overlay_h", "h", ///< height of the overlay video
+ "hsub",
+ "vsub",
+ "x",
+ "y",
+ "n", ///< number of frame
+ "pos", ///< position in the file
+ "t", ///< timestamp expressed in seconds
NULL
};
enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
VAR_MAIN_W, VAR_MW,
VAR_MAIN_H, VAR_MH,
VAR_OVERLAY_W, VAR_OW,
VAR_OVERLAY_H, VAR_OH,
+ VAR_HSUB,
+ VAR_VSUB,
+ VAR_X,
+ VAR_Y,
+ VAR_N,
+ VAR_POS,
+ VAR_T,
VAR_VARS_NB
};
@@ -66,60 +76,225 @@ enum EOFAction {
EOF_ACTION_PASS
};
-static const char *eof_action_str[] = {
+static const char * const eof_action_str[] = {
"repeat", "endall", "pass"
};
#define MAIN 0
#define OVERLAY 1
+#define R 0
+#define G 1
+#define B 2
+#define A 3
+
+#define Y 0
+#define U 1
+#define V 2
+
+enum EvalMode {
+ EVAL_MODE_INIT,
+ EVAL_MODE_FRAME,
+ EVAL_MODE_NB
+};
+
+enum OverlayFormat {
+ OVERLAY_FORMAT_YUV420,
+ OVERLAY_FORMAT_YUV422,
+ OVERLAY_FORMAT_YUV444,
+ OVERLAY_FORMAT_RGB,
+ OVERLAY_FORMAT_NB
+};
+
typedef struct OverlayContext {
const AVClass *class;
int x, y; ///< position of overlayed picture
- int max_plane_step[4]; ///< steps per pixel for each plane
+ int allow_packed_rgb;
+ uint8_t main_is_packed_rgb;
+ uint8_t main_rgba_map[4];
+ uint8_t main_has_alpha;
+ uint8_t overlay_is_packed_rgb;
+ uint8_t overlay_rgba_map[4];
+ uint8_t overlay_has_alpha;
+ int format; ///< OverlayFormat
+ int eval_mode; ///< EvalMode
+
+ FFDualInputContext dinput;
+
+ int main_pix_step[4]; ///< steps per pixel for each plane of the main output
+ int overlay_pix_step[4]; ///< steps per pixel for each plane of the overlay
int hsub, vsub; ///< chroma subsampling values
+ double var_values[VAR_VARS_NB];
char *x_expr, *y_expr;
- enum EOFAction eof_action; ///< action to take on EOF from source
+ int eof_action; ///< action to take on EOF from source
- AVFrame *main;
- AVFrame *over_prev, *over_next;
+ AVExpr *x_pexpr, *y_pexpr;
} OverlayContext;
static av_cold void uninit(AVFilterContext *ctx)
{
OverlayContext *s = ctx->priv;
- av_frame_free(&s->main);
- av_frame_free(&s->over_prev);
- av_frame_free(&s->over_next);
+ ff_dualinput_uninit(&s->dinput);
+ av_expr_free(s->x_pexpr); s->x_pexpr = NULL;
+ av_expr_free(s->y_pexpr); s->y_pexpr = NULL;
+}
+
+static inline int normalize_xy(double d, int chroma_sub)
+{
+ if (isnan(d))
+ return INT_MAX;
+ return (int)d & ~((1 << chroma_sub) - 1);
+}
+
+static void eval_expr(AVFilterContext *ctx)
+{
+ OverlayContext *s = ctx->priv;
+
+ s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL);
+ s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, NULL);
+ s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL);
+ s->x = normalize_xy(s->var_values[VAR_X], s->hsub);
+ s->y = normalize_xy(s->var_values[VAR_Y], s->vsub);
+}
+
+static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx)
+{
+ int ret;
+ AVExpr *old = NULL;
+
+ if (*pexpr)
+ old = *pexpr;
+ ret = av_expr_parse(pexpr, expr, var_names,
+ NULL, NULL, NULL, NULL, 0, log_ctx);
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Error when evaluating the expression '%s' for %s\n",
+ expr, option);
+ *pexpr = old;
+ return ret;
+ }
+
+ av_expr_free(old);
+ return 0;
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ OverlayContext *s = ctx->priv;
+ int ret;
+
+ if (!strcmp(cmd, "x"))
+ ret = set_expr(&s->x_pexpr, args, cmd, ctx);
+ else if (!strcmp(cmd, "y"))
+ ret = set_expr(&s->y_pexpr, args, cmd, ctx);
+ else
+ ret = AVERROR(ENOSYS);
+
+ if (ret < 0)
+ return ret;
+
+ if (s->eval_mode == EVAL_MODE_INIT) {
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d\n",
+ s->var_values[VAR_X], s->x,
+ s->var_values[VAR_Y], s->y);
+ }
+ return ret;
}
static int query_formats(AVFilterContext *ctx)
{
- const enum AVPixelFormat inout_pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
- const enum AVPixelFormat blend_pix_fmts[] = { AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE };
- AVFilterFormats *inout_formats = ff_make_format_list(inout_pix_fmts);
- AVFilterFormats *blend_formats = ff_make_format_list(blend_pix_fmts);
+ OverlayContext *s = ctx->priv;
- ff_formats_ref(inout_formats, &ctx->inputs [MAIN ]->out_formats);
- ff_formats_ref(blend_formats, &ctx->inputs [OVERLAY]->out_formats);
- ff_formats_ref(inout_formats, &ctx->outputs[MAIN ]->in_formats );
+ /* overlay formats contains alpha, for avoiding conversion with alpha information loss */
+ static const enum AVPixelFormat main_pix_fmts_yuv420[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat overlay_pix_fmts_yuv420[] = {
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE
+ };
+
+ static const enum AVPixelFormat main_pix_fmts_yuv422[] = {
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat overlay_pix_fmts_yuv422[] = {
+ AV_PIX_FMT_YUVA422P, AV_PIX_FMT_NONE
+ };
+
+ static const enum AVPixelFormat main_pix_fmts_yuv444[] = {
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat overlay_pix_fmts_yuv444[] = {
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE
+ };
+
+ static const enum AVPixelFormat main_pix_fmts_rgb[] = {
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+ };
+ static const enum AVPixelFormat overlay_pix_fmts_rgb[] = {
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *main_formats;
+ AVFilterFormats *overlay_formats;
+
+ switch (s->format) {
+ case OVERLAY_FORMAT_YUV420:
+ main_formats = ff_make_format_list(main_pix_fmts_yuv420);
+ overlay_formats = ff_make_format_list(overlay_pix_fmts_yuv420);
+ break;
+ case OVERLAY_FORMAT_YUV422:
+ main_formats = ff_make_format_list(main_pix_fmts_yuv422);
+ overlay_formats = ff_make_format_list(overlay_pix_fmts_yuv422);
+ break;
+ case OVERLAY_FORMAT_YUV444:
+ main_formats = ff_make_format_list(main_pix_fmts_yuv444);
+ overlay_formats = ff_make_format_list(overlay_pix_fmts_yuv444);
+ break;
+ case OVERLAY_FORMAT_RGB:
+ main_formats = ff_make_format_list(main_pix_fmts_rgb);
+ overlay_formats = ff_make_format_list(overlay_pix_fmts_rgb);
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ ff_formats_ref(main_formats, &ctx->inputs [MAIN ]->out_formats);
+ ff_formats_ref(overlay_formats, &ctx->inputs [OVERLAY]->out_formats);
+ ff_formats_ref(main_formats, &ctx->outputs[MAIN ]->in_formats );
return 0;
}
+static const enum AVPixelFormat alpha_pix_fmts[] = {
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE
+};
+
static int config_input_main(AVFilterLink *inlink)
{
OverlayContext *s = inlink->dst->priv;
const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
- av_image_fill_max_pixsteps(s->max_plane_step, NULL, pix_desc);
+ av_image_fill_max_pixsteps(s->main_pix_step, NULL, pix_desc);
+
s->hsub = pix_desc->log2_chroma_w;
s->vsub = pix_desc->log2_chroma_h;
+ s->main_is_packed_rgb =
+ ff_fill_rgba_map(s->main_rgba_map, inlink->format) >= 0;
+ s->main_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
return 0;
}
@@ -127,66 +302,58 @@ static int config_input_overlay(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
OverlayContext *s = inlink->dst->priv;
- char *expr;
- double var_values[VAR_VARS_NB], res;
int ret;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
+
+ av_image_fill_max_pixsteps(s->overlay_pix_step, NULL, pix_desc);
/* Finish the configuration by evaluating the expressions
now when both inputs are configured. */
- var_values[VAR_E ] = M_E;
- var_values[VAR_PHI] = M_PHI;
- var_values[VAR_PI ] = M_PI;
-
- var_values[VAR_MAIN_W ] = var_values[VAR_MW] = ctx->inputs[MAIN ]->w;
- var_values[VAR_MAIN_H ] = var_values[VAR_MH] = ctx->inputs[MAIN ]->h;
- var_values[VAR_OVERLAY_W] = var_values[VAR_OW] = ctx->inputs[OVERLAY]->w;
- var_values[VAR_OVERLAY_H] = var_values[VAR_OH] = ctx->inputs[OVERLAY]->h;
-
- if ((ret = av_expr_parse_and_eval(&res, (expr = s->x_expr), var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
- s->x = res;
- if ((ret = av_expr_parse_and_eval(&res, (expr = s->y_expr), var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)))
- goto fail;
- s->y = res;
- /* x may depend on y */
- if ((ret = av_expr_parse_and_eval(&res, (expr = s->x_expr), var_names, var_values,
- NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
- goto fail;
- s->x = res;
+ s->var_values[VAR_MAIN_W ] = s->var_values[VAR_MW] = ctx->inputs[MAIN ]->w;
+ s->var_values[VAR_MAIN_H ] = s->var_values[VAR_MH] = ctx->inputs[MAIN ]->h;
+ s->var_values[VAR_OVERLAY_W] = s->var_values[VAR_OW] = ctx->inputs[OVERLAY]->w;
+ s->var_values[VAR_OVERLAY_H] = s->var_values[VAR_OH] = ctx->inputs[OVERLAY]->h;
+ s->var_values[VAR_HSUB] = 1<<pix_desc->log2_chroma_w;
+ s->var_values[VAR_VSUB] = 1<<pix_desc->log2_chroma_h;
+ s->var_values[VAR_X] = NAN;
+ s->var_values[VAR_Y] = NAN;
+ s->var_values[VAR_N] = 0;
+ s->var_values[VAR_T] = NAN;
+ s->var_values[VAR_POS] = NAN;
+
+ if ((ret = set_expr(&s->x_pexpr, s->x_expr, "x", ctx)) < 0 ||
+ (ret = set_expr(&s->y_pexpr, s->y_expr, "y", ctx)) < 0)
+ return ret;
+
+ s->overlay_is_packed_rgb =
+ ff_fill_rgba_map(s->overlay_rgba_map, inlink->format) >= 0;
+ s->overlay_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts);
+
+ if (s->eval_mode == EVAL_MODE_INIT) {
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_VERBOSE, "x:%f xi:%d y:%f yi:%d\n",
+ s->var_values[VAR_X], s->x,
+ s->var_values[VAR_Y], s->y);
+ }
av_log(ctx, AV_LOG_VERBOSE,
- "main w:%d h:%d fmt:%s overlay x:%d y:%d w:%d h:%d fmt:%s eof_action:%s\n",
+ "main w:%d h:%d fmt:%s overlay w:%d h:%d fmt:%s eof_action:%s\n",
ctx->inputs[MAIN]->w, ctx->inputs[MAIN]->h,
av_get_pix_fmt_name(ctx->inputs[MAIN]->format),
- s->x, s->y,
ctx->inputs[OVERLAY]->w, ctx->inputs[OVERLAY]->h,
av_get_pix_fmt_name(ctx->inputs[OVERLAY]->format),
eof_action_str[s->eof_action]);
-
- if (s->x < 0 || s->y < 0 ||
- s->x + var_values[VAR_OVERLAY_W] > var_values[VAR_MAIN_W] ||
- s->y + var_values[VAR_OVERLAY_H] > var_values[VAR_MAIN_H]) {
- av_log(ctx, AV_LOG_ERROR,
- "Overlay area (%d,%d)<->(%d,%d) not within the main area (0,0)<->(%d,%d) or zero-sized\n",
- s->x, s->y,
- (int)(s->x + var_values[VAR_OVERLAY_W]),
- (int)(s->y + var_values[VAR_OVERLAY_H]),
- (int)var_values[VAR_MAIN_W], (int)var_values[VAR_MAIN_H]);
- return AVERROR(EINVAL);
- }
return 0;
-
-fail:
- av_log(NULL, AV_LOG_ERROR,
- "Error when evaluating the expression '%s'\n", expr);
- return ret;
}
static int config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
+ OverlayContext *s = ctx->priv;
+ int ret;
+
+ if ((ret = ff_dualinput_init(ctx, &s->dinput)) < 0)
+ return ret;
outlink->w = ctx->inputs[MAIN]->w;
outlink->h = ctx->inputs[MAIN]->h;
@@ -195,71 +362,196 @@ static int config_output(AVFilterLink *outlink)
return 0;
}
-static void blend_frame(AVFilterContext *ctx,
- AVFrame *dst, AVFrame *src,
+// divide by 255 and round to nearest
+// apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
+#define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
+
+// calculate the unpremultiplied alpha, applying the general equation:
+// alpha = alpha_overlay / ( (alpha_main + alpha_overlay) - (alpha_main * alpha_overlay) )
+// (((x) << 16) - ((x) << 9) + (x)) is a faster version of: 255 * 255 * x
+// ((((x) + (y)) << 8) - ((x) + (y)) - (y) * (x)) is a faster version of: 255 * (x + y)
+#define UNPREMULTIPLY_ALPHA(x, y) ((((x) << 16) - ((x) << 9) + (x)) / ((((x) + (y)) << 8) - ((x) + (y)) - (y) * (x)))
+
+/**
+ * Blend image in src to destination buffer dst at position (x, y).
+ */
+static void blend_image(AVFilterContext *ctx,
+ AVFrame *dst, const AVFrame *src,
int x, int y)
{
OverlayContext *s = ctx->priv;
- int i, j, k;
- int width, height;
- int overlay_end_y = y + src->height;
- int end_y, start_y;
-
- width = FFMIN(dst->width - x, src->width);
- end_y = FFMIN(dst->height, overlay_end_y);
- start_y = FFMAX(y, 0);
- height = end_y - start_y;
-
- if (dst->format == AV_PIX_FMT_BGR24 || dst->format == AV_PIX_FMT_RGB24) {
- uint8_t *dp = dst->data[0] + x * 3 + start_y * dst->linesize[0];
- uint8_t *sp = src->data[0];
- int b = dst->format == AV_PIX_FMT_BGR24 ? 2 : 0;
- int r = dst->format == AV_PIX_FMT_BGR24 ? 0 : 2;
- if (y < 0)
- sp += -y * src->linesize[0];
- for (i = 0; i < height; i++) {
- uint8_t *d = dp, *s = sp;
- for (j = 0; j < width; j++) {
- d[r] = (d[r] * (0xff - s[3]) + s[0] * s[3] + 128) >> 8;
- d[1] = (d[1] * (0xff - s[3]) + s[1] * s[3] + 128) >> 8;
- d[b] = (d[b] * (0xff - s[3]) + s[2] * s[3] + 128) >> 8;
- d += 3;
- s += 4;
+ int i, imax, j, jmax, k, kmax;
+ const int src_w = src->width;
+ const int src_h = src->height;
+ const int dst_w = dst->width;
+ const int dst_h = dst->height;
+
+ if (x >= dst_w || x+src_w < 0 ||
+ y >= dst_h || y+src_h < 0)
+ return; /* no intersection */
+
+ if (s->main_is_packed_rgb) {
+ uint8_t alpha; ///< the amount of overlay to blend on to main
+ const int dr = s->main_rgba_map[R];
+ const int dg = s->main_rgba_map[G];
+ const int db = s->main_rgba_map[B];
+ const int da = s->main_rgba_map[A];
+ const int dstep = s->main_pix_step[0];
+ const int sr = s->overlay_rgba_map[R];
+ const int sg = s->overlay_rgba_map[G];
+ const int sb = s->overlay_rgba_map[B];
+ const int sa = s->overlay_rgba_map[A];
+ const int sstep = s->overlay_pix_step[0];
+ const int main_has_alpha = s->main_has_alpha;
+ uint8_t *s, *sp, *d, *dp;
+
+ i = FFMAX(-y, 0);
+ sp = src->data[0] + i * src->linesize[0];
+ dp = dst->data[0] + (y+i) * dst->linesize[0];
+
+ for (imax = FFMIN(-y + dst_h, src_h); i < imax; i++) {
+ j = FFMAX(-x, 0);
+ s = sp + j * sstep;
+ d = dp + (x+j) * dstep;
+
+ for (jmax = FFMIN(-x + dst_w, src_w); j < jmax; j++) {
+ alpha = s[sa];
+
+ // if the main channel has an alpha channel, alpha has to be calculated
+ // to create an un-premultiplied (straight) alpha value
+ if (main_has_alpha && alpha != 0 && alpha != 255) {
+ uint8_t alpha_d = d[da];
+ alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d);
+ }
+
+ switch (alpha) {
+ case 0:
+ break;
+ case 255:
+ d[dr] = s[sr];
+ d[dg] = s[sg];
+ d[db] = s[sb];
+ break;
+ default:
+ // main_value = main_value * (1 - alpha) + overlay_value * alpha
+ // since alpha is in the range 0-255, the result must divided by 255
+ d[dr] = FAST_DIV255(d[dr] * (255 - alpha) + s[sr] * alpha);
+ d[dg] = FAST_DIV255(d[dg] * (255 - alpha) + s[sg] * alpha);
+ d[db] = FAST_DIV255(d[db] * (255 - alpha) + s[sb] * alpha);
+ }
+ if (main_has_alpha) {
+ switch (alpha) {
+ case 0:
+ break;
+ case 255:
+ d[da] = s[sa];
+ break;
+ default:
+ // apply alpha compositing: main_alpha += (1-main_alpha) * overlay_alpha
+ d[da] += FAST_DIV255((255 - d[da]) * s[sa]);
+ }
+ }
+ d += dstep;
+ s += sstep;
}
dp += dst->linesize[0];
sp += src->linesize[0];
}
} else {
+ const int main_has_alpha = s->main_has_alpha;
+ if (main_has_alpha) {
+ uint8_t alpha; ///< the amount of overlay to blend on to main
+ uint8_t *s, *sa, *d, *da;
+
+ i = FFMAX(-y, 0);
+ sa = src->data[3] + i * src->linesize[3];
+ da = dst->data[3] + (y+i) * dst->linesize[3];
+
+ for (imax = FFMIN(-y + dst_h, src_h); i < imax; i++) {
+ j = FFMAX(-x, 0);
+ s = sa + j;
+ d = da + x+j;
+
+ for (jmax = FFMIN(-x + dst_w, src_w); j < jmax; j++) {
+ alpha = *s;
+ if (alpha != 0 && alpha != 255) {
+ uint8_t alpha_d = *d;
+ alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d);
+ }
+ switch (alpha) {
+ case 0:
+ break;
+ case 255:
+ *d = *s;
+ break;
+ default:
+ // apply alpha compositing: main_alpha += (1-main_alpha) * overlay_alpha
+ *d += FAST_DIV255((255 - *d) * *s);
+ }
+ d += 1;
+ s += 1;
+ }
+ da += dst->linesize[3];
+ sa += src->linesize[3];
+ }
+ }
for (i = 0; i < 3; i++) {
int hsub = i ? s->hsub : 0;
int vsub = i ? s->vsub : 0;
- uint8_t *dp = dst->data[i] + (x >> hsub) +
- (start_y >> vsub) * dst->linesize[i];
- uint8_t *sp = src->data[i];
- uint8_t *ap = src->data[3];
- int wp = FFALIGN(width, 1<<hsub) >> hsub;
- int hp = FFALIGN(height, 1<<vsub) >> vsub;
- if (y < 0) {
- sp += ((-y) >> vsub) * src->linesize[i];
- ap += -y * src->linesize[3];
- }
- for (j = 0; j < hp; j++) {
- uint8_t *d = dp, *s = sp, *a = ap;
- for (k = 0; k < wp; k++) {
- // average alpha for color components, improve quality
+ int src_wp = FF_CEIL_RSHIFT(src_w, hsub);
+ int src_hp = FF_CEIL_RSHIFT(src_h, vsub);
+ int dst_wp = FF_CEIL_RSHIFT(dst_w, hsub);
+ int dst_hp = FF_CEIL_RSHIFT(dst_h, vsub);
+ int yp = y>>vsub;
+ int xp = x>>hsub;
+ uint8_t *s, *sp, *d, *dp, *a, *ap;
+
+ j = FFMAX(-yp, 0);
+ sp = src->data[i] + j * src->linesize[i];
+ dp = dst->data[i] + (yp+j) * dst->linesize[i];
+ ap = src->data[3] + (j<<vsub) * src->linesize[3];
+
+ for (jmax = FFMIN(-yp + dst_hp, src_hp); j < jmax; j++) {
+ k = FFMAX(-xp, 0);
+ d = dp + xp+k;
+ s = sp + k;
+ a = ap + (k<<hsub);
+
+ for (kmax = FFMIN(-xp + dst_wp, src_wp); k < kmax; k++) {
int alpha_v, alpha_h, alpha;
- if (hsub && vsub && j+1 < hp && k+1 < wp) {
+
+ // average alpha for color components, improve quality
+ if (hsub && vsub && j+1 < src_hp && k+1 < src_wp) {
alpha = (a[0] + a[src->linesize[3]] +
a[1] + a[src->linesize[3]+1]) >> 2;
} else if (hsub || vsub) {
- alpha_h = hsub && k+1 < wp ?
+ alpha_h = hsub && k+1 < src_wp ?
(a[0] + a[1]) >> 1 : a[0];
- alpha_v = vsub && j+1 < hp ?
+ alpha_v = vsub && j+1 < src_hp ?
(a[0] + a[src->linesize[3]]) >> 1 : a[0];
alpha = (alpha_v + alpha_h) >> 1;
} else
alpha = a[0];
- *d = (*d * (0xff - alpha) + *s++ * alpha + 128) >> 8;
+ // if the main channel has an alpha channel, alpha has to be calculated
+ // to create an un-premultiplied (straight) alpha value
+ if (main_has_alpha && alpha != 0 && alpha != 255) {
+ // average alpha for color components, improve quality
+ uint8_t alpha_d;
+ if (hsub && vsub && j+1 < src_hp && k+1 < src_wp) {
+ alpha_d = (d[0] + d[src->linesize[3]] +
+ d[1] + d[src->linesize[3]+1]) >> 2;
+ } else if (hsub || vsub) {
+ alpha_h = hsub && k+1 < src_wp ?
+ (d[0] + d[1]) >> 1 : d[0];
+ alpha_v = vsub && j+1 < src_hp ?
+ (d[0] + d[src->linesize[3]]) >> 1 : d[0];
+ alpha_d = (alpha_v + alpha_h) >> 1;
+ } else
+ alpha_d = d[0];
+ alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d);
+ }
+ *d = FAST_DIV255(*d * (255 - alpha) + *s * alpha);
+ s++;
d++;
a += 1 << hsub;
}
@@ -271,136 +563,107 @@ static void blend_frame(AVFilterContext *ctx,
}
}
-static int filter_frame_main(AVFilterLink *inlink, AVFrame *frame)
+static AVFrame *do_blend(AVFilterContext *ctx, AVFrame *mainpic,
+ const AVFrame *second)
{
- OverlayContext *s = inlink->dst->priv;
-
- av_assert0(!s->main);
- s->main = frame;
+ OverlayContext *s = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
- return 0;
-}
+ if (s->eval_mode == EVAL_MODE_FRAME) {
+ int64_t pos = av_frame_get_pkt_pos(mainpic);
-static int filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame)
-{
- OverlayContext *s = inlink->dst->priv;
+ s->var_values[VAR_N] = inlink->frame_count;
+ s->var_values[VAR_T] = mainpic->pts == AV_NOPTS_VALUE ?
+ NAN : mainpic->pts * av_q2d(inlink->time_base);
+ s->var_values[VAR_POS] = pos == -1 ? NAN : pos;
- av_assert0(!s->over_next);
- s->over_next = frame;
+ eval_expr(ctx);
+ av_log(ctx, AV_LOG_DEBUG, "n:%f t:%f pos:%f x:%f xi:%d y:%f yi:%d\n",
+ s->var_values[VAR_N], s->var_values[VAR_T], s->var_values[VAR_POS],
+ s->var_values[VAR_X], s->x,
+ s->var_values[VAR_Y], s->y);
+ }
- return 0;
+ blend_image(ctx, mainpic, second, s->x, s->y);
+ return mainpic;
}
-static int output_frame(AVFilterContext *ctx)
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
{
- OverlayContext *s = ctx->priv;
- AVFilterLink *outlink = ctx->outputs[0];
- int ret = ff_filter_frame(outlink, s->main);
- s->main = NULL;
-
- return ret;
+ OverlayContext *s = inlink->dst->priv;
+ av_log(inlink->dst, AV_LOG_DEBUG, "Incoming frame (time:%s) from link #%d\n", av_ts2timestr(inpicref->pts, &inlink->time_base), FF_INLINK_IDX(inlink));
+ return ff_dualinput_filter_frame(&s->dinput, inlink, inpicref);
}
-static int handle_overlay_eof(AVFilterContext *ctx)
+static int request_frame(AVFilterLink *outlink)
{
- OverlayContext *s = ctx->priv;
- /* Repeat previous frame on secondary input */
- if (s->over_prev && s->eof_action == EOF_ACTION_REPEAT)
- blend_frame(ctx, s->main, s->over_prev, s->x, s->y);
- /* End both streams */
- else if (s->eof_action == EOF_ACTION_ENDALL)
- return AVERROR_EOF;
- return output_frame(ctx);
+ OverlayContext *s = outlink->src->priv;
+ return ff_dualinput_request_frame(&s->dinput, outlink);
}
-static int request_frame(AVFilterLink *outlink)
+static av_cold int init(AVFilterContext *ctx)
{
- AVFilterContext *ctx = outlink->src;
- OverlayContext *s = ctx->priv;
- AVRational tb_main = ctx->inputs[MAIN]->time_base;
- AVRational tb_over = ctx->inputs[OVERLAY]->time_base;
- int ret = 0;
-
- /* get a frame on the main input */
- if (!s->main) {
- ret = ff_request_frame(ctx->inputs[MAIN]);
- if (ret < 0)
- return ret;
- }
+ OverlayContext *s = ctx->priv;
- /* get a new frame on the overlay input, on EOF check setting 'eof_action' */
- if (!s->over_next) {
- ret = ff_request_frame(ctx->inputs[OVERLAY]);
- if (ret == AVERROR_EOF)
- return handle_overlay_eof(ctx);
- else if (ret < 0)
- return ret;
+ if (s->allow_packed_rgb) {
+ av_log(ctx, AV_LOG_WARNING,
+ "The rgb option is deprecated and is overriding the format option, use format instead\n");
+ s->format = OVERLAY_FORMAT_RGB;
}
-
- while (s->main->pts != AV_NOPTS_VALUE &&
- s->over_next->pts != AV_NOPTS_VALUE &&
- av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main) < 0) {
- av_frame_free(&s->over_prev);
- FFSWAP(AVFrame*, s->over_prev, s->over_next);
-
- ret = ff_request_frame(ctx->inputs[OVERLAY]);
- if (ret == AVERROR_EOF)
- return handle_overlay_eof(ctx);
- else if (ret < 0)
- return ret;
+ if (!s->dinput.repeatlast || s->eof_action == EOF_ACTION_PASS) {
+ s->dinput.repeatlast = 0;
+ s->eof_action = EOF_ACTION_PASS;
}
-
- if (s->main->pts == AV_NOPTS_VALUE ||
- s->over_next->pts == AV_NOPTS_VALUE ||
- !av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main)) {
- blend_frame(ctx, s->main, s->over_next, s->x, s->y);
- av_frame_free(&s->over_prev);
- FFSWAP(AVFrame*, s->over_prev, s->over_next);
- } else if (s->over_prev) {
- blend_frame(ctx, s->main, s->over_prev, s->x, s->y);
+ if (s->dinput.shortest || s->eof_action == EOF_ACTION_ENDALL) {
+ s->dinput.shortest = 1;
+ s->eof_action = EOF_ACTION_ENDALL;
}
- return output_frame(ctx);
+ s->dinput.process = do_blend;
+ return 0;
}
#define OFFSET(x) offsetof(OverlayContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "x", "Horizontal position of the left edge of the overlaid video on the "
- "main video.", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
- { "y", "Vertical position of the top edge of the overlaid video on the "
- "main video.", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption overlay_options[] = {
+ { "x", "set the x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "y", "set the y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "eof_action", "Action to take when encountering EOF from secondary input ",
OFFSET(eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT },
EOF_ACTION_REPEAT, EOF_ACTION_PASS, .flags = FLAGS, "eof_action" },
{ "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" },
{ "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" },
{ "pass", "Pass through the main input.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_PASS }, .flags = FLAGS, "eof_action" },
- { NULL },
+ { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_FRAME}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
+ { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
+ { "frame", "eval expressions per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
+ { "rgb", "force packed RGB in input and output (deprecated)", OFFSET(allow_packed_rgb), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "shortest", "force termination when the shortest input terminates", OFFSET(dinput.shortest), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+ { "format", "set output format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=OVERLAY_FORMAT_YUV420}, 0, OVERLAY_FORMAT_NB-1, FLAGS, "format" },
+ { "yuv420", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_YUV420}, .flags = FLAGS, .unit = "format" },
+ { "yuv422", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_YUV422}, .flags = FLAGS, .unit = "format" },
+ { "yuv444", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_YUV444}, .flags = FLAGS, .unit = "format" },
+ { "rgb", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_RGB}, .flags = FLAGS, .unit = "format" },
+ { "repeatlast", "repeat overlay of the last overlay frame", OFFSET(dinput.repeatlast), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { NULL }
};
-static const AVClass overlay_class = {
- .class_name = "overlay",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(overlay);
static const AVFilterPad avfilter_vf_overlay_inputs[] = {
{
.name = "main",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_input_main,
- .filter_frame = filter_frame_main,
+ .filter_frame = filter_frame,
.needs_writable = 1,
- .needs_fifo = 1,
},
{
.name = "overlay",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_input_overlay,
- .filter_frame = filter_frame_overlay,
- .needs_fifo = 1,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -416,16 +679,15 @@ static const AVFilterPad avfilter_vf_overlay_outputs[] = {
};
AVFilter ff_vf_overlay = {
- .name = "overlay",
- .description = NULL_IF_CONFIG_SMALL("Overlay a video source on top of the input."),
-
- .uninit = uninit,
-
- .priv_size = sizeof(OverlayContext),
- .priv_class = &overlay_class,
-
+ .name = "overlay",
+ .description = NULL_IF_CONFIG_SMALL("Overlay a video source on top of the input."),
+ .init = init,
+ .uninit = uninit,
+ .priv_size = sizeof(OverlayContext),
+ .priv_class = &overlay_class,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_overlay_inputs,
- .outputs = avfilter_vf_overlay_outputs,
+ .process_command = process_command,
+ .inputs = avfilter_vf_overlay_inputs,
+ .outputs = avfilter_vf_overlay_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
};
diff --git a/libavfilter/vf_owdenoise.c b/libavfilter/vf_owdenoise.c
new file mode 100644
index 0000000000..f91bbe5db1
--- /dev/null
+++ b/libavfilter/vf_owdenoise.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2007 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * 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.
+ */
+
+/**
+ * @todo try to change to int
+ * @todo try lifting based implementation
+ * @todo optimize optimize optimize
+ * @todo hard thresholding
+ * @todo use QP to decide filter strength
+ * @todo wavelet normalization / least squares optimal signal vs. noise thresholds
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ double luma_strength;
+ double chroma_strength;
+ int depth;
+ float *plane[16+1][4];
+ int linesize;
+ int hsub, vsub;
+} OWDenoiseContext;
+
+#define OFFSET(x) offsetof(OWDenoiseContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption owdenoise_options[] = {
+ { "depth", "set depth", OFFSET(depth), AV_OPT_TYPE_INT, {.i64 = 8}, 8, 16, FLAGS },
+ { "luma_strength", "set luma strength", OFFSET(luma_strength), AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, 0, 1000, FLAGS },
+ { "ls", "set luma strength", OFFSET(luma_strength), AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, 0, 1000, FLAGS },
+ { "chroma_strength", "set chroma strength", OFFSET(chroma_strength), AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, 0, 1000, FLAGS },
+ { "cs", "set chroma strength", OFFSET(chroma_strength), AV_OPT_TYPE_DOUBLE, {.dbl = 1.0}, 0, 1000, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(owdenoise);
+
+DECLARE_ALIGNED(8, static const uint8_t, dither)[8][8] = {
+ { 0, 48, 12, 60, 3, 51, 15, 63 },
+ { 32, 16, 44, 28, 35, 19, 47, 31 },
+ { 8, 56, 4, 52, 11, 59, 7, 55 },
+ { 40, 24, 36, 20, 43, 27, 39, 23 },
+ { 2, 50, 14, 62, 1, 49, 13, 61 },
+ { 34, 18, 46, 30, 33, 17, 45, 29 },
+ { 10, 58, 6, 54, 9, 57, 5, 53 },
+ { 42, 26, 38, 22, 41, 25, 37, 21 },
+};
+
+static const double coeff[2][5] = {
+ {
+ 0.6029490182363579 * M_SQRT2,
+ 0.2668641184428723 * M_SQRT2,
+ -0.07822326652898785 * M_SQRT2,
+ -0.01686411844287495 * M_SQRT2,
+ 0.02674875741080976 * M_SQRT2,
+ },{
+ 1.115087052456994 / M_SQRT2,
+ -0.5912717631142470 / M_SQRT2,
+ -0.05754352622849957 / M_SQRT2,
+ 0.09127176311424948 / M_SQRT2,
+ }
+};
+
+static const double icoeff[2][5] = {
+ {
+ 1.115087052456994 / M_SQRT2,
+ 0.5912717631142470 / M_SQRT2,
+ -0.05754352622849957 / M_SQRT2,
+ -0.09127176311424948 / M_SQRT2,
+ },{
+ 0.6029490182363579 * M_SQRT2,
+ -0.2668641184428723 * M_SQRT2,
+ -0.07822326652898785 * M_SQRT2,
+ 0.01686411844287495 * M_SQRT2,
+ 0.02674875741080976 * M_SQRT2,
+ }
+};
+
+
+static inline void decompose(float *dst_l, float *dst_h, const float *src,
+ int linesize, int w)
+{
+ int x, i;
+ for (x = 0; x < w; x++) {
+ double sum_l = src[x * linesize] * coeff[0][0];
+ double sum_h = src[x * linesize] * coeff[1][0];
+ for (i = 1; i <= 4; i++) {
+ const double s = src[avpriv_mirror(x - i, w - 1) * linesize]
+ + src[avpriv_mirror(x + i, w - 1) * linesize];
+
+ sum_l += coeff[0][i] * s;
+ sum_h += coeff[1][i] * s;
+ }
+ dst_l[x * linesize] = sum_l;
+ dst_h[x * linesize] = sum_h;
+ }
+}
+
+static inline void compose(float *dst, const float *src_l, const float *src_h,
+ int linesize, int w)
+{
+ int x, i;
+ for (x = 0; x < w; x++) {
+ double sum_l = src_l[x * linesize] * icoeff[0][0];
+ double sum_h = src_h[x * linesize] * icoeff[1][0];
+ for (i = 1; i <= 4; i++) {
+ const int x0 = avpriv_mirror(x - i, w - 1) * linesize;
+ const int x1 = avpriv_mirror(x + i, w - 1) * linesize;
+
+ sum_l += icoeff[0][i] * (src_l[x0] + src_l[x1]);
+ sum_h += icoeff[1][i] * (src_h[x0] + src_h[x1]);
+ }
+ dst[x * linesize] = (sum_l + sum_h) * 0.5;
+ }
+}
+
+static inline void decompose2D(float *dst_l, float *dst_h, const float *src,
+ int xlinesize, int ylinesize,
+ int step, int w, int h)
+{
+ int y, x;
+ for (y = 0; y < h; y++)
+ for (x = 0; x < step; x++)
+ decompose(dst_l + ylinesize*y + xlinesize*x,
+ dst_h + ylinesize*y + xlinesize*x,
+ src + ylinesize*y + xlinesize*x,
+ step * xlinesize, (w - x + step - 1) / step);
+}
+
+static inline void compose2D(float *dst, const float *src_l, const float *src_h,
+ int xlinesize, int ylinesize,
+ int step, int w, int h)
+{
+ int y, x;
+ for (y = 0; y < h; y++)
+ for (x = 0; x < step; x++)
+ compose(dst + ylinesize*y + xlinesize*x,
+ src_l + ylinesize*y + xlinesize*x,
+ src_h + ylinesize*y + xlinesize*x,
+ step * xlinesize, (w - x + step - 1) / step);
+}
+
+static void decompose2D2(float *dst[4], float *src, float *temp[2],
+ int linesize, int step, int w, int h)
+{
+ decompose2D(temp[0], temp[1], src, 1, linesize, step, w, h);
+ decompose2D( dst[0], dst[1], temp[0], linesize, 1, step, h, w);
+ decompose2D( dst[2], dst[3], temp[1], linesize, 1, step, h, w);
+}
+
+static void compose2D2(float *dst, float *src[4], float *temp[2],
+ int linesize, int step, int w, int h)
+{
+ compose2D(temp[0], src[0], src[1], linesize, 1, step, h, w);
+ compose2D(temp[1], src[2], src[3], linesize, 1, step, h, w);
+ compose2D(dst, temp[0], temp[1], 1, linesize, step, w, h);
+}
+
+static void filter(OWDenoiseContext *s,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize,
+ int width, int height, double strength)
+{
+ int x, y, i, j, depth = s->depth;
+
+ while (1<<depth > width || 1<<depth > height)
+ depth--;
+
+ for (y = 0; y < height; y++)
+ for(x = 0; x < width; x++)
+ s->plane[0][0][y*s->linesize + x] = src[y*src_linesize + x];
+
+ for (i = 0; i < depth; i++)
+ decompose2D2(s->plane[i + 1], s->plane[i][0], s->plane[0] + 1, s->linesize, 1<<i, width, height);
+
+ for (i = 0; i < depth; i++) {
+ for (j = 1; j < 4; j++) {
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ double v = s->plane[i + 1][j][y*s->linesize + x];
+ if (v > strength) v -= strength;
+ else if (v < -strength) v += strength;
+ else v = 0;
+ s->plane[i + 1][j][x + y*s->linesize] = v;
+ }
+ }
+ }
+ }
+ for (i = depth-1; i >= 0; i--)
+ compose2D2(s->plane[i][0], s->plane[i + 1], s->plane[0] + 1, s->linesize, 1<<i, width, height);
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ i = s->plane[0][0][y*s->linesize + x] + dither[x&7][y&7]*(1.0/64) + 1.0/128; // yes the rounding is insane but optimal :)
+ if ((unsigned)i > 255U) i = ~(i >> 31);
+ dst[y*dst_linesize + x] = i;
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ int direct = 0;
+ AVFilterContext *ctx = inlink->dst;
+ OWDenoiseContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ const int cw = FF_CEIL_RSHIFT(inlink->w, s->hsub);
+ const int ch = FF_CEIL_RSHIFT(inlink->h, s->vsub);
+
+ if (av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ filter(s, out->data[0], out->linesize[0], in->data[0], in->linesize[0], inlink->w, inlink->h, s->luma_strength);
+ filter(s, out->data[1], out->linesize[1], in->data[1], in->linesize[1], cw, ch, s->chroma_strength);
+ filter(s, out->data[2], out->linesize[2], in->data[2], in->linesize[2], cw, ch, s->chroma_strength);
+
+ if (!direct) {
+ if (in->data[3])
+ av_image_copy_plane(out->data[3], out->linesize[3],
+ in ->data[3], in ->linesize[3],
+ inlink->w, inlink->h);
+ av_frame_free(&in);
+ }
+
+ return ff_filter_frame(outlink, out);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVA444P, AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ int i, j;
+ OWDenoiseContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const int h = FFALIGN(inlink->h, 16);
+
+ s->hsub = desc->log2_chroma_w;
+ s->vsub = desc->log2_chroma_h;
+
+ s->linesize = FFALIGN(inlink->w, 16);
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i <= s->depth; i++) {
+ s->plane[i][j] = av_malloc_array(s->linesize, h * sizeof(s->plane[0][0][0]));
+ if (!s->plane[i][j])
+ return AVERROR(ENOMEM);
+ }
+ }
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i, j;
+ OWDenoiseContext *s = ctx->priv;
+
+ for (j = 0; j < 4; j++)
+ for (i = 0; i <= s->depth; i++)
+ av_freep(&s->plane[i][j]);
+}
+
+static const AVFilterPad owdenoise_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad owdenoise_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_owdenoise = {
+ .name = "owdenoise",
+ .description = NULL_IF_CONFIG_SMALL("Denoise using wavelets."),
+ .priv_size = sizeof(OWDenoiseContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = owdenoise_inputs,
+ .outputs = owdenoise_outputs,
+ .priv_class = &owdenoise_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c
index 634af4c941..63dc6a8b6c 100644
--- a/libavfilter/vf_pad.c
+++ b/libavfilter/vf_pad.c
@@ -2,20 +2,20 @@
* Copyright (c) 2008 vmrsss
* Copyright (c) 2009 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,9 +42,6 @@
#include "drawutils.h"
static const char *const var_names[] = {
- "PI",
- "PHI",
- "E",
"in_w", "iw",
"in_h", "ih",
"out_w", "ow",
@@ -52,15 +49,14 @@ static const char *const var_names[] = {
"x",
"y",
"a",
+ "sar",
+ "dar",
"hsub",
"vsub",
NULL
};
enum var_name {
- VAR_PI,
- VAR_PHI,
- VAR_E,
VAR_IN_W, VAR_IW,
VAR_IN_H, VAR_IH,
VAR_OUT_W, VAR_OW,
@@ -68,6 +64,8 @@ enum var_name {
VAR_X,
VAR_Y,
VAR_A,
+ VAR_SAR,
+ VAR_DAR,
VAR_HSUB,
VAR_VSUB,
VARS_NB
@@ -75,23 +73,7 @@ enum var_name {
static int query_formats(AVFilterContext *ctx)
{
- static const enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
- AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
-
- 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
- AV_PIX_FMT_YUVA420P,
-
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
}
typedef struct PadContext {
@@ -104,58 +86,32 @@ typedef struct PadContext {
char *h_expr; ///< height expression string
char *x_expr; ///< width expression string
char *y_expr; ///< height expression string
- char *color_str;
-
- uint8_t color[4]; ///< color expressed either in YUVA or RGBA colorspace for the padding area
- uint8_t *line[4];
- int line_step[4];
- int hsub, vsub; ///< chroma subsampling values
+ uint8_t rgba_color[4]; ///< color for the padding area
+ FFDrawContext draw;
+ FFDrawColor color;
} PadContext;
-static av_cold int init(AVFilterContext *ctx)
-{
- PadContext *s = ctx->priv;
-
- if (av_parse_color(s->color, s->color_str, -1, ctx) < 0)
- return AVERROR(EINVAL);
-
- return 0;
-}
-
-static av_cold void uninit(AVFilterContext *ctx)
-{
- PadContext *s = ctx->priv;
- int i;
-
- for (i = 0; i < 4; i++) {
- av_freep(&s->line[i]);
- s->line_step[i] = 0;
- }
-}
-
static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
PadContext *s = ctx->priv;
- const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
- uint8_t rgba_color[4];
- int ret, is_packed_rgba;
+ int ret;
double var_values[VARS_NB], res;
char *expr;
- s->hsub = pix_desc->log2_chroma_w;
- s->vsub = pix_desc->log2_chroma_h;
+ ff_draw_init(&s->draw, inlink->format, 0);
+ ff_draw_color(&s->draw, &s->color, s->rgba_color);
- var_values[VAR_PI] = M_PI;
- var_values[VAR_PHI] = M_PHI;
- var_values[VAR_E] = M_E;
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_HSUB] = 1<<s->hsub;
- var_values[VAR_VSUB] = 1<<s->vsub;
+ 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];
+ var_values[VAR_HSUB] = 1 << s->draw.hsub_max;
+ var_values[VAR_VSUB] = 1 << s->draw.vsub_max;
/* evaluate width and height */
av_expr_parse_and_eval(&res, (expr = s->w_expr),
@@ -202,22 +158,16 @@ static int config_input(AVFilterLink *inlink)
if (!s->h)
s->h = inlink->h;
- s->w &= ~((1 << s->hsub) - 1);
- s->h &= ~((1 << s->vsub) - 1);
- s->x &= ~((1 << s->hsub) - 1);
- s->y &= ~((1 << s->vsub) - 1);
+ s->w = ff_draw_round_to_sub(&s->draw, 0, -1, s->w);
+ s->h = ff_draw_round_to_sub(&s->draw, 1, -1, s->h);
+ s->x = ff_draw_round_to_sub(&s->draw, 0, -1, s->x);
+ s->y = ff_draw_round_to_sub(&s->draw, 1, -1, s->y);
+ s->in_w = ff_draw_round_to_sub(&s->draw, 0, -1, inlink->w);
+ s->in_h = ff_draw_round_to_sub(&s->draw, 1, -1, inlink->h);
- s->in_w = inlink->w & ~((1 << s->hsub) - 1);
- s->in_h = inlink->h & ~((1 << s->vsub) - 1);
-
- memcpy(rgba_color, s->color, sizeof(rgba_color));
- ff_fill_line_with_color(s->line, s->line_step, s->w, s->color,
- inlink->format, rgba_color, &is_packed_rgba, NULL);
-
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d x:%d y:%d color:0x%02X%02X%02X%02X[%s]\n",
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d x:%d y:%d color:0x%02X%02X%02X%02X\n",
inlink->w, inlink->h, s->w, s->h, s->x, s->y,
- s->color[0], s->color[1], s->color[2], s->color[3],
- is_packed_rgba ? "rgba" : "yuva");
+ s->rgba_color[0], s->rgba_color[1], s->rgba_color[2], s->rgba_color[3]);
if (s->x < 0 || s->y < 0 ||
s->w <= 0 || s->h <= 0 ||
@@ -262,12 +212,11 @@ static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
frame->width = w;
frame->height = h;
- for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
- int hsub = (plane == 1 || plane == 2) ? s->hsub : 0;
- int vsub = (plane == 1 || plane == 2) ? s->vsub : 0;
-
- frame->data[plane] += (s->x >> hsub) * s->line_step[plane] +
- (s->y >> vsub) * frame->linesize[plane];
+ for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) {
+ int hsub = s->draw.hsub[plane];
+ int vsub = s->draw.vsub[plane];
+ frame->data[plane] += (s->x >> hsub) * s->draw.pixelstep[plane] +
+ (s->y >> vsub) * frame->linesize[plane];
}
return frame;
@@ -288,38 +237,37 @@ static int buffer_needs_copy(PadContext *s, AVFrame *frame, AVBufferRef *buf)
/* for each plane in this buffer, check that it can be padded without
* going over buffer bounds or other planes */
for (i = 0; i < FF_ARRAY_ELEMS(planes) && planes[i] >= 0; i++) {
- int hsub = (planes[i] == 1 || planes[i] == 2) ? s->hsub : 0;
- int vsub = (planes[i] == 1 || planes[i] == 2) ? s->vsub : 0;
+ int hsub = s->draw.hsub[planes[i]];
+ int vsub = s->draw.vsub[planes[i]];
uint8_t *start = frame->data[planes[i]];
- uint8_t *end = start + (frame->height >> hsub) *
+ uint8_t *end = start + (frame->height >> vsub) *
frame->linesize[planes[i]];
/* amount of free space needed before the start and after the end
* of the plane */
- ptrdiff_t req_start = (s->x >> hsub) * s->line_step[planes[i]] +
+ ptrdiff_t req_start = (s->x >> hsub) * s->draw.pixelstep[planes[i]] +
(s->y >> vsub) * frame->linesize[planes[i]];
ptrdiff_t req_end = ((s->w - s->x - frame->width) >> hsub) *
- s->line_step[planes[i]] +
- (s->y >> vsub) * frame->linesize[planes[i]];
+ s->draw.pixelstep[planes[i]] +
+ ((s->h - s->y - frame->height) >> vsub) * frame->linesize[planes[i]];
- if (frame->linesize[planes[i]] < (s->w >> hsub) * s->line_step[planes[i]])
+ if (frame->linesize[planes[i]] < (s->w >> hsub) * s->draw.pixelstep[planes[i]])
return 1;
if (start - buf->data < req_start ||
(buf->data + buf->size) - end < req_end)
return 1;
-#define SIGN(x) ((x) > 0 ? 1 : -1)
for (j = 0; j < FF_ARRAY_ELEMS(planes) && planes[j] >= 0; j++) {
- int hsub1 = (planes[j] == 1 || planes[j] == 2) ? s->hsub : 0;
+ int vsub1 = s->draw.vsub[planes[j]];
uint8_t *start1 = frame->data[planes[j]];
- uint8_t *end1 = start1 + (frame->height >> hsub1) *
+ uint8_t *end1 = start1 + (frame->height >> vsub1) *
frame->linesize[planes[j]];
if (i == j)
continue;
- if (SIGN(start - end1) != SIGN(start - end1 - req_start) ||
- SIGN(end - start1) != SIGN(end - start1 + req_end))
+ if (FFSIGN(start - end1) != FFSIGN(start - end1 - req_start) ||
+ FFSIGN(end - start1) != FFSIGN(end - start1 + req_end))
return 1;
}
}
@@ -334,7 +282,7 @@ static int frame_needs_copy(PadContext *s, AVFrame *frame)
if (!av_frame_is_writable(frame))
return 1;
- for (i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++)
+ for (i = 0; i < 4 && frame->buf[i]; i++)
if (buffer_needs_copy(s, frame, frame->buf[i]))
return 1;
return 0;
@@ -361,41 +309,40 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
int i;
out = in;
- for (i = 0; i < FF_ARRAY_ELEMS(out->data) && out->data[i]; i++) {
- int hsub = (i == 1 || i == 2) ? s->hsub : 0;
- int vsub = (i == 1 || i == 2) ? s->vsub : 0;
- out->data[i] -= (s->x >> hsub) * s->line_step[i] +
+ for (i = 0; i < 4 && out->data[i] && out->linesize[i]; i++) {
+ int hsub = s->draw.hsub[i];
+ int vsub = s->draw.vsub[i];
+ out->data[i] -= (s->x >> hsub) * s->draw.pixelstep[i] +
(s->y >> vsub) * out->linesize[i];
}
}
/* top bar */
if (s->y) {
- ff_draw_rectangle(out->data, out->linesize,
- s->line, s->line_step, s->hsub, s->vsub,
+ ff_fill_rectangle(&s->draw, &s->color,
+ out->data, out->linesize,
0, 0, s->w, s->y);
}
/* bottom bar */
if (s->h > s->y + s->in_h) {
- ff_draw_rectangle(out->data, out->linesize,
- s->line, s->line_step, s->hsub, s->vsub,
+ ff_fill_rectangle(&s->draw, &s->color,
+ out->data, out->linesize,
0, s->y + s->in_h, s->w, s->h - s->y - s->in_h);
}
/* left border */
- ff_draw_rectangle(out->data, out->linesize, s->line, s->line_step,
- s->hsub, s->vsub, 0, s->y, s->x, in->height);
+ ff_fill_rectangle(&s->draw, &s->color, out->data, out->linesize,
+ 0, s->y, s->x, in->height);
if (needs_copy) {
- ff_copy_rectangle(out->data, out->linesize, in->data, in->linesize,
- s->line_step, s->hsub, s->vsub,
- s->x, s->y, 0, in->width, in->height);
+ ff_copy_rectangle2(&s->draw,
+ out->data, out->linesize, in->data, in->linesize,
+ s->x, s->y, 0, 0, in->width, in->height);
}
/* right border */
- ff_draw_rectangle(out->data, out->linesize,
- s->line, s->line_step, s->hsub, s->vsub,
+ ff_fill_rectangle(&s->draw, &s->color, out->data, out->linesize,
s->x + s->in_w, s->y, s->w - s->x - s->in_w,
in->height);
@@ -408,24 +355,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
#define OFFSET(x) offsetof(PadContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "width", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
- { "height", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
- { "x", "Horizontal position of the left edge of the input video in the "
- "output video", OFFSET(x_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
- { "y", "Vertical position of the top edge of the input video in the "
- "output video", OFFSET(y_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
- { "color", "Color of the padded area", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
- { NULL },
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption pad_options[] = {
+ { "width", "set the pad area width expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "w", "set the pad area width expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "height", "set the pad area height expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "h", "set the pad area height expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "x", "set the x offset expression for the input image position", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "y", "set the y offset expression for the input image position", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "color", "set the color of the padded area border", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS },
+ { NULL }
};
-static const AVClass pad_class = {
- .class_name = "pad",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(pad);
static const AVFilterPad avfilter_vf_pad_inputs[] = {
{
@@ -449,15 +392,10 @@ static const AVFilterPad avfilter_vf_pad_outputs[] = {
AVFilter ff_vf_pad = {
.name = "pad",
- .description = NULL_IF_CONFIG_SMALL("Pad input image to width:height[:x:y[:color]] (default x and y: 0, default color: black)."),
-
+ .description = NULL_IF_CONFIG_SMALL("Pad the input video."),
.priv_size = sizeof(PadContext),
.priv_class = &pad_class,
- .init = init,
- .uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_pad_inputs,
-
- .outputs = avfilter_vf_pad_outputs,
+ .inputs = avfilter_vf_pad_inputs,
+ .outputs = avfilter_vf_pad_outputs,
};
diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c
new file mode 100644
index 0000000000..4b49058b35
--- /dev/null
+++ b/libavfilter/vf_palettegen.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2015 Stupeflix
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Generate one palette for a whole video stream.
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/qsort.h"
+#include "avfilter.h"
+#include "internal.h"
+
+/* Reference a color and how much it's used */
+struct color_ref {
+ uint32_t color;
+ uint64_t count;
+};
+
+/* Store a range of colors */
+struct range_box {
+ uint32_t color; // average color
+ int64_t variance; // overall variance of the box (how much the colors are spread)
+ int start; // index in PaletteGenContext->refs
+ int len; // number of referenced colors
+ int sorted_by; // whether range of colors is sorted by red (0), green (1) or blue (2)
+};
+
+struct hist_node {
+ struct color_ref *entries;
+ int nb_entries;
+};
+
+enum {
+ STATS_MODE_ALL_FRAMES,
+ STATS_MODE_DIFF_FRAMES,
+ NB_STATS_MODE
+};
+
+#define NBITS 5
+#define HIST_SIZE (1<<(3*NBITS))
+
+typedef struct {
+ const AVClass *class;
+
+ int max_colors;
+ int reserve_transparent;
+ int stats_mode;
+
+ AVFrame *prev_frame; // previous frame used for the diff stats_mode
+ struct hist_node histogram[HIST_SIZE]; // histogram/hashtable of the colors
+ struct color_ref **refs; // references of all the colors used in the stream
+ int nb_refs; // number of color references (or number of different colors)
+ struct range_box boxes[256]; // define the segmentation of the colorspace (the final palette)
+ int nb_boxes; // number of boxes (increase will segmenting them)
+ int palette_pushed; // if the palette frame is pushed into the outlink or not
+} PaletteGenContext;
+
+#define OFFSET(x) offsetof(PaletteGenContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption palettegen_options[] = {
+ { "max_colors", "set the maximum number of colors to use in the palette", OFFSET(max_colors), AV_OPT_TYPE_INT, {.i64=256}, 4, 256, FLAGS },
+ { "reserve_transparent", "reserve a palette entry for transparency", OFFSET(reserve_transparent), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { "stats_mode", "set statistics mode", OFFSET(stats_mode), AV_OPT_TYPE_INT, {.i64=STATS_MODE_ALL_FRAMES}, 0, NB_STATS_MODE, FLAGS, "mode" },
+ { "full", "compute full frame histograms", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_ALL_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "diff", "compute histograms only for the part that differs from previous frame", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_DIFF_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(palettegen);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat in_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+ static const enum AVPixelFormat out_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+ AVFilterFormats *in = ff_make_format_list(in_fmts);
+ AVFilterFormats *out = ff_make_format_list(out_fmts);
+ if (!in || !out) {
+ av_freep(&in);
+ av_freep(&out);
+ return AVERROR(ENOMEM);
+ }
+ ff_formats_ref(in, &ctx->inputs[0]->out_formats);
+ ff_formats_ref(out, &ctx->outputs[0]->in_formats);
+ return 0;
+}
+
+typedef int (*cmp_func)(const void *, const void *);
+
+#define DECLARE_CMP_FUNC(name, pos) \
+static int cmp_##name(const void *pa, const void *pb) \
+{ \
+ const struct color_ref * const *a = pa; \
+ const struct color_ref * const *b = pb; \
+ return ((*a)->color >> (8 * (2 - (pos))) & 0xff) \
+ - ((*b)->color >> (8 * (2 - (pos))) & 0xff); \
+}
+
+DECLARE_CMP_FUNC(r, 0)
+DECLARE_CMP_FUNC(g, 1)
+DECLARE_CMP_FUNC(b, 2)
+
+static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
+
+/**
+ * Simple color comparison for sorting the final palette
+ */
+static int cmp_color(const void *a, const void *b)
+{
+ const struct range_box *box1 = a;
+ const struct range_box *box2 = b;
+ return box1->color - box2->color;
+}
+
+static av_always_inline int diff(const uint32_t a, const uint32_t b)
+{
+ const uint8_t c1[] = {a >> 16 & 0xff, a >> 8 & 0xff, a & 0xff};
+ const uint8_t c2[] = {b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff};
+ const int dr = c1[0] - c2[0];
+ const int dg = c1[1] - c2[1];
+ const int db = c1[2] - c2[2];
+ return dr*dr + dg*dg + db*db;
+}
+
+/**
+ * Find the next box to split: pick the one with the highest variance
+ */
+static int get_next_box_id_to_split(PaletteGenContext *s)
+{
+ int box_id, i, best_box_id = -1;
+ int64_t max_variance = -1;
+
+ if (s->nb_boxes == s->max_colors - s->reserve_transparent)
+ return -1;
+
+ for (box_id = 0; box_id < s->nb_boxes; box_id++) {
+ struct range_box *box = &s->boxes[box_id];
+
+ if (s->boxes[box_id].len >= 2) {
+
+ if (box->variance == -1) {
+ int64_t variance = 0;
+
+ for (i = 0; i < box->len; i++) {
+ const struct color_ref *ref = s->refs[box->start + i];
+ variance += diff(ref->color, box->color) * ref->count;
+ }
+ box->variance = variance;
+ }
+ if (box->variance > max_variance) {
+ best_box_id = box_id;
+ max_variance = box->variance;
+ }
+ } else {
+ box->variance = -1;
+ }
+ }
+ return best_box_id;
+}
+
+/**
+ * Get the 32-bit average color for the range of RGB colors enclosed in the
+ * specified box. Takes into account the weight of each color.
+ */
+static uint32_t get_avg_color(struct color_ref * const *refs,
+ const struct range_box *box)
+{
+ int i;
+ const int n = box->len;
+ uint64_t r = 0, g = 0, b = 0, div = 0;
+
+ for (i = 0; i < n; i++) {
+ const struct color_ref *ref = refs[box->start + i];
+ r += (ref->color >> 16 & 0xff) * ref->count;
+ g += (ref->color >> 8 & 0xff) * ref->count;
+ b += (ref->color & 0xff) * ref->count;
+ div += ref->count;
+ }
+
+ r = r / div;
+ g = g / div;
+ b = b / div;
+
+ return 0xffU<<24 | r<<16 | g<<8 | b;
+}
+
+/**
+ * Split given box in two at position n. The original box becomes the left part
+ * of the split, and the new index box is the right part.
+ */
+static void split_box(PaletteGenContext *s, struct range_box *box, int n)
+{
+ struct range_box *new_box = &s->boxes[s->nb_boxes++];
+ new_box->start = n + 1;
+ new_box->len = box->start + box->len - new_box->start;
+ new_box->sorted_by = box->sorted_by;
+ box->len -= new_box->len;
+
+ av_assert0(box->len >= 1);
+ av_assert0(new_box->len >= 1);
+
+ box->color = get_avg_color(s->refs, box);
+ new_box->color = get_avg_color(s->refs, new_box);
+ box->variance = -1;
+ new_box->variance = -1;
+}
+
+/**
+ * Write the palette into the output frame.
+ */
+static void write_palette(AVFilterContext *ctx, AVFrame *out)
+{
+ const PaletteGenContext *s = ctx->priv;
+ int x, y, box_id = 0;
+ uint32_t *pal = (uint32_t *)out->data[0];
+ const int pal_linesize = out->linesize[0] >> 2;
+ uint32_t last_color = 0;
+
+ for (y = 0; y < out->height; y++) {
+ for (x = 0; x < out->width; x++) {
+ if (box_id < s->nb_boxes) {
+ pal[x] = s->boxes[box_id++].color;
+ if ((x || y) && pal[x] == last_color)
+ av_log(ctx, AV_LOG_WARNING, "Dupped color: %08X\n", pal[x]);
+ last_color = pal[x];
+ } else {
+ pal[x] = 0xff000000; // pad with black
+ }
+ }
+ pal += pal_linesize;
+ }
+
+ if (s->reserve_transparent) {
+ av_assert0(s->nb_boxes < 256);
+ pal[out->width - pal_linesize - 1] = 0x0000ff00; // add a green transparent color
+ }
+}
+
+/**
+ * Crawl the histogram to get all the defined colors, and create a linear list
+ * of them (each color reference entry is a pointer to the value in the
+ * histogram/hash table).
+ */
+static struct color_ref **load_color_refs(const struct hist_node *hist, int nb_refs)
+{
+ int i, j, k = 0;
+ struct color_ref **refs = av_malloc_array(nb_refs, sizeof(*refs));
+
+ if (!refs)
+ return NULL;
+
+ for (j = 0; j < HIST_SIZE; j++) {
+ const struct hist_node *node = &hist[j];
+
+ for (i = 0; i < node->nb_entries; i++)
+ refs[k++] = &node->entries[i];
+ }
+
+ return refs;
+}
+
+static double set_colorquant_ratio_meta(AVFrame *out, int nb_out, int nb_in)
+{
+ char buf[32];
+ const double ratio = (double)nb_out / nb_in;
+ snprintf(buf, sizeof(buf), "%f", ratio);
+ av_dict_set(&out->metadata, "lavfi.color_quant_ratio", buf, 0);
+ return ratio;
+}
+
+/**
+ * Main function implementing the Median Cut Algorithm defined by Paul Heckbert
+ * in Color Image Quantization for Frame Buffer Display (1982)
+ */
+static AVFrame *get_palette_frame(AVFilterContext *ctx)
+{
+ AVFrame *out;
+ PaletteGenContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ double ratio;
+ int box_id = 0;
+ struct range_box *box;
+
+ /* reference only the used colors from histogram */
+ s->refs = load_color_refs(s->histogram, s->nb_refs);
+ if (!s->refs) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to allocate references for %d different colors\n", s->nb_refs);
+ return NULL;
+ }
+
+ /* create the palette frame */
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return NULL;
+ out->pts = 0;
+
+ /* set first box for 0..nb_refs */
+ box = &s->boxes[box_id];
+ box->len = s->nb_refs;
+ box->sorted_by = -1;
+ box->color = get_avg_color(s->refs, box);
+ box->variance = -1;
+ s->nb_boxes = 1;
+
+ while (box && box->len > 1) {
+ int i, rr, gr, br, longest;
+ uint64_t median, box_weight = 0;
+
+ /* compute the box weight (sum all the weights of the colors in the
+ * range) and its boundings */
+ uint8_t min[3] = {0xff, 0xff, 0xff};
+ uint8_t max[3] = {0x00, 0x00, 0x00};
+ for (i = box->start; i < box->start + box->len; i++) {
+ const struct color_ref *ref = s->refs[i];
+ const uint32_t rgb = ref->color;
+ const uint8_t r = rgb >> 16 & 0xff, g = rgb >> 8 & 0xff, b = rgb & 0xff;
+ min[0] = FFMIN(r, min[0]), max[0] = FFMAX(r, max[0]);
+ min[1] = FFMIN(g, min[1]), max[1] = FFMAX(g, max[1]);
+ min[2] = FFMIN(b, min[2]), max[2] = FFMAX(b, max[2]);
+ box_weight += ref->count;
+ }
+
+ /* define the axis to sort by according to the widest range of colors */
+ rr = max[0] - min[0];
+ gr = max[1] - min[1];
+ br = max[2] - min[2];
+ longest = 1; // pick green by default (the color the eye is the most sensitive to)
+ if (br >= rr && br >= gr) longest = 2;
+ if (rr >= gr && rr >= br) longest = 0;
+ if (gr >= rr && gr >= br) longest = 1; // prefer green again
+
+ av_dlog(ctx, "box #%02X [%6d..%-6d] (%6d) w:%-6"PRIu64" ranges:[%2x %2x %2x] sort by %c (already sorted:%c) ",
+ box_id, box->start, box->start + box->len - 1, box->len, box_weight,
+ rr, gr, br, "rgb"[longest], box->sorted_by == longest ? 'y':'n');
+
+ /* sort the range by its longest axis if it's not already sorted */
+ if (box->sorted_by != longest) {
+ cmp_func cmpf = cmp_funcs[longest];
+ AV_QSORT(&s->refs[box->start], box->len, const struct color_ref *, cmpf);
+ box->sorted_by = longest;
+ }
+
+ /* locate the median where to split */
+ median = (box_weight + 1) >> 1;
+ box_weight = 0;
+ /* if you have 2 boxes, the maximum is actually #0: you must have at
+ * least 1 color on each side of the split, hence the -2 */
+ for (i = box->start; i < box->start + box->len - 2; i++) {
+ box_weight += s->refs[i]->count;
+ if (box_weight > median)
+ break;
+ }
+ av_dlog(ctx, "split @ i=%-6d with w=%-6"PRIu64" (target=%6"PRIu64")\n", i, box_weight, median);
+ split_box(s, box, i);
+
+ box_id = get_next_box_id_to_split(s);
+ box = box_id >= 0 ? &s->boxes[box_id] : NULL;
+ }
+
+ ratio = set_colorquant_ratio_meta(out, s->nb_boxes, s->nb_refs);
+ av_log(ctx, AV_LOG_INFO, "%d%s colors generated out of %d colors; ratio=%f\n",
+ s->nb_boxes, s->reserve_transparent ? "(+1)" : "", s->nb_refs, ratio);
+
+ qsort(s->boxes, s->nb_boxes, sizeof(*s->boxes), cmp_color);
+
+ write_palette(ctx, out);
+
+ return out;
+}
+
+/**
+ * Hashing function for the color.
+ * It keeps the NBITS least significant bit of each component to make it
+ * "random" even if the scene doesn't have much different colors.
+ */
+static inline unsigned color_hash(uint32_t color)
+{
+ const uint8_t r = color >> 16 & ((1<<NBITS)-1);
+ const uint8_t g = color >> 8 & ((1<<NBITS)-1);
+ const uint8_t b = color & ((1<<NBITS)-1);
+ return r<<(NBITS*2) | g<<NBITS | b;
+}
+
+/**
+ * Locate the color in the hash table and increment its counter.
+ */
+static int color_inc(struct hist_node *hist, uint32_t color)
+{
+ int i;
+ const unsigned hash = color_hash(color);
+ struct hist_node *node = &hist[hash];
+ struct color_ref *e;
+
+ for (i = 0; i < node->nb_entries; i++) {
+ e = &node->entries[i];
+ if (e->color == color) {
+ e->count++;
+ return 0;
+ }
+ }
+
+ e = av_dynarray2_add((void**)&node->entries, &node->nb_entries,
+ sizeof(*node->entries), NULL);
+ if (!e)
+ return AVERROR(ENOMEM);
+ e->color = color;
+ e->count = 1;
+ return 1;
+}
+
+/**
+ * Update histogram when pixels differ from previous frame.
+ */
+static int update_histogram_diff(struct hist_node *hist,
+ const AVFrame *f1, const AVFrame *f2)
+{
+ int x, y, ret, nb_diff_colors = 0;
+
+ for (y = 0; y < f1->height; y++) {
+ const uint32_t *p = (const uint32_t *)(f1->data[0] + y*f1->linesize[0]);
+ const uint32_t *q = (const uint32_t *)(f2->data[0] + y*f2->linesize[0]);
+
+ for (x = 0; x < f1->width; x++) {
+ if (p[x] == q[x])
+ continue;
+ ret = color_inc(hist, p[x]);
+ if (ret < 0)
+ return ret;
+ nb_diff_colors += ret;
+ }
+ }
+ return nb_diff_colors;
+}
+
+/**
+ * Simple histogram of the frame.
+ */
+static int update_histogram_frame(struct hist_node *hist, const AVFrame *f)
+{
+ int x, y, ret, nb_diff_colors = 0;
+
+ for (y = 0; y < f->height; y++) {
+ const uint32_t *p = (const uint32_t *)(f->data[0] + y*f->linesize[0]);
+
+ for (x = 0; x < f->width; x++) {
+ ret = color_inc(hist, p[x]);
+ if (ret < 0)
+ return ret;
+ nb_diff_colors += ret;
+ }
+ }
+ return nb_diff_colors;
+}
+
+/**
+ * Update the histogram for each passing frame. No frame will be pushed here.
+ */
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ PaletteGenContext *s = ctx->priv;
+ const int ret = s->prev_frame ? update_histogram_diff(s->histogram, s->prev_frame, in)
+ : update_histogram_frame(s->histogram, in);
+
+ if (ret > 0)
+ s->nb_refs += ret;
+
+ if (s->stats_mode == STATS_MODE_DIFF_FRAMES) {
+ av_frame_free(&s->prev_frame);
+ s->prev_frame = in;
+ } else {
+ av_frame_free(&in);
+ }
+
+ return ret;
+}
+
+/**
+ * Returns only one frame at the end containing the full palette.
+ */
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ PaletteGenContext *s = ctx->priv;
+ int r;
+
+ r = ff_request_frame(inlink);
+ if (r == AVERROR_EOF && !s->palette_pushed && s->nb_refs) {
+ r = ff_filter_frame(outlink, get_palette_frame(ctx));
+ s->palette_pushed = 1;
+ return r;
+ }
+ return r;
+}
+
+/**
+ * The output is one simple 16x16 squared-pixels palette.
+ */
+static int config_output(AVFilterLink *outlink)
+{
+ outlink->w = outlink->h = 16;
+ outlink->sample_aspect_ratio = av_make_q(1, 1);
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i;
+ PaletteGenContext *s = ctx->priv;
+
+ for (i = 0; i < HIST_SIZE; i++)
+ av_freep(&s->histogram[i].entries);
+ av_freep(&s->refs);
+ av_frame_free(&s->prev_frame);
+}
+
+static const AVFilterPad palettegen_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad palettegen_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_palettegen = {
+ .name = "palettegen",
+ .description = NULL_IF_CONFIG_SMALL("Find the optimal palette for a given stream."),
+ .priv_size = sizeof(PaletteGenContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = palettegen_inputs,
+ .outputs = palettegen_outputs,
+ .priv_class = &palettegen_class,
+};
diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
new file mode 100644
index 0000000000..8835d8b21c
--- /dev/null
+++ b/libavfilter/vf_paletteuse.c
@@ -0,0 +1,1071 @@
+/*
+ * Copyright (c) 2015 Stupeflix
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Use a palette to downsample an input video stream.
+ */
+
+#include "libavutil/bprint.h"
+#include "libavutil/opt.h"
+#include "libavutil/qsort.h"
+#include "dualinput.h"
+#include "avfilter.h"
+
+enum dithering_mode {
+ DITHERING_NONE,
+ DITHERING_BAYER,
+ DITHERING_HECKBERT,
+ DITHERING_FLOYD_STEINBERG,
+ DITHERING_SIERRA2,
+ DITHERING_SIERRA2_4A,
+ NB_DITHERING
+};
+
+enum color_search_method {
+ COLOR_SEARCH_NNS_ITERATIVE,
+ COLOR_SEARCH_NNS_RECURSIVE,
+ COLOR_SEARCH_BRUTEFORCE,
+ NB_COLOR_SEARCHES
+};
+
+enum diff_mode {
+ DIFF_MODE_NONE,
+ DIFF_MODE_RECTANGLE,
+ NB_DIFF_MODE
+};
+
+struct color_node {
+ uint8_t val[3];
+ uint8_t palette_id;
+ int split;
+ int left_id, right_id;
+};
+
+#define NBITS 5
+#define CACHE_SIZE (1<<(3*NBITS))
+
+struct cached_color {
+ uint32_t color;
+ uint8_t pal_entry;
+};
+
+struct cache_node {
+ struct cached_color *entries;
+ int nb_entries;
+};
+
+struct PaletteUseContext;
+
+typedef int (*set_frame_func)(struct PaletteUseContext *s, AVFrame *out, AVFrame *in,
+ int x_start, int y_start, int width, int height);
+
+typedef struct PaletteUseContext {
+ const AVClass *class;
+ FFDualInputContext dinput;
+ struct cache_node cache[CACHE_SIZE]; /* lookup cache */
+ struct color_node map[AVPALETTE_COUNT]; /* 3D-Tree (KD-Tree with K=3) for reverse colormap */
+ uint32_t palette[AVPALETTE_COUNT];
+ int palette_loaded;
+ int dither;
+ set_frame_func set_frame;
+ int bayer_scale;
+ int ordered_dither[8*8];
+ int diff_mode;
+ AVFrame *last_in;
+ AVFrame *last_out;
+
+ /* debug options */
+ char *dot_filename;
+ int color_search_method;
+ int calc_mean_err;
+ uint64_t total_mean_err;
+ int debug_accuracy;
+} PaletteUseContext;
+
+#define OFFSET(x) offsetof(PaletteUseContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption paletteuse_options[] = {
+ { "dither", "select dithering mode", OFFSET(dither), AV_OPT_TYPE_INT, {.i64=DITHERING_SIERRA2_4A}, 0, NB_DITHERING-1, FLAGS, "dithering_mode" },
+ { "bayer", "ordered 8x8 bayer dithering (deterministic)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_BAYER}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
+ { "heckbert", "dithering as defined by Paul Heckbert in 1982 (simple error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_HECKBERT}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
+ { "floyd_steinberg", "Floyd and Steingberg dithering (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_FLOYD_STEINBERG}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
+ { "sierra2", "Frankie Sierra dithering v2 (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_SIERRA2}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
+ { "sierra2_4a", "Frankie Sierra dithering v2 \"Lite\" (error diffusion)", 0, AV_OPT_TYPE_CONST, {.i64=DITHERING_SIERRA2_4A}, INT_MIN, INT_MAX, FLAGS, "dithering_mode" },
+ { "bayer_scale", "set scale for bayer dithering", OFFSET(bayer_scale), AV_OPT_TYPE_INT, {.i64=2}, 0, 5, FLAGS },
+ { "diff_mode", "set frame difference mode", OFFSET(diff_mode), AV_OPT_TYPE_INT, {.i64=DIFF_MODE_NONE}, 0, NB_DIFF_MODE-1, FLAGS, "diff_mode" },
+ { "rectangle", "process smallest different rectangle", 0, AV_OPT_TYPE_CONST, {.i64=DIFF_MODE_RECTANGLE}, INT_MIN, INT_MAX, FLAGS, "diff_mode" },
+
+ /* following are the debug options, not part of the official API */
+ { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "color_search", "set reverse colormap color search method", OFFSET(color_search_method), AV_OPT_TYPE_INT, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, 0, NB_COLOR_SEARCHES-1, FLAGS, "search" },
+ { "nns_iterative", "iterative search", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_ITERATIVE}, INT_MIN, INT_MAX, FLAGS, "search" },
+ { "nns_recursive", "recursive search", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_NNS_RECURSIVE}, INT_MIN, INT_MAX, FLAGS, "search" },
+ { "bruteforce", "brute-force into the palette", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE}, INT_MIN, INT_MAX, FLAGS, "search" },
+ { "mean_err", "compute and print mean error", OFFSET(calc_mean_err), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS },
+ { "debug_accuracy", "test color search accuracy", OFFSET(debug_accuracy), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(paletteuse);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat in_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+ static const enum AVPixelFormat inpal_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+ static const enum AVPixelFormat out_fmts[] = {AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE};
+ AVFilterFormats *in = ff_make_format_list(in_fmts);
+ AVFilterFormats *inpal = ff_make_format_list(inpal_fmts);
+ AVFilterFormats *out = ff_make_format_list(out_fmts);
+ if (!in || !inpal || !out) {
+ av_freep(&in);
+ av_freep(&inpal);
+ av_freep(&out);
+ return AVERROR(ENOMEM);
+ }
+ ff_formats_ref(in, &ctx->inputs[0]->out_formats);
+ ff_formats_ref(inpal, &ctx->inputs[1]->out_formats);
+ ff_formats_ref(out, &ctx->outputs[0]->in_formats);
+ return 0;
+}
+
+static av_always_inline int dither_color(uint32_t px, int er, int eg, int eb, int scale, int shift)
+{
+ return av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<<shift))) << 16
+ | av_clip_uint8((px >> 8 & 0xff) + ((eg * scale) / (1<<shift))) << 8
+ | av_clip_uint8((px & 0xff) + ((eb * scale) / (1<<shift)));
+}
+
+static av_always_inline int diff(const uint8_t *c1, const uint8_t *c2)
+{
+ // XXX: try L*a*b with CIE76 (dL*dL + da*da + db*db)
+ const int dr = c1[0] - c2[0];
+ const int dg = c1[1] - c2[1];
+ const int db = c1[2] - c2[2];
+ return dr*dr + dg*dg + db*db;
+}
+
+static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *rgb)
+{
+ int i, pal_id = -1, min_dist = INT_MAX;
+
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t c = palette[i];
+
+ if ((c & 0xff000000) == 0xff000000) { // ignore transparent entry
+ const uint8_t palrgb[] = {
+ palette[i]>>16 & 0xff,
+ palette[i]>> 8 & 0xff,
+ palette[i] & 0xff,
+ };
+ const int d = diff(palrgb, rgb);
+ if (d < min_dist) {
+ pal_id = i;
+ min_dist = d;
+ }
+ }
+ }
+ return pal_id;
+}
+
+/* Recursive form, simpler but a bit slower. Kept for reference. */
+struct nearest_color {
+ int node_pos;
+ int dist_sqd;
+};
+
+static void colormap_nearest_node(const struct color_node *map,
+ const int node_pos,
+ const uint8_t *target,
+ struct nearest_color *nearest)
+{
+ const struct color_node *kd = map + node_pos;
+ const int s = kd->split;
+ int dx, nearer_kd_id, further_kd_id;
+ const uint8_t *current = kd->val;
+ const int current_to_target = diff(target, current);
+
+ if (current_to_target < nearest->dist_sqd) {
+ nearest->node_pos = node_pos;
+ nearest->dist_sqd = current_to_target;
+ }
+
+ if (kd->left_id != -1 || kd->right_id != -1) {
+ dx = target[s] - current[s];
+
+ if (dx <= 0) nearer_kd_id = kd->left_id, further_kd_id = kd->right_id;
+ else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
+
+ if (nearer_kd_id != -1)
+ colormap_nearest_node(map, nearer_kd_id, target, nearest);
+
+ if (further_kd_id != -1 && dx*dx < nearest->dist_sqd)
+ colormap_nearest_node(map, further_kd_id, target, nearest);
+ }
+}
+
+static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb)
+{
+ struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1};
+ colormap_nearest_node(node, 0, rgb, &res);
+ return node[res.node_pos].palette_id;
+}
+
+struct stack_node {
+ int color_id;
+ int dx2;
+};
+
+static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target)
+{
+ int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
+ struct stack_node nodes[16];
+ struct stack_node *node = &nodes[0];
+
+ for (;;) {
+
+ const struct color_node *kd = &root[cur_color_id];
+ const uint8_t *current = kd->val;
+ const int current_to_target = diff(target, current);
+
+ /* Compare current color node to the target and update our best node if
+ * it's actually better. */
+ if (current_to_target < best_dist) {
+ best_node_id = cur_color_id;
+ if (!current_to_target)
+ goto end; // exact match, we can return immediately
+ best_dist = current_to_target;
+ }
+
+ /* Check if it's not a leaf */
+ if (kd->left_id != -1 || kd->right_id != -1) {
+ const int split = kd->split;
+ const int dx = target[split] - current[split];
+ int nearer_kd_id, further_kd_id;
+
+ /* Define which side is the most interesting. */
+ if (dx <= 0) nearer_kd_id = kd->left_id, further_kd_id = kd->right_id;
+ else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
+
+ if (nearer_kd_id != -1) {
+ if (further_kd_id != -1) {
+ /* Here, both paths are defined, so we push a state for
+ * when we are going back. */
+ node->color_id = further_kd_id;
+ node->dx2 = dx*dx;
+ pos++;
+ node++;
+ }
+ /* We can now update current color with the most probable path
+ * (no need to create a state since there is nothing to save
+ * anymore). */
+ cur_color_id = nearer_kd_id;
+ continue;
+ } else if (dx*dx < best_dist) {
+ /* The nearest path isn't available, so there is only one path
+ * possible and it's the least probable. We enter it only if the
+ * distance from the current point to the hyper rectangle is
+ * less than our best distance. */
+ cur_color_id = further_kd_id;
+ continue;
+ }
+ }
+
+ /* Unstack as much as we can, typically as long as the least probable
+ * branch aren't actually probable. */
+ do {
+ if (--pos < 0)
+ goto end;
+ node--;
+ } while (node->dx2 >= best_dist);
+
+ /* We got a node where the least probable branch might actually contain
+ * a relevant color. */
+ cur_color_id = node->color_id;
+ }
+
+end:
+ return root[best_node_id].palette_id;
+}
+
+#define COLORMAP_NEAREST(search, palette, root, target) \
+ search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target) : \
+ search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target) : \
+ colormap_nearest_bruteforce(palette, target)
+
+/**
+ * Check if the requested color is in the cache already. If not, find it in the
+ * color tree and cache it.
+ * Note: r, g, and b are the component of c but are passed as well to avoid
+ * recomputing them (they are generally computed by the caller for other uses).
+ */
+static av_always_inline int color_get(struct cache_node *cache, uint32_t color,
+ uint8_t r, uint8_t g, uint8_t b,
+ const struct color_node *map,
+ const uint32_t *palette,
+ const enum color_search_method search_method)
+{
+ int i;
+ const uint8_t rgb[] = {r, g, b};
+ const uint8_t rhash = r & ((1<<NBITS)-1);
+ const uint8_t ghash = g & ((1<<NBITS)-1);
+ const uint8_t bhash = b & ((1<<NBITS)-1);
+ const unsigned hash = rhash<<(NBITS*2) | ghash<<NBITS | bhash;
+ struct cache_node *node = &cache[hash];
+ struct cached_color *e;
+
+ for (i = 0; i < node->nb_entries; i++) {
+ e = &node->entries[i];
+ if (e->color == color)
+ return e->pal_entry;
+ }
+
+ e = av_dynarray2_add((void**)&node->entries, &node->nb_entries,
+ sizeof(*node->entries), NULL);
+ if (!e)
+ return AVERROR(ENOMEM);
+ e->color = color;
+ e->pal_entry = COLORMAP_NEAREST(search_method, palette, map, rgb);
+ return e->pal_entry;
+}
+
+static av_always_inline int get_dst_color_err(struct cache_node *cache,
+ uint32_t c, const struct color_node *map,
+ const uint32_t *palette,
+ int *er, int *eg, int *eb,
+ const enum color_search_method search_method)
+{
+ const uint8_t r = c >> 16 & 0xff;
+ const uint8_t g = c >> 8 & 0xff;
+ const uint8_t b = c & 0xff;
+ const int dstx = color_get(cache, c, r, g, b, map, palette, search_method);
+ const uint32_t dstc = palette[dstx];
+ *er = r - (dstc >> 16 & 0xff);
+ *eg = g - (dstc >> 8 & 0xff);
+ *eb = b - (dstc & 0xff);
+ return dstx;
+}
+
+static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFrame *in,
+ int x_start, int y_start, int w, int h,
+ enum dithering_mode dither,
+ const enum color_search_method search_method)
+{
+ int x, y;
+ const struct color_node *map = s->map;
+ struct cache_node *cache = s->cache;
+ const uint32_t *palette = s->palette;
+ const int src_linesize = in ->linesize[0] >> 2;
+ const int dst_linesize = out->linesize[0];
+ uint32_t *src = ((uint32_t *)in ->data[0]) + y_start*src_linesize;
+ uint8_t *dst = out->data[0] + y_start*dst_linesize;
+
+ w += x_start;
+ h += y_start;
+
+ for (y = y_start; y < h; y++) {
+ for (x = x_start; x < w; x++) {
+ int er, eg, eb;
+
+ if (dither == DITHERING_BAYER) {
+ const int d = s->ordered_dither[(y & 7)<<3 | (x & 7)];
+ const uint8_t r8 = src[x] >> 16 & 0xff;
+ const uint8_t g8 = src[x] >> 8 & 0xff;
+ const uint8_t b8 = src[x] & 0xff;
+ const uint8_t r = av_clip_uint8(r8 + d);
+ const uint8_t g = av_clip_uint8(g8 + d);
+ const uint8_t b = av_clip_uint8(b8 + d);
+ const uint32_t c = r<<16 | g<<8 | b;
+ const int color = color_get(cache, c, r, g, b, map, palette, search_method);
+
+ if (color < 0)
+ return color;
+ dst[x] = color;
+
+ } else if (dither == DITHERING_HECKBERT) {
+ const int right = x < w - 1, down = y < h - 1;
+ const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
+
+ if (color < 0)
+ return color;
+ dst[x] = color;
+
+ if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 3, 3);
+ if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 3, 3);
+ if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 2, 3);
+
+ } else if (dither == DITHERING_FLOYD_STEINBERG) {
+ const int right = x < w - 1, down = y < h - 1, left = x > x_start;
+ const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
+
+ if (color < 0)
+ return color;
+ dst[x] = color;
+
+ if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 7, 4);
+ if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 3, 4);
+ if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 5, 4);
+ if (right && down) src[src_linesize + x + 1] = dither_color(src[src_linesize + x + 1], er, eg, eb, 1, 4);
+
+ } else if (dither == DITHERING_SIERRA2) {
+ const int right = x < w - 1, down = y < h - 1, left = x > x_start;
+ const int right2 = x < w - 2, left2 = x > x_start + 1;
+ const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
+
+ if (color < 0)
+ return color;
+ dst[x] = color;
+
+ if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 4, 4);
+ if (right2) src[ x + 2] = dither_color(src[ x + 2], er, eg, eb, 3, 4);
+
+ if (down) {
+ if (left2) src[ src_linesize + x - 2] = dither_color(src[ src_linesize + x - 2], er, eg, eb, 1, 4);
+ if (left) src[ src_linesize + x - 1] = dither_color(src[ src_linesize + x - 1], er, eg, eb, 2, 4);
+ src[ src_linesize + x ] = dither_color(src[ src_linesize + x ], er, eg, eb, 3, 4);
+ if (right) src[ src_linesize + x + 1] = dither_color(src[ src_linesize + x + 1], er, eg, eb, 2, 4);
+ if (right2) src[ src_linesize + x + 2] = dither_color(src[ src_linesize + x + 2], er, eg, eb, 1, 4);
+ }
+
+ } else if (dither == DITHERING_SIERRA2_4A) {
+ const int right = x < w - 1, down = y < h - 1, left = x > x_start;
+ const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method);
+
+ if (color < 0)
+ return color;
+ dst[x] = color;
+
+ if (right) src[ x + 1] = dither_color(src[ x + 1], er, eg, eb, 2, 2);
+ if (left && down) src[src_linesize + x - 1] = dither_color(src[src_linesize + x - 1], er, eg, eb, 1, 2);
+ if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 1, 2);
+
+ } else {
+ const uint8_t r = src[x] >> 16 & 0xff;
+ const uint8_t g = src[x] >> 8 & 0xff;
+ const uint8_t b = src[x] & 0xff;
+ const int color = color_get(cache, src[x] & 0xffffff, r, g, b, map, palette, search_method);
+
+ if (color < 0)
+ return color;
+ dst[x] = color;
+ }
+ }
+ src += src_linesize;
+ dst += dst_linesize;
+ }
+ return 0;
+}
+
+#define INDENT 4
+static void disp_node(AVBPrint *buf,
+ const struct color_node *map,
+ int parent_id, int node_id,
+ int depth)
+{
+ const struct color_node *node = &map[node_id];
+ const uint32_t fontcolor = node->val[0] > 0x50 &&
+ node->val[1] > 0x50 &&
+ node->val[2] > 0x50 ? 0 : 0xffffff;
+ av_bprintf(buf, "%*cnode%d ["
+ "label=\"%c%02X%c%02X%c%02X%c\" "
+ "fillcolor=\"#%02x%02x%02x\" "
+ "fontcolor=\"#%06X\"]\n",
+ depth*INDENT, ' ', node->palette_id,
+ "[ "[node->split], node->val[0],
+ "][ "[node->split], node->val[1],
+ " ]["[node->split], node->val[2],
+ " ]"[node->split],
+ node->val[0], node->val[1], node->val[2],
+ fontcolor);
+ if (parent_id != -1)
+ av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ',
+ map[parent_id].palette_id, node->palette_id);
+ if (node->left_id != -1) disp_node(buf, map, node_id, node->left_id, depth + 1);
+ if (node->right_id != -1) disp_node(buf, map, node_id, node->right_id, depth + 1);
+}
+
+// debug_kdtree=kdtree.dot -> dot -Tpng kdtree.dot > kdtree.png
+static int disp_tree(const struct color_node *node, const char *fname)
+{
+ AVBPrint buf;
+ FILE *f = av_fopen_utf8(fname, "w");
+
+ if (!f) {
+ int ret = AVERROR(errno);
+ av_log(NULL, AV_LOG_ERROR, "Cannot open file '%s' for writing: %s\n",
+ fname, av_err2str(ret));
+ return ret;
+ }
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ av_bprintf(&buf, "digraph {\n");
+ av_bprintf(&buf, " node [style=filled fontsize=10 shape=box]\n");
+ disp_node(&buf, node, -1, 0, 0);
+ av_bprintf(&buf, "}\n");
+
+ fwrite(buf.str, 1, buf.len, f);
+ fclose(f);
+ av_bprint_finalize(&buf, NULL);
+ return 0;
+}
+
+static int debug_accuracy(const struct color_node *node, const uint32_t *palette,
+ const enum color_search_method search_method)
+{
+ int r, g, b, ret = 0;
+
+ for (r = 0; r < 256; r++) {
+ for (g = 0; g < 256; g++) {
+ for (b = 0; b < 256; b++) {
+ const uint8_t rgb[] = {r, g, b};
+ const int r1 = COLORMAP_NEAREST(search_method, palette, node, rgb);
+ const int r2 = colormap_nearest_bruteforce(palette, rgb);
+ if (r1 != r2) {
+ const uint32_t c1 = palette[r1];
+ const uint32_t c2 = palette[r2];
+ const uint8_t palrgb1[] = { c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff };
+ const uint8_t palrgb2[] = { c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff };
+ const int d1 = diff(palrgb1, rgb);
+ const int d2 = diff(palrgb2, rgb);
+ if (d1 != d2) {
+ av_log(NULL, AV_LOG_ERROR,
+ "/!\\ %02X%02X%02X: %d ! %d (%06X ! %06X) / dist: %d ! %d\n",
+ r, g, b, r1, r2, c1 & 0xffffff, c2 & 0xffffff, d1, d2);
+ ret = 1;
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+struct color {
+ uint32_t value;
+ uint8_t pal_id;
+};
+
+struct color_rect {
+ uint8_t min[3];
+ uint8_t max[3];
+};
+
+typedef int (*cmp_func)(const void *, const void *);
+
+#define DECLARE_CMP_FUNC(name, pos) \
+static int cmp_##name(const void *pa, const void *pb) \
+{ \
+ const struct color *a = pa; \
+ const struct color *b = pb; \
+ return (a->value >> (8 * (2 - (pos))) & 0xff) \
+ - (b->value >> (8 * (2 - (pos))) & 0xff); \
+}
+
+DECLARE_CMP_FUNC(r, 0)
+DECLARE_CMP_FUNC(g, 1)
+DECLARE_CMP_FUNC(b, 2)
+
+static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b};
+
+static int get_next_color(const uint8_t *color_used, const uint32_t *palette,
+ int *component, const struct color_rect *box)
+{
+ int wr, wg, wb;
+ int i, longest = 0;
+ unsigned nb_color = 0;
+ struct color_rect ranges;
+ struct color tmp_pal[256];
+ cmp_func cmpf;
+
+ ranges.min[0] = ranges.min[1] = ranges.min[2] = 0xff;
+ ranges.max[0] = ranges.max[1] = ranges.max[2] = 0x00;
+
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t c = palette[i];
+ const uint8_t r = c >> 16 & 0xff;
+ const uint8_t g = c >> 8 & 0xff;
+ const uint8_t b = c & 0xff;
+
+ if (color_used[i] ||
+ r < box->min[0] || g < box->min[1] || b < box->min[2] ||
+ r > box->max[0] || g > box->max[1] || b > box->max[2])
+ continue;
+
+ if (r < ranges.min[0]) ranges.min[0] = r;
+ if (g < ranges.min[1]) ranges.min[1] = g;
+ if (b < ranges.min[2]) ranges.min[2] = b;
+
+ if (r > ranges.max[0]) ranges.max[0] = r;
+ if (g > ranges.max[1]) ranges.max[1] = g;
+ if (b > ranges.max[2]) ranges.max[2] = b;
+
+ tmp_pal[nb_color].value = c;
+ tmp_pal[nb_color].pal_id = i;
+
+ nb_color++;
+ }
+
+ if (!nb_color)
+ return -1;
+
+ /* define longest axis that will be the split component */
+ wr = ranges.max[0] - ranges.min[0];
+ wg = ranges.max[1] - ranges.min[1];
+ wb = ranges.max[2] - ranges.min[2];
+ if (wr >= wg && wr >= wb) longest = 0;
+ if (wg >= wr && wg >= wb) longest = 1;
+ if (wb >= wr && wb >= wg) longest = 2;
+ cmpf = cmp_funcs[longest];
+ *component = longest;
+
+ /* sort along this axis to get median */
+ AV_QSORT(tmp_pal, nb_color, struct color, cmpf);
+
+ return tmp_pal[nb_color >> 1].pal_id;
+}
+
+static int colormap_insert(struct color_node *map,
+ uint8_t *color_used,
+ int *nb_used,
+ const uint32_t *palette,
+ const struct color_rect *box)
+{
+ uint32_t c;
+ int component, cur_id;
+ int node_left_id = -1, node_right_id = -1;
+ struct color_node *node;
+ struct color_rect box1, box2;
+ const int pal_id = get_next_color(color_used, palette, &component, box);
+
+ if (pal_id < 0)
+ return -1;
+
+ /* create new node with that color */
+ cur_id = (*nb_used)++;
+ c = palette[pal_id];
+ node = &map[cur_id];
+ node->split = component;
+ node->palette_id = pal_id;
+ node->val[0] = c>>16 & 0xff;
+ node->val[1] = c>> 8 & 0xff;
+ node->val[2] = c & 0xff;
+
+ color_used[pal_id] = 1;
+
+ /* get the two boxes this node creates */
+ box1 = box2 = *box;
+ box1.max[component] = node->val[component];
+ box2.min[component] = node->val[component] + 1;
+
+ node_left_id = colormap_insert(map, color_used, nb_used, palette, &box1);
+
+ if (box2.min[component] <= box2.max[component])
+ node_right_id = colormap_insert(map, color_used, nb_used, palette, &box2);
+
+ node->left_id = node_left_id;
+ node->right_id = node_right_id;
+
+ return cur_id;
+}
+
+static int cmp_pal_entry(const void *a, const void *b)
+{
+ const int c1 = *(const uint32_t *)a & 0xffffff;
+ const int c2 = *(const uint32_t *)b & 0xffffff;
+ return c1 - c2;
+}
+
+static void load_colormap(PaletteUseContext *s)
+{
+ int i, nb_used = 0;
+ uint8_t color_used[AVPALETTE_COUNT] = {0};
+ uint32_t last_color = 0;
+ struct color_rect box;
+
+ /* disable transparent colors and dups */
+ qsort(s->palette, AVPALETTE_COUNT, sizeof(*s->palette), cmp_pal_entry);
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t c = s->palette[i];
+ if (i != 0 && c == last_color) {
+ color_used[i] = 1;
+ continue;
+ }
+ last_color = c;
+ if ((c & 0xff000000) != 0xff000000) {
+ color_used[i] = 1; // ignore transparent color(s)
+ continue;
+ }
+ }
+
+ box.min[0] = box.min[1] = box.min[2] = 0x00;
+ box.max[0] = box.max[1] = box.max[2] = 0xff;
+
+ colormap_insert(s->map, color_used, &nb_used, s->palette, &box);
+
+ if (s->dot_filename)
+ disp_tree(s->map, s->dot_filename);
+
+ if (s->debug_accuracy) {
+ if (!debug_accuracy(s->map, s->palette, s->color_search_method))
+ av_log(NULL, AV_LOG_INFO, "Accuracy check passed\n");
+ }
+}
+
+static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1,
+ const AVFrame *in2, int frame_count)
+{
+ int x, y;
+ const uint32_t *palette = s->palette;
+ uint32_t *src1 = (uint32_t *)in1->data[0];
+ uint8_t *src2 = in2->data[0];
+ const int src1_linesize = in1->linesize[0] >> 2;
+ const int src2_linesize = in2->linesize[0];
+ const float div = in1->width * in1->height * 3;
+ unsigned mean_err = 0;
+
+ for (y = 0; y < in1->height; y++) {
+ for (x = 0; x < in1->width; x++) {
+ const uint32_t c1 = src1[x];
+ const uint32_t c2 = palette[src2[x]];
+ const uint8_t rgb1[] = {c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff};
+ const uint8_t rgb2[] = {c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff};
+ mean_err += diff(rgb1, rgb2);
+ }
+ src1 += src1_linesize;
+ src2 += src2_linesize;
+ }
+
+ s->total_mean_err += mean_err;
+
+ av_log(NULL, AV_LOG_INFO, "MEP:%.3f TotalMEP:%.3f\n",
+ mean_err / div, s->total_mean_err / (div * frame_count));
+}
+
+static void set_processing_window(enum diff_mode diff_mode,
+ const AVFrame *prv_src, const AVFrame *cur_src,
+ const AVFrame *prv_dst, AVFrame *cur_dst,
+ int *xp, int *yp, int *wp, int *hp)
+{
+ int x_start = 0, y_start = 0;
+ int width = cur_src->width;
+ int height = cur_src->height;
+
+ if (prv_src && diff_mode == DIFF_MODE_RECTANGLE) {
+ int y;
+ int x_end = cur_src->width - 1,
+ y_end = cur_src->height - 1;
+ const uint32_t *prv_srcp = (const uint32_t *)prv_src->data[0];
+ const uint32_t *cur_srcp = (const uint32_t *)cur_src->data[0];
+ const uint8_t *prv_dstp = prv_dst->data[0];
+ uint8_t *cur_dstp = cur_dst->data[0];
+
+ const int prv_src_linesize = prv_src->linesize[0] >> 2;
+ const int cur_src_linesize = cur_src->linesize[0] >> 2;
+ const int prv_dst_linesize = prv_dst->linesize[0];
+ const int cur_dst_linesize = cur_dst->linesize[0];
+
+ /* skip common lines */
+ while (y_start < y_end && !memcmp(prv_srcp + y_start*prv_src_linesize,
+ cur_srcp + y_start*cur_src_linesize,
+ cur_src->width * 4)) {
+ memcpy(cur_dstp + y_start*cur_dst_linesize,
+ prv_dstp + y_start*prv_dst_linesize,
+ cur_dst->width);
+ y_start++;
+ }
+ while (y_end > y_start && !memcmp(prv_srcp + y_end*prv_src_linesize,
+ cur_srcp + y_end*cur_src_linesize,
+ cur_src->width * 4)) {
+ memcpy(cur_dstp + y_end*cur_dst_linesize,
+ prv_dstp + y_end*prv_dst_linesize,
+ cur_dst->width);
+ y_end--;
+ }
+
+ height = y_end + 1 - y_start;
+
+ /* skip common columns */
+ while (x_start < x_end) {
+ int same_column = 1;
+ for (y = y_start; y <= y_end; y++) {
+ if (prv_srcp[y*prv_src_linesize + x_start] != cur_srcp[y*cur_src_linesize + x_start]) {
+ same_column = 0;
+ break;
+ }
+ }
+ if (!same_column)
+ break;
+ x_start++;
+ }
+ while (x_end > x_start) {
+ int same_column = 1;
+ for (y = y_start; y <= y_end; y++) {
+ if (prv_srcp[y*prv_src_linesize + x_end] != cur_srcp[y*cur_src_linesize + x_end]) {
+ same_column = 0;
+ break;
+ }
+ }
+ if (!same_column)
+ break;
+ x_end--;
+ }
+ width = x_end + 1 - x_start;
+
+ if (x_start) {
+ for (y = y_start; y <= y_end; y++)
+ memcpy(cur_dstp + y*cur_dst_linesize,
+ prv_dstp + y*prv_dst_linesize, x_start);
+ }
+ if (x_end != cur_src->width - 1) {
+ const int copy_len = cur_src->width - 1 - x_end;
+ for (y = y_start; y <= y_end; y++)
+ memcpy(cur_dstp + y*cur_dst_linesize + x_end + 1,
+ prv_dstp + y*prv_dst_linesize + x_end + 1,
+ copy_len);
+ }
+ }
+ *xp = x_start;
+ *yp = y_start;
+ *wp = width;
+ *hp = height;
+}
+
+static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in)
+{
+ int x, y, w, h;
+ AVFilterContext *ctx = inlink->dst;
+ PaletteUseContext *s = ctx->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+
+ AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return NULL;
+ }
+ av_frame_copy_props(out, in);
+
+ set_processing_window(s->diff_mode, s->last_in, in,
+ s->last_out, out, &x, &y, &w, &h);
+ av_frame_free(&s->last_in);
+ av_frame_free(&s->last_out);
+ s->last_in = av_frame_clone(in);
+ s->last_out = av_frame_clone(out);
+ if (!s->last_in || !s->last_out ||
+ av_frame_make_writable(s->last_in) < 0) {
+ av_frame_free(&in);
+ av_frame_free(&out);
+ return NULL;
+ }
+
+ av_dlog(ctx, "%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n",
+ w, h, x, y, x+w, y+h, in->width, in->height);
+
+ if (s->set_frame(s, out, in, x, y, w, h) < 0) {
+ av_frame_free(&out);
+ return NULL;
+ }
+ memcpy(out->data[1], s->palette, AVPALETTE_SIZE);
+ if (s->calc_mean_err)
+ debug_mean_error(s, in, out, inlink->frame_count);
+ av_frame_free(&in);
+ return out;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ int ret;
+ AVFilterContext *ctx = outlink->src;
+ PaletteUseContext *s = ctx->priv;
+
+ outlink->w = ctx->inputs[0]->w;
+ outlink->h = ctx->inputs[0]->h;
+
+ outlink->time_base = ctx->inputs[0]->time_base;
+ if ((ret = ff_dualinput_init(ctx, &s->dinput)) < 0)
+ return ret;
+ return 0;
+}
+
+static int config_input_palette(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+
+ if (inlink->w * inlink->h != AVPALETTE_COUNT) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Palette input must contain exactly %d pixels. "
+ "Specified input has %dx%d=%d pixels\n",
+ AVPALETTE_COUNT, inlink->w, inlink->h,
+ inlink->w * inlink->h);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame)
+{
+ int i, x, y;
+ const uint32_t *p = (const uint32_t *)palette_frame->data[0];
+ const int p_linesize = palette_frame->linesize[0] >> 2;
+
+ i = 0;
+ for (y = 0; y < palette_frame->height; y++) {
+ for (x = 0; x < palette_frame->width; x++)
+ s->palette[i++] = p[x];
+ p += p_linesize;
+ }
+
+ load_colormap(s);
+
+ s->palette_loaded = 1;
+}
+
+static AVFrame *load_apply_palette(AVFilterContext *ctx, AVFrame *main,
+ const AVFrame *second)
+{
+ AVFilterLink *inlink = ctx->inputs[0];
+ PaletteUseContext *s = ctx->priv;
+ if (!s->palette_loaded) {
+ load_palette(s, second);
+ }
+ return apply_palette(inlink, main);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ PaletteUseContext *s = inlink->dst->priv;
+ return ff_dualinput_filter_frame(&s->dinput, inlink, in);
+}
+
+#define DEFINE_SET_FRAME(color_search, name, value) \
+static int set_frame_##name(PaletteUseContext *s, AVFrame *out, AVFrame *in, \
+ int x_start, int y_start, int w, int h) \
+{ \
+ return set_frame(s, out, in, x_start, y_start, w, h, value, color_search); \
+}
+
+#define DEFINE_SET_FRAME_COLOR_SEARCH(color_search, color_search_macro) \
+ DEFINE_SET_FRAME(color_search_macro, color_search##_##none, DITHERING_NONE) \
+ DEFINE_SET_FRAME(color_search_macro, color_search##_##bayer, DITHERING_BAYER) \
+ DEFINE_SET_FRAME(color_search_macro, color_search##_##heckbert, DITHERING_HECKBERT) \
+ DEFINE_SET_FRAME(color_search_macro, color_search##_##floyd_steinberg, DITHERING_FLOYD_STEINBERG) \
+ DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2, DITHERING_SIERRA2) \
+ DEFINE_SET_FRAME(color_search_macro, color_search##_##sierra2_4a, DITHERING_SIERRA2_4A) \
+
+DEFINE_SET_FRAME_COLOR_SEARCH(nns_iterative, COLOR_SEARCH_NNS_ITERATIVE)
+DEFINE_SET_FRAME_COLOR_SEARCH(nns_recursive, COLOR_SEARCH_NNS_RECURSIVE)
+DEFINE_SET_FRAME_COLOR_SEARCH(bruteforce, COLOR_SEARCH_BRUTEFORCE)
+
+#define DITHERING_ENTRIES(color_search) { \
+ set_frame_##color_search##_none, \
+ set_frame_##color_search##_bayer, \
+ set_frame_##color_search##_heckbert, \
+ set_frame_##color_search##_floyd_steinberg, \
+ set_frame_##color_search##_sierra2, \
+ set_frame_##color_search##_sierra2_4a, \
+}
+
+static const set_frame_func set_frame_lut[NB_COLOR_SEARCHES][NB_DITHERING] = {
+ DITHERING_ENTRIES(nns_iterative),
+ DITHERING_ENTRIES(nns_recursive),
+ DITHERING_ENTRIES(bruteforce),
+};
+
+static int dither_value(int p)
+{
+ const int q = p ^ (p >> 3);
+ return (p & 4) >> 2 | (q & 4) >> 1 \
+ | (p & 2) << 1 | (q & 2) << 2 \
+ | (p & 1) << 4 | (q & 1) << 5;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ PaletteUseContext *s = ctx->priv;
+ s->dinput.repeatlast = 1; // only 1 frame in the palette
+ s->dinput.process = load_apply_palette;
+
+ s->set_frame = set_frame_lut[s->color_search_method][s->dither];
+
+ if (s->dither == DITHERING_BAYER) {
+ int i;
+ const int delta = 1 << (5 - s->bayer_scale); // to avoid too much luma
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->ordered_dither); i++)
+ s->ordered_dither[i] = (dither_value(i) >> s->bayer_scale) - delta;
+ }
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ PaletteUseContext *s = outlink->src->priv;
+ return ff_dualinput_request_frame(&s->dinput, outlink);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i;
+ PaletteUseContext *s = ctx->priv;
+
+ ff_dualinput_uninit(&s->dinput);
+ for (i = 0; i < CACHE_SIZE; i++)
+ av_freep(&s->cache[i].entries);
+ av_frame_free(&s->last_in);
+ av_frame_free(&s->last_out);
+}
+
+static const AVFilterPad paletteuse_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .needs_writable = 1, // for error diffusal dithering
+ },{
+ .name = "palette",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input_palette,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad paletteuse_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_paletteuse = {
+ .name = "paletteuse",
+ .description = NULL_IF_CONFIG_SMALL("Use a palette to downsample an input video stream."),
+ .priv_size = sizeof(PaletteUseContext),
+ .query_formats = query_formats,
+ .init = init,
+ .uninit = uninit,
+ .inputs = paletteuse_inputs,
+ .outputs = paletteuse_outputs,
+ .priv_class = &paletteuse_class,
+};
diff --git a/libavfilter/vf_perspective.c b/libavfilter/vf_perspective.c
new file mode 100644
index 0000000000..970870cda5
--- /dev/null
+++ b/libavfilter/vf_perspective.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 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 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/avassert.h"
+#include "libavutil/eval.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#define SUB_PIXEL_BITS 8
+#define SUB_PIXELS (1 << SUB_PIXEL_BITS)
+#define COEFF_BITS 11
+
+#define LINEAR 0
+#define CUBIC 1
+
+typedef struct PerspectiveContext {
+ const AVClass *class;
+ char *expr_str[4][2];
+ double ref[4][2];
+ int32_t (*pv)[2];
+ int32_t coeff[SUB_PIXELS][4];
+ int interpolation;
+ int linesize[4];
+ int height[4];
+ int hsub, vsub;
+ int nb_planes;
+ int sense;
+
+ int (*perspective)(AVFilterContext *ctx,
+ void *arg, int job, int nb_jobs);
+} PerspectiveContext;
+
+#define OFFSET(x) offsetof(PerspectiveContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+enum PERSPECTIVESense {
+ PERSPECTIVE_SENSE_SOURCE = 0, ///< coordinates give locations in source of corners of destination.
+ PERSPECTIVE_SENSE_DESTINATION = 1, ///< coordinates give locations in destination of corners of source.
+};
+
+static const AVOption perspective_options[] = {
+ { "x0", "set top left x coordinate", OFFSET(expr_str[0][0]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS },
+ { "y0", "set top left y coordinate", OFFSET(expr_str[0][1]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS },
+ { "x1", "set top right x coordinate", OFFSET(expr_str[1][0]), AV_OPT_TYPE_STRING, {.str="W"}, 0, 0, FLAGS },
+ { "y1", "set top right y coordinate", OFFSET(expr_str[1][1]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS },
+ { "x2", "set bottom left x coordinate", OFFSET(expr_str[2][0]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS },
+ { "y2", "set bottom left y coordinate", OFFSET(expr_str[2][1]), AV_OPT_TYPE_STRING, {.str="H"}, 0, 0, FLAGS },
+ { "x3", "set bottom right x coordinate", OFFSET(expr_str[3][0]), AV_OPT_TYPE_STRING, {.str="W"}, 0, 0, FLAGS },
+ { "y3", "set bottom right y coordinate", OFFSET(expr_str[3][1]), AV_OPT_TYPE_STRING, {.str="H"}, 0, 0, FLAGS },
+ { "interpolation", "set interpolation", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=LINEAR}, 0, 1, FLAGS, "interpolation" },
+ { "linear", "", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "interpolation" },
+ { "cubic", "", 0, AV_OPT_TYPE_CONST, {.i64=CUBIC}, 0, 0, FLAGS, "interpolation" },
+ { "sense", "specify the sense of the coordinates", OFFSET(sense), AV_OPT_TYPE_INT, {.i64=PERSPECTIVE_SENSE_SOURCE}, 0, 1, FLAGS, "sense"},
+ { "source", "specify locations in source to send to corners in destination",
+ 0, AV_OPT_TYPE_CONST, {.i64=PERSPECTIVE_SENSE_SOURCE}, 0, 0, FLAGS, "sense"},
+ { "destination", "specify locations in destination to send corners of source",
+ 0, AV_OPT_TYPE_CONST, {.i64=PERSPECTIVE_SENSE_DESTINATION}, 0, 0, FLAGS, "sense"},
+
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(perspective);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static inline double get_coeff(double d)
+{
+ double coeff, A = -0.60;
+
+ d = fabs(d);
+
+ if (d < 1.0)
+ coeff = (1.0 - (A + 3.0) * d * d + (A + 2.0) * d * d * d);
+ else if (d < 2.0)
+ coeff = (-4.0 * A + 8.0 * A * d - 5.0 * A * d * d + A * d * d * d);
+ else
+ coeff = 0.0;
+
+ return coeff;
+}
+
+static const char *const var_names[] = { "W", "H", NULL };
+enum { VAR_W, VAR_H, VAR_VARS_NB };
+
+static int config_input(AVFilterLink *inlink)
+{
+ double x0, x1, x2, x3, x4, x5, x6, x7, x8, q;
+ double t0, t1, t2, t3;
+ AVFilterContext *ctx = inlink->dst;
+ PerspectiveContext *s = ctx->priv;
+ double (*ref)[2] = s->ref;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ double values[VAR_VARS_NB] = { [VAR_W] = inlink->w, [VAR_H] = inlink->h };
+ int h = inlink->h;
+ int w = inlink->w;
+ int x, y, i, j, ret;
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 2; j++) {
+ if (!s->expr_str[i][j])
+ return AVERROR(EINVAL);
+ ret = av_expr_parse_and_eval(&s->ref[i][j], s->expr_str[i][j],
+ var_names, &values[0],
+ NULL, NULL, NULL, NULL,
+ 0, 0, ctx);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ s->hsub = desc->log2_chroma_w;
+ s->vsub = desc->log2_chroma_h;
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+ if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->height[1] = s->height[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->height[0] = s->height[3] = inlink->h;
+
+ s->pv = av_realloc_f(s->pv, w * h, 2 * sizeof(*s->pv));
+ if (!s->pv)
+ return AVERROR(ENOMEM);
+
+ switch (s->sense) {
+ case PERSPECTIVE_SENSE_SOURCE:
+ x6 = ((ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0]) *
+ (ref[2][1] - ref[3][1]) -
+ ( ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1]) *
+ (ref[2][0] - ref[3][0])) * h;
+ x7 = ((ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1]) *
+ (ref[1][0] - ref[3][0]) -
+ ( ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0]) *
+ (ref[1][1] - ref[3][1])) * w;
+ q = ( ref[1][0] - ref[3][0]) * (ref[2][1] - ref[3][1]) -
+ ( ref[2][0] - ref[3][0]) * (ref[1][1] - ref[3][1]);
+
+ x0 = q * (ref[1][0] - ref[0][0]) * h + x6 * ref[1][0];
+ x1 = q * (ref[2][0] - ref[0][0]) * w + x7 * ref[2][0];
+ x2 = q * ref[0][0] * w * h;
+ x3 = q * (ref[1][1] - ref[0][1]) * h + x6 * ref[1][1];
+ x4 = q * (ref[2][1] - ref[0][1]) * w + x7 * ref[2][1];
+ x5 = q * ref[0][1] * w * h;
+ x8 = q * w * h;
+ break;
+ case PERSPECTIVE_SENSE_DESTINATION:
+ t0 = ref[0][0] * (ref[3][1] - ref[1][1]) +
+ ref[1][0] * (ref[0][1] - ref[3][1]) +
+ ref[3][0] * (ref[1][1] - ref[0][1]);
+ t1 = ref[1][0] * (ref[2][1] - ref[3][1]) +
+ ref[2][0] * (ref[3][1] - ref[1][1]) +
+ ref[3][0] * (ref[1][1] - ref[2][1]);
+ t2 = ref[0][0] * (ref[3][1] - ref[2][1]) +
+ ref[2][0] * (ref[0][1] - ref[3][1]) +
+ ref[3][0] * (ref[2][1] - ref[0][1]);
+ t3 = ref[0][0] * (ref[1][1] - ref[2][1]) +
+ ref[1][0] * (ref[2][1] - ref[0][1]) +
+ ref[2][0] * (ref[0][1] - ref[1][1]);
+
+ x0 = t0 * t1 * w * (ref[2][1] - ref[0][1]);
+ x1 = t0 * t1 * w * (ref[0][0] - ref[2][0]);
+ x2 = t0 * t1 * w * (ref[0][1] * ref[2][0] - ref[0][0] * ref[2][1]);
+ x3 = t1 * t2 * h * (ref[1][1] - ref[0][1]);
+ x4 = t1 * t2 * h * (ref[0][0] - ref[1][0]);
+ x5 = t1 * t2 * h * (ref[0][1] * ref[1][0] - ref[0][0] * ref[1][1]);
+ x6 = t1 * t2 * (ref[1][1] - ref[0][1]) +
+ t0 * t3 * (ref[2][1] - ref[3][1]);
+ x7 = t1 * t2 * (ref[0][0] - ref[1][0]) +
+ t0 * t3 * (ref[3][0] - ref[2][0]);
+ x8 = t1 * t2 * (ref[0][1] * ref[1][0] - ref[0][0] * ref[1][1]) +
+ t0 * t3 * (ref[2][0] * ref[3][1] - ref[2][1] * ref[3][0]);
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ for (y = 0; y < h; y++){
+ for (x = 0; x < w; x++){
+ int u, v;
+
+ u = (int)floor(SUB_PIXELS * (x0 * x + x1 * y + x2) /
+ (x6 * x + x7 * y + x8) + 0.5);
+ v = (int)floor(SUB_PIXELS * (x3 * x + x4 * y + x5) /
+ (x6 * x + x7 * y + x8) + 0.5);
+
+ s->pv[x + y * w][0] = u;
+ s->pv[x + y * w][1] = v;
+ }
+ }
+
+ for (i = 0; i < SUB_PIXELS; i++){
+ double d = i / (double)SUB_PIXELS;
+ double temp[4];
+ double sum = 0;
+
+ for (j = 0; j < 4; j++)
+ temp[j] = get_coeff(j - d - 1);
+
+ for (j = 0; j < 4; j++)
+ sum += temp[j];
+
+ for (j = 0; j < 4; j++)
+ s->coeff[i][j] = (int)floor((1 << COEFF_BITS) * temp[j] / sum + 0.5);
+ }
+
+ return 0;
+}
+
+typedef struct ThreadData {
+ uint8_t *dst;
+ int dst_linesize;
+ uint8_t *src;
+ int src_linesize;
+ int w, h;
+ int hsub, vsub;
+} ThreadData;
+
+static int resample_cubic(AVFilterContext *ctx, void *arg,
+ int job, int nb_jobs)
+{
+ PerspectiveContext *s = ctx->priv;
+ ThreadData *td = arg;
+ uint8_t *dst = td->dst;
+ int dst_linesize = td->dst_linesize;
+ uint8_t *src = td->src;
+ int src_linesize = td->src_linesize;
+ int w = td->w;
+ int h = td->h;
+ int hsub = td->hsub;
+ int vsub = td->vsub;
+ int start = (h * job) / nb_jobs;
+ int end = (h * (job+1)) / nb_jobs;
+ const int linesize = s->linesize[0];
+ int x, y;
+
+ for (y = start; y < end; y++) {
+ int sy = y << vsub;
+ for (x = 0; x < w; x++) {
+ int u, v, subU, subV, sum, sx;
+
+ sx = x << hsub;
+ u = s->pv[sx + sy * linesize][0] >> hsub;
+ v = s->pv[sx + sy * linesize][1] >> vsub;
+ subU = u & (SUB_PIXELS - 1);
+ subV = v & (SUB_PIXELS - 1);
+ u >>= SUB_PIXEL_BITS;
+ v >>= SUB_PIXEL_BITS;
+
+ if (u > 0 && v > 0 && u < w - 2 && v < h - 2){
+ const int index = u + v*src_linesize;
+ const int a = s->coeff[subU][0];
+ const int b = s->coeff[subU][1];
+ const int c = s->coeff[subU][2];
+ const int d = s->coeff[subU][3];
+
+ sum = s->coeff[subV][0] * (a * src[index - 1 - src_linesize] + b * src[index - 0 - src_linesize] +
+ c * src[index + 1 - src_linesize] + d * src[index + 2 - src_linesize]) +
+ s->coeff[subV][1] * (a * src[index - 1 ] + b * src[index - 0 ] +
+ c * src[index + 1 ] + d * src[index + 2 ]) +
+ s->coeff[subV][2] * (a * src[index - 1 + src_linesize] + b * src[index - 0 + src_linesize] +
+ c * src[index + 1 + src_linesize] + d * src[index + 2 + src_linesize]) +
+ s->coeff[subV][3] * (a * src[index - 1 + 2 * src_linesize] + b * src[index - 0 + 2 * src_linesize] +
+ c * src[index + 1 + 2 * src_linesize] + d * src[index + 2 + 2 * src_linesize]);
+ } else {
+ int dx, dy;
+
+ sum = 0;
+
+ for (dy = 0; dy < 4; dy++) {
+ int iy = v + dy - 1;
+
+ if (iy < 0)
+ iy = 0;
+ else if (iy >= h)
+ iy = h-1;
+ for (dx = 0; dx < 4; dx++) {
+ int ix = u + dx - 1;
+
+ if (ix < 0)
+ ix = 0;
+ else if (ix >= w)
+ ix = w - 1;
+
+ sum += s->coeff[subU][dx] * s->coeff[subV][dy] * src[ ix + iy * src_linesize];
+ }
+ }
+ }
+
+ sum = (sum + (1<<(COEFF_BITS * 2 - 1))) >> (COEFF_BITS * 2);
+ sum = av_clip_uint8(sum);
+ dst[x + y * dst_linesize] = sum;
+ }
+ }
+ return 0;
+}
+
+static int resample_linear(AVFilterContext *ctx, void *arg,
+ int job, int nb_jobs)
+{
+ PerspectiveContext *s = ctx->priv;
+ ThreadData *td = arg;
+ uint8_t *dst = td->dst;
+ int dst_linesize = td->dst_linesize;
+ uint8_t *src = td->src;
+ int src_linesize = td->src_linesize;
+ int w = td->w;
+ int h = td->h;
+ int hsub = td->hsub;
+ int vsub = td->vsub;
+ int start = (h * job) / nb_jobs;
+ int end = (h * (job+1)) / nb_jobs;
+ const int linesize = s->linesize[0];
+ int x, y;
+
+ for (y = start; y < end; y++){
+ int sy = y << vsub;
+ for (x = 0; x < w; x++){
+ int u, v, subU, subV, sum, sx, index, subUI, subVI;
+
+ sx = x << hsub;
+ u = s->pv[sx + sy * linesize][0] >> hsub;
+ v = s->pv[sx + sy * linesize][1] >> vsub;
+ subU = u & (SUB_PIXELS - 1);
+ subV = v & (SUB_PIXELS - 1);
+ u >>= SUB_PIXEL_BITS;
+ v >>= SUB_PIXEL_BITS;
+
+ index = u + v * src_linesize;
+ subUI = SUB_PIXELS - subU;
+ subVI = SUB_PIXELS - subV;
+
+ if ((unsigned)u < (unsigned)(w - 1)){
+ if((unsigned)v < (unsigned)(h - 1)){
+ sum = subVI * (subUI * src[index] + subU * src[index + 1]) +
+ subV * (subUI * src[index + src_linesize] + subU * src[index + src_linesize + 1]);
+ sum = (sum + (1 << (SUB_PIXEL_BITS * 2 - 1)))>> (SUB_PIXEL_BITS * 2);
+ } else {
+ if (v < 0)
+ v = 0;
+ else
+ v = h - 1;
+ index = u + v * src_linesize;
+ sum = subUI * src[index] + subU * src[index + 1];
+ sum = (sum + (1 << (SUB_PIXEL_BITS - 1))) >> SUB_PIXEL_BITS;
+ }
+ } else {
+ if (u < 0)
+ u = 0;
+ else
+ u = w - 1;
+ if ((unsigned)v < (unsigned)(h - 1)){
+ index = u + v * src_linesize;
+ sum = subVI * src[index] + subV * src[index + src_linesize];
+ sum = (sum + (1 << (SUB_PIXEL_BITS - 1))) >> SUB_PIXEL_BITS;
+ } else {
+ if (v < 0)
+ v = 0;
+ else
+ v = h - 1;
+ index = u + v * src_linesize;
+ sum = src[index];
+ }
+ }
+
+ sum = av_clip_uint8(sum);
+ dst[x + y * dst_linesize] = sum;
+ }
+ }
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ PerspectiveContext *s = ctx->priv;
+
+ switch (s->interpolation) {
+ case LINEAR: s->perspective = resample_linear; break;
+ case CUBIC: s->perspective = resample_cubic; break;
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ PerspectiveContext *s = ctx->priv;
+ AVFrame *out;
+ int plane;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&frame);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, frame);
+
+ for (plane = 0; plane < s->nb_planes; plane++) {
+ int hsub = plane == 1 || plane == 2 ? s->hsub : 0;
+ int vsub = plane == 1 || plane == 2 ? s->vsub : 0;
+ ThreadData td = {.dst = out->data[plane],
+ .dst_linesize = out->linesize[plane],
+ .src = frame->data[plane],
+ .src_linesize = frame->linesize[plane],
+ .w = s->linesize[plane],
+ .h = s->height[plane],
+ .hsub = hsub,
+ .vsub = vsub };
+ ctx->internal->execute(ctx, s->perspective, &td, NULL, FFMIN(td.h, ctx->graph->nb_threads));
+ }
+
+ av_frame_free(&frame);
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ PerspectiveContext *s = ctx->priv;
+
+ av_freep(&s->pv);
+}
+
+static const AVFilterPad perspective_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad perspective_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_perspective = {
+ .name = "perspective",
+ .description = NULL_IF_CONFIG_SMALL("Correct the perspective of video."),
+ .priv_size = sizeof(PerspectiveContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = perspective_inputs,
+ .outputs = perspective_outputs,
+ .priv_class = &perspective_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_phase.c b/libavfilter/vf_phase.c
new file mode 100644
index 0000000000..35c343fbec
--- /dev/null
+++ b/libavfilter/vf_phase.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2004 Ville Saari
+ *
+ * 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/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum PhaseMode {
+ PROGRESSIVE,
+ TOP_FIRST,
+ BOTTOM_FIRST,
+ TOP_FIRST_ANALYZE,
+ BOTTOM_FIRST_ANALYZE,
+ ANALYZE,
+ FULL_ANALYZE,
+ AUTO,
+ AUTO_ANALYZE
+};
+
+typedef struct PhaseContext {
+ const AVClass *class;
+ int mode; ///<PhaseMode
+ AVFrame *frame; /* previous frame */
+ int nb_planes;
+ int planeheight[4];
+ int linesize[4];
+} PhaseContext;
+
+#define OFFSET(x) offsetof(PhaseContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, unit }
+
+static const AVOption phase_options[] = {
+ { "mode", "set phase mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=AUTO_ANALYZE}, PROGRESSIVE, AUTO_ANALYZE, FLAGS, "mode" },
+ CONST("p", "progressive", PROGRESSIVE, "mode"),
+ CONST("t", "top first", TOP_FIRST, "mode"),
+ CONST("b", "bottom first", BOTTOM_FIRST, "mode"),
+ CONST("T", "top first analyze", TOP_FIRST_ANALYZE, "mode"),
+ CONST("B", "bottom first analyze", BOTTOM_FIRST_ANALYZE, "mode"),
+ CONST("u", "analyze", ANALYZE, "mode"),
+ CONST("U", "full analyze", FULL_ANALYZE, "mode"),
+ CONST("a", "auto", AUTO, "mode"),
+ CONST("A", "auto analyze", AUTO_ANALYZE, "mode"),
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(phase);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ PhaseContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ return 0;
+}
+
+/*
+ * This macro interpolates the value of both fields at a point halfway
+ * between lines and takes the squared difference. In field resolution
+ * the point is a quarter pixel below a line in one field and a quarter
+ * pixel above a line in other.
+ *
+ * (The result is actually multiplied by 25)
+ */
+#define DIFF(a, as, b, bs) ((t) = ((*(a) - (b)[bs]) << 2) + (a)[(as) << 1] - (b)[-(bs)], (t) * (t))
+
+/*
+ * Find which field combination has the smallest average squared difference
+ * between the fields.
+ */
+static enum PhaseMode analyze_plane(void *ctx, enum PhaseMode mode, AVFrame *old, AVFrame *new)
+{
+ double bdiff, tdiff, pdiff, scale;
+ const int ns = new->linesize[0];
+ const int os = old->linesize[0];
+ const uint8_t *nptr = new->data[0];
+ const uint8_t *optr = old->data[0];
+ const int h = new->height;
+ const int w = new->width;
+ int bdif, tdif, pdif;
+
+ if (mode == AUTO) {
+ mode = new->interlaced_frame ? new->top_field_first ?
+ TOP_FIRST : BOTTOM_FIRST : PROGRESSIVE;
+ } else if (mode == AUTO_ANALYZE) {
+ mode = new->interlaced_frame ? new->top_field_first ?
+ TOP_FIRST_ANALYZE : BOTTOM_FIRST_ANALYZE : FULL_ANALYZE;
+ }
+
+ if (mode <= BOTTOM_FIRST) {
+ bdiff = pdiff = tdiff = 65536.0;
+ } else {
+ int top = 0, t;
+ const uint8_t *rend, *end = nptr + (h - 2) * ns;
+
+ bdiff = pdiff = tdiff = 0.0;
+
+ nptr += ns;
+ optr += os;
+ while (nptr < end) {
+ pdif = tdif = bdif = 0;
+
+ switch (mode) {
+ case TOP_FIRST_ANALYZE:
+ if (top) {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ pdif += DIFF(nptr, ns, nptr, ns);
+ tdif += DIFF(nptr, ns, optr, os);
+ }
+ } else {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ pdif += DIFF(nptr, ns, nptr, ns);
+ tdif += DIFF(optr, os, nptr, ns);
+ }
+ }
+ break;
+ case BOTTOM_FIRST_ANALYZE:
+ if (top) {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ pdif += DIFF(nptr, ns, nptr, ns);
+ bdif += DIFF(optr, os, nptr, ns);
+ }
+ } else {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ pdif += DIFF(nptr, ns, nptr, ns);
+ bdif += DIFF(nptr, ns, optr, os);
+ }
+ }
+ break;
+ case ANALYZE:
+ if (top) {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ tdif += DIFF(nptr, ns, optr, os);
+ bdif += DIFF(optr, os, nptr, ns);
+ }
+ } else {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ bdif += DIFF(nptr, ns, optr, os);
+ tdif += DIFF(optr, os, nptr, ns);
+ }
+ }
+ break;
+ case FULL_ANALYZE:
+ if (top) {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ pdif += DIFF(nptr, ns, nptr, ns);
+ tdif += DIFF(nptr, ns, optr, os);
+ bdif += DIFF(optr, os, nptr, ns);
+ }
+ } else {
+ for (rend = nptr + w; nptr < rend; nptr++, optr++) {
+ pdif += DIFF(nptr, ns, nptr, ns);
+ bdif += DIFF(nptr, ns, optr, os);
+ tdif += DIFF(optr, os, nptr, ns);
+ }
+ }
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ pdiff += (double)pdif;
+ tdiff += (double)tdif;
+ bdiff += (double)bdif;
+ nptr += ns - w;
+ optr += os - w;
+ top ^= 1;
+ }
+
+ scale = 1.0 / (w * (h - 3)) / 25.0;
+ pdiff *= scale;
+ tdiff *= scale;
+ bdiff *= scale;
+
+ if (mode == TOP_FIRST_ANALYZE) {
+ bdiff = 65536.0;
+ } else if (mode == BOTTOM_FIRST_ANALYZE) {
+ tdiff = 65536.0;
+ } else if (mode == ANALYZE) {
+ pdiff = 65536.0;
+ }
+
+ if (bdiff < pdiff && bdiff < tdiff) {
+ mode = BOTTOM_FIRST;
+ } else if (tdiff < pdiff && tdiff < bdiff) {
+ mode = TOP_FIRST;
+ } else {
+ mode = PROGRESSIVE;
+ }
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "mode=%c tdiff=%f bdiff=%f pdiff=%f\n",
+ mode == BOTTOM_FIRST ? 'b' : mode == TOP_FIRST ? 't' : 'p',
+ tdiff, bdiff, pdiff);
+ return mode;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ PhaseContext *s = ctx->priv;
+ enum PhaseMode mode;
+ int plane, top, y;
+ AVFrame *out;
+
+ if (ctx->is_disabled) {
+ av_frame_free(&s->frame);
+ /* we keep a reference to the previous frame so the filter can start
+ * being useful as soon as it's not disabled, avoiding the 1-frame
+ * delay. */
+ s->frame = av_frame_clone(in);
+ return ff_filter_frame(outlink, in);
+ }
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ if (!s->frame) {
+ s->frame = in;
+ mode = PROGRESSIVE;
+ } else {
+ mode = analyze_plane(ctx, s->mode, s->frame, in);
+ }
+
+ for (plane = 0; plane < s->nb_planes; plane++) {
+ const uint8_t *buf = s->frame->data[plane];
+ const uint8_t *from = in->data[plane];
+ uint8_t *to = out->data[plane];
+
+ for (y = 0, top = 1; y < s->planeheight[plane]; y++, top ^= 1) {
+ memcpy(to, mode == (top ? BOTTOM_FIRST : TOP_FIRST) ? buf : from, s->linesize[plane]);
+
+ buf += s->frame->linesize[plane];
+ from += in->linesize[plane];
+ to += out->linesize[plane];
+ }
+ }
+
+ if (in != s->frame)
+ av_frame_free(&s->frame);
+ s->frame = in;
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ PhaseContext *s = ctx->priv;
+
+ av_frame_free(&s->frame);
+}
+
+static const AVFilterPad phase_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad phase_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_phase = {
+ .name = "phase",
+ .description = NULL_IF_CONFIG_SMALL("Phase shift fields."),
+ .priv_size = sizeof(PhaseContext),
+ .priv_class = &phase_class,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = phase_inputs,
+ .outputs = phase_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index 0c5b7a16f4..790dd0d9c2 100644
--- a/libavfilter/vf_pixdesctest.c
+++ b/libavfilter/vf_pixdesctest.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,7 +47,7 @@ static int config_props(AVFilterLink *inlink)
priv->pix_desc = av_pix_fmt_desc_get(inlink->format);
av_freep(&priv->line);
- if (!(priv->line = av_malloc(sizeof(*priv->line) * inlink->w)))
+ if (!(priv->line = av_malloc_array(sizeof(*priv->line), inlink->w)))
return AVERROR(ENOMEM);
return 0;
@@ -59,6 +59,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
AVFilterLink *outlink = inlink->dst->outputs[0];
AVFrame *out;
int i, c, w = inlink->w, h = inlink->h;
+ const int cw = FF_CEIL_RSHIFT(w, priv->pix_desc->log2_chroma_w);
+ const int ch = FF_CEIL_RSHIFT(h, priv->pix_desc->log2_chroma_h);
out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
if (!out) {
@@ -69,27 +71,26 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
av_frame_copy_props(out, in);
for (i = 0; i < 4; i++) {
- int h = outlink->h;
- h = i == 1 || i == 2 ? h>>priv->pix_desc->log2_chroma_h : h;
+ const int h1 = i == 1 || i == 2 ? ch : h;
if (out->data[i]) {
uint8_t *data = out->data[i] +
- (out->linesize[i] > 0 ? 0 : out->linesize[i] * (h-1));
- memset(data, 0, FFABS(out->linesize[i]) * h);
+ (out->linesize[i] > 0 ? 0 : out->linesize[i] * (h1-1));
+ memset(data, 0, FFABS(out->linesize[i]) * h1);
}
}
/* copy palette */
if (priv->pix_desc->flags & AV_PIX_FMT_FLAG_PAL ||
priv->pix_desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)
- memcpy(out->data[1], in->data[1], 256*4);
+ memcpy(out->data[1], in->data[1], AVPALETTE_SIZE);
for (c = 0; c < priv->pix_desc->nb_components; c++) {
- int w1 = c == 1 || c == 2 ? w>>priv->pix_desc->log2_chroma_w : w;
- int h1 = c == 1 || c == 2 ? h>>priv->pix_desc->log2_chroma_h : h;
+ const int w1 = c == 1 || c == 2 ? cw : w;
+ const int h1 = c == 1 || c == 2 ? ch : h;
for (i = 0; i < h1; i++) {
av_read_image_line(priv->line,
- in->data,
+ (void*)in->data,
in->linesize,
priv->pix_desc,
0, i, c, w1, 0);
@@ -127,11 +128,8 @@ static const AVFilterPad avfilter_vf_pixdesctest_outputs[] = {
AVFilter ff_vf_pixdesctest = {
.name = "pixdesctest",
.description = NULL_IF_CONFIG_SMALL("Test pixel format definitions."),
-
- .priv_size = sizeof(PixdescTestContext),
- .uninit = uninit,
-
- .inputs = avfilter_vf_pixdesctest_inputs,
-
- .outputs = avfilter_vf_pixdesctest_outputs,
+ .priv_size = sizeof(PixdescTestContext),
+ .uninit = uninit,
+ .inputs = avfilter_vf_pixdesctest_inputs,
+ .outputs = avfilter_vf_pixdesctest_outputs,
};
diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c
new file mode 100644
index 0000000000..bac1d53356
--- /dev/null
+++ b/libavfilter/vf_pp.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2002 A'rpi
+ * Copyright (C) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ * libpostproc filter, ported from MPlayer.
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+
+#include "libpostproc/postprocess.h"
+
+typedef struct {
+ const AVClass *class;
+ char *subfilters;
+ int mode_id;
+ pp_mode *modes[PP_QUALITY_MAX + 1];
+ void *pp_ctx;
+} PPFilterContext;
+
+#define OFFSET(x) offsetof(PPFilterContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption pp_options[] = {
+ { "subfilters", "set postprocess subfilters", OFFSET(subfilters), AV_OPT_TYPE_STRING, {.str="de"}, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(pp);
+
+static av_cold int pp_init(AVFilterContext *ctx)
+{
+ int i;
+ PPFilterContext *pp = ctx->priv;
+
+ for (i = 0; i <= PP_QUALITY_MAX; i++) {
+ pp->modes[i] = pp_get_mode_by_name_and_quality(pp->subfilters, i);
+ if (!pp->modes[i])
+ return AVERROR_EXTERNAL;
+ }
+ pp->mode_id = PP_QUALITY_MAX;
+ return 0;
+}
+
+static int pp_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ PPFilterContext *pp = ctx->priv;
+
+ if (!strcmp(cmd, "quality")) {
+ pp->mode_id = av_clip(strtol(args, NULL, 10), 0, PP_QUALITY_MAX);
+ return 0;
+ }
+ return AVERROR(ENOSYS);
+}
+
+static int pp_query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_GBRP,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int pp_config_props(AVFilterLink *inlink)
+{
+ int flags = PP_CPU_CAPS_AUTO;
+ PPFilterContext *pp = inlink->dst->priv;
+
+ switch (inlink->format) {
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_YUVJ420P:
+ case AV_PIX_FMT_YUV420P: flags |= PP_FORMAT_420; break;
+ case AV_PIX_FMT_YUVJ422P:
+ case AV_PIX_FMT_YUV422P: flags |= PP_FORMAT_422; break;
+ case AV_PIX_FMT_YUV411P: flags |= PP_FORMAT_411; break;
+ case AV_PIX_FMT_GBRP:
+ case AV_PIX_FMT_YUVJ444P:
+ case AV_PIX_FMT_YUV444P: flags |= PP_FORMAT_444; break;
+ case AV_PIX_FMT_YUVJ440P:
+ case AV_PIX_FMT_YUV440P: flags |= PP_FORMAT_440; break;
+ default: av_assert0(0);
+ }
+
+ pp->pp_ctx = pp_get_context(inlink->w, inlink->h, flags);
+ if (!pp->pp_ctx)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static int pp_filter_frame(AVFilterLink *inlink, AVFrame *inbuf)
+{
+ AVFilterContext *ctx = inlink->dst;
+ PPFilterContext *pp = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ const int aligned_w = FFALIGN(outlink->w, 8);
+ const int aligned_h = FFALIGN(outlink->h, 8);
+ AVFrame *outbuf;
+ int qstride, qp_type;
+ int8_t *qp_table ;
+
+ outbuf = ff_get_video_buffer(outlink, aligned_w, aligned_h);
+ if (!outbuf) {
+ av_frame_free(&inbuf);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outbuf, inbuf);
+ outbuf->width = inbuf->width;
+ outbuf->height = inbuf->height;
+ qp_table = av_frame_get_qp_table(inbuf, &qstride, &qp_type);
+
+ pp_postprocess((const uint8_t **)inbuf->data, inbuf->linesize,
+ outbuf->data, outbuf->linesize,
+ aligned_w, outlink->h,
+ qp_table,
+ qstride,
+ pp->modes[pp->mode_id],
+ pp->pp_ctx,
+ outbuf->pict_type | (qp_type ? PP_PICT_TYPE_QP2 : 0));
+
+ av_frame_free(&inbuf);
+ return ff_filter_frame(outlink, outbuf);
+}
+
+static av_cold void pp_uninit(AVFilterContext *ctx)
+{
+ int i;
+ PPFilterContext *pp = ctx->priv;
+
+ for (i = 0; i <= PP_QUALITY_MAX; i++)
+ pp_free_mode(pp->modes[i]);
+ if (pp->pp_ctx)
+ pp_free_context(pp->pp_ctx);
+}
+
+static const AVFilterPad pp_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = pp_config_props,
+ .filter_frame = pp_filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad pp_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_pp = {
+ .name = "pp",
+ .description = NULL_IF_CONFIG_SMALL("Filter video using libpostproc."),
+ .priv_size = sizeof(PPFilterContext),
+ .init = pp_init,
+ .uninit = pp_uninit,
+ .query_formats = pp_query_formats,
+ .inputs = pp_inputs,
+ .outputs = pp_outputs,
+ .process_command = pp_process_command,
+ .priv_class = &pp_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_pp7.c b/libavfilter/vf_pp7.c
new file mode 100644
index 0000000000..9e78c39ac7
--- /dev/null
+++ b/libavfilter/vf_pp7.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2014 Arwa Arif <arwaarif1994@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 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
+ * Postprocessing filter - 7
+ *
+ * Originally written by Michael Niedermayer for the MPlayer
+ * project, and ported by Arwa Arif for FFmpeg.
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+#include "vf_pp7.h"
+
+enum mode {
+ MODE_HARD,
+ MODE_SOFT,
+ MODE_MEDIUM
+};
+
+#define OFFSET(x) offsetof(PP7Context, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption pp7_options[] = {
+ { "qp", "force a constant quantizer parameter", OFFSET(qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 64, FLAGS },
+ { "mode", "set thresholding mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_MEDIUM}, 0, 2, FLAGS, "mode" },
+ { "hard", "hard thresholding", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_HARD}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "soft", "soft thresholding", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_SOFT}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "medium", "medium thresholding", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_MEDIUM}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(pp7);
+
+DECLARE_ALIGNED(8, static const uint8_t, dither)[8][8] = {
+ { 0, 48, 12, 60, 3, 51, 15, 63, },
+ { 32, 16, 44, 28, 35, 19, 47, 31, },
+ { 8, 56, 4, 52, 11, 59, 7, 55, },
+ { 40, 24, 36, 20, 43, 27, 39, 23, },
+ { 2, 50, 14, 62, 1, 49, 13, 61, },
+ { 34, 18, 46, 30, 33, 17, 45, 29, },
+ { 10, 58, 6, 54, 9, 57, 5, 53, },
+ { 42, 26, 38, 22, 41, 25, 37, 21, },
+};
+
+#define N0 4
+#define N1 5
+#define N2 10
+#define SN0 2
+#define SN1 2.2360679775
+#define SN2 3.16227766017
+#define N (1 << 16)
+
+static const int factor[16] = {
+ N / (N0 * N0), N / (N0 * N1), N / (N0 * N0), N / (N0 * N2),
+ N / (N1 * N0), N / (N1 * N1), N / (N1 * N0), N / (N1 * N2),
+ N / (N0 * N0), N / (N0 * N1), N / (N0 * N0), N / (N0 * N2),
+ N / (N2 * N0), N / (N2 * N1), N / (N2 * N0), N / (N2 * N2),
+};
+
+static void init_thres2(PP7Context *p)
+{
+ int qp, i;
+ int bias = 0; //FIXME
+
+ for (qp = 0; qp < 99; qp++) {
+ for (i = 0; i < 16; i++) {
+ p->thres2[qp][i] = ((i&1) ? SN2 : SN0) * ((i&4) ? SN2 : SN0) * FFMAX(1, qp) * (1<<2) - 1 - bias;
+ }
+ }
+}
+
+static inline void dctA_c(int16_t *dst, uint8_t *src, int stride)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ int s0 = src[0 * stride] + src[6 * stride];
+ int s1 = src[1 * stride] + src[5 * stride];
+ int s2 = src[2 * stride] + src[4 * stride];
+ int s3 = src[3 * stride];
+ int s = s3 + s3;
+ s3 = s - s0;
+ s0 = s + s0;
+ s = s2 + s1;
+ s2 = s2 - s1;
+ dst[0] = s0 + s;
+ dst[2] = s0 - s;
+ dst[1] = 2 * s3 + s2;
+ dst[3] = s3 - 2 * s2;
+ src++;
+ dst += 4;
+ }
+}
+
+static void dctB_c(int16_t *dst, int16_t *src)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ int s0 = src[0 * 4] + src[6 * 4];
+ int s1 = src[1 * 4] + src[5 * 4];
+ int s2 = src[2 * 4] + src[4 * 4];
+ int s3 = src[3 * 4];
+ int s = s3 + s3;
+ s3 = s - s0;
+ s0 = s + s0;
+ s = s2 + s1;
+ s2 = s2 - s1;
+ dst[0 * 4] = s0 + s;
+ dst[2 * 4] = s0 - s;
+ dst[1 * 4] = 2 * s3 + s2;
+ dst[3 * 4] = s3 - 2 * s2;
+ src++;
+ dst++;
+ }
+}
+
+static int hardthresh_c(PP7Context *p, int16_t *src, int qp)
+{
+ int i;
+ int a;
+
+ a = src[0] * factor[0];
+ for (i = 1; i < 16; i++) {
+ unsigned int threshold1 = p->thres2[qp][i];
+ unsigned int threshold2 = threshold1 << 1;
+ int level = src[i];
+ if (((unsigned)(level + threshold1)) > threshold2)
+ a += level * factor[i];
+ }
+ return (a + (1 << 11)) >> 12;
+}
+
+static int mediumthresh_c(PP7Context *p, int16_t *src, int qp)
+{
+ int i;
+ int a;
+
+ a = src[0] * factor[0];
+ for (i = 1; i < 16; i++) {
+ unsigned int threshold1 = p->thres2[qp][i];
+ unsigned int threshold2 = threshold1 << 1;
+ int level = src[i];
+ if (((unsigned)(level + threshold1)) > threshold2) {
+ if (((unsigned)(level + 2 * threshold1)) > 2 * threshold2)
+ a += level * factor[i];
+ else {
+ if (level > 0)
+ a += 2 * (level - (int)threshold1) * factor[i];
+ else
+ a += 2 * (level + (int)threshold1) * factor[i];
+ }
+ }
+ }
+ return (a + (1 << 11)) >> 12;
+}
+
+static int softthresh_c(PP7Context *p, int16_t *src, int qp)
+{
+ int i;
+ int a;
+
+ a = src[0] * factor[0];
+ for (i = 1; i < 16; i++) {
+ unsigned int threshold1 = p->thres2[qp][i];
+ unsigned int threshold2 = threshold1 << 1;
+ int level = src[i];
+ if (((unsigned)(level + threshold1)) > threshold2) {
+ if (level > 0)
+ a += (level - (int)threshold1) * factor[i];
+ else
+ a += (level + (int)threshold1) * factor[i];
+ }
+ }
+ return (a + (1 << 11)) >> 12;
+}
+
+static void filter(PP7Context *p, uint8_t *dst, uint8_t *src,
+ int dst_stride, int src_stride,
+ int width, int height,
+ uint8_t *qp_store, int qp_stride, int is_luma)
+{
+ int x, y;
+ const int stride = is_luma ? p->temp_stride : ((width + 16 + 15) & (~15));
+ uint8_t *p_src = p->src + 8 * stride;
+ int16_t *block = (int16_t *)p->src;
+ int16_t *temp = (int16_t *)(p->src + 32);
+
+ if (!src || !dst) return;
+ for (y = 0; y < height; y++) {
+ int index = 8 + 8 * stride + y * stride;
+ memcpy(p_src + index, src + y * src_stride, width);
+ for (x = 0; x < 8; x++) {
+ p_src[index - x - 1]= p_src[index + x ];
+ p_src[index + width + x ]= p_src[index + width - x - 1];
+ }
+ }
+ for (y = 0; y < 8; y++) {
+ memcpy(p_src + ( 7 - y ) * stride, p_src + ( y + 8 ) * stride, stride);
+ memcpy(p_src + (height + 8 + y) * stride, p_src + (height - y + 7) * stride, stride);
+ }
+ //FIXME (try edge emu)
+
+ for (y = 0; y < height; y++) {
+ for (x = -8; x < 0; x += 4) {
+ const int index = x + y * stride + (8 - 3) * (1 + stride) + 8; //FIXME silly offset
+ uint8_t *src = p_src + index;
+ int16_t *tp = temp + 4 * x;
+
+ dctA_c(tp + 4 * 8, src, stride);
+ }
+ for (x = 0; x < width; ) {
+ const int qps = 3 + is_luma;
+ int qp;
+ int end = FFMIN(x + 8, width);
+
+ if (p->qp)
+ qp = p->qp;
+ else {
+ qp = qp_store[ (FFMIN(x, width - 1) >> qps) + (FFMIN(y, height - 1) >> qps) * qp_stride];
+ qp = ff_norm_qscale(qp, p->qscale_type);
+ }
+ for (; x < end; x++) {
+ const int index = x + y * stride + (8 - 3) * (1 + stride) + 8; //FIXME silly offset
+ uint8_t *src = p_src + index;
+ int16_t *tp = temp + 4 * x;
+ int v;
+
+ if ((x & 3) == 0)
+ dctA_c(tp + 4 * 8, src, stride);
+
+ p->dctB(block, tp);
+
+ v = p->requantize(p, block, qp);
+ v = (v + dither[y & 7][x & 7]) >> 6;
+ if ((unsigned)v > 255)
+ v = (-v) >> 31;
+ dst[x + y * dst_stride] = v;
+ }
+ }
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_GBRP,
+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ PP7Context *pp7 = ctx->priv;
+ const int h = FFALIGN(inlink->h + 16, 16);
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ pp7->hsub = desc->log2_chroma_w;
+ pp7->vsub = desc->log2_chroma_h;
+
+ pp7->temp_stride = FFALIGN(inlink->w + 16, 16);
+ pp7->src = av_malloc_array(pp7->temp_stride, (h + 8) * sizeof(uint8_t));
+
+ if (!pp7->src)
+ return AVERROR(ENOMEM);
+
+ init_thres2(pp7);
+
+ switch (pp7->mode) {
+ case 0: pp7->requantize = hardthresh_c; break;
+ case 1: pp7->requantize = softthresh_c; break;
+ default:
+ case 2: pp7->requantize = mediumthresh_c; break;
+ }
+
+ pp7->dctB = dctB_c;
+
+ if (ARCH_X86)
+ ff_pp7_init_x86(pp7);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ PP7Context *pp7 = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out = in;
+
+ int qp_stride = 0;
+ uint8_t *qp_table = NULL;
+
+ if (!pp7->qp)
+ qp_table = av_frame_get_qp_table(in, &qp_stride, &pp7->qscale_type);
+
+ if (!ctx->is_disabled) {
+ const int cw = FF_CEIL_RSHIFT(inlink->w, pp7->hsub);
+ const int ch = FF_CEIL_RSHIFT(inlink->h, pp7->vsub);
+
+ /* get a new frame if in-place is not possible or if the dimensions
+ * are not multiple of 8 */
+ if (!av_frame_is_writable(in) || (inlink->w & 7) || (inlink->h & 7)) {
+ const int aligned_w = FFALIGN(inlink->w, 8);
+ const int aligned_h = FFALIGN(inlink->h, 8);
+
+ out = ff_get_video_buffer(outlink, aligned_w, aligned_h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ out->width = in->width;
+ out->height = in->height;
+ }
+
+ if (qp_table || pp7->qp) {
+
+ filter(pp7, out->data[0], in->data[0], out->linesize[0], in->linesize[0],
+ inlink->w, inlink->h, qp_table, qp_stride, 1);
+ filter(pp7, out->data[1], in->data[1], out->linesize[1], in->linesize[1],
+ cw, ch, qp_table, qp_stride, 0);
+ filter(pp7, out->data[2], in->data[2], out->linesize[2], in->linesize[2],
+ cw, ch, qp_table, qp_stride, 0);
+ emms_c();
+ }
+ }
+
+ if (in != out) {
+ if (in->data[3])
+ av_image_copy_plane(out->data[3], out->linesize[3],
+ in ->data[3], in ->linesize[3],
+ inlink->w, inlink->h);
+ av_frame_free(&in);
+ }
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ PP7Context *pp7 = ctx->priv;
+ av_freep(&pp7->src);
+}
+
+static const AVFilterPad pp7_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad pp7_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_pp7 = {
+ .name = "pp7",
+ .description = NULL_IF_CONFIG_SMALL("Apply Postprocessing 7 filter."),
+ .priv_size = sizeof(PP7Context),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = pp7_inputs,
+ .outputs = pp7_outputs,
+ .priv_class = &pp7_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_pp7.h b/libavfilter/vf_pp7.h
new file mode 100644
index 0000000000..9aa8d732c1
--- /dev/null
+++ b/libavfilter/vf_pp7.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2014 Arwa Arif <arwaarif1994@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 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.
+ */
+
+#ifndef AVFILTER_PP7_H
+#define AVFILTER_PP7_H
+
+#include "avfilter.h"
+
+typedef struct PP7Context {
+ AVClass *class;
+ int thres2[99][16];
+
+ int qp;
+ int mode;
+ int qscale_type;
+ int hsub;
+ int vsub;
+ int temp_stride;
+ uint8_t *src;
+
+ int (*requantize)(struct PP7Context *p, int16_t *src, int qp);
+ void (*dctB)(int16_t *dst, int16_t *src);
+
+} PP7Context;
+
+void ff_pp7_init_x86(PP7Context *pp7);
+
+#endif /* AVFILTER_PP7_H */
diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c
new file mode 100644
index 0000000000..406be881a6
--- /dev/null
+++ b/libavfilter/vf_psnr.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2011 Roger Pau Monné <roger.pau@entel.upc.edu>
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Caculate the PSNR between two input videos.
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "dualinput.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct PSNRContext {
+ const AVClass *class;
+ FFDualInputContext dinput;
+ double mse, min_mse, max_mse;
+ uint64_t nb_frames;
+ FILE *stats_file;
+ char *stats_file_str;
+ int max[4], average_max;
+ int is_rgb;
+ uint8_t rgba_map[4];
+ char comps[4];
+ int nb_components;
+ int planewidth[4];
+ int planeheight[4];
+
+ void (*compute_mse)(struct PSNRContext *s,
+ const uint8_t *m[4], const int ml[4],
+ const uint8_t *r[4], const int rl[4],
+ int w, int h, double mse[4]);
+} PSNRContext;
+
+#define OFFSET(x) offsetof(PSNRContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption psnr_options[] = {
+ {"stats_file", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
+ {"f", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(psnr);
+
+static inline unsigned pow2(unsigned base)
+{
+ return base*base;
+}
+
+static inline double get_psnr(double mse, uint64_t nb_frames, int max)
+{
+ return 10.0 * log(pow2(max) / (mse / nb_frames)) / log(10.0);
+}
+
+static inline
+void compute_images_mse(PSNRContext *s,
+ const uint8_t *main_data[4], const int main_linesizes[4],
+ const uint8_t *ref_data[4], const int ref_linesizes[4],
+ int w, int h, double mse[4])
+{
+ int i, c, j;
+
+ for (c = 0; c < s->nb_components; c++) {
+ const int outw = s->planewidth[c];
+ const int outh = s->planeheight[c];
+ const uint8_t *main_line = main_data[c];
+ const uint8_t *ref_line = ref_data[c];
+ const int ref_linesize = ref_linesizes[c];
+ const int main_linesize = main_linesizes[c];
+ uint64_t m = 0;
+
+ for (i = 0; i < outh; i++) {
+ int m2 = 0;
+ for (j = 0; j < outw; j++)
+ m2 += pow2(main_line[j] - ref_line[j]);
+ m += m2;
+ ref_line += ref_linesize;
+ main_line += main_linesize;
+ }
+ mse[c] = m / (double)(outw * outh);
+ }
+}
+
+static inline
+void compute_images_mse_16bit(PSNRContext *s,
+ const uint8_t *main_data[4], const int main_linesizes[4],
+ const uint8_t *ref_data[4], const int ref_linesizes[4],
+ int w, int h, double mse[4])
+{
+ int i, c, j;
+
+ for (c = 0; c < s->nb_components; c++) {
+ const int outw = s->planewidth[c];
+ const int outh = s->planeheight[c];
+ const uint16_t *main_line = (uint16_t *)main_data[c];
+ const uint16_t *ref_line = (uint16_t *)ref_data[c];
+ const int ref_linesize = ref_linesizes[c] / 2;
+ const int main_linesize = main_linesizes[c] / 2;
+ uint64_t m = 0;
+
+ for (i = 0; i < outh; i++) {
+ for (j = 0; j < outw; j++)
+ m += pow2(main_line[j] - ref_line[j]);
+ ref_line += ref_linesize;
+ main_line += main_linesize;
+ }
+ mse[c] = m / (double)(outw * outh);
+ }
+}
+
+static void set_meta(AVDictionary **metadata, const char *key, char comp, float d)
+{
+ char value[128];
+ snprintf(value, sizeof(value), "%0.2f", 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 AVFrame *do_psnr(AVFilterContext *ctx, AVFrame *main,
+ const AVFrame *ref)
+{
+ PSNRContext *s = ctx->priv;
+ double comp_mse[4], mse = 0;
+ int j, c;
+ AVDictionary **metadata = avpriv_frame_get_metadatap(main);
+
+ s->compute_mse(s, (const uint8_t **)main->data, main->linesize,
+ (const uint8_t **)ref->data, ref->linesize,
+ main->width, main->height, comp_mse);
+
+ for (j = 0; j < s->nb_components; j++)
+ mse += comp_mse[j];
+ mse /= s->nb_components;
+
+ s->min_mse = FFMIN(s->min_mse, mse);
+ s->max_mse = FFMAX(s->max_mse, mse);
+
+ s->mse += mse;
+ s->nb_frames++;
+
+ for (j = 0; j < s->nb_components; j++) {
+ c = s->is_rgb ? s->rgba_map[j] : j;
+ set_meta(metadata, "lavfi.psnr.mse.", s->comps[j], comp_mse[c]);
+ set_meta(metadata, "lavfi.psnr.mse_avg", 0, mse);
+ set_meta(metadata, "lavfi.psnr.psnr.", s->comps[j], get_psnr(comp_mse[c], 1, s->max[c]));
+ set_meta(metadata, "lavfi.psnr.psnr_avg", 0, get_psnr(mse, 1, s->average_max));
+ }
+
+ if (s->stats_file) {
+ fprintf(s->stats_file, "n:%"PRId64" mse_avg:%0.2f ", s->nb_frames, mse);
+ for (j = 0; j < s->nb_components; j++) {
+ c = s->is_rgb ? s->rgba_map[j] : j;
+ fprintf(s->stats_file, "mse_%c:%0.2f ", s->comps[j], comp_mse[c]);
+ }
+ for (j = 0; j < s->nb_components; j++) {
+ c = s->is_rgb ? s->rgba_map[j] : j;
+ fprintf(s->stats_file, "psnr_%c:%0.2f ", s->comps[j],
+ get_psnr(comp_mse[c], 1, s->max[c]));
+ }
+ fprintf(s->stats_file, "\n");
+ }
+
+ return main;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ PSNRContext *s = ctx->priv;
+
+ s->min_mse = +INFINITY;
+ s->max_mse = -INFINITY;
+
+ if (s->stats_file_str) {
+ s->stats_file = fopen(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);
+ return err;
+ }
+ }
+
+ s->dinput.process = do_psnr;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_GRAY8, 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_GBRAP16,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input_ref(AVFilterLink *inlink)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ AVFilterContext *ctx = inlink->dst;
+ PSNRContext *s = ctx->priv;
+ int j;
+
+ s->nb_components = desc->nb_components;
+ 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 input videos must be same.\n");
+ return AVERROR(EINVAL);
+ }
+ if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
+ av_log(ctx, AV_LOG_ERROR, "Inputs must be of same pixel format.\n");
+ return AVERROR(EINVAL);
+ }
+
+ switch (inlink->format) {
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_GRAY16:
+ case AV_PIX_FMT_GBRP:
+ case AV_PIX_FMT_GBRP9:
+ case AV_PIX_FMT_GBRP10:
+ case AV_PIX_FMT_GBRP12:
+ case AV_PIX_FMT_GBRP14:
+ case AV_PIX_FMT_GBRP16:
+ case AV_PIX_FMT_GBRAP:
+ case AV_PIX_FMT_GBRAP16:
+ case AV_PIX_FMT_YUVJ411P:
+ case AV_PIX_FMT_YUVJ420P:
+ case AV_PIX_FMT_YUVJ422P:
+ case AV_PIX_FMT_YUVJ440P:
+ case AV_PIX_FMT_YUVJ444P:
+ s->max[0] = (1 << (desc->comp[0].depth_minus1 + 1)) - 1;
+ s->max[1] = (1 << (desc->comp[1].depth_minus1 + 1)) - 1;
+ s->max[2] = (1 << (desc->comp[2].depth_minus1 + 1)) - 1;
+ s->max[3] = (1 << (desc->comp[3].depth_minus1 + 1)) - 1;
+ break;
+ default:
+ s->max[0] = 235 * (1 << (desc->comp[0].depth_minus1 - 7));
+ s->max[1] = 240 * (1 << (desc->comp[1].depth_minus1 - 7));
+ s->max[2] = 240 * (1 << (desc->comp[2].depth_minus1 - 7));
+ s->max[3] = (1 << (desc->comp[3].depth_minus1 + 1)) - 1;
+ }
+
+ 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';
+
+ for (j = 0; j < s->nb_components; j++)
+ s->average_max += s->max[j];
+ s->average_max /= s->nb_components;
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+ s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
+ s->planewidth[0] = s->planewidth[3] = inlink->w;
+
+ s->compute_mse = desc->comp[0].depth_minus1 > 7 ? compute_images_mse_16bit : compute_images_mse;
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ PSNRContext *s = ctx->priv;
+ AVFilterLink *mainlink = ctx->inputs[0];
+ int ret;
+
+ outlink->w = mainlink->w;
+ outlink->h = mainlink->h;
+ outlink->time_base = mainlink->time_base;
+ outlink->sample_aspect_ratio = mainlink->sample_aspect_ratio;
+ outlink->frame_rate = mainlink->frame_rate;
+ if ((ret = ff_dualinput_init(ctx, &s->dinput)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ PSNRContext *s = inlink->dst->priv;
+ return ff_dualinput_filter_frame(&s->dinput, inlink, inpicref);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ PSNRContext *s = outlink->src->priv;
+ return ff_dualinput_request_frame(&s->dinput, outlink);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ PSNRContext *s = ctx->priv;
+
+ if (s->nb_frames > 0) {
+ av_log(ctx, AV_LOG_INFO, "PSNR average:%0.2f min:%0.2f max:%0.2f\n",
+ get_psnr(s->mse, s->nb_frames, s->average_max),
+ get_psnr(s->max_mse, 1, s->average_max),
+ get_psnr(s->min_mse, 1, s->average_max));
+ }
+
+ ff_dualinput_uninit(&s->dinput);
+
+ if (s->stats_file)
+ fclose(s->stats_file);
+}
+
+static const AVFilterPad psnr_inputs[] = {
+ {
+ .name = "main",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },{
+ .name = "reference",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input_ref,
+ },
+ { NULL }
+};
+
+static const AVFilterPad psnr_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_psnr = {
+ .name = "psnr",
+ .description = NULL_IF_CONFIG_SMALL("Calculate the PSNR between two video streams."),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(PSNRContext),
+ .priv_class = &psnr_class,
+ .inputs = psnr_inputs,
+ .outputs = psnr_outputs,
+};
diff --git a/libavfilter/vf_pullup.c b/libavfilter/vf_pullup.c
new file mode 100644
index 0000000000..ea15019ab0
--- /dev/null
+++ b/libavfilter/vf_pullup.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 2003 Rich Felker
+ *
+ * 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/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "vf_pullup.h"
+
+#define F_HAVE_BREAKS 1
+#define F_HAVE_AFFINITY 2
+
+#define BREAK_LEFT 1
+#define BREAK_RIGHT 2
+
+#define OFFSET(x) offsetof(PullupContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption pullup_options[] = {
+ { "jl", "set left junk size", OFFSET(junk_left), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS },
+ { "jr", "set right junk size", OFFSET(junk_right), AV_OPT_TYPE_INT, {.i64=1}, 0, INT_MAX, FLAGS },
+ { "jt", "set top junk size", OFFSET(junk_top), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS },
+ { "jb", "set bottom junk size", OFFSET(junk_bottom), AV_OPT_TYPE_INT, {.i64=4}, 1, INT_MAX, FLAGS },
+ { "sb", "set strict breaks", OFFSET(strict_breaks), AV_OPT_TYPE_INT, {.i64=0},-1, 1, FLAGS },
+ { "mp", "set metric plane", OFFSET(metric_plane), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "mp" },
+ { "y", "luma", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mp" },
+ { "u", "chroma blue", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mp" },
+ { "v", "chroma red", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mp" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(pullup);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+#define ABS(a) (((a) ^ ((a) >> 31)) - ((a) >> 31))
+
+static int diff_c(const uint8_t *a, const uint8_t *b, ptrdiff_t s)
+{
+ int i, j, diff = 0;
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++)
+ diff += ABS(a[j] - b[j]);
+ a += s;
+ b += s;
+ }
+
+ return diff;
+}
+
+static int comb_c(const uint8_t *a, const uint8_t *b, ptrdiff_t s)
+{
+ int i, j, comb = 0;
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++)
+ comb += ABS((a[j] << 1) - b[j - s] - b[j ]) +
+ ABS((b[j] << 1) - a[j ] - a[j + s]);
+ a += s;
+ b += s;
+ }
+
+ return comb;
+}
+
+static int var_c(const uint8_t *a, const uint8_t *b, ptrdiff_t s)
+{
+ int i, j, var = 0;
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 8; j++)
+ var += ABS(a[j] - a[j + s]);
+ a += s;
+ }
+
+ return 4 * var; /* match comb scaling */
+}
+
+static int alloc_metrics(PullupContext *s, PullupField *f)
+{
+ f->diffs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->diffs));
+ f->combs = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->combs));
+ f->vars = av_calloc(FFALIGN(s->metric_length, 16), sizeof(*f->vars));
+
+ if (!f->diffs || !f->combs || !f->vars) {
+ av_freep(&f->diffs);
+ av_freep(&f->combs);
+ av_freep(&f->vars);
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+}
+
+static void free_field_queue(PullupField *head)
+{
+ PullupField *f = head;
+ do {
+ PullupField *next;
+ if (!f)
+ break;
+ av_free(f->diffs);
+ av_free(f->combs);
+ av_free(f->vars);
+ next = f->next;
+ memset(f, 0, sizeof(*f)); // clear all pointers to avoid stale ones
+ av_free(f);
+ f = next;
+ } while (f != head);
+}
+
+static PullupField *make_field_queue(PullupContext *s, int len)
+{
+ PullupField *head, *f;
+
+ f = head = av_mallocz(sizeof(*head));
+ if (!f)
+ return NULL;
+
+ if (alloc_metrics(s, f) < 0) {
+ av_free(f);
+ return NULL;
+ }
+
+ for (; len > 0; len--) {
+ f->next = av_mallocz(sizeof(*f->next));
+ if (!f->next) {
+ free_field_queue(head);
+ return NULL;
+ }
+
+ f->next->prev = f;
+ f = f->next;
+ if (alloc_metrics(s, f) < 0) {
+ free_field_queue(head);
+ return NULL;
+ }
+ }
+
+ f->next = head;
+ head->prev = f;
+
+ return head;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ PullupContext *s = ctx->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int mp = s->metric_plane;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ if (mp + 1 > s->nb_planes) {
+ av_log(ctx, AV_LOG_ERROR, "input format does not have such plane\n");
+ return AVERROR(EINVAL);
+ }
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+ s->planewidth[1] = s->planewidth[2] = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
+ s->planewidth[0] = s->planewidth[3] = inlink->w;
+
+ s->metric_w = (s->planewidth[mp] - ((s->junk_left + s->junk_right) << 3)) >> 3;
+ s->metric_h = (s->planeheight[mp] - ((s->junk_top + s->junk_bottom) << 1)) >> 3;
+ s->metric_offset = (s->junk_left << 3) + (s->junk_top << 1) * s->planewidth[mp];
+ s->metric_length = s->metric_w * s->metric_h;
+
+ av_log(ctx, AV_LOG_DEBUG, "w: %d h: %d\n", s->metric_w, s->metric_h);
+ av_log(ctx, AV_LOG_DEBUG, "offset: %d length: %d\n", s->metric_offset, s->metric_length);
+
+ s->head = make_field_queue(s, 8);
+ if (!s->head)
+ return AVERROR(ENOMEM);
+
+ s->diff = diff_c;
+ s->comb = comb_c;
+ s->var = var_c;
+
+ if (ARCH_X86)
+ ff_pullup_init_x86(s);
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ return 0;
+}
+
+static PullupBuffer *pullup_lock_buffer(PullupBuffer *b, int parity)
+{
+ if (!b)
+ return NULL;
+
+ if ((parity + 1) & 1)
+ b->lock[0]++;
+ if ((parity + 1) & 2)
+ b->lock[1]++;
+
+ return b;
+}
+
+static void pullup_release_buffer(PullupBuffer *b, int parity)
+{
+ if (!b)
+ return;
+
+ if ((parity + 1) & 1)
+ b->lock[0]--;
+ if ((parity + 1) & 2)
+ b->lock[1]--;
+}
+
+static int alloc_buffer(PullupContext *s, PullupBuffer *b)
+{
+ int i;
+
+ if (b->planes[0])
+ return 0;
+ for (i = 0; i < s->nb_planes; i++) {
+ b->planes[i] = av_malloc(s->planeheight[i] * s->planewidth[i]);
+ }
+ if (s->nb_planes == 1)
+ b->planes[1] = av_malloc(4*256);
+
+ return 0;
+}
+
+static PullupBuffer *pullup_get_buffer(PullupContext *s, int parity)
+{
+ int i;
+
+ /* Try first to get the sister buffer for the previous field */
+ if (parity < 2 && s->last && parity != s->last->parity
+ && !s->last->buffer->lock[parity]) {
+ alloc_buffer(s, s->last->buffer);
+ return pullup_lock_buffer(s->last->buffer, parity);
+ }
+
+ /* Prefer a buffer with both fields open */
+ for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) {
+ if (s->buffers[i].lock[0])
+ continue;
+ if (s->buffers[i].lock[1])
+ continue;
+ alloc_buffer(s, &s->buffers[i]);
+ return pullup_lock_buffer(&s->buffers[i], parity);
+ }
+
+ if (parity == 2)
+ return 0;
+
+ /* Search for any half-free buffer */
+ for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) {
+ if (((parity + 1) & 1) && s->buffers[i].lock[0])
+ continue;
+ if (((parity + 1) & 2) && s->buffers[i].lock[1])
+ continue;
+ alloc_buffer(s, &s->buffers[i]);
+ return pullup_lock_buffer(&s->buffers[i], parity);
+ }
+
+ return NULL;
+}
+
+static int queue_length(PullupField *begin, PullupField *end)
+{
+ PullupField *f;
+ int count = 1;
+
+ if (!begin || !end)
+ return 0;
+
+ for (f = begin; f != end; f = f->next)
+ count++;
+
+ return count;
+}
+
+static int find_first_break(PullupField *f, int max)
+{
+ int i;
+
+ for (i = 0; i < max; i++) {
+ if (f->breaks & BREAK_RIGHT || f->next->breaks & BREAK_LEFT)
+ return i + 1;
+ f = f->next;
+ }
+
+ return 0;
+}
+
+static void compute_breaks(PullupContext *s, PullupField *f0)
+{
+ PullupField *f1 = f0->next;
+ PullupField *f2 = f1->next;
+ PullupField *f3 = f2->next;
+ int i, l, max_l = 0, max_r = 0;
+
+ if (f0->flags & F_HAVE_BREAKS)
+ return;
+
+ f0->flags |= F_HAVE_BREAKS;
+
+ /* Special case when fields are 100% identical */
+ if (f0->buffer == f2->buffer && f1->buffer != f3->buffer) {
+ f2->breaks |= BREAK_RIGHT;
+ return;
+ }
+
+ if (f0->buffer != f2->buffer && f1->buffer == f3->buffer) {
+ f1->breaks |= BREAK_LEFT;
+ return;
+ }
+
+ for (i = 0; i < s->metric_length; i++) {
+ l = f2->diffs[i] - f3->diffs[i];
+
+ if ( l > max_l)
+ max_l = l;
+ if (-l > max_r)
+ max_r = -l;
+ }
+
+ /* Don't get tripped up when differences are mostly quant error */
+ if (max_l + max_r < 128)
+ return;
+ if (max_l > 4 * max_r)
+ f1->breaks |= BREAK_LEFT;
+ if (max_r > 4 * max_l)
+ f2->breaks |= BREAK_RIGHT;
+}
+
+static void compute_affinity(PullupContext *s, PullupField *f)
+{
+ int i, max_l = 0, max_r = 0, l;
+
+ if (f->flags & F_HAVE_AFFINITY)
+ return;
+
+ f->flags |= F_HAVE_AFFINITY;
+
+ if (f->buffer == f->next->next->buffer) {
+ f->affinity = 1;
+ f->next->affinity = 0;
+ f->next->next->affinity = -1;
+ f->next->flags |= F_HAVE_AFFINITY;
+ f->next->next->flags |= F_HAVE_AFFINITY;
+ return;
+ }
+
+ for (i = 0; i < s->metric_length; i++) {
+ int v = f->vars[i];
+ int lv = f->prev->vars[i];
+ int rv = f->next->vars[i];
+ int lc = f-> combs[i] - 2*(v < lv ? v : lv);
+ int rc = f->next->combs[i] - 2*(v < rv ? v : rv);
+
+ lc = FFMAX(lc, 0);
+ rc = FFMAX(rc, 0);
+ l = lc - rc;
+
+ if ( l > max_l)
+ max_l = l;
+ if (-l > max_r)
+ max_r = -l;
+ }
+
+ if (max_l + max_r < 64)
+ return;
+
+ if (max_r > 6 * max_l)
+ f->affinity = -1;
+ else if (max_l > 6 * max_r)
+ f->affinity = 1;
+}
+
+static int decide_frame_length(PullupContext *s)
+{
+ PullupField *f0 = s->first;
+ PullupField *f1 = f0->next;
+ PullupField *f2 = f1->next;
+ PullupField *f;
+ int i, l, n;
+
+ if (queue_length(s->first, s->last) < 4)
+ return 0;
+
+ f = s->first;
+ n = queue_length(f, s->last);
+ for (i = 0; i < n - 1; i++) {
+ if (i < n - 3)
+ compute_breaks(s, f);
+
+ compute_affinity(s, f);
+
+ f = f->next;
+ }
+
+ if (f0->affinity == -1)
+ return 1;
+
+ l = find_first_break(f0, 3);
+
+ if (l == 1 && s->strict_breaks < 0)
+ l = 0;
+
+ switch (l) {
+ case 1:
+ return 1 + (s->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1);
+ case 2:
+ /* FIXME: strictly speaking, f0->prev is no longer valid... :) */
+ if (s->strict_pairs
+ && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT)
+ && (f0->affinity != 1 || f1->affinity != -1) )
+ return 1;
+ return 1 + (f1->affinity != 1);
+ case 3:
+ return 2 + (f2->affinity != 1);
+ default:
+ /* 9 possibilities covered before switch */
+ if (f1->affinity == 1)
+ return 1; /* covers 6 */
+ else if (f1->affinity == -1)
+ return 2; /* covers 6 */
+ else if (f2->affinity == -1) { /* covers 2 */
+ return (f0->affinity == 1) ? 3 : 1;
+ } else {
+ return 2; /* the remaining 6 */
+ }
+ }
+}
+
+static PullupFrame *pullup_get_frame(PullupContext *s)
+{
+ PullupFrame *fr = &s->frame;
+ int i, n = decide_frame_length(s);
+ int aff = s->first->next->affinity;
+
+ av_assert1(n < FF_ARRAY_ELEMS(fr->ifields));
+ if (!n || fr->lock)
+ return NULL;
+
+ fr->lock++;
+ fr->length = n;
+ fr->parity = s->first->parity;
+ fr->buffer = 0;
+
+ for (i = 0; i < n; i++) {
+ /* We cheat and steal the buffer without release+relock */
+ fr->ifields[i] = s->first->buffer;
+ s->first->buffer = 0;
+ s->first = s->first->next;
+ }
+
+ if (n == 1) {
+ fr->ofields[fr->parity ] = fr->ifields[0];
+ fr->ofields[fr->parity ^ 1] = 0;
+ } else if (n == 2) {
+ fr->ofields[fr->parity ] = fr->ifields[0];
+ fr->ofields[fr->parity ^ 1] = fr->ifields[1];
+ } else if (n == 3) {
+ if (!aff)
+ aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1;
+ fr->ofields[fr->parity ] = fr->ifields[1 + aff];
+ fr->ofields[fr->parity ^ 1] = fr->ifields[1 ];
+ }
+
+ pullup_lock_buffer(fr->ofields[0], 0);
+ pullup_lock_buffer(fr->ofields[1], 1);
+
+ if (fr->ofields[0] == fr->ofields[1]) {
+ fr->buffer = fr->ofields[0];
+ pullup_lock_buffer(fr->buffer, 2);
+ return fr;
+ }
+
+ return fr;
+}
+
+static void pullup_release_frame(PullupFrame *f)
+{
+ int i;
+
+ for (i = 0; i < f->length; i++)
+ pullup_release_buffer(f->ifields[i], f->parity ^ (i & 1));
+
+ pullup_release_buffer(f->ofields[0], 0);
+ pullup_release_buffer(f->ofields[1], 1);
+
+ if (f->buffer)
+ pullup_release_buffer(f->buffer, 2);
+ f->lock--;
+}
+
+static void compute_metric(PullupContext *s, int *dest,
+ PullupField *fa, int pa, PullupField *fb, int pb,
+ int (*func)(const uint8_t *, const uint8_t *, ptrdiff_t))
+{
+ int mp = s->metric_plane;
+ int xstep = 8;
+ int ystep = s->planewidth[mp] << 3;
+ int stride = s->planewidth[mp] << 1; /* field stride */
+ int w = s->metric_w * xstep;
+ uint8_t *a, *b;
+ int x, y;
+
+ if (!fa->buffer || !fb->buffer)
+ return;
+
+ /* Shortcut for duplicate fields (e.g. from RFF flag) */
+ if (fa->buffer == fb->buffer && pa == pb) {
+ memset(dest, 0, s->metric_length * sizeof(*dest));
+ return;
+ }
+
+ a = fa->buffer->planes[mp] + pa * s->planewidth[mp] + s->metric_offset;
+ b = fb->buffer->planes[mp] + pb * s->planewidth[mp] + s->metric_offset;
+
+ for (y = 0; y < s->metric_h; y++) {
+ for (x = 0; x < w; x += xstep)
+ *dest++ = func(a + x, b + x, stride);
+ a += ystep; b += ystep;
+ }
+}
+
+static int check_field_queue(PullupContext *s)
+{
+ int ret;
+
+ if (s->head->next == s->first) {
+ PullupField *f = av_mallocz(sizeof(*f));
+
+ if (!f)
+ return AVERROR(ENOMEM);
+
+ if ((ret = alloc_metrics(s, f)) < 0) {
+ av_free(f);
+ return ret;
+ }
+
+ f->prev = s->head;
+ f->next = s->first;
+ s->head->next = f;
+ s->first->prev = f;
+ }
+
+ return 0;
+}
+
+static void pullup_submit_field(PullupContext *s, PullupBuffer *b, int parity)
+{
+ PullupField *f;
+
+ /* Grow the circular list if needed */
+ if (check_field_queue(s) < 0)
+ return;
+
+ /* Cannot have two fields of same parity in a row; drop the new one */
+ if (s->last && s->last->parity == parity)
+ return;
+
+ f = s->head;
+ f->parity = parity;
+ f->buffer = pullup_lock_buffer(b, parity);
+ f->flags = 0;
+ f->breaks = 0;
+ f->affinity = 0;
+
+ compute_metric(s, f->diffs, f, parity, f->prev->prev, parity, s->diff);
+ compute_metric(s, f->combs, parity ? f->prev : f, 0, parity ? f : f->prev, 1, s->comb);
+ compute_metric(s, f->vars, f, parity, f, -1, s->var);
+ emms_c();
+
+ /* Advance the circular list */
+ if (!s->first)
+ s->first = s->head;
+
+ s->last = s->head;
+ s->head = s->head->next;
+}
+
+static void copy_field(PullupContext *s,
+ PullupBuffer *dst, PullupBuffer *src, int parity)
+{
+ uint8_t *dd, *ss;
+ int i;
+
+ for (i = 0; i < s->nb_planes; i++) {
+ ss = src->planes[i] + parity * s->planewidth[i];
+ dd = dst->planes[i] + parity * s->planewidth[i];
+
+ av_image_copy_plane(dd, s->planewidth[i] << 1,
+ ss, s->planewidth[i] << 1,
+ s->planewidth[i], s->planeheight[i] >> 1);
+ }
+}
+
+static void pullup_pack_frame(PullupContext *s, PullupFrame *fr)
+{
+ int i;
+
+ if (fr->buffer)
+ return;
+
+ if (fr->length < 2)
+ return; /* FIXME: deal with this */
+
+ for (i = 0; i < 2; i++) {
+ if (fr->ofields[i]->lock[i^1])
+ continue;
+
+ fr->buffer = fr->ofields[i];
+ pullup_lock_buffer(fr->buffer, 2);
+ copy_field(s, fr->buffer, fr->ofields[i^1], i^1);
+ return;
+ }
+
+ fr->buffer = pullup_get_buffer(s, 2);
+
+ copy_field(s, fr->buffer, fr->ofields[0], 0);
+ copy_field(s, fr->buffer, fr->ofields[1], 1);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ PullupContext *s = ctx->priv;
+ PullupBuffer *b;
+ PullupFrame *f;
+ AVFrame *out;
+ int p, ret = 0;
+
+ b = pullup_get_buffer(s, 2);
+ if (!b) {
+ av_log(ctx, AV_LOG_WARNING, "Could not get buffer!\n");
+ f = pullup_get_frame(s);
+ pullup_release_frame(f);
+ goto end;
+ }
+
+ av_image_copy(b->planes, s->planewidth,
+ (const uint8_t**)in->data, in->linesize,
+ inlink->format, inlink->w, inlink->h);
+
+ p = in->interlaced_frame ? !in->top_field_first : 0;
+ pullup_submit_field(s, b, p );
+ pullup_submit_field(s, b, p^1);
+
+ if (in->repeat_pict)
+ pullup_submit_field(s, b, p);
+
+ pullup_release_buffer(b, 2);
+
+ f = pullup_get_frame(s);
+ if (!f)
+ goto end;
+
+ if (f->length < 2) {
+ pullup_release_frame(f);
+ f = pullup_get_frame(s);
+ if (!f)
+ goto end;
+ if (f->length < 2) {
+ pullup_release_frame(f);
+ if (!in->repeat_pict)
+ goto end;
+ f = pullup_get_frame(s);
+ if (!f)
+ goto end;
+ if (f->length < 2) {
+ pullup_release_frame(f);
+ goto end;
+ }
+ }
+ }
+
+ /* If the frame isn't already exportable... */
+ if (!f->buffer)
+ pullup_pack_frame(s, f);
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ av_frame_copy_props(out, in);
+
+ av_image_copy(out->data, out->linesize,
+ (const uint8_t**)f->buffer->planes, s->planewidth,
+ inlink->format, inlink->w, inlink->h);
+
+ ret = ff_filter_frame(outlink, out);
+ pullup_release_frame(f);
+end:
+ av_frame_free(&in);
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ PullupContext *s = ctx->priv;
+ int i;
+
+ free_field_queue(s->head);
+ s->last = NULL;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(s->buffers); i++) {
+ av_freep(&s->buffers[i].planes[0]);
+ av_freep(&s->buffers[i].planes[1]);
+ av_freep(&s->buffers[i].planes[2]);
+ }
+}
+
+static const AVFilterPad pullup_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad pullup_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_pullup = {
+ .name = "pullup",
+ .description = NULL_IF_CONFIG_SMALL("Pullup from field sequence to frames."),
+ .priv_size = sizeof(PullupContext),
+ .priv_class = &pullup_class,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = pullup_inputs,
+ .outputs = pullup_outputs,
+};
diff --git a/libavfilter/vf_pullup.h b/libavfilter/vf_pullup.h
new file mode 100644
index 0000000000..8f59335180
--- /dev/null
+++ b/libavfilter/vf_pullup.h
@@ -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
+ */
+
+#ifndef AVFILTER_PULLUP_H
+#define AVFILTER_PULLUP_H
+
+#include "avfilter.h"
+
+typedef struct PullupBuffer {
+ int lock[2];
+ uint8_t *planes[4];
+} PullupBuffer;
+
+typedef struct PullupField {
+ int parity;
+ PullupBuffer *buffer;
+ unsigned flags;
+ int breaks;
+ int affinity;
+ int *diffs;
+ int *combs;
+ int *vars;
+ struct PullupField *prev, *next;
+} PullupField;
+
+typedef struct PullupFrame {
+ int lock;
+ int length;
+ int parity;
+ PullupBuffer *ifields[4], *ofields[2];
+ PullupBuffer *buffer;
+} PullupFrame;
+
+typedef struct PullupContext {
+ const AVClass *class;
+ int junk_left, junk_right, junk_top, junk_bottom;
+ int metric_plane;
+ int strict_breaks;
+ int strict_pairs;
+ int metric_w, metric_h, metric_length;
+ int metric_offset;
+ int nb_planes;
+ int planewidth[4];
+ int planeheight[4];
+ PullupField *first, *last, *head;
+ PullupBuffer buffers[10];
+ PullupFrame frame;
+
+ int (*diff)(const uint8_t *a, const uint8_t *b, ptrdiff_t s);
+ int (*comb)(const uint8_t *a, const uint8_t *b, ptrdiff_t s);
+ int (*var )(const uint8_t *a, const uint8_t *b, ptrdiff_t s);
+} PullupContext;
+
+void ff_pullup_init_x86(PullupContext *s);
+
+#endif /* AVFILTER_PULLUP_H */
diff --git a/libavfilter/vf_qp.c b/libavfilter/vf_qp.c
new file mode 100644
index 0000000000..33d39493bc
--- /dev/null
+++ b/libavfilter/vf_qp.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <math.h>
+#include "libavutil/eval.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct QPContext {
+ const AVClass *class;
+ char *qp_expr_str;
+ int8_t lut[257];
+ int h, qstride;
+ int evaluate_per_mb;
+} QPContext;
+
+#define OFFSET(x) offsetof(QPContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption qp_options[] = {
+ { "qp", "set qp expression", OFFSET(qp_expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(qp);
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ QPContext *s = ctx->priv;
+ int i;
+ int ret;
+ AVExpr *e = NULL;
+ static const char *var_names[] = { "known", "qp", "x", "y", "w", "h", NULL };
+
+ if (!s->qp_expr_str)
+ return 0;
+
+ ret = av_expr_parse(&e, s->qp_expr_str, var_names, NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0)
+ return ret;
+
+ s->h = (inlink->h + 15) >> 4;
+ s->qstride = (inlink->w + 15) >> 4;
+ for (i = -129; i < 128; i++) {
+ double var_values[] = { i != -129, i, NAN, NAN, s->qstride, s->h, 0};
+ double temp_val = av_expr_eval(e, var_values, NULL);
+
+ if (isnan(temp_val)) {
+ if(strchr(s->qp_expr_str, 'x') || strchr(s->qp_expr_str, 'y'))
+ s->evaluate_per_mb = 1;
+ else {
+ av_expr_free(e);
+ return AVERROR(EINVAL);
+ }
+ }
+
+ s->lut[i + 129] = lrintf(temp_val);
+ }
+ av_expr_free(e);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ QPContext *s = ctx->priv;
+ AVBufferRef *out_qp_table_buf;
+ AVFrame *out = NULL;
+ const int8_t *in_qp_table;
+ int type, stride, ret;
+
+ if (!s->qp_expr_str || ctx->is_disabled)
+ return ff_filter_frame(outlink, in);
+
+ out_qp_table_buf = av_buffer_alloc(s->h * s->qstride);
+ if (!out_qp_table_buf) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ out = av_frame_clone(in);
+ if (!out) {
+ av_buffer_unref(&out_qp_table_buf);
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ in_qp_table = av_frame_get_qp_table(in, &stride, &type);
+ av_frame_set_qp_table(out, out_qp_table_buf, s->qstride, type);
+
+
+ if (s->evaluate_per_mb) {
+ int y, x;
+
+ for (y = 0; y < s->h; y++)
+ for (x = 0; x < s->qstride; x++) {
+ int qp = in_qp_table ? in_qp_table[x + stride * y] : NAN;
+ double var_values[] = { !!in_qp_table, qp, x, y, s->qstride, s->h, 0};
+ static const char *var_names[] = { "known", "qp", "x", "y", "w", "h", NULL };
+ double temp_val;
+
+ ret = av_expr_parse_and_eval(&temp_val, s->qp_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, 0, 0, ctx);
+ if (ret < 0)
+ goto fail;
+ out_qp_table_buf->data[x + s->qstride * y] = lrintf(temp_val);
+ }
+ } else if (in_qp_table) {
+ int y, x;
+
+ for (y = 0; y < s->h; y++)
+ for (x = 0; x < s->qstride; x++)
+ out_qp_table_buf->data[x + s->qstride * y] = s->lut[129 +
+ ((int8_t)in_qp_table[x + stride * y])];
+ } else {
+ int y, x, qp = s->lut[0];
+
+ for (y = 0; y < s->h; y++)
+ for (x = 0; x < s->qstride; x++)
+ out_qp_table_buf->data[x + s->qstride * y] = qp;
+ }
+
+ ret = ff_filter_frame(outlink, out);
+ out = NULL;
+fail:
+ av_frame_free(&in);
+ av_frame_free(&out);
+ return ret;
+}
+
+static const AVFilterPad qp_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad qp_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_qp = {
+ .name = "qp",
+ .description = NULL_IF_CONFIG_SMALL("Change video quantization parameters."),
+ .priv_size = sizeof(QPContext),
+ .inputs = qp_inputs,
+ .outputs = qp_outputs,
+ .priv_class = &qp_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_removelogo.c b/libavfilter/vf_removelogo.c
new file mode 100644
index 0000000000..94b92a5853
--- /dev/null
+++ b/libavfilter/vf_removelogo.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2005 Robert Edele <yartrebo@earthlink.net>
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Advanced blur-based logo removing filter
+ *
+ * This filter loads an image mask file showing where a logo is and
+ * uses a blur transform to remove the logo.
+ *
+ * Based on the libmpcodecs remove-logo filter by Robert Edele.
+ */
+
+/**
+ * This code implements a filter to remove annoying TV logos and other annoying
+ * images placed onto a video stream. It works by filling in the pixels that
+ * comprise the logo with neighboring pixels. The transform is very loosely
+ * based on a gaussian blur, but it is different enough to merit its own
+ * paragraph later on. It is a major improvement on the old delogo filter as it
+ * both uses a better blurring algorithm and uses a bitmap to use an arbitrary
+ * and generally much tighter fitting shape than a rectangle.
+ *
+ * The logo removal algorithm has two key points. The first is that it
+ * distinguishes between pixels in the logo and those not in the logo by using
+ * the passed-in bitmap. Pixels not in the logo are copied over directly without
+ * being modified and they also serve as source pixels for the logo
+ * fill-in. Pixels inside the logo have the mask applied.
+ *
+ * At init-time the bitmap is reprocessed internally, and the distance to the
+ * nearest edge of the logo (Manhattan distance), along with a little extra to
+ * remove rough edges, is stored in each pixel. This is done using an in-place
+ * erosion algorithm, and incrementing each pixel that survives any given
+ * erosion. Once every pixel is eroded, the maximum value is recorded, and a
+ * set of masks from size 0 to this size are generaged. The masks are circular
+ * binary masks, where each pixel within a radius N (where N is the size of the
+ * mask) is a 1, and all other pixels are a 0. Although a gaussian mask would be
+ * more mathematically accurate, a binary mask works better in practice because
+ * we generally do not use the central pixels in the mask (because they are in
+ * the logo region), and thus a gaussian mask will cause too little blur and
+ * thus a very unstable image.
+ *
+ * The mask is applied in a special way. Namely, only pixels in the mask that
+ * line up to pixels outside the logo are used. The dynamic mask size means that
+ * the mask is just big enough so that the edges touch pixels outside the logo,
+ * so the blurring is kept to a minimum and at least the first boundary
+ * condition is met (that the image function itself is continuous), even if the
+ * second boundary condition (that the derivative of the image function is
+ * continuous) is not met. A masking algorithm that does preserve the second
+ * boundary coundition (perhaps something based on a highly-modified bi-cubic
+ * algorithm) should offer even better results on paper, but the noise in a
+ * typical TV signal should make anything based on derivatives hopelessly noisy.
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "bbox.h"
+#include "lavfutils.h"
+#include "lswsutils.h"
+
+typedef struct {
+ const AVClass *class;
+ char *filename;
+ /* Stores our collection of masks. The first is for an array of
+ the second for the y axis, and the third for the x axis. */
+ int ***mask;
+ int max_mask_size;
+ int mask_w, mask_h;
+
+ uint8_t *full_mask_data;
+ FFBoundingBox full_mask_bbox;
+ uint8_t *half_mask_data;
+ FFBoundingBox half_mask_bbox;
+} RemovelogoContext;
+
+#define OFFSET(x) offsetof(RemovelogoContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption removelogo_options[] = {
+ { "filename", "set bitmap filename", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "f", "set bitmap filename", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(removelogo);
+
+/**
+ * Choose a slightly larger mask size to improve performance.
+ *
+ * This function maps the absolute minimum mask size needed to the
+ * mask size we'll actually use. f(x) = x (the smallest that will
+ * work) will produce the sharpest results, but will be quite
+ * jittery. f(x) = 1.25x (what I'm using) is a good tradeoff in my
+ * opinion. This will calculate only at init-time, so you can put a
+ * long expression here without effecting performance.
+ */
+#define apply_mask_fudge_factor(x) (((x) >> 2) + (x))
+
+/**
+ * Pre-process an image to give distance information.
+ *
+ * This function takes a bitmap image and converts it in place into a
+ * distance image. A distance image is zero for pixels outside of the
+ * logo and is the Manhattan distance (|dx| + |dy|) from the logo edge
+ * for pixels inside of the logo. This will overestimate the distance,
+ * but that is safe, and is far easier to implement than a proper
+ * pythagorean distance since I'm using a modified erosion algorithm
+ * to compute the distances.
+ *
+ * @param mask image which will be converted from a greyscale image
+ * into a distance image.
+ */
+static void convert_mask_to_strength_mask(uint8_t *data, int linesize,
+ int w, int h, int min_val,
+ int *max_mask_size)
+{
+ int x, y;
+
+ /* How many times we've gone through the loop. Used in the
+ in-place erosion algorithm and to get us max_mask_size later on. */
+ int current_pass = 0;
+
+ /* set all non-zero values to 1 */
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++)
+ data[y*linesize + x] = data[y*linesize + x] > min_val;
+
+ /* For each pass, if a pixel is itself the same value as the
+ current pass, and its four neighbors are too, then it is
+ incremented. If no pixels are incremented by the end of the
+ pass, then we go again. Edge pixels are counted as always
+ excluded (this should be true anyway for any sane mask, but if
+ it isn't this will ensure that we eventually exit). */
+ while (1) {
+ /* If this doesn't get set by the end of this pass, then we're done. */
+ int has_anything_changed = 0;
+ uint8_t *current_pixel0 = data + 1 + linesize, *current_pixel;
+ current_pass++;
+
+ for (y = 1; y < h-1; y++) {
+ current_pixel = current_pixel0;
+ for (x = 1; x < w-1; x++) {
+ /* Apply the in-place erosion transform. It is based
+ on the following two premises:
+ 1 - Any pixel that fails 1 erosion will fail all
+ future erosions.
+
+ 2 - Only pixels having survived all erosions up to
+ the present will be >= to current_pass.
+ It doesn't matter if it survived the current pass,
+ failed it, or hasn't been tested yet. By using >=
+ instead of ==, we allow the algorithm to work in
+ place. */
+ if ( *current_pixel >= current_pass &&
+ *(current_pixel + 1) >= current_pass &&
+ *(current_pixel - 1) >= current_pass &&
+ *(current_pixel + linesize) >= current_pass &&
+ *(current_pixel - linesize) >= current_pass) {
+ /* Increment the value since it still has not been
+ * eroded, as evidenced by the if statement that
+ * just evaluated to true. */
+ (*current_pixel)++;
+ has_anything_changed = 1;
+ }
+ current_pixel++;
+ }
+ current_pixel0 += linesize;
+ }
+ if (!has_anything_changed)
+ break;
+ }
+
+ /* Apply the fudge factor, which will increase the size of the
+ * mask a little to reduce jitter at the cost of more blur. */
+ for (y = 1; y < h - 1; y++)
+ for (x = 1; x < w - 1; x++)
+ data[(y * linesize) + x] = apply_mask_fudge_factor(data[(y * linesize) + x]);
+
+ /* As a side-effect, we now know the maximum mask size, which
+ * we'll use to generate our masks. */
+ /* Apply the fudge factor to this number too, since we must ensure
+ * that enough masks are generated. */
+ *max_mask_size = apply_mask_fudge_factor(current_pass + 1);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int load_mask(uint8_t **mask, int *w, int *h,
+ const char *filename, void *log_ctx)
+{
+ int ret;
+ enum AVPixelFormat pix_fmt;
+ uint8_t *src_data[4], *gray_data[4];
+ int src_linesize[4], gray_linesize[4];
+
+ /* load image from file */
+ if ((ret = ff_load_image(src_data, src_linesize, w, h, &pix_fmt, filename, log_ctx)) < 0)
+ return ret;
+
+ /* convert the image to GRAY8 */
+ if ((ret = ff_scale_image(gray_data, gray_linesize, *w, *h, AV_PIX_FMT_GRAY8,
+ src_data, src_linesize, *w, *h, pix_fmt,
+ log_ctx)) < 0)
+ goto end;
+
+ /* copy mask to a newly allocated array */
+ *mask = av_malloc(*w * *h);
+ if (!*mask)
+ ret = AVERROR(ENOMEM);
+ av_image_copy_plane(*mask, *w, gray_data[0], gray_linesize[0], *w, *h);
+
+end:
+ av_freep(&src_data[0]);
+ av_freep(&gray_data[0]);
+ return ret;
+}
+
+/**
+ * Generate a scaled down image with half width, height, and intensity.
+ *
+ * This function not only scales down an image, but halves the value
+ * in each pixel too. The purpose of this is to produce a chroma
+ * filter image out of a luma filter image. The pixel values store the
+ * distance to the edge of the logo and halving the dimensions halves
+ * the distance. This function rounds up, because a downwards rounding
+ * error could cause the filter to fail, but an upwards rounding error
+ * will only cause a minor amount of excess blur in the chroma planes.
+ */
+static void generate_half_size_image(const uint8_t *src_data, int src_linesize,
+ uint8_t *dst_data, int dst_linesize,
+ int src_w, int src_h,
+ int *max_mask_size)
+{
+ int x, y;
+
+ /* Copy over the image data, using the average of 4 pixels for to
+ * calculate each downsampled pixel. */
+ for (y = 0; y < src_h/2; y++) {
+ for (x = 0; x < src_w/2; x++) {
+ /* Set the pixel if there exists a non-zero value in the
+ * source pixels, else clear it. */
+ dst_data[(y * dst_linesize) + x] =
+ src_data[((y << 1) * src_linesize) + (x << 1)] ||
+ src_data[((y << 1) * src_linesize) + (x << 1) + 1] ||
+ src_data[(((y << 1) + 1) * src_linesize) + (x << 1)] ||
+ src_data[(((y << 1) + 1) * src_linesize) + (x << 1) + 1];
+ dst_data[(y * dst_linesize) + x] = FFMIN(1, dst_data[(y * dst_linesize) + x]);
+ }
+ }
+
+ convert_mask_to_strength_mask(dst_data, dst_linesize,
+ src_w/2, src_h/2, 0, max_mask_size);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ RemovelogoContext *s = ctx->priv;
+ int ***mask;
+ int ret = 0;
+ int a, b, c, w, h;
+ int full_max_mask_size, half_max_mask_size;
+
+ if (!s->filename) {
+ av_log(ctx, AV_LOG_ERROR, "The bitmap file name is mandatory\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* Load our mask image. */
+ if ((ret = load_mask(&s->full_mask_data, &w, &h, s->filename, ctx)) < 0)
+ return ret;
+ s->mask_w = w;
+ s->mask_h = h;
+
+ convert_mask_to_strength_mask(s->full_mask_data, w, w, h,
+ 16, &full_max_mask_size);
+
+ /* Create the scaled down mask image for the chroma planes. */
+ if (!(s->half_mask_data = av_mallocz(w/2 * h/2)))
+ return AVERROR(ENOMEM);
+ generate_half_size_image(s->full_mask_data, w,
+ s->half_mask_data, w/2,
+ w, h, &half_max_mask_size);
+
+ s->max_mask_size = FFMAX(full_max_mask_size, half_max_mask_size);
+
+ /* Create a circular mask for each size up to max_mask_size. When
+ the filter is applied, the mask size is determined on a pixel
+ by pixel basis, with pixels nearer the edge of the logo getting
+ smaller mask sizes. */
+ mask = (int ***)av_malloc_array(s->max_mask_size + 1, sizeof(int **));
+ if (!mask)
+ return AVERROR(ENOMEM);
+
+ for (a = 0; a <= s->max_mask_size; a++) {
+ mask[a] = (int **)av_malloc_array((a * 2) + 1, sizeof(int *));
+ if (!mask[a]) {
+ av_free(mask);
+ return AVERROR(ENOMEM);
+ }
+ for (b = -a; b <= a; b++) {
+ mask[a][b + a] = (int *)av_malloc_array((a * 2) + 1, sizeof(int));
+ if (!mask[a][b + a]) {
+ av_free(mask);
+ return AVERROR(ENOMEM);
+ }
+ for (c = -a; c <= a; c++) {
+ if ((b * b) + (c * c) <= (a * a)) /* Circular 0/1 mask. */
+ mask[a][b + a][c + a] = 1;
+ else
+ mask[a][b + a][c + a] = 0;
+ }
+ }
+ }
+ s->mask = mask;
+
+ /* Calculate our bounding rectangles, which determine in what
+ * region the logo resides for faster processing. */
+ ff_calculate_bounding_box(&s->full_mask_bbox, s->full_mask_data, w, w, h, 0);
+ ff_calculate_bounding_box(&s->half_mask_bbox, s->half_mask_data, w/2, w/2, h/2, 0);
+
+#define SHOW_LOGO_INFO(mask_type) \
+ av_log(ctx, AV_LOG_VERBOSE, #mask_type " x1:%d x2:%d y1:%d y2:%d max_mask_size:%d\n", \
+ s->mask_type##_mask_bbox.x1, s->mask_type##_mask_bbox.x2, \
+ s->mask_type##_mask_bbox.y1, s->mask_type##_mask_bbox.y2, \
+ mask_type##_max_mask_size);
+ SHOW_LOGO_INFO(full);
+ SHOW_LOGO_INFO(half);
+
+ return 0;
+}
+
+static int config_props_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ RemovelogoContext *s = ctx->priv;
+
+ if (inlink->w != s->mask_w || inlink->h != s->mask_h) {
+ av_log(ctx, AV_LOG_INFO,
+ "Mask image size %dx%d does not match with the input video size %dx%d\n",
+ s->mask_w, s->mask_h, inlink->w, inlink->h);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+/**
+ * Blur image.
+ *
+ * It takes a pixel that is inside the mask and blurs it. It does so
+ * by finding the average of all the pixels within the mask and
+ * outside of the mask.
+ *
+ * @param mask_data the mask plane to use for averaging
+ * @param image_data the image plane to blur
+ * @param w width of the image
+ * @param h height of the image
+ * @param x x-coordinate of the pixel to blur
+ * @param y y-coordinate of the pixel to blur
+ */
+static unsigned int blur_pixel(int ***mask,
+ const uint8_t *mask_data, int mask_linesize,
+ uint8_t *image_data, int image_linesize,
+ int w, int h, int x, int y)
+{
+ /* Mask size tells how large a circle to use. The radius is about
+ * (slightly larger than) mask size. */
+ int mask_size;
+ int start_posx, start_posy, end_posx, end_posy;
+ int i, j;
+ unsigned int accumulator = 0, divisor = 0;
+ /* What pixel we are reading out of the circular blur mask. */
+ const uint8_t *image_read_position;
+ /* What pixel we are reading out of the filter image. */
+ const uint8_t *mask_read_position;
+
+ /* Prepare our bounding rectangle and clip it if need be. */
+ mask_size = mask_data[y * mask_linesize + x];
+ start_posx = FFMAX(0, x - mask_size);
+ start_posy = FFMAX(0, y - mask_size);
+ end_posx = FFMIN(w - 1, x + mask_size);
+ end_posy = FFMIN(h - 1, y + mask_size);
+
+ image_read_position = image_data + image_linesize * start_posy + start_posx;
+ mask_read_position = mask_data + mask_linesize * start_posy + start_posx;
+
+ for (j = start_posy; j <= end_posy; j++) {
+ for (i = start_posx; i <= end_posx; i++) {
+ /* Check if this pixel is in the mask or not. Only use the
+ * pixel if it is not. */
+ if (!(*mask_read_position) && mask[mask_size][i - start_posx][j - start_posy]) {
+ accumulator += *image_read_position;
+ divisor++;
+ }
+
+ image_read_position++;
+ mask_read_position++;
+ }
+
+ image_read_position += (image_linesize - ((end_posx + 1) - start_posx));
+ mask_read_position += (mask_linesize - ((end_posx + 1) - start_posx));
+ }
+
+ /* If divisor is 0, it means that not a single pixel is outside of
+ the logo, so we have no data. Else we need to normalise the
+ data using the divisor. */
+ return divisor == 0 ? 255:
+ (accumulator + (divisor / 2)) / divisor; /* divide, taking into account average rounding error */
+}
+
+/**
+ * Blur image plane using a mask.
+ *
+ * @param source The image to have it's logo removed.
+ * @param destination Where the output image will be stored.
+ * @param source_stride How far apart (in memory) two consecutive lines are.
+ * @param destination Same as source_stride, but for the destination image.
+ * @param width Width of the image. This is the same for source and destination.
+ * @param height Height of the image. This is the same for source and destination.
+ * @param is_image_direct If the image is direct, then source and destination are
+ * the same and we can save a lot of time by not copying pixels that
+ * haven't changed.
+ * @param filter The image that stores the distance to the edge of the logo for
+ * each pixel.
+ * @param logo_start_x smallest x-coordinate that contains at least 1 logo pixel.
+ * @param logo_start_y smallest y-coordinate that contains at least 1 logo pixel.
+ * @param logo_end_x largest x-coordinate that contains at least 1 logo pixel.
+ * @param logo_end_y largest y-coordinate that contains at least 1 logo pixel.
+ *
+ * This function processes an entire plane. Pixels outside of the logo are copied
+ * to the output without change, and pixels inside the logo have the de-blurring
+ * function applied.
+ */
+static void blur_image(int ***mask,
+ const uint8_t *src_data, int src_linesize,
+ uint8_t *dst_data, int dst_linesize,
+ const uint8_t *mask_data, int mask_linesize,
+ int w, int h, int direct,
+ FFBoundingBox *bbox)
+{
+ int x, y;
+ uint8_t *dst_line;
+ const uint8_t *src_line;
+
+ if (!direct)
+ av_image_copy_plane(dst_data, dst_linesize, src_data, src_linesize, w, h);
+
+ for (y = bbox->y1; y <= bbox->y2; y++) {
+ src_line = src_data + src_linesize * y;
+ dst_line = dst_data + dst_linesize * y;
+
+ for (x = bbox->x1; x <= bbox->x2; x++) {
+ if (mask_data[y * mask_linesize + x]) {
+ /* Only process if we are in the mask. */
+ dst_line[x] = blur_pixel(mask,
+ mask_data, mask_linesize,
+ dst_data, dst_linesize,
+ w, h, x, y);
+ } else {
+ /* Else just copy the data. */
+ if (!direct)
+ dst_line[x] = src_line[x];
+ }
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ RemovelogoContext *s = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpicref;
+ int direct = 0;
+
+ if (av_frame_is_writable(inpicref)) {
+ direct = 1;
+ outpicref = inpicref;
+ } else {
+ outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpicref) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpicref, inpicref);
+ }
+
+ blur_image(s->mask,
+ inpicref ->data[0], inpicref ->linesize[0],
+ outpicref->data[0], outpicref->linesize[0],
+ s->full_mask_data, inlink->w,
+ inlink->w, inlink->h, direct, &s->full_mask_bbox);
+ blur_image(s->mask,
+ inpicref ->data[1], inpicref ->linesize[1],
+ outpicref->data[1], outpicref->linesize[1],
+ s->half_mask_data, inlink->w/2,
+ inlink->w/2, inlink->h/2, direct, &s->half_mask_bbox);
+ blur_image(s->mask,
+ inpicref ->data[2], inpicref ->linesize[2],
+ outpicref->data[2], outpicref->linesize[2],
+ s->half_mask_data, inlink->w/2,
+ inlink->w/2, inlink->h/2, direct, &s->half_mask_bbox);
+
+ if (!direct)
+ av_frame_free(&inpicref);
+
+ return ff_filter_frame(outlink, outpicref);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ RemovelogoContext *s = ctx->priv;
+ int a, b;
+
+ av_freep(&s->full_mask_data);
+ av_freep(&s->half_mask_data);
+
+ if (s->mask) {
+ /* Loop through each mask. */
+ for (a = 0; a <= s->max_mask_size; a++) {
+ /* Loop through each scanline in a mask. */
+ for (b = -a; b <= a; b++) {
+ av_freep(&s->mask[a][b + a]); /* Free a scanline. */
+ }
+ av_freep(&s->mask[a]);
+ }
+ /* Free the array of pointers pointing to the masks. */
+ av_freep(&s->mask);
+ }
+}
+
+static const AVFilterPad removelogo_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad removelogo_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_removelogo = {
+ .name = "removelogo",
+ .description = NULL_IF_CONFIG_SMALL("Remove a TV logo based on a mask image."),
+ .priv_size = sizeof(RemovelogoContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = removelogo_inputs,
+ .outputs = removelogo_outputs,
+ .priv_class = &removelogo_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_repeatfields.c b/libavfilter/vf_repeatfields.c
new file mode 100644
index 0000000000..b9e73ec6de
--- /dev/null
+++ b/libavfilter/vf_repeatfields.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2003 Tobias Diedrich
+ *
+ * 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/imgutils.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct RepeatFieldsContext {
+ const AVClass *class;
+ int state;
+ int nb_planes;
+ int linesize[4];
+ int planeheight[4];
+ AVFrame *frame;
+} RepeatFieldsContext;
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ RepeatFieldsContext *s = ctx->priv;
+
+ av_frame_free(&s->frame);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pixel_fmts_eq[] = {
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pixel_fmts_eq);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ RepeatFieldsContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ return 0;
+}
+
+static void update_pts(AVFilterLink *link, AVFrame *f, int64_t pts, int fields)
+{
+ if (av_cmp_q(link->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);
+ } else
+ f->pts = AV_NOPTS_VALUE;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in) {
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ RepeatFieldsContext *s = ctx->priv;
+ AVFrame *out;
+ int ret, i;
+ int state = s->state;
+
+ if (!s->frame) {
+ s->frame = av_frame_clone(in);
+ if (!s->frame)
+ return AVERROR(ENOMEM);
+ s->frame->pts = AV_NOPTS_VALUE;
+ }
+
+ out = s->frame;
+
+ if ((state == 0 && !in->top_field_first) ||
+ (state == 1 && in->top_field_first)) {
+ av_log(ctx, AV_LOG_WARNING, "Unexpected field flags: "
+ "state=%d top_field_first=%d repeat_first_field=%d\n",
+ state, in->top_field_first, in->repeat_pict);
+ state ^= 1;
+ }
+
+ if (state == 0) {
+ AVFrame *new;
+
+ new = av_frame_clone(in);
+ if (!new)
+ return AVERROR(ENOMEM);
+
+ ret = ff_filter_frame(outlink, new);
+
+ if (in->repeat_pict) {
+ av_frame_make_writable(out);
+ update_pts(outlink, out, in->pts, 2);
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(out->data[i], out->linesize[i] * 2,
+ in->data[i], in->linesize[i] * 2,
+ s->linesize[i], s->planeheight[i] / 2);
+ }
+ state = 1;
+ }
+ } else {
+ for (i = 0; i < s->nb_planes; i++) {
+ av_frame_make_writable(out);
+ av_image_copy_plane(out->data[i] + out->linesize[i], out->linesize[i] * 2,
+ in->data[i] + in->linesize[i], in->linesize[i] * 2,
+ s->linesize[i], s->planeheight[i] / 2);
+ }
+
+ ret = ff_filter_frame(outlink, av_frame_clone(out));
+
+ if (in->repeat_pict) {
+ AVFrame *new;
+
+ new = av_frame_clone(in);
+ if (!new)
+ return AVERROR(ENOMEM);
+
+ ret = ff_filter_frame(outlink, new);
+ state = 0;
+ } else {
+ av_frame_make_writable(out);
+ update_pts(outlink, out, in->pts, 1);
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(out->data[i], out->linesize[i] * 2,
+ in->data[i], in->linesize[i] * 2,
+ s->linesize[i], s->planeheight[i] / 2);
+ }
+ }
+ }
+
+ s->state = state;
+
+ av_frame_free(&in);
+ return ret;
+}
+
+static const AVFilterPad repeatfields_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad repeatfields_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_repeatfields = {
+ .name = "repeatfields",
+ .description = NULL_IF_CONFIG_SMALL("Hard repeat fields based on MPEG repeat field flag."),
+ .priv_size = sizeof(RepeatFieldsContext),
+ .uninit = uninit,
+ .inputs = repeatfields_inputs,
+ .outputs = repeatfields_outputs,
+ .query_formats = query_formats,
+};
diff --git a/libavfilter/vf_rotate.c b/libavfilter/vf_rotate.c
new file mode 100644
index 0000000000..46ab796c7a
--- /dev/null
+++ b/libavfilter/vf_rotate.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ * Copyright (c) 2008 Vitor Sessak
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * rotation filter, partially based on the tests/rotozoom.c program
+*/
+
+#include "libavutil/avstring.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+
+#include "avfilter.h"
+#include "drawutils.h"
+#include "internal.h"
+#include "video.h"
+
+#include <float.h>
+
+static const char * const var_names[] = {
+ "in_w" , "iw", ///< width of the input video
+ "in_h" , "ih", ///< height of the input video
+ "out_w", "ow", ///< width of the input video
+ "out_h", "oh", ///< height of the input video
+ "hsub", "vsub",
+ "n", ///< number of frame
+ "t", ///< timestamp expressed in seconds
+ 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_HSUB, VAR_VSUB,
+ VAR_N,
+ VAR_T,
+ VAR_VARS_NB
+};
+
+typedef struct {
+ const AVClass *class;
+ double angle;
+ char *angle_expr_str; ///< expression for the angle
+ AVExpr *angle_expr; ///< parsed expression for the angle
+ char *outw_expr_str, *outh_expr_str;
+ int outh, outw;
+ uint8_t fillcolor[4]; ///< color expressed either in YUVA or RGBA colorspace for the padding area
+ char *fillcolor_str;
+ int fillcolor_enable;
+ int hsub, vsub;
+ int nb_planes;
+ int use_bilinear;
+ float sinx, cosx;
+ double var_values[VAR_VARS_NB];
+ FFDrawContext draw;
+ FFDrawColor color;
+} RotContext;
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+ int inw, inh;
+ int outw, outh;
+ int plane;
+ int xi, yi;
+ int xprime, yprime;
+ int c, s;
+} ThreadData;
+
+#define OFFSET(x) offsetof(RotContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption rotate_options[] = {
+ { "angle", "set angle (in radians)", OFFSET(angle_expr_str), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "a", "set angle (in radians)", OFFSET(angle_expr_str), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "out_w", "set output width expression", OFFSET(outw_expr_str), AV_OPT_TYPE_STRING, {.str="iw"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "ow", "set output width expression", OFFSET(outw_expr_str), AV_OPT_TYPE_STRING, {.str="iw"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "out_h", "set output height expression", OFFSET(outh_expr_str), AV_OPT_TYPE_STRING, {.str="ih"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "oh", "set output height expression", OFFSET(outh_expr_str), AV_OPT_TYPE_STRING, {.str="ih"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "fillcolor", "set background fill color", OFFSET(fillcolor_str), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "c", "set background fill color", OFFSET(fillcolor_str), AV_OPT_TYPE_STRING, {.str="black"}, CHAR_MIN, CHAR_MAX, .flags=FLAGS },
+ { "bilinear", "use bilinear interpolation", OFFSET(use_bilinear), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags=FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(rotate);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ RotContext *rot = ctx->priv;
+
+ if (!strcmp(rot->fillcolor_str, "none"))
+ rot->fillcolor_enable = 0;
+ else if (av_parse_color(rot->fillcolor, rot->fillcolor_str, -1, ctx) >= 0)
+ rot->fillcolor_enable = 1;
+ else
+ return AVERROR(EINVAL);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ RotContext *rot = ctx->priv;
+
+ av_expr_free(rot->angle_expr);
+ rot->angle_expr = NULL;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_RGB0,
+ AV_PIX_FMT_0BGR, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static double get_rotated_w(void *opaque, double angle)
+{
+ RotContext *rot = opaque;
+ double inw = rot->var_values[VAR_IN_W];
+ double inh = rot->var_values[VAR_IN_H];
+ float sinx = sin(angle);
+ float cosx = cos(angle);
+
+ return FFMAX(0, inh * sinx) + FFMAX(0, -inw * cosx) +
+ FFMAX(0, inw * cosx) + FFMAX(0, -inh * sinx);
+}
+
+static double get_rotated_h(void *opaque, double angle)
+{
+ RotContext *rot = opaque;
+ double inw = rot->var_values[VAR_IN_W];
+ double inh = rot->var_values[VAR_IN_H];
+ float sinx = sin(angle);
+ float cosx = cos(angle);
+
+ return FFMAX(0, -inh * cosx) + FFMAX(0, -inw * sinx) +
+ FFMAX(0, inh * cosx) + FFMAX(0, inw * sinx);
+}
+
+static double (* const func1[])(void *, double) = {
+ get_rotated_w,
+ get_rotated_h,
+ NULL
+};
+
+static const char * const func1_names[] = {
+ "rotw",
+ "roth",
+ NULL
+};
+
+static int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ RotContext *rot = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+ double res;
+ char *expr;
+
+ ff_draw_init(&rot->draw, inlink->format, 0);
+ ff_draw_color(&rot->draw, &rot->color, rot->fillcolor);
+
+ rot->hsub = pixdesc->log2_chroma_w;
+ rot->vsub = pixdesc->log2_chroma_h;
+
+ rot->var_values[VAR_IN_W] = rot->var_values[VAR_IW] = inlink->w;
+ rot->var_values[VAR_IN_H] = rot->var_values[VAR_IH] = inlink->h;
+ rot->var_values[VAR_HSUB] = 1<<rot->hsub;
+ rot->var_values[VAR_VSUB] = 1<<rot->vsub;
+ rot->var_values[VAR_N] = NAN;
+ rot->var_values[VAR_T] = NAN;
+ rot->var_values[VAR_OUT_W] = rot->var_values[VAR_OW] = NAN;
+ rot->var_values[VAR_OUT_H] = rot->var_values[VAR_OH] = NAN;
+
+ av_expr_free(rot->angle_expr);
+ rot->angle_expr = NULL;
+ if ((ret = av_expr_parse(&rot->angle_expr, expr = rot->angle_expr_str, var_names,
+ func1_names, func1, NULL, NULL, 0, ctx)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Error occurred parsing angle expression '%s'\n", rot->angle_expr_str);
+ return ret;
+ }
+
+#define SET_SIZE_EXPR(name, opt_name) do { \
+ ret = av_expr_parse_and_eval(&res, expr = rot->name##_expr_str, \
+ var_names, rot->var_values, \
+ func1_names, func1, NULL, NULL, rot, 0, ctx); \
+ if (ret < 0 || isnan(res) || isinf(res) || res <= 0) { \
+ av_log(ctx, AV_LOG_ERROR, \
+ "Error parsing or evaluating expression for option %s: " \
+ "invalid expression '%s' or non-positive or indefinite value %f\n", \
+ opt_name, expr, res); \
+ return ret; \
+ } \
+} while (0)
+
+ /* evaluate width and height */
+ av_expr_parse_and_eval(&res, expr = rot->outw_expr_str, var_names, rot->var_values,
+ func1_names, func1, NULL, NULL, rot, 0, ctx);
+ rot->var_values[VAR_OUT_W] = rot->var_values[VAR_OW] = res;
+ rot->outw = res + 0.5;
+ SET_SIZE_EXPR(outh, "out_w");
+ rot->var_values[VAR_OUT_H] = rot->var_values[VAR_OH] = res;
+ rot->outh = res + 0.5;
+
+ /* evaluate the width again, as it may depend on the evaluated output height */
+ SET_SIZE_EXPR(outw, "out_h");
+ rot->var_values[VAR_OUT_W] = rot->var_values[VAR_OW] = res;
+ rot->outw = res + 0.5;
+
+ /* compute number of planes */
+ rot->nb_planes = av_pix_fmt_count_planes(inlink->format);
+ outlink->w = rot->outw;
+ outlink->h = rot->outh;
+ return 0;
+}
+
+#define FIXP (1<<16)
+#define FIXP2 (1<<20)
+#define INT_PI 3294199 //(M_PI * FIXP2)
+
+/**
+ * Compute the sin of a using integer values.
+ * Input is scaled by FIXP2 and output values are scaled by FIXP.
+ */
+static int64_t int_sin(int64_t a)
+{
+ int64_t a2, res = 0;
+ int i;
+ if (a < 0) a = INT_PI-a; // 0..inf
+ a %= 2 * INT_PI; // 0..2PI
+
+ if (a >= INT_PI*3/2) a -= 2*INT_PI; // -PI/2 .. 3PI/2
+ if (a >= INT_PI/2 ) a = INT_PI - a; // -PI/2 .. PI/2
+
+ /* compute sin using Taylor series approximated to the fifth term */
+ a2 = (a*a)/(FIXP2);
+ for (i = 2; i < 11; i += 2) {
+ res += a;
+ a = -a*a2 / (FIXP2*i*(i+1));
+ }
+ return (res + 8)>>4;
+}
+
+/**
+ * Interpolate the color in src at position x and y using bilinear
+ * interpolation.
+ */
+static uint8_t *interpolate_bilinear(uint8_t *dst_color,
+ const uint8_t *src, int src_linesize, int src_linestep,
+ int x, int y, int max_x, int max_y)
+{
+ int int_x = av_clip(x>>16, 0, max_x);
+ int int_y = av_clip(y>>16, 0, max_y);
+ int frac_x = x&0xFFFF;
+ int frac_y = y&0xFFFF;
+ int i;
+ int int_x1 = FFMIN(int_x+1, max_x);
+ int int_y1 = FFMIN(int_y+1, max_y);
+
+ for (i = 0; i < src_linestep; i++) {
+ int s00 = src[src_linestep * int_x + i + src_linesize * int_y ];
+ int s01 = src[src_linestep * int_x1 + i + src_linesize * int_y ];
+ int s10 = src[src_linestep * int_x + i + src_linesize * int_y1];
+ int s11 = src[src_linestep * int_x1 + i + src_linesize * int_y1];
+ int s0 = (((1<<16) - frac_x)*s00 + frac_x*s01);
+ int s1 = (((1<<16) - frac_x)*s10 + frac_x*s11);
+
+ dst_color[i] = ((int64_t)((1<<16) - frac_y)*s0 + (int64_t)frac_y*s1) >> 32;
+ }
+
+ return dst_color;
+}
+
+static av_always_inline void copy_elem(uint8_t *pout, const uint8_t *pin, int elem_size)
+{
+ int v;
+ switch (elem_size) {
+ case 1:
+ *pout = *pin;
+ break;
+ case 2:
+ *((uint16_t *)pout) = *((uint16_t *)pin);
+ break;
+ case 3:
+ v = AV_RB24(pin);
+ AV_WB24(pout, v);
+ break;
+ case 4:
+ *((uint32_t *)pout) = *((uint32_t *)pin);
+ break;
+ default:
+ memcpy(pout, pin, elem_size);
+ break;
+ }
+}
+
+static av_always_inline void simple_rotate_internal(uint8_t *dst, const uint8_t *src, int src_linesize, int angle, int elem_size, int len)
+{
+ int i;
+ switch(angle) {
+ case 0:
+ memcpy(dst, src, elem_size * len);
+ break;
+ case 1:
+ for (i = 0; i<len; i++)
+ copy_elem(dst + i*elem_size, src + (len-i-1)*src_linesize, elem_size);
+ break;
+ case 2:
+ for (i = 0; i<len; i++)
+ copy_elem(dst + i*elem_size, src + (len-i-1)*elem_size, elem_size);
+ break;
+ case 3:
+ for (i = 0; i<len; i++)
+ copy_elem(dst + i*elem_size, src + i*src_linesize, elem_size);
+ break;
+ }
+}
+
+static av_always_inline void simple_rotate(uint8_t *dst, const uint8_t *src, int src_linesize, int angle, int elem_size, int len)
+{
+ switch(elem_size) {
+ case 1 : simple_rotate_internal(dst, src, src_linesize, angle, 1, len); break;
+ case 2 : simple_rotate_internal(dst, src, src_linesize, angle, 2, len); break;
+ case 3 : simple_rotate_internal(dst, src, src_linesize, angle, 3, len); break;
+ case 4 : simple_rotate_internal(dst, src, src_linesize, angle, 4, len); break;
+ default: simple_rotate_internal(dst, src, src_linesize, angle, elem_size, len); break;
+ }
+}
+
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)*av_q2d(tb))
+
+static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs)
+{
+ ThreadData *td = arg;
+ AVFrame *in = td->in;
+ AVFrame *out = td->out;
+ RotContext *rot = ctx->priv;
+ const int outw = td->outw, outh = td->outh;
+ const int inw = td->inw, inh = td->inh;
+ const int plane = td->plane;
+ const int xi = td->xi, yi = td->yi;
+ const int c = td->c, s = td->s;
+ const int start = (outh * job ) / nb_jobs;
+ const int end = (outh * (job+1)) / nb_jobs;
+ int xprime = td->xprime + start * s;
+ int yprime = td->yprime + start * c;
+ int i, j, x, y;
+
+ for (j = start; j < end; j++) {
+ x = xprime + xi + FIXP*(inw-1)/2;
+ y = yprime + yi + FIXP*(inh-1)/2;
+
+ if (fabs(rot->angle - 0) < FLT_EPSILON && outw == inw && outh == inh) {
+ simple_rotate(out->data[plane] + j * out->linesize[plane],
+ in->data[plane] + j * in->linesize[plane],
+ in->linesize[plane], 0, rot->draw.pixelstep[plane], outw);
+ } else if (fabs(rot->angle - M_PI/2) < FLT_EPSILON && outw == inh && outh == inw) {
+ simple_rotate(out->data[plane] + j * out->linesize[plane],
+ in->data[plane] + j * rot->draw.pixelstep[plane],
+ in->linesize[plane], 1, rot->draw.pixelstep[plane], outw);
+ } else if (fabs(rot->angle - M_PI) < FLT_EPSILON && outw == inw && outh == inh) {
+ simple_rotate(out->data[plane] + j * out->linesize[plane],
+ in->data[plane] + (outh-j-1) * in->linesize[plane],
+ in->linesize[plane], 2, rot->draw.pixelstep[plane], outw);
+ } else if (fabs(rot->angle - 3*M_PI/2) < FLT_EPSILON && outw == inh && outh == inw) {
+ simple_rotate(out->data[plane] + j * out->linesize[plane],
+ in->data[plane] + (outh-j-1) * rot->draw.pixelstep[plane],
+ in->linesize[plane], 3, rot->draw.pixelstep[plane], outw);
+ } else {
+
+ for (i = 0; i < outw; i++) {
+ int32_t v;
+ int x1, y1;
+ uint8_t *pin, *pout;
+ x1 = x>>16;
+ y1 = y>>16;
+
+ /* the out-of-range values avoid border artifacts */
+ if (x1 >= -1 && x1 <= inw && y1 >= -1 && y1 <= inh) {
+ uint8_t inp_inv[4]; /* interpolated input value */
+ pout = out->data[plane] + j * out->linesize[plane] + i * rot->draw.pixelstep[plane];
+ if (rot->use_bilinear) {
+ pin = interpolate_bilinear(inp_inv,
+ in->data[plane], in->linesize[plane], rot->draw.pixelstep[plane],
+ x, y, inw-1, inh-1);
+ } else {
+ int x2 = av_clip(x1, 0, inw-1);
+ int y2 = av_clip(y1, 0, inh-1);
+ pin = in->data[plane] + y2 * in->linesize[plane] + x2 * rot->draw.pixelstep[plane];
+ }
+ switch (rot->draw.pixelstep[plane]) {
+ case 1:
+ *pout = *pin;
+ break;
+ case 2:
+ *((uint16_t *)pout) = *((uint16_t *)pin);
+ break;
+ case 3:
+ v = AV_RB24(pin);
+ AV_WB24(pout, v);
+ break;
+ case 4:
+ *((uint32_t *)pout) = *((uint32_t *)pin);
+ break;
+ default:
+ memcpy(pout, pin, rot->draw.pixelstep[plane]);
+ break;
+ }
+ }
+ x += c;
+ y -= s;
+ }
+ }
+ xprime += s;
+ yprime += c;
+ }
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+ RotContext *rot = ctx->priv;
+ int angle_int, s, c, plane;
+ double res;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ rot->var_values[VAR_N] = inlink->frame_count;
+ rot->var_values[VAR_T] = TS2T(in->pts, inlink->time_base);
+ rot->angle = res = av_expr_eval(rot->angle_expr, rot->var_values, rot);
+
+ av_log(ctx, AV_LOG_DEBUG, "n:%f time:%f angle:%f/PI\n",
+ rot->var_values[VAR_N], rot->var_values[VAR_T], rot->angle/M_PI);
+
+ angle_int = res * FIXP * 16;
+ s = int_sin(angle_int);
+ c = int_sin(angle_int + INT_PI/2);
+
+ /* fill background */
+ if (rot->fillcolor_enable)
+ ff_fill_rectangle(&rot->draw, &rot->color, out->data, out->linesize,
+ 0, 0, outlink->w, outlink->h);
+
+ for (plane = 0; plane < rot->nb_planes; plane++) {
+ int hsub = plane == 1 || plane == 2 ? rot->hsub : 0;
+ int vsub = plane == 1 || plane == 2 ? rot->vsub : 0;
+ const int outw = FF_CEIL_RSHIFT(outlink->w, hsub);
+ const int outh = FF_CEIL_RSHIFT(outlink->h, vsub);
+ ThreadData td = { .in = in, .out = out,
+ .inw = FF_CEIL_RSHIFT(inlink->w, hsub),
+ .inh = FF_CEIL_RSHIFT(inlink->h, vsub),
+ .outh = outh, .outw = outw,
+ .xi = -(outw-1) * c / 2, .yi = (outw-1) * s / 2,
+ .xprime = -(outh-1) * s / 2,
+ .yprime = -(outh-1) * c / 2,
+ .plane = plane, .c = c, .s = s };
+
+
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outh, ctx->graph->nb_threads));
+ }
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ RotContext *rot = ctx->priv;
+ int ret;
+
+ if (!strcmp(cmd, "angle") || !strcmp(cmd, "a")) {
+ AVExpr *old = rot->angle_expr;
+ ret = av_expr_parse(&rot->angle_expr, args, var_names,
+ NULL, NULL, NULL, NULL, 0, ctx);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Error when parsing the expression '%s' for angle command\n", args);
+ rot->angle_expr = old;
+ return ret;
+ }
+ av_expr_free(old);
+ } else
+ ret = AVERROR(ENOSYS);
+
+ return ret;
+}
+
+static const AVFilterPad rotate_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad rotate_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_rotate = {
+ .name = "rotate",
+ .description = NULL_IF_CONFIG_SMALL("Rotate the input image."),
+ .priv_size = sizeof(RotContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .process_command = process_command,
+ .inputs = rotate_inputs,
+ .outputs = rotate_outputs,
+ .priv_class = &rotate_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_sab.c b/libavfilter/vf_sab.c
new file mode 100644
index 0000000000..da59439652
--- /dev/null
+++ b/libavfilter/vf_sab.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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
+ * Shape Adaptive Blur filter, ported from MPlayer libmpcodecs/vf_sab.c
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libswscale/swscale.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+typedef struct {
+ float radius;
+ float pre_filter_radius;
+ float strength;
+ float quality;
+ struct SwsContext *pre_filter_context;
+ uint8_t *pre_filter_buf;
+ int pre_filter_linesize;
+ int dist_width;
+ int dist_linesize;
+ int *dist_coeff;
+#define COLOR_DIFF_COEFF_SIZE 512
+ int color_diff_coeff[COLOR_DIFF_COEFF_SIZE];
+} FilterParam;
+
+typedef struct {
+ const AVClass *class;
+ FilterParam luma;
+ FilterParam chroma;
+ int hsub;
+ int vsub;
+ unsigned int sws_flags;
+} SabContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+#define RADIUS_MIN 0.1
+#define RADIUS_MAX 4.0
+
+#define PRE_FILTER_RADIUS_MIN 0.1
+#define PRE_FILTER_RADIUS_MAX 2.0
+
+#define STRENGTH_MIN 0.1
+#define STRENGTH_MAX 100.0
+
+#define OFFSET(x) offsetof(SabContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption sab_options[] = {
+ { "luma_radius", "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
+ { "lr" , "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
+ { "luma_pre_filter_radius", "set luma pre-filter radius", OFFSET(luma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, PRE_FILTER_RADIUS_MIN, PRE_FILTER_RADIUS_MAX, .flags=FLAGS },
+ { "lpfr", "set luma pre-filter radius", OFFSET(luma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, PRE_FILTER_RADIUS_MIN, PRE_FILTER_RADIUS_MAX, .flags=FLAGS },
+ { "luma_strength", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
+ { "ls", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
+
+ { "chroma_radius", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
+ { "cr", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
+ { "chroma_pre_filter_radius", "set chroma pre-filter radius", OFFSET(chroma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=PRE_FILTER_RADIUS_MIN-1},
+ PRE_FILTER_RADIUS_MIN-1, PRE_FILTER_RADIUS_MAX, .flags=FLAGS },
+ { "cpfr", "set chroma pre-filter radius", OFFSET(chroma.pre_filter_radius), AV_OPT_TYPE_FLOAT, {.dbl=PRE_FILTER_RADIUS_MIN-1},
+ PRE_FILTER_RADIUS_MIN-1, PRE_FILTER_RADIUS_MAX, .flags=FLAGS },
+ { "chroma_strength", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
+ { "cs", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
+
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(sab);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ SabContext *sab = ctx->priv;
+
+ /* make chroma default to luma values, if not explicitly set */
+ if (sab->chroma.radius < RADIUS_MIN)
+ sab->chroma.radius = sab->luma.radius;
+ if (sab->chroma.pre_filter_radius < PRE_FILTER_RADIUS_MIN)
+ sab->chroma.pre_filter_radius = sab->luma.pre_filter_radius;
+ if (sab->chroma.strength < STRENGTH_MIN)
+ sab->chroma.strength = sab->luma.strength;
+
+ sab->luma.quality = sab->chroma.quality = 3.0;
+ sab->sws_flags = SWS_POINT;
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "luma_radius:%f luma_pre_filter_radius::%f luma_strength:%f "
+ "chroma_radius:%f chroma_pre_filter_radius:%f chroma_strength:%f\n",
+ sab->luma .radius, sab->luma .pre_filter_radius, sab->luma .strength,
+ sab->chroma.radius, sab->chroma.pre_filter_radius, sab->chroma.strength);
+ return 0;
+}
+
+static void close_filter_param(FilterParam *f)
+{
+ if (f->pre_filter_context) {
+ sws_freeContext(f->pre_filter_context);
+ f->pre_filter_context = NULL;
+ }
+ av_freep(&f->pre_filter_buf);
+ av_freep(&f->dist_coeff);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SabContext *sab = ctx->priv;
+
+ close_filter_param(&sab->luma);
+ close_filter_param(&sab->chroma);
+}
+
+static int open_filter_param(FilterParam *f, int width, int height, unsigned int sws_flags)
+{
+ SwsVector *vec;
+ SwsFilter sws_f;
+ int i, x, y;
+ int linesize = FFALIGN(width, 8);
+
+ f->pre_filter_buf = av_malloc(linesize * height);
+ if (!f->pre_filter_buf)
+ return AVERROR(ENOMEM);
+
+ f->pre_filter_linesize = linesize;
+ vec = sws_getGaussianVec(f->pre_filter_radius, f->quality);
+ sws_f.lumH = sws_f.lumV = vec;
+ sws_f.chrH = sws_f.chrV = NULL;
+ f->pre_filter_context = sws_getContext(width, height, AV_PIX_FMT_GRAY8,
+ width, height, AV_PIX_FMT_GRAY8,
+ sws_flags, &sws_f, NULL, NULL);
+ sws_freeVec(vec);
+
+ vec = sws_getGaussianVec(f->strength, 5.0);
+ for (i = 0; i < COLOR_DIFF_COEFF_SIZE; i++) {
+ double d;
+ int index = i-COLOR_DIFF_COEFF_SIZE/2 + vec->length/2;
+
+ if (index < 0 || index >= vec->length) d = 0.0;
+ else d = vec->coeff[index];
+
+ f->color_diff_coeff[i] = (int)(d/vec->coeff[vec->length/2]*(1<<12) + 0.5);
+ }
+ sws_freeVec(vec);
+
+ vec = sws_getGaussianVec(f->radius, f->quality);
+ f->dist_width = vec->length;
+ f->dist_linesize = FFALIGN(vec->length, 8);
+ f->dist_coeff = av_malloc_array(f->dist_width, f->dist_linesize * sizeof(*f->dist_coeff));
+ if (!f->dist_coeff) {
+ sws_freeVec(vec);
+ return AVERROR(ENOMEM);
+ }
+
+ for (y = 0; y < vec->length; y++) {
+ for (x = 0; x < vec->length; x++) {
+ double d = vec->coeff[x] * vec->coeff[y];
+ f->dist_coeff[x + y*f->dist_linesize] = (int)(d*(1<<10) + 0.5);
+ }
+ }
+ sws_freeVec(vec);
+
+ return 0;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ SabContext *sab = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ sab->hsub = desc->log2_chroma_w;
+ sab->vsub = desc->log2_chroma_h;
+
+ close_filter_param(&sab->luma);
+ ret = open_filter_param(&sab->luma, inlink->w, inlink->h, sab->sws_flags);
+ if (ret < 0)
+ return ret;
+
+ close_filter_param(&sab->chroma);
+ ret = open_filter_param(&sab->chroma,
+ FF_CEIL_RSHIFT(inlink->w, sab->hsub),
+ FF_CEIL_RSHIFT(inlink->h, sab->vsub), sab->sws_flags);
+ return ret;
+}
+
+#define NB_PLANES 4
+
+static void blur(uint8_t *dst, const int dst_linesize,
+ const uint8_t *src, const int src_linesize,
+ const int w, const int h, FilterParam *fp)
+{
+ int x, y;
+ FilterParam f = *fp;
+ const int radius = f.dist_width/2;
+
+ const uint8_t * const src2[NB_PLANES] = { src };
+ int src2_linesize[NB_PLANES] = { src_linesize };
+ uint8_t *dst2[NB_PLANES] = { f.pre_filter_buf };
+ int dst2_linesize[NB_PLANES] = { f.pre_filter_linesize };
+
+ sws_scale(f.pre_filter_context, src2, src2_linesize, 0, h, dst2, dst2_linesize);
+
+#define UPDATE_FACTOR do { \
+ int factor; \
+ factor = f.color_diff_coeff[COLOR_DIFF_COEFF_SIZE/2 + pre_val - \
+ f.pre_filter_buf[ix + iy*f.pre_filter_linesize]] * f.dist_coeff[dx + dy*f.dist_linesize]; \
+ sum += src[ix + iy*src_linesize] * factor; \
+ div += factor; \
+ } while (0)
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int sum = 0;
+ int div = 0;
+ int dy;
+ const int pre_val = f.pre_filter_buf[x + y*f.pre_filter_linesize];
+ if (x >= radius && x < w - radius) {
+ for (dy = 0; dy < radius*2 + 1; dy++) {
+ int dx;
+ int iy = y+dy - radius;
+ iy = avpriv_mirror(iy, h-1);
+
+ for (dx = 0; dx < radius*2 + 1; dx++) {
+ const int ix = x+dx - radius;
+ UPDATE_FACTOR;
+ }
+ }
+ } else {
+ for (dy = 0; dy < radius*2+1; dy++) {
+ int dx;
+ int iy = y+dy - radius;
+ iy = avpriv_mirror(iy, h-1);
+
+ for (dx = 0; dx < radius*2 + 1; dx++) {
+ int ix = x+dx - radius;
+ ix = avpriv_mirror(ix, w-1);
+ UPDATE_FACTOR;
+ }
+ }
+ }
+ dst[x + y*dst_linesize] = (sum + div/2) / div;
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ SabContext *sab = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpic;
+
+ outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpic) {
+ av_frame_free(&inpic);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpic, inpic);
+
+ blur(outpic->data[0], outpic->linesize[0], inpic->data[0], inpic->linesize[0],
+ inlink->w, inlink->h, &sab->luma);
+ if (inpic->data[2]) {
+ int cw = FF_CEIL_RSHIFT(inlink->w, sab->hsub);
+ int ch = FF_CEIL_RSHIFT(inlink->h, sab->vsub);
+ blur(outpic->data[1], outpic->linesize[1], inpic->data[1], inpic->linesize[1], cw, ch, &sab->chroma);
+ blur(outpic->data[2], outpic->linesize[2], inpic->data[2], inpic->linesize[2], cw, ch, &sab->chroma);
+ }
+
+ av_frame_free(&inpic);
+ return ff_filter_frame(outlink, outpic);
+}
+
+static const AVFilterPad sab_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad sab_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_sab = {
+ .name = "sab",
+ .description = NULL_IF_CONFIG_SMALL("Apply shape adaptive blur."),
+ .priv_size = sizeof(SabContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = sab_inputs,
+ .outputs = sab_outputs,
+ .priv_class = &sab_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 73ea9d23e0..2a3d00808d 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,73 +35,128 @@
#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
#include "libswscale/swscale.h"
static const char *const var_names[] = {
- "PI",
- "PHI",
- "E",
"in_w", "iw",
"in_h", "ih",
"out_w", "ow",
"out_h", "oh",
- "a", "dar",
+ "a",
"sar",
+ "dar",
"hsub",
"vsub",
+ "ohsub",
+ "ovsub",
NULL
};
enum var_name {
- VAR_PI,
- VAR_PHI,
- VAR_E,
VAR_IN_W, VAR_IW,
VAR_IN_H, VAR_IH,
VAR_OUT_W, VAR_OW,
VAR_OUT_H, VAR_OH,
- VAR_A, VAR_DAR,
+ VAR_A,
VAR_SAR,
+ VAR_DAR,
VAR_HSUB,
VAR_VSUB,
+ VAR_OHSUB,
+ VAR_OVSUB,
VARS_NB
};
typedef struct ScaleContext {
const AVClass *class;
struct SwsContext *sws; ///< software scaler context
+ struct SwsContext *isws[2]; ///< software scaler context for interlaced material
+ AVDictionary *opts;
/**
* New dimensions. Special values are:
* 0 = original width/height
* -1 = keep original aspect
+ * -N = try to keep aspect but make sure it is divisible by N
*/
int w, h;
+ char *size_str;
unsigned int flags; ///sws flags
int hsub, vsub; ///< chroma subsampling
int slice_y; ///< top of current output slice
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;
char *w_expr; ///< width expression string
char *h_expr; ///< height expression string
char *flags_str;
+
+ char *in_color_matrix;
+ char *out_color_matrix;
+
+ int in_range;
+ int out_range;
+
+ int out_h_chr_pos;
+ int out_v_chr_pos;
+ int in_h_chr_pos;
+ int in_v_chr_pos;
+
+ int force_original_aspect_ratio;
} ScaleContext;
-static av_cold int init(AVFilterContext *ctx)
+static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts)
{
ScaleContext *scale = ctx->priv;
+ int ret;
+
+ 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");
+ return AVERROR(EINVAL);
+ }
+
+ if (scale->w_expr && !scale->h_expr)
+ FFSWAP(char *, scale->w_expr, scale->size_str);
+
+ if (scale->size_str) {
+ char buf[32];
+ if ((ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid size '%s'\n", scale->size_str);
+ return ret;
+ }
+ snprintf(buf, sizeof(buf)-1, "%d", scale->w);
+ av_opt_set(scale, "w", buf, 0);
+ snprintf(buf, sizeof(buf)-1, "%d", scale->h);
+ av_opt_set(scale, "h", buf, 0);
+ }
+ if (!scale->w_expr)
+ av_opt_set(scale, "w", "iw", 0);
+ if (!scale->h_expr)
+ av_opt_set(scale, "h", "ih", 0);
+
+ av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
+ scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
+
+ scale->flags = 0;
if (scale->flags_str) {
const AVClass *class = sws_get_class();
const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0,
AV_OPT_SEARCH_FAKE_OBJ);
int ret = av_opt_eval_flags(&class, o, scale->flags_str, &scale->flags);
-
if (ret < 0)
return ret;
}
+ scale->opts = *opts;
+ *opts = NULL;
return 0;
}
@@ -110,7 +165,10 @@ static av_cold void uninit(AVFilterContext *ctx)
{
ScaleContext *scale = ctx->priv;
sws_freeContext(scale->sws);
+ sws_freeContext(scale->isws[0]);
+ sws_freeContext(scale->isws[1]);
scale->sws = NULL;
+ av_dict_free(&scale->opts);
}
static int query_formats(AVFilterContext *ctx)
@@ -138,7 +196,7 @@ static int query_formats(AVFilterContext *ctx)
formats = NULL;
while ((desc = av_pix_fmt_desc_next(desc))) {
pix_fmt = av_pix_fmt_desc_get_id(desc);
- if ((sws_isSupportedOutput(pix_fmt) ||
+ if ((sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8 ||
sws_isSupportedEndiannessConversion(pix_fmt))
&& (ret = ff_add_format(&formats, pix_fmt)) < 0) {
ff_formats_unref(&formats);
@@ -151,20 +209,42 @@ static int query_formats(AVFilterContext *ctx)
return 0;
}
+static const int *parse_yuv_type(const char *s, enum AVColorSpace colorspace)
+{
+ if (!s)
+ s = "bt601";
+
+ if (s && strstr(s, "bt709")) {
+ colorspace = AVCOL_SPC_BT709;
+ } else if (s && strstr(s, "fcc")) {
+ colorspace = AVCOL_SPC_FCC;
+ } else if (s && strstr(s, "smpte240m")) {
+ colorspace = AVCOL_SPC_SMPTE240M;
+ } else if (s && (strstr(s, "bt601") || strstr(s, "bt470") || strstr(s, "smpte170m"))) {
+ colorspace = AVCOL_SPC_BT470BG;
+ }
+
+ if (colorspace < 1 || colorspace > 7) {
+ colorspace = AVCOL_SPC_BT470BG;
+ }
+
+ return sws_getCoefficients(colorspace);
+}
+
static int config_props(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
AVFilterLink *inlink = outlink->src->inputs[0];
+ enum AVPixelFormat outfmt = outlink->format;
ScaleContext *scale = ctx->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
int64_t w, h;
double var_values[VARS_NB], res;
char *expr;
int ret;
+ int factor_w, factor_h;
- var_values[VAR_PI] = M_PI;
- var_values[VAR_PHI] = M_PHI;
- var_values[VAR_E] = M_E;
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;
@@ -175,6 +255,8 @@ static int config_props(AVFilterLink *outlink)
var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
+ var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w;
+ var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h;
/* evaluate width and height */
av_expr_parse_and_eval(&res, (expr = scale->w_expr),
@@ -196,22 +278,47 @@ static int config_props(AVFilterLink *outlink)
w = scale->w;
h = scale->h;
- /* sanity check params */
- if (w < -1 || h < -1) {
- av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n");
- return AVERROR(EINVAL);
+ /* Check if it is requested that the result has to be divisible by a some
+ * factor (w or h = -n with n being the factor). */
+ factor_w = 1;
+ factor_h = 1;
+ if (w < -1) {
+ factor_w = -w;
}
- if (w == -1 && h == -1)
+ if (h < -1) {
+ factor_h = -h;
+ }
+
+ if (w < 0 && h < 0)
scale->w = scale->h = 0;
if (!(w = scale->w))
w = inlink->w;
if (!(h = scale->h))
h = inlink->h;
- if (w == -1)
- w = av_rescale(h, inlink->w, inlink->h);
- if (h == -1)
- h = av_rescale(w, inlink->h, inlink->w);
+
+ /* Make sure that the result is divisible by the factor we determined
+ * earlier. If no factor was set, it is nothing will happen as the default
+ * factor is 1 */
+ if (w < 0)
+ w = av_rescale(h, inlink->w, inlink->h * factor_w) * factor_w;
+ if (h < 0)
+ h = av_rescale(w, inlink->h, inlink->w * factor_h) * factor_h;
+
+ /* Note that force_original_aspect_ratio may overwrite the previous set
+ * dimensions so that it is not divisible by the set factors anymore. */
+ if (scale->force_original_aspect_ratio) {
+ int tmp_w = av_rescale(h, inlink->w, inlink->h);
+ int tmp_h = av_rescale(w, inlink->h, inlink->w);
+
+ if (scale->force_original_aspect_ratio == 1) {
+ w = FFMIN(tmp_w, w);
+ h = FFMIN(tmp_h, h);
+ } else {
+ w = FFMAX(tmp_w, w);
+ h = FFMAX(tmp_h, h);
+ }
+ }
if (w > INT_MAX || h > INT_MAX ||
(h * inlink->w) > INT_MAX ||
@@ -222,49 +329,146 @@ static int config_props(AVFilterLink *outlink)
outlink->h = h;
/* TODO: make algorithm configurable */
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s -> w:%d h:%d fmt:%s flags:0x%0x\n",
- inlink ->w, inlink ->h, av_get_pix_fmt_name(inlink->format),
- outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
- scale->flags);
scale->input_is_pal = desc->flags & AV_PIX_FMT_FLAG_PAL ||
desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL;
+ if (outfmt == AV_PIX_FMT_PAL8) outfmt = AV_PIX_FMT_BGR8;
+ scale->output_is_pal = av_pix_fmt_desc_get(outfmt)->flags & AV_PIX_FMT_FLAG_PAL ||
+ av_pix_fmt_desc_get(outfmt)->flags & AV_PIX_FMT_FLAG_PSEUDOPAL;
if (scale->sws)
sws_freeContext(scale->sws);
+ if (scale->isws[0])
+ sws_freeContext(scale->isws[0]);
+ if (scale->isws[1])
+ sws_freeContext(scale->isws[1]);
+ scale->isws[0] = scale->isws[1] = scale->sws = NULL;
if (inlink->w == outlink->w && inlink->h == outlink->h &&
inlink->format == outlink->format)
- scale->sws = NULL;
+ ;
else {
- scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
- outlink->w, outlink->h, outlink->format,
- scale->flags, NULL, NULL, NULL);
- if (!scale->sws)
- return AVERROR(EINVAL);
- }
+ struct SwsContext **swscs[3] = {&scale->sws, &scale->isws[0], &scale->isws[1]};
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ struct SwsContext **s = swscs[i];
+ *s = sws_alloc_context();
+ if (!*s)
+ return AVERROR(ENOMEM);
+
+ if (scale->opts) {
+ AVDictionaryEntry *e = NULL;
+
+ while ((e = av_dict_get(scale->opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = av_opt_set(*s, e->key, e->value, 0)) < 0)
+ return ret;
+ }
+ }
+ av_opt_set_int(*s, "srcw", inlink ->w, 0);
+ av_opt_set_int(*s, "srch", inlink ->h >> !!i, 0);
+ av_opt_set_int(*s, "src_format", inlink->format, 0);
+ av_opt_set_int(*s, "dstw", outlink->w, 0);
+ av_opt_set_int(*s, "dsth", outlink->h >> !!i, 0);
+ av_opt_set_int(*s, "dst_format", outfmt, 0);
+ av_opt_set_int(*s, "sws_flags", scale->flags, 0);
+
+ /* Override YUV420P settings to have the correct (MPEG-2) chroma positions
+ * MPEG-2 chroma positions are used by convention
+ * XXX: support other 4:2:0 pixel formats */
+ if (inlink->format == AV_PIX_FMT_YUV420P) {
+ scale->in_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192;
+ }
+
+ if (outlink->format == AV_PIX_FMT_YUV420P) {
+ scale->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", scale->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", scale->out_v_chr_pos, 0);
+
+ if ((ret = sws_init_context(*s, NULL, NULL)) < 0)
+ return ret;
+ if (!scale->interlaced)
+ break;
+ }
+ }
- if (inlink->sample_aspect_ratio.num)
- outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h*inlink->w,
- outlink->w*inlink->h},
- inlink->sample_aspect_ratio);
- else
+ if (inlink->sample_aspect_ratio.num){
+ outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
+ } else
outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
+ inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
+ inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
+ outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
+ outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
+ scale->flags);
return 0;
fail:
av_log(NULL, AV_LOG_ERROR,
- "Error when evaluating the expression '%s'\n", expr);
+ "Error when evaluating the expression '%s'.\n"
+ "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
+ expr, scale->w_expr, scale->h_expr);
return ret;
}
+static int scale_slice(AVFilterLink *link, AVFrame *out_buf, AVFrame *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
+{
+ ScaleContext *scale = link->dst->priv;
+ const uint8_t *in[4];
+ uint8_t *out[4];
+ int in_stride[4],out_stride[4];
+ int i;
+
+ for(i=0; i<4; i++){
+ int vsub= ((i+1)&2) ? scale->vsub : 0;
+ in_stride[i] = cur_pic->linesize[i] * mul;
+ out_stride[i] = out_buf->linesize[i] * mul;
+ in[i] = cur_pic->data[i] + ((y>>vsub)+field) * cur_pic->linesize[i];
+ out[i] = out_buf->data[i] + field * out_buf->linesize[i];
+ }
+ if(scale->input_is_pal)
+ in[1] = cur_pic->data[1];
+ if(scale->output_is_pal)
+ out[1] = out_buf->data[1];
+
+ return sws_scale(sws, in, in_stride, y/mul, h,
+ out,out_stride);
+}
+
static int filter_frame(AVFilterLink *link, AVFrame *in)
{
ScaleContext *scale = link->dst->priv;
AVFilterLink *outlink = link->dst->outputs[0];
AVFrame *out;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
+ char buf[32];
+ int in_range;
+
+ if (av_frame_get_colorspace(in) == AVCOL_SPC_YCGCO)
+ av_log(link->dst, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n");
+
+ if( in->width != link->w
+ || in->height != link->h
+ || in->format != link->format) {
+ int ret;
+ snprintf(buf, sizeof(buf)-1, "%d", outlink->w);
+ av_opt_set(scale, "w", buf, 0);
+ snprintf(buf, sizeof(buf)-1, "%d", outlink->h);
+ av_opt_set(scale, "h", buf, 0);
+
+ link->dst->inputs[0]->format = in->format;
+ link->dst->inputs[0]->w = in->width;
+ link->dst->inputs[0]->h = in->height;
+
+ if ((ret = config_props(outlink)) < 0)
+ return ret;
+ }
if (!scale->sws)
return ff_filter_frame(outlink, in);
@@ -282,38 +486,115 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
out->width = outlink->w;
out->height = outlink->h;
+ 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);
+
+ in_range = av_frame_get_color_range(in);
+
+ if ( scale->in_color_matrix
+ || scale->out_color_matrix
+ || scale-> in_range != AVCOL_RANGE_UNSPECIFIED
+ || in_range != AVCOL_RANGE_UNSPECIFIED
+ || scale->out_range != AVCOL_RANGE_UNSPECIFIED) {
+ int in_full, out_full, brightness, contrast, saturation;
+ const int *inv_table, *table;
+
+ sws_getColorspaceDetails(scale->sws, (int **)&inv_table, &in_full,
+ (int **)&table, &out_full,
+ &brightness, &contrast, &saturation);
+
+ if (scale->in_color_matrix)
+ inv_table = parse_yuv_type(scale->in_color_matrix, av_frame_get_colorspace(in));
+ if (scale->out_color_matrix)
+ table = parse_yuv_type(scale->out_color_matrix, AVCOL_SPC_UNSPECIFIED);
+
+ if (scale-> in_range != AVCOL_RANGE_UNSPECIFIED)
+ in_full = (scale-> in_range == AVCOL_RANGE_JPEG);
+ else if (in_range != AVCOL_RANGE_UNSPECIFIED)
+ in_full = (in_range == AVCOL_RANGE_JPEG);
+ if (scale->out_range != AVCOL_RANGE_UNSPECIFIED)
+ out_full = (scale->out_range == AVCOL_RANGE_JPEG);
+
+ sws_setColorspaceDetails(scale->sws, inv_table, in_full,
+ table, out_full,
+ brightness, contrast, saturation);
+ if (scale->isws[0])
+ sws_setColorspaceDetails(scale->isws[0], inv_table, in_full,
+ table, out_full,
+ brightness, contrast, saturation);
+ if (scale->isws[1])
+ sws_setColorspaceDetails(scale->isws[1], inv_table, in_full,
+ table, out_full,
+ brightness, contrast, saturation);
+ }
+
av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
(int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
(int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
INT_MAX);
- sws_scale(scale->sws, in->data, in->linesize, 0, in->height,
- out->data, out->linesize);
+ if(scale->interlaced>0 || (scale->interlaced<0 && in->interlaced_frame)){
+ scale_slice(link, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0);
+ scale_slice(link, out, in, scale->isws[1], 0, link->h /2, 2, 1);
+ }else{
+ scale_slice(link, out, in, scale->sws, 0, link->h, 1, 0);
+ }
av_frame_free(&in);
return ff_filter_frame(outlink, out);
}
+static const AVClass *child_class_next(const AVClass *prev)
+{
+ return prev ? NULL : sws_get_class();
+}
+
#define OFFSET(x) offsetof(ScaleContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS },
- { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS },
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption scale_options[] = {
+ { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "width", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
+ { "height","Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = FLAGS },
{ "flags", "Flags to pass to libswscale", OFFSET(flags_str), AV_OPT_TYPE_STRING, { .str = "bilinear" }, .flags = FLAGS },
- { NULL },
+ { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_INT, {.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 },
+ { "in_color_matrix", "set input YCbCr type", OFFSET(in_color_matrix), AV_OPT_TYPE_STRING, { .str = "auto" }, .flags = FLAGS },
+ { "out_color_matrix", "set output YCbCr type", OFFSET(out_color_matrix), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
+ { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" },
+ { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" },
+ { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, "range" },
+ { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" },
+ { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" },
+ { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" },
+ { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" },
+ { "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" },
+ { "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 },
+ { "out_h_chr_pos", "output horizontal chroma position in luma grid/256", OFFSET(out_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" },
+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" },
+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" },
+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" },
+ { NULL }
};
static const AVClass scale_class = {
- .class_name = "scale",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ .class_name = "scale",
+ .item_name = av_default_item_name,
+ .option = scale_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
+ .child_class_next = child_class_next,
};
static const AVFilterPad avfilter_vf_scale_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
},
{ NULL }
@@ -329,17 +610,13 @@ static const AVFilterPad avfilter_vf_scale_outputs[] = {
};
AVFilter ff_vf_scale = {
- .name = "scale",
- .description = NULL_IF_CONFIG_SMALL("Scale the input video to width:height size and/or convert the image format."),
-
- .init = init,
- .uninit = uninit,
-
+ .name = "scale",
+ .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),
+ .init_dict = init_dict,
+ .uninit = uninit,
.query_formats = query_formats,
-
- .priv_size = sizeof(ScaleContext),
- .priv_class = &scale_class,
-
- .inputs = avfilter_vf_scale_inputs,
- .outputs = avfilter_vf_scale_outputs,
+ .priv_size = sizeof(ScaleContext),
+ .priv_class = &scale_class,
+ .inputs = avfilter_vf_scale_inputs,
+ .outputs = avfilter_vf_scale_outputs,
};
diff --git a/libavfilter/vf_select.c b/libavfilter/vf_select.c
deleted file mode 100644
index 8d0e6c3be0..0000000000
--- a/libavfilter/vf_select.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (c) 2011 Stefano Sabatini
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * filter for selecting which frame passes in the filterchain
- */
-
-#include "libavutil/eval.h"
-#include "libavutil/fifo.h"
-#include "libavutil/internal.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-#include "avfilter.h"
-#include "internal.h"
-#include "video.h"
-
-static const char *const var_names[] = {
- "E", ///< Euler number
- "PHI", ///< golden ratio
- "PI", ///< greek pi
-
- "TB", ///< timebase
-
- "pts", ///< original pts in the file of the frame
- "start_pts", ///< first PTS in the stream, expressed in TB units
- "prev_pts", ///< previous frame PTS
- "prev_selected_pts", ///< previous selected frame PTS
-
- "t", ///< first PTS in seconds
- "start_t", ///< first PTS in the stream, expressed in seconds
- "prev_t", ///< previous frame time
- "prev_selected_t", ///< previously selected time
-
- "pict_type", ///< the type of picture in the movie
- "I",
- "P",
- "B",
- "S",
- "SI",
- "SP",
- "BI",
-
- "interlace_type", ///< the frame interlace type
- "PROGRESSIVE",
- "TOPFIRST",
- "BOTTOMFIRST",
-
- "n", ///< frame number (starting from zero)
- "selected_n", ///< selected frame number (starting from zero)
- "prev_selected_n", ///< number of the last selected frame
-
- "key", ///< tell if the frame is a key frame
- "pos", ///< original position in the file of the frame
-
- NULL
-};
-
-enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
-
- VAR_TB,
-
- VAR_PTS,
- VAR_START_PTS,
- VAR_PREV_PTS,
- VAR_PREV_SELECTED_PTS,
-
- VAR_T,
- VAR_START_T,
- VAR_PREV_T,
- VAR_PREV_SELECTED_T,
-
- VAR_PICT_TYPE,
- VAR_PICT_TYPE_I,
- VAR_PICT_TYPE_P,
- VAR_PICT_TYPE_B,
- VAR_PICT_TYPE_S,
- VAR_PICT_TYPE_SI,
- VAR_PICT_TYPE_SP,
- VAR_PICT_TYPE_BI,
-
- VAR_INTERLACE_TYPE,
- VAR_INTERLACE_TYPE_P,
- VAR_INTERLACE_TYPE_T,
- VAR_INTERLACE_TYPE_B,
-
- VAR_N,
- VAR_SELECTED_N,
- VAR_PREV_SELECTED_N,
-
- VAR_KEY,
-
- VAR_VARS_NB
-};
-
-#define FIFO_SIZE 8
-
-typedef struct SelectContext {
- const AVClass *class;
- char *expr_str;
- AVExpr *expr;
- double var_values[VAR_VARS_NB];
- double select;
- int cache_frames;
- AVFifoBuffer *pending_frames; ///< FIFO buffer of video frames
-} SelectContext;
-
-static av_cold int init(AVFilterContext *ctx)
-{
- SelectContext *select = ctx->priv;
- int ret;
-
- if ((ret = av_expr_parse(&select->expr, select->expr_str,
- var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n",
- select->expr_str);
- return ret;
- }
-
- select->pending_frames = av_fifo_alloc(FIFO_SIZE*sizeof(AVFrame*));
- if (!select->pending_frames) {
- av_log(ctx, AV_LOG_ERROR, "Failed to allocate pending frames buffer.\n");
- return AVERROR(ENOMEM);
- }
- return 0;
-}
-
-#define INTERLACE_TYPE_P 0
-#define INTERLACE_TYPE_T 1
-#define INTERLACE_TYPE_B 2
-
-static int config_input(AVFilterLink *inlink)
-{
- SelectContext *select = inlink->dst->priv;
-
- select->var_values[VAR_E] = M_E;
- select->var_values[VAR_PHI] = M_PHI;
- select->var_values[VAR_PI] = M_PI;
-
- select->var_values[VAR_N] = 0.0;
- select->var_values[VAR_SELECTED_N] = 0.0;
-
- select->var_values[VAR_TB] = av_q2d(inlink->time_base);
-
- select->var_values[VAR_PREV_PTS] = NAN;
- select->var_values[VAR_PREV_SELECTED_PTS] = NAN;
- select->var_values[VAR_PREV_SELECTED_T] = NAN;
- select->var_values[VAR_START_PTS] = NAN;
- select->var_values[VAR_START_T] = NAN;
-
- select->var_values[VAR_PICT_TYPE_I] = AV_PICTURE_TYPE_I;
- select->var_values[VAR_PICT_TYPE_P] = AV_PICTURE_TYPE_P;
- select->var_values[VAR_PICT_TYPE_B] = AV_PICTURE_TYPE_B;
- select->var_values[VAR_PICT_TYPE_SI] = AV_PICTURE_TYPE_SI;
- select->var_values[VAR_PICT_TYPE_SP] = AV_PICTURE_TYPE_SP;
-
- select->var_values[VAR_INTERLACE_TYPE_P] = INTERLACE_TYPE_P;
- select->var_values[VAR_INTERLACE_TYPE_T] = INTERLACE_TYPE_T;
- select->var_values[VAR_INTERLACE_TYPE_B] = INTERLACE_TYPE_B;;
-
- return 0;
-}
-
-#define D2TS(d) (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
-#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
-
-static int select_frame(AVFilterContext *ctx, AVFrame *frame)
-{
- SelectContext *select = ctx->priv;
- AVFilterLink *inlink = ctx->inputs[0];
- double res;
-
- if (isnan(select->var_values[VAR_START_PTS]))
- select->var_values[VAR_START_PTS] = TS2D(frame->pts);
- 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_PTS] = TS2D(frame->pts);
- select->var_values[VAR_T ] = TS2D(frame->pts) * av_q2d(inlink->time_base);
- select->var_values[VAR_PREV_PTS] = TS2D(frame->pts);
-
- select->var_values[VAR_INTERLACE_TYPE] =
- !frame->interlaced_frame ? INTERLACE_TYPE_P :
- frame->top_field_first ? INTERLACE_TYPE_T : INTERLACE_TYPE_B;
- select->var_values[VAR_PICT_TYPE] = frame->pict_type;
-
- res = av_expr_eval(select->expr, select->var_values, NULL);
-
- select->var_values[VAR_N] += 1.0;
-
- if (res) {
- select->var_values[VAR_PREV_SELECTED_N] = select->var_values[VAR_N];
- select->var_values[VAR_PREV_SELECTED_PTS] = select->var_values[VAR_PTS];
- select->var_values[VAR_PREV_SELECTED_T] = select->var_values[VAR_T];
- select->var_values[VAR_SELECTED_N] += 1.0;
- }
- return res;
-}
-
-static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
-{
- SelectContext *select = inlink->dst->priv;
-
- select->select = select_frame(inlink->dst, frame);
- if (select->select) {
- /* frame was requested through poll_frame */
- if (select->cache_frames) {
- if (!av_fifo_space(select->pending_frames)) {
- av_log(inlink->dst, AV_LOG_ERROR,
- "Buffering limit reached, cannot cache more frames\n");
- av_frame_free(&frame);
- } else
- av_fifo_generic_write(select->pending_frames, &frame,
- sizeof(frame), NULL);
- return 0;
- }
- return ff_filter_frame(inlink->dst->outputs[0], frame);
- }
-
- av_frame_free(&frame);
- return 0;
-}
-
-static int request_frame(AVFilterLink *outlink)
-{
- AVFilterContext *ctx = outlink->src;
- SelectContext *select = ctx->priv;
- AVFilterLink *inlink = outlink->src->inputs[0];
- select->select = 0;
-
- if (av_fifo_size(select->pending_frames)) {
- AVFrame *frame;
-
- av_fifo_generic_read(select->pending_frames, &frame, sizeof(frame), NULL);
- return ff_filter_frame(outlink, frame);
- }
-
- while (!select->select) {
- int ret = ff_request_frame(inlink);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int poll_frame(AVFilterLink *outlink)
-{
- SelectContext *select = outlink->src->priv;
- AVFilterLink *inlink = outlink->src->inputs[0];
- int count, ret;
-
- if (!av_fifo_size(select->pending_frames)) {
- if ((count = ff_poll_frame(inlink)) <= 0)
- return count;
- /* request frame from input, and apply select condition to it */
- select->cache_frames = 1;
- while (count-- && av_fifo_space(select->pending_frames)) {
- ret = ff_request_frame(inlink);
- if (ret < 0)
- break;
- }
- select->cache_frames = 0;
- }
-
- return av_fifo_size(select->pending_frames)/sizeof(AVFrame*);
-}
-
-static av_cold void uninit(AVFilterContext *ctx)
-{
- SelectContext *select = ctx->priv;
- AVFrame *frame;
-
- av_expr_free(select->expr);
- select->expr = NULL;
-
- while (select->pending_frames &&
- av_fifo_generic_read(select->pending_frames, &frame, sizeof(frame), NULL) == sizeof(frame))
- av_frame_free(&frame);
- av_fifo_free(select->pending_frames);
- select->pending_frames = NULL;
-}
-
-#define OFFSET(x) offsetof(SelectContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "expr", "An expression to use for selecting frames", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS },
- { NULL },
-};
-
-static const AVClass select_class = {
- .class_name = "select",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-static const AVFilterPad avfilter_vf_select_inputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .config_props = config_input,
- .filter_frame = filter_frame,
- },
- { NULL }
-};
-
-static const AVFilterPad avfilter_vf_select_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .poll_frame = poll_frame,
- .request_frame = request_frame,
- },
- { NULL }
-};
-
-AVFilter ff_vf_select = {
- .name = "select",
- .description = NULL_IF_CONFIG_SMALL("Select frames to pass in output."),
- .init = init,
- .uninit = uninit,
-
- .priv_size = sizeof(SelectContext),
- .priv_class = &select_class,
-
- .inputs = avfilter_vf_select_inputs,
- .outputs = avfilter_vf_select_outputs,
-};
diff --git a/libavfilter/vf_separatefields.c b/libavfilter/vf_separatefields.c
new file mode 100644
index 0000000000..42ce682972
--- /dev/null
+++ b/libavfilter/vf_separatefields.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+
+typedef struct {
+ int nb_planes;
+ AVFrame *second;
+} SeparateFieldsContext;
+
+static int config_props_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ SeparateFieldsContext *sf = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ sf->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ if (inlink->h & 1) {
+ av_log(ctx, AV_LOG_ERROR, "height must be even\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ 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;
+ outlink->w = inlink->w;
+ outlink->h = inlink->h / 2;
+
+ return 0;
+}
+
+static void extract_field(AVFrame *frame, int nb_planes, int type)
+{
+ int i;
+
+ for (i = 0; i < nb_planes; i++) {
+ if (type)
+ frame->data[i] = frame->data[i] + frame->linesize[i];
+ frame->linesize[i] *= 2;
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SeparateFieldsContext *sf = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int ret;
+
+ inpicref->height = outlink->h;
+ inpicref->interlaced_frame = 0;
+
+ if (!sf->second) {
+ goto clone;
+ } else {
+ AVFrame *second = sf->second;
+
+ extract_field(second, sf->nb_planes, second->top_field_first);
+
+ if (second->pts != AV_NOPTS_VALUE &&
+ inpicref->pts != AV_NOPTS_VALUE)
+ second->pts += inpicref->pts;
+ else
+ second->pts = AV_NOPTS_VALUE;
+
+ ret = ff_filter_frame(outlink, second);
+ if (ret < 0)
+ return ret;
+clone:
+ sf->second = av_frame_clone(inpicref);
+ if (!sf->second)
+ return AVERROR(ENOMEM);
+ }
+
+ extract_field(inpicref, sf->nb_planes, !inpicref->top_field_first);
+
+ if (inpicref->pts != AV_NOPTS_VALUE)
+ inpicref->pts *= 2;
+
+ return ff_filter_frame(outlink, inpicref);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ SeparateFieldsContext *sf = ctx->priv;
+ int ret;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+ if (ret == AVERROR_EOF && sf->second) {
+ sf->second->pts *= 2;
+ extract_field(sf->second, sf->nb_planes, sf->second->top_field_first);
+ ret = ff_filter_frame(outlink, sf->second);
+ sf->second = 0;
+ }
+
+ return ret;
+}
+
+static const AVFilterPad separatefields_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad separatefields_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_separatefields = {
+ .name = "separatefields",
+ .description = NULL_IF_CONFIG_SMALL("Split input video frames into fields."),
+ .priv_size = sizeof(SeparateFieldsContext),
+ .inputs = separatefields_inputs,
+ .outputs = separatefields_outputs,
+};
diff --git a/libavfilter/vf_setfield.c b/libavfilter/vf_setfield.c
new file mode 100644
index 0000000000..96e9d18bd3
--- /dev/null
+++ b/libavfilter/vf_setfield.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * set field order
+ */
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "video.h"
+
+enum SetFieldMode {
+ MODE_AUTO = -1,
+ MODE_BFF,
+ MODE_TFF,
+ MODE_PROG,
+};
+
+typedef struct {
+ const AVClass *class;
+ int mode; ///< SetFieldMode
+} SetFieldContext;
+
+#define OFFSET(x) offsetof(SetFieldContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption setfield_options[] = {
+ {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_AUTO}, -1, MODE_PROG, FLAGS, "mode"},
+ {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(setfield);
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+{
+ SetFieldContext *setfield = inlink->dst->priv;
+
+ if (setfield->mode == MODE_PROG) {
+ picref->interlaced_frame = 0;
+ } else if (setfield->mode != MODE_AUTO) {
+ picref->interlaced_frame = 1;
+ picref->top_field_first = setfield->mode;
+ }
+ return ff_filter_frame(inlink->dst->outputs[0], picref);
+}
+
+static const AVFilterPad setfield_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad setfield_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_setfield = {
+ .name = "setfield",
+ .description = NULL_IF_CONFIG_SMALL("Force field for the output video frame."),
+ .priv_size = sizeof(SetFieldContext),
+ .priv_class = &setfield_class,
+ .inputs = setfield_inputs,
+ .outputs = setfield_outputs,
+};
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index ede1765d1e..5125944798 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -1,19 +1,19 @@
/*
* Copyright (c) 2011 Stefano Sabatini
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,15 +30,12 @@
#include "libavutil/internal.h"
#include "libavutil/pixdesc.h"
#include "libavutil/stereo3d.h"
+#include "libavutil/timestamp.h"
#include "avfilter.h"
#include "internal.h"
#include "video.h"
-typedef struct ShowInfoContext {
- unsigned int frame;
-} ShowInfoContext;
-
static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd)
{
AVStereo3D *stereo;
@@ -69,34 +66,49 @@ static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd)
av_log(ctx, AV_LOG_INFO, " (inverted)");
}
+static void update_sample_stats(const uint8_t *src, int len, int64_t *sum, int64_t *sum2)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ *sum += src[i];
+ *sum2 += src[i] * src[i];
+ }
+}
+
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
{
AVFilterContext *ctx = inlink->dst;
- ShowInfoContext *showinfo = ctx->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
uint32_t plane_checksum[4] = {0}, checksum = 0;
+ int64_t sum[4] = {0}, sum2[4] = {0};
+ int32_t pixelcount[4] = {0};
int i, plane, vsub = desc->log2_chroma_h;
- for (plane = 0; frame->data[plane] && plane < 4; plane++) {
+ for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) {
uint8_t *data = frame->data[plane];
- int h = plane == 1 || plane == 2 ? inlink->h >> vsub : inlink->h;
+ int h = plane == 1 || plane == 2 ? FF_CEIL_RSHIFT(inlink->h, vsub) : inlink->h;
int linesize = av_image_get_linesize(frame->format, frame->width, plane);
+
if (linesize < 0)
return linesize;
for (i = 0; i < h; i++) {
plane_checksum[plane] = av_adler32_update(plane_checksum[plane], data, linesize);
checksum = av_adler32_update(checksum, data, linesize);
+
+ update_sample_stats(data, linesize, sum+plane, sum2+plane);
+ pixelcount[plane] += linesize;
data += frame->linesize[plane];
}
}
av_log(ctx, AV_LOG_INFO,
- "n:%d pts:%"PRId64" pts_time:%f "
+ "n:%4"PRId64" pts:%7s pts_time:%-7s pos:%9"PRId64" "
"fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c "
- "checksum:%"PRIu32" plane_checksum:[%"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"]\n",
- showinfo->frame,
- frame->pts, frame->pts * av_q2d(inlink->time_base),
+ "checksum:%08"PRIX32" plane_checksum:[%08"PRIX32,
+ inlink->frame_count,
+ av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base), av_frame_get_pkt_pos(frame),
desc->name,
frame->sample_aspect_ratio.num, frame->sample_aspect_ratio.den,
frame->width, frame->height,
@@ -104,7 +116,18 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
frame->top_field_first ? 'T' : 'B', /* Top / Bottom */
frame->key_frame,
av_get_picture_type_char(frame->pict_type),
- checksum, plane_checksum[0], plane_checksum[1], plane_checksum[2], plane_checksum[3]);
+ checksum, plane_checksum[0]);
+
+ for (plane = 1; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++)
+ av_log(ctx, AV_LOG_INFO, " %08"PRIX32, plane_checksum[plane]);
+ av_log(ctx, AV_LOG_INFO, "] mean:[");
+ for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++)
+ av_log(ctx, AV_LOG_INFO, "%"PRId64" ", (sum[plane] + pixelcount[plane]/2) / pixelcount[plane]);
+ av_log(ctx, AV_LOG_INFO, "\b] stdev:[");
+ for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++)
+ av_log(ctx, AV_LOG_INFO, "%3.1f ",
+ sqrt((sum2[plane] - sum[plane]*(double)sum[plane]/pixelcount[plane])/pixelcount[plane]));
+ av_log(ctx, AV_LOG_INFO, "\b]\n");
for (i = 0; i < frame->nb_side_data; i++) {
AVFrameSideData *sd = frame->side_data[i];
@@ -136,16 +159,39 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
av_log(ctx, AV_LOG_INFO, "\n");
}
- showinfo->frame++;
return ff_filter_frame(inlink->dst->outputs[0], frame);
}
+static int config_props(AVFilterContext *ctx, AVFilterLink *link, int is_out)
+{
+
+ 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
+ );
+
+ return 0;
+}
+
+static int config_props_in(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->dst;
+ return config_props(ctx, link, 0);
+}
+
+static int config_props_out(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->src;
+ return config_props(ctx, link, 1);
+}
+
static const AVFilterPad avfilter_vf_showinfo_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = ff_null_get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props_in,
},
{ NULL }
};
@@ -153,7 +199,8 @@ static const AVFilterPad avfilter_vf_showinfo_inputs[] = {
static const AVFilterPad avfilter_vf_showinfo_outputs[] = {
{
.name = "default",
- .type = AVMEDIA_TYPE_VIDEO
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props_out,
},
{ NULL }
};
@@ -161,10 +208,6 @@ static const AVFilterPad avfilter_vf_showinfo_outputs[] = {
AVFilter ff_vf_showinfo = {
.name = "showinfo",
.description = NULL_IF_CONFIG_SMALL("Show textual information for each video frame."),
-
- .priv_size = sizeof(ShowInfoContext),
-
- .inputs = avfilter_vf_showinfo_inputs,
-
- .outputs = avfilter_vf_showinfo_outputs,
+ .inputs = avfilter_vf_showinfo_inputs,
+ .outputs = avfilter_vf_showinfo_outputs,
};
diff --git a/libavfilter/vf_showpalette.c b/libavfilter/vf_showpalette.c
new file mode 100644
index 0000000000..e4d59b62c8
--- /dev/null
+++ b/libavfilter/vf_showpalette.c
@@ -0,0 +1,130 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Display frame palette (AV_PIX_FMT_PAL8)
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int size;
+} ShowPaletteContext;
+
+#define OFFSET(x) offsetof(ShowPaletteContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption showpalette_options[] = {
+ { "s", "set pixel box size", OFFSET(size), AV_OPT_TYPE_INT, {.i64=30}, 1, 100, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(showpalette);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat in_fmts[] = {AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE};
+ static const enum AVPixelFormat out_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+ AVFilterFormats *in = ff_make_format_list(in_fmts);
+ AVFilterFormats *out = ff_make_format_list(out_fmts);
+ if (!in || !out) {
+ av_freep(&in);
+ av_freep(&out);
+ return AVERROR(ENOMEM);
+ }
+ ff_formats_ref(in, &ctx->inputs[0]->out_formats);
+ ff_formats_ref(out, &ctx->outputs[0]->in_formats);
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ const ShowPaletteContext *s = ctx->priv;
+ outlink->w = outlink->h = 16 * s->size;
+ return 0;
+}
+
+static int disp_palette(AVFrame *out, const AVFrame *in, int size)
+{
+ int x, y, i, j;
+ uint32_t *dst = (uint32_t *)out->data[0];
+ const int dst_linesize = out->linesize[0] >> 2;
+ const uint32_t *pal = (uint32_t *)in->data[1];
+
+ for (y = 0; y < 16; y++)
+ for (x = 0; x < 16; x++)
+ for (j = 0; j < size; j++)
+ for (i = 0; i < size; i++)
+ dst[(y*dst_linesize + x) * size + j*dst_linesize + i] = pal[y*16 + x];
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ int ret;
+ AVFrame *out;
+ AVFilterContext *ctx = inlink->dst;
+ const ShowPaletteContext *s= ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ ret = disp_palette(out, in, s->size);
+ av_frame_free(&in);
+ return ret < 0 ? ret : ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad showpalette_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad showpalette_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_showpalette = {
+ .name = "showpalette",
+ .description = NULL_IF_CONFIG_SMALL("Display frame palette"),
+ .priv_size = sizeof(ShowPaletteContext),
+ .query_formats = query_formats,
+ .inputs = showpalette_inputs,
+ .outputs = showpalette_outputs,
+ .priv_class = &showpalette_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_shuffleplanes.c b/libavfilter/vf_shuffleplanes.c
index 1bc77b0a31..80085cd712 100644
--- a/libavfilter/vf_shuffleplanes.c
+++ b/libavfilter/vf_shuffleplanes.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -125,7 +125,7 @@ fail:
}
#define OFFSET(x) offsetof(ShufflePlanesContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
static const AVOption shuffleplanes_options[] = {
{ "map0", "Index of the input plane to be used as the first output plane ", OFFSET(map[0]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 4, FLAGS },
{ "map1", "Index of the input plane to be used as the second output plane ", OFFSET(map[1]), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 4, FLAGS },
diff --git a/libavfilter/vf_signalstats.c b/libavfilter/vf_signalstats.c
new file mode 100644
index 0000000000..88b715e698
--- /dev/null
+++ b/libavfilter/vf_signalstats.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2010 Mark Heath mjpeg0 @ silicontrip dot org
+ * Copyright (c) 2014 ClĂ©ment BÅ“sch
+ * Copyright (c) 2014 Dave Rice @dericed
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/pixdesc.h"
+#include "internal.h"
+
+enum FilterMode {
+ FILTER_NONE = -1,
+ FILTER_TOUT,
+ FILTER_VREP,
+ FILTER_BRNG,
+ FILT_NUMB
+};
+
+typedef struct {
+ const AVClass *class;
+ int chromah; // height of chroma plane
+ int chromaw; // width of chroma plane
+ int hsub; // horizontal subsampling
+ int vsub; // vertical subsampling
+ int fs; // pixel count per frame
+ int cfs; // pixel count per frame of chroma planes
+ int outfilter; // FilterMode
+ int filters;
+ AVFrame *frame_prev;
+ uint8_t rgba_color[4];
+ int yuv_color[3];
+ int nb_jobs;
+ int *jobs_rets;
+
+ AVFrame *frame_sat;
+ AVFrame *frame_hue;
+} SignalstatsContext;
+
+typedef struct ThreadData {
+ const AVFrame *in;
+ AVFrame *out;
+} ThreadData;
+
+typedef struct ThreadDataHueSatMetrics {
+ const AVFrame *src;
+ AVFrame *dst_sat, *dst_hue;
+} ThreadDataHueSatMetrics;
+
+#define OFFSET(x) offsetof(SignalstatsContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption signalstats_options[] = {
+ {"stat", "set statistics filters", OFFSET(filters), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, INT_MAX, FLAGS, "filters"},
+ {"tout", "analyze pixels for temporal outliers", 0, AV_OPT_TYPE_CONST, {.i64=1<<FILTER_TOUT}, 0, 0, FLAGS, "filters"},
+ {"vrep", "analyze video lines for vertical line repetition", 0, AV_OPT_TYPE_CONST, {.i64=1<<FILTER_VREP}, 0, 0, FLAGS, "filters"},
+ {"brng", "analyze for pixels outside of broadcast range", 0, AV_OPT_TYPE_CONST, {.i64=1<<FILTER_BRNG}, 0, 0, FLAGS, "filters"},
+ {"out", "set video filter", OFFSET(outfilter), AV_OPT_TYPE_INT, {.i64=FILTER_NONE}, -1, FILT_NUMB-1, FLAGS, "out"},
+ {"tout", "highlight pixels that depict temporal outliers", 0, AV_OPT_TYPE_CONST, {.i64=FILTER_TOUT}, 0, 0, FLAGS, "out"},
+ {"vrep", "highlight video lines that depict vertical line repetition", 0, AV_OPT_TYPE_CONST, {.i64=FILTER_VREP}, 0, 0, FLAGS, "out"},
+ {"brng", "highlight pixels that are outside of broadcast range", 0, AV_OPT_TYPE_CONST, {.i64=FILTER_BRNG}, 0, 0, FLAGS, "out"},
+ {"c", "set highlight color", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str="yellow"}, .flags=FLAGS},
+ {"color", "set highlight color", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str="yellow"}, .flags=FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(signalstats);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ uint8_t r, g, b;
+ SignalstatsContext *s = ctx->priv;
+
+ if (s->outfilter != FILTER_NONE)
+ s->filters |= 1 << s->outfilter;
+
+ r = s->rgba_color[0];
+ g = s->rgba_color[1];
+ b = s->rgba_color[2];
+ s->yuv_color[0] = (( 66*r + 129*g + 25*b + (1<<7)) >> 8) + 16;
+ s->yuv_color[1] = ((-38*r + -74*g + 112*b + (1<<7)) >> 8) + 128;
+ s->yuv_color[2] = ((112*r + -94*g + -18*b + (1<<7)) >> 8) + 128;
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SignalstatsContext *s = ctx->priv;
+ av_frame_free(&s->frame_prev);
+ av_frame_free(&s->frame_sat);
+ av_frame_free(&s->frame_hue);
+ av_freep(&s->jobs_rets);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ // TODO: add more
+ 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_YUV440P,
+ AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static AVFrame *alloc_frame(enum AVPixelFormat pixfmt, int w, int h)
+{
+ AVFrame *frame = av_frame_alloc();
+ if (!frame)
+ return NULL;
+
+ frame->format = pixfmt;
+ frame->width = w;
+ frame->height = h;
+
+ if (av_frame_get_buffer(frame, 32) < 0) {
+ av_frame_free(&frame);
+ return NULL;
+ }
+
+ return frame;
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ SignalstatsContext *s = ctx->priv;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
+ s->hsub = desc->log2_chroma_w;
+ s->vsub = desc->log2_chroma_h;
+
+ outlink->w = inlink->w;
+ outlink->h = inlink->h;
+
+ s->chromaw = FF_CEIL_RSHIFT(inlink->w, s->hsub);
+ s->chromah = FF_CEIL_RSHIFT(inlink->h, s->vsub);
+
+ s->fs = inlink->w * inlink->h;
+ s->cfs = s->chromaw * s->chromah;
+
+ s->nb_jobs = FFMAX(1, FFMIN(inlink->h, ctx->graph->nb_threads));
+ s->jobs_rets = av_malloc_array(s->nb_jobs, sizeof(*s->jobs_rets));
+ if (!s->jobs_rets)
+ return AVERROR(ENOMEM);
+
+ s->frame_sat = alloc_frame(AV_PIX_FMT_GRAY8, inlink->w, inlink->h);
+ s->frame_hue = alloc_frame(AV_PIX_FMT_GRAY16, inlink->w, inlink->h);
+ if (!s->frame_sat || !s->frame_hue)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static void burn_frame(const SignalstatsContext *s, AVFrame *f, int x, int y)
+{
+ const int chromax = x >> s->hsub;
+ const int chromay = y >> s->vsub;
+ f->data[0][y * f->linesize[0] + x] = s->yuv_color[0];
+ f->data[1][chromay * f->linesize[1] + chromax] = s->yuv_color[1];
+ f->data[2][chromay * f->linesize[2] + chromax] = s->yuv_color[2];
+}
+
+static int filter_brng(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ ThreadData *td = arg;
+ const SignalstatsContext *s = ctx->priv;
+ const AVFrame *in = td->in;
+ AVFrame *out = td->out;
+ const int w = in->width;
+ const int h = in->height;
+ const int slice_start = (h * jobnr ) / nb_jobs;
+ const int slice_end = (h * (jobnr+1)) / nb_jobs;
+ int x, y, score = 0;
+
+ for (y = slice_start; y < slice_end; y++) {
+ const int yc = y >> s->vsub;
+ const uint8_t *pluma = &in->data[0][y * in->linesize[0]];
+ const uint8_t *pchromau = &in->data[1][yc * in->linesize[1]];
+ const uint8_t *pchromav = &in->data[2][yc * in->linesize[2]];
+
+ for (x = 0; x < w; x++) {
+ const int xc = x >> s->hsub;
+ const int luma = pluma[x];
+ const int chromau = pchromau[xc];
+ const int chromav = pchromav[xc];
+ const int filt = luma < 16 || luma > 235 ||
+ chromau < 16 || chromau > 240 ||
+ chromav < 16 || chromav > 240;
+ score += filt;
+ if (out && filt)
+ burn_frame(s, out, x, y);
+ }
+ }
+ return score;
+}
+
+static int filter_tout_outlier(uint8_t x, uint8_t y, uint8_t z)
+{
+ return ((abs(x - y) + abs (z - y)) / 2) - abs(z - x) > 4; // make 4 configurable?
+}
+
+static int filter_tout(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ ThreadData *td = arg;
+ const SignalstatsContext *s = ctx->priv;
+ const AVFrame *in = td->in;
+ AVFrame *out = td->out;
+ const int w = in->width;
+ const int h = in->height;
+ const int slice_start = (h * jobnr ) / nb_jobs;
+ const int slice_end = (h * (jobnr+1)) / nb_jobs;
+ const uint8_t *p = in->data[0];
+ int lw = in->linesize[0];
+ int x, y, score = 0, filt;
+
+ for (y = slice_start; y < slice_end; y++) {
+
+ if (y - 1 < 0 || y + 1 >= h)
+ continue;
+
+ // detect two pixels above and below (to eliminate interlace artefacts)
+ // should check that video format is infact interlaced.
+
+#define FILTER(i, j) \
+ filter_tout_outlier(p[(y-j) * lw + x + i], \
+ p[ y * lw + x + i], \
+ p[(y+j) * lw + x + i])
+
+#define FILTER3(j) (FILTER(-1, j) && FILTER(0, j) && FILTER(1, j))
+
+ if (y - 2 >= 0 && y + 2 < h) {
+ for (x = 1; x < w - 1; x++) {
+ filt = FILTER3(2) && FILTER3(1);
+ score += filt;
+ if (filt && out)
+ burn_frame(s, out, x, y);
+ }
+ } else {
+ for (x = 1; x < w - 1; x++) {
+ filt = FILTER3(1);
+ score += filt;
+ if (filt && out)
+ burn_frame(s, out, x, y);
+ }
+ }
+ }
+ return score;
+}
+
+#define VREP_START 4
+
+static int filter_vrep(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ ThreadData *td = arg;
+ const SignalstatsContext *s = ctx->priv;
+ const AVFrame *in = td->in;
+ AVFrame *out = td->out;
+ const int w = in->width;
+ const int h = in->height;
+ const int slice_start = (h * jobnr ) / nb_jobs;
+ const int slice_end = (h * (jobnr+1)) / nb_jobs;
+ const uint8_t *p = in->data[0];
+ const int lw = in->linesize[0];
+ int x, y, score = 0;
+
+ for (y = slice_start; y < slice_end; y++) {
+ const int y2lw = (y - VREP_START) * lw;
+ const int ylw = y * lw;
+ int filt, totdiff = 0;
+
+ if (y < VREP_START)
+ continue;
+
+ for (x = 0; x < w; x++)
+ totdiff += abs(p[y2lw + x] - p[ylw + x]);
+ filt = totdiff < w;
+
+ score += filt;
+ if (filt && out)
+ for (x = 0; x < w; x++)
+ burn_frame(s, out, x, y);
+ }
+ return score * w;
+}
+
+static const struct {
+ const char *name;
+ int (*process)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
+} filters_def[] = {
+ {"TOUT", filter_tout},
+ {"VREP", filter_vrep},
+ {"BRNG", filter_brng},
+ {NULL}
+};
+
+#define DEPTH 256
+
+static int compute_sat_hue_metrics(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+ int i, j;
+ ThreadDataHueSatMetrics *td = arg;
+ const SignalstatsContext *s = ctx->priv;
+ const AVFrame *src = td->src;
+ AVFrame *dst_sat = td->dst_sat;
+ AVFrame *dst_hue = td->dst_hue;
+
+ const int slice_start = (s->chromah * jobnr ) / nb_jobs;
+ const int slice_end = (s->chromah * (jobnr+1)) / nb_jobs;
+
+ const int lsz_u = src->linesize[1];
+ const int lsz_v = src->linesize[2];
+ const uint8_t *p_u = src->data[1] + slice_start * lsz_u;
+ const uint8_t *p_v = src->data[2] + slice_start * lsz_v;
+
+ const int lsz_sat = dst_sat->linesize[0];
+ const int lsz_hue = dst_hue->linesize[0];
+ uint8_t *p_sat = dst_sat->data[0] + slice_start * lsz_sat;
+ uint8_t *p_hue = dst_hue->data[0] + slice_start * lsz_hue;
+
+ for (j = slice_start; j < slice_end; j++) {
+ for (i = 0; i < s->chromaw; i++) {
+ const int yuvu = p_u[i];
+ const int yuvv = p_v[i];
+ p_sat[i] = hypot(yuvu - 128, yuvv - 128); // int or round?
+ ((int16_t*)p_hue)[i] = floor((180 / M_PI) * atan2f(yuvu-128, yuvv-128) + 180);
+ }
+ p_u += lsz_u;
+ p_v += lsz_v;
+ p_sat += lsz_sat;
+ p_hue += lsz_hue;
+ }
+
+ return 0;
+}
+
+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[DEPTH] = {0},
+ histu[DEPTH] = {0},
+ histv[DEPTH] = {0},
+ histhue[360] = {0},
+ histsat[DEPTH] = {0}; // limited to 8 bit data.
+ 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;
+
+ 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);
+ av_frame_make_writable(out);
+ }
+
+ ctx->internal->execute(ctx, compute_sat_hue_metrics, &td_huesat,
+ NULL, FFMIN(s->chromah, ctx->graph->nb_threads));
+
+ // Calculate luma histogram and difference with previous frame or field.
+ for (j = 0; j < link->h; j++) {
+ for (i = 0; i < link->w; i++) {
+ const int yuv = in->data[0][w + i];
+ 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 (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];
+ 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<<fil) {
+ ThreadData td = {
+ .in = in,
+ .out = out != in && s->outfilter == fil ? out : NULL,
+ };
+ memset(s->jobs_rets, 0, s->nb_jobs * sizeof(*s->jobs_rets));
+ ctx->internal->execute(ctx, filters_def[fil].process,
+ &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 < DEPTH; 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);
+
+ for (fil = 0; fil < FILT_NUMB; fil ++) {
+ if (s->filters & 1<<fil) {
+ char metaname[128];
+ snprintf(metabuf, sizeof(metabuf), "%g", 1.0 * filtot[fil] / s->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 const AVFilterPad signalstats_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad signalstats_outputs[] = {
+ {
+ .name = "default",
+ .config_props = config_props,
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_signalstats = {
+ .name = "signalstats",
+ .description = "Generate statistics from video analysis.",
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .priv_size = sizeof(SignalstatsContext),
+ .inputs = signalstats_inputs,
+ .outputs = signalstats_outputs,
+ .priv_class = &signalstats_class,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_smartblur.c b/libavfilter/vf_smartblur.c
new file mode 100644
index 0000000000..169f540b15
--- /dev/null
+++ b/libavfilter/vf_smartblur.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2012 Jeremy Tran
+ *
+ * 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
+ * Apply a smartblur filter to the input video
+ * Ported from MPlayer libmpcodecs/vf_smartblur.c by Michael Niedermayer.
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libswscale/swscale.h"
+
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+
+#define RADIUS_MIN 0.1
+#define RADIUS_MAX 5.0
+
+#define STRENGTH_MIN -1.0
+#define STRENGTH_MAX 1.0
+
+#define THRESHOLD_MIN -30
+#define THRESHOLD_MAX 30
+
+typedef struct {
+ float radius;
+ float strength;
+ int threshold;
+ float quality;
+ struct SwsContext *filter_context;
+} FilterParam;
+
+typedef struct {
+ const AVClass *class;
+ FilterParam luma;
+ FilterParam chroma;
+ int hsub;
+ int vsub;
+ unsigned int sws_flags;
+} SmartblurContext;
+
+#define OFFSET(x) offsetof(SmartblurContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption smartblur_options[] = {
+ { "luma_radius", "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
+ { "lr" , "set luma radius", OFFSET(luma.radius), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, RADIUS_MIN, RADIUS_MAX, .flags=FLAGS },
+ { "luma_strength", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
+ { "ls", "set luma strength", OFFSET(luma.strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, STRENGTH_MIN, STRENGTH_MAX, .flags=FLAGS },
+ { "luma_threshold", "set luma threshold", OFFSET(luma.threshold), AV_OPT_TYPE_INT, {.i64=0}, THRESHOLD_MIN, THRESHOLD_MAX, .flags=FLAGS },
+ { "lt", "set luma threshold", OFFSET(luma.threshold), AV_OPT_TYPE_INT, {.i64=0}, THRESHOLD_MIN, THRESHOLD_MAX, .flags=FLAGS },
+
+ { "chroma_radius", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
+ { "cr", "set chroma radius", OFFSET(chroma.radius), AV_OPT_TYPE_FLOAT, {.dbl=RADIUS_MIN-1}, RADIUS_MIN-1, RADIUS_MAX, .flags=FLAGS },
+ { "chroma_strength", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
+ { "cs", "set chroma strength", OFFSET(chroma.strength), AV_OPT_TYPE_FLOAT, {.dbl=STRENGTH_MIN-1}, STRENGTH_MIN-1, STRENGTH_MAX, .flags=FLAGS },
+ { "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 },
+
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(smartblur);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ SmartblurContext *sblur = ctx->priv;
+
+ /* make chroma default to luma values, if not explicitly set */
+ if (sblur->chroma.radius < RADIUS_MIN)
+ sblur->chroma.radius = sblur->luma.radius;
+ if (sblur->chroma.strength < STRENGTH_MIN)
+ sblur->chroma.strength = sblur->luma.strength;
+ if (sblur->chroma.threshold < THRESHOLD_MIN)
+ sblur->chroma.threshold = sblur->luma.threshold;
+
+ sblur->luma.quality = sblur->chroma.quality = 3.0;
+ sblur->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",
+ sblur->luma.radius, sblur->luma.strength, sblur->luma.threshold,
+ sblur->chroma.radius, sblur->chroma.strength, sblur->chroma.threshold);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SmartblurContext *sblur = ctx->priv;
+
+ sws_freeContext(sblur->luma.filter_context);
+ sws_freeContext(sblur->chroma.filter_context);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int alloc_sws_context(FilterParam *f, int width, int height, unsigned int flags)
+{
+ SwsVector *vec;
+ SwsFilter sws_filter;
+
+ vec = sws_getGaussianVec(f->radius, f->quality);
+
+ if (!vec)
+ return AVERROR(EINVAL);
+
+ sws_scaleVec(vec, f->strength);
+ vec->coeff[vec->length / 2] += 1.0 - f->strength;
+ sws_filter.lumH = sws_filter.lumV = vec;
+ sws_filter.chrH = sws_filter.chrV = NULL;
+ f->filter_context = sws_getCachedContext(NULL,
+ width, height, AV_PIX_FMT_GRAY8,
+ width, height, AV_PIX_FMT_GRAY8,
+ flags, &sws_filter, NULL, NULL);
+
+ sws_freeVec(vec);
+
+ if (!f->filter_context)
+ return AVERROR(EINVAL);
+
+ return 0;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ SmartblurContext *sblur = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ sblur->hsub = desc->log2_chroma_w;
+ sblur->vsub = desc->log2_chroma_h;
+
+ alloc_sws_context(&sblur->luma, inlink->w, inlink->h, sblur->sws_flags);
+ alloc_sws_context(&sblur->chroma,
+ FF_CEIL_RSHIFT(inlink->w, sblur->hsub),
+ FF_CEIL_RSHIFT(inlink->h, sblur->vsub),
+ sblur->sws_flags);
+
+ return 0;
+}
+
+static void blur(uint8_t *dst, const int dst_linesize,
+ const uint8_t *src, const int src_linesize,
+ const int w, const int h, const int threshold,
+ struct SwsContext *filter_context)
+{
+ int x, y;
+ int orig, filtered;
+ int diff;
+ /* Declare arrays of 4 to get aligned data */
+ const uint8_t* const src_array[4] = {src};
+ uint8_t *dst_array[4] = {dst};
+ int src_linesize_array[4] = {src_linesize};
+ int dst_linesize_array[4] = {dst_linesize};
+
+ sws_scale(filter_context, src_array, src_linesize_array,
+ 0, h, dst_array, dst_linesize_array);
+
+ if (threshold > 0) {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ orig = src[x + y * src_linesize];
+ filtered = dst[x + y * dst_linesize];
+ diff = orig - filtered;
+
+ if (diff > 0) {
+ if (diff > 2 * threshold)
+ dst[x + y * dst_linesize] = orig;
+ else if (diff > threshold)
+ /* add 'diff' and subtract 'threshold' from 'filtered' */
+ dst[x + y * dst_linesize] = orig - threshold;
+ } else {
+ if (-diff > 2 * threshold)
+ dst[x + y * dst_linesize] = orig;
+ else if (-diff > threshold)
+ /* add 'diff' and 'threshold' to 'filtered' */
+ dst[x + y * dst_linesize] = orig + threshold;
+ }
+ }
+ }
+ } else if (threshold < 0) {
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ orig = src[x + y * src_linesize];
+ filtered = dst[x + y * dst_linesize];
+ diff = orig - filtered;
+
+ if (diff > 0) {
+ if (diff <= -threshold)
+ dst[x + y * dst_linesize] = orig;
+ else if (diff <= -2 * threshold)
+ /* subtract 'diff' and 'threshold' from 'orig' */
+ dst[x + y * dst_linesize] = filtered - threshold;
+ } else {
+ if (diff >= threshold)
+ dst[x + y * dst_linesize] = orig;
+ else if (diff >= 2 * threshold)
+ /* add 'threshold' and subtract 'diff' from 'orig' */
+ dst[x + y * dst_linesize] = filtered + threshold;
+ }
+ }
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
+{
+ SmartblurContext *sblur = inlink->dst->priv;
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpic;
+ int cw = FF_CEIL_RSHIFT(inlink->w, sblur->hsub);
+ int ch = FF_CEIL_RSHIFT(inlink->h, sblur->vsub);
+
+ outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpic) {
+ av_frame_free(&inpic);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpic, inpic);
+
+ blur(outpic->data[0], outpic->linesize[0],
+ inpic->data[0], inpic->linesize[0],
+ inlink->w, inlink->h, sblur->luma.threshold,
+ sblur->luma.filter_context);
+
+ if (inpic->data[2]) {
+ blur(outpic->data[1], outpic->linesize[1],
+ inpic->data[1], inpic->linesize[1],
+ cw, ch, sblur->chroma.threshold,
+ sblur->chroma.filter_context);
+ blur(outpic->data[2], outpic->linesize[2],
+ inpic->data[2], inpic->linesize[2],
+ cw, ch, sblur->chroma.threshold,
+ sblur->chroma.filter_context);
+ }
+
+ av_frame_free(&inpic);
+ return ff_filter_frame(outlink, outpic);
+}
+
+static const AVFilterPad smartblur_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad smartblur_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_smartblur = {
+ .name = "smartblur",
+ .description = NULL_IF_CONFIG_SMALL("Blur the input video without impacting the outlines."),
+ .priv_size = sizeof(SmartblurContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = smartblur_inputs,
+ .outputs = smartblur_outputs,
+ .priv_class = &smartblur_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_spp.c b/libavfilter/vf_spp.c
new file mode 100644
index 0000000000..b75f5f3937
--- /dev/null
+++ b/libavfilter/vf_spp.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * 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
+ * Simple post processing filter
+ *
+ * This implementation is based on an algorithm described in
+ * "Aria Nosratinia Embedded Post-Processing for
+ * Enhancement of Compressed Images (1999)"
+ *
+ * Originally written by Michael Niedermayer for the MPlayer project, and
+ * ported by ClĂ©ment BÅ“sch for FFmpeg.
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+#include "vf_spp.h"
+
+enum mode {
+ MODE_HARD,
+ MODE_SOFT,
+ NB_MODES
+};
+
+static const AVClass *child_class_next(const AVClass *prev)
+{
+ return prev ? NULL : avcodec_dct_get_class();
+}
+
+static void *child_next(void *obj, void *prev)
+{
+ SPPContext *s = obj;
+ return prev ? NULL : s->dct;
+}
+
+#define OFFSET(x) offsetof(SPPContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption spp_options[] = {
+ { "quality", "set quality", OFFSET(log2_count), AV_OPT_TYPE_INT, {.i64 = 3}, 0, MAX_LEVEL, FLAGS },
+ { "qp", "force a constant quantizer parameter", OFFSET(qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 63, FLAGS },
+ { "mode", "set thresholding mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_HARD}, 0, NB_MODES - 1, FLAGS, "mode" },
+ { "hard", "hard thresholding", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_HARD}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "soft", "soft thresholding", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_SOFT}, INT_MIN, INT_MAX, FLAGS, "mode" },
+ { "use_bframe_qp", "use B-frames' QP", OFFSET(use_bframe_qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+static const AVClass spp_class = {
+ .class_name = "spp",
+ .item_name = av_default_item_name,
+ .option = spp_options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
+ .child_class_next = child_class_next,
+ .child_next = child_next,
+};
+
+// XXX: share between filters?
+DECLARE_ALIGNED(8, static const uint8_t, ldither)[8][8] = {
+ { 0, 48, 12, 60, 3, 51, 15, 63 },
+ { 32, 16, 44, 28, 35, 19, 47, 31 },
+ { 8, 56, 4, 52, 11, 59, 7, 55 },
+ { 40, 24, 36, 20, 43, 27, 39, 23 },
+ { 2, 50, 14, 62, 1, 49, 13, 61 },
+ { 34, 18, 46, 30, 33, 17, 45, 29 },
+ { 10, 58, 6, 54, 9, 57, 5, 53 },
+ { 42, 26, 38, 22, 41, 25, 37, 21 },
+};
+
+static const uint8_t offset[127][2] = {
+ {0,0},
+ {0,0}, {4,4}, // quality = 1
+ {0,0}, {2,2}, {6,4}, {4,6}, // quality = 2
+ {0,0}, {5,1}, {2,2}, {7,3}, {4,4}, {1,5}, {6,6}, {3,7}, // quality = 3
+
+ {0,0}, {4,0}, {1,1}, {5,1}, {3,2}, {7,2}, {2,3}, {6,3}, // quality = 4
+ {0,4}, {4,4}, {1,5}, {5,5}, {3,6}, {7,6}, {2,7}, {6,7},
+
+ {0,0}, {0,2}, {0,4}, {0,6}, {1,1}, {1,3}, {1,5}, {1,7}, // quality = 5
+ {2,0}, {2,2}, {2,4}, {2,6}, {3,1}, {3,3}, {3,5}, {3,7},
+ {4,0}, {4,2}, {4,4}, {4,6}, {5,1}, {5,3}, {5,5}, {5,7},
+ {6,0}, {6,2}, {6,4}, {6,6}, {7,1}, {7,3}, {7,5}, {7,7},
+
+ {0,0}, {4,4}, {0,4}, {4,0}, {2,2}, {6,6}, {2,6}, {6,2}, // quality = 6
+ {0,2}, {4,6}, {0,6}, {4,2}, {2,0}, {6,4}, {2,4}, {6,0},
+ {1,1}, {5,5}, {1,5}, {5,1}, {3,3}, {7,7}, {3,7}, {7,3},
+ {1,3}, {5,7}, {1,7}, {5,3}, {3,1}, {7,5}, {3,5}, {7,1},
+ {0,1}, {4,5}, {0,5}, {4,1}, {2,3}, {6,7}, {2,7}, {6,3},
+ {0,3}, {4,7}, {0,7}, {4,3}, {2,1}, {6,5}, {2,5}, {6,1},
+ {1,0}, {5,4}, {1,4}, {5,0}, {3,2}, {7,6}, {3,6}, {7,2},
+ {1,2}, {5,6}, {1,6}, {5,2}, {3,0}, {7,4}, {3,4}, {7,0},
+};
+
+static void hardthresh_c(int16_t dst[64], const int16_t src[64],
+ int qp, const uint8_t *permutation)
+{
+ int i;
+ int bias = 0; // FIXME
+
+ unsigned threshold1 = qp * ((1<<4) - bias) - 1;
+ unsigned threshold2 = threshold1 << 1;
+
+ memset(dst, 0, 64 * sizeof(dst[0]));
+ dst[0] = (src[0] + 4) >> 3;
+
+ for (i = 1; i < 64; i++) {
+ int level = src[i];
+ if (((unsigned)(level + threshold1)) > threshold2) {
+ const int j = permutation[i];
+ dst[j] = (level + 4) >> 3;
+ }
+ }
+}
+
+static void softthresh_c(int16_t dst[64], const int16_t src[64],
+ int qp, const uint8_t *permutation)
+{
+ int i;
+ int bias = 0; //FIXME
+
+ unsigned threshold1 = qp * ((1<<4) - bias) - 1;
+ unsigned threshold2 = threshold1 << 1;
+
+ memset(dst, 0, 64 * sizeof(dst[0]));
+ dst[0] = (src[0] + 4) >> 3;
+
+ for (i = 1; i < 64; i++) {
+ int level = src[i];
+ if (((unsigned)(level + threshold1)) > threshold2) {
+ const int j = permutation[i];
+ if (level > 0) dst[j] = (level - threshold1 + 4) >> 3;
+ else dst[j] = (level + threshold1 + 4) >> 3;
+ }
+ }
+}
+
+static void store_slice_c(uint8_t *dst, const int16_t *src,
+ int dst_linesize, int src_linesize,
+ int width, int height, int log2_scale,
+ const uint8_t dither[8][8])
+{
+ int y, x;
+
+#define STORE(pos) do { \
+ temp = ((src[x + y*src_linesize + pos] << log2_scale) + d[pos]) >> 6; \
+ if (temp & 0x100) \
+ temp = ~(temp >> 31); \
+ dst[x + y*dst_linesize + pos] = temp; \
+} while (0)
+
+ for (y = 0; y < height; y++) {
+ const uint8_t *d = dither[y];
+ for (x = 0; x < width; x += 8) {
+ int temp;
+ STORE(0);
+ STORE(1);
+ STORE(2);
+ STORE(3);
+ STORE(4);
+ STORE(5);
+ STORE(6);
+ STORE(7);
+ }
+ }
+}
+
+static void store_slice16_c(uint16_t *dst, const int16_t *src,
+ int dst_linesize, int src_linesize,
+ int width, int height, int log2_scale,
+ const uint8_t dither[8][8], int depth)
+{
+ int y, x;
+ unsigned int mask = -1<<depth;
+
+#define STORE16(pos) do { \
+ temp = ((src[x + y*src_linesize + pos] << log2_scale) + (d[pos]>>1)) >> 5; \
+ if (temp & mask ) \
+ temp = ~(temp >> 31); \
+ dst[x + y*dst_linesize + pos] = temp; \
+} while (0)
+
+ for (y = 0; y < height; y++) {
+ const uint8_t *d = dither[y];
+ for (x = 0; x < width; x += 8) {
+ int temp;
+ STORE16(0);
+ STORE16(1);
+ STORE16(2);
+ STORE16(3);
+ STORE16(4);
+ STORE16(5);
+ STORE16(6);
+ STORE16(7);
+ }
+ }
+}
+
+static inline void add_block(uint16_t *dst, int linesize, const int16_t block[64])
+{
+ int y;
+
+ for (y = 0; y < 8; y++) {
+ *(uint32_t *)&dst[0 + y*linesize] += *(uint32_t *)&block[0 + y*8];
+ *(uint32_t *)&dst[2 + y*linesize] += *(uint32_t *)&block[2 + y*8];
+ *(uint32_t *)&dst[4 + y*linesize] += *(uint32_t *)&block[4 + y*8];
+ *(uint32_t *)&dst[6 + y*linesize] += *(uint32_t *)&block[6 + y*8];
+ }
+}
+
+static void filter(SPPContext *p, uint8_t *dst, uint8_t *src,
+ int dst_linesize, int src_linesize, int width, int height,
+ const uint8_t *qp_table, int qp_stride, int is_luma, int depth)
+{
+ int x, y, i;
+ const int count = 1 << p->log2_count;
+ const int linesize = is_luma ? p->temp_linesize : FFALIGN(width+16, 16);
+ DECLARE_ALIGNED(16, uint64_t, block_align)[32];
+ int16_t *block = (int16_t *)block_align;
+ int16_t *block2 = (int16_t *)(block_align + 16);
+ uint16_t *psrc16 = (uint16_t*)p->src;
+ const int sample_bytes = (depth+7) / 8;
+
+ for (y = 0; y < height; y++) {
+ int index = 8 + 8*linesize + y*linesize;
+ memcpy(p->src + index*sample_bytes, src + y*src_linesize, width*sample_bytes);
+ if (sample_bytes == 1) {
+ for (x = 0; x < 8; x++) {
+ p->src[index - x - 1] = p->src[index + x ];
+ p->src[index + width + x ] = p->src[index + width - x - 1];
+ }
+ } else {
+ for (x = 0; x < 8; x++) {
+ psrc16[index - x - 1] = psrc16[index + x ];
+ psrc16[index + width + x ] = psrc16[index + width - x - 1];
+ }
+ }
+ }
+ for (y = 0; y < 8; y++) {
+ memcpy(p->src + ( 7-y)*linesize * sample_bytes, p->src + ( y+8)*linesize * sample_bytes, linesize * sample_bytes);
+ memcpy(p->src + (height+8+y)*linesize * sample_bytes, p->src + (height-y+7)*linesize * sample_bytes, linesize * sample_bytes);
+ }
+
+ for (y = 0; y < height + 8; y += 8) {
+ memset(p->temp + (8 + y) * linesize, 0, 8 * linesize * sizeof(*p->temp));
+ for (x = 0; x < width + 8; x += 8) {
+ int qp;
+
+ if (p->qp) {
+ qp = p->qp;
+ } else{
+ const int qps = 3 + is_luma;
+ qp = qp_table[(FFMIN(x, width - 1) >> qps) + (FFMIN(y, height - 1) >> qps) * qp_stride];
+ qp = FFMAX(1, ff_norm_qscale(qp, p->qscale_type));
+ }
+ for (i = 0; i < count; i++) {
+ const int x1 = x + offset[i + count - 1][0];
+ const int y1 = y + offset[i + count - 1][1];
+ const int index = x1 + y1*linesize;
+ p->dct->get_pixels(block, p->src + sample_bytes*index, sample_bytes*linesize);
+ p->dct->fdct(block);
+ p->requantize(block2, block, qp, p->dct->idct_permutation);
+ p->dct->idct(block2);
+ add_block(p->temp + index, linesize, block2);
+ }
+ }
+ if (y) {
+ if (sample_bytes == 1) {
+ p->store_slice(dst + (y - 8) * dst_linesize, p->temp + 8 + y*linesize,
+ dst_linesize, linesize, width,
+ FFMIN(8, height + 8 - y), MAX_LEVEL - p->log2_count,
+ ldither);
+ } else {
+ store_slice16_c((uint16_t*)(dst + (y - 8) * dst_linesize), p->temp + 8 + y*linesize,
+ dst_linesize/2, linesize, width,
+ FFMIN(8, height + 8 - y), MAX_LEVEL - p->log2_count,
+ ldither, depth);
+ }
+ }
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10,
+ AV_PIX_FMT_YUV420P10,
+ AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9,
+ AV_PIX_FMT_YUV420P9,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_GBRP,
+ AV_PIX_FMT_GBRP9,
+ AV_PIX_FMT_GBRP10,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ SPPContext *spp = inlink->dst->priv;
+ const int h = FFALIGN(inlink->h + 16, 16);
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const int bps = desc->comp[0].depth_minus1 + 1;
+
+ av_opt_set_int(spp->dct, "bits_per_sample", bps, 0);
+ avcodec_dct_init(spp->dct);
+
+ if (ARCH_X86)
+ ff_spp_init_x86(spp);
+
+ spp->hsub = desc->log2_chroma_w;
+ spp->vsub = desc->log2_chroma_h;
+ spp->temp_linesize = FFALIGN(inlink->w + 16, 16);
+ spp->temp = av_malloc_array(spp->temp_linesize, h * sizeof(*spp->temp));
+ spp->src = av_malloc_array(spp->temp_linesize, h * sizeof(*spp->src) * 2);
+
+ if (!spp->temp || !spp->src)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ SPPContext *spp = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out = in;
+ int qp_stride = 0;
+ const int8_t *qp_table = NULL;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ const int depth = desc->comp[0].depth_minus1 + 1;
+
+ /* if we are not in a constant user quantizer mode and we don't want to use
+ * the quantizers from the B-frames (B-frames often have a higher QP), we
+ * need to save the qp table from the last non B-frame; this is what the
+ * following code block does */
+ if (!spp->qp) {
+ qp_table = av_frame_get_qp_table(in, &qp_stride, &spp->qscale_type);
+
+ if (qp_table && !spp->use_bframe_qp && in->pict_type != AV_PICTURE_TYPE_B) {
+ int w, h;
+
+ /* if the qp stride is not set, it means the QP are only defined on
+ * a line basis */
+ if (!qp_stride) {
+ w = FF_CEIL_RSHIFT(inlink->w, 4);
+ h = 1;
+ } else {
+ w = qp_stride;
+ h = FF_CEIL_RSHIFT(inlink->h, 4);
+ }
+
+ if (w * h > spp->non_b_qp_alloc_size) {
+ int ret = av_reallocp_array(&spp->non_b_qp_table, w, h);
+ if (ret < 0) {
+ spp->non_b_qp_alloc_size = 0;
+ return ret;
+ }
+ spp->non_b_qp_alloc_size = w * h;
+ }
+
+ av_assert0(w * h <= spp->non_b_qp_alloc_size);
+ memcpy(spp->non_b_qp_table, qp_table, w * h);
+ }
+ }
+
+ if (spp->log2_count && !ctx->is_disabled) {
+ if (!spp->use_bframe_qp && spp->non_b_qp_table)
+ qp_table = spp->non_b_qp_table;
+
+ if (qp_table || spp->qp) {
+ const int cw = FF_CEIL_RSHIFT(inlink->w, spp->hsub);
+ const int ch = FF_CEIL_RSHIFT(inlink->h, spp->vsub);
+
+ /* get a new frame if in-place is not possible or if the dimensions
+ * are not multiple of 8 */
+ if (!av_frame_is_writable(in) || (inlink->w & 7) || (inlink->h & 7)) {
+ const int aligned_w = FFALIGN(inlink->w, 8);
+ const int aligned_h = FFALIGN(inlink->h, 8);
+
+ out = ff_get_video_buffer(outlink, aligned_w, aligned_h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ out->width = in->width;
+ out->height = in->height;
+ }
+
+ filter(spp, out->data[0], in->data[0], out->linesize[0], in->linesize[0], inlink->w, inlink->h, qp_table, qp_stride, 1, depth);
+
+ if (out->data[2]) {
+ filter(spp, out->data[1], in->data[1], out->linesize[1], in->linesize[1], cw, ch, qp_table, qp_stride, 0, depth);
+ filter(spp, out->data[2], in->data[2], out->linesize[2], in->linesize[2], cw, ch, qp_table, qp_stride, 0, depth);
+ }
+ emms_c();
+ }
+ }
+
+ if (in != out) {
+ if (in->data[3])
+ av_image_copy_plane(out->data[3], out->linesize[3],
+ in ->data[3], in ->linesize[3],
+ inlink->w, inlink->h);
+ av_frame_free(&in);
+ }
+ return ff_filter_frame(outlink, out);
+}
+
+static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ SPPContext *spp = ctx->priv;
+
+ if (!strcmp(cmd, "level")) {
+ if (!strcmp(args, "max"))
+ spp->log2_count = MAX_LEVEL;
+ else
+ spp->log2_count = av_clip(strtol(args, NULL, 10), 0, MAX_LEVEL);
+ return 0;
+ }
+ return AVERROR(ENOSYS);
+}
+
+static av_cold int init_dict(AVFilterContext *ctx, AVDictionary **opts)
+{
+ SPPContext *spp = ctx->priv;
+ int ret;
+
+ spp->avctx = avcodec_alloc_context3(NULL);
+ spp->dct = avcodec_dct_alloc();
+ if (!spp->avctx || !spp->dct)
+ return AVERROR(ENOMEM);
+
+ if (opts) {
+ AVDictionaryEntry *e = NULL;
+
+ while ((e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = av_opt_set(spp->dct, e->key, e->value, 0)) < 0)
+ return ret;
+ }
+ av_dict_free(opts);
+ }
+
+ spp->store_slice = store_slice_c;
+ switch (spp->mode) {
+ case MODE_HARD: spp->requantize = hardthresh_c; break;
+ case MODE_SOFT: spp->requantize = softthresh_c; break;
+ }
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SPPContext *spp = ctx->priv;
+
+ av_freep(&spp->temp);
+ av_freep(&spp->src);
+ if (spp->avctx) {
+ avcodec_close(spp->avctx);
+ av_freep(&spp->avctx);
+ }
+ av_freep(&spp->dct);
+ av_freep(&spp->non_b_qp_table);
+}
+
+static const AVFilterPad spp_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad spp_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_spp = {
+ .name = "spp",
+ .description = NULL_IF_CONFIG_SMALL("Apply a simple post processing filter."),
+ .priv_size = sizeof(SPPContext),
+ .init_dict = init_dict,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = spp_inputs,
+ .outputs = spp_outputs,
+ .process_command = process_command,
+ .priv_class = &spp_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_spp.h b/libavfilter/vf_spp.h
new file mode 100644
index 0000000000..6b70a91770
--- /dev/null
+++ b/libavfilter/vf_spp.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ */
+
+#ifndef AVFILTER_SPP_H
+#define AVFILTER_SPP_H
+
+#include "libavcodec/avcodec.h"
+#include "libavcodec/avdct.h"
+#include "avfilter.h"
+
+#define MAX_LEVEL 6 /* quality levels */
+
+typedef struct {
+ const AVClass *av_class;
+
+ int log2_count;
+ int qp;
+ int mode;
+ int qscale_type;
+ int temp_linesize;
+ uint8_t *src;
+ uint16_t *temp;
+ AVCodecContext *avctx;
+ AVDCT *dct;
+ int8_t *non_b_qp_table;
+ int non_b_qp_alloc_size;
+ int use_bframe_qp;
+ int hsub, vsub;
+
+ void (*store_slice)(uint8_t *dst, const int16_t *src,
+ int dst_stride, int src_stride,
+ int width, int height, int log2_scale,
+ const uint8_t dither[8][8]);
+
+ void (*requantize)(int16_t dst[64], const int16_t src[64],
+ int qp, const uint8_t *permutation);
+} SPPContext;
+
+void ff_spp_init_x86(SPPContext *s);
+
+#endif /* AVFILTER_SPP_H */
diff --git a/libavfilter/vf_stereo3d.c b/libavfilter/vf_stereo3d.c
new file mode 100644
index 0000000000..771bdde676
--- /dev/null
+++ b/libavfilter/vf_stereo3d.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2010 Gordon Schmidt <gordon.schmidt <at> s2000.tu-chemnitz.de>
+ * Copyright (c) 2013 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 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/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+enum StereoCode {
+ ANAGLYPH_RC_GRAY, // anaglyph red/cyan gray
+ ANAGLYPH_RC_HALF, // anaglyph red/cyan half colored
+ ANAGLYPH_RC_COLOR, // anaglyph red/cyan colored
+ ANAGLYPH_RC_DUBOIS, // anaglyph red/cyan dubois
+ ANAGLYPH_GM_GRAY, // anaglyph green/magenta gray
+ ANAGLYPH_GM_HALF, // anaglyph green/magenta half colored
+ ANAGLYPH_GM_COLOR, // anaglyph green/magenta colored
+ ANAGLYPH_GM_DUBOIS, // anaglyph green/magenta dubois
+ ANAGLYPH_YB_GRAY, // anaglyph yellow/blue gray
+ ANAGLYPH_YB_HALF, // anaglyph yellow/blue half colored
+ ANAGLYPH_YB_COLOR, // anaglyph yellow/blue colored
+ ANAGLYPH_YB_DUBOIS, // anaglyph yellow/blue dubois
+ ANAGLYPH_RB_GRAY, // anaglyph red/blue gray
+ ANAGLYPH_RG_GRAY, // anaglyph red/green gray
+ MONO_L, // mono output for debugging (left eye only)
+ MONO_R, // mono output for debugging (right eye only)
+ INTERLEAVE_ROWS_LR, // row-interleave (left eye has top row)
+ INTERLEAVE_ROWS_RL, // row-interleave (right eye has top row)
+ SIDE_BY_SIDE_LR, // side by side parallel (left eye left, right eye right)
+ SIDE_BY_SIDE_RL, // side by side crosseye (right eye left, left eye right)
+ SIDE_BY_SIDE_2_LR, // side by side parallel with half width resolution
+ SIDE_BY_SIDE_2_RL, // side by side crosseye with half width resolution
+ ABOVE_BELOW_LR, // above-below (left eye above, right eye below)
+ ABOVE_BELOW_RL, // above-below (right eye above, left eye below)
+ ABOVE_BELOW_2_LR, // above-below with half height resolution
+ ABOVE_BELOW_2_RL, // above-below with half height resolution
+ ALTERNATING_LR, // alternating frames (left eye first, right eye second)
+ ALTERNATING_RL, // alternating frames (right eye first, left eye second)
+ STEREO_CODE_COUNT // TODO: needs autodetection
+};
+
+typedef struct StereoComponent {
+ int format; ///< StereoCode
+ int width, height;
+ int off_left, off_right;
+ int off_lstep, off_rstep;
+ int row_left, row_right;
+} StereoComponent;
+
+static const int ana_coeff[][3][6] = {
+ [ANAGLYPH_RB_GRAY] =
+ {{19595, 38470, 7471, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 19595, 38470, 7471}},
+ [ANAGLYPH_RG_GRAY] =
+ {{19595, 38470, 7471, 0, 0, 0},
+ { 0, 0, 0, 19595, 38470, 7471},
+ { 0, 0, 0, 0, 0, 0}},
+ [ANAGLYPH_RC_GRAY] =
+ {{19595, 38470, 7471, 0, 0, 0},
+ { 0, 0, 0, 19595, 38470, 7471},
+ { 0, 0, 0, 19595, 38470, 7471}},
+ [ANAGLYPH_RC_HALF] =
+ {{19595, 38470, 7471, 0, 0, 0},
+ { 0, 0, 0, 0, 65536, 0},
+ { 0, 0, 0, 0, 0, 65536}},
+ [ANAGLYPH_RC_COLOR] =
+ {{65536, 0, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 65536, 0},
+ { 0, 0, 0, 0, 0, 65536}},
+ [ANAGLYPH_RC_DUBOIS] =
+ {{29891, 32800, 11559, -2849, -5763, -102},
+ {-2627, -2479, -1033, 24804, 48080, -1209},
+ { -997, -1350, -358, -4729, -7403, 80373}},
+ [ANAGLYPH_GM_GRAY] =
+ {{ 0, 0, 0, 19595, 38470, 7471},
+ {19595, 38470, 7471, 0, 0, 0},
+ { 0, 0, 0, 19595, 38470, 7471}},
+ [ANAGLYPH_GM_HALF] =
+ {{ 0, 0, 0, 65536, 0, 0},
+ {19595, 38470, 7471, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 65536}},
+ [ANAGLYPH_GM_COLOR] =
+ {{ 0, 0, 0, 65536, 0, 0},
+ { 0, 65536, 0, 0, 0, 0},
+ { 0, 0, 0, 0, 0, 65536}},
+ [ANAGLYPH_GM_DUBOIS] =
+ {{-4063,-10354, -2556, 34669, 46203, 1573},
+ {18612, 43778, 9372, -1049, -983, -4260},
+ { -983, -1769, 1376, 590, 4915, 61407}},
+ [ANAGLYPH_YB_GRAY] =
+ {{ 0, 0, 0, 19595, 38470, 7471},
+ { 0, 0, 0, 19595, 38470, 7471},
+ {19595, 38470, 7471, 0, 0, 0}},
+ [ANAGLYPH_YB_HALF] =
+ {{ 0, 0, 0, 65536, 0, 0},
+ { 0, 0, 0, 0, 65536, 0},
+ {19595, 38470, 7471, 0, 0, 0}},
+ [ANAGLYPH_YB_COLOR] =
+ {{ 0, 0, 0, 65536, 0, 0},
+ { 0, 0, 0, 0, 65536, 0},
+ { 0, 0, 65536, 0, 0, 0}},
+ [ANAGLYPH_YB_DUBOIS] =
+ {{65535,-12650,18451, -987, -7590, -1049},
+ {-1604, 56032, 4196, 370, 3826, -1049},
+ {-2345,-10676, 1358, 5801, 11416, 56217}},
+};
+
+typedef struct Stereo3DContext {
+ const AVClass *class;
+ StereoComponent in, out;
+ int width, height;
+ int row_step;
+ const int *ana_matrix[3];
+ int nb_planes;
+ int linesize[4];
+ int pheight[4];
+ int hsub, vsub;
+ int pixstep[4];
+ AVFrame *prev;
+ double ts_unit;
+} Stereo3DContext;
+
+#define OFFSET(x) offsetof(Stereo3DContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption stereo3d_options[] = {
+ { "in", "set input format", OFFSET(in.format), AV_OPT_TYPE_INT, {.i64=SIDE_BY_SIDE_LR}, SIDE_BY_SIDE_LR, STEREO_CODE_COUNT-1, FLAGS, "in"},
+ { "ab2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, "in" },
+ { "ab2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, "in" },
+ { "abl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, "in" },
+ { "abr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, "in" },
+ { "al", "alternating frames left first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_LR}, 0, 0, FLAGS, "in" },
+ { "ar", "alternating frames right first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_RL}, 0, 0, FLAGS, "in" },
+ { "sbs2l", "side by side half width left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, "in" },
+ { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, "in" },
+ { "sbsl", "side by side left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR}, 0, 0, FLAGS, "in" },
+ { "sbsr", "side by side right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL}, 0, 0, FLAGS, "in" },
+ { "out", "set output format", OFFSET(out.format), AV_OPT_TYPE_INT, {.i64=ANAGLYPH_RC_DUBOIS}, 0, STEREO_CODE_COUNT-1, FLAGS, "out"},
+ { "ab2l", "above below half height left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_LR}, 0, 0, FLAGS, "out" },
+ { "ab2r", "above below half height right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_2_RL}, 0, 0, FLAGS, "out" },
+ { "abl", "above below left first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_LR}, 0, 0, FLAGS, "out" },
+ { "abr", "above below right first", 0, AV_OPT_TYPE_CONST, {.i64=ABOVE_BELOW_RL}, 0, 0, FLAGS, "out" },
+ { "agmc", "anaglyph green magenta color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_COLOR}, 0, 0, FLAGS, "out" },
+ { "agmd", "anaglyph green magenta dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_DUBOIS}, 0, 0, FLAGS, "out" },
+ { "agmg", "anaglyph green magenta gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_GRAY}, 0, 0, FLAGS, "out" },
+ { "agmh", "anaglyph green magenta half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_GM_HALF}, 0, 0, FLAGS, "out" },
+ { "al", "alternating frames left first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_LR}, 0, 0, FLAGS, "out" },
+ { "ar", "alternating frames right first", 0, AV_OPT_TYPE_CONST, {.i64=ALTERNATING_RL}, 0, 0, FLAGS, "out" },
+ { "arbg", "anaglyph red blue gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RB_GRAY}, 0, 0, FLAGS, "out" },
+ { "arcc", "anaglyph red cyan color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_COLOR}, 0, 0, FLAGS, "out" },
+ { "arcd", "anaglyph red cyan dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_DUBOIS}, 0, 0, FLAGS, "out" },
+ { "arcg", "anaglyph red cyan gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_GRAY}, 0, 0, FLAGS, "out" },
+ { "arch", "anaglyph red cyan half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RC_HALF}, 0, 0, FLAGS, "out" },
+ { "argg", "anaglyph red green gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_RG_GRAY}, 0, 0, FLAGS, "out" },
+ { "aybc", "anaglyph yellow blue color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_COLOR}, 0, 0, FLAGS, "out" },
+ { "aybd", "anaglyph yellow blue dubois", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_DUBOIS}, 0, 0, FLAGS, "out" },
+ { "aybg", "anaglyph yellow blue gray", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_GRAY}, 0, 0, FLAGS, "out" },
+ { "aybh", "anaglyph yellow blue half color", 0, AV_OPT_TYPE_CONST, {.i64=ANAGLYPH_YB_HALF}, 0, 0, FLAGS, "out" },
+ { "irl", "interleave rows left first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_LR}, 0, 0, FLAGS, "out" },
+ { "irr", "interleave rows right first", 0, AV_OPT_TYPE_CONST, {.i64=INTERLEAVE_ROWS_RL}, 0, 0, FLAGS, "out" },
+ { "ml", "mono left", 0, AV_OPT_TYPE_CONST, {.i64=MONO_L}, 0, 0, FLAGS, "out" },
+ { "mr", "mono right", 0, AV_OPT_TYPE_CONST, {.i64=MONO_R}, 0, 0, FLAGS, "out" },
+ { "sbs2l", "side by side half width left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_LR}, 0, 0, FLAGS, "out" },
+ { "sbs2r", "side by side half width right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_2_RL}, 0, 0, FLAGS, "out" },
+ { "sbsl", "side by side left first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_LR}, 0, 0, FLAGS, "out" },
+ { "sbsr", "side by side right first", 0, AV_OPT_TYPE_CONST, {.i64=SIDE_BY_SIDE_RL}, 0, 0, FLAGS, "out" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(stereo3d);
+
+static const enum AVPixelFormat anaglyph_pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+};
+
+static const enum AVPixelFormat other_pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGB48BE, AV_PIX_FMT_BGR48BE,
+ AV_PIX_FMT_RGB48LE, AV_PIX_FMT_BGR48LE,
+ AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_BGRA64BE,
+ AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_BGRA64LE,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_GBRP,
+ AV_PIX_FMT_GBRP9BE, AV_PIX_FMT_GBRP9LE,
+ AV_PIX_FMT_GBRP10BE, AV_PIX_FMT_GBRP10LE,
+ AV_PIX_FMT_GBRP12BE, AV_PIX_FMT_GBRP12LE,
+ AV_PIX_FMT_GBRP14BE, AV_PIX_FMT_GBRP14LE,
+ AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRP16LE,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUV440P,
+ AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVJ422P,
+ AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUV420P9LE, AV_PIX_FMT_YUVA420P9LE,
+ AV_PIX_FMT_YUV420P9BE, AV_PIX_FMT_YUVA420P9BE,
+ AV_PIX_FMT_YUV422P9LE, AV_PIX_FMT_YUVA422P9LE,
+ AV_PIX_FMT_YUV422P9BE, AV_PIX_FMT_YUVA422P9BE,
+ AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUVA444P9LE,
+ AV_PIX_FMT_YUV444P9BE, AV_PIX_FMT_YUVA444P9BE,
+ AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUVA420P10LE,
+ AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUVA420P10BE,
+ AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUVA422P10LE,
+ AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUVA422P10BE,
+ AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUVA444P10LE,
+ AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUVA444P10BE,
+ AV_PIX_FMT_YUV420P12BE, AV_PIX_FMT_YUV420P12LE,
+ AV_PIX_FMT_YUV422P12BE, AV_PIX_FMT_YUV422P12LE,
+ AV_PIX_FMT_YUV444P12BE, AV_PIX_FMT_YUV444P12LE,
+ AV_PIX_FMT_YUV420P14BE, AV_PIX_FMT_YUV420P14LE,
+ AV_PIX_FMT_YUV422P14BE, AV_PIX_FMT_YUV422P14LE,
+ AV_PIX_FMT_YUV444P14BE, AV_PIX_FMT_YUV444P14LE,
+ AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUVA420P16LE,
+ AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUVA420P16BE,
+ AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUVA422P16LE,
+ AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUVA422P16BE,
+ AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUVA444P16LE,
+ AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUVA444P16BE,
+ AV_PIX_FMT_NONE
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ Stereo3DContext *s = ctx->priv;
+ const enum AVPixelFormat *pix_fmts;
+ AVFilterFormats *fmts_list;
+
+ switch (s->out.format) {
+ case ANAGLYPH_GM_COLOR:
+ case ANAGLYPH_GM_DUBOIS:
+ case ANAGLYPH_GM_GRAY:
+ case ANAGLYPH_GM_HALF:
+ case ANAGLYPH_RB_GRAY:
+ case ANAGLYPH_RC_COLOR:
+ case ANAGLYPH_RC_DUBOIS:
+ case ANAGLYPH_RC_GRAY:
+ case ANAGLYPH_RC_HALF:
+ case ANAGLYPH_RG_GRAY:
+ case ANAGLYPH_YB_COLOR:
+ case ANAGLYPH_YB_DUBOIS:
+ case ANAGLYPH_YB_GRAY:
+ case ANAGLYPH_YB_HALF:
+ pix_fmts = anaglyph_pix_fmts;
+ break;
+ default:
+ pix_fmts = other_pix_fmts;
+ }
+
+ fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = ctx->inputs[0];
+ Stereo3DContext *s = ctx->priv;
+ AVRational aspect = inlink->sample_aspect_ratio;
+ AVRational fps = inlink->frame_rate;
+ AVRational tb = inlink->time_base;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
+ int ret;
+
+ switch (s->in.format) {
+ case SIDE_BY_SIDE_2_LR:
+ case SIDE_BY_SIDE_LR:
+ case SIDE_BY_SIDE_2_RL:
+ case SIDE_BY_SIDE_RL:
+ if (inlink->w & 1) {
+ av_log(ctx, AV_LOG_ERROR, "width must be even\n");
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ case ABOVE_BELOW_2_LR:
+ case ABOVE_BELOW_LR:
+ case ABOVE_BELOW_2_RL:
+ case ABOVE_BELOW_RL:
+ if (s->out.format == INTERLEAVE_ROWS_LR ||
+ s->out.format == INTERLEAVE_ROWS_RL) {
+ if (inlink->h & 3) {
+ av_log(ctx, AV_LOG_ERROR, "height must be multiple of 4\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ if (inlink->h & 1) {
+ av_log(ctx, AV_LOG_ERROR, "height must be even\n");
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ }
+
+ s->in.width =
+ s->width = inlink->w;
+ s->in.height =
+ s->height = inlink->h;
+ s->row_step = 1;
+ s->in.off_lstep =
+ s->in.off_rstep =
+ s->in.off_left =
+ s->in.off_right =
+ s->in.row_left =
+ s->in.row_right = 0;
+
+ switch (s->in.format) {
+ case SIDE_BY_SIDE_2_LR:
+ aspect.num *= 2;
+ case SIDE_BY_SIDE_LR:
+ s->width = inlink->w / 2;
+ s->in.off_right = s->width;
+ break;
+ case SIDE_BY_SIDE_2_RL:
+ aspect.num *= 2;
+ case SIDE_BY_SIDE_RL:
+ s->width = inlink->w / 2;
+ s->in.off_left = s->width;
+ break;
+ case ABOVE_BELOW_2_LR:
+ aspect.den *= 2;
+ case ABOVE_BELOW_LR:
+ s->in.row_right =
+ s->height = inlink->h / 2;
+ break;
+ case ABOVE_BELOW_2_RL:
+ aspect.den *= 2;
+ case ABOVE_BELOW_RL:
+ s->in.row_left =
+ s->height = inlink->h / 2;
+ break;
+ case ALTERNATING_RL:
+ case ALTERNATING_LR:
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ fps.den *= 2;
+ tb.num *= 2;
+ break;
+ default:
+ av_log(ctx, AV_LOG_ERROR, "input format %d is not supported\n", s->in.format);
+ return AVERROR(EINVAL);
+ }
+
+ s->out.width = s->width;
+ s->out.height = s->height;
+ s->out.off_lstep =
+ s->out.off_rstep =
+ s->out.off_left =
+ s->out.off_right =
+ s->out.row_left =
+ s->out.row_right = 0;
+
+ switch (s->out.format) {
+ case ANAGLYPH_RB_GRAY:
+ case ANAGLYPH_RG_GRAY:
+ case ANAGLYPH_RC_GRAY:
+ case ANAGLYPH_RC_HALF:
+ case ANAGLYPH_RC_COLOR:
+ case ANAGLYPH_RC_DUBOIS:
+ case ANAGLYPH_GM_GRAY:
+ case ANAGLYPH_GM_HALF:
+ case ANAGLYPH_GM_COLOR:
+ case ANAGLYPH_GM_DUBOIS:
+ case ANAGLYPH_YB_GRAY:
+ case ANAGLYPH_YB_HALF:
+ case ANAGLYPH_YB_COLOR:
+ case ANAGLYPH_YB_DUBOIS: {
+ uint8_t rgba_map[4];
+
+ ff_fill_rgba_map(rgba_map, outlink->format);
+ s->ana_matrix[rgba_map[0]] = &ana_coeff[s->out.format][0][0];
+ s->ana_matrix[rgba_map[1]] = &ana_coeff[s->out.format][1][0];
+ s->ana_matrix[rgba_map[2]] = &ana_coeff[s->out.format][2][0];
+ break;
+ }
+ case SIDE_BY_SIDE_2_LR:
+ aspect.den *= 2;
+ case SIDE_BY_SIDE_LR:
+ s->out.width = s->width * 2;
+ s->out.off_right = s->width;
+ break;
+ case SIDE_BY_SIDE_2_RL:
+ aspect.den *= 2;
+ case SIDE_BY_SIDE_RL:
+ s->out.width = s->width * 2;
+ s->out.off_left = s->width;
+ break;
+ case ABOVE_BELOW_2_LR:
+ aspect.num *= 2;
+ case ABOVE_BELOW_LR:
+ s->out.height = s->height * 2;
+ s->out.row_right = s->height;
+ break;
+ case ABOVE_BELOW_2_RL:
+ aspect.num *= 2;
+ case ABOVE_BELOW_RL:
+ s->out.height = s->height * 2;
+ s->out.row_left = s->height;
+ break;
+ case INTERLEAVE_ROWS_LR:
+ s->row_step = 2;
+ s->height = s->height / 2;
+ s->out.off_rstep =
+ s->in.off_rstep = 1;
+ break;
+ case INTERLEAVE_ROWS_RL:
+ s->row_step = 2;
+ s->height = s->height / 2;
+ s->out.off_lstep =
+ s->in.off_lstep = 1;
+ break;
+ case MONO_R:
+ s->in.off_left = s->in.off_right;
+ s->in.row_left = s->in.row_right;
+ case MONO_L:
+ break;
+ case ALTERNATING_RL:
+ case ALTERNATING_LR:
+ fps.num *= 2;
+ tb.den *= 2;
+ break;
+ default:
+ av_log(ctx, AV_LOG_ERROR, "output format %d is not supported\n", s->out.format);
+ return AVERROR(EINVAL);
+ }
+
+ outlink->w = s->out.width;
+ outlink->h = s->out.height;
+ outlink->frame_rate = fps;
+ outlink->time_base = tb;
+ outlink->sample_aspect_ratio = aspect;
+
+ if ((ret = av_image_fill_linesizes(s->linesize, outlink->format, s->width)) < 0)
+ return ret;
+ s->nb_planes = av_pix_fmt_count_planes(outlink->format);
+ av_image_fill_max_pixsteps(s->pixstep, NULL, desc);
+ s->ts_unit = av_q2d(av_inv_q(av_mul_q(outlink->frame_rate, outlink->time_base)));
+ s->pheight[1] = s->pheight[2] = FF_CEIL_RSHIFT(s->height, desc->log2_chroma_h);
+ s->pheight[0] = s->pheight[3] = s->height;
+ s->hsub = desc->log2_chroma_w;
+ s->vsub = desc->log2_chroma_h;
+
+ return 0;
+}
+
+static inline uint8_t ana_convert(const int *coeff, const uint8_t *left, const uint8_t *right)
+{
+ int sum;
+
+ sum = coeff[0] * left[0] + coeff[3] * right[0]; //red in
+ sum += coeff[1] * left[1] + coeff[4] * right[1]; //green in
+ sum += coeff[2] * left[2] + coeff[5] * right[2]; //blue in
+
+ return av_clip_uint8(sum >> 16);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ Stereo3DContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out, *oleft, *oright, *ileft, *iright;
+ int out_off_left[4], out_off_right[4];
+ int in_off_left[4], in_off_right[4];
+ int i;
+
+ switch (s->in.format) {
+ case ALTERNATING_LR:
+ case ALTERNATING_RL:
+ if (!s->prev) {
+ s->prev = inpicref;
+ return 0;
+ }
+ ileft = s->prev;
+ iright = inpicref;
+ if (s->in.format == ALTERNATING_RL)
+ FFSWAP(AVFrame *, ileft, iright);
+ break;
+ default:
+ ileft = iright = inpicref;
+ };
+
+ out = oleft = oright = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&s->prev);
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, inpicref);
+
+ if (s->out.format == ALTERNATING_LR ||
+ s->out.format == ALTERNATING_RL) {
+ oright = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!oright) {
+ av_frame_free(&oleft);
+ av_frame_free(&s->prev);
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(oright, inpicref);
+ }
+
+ for (i = 0; i < 4; i++) {
+ int hsub = i == 1 || i == 2 ? s->hsub : 0;
+ int vsub = i == 1 || i == 2 ? s->vsub : 0;
+ in_off_left[i] = (FF_CEIL_RSHIFT(s->in.row_left, vsub) + s->in.off_lstep) * ileft->linesize[i] + FF_CEIL_RSHIFT(s->in.off_left * s->pixstep[i], hsub);
+ in_off_right[i] = (FF_CEIL_RSHIFT(s->in.row_right, vsub) + s->in.off_rstep) * iright->linesize[i] + FF_CEIL_RSHIFT(s->in.off_right * s->pixstep[i], hsub);
+ out_off_left[i] = (FF_CEIL_RSHIFT(s->out.row_left, vsub) + s->out.off_lstep) * oleft->linesize[i] + FF_CEIL_RSHIFT(s->out.off_left * s->pixstep[i], hsub);
+ out_off_right[i] = (FF_CEIL_RSHIFT(s->out.row_right, vsub) + s->out.off_rstep) * oright->linesize[i] + FF_CEIL_RSHIFT(s->out.off_right * s->pixstep[i], hsub);
+ }
+
+ switch (s->out.format) {
+ case ALTERNATING_LR:
+ case ALTERNATING_RL:
+ case SIDE_BY_SIDE_LR:
+ case SIDE_BY_SIDE_RL:
+ case SIDE_BY_SIDE_2_LR:
+ case SIDE_BY_SIDE_2_RL:
+ case ABOVE_BELOW_LR:
+ case ABOVE_BELOW_RL:
+ case ABOVE_BELOW_2_LR:
+ case ABOVE_BELOW_2_RL:
+ case INTERLEAVE_ROWS_LR:
+ case INTERLEAVE_ROWS_RL:
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(oleft->data[i] + out_off_left[i],
+ oleft->linesize[i] * s->row_step,
+ ileft->data[i] + in_off_left[i],
+ ileft->linesize[i] * s->row_step,
+ s->linesize[i], s->pheight[i]);
+ av_image_copy_plane(oright->data[i] + out_off_right[i],
+ oright->linesize[i] * s->row_step,
+ iright->data[i] + in_off_right[i],
+ iright->linesize[i] * s->row_step,
+ s->linesize[i], s->pheight[i]);
+ }
+ break;
+ case MONO_L:
+ iright = ileft;
+ case MONO_R:
+ for (i = 0; i < s->nb_planes; i++) {
+ av_image_copy_plane(out->data[i], out->linesize[i],
+ iright->data[i] + in_off_left[i],
+ iright->linesize[i],
+ s->linesize[i], s->pheight[i]);
+ }
+ break;
+ case ANAGLYPH_RB_GRAY:
+ case ANAGLYPH_RG_GRAY:
+ case ANAGLYPH_RC_GRAY:
+ case ANAGLYPH_RC_HALF:
+ case ANAGLYPH_RC_COLOR:
+ case ANAGLYPH_RC_DUBOIS:
+ case ANAGLYPH_GM_GRAY:
+ case ANAGLYPH_GM_HALF:
+ case ANAGLYPH_GM_COLOR:
+ case ANAGLYPH_GM_DUBOIS:
+ case ANAGLYPH_YB_GRAY:
+ case ANAGLYPH_YB_HALF:
+ case ANAGLYPH_YB_COLOR:
+ case ANAGLYPH_YB_DUBOIS: {
+ int x, y, il, ir, o;
+ const uint8_t *lsrc = ileft->data[0];
+ const uint8_t *rsrc = iright->data[0];
+ uint8_t *dst = out->data[0];
+ int out_width = s->out.width;
+ const int **ana_matrix = s->ana_matrix;
+
+ for (y = 0; y < s->out.height; y++) {
+ o = out->linesize[0] * y;
+ il = in_off_left[0] + y * ileft->linesize[0];
+ ir = in_off_right[0] + y * iright->linesize[0];
+ for (x = 0; x < out_width; x++, il += 3, ir += 3, o+= 3) {
+ dst[o ] = ana_convert(ana_matrix[0], lsrc + il, rsrc + ir);
+ dst[o + 1] = ana_convert(ana_matrix[1], lsrc + il, rsrc + ir);
+ dst[o + 2] = ana_convert(ana_matrix[2], lsrc + il, rsrc + ir);
+ }
+ }
+ break;
+ }
+ default:
+ av_assert0(0);
+ }
+
+ av_frame_free(&inpicref);
+ av_frame_free(&s->prev);
+ if (oright != oleft) {
+ if (s->out.format == ALTERNATING_LR)
+ FFSWAP(AVFrame *, oleft, oright);
+ oright->pts = outlink->frame_count * s->ts_unit;
+ ff_filter_frame(outlink, oright);
+ out = oleft;
+ oleft->pts = outlink->frame_count * s->ts_unit;
+ } else if (s->in.format == ALTERNATING_LR ||
+ s->in.format == ALTERNATING_RL) {
+ out->pts = outlink->frame_count * s->ts_unit;
+ }
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ Stereo3DContext *s = ctx->priv;
+
+ av_frame_free(&s->prev);
+}
+
+static const AVFilterPad stereo3d_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad stereo3d_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_stereo3d = {
+ .name = "stereo3d",
+ .description = NULL_IF_CONFIG_SMALL("Convert video stereoscopic 3D view."),
+ .priv_size = sizeof(Stereo3DContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = stereo3d_inputs,
+ .outputs = stereo3d_outputs,
+ .priv_class = &stereo3d_class,
+};
diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c
new file mode 100644
index 0000000000..5e1324c715
--- /dev/null
+++ b/libavfilter/vf_subtitles.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2011 Baptiste Coudurier
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Libass subtitles burning filter.
+ *
+ * @see{http://www.matroska.org/technical/specs/subtitles/ssa.html}
+ */
+
+#include <ass/ass.h>
+
+#include "config.h"
+#if CONFIG_SUBTITLES_FILTER
+# include "libavcodec/avcodec.h"
+# include "libavformat/avformat.h"
+#endif
+#include "libavutil/avstring.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "drawutils.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "formats.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ ASS_Library *library;
+ ASS_Renderer *renderer;
+ ASS_Track *track;
+ char *filename;
+ char *charenc;
+ char *force_style;
+ int stream_index;
+ uint8_t rgba_map[4];
+ int pix_step[4]; ///< steps per pixel for each plane of the main output
+ int original_w, original_h;
+ int shaping;
+ FFDrawContext draw;
+} AssContext;
+
+#define OFFSET(x) offsetof(AssContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+#define COMMON_OPTIONS \
+ {"filename", "set the filename of file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, \
+ {"f", "set the filename of file to read", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, \
+ {"original_size", "set the size of the original video (used to scale fonts)", OFFSET(original_w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, \
+
+/* libass supports a log level ranging from 0 to 7 */
+static const int ass_libavfilter_log_level_map[] = {
+ [0] = AV_LOG_FATAL, /* MSGL_FATAL */
+ [1] = AV_LOG_ERROR, /* MSGL_ERR */
+ [2] = AV_LOG_WARNING, /* MSGL_WARN */
+ [3] = AV_LOG_WARNING, /* <undefined> */
+ [4] = AV_LOG_INFO, /* MSGL_INFO */
+ [5] = AV_LOG_INFO, /* <undefined> */
+ [6] = AV_LOG_VERBOSE, /* MSGL_V */
+ [7] = AV_LOG_DEBUG, /* MSGL_DBG2 */
+};
+
+static void ass_log(int ass_level, const char *fmt, va_list args, void *ctx)
+{
+ const int ass_level_clip = av_clip(ass_level, 0,
+ FF_ARRAY_ELEMS(ass_libavfilter_log_level_map) - 1);
+ const int level = ass_libavfilter_log_level_map[ass_level_clip];
+
+ av_vlog(ctx, level, fmt, args);
+ av_log(ctx, level, "\n");
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ AssContext *ass = ctx->priv;
+
+ if (!ass->filename) {
+ av_log(ctx, AV_LOG_ERROR, "No filename provided!\n");
+ return AVERROR(EINVAL);
+ }
+
+ ass->library = ass_library_init();
+ if (!ass->library) {
+ av_log(ctx, AV_LOG_ERROR, "Could not initialize libass.\n");
+ return AVERROR(EINVAL);
+ }
+ ass_set_message_cb(ass->library, ass_log, ctx);
+
+ ass->renderer = ass_renderer_init(ass->library);
+ if (!ass->renderer) {
+ av_log(ctx, AV_LOG_ERROR, "Could not initialize libass renderer.\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ AssContext *ass = ctx->priv;
+
+ if (ass->track)
+ ass_free_track(ass->track);
+ if (ass->renderer)
+ ass_renderer_done(ass->renderer);
+ if (ass->library)
+ ass_library_done(ass->library);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AssContext *ass = inlink->dst->priv;
+
+ ff_draw_init(&ass->draw, inlink->format, 0);
+
+ ass_set_frame_size (ass->renderer, inlink->w, inlink->h);
+ if (ass->original_w && ass->original_h)
+ ass_set_aspect_ratio(ass->renderer, (double)inlink->w / inlink->h,
+ (double)ass->original_w / ass->original_h);
+ if (ass->shaping != -1)
+ ass_set_shaper(ass->renderer, ass->shaping);
+
+ return 0;
+}
+
+/* libass stores an RGBA color in the format RRGGBBTT, where TT is the transparency level */
+#define AR(c) ( (c)>>24)
+#define AG(c) (((c)>>16)&0xFF)
+#define AB(c) (((c)>>8) &0xFF)
+#define AA(c) ((0xFF-(c)) &0xFF)
+
+static void overlay_ass_image(AssContext *ass, AVFrame *picref,
+ const ASS_Image *image)
+{
+ for (; image; image = image->next) {
+ uint8_t rgba_color[] = {AR(image->color), AG(image->color), AB(image->color), AA(image->color)};
+ FFDrawColor color;
+ ff_draw_color(&ass->draw, &color, rgba_color);
+ ff_blend_mask(&ass->draw, &color,
+ picref->data, picref->linesize,
+ picref->width, picref->height,
+ image->bitmap, image->stride, image->w, image->h,
+ 3, 0, image->dst_x, image->dst_y);
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AssContext *ass = ctx->priv;
+ int detect_change = 0;
+ double time_ms = picref->pts * av_q2d(inlink->time_base) * 1000;
+ ASS_Image *image = ass_render_frame(ass->renderer, ass->track,
+ time_ms, &detect_change);
+
+ if (detect_change)
+ av_log(ctx, AV_LOG_DEBUG, "Change happened at time ms:%f\n", time_ms);
+
+ overlay_ass_image(ass, picref, image);
+
+ return ff_filter_frame(outlink, picref);
+}
+
+static const AVFilterPad ass_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ .needs_writable = 1,
+ },
+ { NULL }
+};
+
+static const AVFilterPad ass_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+#if CONFIG_ASS_FILTER
+
+static const AVOption ass_options[] = {
+ COMMON_OPTIONS
+ {"shaping", "set shaping engine", OFFSET(shaping), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, FLAGS, "shaping_mode"},
+ {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, INT_MIN, INT_MAX, FLAGS, "shaping_mode"},
+ {"simple", "simple shaping", 0, AV_OPT_TYPE_CONST, {.i64 = ASS_SHAPING_SIMPLE}, INT_MIN, INT_MAX, FLAGS, "shaping_mode"},
+ {"complex", "complex shaping", 0, AV_OPT_TYPE_CONST, {.i64 = ASS_SHAPING_COMPLEX}, INT_MIN, INT_MAX, FLAGS, "shaping_mode"},
+ {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(ass);
+
+static av_cold int init_ass(AVFilterContext *ctx)
+{
+ AssContext *ass = ctx->priv;
+ int ret = init(ctx);
+
+ if (ret < 0)
+ return ret;
+
+ /* Initialize fonts */
+ ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1);
+
+ ass->track = ass_read_file(ass->library, ass->filename, NULL);
+ if (!ass->track) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Could not create a libass track when reading file '%s'\n",
+ ass->filename);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+AVFilter ff_vf_ass = {
+ .name = "ass",
+ .description = NULL_IF_CONFIG_SMALL("Render ASS subtitles onto input video using the libass library."),
+ .priv_size = sizeof(AssContext),
+ .init = init_ass,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = ass_inputs,
+ .outputs = ass_outputs,
+ .priv_class = &ass_class,
+};
+#endif
+
+#if CONFIG_SUBTITLES_FILTER
+
+static const AVOption subtitles_options[] = {
+ COMMON_OPTIONS
+ {"charenc", "set input character encoding", OFFSET(charenc), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"stream_index", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS},
+ {"si", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS},
+ {"force_style", "force subtitle style", OFFSET(force_style), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {NULL},
+};
+
+static const char * const font_mimetypes[] = {
+ "application/x-truetype-font",
+ "application/vnd.ms-opentype",
+ "application/x-font-ttf",
+ NULL
+};
+
+static int attachment_is_font(AVStream * st)
+{
+ const AVDictionaryEntry *tag = NULL;
+ int n;
+
+ tag = av_dict_get(st->metadata, "mimetype", NULL, AV_DICT_MATCH_CASE);
+
+ if (tag) {
+ for (n = 0; font_mimetypes[n]; n++) {
+ if (av_strcasecmp(font_mimetypes[n], tag->value) == 0)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+AVFILTER_DEFINE_CLASS(subtitles);
+
+static av_cold int init_subtitles(AVFilterContext *ctx)
+{
+ int j, ret, sid;
+ int k = 0;
+ AVDictionary *codec_opts = NULL;
+ AVFormatContext *fmt = NULL;
+ AVCodecContext *dec_ctx = NULL;
+ AVCodec *dec = NULL;
+ const AVCodecDescriptor *dec_desc;
+ AVStream *st;
+ AVPacket pkt;
+ AssContext *ass = ctx->priv;
+
+ /* Init libass */
+ ret = init(ctx);
+ if (ret < 0)
+ return ret;
+ ass->track = ass_new_track(ass->library);
+ if (!ass->track) {
+ av_log(ctx, AV_LOG_ERROR, "Could not create a libass track\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* Open subtitles file */
+ ret = avformat_open_input(&fmt, ass->filename, NULL, NULL);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename);
+ goto end;
+ }
+ ret = avformat_find_stream_info(fmt, NULL);
+ if (ret < 0)
+ goto end;
+
+ /* Locate subtitles stream */
+ if (ass->stream_index < 0)
+ ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
+ else {
+ ret = -1;
+ if (ass->stream_index < fmt->nb_streams) {
+ for (j = 0; j < fmt->nb_streams; j++) {
+ if (fmt->streams[j]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ if (ass->stream_index == k) {
+ ret = j;
+ break;
+ }
+ k++;
+ }
+ }
+ }
+ }
+
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_ERROR, "Unable to locate subtitle stream in %s\n",
+ ass->filename);
+ goto end;
+ }
+ sid = ret;
+ st = fmt->streams[sid];
+
+ /* Load attached fonts */
+ for (j = 0; j < fmt->nb_streams; j++) {
+ AVStream *st = fmt->streams[j];
+ if (st->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT &&
+ attachment_is_font(st)) {
+ const AVDictionaryEntry *tag = NULL;
+ tag = av_dict_get(st->metadata, "filename", NULL,
+ AV_DICT_MATCH_CASE);
+
+ if (tag) {
+ av_log(ctx, AV_LOG_DEBUG, "Loading attached font: %s\n",
+ tag->value);
+ ass_add_font(ass->library, tag->value,
+ st->codec->extradata,
+ st->codec->extradata_size);
+ } else {
+ av_log(ctx, AV_LOG_WARNING,
+ "Font attachment has no filename, ignored.\n");
+ }
+ }
+ }
+
+ /* Initialize fonts */
+ ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1);
+
+ /* Open decoder */
+ dec_ctx = st->codec;
+ dec = avcodec_find_decoder(dec_ctx->codec_id);
+ if (!dec) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to find subtitle codec %s\n",
+ avcodec_get_name(dec_ctx->codec_id));
+ return AVERROR(EINVAL);
+ }
+ dec_desc = avcodec_descriptor_get(dec_ctx->codec_id);
+ if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Only text based subtitles are currently supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (ass->charenc)
+ av_dict_set(&codec_opts, "sub_charenc", ass->charenc, 0);
+ ret = avcodec_open2(dec_ctx, dec, &codec_opts);
+ if (ret < 0)
+ goto end;
+
+ if (ass->force_style) {
+ char **list = NULL;
+ char *temp = NULL;
+ char *ptr = av_strtok(ass->force_style, ",", &temp);
+ int i = 0;
+ while (ptr) {
+ av_dynarray_add(&list, &i, ptr);
+ if (!list) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ ptr = av_strtok(NULL, ",", &temp);
+ }
+ av_dynarray_add(&list, &i, NULL);
+ if (!list) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ ass_set_style_overrides(ass->library, list);
+ av_free(list);
+ }
+ /* Decode subtitles and push them into the renderer (libass) */
+ if (dec_ctx->subtitle_header)
+ ass_process_codec_private(ass->track,
+ dec_ctx->subtitle_header,
+ dec_ctx->subtitle_header_size);
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+ while (av_read_frame(fmt, &pkt) >= 0) {
+ int i, got_subtitle;
+ AVSubtitle sub = {0};
+
+ if (pkt.stream_index == sid) {
+ ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt);
+ if (ret < 0) {
+ av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n",
+ av_err2str(ret));
+ } else if (got_subtitle) {
+ for (i = 0; i < sub.num_rects; i++) {
+ char *ass_line = sub.rects[i]->ass;
+ if (!ass_line)
+ break;
+ ass_process_data(ass->track, ass_line, strlen(ass_line));
+ }
+ }
+ }
+ av_free_packet(&pkt);
+ avsubtitle_free(&sub);
+ }
+
+end:
+ av_dict_free(&codec_opts);
+ if (dec_ctx)
+ avcodec_close(dec_ctx);
+ if (fmt)
+ avformat_close_input(&fmt);
+ return ret;
+}
+
+AVFilter ff_vf_subtitles = {
+ .name = "subtitles",
+ .description = NULL_IF_CONFIG_SMALL("Render text subtitles onto input video using the libass library."),
+ .priv_size = sizeof(AssContext),
+ .init = init_subtitles,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = ass_inputs,
+ .outputs = ass_outputs,
+ .priv_class = &subtitles_class,
+};
+#endif
diff --git a/libavfilter/vf_super2xsai.c b/libavfilter/vf_super2xsai.c
new file mode 100644
index 0000000000..67e9f97e54
--- /dev/null
+++ b/libavfilter/vf_super2xsai.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2010 Niel van der Westhuizen <nielkie@gmail.com>
+ * Copyright (c) 2002 A'rpi
+ * Copyright (c) 1997-2001 ZSNES Team ( zsknight@zsnes.com / _demo_@zsnes.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 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
+ * Super 2xSaI video filter
+ * Ported from MPlayer libmpcodecs/vf_2xsai.c.
+ */
+
+#include "libavutil/pixdesc.h"
+#include "libavutil/intreadwrite.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct {
+ /* masks used for two pixels interpolation */
+ uint32_t hi_pixel_mask;
+ uint32_t lo_pixel_mask;
+
+ /* masks used for four pixels interpolation */
+ uint32_t q_hi_pixel_mask;
+ uint32_t q_lo_pixel_mask;
+
+ int bpp; ///< bytes per pixel, pixel stride for each (packed) pixel
+ int is_be;
+} Super2xSaIContext;
+
+#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D))
+
+#define INTERPOLATE(A, B) (((A & hi_pixel_mask) >> 1) + ((B & hi_pixel_mask) >> 1) + (A & B & lo_pixel_mask))
+
+#define Q_INTERPOLATE(A, B, C, D) ((A & q_hi_pixel_mask) >> 2) + ((B & q_hi_pixel_mask) >> 2) + ((C & q_hi_pixel_mask) >> 2) + ((D & q_hi_pixel_mask) >> 2) \
+ + ((((A & q_lo_pixel_mask) + (B & q_lo_pixel_mask) + (C & q_lo_pixel_mask) + (D & q_lo_pixel_mask)) >> 2) & q_lo_pixel_mask)
+
+static void super2xsai(AVFilterContext *ctx,
+ uint8_t *src, int src_linesize,
+ uint8_t *dst, int dst_linesize,
+ int width, int height)
+{
+ Super2xSaIContext *sai = ctx->priv;
+ unsigned int x, y;
+ uint32_t color[4][4];
+ unsigned char *src_line[4];
+ const int bpp = sai->bpp;
+ const uint32_t hi_pixel_mask = sai->hi_pixel_mask;
+ const uint32_t lo_pixel_mask = sai->lo_pixel_mask;
+ const uint32_t q_hi_pixel_mask = sai->q_hi_pixel_mask;
+ const uint32_t q_lo_pixel_mask = sai->q_lo_pixel_mask;
+
+ /* Point to the first 4 lines, first line is duplicated */
+ src_line[0] = src;
+ src_line[1] = src;
+ src_line[2] = src + src_linesize*FFMIN(1, height-1);
+ src_line[3] = src + src_linesize*FFMIN(2, height-1);
+
+#define READ_COLOR4(dst, src_line, off) dst = *((const uint32_t *)src_line + off)
+#define READ_COLOR3(dst, src_line, off) dst = AV_RL24 (src_line + 3*off)
+#define READ_COLOR2(dst, src_line, off) dst = sai->is_be ? AV_RB16(src_line + 2 * off) : AV_RL16(src_line + 2 * off)
+
+ for (y = 0; y < height; y++) {
+ uint8_t *dst_line[2];
+
+ dst_line[0] = dst + dst_linesize*2*y;
+ dst_line[1] = dst + dst_linesize*(2*y+1);
+
+ switch (bpp) {
+ case 4:
+ READ_COLOR4(color[0][0], src_line[0], 0); color[0][1] = color[0][0]; READ_COLOR4(color[0][2], src_line[0], 1); READ_COLOR4(color[0][3], src_line[0], 2);
+ READ_COLOR4(color[1][0], src_line[1], 0); color[1][1] = color[1][0]; READ_COLOR4(color[1][2], src_line[1], 1); READ_COLOR4(color[1][3], src_line[1], 2);
+ READ_COLOR4(color[2][0], src_line[2], 0); color[2][1] = color[2][0]; READ_COLOR4(color[2][2], src_line[2], 1); READ_COLOR4(color[2][3], src_line[2], 2);
+ READ_COLOR4(color[3][0], src_line[3], 0); color[3][1] = color[3][0]; READ_COLOR4(color[3][2], src_line[3], 1); READ_COLOR4(color[3][3], src_line[3], 2);
+ break;
+ case 3:
+ READ_COLOR3(color[0][0], src_line[0], 0); color[0][1] = color[0][0]; READ_COLOR3(color[0][2], src_line[0], 1); READ_COLOR3(color[0][3], src_line[0], 2);
+ READ_COLOR3(color[1][0], src_line[1], 0); color[1][1] = color[1][0]; READ_COLOR3(color[1][2], src_line[1], 1); READ_COLOR3(color[1][3], src_line[1], 2);
+ READ_COLOR3(color[2][0], src_line[2], 0); color[2][1] = color[2][0]; READ_COLOR3(color[2][2], src_line[2], 1); READ_COLOR3(color[2][3], src_line[2], 2);
+ READ_COLOR3(color[3][0], src_line[3], 0); color[3][1] = color[3][0]; READ_COLOR3(color[3][2], src_line[3], 1); READ_COLOR3(color[3][3], src_line[3], 2);
+ break;
+ default:
+ READ_COLOR2(color[0][0], src_line[0], 0); color[0][1] = color[0][0]; READ_COLOR2(color[0][2], src_line[0], 1); READ_COLOR2(color[0][3], src_line[0], 2);
+ READ_COLOR2(color[1][0], src_line[1], 0); color[1][1] = color[1][0]; READ_COLOR2(color[1][2], src_line[1], 1); READ_COLOR2(color[1][3], src_line[1], 2);
+ READ_COLOR2(color[2][0], src_line[2], 0); color[2][1] = color[2][0]; READ_COLOR2(color[2][2], src_line[2], 1); READ_COLOR2(color[2][3], src_line[2], 2);
+ READ_COLOR2(color[3][0], src_line[3], 0); color[3][1] = color[3][0]; READ_COLOR2(color[3][2], src_line[3], 1); READ_COLOR2(color[3][3], src_line[3], 2);
+ }
+
+ for (x = 0; x < width; x++) {
+ uint32_t product1a, product1b, product2a, product2b;
+
+//--------------------------------------- B0 B1 B2 B3 0 1 2 3
+// 4 5* 6 S2 -> 4 5* 6 7
+// 1 2 3 S1 8 9 10 11
+// A0 A1 A2 A3 12 13 14 15
+//--------------------------------------
+ if (color[2][1] == color[1][2] && color[1][1] != color[2][2]) {
+ product2b = color[2][1];
+ product1b = product2b;
+ } else if (color[1][1] == color[2][2] && color[2][1] != color[1][2]) {
+ product2b = color[1][1];
+ product1b = product2b;
+ } else if (color[1][1] == color[2][2] && color[2][1] == color[1][2]) {
+ int r = 0;
+
+ r += GET_RESULT(color[1][2], color[1][1], color[1][0], color[3][1]);
+ r += GET_RESULT(color[1][2], color[1][1], color[2][0], color[0][1]);
+ r += GET_RESULT(color[1][2], color[1][1], color[3][2], color[2][3]);
+ r += GET_RESULT(color[1][2], color[1][1], color[0][2], color[1][3]);
+
+ if (r > 0)
+ product1b = color[1][2];
+ else if (r < 0)
+ product1b = color[1][1];
+ else
+ product1b = INTERPOLATE(color[1][1], color[1][2]);
+
+ product2b = product1b;
+ } else {
+ if (color[1][2] == color[2][2] && color[2][2] == color[3][1] && color[2][1] != color[3][2] && color[2][2] != color[3][0])
+ product2b = Q_INTERPOLATE(color[2][2], color[2][2], color[2][2], color[2][1]);
+ else if (color[1][1] == color[2][1] && color[2][1] == color[3][2] && color[3][1] != color[2][2] && color[2][1] != color[3][3])
+ product2b = Q_INTERPOLATE(color[2][1], color[2][1], color[2][1], color[2][2]);
+ else
+ product2b = INTERPOLATE(color[2][1], color[2][2]);
+
+ if (color[1][2] == color[2][2] && color[1][2] == color[0][1] && color[1][1] != color[0][2] && color[1][2] != color[0][0])
+ product1b = Q_INTERPOLATE(color[1][2], color[1][2], color[1][2], color[1][1]);
+ else if (color[1][1] == color[2][1] && color[1][1] == color[0][2] && color[0][1] != color[1][2] && color[1][1] != color[0][3])
+ product1b = Q_INTERPOLATE(color[1][2], color[1][1], color[1][1], color[1][1]);
+ else
+ product1b = INTERPOLATE(color[1][1], color[1][2]);
+ }
+
+ if (color[1][1] == color[2][2] && color[2][1] != color[1][2] && color[1][0] == color[1][1] && color[1][1] != color[3][2])
+ product2a = INTERPOLATE(color[2][1], color[1][1]);
+ else if (color[1][1] == color[2][0] && color[1][2] == color[1][1] && color[1][0] != color[2][1] && color[1][1] != color[3][0])
+ product2a = INTERPOLATE(color[2][1], color[1][1]);
+ else
+ product2a = color[2][1];
+
+ if (color[2][1] == color[1][2] && color[1][1] != color[2][2] && color[2][0] == color[2][1] && color[2][1] != color[0][2])
+ product1a = INTERPOLATE(color[2][1], color[1][1]);
+ else if (color[1][0] == color[2][1] && color[2][2] == color[2][1] && color[2][0] != color[1][1] && color[2][1] != color[0][0])
+ product1a = INTERPOLATE(color[2][1], color[1][1]);
+ else
+ product1a = color[1][1];
+
+ /* Set the calculated pixels */
+ switch (bpp) {
+ case 4:
+ AV_WN32A(dst_line[0] + x * 8, product1a);
+ AV_WN32A(dst_line[0] + x * 8 + 4, product1b);
+ AV_WN32A(dst_line[1] + x * 8, product2a);
+ AV_WN32A(dst_line[1] + x * 8 + 4, product2b);
+ break;
+ case 3:
+ AV_WL24(dst_line[0] + x * 6, product1a);
+ AV_WL24(dst_line[0] + x * 6 + 3, product1b);
+ AV_WL24(dst_line[1] + x * 6, product2a);
+ AV_WL24(dst_line[1] + x * 6 + 3, product2b);
+ break;
+ default: // bpp = 2
+ if (sai->is_be) {
+ AV_WB32(dst_line[0] + x * 4, product1a | (product1b << 16));
+ AV_WB32(dst_line[1] + x * 4, product2a | (product2b << 16));
+ } else {
+ AV_WL32(dst_line[0] + x * 4, product1a | (product1b << 16));
+ AV_WL32(dst_line[1] + x * 4, product2a | (product2b << 16));
+ }
+ }
+
+ /* Move color matrix forward */
+ color[0][0] = color[0][1]; color[0][1] = color[0][2]; color[0][2] = color[0][3];
+ color[1][0] = color[1][1]; color[1][1] = color[1][2]; color[1][2] = color[1][3];
+ color[2][0] = color[2][1]; color[2][1] = color[2][2]; color[2][2] = color[2][3];
+ color[3][0] = color[3][1]; color[3][1] = color[3][2]; color[3][2] = color[3][3];
+
+ if (x < width - 3) {
+ x += 3;
+ switch (bpp) {
+ case 4:
+ READ_COLOR4(color[0][3], src_line[0], x);
+ READ_COLOR4(color[1][3], src_line[1], x);
+ READ_COLOR4(color[2][3], src_line[2], x);
+ READ_COLOR4(color[3][3], src_line[3], x);
+ break;
+ case 3:
+ READ_COLOR3(color[0][3], src_line[0], x);
+ READ_COLOR3(color[1][3], src_line[1], x);
+ READ_COLOR3(color[2][3], src_line[2], x);
+ READ_COLOR3(color[3][3], src_line[3], x);
+ break;
+ default: /* case 2 */
+ READ_COLOR2(color[0][3], src_line[0], x);
+ READ_COLOR2(color[1][3], src_line[1], x);
+ READ_COLOR2(color[2][3], src_line[2], x);
+ READ_COLOR2(color[3][3], src_line[3], x);
+ }
+ x -= 3;
+ }
+ }
+
+ /* We're done with one line, so we shift the source lines up */
+ src_line[0] = src_line[1];
+ src_line[1] = src_line[2];
+ src_line[2] = src_line[3];
+
+ /* Read next line */
+ src_line[3] = src_line[2];
+ if (y < height - 3)
+ src_line[3] += src_linesize;
+ } // y loop
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGB565BE, AV_PIX_FMT_BGR565BE, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_BGR555BE,
+ AV_PIX_FMT_RGB565LE, AV_PIX_FMT_BGR565LE, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_BGR555LE,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ Super2xSaIContext *sai = inlink->dst->priv;
+
+ sai->hi_pixel_mask = 0xFEFEFEFE;
+ sai->lo_pixel_mask = 0x01010101;
+ sai->q_hi_pixel_mask = 0xFCFCFCFC;
+ sai->q_lo_pixel_mask = 0x03030303;
+ sai->bpp = 4;
+
+ switch (inlink->format) {
+ case AV_PIX_FMT_RGB24:
+ case AV_PIX_FMT_BGR24:
+ sai->bpp = 3;
+ break;
+
+ case AV_PIX_FMT_RGB565BE:
+ case AV_PIX_FMT_BGR565BE:
+ sai->is_be = 1;
+ case AV_PIX_FMT_RGB565LE:
+ case AV_PIX_FMT_BGR565LE:
+ sai->hi_pixel_mask = 0xF7DEF7DE;
+ sai->lo_pixel_mask = 0x08210821;
+ sai->q_hi_pixel_mask = 0xE79CE79C;
+ sai->q_lo_pixel_mask = 0x18631863;
+ sai->bpp = 2;
+ break;
+
+ case AV_PIX_FMT_BGR555BE:
+ case AV_PIX_FMT_RGB555BE:
+ sai->is_be = 1;
+ case AV_PIX_FMT_BGR555LE:
+ case AV_PIX_FMT_RGB555LE:
+ sai->hi_pixel_mask = 0x7BDE7BDE;
+ sai->lo_pixel_mask = 0x04210421;
+ sai->q_hi_pixel_mask = 0x739C739C;
+ sai->q_lo_pixel_mask = 0x0C630C63;
+ sai->bpp = 2;
+ break;
+ }
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterLink *inlink = outlink->src->inputs[0];
+
+ outlink->w = inlink->w*2;
+ outlink->h = inlink->h*2;
+
+ av_log(inlink->dst, AV_LOG_VERBOSE, "fmt:%s size:%dx%d -> size:%dx%d\n",
+ av_get_pix_fmt_name(inlink->format),
+ inlink->w, inlink->h, outlink->w, outlink->h);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ AVFrame *outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!outpicref) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(outpicref, inpicref);
+ outpicref->width = outlink->w;
+ outpicref->height = outlink->h;
+
+ super2xsai(inlink->dst, inpicref->data[0], inpicref->linesize[0],
+ outpicref->data[0], outpicref->linesize[0],
+ inlink->w, inlink->h);
+
+ av_frame_free(&inpicref);
+ return ff_filter_frame(outlink, outpicref);
+}
+
+static const AVFilterPad super2xsai_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad super2xsai_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_super2xsai = {
+ .name = "super2xsai",
+ .description = NULL_IF_CONFIG_SMALL("Scale the input by 2x using the Super2xSaI pixel art algorithm."),
+ .priv_size = sizeof(Super2xSaIContext),
+ .query_formats = query_formats,
+ .inputs = super2xsai_inputs,
+ .outputs = super2xsai_outputs,
+};
diff --git a/libavfilter/vf_swapuv.c b/libavfilter/vf_swapuv.c
new file mode 100644
index 0000000000..632e31c75e
--- /dev/null
+++ b/libavfilter/vf_swapuv.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * swap UV filter
+ */
+
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+static void do_swap(AVFrame *frame)
+{
+ FFSWAP(uint8_t*, frame->data[1], frame->data[2]);
+ FFSWAP(int, frame->linesize[1], frame->linesize[2]);
+ FFSWAP(uint64_t, frame->error[1], frame->error[2]);
+ FFSWAP(AVBufferRef*, frame->buf[1], frame->buf[2]);
+}
+
+static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
+{
+ AVFrame *picref = ff_default_get_video_buffer(link, w, h);
+ do_swap(picref);
+ return picref;
+}
+
+static int filter_frame(AVFilterLink *link, AVFrame *inpicref)
+{
+ do_swap(inpicref);
+ return ff_filter_frame(link->dst->outputs[0], inpicref);
+}
+
+static int is_planar_yuv(const AVPixFmtDescriptor *desc)
+{
+ int i;
+
+ if (desc->flags & ~(AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA) ||
+ desc->nb_components < 3 ||
+ (desc->comp[1].depth_minus1 != desc->comp[2].depth_minus1))
+ return 0;
+ for (i = 0; i < desc->nb_components; i++) {
+ if (desc->comp[i].offset_plus1 != 1 ||
+ desc->comp[i].shift != 0 ||
+ desc->comp[i].plane != i)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *formats = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (is_planar_yuv(desc))
+ ff_add_format(&formats, fmt);
+ }
+
+ return ff_set_common_formats(ctx, formats);
+}
+
+static const AVFilterPad swapuv_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer = get_video_buffer,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad swapuv_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_swapuv = {
+ .name = "swapuv",
+ .description = NULL_IF_CONFIG_SMALL("Swap U and V components."),
+ .query_formats = query_formats,
+ .inputs = swapuv_inputs,
+ .outputs = swapuv_outputs,
+};
diff --git a/libavfilter/vf_telecine.c b/libavfilter/vf_telecine.c
new file mode 100644
index 0000000000..26f0ef8abc
--- /dev/null
+++ b/libavfilter/vf_telecine.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2012 Rudolf Polzer
+ * Copyright (c) 2013 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file telecine filter, heavily based from mpv-player:TOOLS/vf_dlopen/telecine.c by
+ * Rudolf Polzer.
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int first_field;
+ char *pattern;
+ unsigned int pattern_pos;
+ int64_t start_time;
+
+ AVRational pts;
+ AVRational ts_unit;
+ int out_cnt;
+ int occupied;
+
+ int nb_planes;
+ int planeheight[4];
+ int stride[4];
+
+ AVFrame *frame[5];
+ AVFrame *temp;
+} TelecineContext;
+
+#define OFFSET(x) offsetof(TelecineContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption telecine_options[] = {
+ {"first_field", "select first field", OFFSET(first_field), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "field"},
+ {"top", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
+ {"t", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
+ {"bottom", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
+ {"b", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
+ {"pattern", "pattern that describe for how many fields a frame is to be displayed", OFFSET(pattern), AV_OPT_TYPE_STRING, {.str="23"}, 0, 0, FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(telecine);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ TelecineContext *s = ctx->priv;
+ const char *p;
+ int max = 0;
+
+ if (!strlen(s->pattern)) {
+ av_log(ctx, AV_LOG_ERROR, "No pattern provided.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (p = s->pattern; *p; p++) {
+ if (!av_isdigit(*p)) {
+ av_log(ctx, AV_LOG_ERROR, "Provided pattern includes non-numeric characters.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ max = FFMAX(*p - '0', max);
+ s->pts.num += 2;
+ s->pts.den += *p - '0';
+ }
+
+ s->start_time = AV_NOPTS_VALUE;
+
+ s->out_cnt = (max + 1) / 2;
+ av_log(ctx, AV_LOG_INFO, "Telecine pattern %s yields up to %d frames per frame, pts advance factor: %d/%d\n",
+ s->pattern, s->out_cnt, s->pts.num, s->pts.den);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ AVFilterFormats *pix_fmts = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
+ desc->flags & AV_PIX_FMT_FLAG_PAL ||
+ desc->flags & AV_PIX_FMT_FLAG_BITSTREAM))
+ ff_add_format(&pix_fmts, fmt);
+ }
+
+ return ff_set_common_formats(ctx, pix_fmts);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ TelecineContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int i, ret;
+
+ s->temp = ff_get_video_buffer(inlink, inlink->w, inlink->h);
+ if (!s->temp)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < s->out_cnt; i++) {
+ s->frame[i] = ff_get_video_buffer(inlink, inlink->w, inlink->h);
+ if (!s->frame[i])
+ return AVERROR(ENOMEM);
+ }
+
+ if ((ret = av_image_fill_linesizes(s->stride, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+
+ return 0;
+}
+
+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;
+
+ if (!fps.num || !fps.den) {
+ av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
+ "current rate of %d/%d is invalid\n", fps.num, fps.den);
+ return AVERROR(EINVAL);
+ }
+ 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);
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ outlink->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);
+
+ s->ts_unit = av_inv_q(av_mul_q(fps, outlink->time_base));
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ TelecineContext *s = ctx->priv;
+ int i, len, ret = 0, nout = 0;
+
+ if (s->start_time == AV_NOPTS_VALUE)
+ s->start_time = inpicref->pts;
+
+ len = s->pattern[s->pattern_pos] - '0';
+
+ s->pattern_pos++;
+ if (!s->pattern[s->pattern_pos])
+ s->pattern_pos = 0;
+
+ if (!len) { // do not output any field from this frame
+ av_frame_free(&inpicref);
+ return 0;
+ }
+
+ if (s->occupied) {
+ for (i = 0; i < s->nb_planes; i++) {
+ // fill in the EARLIER field from the buffered pic
+ av_image_copy_plane(s->frame[nout]->data[i] + s->frame[nout]->linesize[i] * s->first_field,
+ s->frame[nout]->linesize[i] * 2,
+ s->temp->data[i] + s->temp->linesize[i] * s->first_field,
+ s->temp->linesize[i] * 2,
+ s->stride[i],
+ (s->planeheight[i] - s->first_field + 1) / 2);
+ // fill in the LATER field from the new pic
+ av_image_copy_plane(s->frame[nout]->data[i] + s->frame[nout]->linesize[i] * !s->first_field,
+ s->frame[nout]->linesize[i] * 2,
+ inpicref->data[i] + inpicref->linesize[i] * !s->first_field,
+ inpicref->linesize[i] * 2,
+ s->stride[i],
+ (s->planeheight[i] - !s->first_field + 1) / 2);
+ }
+ nout++;
+ len--;
+ s->occupied = 0;
+ }
+
+ while (len >= 2) {
+ // output THIS image as-is
+ for (i = 0; i < s->nb_planes; i++)
+ av_image_copy_plane(s->frame[nout]->data[i], s->frame[nout]->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ s->stride[i],
+ s->planeheight[i]);
+ nout++;
+ len -= 2;
+ }
+
+ if (len >= 1) {
+ // copy THIS image to the buffer, we need it later
+ for (i = 0; i < s->nb_planes; i++)
+ av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
+ inpicref->data[i], inpicref->linesize[i],
+ s->stride[i],
+ s->planeheight[i]);
+ s->occupied = 1;
+ }
+
+ for (i = 0; i < nout; i++) {
+ AVFrame *frame = av_frame_clone(s->frame[i]);
+
+ if (!frame) {
+ av_frame_free(&inpicref);
+ return AVERROR(ENOMEM);
+ }
+
+ av_frame_copy_props(frame, inpicref);
+ frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) +
+ av_rescale(outlink->frame_count, s->ts_unit.num,
+ s->ts_unit.den);
+ ret = ff_filter_frame(outlink, frame);
+ }
+ av_frame_free(&inpicref);
+
+ return ret;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ TelecineContext *s = ctx->priv;
+ int i;
+
+ av_frame_free(&s->temp);
+ for (i = 0; i < s->out_cnt; i++)
+ av_frame_free(&s->frame[i]);
+}
+
+static const AVFilterPad telecine_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad telecine_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_telecine = {
+ .name = "telecine",
+ .description = NULL_IF_CONFIG_SMALL("Apply a telecine pattern."),
+ .priv_size = sizeof(TelecineContext),
+ .priv_class = &telecine_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = telecine_inputs,
+ .outputs = telecine_outputs,
+};
diff --git a/libavfilter/vf_thumbnail.c b/libavfilter/vf_thumbnail.c
new file mode 100644
index 0000000000..d70d0635a3
--- /dev/null
+++ b/libavfilter/vf_thumbnail.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2011 Smartjog S.A.S, ClĂ©ment BÅ“sch <clement.boesch@smartjog.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
+ * Potential thumbnail lookup filter to reduce the risk of an inappropriate
+ * selection (such as a black frame) we could get with an absolute seek.
+ *
+ * Simplified version of algorithm by Vadim Zaliva <lord@crocodile.org>.
+ * @see http://notbrainsurgery.livejournal.com/29773.html
+ */
+
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#define HIST_SIZE (3*256)
+
+struct thumb_frame {
+ AVFrame *buf; ///< cached frame
+ int histogram[HIST_SIZE]; ///< RGB color distribution histogram of the frame
+};
+
+typedef struct {
+ const AVClass *class;
+ int n; ///< current frame
+ int n_frames; ///< number of frames for analysis
+ struct thumb_frame *frames; ///< the n_frames frames
+ AVRational tb; ///< copy of the input timebase to ease access
+} ThumbContext;
+
+#define OFFSET(x) offsetof(ThumbContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption thumbnail_options[] = {
+ { "n", "set the frames batch size", OFFSET(n_frames), AV_OPT_TYPE_INT, {.i64=100}, 2, INT_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(thumbnail);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ThumbContext *thumb = ctx->priv;
+
+ thumb->frames = av_calloc(thumb->n_frames, sizeof(*thumb->frames));
+ if (!thumb->frames) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Allocation failure, try to lower the number of frames\n");
+ return AVERROR(ENOMEM);
+ }
+ av_log(ctx, AV_LOG_VERBOSE, "batch size: %d frames\n", thumb->n_frames);
+ return 0;
+}
+
+/**
+ * @brief Compute Sum-square deviation to estimate "closeness".
+ * @param hist color distribution histogram
+ * @param median average color distribution histogram
+ * @return sum of squared errors
+ */
+static double frame_sum_square_err(const int *hist, const double *median)
+{
+ int i;
+ double err, sum_sq_err = 0;
+
+ for (i = 0; i < HIST_SIZE; i++) {
+ err = median[i] - (double)hist[i];
+ sum_sq_err += err*err;
+ }
+ return sum_sq_err;
+}
+
+static AVFrame *get_best_frame(AVFilterContext *ctx)
+{
+ AVFrame *picref;
+ ThumbContext *thumb = ctx->priv;
+ int i, j, best_frame_idx = 0;
+ int nb_frames = thumb->n;
+ double avg_hist[HIST_SIZE] = {0}, sq_err, min_sq_err = -1;
+
+ // average histogram of the N frames
+ for (j = 0; j < FF_ARRAY_ELEMS(avg_hist); j++) {
+ for (i = 0; i < nb_frames; i++)
+ avg_hist[j] += (double)thumb->frames[i].histogram[j];
+ avg_hist[j] /= nb_frames;
+ }
+
+ // find the frame closer to the average using the sum of squared errors
+ for (i = 0; i < nb_frames; i++) {
+ sq_err = frame_sum_square_err(thumb->frames[i].histogram, avg_hist);
+ if (i == 0 || sq_err < min_sq_err)
+ best_frame_idx = i, min_sq_err = sq_err;
+ }
+
+ // free and reset everything (except the best frame buffer)
+ for (i = 0; i < nb_frames; i++) {
+ memset(thumb->frames[i].histogram, 0, sizeof(thumb->frames[i].histogram));
+ if (i != best_frame_idx)
+ av_frame_free(&thumb->frames[i].buf);
+ }
+ thumb->n = 0;
+
+ // raise the chosen one
+ picref = thumb->frames[best_frame_idx].buf;
+ av_log(ctx, AV_LOG_INFO, "frame id #%d (pts_time=%f) selected "
+ "from a set of %d images\n", best_frame_idx,
+ picref->pts * av_q2d(thumb->tb), nb_frames);
+ thumb->frames[best_frame_idx].buf = NULL;
+
+ return picref;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ int i, j;
+ AVFilterContext *ctx = inlink->dst;
+ ThumbContext *thumb = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ int *hist = thumb->frames[thumb->n].histogram;
+ const uint8_t *p = frame->data[0];
+
+ // keep a reference of each frame
+ thumb->frames[thumb->n].buf = frame;
+
+ // update current frame RGB histogram
+ for (j = 0; j < inlink->h; j++) {
+ for (i = 0; i < inlink->w; i++) {
+ hist[0*256 + p[i*3 ]]++;
+ hist[1*256 + p[i*3 + 1]]++;
+ hist[2*256 + p[i*3 + 2]]++;
+ }
+ p += frame->linesize[0];
+ }
+
+ // no selection until the buffer of N frames is filled up
+ thumb->n++;
+ if (thumb->n < thumb->n_frames)
+ return 0;
+
+ return ff_filter_frame(outlink, get_best_frame(ctx));
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ int i;
+ ThumbContext *thumb = ctx->priv;
+ for (i = 0; i < thumb->n_frames && thumb->frames[i].buf; i++)
+ av_frame_free(&thumb->frames[i].buf);
+ av_freep(&thumb->frames);
+}
+
+static int request_frame(AVFilterLink *link)
+{
+ AVFilterContext *ctx = link->src;
+ ThumbContext *thumb = ctx->priv;
+
+ /* loop until a frame thumbnail is available (when a frame is queued,
+ * thumb->n is reset to zero) */
+ do {
+ int ret = ff_request_frame(ctx->inputs[0]);
+ if (ret == AVERROR_EOF && thumb->n) {
+ ret = ff_filter_frame(link, get_best_frame(ctx));
+ if (ret < 0)
+ return ret;
+ ret = AVERROR_EOF;
+ }
+ if (ret < 0)
+ return ret;
+ } while (thumb->n);
+ return 0;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ ThumbContext *thumb = ctx->priv;
+
+ thumb->tb = inlink->time_base;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static const AVFilterPad thumbnail_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad thumbnail_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_thumbnail = {
+ .name = "thumbnail",
+ .description = NULL_IF_CONFIG_SMALL("Select the most representative frame in a given sequence of consecutive frames."),
+ .priv_size = sizeof(ThumbContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = thumbnail_inputs,
+ .outputs = thumbnail_outputs,
+ .priv_class = &thumbnail_class,
+};
diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c
new file mode 100644
index 0000000000..47569771d0
--- /dev/null
+++ b/libavfilter/vf_tile.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * tile video filter
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "drawutils.h"
+#include "formats.h"
+#include "video.h"
+#include "internal.h"
+
+typedef struct {
+ const AVClass *class;
+ unsigned w, h;
+ unsigned margin;
+ unsigned padding;
+ unsigned current;
+ unsigned nb_frames;
+ FFDrawContext draw;
+ FFDrawColor blank;
+ AVFrame *out_ref;
+ uint8_t rgba_color[4];
+} TileContext;
+
+#define REASONABLE_SIZE 1024
+
+#define OFFSET(x) offsetof(TileContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption tile_options[] = {
+ { "layout", "set grid size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE,
+ {.str = "6x5"}, 0, 0, FLAGS },
+ { "nb_frames", "set maximum number of frame to render", OFFSET(nb_frames),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
+ { "margin", "set outer border margin in pixels", OFFSET(margin),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1024, FLAGS },
+ { "padding", "set inner border thickness in pixels", OFFSET(padding),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1024, FLAGS },
+ { "color", "set the color of the unused area", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(tile);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ TileContext *tile = ctx->priv;
+
+ if (tile->w > REASONABLE_SIZE || tile->h > REASONABLE_SIZE) {
+ av_log(ctx, AV_LOG_ERROR, "Tile size %ux%u is insane.\n",
+ tile->w, tile->h);
+ return AVERROR(EINVAL);
+ }
+
+ if (tile->nb_frames == 0) {
+ tile->nb_frames = tile->w * tile->h;
+ } else if (tile->nb_frames > tile->w * tile->h) {
+ av_log(ctx, AV_LOG_ERROR, "nb_frames must be less than or equal to %dx%d=%d\n",
+ tile->w, tile->h, tile->w * tile->h);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ TileContext *tile = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ 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;
+
+ if (inlink->w > (INT_MAX - total_margin_w) / tile->w) {
+ av_log(ctx, AV_LOG_ERROR, "Total width %ux%u is too much.\n",
+ tile->w, inlink->w);
+ return AVERROR(EINVAL);
+ }
+ if (inlink->h > (INT_MAX - total_margin_h) / tile->h) {
+ av_log(ctx, AV_LOG_ERROR, "Total height %ux%u is too much.\n",
+ tile->h, inlink->h);
+ return AVERROR(EINVAL);
+ }
+ 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));
+ ff_draw_init(&tile->draw, inlink->format, 0);
+ ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color);
+
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return 0;
+}
+
+static void get_current_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y)
+{
+ TileContext *tile = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ const unsigned tx = tile->current % tile->w;
+ const unsigned ty = tile->current / tile->w;
+
+ *x = tile->margin + (inlink->w + tile->padding) * tx;
+ *y = tile->margin + (inlink->h + tile->padding) * ty;
+}
+
+static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf)
+{
+ TileContext *tile = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ unsigned x0, y0;
+
+ get_current_tile_pos(ctx, &x0, &y0);
+ ff_fill_rectangle(&tile->draw, &tile->blank,
+ out_buf->data, out_buf->linesize,
+ x0, y0, inlink->w, inlink->h);
+ tile->current++;
+}
+static int end_last_frame(AVFilterContext *ctx)
+{
+ TileContext *tile = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out_buf = tile->out_ref;
+ int ret;
+
+ while (tile->current < tile->nb_frames)
+ draw_blank_frame(ctx, out_buf);
+ ret = ff_filter_frame(outlink, out_buf);
+ tile->current = 0;
+ return ret;
+}
+
+/* Note: direct rendering is not possible since there is no guarantee that
+ * buffers are fed to filter_frame in the order they were obtained from
+ * get_buffer (think B-frames). */
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ TileContext *tile = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ unsigned x0, y0;
+
+ if (!tile->current) {
+ tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!tile->out_ref) {
+ av_frame_free(&picref);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(tile->out_ref, picref);
+ tile->out_ref->width = outlink->w;
+ tile->out_ref->height = outlink->h;
+
+ /* fill surface once for margin/padding */
+ if (tile->margin || tile->padding)
+ ff_fill_rectangle(&tile->draw, &tile->blank,
+ tile->out_ref->data,
+ tile->out_ref->linesize,
+ 0, 0, outlink->w, outlink->h);
+ }
+
+ get_current_tile_pos(ctx, &x0, &y0);
+ ff_copy_rectangle2(&tile->draw,
+ tile->out_ref->data, tile->out_ref->linesize,
+ picref->data, picref->linesize,
+ x0, y0, 0, 0, inlink->w, inlink->h);
+
+ av_frame_free(&picref);
+ if (++tile->current == tile->nb_frames)
+ return end_last_frame(ctx);
+
+ return 0;
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ TileContext *tile = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ int r;
+
+ r = ff_request_frame(inlink);
+ if (r == AVERROR_EOF && tile->current)
+ r = end_last_frame(ctx);
+ return r;
+}
+
+static const AVFilterPad tile_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad tile_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_props,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_tile = {
+ .name = "tile",
+ .description = NULL_IF_CONFIG_SMALL("Tile several successive frames together."),
+ .init = init,
+ .query_formats = query_formats,
+ .priv_size = sizeof(TileContext),
+ .inputs = tile_inputs,
+ .outputs = tile_outputs,
+ .priv_class = &tile_class,
+};
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
new file mode 100644
index 0000000000..096a614d67
--- /dev/null
+++ b/libavfilter/vf_tinterlace.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2010 Baptiste Coudurier
+ * Copyright (c) 2003 Michael Zucchi <notzed@ximian.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 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
+ * temporal field interlace filter, ported from MPlayer/libmpcodecs
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/avassert.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "tinterlace.h"
+
+#define OFFSET(x) offsetof(TInterlaceContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+#define TINTERLACE_FLAG_VLPF 01
+#define TINTERLACE_FLAG_EXACT_TB 2
+
+static const AVOption tinterlace_options[] = {
+ {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"},
+ {"merge", "merge fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"drop_even", "drop even fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"drop_odd", "drop odd fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"pad", "pad alternate lines with black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"interleave_top", "interleave top and bottom fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"interleave_bottom", "interleave bottom and top fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ {"interlacex2", "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2}, INT_MIN, INT_MAX, FLAGS, "mode"},
+
+ {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
+ {"low_pass_filter", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
+ {"vlpf", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
+ {"exact_tb", "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
+
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(tinterlace);
+
+#define FULL_SCALE_YUVJ_FORMATS \
+ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
+
+static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
+ FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE
+};
+
+static const AVRational standard_tbs[] = {
+ {1, 25},
+ {1, 30},
+ {1001, 30000},
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
+ const uint8_t *srcp_above, const uint8_t *srcp_below)
+{
+ int i;
+ for (i = 0; i < width; i++) {
+ // this calculation is an integer representation of
+ // '0.5 * current + 0.25 * above + 0.25 * below'
+ // '1 +' is for rounding.
+ dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
+ }
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ TInterlaceContext *tinterlace = ctx->priv;
+
+ av_frame_free(&tinterlace->cur );
+ av_frame_free(&tinterlace->next);
+ av_freep(&tinterlace->black_data[0]);
+}
+
+static int config_out_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ AVFilterLink *inlink = outlink->src->inputs[0];
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
+ TInterlaceContext *tinterlace = ctx->priv;
+ int i;
+
+ tinterlace->vsub = desc->log2_chroma_h;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+ outlink->w = inlink->w;
+ outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD ?
+ inlink->h*2 : inlink->h;
+
+ if (tinterlace->mode == MODE_PAD) {
+ uint8_t black[4] = { 16, 128, 128, 16 };
+ int i, ret;
+ if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
+ black[0] = black[3] = 0;
+ ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
+ outlink->w, outlink->h, outlink->format, 1);
+ if (ret < 0)
+ return ret;
+
+ /* fill black picture with black */
+ for (i = 0; i < 4 && tinterlace->black_data[i]; i++) {
+ int h = i == 1 || i == 2 ? FF_CEIL_RSHIFT(outlink->h, desc->log2_chroma_h) : outlink->h;
+ memset(tinterlace->black_data[i], black[i],
+ tinterlace->black_linesize[i] * h);
+ }
+ }
+ if ((tinterlace->flags & TINTERLACE_FLAG_VLPF)
+ && !(tinterlace->mode == MODE_INTERLEAVE_TOP
+ || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
+ av_log(ctx, AV_LOG_WARNING, "low_pass_filter flag ignored with mode %d\n",
+ tinterlace->mode);
+ tinterlace->flags &= ~TINTERLACE_FLAG_VLPF;
+ }
+ 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});
+ outlink->time_base = av_mul_q(inlink->time_base , (AVRational){1,2});
+ } else if (tinterlace->mode != MODE_PAD) {
+ outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
+ outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1});
+ }
+
+ for (i = 0; i<FF_ARRAY_ELEMS(standard_tbs); i++){
+ if (!av_cmp_q(standard_tbs[i], outlink->time_base))
+ break;
+ }
+ if (i == FF_ARRAY_ELEMS(standard_tbs) ||
+ (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
+ outlink->time_base = tinterlace->preout_time_base;
+
+ if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
+ tinterlace->lowpass_line = lowpass_line_c;
+ if (ARCH_X86)
+ ff_tinterlace_init_x86(tinterlace);
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n",
+ tinterlace->mode, (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "on" : "off",
+ inlink->h, outlink->h);
+
+ return 0;
+}
+
+#define FIELD_UPPER 0
+#define FIELD_LOWER 1
+#define FIELD_UPPER_AND_LOWER 2
+
+/**
+ * Copy picture field from src to dst.
+ *
+ * @param src_field copy from upper, lower field or both
+ * @param interleave leave a padding line between each copied line
+ * @param dst_field copy to upper or lower field,
+ * only meaningful when interleave is selected
+ * @param flags context flags
+ */
+static inline
+void copy_picture_field(TInterlaceContext *tinterlace,
+ uint8_t *dst[4], int dst_linesize[4],
+ const uint8_t *src[4], int src_linesize[4],
+ enum AVPixelFormat format, int w, int src_h,
+ int src_field, int interleave, int dst_field,
+ int flags)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
+ int hsub = desc->log2_chroma_w;
+ int plane, vsub = desc->log2_chroma_h;
+ int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
+ int h;
+
+ for (plane = 0; plane < desc->nb_components; plane++) {
+ int lines = plane == 1 || plane == 2 ? FF_CEIL_RSHIFT(src_h, vsub) : src_h;
+ int cols = plane == 1 || plane == 2 ? FF_CEIL_RSHIFT( w, hsub) : w;
+ uint8_t *dstp = dst[plane];
+ const uint8_t *srcp = src[plane];
+
+ lines = (lines + (src_field == FIELD_UPPER)) / k;
+ if (src_field == FIELD_LOWER)
+ srcp += src_linesize[plane];
+ if (interleave && dst_field == FIELD_LOWER)
+ dstp += dst_linesize[plane];
+ if (flags & TINTERLACE_FLAG_VLPF) {
+ // Low-pass filtering is required when creating an interlaced destination from
+ // a progressive source which contains high-frequency vertical detail.
+ // Filtering will reduce interlace 'twitter' and Moire patterning.
+ int srcp_linesize = src_linesize[plane] * k;
+ int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
+ for (h = lines; h > 0; h--) {
+ const uint8_t *srcp_above = srcp - src_linesize[plane];
+ const uint8_t *srcp_below = srcp + src_linesize[plane];
+ if (h == lines) srcp_above = srcp; // there is no line above
+ if (h == 1) srcp_below = srcp; // there is no line below
+
+ tinterlace->lowpass_line(dstp, cols, srcp, srcp_above, srcp_below);
+ dstp += dstp_linesize;
+ srcp += srcp_linesize;
+ }
+ } else {
+ av_image_copy_plane(dstp, dst_linesize[plane] * (interleave ? 2 : 1),
+ srcp, src_linesize[plane]*k, cols, lines);
+ }
+ }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ TInterlaceContext *tinterlace = ctx->priv;
+ AVFrame *cur, *next, *out;
+ int field, tff, ret;
+
+ av_frame_free(&tinterlace->cur);
+ tinterlace->cur = tinterlace->next;
+ tinterlace->next = picref;
+
+ cur = tinterlace->cur;
+ next = tinterlace->next;
+ /* we need at least two frames */
+ if (!tinterlace->cur)
+ return 0;
+
+ switch (tinterlace->mode) {
+ case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
+ * the lower field, generating a double-height video at half framerate */
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out, cur);
+ out->height = outlink->h;
+ out->interlaced_frame = 1;
+ out->top_field_first = 1;
+
+ /* write odd frame lines into the upper field of the new frame */
+ 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, 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, FIELD_LOWER, tinterlace->flags);
+ av_frame_free(&tinterlace->next);
+ break;
+
+ case MODE_DROP_ODD: /* only output even frames, odd frames are dropped; height unchanged, half framerate */
+ case MODE_DROP_EVEN: /* only output odd frames, even frames are dropped; height unchanged, half framerate */
+ out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_free(&tinterlace->next);
+ break;
+
+ case MODE_PAD: /* expand each frame to double height, but pad alternate
+ * lines with black; framerate unchanged */
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out, cur);
+ out->height = outlink->h;
+
+ field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
+ /* copy upper and lower fields */
+ 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, field, tinterlace->flags);
+ /* pad with black the other field */
+ copy_picture_field(tinterlace, out->data, out->linesize,
+ (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
+ inlink->format, inlink->w, inlink->h,
+ FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags);
+ break;
+
+ /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
+ * halving the frame rate and preserving image height */
+ case MODE_INTERLEAVE_TOP: /* top field first */
+ case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
+ tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out, cur);
+ out->interlaced_frame = 1;
+ out->top_field_first = tff;
+
+ /* copy upper/lower field from cur */
+ copy_picture_field(tinterlace, out->data, out->linesize,
+ (const uint8_t **)cur->data, cur->linesize,
+ inlink->format, inlink->w, inlink->h,
+ tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
+ tinterlace->flags);
+ /* copy lower/upper field from next */
+ copy_picture_field(tinterlace, out->data, out->linesize,
+ (const uint8_t **)next->data, next->linesize,
+ inlink->format, inlink->w, inlink->h,
+ tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
+ tinterlace->flags);
+ av_frame_free(&tinterlace->next);
+ break;
+ case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
+ /* output current frame first */
+ out = av_frame_clone(cur);
+ if (!out)
+ return AVERROR(ENOMEM);
+ out->interlaced_frame = 1;
+ if (cur->pts != AV_NOPTS_VALUE)
+ out->pts = cur->pts*2;
+
+ out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+ if ((ret = ff_filter_frame(outlink, out)) < 0)
+ return ret;
+
+ /* output mix of current and next frame */
+ tff = next->top_field_first;
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out, next);
+ out->interlaced_frame = 1;
+ out->top_field_first = !tff;
+
+ if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE)
+ out->pts = cur->pts + next->pts;
+ else
+ out->pts = AV_NOPTS_VALUE;
+ /* write current frame second field lines into the second field of the new frame */
+ copy_picture_field(tinterlace, out->data, out->linesize,
+ (const uint8_t **)cur->data, cur->linesize,
+ inlink->format, inlink->w, inlink->h,
+ tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
+ tinterlace->flags);
+ /* write next frame first field lines into the first 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,
+ tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
+ tinterlace->flags);
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+ ret = ff_filter_frame(outlink, out);
+ tinterlace->frame++;
+
+ return ret;
+}
+
+static const AVFilterPad tinterlace_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad tinterlace_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_out_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_tinterlace = {
+ .name = "tinterlace",
+ .description = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
+ .priv_size = sizeof(TInterlaceContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = tinterlace_inputs,
+ .outputs = tinterlace_outputs,
+ .priv_class = &tinterlace_class,
+};
diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c
index 07602b9086..911329caac 100644
--- a/libavfilter/vf_transpose.c
+++ b/libavfilter/vf_transpose.c
@@ -2,20 +2,20 @@
* Copyright (c) 2010 Stefano Sabatini
* Copyright (c) 2008 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,6 +38,12 @@
#include "internal.h"
#include "video.h"
+typedef enum {
+ TRANSPOSE_PT_TYPE_NONE,
+ TRANSPOSE_PT_TYPE_LANDSCAPE,
+ TRANSPOSE_PT_TYPE_PORTRAIT,
+} PassthroughType;
+
enum TransposeDir {
TRANSPOSE_CCLOCK_FLIP,
TRANSPOSE_CLOCK,
@@ -50,37 +56,26 @@ typedef struct TransContext {
int hsub, vsub;
int pixsteps[4];
- enum TransposeDir dir;
+ int passthrough; ///< PassthroughType, landscape passthrough mode enabled
+ int dir; ///< TransposeDir
} TransContext;
static int query_formats(AVFilterContext *ctx)
{
- enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
- AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
- AV_PIX_FMT_RGB565BE, AV_PIX_FMT_RGB565LE,
- AV_PIX_FMT_RGB555BE, AV_PIX_FMT_RGB555LE,
- AV_PIX_FMT_BGR565BE, AV_PIX_FMT_BGR565LE,
- AV_PIX_FMT_BGR555BE, AV_PIX_FMT_BGR555LE,
- AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE,
- AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUV420P16BE,
- AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUV422P16BE,
- AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUV444P16BE,
- AV_PIX_FMT_NV12, AV_PIX_FMT_NV21,
- AV_PIX_FMT_RGB8, AV_PIX_FMT_BGR8,
- AV_PIX_FMT_RGB4_BYTE, AV_PIX_FMT_BGR4_BYTE,
- AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P,
- AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P,
- AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
- AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P,
- AV_PIX_FMT_YUVA420P, AV_PIX_FMT_GRAY8,
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+ AVFilterFormats *pix_fmts = NULL;
+ int fmt;
+
+ for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
+ if (!(desc->flags & AV_PIX_FMT_FLAG_PAL ||
+ desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
+ desc->flags & AV_PIX_FMT_FLAG_BITSTREAM ||
+ desc->log2_chroma_w != desc->log2_chroma_h))
+ ff_add_format(&pix_fmts, fmt);
+ }
+
+
+ return ff_set_common_formats(ctx, pix_fmts);
}
static int config_props_output(AVFilterLink *outlink)
@@ -91,6 +86,23 @@ static int config_props_output(AVFilterLink *outlink)
const AVPixFmtDescriptor *desc_out = av_pix_fmt_desc_get(outlink->format);
const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format);
+ if (trans->dir&4) {
+ av_log(ctx, AV_LOG_WARNING,
+ "dir values greater than 3 are deprecated, use the passthrough option instead\n");
+ trans->dir &= 3;
+ trans->passthrough = TRANSPOSE_PT_TYPE_LANDSCAPE;
+ }
+
+ if ((inlink->w >= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) ||
+ (inlink->w <= inlink->h && trans->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) {
+ av_log(ctx, AV_LOG_VERBOSE,
+ "w:%d h:%d -> w:%d h:%d (passthrough mode)\n",
+ inlink->w, inlink->h, inlink->w, inlink->h);
+ return 0;
+ } else {
+ trans->passthrough = TRANSPOSE_PT_TYPE_NONE;
+ }
+
trans->hsub = desc_in->log2_chroma_w;
trans->vsub = desc_in->log2_chroma_h;
@@ -113,41 +125,43 @@ static int config_props_output(AVFilterLink *outlink)
return 0;
}
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
{
- AVFilterLink *outlink = inlink->dst->outputs[0];
TransContext *trans = inlink->dst->priv;
- AVFrame *out;
- int plane;
- out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
- if (!out) {
- av_frame_free(&in);
- return AVERROR(ENOMEM);
- }
+ return trans->passthrough ?
+ ff_null_get_video_buffer (inlink, w, h) :
+ ff_default_get_video_buffer(inlink, w, h);
+}
- out->pts = in->pts;
+typedef struct ThreadData {
+ AVFrame *in, *out;
+} ThreadData;
- if (in->sample_aspect_ratio.num == 0) {
- out->sample_aspect_ratio = in->sample_aspect_ratio;
- } else {
- out->sample_aspect_ratio.num = in->sample_aspect_ratio.den;
- out->sample_aspect_ratio.den = in->sample_aspect_ratio.num;
- }
+static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr,
+ int nb_jobs)
+{
+ TransContext *trans = ctx->priv;
+ ThreadData *td = arg;
+ AVFrame *out = td->out;
+ AVFrame *in = td->in;
+ int plane;
for (plane = 0; out->data[plane]; plane++) {
int hsub = plane == 1 || plane == 2 ? trans->hsub : 0;
int vsub = plane == 1 || plane == 2 ? trans->vsub : 0;
int pixstep = trans->pixsteps[plane];
- int inh = in->height >> vsub;
- int outw = out->width >> hsub;
- int outh = out->height >> vsub;
+ int inh = in->height >> vsub;
+ int outw = FF_CEIL_RSHIFT(out->width, hsub);
+ int outh = FF_CEIL_RSHIFT(out->height, vsub);
+ int start = (outh * jobnr ) / nb_jobs;
+ int end = (outh * (jobnr+1)) / nb_jobs;
uint8_t *dst, *src;
int dstlinesize, srclinesize;
int x, y;
- dst = out->data[plane];
dstlinesize = out->linesize[plane];
+ dst = out->data[plane] + start * dstlinesize;
src = in->data[plane];
srclinesize = in->linesize[plane];
@@ -157,64 +171,115 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
}
if (trans->dir & 2) {
- dst += out->linesize[plane] * (outh - 1);
+ dst = out->data[plane] + dstlinesize * (outh - start - 1);
dstlinesize *= -1;
}
- for (y = 0; y < outh; y++) {
- switch (pixstep) {
- case 1:
+ switch (pixstep) {
+ case 1:
+ for (y = start; y < end; y++, dst += dstlinesize)
for (x = 0; x < outw; x++)
dst[x] = src[x * srclinesize + y];
- break;
- case 2:
+ break;
+ case 2:
+ for (y = start; y < end; y++, dst += dstlinesize) {
for (x = 0; x < outw; x++)
*((uint16_t *)(dst + 2 * x)) =
*((uint16_t *)(src + x * srclinesize + y * 2));
- break;
- case 3:
+ }
+ break;
+ case 3:
+ for (y = start; y < end; y++, dst += dstlinesize) {
for (x = 0; x < outw; x++) {
int32_t v = AV_RB24(src + x * srclinesize + y * 3);
AV_WB24(dst + 3 * x, v);
}
- break;
- case 4:
+ }
+ break;
+ case 4:
+ for (y = start; y < end; y++, dst += dstlinesize) {
for (x = 0; x < outw; x++)
*((uint32_t *)(dst + 4 * x)) =
*((uint32_t *)(src + x * srclinesize + y * 4));
- break;
}
- dst += dstlinesize;
+ break;
+ case 6:
+ for (y = start; y < end; y++, dst += dstlinesize) {
+ for (x = 0; x < outw; x++) {
+ int64_t v = AV_RB48(src + x * srclinesize + y*6);
+ AV_WB48(dst + 6*x, v);
+ }
+ }
+ break;
+ case 8:
+ for (y = start; y < end; y++, dst += dstlinesize) {
+ for (x = 0; x < outw; x++)
+ *((uint64_t *)(dst + 8*x)) = *((uint64_t *)(src + x * srclinesize + y*8));
+ }
+ break;
}
}
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ TransContext *trans = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ThreadData td;
+ AVFrame *out;
+
+ if (trans->passthrough)
+ return ff_filter_frame(outlink, in);
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ if (in->sample_aspect_ratio.num == 0) {
+ out->sample_aspect_ratio = in->sample_aspect_ratio;
+ } else {
+ out->sample_aspect_ratio.num = in->sample_aspect_ratio.den;
+ out->sample_aspect_ratio.den = in->sample_aspect_ratio.num;
+ }
+
+ td.in = in, td.out = out;
+ ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads));
av_frame_free(&in);
return ff_filter_frame(outlink, out);
}
#define OFFSET(x) offsetof(TransContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "dir", "Transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP },
- TRANSPOSE_CCLOCK_FLIP, TRANSPOSE_CLOCK_FLIP, FLAGS, "dir" },
- { "cclock_flip", "counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .unit = "dir" },
- { "clock", "clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .unit = "dir" },
- { "cclock", "counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .unit = "dir" },
- { "clock_flip", "clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .unit = "dir" },
- { NULL },
-};
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption transpose_options[] = {
+ { "dir", "set transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 7, FLAGS, "dir" },
+ { "cclock_flip", "rotate counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .unit = "dir" },
+ { "clock", "rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .unit = "dir" },
+ { "cclock", "rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .unit = "dir" },
+ { "clock_flip", "rotate clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .unit = "dir" },
-static const AVClass transpose_class = {
- .class_name = "transpose",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+ { "passthrough", "do not apply transposition if the input matches the specified geometry",
+ OFFSET(passthrough), AV_OPT_TYPE_INT, {.i64=TRANSPOSE_PT_TYPE_NONE}, 0, INT_MAX, FLAGS, "passthrough" },
+ { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_NONE}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
+ { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_PORTRAIT}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
+ { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_LANDSCAPE}, INT_MIN, INT_MAX, FLAGS, "passthrough" },
+
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(transpose);
+
static const AVFilterPad avfilter_vf_transpose_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer = get_video_buffer,
.filter_frame = filter_frame,
},
{ NULL }
@@ -237,4 +302,5 @@ AVFilter ff_vf_transpose = {
.query_formats = query_formats,
.inputs = avfilter_vf_transpose_inputs,
.outputs = avfilter_vf_transpose_outputs,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
};
diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c
index d0d59e24ff..d5f5018ce4 100644
--- a/libavfilter/vf_unsharp.c
+++ b/libavfilter/vf_unsharp.c
@@ -3,26 +3,26 @@
* Port copyright (c) 2010 Daniel G. Taylor <dan@programmer-art.org>
* Relicensed to the LGPL with permission from Remi Guyomarch.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
- * blur / sharpen filter, ported to Libav from MPlayer
+ * blur / sharpen filter, ported to FFmpeg from MPlayer
* libmpcodecs/unsharp.c.
*
* This code is based on:
@@ -41,79 +41,57 @@
#include "internal.h"
#include "video.h"
#include "libavutil/common.h"
+#include "libavutil/imgutils.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
-
-#define MIN_SIZE 3
-#define MAX_SIZE 13
-
-/* right-shift and round-up */
-#define SHIFTUP(x,shift) (-((-(x))>>(shift)))
-
-typedef struct FilterParam {
- 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 *sc[(MAX_SIZE * MAX_SIZE) - 1]; ///< finite state machine storage
-} FilterParam;
-
-typedef struct UnsharpContext {
- const AVClass *class;
- int lmsize_x, lmsize_y, cmsize_x, cmsize_y;
- float lamount, camount;
- FilterParam luma; ///< luma parameters (width, height, amount)
- FilterParam chroma; ///< chroma parameters (width, height, amount)
- int hsub, vsub;
-} UnsharpContext;
+#include "unsharp.h"
+#include "unsharp_opencl.h"
static void apply_unsharp( uint8_t *dst, int dst_stride,
const uint8_t *src, int src_stride,
- int width, int height, FilterParam *fp)
+ int width, int height, UnsharpFilterParam *fp)
{
uint32_t **sc = fp->sc;
- uint32_t sr[(MAX_SIZE * MAX_SIZE) - 1], tmp1, tmp2;
+ uint32_t sr[MAX_MATRIX_SIZE - 1], tmp1, tmp2;
int32_t res;
int x, y, z;
- const uint8_t *src2;
-
- if (!fp->amount) {
- if (dst_stride == src_stride)
- memcpy(dst, src, src_stride * height);
- else
- for (y = 0; y < height; y++, dst += dst_stride, src += src_stride)
- memcpy(dst, src, width);
+ const uint8_t *src2 = NULL; //silence a warning
+ const int amount = fp->amount;
+ const int steps_x = fp->steps_x;
+ const int steps_y = fp->steps_y;
+ const int scalebits = fp->scalebits;
+ const int32_t halfscale = fp->halfscale;
+
+ if (!amount) {
+ av_image_copy_plane(dst, dst_stride, src, src_stride, width, height);
return;
}
- for (y = 0; y < 2 * fp->steps_y; y++)
- memset(sc[y], 0, sizeof(sc[y][0]) * (width + 2 * fp->steps_x));
+ for (y = 0; y < 2 * steps_y; y++)
+ memset(sc[y], 0, sizeof(sc[y][0]) * (width + 2 * steps_x));
- for (y = -fp->steps_y; y < height + fp->steps_y; y++) {
+ for (y = -steps_y; y < height + steps_y; y++) {
if (y < height)
src2 = src;
- memset(sr, 0, sizeof(sr[0]) * (2 * fp->steps_x - 1));
- for (x = -fp->steps_x; x < width + fp->steps_x; x++) {
+ memset(sr, 0, sizeof(sr[0]) * (2 * steps_x - 1));
+ for (x = -steps_x; x < width + steps_x; x++) {
tmp1 = x <= 0 ? src2[0] : x >= width ? src2[width-1] : src2[x];
- for (z = 0; z < fp->steps_x * 2; z += 2) {
+ for (z = 0; z < steps_x * 2; z += 2) {
tmp2 = sr[z + 0] + tmp1; sr[z + 0] = tmp1;
tmp1 = sr[z + 1] + tmp2; sr[z + 1] = tmp2;
}
- for (z = 0; z < fp->steps_y * 2; z += 2) {
- tmp2 = sc[z + 0][x + fp->steps_x] + tmp1; sc[z + 0][x + fp->steps_x] = tmp1;
- tmp1 = sc[z + 1][x + fp->steps_x] + tmp2; sc[z + 1][x + fp->steps_x] = tmp2;
+ for (z = 0; z < steps_y * 2; z += 2) {
+ tmp2 = sc[z + 0][x + steps_x] + tmp1; sc[z + 0][x + steps_x] = tmp1;
+ tmp1 = sc[z + 1][x + steps_x] + tmp2; sc[z + 1][x + steps_x] = tmp2;
}
- if (x >= fp->steps_x && y >= fp->steps_y) {
- const uint8_t *srx = src - fp->steps_y * src_stride + x - fp->steps_x;
- uint8_t *dsx = dst - fp->steps_y * dst_stride + x - fp->steps_x;
+ if (x >= steps_x && y >= steps_y) {
+ const uint8_t *srx = src - steps_y * src_stride + x - steps_x;
+ uint8_t *dsx = dst - steps_y * dst_stride + x - steps_x;
- res = (int32_t)*srx + ((((int32_t) * srx - (int32_t)((tmp1 + fp->halfscale) >> fp->scalebits)) * fp->amount) >> 16);
+ res = (int32_t)*srx + ((((int32_t) * srx - (int32_t)((tmp1 + halfscale) >> scalebits)) * amount) >> 16);
*dsx = av_clip_uint8(res);
}
}
@@ -124,7 +102,25 @@ static void apply_unsharp( uint8_t *dst, int dst_stride,
}
}
-static void set_filter_param(FilterParam *fp, int msize_x, int msize_y, float amount)
+static int apply_unsharp_c(AVFilterContext *ctx, AVFrame *in, AVFrame *out)
+{
+ AVFilterLink *inlink = ctx->inputs[0];
+ UnsharpContext *unsharp = ctx->priv;
+ int i, plane_w[3], plane_h[3];
+ UnsharpFilterParam *fp[3];
+ plane_w[0] = inlink->w;
+ plane_w[1] = plane_w[2] = FF_CEIL_RSHIFT(inlink->w, unsharp->hsub);
+ plane_h[0] = inlink->h;
+ plane_h[1] = plane_h[2] = FF_CEIL_RSHIFT(inlink->h, unsharp->vsub);
+ fp[0] = &unsharp->luma;
+ fp[1] = fp[2] = &unsharp->chroma;
+ for (i = 0; i < 3; i++) {
+ apply_unsharp(out->data[i], out->linesize[i], in->data[i], in->linesize[i], plane_w[i], plane_h[i], fp[i]);
+ }
+ return 0;
+}
+
+static void set_filter_param(UnsharpFilterParam *fp, int msize_x, int msize_y, float amount)
{
fp->msize_x = msize_x;
fp->msize_y = msize_y;
@@ -138,67 +134,99 @@ static void set_filter_param(FilterParam *fp, int msize_x, int msize_y, float am
static av_cold int init(AVFilterContext *ctx)
{
+ int ret = 0;
UnsharpContext *unsharp = ctx->priv;
+
set_filter_param(&unsharp->luma, unsharp->lmsize_x, unsharp->lmsize_y, unsharp->lamount);
set_filter_param(&unsharp->chroma, unsharp->cmsize_x, unsharp->cmsize_y, unsharp->camount);
+ unsharp->apply_unsharp = apply_unsharp_c;
+ if (!CONFIG_OPENCL && unsharp->opencl) {
+ av_log(ctx, AV_LOG_ERROR, "OpenCL support was not enabled in this build, cannot be selected\n");
+ return AVERROR(EINVAL);
+ }
+ if (CONFIG_OPENCL && unsharp->opencl) {
+ unsharp->apply_unsharp = ff_opencl_apply_unsharp;
+ ret = ff_opencl_unsharp_init(ctx);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
static int query_formats(AVFilterContext *ctx)
{
- enum AVPixelFormat pix_fmts[] = {
+ static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P,
AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_NONE
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
-
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
-static void init_filter_param(AVFilterContext *ctx, FilterParam *fp, const char *effect_type, int width)
+static int init_filter_param(AVFilterContext *ctx, UnsharpFilterParam *fp, const char *effect_type, int width)
{
int z;
- const char *effect;
+ const char *effect = fp->amount == 0 ? "none" : fp->amount < 0 ? "blur" : "sharpen";
- effect = fp->amount == 0 ? "none" : fp->amount < 0 ? "blur" : "sharpen";
+ if (!(fp->msize_x & fp->msize_y & 1)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid even size for %s matrix size %dx%d\n",
+ effect_type, fp->msize_x, fp->msize_y);
+ return AVERROR(EINVAL);
+ }
av_log(ctx, AV_LOG_VERBOSE, "effect:%s type:%s msize_x:%d msize_y:%d amount:%0.2f\n",
effect, effect_type, fp->msize_x, fp->msize_y, fp->amount / 65535.0);
for (z = 0; z < 2 * fp->steps_y; z++)
- fp->sc[z] = av_malloc(sizeof(*(fp->sc[z])) * (width + 2 * fp->steps_x));
+ if (!(fp->sc[z] = av_malloc_array(width + 2 * fp->steps_x,
+ sizeof(*(fp->sc[z])))))
+ return AVERROR(ENOMEM);
+
+ return 0;
}
static int config_props(AVFilterLink *link)
{
UnsharpContext *unsharp = link->dst->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
+ int ret;
unsharp->hsub = desc->log2_chroma_w;
unsharp->vsub = desc->log2_chroma_h;
- init_filter_param(link->dst, &unsharp->luma, "luma", link->w);
- init_filter_param(link->dst, &unsharp->chroma, "chroma", SHIFTUP(link->w, unsharp->hsub));
+ ret = init_filter_param(link->dst, &unsharp->luma, "luma", link->w);
+ if (ret < 0)
+ return ret;
+ ret = init_filter_param(link->dst, &unsharp->chroma, "chroma", FF_CEIL_RSHIFT(link->w, unsharp->hsub));
+ if (ret < 0)
+ return ret;
return 0;
}
-static void free_filter_param(FilterParam *fp)
+static void free_filter_param(UnsharpFilterParam *fp)
{
int z;
for (z = 0; z < 2 * fp->steps_y; z++)
- av_free(fp->sc[z]);
+ av_freep(&fp->sc[z]);
}
static av_cold void uninit(AVFilterContext *ctx)
{
UnsharpContext *unsharp = ctx->priv;
+ if (CONFIG_OPENCL && unsharp->opencl) {
+ ff_opencl_unsharp_uninit(ctx);
+ }
+
free_filter_param(&unsharp->luma);
free_filter_param(&unsharp->chroma);
}
@@ -208,8 +236,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
UnsharpContext *unsharp = link->dst->priv;
AVFilterLink *outlink = link->dst->outputs[0];
AVFrame *out;
- int cw = SHIFTUP(link->w, unsharp->hsub);
- int ch = SHIFTUP(link->h, unsharp->vsub);
+ int ret = 0;
out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
if (!out) {
@@ -217,33 +244,43 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
return AVERROR(ENOMEM);
}
av_frame_copy_props(out, in);
+ if (CONFIG_OPENCL && unsharp->opencl) {
+ ret = ff_opencl_unsharp_process_inout_buf(link->dst, in, out);
+ if (ret < 0)
+ goto end;
+ }
- apply_unsharp(out->data[0], out->linesize[0], in->data[0], in->linesize[0], link->w, link->h, &unsharp->luma);
- apply_unsharp(out->data[1], out->linesize[1], in->data[1], in->linesize[1], cw, ch, &unsharp->chroma);
- apply_unsharp(out->data[2], out->linesize[2], in->data[2], in->linesize[2], cw, ch, &unsharp->chroma);
-
+ ret = unsharp->apply_unsharp(link->dst, in, out);
+end:
av_frame_free(&in);
+
+ if (ret < 0)
+ return ret;
return ff_filter_frame(outlink, out);
}
#define OFFSET(x) offsetof(UnsharpContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "luma_msize_x", "luma matrix horizontal size", OFFSET(lmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
- { "luma_msize_y", "luma matrix vertical size", OFFSET(lmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
- { "luma_amount", "luma effect strength", OFFSET(lamount), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, -2, 5, FLAGS },
- { "chroma_msize_x", "chroma matrix horizontal size", OFFSET(cmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
- { "chroma_msize_y", "chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
- { "chroma_amount", "chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
- { NULL },
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+#define MIN_SIZE 3
+#define MAX_SIZE 63
+static const AVOption unsharp_options[] = {
+ { "luma_msize_x", "set luma matrix horizontal size", OFFSET(lmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "lx", "set luma matrix horizontal size", OFFSET(lmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "luma_msize_y", "set luma matrix vertical size", OFFSET(lmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "ly", "set luma matrix vertical size", OFFSET(lmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "luma_amount", "set luma effect strength", OFFSET(lamount), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, -2, 5, FLAGS },
+ { "la", "set luma effect strength", OFFSET(lamount), AV_OPT_TYPE_FLOAT, { .dbl = 1 }, -2, 5, FLAGS },
+ { "chroma_msize_x", "set chroma matrix horizontal size", OFFSET(cmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "cx", "set chroma matrix horizontal size", OFFSET(cmsize_x), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "chroma_msize_y", "set chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "cy", "set chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS },
+ { "chroma_amount", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
+ { "ca", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS },
+ { "opencl", "use OpenCL filtering capabilities", OFFSET(opencl), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+ { NULL }
};
-static const AVClass unsharp_class = {
- .class_name = "unsharp",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+AVFILTER_DEFINE_CLASS(unsharp);
static const AVFilterPad avfilter_vf_unsharp_inputs[] = {
{
@@ -264,17 +301,14 @@ static const AVFilterPad avfilter_vf_unsharp_outputs[] = {
};
AVFilter ff_vf_unsharp = {
- .name = "unsharp",
- .description = NULL_IF_CONFIG_SMALL("Sharpen or blur the input video."),
-
- .priv_size = sizeof(UnsharpContext),
- .priv_class = &unsharp_class,
-
- .init = init,
- .uninit = uninit,
+ .name = "unsharp",
+ .description = NULL_IF_CONFIG_SMALL("Sharpen or blur the input video."),
+ .priv_size = sizeof(UnsharpContext),
+ .priv_class = &unsharp_class,
+ .init = init,
+ .uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_unsharp_inputs,
-
- .outputs = avfilter_vf_unsharp_outputs,
+ .inputs = avfilter_vf_unsharp_inputs,
+ .outputs = avfilter_vf_unsharp_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
diff --git a/libavfilter/vf_uspp.c b/libavfilter/vf_uspp.c
new file mode 100644
index 0000000000..82ee99760c
--- /dev/null
+++ b/libavfilter/vf_uspp.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2014 Arwa Arif <arwaarif1994@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 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
+ * Ultra Slow/Simple Post-processing filter.
+ *
+ * Originally written by Michael Niedermayer for the MPlayer project, and
+ * ported by Arwa Arif for FFmpeg.
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+#include "avfilter.h"
+
+#define MAX_LEVEL 8 /* quality levels */
+#define BLOCK 16
+
+typedef struct {
+ const AVClass *av_class;
+ int log2_count;
+ int hsub, vsub;
+ int qp;
+ int qscale_type;
+ int temp_stride[3];
+ uint8_t *src[3];
+ uint16_t *temp[3];
+ int outbuf_size;
+ uint8_t *outbuf;
+ AVCodecContext *avctx_enc[BLOCK*BLOCK];
+ AVFrame *frame;
+ AVFrame *frame_dec;
+ uint8_t *non_b_qp_table;
+ int non_b_qp_alloc_size;
+ int use_bframe_qp;
+} USPPContext;
+
+#define OFFSET(x) offsetof(USPPContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption uspp_options[] = {
+ { "quality", "set quality", OFFSET(log2_count), AV_OPT_TYPE_INT, {.i64 = 3}, 0, MAX_LEVEL, FLAGS },
+ { "qp", "force a constant quantizer parameter", OFFSET(qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 63, FLAGS },
+ { "use_bframe_qp", "use B-frames' QP", OFFSET(use_bframe_qp), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(uspp);
+
+DECLARE_ALIGNED(8, static const uint8_t, dither)[8][8] = {
+ { 0*4, 48*4, 12*4, 60*4, 3*4, 51*4, 15*4, 63*4, },
+ { 32*4, 16*4, 44*4, 28*4, 35*4, 19*4, 47*4, 31*4, },
+ { 8*4, 56*4, 4*4, 52*4, 11*4, 59*4, 7*4, 55*4, },
+ { 40*4, 24*4, 36*4, 20*4, 43*4, 27*4, 39*4, 23*4, },
+ { 2*4, 50*4, 14*4, 62*4, 1*4, 49*4, 13*4, 61*4, },
+ { 34*4, 18*4, 46*4, 30*4, 33*4, 17*4, 45*4, 29*4, },
+ { 10*4, 58*4, 6*4, 54*4, 9*4, 57*4, 5*4, 53*4, },
+ { 42*4, 26*4, 38*4, 22*4, 41*4, 25*4, 37*4, 21*4, },
+};
+
+static const uint8_t offset[511][2] = {
+ { 0, 0},
+ { 0, 0}, { 8, 8}, // quality 1
+ { 0, 0}, { 4, 4}, {12, 8}, { 8,12}, // quality 2
+ { 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14}, // quality 3
+
+ { 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14},
+ { 5, 1}, {15, 3}, { 9, 5}, { 3, 7}, {13, 9}, { 7,11}, { 1,13}, {11,15}, // quality 4
+
+ { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9},
+ { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
+ { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13},
+ { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, // quality 5
+
+ { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8},
+ { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9},
+ { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 2}, {15, 2}, { 7,10}, {15,10},
+ { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 3}, {14, 3}, { 6,11}, {14,11},
+ { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 4}, {12, 4}, { 4,12}, {12,12},
+ { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 5}, {13, 5}, { 5,13}, {13,13},
+ { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 6}, {15, 6}, { 7,14}, {15,14},
+ { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, // quality 6
+
+ { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10},
+ { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14},
+ { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11},
+ { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15},
+ { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10},
+ { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 2, 6}, {10, 6}, { 2,14}, {10,14},
+ { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11},
+ { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 3, 7}, {11, 7}, { 3,15}, {11,15},
+ { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 4, 2}, {12, 2}, { 4,10}, {12,10},
+ { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 4, 6}, {12, 6}, { 4,14}, {12,14},
+ { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 5, 3}, {13, 3}, { 5,11}, {13,11},
+ { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 5, 7}, {13, 7}, { 5,15}, {13,15},
+ { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 6, 2}, {14, 2}, { 6,10}, {14,10},
+ { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 6, 6}, {14, 6}, { 6,14}, {14,14},
+ { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
+ { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, // quality 7
+
+ { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12},
+ { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8},
+ { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14},
+ { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10},
+ { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14},
+ { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10},
+ { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12},
+ { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8},
+ { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13},
+ { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9},
+ { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15},
+ { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
+ { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15},
+ { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, // quality 8
+ { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13},
+ { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9},
+ { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13},
+ { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9},
+ { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15},
+ { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11},
+ { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15},
+ { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11},
+ { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13},
+ { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9},
+ { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12},
+ { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8},
+ { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14},
+ { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10},
+ { 1, 2}, { 9, 2}, { 1,10}, { 9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14},
+ { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10},
+ { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12},
+ { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
+};
+
+static void store_slice_c(uint8_t *dst, const uint16_t *src,
+ int dst_stride, int src_stride,
+ int width, int height, int log2_scale)
+{
+ int y, x;
+
+#define STORE(pos) do { \
+ temp = ((src[x + y * src_stride + pos] << log2_scale) + d[pos]) >> 8; \
+ if (temp & 0x100) temp = ~(temp >> 31); \
+ dst[x + y * dst_stride + pos] = temp; \
+} while (0)
+
+ for (y = 0; y < height; y++) {
+ const uint8_t *d = dither[y&7];
+ for (x = 0; x < width; x += 8) {
+ int temp;
+ STORE(0);
+ STORE(1);
+ STORE(2);
+ STORE(3);
+ STORE(4);
+ STORE(5);
+ STORE(6);
+ STORE(7);
+ }
+ }
+}
+
+static void filter(USPPContext *p, uint8_t *dst[3], uint8_t *src[3],
+ int dst_stride[3], int src_stride[3], int width,
+ int height, uint8_t *qp_store, int qp_stride)
+{
+ int x, y, i, j;
+ const int count = 1<<p->log2_count;
+
+ for (i = 0; i < 3; i++) {
+ int is_chroma = !!i;
+ int w = FF_CEIL_RSHIFT(width, is_chroma ? p->hsub : 0);
+ int h = FF_CEIL_RSHIFT(height, is_chroma ? p->vsub : 0);
+ int stride = p->temp_stride[i];
+ int block = BLOCK >> (is_chroma ? p->hsub : 0);
+
+ if (!src[i] || !dst[i])
+ continue;
+ for (y = 0; y < h; y++) {
+ int index = block + block * stride + y * stride;
+
+ memcpy(p->src[i] + index, src[i] + y * src_stride[i], w );
+ for (x = 0; x < block; x++) {
+ p->src[i][index - x - 1] = p->src[i][index + x ];
+ p->src[i][index + w + x ] = p->src[i][index + w - x - 1];
+ }
+ }
+ for (y = 0; y < block; y++) {
+ memcpy(p->src[i] + ( block-1-y) * stride, p->src[i] + ( y+block ) * stride, stride);
+ memcpy(p->src[i] + (h+block +y) * stride, p->src[i] + (h-y+block-1) * stride, stride);
+ }
+
+ p->frame->linesize[i] = stride;
+ memset(p->temp[i], 0, (h + 2 * block) * stride * sizeof(int16_t));
+ }
+
+ if (p->qp)
+ p->frame->quality = p->qp * FF_QP2LAMBDA;
+ else {
+ int qpsum=0;
+ int qpcount = (height>>4) * (height>>4);
+
+ for (y = 0; y < (height>>4); y++) {
+ for (x = 0; x < (width>>4); x++)
+ qpsum += qp_store[x + y * qp_stride];
+ }
+ p->frame->quality = ff_norm_qscale((qpsum + qpcount/2) / qpcount, p->qscale_type) * FF_QP2LAMBDA;
+ }
+// init per MB qscale stuff FIXME
+ p->frame->height = height;
+ p->frame->width = width;
+
+ for (i = 0; i < count; i++) {
+ const int x1 = offset[i+count-1][0];
+ const int y1 = offset[i+count-1][1];
+ const int x1c = x1 >> p->hsub;
+ const int y1c = y1 >> p->vsub;
+ const int BLOCKc = BLOCK >> p->hsub;
+ int offset;
+ AVPacket pkt = {0};
+ int got_pkt_ptr;
+
+ av_init_packet(&pkt);
+ pkt.data = p->outbuf;
+ pkt.size = p->outbuf_size;
+
+ p->frame->data[0] = p->src[0] + x1 + y1 * p->frame->linesize[0];
+ p->frame->data[1] = p->src[1] + x1c + y1c * p->frame->linesize[1];
+ p->frame->data[2] = p->src[2] + x1c + y1c * p->frame->linesize[2];
+ p->frame->format = p->avctx_enc[i]->pix_fmt;
+
+ avcodec_encode_video2(p->avctx_enc[i], &pkt, p->frame, &got_pkt_ptr);
+ p->frame_dec = p->avctx_enc[i]->coded_frame;
+
+ offset = (BLOCK-x1) + (BLOCK-y1) * p->frame_dec->linesize[0];
+
+ for (y = 0; y < height; y++)
+ for (x = 0; x < width; x++)
+ p->temp[0][x + y * p->temp_stride[0]] += p->frame_dec->data[0][x + y * p->frame_dec->linesize[0] + offset];
+
+ if (!src[2] || !dst[2])
+ continue;
+
+ offset = (BLOCKc-x1c) + (BLOCKc-y1c) * p->frame_dec->linesize[1];
+
+ for (y = 0; y < FF_CEIL_RSHIFT(height, p->vsub); y++) {
+ for (x = 0; x < FF_CEIL_RSHIFT(width, p->hsub); x++) {
+ p->temp[1][x + y * p->temp_stride[1]] += p->frame_dec->data[1][x + y * p->frame_dec->linesize[1] + offset];
+ p->temp[2][x + y * p->temp_stride[2]] += p->frame_dec->data[2][x + y * p->frame_dec->linesize[2] + offset];
+ }
+ }
+ }
+
+ for (j = 0; j < 3; j++) {
+ int is_chroma = !!j;
+ if (!dst[j])
+ continue;
+ store_slice_c(dst[j], p->temp[j], dst_stride[j], p->temp_stride[j],
+ FF_CEIL_RSHIFT(width, is_chroma ? p->hsub : 0),
+ FF_CEIL_RSHIFT(height, is_chroma ? p->vsub : 0),
+ 8-p->log2_count);
+ }
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV420P,
+ AV_PIX_FMT_YUV410P,
+ AV_PIX_FMT_YUVJ444P,
+ AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+
+ AVFilterContext *ctx = inlink->dst;
+ USPPContext *uspp = ctx->priv;
+ const int height = inlink->h;
+ const int width = inlink->w;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int i;
+
+ AVCodec *enc = avcodec_find_encoder(AV_CODEC_ID_SNOW);
+ if (!enc) {
+ av_log(ctx, AV_LOG_ERROR, "SNOW encoder not found.\n");
+ return AVERROR(EINVAL);
+ }
+
+ uspp->hsub = desc->log2_chroma_w;
+ uspp->vsub = desc->log2_chroma_h;
+
+ for (i = 0; i < 3; i++) {
+ int is_chroma = !!i;
+ int w = (width + 4 * BLOCK-1) & (~(2 * BLOCK-1));
+ int h = (height + 4 * BLOCK-1) & (~(2 * BLOCK-1));
+
+ if (is_chroma) {
+ w = FF_CEIL_RSHIFT(w, uspp->hsub);
+ h = FF_CEIL_RSHIFT(h, uspp->vsub);
+ }
+
+ uspp->temp_stride[i] = w;
+ if (!(uspp->temp[i] = av_malloc_array(uspp->temp_stride[i], h * sizeof(int16_t))))
+ return AVERROR(ENOMEM);
+ if (!(uspp->src [i] = av_malloc_array(uspp->temp_stride[i], h * sizeof(uint8_t))))
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < (1<<uspp->log2_count); i++) {
+ AVCodecContext *avctx_enc;
+ AVDictionary *opts = NULL;
+ int ret;
+
+ if (!(uspp->avctx_enc[i] = avcodec_alloc_context3(NULL)))
+ return AVERROR(ENOMEM);
+
+ avctx_enc = uspp->avctx_enc[i];
+ avctx_enc->width = width + BLOCK;
+ avctx_enc->height = height + BLOCK;
+ avctx_enc->time_base = (AVRational){1,25}; // meaningless
+ avctx_enc->gop_size = INT_MAX;
+ avctx_enc->max_b_frames = 0;
+ avctx_enc->pix_fmt = inlink->format;
+ avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY;
+ avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+ avctx_enc->global_quality = 123;
+ av_dict_set(&opts, "no_bitstream", "1", 0);
+ ret = avcodec_open2(avctx_enc, enc, &opts);
+ if (ret < 0)
+ return ret;
+ av_dict_free(&opts);
+ av_assert0(avctx_enc->codec);
+ }
+
+ uspp->outbuf_size = (width + BLOCK) * (height + BLOCK) * 10;
+ if (!(uspp->frame = av_frame_alloc()))
+ return AVERROR(ENOMEM);
+ if (!(uspp->outbuf = av_malloc(uspp->outbuf_size)))
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ USPPContext *uspp = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out = in;
+
+ int qp_stride = 0;
+ uint8_t *qp_table = NULL;
+
+ /* if we are not in a constant user quantizer mode and we don't want to use
+ * the quantizers from the B-frames (B-frames often have a higher QP), we
+ * need to save the qp table from the last non B-frame; this is what the
+ * following code block does */
+ if (!uspp->qp) {
+ qp_table = av_frame_get_qp_table(in, &qp_stride, &uspp->qscale_type);
+
+ if (qp_table && !uspp->use_bframe_qp && in->pict_type != AV_PICTURE_TYPE_B) {
+ int w, h;
+
+ /* if the qp stride is not set, it means the QP are only defined on
+ * a line basis */
+ if (!qp_stride) {
+ w = FF_CEIL_RSHIFT(inlink->w, 4);
+ h = 1;
+ } else {
+ w = qp_stride;
+ h = FF_CEIL_RSHIFT(inlink->h, 4);
+ }
+
+ if (w * h > uspp->non_b_qp_alloc_size) {
+ int ret = av_reallocp_array(&uspp->non_b_qp_table, w, h);
+ if (ret < 0) {
+ uspp->non_b_qp_alloc_size = 0;
+ return ret;
+ }
+ uspp->non_b_qp_alloc_size = w * h;
+ }
+
+ av_assert0(w * h <= uspp->non_b_qp_alloc_size);
+ memcpy(uspp->non_b_qp_table, qp_table, w * h);
+ }
+ }
+
+ if (uspp->log2_count && !ctx->is_disabled) {
+ if (!uspp->use_bframe_qp && uspp->non_b_qp_table)
+ qp_table = uspp->non_b_qp_table;
+
+ if (qp_table || uspp->qp) {
+
+ /* get a new frame if in-place is not possible or if the dimensions
+ * are not multiple of 8 */
+ if (!av_frame_is_writable(in) || (inlink->w & 7) || (inlink->h & 7)) {
+ const int aligned_w = FFALIGN(inlink->w, 8);
+ const int aligned_h = FFALIGN(inlink->h, 8);
+
+ out = ff_get_video_buffer(outlink, aligned_w, aligned_h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ out->width = in->width;
+ out->height = in->height;
+ }
+
+ filter(uspp, out->data, in->data, out->linesize, in->linesize,
+ inlink->w, inlink->h, qp_table, qp_stride);
+ }
+ }
+
+ if (in != out) {
+ if (in->data[3])
+ av_image_copy_plane(out->data[3], out->linesize[3],
+ in ->data[3], in ->linesize[3],
+ inlink->w, inlink->h);
+ av_frame_free(&in);
+ }
+ return ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ USPPContext *uspp = ctx->priv;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ av_freep(&uspp->temp[i]);
+ av_freep(&uspp->src[i]);
+ }
+
+ for (i = 0; i < (1 << uspp->log2_count); i++) {
+ avcodec_close(uspp->avctx_enc[i]);
+ av_freep(&uspp->avctx_enc[i]);
+ }
+
+ av_freep(&uspp->non_b_qp_table);
+ av_freep(&uspp->outbuf);
+ av_frame_free(&uspp->frame);
+}
+
+static const AVFilterPad uspp_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad uspp_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_uspp = {
+ .name = "uspp",
+ .description = NULL_IF_CONFIG_SMALL("Apply Ultra Simple / Slow Post-processing filter."),
+ .priv_size = sizeof(USPPContext),
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = uspp_inputs,
+ .outputs = uspp_outputs,
+ .priv_class = &uspp_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index fa54985722..4a4ae0e5e1 100644
--- a/libavfilter/vf_vflip.c
+++ b/libavfilter/vf_vflip.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Bobby Bingham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,9 +55,10 @@ static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
for (i = 0; i < 4; i ++) {
int vsub = i == 1 || i == 2 ? flip->vsub : 0;
+ int height = FF_CEIL_RSHIFT(h, vsub);
if (frame->data[i]) {
- frame->data[i] += ((h >> vsub) - 1) * frame->linesize[i];
+ frame->data[i] += (height - 1) * frame->linesize[i];
frame->linesize[i] = -frame->linesize[i];
}
}
@@ -72,9 +73,10 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
for (i = 0; i < 4; i ++) {
int vsub = i == 1 || i == 2 ? flip->vsub : 0;
+ int height = FF_CEIL_RSHIFT(link->h, vsub);
if (frame->data[i]) {
- frame->data[i] += ((link->h >> vsub)-1) * frame->linesize[i];
+ frame->data[i] += (height - 1) * frame->linesize[i];
frame->linesize[i] = -frame->linesize[i];
}
}
@@ -101,11 +103,9 @@ static const AVFilterPad avfilter_vf_vflip_outputs[] = {
};
AVFilter ff_vf_vflip = {
- .name = "vflip",
+ .name = "vflip",
.description = NULL_IF_CONFIG_SMALL("Flip the input video vertically."),
-
- .priv_size = sizeof(FlipContext),
-
- .inputs = avfilter_vf_vflip_inputs,
- .outputs = avfilter_vf_vflip_outputs,
+ .priv_size = sizeof(FlipContext),
+ .inputs = avfilter_vf_vflip_inputs,
+ .outputs = avfilter_vf_vflip_outputs,
};
diff --git a/libavfilter/vf_vidstabdetect.c b/libavfilter/vf_vidstabdetect.c
new file mode 100644
index 0000000000..d8f70f985e
--- /dev/null
+++ b/libavfilter/vf_vidstabdetect.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2013 Georg Martius <georg dot martius at web dot de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 DEFAULT_RESULT_NAME "transforms.trf"
+
+#include <vid.stab/libvidstab.h>
+
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#include "vidstabutils.h"
+
+typedef struct {
+ const AVClass *class;
+
+ VSMotionDetect md;
+ VSMotionDetectConfig conf;
+
+ char *result;
+ FILE *f;
+} StabData;
+
+
+#define OFFSET(x) offsetof(StabData, x)
+#define OFFSETC(x) (offsetof(StabData, conf)+offsetof(VSMotionDetectConfig, x))
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption vidstabdetect_options[] = {
+ {"result", "path to the file used to write the transforms", OFFSET(result), AV_OPT_TYPE_STRING, {.str = DEFAULT_RESULT_NAME}, .flags = FLAGS},
+ {"shakiness", "how shaky is the video and how quick is the camera?"
+ " 1: little (fast) 10: very strong/quick (slow)", OFFSETC(shakiness), AV_OPT_TYPE_INT, {.i64 = 5}, 1, 10, FLAGS},
+ {"accuracy", "(>=shakiness) 1: low 15: high (slow)", OFFSETC(accuracy), AV_OPT_TYPE_INT, {.i64 = 15}, 1, 15, FLAGS},
+ {"stepsize", "region around minimum is scanned with 1 pixel resolution", OFFSETC(stepSize), AV_OPT_TYPE_INT, {.i64 = 6}, 1, 32, FLAGS},
+ {"mincontrast", "below this contrast a field is discarded (0-1)", OFFSETC(contrastThreshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.25}, 0.0, 1.0, FLAGS},
+ {"show", "0: draw nothing; 1,2: show fields and transforms", OFFSETC(show), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, FLAGS},
+ {"tripod", "virtual tripod mode (if >0): motion is compared to a reference"
+ " reference frame (frame # is the value)", OFFSETC(virtualTripod), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(vidstabdetect);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ StabData *sd = ctx->priv;
+ ff_vs_init();
+ sd->class = &vidstabdetect_class;
+ av_log(ctx, AV_LOG_VERBOSE, "vidstabdetect filter: init %s\n", LIBVIDSTAB_VERSION);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ StabData *sd = ctx->priv;
+ VSMotionDetect *md = &(sd->md);
+
+ if (sd->f) {
+ fclose(sd->f);
+ sd->f = NULL;
+ }
+
+ vsMotionDetectionCleanup(md);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ // If you add something here also add it in vidstabutils.c
+ 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_YUVA420P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ StabData *sd = ctx->priv;
+
+ VSMotionDetect* md = &(sd->md);
+ VSFrameInfo fi;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ vsFrameInfoInit(&fi, inlink->w, inlink->h,
+ ff_av2vs_pixfmt(ctx, inlink->format));
+ if (fi.bytesPerPixel != av_get_bits_per_pixel(desc)/8) {
+ av_log(ctx, AV_LOG_ERROR, "pixel-format error: wrong bits/per/pixel, please report a BUG");
+ return AVERROR(EINVAL);
+ }
+ if (fi.log2ChromaW != desc->log2_chroma_w) {
+ av_log(ctx, AV_LOG_ERROR, "pixel-format error: log2_chroma_w, please report a BUG");
+ return AVERROR(EINVAL);
+ }
+
+ if (fi.log2ChromaH != desc->log2_chroma_h) {
+ av_log(ctx, AV_LOG_ERROR, "pixel-format error: log2_chroma_h, please report a BUG");
+ return AVERROR(EINVAL);
+ }
+
+ // set values that are not initialized by the options
+ sd->conf.algo = 1;
+ sd->conf.modName = "vidstabdetect";
+ if (vsMotionDetectInit(md, &sd->conf, &fi) != VS_OK) {
+ av_log(ctx, AV_LOG_ERROR, "initialization of Motion Detection failed, please report a BUG");
+ return AVERROR(EINVAL);
+ }
+
+ vsMotionDetectGetConfig(&sd->conf, md);
+ av_log(ctx, AV_LOG_INFO, "Video stabilization settings (pass 1/2):\n");
+ av_log(ctx, AV_LOG_INFO, " shakiness = %d\n", sd->conf.shakiness);
+ av_log(ctx, AV_LOG_INFO, " accuracy = %d\n", sd->conf.accuracy);
+ av_log(ctx, AV_LOG_INFO, " stepsize = %d\n", sd->conf.stepSize);
+ av_log(ctx, AV_LOG_INFO, " mincontrast = %f\n", sd->conf.contrastThreshold);
+ av_log(ctx, AV_LOG_INFO, " tripod = %d\n", sd->conf.virtualTripod);
+ av_log(ctx, AV_LOG_INFO, " show = %d\n", sd->conf.show);
+ av_log(ctx, AV_LOG_INFO, " result = %s\n", sd->result);
+
+ sd->f = fopen(sd->result, "w");
+ if (sd->f == NULL) {
+ av_log(ctx, AV_LOG_ERROR, "cannot open transform file %s\n", sd->result);
+ return AVERROR(EINVAL);
+ } else {
+ if (vsPrepareFile(md, sd->f) != VS_OK) {
+ av_log(ctx, AV_LOG_ERROR, "cannot write to transform file %s\n", sd->result);
+ return AVERROR(EINVAL);
+ }
+ }
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ StabData *sd = ctx->priv;
+ VSMotionDetect *md = &(sd->md);
+ LocalMotions localmotions;
+
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ VSFrame frame;
+ int plane;
+
+ if (sd->conf.show > 0 && !av_frame_is_writable(in))
+ av_frame_make_writable(in);
+
+ for (plane = 0; plane < md->fi.planes; plane++) {
+ frame.data[plane] = in->data[plane];
+ frame.linesize[plane] = in->linesize[plane];
+ }
+ if (vsMotionDetection(md, &localmotions, &frame) != VS_OK) {
+ av_log(ctx, AV_LOG_ERROR, "motion detection failed");
+ return AVERROR(AVERROR_EXTERNAL);
+ } else {
+ if (vsWriteToFile(md, sd->f, &localmotions) != VS_OK) {
+ int ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "cannot write to transform file");
+ return ret;
+ }
+ vs_vector_del(&localmotions);
+ }
+
+ return ff_filter_frame(outlink, in);
+}
+
+static const AVFilterPad avfilter_vf_vidstabdetect_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_vf_vidstabdetect_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_vidstabdetect = {
+ .name = "vidstabdetect",
+ .description = NULL_IF_CONFIG_SMALL("Extract relative transformations, "
+ "pass 1 of 2 for stabilization "
+ "(see vidstabtransform for pass 2)."),
+ .priv_size = sizeof(StabData),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = avfilter_vf_vidstabdetect_inputs,
+ .outputs = avfilter_vf_vidstabdetect_outputs,
+ .priv_class = &vidstabdetect_class,
+};
diff --git a/libavfilter/vf_vidstabtransform.c b/libavfilter/vf_vidstabtransform.c
new file mode 100644
index 0000000000..97e6661d37
--- /dev/null
+++ b/libavfilter/vf_vidstabtransform.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2013 Georg Martius <georg dot martius at web dot de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 DEFAULT_INPUT_NAME "transforms.trf"
+
+#include <vid.stab/libvidstab.h>
+
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
+#include "avfilter.h"
+#include "internal.h"
+
+#include "vidstabutils.h"
+
+typedef struct {
+ const AVClass *class;
+
+ VSTransformData td;
+ VSTransformConfig conf;
+
+ VSTransformations trans; // transformations
+ char *input; // name of transform file
+ int tripod;
+ int debug;
+} TransformContext;
+
+#define OFFSET(x) offsetof(TransformContext, x)
+#define OFFSETC(x) (offsetof(TransformContext, conf)+offsetof(VSTransformConfig, x))
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption vidstabtransform_options[] = {
+ {"input", "set path to the file storing the transforms", OFFSET(input),
+ AV_OPT_TYPE_STRING, {.str = DEFAULT_INPUT_NAME}, .flags = FLAGS },
+ {"smoothing", "set number of frames*2 + 1 used for lowpass filtering", OFFSETC(smoothing),
+ AV_OPT_TYPE_INT, {.i64 = 15}, 0, 1000, FLAGS},
+
+ {"optalgo", "set camera path optimization algo", OFFSETC(camPathAlgo),
+ AV_OPT_TYPE_INT, {.i64 = VSOptimalL1}, VSOptimalL1, VSAvg, FLAGS, "optalgo"},
+ { "opt", "global optimization", 0, // from version 1.0 on
+ AV_OPT_TYPE_CONST, {.i64 = VSOptimalL1 }, 0, 0, FLAGS, "optalgo"},
+ { "gauss", "gaussian kernel", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VSGaussian }, 0, 0, FLAGS, "optalgo"},
+ { "avg", "simple averaging on motion", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VSAvg }, 0, 0, FLAGS, "optalgo"},
+
+ {"maxshift", "set maximal number of pixels to translate image", OFFSETC(maxShift),
+ AV_OPT_TYPE_INT, {.i64 = -1}, -1, 500, FLAGS},
+ {"maxangle", "set maximal angle in rad to rotate image", OFFSETC(maxAngle),
+ AV_OPT_TYPE_DOUBLE, {.dbl = -1.0}, -1.0, 3.14, FLAGS},
+
+ {"crop", "set cropping mode", OFFSETC(crop),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS, "crop"},
+ { "keep", "keep border", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VSKeepBorder }, 0, 0, FLAGS, "crop"},
+ { "black", "black border", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VSCropBorder }, 0, 0, FLAGS, "crop"},
+
+ {"invert", "invert transforms", OFFSETC(invert),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS},
+ {"relative", "consider transforms as relative", OFFSETC(relative),
+ AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, FLAGS},
+ {"zoom", "set percentage to zoom (>0: zoom in, <0: zoom out", OFFSETC(zoom),
+ AV_OPT_TYPE_DOUBLE, {.dbl = 0}, -100, 100, FLAGS},
+ {"optzoom", "set optimal zoom (0: nothing, 1: optimal static zoom, 2: optimal dynamic zoom)", OFFSETC(optZoom),
+ AV_OPT_TYPE_INT, {.i64 = 1}, 0, 2, FLAGS},
+ {"zoomspeed", "for adative zoom: percent to zoom maximally each frame", OFFSETC(zoomSpeed),
+ AV_OPT_TYPE_DOUBLE, {.dbl = 0.25}, 0, 5, FLAGS},
+
+ {"interpol", "set type of interpolation", OFFSETC(interpolType),
+ AV_OPT_TYPE_INT, {.i64 = 2}, 0, 3, FLAGS, "interpol"},
+ { "no", "no interpolation", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VS_Zero }, 0, 0, FLAGS, "interpol"},
+ { "linear", "linear (horizontal)", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VS_Linear }, 0, 0, FLAGS, "interpol"},
+ { "bilinear","bi-linear", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VS_BiLinear},0, 0, FLAGS, "interpol"},
+ { "bicubic", "bi-cubic", 0,
+ AV_OPT_TYPE_CONST, {.i64 = VS_BiCubic },0, 0, FLAGS, "interpol"},
+
+ {"tripod", "enable virtual tripod mode (same as relative=0:smoothing=0)", OFFSET(tripod),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS},
+ {"debug", "enable debug mode and writer global motions information to file", OFFSET(debug),
+ AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS},
+ {NULL}
+};
+
+AVFILTER_DEFINE_CLASS(vidstabtransform);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ TransformContext *tc = ctx->priv;
+ ff_vs_init();
+ tc->class = &vidstabtransform_class;
+ av_log(ctx, AV_LOG_VERBOSE, "vidstabtransform filter: init %s\n", LIBVIDSTAB_VERSION);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ TransformContext *tc = ctx->priv;
+
+ vsTransformDataCleanup(&tc->td);
+ vsTransformationsCleanup(&tc->trans);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ // If you add something here also add it in vidstabutils.c
+ 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_YUVA420P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, AV_PIX_FMT_RGBA,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+
+static int config_input(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->dst;
+ TransformContext *tc = ctx->priv;
+ FILE *f;
+
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+
+ VSTransformData *td = &(tc->td);
+
+ VSFrameInfo fi_src;
+ VSFrameInfo fi_dest;
+
+ if (!vsFrameInfoInit(&fi_src, inlink->w, inlink->h,
+ ff_av2vs_pixfmt(ctx, inlink->format)) ||
+ !vsFrameInfoInit(&fi_dest, inlink->w, inlink->h,
+ ff_av2vs_pixfmt(ctx, inlink->format))) {
+ av_log(ctx, AV_LOG_ERROR, "unknown pixel format: %i (%s)",
+ inlink->format, desc->name);
+ return AVERROR(EINVAL);
+ }
+
+ if (fi_src.bytesPerPixel != av_get_bits_per_pixel(desc)/8 ||
+ fi_src.log2ChromaW != desc->log2_chroma_w ||
+ fi_src.log2ChromaH != desc->log2_chroma_h) {
+ av_log(ctx, AV_LOG_ERROR, "pixel-format error: bpp %i<>%i ",
+ fi_src.bytesPerPixel, av_get_bits_per_pixel(desc)/8);
+ av_log(ctx, AV_LOG_ERROR, "chroma_subsampl: w: %i<>%i h: %i<>%i\n",
+ fi_src.log2ChromaW, desc->log2_chroma_w,
+ fi_src.log2ChromaH, desc->log2_chroma_h);
+ return AVERROR(EINVAL);
+ }
+
+ // set values that are not initializes by the options
+ tc->conf.modName = "vidstabtransform";
+ tc->conf.verbose = 1 + tc->debug;
+ if (tc->tripod) {
+ av_log(ctx, AV_LOG_INFO, "Virtual tripod mode: relative=0, smoothing=0\n");
+ tc->conf.relative = 0;
+ tc->conf.smoothing = 0;
+ }
+ tc->conf.simpleMotionCalculation = 0;
+ tc->conf.storeTransforms = tc->debug;
+ tc->conf.smoothZoom = 0;
+
+ if (vsTransformDataInit(td, &tc->conf, &fi_src, &fi_dest) != VS_OK) {
+ av_log(ctx, AV_LOG_ERROR, "initialization of vid.stab transform failed, please report a BUG\n");
+ return AVERROR(EINVAL);
+ }
+
+ vsTransformGetConfig(&tc->conf, td);
+ av_log(ctx, AV_LOG_INFO, "Video transformation/stabilization settings (pass 2/2):\n");
+ av_log(ctx, AV_LOG_INFO, " input = %s\n", tc->input);
+ av_log(ctx, AV_LOG_INFO, " smoothing = %d\n", tc->conf.smoothing);
+ av_log(ctx, AV_LOG_INFO, " optalgo = %s\n",
+ tc->conf.camPathAlgo == VSOptimalL1 ? "opt" :
+ (tc->conf.camPathAlgo == VSGaussian ? "gauss" : "avg"));
+ av_log(ctx, AV_LOG_INFO, " maxshift = %d\n", tc->conf.maxShift);
+ av_log(ctx, AV_LOG_INFO, " maxangle = %f\n", tc->conf.maxAngle);
+ av_log(ctx, AV_LOG_INFO, " crop = %s\n", tc->conf.crop ? "Black" : "Keep");
+ av_log(ctx, AV_LOG_INFO, " relative = %s\n", tc->conf.relative ? "True": "False");
+ av_log(ctx, AV_LOG_INFO, " invert = %s\n", tc->conf.invert ? "True" : "False");
+ av_log(ctx, AV_LOG_INFO, " zoom = %f\n", tc->conf.zoom);
+ av_log(ctx, AV_LOG_INFO, " optzoom = %s\n",
+ tc->conf.optZoom == 1 ? "Static (1)" : (tc->conf.optZoom == 2 ? "Dynamic (2)" : "Off (0)"));
+ if (tc->conf.optZoom == 2)
+ av_log(ctx, AV_LOG_INFO, " zoomspeed = %g\n", tc->conf.zoomSpeed);
+ av_log(ctx, AV_LOG_INFO, " interpol = %s\n", getInterpolationTypeName(tc->conf.interpolType));
+
+ f = fopen(tc->input, "r");
+ if (!f) {
+ int ret = AVERROR(errno);
+ av_log(ctx, AV_LOG_ERROR, "cannot open input file %s\n", tc->input);
+ return ret;
+ } else {
+ VSManyLocalMotions mlms;
+ if (vsReadLocalMotionsFile(f, &mlms) == VS_OK) {
+ // calculate the actual transforms from the local motions
+ if (vsLocalmotions2Transforms(td, &mlms, &tc->trans) != VS_OK) {
+ av_log(ctx, AV_LOG_ERROR, "calculating transformations failed\n");
+ return AVERROR(EINVAL);
+ }
+ } else { // try to read old format
+ if (!vsReadOldTransforms(td, f, &tc->trans)) { /* read input file */
+ av_log(ctx, AV_LOG_ERROR, "error parsing input file %s\n", tc->input);
+ return AVERROR(EINVAL);
+ }
+ }
+ }
+ fclose(f);
+
+ if (vsPreprocessTransforms(td, &tc->trans) != VS_OK) {
+ av_log(ctx, AV_LOG_ERROR, "error while preprocessing transforms\n");
+ return AVERROR(EINVAL);
+ }
+
+ // TODO: add sharpening, so far the user needs to call the unsharp filter manually
+ return 0;
+}
+
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ TransformContext *tc = ctx->priv;
+ VSTransformData* td = &(tc->td);
+
+ AVFilterLink *outlink = inlink->dst->outputs[0];
+ int direct = 0;
+ AVFrame *out;
+ VSFrame inframe;
+ int plane;
+
+ if (av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ for (plane = 0; plane < vsTransformGetSrcFrameInfo(td)->planes; plane++) {
+ inframe.data[plane] = in->data[plane];
+ inframe.linesize[plane] = in->linesize[plane];
+ }
+ if (direct) {
+ vsTransformPrepare(td, &inframe, &inframe);
+ } else { // separate frames
+ VSFrame outframe;
+ for (plane = 0; plane < vsTransformGetDestFrameInfo(td)->planes; plane++) {
+ outframe.data[plane] = out->data[plane];
+ outframe.linesize[plane] = out->linesize[plane];
+ }
+ vsTransformPrepare(td, &inframe, &outframe);
+ }
+
+ vsDoTransform(td, vsGetNextTransform(td, &tc->trans));
+
+ vsTransformFinish(td);
+
+ if (!direct)
+ av_frame_free(&in);
+
+ return ff_filter_frame(outlink, out);
+}
+
+static const AVFilterPad avfilter_vf_vidstabtransform_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad avfilter_vf_vidstabtransform_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_vidstabtransform = {
+ .name = "vidstabtransform",
+ .description = NULL_IF_CONFIG_SMALL("Transform the frames, "
+ "pass 2 of 2 for stabilization "
+ "(see vidstabdetect for pass 1)."),
+ .priv_size = sizeof(TransformContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = avfilter_vf_vidstabtransform_inputs,
+ .outputs = avfilter_vf_vidstabtransform_outputs,
+ .priv_class = &vidstabtransform_class,
+};
diff --git a/libavfilter/vf_vignette.c b/libavfilter/vf_vignette.c
new file mode 100644
index 0000000000..286104963e
--- /dev/null
+++ b/libavfilter/vf_vignette.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <float.h> /* DBL_MAX */
+
+#include "libavutil/opt.h"
+#include "libavutil/eval.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+static const char *const var_names[] = {
+ "w", // stream width
+ "h", // stream height
+ "n", // frame count
+ "pts", // presentation timestamp expressed in AV_TIME_BASE units
+ "r", // frame rate
+ "t", // timestamp expressed in seconds
+ "tb", // timebase
+ NULL
+};
+
+enum var_name {
+ VAR_W,
+ VAR_H,
+ VAR_N,
+ VAR_PTS,
+ VAR_R,
+ VAR_T,
+ VAR_TB,
+ VAR_NB
+};
+
+enum EvalMode {
+ EVAL_MODE_INIT,
+ EVAL_MODE_FRAME,
+ EVAL_MODE_NB
+};
+
+typedef struct {
+ const AVClass *class;
+ const AVPixFmtDescriptor *desc;
+ int backward;
+ int eval_mode; ///< EvalMode
+#define DEF_EXPR_FIELDS(name) AVExpr *name##_pexpr; char *name##_expr; double name
+ DEF_EXPR_FIELDS(angle);
+ DEF_EXPR_FIELDS(x0);
+ DEF_EXPR_FIELDS(y0);
+ double var_values[VAR_NB];
+ float *fmap;
+ int fmap_linesize;
+ double dmax;
+ float xscale, yscale;
+ uint32_t dither;
+ int do_dither;
+ AVRational aspect;
+ AVRational scale;
+} VignetteContext;
+
+#define OFFSET(x) offsetof(VignetteContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption vignette_options[] = {
+ { "angle", "set lens angle", OFFSET(angle_expr), AV_OPT_TYPE_STRING, {.str="PI/5"}, .flags = FLAGS },
+ { "a", "set lens angle", OFFSET(angle_expr), AV_OPT_TYPE_STRING, {.str="PI/5"}, .flags = FLAGS },
+ { "x0", "set circle center position on x-axis", OFFSET(x0_expr), AV_OPT_TYPE_STRING, {.str="w/2"}, .flags = FLAGS },
+ { "y0", "set circle center position on y-axis", OFFSET(y0_expr), AV_OPT_TYPE_STRING, {.str="h/2"}, .flags = FLAGS },
+ { "mode", "set forward/backward mode", OFFSET(backward), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS, "mode" },
+ { "forward", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ { "backward", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, FLAGS, "mode"},
+ { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
+ { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
+ { "frame", "eval expressions for each frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
+ { "dither", "set dithering", OFFSET(do_dither), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, FLAGS },
+ { "aspect", "set aspect ratio", OFFSET(aspect), AV_OPT_TYPE_RATIONAL, {.dbl = 1}, 0, DBL_MAX, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(vignette);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ VignetteContext *s = ctx->priv;
+
+#define PARSE_EXPR(name) do { \
+ int ret = av_expr_parse(&s->name##_pexpr, s->name##_expr, var_names, \
+ NULL, NULL, NULL, NULL, 0, ctx); \
+ if (ret < 0) { \
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse expression for '" \
+ AV_STRINGIFY(name) "'\n"); \
+ return ret; \
+ } \
+} while (0)
+
+ PARSE_EXPR(angle);
+ PARSE_EXPR(x0);
+ PARSE_EXPR(y0);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ VignetteContext *s = ctx->priv;
+ av_freep(&s->fmap);
+ av_expr_free(s->angle_pexpr);
+ av_expr_free(s->x0_pexpr);
+ av_expr_free(s->y0_pexpr);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static double get_natural_factor(const VignetteContext *s, int x, int y)
+{
+ const int xx = (x - s->x0) * s->xscale;
+ const int yy = (y - s->y0) * s->yscale;
+ const double dnorm = hypot(xx, yy) / s->dmax;
+ if (dnorm > 1) {
+ return 0;
+ } else {
+ const double c = cos(s->angle * dnorm);
+ return (c*c)*(c*c); // do not remove braces, it helps compilers
+ }
+}
+
+#define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
+#define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
+
+static void update_context(VignetteContext *s, AVFilterLink *inlink, AVFrame *frame)
+{
+ int x, y;
+ float *dst = s->fmap;
+ int dst_linesize = s->fmap_linesize;
+
+ if (frame) {
+ s->var_values[VAR_N] = inlink->frame_count;
+ s->var_values[VAR_T] = TS2T(frame->pts, inlink->time_base);
+ s->var_values[VAR_PTS] = TS2D(frame->pts);
+ } else {
+ s->var_values[VAR_N] = NAN;
+ s->var_values[VAR_T] = NAN;
+ s->var_values[VAR_PTS] = NAN;
+ }
+
+ s->angle = av_expr_eval(s->angle_pexpr, s->var_values, NULL);
+ s->x0 = av_expr_eval(s->x0_pexpr, s->var_values, NULL);
+ s->y0 = av_expr_eval(s->y0_pexpr, s->var_values, NULL);
+
+ if (isnan(s->x0) || isnan(s->y0) || isnan(s->angle))
+ s->eval_mode = EVAL_MODE_FRAME;
+
+ s->angle = av_clipf(s->angle, 0, M_PI_2);
+
+ if (s->backward) {
+ for (y = 0; y < inlink->h; y++) {
+ for (x = 0; x < inlink->w; x++)
+ dst[x] = 1. / get_natural_factor(s, x, y);
+ dst += dst_linesize;
+ }
+ } else {
+ for (y = 0; y < inlink->h; y++) {
+ for (x = 0; x < inlink->w; x++)
+ dst[x] = get_natural_factor(s, x, y);
+ dst += dst_linesize;
+ }
+ }
+}
+
+static inline double get_dither_value(VignetteContext *s)
+{
+ double dv = 0;
+ if (s->do_dither) {
+ dv = s->dither / (double)(1LL<<32);
+ s->dither = s->dither * 1664525 + 1013904223;
+ }
+ return dv;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ unsigned x, y, direct = 0;
+ AVFilterContext *ctx = inlink->dst;
+ VignetteContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out;
+
+ if (av_frame_is_writable(in)) {
+ direct = 1;
+ out = in;
+ } else {
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+ }
+
+ if (s->eval_mode == EVAL_MODE_FRAME)
+ update_context(s, inlink, in);
+
+ if (s->desc->flags & AV_PIX_FMT_FLAG_RGB) {
+ uint8_t *dst = out->data[0];
+ const uint8_t *src = in ->data[0];
+ const float *fmap = s->fmap;
+ const int dst_linesize = out->linesize[0];
+ const int src_linesize = in ->linesize[0];
+ const int fmap_linesize = s->fmap_linesize;
+
+ for (y = 0; y < inlink->h; y++) {
+ uint8_t *dstp = dst;
+ const uint8_t *srcp = src;
+
+ for (x = 0; x < inlink->w; x++, dstp += 3, srcp += 3) {
+ const float f = fmap[x];
+
+ dstp[0] = av_clip_uint8(srcp[0] * f + get_dither_value(s));
+ dstp[1] = av_clip_uint8(srcp[1] * f + get_dither_value(s));
+ dstp[2] = av_clip_uint8(srcp[2] * f + get_dither_value(s));
+ }
+ dst += dst_linesize;
+ src += src_linesize;
+ fmap += fmap_linesize;
+ }
+ } else {
+ int plane;
+
+ for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) {
+ uint8_t *dst = out->data[plane];
+ const uint8_t *src = in ->data[plane];
+ const float *fmap = s->fmap;
+ const int dst_linesize = out->linesize[plane];
+ const int src_linesize = in ->linesize[plane];
+ const int fmap_linesize = s->fmap_linesize;
+ const int chroma = plane == 1 || plane == 2;
+ const int hsub = chroma ? s->desc->log2_chroma_w : 0;
+ const int vsub = chroma ? s->desc->log2_chroma_h : 0;
+ const int w = FF_CEIL_RSHIFT(inlink->w, hsub);
+ const int h = FF_CEIL_RSHIFT(inlink->h, vsub);
+
+ for (y = 0; y < h; y++) {
+ uint8_t *dstp = dst;
+ const uint8_t *srcp = src;
+
+ for (x = 0; x < w; x++) {
+ const double dv = get_dither_value(s);
+ if (chroma) *dstp++ = av_clip_uint8(fmap[x << hsub] * (*srcp++ - 127) + 127 + dv);
+ else *dstp++ = av_clip_uint8(fmap[x ] * *srcp++ + dv);
+ }
+ dst += dst_linesize;
+ src += src_linesize;
+ fmap += fmap_linesize << vsub;
+ }
+ }
+ }
+
+ if (!direct)
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ VignetteContext *s = inlink->dst->priv;
+ 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);
+
+ if (!sar.num || !sar.den)
+ sar.num = sar.den = 1;
+ if (sar.num > sar.den) {
+ s->xscale = av_q2d(av_div_q(sar, s->aspect));
+ s->yscale = 1;
+ } else {
+ s->yscale = av_q2d(av_div_q(s->aspect, sar));
+ s->xscale = 1;
+ }
+ s->dmax = hypot(inlink->w / 2., inlink->h / 2.);
+ av_log(s, AV_LOG_DEBUG, "xscale=%f yscale=%f dmax=%f\n",
+ s->xscale, s->yscale, s->dmax);
+
+ s->fmap_linesize = FFALIGN(inlink->w, 32);
+ s->fmap = av_malloc_array(s->fmap_linesize, inlink->h * sizeof(*s->fmap));
+ if (!s->fmap)
+ return AVERROR(ENOMEM);
+
+ if (s->eval_mode == EVAL_MODE_INIT)
+ update_context(s, inlink, NULL);
+
+ return 0;
+}
+
+static const AVFilterPad vignette_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+static const AVFilterPad vignette_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_vignette = {
+ .name = "vignette",
+ .description = NULL_IF_CONFIG_SMALL("Make or reverse a vignette effect."),
+ .priv_size = sizeof(VignetteContext),
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = vignette_inputs,
+ .outputs = vignette_outputs,
+ .priv_class = &vignette_class,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/vf_w3fdif.c b/libavfilter/vf_w3fdif.c
new file mode 100644
index 0000000000..bb0316b3dc
--- /dev/null
+++ b/libavfilter/vf_w3fdif.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2012 British Broadcasting Corporation, All Rights Reserved
+ * Author of de-interlace algorithm: Jim Easterbrook for BBC R&D
+ * Based on the process described by Martin Weston for BBC R&D
+ * Author of FFmpeg filter: Mark Himsley for BBC Broadcast Systems Development
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+typedef struct W3FDIFContext {
+ const AVClass *class;
+ int filter; ///< 0 is simple, 1 is more complex
+ int deint; ///< which frames to deinterlace
+ int linesize[4]; ///< bytes of pixel data per line for each plane
+ int planeheight[4]; ///< height of each plane
+ int field; ///< which field are we on, 0 or 1
+ int eof;
+ int nb_planes;
+ AVFrame *prev, *cur, *next; ///< previous, current, next frames
+ int32_t *work_line; ///< line we are calculating
+} W3FDIFContext;
+
+#define OFFSET(x) offsetof(W3FDIFContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, 0, 0, FLAGS, unit }
+
+static const AVOption w3fdif_options[] = {
+ { "filter", "specify the filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "filter" },
+ CONST("simple", NULL, 0, "filter"),
+ CONST("complex", NULL, 1, "filter"),
+ { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "deint" },
+ CONST("all", "deinterlace all frames", 0, "deint"),
+ CONST("interlaced", "only deinterlace frames marked as interlaced", 1, "deint"),
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(w3fdif);
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
+ AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ W3FDIFContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
+ int ret;
+
+ if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
+ return ret;
+
+ s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
+ s->planeheight[0] = s->planeheight[3] = inlink->h;
+
+ s->nb_planes = av_pix_fmt_count_planes(inlink->format);
+ s->work_line = av_calloc(s->linesize[0], sizeof(*s->work_line));
+ if (!s->work_line)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterLink *inlink = outlink->src->inputs[0];
+
+ 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;
+ outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
+
+ return 0;
+}
+
+/*
+ * Filter coefficients from PH-2071, scaled by 256 * 256.
+ * Each set of coefficients has a set for low-frequencies and high-frequencies.
+ * n_coef_lf[] and n_coef_hf[] are the number of coefs for simple and more-complex.
+ * It is important for later that n_coef_lf[] is even and n_coef_hf[] is odd.
+ * coef_lf[][] and coef_hf[][] are the coefficients for low-frequencies
+ * and high-frequencies for simple and more-complex mode.
+ */
+static const int8_t n_coef_lf[2] = { 2, 4 };
+static const int32_t coef_lf[2][4] = {{ 32768, 32768, 0, 0},
+ { -1704, 34472, 34472, -1704}};
+static const int8_t n_coef_hf[2] = { 3, 5 };
+static const int32_t coef_hf[2][5] = {{ -4096, 8192, -4096, 0, 0},
+ { 2032, -7602, 11140, -7602, 2032}};
+
+static void deinterlace_plane(AVFilterContext *ctx, AVFrame *out,
+ const AVFrame *cur, const AVFrame *adj,
+ const int filter, const int plane)
+{
+ W3FDIFContext *s = ctx->priv;
+ uint8_t *in_line, *in_lines_cur[5], *in_lines_adj[5];
+ uint8_t *out_line, *out_pixel;
+ int32_t *work_line, *work_pixel;
+ uint8_t *cur_data = cur->data[plane];
+ uint8_t *adj_data = adj->data[plane];
+ uint8_t *dst_data = out->data[plane];
+ const int linesize = s->linesize[plane];
+ const int height = s->planeheight[plane];
+ const int cur_line_stride = cur->linesize[plane];
+ const int adj_line_stride = adj->linesize[plane];
+ const int dst_line_stride = out->linesize[plane];
+ int i, j, y_in, y_out;
+
+ /* copy unchanged the lines of the field */
+ y_out = s->field == cur->top_field_first;
+
+ in_line = cur_data + (y_out * cur_line_stride);
+ out_line = dst_data + (y_out * dst_line_stride);
+
+ while (y_out < height) {
+ memcpy(out_line, in_line, linesize);
+ y_out += 2;
+ in_line += cur_line_stride * 2;
+ out_line += dst_line_stride * 2;
+ }
+
+ /* interpolate other lines of the field */
+ y_out = s->field != cur->top_field_first;
+
+ out_line = dst_data + (y_out * dst_line_stride);
+
+ while (y_out < height) {
+ /* clear workspace */
+ memset(s->work_line, 0, sizeof(*s->work_line) * linesize);
+
+ /* get low vertical frequencies from current field */
+ for (j = 0; j < n_coef_lf[filter]; j++) {
+ y_in = (y_out + 1) + (j * 2) - n_coef_lf[filter];
+
+ while (y_in < 0)
+ y_in += 2;
+ while (y_in >= height)
+ y_in -= 2;
+
+ in_lines_cur[j] = cur_data + (y_in * cur_line_stride);
+ }
+
+ work_line = s->work_line;
+ switch (n_coef_lf[filter]) {
+ case 2:
+ for (i = 0; i < linesize; i++) {
+ *work_line += *in_lines_cur[0]++ * coef_lf[filter][0];
+ *work_line++ += *in_lines_cur[1]++ * coef_lf[filter][1];
+ }
+ break;
+ case 4:
+ for (i = 0; i < linesize; i++) {
+ *work_line += *in_lines_cur[0]++ * coef_lf[filter][0];
+ *work_line += *in_lines_cur[1]++ * coef_lf[filter][1];
+ *work_line += *in_lines_cur[2]++ * coef_lf[filter][2];
+ *work_line++ += *in_lines_cur[3]++ * coef_lf[filter][3];
+ }
+ }
+
+ /* get high vertical frequencies from adjacent fields */
+ for (j = 0; j < n_coef_hf[filter]; j++) {
+ y_in = (y_out + 1) + (j * 2) - n_coef_hf[filter];
+
+ while (y_in < 0)
+ y_in += 2;
+ while (y_in >= height)
+ y_in -= 2;
+
+ in_lines_cur[j] = cur_data + (y_in * cur_line_stride);
+ in_lines_adj[j] = adj_data + (y_in * adj_line_stride);
+ }
+
+ work_line = s->work_line;
+ switch (n_coef_hf[filter]) {
+ case 3:
+ for (i = 0; i < linesize; i++) {
+ *work_line += *in_lines_cur[0]++ * coef_hf[filter][0];
+ *work_line += *in_lines_adj[0]++ * coef_hf[filter][0];
+ *work_line += *in_lines_cur[1]++ * coef_hf[filter][1];
+ *work_line += *in_lines_adj[1]++ * coef_hf[filter][1];
+ *work_line += *in_lines_cur[2]++ * coef_hf[filter][2];
+ *work_line++ += *in_lines_adj[2]++ * coef_hf[filter][2];
+ }
+ break;
+ case 5:
+ for (i = 0; i < linesize; i++) {
+ *work_line += *in_lines_cur[0]++ * coef_hf[filter][0];
+ *work_line += *in_lines_adj[0]++ * coef_hf[filter][0];
+ *work_line += *in_lines_cur[1]++ * coef_hf[filter][1];
+ *work_line += *in_lines_adj[1]++ * coef_hf[filter][1];
+ *work_line += *in_lines_cur[2]++ * coef_hf[filter][2];
+ *work_line += *in_lines_adj[2]++ * coef_hf[filter][2];
+ *work_line += *in_lines_cur[3]++ * coef_hf[filter][3];
+ *work_line += *in_lines_adj[3]++ * coef_hf[filter][3];
+ *work_line += *in_lines_cur[4]++ * coef_hf[filter][4];
+ *work_line++ += *in_lines_adj[4]++ * coef_hf[filter][4];
+ }
+ }
+
+ /* save scaled result to the output frame, scaling down by 256 * 256 */
+ work_pixel = s->work_line;
+ out_pixel = out_line;
+
+ for (j = 0; j < linesize; j++, out_pixel++, work_pixel++)
+ *out_pixel = av_clip(*work_pixel, 0, 255 * 256 * 256) >> 16;
+
+ /* move on to next line */
+ y_out += 2;
+ out_line += dst_line_stride * 2;
+ }
+}
+
+static int filter(AVFilterContext *ctx, int is_second)
+{
+ W3FDIFContext *s = ctx->priv;
+ AVFilterLink *outlink = ctx->outputs[0];
+ AVFrame *out, *adj;
+ int plane;
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out)
+ return AVERROR(ENOMEM);
+ av_frame_copy_props(out, s->cur);
+ out->interlaced_frame = 0;
+
+ if (!is_second) {
+ if (out->pts != AV_NOPTS_VALUE)
+ out->pts *= 2;
+ } else {
+ int64_t cur_pts = s->cur->pts;
+ int64_t next_pts = s->next->pts;
+
+ if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
+ out->pts = cur_pts + next_pts;
+ } else {
+ out->pts = AV_NOPTS_VALUE;
+ }
+ }
+
+ adj = s->field ? s->next : s->prev;
+ for (plane = 0; plane < s->nb_planes; plane++)
+ deinterlace_plane(ctx, out, s->cur, adj, s->filter, plane);
+
+ s->field = !s->field;
+
+ return ff_filter_frame(outlink, out);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
+{
+ AVFilterContext *ctx = inlink->dst;
+ W3FDIFContext *s = ctx->priv;
+ int ret;
+
+ av_frame_free(&s->prev);
+ s->prev = s->cur;
+ s->cur = s->next;
+ s->next = frame;
+
+ if (!s->cur) {
+ s->cur = av_frame_clone(s->next);
+ if (!s->cur)
+ return AVERROR(ENOMEM);
+ }
+
+ if ((s->deint && !s->cur->interlaced_frame) || ctx->is_disabled) {
+ AVFrame *out = av_frame_clone(s->cur);
+ if (!out)
+ return AVERROR(ENOMEM);
+
+ av_frame_free(&s->prev);
+ if (out->pts != AV_NOPTS_VALUE)
+ out->pts *= 2;
+ return ff_filter_frame(ctx->outputs[0], out);
+ }
+
+ if (!s->prev)
+ return 0;
+
+ ret = filter(ctx, 0);
+ if (ret < 0)
+ return ret;
+
+ return filter(ctx, 1);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ W3FDIFContext *s = ctx->priv;
+
+ do {
+ int ret;
+
+ if (s->eof)
+ return AVERROR_EOF;
+
+ ret = ff_request_frame(ctx->inputs[0]);
+
+ if (ret == AVERROR_EOF && s->cur) {
+ AVFrame *next = av_frame_clone(s->next);
+ if (!next)
+ return AVERROR(ENOMEM);
+ next->pts = s->next->pts * 2 - s->cur->pts;
+ filter_frame(ctx->inputs[0], next);
+ s->eof = 1;
+ } else if (ret < 0) {
+ return ret;
+ }
+ } while (!s->cur);
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ W3FDIFContext *s = ctx->priv;
+
+ av_frame_free(&s->prev);
+ av_frame_free(&s->cur );
+ av_frame_free(&s->next);
+ av_freep(&s->work_line);
+}
+
+static const AVFilterPad w3fdif_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ .config_props = config_input,
+ },
+ { NULL }
+};
+
+static const AVFilterPad w3fdif_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ .request_frame = request_frame,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_w3fdif = {
+ .name = "w3fdif",
+ .description = NULL_IF_CONFIG_SMALL("Apply Martin Weston three field deinterlace."),
+ .priv_size = sizeof(W3FDIFContext),
+ .priv_class = &w3fdif_class,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = w3fdif_inputs,
+ .outputs = w3fdif_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
+};
diff --git a/libavfilter/vf_xbr.c b/libavfilter/vf_xbr.c
new file mode 100644
index 0000000000..38c3b70673
--- /dev/null
+++ b/libavfilter/vf_xbr.c
@@ -0,0 +1,433 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * Copyright (c) 2011, 2012 Hyllian/Jararaca <sergiogdb@gmail.com>
+ * Copyright (c) 2014 Arwa Arif <arwaarif1994@gmail.com>
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * XBR Filter is used for depixelization of image.
+ * This is based on Hyllian's xBR shader.
+ *
+ * @see http://www.libretro.com/forums/viewtopic.php?f=6&t=134
+ * @see https://github.com/yoyofr/iFBA/blob/master/fba_src/src/intf/video/scalers/xbr.cpp
+ */
+
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
+#include "internal.h"
+
+#define LB_MASK 0x00FEFEFE
+#define RED_BLUE_MASK 0x00FF00FF
+#define GREEN_MASK 0x0000FF00
+
+typedef int (*xbrfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
+
+typedef struct {
+ const AVClass *class;
+ int n;
+ xbrfunc_t func;
+ uint32_t rgbtoyuv[1<<24];
+} XBRContext;
+
+typedef struct ThreadData {
+ AVFrame *in, *out;
+ const uint32_t *rgbtoyuv;
+} ThreadData;
+
+#define OFFSET(x) offsetof(XBRContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption xbr_options[] = {
+ { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 4, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(xbr);
+
+static uint32_t pixel_diff(uint32_t x, uint32_t y, const uint32_t *r2y)
+{
+#define YMASK 0xff0000
+#define UMASK 0x00ff00
+#define VMASK 0x0000ff
+
+ uint32_t yuv1 = r2y[x & 0xffffff];
+ uint32_t yuv2 = r2y[y & 0xffffff];
+
+ return (abs((yuv1 & YMASK) - (yuv2 & YMASK)) >> 16) +
+ (abs((yuv1 & UMASK) - (yuv2 & UMASK)) >> 8) +
+ abs((yuv1 & VMASK) - (yuv2 & VMASK));
+}
+
+#define ALPHA_BLEND_128_W(a, b) ((((a) & LB_MASK) >> 1) + (((b) & LB_MASK) >> 1))
+#define ALPHA_BLEND_BASE(a, b, m, s) ( (RED_BLUE_MASK & (((a) & RED_BLUE_MASK) + (((((b) & RED_BLUE_MASK) - ((a) & RED_BLUE_MASK)) * (m)) >> (s)))) \
+ | (GREEN_MASK & (((a) & GREEN_MASK) + (((((b) & GREEN_MASK) - ((a) & GREEN_MASK)) * (m)) >> (s)))))
+#define ALPHA_BLEND_32_W(a, b) ALPHA_BLEND_BASE(a, b, 1, 3)
+#define ALPHA_BLEND_64_W(a, b) ALPHA_BLEND_BASE(a, b, 1, 2)
+#define ALPHA_BLEND_192_W(a, b) ALPHA_BLEND_BASE(a, b, 3, 2)
+#define ALPHA_BLEND_224_W(a, b) ALPHA_BLEND_BASE(a, b, 7, 3)
+
+#define df(A, B) pixel_diff(A, B, r2y)
+#define eq(A, B) (df(A, B) < 155)
+
+#define FILT2(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, \
+ N0, N1, N2, N3) do { \
+ if (PE != PH && PE != PF) { \
+ const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2); \
+ const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2); \
+ if (e <= i) { \
+ const unsigned px = df(PE,PF) <= df(PE,PH) ? PF : PH; \
+ if (e < i && (!eq(PF,PB) && !eq(PH,PD) || eq(PE,PI) \
+ && (!eq(PF,I4) && !eq(PH,I5)) \
+ || eq(PE,PG) || eq(PE,PC))) { \
+ const unsigned ke = df(PF,PG); \
+ const unsigned ki = df(PH,PC); \
+ const int left = ke<<1 <= ki && PE != PG && PD != PG; \
+ const int up = ke >= ki<<1 && PE != PC && PB != PC; \
+ if (left && up) { \
+ E[N3] = ALPHA_BLEND_224_W(E[N3], px); \
+ E[N2] = ALPHA_BLEND_64_W( E[N2], px); \
+ E[N1] = E[N2]; \
+ } else if (left) { \
+ E[N3] = ALPHA_BLEND_192_W(E[N3], px); \
+ E[N2] = ALPHA_BLEND_64_W( E[N2], px); \
+ } else if (up) { \
+ E[N3] = ALPHA_BLEND_192_W(E[N3], px); \
+ E[N1] = ALPHA_BLEND_64_W( E[N1], px); \
+ } else { /* diagonal */ \
+ E[N3] = ALPHA_BLEND_128_W(E[N3], px); \
+ } \
+ } else { \
+ E[N3] = ALPHA_BLEND_128_W(E[N3], px); \
+ } \
+ } \
+ } \
+} while (0)
+
+#define FILT3(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, \
+ N0, N1, N2, N3, N4, N5, N6, N7, N8) do { \
+ if (PE != PH && PE != PF) { \
+ const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2); \
+ const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2); \
+ if (e <= i) { \
+ const unsigned px = df(PE,PF) <= df(PE,PH) ? PF : PH; \
+ if (e < i && (!eq(PF,PB) && !eq(PF,PC) || !eq(PH,PD) && !eq(PH,PG) || eq(PE,PI) \
+ && (!eq(PF,F4) && !eq(PF,I4) || !eq(PH,H5) && !eq(PH,I5)) \
+ || eq(PE,PG) || eq(PE,PC))) { \
+ const unsigned ke = df(PF,PG); \
+ const unsigned ki = df(PH,PC); \
+ const int left = ke<<1 <= ki && PE != PG && PD != PG; \
+ const int up = ke >= ki<<1 && PE != PC && PB != PC; \
+ if (left && up) { \
+ E[N7] = ALPHA_BLEND_192_W(E[N7], px); \
+ E[N6] = ALPHA_BLEND_64_W( E[N6], px); \
+ E[N5] = E[N7]; \
+ E[N2] = E[N6]; \
+ E[N8] = px; \
+ } else if (left) { \
+ E[N7] = ALPHA_BLEND_192_W(E[N7], px); \
+ E[N5] = ALPHA_BLEND_64_W( E[N5], px); \
+ E[N6] = ALPHA_BLEND_64_W( E[N6], px); \
+ E[N8] = px; \
+ } else if (up) { \
+ E[N5] = ALPHA_BLEND_192_W(E[N5], px); \
+ E[N7] = ALPHA_BLEND_64_W( E[N7], px); \
+ E[N2] = ALPHA_BLEND_64_W( E[N2], px); \
+ E[N8] = px; \
+ } else { /* diagonal */ \
+ E[N8] = ALPHA_BLEND_224_W(E[N8], px); \
+ E[N5] = ALPHA_BLEND_32_W( E[N5], px); \
+ E[N7] = ALPHA_BLEND_32_W( E[N7], px); \
+ } \
+ } else { \
+ E[N8] = ALPHA_BLEND_128_W(E[N8], px); \
+ } \
+ } \
+ } \
+} while (0)
+
+#define FILT4(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, \
+ N15, N14, N11, N3, N7, N10, N13, N12, N9, N6, N2, N1, N5, N8, N4, N0) do { \
+ if (PE != PH && PE != PF) { \
+ const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2); \
+ const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2); \
+ if (e <= i) { \
+ const unsigned px = df(PE,PF) <= df(PE,PH) ? PF : PH; \
+ if (e < i && (!eq(PF,PB) && !eq(PH,PD) || eq(PE,PI) \
+ && (!eq(PF,I4) && !eq(PH,I5)) \
+ || eq(PE,PG) || eq(PE,PC))) { \
+ const unsigned ke = df(PF,PG); \
+ const unsigned ki = df(PH,PC); \
+ const int left = ke<<1 <= ki && PE != PG && PD != PG; \
+ const int up = ke >= ki<<1 && PE != PC && PB != PC; \
+ if (left && up) { \
+ E[N13] = ALPHA_BLEND_192_W(E[N13], px); \
+ E[N12] = ALPHA_BLEND_64_W( E[N12], px); \
+ E[N15] = E[N14] = E[N11] = px; \
+ E[N10] = E[N3] = E[N12]; \
+ E[N7] = E[N13]; \
+ } else if (left) { \
+ E[N11] = ALPHA_BLEND_192_W(E[N11], px); \
+ E[N13] = ALPHA_BLEND_192_W(E[N13], px); \
+ E[N10] = ALPHA_BLEND_64_W( E[N10], px); \
+ E[N12] = ALPHA_BLEND_64_W( E[N12], px); \
+ E[N14] = px; \
+ E[N15] = px; \
+ } else if (up) { \
+ E[N14] = ALPHA_BLEND_192_W(E[N14], px); \
+ E[N7 ] = ALPHA_BLEND_192_W(E[N7 ], px); \
+ E[N10] = ALPHA_BLEND_64_W( E[N10], px); \
+ E[N3 ] = ALPHA_BLEND_64_W( E[N3 ], px); \
+ E[N11] = px; \
+ E[N15] = px; \
+ } else { /* diagonal */ \
+ E[N11] = ALPHA_BLEND_128_W(E[N11], px); \
+ E[N14] = ALPHA_BLEND_128_W(E[N14], px); \
+ E[N15] = px; \
+ } \
+ } else { \
+ E[N15] = ALPHA_BLEND_128_W(E[N15], px); \
+ } \
+ } \
+ } \
+} while (0)
+
+static av_always_inline void xbr_filter(const ThreadData *td, int jobnr, int nb_jobs, int n)
+{
+ int x, y;
+ const AVFrame *input = td->in;
+ AVFrame *output = td->out;
+ const uint32_t *r2y = td->rgbtoyuv;
+ const int slice_start = (input->height * jobnr ) / nb_jobs;
+ const int slice_end = (input->height * (jobnr+1)) / nb_jobs;
+ const int nl = output->linesize[0] >> 2;
+ const int nl1 = nl + nl;
+ const int nl2 = nl1 + nl;
+
+ for (y = slice_start; y < slice_end; y++) {
+
+ uint32_t *E = (uint32_t *)(output->data[0] + y * output->linesize[0] * n);
+ const uint32_t *sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8); /* center */
+ const uint32_t *sa1 = sa2 - (input->linesize[0]>>2); /* up x1 */
+ const uint32_t *sa0 = sa1 - (input->linesize[0]>>2); /* up x2 */
+ const uint32_t *sa3 = sa2 + (input->linesize[0]>>2); /* down x1 */
+ const uint32_t *sa4 = sa3 + (input->linesize[0]>>2); /* down x2 */
+
+ if (y <= 1) {
+ sa0 = sa1;
+ if (y == 0) {
+ sa0 = sa1 = sa2;
+ }
+ }
+
+ if (y >= input->height - 2) {
+ sa4 = sa3;
+ if (y == input->height - 1) {
+ sa4 = sa3 = sa2;
+ }
+ }
+
+ for (x = 0; x < input->width; x++) {
+ const uint32_t B1 = sa0[2];
+ const uint32_t PB = sa1[2];
+ const uint32_t PE = sa2[2];
+ const uint32_t PH = sa3[2];
+ const uint32_t H5 = sa4[2];
+
+ const int pprev = 2 - (x > 0);
+ const uint32_t A1 = sa0[pprev];
+ const uint32_t PA = sa1[pprev];
+ const uint32_t PD = sa2[pprev];
+ const uint32_t PG = sa3[pprev];
+ const uint32_t G5 = sa4[pprev];
+
+ const int pprev2 = pprev - (x > 1);
+ const uint32_t A0 = sa1[pprev2];
+ const uint32_t D0 = sa2[pprev2];
+ const uint32_t G0 = sa3[pprev2];
+
+ const int pnext = 3 - (x == input->width - 1);
+ const uint32_t C1 = sa0[pnext];
+ const uint32_t PC = sa1[pnext];
+ const uint32_t PF = sa2[pnext];
+ const uint32_t PI = sa3[pnext];
+ const uint32_t I5 = sa4[pnext];
+
+ const int pnext2 = pnext + 1 - (x >= input->width - 2);
+ const uint32_t C4 = sa1[pnext2];
+ const uint32_t F4 = sa2[pnext2];
+ const uint32_t I4 = sa3[pnext2];
+
+ if (n == 2) {
+ E[0] = E[1] = // 0, 1
+ E[nl] = E[nl + 1] = PE; // 2, 3
+
+ FILT2(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, nl, nl+1);
+ FILT2(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, nl, 0, nl+1, 1);
+ FILT2(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, nl+1, nl, 1, 0);
+ FILT2(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 1, nl+1, 0, nl);
+ } else if (n == 3) {
+ E[0] = E[1] = E[2] = // 0, 1, 2
+ E[nl] = E[nl+1] = E[nl+2] = // 3, 4, 5
+ E[nl1] = E[nl1+1] = E[nl1+2] = PE; // 6, 7, 8
+
+ FILT3(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, 2, nl, nl+1, nl+2, nl1, nl1+1, nl1+2);
+ FILT3(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, nl1, nl, 0, nl1+1, nl+1, 1, nl1+2, nl+2, 2);
+ FILT3(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, nl1+2, nl1+1, nl1, nl+2, nl+1, nl, 2, 1, 0);
+ FILT3(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 2, nl+2, nl1+2, 1, nl+1, nl1+1, 0, nl, nl1);
+ } else if (n == 4) {
+ E[0] = E[1] = E[2] = E[3] = // 0, 1, 2, 3
+ E[nl] = E[nl+1] = E[nl+2] = E[nl+3] = // 4, 5, 6, 7
+ E[nl1] = E[nl1+1] = E[nl1+2] = E[nl1+3] = // 8, 9, 10, 11
+ E[nl2] = E[nl2+1] = E[nl2+2] = E[nl2+3] = PE; // 12, 13, 14, 15
+
+ FILT4(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, nl2+3, nl2+2, nl1+3, 3, nl+3, nl1+2, nl2+1, nl2, nl1+1, nl+2, 2, 1, nl+1, nl1, nl, 0);
+ FILT4(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, 3, nl+3, 2, 0, 1, nl+2, nl1+3, nl2+3, nl1+2, nl+1, nl, nl1, nl1+1, nl2+2, nl2+1, nl2);
+ FILT4(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, 0, 1, nl, nl2, nl1, nl+1, 2, 3, nl+2, nl1+1, nl2+1, nl2+2, nl1+2, nl+3, nl1+3, nl2+3);
+ FILT4(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, nl2, nl1, nl2+1, nl2+3, nl2+2, nl1+1, nl, 0, nl+1, nl1+2, nl1+3, nl+3, nl+2, 1, 2, 3);
+ }
+
+ sa0 += 1;
+ sa1 += 1;
+ sa2 += 1;
+ sa3 += 1;
+ sa4 += 1;
+
+ E += n;
+ }
+ }
+}
+
+#define XBR_FUNC(size) \
+static int xbr##size##x(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
+{ \
+ xbr_filter(arg, jobnr, nb_jobs, size); \
+ return 0; \
+}
+
+XBR_FUNC(2)
+XBR_FUNC(3)
+XBR_FUNC(4)
+
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ XBRContext *xbr = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ outlink->w = inlink->w * xbr->n;
+ outlink->h = inlink->h * xbr->n;
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_0RGB32, AV_PIX_FMT_NONE,
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ XBRContext *xbr = ctx->priv;
+ ThreadData td;
+
+ AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+
+ av_frame_copy_props(out, in);
+
+ td.in = in;
+ td.out = out;
+ td.rgbtoyuv = xbr->rgbtoyuv;
+ ctx->internal->execute(ctx, xbr->func, &td, NULL, FFMIN(inlink->h, ctx->graph->nb_threads));
+
+ out->width = outlink->w;
+ out->height = outlink->h;
+
+ av_frame_free(&in);
+ return ff_filter_frame(outlink, out);
+}
+
+static int init(AVFilterContext *ctx)
+{
+ XBRContext *xbr = ctx->priv;
+ static const xbrfunc_t xbrfuncs[] = {xbr2x, xbr3x, xbr4x};
+
+ uint32_t c;
+ int bg, rg, g;
+
+ for (bg = -255; bg < 256; bg++) {
+ for (rg = -255; rg < 256; rg++) {
+ const uint32_t u = (uint32_t)((-169*rg + 500*bg)/1000) + 128;
+ const uint32_t v = (uint32_t)(( 500*rg - 81*bg)/1000) + 128;
+ int startg = FFMAX3(-bg, -rg, 0);
+ int endg = FFMIN3(255-bg, 255-rg, 255);
+ uint32_t y = (uint32_t)(( 299*rg + 1000*startg + 114*bg)/1000);
+ c = bg + (rg<<16) + 0x010101 * startg;
+ for (g = startg; g <= endg; g++) {
+ xbr->rgbtoyuv[c] = ((y++) << 16) + (u << 8) + v;
+ c+= 0x010101;
+ }
+ }
+ }
+
+ xbr->func = xbrfuncs[xbr->n - 2];
+ return 0;
+}
+
+static const AVFilterPad xbr_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad xbr_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_xbr = {
+ .name = "xbr",
+ .description = NULL_IF_CONFIG_SMALL("Scale the input using xBR algorithm."),
+ .inputs = xbr_inputs,
+ .outputs = xbr_outputs,
+ .query_formats = query_formats,
+ .priv_size = sizeof(XBRContext),
+ .priv_class = &xbr_class,
+ .init = init,
+ .flags = AVFILTER_FLAG_SLICE_THREADS,
+};
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index 53c567cb96..b32f38b57a 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -1,37 +1,34 @@
/*
- * Copyright (C) 2006-2010 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2006-2011 Michael Niedermayer <michaelni@gmx.at>
* 2010 James Darnley <james.darnley@gmail.com>
*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/cpu.h"
#include "libavutil/common.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/imgutils.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
#include "yadif.h"
-#undef NDEBUG
-#include <assert.h>
-
typedef struct ThreadData {
AVFrame *frame;
int plane;
@@ -69,7 +66,7 @@ typedef struct ThreadData {
CHECK( 1) CHECK( 2) }} }} \
}\
\
- if (mode < 2) { \
+ if (!(mode&2)) { \
int b = (prev2[2 * mrefs] + next2[2 * mrefs])>>1; \
int f = (prev2[2 * prefs] + next2[2 * prefs])>>1; \
int max = FFMAX3(d - e, d - c, FFMIN(b - c, f - e)); \
@@ -112,6 +109,7 @@ static void filter_line_c(void *dst1,
FILTER(0, w, 1)
}
+#define MAX_ALIGN 8
static void filter_edges(void *dst1, void *prev1, void *cur1, void *next1,
int w, int prefs, int mrefs, int parity, int mode)
{
@@ -127,13 +125,14 @@ static void filter_edges(void *dst1, void *prev1, void *cur1, void *next1,
* for is_not_edge should let the compiler ignore the whole branch. */
FILTER(0, 3, 0)
- dst = (uint8_t*)dst1 + w - 3;
- prev = (uint8_t*)prev1 + w - 3;
- cur = (uint8_t*)cur1 + w - 3;
- next = (uint8_t*)next1 + w - 3;
+ dst = (uint8_t*)dst1 + w - (MAX_ALIGN-1);
+ prev = (uint8_t*)prev1 + w - (MAX_ALIGN-1);
+ cur = (uint8_t*)cur1 + w - (MAX_ALIGN-1);
+ next = (uint8_t*)next1 + w - (MAX_ALIGN-1);
prev2 = (uint8_t*)(parity ? prev : cur);
next2 = (uint8_t*)(parity ? cur : next);
+ FILTER(w - (MAX_ALIGN-1), w - 3, 1)
FILTER(w - 3, w, 0)
}
@@ -171,13 +170,14 @@ static void filter_edges_16bit(void *dst1, void *prev1, void *cur1, void *next1,
FILTER(0, 3, 0)
- dst = (uint16_t*)dst1 + w - 3;
- prev = (uint16_t*)prev1 + w - 3;
- cur = (uint16_t*)cur1 + w - 3;
- next = (uint16_t*)next1 + w - 3;
+ dst = (uint16_t*)dst1 + w - (MAX_ALIGN/2-1);
+ prev = (uint16_t*)prev1 + w - (MAX_ALIGN/2-1);
+ cur = (uint16_t*)cur1 + w - (MAX_ALIGN/2-1);
+ next = (uint16_t*)next1 + w - (MAX_ALIGN/2-1);
prev2 = (uint16_t*)(parity ? prev : cur);
next2 = (uint16_t*)(parity ? cur : next);
+ FILTER(w - (MAX_ALIGN/2-1), w - 3, 1)
FILTER(w - 3, w, 0)
}
@@ -188,9 +188,8 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
int refs = s->cur->linesize[td->plane];
int df = (s->csp->comp[td->plane].depth_minus1 + 8) / 8;
int pix_3 = 3 * df;
- int slice_h = td->h / nb_jobs;
- int slice_start = jobnr * slice_h;
- int slice_end = (jobnr == nb_jobs - 1) ? td->h : (jobnr + 1) * slice_h;
+ int slice_start = (td->h * jobnr ) / nb_jobs;
+ int slice_end = (td->h * (jobnr+1)) / nb_jobs;
int y;
/* filtering reads 3 pixels to the left/right; to avoid invalid reads,
@@ -204,7 +203,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
uint8_t *dst = &td->frame->data[td->plane][y * td->frame->linesize[td->plane]];
int mode = y == 1 || y + 2 == td->h ? 2 : s->mode;
s->filter_line(dst + pix_3, prev + pix_3, cur + pix_3,
- next + pix_3, td->w - 6,
+ next + pix_3, td->w - (3 + MAX_ALIGN/df-1),
y + 1 < td->h ? refs : -refs,
y ? -refs : refs,
td->parity ^ td->tff, mode);
@@ -232,8 +231,8 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic,
int h = dstpic->height;
if (i == 1 || i == 2) {
- w >>= yadif->csp->log2_chroma_w;
- h >>= yadif->csp->log2_chroma_h;
+ w = FF_CEIL_RSHIFT(w, yadif->csp->log2_chroma_w);
+ h = FF_CEIL_RSHIFT(h, yadif->csp->log2_chroma_h);
}
@@ -247,24 +246,6 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic,
emms_c();
}
-static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
-{
- AVFrame *frame;
- int width = FFALIGN(w, 32);
- int height = FFALIGN(h + 2, 32);
- int i;
-
- frame = ff_default_get_video_buffer(link, width, height);
-
- frame->width = w;
- frame->height = h;
-
- for (i = 0; i < 3; i++)
- frame->data[i] += frame->linesize[i];
-
- return frame;
-}
-
static int return_frame(AVFilterContext *ctx, int is_second)
{
YADIFContext *yadif = ctx->priv;
@@ -305,11 +286,36 @@ static int return_frame(AVFilterContext *ctx, int is_second)
return ret;
}
+static int checkstride(YADIFContext *yadif, const AVFrame *a, const AVFrame *b)
+{
+ int i;
+ for (i = 0; i < yadif->csp->nb_components; i++)
+ if (a->linesize[i] != b->linesize[i])
+ return 1;
+ return 0;
+}
+
+static void fixstride(AVFilterLink *link, AVFrame *f)
+{
+ AVFrame *dst = ff_default_get_video_buffer(link, f->width, f->height);
+ if(!dst)
+ return;
+ av_frame_copy_props(dst, f);
+ av_image_copy(dst->data, dst->linesize,
+ (const uint8_t **)f->data, f->linesize,
+ dst->format, dst->width, dst->height);
+ av_frame_unref(f);
+ av_frame_move_ref(f, dst);
+ av_frame_free(&dst);
+}
+
static int filter_frame(AVFilterLink *link, AVFrame *frame)
{
AVFilterContext *ctx = link->dst;
YADIFContext *yadif = ctx->priv;
+ av_assert0(frame);
+
if (yadif->frame_pending)
return_frame(ctx, 1);
@@ -319,10 +325,31 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
yadif->cur = yadif->next;
yadif->next = frame;
- if (!yadif->cur)
+ if (!yadif->cur &&
+ !(yadif->cur = av_frame_clone(yadif->next)))
+ return AVERROR(ENOMEM);
+
+ if (checkstride(yadif, yadif->next, yadif->cur)) {
+ av_log(ctx, AV_LOG_VERBOSE, "Reallocating frame due to differing stride\n");
+ fixstride(link, yadif->next);
+ }
+ if (checkstride(yadif, yadif->next, yadif->cur))
+ fixstride(link, yadif->cur);
+ if (yadif->prev && checkstride(yadif, yadif->next, yadif->prev))
+ fixstride(link, yadif->prev);
+ if (checkstride(yadif, yadif->next, yadif->cur) || (yadif->prev && checkstride(yadif, yadif->next, yadif->prev))) {
+ av_log(ctx, AV_LOG_ERROR, "Failed to reallocate frame\n");
+ return -1;
+ }
+
+ if (!yadif->prev)
return 0;
- if (yadif->auto_enable && !yadif->cur->interlaced_frame) {
+ if ((yadif->deint && !yadif->cur->interlaced_frame) ||
+ ctx->is_disabled ||
+ (yadif->deint && !yadif->prev->interlaced_frame && yadif->prev->repeat_pict) ||
+ (yadif->deint && !yadif->next->interlaced_frame && yadif->next->repeat_pict)
+ ) {
yadif->out = av_frame_clone(yadif->cur);
if (!yadif->out)
return AVERROR(ENOMEM);
@@ -333,10 +360,6 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame)
return ff_filter_frame(ctx->outputs[0], yadif->out);
}
- if (!yadif->prev &&
- !(yadif->prev = av_frame_clone(yadif->cur)))
- return AVERROR(ENOMEM);
-
yadif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h);
if (!yadif->out)
return AVERROR(ENOMEM);
@@ -368,7 +391,7 @@ static int request_frame(AVFilterLink *link)
ret = ff_request_frame(link->src->inputs[0]);
- if (ret == AVERROR_EOF && yadif->next) {
+ if (ret == AVERROR_EOF && yadif->cur) {
AVFrame *next = av_frame_clone(yadif->next);
if (!next)
@@ -381,46 +404,18 @@ static int request_frame(AVFilterLink *link)
} else if (ret < 0) {
return ret;
}
- } while (!yadif->cur);
+ } while (!yadif->prev);
return 0;
}
-static int poll_frame(AVFilterLink *link)
-{
- YADIFContext *yadif = link->src->priv;
- int ret, val;
-
- if (yadif->frame_pending)
- return 1;
-
- val = ff_poll_frame(link->src->inputs[0]);
- if (val <= 0)
- return val;
-
- //FIXME change API to not requre this red tape
- if (val == 1 && !yadif->next) {
- if ((ret = ff_request_frame(link->src->inputs[0])) < 0)
- return ret;
- val = ff_poll_frame(link->src->inputs[0]);
- if (val <= 0)
- return val;
- }
- assert(yadif->next || !val);
-
- if (yadif->auto_enable && yadif->next && !yadif->next->interlaced_frame)
- return val;
-
- return val * ((yadif->mode&1)+1);
-}
-
static av_cold void uninit(AVFilterContext *ctx)
{
YADIFContext *yadif = ctx->priv;
- if (yadif->prev) av_frame_free(&yadif->prev);
- if (yadif->cur ) av_frame_free(&yadif->cur );
- if (yadif->next) av_frame_free(&yadif->next);
+ av_frame_free(&yadif->prev);
+ av_frame_free(&yadif->cur );
+ av_frame_free(&yadif->next);
}
static int query_formats(AVFilterContext *ctx)
@@ -435,26 +430,46 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_YUVJ420P,
AV_PIX_FMT_YUVJ422P,
AV_PIX_FMT_YUVJ444P,
- AV_NE( AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY16LE ),
+ AV_PIX_FMT_GRAY16,
AV_PIX_FMT_YUV440P,
AV_PIX_FMT_YUVJ440P,
- AV_NE( AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUV420P10LE ),
- AV_NE( AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUV422P10LE ),
- AV_NE( AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUV444P10LE ),
- AV_NE( AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUV420P16LE ),
- AV_NE( AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUV422P16LE ),
- AV_NE( AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUV444P16LE ),
+ AV_PIX_FMT_YUV420P9,
+ AV_PIX_FMT_YUV422P9,
+ AV_PIX_FMT_YUV444P9,
+ AV_PIX_FMT_YUV420P10,
+ AV_PIX_FMT_YUV422P10,
+ AV_PIX_FMT_YUV444P10,
+ AV_PIX_FMT_YUV420P12,
+ AV_PIX_FMT_YUV422P12,
+ AV_PIX_FMT_YUV444P12,
+ AV_PIX_FMT_YUV420P14,
+ AV_PIX_FMT_YUV422P14,
+ AV_PIX_FMT_YUV444P14,
+ AV_PIX_FMT_YUV420P16,
+ AV_PIX_FMT_YUV422P16,
+ AV_PIX_FMT_YUV444P16,
AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUVA444P,
+ 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_NONE
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
-
- return 0;
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static int config_props(AVFilterLink *link)
{
+ AVFilterContext *ctx = link->src;
YADIFContext *s = link->src->priv;
link->time_base.num = link->src->inputs[0]->time_base.num;
@@ -462,6 +477,14 @@ static int config_props(AVFilterLink *link)
link->w = link->src->inputs[0]->w;
link->h = link->src->inputs[0]->h;
+ if(s->mode&1)
+ link->frame_rate = av_mul_q(link->src->inputs[0]->frame_rate, (AVRational){2,1});
+
+ if (link->w < 3 || link->h < 3) {
+ av_log(ctx, AV_LOG_ERROR, "Video of less than 3 columns or lines is not supported\n");
+ return AVERROR(EINVAL);
+ }
+
s->csp = av_pix_fmt_desc_get(link->format);
if (s->csp->comp[0].depth_minus1 / 8 == 1) {
s->filter_line = filter_line_c_16bit;
@@ -469,39 +492,46 @@ static int config_props(AVFilterLink *link)
} else {
s->filter_line = filter_line_c;
s->filter_edges = filter_edges;
-
- if (ARCH_X86)
- ff_yadif_init_x86(s);
}
+ if (ARCH_X86)
+ ff_yadif_init_x86(s);
+
return 0;
}
+
#define OFFSET(x) offsetof(YADIFContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "mode", NULL, OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, FLAGS },
- { "parity", NULL, OFFSET(parity), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, FLAGS, "parity" },
- { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, .unit = "parity" },
- { "tff", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .unit = "parity" },
- { "bff", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .unit = "parity" },
- { "auto", NULL, OFFSET(auto_enable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
- { NULL },
-};
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
-static const AVClass yadif_class = {
- .class_name = "yadif",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
+static const AVOption yadif_options[] = {
+ { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FRAME}, 0, 3, FLAGS, "mode"},
+ CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"),
+ CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"),
+ CONST("send_frame_nospatial", "send one frame for each frame, but skip spatial interlacing check", YADIF_MODE_SEND_FRAME_NOSPATIAL, "mode"),
+ CONST("send_field_nospatial", "send one frame for each field, but skip spatial interlacing check", YADIF_MODE_SEND_FIELD_NOSPATIAL, "mode"),
+
+ { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" },
+ CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"),
+ CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"),
+ CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"),
+
+ { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" },
+ CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"),
+ CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"),
+
+ { NULL }
};
+AVFILTER_DEFINE_CLASS(yadif);
+
static const AVFilterPad avfilter_vf_yadif_inputs[] = {
{
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .get_video_buffer = get_video_buffer,
- .filter_frame = filter_frame,
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
},
{ NULL }
};
@@ -510,7 +540,6 @@ static const AVFilterPad avfilter_vf_yadif_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
- .poll_frame = poll_frame,
.request_frame = request_frame,
.config_props = config_props,
},
@@ -519,16 +548,12 @@ static const AVFilterPad avfilter_vf_yadif_outputs[] = {
AVFilter ff_vf_yadif = {
.name = "yadif",
- .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image"),
-
+ .description = NULL_IF_CONFIG_SMALL("Deinterlace the input image."),
.priv_size = sizeof(YADIFContext),
.priv_class = &yadif_class,
.uninit = uninit,
.query_formats = query_formats,
-
- .inputs = avfilter_vf_yadif_inputs,
-
- .outputs = avfilter_vf_yadif_outputs,
-
- .flags = AVFILTER_FLAG_SLICE_THREADS,
+ .inputs = avfilter_vf_yadif_inputs,
+ .outputs = avfilter_vf_yadif_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS,
};
diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c
new file mode 100644
index 0000000000..c49193a065
--- /dev/null
+++ b/libavfilter/vf_zoompan.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "libswscale/swscale.h"
+
+static const char *const var_names[] = {
+ "in_w", "iw",
+ "in_h", "ih",
+ "out_w", "ow",
+ "out_h", "oh",
+ "in",
+ "on",
+ "duration",
+ "pduration",
+ "time",
+ "frame",
+ "zoom",
+ "pzoom",
+ "x", "px",
+ "y", "py",
+ "a",
+ "sar",
+ "dar",
+ "hsub",
+ "vsub",
+ 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_IN,
+ VAR_ON,
+ VAR_DURATION,
+ VAR_PDURATION,
+ VAR_TIME,
+ VAR_FRAME,
+ VAR_ZOOM,
+ VAR_PZOOM,
+ VAR_X, VAR_PX,
+ VAR_Y, VAR_PY,
+ VAR_A,
+ VAR_SAR,
+ VAR_DAR,
+ VAR_HSUB,
+ VAR_VSUB,
+ VARS_NB
+};
+
+typedef struct ZPcontext {
+ const AVClass *class;
+ char *zoom_expr_str;
+ char *x_expr_str;
+ char *y_expr_str;
+ char *duration_expr_str;
+ int w, h;
+ double x, y;
+ double prev_zoom;
+ int prev_nb_frames;
+ struct SwsContext *sws;
+ int64_t frame_count;
+} ZPContext;
+
+#define OFFSET(x) offsetof(ZPContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+static const AVOption zoompan_options[] = {
+ { "zoom", "set the zoom expression", OFFSET(zoom_expr_str), AV_OPT_TYPE_STRING, {.str = "1" }, .flags = FLAGS },
+ { "z", "set the zoom expression", OFFSET(zoom_expr_str), AV_OPT_TYPE_STRING, {.str = "1" }, .flags = FLAGS },
+ { "x", "set the x expression", OFFSET(x_expr_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags = FLAGS },
+ { "y", "set the y expression", OFFSET(y_expr_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags = FLAGS },
+ { "d", "set the duration expression", OFFSET(duration_expr_str), AV_OPT_TYPE_STRING, {.str="90"}, .flags = FLAGS },
+ { "s", "set the output image size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, .flags = FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(zoompan);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ ZPContext *s = ctx->priv;
+
+ s->prev_zoom = 1;
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ ZPContext *s = ctx->priv;
+
+ outlink->w = s->w;
+ outlink->h = s->h;
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ ZPContext *s = ctx->priv;
+ double var_values[VARS_NB], nb_frames, zoom, dx, dy;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(in->format);
+ AVFrame *out = NULL;
+ int i, k, x, y, w, h, ret = 0;
+
+ var_values[VAR_IN_W] = var_values[VAR_IW] = in->width;
+ var_values[VAR_IN_H] = var_values[VAR_IH] = in->height;
+ var_values[VAR_OUT_W] = var_values[VAR_OW] = s->w;
+ var_values[VAR_OUT_H] = var_values[VAR_OH] = s->h;
+ var_values[VAR_IN] = inlink->frame_count + 1;
+ var_values[VAR_ON] = outlink->frame_count + 1;
+ var_values[VAR_PX] = s->x;
+ var_values[VAR_PY] = s->y;
+ var_values[VAR_X] = 0;
+ var_values[VAR_Y] = 0;
+ var_values[VAR_PZOOM] = s->prev_zoom;
+ var_values[VAR_ZOOM] = 1;
+ var_values[VAR_PDURATION] = s->prev_nb_frames;
+ var_values[VAR_A] = (double) in->width / in->height;
+ 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];
+ var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
+ var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
+
+ if ((ret = av_expr_parse_and_eval(&nb_frames, s->duration_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ goto fail;
+
+ var_values[VAR_DURATION] = nb_frames;
+ for (i = 0; i < nb_frames; i++) {
+ int px[4];
+ int py[4];
+ uint8_t *input[4];
+ int64_t pts = av_rescale_q(in->pts, inlink->time_base,
+ outlink->time_base) + s->frame_count;
+
+ var_values[VAR_TIME] = pts * av_q2d(outlink->time_base);
+ var_values[VAR_FRAME] = i;
+ var_values[VAR_ON] = outlink->frame_count + 1;
+ if ((ret = av_expr_parse_and_eval(&zoom, s->zoom_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ goto fail;
+
+ zoom = av_clipd(zoom, 1, 10);
+ var_values[VAR_ZOOM] = zoom;
+ w = in->width * (1.0 / zoom);
+ h = in->height * (1.0 / zoom);
+
+ if ((ret = av_expr_parse_and_eval(&dx, s->x_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ goto fail;
+ x = dx = av_clipd(dx, 0, FFMAX(in->width - w, 0));
+ var_values[VAR_X] = dx;
+ x &= ~((1 << desc->log2_chroma_w) - 1);
+
+ if ((ret = av_expr_parse_and_eval(&dy, s->y_expr_str,
+ var_names, var_values,
+ NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
+ goto fail;
+ y = dy = av_clipd(dy, 0, FFMAX(in->height - h, 0));
+ var_values[VAR_Y] = dy;
+ y &= ~((1 << desc->log2_chroma_h) - 1);
+
+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+ if (!out) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ px[1] = px[2] = FF_CEIL_RSHIFT(x, desc->log2_chroma_w);
+ px[0] = px[3] = x;
+
+ py[1] = py[2] = FF_CEIL_RSHIFT(y, desc->log2_chroma_h);
+ py[0] = py[3] = y;
+
+ s->sws = sws_alloc_context();
+ if (!s->sws) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ for (k = 0; in->data[k]; k++)
+ input[k] = in->data[k] + py[k] * in->linesize[k] + px[k];
+
+ av_opt_set_int(s->sws, "srcw", w, 0);
+ av_opt_set_int(s->sws, "srch", h, 0);
+ av_opt_set_int(s->sws, "src_format", in->format, 0);
+ av_opt_set_int(s->sws, "dstw", outlink->w, 0);
+ av_opt_set_int(s->sws, "dsth", outlink->h, 0);
+ av_opt_set_int(s->sws, "dst_format", outlink->format, 0);
+ av_opt_set_int(s->sws, "sws_flags", SWS_BICUBIC, 0);
+
+ if ((ret = sws_init_context(s->sws, NULL, NULL)) < 0)
+ goto fail;
+
+ sws_scale(s->sws, (const uint8_t *const *)&input, in->linesize, 0, h, out->data, out->linesize);
+
+ out->pts = pts;
+ s->frame_count++;
+
+ ret = ff_filter_frame(outlink, out);
+ if (ret < 0)
+ break;
+ out = NULL;
+
+ sws_freeContext(s->sws);
+ s->sws = NULL;
+ }
+
+ s->x = dx;
+ s->y = dy;
+ s->prev_zoom = zoom;
+ s->prev_nb_frames = nb_frames;
+
+fail:
+ sws_freeContext(s->sws);
+ s->sws = NULL;
+ av_frame_free(&out);
+ av_frame_free(&in);
+ return ret;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ 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_YUVA444P, AV_PIX_FMT_YUVA422P,
+ AV_PIX_FMT_YUVA420P,
+ AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
+ AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
+ AV_PIX_FMT_YUVJ411P,
+ AV_PIX_FMT_GRAY8,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ ZPContext *s = ctx->priv;
+
+ sws_freeContext(s->sws);
+ s->sws = NULL;
+}
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .config_props = config_output,
+ },
+ { NULL }
+};
+
+AVFilter ff_vf_zoompan = {
+ .name = "zoompan",
+ .description = NULL_IF_CONFIG_SMALL("Apply Zoom & Pan effect."),
+ .priv_size = sizeof(ZPContext),
+ .priv_class = &zoompan_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = inputs,
+ .outputs = outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
diff --git a/libavfilter/video.c b/libavfilter/video.c
index 9f1103e734..6a554834b3 100644
--- a/libavfilter/video.c
+++ b/libavfilter/video.c
@@ -1,24 +1,29 @@
/*
- * This file is part of Libav.
+ * Copyright 2007 Bobby Bingham
+ * Copyright Stefano Sabatini <stefasab gmail com>
+ * Copyright Vitor Sessak <vitor1001 gmail com>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include <stdio.h>
+#include "libavutil/avassert.h"
#include "libavutil/buffer.h"
#include "libavutil/imgutils.h"
#include "libavutil/mem.h"
@@ -56,7 +61,7 @@ AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h)
#if FF_API_AVFILTERBUFFER
AVFilterBufferRef *
-avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int perms,
+avfilter_get_video_buffer_ref_from_arrays(uint8_t * const data[4], const int linesize[4], int perms,
int w, int h, enum AVPixelFormat format)
{
AVFilterBuffer *pic = av_mallocz(sizeof(AVFilterBuffer));
@@ -105,7 +110,7 @@ AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h)
{
AVFrame *ret = NULL;
- FF_DPRINTF_START(NULL, get_video_buffer); ff_dlog_link(NULL, link, 0);
+ FF_TPRINTF_START(NULL, get_video_buffer); ff_tlog_link(NULL, link, 0);
if (link->dstpad->get_video_buffer)
ret = link->dstpad->get_video_buffer(link, w, h);
diff --git a/libavfilter/video.h b/libavfilter/video.h
index f7e8e34008..56c58d6766 100644
--- a/libavfilter/video.h
+++ b/libavfilter/video.h
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2007 Bobby Bingham
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavfilter/vidstabutils.c b/libavfilter/vidstabutils.c
new file mode 100644
index 0000000000..13544cf573
--- /dev/null
+++ b/libavfilter/vidstabutils.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2013 Georg Martius <georg dot martius at web dot de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "vidstabutils.h"
+
+/** convert AV's pixelformat to vid.stab pixelformat */
+VSPixelFormat ff_av2vs_pixfmt(AVFilterContext *ctx, enum AVPixelFormat pf)
+{
+ switch (pf) {
+ case AV_PIX_FMT_YUV420P: return PF_YUV420P;
+ case AV_PIX_FMT_YUV422P: return PF_YUV422P;
+ case AV_PIX_FMT_YUV444P: return PF_YUV444P;
+ case AV_PIX_FMT_YUV410P: return PF_YUV410P;
+ case AV_PIX_FMT_YUV411P: return PF_YUV411P;
+ case AV_PIX_FMT_YUV440P: return PF_YUV440P;
+ case AV_PIX_FMT_YUVA420P: return PF_YUVA420P;
+ case AV_PIX_FMT_GRAY8: return PF_GRAY8;
+ case AV_PIX_FMT_RGB24: return PF_RGB24;
+ case AV_PIX_FMT_BGR24: return PF_BGR24;
+ case AV_PIX_FMT_RGBA: return PF_RGBA;
+ default:
+ av_log(ctx, AV_LOG_ERROR, "cannot deal with pixel format %i\n", pf);
+ return PF_NONE;
+ }
+}
+
+/** struct to hold a valid context for logging from within vid.stab lib */
+typedef struct {
+ const AVClass *class;
+} VS2AVLogCtx;
+
+/** wrapper to log vs_log into av_log */
+static int vs2av_log(int type, const char *tag, const char *format, ...)
+{
+ va_list ap;
+ VS2AVLogCtx ctx;
+ AVClass class = {
+ .class_name = tag,
+ .item_name = av_default_item_name,
+ .option = 0,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_FILTER,
+ };
+ ctx.class = &class;
+ va_start(ap, format);
+ av_vlog(&ctx, type, format, ap);
+ va_end(ap);
+ return VS_OK;
+}
+
+/** sets the memory allocation function and logging constants to av versions */
+void ff_vs_init(void)
+{
+ vs_malloc = av_malloc;
+ vs_zalloc = av_mallocz;
+ vs_realloc = av_realloc;
+ vs_free = av_free;
+
+ VS_ERROR_TYPE = AV_LOG_ERROR;
+ VS_WARN_TYPE = AV_LOG_WARNING;
+ VS_INFO_TYPE = AV_LOG_INFO;
+ VS_MSG_TYPE = AV_LOG_VERBOSE;
+
+ vs_log = vs2av_log;
+
+ VS_ERROR = 0;
+ VS_OK = 1;
+}
diff --git a/libavfilter/vidstabutils.h b/libavfilter/vidstabutils.h
new file mode 100644
index 0000000000..c6d6cedb72
--- /dev/null
+++ b/libavfilter/vidstabutils.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013 Georg Martius <georg dot martius at web dot de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_VIDSTABUTILS_H
+#define AVFILTER_VIDSTABUTILS_H
+
+#include <vid.stab/libvidstab.h>
+
+#include "avfilter.h"
+
+/* Conversion routines between libav* and vid.stab */
+
+/**
+ * Converts an AVPixelFormat to a VSPixelFormat.
+ *
+ * @param[in] ctx AVFilterContext used for logging
+ * @param[in] pf AVPixelFormat
+ * @return a corresponding VSPixelFormat
+ */
+VSPixelFormat ff_av2vs_pixfmt(AVFilterContext *ctx, enum AVPixelFormat pf);
+
+/**
+ * Initialize libvidstab
+ *
+ * Sets the memory allocation functions and logging constants to corresponding
+ * av* versions.
+ */
+void ff_vs_init(void);
+
+#endif
diff --git a/libavfilter/vsink_nullsink.c b/libavfilter/vsink_nullsink.c
index 14b6b122ab..281721bc55 100644
--- a/libavfilter/vsink_nullsink.c
+++ b/libavfilter/vsink_nullsink.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavfilter/vsrc_cellauto.c b/libavfilter/vsrc_cellauto.c
new file mode 100644
index 0000000000..4f4b01c60d
--- /dev/null
+++ b/libavfilter/vsrc_cellauto.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) Stefano Sabatini 2011
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * cellular automaton video source, based on Stephen Wolfram "experimentus crucis"
+ */
+
+/* #define DEBUG */
+
+#include "libavutil/file.h"
+#include "libavutil/lfg.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 "formats.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ char *filename;
+ char *rule_str;
+ uint8_t *file_buf;
+ size_t file_bufsize;
+ uint8_t *buf;
+ int buf_prev_row_idx, buf_row_idx;
+ uint8_t rule;
+ uint64_t pts;
+ AVRational frame_rate;
+ double random_fill_ratio;
+ uint32_t random_seed;
+ int stitch, scroll, start_full;
+ int64_t generation; ///< the generation number, starting from 0
+ AVLFG lfg;
+ char *pattern;
+} CellAutoContext;
+
+#define OFFSET(x) offsetof(CellAutoContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption cellauto_options[] = {
+ { "filename", "read initial pattern from file", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "f", "read initial pattern from file", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "pattern", "set initial pattern", OFFSET(pattern), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "p", "set initial pattern", OFFSET(pattern), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, FLAGS },
+ { "rule", "set rule", OFFSET(rule), AV_OPT_TYPE_INT, {.i64 = 110}, 0, 255, FLAGS },
+ { "random_fill_ratio", "set fill ratio for filling initial grid randomly", OFFSET(random_fill_ratio), AV_OPT_TYPE_DOUBLE, {.dbl = 1/M_PHI}, 0, 1, FLAGS },
+ { "ratio", "set fill ratio for filling initial grid randomly", OFFSET(random_fill_ratio), AV_OPT_TYPE_DOUBLE, {.dbl = 1/M_PHI}, 0, 1, FLAGS },
+ { "random_seed", "set the seed for filling the initial grid randomly", OFFSET(random_seed), AV_OPT_TYPE_INT, {.i64 = -1}, -1, UINT32_MAX, FLAGS },
+ { "seed", "set the seed for filling the initial grid randomly", OFFSET(random_seed), AV_OPT_TYPE_INT, {.i64 = -1}, -1, UINT32_MAX, FLAGS },
+ { "scroll", "scroll pattern downward", OFFSET(scroll), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, FLAGS },
+ { "start_full", "start filling the whole video", OFFSET(start_full), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS },
+ { "full", "start filling the whole video", OFFSET(start_full), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, FLAGS },
+ { "stitch", "stitch boundaries", OFFSET(stitch), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(cellauto);
+
+#ifdef DEBUG
+static void show_cellauto_row(AVFilterContext *ctx)
+{
+ CellAutoContext *cellauto = ctx->priv;
+ int i;
+ uint8_t *row = cellauto->buf + cellauto->w * cellauto->buf_row_idx;
+ char *line = av_malloc(cellauto->w + 1);
+ if (!line)
+ return;
+
+ for (i = 0; i < cellauto->w; i++)
+ line[i] = row[i] ? '@' : ' ';
+ line[i] = 0;
+ av_log(ctx, AV_LOG_DEBUG, "generation:%"PRId64" row:%s|\n", cellauto->generation, line);
+ av_free(line);
+}
+#endif
+
+static int init_pattern_from_string(AVFilterContext *ctx)
+{
+ CellAutoContext *cellauto = ctx->priv;
+ char *p;
+ int i, w = 0;
+
+ w = strlen(cellauto->pattern);
+ av_log(ctx, AV_LOG_DEBUG, "w:%d\n", w);
+
+ if (cellauto->w) {
+ if (w > cellauto->w) {
+ av_log(ctx, AV_LOG_ERROR,
+ "The specified width is %d which cannot contain the provided string width of %d\n",
+ cellauto->w, w);
+ return AVERROR(EINVAL);
+ }
+ } else {
+ /* width was not specified, set it to width of the provided row */
+ cellauto->w = w;
+ cellauto->h = (double)cellauto->w * M_PHI;
+ }
+
+ cellauto->buf = av_mallocz_array(sizeof(uint8_t) * cellauto->w, cellauto->h);
+ if (!cellauto->buf)
+ return AVERROR(ENOMEM);
+
+ /* fill buf */
+ p = cellauto->pattern;
+ for (i = (cellauto->w - w)/2;; i++) {
+ av_log(ctx, AV_LOG_DEBUG, "%d %c\n", i, *p == '\n' ? 'N' : *p);
+ if (*p == '\n' || !*p)
+ break;
+ else
+ cellauto->buf[i] = !!av_isgraph(*(p++));
+ }
+
+ return 0;
+}
+
+static int init_pattern_from_file(AVFilterContext *ctx)
+{
+ CellAutoContext *cellauto = ctx->priv;
+ int ret;
+
+ ret = av_file_map(cellauto->filename,
+ &cellauto->file_buf, &cellauto->file_bufsize, 0, ctx);
+ if (ret < 0)
+ return ret;
+
+ /* create a string based on the read file */
+ cellauto->pattern = av_malloc(cellauto->file_bufsize + 1);
+ if (!cellauto->pattern)
+ return AVERROR(ENOMEM);
+ memcpy(cellauto->pattern, cellauto->file_buf, cellauto->file_bufsize);
+ cellauto->pattern[cellauto->file_bufsize] = 0;
+
+ return init_pattern_from_string(ctx);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ CellAutoContext *cellauto = ctx->priv;
+ int ret;
+
+ if (!cellauto->w && !cellauto->filename && !cellauto->pattern)
+ av_opt_set(cellauto, "size", "320x518", 0);
+
+ if (cellauto->filename && cellauto->pattern) {
+ av_log(ctx, AV_LOG_ERROR, "Only one of the filename or pattern options can be used\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (cellauto->filename) {
+ if ((ret = init_pattern_from_file(ctx)) < 0)
+ return ret;
+ } else if (cellauto->pattern) {
+ if ((ret = init_pattern_from_string(ctx)) < 0)
+ return ret;
+ } else {
+ /* fill the first row randomly */
+ int i;
+
+ cellauto->buf = av_mallocz_array(sizeof(uint8_t) * cellauto->w, cellauto->h);
+ if (!cellauto->buf)
+ return AVERROR(ENOMEM);
+ if (cellauto->random_seed == -1)
+ cellauto->random_seed = av_get_random_seed();
+
+ av_lfg_init(&cellauto->lfg, cellauto->random_seed);
+
+ for (i = 0; i < cellauto->w; i++) {
+ double r = (double)av_lfg_get(&cellauto->lfg) / UINT32_MAX;
+ if (r <= cellauto->random_fill_ratio)
+ cellauto->buf[i] = 1;
+ }
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "s:%dx%d r:%d/%d rule:%d stitch:%d scroll:%d full:%d seed:%u\n",
+ cellauto->w, cellauto->h, cellauto->frame_rate.num, cellauto->frame_rate.den,
+ cellauto->rule, cellauto->stitch, cellauto->scroll, cellauto->start_full,
+ cellauto->random_seed);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ CellAutoContext *cellauto = ctx->priv;
+
+ av_file_unmap(cellauto->file_buf, cellauto->file_bufsize);
+ av_freep(&cellauto->buf);
+ av_freep(&cellauto->pattern);
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ CellAutoContext *cellauto = outlink->src->priv;
+
+ outlink->w = cellauto->w;
+ outlink->h = cellauto->h;
+ outlink->time_base = av_inv_q(cellauto->frame_rate);
+
+ return 0;
+}
+
+static void evolve(AVFilterContext *ctx)
+{
+ CellAutoContext *cellauto = ctx->priv;
+ int i, v, pos[3];
+ uint8_t *row, *prev_row = cellauto->buf + cellauto->buf_row_idx * cellauto->w;
+ enum { NW, N, NE };
+
+ cellauto->buf_prev_row_idx = cellauto->buf_row_idx;
+ cellauto->buf_row_idx = cellauto->buf_row_idx == cellauto->h-1 ? 0 : cellauto->buf_row_idx+1;
+ row = cellauto->buf + cellauto->w * cellauto->buf_row_idx;
+
+ for (i = 0; i < cellauto->w; i++) {
+ if (cellauto->stitch) {
+ pos[NW] = i-1 < 0 ? cellauto->w-1 : i-1;
+ pos[N] = i;
+ pos[NE] = i+1 == cellauto->w ? 0 : i+1;
+ v = prev_row[pos[NW]]<<2 | prev_row[pos[N]]<<1 | prev_row[pos[NE]];
+ } else {
+ v = 0;
+ v|= i-1 >= 0 ? prev_row[i-1]<<2 : 0;
+ v|= prev_row[i ]<<1 ;
+ v|= i+1 < cellauto->w ? prev_row[i+1] : 0;
+ }
+ row[i] = !!(cellauto->rule & (1<<v));
+ av_dlog(ctx, "i:%d context:%c%c%c -> cell:%d\n", i,
+ v&4?'@':' ', v&2?'@':' ', v&1?'@':' ', row[i]);
+ }
+
+ cellauto->generation++;
+}
+
+static void fill_picture(AVFilterContext *ctx, AVFrame *picref)
+{
+ CellAutoContext *cellauto = ctx->priv;
+ int i, j, k, row_idx = 0;
+ uint8_t *p0 = picref->data[0];
+
+ if (cellauto->scroll && cellauto->generation >= cellauto->h)
+ /* show on top the oldest row */
+ row_idx = (cellauto->buf_row_idx + 1) % cellauto->h;
+
+ /* fill the output picture with the whole buffer */
+ for (i = 0; i < cellauto->h; i++) {
+ uint8_t byte = 0;
+ uint8_t *row = cellauto->buf + row_idx*cellauto->w;
+ uint8_t *p = p0;
+ for (k = 0, j = 0; j < cellauto->w; j++) {
+ byte |= row[j]<<(7-k++);
+ if (k==8 || j == cellauto->w-1) {
+ k = 0;
+ *p++ = byte;
+ byte = 0;
+ }
+ }
+ row_idx = (row_idx + 1) % cellauto->h;
+ p0 += picref->linesize[0];
+ }
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ CellAutoContext *cellauto = outlink->src->priv;
+ AVFrame *picref = ff_get_video_buffer(outlink, cellauto->w, cellauto->h);
+ if (!picref)
+ return AVERROR(ENOMEM);
+ picref->sample_aspect_ratio = (AVRational) {1, 1};
+ if (cellauto->generation == 0 && cellauto->start_full) {
+ int i;
+ for (i = 0; i < cellauto->h-1; i++)
+ evolve(outlink->src);
+ }
+ fill_picture(outlink->src, picref);
+ evolve(outlink->src);
+
+ picref->pts = cellauto->pts++;
+
+#ifdef DEBUG
+ show_cellauto_row(outlink->src);
+#endif
+ return ff_filter_frame(outlink, picref);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE };
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static const AVFilterPad cellauto_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vsrc_cellauto = {
+ .name = "cellauto",
+ .description = NULL_IF_CONFIG_SMALL("Create pattern generated by an elementary cellular automaton."),
+ .priv_size = sizeof(CellAutoContext),
+ .priv_class = &cellauto_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = cellauto_outputs,
+};
diff --git a/libavfilter/vsrc_color.c b/libavfilter/vsrc_color.c
deleted file mode 100644
index 3b506ec422..0000000000
--- a/libavfilter/vsrc_color.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (c) 2010 Stefano Sabatini
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * color source
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-#include "video.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/colorspace.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/internal.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/mem.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "drawutils.h"
-
-typedef struct ColorContext {
- const AVClass *class;
- int w, h;
- uint8_t color[4];
- AVRational time_base;
- uint8_t *line[4];
- int line_step[4];
- int hsub, vsub; ///< chroma subsampling values
- uint64_t pts;
- char *color_str;
- char *size_str;
- char *framerate_str;
-} ColorContext;
-
-static av_cold int color_init(AVFilterContext *ctx)
-{
- ColorContext *color = ctx->priv;
- AVRational frame_rate_q;
- int ret;
-
- if (av_parse_video_size(&color->w, &color->h, color->size_str) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid frame size: %s\n", color->size_str);
- return AVERROR(EINVAL);
- }
-
- if (av_parse_video_rate(&frame_rate_q, color->framerate_str) < 0 ||
- frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: %s\n", color->framerate_str);
- return AVERROR(EINVAL);
- }
- color->time_base.num = frame_rate_q.den;
- color->time_base.den = frame_rate_q.num;
-
- if ((ret = av_parse_color(color->color, color->color_str, -1, ctx)) < 0)
- return ret;
-
- return 0;
-}
-
-static av_cold void color_uninit(AVFilterContext *ctx)
-{
- ColorContext *color = ctx->priv;
- int i;
-
- for (i = 0; i < 4; i++) {
- av_freep(&color->line[i]);
- color->line_step[i] = 0;
- }
-}
-
-static int query_formats(AVFilterContext *ctx)
-{
- static const enum AVPixelFormat pix_fmts[] = {
- AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA,
- AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
- AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
-
- 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_YUVJ444P, AV_PIX_FMT_YUVJ422P,
- AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
- AV_PIX_FMT_YUVA420P,
-
- AV_PIX_FMT_NONE
- };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
-}
-
-static int color_config_props(AVFilterLink *inlink)
-{
- AVFilterContext *ctx = inlink->src;
- ColorContext *color = ctx->priv;
- uint8_t rgba_color[4];
- int is_packed_rgba;
- const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
-
- color->hsub = pix_desc->log2_chroma_w;
- color->vsub = pix_desc->log2_chroma_h;
-
- color->w &= ~((1 << color->hsub) - 1);
- color->h &= ~((1 << color->vsub) - 1);
- if (av_image_check_size(color->w, color->h, 0, ctx) < 0)
- return AVERROR(EINVAL);
-
- memcpy(rgba_color, color->color, sizeof(rgba_color));
- ff_fill_line_with_color(color->line, color->line_step, color->w, color->color,
- inlink->format, rgba_color, &is_packed_rgba, NULL);
-
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d r:%d/%d color:0x%02x%02x%02x%02x[%s]\n",
- color->w, color->h, color->time_base.den, color->time_base.num,
- color->color[0], color->color[1], color->color[2], color->color[3],
- is_packed_rgba ? "rgba" : "yuva");
- inlink->w = color->w;
- inlink->h = color->h;
- inlink->time_base = color->time_base;
-
- return 0;
-}
-
-static int color_request_frame(AVFilterLink *link)
-{
- ColorContext *color = link->src->priv;
- AVFrame *frame = ff_get_video_buffer(link, color->w, color->h);
-
- if (!frame)
- return AVERROR(ENOMEM);
-
- frame->sample_aspect_ratio = (AVRational) {1, 1};
- frame->pts = color->pts++;
-
- ff_draw_rectangle(frame->data, frame->linesize,
- color->line, color->line_step, color->hsub, color->vsub,
- 0, 0, color->w, color->h);
- return ff_filter_frame(link, frame);
-}
-
-#define OFFSET(x) offsetof(ColorContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "color", "Output video color", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, .flags = FLAGS },
- { "size", "Output video size (wxh or an abbreviation)", OFFSET(size_str), AV_OPT_TYPE_STRING, { .str = "320x240" }, .flags = FLAGS },
- { "framerate", "Output video framerate", OFFSET(framerate_str), AV_OPT_TYPE_STRING, { .str = "25" }, .flags = FLAGS },
- { NULL },
-};
-
-static const AVClass color_class = {
- .class_name = "color",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-static const AVFilterPad avfilter_vsrc_color_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .request_frame = color_request_frame,
- .config_props = color_config_props
- },
- { NULL }
-};
-
-AVFilter ff_vsrc_color = {
- .name = "color",
- .description = NULL_IF_CONFIG_SMALL("Provide an uniformly colored input, syntax is: [color[:size[:rate]]]"),
-
- .priv_class = &color_class,
- .priv_size = sizeof(ColorContext),
- .init = color_init,
- .uninit = color_uninit,
-
- .query_formats = query_formats,
-
- .inputs = NULL,
-
- .outputs = avfilter_vsrc_color_outputs,
-};
diff --git a/libavfilter/vsrc_life.c b/libavfilter/vsrc_life.c
new file mode 100644
index 0000000000..47630add7d
--- /dev/null
+++ b/libavfilter/vsrc_life.c
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) Stefano Sabatini 2010
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * life video source, based on John Conways' Life Game
+ */
+
+/* #define DEBUG */
+
+#include "libavutil/file.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/lfg.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 "formats.h"
+#include "video.h"
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ char *filename;
+ char *rule_str;
+ uint8_t *file_buf;
+ size_t file_bufsize;
+
+ /**
+ * The two grid state buffers.
+ *
+ * A 0xFF (ALIVE_CELL) value means the cell is alive (or new born), while
+ * the decreasing values from 0xFE to 0 means the cell is dead; the range
+ * of values is used for the slow death effect, or mold (0xFE means dead,
+ * 0xFD means very dead, 0xFC means very very dead... and 0x00 means
+ * definitely dead/mold).
+ */
+ uint8_t *buf[2];
+
+ uint8_t buf_idx;
+ uint16_t stay_rule; ///< encode the behavior for filled cells
+ uint16_t born_rule; ///< encode the behavior for empty cells
+ uint64_t pts;
+ AVRational frame_rate;
+ double random_fill_ratio;
+ uint32_t random_seed;
+ int stitch;
+ int mold;
+ uint8_t life_color[4];
+ uint8_t death_color[4];
+ uint8_t mold_color[4];
+ AVLFG lfg;
+ void (*draw)(AVFilterContext*, AVFrame*);
+} LifeContext;
+
+#define ALIVE_CELL 0xFF
+#define OFFSET(x) offsetof(LifeContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption life_options[] = {
+ { "filename", "set source file", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "f", "set source file", OFFSET(filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, FLAGS },
+ { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, FLAGS },
+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "rule", "set rule", OFFSET(rule_str), AV_OPT_TYPE_STRING, {.str = "B3/S23"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "random_fill_ratio", "set fill ratio for filling initial grid randomly", OFFSET(random_fill_ratio), AV_OPT_TYPE_DOUBLE, {.dbl=1/M_PHI}, 0, 1, FLAGS },
+ { "ratio", "set fill ratio for filling initial grid randomly", OFFSET(random_fill_ratio), AV_OPT_TYPE_DOUBLE, {.dbl=1/M_PHI}, 0, 1, FLAGS },
+ { "random_seed", "set the seed for filling the initial grid randomly", OFFSET(random_seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, UINT32_MAX, FLAGS },
+ { "seed", "set the seed for filling the initial grid randomly", OFFSET(random_seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, UINT32_MAX, FLAGS },
+ { "stitch", "stitch boundaries", OFFSET(stitch), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
+ { "mold", "set mold speed for dead cells", OFFSET(mold), AV_OPT_TYPE_INT, {.i64=0}, 0, 0xFF, FLAGS },
+ { "life_color", "set life color", OFFSET( life_color), AV_OPT_TYPE_COLOR, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "death_color", "set death color", OFFSET(death_color), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "mold_color", "set mold color", OFFSET( mold_color), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(life);
+
+static int parse_rule(uint16_t *born_rule, uint16_t *stay_rule,
+ const char *rule_str, void *log_ctx)
+{
+ char *tail;
+ const char *p = rule_str;
+ *born_rule = 0;
+ *stay_rule = 0;
+
+ if (strchr("bBsS", *p)) {
+ /* parse rule as a Born / Stay Alive code, see
+ * http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life */
+ do {
+ uint16_t *rule = (*p == 'b' || *p == 'B') ? born_rule : stay_rule;
+ p++;
+ while (*p >= '0' && *p <= '8') {
+ *rule += 1<<(*p - '0');
+ p++;
+ }
+ if (*p != '/')
+ break;
+ p++;
+ } while (strchr("bBsS", *p));
+
+ if (*p)
+ goto error;
+ } else {
+ /* parse rule as a number, expressed in the form STAY|(BORN<<9),
+ * where STAY and BORN encode the corresponding 9-bits rule */
+ long int rule = strtol(rule_str, &tail, 10);
+ if (*tail)
+ goto error;
+ *born_rule = ((1<<9)-1) & rule;
+ *stay_rule = rule >> 9;
+ }
+
+ return 0;
+
+error:
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid rule code '%s' provided\n", rule_str);
+ return AVERROR(EINVAL);
+}
+
+#ifdef DEBUG
+static void show_life_grid(AVFilterContext *ctx)
+{
+ LifeContext *life = ctx->priv;
+ int i, j;
+
+ char *line = av_malloc(life->w + 1);
+ if (!line)
+ return;
+ for (i = 0; i < life->h; i++) {
+ for (j = 0; j < life->w; j++)
+ line[j] = life->buf[life->buf_idx][i*life->w + j] == ALIVE_CELL ? '@' : ' ';
+ line[j] = 0;
+ av_log(ctx, AV_LOG_DEBUG, "%3d: %s\n", i, line);
+ }
+ av_free(line);
+}
+#endif
+
+static int init_pattern_from_file(AVFilterContext *ctx)
+{
+ LifeContext *life = ctx->priv;
+ char *p;
+ int ret, i, i0, j, h = 0, w, max_w = 0;
+
+ if ((ret = av_file_map(life->filename, &life->file_buf, &life->file_bufsize,
+ 0, ctx)) < 0)
+ return ret;
+ av_freep(&life->filename);
+
+ /* prescan file to get the number of lines and the maximum width */
+ w = 0;
+ for (i = 0; i < life->file_bufsize; i++) {
+ if (life->file_buf[i] == '\n') {
+ h++; max_w = FFMAX(w, max_w); w = 0;
+ } else {
+ w++;
+ }
+ }
+ av_log(ctx, AV_LOG_DEBUG, "h:%d max_w:%d\n", h, max_w);
+
+ if (life->w) {
+ if (max_w > life->w || h > life->h) {
+ av_log(ctx, AV_LOG_ERROR,
+ "The specified size is %dx%d which cannot contain the provided file size of %dx%d\n",
+ life->w, life->h, max_w, h);
+ return AVERROR(EINVAL);
+ }
+ } else {
+ /* size was not specified, set it to size of the grid */
+ life->w = max_w;
+ life->h = h;
+ }
+
+ if (!(life->buf[0] = av_calloc(life->h * life->w, sizeof(*life->buf[0]))) ||
+ !(life->buf[1] = av_calloc(life->h * life->w, sizeof(*life->buf[1])))) {
+ av_freep(&life->buf[0]);
+ av_freep(&life->buf[1]);
+ return AVERROR(ENOMEM);
+ }
+
+ /* fill buf[0] */
+ p = life->file_buf;
+ for (i0 = 0, i = (life->h - h)/2; i0 < h; i0++, i++) {
+ for (j = (life->w - max_w)/2;; j++) {
+ av_log(ctx, AV_LOG_DEBUG, "%d:%d %c\n", i, j, *p == '\n' ? 'N' : *p);
+ if (*p == '\n') {
+ p++; break;
+ } else
+ life->buf[0][i*life->w + j] = av_isgraph(*(p++)) ? ALIVE_CELL : 0;
+ }
+ }
+ life->buf_idx = 0;
+
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ LifeContext *life = ctx->priv;
+ int ret;
+
+ if (!life->w && !life->filename)
+ av_opt_set(life, "size", "320x240", 0);
+
+ if ((ret = parse_rule(&life->born_rule, &life->stay_rule, life->rule_str, ctx)) < 0)
+ return ret;
+
+ if (!life->mold && memcmp(life->mold_color, "\x00\x00\x00", 3))
+ av_log(ctx, AV_LOG_WARNING,
+ "Mold color is set while mold isn't, ignoring the color.\n");
+
+ if (!life->filename) {
+ /* fill the grid randomly */
+ int i;
+
+ if (!(life->buf[0] = av_calloc(life->h * life->w, sizeof(*life->buf[0]))) ||
+ !(life->buf[1] = av_calloc(life->h * life->w, sizeof(*life->buf[1])))) {
+ av_freep(&life->buf[0]);
+ av_freep(&life->buf[1]);
+ return AVERROR(ENOMEM);
+ }
+ if (life->random_seed == -1)
+ life->random_seed = av_get_random_seed();
+
+ av_lfg_init(&life->lfg, life->random_seed);
+
+ for (i = 0; i < life->w * life->h; i++) {
+ double r = (double)av_lfg_get(&life->lfg) / UINT32_MAX;
+ if (r <= life->random_fill_ratio)
+ life->buf[0][i] = ALIVE_CELL;
+ }
+ life->buf_idx = 0;
+ } else {
+ if ((ret = init_pattern_from_file(ctx)) < 0)
+ return ret;
+ }
+
+ av_log(ctx, AV_LOG_VERBOSE,
+ "s:%dx%d r:%d/%d rule:%s stay_rule:%d born_rule:%d stitch:%d seed:%u\n",
+ life->w, life->h, life->frame_rate.num, life->frame_rate.den,
+ life->rule_str, life->stay_rule, life->born_rule, life->stitch,
+ life->random_seed);
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ LifeContext *life = ctx->priv;
+
+ av_file_unmap(life->file_buf, life->file_bufsize);
+ av_freep(&life->rule_str);
+ av_freep(&life->buf[0]);
+ av_freep(&life->buf[1]);
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ LifeContext *life = outlink->src->priv;
+
+ outlink->w = life->w;
+ outlink->h = life->h;
+ outlink->time_base = av_inv_q(life->frame_rate);
+
+ return 0;
+}
+
+static void evolve(AVFilterContext *ctx)
+{
+ LifeContext *life = ctx->priv;
+ int i, j;
+ uint8_t *oldbuf = life->buf[ life->buf_idx];
+ uint8_t *newbuf = life->buf[!life->buf_idx];
+
+ enum { NW, N, NE, W, E, SW, S, SE };
+
+ /* evolve the grid */
+ for (i = 0; i < life->h; i++) {
+ for (j = 0; j < life->w; j++) {
+ int pos[8][2], n, alive, cell;
+ if (life->stitch) {
+ pos[NW][0] = (i-1) < 0 ? life->h-1 : i-1; pos[NW][1] = (j-1) < 0 ? life->w-1 : j-1;
+ pos[N ][0] = (i-1) < 0 ? life->h-1 : i-1; pos[N ][1] = j ;
+ pos[NE][0] = (i-1) < 0 ? life->h-1 : i-1; pos[NE][1] = (j+1) == life->w ? 0 : j+1;
+ pos[W ][0] = i ; pos[W ][1] = (j-1) < 0 ? life->w-1 : j-1;
+ pos[E ][0] = i ; pos[E ][1] = (j+1) == life->w ? 0 : j+1;
+ pos[SW][0] = (i+1) == life->h ? 0 : i+1; pos[SW][1] = (j-1) < 0 ? life->w-1 : j-1;
+ pos[S ][0] = (i+1) == life->h ? 0 : i+1; pos[S ][1] = j ;
+ pos[SE][0] = (i+1) == life->h ? 0 : i+1; pos[SE][1] = (j+1) == life->w ? 0 : j+1;
+ } else {
+ pos[NW][0] = (i-1) < 0 ? -1 : i-1; pos[NW][1] = (j-1) < 0 ? -1 : j-1;
+ pos[N ][0] = (i-1) < 0 ? -1 : i-1; pos[N ][1] = j ;
+ pos[NE][0] = (i-1) < 0 ? -1 : i-1; pos[NE][1] = (j+1) == life->w ? -1 : j+1;
+ pos[W ][0] = i ; pos[W ][1] = (j-1) < 0 ? -1 : j-1;
+ pos[E ][0] = i ; pos[E ][1] = (j+1) == life->w ? -1 : j+1;
+ pos[SW][0] = (i+1) == life->h ? -1 : i+1; pos[SW][1] = (j-1) < 0 ? -1 : j-1;
+ pos[S ][0] = (i+1) == life->h ? -1 : i+1; pos[S ][1] = j ;
+ pos[SE][0] = (i+1) == life->h ? -1 : i+1; pos[SE][1] = (j+1) == life->w ? -1 : j+1;
+ }
+
+ /* compute the number of live neighbor cells */
+ n = (pos[NW][0] == -1 || pos[NW][1] == -1 ? 0 : oldbuf[pos[NW][0]*life->w + pos[NW][1]] == ALIVE_CELL) +
+ (pos[N ][0] == -1 || pos[N ][1] == -1 ? 0 : oldbuf[pos[N ][0]*life->w + pos[N ][1]] == ALIVE_CELL) +
+ (pos[NE][0] == -1 || pos[NE][1] == -1 ? 0 : oldbuf[pos[NE][0]*life->w + pos[NE][1]] == ALIVE_CELL) +
+ (pos[W ][0] == -1 || pos[W ][1] == -1 ? 0 : oldbuf[pos[W ][0]*life->w + pos[W ][1]] == ALIVE_CELL) +
+ (pos[E ][0] == -1 || pos[E ][1] == -1 ? 0 : oldbuf[pos[E ][0]*life->w + pos[E ][1]] == ALIVE_CELL) +
+ (pos[SW][0] == -1 || pos[SW][1] == -1 ? 0 : oldbuf[pos[SW][0]*life->w + pos[SW][1]] == ALIVE_CELL) +
+ (pos[S ][0] == -1 || pos[S ][1] == -1 ? 0 : oldbuf[pos[S ][0]*life->w + pos[S ][1]] == ALIVE_CELL) +
+ (pos[SE][0] == -1 || pos[SE][1] == -1 ? 0 : oldbuf[pos[SE][0]*life->w + pos[SE][1]] == ALIVE_CELL);
+ cell = oldbuf[i*life->w + j];
+ alive = 1<<n & (cell == ALIVE_CELL ? life->stay_rule : life->born_rule);
+ if (alive) *newbuf = ALIVE_CELL; // new cell is alive
+ else if (cell) *newbuf = cell - 1; // new cell is dead and in the process of mold
+ else *newbuf = 0; // new cell is definitely dead
+ av_dlog(ctx, "i:%d j:%d live_neighbors:%d cell:%d -> cell:%d\n", i, j, n, cell, *newbuf);
+ newbuf++;
+ }
+ }
+
+ life->buf_idx = !life->buf_idx;
+}
+
+static void fill_picture_monoblack(AVFilterContext *ctx, AVFrame *picref)
+{
+ LifeContext *life = ctx->priv;
+ uint8_t *buf = life->buf[life->buf_idx];
+ int i, j, k;
+
+ /* fill the output picture with the old grid buffer */
+ for (i = 0; i < life->h; i++) {
+ uint8_t byte = 0;
+ uint8_t *p = picref->data[0] + i * picref->linesize[0];
+ for (k = 0, j = 0; j < life->w; j++) {
+ byte |= (buf[i*life->w+j] == ALIVE_CELL)<<(7-k++);
+ if (k==8 || j == life->w-1) {
+ k = 0;
+ *p++ = byte;
+ byte = 0;
+ }
+ }
+ }
+}
+
+// divide by 255 and round to nearest
+// apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
+#define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
+
+static void fill_picture_rgb(AVFilterContext *ctx, AVFrame *picref)
+{
+ LifeContext *life = ctx->priv;
+ uint8_t *buf = life->buf[life->buf_idx];
+ int i, j;
+
+ /* fill the output picture with the old grid buffer */
+ for (i = 0; i < life->h; i++) {
+ uint8_t *p = picref->data[0] + i * picref->linesize[0];
+ for (j = 0; j < life->w; j++) {
+ uint8_t v = buf[i*life->w + j];
+ if (life->mold && v != ALIVE_CELL) {
+ const uint8_t *c1 = life-> mold_color;
+ const uint8_t *c2 = life->death_color;
+ int death_age = FFMIN((0xff - v) * life->mold, 0xff);
+ *p++ = FAST_DIV255((c2[0] << 8) + ((int)c1[0] - (int)c2[0]) * death_age);
+ *p++ = FAST_DIV255((c2[1] << 8) + ((int)c1[1] - (int)c2[1]) * death_age);
+ *p++ = FAST_DIV255((c2[2] << 8) + ((int)c1[2] - (int)c2[2]) * death_age);
+ } else {
+ const uint8_t *c = v == ALIVE_CELL ? life->life_color : life->death_color;
+ AV_WB24(p, c[0]<<16 | c[1]<<8 | c[2]);
+ p += 3;
+ }
+ }
+ }
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ LifeContext *life = outlink->src->priv;
+ AVFrame *picref = ff_get_video_buffer(outlink, life->w, life->h);
+ if (!picref)
+ return AVERROR(ENOMEM);
+ picref->sample_aspect_ratio = (AVRational) {1, 1};
+ picref->pts = life->pts++;
+
+ life->draw(outlink->src, picref);
+ evolve(outlink->src);
+#ifdef DEBUG
+ show_life_grid(outlink->src);
+#endif
+ return ff_filter_frame(outlink, picref);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ LifeContext *life = ctx->priv;
+ enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NONE, AV_PIX_FMT_NONE };
+ AVFilterFormats *fmts_list;
+
+ if (life->mold || memcmp(life-> life_color, "\xff\xff\xff", 3)
+ || memcmp(life->death_color, "\x00\x00\x00", 3)) {
+ pix_fmts[0] = AV_PIX_FMT_RGB24;
+ life->draw = fill_picture_rgb;
+ } else {
+ pix_fmts[0] = AV_PIX_FMT_MONOBLACK;
+ life->draw = fill_picture_monoblack;
+ }
+
+ fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ ff_set_common_formats(ctx, fmts_list);
+ return 0;
+}
+
+static const AVFilterPad life_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL}
+};
+
+AVFilter ff_vsrc_life = {
+ .name = "life",
+ .description = NULL_IF_CONFIG_SMALL("Create life."),
+ .priv_size = sizeof(LifeContext),
+ .priv_class = &life_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = life_outputs,
+};
diff --git a/libavfilter/vsrc_mandelbrot.c b/libavfilter/vsrc_mandelbrot.c
new file mode 100644
index 0000000000..e26fecd968
--- /dev/null
+++ b/libavfilter/vsrc_mandelbrot.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2011 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
+ *
+ * The vsrc_color filter from Stefano Sabatini was used as template to create
+ * this
+ */
+
+/**
+ * @file
+ * Mandelbrot fraktal renderer
+ */
+
+#include "avfilter.h"
+#include "formats.h"
+#include "video.h"
+#include "internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include <float.h>
+#include <math.h>
+
+#define SQR(a) ((a)*(a))
+
+enum Outer{
+ ITERATION_COUNT,
+ NORMALIZED_ITERATION_COUNT,
+ WHITE,
+ OUTZ,
+};
+
+enum Inner{
+ BLACK,
+ PERIOD,
+ CONVTIME,
+ MINCOL,
+};
+
+typedef struct Point {
+ double p[2];
+ uint32_t val;
+} Point;
+
+typedef struct {
+ const AVClass *class;
+ int w, h;
+ AVRational frame_rate;
+ uint64_t pts;
+ int maxiter;
+ double start_x;
+ double start_y;
+ double start_scale;
+ double end_scale;
+ double end_pts;
+ double bailout;
+ int outer;
+ int inner;
+ int cache_allocated;
+ int cache_used;
+ Point *point_cache;
+ Point *next_cache;
+ double (*zyklus)[2];
+ uint32_t dither;
+
+ double morphxf;
+ double morphyf;
+ double morphamp;
+} MBContext;
+
+#define OFFSET(x) offsetof(MBContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption mandelbrot_options[] = {
+ {"size", "set frame size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="640x480"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ {"s", "set frame size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="640x480"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ {"rate", "set frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ {"r", "set frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ {"maxiter", "set max iterations number", OFFSET(maxiter), AV_OPT_TYPE_INT, {.i64=7189}, 1, INT_MAX, FLAGS },
+ {"start_x", "set the initial x position", OFFSET(start_x), AV_OPT_TYPE_DOUBLE, {.dbl=-0.743643887037158704752191506114774}, -100, 100, FLAGS },
+ {"start_y", "set the initial y position", OFFSET(start_y), AV_OPT_TYPE_DOUBLE, {.dbl=-0.131825904205311970493132056385139}, -100, 100, FLAGS },
+ {"start_scale", "set the initial scale value", OFFSET(start_scale), AV_OPT_TYPE_DOUBLE, {.dbl=3.0}, 0, FLT_MAX, FLAGS },
+ {"end_scale", "set the terminal scale value", OFFSET(end_scale), AV_OPT_TYPE_DOUBLE, {.dbl=0.3}, 0, FLT_MAX, FLAGS },
+ {"end_pts", "set the terminal pts value", OFFSET(end_pts), AV_OPT_TYPE_DOUBLE, {.dbl=400}, 0, INT64_MAX, FLAGS },
+ {"bailout", "set the bailout value", OFFSET(bailout), AV_OPT_TYPE_DOUBLE, {.dbl=10}, 0, FLT_MAX, FLAGS },
+ {"morphxf", "set morph x frequency", OFFSET(morphxf), AV_OPT_TYPE_DOUBLE, {.dbl=0.01}, -FLT_MAX, FLT_MAX, FLAGS },
+ {"morphyf", "set morph y frequency", OFFSET(morphyf), AV_OPT_TYPE_DOUBLE, {.dbl=0.0123}, -FLT_MAX, FLT_MAX, FLAGS },
+ {"morphamp", "set morph amplitude", OFFSET(morphamp), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -FLT_MAX, FLT_MAX, FLAGS },
+
+ {"outer", "set outer coloring mode", OFFSET(outer), AV_OPT_TYPE_INT, {.i64=NORMALIZED_ITERATION_COUNT}, 0, INT_MAX, FLAGS, "outer" },
+ {"iteration_count", "set iteration count mode", 0, AV_OPT_TYPE_CONST, {.i64=ITERATION_COUNT}, INT_MIN, INT_MAX, FLAGS, "outer" },
+ {"normalized_iteration_count", "set normalized iteration count mode", 0, AV_OPT_TYPE_CONST, {.i64=NORMALIZED_ITERATION_COUNT}, INT_MIN, INT_MAX, FLAGS, "outer" },
+ {"white", "set white mode", 0, AV_OPT_TYPE_CONST, {.i64=WHITE}, INT_MIN, INT_MAX, FLAGS, "outer" },
+ {"outz", "set outz mode", 0, AV_OPT_TYPE_CONST, {.i64=OUTZ}, INT_MIN, INT_MAX, FLAGS, "outer" },
+
+ {"inner", "set inner coloring mode", OFFSET(inner), AV_OPT_TYPE_INT, {.i64=MINCOL}, 0, INT_MAX, FLAGS, "inner" },
+ {"black", "set black mode", 0, AV_OPT_TYPE_CONST, {.i64=BLACK}, INT_MIN, INT_MAX, FLAGS, "inner"},
+ {"period", "set period mode", 0, AV_OPT_TYPE_CONST, {.i64=PERIOD}, INT_MIN, INT_MAX, FLAGS, "inner"},
+ {"convergence", "show time until convergence", 0, AV_OPT_TYPE_CONST, {.i64=CONVTIME}, INT_MIN, INT_MAX, FLAGS, "inner"},
+ {"mincol", "color based on point closest to the origin of the iterations", 0, AV_OPT_TYPE_CONST, {.i64=MINCOL}, INT_MIN, INT_MAX, FLAGS, "inner"},
+
+ {NULL},
+};
+
+AVFILTER_DEFINE_CLASS(mandelbrot);
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ MBContext *mb = ctx->priv;
+
+ mb->bailout *= mb->bailout;
+
+ mb->start_scale /=mb->h;
+ mb->end_scale /=mb->h;
+
+ mb->cache_allocated = mb->w * mb->h * 3;
+ mb->cache_used = 0;
+ mb->point_cache= av_malloc_array(mb->cache_allocated, sizeof(*mb->point_cache));
+ mb-> next_cache= av_malloc_array(mb->cache_allocated, sizeof(*mb-> next_cache));
+ mb-> zyklus = av_malloc_array(mb->maxiter + 16, sizeof(*mb->zyklus));
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ MBContext *mb = ctx->priv;
+
+ av_freep(&mb->point_cache);
+ av_freep(&mb-> next_cache);
+ av_freep(&mb->zyklus);
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_BGR32,
+ AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->src;
+ MBContext *mb = ctx->priv;
+
+ if (av_image_check_size(mb->w, mb->h, 0, ctx) < 0)
+ return AVERROR(EINVAL);
+
+ inlink->w = mb->w;
+ inlink->h = mb->h;
+ inlink->time_base = av_inv_q(mb->frame_rate);
+
+ return 0;
+}
+
+static void fill_from_cache(AVFilterContext *ctx, uint32_t *color, int *in_cidx, int *out_cidx, double py, double scale){
+ MBContext *mb = ctx->priv;
+ if(mb->morphamp)
+ return;
+ for(; *in_cidx < mb->cache_used; (*in_cidx)++){
+ Point *p= &mb->point_cache[*in_cidx];
+ int x;
+ if(p->p[1] > py)
+ break;
+ x= round((p->p[0] - mb->start_x) / scale + mb->w/2);
+ if(x<0 || x >= mb->w)
+ continue;
+ if(color) color[x] = p->val;
+ if(out_cidx && *out_cidx < mb->cache_allocated)
+ mb->next_cache[(*out_cidx)++]= *p;
+ }
+}
+
+static int interpol(MBContext *mb, uint32_t *color, int x, int y, int linesize)
+{
+ uint32_t a,b,c,d, i;
+ uint32_t ipol=0xFF000000;
+ int dist;
+
+ if(!x || !y || x+1==mb->w || y+1==mb->h)
+ return 0;
+
+ dist= FFMAX(FFABS(x-(mb->w>>1))*mb->h, FFABS(y-(mb->h>>1))*mb->w);
+
+ if(dist<(mb->w*mb->h>>3))
+ return 0;
+
+ a=color[(x+1) + (y+0)*linesize];
+ b=color[(x-1) + (y+1)*linesize];
+ c=color[(x+0) + (y+1)*linesize];
+ d=color[(x+1) + (y+1)*linesize];
+
+ if(a&&c){
+ b= color[(x-1) + (y+0)*linesize];
+ d= color[(x+0) + (y-1)*linesize];
+ }else if(b&&d){
+ a= color[(x+1) + (y-1)*linesize];
+ c= color[(x-1) + (y-1)*linesize];
+ }else if(c){
+ d= color[(x+0) + (y-1)*linesize];
+ a= color[(x-1) + (y+0)*linesize];
+ b= color[(x+1) + (y-1)*linesize];
+ }else if(d){
+ c= color[(x-1) + (y-1)*linesize];
+ a= color[(x-1) + (y+0)*linesize];
+ b= color[(x+1) + (y-1)*linesize];
+ }else
+ return 0;
+
+ for(i=0; i<3; i++){
+ int s= 8*i;
+ uint8_t ac= a>>s;
+ uint8_t bc= b>>s;
+ uint8_t cc= c>>s;
+ uint8_t dc= d>>s;
+ int ipolab= (ac + bc);
+ int ipolcd= (cc + dc);
+ if(FFABS(ipolab - ipolcd) > 5)
+ return 0;
+ if(FFABS(ac-bc)+FFABS(cc-dc) > 20)
+ return 0;
+ ipol |= ((ipolab + ipolcd + 2)/4)<<s;
+ }
+ color[x + y*linesize]= ipol;
+ return 1;
+}
+
+static void draw_mandelbrot(AVFilterContext *ctx, uint32_t *color, int linesize, int64_t pts)
+{
+ MBContext *mb = ctx->priv;
+ int x,y,i, in_cidx=0, next_cidx=0, tmp_cidx;
+ double scale= mb->start_scale*pow(mb->end_scale/mb->start_scale, pts/mb->end_pts);
+ int use_zyklus=0;
+ fill_from_cache(ctx, NULL, &in_cidx, NULL, mb->start_y+scale*(-mb->h/2-0.5), scale);
+ tmp_cidx= in_cidx;
+ memset(color, 0, sizeof(*color)*mb->w);
+ for(y=0; y<mb->h; y++){
+ int y1= y+1;
+ const double ci=mb->start_y+scale*(y-mb->h/2);
+ fill_from_cache(ctx, NULL, &in_cidx, &next_cidx, ci, scale);
+ if(y1<mb->h){
+ memset(color+linesize*y1, 0, sizeof(*color)*mb->w);
+ fill_from_cache(ctx, color+linesize*y1, &tmp_cidx, NULL, ci + 3*scale/2, scale);
+ }
+
+ for(x=0; x<mb->w; x++){
+ float av_uninit(epsilon);
+ const double cr=mb->start_x+scale*(x-mb->w/2);
+ double zr=cr;
+ double zi=ci;
+ uint32_t c=0;
+ double dv= mb->dither / (double)(1LL<<32);
+ mb->dither= mb->dither*1664525+1013904223;
+
+ if(color[x + y*linesize] & 0xFF000000)
+ continue;
+ if(!mb->morphamp){
+ if(interpol(mb, color, x, y, linesize)){
+ if(next_cidx < mb->cache_allocated){
+ mb->next_cache[next_cidx ].p[0]= cr;
+ mb->next_cache[next_cidx ].p[1]= ci;
+ mb->next_cache[next_cidx++].val = color[x + y*linesize];
+ }
+ continue;
+ }
+ }else{
+ zr += cos(pts * mb->morphxf) * mb->morphamp;
+ zi += sin(pts * mb->morphyf) * mb->morphamp;
+ }
+
+ use_zyklus= (x==0 || mb->inner!=BLACK ||color[x-1 + y*linesize] == 0xFF000000);
+ if(use_zyklus)
+ epsilon= scale*1*sqrt(SQR(x-mb->w/2) + SQR(y-mb->h/2))/mb->w;
+
+#define Z_Z2_C(outr,outi,inr,ini)\
+ outr= inr*inr - ini*ini + cr;\
+ outi= 2*inr*ini + ci;
+
+#define Z_Z2_C_ZYKLUS(outr,outi,inr,ini, Z)\
+ Z_Z2_C(outr,outi,inr,ini)\
+ if(use_zyklus){\
+ if(Z && fabs(mb->zyklus[i>>1][0]-outr)+fabs(mb->zyklus[i>>1][1]-outi) <= epsilon)\
+ break;\
+ }\
+ mb->zyklus[i][0]= outr;\
+ mb->zyklus[i][1]= outi;\
+
+
+
+ for(i=0; i<mb->maxiter-8; i++){
+ double t;
+ Z_Z2_C_ZYKLUS(t, zi, zr, zi, 0)
+ i++;
+ Z_Z2_C_ZYKLUS(zr, zi, t, zi, 1)
+ i++;
+ Z_Z2_C_ZYKLUS(t, zi, zr, zi, 0)
+ i++;
+ Z_Z2_C_ZYKLUS(zr, zi, t, zi, 1)
+ i++;
+ Z_Z2_C_ZYKLUS(t, zi, zr, zi, 0)
+ i++;
+ Z_Z2_C_ZYKLUS(zr, zi, t, zi, 1)
+ i++;
+ Z_Z2_C_ZYKLUS(t, zi, zr, zi, 0)
+ i++;
+ Z_Z2_C_ZYKLUS(zr, zi, t, zi, 1)
+ if(zr*zr + zi*zi > mb->bailout){
+ i-= FFMIN(7, i);
+ for(; i<mb->maxiter; i++){
+ zr= mb->zyklus[i][0];
+ zi= mb->zyklus[i][1];
+ if(zr*zr + zi*zi > mb->bailout){
+ switch(mb->outer){
+ case ITERATION_COUNT:
+ zr = i;
+ c = lrintf((sin(zr)+1)*127) + lrintf((sin(zr/1.234)+1)*127)*256*256 + lrintf((sin(zr/100)+1)*127)*256;
+ break;
+ case NORMALIZED_ITERATION_COUNT:
+ zr = i + log2(log(mb->bailout) / log(zr*zr + zi*zi));
+ c = lrintf((sin(zr)+1)*127) + lrintf((sin(zr/1.234)+1)*127)*256*256 + lrintf((sin(zr/100)+1)*127)*256;
+ break;
+ case WHITE:
+ c = 0xFFFFFF;
+ break;
+ case OUTZ:
+ zr /= mb->bailout;
+ zi /= mb->bailout;
+ c = (((int)(zr*128+128))&0xFF)*256 + (((int)(zi*128+128))&0xFF);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if(!c){
+ if(mb->inner==PERIOD){
+ int j;
+ for(j=i-1; j; j--)
+ if(SQR(mb->zyklus[j][0]-zr) + SQR(mb->zyklus[j][1]-zi) < epsilon*epsilon*10)
+ break;
+ if(j){
+ c= i-j;
+ c= ((c<<5)&0xE0) + ((c<<10)&0xE000) + ((c<<15)&0xE00000);
+ }
+ }else if(mb->inner==CONVTIME){
+ c= floor(i*255.0/mb->maxiter+dv)*0x010101;
+ } else if(mb->inner==MINCOL){
+ int j;
+ double closest=9999;
+ int closest_index=0;
+ for(j=i-1; j>=0; j--)
+ if(SQR(mb->zyklus[j][0]) + SQR(mb->zyklus[j][1]) < closest){
+ closest= SQR(mb->zyklus[j][0]) + SQR(mb->zyklus[j][1]);
+ closest_index= j;
+ }
+ closest = sqrt(closest);
+ c= lrintf((mb->zyklus[closest_index][0]/closest+1)*127+dv) + lrintf((mb->zyklus[closest_index][1]/closest+1)*127+dv)*256;
+ }
+ }
+ c |= 0xFF000000;
+ color[x + y*linesize]= c;
+ if(next_cidx < mb->cache_allocated){
+ mb->next_cache[next_cidx ].p[0]= cr;
+ mb->next_cache[next_cidx ].p[1]= ci;
+ mb->next_cache[next_cidx++].val = c;
+ }
+ }
+ fill_from_cache(ctx, NULL, &in_cidx, &next_cidx, ci + scale/2, scale);
+ }
+ FFSWAP(void*, mb->next_cache, mb->point_cache);
+ mb->cache_used = next_cidx;
+ if(mb->cache_used == mb->cache_allocated)
+ av_log(ctx, AV_LOG_INFO, "Mandelbrot cache is too small!\n");
+}
+
+static int request_frame(AVFilterLink *link)
+{
+ MBContext *mb = link->src->priv;
+ AVFrame *picref = ff_get_video_buffer(link, mb->w, mb->h);
+ if (!picref)
+ return AVERROR(ENOMEM);
+
+ picref->sample_aspect_ratio = (AVRational) {1, 1};
+ picref->pts = mb->pts++;
+
+ draw_mandelbrot(link->src, (uint32_t*)picref->data[0], picref->linesize[0]/4, picref->pts);
+ return ff_filter_frame(link, picref);
+}
+
+static const AVFilterPad mandelbrot_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vsrc_mandelbrot = {
+ .name = "mandelbrot",
+ .description = NULL_IF_CONFIG_SMALL("Render a Mandelbrot fractal."),
+ .priv_size = sizeof(MBContext),
+ .priv_class = &mandelbrot_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = mandelbrot_outputs,
+};
diff --git a/libavfilter/vsrc_movie.c b/libavfilter/vsrc_movie.c
deleted file mode 100644
index a99be39758..0000000000
--- a/libavfilter/vsrc_movie.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (c) 2010 Stefano Sabatini
- * Copyright (c) 2008 Victor Paesa
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * movie video source
- *
- * @todo use direct rendering (no allocation of a new frame)
- * @todo support a PTS correction mechanism
- * @todo support more than one output stream
- */
-
-#include <float.h>
-#include <stdint.h>
-
-#include "libavutil/attributes.h"
-#include "libavutil/avstring.h"
-#include "libavutil/opt.h"
-#include "libavutil/imgutils.h"
-#include "libavformat/avformat.h"
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-#include "video.h"
-
-typedef struct MovieContext {
- const AVClass *class;
- int64_t seek_point; ///< seekpoint in microseconds
- double seek_point_d;
- char *format_name;
- char *file_name;
- int stream_index;
-
- AVFormatContext *format_ctx;
- AVCodecContext *codec_ctx;
- int is_done;
- AVFrame *frame; ///< video frame to store the decoded images in
-
- int w, h;
-} MovieContext;
-
-#define OFFSET(x) offsetof(MovieContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-
-static const AVOption movie_options[]= {
- { "filename", NULL, OFFSET(file_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "format_name", "set format name", OFFSET(format_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "f", "set format name", OFFSET(format_name), AV_OPT_TYPE_STRING, .flags = FLAGS },
- { "stream_index", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
- { "si", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS },
- { "seek_point", "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, (INT64_MAX-1) / 1000000, FLAGS },
- { "sp", "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, 0, (INT64_MAX-1) / 1000000, FLAGS },
- { NULL },
-};
-
-static const char *movie_get_name(void *ctx)
-{
- return "movie";
-}
-
-static const AVClass movie_class = {
- "MovieContext",
- movie_get_name,
- movie_options
-};
-
-static av_cold int movie_init(AVFilterContext *ctx)
-{
- MovieContext *movie = ctx->priv;
- AVInputFormat *iformat = NULL;
- AVCodec *codec;
- int ret;
- int64_t timestamp;
-
- av_register_all();
-
- // Try to find the movie format (container)
- iformat = movie->format_name ? av_find_input_format(movie->format_name) : NULL;
-
- movie->format_ctx = NULL;
- if ((ret = avformat_open_input(&movie->format_ctx, movie->file_name, iformat, NULL)) < 0) {
- av_log(ctx, AV_LOG_ERROR,
- "Failed to avformat_open_input '%s'\n", movie->file_name);
- return ret;
- }
- if ((ret = avformat_find_stream_info(movie->format_ctx, NULL)) < 0)
- av_log(ctx, AV_LOG_WARNING, "Failed to find stream info\n");
-
- // if seeking requested, we execute it
- if (movie->seek_point > 0) {
- timestamp = movie->seek_point;
- // add the stream start time, should it exist
- if (movie->format_ctx->start_time != AV_NOPTS_VALUE) {
- if (timestamp > INT64_MAX - movie->format_ctx->start_time) {
- av_log(ctx, AV_LOG_ERROR,
- "%s: seek value overflow with start_time:%"PRId64" seek_point:%"PRId64"\n",
- movie->file_name, movie->format_ctx->start_time, movie->seek_point);
- return AVERROR(EINVAL);
- }
- timestamp += movie->format_ctx->start_time;
- }
- if ((ret = av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "%s: could not seek to position %"PRId64"\n",
- movie->file_name, timestamp);
- return ret;
- }
- }
-
- /* select the video stream */
- if ((ret = av_find_best_stream(movie->format_ctx, AVMEDIA_TYPE_VIDEO,
- movie->stream_index, -1, NULL, 0)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "No video stream with index '%d' found\n",
- movie->stream_index);
- return ret;
- }
- movie->stream_index = ret;
- movie->codec_ctx = movie->format_ctx->streams[movie->stream_index]->codec;
-
- /*
- * So now we've got a pointer to the so-called codec context for our video
- * stream, but we still have to find the actual codec and open it.
- */
- codec = avcodec_find_decoder(movie->codec_ctx->codec_id);
- if (!codec) {
- av_log(ctx, AV_LOG_ERROR, "Failed to find any codec\n");
- return AVERROR(EINVAL);
- }
-
- movie->codec_ctx->refcounted_frames = 1;
-
- if ((ret = avcodec_open2(movie->codec_ctx, codec, NULL)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Failed to open codec\n");
- return ret;
- }
-
- movie->w = movie->codec_ctx->width;
- movie->h = movie->codec_ctx->height;
-
- av_log(ctx, AV_LOG_VERBOSE, "seek_point:%"PRIi64" format_name:%s file_name:%s stream_index:%d\n",
- movie->seek_point, movie->format_name, movie->file_name,
- movie->stream_index);
-
- return 0;
-}
-
-static av_cold int init(AVFilterContext *ctx)
-{
- MovieContext *movie = ctx->priv;
-
- movie->seek_point = movie->seek_point_d * 1000000 + 0.5;
-
- return movie_init(ctx);
-}
-
-static av_cold void uninit(AVFilterContext *ctx)
-{
- MovieContext *movie = ctx->priv;
-
- if (movie->codec_ctx)
- avcodec_close(movie->codec_ctx);
- if (movie->format_ctx)
- avformat_close_input(&movie->format_ctx);
- av_frame_free(&movie->frame);
-}
-
-static int query_formats(AVFilterContext *ctx)
-{
- MovieContext *movie = ctx->priv;
- enum AVPixelFormat pix_fmts[] = { movie->codec_ctx->pix_fmt, AV_PIX_FMT_NONE };
-
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
-}
-
-static int config_output_props(AVFilterLink *outlink)
-{
- MovieContext *movie = outlink->src->priv;
-
- outlink->w = movie->w;
- outlink->h = movie->h;
- outlink->time_base = movie->format_ctx->streams[movie->stream_index]->time_base;
-
- return 0;
-}
-
-static int movie_get_frame(AVFilterLink *outlink)
-{
- MovieContext *movie = outlink->src->priv;
- AVPacket pkt;
- int ret, frame_decoded;
-
- if (movie->is_done == 1)
- return 0;
-
- movie->frame = av_frame_alloc();
- if (!movie->frame)
- return AVERROR(ENOMEM);
-
- while ((ret = av_read_frame(movie->format_ctx, &pkt)) >= 0) {
- // Is this a packet from the video stream?
- if (pkt.stream_index == movie->stream_index) {
- avcodec_decode_video2(movie->codec_ctx, movie->frame, &frame_decoded, &pkt);
-
- if (frame_decoded) {
- if (movie->frame->pkt_pts != AV_NOPTS_VALUE)
- movie->frame->pts = movie->frame->pkt_pts;
- av_log(outlink->src, AV_LOG_TRACE,
- "movie_get_frame(): file:'%s' pts:%"PRId64" time:%f aspect:%d/%d\n",
- movie->file_name, movie->frame->pts,
- (double)movie->frame->pts *
- av_q2d(movie->format_ctx->streams[movie->stream_index]->time_base),
- movie->frame->sample_aspect_ratio.num,
- movie->frame->sample_aspect_ratio.den);
- // We got it. Free the packet since we are returning
- av_free_packet(&pkt);
-
- return 0;
- }
- }
- // Free the packet that was allocated by av_read_frame
- av_free_packet(&pkt);
- }
-
- // On multi-frame source we should stop the mixing process when
- // the movie source does not have more frames
- if (ret == AVERROR_EOF)
- movie->is_done = 1;
- return ret;
-}
-
-static int request_frame(AVFilterLink *outlink)
-{
- MovieContext *movie = outlink->src->priv;
- int ret;
-
- if (movie->is_done)
- return AVERROR_EOF;
- if ((ret = movie_get_frame(outlink)) < 0)
- return ret;
-
- ret = ff_filter_frame(outlink, movie->frame);
- movie->frame = NULL;
-
- return ret;
-}
-
-static const AVFilterPad avfilter_vsrc_movie_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .request_frame = request_frame,
- .config_props = config_output_props,
- },
- { NULL }
-};
-
-AVFilter ff_vsrc_movie = {
- .name = "movie",
- .description = NULL_IF_CONFIG_SMALL("Read from a movie source."),
- .priv_size = sizeof(MovieContext),
- .priv_class = &movie_class,
- .init = init,
- .uninit = uninit,
- .query_formats = query_formats,
-
- .inputs = NULL,
- .outputs = avfilter_vsrc_movie_outputs,
-};
diff --git a/libavfilter/vsrc_mptestsrc.c b/libavfilter/vsrc_mptestsrc.c
new file mode 100644
index 0000000000..bc5b2cd252
--- /dev/null
+++ b/libavfilter/vsrc_mptestsrc.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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
+ * MP test source, ported from MPlayer libmpcodecs/vf_test.c
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "avfilter.h"
+#include "internal.h"
+#include "formats.h"
+#include "video.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+
+enum test_type {
+ TEST_DC_LUMA,
+ TEST_DC_CHROMA,
+ TEST_FREQ_LUMA,
+ TEST_FREQ_CHROMA,
+ TEST_AMP_LUMA,
+ TEST_AMP_CHROMA,
+ TEST_CBP,
+ TEST_MV,
+ TEST_RING1,
+ TEST_RING2,
+ TEST_ALL,
+ TEST_NB
+};
+
+typedef struct MPTestContext {
+ const AVClass *class;
+ AVRational frame_rate;
+ int64_t pts, max_pts, duration;
+ int hsub, vsub;
+ int test; ///< test_type
+} MPTestContext;
+
+#define OFFSET(x) offsetof(MPTestContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVOption mptestsrc_options[]= {
+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
+ { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
+ { "d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },
+
+ { "test", "set test to perform", OFFSET(test), AV_OPT_TYPE_INT, {.i64=TEST_ALL}, 0, INT_MAX, FLAGS, "test" },
+ { "t", "set test to perform", OFFSET(test), AV_OPT_TYPE_INT, {.i64=TEST_ALL}, 0, INT_MAX, FLAGS, "test" },
+ { "dc_luma", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_DC_LUMA}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "dc_chroma", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_DC_CHROMA}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "freq_luma", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_FREQ_LUMA}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "freq_chroma", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_FREQ_CHROMA}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "amp_luma", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_AMP_LUMA}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "amp_chroma", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_AMP_CHROMA}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "cbp", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_CBP}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "mv", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_MV}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "ring1", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_RING1}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "ring2", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_RING2}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { "all", "", 0, AV_OPT_TYPE_CONST, {.i64=TEST_ALL}, INT_MIN, INT_MAX, FLAGS, "test" },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(mptestsrc);
+
+static double c[64];
+
+static void init_idct(void)
+{
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ double s = i == 0 ? sqrt(0.125) : 0.5;
+
+ for (j = 0; j < 8; j++)
+ c[i*8+j] = s*cos((M_PI/8.0)*i*(j+0.5));
+ }
+}
+
+static void idct(uint8_t *dst, int dst_linesize, int src[64])
+{
+ int i, j, k;
+ double tmp[64];
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++) {
+ double sum = 0.0;
+
+ for (k = 0; k < 8; k++)
+ sum += c[k*8+j] * src[8*i+k];
+
+ tmp[8*i+j] = sum;
+ }
+ }
+
+ for (j = 0; j < 8; j++) {
+ for (i = 0; i < 8; i++) {
+ double sum = 0.0;
+
+ for (k = 0; k < 8; k++)
+ sum += c[k*8+i]*tmp[8*k+j];
+
+ dst[dst_linesize*i + j] = av_clip_uint8((int)floor(sum+0.5));
+ }
+ }
+}
+
+static void draw_dc(uint8_t *dst, int dst_linesize, int color, int w, int h)
+{
+ int x, y;
+
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++)
+ dst[x + y*dst_linesize] = color;
+}
+
+static void draw_basis(uint8_t *dst, int dst_linesize, int amp, int freq, int dc)
+{
+ int src[64];
+
+ memset(src, 0, 64*sizeof(int));
+ src[0] = dc;
+ if (amp)
+ src[freq] = amp;
+ idct(dst, dst_linesize, src);
+}
+
+static void draw_cbp(uint8_t *dst[3], int dst_linesize[3], int cbp, int amp, int dc)
+{
+ if (cbp&1) draw_basis(dst[0] , dst_linesize[0], amp, 1, dc);
+ if (cbp&2) draw_basis(dst[0]+8 , dst_linesize[0], amp, 1, dc);
+ if (cbp&4) draw_basis(dst[0]+ 8*dst_linesize[0], dst_linesize[0], amp, 1, dc);
+ if (cbp&8) draw_basis(dst[0]+8+8*dst_linesize[0], dst_linesize[0], amp, 1, dc);
+ if (cbp&16) draw_basis(dst[1] , dst_linesize[1], amp, 1, dc);
+ if (cbp&32) draw_basis(dst[2] , dst_linesize[2], amp, 1, dc);
+}
+
+static void dc_test(uint8_t *dst, int dst_linesize, int w, int h, int off)
+{
+ const int step = FFMAX(256/(w*h/256), 1);
+ int x, y, color = off;
+
+ for (y = 0; y < h; y += 16) {
+ for (x = 0; x < w; x += 16) {
+ draw_dc(dst + x + y*dst_linesize, dst_linesize, color, 8, 8);
+ color += step;
+ }
+ }
+}
+
+static void freq_test(uint8_t *dst, int dst_linesize, int off)
+{
+ int x, y, freq = 0;
+
+ for (y = 0; y < 8*16; y += 16) {
+ for (x = 0; x < 8*16; x += 16) {
+ draw_basis(dst + x + y*dst_linesize, dst_linesize, 4*(96+off), freq, 128*8);
+ freq++;
+ }
+ }
+}
+
+static void amp_test(uint8_t *dst, int dst_linesize, int off)
+{
+ int x, y, amp = off;
+
+ for (y = 0; y < 16*16; y += 16) {
+ for (x = 0; x < 16*16; x += 16) {
+ draw_basis(dst + x + y*dst_linesize, dst_linesize, 4*amp, 1, 128*8);
+ amp++;
+ }
+ }
+}
+
+static void cbp_test(uint8_t *dst[3], int dst_linesize[3], int off)
+{
+ int x, y, cbp = 0;
+
+ for (y = 0; y < 16*8; y += 16) {
+ for (x = 0; x < 16*8; x += 16) {
+ uint8_t *dst1[3];
+ dst1[0] = dst[0] + x*2 + y*2*dst_linesize[0];
+ dst1[1] = dst[1] + x + y* dst_linesize[1];
+ dst1[2] = dst[2] + x + y* dst_linesize[2];
+
+ draw_cbp(dst1, dst_linesize, cbp, (64+off)*4, 128*8);
+ cbp++;
+ }
+ }
+}
+
+static void mv_test(uint8_t *dst, int dst_linesize, int off)
+{
+ int x, y;
+
+ for (y = 0; y < 16*16; y++) {
+ if (y&16)
+ continue;
+ for (x = 0; x < 16*16; x++)
+ dst[x + y*dst_linesize] = x + off*8/(y/32+1);
+ }
+}
+
+static void ring1_test(uint8_t *dst, int dst_linesize, int off)
+{
+ int x, y, color = 0;
+
+ for (y = off; y < 16*16; y += 16) {
+ for (x = off; x < 16*16; x += 16) {
+ draw_dc(dst + x + y*dst_linesize, dst_linesize, ((x+y)&16) ? color : -color, 16, 16);
+ color++;
+ }
+ }
+}
+
+static void ring2_test(uint8_t *dst, int dst_linesize, int off)
+{
+ int x, y;
+
+ for (y = 0; y < 16*16; y++) {
+ for (x = 0; x < 16*16; x++) {
+ double d = sqrt((x-8*16)*(x-8*16) + (y-8*16)*(y-8*16));
+ double r = d/20 - (int)(d/20);
+ if (r < off/30.0) {
+ dst[x + y*dst_linesize] = 255;
+ dst[x + y*dst_linesize+256] = 0;
+ } else {
+ dst[x + y*dst_linesize] = x;
+ dst[x + y*dst_linesize+256] = x;
+ }
+ }
+ }
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ MPTestContext *test = ctx->priv;
+
+ test->max_pts = test->duration >= 0 ?
+ av_rescale_q(test->duration, AV_TIME_BASE_Q, av_inv_q(test->frame_rate)) : -1;
+ test->pts = 0;
+
+ av_log(ctx, AV_LOG_VERBOSE, "rate:%d/%d duration:%f\n",
+ test->frame_rate.num, test->frame_rate.den,
+ test->duration < 0 ? -1 : test->max_pts * av_q2d(av_inv_q(test->frame_rate)));
+ init_idct();
+
+ return 0;
+}
+
+static int config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ MPTestContext *test = ctx->priv;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(outlink->format);
+
+ test->hsub = pix_desc->log2_chroma_w;
+ test->vsub = pix_desc->log2_chroma_h;
+
+ outlink->w = WIDTH;
+ outlink->h = HEIGHT;
+ outlink->time_base = av_inv_q(test->frame_rate);
+
+ return 0;
+}
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ MPTestContext *test = outlink->src->priv;
+ AVFrame *picref;
+ int w = WIDTH, h = HEIGHT,
+ cw = FF_CEIL_RSHIFT(w, test->hsub), ch = FF_CEIL_RSHIFT(h, test->vsub);
+ unsigned int frame = outlink->frame_count;
+ enum test_type tt = test->test;
+ int i;
+
+ if (test->max_pts >= 0 && test->pts > test->max_pts)
+ return AVERROR_EOF;
+ picref = ff_get_video_buffer(outlink, w, h);
+ if (!picref)
+ return AVERROR(ENOMEM);
+ picref->pts = test->pts++;
+
+ // clean image
+ for (i = 0; i < h; i++)
+ memset(picref->data[0] + i*picref->linesize[0], 0, w);
+ for (i = 0; i < ch; i++) {
+ memset(picref->data[1] + i*picref->linesize[1], 128, cw);
+ memset(picref->data[2] + i*picref->linesize[2], 128, cw);
+ }
+
+ if (tt == TEST_ALL && frame%30) /* draw a black frame at the beginning of each test */
+ tt = (frame/30)%(TEST_NB-1);
+
+ switch (tt) {
+ case TEST_DC_LUMA: dc_test(picref->data[0], picref->linesize[0], 256, 256, frame%30); break;
+ case TEST_DC_CHROMA: dc_test(picref->data[1], picref->linesize[1], 256, 256, frame%30); break;
+ case TEST_FREQ_LUMA: freq_test(picref->data[0], picref->linesize[0], frame%30); break;
+ case TEST_FREQ_CHROMA: freq_test(picref->data[1], picref->linesize[1], frame%30); break;
+ case TEST_AMP_LUMA: amp_test(picref->data[0], picref->linesize[0], frame%30); break;
+ case TEST_AMP_CHROMA: amp_test(picref->data[1], picref->linesize[1], frame%30); break;
+ case TEST_CBP: cbp_test(picref->data , picref->linesize , frame%30); break;
+ case TEST_MV: mv_test(picref->data[0], picref->linesize[0], frame%30); break;
+ case TEST_RING1: ring1_test(picref->data[0], picref->linesize[0], frame%30); break;
+ case TEST_RING2: ring2_test(picref->data[0], picref->linesize[0], frame%30); break;
+ }
+
+ return ff_filter_frame(outlink, picref);
+}
+
+static const AVFilterPad mptestsrc_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vsrc_mptestsrc = {
+ .name = "mptestsrc",
+ .description = NULL_IF_CONFIG_SMALL("Generate various test pattern."),
+ .priv_size = sizeof(MPTestContext),
+ .priv_class = &mptestsrc_class,
+ .init = init,
+ .query_formats = query_formats,
+ .inputs = NULL,
+ .outputs = mptestsrc_outputs,
+};
diff --git a/libavfilter/vsrc_nullsrc.c b/libavfilter/vsrc_nullsrc.c
deleted file mode 100644
index 63e90fdd1a..0000000000
--- a/libavfilter/vsrc_nullsrc.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * null video source
- */
-
-#include <stdio.h>
-
-#include "libavutil/avstring.h"
-#include "libavutil/eval.h"
-#include "libavutil/internal.h"
-#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
-#include "libavutil/parseutils.h"
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-
-static const char *const var_names[] = {
- "E",
- "PHI",
- "PI",
- "AVTB", /* default timebase 1/AV_TIME_BASE */
- NULL
-};
-
-enum var_name {
- VAR_E,
- VAR_PHI,
- VAR_PI,
- VAR_AVTB,
- VAR_VARS_NB
-};
-
-typedef struct NullContext {
- const AVClass *class;
- int w, h;
- char *tb_expr;
- double var_values[VAR_VARS_NB];
-} NullContext;
-
-static int config_props(AVFilterLink *outlink)
-{
- AVFilterContext *ctx = outlink->src;
- NullContext *priv = ctx->priv;
- AVRational tb;
- int ret;
- double res;
-
- priv->var_values[VAR_E] = M_E;
- priv->var_values[VAR_PHI] = M_PHI;
- priv->var_values[VAR_PI] = M_PI;
- priv->var_values[VAR_AVTB] = av_q2d(AV_TIME_BASE_Q);
-
- if ((ret = av_expr_parse_and_eval(&res, priv->tb_expr, var_names, priv->var_values,
- NULL, NULL, NULL, NULL, NULL, 0, NULL)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid expression '%s' for timebase.\n", priv->tb_expr);
- return ret;
- }
- tb = av_d2q(res, INT_MAX);
- if (tb.num <= 0 || tb.den <= 0) {
- av_log(ctx, AV_LOG_ERROR,
- "Invalid non-positive value for the timebase %d/%d.\n",
- tb.num, tb.den);
- return AVERROR(EINVAL);
- }
-
- outlink->w = priv->w;
- outlink->h = priv->h;
- outlink->time_base = tb;
-
- av_log(outlink->src, AV_LOG_VERBOSE, "w:%d h:%d tb:%d/%d\n", priv->w, priv->h,
- tb.num, tb.den);
-
- return 0;
-}
-
-static int request_frame(AVFilterLink *link)
-{
- return -1;
-}
-
-#define OFFSET(x) offsetof(NullContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption options[] = {
- { "width", NULL, OFFSET(w), AV_OPT_TYPE_INT, { .i64 = 352 }, 1, INT_MAX, FLAGS },
- { "height", NULL, OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 288 }, 1, INT_MAX, FLAGS },
- { "timebase", NULL, OFFSET(tb_expr), AV_OPT_TYPE_STRING, { .str = "AVTB" }, 0, 0, FLAGS },
- { NULL },
-};
-
-static const AVClass nullsrc_class = {
- .class_name = "nullsrc",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
-
-static const AVFilterPad avfilter_vsrc_nullsrc_outputs[] = {
- {
- .name = "default",
- .type = AVMEDIA_TYPE_VIDEO,
- .config_props = config_props,
- .request_frame = request_frame,
- },
- { NULL }
-};
-
-AVFilter ff_vsrc_nullsrc = {
- .name = "nullsrc",
- .description = NULL_IF_CONFIG_SMALL("Null video source, never return images."),
-
- .priv_size = sizeof(NullContext),
- .priv_class = &nullsrc_class,
-
- .inputs = NULL,
-
- .outputs = avfilter_vsrc_nullsrc_outputs,
-};
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index e41625ef9a..7f981bad23 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -1,21 +1,22 @@
/*
* Copyright (c) 2007 Nicolas George <nicolas.george@normalesup.org>
* Copyright (c) 2011 Stefano Sabatini
+ * Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,87 +29,96 @@
*
* rgbtestsrc is ported from MPlayer libmpcodecs/vf_rgbtest.c by
* Michael Niedermayer.
+ *
+ * smptebars and smptehdbars are by Paul B Mahol.
*/
#include <float.h>
+#include "libavutil/avassert.h"
#include "libavutil/common.h"
-#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/parseutils.h"
#include "avfilter.h"
+#include "drawutils.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
typedef struct TestSourceContext {
const AVClass *class;
- int h, w;
+ int w, h;
unsigned int nb_frame;
- AVRational time_base;
- int64_t pts, max_pts;
- char *size; ///< video frame size
- char *rate; ///< video frame rate
- char *duration; ///< total duration of the generated video
+ AVRational time_base, frame_rate;
+ int64_t pts;
+ int64_t duration; ///< duration expressed in microseconds
AVRational sar; ///< sample aspect ratio
+ int draw_once; ///< draw only the first frame, always put out the same picture
+ int draw_once_reset; ///< draw only the first frame or in case of reset
+ AVFrame *picref; ///< cached reference containing the painted picture
void (* fill_picture_fn)(AVFilterContext *ctx, AVFrame *frame);
+ /* only used by testsrc */
+ int nb_decimals;
+
+ /* only used by color */
+ FFDrawContext draw;
+ FFDrawColor color;
+ uint8_t color_rgba[4];
+
/* only used by rgbtest */
- int rgba_map[4];
+ uint8_t rgba_map[4];
+
+ /* only used by haldclut */
+ int level;
} TestSourceContext;
#define OFFSET(x) offsetof(TestSourceContext, x)
-#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
-static const AVOption testsrc_options[] = {
- { "size", "set video size", OFFSET(size), AV_OPT_TYPE_STRING, {.str = "320x240"}, .flags = FLAGS },
- { "s", "set video size", OFFSET(size), AV_OPT_TYPE_STRING, {.str = "320x240"}, .flags = FLAGS },
- { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_STRING, {.str = "25"}, .flags = FLAGS },
- { "r", "set video rate", OFFSET(rate), AV_OPT_TYPE_STRING, {.str = "25"}, .flags = FLAGS },
- { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = FLAGS },
- { "sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl = 1}, 0, INT_MAX, FLAGS },
- { NULL },
-};
+#define SIZE_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 },\
-static av_cold int init_common(AVFilterContext *ctx)
-{
- TestSourceContext *test = ctx->priv;
- AVRational frame_rate_q;
- int64_t duration = -1;
- int ret = 0;
+#define COMMON_OPTIONS_NOSIZE \
+ { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
+ { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },\
+ { "duration", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\
+ { "d", "set video duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = -1}, -1, INT64_MAX, FLAGS },\
+ { "sar", "set video sample aspect ratio", OFFSET(sar), AV_OPT_TYPE_RATIONAL, {.dbl= 1}, 0, INT_MAX, FLAGS },
- if ((ret = av_parse_video_size(&test->w, &test->h, test->size)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid frame size: '%s'\n", test->size);
- return ret;
- }
+#define COMMON_OPTIONS SIZE_OPTIONS COMMON_OPTIONS_NOSIZE
- if ((ret = av_parse_video_rate(&frame_rate_q, test->rate)) < 0 ||
- frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", test->rate);
- return ret;
- }
+static const AVOption options[] = {
+ COMMON_OPTIONS
+ { NULL }
+};
- if ((test->duration) && (ret = av_parse_time(&duration, test->duration, 1)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", test->duration);
- return ret;
- }
+static av_cold int init(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
- test->time_base.num = frame_rate_q.den;
- test->time_base.den = frame_rate_q.num;
- test->max_pts = duration >= 0 ?
- av_rescale_q(duration, AV_TIME_BASE_Q, test->time_base) : -1;
+ test->time_base = av_inv_q(test->frame_rate);
test->nb_frame = 0;
test->pts = 0;
- av_log(ctx, AV_LOG_DEBUG, "size:%dx%d rate:%d/%d duration:%f sar:%d/%d\n",
- test->w, test->h, frame_rate_q.num, frame_rate_q.den,
- duration < 0 ? -1 : test->max_pts * av_q2d(test->time_base),
+ av_log(ctx, AV_LOG_VERBOSE, "size:%dx%d rate:%d/%d duration:%f sar:%d/%d\n",
+ test->w, test->h, test->frame_rate.num, test->frame_rate.den,
+ test->duration < 0 ? -1 : (double)test->duration/1000000,
test->sar.num, test->sar.den);
return 0;
}
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+
+ av_frame_free(&test->picref);
+}
+
static int config_props(AVFilterLink *outlink)
{
TestSourceContext *test = outlink->src->priv;
@@ -116,7 +126,8 @@ static int config_props(AVFilterLink *outlink)
outlink->w = test->w;
outlink->h = test->h;
outlink->sample_aspect_ratio = test->sar;
- outlink->time_base = test->time_base;
+ outlink->frame_rate = test->frame_rate;
+ outlink->time_base = test->time_base;
return 0;
}
@@ -126,36 +137,322 @@ static int request_frame(AVFilterLink *outlink)
TestSourceContext *test = outlink->src->priv;
AVFrame *frame;
- if (test->max_pts >= 0 && test->pts > test->max_pts)
+ if (test->duration >= 0 &&
+ av_rescale_q(test->pts, test->time_base, AV_TIME_BASE_Q) >= test->duration)
return AVERROR_EOF;
- frame = ff_get_video_buffer(outlink, test->w, test->h);
+
+ if (test->draw_once) {
+ if (test->draw_once_reset) {
+ av_frame_free(&test->picref);
+ test->draw_once_reset = 0;
+ }
+ if (!test->picref) {
+ test->picref =
+ ff_get_video_buffer(outlink, test->w, test->h);
+ if (!test->picref)
+ return AVERROR(ENOMEM);
+ test->fill_picture_fn(outlink->src, test->picref);
+ }
+ frame = av_frame_clone(test->picref);
+ } else
+ frame = ff_get_video_buffer(outlink, test->w, test->h);
+
if (!frame)
return AVERROR(ENOMEM);
-
- frame->pts = test->pts++;
+ frame->pts = test->pts;
frame->key_frame = 1;
frame->interlaced_frame = 0;
frame->pict_type = AV_PICTURE_TYPE_I;
frame->sample_aspect_ratio = test->sar;
+ if (!test->draw_once)
+ test->fill_picture_fn(outlink->src, frame);
+
+ test->pts++;
test->nb_frame++;
- test->fill_picture_fn(outlink->src, frame);
return ff_filter_frame(outlink, frame);
}
-#if CONFIG_TESTSRC_FILTER
+#if CONFIG_COLOR_FILTER
+
+static const AVOption color_options[] = {
+ { "color", "set color", OFFSET(color_rgba), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ { "c", "set color", OFFSET(color_rgba), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS },
+ COMMON_OPTIONS
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(color);
-static const char *testsrc_get_name(void *ctx)
+static void color_fill_picture(AVFilterContext *ctx, AVFrame *picref)
{
- return "testsrc";
+ TestSourceContext *test = ctx->priv;
+ ff_fill_rectangle(&test->draw, &test->color,
+ picref->data, picref->linesize,
+ 0, 0, test->w, test->h);
}
-static const AVClass testsrc_class = {
- .class_name = "TestSourceContext",
- .item_name = testsrc_get_name,
- .option = testsrc_options,
+static av_cold int color_init(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+ test->fill_picture_fn = color_fill_picture;
+ test->draw_once = 1;
+ return init(ctx);
+}
+
+static int color_query_formats(AVFilterContext *ctx)
+{
+ return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+}
+
+static int color_config_props(AVFilterLink *inlink)
+{
+ AVFilterContext *ctx = inlink->src;
+ TestSourceContext *test = ctx->priv;
+ int ret;
+
+ ff_draw_init(&test->draw, inlink->format, 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);
+
+ if ((ret = config_props(inlink)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int color_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
+ char *res, int res_len, int flags)
+{
+ TestSourceContext *test = ctx->priv;
+ int ret;
+
+ if (!strcmp(cmd, "color") || !strcmp(cmd, "c")) {
+ uint8_t color_rgba[4];
+
+ ret = av_parse_color(color_rgba, args, -1, ctx);
+ if (ret < 0)
+ return ret;
+
+ memcpy(test->color_rgba, color_rgba, sizeof(color_rgba));
+ ff_draw_color(&test->draw, &test->color, test->color_rgba);
+ test->draw_once_reset = 1;
+ return 0;
+ }
+
+ return AVERROR(ENOSYS);
+}
+
+static const AVFilterPad color_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = color_config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vsrc_color = {
+ .name = "color",
+ .description = NULL_IF_CONFIG_SMALL("Provide an uniformly colored input."),
+ .priv_class = &color_class,
+ .priv_size = sizeof(TestSourceContext),
+ .init = color_init,
+ .uninit = uninit,
+ .query_formats = color_query_formats,
+ .inputs = NULL,
+ .outputs = color_outputs,
+ .process_command = color_process_command,
};
+#endif /* CONFIG_COLOR_FILTER */
+
+#if CONFIG_HALDCLUTSRC_FILTER
+
+static const AVOption haldclutsrc_options[] = {
+ { "level", "set level", OFFSET(level), AV_OPT_TYPE_INT, {.i64 = 6}, 2, 8, FLAGS },
+ COMMON_OPTIONS_NOSIZE
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(haldclutsrc);
+
+static void haldclutsrc_fill_picture(AVFilterContext *ctx, AVFrame *frame)
+{
+ int i, j, k, x = 0, y = 0, is16bit = 0, step;
+ uint32_t alpha = 0;
+ const TestSourceContext *hc = ctx->priv;
+ int level = hc->level;
+ float scale;
+ const int w = frame->width;
+ const int h = frame->height;
+ const uint8_t *data = frame->data[0];
+ const int linesize = frame->linesize[0];
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+ uint8_t rgba_map[4];
+
+ av_assert0(w == h && w == level*level*level);
+
+ ff_fill_rgba_map(rgba_map, frame->format);
+
+ switch (frame->format) {
+ case AV_PIX_FMT_RGB48:
+ case AV_PIX_FMT_BGR48:
+ case AV_PIX_FMT_RGBA64:
+ case AV_PIX_FMT_BGRA64:
+ is16bit = 1;
+ alpha = 0xffff;
+ break;
+ case AV_PIX_FMT_RGBA:
+ case AV_PIX_FMT_BGRA:
+ case AV_PIX_FMT_ARGB:
+ case AV_PIX_FMT_ABGR:
+ alpha = 0xff;
+ break;
+ }
+
+ step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit);
+ scale = ((float)(1 << (8*(is16bit+1))) - 1) / (level*level - 1);
+
+#define LOAD_CLUT(nbits) do { \
+ uint##nbits##_t *dst = ((uint##nbits##_t *)(data + y*linesize)) + x*step; \
+ dst[rgba_map[0]] = av_clip_uint##nbits(i * scale); \
+ dst[rgba_map[1]] = av_clip_uint##nbits(j * scale); \
+ dst[rgba_map[2]] = av_clip_uint##nbits(k * scale); \
+ if (step == 4) \
+ dst[rgba_map[3]] = alpha; \
+} while (0)
+
+ level *= level;
+ for (k = 0; k < level; k++) {
+ for (j = 0; j < level; j++) {
+ for (i = 0; i < level; i++) {
+ if (!is16bit)
+ LOAD_CLUT(8);
+ else
+ LOAD_CLUT(16);
+ if (++x == w) {
+ x = 0;
+ y++;
+ }
+ }
+ }
+ }
+}
+
+static av_cold int haldclutsrc_init(AVFilterContext *ctx)
+{
+ TestSourceContext *hc = ctx->priv;
+ hc->fill_picture_fn = haldclutsrc_fill_picture;
+ hc->draw_once = 1;
+ return init(ctx);
+}
+
+static int haldclutsrc_query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
+ AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
+ AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR,
+ AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR,
+ AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
+ AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48,
+ AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
+ AV_PIX_FMT_NONE,
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static int haldclutsrc_config_props(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ TestSourceContext *hc = ctx->priv;
+
+ hc->w = hc->h = hc->level * hc->level * hc->level;
+ return config_props(outlink);
+}
+
+static const AVFilterPad haldclutsrc_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = haldclutsrc_config_props,
+ },
+ { NULL }
+};
+
+AVFilter ff_vsrc_haldclutsrc = {
+ .name = "haldclutsrc",
+ .description = NULL_IF_CONFIG_SMALL("Provide an identity Hald CLUT."),
+ .priv_class = &haldclutsrc_class,
+ .priv_size = sizeof(TestSourceContext),
+ .init = haldclutsrc_init,
+ .uninit = uninit,
+ .query_formats = haldclutsrc_query_formats,
+ .inputs = NULL,
+ .outputs = haldclutsrc_outputs,
+};
+#endif /* CONFIG_HALDCLUTSRC_FILTER */
+
+#if CONFIG_NULLSRC_FILTER
+
+#define nullsrc_options options
+AVFILTER_DEFINE_CLASS(nullsrc);
+
+static void nullsrc_fill_picture(AVFilterContext *ctx, AVFrame *picref) { }
+
+static av_cold int nullsrc_init(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+
+ test->fill_picture_fn = nullsrc_fill_picture;
+ return init(ctx);
+}
+
+static const AVFilterPad nullsrc_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL },
+};
+
+AVFilter ff_vsrc_nullsrc = {
+ .name = "nullsrc",
+ .description = NULL_IF_CONFIG_SMALL("Null video source, return unprocessed video frames."),
+ .init = nullsrc_init,
+ .uninit = uninit,
+ .priv_size = sizeof(TestSourceContext),
+ .priv_class = &nullsrc_class,
+ .inputs = NULL,
+ .outputs = nullsrc_outputs,
+};
+
+#endif /* CONFIG_NULLSRC_FILTER */
+
+#if CONFIG_TESTSRC_FILTER
+
+static const AVOption testsrc_options[] = {
+ COMMON_OPTIONS
+ { "decimals", "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.i64=0}, 0, 17, FLAGS },
+ { "n", "set number of decimals to show", OFFSET(nb_decimals), AV_OPT_TYPE_INT, {.i64=0}, 0, 17, FLAGS },
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(testsrc);
+
/**
* Fill a rectangle with value val.
*
@@ -168,8 +465,8 @@ static const AVClass testsrc_class = {
* @param w width of the rectangle to draw, expressed as a number of segment_width units
* @param h height of the rectangle to draw, expressed as a number of segment_width units
*/
-static void draw_rectangle(unsigned val, uint8_t *dst, int dst_linesize, unsigned segment_width,
- unsigned x, unsigned y, unsigned w, unsigned h)
+static void draw_rectangle(unsigned val, uint8_t *dst, int dst_linesize, int segment_width,
+ int x, int y, int w, int h)
{
int i;
int step = 3;
@@ -183,8 +480,8 @@ static void draw_rectangle(unsigned val, uint8_t *dst, int dst_linesize, unsigne
}
}
-static void draw_digit(int digit, uint8_t *dst, unsigned dst_linesize,
- unsigned segment_width)
+static void draw_digit(int digit, uint8_t *dst, int dst_linesize,
+ int segment_width)
{
#define TOP_HBAR 1
#define MID_HBAR 2
@@ -278,7 +575,7 @@ static void test_fill_picture(AVFilterContext *ctx, AVFrame *frame)
}
/* draw sliding color line */
- p = data + frame->linesize[0] * height * 3/4;
+ p0 = p = data + frame->linesize[0] * (height * 3/4);
grad = (256 * test->nb_frame * test->time_base.num / test->time_base.den) %
GRADIENT_SIZE;
rgrad = 0;
@@ -306,15 +603,25 @@ static void test_fill_picture(AVFilterContext *ctx, AVFrame *frame)
if (grad >= GRADIENT_SIZE)
grad -= GRADIENT_SIZE;
}
+ p = p0;
for (y = height / 8; y > 0; y--) {
- memcpy(p, p - frame->linesize[0], 3 * width);
+ memcpy(p+frame->linesize[0], p, 3 * width);
p += frame->linesize[0];
}
/* draw digits */
seg_size = width / 80;
if (seg_size >= 1 && height >= 13 * seg_size) {
- second = test->nb_frame * test->time_base.num / test->time_base.den;
+ int64_t p10decimals = 1;
+ double time = av_q2d(test->time_base) * test->nb_frame *
+ pow(10, test->nb_decimals);
+ if (time >= INT_MAX)
+ return;
+
+ for (x = 0; x < test->nb_decimals; x++)
+ p10decimals *= 10;
+
+ second = av_rescale_rnd(test->nb_frame * test->time_base.num, p10decimals, test->time_base.den, AV_ROUND_ZERO);
x = width - (width - seg_size * 64) / 2;
y = (height - seg_size * 13) / 2;
p = data + (x*3 + y * frame->linesize[0]);
@@ -333,7 +640,7 @@ static av_cold int test_init(AVFilterContext *ctx)
TestSourceContext *test = ctx->priv;
test->fill_picture_fn = test_fill_picture;
- return init_common(ctx);
+ return init(ctx);
}
static int test_query_formats(AVFilterContext *ctx)
@@ -341,8 +648,11 @@ static int test_query_formats(AVFilterContext *ctx)
static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {
@@ -361,28 +671,18 @@ AVFilter ff_vsrc_testsrc = {
.priv_size = sizeof(TestSourceContext),
.priv_class = &testsrc_class,
.init = test_init,
-
+ .uninit = uninit,
.query_formats = test_query_formats,
-
- .inputs = NULL,
-
- .outputs = avfilter_vsrc_testsrc_outputs,
+ .inputs = NULL,
+ .outputs = avfilter_vsrc_testsrc_outputs,
};
#endif /* CONFIG_TESTSRC_FILTER */
#if CONFIG_RGBTESTSRC_FILTER
-static const char *rgbtestsrc_get_name(void *ctx)
-{
- return "rgbtestsrc";
-}
-
-static const AVClass rgbtestsrc_class = {
- .class_name = "RGBTestSourceContext",
- .item_name = rgbtestsrc_get_name,
- .option = testsrc_options,
-};
+#define rgbtestsrc_options options
+AVFILTER_DEFINE_CLASS(rgbtestsrc);
#define R 0
#define G 1
@@ -391,7 +691,7 @@ static const AVClass rgbtestsrc_class = {
static void rgbtest_put_pixel(uint8_t *dst, int dst_linesize,
int x, int y, int r, int g, int b, enum AVPixelFormat fmt,
- int rgba_map[4])
+ uint8_t rgba_map[4])
{
int32_t v;
uint8_t *p;
@@ -413,7 +713,7 @@ static void rgbtest_put_pixel(uint8_t *dst, int dst_linesize,
case AV_PIX_FMT_BGRA:
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_ABGR:
- v = (r << (rgba_map[R]*8)) + (g << (rgba_map[G]*8)) + (b << (rgba_map[B]*8));
+ v = (r << (rgba_map[R]*8)) + (g << (rgba_map[G]*8)) + (b << (rgba_map[B]*8)) + (255 << (rgba_map[A]*8));
p = dst + 4*x + y*dst_linesize;
AV_WL32(p, v);
break;
@@ -444,8 +744,9 @@ static av_cold int rgbtest_init(AVFilterContext *ctx)
{
TestSourceContext *test = ctx->priv;
+ test->draw_once = 1;
test->fill_picture_fn = rgbtest_fill_picture;
- return init_common(ctx);
+ return init(ctx);
}
static int rgbtest_query_formats(AVFilterContext *ctx)
@@ -458,23 +759,18 @@ static int rgbtest_query_formats(AVFilterContext *ctx)
AV_PIX_FMT_RGB555, AV_PIX_FMT_BGR555,
AV_PIX_FMT_NONE
};
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
- return 0;
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
}
static int rgbtest_config_props(AVFilterLink *outlink)
{
TestSourceContext *test = outlink->src->priv;
- switch (outlink->format) {
- case AV_PIX_FMT_ARGB: test->rgba_map[A] = 0; test->rgba_map[R] = 1; test->rgba_map[G] = 2; test->rgba_map[B] = 3; break;
- case AV_PIX_FMT_ABGR: test->rgba_map[A] = 0; test->rgba_map[B] = 1; test->rgba_map[G] = 2; test->rgba_map[R] = 3; break;
- case AV_PIX_FMT_RGBA:
- case AV_PIX_FMT_RGB24: test->rgba_map[R] = 0; test->rgba_map[G] = 1; test->rgba_map[B] = 2; test->rgba_map[A] = 3; break;
- case AV_PIX_FMT_BGRA:
- case AV_PIX_FMT_BGR24: test->rgba_map[B] = 0; test->rgba_map[G] = 1; test->rgba_map[R] = 2; test->rgba_map[A] = 3; break;
- }
-
+ ff_fill_rgba_map(test->rgba_map, outlink->format);
return config_props(outlink);
}
@@ -494,12 +790,293 @@ AVFilter ff_vsrc_rgbtestsrc = {
.priv_size = sizeof(TestSourceContext),
.priv_class = &rgbtestsrc_class,
.init = rgbtest_init,
-
+ .uninit = uninit,
.query_formats = rgbtest_query_formats,
+ .inputs = NULL,
+ .outputs = avfilter_vsrc_rgbtestsrc_outputs,
+};
+
+#endif /* CONFIG_RGBTESTSRC_FILTER */
- .inputs = NULL,
+#if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER
- .outputs = avfilter_vsrc_rgbtestsrc_outputs,
+static const uint8_t rainbow[7][4] = {
+ { 180, 128, 128, 255 }, /* gray */
+ { 168, 44, 136, 255 }, /* yellow */
+ { 145, 147, 44, 255 }, /* cyan */
+ { 133, 63, 52, 255 }, /* green */
+ { 63, 193, 204, 255 }, /* magenta */
+ { 51, 109, 212, 255 }, /* red */
+ { 28, 212, 120, 255 }, /* blue */
};
-#endif /* CONFIG_RGBTESTSRC_FILTER */
+static const uint8_t wobnair[7][4] = {
+ { 32, 240, 118, 255 }, /* blue */
+ { 19, 128, 128, 255 }, /* 7.5% intensity black */
+ { 54, 184, 198, 255 }, /* magenta */
+ { 19, 128, 128, 255 }, /* 7.5% intensity black */
+ { 188, 154, 16, 255 }, /* cyan */
+ { 19, 128, 128, 255 }, /* 7.5% intensity black */
+ { 191, 128, 128, 255 }, /* gray */
+};
+
+static const uint8_t white[4] = { 235, 128, 128, 255 };
+static const uint8_t black[4] = { 19, 128, 128, 255 }; /* 7.5% intensity black */
+
+/* pluge pulses */
+static const uint8_t neg4ire[4] = { 9, 128, 128, 255 }; /* 3.5% intensity black */
+static const uint8_t pos4ire[4] = { 29, 128, 128, 255 }; /* 11.5% intensity black */
+
+/* fudged Q/-I */
+static const uint8_t i_pixel[4] = { 61, 153, 99, 255 };
+static const uint8_t q_pixel[4] = { 35, 174, 152, 255 };
+
+static const uint8_t gray40[4] = { 104, 128, 128, 255 };
+static const uint8_t gray15[4] = { 49, 128, 128, 255 };
+static const uint8_t cyan[4] = { 188, 154, 16, 255 };
+static const uint8_t yellow[4] = { 219, 16, 138, 255 };
+static const uint8_t blue[4] = { 32, 240, 118, 255 };
+static const uint8_t red[4] = { 63, 102, 240, 255 };
+static const uint8_t black0[4] = { 16, 128, 128, 255 };
+static const uint8_t black2[4] = { 20, 128, 128, 255 };
+static const uint8_t black4[4] = { 25, 128, 128, 255 };
+static const uint8_t neg2[4] = { 12, 128, 128, 255 };
+
+static void draw_bar(TestSourceContext *test, const uint8_t color[4],
+ unsigned x, unsigned y, unsigned w, unsigned h,
+ AVFrame *frame)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+ uint8_t *p, *p0;
+ int plane;
+
+ x = FFMIN(x, test->w - 1);
+ y = FFMIN(y, test->h - 1);
+ w = FFMIN(w, test->w - x);
+ h = FFMIN(h, test->h - y);
+
+ av_assert0(x + w <= test->w);
+ av_assert0(y + h <= test->h);
+
+ for (plane = 0; frame->data[plane]; plane++) {
+ const int c = color[plane];
+ const int linesize = frame->linesize[plane];
+ int i, px, py, pw, ph;
+
+ if (plane == 1 || plane == 2) {
+ px = x >> desc->log2_chroma_w;
+ pw = w >> desc->log2_chroma_w;
+ py = y >> desc->log2_chroma_h;
+ ph = h >> desc->log2_chroma_h;
+ } else {
+ px = x;
+ pw = w;
+ py = y;
+ ph = h;
+ }
+
+ p0 = p = frame->data[plane] + py * linesize + px;
+ memset(p, c, pw);
+ p += linesize;
+ for (i = 1; i < ph; i++, p += linesize)
+ memcpy(p, p0, pw);
+ }
+}
+
+static int smptebars_query_formats(AVFilterContext *ctx)
+{
+ static const enum AVPixelFormat pix_fmts[] = {
+ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
+ AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
+ AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
+ AV_PIX_FMT_NONE,
+ };
+
+ AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+ if (!fmts_list)
+ return AVERROR(ENOMEM);
+ return ff_set_common_formats(ctx, fmts_list);
+}
+
+static const AVFilterPad smptebars_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame,
+ .config_props = config_props,
+ },
+ { NULL }
+};
+
+#if CONFIG_SMPTEBARS_FILTER
+
+#define smptebars_options options
+AVFILTER_DEFINE_CLASS(smptebars);
+
+static void smptebars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
+{
+ TestSourceContext *test = ctx->priv;
+ int r_w, r_h, w_h, p_w, p_h, i, tmp, x = 0;
+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
+
+ av_frame_set_colorspace(picref, AVCOL_SPC_BT470BG);
+
+ r_w = FFALIGN((test->w + 6) / 7, 1 << pixdesc->log2_chroma_w);
+ r_h = FFALIGN(test->h * 2 / 3, 1 << pixdesc->log2_chroma_h);
+ w_h = FFALIGN(test->h * 3 / 4 - r_h, 1 << pixdesc->log2_chroma_h);
+ p_w = FFALIGN(r_w * 5 / 4, 1 << pixdesc->log2_chroma_w);
+ p_h = test->h - w_h - r_h;
+
+ for (i = 0; i < 7; i++) {
+ draw_bar(test, rainbow[i], x, 0, r_w, r_h, picref);
+ draw_bar(test, wobnair[i], x, r_h, r_w, w_h, picref);
+ x += r_w;
+ }
+ x = 0;
+ draw_bar(test, i_pixel, x, r_h + w_h, p_w, p_h, picref);
+ x += p_w;
+ draw_bar(test, white, x, r_h + w_h, p_w, p_h, picref);
+ x += p_w;
+ draw_bar(test, q_pixel, x, r_h + w_h, p_w, p_h, picref);
+ x += p_w;
+ tmp = FFALIGN(5 * r_w - x, 1 << pixdesc->log2_chroma_w);
+ draw_bar(test, black, x, r_h + w_h, tmp, p_h, picref);
+ x += tmp;
+ tmp = FFALIGN(r_w / 3, 1 << pixdesc->log2_chroma_w);
+ draw_bar(test, neg4ire, x, r_h + w_h, tmp, p_h, picref);
+ x += tmp;
+ draw_bar(test, black, x, r_h + w_h, tmp, p_h, picref);
+ x += tmp;
+ draw_bar(test, pos4ire, x, r_h + w_h, tmp, p_h, picref);
+ x += tmp;
+ draw_bar(test, black, x, r_h + w_h, test->w - x, p_h, picref);
+}
+
+static av_cold int smptebars_init(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+
+ test->fill_picture_fn = smptebars_fill_picture;
+ test->draw_once = 1;
+ return init(ctx);
+}
+
+AVFilter ff_vsrc_smptebars = {
+ .name = "smptebars",
+ .description = NULL_IF_CONFIG_SMALL("Generate SMPTE color bars."),
+ .priv_size = sizeof(TestSourceContext),
+ .priv_class = &smptebars_class,
+ .init = smptebars_init,
+ .uninit = uninit,
+ .query_formats = smptebars_query_formats,
+ .inputs = NULL,
+ .outputs = smptebars_outputs,
+};
+
+#endif /* CONFIG_SMPTEBARS_FILTER */
+
+#if CONFIG_SMPTEHDBARS_FILTER
+
+#define smptehdbars_options options
+AVFILTER_DEFINE_CLASS(smptehdbars);
+
+static void smptehdbars_fill_picture(AVFilterContext *ctx, AVFrame *picref)
+{
+ TestSourceContext *test = ctx->priv;
+ int d_w, r_w, r_h, l_w, i, tmp, x = 0, y = 0;
+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format);
+
+ av_frame_set_colorspace(picref, AVCOL_SPC_BT709);
+
+ d_w = FFALIGN(test->w / 8, 1 << pixdesc->log2_chroma_w);
+ r_h = FFALIGN(test->h * 7 / 12, 1 << pixdesc->log2_chroma_h);
+ draw_bar(test, gray40, x, 0, d_w, r_h, picref);
+ x += d_w;
+
+ r_w = FFALIGN((((test->w + 3) / 4) * 3) / 7, 1 << pixdesc->log2_chroma_w);
+ for (i = 0; i < 7; i++) {
+ draw_bar(test, rainbow[i], x, 0, r_w, r_h, picref);
+ x += r_w;
+ }
+ draw_bar(test, gray40, x, 0, test->w - x, r_h, picref);
+ y = r_h;
+ r_h = FFALIGN(test->h / 12, 1 << pixdesc->log2_chroma_h);
+ draw_bar(test, cyan, 0, y, d_w, r_h, picref);
+ x = d_w;
+ draw_bar(test, i_pixel, x, y, r_w, r_h, picref);
+ x += r_w;
+ tmp = r_w * 6;
+ draw_bar(test, rainbow[0], x, y, tmp, r_h, picref);
+ x += tmp;
+ l_w = x;
+ draw_bar(test, blue, x, y, test->w - x, r_h, picref);
+ y += r_h;
+ draw_bar(test, yellow, 0, y, d_w, r_h, picref);
+ x = d_w;
+ draw_bar(test, q_pixel, x, y, r_w, r_h, picref);
+ x += r_w;
+
+ for (i = 0; i < tmp; i += 1 << pixdesc->log2_chroma_w) {
+ uint8_t yramp[4] = {0};
+
+ yramp[0] = i * 255 / tmp;
+ yramp[1] = 128;
+ yramp[2] = 128;
+ yramp[3] = 255;
+
+ draw_bar(test, yramp, x, y, 1 << pixdesc->log2_chroma_w, r_h, picref);
+ x += 1 << pixdesc->log2_chroma_w;
+ }
+ draw_bar(test, red, x, y, test->w - x, r_h, picref);
+ y += r_h;
+ draw_bar(test, gray15, 0, y, d_w, test->h - y, picref);
+ x = d_w;
+ tmp = FFALIGN(r_w * 3 / 2, 1 << pixdesc->log2_chroma_w);
+ draw_bar(test, black0, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ tmp = FFALIGN(r_w * 2, 1 << pixdesc->log2_chroma_w);
+ draw_bar(test, white, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ tmp = FFALIGN(r_w * 5 / 6, 1 << pixdesc->log2_chroma_w);
+ draw_bar(test, black0, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ tmp = FFALIGN(r_w / 3, 1 << pixdesc->log2_chroma_w);
+ draw_bar(test, neg2, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ draw_bar(test, black0, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ draw_bar(test, black2, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ draw_bar(test, black0, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ draw_bar(test, black4, x, y, tmp, test->h - y, picref);
+ x += tmp;
+ r_w = l_w - x;
+ draw_bar(test, black0, x, y, r_w, test->h - y, picref);
+ x += r_w;
+ draw_bar(test, gray15, x, y, test->w - x, test->h - y, picref);
+}
+
+static av_cold int smptehdbars_init(AVFilterContext *ctx)
+{
+ TestSourceContext *test = ctx->priv;
+
+ test->fill_picture_fn = smptehdbars_fill_picture;
+ test->draw_once = 1;
+ return init(ctx);
+}
+
+AVFilter ff_vsrc_smptehdbars = {
+ .name = "smptehdbars",
+ .description = NULL_IF_CONFIG_SMALL("Generate SMPTE HD color bars."),
+ .priv_size = sizeof(TestSourceContext),
+ .priv_class = &smptehdbars_class,
+ .init = smptehdbars_init,
+ .uninit = uninit,
+ .query_formats = smptebars_query_formats,
+ .inputs = NULL,
+ .outputs = smptebars_outputs,
+};
+
+#endif /* CONFIG_SMPTEHDBARS_FILTER */
+#endif /* CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER */
diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
index 13b5d318ec..49f45b630e 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -1,11 +1,24 @@
+OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o
+OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o
OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_init.o
OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o
+OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet_init.o
OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace_init.o
+OBJS-$(CONFIG_NOISE_FILTER) += x86/vf_noise.o
+OBJS-$(CONFIG_PP7_FILTER) += x86/vf_pp7_init.o
+OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup_init.o
+OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o
+OBJS-$(CONFIG_TINTERLACE_FILTER) += x86/vf_tinterlace_init.o
OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o
OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif_init.o
+YASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o
YASM-OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun.o
YASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.o
+YASM-OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet.o
YASM-OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace.o
+YASM-OBJS-$(CONFIG_PP7_FILTER) += x86/vf_pp7.o
+YASM-OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup.o
+YASM-OBJS-$(CONFIG_TINTERLACE_FILTER) += x86/vf_interlace.o
YASM-OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume.o
-YASM-OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif.o
+YASM-OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif.o x86/yadif-16.o x86/yadif-10.o
diff --git a/libavfilter/x86/af_volume.asm b/libavfilter/x86/af_volume.asm
index 4e5ad2258c..f4cbcbc5de 100644
--- a/libavfilter/x86/af_volume.asm
+++ b/libavfilter/x86/af_volume.asm
@@ -2,20 +2,20 @@
;* x86-optimized functions for volume filter
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -99,9 +99,11 @@ cglobal scale_samples_s32, 4,4,4, dst, src, len, volume
INIT_XMM sse2
%define CVTDQ2PD cvtdq2pd
SCALE_SAMPLES_S32
+%if HAVE_AVX_EXTERNAL
%define CVTDQ2PD vcvtdq2pd
INIT_YMM avx
SCALE_SAMPLES_S32
+%endif
%undef CVTDQ2PD
; NOTE: This is not bit-identical with the C version because it clips to
diff --git a/libavfilter/x86/af_volume_init.c b/libavfilter/x86/af_volume_init.c
index c59e0eda8e..57c7eab65f 100644
--- a/libavfilter/x86/af_volume_init.c
+++ b/libavfilter/x86/af_volume_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavfilter/x86/vf_eq.c b/libavfilter/x86/vf_eq.c
new file mode 100644
index 0000000000..16f399505f
--- /dev/null
+++ b/libavfilter/x86/vf_eq.c
@@ -0,0 +1,96 @@
+/*
+ *
+ * Original MPlayer filters by Richard Felker.
+ *
+ * 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavfilter/vf_eq.h"
+
+#if HAVE_MMX_INLINE && HAVE_6REGS
+static void process_MMX(EQParameters *param, uint8_t *dst, int dst_stride,
+ const uint8_t *src, int src_stride, int w, int h)
+{
+ int i;
+ int pel;
+ int dstep = dst_stride - w;
+ int sstep = src_stride - w;
+ short brvec[4];
+ short contvec[4];
+ int contrast = (int) (param->contrast * 256 * 16);
+ int brightness = ((int) (100.0 * param->brightness + 100.0) * 511) / 200 - 128 - contrast / 32;
+
+ brvec[0] = brvec[1] = brvec[2] = brvec[3] = brightness;
+ contvec[0] = contvec[1] = contvec[2] = contvec[3] = contrast;
+
+ while (h--) {
+ __asm__ volatile (
+ "movq (%5), %%mm3 \n\t"
+ "movq (%6), %%mm4 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "movl %4, %%eax \n\t"
+ ".p2align 4 \n\t"
+ "1: \n\t"
+ "movq (%0), %%mm1 \n\t"
+ "movq (%0), %%mm2 \n\t"
+ "punpcklbw %%mm0, %%mm1\n\t"
+ "punpckhbw %%mm0, %%mm2\n\t"
+ "psllw $4, %%mm1 \n\t"
+ "psllw $4, %%mm2 \n\t"
+ "pmulhw %%mm4, %%mm1 \n\t"
+ "pmulhw %%mm4, %%mm2 \n\t"
+ "paddw %%mm3, %%mm1 \n\t"
+ "paddw %%mm3, %%mm2 \n\t"
+ "packuswb %%mm2, %%mm1 \n\t"
+ "add $8, %0 \n\t"
+ "movq %%mm1, (%1) \n\t"
+ "add $8, %1 \n\t"
+ "decl %%eax \n\t"
+ "jnz 1b \n\t"
+ : "=r" (src), "=r" (dst)
+ : "0" (src), "1" (dst), "r" (w>>3), "r" (brvec), "r" (contvec)
+ : "%eax"
+ );
+
+ for (i = w&7; i; i--) {
+ pel = ((*src++ * contrast) >> 12) + brightness;
+ if (pel & ~255)
+ pel = (-pel) >> 31;
+ *dst++ = pel;
+ }
+
+ src += sstep;
+ dst += dstep;
+ }
+ __asm__ volatile ( "emms \n\t" ::: "memory" );
+}
+#endif
+
+av_cold void ff_eq_init_x86(EQContext *eq)
+{
+#if HAVE_MMX_INLINE && HAVE_6REGS
+ int cpu_flags = av_get_cpu_flags();
+
+ if (cpu_flags & AV_CPU_FLAG_MMX) {
+ eq->process = process_MMX;
+ }
+#endif
+}
diff --git a/libavfilter/x86/vf_fspp.asm b/libavfilter/x86/vf_fspp.asm
new file mode 100644
index 0000000000..e88feb981a
--- /dev/null
+++ b/libavfilter/x86/vf_fspp.asm
@@ -0,0 +1,727 @@
+;*****************************************************************************
+;* x86-optimized functions for fspp filter
+;*
+;* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+;* Copyright (C) 2005 Nikolaj Poroshin <porosh3@psu.ru>
+;*
+;* 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/x86/x86util.asm"
+
+SECTION_RODATA
+
+pb_dither: db 0, 48, 12, 60, 3, 51, 15, 63, 32, 16, 44, 28, 35, 19, 47, 31, \
+ 8, 56, 4, 52, 11, 59, 7, 55, 40, 24, 36, 20, 43, 27, 39, 23, \
+ 2, 50, 14, 62, 1, 49, 13, 61, 34, 18, 46, 30, 33, 17, 45, 29, \
+ 10, 58, 6, 54, 9, 57, 5, 53, 42, 26, 38, 22, 41, 25, 37, 21
+pw_187E: times 4 dw 0x187E ; FIX64(0.382683433, 14)
+pw_22A3: times 4 dw 0x22A3 ; FIX64(1.082392200, 13)
+pw_2D41: times 4 dw 0x2D41 ; FIX64(1.414213562, 13)
+pw_539F: times 4 dw 0x539F ; FIX64(1.306562965, 14)
+pw_5A82: times 4 dw 0x5A82 ; FIX64(1.414213562, 14)
+pw_3B21: times 4 dw 0x3B21 ; FIX64(1.847759065, 13)
+pw_AC62: times 4 dw 0xAC62 ; FIX64(-2.613125930, 13)
+pw_3642: times 4 dw 0x3642 ; FIX64(0.847759065, 14)
+pw_2441: times 4 dw 0x2441 ; FIX64(0.566454497, 14)
+pw_0CBB: times 4 dw 0x0CBB ; FIX64(0.198912367, 14)
+pw_4: times 4 dw 4
+pw_2: times 4 dw 2
+
+SECTION .text
+
+%define DCTSIZE 8
+
+INIT_MMX mmx
+
+;void ff_store_slice_mmx(uint8_t *dst, int16_t *src,
+; ptrdiff_t dst_stride, ptrdiff_t src_stride,
+; ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale)
+%if ARCH_X86_64
+cglobal store_slice, 7, 9, 0, dst, src, dst_stride, src_stride, width, dither_height, dither, tmp, tmp2
+%else
+cglobal store_slice, 2, 7, 0, dst, src, width, dither_height, dither, tmp, tmp2
+%define dst_strideq r2m
+%define src_strideq r3m
+ mov widthq, r4m
+ mov dither_heightq, r5m
+ mov ditherq, r6m ; log2_scale
+%endif
+ add widthq, 7
+ mov tmpq, src_strideq
+ and widthq, ~7
+ sub dst_strideq, widthq
+ movd m5, ditherq ; log2_scale
+ xor ditherq, -1 ; log2_scale
+ mov tmp2q, tmpq
+ add ditherq, 7 ; log2_scale
+ neg tmpq
+ sub tmp2q, widthq
+ movd m2, ditherq ; log2_scale
+ add tmp2q, tmp2q
+ lea ditherq, [pb_dither]
+ mov src_strideq, tmp2q
+ shl tmpq, 4
+ lea dither_heightq, [ditherq+dither_heightq*8]
+ pxor m7, m7
+
+.loop_height:
+ movq m3, [ditherq]
+ movq m4, m3
+ punpcklbw m3, m7
+ punpckhbw m4, m7
+ mov tmp2q, widthq
+ psraw m3, m5
+ psraw m4, m5
+
+.loop_width:
+ movq [srcq+tmpq], m7
+ movq m0, [srcq]
+ movq m1, [srcq+8]
+ movq [srcq+tmpq+8], m7
+ paddw m0, m3
+ paddw m1, m4
+ movq [srcq], m7
+ psraw m0, m2
+ psraw m1, m2
+ movq [srcq+8], m7
+ packuswb m0, m1
+ add srcq, 16
+ movq [dstq], m0
+ add dstq, 8
+ sub tmp2q, 8
+ jg .loop_width
+
+ add srcq, src_strideq
+ add ditherq, 8
+ add dstq, dst_strideq
+ cmp ditherq, dither_heightq
+ jl .loop_height
+ RET
+
+;void ff_store_slice2_mmx(uint8_t *dst, int16_t *src,
+; ptrdiff_t dst_stride, ptrdiff_t src_stride,
+; ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale)
+%if ARCH_X86_64
+cglobal store_slice2, 7, 9, 0, dst, src, dst_stride, src_stride, width, dither_height, dither, tmp, tmp2
+%else
+cglobal store_slice2, 0, 7, 0, dst, src, width, dither_height, dither, tmp, tmp2
+%define dst_strideq r2m
+%define src_strideq r3m
+ mov dstq, dstm
+ mov srcq, srcm
+ mov widthq, r4m
+ mov dither_heightq, r5m
+ mov ditherq, r6m ; log2_scale
+%endif
+ add widthq, 7
+ mov tmpq, src_strideq
+ and widthq, ~7
+ sub dst_strideq, widthq
+ movd m5, ditherq ; log2_scale
+ xor ditherq, -1 ; log2_scale
+ mov tmp2q, tmpq
+ add ditherq, 7 ; log2_scale
+ sub tmp2q, widthq
+ movd m2, ditherq ; log2_scale
+ add tmp2q, tmp2q
+ lea ditherq, [pb_dither]
+ mov src_strideq, tmp2q
+ shl tmpq, 5
+ lea dither_heightq, [ditherq+dither_heightq*8]
+ pxor m7, m7
+
+.loop_height:
+ movq m3, [ditherq]
+ movq m4, m3
+ punpcklbw m3, m7
+ punpckhbw m4, m7
+ mov tmp2q,widthq
+ psraw m3, m5
+ psraw m4, m5
+
+.loop_width:
+ movq m0, [srcq]
+ movq m1, [srcq+8]
+ paddw m0, m3
+ paddw m0, [srcq+tmpq]
+ paddw m1, m4
+ movq m6, [srcq+tmpq+8]
+ movq [srcq+tmpq], m7
+ psraw m0, m2
+ paddw m1, m6
+ movq [srcq+tmpq+8], m7
+ psraw m1, m2
+ packuswb m0, m1
+ movq [dstq], m0
+ add srcq, 16
+ add dstq, 8
+ sub tmp2q, 8
+ jg .loop_width
+
+ add srcq, src_strideq
+ add ditherq, 8
+ add dstq, dst_strideq
+ cmp ditherq, dither_heightq
+ jl .loop_height
+ RET
+
+;void ff_mul_thrmat_mmx(int16_t *thr_adr_noq, int16_t *thr_adr, int q);
+cglobal mul_thrmat, 3, 3, 0, thrn, thr, q
+ movd m7, qd
+ movq m0, [thrnq]
+ punpcklwd m7, m7
+ movq m1, [thrnq+8]
+ punpckldq m7, m7
+ pmullw m0, m7
+ movq m2, [thrnq+8*2]
+ pmullw m1, m7
+ movq m3, [thrnq+8*3]
+ pmullw m2, m7
+ movq [thrq], m0
+ movq m4, [thrnq+8*4]
+ pmullw m3, m7
+ movq [thrq+8], m1
+ movq m5, [thrnq+8*5]
+ pmullw m4, m7
+ movq [thrq+8*2], m2
+ movq m6, [thrnq+8*6]
+ pmullw m5, m7
+ movq [thrq+8*3], m3
+ movq m0, [thrnq+8*7]
+ pmullw m6, m7
+ movq [thrq+8*4], m4
+ movq m1, [thrnq+8*7+8]
+ pmullw m0, m7
+ movq [thrq+8*5], m5
+ movq m2, [thrnq+8*7+8*2]
+ pmullw m1, m7
+ movq [thrq+8*6], m6
+ movq m3, [thrnq+8*7+8*3]
+ pmullw m2, m7
+ movq [thrq+8*7], m0
+ movq m4, [thrnq+8*7+8*4]
+ pmullw m3, m7
+ movq [thrq+8*7+8], m1
+ movq m5, [thrnq+8*7+8*5]
+ pmullw m4, m7
+ movq [thrq+8*7+8*2], m2
+ movq m6, [thrnq+8*7+8*6]
+ pmullw m5, m7
+ movq [thrq+8*7+8*3], m3
+ movq m0, [thrnq+14*8]
+ pmullw m6, m7
+ movq [thrq+8*7+8*4], m4
+ movq m1, [thrnq+14*8+8]
+ pmullw m0, m7
+ movq [thrq+8*7+8*5], m5
+ pmullw m1, m7
+ movq [thrq+8*7+8*6], m6
+ movq [thrq+14*8], m0
+ movq [thrq+14*8+8], m1
+ RET
+
+%macro COLUMN_FDCT 1-3 0, 0
+ movq m1, [srcq+DCTSIZE*0*2]
+ movq m7, [srcq+DCTSIZE*3*2]
+ movq m0, m1
+ paddw m1, [srcq+DCTSIZE*7*2]
+ movq m3, m7
+ paddw m7, [srcq+DCTSIZE*4*2]
+ movq m5, m1
+ movq m6, [srcq+DCTSIZE*1*2]
+ psubw m1, m7
+ movq m2, [srcq+DCTSIZE*2*2]
+ movq m4, m6
+ paddw m6, [srcq+DCTSIZE*6*2]
+ paddw m5, m7
+ paddw m2, [srcq+DCTSIZE*5*2]
+ movq m7, m6
+ paddw m6, m2
+ psubw m7, m2
+ movq m2, m5
+ paddw m5, m6
+ psubw m2, m6
+ paddw m7, m1
+ movq m6, [thrq+4*16+%2]
+ psllw m7, 2
+ psubw m5, [thrq+%2]
+ psubw m2, m6
+ paddusw m5, [thrq+%2]
+ paddusw m2, m6
+ pmulhw m7, [pw_2D41]
+ paddw m5, [thrq+%2]
+ paddw m2, m6
+ psubusw m5, [thrq+%2]
+ psubusw m2, m6
+ paddw m5, [pw_2]
+ movq m6, m2
+ paddw m2, m5
+ psubw m5, m6
+ movq m6, m1
+ paddw m1, m7
+ psubw m1, [thrq+2*16+%2]
+ psubw m6, m7
+ movq m7, [thrq+6*16+%2]
+ psraw m5, 2
+ paddusw m1, [thrq+2*16+%2]
+ psubw m6, m7
+ paddw m1, [thrq+2*16+%2]
+ paddusw m6, m7
+ psubusw m1, [thrq+2*16+%2]
+ paddw m6, m7
+ psubw m3, [srcq+DCTSIZE*4*2]
+ psubusw m6, m7
+ movq m7, m1
+ psraw m2, 2
+ psubw m4, [srcq+DCTSIZE*6*2]
+ psubw m1, m6
+ psubw m0, [srcq+DCTSIZE*7*2]
+ paddw m6, m7
+ psraw m6, 2
+ movq m7, m2
+ pmulhw m1, [pw_5A82]
+ paddw m2, m6
+ movq [rsp], m2
+ psubw m7, m6
+ movq m2, [srcq+DCTSIZE*2*2]
+ psubw m1, m6
+ psubw m2, [srcq+DCTSIZE*5*2]
+ movq m6, m5
+ movq [rsp+8*3], m7
+ paddw m3, m2
+ paddw m2, m4
+ paddw m4, m0
+ movq m7, m3
+ psubw m3, m4
+ psllw m3, 2
+ psllw m7, 2
+ pmulhw m3, [pw_187E]
+ psllw m4, 2
+ pmulhw m7, [pw_22A3]
+ psllw m2, 2
+ pmulhw m4, [pw_539F]
+ paddw m5, m1
+ pmulhw m2, [pw_2D41]
+ psubw m6, m1
+ paddw m7, m3
+ movq [rsp+8], m5
+ paddw m4, m3
+ movq m3, [thrq+3*16+%2]
+ movq m1, m0
+ movq [rsp+8*2], m6
+ psubw m1, m2
+ paddw m0, m2
+ movq m5, m1
+ movq m2, [thrq+5*16+%2]
+ psubw m1, m7
+ paddw m5, m7
+ psubw m1, m3
+ movq m7, [thrq+16+%2]
+ psubw m5, m2
+ movq m6, m0
+ paddw m0, m4
+ paddusw m1, m3
+ psubw m6, m4
+ movq m4, [thrq+7*16+%2]
+ psubw m0, m7
+ psubw m6, m4
+ paddusw m5, m2
+ paddusw m6, m4
+ paddw m1, m3
+ paddw m5, m2
+ paddw m6, m4
+ psubusw m1, m3
+ psubusw m5, m2
+ psubusw m6, m4
+ movq m4, m1
+ por m4, m5
+ paddusw m0, m7
+ por m4, m6
+ paddw m0, m7
+ packssdw m4, m4
+ psubusw m0, m7
+ movd tmpd, m4
+ or tmpd, tmpd
+ jnz %1
+ movq m4, [rsp]
+ movq m1, m0
+ pmulhw m0, [pw_3642]
+ movq m2, m1
+ movq m5, [outq+DCTSIZE*0*2]
+ movq m3, m2
+ pmulhw m1, [pw_2441]
+ paddw m5, m4
+ movq m6, [rsp+8]
+ psraw m3, 2
+ pmulhw m2, [pw_0CBB]
+ psubw m4, m3
+ movq m7, [outq+DCTSIZE*1*2]
+ paddw m5, m3
+ movq [outq+DCTSIZE*7*2], m4
+ paddw m7, m6
+ movq m3, [rsp+8*2]
+ psubw m6, m0
+ movq m4, [outq+DCTSIZE*2*2]
+ paddw m7, m0
+ movq [outq], m5
+ paddw m4, m3
+ movq [outq+DCTSIZE*6*2], m6
+ psubw m3, m1
+ movq m5, [outq+DCTSIZE*5*2]
+ paddw m4, m1
+ movq m6, [outq+DCTSIZE*3*2]
+ paddw m5, m3
+ movq m0, [rsp+8*3]
+ add srcq, 8+%3
+ movq [outq+DCTSIZE*1*2], m7
+ paddw m6, m0
+ movq [outq+DCTSIZE*2*2], m4
+ psubw m0, m2
+ movq m7, [outq+DCTSIZE*4*2]
+ paddw m6, m2
+ movq [outq+DCTSIZE*5*2], m5
+ paddw m7, m0
+ movq [outq+DCTSIZE*3*2], m6
+ movq [outq+DCTSIZE*4*2], m7
+ add outq, 8+%3
+%endmacro
+
+%macro COLUMN_IDCT 0-1 0
+ movq m3, m5
+ psubw m5, m1
+ psllw m5, 1
+ paddw m3, m1
+ movq m2, m0
+ psubw m0, m6
+ movq m1, m5
+ psllw m0, 1
+ pmulhw m1, [pw_AC62]
+ paddw m5, m0
+ pmulhw m5, [pw_3B21]
+ paddw m2, m6
+ pmulhw m0, [pw_22A3]
+ movq m7, m2
+ movq m4, [rsp]
+ psubw m2, m3
+ psllw m2, 1
+ paddw m7, m3
+ pmulhw m2, [pw_2D41]
+ movq m6, m4
+ psraw m7, 2
+ paddw m4, [outq]
+ psubw m6, m7
+ movq m3, [rsp+8]
+ paddw m4, m7
+ movq [outq+DCTSIZE*7*2], m6
+ paddw m1, m5
+ movq [outq], m4
+ psubw m1, m7
+ movq m7, [rsp+8*2]
+ psubw m0, m5
+ movq m6, [rsp+8*3]
+ movq m5, m3
+ paddw m3, [outq+DCTSIZE*1*2]
+ psubw m5, m1
+ psubw m2, m1
+ paddw m3, m1
+ movq [outq+DCTSIZE*6*2], m5
+ movq m4, m7
+ paddw m7, [outq+DCTSIZE*2*2]
+ psubw m4, m2
+ paddw m4, [outq+DCTSIZE*5*2]
+ paddw m7, m2
+ movq [outq+DCTSIZE*1*2], m3
+ paddw m0, m2
+ movq [outq+DCTSIZE*2*2], m7
+ movq m1, m6
+ paddw m6, [outq+DCTSIZE*4*2]
+ psubw m1, m0
+ paddw m1, [outq+DCTSIZE*3*2]
+ paddw m6, m0
+ movq [outq+DCTSIZE*5*2], m4
+ add srcq, 8+%1
+ movq [outq+DCTSIZE*4*2], m6
+ movq [outq+DCTSIZE*3*2], m1
+ add outq, 8+%1
+%endmacro
+
+;void ff_column_fidct_mmx(int16_t *thr_adr, int16_t *data, int16_t *output, int cnt);
+cglobal column_fidct, 4, 5, 0, 32, thr, src, out, cnt, tmp
+.fdct1:
+ COLUMN_FDCT .idct1
+ jmp .fdct2
+
+.idct1:
+ COLUMN_IDCT
+
+.fdct2:
+ COLUMN_FDCT .idct2, 8, 16
+ sub cntd, 2
+ jg .fdct1
+ RET
+
+.idct2:
+ COLUMN_IDCT 16
+ sub cntd, 2
+ jg .fdct1
+ RET
+
+;void ff_row_idct_mmx(int16_t *workspace, int16_t *output_adr, ptrdiff_t output_stride, int cnt);
+cglobal row_idct, 4, 5, 0, 16, src, dst, stride, cnt, stride3
+ add strideq, strideq
+ lea stride3q, [strideq+strideq*2]
+.loop:
+ movq m0, [srcq+DCTSIZE*0*2]
+ movq m1, [srcq+DCTSIZE*1*2]
+ movq m4, m0
+ movq m2, [srcq+DCTSIZE*2*2]
+ punpcklwd m0, m1
+ movq m3, [srcq+DCTSIZE*3*2]
+ punpckhwd m4, m1
+ movq m7, m2
+ punpcklwd m2, m3
+ movq m6, m0
+ punpckldq m0, m2
+ punpckhdq m6, m2
+ movq m5, m0
+ punpckhwd m7, m3
+ psubw m0, m6
+ pmulhw m0, [pw_5A82]
+ movq m2, m4
+ punpckldq m4, m7
+ paddw m5, m6
+ punpckhdq m2, m7
+ movq m1, m4
+ psllw m0, 2
+ paddw m4, m2
+ movq m3, [srcq+DCTSIZE*0*2+8]
+ psubw m1, m2
+ movq m2, [srcq+DCTSIZE*1*2+8]
+ psubw m0, m5
+ movq m6, m4
+ paddw m4, m5
+ psubw m6, m5
+ movq m7, m1
+ movq m5, [srcq+DCTSIZE*2*2+8]
+ paddw m1, m0
+ movq [rsp], m4
+ movq m4, m3
+ movq [rsp+8], m6
+ punpcklwd m3, m2
+ movq m6, [srcq+DCTSIZE*3*2+8]
+ punpckhwd m4, m2
+ movq m2, m5
+ punpcklwd m5, m6
+ psubw m7, m0
+ punpckhwd m2, m6
+ movq m0, m3
+ punpckldq m3, m5
+ punpckhdq m0, m5
+ movq m5, m4
+ movq m6, m3
+ punpckldq m4, m2
+ psubw m3, m0
+ punpckhdq m5, m2
+ paddw m6, m0
+ movq m2, m4
+ movq m0, m3
+ psubw m4, m5
+ pmulhw m0, [pw_AC62]
+ paddw m3, m4
+ pmulhw m3, [pw_3B21]
+ paddw m2, m5
+ pmulhw m4, [pw_22A3]
+ movq m5, m2
+ psubw m2, m6
+ paddw m5, m6
+ pmulhw m2, [pw_2D41]
+ paddw m0, m3
+ psllw m0, 3
+ psubw m4, m3
+ movq m6, [rsp]
+ movq m3, m1
+ psllw m4, 3
+ psubw m0, m5
+ psllw m2, 3
+ paddw m1, m0
+ psubw m2, m0
+ psubw m3, m0
+ paddw m4, m2
+ movq m0, m7
+ paddw m7, m2
+ psubw m0, m2
+ movq m2, [pw_4]
+ psubw m6, m5
+ paddw m5, [rsp]
+ paddw m1, m2
+ paddw m5, m2
+ psraw m1, 3
+ paddw m7, m2
+ psraw m5, 3
+ paddw m5, [dstq]
+ psraw m7, 3
+ paddw m1, [dstq+strideq*1]
+ paddw m0, m2
+ paddw m7, [dstq+strideq*2]
+ paddw m3, m2
+ movq [dstq], m5
+ paddw m6, m2
+ movq [dstq+strideq*1], m1
+ psraw m0, 3
+ movq [dstq+strideq*2], m7
+ add dstq, stride3q
+ movq m5, [rsp+8]
+ psraw m3, 3
+ paddw m0, [dstq+strideq*2]
+ psubw m5, m4
+ paddw m3, [dstq+stride3q*1]
+ psraw m6, 3
+ paddw m4, [rsp+8]
+ paddw m5, m2
+ paddw m6, [dstq+strideq*4]
+ paddw m4, m2
+ movq [dstq+strideq*2], m0
+ psraw m5, 3
+ paddw m5, [dstq]
+ psraw m4, 3
+ paddw m4, [dstq+strideq*1]
+ add srcq, DCTSIZE*2*4
+ movq [dstq+stride3q*1], m3
+ movq [dstq+strideq*4], m6
+ movq [dstq], m5
+ movq [dstq+strideq*1], m4
+ sub dstq, stride3q
+ add dstq, 8
+ dec r3d
+ jnz .loop
+ RET
+
+;void ff_row_fdct_mmx(int16_t *data, const uint8_t *pixels, ptrdiff_t line_size, int cnt);
+cglobal row_fdct, 4, 5, 0, 16, src, pix, stride, cnt, stride3
+ lea stride3q, [strideq+strideq*2]
+.loop:
+ movd m0, [pixq]
+ pxor m7, m7
+ movd m1, [pixq+strideq*1]
+ punpcklbw m0, m7
+ movd m2, [pixq+strideq*2]
+ punpcklbw m1, m7
+ punpcklbw m2, m7
+ add pixq,stride3q
+ movq m5, m0
+ movd m3, [pixq+strideq*4]
+ movq m6, m1
+ movd m4, [pixq+stride3q*1]
+ punpcklbw m3, m7
+ psubw m5, m3
+ punpcklbw m4, m7
+ paddw m0, m3
+ psubw m6, m4
+ movd m3, [pixq+strideq*2]
+ paddw m1, m4
+ movq [rsp], m5
+ punpcklbw m3, m7
+ movq [rsp+8], m6
+ movq m4, m2
+ movd m5, [pixq]
+ paddw m2, m3
+ movd m6, [pixq+strideq*1]
+ punpcklbw m5, m7
+ psubw m4, m3
+ punpcklbw m6, m7
+ movq m3, m5
+ paddw m5, m6
+ psubw m3, m6
+ movq m6, m0
+ movq m7, m1
+ psubw m0, m5
+ psubw m1, m2
+ paddw m7, m2
+ paddw m1, m0
+ movq m2, m7
+ psllw m1, 2
+ paddw m6, m5
+ pmulhw m1, [pw_2D41]
+ paddw m7, m6
+ psubw m6, m2
+ movq m5, m0
+ movq m2, m7
+ punpcklwd m7, m6
+ paddw m0, m1
+ punpckhwd m2, m6
+ psubw m5, m1
+ movq m6, m0
+ movq m1, [rsp+8]
+ punpcklwd m0, m5
+ punpckhwd m6, m5
+ movq m5, m0
+ punpckldq m0, m7
+ paddw m3, m4
+ punpckhdq m5, m7
+ movq m7, m6
+ movq [srcq+DCTSIZE*0*2], m0
+ punpckldq m6, m2
+ movq [srcq+DCTSIZE*1*2], m5
+ punpckhdq m7, m2
+ movq [srcq+DCTSIZE*2*2], m6
+ paddw m4, m1
+ movq [srcq+DCTSIZE*3*2], m7
+ psllw m3, 2
+ movq m2, [rsp]
+ psllw m4, 2
+ pmulhw m4, [pw_2D41]
+ paddw m1, m2
+ psllw m1, 2
+ movq m0, m3
+ pmulhw m0, [pw_22A3]
+ psubw m3, m1
+ pmulhw m3, [pw_187E]
+ movq m5, m2
+ pmulhw m1, [pw_539F]
+ psubw m2, m4
+ paddw m5, m4
+ movq m6, m2
+ paddw m0, m3
+ movq m7, m5
+ paddw m2, m0
+ psubw m6, m0
+ movq m4, m2
+ paddw m1, m3
+ punpcklwd m2, m6
+ paddw m5, m1
+ punpckhwd m4, m6
+ psubw m7, m1
+ movq m6, m5
+ punpcklwd m5, m7
+ punpckhwd m6, m7
+ movq m7, m2
+ punpckldq m2, m5
+ sub pixq, stride3q
+ punpckhdq m7, m5
+ movq m5, m4
+ movq [srcq+DCTSIZE*0*2+8], m2
+ punpckldq m4, m6
+ movq [srcq+DCTSIZE*1*2+8], m7
+ punpckhdq m5, m6
+ movq [srcq+DCTSIZE*2*2+8], m4
+ add pixq, 4
+ movq [srcq+DCTSIZE*3*2+8], m5
+ add srcq, DCTSIZE*4*2
+ dec cntd
+ jnz .loop
+ RET
diff --git a/libavfilter/x86/vf_fspp_init.c b/libavfilter/x86/vf_fspp_init.c
new file mode 100644
index 0000000000..8e00317cb7
--- /dev/null
+++ b/libavfilter/x86/vf_fspp_init.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2005 Nikolaj Poroshin <porosh3@psu.ru>
+ *
+ * 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/attributes.h"
+#include "libavutil/x86/cpu.h"
+#include "libavfilter/vf_fspp.h"
+
+void ff_store_slice_mmx(uint8_t *dst, int16_t *src,
+ ptrdiff_t dst_stride, ptrdiff_t src_stride,
+ ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale);
+void ff_store_slice2_mmx(uint8_t *dst, int16_t *src,
+ ptrdiff_t dst_stride, ptrdiff_t src_stride,
+ ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale);
+void ff_mul_thrmat_mmx(int16_t *thr_adr_noq, int16_t *thr_adr, int q);
+void ff_column_fidct_mmx(int16_t *thr_adr, int16_t *data, int16_t *output, int cnt);
+void ff_row_idct_mmx(int16_t *workspace, int16_t *output_adr, ptrdiff_t output_stride, int cnt);
+void ff_row_fdct_mmx(int16_t *data, const uint8_t *pixels, ptrdiff_t line_size, int cnt);
+
+av_cold void ff_fspp_init_x86(FSPPContext *s)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMX(cpu_flags)) {
+ s->store_slice = ff_store_slice_mmx;
+ s->store_slice2 = ff_store_slice2_mmx;
+ s->mul_thrmat = ff_mul_thrmat_mmx;
+ s->column_fidct = ff_column_fidct_mmx;
+ s->row_idct = ff_row_idct_mmx;
+ s->row_fdct = ff_row_fdct_mmx;
+ }
+}
diff --git a/libavfilter/x86/vf_gradfun.asm b/libavfilter/x86/vf_gradfun.asm
index 00fcb166fb..3581f89fe8 100644
--- a/libavfilter/x86/vf_gradfun.asm
+++ b/libavfilter/x86/vf_gradfun.asm
@@ -1,20 +1,20 @@
;******************************************************************************
;* x86-optimized functions for gradfun filter
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavfilter/x86/vf_gradfun_init.c b/libavfilter/x86/vf_gradfun_init.c
index 3f23bf6799..c638a05e87 100644
--- a/libavfilter/x86/vf_gradfun_init.c
+++ b/libavfilter/x86/vf_gradfun_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2009 Loren Merritt <lorenm@u.washington.edu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,29 +26,29 @@
#include "libavutil/x86/cpu.h"
#include "libavfilter/gradfun.h"
-void ff_gradfun_filter_line_mmxext(intptr_t x, uint8_t *dst, uint8_t *src,
- uint16_t *dc, int thresh,
+void ff_gradfun_filter_line_mmxext(intptr_t x, uint8_t *dst, const uint8_t *src,
+ const uint16_t *dc, int thresh,
const uint16_t *dithers);
-
-void ff_gradfun_filter_line_ssse3(intptr_t x, uint8_t *dst, uint8_t *src,
- uint16_t *dc, int thresh,
+void ff_gradfun_filter_line_ssse3(intptr_t x, uint8_t *dst, const uint8_t *src,
+ const uint16_t *dc, int thresh,
const uint16_t *dithers);
void ff_gradfun_blur_line_movdqa_sse2(intptr_t x, uint16_t *buf,
- uint16_t *buf1, uint16_t *dc,
- uint8_t *src1, uint8_t *src2);
+ const uint16_t *buf1, uint16_t *dc,
+ const uint8_t *src1, const uint8_t *src2);
void ff_gradfun_blur_line_movdqu_sse2(intptr_t x, uint16_t *buf,
- uint16_t *buf1, uint16_t *dc,
- uint8_t *src1, uint8_t *src2);
+ const uint16_t *buf1, uint16_t *dc,
+ const uint8_t *src1, const uint8_t *src2);
#if HAVE_YASM
-static void gradfun_filter_line(uint8_t *dst, uint8_t *src, uint16_t *dc,
- int width, int thresh, const uint16_t *dithers,
- int alignment)
+static void gradfun_filter_line_mmxext(uint8_t *dst, const uint8_t *src,
+ const uint16_t *dc,
+ int width, int thresh,
+ const uint16_t *dithers)
{
intptr_t x;
- if (width & alignment) {
- x = width & ~alignment;
+ if (width & 3) {
+ x = width & ~3;
ff_gradfun_filter_line_c(dst + x, src + x, dc + x / 2,
width - x, thresh, dithers);
width = x;
@@ -58,22 +58,25 @@ static void gradfun_filter_line(uint8_t *dst, uint8_t *src, uint16_t *dc,
thresh, dithers);
}
-static void gradfun_filter_line_mmxext(uint8_t *dst, uint8_t *src, uint16_t *dc,
- int width, int thresh,
- const uint16_t *dithers)
-{
- gradfun_filter_line(dst, src, dc, width, thresh, dithers, 3);
-}
-
-static void gradfun_filter_line_ssse3(uint8_t *dst, uint8_t *src, uint16_t *dc,
+static void gradfun_filter_line_ssse3(uint8_t *dst, const uint8_t *src, const uint16_t *dc,
int width, int thresh,
const uint16_t *dithers)
{
- gradfun_filter_line(dst, src, dc, width, thresh, dithers, 7);
+ intptr_t x;
+ if (width & 7) {
+ // could be 10% faster if I somehow eliminated this
+ x = width & ~7;
+ ff_gradfun_filter_line_c(dst + x, src + x, dc + x / 2,
+ width - x, thresh, dithers);
+ width = x;
+ }
+ x = -width;
+ ff_gradfun_filter_line_ssse3(x, dst + width, src + width, dc + width / 2,
+ thresh, dithers);
}
-static void gradfun_blur_line_sse2(uint16_t *dc, uint16_t *buf, uint16_t *buf1,
- uint8_t *src, int src_linesize, int width)
+static void gradfun_blur_line_sse2(uint16_t *dc, uint16_t *buf, const uint16_t *buf1,
+ const uint8_t *src, int src_linesize, int width)
{
intptr_t x = -2 * width;
if (((intptr_t) src | src_linesize) & 15)
diff --git a/libavfilter/x86/vf_hqdn3d.asm b/libavfilter/x86/vf_hqdn3d.asm
index 02632a1f09..961127e670 100644
--- a/libavfilter/x86/vf_hqdn3d.asm
+++ b/libavfilter/x86/vf_hqdn3d.asm
@@ -1,20 +1,20 @@
;******************************************************************************
;* Copyright (c) 2012 Loren Merritt
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavfilter/x86/vf_hqdn3d_init.c b/libavfilter/x86/vf_hqdn3d_init.c
index 06f9e00ec9..b63916b674 100644
--- a/libavfilter/x86/vf_hqdn3d_init.c
+++ b/libavfilter/x86/vf_hqdn3d_init.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2012 Loren Merritt
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
diff --git a/libavfilter/x86/vf_idet.asm b/libavfilter/x86/vf_idet.asm
new file mode 100644
index 0000000000..007e63deb9
--- /dev/null
+++ b/libavfilter/x86/vf_idet.asm
@@ -0,0 +1,170 @@
+;*****************************************************************************
+;* x86-optimized functions for idet filter
+;*
+;* Copyright (C) 2014 Pascal Massimino (pascal.massimino@gmail.com)
+;* Copyright (c) 2014 Neil Birkbeck (birkbeck@google.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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_TEXT
+
+; Implementation that does 8-bytes at a time using single-word operations.
+%macro IDET_FILTER_LINE 1
+INIT_MMX %1
+cglobal idet_filter_line, 4, 5, 0, a, b, c, width, index
+ xor indexq, indexq
+%define m_zero m2
+%define m_sum m5
+ pxor m_sum, m_sum
+ pxor m_zero, m_zero
+
+.loop:
+ movu m0, [aq + indexq*1]
+ punpckhbw m1, m0, m_zero
+ punpcklbw m0, m_zero
+
+ movu m3, [cq + indexq*1]
+ punpckhbw m4, m3, m_zero
+ punpcklbw m3, m_zero
+
+ paddsw m1, m4
+ paddsw m0, m3
+
+ movu m3, [bq + indexq*1]
+ punpckhbw m4, m3, m_zero
+ punpcklbw m3, m_zero
+
+ paddw m4, m4
+ paddw m3, m3
+ psubsw m1, m4
+ psubsw m0, m3
+
+ ABS2 m1, m0, m4, m3
+
+ paddw m0, m1
+ punpckhwd m1, m0, m_zero
+ punpcklwd m0, m_zero
+
+ paddd m0, m1
+ paddd m_sum, m0
+
+ add indexq, 0x8
+ CMP widthd, indexd
+ jg .loop
+
+ HADDD m_sum, m0
+ movd eax, m_sum
+ RET
+%endmacro
+
+%if ARCH_X86_32
+IDET_FILTER_LINE mmxext
+IDET_FILTER_LINE mmx
+%endif
+
+;******************************************************************************
+; 16bit implementation that does 4/8-pixels at a time
+
+%macro PABS_DIFF_WD 3 ; a, b, junk , output=a
+ psubusw %3, %2, %1
+ psubusw %1, %2
+ por %1, %3
+
+ mova %2, %1
+ punpcklwd %1, m_zero
+ punpckhwd %2, m_zero
+ paddd %1, %2
+%endmacro
+
+%macro IDET_FILTER_LINE_16BIT 1 ; %1=increment (4 or 8 words)
+cglobal idet_filter_line_16bit, 4, 5, 8, a, b, c, width, index
+ xor indexq, indexq
+%define m_zero m1
+%define m_sum m0
+ pxor m_sum, m_sum
+ pxor m_zero, m_zero
+
+.loop_16bit:
+ movu m2, [bq + indexq * 2] ; B
+ movu m3, [aq + indexq * 2] ; A
+ mova m6, m2
+ psubusw m5, m2, m3 ; ba
+
+ movu m4, [cq + indexq * 2] ; C
+ add indexq, %1
+ psubusw m3, m2 ; ab
+ CMP indexd, widthd
+
+ psubusw m6, m4 ; bc
+ psubusw m4, m2 ; cb
+
+ PABS_DIFF_WD m3, m6, m7 ; |ab - bc|
+ PABS_DIFF_WD m5, m4, m7 ; |ba - cb|
+ paddd m_sum, m3
+ paddd m_sum, m5
+ jl .loop_16bit
+
+ HADDD m_sum, m2
+ movd eax, m_sum
+ RET
+%endmacro
+
+INIT_XMM sse2
+IDET_FILTER_LINE_16BIT 8
+%if ARCH_X86_32
+INIT_MMX mmx
+IDET_FILTER_LINE_16BIT 4
+%endif
+
+;******************************************************************************
+; SSE2 8-bit implementation that does 16-bytes at a time:
+
+INIT_XMM sse2
+cglobal idet_filter_line, 4, 6, 7, a, b, c, width, index, total
+ xor indexq, indexq
+ pxor m0, m0
+ pxor m1, m1
+
+.sse2_loop:
+ movu m2, [bq + indexq*1] ; B
+ movu m3, [aq + indexq*1] ; A
+ mova m6, m2
+ mova m4, m3
+ psubusb m5, m2, m3 ; ba
+
+ movu m3, [cq + indexq*1] ; C
+ add indexq, 0x10
+ psubusb m4, m2 ; ab
+ CMP indexd, widthd
+
+ psubusb m6, m3 ; bc
+ psubusb m3, m2 ; cb
+
+ psadbw m4, m6 ; |ab - bc|
+ paddq m0, m4
+ psadbw m5, m3 ; |ba - cb|
+ paddq m1, m5
+ jl .sse2_loop
+
+ paddq m0, m1
+ movhlps m1, m0
+ paddq m0, m1
+ movd eax, m0
+ RET
diff --git a/libavfilter/x86/vf_idet_init.c b/libavfilter/x86/vf_idet_init.c
new file mode 100644
index 0000000000..1147ca8ba8
--- /dev/null
+++ b/libavfilter/x86/vf_idet_init.c
@@ -0,0 +1,87 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "libavfilter/vf_idet.h"
+
+#if HAVE_YASM
+
+/* declares main callable idet_filter_line_{mmx,mmxext,sse2}() */
+#define FUNC_MAIN_DECL(KIND, SPAN) \
+int ff_idet_filter_line_##KIND(const uint8_t *a, const uint8_t *b, \
+ const uint8_t *c, int w); \
+static int idet_filter_line_##KIND(const uint8_t *a, const uint8_t *b, \
+ const uint8_t *c, int w) { \
+ int sum = 0; \
+ const int left_over = w & (SPAN - 1); \
+ w -= left_over; \
+ if (w > 0) \
+ sum += ff_idet_filter_line_##KIND(a, b, c, w); \
+ if (left_over > 0) \
+ sum += ff_idet_filter_line_c(a + w, b + w, c + w, left_over); \
+ return sum; \
+}
+
+
+#define FUNC_MAIN_DECL_16bit(KIND, SPAN) \
+int ff_idet_filter_line_16bit_##KIND(const uint16_t *a, const uint16_t *b, \
+ const uint16_t *c, int w); \
+static int idet_filter_line_16bit_##KIND(const uint16_t *a, const uint16_t *b, \
+ const uint16_t *c, int w) { \
+ int sum = 0; \
+ const int left_over = w & (SPAN - 1); \
+ w -= left_over; \
+ if (w > 0) \
+ sum += ff_idet_filter_line_16bit_##KIND(a, b, c, w); \
+ if (left_over > 0) \
+ sum += ff_idet_filter_line_c_16bit(a + w, b + w, c + w, left_over); \
+ return sum; \
+}
+
+FUNC_MAIN_DECL(sse2, 16)
+FUNC_MAIN_DECL_16bit(sse2, 8)
+#if ARCH_X86_32
+FUNC_MAIN_DECL(mmx, 8)
+FUNC_MAIN_DECL(mmxext, 8)
+FUNC_MAIN_DECL_16bit(mmx, 4)
+#endif
+
+#endif
+av_cold void ff_idet_init_x86(IDETContext *idet, int for_16b)
+{
+#if HAVE_YASM
+ const int cpu_flags = av_get_cpu_flags();
+
+#if ARCH_X86_32
+ if (EXTERNAL_MMX(cpu_flags)) {
+ idet->filter_line = for_16b ? (ff_idet_filter_func)idet_filter_line_16bit_mmx : idet_filter_line_mmx;
+ }
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ idet->filter_line = for_16b ? (ff_idet_filter_func)idet_filter_line_16bit_mmx : idet_filter_line_mmxext;
+ }
+#endif // ARCH_x86_32
+
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ idet->filter_line = for_16b ? (ff_idet_filter_func)idet_filter_line_16bit_sse2 : idet_filter_line_sse2;
+ }
+#endif // HAVE_YASM
+}
diff --git a/libavfilter/x86/vf_interlace.asm b/libavfilter/x86/vf_interlace.asm
index 85811da8d1..ce3dd81311 100644
--- a/libavfilter/x86/vf_interlace.asm
+++ b/libavfilter/x86/vf_interlace.asm
@@ -4,20 +4,20 @@
;* Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
;* Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or modify
+;* 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.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+;* with FFmpeg; if not, write to the Free Software Foundation, Inc.,
;* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
;******************************************************************************
diff --git a/libavfilter/x86/vf_interlace_init.c b/libavfilter/x86/vf_interlace_init.c
index 231ab85a1c..68ee47d9bc 100644
--- a/libavfilter/x86/vf_interlace_init.c
+++ b/libavfilter/x86/vf_interlace_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or modify
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that 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 Libav; if not, write to the Free Software Foundation, Inc.,
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
diff --git a/libavfilter/x86/vf_noise.c b/libavfilter/x86/vf_noise.c
new file mode 100644
index 0000000000..0a86cb084b
--- /dev/null
+++ b/libavfilter/x86/vf_noise.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2013 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
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/x86/cpu.h"
+#include "libavutil/x86/asm.h"
+#include "libavfilter/vf_noise.h"
+
+#if HAVE_INLINE_ASM
+static void line_noise_mmx(uint8_t *dst, const uint8_t *src,
+ const int8_t *noise, int len, int shift)
+{
+ x86_reg mmx_len= len & (~7);
+ noise += shift;
+
+ __asm__ volatile(
+ "mov %3, %%"REG_a" \n\t"
+ "pcmpeqb %%mm7, %%mm7 \n\t"
+ "psllw $15, %%mm7 \n\t"
+ "packsswb %%mm7, %%mm7 \n\t"
+ ".p2align 4 \n\t"
+ "1: \n\t"
+ "movq (%0, %%"REG_a"), %%mm0 \n\t"
+ "movq (%1, %%"REG_a"), %%mm1 \n\t"
+ "pxor %%mm7, %%mm0 \n\t"
+ "paddsb %%mm1, %%mm0 \n\t"
+ "pxor %%mm7, %%mm0 \n\t"
+ "movq %%mm0, (%2, %%"REG_a") \n\t"
+ "add $8, %%"REG_a" \n\t"
+ " js 1b \n\t"
+ :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
+ : "%"REG_a
+ );
+ if (mmx_len != len)
+ ff_line_noise_c(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
+}
+
+#if HAVE_6REGS
+static void line_noise_avg_mmx(uint8_t *dst, const uint8_t *src,
+ int len, const int8_t * const *shift)
+{
+ x86_reg mmx_len = len & (~7);
+
+ __asm__ volatile(
+ "mov %5, %%"REG_a" \n\t"
+ ".p2align 4 \n\t"
+ "1: \n\t"
+ "movq (%1, %%"REG_a"), %%mm1 \n\t"
+ "movq (%0, %%"REG_a"), %%mm0 \n\t"
+ "paddb (%2, %%"REG_a"), %%mm1 \n\t"
+ "paddb (%3, %%"REG_a"), %%mm1 \n\t"
+ "movq %%mm0, %%mm2 \n\t"
+ "movq %%mm1, %%mm3 \n\t"
+ "punpcklbw %%mm0, %%mm0 \n\t"
+ "punpckhbw %%mm2, %%mm2 \n\t"
+ "punpcklbw %%mm1, %%mm1 \n\t"
+ "punpckhbw %%mm3, %%mm3 \n\t"
+ "pmulhw %%mm0, %%mm1 \n\t"
+ "pmulhw %%mm2, %%mm3 \n\t"
+ "paddw %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm3 \n\t"
+ "paddw %%mm0, %%mm1 \n\t"
+ "paddw %%mm2, %%mm3 \n\t"
+ "psrlw $8, %%mm1 \n\t"
+ "psrlw $8, %%mm3 \n\t"
+ "packuswb %%mm3, %%mm1 \n\t"
+ "movq %%mm1, (%4, %%"REG_a") \n\t"
+ "add $8, %%"REG_a" \n\t"
+ " js 1b \n\t"
+ :: "r" (src+mmx_len), "r" (shift[0]+mmx_len), "r" (shift[1]+mmx_len), "r" (shift[2]+mmx_len),
+ "r" (dst+mmx_len), "g" (-mmx_len)
+ : "%"REG_a
+ );
+
+ if (mmx_len != len){
+ const int8_t *shift2[3] = { shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len };
+ ff_line_noise_avg_c(dst+mmx_len, src+mmx_len, len-mmx_len, shift2);
+ }
+}
+#endif /* HAVE_6REGS */
+
+static void line_noise_mmxext(uint8_t *dst, const uint8_t *src,
+ const int8_t *noise, int len, int shift)
+{
+ x86_reg mmx_len = len & (~7);
+ noise += shift;
+
+ __asm__ volatile(
+ "mov %3, %%"REG_a" \n\t"
+ "pcmpeqb %%mm7, %%mm7 \n\t"
+ "psllw $15, %%mm7 \n\t"
+ "packsswb %%mm7, %%mm7 \n\t"
+ ".p2align 4 \n\t"
+ "1: \n\t"
+ "movq (%0, %%"REG_a"), %%mm0 \n\t"
+ "movq (%1, %%"REG_a"), %%mm1 \n\t"
+ "pxor %%mm7, %%mm0 \n\t"
+ "paddsb %%mm1, %%mm0 \n\t"
+ "pxor %%mm7, %%mm0 \n\t"
+ "movntq %%mm0, (%2, %%"REG_a") \n\t"
+ "add $8, %%"REG_a" \n\t"
+ " js 1b \n\t"
+ :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len)
+ : "%"REG_a
+ );
+ if (mmx_len != len)
+ ff_line_noise_c(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0);
+}
+#endif /* HAVE_INLINE_ASM */
+
+av_cold void ff_noise_init_x86(NoiseContext *n)
+{
+#if HAVE_INLINE_ASM
+ int cpu_flags = av_get_cpu_flags();
+
+ if (INLINE_MMX(cpu_flags)) {
+ n->line_noise = line_noise_mmx;
+#if HAVE_6REGS
+ n->line_noise_avg = line_noise_avg_mmx;
+#endif
+ }
+ if (INLINE_MMXEXT(cpu_flags)) {
+ n->line_noise = line_noise_mmxext;
+ }
+#endif
+}
diff --git a/libavfilter/x86/vf_pp7.asm b/libavfilter/x86/vf_pp7.asm
new file mode 100644
index 0000000000..7b3e5cf5e3
--- /dev/null
+++ b/libavfilter/x86/vf_pp7.asm
@@ -0,0 +1,57 @@
+;*****************************************************************************
+;* x86-optimized functions for pp7 filter
+;*
+;* Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+;*
+;* 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/x86/x86util.asm"
+
+SECTION .text
+
+INIT_MMX mmx
+
+;void ff_pp7_dctB_mmx(int16_t *dst, int16_t *src)
+cglobal pp7_dctB, 2, 2, 0, dst, src
+ movq m0, [srcq]
+ movq m1, [srcq+mmsize*1]
+ paddw m0, [srcq+mmsize*6]
+ paddw m1, [srcq+mmsize*5]
+ movq m2, [srcq+mmsize*2]
+ movq m3, [srcq+mmsize*3]
+ paddw m2, [srcq+mmsize*4]
+ paddw m3, m3
+ movq m4, m3
+ psubw m3, m0
+ paddw m4, m0
+ movq m0, m2
+ psubw m2, m1
+ paddw m0, m1
+ movq m1, m4
+ psubw m4, m0
+ paddw m1, m0
+ movq m0, m3
+ psubw m3, m2
+ psubw m3, m2
+ paddw m2, m0
+ paddw m2, m0
+ movq [dstq], m1
+ movq [dstq+mmsize*2], m4
+ movq [dstq+mmsize*1], m2
+ movq [dstq+mmsize*3], m3
+ RET
diff --git a/libavfilter/x86/vf_pp7_init.c b/libavfilter/x86/vf_pp7_init.c
new file mode 100644
index 0000000000..165b0dd5d0
--- /dev/null
+++ b/libavfilter/x86/vf_pp7_init.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/x86/cpu.h"
+#include "libavfilter/vf_pp7.h"
+
+void ff_pp7_dctB_mmx(int16_t *dst, int16_t *src);
+
+av_cold void ff_pp7_init_x86(PP7Context *p)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMX(cpu_flags))
+ p->dctB = ff_pp7_dctB_mmx;
+}
diff --git a/libavfilter/x86/vf_pullup.asm b/libavfilter/x86/vf_pullup.asm
new file mode 100644
index 0000000000..d3a195511e
--- /dev/null
+++ b/libavfilter/x86/vf_pullup.asm
@@ -0,0 +1,178 @@
+;*****************************************************************************
+;* x86-optimized functions for pullup filter
+;*
+;* 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/x86/x86util.asm"
+
+SECTION_TEXT
+
+INIT_MMX mmx
+cglobal pullup_filter_diff, 3, 5, 8, first, second, size
+ mov r3, 4
+ pxor m4, m4
+ pxor m7, m7
+
+.loop:
+ movq m0, [firstq]
+ movq m2, [firstq]
+ add firstq, sizeq
+ movq m1, [secondq]
+ add secondq, sizeq
+ psubusb m2, m1
+ psubusb m1, m0
+ movq m0, m2
+ movq m3, m1
+ punpcklbw m0, m7
+ punpcklbw m1, m7
+ punpckhbw m2, m7
+ punpckhbw m3, m7
+ paddw m4, m0
+ paddw m4, m1
+ paddw m4, m2
+ paddw m4, m3
+
+ dec r3
+ jnz .loop
+
+ movq m3, m4
+ punpcklwd m4, m7
+ punpckhwd m3, m7
+ paddd m3, m4
+ movd eax, m3
+ psrlq m3, 32
+ movd r4d, m3
+ add eax, r4d
+ RET
+
+INIT_MMX mmx
+cglobal pullup_filter_comb, 3, 5, 8, first, second, size
+ mov r3, 4
+ pxor m6, m6
+ pxor m7, m7
+ sub secondq, sizeq
+
+.loop:
+ movq m0, [firstq]
+ movq m1, [secondq]
+ punpcklbw m0, m7
+ movq m2, [secondq+sizeq]
+ punpcklbw m1, m7
+ punpcklbw m2, m7
+ paddw m0, m0
+ paddw m1, m2
+ movq m2, m0
+ psubusw m0, m1
+ psubusw m1, m2
+ paddw m6, m0
+ paddw m6, m1
+
+ movq m0, [firstq]
+ movq m1, [secondq]
+ punpckhbw m0, m7
+ movq m2, [secondq+sizeq]
+ punpckhbw m1, m7
+ punpckhbw m2, m7
+ paddw m0, m0
+ paddw m1, m2
+ movq m2, m0
+ psubusw m0, m1
+ psubusw m1, m2
+ paddw m6, m0
+ paddw m6, m1
+
+ movq m0, [secondq+sizeq]
+ movq m1, [firstq]
+ punpcklbw m0, m7
+ movq m2, [firstq+sizeq]
+ punpcklbw m1, m7
+ punpcklbw m2, m7
+ paddw m0, m0
+ paddw m1, m2
+ movq m2, m0
+ psubusw m0, m1
+ psubusw m1, m2
+ paddw m6, m0
+ paddw m6, m1
+
+ movq m0, [secondq+sizeq]
+ movq m1, [firstq]
+ punpckhbw m0, m7
+ movq m2, [firstq+sizeq]
+ punpckhbw m1, m7
+ punpckhbw m2, m7
+ paddw m0, m0
+ paddw m1, m2
+ movq m2, m0
+ psubusw m0, m1
+ psubusw m1, m2
+ paddw m6, m0
+ paddw m6, m1
+
+ add firstq, sizeq
+ add secondq, sizeq
+ dec r3
+ jnz .loop
+
+ movq m5, m6
+ punpcklwd m6, m7
+ punpckhwd m5, m7
+ paddd m5, m6
+ movd eax, m5
+ psrlq m5, 32
+ movd r4d, m5
+ add eax, r4d
+ RET
+
+INIT_MMX mmx
+cglobal pullup_filter_var, 3, 5, 8, first, second, size
+ mov r3, 3
+ pxor m4, m4
+ pxor m7, m7
+
+.loop:
+ movq m0, [firstq]
+ movq m2, [firstq]
+ movq m1, [firstq+sizeq]
+ add firstq, sizeq
+ psubusb m2, m1
+ psubusb m1, m0
+ movq m0, m2
+ movq m3, m1
+ punpcklbw m0, m7
+ punpcklbw m1, m7
+ punpckhbw m2, m7
+ punpckhbw m3, m7
+ paddw m4, m0
+ paddw m4, m1
+ paddw m4, m2
+ paddw m4, m3
+
+ dec r3
+ jnz .loop
+
+ movq m3, m4
+ punpcklwd m4, m7
+ punpckhwd m3, m7
+ paddd m3, m4
+ movd eax, m3
+ psrlq m3, 32
+ movd r4d, m3
+ add eax, r4d
+ shl eax, 2
+ RET
diff --git a/libavfilter/x86/vf_pullup_init.c b/libavfilter/x86/vf_pullup_init.c
new file mode 100644
index 0000000000..5b36b68e51
--- /dev/null
+++ b/libavfilter/x86/vf_pullup_init.c
@@ -0,0 +1,41 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "libavfilter/vf_pullup.h"
+
+int ff_pullup_filter_diff_mmx(const uint8_t *a, const uint8_t *b, ptrdiff_t s);
+int ff_pullup_filter_comb_mmx(const uint8_t *a, const uint8_t *b, ptrdiff_t s);
+int ff_pullup_filter_var_mmx (const uint8_t *a, const uint8_t *b, ptrdiff_t s);
+
+av_cold void ff_pullup_init_x86(PullupContext *s)
+{
+#if HAVE_YASM
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMX(cpu_flags)) {
+ s->diff = ff_pullup_filter_diff_mmx;
+ s->comb = ff_pullup_filter_comb_mmx;
+ s->var = ff_pullup_filter_var_mmx;
+ }
+#endif
+}
diff --git a/libavfilter/x86/vf_spp.c b/libavfilter/x86/vf_spp.c
new file mode 100644
index 0000000000..1cfb9e81f7
--- /dev/null
+++ b/libavfilter/x86/vf_spp.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavfilter/vf_spp.h"
+
+#if HAVE_MMX_INLINE
+static void hardthresh_mmx(int16_t dst[64], const int16_t src[64],
+ int qp, const uint8_t *permutation)
+{
+ int bias = 0; //FIXME
+ unsigned int threshold1;
+
+ threshold1 = qp * ((1<<4) - bias) - 1;
+
+#define REQUANT_CORE(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \
+ "movq " #src0 ", %%mm0 \n" \
+ "movq " #src1 ", %%mm1 \n" \
+ "movq " #src2 ", %%mm2 \n" \
+ "movq " #src3 ", %%mm3 \n" \
+ "psubw %%mm4, %%mm0 \n" \
+ "psubw %%mm4, %%mm1 \n" \
+ "psubw %%mm4, %%mm2 \n" \
+ "psubw %%mm4, %%mm3 \n" \
+ "paddusw %%mm5, %%mm0 \n" \
+ "paddusw %%mm5, %%mm1 \n" \
+ "paddusw %%mm5, %%mm2 \n" \
+ "paddusw %%mm5, %%mm3 \n" \
+ "paddw %%mm6, %%mm0 \n" \
+ "paddw %%mm6, %%mm1 \n" \
+ "paddw %%mm6, %%mm2 \n" \
+ "paddw %%mm6, %%mm3 \n" \
+ "psubusw %%mm6, %%mm0 \n" \
+ "psubusw %%mm6, %%mm1 \n" \
+ "psubusw %%mm6, %%mm2 \n" \
+ "psubusw %%mm6, %%mm3 \n" \
+ "psraw $3, %%mm0 \n" \
+ "psraw $3, %%mm1 \n" \
+ "psraw $3, %%mm2 \n" \
+ "psraw $3, %%mm3 \n" \
+ \
+ "movq %%mm0, %%mm7 \n" \
+ "punpcklwd %%mm2, %%mm0 \n" /*A*/ \
+ "punpckhwd %%mm2, %%mm7 \n" /*C*/ \
+ "movq %%mm1, %%mm2 \n" \
+ "punpcklwd %%mm3, %%mm1 \n" /*B*/ \
+ "punpckhwd %%mm3, %%mm2 \n" /*D*/ \
+ "movq %%mm0, %%mm3 \n" \
+ "punpcklwd %%mm1, %%mm0 \n" /*A*/ \
+ "punpckhwd %%mm7, %%mm3 \n" /*C*/ \
+ "punpcklwd %%mm2, %%mm7 \n" /*B*/ \
+ "punpckhwd %%mm2, %%mm1 \n" /*D*/ \
+ \
+ "movq %%mm0, " #dst0 " \n" \
+ "movq %%mm7, " #dst1 " \n" \
+ "movq %%mm3, " #dst2 " \n" \
+ "movq %%mm1, " #dst3 " \n"
+
+ __asm__ volatile(
+ "movd %2, %%mm4 \n"
+ "movd %3, %%mm5 \n"
+ "movd %4, %%mm6 \n"
+ "packssdw %%mm4, %%mm4 \n"
+ "packssdw %%mm5, %%mm5 \n"
+ "packssdw %%mm6, %%mm6 \n"
+ "packssdw %%mm4, %%mm4 \n"
+ "packssdw %%mm5, %%mm5 \n"
+ "packssdw %%mm6, %%mm6 \n"
+ REQUANT_CORE( (%1), 8(%1), 16(%1), 24(%1), (%0), 8(%0), 64(%0), 72(%0))
+ REQUANT_CORE(32(%1), 40(%1), 48(%1), 56(%1),16(%0),24(%0), 48(%0), 56(%0))
+ REQUANT_CORE(64(%1), 72(%1), 80(%1), 88(%1),32(%0),40(%0), 96(%0),104(%0))
+ REQUANT_CORE(96(%1),104(%1),112(%1),120(%1),80(%0),88(%0),112(%0),120(%0))
+ : : "r" (src), "r" (dst), "g" (threshold1+1), "g" (threshold1+5), "g" (threshold1-4) //FIXME maybe more accurate then needed?
+ );
+ dst[0] = (src[0] + 4) >> 3;
+}
+
+static void softthresh_mmx(int16_t dst[64], const int16_t src[64],
+ int qp, const uint8_t *permutation)
+{
+ int bias = 0; //FIXME
+ unsigned int threshold1;
+
+ threshold1 = qp*((1<<4) - bias) - 1;
+
+#undef REQUANT_CORE
+#define REQUANT_CORE(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \
+ "movq " #src0 ", %%mm0 \n" \
+ "movq " #src1 ", %%mm1 \n" \
+ "pxor %%mm6, %%mm6 \n" \
+ "pxor %%mm7, %%mm7 \n" \
+ "pcmpgtw %%mm0, %%mm6 \n" \
+ "pcmpgtw %%mm1, %%mm7 \n" \
+ "pxor %%mm6, %%mm0 \n" \
+ "pxor %%mm7, %%mm1 \n" \
+ "psubusw %%mm4, %%mm0 \n" \
+ "psubusw %%mm4, %%mm1 \n" \
+ "pxor %%mm6, %%mm0 \n" \
+ "pxor %%mm7, %%mm1 \n" \
+ "movq " #src2 ", %%mm2 \n" \
+ "movq " #src3 ", %%mm3 \n" \
+ "pxor %%mm6, %%mm6 \n" \
+ "pxor %%mm7, %%mm7 \n" \
+ "pcmpgtw %%mm2, %%mm6 \n" \
+ "pcmpgtw %%mm3, %%mm7 \n" \
+ "pxor %%mm6, %%mm2 \n" \
+ "pxor %%mm7, %%mm3 \n" \
+ "psubusw %%mm4, %%mm2 \n" \
+ "psubusw %%mm4, %%mm3 \n" \
+ "pxor %%mm6, %%mm2 \n" \
+ "pxor %%mm7, %%mm3 \n" \
+ \
+ "paddsw %%mm5, %%mm0 \n" \
+ "paddsw %%mm5, %%mm1 \n" \
+ "paddsw %%mm5, %%mm2 \n" \
+ "paddsw %%mm5, %%mm3 \n" \
+ "psraw $3, %%mm0 \n" \
+ "psraw $3, %%mm1 \n" \
+ "psraw $3, %%mm2 \n" \
+ "psraw $3, %%mm3 \n" \
+ \
+ "movq %%mm0, %%mm7 \n" \
+ "punpcklwd %%mm2, %%mm0 \n" /*A*/ \
+ "punpckhwd %%mm2, %%mm7 \n" /*C*/ \
+ "movq %%mm1, %%mm2 \n" \
+ "punpcklwd %%mm3, %%mm1 \n" /*B*/ \
+ "punpckhwd %%mm3, %%mm2 \n" /*D*/ \
+ "movq %%mm0, %%mm3 \n" \
+ "punpcklwd %%mm1, %%mm0 \n" /*A*/ \
+ "punpckhwd %%mm7, %%mm3 \n" /*C*/ \
+ "punpcklwd %%mm2, %%mm7 \n" /*B*/ \
+ "punpckhwd %%mm2, %%mm1 \n" /*D*/ \
+ \
+ "movq %%mm0, " #dst0 " \n" \
+ "movq %%mm7, " #dst1 " \n" \
+ "movq %%mm3, " #dst2 " \n" \
+ "movq %%mm1, " #dst3 " \n"
+
+ __asm__ volatile(
+ "movd %2, %%mm4 \n"
+ "movd %3, %%mm5 \n"
+ "packssdw %%mm4, %%mm4 \n"
+ "packssdw %%mm5, %%mm5 \n"
+ "packssdw %%mm4, %%mm4 \n"
+ "packssdw %%mm5, %%mm5 \n"
+ REQUANT_CORE( (%1), 8(%1), 16(%1), 24(%1), (%0), 8(%0), 64(%0), 72(%0))
+ REQUANT_CORE(32(%1), 40(%1), 48(%1), 56(%1),16(%0),24(%0), 48(%0), 56(%0))
+ REQUANT_CORE(64(%1), 72(%1), 80(%1), 88(%1),32(%0),40(%0), 96(%0),104(%0))
+ REQUANT_CORE(96(%1),104(%1),112(%1),120(%1),80(%0),88(%0),112(%0),120(%0))
+ : : "r" (src), "r" (dst), "g" (threshold1), "rm" (4) //FIXME maybe more accurate then needed?
+ );
+
+ dst[0] = (src[0] + 4) >> 3;
+}
+
+static void store_slice_mmx(uint8_t *dst, const int16_t *src,
+ int dst_stride, int src_stride,
+ int width, int height, int log2_scale,
+ const uint8_t dither[8][8])
+{
+ int y;
+
+ for (y = 0; y < height; y++) {
+ uint8_t *dst1 = dst;
+ const int16_t *src1 = src;
+ __asm__ volatile(
+ "movq (%3), %%mm3 \n"
+ "movq (%3), %%mm4 \n"
+ "movd %4, %%mm2 \n"
+ "pxor %%mm0, %%mm0 \n"
+ "punpcklbw %%mm0, %%mm3 \n"
+ "punpckhbw %%mm0, %%mm4 \n"
+ "psraw %%mm2, %%mm3 \n"
+ "psraw %%mm2, %%mm4 \n"
+ "movd %5, %%mm2 \n"
+ "1: \n"
+ "movq (%0), %%mm0 \n"
+ "movq 8(%0), %%mm1 \n"
+ "paddw %%mm3, %%mm0 \n"
+ "paddw %%mm4, %%mm1 \n"
+ "psraw %%mm2, %%mm0 \n"
+ "psraw %%mm2, %%mm1 \n"
+ "packuswb %%mm1, %%mm0 \n"
+ "movq %%mm0, (%1) \n"
+ "add $16, %0 \n"
+ "add $8, %1 \n"
+ "cmp %2, %1 \n"
+ " jb 1b \n"
+ : "+r" (src1), "+r"(dst1)
+ : "r"(dst + width), "r"(dither[y]), "g"(log2_scale), "g"(MAX_LEVEL - log2_scale)
+ );
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+#endif /* HAVE_MMX_INLINE */
+
+av_cold void ff_spp_init_x86(SPPContext *s)
+{
+#if HAVE_MMX_INLINE
+ int cpu_flags = av_get_cpu_flags();
+
+ if (cpu_flags & AV_CPU_FLAG_MMX) {
+ s->store_slice = store_slice_mmx;
+ if (av_get_int(s->dct, "bits_per_sample", NULL) <= 8) {
+ switch (s->mode) {
+ case 0: s->requantize = hardthresh_mmx; break;
+ case 1: s->requantize = softthresh_mmx; break;
+ }
+ }
+ }
+#endif
+}
diff --git a/libavfilter/x86/vf_tinterlace_init.c b/libavfilter/x86/vf_tinterlace_init.c
new file mode 100644
index 0000000000..ddb0cced36
--- /dev/null
+++ b/libavfilter/x86/vf_tinterlace_init.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
+ *
+ * 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/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/internal.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+
+#include "libavfilter/tinterlace.h"
+
+void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize,
+ const uint8_t *srcp,
+ const uint8_t *srcp_above,
+ const uint8_t *srcp_below);
+void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize,
+ const uint8_t *srcp,
+ const uint8_t *srcp_above,
+ const uint8_t *srcp_below);
+
+av_cold void ff_tinterlace_init_x86(TInterlaceContext *s)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_SSE2(cpu_flags))
+ s->lowpass_line = ff_lowpass_line_sse2;
+ if (EXTERNAL_AVX(cpu_flags))
+ s->lowpass_line = ff_lowpass_line_avx;
+}
diff --git a/libavfilter/x86/vf_yadif.asm b/libavfilter/x86/vf_yadif.asm
index 3d8b2bc180..a29620ce55 100644
--- a/libavfilter/x86/vf_yadif.asm
+++ b/libavfilter/x86/vf_yadif.asm
@@ -4,20 +4,20 @@
;* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
;* Copyright (c) 2013 Daniel Kang <daniel.d.kang@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -39,11 +39,7 @@ SECTION .text
pavgb m5, m3
pand m4, [pb_1]
psubusb m5, m4
-%if mmsize == 16
- psrldq m5, 1
-%else
- psrlq m5, 8
-%endif
+ RSHIFT m5, 1
punpcklbw m5, m7
mova m4, m2
psubusb m2, m3
@@ -51,13 +47,8 @@ SECTION .text
pmaxub m2, m3
mova m3, m2
mova m4, m2
-%if mmsize == 16
- psrldq m3, 1
- psrldq m4, 2
-%else
- psrlq m3, 8
- psrlq m4, 16
-%endif
+ RSHIFT m3, 1
+ RSHIFT m4, 2
punpcklbw m2, m7
punpcklbw m3, m7
punpcklbw m4, m7
@@ -90,17 +81,17 @@ SECTION .text
%endmacro
%macro LOAD 2
- movh m%1, %2
- punpcklbw m%1, m7
+ movh %1, %2
+ punpcklbw %1, m7
%endmacro
%macro FILTER 3
.loop%1:
pxor m7, m7
- LOAD 0, [curq+t1]
- LOAD 1, [curq+t0]
- LOAD 2, [%2]
- LOAD 3, [%3]
+ LOAD m0, [curq+t1]
+ LOAD m1, [curq+t0]
+ LOAD m2, [%2]
+ LOAD m3, [%3]
mova m4, m3
paddw m3, m2
psraw m3, 1
@@ -109,8 +100,8 @@ SECTION .text
mova [rsp+32], m1
psubw m2, m4
ABS1 m2, m4
- LOAD 3, [prevq+t1]
- LOAD 4, [prevq+t0]
+ LOAD m3, [prevq+t1]
+ LOAD m4, [prevq+t0]
psubw m3, m0
psubw m4, m1
ABS1 m3, m5
@@ -119,8 +110,8 @@ SECTION .text
psrlw m2, 1
psrlw m3, 1
pmaxsw m2, m3
- LOAD 3, [nextq+t1]
- LOAD 4, [nextq+t0]
+ LOAD m3, [nextq+t1]
+ LOAD m4, [nextq+t0]
psubw m3, m0
psubw m4, m1
ABS1 m3, m5
@@ -166,10 +157,10 @@ SECTION .text
mova m6, [rsp+48]
cmp DWORD r8m, 2
jge .end%1
- LOAD 2, [%2+t1*2]
- LOAD 4, [%3+t1*2]
- LOAD 3, [%2+t0*2]
- LOAD 5, [%3+t0*2]
+ LOAD m2, [%2+t1*2]
+ LOAD m4, [%3+t1*2]
+ LOAD m3, [%2+t0*2]
+ LOAD m5, [%3+t0*2]
paddw m2, m4
paddw m3, m5
psrlw m2, 1
@@ -220,8 +211,6 @@ cglobal yadif_filter_line, 4, 6, 8, 80, dst, prev, cur, next, w, prefs, \
cglobal yadif_filter_line, 4, 7, 8, 80, dst, prev, cur, next, w, prefs, \
mrefs, parity, mode
%endif
- cmp DWORD wm, 0
- jle .ret
%if ARCH_X86_32
mov r4, r5mp
mov r5, r6mp
diff --git a/libavfilter/x86/vf_yadif_init.c b/libavfilter/x86/vf_yadif_init.c
index 510a02394c..1460a642c3 100644
--- a/libavfilter/x86/vf_yadif_init.c
+++ b/libavfilter/x86/vf_yadif_init.c
@@ -1,26 +1,25 @@
/*
* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/internal.h"
#include "libavutil/mem.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
@@ -36,16 +35,63 @@ void ff_yadif_filter_line_ssse3(void *dst, void *prev, void *cur,
void *next, int w, int prefs,
int mrefs, int parity, int mode);
+void ff_yadif_filter_line_16bit_mmxext(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+void ff_yadif_filter_line_16bit_sse2(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+void ff_yadif_filter_line_16bit_ssse3(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+void ff_yadif_filter_line_16bit_sse4(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+
+void ff_yadif_filter_line_10bit_mmxext(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+void ff_yadif_filter_line_10bit_sse2(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+void ff_yadif_filter_line_10bit_ssse3(void *dst, void *prev, void *cur,
+ void *next, int w, int prefs,
+ int mrefs, int parity, int mode);
+
av_cold void ff_yadif_init_x86(YADIFContext *yadif)
{
int cpu_flags = av_get_cpu_flags();
+ int bit_depth = (!yadif->csp) ? 8
+ : yadif->csp->comp[0].depth_minus1 + 1;
+ if (bit_depth >= 15) {
+#if ARCH_X86_32
+ if (EXTERNAL_MMXEXT(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_16bit_mmxext;
+#endif /* ARCH_X86_32 */
+ if (EXTERNAL_SSE2(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_16bit_sse2;
+ if (EXTERNAL_SSSE3(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_16bit_ssse3;
+ if (EXTERNAL_SSE4(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_16bit_sse4;
+ } else if ( bit_depth >= 9 && bit_depth <= 14) {
+#if ARCH_X86_32
+ if (EXTERNAL_MMXEXT(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_10bit_mmxext;
+#endif /* ARCH_X86_32 */
+ if (EXTERNAL_SSE2(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_10bit_sse2;
+ if (EXTERNAL_SSSE3(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_10bit_ssse3;
+ } else {
#if ARCH_X86_32
- if (EXTERNAL_MMXEXT(cpu_flags))
- yadif->filter_line = ff_yadif_filter_line_mmxext;
+ if (EXTERNAL_MMXEXT(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_mmxext;
#endif /* ARCH_X86_32 */
- if (EXTERNAL_SSE2(cpu_flags))
- yadif->filter_line = ff_yadif_filter_line_sse2;
- if (EXTERNAL_SSSE3(cpu_flags))
- yadif->filter_line = ff_yadif_filter_line_ssse3;
+ if (EXTERNAL_SSE2(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_sse2;
+ if (EXTERNAL_SSSE3(cpu_flags))
+ yadif->filter_line = ff_yadif_filter_line_ssse3;
+ }
}
diff --git a/libavfilter/x86/yadif-10.asm b/libavfilter/x86/yadif-10.asm
new file mode 100644
index 0000000000..8853e0d2c7
--- /dev/null
+++ b/libavfilter/x86/yadif-10.asm
@@ -0,0 +1,255 @@
+;*****************************************************************************
+;* x86-optimized functions for yadif filter
+;*
+;* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
+;* Copyright (c) 2013 Daniel Kang <daniel.d.kang@gmail.com>
+;* Copyright (c) 2011-2013 James Darnley <james.darnley@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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pw_1: times 8 dw 1
+
+SECTION .text
+
+%macro PMAXUW 2
+%if cpuflag(sse4)
+ pmaxuw %1, %2
+%else
+ psubusw %1, %2
+ paddusw %1, %2
+%endif
+%endmacro
+
+%macro CHECK 2
+ movu m2, [curq+t1+%1*2]
+ movu m3, [curq+t0+%2*2]
+ mova m4, m2
+ mova m5, m2
+ pxor m4, m3
+ pavgw m5, m3
+ pand m4, [pw_1]
+ psubusw m5, m4
+ RSHIFT m5, 2
+ mova m4, m2
+ psubusw m2, m3
+ psubusw m3, m4
+ PMAXUW m2, m3
+ mova m3, m2
+ mova m4, m2
+ RSHIFT m3, 2
+ RSHIFT m4, 4
+ paddw m2, m3
+ paddw m2, m4
+%endmacro
+
+%macro CHECK1 0
+ mova m3, m0
+ pcmpgtw m3, m2
+ pminsw m0, m2
+ mova m6, m3
+ pand m5, m3
+ pandn m3, m1
+ por m3, m5
+ mova m1, m3
+%endmacro
+
+; %macro CHECK2 0
+; paddw m6, [pw_1]
+; psllw m6, 14
+; paddsw m2, m6
+; mova m3, m0
+; pcmpgtw m3, m2
+; pminsw m0, m2
+; pand m5, m3
+; pandn m3, m1
+; por m3, m5
+; mova m1, m3
+; %endmacro
+
+; This version of CHECK2 is required for 14-bit samples. The left-shift trick
+; in the old code is not large enough to correctly select pixels or scores.
+
+%macro CHECK2 0
+ mova m3, m0
+ pcmpgtw m0, m2
+ pand m0, m6
+ mova m6, m0
+ pand m5, m6
+ pand m2, m0
+ pandn m6, m1
+ pandn m0, m3
+ por m6, m5
+ por m0, m2
+ mova m1, m6
+%endmacro
+
+%macro LOAD 2
+ movu %1, %2
+%endmacro
+
+%macro FILTER 3
+.loop%1:
+ pxor m7, m7
+ LOAD m0, [curq+t1]
+ LOAD m1, [curq+t0]
+ LOAD m2, [%2]
+ LOAD m3, [%3]
+ mova m4, m3
+ paddw m3, m2
+ psraw m3, 1
+ mova [rsp+ 0], m0
+ mova [rsp+16], m3
+ mova [rsp+32], m1
+ psubw m2, m4
+ ABS1 m2, m4
+ LOAD m3, [prevq+t1]
+ LOAD m4, [prevq+t0]
+ psubw m3, m0
+ psubw m4, m1
+ ABS2 m3, m4, m5, m6
+ paddw m3, m4
+ psrlw m2, 1
+ psrlw m3, 1
+ pmaxsw m2, m3
+ LOAD m3, [nextq+t1]
+ LOAD m4, [nextq+t0]
+ psubw m3, m0
+ psubw m4, m1
+ ABS2 m3, m4, m5, m6
+ paddw m3, m4
+ psrlw m3, 1
+ pmaxsw m2, m3
+ mova [rsp+48], m2
+
+ paddw m1, m0
+ paddw m0, m0
+ psubw m0, m1
+ psrlw m1, 1
+ ABS1 m0, m2
+
+ movu m2, [curq+t1-1*2]
+ movu m3, [curq+t0-1*2]
+ mova m4, m2
+ psubusw m2, m3
+ psubusw m3, m4
+ PMAXUW m2, m3
+ mova m3, m2
+ RSHIFT m3, 4
+ paddw m0, m2
+ paddw m0, m3
+ psubw m0, [pw_1]
+
+ CHECK -2, 0
+ CHECK1
+ CHECK -3, 1
+ CHECK2
+ CHECK 0, -2
+ CHECK1
+ CHECK 1, -3
+ CHECK2
+
+ mova m6, [rsp+48]
+ cmp DWORD r8m, 2
+ jge .end%1
+ LOAD m2, [%2+t1*2]
+ LOAD m4, [%3+t1*2]
+ LOAD m3, [%2+t0*2]
+ LOAD m5, [%3+t0*2]
+ paddw m2, m4
+ paddw m3, m5
+ psrlw m2, 1
+ psrlw m3, 1
+ mova m4, [rsp+ 0]
+ mova m5, [rsp+16]
+ mova m7, [rsp+32]
+ psubw m2, m4
+ psubw m3, m7
+ mova m0, m5
+ psubw m5, m4
+ psubw m0, m7
+ mova m4, m2
+ pminsw m2, m3
+ pmaxsw m3, m4
+ pmaxsw m2, m5
+ pminsw m3, m5
+ pmaxsw m2, m0
+ pminsw m3, m0
+ pxor m4, m4
+ pmaxsw m6, m3
+ psubw m4, m2
+ pmaxsw m6, m4
+
+.end%1:
+ mova m2, [rsp+16]
+ mova m3, m2
+ psubw m2, m6
+ paddw m3, m6
+ pmaxsw m1, m2
+ pminsw m1, m3
+
+ movu [dstq], m1
+ add dstq, mmsize-4
+ add prevq, mmsize-4
+ add curq, mmsize-4
+ add nextq, mmsize-4
+ sub DWORD r4m, mmsize/2-2
+ jg .loop%1
+%endmacro
+
+%macro YADIF 0
+%if ARCH_X86_32
+cglobal yadif_filter_line_10bit, 4, 6, 8, 80, dst, prev, cur, next, w, \
+ prefs, mrefs, parity, mode
+%else
+cglobal yadif_filter_line_10bit, 4, 7, 8, 80, dst, prev, cur, next, w, \
+ prefs, mrefs, parity, mode
+%endif
+%if ARCH_X86_32
+ mov r4, r5mp
+ mov r5, r6mp
+ DECLARE_REG_TMP 4,5
+%else
+ movsxd r5, DWORD r5m
+ movsxd r6, DWORD r6m
+ DECLARE_REG_TMP 5,6
+%endif
+
+ cmp DWORD paritym, 0
+ je .parity0
+ FILTER 1, prevq, curq
+ jmp .ret
+
+.parity0:
+ FILTER 0, curq, nextq
+
+.ret:
+ RET
+%endmacro
+
+INIT_XMM ssse3
+YADIF
+INIT_XMM sse2
+YADIF
+%if ARCH_X86_32
+INIT_MMX mmxext
+YADIF
+%endif
diff --git a/libavfilter/x86/yadif-16.asm b/libavfilter/x86/yadif-16.asm
new file mode 100644
index 0000000000..79d127dfaa
--- /dev/null
+++ b/libavfilter/x86/yadif-16.asm
@@ -0,0 +1,317 @@
+;*****************************************************************************
+;* x86-optimized functions for yadif filter
+;*
+;* Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at>
+;* Copyright (c) 2013 Daniel Kang <daniel.d.kang@gmail.com>
+;* Copyright (c) 2011-2013 James Darnley <james.darnley@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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+
+pw_1: times 8 dw 1
+pw_8000: times 8 dw 0x8000
+pd_1: times 4 dd 1
+pd_8000: times 4 dd 0x8000
+
+SECTION .text
+
+%macro PABS 2
+%if cpuflag(ssse3)
+ pabsd %1, %1
+%else
+ pxor %2, %2
+ pcmpgtd %2, %1
+ pxor %1, %2
+ psubd %1, %2
+%endif
+%endmacro
+
+%macro PACK 1
+%if cpuflag(sse4)
+ packusdw %1, %1
+%else
+ psubd %1, [pd_8000]
+ packssdw %1, %1
+ paddw %1, [pw_8000]
+%endif
+%endmacro
+
+%macro PMINSD 3
+%if cpuflag(sse4)
+ pminsd %1, %2
+%else
+ mova %3, %2
+ pcmpgtd %3, %1
+ pand %1, %3
+ pandn %3, %2
+ por %1, %3
+%endif
+%endmacro
+
+%macro PMAXSD 3
+%if cpuflag(sse4)
+ pmaxsd %1, %2
+%else
+ mova %3, %1
+ pcmpgtd %3, %2
+ pand %1, %3
+ pandn %3, %2
+ por %1, %3
+%endif
+%endmacro
+
+%macro PMAXUW 2
+%if cpuflag(sse4)
+ pmaxuw %1, %2
+%else
+ psubusw %1, %2
+ paddusw %1, %2
+%endif
+%endmacro
+
+%macro CHECK 2
+ movu m2, [curq+t1+%1*2]
+ movu m3, [curq+t0+%2*2]
+ mova m4, m2
+ mova m5, m2
+ pxor m4, m3
+ pavgw m5, m3
+ pand m4, [pw_1]
+ psubusw m5, m4
+ RSHIFT m5, 2
+ punpcklwd m5, m7
+ mova m4, m2
+ psubusw m2, m3
+ psubusw m3, m4
+ PMAXUW m2, m3
+ mova m3, m2
+ mova m4, m2
+ RSHIFT m3, 2
+ RSHIFT m4, 4
+ punpcklwd m2, m7
+ punpcklwd m3, m7
+ punpcklwd m4, m7
+ paddd m2, m3
+ paddd m2, m4
+%endmacro
+
+%macro CHECK1 0
+ mova m3, m0
+ pcmpgtd m3, m2
+ PMINSD m0, m2, m6
+ mova m6, m3
+ pand m5, m3
+ pandn m3, m1
+ por m3, m5
+ mova m1, m3
+%endmacro
+
+%macro CHECK2 0
+ paddd m6, [pd_1]
+ pslld m6, 30
+ paddd m2, m6
+ mova m3, m0
+ pcmpgtd m3, m2
+ PMINSD m0, m2, m4
+ pand m5, m3
+ pandn m3, m1
+ por m3, m5
+ mova m1, m3
+%endmacro
+
+; This version of CHECK2 has 3 fewer instructions on sets older than SSE4 but I
+; am not sure whether it is any faster. A rewrite or refactor of the filter
+; code should make it possible to eliminate the move instruction at the end. It
+; exists to satisfy the expectation that the "score" values are in m1.
+
+; %macro CHECK2 0
+; mova m3, m0
+; pcmpgtd m0, m2
+; pand m0, m6
+; mova m6, m0
+; pand m5, m6
+; pand m2, m0
+; pandn m6, m1
+; pandn m0, m3
+; por m6, m5
+; por m0, m2
+; mova m1, m6
+; %endmacro
+
+%macro LOAD 2
+ movh %1, %2
+ punpcklwd %1, m7
+%endmacro
+
+%macro FILTER 3
+.loop%1:
+ pxor m7, m7
+ LOAD m0, [curq+t1]
+ LOAD m1, [curq+t0]
+ LOAD m2, [%2]
+ LOAD m3, [%3]
+ mova m4, m3
+ paddd m3, m2
+ psrad m3, 1
+ mova [rsp+ 0], m0
+ mova [rsp+16], m3
+ mova [rsp+32], m1
+ psubd m2, m4
+ PABS m2, m4
+ LOAD m3, [prevq+t1]
+ LOAD m4, [prevq+t0]
+ psubd m3, m0
+ psubd m4, m1
+ PABS m3, m5
+ PABS m4, m5
+ paddd m3, m4
+ psrld m2, 1
+ psrld m3, 1
+ PMAXSD m2, m3, m6
+ LOAD m3, [nextq+t1]
+ LOAD m4, [nextq+t0]
+ psubd m3, m0
+ psubd m4, m1
+ PABS m3, m5
+ PABS m4, m5
+ paddd m3, m4
+ psrld m3, 1
+ PMAXSD m2, m3, m6
+ mova [rsp+48], m2
+
+ paddd m1, m0
+ paddd m0, m0
+ psubd m0, m1
+ psrld m1, 1
+ PABS m0, m2
+
+ movu m2, [curq+t1-1*2]
+ movu m3, [curq+t0-1*2]
+ mova m4, m2
+ psubusw m2, m3
+ psubusw m3, m4
+ PMAXUW m2, m3
+ mova m3, m2
+ RSHIFT m3, 4
+ punpcklwd m2, m7
+ punpcklwd m3, m7
+ paddd m0, m2
+ paddd m0, m3
+ psubd m0, [pd_1]
+
+ CHECK -2, 0
+ CHECK1
+ CHECK -3, 1
+ CHECK2
+ CHECK 0, -2
+ CHECK1
+ CHECK 1, -3
+ CHECK2
+
+ mova m6, [rsp+48]
+ cmp DWORD r8m, 2
+ jge .end%1
+ LOAD m2, [%2+t1*2]
+ LOAD m4, [%3+t1*2]
+ LOAD m3, [%2+t0*2]
+ LOAD m5, [%3+t0*2]
+ paddd m2, m4
+ paddd m3, m5
+ psrld m2, 1
+ psrld m3, 1
+ mova m4, [rsp+ 0]
+ mova m5, [rsp+16]
+ mova m7, [rsp+32]
+ psubd m2, m4
+ psubd m3, m7
+ mova m0, m5
+ psubd m5, m4
+ psubd m0, m7
+ mova m4, m2
+ PMINSD m2, m3, m7
+ PMAXSD m3, m4, m7
+ PMAXSD m2, m5, m7
+ PMINSD m3, m5, m7
+ PMAXSD m2, m0, m7
+ PMINSD m3, m0, m7
+ pxor m4, m4
+ PMAXSD m6, m3, m7
+ psubd m4, m2
+ PMAXSD m6, m4, m7
+
+.end%1:
+ mova m2, [rsp+16]
+ mova m3, m2
+ psubd m2, m6
+ paddd m3, m6
+ PMAXSD m1, m2, m7
+ PMINSD m1, m3, m7
+ PACK m1
+
+ movh [dstq], m1
+ add dstq, mmsize/2
+ add prevq, mmsize/2
+ add curq, mmsize/2
+ add nextq, mmsize/2
+ sub DWORD r4m, mmsize/4
+ jg .loop%1
+%endmacro
+
+%macro YADIF 0
+%if ARCH_X86_32
+cglobal yadif_filter_line_16bit, 4, 6, 8, 80, dst, prev, cur, next, w, \
+ prefs, mrefs, parity, mode
+%else
+cglobal yadif_filter_line_16bit, 4, 7, 8, 80, dst, prev, cur, next, w, \
+ prefs, mrefs, parity, mode
+%endif
+%if ARCH_X86_32
+ mov r4, r5mp
+ mov r5, r6mp
+ DECLARE_REG_TMP 4,5
+%else
+ movsxd r5, DWORD r5m
+ movsxd r6, DWORD r6m
+ DECLARE_REG_TMP 5,6
+%endif
+
+ cmp DWORD paritym, 0
+ je .parity0
+ FILTER 1, prevq, curq
+ jmp .ret
+
+.parity0:
+ FILTER 0, curq, nextq
+
+.ret:
+ RET
+%endmacro
+
+INIT_XMM sse4
+YADIF
+INIT_XMM ssse3
+YADIF
+INIT_XMM sse2
+YADIF
+%if ARCH_X86_32
+INIT_MMX mmxext
+YADIF
+%endif
diff --git a/libavfilter/yadif.h b/libavfilter/yadif.h
index 75e35c4bcf..d23d1380d0 100644
--- a/libavfilter/yadif.h
+++ b/libavfilter/yadif.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,31 +22,33 @@
#include "libavutil/pixdesc.h"
#include "avfilter.h"
+enum YADIFMode {
+ YADIF_MODE_SEND_FRAME = 0, ///< send 1 frame for each frame
+ YADIF_MODE_SEND_FIELD = 1, ///< send 1 frame for each field
+ YADIF_MODE_SEND_FRAME_NOSPATIAL = 2, ///< send 1 frame for each frame but skips spatial interlacing check
+ YADIF_MODE_SEND_FIELD_NOSPATIAL = 3, ///< send 1 frame for each field but skips spatial interlacing check
+};
+
+enum YADIFParity {
+ YADIF_PARITY_TFF = 0, ///< top field first
+ YADIF_PARITY_BFF = 1, ///< bottom field first
+ YADIF_PARITY_AUTO = -1, ///< auto detection
+};
+
+enum YADIFDeint {
+ YADIF_DEINT_ALL = 0, ///< deinterlace all frames
+ YADIF_DEINT_INTERLACED = 1, ///< only deinterlace frames marked as interlaced
+};
+
typedef struct YADIFContext {
const AVClass *class;
- /**
- * 0: send 1 frame for each frame
- * 1: send 1 frame for each field
- * 2: like 0 but skips spatial interlacing check
- * 3: like 1 but skips spatial interlacing check
- */
- int mode;
- /**
- * 0: top field first
- * 1: bottom field first
- * -1: auto-detection
- */
- int parity;
+ int mode; ///< YADIFMode
+ int parity; ///< YADIFParity
+ int deint; ///< YADIFDeint
int frame_pending;
- /**
- * 0: deinterlace all frames
- * 1: only deinterlace frames marked as interlaced
- */
- int auto_enable;
-
AVFrame *cur;
AVFrame *next;
AVFrame *prev;
@@ -63,6 +65,8 @@ typedef struct YADIFContext {
const AVPixFmtDescriptor *csp;
int eof;
+ uint8_t *temp_line;
+ int temp_line_size;
} YADIFContext;
void ff_yadif_init_x86(YADIFContext *yadif);
diff --git a/libavformat/4xm.c b/libavformat/4xm.c
index 6253ffb58e..8fdad185f4 100644
--- a/libavformat/4xm.c
+++ b/libavformat/4xm.c
@@ -1,21 +1,21 @@
/*
* 4X Technologies .4xm File Demuxer (no muxer)
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -77,7 +77,7 @@ typedef struct FourxmDemuxContext {
AudioTrack *tracks;
int64_t video_pts;
- float fps;
+ AVRational fps;
} FourxmDemuxContext;
static int fourxm_probe(AVProbeData *p)
@@ -104,7 +104,7 @@ static int parse_vtrk(AVFormatContext *s,
if (!st)
return AVERROR(ENOMEM);
- avpriv_set_pts_info(st, 60, 1, fourxm->fps);
+ avpriv_set_pts_info(st, 60, fourxm->fps.den, fourxm->fps.num);
fourxm->video_stream_index = st->index;
@@ -134,8 +134,11 @@ static int parse_strk(AVFormatContext *s,
return AVERROR_INVALIDDATA;
track = AV_RL32(buf + 8);
- if (track < 0)
+ if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1) {
+ av_log(s, AV_LOG_ERROR, "current_track too large\n");
return AVERROR_INVALIDDATA;
+ }
+
if (track + 1 > fourxm->track_count) {
if (av_reallocp_array(&fourxm->tracks, track + 1, sizeof(AudioTrack)))
return AVERROR(ENOMEM);
@@ -155,6 +158,11 @@ static int parse_strk(AVFormatContext *s,
av_log(s, AV_LOG_ERROR, "audio header invalid\n");
return AVERROR_INVALIDDATA;
}
+ if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) {
+ av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st)
@@ -198,7 +206,7 @@ static int fourxm_read_header(AVFormatContext *s)
fourxm->track_count = 0;
fourxm->tracks = NULL;
- fourxm->fps = 1.0;
+ fourxm->fps = (AVRational){1,1};
/* skip the first 3 32-bit numbers */
avio_skip(pb, 12);
@@ -222,13 +230,18 @@ static int fourxm_read_header(AVFormatContext *s)
for (i = 0; i < header_size - 8; i++) {
fourcc_tag = AV_RL32(&header[i]);
size = AV_RL32(&header[i + 4]);
+ if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) {
+ av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8);
+ return AVERROR_INVALIDDATA;
+ }
if (fourcc_tag == std__TAG) {
if (header_size - i < 16) {
+ av_log(s, AV_LOG_ERROR, "std TAG truncated\n");
ret = AVERROR_INVALIDDATA;
goto fail;
}
- fourxm->fps = av_int2float(AV_RL32(&header[i + 12]));
+ fourxm->fps = av_d2q(av_int2float(AV_RL32(&header[i + 12])), 10000);
} else if (fourcc_tag == vtrk_TAG) {
if ((ret = parse_vtrk(s, fourxm, header + i, size,
header_size - i)) < 0)
@@ -280,7 +293,7 @@ static int fourxm_read_packet(AVFormatContext *s,
return ret;
fourcc_tag = AV_RL32(&header[0]);
size = AV_RL32(&header[4]);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
switch (fourcc_tag) {
case LIST_TAG:
@@ -309,8 +322,10 @@ static int fourxm_read_packet(AVFormatContext *s,
if (ret < 0) {
av_free_packet(pkt);
- } else
+ } else {
packet_read = 1;
+ av_shrink_packet(pkt, ret + 8);
+ }
break;
case snd__TAG:
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 73b9f63ba9..bca9d5b9d4 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avformat
HEADERS = avformat.h \
@@ -12,7 +14,6 @@ OBJS = allformats.o \
format.o \
id3v1.o \
id3v2.o \
- log2_tab.o \
metadata.o \
mux.o \
options.o \
@@ -54,47 +55,70 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \
rtpdec_xiph.o \
srtp.o
OBJS-$(CONFIG_RTPENC_CHAIN) += rtpenc_chain.o rtp.o
+OBJS-$(CONFIG_SHARED) += log2_tab.o golomb_tab.o
# muxers/demuxers
OBJS-$(CONFIG_A64_MUXER) += a64.o rawenc.o
-OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o rawdec.o
+OBJS-$(CONFIG_AAC_DEMUXER) += aacdec.o apetag.o img2.o rawdec.o
OBJS-$(CONFIG_AC3_DEMUXER) += ac3dec.o rawdec.o
OBJS-$(CONFIG_AC3_MUXER) += rawenc.o
+OBJS-$(CONFIG_ACT_DEMUXER) += act.o
+OBJS-$(CONFIG_ADF_DEMUXER) += bintext.o sauce.o
+OBJS-$(CONFIG_ADP_DEMUXER) += adp.o
OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o
OBJS-$(CONFIG_ADX_MUXER) += rawenc.o
-OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o
+OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o apetag.o img2.o \
+ id3v2enc.o
OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o
-OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o pcm.o
-OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o
+OBJS-$(CONFIG_AFC_DEMUXER) += afc.o
+OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o pcm.o isom.o \
+ mov_chan.o
+OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o isom.o id3v2enc.o
OBJS-$(CONFIG_AMR_DEMUXER) += amr.o
OBJS-$(CONFIG_AMR_MUXER) += amr.o
OBJS-$(CONFIG_ANM_DEMUXER) += anm.o
OBJS-$(CONFIG_APC_DEMUXER) += apc.o
OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o
+OBJS-$(CONFIG_APNG_DEMUXER) += apngdec.o
+OBJS-$(CONFIG_APNG_MUXER) += apngenc.o
+OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o
OBJS-$(CONFIG_ASF_DEMUXER) += asfdec.o asf.o asfcrypt.o \
avlanguage.o
OBJS-$(CONFIG_ASF_MUXER) += asfenc.o asf.o
-OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o
+OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o subtitles.o
OBJS-$(CONFIG_ASS_MUXER) += assenc.o
+OBJS-$(CONFIG_AST_DEMUXER) += ast.o astdec.o
+OBJS-$(CONFIG_AST_MUXER) += ast.o astenc.o
OBJS-$(CONFIG_AU_DEMUXER) += au.o pcm.o
OBJS-$(CONFIG_AU_MUXER) += au.o rawenc.o
OBJS-$(CONFIG_AVI_DEMUXER) += avidec.o isom.o
-OBJS-$(CONFIG_AVI_MUXER) += avienc.o
+OBJS-$(CONFIG_AVI_MUXER) += avienc.o mpegtsenc.o avlanguage.o
OBJS-$(CONFIG_AVISYNTH) += avisynth.o
OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o swf.o
+OBJS-$(CONFIG_AVR_DEMUXER) += avr.o pcm.o
OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o
OBJS-$(CONFIG_BETHSOFTVID_DEMUXER) += bethsoftvid.o
OBJS-$(CONFIG_BFI_DEMUXER) += bfi.o
OBJS-$(CONFIG_BINK_DEMUXER) += bink.o
+OBJS-$(CONFIG_BINTEXT_DEMUXER) += bintext.o sauce.o
+OBJS-$(CONFIG_BIT_DEMUXER) += bit.o
+OBJS-$(CONFIG_BIT_MUXER) += bit.o
OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o
+OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o
+OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o
OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o
OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \
isom.o replaygain.o
+OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o isom.o
OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o
OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o
OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o
+OBJS-$(CONFIG_CINE_DEMUXER) += cinedec.o
+OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o
OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
+OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o
+OBJS-$(CONFIG_DATA_MUXER) += rawdec.o
OBJS-$(CONFIG_DASH_MUXER) += dashenc.o isom.o
OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o
OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o
@@ -103,17 +127,23 @@ OBJS-$(CONFIG_DIRAC_DEMUXER) += diracdec.o rawdec.o
OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o
OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddec.o rawdec.o
OBJS-$(CONFIG_DNXHD_MUXER) += rawenc.o
+OBJS-$(CONFIG_DSF_DEMUXER) += dsfdec.o
OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o
OBJS-$(CONFIG_DSS_DEMUXER) += dss.o
+OBJS-$(CONFIG_DTSHD_DEMUXER) += dtshddec.o
OBJS-$(CONFIG_DTS_DEMUXER) += dtsdec.o rawdec.o
OBJS-$(CONFIG_DTS_MUXER) += rawenc.o
OBJS-$(CONFIG_DV_DEMUXER) += dv.o
OBJS-$(CONFIG_DV_MUXER) += dvenc.o
+OBJS-$(CONFIG_DVBSUB_DEMUXER) += dvbsub.o
OBJS-$(CONFIG_DXA_DEMUXER) += dxa.o
OBJS-$(CONFIG_EA_CDATA_DEMUXER) += eacdata.o
OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o
OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o
OBJS-$(CONFIG_EAC3_MUXER) += rawenc.o
+OBJS-$(CONFIG_EPAF_DEMUXER) += epafdec.o pcm.o
+OBJS-$(CONFIG_FFM_DEMUXER) += ffmdec.o
+OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o
OBJS-$(CONFIG_FFMETADATA_DEMUXER) += ffmetadec.o
OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o
OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o
@@ -127,17 +157,22 @@ OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \
vorbiscomment.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
OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o
OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o
OBJS-$(CONFIG_FRAMEMD5_MUXER) += md5enc.o framehash.o
+OBJS-$(CONFIG_FRM_DEMUXER) += frmdec.o
OBJS-$(CONFIG_GIF_MUXER) += gif.o
+OBJS-$(CONFIG_GIF_DEMUXER) += gifdec.o
OBJS-$(CONFIG_GSM_DEMUXER) += gsmdec.o
OBJS-$(CONFIG_GXF_DEMUXER) += gxf.o
OBJS-$(CONFIG_GXF_MUXER) += gxfenc.o audiointerleave.o
OBJS-$(CONFIG_G722_DEMUXER) += g722.o rawdec.o
OBJS-$(CONFIG_G722_MUXER) += rawenc.o
OBJS-$(CONFIG_G723_1_DEMUXER) += g723_1.o
+OBJS-$(CONFIG_G723_1_MUXER) += rawenc.o
+OBJS-$(CONFIG_G729_DEMUXER) += g729dec.o
OBJS-$(CONFIG_H261_DEMUXER) += h261dec.o rawdec.o
OBJS-$(CONFIG_H261_MUXER) += rawenc.o
OBJS-$(CONFIG_H263_DEMUXER) += h263dec.o rawdec.o
@@ -150,7 +185,10 @@ OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o
OBJS-$(CONFIG_HLS_DEMUXER) += hls.o
OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o
OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o
+OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o
+OBJS-$(CONFIG_ICO_MUXER) += icoenc.o
OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o
+OBJS-$(CONFIG_IDF_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_IFF_DEMUXER) += iff.o
OBJS-$(CONFIG_ILBC_DEMUXER) += ilbc.o
OBJS-$(CONFIG_ILBC_MUXER) += ilbc.o
@@ -158,37 +196,65 @@ OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2dec.o img2.o
OBJS-$(CONFIG_IMAGE2_MUXER) += img2enc.o img2.o
OBJS-$(CONFIG_IMAGE2PIPE_DEMUXER) += img2dec.o img2.o
OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2enc.o img2.o
+OBJS-$(CONFIG_IMAGE2_ALIAS_PIX_DEMUXER) += img2_alias_pix.o
+OBJS-$(CONFIG_IMAGE2_BRENDER_PIX_DEMUXER) += img2_brender_pix.o
+OBJS-$(CONFIG_IMAGE_BMP_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_DPX_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_EXR_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_JPEG_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_PICTOR_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_PNG_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_QDRAW_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_TIFF_PIPE_DEMUXER) += img2dec.o img2.o
+OBJS-$(CONFIG_IMAGE_WEBP_PIPE_DEMUXER) += img2dec.o img2.o
OBJS-$(CONFIG_INGENIENT_DEMUXER) += ingenientdec.o rawdec.o
OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o
+OBJS-$(CONFIG_IRCAM_DEMUXER) += ircamdec.o ircam.o pcm.o
+OBJS-$(CONFIG_IRCAM_MUXER) += ircamenc.o ircam.o rawenc.o
OBJS-$(CONFIG_ISS_DEMUXER) += iss.o
OBJS-$(CONFIG_IV8_DEMUXER) += iv8.o
OBJS-$(CONFIG_IVF_DEMUXER) += ivfdec.o
OBJS-$(CONFIG_IVF_MUXER) += ivfenc.o
+OBJS-$(CONFIG_JACOSUB_DEMUXER) += jacosubdec.o subtitles.o
+OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o
OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o
OBJS-$(CONFIG_LATM_DEMUXER) += rawdec.o
-OBJS-$(CONFIG_LATM_MUXER) += latmenc.o
+OBJS-$(CONFIG_LATM_MUXER) += latmenc.o rawenc.o
OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o
+OBJS-$(CONFIG_LOAS_DEMUXER) += loasdec.o rawdec.o
+OBJS-$(CONFIG_LRC_DEMUXER) += lrcdec.o lrc.o subtitles.o
+OBJS-$(CONFIG_LRC_MUXER) += lrcenc.o lrc.o
+OBJS-$(CONFIG_LVF_DEMUXER) += lvfdec.o
OBJS-$(CONFIG_LXF_DEMUXER) += lxfdec.o
OBJS-$(CONFIG_M4V_DEMUXER) += m4vdec.o rawdec.o
OBJS-$(CONFIG_M4V_MUXER) += rawenc.o
OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \
- isom.o rmsipr.o \
+ isom.o rmsipr.o flac_picture.o \
oggparsevorbis.o vorbiscomment.o \
flac_picture.o replaygain.o
OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o hevc.o \
- flacenc_header.o avlanguage.o vorbiscomment.o wv.o
+ flacenc_header.o avlanguage.o vorbiscomment.o wv.o \
+ webmdashenc.o webm_chunk.o
OBJS-$(CONFIG_MD5_MUXER) += md5enc.o
+OBJS-$(CONFIG_MGSTS_DEMUXER) += mgsts.o
+OBJS-$(CONFIG_MICRODVD_DEMUXER) += microdvddec.o subtitles.o
+OBJS-$(CONFIG_MICRODVD_MUXER) += microdvdenc.o
OBJS-$(CONFIG_MJPEG_DEMUXER) += rawdec.o
OBJS-$(CONFIG_MJPEG_MUXER) += rawenc.o
OBJS-$(CONFIG_MLP_DEMUXER) += rawdec.o
OBJS-$(CONFIG_MLP_MUXER) += rawenc.o
+OBJS-$(CONFIG_MLV_DEMUXER) += mlvdec.o riffdec.o
OBJS-$(CONFIG_MM_DEMUXER) += mm.o
-OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o pcm.o
-OBJS-$(CONFIG_MMF_MUXER) += mmf.o
+OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o
+OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o
OBJS-$(CONFIG_MOV_DEMUXER) += mov.o isom.o mov_chan.o replaygain.o
OBJS-$(CONFIG_MOV_MUXER) += movenc.o isom.o avc.o hevc.o \
- movenchint.o mov_chan.o
+ movenchint.o mov_chan.o rtp.o
OBJS-$(CONFIG_MP2_MUXER) += mp3enc.o rawenc.o id3v2enc.o
OBJS-$(CONFIG_MP3_DEMUXER) += mp3dec.o replaygain.o
OBJS-$(CONFIG_MP3_MUXER) += mp3enc.o rawenc.o id3v2enc.o
@@ -206,6 +272,8 @@ OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o isom.o
OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o
OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o
OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o
+OBJS-$(CONFIG_MPL2_DEMUXER) += mpl2dec.o subtitles.o
+OBJS-$(CONFIG_MPSUB_DEMUXER) += mpsubdec.o subtitles.o
OBJS-$(CONFIG_MSNWC_TCP_DEMUXER) += msnwc_tcp.o
OBJS-$(CONFIG_MTV_DEMUXER) += mtv.o
OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o
@@ -214,9 +282,10 @@ OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o
OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o
OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o
OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o
+OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o
OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o
OBJS-$(CONFIG_NULL_MUXER) += nullenc.o
-OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o
+OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o isom.o
OBJS-$(CONFIG_NUT_MUXER) += nutenc.o nut.o
OBJS-$(CONFIG_NUV_DEMUXER) += nuv.o
OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \
@@ -233,10 +302,14 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \
replaygain.o \
vorbiscomment.o \
flac_picture.o
+OBJS-$(CONFIG_OGA_MUXER) += oggenc.o \
+ vorbiscomment.o
OBJS-$(CONFIG_OGG_MUXER) += oggenc.o \
vorbiscomment.o
OBJS-$(CONFIG_OMA_DEMUXER) += omadec.o pcm.o oma.o
OBJS-$(CONFIG_OMA_MUXER) += omaenc.o rawenc.o oma.o id3v2enc.o
+OBJS-$(CONFIG_OPUS_MUXER) += oggenc.o \
+ vorbiscomment.o
OBJS-$(CONFIG_PAF_DEMUXER) += paf.o
OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_ALAW_MUXER) += pcmenc.o rawenc.o
@@ -278,17 +351,22 @@ OBJS-$(CONFIG_PCM_U32LE_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U32LE_MUXER) += pcmenc.o rawenc.o
OBJS-$(CONFIG_PCM_U8_DEMUXER) += pcmdec.o pcm.o
OBJS-$(CONFIG_PCM_U8_MUXER) += pcmenc.o rawenc.o
+OBJS-$(CONFIG_PJS_DEMUXER) += pjsdec.o subtitles.o
OBJS-$(CONFIG_PMP_DEMUXER) += pmpdec.o
OBJS-$(CONFIG_PVA_DEMUXER) += pva.o
+OBJS-$(CONFIG_PVF_DEMUXER) += pvfdec.o pcm.o
OBJS-$(CONFIG_QCP_DEMUXER) += qcp.o
OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o
OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o
OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o
+OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o
+OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o
OBJS-$(CONFIG_RL2_DEMUXER) += rl2.o
OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o rm.o rmsipr.o
OBJS-$(CONFIG_RM_MUXER) += rmenc.o rm.o
OBJS-$(CONFIG_ROQ_DEMUXER) += idroqdec.o
OBJS-$(CONFIG_ROQ_MUXER) += idroqenc.o rawenc.o
+OBJS-$(CONFIG_RSD_DEMUXER) += rsd.o
OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o
OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o
OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o
@@ -311,9 +389,12 @@ OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o \
urldecode.o
OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o \
urldecode.o
+OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o
OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o
OBJS-$(CONFIG_SAP_MUXER) += sapenc.o
+OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o
OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o
+OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o
OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o
OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o
OBJS-$(CONFIG_SHORTEN_DEMUXER) += rawdec.o
@@ -325,45 +406,73 @@ OBJS-$(CONFIG_SMOOTHSTREAMING_MUXER) += smoothstreamingenc.o isom.o
OBJS-$(CONFIG_SMUSH_DEMUXER) += smush.o
OBJS-$(CONFIG_SOL_DEMUXER) += sol.o pcm.o
OBJS-$(CONFIG_SOX_DEMUXER) += soxdec.o pcm.o
-OBJS-$(CONFIG_SOX_MUXER) += soxenc.o
+OBJS-$(CONFIG_SOX_MUXER) += soxenc.o rawenc.o
OBJS-$(CONFIG_SPDIF_DEMUXER) += spdif.o spdifdec.o
OBJS-$(CONFIG_SPDIF_MUXER) += spdif.o spdifenc.o
-OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o
-OBJS-$(CONFIG_SRT_MUXER) += rawenc.o
+OBJS-$(CONFIG_SPEEX_MUXER) += oggenc.o \
+ vorbiscomment.o
+OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o
+OBJS-$(CONFIG_SRT_MUXER) += srtenc.o
+OBJS-$(CONFIG_STL_DEMUXER) += stldec.o subtitles.o
OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o
+OBJS-$(CONFIG_SUBVIEWER1_DEMUXER) += subviewer1dec.o subtitles.o
+OBJS-$(CONFIG_SUBVIEWER_DEMUXER) += subviewerdec.o subtitles.o
+OBJS-$(CONFIG_SUP_DEMUXER) += supdec.o
OBJS-$(CONFIG_SWF_DEMUXER) += swfdec.o swf.o
OBJS-$(CONFIG_SWF_MUXER) += swfenc.o swf.o
OBJS-$(CONFIG_TAK_DEMUXER) += takdec.o apetag.o img2.o rawdec.o
+OBJS-$(CONFIG_TEDCAPTIONS_DEMUXER) += tedcaptionsdec.o subtitles.o
+OBJS-$(CONFIG_TEE_MUXER) += tee.o
OBJS-$(CONFIG_THP_DEMUXER) += thp.o
OBJS-$(CONFIG_TIERTEXSEQ_DEMUXER) += tiertexseq.o
+OBJS-$(CONFIG_MKVTIMESTAMP_V2_MUXER) += mkvtimestamp_v2.o
OBJS-$(CONFIG_TMV_DEMUXER) += tmv.o
OBJS-$(CONFIG_TRUEHD_DEMUXER) += rawdec.o
OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o
-OBJS-$(CONFIG_TTA_DEMUXER) += tta.o
+OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o
OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o
OBJS-$(CONFIG_TXD_DEMUXER) += txd.o
+OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o
OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o
+OBJS-$(CONFIG_VC1_MUXER) += rawenc.o
OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o
OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o
+OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o
OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o
+OBJS-$(CONFIG_VOBSUB_DEMUXER) += subtitles.o # mpeg demuxer is in the dependencies
OBJS-$(CONFIG_VOC_DEMUXER) += vocdec.o voc.o
OBJS-$(CONFIG_VOC_MUXER) += vocenc.o voc.o
+OBJS-$(CONFIG_VPLAYER_DEMUXER) += vplayerdec.o subtitles.o
OBJS-$(CONFIG_VQF_DEMUXER) += vqf.o
-OBJS-$(CONFIG_W64_DEMUXER) += wavdec.o pcm.o
+OBJS-$(CONFIG_W64_DEMUXER) += wavdec.o w64.o pcm.o
+OBJS-$(CONFIG_W64_MUXER) += wavenc.o w64.o
OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o
OBJS-$(CONFIG_WAV_MUXER) += wavenc.o
OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o
OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \
isom.o avc.o hevc.o \
flacenc_header.o avlanguage.o \
- wv.o vorbiscomment.o
+ wv.o vorbiscomment.o \
+ webmdashenc.o webm_chunk.o
+OBJS-$(CONFIG_WEBM_DASH_MANIFEST_DEMUXER)+= matroskadec.o matroska.o \
+ isom.o rmsipr.o flac_picture.o \
+ oggparsevorbis.o vorbiscomment.o \
+ flac_picture.o replaygain.o
+OBJS-$(CONFIG_WEBM_DASH_MANIFEST_MUXER) += webmdashenc.o matroska.o
+OBJS-$(CONFIG_WEBM_CHUNK_MUXER) += webm_chunk.o matroska.o
+OBJS-$(CONFIG_WEBP_MUXER) += webpenc.o
+OBJS-$(CONFIG_WEBVTT_DEMUXER) += webvttdec.o subtitles.o
+OBJS-$(CONFIG_WEBVTT_MUXER) += webvttenc.o
OBJS-$(CONFIG_WSAUD_DEMUXER) += westwood_aud.o
OBJS-$(CONFIG_WSVQA_DEMUXER) += westwood_vqa.o
-OBJS-$(CONFIG_WTV_DEMUXER) += wtv.o asfdec.o asf.o asfcrypt.o \
+OBJS-$(CONFIG_WTV_DEMUXER) += wtvdec.o wtv_common.o asfdec.o asf.o asfcrypt.o \
avlanguage.o mpegts.o isom.o
+OBJS-$(CONFIG_WTV_MUXER) += wtvenc.o wtv_common.o \
+ mpegtsenc.o asf.o
OBJS-$(CONFIG_WV_DEMUXER) += wvdec.o wv.o apetag.o img2.o
OBJS-$(CONFIG_WV_MUXER) += wvenc.o wv.o apetag.o img2.o
OBJS-$(CONFIG_XA_DEMUXER) += xa.o
+OBJS-$(CONFIG_XBIN_DEMUXER) += bintext.o sauce.o
OBJS-$(CONFIG_XMV_DEMUXER) += xmv.o
OBJS-$(CONFIG_XWMA_DEMUXER) += xwma.o
OBJS-$(CONFIG_YOP_DEMUXER) += yop.o
@@ -371,15 +480,26 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpegenc.o
OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpegdec.o
# external libraries
+OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o
+OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o
+OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o
+OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o
+OBJS-$(CONFIG_LIBQUVI_DEMUXER) += libquvi.o
OBJS-$(CONFIG_LIBRTMP) += librtmp.o
+OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o
+OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o
# protocols I/O
OBJS-$(CONFIG_APPLEHTTP_PROTOCOL) += hlsproto.o
+OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o
+OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o
OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o
OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o
+OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o
OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o
OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o
OBJS-$(CONFIG_FILE_PROTOCOL) += file.o
+OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o
OBJS-$(CONFIG_GOPHER_PROTOCOL) += gopher.o
OBJS-$(CONFIG_HLS_PROTOCOL) += hlsproto.o
OBJS-$(CONFIG_HTTP_PROTOCOL) += http.o httpauth.o urldecode.o
@@ -399,13 +519,21 @@ OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o
OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
+OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o
OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o
OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o
OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o
+OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o
OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o
OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
+# libavdevice dependencies
+OBJS-$(CONFIG_IEC61883_INDEV) += dv.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avformatres.o
+
SKIPHEADERS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpdh.h
SKIPHEADERS-$(CONFIG_NETWORK) += network.h rtsp.h
@@ -419,4 +547,5 @@ TOOLS = aviocat \
ismindex \
pktdumper \
probetest \
+ seek_print \
sidxindex \
diff --git a/libavformat/a64.c b/libavformat/a64.c
index c8e8e646b5..a7f93a27b1 100644
--- a/libavformat/a64.c
+++ b/libavformat/a64.c
@@ -2,25 +2,24 @@
* a64 muxer
* Copyright (c) 2009 Tobias Bindhammer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avcodec.h"
-#include "libavcodec/a64enc.h"
#include "libavcodec/bytestream.h"
#include "avformat.h"
#include "rawenc.h"
@@ -41,7 +40,7 @@ static int a64_write_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- switch (avctx->codec->id) {
+ switch (avctx->codec_id) {
case AV_CODEC_ID_A64_MULTI:
header[2] = 0x00;
header[3] = AV_RB32(avctx->extradata+0);
diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c
index 566c3e78b9..1b98e1ddb5 100644
--- a/libavformat/aacdec.c
+++ b/libavformat/aacdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2009 Robert Swain ( rob opendot cl )
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,15 +25,16 @@
#include "internal.h"
#include "rawdec.h"
#include "id3v1.h"
+#include "apetag.h"
static int adts_aac_probe(AVProbeData *p)
{
int max_frames = 0, first_frames = 0;
int fsize, frames;
- uint8_t *buf0 = p->buf;
- uint8_t *buf2;
- uint8_t *buf;
- uint8_t *end = buf0 + p->buf_size - 7;
+ const uint8_t *buf0 = p->buf;
+ const uint8_t *buf2;
+ const uint8_t *buf;
+ const uint8_t *end = buf0 + p->buf_size - 7;
buf = buf0;
@@ -55,6 +56,7 @@ static int adts_aac_probe(AVProbeData *p)
fsize = (AV_RB32(buf2 + 3) >> 13) & 0x1FFF;
if (fsize < 7)
break;
+ fsize = FFMIN(fsize, end - buf2);
buf2 += fsize;
}
max_frames = FFMAX(max_frames, frames);
@@ -84,9 +86,15 @@ static int adts_aac_read_header(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = s->iformat->raw_codec_id;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
ff_id3v1_read(s);
+ if (s->pb->seekable &&
+ !av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
+ int64_t cur = avio_tell(s->pb);
+ ff_ape_parse_tag(s);
+ avio_seek(s->pb, cur, SEEK_SET);
+ }
// LCM of all possible ADTS sample rates
avpriv_set_pts_info(st, 64, 1, 28224000);
diff --git a/libavformat/ac3dec.c b/libavformat/ac3dec.c
index 4ceffa54dd..58ef44d45a 100644
--- a/libavformat/ac3dec.c
+++ b/libavformat/ac3dec.c
@@ -2,20 +2,20 @@
* RAW AC-3 and E-AC-3 demuxer
* Copyright (c) 2007 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,8 +27,8 @@
static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id)
{
int max_frames, first_frames = 0, frames;
- uint8_t *buf, *buf2, *end;
- AC3HeaderInfo hdr;
+ const uint8_t *buf, *buf2, *end;
+ AC3HeaderInfo *phdr = NULL;
GetBitContext gbc;
enum AVCodecID codec_id = AV_CODEC_ID_AC3;
@@ -37,51 +37,54 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id)
end = buf + p->buf_size;
for(; buf < end; buf++) {
+ if(buf > p->buf && !(buf[0] == 0x0B && buf[1] == 0x77)
+ && !(buf[0] == 0x77 && buf[1] == 0x0B) )
+ continue;
buf2 = buf;
for(frames = 0; buf2 < end; frames++) {
- init_get_bits(&gbc, buf2, 54);
- if(avpriv_ac3_parse_header(&gbc, &hdr) < 0)
+ uint8_t buf3[4096];
+ int i;
+ if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8))
+ buf2+=16;
+ if (buf[0] == 0x77 && buf[1] == 0x0B) {
+ for(i=0; i<8; i+=2) {
+ buf3[i ] = buf[i+1];
+ buf3[i+1] = buf[i ];
+ }
+ init_get_bits(&gbc, buf3, 54);
+ }else
+ init_get_bits(&gbc, buf2, 54);
+ if(avpriv_ac3_parse_header2(&gbc, &phdr) < 0)
break;
- if(buf2 + hdr.frame_size > end ||
- av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, hdr.frame_size - 2))
+ if(buf2 + phdr->frame_size > end)
break;
- if (hdr.bitstream_id > 10)
+ if (buf[0] == 0x77 && buf[1] == 0x0B) {
+ av_assert0(phdr->frame_size <= sizeof(buf3));
+ for(i=8; i<phdr->frame_size; i+=2) {
+ buf3[i ] = buf[i+1];
+ buf3[i+1] = buf[i ];
+ }
+ }
+ if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, phdr->frame_size - 2))
+ break;
+ if (phdr->bitstream_id > 10)
codec_id = AV_CODEC_ID_EAC3;
- buf2 += hdr.frame_size;
+ buf2 += phdr->frame_size;
}
max_frames = FFMAX(max_frames, frames);
if(buf == p->buf)
first_frames = frames;
}
+ av_freep(&phdr);
if(codec_id != expected_codec_id) return 0;
// keep this in sync with mp3 probe, both need to avoid
// issues with MPEG-files!
- if (first_frames >= 4) return AVPROBE_SCORE_EXTENSION + 1;
-
- if (max_frames) {
- int pes = 0, i;
- unsigned int code = -1;
-
-#define VIDEO_ID 0x000001e0
-#define AUDIO_ID 0x000001c0
- /* do a search for mpegps headers to be able to properly bias
- * towards mpegps if we detect this stream as both. */
- for (i = 0; i<p->buf_size; i++) {
- code = (code << 8) + p->buf[i];
- if ((code & 0xffffff00) == 0x100) {
- if ((code & 0x1f0) == VIDEO_ID) pes++;
- else if((code & 0x1e0) == AUDIO_ID) pes++;
- }
- }
-
- if (pes)
- max_frames = (max_frames + pes - 1) / pes;
- }
- if (max_frames > 500) return AVPROBE_SCORE_EXTENSION;
- else if (max_frames >= 4) return AVPROBE_SCORE_EXTENSION / 2;
- else if (max_frames >= 1) return 1;
- else return 0;
+ if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1;
+ else if(max_frames>200)return AVPROBE_SCORE_EXTENSION;
+ else if(max_frames>=4) return AVPROBE_SCORE_EXTENSION/2;
+ else if(max_frames>=1) return 1;
+ else return 0;
}
#if CONFIG_AC3_DEMUXER
diff --git a/libavformat/act.c b/libavformat/act.c
new file mode 100644
index 0000000000..7b6b8406fc
--- /dev/null
+++ b/libavformat/act.c
@@ -0,0 +1,207 @@
+/*
+ * ACT file format demuxer
+ * Copyright (c) 2007-2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "riff.h"
+#include "internal.h"
+#include "libavcodec/get_bits.h"
+
+#define CHUNK_SIZE 512
+#define RIFF_TAG MKTAG('R','I','F','F')
+#define WAVE_TAG MKTAG('W','A','V','E')
+
+typedef struct{
+ int bytes_left_in_chunk;
+ uint8_t audio_buffer[22];///< temporary buffer for ACT frame
+ char second_packet; ///< 1 - if temporary buffer contains valid (second) G.729 packet
+} ACTContext;
+
+static int probe(AVProbeData *p)
+{
+ int i;
+
+ if ((AV_RL32(&p->buf[0]) != RIFF_TAG) ||
+ (AV_RL32(&p->buf[8]) != WAVE_TAG) ||
+ (AV_RL32(&p->buf[16]) != 16))
+ return 0;
+
+ //We can't be sure that this is ACT and not regular WAV
+ if (p->buf_size<512)
+ return 0;
+
+ for(i=44; i<256; i++)
+ if(p->buf[i])
+ return 0;
+
+ if(p->buf[256]!=0x84)
+ return 0;
+
+ for(i=264; i<512; i++)
+ if(p->buf[i])
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ ACTContext* ctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int size;
+ AVStream* st;
+
+ int min,sec,msec;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 16);
+ size=avio_rl32(pb);
+ ff_get_wav_header(pb, st->codec, size, 0);
+
+ /*
+ 8000Hz (Fine-rec) file format has 10 bytes long
+ packets with 10ms of sound data in them
+ */
+ if (st->codec->sample_rate != 8000) {
+ av_log(s, AV_LOG_ERROR, "Sample rate %d is not supported.\n", st->codec->sample_rate);
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->frame_size=80;
+ st->codec->channels=1;
+ avpriv_set_pts_info(st, 64, 1, 100);
+
+ st->codec->codec_id=AV_CODEC_ID_G729;
+
+ avio_seek(pb, 257, SEEK_SET);
+ msec=avio_rl16(pb);
+ sec=avio_r8(pb);
+ min=avio_rl32(pb);
+
+ st->duration = av_rescale(1000*(min*60+sec)+msec, st->codec->sample_rate, 1000 * st->codec->frame_size);
+
+ ctx->bytes_left_in_chunk=CHUNK_SIZE;
+
+ avio_seek(pb, 512, SEEK_SET);
+
+ return 0;
+}
+
+
+static int read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ ACTContext *ctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int ret;
+ int frame_size=s->streams[0]->codec->sample_rate==8000?10:22;
+
+
+ if(s->streams[0]->codec->sample_rate==8000)
+ ret=av_new_packet(pkt, 10);
+ else
+ ret=av_new_packet(pkt, 11);
+
+ if(ret)
+ return ret;
+
+ if(s->streams[0]->codec->sample_rate==4400 && !ctx->second_packet)
+ {
+ ret = avio_read(pb, ctx->audio_buffer, frame_size);
+
+ if(ret<0)
+ return ret;
+ if(ret!=frame_size)
+ return AVERROR(EIO);
+
+ pkt->data[0]=ctx->audio_buffer[11];
+ pkt->data[1]=ctx->audio_buffer[0];
+ pkt->data[2]=ctx->audio_buffer[12];
+ pkt->data[3]=ctx->audio_buffer[1];
+ pkt->data[4]=ctx->audio_buffer[13];
+ pkt->data[5]=ctx->audio_buffer[2];
+ pkt->data[6]=ctx->audio_buffer[14];
+ pkt->data[7]=ctx->audio_buffer[3];
+ pkt->data[8]=ctx->audio_buffer[15];
+ pkt->data[9]=ctx->audio_buffer[4];
+ pkt->data[10]=ctx->audio_buffer[16];
+
+ ctx->second_packet=1;
+ }
+ else if(s->streams[0]->codec->sample_rate==4400 && ctx->second_packet)
+ {
+ pkt->data[0]=ctx->audio_buffer[5];
+ pkt->data[1]=ctx->audio_buffer[17];
+ pkt->data[2]=ctx->audio_buffer[6];
+ pkt->data[3]=ctx->audio_buffer[18];
+ pkt->data[4]=ctx->audio_buffer[7];
+ pkt->data[5]=ctx->audio_buffer[19];
+ pkt->data[6]=ctx->audio_buffer[8];
+ pkt->data[7]=ctx->audio_buffer[20];
+ pkt->data[8]=ctx->audio_buffer[9];
+ pkt->data[9]=ctx->audio_buffer[21];
+ pkt->data[10]=ctx->audio_buffer[10];
+
+ ctx->second_packet=0;
+ }
+ else // 8000 Hz
+ {
+ ret = avio_read(pb, ctx->audio_buffer, frame_size);
+
+ if(ret<0)
+ return ret;
+ if(ret!=frame_size)
+ return AVERROR(EIO);
+
+ pkt->data[0]=ctx->audio_buffer[5];
+ pkt->data[1]=ctx->audio_buffer[0];
+ pkt->data[2]=ctx->audio_buffer[6];
+ pkt->data[3]=ctx->audio_buffer[1];
+ pkt->data[4]=ctx->audio_buffer[7];
+ pkt->data[5]=ctx->audio_buffer[2];
+ pkt->data[6]=ctx->audio_buffer[8];
+ pkt->data[7]=ctx->audio_buffer[3];
+ pkt->data[8]=ctx->audio_buffer[9];
+ pkt->data[9]=ctx->audio_buffer[4];
+ }
+
+ ctx->bytes_left_in_chunk -= frame_size;
+
+ if(ctx->bytes_left_in_chunk < frame_size)
+ {
+ avio_skip(pb, ctx->bytes_left_in_chunk);
+ ctx->bytes_left_in_chunk=CHUNK_SIZE;
+ }
+
+ pkt->duration=1;
+
+ return ret;
+}
+
+AVInputFormat ff_act_demuxer = {
+ .name = "act",
+ .long_name = "ACT Voice file format",
+ .priv_data_size = sizeof(ACTContext),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+};
diff --git a/libavformat/adp.c b/libavformat/adp.c
new file mode 100644
index 0000000000..8a3661ae15
--- /dev/null
+++ b/libavformat/adp.c
@@ -0,0 +1,98 @@
+/*
+ * ADP demuxer
+ * Copyright (c) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+
+static int adp_probe(AVProbeData *p)
+{
+ int i, changes = 0;
+ char last = 0;
+
+ if (p->buf_size < 32)
+ return 0;
+
+ for (i = 0; i < p->buf_size - 3; i+=32) {
+ if (p->buf[i] != p->buf[i+2] || p->buf[i+1] != p->buf[i+3])
+ return 0;
+ if (p->buf[i] != last)
+ changes++;
+ last = p->buf[i];
+ }
+ if (changes <= 1)
+ return 0;
+
+ return p->buf_size < 260 ? 1 : AVPROBE_SCORE_MAX / 4;
+}
+
+static int adp_read_header(AVFormatContext *s)
+{
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_DTK;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ st->codec->channels = 2;
+ st->codec->sample_rate = 48000;
+ st->start_time = 0;
+ if (s->pb->seekable)
+ st->duration = av_get_audio_frame_duration(st->codec, avio_size(s->pb));
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ return 0;
+}
+
+static int adp_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int ret, size = 1024;
+
+ if (avio_feof(s->pb))
+ return AVERROR_EOF;
+
+ ret = av_get_packet(s->pb, pkt, size);
+
+ if (ret != size) {
+ if (ret < 0) {
+ av_free_packet(pkt);
+ return ret;
+ }
+ av_shrink_packet(pkt, ret);
+ }
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_adp_demuxer = {
+ .name = "adp",
+ .long_name = NULL_IF_CONFIG_SMALL("ADP"),
+ .read_probe = adp_probe,
+ .read_header = adp_read_header,
+ .read_packet = adp_read_packet,
+ .extensions = "adp,dtk",
+};
diff --git a/libavformat/adtsenc.c b/libavformat/adtsenc.c
index 55d7510557..7448ec794f 100644
--- a/libavformat/adtsenc.c
+++ b/libavformat/adtsenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
* Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,22 +24,28 @@
#include "libavcodec/put_bits.h"
#include "libavcodec/avcodec.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavutil/opt.h"
#include "avformat.h"
+#include "apetag.h"
+#include "id3v2.h"
#define ADTS_HEADER_SIZE 7
typedef struct ADTSContext {
+ AVClass *class;
int write_adts;
int objecttype;
int sample_rate_index;
int channel_conf;
int pce_size;
+ int apetag;
+ int id3v2tag;
uint8_t pce_data[MAX_PCE_SIZE];
} ADTSContext;
#define ADTS_MAX_FRAME_BYTES ((1 << 13) - 1)
-static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, uint8_t *buf, int size)
+static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, const uint8_t *buf, int size)
{
GetBitContext gb;
PutBitContext pb;
@@ -93,6 +99,8 @@ static int adts_write_header(AVFormatContext *s)
ADTSContext *adts = s->priv_data;
AVCodecContext *avc = s->streams[0]->codec;
+ if (adts->id3v2tag)
+ ff_id3v2_write_simple(s, 4, ID3v2_DEFAULT_MAGIC);
if (avc->extradata_size > 0)
return adts_decode_extradata(s, adts, avc->extradata,
avc->extradata_size);
@@ -162,6 +170,31 @@ static int adts_write_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
+static int adts_write_trailer(AVFormatContext *s)
+{
+ ADTSContext *adts = s->priv_data;
+
+ if (adts->apetag)
+ ff_ape_write_tag(s);
+
+ return 0;
+}
+
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+#define OFFSET(obj) offsetof(ADTSContext, obj)
+static const AVOption options[] = {
+ { "write_id3v2", "Enable ID3v2 tag writing", OFFSET(id3v2tag), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC},
+ { "write_apetag", "Enable APE tag writing", OFFSET(apetag), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC},
+ { NULL },
+};
+
+static const AVClass adts_muxer_class = {
+ .class_name = "ADTS muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_adts_muxer = {
.name = "adts",
.long_name = NULL_IF_CONFIG_SMALL("ADTS AAC (Advanced Audio Coding)"),
@@ -172,5 +205,7 @@ AVOutputFormat ff_adts_muxer = {
.video_codec = AV_CODEC_ID_NONE,
.write_header = adts_write_header,
.write_packet = adts_write_packet,
+ .write_trailer = adts_write_trailer,
+ .priv_class = &adts_muxer_class,
.flags = AVFMT_NOTIMESTAMPS,
};
diff --git a/libavformat/adxdec.c b/libavformat/adxdec.c
index 9d3ebe398b..e7107ac579 100644
--- a/libavformat/adxdec.c
+++ b/libavformat/adxdec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,6 +40,11 @@ static int adx_read_packet(AVFormatContext *s, AVPacket *pkt)
AVCodecContext *avctx = s->streams[0]->codec;
int ret, size;
+ if (avctx->channels <= 0) {
+ av_log(s, AV_LOG_ERROR, "invalid number of channels %d\n", avctx->channels);
+ return AVERROR_INVALIDDATA;
+ }
+
size = BLOCK_SIZE * avctx->channels;
pkt->pos = avio_tell(s->pb);
@@ -76,14 +81,8 @@ static int adx_read_header(AVFormatContext *s)
c->header_size = avio_rb16(s->pb) + 4;
avio_seek(s->pb, -4, SEEK_CUR);
- avctx->extradata = av_mallocz(c->header_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
+ if (ff_get_extradata(avctx, s->pb, c->header_size) < 0)
return AVERROR(ENOMEM);
- if (avio_read(s->pb, avctx->extradata, c->header_size) < c->header_size) {
- av_freep(&avctx->extradata);
- return AVERROR(EIO);
- }
- avctx->extradata_size = c->header_size;
if (avctx->extradata_size < 12) {
av_log(s, AV_LOG_ERROR, "Invalid extradata size.\n");
diff --git a/libavformat/aea.c b/libavformat/aea.c
index c107109cfa..db415c9543 100644
--- a/libavformat/aea.c
+++ b/libavformat/aea.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,12 +34,8 @@ static int aea_read_probe(AVProbeData *p)
/* Magic is '00 08 00 00' in Little Endian*/
if (AV_RL32(p->buf)==0x800) {
- int bsm_s, bsm_e, inb_s, inb_e, ch;
- ch = p->buf[264];
- bsm_s = p->buf[2048];
- inb_s = p->buf[2048+1];
- inb_e = p->buf[2048+210];
- bsm_e = p->buf[2048+211];
+ int ch, i;
+ ch = p->buf[264];
if (ch != 1 && ch != 2)
return 0;
@@ -48,8 +44,17 @@ static int aea_read_probe(AVProbeData *p)
* the block size mode bytes have to be the same
* the info bytes have to be the same
*/
- if (bsm_s == bsm_e && inb_s == inb_e)
- return AVPROBE_SCORE_MAX / 4 + 1;
+ for (i = 2048; i + 211 < p->buf_size; i+= 212) {
+ int bsm_s, bsm_e, inb_s, inb_e;
+ bsm_s = p->buf[0];
+ inb_s = p->buf[1];
+ inb_e = p->buf[210];
+ bsm_e = p->buf[211];
+
+ if (bsm_s != bsm_e || inb_s != inb_e)
+ return 0;
+ }
+ return AVPROBE_SCORE_MAX / 4 + 1;
}
return 0;
}
diff --git a/libavformat/afc.c b/libavformat/afc.c
new file mode 100644
index 0000000000..8dbd232fc1
--- /dev/null
+++ b/libavformat/afc.c
@@ -0,0 +1,79 @@
+/*
+ * AFC demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/channel_layout.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct AFCDemuxContext {
+ int64_t data_end;
+} AFCDemuxContext;
+
+static int afc_read_header(AVFormatContext *s)
+{
+ AFCDemuxContext *c = s->priv_data;
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_AFC;
+ st->codec->channels = 2;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+
+ if (ff_alloc_extradata(st->codec, 1))
+ return AVERROR(ENOMEM);
+ st->codec->extradata[0] = 8 * st->codec->channels;
+
+ c->data_end = avio_rb32(s->pb) + 32LL;
+ st->duration = avio_rb32(s->pb);
+ st->codec->sample_rate = avio_rb16(s->pb);
+ avio_skip(s->pb, 22);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ return 0;
+}
+
+static int afc_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AFCDemuxContext *c = s->priv_data;
+ int64_t size;
+ int ret;
+
+ size = FFMIN(c->data_end - avio_tell(s->pb), 18 * 128);
+ if (size <= 0)
+ return AVERROR_EOF;
+
+ ret = av_get_packet(s->pb, pkt, size);
+ pkt->stream_index = 0;
+ return ret;
+}
+
+AVInputFormat ff_afc_demuxer = {
+ .name = "afc",
+ .long_name = NULL_IF_CONFIG_SMALL("AFC"),
+ .priv_data_size = sizeof(AFCDemuxContext),
+ .read_header = afc_read_header,
+ .read_packet = afc_read_packet,
+ .extensions = "afc",
+ .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
+};
diff --git a/libavformat/aiff.h b/libavformat/aiff.h
index f88f957e71..4470254022 100644
--- a/libavformat/aiff.h
+++ b/libavformat/aiff.h
@@ -2,20 +2,20 @@
* AIFF/AIFF-C muxer/demuxer common header
* Copyright (c) 2006 Patrick Guimond
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,16 +33,20 @@
static const AVCodecTag ff_codec_aiff_tags[] = {
{ AV_CODEC_ID_PCM_S16BE, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_S8, MKTAG('N','O','N','E') },
+ { AV_CODEC_ID_PCM_U8, MKTAG('r','a','w',' ') },
{ AV_CODEC_ID_PCM_S24BE, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_S32BE, MKTAG('N','O','N','E') },
{ AV_CODEC_ID_PCM_F32BE, MKTAG('f','l','3','2') },
{ AV_CODEC_ID_PCM_F64BE, MKTAG('f','l','6','4') },
{ AV_CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },
{ AV_CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') },
+ { AV_CODEC_ID_PCM_S24BE, MKTAG('i','n','2','4') },
+ { AV_CODEC_ID_PCM_S32BE, MKTAG('i','n','3','2') },
{ AV_CODEC_ID_MACE3, MKTAG('M','A','C','3') },
{ AV_CODEC_ID_MACE6, MKTAG('M','A','C','6') },
{ AV_CODEC_ID_GSM, MKTAG('G','S','M',' ') },
- { AV_CODEC_ID_ADPCM_G726, MKTAG('G','7','2','6') },
+ { AV_CODEC_ID_ADPCM_G722, MKTAG('G','7','2','2') },
+ { AV_CODEC_ID_ADPCM_G726LE, MKTAG('G','7','2','6') },
{ AV_CODEC_ID_PCM_S16BE, MKTAG('t','w','o','s') },
{ AV_CODEC_ID_PCM_S16LE, MKTAG('s','o','w','t') },
{ AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') },
diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c
index add843b267..ff04c2b8f4 100644
--- a/libavformat/aiffdec.c
+++ b/libavformat/aiffdec.c
@@ -2,29 +2,33 @@
* AIFF/AIFF-C demuxer
* Copyright (c) 2006 Patrick Guimond
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/mathematics.h"
#include "libavutil/dict.h"
#include "avformat.h"
#include "internal.h"
#include "pcm.h"
#include "aiff.h"
+#include "isom.h"
+#include "id3v2.h"
+#include "mov_chan.h"
#define AIFF 0
#define AIFF_C_VERSION1 0xA2805140
@@ -54,7 +58,7 @@ static int get_tag(AVIOContext *pb, uint32_t * tag)
{
int size;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
*tag = avio_rl32(pb);
@@ -70,19 +74,20 @@ static int get_tag(AVIOContext *pb, uint32_t * tag)
static void get_meta(AVFormatContext *s, const char *key, int size)
{
uint8_t *str = av_malloc(size+1);
- int res;
- if (!str) {
- avio_skip(s->pb, size);
- return;
- }
-
- res = avio_read(s->pb, str, size);
- if (res < 0)
- return;
+ if (str) {
+ int res = avio_read(s->pb, str, size);
+ if (res < 0){
+ av_free(str);
+ return;
+ }
+ size += (size&1)-res;
+ str[res] = 0;
+ av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL);
+ }else
+ size+= size&1;
- str[res] = 0;
- av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL);
+ avio_skip(s->pb, size);
}
/* Returns the number of sound data frames or negative on error */
@@ -111,7 +116,9 @@ static unsigned int get_aiff_header(AVFormatContext *s, int size,
size -= 18;
/* get codec id for AIFF-C */
- if (version == AIFF_C_VERSION1) {
+ if (size < 4) {
+ version = AIFF;
+ } else if (version == AIFF_C_VERSION1) {
codec->codec_tag = avio_rl32(pb);
codec->codec_id = ff_codec_get_id(ff_codec_aiff_tags, codec->codec_tag);
size -= 4;
@@ -136,16 +143,17 @@ static unsigned int get_aiff_header(AVFormatContext *s, int size,
case AV_CODEC_ID_MACE3:
codec->block_align = 2*codec->channels;
break;
+ case AV_CODEC_ID_ADPCM_G726LE:
+ codec->bits_per_coded_sample = 5;
+ case AV_CODEC_ID_ADPCM_G722:
case AV_CODEC_ID_MACE6:
codec->block_align = 1*codec->channels;
break;
case AV_CODEC_ID_GSM:
codec->block_align = 33;
break;
- case AV_CODEC_ID_QCELP:
- codec->block_align = 35;
- break;
default:
+ aiff->block_duration = 1;
break;
}
if (codec->block_align > 0)
@@ -156,7 +164,7 @@ static unsigned int get_aiff_header(AVFormatContext *s, int size,
/* Block align needs to be computed in all cases, as the definition
* is specific to applications -> here we use the WAVE format definition */
if (!codec->block_align)
- codec->block_align = (codec->bits_per_coded_sample * codec->channels) >> 3;
+ codec->block_align = (av_get_bits_per_sample(codec->codec_id) * codec->channels) >> 3;
if (aiff->block_duration) {
codec->bit_rate = codec->sample_rate * (codec->block_align << 3) /
@@ -185,13 +193,14 @@ static int aiff_probe(AVProbeData *p)
/* aiff input */
static int aiff_read_header(AVFormatContext *s)
{
- int size, filesize;
- int64_t offset = 0;
+ int ret, size, filesize;
+ int64_t offset = 0, position;
uint32_t tag;
unsigned version = AIFF_C_VERSION1;
AVIOContext *pb = s->pb;
AVStream * st;
AIFFInputContext *aiff = s->priv_data;
+ ID3v2ExtraMeta *id3v2_extra_meta = NULL;
/* check FORM header */
filesize = get_tag(pb, &tag);
@@ -214,6 +223,11 @@ static int aiff_read_header(AVFormatContext *s)
while (filesize > 0) {
/* parse different chunks */
size = get_tag(pb, &tag);
+
+ if (size == AVERROR_EOF && offset > 0 && st->codec->block_align) {
+ av_log(s, AV_LOG_WARNING, "header parser hit EOF\n");
+ goto got_sound;
+ }
if (size < 0)
return size;
@@ -228,6 +242,18 @@ static int aiff_read_header(AVFormatContext *s)
if (offset > 0) // COMM is after SSND
goto got_sound;
break;
+ case MKTAG('I', 'D', '3', ' '):
+ position = avio_tell(pb);
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size);
+ if (id3v2_extra_meta)
+ if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) {
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+ return ret;
+ }
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+ if (position + size > avio_tell(pb))
+ avio_skip(pb, position + size - avio_tell(pb));
+ break;
case MKTAG('F', 'V', 'E', 'R'): /* Version chunk */
version = avio_rb32(pb);
break;
@@ -248,7 +274,7 @@ static int aiff_read_header(AVFormatContext *s)
offset = avio_rb32(pb); /* Offset of sound data */
avio_rb32(pb); /* BlockSize... don't care */
offset += avio_tell(pb); /* Compute absolute data offset */
- if (st->codec->block_align) /* Assume COMM already parsed */
+ if (st->codec->block_align && !pb->seekable) /* Assume COMM already parsed */
goto got_sound;
if (!pb->seekable) {
av_log(s, AV_LOG_ERROR, "file is not seekable\n");
@@ -259,12 +285,35 @@ static int aiff_read_header(AVFormatContext *s)
case MKTAG('w', 'a', 'v', 'e'):
if ((uint64_t)size > (1<<30))
return -1;
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = size;
- avio_read(pb, st->codec->extradata, size);
+ if (st->codec->codec_id == AV_CODEC_ID_QDM2 && size>=12*4 && !st->codec->block_align) {
+ st->codec->block_align = AV_RB32(st->codec->extradata+11*4);
+ aiff->block_duration = AV_RB32(st->codec->extradata+9*4);
+ } else if (st->codec->codec_id == AV_CODEC_ID_QCELP) {
+ char rate = 0;
+ if (size >= 25)
+ rate = st->codec->extradata[24];
+ switch (rate) {
+ case 'H': // RATE_HALF
+ st->codec->block_align = 17;
+ break;
+ case 'F': // RATE_FULL
+ default:
+ st->codec->block_align = 35;
+ }
+ aiff->block_duration = 160;
+ st->codec->bit_rate = st->codec->sample_rate * (st->codec->block_align << 3) /
+ aiff->block_duration;
+ }
+ break;
+ case MKTAG('C','H','A','N'):
+ if(ff_mov_read_chan(s, pb, st, size) < 0)
+ return AVERROR_INVALIDDATA;
break;
+ case 0:
+ if (offset > 0 && st->codec->block_align) // COMM && SSND
+ goto got_sound;
default: /* Jump */
if (size & 1) /* Always even aligned */
size++;
@@ -305,15 +354,23 @@ static int aiff_read_packet(AVFormatContext *s,
return AVERROR_EOF;
/* Now for that packet */
- if (st->codec->block_align >= 33) // GSM, QCLP, IMA4
+ switch (st->codec->codec_id) {
+ case AV_CODEC_ID_ADPCM_IMA_QT:
+ case AV_CODEC_ID_GSM:
+ case AV_CODEC_ID_QDM2:
+ case AV_CODEC_ID_QCELP:
size = st->codec->block_align;
- else
+ break;
+ default:
size = (MAX_SIZE / st->codec->block_align) * st->codec->block_align;
+ }
size = FFMIN(max_size, size);
res = av_get_packet(s->pb, pkt, size);
if (res < 0)
return res;
+ if (size >= st->codec->block_align)
+ pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
/* Only one stream in an AIFF file */
pkt->stream_index = 0;
pkt->duration = (res / st->codec->block_align) * aiff->block_duration;
diff --git a/libavformat/aiffenc.c b/libavformat/aiffenc.c
index aa68108368..e2828e7508 100644
--- a/libavformat/aiffenc.c
+++ b/libavformat/aiffenc.c
@@ -2,44 +2,126 @@
* AIFF/AIFF-C muxer
* Copyright (c) 2006 Patrick Guimond
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include "libavutil/intfloat.h"
+#include "libavutil/opt.h"
#include "avformat.h"
#include "internal.h"
#include "aiff.h"
#include "avio_internal.h"
+#include "isom.h"
+#include "id3v2.h"
typedef struct AIFFOutputContext {
+ const AVClass *class;
int64_t form;
int64_t frames;
int64_t ssnd;
+ int audio_stream_idx;
+ AVPacketList *pict_list;
+ int write_id3v2;
+ int id3v2_version;
} AIFFOutputContext;
+static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
+{
+ int ret;
+ uint64_t pos, end, size;
+ ID3v2EncContext id3v2 = { 0 };
+ AVIOContext *pb = s->pb;
+ AVPacketList *pict_list = aiff->pict_list;
+
+ if (!pb->seekable)
+ return 0;
+
+ if (!s->metadata && !aiff->pict_list)
+ return 0;
+
+ avio_wl32(pb, MKTAG('I', 'D', '3', ' '));
+ avio_wb32(pb, 0);
+ pos = avio_tell(pb);
+
+ ff_id3v2_start(&id3v2, pb, aiff->id3v2_version, ID3v2_DEFAULT_MAGIC);
+ ff_id3v2_write_metadata(s, &id3v2);
+ while (pict_list) {
+ if ((ret = ff_id3v2_write_apic(s, &id3v2, &pict_list->pkt)) < 0)
+ return ret;
+ pict_list = pict_list->next;
+ }
+ ff_id3v2_finish(&id3v2, pb, s->metadata_header_padding);
+
+ end = avio_tell(pb);
+ size = end - pos;
+
+ /* Update chunk size */
+ avio_seek(pb, pos - 4, SEEK_SET);
+ avio_wb32(pb, size);
+ avio_seek(pb, end, SEEK_SET);
+
+ if (size & 1)
+ avio_w8(pb, 0);
+
+ return 0;
+}
+
+static void put_meta(AVFormatContext *s, const char *key, uint32_t id)
+{
+ AVDictionaryEntry *tag;
+ AVIOContext *pb = s->pb;
+
+ if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
+ int size = strlen(tag->value);
+
+ avio_wl32(pb, id);
+ avio_wb32(pb, FFALIGN(size, 2));
+ avio_write(pb, tag->value, size);
+ if (size & 1)
+ avio_w8(pb, 0);
+ }
+}
+
static int aiff_write_header(AVFormatContext *s)
{
AIFFOutputContext *aiff = s->priv_data;
AVIOContext *pb = s->pb;
- AVCodecContext *enc = s->streams[0]->codec;
+ AVCodecContext *enc;
uint64_t sample_rate;
- int aifc = 0;
+ int i, aifc = 0;
+
+ aiff->audio_stream_idx = -1;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (aiff->audio_stream_idx < 0 && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ aiff->audio_stream_idx = i;
+ } else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) {
+ av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in AIFF.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ if (aiff->audio_stream_idx < 0) {
+ av_log(s, AV_LOG_ERROR, "No audio stream present.\n");
+ return AVERROR(EINVAL);
+ }
+
+ enc = s->streams[aiff->audio_stream_idx]->codec;
/* First verify if format is ok */
if (!enc->codec_tag)
@@ -54,7 +136,6 @@ static int aiff_write_header(AVFormatContext *s)
ffio_wfourcc(pb, aifc ? "AIFC" : "AIFF");
if (aifc) { // compressed audio
- enc->bits_per_coded_sample = 16;
if (!enc->block_align) {
av_log(s, AV_LOG_ERROR, "block align not set\n");
return -1;
@@ -65,6 +146,17 @@ static int aiff_write_header(AVFormatContext *s)
avio_wb32(pb, 0xA2805140);
}
+ if (enc->channels > 2 && enc->channel_layout) {
+ ffio_wfourcc(pb, "CHAN");
+ avio_wb32(pb, 12);
+ ff_mov_write_chan(pb, enc->channel_layout);
+ }
+
+ put_meta(s, "title", MKTAG('N', 'A', 'M', 'E'));
+ put_meta(s, "author", MKTAG('A', 'U', 'T', 'H'));
+ put_meta(s, "copyright", MKTAG('(', 'c', ')', ' '));
+ put_meta(s, "comment", MKTAG('A', 'N', 'N', 'O'));
+
/* Common chunk */
ffio_wfourcc(pb, "COMM");
avio_wb32(pb, aifc ? 24 : 18); /* size */
@@ -93,6 +185,12 @@ static int aiff_write_header(AVFormatContext *s)
avio_wb16(pb, 0);
}
+ if (enc->codec_tag == MKTAG('Q','D','M','2') && enc->extradata_size) {
+ ffio_wfourcc(pb, "wave");
+ avio_wb32(pb, enc->extradata_size);
+ avio_write(pb, enc->extradata, enc->extradata_size);
+ }
+
/* Sound data chunk */
ffio_wfourcc(pb, "SSND");
aiff->ssnd = avio_tell(pb); /* Sound chunk size */
@@ -100,7 +198,8 @@ static int aiff_write_header(AVFormatContext *s)
avio_wb32(pb, 0); /* Data offset */
avio_wb32(pb, 0); /* Block-size (block align) */
- avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
+ avpriv_set_pts_info(s->streams[aiff->audio_stream_idx], 64, 1,
+ s->streams[aiff->audio_stream_idx]->codec->sample_rate);
/* Data is starting here */
avio_flush(pb);
@@ -110,16 +209,54 @@ static int aiff_write_header(AVFormatContext *s)
static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt)
{
+ AIFFOutputContext *aiff = s->priv_data;
AVIOContext *pb = s->pb;
- avio_write(pb, pkt->data, pkt->size);
+ if (pkt->stream_index == aiff->audio_stream_idx)
+ avio_write(pb, pkt->data, pkt->size);
+ else {
+ int ret;
+ AVPacketList *pict_list, *last;
+
+ if (s->streams[pkt->stream_index]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ return 0;
+
+ /* warn only once for each stream */
+ if (s->streams[pkt->stream_index]->nb_frames == 1) {
+ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
+ " ignoring.\n", pkt->stream_index);
+ }
+ if (s->streams[pkt->stream_index]->nb_frames >= 1)
+ return 0;
+
+ pict_list = av_mallocz(sizeof(AVPacketList));
+ if (!pict_list)
+ return AVERROR(ENOMEM);
+
+ if ((ret = av_copy_packet(&pict_list->pkt, pkt)) < 0) {
+ av_freep(&pict_list);
+ return ret;
+ }
+
+ if (!aiff->pict_list)
+ aiff->pict_list = pict_list;
+ else {
+ last = aiff->pict_list;
+ while (last->next)
+ last = last->next;
+ last->next = pict_list;
+ }
+ }
+
return 0;
}
static int aiff_write_trailer(AVFormatContext *s)
{
+ int ret;
AVIOContext *pb = s->pb;
AIFFOutputContext *aiff = s->priv_data;
- AVCodecContext *enc = s->streams[0]->codec;
+ AVPacketList *pict_list = aiff->pict_list;
+ AVCodecContext *enc = s->streams[aiff->audio_stream_idx]->codec;
/* Chunks sizes must be even */
int64_t file_size, end_size;
@@ -130,10 +267,6 @@ static int aiff_write_trailer(AVFormatContext *s)
}
if (s->pb->seekable) {
- /* File length */
- avio_seek(pb, aiff->form, SEEK_SET);
- avio_wb32(pb, file_size - aiff->form - 4);
-
/* Number of sample frames */
avio_seek(pb, aiff->frames, SEEK_SET);
avio_wb32(pb, (file_size-aiff->ssnd-12)/enc->block_align);
@@ -145,12 +278,46 @@ static int aiff_write_trailer(AVFormatContext *s)
/* return to the end */
avio_seek(pb, end_size, SEEK_SET);
+ /* Write ID3 tags */
+ if (aiff->write_id3v2)
+ if ((ret = put_id3v2_tags(s, aiff)) < 0)
+ return ret;
+
+ /* File length */
+ file_size = avio_tell(pb);
+ avio_seek(pb, aiff->form, SEEK_SET);
+ avio_wb32(pb, file_size - aiff->form - 4);
+
avio_flush(pb);
}
+ while (pict_list) {
+ AVPacketList *next = pict_list->next;
+ av_free_packet(&pict_list->pkt);
+ av_freep(&pict_list);
+ pict_list = next;
+ }
+
return 0;
}
+#define OFFSET(x) offsetof(AIFFOutputContext, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "write_id3v2", "Enable ID3 tags writing.",
+ OFFSET(write_id3v2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC },
+ { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.",
+ OFFSET(id3v2_version), AV_OPT_TYPE_INT, {.i64 = 4}, 3, 4, ENC },
+ { NULL },
+};
+
+static const AVClass aiff_muxer_class = {
+ .class_name = "AIFF muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_aiff_muxer = {
.name = "aiff",
.long_name = NULL_IF_CONFIG_SMALL("Audio IFF"),
@@ -158,9 +325,10 @@ AVOutputFormat ff_aiff_muxer = {
.extensions = "aif,aiff,afc,aifc",
.priv_data_size = sizeof(AIFFOutputContext),
.audio_codec = AV_CODEC_ID_PCM_S16BE,
- .video_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_PNG,
.write_header = aiff_write_header,
.write_packet = aiff_write_packet,
.write_trailer = aiff_write_trailer,
.codec_tag = (const AVCodecTag* const []){ ff_codec_aiff_tags, 0 },
+ .priv_class = &aiff_muxer_class,
};
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index f4be81a458..0f53d4c73c 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -2,20 +2,20 @@
* Register all the formats and protocols
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -62,57 +62,80 @@ void av_register_all(void)
REGISTER_MUXER (A64, a64);
REGISTER_DEMUXER (AAC, aac);
REGISTER_MUXDEMUX(AC3, ac3);
+ REGISTER_DEMUXER (ACT, act);
+ REGISTER_DEMUXER (ADF, adf);
+ REGISTER_DEMUXER (ADP, adp);
REGISTER_MUXER (ADTS, adts);
REGISTER_MUXDEMUX(ADX, adx);
REGISTER_DEMUXER (AEA, aea);
+ REGISTER_DEMUXER (AFC, afc);
REGISTER_MUXDEMUX(AIFF, aiff);
REGISTER_MUXDEMUX(AMR, amr);
REGISTER_DEMUXER (ANM, anm);
REGISTER_DEMUXER (APC, apc);
REGISTER_DEMUXER (APE, ape);
+ REGISTER_MUXDEMUX(APNG, apng);
+ REGISTER_DEMUXER (AQTITLE, aqtitle);
REGISTER_MUXDEMUX(ASF, asf);
REGISTER_MUXDEMUX(ASS, ass);
+ REGISTER_MUXDEMUX(AST, ast);
REGISTER_MUXER (ASF_STREAM, asf_stream);
REGISTER_MUXDEMUX(AU, au);
REGISTER_MUXDEMUX(AVI, avi);
REGISTER_DEMUXER (AVISYNTH, avisynth);
REGISTER_MUXER (AVM2, avm2);
+ REGISTER_DEMUXER (AVR, avr);
REGISTER_DEMUXER (AVS, avs);
REGISTER_DEMUXER (BETHSOFTVID, bethsoftvid);
REGISTER_DEMUXER (BFI, bfi);
+ REGISTER_DEMUXER (BINTEXT, bintext);
REGISTER_DEMUXER (BINK, bink);
+ REGISTER_MUXDEMUX(BIT, bit);
REGISTER_DEMUXER (BMV, bmv);
+ REGISTER_DEMUXER (BRSTM, brstm);
+ REGISTER_DEMUXER (BOA, boa);
REGISTER_DEMUXER (C93, c93);
- REGISTER_DEMUXER (CAF, caf);
+ REGISTER_MUXDEMUX(CAF, caf);
REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo);
REGISTER_DEMUXER (CDG, cdg);
REGISTER_DEMUXER (CDXL, cdxl);
+ REGISTER_DEMUXER (CINE, cine);
+ REGISTER_DEMUXER (CONCAT, concat);
REGISTER_MUXER (CRC, crc);
REGISTER_MUXER (DASH, dash);
+ REGISTER_MUXDEMUX(DATA, data);
REGISTER_MUXDEMUX(DAUD, daud);
REGISTER_DEMUXER (DFA, dfa);
REGISTER_MUXDEMUX(DIRAC, dirac);
REGISTER_MUXDEMUX(DNXHD, dnxhd);
+ REGISTER_DEMUXER (DSF, dsf);
REGISTER_DEMUXER (DSICIN, dsicin);
REGISTER_DEMUXER (DSS, dss);
REGISTER_MUXDEMUX(DTS, dts);
+ REGISTER_DEMUXER (DTSHD, dtshd);
REGISTER_MUXDEMUX(DV, dv);
+ REGISTER_DEMUXER (DVBSUB, dvbsub);
REGISTER_DEMUXER (DXA, dxa);
REGISTER_DEMUXER (EA, ea);
REGISTER_DEMUXER (EA_CDATA, ea_cdata);
REGISTER_MUXDEMUX(EAC3, eac3);
+ REGISTER_DEMUXER (EPAF, epaf);
REGISTER_MUXER (F4V, f4v);
+ REGISTER_MUXDEMUX(FFM, ffm);
REGISTER_MUXDEMUX(FFMETADATA, ffmetadata);
REGISTER_MUXDEMUX(FILMSTRIP, filmstrip);
REGISTER_MUXDEMUX(FLAC, flac);
REGISTER_DEMUXER (FLIC, flic);
REGISTER_MUXDEMUX(FLV, flv);
+ REGISTER_DEMUXER (LIVE_FLV, live_flv);
REGISTER_DEMUXER (FOURXM, fourxm);
REGISTER_MUXER (FRAMECRC, framecrc);
REGISTER_MUXER (FRAMEMD5, framemd5);
+ REGISTER_DEMUXER (FRM, frm);
REGISTER_MUXDEMUX(G722, g722);
- REGISTER_DEMUXER (G723_1, g723_1);
- REGISTER_MUXER (GIF, gif);
+ REGISTER_MUXDEMUX(G723_1, g723_1);
+ REGISTER_DEMUXER (G729, g729);
+ REGISTER_MUXDEMUX(GIF, gif);
REGISTER_DEMUXER (GSM, gsm);
REGISTER_MUXDEMUX(GXF, gxf);
REGISTER_MUXDEMUX(H261, h261);
@@ -122,28 +145,40 @@ void av_register_all(void)
REGISTER_MUXDEMUX(HEVC, hevc);
REGISTER_MUXDEMUX(HLS, hls);
REGISTER_DEMUXER (HNM, hnm);
+ REGISTER_MUXDEMUX(ICO, ico);
REGISTER_DEMUXER (IDCIN, idcin);
+ REGISTER_DEMUXER (IDF, idf);
REGISTER_DEMUXER (IFF, iff);
REGISTER_MUXDEMUX(ILBC, ilbc);
REGISTER_MUXDEMUX(IMAGE2, image2);
REGISTER_MUXDEMUX(IMAGE2PIPE, image2pipe);
+ REGISTER_DEMUXER (IMAGE2_ALIAS_PIX, image2_alias_pix);
+ REGISTER_DEMUXER (IMAGE2_BRENDER_PIX, image2_brender_pix);
REGISTER_DEMUXER (INGENIENT, ingenient);
REGISTER_DEMUXER (IPMOVIE, ipmovie);
REGISTER_MUXER (IPOD, ipod);
+ REGISTER_MUXDEMUX(IRCAM, ircam);
REGISTER_MUXER (ISMV, ismv);
REGISTER_DEMUXER (ISS, iss);
REGISTER_DEMUXER (IV8, iv8);
REGISTER_MUXDEMUX(IVF, ivf);
+ REGISTER_MUXDEMUX(JACOSUB, jacosub);
REGISTER_DEMUXER (JV, jv);
REGISTER_MUXDEMUX(LATM, latm);
REGISTER_DEMUXER (LMLM4, lmlm4);
+ REGISTER_DEMUXER (LOAS, loas);
+ REGISTER_MUXDEMUX(LRC, lrc);
+ REGISTER_DEMUXER (LVF, lvf);
REGISTER_DEMUXER (LXF, lxf);
REGISTER_MUXDEMUX(M4V, m4v);
REGISTER_MUXER (MD5, md5);
REGISTER_MUXDEMUX(MATROSKA, matroska);
REGISTER_MUXER (MATROSKA_AUDIO, matroska_audio);
+ REGISTER_DEMUXER (MGSTS, mgsts);
+ REGISTER_MUXDEMUX(MICRODVD, microdvd);
REGISTER_MUXDEMUX(MJPEG, mjpeg);
REGISTER_MUXDEMUX(MLP, mlp);
+ REGISTER_DEMUXER (MLV, mlv);
REGISTER_DEMUXER (MM, mm);
REGISTER_MUXDEMUX(MMF, mmf);
REGISTER_MUXDEMUX(MOV, mov);
@@ -164,14 +199,18 @@ void av_register_all(void)
REGISTER_DEMUXER (MPEGTSRAW, mpegtsraw);
REGISTER_DEMUXER (MPEGVIDEO, mpegvideo);
REGISTER_MUXER (MPJPEG, mpjpeg);
+ REGISTER_DEMUXER (MPL2, mpl2);
+ REGISTER_DEMUXER (MPSUB, mpsub);
REGISTER_DEMUXER (MSNWC_TCP, msnwc_tcp);
REGISTER_DEMUXER (MTV, mtv);
REGISTER_DEMUXER (MV, mv);
REGISTER_DEMUXER (MVI, mvi);
REGISTER_MUXDEMUX(MXF, mxf);
REGISTER_MUXER (MXF_D10, mxf_d10);
+ REGISTER_MUXER (MXF_OPATOM, mxf_opatom);
REGISTER_DEMUXER (MXG, mxg);
REGISTER_DEMUXER (NC, nc);
+ REGISTER_DEMUXER (NISTSPHERE, nistsphere);
REGISTER_DEMUXER (NSV, nsv);
REGISTER_MUXER (NULL, null);
REGISTER_MUXDEMUX(NUT, nut);
@@ -201,30 +240,40 @@ void av_register_all(void)
REGISTER_MUXDEMUX(PCM_U16BE, pcm_u16be);
REGISTER_MUXDEMUX(PCM_U16LE, pcm_u16le);
REGISTER_MUXDEMUX(PCM_U8, pcm_u8);
+ REGISTER_DEMUXER (PJS, pjs);
REGISTER_DEMUXER (PMP, pmp);
REGISTER_MUXER (PSP, psp);
REGISTER_DEMUXER (PVA, pva);
+ REGISTER_DEMUXER (PVF, pvf);
REGISTER_DEMUXER (QCP, qcp);
REGISTER_DEMUXER (R3D, r3d);
REGISTER_MUXDEMUX(RAWVIDEO, rawvideo);
+ REGISTER_DEMUXER (REALTEXT, realtext);
+ REGISTER_DEMUXER (REDSPARK, redspark);
REGISTER_DEMUXER (RL2, rl2);
REGISTER_MUXDEMUX(RM, rm);
REGISTER_MUXDEMUX(ROQ, roq);
REGISTER_DEMUXER (RPL, rpl);
+ REGISTER_DEMUXER (RSD, rsd);
REGISTER_MUXDEMUX(RSO, rso);
REGISTER_MUXDEMUX(RTP, rtp);
REGISTER_MUXER (RTP_MPEGTS, rtp_mpegts);
REGISTER_MUXDEMUX(RTSP, rtsp);
+ REGISTER_DEMUXER (SAMI, sami);
REGISTER_MUXDEMUX(SAP, sap);
+ REGISTER_DEMUXER (SBG, sbg);
REGISTER_DEMUXER (SDP, sdp);
+ REGISTER_DEMUXER (SDR2, sdr2);
#if CONFIG_RTPDEC
ff_register_rtp_dynamic_payload_handlers();
ff_register_rdt_dynamic_payload_handlers();
#endif
REGISTER_DEMUXER (SEGAFILM, segafilm);
REGISTER_MUXER (SEGMENT, segment);
+ REGISTER_MUXER (SEGMENT, stream_segment);
REGISTER_DEMUXER (SHORTEN, shorten);
REGISTER_DEMUXER (SIFF, siff);
+ REGISTER_DEMUXER (SLN, sln);
REGISTER_DEMUXER (SMACKER, smacker);
REGISTER_MUXDEMUX(SMJPEG, smjpeg);
REGISTER_MUXER (SMOOTHSTREAMING, smoothstreaming);
@@ -235,42 +284,78 @@ void av_register_all(void)
REGISTER_MUXDEMUX(SPDIF, spdif);
REGISTER_MUXDEMUX(SRT, srt);
REGISTER_DEMUXER (STR, str);
+ REGISTER_DEMUXER (STL, stl);
+ REGISTER_DEMUXER (SUBVIEWER1, subviewer1);
+ REGISTER_DEMUXER (SUBVIEWER, subviewer);
+ REGISTER_DEMUXER (SUP, sup);
REGISTER_MUXDEMUX(SWF, swf);
REGISTER_DEMUXER (TAK, tak);
+ REGISTER_MUXER (TEE, tee);
+ REGISTER_DEMUXER (TEDCAPTIONS, tedcaptions);
REGISTER_MUXER (TG2, tg2);
REGISTER_MUXER (TGP, tgp);
REGISTER_DEMUXER (THP, thp);
REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq);
+ REGISTER_MUXER (MKVTIMESTAMP_V2, mkvtimestamp_v2);
REGISTER_DEMUXER (TMV, tmv);
REGISTER_MUXDEMUX(TRUEHD, truehd);
REGISTER_DEMUXER (TTA, tta);
REGISTER_DEMUXER (TXD, txd);
REGISTER_DEMUXER (TTY, tty);
- REGISTER_DEMUXER (VC1, vc1);
+ REGISTER_MUXER (UNCODEDFRAMECRC, uncodedframecrc);
+ REGISTER_MUXDEMUX(VC1, vc1);
REGISTER_MUXDEMUX(VC1T, vc1t);
+ REGISTER_DEMUXER (VIVO, vivo);
REGISTER_DEMUXER (VMD, vmd);
+ REGISTER_DEMUXER (VOBSUB, vobsub);
REGISTER_MUXDEMUX(VOC, voc);
+ REGISTER_DEMUXER (VPLAYER, vplayer);
REGISTER_DEMUXER (VQF, vqf);
- REGISTER_DEMUXER (W64, w64);
+ REGISTER_MUXDEMUX(W64, w64);
REGISTER_MUXDEMUX(WAV, wav);
REGISTER_DEMUXER (WC3, wc3);
REGISTER_MUXER (WEBM, webm);
+ REGISTER_MUXDEMUX(WEBM_DASH_MANIFEST, webm_dash_manifest);
+ REGISTER_MUXER (WEBM_CHUNK, webm_chunk);
+ REGISTER_MUXER (WEBP, webp);
+ REGISTER_MUXDEMUX(WEBVTT, webvtt);
REGISTER_DEMUXER (WSAUD, wsaud);
REGISTER_DEMUXER (WSVQA, wsvqa);
- REGISTER_DEMUXER (WTV, wtv);
+ REGISTER_MUXDEMUX(WTV, wtv);
REGISTER_MUXDEMUX(WV, wv);
REGISTER_DEMUXER (XA, xa);
+ REGISTER_DEMUXER (XBIN, xbin);
REGISTER_DEMUXER (XMV, xmv);
REGISTER_DEMUXER (XWMA, xwma);
REGISTER_DEMUXER (YOP, yop);
REGISTER_MUXDEMUX(YUV4MPEGPIPE, yuv4mpegpipe);
+ /* image demuxers */
+ REGISTER_DEMUXER (IMAGE_BMP_PIPE, image_bmp_pipe);
+ REGISTER_DEMUXER (IMAGE_DPX_PIPE, image_dpx_pipe);
+ REGISTER_DEMUXER (IMAGE_EXR_PIPE, image_exr_pipe);
+ REGISTER_DEMUXER (IMAGE_J2K_PIPE, image_j2k_pipe);
+ REGISTER_DEMUXER (IMAGE_JPEG_PIPE, image_jpeg_pipe);
+ REGISTER_DEMUXER (IMAGE_JPEGLS_PIPE, image_jpegls_pipe);
+ REGISTER_DEMUXER (IMAGE_PICTOR_PIPE, image_pictor_pipe);
+ REGISTER_DEMUXER (IMAGE_PNG_PIPE, image_png_pipe);
+ REGISTER_DEMUXER (IMAGE_QDRAW_PIPE, image_qdraw_pipe);
+ REGISTER_DEMUXER (IMAGE_SGI_PIPE, image_sgi_pipe);
+ REGISTER_DEMUXER (IMAGE_SUNRAST_PIPE, image_sunrast_pipe);
+ REGISTER_DEMUXER (IMAGE_TIFF_PIPE, image_tiff_pipe);
+ REGISTER_DEMUXER (IMAGE_WEBP_PIPE, image_webp_pipe);
+
+
/* protocols */
+ REGISTER_PROTOCOL(BLURAY, bluray);
+ REGISTER_PROTOCOL(CACHE, cache);
REGISTER_PROTOCOL(CONCAT, concat);
REGISTER_PROTOCOL(CRYPTO, crypto);
+ REGISTER_PROTOCOL(DATA, data);
REGISTER_PROTOCOL(FFRTMPCRYPT, ffrtmpcrypt);
REGISTER_PROTOCOL(FFRTMPHTTP, ffrtmphttp);
REGISTER_PROTOCOL(FILE, file);
+ REGISTER_PROTOCOL(FTP, ftp);
REGISTER_PROTOCOL(GOPHER, gopher);
REGISTER_PROTOCOL(HLS, hls);
REGISTER_PROTOCOL(HTTP, http);
@@ -290,15 +375,23 @@ void av_register_all(void)
REGISTER_PROTOCOL(RTP, rtp);
REGISTER_PROTOCOL(SCTP, sctp);
REGISTER_PROTOCOL(SRTP, srtp);
+ REGISTER_PROTOCOL(SUBFILE, subfile);
REGISTER_PROTOCOL(TCP, tcp);
REGISTER_PROTOCOL(TLS, tls);
REGISTER_PROTOCOL(UDP, udp);
+ REGISTER_PROTOCOL(UDPLITE, udplite);
REGISTER_PROTOCOL(UNIX, unix);
/* external libraries */
+ REGISTER_DEMUXER (LIBGME, libgme);
+ REGISTER_DEMUXER (LIBMODPLUG, libmodplug);
+ REGISTER_MUXDEMUX(LIBNUT, libnut);
+ REGISTER_DEMUXER (LIBQUVI, libquvi);
REGISTER_PROTOCOL(LIBRTMP, librtmp);
REGISTER_PROTOCOL(LIBRTMPE, librtmpe);
REGISTER_PROTOCOL(LIBRTMPS, librtmps);
REGISTER_PROTOCOL(LIBRTMPT, librtmpt);
REGISTER_PROTOCOL(LIBRTMPTE, librtmpte);
+ REGISTER_PROTOCOL(LIBSSH, libssh);
+ REGISTER_PROTOCOL(LIBSMBCLIENT, libsmbclient);
}
diff --git a/libavformat/amr.c b/libavformat/amr.c
index afd062ee36..8f44de1b38 100644
--- a/libavformat/amr.c
+++ b/libavformat/amr.c
@@ -2,20 +2,20 @@
* amr file format
* Copyright (c) 2001 ffmpeg project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,11 @@ Only mono files are supported.
#include "avformat.h"
#include "internal.h"
+typedef struct {
+ uint64_t cumulated_size;
+ uint64_t block_count;
+} AMRContext;
+
static const char AMR_header[] = "#!AMR\n";
static const char AMRWB_header[] = "#!AMR-WB\n";
@@ -110,12 +115,13 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
AVCodecContext *enc = s->streams[0]->codec;
int read, size = 0, toc, mode;
int64_t pos = avio_tell(s->pb);
+ AMRContext *amr = s->priv_data;
- if (s->pb->eof_reached) {
+ if (avio_feof(s->pb)) {
return AVERROR(EIO);
}
- // FIXME this is wrong, this should rather be in a AVParset
+ // FIXME this is wrong, this should rather be in a AVParser
toc = avio_r8(s->pb);
mode = (toc >> 3) & 0x0F;
@@ -131,15 +137,16 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
};
size = packed_size[mode];
- } else {
- assert(0);
}
if (!size || av_new_packet(pkt, size))
return AVERROR(EIO);
- /* Both AMR formats have 50 frames per second */
- s->streams[0]->codec->bit_rate = size*8*50;
+ if (amr->cumulated_size < UINT64_MAX - size) {
+ amr->cumulated_size += size;
+ /* Both AMR formats have 50 frames per second */
+ s->streams[0]->codec->bit_rate = amr->cumulated_size / ++amr->block_count * 8 * 50;
+ }
pkt->stream_index = 0;
pkt->pos = pos;
@@ -159,6 +166,7 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt)
AVInputFormat ff_amr_demuxer = {
.name = "amr",
.long_name = NULL_IF_CONFIG_SMALL("3GPP AMR"),
+ .priv_data_size = sizeof(AMRContext),
.read_probe = amr_probe,
.read_header = amr_read_header,
.read_packet = amr_read_packet,
diff --git a/libavformat/anm.c b/libavformat/anm.c
index 6b8e3066f3..f718797310 100644
--- a/libavformat/anm.c
+++ b/libavformat/anm.c
@@ -2,20 +2,20 @@
* Deluxe Paint Animation demuxer
* Copyright (c) 2009 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -175,7 +175,7 @@ static int read_packet(AVFormatContext *s,
Page *p;
int tmp, record_size;
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR(EIO);
if (anm->page < 0)
diff --git a/libavformat/apc.c b/libavformat/apc.c
index 0b6c5836c1..21bb514cd0 100644
--- a/libavformat/apc.c
+++ b/libavformat/apc.c
@@ -2,20 +2,20 @@
* CRYO APC audio format demuxer
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,7 @@
#include "libavutil/channel_layout.h"
#include "avformat.h"
+#include "internal.h"
static int apc_probe(AVProbeData *p)
{
@@ -51,14 +52,9 @@ static int apc_read_header(AVFormatContext *s)
avio_rl32(pb); /* number of samples */
st->codec->sample_rate = avio_rl32(pb);
- st->codec->extradata_size = 2 * 4;
- st->codec->extradata = av_malloc(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
-
/* initial predictor values for adpcm decoder */
- avio_read(pb, st->codec->extradata, 2 * 4);
+ if (ff_get_extradata(st->codec, pb, 2 * 4) < 0)
+ return AVERROR(ENOMEM);
if (avio_rl32(pb)) {
st->codec->channels = 2;
@@ -82,6 +78,7 @@ static int apc_read_packet(AVFormatContext *s, AVPacket *pkt)
{
if (av_get_packet(s->pb, pkt, MAX_READ_SIZE) <= 0)
return AVERROR(EIO);
+ pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
pkt->stream_index = 0;
return 0;
}
diff --git a/libavformat/ape.c b/libavformat/ape.c
index 09a756da60..69b001a578 100644
--- a/libavformat/ape.c
+++ b/libavformat/ape.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,8 +38,6 @@
#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level
#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored)
-#define MAC_SUBFRAME_SIZE 4608
-
#define APE_EXTRADATA_SIZE 6
typedef struct APEFrame {
@@ -88,10 +86,14 @@ typedef struct APEContext {
static int ape_probe(AVProbeData * p)
{
- if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ')
- return AVPROBE_SCORE_MAX;
+ int version = AV_RL16(p->buf+4);
+ if (AV_RL32(p->buf) != MKTAG('M', 'A', 'C', ' '))
+ return 0;
- return 0;
+ if (version < APE_MIN_VERSION || version > APE_MAX_VERSION)
+ return AVPROBE_SCORE_MAX/4;
+
+ return AVPROBE_SCORE_MAX;
}
static void ape_dumpinfo(AVFormatContext * s, APEContext * ape_ctx)
@@ -172,14 +174,14 @@ static int ape_read_header(AVFormatContext * s)
tag = avio_rl32(pb);
if (tag != MKTAG('M', 'A', 'C', ' '))
- return -1;
+ return AVERROR_INVALIDDATA;
ape->fileversion = avio_rl16(pb);
if (ape->fileversion < APE_MIN_VERSION || ape->fileversion > APE_MAX_VERSION) {
av_log(s, AV_LOG_ERROR, "Unsupported file version - %d.%02d\n",
ape->fileversion / 1000, (ape->fileversion % 1000) / 10);
- return -1;
+ return AVERROR_PATCHWELCOME;
}
if (ape->fileversion >= 3980) {
@@ -258,15 +260,15 @@ static int ape_read_header(AVFormatContext * s)
if(ape->totalframes > UINT_MAX / sizeof(APEFrame)){
av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n",
ape->totalframes);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (ape->seektablelength / sizeof(*ape->seektable) < ape->totalframes) {
av_log(s, AV_LOG_ERROR,
- "Number of seek entries is less than number of frames: %zu vs. %"PRIu32"\n",
+ "Number of seek entries is less than number of frames: %"SIZE_SPECIFIER" vs. %"PRIu32"\n",
ape->seektablelength / sizeof(*ape->seektable), ape->totalframes);
return AVERROR_INVALIDDATA;
}
- ape->frames = av_malloc(ape->totalframes * sizeof(APEFrame));
+ ape->frames = av_malloc_array(ape->totalframes, sizeof(APEFrame));
if(!ape->frames)
return AVERROR(ENOMEM);
ape->firstframe = ape->junklength + ape->descriptorlength + ape->headerlength + ape->seektablelength + ape->wavheaderlength;
@@ -280,18 +282,20 @@ static int ape_read_header(AVFormatContext * s)
ape->totalsamples += ape->blocksperframe * (ape->totalframes - 1);
if (ape->seektablelength > 0) {
- ape->seektable = av_malloc(ape->seektablelength);
+ ape->seektable = av_mallocz(ape->seektablelength);
if (!ape->seektable)
return AVERROR(ENOMEM);
for (i = 0; i < ape->seektablelength / sizeof(uint32_t) && !pb->eof_reached; i++)
ape->seektable[i] = avio_rl32(pb);
if (ape->fileversion < 3810) {
- ape->bittable = av_malloc(ape->totalframes);
+ ape->bittable = av_mallocz(ape->totalframes);
if (!ape->bittable)
return AVERROR(ENOMEM);
for (i = 0; i < ape->totalframes && !pb->eof_reached; i++)
ape->bittable[i] = avio_r8(pb);
}
+ if (pb->eof_reached)
+ av_log(s, AV_LOG_WARNING, "File truncated\n");
}
ape->frames[0].pos = ape->firstframe;
@@ -340,7 +344,7 @@ static int ape_read_header(AVFormatContext * s)
/* now we are ready: build format streams */
st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
total_blocks = (ape->totalframes == 0) ? 0 : ((ape->totalframes - 1) * ape->blocksperframe) + ape->finalframeblocks;
@@ -353,11 +357,11 @@ static int ape_read_header(AVFormatContext * s)
st->nb_frames = ape->totalframes;
st->start_time = 0;
- st->duration = total_blocks / MAC_SUBFRAME_SIZE;
- avpriv_set_pts_info(st, 64, MAC_SUBFRAME_SIZE, ape->samplerate);
+ st->duration = total_blocks;
+ avpriv_set_pts_info(st, 64, 1, ape->samplerate);
- st->codec->extradata = av_malloc(APE_EXTRADATA_SIZE);
- st->codec->extradata_size = APE_EXTRADATA_SIZE;
+ if (ff_alloc_extradata(st->codec, APE_EXTRADATA_SIZE))
+ return AVERROR(ENOMEM);
AV_WL16(st->codec->extradata + 0, ape->fileversion);
AV_WL16(st->codec->extradata + 2, ape->compressiontype);
AV_WL16(st->codec->extradata + 4, ape->formatflags);
@@ -366,7 +370,7 @@ static int ape_read_header(AVFormatContext * s)
for (i = 0; i < ape->totalframes; i++) {
ape->frames[i].pts = pts;
av_add_index_entry(st, ape->frames[i].pos, ape->frames[i].pts, 0, 0, AVINDEX_KEYFRAME);
- pts += ape->blocksperframe / MAC_SUBFRAME_SIZE;
+ pts += ape->blocksperframe;
}
/* try to read APE tags */
@@ -385,7 +389,7 @@ static int ape_read_packet(AVFormatContext * s, AVPacket * pkt)
APEContext *ape = s->priv_data;
uint32_t extra_size = 8;
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR_EOF;
if (ape->currentframe >= ape->totalframes)
return AVERROR_EOF;
@@ -413,6 +417,10 @@ static int ape_read_packet(AVFormatContext * s, AVPacket * pkt)
AV_WL32(pkt->data , nblocks);
AV_WL32(pkt->data + 4, ape->frames[ape->currentframe].skip);
ret = avio_read(s->pb, pkt->data + extra_size, ape->frames[ape->currentframe].size);
+ if (ret < 0) {
+ av_free_packet(pkt);
+ return ret;
+ }
pkt->pts = ape->frames[ape->currentframe].pts;
pkt->stream_index = 0;
diff --git a/libavformat/apetag.c b/libavformat/apetag.c
index 4d65301697..26359205f8 100644
--- a/libavformat/apetag.c
+++ b/libavformat/apetag.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,8 +29,6 @@
#include "apetag.h"
#include "internal.h"
-#define APE_TAG_VERSION 2000
-#define APE_TAG_FOOTER_BYTES 32
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
@@ -64,15 +62,19 @@ static int ape_tag_read_field(AVFormatContext *s)
if (flags & APE_TAG_FLAG_IS_BINARY) {
uint8_t filename[1024];
enum AVCodecID id;
+ int ret;
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
- size -= avio_get_str(pb, size, filename, sizeof(filename));
- if (size <= 0) {
+ ret = avio_get_str(pb, size, filename, sizeof(filename));
+ if (ret < 0)
+ return ret;
+ if (size <= ret) {
av_log(s, AV_LOG_WARNING, "Skipping binary tag '%s'.\n", key);
return 0;
}
+ size -= ret;
av_dict_set(&st->metadata, key, filename, 0);
@@ -94,14 +96,8 @@ static int ape_tag_read_field(AVFormatContext *s)
st->attached_pic.stream_index = st->index;
st->attached_pic.flags |= AV_PKT_FLAG_KEY;
} else {
- st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, s->pb, size) < 0)
return AVERROR(ENOMEM);
- if (avio_read(pb, st->codec->extradata, size) != size) {
- av_freep(&st->codec->extradata);
- return AVERROR(EIO);
- }
- st->codec->extradata_size = size;
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
}
} else {
@@ -134,7 +130,7 @@ 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 (strncmp(buf, "APETAGEX", 8)) {
+ if (strncmp(buf, APE_TAG_PREAMBLE, 8)) {
return 0;
}
@@ -176,43 +172,61 @@ int64_t ff_ape_parse_tag(AVFormatContext *s)
return tag_start;
}
+static int string_is_ascii(const uint8_t *str)
+{
+ while (*str && *str >= 0x20 && *str <= 0x7e ) str++;
+ return !*str;
+}
+
int ff_ape_write_tag(AVFormatContext *s)
{
AVDictionaryEntry *e = NULL;
- int64_t start, end;
- int size, count = 0;
-
- if (!s->pb->seekable)
- return 0;
+ int size, ret, count = 0;
+ AVIOContext *dyn_bc = NULL;
+ uint8_t *dyn_buf = NULL;
- start = avio_tell(s->pb);
-
- // header
- avio_write(s->pb, "APETAGEX", 8); // id
- avio_wl32 (s->pb, APE_TAG_VERSION); // version
- avio_wl32(s->pb, 0); // reserve space for size
- avio_wl32(s->pb, 0); // reserve space for tag count
+ if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
+ goto end;
// flags
- avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER |
+ avio_wl32(dyn_bc, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER |
APE_TAG_FLAG_IS_HEADER);
- ffio_fill(s->pb, 0, 8); // reserved
+ ffio_fill(dyn_bc, 0, 8); // reserved
while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
- int val_len = strlen(e->value);
+ int val_len;
- avio_wl32(s->pb, val_len); // value length
- avio_wl32(s->pb, 0); // item flags
- avio_put_str(s->pb, e->key); // key
- avio_write(s->pb, e->value, val_len); // value
+ if (!string_is_ascii(e->key)) {
+ av_log(s, AV_LOG_WARNING, "Non ASCII keys are not allowed\n");
+ continue;
+ }
+
+ val_len = strlen(e->value);
+ avio_wl32(dyn_bc, val_len); // value length
+ avio_wl32(dyn_bc, 0); // item flags
+ avio_put_str(dyn_bc, e->key); // key
+ avio_write(dyn_bc, e->value, val_len); // value
count++;
}
+ if (!count)
+ goto end;
+
+ size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ if (size <= 0)
+ goto end;
+ size += 20;
+
+ // header
+ avio_write(s->pb, "APETAGEX", 8); // id
+ avio_wl32(s->pb, APE_TAG_VERSION); // version
+ avio_wl32(s->pb, size);
+ avio_wl32(s->pb, count);
- size = avio_tell(s->pb) - start;
+ avio_write(s->pb, dyn_buf, size - 20);
// footer
avio_write(s->pb, "APETAGEX", 8); // id
- avio_wl32 (s->pb, APE_TAG_VERSION); // version
+ avio_wl32(s->pb, APE_TAG_VERSION); // version
avio_wl32(s->pb, size); // size
avio_wl32(s->pb, count); // tag count
@@ -220,12 +234,10 @@ int ff_ape_write_tag(AVFormatContext *s)
avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER);
ffio_fill(s->pb, 0, 8); // reserved
- // update values in the header
- end = avio_tell(s->pb);
- avio_seek(s->pb, start + 12, SEEK_SET);
- avio_wl32(s->pb, size);
- avio_wl32(s->pb, count);
- avio_seek(s->pb, end, SEEK_SET);
+end:
+ if (dyn_bc && !dyn_buf)
+ avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ av_freep(&dyn_buf);
- return 0;
+ return ret;
}
diff --git a/libavformat/apetag.h b/libavformat/apetag.h
index 36e3211fc8..cf2a5f8ab4 100644
--- a/libavformat/apetag.h
+++ b/libavformat/apetag.h
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Benjamin Zores <ben@geexbox.org>
* based upon libdemac from Dave Chapman.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,10 @@
#include "avformat.h"
+#define APE_TAG_PREAMBLE "APETAGEX"
+#define APE_TAG_VERSION 2000
+#define APE_TAG_FOOTER_BYTES 32
+
/**
* Read and parse an APE tag
*
diff --git a/libavformat/apngdec.c b/libavformat/apngdec.c
new file mode 100644
index 0000000000..6deff3b66b
--- /dev/null
+++ b/libavformat/apngdec.c
@@ -0,0 +1,447 @@
+/*
+ * APNG demuxer
+ * Copyright (c) 2014 Benoit Fouet
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * APNG demuxer.
+ * @see https://wiki.mozilla.org/APNG_Specification
+ * @see http://www.w3.org/TR/PNG
+ */
+
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavcodec/apng.h"
+#include "libavcodec/png.h"
+#include "libavcodec/bytestream.h"
+
+#define DEFAULT_APNG_FPS 15
+
+typedef struct APNGDemuxContext {
+ const AVClass *class;
+
+ int max_fps;
+ int default_fps;
+
+ int64_t pkt_pts;
+ int pkt_duration;
+
+ int is_key_frame;
+
+ /*
+ * loop options
+ */
+ int ignore_loop;
+ uint32_t num_frames;
+ uint32_t num_play;
+ uint32_t cur_loop;
+} APNGDemuxContext;
+
+/*
+ * To be a valid APNG file, we mandate, in this order:
+ * PNGSIG
+ * IHDR
+ * ...
+ * acTL
+ * ...
+ * IDAT
+ */
+static int apng_probe(AVProbeData *p)
+{
+ GetByteContext gb;
+ int state = 0;
+ uint32_t len, tag;
+
+ bytestream2_init(&gb, p->buf, p->buf_size);
+
+ if (bytestream2_get_be64(&gb) != PNGSIG)
+ return 0;
+
+ for (;;) {
+ len = bytestream2_get_be32(&gb);
+ if (len > 0x7fffffff)
+ return 0;
+
+ tag = bytestream2_get_le32(&gb);
+ /* we don't check IDAT size, as this is the last tag
+ * we check, and it may be larger than the probe buffer */
+ if (tag != MKTAG('I', 'D', 'A', 'T') &&
+ len + 4 > bytestream2_get_bytes_left(&gb))
+ return 0;
+
+ switch (tag) {
+ case MKTAG('I', 'H', 'D', 'R'):
+ if (len != 13)
+ return 0;
+ if (av_image_check_size(bytestream2_get_be32(&gb), bytestream2_get_be32(&gb), 0, NULL))
+ return 0;
+ bytestream2_skip(&gb, 9);
+ state++;
+ break;
+ case MKTAG('a', 'c', 'T', 'L'):
+ if (state != 1 ||
+ len != 8 ||
+ bytestream2_get_be32(&gb) == 0) /* 0 is not a valid value for number of frames */
+ return 0;
+ bytestream2_skip(&gb, 8);
+ state++;
+ break;
+ case MKTAG('I', 'D', 'A', 'T'):
+ if (state != 2)
+ return 0;
+ goto end;
+ default:
+ /* skip other tags */
+ bytestream2_skip(&gb, len + 4);
+ break;
+ }
+ }
+
+end:
+ return AVPROBE_SCORE_MAX;
+}
+
+static int append_extradata(AVCodecContext *s, AVIOContext *pb, int len)
+{
+ int previous_size = s->extradata_size;
+ int new_size, ret;
+ uint8_t *new_extradata;
+
+ if (previous_size > INT_MAX - len)
+ return AVERROR_INVALIDDATA;
+
+ new_size = previous_size + len;
+ new_extradata = av_realloc(s->extradata, new_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!new_extradata)
+ return AVERROR(ENOMEM);
+ s->extradata = new_extradata;
+ s->extradata_size = new_size;
+
+ if ((ret = avio_read(pb, s->extradata + previous_size, len)) < 0)
+ return ret;
+
+ return previous_size;
+}
+
+static int apng_read_header(AVFormatContext *s)
+{
+ APNGDemuxContext *ctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint32_t len, tag;
+ AVStream *st;
+ int acTL_found = 0;
+ int64_t ret = AVERROR_INVALIDDATA;
+
+ /* verify PNGSIG */
+ if (avio_rb64(pb) != PNGSIG)
+ return ret;
+
+ /* parse IHDR (must be first chunk) */
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+ if (len != 13 || tag != MKTAG('I', 'H', 'D', 'R'))
+ return ret;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ /* set the timebase to something large enough (1/100,000 of second)
+ * to hopefully cope with all sane frame durations */
+ avpriv_set_pts_info(st, 64, 1, 100000);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_APNG;
+ st->codec->width = avio_rb32(pb);
+ st->codec->height = avio_rb32(pb);
+ if ((ret = av_image_check_size(st->codec->width, st->codec->height, 0, s)) < 0)
+ return ret;
+
+ /* extradata will contain every chunk up to the first fcTL (excluded) */
+ st->codec->extradata = av_malloc(len + 12 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
+ st->codec->extradata_size = len + 12;
+ AV_WB32(st->codec->extradata, len);
+ AV_WL32(st->codec->extradata+4, tag);
+ AV_WB32(st->codec->extradata+8, st->codec->width);
+ AV_WB32(st->codec->extradata+12, st->codec->height);
+ if ((ret = avio_read(pb, st->codec->extradata+16, 9)) < 0)
+ goto fail;
+
+ while (!avio_feof(pb)) {
+ if (acTL_found && ctx->num_play != 1) {
+ int64_t size = avio_size(pb);
+ int64_t offset = avio_tell(pb);
+ if (size < 0) {
+ ret = size;
+ goto fail;
+ } else if (offset < 0) {
+ ret = offset;
+ goto fail;
+ } else if ((ret = ffio_ensure_seekback(pb, size - offset)) < 0) {
+ av_log(s, AV_LOG_WARNING, "Could not ensure seekback, will not loop\n");
+ ctx->num_play = 1;
+ }
+ }
+ if ((ctx->num_play == 1 || !acTL_found) &&
+ ((ret = ffio_ensure_seekback(pb, 4 /* len */ + 4 /* tag */)) < 0))
+ goto fail;
+
+ len = avio_rb32(pb);
+ if (len > 0x7fffffff) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ tag = avio_rl32(pb);
+ switch (tag) {
+ case MKTAG('a', 'c', 'T', 'L'):
+ if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 ||
+ (ret = append_extradata(st->codec, pb, len + 12)) < 0)
+ goto fail;
+ acTL_found = 1;
+ ctx->num_frames = AV_RB32(st->codec->extradata + ret + 8);
+ ctx->num_play = AV_RB32(st->codec->extradata + ret + 12);
+ av_log(s, AV_LOG_DEBUG, "num_frames: %"PRIu32", num_play: %"PRIu32"\n",
+ ctx->num_frames, ctx->num_play);
+ break;
+ case MKTAG('f', 'c', 'T', 'L'):
+ if (!acTL_found) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0)
+ goto fail;
+ return 0;
+ default:
+ if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 ||
+ (ret = append_extradata(st->codec, pb, len + 12)) < 0)
+ goto fail;
+ }
+ }
+
+fail:
+ if (st->codec->extradata_size) {
+ av_freep(&st->codec->extradata);
+ st->codec->extradata_size = 0;
+ }
+ return ret;
+}
+
+static int decode_fctl_chunk(AVFormatContext *s, APNGDemuxContext *ctx, AVPacket *pkt)
+{
+ uint32_t sequence_number, width, height, x_offset, y_offset;
+ uint16_t delay_num, delay_den;
+ uint8_t dispose_op, blend_op;
+
+ sequence_number = avio_rb32(s->pb);
+ width = avio_rb32(s->pb);
+ height = avio_rb32(s->pb);
+ x_offset = avio_rb32(s->pb);
+ y_offset = avio_rb32(s->pb);
+ delay_num = avio_rb16(s->pb);
+ delay_den = avio_rb16(s->pb);
+ dispose_op = avio_r8(s->pb);
+ blend_op = avio_r8(s->pb);
+ avio_skip(s->pb, 4); /* crc */
+
+ /* default is hundredths of seconds */
+ if (!delay_den)
+ delay_den = 100;
+ if (!delay_num || delay_den / delay_num > ctx->max_fps) {
+ delay_num = 1;
+ delay_den = ctx->default_fps;
+ }
+ ctx->pkt_duration = av_rescale_q(delay_num,
+ (AVRational){ 1, delay_den },
+ s->streams[0]->time_base);
+
+ av_log(s, AV_LOG_DEBUG, "%s: "
+ "sequence_number: %"PRId32", "
+ "width: %"PRIu32", "
+ "height: %"PRIu32", "
+ "x_offset: %"PRIu32", "
+ "y_offset: %"PRIu32", "
+ "delay_num: %"PRIu16", "
+ "delay_den: %"PRIu16", "
+ "dispose_op: %d, "
+ "blend_op: %d\n",
+ __FUNCTION__,
+ sequence_number,
+ width,
+ height,
+ x_offset,
+ y_offset,
+ delay_num,
+ delay_den,
+ dispose_op,
+ blend_op);
+
+ if (width != s->streams[0]->codec->width ||
+ height != s->streams[0]->codec->height ||
+ x_offset != 0 ||
+ y_offset != 0) {
+ if (sequence_number == 0 ||
+ x_offset >= s->streams[0]->codec->width ||
+ width > s->streams[0]->codec->width - x_offset ||
+ y_offset >= s->streams[0]->codec->height ||
+ height > s->streams[0]->codec->height - y_offset)
+ return AVERROR_INVALIDDATA;
+ ctx->is_key_frame = 0;
+ } else {
+ if (sequence_number == 0 && dispose_op == APNG_DISPOSE_OP_PREVIOUS)
+ dispose_op = APNG_DISPOSE_OP_BACKGROUND;
+ ctx->is_key_frame = dispose_op == APNG_DISPOSE_OP_BACKGROUND ||
+ blend_op == APNG_BLEND_OP_SOURCE;
+ }
+
+ return 0;
+}
+
+static int apng_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ APNGDemuxContext *ctx = s->priv_data;
+ int64_t ret;
+ int64_t size;
+ AVIOContext *pb = s->pb;
+ uint32_t len, tag;
+
+ /*
+ * fcTL chunk length, in bytes:
+ * 4 (length)
+ * 4 (tag)
+ * 26 (actual chunk)
+ * 4 (crc) bytes
+ * and needed next:
+ * 4 (length)
+ * 4 (tag (must be fdAT or IDAT))
+ */
+ /* if num_play is not 1, then the seekback is already guaranteed */
+ if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 46)) < 0)
+ return ret;
+
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+ switch (tag) {
+ case MKTAG('f', 'c', 'T', 'L'):
+ if (len != 26)
+ return AVERROR_INVALIDDATA;
+
+ if ((ret = decode_fctl_chunk(s, ctx, pkt)) < 0)
+ return ret;
+
+ /* fcTL must precede fdAT or IDAT */
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+ if (len > 0x7fffffff ||
+ tag != MKTAG('f', 'd', 'A', 'T') &&
+ tag != MKTAG('I', 'D', 'A', 'T'))
+ return AVERROR_INVALIDDATA;
+
+ size = 38 /* fcTL */ + 8 /* len, tag */ + len + 4 /* crc */;
+ if (size > INT_MAX)
+ return AVERROR(EINVAL);
+
+ if ((ret = avio_seek(pb, -46, SEEK_CUR)) < 0 ||
+ (ret = av_append_packet(pb, pkt, size)) < 0)
+ return ret;
+
+ if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 8)) < 0)
+ return ret;
+
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+ while (tag &&
+ tag != MKTAG('f', 'c', 'T', 'L') &&
+ tag != MKTAG('I', 'E', 'N', 'D')) {
+ if (len > 0x7fffffff)
+ return AVERROR_INVALIDDATA;
+ if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0 ||
+ (ret = av_append_packet(pb, pkt, len + 12)) < 0)
+ return ret;
+ if (ctx->num_play == 1 && (ret = ffio_ensure_seekback(pb, 8)) < 0)
+ return ret;
+ len = avio_rb32(pb);
+ tag = avio_rl32(pb);
+ }
+ if ((ret = avio_seek(pb, -8, SEEK_CUR)) < 0)
+ return ret;
+
+ if (ctx->is_key_frame)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->pts = ctx->pkt_pts;
+ pkt->duration = ctx->pkt_duration;
+ ctx->pkt_pts += ctx->pkt_duration;
+ return ret;
+ case MKTAG('I', 'E', 'N', 'D'):
+ ctx->cur_loop++;
+ if (ctx->ignore_loop || ctx->num_play >= 1 && ctx->cur_loop == ctx->num_play) {
+ avio_seek(pb, -8, SEEK_CUR);
+ return AVERROR_EOF;
+ }
+ if ((ret = avio_seek(pb, s->streams[0]->codec->extradata_size + 8, SEEK_SET)) < 0)
+ return ret;
+ return 0;
+ default:
+ {
+ char tag_buf[32];
+
+ av_get_codec_tag_string(tag_buf, sizeof(tag_buf), tag);
+ avpriv_request_sample(s, "In-stream tag=%s (0x%08X) len=%"PRIu32, tag_buf, tag, len);
+ avio_skip(pb, len + 4);
+ }
+ }
+
+ /* Handle the unsupported yet cases */
+ return AVERROR_PATCHWELCOME;
+}
+
+static const AVOption options[] = {
+ { "ignore_loop", "ignore loop setting" , offsetof(APNGDemuxContext, ignore_loop),
+ AV_OPT_TYPE_INT, { .i64 = 1 } , 0, 1 , AV_OPT_FLAG_DECODING_PARAM },
+ { "max_fps" , "maximum framerate (0 is no limit)" , offsetof(APNGDemuxContext, max_fps),
+ AV_OPT_TYPE_INT, { .i64 = DEFAULT_APNG_FPS }, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { "default_fps", "default framerate (0 is as fast as possible)", offsetof(APNGDemuxContext, default_fps),
+ AV_OPT_TYPE_INT, { .i64 = DEFAULT_APNG_FPS }, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass demuxer_class = {
+ .class_name = "APNG demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEMUXER,
+};
+
+AVInputFormat ff_apng_demuxer = {
+ .name = "apng",
+ .long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
+ .priv_data_size = sizeof(APNGDemuxContext),
+ .read_probe = apng_probe,
+ .read_header = apng_read_header,
+ .read_packet = apng_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+ .priv_class = &demuxer_class,
+};
diff --git a/libavformat/apngenc.c b/libavformat/apngenc.c
new file mode 100644
index 0000000000..dcf6b906e1
--- /dev/null
+++ b/libavformat/apngenc.c
@@ -0,0 +1,271 @@
+/*
+ * APNG muxer
+ * Copyright (c) 2015 Donny Yang
+ *
+ * first version by Donny Yang <work@kota.moe>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/crc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavcodec/png.h"
+#include "libavcodec/apng.h"
+
+typedef struct APNGMuxContext {
+ AVClass *class;
+
+ uint32_t plays;
+ AVRational last_delay;
+
+ uint64_t acTL_offset;
+ uint32_t frame_number;
+
+ AVPacket *prev_packet;
+ AVRational prev_delay;
+
+ int framerate_warned;
+} APNGMuxContext;
+
+static uint8_t *apng_find_chunk(uint32_t tag, uint8_t *buf, size_t length)
+{
+ size_t b;
+ for (b = 0; b < length; b += AV_RB32(buf + b) + 12)
+ if (AV_RB32(&buf[b + 4]) == tag)
+ return &buf[b];
+ return NULL;
+}
+
+static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
+ uint8_t *buf, size_t length)
+{
+ const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
+ uint32_t crc = ~0U;
+ uint8_t tagbuf[4];
+
+ av_assert0(crc_table);
+
+ avio_wb32(io_context, length);
+ AV_WB32(tagbuf, tag);
+ crc = av_crc(crc_table, crc, tagbuf, 4);
+ avio_wb32(io_context, tag);
+ if (length > 0) {
+ crc = av_crc(crc_table, crc, buf, length);
+ avio_write(io_context, buf, length);
+ }
+ avio_wb32(io_context, ~crc);
+}
+
+static int apng_write_header(AVFormatContext *format_context)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+
+ if (format_context->nb_streams != 1 ||
+ format_context->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
+ format_context->streams[0]->codec->codec_id != AV_CODEC_ID_APNG) {
+ av_log(format_context, AV_LOG_ERROR,
+ "APNG muxer supports only a single video APNG stream.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (apng->last_delay.num > USHRT_MAX || apng->last_delay.den > USHRT_MAX) {
+ av_reduce(&apng->last_delay.num, &apng->last_delay.den,
+ apng->last_delay.num, apng->last_delay.den, USHRT_MAX);
+ av_log(format_context, AV_LOG_WARNING,
+ "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
+ apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
+ }
+
+ avio_wb64(format_context->pb, PNGSIG);
+ // Remaining headers are written when they are copied from the encoder
+
+ return 0;
+}
+
+static void flush_packet(AVFormatContext *format_context, AVPacket *packet)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+ AVIOContext *io_context = format_context->pb;
+ AVStream *codec_stream = format_context->streams[0];
+ AVCodecContext *codec_context = codec_stream->codec;
+
+ av_assert0(apng->prev_packet);
+
+ if (apng->frame_number == 0 && !packet) {
+ uint8_t *existing_acTL_chunk;
+ uint8_t *existing_fcTL_chunk;
+
+ av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
+
+ // Write normal PNG headers without acTL chunk
+ existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), codec_context->extradata, codec_context->extradata_size);
+ if (existing_acTL_chunk) {
+ uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
+ avio_write(io_context, codec_context->extradata, existing_acTL_chunk - codec_context->extradata);
+ avio_write(io_context, chunk_after_acTL, codec_context->extradata + codec_context->extradata_size - chunk_after_acTL);
+ } else {
+ avio_write(io_context, codec_context->extradata, codec_context->extradata_size);
+ }
+
+ // Write frame data without fcTL chunk
+ existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
+ if (existing_fcTL_chunk) {
+ uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
+ avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
+ avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
+ } else {
+ avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
+ }
+ } else {
+ uint8_t *existing_fcTL_chunk;
+
+ if (apng->frame_number == 0) {
+ uint8_t *existing_acTL_chunk;
+
+ // Write normal PNG headers
+ avio_write(io_context, codec_context->extradata, codec_context->extradata_size);
+
+ existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), codec_context->extradata, codec_context->extradata_size);
+ if (!existing_acTL_chunk) {
+ uint8_t buf[8];
+ // Write animation control header
+ apng->acTL_offset = avio_tell(io_context);
+ AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
+ AV_WB32(buf + 4, apng->plays);
+ apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
+ }
+ }
+
+ existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
+ if (existing_fcTL_chunk) {
+ AVRational delay;
+
+ existing_fcTL_chunk += 8;
+ delay.num = AV_RB16(existing_fcTL_chunk + 20);
+ delay.den = AV_RB16(existing_fcTL_chunk + 22);
+
+ if (delay.num == 0 && delay.den == 0) {
+ if (packet) {
+ int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
+ int64_t delay_den_raw = codec_stream->time_base.den;
+ if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, USHRT_MAX) &&
+ !apng->framerate_warned) {
+ av_log(format_context, AV_LOG_WARNING,
+ "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
+ apng->framerate_warned = 1;
+ }
+ } else if (apng->last_delay.den > 0) {
+ delay = apng->last_delay;
+ } else {
+ delay = apng->prev_delay;
+ }
+
+ // Update frame control header with new delay
+ AV_WB16(existing_fcTL_chunk + 20, delay.num);
+ AV_WB16(existing_fcTL_chunk + 22, delay.den);
+ AV_WB32(existing_fcTL_chunk + 26, ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, existing_fcTL_chunk - 4, 26 + 4));
+ }
+ apng->prev_delay = delay;
+ }
+
+ // Write frame data
+ avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
+ }
+ ++apng->frame_number;
+
+ av_free_packet(apng->prev_packet);
+ if (packet)
+ av_copy_packet(apng->prev_packet, packet);
+}
+
+static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+
+ if (!apng->prev_packet) {
+ apng->prev_packet = av_malloc(sizeof(*apng->prev_packet));
+ if (!apng->prev_packet)
+ return AVERROR(ENOMEM);
+
+ av_copy_packet(apng->prev_packet, packet);
+ } else {
+ flush_packet(format_context, packet);
+ }
+
+ return 0;
+}
+
+static int apng_write_trailer(AVFormatContext *format_context)
+{
+ APNGMuxContext *apng = format_context->priv_data;
+ AVIOContext *io_context = format_context->pb;
+ uint8_t buf[8];
+
+ if (apng->prev_packet) {
+ flush_packet(format_context, NULL);
+ av_freep(&apng->prev_packet);
+ }
+
+ apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
+
+ if (apng->acTL_offset && io_context->seekable) {
+ avio_seek(io_context, apng->acTL_offset, SEEK_SET);
+
+ AV_WB32(buf, apng->frame_number);
+ AV_WB32(buf + 4, apng->plays);
+ apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
+ }
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(APNGMuxContext, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
+ AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT_MAX, ENC },
+ { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
+ AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, USHRT_MAX, ENC },
+ { NULL },
+};
+
+static const AVClass apng_muxer_class = {
+ .class_name = "APNG muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .option = options,
+};
+
+AVOutputFormat ff_apng_muxer = {
+ .name = "apng",
+ .long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
+ .mime_type = "image/png",
+ .extensions = "apng",
+ .priv_data_size = sizeof(APNGMuxContext),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_APNG,
+ .write_header = apng_write_header,
+ .write_packet = apng_write_packet,
+ .write_trailer = apng_write_trailer,
+ .priv_class = &apng_muxer_class,
+ .flags = AVFMT_VARIABLE_FPS,
+};
diff --git a/libavformat/aqtitledec.c b/libavformat/aqtitledec.c
new file mode 100644
index 0000000000..95087665aa
--- /dev/null
+++ b/libavformat/aqtitledec.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * AQTitle subtitles format demuxer
+ *
+ * @see http://web.archive.org/web/20070210095721/http://www.volny.cz/aberka/czech/aqt.html
+ * @see https://trac.annodex.net/wiki/AQTitle
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavutil/opt.h"
+
+typedef struct {
+ const AVClass *class;
+ FFDemuxSubtitlesQueue q;
+ AVRational frame_rate;
+} AQTitleContext;
+
+static int aqt_probe(AVProbeData *p)
+{
+ int frame;
+ const char *ptr = p->buf;
+
+ if (sscanf(ptr, "-->> %d", &frame) == 1)
+ return AVPROBE_SCORE_EXTENSION;
+ return 0;
+}
+
+static int aqt_read_header(AVFormatContext *s)
+{
+ AQTitleContext *aqt = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ int new_event = 1;
+ int64_t pos = 0, frame = AV_NOPTS_VALUE;
+ AVPacket *sub = NULL;
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, aqt->frame_rate.den, aqt->frame_rate.num);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_TEXT;
+
+ while (!avio_feof(s->pb)) {
+ char line[4096];
+ int len = ff_get_line(s->pb, line, sizeof(line));
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ if (sscanf(line, "-->> %"SCNd64, &frame) == 1) {
+ new_event = 1;
+ pos = avio_tell(s->pb);
+ if (sub) {
+ sub->duration = frame - sub->pts;
+ sub = NULL;
+ }
+ } else if (*line) {
+ if (!new_event) {
+ sub = ff_subtitles_queue_insert(&aqt->q, "\n", 1, 1);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ }
+ sub = ff_subtitles_queue_insert(&aqt->q, line, strlen(line), !new_event);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ if (new_event) {
+ sub->pts = frame;
+ sub->duration = -1;
+ sub->pos = pos;
+ }
+ new_event = 0;
+ }
+ }
+
+ ff_subtitles_queue_finalize(&aqt->q);
+ return 0;
+}
+
+static int aqt_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AQTitleContext *aqt = s->priv_data;
+ return ff_subtitles_queue_read_packet(&aqt->q, pkt);
+}
+
+static int aqt_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ AQTitleContext *aqt = s->priv_data;
+ return ff_subtitles_queue_seek(&aqt->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int aqt_read_close(AVFormatContext *s)
+{
+ AQTitleContext *aqt = s->priv_data;
+ ff_subtitles_queue_clean(&aqt->q);
+ return 0;
+}
+
+#define OFFSET(x) offsetof(AQTitleContext, x)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM
+static const AVOption aqt_options[] = {
+ { "subfps", "set the movie frame rate", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=25}, 0, INT_MAX, SD },
+ { NULL }
+};
+
+static const AVClass aqt_class = {
+ .class_name = "aqtdec",
+ .item_name = av_default_item_name,
+ .option = aqt_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_aqtitle_demuxer = {
+ .name = "aqtitle",
+ .long_name = NULL_IF_CONFIG_SMALL("AQTitle subtitles"),
+ .priv_data_size = sizeof(AQTitleContext),
+ .read_probe = aqt_probe,
+ .read_header = aqt_read_header,
+ .read_packet = aqt_read_packet,
+ .read_seek2 = aqt_read_seek,
+ .read_close = aqt_read_close,
+ .extensions = "aqt",
+ .priv_class = &aqt_class,
+};
diff --git a/libavformat/asf.c b/libavformat/asf.c
index ec34b5010d..80d24dbf43 100644
--- a/libavformat/asf.c
+++ b/libavformat/asf.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -159,7 +159,6 @@ const AVMetadataConv ff_asf_metadata_conv[] = {
{ "WM/Publisher", "publisher" },
{ "WM/Tool", "encoder" },
{ "WM/TrackNumber", "track" },
- { "WM/Track", "track" },
{ "WM/MediaStationCallSign", "service_provider" },
{ "WM/MediaStationName", "service_name" },
// { "Year" , "date" }, TODO: conversion year<->date
diff --git a/libavformat/asf.h b/libavformat/asf.h
index 2f6722adca..0c9598a8d8 100644
--- a/libavformat/asf.h
+++ b/libavformat/asf.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,14 +28,22 @@
#define PACKET_SIZE 3200
+typedef struct ASFPayload {
+ uint8_t type;
+ uint16_t size;
+} ASFPayload;
+
typedef struct ASFStream {
int num;
unsigned char seq;
/* use for reading */
AVPacket pkt;
int frag_offset;
+ int packet_obj_size;
int timestamp;
int64_t duration;
+ int skip_to_key;
+ int pkt_clean;
int ds_span; /* descrambling */
int ds_packet_size;
@@ -47,6 +55,9 @@ typedef struct ASFStream {
int palette_changed;
uint32_t palette[256];
+
+ int payload_ext_ct;
+ ASFPayload payload[8];
} ASFStream;
typedef struct ASFMainHeader {
diff --git a/libavformat/asfcrypt.c b/libavformat/asfcrypt.c
index c261475848..a402758d0a 100644
--- a/libavformat/asfcrypt.c
+++ b/libavformat/asfcrypt.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Reimar Doeffinger
* This is a rewrite of code contained in freeme/freeme2
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/asfcrypt.h b/libavformat/asfcrypt.h
index 53388b426e..8b80d63c5d 100644
--- a/libavformat/asfcrypt.h
+++ b/libavformat/asfcrypt.h
@@ -2,20 +2,20 @@
* ASF decryption
* Copyright (c) 2007 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c
index 34e9036d7a..359ee8be2f 100644
--- a/libavformat/asfdec.c
+++ b/libavformat/asfdec.c
@@ -2,20 +2,20 @@
* ASF compatible demuxer
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,8 +69,8 @@ typedef struct ASFContext {
unsigned int packet_frag_offset;
unsigned int packet_frag_size;
int64_t packet_frag_timestamp;
+ int ts_is_pts;
int packet_multi_size;
- int packet_obj_size;
int packet_time_delta;
int packet_time_start;
int64_t packet_pos;
@@ -100,12 +100,8 @@ static const AVClass asf_class = {
#include <assert.h>
#define ASF_MAX_STREAMS 127
-#define FRAME_HEADER_SIZE 17
-// Fix Me! FRAME_HEADER_SIZE may be different.
-
-static const ff_asf_guid index_guid = {
- 0x90, 0x08, 0x00, 0x33, 0xb1, 0xe5, 0xcf, 0x11, 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
-};
+#define FRAME_HEADER_SIZE 16
+// Fix Me! FRAME_HEADER_SIZE may be different. (17 is known to be too large)
#ifdef DEBUG
static const ff_asf_guid stream_bitrate_guid = { /* (http://get.to/sdp) */
@@ -131,7 +127,7 @@ static void print_guid(ff_asf_guid *g)
else PRINT_IF_GUID(g, ff_asf_codec_comment_header);
else PRINT_IF_GUID(g, ff_asf_codec_comment1_header);
else PRINT_IF_GUID(g, ff_asf_data_header);
- else PRINT_IF_GUID(g, index_guid);
+ else PRINT_IF_GUID(g, ff_asf_simple_index_header);
else PRINT_IF_GUID(g, ff_asf_head1_guid);
else PRINT_IF_GUID(g, ff_asf_head2_guid);
else PRINT_IF_GUID(g, ff_asf_my_guid);
@@ -152,7 +148,7 @@ static void print_guid(ff_asf_guid *g)
}
#undef PRINT_IF_GUID
#else
-#define print_guid(g)
+#define print_guid(g) while(0)
#endif
static int asf_probe(AVProbeData *pd)
@@ -275,7 +271,7 @@ static void get_id3_tag(AVFormatContext *s, int len)
{
ID3v2ExtraMeta *id3v2_extra_meta = NULL;
- ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len);
if (id3v2_extra_meta)
ff_id3v2_parse_apic(s, &id3v2_extra_meta);
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
@@ -286,19 +282,23 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int
ASFContext *asf = s->priv_data;
char *value = NULL;
int64_t off = avio_tell(s->pb);
+#define LEN 22
- if ((unsigned)len >= (UINT_MAX - 1) / 2)
+ if ((unsigned)len >= (UINT_MAX - LEN) / 2)
return;
if (!asf->export_xmp && !strncmp(key, "xmp", 3))
goto finish;
- value = av_malloc(2 * len + 1);
+ value = av_malloc(2 * len + LEN);
if (!value)
goto finish;
if (type == 0) { // UTF16-LE
avio_get_str16le(s->pb, len, value, 2 * len + 1);
+ } else if (type == -1) { // ASCII
+ avio_read(s->pb, value, len);
+ value[len]=0;
} else if (type == 1) { // byte array
if (!strcmp(key, "WM/Picture")) { // handle cover art
asf_read_picture(s, len);
@@ -310,7 +310,7 @@ static void get_tag(AVFormatContext *s, const char *key, int type, int len, int
goto finish;
} else if (type > 1 && type <= 5) { // boolean or DWORD or QWORD or WORD
uint64_t num = get_value(s->pb, type, type2_size);
- snprintf(value, len, "%"PRIu64, num);
+ snprintf(value, LEN, "%"PRIu64, num);
} else if (type == 6) { // (don't) handle GUID
av_log(s, AV_LOG_DEBUG, "Unsupported GUID value in tag %s.\n", key);
goto finish;
@@ -375,17 +375,13 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
- asf_st = av_mallocz(sizeof(ASFStream));
- if (!asf_st)
- return AVERROR(ENOMEM);
- st->priv_data = asf_st;
- st->start_time = 0;
start_time = asf->hdr.preroll;
- asf_st->stream_language_index = 128; // invalid stream index means no language info
-
if (!(asf->hdr.flags & 0x01)) { // if we aren't streaming...
- st->duration = asf->hdr.play_time /
+ int64_t fsize = avio_size(pb);
+ if (fsize <= 0 || (int64_t)asf->hdr.file_size <= 0 ||
+ FFABS(fsize - (int64_t)asf->hdr.file_size) / (float)FFMIN(fsize, asf->hdr.file_size) < 0.05)
+ st->duration = asf->hdr.play_time /
(10000000 / 1000) - start_time;
}
ff_get_guid(pb, &g);
@@ -413,6 +409,7 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
st->id = avio_rl16(pb) & 0x7f; /* stream id */
// mapping of asf ID to AV stream ID;
asf->asfid2avid[st->id] = s->nb_streams - 1;
+ asf_st = &asf->streams[st->id];
avio_rl32(pb);
@@ -432,13 +429,13 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
st->codec->codec_type = type;
if (type == AVMEDIA_TYPE_AUDIO) {
- int ret = ff_get_wav_header(pb, st->codec, type_specific_size);
+ int ret = ff_get_wav_header(pb, st->codec, type_specific_size, 0);
if (ret < 0)
return ret;
if (is_dvr_ms_audio) {
// codec_id and codec_tag are unreliable in dvr_ms
// files. Set them later by probing stream.
- st->codec->codec_id = AV_CODEC_ID_PROBE;
+ st->request_probe = 1;
st->codec->codec_tag = 0;
}
if (st->codec->codec_id == AV_CODEC_ID_AAC)
@@ -475,9 +472,11 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
tag1 = avio_rl32(pb);
avio_skip(pb, 20);
if (sizeX > 40) {
- st->codec->extradata_size = sizeX - 40;
+ st->codec->extradata_size = ffio_limit(pb, sizeX - 40);
st->codec->extradata = av_mallocz(st->codec->extradata_size +
FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
avio_read(pb, st->codec->extradata, st->codec->extradata_size);
}
@@ -510,6 +509,8 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
}
if (st->codec->codec_id == AV_CODEC_ID_H264)
st->need_parsing = AVSTREAM_PARSE_FULL_ONCE;
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4)
+ st->need_parsing = AVSTREAM_PARSE_FULL_ONCE;
}
pos2 = avio_tell(pb);
avio_skip(pb, size - (pos2 - pos1 + 24));
@@ -546,8 +547,10 @@ static int asf_read_ext_stream_properties(AVFormatContext *s, int64_t size)
stream_ct = avio_rl16(pb); // stream-name-count
payload_ext_ct = avio_rl16(pb); // payload-extension-system-count
- if (stream_num < 128)
+ if (stream_num < 128) {
asf->stream_bitrates[stream_num] = leak_rate;
+ asf->streams[stream_num].payload_ext_ct = 0;
+ }
for (i = 0; i < stream_ct; i++) {
avio_rl16(pb);
@@ -556,10 +559,18 @@ static int asf_read_ext_stream_properties(AVFormatContext *s, int64_t size)
}
for (i = 0; i < payload_ext_ct; i++) {
+ int size;
ff_get_guid(pb, &g);
- avio_skip(pb, 2);
+ size = avio_rl16(pb);
ext_len = avio_rl32(pb);
avio_skip(pb, ext_len);
+ if (stream_num < 128 && i < FF_ARRAY_ELEMS(asf->streams[stream_num].payload)) {
+ ASFPayload *p = &asf->streams[stream_num].payload[i];
+ p->type = g[0];
+ p->size = size;
+ av_log(s, AV_LOG_DEBUG, "Payload extension %x %d\n", g[0], p->size );
+ asf->streams[stream_num].payload_ext_ct ++;
+ }
}
return 0;
@@ -723,12 +734,16 @@ static int asf_read_header(AVFormatContext *s)
ff_get_guid(pb, &g);
if (ff_guidcmp(&g, &ff_asf_header))
- return -1;
+ return AVERROR_INVALIDDATA;
avio_rl64(pb);
avio_rl32(pb);
avio_r8(pb);
avio_r8(pb);
memset(&asf->asfid2avid, -1, sizeof(asf->asfid2avid));
+
+ for (i = 0; i<128; i++)
+ asf->streams[i].stream_language_index = 128; // invalid stream index means no language info
+
for (;;) {
uint64_t gpos = avio_tell(pb);
ff_get_guid(pb, &g);
@@ -745,7 +760,7 @@ static int asf_read_header(AVFormatContext *s)
break;
}
if (gsize < 24)
- return -1;
+ return AVERROR_INVALIDDATA;
if (!ff_guidcmp(&g, &ff_asf_file_header)) {
int ret = asf_read_file_properties(s, gsize);
if (ret < 0)
@@ -776,19 +791,35 @@ static int asf_read_header(AVFormatContext *s)
continue;
} else if (!ff_guidcmp(&g, &ff_asf_marker_header)) {
asf_read_marker(s, gsize);
- } else if (pb->eof_reached) {
- return -1;
+ } else if (avio_feof(pb)) {
+ return AVERROR_EOF;
} else {
if (!s->keylen) {
if (!ff_guidcmp(&g, &ff_asf_content_encryption)) {
+ unsigned int len;
+ int ret;
+ AVPacket pkt;
av_log(s, AV_LOG_WARNING,
"DRM protected stream detected, decoding will likely fail!\n");
+ len= avio_rl32(pb);
+ av_log(s, AV_LOG_DEBUG, "Secret data:\n");
+
+ if ((ret = av_get_packet(pb, &pkt, len)) < 0)
+ return ret;
+ av_hex_dump_log(s, AV_LOG_DEBUG, pkt.data, pkt.size);
+ av_free_packet(&pkt);
+ len= avio_rl32(pb);
+ get_tag(s, "ASF_Protection_Type", -1, len, 32);
+ len= avio_rl32(pb);
+ get_tag(s, "ASF_Key_ID", -1, len, 32);
+ len= avio_rl32(pb);
+ get_tag(s, "ASF_License_URL", -1, len, 32);
} else if (!ff_guidcmp(&g, &ff_asf_ext_content_encryption)) {
av_log(s, AV_LOG_WARNING,
"Ext DRM protected stream detected, decoding will likely fail!\n");
+ av_dict_set(&s->metadata, "encryption", "ASF Extended Content Encryption", 0);
} else if (!ff_guidcmp(&g, &ff_asf_digital_signature)) {
- av_log(s, AV_LOG_WARNING,
- "Digital signature detected, decoding will likely fail!\n");
+ av_log(s, AV_LOG_INFO, "Digital signature detected!\n");
}
}
}
@@ -802,8 +833,8 @@ static int asf_read_header(AVFormatContext *s)
avio_rl64(pb);
avio_r8(pb);
avio_r8(pb);
- if (pb->eof_reached)
- return -1;
+ if (avio_feof(pb))
+ return AVERROR_EOF;
asf->data_offset = avio_tell(pb);
asf->packet_size_left = 0;
@@ -902,20 +933,20 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
* the stream. */
if (pb->error == AVERROR(EAGAIN))
return AVERROR(EAGAIN);
- if (!pb->eof_reached)
+ if (!avio_feof(pb))
av_log(s, AV_LOG_ERROR,
"ff asf bad header %x at:%"PRId64"\n", c, avio_tell(pb));
}
if ((c & 0x8f) == 0x82) {
if (d || e) {
- if (!pb->eof_reached)
+ if (!avio_feof(pb))
av_log(s, AV_LOG_ERROR, "ff asf bad non zero\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
c = avio_r8(pb);
d = avio_r8(pb);
rsize += 3;
- } else if (!pb->eof_reached) {
+ } else if(!avio_feof(pb)) {
avio_seek(pb, -1, SEEK_CUR); // FIXME
}
@@ -931,12 +962,12 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
av_log(s, AV_LOG_ERROR,
"invalid packet_length %"PRIu32" at:%"PRId64"\n",
packet_length, avio_tell(pb));
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (padsize >= packet_length) {
av_log(s, AV_LOG_ERROR,
"invalid padsize %"PRIu32" at:%"PRId64"\n", padsize, avio_tell(pb));
- return -1;
+ return AVERROR_INVALIDDATA;
}
asf->packet_timestamp = avio_rl32(pb);
@@ -956,7 +987,7 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
av_log(s, AV_LOG_ERROR,
"invalid packet header length %d for pktlen %"PRIu32"-%"PRIu32" at %"PRId64"\n",
rsize, packet_length, padsize, avio_tell(pb));
- return -1;
+ return AVERROR_INVALIDDATA;
}
asf->packet_size_left = packet_length - padsize - rsize;
if (packet_length < asf->hdr.min_pktsize)
@@ -974,13 +1005,16 @@ static int asf_get_packet(AVFormatContext *s, AVIOContext *pb)
static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
{
ASFContext *asf = s->priv_data;
+ ASFStream *asfst;
int rsize = 1;
int num = avio_r8(pb);
- int64_t ts0;
+ int i;
+ int64_t ts0, ts1 av_unused;
asf->packet_segments--;
asf->packet_key_frame = num >> 7;
asf->stream_index = asf->asfid2avid[num & 0x7f];
+ asfst = &asf->streams[num & 0x7f];
// sequence should be ignored!
DO_2BITS(asf->packet_property >> 4, asf->packet_seq, 0);
DO_2BITS(asf->packet_property >> 2, asf->packet_frag_offset, 0);
@@ -988,26 +1022,63 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
av_log(asf, AV_LOG_TRACE, "key:%d stream:%d seq:%d offset:%d replic_size:%d\n",
asf->packet_key_frame, asf->stream_index, asf->packet_seq,
asf->packet_frag_offset, asf->packet_replic_size);
+ if (rsize+(int64_t)asf->packet_replic_size > asf->packet_size_left) {
+ av_log(s, AV_LOG_ERROR, "packet_replic_size %d is invalid\n", asf->packet_replic_size);
+ return AVERROR_INVALIDDATA;
+ }
if (asf->packet_replic_size >= 8) {
- asf->packet_obj_size = avio_rl32(pb);
- if (asf->packet_obj_size >= (1 << 24) || asf->packet_obj_size <= 0) {
+ int64_t end = avio_tell(pb) + asf->packet_replic_size;
+ AVRational aspect;
+ asfst->packet_obj_size = avio_rl32(pb);
+ if (asfst->packet_obj_size >= (1 << 24) || asfst->packet_obj_size <= 0) {
av_log(s, AV_LOG_ERROR, "packet_obj_size invalid\n");
- return -1;
+ asfst->packet_obj_size = 0;
+ return AVERROR_INVALIDDATA;
}
asf->packet_frag_timestamp = avio_rl32(pb); // timestamp
- if (asf->packet_replic_size >= 8 + 38 + 4) {
- avio_skip(pb, 10);
- ts0 = avio_rl64(pb);
- avio_skip(pb, 8);
- avio_skip(pb, 12);
- avio_rl32(pb);
- avio_skip(pb, asf->packet_replic_size - 8 - 38 - 4);
- if (ts0 != -1)
- asf->packet_frag_timestamp = ts0 / 10000;
- else
- asf->packet_frag_timestamp = AV_NOPTS_VALUE;
- } else
- avio_skip(pb, asf->packet_replic_size - 8);
+
+ for (i = 0; i < asfst->payload_ext_ct; i++) {
+ ASFPayload *p = &asfst->payload[i];
+ int size = p->size;
+ int64_t payend;
+ if (size == 0xFFFF)
+ size = avio_rl16(pb);
+ payend = avio_tell(pb) + size;
+ if (payend > end) {
+ av_log(s, AV_LOG_ERROR, "too long payload\n");
+ break;
+ }
+ switch (p->type) {
+ case 0x50:
+// duration = avio_rl16(pb);
+ break;
+ case 0x54:
+ aspect.num = avio_r8(pb);
+ aspect.den = avio_r8(pb);
+ if (aspect.num > 0 && aspect.den > 0 && asf->stream_index >= 0) {
+ s->streams[asf->stream_index]->sample_aspect_ratio = aspect;
+ }
+ break;
+ case 0x2A:
+ avio_skip(pb, 8);
+ ts0 = avio_rl64(pb);
+ ts1 = avio_rl64(pb);
+ if (ts0!= -1) asf->packet_frag_timestamp = ts0/10000;
+ else asf->packet_frag_timestamp = AV_NOPTS_VALUE;
+ asf->ts_is_pts = 1;
+ break;
+ case 0x5B:
+ case 0xB7:
+ case 0xCC:
+ case 0xC0:
+ case 0xA0:
+ //unknown
+ break;
+ }
+ avio_seek(pb, payend, SEEK_SET);
+ }
+
+ avio_seek(pb, end, SEEK_SET);
rsize += asf->packet_replic_size; // FIXME - check validity
} else if (asf->packet_replic_size == 1) {
// multipacket - frag_offset is beginning timestamp
@@ -1020,18 +1091,18 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
} else if (asf->packet_replic_size != 0) {
av_log(s, AV_LOG_ERROR, "unexpected packet_replic_size of %d\n",
asf->packet_replic_size);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (asf->packet_flags & 0x01) {
DO_2BITS(asf->packet_segsizetype >> 6, asf->packet_frag_size, 0); // 0 is illegal
if (rsize > asf->packet_size_left) {
av_log(s, AV_LOG_ERROR, "packet_replic_size is invalid\n");
- return -1;
+ return AVERROR_INVALIDDATA;
} else if (asf->packet_frag_size > asf->packet_size_left - rsize) {
if (asf->packet_frag_size > asf->packet_size_left - rsize + asf->packet_padsize) {
av_log(s, AV_LOG_ERROR, "packet_frag_size is invalid (%d-%d)\n",
asf->packet_size_left, rsize);
- return -1;
+ return AVERROR_INVALIDDATA;
} else {
int diff = asf->packet_frag_size - (asf->packet_size_left - rsize);
asf->packet_size_left += diff;
@@ -1039,16 +1110,12 @@ static int asf_read_frame_header(AVFormatContext *s, AVIOContext *pb)
}
}
} else {
- if (rsize > asf->packet_size_left) {
- av_log(s, AV_LOG_ERROR, "packet_replic_size is invalid\n");
- return -1;
- }
asf->packet_frag_size = asf->packet_size_left - rsize;
}
if (asf->packet_replic_size == 1) {
asf->packet_multi_size = asf->packet_frag_size;
if (asf->packet_multi_size > asf->packet_size_left)
- return -1;
+ return AVERROR_INVALIDDATA;
}
asf->packet_size_left -= rsize;
@@ -1070,12 +1137,10 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
ASFStream *asf_st = 0;
for (;;) {
int ret;
-
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
-
if (asf->packet_size_left < FRAME_HEADER_SIZE ||
- asf->packet_segments < 1) {
+ asf->packet_segments < 1 && asf->packet_time_start == 0) {
int ret = asf->packet_size_left + asf->packet_padsize;
assert(ret >= 0);
@@ -1090,13 +1155,13 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
}
if (asf->packet_time_start == 0) {
if (asf_read_frame_header(s, pb) < 0) {
- asf->packet_segments = 0;
+ asf->packet_time_start = asf->packet_segments = 0;
continue;
}
if (asf->stream_index < 0 ||
s->streams[asf->stream_index]->discard >= AVDISCARD_ALL ||
(!asf->packet_key_frame &&
- s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY)) {
+ (s->streams[asf->stream_index]->discard >= AVDISCARD_NONKEY || asf->streams[s->streams[asf->stream_index]->id].skip_to_key))) {
asf->packet_time_start = 0;
/* unhandled packet (should not happen) */
avio_skip(pb, asf->packet_frag_size);
@@ -1106,7 +1171,8 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
asf->packet_frag_size);
continue;
}
- asf->asf_st = s->streams[asf->stream_index]->priv_data;
+ asf->asf_st = &asf->streams[s->streams[asf->stream_index]->id];
+ asf->asf_st->skip_to_key = 0;
}
asf_st = asf->asf_st;
av_assert0(asf_st);
@@ -1125,41 +1191,41 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
// frag_offset is here used as the beginning timestamp
asf->packet_frag_timestamp = asf->packet_time_start;
asf->packet_time_start += asf->packet_time_delta;
- asf->packet_obj_size = asf->packet_frag_size = avio_r8(pb);
+ asf_st->packet_obj_size = asf->packet_frag_size = avio_r8(pb);
asf->packet_size_left--;
asf->packet_multi_size--;
- if (asf->packet_multi_size < asf->packet_obj_size) {
+ if (asf->packet_multi_size < asf_st->packet_obj_size) {
asf->packet_time_start = 0;
avio_skip(pb, asf->packet_multi_size);
asf->packet_size_left -= asf->packet_multi_size;
continue;
}
- asf->packet_multi_size -= asf->packet_obj_size;
- }
- if (asf_st->frag_offset + asf->packet_frag_size <= asf_st->pkt.size &&
- asf_st->frag_offset + asf->packet_frag_size > asf->packet_obj_size) {
- av_log(s, AV_LOG_INFO, "ignoring invalid packet_obj_size (%d %d %d %d)\n",
- asf_st->frag_offset, asf->packet_frag_size,
- asf->packet_obj_size, asf_st->pkt.size);
- asf->packet_obj_size = asf_st->pkt.size;
+ asf->packet_multi_size -= asf_st->packet_obj_size;
}
- if (asf_st->pkt.size != asf->packet_obj_size ||
+ if (asf_st->pkt.size != asf_st->packet_obj_size ||
// FIXME is this condition sufficient?
asf_st->frag_offset + asf->packet_frag_size > asf_st->pkt.size) {
+ int ret;
+
if (asf_st->pkt.data) {
av_log(s, AV_LOG_INFO,
"freeing incomplete packet size %d, new %d\n",
- asf_st->pkt.size, asf->packet_obj_size);
+ asf_st->pkt.size, asf_st->packet_obj_size);
asf_st->frag_offset = 0;
av_free_packet(&asf_st->pkt);
}
/* new packet */
- av_new_packet(&asf_st->pkt, asf->packet_obj_size);
+ if ((ret = av_new_packet(&asf_st->pkt, asf_st->packet_obj_size)) < 0)
+ return ret;
asf_st->seq = asf->packet_seq;
- asf_st->pkt.dts = asf->packet_frag_timestamp - asf->hdr.preroll;
+ if (asf->ts_is_pts) {
+ asf_st->pkt.pts = asf->packet_frag_timestamp - asf->hdr.preroll;
+ } else
+ asf_st->pkt.dts = asf->packet_frag_timestamp - asf->hdr.preroll;
asf_st->pkt.stream_index = asf->stream_index;
asf_st->pkt.pos = asf_st->packet_pos = asf->packet_pos;
+ asf_st->pkt_clean = 0;
if (asf_st->pkt.data && asf_st->palette_changed) {
uint8_t *pal;
@@ -1176,7 +1242,7 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
asf->stream_index, asf->packet_key_frame,
asf_st->pkt.flags & AV_PKT_FLAG_KEY,
s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO,
- asf->packet_obj_size);
+ asf_st->packet_obj_size);
if (s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
asf->packet_key_frame = 1;
if (asf->packet_key_frame)
@@ -1200,6 +1266,11 @@ static int asf_parse_packet(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
continue;
}
+ if (asf->packet_frag_offset != asf_st->frag_offset && !asf_st->pkt_clean) {
+ memset(asf_st->pkt.data + asf_st->frag_offset, 0, asf_st->pkt.size - asf_st->frag_offset);
+ asf_st->pkt_clean = 1;
+ }
+
ret = avio_read(pb, asf_st->pkt.data + asf->packet_frag_offset,
asf->packet_frag_size);
if (ret != asf->packet_frag_size) {
@@ -1317,7 +1388,6 @@ static void asf_reset_header(AVFormatContext *s)
int i;
asf->packet_size_left = 0;
- asf->packet_segments = 0;
asf->packet_flags = 0;
asf->packet_property = 0;
asf->packet_timestamp = 0;
@@ -1331,21 +1401,34 @@ static void asf_reset_header(AVFormatContext *s)
asf->packet_frag_size = 0;
asf->packet_frag_timestamp = 0;
asf->packet_multi_size = 0;
- asf->packet_obj_size = 0;
asf->packet_time_delta = 0;
asf->packet_time_start = 0;
- for (i = 0; i < s->nb_streams; i++) {
- asf_st = s->streams[i]->priv_data;
- if (!asf_st)
- continue;
+ for (i = 0; i < 128; i++) {
+ asf_st = &asf->streams[i];
av_free_packet(&asf_st->pkt);
+ asf_st->packet_obj_size = 0;
asf_st->frag_offset = 0;
asf_st->seq = 0;
}
asf->asf_st = NULL;
}
+static void skip_to_key(AVFormatContext *s)
+{
+ ASFContext *asf = s->priv_data;
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ int j = asf->asfid2avid[i];
+ ASFStream *asf_st = &asf->streams[i];
+ if (j < 0 || s->streams[j]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+
+ asf_st->skip_to_key = 1;
+ }
+}
+
static int asf_read_close(AVFormatContext *s)
{
asf_reset_header(s);
@@ -1356,6 +1439,7 @@ static int asf_read_close(AVFormatContext *s)
static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
int64_t *ppos, int64_t pos_limit)
{
+ ASFContext *asf = s->priv_data;
AVPacket pkt1, *pkt = &pkt1;
ASFStream *asf_st;
int64_t pts;
@@ -1371,11 +1455,13 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
s->packet_size * s->packet_size +
s->internal->data_offset;
*ppos = pos;
- avio_seek(s->pb, pos, SEEK_SET);
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+ ff_read_frame_flush(s);
asf_reset_header(s);
for (;;) {
- if (asf_read_packet(s, pkt) < 0) {
+ if (av_read_frame(s, pkt) < 0) {
av_log(s, AV_LOG_INFO, "asf_read_pts failed\n");
return AV_NOPTS_VALUE;
}
@@ -1386,8 +1472,7 @@ static int64_t asf_read_pts(AVFormatContext *s, int stream_index,
if (pkt->flags & AV_PKT_FLAG_KEY) {
i = pkt->stream_index;
- asf_st = s->streams[i]->priv_data;
- av_assert0(asf_st);
+ asf_st = &asf->streams[s->streams[i]->id];
// assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0);
pos = asf_st->packet_pos;
@@ -1410,17 +1495,20 @@ static int asf_build_simple_index(AVFormatContext *s, int stream_index)
ff_asf_guid g;
ASFContext *asf = s->priv_data;
int64_t current_pos = avio_tell(s->pb);
- int i, ret = 0;
+ int64_t ret;
+
+ if((ret = avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET)) < 0) {
+ return ret;
+ }
- avio_seek(s->pb, asf->data_object_offset + asf->data_object_size, SEEK_SET);
if ((ret = ff_get_guid(s->pb, &g)) < 0)
goto end;
/* the data object can be followed by other top-level objects,
* skip them until the simple index object is reached */
- while (ff_guidcmp(&g, &index_guid)) {
+ while (ff_guidcmp(&g, &ff_asf_simple_index_header)) {
int64_t gsize = avio_rl64(s->pb);
- if (gsize < 24 || s->pb->eof_reached) {
+ if (gsize < 24 || avio_feof(s->pb)) {
goto end;
}
avio_skip(s->pb, gsize - 24);
@@ -1431,6 +1519,7 @@ static int asf_build_simple_index(AVFormatContext *s, int stream_index)
{
int64_t itime, last_pos = -1;
int pct, ict;
+ int i;
int64_t av_unused gsize = avio_rl64(s->pb);
if ((ret = ff_get_guid(s->pb, &g)) < 0)
goto end;
@@ -1454,11 +1543,12 @@ static int asf_build_simple_index(AVFormatContext *s, int stream_index)
last_pos = pos;
}
}
- asf->index_read = ict > 0;
+ asf->index_read = ict > 1;
}
end:
- if (s->pb->eof_reached)
- ret = 0;
+// if (avio_feof(s->pb)) {
+// ret = 0;
+// }
avio_seek(s->pb, current_pos, SEEK_SET);
return ret;
}
@@ -1468,15 +1558,14 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
{
ASFContext *asf = s->priv_data;
AVStream *st = s->streams[stream_index];
- int64_t pos;
- int index, ret = 0;
+ int ret = 0;
if (s->packet_size <= 0)
return -1;
/* Try using the protocol's read_seek if available */
if (s->pb) {
- int ret = avio_seek_time(s->pb, stream_index, pts, flags);
+ int64_t ret = avio_seek_time(s->pb, stream_index, pts, flags);
if (ret >= 0)
asf_reset_header(s);
if (ret != AVERROR(ENOSYS))
@@ -1490,19 +1579,24 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
return 0;
}
- if (!asf->index_read)
+ if (!asf->index_read) {
ret = asf_build_simple_index(s, stream_index);
+ if (ret < 0)
+ asf->index_read = -1;
+ }
- if (!ret && asf->index_read && st->index_entries) {
- index = av_index_search_timestamp(st, pts, flags);
+ if (asf->index_read > 0 && st->index_entries) {
+ int index = av_index_search_timestamp(st, pts, flags);
if (index >= 0) {
/* find the position */
- pos = st->index_entries[index].pos;
+ uint64_t pos = st->index_entries[index].pos;
/* do the seek */
av_log(s, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos);
- avio_seek(s->pb, pos, SEEK_SET);
+ if(avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return -1;
asf_reset_header(s);
+ skip_to_key(s);
return 0;
}
}
@@ -1510,6 +1604,7 @@ static int asf_read_seek(AVFormatContext *s, int stream_index,
if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0)
return -1;
asf_reset_header(s);
+ skip_to_key(s);
return 0;
}
diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c
index 39ba3d9b92..015c731cec 100644
--- a/libavformat/asfenc.c
+++ b/libavformat/asfenc.c
@@ -2,23 +2,24 @@
* ASF muxer
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/dict.h"
#include "libavutil/mathematics.h"
#include "avformat.h"
@@ -27,12 +28,9 @@
#include "riff.h"
#include "asf.h"
-#undef NDEBUG
-#include <assert.h>
-
-
#define ASF_INDEXED_INTERVAL 10000000
-#define ASF_INDEX_BLOCK 600
+#define ASF_INDEX_BLOCK (1<<9)
+#define ASF_PAYLOADS_PER_PACKET 63
#define ASF_PACKET_ERROR_CORRECTION_DATA_SIZE 0x2
#define ASF_PACKET_ERROR_CORRECTION_FLAGS \
@@ -195,36 +193,33 @@ typedef struct ASFContext {
/* packet filling */
unsigned char multi_payloads_present;
int packet_size_left;
- int packet_timestamp_start;
- int packet_timestamp_end;
+ int64_t packet_timestamp_start;
+ int64_t packet_timestamp_end;
unsigned int packet_nb_payloads;
uint8_t packet_buf[PACKET_SIZE];
AVIOContext pb;
/* only for reading */
uint64_t data_offset; ///< beginning of the first data packet
- int64_t last_indexed_pts;
ASFIndex *index_ptr;
- uint32_t nb_index_count;
uint32_t nb_index_memory_alloc;
uint16_t maximum_packet;
+ uint32_t next_packet_number;
+ uint16_t next_packet_count;
+ uint64_t next_packet_offset;
+ int next_start_sec;
+ int end_sec;
} ASFContext;
static const AVCodecTag codec_asf_bmp_tags[] = {
- { AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
{ AV_CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
+ { AV_CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
{ AV_CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
{ AV_CODEC_ID_NONE, 0 },
};
#define PREROLL_TIME 3100
-static void put_guid(AVIOContext *s, const ff_asf_guid *g)
-{
- assert(sizeof(*g) == 16);
- avio_write(s, *g, sizeof(*g));
-}
-
static void put_str16(AVIOContext *s, const char *tag)
{
int len;
@@ -245,7 +240,7 @@ static int64_t put_header(AVIOContext *pb, const ff_asf_guid *g)
int64_t pos;
pos = avio_tell(pb);
- put_guid(pb, g);
+ ff_put_guid(pb, g);
avio_wl64(pb, 24);
return pos;
}
@@ -293,7 +288,7 @@ static int32_t get_send_time(ASFContext *asf, int64_t pres_time, uint64_t *offse
int i;
int32_t send_time = 0;
*offset = asf->data_offset + DATA_HEADER_SIZE;
- for (i = 0; i < asf->nb_index_count; i++) {
+ for (i = 0; i < asf->next_start_sec; i++) {
if (pres_time <= asf->index_ptr[i].send_time)
break;
send_time = asf->index_ptr[i].send_time;
@@ -311,7 +306,7 @@ static int asf_write_markers(AVFormatContext *s)
AVRational scale = {1, 10000000};
int64_t hpos = put_header(pb, &ff_asf_marker_header);
- put_guid(pb, &ff_asf_reserved_4); // ASF spec mandates this reserved value
+ ff_put_guid(pb, &ff_asf_reserved_4);// ASF spec mandates this reserved value
avio_wl32(pb, s->nb_chapters); // markers count
avio_wl16(pb, 0); // ASF spec mandates 0 for this
avio_wl16(pb, 0); // name length 0, no name given
@@ -354,7 +349,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
AVIOContext *pb = s->pb;
AVDictionaryEntry *tags[5];
int header_size, n, extra_size, extra_size2, wav_extra_size, file_time;
- int has_title;
+ int has_title, has_aspect_ratio = 0;
int metadata_count;
AVCodecContext *enc;
int64_t header_offset, cur_pos, hpos;
@@ -380,13 +375,17 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
avpriv_set_pts_info(s->streams[n], 32, 1, 1000); /* 32 bit pts in ms */
bit_rate += enc->bit_rate;
+ if ( enc->codec_type == AVMEDIA_TYPE_VIDEO
+ && enc->sample_aspect_ratio.num > 0
+ && enc->sample_aspect_ratio.den > 0)
+ has_aspect_ratio++;
}
if (asf->is_streamed) {
put_chunk(s, 0x4824, 0, 0xc00); /* start of stream (length will be patched later) */
}
- put_guid(pb, &ff_asf_header);
+ ff_put_guid(pb, &ff_asf_header);
avio_wl64(pb, -1); /* header length, will be patched after */
avio_wl32(pb, 3 + has_title + !!metadata_count + s->nb_streams); /* number of chunks in header */
avio_w8(pb, 1); /* ??? */
@@ -395,7 +394,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
/* file header */
header_offset = avio_tell(pb);
hpos = put_header(pb, &ff_asf_file_header);
- put_guid(pb, &ff_asf_my_guid);
+ ff_put_guid(pb, &ff_asf_my_guid);
avio_wl64(pb, file_size);
file_time = 0;
avio_wl64(pb, unix_to_file_time(file_time));
@@ -406,14 +405,46 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
avio_wl32(pb, (asf->is_streamed || !pb->seekable) ? 3 : 2); /* ??? */
avio_wl32(pb, s->packet_size); /* packet size */
avio_wl32(pb, s->packet_size); /* packet size */
- avio_wl32(pb, bit_rate); /* Nominal data rate in bps */
+ avio_wl32(pb, bit_rate ? bit_rate : -1); /* Maximum data rate in bps */
end_header(pb, hpos);
/* unknown headers */
hpos = put_header(pb, &ff_asf_head1_guid);
- put_guid(pb, &ff_asf_head2_guid);
- avio_wl32(pb, 6);
- avio_wl16(pb, 0);
+ ff_put_guid(pb, &ff_asf_head2_guid);
+ avio_wl16(pb, 6);
+ if (has_aspect_ratio) {
+ int64_t hpos2;
+ avio_wl32(pb, 26 + has_aspect_ratio * 84);
+ hpos2 = put_header(pb, &ff_asf_metadata_header);
+ avio_wl16(pb, 2 * has_aspect_ratio);
+ for (n = 0; n < s->nb_streams; n++) {
+ enc = s->streams[n]->codec;
+ if ( enc->codec_type == AVMEDIA_TYPE_VIDEO
+ && enc->sample_aspect_ratio.num > 0
+ && enc->sample_aspect_ratio.den > 0) {
+ AVRational sar = enc->sample_aspect_ratio;
+ avio_wl16(pb, 0);
+ // the stream number is set like this below
+ avio_wl16(pb, n + 1);
+ avio_wl16(pb, 26); // name_len
+ avio_wl16(pb, 3); // value_type
+ avio_wl32(pb, 4); // value_len
+ avio_put_str16le(pb, "AspectRatioX");
+ avio_wl32(pb, sar.num);
+ avio_wl16(pb, 0);
+ // the stream number is set like this below
+ avio_wl16(pb, n + 1);
+ avio_wl16(pb, 26); // name_len
+ avio_wl16(pb, 3); // value_type
+ avio_wl32(pb, 4); // value_len
+ avio_put_str16le(pb, "AspectRatioY");
+ avio_wl32(pb, sar.den);
+ }
+ }
+ end_header(pb, hpos2);
+ } else {
+ avio_wl32(pb, 0);
+ }
end_header(pb, hpos);
/* title and other infos */
@@ -450,7 +481,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
/* chapters using ASF markers */
if (!asf->is_streamed && s->nb_chapters) {
int ret;
- if (ret = asf_write_markers(s))
+ if ((ret = asf_write_markers(s)) < 0)
return ret;
}
/* stream headers */
@@ -460,7 +491,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
enc = s->streams[n]->codec;
asf->streams[n].num = n + 1;
- asf->streams[n].seq = 0;
+ asf->streams[n].seq = 1;
switch (enc->codec_type) {
case AVMEDIA_TYPE_AUDIO:
@@ -478,11 +509,11 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
hpos = put_header(pb, &ff_asf_stream_header);
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
- put_guid(pb, &ff_asf_audio_stream);
- put_guid(pb, &ff_asf_audio_conceal_spread);
+ ff_put_guid(pb, &ff_asf_audio_stream);
+ ff_put_guid(pb, &ff_asf_audio_conceal_spread);
} else {
- put_guid(pb, &ff_asf_video_stream);
- put_guid(pb, &ff_asf_video_conceal_none);
+ ff_put_guid(pb, &ff_asf_video_stream);
+ ff_put_guid(pb, &ff_asf_video_conceal_none);
}
avio_wl64(pb, 0); /* ??? */
es_pos = avio_tell(pb);
@@ -493,7 +524,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
if (enc->codec_type == AVMEDIA_TYPE_AUDIO) {
/* WAVEFORMATEX header */
- int wavsize = ff_put_wav_header(pb, enc);
+ int wavsize = ff_put_wav_header(pb, enc, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX);
if (wavsize < 0)
return -1;
@@ -521,7 +552,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
avio_wl16(pb, 40 + enc->extradata_size); /* size */
/* BITMAPINFOHEADER header */
- ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1);
+ ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 1, 0);
}
end_header(pb, hpos);
}
@@ -529,7 +560,7 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
/* media comments */
hpos = put_header(pb, &ff_asf_codec_comment_header);
- put_guid(pb, &ff_asf_codec_comment1_header);
+ ff_put_guid(pb, &ff_asf_codec_comment1_header);
avio_wl32(pb, s->nb_streams);
for (n = 0; n < s->nb_streams; n++) {
const AVCodecDescriptor *codec_desc;
@@ -603,9 +634,9 @@ static int asf_write_header1(AVFormatContext *s, int64_t file_size,
/* movie chunk, followed by packets of packet_size */
asf->data_offset = cur_pos;
- put_guid(pb, &ff_asf_data_header);
+ ff_put_guid(pb, &ff_asf_data_header);
avio_wl64(pb, data_chunk_size);
- put_guid(pb, &ff_asf_my_guid);
+ ff_put_guid(pb, &ff_asf_my_guid);
avio_wl64(pb, asf->nb_packets); /* nb packets */
avio_w8(pb, 1); /* ??? */
avio_w8(pb, 1); /* ??? */
@@ -617,12 +648,13 @@ static int asf_write_header(AVFormatContext *s)
ASFContext *asf = s->priv_data;
s->packet_size = PACKET_SIZE;
+ s->max_interleave_delta = 0;
asf->nb_packets = 0;
- asf->last_indexed_pts = 0;
asf->index_ptr = av_malloc(sizeof(ASFIndex) * ASF_INDEX_BLOCK);
+ if (!asf->index_ptr)
+ return AVERROR(ENOMEM);
asf->nb_index_memory_alloc = ASF_INDEX_BLOCK;
- asf->nb_index_count = 0;
asf->maximum_packet = 0;
/* the data-chunk-size has to be 50 (DATA_HEADER_SIZE), which is
@@ -642,6 +674,9 @@ static int asf_write_header(AVFormatContext *s)
ffio_init_context(&asf->pb, asf->packet_buf, s->packet_size, 1,
NULL, NULL, NULL, NULL);
+ if (s->avoid_negative_ts < 0)
+ s->avoid_negative_ts = 1;
+
return 0;
}
@@ -668,7 +703,7 @@ static int put_payload_parsing_info(AVFormatContext *s,
padsize -= PACKET_HEADER_MIN_SIZE;
if (asf->multi_payloads_present)
padsize--;
- assert(padsize >= 0);
+ av_assert0(padsize >= 0);
avio_w8(pb, ASF_PACKET_ERROR_CORRECTION_FLAGS);
for (i = 0; i < ASF_PACKET_ERROR_CORRECTION_DATA_SIZE; i++)
@@ -707,20 +742,19 @@ static void flush_packet(AVFormatContext *s)
ASFContext *asf = s->priv_data;
int packet_hdr_size, packet_filled_size;
- assert(asf->packet_timestamp_end >= asf->packet_timestamp_start);
+ av_assert0(asf->packet_timestamp_end >= asf->packet_timestamp_start);
if (asf->is_streamed)
put_chunk(s, 0x4424, s->packet_size, 0);
packet_hdr_size = put_payload_parsing_info(s,
asf->packet_timestamp_start,
- asf->packet_timestamp_end -
- asf->packet_timestamp_start,
+ asf->packet_timestamp_end - asf->packet_timestamp_start,
asf->packet_nb_payloads,
asf->packet_size_left);
packet_filled_size = PACKET_SIZE - asf->packet_size_left;
- assert(packet_hdr_size <= asf->packet_size_left);
+ av_assert0(packet_hdr_size <= asf->packet_size_left);
memset(asf->packet_buf + packet_filled_size, 0, asf->packet_size_left);
avio_write(s->pb, asf->packet_buf, s->packet_size - packet_hdr_size);
@@ -735,7 +769,7 @@ static void flush_packet(AVFormatContext *s)
}
static void put_payload_header(AVFormatContext *s, ASFStream *stream,
- int presentation_time, int m_obj_size,
+ int64_t presentation_time, int m_obj_size,
int m_obj_offset, int payload_len, int flags)
{
ASFContext *asf = s->priv_data;
@@ -758,7 +792,7 @@ static void put_payload_header(AVFormatContext *s, ASFStream *stream,
avio_w8(pb, ASF_PAYLOAD_REPLICATED_DATA_LENGTH);
avio_wl32(pb, m_obj_size); // Replicated Data - Media Object Size
- avio_wl32(pb, presentation_time); // Replicated Data - Presentation Time
+ avio_wl32(pb, (uint32_t) presentation_time); // Replicated Data - Presentation Time
if (asf->multi_payloads_present) {
avio_wl16(pb, payload_len); // payload length
@@ -766,7 +800,7 @@ static void put_payload_header(AVFormatContext *s, ASFStream *stream,
}
static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
- int timestamp, const uint8_t *buf,
+ int64_t timestamp, const uint8_t *buf,
int m_obj_size, int flags)
{
ASFContext *asf = s->priv_data;
@@ -824,20 +858,65 @@ static void put_frame(AVFormatContext *s, ASFStream *stream, AVStream *avst,
flush_packet(s);
else if (asf->packet_size_left <= (PAYLOAD_HEADER_SIZE_MULTIPLE_PAYLOADS + PACKET_HEADER_MIN_SIZE + 1))
flush_packet(s);
+ else if (asf->packet_nb_payloads == ASF_PAYLOADS_PER_PACKET)
+ flush_packet(s);
}
stream->seq++;
}
+static int update_index(AVFormatContext *s, int start_sec,
+ uint32_t packet_number, uint16_t packet_count,
+ uint64_t packet_offset)
+{
+ ASFContext *asf = s->priv_data;
+
+ if (start_sec > asf->next_start_sec) {
+ int i;
+
+ if (!asf->next_start_sec) {
+ asf->next_packet_number = packet_number;
+ asf->next_packet_count = packet_count;
+ asf->next_packet_offset = packet_offset;
+ }
+
+ if (start_sec > asf->nb_index_memory_alloc) {
+ int err;
+ asf->nb_index_memory_alloc = (start_sec + ASF_INDEX_BLOCK) & ~(ASF_INDEX_BLOCK - 1);
+ if ((err = av_reallocp_array(&asf->index_ptr,
+ asf->nb_index_memory_alloc,
+ sizeof(*asf->index_ptr))) < 0) {
+ asf->nb_index_memory_alloc = 0;
+ return err;
+ }
+ }
+ for (i = asf->next_start_sec; i < start_sec; i++) {
+ asf->index_ptr[i].packet_number = asf->next_packet_number;
+ asf->index_ptr[i].packet_count = asf->next_packet_count;
+ asf->index_ptr[i].send_time = asf->next_start_sec * INT64_C(10000000);
+ asf->index_ptr[i].offset = asf->next_packet_offset;
+
+ }
+ }
+ asf->maximum_packet = FFMAX(asf->maximum_packet, packet_count);
+ asf->next_packet_number = packet_number;
+ asf->next_packet_count = packet_count;
+ asf->next_packet_offset = packet_offset;
+ asf->next_start_sec = start_sec;
+
+ return 0;
+}
+
static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASFContext *asf = s->priv_data;
AVIOContext *pb = s->pb;
ASFStream *stream;
- int64_t duration;
AVCodecContext *codec;
- int64_t packet_st, pts;
- int start_sec, i;
+ uint32_t packet_number;
+ int64_t pts;
+ int start_sec;
int flags = pkt->flags;
+ int ret;
uint64_t offset = avio_tell(pb);
codec = s->streams[pkt->stream_index]->codec;
@@ -847,53 +926,38 @@ static int asf_write_packet(AVFormatContext *s, AVPacket *pkt)
flags &= ~AV_PKT_FLAG_KEY;
pts = (pkt->pts != AV_NOPTS_VALUE) ? pkt->pts : pkt->dts;
- assert(pts != AV_NOPTS_VALUE);
- duration = pts * 10000;
- asf->duration = FFMAX(asf->duration, duration + pkt->duration * 10000);
+ av_assert0(pts != AV_NOPTS_VALUE);
+ pts *= 10000;
+ asf->duration = FFMAX(asf->duration, pts + pkt->duration * 10000);
- packet_st = asf->nb_packets;
+ packet_number = asf->nb_packets;
put_frame(s, stream, s->streams[pkt->stream_index],
pkt->dts, pkt->data, pkt->size, flags);
+ start_sec = (int)((PREROLL_TIME * 10000 + pts + ASF_INDEXED_INTERVAL - 1)
+ / ASF_INDEXED_INTERVAL);
+
/* check index */
if ((!asf->is_streamed) && (flags & AV_PKT_FLAG_KEY)) {
- start_sec = (int)(duration / INT64_C(10000000));
- if (start_sec != (int)(asf->last_indexed_pts / INT64_C(10000000))) {
- for (i = asf->nb_index_count; i < start_sec; i++) {
- if (i >= asf->nb_index_memory_alloc) {
- int err;
- asf->nb_index_memory_alloc += ASF_INDEX_BLOCK;
- if ((err = av_reallocp_array(&asf->index_ptr,
- asf->nb_index_memory_alloc,
- sizeof(*asf->index_ptr))) < 0) {
- asf->nb_index_memory_alloc = 0;
- return err;
- }
- }
- // store
- asf->index_ptr[i].packet_number = (uint32_t)packet_st;
- asf->index_ptr[i].packet_count = (uint16_t)(asf->nb_packets - packet_st);
- asf->index_ptr[i].send_time = start_sec * INT64_C(10000000);
- asf->index_ptr[i].offset = offset;
- asf->maximum_packet = FFMAX(asf->maximum_packet,
- (uint16_t)(asf->nb_packets - packet_st));
- }
- asf->nb_index_count = start_sec;
- asf->last_indexed_pts = duration;
- }
+ uint16_t packet_count = asf->nb_packets - packet_number;
+ ret = update_index(s, start_sec, packet_number, packet_count, offset);
+ if (ret < 0)
+ return ret;
}
+ asf->end_sec = start_sec;
+
return 0;
}
-static int asf_write_index(AVFormatContext *s, ASFIndex *index,
+static int asf_write_index(AVFormatContext *s, const ASFIndex *index,
uint16_t max, uint32_t count)
{
AVIOContext *pb = s->pb;
int i;
- put_guid(pb, &ff_asf_simple_index_header);
+ ff_put_guid(pb, &ff_asf_simple_index_header);
avio_wl64(pb, 24 + 16 + 8 + 4 + 4 + (4 + 2) * count);
- put_guid(pb, &ff_asf_my_guid);
+ ff_put_guid(pb, &ff_asf_my_guid);
avio_wl64(pb, ASF_INDEXED_INTERVAL);
avio_wl32(pb, max);
avio_wl32(pb, count);
@@ -909,6 +973,7 @@ static int asf_write_trailer(AVFormatContext *s)
{
ASFContext *asf = s->priv_data;
int64_t file_size, data_size;
+ int ret;
/* flush the current packet */
if (asf->pb.buf_ptr > asf->pb.buffer)
@@ -916,8 +981,11 @@ static int asf_write_trailer(AVFormatContext *s)
/* write index */
data_size = avio_tell(s->pb);
- if ((!asf->is_streamed) && (asf->nb_index_count != 0))
- asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->nb_index_count);
+ if (!asf->is_streamed && asf->next_start_sec) {
+ if ((ret = update_index(s, asf->end_sec + 1, 0, 0, 0)) < 0)
+ return ret;
+ asf_write_index(s, asf->index_ptr, asf->maximum_packet, asf->next_start_sec);
+ }
avio_flush(s->pb);
if (asf->is_streamed || !s->pb->seekable) {
@@ -929,7 +997,7 @@ static int asf_write_trailer(AVFormatContext *s)
asf_write_header1(s, file_size, data_size - asf->data_offset);
}
- av_free(asf->index_ptr);
+ av_freep(&asf->index_ptr);
return 0;
}
@@ -940,7 +1008,7 @@ AVOutputFormat ff_asf_muxer = {
.mime_type = "video/x-ms-asf",
.extensions = "asf,wmv,wma",
.priv_data_size = sizeof(ASFContext),
- .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_MP2,
+ .audio_codec = AV_CODEC_ID_WMAV2,
.video_codec = AV_CODEC_ID_MSMPEG4V3,
.write_header = asf_write_header,
.write_packet = asf_write_packet,
@@ -959,7 +1027,7 @@ AVOutputFormat ff_asf_stream_muxer = {
.mime_type = "video/x-ms-asf",
.extensions = "asf,wmv,wma",
.priv_data_size = sizeof(ASFContext),
- .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_MP2,
+ .audio_codec = AV_CODEC_ID_WMAV2,
.video_codec = AV_CODEC_ID_MSMPEG4V3,
.write_header = asf_write_stream_header,
.write_packet = asf_write_packet,
diff --git a/libavformat/assdec.c b/libavformat/assdec.c
index f9f1bdfb9a..c62e76f0dd 100644
--- a/libavformat/assdec.c
+++ b/libavformat/assdec.c
@@ -1,224 +1,187 @@
/*
* SSA/ASS demuxer
* Copyright (c) 2008 Michael Niedermayer
+ * Copyright (c) 2014 ClĂ©ment BÅ“sch
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
-#include "libavutil/mathematics.h"
-
#include "avformat.h"
#include "internal.h"
-
-#define MAX_LINESIZE 2000
+#include "subtitles.h"
+#include "libavcodec/internal.h"
+#include "libavutil/bprint.h"
typedef struct ASSContext {
- uint8_t *event_buffer;
- uint8_t **event;
- unsigned int event_count;
- unsigned int event_index;
+ FFDemuxSubtitlesQueue q;
+ unsigned readorder;
} ASSContext;
-static int probe(AVProbeData *p)
+static int ass_probe(AVProbeData *p)
{
- const char *header = "[Script Info]";
+ char buf[13];
+ FFTextReader tr;
+ ff_text_init_buf(&tr, p->buf, p->buf_size);
- if (!memcmp(p->buf, header, strlen(header)) ||
- !memcmp(p->buf + 3, header, strlen(header)))
+ ff_text_read(&tr, buf, sizeof(buf));
+
+ if (!memcmp(buf, "[Script Info]", 13))
return AVPROBE_SCORE_MAX;
return 0;
}
-static int read_close(AVFormatContext *s)
+static int ass_read_close(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
-
- av_freep(&ass->event_buffer);
- av_freep(&ass->event);
-
+ ff_subtitles_queue_clean(&ass->q);
return 0;
}
-static int64_t get_pts(const uint8_t *p)
+static int read_dialogue(ASSContext *ass, AVBPrint *dst, const uint8_t *p,
+ int64_t *start, int *duration)
{
- int hour, min, sec, hsec;
-
- if (sscanf(p, "%*[^,],%d:%d:%d%*c%d", &hour, &min, &sec, &hsec) != 4)
- return AV_NOPTS_VALUE;
-
- av_log(NULL, AV_LOG_TRACE, "%d %d %d %d [%s]\n", hour, min, sec, hsec, p);
-
- min += 60 * hour;
- sec += 60 * min;
-
- return sec * 100 + hsec;
+ int pos = 0;
+ int64_t end;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+
+ if (sscanf(p, "Dialogue: %*[^,],%d:%d:%d%*c%d,%d:%d:%d%*c%d,%n",
+ &hh1, &mm1, &ss1, &ms1,
+ &hh2, &mm2, &ss2, &ms2, &pos) >= 8 && pos > 0) {
+
+ /* This is not part of the sscanf itself in order to handle an actual
+ * number (which would be the Layer) or the form "Marked=N" (which is
+ * the old SSA field, now replaced by Layer, and will lead to Layer
+ * being 0 here). */
+ const int layer = atoi(p + 10);
+
+ end = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
+ *start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
+ *duration = end - *start;
+
+ av_bprint_clear(dst);
+ av_bprintf(dst, "%u,%d,%s", ass->readorder++, layer, p + pos);
+
+ /* right strip the buffer */
+ while (dst->len > 0 &&
+ dst->str[dst->len - 1] == '\r' ||
+ dst->str[dst->len - 1] == '\n')
+ dst->str[--dst->len] = 0;
+ return 0;
+ }
+ return -1;
}
-static int event_cmp(const void *_a, const void *_b)
+static int64_t get_line(AVBPrint *buf, FFTextReader *tr)
{
- const uint8_t *const *a = _a, *const *b = _b;
- return get_pts(*a) - get_pts(*b);
+ int64_t pos = ff_text_pos(tr);
+
+ av_bprint_clear(buf);
+ for (;;) {
+ char c = ff_text_r8(tr);
+ if (!c)
+ break;
+ av_bprint_chars(buf, c, 1);
+ if (c == '\n')
+ break;
+ }
+ return pos;
}
-static int read_header(AVFormatContext *s)
+static int ass_read_header(AVFormatContext *s)
{
- int i, len, header_remaining;
ASSContext *ass = s->priv_data;
- AVIOContext *pb = s->pb;
+ AVBPrint header, line, rline;
+ int res = 0;
AVStream *st;
- int allocated[2] = { 0 };
- uint8_t *p, **dst[2] = { 0 };
- int pos[2] = { 0 };
+ FFTextReader tr;
+ ff_text_init_avio(s, &tr, s->pb);
st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 64, 1, 100);
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- st->codec->codec_id = AV_CODEC_ID_SSA;
+ st->codec->codec_id = AV_CODEC_ID_ASS;
- header_remaining = INT_MAX;
- dst[0] = &st->codec->extradata;
- dst[1] = &ass->event_buffer;
- while (!pb->eof_reached) {
- uint8_t line[MAX_LINESIZE];
+ av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&rline, 0, AV_BPRINT_SIZE_UNLIMITED);
- len = ff_get_line(pb, line, sizeof(line));
+ for (;;) {
+ int64_t pos = get_line(&line, &tr);
+ int64_t ts_start = AV_NOPTS_VALUE;
+ int duration = -1;
+ AVPacket *sub;
- if (!memcmp(line, "[Events]", 8))
- header_remaining = 2;
- else if (line[0] == '[')
- header_remaining = INT_MAX;
+ if (!line.str[0]) // EOF
+ break;
- i = header_remaining == 0;
-
- if (i && get_pts(line) == AV_NOPTS_VALUE)
+ if (read_dialogue(ass, &rline, line.str, &ts_start, &duration) < 0) {
+ av_bprintf(&header, "%s", line.str);
continue;
-
- p = av_fast_realloc(*(dst[i]), &allocated[i], pos[i] + MAX_LINESIZE);
- if (!p)
- goto fail;
- *(dst[i]) = p;
- memcpy(p + pos[i], line, len + 1);
- pos[i] += len;
- if (i)
- ass->event_count++;
- else
- header_remaining--;
- }
- st->codec->extradata_size = pos[0];
-
- if (ass->event_count >= UINT_MAX / sizeof(*ass->event))
- goto fail;
-
- ass->event = av_malloc(ass->event_count * sizeof(*ass->event));
- p = ass->event_buffer;
- for (i = 0; i < ass->event_count; i++) {
- ass->event[i] = p;
- while (*p && *p != '\n')
- p++;
- p++;
+ }
+ sub = ff_subtitles_queue_insert(&ass->q, rline.str, rline.len, 0);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ sub->pos = pos;
+ sub->pts = ts_start;
+ sub->duration = duration;
}
- qsort(ass->event, ass->event_count, sizeof(*ass->event), event_cmp);
-
- return 0;
+ res = avpriv_bprint_to_extradata(st->codec, &header);
+ if (res < 0)
+ goto end;
-fail:
- read_close(s);
+ ff_subtitles_queue_finalize(&ass->q);
- return -1;
+end:
+ av_bprint_finalize(&header, NULL);
+ av_bprint_finalize(&line, NULL);
+ av_bprint_finalize(&rline, NULL);
+ return res;
}
-static int read_packet(AVFormatContext *s, AVPacket *pkt)
+static int ass_read_packet(AVFormatContext *s, AVPacket *pkt)
{
ASSContext *ass = s->priv_data;
- uint8_t *p, *end;
- int ret;
-
- if (ass->event_index >= ass->event_count)
- return AVERROR(EIO);
-
- p = ass->event[ass->event_index];
-
- end = strchr(p, '\n');
- ret = av_new_packet(pkt, end ? end - p + 1 : strlen(p));
- if (ret < 0)
- return ret;
- pkt->flags |= AV_PKT_FLAG_KEY;
- pkt->pos = p - ass->event_buffer + s->streams[0]->codec->extradata_size;
- pkt->pts = pkt->dts = get_pts(p);
- memcpy(pkt->data, p, pkt->size);
-
- ass->event_index++;
-
- return 0;
+ return ff_subtitles_queue_read_packet(&ass->q, pkt);
}
-static int read_seek2(AVFormatContext *s, int stream_index,
- int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+static int ass_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
ASSContext *ass = s->priv_data;
-
- if (flags & AVSEEK_FLAG_BYTE) {
- return AVERROR(ENOSYS);
- } else if (flags & AVSEEK_FLAG_FRAME) {
- if (ts < 0 || ts >= ass->event_count)
- return AVERROR(ERANGE);
- ass->event_index = ts;
- } else {
- int i, idx = -1;
- int64_t min_ts_diff = INT64_MAX;
- if (stream_index == -1) {
- AVRational time_base = s->streams[0]->time_base;
- ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
- min_ts = av_rescale_rnd(min_ts, time_base.den,
- time_base.num * (int64_t) AV_TIME_BASE,
- AV_ROUND_UP);
- max_ts = av_rescale_rnd(max_ts, time_base.den,
- time_base.num * (int64_t) AV_TIME_BASE,
- AV_ROUND_DOWN);
- }
- /* TODO: ass->event[] is sorted by pts so we could do a binary search */
- for (i = 0; i < ass->event_count; i++) {
- int64_t pts = get_pts(ass->event[i]);
- int64_t ts_diff = FFABS(pts - ts);
- if (pts >= min_ts && pts <= max_ts && ts_diff < min_ts_diff) {
- min_ts_diff = ts_diff;
- idx = i;
- }
- }
- if (idx < 0)
- return AVERROR(ERANGE);
- ass->event_index = idx;
- }
- return 0;
+ return ff_subtitles_queue_seek(&ass->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
}
AVInputFormat ff_ass_demuxer = {
.name = "ass",
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
.priv_data_size = sizeof(ASSContext),
- .read_probe = probe,
- .read_header = read_header,
- .read_packet = read_packet,
- .read_close = read_close,
- .read_seek2 = read_seek2,
+ .read_probe = ass_probe,
+ .read_header = ass_read_header,
+ .read_packet = ass_read_packet,
+ .read_close = ass_read_close,
+ .read_seek2 = ass_read_seek,
};
diff --git a/libavformat/assenc.c b/libavformat/assenc.c
index 751485dfb5..52226168c2 100644
--- a/libavformat/assenc.c
+++ b/libavformat/assenc.c
@@ -2,76 +2,238 @@
* SSA/ASS muxer
* Copyright (c) 2008 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avformat.h"
+#include "internal.h"
-typedef struct ASSContext{
- unsigned int extra_index;
-}ASSContext;
+#include "libavutil/opt.h"
+
+typedef struct DialogueLine {
+ int readorder;
+ char *line;
+ struct DialogueLine *prev, *next;
+} DialogueLine;
+
+typedef struct ASSContext {
+ const AVClass *class;
+ int write_ts; // 0: ssa (timing in payload), 1: ass (matroska like)
+ int expected_readorder;
+ DialogueLine *dialogue_cache;
+ DialogueLine *last_added_dialogue;
+ int cache_size;
+ int ssa_mode;
+ int ignore_readorder;
+ uint8_t *trailer;
+ size_t trailer_size;
+} ASSContext;
static int write_header(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
- AVCodecContext *avctx= s->streams[0]->codec;
- uint8_t *last= NULL;
+ AVCodecContext *avctx = s->streams[0]->codec;
- if(s->nb_streams != 1 || avctx->codec_id != AV_CODEC_ID_SSA){
+ if (s->nb_streams != 1 || (avctx->codec_id != AV_CODEC_ID_SSA &&
+ avctx->codec_id != AV_CODEC_ID_ASS)) {
av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n");
- return -1;
+ return AVERROR(EINVAL);
}
+ ass->write_ts = avctx->codec_id == AV_CODEC_ID_ASS;
+ avpriv_set_pts_info(s->streams[0], 64, 1, 100);
+ if (avctx->extradata_size > 0) {
+ size_t header_size = avctx->extradata_size;
+ uint8_t *trailer = strstr(avctx->extradata, "\n[Events]");
- while(ass->extra_index < avctx->extradata_size){
- uint8_t *p = avctx->extradata + ass->extra_index;
- uint8_t *end= strchr(p, '\n');
- if(!end) end= avctx->extradata + avctx->extradata_size;
- else end++;
+ if (trailer)
+ trailer = strstr(trailer, "Format:");
+ if (trailer)
+ trailer = strstr(trailer, "\n");
- avio_write(s->pb, p, end-p);
- ass->extra_index += end-p;
+ if (trailer++) {
+ header_size = (trailer - avctx->extradata);
+ ass->trailer_size = avctx->extradata_size - header_size;
+ if (ass->trailer_size)
+ ass->trailer = trailer;
+ }
- if(last && !memcmp(last, "[Events]", 8))
- break;
- last=p;
+ avio_write(s->pb, avctx->extradata, header_size);
+ if (avctx->extradata[header_size - 1] != '\n')
+ avio_write(s->pb, "\r\n", 2);
+ ass->ssa_mode = !strstr(avctx->extradata, "\n[V4+ Styles]");
+ if (!strstr(avctx->extradata, "\n[Events]"))
+ avio_printf(s->pb, "[Events]\r\nFormat: %s, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n",
+ ass->ssa_mode ? "Marked" : "Layer");
}
-
avio_flush(s->pb);
return 0;
}
+static void purge_dialogues(AVFormatContext *s, int force)
+{
+ int n = 0;
+ ASSContext *ass = s->priv_data;
+ DialogueLine *dialogue = ass->dialogue_cache;
+
+ while (dialogue && (dialogue->readorder == ass->expected_readorder || force)) {
+ DialogueLine *next = dialogue->next;
+ if (dialogue->readorder != ass->expected_readorder) {
+ av_log(s, AV_LOG_WARNING, "ReadOrder gap found between %d and %d\n",
+ ass->expected_readorder, dialogue->readorder);
+ ass->expected_readorder = dialogue->readorder;
+ }
+ avio_printf(s->pb, "Dialogue: %s\r\n", dialogue->line);
+ if (dialogue == ass->last_added_dialogue)
+ ass->last_added_dialogue = next;
+ av_freep(&dialogue->line);
+ av_free(dialogue);
+ if (next)
+ next->prev = NULL;
+ dialogue = ass->dialogue_cache = next;
+ ass->expected_readorder++;
+ n++;
+ }
+ ass->cache_size -= n;
+ if (n > 1)
+ av_log(s, AV_LOG_DEBUG, "wrote %d ASS lines, cached dialogues: %d, waiting for event id %d\n",
+ n, ass->cache_size, ass->expected_readorder);
+}
+
+static void insert_dialogue(ASSContext *ass, DialogueLine *dialogue)
+{
+ DialogueLine *cur, *next = NULL, *prev = NULL;
+
+ /* from the last added to the end of the list */
+ if (ass->last_added_dialogue) {
+ for (cur = ass->last_added_dialogue; cur; cur = cur->next) {
+ if (cur->readorder > dialogue->readorder)
+ break;
+ prev = cur;
+ next = cur->next;
+ }
+ }
+
+ /* from the beginning to the last one added */
+ if (!prev) {
+ next = ass->dialogue_cache;
+ for (cur = next; cur != ass->last_added_dialogue; cur = cur->next) {
+ if (cur->readorder > dialogue->readorder)
+ break;
+ prev = cur;
+ next = cur->next;
+ }
+ }
+
+ if (prev) {
+ prev->next = dialogue;
+ dialogue->prev = prev;
+ } else {
+ dialogue->prev = ass->dialogue_cache;
+ ass->dialogue_cache = dialogue;
+ }
+ if (next) {
+ next->prev = dialogue;
+ dialogue->next = next;
+ }
+ ass->cache_size++;
+ ass->last_added_dialogue = dialogue;
+}
+
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
- avio_write(s->pb, pkt->data, pkt->size);
+ ASSContext *ass = s->priv_data;
+
+ if (ass->write_ts) {
+ long int layer;
+ char *p = pkt->data;
+ int64_t start = pkt->pts;
+ int64_t end = start + pkt->duration;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+ DialogueLine *dialogue = av_mallocz(sizeof(*dialogue));
+
+ if (!dialogue)
+ return AVERROR(ENOMEM);
+
+ dialogue->readorder = strtol(p, &p, 10);
+ if (dialogue->readorder < ass->expected_readorder)
+ av_log(s, AV_LOG_WARNING, "Unexpected ReadOrder %d\n",
+ dialogue->readorder);
+ if (*p == ',')
+ p++;
+
+ if (ass->ssa_mode && !strncmp(p, "Marked=", 7))
+ p += 7;
+
+ layer = strtol(p, &p, 10);
+ if (*p == ',')
+ p++;
+ hh1 = (int)(start / 360000); mm1 = (int)(start / 6000) % 60;
+ hh2 = (int)(end / 360000); mm2 = (int)(end / 6000) % 60;
+ ss1 = (int)(start / 100) % 60; ms1 = (int)(start % 100);
+ ss2 = (int)(end / 100) % 60; ms2 = (int)(end % 100);
+ if (hh1 > 9) hh1 = 9, mm1 = 59, ss1 = 59, ms1 = 99;
+ if (hh2 > 9) hh2 = 9, mm2 = 59, ss2 = 59, ms2 = 99;
+
+ dialogue->line = av_asprintf("%s%ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s",
+ ass->ssa_mode ? "Marked=" : "",
+ layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p);
+ if (!dialogue->line) {
+ av_free(dialogue);
+ return AVERROR(ENOMEM);
+ }
+ insert_dialogue(ass, dialogue);
+ purge_dialogues(s, ass->ignore_readorder);
+ } else {
+ avio_write(s->pb, pkt->data, pkt->size);
+ }
+
return 0;
}
static int write_trailer(AVFormatContext *s)
{
ASSContext *ass = s->priv_data;
- AVCodecContext *avctx= s->streams[0]->codec;
- avio_write(s->pb, avctx->extradata + ass->extra_index,
- avctx->extradata_size - ass->extra_index);
+ purge_dialogues(s, 1);
+
+ if (ass->trailer) {
+ avio_write(s->pb, ass->trailer, ass->trailer_size);
+ }
return 0;
}
+#define OFFSET(x) offsetof(ASSContext, x)
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "ignore_readorder", "write events immediately, even if they're out-of-order", OFFSET(ignore_readorder), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
+ { NULL },
+};
+
+static const AVClass ass_class = {
+ .class_name = "ass muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_ass_muxer = {
.name = "ass",
.long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"),
@@ -82,5 +244,6 @@ AVOutputFormat ff_ass_muxer = {
.write_header = write_header,
.write_packet = write_packet,
.write_trailer = write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_NOTIMESTAMPS,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_NOTIMESTAMPS | AVFMT_TS_NONSTRICT,
+ .priv_class = &ass_class,
};
diff --git a/libavformat/ast.c b/libavformat/ast.c
new file mode 100644
index 0000000000..9de74aae69
--- /dev/null
+++ b/libavformat/ast.c
@@ -0,0 +1,29 @@
+/*
+ * AST common code
+ * Copyright (c) 2012 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+const AVCodecTag ff_codec_ast_tags[] = {
+ { AV_CODEC_ID_ADPCM_AFC, 0 },
+ { AV_CODEC_ID_PCM_S16BE_PLANAR, 1 },
+ { AV_CODEC_ID_NONE, 0 },
+};
diff --git a/libavformat/ast.h b/libavformat/ast.h
new file mode 100644
index 0000000000..4a399ea410
--- /dev/null
+++ b/libavformat/ast.h
@@ -0,0 +1,30 @@
+/*
+ * AST common code
+ * Copyright (c) 2012 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_AST_H
+#define AVFORMAT_AST_H
+
+#include "avformat.h"
+#include "internal.h"
+
+extern const AVCodecTag ff_codec_ast_tags[];
+
+#endif /* AVFORMAT_AST_H */
diff --git a/libavformat/astdec.c b/libavformat/astdec.c
new file mode 100644
index 0000000000..92c208d044
--- /dev/null
+++ b/libavformat/astdec.c
@@ -0,0 +1,122 @@
+/*
+ * AST demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "ast.h"
+
+static int ast_probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) != MKTAG('S','T','R','M'))
+ return 0;
+
+ if (!AV_RB16(p->buf + 10) ||
+ !AV_RB16(p->buf + 12) || AV_RB16(p->buf + 12) > 256 ||
+ !AV_RB32(p->buf + 16) || AV_RB32(p->buf + 16) > 8*48000)
+ return AVPROBE_SCORE_MAX / 8;
+
+ return AVPROBE_SCORE_MAX / 3 * 2;
+}
+
+static int ast_read_header(AVFormatContext *s)
+{
+ int depth;
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(s->pb, 8);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = ff_codec_get_id(ff_codec_ast_tags, avio_rb16(s->pb));
+
+ depth = avio_rb16(s->pb);
+ if (depth != 16) {
+ avpriv_request_sample(s, "depth %d", depth);
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->channels = avio_rb16(s->pb);
+ if (!st->codec->channels)
+ return AVERROR_INVALIDDATA;
+
+ if (st->codec->channels == 2)
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ else if (st->codec->channels == 4)
+ st->codec->channel_layout = AV_CH_LAYOUT_4POINT0;
+
+ avio_skip(s->pb, 2);
+ st->codec->sample_rate = avio_rb32(s->pb);
+ if (st->codec->sample_rate <= 0)
+ return AVERROR_INVALIDDATA;
+ st->start_time = 0;
+ st->duration = avio_rb32(s->pb);
+ avio_skip(s->pb, 40);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ return 0;
+}
+
+static int ast_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ uint32_t type, size;
+ int64_t pos;
+ int ret;
+
+ if (avio_feof(s->pb))
+ return AVERROR_EOF;
+
+ pos = avio_tell(s->pb);
+ type = avio_rl32(s->pb);
+ size = avio_rb32(s->pb);
+ if (size > INT_MAX / s->streams[0]->codec->channels)
+ return AVERROR_INVALIDDATA;
+
+ size *= s->streams[0]->codec->channels;
+ if ((ret = avio_skip(s->pb, 24)) < 0) // padding
+ return ret;
+
+ if (type == MKTAG('B','L','C','K')) {
+ ret = av_get_packet(s->pb, pkt, size);
+ pkt->stream_index = 0;
+ pkt->pos = pos;
+ } else {
+ av_log(s, AV_LOG_ERROR, "unknown chunk %x\n", type);
+ avio_skip(s->pb, size);
+ ret = AVERROR_INVALIDDATA;
+ }
+
+ return ret;
+}
+
+AVInputFormat ff_ast_demuxer = {
+ .name = "ast",
+ .long_name = NULL_IF_CONFIG_SMALL("AST (Audio Stream)"),
+ .read_probe = ast_probe,
+ .read_header = ast_read_header,
+ .read_packet = ast_read_packet,
+ .extensions = "ast",
+ .flags = AVFMT_GENERIC_INDEX,
+ .codec_tag = (const AVCodecTag* const []){ff_codec_ast_tags, 0},
+};
diff --git a/libavformat/astenc.c b/libavformat/astenc.c
new file mode 100644
index 0000000000..cf7a12c95d
--- /dev/null
+++ b/libavformat/astenc.c
@@ -0,0 +1,214 @@
+/*
+ * AST muxer
+ * Copyright (c) 2012 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "ast.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+
+typedef struct ASTMuxContext {
+ AVClass *class;
+ int64_t size;
+ int64_t samples;
+ int64_t loopstart;
+ int64_t loopend;
+ int fbs;
+} ASTMuxContext;
+
+#define CHECK_LOOP(type) \
+ if (ast->loop ## type > 0) { \
+ ast->loop ## type = av_rescale_rnd(ast->loop ## type, enc->sample_rate, 1000, AV_ROUND_DOWN); \
+ if (ast->loop ## type < 0 || ast->loop ## type > UINT_MAX) { \
+ av_log(s, AV_LOG_ERROR, "Invalid loop" #type " value\n"); \
+ return AVERROR(EINVAL); \
+ } \
+ }
+
+static int ast_write_header(AVFormatContext *s)
+{
+ ASTMuxContext *ast = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *enc;
+ unsigned int codec_tag;
+
+ if (s->nb_streams == 1) {
+ enc = s->streams[0]->codec;
+ } else {
+ av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (enc->codec_id == AV_CODEC_ID_ADPCM_AFC) {
+ av_log(s, AV_LOG_ERROR, "muxing ADPCM AFC is not implemented\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ codec_tag = ff_codec_get_tag(ff_codec_ast_tags, enc->codec_id);
+ if (!codec_tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (ast->loopend > 0 && ast->loopstart >= ast->loopend) {
+ av_log(s, AV_LOG_ERROR, "loopend can't be less or equal to loopstart\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* Convert milliseconds to samples */
+ CHECK_LOOP(start)
+ CHECK_LOOP(end)
+
+ ffio_wfourcc(pb, "STRM");
+
+ ast->size = avio_tell(pb);
+ avio_wb32(pb, 0); /* File size minus header */
+ avio_wb16(pb, codec_tag);
+ avio_wb16(pb, 16); /* Bit depth */
+ avio_wb16(pb, enc->channels);
+ avio_wb16(pb, 0); /* Loop flag */
+ avio_wb32(pb, enc->sample_rate);
+
+ ast->samples = avio_tell(pb);
+ avio_wb32(pb, 0); /* Number of samples */
+ avio_wb32(pb, 0); /* Loopstart */
+ avio_wb32(pb, 0); /* Loopend */
+ avio_wb32(pb, 0); /* Size of first block */
+
+ /* Unknown */
+ avio_wb32(pb, 0);
+ avio_wl32(pb, 0x7F);
+ avio_wb64(pb, 0);
+ avio_wb64(pb, 0);
+ avio_wb32(pb, 0);
+
+ avio_flush(pb);
+
+ return 0;
+}
+
+static int ast_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ ASTMuxContext *ast = s->priv_data;
+ AVCodecContext *enc = s->streams[0]->codec;
+ int size = pkt->size / enc->channels;
+
+ if (s->streams[0]->nb_frames == 0)
+ ast->fbs = size;
+
+ ffio_wfourcc(pb, "BLCK");
+ avio_wb32(pb, size); /* Block size */
+
+ /* padding */
+ avio_wb64(pb, 0);
+ avio_wb64(pb, 0);
+ avio_wb64(pb, 0);
+
+ avio_write(pb, pkt->data, pkt->size);
+
+ return 0;
+}
+
+static int ast_write_trailer(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ ASTMuxContext *ast = s->priv_data;
+ AVCodecContext *enc = s->streams[0]->codec;
+ int64_t file_size = avio_tell(pb);
+ int64_t samples = (file_size - 64 - (32 * s->streams[0]->nb_frames)) / enc->block_align; /* PCM_S16BE_PLANAR */
+
+ av_log(s, AV_LOG_DEBUG, "total samples: %"PRId64"\n", samples);
+
+ if (s->pb->seekable) {
+ /* Number of samples */
+ avio_seek(pb, ast->samples, SEEK_SET);
+ avio_wb32(pb, samples);
+
+ /* Loopstart if provided */
+ if (ast->loopstart > 0) {
+ if (ast->loopstart >= samples) {
+ av_log(s, AV_LOG_WARNING, "Loopstart value is out of range and will be ignored\n");
+ ast->loopstart = -1;
+ avio_skip(pb, 4);
+ } else
+ avio_wb32(pb, ast->loopstart);
+ } else
+ avio_skip(pb, 4);
+
+ /* Loopend if provided. Otherwise number of samples again */
+ if (ast->loopend && ast->loopstart >= 0) {
+ if (ast->loopend > samples) {
+ av_log(s, AV_LOG_WARNING, "Loopend value is out of range and will be ignored\n");
+ ast->loopend = samples;
+ }
+ avio_wb32(pb, ast->loopend);
+ } else {
+ avio_wb32(pb, samples);
+ }
+
+ /* Size of first block */
+ avio_wb32(pb, ast->fbs);
+
+ /* File size minus header */
+ avio_seek(pb, ast->size, SEEK_SET);
+ avio_wb32(pb, file_size - 64);
+
+ /* Loop flag */
+ if (ast->loopstart >= 0) {
+ avio_skip(pb, 6);
+ avio_wb16(pb, 0xFFFF);
+ }
+
+ avio_seek(pb, file_size, SEEK_SET);
+ avio_flush(pb);
+ }
+ return 0;
+}
+
+#define OFFSET(obj) offsetof(ASTMuxContext, obj)
+static const AVOption options[] = {
+ { "loopstart", "Loopstart position in milliseconds.", OFFSET(loopstart), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "loopend", "Loopend position in milliseconds.", OFFSET(loopend), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+static const AVClass ast_muxer_class = {
+ .class_name = "AST muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_ast_muxer = {
+ .name = "ast",
+ .long_name = NULL_IF_CONFIG_SMALL("AST (Audio Stream)"),
+ .extensions = "ast",
+ .priv_data_size = sizeof(ASTMuxContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16BE_PLANAR,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = ast_write_header,
+ .write_packet = ast_write_packet,
+ .write_trailer = ast_write_trailer,
+ .priv_class = &ast_muxer_class,
+ .codec_tag = (const AVCodecTag* const []){ff_codec_ast_tags, 0},
+};
diff --git a/libavformat/au.c b/libavformat/au.c
index e682cbf305..53702bcb42 100644
--- a/libavformat/au.c
+++ b/libavformat/au.c
@@ -4,20 +4,20 @@
*
* first version by Francois Revol <revol@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,12 @@
#include "internal.h"
#include "avio_internal.h"
#include "pcm.h"
+#include "libavutil/avassert.h"
+
+/* if we don't know the size in advance */
+#define AU_UNKNOWN_SIZE ((uint32_t)(~0))
+/* the specification requires an annotation field of at least eight bytes */
+#define AU_HEADER_SIZE (24+8)
static const AVCodecTag codec_au_tags[] = {
{ AV_CODEC_ID_PCM_MULAW, 1 },
@@ -40,7 +46,12 @@ static const AVCodecTag codec_au_tags[] = {
{ AV_CODEC_ID_PCM_S32BE, 5 },
{ AV_CODEC_ID_PCM_F32BE, 6 },
{ AV_CODEC_ID_PCM_F64BE, 7 },
+ { AV_CODEC_ID_ADPCM_G726LE, 23 },
+ { AV_CODEC_ID_ADPCM_G722,24 },
+ { AV_CODEC_ID_ADPCM_G726LE, 25 },
+ { AV_CODEC_ID_ADPCM_G726LE, 26 },
{ AV_CODEC_ID_PCM_ALAW, 27 },
+ { AV_CODEC_ID_ADPCM_G726LE, MKBETAG('7','2','6','2') },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -59,7 +70,7 @@ static int au_probe(AVProbeData *p)
static int au_read_header(AVFormatContext *s)
{
- int size;
+ int size, data_size = 0;
unsigned int tag;
AVIOContext *pb = s->pb;
unsigned int id, channels, rate;
@@ -71,7 +82,12 @@ static int au_read_header(AVFormatContext *s)
if (tag != MKTAG('.', 's', 'n', 'd'))
return AVERROR_INVALIDDATA;
size = avio_rb32(pb); /* header size */
- avio_rb32(pb); /* data size */
+ data_size = avio_rb32(pb); /* data size in bytes */
+
+ if (data_size < 0 && data_size != AU_UNKNOWN_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid negative data size '%d' found\n", data_size);
+ return AVERROR_INVALIDDATA;
+ }
id = avio_rb32(pb);
rate = avio_rb32(pb);
@@ -90,7 +106,15 @@ static int au_read_header(AVFormatContext *s)
}
bps = av_get_bits_per_sample(codec);
- if (!bps) {
+ if (codec == AV_CODEC_ID_ADPCM_G726LE) {
+ if (id == MKBETAG('7','2','6','2')) {
+ bps = 2;
+ } else {
+ const uint8_t bpcss[] = {4, 0, 3, 5};
+ av_assert0(id >= 23 && id < 23 + 4);
+ bps = bpcss[id - 23];
+ }
+ } else if (!bps) {
avpriv_request_sample(s, "Unknown bits per sample");
return AVERROR_PATCHWELCOME;
}
@@ -113,8 +137,11 @@ static int au_read_header(AVFormatContext *s)
st->codec->codec_id = codec;
st->codec->channels = channels;
st->codec->sample_rate = rate;
+ st->codec->bits_per_coded_sample = bps;
st->codec->bit_rate = channels * rate * bps;
- st->codec->block_align = channels * bps >> 3;
+ st->codec->block_align = FFMAX(bps * st->codec->channels / 8, 1);
+ if (data_size != AU_UNKNOWN_SIZE)
+ st->duration = (((int64_t)data_size)<<3) / (st->codec->channels * (int64_t)bps);
st->start_time = 0;
avpriv_set_pts_info(st, 64, 1, rate);
@@ -122,27 +149,12 @@ static int au_read_header(AVFormatContext *s)
return 0;
}
-static int au_read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- int ret;
-
- ret = av_get_packet(s->pb, pkt, BLOCK_SIZE *
- s->streams[0]->codec->block_align);
- if (ret < 0)
- return ret;
-
- pkt->stream_index = 0;
- pkt->duration = ret / s->streams[0]->codec->block_align;
-
- return 0;
-}
-
AVInputFormat ff_au_demuxer = {
.name = "au",
.long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
.read_probe = au_probe,
.read_header = au_read_header,
- .read_packet = au_read_packet,
+ .read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
.codec_tag = (const AVCodecTag* const []) { codec_au_tags, 0 },
};
@@ -153,35 +165,29 @@ AVInputFormat ff_au_demuxer = {
#include "rawenc.h"
-/* if we don't know the size in advance */
-#define AU_UNKNOWN_SIZE ((uint32_t)(~0))
-
-/* AUDIO_FILE header */
-static int put_au_header(AVIOContext *pb, AVCodecContext *enc)
+static int au_write_header(AVFormatContext *s)
{
- if (!enc->codec_tag)
+ AVIOContext *pb = s->pb;
+ AVCodecContext *enc = s->streams[0]->codec;
+
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ enc->codec_tag = ff_codec_get_tag(codec_au_tags, enc->codec_id);
+ if (!enc->codec_tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
return AVERROR(EINVAL);
+ }
ffio_wfourcc(pb, ".snd"); /* magic number */
- avio_wb32(pb, 24); /* header size */
+ avio_wb32(pb, AU_HEADER_SIZE); /* header size */
avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */
avio_wb32(pb, enc->codec_tag); /* codec ID */
avio_wb32(pb, enc->sample_rate);
avio_wb32(pb, enc->channels);
-
- return 0;
-}
-
-static int au_write_header(AVFormatContext *s)
-{
- AVIOContext *pb = s->pb;
- int ret;
-
- s->priv_data = NULL;
-
- if ((ret = put_au_header(pb, s->streams[0]->codec)) < 0)
- return ret;
-
+ avio_wb64(pb, 0); /* annotation field */
avio_flush(pb);
return 0;
@@ -190,13 +196,12 @@ static int au_write_header(AVFormatContext *s)
static int au_write_trailer(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
- int64_t file_size;
+ int64_t file_size = avio_tell(pb);
- if (s->pb->seekable) {
+ if (s->pb->seekable && file_size < INT32_MAX) {
/* update file size */
- file_size = avio_tell(pb);
avio_seek(pb, 8, SEEK_SET);
- avio_wb32(pb, (uint32_t)(file_size - 24));
+ avio_wb32(pb, (uint32_t)(file_size - AU_HEADER_SIZE));
avio_seek(pb, file_size, SEEK_SET);
avio_flush(pb);
}
diff --git a/libavformat/audiointerleave.c b/libavformat/audiointerleave.c
index ba78d4e988..b64010ff44 100644
--- a/libavformat/audiointerleave.c
+++ b/libavformat/audiointerleave.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,7 +34,7 @@ void ff_audio_interleave_close(AVFormatContext *s)
AudioInterleaveContext *aic = st->priv_data;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- av_fifo_free(aic->fifo);
+ av_fifo_freep(&aic->fifo);
}
}
@@ -45,8 +45,12 @@ int ff_audio_interleave_init(AVFormatContext *s,
int i;
if (!samples_per_frame)
- return -1;
+ return AVERROR(EINVAL);
+ if (!time_base.num) {
+ av_log(s, AV_LOG_ERROR, "timebase not set for audio interleave\n");
+ return AVERROR(EINVAL);
+ }
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
AudioInterleaveContext *aic = st->priv_data;
@@ -56,14 +60,15 @@ int ff_audio_interleave_init(AVFormatContext *s,
av_get_bits_per_sample(st->codec->codec_id)) / 8;
if (!aic->sample_size) {
av_log(s, AV_LOG_ERROR, "could not compute sample size\n");
- return -1;
+ return AVERROR(EINVAL);
}
aic->samples_per_frame = samples_per_frame;
aic->samples = aic->samples_per_frame;
aic->time_base = time_base;
aic->fifo_size = 100* *aic->samples;
- aic->fifo= av_fifo_alloc(100 * *aic->samples);
+ if (!(aic->fifo= av_fifo_alloc_array(100, *aic->samples)))
+ return AVERROR(ENOMEM);
}
}
@@ -110,7 +115,7 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt
unsigned new_size = av_fifo_size(aic->fifo) + pkt->size;
if (new_size > aic->fifo_size) {
if (av_fifo_realloc2(aic->fifo, new_size) < 0)
- return -1;
+ return AVERROR(ENOMEM);
aic->fifo_size = new_size;
}
av_fifo_generic_write(aic->fifo, pkt->data, pkt->size, NULL);
@@ -128,9 +133,12 @@ int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt
AVStream *st = s->streams[i];
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
AVPacket new_pkt;
- while (interleave_new_audio_packet(s, &new_pkt, i, flush))
+ while ((ret = interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) {
if ((ret = ff_interleave_add_packet(s, &new_pkt, compare_ts)) < 0)
return ret;
+ }
+ if (ret < 0)
+ return ret;
}
}
diff --git a/libavformat/audiointerleave.h b/libavformat/audiointerleave.h
index 9c7b548c1d..4d77832fa1 100644
--- a/libavformat/audiointerleave.h
+++ b/libavformat/audiointerleave.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/avc.c b/libavformat/avc.c
index e639ed5593..9d843e0ca4 100644
--- a/libavformat/avc.c
+++ b/libavformat/avc.c
@@ -2,20 +2,20 @@
* AVC helper functions for muxers
* Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -180,7 +180,7 @@ int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size)
if (11 + sps_size + pps_size > *size)
return AVERROR_INVALIDDATA;
out_size = 8 + sps_size + pps_size;
- out = av_mallocz(out_size);
+ out = av_mallocz(out_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!out)
return AVERROR(ENOMEM);
AV_WB32(&out[0], 0x00000001);
diff --git a/libavformat/avc.h b/libavformat/avc.h
index 2442e5fff6..c5e80ff650 100644
--- a/libavformat/avc.h
+++ b/libavformat/avc.h
@@ -2,20 +2,20 @@
* AVC helper functions for muxers
* Copyright (c) 2008 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index aa11cff2f3..719c23b33c 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,7 @@
*
* Main lavf structure used for both muxing and demuxing is AVFormatContext,
* which exports all information about the file being read or written. As with
- * most Libav structures, its size is not part of public ABI, so it cannot be
+ * most Libavformat structures, its size is not part of public ABI, so it cannot be
* allocated on stack or directly with av_malloc(). To create an
* AVFormatContext, use avformat_alloc_context() (some functions, like
* avformat_open_input() might do that for you).
@@ -233,6 +233,53 @@
*
* @defgroup lavf_io I/O Read/Write
* @{
+ * @section lavf_io_dirlist Directory listing
+ * The directory listing API allows to list files on remote servers.
+ *
+ * Some of possible use cases:
+ * - an "open file" dialog to choose files from a remote location,
+ * - a recursive media finder providing a player with an ability to play all
+ * files from a given directory.
+ *
+ * @subsection lavf_io_dirlist_open Opening a directory
+ * At first, a directory needs to be opened by calling avio_open_dir()
+ * supplied with a URL and, optionally, ::AVDictionary containing
+ * protocol-specific parameters. The function returns zero or positive
+ * integer and allocates AVIODirContext on success.
+ *
+ * @code
+ * AVIODirContext *ctx = NULL;
+ * if (avio_open_dir(&ctx, "smb://example.com/some_dir", NULL) < 0) {
+ * fprintf(stderr, "Cannot open directory.\n");
+ * abort();
+ * }
+ * @endcode
+ *
+ * This code tries to open a sample directory using smb protocol without
+ * any additional parameters.
+ *
+ * @subsection lavf_io_dirlist_read Reading entries
+ * Each directory's entry (i.e. file, another directory, anything else
+ * within ::AVIODirEntryType) is represented by AVIODirEntry.
+ * Reading consecutive entries from an opened AVIODirContext is done by
+ * repeatedly calling avio_read_dir() on it. Each call returns zero or
+ * positive integer if successful. Reading can be stopped right after the
+ * NULL entry has been read -- it means there are no entries left to be
+ * read. The following code reads all entries from a directory associated
+ * with ctx and prints their names to standard output.
+ * @code
+ * AVIODirEntry *entry = NULL;
+ * for (;;) {
+ * if (avio_read_dir(ctx, &entry) < 0) {
+ * fprintf(stderr, "Cannot list directory.\n");
+ * abort();
+ * }
+ * if (!entry)
+ * break;
+ * printf("%s\n", entry->name);
+ * avio_free_directory_entry(&entry);
+ * }
+ * @endcode
* @}
*
* @defgroup lavf_codec Demuxers
@@ -265,6 +312,8 @@
struct AVFormatContext;
+struct AVDeviceInfoList;
+struct AVDeviceCapabilitiesQuery;
/**
* @defgroup metadata_api Public Metadata API
@@ -276,7 +325,7 @@ struct AVFormatContext;
*
* Metadata is exported or set as pairs of key/value strings in the 'metadata'
* fields of the AVFormatContext, AVStream, AVChapter and AVProgram structs
- * using the @ref lavu_dict "AVDictionary" API. Like all strings in Libav,
+ * using the @ref lavu_dict "AVDictionary" API. Like all strings in FFmpeg,
* metadata is assumed to be UTF-8 encoded Unicode. Note that metadata
* exported by demuxers isn't checked to be valid UTF-8 in most cases.
*
@@ -403,6 +452,9 @@ typedef struct AVProbeData {
const char *mime_type; /**< mime_type, when known. */
} AVProbeData;
+#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4)
+#define AVPROBE_SCORE_STREAM_RETRY (AVPROBE_SCORE_MAX/4-1)
+
#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension
#define AVPROBE_SCORE_MIME 75 ///< score for file mime type
#define AVPROBE_SCORE_MAX 100 ///< maximum score
@@ -426,14 +478,24 @@ typedef struct AVProbeData {
#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */
#define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */
#define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */
-#define AVFMT_TS_NONSTRICT 0x20000 /**< Format does not require strictly
+#if LIBAVFORMAT_VERSION_MAJOR <= 54
+#define AVFMT_TS_NONSTRICT 0x8020000 //we try to be compatible to the ABIs of ffmpeg and major forks
+#else
+#define AVFMT_TS_NONSTRICT 0x20000
+#endif
+ /**< Format does not require strictly
increasing timestamps, but they must
still be monotonic */
#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative
timestamps. If not set the timestamp
will be shifted in av_write_frame and
av_interleaved_write_frame so they
- start from 0. */
+ start from 0.
+ The user or muxer can override this through
+ AVFormatContext.avoid_negative_ts
+ */
+
+#define AVFMT_SEEK_TO_PTS 0x4000000 /**< Seeking is based on PTS */
/**
* @addtogroup lavf_encoding
@@ -503,8 +565,44 @@ typedef struct AVOutputFormat {
*
* @return 1 if the codec is supported, 0 if it is not.
* A negative number if unknown.
+ * MKTAG('A', 'P', 'I', 'C') if the codec is only supported as AV_DISPOSITION_ATTACHED_PIC
*/
int (*query_codec)(enum AVCodecID id, int std_compliance);
+
+ void (*get_output_timestamp)(struct AVFormatContext *s, int stream,
+ int64_t *dts, int64_t *wall);
+ /**
+ * Allows sending messages from application to device.
+ */
+ int (*control_message)(struct AVFormatContext *s, int type,
+ void *data, size_t data_size);
+
+ /**
+ * Write an uncoded AVFrame.
+ *
+ * See av_write_uncoded_frame() for details.
+ *
+ * The library will free *frame afterwards, but the muxer can prevent it
+ * by setting the pointer to NULL.
+ */
+ int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index,
+ AVFrame **frame, unsigned flags);
+ /**
+ * Returns device list with it properties.
+ * @see avdevice_list_devices() for more details.
+ */
+ int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
+ /**
+ * Initialize device capabilities submodule.
+ * @see avdevice_capabilities_create() for more details.
+ */
+ int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
+ /**
+ * Free device capabilities submodule.
+ * @see avdevice_capabilities_free() for more details.
+ */
+ int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
+ enum AVCodecID data_codec; /**< default data codec */
} AVOutputFormat;
/**
* @}
@@ -531,7 +629,7 @@ typedef struct AVInputFormat {
/**
* Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,
* AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,
- * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK.
+ * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS.
*/
int flags;
@@ -640,6 +738,24 @@ typedef struct AVInputFormat {
* Active streams are all streams that have AVStream.discard < AVDISCARD_ALL.
*/
int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
+
+ /**
+ * Returns device list with it properties.
+ * @see avdevice_list_devices() for more details.
+ */
+ int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);
+
+ /**
+ * Initialize device capabilities submodule.
+ * @see avdevice_capabilities_create() for more details.
+ */
+ int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
+
+ /**
+ * Free device capabilities submodule.
+ * @see avdevice_capabilities_free() for more details.
+ */
+ int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);
} AVInputFormat;
/**
* @}
@@ -651,11 +767,19 @@ enum AVStreamParseType {
AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */
AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */
AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */
+ AVSTREAM_PARSE_FULL_RAW=MKTAG(0,'R','A','W'), /**< full parsing and repack with timestamp and position generation by parser for raw
+ this assumes that each packet in the file contains no demuxer level headers and
+ just codec level data, otherwise position generation would fail */
};
typedef struct AVIndexEntry {
int64_t pos;
- int64_t timestamp;
+ int64_t timestamp; /**<
+ * Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are available
+ * when seeking to this entry. That means preferable PTS on keyframe based formats.
+ * But demuxers can choose to store a different timestamp, if it is more convenient for the implementation or nothing better
+ * is known
+ */
#define AVINDEX_KEYFRAME 0x0001
int flags:2;
int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs. 32 bytes due to possible 8-byte alignment).
@@ -687,6 +811,20 @@ typedef struct AVIndexEntry {
#define AV_DISPOSITION_ATTACHED_PIC 0x0400
/**
+ * To specify text track kind (different from subtitles default).
+ */
+#define AV_DISPOSITION_CAPTIONS 0x10000
+#define AV_DISPOSITION_DESCRIPTIONS 0x20000
+#define AV_DISPOSITION_METADATA 0x40000
+
+/**
+ * Options for behavior on timestamp wrap detection.
+ */
+#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap
+#define AV_PTS_WRAP_ADD_OFFSET 1 ///< add the format specific offset on wrap detection
+#define AV_PTS_WRAP_SUB_OFFSET -1 ///< subtract the format specific offset on wrap detection
+
+/**
* Stream structure.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
@@ -738,10 +876,12 @@ typedef struct AVStream {
AVRational time_base;
/**
- * Decoding: pts of the first frame of the stream, in stream time base.
+ * Decoding: pts of the first frame of the stream in presentation order, in stream time base.
* Only set this if you are absolutely 100% sure that the value you set
* it to really is the pts of the first frame.
* This may be undefined (AV_NOPTS_VALUE).
+ * @note The ASF header does NOT contain a correct start_time the ASF
+ * demuxer must NOT set this.
*/
int64_t start_time;
@@ -800,6 +940,8 @@ typedef struct AVStream {
* - muxing: May be set by the caller before avformat_write_header().
*
* Freed by libavformat in avformat_free_context().
+ *
+ * @see av_format_inject_global_side_data()
*/
AVPacketSideData *side_data;
/**
@@ -826,11 +968,25 @@ typedef struct AVStream {
/**
* Stream information used internally by av_find_stream_info()
*/
-#define MAX_STD_TIMEBASES (60*12+5)
+#define MAX_STD_TIMEBASES (30*12+7+6)
struct {
- int nb_decoded_frames;
+ int64_t last_dts;
+ int64_t duration_gcd;
+ int duration_count;
+ int64_t rfps_duration_sum;
+ double (*duration_error)[2][MAX_STD_TIMEBASES];
+ int64_t codec_info_duration;
+ int64_t codec_info_duration_fields;
+
+ /**
+ * 0 -> decoder has not been searched for yet.
+ * >0 -> decoder found
+ * <0 -> decoder with codec_id == -found_decoder has not been found
+ */
int found_decoder;
+ int64_t last_duration;
+
/**
* Those are used for average framerate estimation.
*/
@@ -844,6 +1000,13 @@ typedef struct AVStream {
int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */
// Timestamp generation support:
+ /**
+ * Timestamp corresponding to the last dts sync point.
+ *
+ * Initialized when AVCodecParserContext.dts_sync_point >= 0 and
+ * a DTS is received from the underlying container. Otherwise set to
+ * AV_NOPTS_VALUE by default.
+ */
int64_t first_dts;
int64_t cur_dts;
int64_t last_IP_pts;
@@ -876,8 +1039,153 @@ typedef struct AVStream {
support seeking natively. */
int nb_index_entries;
unsigned int index_entries_allocated_size;
+
+ /**
+ * Real base framerate of the stream.
+ * This is the lowest framerate with which all timestamps can be
+ * represented accurately (it is the least common multiple of all
+ * framerates in the stream). Note, this value is just a guess!
+ * For example, if the time base is 1/90000 and all frames have either
+ * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1.
+ *
+ * Code outside avformat should access this field using:
+ * av_stream_get/set_r_frame_rate(stream)
+ */
+ AVRational r_frame_rate;
+
+ /**
+ * Stream Identifier
+ * This is the MPEG-TS stream identifier +1
+ * 0 means unknown
+ */
+ int stream_identifier;
+
+ int64_t interleaver_chunk_size;
+ int64_t interleaver_chunk_duration;
+
+ /**
+ * stream probing state
+ * -1 -> probing finished
+ * 0 -> no probing requested
+ * rest -> perform probing with request_probe being the minimum score to accept.
+ * NOT PART OF PUBLIC API
+ */
+ int request_probe;
+ /**
+ * Indicates that everything up to the next keyframe
+ * should be discarded.
+ */
+ int skip_to_keyframe;
+
+ /**
+ * Number of samples to skip at the start of the frame decoded from the next packet.
+ */
+ int skip_samples;
+
+ /**
+ * If not 0, the number of samples that should be skipped from the start of
+ * the stream (the samples are removed from packets with pts==0, which also
+ * assumes negative timestamps do not happen).
+ * Intended for use with formats such as mp3 with ad-hoc gapless audio
+ * support.
+ */
+ int64_t start_skip_samples;
+
+ /**
+ * If not 0, the first audio sample that should be discarded from the stream.
+ * This is broken by design (needs global sample count), but can't be
+ * avoided for broken by design formats such as mp3 with ad-hoc gapless
+ * audio support.
+ */
+ int64_t first_discard_sample;
+
+ /**
+ * The sample after last sample that is intended to be discarded after
+ * first_discard_sample. Works on frame boundaries only. Used to prevent
+ * early EOF if the gapless info is broken (considered concatenated mp3s).
+ */
+ int64_t last_discard_sample;
+
+ /**
+ * Number of internally decoded frames, used internally in libavformat, do not access
+ * its lifetime differs from info which is why it is not in that structure.
+ */
+ int nb_decoded_frames;
+
+ /**
+ * Timestamp offset added to timestamps before muxing
+ * NOT PART OF PUBLIC API
+ */
+ int64_t mux_ts_offset;
+
+ /**
+ * Internal data to check for wrapping of the time stamp
+ */
+ int64_t pts_wrap_reference;
+
+ /**
+ * Options for behavior, when a wrap is detected.
+ *
+ * Defined by AV_PTS_WRAP_ values.
+ *
+ * If correction is enabled, there are two possibilities:
+ * If the first time stamp is near the wrap point, the wrap offset
+ * will be subtracted, which will create negative time stamps.
+ * Otherwise the offset will be added.
+ */
+ int pts_wrap_behavior;
+
+ /**
+ * Internal data to prevent doing update_initial_durations() twice
+ */
+ int update_initial_durations_done;
+
+ /**
+ * Internal data to generate dts from pts
+ */
+ int64_t pts_reorder_error[MAX_REORDER_DELAY+1];
+ uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1];
+
+ /**
+ * Internal data to analyze DTS and detect faulty mpeg streams
+ */
+ int64_t last_dts_for_order_check;
+ uint8_t dts_ordered;
+ uint8_t dts_misordered;
+
+ /**
+ * Internal data to inject global side data
+ */
+ int inject_global_side_data;
+
+ /**
+ * String containing paris of key and values describing recommended encoder configuration.
+ * Paris are separated by ','.
+ * Keys are separated from values by '='.
+ */
+ char *recommended_encoder_configuration;
+
+ /**
+ * display aspect ratio (0 if unknown)
+ * - encoding: unused
+ * - decoding: Set by libavformat to calculate sample_aspect_ratio internally
+ */
+ AVRational display_aspect_ratio;
} AVStream;
+AVRational av_stream_get_r_frame_rate(const AVStream *s);
+void av_stream_set_r_frame_rate(AVStream *s, AVRational r);
+struct AVCodecParserContext *av_stream_get_parser(const AVStream *s);
+char* av_stream_get_recommended_encoder_configuration(const AVStream *s);
+void av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration);
+
+/**
+ * Returns the pts of the last muxed packet + its duration
+ *
+ * the retuned value is undefined when used with a demuxer.
+ */
+int64_t av_stream_get_end_pts(const AVStream *st);
+
#define AV_PROGRAM_RUNNING 1
/**
@@ -893,6 +1201,23 @@ typedef struct AVProgram {
unsigned int *stream_index;
unsigned int nb_stream_indexes;
AVDictionary *metadata;
+
+ int program_num;
+ int pmt_pid;
+ int pcr_pid;
+
+ /*****************************************************************
+ * All fields below this line are not part of the public API. They
+ * may not be used outside of libavformat and can be changed and
+ * removed at will.
+ * New public fields should be added right above.
+ *****************************************************************
+ */
+ int64_t start_time;
+ int64_t end_time;
+
+ int64_t pts_wrap_reference; ///< reference dts for wrap detection
+ int pts_wrap_behavior; ///< behavior on wrap detection
} AVProgram;
#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present
@@ -905,6 +1230,26 @@ typedef struct AVChapter {
AVDictionary *metadata;
} AVChapter;
+
+/**
+ * Callback used by devices to communicate with application.
+ */
+typedef int (*av_format_control_message)(struct AVFormatContext *s, int type,
+ void *data, size_t data_size);
+
+typedef int (*AVOpenCallback)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags,
+ const AVIOInterruptCB *int_cb, AVDictionary **options);
+
+/**
+ * The duration of a video can be estimated through various ways, and this enum can be used
+ * to know how the duration was estimated.
+ */
+enum AVDurationEstimationMethod {
+ AVFMT_DURATION_FROM_PTS, ///< Duration accurately estimated from PTSes
+ AVFMT_DURATION_FROM_STREAM, ///< Duration estimated from a stream with a known duration
+ AVFMT_DURATION_FROM_BITRATE ///< Duration estimated from bitrate (less accurate)
+};
+
typedef struct AVFormatInternal AVFormatInternal;
/**
@@ -1015,7 +1360,7 @@ typedef struct AVFormatContext {
/**
* Total stream bitrate in bit/s, 0 if not
* available. Never set it directly if the file_size and the
- * duration are known as Libav can compute it automatically.
+ * duration are known as FFmpeg can compute it automatically.
*/
int bit_rate;
@@ -1044,19 +1389,21 @@ typedef struct AVFormatContext {
* This flag is mainly intended for testing.
*/
#define AVFMT_FLAG_BITEXACT 0x0400
+#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload
+#define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down)
+#define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted)
+#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate.
+#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats
/**
- * Maximum size of the data read from input for determining
- * the input container format.
- * Demuxing only, set by the caller before avformat_open_input().
+ * @deprecated deprecated in favor of probesize2
*/
unsigned int probesize;
/**
- * Maximum duration (in AV_TIME_BASE units) of the data read
- * from input in avformat_find_stream_info().
- * Demuxing only, set by the caller before avformat_find_stream_info().
+ * @deprecated deprecated in favor of max_analyze_duration2
*/
+ attribute_deprecated
int max_analyze_duration;
const uint8_t *key;
@@ -1129,7 +1476,12 @@ typedef struct AVFormatContext {
* Start time of the stream in real world time, in microseconds
* since the Unix epoch (00:00 1st January 1970). That is, pts=0 in the
* stream was captured at this real world time.
- * Muxing only, set by the caller before avformat_write_header().
+ * - muxing: Set by the caller before avformat_write_header(). If set to
+ * either 0 or AV_NOPTS_VALUE, then the current wall-time will
+ * be used.
+ * - demuxing: Set by libavformat. AV_NOPTS_VALUE if unknown. Note that
+ * the value may become known after some number of frames
+ * have been received.
*/
int64_t start_time_realtime;
@@ -1205,7 +1557,7 @@ typedef struct AVFormatContext {
/**
* Avoid negative timestamps during muxing.
* Any value of the AVFMT_AVOID_NEG_TS_* constants.
- * Note, this only works when using av_interleaved_write_frame.
+ * Note, this only works when using av_interleaved_write_frame. (interleave_packet_per_dts is in use)
* - muxing: Set by user
* - demuxing: unused
*/
@@ -1215,12 +1567,271 @@ typedef struct AVFormatContext {
#define AVFMT_AVOID_NEG_TS_MAKE_ZERO 2 ///< Shift timestamps so that they start at 0
/**
+ * Transport stream id.
+ * This will be moved into demuxer private options. Thus no API/ABI compatibility
+ */
+ int ts_id;
+
+ /**
+ * Audio preload in microseconds.
+ * Note, not all formats support this and unpredictable things may happen if it is used when not supported.
+ * - encoding: Set by user via AVOptions (NO direct access)
+ * - decoding: unused
+ */
+ int audio_preload;
+
+ /**
+ * Max chunk time in microseconds.
+ * Note, not all formats support this and unpredictable things may happen if it is used when not supported.
+ * - encoding: Set by user via AVOptions (NO direct access)
+ * - decoding: unused
+ */
+ int max_chunk_duration;
+
+ /**
+ * Max chunk size in bytes
+ * Note, not all formats support this and unpredictable things may happen if it is used when not supported.
+ * - encoding: Set by user via AVOptions (NO direct access)
+ * - decoding: unused
+ */
+ int max_chunk_size;
+
+ /**
+ * forces the use of wallclock timestamps as pts/dts of packets
+ * This has undefined results in the presence of B frames.
+ * - encoding: unused
+ * - decoding: Set by user via AVOptions (NO direct access)
+ */
+ int use_wallclock_as_timestamps;
+
+ /**
+ * avio flags, used to force AVIO_FLAG_DIRECT.
+ * - encoding: unused
+ * - decoding: Set by user via AVOptions (NO direct access)
+ */
+ int avio_flags;
+
+ /**
+ * The duration field can be estimated through various ways, and this field can be used
+ * to know how the duration was estimated.
+ * - encoding: unused
+ * - decoding: Read by user via AVOptions (NO direct access)
+ */
+ enum AVDurationEstimationMethod duration_estimation_method;
+
+ /**
+ * Skip initial bytes when opening stream
+ * - encoding: unused
+ * - decoding: Set by user via AVOptions (NO direct access)
+ */
+ int64_t skip_initial_bytes;
+
+ /**
+ * Correct single timestamp overflows
+ * - encoding: unused
+ * - decoding: Set by user via AVOptions (NO direct access)
+ */
+ unsigned int correct_ts_overflow;
+
+ /**
+ * Force seeking to any (also non key) frames.
+ * - encoding: unused
+ * - decoding: Set by user via AVOptions (NO direct access)
+ */
+ int seek2any;
+
+ /**
+ * Flush the I/O context after each packet.
+ * - encoding: Set by user via AVOptions (NO direct access)
+ * - decoding: unused
+ */
+ int flush_packets;
+
+ /**
+ * format probing score.
+ * The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes
+ * the format.
+ * - encoding: unused
+ * - decoding: set by avformat, read by user via av_format_get_probe_score() (NO direct access)
+ */
+ int probe_score;
+
+ /**
+ * number of bytes to read maximally to identify format.
+ * - encoding: unused
+ * - decoding: set by user through AVOPtions (NO direct access)
+ */
+ int format_probesize;
+
+ /**
+ * ',' separated list of allowed decoders.
+ * If NULL then all are allowed
+ * - encoding: unused
+ * - decoding: set by user through AVOptions (NO direct access)
+ */
+ char *codec_whitelist;
+
+ /**
+ * ',' separated list of allowed demuxers.
+ * If NULL then all are allowed
+ * - encoding: unused
+ * - decoding: set by user through AVOptions (NO direct access)
+ */
+ char *format_whitelist;
+
+ /**
* An opaque field for libavformat internal usage.
* Must not be accessed in any way by callers.
*/
AVFormatInternal *internal;
+
+ /**
+ * IO repositioned flag.
+ * This is set by avformat when the underlaying IO context read pointer
+ * is repositioned, for example when doing byte based seeking.
+ * Demuxers can use the flag to detect such changes.
+ */
+ int io_repositioned;
+
+ /**
+ * Forced video codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_video_codec (NO direct access).
+ */
+ AVCodec *video_codec;
+
+ /**
+ * Forced audio codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_audio_codec (NO direct access).
+ */
+ AVCodec *audio_codec;
+
+ /**
+ * Forced subtitle codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_subtitle_codec (NO direct access).
+ */
+ AVCodec *subtitle_codec;
+
+ /**
+ * Forced data codec.
+ * This allows forcing a specific decoder, even when there are multiple with
+ * the same codec_id.
+ * Demuxing: Set by user via av_format_set_data_codec (NO direct access).
+ */
+ AVCodec *data_codec;
+
+ /**
+ * Number of bytes to be written as padding in a metadata header.
+ * Demuxing: Unused.
+ * Muxing: Set by user via av_format_set_metadata_header_padding.
+ */
+ int metadata_header_padding;
+
+ /**
+ * User data.
+ * This is a place for some private data of the user.
+ * Mostly usable with control_message_cb or any future callbacks in device's context.
+ */
+ void *opaque;
+
+ /**
+ * Callback used by devices to communicate with application.
+ */
+ av_format_control_message control_message_cb;
+
+ /**
+ * Output timestamp offset, in microseconds.
+ * Muxing: set by user via AVOptions (NO direct access)
+ */
+ int64_t output_ts_offset;
+
+ /**
+ * Maximum duration (in AV_TIME_BASE units) of the data read
+ * from input in avformat_find_stream_info().
+ * Demuxing only, set by the caller before avformat_find_stream_info()
+ * via AVOptions (NO direct access).
+ * Can be set to 0 to let avformat choose using a heuristic.
+ */
+ int64_t max_analyze_duration2;
+
+ /**
+ * Maximum size of the data read from input for determining
+ * the input container format.
+ * Demuxing only, set by the caller before avformat_open_input()
+ * via AVOptions (NO direct access).
+ */
+ int64_t probesize2;
+
+ /**
+ * dump format separator.
+ * can be ", " or "\n " or anything else
+ * Code outside libavformat should access this field using AVOptions
+ * (NO direct access).
+ * - muxing: Set by user.
+ * - demuxing: Set by user.
+ */
+ uint8_t *dump_separator;
+
+ /**
+ * Forced Data codec_id.
+ * Demuxing: Set by user.
+ */
+ enum AVCodecID data_codec_id;
+
+ /**
+ * Called to open further IO contexts when needed for demuxing.
+ *
+ * This can be set by the user application to perform security checks on
+ * the URLs before opening them.
+ * The function should behave like avio_open2(), AVFormatContext is provided
+ * as contextual information and to reach AVFormatContext.opaque.
+ *
+ * If NULL then some simple checks are used together with avio_open2().
+ *
+ * Must not be accessed directly from outside avformat.
+ * @See av_format_set_open_cb()
+ *
+ * Demuxing: Set by user.
+ */
+ int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options);
} AVFormatContext;
+int av_format_get_probe_score(const AVFormatContext *s);
+AVCodec * av_format_get_video_codec(const AVFormatContext *s);
+void av_format_set_video_codec(AVFormatContext *s, AVCodec *c);
+AVCodec * av_format_get_audio_codec(const AVFormatContext *s);
+void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c);
+AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s);
+void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c);
+AVCodec * av_format_get_data_codec(const AVFormatContext *s);
+void av_format_set_data_codec(AVFormatContext *s, AVCodec *c);
+int av_format_get_metadata_header_padding(const AVFormatContext *s);
+void av_format_set_metadata_header_padding(AVFormatContext *s, int c);
+void * av_format_get_opaque(const AVFormatContext *s);
+void av_format_set_opaque(AVFormatContext *s, void *opaque);
+av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s);
+void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback);
+AVOpenCallback av_format_get_open_cb(const AVFormatContext *s);
+void av_format_set_open_cb(AVFormatContext *s, AVOpenCallback callback);
+
+/**
+ * This function will cause global side data to be injected in the next packet
+ * of each stream as well as after any subsequent seek.
+ */
+void av_format_inject_global_side_data(AVFormatContext *s);
+
+/**
+ * Returns the method used to set ctx->duration.
+ *
+ * @return AVFMT_DURATION_FROM_PTS, AVFMT_DURATION_FROM_STREAM, or AVFMT_DURATION_FROM_BITRATE.
+ */
+enum AVDurationEstimationMethod av_fmt_ctx_get_duration_estimation_method(const AVFormatContext* ctx);
+
typedef struct AVPacketList {
AVPacket pkt;
struct AVPacketList *next;
@@ -1258,7 +1869,6 @@ const char *avformat_license(void);
*
* @see av_register_input_format()
* @see av_register_output_format()
- * @see av_register_protocol()
*/
void av_register_all(void);
@@ -1324,6 +1934,9 @@ const AVClass *avformat_get_class(void);
*
* When muxing, should be called by the user before avformat_write_header().
*
+ * User is required to call avcodec_close() and avformat_free_context() to
+ * clean up the allocation by avformat_new_stream().
+ *
* @param s media file handle
* @param c If non-NULL, the AVCodecContext corresponding to the new stream
* will be initialized to use this codec. This is needed for e.g. codec-specific
@@ -1352,6 +1965,25 @@ AVProgram *av_new_program(AVFormatContext *s, int id);
/**
+ * Allocate an AVFormatContext for an output format.
+ * avformat_free_context() can be used to free the context and
+ * everything allocated by the framework within it.
+ *
+ * @param *ctx is set to the created format context, or to NULL in
+ * case of failure
+ * @param oformat format to use for allocating the context, if NULL
+ * format_name and filename are used instead
+ * @param format_name the name of output format to use for allocating the
+ * context, if NULL filename is used instead
+ * @param filename the name of the filename to use for allocating the
+ * context, may be NULL
+ * @return >= 0 in case of success, a negative AVERROR code in case of
+ * failure
+ */
+int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat,
+ const char *format_name, const char *filename);
+
+/**
* @addtogroup lavf_decoding
* @{
*/
@@ -1385,6 +2017,15 @@ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened);
AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max);
/**
+ * Guess the file format.
+ *
+ * @param is_opened Whether the file is already opened; determines whether
+ * demuxers with or without AVFMT_NOFILE are probed.
+ * @param score_ret The score of the best detection.
+ */
+AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret);
+
+/**
* Probe a bytestream to determine the input format. Each time a probe returns
* with a score that is too low, the probe buffer size is increased and another
* attempt is made. When the maximum probe size is reached, the input format
@@ -1396,9 +2037,17 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score
* @param logctx the log context
* @param offset the offset within the bytestream to probe from
* @param max_probe_size the maximum probe buffer size (zero for default)
- * @return 0 in case of success, a negative value corresponding to an
+ * @return the score in case of success, a negative value corresponding to an
+ * the maximal score is AVPROBE_SCORE_MAX
* AVERROR code otherwise
*/
+int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
+ const char *filename, void *logctx,
+ unsigned int offset, unsigned int max_probe_size);
+
+/**
+ * Like av_probe_input_buffer2() but returns 0 on success
+ */
int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
const char *filename, void *logctx,
unsigned int offset, unsigned int max_probe_size);
@@ -1424,6 +2073,9 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
*/
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);
+attribute_deprecated
+int av_demuxer_open(AVFormatContext *ic);
+
/**
* Read packets of a media file to get stream information. This
* is useful for file formats with no headers such as MPEG. This
@@ -1448,6 +2100,18 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
/**
+ * Find the programs which belong to a given stream.
+ *
+ * @param ic media file handle
+ * @param last the last found program, the search will start after this
+ * program, or from the beginning if it is NULL
+ * @param s stream index
+ * @return the next program which belongs to s, NULL if no program is found or
+ * the last program is not among the programs of ic.
+ */
+AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s);
+
+/**
* Find the "best" stream in the file.
* The best stream is determined according to various heuristics as the most
* likely to be what the user expects.
@@ -1534,6 +2198,7 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
* or if stream_index is -1, in AV_TIME_BASE units.
* If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as
* keyframes (this may not be supported by all demuxers).
+ * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored.
*
* @param s media file handle
* @param stream_index index of the stream which is used as time base reference
@@ -1550,6 +2215,24 @@ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
/**
+ * Discard all internally buffered data. This can be useful when dealing with
+ * discontinuities in the byte stream. Generally works only with formats that
+ * can resync. This includes headerless formats like MPEG-TS/TS but should also
+ * work with NUT, Ogg and in a limited way AVI for example.
+ *
+ * The set of streams, the detected duration, stream parameters and codecs do
+ * not change when calling this function. If you want a complete reset, it's
+ * better to open a new AVFormatContext.
+ *
+ * This does not flush the AVIOContext (s->pb). If necessary, call
+ * avio_flush(s->pb) before calling this function.
+ *
+ * @param s media file handle
+ * @return >=0 on success, error code otherwise
+ */
+int avformat_flush(AVFormatContext *s);
+
+/**
* Start playing a network-based stream (e.g. RTSP stream) at the
* current position.
*/
@@ -1665,6 +2348,44 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt);
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
/**
+ * Write a uncoded frame to an output media file.
+ *
+ * The frame must be correctly interleaved according to the container
+ * specification; if not, then av_interleaved_write_frame() must be used.
+ *
+ * See av_interleaved_write_frame() for details.
+ */
+int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
+ AVFrame *frame);
+
+/**
+ * Write a uncoded frame to an output media file.
+ *
+ * If the muxer supports it, this function allows to write an AVFrame
+ * structure directly, without encoding it into a packet.
+ * It is mostly useful for devices and similar special muxers that use raw
+ * video or PCM data and will not serialize it into a byte stream.
+ *
+ * To test whether it is possible to use it with a given muxer and stream,
+ * use av_write_uncoded_frame_query().
+ *
+ * The caller gives up ownership of the frame and must not access it
+ * afterwards.
+ *
+ * @return >=0 for success, a negative code on error
+ */
+int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
+ AVFrame *frame);
+
+/**
+ * Test whether a muxer supports uncoded frame.
+ *
+ * @return >=0 if an uncoded frame can be written to that muxer and stream,
+ * <0 if not
+ */
+int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index);
+
+/**
* Write the stream trailer to an output media file and free the
* file private data.
*
@@ -1699,6 +2420,25 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
enum AVMediaType type);
/**
+ * Get timing information for the data currently output.
+ * The exact meaning of "currently output" depends on the format.
+ * It is mostly relevant for devices that have an internal buffer and/or
+ * work in real time.
+ * @param s media file handle
+ * @param stream stream in the media file
+ * @param[out] dts DTS of the last packet output for the stream, in stream
+ * time_base units
+ * @param[out] wall absolute time when that packet whas output,
+ * in microsecond
+ * @return 0 if OK, AVERROR(ENOSYS) if the format does not support it
+ * Note: some formats or devices may not allow to measure dts and wall
+ * atomically.
+ */
+int av_get_output_timestamp(struct AVFormatContext *s, int stream,
+ int64_t *dts, int64_t *wall);
+
+
+/**
* @}
*/
@@ -1745,7 +2485,7 @@ void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size);
* @param dump_payload True if the payload must be displayed, too.
* @param st AVStream that the packet belongs to
*/
-void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st);
+void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st);
/**
@@ -1759,8 +2499,8 @@ void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st);
* @param dump_payload True if the payload must be displayed, too.
* @param st AVStream that the packet belongs to
*/
-void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload,
- AVStream *st);
+void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload,
+ const AVStream *st);
/**
* Get the AVCodecID for the given codec tag tag.
@@ -1782,6 +2522,18 @@ enum AVCodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned i
*/
unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum AVCodecID id);
+/**
+ * Get the codec tag for the given codec id.
+ *
+ * @param tags list of supported codec_id - codec_tag pairs, as stored
+ * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag
+ * @param id codec id that should be searched for in the list
+ * @param tag A pointer to the found tag
+ * @return 0 if id was not found in tags, > 0 if it was found
+ */
+int av_codec_get_tag2(const struct AVCodecTag * const *tags, enum AVCodecID id,
+ unsigned int *tag);
+
int av_find_default_stream_index(AVFormatContext *s);
/**
@@ -1840,9 +2592,9 @@ void av_url_split(char *proto, int proto_size,
* codec and time base.
*
* @param ic the context to analyze
- * @param index the index to print, if you have multiple inputs or outputs
+ * @param index index of the stream to dump information about
* @param url the URL to print, such as source or destination file
- * @param is_output whether the context is input or ouput
+ * @param is_output Select whether the specified context is an input(0) or output(1)
*/
void av_dump_format(AVFormatContext *ic,
int index,
@@ -1934,10 +2686,67 @@ const struct AVCodecTag *avformat_get_riff_video_tags(void);
*/
const struct AVCodecTag *avformat_get_riff_audio_tags(void);
/**
+ * @return the table mapping MOV FourCCs for video to libavcodec AVCodecID.
+ */
+const struct AVCodecTag *avformat_get_mov_video_tags(void);
+/**
+ * @return the table mapping MOV FourCCs for audio to AVCodecID.
+ */
+const struct AVCodecTag *avformat_get_mov_audio_tags(void);
+
+/**
* @}
*/
/**
+ * Guess the sample aspect ratio of a frame, based on both the stream and the
+ * frame aspect ratio.
+ *
+ * Since the frame aspect ratio is set by the codec but the stream aspect ratio
+ * is set by the demuxer, these two may not be equal. This function tries to
+ * return the value that you should use if you would like to display the frame.
+ *
+ * Basic logic is to use the stream aspect ratio if it is set to something sane
+ * otherwise use the frame aspect ratio. This way a container setting, which is
+ * usually easy to modify can override the coded value in the frames.
+ *
+ * @param format the format context which the stream is part of
+ * @param stream the stream which the frame is part of
+ * @param frame the frame with the aspect ratio to be determined
+ * @return the guessed (valid) sample_aspect_ratio, 0/1 if no idea
+ */
+AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame);
+
+/**
+ * Guess the frame rate, based on both the container and codec information.
+ *
+ * @param ctx the format context which the stream is part of
+ * @param stream the stream which the frame is part of
+ * @param frame the frame for which the frame rate should be determined, may be NULL
+ * @return the guessed (valid) frame rate, 0/1 if no idea
+ */
+AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame);
+
+/**
+ * Check if the stream st contained in s is matched by the stream specifier
+ * spec.
+ *
+ * See the "stream specifiers" chapter in the documentation for the syntax
+ * of spec.
+ *
+ * @return >0 if st is matched by spec;
+ * 0 if st is not matched by spec;
+ * AVERROR code if spec is invalid
+ *
+ * @note A stream specifier can match several streams in the format.
+ */
+int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st,
+ const char *spec);
+
+int avformat_queue_attached_pictures(AVFormatContext *s);
+
+
+/**
* @}
*/
diff --git a/libavformat/avformatres.rc b/libavformat/avformatres.rc
new file mode 100644
index 0000000000..ffe61e0d80
--- /dev/null
+++ b/libavformat/avformatres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libavformat
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libavformat/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO, 0
+PRODUCTVERSION LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg container format library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBAVFORMAT_VERSION)
+ VALUE "InternalName", "libavformat"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "avformat" BUILDSUF "-" AV_STRINGIFY(LIBAVFORMAT_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libavformat/avi.h b/libavformat/avi.h
index e05db9c63f..34da76f715 100644
--- a/libavformat/avi.h
+++ b/libavformat/avi.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 4caba46f46..5348b44b74 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -2,27 +2,29 @@
* AVI demuxer
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/bswap.h"
+#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
@@ -33,9 +35,9 @@
#include "internal.h"
#include "isom.h"
#include "riff.h"
-
-#undef NDEBUG
-#include <assert.h>
+#include "libavcodec/bytestream.h"
+#include "libavcodec/exif.h"
+#include "libavcodec/internal.h"
typedef struct AVIStream {
int64_t frame_offset; /* current frame (video) or byte (audio) counter
@@ -60,12 +62,16 @@ typedef struct AVIStream {
AVFormatContext *sub_ctx;
AVPacket sub_pkt;
uint8_t *sub_buffer;
+
+ int64_t seek_pos;
} AVIStream;
typedef struct AVIContext {
+ const AVClass *class;
int64_t riff_end;
int64_t movi_end;
int64_t fsize;
+ int64_t io_fsize;
int64_t movi_list;
int64_t last_pkt_pos;
int index_loaded;
@@ -74,9 +80,26 @@ typedef struct AVIContext {
int stream_index;
DVDemuxContext *dv_demux;
int odml_depth;
+ int use_odml;
#define MAX_ODML_DEPTH 1000
+ int64_t dts_max;
} AVIContext;
+
+static const AVOption options[] = {
+ { "use_odml", "use odml index", offsetof(AVIContext, use_odml), AV_OPT_TYPE_INT, {.i64 = 1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM},
+ { NULL },
+};
+
+static const AVClass demuxer_class = {
+ .class_name = "avi",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEMUXER,
+};
+
+
static const char avi_headers[][8] = {
{ 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' },
{ 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' },
@@ -95,8 +118,8 @@ static int avi_load_index(AVFormatContext *s);
static int guess_ni_flag(AVFormatContext *s);
#define print_tag(str, tag, size) \
- av_log(NULL, AV_LOG_TRACE, "%s: tag=%c%c%c%c size=0x%x\n", \
- str, tag & 0xff, \
+ av_log(NULL, AV_LOG_TRACE, "pos:%"PRIX64" %s: tag=%c%c%c%c size=0x%x\n", \
+ avio_tell(pb), str, tag & 0xff, \
(tag >> 8) & 0xff, \
(tag >> 16) & 0xff, \
(tag >> 24) & 0xff, \
@@ -115,7 +138,7 @@ static inline int get_duration(AVIStream *ast, int len)
static int get_riff(AVFormatContext *s, AVIOContext *pb)
{
AVIContext *avi = s->priv_data;
- char header[8];
+ char header[8] = {0};
int i;
/* check RIFF header */
@@ -157,12 +180,13 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
av_log(s, AV_LOG_TRACE,
"longs_pre_entry:%d index_type:%d entries_in_use:%d "
- "chunk_id:%X base:%16"PRIX64"\n",
+ "chunk_id:%X base:%16"PRIX64" frame_num:%d\n",
longs_pre_entry,
index_type,
entries_in_use,
chunk_id,
- base);
+ base,
+ frame_num);
if (stream_id >= s->nb_streams || stream_id < 0)
return AVERROR_INVALIDDATA;
@@ -198,12 +222,12 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
av_log(s, AV_LOG_TRACE, "pos:%"PRId64", len:%X\n", pos, len);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_INVALIDDATA;
if (last_pos == pos || pos == base - 8)
avi->non_interleaved = 1;
- if (last_pos != pos && (len || !ast->sample_size))
+ if (last_pos != pos && len)
av_add_index_entry(st, pos, ast->cum_len, len, 0,
key ? AVINDEX_KEYFRAME : 0);
@@ -216,7 +240,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
avio_rl32(pb); /* size */
duration = avio_rl32(pb);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_INVALIDDATA;
pos = avio_tell(pb);
@@ -226,16 +250,21 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
return AVERROR_INVALIDDATA;
}
- avio_seek(pb, offset + 8, SEEK_SET);
+ if (avio_seek(pb, offset + 8, SEEK_SET) < 0)
+ return -1;
avi->odml_depth++;
read_braindead_odml_indx(s, frame_num);
avi->odml_depth--;
frame_num += duration;
- avio_seek(pb, pos, SEEK_SET);
+ if (avio_seek(pb, pos, SEEK_SET) < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to restore position after reading index\n");
+ return -1;
+ }
+
}
}
- avi->index_loaded = 1;
+ avi->index_loaded = 2;
return 0;
}
@@ -281,7 +310,8 @@ static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag,
value = av_malloc(size + 1);
if (!value)
return AVERROR(ENOMEM);
- avio_read(pb, value, size);
+ if (avio_read(pb, value, size) != size)
+ return AVERROR_INVALIDDATA;
value[size] = 0;
AV_WL32(key, tag);
@@ -326,6 +356,7 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end)
uint16_t size = avio_rl16(s->pb);
const char *name = NULL;
char buffer[64] = { 0 };
+ size = FFMIN(size, tag_end - avio_tell(s->pb));
size -= avio_read(s->pb, buffer,
FFMIN(size, sizeof(buffer) - 1));
switch (tag) {
@@ -354,6 +385,88 @@ static void avi_read_nikon(AVFormatContext *s, uint64_t end)
}
}
+static int avi_extract_stream_metadata(AVStream *st)
+{
+ GetByteContext gb;
+ uint8_t *data = st->codec->extradata;
+ int data_size = st->codec->extradata_size;
+ int tag, offset;
+
+ if (!data || data_size < 8) {
+ return AVERROR_INVALIDDATA;
+ }
+
+ bytestream2_init(&gb, data, data_size);
+
+ tag = bytestream2_get_le32(&gb);
+
+ switch (tag) {
+ case MKTAG('A', 'V', 'I', 'F'):
+ // skip 4 byte padding
+ bytestream2_skip(&gb, 4);
+ offset = bytestream2_tell(&gb);
+ bytestream2_init(&gb, data + offset, data_size - offset);
+
+ // decode EXIF tags from IFD, AVI is always little-endian
+ return avpriv_exif_decode_ifd(st->codec, &gb, 1, 0, &st->metadata);
+ break;
+ case MKTAG('C', 'A', 'S', 'I'):
+ avpriv_request_sample(st->codec, "RIFF stream data tag type CASI (%u)", tag);
+ break;
+ case MKTAG('Z', 'o', 'r', 'a'):
+ avpriv_request_sample(st->codec, "RIFF stream data tag type Zora (%u)", tag);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int calculate_bitrate(AVFormatContext *s)
+{
+ AVIContext *avi = s->priv_data;
+ int i, j;
+ int64_t lensum = 0;
+ int64_t maxpos = 0;
+
+ for (i = 0; i<s->nb_streams; i++) {
+ int64_t len = 0;
+ AVStream *st = s->streams[i];
+
+ if (!st->nb_index_entries)
+ continue;
+
+ for (j = 0; j < st->nb_index_entries; j++)
+ len += st->index_entries[j].size;
+ maxpos = FFMAX(maxpos, st->index_entries[j-1].pos);
+ lensum += len;
+ }
+ if (maxpos < avi->io_fsize*9/10) // index does not cover the whole file
+ return 0;
+ if (lensum*9/10 > maxpos || lensum < maxpos*9/10) // frame sum and filesize mismatch
+ return 0;
+
+ for (i = 0; i<s->nb_streams; i++) {
+ int64_t len = 0;
+ AVStream *st = s->streams[i];
+ int64_t duration;
+ int64_t bitrate;
+
+ for (j = 0; j < st->nb_index_entries; j++)
+ len += st->index_entries[j].size;
+
+ if (st->nb_index_entries < 2 || st->codec->bit_rate > 0)
+ continue;
+ duration = st->index_entries[j-1].timestamp - st->index_entries[0].timestamp;
+ bitrate = av_rescale(8*len, st->time_base.den, duration * st->time_base.num);
+ if (bitrate <= INT_MAX && bitrate > 0) {
+ st->codec->bit_rate = bitrate;
+ }
+ }
+ return 1;
+}
+
static int avi_read_header(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
@@ -368,6 +481,7 @@ static int avi_read_header(AVFormatContext *s)
int amv_file_format = 0;
uint64_t list_end = 0;
int ret;
+ AVDictionaryEntry *dict_entry;
avi->stream_index = -1;
@@ -375,7 +489,9 @@ static int avi_read_header(AVFormatContext *s)
if (ret < 0)
return ret;
- avi->fsize = avio_size(pb);
+ av_log(avi, AV_LOG_DEBUG, "use odml:%d\n", avi->use_odml);
+
+ avi->io_fsize = avi->fsize = avio_size(pb);
if (avi->fsize <= 0 || avi->fsize < avi->riff_end)
avi->fsize = avi->riff_end == 8 ? INT64_MAX : avi->riff_end;
@@ -384,7 +500,7 @@ static int avi_read_header(AVFormatContext *s)
codec_type = -1;
frame_period = 0;
for (;;) {
- if (pb->eof_reached)
+ if (avio_feof(pb))
goto fail;
tag = avio_rl32(pb);
size = avio_rl32(pb);
@@ -432,7 +548,7 @@ static int avi_read_header(AVFormatContext *s)
/* AVI header */
/* using frame_period is bad idea */
frame_period = avio_rl32(pb);
- avio_skip(pb, 4);
+ avio_rl32(pb); /* max. bytes per second */
avio_rl32(pb);
avi->non_interleaved |= avio_rl32(pb) & AVIF_MUSTUSEINDEX;
@@ -488,6 +604,8 @@ static int avi_read_header(AVFormatContext *s)
ast = s->streams[0]->priv_data;
av_freep(&s->streams[0]->codec->extradata);
av_freep(&s->streams[0]->codec);
+ if (s->streams[0]->info)
+ av_freep(&s->streams[0]->info->duration_error);
av_freep(&s->streams[0]->info);
av_freep(&s->streams[0]);
s->nb_streams = 0;
@@ -516,7 +634,7 @@ static int avi_read_header(AVFormatContext *s)
break;
}
- assert(stream_index < s->nb_streams);
+ av_assert0(stream_index < s->nb_streams);
ast->handler = handler;
avio_rl32(pb); /* flags */
@@ -547,6 +665,10 @@ static int avi_read_header(AVFormatContext *s)
st->start_time = 0;
avio_rl32(pb); /* buffer size */
avio_rl32(pb); /* quality */
+ if (ast->cum_len*ast->scale/ast->rate > 3600) {
+ av_log(s, AV_LOG_ERROR, "crazy start time, iam scared, giving up\n");
+ ast->cum_len = 0;
+ }
ast->sample_size = avio_rl32(pb); /* sample ssize */
ast->cum_len *= FFMAX(1, ast->sample_size);
av_log(s, AV_LOG_TRACE, "%"PRIu32" %"PRIu32" %d\n",
@@ -557,6 +679,7 @@ static int avi_read_header(AVFormatContext *s)
codec_type = AVMEDIA_TYPE_VIDEO;
ast->sample_size = 0;
+ st->avg_frame_rate = av_inv_q(st->time_base);
break;
case MKTAG('a', 'u', 'd', 's'):
codec_type = AVMEDIA_TYPE_AUDIO;
@@ -568,8 +691,7 @@ static int avi_read_header(AVFormatContext *s)
codec_type = AVMEDIA_TYPE_DATA;
break;
default:
- av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1);
- goto fail;
+ av_log(s, AV_LOG_INFO, "unknown stream type %X\n", tag1);
}
if (ast->sample_size < 0) {
@@ -588,20 +710,32 @@ static int avi_read_header(AVFormatContext *s)
ast->sample_size = 0;
}
- if (ast->sample_size == 0)
+ if (ast->sample_size == 0) {
st->duration = st->nb_frames;
+ if (st->duration > 0 && avi->io_fsize > 0 && avi->riff_end > avi->io_fsize) {
+ av_log(s, AV_LOG_DEBUG, "File is truncated adjusting duration\n");
+ st->duration = av_rescale(st->duration, avi->io_fsize, avi->riff_end);
+ }
+ }
ast->frame_offset = ast->cum_len;
avio_skip(pb, size - 12 * 4);
break;
case MKTAG('s', 't', 'r', 'f'):
/* stream header */
+ if (!size)
+ break;
if (stream_index >= (unsigned)s->nb_streams || avi->dv_demux) {
avio_skip(pb, size);
} else {
uint64_t cur_pos = avio_tell(pb);
+ unsigned esize;
if (cur_pos < list_end)
size = FFMIN(size, list_end - cur_pos);
st = s->streams[stream_index];
+ if (st->codec->codec_type != AVMEDIA_TYPE_UNKNOWN) {
+ avio_skip(pb, size);
+ break;
+ }
switch (codec_type) {
case AVMEDIA_TYPE_VIDEO:
if (amv_file_format) {
@@ -612,7 +746,7 @@ static int avi_read_header(AVFormatContext *s)
avio_skip(pb, size);
break;
}
- tag1 = ff_get_bmp_header(pb, st);
+ tag1 = ff_get_bmp_header(pb, st, &esize);
if (tag1 == MKTAG('D', 'X', 'S', 'B') ||
tag1 == MKTAG('D', 'X', 'S', 'A')) {
@@ -622,17 +756,13 @@ static int avi_read_header(AVFormatContext *s)
break;
}
- if (size > 10 * 4 && size < (1 << 30)) {
- st->codec->extradata_size = size - 10 * 4;
- st->codec->extradata = av_malloc(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
- st->codec->extradata_size = 0;
+ if (size > 10 * 4 && size < (1 << 30) && size < avi->fsize) {
+ if (esize == size-1 && (esize&1)) {
+ st->codec->extradata_size = esize - 10 * 4;
+ } else
+ st->codec->extradata_size = size - 10 * 4;
+ if (ff_get_extradata(st->codec, pb, st->codec->extradata_size) < 0)
return AVERROR(ENOMEM);
- }
- avio_read(pb,
- st->codec->extradata,
- st->codec->extradata_size);
}
// FIXME: check if the encoder really did this correctly
@@ -642,7 +772,7 @@ static int avi_read_header(AVFormatContext *s)
/* Extract palette from extradata if bpp <= 8.
* This code assumes that extradata contains only palette.
* This is true for all paletted codecs implemented in
- * Libav. */
+ * FFmpeg. */
if (st->codec->extradata_size &&
(st->codec->bits_per_coded_sample <= 8)) {
int pal_size = (1 << st->codec->bits_per_coded_sample) << 2;
@@ -651,12 +781,12 @@ static int avi_read_header(AVFormatContext *s)
pal_size = FFMIN(pal_size, st->codec->extradata_size);
pal_src = st->codec->extradata +
st->codec->extradata_size - pal_size;
-#if HAVE_BIGENDIAN
+ /* Exclude the "BottomUp" field from the palette */
+ if (pal_src - st->codec->extradata >= 9 &&
+ !memcmp(st->codec->extradata + st->codec->extradata_size - 9, "BottomUp", 9))
+ pal_src -= 9;
for (i = 0; i < pal_size / 4; i++)
- ast->pal[i] = av_bswap32(((uint32_t *)pal_src)[i]);
-#else
- memcpy(ast->pal, pal_src, pal_size);
-#endif
+ ast->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
ast->has_pal = 1;
}
@@ -685,11 +815,8 @@ static int avi_read_header(AVFormatContext *s)
ast->handler == MKTAG('X', 'V', 'I', 'D'))
st->codec->codec_tag = MKTAG('X', 'V', 'I', 'D');
- // Support "Resolution 1:1" for Avid AVI Codec
- if (tag1 == MKTAG('A', 'V', 'R', 'n') &&
- st->codec->extradata_size >= 31 &&
- !memcmp(&st->codec->extradata[28], "1:1", 3))
- st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ if (st->codec->codec_tag == MKTAG('V', 'S', 'S', 'H'))
+ st->need_parsing = AVSTREAM_PARSE_FULL;
if (st->codec->codec_tag == 0 && st->codec->height > 0 &&
st->codec->extradata_size < 1U << 30) {
@@ -708,7 +835,7 @@ static int avi_read_header(AVFormatContext *s)
// avio_skip(pb, size - 5 * 4);
break;
case AVMEDIA_TYPE_AUDIO:
- ret = ff_get_wav_header(pb, st->codec, size);
+ ret = ff_get_wav_header(pb, st->codec, size, 0);
if (ret < 0)
return ret;
ast->dshow_block_align = st->codec->block_align;
@@ -739,15 +866,28 @@ static int avi_read_header(AVFormatContext *s)
if (ast->handler == AV_RL32("Axan")) {
st->codec->codec_id = AV_CODEC_ID_XAN_DPCM;
st->codec->codec_tag = 0;
+ ast->dshow_block_align = 0;
}
if (amv_file_format) {
st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV;
ast->dshow_block_align = 0;
}
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align <= 4 && ast->dshow_block_align ||
+ st->codec->codec_id == AV_CODEC_ID_MP2 && ast->dshow_block_align <= 4 && ast->dshow_block_align) {
+ av_log(s, AV_LOG_DEBUG, "overriding invalid dshow_block_align of %d\n", ast->dshow_block_align);
+ ast->dshow_block_align = 0;
+ }
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 1024 && ast->sample_size == 1024 ||
+ st->codec->codec_id == AV_CODEC_ID_AAC && ast->dshow_block_align == 4096 && ast->sample_size == 4096 ||
+ st->codec->codec_id == AV_CODEC_ID_MP3 && ast->dshow_block_align == 1152 && ast->sample_size == 1152) {
+ av_log(s, AV_LOG_DEBUG, "overriding sample_size\n");
+ ast->sample_size = 0;
+ }
break;
case AVMEDIA_TYPE_SUBTITLE:
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- st->codec->codec_id = AV_CODEC_ID_PROBE;
+ st->request_probe= 1;
+ avio_skip(pb, size);
break;
default:
st->codec->codec_type = AVMEDIA_TYPE_DATA;
@@ -758,9 +898,35 @@ static int avi_read_header(AVFormatContext *s)
}
}
break;
+ case MKTAG('s', 't', 'r', 'd'):
+ if (stream_index >= (unsigned)s->nb_streams
+ || s->streams[stream_index]->codec->extradata_size
+ || s->streams[stream_index]->codec->codec_tag == MKTAG('H','2','6','4')) {
+ avio_skip(pb, size);
+ } else {
+ uint64_t cur_pos = avio_tell(pb);
+ if (cur_pos < list_end)
+ size = FFMIN(size, list_end - cur_pos);
+ st = s->streams[stream_index];
+
+ if (size<(1<<30)) {
+ if (ff_get_extradata(st->codec, pb, size) < 0)
+ return AVERROR(ENOMEM);
+ }
+
+ if (st->codec->extradata_size & 1) //FIXME check if the encoder really did this correctly
+ avio_r8(pb);
+
+ ret = avi_extract_stream_metadata(st);
+ if (ret < 0) {
+ av_log(s, AV_LOG_WARNING, "could not decoding EXIF data in stream header.\n");
+ }
+ }
+ break;
case MKTAG('i', 'n', 'd', 'x'):
i = avio_tell(pb);
if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
+ avi->use_odml &&
read_braindead_odml_indx(s, 0) < 0 &&
(s->error_recognition & AV_EF_EXPLODE))
goto fail;
@@ -829,17 +995,32 @@ fail:
if (!avi->index_loaded && pb->seekable)
avi_load_index(s);
- avi->index_loaded = 1;
+ calculate_bitrate(s);
+ avi->index_loaded |= 1;
if ((ret = guess_ni_flag(s)) < 0)
return ret;
- avi->non_interleaved |= ret;
+ avi->non_interleaved |= ret | (s->flags & AVFMT_FLAG_SORT_DTS);
+
+ dict_entry = av_dict_get(s->metadata, "ISFT", NULL, 0);
+ if (dict_entry && !strcmp(dict_entry->value, "PotEncoder"))
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if ( st->codec->codec_id == AV_CODEC_ID_MPEG1VIDEO
+ || st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ }
+
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
if (st->nb_index_entries)
break;
}
+ // DV-in-AVI cannot be non-interleaved, if set this must be
+ // a mis-detection.
+ if (avi->dv_demux)
+ avi->non_interleaved = 0;
if (i == s->nb_streams && avi->non_interleaved) {
av_log(s, AV_LOG_WARNING,
"Non-interleaved AVI without index, switching to interleaved\n");
@@ -857,15 +1038,17 @@ fail:
return 0;
}
-static int read_gab2_sub(AVStream *st, AVPacket *pkt)
+static int read_gab2_sub(AVFormatContext *s, AVStream *st, AVPacket *pkt)
{
if (pkt->size >= 7 &&
+ pkt->size < INT_MAX - AVPROBE_PADDING_SIZE &&
!strcmp(pkt->data, "GAB2") && AV_RL16(pkt->data + 5) == 2) {
uint8_t desc[256];
int score = AVPROBE_SCORE_EXTENSION, ret;
AVIStream *ast = st->priv_data;
AVInputFormat *sub_demuxer;
AVRational time_base;
+ int size;
AVIOContext *pb = avio_alloc_context(pkt->data + 7,
pkt->size - 7,
0, NULL, NULL, NULL, NULL);
@@ -883,15 +1066,25 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt)
avio_rl16(pb); /* flags? */
avio_rl32(pb); /* data size */
- pd = (AVProbeData) { .buf = pb->buf_ptr,
- .buf_size = pb->buf_end - pb->buf_ptr };
- if (!(sub_demuxer = av_probe_input_format2(&pd, 1, &score)))
+ size = pb->buf_end - pb->buf_ptr;
+ pd = (AVProbeData) { .buf = av_mallocz(size + AVPROBE_PADDING_SIZE),
+ .buf_size = size };
+ if (!pd.buf)
+ goto error;
+ memcpy(pd.buf, pb->buf_ptr, size);
+ sub_demuxer = av_probe_input_format2(&pd, 1, &score);
+ av_freep(&pd.buf);
+ if (!sub_demuxer)
goto error;
if (!(ast->sub_ctx = avformat_alloc_context()))
goto error;
ast->sub_ctx->pb = pb;
+
+ if (ff_copy_whitelists(ast->sub_ctx, s) < 0)
+ goto error;
+
if (!avformat_open_input(&ast->sub_ctx, "", sub_demuxer, NULL)) {
ff_read_packet(ast->sub_ctx, &ast->sub_pkt);
*st->codec = *ast->sub_ctx->streams[0]->codec;
@@ -904,6 +1097,7 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt)
return 1;
error:
+ av_freep(&ast->sub_ctx);
av_freep(&pb);
}
return 0;
@@ -943,7 +1137,7 @@ static AVStream *get_subtitle_pkt(AVFormatContext *s, AVStream *next_st,
return sub_st;
}
-static int get_stream_idx(int *d)
+static int get_stream_idx(const unsigned *d)
{
if (d[0] >= '0' && d[0] <= '9' &&
d[1] >= '0' && d[1] <= '9') {
@@ -953,6 +1147,10 @@ static int get_stream_idx(int *d)
}
}
+/**
+ *
+ * @param exit_early set to 1 to just gather packet position without making the changes needed to actually read & return the packet
+ */
static int avi_sync(AVFormatContext *s, int exit_early)
{
AVIContext *avi = s->priv_data;
@@ -964,7 +1162,7 @@ static int avi_sync(AVFormatContext *s, int exit_early)
start_sync:
memset(d, -1, sizeof(d));
- for (i = sync = avio_tell(pb); !pb->eof_reached; i++) {
+ for (i = sync = avio_tell(pb); !avio_feof(pb); i++) {
int j;
for (j = 0; j < 7; j++)
@@ -974,9 +1172,9 @@ start_sync:
size = d[4] + (d[5] << 8) + (d[6] << 16) + (d[7] << 24);
n = get_stream_idx(d + 2);
- av_log(s, AV_LOG_TRACE, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n",
+ ff_tlog(s, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n",
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n);
- if (i + (uint64_t)size > avi->fsize || d[0] > 127)
+ if (i*(avi->io_fsize>0) + (uint64_t)size > avi->fsize || d[0] > 127)
continue;
// parse ix##
@@ -994,7 +1192,7 @@ start_sync:
goto start_sync;
}
- n = avi->dv_demux ? 0 : get_stream_idx(d);
+ n = get_stream_idx(d);
if (!((i - avi->last_pkt_pos) & 1) &&
get_stream_idx(d + 1) < s->nb_streams)
@@ -1006,6 +1204,9 @@ start_sync:
goto start_sync;
}
+ if (avi->dv_demux && n != 0)
+ continue;
+
// parse ##dc/##wb
if (n < s->nb_streams) {
AVStream *st;
@@ -1013,16 +1214,22 @@ start_sync:
st = s->streams[n];
ast = st->priv_data;
+ if (!ast) {
+ av_log(s, AV_LOG_WARNING, "Skipping foreign stream %d packet\n", n);
+ continue;
+ }
+
if (s->nb_streams >= 2) {
AVStream *st1 = s->streams[1];
AVIStream *ast1 = st1->priv_data;
// workaround for broken small-file-bug402.avi
- if (d[2] == 'w' && d[3] == 'b' && n == 0 &&
- st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- st1->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- ast->prefix == 'd' * 256 + 'c' &&
- (d[2] * 256 + d[3] == ast1->prefix ||
- !ast1->prefix_count)) {
+ if ( d[2] == 'w' && d[3] == 'b'
+ && n == 0
+ && st ->codec->codec_type == AVMEDIA_TYPE_VIDEO
+ && st1->codec->codec_type == AVMEDIA_TYPE_AUDIO
+ && ast->prefix == 'd'*256+'c'
+ && (d[2]*256+d[3] == ast1->prefix || !ast1->prefix_count)
+ ) {
n = 1;
st = st1;
ast = ast1;
@@ -1039,9 +1246,9 @@ start_sync:
|| st->discard >= AVDISCARD_ALL)) {
if (!exit_early) {
ast->frame_offset += get_duration(ast, size);
+ avio_skip(pb, size);
+ goto start_sync;
}
- avio_skip(pb, size);
- goto start_sync;
}
if (d[2] == 'p' && d[3] == 'c' && size <= 4 * 256 + 4) {
@@ -1052,7 +1259,7 @@ start_sync:
// b + (g << 8) + (r << 16);
for (; k <= last; k++)
- ast->pal[k] = avio_rb32(pb) >> 8;
+ ast->pal[k] = 0xFFU<<24 | avio_rb32(pb)>>8;
ast->has_pal = 1;
goto start_sync;
@@ -1074,7 +1281,7 @@ start_sync:
ast->packet_size = size + 8;
ast->remaining = size;
- if (size || !ast->sample_size) {
+ if (size) {
uint64_t pos = avio_tell(pb) - 8;
if (!st->index_entries || !st->nb_index_entries ||
st->index_entries[st->nb_index_entries - 1].pos < pos) {
@@ -1087,6 +1294,8 @@ start_sync:
}
}
+ if (pb->error)
+ return pb->error;
return AVERROR_EOF;
}
@@ -1143,10 +1352,7 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR_EOF;
best_ast = best_st->priv_data;
- best_ts = av_rescale_q(best_ts,
- (AVRational) { FFMAX(1, best_ast->sample_size),
- AV_TIME_BASE },
- best_st->time_base);
+ best_ts = best_ast->frame_offset;
if (best_ast->remaining) {
i = av_index_search_timestamp(best_st,
best_ts,
@@ -1161,15 +1367,18 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
if (i >= 0) {
int64_t pos = best_st->index_entries[i].pos;
pos += best_ast->packet_size - best_ast->remaining;
- avio_seek(s->pb, pos + 8, SEEK_SET);
+ if (avio_seek(s->pb, pos + 8, SEEK_SET) < 0)
+ return AVERROR_EOF;
- assert(best_ast->remaining <= best_ast->packet_size);
+ av_assert0(best_ast->remaining <= best_ast->packet_size);
avi->stream_index = best_stream_index;
if (!best_ast->remaining)
best_ast->packet_size =
best_ast->remaining = best_st->index_entries[i].size;
}
+ else
+ return AVERROR_EOF;
}
resync:
@@ -1196,8 +1405,9 @@ resync:
err = av_get_packet(pb, pkt, size);
if (err < 0)
return err;
+ size = err;
- if (ast->has_pal && pkt->data && pkt->size < (unsigned)INT_MAX / 2) {
+ if (ast->has_pal && pkt->size < (unsigned)INT_MAX / 2) {
uint8_t *pal;
pal = av_packet_new_side_data(pkt,
AV_PKT_DATA_PALETTE,
@@ -1219,7 +1429,7 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
#endif
size = avpriv_dv_produce_packet(avi->dv_demux, pkt,
- pkt->data, pkt->size);
+ pkt->data, pkt->size, pkt->pos);
#if FF_API_DESTRUCT_PACKET
FF_DISABLE_DEPRECATION_WARNINGS
pkt->destruct = dstr;
@@ -1230,7 +1440,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (size < 0)
av_free_packet(pkt);
} else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE &&
- !st->codec->codec_tag && read_gab2_sub(st, pkt)) {
+ !st->codec->codec_tag && read_gab2_sub(s, st, pkt)) {
ast->frame_offset++;
avi->stream_index = -1;
ast->remaining = 0;
@@ -1254,17 +1464,33 @@ FF_ENABLE_DEPRECATION_WARNINGS
size);
pkt->stream_index = avi->stream_index;
- if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->index_entries) {
AVIndexEntry *e;
int index;
- assert(st->index_entries);
- index = av_index_search_timestamp(st, ast->frame_offset, 0);
+ index = av_index_search_timestamp(st, ast->frame_offset, AVSEEK_FLAG_ANY);
e = &st->index_entries[index];
- if (index >= 0 && e->timestamp == ast->frame_offset)
+ if (index >= 0 && e->timestamp == ast->frame_offset) {
+ if (index == st->nb_index_entries-1) {
+ int key=1;
+ uint32_t state=-1;
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG4) {
+ const uint8_t *ptr = pkt->data, *end = ptr + FFMIN(size, 256);
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &state);
+ if (state == 0x1B6 && ptr < end) {
+ key = !(*ptr & 0xC0);
+ break;
+ }
+ }
+ }
+ if (!key)
+ e->flags &= ~AVINDEX_KEYFRAME;
+ }
if (e->flags & AVINDEX_KEYFRAME)
pkt->flags |= AV_PKT_FLAG_KEY;
+ }
} else {
pkt->flags |= AV_PKT_FLAG_KEY;
}
@@ -1276,6 +1502,22 @@ FF_ENABLE_DEPRECATION_WARNINGS
ast->packet_size = 0;
}
+ if (!avi->non_interleaved && pkt->pos >= 0 && ast->seek_pos > pkt->pos) {
+ av_free_packet(pkt);
+ goto resync;
+ }
+ ast->seek_pos= 0;
+
+ if (!avi->non_interleaved && st->nb_index_entries>1 && avi->index_loaded>1) {
+ int64_t dts= av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q);
+
+ if (avi->dts_max - dts > 2*AV_TIME_BASE) {
+ avi->non_interleaved= 1;
+ av_log(s, AV_LOG_INFO, "Switching to NI mode, due to poor interleaving\n");
+ }else if (avi->dts_max < dts)
+ avi->dts_max = dts;
+ }
+
return 0;
}
@@ -1295,7 +1537,9 @@ static int avi_read_idx1(AVFormatContext *s, int size)
AVIStream *ast;
unsigned int index, tag, flags, pos, len, first_packet = 1;
unsigned last_pos = -1;
+ unsigned last_idx = -1;
int64_t idx1_pos, first_packet_pos = 0, data_offset = 0;
+ int anykey = 0;
nb_index_entries = size / 16;
if (nb_index_entries <= 0)
@@ -1308,8 +1552,16 @@ static int avi_read_idx1(AVFormatContext *s, int size)
avi->stream_index = -1;
avio_seek(pb, idx1_pos, SEEK_SET);
+ if (s->nb_streams == 1 && s->streams[0]->codec->codec_tag == AV_RL32("MMES")) {
+ first_packet_pos = 0;
+ data_offset = avi->movi_list;
+ }
+
/* Read the entries and sort them in each stream component. */
for (i = 0; i < nb_index_entries; i++) {
+ if (avio_feof(pb))
+ return -1;
+
tag = avio_rl32(pb);
flags = avio_rl32(pb);
pos = avio_rl32(pb);
@@ -1324,7 +1576,7 @@ static int avi_read_idx1(AVFormatContext *s, int size)
st = s->streams[index];
ast = st->priv_data;
- if (first_packet && first_packet_pos && len) {
+ if (first_packet && first_packet_pos) {
data_offset = first_packet_pos - pos;
first_packet = 0;
}
@@ -1332,16 +1584,25 @@ static int avi_read_idx1(AVFormatContext *s, int size)
av_log(s, AV_LOG_TRACE, "%d cum_len=%"PRId64"\n", len, ast->cum_len);
- if (pb->eof_reached)
- return AVERROR_INVALIDDATA;
-
+ // even if we have only a single stream, we should
+ // switch to non-interleaved to get correct timestamps
if (last_pos == pos)
avi->non_interleaved = 1;
- else if (len || !ast->sample_size)
+ if (last_idx != pos && len) {
av_add_index_entry(st, pos, ast->cum_len, len, 0,
(flags & AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
+ last_idx= pos;
+ }
ast->cum_len += get_duration(ast, len);
last_pos = pos;
+ anykey |= flags&AVIIF_INDEX;
+ }
+ if (!anykey) {
+ for (index = 0; index < s->nb_streams; index++) {
+ st = s->streams[index];
+ if (st->nb_index_entries)
+ st->index_entries[0].flags |= AVINDEX_KEYFRAME;
+ }
}
return 0;
}
@@ -1355,7 +1616,6 @@ static int check_stream_max_drift(AVFormatContext *s)
int *idx = av_mallocz_array(s->nb_streams, sizeof(*idx));
if (!idx)
return AVERROR(ENOMEM);
-
for (min_pos = pos = 0; min_pos != INT64_MAX; pos = min_pos + 1LU) {
int64_t max_dts = INT64_MIN / 2;
int64_t min_dts = INT64_MAX / 2;
@@ -1446,16 +1706,19 @@ static int avi_load_index(AVFormatContext *s)
AVIOContext *pb = s->pb;
uint32_t tag, size;
int64_t pos = avio_tell(pb);
+ int64_t next;
int ret = -1;
if (avio_seek(pb, avi->movi_end, SEEK_SET) < 0)
goto the_end; // maybe truncated file
av_log(s, AV_LOG_TRACE, "movi_end=0x%"PRIx64"\n", avi->movi_end);
for (;;) {
- if (pb->eof_reached)
- break;
tag = avio_rl32(pb);
size = avio_rl32(pb);
+ if (avio_feof(pb))
+ break;
+ next = avio_tell(pb) + size + (size & 1);
+
av_log(s, AV_LOG_TRACE, "tag=%c%c%c%c size=0x%x\n",
tag & 0xff,
(tag >> 8) & 0xff,
@@ -1465,12 +1728,17 @@ static int avi_load_index(AVFormatContext *s)
if (tag == MKTAG('i', 'd', 'x', '1') &&
avi_read_idx1(s, size) >= 0) {
+ avi->index_loaded=2;
ret = 0;
+ }else if (tag == MKTAG('L', 'I', 'S', 'T')) {
+ uint32_t tag1 = avio_rl32(pb);
+
+ if (tag1 == MKTAG('I', 'N', 'F', 'O'))
+ ff_read_riff_info(s, size - 4);
+ }else if (!ret)
break;
- }
- size += (size & 1);
- if (avio_skip(pb, size) < 0)
+ if (avio_seek(pb, next, SEEK_SET) < 0)
break; // something is wrong here
}
@@ -1495,7 +1763,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index,
AVIContext *avi = s->priv_data;
AVStream *st;
int i, index;
- int64_t pos;
+ int64_t pos, pos_min;
AVIStream *ast;
/* Does not matter which stream is requested dv in avi has the
@@ -1507,16 +1775,23 @@ static int avi_read_seek(AVFormatContext *s, int stream_index,
if (!avi->index_loaded) {
/* we only load the index on demand */
avi_load_index(s);
- avi->index_loaded = 1;
+ avi->index_loaded |= 1;
}
+ av_assert0(stream_index >= 0);
st = s->streams[stream_index];
ast = st->priv_data;
index = av_index_search_timestamp(st,
timestamp * FFMAX(ast->sample_size, 1),
flags);
- if (index < 0)
+ if (index < 0) {
+ if (st->nb_index_entries > 0)
+ av_log(s, AV_LOG_DEBUG, "Failed to find timestamp %"PRId64 " in index %"PRId64 " .. %"PRId64 "\n",
+ timestamp * FFMAX(ast->sample_size, 1),
+ st->index_entries[0].timestamp,
+ st->index_entries[st->nb_index_entries - 1].timestamp);
return AVERROR_INVALIDDATA;
+ }
/* find the position */
pos = st->index_entries[index].pos;
@@ -1530,15 +1805,18 @@ static int avi_read_seek(AVFormatContext *s, int stream_index,
/* offsets. Calling with other stream indexes should have failed */
/* the av_index_search_timestamp call above. */
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return -1;
+
/* Feed the DV video stream version of the timestamp to the */
/* DV demux so it can synthesize correct timestamps. */
ff_dv_offset_reset(avi->dv_demux, timestamp);
- avio_seek(s->pb, pos, SEEK_SET);
avi->stream_index = -1;
return 0;
}
+ pos_min = pos;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st2 = s->streams[i];
AVIStream *ast2 = st2->priv_data;
@@ -1554,35 +1832,46 @@ static int avi_read_seek(AVFormatContext *s, int stream_index,
if (st2->nb_index_entries <= 0)
continue;
-// assert(st2->codec->block_align);
- assert((int64_t)st2->time_base.num * ast2->rate ==
- (int64_t)st2->time_base.den * ast2->scale);
+// av_assert1(st2->codec->block_align);
+ av_assert0(fabs(av_q2d(st2->time_base) - ast2->scale / (double)ast2->rate) < av_q2d(st2->time_base) * 0.00000001);
index = av_index_search_timestamp(st2,
av_rescale_q(timestamp,
st->time_base,
st2->time_base) *
FFMAX(ast2->sample_size, 1),
- flags | AVSEEK_FLAG_BACKWARD);
+ flags |
+ AVSEEK_FLAG_BACKWARD |
+ (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0));
if (index < 0)
index = 0;
+ ast2->seek_pos = st2->index_entries[index].pos;
+ pos_min = FFMIN(pos_min,ast2->seek_pos);
+ }
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st2 = s->streams[i];
+ AVIStream *ast2 = st2->priv_data;
- if (!avi->non_interleaved) {
- while (index > 0 && st2->index_entries[index].pos > pos)
- index--;
- while (index + 1 < st2->nb_index_entries &&
- st2->index_entries[index].pos < pos)
- index++;
- }
+ if (ast2->sub_ctx || st2->nb_index_entries <= 0)
+ continue;
- av_log(s, AV_LOG_TRACE, "%"PRId64" %d %"PRId64"\n",
- timestamp, index, st2->index_entries[index].timestamp);
- /* extract the current frame number */
+ index = av_index_search_timestamp(
+ st2,
+ av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1),
+ flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0));
+ if (index < 0)
+ index = 0;
+ while (!avi->non_interleaved && index>0 && st2->index_entries[index-1].pos >= pos_min)
+ index--;
ast2->frame_offset = st2->index_entries[index].timestamp;
}
/* do the seek */
- avio_seek(s->pb, pos, SEEK_SET);
+ if (avio_seek(s->pb, pos_min, SEEK_SET) < 0) {
+ av_log(s, AV_LOG_ERROR, "Seek failed\n");
+ return -1;
+ }
avi->stream_index = -1;
+ avi->dts_max = INT_MIN;
return 0;
}
@@ -1599,12 +1888,12 @@ static int avi_read_close(AVFormatContext *s)
av_freep(&ast->sub_ctx->pb);
avformat_close_input(&ast->sub_ctx);
}
- av_free(ast->sub_buffer);
+ av_freep(&ast->sub_buffer);
av_free_packet(&ast->sub_pkt);
}
}
- av_free(avi->dv_demux);
+ av_freep(&avi->dv_demux);
return 0;
}
@@ -1615,8 +1904,8 @@ static int avi_probe(AVProbeData *p)
/* check file header */
for (i = 0; avi_headers[i][0]; i++)
- if (!memcmp(p->buf, avi_headers[i], 4) &&
- !memcmp(p->buf + 8, avi_headers[i] + 4, 4))
+ if (AV_RL32(p->buf ) == AV_RL32(avi_headers[i] ) &&
+ AV_RL32(p->buf + 8) == AV_RL32(avi_headers[i] + 4))
return AVPROBE_SCORE_MAX;
return 0;
@@ -1632,4 +1921,5 @@ AVInputFormat ff_avi_demuxer = {
.read_packet = avi_read_packet,
.read_close = avi_read_close,
.read_seek = avi_read_seek,
+ .priv_class = &demuxer_class,
};
diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index 9c2936af60..5396a7d577 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -2,29 +2,39 @@
* AVI muxer
* Copyright (c) 2000 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+
+//#define DEBUG
+
#include "avformat.h"
#include "internal.h"
#include "avi.h"
#include "avio_internal.h"
#include "riff.h"
+#include "mpegts.h"
+#include "libavformat/avlanguage.h"
+#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
+#include "libavutil/avassert.h"
+#include "libavutil/timestamp.h"
+#include "libavutil/pixdesc.h"
+#include "libavcodec/raw.h"
/*
* TODO:
@@ -39,8 +49,10 @@ typedef struct AVIIentry {
typedef struct AVIIndex {
int64_t indx_start;
+ int64_t audio_strm_offset;
int entry;
int ents_allocated;
+ int master_odml_riff_id_base;
AVIIentry** cluster;
} AVIIndex;
@@ -52,14 +64,20 @@ typedef struct AVIContext {
typedef struct AVIStream {
int64_t frames_hdr_strm;
- int audio_strm_length;
+ int64_t audio_strm_length;
int packet_count;
int entry;
+ int max_size;
+ int sample_requested;
+
+ int64_t last_dts;
AVIIndex indexes;
} AVIStream;
-static inline AVIIentry *avi_get_ientry(AVIIndex *idx, int ent_id)
+static int avi_write_packet(AVFormatContext *s, AVPacket *pkt);
+
+static inline AVIIentry *avi_get_ientry(const AVIIndex *idx, int ent_id)
{
int cl = ent_id / AVI_INDEX_CLUSTER_SIZE;
int id = ent_id % AVI_INDEX_CLUSTER_SIZE;
@@ -76,6 +94,7 @@ static int64_t avi_start_new_riff(AVFormatContext *s, AVIOContext *pb,
avi->riff_id++;
for (i = 0; i < s->nb_streams; i++) {
AVIStream *avist = s->streams[i]->priv_data;
+ avist->indexes.audio_strm_offset = avist->audio_strm_length;
avist->indexes.entry = 0;
}
@@ -117,7 +136,7 @@ static int avi_write_counters(AVFormatContext *s, int riff_id)
for (n = 0; n < s->nb_streams; n++) {
AVIStream *avist = s->streams[n]->priv_data;
- assert(avist->frames_hdr_strm);
+ av_assert0(avist->frames_hdr_strm);
stream = s->streams[n]->codec;
avio_seek(pb, avist->frames_hdr_strm, SEEK_SET);
ff_parse_specific_params(s->streams[n], &au_byterate, &au_ssize, &au_scale);
@@ -129,7 +148,7 @@ static int avi_write_counters(AVFormatContext *s, int riff_id)
nb_frames = FFMAX(nb_frames, avist->packet_count);
}
if (riff_id == 1) {
- assert(avi->frames_hdr_all);
+ av_assert0(avi->frames_hdr_all);
avio_seek(pb, avi->frames_hdr_all, SEEK_SET);
avio_wl32(pb, nb_frames);
}
@@ -138,6 +157,33 @@ static int avi_write_counters(AVFormatContext *s, int riff_id)
return 0;
}
+static void write_odml_master(AVFormatContext *s, int stream_index)
+{
+ AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[stream_index];
+ AVCodecContext *enc = st->codec;
+ AVIStream *avist = st->priv_data;
+ unsigned char tag[5];
+ int j;
+
+ /* Starting to lay out AVI OpenDML master index.
+ * We want to make it JUNK entry for now, since we'd
+ * like to get away without making AVI an OpenDML one
+ * for compatibility reasons. */
+ avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
+ avio_wl16(pb, 4); /* wLongsPerEntry */
+ avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
+ avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
+ avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */
+ ffio_wfourcc(pb, avi_stream2fourcc(tag, stream_index, enc->codec_type));
+ /* dwChunkId */
+ avio_wl64(pb, 0); /* dwReserved[3] */
+ avio_wl32(pb, 0); /* Must be 0. */
+ for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
+ avio_wl64(pb, 0);
+ ff_end_tag(pb, avist->indexes.indx_start);
+}
+
static int avi_write_header(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
@@ -147,11 +193,12 @@ static int avi_write_header(AVFormatContext *s)
AVStream *video_st = NULL;
int64_t list1, list2, strh, strf;
AVDictionaryEntry *t = NULL;
+ int padding;
if (s->nb_streams > AVI_MAX_STREAM_COUNT) {
av_log(s, AV_LOG_ERROR, "AVI does not support >%d streams\n",
AVI_MAX_STREAM_COUNT);
- return -1;
+ return AVERROR(EINVAL);
}
for (n = 0; n < s->nb_streams; n++) {
@@ -254,9 +301,18 @@ static int avi_write_header(AVFormatContext *s)
ff_parse_specific_params(st, &au_byterate, &au_ssize, &au_scale);
+ if ( enc->codec_type == AVMEDIA_TYPE_VIDEO
+ && enc->codec_id != AV_CODEC_ID_XSUB
+ && au_byterate > 1000LL*au_scale) {
+ au_byterate = 600;
+ au_scale = 1;
+ }
+ avpriv_set_pts_info(st, 64, au_scale, au_byterate);
+ if (enc->codec_id == AV_CODEC_ID_XSUB)
+ au_scale = au_byterate = 0;
+
avio_wl32(pb, au_scale); /* scale */
avio_wl32(pb, au_byterate); /* rate */
- avpriv_set_pts_info(st, 64, au_scale, au_byterate);
avio_wl32(pb, 0); /* start */
/* remember this offset to fill later */
@@ -267,7 +323,7 @@ static int avi_write_header(AVFormatContext *s)
else
avio_wl32(pb, 0); /* length, XXX: filled later */
- /* suggested buffer size */ //FIXME set at the end to largest chunk
+ /* suggested buffer size, is set to largest chunk size in avi_write_trailer */
if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
avio_wl32(pb, 1024 * 1024);
else if (enc->codec_type == AVMEDIA_TYPE_AUDIO)
@@ -282,6 +338,9 @@ static int avi_write_header(AVFormatContext *s)
ff_end_tag(pb, strh);
if (enc->codec_type != AVMEDIA_TYPE_DATA) {
+ int ret;
+ enum AVPixelFormat pix_fmt;
+
strf = ff_start_tag(pb, "strf");
switch (enc->codec_type) {
case AVMEDIA_TYPE_SUBTITLE:
@@ -290,43 +349,51 @@ static int avi_write_header(AVFormatContext *s)
if (enc->codec_id != AV_CODEC_ID_XSUB)
break;
case AVMEDIA_TYPE_VIDEO:
- ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 0);
+ /* WMP expects RGB 5:5:5 rawvideo in avi to have bpp set to 16. */
+ if ( !enc->codec_tag
+ && enc->codec_id == AV_CODEC_ID_RAWVIDEO
+ && enc->pix_fmt == AV_PIX_FMT_RGB555LE
+ && enc->bits_per_coded_sample == 15)
+ enc->bits_per_coded_sample = 16;
+ ff_put_bmp_header(pb, enc, ff_codec_bmp_tags, 0, 0);
+ pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_avi,
+ enc->bits_per_coded_sample);
+ if ( !enc->codec_tag
+ && enc->codec_id == AV_CODEC_ID_RAWVIDEO
+ && enc->pix_fmt != pix_fmt
+ && enc->pix_fmt != AV_PIX_FMT_NONE)
+ av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to avi, output file will be unreadable\n",
+ av_get_pix_fmt_name(enc->pix_fmt));
break;
case AVMEDIA_TYPE_AUDIO:
- if (ff_put_wav_header(pb, enc) < 0)
- return -1;
+ if ((ret = ff_put_wav_header(pb, enc, 0)) < 0)
+ return ret;
break;
default:
- return -1;
+ av_log(s, AV_LOG_ERROR,
+ "Invalid or not supported codec type '%s' found in the input\n",
+ (char *)av_x_if_null(av_get_media_type_string(enc->codec_type), "?"));
+ return AVERROR(EINVAL);
}
ff_end_tag(pb, strf);
if ((t = av_dict_get(st->metadata, "title", NULL, 0))) {
ff_riff_write_info_tag(s->pb, "strn", t->value);
t = NULL;
}
+ if (enc->codec_id == AV_CODEC_ID_XSUB
+ && (t = av_dict_get(s->streams[i]->metadata, "language", NULL, 0))) {
+ const char* langstr = av_convert_lang_to(t->value, AV_LANG_ISO639_1);
+ t = NULL;
+ if (langstr) {
+ char* str = av_asprintf("Subtitle - %s-xx;02", langstr);
+ ff_riff_write_info_tag(s->pb, "strn", str);
+ av_free(str);
+ }
+ }
}
if (pb->seekable) {
- unsigned char tag[5];
- int j;
-
- /* Starting to lay out AVI OpenDML master index.
- * We want to make it JUNK entry for now, since we'd
- * like to get away without making AVI an OpenDML one
- * for compatibility reasons. */
- avist->indexes.entry = avist->indexes.ents_allocated = 0;
- avist->indexes.indx_start = ff_start_tag(pb, "JUNK");
- avio_wl16(pb, 4); /* wLongsPerEntry */
- avio_w8(pb, 0); /* bIndexSubType (0 == frame index) */
- avio_w8(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */
- avio_wl32(pb, 0); /* nEntriesInUse (will fill out later on) */
- ffio_wfourcc(pb, avi_stream2fourcc(tag, i, enc->codec_type));
- /* dwChunkId */
- avio_wl64(pb, 0); /* dwReserved[3] */
- // avio_wl32(pb, 0); /* Must be 0. */
- for (j = 0; j < AVI_MASTER_INDEX_SIZE * 2; j++)
- avio_wl64(pb, 0);
- ff_end_tag(pb, avist->indexes.indx_start);
+ write_odml_master(s, i);
}
if (enc->codec_type == AVMEDIA_TYPE_VIDEO &&
@@ -342,7 +409,7 @@ static int avi_write_header(AVFormatContext *s)
avio_wl32(pb, 0); // video format = unknown
avio_wl32(pb, 0); // video standard = unknown
// TODO: should be avg_frame_rate
- avio_wl32(pb, lrintf(1.0 / av_q2d(st->time_base)));
+ avio_wl32(pb, (2LL*st->time_base.den + st->time_base.num - 1) / (2LL * st->time_base.num));
avio_wl32(pb, enc->width);
avio_wl32(pb, enc->height);
avio_wl16(pb, den);
@@ -381,11 +448,18 @@ static int avi_write_header(AVFormatContext *s)
ff_riff_write_info(s);
+
+ padding = s->metadata_header_padding;
+ if (padding < 0)
+ padding = 1016;
+
/* some padding for easier tag editing */
- list2 = ff_start_tag(pb, "JUNK");
- for (i = 0; i < 1016; i += 4)
- avio_wl32(pb, 0);
- ff_end_tag(pb, list2);
+ if (padding) {
+ list2 = ff_start_tag(pb, "JUNK");
+ for (i = padding; i > 0; i -= 4)
+ avio_wl32(pb, 0);
+ ff_end_tag(pb, list2);
+ }
avi->movi_list = ff_start_tag(pb, "LIST");
ffio_wfourcc(pb, "movi");
@@ -395,6 +469,39 @@ static int avi_write_header(AVFormatContext *s)
return 0;
}
+static void update_odml_entry(AVFormatContext *s, int stream_index, int64_t ix, int size)
+{
+ AVIOContext *pb = s->pb;
+ AVIContext *avi = s->priv_data;
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ int64_t pos;
+ int au_byterate, au_ssize, au_scale;
+
+ avio_flush(pb);
+ pos = avio_tell(pb);
+
+ /* Updating one entry in the AVI OpenDML master index */
+ avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET);
+ ffio_wfourcc(pb, "indx"); /* enabling this entry */
+ avio_skip(pb, 8);
+ avio_wl32(pb, avi->riff_id - avist->indexes.master_odml_riff_id_base); /* nEntriesInUse */
+ avio_skip(pb, 16 * (avi->riff_id - avist->indexes.master_odml_riff_id_base));
+ avio_wl64(pb, ix); /* qwOffset */
+ avio_wl32(pb, size); /* dwSize */
+ ff_parse_specific_params(s->streams[stream_index], &au_byterate, &au_ssize, &au_scale);
+ if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO && au_ssize > 0) {
+ uint32_t audio_segm_size = (avist->audio_strm_length - avist->indexes.audio_strm_offset);
+ if ((audio_segm_size % au_ssize > 0) && !avist->sample_requested) {
+ avpriv_request_sample(s, "OpenDML index duration for audio packets with partial frames");
+ avist->sample_requested = 1;
+ }
+ avio_wl32(pb, audio_segm_size / au_ssize); /* dwDuration (sample count) */
+ } else
+ avio_wl32(pb, avist->indexes.entry); /* dwDuration (packet count) */
+
+ avio_seek(pb, pos, SEEK_SET);
+}
+
static int avi_write_ix(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
@@ -403,14 +510,26 @@ static int avi_write_ix(AVFormatContext *s)
char ix_tag[] = "ix00";
int i, j;
- assert(pb->seekable);
+ av_assert0(pb->seekable);
- if (avi->riff_id > AVI_MASTER_INDEX_SIZE)
- return -1;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVIStream *avist = s->streams[i]->priv_data;
+ if (avi->riff_id - avist->indexes.master_odml_riff_id_base == AVI_MASTER_INDEX_SIZE) {
+ int64_t pos;
+ int size = 8+2+1+1+4+8+4+4+16*AVI_MASTER_INDEX_SIZE;
+
+ pos = avio_tell(pb);
+ update_odml_entry(s, i, pos, size);
+ write_odml_master(s, i);
+ av_assert1(avio_tell(pb) - pos == size);
+ avist->indexes.master_odml_riff_id_base = avi->riff_id - 1;
+ }
+ av_assert0(avi->riff_id - avist->indexes.master_odml_riff_id_base < AVI_MASTER_INDEX_SIZE);
+ }
for (i = 0; i < s->nb_streams; i++) {
AVIStream *avist = s->streams[i]->priv_data;
- int64_t ix, pos;
+ int64_t ix;
avi_stream2fourcc(tag, i, s->streams[i]->codec->codec_type);
ix_tag[3] = '0' + i;
@@ -435,20 +554,8 @@ static int avi_write_ix(AVFormatContext *s)
avio_wl32(pb, ((uint32_t) ie->len & ~0x80000000) |
(ie->flags & 0x10 ? 0 : 0x80000000));
}
- avio_flush(pb);
- pos = avio_tell(pb);
-
- /* Updating one entry in the AVI OpenDML master index */
- avio_seek(pb, avist->indexes.indx_start - 8, SEEK_SET);
- ffio_wfourcc(pb, "indx"); /* enabling this entry */
- avio_skip(pb, 8);
- avio_wl32(pb, avi->riff_id); /* nEntriesInUse */
- avio_skip(pb, 16 * avi->riff_id);
- avio_wl64(pb, ix); /* qwOffset */
- avio_wl32(pb, pos - ix); /* dwSize */
- avio_wl32(pb, avist->indexes.entry); /* dwDuration */
-
- avio_seek(pb, pos, SEEK_SET);
+
+ update_odml_entry(s, i, ix, avio_tell(pb) - ix);
}
return 0;
}
@@ -504,27 +611,56 @@ static int avi_write_idx1(AVFormatContext *s)
return 0;
}
-static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
+static int write_skip_frames(AVFormatContext *s, int stream_index, int64_t dts)
{
- unsigned char tag[5];
- unsigned int flags = 0;
- const int stream_index = pkt->stream_index;
- int size = pkt->size;
- AVIContext *avi = s->priv_data;
- AVIOContext *pb = s->pb;
AVIStream *avist = s->streams[stream_index]->priv_data;
AVCodecContext *enc = s->streams[stream_index]->codec;
- while (enc->block_align == 0 && pkt->dts != AV_NOPTS_VALUE &&
- pkt->dts > avist->packet_count) {
+ av_dlog(s, "dts:%s packet_count:%d stream_index:%d\n", av_ts2str(dts), avist->packet_count, stream_index);
+ while (enc->block_align == 0 && dts != AV_NOPTS_VALUE &&
+ dts > avist->packet_count && enc->codec_id != AV_CODEC_ID_XSUB && avist->packet_count) {
AVPacket empty_packet;
+ if (dts - avist->packet_count > 60000) {
+ av_log(s, AV_LOG_ERROR, "Too large number of skipped frames %"PRId64" > 60000\n", dts - avist->packet_count);
+ return AVERROR(EINVAL);
+ }
+
av_init_packet(&empty_packet);
empty_packet.size = 0;
empty_packet.data = NULL;
empty_packet.stream_index = stream_index;
avi_write_packet(s, &empty_packet);
+ av_dlog(s, "dup dts:%s packet_count:%d\n", av_ts2str(dts), avist->packet_count);
+ }
+
+ return 0;
+}
+
+static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ unsigned char tag[5];
+ unsigned int flags = 0;
+ const int stream_index = pkt->stream_index;
+ int size = pkt->size;
+ AVIContext *avi = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVIStream *avist = s->streams[stream_index]->priv_data;
+ AVCodecContext *enc = s->streams[stream_index]->codec;
+ int ret;
+
+ if (enc->codec_id == AV_CODEC_ID_H264 && enc->codec_tag == MKTAG('H','2','6','4') && pkt->size) {
+ ret = ff_check_h264_startcode(s, s->streams[stream_index], pkt);
+ if (ret < 0)
+ return ret;
}
+
+ if ((ret = write_skip_frames(s, stream_index, pkt->dts)) < 0)
+ return ret;
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ avist->last_dts = pkt->dts + pkt->duration;
+
avist->packet_count++;
// Make sure to put an OpenDML chunk when the file size exceeds the limits
@@ -547,27 +683,27 @@ static int avi_write_packet(AVFormatContext *s, AVPacket *pkt)
avist->audio_strm_length += size;
if (s->pb->seekable) {
- int err;
AVIIndex *idx = &avist->indexes;
int cl = idx->entry / AVI_INDEX_CLUSTER_SIZE;
int id = idx->entry % AVI_INDEX_CLUSTER_SIZE;
if (idx->ents_allocated <= idx->entry) {
- if ((err = av_reallocp(&idx->cluster,
- (cl + 1) * sizeof(*idx->cluster))) < 0) {
+ idx->cluster = av_realloc_f(idx->cluster, sizeof(void*), cl+1);
+ if (!idx->cluster) {
idx->ents_allocated = 0;
idx->entry = 0;
- return err;
+ return AVERROR(ENOMEM);
}
idx->cluster[cl] =
av_malloc(AVI_INDEX_CLUSTER_SIZE * sizeof(AVIIentry));
if (!idx->cluster[cl])
- return -1;
+ return AVERROR(ENOMEM);
idx->ents_allocated += AVI_INDEX_CLUSTER_SIZE;
}
idx->cluster[cl][id].flags = flags;
idx->cluster[cl][id].pos = avio_tell(pb) - avi->movi_list;
idx->cluster[cl][id].len = size;
+ avist->max_size = FFMAX(avist->max_size, size);
idx->entry++;
}
@@ -588,6 +724,11 @@ static int avi_write_trailer(AVFormatContext *s)
int i, j, n, nb_frames;
int64_t file_size;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVIStream *avist = s->streams[i]->priv_data;
+ write_skip_frames(s, i, avist->last_dts);
+ }
+
if (pb->seekable) {
if (avi->riff_id == 1) {
ff_end_tag(pb, avi->movi_list);
@@ -626,9 +767,13 @@ static int avi_write_trailer(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVIStream *avist = s->streams[i]->priv_data;
for (j = 0; j < avist->indexes.ents_allocated / AVI_INDEX_CLUSTER_SIZE; j++)
- av_free(avist->indexes.cluster[j]);
+ av_freep(&avist->indexes.cluster[j]);
av_freep(&avist->indexes.cluster);
avist->indexes.ents_allocated = avist->indexes.entry = 0;
+ if (pb->seekable) {
+ avio_seek(pb, avist->frames_hdr_strm + 4, SEEK_SET);
+ avio_wl32(pb, avist->max_size);
+ }
}
return res;
diff --git a/libavformat/avio.c b/libavformat/avio.c
index ff740a28b7..a990ea2229 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -2,20 +2,20 @@
* unbuffered I/O
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,7 @@
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/time.h"
+#include "libavutil/avassert.h"
#include "os_support.h"
#include "avformat.h"
#if CONFIG_NETWORK
@@ -116,6 +117,16 @@ static int url_alloc_for_protocol(URLContext **puc, struct URLProtocol *up,
if (up->flags & URL_PROTOCOL_FLAG_NETWORK && !ff_network_init())
return AVERROR(EIO);
#endif
+ if ((flags & AVIO_FLAG_READ) && !up->url_read) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Impossible to open the '%s' protocol for reading\n", up->name);
+ return AVERROR(EIO);
+ }
+ if ((flags & AVIO_FLAG_WRITE) && !up->url_write) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Impossible to open the '%s' protocol for writing\n", up->name);
+ return AVERROR(EIO);
+ }
uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);
if (!uc) {
err = AVERROR(ENOMEM);
@@ -135,8 +146,33 @@ static int url_alloc_for_protocol(URLContext **puc, struct URLProtocol *up,
goto fail;
}
if (up->priv_data_class) {
+ int proto_len= strlen(up->name);
+ char *start = strchr(uc->filename, ',');
*(const AVClass **)uc->priv_data = up->priv_data_class;
av_opt_set_defaults(uc->priv_data);
+ if(!strncmp(up->name, uc->filename, proto_len) && uc->filename + proto_len == start){
+ int ret= 0;
+ char *p= start;
+ char sep= *++p;
+ char *key, *val;
+ p++;
+ while(ret >= 0 && (key= strchr(p, sep)) && p<key && (val = strchr(key+1, sep))){
+ *val= *key= 0;
+ ret= av_opt_set(uc->priv_data, p, key+1, 0);
+ if (ret == AVERROR_OPTION_NOT_FOUND)
+ av_log(uc, AV_LOG_ERROR, "Key '%s' not found.\n", p);
+ *val= *key= sep;
+ p= val+1;
+ }
+ if(ret<0 || p!=key){
+ av_log(uc, AV_LOG_ERROR, "Error parsing options string %s\n", start);
+ av_freep(&uc->priv_data);
+ av_freep(&uc);
+ err = AVERROR(EINVAL);
+ goto fail;
+ }
+ memmove(start, key+1, strlen(key));
+ }
}
}
if (int_cb)
@@ -180,31 +216,54 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"0123456789+-."
-int ffurl_alloc(URLContext **puc, const char *filename, int flags,
- const AVIOInterruptCB *int_cb)
+static struct URLProtocol *url_find_protocol(const char *filename)
{
URLProtocol *up = NULL;
char proto_str[128], proto_nested[128], *ptr;
size_t proto_len = strspn(filename, URL_SCHEME_CHARS);
- if (filename[proto_len] != ':' || is_dos_path(filename))
+ if (filename[proto_len] != ':' &&
+ (filename[proto_len] != ',' || !strchr(filename + proto_len + 1, ':')) ||
+ is_dos_path(filename))
strcpy(proto_str, "file");
else
av_strlcpy(proto_str, filename,
FFMIN(proto_len + 1, sizeof(proto_str)));
+ if ((ptr = strchr(proto_str, ',')))
+ *ptr = '\0';
av_strlcpy(proto_nested, proto_str, sizeof(proto_nested));
if ((ptr = strchr(proto_nested, '+')))
*ptr = '\0';
while (up = ffurl_protocol_next(up)) {
if (!strcmp(proto_str, up->name))
- return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
+ break;
if (up->flags & URL_PROTOCOL_FLAG_NESTED_SCHEME &&
!strcmp(proto_nested, up->name))
- return url_alloc_for_protocol(puc, up, filename, flags, int_cb);
+ break;
+ }
+
+ return up;
+}
+
+int ffurl_alloc(URLContext **puc, const char *filename, int flags,
+ const AVIOInterruptCB *int_cb)
+{
+ URLProtocol *p = NULL;
+
+ if (!first_protocol) {
+ av_log(NULL, AV_LOG_WARNING, "No URL Protocols are registered. "
+ "Missing call to av_register_all()?\n");
}
+
+ p = url_find_protocol(filename);
+ if (p)
+ return url_alloc_for_protocol(puc, p, filename, flags, int_cb);
+
*puc = NULL;
+ if (av_strstart(filename, "https:", NULL))
+ av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile with openssl or gnutls enabled.\n");
return AVERROR_PROTOCOL_NOT_FOUND;
}
@@ -212,11 +271,13 @@ int ffurl_open(URLContext **puc, const char *filename, int flags,
const AVIOInterruptCB *int_cb, AVDictionary **options)
{
int ret = ffurl_alloc(puc, filename, flags, int_cb);
- if (ret)
+ if (ret < 0)
return ret;
if (options && (*puc)->prot->priv_data_class &&
(ret = av_opt_set_dict((*puc)->priv_data, options)) < 0)
goto fail;
+ if ((ret = av_opt_set_dict(*puc, options)) < 0)
+ goto fail;
ret = ffurl_connect(*puc, options);
if (!ret)
return 0;
@@ -234,9 +295,12 @@ static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
{
int ret, len;
int fast_retries = 5;
+ int64_t wait_since = 0;
len = 0;
while (len < size_min) {
+ if (ff_check_interrupt(&h->interrupt_callback))
+ return AVERROR_EXIT;
ret = transfer_func(h, buf + len, size - len);
if (ret == AVERROR(EINTR))
continue;
@@ -244,17 +308,22 @@ static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
return ret;
if (ret == AVERROR(EAGAIN)) {
ret = 0;
- if (fast_retries)
+ if (fast_retries) {
fast_retries--;
- else
+ } else {
+ if (h->rw_timeout) {
+ if (!wait_since)
+ wait_since = av_gettime_relative();
+ else if (av_gettime_relative() > wait_since + h->rw_timeout)
+ return AVERROR(EIO);
+ }
av_usleep(1000);
+ }
} else if (ret < 1)
return (ret < 0 && ret != AVERROR_EOF) ? ret : len;
if (ret)
fast_retries = FFMAX(fast_retries, 2);
len += ret;
- if (ff_check_interrupt(&h->interrupt_callback))
- return AVERROR_EXIT;
}
return len;
}
@@ -281,7 +350,7 @@ int ffurl_write(URLContext *h, const unsigned char *buf, int size)
if (h->max_packet_size && size > h->max_packet_size)
return AVERROR(EIO);
- return retry_transfer_wrapper(h, buf, size, size,
+ return retry_transfer_wrapper(h, (unsigned char *)buf, size, size,
(int (*)(struct URLContext *, uint8_t *, int))
h->prot->url_write);
}
@@ -296,8 +365,9 @@ int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
return ret;
}
-int ffurl_close(URLContext *h)
+int ffurl_closep(URLContext **hh)
{
+ URLContext *h= *hh;
int ret = 0;
if (!h)
return 0; /* can happen when ffurl_open fails */
@@ -311,17 +381,30 @@ int ffurl_close(URLContext *h)
if (h->prot->priv_data_size) {
if (h->prot->priv_data_class)
av_opt_free(h->priv_data);
- av_free(h->priv_data);
+ av_freep(&h->priv_data);
}
- av_free(h);
+ av_freep(hh);
return ret;
}
+int ffurl_close(URLContext *h)
+{
+ return ffurl_closep(&h);
+}
+
+
+const char *avio_find_protocol_name(const char *url)
+{
+ URLProtocol *p = url_find_protocol(url);
+
+ return p ? p->name : NULL;
+}
+
int avio_check(const char *url, int flags)
{
URLContext *h;
int ret = ffurl_alloc(&h, url, flags, NULL);
- if (ret)
+ if (ret < 0)
return ret;
if (h->prot->url_check) {
@@ -336,6 +419,79 @@ int avio_check(const char *url, int flags)
return ret;
}
+int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options)
+{
+ URLContext *h = NULL;
+ AVIODirContext *ctx = NULL;
+ int ret;
+ av_assert0(s);
+
+ ctx = av_mallocz(sizeof(*ctx));
+ if (!ctx) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if ((ret = ffurl_alloc(&h, url, AVIO_FLAG_READ, NULL)) < 0)
+ goto fail;
+
+ if (h->prot->url_open_dir && h->prot->url_read_dir && h->prot->url_close_dir) {
+ if (options && h->prot->priv_data_class &&
+ (ret = av_opt_set_dict(h->priv_data, options)) < 0)
+ goto fail;
+ ret = h->prot->url_open_dir(h);
+ } else
+ ret = AVERROR(ENOSYS);
+ if (ret < 0)
+ goto fail;
+
+ ctx->url_context = h;
+ *s = ctx;
+ return 0;
+
+ fail:
+ av_free(ctx);
+ *s = NULL;
+ ffurl_close(h);
+ return ret;
+}
+
+int avio_read_dir(AVIODirContext *s, AVIODirEntry **next)
+{
+ URLContext *h;
+ int ret;
+
+ if (!s || !s->url_context)
+ return AVERROR(EINVAL);
+ h = s->url_context;
+ if ((ret = h->prot->url_read_dir(h, next)) < 0)
+ avio_free_directory_entry(next);
+ return ret;
+}
+
+int avio_close_dir(AVIODirContext **s)
+{
+ URLContext *h;
+
+ av_assert0(s);
+ if (!(*s) || !(*s)->url_context)
+ return AVERROR(EINVAL);
+ h = (*s)->url_context;
+ h->prot->url_close_dir(h);
+ ffurl_close(h);
+ av_freep(s);
+ *s = NULL;
+ return 0;
+}
+
+void avio_free_directory_entry(AVIODirEntry **entry)
+{
+ if (!entry || !*entry)
+ return;
+ av_free((*entry)->name);
+ av_freep(entry);
+}
+
int64_t ffurl_size(URLContext *h)
{
int64_t pos, size;
diff --git a/libavformat/avio.h b/libavformat/avio.h
index 3360e8296e..51913e39fc 100644
--- a/libavformat/avio.h
+++ b/libavformat/avio.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_AVIO_H
@@ -34,7 +34,6 @@
#include "libavformat/version.h"
-
#define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */
/**
@@ -54,6 +53,50 @@ typedef struct AVIOInterruptCB {
} AVIOInterruptCB;
/**
+ * Directory entry types.
+ */
+enum AVIODirEntryType {
+ AVIO_ENTRY_UNKNOWN,
+ AVIO_ENTRY_BLOCK_DEVICE,
+ AVIO_ENTRY_CHARACTER_DEVICE,
+ AVIO_ENTRY_DIRECTORY,
+ AVIO_ENTRY_NAMED_PIPE,
+ AVIO_ENTRY_SYMBOLIC_LINK,
+ AVIO_ENTRY_SOCKET,
+ AVIO_ENTRY_FILE,
+ AVIO_ENTRY_SERVER,
+ AVIO_ENTRY_SHARE,
+ AVIO_ENTRY_WORKGROUP,
+};
+
+/**
+ * Describes single entry of the directory.
+ *
+ * Only name and type fields are guaranteed be set.
+ * Rest of fields are protocol or/and platform dependent and might be unknown.
+ */
+typedef struct AVIODirEntry {
+ char *name; /**< Filename */
+ int type; /**< Type of the entry */
+ int utf8; /**< Set to 1 when name is encoded with UTF-8, 0 otherwise.
+ Name can be encoded with UTF-8 eventhough 0 is set. */
+ int64_t size; /**< File size in bytes, -1 if unknown. */
+ int64_t modification_timestamp; /**< Time of last modification in microseconds since unix
+ epoch, -1 if unknown. */
+ int64_t access_timestamp; /**< Time of last access in microseconds since unix epoch,
+ -1 if unknown. */
+ int64_t status_change_timestamp; /**< Time of last status change in microseconds since unix
+ epoch, -1 if unknown. */
+ int64_t user_id; /**< User ID of owner, -1 if unknown. */
+ int64_t group_id; /**< Group ID of owner, -1 if unknown. */
+ int64_t filemode; /**< Unix file mode, -1 if unknown. */
+} AVIODirEntry;
+
+typedef struct AVIODirContext {
+ struct URLContext *url_context;
+} AVIODirContext;
+
+/**
* Bytestream IO Context.
* New fields can be added to the end with minor version bumps.
* Removal, reordering and changes to existing fields require a major
@@ -115,11 +158,58 @@ typedef struct AVIOContext {
* A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
*/
int seekable;
+
+ /**
+ * max filesize, used to limit allocations
+ * This field is internal to libavformat and access from outside is not allowed.
+ */
+ int64_t maxsize;
+
+ /**
+ * avio_read and avio_write should if possible be satisfied directly
+ * instead of going through a buffer, and avio_seek will always
+ * call the underlying seek function directly.
+ */
+ int direct;
+
+ /**
+ * Bytes read statistic
+ * This field is internal to libavformat and access from outside is not allowed.
+ */
+ int64_t bytes_read;
+
+ /**
+ * seek statistic
+ * This field is internal to libavformat and access from outside is not allowed.
+ */
+ int seek_count;
+
+ /**
+ * writeout statistic
+ * This field is internal to libavformat and access from outside is not allowed.
+ */
+ int writeout_count;
+
+ /**
+ * Original buffer size
+ * used internally after probing and ensure seekback to reset the buffer size
+ * This field is internal to libavformat and access from outside is not allowed.
+ */
+ int orig_buffer_size;
} AVIOContext;
/* unbuffered I/O */
/**
+ * Return the name of the protocol that will handle the passed URL.
+ *
+ * NULL is returned if no protocol could be found for the given URL.
+ *
+ * @return Name of the protocol or NULL.
+ */
+const char *avio_find_protocol_name(const char *url);
+
+/**
* Return AVIO_FLAG_* access flags corresponding to the access permissions
* of the resource in url, or a negative value corresponding to an
* AVERROR code in case of failure. The returned access flags are
@@ -134,11 +224,57 @@ typedef struct AVIOContext {
int avio_check(const char *url, int flags);
/**
+ * Open directory for reading.
+ *
+ * @param s directory read context. Pointer to a NULL pointer must be passed.
+ * @param url directory to be listed.
+ * @param options A dictionary filled with protocol-private options. On return
+ * this parameter will be destroyed and replaced with a dictionary
+ * containing options that were not found. May be NULL.
+ * @return >=0 on success or negative on error.
+ */
+int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options);
+
+/**
+ * Get next directory entry.
+ *
+ * Returned entry must be freed with avio_free_directory_entry(). In particular
+ * it may outlive AVIODirContext.
+ *
+ * @param s directory read context.
+ * @param[out] next next entry or NULL when no more entries.
+ * @return >=0 on success or negative on error. End of list is not considered an
+ * error.
+ */
+int avio_read_dir(AVIODirContext *s, AVIODirEntry **next);
+
+/**
+ * Close directory.
+ *
+ * @note Entries created using avio_read_dir() are not deleted and must be
+ * freeded with avio_free_directory_entry().
+ *
+ * @param s directory read context.
+ * @return >=0 on success or negative on error.
+ */
+int avio_close_dir(AVIODirContext **s);
+
+/**
+ * Free entry allocated by avio_read_dir().
+ *
+ * @param entry entry to be freed.
+ */
+void avio_free_directory_entry(AVIODirEntry **entry);
+
+/**
* Allocate and initialize an AVIOContext for buffered I/O. It must be later
* freed with av_free().
*
* @param buffer Memory block for input/output operations via AVIOContext.
* The buffer must be allocated with av_malloc() and friends.
+ * It may be freed and replaced with a new buffer by libavformat.
+ * AVIOContext.buffer holds the buffer currently in use,
+ * which must be later freed with av_free().
* @param buffer_size The buffer size is very important for performance.
* For protocols with fixed blocksize it should be set to this blocksize.
* For others a typical size is a cache page, e.g. 4kb.
@@ -146,6 +282,7 @@ int avio_check(const char *url, int flags);
* @param opaque An opaque pointer to user-specific data.
* @param read_packet A function for refilling the buffer, may be NULL.
* @param write_packet A function for writing the buffer contents, may be NULL.
+ * The function may not change the input buffers content.
* @param seek A function for seeking to specified byte position, may be NULL.
*
* @return Allocated AVIOContext or NULL on failure.
@@ -183,6 +320,12 @@ int avio_put_str(AVIOContext *s, const char *str);
int avio_put_str16le(AVIOContext *s, const char *str);
/**
+ * Convert an UTF-8 string to UTF-16BE and write it.
+ * @return number of bytes written.
+ */
+int avio_put_str16be(AVIOContext *s, const char *str);
+
+/**
* Passing this as the "whence" parameter to a seek function causes it to
* return the filesize without seeking anywhere. Supporting this is optional.
* If it is not supported then the seek function will return <0.
@@ -191,8 +334,8 @@ int avio_put_str16le(AVIOContext *s, const char *str);
/**
* Oring this flag as into the "whence" parameter to a seek function causes it to
- * seek by any means (like reopening and linear reading) or other normally unreasonble
- * means that can be extreemly slow.
+ * seek by any means (like reopening and linear reading) or other normally unreasonable
+ * means that can be extremely slow.
* This may be ignored by the seek code.
*/
#define AVSEEK_FORCE 0x20000
@@ -207,10 +350,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence);
* Skip given number of bytes forward
* @return new position or AVERROR.
*/
-static av_always_inline int64_t avio_skip(AVIOContext *s, int64_t offset)
-{
- return avio_seek(s, offset, SEEK_CUR);
-}
+int64_t avio_skip(AVIOContext *s, int64_t offset);
/**
* ftell() equivalent for AVIOContext.
@@ -227,12 +367,34 @@ static av_always_inline int64_t avio_tell(AVIOContext *s)
*/
int64_t avio_size(AVIOContext *s);
+/**
+ * feof() equivalent for AVIOContext.
+ * @return non zero if and only if end of file
+ */
+int avio_feof(AVIOContext *s);
+#if FF_API_URL_FEOF
+/**
+ * @deprecated use avio_feof()
+ */
+attribute_deprecated
+int url_feof(AVIOContext *s);
+#endif
+
/** @warning currently size is limited */
int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3);
+/**
+ * Force flushing of buffered data.
+ *
+ * For write streams, force the buffered data to be immediately written to the output,
+ * without to wait to fill the internal buffer.
+ *
+ * For read streams, discard all currently buffered data, and advance the
+ * reported file position to that of the underlying stream. This does not
+ * read new data, and does not perform any seeks.
+ */
void avio_flush(AVIOContext *s);
-
/**
* Read size bytes from AVIOContext into buf.
* @return number of bytes read or AVERROR
@@ -311,6 +473,14 @@ int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen);
#define AVIO_FLAG_NONBLOCK 8
/**
+ * Use direct mode.
+ * avio_read and avio_write should if possible be satisfied directly
+ * instead of going through a buffer, and avio_seek will always
+ * call the underlying seek function directly.
+ */
+#define AVIO_FLAG_DIRECT 0x8000
+
+/**
* Create and initialize a AVIOContext for accessing the
* resource indicated by url.
* @note When the resource indicated by url has been opened in
@@ -321,7 +491,7 @@ int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen);
* @param url resource to access
* @param flags flags which control how the resource indicated by url
* is to be opened
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open(AVIOContext **s, const char *url, int flags);
@@ -341,7 +511,7 @@ int avio_open(AVIOContext **s, const char *url, int flags);
* @param options A dictionary filled with protocol-private options. On return
* this parameter will be destroyed and replaced with a dict containing options
* that were not found. May be NULL.
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int avio_open2(AVIOContext **s, const char *url, int flags,
@@ -423,17 +593,28 @@ int avio_pause(AVIOContext *h, int pause);
* If stream_index is (-1) the timestamp should be in AV_TIME_BASE
* units from the beginning of the presentation.
* If a stream_index >= 0 is used and the protocol does not support
- * seeking based on component streams, the call will fail with ENOTSUP.
+ * seeking based on component streams, the call will fail.
* @param timestamp timestamp in AVStream.time_base units
* or if there is no stream specified then in AV_TIME_BASE units.
* @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE
* and AVSEEK_FLAG_ANY. The protocol may silently ignore
* AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will
- * fail with ENOTSUP if used and not supported.
+ * fail if used and not supported.
* @return >= 0 on success
* @see AVInputFormat::read_seek
*/
int64_t avio_seek_time(AVIOContext *h, int stream_index,
int64_t timestamp, int flags);
+/* Avoid a warning. The header can not be included because it breaks c++. */
+struct AVBPrint;
+
+/**
+ * Read contents of h into print buffer, up to max_size bytes, or up to EOF.
+ *
+ * @return 0 for success (max_size bytes read or EOF reached), negative error
+ * code otherwise
+ */
+int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size);
+
#endif /* AVFORMAT_AVIO_H */
diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h
index c8630ab66e..1ed5831e78 100644
--- a/libavformat/avio_internal.h
+++ b/libavformat/avio_internal.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -78,16 +78,27 @@ static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
* @param s The read-only AVIOContext to rewind
* @param buf The probe buffer containing the first buf_size bytes of the file
* @param buf_size The size of buf
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
-int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char *buf, int buf_size);
+int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **buf, int buf_size);
uint64_t ffio_read_varlen(AVIOContext *bc);
/** @warning must be called before any I/O */
int ffio_set_buf_size(AVIOContext *s, int buf_size);
+/**
+ * Ensures that the requested seekback buffer size will be available
+ *
+ * Will ensure that when reading sequentially up to buf_size, seeking
+ * within the current pos and pos+buf_size is possible.
+ * Once the stream position moves outside this window this guarantee is lost.
+ */
+int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size);
+
+int ffio_limit(AVIOContext *s, int size);
+
void ffio_init_checksum(AVIOContext *s,
unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len),
unsigned long checksum);
@@ -116,7 +127,7 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size);
*
* @param s Used to return the pointer to the created AVIOContext.
* In case of failure the pointed to value is set to NULL.
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffio_fdopen(AVIOContext **s, URLContext *h);
diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
index 59f807cbd3..9701d74f19 100644
--- a/libavformat/aviobuf.c
+++ b/libavformat/aviobuf.c
@@ -2,28 +2,30 @@
* buffered I/O
* Copyright (c) 2000,2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/bprint.h"
#include "libavutil/crc.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "avformat.h"
#include "avio.h"
#include "avio_internal.h"
@@ -77,9 +79,11 @@ int ffio_init_context(AVIOContext *s,
int64_t (*seek)(void *opaque, int64_t offset, int whence))
{
s->buffer = buffer;
+ s->orig_buffer_size =
s->buffer_size = buffer_size;
s->buf_ptr = buffer;
s->opaque = opaque;
+ s->direct = 0;
url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);
@@ -121,28 +125,36 @@ AVIOContext *avio_alloc_context(
return s;
}
-static void flush_buffer(AVIOContext *s)
+static void writeout(AVIOContext *s, const uint8_t *data, int len)
{
- if (s->buf_ptr > s->buffer) {
- if (s->write_packet && !s->error) {
- int ret = s->write_packet(s->opaque, s->buffer,
- s->buf_ptr - s->buffer);
- if (ret < 0) {
- s->error = ret;
- }
+ if (s->write_packet && !s->error) {
+ int ret = s->write_packet(s->opaque, (uint8_t *)data, len);
+ if (ret < 0) {
+ s->error = ret;
}
+ }
+ s->writeout_count ++;
+ s->pos += len;
+}
+
+static void flush_buffer(AVIOContext *s)
+{
+ if (s->write_flag && s->buf_ptr > s->buffer) {
+ writeout(s, s->buffer, s->buf_ptr - s->buffer);
if (s->update_checksum) {
s->checksum = s->update_checksum(s->checksum, s->checksum_ptr,
s->buf_ptr - s->checksum_ptr);
s->checksum_ptr = s->buffer;
}
- s->pos += s->buf_ptr - s->buffer;
}
s->buf_ptr = s->buffer;
+ if (!s->write_flag)
+ s->buf_end = s->buffer;
}
void avio_w8(AVIOContext *s, int b)
{
+ av_assert2(b>=-128 && b<=255);
*s->buf_ptr++ = b;
if (s->buf_ptr >= s->buf_end)
flush_buffer(s);
@@ -164,6 +176,11 @@ void ffio_fill(AVIOContext *s, int b, int count)
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
{
+ if (s->direct && !s->update_checksum) {
+ avio_flush(s);
+ writeout(s, buf, size);
+ return;
+ }
while (size > 0) {
int len = FFMIN(s->buf_end - s->buf_ptr, size);
memcpy(s->buf_ptr, buf, len);
@@ -188,12 +205,14 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
int64_t offset1;
int64_t pos;
int force = whence & AVSEEK_FORCE;
+ int buffer_size;
whence &= ~AVSEEK_FORCE;
if(!s)
return AVERROR(EINVAL);
- pos = s->pos - (s->write_flag ? 0 : (s->buf_end - s->buffer));
+ buffer_size = s->buf_end - s->buffer;
+ pos = s->pos - (s->write_flag ? 0 : buffer_size);
if (whence != SEEK_CUR && whence != SEEK_SET)
return AVERROR(EINVAL);
@@ -204,23 +223,38 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
return offset1;
offset += offset1;
}
+ if (offset < 0)
+ return AVERROR(EINVAL);
+
offset1 = offset - pos;
- if (!s->must_flush &&
- offset1 >= 0 && offset1 < (s->buf_end - s->buffer)) {
+ if (!s->must_flush && (!s->direct || !s->seek) &&
+ offset1 >= 0 && offset1 <= buffer_size - s->write_flag) {
/* can do the seek inside the buffer */
s->buf_ptr = s->buffer + offset1;
} else if ((!s->seekable ||
offset1 <= s->buf_end + SHORT_SEEK_THRESHOLD - s->buffer) &&
!s->write_flag && offset1 >= 0 &&
+ (!s->direct || !s->seek) &&
(whence != SEEK_END || force)) {
while(s->pos < offset && !s->eof_reached)
fill_buffer(s);
if (s->eof_reached)
return AVERROR_EOF;
s->buf_ptr = s->buf_end + offset - s->pos;
- } else {
+ } else if(!s->write_flag && offset1 < 0 && -offset1 < buffer_size>>1 && s->seek && offset > 0) {
int64_t res;
+ pos -= FFMIN(buffer_size>>1, pos);
+ if ((res = s->seek(s->opaque, pos, SEEK_SET)) < 0)
+ return res;
+ s->buf_end =
+ s->buf_ptr = s->buffer;
+ s->pos = pos;
+ s->eof_reached = 0;
+ fill_buffer(s);
+ return avio_seek(s, offset, SEEK_SET | force);
+ } else {
+ int64_t res;
if (s->write_flag) {
flush_buffer(s);
s->must_flush = 1;
@@ -229,6 +263,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
return AVERROR(EPIPE);
if ((res = s->seek(s->opaque, offset, SEEK_SET)) < 0)
return res;
+ s->seek_count ++;
if (!s->write_flag)
s->buf_end = s->buffer;
s->buf_ptr = s->buffer;
@@ -238,6 +273,11 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
return offset;
}
+int64_t avio_skip(AVIOContext *s, int64_t offset)
+{
+ return avio_seek(s, offset, SEEK_CUR);
+}
+
int64_t avio_size(AVIOContext *s)
{
int64_t size;
@@ -257,20 +297,38 @@ int64_t avio_size(AVIOContext *s)
return size;
}
+int avio_feof(AVIOContext *s)
+{
+ if(!s)
+ return 0;
+ if(s->eof_reached){
+ s->eof_reached=0;
+ fill_buffer(s);
+ }
+ return s->eof_reached;
+}
+
+#if FF_API_URL_FEOF
+int url_feof(AVIOContext *s)
+{
+ return avio_feof(s);
+}
+#endif
+
void avio_wl32(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val);
- avio_w8(s, val >> 8);
- avio_w8(s, val >> 16);
- avio_w8(s, val >> 24);
+ avio_w8(s, (uint8_t) val );
+ avio_w8(s, (uint8_t)(val >> 8 ));
+ avio_w8(s, (uint8_t)(val >> 16));
+ avio_w8(s, val >> 24 );
}
void avio_wb32(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val >> 24);
- avio_w8(s, val >> 16);
- avio_w8(s, val >> 8);
- avio_w8(s, val);
+ avio_w8(s, val >> 24 );
+ avio_w8(s, (uint8_t)(val >> 16));
+ avio_w8(s, (uint8_t)(val >> 8 ));
+ avio_w8(s, (uint8_t) val );
}
int avio_put_str(AVIOContext *s, const char *str)
@@ -284,23 +342,45 @@ int avio_put_str(AVIOContext *s, const char *str)
return len;
}
-int avio_put_str16le(AVIOContext *s, const char *str)
+static inline int put_str16(AVIOContext *s, const char *str, const int be)
{
const uint8_t *q = str;
int ret = 0;
+ int err = 0;
while (*q) {
uint32_t ch;
uint16_t tmp;
- GET_UTF8(ch, *q++, break;)
- PUT_UTF16(ch, tmp, avio_wl16(s, tmp); ret += 2;)
+ GET_UTF8(ch, *q++, goto invalid;)
+ PUT_UTF16(ch, tmp, be ? avio_wb16(s, tmp) : avio_wl16(s, tmp);
+ ret += 2;)
+ continue;
+invalid:
+ av_log(s, AV_LOG_ERROR, "Invaid UTF8 sequence in avio_put_str16%s\n", be ? "be" : "le");
+ err = AVERROR(EINVAL);
}
- avio_wl16(s, 0);
+ if (be)
+ avio_wb16(s, 0);
+ else
+ avio_wl16(s, 0);
+ if (err)
+ return err;
ret += 2;
return ret;
}
+#define PUT_STR16(type, big_endian) \
+int avio_put_str16 ## type(AVIOContext *s, const char *str) \
+{ \
+return put_str16(s, str, big_endian); \
+}
+
+PUT_STR16(le, 0)
+PUT_STR16(be, 1)
+
+#undef PUT_STR16
+
int ff_get_v_length(uint64_t val)
{
int i = 1;
@@ -316,7 +396,7 @@ void ff_put_v(AVIOContext *bc, uint64_t val)
int i = ff_get_v_length(val);
while (--i > 0)
- avio_w8(bc, 128 | (val >> (7 * i)));
+ avio_w8(bc, 128 | (uint8_t)(val >> (7*i)));
avio_w8(bc, val & 127);
}
@@ -335,38 +415,37 @@ void avio_wb64(AVIOContext *s, uint64_t val)
void avio_wl16(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val);
- avio_w8(s, val >> 8);
+ avio_w8(s, (uint8_t)val);
+ avio_w8(s, (int)val >> 8);
}
void avio_wb16(AVIOContext *s, unsigned int val)
{
- avio_w8(s, val >> 8);
- avio_w8(s, val);
+ avio_w8(s, (int)val >> 8);
+ avio_w8(s, (uint8_t)val);
}
void avio_wl24(AVIOContext *s, unsigned int val)
{
avio_wl16(s, val & 0xffff);
- avio_w8(s, val >> 16);
+ avio_w8(s, (int)val >> 16);
}
void avio_wb24(AVIOContext *s, unsigned int val)
{
- avio_wb16(s, val >> 8);
- avio_w8(s, val);
+ avio_wb16(s, (int)val >> 8);
+ avio_w8(s, (uint8_t)val);
}
/* Input stream */
static void fill_buffer(AVIOContext *s)
{
- uint8_t *dst = !s->max_packet_size &&
- s->buf_end - s->buffer < s->buffer_size ?
- s->buf_end : s->buffer;
- int len = s->buffer_size - (dst - s->buffer);
int max_buffer_size = s->max_packet_size ?
s->max_packet_size : IO_BUFFER_SIZE;
+ uint8_t *dst = s->buf_end - s->buffer + max_buffer_size < s->buffer_size ?
+ s->buf_end : s->buffer;
+ int len = s->buffer_size - (dst - s->buffer);
/* can't fill the buffer without read_packet, just set EOF if appropriate */
if (!s->read_packet && s->buf_ptr >= s->buf_end)
@@ -384,11 +463,14 @@ static void fill_buffer(AVIOContext *s)
}
/* make buffer smaller in case it ended up large after probing */
- if (s->buffer_size > max_buffer_size) {
- ffio_set_buf_size(s, max_buffer_size);
+ if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size) {
+ if (dst == s->buffer) {
+ ffio_set_buf_size(s, s->orig_buffer_size);
- s->checksum_ptr = dst = s->buffer;
- len = s->buffer_size;
+ s->checksum_ptr = dst = s->buffer;
+ }
+ av_assert0(len >= s->orig_buffer_size);
+ len = s->orig_buffer_size;
}
if (s->read_packet)
@@ -405,6 +487,7 @@ static void fill_buffer(AVIOContext *s)
s->pos += len;
s->buf_ptr = dst;
s->buf_end = dst + len;
+ s->bytes_read += len;
}
}
@@ -459,7 +542,7 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
if (len > size)
len = size;
if (len == 0 || s->write_flag) {
- if(size > s->buffer_size && !s->update_checksum){
+ if((s->direct || size > s->buffer_size) && !s->update_checksum){
if(s->read_packet)
len = s->read_packet(s->opaque, buf, size);
if (len <= 0) {
@@ -471,6 +554,7 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
break;
} else {
s->pos += len;
+ s->bytes_read += len;
size -= len;
buf += len;
s->buf_ptr = s->buffer;
@@ -490,8 +574,8 @@ int avio_read(AVIOContext *s, unsigned char *buf, int size)
}
}
if (size1 == size) {
- if (s->error) return s->error;
- if (s->eof_reached) return AVERROR_EOF;
+ if (s->error) return s->error;
+ if (avio_feof(s)) return AVERROR_EOF;
}
return size1 - size;
}
@@ -539,8 +623,8 @@ int ffio_read_partial(AVIOContext *s, unsigned char *buf, int size)
memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len;
if (!len) {
- if (s->error) return s->error;
- if (s->eof_reached) return AVERROR_EOF;
+ if (s->error) return s->error;
+ if (avio_feof(s)) return AVERROR_EOF;
}
return len;
}
@@ -609,7 +693,9 @@ int ff_get_line(AVIOContext *s, char *buf, int maxlen)
c = avio_r8(s);
if (c && i < maxlen-1)
buf[i++] = c;
- } while (c != '\n' && c);
+ } while (c != '\n' && c != '\r' && c);
+ if (c == '\r' && avio_r8(s) != '\n' && !avio_feof(s))
+ avio_skip(s, -1);
buf[i] = 0;
return i;
@@ -699,6 +785,7 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
av_free(buffer);
return AVERROR(ENOMEM);
}
+ (*s)->direct = h->flags & AVIO_FLAG_DIRECT;
(*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL;
(*s)->max_packet_size = max_packet_size;
if(h->prot) {
@@ -709,6 +796,32 @@ int ffio_fdopen(AVIOContext **s, URLContext *h)
return 0;
}
+int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
+{
+ uint8_t *buffer;
+ int max_buffer_size = s->max_packet_size ?
+ s->max_packet_size : IO_BUFFER_SIZE;
+ int filled = s->buf_end - s->buffer;
+
+ buf_size += s->buf_ptr - s->buffer + max_buffer_size;
+
+ if (buf_size < filled || s->seekable || !s->read_packet)
+ return 0;
+ av_assert0(!s->write_flag);
+
+ buffer = av_malloc(buf_size);
+ if (!buffer)
+ return AVERROR(ENOMEM);
+
+ memcpy(buffer, s->buffer, filled);
+ av_free(s->buffer);
+ s->buf_ptr = buffer + (s->buf_ptr - s->buffer);
+ s->buf_end = buffer + (s->buf_end - s->buffer);
+ s->buffer = buffer;
+ s->buffer_size = buf_size;
+ return 0;
+}
+
int ffio_set_buf_size(AVIOContext *s, int buf_size)
{
uint8_t *buffer;
@@ -718,6 +831,7 @@ int ffio_set_buf_size(AVIOContext *s, int buf_size)
av_free(s->buffer);
s->buffer = buffer;
+ s->orig_buffer_size =
s->buffer_size = buf_size;
s->buf_ptr = buffer;
url_resetbuf(s, s->write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);
@@ -726,7 +840,7 @@ int ffio_set_buf_size(AVIOContext *s, int buf_size)
static int url_resetbuf(AVIOContext *s, int flags)
{
- assert(flags == AVIO_FLAG_WRITE || flags == AVIO_FLAG_READ);
+ av_assert1(flags == AVIO_FLAG_WRITE || flags == AVIO_FLAG_READ);
if (flags & AVIO_FLAG_WRITE) {
s->buf_end = s->buffer + s->buffer_size;
@@ -738,27 +852,32 @@ static int url_resetbuf(AVIOContext *s, int flags)
return 0;
}
-int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char *buf, int buf_size)
+int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **bufp, int buf_size)
{
int64_t buffer_start;
int buffer_size;
int overlap, new_size, alloc_size;
+ uint8_t *buf = *bufp;
- if (s->write_flag)
+ if (s->write_flag) {
+ av_freep(bufp);
return AVERROR(EINVAL);
+ }
buffer_size = s->buf_end - s->buffer;
/* the buffers must touch or overlap */
- if ((buffer_start = s->pos - buffer_size) > buf_size)
+ if ((buffer_start = s->pos - buffer_size) > buf_size) {
+ av_freep(bufp);
return AVERROR(EINVAL);
+ }
overlap = buf_size - buffer_start;
new_size = buf_size + buffer_size - overlap;
alloc_size = FFMAX(s->buffer_size, new_size);
if (alloc_size > buf_size)
- if (!(buf = av_realloc(buf, alloc_size)))
+ if (!(buf = (*bufp) = av_realloc_f(buf, 1, alloc_size)))
return AVERROR(ENOMEM);
if (new_size > buf_size) {
@@ -799,6 +918,12 @@ int avio_open2(AVIOContext **s, const char *filename, int flags,
return 0;
}
+int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags,
+ const AVIOInterruptCB *int_cb, AVDictionary **options)
+{
+ return avio_open2(pb, url, flags, int_cb, options);
+}
+
int avio_close(AVIOContext *s)
{
URLContext *h;
@@ -809,6 +934,10 @@ int avio_close(AVIOContext *s)
avio_flush(s);
h = s->opaque;
av_freep(&s->buffer);
+ if (s->write_flag)
+ av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count);
+ else
+ av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count);
av_free(s);
return ffurl_close(h);
}
@@ -860,6 +989,24 @@ int64_t avio_seek_time(AVIOContext *s, int stream_index,
return ret;
}
+int avio_read_to_bprint(AVIOContext *h, AVBPrint *pb, size_t max_size)
+{
+ int ret;
+ char buf[1024];
+ while (max_size) {
+ ret = avio_read(h, buf, FFMIN(max_size, sizeof(buf)));
+ if (ret == AVERROR_EOF)
+ return 0;
+ if (ret <= 0)
+ return ret;
+ av_bprint_append_data(pb, buf, ret);
+ if (!av_bprint_is_complete(pb))
+ return AVERROR(ENOMEM);
+ max_size -= ret;
+ }
+ return 0;
+}
+
/* output in a dynamic buffer */
typedef struct DynBuffer {
diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c
index 1a6a73f53e..7dc5ee7df6 100644
--- a/libavformat/avisynth.c
+++ b/libavformat/avisynth.c
@@ -2,20 +2,19 @@
* AviSynth/AvxSynth support
* Copyright (c) 2012 AvxSynth Team.
*
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,12 +31,12 @@
#ifdef _WIN32
#include <windows.h>
#undef EXTERN_C
- #include <avisynth/avisynth_c.h>
+ #include "compat/avisynth/avisynth_c.h"
#define AVISYNTH_LIB "avisynth"
#define USING_AVISYNTH
#else
#include <dlfcn.h>
- #include <avxsynth/avxsynth_c.h>
+ #include "compat/avisynth/avxsynth_c.h"
#define AVISYNTH_NAME "libavxsynth"
#define AVISYNTH_LIB AVISYNTH_NAME SLIBSUF
@@ -405,7 +404,7 @@ static int avisynth_open_file(AVFormatContext *s)
avs->vi = avs_library.avs_get_video_info(avs->clip);
#ifdef USING_AVISYNTH
- /* On Windows, libav supports AviSynth interface version 6 or higher.
+ /* 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. Since AvxSynth identifies itself
* as interface version 3 like 2.5.8, this needs to be special-cased. */
diff --git a/libavformat/avlanguage.c b/libavformat/avlanguage.c
index e606ef22f9..39f2560d94 100644
--- a/libavformat/avlanguage.c
+++ b/libavformat/avlanguage.c
@@ -1,20 +1,20 @@
/*
* Cyril Comparon, Larbi Joubala, Resonate-MP4 2009
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/avlanguage.h b/libavformat/avlanguage.h
index 2ec3e2d372..7fb8968810 100644
--- a/libavformat/avlanguage.h
+++ b/libavformat/avlanguage.h
@@ -1,20 +1,20 @@
/*
* Cyril Comparon, Larbi Joubala, Resonate-MP4 2009
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/avr.c b/libavformat/avr.c
new file mode 100644
index 0000000000..a33134eed5
--- /dev/null
+++ b/libavformat/avr.c
@@ -0,0 +1,99 @@
+/*
+ * AVR demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+
+static int avr_probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) != MKTAG('2', 'B', 'I', 'T'))
+ return 0;
+
+ if (!AV_RB16(p->buf+12) || AV_RB16(p->buf+12) > 256) // channels
+ return AVPROBE_SCORE_EXTENSION/2;
+ if (AV_RB16(p->buf+14) > 256) // bps
+ return AVPROBE_SCORE_EXTENSION/2;
+
+ return AVPROBE_SCORE_EXTENSION;
+}
+
+static int avr_read_header(AVFormatContext *s)
+{
+ uint16_t chan, sign, bps;
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ avio_skip(s->pb, 4); // magic
+ avio_skip(s->pb, 8); // sample_name
+
+ chan = avio_rb16(s->pb);
+ if (!chan) {
+ st->codec->channels = 1;
+ } else if (chan == 0xFFFFu) {
+ st->codec->channels = 2;
+ } else {
+ avpriv_request_sample(s, "chan %d", chan);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ st->codec->bits_per_coded_sample = bps = avio_rb16(s->pb);
+
+ sign = avio_rb16(s->pb);
+
+ avio_skip(s->pb, 2); // loop
+ avio_skip(s->pb, 2); // midi
+ avio_skip(s->pb, 1); // replay speed
+
+ st->codec->sample_rate = avio_rb24(s->pb);
+ avio_skip(s->pb, 4 * 3);
+ avio_skip(s->pb, 2 * 3);
+ avio_skip(s->pb, 20);
+ avio_skip(s->pb, 64);
+
+ st->codec->codec_id = ff_get_pcm_codec_id(bps, 0, 1, sign);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) {
+ avpriv_request_sample(s, "Bps %d and sign %d", bps, sign);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ st->codec->block_align = bps * st->codec->channels / 8;
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ return 0;
+}
+
+AVInputFormat ff_avr_demuxer = {
+ .name = "avr",
+ .long_name = NULL_IF_CONFIG_SMALL("AVR (Audio Visual Research)"),
+ .read_probe = avr_probe,
+ .read_header = avr_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "avr",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/avs.c b/libavformat/avs.c
index d8042c51f9..b699dbf9ba 100644
--- a/libavformat/avs.c
+++ b/libavformat/avs.c
@@ -2,20 +2,20 @@
* AVS demuxer.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,7 +52,7 @@ static int avs_probe(AVProbeData * p)
if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0)
/* Ensure the buffer probe scores higher than the extension probe.
* This avoids problems with misdetection as AviSynth scripts. */
- return AVPROBE_SCORE_EXTENSION + 1;
+ return AVPROBE_SCORE_EXTENSION + 5;
return 0;
}
@@ -190,6 +190,9 @@ static int avs_read_packet(AVFormatContext * s, AVPacket * pkt)
avs->st_video->codec->height = avs->height;
avs->st_video->codec->bits_per_coded_sample=avs->bits_per_sample;
avs->st_video->nb_frames = avs->nb_frames;
+#if FF_API_R_FRAME_RATE
+ avs->st_video->r_frame_rate =
+#endif
avs->st_video->avg_frame_rate = (AVRational){avs->fps, 1};
}
return avs_read_video_packet(s, pkt, type, sub_type, size,
diff --git a/libavformat/bethsoftvid.c b/libavformat/bethsoftvid.c
index 135a3c491a..40a425271d 100644
--- a/libavformat/bethsoftvid.c
+++ b/libavformat/bethsoftvid.c
@@ -2,20 +2,20 @@
* Bethsoft VID format Demuxer
* Copyright (c) 2007 Nicholas Tung
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,6 +61,9 @@ static int vid_probe(AVProbeData *p)
if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0))
return 0;
+ if (p->buf[4] != 2)
+ return AVPROBE_SCORE_MAX / 4;
+
return AVPROBE_SCORE_MAX;
}
@@ -190,9 +193,11 @@ static int read_frame(BVID_DemuxContext *vid, AVIOContext *pb, AVPacket *pkt,
BVID_PALETTE_SIZE);
if (!pdata) {
ret = AVERROR(ENOMEM);
+ av_log(s, AV_LOG_ERROR, "Failed to allocate palette side data\n");
goto fail;
}
memcpy(pdata, vid->palette, BVID_PALETTE_SIZE);
+
av_freep(&vid->palette);
}
@@ -211,8 +216,8 @@ static int vid_read_packet(AVFormatContext *s,
int audio_length;
int ret_value;
- if(vid->is_finished || pb->eof_reached)
- return AVERROR(EIO);
+ if(vid->is_finished || avio_feof(pb))
+ return AVERROR_EOF;
block_type = avio_r8(pb);
switch(block_type){
diff --git a/libavformat/bfi.c b/libavformat/bfi.c
index 19060e760f..cc7f4948c9 100644
--- a/libavformat/bfi.c
+++ b/libavformat/bfi.c
@@ -2,20 +2,20 @@
* Brute Force & Ignorance (BFI) demuxer
* Copyright (c) 2008 Sisir Koppaka
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,6 +81,8 @@ static int bfi_read_header(AVFormatContext * s)
/*Load the palette to extradata */
avio_skip(pb, 8);
vstream->codec->extradata = av_malloc(768);
+ if (!vstream->codec->extradata)
+ return AVERROR(ENOMEM);
vstream->codec->extradata_size = 768;
avio_read(pb, vstream->codec->extradata,
vstream->codec->extradata_size);
@@ -92,6 +94,8 @@ static int bfi_read_header(AVFormatContext * s)
vstream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vstream->codec->codec_id = AV_CODEC_ID_BFI;
vstream->codec->pix_fmt = AV_PIX_FMT_PAL8;
+ vstream->nb_frames =
+ vstream->duration = bfi->nframes;
/* Set up the audio codec now... */
astream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
@@ -112,15 +116,15 @@ static int bfi_read_packet(AVFormatContext * s, AVPacket * pkt)
BFIContext *bfi = s->priv_data;
AVIOContext *pb = s->pb;
int ret, audio_offset, video_offset, chunk_size, audio_size = 0;
- if (bfi->nframes == 0 || pb->eof_reached) {
- return AVERROR(EIO);
+ if (bfi->nframes == 0 || avio_feof(pb)) {
+ return AVERROR_EOF;
}
/* If all previous chunks were completely read, then find a new one... */
if (!bfi->avflag) {
uint32_t state = 0;
while(state != MKTAG('S','A','V','I')){
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
state = 256*state + avio_r8(pb);
}
diff --git a/libavformat/bink.c b/libavformat/bink.c
index 3224790485..332edbb7d9 100644
--- a/libavformat/bink.c
+++ b/libavformat/bink.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008-2010 Peter Ross (pross@xvid.org)
* Copyright (c) 2009 Daniel Verkamp (daniel@drv.nu)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,8 +61,10 @@ static int probe(AVProbeData *p)
{
const uint8_t *b = p->buf;
- if ( b[0] == 'B' && b[1] == 'I' && b[2] == 'K' &&
- (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i') &&
+ if (((b[0] == 'B' && b[1] == 'I' && b[2] == 'K' &&
+ (b[3] == 'b' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || b[3] == 'i')) ||
+ (b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */
+ (b[3] == 'a' || b[3] == 'd' || b[3] == 'f' || b[3] == 'g'))) &&
AV_RL32(b+8) > 0 && // num_frames
AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH &&
AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT &&
@@ -81,6 +83,7 @@ static int read_header(AVFormatContext *s)
uint32_t pos, next_pos;
uint16_t flags;
int keyframe;
+ int ret;
vst = avformat_new_stream(s, NULL);
if (!vst)
@@ -120,11 +123,14 @@ static int read_header(AVFormatContext *s)
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = AV_CODEC_ID_BINKVIDEO;
- vst->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!vst->codec->extradata)
+
+ if ((vst->codec->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) {
+ av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n");
+ vst->codec->codec_id = AV_CODEC_ID_NONE;
+ }
+
+ if (ff_get_extradata(vst->codec, pb, 4) < 0)
return AVERROR(ENOMEM);
- vst->codec->extradata_size = 4;
- avio_read(pb, vst->codec->extradata, 4);
bink->num_audio_tracks = avio_rl32(pb);
@@ -156,10 +162,8 @@ static int read_header(AVFormatContext *s)
ast->codec->channels = 1;
ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
}
- ast->codec->extradata = av_mallocz(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!ast->codec->extradata)
+ if (ff_alloc_extradata(ast->codec, 4))
return AVERROR(ENOMEM);
- ast->codec->extradata_size = 4;
AV_WL32(ast->codec->extradata, vst->codec->codec_tag);
}
@@ -185,11 +189,15 @@ static int read_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "invalid frame index table\n");
return AVERROR(EIO);
}
- av_add_index_entry(vst, pos, i, next_pos - pos, 0,
- keyframe ? AVINDEX_KEYFRAME : 0);
+ if ((ret = av_add_index_entry(vst, pos, i, next_pos - pos, 0,
+ keyframe ? AVINDEX_KEYFRAME : 0)) < 0)
+ return ret;
}
- avio_skip(pb, 4);
+ if (vst->index_entries)
+ avio_seek(pb, vst->index_entries[0].pos, SEEK_SET);
+ else
+ avio_skip(pb, 4);
bink->current_track = -1;
return 0;
@@ -206,7 +214,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *st = s->streams[0]; // stream 0 is video stream with index
if (bink->video_pts >= st->duration)
- return AVERROR(EIO);
+ return AVERROR_EOF;
index_entry = av_index_search_timestamp(st, bink->video_pts,
AVSEEK_FLAG_ANY);
@@ -288,4 +296,5 @@ AVInputFormat ff_bink_demuxer = {
.read_header = read_header,
.read_packet = read_packet,
.read_seek = read_seek,
+ .flags = AVFMT_SHOW_IDS,
};
diff --git a/libavformat/bintext.c b/libavformat/bintext.c
new file mode 100644
index 0000000000..217ea49247
--- /dev/null
+++ b/libavformat/bintext.c
@@ -0,0 +1,388 @@
+/*
+ * Binary text demuxer
+ * eXtended BINary text (XBIN) demuxer
+ * Artworx Data Format demuxer
+ * iCEDraw File demuxer
+ * Copyright (c) 2010 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Binary text demuxer
+ * eXtended BINary text (XBIN) demuxer
+ * Artworx Data Format demuxer
+ * iCEDraw File demuxer
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "avformat.h"
+#include "internal.h"
+#include "sauce.h"
+#include "libavcodec/bintext.h"
+
+typedef struct {
+ const AVClass *class;
+ int chars_per_frame; /**< characters to send decoder per frame;
+ set by private options as characters per second, and then
+ converted to characters per frame at runtime */
+ int width, height; /**< video size (WxH pixels) (private option) */
+ AVRational framerate; /**< frames per second (private option) */
+ uint64_t fsize; /**< file size less metadata buffer */
+} BinDemuxContext;
+
+static AVStream * init_stream(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return NULL;
+ st->codec->codec_tag = 0;
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+
+ if (!bin->width) {
+ st->codec->width = (80<<3);
+ st->codec->height = (25<<4);
+ }
+
+ avpriv_set_pts_info(st, 60, bin->framerate.den, bin->framerate.num);
+
+ /* simulate tty display speed */
+ bin->chars_per_frame = av_clip(av_q2d(st->time_base) * bin->chars_per_frame, 1, INT_MAX);
+
+ return st;
+}
+
+#if CONFIG_BINTEXT_DEMUXER | CONFIG_ADF_DEMUXER | CONFIG_IDF_DEMUXER
+/**
+ * Given filesize and width, calculate height (assume font_height of 16)
+ */
+static void calculate_height(AVCodecContext *avctx, uint64_t fsize)
+{
+ avctx->height = (fsize / ((avctx->width>>3)*2)) << 4;
+}
+#endif
+
+#if CONFIG_BINTEXT_DEMUXER
+static const uint8_t next_magic[]={
+ 0x1A, 0x1B, '[', '0', ';', '3', '0', ';', '4', '0', 'm', 'N', 'E', 'X', 'T', 0x00
+};
+
+static int next_tag_read(AVFormatContext *avctx, uint64_t *fsize)
+{
+ AVIOContext *pb = avctx->pb;
+ char buf[36];
+ int len;
+ uint64_t start_pos = avio_size(pb) - 256;
+
+ avio_seek(pb, start_pos, SEEK_SET);
+ if (avio_read(pb, buf, sizeof(next_magic)) != sizeof(next_magic))
+ return -1;
+ if (memcmp(buf, next_magic, sizeof(next_magic)))
+ return -1;
+ if (avio_r8(pb) != 0x01)
+ return -1;
+
+ *fsize -= 256;
+
+#define GET_EFI2_META(name,size) \
+ len = avio_r8(pb); \
+ if (len < 1 || len > size) \
+ return -1; \
+ if (avio_read(pb, buf, size) == size && *buf) { \
+ buf[len] = 0; \
+ av_dict_set(&avctx->metadata, name, buf, 0); \
+ }
+
+ GET_EFI2_META("filename", 12)
+ GET_EFI2_META("author", 20)
+ GET_EFI2_META("publisher", 20)
+ GET_EFI2_META("title", 35)
+
+ return 0;
+}
+
+static void predict_width(AVCodecContext *avctx, uint64_t fsize, int got_width)
+{
+ /** attempt to guess width */
+ if (!got_width)
+ avctx->width = fsize > 4000 ? (160<<3) : (80<<3);
+}
+
+static int bintext_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ AVStream *st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_id = AV_CODEC_ID_BINTEXT;
+
+ if (ff_alloc_extradata(st->codec, 2))
+ return AVERROR(ENOMEM);
+ st->codec->extradata[0] = 16;
+ st->codec->extradata[1] = 0;
+
+ if (pb->seekable) {
+ int got_width = 0;
+ bin->fsize = avio_size(pb);
+ if (ff_sauce_read(s, &bin->fsize, &got_width, 0) < 0)
+ next_tag_read(s, &bin->fsize);
+ if (!bin->width) {
+ predict_width(st->codec, bin->fsize, got_width);
+ calculate_height(st->codec, bin->fsize);
+ }
+ avio_seek(pb, 0, SEEK_SET);
+ }
+ return 0;
+}
+#endif /* CONFIG_BINTEXT_DEMUXER */
+
+#if CONFIG_XBIN_DEMUXER
+static int xbin_probe(AVProbeData *p)
+{
+ const uint8_t *d = p->buf;
+
+ if (AV_RL32(d) == MKTAG('X','B','I','N') && d[4] == 0x1A &&
+ AV_RL16(d+5) > 0 && AV_RL16(d+5) <= 160 &&
+ d[9] > 0 && d[9] <= 32)
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int xbin_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+ char fontheight, flags;
+
+ AVStream *st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 5);
+ st->codec->width = avio_rl16(pb)<<3;
+ st->codec->height = avio_rl16(pb);
+ fontheight = avio_r8(pb);
+ st->codec->height *= fontheight;
+ flags = avio_r8(pb);
+
+ st->codec->extradata_size = 2;
+ if ((flags & BINTEXT_PALETTE))
+ st->codec->extradata_size += 48;
+ if ((flags & BINTEXT_FONT))
+ st->codec->extradata_size += fontheight * (flags & 0x10 ? 512 : 256);
+ st->codec->codec_id = flags & 4 ? AV_CODEC_ID_XBIN : AV_CODEC_ID_BINTEXT;
+
+ if (ff_alloc_extradata(st->codec, st->codec->extradata_size))
+ return AVERROR(ENOMEM);
+ st->codec->extradata[0] = fontheight;
+ st->codec->extradata[1] = flags;
+ if (avio_read(pb, st->codec->extradata + 2, st->codec->extradata_size - 2) < 0)
+ return AVERROR(EIO);
+
+ if (pb->seekable) {
+ bin->fsize = avio_size(pb) - 9 - st->codec->extradata_size;
+ ff_sauce_read(s, &bin->fsize, NULL, 0);
+ avio_seek(pb, 9 + st->codec->extradata_size, SEEK_SET);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_XBIN_DEMUXER */
+
+#if CONFIG_ADF_DEMUXER
+static int adf_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+
+ if (avio_r8(pb) != 1)
+ return AVERROR_INVALIDDATA;
+
+ st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_id = AV_CODEC_ID_BINTEXT;
+
+ if (ff_alloc_extradata(st->codec, 2 + 48 + 4096))
+ return AVERROR(ENOMEM);
+ st->codec->extradata[0] = 16;
+ st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
+
+ if (avio_read(pb, st->codec->extradata + 2, 24) < 0)
+ return AVERROR(EIO);
+ avio_skip(pb, 144);
+ if (avio_read(pb, st->codec->extradata + 2 + 24, 24) < 0)
+ return AVERROR(EIO);
+ if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
+ return AVERROR(EIO);
+
+ if (pb->seekable) {
+ int got_width = 0;
+ bin->fsize = avio_size(pb) - 1 - 192 - 4096;
+ st->codec->width = 80<<3;
+ ff_sauce_read(s, &bin->fsize, &got_width, 0);
+ if (!bin->width)
+ calculate_height(st->codec, bin->fsize);
+ avio_seek(pb, 1 + 192 + 4096, SEEK_SET);
+ }
+ return 0;
+}
+#endif /* CONFIG_ADF_DEMUXER */
+
+#if CONFIG_IDF_DEMUXER
+static const uint8_t idf_magic[] = {
+ 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00
+};
+
+static int idf_probe(AVProbeData *p)
+{
+ if (p->buf_size < sizeof(idf_magic))
+ return 0;
+ if (!memcmp(p->buf, idf_magic, sizeof(idf_magic)))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int idf_read_header(AVFormatContext *s)
+{
+ BinDemuxContext *bin = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ int got_width = 0;
+
+ if (!pb->seekable)
+ return AVERROR(EIO);
+
+ st = init_stream(s);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_id = AV_CODEC_ID_IDF;
+
+ if (ff_alloc_extradata(st->codec, 2 + 48 + 4096))
+ return AVERROR(ENOMEM);
+ st->codec->extradata[0] = 16;
+ st->codec->extradata[1] = BINTEXT_PALETTE|BINTEXT_FONT;
+
+ avio_seek(pb, avio_size(pb) - 4096 - 48, SEEK_SET);
+
+ if (avio_read(pb, st->codec->extradata + 2 + 48, 4096) < 0)
+ return AVERROR(EIO);
+ if (avio_read(pb, st->codec->extradata + 2, 48) < 0)
+ return AVERROR(EIO);
+
+ bin->fsize = avio_size(pb) - 12 - 4096 - 48;
+ ff_sauce_read(s, &bin->fsize, &got_width, 0);
+ if (!bin->width)
+ calculate_height(st->codec, bin->fsize);
+ avio_seek(pb, 12, SEEK_SET);
+ return 0;
+}
+#endif /* CONFIG_IDF_DEMUXER */
+
+static int read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ BinDemuxContext *bin = s->priv_data;
+
+ if (bin->fsize > 0) {
+ if (av_get_packet(s->pb, pkt, bin->fsize) < 0)
+ return AVERROR(EIO);
+ bin->fsize = -1; /* done */
+ } else if (!bin->fsize) {
+ if (avio_feof(s->pb))
+ return AVERROR(EIO);
+ if (av_get_packet(s->pb, pkt, bin->chars_per_frame) < 0)
+ return AVERROR(EIO);
+ } else {
+ return AVERROR(EIO);
+ }
+
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ return 0;
+}
+
+#define OFFSET(x) offsetof(BinDemuxContext, x)
+static const AVOption options[] = {
+ { "linespeed", "set simulated line speed (bytes per second)", OFFSET(chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
+ { "video_size", "set video size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { "framerate", "set framerate (frames per second)", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+#define CLASS(name) \
+(const AVClass[1]){{ \
+ .class_name = name, \
+ .item_name = av_default_item_name, \
+ .option = options, \
+ .version = LIBAVUTIL_VERSION_INT, \
+}}
+
+#if CONFIG_BINTEXT_DEMUXER
+AVInputFormat ff_bintext_demuxer = {
+ .name = "bin",
+ .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_header = bintext_read_header,
+ .read_packet = read_packet,
+ .extensions = "bin",
+ .priv_class = CLASS("Binary text demuxer"),
+};
+#endif
+
+#if CONFIG_XBIN_DEMUXER
+AVInputFormat ff_xbin_demuxer = {
+ .name = "xbin",
+ .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text (XBIN)"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_probe = xbin_probe,
+ .read_header = xbin_read_header,
+ .read_packet = read_packet,
+ .priv_class = CLASS("eXtended BINary text (XBIN) demuxer"),
+};
+#endif
+
+#if CONFIG_ADF_DEMUXER
+AVInputFormat ff_adf_demuxer = {
+ .name = "adf",
+ .long_name = NULL_IF_CONFIG_SMALL("Artworx Data Format"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_header = adf_read_header,
+ .read_packet = read_packet,
+ .extensions = "adf",
+ .priv_class = CLASS("Artworx Data Format demuxer"),
+};
+#endif
+
+#if CONFIG_IDF_DEMUXER
+AVInputFormat ff_idf_demuxer = {
+ .name = "idf",
+ .long_name = NULL_IF_CONFIG_SMALL("iCE Draw File"),
+ .priv_data_size = sizeof(BinDemuxContext),
+ .read_probe = idf_probe,
+ .read_header = idf_read_header,
+ .read_packet = read_packet,
+ .extensions = "idf",
+ .priv_class = CLASS("iCE Draw File demuxer"),
+};
+#endif
diff --git a/libavformat/bit.c b/libavformat/bit.c
new file mode 100644
index 0000000000..138d2feadb
--- /dev/null
+++ b/libavformat/bit.c
@@ -0,0 +1,163 @@
+/*
+ * G.729 bit format muxer and demuxer
+ * Copyright (c) 2007-2008 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+#include "libavcodec/get_bits.h"
+#include "libavcodec/put_bits.h"
+
+#define MAX_FRAME_SIZE 10
+
+#define SYNC_WORD 0x6b21
+#define BIT_0 0x7f
+#define BIT_1 0x81
+
+static int probe(AVProbeData *p)
+{
+ int i, j;
+
+ if(p->buf_size < 0x40)
+ return 0;
+
+ for(i=0; i+3<p->buf_size && i< 10*0x50; ){
+ if(AV_RL16(&p->buf[0]) != SYNC_WORD)
+ return 0;
+ j=AV_RL16(&p->buf[2]);
+ if(j!=0x40 && j!=0x50)
+ return 0;
+ i+=j;
+ }
+ return AVPROBE_SCORE_EXTENSION;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ AVStream* st;
+
+ st=avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id=AV_CODEC_ID_G729;
+ st->codec->sample_rate=8000;
+ st->codec->block_align = 16;
+ st->codec->channels=1;
+
+ avpriv_set_pts_info(st, 64, 1, 100);
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s,
+ AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ PutBitContext pbo;
+ uint16_t buf[8 * MAX_FRAME_SIZE + 2];
+ int packet_size;
+ uint16_t* src=buf;
+ int i, j, ret;
+ int64_t pos= avio_tell(pb);
+
+ if(avio_feof(pb))
+ return AVERROR_EOF;
+
+ avio_rl16(pb); // sync word
+ packet_size = avio_rl16(pb) / 8;
+ if(packet_size > MAX_FRAME_SIZE)
+ return AVERROR_INVALIDDATA;
+
+ ret = avio_read(pb, (uint8_t*)buf, (8 * packet_size) * sizeof(uint16_t));
+ if(ret<0)
+ return ret;
+ if(ret != 8 * packet_size * sizeof(uint16_t))
+ return AVERROR(EIO);
+
+ if (av_new_packet(pkt, packet_size) < 0)
+ return AVERROR(ENOMEM);
+
+ init_put_bits(&pbo, pkt->data, packet_size);
+ for(j=0; j < packet_size; j++)
+ for(i=0; i<8;i++)
+ put_bits(&pbo,1, AV_RL16(src++) == BIT_1 ? 1 : 0);
+
+ flush_put_bits(&pbo);
+
+ pkt->duration=1;
+ pkt->pos = pos;
+ return 0;
+}
+
+AVInputFormat ff_bit_demuxer = {
+ .name = "bit",
+ .long_name = NULL_IF_CONFIG_SMALL("G.729 BIT file format"),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .extensions = "bit",
+};
+
+#if CONFIG_MUXERS
+static int write_header(AVFormatContext *s)
+{
+ AVCodecContext *enc = s->streams[0]->codec;
+
+ if ((enc->codec_id != AV_CODEC_ID_G729) || enc->channels != 1) {
+ av_log(s, AV_LOG_ERROR,
+ "only codec g729 with 1 channel is supported by this format\n");
+ return AVERROR(EINVAL);
+ }
+
+ enc->bits_per_coded_sample = 16;
+ enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
+
+ return 0;
+}
+
+static int write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ GetBitContext gb;
+ int i;
+
+ if (pkt->size != 10)
+ return AVERROR(EINVAL);
+
+ avio_wl16(pb, SYNC_WORD);
+ avio_wl16(pb, 8 * 10);
+
+ init_get_bits(&gb, pkt->data, 8*10);
+ for(i=0; i< 8 * 10; i++)
+ avio_wl16(pb, get_bits1(&gb) ? BIT_1 : BIT_0);
+
+ return 0;
+}
+
+AVOutputFormat ff_bit_muxer = {
+ .name = "bit",
+ .long_name = NULL_IF_CONFIG_SMALL("G.729 BIT file format"),
+ .mime_type = "audio/bit",
+ .extensions = "bit",
+ .audio_codec = AV_CODEC_ID_G729,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = write_header,
+ .write_packet = write_packet,
+};
+#endif
diff --git a/libavformat/bluray.c b/libavformat/bluray.c
new file mode 100644
index 0000000000..d2c57aab9c
--- /dev/null
+++ b/libavformat/bluray.c
@@ -0,0 +1,235 @@
+/*
+ * BluRay (libbluray) protocol
+ *
+ * Copyright (c) 2012 Petri Hintukainen <phintuka <at> users.sourceforge.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <libbluray/bluray.h>
+
+#include "libavutil/avstring.h"
+#include "libavformat/avformat.h"
+#include "libavformat/url.h"
+#include "libavutil/opt.h"
+
+#define BLURAY_PROTO_PREFIX "bluray:"
+#define MIN_PLAYLIST_LENGTH 180 /* 3 min */
+
+typedef struct {
+ const AVClass *class;
+
+ BLURAY *bd;
+
+ int playlist;
+ int angle;
+ int chapter;
+ /*int region;*/
+} BlurayContext;
+
+#define OFFSET(x) offsetof(BlurayContext, x)
+static const AVOption options[] = {
+{"playlist", "", OFFSET(playlist), AV_OPT_TYPE_INT, { .i64=-1 }, -1, 99999, AV_OPT_FLAG_DECODING_PARAM },
+{"angle", "", OFFSET(angle), AV_OPT_TYPE_INT, { .i64=0 }, 0, 0xfe, AV_OPT_FLAG_DECODING_PARAM },
+{"chapter", "", OFFSET(chapter), AV_OPT_TYPE_INT, { .i64=1 }, 1, 0xfffe, AV_OPT_FLAG_DECODING_PARAM },
+/*{"region", "bluray player region code (1 = region A, 2 = region B, 4 = region C)", OFFSET(region), AV_OPT_TYPE_INT, { .i64=0 }, 0, 3, AV_OPT_FLAG_DECODING_PARAM },*/
+{NULL}
+};
+
+static const AVClass bluray_context_class = {
+ .class_name = "bluray",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+
+static int check_disc_info(URLContext *h)
+{
+ BlurayContext *bd = h->priv_data;
+ const BLURAY_DISC_INFO *disc_info;
+
+ disc_info = bd_get_disc_info(bd->bd);
+ if (!disc_info) {
+ av_log(h, AV_LOG_ERROR, "bd_get_disc_info() failed\n");
+ return -1;
+ }
+
+ if (!disc_info->bluray_detected) {
+ av_log(h, AV_LOG_ERROR, "BluRay disc not detected\n");
+ return -1;
+ }
+
+ /* AACS */
+ if (disc_info->aacs_detected && !disc_info->aacs_handled) {
+ if (!disc_info->libaacs_detected) {
+ av_log(h, AV_LOG_ERROR,
+ "Media stream encrypted with AACS, install and configure libaacs\n");
+ } else {
+ av_log(h, AV_LOG_ERROR, "Your libaacs can't decrypt this media\n");
+ }
+ return -1;
+ }
+
+ /* BD+ */
+ if (disc_info->bdplus_detected && !disc_info->bdplus_handled) {
+ /*
+ if (!disc_info->libbdplus_detected) {
+ av_log(h, AV_LOG_ERROR,
+ "Media stream encrypted with BD+, install and configure libbdplus");
+ } else {
+ */
+ av_log(h, AV_LOG_ERROR, "Unable to decrypt BD+ encrypted media\n");
+ /*}*/
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bluray_close(URLContext *h)
+{
+ BlurayContext *bd = h->priv_data;
+ if (bd->bd) {
+ bd_close(bd->bd);
+ }
+
+ return 0;
+}
+
+static int bluray_open(URLContext *h, const char *path, int flags)
+{
+ BlurayContext *bd = h->priv_data;
+ int num_title_idx;
+ const char *diskname = path;
+
+ av_strstart(path, BLURAY_PROTO_PREFIX, &diskname);
+
+ bd->bd = bd_open(diskname, NULL);
+ if (!bd->bd) {
+ av_log(h, AV_LOG_ERROR, "bd_open() failed\n");
+ return AVERROR(EIO);
+ }
+
+ /* check if disc can be played */
+ if (check_disc_info(h) < 0) {
+ return AVERROR(EIO);
+ }
+
+ /* setup player registers */
+ /* region code has no effect without menus
+ if (bd->region > 0 && bd->region < 5) {
+ av_log(h, AV_LOG_INFO, "setting region code to %d (%c)\n", bd->region, 'A' + (bd->region - 1));
+ bd_set_player_setting(bd->bd, BLURAY_PLAYER_SETTING_REGION_CODE, bd->region);
+ }
+ */
+
+ /* load title list */
+ num_title_idx = bd_get_titles(bd->bd, TITLES_RELEVANT, MIN_PLAYLIST_LENGTH);
+ av_log(h, AV_LOG_INFO, "%d usable playlists:\n", num_title_idx);
+ if (num_title_idx < 1) {
+ return AVERROR(EIO);
+ }
+
+ /* if playlist was not given, select longest playlist */
+ if (bd->playlist < 0) {
+ uint64_t duration = 0;
+ int i;
+ for (i = 0; i < num_title_idx; i++) {
+ BLURAY_TITLE_INFO *info = bd_get_title_info(bd->bd, i, 0);
+
+ av_log(h, AV_LOG_INFO, "playlist %05d.mpls (%d:%02d:%02d)\n",
+ info->playlist,
+ ((int)(info->duration / 90000) / 3600),
+ ((int)(info->duration / 90000) % 3600) / 60,
+ ((int)(info->duration / 90000) % 60));
+
+ if (info->duration > duration) {
+ bd->playlist = info->playlist;
+ duration = info->duration;
+ }
+
+ bd_free_title_info(info);
+ }
+ av_log(h, AV_LOG_INFO, "selected %05d.mpls\n", bd->playlist);
+ }
+
+ /* select playlist */
+ if (bd_select_playlist(bd->bd, bd->playlist) <= 0) {
+ av_log(h, AV_LOG_ERROR, "bd_select_playlist(%05d.mpls) failed\n", bd->playlist);
+ return AVERROR(EIO);
+ }
+
+ /* select angle */
+ if (bd->angle >= 0) {
+ bd_select_angle(bd->bd, bd->angle);
+ }
+
+ /* select chapter */
+ if (bd->chapter > 1) {
+ bd_seek_chapter(bd->bd, bd->chapter - 1);
+ }
+
+ return 0;
+}
+
+static int bluray_read(URLContext *h, unsigned char *buf, int size)
+{
+ BlurayContext *bd = h->priv_data;
+ int len;
+
+ if (!bd || !bd->bd) {
+ return AVERROR(EFAULT);
+ }
+
+ len = bd_read(bd->bd, buf, size);
+
+ return len;
+}
+
+static int64_t bluray_seek(URLContext *h, int64_t pos, int whence)
+{
+ BlurayContext *bd = h->priv_data;
+
+ if (!bd || !bd->bd) {
+ return AVERROR(EFAULT);
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ case SEEK_CUR:
+ case SEEK_END:
+ return bd_seek(bd->bd, pos);
+
+ case AVSEEK_SIZE:
+ return bd_get_title_size(bd->bd);
+ }
+
+ av_log(h, AV_LOG_ERROR, "Unsupported whence operation %d\n", whence);
+ return AVERROR(EINVAL);
+}
+
+
+URLProtocol ff_bluray_protocol = {
+ .name = "bluray",
+ .url_close = bluray_close,
+ .url_open = bluray_open,
+ .url_read = bluray_read,
+ .url_seek = bluray_seek,
+ .priv_data_size = sizeof(BlurayContext),
+ .priv_data_class = &bluray_context_class,
+};
diff --git a/libavformat/bmv.c b/libavformat/bmv.c
index b5572aff37..f7a6068af3 100644
--- a/libavformat/bmv.c
+++ b/libavformat/bmv.c
@@ -2,20 +2,20 @@
* Discworld II BMV demuxer
* Copyright (c) 2011 Konstantin Shishkov.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/boadec.c b/libavformat/boadec.c
new file mode 100644
index 0000000000..be003e59c1
--- /dev/null
+++ b/libavformat/boadec.c
@@ -0,0 +1,79 @@
+/*
+ * Black ops audio demuxer
+ * Copyright (c) 2013 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+
+static int probe(AVProbeData *p)
+{
+ if (p->buf_size < 2096)
+ return 0;
+ if ( AV_RL32(p->buf ) != 1
+ || AV_RL32(p->buf + 8) > 100000
+ || AV_RL32(p->buf + 12) > 8
+ || AV_RL32(p->buf + 16) != 2096
+ ||!AV_RL32(p->buf + 21)
+ || AV_RL16(p->buf + 25) != 2096
+ || AV_RL32(p->buf + 48) % AV_RL32(p->buf + 21)
+ )
+ return 0;
+ return AVPROBE_SCORE_EXTENSION;
+}
+
+
+static int read_header(AVFormatContext *s)
+{
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_MS;
+
+ avio_rl32(s->pb);
+ avio_rl32(s->pb);
+ st->codec->sample_rate = avio_rl32(s->pb);
+ st->codec->channels = avio_rl32(s->pb);
+ s->internal->data_offset = avio_rl32(s->pb);
+ avio_r8(s->pb);
+ st->codec->block_align = st->codec->channels * avio_rl32(s->pb);
+
+ avio_seek(s->pb, s->internal->data_offset, SEEK_SET);
+
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVStream *st = s->streams[0];
+
+ return av_get_packet(s->pb, pkt, st->codec->block_align);
+}
+
+AVInputFormat ff_boa_demuxer = {
+ .name = "boa",
+ .long_name = NULL_IF_CONFIG_SMALL("Black Ops Audio"),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/brstm.c b/libavformat/brstm.c
new file mode 100644
index 0000000000..19a4a2a96b
--- /dev/null
+++ b/libavformat/brstm.c
@@ -0,0 +1,297 @@
+/*
+ * BRSTM demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/bytestream.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct BRSTMDemuxContext {
+ uint32_t block_size;
+ uint32_t block_count;
+ uint32_t current_block;
+ uint32_t samples_per_block;
+ uint32_t last_block_used_bytes;
+ uint8_t *table;
+ uint8_t *adpc;
+} BRSTMDemuxContext;
+
+static int probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) == MKTAG('R','S','T','M') &&
+ (AV_RL16(p->buf + 4) == 0xFFFE ||
+ AV_RL16(p->buf + 4) == 0xFEFF))
+ return AVPROBE_SCORE_MAX / 3 * 2;
+ return 0;
+}
+
+static int read_close(AVFormatContext *s)
+{
+ BRSTMDemuxContext *b = s->priv_data;
+
+ av_freep(&b->table);
+ av_freep(&b->adpc);
+
+ return 0;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ BRSTMDemuxContext *b = s->priv_data;
+ int bom, major, minor, codec, chunk;
+ int64_t pos, h1offset, toffset;
+ uint32_t size, start, asize;
+ AVStream *st;
+ int ret = AVERROR_EOF;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ avio_skip(s->pb, 4);
+
+ bom = avio_rb16(s->pb);
+ if (bom != 0xFEFF && bom != 0xFFFE) {
+ av_log(s, AV_LOG_ERROR, "invalid byte order: %X\n", bom);
+ return AVERROR_INVALIDDATA;
+ }
+ if (bom == 0xFFFE) {
+ avpriv_request_sample(s, "little endian byte order");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ major = avio_r8(s->pb);
+ minor = avio_r8(s->pb);
+ avio_skip(s->pb, 4); // size of file
+ size = avio_rb16(s->pb);
+ if (size < 14)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, size - 14);
+ pos = avio_tell(s->pb);
+ if (avio_rl32(s->pb) != MKTAG('H','E','A','D'))
+ return AVERROR_INVALIDDATA;
+ size = avio_rb32(s->pb);
+ if (size < 256)
+ return AVERROR_INVALIDDATA;
+ avio_skip(s->pb, 4); // unknown
+ h1offset = avio_rb32(s->pb);
+ if (h1offset > size)
+ return AVERROR_INVALIDDATA;
+ avio_skip(s->pb, 12);
+ toffset = avio_rb32(s->pb) + 16LL;
+ if (toffset > size)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, pos + h1offset + 8 - avio_tell(s->pb));
+ codec = avio_r8(s->pb);
+
+ switch (codec) {
+ case 0: codec = AV_CODEC_ID_PCM_S8_PLANAR; break;
+ case 1: codec = AV_CODEC_ID_PCM_S16BE_PLANAR; break;
+ case 2: codec = AV_CODEC_ID_ADPCM_THP; break;
+ default:
+ avpriv_request_sample(s, "codec %d", codec);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ avio_skip(s->pb, 1); // loop flag
+ st->codec->codec_id = codec;
+ st->codec->channels = avio_r8(s->pb);
+ if (!st->codec->channels)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, 1); // padding
+ st->codec->sample_rate = avio_rb16(s->pb);
+ if (!st->codec->sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, 2); // padding
+ avio_skip(s->pb, 4); // loop start sample
+ st->start_time = 0;
+ st->duration = avio_rb32(s->pb);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ start = avio_rb32(s->pb);
+ b->current_block = 0;
+ b->block_count = avio_rb32(s->pb);
+ if (b->block_count > UINT16_MAX) {
+ av_log(s, AV_LOG_WARNING, "too many blocks: %u\n", b->block_count);
+ return AVERROR_INVALIDDATA;
+ }
+
+ b->block_size = avio_rb32(s->pb);
+ if (b->block_size > UINT16_MAX / st->codec->channels)
+ return AVERROR_INVALIDDATA;
+ b->block_size *= st->codec->channels;
+
+ b->samples_per_block = avio_rb32(s->pb);
+ b->last_block_used_bytes = avio_rb32(s->pb);
+ if (b->last_block_used_bytes > UINT16_MAX / st->codec->channels)
+ return AVERROR_INVALIDDATA;
+ b->last_block_used_bytes *= st->codec->channels;
+
+ avio_skip(s->pb, 4); // last block samples
+ avio_skip(s->pb, 4); // last block size
+
+ if (codec == AV_CODEC_ID_ADPCM_THP) {
+ int ch;
+
+ avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
+ toffset = avio_rb32(s->pb) + 16LL;
+ if (toffset > size)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, pos + toffset - avio_tell(s->pb));
+ b->table = av_mallocz(32 * st->codec->channels);
+ if (!b->table)
+ return AVERROR(ENOMEM);
+
+ for (ch = 0; ch < st->codec->channels; ch++) {
+ if (avio_read(s->pb, b->table + ch * 32, 32) != 32) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ avio_skip(s->pb, 24);
+ }
+ }
+
+ if (size < (avio_tell(s->pb) - pos)) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ avio_skip(s->pb, size - (avio_tell(s->pb) - pos));
+
+ while (!avio_feof(s->pb)) {
+ chunk = avio_rl32(s->pb);
+ size = avio_rb32(s->pb);
+ if (size < 8) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ size -= 8;
+ switch (chunk) {
+ case MKTAG('A','D','P','C'):
+ if (codec != AV_CODEC_ID_ADPCM_THP)
+ goto skip;
+
+ asize = b->block_count * st->codec->channels * 4;
+ if (size < asize) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ if (b->adpc) {
+ av_log(s, AV_LOG_WARNING, "skipping additional ADPC chunk\n");
+ goto skip;
+ } else {
+ b->adpc = av_mallocz(asize);
+ if (!b->adpc) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_read(s->pb, b->adpc, asize);
+ avio_skip(s->pb, size - asize);
+ }
+ break;
+ case MKTAG('D','A','T','A'):
+ if ((start < avio_tell(s->pb)) ||
+ (!b->adpc && codec == AV_CODEC_ID_ADPCM_THP)) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ avio_skip(s->pb, start - avio_tell(s->pb));
+
+ if (major != 1 || minor)
+ avpriv_request_sample(s, "Version %d.%d", major, minor);
+
+ return 0;
+ default:
+ av_log(s, AV_LOG_WARNING, "skipping unknown chunk: %X\n", chunk);
+skip:
+ avio_skip(s->pb, size);
+ }
+ }
+
+fail:
+ read_close(s);
+
+ return ret;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVCodecContext *codec = s->streams[0]->codec;
+ BRSTMDemuxContext *b = s->priv_data;
+ uint32_t samples, size;
+ int ret;
+
+ if (avio_feof(s->pb))
+ return AVERROR_EOF;
+ b->current_block++;
+ if (b->current_block == b->block_count) {
+ size = b->last_block_used_bytes;
+ samples = size / (8 * codec->channels) * 14;
+ } else if (b->current_block < b->block_count) {
+ size = b->block_size;
+ samples = b->samples_per_block;
+ } else {
+ return AVERROR_EOF;
+ }
+
+ if (codec->codec_id == AV_CODEC_ID_ADPCM_THP) {
+ uint8_t *dst;
+
+ if (av_new_packet(pkt, 8 + (32 + 4) * codec->channels + size) < 0)
+ return AVERROR(ENOMEM);
+ dst = pkt->data;
+ bytestream_put_be32(&dst, size);
+ bytestream_put_be32(&dst, samples);
+ bytestream_put_buffer(&dst, b->table, 32 * codec->channels);
+ bytestream_put_buffer(&dst, b->adpc + 4 * codec->channels *
+ (b->current_block - 1), 4 * codec->channels);
+
+ ret = avio_read(s->pb, dst, size);
+ if (ret != size)
+ av_free_packet(pkt);
+ pkt->duration = samples;
+ } else {
+ ret = av_get_packet(s->pb, pkt, size);
+ }
+
+ pkt->stream_index = 0;
+
+ if (ret != size)
+ ret = AVERROR(EIO);
+
+ return ret;
+}
+
+AVInputFormat ff_brstm_demuxer = {
+ .name = "brstm",
+ .long_name = NULL_IF_CONFIG_SMALL("BRSTM (Binary Revolution Stream)"),
+ .priv_data_size = sizeof(BRSTMDemuxContext),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_close = read_close,
+ .extensions = "brstm",
+};
diff --git a/libavformat/c93.c b/libavformat/c93.c
index fdb7a87a2a..d67afcfb4b 100644
--- a/libavformat/c93.c
+++ b/libavformat/c93.c
@@ -2,20 +2,20 @@
* Interplay C93 demuxer
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -133,7 +133,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
}
if (c93->current_frame >= br->frames) {
if (c93->current_block >= 511 || !br[1].length)
- return AVERROR(EIO);
+ return AVERROR_EOF;
br++;
c93->current_block++;
c93->current_frame = 0;
diff --git a/libavformat/cache.c b/libavformat/cache.c
new file mode 100644
index 0000000000..d3d12bb4d5
--- /dev/null
+++ b/libavformat/cache.c
@@ -0,0 +1,322 @@
+/*
+ * Input cache protocol.
+ * Copyright (c) 2011,2014 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 file.c by Fabrice Bellard
+ */
+
+/**
+ * @TODO
+ * support keeping files
+ * support filling with a background thread
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/file.h"
+#include "libavutil/opt.h"
+#include "libavutil/tree.h"
+#include "avformat.h"
+#include <fcntl.h>
+#if HAVE_IO_H
+#include <io.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <stdlib.h>
+#include "os_support.h"
+#include "url.h"
+
+typedef struct CacheEntry {
+ int64_t logical_pos;
+ int64_t physical_pos;
+ int size;
+} CacheEntry;
+
+typedef struct Context {
+ AVClass *class;
+ int fd;
+ struct AVTreeNode *root;
+ int64_t logical_pos;
+ int64_t cache_pos;
+ int64_t inner_pos;
+ int64_t end;
+ int is_true_eof;
+ URLContext *inner;
+ int64_t cache_hit, cache_miss;
+ int read_ahead_limit;
+} Context;
+
+static int cmp(void *key, const void *node)
+{
+ return (*(int64_t *) key) - ((const CacheEntry *) node)->logical_pos;
+}
+
+static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
+{
+ char *buffername;
+ Context *c= h->priv_data;
+
+ av_strstart(arg, "cache:", &arg);
+
+ c->fd = av_tempfile("ffcache", &buffername, 0, h);
+ if (c->fd < 0){
+ av_log(h, AV_LOG_ERROR, "Failed to create tempfile\n");
+ return c->fd;
+ }
+
+ unlink(buffername);
+ av_freep(&buffername);
+
+ return ffurl_open(&c->inner, arg, flags, &h->interrupt_callback, options);
+}
+
+static int add_entry(URLContext *h, const unsigned char *buf, int size)
+{
+ Context *c= h->priv_data;
+ int64_t pos = -1;
+ int ret;
+ CacheEntry *entry = NULL, *next[2] = {NULL, NULL};
+ CacheEntry *entry_ret;
+ struct AVTreeNode *node = NULL;
+
+ //FIXME avoid lseek
+ pos = lseek(c->fd, 0, SEEK_END);
+ if (pos < 0) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "seek in cache failed\n");
+ goto fail;
+ }
+ c->cache_pos = pos;
+
+ ret = write(c->fd, buf, size);
+ if (ret < 0) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "write in cache failed\n");
+ goto fail;
+ }
+ c->cache_pos += ret;
+
+ entry = av_tree_find(c->root, &c->logical_pos, cmp, (void**)next);
+
+ if (!entry)
+ entry = next[0];
+
+ if (!entry ||
+ entry->logical_pos + entry->size != c->logical_pos ||
+ entry->physical_pos + entry->size != pos
+ ) {
+ entry = av_malloc(sizeof(*entry));
+ node = av_tree_node_alloc();
+ if (!entry || !node) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ entry->logical_pos = c->logical_pos;
+ entry->physical_pos = pos;
+ entry->size = ret;
+
+ entry_ret = av_tree_insert(&c->root, entry, cmp, &node);
+ if (entry_ret && entry_ret != entry) {
+ ret = -1;
+ av_log(h, AV_LOG_ERROR, "av_tree_insert failed\n");
+ goto fail;
+ }
+ } else
+ entry->size += ret;
+
+ return 0;
+fail:
+ //we could truncate the file to pos here if pos >=0 but ftruncate isn't available in VS so
+ //for simplicty we just leave the file a bit larger
+ av_free(entry);
+ av_free(node);
+ return ret;
+}
+
+static int cache_read(URLContext *h, unsigned char *buf, int size)
+{
+ Context *c= h->priv_data;
+ CacheEntry *entry, *next[2] = {NULL, NULL};
+ int r;
+
+ entry = av_tree_find(c->root, &c->logical_pos, cmp, (void**)next);
+
+ if (!entry)
+ entry = next[0];
+
+ if (entry) {
+ int64_t in_block_pos = c->logical_pos - entry->logical_pos;
+ av_assert0(entry->logical_pos <= c->logical_pos);
+ if (in_block_pos < entry->size) {
+ int64_t physical_target = entry->physical_pos + in_block_pos;
+
+ if (c->cache_pos != physical_target) {
+ r = lseek(c->fd, physical_target, SEEK_SET);
+ } else
+ r = c->cache_pos;
+
+ if (r >= 0) {
+ c->cache_pos = r;
+ r = read(c->fd, buf, FFMIN(size, entry->size - in_block_pos));
+ }
+
+ if (r > 0) {
+ c->cache_pos += r;
+ c->logical_pos += r;
+ c->cache_hit ++;
+ return r;
+ }
+ }
+ }
+
+ // Cache miss or some kind of fault with the cache
+
+ if (c->logical_pos != c->inner_pos) {
+ r = ffurl_seek(c->inner, c->logical_pos, SEEK_SET);
+ if (r<0) {
+ av_log(h, AV_LOG_ERROR, "Failed to perform internal seek\n");
+ return r;
+ }
+ c->inner_pos = r;
+ }
+
+ r = ffurl_read(c->inner, buf, size);
+ if (r == 0 && size>0) {
+ c->is_true_eof = 1;
+ av_assert0(c->end >= c->logical_pos);
+ }
+ if (r<=0)
+ return r;
+ c->inner_pos += r;
+
+ c->cache_miss ++;
+
+ add_entry(h, buf, r);
+ c->logical_pos += r;
+ c->end = FFMAX(c->end, c->logical_pos);
+
+ return r;
+}
+
+static int64_t cache_seek(URLContext *h, int64_t pos, int whence)
+{
+ Context *c= h->priv_data;
+ int64_t ret;
+
+ if (whence == AVSEEK_SIZE) {
+ pos= ffurl_seek(c->inner, pos, whence);
+ if(pos <= 0){
+ pos= ffurl_seek(c->inner, -1, SEEK_END);
+ if (ffurl_seek(c->inner, c->inner_pos, SEEK_SET) < 0)
+ av_log(h, AV_LOG_ERROR, "Inner protocol failed to seekback end : %"PRId64"\n", pos);
+ }
+ if (pos > 0)
+ c->is_true_eof = 1;
+ c->end = FFMAX(c->end, pos);
+ return pos;
+ }
+
+ if (whence == SEEK_CUR) {
+ whence = SEEK_SET;
+ pos += c->logical_pos;
+ } else if (whence == SEEK_END && c->is_true_eof) {
+resolve_eof:
+ whence = SEEK_SET;
+ pos += c->end;
+ }
+
+ if (whence == SEEK_SET && pos >= 0 && pos < c->end) {
+ //Seems within filesize, assume it will not fail.
+ c->logical_pos = pos;
+ return pos;
+ }
+
+ //cache miss
+ ret= ffurl_seek(c->inner, pos, whence);
+ if ((whence == SEEK_SET && pos >= c->logical_pos ||
+ whence == SEEK_END && pos <= 0) && ret < 0) {
+ if ( (whence == SEEK_SET && c->read_ahead_limit >= pos - c->logical_pos)
+ || c->read_ahead_limit < 0) {
+ uint8_t tmp[32768];
+ while (c->logical_pos < pos || whence == SEEK_END) {
+ int size = sizeof(tmp);
+ if (whence == SEEK_SET)
+ size = FFMIN(sizeof(tmp), pos - c->logical_pos);
+ ret = cache_read(h, tmp, size);
+ if (ret == 0 && whence == SEEK_END) {
+ av_assert0(c->is_true_eof);
+ goto resolve_eof;
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ return c->logical_pos;
+ }
+ }
+
+ if (ret >= 0) {
+ c->logical_pos = ret;
+ c->end = FFMAX(c->end, ret);
+ }
+
+ return ret;
+}
+
+static int cache_close(URLContext *h)
+{
+ Context *c= h->priv_data;
+
+ av_log(h, AV_LOG_INFO, "Statistics, cache hits:%"PRId64" cache misses:%"PRId64"\n",
+ c->cache_hit, c->cache_miss);
+
+ close(c->fd);
+ ffurl_close(c->inner);
+ av_tree_destroy(c->root);
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(Context, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption options[] = {
+ { "read_ahead_limit", "Amount in bytes that may be read ahead when seeking isn't supported, -1 for unlimited", OFFSET(read_ahead_limit), AV_OPT_TYPE_INT, { .i64 = 65536 }, -1, INT_MAX, D },
+ {NULL},
+};
+
+static const AVClass cache_context_class = {
+ .class_name = "Cache",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+URLProtocol ff_cache_protocol = {
+ .name = "cache",
+ .url_open2 = cache_open,
+ .url_read = cache_read,
+ .url_seek = cache_seek,
+ .url_close = cache_close,
+ .priv_data_size = sizeof(Context),
+ .priv_data_class = &cache_context_class,
+};
diff --git a/libavformat/caf.c b/libavformat/caf.c
index cf128d5624..c1ecc94425 100644
--- a/libavformat/caf.c
+++ b/libavformat/caf.c
@@ -2,20 +2,20 @@
* CAF common code
* Copyright (c) 2007 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,27 +32,35 @@
* Known codec tags for CAF
*/
const AVCodecTag ff_codec_caf_tags[] = {
- { AV_CODEC_ID_AAC, MKBETAG('a','a','c',' ') },
- { AV_CODEC_ID_AC3, MKBETAG('a','c','-','3') },
- { AV_CODEC_ID_ALAC, MKBETAG('a','l','a','c') },
+ { AV_CODEC_ID_AAC, MKTAG('a','a','c',' ') },
+ { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
+ { AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') },
+ { AV_CODEC_ID_ADPCM_IMA_WAV, MKTAG('m','s', 0, 17 ) },
+ { AV_CODEC_ID_ADPCM_MS, MKTAG('m','s', 0, 2 ) },
+ { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
+ { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
/* FIXME: use DV demuxer, as done in MOV */
- /*{ AV_CODEC_ID_DVAUDIO, MKBETAG('v','d','v','a') },*/
- /*{ AV_CODEC_ID_DVAUDIO, MKBETAG('d','v','c','a') },*/
- { AV_CODEC_ID_ADPCM_IMA_QT, MKBETAG('i','m','a','4') },
- { AV_CODEC_ID_MACE3, MKBETAG('M','A','C','3') },
- { AV_CODEC_ID_MACE6, MKBETAG('M','A','C','6') },
- { AV_CODEC_ID_MP3, MKBETAG('.','m','p','3') },
- { AV_CODEC_ID_MP2, MKBETAG('.','m','p','2') },
- { AV_CODEC_ID_MP1, MKBETAG('.','m','p','1') },
- { AV_CODEC_ID_PCM_ALAW, MKBETAG('a','l','a','w') },
- { AV_CODEC_ID_PCM_MULAW, MKBETAG('u','l','a','w') },
- { AV_CODEC_ID_QCELP, MKBETAG('Q','c','l','p') },
- { AV_CODEC_ID_QDM2, MKBETAG('Q','D','M','2') },
- { AV_CODEC_ID_QDM2, MKBETAG('Q','D','M','C') },
+ /*{ AV_CODEC_ID_DVAUDIO, MKTAG('v','d','v','a') },*/
+ /*{ AV_CODEC_ID_DVAUDIO, MKTAG('d','v','c','a') },*/
+ { AV_CODEC_ID_GSM, MKTAG('a','g','s','m') },
+ { AV_CODEC_ID_GSM_MS, MKTAG('m','s', 0, '1') },
+ { AV_CODEC_ID_ILBC, MKTAG('i','l','b','c') },
+ { AV_CODEC_ID_MACE3, MKTAG('M','A','C','3') },
+ { AV_CODEC_ID_MACE6, MKTAG('M','A','C','6') },
+ { AV_CODEC_ID_MP1, MKTAG('.','m','p','1') },
+ { AV_CODEC_ID_MP2, MKTAG('.','m','p','2') },
+ { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
+ { AV_CODEC_ID_MP3, MKTAG('m','s', 0 ,'U') },
+ { AV_CODEC_ID_PCM_ALAW, MKTAG('a','l','a','w') },
+ { AV_CODEC_ID_PCM_MULAW, MKTAG('u','l','a','w') },
+ { AV_CODEC_ID_QCELP, MKTAG('Q','c','l','p') },
+ { AV_CODEC_ID_QDM2, MKTAG('Q','D','M','2') },
+ { AV_CODEC_ID_QDM2, MKTAG('Q','D','M','C') },
/* currently unsupported codecs */
- /*{ AC-3 over S/PDIF MKBETAG('c','a','c','3') },*/
- /*{ MPEG4CELP MKBETAG('c','e','l','p') },*/
- /*{ MPEG4HVXC MKBETAG('h','v','x','c') },*/
- /*{ MPEG4TwinVQ MKBETAG('t','w','v','q') },*/
+ /*{ AC-3 over S/PDIF MKTAG('c','a','c','3') },*/
+ /*{ MPEG4CELP MKTAG('c','e','l','p') },*/
+ /*{ MPEG4HVXC MKTAG('h','v','x','c') },*/
+ /*{ MPEG4TwinVQ MKTAG('t','w','v','q') },*/
{ AV_CODEC_ID_NONE, 0 },
};
+
diff --git a/libavformat/caf.h b/libavformat/caf.h
index 7ca4dc5c66..9c25f2c683 100644
--- a/libavformat/caf.h
+++ b/libavformat/caf.h
@@ -2,20 +2,20 @@
* CAF common code
* Copyright (c) 2007 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/cafdec.c b/libavformat/cafdec.c
index a37ceaaebd..cc6ed0ce9f 100644
--- a/libavformat/cafdec.c
+++ b/libavformat/cafdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Justin Ruggles
* Copyright (c) 2009 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,7 +71,7 @@ static int read_desc_chunk(AVFormatContext *s)
/* parse format description */
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->sample_rate = av_int2double(avio_rb64(pb));
- st->codec->codec_tag = avio_rb32(pb);
+ st->codec->codec_tag = avio_rl32(pb);
flags = avio_rb32(pb);
caf->bytes_per_packet = avio_rb32(pb);
st->codec->block_align = caf->bytes_per_packet;
@@ -88,7 +88,7 @@ static int read_desc_chunk(AVFormatContext *s)
}
/* determine codec */
- if (st->codec->codec_tag == MKBETAG('l','p','c','m'))
+ if (st->codec->codec_tag == MKTAG('l','p','c','m'))
st->codec->codec_id = ff_mov_get_lpcm_codec_id(st->codec->bits_per_coded_sample, (flags ^ 0x2) | 0x4);
else
st->codec->codec_id = ff_codec_get_id(ff_codec_caf_tags, st->codec->codec_tag);
@@ -129,10 +129,13 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size)
avio_skip(pb, size);
return AVERROR_INVALIDDATA;
}
- avio_read(pb, preamble, ALAC_PREAMBLE);
+ if (avio_read(pb, preamble, ALAC_PREAMBLE) != ALAC_PREAMBLE) {
+ av_log(s, AV_LOG_ERROR, "failed to read preamble\n");
+ return AVERROR_INVALIDDATA;
+ }
- st->codec->extradata = av_mallocz(ALAC_HEADER + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ av_freep(&st->codec->extradata);
+ if (ff_alloc_extradata(st->codec, ALAC_HEADER))
return AVERROR(ENOMEM);
/* For the old style cookie, we skip 12 bytes, then read 36 bytes.
@@ -145,23 +148,28 @@ static int read_kuki_chunk(AVFormatContext *s, int64_t size)
av_freep(&st->codec->extradata);
return AVERROR_INVALIDDATA;
}
- avio_read(pb, st->codec->extradata, ALAC_HEADER);
+ if (avio_read(pb, st->codec->extradata, ALAC_HEADER) != ALAC_HEADER) {
+ av_log(s, AV_LOG_ERROR, "failed to read kuki header\n");
+ av_freep(&st->codec->extradata);
+ return AVERROR_INVALIDDATA;
+ }
avio_skip(pb, size - ALAC_PREAMBLE - ALAC_HEADER);
} else {
AV_WB32(st->codec->extradata, 36);
memcpy(&st->codec->extradata[4], "alac", 4);
AV_WB32(&st->codec->extradata[8], 0);
memcpy(&st->codec->extradata[12], preamble, 12);
- avio_read(pb, &st->codec->extradata[24], ALAC_NEW_KUKI - 12);
+ if (avio_read(pb, &st->codec->extradata[24], ALAC_NEW_KUKI - 12) != ALAC_NEW_KUKI - 12) {
+ av_log(s, AV_LOG_ERROR, "failed to read new kuki header\n");
+ av_freep(&st->codec->extradata);
+ return AVERROR_INVALIDDATA;
+ }
avio_skip(pb, size - ALAC_NEW_KUKI);
}
- st->codec->extradata_size = ALAC_HEADER;
} else {
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ av_freep(&st->codec->extradata);
+ if (ff_get_extradata(st->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- avio_read(pb, st->codec->extradata, size);
- st->codec->extradata_size = size;
}
return 0;
@@ -209,10 +217,10 @@ static void read_info_chunk(AVFormatContext *s, int64_t size)
AVIOContext *pb = s->pb;
unsigned int i;
unsigned int nb_entries = avio_rb32(pb);
- for (i = 0; i < nb_entries; i++) {
+ for (i = 0; i < nb_entries && !avio_feof(pb); i++) {
char key[32];
char value[1024];
- avio_get_str(pb, INT_MAX, key, sizeof(key));
+ avio_get_str(pb, INT_MAX, key, sizeof(key));
avio_get_str(pb, INT_MAX, value, sizeof(value));
av_dict_set(&s->metadata, key, value, 0);
}
@@ -225,7 +233,7 @@ static int read_header(AVFormatContext *s)
AVStream *st;
uint32_t tag = 0;
int found_data, ret;
- int64_t size;
+ int64_t size, pos;
avio_skip(pb, 8); /* magic, version, file flags */
@@ -245,7 +253,7 @@ static int read_header(AVFormatContext *s)
/* parse each chunk */
found_data = 0;
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
/* stop at data chunk if seeking is not supported or
data chunk size is unknown */
@@ -254,7 +262,8 @@ static int read_header(AVFormatContext *s)
tag = avio_rb32(pb);
size = avio_rb64(pb);
- if (pb->eof_reached)
+ pos = avio_tell(pb);
+ if (avio_feof(pb))
break;
switch (tag) {
@@ -291,15 +300,20 @@ static int read_header(AVFormatContext *s)
default:
#define _(x) ((x) >= ' ' ? (x) : ' ')
av_log(s, AV_LOG_WARNING,
- "skipping CAF chunk: %08"PRIX32" (%"PRIu32"%"PRIu32"%"PRIu32"%"PRIu32")\n",
- tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF));
+ "skipping CAF chunk: %08"PRIX32" (%c%c%c%c), size %"PRId64"\n",
+ tag, _(tag>>24), _((tag>>16)&0xFF), _((tag>>8)&0xFF), _(tag&0xFF), size);
#undef _
case MKBETAG('f','r','e','e'):
if (size < 0)
return AVERROR_INVALIDDATA;
- avio_skip(pb, size);
break;
}
+
+ if (size > 0) {
+ if (pos > INT64_MAX - size)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, FFMAX(0, pos + size - avio_tell(pb)));
+ }
}
if (!found_data)
@@ -308,7 +322,7 @@ static int read_header(AVFormatContext *s)
if (caf->bytes_per_packet > 0 && caf->frames_per_packet > 0) {
if (caf->data_size > 0)
st->nb_frames = (caf->data_size / caf->bytes_per_packet) * caf->frames_per_packet;
- } else if (st->nb_index_entries) {
+ } else if (st->nb_index_entries && st->duration > 0) {
st->codec->bit_rate = st->codec->sample_rate * caf->data_size * 8 /
st->duration;
} else {
@@ -337,13 +351,15 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
int res, pkt_size = 0, pkt_frames = 0;
int64_t left = CAF_MAX_PKT_SIZE;
- if (pb->eof_reached)
- return AVERROR(EIO);
+ if (avio_feof(pb))
+ return AVERROR_EOF;
/* don't read past end of data chunk */
if (caf->data_size > 0) {
left = (caf->data_start + caf->data_size) - avio_tell(pb);
- if (left <= 0)
+ if (!left)
+ return AVERROR_EOF;
+ if (left < 0)
return AVERROR(EIO);
}
@@ -394,7 +410,7 @@ static int read_seek(AVFormatContext *s, int stream_index,
if (caf->frames_per_packet > 0 && caf->bytes_per_packet > 0) {
/* calculate new byte position based on target frame position */
- pos = caf->bytes_per_packet * timestamp / caf->frames_per_packet;
+ pos = caf->bytes_per_packet * (timestamp / caf->frames_per_packet);
if (caf->data_size > 0)
pos = FFMIN(pos, caf->data_size);
packet_cnt = pos / caf->bytes_per_packet;
diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c
new file mode 100644
index 0000000000..1708275e11
--- /dev/null
+++ b/libavformat/cafenc.c
@@ -0,0 +1,286 @@
+/*
+ * Core Audio Format muxer
+ * Copyright (c) 2011 Carl Eugen Hoyos
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "caf.h"
+#include "isom.h"
+#include "avio_internal.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/dict.h"
+
+typedef struct {
+ int64_t data;
+ uint8_t *pkt_sizes;
+ int size_buffer_size;
+ int size_entries_used;
+ int packets;
+} CAFContext;
+
+static uint32_t codec_flags(enum AVCodecID codec_id) {
+ switch (codec_id) {
+ case AV_CODEC_ID_PCM_F32BE:
+ case AV_CODEC_ID_PCM_F64BE:
+ return 1; //< kCAFLinearPCMFormatFlagIsFloat
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S24LE:
+ case AV_CODEC_ID_PCM_S32LE:
+ return 2; //< kCAFLinearPCMFormatFlagIsLittleEndian
+ case AV_CODEC_ID_PCM_F32LE:
+ case AV_CODEC_ID_PCM_F64LE:
+ return 3; //< kCAFLinearPCMFormatFlagIsFloat | kCAFLinearPCMFormatFlagIsLittleEndian
+ default:
+ return 0;
+ }
+}
+
+static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels, int block_align) {
+ switch (codec_id) {
+ case AV_CODEC_ID_PCM_S8:
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S16BE:
+ case AV_CODEC_ID_PCM_S24LE:
+ case AV_CODEC_ID_PCM_S24BE:
+ case AV_CODEC_ID_PCM_S32LE:
+ case AV_CODEC_ID_PCM_S32BE:
+ case AV_CODEC_ID_PCM_F32LE:
+ case AV_CODEC_ID_PCM_F32BE:
+ case AV_CODEC_ID_PCM_F64LE:
+ case AV_CODEC_ID_PCM_F64BE:
+ case AV_CODEC_ID_PCM_ALAW:
+ case AV_CODEC_ID_PCM_MULAW:
+ return 1;
+ case AV_CODEC_ID_MACE3:
+ case AV_CODEC_ID_MACE6:
+ return 6;
+ case AV_CODEC_ID_ADPCM_IMA_QT:
+ return 64;
+ case AV_CODEC_ID_AMR_NB:
+ case AV_CODEC_ID_GSM:
+ case AV_CODEC_ID_ILBC:
+ case AV_CODEC_ID_QCELP:
+ return 160;
+ case AV_CODEC_ID_GSM_MS:
+ return 320;
+ case AV_CODEC_ID_MP1:
+ return 384;
+ case AV_CODEC_ID_MP2:
+ case AV_CODEC_ID_MP3:
+ return 1152;
+ case AV_CODEC_ID_AC3:
+ return 1536;
+ case AV_CODEC_ID_QDM2:
+ return 2048 * channels;
+ case AV_CODEC_ID_ALAC:
+ return 4096;
+ case AV_CODEC_ID_ADPCM_IMA_WAV:
+ return (block_align - 4 * channels) * 8 / (4 * channels) + 1;
+ case AV_CODEC_ID_ADPCM_MS:
+ return (block_align - 7 * channels) * 2 / channels + 2;
+ default:
+ return 0;
+ }
+}
+
+static int caf_write_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ AVCodecContext *enc = s->streams[0]->codec;
+ CAFContext *caf = s->priv_data;
+ AVDictionaryEntry *t = NULL;
+ unsigned int codec_tag = ff_codec_get_tag(ff_codec_caf_tags, enc->codec_id);
+ int64_t chunk_size = 0;
+ int frame_size = enc->frame_size;
+
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "CAF files have exactly one stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ switch (enc->codec_id) {
+ case AV_CODEC_ID_AAC:
+ av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ switch (enc->codec_id) {
+ case AV_CODEC_ID_PCM_S8:
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S16BE:
+ case AV_CODEC_ID_PCM_S24LE:
+ case AV_CODEC_ID_PCM_S24BE:
+ case AV_CODEC_ID_PCM_S32LE:
+ case AV_CODEC_ID_PCM_S32BE:
+ case AV_CODEC_ID_PCM_F32LE:
+ case AV_CODEC_ID_PCM_F32BE:
+ case AV_CODEC_ID_PCM_F64LE:
+ case AV_CODEC_ID_PCM_F64BE:
+ codec_tag = MKTAG('l','p','c','m');
+ }
+
+ if (!codec_tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!enc->block_align && !pb->seekable) {
+ av_log(s, AV_LOG_ERROR, "Muxing variable packet size not supported on non seekable output\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (enc->codec_id != AV_CODEC_ID_MP3 || frame_size != 576)
+ frame_size = samples_per_packet(enc->codec_id, enc->channels, enc->block_align);
+
+ ffio_wfourcc(pb, "caff"); //< mFileType
+ avio_wb16(pb, 1); //< mFileVersion
+ avio_wb16(pb, 0); //< mFileFlags
+
+ ffio_wfourcc(pb, "desc"); //< Audio Description chunk
+ avio_wb64(pb, 32); //< mChunkSize
+ avio_wb64(pb, av_double2int(enc->sample_rate)); //< mSampleRate
+ avio_wl32(pb, codec_tag); //< mFormatID
+ avio_wb32(pb, codec_flags(enc->codec_id)); //< mFormatFlags
+ avio_wb32(pb, enc->block_align); //< mBytesPerPacket
+ avio_wb32(pb, frame_size); //< mFramesPerPacket
+ avio_wb32(pb, enc->channels); //< mChannelsPerFrame
+ avio_wb32(pb, av_get_bits_per_sample(enc->codec_id)); //< mBitsPerChannel
+
+ if (enc->channel_layout) {
+ ffio_wfourcc(pb, "chan");
+ avio_wb64(pb, 12);
+ ff_mov_write_chan(pb, enc->channel_layout);
+ }
+
+ if (enc->codec_id == AV_CODEC_ID_ALAC) {
+ ffio_wfourcc(pb, "kuki");
+ avio_wb64(pb, 12 + enc->extradata_size);
+ avio_write(pb, "\0\0\0\14frmaalac", 12);
+ avio_write(pb, enc->extradata, enc->extradata_size);
+ } else if (enc->codec_id == AV_CODEC_ID_AMR_NB) {
+ ffio_wfourcc(pb, "kuki");
+ avio_wb64(pb, 29);
+ avio_write(pb, "\0\0\0\14frmasamr", 12);
+ avio_wb32(pb, 0x11); /* size */
+ avio_write(pb, "samrFFMP", 8);
+ avio_w8(pb, 0); /* decoder version */
+
+ avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
+ avio_w8(pb, 0x00); /* Mode change period (no restriction) */
+ avio_w8(pb, 0x01); /* Frames per sample */
+ } else if (enc->codec_id == AV_CODEC_ID_QDM2) {
+ ffio_wfourcc(pb, "kuki");
+ avio_wb64(pb, enc->extradata_size);
+ avio_write(pb, enc->extradata, enc->extradata_size);
+ }
+
+ if (av_dict_count(s->metadata)) {
+ ffio_wfourcc(pb, "info"); //< Information chunk
+ while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ chunk_size += strlen(t->key) + strlen(t->value) + 2;
+ }
+ avio_wb64(pb, chunk_size + 4);
+ avio_wb32(pb, av_dict_count(s->metadata));
+ t = NULL;
+ while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ avio_put_str(pb, t->key);
+ avio_put_str(pb, t->value);
+ }
+ }
+
+ ffio_wfourcc(pb, "data"); //< Audio Data chunk
+ caf->data = avio_tell(pb);
+ avio_wb64(pb, -1); //< mChunkSize
+ avio_wb32(pb, 0); //< mEditCount
+
+ avio_flush(pb);
+ return 0;
+}
+
+static int caf_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ CAFContext *caf = s->priv_data;
+
+ avio_write(s->pb, pkt->data, pkt->size);
+ if (!s->streams[0]->codec->block_align) {
+ void *pkt_sizes = caf->pkt_sizes;
+ int i, alloc_size = caf->size_entries_used + 5;
+ if (alloc_size < 0) {
+ caf->pkt_sizes = NULL;
+ } else {
+ caf->pkt_sizes = av_fast_realloc(caf->pkt_sizes,
+ &caf->size_buffer_size,
+ alloc_size);
+ }
+ if (!caf->pkt_sizes) {
+ av_free(pkt_sizes);
+ return AVERROR(ENOMEM);
+ }
+ for (i = 4; i > 0; i--) {
+ unsigned top = pkt->size >> i * 7;
+ if (top)
+ caf->pkt_sizes[caf->size_entries_used++] = 128 | top;
+ }
+ caf->pkt_sizes[caf->size_entries_used++] = pkt->size & 127;
+ caf->packets++;
+ }
+ return 0;
+}
+
+static int caf_write_trailer(AVFormatContext *s)
+{
+ CAFContext *caf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *enc = s->streams[0]->codec;
+
+ if (pb->seekable) {
+ int64_t file_size = avio_tell(pb);
+
+ avio_seek(pb, caf->data, SEEK_SET);
+ avio_wb64(pb, file_size - caf->data - 8);
+ avio_seek(pb, file_size, SEEK_SET);
+ if (!enc->block_align) {
+ ffio_wfourcc(pb, "pakt");
+ avio_wb64(pb, caf->size_entries_used + 24);
+ avio_wb64(pb, caf->packets); ///< mNumberPackets
+ avio_wb64(pb, caf->packets * samples_per_packet(enc->codec_id, enc->channels, enc->block_align)); ///< mNumberValidFrames
+ avio_wb32(pb, 0); ///< mPrimingFrames
+ avio_wb32(pb, 0); ///< mRemainderFrames
+ avio_write(pb, caf->pkt_sizes, caf->size_entries_used);
+ caf->size_buffer_size = 0;
+ }
+ avio_flush(pb);
+ }
+ av_freep(&caf->pkt_sizes);
+ return 0;
+}
+
+AVOutputFormat ff_caf_muxer = {
+ .name = "caf",
+ .long_name = NULL_IF_CONFIG_SMALL("Apple CAF (Core Audio Format)"),
+ .mime_type = "audio/x-caf",
+ .extensions = "caf",
+ .priv_data_size = sizeof(CAFContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16BE,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = caf_write_header,
+ .write_packet = caf_write_packet,
+ .write_trailer = caf_write_trailer,
+ .codec_tag = (const AVCodecTag* const []){ff_codec_caf_tags, 0},
+};
diff --git a/libavformat/cavsvideodec.c b/libavformat/cavsvideodec.c
index fcca9e18b3..b4da58e345 100644
--- a/libavformat/cavsvideodec.c
+++ b/libavformat/cavsvideodec.c
@@ -2,25 +2,26 @@
* RAW Chinese AVS video demuxer
* Copyright (c) 2009 Stefan Gehrer <stefan.gehrer@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "rawdec.h"
+#include "libavcodec/internal.h"
#define CAVS_SEQ_START_CODE 0x000001b0
#define CAVS_PIC_I_START_CODE 0x000001b3
@@ -33,10 +34,10 @@ static int cavsvideo_probe(AVProbeData *p)
{
uint32_t code= -1;
int pic=0, seq=0, slice_pos = 0;
- int i;
+ const uint8_t *ptr = p->buf, *end = p->buf + p->buf_size;
- for(i=0; i<p->buf_size; i++){
- code = (code<<8) + p->buf[i];
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &code);
if ((code & 0xffffff00) == 0x100) {
if(code < CAVS_SEQ_START_CODE) {
/* slices have to be consecutive */
@@ -49,7 +50,7 @@ static int cavsvideo_probe(AVProbeData *p)
if (code == CAVS_SEQ_START_CODE) {
seq++;
/* check for the only currently supported profile */
- if(p->buf[i+1] != CAVS_PROFILE_JIZHUN)
+ if (*ptr != CAVS_PROFILE_JIZHUN)
return 0;
} else if ((code == CAVS_PIC_I_START_CODE) ||
(code == CAVS_PIC_PB_START_CODE)) {
@@ -61,7 +62,7 @@ static int cavsvideo_probe(AVProbeData *p)
}
}
if(seq && seq*9<=pic*10)
- return AVPROBE_SCORE_EXTENSION;
+ return AVPROBE_SCORE_EXTENSION+1;
return 0;
}
diff --git a/libavformat/cdg.c b/libavformat/cdg.c
index e699691925..baf37d4c6a 100644
--- a/libavformat/cdg.c
+++ b/libavformat/cdg.c
@@ -2,20 +2,20 @@
* CD Graphics Demuxer
* Copyright (c) 2009 Michael Tison
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,10 +46,11 @@ static int read_header(AVFormatContext *s)
avpriv_set_pts_info(vst, 32, 1, 300);
ret = avio_size(s->pb);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ av_log(s, AV_LOG_WARNING, "Cannot calculate duration as file size cannot be determined\n");
+ } else
+ vst->duration = (ret * vst->time_base.den) / (CDG_PACKET_SIZE * 300);
- vst->duration = (ret * vst->time_base.den) / (CDG_PACKET_SIZE * 300);
return 0;
}
@@ -71,6 +72,12 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
}
pkt->stream_index = 0;
+ pkt->dts=
+ pkt->pts= pkt->pos / CDG_PACKET_SIZE;
+
+ if(ret>5 && (pkt->data[0]&0x3F) == 9 && (pkt->data[1]&0x3F)==1 && !(pkt->data[2+2+1] & 0x0F)){
+ pkt->flags = AV_PKT_FLAG_KEY;
+ }
return ret;
}
@@ -80,5 +87,6 @@ AVInputFormat ff_cdg_demuxer = {
.priv_data_size = sizeof(CDGContext),
.read_header = read_header,
.read_packet = read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
.extensions = "cdg",
};
diff --git a/libavformat/cdxl.c b/libavformat/cdxl.c
index a2cba526ca..f198bf50fa 100644
--- a/libavformat/cdxl.c
+++ b/libavformat/cdxl.c
@@ -2,20 +2,20 @@
* CDXL demuxer
* Copyright (c) 2011-2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,8 +37,51 @@ typedef struct CDXLDemuxContext {
uint8_t header[CDXL_HEADER_SIZE];
int video_stream_index;
int audio_stream_index;
+ int64_t filesize;
} CDXLDemuxContext;
+static int cdxl_read_probe(AVProbeData *p)
+{
+ int score = AVPROBE_SCORE_EXTENSION + 10;
+
+ if (p->buf_size < CDXL_HEADER_SIZE)
+ return 0;
+
+ /* reserved bytes should always be set to 0 */
+ if (AV_RN64(&p->buf[24]) || AV_RN16(&p->buf[10]))
+ return 0;
+
+ /* check type */
+ if (p->buf[0] != 1)
+ return 0;
+
+ /* check palette size */
+ if (AV_RB16(&p->buf[20]) > 512)
+ return 0;
+
+ /* check number of planes */
+ if (p->buf[18] || !p->buf[19])
+ return 0;
+
+ /* check widh and height */
+ if (!AV_RN16(&p->buf[14]) || !AV_RN16(&p->buf[16]))
+ return 0;
+
+ /* chunk size */
+ if (AV_RB32(&p->buf[2]) < AV_RB16(&p->buf[22]) + AV_RB16(&p->buf[20]) + CDXL_HEADER_SIZE)
+ return 0;
+
+ /* previous chunk size */
+ if (AV_RN32(&p->buf[6]))
+ score /= 2;
+
+ /* current frame number, usually starts from 1 */
+ if (AV_RB16(&p->buf[12]) != 1)
+ score /= 2;
+
+ return score;
+}
+
static int cdxl_read_header(AVFormatContext *s)
{
CDXLDemuxContext *cdxl = s->priv_data;
@@ -54,6 +97,8 @@ static int cdxl_read_header(AVFormatContext *s)
cdxl->video_stream_index = -1;
cdxl->audio_stream_index = -1;
+ cdxl->filesize = avio_size(s->pb);
+
s->ctx_flags |= AVFMTCTX_NOHEADER;
return 0;
@@ -66,9 +111,9 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt)
uint32_t current_size, video_size, image_size;
uint16_t audio_size, palette_size, width, height;
int64_t pos;
- int ret;
+ int frames, ret;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
pos = avio_tell(pb);
@@ -85,6 +130,8 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt)
height = AV_RB16(&cdxl->header[16]);
palette_size = AV_RB16(&cdxl->header[20]);
audio_size = AV_RB16(&cdxl->header[22]);
+ if (FFALIGN(width, 16) * (uint64_t)height * cdxl->header[19] > INT_MAX)
+ return AVERROR_INVALIDDATA;
image_size = FFALIGN(width, 16) * height * cdxl->header[19] / 8;
video_size = palette_size + image_size;
@@ -133,6 +180,15 @@ static int cdxl_read_packet(AVFormatContext *s, AVPacket *pkt)
st->codec->codec_id = AV_CODEC_ID_CDXL;
st->codec->width = width;
st->codec->height = height;
+
+ if (audio_size + video_size && cdxl->filesize > 0) {
+ frames = cdxl->filesize / (audio_size + video_size);
+
+ if(cdxl->framerate)
+ st->duration = frames;
+ else
+ st->duration = frames * (int64_t)audio_size;
+ }
st->start_time = 0;
cdxl->video_stream_index = st->index;
if (cdxl->framerate)
@@ -180,6 +236,7 @@ AVInputFormat ff_cdxl_demuxer = {
.name = "cdxl",
.long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
.priv_data_size = sizeof(CDXLDemuxContext),
+ .read_probe = cdxl_read_probe,
.read_header = cdxl_read_header,
.read_packet = cdxl_read_packet,
.extensions = "cdxl,xl",
diff --git a/libavformat/cinedec.c b/libavformat/cinedec.c
new file mode 100644
index 0000000000..632f46c454
--- /dev/null
+++ b/libavformat/cinedec.c
@@ -0,0 +1,325 @@
+/*
+ * Phantom Cine demuxer
+ * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Phantom Cine demuxer
+ * @author Peter Ross <pross@xvid.org>
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/bmp.h"
+#include "libavutil/intfloat.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct {
+ uint64_t pts;
+} CineDemuxContext;
+
+/** Compression */
+enum {
+ CC_RGB = 0, /**< Gray */
+ CC_LEAD = 1, /**< LEAD (M)JPEG */
+ CC_UNINT = 2 /**< Uninterpolated color image (CFA field indicates color ordering) */
+};
+
+/** Color Filter Array */
+enum {
+ CFA_NONE = 0, /**< GRAY */
+ CFA_VRI = 1, /**< GBRG/RGGB */
+ CFA_VRIV6 = 2, /**< BGGR/GRBG */
+ CFA_BAYER = 3, /**< GB/RG */
+ CFA_BAYERFLIP = 4, /**< RG/GB */
+
+ CFA_TLGRAY = 0x80000000,
+ CFA_TRGRAY = 0x40000000,
+ CFA_BLGRAY = 0x20000000,
+ CFA_BRGRAY = 0x10000000
+};
+
+static int cine_read_probe(AVProbeData *p)
+{
+ int HeaderSize;
+ if (p->buf[0] == 'C' && p->buf[1] == 'I' && // Type
+ (HeaderSize = AV_RL16(p->buf + 2)) >= 0x2C && // HeaderSize
+ AV_RL16(p->buf + 4) <= CC_UNINT && // Compression
+ AV_RL16(p->buf + 6) <= 1 && // Version
+ AV_RL32(p->buf + 20) && // ImageCount
+ AV_RL32(p->buf + 24) >= HeaderSize && // OffImageHeader
+ AV_RL32(p->buf + 28) >= HeaderSize && // OffSetup
+ AV_RL32(p->buf + 32) >= HeaderSize) // OffImageOffsets
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int set_metadata_int(AVDictionary **dict, const char *key, int value, int allow_zero)
+{
+ if (value || allow_zero) {
+ return av_dict_set_int(dict, key, value, 0);
+ }
+ return 0;
+}
+
+static int set_metadata_float(AVDictionary **dict, const char *key, float value, int allow_zero)
+{
+ if (value != 0 || allow_zero) {
+ char tmp[64];
+ snprintf(tmp, sizeof(tmp), "%f", value);
+ return av_dict_set(dict, key, tmp, 0);
+ }
+ return 0;
+}
+
+static int cine_read_header(AVFormatContext *avctx)
+{
+ AVIOContext *pb = avctx->pb;
+ AVStream *st;
+ unsigned int version, compression, offImageHeader, offSetup, offImageOffsets, biBitCount, length, CFA;
+ int vflip;
+ char *description;
+ uint64_t i;
+
+ st = avformat_new_stream(avctx, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->codec->codec_tag = 0;
+
+ /* CINEFILEHEADER structure */
+ avio_skip(pb, 4); // Type, Headersize
+
+ compression = avio_rl16(pb);
+ version = avio_rl16(pb);
+ if (version != 1) {
+ avpriv_request_sample(avctx, "uknown version %i", version);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 12); // FirstMovieImage, TotalImageCount, FirstImageNumber
+
+ st->duration = avio_rl32(pb);
+ offImageHeader = avio_rl32(pb);
+ offSetup = avio_rl32(pb);
+ offImageOffsets = avio_rl32(pb);
+
+ avio_skip(pb, 8); // TriggerTime
+
+ /* BITMAPINFOHEADER structure */
+ avio_seek(pb, offImageHeader, SEEK_SET);
+ avio_skip(pb, 4); //biSize
+ st->codec->width = avio_rl32(pb);
+ st->codec->height = avio_rl32(pb);
+
+ if (avio_rl16(pb) != 1) // biPlanes
+ return AVERROR_INVALIDDATA;
+
+ biBitCount = avio_rl16(pb);
+ if (biBitCount != 8 && biBitCount != 16 && biBitCount != 24 && biBitCount != 48) {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+
+ switch (avio_rl32(pb)) {
+ case BMP_RGB:
+ vflip = 0;
+ break;
+ case 0x100: /* BI_PACKED */
+ st->codec->codec_tag = MKTAG('B', 'I', 'T', 0);
+ vflip = 1;
+ break;
+ default:
+ avpriv_request_sample(avctx, "unknown bitmap compression");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 4); // biSizeImage
+
+ /* parse SETUP structure */
+ avio_seek(pb, offSetup, SEEK_SET);
+ avio_skip(pb, 140); // FrameRatae16 .. descriptionOld
+ if (avio_rl16(pb) != 0x5453)
+ return AVERROR_INVALIDDATA;
+ length = avio_rl16(pb);
+ if (length < 0x163C) {
+ avpriv_request_sample(avctx, "short SETUP header");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 616); // Binning .. bFlipH
+ if (!avio_rl32(pb) ^ vflip) {
+ st->codec->extradata = av_strdup("BottomUp");
+ st->codec->extradata_size = 9;
+ }
+
+ avio_skip(pb, 4); // Grid
+
+ avpriv_set_pts_info(st, 64, 1, avio_rl32(pb));
+
+ avio_skip(pb, 20); // Shutter .. bEnableColor
+
+ set_metadata_int(&st->metadata, "camera_version", avio_rl32(pb), 0);
+ set_metadata_int(&st->metadata, "firmware_version", avio_rl32(pb), 0);
+ set_metadata_int(&st->metadata, "software_version", avio_rl32(pb), 0);
+ set_metadata_int(&st->metadata, "recording_timezone", avio_rl32(pb), 0);
+
+ CFA = avio_rl32(pb);
+
+ set_metadata_int(&st->metadata, "brightness", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "contrast", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "gamma", avio_rl32(pb), 1);
+
+ avio_skip(pb, 12 + 16); // Reserved1 .. AutoExpRect
+ set_metadata_float(&st->metadata, "wbgain[0].r", av_int2float(avio_rl32(pb)), 1);
+ set_metadata_float(&st->metadata, "wbgain[0].b", av_int2float(avio_rl32(pb)), 1);
+ avio_skip(pb, 36); // WBGain[1].. WBView
+
+ st->codec->bits_per_coded_sample = avio_rl32(pb);
+
+ if (compression == CC_RGB) {
+ if (biBitCount == 8) {
+ st->codec->pix_fmt = AV_PIX_FMT_GRAY8;
+ } else if (biBitCount == 16) {
+ st->codec->pix_fmt = AV_PIX_FMT_GRAY16LE;
+ } else if (biBitCount == 24) {
+ st->codec->pix_fmt = AV_PIX_FMT_BGR24;
+ } else if (biBitCount == 48) {
+ st->codec->pix_fmt = AV_PIX_FMT_BGR48LE;
+ } else {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+ } else if (compression == CC_UNINT) {
+ switch (CFA & 0xFFFFFF) {
+ case CFA_BAYER:
+ if (biBitCount == 8) {
+ st->codec->pix_fmt = AV_PIX_FMT_BAYER_GBRG8;
+ } else if (biBitCount == 16) {
+ st->codec->pix_fmt = AV_PIX_FMT_BAYER_GBRG16LE;
+ } else {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ case CFA_BAYERFLIP:
+ if (biBitCount == 8) {
+ st->codec->pix_fmt = AV_PIX_FMT_BAYER_RGGB8;
+ } else if (biBitCount == 16) {
+ st->codec->pix_fmt = AV_PIX_FMT_BAYER_RGGB16LE;
+ } else {
+ avpriv_request_sample(avctx, "unsupported biBitCount %i", biBitCount);
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ default:
+ avpriv_request_sample(avctx, "unsupported Color Field Array (CFA) %i", CFA & 0xFFFFFF);
+ return AVERROR_INVALIDDATA;
+ }
+ } else { //CC_LEAD
+ avpriv_request_sample(avctx, "unsupported compression %i", compression);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 668); // Conv8Min ... Sensor
+
+ set_metadata_int(&st->metadata, "shutter_ns", avio_rl32(pb), 0);
+
+ avio_skip(pb, 24); // EDRShutterNs ... ImHeightAcq
+
+#define DESCRIPTION_SIZE 4096
+ description = av_malloc(DESCRIPTION_SIZE + 1);
+ if (!description)
+ return AVERROR(ENOMEM);
+ i = avio_get_str(pb, DESCRIPTION_SIZE, description, DESCRIPTION_SIZE + 1);
+ if (i < DESCRIPTION_SIZE)
+ avio_skip(pb, DESCRIPTION_SIZE - i);
+ if (description[0])
+ av_dict_set(&st->metadata, "description", description, AV_DICT_DONT_STRDUP_VAL);
+ else
+ av_free(description);
+
+ avio_skip(pb, 1176); // RisingEdge ... cmUser
+
+ set_metadata_int(&st->metadata, "enable_crop", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_left", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_top", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_right", avio_rl32(pb), 1);
+ set_metadata_int(&st->metadata, "crop_bottom", avio_rl32(pb), 1);
+
+ /* parse image offsets */
+ avio_seek(pb, offImageOffsets, SEEK_SET);
+ for (i = 0; i < st->duration; i++)
+ av_add_index_entry(st, avio_rl64(pb), i, 0, 0, AVINDEX_KEYFRAME);
+
+ return 0;
+}
+
+static int cine_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ CineDemuxContext *cine = avctx->priv_data;
+ AVStream *st = avctx->streams[0];
+ AVIOContext *pb = avctx->pb;
+ int n, size, ret;
+
+ if (cine->pts >= st->duration)
+ return AVERROR_EOF;
+
+ avio_seek(pb, st->index_entries[cine->pts].pos, SEEK_SET);
+ n = avio_rl32(pb);
+ if (n < 8)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, n - 8);
+ size = avio_rl32(pb);
+
+ ret = av_get_packet(pb, pkt, size);
+ if (ret < 0)
+ return ret;
+
+ pkt->pts = cine->pts++;
+ pkt->stream_index = 0;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ return 0;
+}
+
+static int cine_read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags)
+{
+ CineDemuxContext *cine = avctx->priv_data;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
+ if (!avctx->pb->seekable)
+ return AVERROR(EIO);
+
+ cine->pts = timestamp;
+ return 0;
+}
+
+AVInputFormat ff_cine_demuxer = {
+ .name = "cine",
+ .long_name = NULL_IF_CONFIG_SMALL("Phantom Cine"),
+ .priv_data_size = sizeof(CineDemuxContext),
+ .read_probe = cine_read_probe,
+ .read_header = cine_read_header,
+ .read_packet = cine_read_packet,
+ .read_seek = cine_read_seek,
+};
diff --git a/libavformat/concat.c b/libavformat/concat.c
index 2fb3ba9059..81fe97082c 100644
--- a/libavformat/concat.c
+++ b/libavformat/concat.c
@@ -4,20 +4,20 @@
* Copyright (c) 2007 Wolfram Gloger
* Copyright (c) 2010 Michele OrrĂ¹
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -114,9 +114,10 @@ static av_cold int concat_open(URLContext *h, const char *uri, int flags)
if (err < 0)
concat_close(h);
- else if ((err = av_reallocp(&nodes, data->length * sizeof(*nodes))) < 0)
+ else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
concat_close(h);
- else
+ err = AVERROR(ENOMEM);
+ } else
data->nodes = nodes;
return err;
}
diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c
new file mode 100644
index 0000000000..f07cfd7e8f
--- /dev/null
+++ b/libavformat/concatdec.c
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/timestamp.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+
+typedef enum ConcatMatchMode {
+ MATCH_ONE_TO_ONE,
+ MATCH_EXACT_ID,
+} ConcatMatchMode;
+
+typedef struct ConcatStream {
+ AVBitStreamFilterContext *bsf;
+ int out_stream_index;
+} ConcatStream;
+
+typedef struct {
+ char *url;
+ int64_t start_time;
+ int64_t duration;
+ ConcatStream *streams;
+ int nb_streams;
+} ConcatFile;
+
+typedef struct {
+ AVClass *class;
+ ConcatFile *files;
+ ConcatFile *cur_file;
+ unsigned nb_files;
+ AVFormatContext *avf;
+ int safe;
+ int seekable;
+ ConcatMatchMode stream_match_mode;
+ unsigned auto_convert;
+} ConcatContext;
+
+static int concat_probe(AVProbeData *probe)
+{
+ return memcmp(probe->buf, "ffconcat version 1.0", 20) ?
+ 0 : AVPROBE_SCORE_MAX;
+}
+
+static char *get_keyword(uint8_t **cursor)
+{
+ char *ret = *cursor += strspn(*cursor, SPACE_CHARS);
+ *cursor += strcspn(*cursor, SPACE_CHARS);
+ if (**cursor) {
+ *((*cursor)++) = 0;
+ *cursor += strspn(*cursor, SPACE_CHARS);
+ }
+ return ret;
+}
+
+static int safe_filename(const char *f)
+{
+ const char *start = f;
+
+ for (; *f; f++) {
+ /* A-Za-z0-9_- */
+ if (!((unsigned)((*f | 32) - 'a') < 26 ||
+ (unsigned)(*f - '0') < 10 || *f == '_' || *f == '-')) {
+ if (f == start)
+ return 0;
+ else if (*f == '/')
+ start = f + 1;
+ else if (*f != '.')
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#define FAIL(retcode) do { ret = (retcode); goto fail; } while(0)
+
+static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile,
+ unsigned *nb_files_alloc)
+{
+ ConcatContext *cat = avf->priv_data;
+ ConcatFile *file;
+ char *url = NULL;
+ const char *proto;
+ size_t url_len, proto_len;
+ int ret;
+
+ if (cat->safe > 0 && !safe_filename(filename)) {
+ av_log(avf, AV_LOG_ERROR, "Unsafe file name '%s'\n", filename);
+ FAIL(AVERROR(EPERM));
+ }
+
+ proto = avio_find_protocol_name(filename);
+ proto_len = proto ? strlen(proto) : 0;
+ if (!memcmp(filename, proto, proto_len) &&
+ (filename[proto_len] == ':' || filename[proto_len] == ',')) {
+ url = filename;
+ filename = NULL;
+ } else {
+ url_len = strlen(avf->filename) + strlen(filename) + 16;
+ if (!(url = av_malloc(url_len)))
+ FAIL(AVERROR(ENOMEM));
+ ff_make_absolute_url(url, url_len, avf->filename, filename);
+ av_freep(&filename);
+ }
+
+ if (cat->nb_files >= *nb_files_alloc) {
+ size_t n = FFMAX(*nb_files_alloc * 2, 16);
+ ConcatFile *new_files;
+ if (n <= cat->nb_files || n > SIZE_MAX / sizeof(*cat->files) ||
+ !(new_files = av_realloc(cat->files, n * sizeof(*cat->files))))
+ FAIL(AVERROR(ENOMEM));
+ cat->files = new_files;
+ *nb_files_alloc = n;
+ }
+
+ file = &cat->files[cat->nb_files++];
+ memset(file, 0, sizeof(*file));
+ *rfile = file;
+
+ file->url = url;
+ file->start_time = AV_NOPTS_VALUE;
+ file->duration = AV_NOPTS_VALUE;
+
+ return 0;
+
+fail:
+ av_free(url);
+ av_free(filename);
+ return ret;
+}
+
+static int copy_stream_props(AVStream *st, AVStream *source_st)
+{
+ int ret;
+
+ if (st->codec->codec_id || !source_st->codec->codec_id) {
+ if (st->codec->extradata_size < source_st->codec->extradata_size) {
+ ret = ff_alloc_extradata(st->codec,
+ source_st->codec->extradata_size);
+ if (ret < 0)
+ return ret;
+ }
+ memcpy(st->codec->extradata, source_st->codec->extradata,
+ source_st->codec->extradata_size);
+ return 0;
+ }
+ if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0)
+ return ret;
+ st->r_frame_rate = source_st->r_frame_rate;
+ st->avg_frame_rate = source_st->avg_frame_rate;
+ st->time_base = source_st->time_base;
+ st->sample_aspect_ratio = source_st->sample_aspect_ratio;
+ return 0;
+}
+
+static int detect_stream_specific(AVFormatContext *avf, int idx)
+{
+ ConcatContext *cat = avf->priv_data;
+ AVStream *st = cat->avf->streams[idx];
+ ConcatStream *cs = &cat->cur_file->streams[idx];
+ AVBitStreamFilterContext *bsf;
+
+ if (cat->auto_convert && st->codec->codec_id == AV_CODEC_ID_H264 &&
+ (st->codec->extradata_size < 4 || AV_RB32(st->codec->extradata) != 1)) {
+ av_log(cat->avf, AV_LOG_INFO,
+ "Auto-inserting h264_mp4toannexb bitstream filter\n");
+ if (!(bsf = av_bitstream_filter_init("h264_mp4toannexb"))) {
+ av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb bitstream filter "
+ "required for H.264 streams\n");
+ return AVERROR_BSF_NOT_FOUND;
+ }
+ cs->bsf = bsf;
+ }
+ return 0;
+}
+
+static int match_streams_one_to_one(AVFormatContext *avf)
+{
+ ConcatContext *cat = avf->priv_data;
+ AVStream *st;
+ int i, ret;
+
+ for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
+ if (i < avf->nb_streams) {
+ st = avf->streams[i];
+ } else {
+ if (!(st = avformat_new_stream(avf, NULL)))
+ return AVERROR(ENOMEM);
+ }
+ if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0)
+ return ret;
+ cat->cur_file->streams[i].out_stream_index = i;
+ }
+ return 0;
+}
+
+static int match_streams_exact_id(AVFormatContext *avf)
+{
+ ConcatContext *cat = avf->priv_data;
+ AVStream *st;
+ int i, j, ret;
+
+ for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
+ st = cat->avf->streams[i];
+ for (j = 0; j < avf->nb_streams; j++) {
+ if (avf->streams[j]->id == st->id) {
+ av_log(avf, AV_LOG_VERBOSE,
+ "Match slave stream #%d with stream #%d id 0x%x\n",
+ i, j, st->id);
+ if ((ret = copy_stream_props(avf->streams[j], st)) < 0)
+ return ret;
+ cat->cur_file->streams[i].out_stream_index = j;
+ }
+ }
+ }
+ return 0;
+}
+
+static int match_streams(AVFormatContext *avf)
+{
+ ConcatContext *cat = avf->priv_data;
+ ConcatStream *map;
+ int i, ret;
+
+ if (cat->cur_file->nb_streams >= cat->avf->nb_streams)
+ return 0;
+ map = av_realloc(cat->cur_file->streams,
+ cat->avf->nb_streams * sizeof(*map));
+ if (!map)
+ return AVERROR(ENOMEM);
+ cat->cur_file->streams = map;
+ memset(map + cat->cur_file->nb_streams, 0,
+ (cat->avf->nb_streams - cat->cur_file->nb_streams) * sizeof(*map));
+
+ for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++)
+ map[i].out_stream_index = -1;
+ switch (cat->stream_match_mode) {
+ case MATCH_ONE_TO_ONE:
+ ret = match_streams_one_to_one(avf);
+ break;
+ case MATCH_EXACT_ID:
+ ret = match_streams_exact_id(avf);
+ break;
+ default:
+ ret = AVERROR_BUG;
+ }
+ if (ret < 0)
+ return ret;
+ for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++)
+ if ((ret = detect_stream_specific(avf, i)) < 0)
+ return ret;
+ cat->cur_file->nb_streams = cat->avf->nb_streams;
+ return 0;
+}
+
+static int open_file(AVFormatContext *avf, unsigned fileno)
+{
+ ConcatContext *cat = avf->priv_data;
+ ConcatFile *file = &cat->files[fileno];
+ int ret;
+
+ if (cat->avf)
+ avformat_close_input(&cat->avf);
+
+ cat->avf = avformat_alloc_context();
+ if (!cat->avf)
+ return AVERROR(ENOMEM);
+
+ cat->avf->interrupt_callback = avf->interrupt_callback;
+
+ if ((ret = ff_copy_whitelists(cat->avf, avf)) < 0)
+ return ret;
+
+ if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 ||
+ (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) {
+ av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url);
+ avformat_close_input(&cat->avf);
+ return ret;
+ }
+ cat->cur_file = file;
+ if (file->start_time == AV_NOPTS_VALUE)
+ file->start_time = !fileno ? 0 :
+ cat->files[fileno - 1].start_time +
+ cat->files[fileno - 1].duration;
+ if ((ret = match_streams(avf)) < 0)
+ return ret;
+ return 0;
+}
+
+static int concat_read_close(AVFormatContext *avf)
+{
+ ConcatContext *cat = avf->priv_data;
+ unsigned i;
+
+ if (cat->avf)
+ avformat_close_input(&cat->avf);
+ for (i = 0; i < cat->nb_files; i++) {
+ av_freep(&cat->files[i].url);
+ av_freep(&cat->files[i].streams);
+ }
+ av_freep(&cat->files);
+ return 0;
+}
+
+static int concat_read_header(AVFormatContext *avf)
+{
+ ConcatContext *cat = avf->priv_data;
+ uint8_t buf[4096];
+ uint8_t *cursor, *keyword;
+ int ret, line = 0, i;
+ unsigned nb_files_alloc = 0;
+ ConcatFile *file = NULL;
+ int64_t time = 0;
+
+ while (1) {
+ if ((ret = ff_get_line(avf->pb, buf, sizeof(buf))) <= 0)
+ break;
+ line++;
+ cursor = buf;
+ keyword = get_keyword(&cursor);
+ if (!*keyword || *keyword == '#')
+ continue;
+
+ if (!strcmp(keyword, "file")) {
+ char *filename = av_get_token((const char **)&cursor, SPACE_CHARS);
+ if (!filename) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: filename required\n", line);
+ FAIL(AVERROR_INVALIDDATA);
+ }
+ if ((ret = add_file(avf, filename, &file, &nb_files_alloc)) < 0)
+ goto fail;
+ } else if (!strcmp(keyword, "duration")) {
+ char *dur_str = get_keyword(&cursor);
+ int64_t dur;
+ if (!file) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: duration without file\n",
+ line);
+ FAIL(AVERROR_INVALIDDATA);
+ }
+ if ((ret = av_parse_time(&dur, dur_str, 1)) < 0) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: invalid duration '%s'\n",
+ line, dur_str);
+ goto fail;
+ }
+ file->duration = dur;
+ } else if (!strcmp(keyword, "stream")) {
+ if (!avformat_new_stream(avf, NULL))
+ FAIL(AVERROR(ENOMEM));
+ } else if (!strcmp(keyword, "exact_stream_id")) {
+ if (!avf->nb_streams) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: exact_stream_id without stream\n",
+ line);
+ FAIL(AVERROR_INVALIDDATA);
+ }
+ avf->streams[avf->nb_streams - 1]->id =
+ strtol(get_keyword(&cursor), NULL, 0);
+ } else if (!strcmp(keyword, "ffconcat")) {
+ char *ver_kw = get_keyword(&cursor);
+ char *ver_val = get_keyword(&cursor);
+ if (strcmp(ver_kw, "version") || strcmp(ver_val, "1.0")) {
+ av_log(avf, AV_LOG_ERROR, "Line %d: invalid version\n", line);
+ FAIL(AVERROR_INVALIDDATA);
+ }
+ if (cat->safe < 0)
+ cat->safe = 1;
+ } else {
+ av_log(avf, AV_LOG_ERROR, "Line %d: unknown keyword '%s'\n",
+ line, keyword);
+ FAIL(AVERROR_INVALIDDATA);
+ }
+ }
+ if (ret < 0)
+ goto fail;
+ if (!cat->nb_files)
+ FAIL(AVERROR_INVALIDDATA);
+
+ for (i = 0; i < cat->nb_files; i++) {
+ if (cat->files[i].start_time == AV_NOPTS_VALUE)
+ cat->files[i].start_time = time;
+ else
+ time = cat->files[i].start_time;
+ if (cat->files[i].duration == AV_NOPTS_VALUE)
+ break;
+ time += cat->files[i].duration;
+ }
+ if (i == cat->nb_files) {
+ avf->duration = time;
+ cat->seekable = 1;
+ }
+
+ cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID :
+ MATCH_ONE_TO_ONE;
+ if ((ret = open_file(avf, 0)) < 0)
+ goto fail;
+ return 0;
+
+fail:
+ concat_read_close(avf);
+ return ret;
+}
+
+static int open_next_file(AVFormatContext *avf)
+{
+ ConcatContext *cat = avf->priv_data;
+ unsigned fileno = cat->cur_file - cat->files;
+
+ if (cat->cur_file->duration == AV_NOPTS_VALUE)
+ cat->cur_file->duration = cat->avf->duration;
+
+ if (++fileno >= cat->nb_files)
+ return AVERROR_EOF;
+ return open_file(avf, fileno);
+}
+
+static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt)
+{
+ AVStream *st = avf->streams[cs->out_stream_index];
+ AVBitStreamFilterContext *bsf;
+ AVPacket pkt2;
+ int ret;
+
+ av_assert0(cs->out_stream_index >= 0);
+ for (bsf = cs->bsf; bsf; bsf = bsf->next) {
+ pkt2 = *pkt;
+ ret = av_bitstream_filter_filter(bsf, st->codec, NULL,
+ &pkt2.data, &pkt2.size,
+ pkt->data, pkt->size,
+ !!(pkt->flags & AV_PKT_FLAG_KEY));
+ if (ret < 0) {
+ av_packet_unref(pkt);
+ return ret;
+ }
+ av_assert0(pkt2.buf);
+ if (ret == 0 && pkt2.data != pkt->data) {
+ if ((ret = av_copy_packet(&pkt2, pkt)) < 0) {
+ av_free(pkt2.data);
+ return ret;
+ }
+ ret = 1;
+ }
+ if (ret > 0) {
+ av_free_packet(pkt);
+ pkt2.buf = av_buffer_create(pkt2.data, pkt2.size,
+ av_buffer_default_free, NULL, 0);
+ if (!pkt2.buf) {
+ av_free(pkt2.data);
+ return AVERROR(ENOMEM);
+ }
+ }
+ *pkt = pkt2;
+ }
+ return 0;
+}
+
+static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+ ConcatContext *cat = avf->priv_data;
+ int ret;
+ int64_t file_start_time, delta;
+ ConcatStream *cs;
+ AVStream *st;
+
+ if (!cat->avf)
+ return AVERROR(EIO);
+
+ while (1) {
+ ret = av_read_frame(cat->avf, pkt);
+ if (ret == AVERROR_EOF) {
+ if ((ret = open_next_file(avf)) < 0)
+ return ret;
+ continue;
+ }
+ if (ret < 0)
+ return ret;
+ if ((ret = match_streams(avf)) < 0) {
+ av_packet_unref(pkt);
+ return ret;
+ }
+ cs = &cat->cur_file->streams[pkt->stream_index];
+ if (cs->out_stream_index < 0) {
+ av_packet_unref(pkt);
+ continue;
+ }
+ pkt->stream_index = cs->out_stream_index;
+ break;
+ }
+ if ((ret = filter_packet(avf, cs, pkt)))
+ return ret;
+
+ st = cat->avf->streams[pkt->stream_index];
+ av_log(avf, AV_LOG_DEBUG, "file:%d stream:%d pts:%s pts_time:%s dts:%s dts_time:%s",
+ (unsigned)(cat->cur_file - cat->files), pkt->stream_index,
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
+
+ file_start_time = cat->avf->start_time;
+ if (file_start_time == AV_NOPTS_VALUE)
+ file_start_time = 0;
+ delta = av_rescale_q(cat->cur_file->start_time - file_start_time,
+ AV_TIME_BASE_Q,
+ cat->avf->streams[pkt->stream_index]->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += delta;
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += delta;
+ av_log(avf, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
+ return ret;
+}
+
+static void rescale_interval(AVRational tb_in, AVRational tb_out,
+ int64_t *min_ts, int64_t *ts, int64_t *max_ts)
+{
+ *ts = av_rescale_q (* ts, tb_in, tb_out);
+ *min_ts = av_rescale_q_rnd(*min_ts, tb_in, tb_out,
+ AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
+ *max_ts = av_rescale_q_rnd(*max_ts, tb_in, tb_out,
+ AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+}
+
+static int try_seek(AVFormatContext *avf, int stream,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ ConcatContext *cat = avf->priv_data;
+ int64_t t0 = cat->cur_file->start_time - cat->avf->start_time;
+
+ ts -= t0;
+ min_ts = min_ts == INT64_MIN ? INT64_MIN : min_ts - t0;
+ max_ts = max_ts == INT64_MAX ? INT64_MAX : max_ts - t0;
+ if (stream >= 0) {
+ if (stream >= cat->avf->nb_streams)
+ return AVERROR(EIO);
+ rescale_interval(AV_TIME_BASE_Q, cat->avf->streams[stream]->time_base,
+ &min_ts, &ts, &max_ts);
+ }
+ return avformat_seek_file(cat->avf, stream, min_ts, ts, max_ts, flags);
+}
+
+static int real_seek(AVFormatContext *avf, int stream,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ ConcatContext *cat = avf->priv_data;
+ int ret, left, right;
+
+ if (stream >= 0) {
+ if (stream >= avf->nb_streams)
+ return AVERROR(EINVAL);
+ rescale_interval(avf->streams[stream]->time_base, AV_TIME_BASE_Q,
+ &min_ts, &ts, &max_ts);
+ }
+
+ left = 0;
+ right = cat->nb_files;
+ while (right - left > 1) {
+ int mid = (left + right) / 2;
+ if (ts < cat->files[mid].start_time)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ if ((ret = open_file(avf, left)) < 0)
+ return ret;
+
+ ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
+ if (ret < 0 &&
+ left < cat->nb_files - 1 &&
+ cat->files[left + 1].start_time < max_ts) {
+ if ((ret = open_file(avf, left + 1)) < 0)
+ return ret;
+ ret = try_seek(avf, stream, min_ts, ts, max_ts, flags);
+ }
+ return ret;
+}
+
+static int concat_seek(AVFormatContext *avf, int stream,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ ConcatContext *cat = avf->priv_data;
+ ConcatFile *cur_file_saved = cat->cur_file;
+ AVFormatContext *cur_avf_saved = cat->avf;
+ int ret;
+
+ if (!cat->seekable)
+ return AVERROR(ESPIPE); /* XXX: can we use it? */
+ if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME))
+ return AVERROR(ENOSYS);
+ cat->avf = NULL;
+ if ((ret = real_seek(avf, stream, min_ts, ts, max_ts, flags)) < 0) {
+ if (cat->avf)
+ avformat_close_input(&cat->avf);
+ cat->avf = cur_avf_saved;
+ cat->cur_file = cur_file_saved;
+ } else {
+ avformat_close_input(&cur_avf_saved);
+ }
+ return ret;
+}
+
+#define OFFSET(x) offsetof(ConcatContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption options[] = {
+ { "safe", "enable safe mode",
+ OFFSET(safe), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, DEC },
+ { "auto_convert", "automatically convert bitstream format",
+ OFFSET(auto_convert), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
+ { NULL }
+};
+
+static const AVClass concat_class = {
+ .class_name = "concat demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+
+AVInputFormat ff_concat_demuxer = {
+ .name = "concat",
+ .long_name = NULL_IF_CONFIG_SMALL("Virtual concatenation script"),
+ .priv_data_size = sizeof(ConcatContext),
+ .read_probe = concat_probe,
+ .read_header = concat_read_header,
+ .read_packet = concat_read_packet,
+ .read_close = concat_read_close,
+ .read_seek2 = concat_seek,
+ .priv_class = &concat_class,
+};
diff --git a/libavformat/crcenc.c b/libavformat/crcenc.c
index 925646bc5e..3fdfea5207 100644
--- a/libavformat/crcenc.c
+++ b/libavformat/crcenc.c
@@ -2,20 +2,20 @@
* CRC encoder (for codec/format testing)
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -59,7 +59,6 @@ static int crc_write_trailer(struct AVFormatContext *s)
AVOutputFormat ff_crc_muxer = {
.name = "crc",
.long_name = NULL_IF_CONFIG_SMALL("CRC testing"),
- .extensions = "",
.priv_data_size = sizeof(CRCState),
.audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_RAWVIDEO,
diff --git a/libavformat/crypto.c b/libavformat/crypto.c
index 6b19b5ee23..f56ee4eb17 100644
--- a/libavformat/crypto.c
+++ b/libavformat/crypto.c
@@ -2,20 +2,20 @@
* Decryption protocol handler
* Copyright (c) 2011 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,14 +41,32 @@ typedef struct CryptoContext {
int keylen;
uint8_t *iv;
int ivlen;
- struct AVAES *aes;
+ uint8_t *decrypt_key;
+ int decrypt_keylen;
+ uint8_t *decrypt_iv;
+ int decrypt_ivlen;
+ uint8_t *encrypt_key;
+ int encrypt_keylen;
+ uint8_t *encrypt_iv;
+ int encrypt_ivlen;
+ struct AVAES *aes_decrypt;
+ struct AVAES *aes_encrypt;
+
+ uint8_t pad[BLOCKSIZE];
+ int pad_len;
+
} 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[] = {
- {"key", "AES decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, .flags = D },
- {"iv", "AES decryption initialization vector", OFFSET(iv), AV_OPT_TYPE_BINARY, .flags = D },
+ {"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 },
+ {"decryption_iv", "AES decryption initialization vector", OFFSET(decrypt_iv), AV_OPT_TYPE_BINARY, .flags = D },
+ {"encryption_key", "AES encryption key", OFFSET(encrypt_key), AV_OPT_TYPE_BINARY, .flags = E },
+ {"encryption_iv", "AES encryption initialization vector", OFFSET(encrypt_iv), AV_OPT_TYPE_BINARY, .flags = E },
{ NULL }
};
@@ -59,7 +77,34 @@ static const AVClass crypto_class = {
.version = LIBAVUTIL_VERSION_INT,
};
-static int crypto_open(URLContext *h, const char *uri, int flags)
+static int set_aes_arg(CryptoContext *c, uint8_t **buf, int *buf_len,
+ uint8_t *default_buf, int default_buf_len,
+ const char *desc)
+{
+ if (!*buf_len) {
+ if (!default_buf_len) {
+ av_log(c, AV_LOG_ERROR, "%s not set\n", desc);
+ return AVERROR(EINVAL);
+ } else if (default_buf_len != BLOCKSIZE) {
+ av_log(c, AV_LOG_ERROR,
+ "invalid %s size (%d bytes, block size is %d)\n",
+ desc, default_buf_len, BLOCKSIZE);
+ return AVERROR(EINVAL);
+ }
+ *buf = av_memdup(default_buf, default_buf_len);
+ if (!*buf)
+ return AVERROR(ENOMEM);
+ *buf_len = default_buf_len;
+ } else if (*buf_len != BLOCKSIZE) {
+ av_log(c, AV_LOG_ERROR,
+ "invalid %s size (%d bytes, block size is %d)\n",
+ desc, *buf_len, BLOCKSIZE);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
+static int crypto_open2(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
const char *nested_url;
int ret = 0;
@@ -72,28 +117,54 @@ static int crypto_open(URLContext *h, const char *uri, int flags)
goto err;
}
- if (c->keylen < BLOCKSIZE || c->ivlen < BLOCKSIZE) {
- av_log(h, AV_LOG_ERROR, "Key or IV not set\n");
- ret = AVERROR(EINVAL);
- goto err;
+ if (flags & AVIO_FLAG_READ) {
+ if ((ret = set_aes_arg(c, &c->decrypt_key, &c->decrypt_keylen,
+ c->key, c->keylen, "decryption key")) < 0)
+ goto err;
+ if ((ret = set_aes_arg(c, &c->decrypt_iv, &c->decrypt_ivlen,
+ c->iv, c->ivlen, "decryption IV")) < 0)
+ goto err;
}
+
if (flags & AVIO_FLAG_WRITE) {
- av_log(h, AV_LOG_ERROR, "Only decryption is supported currently\n");
- ret = AVERROR(ENOSYS);
- goto err;
+ if ((ret = set_aes_arg(c, &c->encrypt_key, &c->encrypt_keylen,
+ c->key, c->keylen, "encryption key")) < 0)
+ if (ret < 0)
+ goto err;
+ if ((ret = set_aes_arg(c, &c->encrypt_iv, &c->encrypt_ivlen,
+ c->iv, c->ivlen, "encryption IV")) < 0)
+ goto err;
}
- if ((ret = ffurl_open(&c->hd, nested_url, AVIO_FLAG_READ,
- &h->interrupt_callback, NULL)) < 0) {
- av_log(h, AV_LOG_ERROR, "Unable to open input\n");
+
+ if ((ret = ffurl_open(&c->hd, nested_url, flags,
+ &h->interrupt_callback, options)) < 0) {
+ av_log(h, AV_LOG_ERROR, "Unable to open resource: %s\n", nested_url);
goto err;
}
- c->aes = av_aes_alloc();
- if (!c->aes) {
- ret = AVERROR(ENOMEM);
- goto err;
+
+ if (flags & AVIO_FLAG_READ) {
+ c->aes_decrypt = av_aes_alloc();
+ if (!c->aes_decrypt) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+ ret = av_aes_init(c->aes_decrypt, c->decrypt_key, BLOCKSIZE*8, 1);
+ if (ret < 0)
+ goto err;
}
- av_aes_init(c->aes, c->key, 128, 1);
+ if (flags & AVIO_FLAG_WRITE) {
+ c->aes_encrypt = av_aes_alloc();
+ if (!c->aes_encrypt) {
+ ret = AVERROR(ENOMEM);
+ goto err;
+ }
+ ret = av_aes_init(c->aes_encrypt, c->encrypt_key, BLOCKSIZE*8, 0);
+ if (ret < 0)
+ goto err;
+ }
+
+ c->pad_len = 0;
h->is_streamed = 1;
@@ -131,8 +202,8 @@ retry:
return AVERROR_EOF;
if (!c->eof)
blocks--;
- av_aes_crypt(c->aes, c->outbuffer, c->inbuffer + c->indata_used, blocks,
- c->iv, 1);
+ av_aes_crypt(c->aes_decrypt, c->outbuffer, c->inbuffer + c->indata_used,
+ blocks, c->decrypt_iv, 1);
c->outdata = BLOCKSIZE * blocks;
c->outptr = c->outbuffer;
c->indata_used += BLOCKSIZE * blocks;
@@ -150,19 +221,73 @@ retry:
goto retry;
}
+static int crypto_write(URLContext *h, const unsigned char *buf, int size)
+{
+ CryptoContext *c = h->priv_data;
+ int total_size, blocks, pad_len, out_size;
+ uint8_t *out_buf;
+ int ret = 0;
+
+ total_size = size + c->pad_len;
+ pad_len = total_size % BLOCKSIZE;
+ out_size = total_size - pad_len;
+ blocks = out_size / BLOCKSIZE;
+
+ if (out_size) {
+ out_buf = av_malloc(out_size);
+ if (!out_buf)
+ return AVERROR(ENOMEM);
+
+ if (c->pad_len) {
+ memcpy(&c->pad[c->pad_len], buf, BLOCKSIZE - c->pad_len);
+ av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0);
+ blocks--;
+ }
+
+ av_aes_crypt(c->aes_encrypt, &out_buf[c->pad_len ? BLOCKSIZE : 0],
+ &buf[c->pad_len ? BLOCKSIZE - c->pad_len: 0],
+ blocks, c->encrypt_iv, 0);
+
+ ret = ffurl_write(c->hd, out_buf, out_size);
+ av_free(out_buf);
+ if (ret < 0)
+ return ret;
+
+ memcpy(c->pad, &buf[size - pad_len], pad_len);
+ } else
+ memcpy(&c->pad[c->pad_len], buf, size);
+
+ c->pad_len = pad_len;
+
+ return size;
+}
+
static int crypto_close(URLContext *h)
{
CryptoContext *c = h->priv_data;
+ uint8_t out_buf[BLOCKSIZE];
+ int ret, pad;
+
+ if (c->aes_encrypt) {
+ pad = BLOCKSIZE - c->pad_len;
+ memset(&c->pad[c->pad_len], pad, pad);
+ av_aes_crypt(c->aes_encrypt, out_buf, c->pad, 1, c->encrypt_iv, 0);
+ if ((ret = ffurl_write(c->hd, out_buf, BLOCKSIZE)) < 0)
+ return ret;
+ }
+
if (c->hd)
ffurl_close(c->hd);
- av_freep(&c->aes);
+ av_freep(&c->aes_decrypt);
+ av_freep(&c->aes_encrypt);
return 0;
}
URLProtocol ff_crypto_protocol = {
.name = "crypto",
- .url_open = crypto_open,
+ .url_open2 = crypto_open2,
.url_read = crypto_read,
+ .url_write = crypto_write,
.url_close = crypto_close,
.priv_data_size = sizeof(CryptoContext),
.priv_data_class = &crypto_class,
diff --git a/libavformat/cutils.c b/libavformat/cutils.c
index f5339a9c5d..d86ba05441 100644
--- a/libavformat/cutils.c
+++ b/libavformat/cutils.c
@@ -2,20 +2,20 @@
* various simple utilities for libavformat
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,27 +23,6 @@
#include "avformat.h"
#include "internal.h"
-/* add one element to a dynamic array */
-void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem)
-{
- /* see similar avconv.c:grow_array() */
- int nb, nb_alloc;
- intptr_t *tab;
-
- nb = *nb_ptr;
- tab = *tab_ptr;
- if ((nb & (nb - 1)) == 0) {
- if (nb == 0)
- nb_alloc = 1;
- else
- nb_alloc = nb * 2;
- tab = av_realloc(tab, nb_alloc * sizeof(intptr_t));
- *tab_ptr = tab;
- }
- tab[nb++] = elem;
- *nb_ptr = nb;
-}
-
#define ISLEAP(y) (((y) % 4 == 0) && (((y) % 100) != 0 || ((y) % 400) == 0))
#define LEAPS_COUNT(y) ((y)/4 - (y)/100 + (y)/400)
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index cedd83b67b..7a932147e5 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -2,20 +2,20 @@
* MPEG-DASH ISO BMFF segmenter
* Copyright (c) 2014 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -507,8 +507,10 @@ static int write_manifest(AVFormatContext *s, int final)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
OutputStream *os = &c->streams[i];
+
if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO)
continue;
+
avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/mp4\" codecs=\"%s\"%s width=\"%d\" height=\"%d\">\n", i, os->codec_str, os->bandwidth_str, st->codec->width, st->codec->height);
output_segment_list(&c->streams[i], out, c);
avio_printf(out, "\t\t\t</Representation>\n");
@@ -520,8 +522,10 @@ static int write_manifest(AVFormatContext *s, int final)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
OutputStream *os = &c->streams[i];
+
if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
continue;
+
avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/mp4\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n", i, os->codec_str, os->bandwidth_str, st->codec->sample_rate);
avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n", st->codec->channels);
output_segment_list(&c->streams[i], out, c);
@@ -533,7 +537,7 @@ static int write_manifest(AVFormatContext *s, int final)
avio_printf(out, "</MPD>\n");
avio_flush(out);
avio_close(out);
- return ff_rename(temp_filename, s->filename);
+ return ff_rename(temp_filename, s->filename, s);
}
static int dash_write_header(AVFormatContext *s)
@@ -582,7 +586,9 @@ static int dash_write_header(AVFormatContext *s)
AVDictionary *opts = NULL;
char filename[1024];
- os->bit_rate = s->streams[i]->codec->bit_rate;
+ os->bit_rate = s->streams[i]->codec->bit_rate ?
+ s->streams[i]->codec->bit_rate :
+ s->streams[i]->codec->rc_max_rate;
if (os->bit_rate) {
snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
" bandwidth=\"%d\"", os->bit_rate);
@@ -827,7 +833,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
} else {
ffurl_close(os->out);
os->out = NULL;
- ret = ff_rename(temp_path, full_path);
+ ret = ff_rename(temp_path, full_path, s);
if (ret < 0)
break;
}
@@ -933,7 +939,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
else
os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
os->packets_written++;
- return ff_write_chained(os->ctx, 0, pkt, s);
+ return ff_write_chained(os->ctx, 0, pkt, s, 0);
}
static int dash_write_trailer(AVFormatContext *s)
diff --git a/libavformat/data_uri.c b/libavformat/data_uri.c
new file mode 100644
index 0000000000..1598b999ae
--- /dev/null
+++ b/libavformat/data_uri.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include "libavutil/avstring.h"
+#include "libavutil/base64.h"
+#include "url.h"
+
+typedef struct {
+ const uint8_t *data;
+ void *tofree;
+ size_t size;
+ size_t pos;
+} DataContext;
+
+static av_cold int data_open(URLContext *h, const char *uri, int flags)
+{
+ DataContext *dc = h->priv_data;
+ const char *data, *opt, *next;
+ char *ddata;
+ int ret, base64 = 0;
+ size_t in_size;
+
+ /* data:content/type[;base64],payload */
+
+ av_strstart(uri, "data:", &uri);
+ data = strchr(uri, ',');
+ if (!data) {
+ av_log(h, AV_LOG_ERROR, "No ',' delimiter in URI\n");
+ return AVERROR(EINVAL);
+ }
+ opt = uri;
+ while (opt < data) {
+ next = av_x_if_null(memchr(opt, ';', data - opt), data);
+ if (opt == uri) {
+ if (!memchr(opt, '/', next - opt)) { /* basic validity check */
+ av_log(h, AV_LOG_ERROR, "Invalid content-type '%.*s'\n",
+ (int)(next - opt), opt);
+ return AVERROR(EINVAL);
+ }
+ av_log(h, AV_LOG_VERBOSE, "Content-type: %.*s\n",
+ (int)(next - opt), opt);
+ } else {
+ if (!av_strncasecmp(opt, "base64", next - opt)) {
+ base64 = 1;
+ } else {
+ av_log(h, AV_LOG_VERBOSE, "Ignoring option '%.*s'\n",
+ (int)(next - opt), opt);
+ }
+ }
+ opt = next + 1;
+ }
+
+ data++;
+ in_size = strlen(data);
+ if (base64) {
+ size_t out_size = 3 * (in_size / 4) + 1;
+
+ if (out_size > INT_MAX || !(ddata = av_malloc(out_size)))
+ return AVERROR(ENOMEM);
+ if ((ret = av_base64_decode(ddata, data, out_size)) < 0) {
+ av_free(ddata);
+ av_log(h, AV_LOG_ERROR, "Invalid base64 in URI\n");
+ return ret;
+ }
+ dc->data = dc->tofree = ddata;
+ dc->size = ret;
+ } else {
+ dc->data = data;
+ dc->size = in_size;
+ }
+ return 0;
+}
+
+static av_cold int data_close(URLContext *h)
+{
+ DataContext *dc = h->priv_data;
+
+ av_freep(&dc->tofree);
+ return 0;
+}
+
+static int data_read(URLContext *h, unsigned char *buf, int size)
+{
+ DataContext *dc = h->priv_data;
+
+ if (dc->pos >= dc->size)
+ return AVERROR_EOF;
+ size = FFMIN(size, dc->size - dc->pos);
+ memcpy(buf, dc->data + dc->pos, size);
+ dc->pos += size;
+ return size;
+}
+
+URLProtocol ff_data_protocol = {
+ .name = "data",
+ .url_open = data_open,
+ .url_close = data_close,
+ .url_read = data_read,
+ .priv_data_size = sizeof(DataContext),
+};
diff --git a/libavformat/dauddec.c b/libavformat/dauddec.c
index 1855e84aae..f6e7491985 100644
--- a/libavformat/dauddec.c
+++ b/libavformat/dauddec.c
@@ -2,20 +2,20 @@
* D-Cinema audio demuxer
* Copyright (c) 2005 Reimar Döffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -41,7 +41,7 @@ static int daud_header(AVFormatContext *s) {
static int daud_packet(AVFormatContext *s, AVPacket *pkt) {
AVIOContext *pb = s->pb;
int ret, size;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
size = avio_rb16(pb);
avio_rb16(pb); // unknown
@@ -55,5 +55,5 @@ AVInputFormat ff_daud_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("D-Cinema audio"),
.read_header = daud_header,
.read_packet = daud_packet,
- .extensions = "302",
+ .extensions = "302,daud",
};
diff --git a/libavformat/daudenc.c b/libavformat/daudenc.c
index 416e895395..99b18d35aa 100644
--- a/libavformat/daudenc.c
+++ b/libavformat/daudenc.c
@@ -2,20 +2,20 @@
* D-Cinema audio muxer
* Copyright (c) 2005 Reimar Döffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/dfa.c b/libavformat/dfa.c
index c097d72cf8..450bc2125c 100644
--- a/libavformat/dfa.c
+++ b/libavformat/dfa.c
@@ -2,20 +2,20 @@
* Chronomaster DFA Format Demuxer
* Copyright (c) 2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,9 @@ static int dfa_probe(AVProbeData *p)
if (p->buf_size < 4 || AV_RL32(p->buf) != MKTAG('D', 'F', 'I', 'A'))
return 0;
+ if (AV_RL32(p->buf + 16) != 0x80)
+ return AVPROBE_SCORE_MAX / 4;
+
return AVPROBE_SCORE_MAX;
}
@@ -38,13 +41,15 @@ static int dfa_read_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
AVStream *st;
int frames;
+ int version;
uint32_t mspf;
if (avio_rl32(pb) != MKTAG('D', 'F', 'I', 'A')) {
av_log(s, AV_LOG_ERROR, "Invalid magic for DFA\n");
return AVERROR_INVALIDDATA;
}
- avio_skip(pb, 2); // unused
+
+ version = avio_rl16(pb);
frames = avio_rl16(pb);
st = avformat_new_stream(s, NULL);
@@ -64,6 +69,12 @@ static int dfa_read_header(AVFormatContext *s)
avio_skip(pb, 128 - 16); // padding
st->duration = frames;
+ if (ff_alloc_extradata(st->codec, 2))
+ return AVERROR(ENOMEM);
+ AV_WL16(st->codec->extradata, version);
+ if (version == 0x100)
+ st->sample_aspect_ratio = (AVRational){2, 1};
+
return 0;
}
@@ -73,12 +84,12 @@ static int dfa_read_packet(AVFormatContext *s, AVPacket *pkt)
uint32_t frame_size;
int ret, first = 1;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
if (av_get_packet(pb, pkt, 12) != 12)
return AVERROR(EIO);
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
if (!first) {
ret = av_append_packet(pb, pkt, 12);
if (ret < 0) {
diff --git a/libavformat/diracdec.c b/libavformat/diracdec.c
index f275212d4a..e061ba5e8e 100644
--- a/libavformat/diracdec.c
+++ b/libavformat/diracdec.c
@@ -2,20 +2,20 @@
* RAW Dirac demuxer
* Copyright (c) 2007 Marco Gerards <marco@gnu.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,10 +25,19 @@
static int dirac_probe(AVProbeData *p)
{
- if (AV_RL32(p->buf) == MKTAG('B', 'B', 'C', 'D'))
- return AVPROBE_SCORE_MAX;
- else
+ unsigned size;
+ if (AV_RL32(p->buf) != MKTAG('B', 'B', 'C', 'D'))
return 0;
+
+ size = AV_RB32(p->buf+5);
+ if (size < 13)
+ return 0;
+ if (size + 13LL > p->buf_size)
+ return AVPROBE_SCORE_MAX / 4;
+ if (AV_RL32(p->buf + size) != MKTAG('B', 'B', 'C', 'D'))
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
}
FF_DEF_RAWVIDEO_DEMUXER(dirac, "raw Dirac", dirac_probe, NULL, AV_CODEC_ID_DIRAC)
diff --git a/libavformat/dnxhddec.c b/libavformat/dnxhddec.c
index 8bb68145fc..7b554003f1 100644
--- a/libavformat/dnxhddec.c
+++ b/libavformat/dnxhddec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@gmail.com>
* Copyright (c) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,7 +37,7 @@ static int dnxhd_probe(AVProbeData *p)
if (!w || !h)
return 0;
compression_id = AV_RB32(p->buf + 0x28);
- if (compression_id < 1237 || compression_id > 1253)
+ if (compression_id < 1235 || compression_id > 1253)
return 0;
return AVPROBE_SCORE_MAX;
}
diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c
new file mode 100644
index 0000000000..ae198b2e93
--- /dev/null
+++ b/libavformat/dsfdec.c
@@ -0,0 +1,159 @@
+/*
+ * DSD Stream File (DSF) demuxer
+ * Copyright (c) 2014 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "id3v2.h"
+
+typedef struct {
+ uint64_t data_end;
+} DSFContext;
+
+static int dsf_probe(AVProbeData *p)
+{
+ if (p->buf_size < 12 || memcmp(p->buf, "DSD ", 4) || AV_RL64(p->buf + 4) != 28)
+ return 0;
+ return AVPROBE_SCORE_MAX;
+}
+
+static const uint64_t dsf_channel_layout[] = {
+ 0,
+ AV_CH_LAYOUT_MONO,
+ AV_CH_LAYOUT_STEREO,
+ AV_CH_LAYOUT_SURROUND,
+ AV_CH_LAYOUT_QUAD,
+ AV_CH_LAYOUT_4POINT0,
+ AV_CH_LAYOUT_5POINT0_BACK,
+ AV_CH_LAYOUT_5POINT1_BACK,
+};
+
+static void read_id3(AVFormatContext *s, uint64_t id3pos)
+{
+ ID3v2ExtraMeta *id3v2_extra_meta = NULL;
+ if (avio_seek(s->pb, id3pos, SEEK_SET) < 0)
+ return;
+
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0);
+ if (id3v2_extra_meta)
+ ff_id3v2_parse_apic(s, &id3v2_extra_meta);
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+}
+
+static int dsf_read_header(AVFormatContext *s)
+{
+ DSFContext *dsf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ uint64_t id3pos;
+ unsigned int channel_type;
+
+ avio_skip(pb, 4);
+ if (avio_rl64(pb) != 28)
+ return AVERROR_INVALIDDATA;
+
+ /* create primary stream before any id3 coverart streams */
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 8);
+ id3pos = avio_rl64(pb);
+ if (pb->seekable) {
+ read_id3(s, id3pos);
+ avio_seek(pb, 28, SEEK_SET);
+ }
+
+ /* fmt chunk */
+
+ if (avio_rl32(pb) != MKTAG('f', 'm', 't', ' ') || avio_rl64(pb) != 52)
+ return AVERROR_INVALIDDATA;
+
+ if (avio_rl32(pb) != 1) {
+ avpriv_request_sample(s, "unknown format version");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (avio_rl32(pb)) {
+ avpriv_request_sample(s, "unknown format id");
+ return AVERROR_INVALIDDATA;
+ }
+
+ channel_type = avio_rl32(pb);
+ if (channel_type < FF_ARRAY_ELEMS(dsf_channel_layout))
+ st->codec->channel_layout = dsf_channel_layout[channel_type];
+ if (!st->codec->channel_layout)
+ avpriv_request_sample(s, "channel type %i", channel_type);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->channels = avio_rl32(pb);
+ st->codec->sample_rate = avio_rl32(pb) / 8;
+
+ switch(avio_rl32(pb)) {
+ case 1: st->codec->codec_id = AV_CODEC_ID_DSD_LSBF_PLANAR; break;
+ case 8: st->codec->codec_id = AV_CODEC_ID_DSD_MSBF_PLANAR; break;
+ default:
+ avpriv_request_sample(s, "unknown most significant bit");
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_skip(pb, 8);
+ st->codec->block_align = avio_rl32(pb);
+ if (st->codec->block_align > INT_MAX / st->codec->channels) {
+ avpriv_request_sample(s, "block_align overflow");
+ return AVERROR_INVALIDDATA;
+ }
+ st->codec->block_align *= st->codec->channels;
+ avio_skip(pb, 4);
+
+ /* data chunk */
+
+ dsf->data_end = avio_tell(pb);
+ if (avio_rl32(pb) != MKTAG('d', 'a', 't', 'a'))
+ return AVERROR_INVALIDDATA;
+ dsf->data_end += avio_rl64(pb);
+
+ return 0;
+}
+
+static int dsf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ DSFContext *dsf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[0];
+ int64_t pos = avio_tell(pb);
+
+ if (pos >= dsf->data_end)
+ return AVERROR_EOF;
+
+ pkt->stream_index = 0;
+ return av_get_packet(pb, pkt, FFMIN(dsf->data_end - pos, st->codec->block_align));
+}
+
+AVInputFormat ff_dsf_demuxer = {
+ .name = "dsf",
+ .long_name = NULL_IF_CONFIG_SMALL("DSD Stream File (DSF)"),
+ .priv_data_size = sizeof(DSFContext),
+ .read_probe = dsf_probe,
+ .read_header = dsf_read_header,
+ .read_packet = dsf_read_packet,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK,
+};
diff --git a/libavformat/dsicin.c b/libavformat/dsicin.c
index 6a7c8b948a..4b5a934ca1 100644
--- a/libavformat/dsicin.c
+++ b/libavformat/dsicin.c
@@ -2,20 +2,20 @@
* Delphine Software International CIN File Demuxer
* Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
+#include "avio_internal.h"
typedef struct CinFileHeader {
@@ -149,7 +150,7 @@ static int cin_read_frame_header(CinDemuxContext *cin, AVIOContext *pb) {
hdr->video_frame_size = avio_rl32(pb);
hdr->audio_frame_size = avio_rl32(pb);
- if (pb->eof_reached || pb->error)
+ if (avio_feof(pb) || pb->error)
return AVERROR(EIO);
if (avio_rl32(pb) != 0xAA55AA55)
@@ -183,6 +184,8 @@ static int cin_read_packet(AVFormatContext *s, AVPacket *pkt)
/* palette and video packet */
pkt_size = (palette_type + 3) * hdr->pal_colors_count + hdr->video_frame_size;
+ pkt_size = ffio_limit(pb, pkt_size);
+
ret = av_new_packet(pkt, 4 + pkt_size);
if (ret < 0)
return ret;
diff --git a/libavformat/dss.c b/libavformat/dss.c
index f7d0ead1c2..ead0ee00dc 100644
--- a/libavformat/dss.c
+++ b/libavformat/dss.c
@@ -2,20 +2,20 @@
* Digital Speech Standard (DSS) demuxer
* Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,6 +54,8 @@ typedef struct DSSDemuxContext {
int swap;
int dss_sp_swap_byte;
int8_t *dss_sp_buf;
+
+ int packet_size;
} DSSDemuxContext;
static int dss_probe(AVProbeData *p)
@@ -78,7 +80,8 @@ static int dss_read_metadata_date(AVFormatContext *s, unsigned int offset,
if (ret < DSS_TIME_SIZE)
return ret < 0 ? ret : AVERROR_EOF;
- sscanf(string, "%2d%2d%2d%2d%2d%2d", &y, &month, &d, &h, &minute, &sec);
+ if (sscanf(string, "%2d%2d%2d%2d%2d%2d", &y, &month, &d, &h, &minute, &sec) != 6)
+ return AVERROR_INVALIDDATA;
/* We deal with a two-digit year here, so set the default date to 2000
* and hope it will never be used in the next century. */
snprintf(datetime, sizeof(datetime), "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
@@ -142,7 +145,7 @@ static int dss_read_header(AVFormatContext *s)
if (ctx->audio_codec == DSS_ACODEC_DSS_SP) {
st->codec->codec_id = AV_CODEC_ID_DSS_SP;
- st->codec->sample_rate = 12000;
+ st->codec->sample_rate = 11025;
} else if (ctx->audio_codec == DSS_ACODEC_G723_1) {
st->codec->codec_id = AV_CODEC_ID_G723_1;
st->codec->sample_rate = 8000;
@@ -209,13 +212,13 @@ static void dss_sp_byte_swap(DSSDemuxContext *ctx,
static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt)
{
DSSDemuxContext *ctx = s->priv_data;
+ AVStream *st = s->streams[0];
int read_size, ret, offset = 0, buff_offset = 0;
+ int64_t pos = avio_tell(s->pb);
if (ctx->counter == 0)
dss_skip_audio_header(s, pkt);
- pkt->pos = avio_tell(s->pb);
-
if (ctx->swap) {
read_size = DSS_FRAME_SIZE - 2;
buff_offset = 3;
@@ -223,13 +226,16 @@ static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt)
read_size = DSS_FRAME_SIZE;
ctx->counter -= read_size;
+ ctx->packet_size = DSS_FRAME_SIZE - 1;
ret = av_new_packet(pkt, DSS_FRAME_SIZE);
if (ret < 0)
return ret;
- pkt->duration = 0;
+ pkt->duration = 264;
+ pkt->pos = pos;
pkt->stream_index = 0;
+ s->bit_rate = 8LL * ctx->packet_size * st->codec->sample_rate * 512 / (506 * pkt->duration);
if (ctx->counter < 0) {
int size2 = ctx->counter + read_size;
@@ -250,6 +256,11 @@ static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt)
dss_sp_byte_swap(ctx, pkt->data, ctx->dss_sp_buf);
+ if (ctx->dss_sp_swap_byte < 0) {
+ ret = AVERROR(EAGAIN);
+ goto error_eof;
+ }
+
if (pkt->data[0] == 0xff)
return AVERROR_INVALIDDATA;
@@ -263,12 +274,13 @@ error_eof:
static int dss_723_1_read_packet(AVFormatContext *s, AVPacket *pkt)
{
DSSDemuxContext *ctx = s->priv_data;
+ AVStream *st = s->streams[0];
int size, byte, ret, offset;
+ int64_t pos = avio_tell(s->pb);
if (ctx->counter == 0)
dss_skip_audio_header(s, pkt);
- pkt->pos = avio_tell(s->pb);
/* We make one byte-step here. Don't forget to add offset. */
byte = avio_r8(s->pb);
if (byte == 0xff)
@@ -276,15 +288,18 @@ static int dss_723_1_read_packet(AVFormatContext *s, AVPacket *pkt)
size = frame_size[byte & 3];
+ ctx->packet_size = size;
ctx->counter -= size;
ret = av_new_packet(pkt, size);
if (ret < 0)
return ret;
+ pkt->pos = pos;
pkt->data[0] = byte;
offset = 1;
pkt->duration = 240;
+ s->bit_rate = 8LL * size * st->codec->sample_rate * 512 / (506 * pkt->duration);
pkt->stream_index = 0;
@@ -325,11 +340,50 @@ static int dss_read_close(AVFormatContext *s)
{
DSSDemuxContext *ctx = s->priv_data;
- av_free(ctx->dss_sp_buf);
+ av_freep(&ctx->dss_sp_buf);
+
+ return 0;
+}
+
+static int dss_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
+{
+ DSSDemuxContext *ctx = s->priv_data;
+ int64_t ret, seekto;
+ uint8_t header[DSS_AUDIO_BLOCK_HEADER_SIZE];
+ int offset;
+
+ if (ctx->audio_codec == DSS_ACODEC_DSS_SP)
+ seekto = timestamp / 264 * 41 / 506 * 512;
+ else
+ seekto = timestamp / 240 * ctx->packet_size / 506 * 512;
+
+ if (seekto < 0)
+ seekto = 0;
+
+ seekto += DSS_HEADER_SIZE;
+
+ ret = avio_seek(s->pb, seekto, SEEK_SET);
+ if (ret < 0)
+ return ret;
+ avio_read(s->pb, header, DSS_AUDIO_BLOCK_HEADER_SIZE);
+ ctx->swap = !!(header[0] & 0x80);
+ offset = 2*header[1] + 2*ctx->swap;
+ if (offset < DSS_AUDIO_BLOCK_HEADER_SIZE)
+ return AVERROR_INVALIDDATA;
+ if (offset == DSS_AUDIO_BLOCK_HEADER_SIZE) {
+ ctx->counter = 0;
+ offset = avio_skip(s->pb, -DSS_AUDIO_BLOCK_HEADER_SIZE);
+ } else {
+ ctx->counter = DSS_BLOCK_SIZE - offset;
+ offset = avio_skip(s->pb, offset - DSS_AUDIO_BLOCK_HEADER_SIZE);
+ }
+ ctx->dss_sp_swap_byte = -1;
return 0;
}
+
AVInputFormat ff_dss_demuxer = {
.name = "dss",
.long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard (DSS)"),
@@ -338,5 +392,6 @@ AVInputFormat ff_dss_demuxer = {
.read_header = dss_read_header,
.read_packet = dss_read_packet,
.read_close = dss_read_close,
+ .read_seek = dss_read_seek,
.extensions = "dss"
};
diff --git a/libavformat/dtsdec.c b/libavformat/dtsdec.c
index 90e9d38582..da0fb61a60 100644
--- a/libavformat/dtsdec.c
+++ b/libavformat/dtsdec.c
@@ -2,25 +2,27 @@
* RAW DTS demuxer
* Copyright (c) 2008 Benjamin Larsson
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavcodec/bytestream.h"
+#include "libavcodec/dca.h"
#include "libavcodec/dca_syncwords.h"
+#include "libavcodec/get_bits.h"
#include "avformat.h"
#include "rawdec.h"
@@ -29,34 +31,88 @@ static int dts_probe(AVProbeData *p)
{
const uint8_t *buf, *bufp;
uint32_t state = -1;
- int markers[3] = {0};
- int sum, max;
+ int markers[4*16] = {0};
+ int sum, max, i;
+ int64_t diff = 0;
+ uint8_t hdr[12 + FF_INPUT_BUFFER_PADDING_SIZE] = { 0 };
- buf = p->buf;
+ buf = p->buf + FFMIN(4096, p->buf_size);
for(; buf < (p->buf+p->buf_size)-2; buf+=2) {
+ int marker, sample_blocks, sample_rate, sr_code, framesize;
+ int lfe;
+ GetBitContext gb;
+
bufp = buf;
state = (state << 16) | bytestream_get_be16(&bufp);
+ if (buf - p->buf >= 4)
+ diff += FFABS(((int16_t)AV_RL16(buf)) - (int16_t)AV_RL16(buf-4));
+
/* regular bitstream */
- if (state == DCA_SYNCWORD_CORE_BE || state == DCA_SYNCWORD_CORE_LE)
- markers[0]++;
+ if (state == DCA_SYNCWORD_CORE_BE &&
+ (bytestream_get_be16(&bufp) & 0xFC00) == 0xFC00)
+ marker = 0;
+ else if (state == DCA_SYNCWORD_CORE_LE &&
+ (bytestream_get_be16(&bufp) & 0x00FC) == 0x00FC)
+ marker = 1;
/* 14 bits big-endian bitstream */
- if (state == DCA_SYNCWORD_CORE_14B_BE)
- if ((bytestream_get_be16(&bufp) & 0xFFF0) == 0x07F0)
- markers[1]++;
+ else if (state == DCA_SYNCWORD_CORE_14B_BE &&
+ (bytestream_get_be16(&bufp) & 0xFFF0) == 0x07F0)
+ marker = 2;
/* 14 bits little-endian bitstream */
- if (state == DCA_SYNCWORD_CORE_14B_LE)
- if ((bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
- markers[2]++;
+ else if (state == DCA_SYNCWORD_CORE_14B_LE &&
+ (bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
+ marker = 3;
+ else
+ continue;
+
+ if (avpriv_dca_convert_bitstream(buf-2, 12, hdr, 12) < 0)
+ continue;
+
+ init_get_bits(&gb, hdr, 96);
+ skip_bits_long(&gb, 39);
+
+ sample_blocks = get_bits(&gb, 7) + 1;
+ if (sample_blocks < 8)
+ continue;
+
+ framesize = get_bits(&gb, 14) + 1;
+ if (framesize < 95)
+ continue;
+
+ skip_bits(&gb, 6);
+ sr_code = get_bits(&gb, 4);
+ sample_rate = avpriv_dca_sample_rates[sr_code];
+ if (sample_rate == 0)
+ continue;
+
+ get_bits(&gb, 5);
+ if (get_bits(&gb, 1))
+ continue;
+
+ skip_bits_long(&gb, 9);
+ lfe = get_bits(&gb, 2);
+ if (lfe > 2)
+ continue;
+
+ marker += 4* sr_code;
+
+ markers[marker] ++;
}
- sum = markers[0] + markers[1] + markers[2];
- max = markers[1] > markers[0];
- max = markers[2] > markers[max] ? 2 : max;
+
+ sum = max = 0;
+ for (i=0; i<FF_ARRAY_ELEMS(markers); i++) {
+ sum += markers[i];
+ if (markers[max] < markers[i])
+ max = i;
+ }
+
if (markers[max] > 3 && p->buf_size / markers[max] < 32*1024 &&
- markers[max] * 4 > sum * 3)
+ markers[max] * 4 > sum * 3 &&
+ diff / p->buf_size > 200)
return AVPROBE_SCORE_EXTENSION + 1;
return 0;
diff --git a/libavformat/dtshddec.c b/libavformat/dtshddec.c
new file mode 100644
index 0000000000..0fd0304703
--- /dev/null
+++ b/libavformat/dtshddec.c
@@ -0,0 +1,139 @@
+/*
+ * Raw DTS-HD demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/dict.h"
+#include "avformat.h"
+
+#define AUPR_HDR 0x415550522D484452
+#define AUPRINFO 0x41555052494E464F
+#define BITSHVTB 0x4249545348565442
+#define BLACKOUT 0x424C41434B4F5554
+#define BRANCHPT 0x4252414E43485054
+#define BUILDVER 0x4255494C44564552
+#define CORESSMD 0x434F524553534D44
+#define DTSHDHDR 0x4454534844484452
+#define EXTSS_MD 0x45585453535f4d44
+#define FILEINFO 0x46494C45494E464F
+#define NAVI_TBL 0x4E4156492D54424C
+#define STRMDATA 0x5354524D44415441
+#define TIMECODE 0x54494D45434F4445
+
+typedef struct DTSHDDemuxContext {
+ uint64_t data_end;
+} DTSHDDemuxContext;
+
+static int dtshd_probe(AVProbeData *p)
+{
+ if (AV_RB64(p->buf) == DTSHDHDR)
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int dtshd_read_header(AVFormatContext *s)
+{
+ DTSHDDemuxContext *dtshd = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint64_t chunk_type, chunk_size;
+ AVStream *st;
+ int ret;
+ char *value;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_DTS;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
+
+ while (!avio_feof(pb)) {
+ chunk_type = avio_rb64(pb);
+ chunk_size = avio_rb64(pb);
+
+ if (chunk_size < 4) {
+ av_log(s, AV_LOG_ERROR, "chunk size too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (chunk_size > ((uint64_t)1 << 61)) {
+ av_log(s, AV_LOG_ERROR, "chunk size too big\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ switch (chunk_type) {
+ case STRMDATA:
+ dtshd->data_end = chunk_size + avio_tell(pb);
+ if (dtshd->data_end <= chunk_size)
+ return AVERROR_INVALIDDATA;
+ return 0;
+ break;
+ case FILEINFO:
+ if (chunk_size > INT_MAX)
+ goto skip;
+ value = av_malloc(chunk_size);
+ if (!value)
+ goto skip;
+ avio_read(pb, value, chunk_size);
+ value[chunk_size - 1] = 0;
+ av_dict_set(&s->metadata, "fileinfo", value,
+ AV_DICT_DONT_STRDUP_VAL);
+ break;
+ default:
+skip:
+ ret = avio_skip(pb, chunk_size);
+ if (ret < 0)
+ return ret;
+ };
+ }
+
+ return AVERROR_EOF;
+}
+
+static int raw_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ DTSHDDemuxContext *dtshd = s->priv_data;
+ int64_t size, left;
+ int ret;
+
+ left = dtshd->data_end - avio_tell(s->pb);
+ size = FFMIN(left, 1024);
+ if (size <= 0)
+ return AVERROR_EOF;
+
+ ret = av_get_packet(s->pb, pkt, size);
+ if (ret < 0)
+ return ret;
+
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_dtshd_demuxer = {
+ .name = "dtshd",
+ .long_name = NULL_IF_CONFIG_SMALL("raw DTS-HD"),
+ .priv_data_size = sizeof(DTSHDDemuxContext),
+ .read_probe = dtshd_probe,
+ .read_header = dtshd_read_header,
+ .read_packet = raw_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+ .extensions = "dtshd",
+ .raw_codec_id = AV_CODEC_ID_DTS,
+};
diff --git a/libavformat/dump.c b/libavformat/dump.c
index 3248e563c8..6355b99f41 100644
--- a/libavformat/dump.c
+++ b/libavformat/dump.c
@@ -1,20 +1,21 @@
/*
- * Various pretty-printing functions for use within Libav
+ * Various pretty-printing functions for use within FFmpeg
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +27,8 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/avstring.h"
#include "libavutil/replaygain.h"
#include "libavutil/stereo3d.h"
@@ -76,7 +79,7 @@ void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size)
hex_dump_internal(avcl, NULL, level, buf, size);
}
-static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt,
+static void pkt_dump_internal(void *avcl, FILE *f, int level, const AVPacket *pkt,
int dump_payload, AVRational time_base)
{
HEXDUMP_PRINT("stream #%d:\n", pkt->stream_index);
@@ -100,13 +103,13 @@ static void pkt_dump_internal(void *avcl, FILE *f, int level, AVPacket *pkt,
av_hex_dump(f, pkt->data, pkt->size);
}
-void av_pkt_dump2(FILE *f, AVPacket *pkt, int dump_payload, AVStream *st)
+void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st)
{
pkt_dump_internal(NULL, f, 0, pkt, dump_payload, st->time_base);
}
-void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload,
- AVStream *st)
+void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload,
+ const AVStream *st)
{
pkt_dump_internal(avcl, NULL, level, pkt, dump_payload, st->time_base);
}
@@ -115,7 +118,9 @@ void av_pkt_dump_log2(void *avcl, int level, AVPacket *pkt, int dump_payload,
static void print_fps(double d, const char *postfix)
{
uint64_t v = lrintf(d * 100);
- if (v % 100)
+ if (!v)
+ av_log(NULL, AV_LOG_INFO, "%1.4f %s", d, postfix);
+ else if (v % 100)
av_log(NULL, AV_LOG_INFO, "%3.2f %s", d, postfix);
else if (v % (100 * 1000))
av_log(NULL, AV_LOG_INFO, "%1.0f %s", d, postfix);
@@ -130,9 +135,22 @@ static void dump_metadata(void *ctx, AVDictionary *m, const char *indent)
av_log(ctx, AV_LOG_INFO, "%sMetadata:\n", indent);
while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX)))
- if (strcmp("language", tag->key))
+ if (strcmp("language", tag->key)) {
+ const char *p = tag->value;
av_log(ctx, AV_LOG_INFO,
- "%s %-16s: %s\n", indent, tag->key, tag->value);
+ "%s %-16s: ", indent, tag->key);
+ while (*p) {
+ char tmp[256];
+ size_t len = strcspn(p, "\x8\xa\xb\xc\xd");
+ av_strlcpy(tmp, p, FFMIN(sizeof(tmp), len+1));
+ av_log(ctx, AV_LOG_INFO, "%s", tmp);
+ p += len;
+ if (*p == 0xd) av_log(ctx, AV_LOG_INFO, " ");
+ if (*p == 0xa) av_log(ctx, AV_LOG_INFO, "\n%s %-16s: ", indent, "");
+ if (*p) p++;
+ }
+ av_log(ctx, AV_LOG_INFO, "\n");
+ }
}
}
@@ -377,8 +395,15 @@ static void dump_stream_format(AVFormatContext *ic, int i,
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
AVStream *st = ic->streams[i];
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
+ char *separator = ic->dump_separator;
+ char **codec_separator = av_opt_ptr(st->codec->av_class, st->codec, "dump_separator");
+ int use_format_separator = !*codec_separator;
+ if (use_format_separator)
+ *codec_separator = av_strdup(separator);
avcodec_string(buf, sizeof(buf), st->codec, is_output);
+ if (use_format_separator)
+ av_freep(codec_separator);
av_log(NULL, AV_LOG_INFO, " Stream #%d:%d", index, i);
/* the pid is an important information, so we display it */
@@ -398,20 +423,24 @@ static void dump_stream_format(AVFormatContext *ic, int i,
st->codec->width * st->sample_aspect_ratio.num,
st->codec->height * st->sample_aspect_ratio.den,
1024 * 1024);
- av_log(NULL, AV_LOG_INFO, ", PAR %d:%d DAR %d:%d",
+ av_log(NULL, AV_LOG_INFO, ", SAR %d:%d DAR %d:%d",
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
display_aspect_ratio.num, display_aspect_ratio.den);
}
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
int fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
+ int tbr = st->r_frame_rate.den && st->r_frame_rate.num;
int tbn = st->time_base.den && st->time_base.num;
int tbc = st->codec->time_base.den && st->codec->time_base.num;
- if (fps || tbn || tbc)
- av_log(NULL, AV_LOG_INFO, "\n ");
+ if (fps || tbr || tbn || tbc)
+ av_log(NULL, AV_LOG_INFO, "%s", separator);
+
if (fps)
- print_fps(av_q2d(st->avg_frame_rate), tbn || tbc ? "fps, " : "fps");
+ print_fps(av_q2d(st->avg_frame_rate), tbr || tbn || tbc ? "fps, " : "fps");
+ if (tbr)
+ print_fps(av_q2d(st->r_frame_rate), tbn || tbc ? "tbr, " : "tbr");
if (tbn)
print_fps(1 / av_q2d(st->time_base), tbc ? "tbn, " : "tbn");
if (tbc)
@@ -464,8 +493,9 @@ void av_dump_format(AVFormatContext *ic, int index,
av_log(NULL, AV_LOG_INFO, " Duration: ");
if (ic->duration != AV_NOPTS_VALUE) {
int hours, mins, secs, us;
- secs = ic->duration / AV_TIME_BASE;
- us = ic->duration % AV_TIME_BASE;
+ int64_t duration = ic->duration + 5000;
+ secs = duration / AV_TIME_BASE;
+ us = duration % AV_TIME_BASE;
mins = secs / 60;
secs %= 60;
hours = mins / 60;
diff --git a/libavformat/dv.c b/libavformat/dv.c
index 1ba8698d20..8500228964 100644
--- a/libavformat/dv.c
+++ b/libavformat/dv.c
@@ -12,20 +12,20 @@
* Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
* Funded by BBC Research & Development
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <time.h>
@@ -36,7 +36,9 @@
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
+#include "libavutil/timecode.h"
#include "dv.h"
+#include "libavutil/avassert.h"
struct DVDemuxContext {
const AVDVProfile* sys; /* Current DV profile. E.g.: 525/60, 625/50 */
@@ -70,27 +72,33 @@ static inline uint16_t dv_audio_12to16(uint16_t sample)
return result;
}
-/*
- * This is the dumbest implementation of all -- it simply looks at
- * a fixed offset and if pack isn't there -- fails. We might want
- * to have a fallback mechanism for complete search of missing packs.
- */
-static const uint8_t *dv_extract_pack(uint8_t *frame, enum dv_pack_type t)
+static const uint8_t *dv_extract_pack(const uint8_t *frame, enum dv_pack_type t)
{
int offs;
+ int c;
- switch (t) {
- case dv_audio_source:
- offs = (80 * 6 + 80 * 16 * 3 + 3);
- break;
- case dv_audio_control:
- offs = (80 * 6 + 80 * 16 * 4 + 3);
- break;
- case dv_video_control:
- offs = (80 * 5 + 48 + 5);
- break;
- default:
- return NULL;
+ for (c = 0; c < 10; c++) {
+ switch (t) {
+ case dv_audio_source:
+ if (c&1) offs = (80 * 6 + 80 * 16 * 0 + 3 + c*12000);
+ else offs = (80 * 6 + 80 * 16 * 3 + 3 + c*12000);
+ break;
+ case dv_audio_control:
+ if (c&1) offs = (80 * 6 + 80 * 16 * 1 + 3 + c*12000);
+ else offs = (80 * 6 + 80 * 16 * 4 + 3 + c*12000);
+ break;
+ case dv_video_control:
+ if (c&1) offs = (80 * 3 + 8 + c*12000);
+ else offs = (80 * 5 + 48 + 5 + c*12000);
+ break;
+ case dv_timecode:
+ offs = (80*1 + 3 + 3);
+ break;
+ default:
+ return NULL;
+ }
+ if (frame[offs] == t)
+ break;
}
return frame[offs] == t ? &frame[offs] : NULL;
@@ -108,7 +116,7 @@ static const int dv_audio_frequency[3] = {
* 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
* are converted into 16bit linear ones.
*/
-static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm,
+static int dv_extract_audio(const uint8_t *frame, uint8_t **ppcm,
const AVDVProfile *sys)
{
int size, chan, i, j, d, of, smpls, freq, quant, half_ch;
@@ -137,9 +145,14 @@ static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm,
* channels 0,1 and odd 2,3. */
ipcm = (sys->height == 720 && !(frame[1] & 0x0C)) ? 2 : 0;
+ if (ipcm + sys->n_difchan > (quant == 1 ? 2 : 4)) {
+ av_log(NULL, AV_LOG_ERROR, "too many dv pcm frames\n");
+ return AVERROR_INVALIDDATA;
+ }
+
/* for each DIF channel */
for (chan = 0; chan < sys->n_difchan; chan++) {
- /* next stereo channel (50Mbps and 100Mbps only) */
+ av_assert0(ipcm<4);
pcm = ppcm[ipcm++];
if (!pcm)
break;
@@ -149,6 +162,7 @@ static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm,
frame += 6 * 80; /* skip DIF segment header */
if (quant == 1 && i == half_ch) {
/* next stereo channel (12bit mode only) */
+ av_assert0(ipcm<4);
pcm = ppcm[ipcm++];
if (!pcm)
break;
@@ -205,7 +219,7 @@ static int dv_extract_audio(uint8_t *frame, uint8_t **ppcm,
return size;
}
-static int dv_extract_audio_info(DVDemuxContext *c, uint8_t *frame)
+static int dv_extract_audio_info(DVDemuxContext *c, const uint8_t *frame)
{
const uint8_t *as_pack;
int freq, stype, smpls, quant, i, ach;
@@ -265,7 +279,7 @@ static int dv_extract_audio_info(DVDemuxContext *c, uint8_t *frame)
return (c->sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
}
-static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame)
+static int dv_extract_video_info(DVDemuxContext *c, const uint8_t *frame)
{
const uint8_t *vsc_pack;
AVCodecContext *avctx;
@@ -278,11 +292,6 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame)
avpriv_set_pts_info(c->vst, 64, c->sys->time_base.num,
c->sys->time_base.den);
c->vst->avg_frame_rate = av_inv_q(c->vst->time_base);
- if (!avctx->width) {
- avctx->width = c->sys->width;
- avctx->height = c->sys->height;
- }
- avctx->pix_fmt = c->sys->pix_fmt;
/* finding out SAR is a little bit messy */
vsc_pack = dv_extract_pack(frame, dv_video_control);
@@ -298,6 +307,22 @@ static int dv_extract_video_info(DVDemuxContext *c, uint8_t *frame)
return size;
}
+static int dv_extract_timecode(DVDemuxContext* c, const uint8_t* frame, char *tc)
+{
+ const uint8_t *tc_pack;
+
+ // For PAL systems, drop frame bit is replaced by an arbitrary
+ // bit so its value should not be considered. Drop frame timecode
+ // is only relevant for NTSC systems.
+ int prevent_df = c->sys->ltc_divisor == 25 || c->sys->ltc_divisor == 50;
+
+ tc_pack = dv_extract_pack(frame, dv_timecode);
+ if (!tc_pack)
+ return 0;
+ av_timecode_make_smpte_tc_string(tc, AV_RB32(tc_pack + 1), prevent_df);
+ return 1;
+}
+
/* The following 3 functions constitute our interface to the world */
DVDemuxContext *avpriv_dv_init_demux(AVFormatContext *s)
@@ -341,7 +366,7 @@ int avpriv_dv_get_packet(DVDemuxContext *c, AVPacket *pkt)
}
int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
- uint8_t *buf, int buf_size)
+ uint8_t *buf, int buf_size, int64_t pos)
{
int size, i;
uint8_t *ppcm[5] = { 0 };
@@ -356,6 +381,7 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
/* FIXME: in case of no audio/bad audio we have to do something */
size = dv_extract_audio_info(c, buf);
for (i = 0; i < c->ach; i++) {
+ c->audio_pkt[i].pos = pos;
c->audio_pkt[i].size = size;
c->audio_pkt[i].pts = c->abytes * 30000 * 8 /
c->ast[i]->codec->bit_rate;
@@ -381,6 +407,7 @@ int avpriv_dv_produce_packet(DVDemuxContext *c, AVPacket *pkt,
size = dv_extract_video_info(c, buf);
av_init_packet(pkt);
pkt->data = buf;
+ pkt->pos = pos;
pkt->size = size;
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->stream_index = c->vst->index;
@@ -395,8 +422,8 @@ static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c,
int64_t timestamp, int flags)
{
// FIXME: sys may be wrong if last dv_read_packet() failed (buffer is junk)
- const AVDVProfile *sys = av_dv_codec_profile(c->vst->codec->width, c->vst->codec->height,
- c->vst->codec->pix_fmt);
+ const AVDVProfile *sys = av_dv_codec_profile2(c->vst->codec->coded_width, c->vst->codec->coded_height,
+ c->vst->codec->pix_fmt, c->vst->codec->time_base);
int64_t offset;
int64_t size = avio_size(s->pb) - s->internal->data_offset;
int64_t max_offset = ((size - 1) / sys->frame_size) * sys->frame_size;
@@ -414,10 +441,13 @@ static int64_t dv_frame_offset(AVFormatContext *s, DVDemuxContext *c,
void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset)
{
c->frames = frame_offset;
- if (c->ach)
+ if (c->ach) {
+ if (c->sys) {
c->abytes = av_rescale_q(c->frames, c->sys->time_base,
(AVRational) { 8, c->ast[0]->codec->bit_rate });
-
+ } else
+ av_log(c->fctx, AV_LOG_ERROR, "cannot adjust audio bytes\n");
+ }
c->audio_pkt[0].size = c->audio_pkt[1].size = 0;
c->audio_pkt[2].size = c->audio_pkt[3].size = 0;
}
@@ -431,6 +461,41 @@ typedef struct RawDVContext {
uint8_t buf[DV_MAX_FRAME_SIZE];
} RawDVContext;
+static int dv_read_timecode(AVFormatContext *s) {
+ int ret;
+ char timecode[AV_TIMECODE_STR_SIZE];
+ int64_t pos = avio_tell(s->pb);
+
+ // Read 3 DIF blocks: Header block and 2 Subcode blocks.
+ int partial_frame_size = 3 * 80;
+ uint8_t *partial_frame = av_mallocz(sizeof(*partial_frame) *
+ partial_frame_size);
+
+ RawDVContext *c = s->priv_data;
+ if (!partial_frame)
+ return AVERROR(ENOMEM);
+
+ ret = avio_read(s->pb, partial_frame, partial_frame_size);
+ if (ret < 0)
+ goto finish;
+
+ if (ret < partial_frame_size) {
+ ret = -1;
+ goto finish;
+ }
+
+ ret = dv_extract_timecode(c->dv_demux, partial_frame, timecode);
+ if (ret)
+ av_dict_set(&s->metadata, "timecode", timecode, 0);
+ else
+ av_log(s, AV_LOG_ERROR, "Detected timecode is invalid\n");
+
+finish:
+ av_free(partial_frame);
+ avio_seek(s->pb, pos, SEEK_SET);
+ return ret;
+}
+
static int dv_read_header(AVFormatContext *s)
{
unsigned state, marker_pos = 0;
@@ -442,7 +507,7 @@ static int dv_read_header(AVFormatContext *s)
state = avio_rb32(s->pb);
while ((state & 0xffffff7f) != 0x1f07003f) {
- if (s->pb->eof_reached) {
+ if (avio_feof(s->pb)) {
av_log(s, AV_LOG_ERROR, "Cannot find DV header.\n");
return -1;
}
@@ -457,7 +522,7 @@ static int dv_read_header(AVFormatContext *s)
}
AV_WB32(c->buf, state);
- if (avio_read(s->pb, c->buf + 4, DV_PROFILE_BYTES - 4) <= 0 ||
+ if (avio_read(s->pb, c->buf + 4, DV_PROFILE_BYTES - 4) != DV_PROFILE_BYTES - 4 ||
avio_seek(s->pb, -DV_PROFILE_BYTES, SEEK_CUR) < 0)
return AVERROR(EIO);
@@ -474,6 +539,9 @@ static int dv_read_header(AVFormatContext *s)
(AVRational) { 8, 1 },
c->dv_demux->sys->time_base);
+ if (s->pb->seekable)
+ dv_read_timecode(s);
+
return 0;
}
@@ -485,13 +553,14 @@ static int dv_read_packet(AVFormatContext *s, AVPacket *pkt)
size = avpriv_dv_get_packet(c->dv_demux, pkt);
if (size < 0) {
+ int64_t pos = avio_tell(s->pb);
if (!c->dv_demux->sys)
return AVERROR(EIO);
size = c->dv_demux->sys->frame_size;
if (avio_read(s->pb, c->buf, size) <= 0)
return AVERROR(EIO);
- size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size);
+ size = avpriv_dv_produce_packet(c->dv_demux, pkt, c->buf, size, pos);
}
return size;
@@ -514,37 +583,43 @@ static int dv_read_seek(AVFormatContext *s, int stream_index,
static int dv_read_close(AVFormatContext *s)
{
RawDVContext *c = s->priv_data;
- av_free(c->dv_demux);
+ av_freep(&c->dv_demux);
return 0;
}
static int dv_probe(AVProbeData *p)
{
- unsigned state, marker_pos = 0;
+ unsigned marker_pos = 0;
int i;
int matches = 0;
+ int firstmatch = 0;
int secondary_matches = 0;
if (p->buf_size < 5)
return 0;
- state = AV_RB32(p->buf);
- for (i = 4; i < p->buf_size; i++) {
- if ((state & 0xffffff7f) == 0x1f07003f)
- matches++;
- // any section header, also with seq/chan num != 0,
- // should appear around every 12000 bytes, at least 10 per frame
- if ((state & 0xff07ff7f) == 0x1f07003f)
- secondary_matches++;
- if (state == 0x003f0700 || state == 0xff3f0700)
- marker_pos = i;
- if (state == 0xff3f0701 && i - marker_pos == 80)
- matches++;
- state = (state << 8) | p->buf[i];
+ for (i = 0; i < p->buf_size-4; i++) {
+ unsigned state = AV_RB32(p->buf+i);
+ if ((state & 0x0007f840) == 0x00070000) {
+ // any section header, also with seq/chan num != 0,
+ // should appear around every 12000 bytes, at least 10 per frame
+ if ((state & 0xff07ff7f) == 0x1f07003f) {
+ secondary_matches++;
+ if ((state & 0xffffff7f) == 0x1f07003f) {
+ matches++;
+ if (!i)
+ firstmatch = 1;
+ }
+ }
+ if (state == 0x003f0700 || state == 0xff3f0700)
+ marker_pos = i;
+ if (state == 0xff3f0701 && i - marker_pos == 80)
+ matches++;
+ }
}
if (matches && p->buf_size / matches < 1024 * 1024) {
- if (matches > 4 ||
+ if (matches > 4 || firstmatch ||
(secondary_matches >= 10 &&
p->buf_size / secondary_matches < 24000))
// not max to avoid dv in mov to match
diff --git a/libavformat/dv.h b/libavformat/dv.h
index e8b2d37904..160c6ab873 100644
--- a/libavformat/dv.h
+++ b/libavformat/dv.h
@@ -8,20 +8,20 @@
* Raw DV format
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,7 @@
typedef struct DVDemuxContext DVDemuxContext;
DVDemuxContext* avpriv_dv_init_demux(AVFormatContext* s);
int avpriv_dv_get_packet(DVDemuxContext*, AVPacket *);
-int avpriv_dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int);
+int avpriv_dv_produce_packet(DVDemuxContext*, AVPacket*, uint8_t*, int, int64_t);
void ff_dv_offset_reset(DVDemuxContext *c, int64_t frame_offset);
typedef struct DVMuxContext DVMuxContext;
diff --git a/libavformat/dvbsub.c b/libavformat/dvbsub.c
new file mode 100644
index 0000000000..3d2f704c49
--- /dev/null
+++ b/libavformat/dvbsub.c
@@ -0,0 +1,70 @@
+/*
+ * RAW dvbsub demuxer
+ * Copyright (c) 2015 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "rawdec.h"
+
+
+static int dvbsub_probe(AVProbeData *p)
+{
+ int i, j, k;
+ const uint8_t *end = p->buf + p->buf_size;
+ int type, len;
+ int max_score = 0;
+
+ for(i=0; i<p->buf_size; i++){
+ if (p->buf[i] == 0x0f) {
+ const uint8_t *ptr = p->buf + i;
+ uint8_t histogram[6] = {0};
+ int min = 255;
+ for(j=0; 6 < end - ptr; j++) {
+ if (*ptr != 0x0f)
+ break;
+ type = ptr[1];
+ //page_id = AV_RB16(ptr + 2);
+ len = AV_RB16(ptr + 4);
+ if (type == 0x80) {
+ ;
+ } else if (type >= 0x10 && type <= 0x14) {
+ histogram[type - 0x10] ++;
+ } else
+ break;
+ if (6 + len > end - ptr)
+ break;
+ ptr += 6 + len;
+ }
+ for (k=0; k < 4; k++) {
+ min = FFMIN(min, histogram[k]);
+ }
+ if (min && j > max_score)
+ max_score = j;
+ }
+ }
+
+ if (max_score > 5)
+ return AVPROBE_SCORE_EXTENSION;
+
+ return 0;
+}
+
+FF_DEF_RAWSUB_DEMUXER(dvbsub, "raw dvbsub", dvbsub_probe, NULL, AV_CODEC_ID_DVB_SUBTITLE, AVFMT_GENERIC_INDEX)
diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c
index a33973f192..e99ac3ce7e 100644
--- a/libavformat/dvenc.c
+++ b/libavformat/dvenc.c
@@ -11,20 +11,20 @@
* 50 Mbps (DVCPRO50) support
* Copyright (c) 2006 Daniel Maas <dmaas@maasdigital.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <time.h>
@@ -37,10 +37,14 @@
#include "dv.h"
#include "libavutil/fifo.h"
#include "libavutil/mathematics.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
struct DVMuxContext {
+ AVClass *av_class;
const AVDVProfile* sys; /* current DV profile, e.g.: 525/60, 625/50 */
int n_ast; /* number of stereo audio streams (up to 2) */
AVStream *ast[2]; /* stereo audio streams */
@@ -50,6 +54,7 @@ struct DVMuxContext {
int has_audio; /* frame under construction has audio */
int has_video; /* frame under construction has video */
uint8_t frame_buf[DV_MAX_FRAME_SIZE]; /* frame under construction */
+ AVTimecode tc; /* timecode context */
};
static const int dv_aaux_packs_dist[12][9] = {
@@ -67,8 +72,16 @@ static const int dv_aaux_packs_dist[12][9] = {
{ 0x50, 0x51, 0x52, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff },
};
-static int dv_audio_frame_size(const AVDVProfile* sys, int frame)
+static int dv_audio_frame_size(const AVDVProfile* sys, int frame, int sample_rate)
{
+ if ((sys->time_base.den == 25 || sys->time_base.den == 50) && sys->time_base.num == 1) {
+ if (sample_rate == 32000) return 1280;
+ else if (sample_rate == 44100) return 1764;
+ else return 1920;
+ }
+
+ av_assert0(sample_rate == 48000);
+
return sys->audio_samples_dist[frame % (sizeof(sys->audio_samples_dist) /
sizeof(sys->audio_samples_dist[0]))];
}
@@ -77,41 +90,29 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu
{
struct tm tc;
time_t ct;
- int ltc_frame;
+ uint32_t timecode;
va_list ap;
+ int audio_type = 0;
+ int channel;
buf[0] = (uint8_t)pack_id;
switch (pack_id) {
case dv_timecode:
- ct = (time_t)av_rescale_rnd(c->frames, c->sys->time_base.num,
- c->sys->time_base.den, AV_ROUND_DOWN);
- ff_brktimegm(ct, &tc);
- /*
- * LTC drop-frame frame counter drops two frames (0 and 1) every
- * minute, unless it is exactly divisible by 10
- */
- ltc_frame = (c->frames + 2 * ct / 60 - 2 * ct / 600) % c->sys->ltc_divisor;
- buf[1] = (0 << 7) | /* color frame: 0 - unsync; 1 - sync mode */
- (1 << 6) | /* drop frame timecode: 0 - nondrop; 1 - drop */
- ((ltc_frame / 10) << 4) | /* tens of frames */
- (ltc_frame % 10); /* units of frames */
- buf[2] = (1 << 7) | /* biphase mark polarity correction: 0 - even; 1 - odd */
- ((tc.tm_sec / 10) << 4) | /* tens of seconds */
- (tc.tm_sec % 10); /* units of seconds */
- buf[3] = (1 << 7) | /* binary group flag BGF0 */
- ((tc.tm_min / 10) << 4) | /* tens of minutes */
- (tc.tm_min % 10); /* units of minutes */
- buf[4] = (1 << 7) | /* binary group flag BGF2 */
- (1 << 6) | /* binary group flag BGF1 */
- ((tc.tm_hour / 10) << 4) | /* tens of hours */
- (tc.tm_hour % 10); /* units of hours */
+ timecode = av_timecode_get_smpte_from_framenum(&c->tc, c->frames);
+ timecode |= 1<<23 | 1<<15 | 1<<7 | 1<<6; // biphase and binary group flags
+ AV_WB32(buf + 1, timecode);
break;
case dv_audio_source: /* AAUX source pack */
va_start(ap, buf);
+ channel = va_arg(ap, int);
+ if (c->ast[channel]->codec->sample_rate == 44100) {
+ audio_type = 1;
+ } else if (c->ast[channel]->codec->sample_rate == 32000)
+ audio_type = 2;
buf[1] = (1 << 7) | /* locked mode -- SMPTE only supports locked mode */
(1 << 6) | /* reserved -- always 1 */
- (dv_audio_frame_size(c->sys, c->frames) -
- c->sys->audio_min_samples[0]);
+ (dv_audio_frame_size(c->sys, c->frames, c->ast[channel]->codec->sample_rate) -
+ c->sys->audio_min_samples[audio_type]);
/* # of samples */
buf[2] = (0 << 7) | /* multi-stereo */
(0 << 5) | /* #of audio channels per block: 0 -- 1 channel */
@@ -123,8 +124,9 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu
(c->sys->n_difchan & 2); /* definition: 0 -- 25Mbps, 2 -- 50Mbps */
buf[4] = (1 << 7) | /* emphasis: 1 -- off */
(0 << 6) | /* emphasis time constant: 0 -- reserved */
- (0 << 3) | /* frequency: 0 -- 48kHz, 1 -- 44,1kHz, 2 -- 32kHz */
+ (audio_type << 3) | /* frequency: 0 -- 48kHz, 1 -- 44,1kHz, 2 -- 32kHz */
0; /* quantization: 0 -- 16bit linear, 1 -- 12bit nonlinear */
+
va_end(ap);
break;
case dv_audio_control:
@@ -184,12 +186,12 @@ static int dv_write_pack(enum dv_pack_type pack_id, DVMuxContext *c, uint8_t* bu
static void dv_inject_audio(DVMuxContext *c, int channel, uint8_t* frame_ptr)
{
int i, j, d, of, size;
- size = 4 * dv_audio_frame_size(c->sys, c->frames);
+ size = 4 * dv_audio_frame_size(c->sys, c->frames, c->ast[channel]->codec->sample_rate);
frame_ptr += channel * c->sys->difseg_size * 150 * 80;
for (i = 0; i < c->sys->difseg_size; i++) {
frame_ptr += 6 * 80; /* skip DIF segment header */
for (j = 0; j < 9; j++) {
- dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], i >= c->sys->difseg_size/2);
+ dv_write_pack(dv_aaux_packs_dist[i][j], c, &frame_ptr[3], channel, i >= c->sys->difseg_size/2);
for (d = 8; d < 80; d+=2) {
of = c->sys->audio_shuffle[i][j] + (d - 8)/2 * c->sys->audio_stride;
if (of*2 >= size)
@@ -242,7 +244,6 @@ static int dv_assemble_frame(DVMuxContext *c, AVStream* st,
int i, reqasize;
*frame = &c->frame_buf[0];
- reqasize = 4 * dv_audio_frame_size(c->sys, c->frames);
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
@@ -261,6 +262,8 @@ static int dv_assemble_frame(DVMuxContext *c, AVStream* st,
av_log(st->codec, AV_LOG_ERROR, "Can't process DV frame #%d. Insufficient video data or severe sync problem.\n", c->frames);
av_fifo_generic_write(c->audio_data[i], data, data_size, NULL);
+ reqasize = 4 * dv_audio_frame_size(c->sys, c->frames, st->codec->sample_rate);
+
/* Let us see if we've got enough audio for one DV frame. */
c->has_audio |= ((reqasize <= av_fifo_size(c->audio_data[i])) << i);
@@ -275,6 +278,7 @@ static int dv_assemble_frame(DVMuxContext *c, AVStream* st,
c->has_audio = 0;
for (i=0; i < c->n_ast; i++) {
dv_inject_audio(c, i, *frame);
+ reqasize = 4 * dv_audio_frame_size(c->sys, c->frames, c->ast[i]->codec->sample_rate);
av_fifo_drain(c->audio_data[i], reqasize);
c->has_audio |= ((reqasize <= av_fifo_size(c->audio_data[i])) << i);
}
@@ -323,15 +327,28 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s)
if (!vst || vst->codec->codec_id != AV_CODEC_ID_DVVIDEO)
goto bail_out;
for (i=0; i<c->n_ast; i++) {
- if (c->ast[i] && (c->ast[i]->codec->codec_id != AV_CODEC_ID_PCM_S16LE ||
- c->ast[i]->codec->sample_rate != 48000 ||
- c->ast[i]->codec->channels != 2))
- goto bail_out;
+ if (c->ast[i]) {
+ if(c->ast[i]->codec->codec_id != AV_CODEC_ID_PCM_S16LE ||
+ c->ast[i]->codec->channels != 2)
+ goto bail_out;
+ if (c->ast[i]->codec->sample_rate != 48000 &&
+ c->ast[i]->codec->sample_rate != 44100 &&
+ c->ast[i]->codec->sample_rate != 32000 )
+ goto bail_out;
+ }
}
- c->sys = av_dv_codec_profile(vst->codec->width, vst->codec->height, vst->codec->pix_fmt);
+ c->sys = av_dv_codec_profile2(vst->codec->width, vst->codec->height,
+ vst->codec->pix_fmt, vst->codec->time_base);
if (!c->sys)
goto bail_out;
+ if ((c->sys->time_base.den != 25 && c->sys->time_base.den != 50) || c->sys->time_base.num != 1) {
+ if (c->ast[0] && c->ast[0]->codec->sample_rate != 48000)
+ goto bail_out;
+ if (c->ast[1] && c->ast[1]->codec->sample_rate != 48000)
+ goto bail_out;
+ }
+
if ((c->n_ast > 1) && (c->sys->n_difchan < 2)) {
/* only 1 stereo pair is allowed in 25Mbps mode */
goto bail_out;
@@ -345,10 +362,10 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s)
c->start_time = ff_iso8601_to_unix_time(t->value);
for (i=0; i < c->n_ast; i++) {
- if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc(100*MAX_AUDIO_FRAME_SIZE))) {
+ if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc_array(100, MAX_AUDIO_FRAME_SIZE))) {
while (i > 0) {
i--;
- av_fifo_free(c->audio_data[i]);
+ av_fifo_freep(&c->audio_data[i]);
}
goto bail_out;
}
@@ -364,19 +381,35 @@ static void dv_delete_mux(DVMuxContext *c)
{
int i;
for (i=0; i < c->n_ast; i++)
- av_fifo_free(c->audio_data[i]);
+ av_fifo_freep(&c->audio_data[i]);
}
static int dv_write_header(AVFormatContext *s)
{
+ AVRational rate;
+ DVMuxContext *dvc = s->priv_data;
+ AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+
if (!dv_init_mux(s)) {
av_log(s, AV_LOG_ERROR, "Can't initialize DV format!\n"
"Make sure that you supply exactly two streams:\n"
- " video: 25fps or 29.97fps, audio: 2ch/48kHz/PCM\n"
+ " video: 25fps or 29.97fps, audio: 2ch/48|44|32kHz/PCM\n"
" (50Mbps allows an optional second audio stream)\n");
return -1;
}
- return 0;
+ rate.num = dvc->sys->ltc_divisor;
+ rate.den = 1;
+ if (!tcr) { // no global timecode, look into the streams
+ int i;
+ for (i = 0; i < s->nb_streams; i++) {
+ tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
+ if (tcr)
+ break;
+ }
+ }
+ if (tcr && av_timecode_init_from_string(&dvc->tc, rate, tcr->value, s) >= 0)
+ return 0;
+ return av_timecode_init(&dvc->tc, rate, 0, 0, s);
}
static int dv_write_packet(struct AVFormatContext *s, AVPacket *pkt)
diff --git a/libavformat/dxa.c b/libavformat/dxa.c
index 4a4d7c2cb0..44033563f8 100644
--- a/libavformat/dxa.c
+++ b/libavformat/dxa.c
@@ -2,20 +2,20 @@
* DXA demuxer
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -67,12 +67,12 @@ static int dxa_read_header(AVFormatContext *s)
tag = avio_rl32(pb);
if (tag != MKTAG('D', 'E', 'X', 'A'))
- return -1;
+ return AVERROR_INVALIDDATA;
flags = avio_r8(pb);
c->frames = avio_rb16(pb);
if(!c->frames){
av_log(s, AV_LOG_ERROR, "File contains no frames ???\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
fps = avio_rb32(pb);
@@ -92,7 +92,7 @@ static int dxa_read_header(AVFormatContext *s)
st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
// Parse WAV data header
if(avio_rl32(pb) == MKTAG('W', 'A', 'V', 'E')){
@@ -105,14 +105,14 @@ static int dxa_read_header(AVFormatContext *s)
ast = avformat_new_stream(s, NULL);
if (!ast)
- return -1;
- ret = ff_get_wav_header(pb, ast->codec, fsize);
+ return AVERROR(ENOMEM);
+ ret = ff_get_wav_header(pb, ast->codec, fsize, 0);
if (ret < 0)
return ret;
if (ast->codec->sample_rate > 0)
avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
// find 'data' chunk
- while(avio_tell(pb) < c->vidpos && !pb->eof_reached){
+ while(avio_tell(pb) < c->vidpos && !avio_feof(pb)){
tag = avio_rl32(pb);
fsize = avio_rl32(pb);
if(tag == MKTAG('d', 'a', 't', 'a')) break;
@@ -170,8 +170,11 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
avio_seek(s->pb, c->vidpos, SEEK_SET);
- while(!s->pb->eof_reached && c->frames){
- avio_read(s->pb, buf, 4);
+ while(!avio_feof(s->pb) && c->frames){
+ if ((ret = avio_read(s->pb, buf, 4)) != 4) {
+ av_log(s, AV_LOG_ERROR, "failed reading chunk type\n");
+ return ret < 0 ? ret : AVERROR_INVALIDDATA;
+ }
switch(AV_RL32(buf)){
case MKTAG('N', 'U', 'L', 'L'):
if(av_new_packet(pkt, 4 + pal_size) < 0)
@@ -189,12 +192,15 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
avio_read(s->pb, pal + 4, 768);
break;
case MKTAG('F', 'R', 'A', 'M'):
- avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4);
+ if ((ret = avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4)) != DXA_EXTRA_SIZE - 4) {
+ av_log(s, AV_LOG_ERROR, "failed reading dxa_extra\n");
+ return ret < 0 ? ret : AVERROR_INVALIDDATA;
+ }
size = AV_RB32(buf + 5);
if(size > 0xFFFFFF){
av_log(s, AV_LOG_ERROR, "Frame size is too big: %"PRIu32"\n",
size);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if(av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size) < 0)
return AVERROR(ENOMEM);
@@ -212,10 +218,10 @@ static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
default:
av_log(s, AV_LOG_ERROR, "Unknown tag %c%c%c%c\n", buf[0], buf[1], buf[2], buf[3]);
- return -1;
+ return AVERROR_INVALIDDATA;
}
}
- return AVERROR(EIO);
+ return AVERROR_EOF;
}
AVInputFormat ff_dxa_demuxer = {
diff --git a/libavformat/eacdata.c b/libavformat/eacdata.c
index c81dec847d..165ff1af99 100644
--- a/libavformat/eacdata.c
+++ b/libavformat/eacdata.c
@@ -2,20 +2,20 @@
* Electronic Arts .cdata file Demuxer
* Copyright (c) 2007 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,7 +40,7 @@ static int cdata_probe(AVProbeData *p)
{
const uint8_t *b = p->buf;
- if (b[0] == 0x04 && (b[1] == 0x00 || b[1] == 0x04 || b[1] == 0x0C))
+ if (b[0] == 0x04 && (b[1] == 0x00 || b[1] == 0x04 || b[1] == 0x0C || b[1] == 0x14))
return AVPROBE_SCORE_MAX/8;
return 0;
}
@@ -51,19 +51,21 @@ static int cdata_read_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
unsigned int sample_rate, header;
AVStream *st;
+ int64_t channel_layout = 0;
header = avio_rb16(pb);
switch (header) {
case 0x0400: cdata->channels = 1; break;
case 0x0404: cdata->channels = 2; break;
- case 0x040C: cdata->channels = 4; break;
+ case 0x040C: cdata->channels = 4; channel_layout = AV_CH_LAYOUT_QUAD; break;
+ case 0x0414: cdata->channels = 6; channel_layout = AV_CH_LAYOUT_5POINT1_BACK; break;
default:
av_log(s, AV_LOG_INFO, "unknown header 0x%04x\n", header);
return -1;
};
sample_rate = avio_rb16(pb);
- avio_skip(pb, 12);
+ avio_skip(pb, (avio_r8(pb) & 0x20) ? 15 : 11);
st = avformat_new_stream(s, NULL);
if (!st)
@@ -72,6 +74,7 @@ static int cdata_read_header(AVFormatContext *s)
st->codec->codec_tag = 0; /* no fourcc */
st->codec->codec_id = AV_CODEC_ID_ADPCM_EA_XAS;
st->codec->channels = cdata->channels;
+ st->codec->channel_layout = channel_layout;
st->codec->sample_rate = sample_rate;
avpriv_set_pts_info(st, 64, 1, sample_rate);
diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c
index 7c1fabee0f..d6a396b1ef 100644
--- a/libavformat/electronicarts.c
+++ b/libavformat/electronicarts.c
@@ -1,21 +1,21 @@
/* Electronic Arts Multimedia File Demuxer
- * Copyright (c) 2004 The ffmpeg Project
+ * Copyright (c) 2004 The FFmpeg Project
* Copyright (c) 2006-2008 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -68,6 +68,7 @@ typedef struct EaDemuxContext {
enum AVCodecID video_codec;
AVRational time_base;
int width, height;
+ int nb_frames;
int video_stream_index;
enum AVCodecID audio_codec;
@@ -108,7 +109,7 @@ static int process_audio_header_elements(AVFormatContext *s)
ea->sample_rate = -1;
ea->num_channels = 1;
- while (!pb->eof_reached && in_header) {
+ while (!avio_feof(pb) && in_header) {
int in_subheader;
uint8_t byte;
byte = avio_r8(pb);
@@ -117,7 +118,7 @@ static int process_audio_header_elements(AVFormatContext *s)
case 0xFD:
av_log(s, AV_LOG_DEBUG, "entered audio subheader\n");
in_subheader = 1;
- while (!pb->eof_reached && in_subheader) {
+ while (!avio_feof(pb) && in_subheader) {
uint8_t subbyte;
subbyte = avio_r8(pb);
@@ -211,8 +212,7 @@ static int process_audio_header_elements(AVFormatContext *s)
case -1:
break;
default:
- av_log(s, AV_LOG_ERROR,
- "unsupported stream type; revision=%i\n", revision);
+ avpriv_request_sample(s, "stream type; revision=%i", revision);
return 0;
}
switch (revision2) {
@@ -220,7 +220,14 @@ static int process_audio_header_elements(AVFormatContext *s)
ea->audio_codec = AV_CODEC_ID_PCM_S16LE_PLANAR;
break;
case 10:
- ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2;
+ switch (revision) {
+ case -1:
+ case 2: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R1; break;
+ case 3: ea->audio_codec = AV_CODEC_ID_ADPCM_EA_R2; break;
+ default:
+ avpriv_request_sample(s, "stream type; revision=%i, revision2=%i", revision, revision2);
+ return 0;
+ }
break;
case 16:
ea->audio_codec = AV_CODEC_ID_MP3;
@@ -229,15 +236,14 @@ static int process_audio_header_elements(AVFormatContext *s)
break;
default:
ea->audio_codec = AV_CODEC_ID_NONE;
- av_log(s, AV_LOG_ERROR,
- "unsupported stream type; revision2=%i\n", revision2);
+ avpriv_request_sample(s, "stream type; revision2=%i", revision2);
return 0;
}
break;
default:
- av_log(s, AV_LOG_ERROR,
- "unsupported stream type; compression_type=%i\n",
- compression_type);
+ avpriv_request_sample(s,
+ "stream type; compression_type=%i",
+ compression_type);
return 0;
}
@@ -278,9 +284,9 @@ static void process_audio_header_eacs(AVFormatContext *s)
ea->audio_codec = AV_CODEC_ID_ADPCM_IMA_EA_EACS;
break;
default:
- av_log(s, AV_LOG_ERROR,
- "unsupported stream type; audio compression_type=%i\n",
- compression_type);
+ avpriv_request_sample(s,
+ "stream type; audio compression_type=%i",
+ compression_type);
}
}
@@ -306,15 +312,23 @@ static void process_video_header_mdec(AVFormatContext *s)
ea->video_codec = AV_CODEC_ID_MDEC;
}
-static void process_video_header_vp6(AVFormatContext *s)
+static int process_video_header_vp6(AVFormatContext *s)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
- avio_skip(pb, 16);
+ avio_skip(pb, 8);
+ ea->nb_frames = avio_rl32(pb);
+ avio_skip(pb, 4);
ea->time_base.den = avio_rl32(pb);
ea->time_base.num = avio_rl32(pb);
+ if (ea->time_base.den <= 0 || ea->time_base.num <= 0) {
+ av_log(s, AV_LOG_ERROR, "Timebase is invalid\n");
+ return AVERROR_INVALIDDATA;
+ }
ea->video_codec = AV_CODEC_ID_VP6;
+
+ return 1;
}
static void process_video_header_cmv(AVFormatContext *s)
@@ -339,20 +353,25 @@ static int process_ea_header(AVFormatContext *s)
int i;
for (i = 0; i < 5 && (!ea->audio_codec || !ea->video_codec); i++) {
- unsigned int startpos = avio_tell(pb);
+ uint64_t startpos = avio_tell(pb);
int err = 0;
blockid = avio_rl32(pb);
size = avio_rl32(pb);
if (i == 0)
- ea->big_endian = size > 0x000FFFFF;
+ ea->big_endian = size > av_bswap32(size);
if (ea->big_endian)
size = av_bswap32(size);
+ if (size < 8) {
+ av_log(s, AV_LOG_ERROR, "chunk size too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
switch (blockid) {
case ISNh_TAG:
if (avio_rl32(pb) != EACS_TAG) {
- av_log(s, AV_LOG_ERROR, "unknown 1SNh headerid\n");
+ avpriv_request_sample(s, "unknown 1SNh headerid");
return 0;
}
process_audio_header_eacs(s);
@@ -364,7 +383,7 @@ static int process_ea_header(AVFormatContext *s)
if (blockid == GSTR_TAG) {
avio_skip(pb, 4);
} else if ((blockid & 0xFFFF) != PT00_TAG) {
- av_log(s, AV_LOG_ERROR, "unknown SCHl headerid\n");
+ avpriv_request_sample(s, "unknown SCHl headerid");
return 0;
}
err = process_audio_header_elements(s);
@@ -380,7 +399,6 @@ static int process_ea_header(AVFormatContext *s)
case kVGT_TAG:
ea->video_codec = AV_CODEC_ID_TGV;
- ea->time_base = (AVRational) { 1, 15 };
break;
case mTCD_TAG:
@@ -409,7 +427,7 @@ static int process_ea_header(AVFormatContext *s)
break;
case MVhd_TAG:
- process_video_header_vp6(s);
+ err = process_video_header_vp6(s);
break;
}
@@ -428,6 +446,8 @@ static int process_ea_header(AVFormatContext *s)
static int ea_probe(AVProbeData *p)
{
+ unsigned big_endian, size;
+
switch (AV_RL32(&p->buf[0])) {
case ISNh_TAG:
case SCHl_TAG:
@@ -442,7 +462,11 @@ static int ea_probe(AVProbeData *p)
default:
return 0;
}
- if (AV_RL32(&p->buf[4]) > 0xfffff && AV_RB32(&p->buf[4]) > 0xfffff)
+ size = AV_RL32(&p->buf[4]);
+ big_endian = size > 0x000FFFFF;
+ if (big_endian)
+ size = av_bswap32(size);
+ if (size > 0xfffff || size < 8)
return 0;
return AVPROBE_SCORE_MAX;
@@ -453,7 +477,7 @@ static int ea_read_header(AVFormatContext *s)
EaDemuxContext *ea = s->priv_data;
AVStream *st;
- if (!process_ea_header(s))
+ if (process_ea_header(s)<=0)
return AVERROR(EIO);
if (ea->video_codec) {
@@ -464,12 +488,17 @@ static int ea_read_header(AVFormatContext *s)
ea->video_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = ea->video_codec;
+ // parsing is necessary to make FFmpeg generate correct timestamps
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
st->codec->codec_tag = 0; /* no fourcc */
st->codec->width = ea->width;
st->codec->height = ea->height;
- avpriv_set_pts_info(st, 33, ea->time_base.num, ea->time_base.den);
- st->avg_frame_rate = (AVRational) { ea->time_base.den,
- ea->time_base.num };
+ st->duration = st->nb_frames = ea->nb_frames;
+ if (ea->time_base.num)
+ avpriv_set_pts_info(st, 64, ea->time_base.num, ea->time_base.den);
+ st->r_frame_rate =
+ st->avg_frame_rate = av_inv_q(ea->time_base);
}
if (ea->audio_codec) {
@@ -519,11 +548,12 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt)
{
EaDemuxContext *ea = s->priv_data;
AVIOContext *pb = s->pb;
+ int partial_packet = 0;
unsigned int chunk_type, chunk_size;
int ret = 0, packet_read = 0, key = 0;
int av_uninit(num_samples);
- while (!packet_read) {
+ while (!packet_read || partial_packet) {
chunk_type = avio_rl32(pb);
chunk_size = ea->big_endian ? avio_rb32(pb) : avio_rl32(pb);
if (chunk_size < 8)
@@ -551,6 +581,13 @@ static int ea_read_packet(AVFormatContext *s, AVPacket *pkt)
avio_skip(pb, 8);
chunk_size -= 12;
}
+
+ if (partial_packet) {
+ avpriv_request_sample(s, "video header followed by audio packet");
+ av_free_packet(pkt);
+ partial_packet = 0;
+ }
+
if (!chunk_size)
continue;
@@ -630,9 +667,15 @@ get_video_packet:
if (!chunk_size)
continue;
- ret = av_get_packet(pb, pkt, chunk_size);
- if (ret < 0)
- return ret;
+ if (partial_packet) {
+ ret = av_append_packet(pb, pkt, chunk_size);
+ } else
+ ret = av_get_packet(pb, pkt, chunk_size);
+ if (ret < 0) {
+ packet_read = 1;
+ break;
+ }
+ partial_packet = chunk_type == MVIh_TAG;
pkt->stream_index = ea->video_stream_index;
pkt->flags |= key;
packet_read = 1;
@@ -644,6 +687,8 @@ get_video_packet:
}
}
+ if (ret < 0 && partial_packet)
+ av_free_packet(pkt);
return ret;
}
diff --git a/libavformat/epafdec.c b/libavformat/epafdec.c
new file mode 100644
index 0000000000..c737892325
--- /dev/null
+++ b/libavformat/epafdec.c
@@ -0,0 +1,104 @@
+/*
+ * Ensoniq Paris Audio File demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+
+static int epaf_probe(AVProbeData *p)
+{
+ if (((AV_RL32(p->buf) == MKTAG('f','a','p',' ') &&
+ AV_RL32(p->buf + 8) == 1) ||
+ (AV_RL32(p->buf) == MKTAG(' ','p','a','f') &&
+ AV_RN32(p->buf + 8) == 0)) &&
+ !AV_RN32(p->buf + 4) && AV_RN32(p->buf + 12) &&
+ AV_RN32(p->buf + 20))
+ return AVPROBE_SCORE_MAX / 4 * 3;
+ return 0;
+}
+
+static int epaf_read_header(AVFormatContext *s)
+{
+ int le, sample_rate, codec, channels;
+ AVStream *st;
+
+ avio_skip(s->pb, 4);
+ if (avio_rl32(s->pb))
+ return AVERROR_INVALIDDATA;
+
+ le = avio_rl32(s->pb);
+ if (le && le != 1)
+ return AVERROR_INVALIDDATA;
+
+ if (le) {
+ sample_rate = avio_rl32(s->pb);
+ codec = avio_rl32(s->pb);
+ channels = avio_rl32(s->pb);
+ } else {
+ sample_rate = avio_rb32(s->pb);
+ codec = avio_rb32(s->pb);
+ channels = avio_rb32(s->pb);
+ }
+
+ if (!channels || !sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->channels = channels;
+ st->codec->sample_rate = sample_rate;
+ switch (codec) {
+ case 0:
+ st->codec->codec_id = le ? AV_CODEC_ID_PCM_S16LE : AV_CODEC_ID_PCM_S16BE;
+ break;
+ case 2:
+ st->codec->codec_id = AV_CODEC_ID_PCM_S8;
+ break;
+ case 1:
+ avpriv_request_sample(s, "24-bit Paris PCM format");
+ default:
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
+ st->codec->block_align = st->codec->bits_per_coded_sample * st->codec->channels / 8;
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ if (avio_skip(s->pb, 2024) < 0)
+ return AVERROR_INVALIDDATA;
+ return 0;
+}
+
+AVInputFormat ff_epaf_demuxer = {
+ .name = "epaf",
+ .long_name = NULL_IF_CONFIG_SMALL("Ensoniq Paris Audio File"),
+ .read_probe = epaf_probe,
+ .read_header = epaf_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "paf,fap",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/ffm.h b/libavformat/ffm.h
new file mode 100644
index 0000000000..b392b8d8d8
--- /dev/null
+++ b/libavformat/ffm.h
@@ -0,0 +1,60 @@
+/*
+ * FFM (ffserver live feed) common header
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_FFM_H
+#define AVFORMAT_FFM_H
+
+#include <stdint.h>
+#include "avformat.h"
+#include "avio.h"
+
+/* The FFM file is made of blocks of fixed size */
+#define FFM_HEADER_SIZE 14
+#define FFM_PACKET_SIZE 4096
+#define PACKET_ID 0x666d
+
+/* each packet contains frames (which can span several packets */
+#define FRAME_HEADER_SIZE 16
+#define FLAG_KEY_FRAME 0x01
+#define FLAG_DTS 0x02
+
+enum {
+ READ_HEADER,
+ READ_DATA,
+};
+
+typedef struct FFMContext {
+ /* only reading mode */
+ int64_t write_index, file_size;
+ int read_state;
+ uint8_t header[FRAME_HEADER_SIZE+4];
+
+ /* read and write */
+ int first_packet; /* true if first packet, needed to set the discontinuity tag */
+ int packet_size;
+ int frame_offset;
+ int64_t dts;
+ uint8_t *packet_ptr, *packet_end;
+ uint8_t packet[FFM_PACKET_SIZE];
+ int64_t start_time;
+} FFMContext;
+
+#endif /* AVFORMAT_FFM_H */
diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c
new file mode 100644
index 0000000000..7c0f4510dc
--- /dev/null
+++ b/libavformat/ffmdec.c
@@ -0,0 +1,740 @@
+/*
+ * FFM (ffserver live feed) demuxer
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "avformat.h"
+#include "internal.h"
+#include "ffm.h"
+#include "avio_internal.h"
+
+static int ffm_is_avail_data(AVFormatContext *s, int size)
+{
+ FFMContext *ffm = s->priv_data;
+ int64_t pos, avail_size;
+ int len;
+
+ len = ffm->packet_end - ffm->packet_ptr;
+ if (size <= len)
+ return 1;
+ pos = avio_tell(s->pb);
+ if (!ffm->write_index) {
+ if (pos == ffm->file_size)
+ return AVERROR_EOF;
+ avail_size = ffm->file_size - pos;
+ } else {
+ if (pos == ffm->write_index) {
+ /* exactly at the end of stream */
+ return AVERROR(EAGAIN);
+ } else if (pos < ffm->write_index) {
+ avail_size = ffm->write_index - pos;
+ } else {
+ avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE);
+ }
+ }
+ avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len;
+ if (size <= avail_size)
+ return 1;
+ else
+ return AVERROR(EAGAIN);
+}
+
+static int ffm_resync(AVFormatContext *s, int state)
+{
+ av_log(s, AV_LOG_ERROR, "resyncing\n");
+ while (state != PACKET_ID) {
+ if (avio_feof(s->pb)) {
+ av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n");
+ return -1;
+ }
+ state = (state << 8) | avio_r8(s->pb);
+ }
+ return 0;
+}
+
+/* first is true if we read the frame header */
+static int ffm_read_data(AVFormatContext *s,
+ uint8_t *buf, int size, int header)
+{
+ FFMContext *ffm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int len, fill_size, size1, frame_offset, id;
+ int64_t last_pos = -1;
+
+ size1 = size;
+ while (size > 0) {
+ redo:
+ len = ffm->packet_end - ffm->packet_ptr;
+ if (len < 0)
+ return -1;
+ if (len > size)
+ len = size;
+ if (len == 0) {
+ if (avio_tell(pb) == ffm->file_size)
+ avio_seek(pb, ffm->packet_size, SEEK_SET);
+ retry_read:
+ if (pb->buffer_size != ffm->packet_size) {
+ int64_t tell = avio_tell(pb);
+ ffio_set_buf_size(pb, ffm->packet_size);
+ avio_seek(pb, tell, SEEK_SET);
+ }
+ id = avio_rb16(pb); /* PACKET_ID */
+ if (id != PACKET_ID) {
+ if (ffm_resync(s, id) < 0)
+ return -1;
+ last_pos = avio_tell(pb);
+ }
+ fill_size = avio_rb16(pb);
+ ffm->dts = avio_rb64(pb);
+ frame_offset = avio_rb16(pb);
+ avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE);
+ ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size);
+ if (ffm->packet_end < ffm->packet || frame_offset < 0)
+ return -1;
+ /* if first packet or resynchronization packet, we must
+ handle it specifically */
+ if (ffm->first_packet || (frame_offset & 0x8000)) {
+ if (!frame_offset) {
+ /* This packet has no frame headers in it */
+ if (avio_tell(pb) >= ffm->packet_size * 3LL) {
+ int64_t seekback = FFMIN(ffm->packet_size * 2LL, avio_tell(pb) - last_pos);
+ seekback = FFMAX(seekback, 0);
+ avio_seek(pb, -seekback, SEEK_CUR);
+ goto retry_read;
+ }
+ /* This is bad, we cannot find a valid frame header */
+ return 0;
+ }
+ ffm->first_packet = 0;
+ if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE)
+ return -1;
+ ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE;
+ if (!header)
+ break;
+ } else {
+ ffm->packet_ptr = ffm->packet;
+ }
+ goto redo;
+ }
+ memcpy(buf, ffm->packet_ptr, len);
+ buf += len;
+ ffm->packet_ptr += len;
+ size -= len;
+ header = 0;
+ }
+ return size1 - size;
+}
+
+/* ensure that acutal seeking happens between FFM_PACKET_SIZE
+ and file_size - FFM_PACKET_SIZE */
+static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1)
+{
+ FFMContext *ffm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t pos;
+
+ pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE);
+ pos = FFMAX(pos, FFM_PACKET_SIZE);
+ av_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos);
+ return avio_seek(pb, pos, SEEK_SET);
+}
+
+static int64_t get_dts(AVFormatContext *s, int64_t pos)
+{
+ AVIOContext *pb = s->pb;
+ int64_t dts;
+
+ ffm_seek1(s, pos);
+ avio_skip(pb, 4);
+ dts = avio_rb64(pb);
+ av_dlog(s, "dts=%0.6f\n", dts / 1000000.0);
+ return dts;
+}
+
+static void adjust_write_index(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t pts;
+ //int64_t orig_write_index = ffm->write_index;
+ int64_t pos_min, pos_max;
+ int64_t pts_start;
+ int64_t ptr = avio_tell(pb);
+
+
+ pos_min = 0;
+ pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE;
+
+ pts_start = get_dts(s, pos_min);
+
+ pts = get_dts(s, pos_max);
+
+ if (pts - 100000 > pts_start)
+ goto end;
+
+ ffm->write_index = FFM_PACKET_SIZE;
+
+ pts_start = get_dts(s, pos_min);
+
+ pts = get_dts(s, pos_max);
+
+ if (pts - 100000 <= pts_start) {
+ while (1) {
+ int64_t newpos;
+ int64_t newpts;
+
+ newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE;
+
+ if (newpos == pos_min)
+ break;
+
+ newpts = get_dts(s, newpos);
+
+ if (newpts - 100000 <= pts) {
+ pos_max = newpos;
+ pts = newpts;
+ } else {
+ pos_min = newpos;
+ }
+ }
+ ffm->write_index += pos_max;
+ }
+
+ end:
+ avio_seek(pb, ptr, SEEK_SET);
+}
+
+
+static int ffm_close(AVFormatContext *s)
+{
+ int i;
+
+ for (i = 0; i < s->nb_streams; i++)
+ av_freep(&s->streams[i]->codec->rc_eq);
+
+ return 0;
+}
+
+static int ffm_append_recommended_configuration(AVStream *st, char **conf)
+{
+ int ret;
+ size_t newsize;
+ av_assert0(conf && st);
+ if (!*conf)
+ return 0;
+ if (!st->recommended_encoder_configuration) {
+ st->recommended_encoder_configuration = *conf;
+ *conf = 0;
+ return 0;
+ }
+ newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2;
+ if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0)
+ return ret;
+ av_strlcat(st->recommended_encoder_configuration, ",", newsize);
+ av_strlcat(st->recommended_encoder_configuration, *conf, newsize);
+ av_freep(conf);
+ return 0;
+}
+
+static int ffm2_read_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *codec;
+ int ret;
+ int f_main = 0, f_cprv = -1, f_stvi = -1, f_stau = -1;
+ AVCodec *enc;
+ char *buffer;
+
+ ffm->packet_size = avio_rb32(pb);
+ if (ffm->packet_size != FFM_PACKET_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid packet size %d, expected size was %d\n",
+ ffm->packet_size, FFM_PACKET_SIZE);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ ffm->write_index = avio_rb64(pb);
+ /* get also filesize */
+ if (pb->seekable) {
+ ffm->file_size = avio_size(pb);
+ if (ffm->write_index && 0)
+ adjust_write_index(s);
+ } else {
+ ffm->file_size = (UINT64_C(1) << 63) - 1;
+ }
+
+ while(!avio_feof(pb)) {
+ unsigned id = avio_rb32(pb);
+ unsigned size = avio_rb32(pb);
+ int64_t next = avio_tell(pb) + size;
+ char rc_eq_buf[128];
+
+ if(!id)
+ break;
+
+ switch(id) {
+ case MKBETAG('M', 'A', 'I', 'N'):
+ if (f_main++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ avio_rb32(pb); /* nb_streams */
+ avio_rb32(pb); /* total bitrate */
+ break;
+ case MKBETAG('C', 'O', 'M', 'M'):
+ f_cprv = f_stvi = f_stau = 0;
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+
+ codec = st->codec;
+ /* generic info */
+ codec->codec_id = avio_rb32(pb);
+ codec->codec_type = avio_r8(pb);
+ codec->bit_rate = avio_rb32(pb);
+ codec->flags = avio_rb32(pb);
+ codec->flags2 = avio_rb32(pb);
+ codec->debug = avio_rb32(pb);
+ if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
+ if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0)
+ return AVERROR(ENOMEM);
+ }
+ break;
+ case MKBETAG('S', 'T', 'V', 'I'):
+ if (f_stvi++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ codec->time_base.num = avio_rb32(pb);
+ codec->time_base.den = avio_rb32(pb);
+ if (codec->time_base.num <= 0 || codec->time_base.den <= 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid time base %d/%d\n",
+ codec->time_base.num, codec->time_base.den);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ codec->width = avio_rb16(pb);
+ codec->height = avio_rb16(pb);
+ codec->gop_size = avio_rb16(pb);
+ codec->pix_fmt = avio_rb32(pb);
+ codec->qmin = avio_r8(pb);
+ codec->qmax = avio_r8(pb);
+ codec->max_qdiff = avio_r8(pb);
+ codec->qcompress = avio_rb16(pb) / 10000.0;
+ codec->qblur = avio_rb16(pb) / 10000.0;
+ codec->bit_rate_tolerance = avio_rb32(pb);
+ avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
+ codec->rc_eq = av_strdup(rc_eq_buf);
+ codec->rc_max_rate = avio_rb32(pb);
+ codec->rc_min_rate = avio_rb32(pb);
+ codec->rc_buffer_size = avio_rb32(pb);
+ codec->i_quant_factor = av_int2double(avio_rb64(pb));
+ codec->b_quant_factor = av_int2double(avio_rb64(pb));
+ codec->i_quant_offset = av_int2double(avio_rb64(pb));
+ codec->b_quant_offset = av_int2double(avio_rb64(pb));
+ codec->dct_algo = avio_rb32(pb);
+ codec->strict_std_compliance = avio_rb32(pb);
+ codec->max_b_frames = avio_rb32(pb);
+ codec->mpeg_quant = avio_rb32(pb);
+ codec->intra_dc_precision = avio_rb32(pb);
+ codec->me_method = avio_rb32(pb);
+ codec->mb_decision = avio_rb32(pb);
+ codec->nsse_weight = avio_rb32(pb);
+ codec->frame_skip_cmp = avio_rb32(pb);
+ codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
+ codec->codec_tag = avio_rb32(pb);
+ codec->thread_count = avio_r8(pb);
+ codec->coder_type = avio_rb32(pb);
+ codec->me_cmp = avio_rb32(pb);
+ codec->me_subpel_quality = avio_rb32(pb);
+ codec->me_range = avio_rb32(pb);
+ codec->keyint_min = avio_rb32(pb);
+ codec->scenechange_threshold = avio_rb32(pb);
+ codec->b_frame_strategy = avio_rb32(pb);
+ codec->qcompress = av_int2double(avio_rb64(pb));
+ codec->qblur = av_int2double(avio_rb64(pb));
+ codec->max_qdiff = avio_rb32(pb);
+ codec->refs = avio_rb32(pb);
+ break;
+ case MKBETAG('S', 'T', 'A', 'U'):
+ if (f_stau++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ codec->sample_rate = avio_rb32(pb);
+ codec->channels = avio_rl16(pb);
+ codec->frame_size = avio_rl16(pb);
+ break;
+ case MKBETAG('C', 'P', 'R', 'V'):
+ if (f_cprv++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ enc = avcodec_find_encoder(codec->codec_id);
+ if (enc && enc->priv_data_size && enc->priv_class) {
+ buffer = av_malloc(size + 1);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, size, buffer, size + 1);
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ }
+ break;
+ case MKBETAG('S', '2', 'V', 'I'):
+ if (f_stvi++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ buffer = av_malloc(size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, INT_MAX, buffer, size);
+ av_set_options_string(codec, buffer, "=", ",");
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ break;
+ case MKBETAG('S', '2', 'A', 'U'):
+ if (f_stau++) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ buffer = av_malloc(size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ avio_get_str(pb, INT_MAX, buffer, size);
+ av_set_options_string(codec, buffer, "=", ",");
+ if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0)
+ goto fail;
+ break;
+ }
+ avio_seek(pb, next, SEEK_SET);
+ }
+
+ /* get until end of block reached */
+ while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached)
+ avio_r8(pb);
+
+ /* init packet demux */
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet;
+ ffm->frame_offset = 0;
+ ffm->dts = 0;
+ ffm->read_state = READ_HEADER;
+ ffm->first_packet = 1;
+ return 0;
+ fail:
+ ffm_close(s);
+ return ret;
+}
+
+static int ffm_read_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *codec;
+ int i, nb_streams;
+ uint32_t tag;
+
+ /* header */
+ tag = avio_rl32(pb);
+ if (tag == MKTAG('F', 'F', 'M', '2'))
+ return ffm2_read_header(s);
+ if (tag != MKTAG('F', 'F', 'M', '1'))
+ goto fail;
+ ffm->packet_size = avio_rb32(pb);
+ if (ffm->packet_size != FFM_PACKET_SIZE)
+ goto fail;
+ ffm->write_index = avio_rb64(pb);
+ /* get also filesize */
+ if (pb->seekable) {
+ ffm->file_size = avio_size(pb);
+ if (ffm->write_index && 0)
+ adjust_write_index(s);
+ } else {
+ ffm->file_size = (UINT64_C(1) << 63) - 1;
+ }
+
+ nb_streams = avio_rb32(pb);
+ avio_rb32(pb); /* total bitrate */
+ /* read each stream */
+ for(i=0;i<nb_streams;i++) {
+ char rc_eq_buf[128];
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ goto fail;
+
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+
+ codec = st->codec;
+ /* generic info */
+ codec->codec_id = avio_rb32(pb);
+ codec->codec_type = avio_r8(pb); /* codec_type */
+ codec->bit_rate = avio_rb32(pb);
+ codec->flags = avio_rb32(pb);
+ codec->flags2 = avio_rb32(pb);
+ codec->debug = avio_rb32(pb);
+ /* specific info */
+ switch(codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ codec->time_base.num = avio_rb32(pb);
+ codec->time_base.den = avio_rb32(pb);
+ if (codec->time_base.num <= 0 || codec->time_base.den <= 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid time base %d/%d\n",
+ codec->time_base.num, codec->time_base.den);
+ goto fail;
+ }
+ codec->width = avio_rb16(pb);
+ codec->height = avio_rb16(pb);
+ codec->gop_size = avio_rb16(pb);
+ codec->pix_fmt = avio_rb32(pb);
+ codec->qmin = avio_r8(pb);
+ codec->qmax = avio_r8(pb);
+ codec->max_qdiff = avio_r8(pb);
+ codec->qcompress = avio_rb16(pb) / 10000.0;
+ codec->qblur = avio_rb16(pb) / 10000.0;
+ codec->bit_rate_tolerance = avio_rb32(pb);
+ avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf));
+ codec->rc_eq = av_strdup(rc_eq_buf);
+ codec->rc_max_rate = avio_rb32(pb);
+ codec->rc_min_rate = avio_rb32(pb);
+ codec->rc_buffer_size = avio_rb32(pb);
+ codec->i_quant_factor = av_int2double(avio_rb64(pb));
+ codec->b_quant_factor = av_int2double(avio_rb64(pb));
+ codec->i_quant_offset = av_int2double(avio_rb64(pb));
+ codec->b_quant_offset = av_int2double(avio_rb64(pb));
+ codec->dct_algo = avio_rb32(pb);
+ codec->strict_std_compliance = avio_rb32(pb);
+ codec->max_b_frames = avio_rb32(pb);
+ codec->mpeg_quant = avio_rb32(pb);
+ codec->intra_dc_precision = avio_rb32(pb);
+ codec->me_method = avio_rb32(pb);
+ codec->mb_decision = avio_rb32(pb);
+ codec->nsse_weight = avio_rb32(pb);
+ codec->frame_skip_cmp = avio_rb32(pb);
+ codec->rc_buffer_aggressivity = av_int2double(avio_rb64(pb));
+ codec->codec_tag = avio_rb32(pb);
+ codec->thread_count = avio_r8(pb);
+ codec->coder_type = avio_rb32(pb);
+ codec->me_cmp = avio_rb32(pb);
+ codec->me_subpel_quality = avio_rb32(pb);
+ codec->me_range = avio_rb32(pb);
+ codec->keyint_min = avio_rb32(pb);
+ codec->scenechange_threshold = avio_rb32(pb);
+ codec->b_frame_strategy = avio_rb32(pb);
+ codec->qcompress = av_int2double(avio_rb64(pb));
+ codec->qblur = av_int2double(avio_rb64(pb));
+ codec->max_qdiff = avio_rb32(pb);
+ codec->refs = avio_rb32(pb);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ codec->sample_rate = avio_rb32(pb);
+ codec->channels = avio_rl16(pb);
+ codec->frame_size = avio_rl16(pb);
+ break;
+ default:
+ goto fail;
+ }
+ if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
+ if (ff_get_extradata(codec, pb, avio_rb32(pb)) < 0)
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ /* get until end of block reached */
+ while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached)
+ avio_r8(pb);
+
+ /* init packet demux */
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet;
+ ffm->frame_offset = 0;
+ ffm->dts = 0;
+ ffm->read_state = READ_HEADER;
+ ffm->first_packet = 1;
+ return 0;
+ fail:
+ ffm_close(s);
+ return -1;
+}
+
+/* return < 0 if eof */
+static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int size;
+ FFMContext *ffm = s->priv_data;
+ int duration, ret;
+
+ switch(ffm->read_state) {
+ case READ_HEADER:
+ if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0)
+ return ret;
+
+ av_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n",
+ avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size);
+ if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) !=
+ FRAME_HEADER_SIZE)
+ return -1;
+ if (ffm->header[1] & FLAG_DTS)
+ if (ffm_read_data(s, ffm->header+16, 4, 1) != 4)
+ return -1;
+ ffm->read_state = READ_DATA;
+ /* fall through */
+ case READ_DATA:
+ size = AV_RB24(ffm->header + 2);
+ if ((ret = ffm_is_avail_data(s, size)) < 0)
+ return ret;
+
+ duration = AV_RB24(ffm->header + 5);
+
+ if (av_new_packet(pkt, size) < 0) {
+ return AVERROR(ENOMEM);
+ }
+ pkt->stream_index = ffm->header[0];
+ if ((unsigned)pkt->stream_index >= s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index);
+ av_free_packet(pkt);
+ ffm->read_state = READ_HEADER;
+ return -1;
+ }
+ pkt->pos = avio_tell(s->pb);
+ if (ffm->header[1] & FLAG_KEY_FRAME)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ ffm->read_state = READ_HEADER;
+ if (ffm_read_data(s, pkt->data, size, 0) != size) {
+ /* bad case: desynchronized packet. we cancel all the packet loading */
+ av_free_packet(pkt);
+ return -1;
+ }
+ pkt->pts = AV_RB64(ffm->header+8);
+ if (ffm->header[1] & FLAG_DTS)
+ pkt->dts = pkt->pts - AV_RB32(ffm->header+16);
+ else
+ pkt->dts = pkt->pts;
+ pkt->duration = duration;
+ break;
+ }
+ return 0;
+}
+
+/* seek to a given time in the file. The file read pointer is
+ positioned at or before pts. XXX: the following code is quite
+ approximative */
+static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags)
+{
+ FFMContext *ffm = s->priv_data;
+ int64_t pos_min, pos_max, pos;
+ int64_t pts_min, pts_max, pts;
+ double pos1;
+
+ av_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0);
+ /* find the position using linear interpolation (better than
+ dichotomy in typical cases) */
+ if (ffm->write_index && ffm->write_index < ffm->file_size) {
+ if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) {
+ pos_min = FFM_PACKET_SIZE;
+ pos_max = ffm->write_index - FFM_PACKET_SIZE;
+ } else {
+ pos_min = ffm->write_index;
+ pos_max = ffm->file_size - FFM_PACKET_SIZE;
+ }
+ } else {
+ pos_min = FFM_PACKET_SIZE;
+ pos_max = ffm->file_size - FFM_PACKET_SIZE;
+ }
+ while (pos_min <= pos_max) {
+ pts_min = get_dts(s, pos_min);
+ pts_max = get_dts(s, pos_max);
+ if (pts_min > wanted_pts || pts_max <= wanted_pts) {
+ pos = pts_min > wanted_pts ? pos_min : pos_max;
+ goto found;
+ }
+ /* linear interpolation */
+ pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) /
+ (double)(pts_max - pts_min);
+ pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE;
+ if (pos <= pos_min)
+ pos = pos_min;
+ else if (pos >= pos_max)
+ pos = pos_max;
+ pts = get_dts(s, pos);
+ /* check if we are lucky */
+ if (pts == wanted_pts) {
+ goto found;
+ } else if (pts > wanted_pts) {
+ pos_max = pos - FFM_PACKET_SIZE;
+ } else {
+ pos_min = pos + FFM_PACKET_SIZE;
+ }
+ }
+ pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
+
+ found:
+ if (ffm_seek1(s, pos) < 0)
+ return -1;
+
+ /* reset read state */
+ ffm->read_state = READ_HEADER;
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet;
+ ffm->first_packet = 1;
+
+ return 0;
+}
+
+static int ffm_probe(AVProbeData *p)
+{
+ if (
+ p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' &&
+ (p->buf[3] == '1' || p->buf[3] == '2'))
+ return AVPROBE_SCORE_MAX + 1;
+ return 0;
+}
+
+AVInputFormat ff_ffm_demuxer = {
+ .name = "ffm",
+ .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
+ .priv_data_size = sizeof(FFMContext),
+ .read_probe = ffm_probe,
+ .read_header = ffm_read_header,
+ .read_packet = ffm_read_packet,
+ .read_close = ffm_close,
+ .read_seek = ffm_seek,
+};
diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c
new file mode 100644
index 0000000000..3abbfdd08f
--- /dev/null
+++ b/libavformat/ffmenc.c
@@ -0,0 +1,374 @@
+/*
+ * FFM (ffserver live feed) muxer
+ * Copyright (c) 2001 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/avassert.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "ffm.h"
+
+static void flush_packet(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ int fill_size, h;
+ AVIOContext *pb = s->pb;
+
+ fill_size = ffm->packet_end - ffm->packet_ptr;
+ memset(ffm->packet_ptr, 0, fill_size);
+
+ av_assert1(avio_tell(pb) % ffm->packet_size == 0);
+
+ /* put header */
+ avio_wb16(pb, PACKET_ID);
+ avio_wb16(pb, fill_size);
+ avio_wb64(pb, ffm->dts);
+ h = ffm->frame_offset;
+ if (ffm->first_packet)
+ h |= 0x8000;
+ avio_wb16(pb, h);
+ avio_write(pb, ffm->packet, ffm->packet_end - ffm->packet);
+ avio_flush(pb);
+
+ /* prepare next packet */
+ ffm->frame_offset = 0; /* no key frame */
+ ffm->packet_ptr = ffm->packet;
+ ffm->first_packet = 0;
+}
+
+/* 'first' is true if first data of a frame */
+static void ffm_write_data(AVFormatContext *s,
+ const uint8_t *buf, int size,
+ int64_t dts, int header)
+{
+ FFMContext *ffm = s->priv_data;
+ int len;
+
+ if (header && ffm->frame_offset == 0) {
+ ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE;
+ ffm->dts = dts;
+ }
+
+ /* write as many packets as needed */
+ while (size > 0) {
+ len = ffm->packet_end - ffm->packet_ptr;
+ if (len > size)
+ len = size;
+ memcpy(ffm->packet_ptr, buf, len);
+
+ ffm->packet_ptr += len;
+ buf += len;
+ size -= len;
+ if (ffm->packet_ptr >= ffm->packet_end)
+ flush_packet(s);
+ }
+}
+
+static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id)
+{
+ uint8_t *dyn_buf;
+ int dyn_size= avio_close_dyn_buf(dpb, &dyn_buf);
+ avio_wb32(pb, id);
+ avio_wb32(pb, dyn_size);
+ avio_write(pb, dyn_buf, dyn_size);
+ av_free(dyn_buf);
+}
+
+static int ffm_write_header_codec_private_ctx(AVFormatContext *s, AVCodecContext *ctx, int type)
+{
+ AVIOContext *pb = s->pb;
+ AVIOContext *tmp;
+ char *buf = NULL;
+ int ret;
+ const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id);
+
+ if (!enc) {
+ av_log(s, AV_LOG_WARNING, "Stream codec is not found. Codec private options are not stored.\n");
+ return 0;
+ }
+ if (ctx->priv_data && enc->priv_class && enc->priv_data_size) {
+ if ((ret = av_opt_serialize(ctx->priv_data, AV_OPT_FLAG_ENCODING_PARAM | type,
+ AV_OPT_SERIALIZE_SKIP_DEFAULTS, &buf, '=', ',')) < 0)
+ return ret;
+ if (buf && strlen(buf)) {
+ if (avio_open_dyn_buf(&tmp) < 0) {
+ av_free(buf);
+ return AVERROR(ENOMEM);
+ }
+ avio_put_str(tmp, buf);
+ write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V'));
+ }
+ av_free(buf);
+ }
+ return 0;
+}
+
+static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecContext *ctx, unsigned tag, int type)
+{
+ AVIOContext *tmp;
+ char *buf = NULL;
+ int ret, need_coma = 0;
+
+#define SKIP_DEFAULTS AV_OPT_SERIALIZE_SKIP_DEFAULTS
+#define OPT_FLAGS_EXACT AV_OPT_SERIALIZE_OPT_FLAGS_EXACT
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+
+ if (avio_open_dyn_buf(&tmp) < 0)
+ return AVERROR(ENOMEM);
+ if ((ret = av_opt_serialize(ctx, ENC | type, SKIP_DEFAULTS, &buf, '=', ',')) < 0)
+ goto fail;
+ if (buf && strlen(buf)) {
+ avio_write(tmp, buf, strlen(buf));
+ av_freep(&buf);
+ need_coma = 1;
+ }
+ if ((ret = av_opt_serialize(ctx, 0, SKIP_DEFAULTS | OPT_FLAGS_EXACT, &buf, '=', ',')) < 0)
+ goto fail;
+ if (buf && strlen(buf)) {
+ if (need_coma)
+ avio_w8(tmp, ',');
+ avio_write(tmp, buf, strlen(buf));
+ }
+ av_freep(&buf);
+ avio_w8(tmp, 0);
+ write_header_chunk(pb, tmp, tag);
+ return 0;
+ fail:
+ av_free(buf);
+ ffio_free_dyn_buf(&tmp);
+ return ret;
+
+#undef SKIP_DEFAULTS
+#undef OPT_FLAGS_EXACT
+#undef ENC
+}
+
+static int ffm_write_recommended_config(AVIOContext *pb, AVCodecContext *ctx, unsigned tag,
+ const char *configuration)
+{
+ int ret;
+ const AVCodec *enc = ctx->codec ? ctx->codec : avcodec_find_encoder(ctx->codec_id);
+ AVIOContext *tmp;
+ AVDictionaryEntry *t = NULL;
+ AVDictionary *all = NULL, *comm = NULL, *prv = NULL;
+ char *buf = NULL;
+
+ if (!enc || !enc->priv_class || !enc->priv_data_size) {
+ /* codec is not known/has no private options, so save everything as common options */
+ if (avio_open_dyn_buf(&tmp) < 0)
+ return AVERROR(ENOMEM);
+ avio_put_str(tmp, configuration);
+ write_header_chunk(pb, tmp, tag);
+ return 0;
+ }
+
+ if ((ret = av_dict_parse_string(&all, configuration, "=", ",", 0)) < 0)
+ return ret;
+
+ while ((t = av_dict_get(all, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ if (av_opt_find((void *)&enc->priv_class, t->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) {
+ if ((ret = av_dict_set(&prv, t->key, t->value, 0)) < 0)
+ goto fail;
+ } else if ((ret = av_dict_set(&comm, t->key, t->value, 0)) < 0)
+ goto fail;
+ }
+
+ if (comm) {
+ if ((ret = av_dict_get_string(comm, &buf, '=', ',')) < 0 ||
+ (ret = avio_open_dyn_buf(&tmp)) < 0)
+ goto fail;
+ avio_put_str(tmp, buf);
+ av_freep(&buf);
+ write_header_chunk(pb, tmp, tag);
+ }
+ if (prv) {
+ if ((ret = av_dict_get_string(prv, &buf, '=', ',')) < 0 ||
+ (ret = avio_open_dyn_buf(&tmp)) < 0)
+ goto fail;
+ avio_put_str(tmp, buf);
+ write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V'));
+ }
+
+ fail:
+ av_free(buf);
+ av_dict_free(&all);
+ av_dict_free(&comm);
+ av_dict_free(&prv);
+ return ret;
+}
+
+static int ffm_write_header(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+ AVDictionaryEntry *t;
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *codec;
+ int bit_rate, i, ret;
+
+ if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) {
+ ret = av_parse_time(&ffm->start_time, t->value, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ ffm->packet_size = FFM_PACKET_SIZE;
+
+ /* header */
+ avio_wl32(pb, MKTAG('F', 'F', 'M', '2'));
+ avio_wb32(pb, ffm->packet_size);
+ avio_wb64(pb, 0); /* current write position */
+
+ if(avio_open_dyn_buf(&pb) < 0)
+ return AVERROR(ENOMEM);
+
+ avio_wb32(pb, s->nb_streams);
+ bit_rate = 0;
+ for(i=0;i<s->nb_streams;i++) {
+ st = s->streams[i];
+ bit_rate += st->codec->bit_rate;
+ }
+ avio_wb32(pb, bit_rate);
+
+ write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N'));
+
+ /* list of streams */
+ for(i=0;i<s->nb_streams;i++) {
+ st = s->streams[i];
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+ if(avio_open_dyn_buf(&pb) < 0)
+ return AVERROR(ENOMEM);
+
+ codec = st->codec;
+ /* generic info */
+ avio_wb32(pb, codec->codec_id);
+ avio_w8(pb, codec->codec_type);
+ avio_wb32(pb, codec->bit_rate);
+ avio_wb32(pb, codec->flags);
+ avio_wb32(pb, codec->flags2);
+ avio_wb32(pb, codec->debug);
+ if (codec->flags & CODEC_FLAG_GLOBAL_HEADER) {
+ avio_wb32(pb, codec->extradata_size);
+ avio_write(pb, codec->extradata, codec->extradata_size);
+ }
+ write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M'));
+ /* specific info */
+ switch(codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (st->recommended_encoder_configuration) {
+ av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n",
+ st->recommended_encoder_configuration);
+ if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'V', 'I'),
+ st->recommended_encoder_configuration)) < 0)
+ return ret;
+ } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0 ||
+ (ret = ffm_write_header_codec_private_ctx(s, codec, AV_OPT_FLAG_VIDEO_PARAM)) < 0)
+ return ret;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if (st->recommended_encoder_configuration) {
+ av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n",
+ st->recommended_encoder_configuration);
+ if ((ret = ffm_write_recommended_config(s->pb, codec, MKBETAG('S', '2', 'A', 'U'),
+ st->recommended_encoder_configuration)) < 0)
+ return ret;
+ } else if ((ret = ffm_write_header_codec_ctx(s->pb, codec, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0 ||
+ (ret = ffm_write_header_codec_private_ctx(s, codec, AV_OPT_FLAG_AUDIO_PARAM)) < 0)
+ return ret;
+ break;
+ default:
+ return -1;
+ }
+ }
+ pb = s->pb;
+
+ avio_wb64(pb, 0); // end of header
+
+ /* flush until end of block reached */
+ while ((avio_tell(pb) % ffm->packet_size) != 0)
+ avio_w8(pb, 0);
+
+ avio_flush(pb);
+
+ /* init packet mux */
+ ffm->packet_ptr = ffm->packet;
+ ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE;
+ av_assert0(ffm->packet_end >= ffm->packet);
+ ffm->frame_offset = 0;
+ ffm->dts = 0;
+ ffm->first_packet = 1;
+
+ return 0;
+}
+
+static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ FFMContext *ffm = s->priv_data;
+ int64_t dts;
+ uint8_t header[FRAME_HEADER_SIZE+4];
+ int header_size = FRAME_HEADER_SIZE;
+
+ dts = ffm->start_time + pkt->dts;
+ /* packet size & key_frame */
+ header[0] = pkt->stream_index;
+ header[1] = 0;
+ if (pkt->flags & AV_PKT_FLAG_KEY)
+ header[1] |= FLAG_KEY_FRAME;
+ AV_WB24(header+2, pkt->size);
+ AV_WB24(header+5, pkt->duration);
+ AV_WB64(header+8, ffm->start_time + pkt->pts);
+ if (pkt->pts != pkt->dts) {
+ header[1] |= FLAG_DTS;
+ AV_WB32(header+16, pkt->pts - pkt->dts);
+ header_size += 4;
+ }
+ ffm_write_data(s, header, header_size, dts, 1);
+ ffm_write_data(s, pkt->data, pkt->size, dts, 0);
+
+ return 0;
+}
+
+static int ffm_write_trailer(AVFormatContext *s)
+{
+ FFMContext *ffm = s->priv_data;
+
+ /* flush packets */
+ if (ffm->packet_ptr > ffm->packet)
+ flush_packet(s);
+
+ return 0;
+}
+
+AVOutputFormat ff_ffm_muxer = {
+ .name = "ffm",
+ .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"),
+ .extensions = "ffm",
+ .priv_data_size = sizeof(FFMContext),
+ .audio_codec = AV_CODEC_ID_MP2,
+ .video_codec = AV_CODEC_ID_MPEG1VIDEO,
+ .write_header = ffm_write_header,
+ .write_packet = ffm_write_packet,
+ .write_trailer = ffm_write_trailer,
+ .flags = AVFMT_TS_NEGATIVE,
+};
diff --git a/libavformat/ffmeta.h b/libavformat/ffmeta.h
index a5380ca13d..ae8778d614 100644
--- a/libavformat/ffmeta.h
+++ b/libavformat/ffmeta.h
@@ -2,20 +2,20 @@
* Common data for metadata muxer/demuxer
* Copyright (c) 2010 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/ffmetadec.c b/libavformat/ffmetadec.c
index 7dbf7ed35d..e226406932 100644
--- a/libavformat/ffmetadec.c
+++ b/libavformat/ffmetadec.c
@@ -2,20 +2,20 @@
* Metadata demuxer
* Copyright (c) 2010 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,7 @@ static void get_line(AVIOContext *s, uint8_t *buf, int size)
buf[i++] = c;
}
buf[i] = 0;
- } while (!s->eof_reached && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0));
+ } while (!avio_feof(s) && (buf[0] == ';' || buf[0] == '#' || buf[0] == 0));
}
static AVChapter *read_chapter(AVFormatContext *s)
@@ -78,10 +78,11 @@ static AVChapter *read_chapter(AVFormatContext *s)
return avpriv_new_chapter(s, s->nb_chapters, tb, start, end, NULL);
}
-static uint8_t *unescape(uint8_t *buf, int size)
+static uint8_t *unescape(const uint8_t *buf, int size)
{
uint8_t *ret = av_malloc(size + 1);
- uint8_t *p1 = ret, *p2 = buf;
+ uint8_t *p1 = ret;
+ const uint8_t *p2 = buf;
if (!ret)
return NULL;
@@ -95,9 +96,10 @@ static uint8_t *unescape(uint8_t *buf, int size)
return ret;
}
-static int read_tag(uint8_t *line, AVDictionary **m)
+static int read_tag(const uint8_t *line, AVDictionary **m)
{
- uint8_t *key, *value, *p = line;
+ uint8_t *key, *value;
+ const uint8_t *p = line;
/* find first not escaped '=' */
while (1) {
@@ -128,14 +130,14 @@ static int read_header(AVFormatContext *s)
AVDictionary **m = &s->metadata;
uint8_t line[1024];
- while(!s->pb->eof_reached) {
+ while(!avio_feof(s->pb)) {
get_line(s->pb, line, sizeof(line));
if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) {
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = AV_CODEC_ID_FFMETADATA;
@@ -145,7 +147,7 @@ static int read_header(AVFormatContext *s)
AVChapter *ch = read_chapter(s);
if (!ch)
- return -1;
+ return AVERROR(ENOMEM);
m = &ch->metadata;
} else
diff --git a/libavformat/ffmetaenc.c b/libavformat/ffmetaenc.c
index 19fe6c960f..a9adbb1d19 100644
--- a/libavformat/ffmetaenc.c
+++ b/libavformat/ffmetaenc.c
@@ -2,20 +2,20 @@
* Metadata muxer
* Copyright (c) 2010 Anton Khirnov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/file.c b/libavformat/file.c
index 2837e9f150..6511328de7 100644
--- a/libavformat/file.c
+++ b/libavformat/file.c
@@ -2,20 +2,20 @@
* buffered file I/O
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,6 +35,14 @@
#include "os_support.h"
#include "url.h"
+/* Some systems may not have S_ISFIFO */
+#ifndef S_ISFIFO
+# ifdef S_IFIFO
+# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+# else
+# define S_ISFIFO(m) 0
+# endif
+#endif
/* standard file protocol */
@@ -42,10 +50,17 @@ typedef struct FileContext {
const AVClass *class;
int fd;
int trunc;
+ int blocksize;
} FileContext;
static const AVOption file_options[] = {
- { "truncate", "Truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
+ { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
+ { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL }
+};
+
+static const AVOption pipe_options[] = {
+ { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
{ NULL }
};
@@ -56,16 +71,29 @@ static const AVClass file_class = {
.version = LIBAVUTIL_VERSION_INT,
};
+static const AVClass pipe_class = {
+ .class_name = "pipe",
+ .item_name = av_default_item_name,
+ .option = pipe_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
static int file_read(URLContext *h, unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
- return read(c->fd, buf, size);
+ int r;
+ size = FFMIN(size, c->blocksize);
+ r = read(c->fd, buf, size);
+ return (-1 == r)?AVERROR(errno):r;
}
static int file_write(URLContext *h, const unsigned char *buf, int size)
{
FileContext *c = h->priv_data;
- return write(c->fd, buf, size);
+ int r;
+ size = FFMIN(size, c->blocksize);
+ r = write(c->fd, buf, size);
+ return (-1 == r)?AVERROR(errno):r;
}
static int file_get_handle(URLContext *h)
@@ -76,14 +104,30 @@ static int file_get_handle(URLContext *h)
static int file_check(URLContext *h, int mask)
{
+ int ret = 0;
+ const char *filename = h->filename;
+ av_strstart(filename, "file:", &filename);
+
+ {
+#if HAVE_ACCESS && defined(R_OK)
+ if (access(filename, F_OK) < 0)
+ return AVERROR(errno);
+ if (mask&AVIO_FLAG_READ)
+ if (access(filename, R_OK) >= 0)
+ ret |= AVIO_FLAG_READ;
+ if (mask&AVIO_FLAG_WRITE)
+ if (access(filename, W_OK) >= 0)
+ ret |= AVIO_FLAG_WRITE;
+#else
struct stat st;
- int ret = stat(h->filename, &st);
+ ret = stat(filename, &st);
if (ret < 0)
return AVERROR(errno);
ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0;
ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
-
+#endif
+ }
return ret;
}
@@ -94,6 +138,7 @@ static int file_open(URLContext *h, const char *filename, int flags)
FileContext *c = h->priv_data;
int access;
int fd;
+ struct stat st;
av_strstart(filename, "file:", &filename);
@@ -115,6 +160,9 @@ static int file_open(URLContext *h, const char *filename, int flags)
if (fd == -1)
return AVERROR(errno);
c->fd = fd;
+
+ h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
+
return 0;
}
@@ -126,9 +174,8 @@ static int64_t file_seek(URLContext *h, int64_t pos, int whence)
if (whence == AVSEEK_SIZE) {
struct stat st;
-
ret = fstat(c->fd, &st);
- return ret < 0 ? AVERROR(errno) : st.st_size;
+ return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
}
ret = lseek(c->fd, pos, whence);
@@ -190,6 +237,7 @@ URLProtocol ff_pipe_protocol = {
.url_get_file_handle = file_get_handle,
.url_check = file_check,
.priv_data_size = sizeof(FileContext),
+ .priv_data_class = &pipe_class,
};
#endif /* CONFIG_PIPE_PROTOCOL */
diff --git a/libavformat/filmstripdec.c b/libavformat/filmstripdec.c
index c82656e72f..cdbb93b11a 100644
--- a/libavformat/filmstripdec.c
+++ b/libavformat/filmstripdec.c
@@ -2,20 +2,20 @@
* Adobe Filmstrip demuxer
* Copyright (c) 2010 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,7 +45,7 @@ static int read_header(AVFormatContext *s)
avio_seek(pb, avio_size(pb) - 36, SEEK_SET);
if (avio_rb32(pb) != RAND_TAG) {
- av_log(s, AV_LOG_ERROR, "magic number not found");
+ av_log(s, AV_LOG_ERROR, "magic number not found\n");
return AVERROR_INVALIDDATA;
}
@@ -67,6 +67,12 @@ static int read_header(AVFormatContext *s)
st->codec->width = avio_rb16(pb);
st->codec->height = avio_rb16(pb);
film->leading = avio_rb16(pb);
+
+ if (st->codec->width * 4LL * st->codec->height >= INT_MAX) {
+ av_log(s, AV_LOG_ERROR, "dimensions too large\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
avpriv_set_pts_info(st, 64, 1, avio_rb16(pb));
avio_seek(pb, 0, SEEK_SET);
@@ -80,9 +86,9 @@ static int read_packet(AVFormatContext *s,
FilmstripDemuxContext *film = s->priv_data;
AVStream *st = s->streams[0];
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR(EIO);
- pkt->dts = avio_tell(s->pb) / (st->codec->width * (st->codec->height + film->leading) * 4);
+ pkt->dts = avio_tell(s->pb) / (st->codec->width * (int64_t)(st->codec->height + film->leading) * 4);
pkt->size = av_get_packet(s->pb, pkt, st->codec->width * st->codec->height * 4);
avio_skip(s->pb, st->codec->width * (int64_t) film->leading * 4);
if (pkt->size < 0)
diff --git a/libavformat/filmstripenc.c b/libavformat/filmstripenc.c
index 0794b18c50..9e2c71082f 100644
--- a/libavformat/filmstripenc.c
+++ b/libavformat/filmstripenc.c
@@ -2,20 +2,20 @@
* Adobe Filmstrip muxer
* Copyright (c) 2010 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,7 +65,7 @@ static int write_trailer(AVFormatContext *s)
avio_wb16(pb, st->codec->height);
avio_wb16(pb, 0); // leading
// TODO: should be avg_frame_rate
- avio_wb16(pb, 1/av_q2d(st->time_base));
+ avio_wb16(pb, st->time_base.den / st->time_base.num);
for (i = 0; i < 16; i++)
avio_w8(pb, 0x00); // reserved
diff --git a/libavformat/flac_picture.c b/libavformat/flac_picture.c
index a6b55379f8..669fd2e782 100644
--- a/libavformat/flac_picture.c
+++ b/libavformat/flac_picture.c
@@ -1,23 +1,25 @@
/*
* Raw FLAC picture parser
+ * Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avformat.h"
#include "flac_picture.h"
#include "id3v2.h"
@@ -32,7 +34,8 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
AVIOContext *pb = NULL;
AVStream *st;
int width, height, ret = 0;
- unsigned int type, len;
+ int len;
+ unsigned int type;
pb = avio_alloc_context(buf, buf_size, 0, NULL, NULL, NULL, NULL);
if (!pb)
@@ -43,15 +46,14 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
av_log(s, AV_LOG_ERROR, "Invalid picture type: %d.\n", type);
if (s->error_recognition & AV_EF_EXPLODE) {
- ret = AVERROR_INVALIDDATA;
- goto fail;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
}
type = 0;
}
/* picture mimetype */
len = avio_rb32(pb);
- if (!len || len >= 64 ||
+ if (len <= 0 || len >= 64 ||
avio_read(pb, mimetype, FFMIN(len, sizeof(mimetype) - 1)) != len) {
av_log(s, AV_LOG_ERROR, "Could not read mimetype from an attached "
"picture.\n");
@@ -59,6 +61,7 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
ret = AVERROR_INVALIDDATA;
goto fail;
}
+ av_assert0(len < sizeof(mimetype));
mimetype[len] = 0;
while (mime->id != AV_CODEC_ID_NONE) {
@@ -80,8 +83,7 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
len = avio_rb32(pb);
if (len > 0) {
if (!(desc = av_malloc(len + 1))) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ RETURN_ERROR(AVERROR(ENOMEM));
}
if (avio_read(pb, desc, len) != len) {
@@ -100,16 +102,16 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
/* picture data */
len = avio_rb32(pb);
- if (!len) {
+ if (len <= 0) {
av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len);
if (s->error_recognition & AV_EF_EXPLODE)
ret = AVERROR_INVALIDDATA;
goto fail;
}
- if (!(data = av_buffer_alloc(len))) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ if (!(data = av_buffer_alloc(len + FF_INPUT_BUFFER_PADDING_SIZE))) {
+ RETURN_ERROR(AVERROR(ENOMEM));
}
+ memset(data->data + len, 0, FF_INPUT_BUFFER_PADDING_SIZE);
if (avio_read(pb, data->data, len) != len) {
av_log(s, AV_LOG_ERROR, "Error reading attached picture data.\n");
if (s->error_recognition & AV_EF_EXPLODE)
@@ -119,8 +121,7 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size)
st = avformat_new_stream(s, NULL);
if (!st) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ RETURN_ERROR(AVERROR(ENOMEM));
}
av_init_packet(&st->attached_pic);
diff --git a/libavformat/flac_picture.h b/libavformat/flac_picture.h
index c7005829bc..4374b6f4f6 100644
--- a/libavformat/flac_picture.h
+++ b/libavformat/flac_picture.h
@@ -1,20 +1,21 @@
/*
* Raw FLAC picture parser
+ * Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +24,8 @@
#include "avformat.h"
+#define RETURN_ERROR(code) do { ret = (code); goto fail; } while (0)
+
int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size);
#endif /* AVFORMAT_FLAC_PICTURE_H */
diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c
index 8abdd9d5b4..4207fd2bf6 100644
--- a/libavformat/flacdec.c
+++ b/libavformat/flacdec.c
@@ -2,20 +2,20 @@
* Raw FLAC demuxer
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@ static int flac_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_FLAC;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
/* the parameters will be extracted from the compressed bitstream */
/* if fLaC marker is not found, assume there is no header */
@@ -48,7 +48,7 @@ static int flac_read_header(AVFormatContext *s)
}
/* process metadata blocks */
- while (!s->pb->eof_reached && !metadata_last) {
+ while (!avio_feof(s->pb) && !metadata_last) {
avio_read(s->pb, header, 4);
flac_parse_block_header(header, &metadata_last, &metadata_type,
&metadata_size);
@@ -63,8 +63,7 @@ static int flac_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
}
if (avio_read(s->pb, buffer, metadata_size) != metadata_size) {
- av_freep(&buffer);
- return AVERROR(EIO);
+ RETURN_ERROR(AVERROR(EIO));
}
break;
/* skip metadata block for unsupported types */
@@ -80,12 +79,10 @@ static int flac_read_header(AVFormatContext *s)
/* STREAMINFO can only occur once */
if (found_streaminfo) {
- av_freep(&buffer);
- return AVERROR_INVALIDDATA;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
}
if (metadata_size != FLAC_STREAMINFO_SIZE) {
- av_freep(&buffer);
- return AVERROR_INVALIDDATA;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
}
found_streaminfo = 1;
st->codec->extradata = buffer;
@@ -109,24 +106,25 @@ static int flac_read_header(AVFormatContext *s)
const uint8_t *offset;
int i, chapters, track, ti;
if (metadata_size < 431)
- return AVERROR_INVALIDDATA;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
offset = buffer + 395;
chapters = bytestream_get_byte(&offset) - 1;
if (chapters <= 0)
- return AVERROR_INVALIDDATA;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
for (i = 0; i < chapters; i++) {
if (offset + 36 - buffer > metadata_size)
- return AVERROR_INVALIDDATA;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
start = bytestream_get_be64(&offset);
track = bytestream_get_byte(&offset);
bytestream_get_buffer(&offset, isrc, 12);
isrc[12] = 0;
offset += 14;
ti = bytestream_get_byte(&offset);
- if (ti <= 0) return AVERROR_INVALIDDATA;
+ if (ti <= 0) RETURN_ERROR(AVERROR_INVALIDDATA);
offset += ti * 12;
avpriv_new_chapter(s, track, st->time_base, start, AV_NOPTS_VALUE, isrc);
}
+ av_freep(&buffer);
} else if (metadata_type == FLAC_METADATA_TYPE_PICTURE) {
ret = ff_flac_parse_picture(s, buffer, metadata_size);
av_freep(&buffer);
@@ -137,8 +135,7 @@ static int flac_read_header(AVFormatContext *s)
} else {
/* STREAMINFO must be the first block */
if (!found_streaminfo) {
- av_freep(&buffer);
- return AVERROR_INVALIDDATA;
+ RETURN_ERROR(AVERROR_INVALIDDATA);
}
/* process supported blocks other than STREAMINFO */
if (metadata_type == FLAC_METADATA_TYPE_VORBIS_COMMENT) {
@@ -173,21 +170,92 @@ static int flac_read_header(AVFormatContext *s)
return ret;
return 0;
+
+fail:
+ av_free(buffer);
+ return ret;
+}
+
+static int raw_flac_probe(AVProbeData *p)
+{
+ if ((p->buf[2] & 0xF0) == 0) // blocksize code invalid
+ return 0;
+ if ((p->buf[2] & 0x0F) == 0x0F) // sample rate code invalid
+ return 0;
+ if ((p->buf[3] & 0xF0) >= FLAC_MAX_CHANNELS + FLAC_CHMODE_MID_SIDE << 4)
+ // channel mode invalid
+ return 0;
+ if ((p->buf[3] & 0x06) == 0x06) // bits per sample code invalid
+ return 0;
+ if ((p->buf[3] & 0x01) == 0x01) // reserved bit set
+ return 0;
+ return AVPROBE_SCORE_EXTENSION / 4 + 1;
}
static int flac_probe(AVProbeData *p)
{
+ if ((AV_RB16(p->buf) & 0xFFFE) == 0xFFF8)
+ return raw_flac_probe(p);
if (p->buf_size < 4 || memcmp(p->buf, "fLaC", 4))
return 0;
return AVPROBE_SCORE_EXTENSION;
}
+static av_unused int64_t flac_read_timestamp(AVFormatContext *s, int stream_index,
+ int64_t *ppos, int64_t pos_limit)
+{
+ AVPacket pkt, out_pkt;
+ AVStream *st = s->streams[stream_index];
+ AVCodecParserContext *parser;
+ int ret;
+ int64_t pts = AV_NOPTS_VALUE;
+
+ if (avio_seek(s->pb, *ppos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+
+ av_init_packet(&pkt);
+ parser = av_parser_init(st->codec->codec_id);
+ if (!parser){
+ return AV_NOPTS_VALUE;
+ }
+ parser->flags |= PARSER_FLAG_USE_CODEC_TS;
+
+ for (;;){
+ ret = ff_raw_read_partial_packet(s, &pkt);
+ if (ret < 0){
+ if (ret == AVERROR(EAGAIN))
+ continue;
+ else
+ break;
+ }
+ av_init_packet(&out_pkt);
+ ret = av_parser_parse2(parser, st->codec,
+ &out_pkt.data, &out_pkt.size, pkt.data, pkt.size,
+ pkt.pts, pkt.dts, *ppos);
+
+ av_free_packet(&pkt);
+ if (out_pkt.size){
+ int size = out_pkt.size;
+ if (parser->pts != AV_NOPTS_VALUE){
+ // seeking may not have started from beginning of a frame
+ // calculate frame start position from next frame backwards
+ *ppos = parser->next_frame_offset - size;
+ pts = parser->pts;
+ break;
+ }
+ }
+ }
+ av_parser_close(parser);
+ return pts;
+}
+
AVInputFormat ff_flac_demuxer = {
.name = "flac",
.long_name = NULL_IF_CONFIG_SMALL("raw FLAC"),
.read_probe = flac_probe,
.read_header = flac_read_header,
.read_packet = ff_raw_read_partial_packet,
+ .read_timestamp = flac_read_timestamp,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "flac",
.raw_codec_id = AV_CODEC_ID_FLAC,
diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c
index a686826543..a45f83ec21 100644
--- a/libavformat/flacenc.c
+++ b/libavformat/flacenc.c
@@ -2,20 +2,20 @@
* raw FLAC muxer
* Copyright (c) 2006-2009 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,7 @@
#include "libavutil/opt.h"
#include "libavcodec/flac.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "flacenc.h"
#include "vorbiscomment.h"
#include "libavcodec/bytestream.h"
@@ -41,23 +42,22 @@ static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_byte
{
avio_w8(pb, last_block ? 0x81 : 0x01);
avio_wb24(pb, n_padding_bytes);
- while (n_padding_bytes > 0) {
- avio_w8(pb, 0);
- n_padding_bytes--;
- }
+ ffio_fill(pb, 0, n_padding_bytes);
return 0;
}
static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m,
int last_block, int bitexact)
{
- const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
- unsigned int len;
+ const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
+ int64_t len;
uint8_t *p, *p0;
ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);
len = ff_vorbiscomment_length(*m, vendor);
+ if (len >= ((1<<24) - 4))
+ return AVERROR(EINVAL);
p0 = av_malloc(len+4);
if (!p0)
return AVERROR(ENOMEM);
@@ -77,12 +77,28 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m,
static int flac_write_header(struct AVFormatContext *s)
{
int ret;
+ int padding = s->metadata_header_padding;
AVCodecContext *codec = s->streams[0]->codec;
FlacMuxerContext *c = s->priv_data;
if (!c->write_header)
return 0;
+ if (s->nb_streams > 1) {
+ av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+ if (codec->codec_id != AV_CODEC_ID_FLAC) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (padding < 0)
+ padding = 8192;
+ /* The FLAC specification states that 24 bits are used to represent the
+ * size of a metadata block so we must clip this value to 2^24-1. */
+ padding = av_clip_uintp2(padding, 24);
+
ret = ff_flac_write_header(s->pb, codec->extradata,
codec->extradata_size, 0);
if (ret)
@@ -105,7 +121,7 @@ static int flac_write_header(struct AVFormatContext *s)
}
}
- ret = flac_write_block_comment(s->pb, &s->metadata, 0,
+ ret = flac_write_block_comment(s->pb, &s->metadata, !padding,
s->flags & AVFMT_FLAG_BITEXACT);
if (ret)
return ret;
@@ -113,8 +129,9 @@ static int flac_write_header(struct AVFormatContext *s)
/* The command line flac encoder defaults to placing a seekpoint
* every 10s. So one might add padding to allow that later
* but there seems to be no simple way to get the duration here.
- * So let's try the flac default of 8192 bytes */
- flac_write_block_padding(s->pb, 8192, 1);
+ * So just add the amount requested by the user. */
+ if (padding)
+ flac_write_block_padding(s->pb, padding, 1);
return ret;
}
diff --git a/libavformat/flacenc.h b/libavformat/flacenc.h
index 54dd8333bc..d5d53a5dcb 100644
--- a/libavformat/flacenc.h
+++ b/libavformat/flacenc.h
@@ -2,20 +2,20 @@
* raw FLAC muxer
* Copyright (C) 2009 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/flacenc_header.c b/libavformat/flacenc_header.c
index 4f9bb206e5..61833cc8b9 100644
--- a/libavformat/flacenc_header.c
+++ b/libavformat/flacenc_header.c
@@ -2,20 +2,20 @@
* raw FLAC muxer
* Copyright (C) 2009 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/flic.c b/libavformat/flic.c
index 2eb6f057b4..bef70c188a 100644
--- a/libavformat/flic.c
+++ b/libavformat/flic.c
@@ -1,21 +1,21 @@
/*
* FLI/FLC Animation File Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,7 +80,7 @@ static int flic_probe(AVProbeData *p)
return 0;
- return AVPROBE_SCORE_MAX;
+ return AVPROBE_SCORE_MAX - 1;
}
static int flic_read_header(AVFormatContext *s)
@@ -117,7 +117,7 @@ static int flic_read_header(AVFormatContext *s)
if (!st->codec->width || !st->codec->height) {
/* Ugly hack needed for the following sample: */
- /* http://samples.libav.org/fli-flc/fli-bugs/specular.flc */
+ /* http://samples.mplayerhq.hu/fli-flc/fli-bugs/specular.flc */
av_log(s, AV_LOG_WARNING,
"File with no specified width/height. Trying 640x480.\n");
st->codec->width = 640;
@@ -125,8 +125,8 @@ static int flic_read_header(AVFormatContext *s)
}
/* send over the whole 128-byte FLIC header */
- st->codec->extradata_size = FLIC_HEADER_SIZE;
- st->codec->extradata = av_malloc(FLIC_HEADER_SIZE);
+ if (ff_alloc_extradata(st->codec, FLIC_HEADER_SIZE))
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, header, FLIC_HEADER_SIZE);
/* peek at the preamble to detect TFTD videos - they seem to always start with an audio chunk */
@@ -158,7 +158,6 @@ static int flic_read_header(AVFormatContext *s)
ast->codec->codec_tag = 0;
ast->codec->sample_rate = FLIC_TFTD_SAMPLE_RATE;
ast->codec->channels = 1;
- ast->codec->sample_fmt = AV_SAMPLE_FMT_U8;
ast->codec->bit_rate = st->codec->sample_rate * 8;
ast->codec->bits_per_coded_sample = 8;
ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
@@ -176,9 +175,9 @@ static int flic_read_header(AVFormatContext *s)
avio_seek(pb, 12, SEEK_SET);
/* send over abbreviated FLIC header chunk */
- av_free(st->codec->extradata);
- st->codec->extradata_size = 12;
- st->codec->extradata = av_malloc(12);
+ av_freep(&st->codec->extradata);
+ if (ff_alloc_extradata(st->codec, 12))
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, header, 12);
} else if (magic_number == FLIC_FILE_MAGIC_1) {
@@ -187,7 +186,7 @@ static int flic_read_header(AVFormatContext *s)
(magic_number == FLIC_FILE_MAGIC_3)) {
avpriv_set_pts_info(st, 64, speed, 1000);
} else {
- av_log(s, AV_LOG_INFO, "Invalid or unsupported magic chunk in file\n");
+ av_log(s, AV_LOG_ERROR, "Invalid or unsupported magic chunk in file\n");
return AVERROR_INVALIDDATA;
}
diff --git a/libavformat/flv.h b/libavformat/flv.h
index fe0fc90d83..db9468f469 100644
--- a/libavformat/flv.h
+++ b/libavformat/flv.h
@@ -1,22 +1,22 @@
/*
* FLV common header
*
- * Copyright (c) 2006 The Libav Project
+ * Copyright (c) 2006 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,6 +46,11 @@
#define AMF_END_OF_OBJECT 0x09
+#define KEYFRAMES_TAG "keyframes"
+#define KEYFRAMES_TIMESTAMP_TAG "times"
+#define KEYFRAMES_BYTEOFFSET_TAG "filepositions"
+
+
enum {
FLV_HEADER_FLAG_HASVIDEO = 1,
FLV_HEADER_FLAG_HASAUDIO = 4,
@@ -58,6 +63,13 @@ enum {
};
enum {
+ FLV_STREAM_TYPE_VIDEO,
+ FLV_STREAM_TYPE_AUDIO,
+ FLV_STREAM_TYPE_DATA,
+ FLV_STREAM_TYPE_NB,
+};
+
+enum {
FLV_MONO = 0,
FLV_STEREO = 1,
};
@@ -95,12 +107,16 @@ enum {
FLV_CODECID_VP6A = 5,
FLV_CODECID_SCREEN2 = 6,
FLV_CODECID_H264 = 7,
+ FLV_CODECID_REALH263= 8,
+ FLV_CODECID_MPEG4 = 9,
};
enum {
- FLV_FRAME_KEY = 1 << FLV_VIDEO_FRAMETYPE_OFFSET,
- FLV_FRAME_INTER = 2 << FLV_VIDEO_FRAMETYPE_OFFSET,
- FLV_FRAME_DISP_INTER = 3 << FLV_VIDEO_FRAMETYPE_OFFSET,
+ FLV_FRAME_KEY = 1 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< key frame (for AVC, a seekable frame)
+ FLV_FRAME_INTER = 2 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< inter frame (for AVC, a non-seekable frame)
+ FLV_FRAME_DISP_INTER = 3 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< disposable inter frame (H.263 only)
+ FLV_FRAME_GENERATED_KEY = 4 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< generated key frame (reserved for server use only)
+ FLV_FRAME_VIDEO_INFO_CMD = 5 << FLV_VIDEO_FRAMETYPE_OFFSET, ///< video info/command frame
};
typedef enum {
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index eb31a6e1e2..07f7b681e9 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -1,26 +1,26 @@
/*
* FLV demuxer
- * Copyright (c) 2003 The Libav Project
+ * Copyright (c) 2003 The FFmpeg Project
*
* This demuxer will generate a 1 byte extradata for VP6F content.
* It is composed of:
* - upper 4bits: difference between encoded width and visible width
* - lower 4bits: difference between encoded height and visible height
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,18 +37,14 @@
#include "avio_internal.h"
#include "flv.h"
-#define KEYFRAMES_TAG "keyframes"
-#define KEYFRAMES_TIMESTAMP_TAG "times"
-#define KEYFRAMES_BYTEOFFSET_TAG "filepositions"
-
#define VALIDATE_INDEX_TS_THRESH 2500
typedef struct FLVContext {
const AVClass *class; ///< Class for private options.
int trust_metadata; ///< configure streams according onMetaData
int wrong_dts; ///< wrong dts due to negative cts
- uint8_t *new_extradata[2];
- int new_extradata_size[2];
+ uint8_t *new_extradata[FLV_STREAM_TYPE_NB];
+ int new_extradata_size[FLV_STREAM_TYPE_NB];
int last_sample_rate;
int last_channels;
struct {
@@ -57,29 +53,49 @@ typedef struct FLVContext {
} validate_index[2];
int validate_next;
int validate_count;
+ int searched_for_end;
} FLVContext;
-static int flv_probe(AVProbeData *p)
+static int probe(AVProbeData *p, int live)
{
- const uint8_t *d;
+ const uint8_t *d = p->buf;
+ unsigned offset = AV_RB32(d + 5);
- d = p->buf;
if (d[0] == 'F' &&
d[1] == 'L' &&
d[2] == 'V' &&
d[3] < 5 && d[5] == 0 &&
- AV_RB32(d + 5) > 8) {
- return AVPROBE_SCORE_MAX;
+ offset + 100 < p->buf_size &&
+ offset > 8) {
+ int is_live = !memcmp(d + offset + 40, "NGINX RTMP", 10);
+
+ if (live == is_live)
+ return AVPROBE_SCORE_MAX;
}
return 0;
}
+static int flv_probe(AVProbeData *p)
+{
+ return probe(p, 0);
+}
+
+static int live_flv_probe(AVProbeData *p)
+{
+ return probe(p, 1);
+}
+
static AVStream *create_stream(AVFormatContext *s, int codec_type)
{
AVStream *st = avformat_new_stream(s, NULL);
if (!st)
return NULL;
st->codec->codec_type = codec_type;
+ if (s->nb_streams>=3 ||( s->nb_streams==2
+ && s->streams[0]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE
+ && s->streams[1]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE))
+ s->ctx_flags &= ~AVFMTCTX_NOHEADER;
+
avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */
return st;
}
@@ -189,7 +205,7 @@ static void flv_set_audio_codec(AVFormatContext *s, AVStream *astream,
acodec->codec_id = AV_CODEC_ID_PCM_ALAW;
break;
default:
- av_log(s, AV_LOG_INFO, "Unsupported audio codec (%x)\n",
+ avpriv_request_sample(s, "Audio codec (%x)",
flv_codecid >> FLV_AUDIO_CODECID_OFFSET);
acodec->codec_tag = flv_codecid >> FLV_AUDIO_CODECID_OFFSET;
}
@@ -228,6 +244,9 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
case FLV_CODECID_H263:
vcodec->codec_id = AV_CODEC_ID_FLV1;
break;
+ case FLV_CODECID_REALH263:
+ vcodec->codec_id = AV_CODEC_ID_H263;
+ break; // Really mean it this time
case FLV_CODECID_SCREEN:
vcodec->codec_id = AV_CODEC_ID_FLASHSV;
break;
@@ -241,9 +260,7 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
vcodec->codec_id = AV_CODEC_ID_VP6A;
if (read) {
if (vcodec->extradata_size != 1) {
- vcodec->extradata = av_malloc(1);
- if (vcodec->extradata)
- vcodec->extradata_size = 1;
+ ff_alloc_extradata(vcodec, 1);
}
if (vcodec->extradata)
vcodec->extradata[0] = avio_r8(s->pb);
@@ -253,9 +270,13 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream,
return 1; // 1 byte body size adjustment for flv_read_packet()
case FLV_CODECID_H264:
vcodec->codec_id = AV_CODEC_ID_H264;
+ vstream->need_parsing = AVSTREAM_PARSE_HEADERS;
return 3; // not 4, reading packet type will consume one byte
+ case FLV_CODECID_MPEG4:
+ vcodec->codec_id = AV_CODEC_ID_MPEG4;
+ return 3;
default:
- av_log(s, AV_LOG_INFO, "Unsupported video codec (%x)\n", flv_codecid);
+ avpriv_request_sample(s, "Video codec (%x)", flv_codecid);
vcodec->codec_tag = flv_codecid;
}
@@ -281,56 +302,55 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
AVStream *vstream, int64_t max_pos)
{
FLVContext *flv = s->priv_data;
- unsigned int arraylen = 0, timeslen = 0, fileposlen = 0, i;
- double num_val;
+ unsigned int timeslen = 0, fileposlen = 0, i;
char str_val[256];
int64_t *times = NULL;
int64_t *filepositions = NULL;
int ret = AVERROR(ENOSYS);
int64_t initial_pos = avio_tell(ioc);
+ if (vstream->nb_index_entries>0) {
+ av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n");
+ return 0;
+ }
+
if (s->flags & AVFMT_FLAG_IGNIDX)
return 0;
while (avio_tell(ioc) < max_pos - 2 &&
amf_get_string(ioc, str_val, sizeof(str_val)) > 0) {
- int64_t *current_array;
+ int64_t **current_array;
+ unsigned int arraylen;
// Expect array object in context
if (avio_r8(ioc) != AMF_DATA_TYPE_ARRAY)
break;
arraylen = avio_rb32(ioc);
- if (arraylen >> 28)
+ if (arraylen>>28)
break;
- /* Expect only 'times' or 'filepositions' sub-arrays in other
- * case refuse to use such metadata for indexing. */
- if (!strcmp(KEYFRAMES_TIMESTAMP_TAG, str_val) && !times) {
- if (!(times = av_mallocz(sizeof(*times) * arraylen))) {
- ret = AVERROR(ENOMEM);
- goto finish;
- }
+ if (!strcmp(KEYFRAMES_TIMESTAMP_TAG , str_val) && !times) {
+ current_array = &times;
timeslen = arraylen;
- current_array = times;
} else if (!strcmp(KEYFRAMES_BYTEOFFSET_TAG, str_val) &&
!filepositions) {
- if (!(filepositions = av_mallocz(sizeof(*filepositions) * arraylen))) {
- ret = AVERROR(ENOMEM);
- goto finish;
- }
+ current_array = &filepositions;
fileposlen = arraylen;
- current_array = filepositions;
} else
// unexpected metatag inside keyframes, will not use such
// metadata for indexing
break;
+ if (!(*current_array = av_mallocz(sizeof(**current_array) * arraylen))) {
+ ret = AVERROR(ENOMEM);
+ goto finish;
+ }
+
for (i = 0; i < arraylen && avio_tell(ioc) < max_pos - 1; i++) {
if (avio_r8(ioc) != AMF_DATA_TYPE_NUMBER)
- goto finish;
- num_val = av_int2double(avio_rb64(ioc));
- current_array[i] = num_val;
+ goto invalid;
+ current_array[0][i] = av_int2double(avio_rb64(ioc));
}
if (times && filepositions) {
// All done, exiting at a position allowing amf_parse_object
@@ -340,7 +360,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
}
}
- if (!ret && timeslen == fileposlen) {
+ if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) {
for (i = 0; i < fileposlen; i++) {
av_add_index_entry(vstream, filepositions[i], times[i] * 1000,
0, 0, AVINDEX_KEYFRAME);
@@ -350,16 +370,15 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc,
flv->validate_count = i + 1;
}
}
- } else
+ } else {
+invalid:
av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n");
+ }
finish:
av_freep(&times);
av_freep(&filepositions);
- // If we got unexpected data, but successfully reset back to
- // the start pos, the caller can continue parsing
- if (ret < 0 && avio_seek(ioc, initial_pos, SEEK_SET) > 0)
- return 0;
+ avio_seek(ioc, initial_pos, SEEK_SET);
return ret;
}
@@ -371,7 +390,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
FLVContext *flv = s->priv_data;
AVIOContext *ioc;
AMFDataType amf_type;
- char str_val[256];
+ char str_val[1024];
double num_val;
num_val = 0;
@@ -386,23 +405,28 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
num_val = avio_r8(ioc);
break;
case AMF_DATA_TYPE_STRING:
- if (amf_get_string(ioc, str_val, sizeof(str_val)) < 0)
+ if (amf_get_string(ioc, str_val, sizeof(str_val)) < 0) {
+ av_log(s, AV_LOG_ERROR, "AMF_DATA_TYPE_STRING parsing failed\n");
return -1;
+ }
break;
case AMF_DATA_TYPE_OBJECT:
if ((vstream || astream) && key &&
+ ioc->seekable &&
!strcmp(KEYFRAMES_TAG, key) && depth == 1)
if (parse_keyframes_index(s, ioc, vstream ? vstream : astream,
max_pos) < 0)
- return -1;
+ av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n");
while (avio_tell(ioc) < max_pos - 2 &&
amf_get_string(ioc, str_val, sizeof(str_val)) > 0)
if (amf_parse_object(s, astream, vstream, str_val, max_pos,
depth + 1) < 0)
return -1; // if we couldn't skip, bomb out.
- if (avio_r8(ioc) != AMF_END_OF_OBJECT)
+ if (avio_r8(ioc) != AMF_END_OF_OBJECT) {
+ av_log(s, AV_LOG_ERROR, "Missing AMF_END_OF_OBJECT in AMF_DATA_TYPE_OBJECT\n");
return -1;
+ }
break;
case AMF_DATA_TYPE_NULL:
case AMF_DATA_TYPE_UNDEFINED:
@@ -417,8 +441,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
if (amf_parse_object(s, astream, vstream, str_val, max_pos,
depth + 1) < 0)
return -1;
- if (avio_r8(ioc) != AMF_END_OF_OBJECT)
+ if (avio_r8(ioc) != AMF_END_OF_OBJECT) {
+ av_log(s, AV_LOG_ERROR, "Missing AMF_END_OF_OBJECT in AMF_DATA_TYPE_MIXEDARRAY\n");
return -1;
+ }
break;
case AMF_DATA_TYPE_ARRAY:
{
@@ -435,15 +461,16 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
avio_skip(ioc, 8 + 2); // timestamp (double) and UTC offset (int16)
break;
default: // unsupported type, we couldn't skip
+ av_log(s, AV_LOG_ERROR, "unsupported amf type %d\n", amf_type);
return -1;
}
if (key) {
+ acodec = astream ? astream->codec : NULL;
+ vcodec = vstream ? vstream->codec : NULL;
+
// stream info doesn't live any deeper than the first object
if (depth == 1) {
- acodec = astream ? astream->codec : NULL;
- vcodec = vstream ? vstream->codec : NULL;
-
if (amf_type == AMF_DATA_TYPE_NUMBER ||
amf_type == AMF_DATA_TYPE_BOOL) {
if (!strcmp(key, "duration"))
@@ -455,7 +482,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
0 <= (int)(num_val * 1024.0))
acodec->bit_rate = num_val * 1024.0;
else if (!strcmp(key, "datastream")) {
- AVStream *st = create_stream(s, AVMEDIA_TYPE_DATA);
+ AVStream *st = create_stream(s, AVMEDIA_TYPE_SUBTITLE);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_TEXT;
@@ -483,6 +510,11 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
}
}
+ if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
+ ((!acodec && !strcmp(key, "audiocodecid")) ||
+ (!vcodec && !strcmp(key, "videocodecid"))))
+ s->ctx_flags &= ~AVFMTCTX_NOHEADER; //If there is either audio/video missing, codecid will be an empty object
+
if (!strcmp(key, "duration") ||
!strcmp(key, "filesize") ||
!strcmp(key, "width") ||
@@ -513,10 +545,15 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
return 0;
}
+#define TYPE_ONTEXTDATA 1
+#define TYPE_ONCAPTION 2
+#define TYPE_UNKNOWN 9
+
static int flv_read_metabody(AVFormatContext *s, int64_t next_pos)
{
AMFDataType type;
AVStream *stream, *astream, *vstream;
+ AVStream av_unused *dstream;
AVIOContext *ioc;
int i;
// only needs to hold the string "onMetaData".
@@ -525,28 +562,34 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos)
astream = NULL;
vstream = NULL;
+ dstream = NULL;
ioc = s->pb;
// first object needs to be "onMetaData" string
type = avio_r8(ioc);
if (type != AMF_DATA_TYPE_STRING ||
amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
- return -1;
+ return TYPE_UNKNOWN;
if (!strcmp(buffer, "onTextData"))
- return 1;
+ return TYPE_ONTEXTDATA;
+
+ if (!strcmp(buffer, "onCaption"))
+ return TYPE_ONCAPTION;
if (strcmp(buffer, "onMetaData") && strcmp(buffer, "onCuePoint"))
- return -1;
+ return TYPE_UNKNOWN;
// find the streams now so that amf_parse_object doesn't need to do
// the lookup every time it is called.
for (i = 0; i < s->nb_streams; i++) {
stream = s->streams[i];
- if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- astream = stream;
- else if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
vstream = stream;
+ else if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ astream = stream;
+ else if (stream->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ dstream = stream;
}
// parse the second object (we want a mixed array)
@@ -571,6 +614,8 @@ static int flv_read_header(AVFormatContext *s)
if (flags & FLV_HEADER_FLAG_HASAUDIO)
if (!create_stream(s, AVMEDIA_TYPE_AUDIO))
return AVERROR(ENOMEM);
+ // Flag doesn't indicate whether or not there is script-data present. Must
+ // create that stream if it's encountered.
offset = avio_rb32(s->pb);
avio_seek(s->pb, offset, SEEK_SET);
@@ -583,20 +628,18 @@ static int flv_read_header(AVFormatContext *s)
static int flv_read_close(AVFormatContext *s)
{
+ int i;
FLVContext *flv = s->priv_data;
- av_freep(&flv->new_extradata[0]);
- av_freep(&flv->new_extradata[1]);
+ for (i=0; i<FLV_STREAM_TYPE_NB; i++)
+ av_freep(&flv->new_extradata[i]);
return 0;
}
static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size)
{
- av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ av_freep(&st->codec->extradata);
+ if (ff_get_extradata(st->codec, s->pb, size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = size;
- avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
return 0;
}
@@ -678,8 +721,11 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
char buf[20];
int ret = AVERROR_INVALIDDATA;
int i, length = -1;
+ int array = 0;
switch (avio_r8(pb)) {
+ case AMF_DATA_TYPE_ARRAY:
+ array = 1;
case AMF_DATA_TYPE_MIXEDARRAY:
avio_seek(pb, 4, SEEK_CUR);
case AMF_DATA_TYPE_OBJECT:
@@ -688,9 +734,9 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
goto skip;
}
- while ((ret = amf_get_string(pb, buf, sizeof(buf))) > 0) {
+ while (array || (ret = amf_get_string(pb, buf, sizeof(buf))) > 0) {
AMFDataType type = avio_r8(pb);
- if (type == AMF_DATA_TYPE_STRING && !strcmp(buf, "text")) {
+ if (type == AMF_DATA_TYPE_STRING && (array || !strcmp(buf, "text"))) {
length = avio_rb16(pb);
ret = av_get_packet(pb, pkt, length);
if (ret < 0)
@@ -710,12 +756,12 @@ static int flv_data_packet(AVFormatContext *s, AVPacket *pkt,
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
- if (st->codec->codec_type == AVMEDIA_TYPE_DATA)
+ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
break;
}
if (i == s->nb_streams) {
- st = create_stream(s, AVMEDIA_TYPE_DATA);
+ st = create_stream(s, AVMEDIA_TYPE_SUBTITLE);
if (!st)
return AVERROR(ENOMEM);
st->codec->codec_id = AV_CODEC_ID_TEXT;
@@ -737,21 +783,23 @@ skip:
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
- int ret, i, type, size, flags, is_audio;
- int64_t next, pos;
+ int ret, i, type, size, flags;
+ int stream_type=-1;
+ int64_t next, pos, meta_pos;
int64_t dts, pts = AV_NOPTS_VALUE;
- int sample_rate = 0, channels = 0;
+ int av_uninit(channels);
+ int av_uninit(sample_rate);
AVStream *st = NULL;
/* pkt size is repeated at end. skip it */
for (;; avio_skip(s->pb, 4)) {
pos = avio_tell(s->pb);
- type = avio_r8(s->pb);
+ type = (avio_r8(s->pb) & 0x1F);
size = avio_rb24(s->pb);
dts = avio_rb24(s->pb);
dts |= avio_r8(s->pb) << 24;
- av_log(s, AV_LOG_TRACE, "type:%d, size:%d, dts:%"PRId64"\n", type, size, dts);
- if (s->pb->eof_reached)
+ av_log(s, AV_LOG_TRACE, "type:%d, size:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, dts, avio_tell(s->pb));
+ if (avio_feof(s->pb))
return AVERROR_EOF;
avio_skip(s->pb, 3); /* stream id, always 0 */
flags = 0;
@@ -778,24 +826,35 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
next = size + avio_tell(s->pb);
if (type == FLV_TAG_TYPE_AUDIO) {
- is_audio = 1;
+ stream_type = FLV_STREAM_TYPE_AUDIO;
flags = avio_r8(s->pb);
size--;
} else if (type == FLV_TAG_TYPE_VIDEO) {
- is_audio = 0;
+ stream_type = FLV_STREAM_TYPE_VIDEO;
flags = avio_r8(s->pb);
size--;
- if ((flags & 0xf0) == 0x50) /* video info / command frame */
+ if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
goto skip;
- } else {
- if (type == FLV_TAG_TYPE_META && size > 13 + 1 + 4)
- if (flv_read_metabody(s, next) > 0) {
+ } else if (type == FLV_TAG_TYPE_META) {
+ stream_type=FLV_STREAM_TYPE_DATA;
+ if (size > 13 + 1 + 4) { // Header-type metadata stuff
+ int type;
+ meta_pos = avio_tell(s->pb);
+ type = flv_read_metabody(s, next);
+ if (type == 0 && dts == 0 || type < 0) {
+ goto skip;
+ } else if (type == TYPE_ONTEXTDATA) {
+ avpriv_request_sample(s, "OnTextData packet");
return flv_data_packet(s, pkt, dts, next);
- } else /* skip packet */
- av_log(s, AV_LOG_DEBUG,
- "Skipping flv packet: type %d, size %d, flags %d.\n",
- type, size, flags);
-
+ } else if (type == TYPE_ONCAPTION) {
+ return flv_data_packet(s, pkt, dts, next);
+ }
+ avio_seek(s->pb, meta_pos, SEEK_SET);
+ }
+ } else {
+ av_log(s, AV_LOG_DEBUG,
+ "Skipping flv packet: type %d, size %d, flags %d.\n",
+ type, size, flags);
skip:
avio_seek(s->pb, next, SEEK_SET);
continue;
@@ -808,32 +867,37 @@ skip:
/* now find stream */
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
- if (is_audio && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- if (flv_same_audio_codec(st->codec, flags))
+ if (stream_type == FLV_STREAM_TYPE_AUDIO) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ (s->audio_codec_id || flv_same_audio_codec(st->codec, flags)))
+ break;
+ } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ (s->video_codec_id || flv_same_video_codec(st->codec, flags)))
break;
- } else if (!is_audio &&
- st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (flv_same_video_codec(st->codec, flags))
+ } else if (stream_type == FLV_STREAM_TYPE_DATA) {
+ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
break;
}
}
if (i == s->nb_streams) {
- st = create_stream(s, is_audio ? AVMEDIA_TYPE_AUDIO
- : AVMEDIA_TYPE_VIDEO);
+ static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE};
+ av_log(s, AV_LOG_WARNING, "Stream discovered after head already parsed\n");
+ st = create_stream(s, stream_types[stream_type]);
if (!st)
return AVERROR(ENOMEM);
+
}
- av_log(s, AV_LOG_TRACE, "%d %X %d \n", is_audio, flags, st->discard);
+ av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard);
if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ||
- is_audio)
+ stream_type == FLV_STREAM_TYPE_AUDIO)
av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);
- if ((st->discard >= AVDISCARD_NONKEY &&
- !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || is_audio)) ||
- (st->discard >= AVDISCARD_BIDIR &&
- ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && !is_audio)) ||
- st->discard >= AVDISCARD_ALL) {
+ if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO)))
+ ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO)))
+ || st->discard >= AVDISCARD_ALL
+ ) {
avio_seek(s->pb, next, SEEK_SET);
continue;
}
@@ -842,12 +906,13 @@ skip:
// if not streamed and no duration from metadata then seek to end to find
// the duration from the timestamps
- if (s->pb->seekable && (!s->duration || s->duration == AV_NOPTS_VALUE)) {
+ if (s->pb->seekable && (!s->duration || s->duration == AV_NOPTS_VALUE) && !flv->searched_for_end) {
int size;
const int64_t pos = avio_tell(s->pb);
// Read the last 4 bytes of the file, this should be the size of the
// previous FLV tag. Use the timestamp of its payload as duration.
- const int64_t fsize = avio_size(s->pb);
+ int64_t fsize = avio_size(s->pb);
+retry_duration:
avio_seek(s->pb, fsize - 4, SEEK_SET);
size = avio_rb32(s->pb);
// Seek to the start of the last FLV tag at position (fsize - 4 - size)
@@ -856,12 +921,19 @@ skip:
if (size == avio_rb24(s->pb) + 11) {
uint32_t ts = avio_rb24(s->pb);
ts |= avio_r8(s->pb) << 24;
- s->duration = ts * (int64_t)AV_TIME_BASE / 1000;
+ if (ts)
+ s->duration = ts * (int64_t)AV_TIME_BASE / 1000;
+ else if (fsize >= 8 && fsize - 8 >= size) {
+ fsize -= size+4;
+ goto retry_duration;
+ }
}
+
avio_seek(s->pb, pos, SEEK_SET);
+ flv->searched_for_end = 1;
}
- if (is_audio) {
+ if (stream_type == FLV_STREAM_TYPE_AUDIO) {
int bits_per_coded_sample;
channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;
sample_rate = 44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >>
@@ -884,49 +956,61 @@ skip:
flv->last_channels =
channels = st->codec->channels;
} else {
- AVCodecContext ctx;
+ AVCodecContext ctx = {0};
ctx.sample_rate = sample_rate;
ctx.bits_per_coded_sample = bits_per_coded_sample;
flv_set_audio_codec(s, st, &ctx, flags & FLV_AUDIO_CODECID_MASK);
sample_rate = ctx.sample_rate;
}
- } else {
+ } else if (stream_type == FLV_STREAM_TYPE_VIDEO) {
size -= flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK, 1);
+ } else if (stream_type == FLV_STREAM_TYPE_DATA) {
+ st->codec->codec_id = AV_CODEC_ID_TEXT;
}
if (st->codec->codec_id == AV_CODEC_ID_AAC ||
- st->codec->codec_id == AV_CODEC_ID_H264) {
+ st->codec->codec_id == AV_CODEC_ID_H264 ||
+ st->codec->codec_id == AV_CODEC_ID_MPEG4) {
int type = avio_r8(s->pb);
size--;
- if (st->codec->codec_id == AV_CODEC_ID_H264) {
+ if (st->codec->codec_id == AV_CODEC_ID_H264 || st->codec->codec_id == AV_CODEC_ID_MPEG4) {
// sign extension
int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000;
pts = dts + cts;
- if (cts < 0 && !flv->wrong_dts) { // dts might be wrong
+ if (cts < 0) { // dts might be wrong
+ if (!flv->wrong_dts)
+ av_log(s, AV_LOG_WARNING,
+ "Negative cts, previous timestamps might be wrong.\n");
flv->wrong_dts = 1;
+ } else if (FFABS(dts - pts) > 1000*60*15) {
av_log(s, AV_LOG_WARNING,
- "Negative cts, previous timestamps might be wrong.\n");
+ "invalid timestamps %"PRId64" %"PRId64"\n", dts, pts);
+ dts = pts = AV_NOPTS_VALUE;
}
}
- if (type == 0) {
+ if (type == 0 && (!st->codec->extradata || st->codec->codec_id == AV_CODEC_ID_AAC ||
+ st->codec->codec_id == AV_CODEC_ID_H264)) {
+ AVDictionaryEntry *t;
+
if (st->codec->extradata) {
- if ((ret = flv_queue_extradata(flv, s->pb, is_audio, size)) < 0)
+ if ((ret = flv_queue_extradata(flv, s->pb, stream_type, size)) < 0)
return ret;
ret = AVERROR(EAGAIN);
goto leave;
}
if ((ret = flv_get_extradata(s, st, size)) < 0)
return ret;
- if (st->codec->codec_id == AV_CODEC_ID_AAC) {
- MPEG4AudioConfig cfg;
- /* Workaround for buggy Omnia A/XE encoder */
- AVDictionaryEntry *t = av_dict_get(s->metadata, "Encoder", NULL, 0);
- if (t && !strcmp(t->value, "Omnia A/XE"))
- st->codec->extradata_size = 2;
+ /* Workaround for buggy Omnia A/XE encoder */
+ t = av_dict_get(s->metadata, "Encoder", NULL, 0);
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && t && !strcmp(t->value, "Omnia A/XE"))
+ st->codec->extradata_size = 2;
+
+ if (st->codec->codec_id == AV_CODEC_ID_AAC && 0) {
+ MPEG4AudioConfig cfg;
- avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
- st->codec->extradata_size * 8, 1);
+ if (avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
+ st->codec->extradata_size * 8, 1) >= 0) {
st->codec->channels = cfg.channels;
st->codec->channel_layout = 0;
if (cfg.ext_sample_rate)
@@ -935,6 +1019,7 @@ skip:
st->codec->sample_rate = cfg.sample_rate;
av_log(s, AV_LOG_TRACE, "mp4a config channels %d sample rate %d\n",
st->codec->channels, st->codec->sample_rate);
+ }
}
ret = AVERROR(EAGAIN);
@@ -950,31 +1035,31 @@ skip:
ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
- return AVERROR(EIO);
- /* note: we need to modify the packet size here to handle the last
- * packet */
- pkt->size = ret;
+ return ret;
pkt->dts = dts;
pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
pkt->stream_index = st->index;
- if (flv->new_extradata[is_audio]) {
+ if (flv->new_extradata[stream_type]) {
uint8_t *side = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
- flv->new_extradata_size[is_audio]);
+ flv->new_extradata_size[stream_type]);
if (side) {
- memcpy(side, flv->new_extradata[is_audio],
- flv->new_extradata_size[is_audio]);
- av_freep(&flv->new_extradata[is_audio]);
- flv->new_extradata_size[is_audio] = 0;
+ memcpy(side, flv->new_extradata[stream_type],
+ flv->new_extradata_size[stream_type]);
+ av_freep(&flv->new_extradata[stream_type]);
+ flv->new_extradata_size[stream_type] = 0;
}
}
- if (is_audio && (sample_rate != flv->last_sample_rate ||
+ if (stream_type == FLV_STREAM_TYPE_AUDIO &&
+ (sample_rate != flv->last_sample_rate ||
channels != flv->last_channels)) {
flv->last_sample_rate = sample_rate;
flv->last_channels = channels;
ff_add_param_change(pkt, channels, 0, sample_rate, 0, 0);
}
- if (is_audio || ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY))
+ if ( stream_type == FLV_STREAM_TYPE_AUDIO ||
+ ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) ||
+ stream_type == FLV_STREAM_TYPE_DATA)
pkt->flags |= AV_PKT_FLAG_KEY;
leave:
@@ -997,7 +1082,7 @@ static const AVOption options[] = {
{ NULL }
};
-static const AVClass class = {
+static const AVClass flv_class = {
.class_name = "flvdec",
.item_name = av_default_item_name,
.option = options,
@@ -1014,5 +1099,26 @@ AVInputFormat ff_flv_demuxer = {
.read_seek = flv_read_seek,
.read_close = flv_read_close,
.extensions = "flv",
- .priv_class = &class,
+ .priv_class = &flv_class,
+};
+
+static const AVClass live_flv_class = {
+ .class_name = "live_flvdec",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_live_flv_demuxer = {
+ .name = "live_flv",
+ .long_name = NULL_IF_CONFIG_SMALL("live RTMP FLV (Flash Video)"),
+ .priv_data_size = sizeof(FLVContext),
+ .read_probe = live_flv_probe,
+ .read_header = flv_read_header,
+ .read_packet = flv_read_packet,
+ .read_seek = flv_read_seek,
+ .read_close = flv_read_close,
+ .extensions = "flv",
+ .priv_class = &live_flv_class,
+ .flags = AVFMT_TS_DISCONT
};
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index 49c52357e2..e4717ca5d2 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -1,40 +1,43 @@
/*
* FLV muxer
- * Copyright (c) 2003 The Libav Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/dict.h"
#include "libavutil/intfloat.h"
+#include "libavutil/avassert.h"
#include "avc.h"
#include "avformat.h"
#include "flv.h"
#include "internal.h"
#include "metadata.h"
-#undef NDEBUG
-#include <assert.h>
static const AVCodecTag flv_video_codec_ids[] = {
{ AV_CODEC_ID_FLV1, FLV_CODECID_H263 },
+ { AV_CODEC_ID_H263, FLV_CODECID_REALH263 },
+ { AV_CODEC_ID_MPEG4, FLV_CODECID_MPEG4 },
{ AV_CODEC_ID_FLASHSV, FLV_CODECID_SCREEN },
{ AV_CODEC_ID_FLASHSV2, FLV_CODECID_SCREEN2 },
{ AV_CODEC_ID_VP6F, FLV_CODECID_VP6 },
+ { AV_CODEC_ID_VP6, FLV_CODECID_VP6 },
{ AV_CODEC_ID_VP6A, FLV_CODECID_VP6A },
{ AV_CODEC_ID_H264, FLV_CODECID_H264 },
{ AV_CODEC_ID_NONE, 0 }
@@ -82,12 +85,12 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
else if (enc->codec_id == AV_CODEC_ID_SPEEX) {
if (enc->sample_rate != 16000) {
av_log(s, AV_LOG_ERROR,
- "flv only supports wideband (16kHz) Speex audio\n");
- return -1;
+ "FLV only supports wideband (16kHz) Speex audio\n");
+ return AVERROR(EINVAL);
}
if (enc->channels != 1) {
- av_log(s, AV_LOG_ERROR, "flv only supports mono Speex audio\n");
- return -1;
+ av_log(s, AV_LOG_ERROR, "FLV only supports mono Speex audio\n");
+ return AVERROR(EINVAL);
}
return FLV_CODECID_SPEEX | FLV_SAMPLERATE_11025HZ | FLV_SAMPLESSIZE_16BIT;
} else {
@@ -110,9 +113,9 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
}
default:
av_log(s, AV_LOG_ERROR,
- "flv does not support that sample rate, "
- "choose from (44100, 22050, 11025).\n");
- return -1;
+ "FLV does not support sample rate %d, "
+ "choose from (44100, 22050, 11025)\n", enc->sample_rate);
+ return AVERROR(EINVAL);
}
}
@@ -153,8 +156,9 @@ static int get_audio_flags(AVFormatContext *s, AVCodecContext *enc)
flags |= enc->codec_tag << 4;
break;
default:
- av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
- return -1;
+ av_log(s, AV_LOG_ERROR, "Audio codec '%s' not compatible with FLV\n",
+ avcodec_get_name(enc->codec_id));
+ return AVERROR(EINVAL);
}
return flags;
@@ -272,6 +276,30 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
}
while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+ if( !strcmp(tag->key, "width")
+ ||!strcmp(tag->key, "height")
+ ||!strcmp(tag->key, "videodatarate")
+ ||!strcmp(tag->key, "framerate")
+ ||!strcmp(tag->key, "videocodecid")
+ ||!strcmp(tag->key, "audiodatarate")
+ ||!strcmp(tag->key, "audiosamplerate")
+ ||!strcmp(tag->key, "audiosamplesize")
+ ||!strcmp(tag->key, "stereo")
+ ||!strcmp(tag->key, "audiocodecid")
+ ||!strcmp(tag->key, "duration")
+ ||!strcmp(tag->key, "onMetaData")
+ ||!strcmp(tag->key, "datasize")
+ ||!strcmp(tag->key, "lasttimestamp")
+ ||!strcmp(tag->key, "totalframes")
+ ||!strcmp(tag->key, "hasAudio")
+ ||!strcmp(tag->key, "hasVideo")
+ ||!strcmp(tag->key, "hasCuePoints")
+ ||!strcmp(tag->key, "hasMetadata")
+ ||!strcmp(tag->key, "hasKeyframes")
+ ){
+ av_log(s, AV_LOG_DEBUG, "Ignoring metadata for %s\n", tag->key);
+ continue;
+ }
put_amf_string(pb, tag->key);
avio_w8(pb, AMF_DATA_TYPE_STRING);
put_amf_string(pb, tag->value);
@@ -332,6 +360,22 @@ static int flv_write_header(AVFormatContext *s)
flv->video_enc = enc;
if (!ff_codec_get_tag(flv_video_codec_ids, enc->codec_id))
return unsupported_codec(s, "Video", enc->codec_id);
+
+ if (enc->codec_id == AV_CODEC_ID_MPEG4 ||
+ enc->codec_id == AV_CODEC_ID_H263) {
+ int error = s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL;
+ av_log(s, error ? AV_LOG_ERROR : AV_LOG_WARNING,
+ "Codec %s is not supported in the official FLV specification,\n", avcodec_get_name(enc->codec_id));
+
+ if (error) {
+ av_log(s, AV_LOG_ERROR,
+ "use vstrict=-1 / -strict -1 to use it anyway.\n");
+ return AVERROR(EINVAL);
+ }
+ } else if (enc->codec_id == AV_CODEC_ID_VP6) {
+ av_log(s, AV_LOG_WARNING,
+ "Muxing VP6 in flv will produce flipped video on playback.\n");
+ }
break;
case AVMEDIA_TYPE_AUDIO:
if (flv->audio_enc) {
@@ -342,15 +386,27 @@ static int flv_write_header(AVFormatContext *s)
flv->audio_enc = enc;
if (get_audio_flags(s, enc) < 0)
return unsupported_codec(s, "Audio", enc->codec_id);
+ if (enc->codec_id == AV_CODEC_ID_PCM_S16BE)
+ av_log(s, AV_LOG_WARNING,
+ "16-bit big-endian audio in flv is valid but most likely unplayable (hardware dependent); use s16le\n");
break;
case AVMEDIA_TYPE_DATA:
- if (enc->codec_id != AV_CODEC_ID_TEXT)
+ if (enc->codec_id != AV_CODEC_ID_TEXT && enc->codec_id != AV_CODEC_ID_NONE)
return unsupported_codec(s, "Data", enc->codec_id);
flv->data_enc = enc;
break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (enc->codec_id != AV_CODEC_ID_TEXT) {
+ av_log(s, AV_LOG_ERROR, "Subtitle codec '%s' for stream %d is not compatible with FLV\n",
+ avcodec_get_name(enc->codec_id), i);
+ return AVERROR_INVALIDDATA;
+ }
+ flv->data_enc = enc;
+ break;
default:
- av_log(s, AV_LOG_ERROR, "codec not compatible with flv\n");
- return -1;
+ av_log(s, AV_LOG_ERROR, "Codec type '%s' for stream %d is not compatible with FLV\n",
+ av_get_media_type_string(enc->codec_type), i);
+ return AVERROR(EINVAL);
}
avpriv_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */
@@ -384,7 +440,7 @@ static int flv_write_header(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVCodecContext *enc = s->streams[i]->codec;
- if (enc->codec_id == AV_CODEC_ID_AAC || enc->codec_id == AV_CODEC_ID_H264) {
+ if (enc->codec_id == AV_CODEC_ID_AAC || enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) {
int64_t pos;
avio_w8(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ?
FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO);
@@ -427,7 +483,7 @@ static int flv_write_trailer(AVFormatContext *s)
AVCodecContext *enc = s->streams[i]->codec;
FLVStreamContext *sc = s->streams[i]->priv_data;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO &&
- enc->codec_id == AV_CODEC_ID_H264)
+ (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4))
put_avc_eos_tag(pb, sc->last_ts);
}
@@ -456,12 +512,12 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
unsigned ts;
int size = pkt->size;
uint8_t *data = NULL;
- int flags = 0, flags_size;
+ int flags = -1, flags_size, ret;
if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A ||
- enc->codec_id == AV_CODEC_ID_AAC)
+ enc->codec_id == AV_CODEC_ID_VP6 || enc->codec_id == AV_CODEC_ID_AAC)
flags_size = 2;
- else if (enc->codec_id == AV_CODEC_ID_H264)
+ else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4)
flags_size = 5;
else
flags_size = 1;
@@ -493,10 +549,11 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
case AVMEDIA_TYPE_AUDIO:
flags = get_audio_flags(s, enc);
- assert(size);
+ av_assert0(size);
avio_w8(pb, FLV_TAG_TYPE_AUDIO);
break;
+ case AVMEDIA_TYPE_SUBTITLE:
case AVMEDIA_TYPE_DATA:
avio_w8(pb, FLV_TAG_TYPE_META);
break;
@@ -504,11 +561,21 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(EINVAL);
}
- if (enc->codec_id == AV_CODEC_ID_H264)
- /* check if extradata looks like MP4 */
+ if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) {
+ /* check if extradata looks like mp4 formated */
if (enc->extradata_size > 0 && *(uint8_t*)enc->extradata != 1)
- if (ff_avc_parse_nal_units_buf(pkt->data, &data, &size) < 0)
- return -1;
+ if ((ret = ff_avc_parse_nal_units_buf(pkt->data, &data, &size)) < 0)
+ return ret;
+ } else if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
+ (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
+ if (!s->streams[pkt->stream_index]->nb_frames) {
+ av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
+ "use the audio bitstream filter 'aac_adtstoasc' to fix it "
+ "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
+ return AVERROR_INVALIDDATA;
+ }
+ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
+ }
/* check Speex packet duration */
if (enc->codec_id == AV_CODEC_ID_SPEEX && ts - sc->last_ts > 160)
@@ -519,26 +586,39 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
if (sc->last_ts < ts)
sc->last_ts = ts;
+ if (size + flags_size >= 1<<24) {
+ av_log(s, AV_LOG_ERROR, "Too large packet with size %u >= %u\n",
+ size + flags_size, 1<<24);
+ return AVERROR(EINVAL);
+ }
+
avio_wb24(pb, size + flags_size);
- avio_wb24(pb, ts);
+ avio_wb24(pb, ts & 0xFFFFFF);
avio_w8(pb, (ts >> 24) & 0x7F); // timestamps are 32 bits _signed_
avio_wb24(pb, flv->reserved);
- if (enc->codec_type == AVMEDIA_TYPE_DATA) {
+ if (enc->codec_type == AVMEDIA_TYPE_DATA ||
+ enc->codec_type == AVMEDIA_TYPE_SUBTITLE ) {
int data_size;
int64_t metadata_size_pos = avio_tell(pb);
- avio_w8(pb, AMF_DATA_TYPE_STRING);
- put_amf_string(pb, "onTextData");
- avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
- avio_wb32(pb, 2);
- put_amf_string(pb, "type");
- avio_w8(pb, AMF_DATA_TYPE_STRING);
- put_amf_string(pb, "Text");
- put_amf_string(pb, "text");
- avio_w8(pb, AMF_DATA_TYPE_STRING);
- put_amf_string(pb, pkt->data);
- put_amf_string(pb, "");
- avio_w8(pb, AMF_END_OF_OBJECT);
+ if (enc->codec_id == AV_CODEC_ID_TEXT) {
+ // legacy FFmpeg magic?
+ avio_w8(pb, AMF_DATA_TYPE_STRING);
+ put_amf_string(pb, "onTextData");
+ avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
+ avio_wb32(pb, 2);
+ put_amf_string(pb, "type");
+ avio_w8(pb, AMF_DATA_TYPE_STRING);
+ put_amf_string(pb, "Text");
+ put_amf_string(pb, "text");
+ avio_w8(pb, AMF_DATA_TYPE_STRING);
+ put_amf_string(pb, pkt->data);
+ put_amf_string(pb, "");
+ avio_w8(pb, AMF_END_OF_OBJECT);
+ } else {
+ // just pass the metadata through
+ avio_write(pb, data ? data : pkt->data, size);
+ }
/* write total size of tag */
data_size = avio_tell(pb) - metadata_size_pos;
avio_seek(pb, metadata_size_pos - 10, SEEK_SET);
@@ -546,7 +626,10 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
avio_seek(pb, data_size + 10 - 3, SEEK_CUR);
avio_wb32(pb, data_size + 11);
} else {
+ av_assert1(flags>=0);
avio_w8(pb,flags);
+ if (enc->codec_id == AV_CODEC_ID_VP6)
+ avio_w8(pb,0);
if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_VP6A) {
if (enc->extradata_size)
avio_w8(pb, enc->extradata[0]);
@@ -555,7 +638,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
(FFALIGN(enc->height, 16) - enc->height));
} else if (enc->codec_id == AV_CODEC_ID_AAC)
avio_w8(pb, 1); // AAC raw
- else if (enc->codec_id == AV_CODEC_ID_H264) {
+ else if (enc->codec_id == AV_CODEC_ID_H264 || enc->codec_id == AV_CODEC_ID_MPEG4) {
avio_w8(pb, 1); // AVC NALU
avio_wb24(pb, pkt->pts - pkt->dts);
}
diff --git a/libavformat/format.c b/libavformat/format.c
index 24b7205d44..7df06b70fc 100644
--- a/libavformat/format.c
+++ b/libavformat/format.c
@@ -2,24 +2,26 @@
* Format register and lookup
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/atomic.h"
#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
#include "libavutil/opt.h"
#include "avio_internal.h"
@@ -27,6 +29,7 @@
#include "id3v2.h"
#include "internal.h"
+
/**
* @file
* Format register and lookup
@@ -36,6 +39,9 @@ static AVInputFormat *first_iformat = NULL;
/** head of registered output format linked list */
static AVOutputFormat *first_oformat = NULL;
+static AVInputFormat **last_iformat = &first_iformat;
+static AVOutputFormat **last_oformat = &first_oformat;
+
AVInputFormat *av_iformat_next(const AVInputFormat *f)
{
if (f)
@@ -54,50 +60,34 @@ AVOutputFormat *av_oformat_next(const AVOutputFormat *f)
void av_register_input_format(AVInputFormat *format)
{
- AVInputFormat **p = &first_iformat;
-
- while (*p)
- p = &(*p)->next;
+ AVInputFormat **p = last_iformat;
- *p = format;
format->next = NULL;
+ while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
+ p = &(*p)->next;
+ last_iformat = &format->next;
}
void av_register_output_format(AVOutputFormat *format)
{
- AVOutputFormat **p = &first_oformat;
-
- while (*p)
- p = &(*p)->next;
+ AVOutputFormat **p = last_oformat;
- *p = format;
format->next = NULL;
+ while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format))
+ p = &(*p)->next;
+ last_oformat = &format->next;
}
int av_match_ext(const char *filename, const char *extensions)
{
- const char *ext, *p;
- char ext1[32], *q;
+ const char *ext;
if (!filename)
return 0;
ext = strrchr(filename, '.');
- if (ext) {
- ext++;
- p = extensions;
- for (;;) {
- q = ext1;
- while (*p != '\0' && *p != ',' && q - ext1 < sizeof(ext1) - 1)
- *q++ = *p++;
- *q = '\0';
- if (!av_strcasecmp(ext1, ext))
- return 1;
- if (*p == '\0')
- break;
- p++;
- }
- }
+ if (ext)
+ return av_match_name(ext + 1, extensions);
return 0;
}
@@ -120,7 +110,7 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
score_max = 0;
while ((fmt = av_oformat_next(fmt))) {
score = 0;
- if (fmt->name && short_name && !av_strcasecmp(fmt->name, short_name))
+ if (fmt->name && short_name && av_match_name(short_name, fmt->name))
score += 100;
if (fmt->mime_type && mime_type && !strcmp(fmt->mime_type, mime_type))
score += 10;
@@ -140,6 +130,12 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
const char *filename, const char *mime_type,
enum AVMediaType type)
{
+ if (av_match_name("segment", fmt->name) || av_match_name("ssegment", fmt->name)) {
+ AVOutputFormat *fmt2 = av_guess_format(NULL, filename, NULL);
+ if (fmt2)
+ fmt = fmt2;
+ }
+
if (type == AVMEDIA_TYPE_VIDEO) {
enum AVCodecID codec_id = AV_CODEC_ID_NONE;
@@ -155,6 +151,8 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
return fmt->audio_codec;
else if (type == AVMEDIA_TYPE_SUBTITLE)
return fmt->subtitle_codec;
+ else if (type == AVMEDIA_TYPE_DATA)
+ return fmt->data_codec;
else
return AV_CODEC_ID_NONE;
}
@@ -168,108 +166,123 @@ AVInputFormat *av_find_input_format(const char *short_name)
return NULL;
}
-AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened,
- int *score_max)
+AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened,
+ int *score_ret)
{
AVProbeData lpd = *pd;
AVInputFormat *fmt1 = NULL, *fmt;
- int score, id3 = 0;
+ int score, nodat = 0, score_max = 0;
+ const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
+
+ if (!lpd.buf)
+ lpd.buf = zerobuffer;
if (lpd.buf_size > 10 && ff_id3v2_match(lpd.buf, ID3v2_DEFAULT_MAGIC)) {
int id3len = ff_id3v2_tag_len(lpd.buf);
if (lpd.buf_size > id3len + 16) {
lpd.buf += id3len;
lpd.buf_size -= id3len;
- }
- id3 = 1;
+ } else if (id3len >= PROBE_BUF_MAX) {
+ nodat = 2;
+ } else
+ nodat = 1;
}
fmt = NULL;
while ((fmt1 = av_iformat_next(fmt1))) {
- if (!is_opened == !(fmt1->flags & AVFMT_NOFILE))
+ if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
continue;
score = 0;
if (fmt1->read_probe) {
score = fmt1->read_probe(&lpd);
+ if (score)
+ av_log(NULL, AV_LOG_TRACE, "Probing %s score:%d size:%d\n", fmt1->name, score, lpd.buf_size);
+ if (fmt1->extensions && av_match_ext(lpd.filename, fmt1->extensions)) {
+ if (nodat == 0) score = FFMAX(score, 1);
+ else if (nodat == 1) score = FFMAX(score, AVPROBE_SCORE_EXTENSION / 2 - 1);
+ else score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
+ }
} else if (fmt1->extensions) {
if (av_match_ext(lpd.filename, fmt1->extensions))
score = AVPROBE_SCORE_EXTENSION;
}
if (av_match_name(lpd.mime_type, fmt1->mime_type))
score = FFMAX(score, AVPROBE_SCORE_MIME);
- if (score > *score_max) {
- *score_max = score;
- fmt = fmt1;
- } else if (score == *score_max)
+ if (score > score_max) {
+ score_max = score;
+ fmt = fmt1;
+ } else if (score == score_max)
fmt = NULL;
}
-
- // A hack for files with huge id3v2 tags -- try to guess by file extension.
- if (!fmt && is_opened && *score_max < AVPROBE_SCORE_EXTENSION / 2) {
- while ((fmt = av_iformat_next(fmt)))
- if (fmt->extensions &&
- av_match_ext(lpd.filename, fmt->extensions)) {
- *score_max = AVPROBE_SCORE_EXTENSION / 2;
- break;
- }
- }
-
- if (!fmt && id3 && *score_max < AVPROBE_SCORE_EXTENSION / 2 - 1) {
- while ((fmt = av_iformat_next(fmt)))
- if (fmt->extensions && av_match_ext("mp3", fmt->extensions)) {
- *score_max = AVPROBE_SCORE_EXTENSION / 2 - 1;
- break;
- }
- }
+ if (nodat == 1)
+ score_max = FFMIN(AVPROBE_SCORE_EXTENSION / 2 - 1, score_max);
+ *score_ret = score_max;
return fmt;
}
+AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max)
+{
+ int score_ret;
+ AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret);
+ if (score_ret > *score_max) {
+ *score_max = score_ret;
+ return fmt;
+ } else
+ return NULL;
+}
+
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened)
{
int score = 0;
return av_probe_input_format2(pd, is_opened, &score);
}
-/* size of probe buffer, for guessing file type from file contents */
-#define PROBE_BUF_MIN 2048
-#define PROBE_BUF_MAX (1 << 20)
-
-int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
+int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt,
const char *filename, void *logctx,
unsigned int offset, unsigned int max_probe_size)
{
AVProbeData pd = { filename ? filename : "" };
uint8_t *buf = NULL;
- int ret = 0, probe_size;
- uint8_t *mime_type_opt = NULL;
+ int ret = 0, probe_size, buf_offset = 0;
+ int score = 0;
+ int ret2;
if (!max_probe_size)
max_probe_size = PROBE_BUF_MAX;
- else if (max_probe_size > PROBE_BUF_MAX)
- max_probe_size = PROBE_BUF_MAX;
- else if (max_probe_size < PROBE_BUF_MIN)
+ else if (max_probe_size < PROBE_BUF_MIN) {
+ av_log(logctx, AV_LOG_ERROR,
+ "Specified probe size value %u cannot be < %u\n", max_probe_size, PROBE_BUF_MIN);
return AVERROR(EINVAL);
+ }
if (offset >= max_probe_size)
return AVERROR(EINVAL);
- avio_skip(pb, offset);
- max_probe_size -= offset;
+
if (pb->av_class) {
+ uint8_t *mime_type_opt = NULL;
av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type_opt);
pd.mime_type = (const char *)mime_type_opt;
- mime_type_opt = NULL;
}
+#if 0
+ if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) {
+ if (!av_strcasecmp(mime_type, "audio/aacp")) {
+ *fmt = av_find_input_format("aac");
+ }
+ av_freep(&mime_type);
+ }
+#endif
+
for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt;
probe_size = FFMIN(probe_size << 1,
FFMAX(max_probe_size, probe_size + 1))) {
- int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX / 4 : 0;
+ score = probe_size < max_probe_size ? AVPROBE_SCORE_RETRY : 0;
/* Read probe data. */
if ((ret = av_reallocp(&buf, probe_size + AVPROBE_PADDING_SIZE)) < 0)
goto fail;
- if ((ret = avio_read(pb, buf + pd.buf_size,
- probe_size - pd.buf_size)) < 0) {
+ if ((ret = avio_read(pb, buf + buf_offset,
+ probe_size - buf_offset)) < 0) {
/* Fail if error was not end of file, otherwise, lower score. */
if (ret != AVERROR_EOF)
goto fail;
@@ -277,8 +290,11 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
score = 0;
ret = 0; /* error was end of file, nothing read */
}
- pd.buf_size += ret;
- pd.buf = buf;
+ buf_offset += ret;
+ if (buf_offset < offset)
+ continue;
+ pd.buf_size = buf_offset - offset;
+ pd.buf = &buf[offset];
memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE);
@@ -286,13 +302,19 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
*fmt = av_probe_input_format2(&pd, 1, &score);
if (*fmt) {
/* This can only be true in the last iteration. */
- if (score <= AVPROBE_SCORE_MAX / 4) {
+ if (score <= AVPROBE_SCORE_RETRY) {
av_log(logctx, AV_LOG_WARNING,
- "Format detected only with low score of %d, "
- "misdetection possible!\n", score);
+ "Format %s detected only with low score of %d, "
+ "misdetection possible!\n", (*fmt)->name, score);
} else
av_log(logctx, AV_LOG_DEBUG,
- "Probed with size=%d and score=%d\n", probe_size, score);
+ "Format %s probed with size=%d and score=%d\n",
+ (*fmt)->name, probe_size, score);
+#if 0
+ FILE *f = fopen("probestat.tmp", "ab");
+ fprintf(f, "probe_size:%d format:%s score:%d filename:%s\n", probe_size, (*fmt)->name, score, filename);
+ fclose(f);
+#endif
}
}
@@ -301,10 +323,18 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
fail:
/* Rewind. Reuse probe buffer to avoid seeking. */
- if (ret < 0 ||
- (ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) {
- av_free(buf);
- }
+ ret2 = ffio_rewind_with_probe_data(pb, &buf, buf_offset);
+ if (ret >= 0)
+ ret = ret2;
+
av_freep(&pd.mime_type);
- return ret;
+ return ret < 0 ? ret : score;
+}
+
+int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt,
+ const char *filename, void *logctx,
+ unsigned int offset, unsigned int max_probe_size)
+{
+ int ret = av_probe_input_buffer2(pb, fmt, filename, logctx, offset, max_probe_size);
+ return ret < 0 ? ret : 0;
}
diff --git a/libavformat/framecrcenc.c b/libavformat/framecrcenc.c
index 4d5483a70e..805b5428f9 100644
--- a/libavformat/framecrcenc.c
+++ b/libavformat/framecrcenc.c
@@ -2,36 +2,76 @@
* frame CRC encoder (for codec/format testing)
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include "libavutil/adler32.h"
+#include "libavutil/avstring.h"
#include "avformat.h"
#include "internal.h"
+static int framecrc_write_header(struct AVFormatContext *s)
+{
+ int i;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ AVCodecContext *avctx = st->codec;
+ if (avctx->extradata) {
+ uint32_t crc = av_adler32_update(0, avctx->extradata, avctx->extradata_size);
+ avio_printf(s->pb, "#extradata %d: %8d, 0x%08"PRIx32"\n",
+ i, avctx->extradata_size, crc);
+ }
+ }
+
+ return ff_framehash_write_header(s);
+}
+
static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
uint32_t crc = av_adler32_update(0, pkt->data, pkt->size);
char buf[256];
- snprintf(buf, sizeof(buf), "%d, %10"PRId64", %10"PRId64", %8d, %8d, 0x%08"PRIx32"\n",
+ snprintf(buf, sizeof(buf), "%d, %10"PRId64", %10"PRId64", %8d, %8d, 0x%08"PRIx32,
pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size, crc);
+ if (pkt->flags != AV_PKT_FLAG_KEY)
+ av_strlcatf(buf, sizeof(buf), ", F=0x%0X", pkt->flags);
+ if (pkt->side_data_elems) {
+ int i, j;
+ av_strlcatf(buf, sizeof(buf), ", S=%d", pkt->side_data_elems);
+
+ for (i=0; i<pkt->side_data_elems; i++) {
+ uint32_t side_data_crc = 0;
+ if (HAVE_BIGENDIAN && AV_PKT_DATA_PALETTE == pkt->side_data[i].type) {
+ for (j=0; j<pkt->side_data[i].size; j++) {
+ side_data_crc = av_adler32_update(side_data_crc,
+ pkt->side_data[i].data + (j^3),
+ 1);
+ }
+ } else {
+ side_data_crc = av_adler32_update(0,
+ pkt->side_data[i].data,
+ pkt->side_data[i].size);
+ }
+ av_strlcatf(buf, sizeof(buf), ", %8d, 0x%08x", pkt->side_data[i].size, side_data_crc);
+ }
+ }
+ av_strlcatf(buf, sizeof(buf), "\n");
avio_write(s->pb, buf, strlen(buf));
return 0;
}
@@ -39,10 +79,9 @@ static int framecrc_write_packet(struct AVFormatContext *s, AVPacket *pkt)
AVOutputFormat ff_framecrc_muxer = {
.name = "framecrc",
.long_name = NULL_IF_CONFIG_SMALL("framecrc testing"),
- .extensions = "",
.audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_RAWVIDEO,
- .write_header = ff_framehash_write_header,
+ .write_header = framecrc_write_header,
.write_packet = framecrc_write_packet,
.flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
AVFMT_TS_NEGATIVE,
diff --git a/libavformat/framehash.c b/libavformat/framehash.c
index 6a6da98ae4..a8357b04ae 100644
--- a/libavformat/framehash.c
+++ b/libavformat/framehash.c
@@ -1,20 +1,20 @@
/*
* Common functions for the frame{crc,md5} muxers
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,9 @@
int ff_framehash_write_header(AVFormatContext *s)
{
int i;
+
+ if (s->nb_streams && !(s->flags & AVFMT_FLAG_BITEXACT))
+ avio_printf(s->pb, "#software: %s\n", LIBAVFORMAT_IDENT);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
avio_printf(s->pb, "#tb %d: %d/%d\n", i, st->time_base.num, st->time_base.den);
diff --git a/libavformat/frmdec.c b/libavformat/frmdec.c
new file mode 100644
index 0000000000..a6f19afcd4
--- /dev/null
+++ b/libavformat/frmdec.c
@@ -0,0 +1,110 @@
+/*
+ * Megalux Frame demuxer
+ * Copyright (c) 2010 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Megalux Frame demuxer
+ */
+
+#include "libavcodec/raw.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+
+static const PixelFormatTag frm_pix_fmt_tags[] = {
+ { AV_PIX_FMT_RGB555, 1 },
+ { AV_PIX_FMT_RGB0, 2 },
+ { AV_PIX_FMT_RGB24, 3 },
+ { AV_PIX_FMT_BGR0, 4 },
+ { AV_PIX_FMT_BGRA, 5 },
+ { AV_PIX_FMT_NONE, 0 },
+};
+
+typedef struct {
+ int count;
+} FrmContext;
+
+static int frm_read_probe(AVProbeData *p)
+{
+ if (p->buf_size > 8 &&
+ p->buf[0] == 'F' && p->buf[1] == 'R' && p->buf[2] == 'M' &&
+ AV_RL16(&p->buf[4]) && AV_RL16(&p->buf[6]))
+ return AVPROBE_SCORE_MAX / 4;
+ return 0;
+}
+
+static int frm_read_header(AVFormatContext *avctx)
+{
+ AVIOContext *pb = avctx->pb;
+ AVStream *st = avformat_new_stream(avctx, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ avio_skip(pb, 3);
+
+ st->codec->pix_fmt = avpriv_find_pix_fmt(frm_pix_fmt_tags, avio_r8(pb));
+ if (!st->codec->pix_fmt)
+ return AVERROR_INVALIDDATA;
+
+ st->codec->codec_tag = 0;
+ st->codec->width = avio_rl16(pb);
+ st->codec->height = avio_rl16(pb);
+ return 0;
+}
+
+static int frm_read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ FrmContext *s = avctx->priv_data;
+ AVCodecContext *stc = avctx->streams[0]->codec;
+ int packet_size, ret;
+
+ if (s->count)
+ return AVERROR_EOF;
+
+ packet_size = avpicture_get_size(stc->pix_fmt, stc->width, stc->height);
+ if (packet_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ ret = av_get_packet(avctx->pb, pkt, packet_size);
+ if (ret < 0)
+ return ret;
+
+ if (stc->pix_fmt == AV_PIX_FMT_BGRA) {
+ int i;
+ for (i = 3; i + 1 <= pkt->size; i += 4)
+ pkt->data[i] = 0xFF - pkt->data[i];
+ }
+
+ pkt->stream_index = 0;
+ s->count++;
+
+ return 0;
+}
+
+AVInputFormat ff_frm_demuxer = {
+ .name = "frm",
+ .priv_data_size = sizeof(FrmContext),
+ .long_name = NULL_IF_CONFIG_SMALL("Megalux Frame"),
+ .read_probe = frm_read_probe,
+ .read_header = frm_read_header,
+ .read_packet = frm_read_packet,
+};
diff --git a/libavformat/ftp.c b/libavformat/ftp.c
new file mode 100644
index 0000000000..27a172e8ad
--- /dev/null
+++ b/libavformat/ftp.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2013 Lukasz Marek <lukasz.m.luki@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
+ */
+
+#include "libavutil/avstring.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+#include "libavutil/opt.h"
+#include "libavutil/bprint.h"
+
+#define CONTROL_BUFFER_SIZE 1024
+
+typedef enum {
+ UNKNOWN,
+ READY,
+ DOWNLOADING,
+ UPLOADING,
+ DISCONNECTED
+} FTPState;
+
+typedef struct {
+ const AVClass *class;
+ URLContext *conn_control; /**< Control connection */
+ URLContext *conn_data; /**< Data connection, NULL when not connected */
+ uint8_t control_buffer[CONTROL_BUFFER_SIZE]; /**< Control connection buffer */
+ uint8_t *control_buf_ptr, *control_buf_end;
+ int server_data_port; /**< Data connection port opened by server, -1 on error. */
+ int server_control_port; /**< Control connection port, default is 21 */
+ char *hostname; /**< Server address. */
+ char *user; /**< Server user */
+ char *password; /**< Server user's password */
+ char *path; /**< Path to resource on server. */
+ int64_t filesize; /**< Size of file on server, -1 on error. */
+ int64_t position; /**< Current position, calculated. */
+ int rw_timeout; /**< Network timeout. */
+ const char *anonymous_password; /**< Password to be used for anonymous user. An email should be used. */
+ int write_seekable; /**< Control seekability, 0 = disable, 1 = enable. */
+ FTPState state; /**< State of data connection */
+} FTPContext;
+
+#define OFFSET(x) offsetof(FTPContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
+ {"ftp-write-seekable", "control seekability of connection during encoding", OFFSET(write_seekable), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
+ {"ftp-anonymous-password", "password for anonymous login. E-mail address should be used.", OFFSET(anonymous_password), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
+ {NULL}
+};
+
+static const AVClass ftp_context_class = {
+ .class_name = "ftp",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int ftp_close(URLContext *h);
+
+static int ftp_getc(FTPContext *s)
+{
+ int len;
+ if (s->control_buf_ptr >= s->control_buf_end) {
+ len = ffurl_read(s->conn_control, s->control_buffer, CONTROL_BUFFER_SIZE);
+ if (len < 0) {
+ return len;
+ } else if (!len) {
+ return -1;
+ } else {
+ s->control_buf_ptr = s->control_buffer;
+ s->control_buf_end = s->control_buffer + len;
+ }
+ }
+ return *s->control_buf_ptr++;
+}
+
+static int ftp_get_line(FTPContext *s, char *line, int line_size)
+{
+ int ch;
+ char *q = line;
+
+ for (;;) {
+ ch = ftp_getc(s);
+ if (ch < 0) {
+ return ch;
+ }
+ if (ch == '\n') {
+ /* process line */
+ if (q > line && q[-1] == '\r')
+ q--;
+ *q = '\0';
+ return 0;
+ } else {
+ if ((q - line) < line_size - 1)
+ *q++ = ch;
+ }
+ }
+}
+
+/*
+ * This routine returns ftp server response code.
+ * Server may send more than one response for a certain command.
+ * First expected code is returned.
+ */
+static int ftp_status(FTPContext *s, char **line, const int response_codes[])
+{
+ int err, i, dash = 0, result = 0, code_found = 0, linesize;
+ char buf[CONTROL_BUFFER_SIZE];
+ AVBPrint line_buffer;
+
+ if (line)
+ av_bprint_init(&line_buffer, 0, AV_BPRINT_SIZE_AUTOMATIC);
+
+ while (!code_found || dash) {
+ if ((err = ftp_get_line(s, buf, sizeof(buf))) < 0) {
+ if (line)
+ av_bprint_finalize(&line_buffer, NULL);
+ return err;
+ }
+
+ av_log(s, AV_LOG_DEBUG, "%s\n", buf);
+
+ linesize = strlen(buf);
+ err = 0;
+ if (linesize >= 3) {
+ for (i = 0; i < 3; ++i) {
+ if (buf[i] < '0' || buf[i] > '9') {
+ err = 0;
+ break;
+ }
+ err *= 10;
+ err += buf[i] - '0';
+ }
+ }
+
+ if (!code_found) {
+ if (err >= 500) {
+ code_found = 1;
+ result = err;
+ } else
+ for (i = 0; response_codes[i]; ++i) {
+ if (err == response_codes[i]) {
+ code_found = 1;
+ result = err;
+ break;
+ }
+ }
+ }
+ if (code_found) {
+ if (line)
+ av_bprintf(&line_buffer, "%s\r\n", buf);
+ if (linesize >= 4) {
+ if (!dash && buf[3] == '-')
+ dash = err;
+ else if (err == dash && buf[3] == ' ')
+ dash = 0;
+ }
+ }
+ }
+
+ if (line)
+ av_bprint_finalize(&line_buffer, line);
+ return result;
+}
+
+static int ftp_send_command(FTPContext *s, const char *command,
+ const int response_codes[], char **response)
+{
+ int err;
+
+ if (response)
+ *response = NULL;
+
+ if ((err = ffurl_write(s->conn_control, command, strlen(command))) < 0)
+ return err;
+ if (!err)
+ return -1;
+
+ /* return status */
+ if (response_codes) {
+ return ftp_status(s, response, response_codes);
+ }
+ return 0;
+}
+
+static void ftp_close_data_connection(FTPContext *s)
+{
+ ffurl_closep(&s->conn_data);
+ s->position = 0;
+ s->state = DISCONNECTED;
+}
+
+static void ftp_close_both_connections(FTPContext *s)
+{
+ ffurl_closep(&s->conn_control);
+ ftp_close_data_connection(s);
+}
+
+static int ftp_auth(FTPContext *s)
+{
+ char buf[CONTROL_BUFFER_SIZE];
+ int err;
+ static const int user_codes[] = {331, 230, 0};
+ static const int pass_codes[] = {230, 0};
+
+ snprintf(buf, sizeof(buf), "USER %s\r\n", s->user);
+ err = ftp_send_command(s, buf, user_codes, NULL);
+ if (err == 331) {
+ if (s->password) {
+ snprintf(buf, sizeof(buf), "PASS %s\r\n", s->password);
+ err = ftp_send_command(s, buf, pass_codes, NULL);
+ } else
+ return AVERROR(EACCES);
+ }
+ if (err != 230)
+ return AVERROR(EACCES);
+
+ return 0;
+}
+
+static int ftp_passive_mode_epsv(FTPContext *s)
+{
+ char *res = NULL, *start = NULL, *end = NULL;
+ int i;
+ static const char d = '|';
+ static const char *command = "EPSV\r\n";
+ static const int epsv_codes[] = {229, 0};
+
+ if (ftp_send_command(s, command, epsv_codes, &res) != 229 || !res)
+ goto fail;
+
+ for (i = 0; res[i]; ++i) {
+ if (res[i] == '(') {
+ start = res + i + 1;
+ } else if (res[i] == ')') {
+ end = res + i;
+ break;
+ }
+ }
+ if (!start || !end)
+ goto fail;
+
+ *end = '\0';
+ if (strlen(start) < 5)
+ goto fail;
+ if (start[0] != d || start[1] != d || start[2] != d || end[-1] != d)
+ goto fail;
+ start += 3;
+ end[-1] = '\0';
+
+ s->server_data_port = atoi(start);
+ av_dlog(s, "Server data port: %d\n", s->server_data_port);
+
+ av_free(res);
+ return 0;
+
+ fail:
+ av_free(res);
+ s->server_data_port = -1;
+ return AVERROR(ENOSYS);
+}
+
+static int ftp_passive_mode(FTPContext *s)
+{
+ char *res = NULL, *start = NULL, *end = NULL;
+ int i;
+ static const char *command = "PASV\r\n";
+ static const int pasv_codes[] = {227, 0};
+
+ if (ftp_send_command(s, command, pasv_codes, &res) != 227 || !res)
+ goto fail;
+
+ for (i = 0; res[i]; ++i) {
+ if (res[i] == '(') {
+ start = res + i + 1;
+ } else if (res[i] == ')') {
+ end = res + i;
+ break;
+ }
+ }
+ if (!start || !end)
+ goto fail;
+
+ *end = '\0';
+ /* skip ip */
+ if (!av_strtok(start, ",", &end)) goto fail;
+ if (!av_strtok(end, ",", &end)) goto fail;
+ if (!av_strtok(end, ",", &end)) goto fail;
+ if (!av_strtok(end, ",", &end)) goto fail;
+
+ /* parse port number */
+ start = av_strtok(end, ",", &end);
+ if (!start) goto fail;
+ s->server_data_port = atoi(start) * 256;
+ start = av_strtok(end, ",", &end);
+ if (!start) goto fail;
+ s->server_data_port += atoi(start);
+ av_dlog(s, "Server data port: %d\n", s->server_data_port);
+
+ av_free(res);
+ return 0;
+
+ fail:
+ av_free(res);
+ s->server_data_port = -1;
+ return AVERROR(EIO);
+}
+
+static int ftp_current_dir(FTPContext *s)
+{
+ char *res = NULL, *start = NULL, *end = NULL;
+ int i;
+ static const char *command = "PWD\r\n";
+ static const int pwd_codes[] = {257, 0};
+
+ if (ftp_send_command(s, command, pwd_codes, &res) != 257 || !res)
+ goto fail;
+
+ for (i = 0; res[i]; ++i) {
+ if (res[i] == '"') {
+ if (!start) {
+ start = res + i + 1;
+ continue;
+ }
+ end = res + i;
+ break;
+ }
+ }
+
+ if (!end)
+ goto fail;
+
+ if (end > res && end[-1] == '/') {
+ end[-1] = '\0';
+ } else
+ *end = '\0';
+ s->path = av_strdup(start);
+
+ av_free(res);
+
+ if (!s->path)
+ return AVERROR(ENOMEM);
+ return 0;
+
+ fail:
+ av_free(res);
+ return AVERROR(EIO);
+}
+
+static int ftp_file_size(FTPContext *s)
+{
+ char command[CONTROL_BUFFER_SIZE];
+ char *res = NULL;
+ static const int size_codes[] = {213, 0};
+
+ snprintf(command, sizeof(command), "SIZE %s\r\n", s->path);
+ if (ftp_send_command(s, command, size_codes, &res) == 213 && res) {
+ s->filesize = strtoll(&res[4], NULL, 10);
+ } else {
+ s->filesize = -1;
+ av_free(res);
+ return AVERROR(EIO);
+ }
+
+ av_free(res);
+ return 0;
+}
+
+static int ftp_retrieve(FTPContext *s)
+{
+ char command[CONTROL_BUFFER_SIZE];
+ static const int retr_codes[] = {150, 0};
+
+ snprintf(command, sizeof(command), "RETR %s\r\n", s->path);
+ if (ftp_send_command(s, command, retr_codes, NULL) != 150)
+ return AVERROR(EIO);
+
+ s->state = DOWNLOADING;
+
+ return 0;
+}
+
+static int ftp_store(FTPContext *s)
+{
+ char command[CONTROL_BUFFER_SIZE];
+ static const int stor_codes[] = {150, 0};
+
+ snprintf(command, sizeof(command), "STOR %s\r\n", s->path);
+ if (ftp_send_command(s, command, stor_codes, NULL) != 150)
+ return AVERROR(EIO);
+
+ s->state = UPLOADING;
+
+ return 0;
+}
+
+static int ftp_type(FTPContext *s)
+{
+ static const char *command = "TYPE I\r\n";
+ static const int type_codes[] = {200, 0};
+
+ if (ftp_send_command(s, command, type_codes, NULL) != 200)
+ return AVERROR(EIO);
+
+ return 0;
+}
+
+static int ftp_restart(FTPContext *s, int64_t pos)
+{
+ char command[CONTROL_BUFFER_SIZE];
+ static const int rest_codes[] = {350, 0};
+
+ snprintf(command, sizeof(command), "REST %"PRId64"\r\n", pos);
+ if (ftp_send_command(s, command, rest_codes, NULL) != 350)
+ return AVERROR(EIO);
+
+ return 0;
+}
+
+static int ftp_features(FTPContext *s)
+{
+ static const char *feat_command = "FEAT\r\n";
+ static const char *enable_utf8_command = "OPTS UTF8 ON\r\n";
+ static const int feat_codes[] = {211, 0};
+ static const int opts_codes[] = {200, 451};
+ char *feat = NULL;
+
+ if (ftp_send_command(s, feat_command, feat_codes, &feat) == 211) {
+ if (av_stristr(feat, "UTF8"))
+ ftp_send_command(s, enable_utf8_command, opts_codes, NULL);
+ }
+ av_freep(&feat);
+
+ return 0;
+}
+
+static int ftp_connect_control_connection(URLContext *h)
+{
+ char buf[CONTROL_BUFFER_SIZE], *response = NULL;
+ int err;
+ AVDictionary *opts = NULL;
+ FTPContext *s = h->priv_data;
+ static const int connect_codes[] = {220, 0};
+
+ if (!s->conn_control) {
+ ff_url_join(buf, sizeof(buf), "tcp", NULL,
+ s->hostname, s->server_control_port, NULL);
+ if (s->rw_timeout != -1) {
+ av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
+ } /* if option is not given, don't pass it and let tcp use its own default */
+ err = ffurl_open(&s->conn_control, buf, AVIO_FLAG_READ_WRITE,
+ &h->interrupt_callback, &opts);
+ av_dict_free(&opts);
+ if (err < 0) {
+ av_log(h, AV_LOG_ERROR, "Cannot open control connection\n");
+ return err;
+ }
+
+ /* check if server is ready */
+ if (ftp_status(s, ((h->flags & AVIO_FLAG_WRITE) ? &response : NULL), connect_codes) != 220) {
+ av_log(h, AV_LOG_ERROR, "FTP server not ready for new users\n");
+ return AVERROR(EACCES);
+ }
+
+ if ((h->flags & AVIO_FLAG_WRITE) && av_stristr(response, "pure-ftpd")) {
+ av_log(h, AV_LOG_WARNING, "Pure-FTPd server is used as an output protocol. It is known issue this implementation may produce incorrect content and it cannot be fixed at this moment.");
+ }
+ av_free(response);
+
+ if ((err = ftp_auth(s)) < 0) {
+ av_log(h, AV_LOG_ERROR, "FTP authentication failed\n");
+ return err;
+ }
+
+ if ((err = ftp_type(s)) < 0) {
+ av_log(h, AV_LOG_ERROR, "Set content type failed\n");
+ return err;
+ }
+
+ ftp_features(s);
+ }
+ return 0;
+}
+
+static int ftp_connect_data_connection(URLContext *h)
+{
+ int err;
+ char buf[CONTROL_BUFFER_SIZE];
+ AVDictionary *opts = NULL;
+ FTPContext *s = h->priv_data;
+
+ if (!s->conn_data) {
+ /* Enter passive mode */
+ if (ftp_passive_mode_epsv(s) < 0) {
+ /* Use PASV as fallback */
+ if ((err = ftp_passive_mode(s)) < 0)
+ return err;
+ }
+ /* Open data connection */
+ ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
+ if (s->rw_timeout != -1) {
+ av_dict_set_int(&opts, "timeout", s->rw_timeout, 0);
+ } /* if option is not given, don't pass it and let tcp use its own default */
+ err = ffurl_open(&s->conn_data, buf, h->flags,
+ &h->interrupt_callback, &opts);
+ av_dict_free(&opts);
+ if (err < 0)
+ return err;
+
+ if (s->position)
+ if ((err = ftp_restart(s, s->position)) < 0)
+ return err;
+ }
+ s->state = READY;
+ return 0;
+}
+
+static int ftp_abort(URLContext *h)
+{
+ static const char *command = "ABOR\r\n";
+ int err;
+ static const int abor_codes[] = {225, 226, 0};
+ FTPContext *s = h->priv_data;
+
+ /* According to RCF 959:
+ "ABOR command tells the server to abort the previous FTP
+ service command and any associated transfer of data."
+
+ There are FTP server implementations that don't response
+ to any commands during data transfer in passive mode (including ABOR).
+
+ This implementation closes data connection by force.
+ */
+
+ if (ftp_send_command(s, command, NULL, NULL) < 0) {
+ ftp_close_both_connections(s);
+ if ((err = ftp_connect_control_connection(h)) < 0) {
+ av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
+ return err;
+ }
+ } else {
+ ftp_close_data_connection(s);
+ if (ftp_status(s, NULL, abor_codes) < 225) {
+ /* wu-ftpd also closes control connection after data connection closing */
+ ffurl_closep(&s->conn_control);
+ if ((err = ftp_connect_control_connection(h)) < 0) {
+ av_log(h, AV_LOG_ERROR, "Reconnect failed.\n");
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int ftp_open(URLContext *h, const char *url, int flags)
+{
+ char proto[10], path[MAX_URL_SIZE], credencials[MAX_URL_SIZE], hostname[MAX_URL_SIZE];
+ const char *tok_user = NULL, *tok_pass = NULL;
+ char *end = NULL;
+ int err;
+ size_t pathlen;
+ FTPContext *s = h->priv_data;
+
+ av_dlog(h, "ftp protocol open\n");
+
+ s->state = DISCONNECTED;
+ s->filesize = -1;
+ s->position = 0;
+
+ av_url_split(proto, sizeof(proto),
+ credencials, sizeof(credencials),
+ hostname, sizeof(hostname),
+ &s->server_control_port,
+ path, sizeof(path),
+ url);
+
+ tok_user = av_strtok(credencials, ":", &end);
+ tok_pass = av_strtok(end, ":", &end);
+ if (!tok_user) {
+ tok_user = "anonymous";
+ tok_pass = av_x_if_null(s->anonymous_password, "nopassword");
+ }
+ s->user = av_strdup(tok_user);
+ s->password = av_strdup(tok_pass);
+ s->hostname = av_strdup(hostname);
+ if (!s->hostname || !s->user || (tok_pass && !s->password)) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ if (s->server_control_port < 0 || s->server_control_port > 65535)
+ s->server_control_port = 21;
+
+ if ((err = ftp_connect_control_connection(h)) < 0)
+ goto fail;
+
+ if ((err = ftp_current_dir(s)) < 0)
+ goto fail;
+ pathlen = strlen(s->path) + strlen(path) + 1;
+ if ((err = av_reallocp(&s->path, pathlen)) < 0)
+ goto fail;
+ av_strlcat(s->path + strlen(s->path), path, pathlen);
+
+ if (ftp_restart(s, 0) < 0) {
+ h->is_streamed = 1;
+ } else {
+ if (ftp_file_size(s) < 0 && flags & AVIO_FLAG_READ)
+ h->is_streamed = 1;
+ if (s->write_seekable != 1 && flags & AVIO_FLAG_WRITE)
+ h->is_streamed = 1;
+ }
+
+ return 0;
+
+ fail:
+ av_log(h, AV_LOG_ERROR, "FTP open failed\n");
+ ftp_close(h);
+ return err;
+}
+
+static int64_t ftp_seek(URLContext *h, int64_t pos, int whence)
+{
+ FTPContext *s = h->priv_data;
+ int err;
+ int64_t new_pos, fake_pos;
+
+ av_dlog(h, "ftp protocol seek %"PRId64" %d\n", pos, whence);
+
+ switch(whence) {
+ case AVSEEK_SIZE:
+ return s->filesize;
+ case SEEK_SET:
+ new_pos = pos;
+ break;
+ case SEEK_CUR:
+ new_pos = s->position + pos;
+ break;
+ case SEEK_END:
+ if (s->filesize < 0)
+ return AVERROR(EIO);
+ new_pos = s->filesize + pos;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ if (h->is_streamed)
+ return AVERROR(EIO);
+
+ if (new_pos < 0) {
+ av_log(h, AV_LOG_ERROR, "Seeking to nagative position.\n");
+ return AVERROR(EINVAL);
+ }
+
+ fake_pos = s->filesize != -1 ? FFMIN(new_pos, s->filesize) : new_pos;
+ if (fake_pos != s->position) {
+ if ((err = ftp_abort(h)) < 0)
+ return err;
+ s->position = fake_pos;
+ }
+ return new_pos;
+}
+
+static int ftp_read(URLContext *h, unsigned char *buf, int size)
+{
+ FTPContext *s = h->priv_data;
+ int read, err, retry_done = 0;
+
+ av_dlog(h, "ftp protocol read %d bytes\n", size);
+ retry:
+ if (s->state == DISCONNECTED) {
+ /* optimization */
+ if (s->position >= s->filesize)
+ return 0;
+ if ((err = ftp_connect_data_connection(h)) < 0)
+ return err;
+ }
+ if (s->state == READY) {
+ if (s->position >= s->filesize)
+ return 0;
+ if ((err = ftp_retrieve(s)) < 0)
+ return err;
+ }
+ if (s->conn_data && s->state == DOWNLOADING) {
+ read = ffurl_read(s->conn_data, buf, size);
+ if (read >= 0) {
+ s->position += read;
+ if (s->position >= s->filesize) {
+ /* server will terminate, but keep current position to avoid madness */
+ /* save position to restart from it */
+ int64_t pos = s->position;
+ if (ftp_abort(h) < 0) {
+ s->position = pos;
+ return AVERROR(EIO);
+ }
+ s->position = pos;
+ }
+ }
+ if (read <= 0 && s->position < s->filesize && !h->is_streamed) {
+ /* Server closed connection. Probably due to inactivity */
+ int64_t pos = s->position;
+ av_log(h, AV_LOG_INFO, "Reconnect to FTP server.\n");
+ if ((err = ftp_abort(h)) < 0)
+ return err;
+ if ((err = ftp_seek(h, pos, SEEK_SET)) < 0) {
+ av_log(h, AV_LOG_ERROR, "Position cannot be restored.\n");
+ return err;
+ }
+ if (!retry_done) {
+ retry_done = 1;
+ goto retry;
+ }
+ }
+ return read;
+ }
+
+ av_log(h, AV_LOG_DEBUG, "FTP read failed\n");
+ return AVERROR(EIO);
+}
+
+static int ftp_write(URLContext *h, const unsigned char *buf, int size)
+{
+ int err;
+ FTPContext *s = h->priv_data;
+ int written;
+
+ av_dlog(h, "ftp protocol write %d bytes\n", size);
+
+ if (s->state == DISCONNECTED) {
+ if ((err = ftp_connect_data_connection(h)) < 0)
+ return err;
+ }
+ if (s->state == READY) {
+ if ((err = ftp_store(s)) < 0)
+ return err;
+ }
+ if (s->conn_data && s->state == UPLOADING) {
+ written = ffurl_write(s->conn_data, buf, size);
+ if (written > 0) {
+ s->position += written;
+ s->filesize = FFMAX(s->filesize, s->position);
+ }
+ return written;
+ }
+
+ av_log(h, AV_LOG_ERROR, "FTP write failed\n");
+ return AVERROR(EIO);
+}
+
+static int ftp_close(URLContext *h)
+{
+ FTPContext *s = h->priv_data;
+
+ av_dlog(h, "ftp protocol close\n");
+
+ ftp_close_both_connections(s);
+ av_freep(&s->user);
+ av_freep(&s->password);
+ av_freep(&s->hostname);
+ av_freep(&s->path);
+
+ return 0;
+}
+
+static int ftp_get_file_handle(URLContext *h)
+{
+ FTPContext *s = h->priv_data;
+
+ av_dlog(h, "ftp protocol get_file_handle\n");
+
+ if (s->conn_data)
+ return ffurl_get_file_handle(s->conn_data);
+
+ return AVERROR(EIO);
+}
+
+static int ftp_shutdown(URLContext *h, int flags)
+{
+ FTPContext *s = h->priv_data;
+
+ av_dlog(h, "ftp protocol shutdown\n");
+
+ if (s->conn_data)
+ return ffurl_shutdown(s->conn_data, flags);
+
+ return AVERROR(EIO);
+}
+
+URLProtocol ff_ftp_protocol = {
+ .name = "ftp",
+ .url_open = ftp_open,
+ .url_read = ftp_read,
+ .url_write = ftp_write,
+ .url_seek = ftp_seek,
+ .url_close = ftp_close,
+ .url_get_file_handle = ftp_get_file_handle,
+ .url_shutdown = ftp_shutdown,
+ .priv_data_size = sizeof(FTPContext),
+ .priv_data_class = &ftp_context_class,
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
+};
diff --git a/libavformat/g722.c b/libavformat/g722.c
index 8052939c79..1a87c7d28c 100644
--- a/libavformat/g722.c
+++ b/libavformat/g722.c
@@ -2,23 +2,24 @@
* g722 raw demuxer
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avformat.h"
#include "internal.h"
#include "rawdec.h"
@@ -39,7 +40,7 @@ static int g722_read_header(AVFormatContext *s)
st->codec->bits_per_coded_sample =
av_get_bits_per_sample(st->codec->codec_id);
- assert(st->codec->bits_per_coded_sample > 0);
+ av_assert0(st->codec->bits_per_coded_sample > 0);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
return 0;
diff --git a/libavformat/g723_1.c b/libavformat/g723_1.c
index b67c07c404..4f3ce8f0ae 100644
--- a/libavformat/g723_1.c
+++ b/libavformat/g723_1.c
@@ -2,20 +2,20 @@
* G.723.1 demuxer
* Copyright (c) 2010 Mohamed Naufal Basheer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,6 +81,6 @@ AVInputFormat ff_g723_1_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("G.723.1"),
.read_header = g723_1_init,
.read_packet = g723_1_read_packet,
- .extensions = "tco",
+ .extensions = "tco,rco,g723_1",
.flags = AVFMT_GENERIC_INDEX
};
diff --git a/libavformat/g729dec.c b/libavformat/g729dec.c
new file mode 100644
index 0000000000..794558ef10
--- /dev/null
+++ b/libavformat/g729dec.c
@@ -0,0 +1,103 @@
+/*
+ * G.729 raw format demuxer
+ * Copyright (c) 2011 Vladimir Voroshilov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+typedef struct G729DemuxerContext {
+ AVClass *class;
+ int bit_rate;
+} G729DemuxerContext;
+
+static int g729_read_header(AVFormatContext *s)
+{
+ AVStream* st;
+ G729DemuxerContext *s1 = s->priv_data;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_G729;
+ st->codec->sample_rate = 8000;
+ st->codec->channels = 1;
+
+ if (s1 && s1->bit_rate) {
+ s->bit_rate = s1->bit_rate;
+ }
+
+ if (s->bit_rate == 0) {
+ av_log(s, AV_LOG_DEBUG, "No bitrate specified. Assuming 8000 b/s\n");
+ s->bit_rate = 8000;
+ }
+
+ if (s->bit_rate == 6400) {
+ st->codec->block_align = 8;
+ } else if (s->bit_rate == 8000) {
+ st->codec->block_align = 10;
+ } else {
+ av_log(s, AV_LOG_ERROR, "Only 8000 b/s and 6400 b/s bitrates are supported. Provided: %d b/s\n", s->bit_rate);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avpriv_set_pts_info(st, st->codec->block_align << 3, 1, st->codec->sample_rate);
+ return 0;
+}
+static int g729_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int ret;
+
+ ret = av_get_packet(s->pb, pkt, s->streams[0]->codec->block_align);
+
+ pkt->stream_index = 0;
+ if (ret < 0)
+ return ret;
+
+ pkt->dts = pkt->pts = pkt->pos / s->streams[0]->codec->block_align;
+
+ return ret;
+}
+
+static const AVOption g729_options[] = {
+ { "bit_rate", "", offsetof(G729DemuxerContext, bit_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass g729_demuxer_class = {
+ .class_name = "g729 demuxer",
+ .item_name = av_default_item_name,
+ .option = g729_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_g729_demuxer = {
+ .name = "g729",
+ .long_name = NULL_IF_CONFIG_SMALL("G.729 raw format demuxer"),
+ .priv_data_size = sizeof(G729DemuxerContext),
+ .read_header = g729_read_header,
+ .read_packet = g729_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+ .extensions = "g729",
+ .priv_class = &g729_demuxer_class,
+};
diff --git a/libavformat/gif.c b/libavformat/gif.c
index ddec778d82..e5d558df07 100644
--- a/libavformat/gif.c
+++ b/libavformat/gif.c
@@ -4,347 +4,220 @@
*
* first version by Francois Revol <revol@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/*
- * Features and limitations:
- * - currently no compression is performed,
- * in fact the size of the data is 9/8 the size of the image in 8bpp
- * - uses only a global standard palette
- * - tested with IE 5.0, Opera for BeOS, NetPositive (BeOS), and Mozilla (BeOS).
- *
- * Reference documents:
- * http://www.goice.co.jp/member/mo/formats/gif.html
- * http://astronomy.swin.edu.au/pbourke/dataformats/gif/
- * http://www.dcs.ed.ac.uk/home/mxr/gfx/2d/GIF89a.txt
- *
- * this url claims to have an LZW algorithm not covered by Unisys patent:
- * http://www.msg.net/utility/whirlgif/gifencod.html
- * could help reduce the size of the files _a lot_...
- * some sites mentions an RLE type compression also.
- */
-
#include "avformat.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
-/* The GIF format uses reversed order for bitstreams... */
-/* at least they don't use PDP_ENDIAN :) */
-#define BITSTREAM_WRITER_LE
-
-#include "libavcodec/put_bits.h"
-
-/* bitstream minipacket size */
-#define GIF_CHUNKS 100
-
-/* slows down the decoding (and some browsers don't like it) */
-/* update on the 'some browsers don't like it issue from above:
- * this was probably due to missing 'Data Sub-block Terminator'
- * (byte 19) in the app_header */
-#define GIF_ADD_APP_HEADER // required to enable looping of animated gif
-
-typedef struct rgb_triplet {
- unsigned char r;
- unsigned char g;
- unsigned char b;
-} rgb_triplet;
-
-/* we use the standard 216 color palette */
-
-/* this script was used to create the palette:
- * for r in 00 33 66 99 cc ff; do
- * for g in 00 33 66 99 cc ff; do
- * echo -n " "
- * for b in 00 33 66 99 cc ff; do
- * echo -n "{ 0x$r, 0x$g, 0x$b }, "
- * done
- * echo ""
- * done
- * done
- */
-
-static const rgb_triplet gif_clut[216] = {
- { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x33 }, { 0x00, 0x00, 0x66 }, { 0x00, 0x00, 0x99 }, { 0x00, 0x00, 0xcc }, { 0x00, 0x00, 0xff },
- { 0x00, 0x33, 0x00 }, { 0x00, 0x33, 0x33 }, { 0x00, 0x33, 0x66 }, { 0x00, 0x33, 0x99 }, { 0x00, 0x33, 0xcc }, { 0x00, 0x33, 0xff },
- { 0x00, 0x66, 0x00 }, { 0x00, 0x66, 0x33 }, { 0x00, 0x66, 0x66 }, { 0x00, 0x66, 0x99 }, { 0x00, 0x66, 0xcc }, { 0x00, 0x66, 0xff },
- { 0x00, 0x99, 0x00 }, { 0x00, 0x99, 0x33 }, { 0x00, 0x99, 0x66 }, { 0x00, 0x99, 0x99 }, { 0x00, 0x99, 0xcc }, { 0x00, 0x99, 0xff },
- { 0x00, 0xcc, 0x00 }, { 0x00, 0xcc, 0x33 }, { 0x00, 0xcc, 0x66 }, { 0x00, 0xcc, 0x99 }, { 0x00, 0xcc, 0xcc }, { 0x00, 0xcc, 0xff },
- { 0x00, 0xff, 0x00 }, { 0x00, 0xff, 0x33 }, { 0x00, 0xff, 0x66 }, { 0x00, 0xff, 0x99 }, { 0x00, 0xff, 0xcc }, { 0x00, 0xff, 0xff },
- { 0x33, 0x00, 0x00 }, { 0x33, 0x00, 0x33 }, { 0x33, 0x00, 0x66 }, { 0x33, 0x00, 0x99 }, { 0x33, 0x00, 0xcc }, { 0x33, 0x00, 0xff },
- { 0x33, 0x33, 0x00 }, { 0x33, 0x33, 0x33 }, { 0x33, 0x33, 0x66 }, { 0x33, 0x33, 0x99 }, { 0x33, 0x33, 0xcc }, { 0x33, 0x33, 0xff },
- { 0x33, 0x66, 0x00 }, { 0x33, 0x66, 0x33 }, { 0x33, 0x66, 0x66 }, { 0x33, 0x66, 0x99 }, { 0x33, 0x66, 0xcc }, { 0x33, 0x66, 0xff },
- { 0x33, 0x99, 0x00 }, { 0x33, 0x99, 0x33 }, { 0x33, 0x99, 0x66 }, { 0x33, 0x99, 0x99 }, { 0x33, 0x99, 0xcc }, { 0x33, 0x99, 0xff },
- { 0x33, 0xcc, 0x00 }, { 0x33, 0xcc, 0x33 }, { 0x33, 0xcc, 0x66 }, { 0x33, 0xcc, 0x99 }, { 0x33, 0xcc, 0xcc }, { 0x33, 0xcc, 0xff },
- { 0x33, 0xff, 0x00 }, { 0x33, 0xff, 0x33 }, { 0x33, 0xff, 0x66 }, { 0x33, 0xff, 0x99 }, { 0x33, 0xff, 0xcc }, { 0x33, 0xff, 0xff },
- { 0x66, 0x00, 0x00 }, { 0x66, 0x00, 0x33 }, { 0x66, 0x00, 0x66 }, { 0x66, 0x00, 0x99 }, { 0x66, 0x00, 0xcc }, { 0x66, 0x00, 0xff },
- { 0x66, 0x33, 0x00 }, { 0x66, 0x33, 0x33 }, { 0x66, 0x33, 0x66 }, { 0x66, 0x33, 0x99 }, { 0x66, 0x33, 0xcc }, { 0x66, 0x33, 0xff },
- { 0x66, 0x66, 0x00 }, { 0x66, 0x66, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x66, 0x66, 0x99 }, { 0x66, 0x66, 0xcc }, { 0x66, 0x66, 0xff },
- { 0x66, 0x99, 0x00 }, { 0x66, 0x99, 0x33 }, { 0x66, 0x99, 0x66 }, { 0x66, 0x99, 0x99 }, { 0x66, 0x99, 0xcc }, { 0x66, 0x99, 0xff },
- { 0x66, 0xcc, 0x00 }, { 0x66, 0xcc, 0x33 }, { 0x66, 0xcc, 0x66 }, { 0x66, 0xcc, 0x99 }, { 0x66, 0xcc, 0xcc }, { 0x66, 0xcc, 0xff },
- { 0x66, 0xff, 0x00 }, { 0x66, 0xff, 0x33 }, { 0x66, 0xff, 0x66 }, { 0x66, 0xff, 0x99 }, { 0x66, 0xff, 0xcc }, { 0x66, 0xff, 0xff },
- { 0x99, 0x00, 0x00 }, { 0x99, 0x00, 0x33 }, { 0x99, 0x00, 0x66 }, { 0x99, 0x00, 0x99 }, { 0x99, 0x00, 0xcc }, { 0x99, 0x00, 0xff },
- { 0x99, 0x33, 0x00 }, { 0x99, 0x33, 0x33 }, { 0x99, 0x33, 0x66 }, { 0x99, 0x33, 0x99 }, { 0x99, 0x33, 0xcc }, { 0x99, 0x33, 0xff },
- { 0x99, 0x66, 0x00 }, { 0x99, 0x66, 0x33 }, { 0x99, 0x66, 0x66 }, { 0x99, 0x66, 0x99 }, { 0x99, 0x66, 0xcc }, { 0x99, 0x66, 0xff },
- { 0x99, 0x99, 0x00 }, { 0x99, 0x99, 0x33 }, { 0x99, 0x99, 0x66 }, { 0x99, 0x99, 0x99 }, { 0x99, 0x99, 0xcc }, { 0x99, 0x99, 0xff },
- { 0x99, 0xcc, 0x00 }, { 0x99, 0xcc, 0x33 }, { 0x99, 0xcc, 0x66 }, { 0x99, 0xcc, 0x99 }, { 0x99, 0xcc, 0xcc }, { 0x99, 0xcc, 0xff },
- { 0x99, 0xff, 0x00 }, { 0x99, 0xff, 0x33 }, { 0x99, 0xff, 0x66 }, { 0x99, 0xff, 0x99 }, { 0x99, 0xff, 0xcc }, { 0x99, 0xff, 0xff },
- { 0xcc, 0x00, 0x00 }, { 0xcc, 0x00, 0x33 }, { 0xcc, 0x00, 0x66 }, { 0xcc, 0x00, 0x99 }, { 0xcc, 0x00, 0xcc }, { 0xcc, 0x00, 0xff },
- { 0xcc, 0x33, 0x00 }, { 0xcc, 0x33, 0x33 }, { 0xcc, 0x33, 0x66 }, { 0xcc, 0x33, 0x99 }, { 0xcc, 0x33, 0xcc }, { 0xcc, 0x33, 0xff },
- { 0xcc, 0x66, 0x00 }, { 0xcc, 0x66, 0x33 }, { 0xcc, 0x66, 0x66 }, { 0xcc, 0x66, 0x99 }, { 0xcc, 0x66, 0xcc }, { 0xcc, 0x66, 0xff },
- { 0xcc, 0x99, 0x00 }, { 0xcc, 0x99, 0x33 }, { 0xcc, 0x99, 0x66 }, { 0xcc, 0x99, 0x99 }, { 0xcc, 0x99, 0xcc }, { 0xcc, 0x99, 0xff },
- { 0xcc, 0xcc, 0x00 }, { 0xcc, 0xcc, 0x33 }, { 0xcc, 0xcc, 0x66 }, { 0xcc, 0xcc, 0x99 }, { 0xcc, 0xcc, 0xcc }, { 0xcc, 0xcc, 0xff },
- { 0xcc, 0xff, 0x00 }, { 0xcc, 0xff, 0x33 }, { 0xcc, 0xff, 0x66 }, { 0xcc, 0xff, 0x99 }, { 0xcc, 0xff, 0xcc }, { 0xcc, 0xff, 0xff },
- { 0xff, 0x00, 0x00 }, { 0xff, 0x00, 0x33 }, { 0xff, 0x00, 0x66 }, { 0xff, 0x00, 0x99 }, { 0xff, 0x00, 0xcc }, { 0xff, 0x00, 0xff },
- { 0xff, 0x33, 0x00 }, { 0xff, 0x33, 0x33 }, { 0xff, 0x33, 0x66 }, { 0xff, 0x33, 0x99 }, { 0xff, 0x33, 0xcc }, { 0xff, 0x33, 0xff },
- { 0xff, 0x66, 0x00 }, { 0xff, 0x66, 0x33 }, { 0xff, 0x66, 0x66 }, { 0xff, 0x66, 0x99 }, { 0xff, 0x66, 0xcc }, { 0xff, 0x66, 0xff },
- { 0xff, 0x99, 0x00 }, { 0xff, 0x99, 0x33 }, { 0xff, 0x99, 0x66 }, { 0xff, 0x99, 0x99 }, { 0xff, 0x99, 0xcc }, { 0xff, 0x99, 0xff },
- { 0xff, 0xcc, 0x00 }, { 0xff, 0xcc, 0x33 }, { 0xff, 0xcc, 0x66 }, { 0xff, 0xcc, 0x99 }, { 0xff, 0xcc, 0xcc }, { 0xff, 0xcc, 0xff },
- { 0xff, 0xff, 0x00 }, { 0xff, 0xff, 0x33 }, { 0xff, 0xff, 0x66 }, { 0xff, 0xff, 0x99 }, { 0xff, 0xff, 0xcc }, { 0xff, 0xff, 0xff },
-};
+/* XXX: random value that shouldn't be taken into effect if there is no
+ * transparent color in the palette (the transparency bit will be set to 0) */
+#define DEFAULT_TRANSPARENCY_INDEX 0x1f
-/* GIF header */
-static int gif_image_write_header(AVIOContext *pb, int width, int height,
- int loop_count, uint32_t *palette)
+static int get_palette_transparency_index(const uint32_t *palette)
{
- int i;
- unsigned int v;
+ int transparent_color_index = -1;
+ unsigned i, smallest_alpha = 0xff;
- avio_write(pb, "GIF", 3);
- avio_write(pb, "89a", 3);
- avio_wl16(pb, width);
- avio_wl16(pb, height);
-
- avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
- avio_w8(pb, 0x1f); /* background color index */
- avio_w8(pb, 0); /* aspect ratio */
-
- /* the global palette */
- if (!palette) {
- avio_write(pb, (const unsigned char *)gif_clut, 216 * 3);
- for (i = 0; i < ((256 - 216) * 3); i++)
- avio_w8(pb, 0);
- } else {
- for (i = 0; i < 256; i++) {
- v = palette[i];
- avio_w8(pb, (v >> 16) & 0xff);
- avio_w8(pb, (v >> 8) & 0xff);
- avio_w8(pb, (v) & 0xff);
- }
- }
+ if (!palette)
+ return -1;
- /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated
- * GIF, see http://members.aol.com/royalef/gifabout.htm#net-extension
- *
- * byte 1 : 33 (hex 0x21) GIF Extension code
- * byte 2 : 255 (hex 0xFF) Application Extension Label
- * byte 3 : 11 (hex (0x0B) Length of Application Block
- * (eleven bytes of data to follow)
- * bytes 4 to 11 : "NETSCAPE"
- * bytes 12 to 14 : "2.0"
- * byte 15 : 3 (hex 0x03) Length of Data Sub-Block
- * (three bytes of data to follow)
- * byte 16 : 1 (hex 0x01)
- * bytes 17 to 18 : 0 to 65535, an unsigned integer in
- * lo-hi byte format. This indicate the
- * number of iterations the loop should
- * be executed.
- * bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator
- */
-
- /* application extension header */
-#ifdef GIF_ADD_APP_HEADER
- if (loop_count >= 0 && loop_count <= 65535) {
- avio_w8(pb, 0x21);
- avio_w8(pb, 0xff);
- avio_w8(pb, 0x0b);
- // bytes 4 to 14
- avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
- avio_w8(pb, 0x03); // byte 15
- avio_w8(pb, 0x01); // byte 16
- avio_wl16(pb, (uint16_t)loop_count);
- avio_w8(pb, 0x00); // byte 19
+ for (i = 0; i < AVPALETTE_COUNT; i++) {
+ const uint32_t v = palette[i];
+ if (v >> 24 < smallest_alpha) {
+ smallest_alpha = v >> 24;
+ transparent_color_index = i;
+ }
}
-#endif
- return 0;
+ return smallest_alpha < 128 ? transparent_color_index : -1;
}
-/* this is maybe slow, but allows for extensions */
-static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
-{
- return (((r) / 47) % 6) * 6 * 6 + (((g) / 47) % 6) * 6 + (((b) / 47) % 6);
-}
-
-static int gif_image_write_image(AVIOContext *pb,
- int x1, int y1, int width, int height,
- const uint8_t *buf, int linesize, int pix_fmt)
+static int gif_image_write_header(AVIOContext *pb, const AVCodecContext *avctx,
+ int loop_count, uint32_t *palette)
{
- PutBitContext p;
- uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
- int i, left, w, v;
- const uint8_t *ptr;
- /* image block */
-
- avio_w8(pb, 0x2c);
- avio_wl16(pb, x1);
- avio_wl16(pb, y1);
- avio_wl16(pb, width);
- avio_wl16(pb, height);
- avio_w8(pb, 0x00); /* flags */
- /* no local clut */
+ int i;
+ int64_t aspect = 0;
+ const AVRational sar = avctx->sample_aspect_ratio;
- avio_w8(pb, 0x08);
+ if (sar.num > 0 && sar.den > 0) {
+ aspect = sar.num * 64LL / sar.den - 15;
+ if (aspect < 0 || aspect > 255)
+ aspect = 0;
+ }
- left = width * height;
+ avio_write(pb, "GIF", 3);
+ avio_write(pb, "89a", 3);
+ avio_wl16(pb, avctx->width);
+ avio_wl16(pb, avctx->height);
- init_put_bits(&p, buffer, 130);
+ if (palette) {
+ const int bcid = get_palette_transparency_index(palette);
-/*
- * the thing here is the bitstream is written as little packets, with a size
- * byte before but it's still the same bitstream between packets (no flush !)
- */
- ptr = buf;
- w = width;
- while (left > 0) {
- put_bits(&p, 9, 0x0100); /* clear code */
-
- for (i = (left < GIF_CHUNKS) ? left : GIF_CHUNKS; i; i--) {
- if (pix_fmt == AV_PIX_FMT_RGB24) {
- v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
- ptr += 3;
- } else {
- v = *ptr++;
- }
- put_bits(&p, 9, v);
- if (--w == 0) {
- w = width;
- buf += linesize;
- ptr = buf;
- }
+ avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */
+ avio_w8(pb, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid); /* background color index */
+ avio_w8(pb, aspect);
+ for (i = 0; i < 256; i++) {
+ const uint32_t v = palette[i] & 0xffffff;
+ avio_wb24(pb, v);
}
+ } else {
+ avio_w8(pb, 0); /* flags */
+ avio_w8(pb, 0); /* background color index */
+ avio_w8(pb, aspect);
+ }
- if (left <= GIF_CHUNKS) {
- put_bits(&p, 9, 0x101); /* end of stream */
- flush_put_bits(&p);
- }
- if (put_bits_ptr(&p) - p.buf > 0) {
- avio_w8(pb, put_bits_ptr(&p) - p.buf); /* byte count of the packet */
- avio_write(pb, p.buf, put_bits_ptr(&p) - p.buf); /* the actual buffer */
- p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
- }
- left -= GIF_CHUNKS;
+
+ if (loop_count >= 0 ) {
+ /* "NETSCAPE EXTENSION" for looped animation GIF */
+ avio_w8(pb, 0x21); /* GIF Extension code */
+ avio_w8(pb, 0xff); /* Application Extension Label */
+ avio_w8(pb, 0x0b); /* Length of Application Block */
+ avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1);
+ avio_w8(pb, 0x03); /* Length of Data Sub-Block */
+ avio_w8(pb, 0x01);
+ avio_wl16(pb, (uint16_t)loop_count);
+ avio_w8(pb, 0x00); /* Data Sub-block Terminator */
}
- avio_w8(pb, 0x00); /* end of image block */
+ avio_flush(pb);
return 0;
}
typedef struct GIFContext {
- AVClass *class; /** Class for private options. */
- int64_t time, file_time;
- uint8_t buffer[100]; /* data chunks */
+ AVClass *class;
int loop;
+ int last_delay;
+ AVPacket *prev_pkt;
+ int duration;
} GIFContext;
static int gif_write_header(AVFormatContext *s)
{
GIFContext *gif = s->priv_data;
- AVIOContext *pb = s->pb;
- AVCodecContext *enc, *video_enc;
- int i, width, height /*, rate*/;
+ AVCodecContext *video_enc;
+ uint32_t palette[AVPALETTE_COUNT];
-/* XXX: do we reject audio streams or just ignore them ?
- * if (s->nb_streams > 1)
- * return -1;
- */
- gif->time = 0;
- gif->file_time = 0;
-
- video_enc = NULL;
- for (i = 0; i < s->nb_streams; i++) {
- enc = s->streams[i]->codec;
- if (enc->codec_type != AVMEDIA_TYPE_AUDIO)
- video_enc = enc;
+ if (s->nb_streams != 1 ||
+ s->streams[0]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
+ s->streams[0]->codec->codec_id != AV_CODEC_ID_GIF) {
+ av_log(s, AV_LOG_ERROR,
+ "GIF muxer supports only a single video GIF stream.\n");
+ return AVERROR(EINVAL);
}
- if (!video_enc) {
- av_free(gif);
- return -1;
- } else {
- width = video_enc->width;
- height = video_enc->height;
-// rate = video_enc->time_base.den;
- }
+ video_enc = s->streams[0]->codec;
- if (video_enc->pix_fmt != AV_PIX_FMT_RGB24) {
- av_log(s, AV_LOG_ERROR,
- "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n");
- return AVERROR(EIO);
+ avpriv_set_pts_info(s->streams[0], 64, 1, 100);
+ if (avpriv_set_systematic_pal2(palette, video_enc->pix_fmt) < 0) {
+ av_assert0(video_enc->pix_fmt == AV_PIX_FMT_PAL8);
+ /* delay header writing: we wait for the first palette to put it
+ * globally */
+ } else {
+ gif_image_write_header(s->pb, video_enc, gif->loop, palette);
}
- gif_image_write_header(pb, width, height, gif->loop, NULL);
-
- avio_flush(s->pb);
return 0;
}
-static int gif_write_video(AVFormatContext *s, AVCodecContext *enc,
- const uint8_t *buf, int size)
+static int flush_packet(AVFormatContext *s, AVPacket *new)
{
+ GIFContext *gif = s->priv_data;
+ int size, bcid;
AVIOContext *pb = s->pb;
- int jiffies;
+ const uint32_t *palette;
+ AVPacket *pkt = gif->prev_pkt;
+
+ if (!pkt)
+ return 0;
+
+ /* Mark one colour as transparent if the input palette contains at least
+ * one colour that is more than 50% transparent. */
+ palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size);
+ if (palette && size != AVPALETTE_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ bcid = get_palette_transparency_index(palette);
+
+ if (new && new->pts != AV_NOPTS_VALUE)
+ gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts);
+ else if (!new && gif->last_delay >= 0)
+ gif->duration = gif->last_delay;
/* graphic control extension block */
avio_w8(pb, 0x21);
avio_w8(pb, 0xf9);
avio_w8(pb, 0x04); /* block size */
- avio_w8(pb, 0x04); /* flags */
-
- /* 1 jiffy is 1/70 s */
- /* the delay_time field indicates the number of jiffies - 1 */
- /* XXX: should use delay, in order to be more accurate */
- /* instead of using the same rounded value each time */
- /* XXX: don't even remember if I really use it for now */
- jiffies = (70 * enc->time_base.num / enc->time_base.den) - 1;
-
- avio_wl16(pb, jiffies);
-
- avio_w8(pb, 0x1f); /* transparent color index */
+ avio_w8(pb, 1<<2 | (bcid >= 0));
+ avio_wl16(pb, gif->duration);
+ avio_w8(pb, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid);
avio_w8(pb, 0x00);
- gif_image_write_image(pb, 0, 0, enc->width, enc->height,
- buf, enc->width * 3, AV_PIX_FMT_RGB24);
+ avio_write(pb, pkt->data, pkt->size);
+
+ av_free_packet(gif->prev_pkt);
+ if (new)
+ av_copy_packet(gif->prev_pkt, new);
return 0;
}
static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
{
- AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
- if (codec->codec_type == AVMEDIA_TYPE_AUDIO)
- return 0; /* just ignore audio */
- else
- return gif_write_video(s, codec, pkt->data, pkt->size);
+ GIFContext *gif = s->priv_data;
+ const AVCodecContext *video_enc = s->streams[0]->codec;
+
+ if (!gif->prev_pkt) {
+ gif->prev_pkt = av_malloc(sizeof(*gif->prev_pkt));
+ if (!gif->prev_pkt)
+ return AVERROR(ENOMEM);
+
+ /* Write the first palette as global palette */
+ if (video_enc->pix_fmt == AV_PIX_FMT_PAL8) {
+ int size;
+ void *palette = av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size);
+
+ if (!palette) {
+ av_log(s, AV_LOG_ERROR, "PAL8 packet is missing palette in extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (size != AVPALETTE_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n");
+ return AVERROR_INVALIDDATA;
+ }
+ gif_image_write_header(s->pb, video_enc, gif->loop, palette);
+ }
+
+ return av_copy_packet(gif->prev_pkt, pkt);
+ }
+ return flush_packet(s, pkt);
}
static int gif_write_trailer(AVFormatContext *s)
{
+ GIFContext *gif = s->priv_data;
AVIOContext *pb = s->pb;
+ flush_packet(s, NULL);
+ av_freep(&gif->prev_pkt);
avio_w8(pb, 0x3b);
return 0;
@@ -353,8 +226,10 @@ static int gif_write_trailer(AVFormatContext *s)
#define OFFSET(x) offsetof(GIFContext, x)
#define ENC AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "loop", "Number of times to loop the output.", OFFSET(loop),
- AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 65535, ENC },
+ { "loop", "Number of times to loop the output: -1 - no loop, 0 - infinite loop", OFFSET(loop),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, -1, 65535, ENC },
+ { "final_delay", "Force delay (in centiseconds) after the last frame", OFFSET(last_delay),
+ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 65535, ENC },
{ NULL },
};
@@ -372,9 +247,10 @@ AVOutputFormat ff_gif_muxer = {
.extensions = "gif",
.priv_data_size = sizeof(GIFContext),
.audio_codec = AV_CODEC_ID_NONE,
- .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .video_codec = AV_CODEC_ID_GIF,
.write_header = gif_write_header,
.write_packet = gif_write_packet,
.write_trailer = gif_write_trailer,
.priv_class = &gif_muxer_class,
+ .flags = AVFMT_VARIABLE_FPS,
};
diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c
new file mode 100644
index 0000000000..bb4c6ec6e6
--- /dev/null
+++ b/libavformat/gifdec.c
@@ -0,0 +1,337 @@
+/*
+ * GIF demuxer
+ * Copyright (c) 2012 Vitaliy E Sugrobov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * GIF demuxer.
+ */
+
+#include "avformat.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+#include "libavcodec/gif.h"
+
+typedef struct GIFDemuxContext {
+ const AVClass *class;
+ /**
+ * Time span in hundredths of second before
+ * the next frame should be drawn on screen.
+ */
+ int delay;
+ /**
+ * Minimum allowed delay between frames in hundredths of
+ * second. Values below this threshold considered to be
+ * invalid and set to value of default_delay.
+ */
+ int min_delay;
+ int max_delay;
+ int default_delay;
+
+ /**
+ * loop options
+ */
+ int total_iter;
+ int iter_count;
+ int ignore_loop;
+} GIFDemuxContext;
+
+/**
+ * Major web browsers display gifs at ~10-15fps when rate
+ * is not explicitly set or have too low values. We assume default rate to be 10.
+ * Default delay = 100hundredths of second / 10fps = 10hos per frame.
+ */
+#define GIF_DEFAULT_DELAY 10
+/**
+ * By default delay values less than this threshold considered to be invalid.
+ */
+#define GIF_MIN_DELAY 2
+
+static int gif_probe(AVProbeData *p)
+{
+ /* check magick */
+ if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6))
+ return 0;
+
+ /* width or height contains zero? */
+ if (!AV_RL16(&p->buf[6]) || !AV_RL16(&p->buf[8]))
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+static int resync(AVIOContext *pb)
+{
+ int i;
+ for (i = 0; i < 6; i++) {
+ int b = avio_r8(pb);
+ if (b != gif87a_sig[i] && b != gif89a_sig[i])
+ i = -(b != 'G');
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+ }
+ return 0;
+}
+
+static int gif_read_header(AVFormatContext *s)
+{
+ GIFDemuxContext *gdc = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ int width, height, ret;
+
+ if ((ret = resync(pb)) < 0)
+ return ret;
+
+ gdc->delay = gdc->default_delay;
+ width = avio_rl16(pb);
+ height = avio_rl16(pb);
+
+ if (width == 0 || height == 0)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ /* GIF format operates with time in "hundredths of second",
+ * therefore timebase is 1/100 */
+ avpriv_set_pts_info(st, 64, 1, 100);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_GIF;
+ st->codec->width = width;
+ st->codec->height = height;
+
+ /* jump to start because gif decoder needs header data too */
+ if (avio_seek(pb, 0, SEEK_SET) != 0)
+ return AVERROR(EIO);
+
+ return 0;
+}
+
+static int gif_skip_subblocks(AVIOContext *pb)
+{
+ int sb_size, ret = 0;
+
+ while (0x00 != (sb_size = avio_r8(pb))) {
+ if ((ret = avio_skip(pb, sb_size)) < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int gif_read_ext(AVFormatContext *s)
+{
+ GIFDemuxContext *gdc = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int sb_size, ext_label = avio_r8(pb);
+ int ret;
+
+ if (ext_label == GIF_GCE_EXT_LABEL) {
+ if ((sb_size = avio_r8(pb)) < 4) {
+ av_log(s, AV_LOG_FATAL, "Graphic Control Extension block's size less than 4.\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* skip packed fields */
+ if ((ret = avio_skip(pb, 1)) < 0)
+ return ret;
+
+ gdc->delay = avio_rl16(pb);
+
+ if (gdc->delay < gdc->min_delay)
+ gdc->delay = gdc->default_delay;
+ gdc->delay = FFMIN(gdc->delay, gdc->max_delay);
+
+ /* skip the rest of the Graphic Control Extension block */
+ if ((ret = avio_skip(pb, sb_size - 3)) < 0 )
+ return ret;
+ } else if (ext_label == GIF_APP_EXT_LABEL) {
+ uint8_t data[256];
+
+ sb_size = avio_r8(pb);
+ ret = avio_read(pb, data, sb_size);
+ if (ret < 0 || !sb_size)
+ return ret;
+
+ if (sb_size == strlen(NETSCAPE_EXT_STR)) {
+ sb_size = avio_r8(pb);
+ ret = avio_read(pb, data, sb_size);
+ if (ret < 0 || !sb_size)
+ return ret;
+
+ if (sb_size == 3 && data[0] == 1) {
+ gdc->total_iter = AV_RL16(data+1);
+
+ if (gdc->total_iter == 0)
+ gdc->total_iter = -1;
+ }
+ }
+ }
+
+ if ((ret = gif_skip_subblocks(pb)) < 0)
+ return ret;
+
+ return 0;
+}
+
+static int gif_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ GIFDemuxContext *gdc = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int packed_fields, block_label, ct_size,
+ keyframe, frame_parsed = 0, ret;
+ int64_t frame_start = avio_tell(pb), frame_end;
+ unsigned char buf[6];
+
+ if ((ret = avio_read(pb, buf, 6)) == 6) {
+ keyframe = memcmp(buf, gif87a_sig, 6) == 0 ||
+ memcmp(buf, gif89a_sig, 6) == 0;
+ } else if (ret < 0) {
+ return ret;
+ } else {
+ keyframe = 0;
+ }
+
+ if (keyframe) {
+parse_keyframe:
+ /* skip 2 bytes of width and 2 of height */
+ if ((ret = avio_skip(pb, 4)) < 0)
+ return ret;
+
+ packed_fields = avio_r8(pb);
+
+ /* skip 1 byte of Background Color Index and 1 byte of Pixel Aspect Ratio */
+ if ((ret = avio_skip(pb, 2)) < 0)
+ return ret;
+
+ /* global color table presence */
+ if (packed_fields & 0x80) {
+ ct_size = 3 * (1 << ((packed_fields & 0x07) + 1));
+
+ if ((ret = avio_skip(pb, ct_size)) < 0)
+ return ret;
+ }
+ } else {
+ avio_seek(pb, -ret, SEEK_CUR);
+ ret = AVERROR_EOF;
+ }
+
+ while (GIF_TRAILER != (block_label = avio_r8(pb)) && !avio_feof(pb)) {
+ if (block_label == GIF_EXTENSION_INTRODUCER) {
+ if ((ret = gif_read_ext (s)) < 0 )
+ goto resync;
+ } else if (block_label == GIF_IMAGE_SEPARATOR) {
+ /* skip to last byte of Image Descriptor header */
+ if ((ret = avio_skip(pb, 8)) < 0)
+ return ret;
+
+ packed_fields = avio_r8(pb);
+
+ /* local color table presence */
+ if (packed_fields & 0x80) {
+ ct_size = 3 * (1 << ((packed_fields & 0x07) + 1));
+
+ if ((ret = avio_skip(pb, ct_size)) < 0)
+ return ret;
+ }
+
+ /* read LZW Minimum Code Size */
+ if (avio_r8(pb) < 1) {
+ av_log(s, AV_LOG_ERROR, "lzw minimum code size must be >= 1\n");
+ goto resync;
+ }
+
+ if ((ret = gif_skip_subblocks(pb)) < 0)
+ goto resync;
+
+ frame_end = avio_tell(pb);
+
+ if (avio_seek(pb, frame_start, SEEK_SET) != frame_start)
+ return AVERROR(EIO);
+
+ ret = av_get_packet(pb, pkt, frame_end - frame_start);
+ if (ret < 0)
+ return ret;
+
+ if (keyframe)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ pkt->stream_index = 0;
+ pkt->duration = gdc->delay;
+
+ /* Graphic Control Extension's scope is single frame.
+ * Remove its influence. */
+ gdc->delay = gdc->default_delay;
+ frame_parsed = 1;
+
+ break;
+ } else {
+ av_log(s, AV_LOG_ERROR, "invalid block label\n");
+resync:
+ if (!keyframe)
+ avio_seek(pb, frame_start, SEEK_SET);
+ if ((ret = resync(pb)) < 0)
+ return ret;
+ frame_start = avio_tell(pb) - 6;
+ keyframe = 1;
+ goto parse_keyframe;
+ }
+ }
+
+ if ((ret >= 0 && !frame_parsed) || ret == AVERROR_EOF) {
+ /* This might happen when there is no image block
+ * between extension blocks and GIF_TRAILER or EOF */
+ if (!gdc->ignore_loop && (block_label == GIF_TRAILER || avio_feof(pb))
+ && (gdc->total_iter < 0 || ++gdc->iter_count < gdc->total_iter))
+ return avio_seek(pb, 0, SEEK_SET);
+ return AVERROR_EOF;
+ } else
+ return ret;
+}
+
+static const AVOption options[] = {
+ { "min_delay" , "minimum valid delay between frames (in hundredths of second)", offsetof(GIFDemuxContext, min_delay) , AV_OPT_TYPE_INT, {.i64 = GIF_MIN_DELAY} , 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
+ { "max_gif_delay", "maximum valid delay between frames (in hundredths of seconds)", offsetof(GIFDemuxContext, max_delay) , AV_OPT_TYPE_INT, {.i64 = 65535} , 0, 65535 , AV_OPT_FLAG_DECODING_PARAM },
+ { "default_delay", "default delay between frames (in hundredths of second)" , offsetof(GIFDemuxContext, default_delay), AV_OPT_TYPE_INT, {.i64 = GIF_DEFAULT_DELAY}, 0, 100 * 60, AV_OPT_FLAG_DECODING_PARAM },
+ { "ignore_loop" , "ignore loop setting (netscape extension)" , offsetof(GIFDemuxContext, ignore_loop) , AV_OPT_TYPE_INT, {.i64 = 1} , 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass demuxer_class = {
+ .class_name = "GIF demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEMUXER,
+};
+
+AVInputFormat ff_gif_demuxer = {
+ .name = "gif",
+ .long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"),
+ .priv_data_size = sizeof(GIFDemuxContext),
+ .read_probe = gif_probe,
+ .read_header = gif_read_header,
+ .read_packet = gif_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+ .priv_class = &demuxer_class,
+};
diff --git a/libavformat/golomb_tab.c b/libavformat/golomb_tab.c
new file mode 100644
index 0000000000..063fae3647
--- /dev/null
+++ b/libavformat/golomb_tab.c
@@ -0,0 +1 @@
+#include "libavcodec/golomb.c"
diff --git a/libavformat/gopher.c b/libavformat/gopher.c
index 962fce798c..a5340d276c 100644
--- a/libavformat/gopher.c
+++ b/libavformat/gopher.c
@@ -5,20 +5,20 @@
*
* based on libavformat/http.c, Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/gsmdec.c b/libavformat/gsmdec.c
index e73aa0ddab..a9865dbee9 100644
--- a/libavformat/gsmdec.c
+++ b/libavformat/gsmdec.c
@@ -2,20 +2,20 @@
* RAW GSM demuxer
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,7 +48,6 @@ static int gsm_read_packet(AVFormatContext *s, AVPacket *pkt)
av_free_packet(pkt);
return ret < 0 ? ret : AVERROR(EIO);
}
- pkt->size = ret;
pkt->duration = 1;
pkt->pts = pkt->pos / GSM_BLOCK_SIZE;
@@ -81,7 +80,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass gsm_class = {
.class_name = "gsm demuxer",
.item_name = av_default_item_name,
.option = options,
@@ -97,5 +96,5 @@ AVInputFormat ff_gsm_demuxer = {
.flags = AVFMT_GENERIC_INDEX,
.extensions = "gsm",
.raw_codec_id = AV_CODEC_ID_GSM,
- .priv_class = &class,
+ .priv_class = &gsm_class,
};
diff --git a/libavformat/gxf.c b/libavformat/gxf.c
index 189584035b..d9b629d7de 100644
--- a/libavformat/gxf.c
+++ b/libavformat/gxf.c
@@ -2,20 +2,20 @@
* GXF demuxer.
* Copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,9 +33,31 @@ struct gxf_stream_info {
int64_t last_field;
AVRational frames_per_second;
int32_t fields_per_frame;
+ int64_t track_aux_data;
};
/**
+ * @brief parse gxf timecode and add it to metadata
+ */
+static int add_timecode_metadata(AVDictionary **pm, const char *key, uint32_t timecode, int fields_per_frame)
+{
+ char tmp[128];
+ int field = timecode & 0xff;
+ int frame = fields_per_frame ? field / fields_per_frame : field;
+ int second = (timecode >> 8) & 0xff;
+ int minute = (timecode >> 16) & 0xff;
+ int hour = (timecode >> 24) & 0x1f;
+ int drop = (timecode >> 29) & 1;
+ // bit 30: color_frame, unused
+ // ignore invalid time code
+ if (timecode >> 31)
+ return 0;
+ snprintf(tmp, sizeof(tmp), "%02d:%02d:%02d%c%02d",
+ hour, minute, second, drop ? ';' : ':', frame);
+ return av_dict_set(pm, key, tmp, 0);
+}
+
+/**
* @brief parses a packet header, extracting type and length
* @param pb AVIOContext to read header from
* @param type detected packet type is stored here
@@ -96,12 +118,10 @@ static int get_sindex(AVFormatContext *s, int id, int format) {
st->codec->codec_id = AV_CODEC_ID_MJPEG;
break;
case 13:
- case 15:
- st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = AV_CODEC_ID_DVVIDEO;
- break;
case 14:
+ case 15:
case 16:
+ case 25:
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_DVVIDEO;
break;
@@ -145,6 +165,12 @@ static int get_sindex(AVFormatContext *s, int id, int format) {
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
st->codec->sample_rate = 48000;
break;
+ case 26: /* AVCi50 / AVCi100 (AVC Intra) */
+ case 29: /* AVCHD */
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_H264;
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ break;
// timecode tracks:
case 7:
case 8:
@@ -152,6 +178,10 @@ static int get_sindex(AVFormatContext *s, int id, int format) {
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->codec->codec_id = AV_CODEC_ID_NONE;
break;
+ case 30:
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_DNXHD;
+ break;
default:
st->codec->codec_type = AVMEDIA_TYPE_UNKNOWN;
st->codec->codec_id = AV_CODEC_ID_NONE;
@@ -228,6 +258,7 @@ static AVRational fps_umf2avr(uint32_t flags) {
static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si) {
si->frames_per_second = (AVRational){0, 0};
si->fields_per_frame = 0;
+ si->track_aux_data = 0x80000000;
while (*len >= 2) {
GXFTrackTag tag = avio_r8(pb);
int tlen = avio_r8(pb);
@@ -241,7 +272,9 @@ static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si
si->frames_per_second = fps_tag2avr(value);
else if (tag == TRACK_FPF && (value == 1 || value == 2))
si->fields_per_frame = value;
- } else
+ } else if (tlen == 8 && tag == TRACK_AUX)
+ si->track_aux_data = avio_rl64(pb);
+ else
avio_skip(pb, tlen);
}
}
@@ -251,15 +284,16 @@ static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si
*/
static void gxf_read_index(AVFormatContext *s, int pkt_len) {
AVIOContext *pb = s->pb;
- AVStream *st = s->streams[0];
+ AVStream *st;
uint32_t fields_per_map = avio_rl32(pb);
uint32_t map_cnt = avio_rl32(pb);
int i;
pkt_len -= 8;
- if (s->flags & AVFMT_FLAG_IGNIDX) {
+ if ((s->flags & AVFMT_FLAG_IGNIDX) || !s->streams) {
avio_skip(pb, pkt_len);
return;
}
+ st = s->streams[0];
if (map_cnt > 1000) {
av_log(s, AV_LOG_ERROR,
"too many index entries %"PRIu32" (%"PRIx32")\n",
@@ -321,8 +355,6 @@ static int gxf_header(AVFormatContext *s) {
track_id = avio_r8(pb);
track_len = avio_rb16(pb);
len -= track_len;
- gxf_track_tags(pb, &track_len, si);
- avio_skip(pb, track_len);
if (!(track_type & 0x80)) {
av_log(s, AV_LOG_ERROR, "invalid track type %x\n", track_type);
continue;
@@ -333,6 +365,16 @@ static int gxf_header(AVFormatContext *s) {
continue;
}
track_id &= 0x3f;
+ gxf_track_tags(pb, &track_len, si);
+ // check for timecode tracks
+ if (track_type == 7 || track_type == 8 || track_type == 24) {
+ add_timecode_metadata(&s->metadata, "timecode",
+ si->track_aux_data & 0xffffffff,
+ si->fields_per_frame);
+
+ }
+ avio_skip(pb, track_len);
+
idx = get_sindex(s, track_id, track_type);
if (idx < 0) continue;
st = s->streams[idx];
@@ -367,10 +409,21 @@ static int gxf_header(AVFormatContext *s) {
avio_skip(pb, 0x30); // payload description
fps = fps_umf2avr(avio_rl32(pb));
if (!main_timebase.num || !main_timebase.den) {
+ av_log(s, AV_LOG_WARNING, "No FPS track tag, using UMF fps tag."
+ " This might give wrong results.\n");
// this may not always be correct, but simply the best we can get
main_timebase.num = fps.den;
main_timebase.den = fps.num * 2;
}
+
+ if (len >= 0x18) {
+ len -= 0x18;
+ avio_skip(pb, 0x10);
+ add_timecode_metadata(&s->metadata, "timecode_at_mark_in",
+ avio_rl32(pb), si->fields_per_frame);
+ add_timecode_metadata(&s->metadata, "timecode_at_mark_out",
+ avio_rl32(pb), si->fields_per_frame);
+ }
} else
av_log(s, AV_LOG_INFO, "UMF packet too short\n");
} else
@@ -389,7 +442,7 @@ static int gxf_header(AVFormatContext *s) {
#define READ_ONE() \
{ \
- if (!max_interval-- || pb->eof_reached) \
+ if (!max_interval-- || avio_feof(pb)) \
goto out; \
tmp = tmp << 8 | avio_r8(pb); \
}
@@ -451,7 +504,7 @@ static int gxf_packet(AVFormatContext *s, AVPacket *pkt) {
int field_nr, field_info, skip = 0;
int stream_index;
if (!parse_packet_header(pb, &pkt_type, &pkt_len)) {
- if (!pb->eof_reached)
+ if (!avio_feof(pb))
av_log(s, AV_LOG_ERROR, "sync lost\n");
return -1;
}
@@ -503,11 +556,11 @@ static int gxf_packet(AVFormatContext *s, AVPacket *pkt) {
return ret;
}
- return AVERROR(EIO);
+ return AVERROR_EOF;
}
static int gxf_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) {
- int res = 0;
+ int64_t res = 0;
uint64_t pos;
uint64_t maxlen = 100 * 1024 * 1024;
AVStream *st = s->streams[0];
diff --git a/libavformat/gxf.h b/libavformat/gxf.h
index c1ac399458..dcdcdefc2d 100644
--- a/libavformat/gxf.h
+++ b/libavformat/gxf.h
@@ -2,20 +2,20 @@
* GXF demuxer
* copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c
index fea1d5d818..12031f7cd9 100644
--- a/libavformat/gxfenc.c
+++ b/libavformat/gxfenc.c
@@ -2,25 +2,28 @@
* GXF muxer.
* Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/intfloat.h"
+#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
+#include "libavutil/timecode.h"
#include "avformat.h"
#include "internal.h"
#include "gxf.h"
@@ -28,6 +31,18 @@
#define GXF_AUDIO_PACKET_SIZE 65536
+#define GXF_TIMECODE(c, d, h, m, s, f) \
+ ((c) << 30 | (d) << 29 | (h) << 24 | (m) << 16 | (s) << 8 | (f))
+
+typedef struct GXFTimecode{
+ int hh;
+ int mm;
+ int ss;
+ int ff;
+ int color;
+ int drop;
+} GXFTimecode;
+
typedef struct GXFStreamContext {
AudioInterleaveContext aic;
uint32_t track_type;
@@ -48,6 +63,7 @@ typedef struct GXFStreamContext {
} GXFStreamContext;
typedef struct GXFContext {
+ AVClass *av_class;
uint32_t nb_fields;
uint16_t audio_tracks;
uint16_t mpeg_tracks;
@@ -66,6 +82,7 @@ typedef struct GXFContext {
uint64_t *map_offsets; ///< offset of map packets
unsigned map_offsets_nb;
unsigned packet_count;
+ GXFTimecode tc;
} GXFContext;
static const struct {
@@ -188,33 +205,50 @@ static int gxf_write_mpeg_auxiliary(AVIOContext *pb, AVStream *st)
else
starting_line = 23; // default PAL
- size = snprintf(buffer, 1024, "Ver 1\nBr %.6f\nIpg 1\nPpi %d\nBpiop %d\n"
+ size = snprintf(buffer, sizeof(buffer), "Ver 1\nBr %.6f\nIpg 1\nPpi %d\nBpiop %d\n"
"Pix 0\nCf %d\nCg %d\nSl %d\nnl16 %d\nVi 1\nf1 1\n",
(float)st->codec->bit_rate, sc->p_per_gop, sc->b_per_i_or_p,
st->codec->pix_fmt == AV_PIX_FMT_YUV422P ? 2 : 1, sc->first_gop_closed == 1,
starting_line, (st->codec->height + 15) / 16);
+ av_assert0(size < sizeof(buffer));
avio_w8(pb, TRACK_MPG_AUX);
avio_w8(pb, size + 1);
avio_write(pb, (uint8_t *)buffer, size + 1);
return size + 3;
}
-static int gxf_write_timecode_auxiliary(AVIOContext *pb, GXFStreamContext *sc)
+static int gxf_write_dv_auxiliary(AVIOContext *pb, AVStream *st)
{
- avio_w8(pb, 0); /* fields */
- avio_w8(pb, 0); /* seconds */
- avio_w8(pb, 0); /* minutes */
- avio_w8(pb, 0); /* flags + hours */
+ int64_t track_aux_data = 0;
+
+ avio_w8(pb, TRACK_AUX);
+ avio_w8(pb, 8);
+ if (st->codec->pix_fmt == AV_PIX_FMT_YUV420P)
+ track_aux_data |= 0x01; /* marks stream as DVCAM instead of DVPRO */
+ track_aux_data |= 0x40000000; /* aux data is valid */
+ avio_wl64(pb, track_aux_data);
+ return 8;
+}
+
+static int gxf_write_timecode_auxiliary(AVIOContext *pb, GXFContext *gxf)
+{
+ uint32_t timecode = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop,
+ gxf->tc.hh, gxf->tc.mm,
+ gxf->tc.ss, gxf->tc.ff);
+
+ avio_w8(pb, TRACK_AUX);
+ avio_w8(pb, 8);
+ avio_wl32(pb, timecode);
/* reserved */
- avio_wb32(pb, 0);
+ avio_wl32(pb, 0);
return 8;
}
static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc, int index)
{
+ GXFContext *gxf = s->priv_data;
AVIOContext *pb = s->pb;
int64_t pos;
- int mpeg = sc->track_type == 4 || sc->track_type == 9;
/* track description section */
avio_w8(pb, sc->media_type + 0x80);
@@ -230,13 +264,21 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc,
avio_wb16(pb, sc->media_info);
avio_w8(pb, 0);
- if (!mpeg) {
- /* auxiliary information */
- avio_w8(pb, TRACK_AUX);
- avio_w8(pb, 8);
- if (sc->track_type == 3)
- gxf_write_timecode_auxiliary(pb, sc);
- else
+ switch (sc->track_type) {
+ case 3: /* timecode */
+ gxf_write_timecode_auxiliary(pb, gxf);
+ break;
+ case 4: /* MPEG2 */
+ case 9: /* MPEG1 */
+ gxf_write_mpeg_auxiliary(pb, s->streams[index]);
+ break;
+ case 5: /* DV25 */
+ case 6: /* DV50 */
+ gxf_write_dv_auxiliary(pb, s->streams[index]);
+ break;
+ default:
+ avio_w8(pb, TRACK_AUX);
+ avio_w8(pb, 8);
avio_wl64(pb, 0);
}
@@ -245,9 +287,6 @@ static int gxf_write_track_description(AVFormatContext *s, GXFStreamContext *sc,
avio_w8(pb, 4);
avio_wb32(pb, 0);
- if (mpeg)
- gxf_write_mpeg_auxiliary(pb, s->streams[index]);
-
/* frame rate */
avio_w8(pb, TRACK_FPS);
avio_w8(pb, 4);
@@ -398,25 +437,36 @@ static int gxf_write_umf_material_description(AVFormatContext *s)
int timecode_base = gxf->time_base.den == 60000 ? 60 : 50;
int64_t timestamp = 0;
AVDictionaryEntry *t;
- uint32_t timecode;
+ uint64_t nb_fields;
+ uint32_t timecode_in; // timecode at mark in
+ uint32_t timecode_out; // timecode at mark out
if (t = av_dict_get(s->metadata, "creation_time", NULL, 0))
timestamp = ff_iso8601_to_unix_time(t->value);
- // XXX drop frame
- timecode =
- gxf->nb_fields / (timecode_base * 3600) % 24 << 24 | // hours
- gxf->nb_fields / (timecode_base * 60) % 60 << 16 | // minutes
- gxf->nb_fields / timecode_base % 60 << 8 | // seconds
- gxf->nb_fields % timecode_base; // fields
+ timecode_in = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop,
+ gxf->tc.hh, gxf->tc.mm,
+ gxf->tc.ss, gxf->tc.ff);
+
+ nb_fields = gxf->nb_fields +
+ gxf->tc.hh * (timecode_base * 3600) +
+ gxf->tc.mm * (timecode_base * 60) +
+ gxf->tc.ss * timecode_base +
+ gxf->tc.ff;
+
+ timecode_out = GXF_TIMECODE(gxf->tc.color, gxf->tc.drop,
+ nb_fields / (timecode_base * 3600) % 24,
+ nb_fields / (timecode_base * 60) % 60,
+ nb_fields / timecode_base % 60,
+ nb_fields % timecode_base);
avio_wl32(pb, gxf->flags);
avio_wl32(pb, gxf->nb_fields); /* length of the longest track */
avio_wl32(pb, gxf->nb_fields); /* length of the shortest track */
avio_wl32(pb, 0); /* mark in */
avio_wl32(pb, gxf->nb_fields); /* mark out */
- avio_wl32(pb, 0); /* timecode mark in */
- avio_wl32(pb, timecode); /* timecode mark out */
+ avio_wl32(pb, timecode_in); /* timecode mark in */
+ avio_wl32(pb, timecode_out); /* timecode mark out */
avio_wl64(pb, timestamp); /* modification time */
avio_wl64(pb, timestamp); /* creation time */
avio_wl16(pb, 0); /* reserved */
@@ -491,9 +541,9 @@ static int gxf_write_umf_media_mpeg(AVIOContext *pb, AVStream *st)
return 32;
}
-static int gxf_write_umf_media_timecode(AVIOContext *pb, GXFStreamContext *sc)
+static int gxf_write_umf_media_timecode(AVIOContext *pb, int drop)
{
- avio_wl32(pb, 1); /* non drop frame */
+ avio_wl32(pb, drop); /* drop frame */
avio_wl32(pb, 0); /* reserved */
avio_wl32(pb, 0); /* reserved */
avio_wl32(pb, 0); /* reserved */
@@ -504,13 +554,20 @@ static int gxf_write_umf_media_timecode(AVIOContext *pb, GXFStreamContext *sc)
return 32;
}
-static int gxf_write_umf_media_dv(AVIOContext *pb, GXFStreamContext *sc)
+static int gxf_write_umf_media_dv(AVIOContext *pb, GXFStreamContext *sc, AVStream *st)
{
- int i;
-
- for (i = 0; i < 8; i++) {
- avio_wb32(pb, 0);
- }
+ int dv_umf_data = 0;
+
+ if (st->codec->pix_fmt == AV_PIX_FMT_YUV420P)
+ dv_umf_data |= 0x20; /* marks as DVCAM instead of DVPRO */
+ avio_wl32(pb, dv_umf_data);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
return 32;
}
@@ -562,7 +619,7 @@ static int gxf_write_umf_media_description(AVFormatContext *s)
avio_wl32(pb, 0); /* reserved */
if (sc == &gxf->timecode_track)
- gxf_write_umf_media_timecode(pb, sc); /* 8 0bytes */
+ gxf_write_umf_media_timecode(pb, gxf->tc.drop);
else {
AVStream *st = s->streams[i];
switch (st->codec->codec_id) {
@@ -574,7 +631,7 @@ static int gxf_write_umf_media_description(AVFormatContext *s)
gxf_write_umf_media_audio(pb, sc);
break;
case AV_CODEC_ID_DVVIDEO:
- gxf_write_umf_media_dv(pb, sc);
+ gxf_write_umf_media_dv(pb, sc, st);
break;
}
}
@@ -625,6 +682,25 @@ static void gxf_init_timecode_track(GXFStreamContext *sc, GXFStreamContext *vsc)
sc->fields = vsc->fields;
}
+static int gxf_init_timecode(AVFormatContext *s, GXFTimecode *tc, const char *tcstr, int fields)
+{
+ char c;
+
+ if (sscanf(tcstr, "%d:%d:%d%c%d", &tc->hh, &tc->mm, &tc->ss, &c, &tc->ff) != 5) {
+ av_log(s, AV_LOG_ERROR, "unable to parse timecode, "
+ "syntax: hh:mm:ss[:;.]ff\n");
+ return -1;
+ }
+
+ tc->color = 0;
+ tc->drop = c != ':';
+
+ if (fields == 2)
+ tc->ff = tc->ff * 2;
+
+ return 0;
+}
+
static int gxf_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
@@ -632,9 +708,11 @@ static int gxf_write_header(AVFormatContext *s)
GXFStreamContext *vsc = NULL;
uint8_t tracks[255] = {0};
int i, media_info = 0;
+ int ret;
+ AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
if (!pb->seekable) {
- av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome");
+ av_log(s, AV_LOG_ERROR, "gxf muxer does not support streamed output, patch welcome\n");
return -1;
}
@@ -692,6 +770,8 @@ static int gxf_write_header(AVFormatContext *s)
"gxf muxer only accepts PAL or NTSC resolutions currently\n");
return -1;
}
+ if (!tcr)
+ tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
avpriv_set_pts_info(st, 64, gxf->time_base.num, gxf->time_base.den);
if (gxf_find_lines_index(st) < 0)
sc->lines_index = -1;
@@ -743,10 +823,14 @@ static int gxf_write_header(AVFormatContext *s)
if (ff_audio_interleave_init(s, GXF_samples_per_frame, (AVRational){ 1, 48000 }) < 0)
return -1;
+ if (tcr && vsc)
+ gxf_init_timecode(s, &gxf->tc, tcr->value, vsc->fields);
+
gxf_init_timecode_track(&gxf->timecode_track, vsc);
gxf->flags |= 0x200000; // time code track is non-drop frame
- gxf_write_map_packet(s, 0);
+ if ((ret = gxf_write_map_packet(s, 0)) < 0)
+ return ret;
gxf_write_flt_packet(s);
gxf_write_umf_packet(s);
@@ -770,6 +854,7 @@ static int gxf_write_trailer(AVFormatContext *s)
AVIOContext *pb = s->pb;
int64_t end;
int i;
+ int ret;
ff_audio_interleave_close(s);
@@ -777,14 +862,16 @@ static int gxf_write_trailer(AVFormatContext *s)
end = avio_tell(pb);
avio_seek(pb, 0, SEEK_SET);
/* overwrite map, flt and umf packets with new values */
- gxf_write_map_packet(s, 1);
+ if ((ret = gxf_write_map_packet(s, 1)) < 0)
+ return ret;
gxf_write_flt_packet(s);
gxf_write_umf_packet(s);
avio_flush(pb);
/* update duration in all map packets */
for (i = 1; i < gxf->map_offsets_nb; i++) {
avio_seek(pb, gxf->map_offsets[i], SEEK_SET);
- gxf_write_map_packet(s, 1);
+ if ((ret = gxf_write_map_packet(s, 1)) < 0)
+ return ret;
avio_flush(pb);
}
@@ -862,7 +949,8 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *st = s->streams[pkt->stream_index];
int64_t pos = avio_tell(pb);
int padding = 0;
- int packet_start_offset = avio_tell(pb) / 1024;
+ unsigned packet_start_offset = avio_tell(pb) / 1024;
+ int ret;
gxf_write_packet_header(pb, PKT_MEDIA);
if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO && pkt->size % 4) /* MPEG-2 frames must be padded */
@@ -880,6 +968,7 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
gxf->flt_entries_nb + 500,
sizeof(*gxf->flt_entries))) < 0) {
gxf->flt_entries_nb = 0;
+ gxf->nb_fields = 0;
av_log(s, AV_LOG_ERROR, "could not reallocate flt entries\n");
return err;
}
@@ -892,7 +981,8 @@ static int gxf_write_packet(AVFormatContext *s, AVPacket *pkt)
gxf->packet_count++;
if (gxf->packet_count == 100) {
- gxf_write_map_packet(s, 0);
+ if ((ret = gxf_write_map_packet(s, 0)) < 0)
+ return ret;
gxf->packet_count = 0;
}
diff --git a/libavformat/h261dec.c b/libavformat/h261dec.c
index 4a5805020f..a1d682128d 100644
--- a/libavformat/h261dec.c
+++ b/libavformat/h261dec.c
@@ -2,20 +2,20 @@
* RAW H.261 video demuxer
* Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,33 +25,30 @@
static int h261_probe(AVProbeData *p)
{
- uint32_t code= -1;
int i;
int valid_psc=0;
int invalid_psc=0;
int next_gn=0;
int src_fmt=0;
- GetBitContext gb;
- init_get_bits(&gb, p->buf, p->buf_size*8);
+ for(i=0; i<p->buf_size; i++){
+ if ((AV_RB16(&p->buf[i]) - 1) < 0xFFU) {
+ int shift = av_log2_16bit(p->buf[i+1]);
+ uint32_t code = AV_RB64(&p->buf[FFMAX(i-1, 0)]) >> (24+shift);
+ if ((code & 0xffff0000) == 0x10000) {
+ int gn= (code>>12)&0xf;
+ if(!gn)
+ src_fmt= code&8;
+ if(gn != next_gn) invalid_psc++;
+ else valid_psc++;
- for(i=0; i<p->buf_size*8; i++){
- if ((code & 0x01ff0000) || !(code & 0xff00)) {
- code = (code<<8) + get_bits(&gb, 8);
- i += 7;
- } else
- code = (code<<1) + get_bits1(&gb);
- if ((code & 0xffff0000) == 0x10000) {
- int gn= (code>>12)&0xf;
- if(!gn)
- src_fmt= code&8;
- if(gn != next_gn) invalid_psc++;
- else valid_psc++;
-
- if(src_fmt){ // CIF
- next_gn= (gn+1 )%13;
- }else{ //QCIF
- next_gn= (gn+1+!!gn)% 7;
+ if(src_fmt){ // CIF
+ static const int lut[16]={1,2,3,4,5,6,7,8,9,10,11,12,0,16,16,16};
+ next_gn = lut[gn];
+ }else{ //QCIF
+ static const int lut[16]={1,3,16,5,16,0,16,16,16,16,16,16,16,16,16,16};
+ next_gn = lut[gn];
+ }
}
}
}
diff --git a/libavformat/h263dec.c b/libavformat/h263dec.c
index 4d826d8c2d..145fb85902 100644
--- a/libavformat/h263dec.c
+++ b/libavformat/h263dec.c
@@ -2,20 +2,20 @@
* RAW H.263 video demuxer
* Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,24 +31,37 @@ static int h263_probe(AVProbeData *p)
int res_change=0;
int src_fmt, last_src_fmt=-1;
int last_gn=0;
+ int tr, last_tr = -1;
for(i=0; i<p->buf_size; i++){
code = (code<<8) + p->buf[i];
- if ((code & 0xfffffc0000) == 0x800000) {
- src_fmt= (code>>2)&3;
+ if ((code & 0xfffffc000000) == 0x80000000) {
+ tr = (code >> 18) & 0xFF;
+ src_fmt= (code>>10)&7;
if( src_fmt != last_src_fmt
&& last_src_fmt>0 && last_src_fmt<6
&& src_fmt<6)
res_change++;
- if((code&0x300)==0x200 && src_fmt){
+ if (tr == last_tr) {
+ invalid_psc++;
+ continue;
+ }
+
+ if (src_fmt != 7 && !(code&(1<<9)) && (code&(1<<5))) {
+ invalid_psc++;
+ continue;
+ }
+
+ if((code&0x30000)==0x20000 && src_fmt){
valid_psc++;
last_gn=0;
}else
invalid_psc++;
last_src_fmt= src_fmt;
- } else if((code & 0xffff800000) == 0x800000) {
- int gn= (code>>(23-5)) & 0x1F;
+ last_tr = tr;
+ } else if((code & 0xffff80000000) == 0x80000000) {
+ int gn= (code>>(31-5)) & 0x1F;
if(gn<last_gn){
invalid_psc++;
}else
diff --git a/libavformat/h264dec.c b/libavformat/h264dec.c
index 6fd45c1336..76073dda78 100644
--- a/libavformat/h264dec.c
+++ b/libavformat/h264dec.c
@@ -2,20 +2,20 @@
* RAW H.264 video demuxer
* Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/hdsenc.c b/libavformat/hdsenc.c
index d96a3d5599..48810a9a34 100644
--- a/libavformat/hdsenc.c
+++ b/libavformat/hdsenc.c
@@ -2,20 +2,20 @@
* Live HDS fragmenter
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -139,21 +139,19 @@ static void hds_free(AVFormatContext *s)
return;
for (i = 0; i < s->nb_streams; i++) {
OutputStream *os = &c->streams[i];
- if (os->out)
- avio_close(os->out);
- os->out = NULL;
+ avio_closep(&os->out);
if (os->ctx && os->ctx_inited)
av_write_trailer(os->ctx);
- if (os->ctx && os->ctx->pb)
- av_free(os->ctx->pb);
+ if (os->ctx)
+ av_freep(&os->ctx->pb);
if (os->ctx)
avformat_free_context(os->ctx);
- av_free(os->metadata);
+ av_freep(&os->metadata);
for (j = 0; j < os->nb_extra_packets; j++)
- av_free(os->extra_packets[j]);
+ av_freep(&os->extra_packets[j]);
for (j = 0; j < os->nb_fragments; j++)
- av_free(os->fragments[j]);
- av_free(os->fragments);
+ av_freep(&os->fragments[j]);
+ av_freep(&os->fragments);
}
av_freep(&c->streams);
}
@@ -204,7 +202,7 @@ static int write_manifest(AVFormatContext *s, int final)
avio_printf(out, "</manifest>\n");
avio_flush(out);
avio_close(out);
- return ff_rename(temp_filename, filename);
+ return ff_rename(temp_filename, filename, s);
}
static void update_size(AVIOContext *out, int64_t pos)
@@ -285,7 +283,7 @@ static int write_abst(AVFormatContext *s, OutputStream *os, int final)
update_size(out, afrt_pos);
update_size(out, 0);
avio_close(out);
- return ff_rename(temp_filename, filename);
+ return ff_rename(temp_filename, filename, s);
}
static int init_file(AVFormatContext *s, OutputStream *os, int64_t start_ts)
@@ -311,8 +309,7 @@ static void close_file(OutputStream *os)
avio_seek(os->out, 0, SEEK_SET);
avio_wb32(os->out, pos);
avio_flush(os->out);
- avio_close(os->out);
- os->out = NULL;
+ avio_closep(&os->out);
}
static int hds_write_header(AVFormatContext *s)
@@ -323,6 +320,7 @@ static int hds_write_header(AVFormatContext *s)
if (mkdir(s->filename, 0777) == -1 && errno != EEXIST) {
ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR , "Failed to create directory %s\n", s->filename);
goto fail;
}
@@ -332,7 +330,7 @@ static int hds_write_header(AVFormatContext *s)
goto fail;
}
- c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
+ c->streams = av_mallocz_array(s->nb_streams, sizeof(*c->streams));
if (!c->streams) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -480,7 +478,7 @@ static int hds_flush(AVFormatContext *s, OutputStream *os, int final,
snprintf(target_filename, sizeof(target_filename),
"%s/stream%dSeg1-Frag%d", s->filename, index, os->fragment_index);
- ret = ff_rename(os->temp_filename, target_filename);
+ ret = ff_rename(os->temp_filename, target_filename, s);
if (ret < 0)
return ret;
add_fragment(os, target_filename, os->frag_start_ts, end_ts - os->frag_start_ts);
@@ -498,7 +496,7 @@ static int hds_flush(AVFormatContext *s, OutputStream *os, int final,
if (remove > 0) {
for (i = 0; i < remove; i++) {
unlink(os->fragments[i]->file);
- av_free(os->fragments[i]);
+ av_freep(&os->fragments[i]);
}
os->nb_fragments -= remove;
memmove(os->fragments, os->fragments + remove,
@@ -516,7 +514,7 @@ static int hds_write_packet(AVFormatContext *s, AVPacket *pkt)
HDSContext *c = s->priv_data;
AVStream *st = s->streams[pkt->stream_index];
OutputStream *os = &c->streams[s->streams[pkt->stream_index]->id];
- int64_t end_dts = os->fragment_index * (int64_t) c->min_frag_duration;
+ int64_t end_dts = os->fragment_index * (int64_t)c->min_frag_duration;
int ret;
if (st->first_dts == AV_NOPTS_VALUE)
@@ -538,7 +536,7 @@ static int hds_write_packet(AVFormatContext *s, AVPacket *pkt)
os->last_ts = pkt->dts;
os->packets_written++;
- return ff_write_chained(os->ctx, pkt->stream_index - os->first_stream, pkt, s);
+ return ff_write_chained(os->ctx, pkt->stream_index - os->first_stream, pkt, s, 0);
}
static int hds_write_trailer(AVFormatContext *s)
diff --git a/libavformat/hevc.c b/libavformat/hevc.c
index 4d43b6a083..16b06b4bf4 100644
--- a/libavformat/hevc.c
+++ b/libavformat/hevc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -189,7 +189,7 @@ static void skip_sub_layer_hrd_parameters(GetBitContext *gb,
}
}
-static void skip_hrd_parameters(GetBitContext *gb, uint8_t cprms_present_flag,
+static int skip_hrd_parameters(GetBitContext *gb, uint8_t cprms_present_flag,
unsigned int max_sub_layers_minus1)
{
unsigned int i;
@@ -246,8 +246,11 @@ static void skip_hrd_parameters(GetBitContext *gb, uint8_t cprms_present_flag,
else
low_delay_hrd_flag = get_bits1(gb);
- if (!low_delay_hrd_flag)
+ if (!low_delay_hrd_flag) {
cpb_cnt_minus1 = get_ue_golomb_long(gb);
+ if (cpb_cnt_minus1 > 31)
+ return AVERROR_INVALIDDATA;
+ }
if (nal_hrd_parameters_present_flag)
skip_sub_layer_hrd_parameters(gb, cpb_cnt_minus1,
@@ -257,6 +260,8 @@ static void skip_hrd_parameters(GetBitContext *gb, uint8_t cprms_present_flag,
skip_sub_layer_hrd_parameters(gb, cpb_cnt_minus1,
sub_pic_hrd_params_present_flag);
}
+
+ return 0;
}
static void skip_timing_info(GetBitContext *gb)
@@ -457,6 +462,9 @@ static int parse_rps(GetBitContext *gb, unsigned int rps_idx,
unsigned int num_negative_pics = get_ue_golomb_long(gb);
unsigned int num_positive_pics = get_ue_golomb_long(gb);
+ if ((num_positive_pics + (uint64_t)num_negative_pics) * 2 > get_bits_left(gb))
+ return AVERROR_INVALIDDATA;
+
num_delta_pocs[rps_idx] = num_negative_pics + num_positive_pics;
for (i = 0; i < num_negative_pics; i++) {
@@ -799,7 +807,7 @@ static void hvcc_init(HEVCDecoderConfigurationRecord *hvcc)
/*
* Initialize this field with an invalid value which can be used to detect
- * whether we didn't see any VUI (in wich case it should be reset to zero).
+ * whether we didn't see any VUI (in which case it should be reset to zero).
*/
hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1;
}
diff --git a/libavformat/hevc.h b/libavformat/hevc.h
index 03c43bd471..796eaf40b1 100644
--- a/libavformat/hevc.h
+++ b/libavformat/hevc.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -89,7 +89,7 @@ int ff_hevc_annexb2mp4_buf(const uint8_t *buf_in, uint8_t **buf_out,
* @param size size (in bytes) of the data buffer
* @param ps_array_completeness whether all parameter sets are in the hvcC (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
+ * @return >=0 in case of success, a negative value corresponding to an AVERROR
* code in case of failure
*/
int ff_isom_write_hvcc(AVIOContext *pb, const uint8_t *data,
diff --git a/libavformat/hevcdec.c b/libavformat/hevcdec.c
index 65a3cdfb3c..e36a0513e3 100644
--- a/libavformat/hevcdec.c
+++ b/libavformat/hevcdec.c
@@ -2,20 +2,20 @@
* RAW HEVC video demuxer
* Copyright (c) 2013 Dirk Farin <dirk.farin@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/hls.c b/libavformat/hls.c
index 8b52a35508..3f1d97eb6f 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -1,21 +1,22 @@
/*
* Apple HTTP Live Streaming demuxer
* Copyright (c) 2010 Martin Storsjo
+ * Copyright (c) 2013 Anssi Hannula
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +27,7 @@
*/
#include "libavutil/avstring.h"
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -35,9 +37,16 @@
#include "internal.h"
#include "avio_internal.h"
#include "url.h"
+#include "id3v2.h"
#define INITIAL_BUFFER_SIZE 32768
+#define MAX_FIELD_LEN 64
+#define MAX_CHARACTERISTICS_LEN 512
+
+#define MPEG_TIME_BASE 90000
+#define MPEG_TIME_BASE_Q (AVRational){1, MPEG_TIME_BASE}
+
/*
* An apple http stream consists of a playlist with media segment files,
* played sequentially. There may be several playlists with the same
@@ -53,23 +62,33 @@
enum KeyType {
KEY_NONE,
KEY_AES_128,
+ KEY_SAMPLE_AES
};
struct segment {
int64_t duration;
- char url[MAX_URL_SIZE];
- char key[MAX_URL_SIZE];
+ int64_t url_offset;
+ int64_t size;
+ char *url;
+ char *key;
enum KeyType key_type;
uint8_t iv[16];
};
+struct rendition;
+
+enum PlaylistType {
+ PLS_TYPE_UNSPECIFIED,
+ PLS_TYPE_EVENT,
+ PLS_TYPE_VOD
+};
+
/*
- * Each variant has its own demuxer. If it currently is active,
+ * Each playlist has its own demuxer. If it currently is active,
* it has an open AVIOContext too, and potentially an AVPacket
* containing the next packet from this stream.
*/
-struct variant {
- int bandwidth;
+struct playlist {
char url[MAX_URL_SIZE];
AVIOContext pb;
uint8_t* read_buffer;
@@ -81,28 +100,88 @@ struct variant {
int stream_offset;
int finished;
+ enum PlaylistType type;
int64_t target_duration;
int start_seq_no;
int n_segments;
struct segment **segments;
int needed, cur_needed;
int cur_seq_no;
+ int64_t cur_seg_offset;
int64_t last_load_time;
char key_url[MAX_URL_SIZE];
uint8_t key[16];
+
+ /* ID3 timestamp handling (elementary audio streams have ID3 timestamps
+ * (and possibly other ID3 tags) in the beginning of each segment) */
+ int is_id3_timestamped; /* -1: not yet known */
+ int64_t id3_mpegts_timestamp; /* in mpegts tb */
+ int64_t id3_offset; /* in stream original tb */
+ uint8_t* id3_buf; /* temp buffer for id3 parsing */
+ unsigned int id3_buf_size;
+ AVDictionary *id3_initial; /* data from first id3 tag */
+ int id3_found; /* ID3 tag found at some point */
+ int id3_changed; /* ID3 tag data has changed at some point */
+ ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer is opened */
+
+ int64_t seek_timestamp;
+ int seek_flags;
+ int seek_stream_index; /* into subdemuxer stream array */
+
+ /* Renditions associated with this playlist, if any.
+ * Alternative rendition playlists have a single rendition associated
+ * with them, and variant main Media Playlists may have
+ * multiple (playlist-less) renditions associated with them. */
+ int n_renditions;
+ struct rendition **renditions;
+};
+
+/*
+ * Renditions are e.g. alternative subtitle or audio streams.
+ * The rendition may either be an external playlist or it may be
+ * contained in the main Media Playlist of the variant (in which case
+ * playlist is NULL).
+ */
+struct rendition {
+ enum AVMediaType type;
+ struct playlist *playlist;
+ char group_id[MAX_FIELD_LEN];
+ char language[MAX_FIELD_LEN];
+ char name[MAX_FIELD_LEN];
+ int disposition;
+};
+
+struct variant {
+ int bandwidth;
+
+ /* every variant contains at least the main Media Playlist in index 0 */
+ int n_playlists;
+ struct playlist **playlists;
+
+ char audio_group[MAX_FIELD_LEN];
+ char video_group[MAX_FIELD_LEN];
+ char subtitles_group[MAX_FIELD_LEN];
};
typedef struct HLSContext {
+ AVClass *class;
int n_variants;
struct variant **variants;
+ int n_playlists;
+ struct playlist **playlists;
+ int n_renditions;
+ struct rendition **renditions;
+
int cur_seq_no;
- int end_of_segment;
+ int live_start_index;
int first_packet;
int64_t first_timestamp;
- int64_t seek_timestamp;
- int seek_flags;
+ int64_t cur_timestamp;
AVIOInterruptCB *interrupt_callback;
+ char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context
+ char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context
+ char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context
} HLSContext;
static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
@@ -113,13 +192,42 @@ static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
return len;
}
-static void free_segment_list(struct variant *var)
+static void free_segment_list(struct playlist *pls)
+{
+ int i;
+ for (i = 0; i < pls->n_segments; i++) {
+ av_freep(&pls->segments[i]->key);
+ av_freep(&pls->segments[i]->url);
+ av_freep(&pls->segments[i]);
+ }
+ av_freep(&pls->segments);
+ pls->n_segments = 0;
+}
+
+static void free_playlist_list(HLSContext *c)
{
int i;
- for (i = 0; i < var->n_segments; i++)
- av_free(var->segments[i]);
- av_freep(&var->segments);
- var->n_segments = 0;
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
+ free_segment_list(pls);
+ av_freep(&pls->renditions);
+ av_freep(&pls->id3_buf);
+ av_dict_free(&pls->id3_initial);
+ ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
+ av_free_packet(&pls->pkt);
+ av_freep(&pls->pb.buffer);
+ if (pls->input)
+ ffurl_close(pls->input);
+ if (pls->ctx) {
+ pls->ctx->pb = NULL;
+ avformat_close_input(&pls->ctx);
+ }
+ av_free(pls);
+ }
+ av_freep(&c->playlists);
+ av_freep(&c->cookies);
+ av_freep(&c->user_agent);
+ c->n_playlists = 0;
}
static void free_variant_list(HLSContext *c)
@@ -127,21 +235,22 @@ static void free_variant_list(HLSContext *c)
int i;
for (i = 0; i < c->n_variants; i++) {
struct variant *var = c->variants[i];
- free_segment_list(var);
- av_free_packet(&var->pkt);
- av_free(var->pb.buffer);
- if (var->input)
- ffurl_close(var->input);
- if (var->ctx) {
- var->ctx->pb = NULL;
- avformat_close_input(&var->ctx);
- }
+ av_freep(&var->playlists);
av_free(var);
}
av_freep(&c->variants);
c->n_variants = 0;
}
+static void free_rendition_list(HLSContext *c)
+{
+ int i;
+ for (i = 0; i < c->n_renditions; i++)
+ av_freep(&c->renditions[i]);
+ av_freep(&c->renditions);
+ c->n_renditions = 0;
+}
+
/*
* Used to reset a statically allocated AVPacket to a clean slate,
* containing no data.
@@ -152,35 +261,78 @@ static void reset_packet(AVPacket *pkt)
pkt->data = NULL;
}
-static struct variant *new_variant(HLSContext *c, int bandwidth,
- const char *url, const char *base)
+static struct playlist *new_playlist(HLSContext *c, const char *url,
+ const char *base)
{
- struct variant *var = av_mallocz(sizeof(struct variant));
- if (!var)
+ struct playlist *pls = av_mallocz(sizeof(struct playlist));
+ if (!pls)
return NULL;
- reset_packet(&var->pkt);
- var->bandwidth = bandwidth;
- ff_make_absolute_url(var->url, sizeof(var->url), base, url);
- dynarray_add(&c->variants, &c->n_variants, var);
- return var;
+ reset_packet(&pls->pkt);
+ ff_make_absolute_url(pls->url, sizeof(pls->url), base, url);
+ pls->seek_timestamp = AV_NOPTS_VALUE;
+
+ pls->is_id3_timestamped = -1;
+ pls->id3_mpegts_timestamp = AV_NOPTS_VALUE;
+
+ dynarray_add(&c->playlists, &c->n_playlists, pls);
+ return pls;
}
struct variant_info {
char bandwidth[20];
+ /* variant group ids: */
+ char audio[MAX_FIELD_LEN];
+ char video[MAX_FIELD_LEN];
+ char subtitles[MAX_FIELD_LEN];
};
+static struct variant *new_variant(HLSContext *c, struct variant_info *info,
+ const char *url, const char *base)
+{
+ struct variant *var;
+ struct playlist *pls;
+
+ pls = new_playlist(c, url, base);
+ if (!pls)
+ return NULL;
+
+ var = av_mallocz(sizeof(struct variant));
+ if (!var)
+ return NULL;
+
+ if (info) {
+ var->bandwidth = atoi(info->bandwidth);
+ strcpy(var->audio_group, info->audio);
+ strcpy(var->video_group, info->video);
+ strcpy(var->subtitles_group, info->subtitles);
+ }
+
+ dynarray_add(&c->variants, &c->n_variants, var);
+ dynarray_add(&var->playlists, &var->n_playlists, pls);
+ return var;
+}
+
static void handle_variant_args(struct variant_info *info, const char *key,
int key_len, char **dest, int *dest_len)
{
if (!strncmp(key, "BANDWIDTH=", key_len)) {
*dest = info->bandwidth;
*dest_len = sizeof(info->bandwidth);
+ } else if (!strncmp(key, "AUDIO=", key_len)) {
+ *dest = info->audio;
+ *dest_len = sizeof(info->audio);
+ } else if (!strncmp(key, "VIDEO=", key_len)) {
+ *dest = info->video;
+ *dest_len = sizeof(info->video);
+ } else if (!strncmp(key, "SUBTITLES=", key_len)) {
+ *dest = info->subtitles;
+ *dest_len = sizeof(info->subtitles);
}
}
struct key_info {
char uri[MAX_URL_SIZE];
- char method[10];
+ char method[11];
char iv[35];
};
@@ -199,24 +351,182 @@ static void handle_key_args(struct key_info *info, const char *key,
}
}
+struct rendition_info {
+ char type[16];
+ char uri[MAX_URL_SIZE];
+ char group_id[MAX_FIELD_LEN];
+ char language[MAX_FIELD_LEN];
+ char assoc_language[MAX_FIELD_LEN];
+ char name[MAX_FIELD_LEN];
+ char defaultr[4];
+ char forced[4];
+ char characteristics[MAX_CHARACTERISTICS_LEN];
+};
+
+static struct rendition *new_rendition(HLSContext *c, struct rendition_info *info,
+ const char *url_base)
+{
+ struct rendition *rend;
+ enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN;
+ char *characteristic;
+ char *chr_ptr;
+ char *saveptr;
+
+ if (!strcmp(info->type, "AUDIO"))
+ type = AVMEDIA_TYPE_AUDIO;
+ else if (!strcmp(info->type, "VIDEO"))
+ type = AVMEDIA_TYPE_VIDEO;
+ else if (!strcmp(info->type, "SUBTITLES"))
+ type = AVMEDIA_TYPE_SUBTITLE;
+ else if (!strcmp(info->type, "CLOSED-CAPTIONS"))
+ /* CLOSED-CAPTIONS is ignored since we do not support CEA-608 CC in
+ * AVC SEI RBSP anyway */
+ return NULL;
+
+ if (type == AVMEDIA_TYPE_UNKNOWN)
+ return NULL;
+
+ /* URI is mandatory for subtitles as per spec */
+ if (type == AVMEDIA_TYPE_SUBTITLE && !info->uri[0])
+ return NULL;
+
+ /* TODO: handle subtitles (each segment has to parsed separately) */
+ if (type == AVMEDIA_TYPE_SUBTITLE)
+ return NULL;
+
+ rend = av_mallocz(sizeof(struct rendition));
+ if (!rend)
+ return NULL;
+
+ dynarray_add(&c->renditions, &c->n_renditions, rend);
+
+ rend->type = type;
+ strcpy(rend->group_id, info->group_id);
+ strcpy(rend->language, info->language);
+ strcpy(rend->name, info->name);
+
+ /* add the playlist if this is an external rendition */
+ if (info->uri[0]) {
+ rend->playlist = new_playlist(c, info->uri, url_base);
+ if (rend->playlist)
+ dynarray_add(&rend->playlist->renditions,
+ &rend->playlist->n_renditions, rend);
+ }
+
+ if (info->assoc_language[0]) {
+ int langlen = strlen(rend->language);
+ if (langlen < sizeof(rend->language) - 3) {
+ rend->language[langlen] = ',';
+ strncpy(rend->language + langlen + 1, info->assoc_language,
+ sizeof(rend->language) - langlen - 2);
+ }
+ }
+
+ if (!strcmp(info->defaultr, "YES"))
+ rend->disposition |= AV_DISPOSITION_DEFAULT;
+ if (!strcmp(info->forced, "YES"))
+ rend->disposition |= AV_DISPOSITION_FORCED;
+
+ chr_ptr = info->characteristics;
+ while ((characteristic = av_strtok(chr_ptr, ",", &saveptr))) {
+ if (!strcmp(characteristic, "public.accessibility.describes-music-and-sound"))
+ rend->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
+ else if (!strcmp(characteristic, "public.accessibility.describes-video"))
+ rend->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+
+ chr_ptr = NULL;
+ }
+
+ return rend;
+}
+
+static void handle_rendition_args(struct rendition_info *info, const char *key,
+ int key_len, char **dest, int *dest_len)
+{
+ if (!strncmp(key, "TYPE=", key_len)) {
+ *dest = info->type;
+ *dest_len = sizeof(info->type);
+ } else if (!strncmp(key, "URI=", key_len)) {
+ *dest = info->uri;
+ *dest_len = sizeof(info->uri);
+ } else if (!strncmp(key, "GROUP-ID=", key_len)) {
+ *dest = info->group_id;
+ *dest_len = sizeof(info->group_id);
+ } else if (!strncmp(key, "LANGUAGE=", key_len)) {
+ *dest = info->language;
+ *dest_len = sizeof(info->language);
+ } else if (!strncmp(key, "ASSOC-LANGUAGE=", key_len)) {
+ *dest = info->assoc_language;
+ *dest_len = sizeof(info->assoc_language);
+ } else if (!strncmp(key, "NAME=", key_len)) {
+ *dest = info->name;
+ *dest_len = sizeof(info->name);
+ } else if (!strncmp(key, "DEFAULT=", key_len)) {
+ *dest = info->defaultr;
+ *dest_len = sizeof(info->defaultr);
+ } else if (!strncmp(key, "FORCED=", key_len)) {
+ *dest = info->forced;
+ *dest_len = sizeof(info->forced);
+ } else if (!strncmp(key, "CHARACTERISTICS=", key_len)) {
+ *dest = info->characteristics;
+ *dest_len = sizeof(info->characteristics);
+ }
+ /*
+ * ignored:
+ * - AUTOSELECT: client may autoselect based on e.g. system language
+ * - INSTREAM-ID: EIA-608 closed caption number ("CC1".."CC4")
+ */
+}
+
+/* used by parse_playlist to allocate a new variant+playlist when the
+ * playlist is detected to be a Media Playlist (not Master Playlist)
+ * and we have no parent Master Playlist (parsing of which would have
+ * allocated the variant and playlist already) */
+static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url)
+{
+ if (*pls)
+ return 0;
+ if (!new_variant(c, NULL, url, NULL))
+ return AVERROR(ENOMEM);
+ *pls = c->playlists[c->n_playlists - 1];
+ return 0;
+}
+
+/* pls = NULL => Master Playlist or parentless Media Playlist
+ * pls = !NULL => parented Media Playlist, playlist+variant allocated */
static int parse_playlist(HLSContext *c, const char *url,
- struct variant *var, AVIOContext *in)
+ struct playlist *pls, AVIOContext *in)
{
- int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0;
+ int ret = 0, is_segment = 0, is_variant = 0;
int64_t duration = 0;
enum KeyType key_type = KEY_NONE;
uint8_t iv[16] = "";
int has_iv = 0;
char key[MAX_URL_SIZE] = "";
- char line[1024];
+ char line[MAX_URL_SIZE];
const char *ptr;
int close_in = 0;
+ int64_t seg_offset = 0;
+ int64_t seg_size = -1;
uint8_t *new_url = NULL;
+ struct variant_info variant_info;
+ char tmp_str[MAX_URL_SIZE];
if (!in) {
+ AVDictionary *opts = NULL;
close_in = 1;
- if ((ret = avio_open2(&in, url, AVIO_FLAG_READ,
- c->interrupt_callback, NULL)) < 0)
+ /* Some HLS servers don't like being sent the range header */
+ av_dict_set(&opts, "seekable", "0", 0);
+
+ // broker prior HTTP options that should be consistent across requests
+ av_dict_set(&opts, "user-agent", c->user_agent, 0);
+ av_dict_set(&opts, "cookies", c->cookies, 0);
+ av_dict_set(&opts, "headers", c->headers, 0);
+
+ ret = avio_open2(&in, url, AVIO_FLAG_READ,
+ c->interrupt_callback, &opts);
+ av_dict_free(&opts);
+ if (ret < 0)
return ret;
}
@@ -229,18 +539,18 @@ static int parse_playlist(HLSContext *c, const char *url,
goto fail;
}
- if (var) {
- free_segment_list(var);
- var->finished = 0;
+ if (pls) {
+ free_segment_list(pls);
+ pls->finished = 0;
+ pls->type = PLS_TYPE_UNSPECIFIED;
}
- while (!in->eof_reached) {
+ while (!avio_feof(in)) {
read_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
- struct variant_info info = {{0}};
is_variant = 1;
+ memset(&variant_info, 0, sizeof(variant_info));
ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args,
- &info);
- bandwidth = atoi(info.bandwidth);
+ &variant_info);
} else if (av_strstart(line, "#EXT-X-KEY:", &ptr)) {
struct key_info info = {{0}};
ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_key_args,
@@ -249,54 +559,65 @@ static int parse_playlist(HLSContext *c, const char *url,
has_iv = 0;
if (!strcmp(info.method, "AES-128"))
key_type = KEY_AES_128;
+ if (!strcmp(info.method, "SAMPLE-AES"))
+ key_type = KEY_SAMPLE_AES;
if (!strncmp(info.iv, "0x", 2) || !strncmp(info.iv, "0X", 2)) {
ff_hex_to_data(iv, info.iv + 2);
has_iv = 1;
}
av_strlcpy(key, info.uri, sizeof(key));
+ } else if (av_strstart(line, "#EXT-X-MEDIA:", &ptr)) {
+ struct rendition_info info = {{0}};
+ ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_rendition_args,
+ &info);
+ new_rendition(c, &info, url);
} else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {
- if (!var) {
- var = new_variant(c, 0, url, NULL);
- if (!var) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- }
- var->target_duration = atoi(ptr) * AV_TIME_BASE;
+ ret = ensure_playlist(c, &pls, url);
+ if (ret < 0)
+ goto fail;
+ pls->target_duration = atoi(ptr) * AV_TIME_BASE;
} else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
- if (!var) {
- var = new_variant(c, 0, url, NULL);
- if (!var) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- }
- var->start_seq_no = atoi(ptr);
+ ret = ensure_playlist(c, &pls, url);
+ if (ret < 0)
+ goto fail;
+ pls->start_seq_no = atoi(ptr);
+ } else if (av_strstart(line, "#EXT-X-PLAYLIST-TYPE:", &ptr)) {
+ ret = ensure_playlist(c, &pls, url);
+ if (ret < 0)
+ goto fail;
+ if (!strcmp(ptr, "EVENT"))
+ pls->type = PLS_TYPE_EVENT;
+ else if (!strcmp(ptr, "VOD"))
+ pls->type = PLS_TYPE_VOD;
} else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {
- if (var)
- var->finished = 1;
+ if (pls)
+ pls->finished = 1;
} else if (av_strstart(line, "#EXTINF:", &ptr)) {
is_segment = 1;
duration = atof(ptr) * AV_TIME_BASE;
+ } else if (av_strstart(line, "#EXT-X-BYTERANGE:", &ptr)) {
+ seg_size = atoi(ptr);
+ ptr = strchr(ptr, '@');
+ if (ptr)
+ seg_offset = atoi(ptr+1);
} else if (av_strstart(line, "#", NULL)) {
continue;
} else if (line[0]) {
if (is_variant) {
- if (!new_variant(c, bandwidth, line, url)) {
+ if (!new_variant(c, &variant_info, line, url)) {
ret = AVERROR(ENOMEM);
goto fail;
}
is_variant = 0;
- bandwidth = 0;
}
if (is_segment) {
struct segment *seg;
- if (!var) {
- var = new_variant(c, 0, url, NULL);
- if (!var) {
+ if (!pls) {
+ if (!new_variant(c, 0, url, NULL)) {
ret = AVERROR(ENOMEM);
goto fail;
}
+ pls = c->playlists[c->n_playlists - 1];
}
seg = av_malloc(sizeof(struct segment));
if (!seg) {
@@ -308,19 +629,49 @@ static int parse_playlist(HLSContext *c, const char *url,
if (has_iv) {
memcpy(seg->iv, iv, sizeof(iv));
} else {
- int seq = var->start_seq_no + var->n_segments;
+ int seq = pls->start_seq_no + pls->n_segments;
memset(seg->iv, 0, sizeof(seg->iv));
AV_WB32(seg->iv + 12, seq);
}
- ff_make_absolute_url(seg->key, sizeof(seg->key), url, key);
- ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);
- dynarray_add(&var->segments, &var->n_segments, seg);
+
+ if (key_type != KEY_NONE) {
+ ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key);
+ seg->key = av_strdup(tmp_str);
+ if (!seg->key) {
+ av_free(seg);
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ } else {
+ seg->key = NULL;
+ }
+
+ ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, line);
+ seg->url = av_strdup(tmp_str);
+ if (!seg->url) {
+ av_free(seg->key);
+ av_free(seg);
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ dynarray_add(&pls->segments, &pls->n_segments, seg);
is_segment = 0;
+
+ seg->size = seg_size;
+ if (seg_size >= 0) {
+ seg->url_offset = seg_offset;
+ seg_offset += seg_size;
+ seg_size = -1;
+ } else {
+ seg->url_offset = 0;
+ seg_offset = 0;
+ }
}
}
}
- if (var)
- var->last_load_time = av_gettime_relative();
+ if (pls)
+ pls->last_load_time = av_gettime_relative();
fail:
av_free(new_url);
@@ -329,72 +680,386 @@ fail:
return ret;
}
-static int open_input(struct variant *var)
+enum ReadFromURLMode {
+ READ_NORMAL,
+ READ_COMPLETE,
+};
+
+/* read from URLContext, limiting read to current segment */
+static int read_from_url(struct playlist *pls, uint8_t *buf, int buf_size,
+ enum ReadFromURLMode mode)
+{
+ int ret;
+ struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no];
+
+ /* limit read if the segment was only a part of a file */
+ if (seg->size >= 0)
+ buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset);
+
+ if (mode == READ_COMPLETE)
+ ret = ffurl_read_complete(pls->input, buf, buf_size);
+ else
+ ret = ffurl_read(pls->input, buf, buf_size);
+
+ if (ret > 0)
+ pls->cur_seg_offset += ret;
+
+ return ret;
+}
+
+/* Parse the raw ID3 data and pass contents to caller */
+static void parse_id3(AVFormatContext *s, AVIOContext *pb,
+ AVDictionary **metadata, int64_t *dts,
+ ID3v2ExtraMetaAPIC **apic, ID3v2ExtraMeta **extra_meta)
+{
+ static const char id3_priv_owner_ts[] = "com.apple.streaming.transportStreamTimestamp";
+ ID3v2ExtraMeta *meta;
+
+ ff_id3v2_read_dict(pb, metadata, ID3v2_DEFAULT_MAGIC, extra_meta);
+ for (meta = *extra_meta; meta; meta = meta->next) {
+ if (!strcmp(meta->tag, "PRIV")) {
+ ID3v2ExtraMetaPRIV *priv = meta->data;
+ if (priv->datasize == 8 && !strcmp(priv->owner, id3_priv_owner_ts)) {
+ /* 33-bit MPEG timestamp */
+ int64_t ts = AV_RB64(priv->data);
+ av_log(s, AV_LOG_DEBUG, "HLS ID3 audio timestamp %"PRId64"\n", ts);
+ if ((ts & ~((1ULL << 33) - 1)) == 0)
+ *dts = ts;
+ else
+ av_log(s, AV_LOG_ERROR, "Invalid HLS ID3 audio timestamp %"PRId64"\n", ts);
+ }
+ } else if (!strcmp(meta->tag, "APIC") && apic)
+ *apic = meta->data;
+ }
+}
+
+/* Check if the ID3 metadata contents have changed */
+static int id3_has_changed_values(struct playlist *pls, AVDictionary *metadata,
+ ID3v2ExtraMetaAPIC *apic)
+{
+ AVDictionaryEntry *entry = NULL;
+ AVDictionaryEntry *oldentry;
+ /* check that no keys have changed values */
+ while ((entry = av_dict_get(metadata, "", entry, AV_DICT_IGNORE_SUFFIX))) {
+ oldentry = av_dict_get(pls->id3_initial, entry->key, NULL, AV_DICT_MATCH_CASE);
+ if (!oldentry || strcmp(oldentry->value, entry->value) != 0)
+ return 1;
+ }
+
+ /* check if apic appeared */
+ if (apic && (pls->ctx->nb_streams != 2 || !pls->ctx->streams[1]->attached_pic.data))
+ return 1;
+
+ if (apic) {
+ int size = pls->ctx->streams[1]->attached_pic.size;
+ if (size != apic->buf->size - FF_INPUT_BUFFER_PADDING_SIZE)
+ return 1;
+
+ if (memcmp(apic->buf->data, pls->ctx->streams[1]->attached_pic.data, size) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Parse ID3 data and handle the found data */
+static void handle_id3(AVIOContext *pb, struct playlist *pls)
+{
+ AVDictionary *metadata = NULL;
+ ID3v2ExtraMetaAPIC *apic = NULL;
+ ID3v2ExtraMeta *extra_meta = NULL;
+ int64_t timestamp = AV_NOPTS_VALUE;
+
+ parse_id3(pls->ctx, pb, &metadata, &timestamp, &apic, &extra_meta);
+
+ if (timestamp != AV_NOPTS_VALUE) {
+ pls->id3_mpegts_timestamp = timestamp;
+ pls->id3_offset = 0;
+ }
+
+ if (!pls->id3_found) {
+ /* initial ID3 tags */
+ av_assert0(!pls->id3_deferred_extra);
+ pls->id3_found = 1;
+
+ /* get picture attachment and set text metadata */
+ if (pls->ctx->nb_streams)
+ ff_id3v2_parse_apic(pls->ctx, &extra_meta);
+ else
+ /* demuxer not yet opened, defer picture attachment */
+ pls->id3_deferred_extra = extra_meta;
+
+ av_dict_copy(&pls->ctx->metadata, metadata, 0);
+ pls->id3_initial = metadata;
+
+ } else {
+ if (!pls->id3_changed && id3_has_changed_values(pls, metadata, apic)) {
+ avpriv_report_missing_feature(pls->ctx, "Changing ID3 metadata in HLS audio elementary stream");
+ pls->id3_changed = 1;
+ }
+ av_dict_free(&metadata);
+ }
+
+ if (!pls->id3_deferred_extra)
+ ff_id3v2_free_extra_meta(&extra_meta);
+}
+
+/* Intercept and handle ID3 tags between URLContext and AVIOContext */
+static void intercept_id3(struct playlist *pls, uint8_t *buf,
+ int buf_size, int *len)
+{
+ /* intercept id3 tags, we do not want to pass them to the raw
+ * demuxer on all segment switches */
+ int bytes;
+ int id3_buf_pos = 0;
+ int fill_buf = 0;
+
+ /* gather all the id3 tags */
+ while (1) {
+ /* see if we can retrieve enough data for ID3 header */
+ if (*len < ID3v2_HEADER_SIZE && buf_size >= ID3v2_HEADER_SIZE) {
+ bytes = read_from_url(pls, buf + *len, ID3v2_HEADER_SIZE - *len, READ_COMPLETE);
+ if (bytes > 0) {
+
+ if (bytes == ID3v2_HEADER_SIZE - *len)
+ /* no EOF yet, so fill the caller buffer again after
+ * we have stripped the ID3 tags */
+ fill_buf = 1;
+
+ *len += bytes;
+
+ } else if (*len <= 0) {
+ /* error/EOF */
+ *len = bytes;
+ fill_buf = 0;
+ }
+ }
+
+ if (*len < ID3v2_HEADER_SIZE)
+ break;
+
+ if (ff_id3v2_match(buf, ID3v2_DEFAULT_MAGIC)) {
+ struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no];
+ int64_t maxsize = seg->size >= 0 ? seg->size : 1024*1024;
+ int taglen = ff_id3v2_tag_len(buf);
+ int tag_got_bytes = FFMIN(taglen, *len);
+ int remaining = taglen - tag_got_bytes;
+
+ if (taglen > maxsize) {
+ av_log(pls->ctx, AV_LOG_ERROR, "Too large HLS ID3 tag (%d > %"PRId64" bytes)\n",
+ taglen, maxsize);
+ break;
+ }
+
+ /*
+ * Copy the id3 tag to our temporary id3 buffer.
+ * We could read a small id3 tag directly without memcpy, but
+ * we would still need to copy the large tags, and handling
+ * both of those cases together with the possibility for multiple
+ * tags would make the handling a bit complex.
+ */
+ pls->id3_buf = av_fast_realloc(pls->id3_buf, &pls->id3_buf_size, id3_buf_pos + taglen);
+ if (!pls->id3_buf)
+ break;
+ memcpy(pls->id3_buf + id3_buf_pos, buf, tag_got_bytes);
+ id3_buf_pos += tag_got_bytes;
+
+ /* strip the intercepted bytes */
+ *len -= tag_got_bytes;
+ memmove(buf, buf + tag_got_bytes, *len);
+ av_log(pls->ctx, AV_LOG_DEBUG, "Stripped %d HLS ID3 bytes\n", tag_got_bytes);
+
+ if (remaining > 0) {
+ /* read the rest of the tag in */
+ if (read_from_url(pls, pls->id3_buf + id3_buf_pos, remaining, READ_COMPLETE) != remaining)
+ break;
+ id3_buf_pos += remaining;
+ av_log(pls->ctx, AV_LOG_DEBUG, "Stripped additional %d HLS ID3 bytes\n", remaining);
+ }
+
+ } else {
+ /* no more ID3 tags */
+ break;
+ }
+ }
+
+ /* re-fill buffer for the caller unless EOF */
+ if (*len >= 0 && (fill_buf || *len == 0)) {
+ bytes = read_from_url(pls, buf + *len, buf_size - *len, READ_NORMAL);
+
+ /* ignore error if we already had some data */
+ if (bytes >= 0)
+ *len += bytes;
+ else if (*len == 0)
+ *len = bytes;
+ }
+
+ if (pls->id3_buf) {
+ /* Now parse all the ID3 tags */
+ AVIOContext id3ioctx;
+ ffio_init_context(&id3ioctx, pls->id3_buf, id3_buf_pos, 0, NULL, NULL, NULL, NULL);
+ handle_id3(&id3ioctx, pls);
+ }
+
+ if (pls->is_id3_timestamped == -1)
+ pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE);
+}
+
+static void update_options(char **dest, const char *name, void *src)
{
- struct segment *seg = var->segments[var->cur_seq_no - var->start_seq_no];
+ av_freep(dest);
+ av_opt_get(src, name, 0, (uint8_t**)dest);
+ if (*dest && !strlen(*dest))
+ av_freep(dest);
+}
+
+static int open_input(HLSContext *c, struct playlist *pls)
+{
+ AVDictionary *opts = NULL;
+ AVDictionary *opts2 = NULL;
+ int ret;
+ struct segment *seg = pls->segments[pls->cur_seq_no - pls->start_seq_no];
+
+ // broker prior HTTP options that should be consistent across requests
+ av_dict_set(&opts, "user-agent", c->user_agent, 0);
+ av_dict_set(&opts, "cookies", c->cookies, 0);
+ av_dict_set(&opts, "headers", c->headers, 0);
+ av_dict_set(&opts, "seekable", "0", 0);
+
+ // Same opts for key request (ffurl_open mutilates the opts so it cannot be used twice)
+ av_dict_copy(&opts2, opts, 0);
+
+ if (seg->size >= 0) {
+ /* try to restrict the HTTP request to the part we want
+ * (if this is in fact a HTTP request) */
+ av_dict_set_int(&opts, "offset", seg->url_offset, 0);
+ av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
+ }
+
+ av_log(pls->parent, AV_LOG_VERBOSE, "HLS request for url '%s', offset %"PRId64", playlist %d\n",
+ seg->url, seg->url_offset, pls->index);
+
if (seg->key_type == KEY_NONE) {
- return ffurl_open(&var->input, seg->url, AVIO_FLAG_READ,
- &var->parent->interrupt_callback, NULL);
+ ret = ffurl_open(&pls->input, seg->url, AVIO_FLAG_READ,
+ &pls->parent->interrupt_callback, &opts);
+
} else if (seg->key_type == KEY_AES_128) {
char iv[33], key[33], url[MAX_URL_SIZE];
- int ret;
- if (strcmp(seg->key, var->key_url)) {
+ if (strcmp(seg->key, pls->key_url)) {
URLContext *uc;
if (ffurl_open(&uc, seg->key, AVIO_FLAG_READ,
- &var->parent->interrupt_callback, NULL) == 0) {
- if (ffurl_read_complete(uc, var->key, sizeof(var->key))
- != sizeof(var->key)) {
+ &pls->parent->interrupt_callback, &opts2) == 0) {
+ if (ffurl_read_complete(uc, pls->key, sizeof(pls->key))
+ != sizeof(pls->key)) {
av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n",
seg->key);
}
+ update_options(&c->cookies, "cookies", uc->priv_data);
+ av_dict_set(&opts, "cookies", c->cookies, 0);
ffurl_close(uc);
} else {
av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n",
seg->key);
}
- av_strlcpy(var->key_url, seg->key, sizeof(var->key_url));
+ av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url));
}
ff_data_to_hex(iv, seg->iv, sizeof(seg->iv), 0);
- ff_data_to_hex(key, var->key, sizeof(var->key), 0);
+ ff_data_to_hex(key, pls->key, sizeof(pls->key), 0);
iv[32] = key[32] = '\0';
if (strstr(seg->url, "://"))
snprintf(url, sizeof(url), "crypto+%s", seg->url);
else
snprintf(url, sizeof(url), "crypto:%s", seg->url);
- if ((ret = ffurl_alloc(&var->input, url, AVIO_FLAG_READ,
- &var->parent->interrupt_callback)) < 0)
- return ret;
- av_opt_set(var->input->priv_data, "key", key, 0);
- av_opt_set(var->input->priv_data, "iv", iv, 0);
- if ((ret = ffurl_connect(var->input, NULL)) < 0) {
- ffurl_close(var->input);
- var->input = NULL;
- return ret;
+ if ((ret = ffurl_alloc(&pls->input, url, AVIO_FLAG_READ,
+ &pls->parent->interrupt_callback)) < 0)
+ goto cleanup;
+ av_opt_set(pls->input->priv_data, "key", key, 0);
+ av_opt_set(pls->input->priv_data, "iv", iv, 0);
+
+ if ((ret = ffurl_connect(pls->input, &opts)) < 0) {
+ ffurl_close(pls->input);
+ pls->input = NULL;
+ goto cleanup;
+ }
+ ret = 0;
+ } else if (seg->key_type == KEY_SAMPLE_AES) {
+ av_log(pls->parent, AV_LOG_ERROR,
+ "SAMPLE-AES encryption is not supported yet\n");
+ ret = AVERROR_PATCHWELCOME;
+ }
+ else
+ ret = AVERROR(ENOSYS);
+
+ /* Seek to the requested position. If this was a HTTP request, the offset
+ * should already be where want it to, but this allows e.g. local testing
+ * without a HTTP server. */
+ if (ret == 0 && seg->key_type == KEY_NONE) {
+ int seekret = ffurl_seek(pls->input, seg->url_offset, SEEK_SET);
+ if (seekret < 0) {
+ av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url);
+ ret = seekret;
+ ffurl_close(pls->input);
+ pls->input = NULL;
}
- return 0;
}
- return AVERROR(ENOSYS);
+
+cleanup:
+ av_dict_free(&opts);
+ av_dict_free(&opts2);
+ pls->cur_seg_offset = 0;
+ return ret;
+}
+
+static int64_t default_reload_interval(struct playlist *pls)
+{
+ return pls->n_segments > 0 ?
+ pls->segments[pls->n_segments - 1]->duration :
+ pls->target_duration;
}
static int read_data(void *opaque, uint8_t *buf, int buf_size)
{
- struct variant *v = opaque;
+ struct playlist *v = opaque;
HLSContext *c = v->parent->priv_data;
int ret, i;
+ int just_opened = 0;
restart:
+ if (!v->needed)
+ return AVERROR_EOF;
+
if (!v->input) {
+ int64_t reload_interval;
+
+ /* Check that the playlist is still needed before opening a new
+ * segment. */
+ if (v->ctx && v->ctx->nb_streams &&
+ v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) {
+ v->needed = 0;
+ for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams;
+ i++) {
+ if (v->parent->streams[i]->discard < AVDISCARD_ALL)
+ v->needed = 1;
+ }
+ }
+ if (!v->needed) {
+ av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n",
+ v->index);
+ return AVERROR_EOF;
+ }
+
/* If this is a live stream and the reload interval has elapsed since
- * the last playlist reload, reload the variant playlists now. */
- int64_t reload_interval = v->n_segments > 0 ?
- v->segments[v->n_segments - 1]->duration :
- v->target_duration;
+ * the last playlist reload, reload the playlists now. */
+ reload_interval = default_reload_interval(v);
reload:
if (!v->finished &&
av_gettime_relative() - v->last_load_time >= reload_interval) {
- if ((ret = parse_playlist(c, v->url, v, NULL)) < 0)
+ if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) {
+ av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n",
+ v->index);
return ret;
+ }
/* If we need to reload the playlist again below (if
* there's still no more segments), switch to a reload
* interval of half the target duration. */
@@ -418,44 +1083,199 @@ reload:
goto reload;
}
- ret = open_input(v);
- if (ret < 0)
- return ret;
+ ret = open_input(c, v);
+ if (ret < 0) {
+ av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n",
+ v->index);
+ v->cur_seq_no += 1;
+ goto reload;
+ }
+ just_opened = 1;
}
- ret = ffurl_read(v->input, buf, buf_size);
- if (ret > 0)
+
+ ret = read_from_url(v, buf, buf_size, READ_NORMAL);
+ if (ret > 0) {
+ if (just_opened && v->is_id3_timestamped != 0) {
+ /* Intercept ID3 tags here, elementary audio streams are required
+ * to convey timestamps using them in the beginning of each segment. */
+ intercept_id3(v, buf, buf_size, &ret);
+ }
+
return ret;
+ }
ffurl_close(v->input);
v->input = NULL;
v->cur_seq_no++;
- c->end_of_segment = 1;
c->cur_seq_no = v->cur_seq_no;
- if (v->ctx && v->ctx->nb_streams &&
- v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) {
- v->needed = 0;
- for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams;
- i++) {
- if (v->parent->streams[i]->discard < AVDISCARD_ALL)
- v->needed = 1;
+ goto restart;
+}
+
+static int playlist_in_multiple_variants(HLSContext *c, struct playlist *pls)
+{
+ int variant_count = 0;
+ int i, j;
+
+ for (i = 0; i < c->n_variants && variant_count < 2; i++) {
+ struct variant *v = c->variants[i];
+
+ for (j = 0; j < v->n_playlists; j++) {
+ if (v->playlists[j] == pls) {
+ variant_count++;
+ break;
+ }
}
}
- if (!v->needed) {
- av_log(v->parent, AV_LOG_INFO, "No longer receiving variant %d\n",
- v->index);
- return AVERROR_EOF;
+
+ return variant_count >= 2;
+}
+
+static void add_renditions_to_variant(HLSContext *c, struct variant *var,
+ enum AVMediaType type, const char *group_id)
+{
+ int i;
+
+ for (i = 0; i < c->n_renditions; i++) {
+ struct rendition *rend = c->renditions[i];
+
+ if (rend->type == type && !strcmp(rend->group_id, group_id)) {
+
+ if (rend->playlist)
+ /* rendition is an external playlist
+ * => add the playlist to the variant */
+ dynarray_add(&var->playlists, &var->n_playlists, rend->playlist);
+ else
+ /* rendition is part of the variant main Media Playlist
+ * => add the rendition to the main Media Playlist */
+ dynarray_add(&var->playlists[0]->renditions,
+ &var->playlists[0]->n_renditions,
+ rend);
+ }
}
- goto restart;
+}
+
+static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pls,
+ enum AVMediaType type)
+{
+ int rend_idx = 0;
+ int i;
+
+ for (i = 0; i < pls->ctx->nb_streams; i++) {
+ AVStream *st = s->streams[pls->stream_offset + i];
+
+ if (st->codec->codec_type != type)
+ continue;
+
+ for (; rend_idx < pls->n_renditions; rend_idx++) {
+ struct rendition *rend = pls->renditions[rend_idx];
+
+ if (rend->type != type)
+ continue;
+
+ if (rend->language[0])
+ av_dict_set(&st->metadata, "language", rend->language, 0);
+ if (rend->name[0])
+ av_dict_set(&st->metadata, "comment", rend->name, 0);
+
+ st->disposition |= rend->disposition;
+ }
+ if (rend_idx >=pls->n_renditions)
+ break;
+ }
+}
+
+/* if timestamp was in valid range: returns 1 and sets seq_no
+ * if not: returns 0 and sets seq_no to closest segment */
+static int find_timestamp_in_playlist(HLSContext *c, struct playlist *pls,
+ int64_t timestamp, int *seq_no)
+{
+ int i;
+ int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ?
+ 0 : c->first_timestamp;
+
+ if (timestamp < pos) {
+ *seq_no = pls->start_seq_no;
+ return 0;
+ }
+
+ for (i = 0; i < pls->n_segments; i++) {
+ int64_t diff = pos + pls->segments[i]->duration - timestamp;
+ if (diff > 0) {
+ *seq_no = pls->start_seq_no + i;
+ return 1;
+ }
+ pos += pls->segments[i]->duration;
+ }
+
+ *seq_no = pls->start_seq_no + pls->n_segments - 1;
+
+ return 0;
+}
+
+static int select_cur_seq_no(HLSContext *c, struct playlist *pls)
+{
+ int seq_no;
+
+ if (!pls->finished && !c->first_packet &&
+ av_gettime_relative() - pls->last_load_time >= default_reload_interval(pls))
+ /* reload the playlist since it was suspended */
+ parse_playlist(c, pls->url, pls, NULL);
+
+ /* If playback is already in progress (we are just selecting a new
+ * playlist) and this is a complete file, find the matching segment
+ * by counting durations. */
+ if (pls->finished && c->cur_timestamp != AV_NOPTS_VALUE) {
+ find_timestamp_in_playlist(c, pls, c->cur_timestamp, &seq_no);
+ return seq_no;
+ }
+
+ if (!pls->finished) {
+ if (!c->first_packet && /* we are doing a segment selection during playback */
+ c->cur_seq_no >= pls->start_seq_no &&
+ c->cur_seq_no < pls->start_seq_no + pls->n_segments)
+ /* While spec 3.4.3 says that we cannot assume anything about the
+ * content at the same sequence number on different playlists,
+ * in practice this seems to work and doing it otherwise would
+ * require us to download a segment to inspect its timestamps. */
+ return c->cur_seq_no;
+
+ /* If this is a live stream, start live_start_index segments from the
+ * start or end */
+ if (c->live_start_index < 0)
+ return pls->start_seq_no + FFMAX(pls->n_segments + c->live_start_index, 0);
+ else
+ return pls->start_seq_no + FFMIN(c->live_start_index, pls->n_segments - 1);
+ }
+
+ /* Otherwise just start on the first segment. */
+ return pls->start_seq_no;
}
static int hls_read_header(AVFormatContext *s)
{
+ URLContext *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb->opaque;
HLSContext *c = s->priv_data;
int ret = 0, i, j, stream_offset = 0;
c->interrupt_callback = &s->interrupt_callback;
+ c->first_packet = 1;
+ c->first_timestamp = AV_NOPTS_VALUE;
+ c->cur_timestamp = AV_NOPTS_VALUE;
+
+ // if the URL context is good, read important options we must broker later
+ if (u && u->prot->priv_data_class) {
+ // get the previous user agent & set back to null if string size is zero
+ update_options(&c->user_agent, "user-agent", u->priv_data);
+
+ // get the previous cookies & set back to null if string size is zero
+ update_options(&c->cookies, "cookies", u->priv_data);
+
+ // get the previous headers & set back to null if string size is zero
+ update_options(&c->headers, "headers", u->priv_data);
+ }
+
if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0)
goto fail;
@@ -464,17 +1284,17 @@ static int hls_read_header(AVFormatContext *s)
ret = AVERROR_EOF;
goto fail;
}
- /* If the playlist only contained variants, parse each individual
- * variant playlist. */
- if (c->n_variants > 1 || c->variants[0]->n_segments == 0) {
- for (i = 0; i < c->n_variants; i++) {
- struct variant *v = c->variants[i];
- if ((ret = parse_playlist(c, v->url, v, NULL)) < 0)
+ /* If the playlist only contained playlists (Master Playlist),
+ * parse each individual playlist. */
+ if (c->n_playlists > 1 || c->playlists[0]->n_segments == 0) {
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
+ if ((ret = parse_playlist(c, pls->url, pls, NULL)) < 0)
goto fail;
}
}
- if (c->variants[0]->n_segments == 0) {
+ if (c->variants[0]->playlists[0]->n_segments == 0) {
av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
ret = AVERROR_EOF;
goto fail;
@@ -482,96 +1302,147 @@ static int hls_read_header(AVFormatContext *s)
/* If this isn't a live stream, calculate the total duration of the
* stream. */
- if (c->variants[0]->finished) {
+ if (c->variants[0]->playlists[0]->finished) {
int64_t duration = 0;
- for (i = 0; i < c->variants[0]->n_segments; i++)
- duration += c->variants[0]->segments[i]->duration;
+ for (i = 0; i < c->variants[0]->playlists[0]->n_segments; i++)
+ duration += c->variants[0]->playlists[0]->segments[i]->duration;
s->duration = duration;
}
- /* Open the demuxer for each variant */
+ /* Associate renditions with variants */
for (i = 0; i < c->n_variants; i++) {
- struct variant *v = c->variants[i];
- AVInputFormat *in_fmt = NULL;
- char bitrate_str[20];
- AVProgram *program;
+ struct variant *var = c->variants[i];
- if (v->n_segments == 0)
- continue;
+ if (var->audio_group[0])
+ add_renditions_to_variant(c, var, AVMEDIA_TYPE_AUDIO, var->audio_group);
+ if (var->video_group[0])
+ add_renditions_to_variant(c, var, AVMEDIA_TYPE_VIDEO, var->video_group);
+ if (var->subtitles_group[0])
+ add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group);
+ }
- if (!(v->ctx = avformat_alloc_context())) {
+ /* Open the demuxer for each playlist */
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
+ AVInputFormat *in_fmt = NULL;
+
+ if (!(pls->ctx = avformat_alloc_context())) {
ret = AVERROR(ENOMEM);
goto fail;
}
- v->index = i;
- v->needed = 1;
- v->parent = s;
+ if (pls->n_segments == 0)
+ continue;
- /* If this is a live stream with more than 3 segments, start at the
- * third last segment. */
- v->cur_seq_no = v->start_seq_no;
- if (!v->finished && v->n_segments > 3)
- v->cur_seq_no = v->start_seq_no + v->n_segments - 3;
+ pls->index = i;
+ pls->needed = 1;
+ pls->parent = s;
+ pls->cur_seq_no = select_cur_seq_no(c, pls);
- v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
- ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v,
+ pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE);
+ if (!pls->read_buffer){
+ ret = AVERROR(ENOMEM);
+ avformat_free_context(pls->ctx);
+ pls->ctx = NULL;
+ goto fail;
+ }
+ ffio_init_context(&pls->pb, pls->read_buffer, INITIAL_BUFFER_SIZE, 0, pls,
read_data, NULL, NULL);
- v->pb.seekable = 0;
- ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url,
+ pls->pb.seekable = 0;
+ ret = av_probe_input_buffer(&pls->pb, &in_fmt, pls->segments[0]->url,
NULL, 0, 0);
if (ret < 0) {
/* Free the ctx - it isn't initialized properly at this point,
* so avformat_close_input shouldn't be called. If
* avformat_open_input fails below, it frees and zeros the
* context, so it doesn't need any special treatment like this. */
- avformat_free_context(v->ctx);
- v->ctx = NULL;
+ av_log(s, AV_LOG_ERROR, "Error when loading first segment '%s'\n", pls->segments[0]->url);
+ avformat_free_context(pls->ctx);
+ pls->ctx = NULL;
goto fail;
}
- v->ctx->pb = &v->pb;
- v->stream_offset = stream_offset;
- ret = avformat_open_input(&v->ctx, v->segments[0]->url, in_fmt, NULL);
- if (ret < 0)
+ pls->ctx->pb = &pls->pb;
+ pls->stream_offset = stream_offset;
+
+ if ((ret = ff_copy_whitelists(pls->ctx, s)) < 0)
goto fail;
- v->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
- ret = avformat_find_stream_info(v->ctx, NULL);
+ ret = avformat_open_input(&pls->ctx, pls->segments[0]->url, in_fmt, NULL);
if (ret < 0)
goto fail;
- snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth);
- program = av_new_program(s, i);
- if (!program)
+ if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) {
+ ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra);
+ avformat_queue_attached_pictures(pls->ctx);
+ ff_id3v2_free_extra_meta(&pls->id3_deferred_extra);
+ pls->id3_deferred_extra = NULL;
+ }
+
+ pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER;
+ ret = avformat_find_stream_info(pls->ctx, NULL);
+ if (ret < 0)
goto fail;
- av_dict_set(&program->metadata, "variant_bitrate", bitrate_str, 0);
- /* Create new AVStreams for each stream in this variant */
- for (j = 0; j < v->ctx->nb_streams; j++) {
+ if (pls->is_id3_timestamped == -1)
+ av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n");
+
+ /* Create new AVStreams for each stream in this playlist */
+ for (j = 0; j < pls->ctx->nb_streams; j++) {
AVStream *st = avformat_new_stream(s, NULL);
- AVStream *ist = v->ctx->streams[j];
+ AVStream *ist = pls->ctx->streams[j];
if (!st) {
ret = AVERROR(ENOMEM);
goto fail;
}
- ff_program_add_stream_index(s, i, stream_offset + j);
st->id = i;
- avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);
- avcodec_copy_context(st->codec, v->ctx->streams[j]->codec);
- if (v->bandwidth)
- av_dict_set(&st->metadata, "variant_bitrate", bitrate_str,
- 0);
+
+ avcodec_copy_context(st->codec, pls->ctx->streams[j]->codec);
+
+ if (pls->is_id3_timestamped) /* custom timestamps via id3 */
+ avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE);
+ else
+ avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);
}
- stream_offset += v->ctx->nb_streams;
+
+ add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO);
+ add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO);
+ add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE);
+
+ stream_offset += pls->ctx->nb_streams;
}
- c->first_packet = 1;
- c->first_timestamp = AV_NOPTS_VALUE;
- c->seek_timestamp = AV_NOPTS_VALUE;
+ /* Create a program for each variant */
+ for (i = 0; i < c->n_variants; i++) {
+ struct variant *v = c->variants[i];
+ AVProgram *program;
+
+ program = av_new_program(s, i);
+ if (!program)
+ goto fail;
+ av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0);
+
+ for (j = 0; j < v->n_playlists; j++) {
+ struct playlist *pls = v->playlists[j];
+ int is_shared = playlist_in_multiple_variants(c, pls);
+ int k;
+
+ for (k = 0; k < pls->ctx->nb_streams; k++) {
+ struct AVStream *st = s->streams[pls->stream_offset + k];
+
+ ff_program_add_stream_index(s, i, pls->stream_offset + k);
+
+ /* Set variant_bitrate for streams unique to this variant */
+ if (!is_shared && v->bandwidth)
+ av_dict_set_int(&st->metadata, "variant_bitrate", v->bandwidth, 0);
+ }
+ }
+ }
return 0;
fail:
+ free_playlist_list(c);
free_variant_list(c);
+ free_rendition_list(c);
return ret;
}
@@ -581,127 +1452,171 @@ static int recheck_discard_flags(AVFormatContext *s, int first)
int i, changed = 0;
/* Check if any new streams are needed */
- for (i = 0; i < c->n_variants; i++)
- c->variants[i]->cur_needed = 0;;
+ for (i = 0; i < c->n_playlists; i++)
+ c->playlists[i]->cur_needed = 0;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
- struct variant *var = c->variants[s->streams[i]->id];
+ struct playlist *pls = c->playlists[s->streams[i]->id];
if (st->discard < AVDISCARD_ALL)
- var->cur_needed = 1;
+ pls->cur_needed = 1;
}
- for (i = 0; i < c->n_variants; i++) {
- struct variant *v = c->variants[i];
- if (v->cur_needed && !v->needed) {
- v->needed = 1;
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
+ if (pls->cur_needed && !pls->needed) {
+ pls->needed = 1;
changed = 1;
- v->cur_seq_no = c->cur_seq_no;
- v->pb.eof_reached = 0;
- av_log(s, AV_LOG_INFO, "Now receiving variant %d\n", i);
- } else if (first && !v->cur_needed && v->needed) {
- if (v->input)
- ffurl_close(v->input);
- v->input = NULL;
- v->needed = 0;
+ pls->cur_seq_no = select_cur_seq_no(c, pls);
+ pls->pb.eof_reached = 0;
+ if (c->cur_timestamp != AV_NOPTS_VALUE) {
+ /* catch up */
+ pls->seek_timestamp = c->cur_timestamp;
+ pls->seek_flags = AVSEEK_FLAG_ANY;
+ pls->seek_stream_index = -1;
+ }
+ av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %d\n", i, pls->cur_seq_no);
+ } else if (first && !pls->cur_needed && pls->needed) {
+ if (pls->input)
+ ffurl_close(pls->input);
+ pls->input = NULL;
+ pls->needed = 0;
changed = 1;
- av_log(s, AV_LOG_INFO, "No longer receiving variant %d\n", i);
+ av_log(s, AV_LOG_INFO, "No longer receiving playlist %d\n", i);
}
}
return changed;
}
+static void fill_timing_for_id3_timestamped_stream(struct playlist *pls)
+{
+ if (pls->id3_offset >= 0) {
+ pls->pkt.dts = pls->id3_mpegts_timestamp +
+ av_rescale_q(pls->id3_offset,
+ pls->ctx->streams[pls->pkt.stream_index]->time_base,
+ MPEG_TIME_BASE_Q);
+ if (pls->pkt.duration)
+ pls->id3_offset += pls->pkt.duration;
+ else
+ pls->id3_offset = -1;
+ } else {
+ /* there have been packets with unknown duration
+ * since the last id3 tag, should not normally happen */
+ pls->pkt.dts = AV_NOPTS_VALUE;
+ }
+
+ if (pls->pkt.duration)
+ pls->pkt.duration = av_rescale_q(pls->pkt.duration,
+ pls->ctx->streams[pls->pkt.stream_index]->time_base,
+ MPEG_TIME_BASE_Q);
+
+ pls->pkt.pts = AV_NOPTS_VALUE;
+}
+
+static AVRational get_timebase(struct playlist *pls)
+{
+ if (pls->is_id3_timestamped)
+ return MPEG_TIME_BASE_Q;
+
+ return pls->ctx->streams[pls->pkt.stream_index]->time_base;
+}
+
+static int compare_ts_with_wrapdetect(int64_t ts_a, struct playlist *pls_a,
+ int64_t ts_b, struct playlist *pls_b)
+{
+ int64_t scaled_ts_a = av_rescale_q(ts_a, get_timebase(pls_a), MPEG_TIME_BASE_Q);
+ int64_t scaled_ts_b = av_rescale_q(ts_b, get_timebase(pls_b), MPEG_TIME_BASE_Q);
+
+ return av_compare_mod(scaled_ts_a, scaled_ts_b, 1LL << 33);
+}
+
static int hls_read_packet(AVFormatContext *s, AVPacket *pkt)
{
HLSContext *c = s->priv_data;
- int ret, i, minvariant = -1;
+ int ret, i, minplaylist = -1;
- if (c->first_packet) {
- recheck_discard_flags(s, 1);
- c->first_packet = 0;
- }
+ recheck_discard_flags(s, c->first_packet);
-start:
- c->end_of_segment = 0;
- for (i = 0; i < c->n_variants; i++) {
- struct variant *var = c->variants[i];
- /* Make sure we've got one buffered packet from each open variant
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
+ /* Make sure we've got one buffered packet from each open playlist
* stream */
- if (var->needed && !var->pkt.data) {
+ if (pls->needed && !pls->pkt.data) {
while (1) {
int64_t ts_diff;
- AVStream *st;
- ret = av_read_frame(var->ctx, &var->pkt);
+ AVRational tb;
+ ret = av_read_frame(pls->ctx, &pls->pkt);
if (ret < 0) {
- if (!var->pb.eof_reached)
+ if (!avio_feof(&pls->pb) && ret != AVERROR_EOF)
return ret;
- reset_packet(&var->pkt);
+ reset_packet(&pls->pkt);
break;
} else {
+ /* stream_index check prevents matching picture attachments etc. */
+ if (pls->is_id3_timestamped && pls->pkt.stream_index == 0) {
+ /* audio elementary streams are id3 timestamped */
+ fill_timing_for_id3_timestamped_stream(pls);
+ }
+
if (c->first_timestamp == AV_NOPTS_VALUE &&
- var->pkt.dts != AV_NOPTS_VALUE)
- c->first_timestamp = av_rescale_q(var->pkt.dts,
- var->ctx->streams[var->pkt.stream_index]->time_base,
- AV_TIME_BASE_Q);
+ pls->pkt.dts != AV_NOPTS_VALUE)
+ c->first_timestamp = av_rescale_q(pls->pkt.dts,
+ get_timebase(pls), AV_TIME_BASE_Q);
}
- if (c->seek_timestamp == AV_NOPTS_VALUE)
+ if (pls->seek_timestamp == AV_NOPTS_VALUE)
break;
- if (var->pkt.dts == AV_NOPTS_VALUE) {
- c->seek_timestamp = AV_NOPTS_VALUE;
- break;
- }
+ if (pls->seek_stream_index < 0 ||
+ pls->seek_stream_index == pls->pkt.stream_index) {
- st = var->ctx->streams[var->pkt.stream_index];
- ts_diff = av_rescale_rnd(var->pkt.dts, AV_TIME_BASE,
- st->time_base.den, AV_ROUND_DOWN) -
- c->seek_timestamp;
- if (ts_diff >= 0 && (c->seek_flags & AVSEEK_FLAG_ANY ||
- var->pkt.flags & AV_PKT_FLAG_KEY)) {
- c->seek_timestamp = AV_NOPTS_VALUE;
- break;
+ if (pls->pkt.dts == AV_NOPTS_VALUE) {
+ pls->seek_timestamp = AV_NOPTS_VALUE;
+ break;
+ }
+
+ tb = get_timebase(pls);
+ ts_diff = av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE,
+ tb.den, AV_ROUND_DOWN) -
+ pls->seek_timestamp;
+ if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY ||
+ pls->pkt.flags & AV_PKT_FLAG_KEY)) {
+ pls->seek_timestamp = AV_NOPTS_VALUE;
+ break;
+ }
}
- av_free_packet(&var->pkt);
- reset_packet(&var->pkt);
+ av_free_packet(&pls->pkt);
+ reset_packet(&pls->pkt);
}
}
- /* Check if this stream still is on an earlier segment number, or
- * has the packet with the lowest dts */
- if (var->pkt.data) {
- struct variant *minvar = minvariant < 0 ?
- NULL : c->variants[minvariant];
- if (minvariant < 0 || var->cur_seq_no < minvar->cur_seq_no) {
- minvariant = i;
- } else if (var->cur_seq_no == minvar->cur_seq_no) {
- int64_t dts = var->pkt.dts;
- int64_t mindts = minvar->pkt.dts;
- AVStream *st = var->ctx->streams[var->pkt.stream_index];
- AVStream *minst = minvar->ctx->streams[minvar->pkt.stream_index];
-
- if (dts == AV_NOPTS_VALUE) {
- minvariant = i;
- } else if (mindts != AV_NOPTS_VALUE) {
- if (st->start_time != AV_NOPTS_VALUE)
- dts -= st->start_time;
- if (minst->start_time != AV_NOPTS_VALUE)
- mindts -= minst->start_time;
-
- if (av_compare_ts(dts, st->time_base,
- mindts, minst->time_base) < 0)
- minvariant = i;
- }
+ /* Check if this stream has the packet with the lowest dts */
+ if (pls->pkt.data) {
+ struct playlist *minpls = minplaylist < 0 ?
+ NULL : c->playlists[minplaylist];
+ if (minplaylist < 0) {
+ minplaylist = i;
+ } else {
+ int64_t dts = pls->pkt.dts;
+ int64_t mindts = minpls->pkt.dts;
+
+ if (dts == AV_NOPTS_VALUE ||
+ (mindts != AV_NOPTS_VALUE && compare_ts_with_wrapdetect(dts, pls, mindts, minpls) < 0))
+ minplaylist = i;
}
}
}
- if (c->end_of_segment) {
- if (recheck_discard_flags(s, 0))
- goto start;
- }
+
/* If we got a packet, return it */
- if (minvariant >= 0) {
- *pkt = c->variants[minvariant]->pkt;
- pkt->stream_index += c->variants[minvariant]->stream_offset;
- reset_packet(&c->variants[minvariant]->pkt);
+ if (minplaylist >= 0) {
+ struct playlist *pls = c->playlists[minplaylist];
+ *pkt = pls->pkt;
+ pkt->stream_index += pls->stream_offset;
+ reset_packet(&c->playlists[minplaylist]->pkt);
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ c->cur_timestamp = av_rescale_q(pkt->dts,
+ pls->ctx->streams[pls->pkt.stream_index]->time_base,
+ AV_TIME_BASE_Q);
+
return 0;
}
return AVERROR_EOF;
@@ -711,7 +1626,9 @@ static int hls_close(AVFormatContext *s)
{
HLSContext *c = s->priv_data;
+ free_playlist_list(c);
free_variant_list(c);
+ free_rendition_list(c);
return 0;
}
@@ -719,58 +1636,80 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
HLSContext *c = s->priv_data;
- int i, j, ret;
+ struct playlist *seek_pls = NULL;
+ int i, seq_no;
+ int64_t first_timestamp, seek_timestamp, duration;
- if ((flags & AVSEEK_FLAG_BYTE) || !c->variants[0]->finished)
+ if ((flags & AVSEEK_FLAG_BYTE) ||
+ !(c->variants[0]->playlists[0]->finished || c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT))
return AVERROR(ENOSYS);
- c->seek_flags = flags;
- c->seek_timestamp = stream_index < 0 ? timestamp :
- av_rescale_rnd(timestamp, AV_TIME_BASE,
- s->streams[stream_index]->time_base.den,
- flags & AVSEEK_FLAG_BACKWARD ?
- AV_ROUND_DOWN : AV_ROUND_UP);
- timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE, stream_index >= 0 ?
- s->streams[stream_index]->time_base.den :
- AV_TIME_BASE, flags & AVSEEK_FLAG_BACKWARD ?
- AV_ROUND_DOWN : AV_ROUND_UP);
- if (s->duration < c->seek_timestamp) {
- c->seek_timestamp = AV_NOPTS_VALUE;
+ first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ?
+ 0 : c->first_timestamp;
+
+ seek_timestamp = av_rescale_rnd(timestamp, AV_TIME_BASE,
+ s->streams[stream_index]->time_base.den,
+ flags & AVSEEK_FLAG_BACKWARD ?
+ AV_ROUND_DOWN : AV_ROUND_UP);
+
+ duration = s->duration == AV_NOPTS_VALUE ?
+ 0 : s->duration;
+
+ if (0 < duration && duration < seek_timestamp - first_timestamp)
return AVERROR(EIO);
+
+ /* find the playlist with the specified stream */
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
+ if (stream_index >= pls->stream_offset &&
+ stream_index - pls->stream_offset < pls->ctx->nb_streams) {
+ seek_pls = pls;
+ break;
+ }
}
+ /* check if the timestamp is valid for the playlist with the
+ * specified stream index */
+ if (!seek_pls || !find_timestamp_in_playlist(c, seek_pls, seek_timestamp, &seq_no))
+ return AVERROR(EIO);
- ret = AVERROR(EIO);
- for (i = 0; i < c->n_variants; i++) {
+ /* set segment now so we do not need to search again below */
+ seek_pls->cur_seq_no = seq_no;
+ seek_pls->seek_stream_index = stream_index - seek_pls->stream_offset;
+
+ for (i = 0; i < c->n_playlists; i++) {
/* Reset reading */
- struct variant *var = c->variants[i];
- int64_t pos = c->first_timestamp == AV_NOPTS_VALUE ?
- 0 : c->first_timestamp;
- if (var->input) {
- ffurl_close(var->input);
- var->input = NULL;
+ struct playlist *pls = c->playlists[i];
+ if (pls->input) {
+ ffurl_close(pls->input);
+ pls->input = NULL;
}
- av_free_packet(&var->pkt);
- reset_packet(&var->pkt);
- var->pb.eof_reached = 0;
+ av_free_packet(&pls->pkt);
+ reset_packet(&pls->pkt);
+ pls->pb.eof_reached = 0;
/* Clear any buffered data */
- var->pb.buf_end = var->pb.buf_ptr = var->pb.buffer;
+ pls->pb.buf_end = pls->pb.buf_ptr = pls->pb.buffer;
/* Reset the pos, to let the mpegts demuxer know we've seeked. */
- var->pb.pos = 0;
-
- /* Locate the segment that contains the target timestamp */
- for (j = 0; j < var->n_segments; j++) {
- if (timestamp >= pos &&
- timestamp < pos + var->segments[j]->duration) {
- var->cur_seq_no = var->start_seq_no + j;
- ret = 0;
- break;
- }
- pos += var->segments[j]->duration;
+ pls->pb.pos = 0;
+ /* Flush the packet queue of the subdemuxer. */
+ ff_read_frame_flush(pls->ctx);
+
+ pls->seek_timestamp = seek_timestamp;
+ pls->seek_flags = flags;
+
+ if (pls != seek_pls) {
+ /* set closest segment seq_no for playlists not handled above */
+ find_timestamp_in_playlist(c, pls, seek_timestamp, &pls->cur_seq_no);
+ /* seek the playlist to the given position without taking
+ * keyframes into account since this playlist does not have the
+ * specified stream where we should look for the keyframes */
+ pls->seek_stream_index = -1;
+ pls->seek_flags |= AVSEEK_FLAG_ANY;
}
- if (ret)
- c->seek_timestamp = AV_NOPTS_VALUE;
}
- return ret;
+
+ c->cur_timestamp = seek_timestamp;
+
+ return 0;
}
static int hls_probe(AVProbeData *p)
@@ -786,9 +1725,25 @@ static int hls_probe(AVProbeData *p)
return 0;
}
+#define OFFSET(x) offsetof(HLSContext, x)
+#define FLAGS AV_OPT_FLAG_DECODING_PARAM
+static const AVOption hls_options[] = {
+ {"live_start_index", "segment index to start live streams at (negative values are from the end)",
+ OFFSET(live_start_index), FF_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS},
+ {NULL}
+};
+
+static const AVClass hls_class = {
+ .class_name = "hls,applehttp",
+ .item_name = av_default_item_name,
+ .option = hls_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVInputFormat ff_hls_demuxer = {
.name = "hls,applehttp",
.long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"),
+ .priv_class = &hls_class,
.priv_data_size = sizeof(HLSContext),
.read_probe = hls_probe,
.read_header = hls_read_header,
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 21c952630d..4d9466c91f 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -2,26 +2,31 @@
* Apple HTTP Live Streaming segmenter
* Copyright (c) 2012, Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 <float.h>
#include <stdint.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "libavutil/parseutils.h"
#include "libavutil/avstring.h"
@@ -30,12 +35,25 @@
#include "avformat.h"
#include "internal.h"
-
-typedef struct ListEntry {
- char name[1024];
- int duration;
- struct ListEntry *next;
-} ListEntry;
+#include "os_support.h"
+
+typedef struct HLSSegment {
+ char filename[1024];
+ double duration; /* in seconds */
+ int64_t pos;
+ int64_t size;
+
+ struct HLSSegment *next;
+} HLSSegment;
+
+typedef enum HLSFlags {
+ // Generate a single media file and use byte ranges in the playlist.
+ HLS_SINGLE_FILE = (1 << 0),
+ HLS_DELETE_SEGMENTS = (1 << 1),
+ HLS_ROUND_DURATIONS = (1 << 2),
+ HLS_DISCONT_START = (1 << 3),
+ HLS_OMIT_ENDLIST = (1 << 4),
+} HLSFlags;
typedef struct HLSContext {
const AVClass *class; // Class for private options.
@@ -43,35 +61,116 @@ typedef struct HLSContext {
int64_t sequence;
int64_t start_sequence;
AVOutputFormat *oformat;
+
AVFormatContext *avf;
+
float time; // Set by a private option.
- int size; // Set by a private option.
+ int max_nb_segments; // Set by a private option.
int wrap; // Set by a private option.
- int allowcache;
+ uint32_t flags; // enum HLSFlags
+ char *segment_filename;
+
+ int allowcache;
int64_t recording_time;
int has_video;
int64_t start_pts;
int64_t end_pts;
- int64_t duration; // last segment duration computed so far, in seconds
+ double duration; // last segment duration computed so far, in seconds
+ int64_t start_pos; // last segment starting position
+ int64_t size; // last segment size
int nb_entries;
- ListEntry *list;
- ListEntry *end_list;
+ int discontinuity_set;
+
+ HLSSegment *segments;
+ HLSSegment *last_segment;
+ HLSSegment *old_segments;
+
char *basename;
char *baseurl;
+ char *format_options_str;
+ AVDictionary *format_options;
} HLSContext;
+static int hls_delete_old_segments(HLSContext *hls) {
+
+ HLSSegment *segment, *previous_segment = NULL;
+ float playlist_duration = 0.0f;
+ int ret = 0, path_size;
+ char *dirname = NULL, *p, *path;
+
+ segment = hls->segments;
+ while (segment) {
+ playlist_duration += segment->duration;
+ segment = segment->next;
+ }
+
+ segment = hls->old_segments;
+ while (segment) {
+ playlist_duration -= segment->duration;
+ previous_segment = segment;
+ segment = previous_segment->next;
+ if (playlist_duration <= -previous_segment->duration) {
+ previous_segment->next = NULL;
+ break;
+ }
+ }
+
+ if (segment) {
+ if (hls->segment_filename) {
+ dirname = av_strdup(hls->segment_filename);
+ } else {
+ dirname = av_strdup(hls->avf->filename);
+ }
+ if (!dirname) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ p = (char *)av_basename(dirname);
+ *p = '\0';
+ }
+
+ while (segment) {
+ av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n",
+ segment->filename);
+ path_size = strlen(dirname) + strlen(segment->filename) + 1;
+ path = av_malloc(path_size);
+ if (!path) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ av_strlcpy(path, dirname, path_size);
+ av_strlcat(path, segment->filename, path_size);
+ if (unlink(path) < 0) {
+ av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n",
+ path, strerror(errno));
+ }
+ av_free(path);
+ previous_segment = segment;
+ segment = previous_segment->next;
+ av_free(previous_segment);
+ }
+
+fail:
+ av_free(dirname);
+
+ return ret;
+}
+
static int hls_mux_init(AVFormatContext *s)
{
HLSContext *hls = s->priv_data;
AVFormatContext *oc;
- int i;
+ int i, ret;
- hls->avf = oc = avformat_alloc_context();
- if (!oc)
- return AVERROR(ENOMEM);
+ ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL);
+ if (ret < 0)
+ return ret;
+ oc = hls->avf;
oc->oformat = hls->oformat;
oc->interrupt_callback = s->interrupt_callback;
+ oc->max_delay = s->max_delay;
+ av_dict_copy(&oc->metadata, s->metadata, 0);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st;
@@ -81,33 +180,46 @@ static int hls_mux_init(AVFormatContext *s)
st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
st->time_base = s->streams[i]->time_base;
}
+ hls->start_pos = 0;
return 0;
}
-static int append_entry(HLSContext *hls, uint64_t duration)
+/* Create a new segment and append it to the segment list */
+static int hls_append_segment(HLSContext *hls, double duration, int64_t pos,
+ int64_t size)
{
- ListEntry *en = av_malloc(sizeof(*en));
+ HLSSegment *en = av_malloc(sizeof(*en));
+ int ret;
if (!en)
return AVERROR(ENOMEM);
- av_strlcpy(en->name, av_basename(hls->avf->filename), sizeof(en->name));
+ av_strlcpy(en->filename, av_basename(hls->avf->filename), sizeof(en->filename));
en->duration = duration;
+ en->pos = pos;
+ en->size = size;
en->next = NULL;
- if (!hls->list)
- hls->list = en;
+ if (!hls->segments)
+ hls->segments = en;
else
- hls->end_list->next = en;
-
- hls->end_list = en;
-
- if (hls->nb_entries >= hls->size) {
- en = hls->list;
- hls->list = en->next;
- av_free(en);
+ hls->last_segment->next = en;
+
+ hls->last_segment = en;
+
+ if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) {
+ en = hls->segments;
+ hls->segments = en->next;
+ if (en && hls->flags & HLS_DELETE_SEGMENTS &&
+ !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) {
+ en->next = hls->old_segments;
+ hls->old_segments = en;
+ if ((ret = hls_delete_old_segments(hls)) < 0)
+ return ret;
+ } else
+ av_free(en);
} else
hls->nb_entries++;
@@ -116,9 +228,9 @@ static int append_entry(HLSContext *hls, uint64_t duration)
return 0;
}
-static void free_entries(HLSContext *hls)
+static void hls_free_segments(HLSSegment *p)
{
- ListEntry *p = hls->list, *en;
+ HLSSegment *en;
while(p) {
en = p;
@@ -130,25 +242,33 @@ static void free_entries(HLSContext *hls)
static int hls_window(AVFormatContext *s, int last)
{
HLSContext *hls = s->priv_data;
- ListEntry *en;
+ HLSSegment *en;
int target_duration = 0;
int ret = 0;
AVIOContext *out = NULL;
char temp_filename[1024];
- int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->size);
+ int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries);
+ int version = hls->flags & HLS_SINGLE_FILE ? 4 : 3;
+ const char *proto = avio_find_protocol_name(s->filename);
+ int use_rename = proto && !strcmp(proto, "file");
+ static unsigned warned_non_file;
+
+ if (!use_rename && !warned_non_file++)
+ av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporarly partial files\n");
- snprintf(temp_filename, sizeof(temp_filename), "%s.tmp", s->filename);
+ snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename);
if ((ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL)) < 0)
goto fail;
- for (en = hls->list; en; en = en->next) {
+ for (en = hls->segments; en; en = en->next) {
if (target_duration < en->duration)
- target_duration = en->duration;
+ target_duration = ceil(en->duration);
}
+ hls->discontinuity_set = 0;
avio_printf(out, "#EXTM3U\n");
- avio_printf(out, "#EXT-X-VERSION:3\n");
+ avio_printf(out, "#EXT-X-VERSION:%d\n", version);
if (hls->allowcache == 0 || hls->allowcache == 1) {
avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES");
}
@@ -157,21 +277,30 @@ static int hls_window(AVFormatContext *s, int last)
av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n",
sequence);
-
- for (en = hls->list; en; en = en->next) {
- avio_printf(out, "#EXTINF:%d,\n", en->duration);
+ if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){
+ avio_printf(out, "#EXT-X-DISCONTINUITY\n");
+ hls->discontinuity_set = 1;
+ }
+ for (en = hls->segments; en; en = en->next) {
+ if (hls->flags & HLS_ROUND_DURATIONS)
+ avio_printf(out, "#EXTINF:%d,\n", (int)round(en->duration));
+ else
+ avio_printf(out, "#EXTINF:%f,\n", en->duration);
+ if (hls->flags & HLS_SINGLE_FILE)
+ avio_printf(out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n",
+ en->size, en->pos);
if (hls->baseurl)
avio_printf(out, "%s", hls->baseurl);
- avio_printf(out, "%s\n", en->name);
+ avio_printf(out, "%s\n", en->filename);
}
- if (last)
+ if (last && (hls->flags & HLS_OMIT_ENDLIST)==0)
avio_printf(out, "#EXT-X-ENDLIST\n");
fail:
avio_closep(&out);
- if (ret >= 0)
- ff_rename(temp_filename, s->filename);
+ if (ret >= 0 && use_rename)
+ ff_rename(temp_filename, s->filename, s);
return ret;
}
@@ -181,9 +310,15 @@ static int hls_start(AVFormatContext *s)
AVFormatContext *oc = c->avf;
int err = 0;
- if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- c->basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0)
- return AVERROR(EINVAL);
+ if (c->flags & HLS_SINGLE_FILE)
+ av_strlcpy(oc->filename, c->basename,
+ sizeof(oc->filename));
+ else
+ if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
+ c->basename, c->wrap ? c->sequence % c->wrap : c->sequence) < 0) {
+ av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->basename);
+ return AVERROR(EINVAL);
+ }
c->number++;
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
@@ -202,12 +337,21 @@ static int hls_write_header(AVFormatContext *s)
int ret, i;
char *p;
const char *pattern = "%d.ts";
- int basename_size = strlen(s->filename) + strlen(pattern) + 1;
+ AVDictionary *options = NULL;
+ int basename_size;
hls->sequence = hls->start_sequence;
hls->recording_time = hls->time * AV_TIME_BASE;
hls->start_pts = AV_NOPTS_VALUE;
+ if (hls->format_options_str) {
+ ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str);
+ goto fail;
+ }
+ }
+
for (i = 0; i < s->nb_streams; i++)
hls->has_video +=
s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO;
@@ -224,35 +368,55 @@ static int hls_write_header(AVFormatContext *s)
goto fail;
}
- hls->basename = av_malloc(basename_size);
-
- if (!hls->basename) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ if (hls->segment_filename) {
+ hls->basename = av_strdup(hls->segment_filename);
+ if (!hls->basename) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ } else {
+ if (hls->flags & HLS_SINGLE_FILE)
+ pattern = ".ts";
+
+ basename_size = strlen(s->filename) + strlen(pattern) + 1;
+ hls->basename = av_malloc(basename_size);
+ if (!hls->basename) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ av_strlcpy(hls->basename, s->filename, basename_size);
+
+ p = strrchr(hls->basename, '.');
+ if (p)
+ *p = '\0';
+ av_strlcat(hls->basename, pattern, basename_size);
}
- strcpy(hls->basename, s->filename);
-
- p = strrchr(hls->basename, '.');
-
- if (p)
- *p = '\0';
-
- av_strlcat(hls->basename, pattern, basename_size);
-
if ((ret = hls_mux_init(s)) < 0)
goto fail;
if ((ret = hls_start(s)) < 0)
goto fail;
- if ((ret = avformat_write_header(hls->avf, NULL)) < 0)
- return ret;
-
-
+ av_dict_copy(&options, hls->format_options, 0);
+ ret = avformat_write_header(hls->avf, &options);
+ if (av_dict_count(options)) {
+ av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ av_assert0(s->nb_streams == hls->avf->nb_streams);
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *inner_st = hls->avf->streams[i];
+ AVStream *outer_st = s->streams[i];
+ avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den);
+ }
fail:
- if (ret) {
- av_free(hls->basename);
+
+ av_dict_free(&options);
+ if (ret < 0) {
+ av_freep(&hls->basename);
if (hls->avf)
avformat_free_context(hls->avf);
}
@@ -265,6 +429,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
AVFormatContext *oc = hls->avf;
AVStream *st = s->streams[pkt->stream_index];
int64_t end_pts = hls->recording_time * hls->number;
+ int is_ref_pkt = 1;
int ret, can_split = 1;
if (hls->start_pts == AV_NOPTS_VALUE) {
@@ -275,28 +440,41 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
if (hls->has_video) {
can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
pkt->flags & AV_PKT_FLAG_KEY;
+ is_ref_pkt = st->codec->codec_type == AVMEDIA_TYPE_VIDEO;
}
if (pkt->pts == AV_NOPTS_VALUE)
- can_split = 0;
- else
- hls->duration = av_rescale(pkt->pts - hls->end_pts,
- st->time_base.num, st->time_base.den);
+ is_ref_pkt = can_split = 0;
+
+ if (is_ref_pkt)
+ hls->duration = (double)(pkt->pts - hls->end_pts)
+ * st->time_base.num / st->time_base.den;
if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base,
end_pts, AV_TIME_BASE_Q) >= 0) {
- ret = append_entry(hls, hls->duration);
- if (ret)
+ int64_t new_start_pos;
+ av_write_frame(oc, NULL); /* Flush any buffered data */
+
+ new_start_pos = avio_tell(hls->avf->pb);
+ hls->size = new_start_pos - hls->start_pos;
+ ret = hls_append_segment(hls, hls->duration, hls->start_pos, hls->size);
+ hls->start_pos = new_start_pos;
+ if (ret < 0)
return ret;
hls->end_pts = pkt->pts;
hls->duration = 0;
- av_write_frame(oc, NULL); /* Flush any buffered data */
- avio_close(oc->pb);
+ if (hls->flags & HLS_SINGLE_FILE) {
+ if (hls->avf->oformat->priv_class && hls->avf->priv_data)
+ av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0);
+ hls->number++;
+ } else {
+ avio_closep(&oc->pb);
- ret = hls_start(s);
+ ret = hls_start(s);
+ }
- if (ret)
+ if (ret < 0)
return ret;
oc = hls->avf;
@@ -305,7 +483,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
return ret;
}
- ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
+ ret = ff_write_chained(oc, pkt->stream_index, pkt, s, 0);
return ret;
}
@@ -316,25 +494,39 @@ static int hls_write_trailer(struct AVFormatContext *s)
AVFormatContext *oc = hls->avf;
av_write_trailer(oc);
- avio_closep(&oc->pb);
+ if (oc->pb) {
+ hls->size = avio_tell(hls->avf->pb) - hls->start_pos;
+ avio_closep(&oc->pb);
+ hls_append_segment(hls, hls->duration, hls->start_pos, hls->size);
+ }
+ av_freep(&hls->basename);
avformat_free_context(oc);
- av_free(hls->basename);
- append_entry(hls, hls->duration);
+ hls->avf = NULL;
hls_window(s, 1);
- free_entries(hls);
+ hls_free_segments(hls->segments);
+ hls_free_segments(hls->old_segments);
return 0;
}
#define OFFSET(x) offsetof(HLSContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- {"start_number", "first number in the sequence", OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E},
- {"hls_time", "segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E},
- {"hls_list_size", "maximum number of playlist entries", OFFSET(size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
- {"hls_wrap", "number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
+ {"start_number", "set first number in the sequence", OFFSET(start_sequence),AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, E},
+ {"hls_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E},
+ {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
+ {"hls_ts_options","set hls mpegts list of options for the container format used for hls", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
+ {"hls_wrap", "set number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E},
{"hls_allow_cache", "explicitly set whether the client MAY (1) or MUST NOT (0) cache media segments", OFFSET(allowcache), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, E},
{"hls_base_url", "url to prepend to each playlist entry", OFFSET(baseurl), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
+ {"hls_segment_filename", "filename template for segment files", OFFSET(segment_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
+ {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"},
+ {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"},
+ {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"},
+ {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"},
+ {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"},
+ {"omit_endlist", "Do not append an endlist when ending stream", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_OMIT_ENDLIST }, 0, UINT_MAX, E, "flags"},
+
{ NULL },
};
diff --git a/libavformat/hlsproto.c b/libavformat/hlsproto.c
index 0eba049797..92843df258 100644
--- a/libavformat/hlsproto.c
+++ b/libavformat/hlsproto.c
@@ -2,20 +2,20 @@
* Apple HTTP Live Streaming Protocol Handler
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,7 +80,7 @@ static void free_segment_list(HLSContext *s)
{
int i;
for (i = 0; i < s->n_segments; i++)
- av_free(s->segments[i]);
+ av_freep(&s->segments[i]);
av_freep(&s->segments);
s->n_segments = 0;
}
@@ -89,7 +89,7 @@ static void free_variant_list(HLSContext *s)
{
int i;
for (i = 0; i < s->n_variants; i++)
- av_free(s->variants[i]);
+ av_freep(&s->variants[i]);
av_freep(&s->variants);
s->n_variants = 0;
}
@@ -128,7 +128,7 @@ static int parse_playlist(URLContext *h, const char *url)
free_segment_list(s);
s->finished = 0;
- while (!in->eof_reached) {
+ while (!avio_feof(in)) {
read_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
struct variant_info info = {{0}};
diff --git a/libavformat/hnm.c b/libavformat/hnm.c
index 54ac6c2ce4..1320fa5206 100644
--- a/libavformat/hnm.c
+++ b/libavformat/hnm.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2012 David Kment
*
- * This file is part of Libav.
+ * This file is part of FFmpeg .
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg ; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -92,7 +92,7 @@ static int hnm_read_header(AVFormatContext *s)
hnm->currentframe = 0;
- if (hnm->width < 320 || hnm->width > 640 ||
+ if (hnm->width < 256 || hnm->width > 640 ||
hnm->height < 150 || hnm->height > 480) {
av_log(s, AV_LOG_ERROR,
"invalid resolution: %ux%u\n", hnm->width, hnm->height);
@@ -150,7 +150,7 @@ static int hnm_read_packet(AVFormatContext *s, AVPacket *pkt)
chunk_id = avio_rl16(pb);
avio_skip(pb, 2);
- if (chunk_size > hnm->superchunk_remaining) {
+ if (chunk_size > hnm->superchunk_remaining || !chunk_size) {
av_log(s, AV_LOG_ERROR,
"invalid chunk size: %"PRIu32", offset: %"PRId64"\n",
chunk_size, avio_tell(pb));
diff --git a/libavformat/http.c b/libavformat/http.c
index 3b9aa2d4a1..4f6716a75b 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -1,21 +1,21 @@
/*
- * HTTP protocol for avconv client
+ * HTTP protocol for ffmpeg client
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,7 +36,7 @@
#include "os_support.h"
#include "url.h"
-/* XXX: POST protocol is not completely implemented because avconv uses
+/* XXX: POST protocol is not completely implemented because ffmpeg uses
* only a subset of it. */
/* The IO buffer size is unrelated to the max URL size in itself, but needs
@@ -64,6 +64,7 @@ typedef struct HTTPContext {
/* Set if the server correctly handles Connection: close and will close
* the connection after feeding us the content. */
int willclose;
+ int seekable; /**< Control seekability, 0 = disable, 1 = enable, -1 = probe. */
int chunked_post;
/* A flag which indicates if the end of chunked encoding has been sent. */
int end_chunked_post;
@@ -73,6 +74,11 @@ typedef struct HTTPContext {
int multiple_requests;
uint8_t *post_data;
int post_datalen;
+ int is_akamai;
+ int is_mediagateway;
+ char *cookies; ///< holds newline (\n) delimited Set-Cookie header field values (without the "Set-Cookie: " field name)
+ /* A dictionary containing cookies keyed by cookie name */
+ AVDictionary *cookie_dict;
int icy;
/* how much data was read since the last ICY metadata packet */
int icy_data_read;
@@ -89,6 +95,8 @@ typedef struct HTTPContext {
AVDictionary *chained_options;
int send_expect_100;
char *method;
+ int reconnect;
+ int listen;
} HTTPContext;
#define OFFSET(x) offsetof(HTTPContext, x)
@@ -97,14 +105,16 @@ typedef struct HTTPContext {
#define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
static const AVOption options[] = {
+ { "seekable", "control seekability of connection", OFFSET(seekable), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, D },
{ "chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
{ "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
{ "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
{ "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
- { "user-agent", "override User-Agent header, for compatibility with ffmpeg", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
+ { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
{ "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E },
{ "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
{ "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
+ { "cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D },
{ "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, D },
{ "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT },
{ "icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT },
@@ -117,12 +127,15 @@ static const AVOption options[] = {
{ "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
{ "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
{ "method", "Override the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
+ { "reconnect", "auto reconnect after disconnect before EOF", OFFSET(reconnect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D },
+ { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E },
{ NULL }
};
static int http_connect(URLContext *h, const char *path, const char *local_path,
const char *hoststr, const char *auth,
const char *proxyauth, int *new_location);
+static int http_read_header(URLContext *h, int *new_location);
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
{
@@ -201,6 +214,8 @@ static int http_open_cnx(URLContext *h, AVDictionary **options)
HTTPContext *s = h->priv_data;
int location_changed, attempts = 0, redirects = 0;
redo:
+ av_dict_copy(options, s->chained_options, 0);
+
cur_auth_type = s->auth_state.auth_type;
cur_proxy_auth_type = s->auth_state.auth_type;
@@ -212,8 +227,7 @@ redo:
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) {
- ffurl_close(s->hd);
- s->hd = NULL;
+ ffurl_closep(&s->hd);
goto redo;
} else
goto fail;
@@ -221,8 +235,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) {
- ffurl_close(s->hd);
- s->hd = NULL;
+ ffurl_closep(&s->hd);
goto redo;
} else
goto fail;
@@ -231,8 +244,7 @@ redo:
s->http_code == 303 || s->http_code == 307) &&
location_changed == 1) {
/* url moved, get next */
- ffurl_close(s->hd);
- s->hd = NULL;
+ ffurl_closep(&s->hd);
if (redirects++ >= MAX_REDIRECTS)
return AVERROR(EIO);
/* Restart the authentication process with the new target, which
@@ -246,9 +258,10 @@ redo:
fail:
if (s->hd)
- ffurl_close(s->hd);
- s->hd = NULL;
- return AVERROR(EIO);
+ ffurl_closep(&s->hd);
+ if (location_changed < 0)
+ return location_changed;
+ return ff_http_averror(s->http_code, AVERROR(EIO));
}
int ff_http_do_new_request(URLContext *h, const char *uri)
@@ -264,19 +277,68 @@ int ff_http_do_new_request(URLContext *h, const char *uri)
if (!s->location)
return AVERROR(ENOMEM);
- av_dict_copy(&options, s->chained_options, 0);
ret = http_open_cnx(h, &options);
av_dict_free(&options);
return ret;
}
+int ff_http_averror(int status_code, int default_averror)
+{
+ switch (status_code) {
+ case 400: return AVERROR_HTTP_BAD_REQUEST;
+ case 401: return AVERROR_HTTP_UNAUTHORIZED;
+ case 403: return AVERROR_HTTP_FORBIDDEN;
+ case 404: return AVERROR_HTTP_NOT_FOUND;
+ default: break;
+ }
+ if (status_code >= 400 && status_code <= 499)
+ return AVERROR_HTTP_OTHER_4XX;
+ else if (status_code >= 500)
+ return AVERROR_HTTP_SERVER_ERROR;
+ else
+ return default_averror;
+}
+
+static int http_listen(URLContext *h, const char *uri, int flags,
+ AVDictionary **options) {
+ HTTPContext *s = h->priv_data;
+ int ret;
+ static const char header[] = "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\n\r\n";
+ char hostname[1024], proto[10];
+ char lower_url[100];
+ const char *lower_proto = "tcp";
+ int port, new_location;
+ av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
+ NULL, 0, uri);
+ if (!strcmp(proto, "https"))
+ lower_proto = "tls";
+ ff_url_join(lower_url, sizeof(lower_url), lower_proto, NULL, hostname, port,
+ NULL);
+ av_dict_set(options, "listen", "1", 0);
+ if ((ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
+ &h->interrupt_callback, options)) < 0)
+ goto fail;
+ if ((ret = ffurl_write(s->hd, header, strlen(header))) < 0)
+ goto fail;
+ if ((ret = http_read_header(h, &new_location)) < 0)
+ goto fail;
+ return 0;
+
+fail:
+ av_dict_free(&s->chained_options);
+ return ret;
+}
+
static int http_open(URLContext *h, const char *uri, int flags,
AVDictionary **options)
{
HTTPContext *s = h->priv_data;
int ret;
- h->is_streamed = 1;
+ if( s->seekable == 1 )
+ h->is_streamed = 0;
+ else
+ h->is_streamed = 1;
s->filesize = -1;
s->location = av_strdup(uri);
@@ -292,6 +354,9 @@ static int http_open(URLContext *h, const char *uri, int flags,
"No trailing CRLF found in HTTP header.\n");
}
+ if (s->listen) {
+ return http_listen(h, uri, flags, options);
+ }
ret = http_open_cnx(h, options);
if (ret < 0)
av_dict_free(&s->chained_options);
@@ -349,7 +414,7 @@ static int check_http_code(URLContext *h, int http_code, const char *end)
(http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
end += strspn(end, SPACE_CHARS);
av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
- return AVERROR(EIO);
+ return ff_http_averror(http_code, AVERROR(EIO));
}
return 0;
}
@@ -379,7 +444,8 @@ static void parse_content_range(URLContext *h, const char *p)
if ((slash = strchr(p, '/')) && strlen(slash) > 0)
s->filesize = strtoll(slash + 1, NULL, 10);
}
- h->is_streamed = 0; /* we _can_ in fact seek */
+ if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
+ h->is_streamed = 0; /* we _can_ in fact seek */
}
static int parse_content_encoding(URLContext *h, const char *p)
@@ -411,7 +477,6 @@ static int parse_content_encoding(URLContext *h, const char *p)
// the header at all if this is the case).
} else {
av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
- return AVERROR(ENOSYS);
}
return 0;
}
@@ -439,6 +504,43 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p)
return 0;
}
+static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
+{
+ char *eql, *name;
+
+ // duplicate the cookie name (dict will dupe the value)
+ if (!(eql = strchr(p, '='))) return AVERROR(EINVAL);
+ if (!(name = av_strndup(p, eql - p))) return AVERROR(ENOMEM);
+
+ // add the cookie to the dictionary
+ av_dict_set(cookies, name, eql, AV_DICT_DONT_STRDUP_KEY);
+
+ return 0;
+}
+
+static int cookie_string(AVDictionary *dict, char **cookies)
+{
+ AVDictionaryEntry *e = NULL;
+ int len = 1;
+
+ // determine how much memory is needed for the cookies string
+ while (e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))
+ len += strlen(e->key) + strlen(e->value) + 1;
+
+ // reallocate the cookies
+ e = NULL;
+ if (*cookies) av_free(*cookies);
+ *cookies = av_malloc(len);
+ if (!*cookies) return AVERROR(ENOMEM);
+ *cookies[0] = '\0';
+
+ // write out the cookies
+ while (e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX))
+ av_strlcatf(*cookies, len, "%s%s\n", e->key, e->value);
+
+ return 0;
+}
+
static int process_line(URLContext *h, char *line, int line_count,
int *new_location)
{
@@ -460,7 +562,7 @@ static int process_line(URLContext *h, char *line, int line_count,
p++;
s->http_code = strtol(p, &end, 10);
- av_log(NULL, AV_LOG_TRACE, "http_code=%d\n", s->http_code);
+ av_log(h, AV_LOG_TRACE, "http_code=%d\n", s->http_code);
if ((ret = check_http_code(h, s->http_code, end)) < 0)
return ret;
@@ -484,7 +586,8 @@ static int process_line(URLContext *h, char *line, int line_count,
} else if (!av_strcasecmp(tag, "Content-Range")) {
parse_content_range(h, p);
} else if (!av_strcasecmp(tag, "Accept-Ranges") &&
- !strncmp(p, "bytes", 5)) {
+ !strncmp(p, "bytes", 5) &&
+ s->seekable == -1) {
h->is_streamed = 0;
} else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
!av_strncasecmp(p, "chunked", 7)) {
@@ -499,9 +602,18 @@ static int process_line(URLContext *h, char *line, int line_count,
} else if (!av_strcasecmp(tag, "Connection")) {
if (!strcmp(p, "close"))
s->willclose = 1;
+ } else if (!av_strcasecmp(tag, "Server")) {
+ if (!av_strcasecmp(p, "AkamaiGHost")) {
+ s->is_akamai = 1;
+ } else if (!av_strncasecmp(p, "MediaGateway", 12)) {
+ s->is_mediagateway = 1;
+ }
} else if (!av_strcasecmp(tag, "Content-Type")) {
av_free(s->mime_type);
s->mime_type = av_strdup(p);
+ } else if (!av_strcasecmp(tag, "Set-Cookie")) {
+ if (parse_cookie(s, p, &s->cookie_dict))
+ av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
} else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
s->icy_metaint = strtoll(p, NULL, 10);
} else if (!av_strncasecmp(tag, "Icy-", 4)) {
@@ -515,6 +627,110 @@ static int process_line(URLContext *h, char *line, int line_count,
return 1;
}
+/**
+ * Create a string containing cookie values for use as a HTTP cookie header
+ * field value for a particular path and domain from the cookie values stored in
+ * the HTTP protocol context. The cookie string is stored in *cookies.
+ *
+ * @return a negative value if an error condition occurred, 0 otherwise
+ */
+static int get_cookies(HTTPContext *s, char **cookies, const char *path,
+ const char *domain)
+{
+ // cookie strings will look like Set-Cookie header field values. Multiple
+ // Set-Cookie fields will result in multiple values delimited by a newline
+ int ret = 0;
+ char *next, *cookie, *set_cookies = av_strdup(s->cookies), *cset_cookies = set_cookies;
+
+ if (!set_cookies) return AVERROR(EINVAL);
+
+ // destroy any cookies in the dictionary.
+ av_dict_free(&s->cookie_dict);
+
+ *cookies = NULL;
+ while ((cookie = av_strtok(set_cookies, "\n", &next))) {
+ int domain_offset = 0;
+ char *param, *next_param, *cdomain = NULL, *cpath = NULL, *cvalue = NULL;
+ set_cookies = NULL;
+
+ // store the cookie in a dict in case it is updated in the response
+ if (parse_cookie(s, cookie, &s->cookie_dict))
+ av_log(s, AV_LOG_WARNING, "Unable to parse '%s'\n", cookie);
+
+ while ((param = av_strtok(cookie, "; ", &next_param))) {
+ if (cookie) {
+ // first key-value pair is the actual cookie value
+ cvalue = av_strdup(param);
+ cookie = NULL;
+ } else if (!av_strncasecmp("path=", param, 5)) {
+ av_free(cpath);
+ cpath = av_strdup(&param[5]);
+ } else if (!av_strncasecmp("domain=", param, 7)) {
+ // if the cookie specifies a sub-domain, skip the leading dot thereby
+ // supporting URLs that point to sub-domains and the master domain
+ int leading_dot = (param[7] == '.');
+ av_free(cdomain);
+ cdomain = av_strdup(&param[7+leading_dot]);
+ } else {
+ // ignore unknown attributes
+ }
+ }
+ if (!cdomain)
+ cdomain = av_strdup(domain);
+
+ // ensure all of the necessary values are valid
+ if (!cdomain || !cpath || !cvalue) {
+ av_log(s, AV_LOG_WARNING,
+ "Invalid cookie found, no value, path or domain specified\n");
+ goto done_cookie;
+ }
+
+ // check if the request path matches the cookie path
+ if (av_strncasecmp(path, cpath, strlen(cpath)))
+ goto done_cookie;
+
+ // the domain should be at least the size of our cookie domain
+ domain_offset = strlen(domain) - strlen(cdomain);
+ if (domain_offset < 0)
+ goto done_cookie;
+
+ // match the cookie domain
+ if (av_strcasecmp(&domain[domain_offset], cdomain))
+ goto done_cookie;
+
+ // cookie parameters match, so copy the value
+ if (!*cookies) {
+ if (!(*cookies = av_strdup(cvalue))) {
+ ret = AVERROR(ENOMEM);
+ goto done_cookie;
+ }
+ } else {
+ char *tmp = *cookies;
+ size_t str_size = strlen(cvalue) + strlen(*cookies) + 3;
+ if (!(*cookies = av_malloc(str_size))) {
+ ret = AVERROR(ENOMEM);
+ goto done_cookie;
+ }
+ snprintf(*cookies, str_size, "%s; %s", tmp, cvalue);
+ av_free(tmp);
+ }
+
+ done_cookie:
+ av_freep(&cdomain);
+ av_freep(&cpath);
+ av_freep(&cvalue);
+ if (ret < 0) {
+ if (*cookies) av_freep(cookies);
+ av_free(cset_cookies);
+ return ret;
+ }
+ }
+
+ av_free(cset_cookies);
+
+ return 0;
+}
+
static inline int has_header(const char *str, const char *header)
{
/* header + 2 to skip over CRLF prefix. (make sure you have one!) */
@@ -535,7 +751,7 @@ static int http_read_header(URLContext *h, int *new_location)
if ((err = http_get_line(s, line, sizeof(line))) < 0)
return err;
- av_log(NULL, AV_LOG_TRACE, "header='%s'\n", line);
+ av_log(h, AV_LOG_TRACE, "header='%s'\n", line);
err = process_line(h, line, s->line_count, new_location);
if (err < 0)
@@ -545,6 +761,13 @@ static int http_read_header(URLContext *h, int *new_location)
s->line_count++;
}
+ if (s->seekable == -1 && s->is_mediagateway && s->filesize == 2000000000)
+ h->is_streamed = 1; /* we can in fact _not_ seek */
+
+ // add any new cookies into the existing cookie string
+ cookie_string(s->cookie_dict, &s->cookies);
+ av_dict_free(&s->cookie_dict);
+
return err;
}
@@ -602,7 +825,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
// Note: we send this on purpose even when s->off is 0 when we're probing,
// since it allows us to detect more reliably if a (non-conforming)
// server supports seeking by analysing the reply headers.
- if (!has_header(s->headers, "\r\nRange: ") && !post) {
+ if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) {
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Range: bytes=%"PRId64"-", s->off);
if (s->end_off)
@@ -634,6 +857,14 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Content-Type: %s\r\n", s->content_type);
+ if (!has_header(s->headers, "\r\nCookie: ") && s->cookies) {
+ char *cookies = NULL;
+ if (!get_cookies(s, &cookies, path, hoststr) && cookies) {
+ len += av_strlcatf(headers + len, sizeof(headers) - len,
+ "Cookie: %s\r\n", cookies);
+ av_free(cookies);
+ }
+ }
if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
len += av_strlcatf(headers + len, sizeof(headers) - len,
"Icy-MetaData: %d\r\n", 1);
@@ -656,14 +887,14 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
authstr ? authstr : "",
proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : "");
- av_freep(&authstr);
- av_freep(&proxyauthstr);
+ av_log(h, AV_LOG_DEBUG, "request: %s\n", s->buffer);
+
if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
- return err;
+ goto done;
if (s->post_data)
if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
- return err;
+ goto done;
/* init input buffer */
s->buf_ptr = s->buffer;
@@ -680,15 +911,23 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
* we've still to send the POST data, but the code calling this
* function will check http_code after we return. */
s->http_code = 200;
- return 0;
+ err = 0;
+ goto done;
}
/* wait for header */
err = http_read_header(h, new_location);
if (err < 0)
- return err;
+ goto done;
+
+ if (*new_location)
+ s->off = off;
- return (off == s->off) ? 0 : -1;
+ err = (off == s->off) ? 0 : -1;
+done:
+ av_freep(&authstr);
+ av_freep(&proxyauthstr);
+ return err;
}
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
@@ -707,6 +946,14 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
s->filesize >= 0 && s->off >= s->filesize)
return AVERROR_EOF;
len = ffurl_read(s->hd, buf, size);
+ if (!len && (!s->willclose || s->chunksize < 0) &&
+ s->filesize >= 0 && s->off < s->filesize) {
+ av_log(h, AV_LOG_ERROR,
+ "Stream ends prematurely at %"PRId64", should be %"PRId64"\n",
+ s->off, s->filesize
+ );
+ return AVERROR(EIO);
+ }
}
if (len > 0) {
s->off += len;
@@ -749,10 +996,12 @@ static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
}
#endif /* CONFIG_ZLIB */
+static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect);
+
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
{
HTTPContext *s = h->priv_data;
- int err, new_location;
+ int err, new_location, read_ret, seek_ret;
if (!s->hd)
return AVERROR_EOF;
@@ -767,7 +1016,6 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
if (!s->chunksize) {
char line[32];
- for (;;) {
do {
if ((err = http_get_line(s, line, sizeof(line))) < 0)
return err;
@@ -780,8 +1028,6 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
if (!s->chunksize)
return 0;
- break;
- }
}
size = FFMIN(size, s->chunksize);
}
@@ -789,9 +1035,23 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
if (s->compressed)
return http_buf_read_compressed(h, buf, size);
#endif /* CONFIG_ZLIB */
- return http_buf_read(h, buf, size);
+ read_ret = http_buf_read(h, buf, size);
+ if (read_ret < 0 && s->reconnect && !h->is_streamed && s->filesize > 0 && s->off < s->filesize) {
+ av_log(h, AV_LOG_INFO, "Will reconnect at %"PRId64".\n", s->off);
+ seek_ret = http_seek_internal(h, s->off, SEEK_SET, 1);
+ if (seek_ret != s->off) {
+ av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRId64".\n", s->off);
+ return read_ret;
+ }
+
+ read_ret = http_buf_read(h, buf, size);
+ }
+
+ return read_ret;
}
+// Like http_read_stream(), but no short reads.
+// Assumes partial reads are an error.
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
{
int pos = 0;
@@ -941,12 +1201,12 @@ static int http_close(URLContext *h)
ret = http_shutdown(h, h->flags);
if (s->hd)
- ffurl_close(s->hd);
+ ffurl_closep(&s->hd);
av_dict_free(&s->chained_options);
return ret;
}
-static int64_t http_seek(URLContext *h, int64_t off, int whence)
+static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int force_reconnect)
{
HTTPContext *s = h->priv_data;
URLContext *old_hd = s->hd;
@@ -957,24 +1217,29 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
if (whence == AVSEEK_SIZE)
return s->filesize;
- else if ((whence == SEEK_CUR && off == 0) ||
- (whence == SEEK_SET && off == s->off))
+ else if (!force_reconnect &&
+ ((whence == SEEK_CUR && off == 0) ||
+ (whence == SEEK_SET && off == s->off)))
return s->off;
else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
return AVERROR(ENOSYS);
- /* we save the old context in case the seek fails */
- old_buf_size = s->buf_end - s->buf_ptr;
- memcpy(old_buf, s->buf_ptr, old_buf_size);
- s->hd = NULL;
if (whence == SEEK_CUR)
off += s->off;
else if (whence == SEEK_END)
off += s->filesize;
+ else if (whence != SEEK_SET)
+ return AVERROR(EINVAL);
+ if (off < 0)
+ return AVERROR(EINVAL);
s->off = off;
+ /* we save the old context in case the seek fails */
+ old_buf_size = s->buf_end - s->buf_ptr;
+ memcpy(old_buf, s->buf_ptr, old_buf_size);
+ s->hd = NULL;
+
/* if it fails, continue on old connection */
- av_dict_copy(&options, s->chained_options, 0);
if ((ret = http_open_cnx(h, &options)) < 0) {
av_dict_free(&options);
memcpy(s->buffer, old_buf, old_buf_size);
@@ -989,6 +1254,11 @@ static int64_t http_seek(URLContext *h, int64_t off, int whence)
return off;
}
+static int64_t http_seek(URLContext *h, int64_t off, int whence)
+{
+ return http_seek_internal(h, off, whence, 0);
+}
+
static int http_get_file_handle(URLContext *h)
{
HTTPContext *s = h->priv_data;
@@ -1044,7 +1314,7 @@ static int http_proxy_close(URLContext *h)
{
HTTPContext *s = h->priv_data;
if (s->hd)
- ffurl_close(s->hd);
+ ffurl_closep(&s->hd);
return 0;
}
@@ -1059,7 +1329,10 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags)
char *authstr;
int new_loc;
- h->is_streamed = 1;
+ if( s->seekable == 1 )
+ h->is_streamed = 0;
+ else
+ h->is_streamed = 1;
av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
pathbuf, sizeof(pathbuf), uri);
@@ -1115,14 +1388,13 @@ redo:
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) {
- ffurl_close(s->hd);
- s->hd = NULL;
+ ffurl_closep(&s->hd);
goto redo;
}
if (s->http_code < 400)
return 0;
- ret = AVERROR(EIO);
+ ret = ff_http_averror(s->http_code, AVERROR(EIO));
fail:
http_proxy_close(h);
diff --git a/libavformat/http.h b/libavformat/http.h
index 3d301a715f..7d02713e31 100644
--- a/libavformat/http.h
+++ b/libavformat/http.h
@@ -2,20 +2,20 @@
* HTTP definitions
* Copyright (c) 2010 Josh Allmann
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,7 +24,7 @@
#include "url.h"
-#define HTTP_HEADERS_SIZE 1024
+#define HTTP_HEADERS_SIZE 4096
/**
* Initialize the authentication state based on another HTTP URLContext.
@@ -40,11 +40,13 @@ void ff_http_init_auth_state(URLContext *dest, const URLContext *src);
/**
* Send a new HTTP request, reusing the old connection.
*
- * @param h pointer to the ressource
+ * @param h pointer to the resource
* @param uri uri used to perform the request
* @return a negative value if an error condition occurred, 0
* otherwise
*/
int ff_http_do_new_request(URLContext *h, const char *uri);
+int ff_http_averror(int status_code, int default_averror);
+
#endif /* AVFORMAT_HTTP_H */
diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c
index b96da3ef12..dbe3eff48f 100644
--- a/libavformat/httpauth.c
+++ b/libavformat/httpauth.c
@@ -2,20 +2,20 @@
* HTTP authentication
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -224,8 +224,11 @@ static char *make_digest_auth(HTTPAuthState *state, const char *username,
av_strlcatf(authstr, len, ",nonce=\"%s\"", digest->nonce);
av_strlcatf(authstr, len, ",uri=\"%s\"", uri);
av_strlcatf(authstr, len, ",response=\"%s\"", response);
+
+ // we are violating the RFC and use "" because all others seem to do that too.
if (digest->algorithm[0])
- av_strlcatf(authstr, len, ",algorithm=%s", digest->algorithm);
+ av_strlcatf(authstr, len, ",algorithm=\"%s\"", digest->algorithm);
+
if (digest->opaque[0])
av_strlcatf(authstr, len, ",opaque=\"%s\"", digest->opaque);
if (digest->qop[0]) {
diff --git a/libavformat/httpauth.h b/libavformat/httpauth.h
index 99bf43ffdc..9c15a38097 100644
--- a/libavformat/httpauth.h
+++ b/libavformat/httpauth.h
@@ -2,20 +2,20 @@
* HTTP authentication
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,7 +56,7 @@ typedef struct HTTPAuthState {
/**
* The currently chosen auth type.
*/
- HTTPAuthType auth_type;
+ int auth_type;
/**
* Authentication realm
*/
diff --git a/libavformat/icecast.c b/libavformat/icecast.c
index 5e3ce66178..a7c7001f03 100644
--- a/libavformat/icecast.c
+++ b/libavformat/icecast.c
@@ -1,26 +1,27 @@
/*
- * Icecast protocol for Libav
+ * Icecast protocol for FFmpeg
* Copyright (c) 2014 Marvin Scholz
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "libavutil/bprint.h"
#include "libavutil/opt.h"
#include "avformat.h"
@@ -65,27 +66,10 @@ static const AVOption options[] = {
};
-static char *cat_header(char buf[], const char key[], const char value[])
+static void cat_header(AVBPrint *bp, const char key[], const char value[])
{
- if (NOT_EMPTY(value)) {
- int len = strlen(key) + strlen(value) + 5;
- int is_first = !buf;
- char *tmp = NULL;
-
- if (buf)
- len += strlen(buf);
- if (!(tmp = av_realloc(buf, len))) {
- av_freep(&buf);
- return NULL;
- } else {
- buf = tmp;
- }
- if (is_first)
- *buf = '\0';
-
- av_strlcatf(buf, len, "%s: %s\r\n", key, value);
- }
- return buf;
+ if (NOT_EMPTY(value))
+ av_bprintf(bp, "%s: %s\r\n", key, value);
}
static int icecast_close(URLContext *h)
@@ -107,20 +91,24 @@ static int icecast_open(URLContext *h, const char *uri, int flags)
char h_url[1024], host[1024], auth[1024], path[1024];
char *headers = NULL, *user = NULL;
int port, ret;
+ AVBPrint bp;
if (flags & AVIO_FLAG_READ)
return AVERROR(ENOSYS);
+ av_bprint_init(&bp, 0, 1);
+
// Build header strings
- headers = cat_header(headers, "Ice-Name", s->name);
- headers = cat_header(headers, "Ice-Description", s->description);
- headers = cat_header(headers, "Ice-URL", s->url);
- headers = cat_header(headers, "Ice-Genre", s->genre);
- headers = cat_header(headers, "Ice-Public", s->public ? "1" : "0");
- if (!headers) {
+ cat_header(&bp, "Ice-Name", s->name);
+ cat_header(&bp, "Ice-Description", s->description);
+ cat_header(&bp, "Ice-URL", s->url);
+ cat_header(&bp, "Ice-Genre", s->genre);
+ cat_header(&bp, "Ice-Public", s->public ? "1" : "0");
+ if (!av_bprint_is_complete(&bp)) {
ret = AVERROR(ENOMEM);
goto cleanup;
}
+ av_bprint_finalize(&bp, &headers);
// Set options
av_dict_set(&opt_dict, "method", s->legacy_icecast ? "SOURCE" : "PUT", 0);
@@ -141,7 +129,7 @@ static int icecast_open(URLContext *h, const char *uri, int flags)
// Check for auth data in URI
if (auth[0]) {
- char *sep = strchr(auth,':');
+ char *sep = strchr(auth, ':');
if (sep) {
*sep = 0;
sep++;
@@ -179,7 +167,6 @@ static int icecast_open(URLContext *h, const char *uri, int flags)
ret = ffurl_open(&s->hd, h_url, AVIO_FLAG_READ_WRITE, NULL, &opt_dict);
cleanup:
- // Free variables
av_freep(&user);
av_freep(&headers);
av_dict_free(&opt_dict);
diff --git a/libavformat/icodec.c b/libavformat/icodec.c
new file mode 100644
index 0000000000..847f0eea2f
--- /dev/null
+++ b/libavformat/icodec.c
@@ -0,0 +1,182 @@
+/*
+ * Microsoft Windows ICO demuxer
+ * Copyright (c) 2011 Peter Ross (pross@xvid.org)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Microsoft Windows ICO demuxer
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/bytestream.h"
+#include "libavcodec/bmp.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct {
+ int offset;
+ int size;
+ int nb_pal;
+} IcoImage;
+
+typedef struct {
+ int current_image;
+ int nb_images;
+ IcoImage * images;
+} IcoDemuxContext;
+
+static int probe(AVProbeData *p)
+{
+ if (AV_RL16(p->buf) == 0 && AV_RL16(p->buf + 2) == 1 && AV_RL16(p->buf + 4))
+ return AVPROBE_SCORE_MAX / 4;
+ return 0;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ IcoDemuxContext *ico = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i, codec;
+
+ avio_skip(pb, 4);
+ ico->nb_images = avio_rl16(pb);
+
+ ico->images = av_malloc_array(ico->nb_images, sizeof(IcoImage));
+ if (!ico->images)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < ico->nb_images; i++) {
+ AVStream *st;
+ int tmp;
+
+ if (avio_seek(pb, 6 + i * 16, SEEK_SET) < 0)
+ break;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->width = avio_r8(pb);
+ st->codec->height = avio_r8(pb);
+ ico->images[i].nb_pal = avio_r8(pb);
+ if (ico->images[i].nb_pal == 255)
+ ico->images[i].nb_pal = 0;
+
+ avio_skip(pb, 5);
+
+ ico->images[i].size = avio_rl32(pb);
+ ico->images[i].offset = avio_rl32(pb);
+
+ if (avio_seek(pb, ico->images[i].offset, SEEK_SET) < 0)
+ break;
+
+ codec = avio_rl32(pb);
+ switch (codec) {
+ case MKTAG(0x89, 'P', 'N', 'G'):
+ st->codec->codec_id = AV_CODEC_ID_PNG;
+ st->codec->width = 0;
+ st->codec->height = 0;
+ break;
+ case 40:
+ if (ico->images[i].size < 40)
+ return AVERROR_INVALIDDATA;
+ st->codec->codec_id = AV_CODEC_ID_BMP;
+ tmp = avio_rl32(pb);
+ if (tmp)
+ st->codec->width = tmp;
+ tmp = avio_rl32(pb);
+ if (tmp)
+ st->codec->height = tmp / 2;
+ break;
+ default:
+ avpriv_request_sample(s, "codec %d", codec);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ IcoDemuxContext *ico = s->priv_data;
+ IcoImage *image;
+ AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[0];
+ int ret;
+
+ if (ico->current_image >= ico->nb_images)
+ return AVERROR(EIO);
+
+ image = &ico->images[ico->current_image];
+
+ if ((ret = avio_seek(pb, image->offset, SEEK_SET)) < 0)
+ return ret;
+
+ if (s->streams[ico->current_image]->codec->codec_id == AV_CODEC_ID_PNG) {
+ if ((ret = av_get_packet(pb, pkt, image->size)) < 0)
+ return ret;
+ } else {
+ uint8_t *buf;
+ if ((ret = av_new_packet(pkt, 14 + image->size)) < 0)
+ return ret;
+ buf = pkt->data;
+
+ /* add BMP header */
+ bytestream_put_byte(&buf, 'B');
+ bytestream_put_byte(&buf, 'M');
+ bytestream_put_le32(&buf, pkt->size);
+ bytestream_put_le16(&buf, 0);
+ bytestream_put_le16(&buf, 0);
+ bytestream_put_le32(&buf, 0);
+
+ if ((ret = avio_read(pb, buf, image->size)) < 0)
+ return ret;
+
+ st->codec->bits_per_coded_sample = AV_RL16(buf + 14);
+
+ if (AV_RL32(buf + 32))
+ image->nb_pal = AV_RL32(buf + 32);
+
+ if (st->codec->bits_per_coded_sample <= 8 && !image->nb_pal) {
+ image->nb_pal = 1 << st->codec->bits_per_coded_sample;
+ AV_WL32(buf + 32, image->nb_pal);
+ }
+
+ AV_WL32(buf - 4, 14 + 40 + image->nb_pal * 4);
+ AV_WL32(buf + 8, AV_RL32(buf + 8) / 2);
+ }
+
+ pkt->stream_index = ico->current_image++;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ return 0;
+}
+
+AVInputFormat ff_ico_demuxer = {
+ .name = "ico",
+ .long_name = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"),
+ .priv_data_size = sizeof(IcoDemuxContext),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
diff --git a/libavformat/icoenc.c b/libavformat/icoenc.c
new file mode 100644
index 0000000000..53d4420f37
--- /dev/null
+++ b/libavformat/icoenc.c
@@ -0,0 +1,203 @@
+/*
+ * Microsoft Windows ICO muxer
+ * Copyright (c) 2012 Michael Bradshaw <mjbshaw 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
+ * Microsoft Windows ICO muxer
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/pixdesc.h"
+#include "avformat.h"
+
+typedef struct {
+ int offset;
+ int size;
+ unsigned char width;
+ unsigned char height;
+ short bits;
+} IcoImage;
+
+typedef struct {
+ int current_image;
+ int nb_images;
+ IcoImage *images;
+} IcoMuxContext;
+
+static int ico_check_attributes(AVFormatContext *s, const AVCodecContext *c)
+{
+ if (c->codec_id == AV_CODEC_ID_BMP) {
+ if (c->pix_fmt == AV_PIX_FMT_PAL8 && AV_PIX_FMT_RGB32 != AV_PIX_FMT_BGRA) {
+ av_log(s, AV_LOG_ERROR, "Wrong endianness for bmp pixel format\n");
+ return AVERROR(EINVAL);
+ } else if (c->pix_fmt != AV_PIX_FMT_PAL8 &&
+ c->pix_fmt != AV_PIX_FMT_RGB555LE &&
+ c->pix_fmt != AV_PIX_FMT_BGR24 &&
+ c->pix_fmt != AV_PIX_FMT_BGRA) {
+ av_log(s, AV_LOG_ERROR, "BMP must be 1bit, 4bit, 8bit, 16bit, 24bit, or 32bit\n");
+ return AVERROR(EINVAL);
+ }
+ } else if (c->codec_id == AV_CODEC_ID_PNG) {
+ if (c->pix_fmt != AV_PIX_FMT_RGBA) {
+ av_log(s, AV_LOG_ERROR, "PNG in ico requires pixel format to be rgba\n");
+ return AVERROR(EINVAL);
+ }
+ } else {
+ const AVCodecDescriptor *codesc = avcodec_descriptor_get(c->codec_id);
+ av_log(s, AV_LOG_ERROR, "Unsupported codec %s\n", codesc ? codesc->name : "");
+ return AVERROR(EINVAL);
+ }
+
+ if (c->width > 256 ||
+ c->height > 256) {
+ av_log(s, AV_LOG_ERROR, "Unsupported dimensions %dx%d (dimensions cannot exceed 256x256)\n", c->width, c->height);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int ico_write_header(AVFormatContext *s)
+{
+ IcoMuxContext *ico = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int ret;
+ int i;
+
+ if (!pb->seekable) {
+ av_log(s, AV_LOG_ERROR, "Output is not seekable\n");
+ return AVERROR(EINVAL);
+ }
+
+ ico->current_image = 0;
+ ico->nb_images = s->nb_streams;
+
+ avio_wl16(pb, 0); // reserved
+ avio_wl16(pb, 1); // 1 == icon
+ avio_skip(pb, 2); // skip the number of images
+
+ for (i = 0; i < s->nb_streams; i++) {
+ if (ret = ico_check_attributes(s, s->streams[i]->codec))
+ return ret;
+
+ // Fill in later when writing trailer...
+ avio_skip(pb, 16);
+ }
+
+ ico->images = av_mallocz_array(ico->nb_images, sizeof(IcoMuxContext));
+ if (!ico->images)
+ return AVERROR(ENOMEM);
+
+ avio_flush(pb);
+
+ return 0;
+}
+
+static int ico_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ IcoMuxContext *ico = s->priv_data;
+ IcoImage *image;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *c = s->streams[pkt->stream_index]->codec;
+ int i;
+
+ if (ico->current_image >= ico->nb_images) {
+ av_log(s, AV_LOG_ERROR, "ICO already contains %d images\n", ico->current_image);
+ return AVERROR(EIO);
+ }
+
+ image = &ico->images[ico->current_image++];
+
+ image->offset = avio_tell(pb);
+ image->width = (c->width == 256) ? 0 : c->width;
+ image->height = (c->height == 256) ? 0 : c->height;
+
+ if (c->codec_id == AV_CODEC_ID_PNG) {
+ image->bits = c->bits_per_coded_sample;
+ image->size = pkt->size;
+
+ avio_write(pb, pkt->data, pkt->size);
+ } else { // BMP
+ if (AV_RL32(pkt->data + 14) != 40) { // must be BITMAPINFOHEADER
+ av_log(s, AV_LOG_ERROR, "Invalid BMP\n");
+ return AVERROR(EINVAL);
+ }
+
+ image->bits = AV_RL16(pkt->data + 28); // allows things like 1bit and 4bit images to be preserved
+ image->size = pkt->size - 14 + c->height * (c->width + 7) / 8;
+
+ avio_write(pb, pkt->data + 14, 8); // Skip the BITMAPFILEHEADER header
+ avio_wl32(pb, AV_RL32(pkt->data + 22) * 2); // rewrite height as 2 * height
+ avio_write(pb, pkt->data + 26, pkt->size - 26);
+
+ for (i = 0; i < c->height * (c->width + 7) / 8; ++i)
+ avio_w8(pb, 0x00); // Write bitmask (opaque)
+ }
+
+ return 0;
+}
+
+static int ico_write_trailer(AVFormatContext *s)
+{
+ IcoMuxContext *ico = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int i;
+
+ avio_seek(pb, 4, SEEK_SET);
+
+ avio_wl16(pb, ico->current_image);
+
+ for (i = 0; i < ico->nb_images; i++) {
+ avio_w8(pb, ico->images[i].width);
+ avio_w8(pb, ico->images[i].height);
+
+ if (s->streams[i]->codec->codec_id == AV_CODEC_ID_BMP &&
+ s->streams[i]->codec->pix_fmt == AV_PIX_FMT_PAL8) {
+ avio_w8(pb, (ico->images[i].bits >= 8) ? 0 : 1 << ico->images[i].bits);
+ } else {
+ avio_w8(pb, 0);
+ }
+
+ avio_w8(pb, 0); // reserved
+ avio_wl16(pb, 1); // color planes
+ avio_wl16(pb, ico->images[i].bits);
+ avio_wl32(pb, ico->images[i].size);
+ avio_wl32(pb, ico->images[i].offset);
+ }
+
+ av_freep(&ico->images);
+
+ return 0;
+}
+
+AVOutputFormat ff_ico_muxer = {
+ .name = "ico",
+ .long_name = NULL_IF_CONFIG_SMALL("Microsoft Windows ICO"),
+ .priv_data_size = sizeof(IcoMuxContext),
+ .mime_type = "image/vnd.microsoft.icon",
+ .extensions = "ico",
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_BMP,
+ .write_header = ico_write_header,
+ .write_packet = ico_write_packet,
+ .write_trailer = ico_write_trailer,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
diff --git a/libavformat/id3v1.c b/libavformat/id3v1.c
index 87930ff361..218ed73f81 100644
--- a/libavformat/id3v1.c
+++ b/libavformat/id3v1.c
@@ -2,20 +2,20 @@
* ID3v1 header parser
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,7 @@
#include "libavcodec/avcodec.h"
#include "libavutil/dict.h"
+/* See Genre List at http://id3.org/id3v2.3.0 */
const char * const ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = {
[0] = "Blues",
[1] = "Classic Rock",
@@ -91,7 +92,7 @@ const char * const ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = {
[64] = "Native American",
[65] = "Cabaret",
[66] = "New Wave",
- [67] = "Psychadelic",
+ [67] = "Psychadelic", /* sic, the misspelling is used in the specification */
[68] = "Rave",
[69] = "Showtunes",
[70] = "Trailer",
@@ -178,7 +179,7 @@ static void get_string(AVFormatContext *s, const char *key,
const uint8_t *buf, int buf_size)
{
int i, c;
- char *q, str[512];
+ char *q, str[512], *first_free_space = NULL;
q = str;
for(i = 0; i < buf_size; i++) {
@@ -187,10 +188,19 @@ static void get_string(AVFormatContext *s, const char *key,
break;
if ((q - str) >= sizeof(str) - 1)
break;
+ if (c == ' ') {
+ if (!first_free_space)
+ first_free_space = q;
+ } else {
+ first_free_space = NULL;
+ }
*q++ = c;
}
*q = '\0';
+ if (first_free_space)
+ *first_free_space = '\0';
+
if (*str)
av_dict_set(&s->metadata, key, str, 0);
}
@@ -202,7 +212,6 @@ static void get_string(AVFormatContext *s, const char *key,
*/
static int parse_tag(AVFormatContext *s, const uint8_t *buf)
{
- char str[5];
int genre;
if (!(buf[0] == 'T' &&
@@ -215,8 +224,7 @@ static int parse_tag(AVFormatContext *s, const uint8_t *buf)
get_string(s, "date", buf + 93, 4);
get_string(s, "comment", buf + 97, 30);
if (buf[125] == 0 && buf[126] != 0) {
- snprintf(str, sizeof(str), "%d", buf[126]);
- av_dict_set(&s->metadata, "track", str, 0);
+ av_dict_set_int(&s->metadata, "track", buf[126], 0);
}
genre = buf[127];
if (genre <= ID3v1_GENRE_MAX)
diff --git a/libavformat/id3v1.h b/libavformat/id3v1.h
index 71070736f1..d5dca35873 100644
--- a/libavformat/id3v1.h
+++ b/libavformat/id3v1.h
@@ -2,20 +2,20 @@
* ID3v1 header parser
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 799eafee7c..2289bfc15a 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -1,24 +1,37 @@
/*
- * ID3v2 header parser
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/**
+ * @file
+ * ID3v2 header parser
+ *
+ * Specifications available at:
+ * http://id3.org/Developer_Information
+ */
+
+#include "config.h"
+
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
@@ -42,12 +55,14 @@ const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
{ "TPUB", "publisher" },
{ "TRCK", "track" },
{ "TSSE", "encoder" },
+ { "USLT", "lyrics" },
{ 0 }
};
const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
- { "TDRL", "date" },
+ { "TCMP", "compilation" },
{ "TDRC", "date" },
+ { "TDRL", "date" },
{ "TDEN", "creation_time" },
{ "TSOA", "album-sort" },
{ "TSOP", "artist-sort" },
@@ -58,6 +73,7 @@ const AVMetadataConv ff_id3v2_4_metadata_conv[] = {
static const AVMetadataConv id3v2_2_metadata_conv[] = {
{ "TAL", "album" },
{ "TCO", "genre" },
+ { "TCP", "compilation" },
{ "TT2", "title" },
{ "TEN", "encoded_by" },
{ "TP1", "artist" },
@@ -155,16 +171,58 @@ static unsigned int get_size(AVIOContext *s, int len)
return v;
}
+static unsigned int size_to_syncsafe(unsigned int size)
+{
+ return (((size) & (0x7f << 0)) >> 0) +
+ (((size) & (0x7f << 8)) >> 1) +
+ (((size) & (0x7f << 16)) >> 2) +
+ (((size) & (0x7f << 24)) >> 3);
+}
+
+/* No real verification, only check that the tag consists of
+ * a combination of capital alpha-numerical characters */
+static int is_tag(const char *buf, unsigned int len)
+{
+ if (!len)
+ return 0;
+
+ while (len--)
+ if ((buf[len] < 'A' ||
+ buf[len] > 'Z') &&
+ (buf[len] < '0' ||
+ buf[len] > '9'))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * Return 1 if the tag of length len at the given offset is valid, 0 if not, -1 on error
+ */
+static int check_tag(AVIOContext *s, int offset, unsigned int len)
+{
+ char tag[4];
+
+ if (len > 4 ||
+ avio_seek(s, offset, SEEK_SET) < 0 ||
+ avio_read(s, tag, len) < (int)len)
+ return -1;
+ else if (!AV_RB32(tag) || is_tag(tag, len))
+ return 1;
+
+ return 0;
+}
+
/**
* Free GEOB type extra metadata.
*/
static void free_geobtag(void *obj)
{
ID3v2ExtraMetaGEOB *geob = obj;
- av_free(geob->mime_type);
- av_free(geob->file_name);
- av_free(geob->description);
- av_free(geob->data);
+ av_freep(&geob->mime_type);
+ av_freep(&geob->file_name);
+ av_freep(&geob->description);
+ av_freep(&geob->data);
av_free(geob);
}
@@ -258,7 +316,7 @@ static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
* Parse a text tag.
*/
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
- const char *key)
+ AVDictionary **metadata, const char *key)
{
uint8_t *dst;
int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
@@ -293,7 +351,52 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
av_freep(&dst);
if (dst)
- av_dict_set(&s->metadata, key, dst, dict_flags);
+ av_dict_set(metadata, key, dst, dict_flags);
+}
+
+static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen,
+ AVDictionary **metadata)
+{
+ uint8_t lang[4];
+ uint8_t *descriptor = NULL; // 'Content descriptor'
+ uint8_t *text = NULL;
+ char *key = NULL;
+ int encoding;
+ int ok = 0;
+
+ if (taglen < 1)
+ goto error;
+
+ encoding = avio_r8(pb);
+ taglen--;
+
+ if (avio_read(pb, lang, 3) < 3)
+ goto error;
+ lang[3] = '\0';
+ taglen -= 3;
+
+ if (decode_str(s, pb, encoding, &descriptor, &taglen) < 0)
+ goto error;
+
+ if (decode_str(s, pb, encoding, &text, &taglen) < 0)
+ goto error;
+
+ // FFmpeg does not support hierarchical metadata, so concatenate the keys.
+ key = av_asprintf("lyrics-%s%s%s", descriptor[0] ? (char *)descriptor : "",
+ descriptor[0] ? "-" : "",
+ lang);
+ if (!key)
+ goto error;
+
+ av_dict_set(metadata, key, text, 0);
+
+ ok = 1;
+error:
+ if (!ok)
+ av_log(s, AV_LOG_ERROR, "Error reading lyrics, skipped\n");
+ av_free(descriptor);
+ av_free(text);
+ av_free(key);
}
/**
@@ -313,14 +416,14 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
if (!geob_data) {
- av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
+ av_log(s, AV_LOG_ERROR, "Failed to alloc %"SIZE_SPECIFIER" bytes\n",
sizeof(ID3v2ExtraMetaGEOB));
return;
}
new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
if (!new_extra) {
- av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
+ av_log(s, AV_LOG_ERROR, "Failed to alloc %"SIZE_SPECIFIER" bytes\n",
sizeof(ID3v2ExtraMeta));
goto fail;
}
@@ -496,7 +599,7 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
}
apic->buf = av_buffer_alloc(taglen + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!apic->buf || avio_read(pb, apic->buf->data, taglen) != taglen)
+ if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen)
goto fail;
memset(apic->buf->data + taglen, 0, FF_INPUT_BUFFER_PADDING_SIZE);
@@ -514,6 +617,106 @@ fail:
avio_seek(pb, end, SEEK_SET);
}
+static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const char *ttag, ID3v2ExtraMeta **extra_meta, int isv34)
+{
+ AVRational time_base = {1, 1000};
+ uint32_t start, end;
+ AVChapter *chapter;
+ uint8_t *dst = NULL;
+ int taglen;
+ char tag[5];
+
+ if (!s) {
+ /* We should probably just put the chapter data to extra_meta here
+ * and do the AVFormatContext-needing part in a separate
+ * ff_id3v2_parse_apic()-like function. */
+ av_log(NULL, AV_LOG_DEBUG, "No AVFormatContext, skipped ID3 chapter data\n");
+ return;
+ }
+
+ if (decode_str(s, pb, 0, &dst, &len) < 0)
+ return;
+ if (len < 16)
+ return;
+
+ start = avio_rb32(pb);
+ end = avio_rb32(pb);
+ avio_skip(pb, 8);
+
+ chapter = avpriv_new_chapter(s, s->nb_chapters + 1, time_base, start, end, dst);
+ if (!chapter) {
+ av_free(dst);
+ return;
+ }
+
+ len -= 16;
+ while (len > 10) {
+ if (avio_read(pb, tag, 4) < 4)
+ goto end;
+ tag[4] = 0;
+ taglen = avio_rb32(pb);
+ avio_skip(pb, 2);
+ len -= 10;
+ if (taglen < 0 || taglen > len)
+ goto end;
+ if (tag[0] == 'T')
+ read_ttag(s, pb, taglen, &chapter->metadata, tag);
+ else
+ avio_skip(pb, taglen);
+ len -= taglen;
+ }
+
+ ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_34_metadata_conv);
+ ff_metadata_conv(&chapter->metadata, NULL, ff_id3v2_4_metadata_conv);
+end:
+ av_free(dst);
+}
+
+static void free_priv(void *obj)
+{
+ ID3v2ExtraMetaPRIV *priv = obj;
+ av_freep(&priv->owner);
+ av_freep(&priv->data);
+ av_freep(&priv);
+}
+
+static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen,
+ const char *tag, ID3v2ExtraMeta **extra_meta, int isv34)
+{
+ ID3v2ExtraMeta *meta;
+ ID3v2ExtraMetaPRIV *priv;
+
+ meta = av_mallocz(sizeof(*meta));
+ priv = av_mallocz(sizeof(*priv));
+
+ if (!meta || !priv)
+ goto fail;
+
+ if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &priv->owner, &taglen) < 0)
+ goto fail;
+
+ priv->data = av_malloc(taglen);
+ if (!priv->data)
+ goto fail;
+
+ priv->datasize = taglen;
+
+ if (avio_read(pb, priv->data, priv->datasize) != priv->datasize)
+ goto fail;
+
+ meta->tag = "PRIV";
+ meta->data = priv;
+ meta->next = *extra_meta;
+ *extra_meta = meta;
+
+ return;
+
+fail:
+ if (priv)
+ free_priv(priv);
+ av_freep(&meta);
+}
+
typedef struct ID3v2EMFunc {
const char *tag3;
const char *tag4;
@@ -526,6 +729,8 @@ typedef struct ID3v2EMFunc {
static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
{ "GEO", "GEOB", read_geobtag, free_geobtag },
{ "PIC", "APIC", read_apic, free_apic },
+ { "CHAP","CHAP", read_chapter, NULL },
+ { "PRIV","PRIV", read_priv, free_priv },
{ NULL }
};
@@ -538,7 +743,7 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
{
int i = 0;
while (id3v2_extra_meta_funcs[i].tag3) {
- if (!memcmp(tag,
+ if (tag && !memcmp(tag,
(isv34 ? id3v2_extra_meta_funcs[i].tag4 :
id3v2_extra_meta_funcs[i].tag3),
(isv34 ? 4 : 3)))
@@ -548,19 +753,25 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
return NULL;
}
-static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
+static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
+ AVFormatContext *s, int len, uint8_t version,
uint8_t flags, ID3v2ExtraMeta **extra_meta)
{
- int isv34, tlen, unsync;
+ int isv34, unsync;
+ unsigned tlen;
char tag[5];
- int64_t next, end = avio_tell(s->pb) + len;
+ int64_t next, end = avio_tell(pb) + len;
int taghdrlen;
const char *reason = NULL;
- AVIOContext pb;
+ AVIOContext pb_local;
AVIOContext *pbx;
unsigned char *buffer = NULL;
int buffer_size = 0;
- const ID3v2EMFunc *extra_func;
+ const ID3v2EMFunc *extra_func = NULL;
+ unsigned char *uncompressed_buffer = NULL;
+ av_unused int uncompressed_buffer_size = 0;
+
+ av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len);
switch (version) {
case 2:
@@ -586,7 +797,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
unsync = flags & 0x80;
if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */
- int extlen = get_size(s->pb, 4);
+ int extlen = get_size(pb, 4);
if (version == 4)
/* In v2.4 the length includes the length field we just read. */
extlen -= 4;
@@ -595,35 +806,63 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
reason = "invalid extended header length";
goto error;
}
- avio_skip(s->pb, extlen);
+ avio_skip(pb, extlen);
+ len -= extlen + 4;
+ if (len < 0) {
+ reason = "extended header too long.";
+ goto error;
+ }
}
while (len >= taghdrlen) {
unsigned int tflags = 0;
int tunsync = 0;
+ int tcomp = 0;
+ int tencr = 0;
+ unsigned long av_unused dlen;
if (isv34) {
- avio_read(s->pb, tag, 4);
+ if (avio_read(pb, tag, 4) < 4)
+ break;
tag[4] = 0;
if (version == 3) {
- tlen = avio_rb32(s->pb);
- } else
- tlen = get_size(s->pb, 4);
- tflags = avio_rb16(s->pb);
+ tlen = avio_rb32(pb);
+ } else {
+ /* some encoders incorrectly uses v3 sizes instead of syncsafe ones
+ * so check the next tag to see which one to use */
+ tlen = avio_rb32(pb);
+ if (tlen > 0x7f) {
+ if (tlen < len) {
+ int64_t cur = avio_tell(pb);
+
+ if (ffio_ensure_seekback(pb, 2 /* tflags */ + tlen + 4 /* next tag */))
+ break;
+
+ if (check_tag(pb, cur + 2 + size_to_syncsafe(tlen), 4) == 1)
+ tlen = size_to_syncsafe(tlen);
+ else if (check_tag(pb, cur + 2 + tlen, 4) != 1)
+ break;
+ avio_seek(pb, cur, SEEK_SET);
+ } else
+ tlen = size_to_syncsafe(tlen);
+ }
+ }
+ tflags = avio_rb16(pb);
tunsync = tflags & ID3v2_FLAG_UNSYNCH;
} else {
- avio_read(s->pb, tag, 3);
+ if (avio_read(pb, tag, 3) < 3)
+ break;
tag[3] = 0;
- tlen = avio_rb24(s->pb);
+ tlen = avio_rb24(pb);
}
- if (tlen < 0 || tlen > len - taghdrlen) {
- av_log(s, AV_LOG_WARNING,
- "Invalid size in frame %s, skipping the rest of tag.\n",
- tag);
+ if (tlen > (1<<28))
break;
- }
len -= taghdrlen + tlen;
- next = avio_tell(s->pb) + tlen;
+
+ if (len < 0)
+ break;
+
+ next = avio_tell(pb) + tlen;
if (!tlen) {
if (tag[0])
@@ -633,57 +872,110 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
}
if (tflags & ID3v2_FLAG_DATALEN) {
- avio_rb32(s->pb);
+ if (tlen < 4)
+ break;
+ dlen = avio_rb32(pb);
tlen -= 4;
- }
+ } else
+ dlen = tlen;
+
+ tcomp = tflags & ID3v2_FLAG_COMPRESSION;
+ tencr = tflags & ID3v2_FLAG_ENCRYPTION;
+
+ /* skip encrypted tags and, if no zlib, compressed tags */
+ if (tencr || (!CONFIG_ZLIB && tcomp)) {
+ const char *type;
+ if (!tcomp)
+ type = "encrypted";
+ else if (!tencr)
+ type = "compressed";
+ else
+ type = "encrypted and compressed";
- if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
- av_log(s, AV_LOG_WARNING,
- "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
- avio_skip(s->pb, tlen);
+ av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
+ avio_skip(pb, tlen);
/* check for text tag or supported special meta tag */
} else if (tag[0] == 'T' ||
+ !memcmp(tag, "USLT", 4) ||
(extra_meta &&
(extra_func = get_extra_meta_func(tag, isv34)))) {
- if (unsync || tunsync) {
- int64_t end = avio_tell(s->pb) + tlen;
- uint8_t *b;
+ pbx = pb;
+
+ if (unsync || tunsync || tcomp) {
av_fast_malloc(&buffer, &buffer_size, tlen);
if (!buffer) {
av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
goto seek;
}
+ }
+ if (unsync || tunsync) {
+ int64_t end = avio_tell(pb) + tlen;
+ uint8_t *b;
+
b = buffer;
- while (avio_tell(s->pb) < end && !s->pb->eof_reached) {
- *b++ = avio_r8(s->pb);
- if (*(b - 1) == 0xff && avio_tell(s->pb) < end - 1 &&
- !s->pb->eof_reached ) {
- uint8_t val = avio_r8(s->pb);
- *b++ = val ? val : avio_r8(s->pb);
+ while (avio_tell(pb) < end && b - buffer < tlen && !pb->eof_reached) {
+ *b++ = avio_r8(pb);
+ if (*(b - 1) == 0xff && avio_tell(pb) < end - 1 &&
+ b - buffer < tlen &&
+ !pb->eof_reached ) {
+ uint8_t val = avio_r8(pb);
+ *b++ = val ? val : avio_r8(pb);
}
}
- ffio_init_context(&pb, buffer, b - buffer, 0, NULL, NULL, NULL,
+ ffio_init_context(&pb_local, buffer, b - buffer, 0, NULL, NULL, NULL,
NULL);
tlen = b - buffer;
- pbx = &pb; // read from sync buffer
- } else {
- pbx = s->pb; // read straight from input
+ pbx = &pb_local; // read from sync buffer
}
+
+#if CONFIG_ZLIB
+ if (tcomp) {
+ int err;
+
+ av_log(s, AV_LOG_DEBUG, "Compresssed frame %s tlen=%d dlen=%ld\n", tag, tlen, dlen);
+
+ av_fast_malloc(&uncompressed_buffer, &uncompressed_buffer_size, dlen);
+ if (!uncompressed_buffer) {
+ av_log(s, AV_LOG_ERROR, "Failed to alloc %ld bytes\n", dlen);
+ goto seek;
+ }
+
+ if (!(unsync || tunsync)) {
+ err = avio_read(pb, buffer, tlen);
+ if (err < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n");
+ goto seek;
+ }
+ tlen = err;
+ }
+
+ err = uncompress(uncompressed_buffer, &dlen, buffer, tlen);
+ if (err != Z_OK) {
+ av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
+ goto seek;
+ }
+ ffio_init_context(&pb_local, uncompressed_buffer, dlen, 0, NULL, NULL, NULL, NULL);
+ tlen = dlen;
+ pbx = &pb_local; // read from sync buffer
+ }
+#endif
if (tag[0] == 'T')
/* parse text tag */
- read_ttag(s, pbx, tlen, tag);
+ read_ttag(s, pbx, tlen, metadata, tag);
+ else if (!memcmp(tag, "USLT", 4))
+ read_uslt(s, pbx, tlen, metadata);
else
/* parse special meta tag */
extra_func->read(s, pbx, tlen, tag, extra_meta, isv34);
} else if (!tag[0]) {
if (tag[1])
- av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding");
- avio_skip(s->pb, tlen);
+ av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n");
+ avio_skip(pb, tlen);
break;
}
/* Skip to end of tag */
seek:
- avio_seek(s->pb, next, SEEK_SET);
+ avio_seek(pb, next, SEEK_SET);
}
/* Footer preset, always 10 bytes, skip over it */
@@ -694,25 +986,38 @@ error:
if (reason)
av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n",
version, reason);
- avio_seek(s->pb, end, SEEK_SET);
+ avio_seek(pb, end, SEEK_SET);
av_free(buffer);
+ av_free(uncompressed_buffer);
return;
}
-void ff_id3v2_read(AVFormatContext *s, const char *magic,
- ID3v2ExtraMeta **extra_meta)
+static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata,
+ AVFormatContext *s, const char *magic,
+ ID3v2ExtraMeta **extra_meta, int64_t max_search_size)
{
int len, ret;
uint8_t buf[ID3v2_HEADER_SIZE];
int found_header;
- int64_t off;
+ int64_t start, off;
+
+ if (max_search_size && max_search_size < ID3v2_HEADER_SIZE)
+ return;
+ start = avio_tell(pb);
do {
/* save the current offset in case there's nothing to read/skip */
- off = avio_tell(s->pb);
- ret = avio_read(s->pb, buf, ID3v2_HEADER_SIZE);
- if (ret != ID3v2_HEADER_SIZE)
+ off = avio_tell(pb);
+ if (max_search_size && off - start >= max_search_size - ID3v2_HEADER_SIZE) {
+ avio_seek(pb, off, SEEK_SET);
break;
+ }
+
+ ret = avio_read(pb, buf, ID3v2_HEADER_SIZE);
+ if (ret != ID3v2_HEADER_SIZE) {
+ avio_seek(pb, off, SEEK_SET);
+ break;
+ }
found_header = ff_id3v2_match(buf, magic);
if (found_header) {
/* parse ID3v2 header */
@@ -720,15 +1025,27 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic,
((buf[7] & 0x7f) << 14) |
((buf[8] & 0x7f) << 7) |
(buf[9] & 0x7f);
- id3v2_parse(s, len, buf[3], buf[5], extra_meta);
+ id3v2_parse(pb, metadata, s, len, buf[3], buf[5], extra_meta);
} else {
- avio_seek(s->pb, off, SEEK_SET);
+ avio_seek(pb, off, SEEK_SET);
}
} while (found_header);
- ff_metadata_conv(&s->metadata, NULL, ff_id3v2_34_metadata_conv);
- ff_metadata_conv(&s->metadata, NULL, id3v2_2_metadata_conv);
- ff_metadata_conv(&s->metadata, NULL, ff_id3v2_4_metadata_conv);
- merge_date(&s->metadata);
+ ff_metadata_conv(metadata, NULL, ff_id3v2_34_metadata_conv);
+ ff_metadata_conv(metadata, NULL, id3v2_2_metadata_conv);
+ ff_metadata_conv(metadata, NULL, ff_id3v2_4_metadata_conv);
+ merge_date(metadata);
+}
+
+void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata,
+ const char *magic, ID3v2ExtraMeta **extra_meta)
+{
+ id3v2_read_internal(pb, metadata, NULL, magic, extra_meta, 0);
+}
+
+void ff_id3v2_read(AVFormatContext *s, const char *magic,
+ ID3v2ExtraMeta **extra_meta, unsigned int max_search_size)
+{
+ id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta, max_search_size);
}
void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
@@ -743,6 +1060,8 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
av_freep(&current);
current = next;
}
+
+ *extra_meta = NULL;
}
int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h
index 7cb4296f11..9d7bf1c03c 100644
--- a/libavformat/id3v2.h
+++ b/libavformat/id3v2.h
@@ -2,20 +2,20 @@
* ID3v2 header parser
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -73,6 +73,12 @@ typedef struct ID3v2ExtraMetaAPIC {
enum AVCodecID id;
} ID3v2ExtraMetaAPIC;
+typedef struct ID3v2ExtraMetaPRIV {
+ uint8_t *owner;
+ uint8_t *data;
+ uint32_t datasize;
+} ID3v2ExtraMetaPRIV;
+
/**
* Detect ID3v2 Header.
* @param buf must be ID3v2_HEADER_SIZE byte long
@@ -89,11 +95,27 @@ int ff_id3v2_match(const uint8_t *buf, const char *magic);
int ff_id3v2_tag_len(const uint8_t *buf);
/**
- * Read an ID3v2 tag, including supported extra metadata
+ * Read an ID3v2 tag into specified dictionary and retrieve supported extra metadata.
+ *
+ * Chapters are not currently read by this variant.
+ *
+ * @param metadata Parsed metadata is stored here
+ * @param extra_meta If not NULL, extra metadata is parsed into a list of
+ * ID3v2ExtraMeta structs and *extra_meta points to the head of the list
+ */
+void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *magic, ID3v2ExtraMeta **extra_meta);
+
+/**
+ * Read an ID3v2 tag, including supported extra metadata and chapters.
+ *
+ * Data is read from and stored to AVFormatContext.
+ *
* @param extra_meta If not NULL, extra metadata is parsed into a list of
* ID3v2ExtraMeta structs and *extra_meta points to the head of the list
+ * @param[opt] max_search_search restrict ID3 magic number search (bytes from start)
*/
-void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta);
+void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta,
+ unsigned int max_search_size);
/**
* Initialize an ID3v2 tag.
@@ -114,7 +136,7 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
/**
* Finalize an opened ID3v2 tag.
*/
-void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb);
+void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb, int padding_bytes);
/**
* Write an ID3v2 tag containing all global metadata from s.
diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c
index 89181c26a0..8b804c4d4a 100644
--- a/libavformat/id3v2enc.c
+++ b/libavformat/id3v2enc.c
@@ -1,20 +1,20 @@
/*
* ID3v2 header writer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "avio.h"
+#include "avio_internal.h"
#include "id3v2.h"
static void id3v2_put_size(AVIOContext *pb, int size)
@@ -110,6 +111,44 @@ static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictio
return -1;
}
+static void id3v2_3_metadata_split_date(AVDictionary **pm)
+{
+ AVDictionaryEntry *mtag = NULL;
+ AVDictionary *dst = NULL;
+ const char *key, *value;
+ char year[5] = {0}, day_month[5] = {0};
+ int i;
+
+ while ((mtag = av_dict_get(*pm, "", mtag, AV_DICT_IGNORE_SUFFIX))) {
+ key = mtag->key;
+ if (!av_strcasecmp(key, "date")) {
+ /* split date tag using "YYYY-MM-DD" format into year and month/day segments */
+ value = mtag->value;
+ i = 0;
+ while (value[i] >= '0' && value[i] <= '9') i++;
+ if (value[i] == '\0' || value[i] == '-') {
+ av_strlcpy(year, value, sizeof(year));
+ av_dict_set(&dst, "TYER", year, 0);
+
+ if (value[i] == '-' &&
+ value[i+1] >= '0' && value[i+1] <= '1' &&
+ value[i+2] >= '0' && value[i+2] <= '9' &&
+ value[i+3] == '-' &&
+ value[i+4] >= '0' && value[i+4] <= '3' &&
+ value[i+5] >= '0' && value[i+5] <= '9' &&
+ (value[i+6] == '\0' || value[i+6] == ' ')) {
+ snprintf(day_month, sizeof(day_month), "%.2s%.2s", value + i + 4, value + i + 1);
+ av_dict_set(&dst, "TDAT", day_month, 0);
+ }
+ } else
+ av_dict_set(&dst, key, value, 0);
+ } else
+ av_dict_set(&dst, key, mtag->value, 0);
+ }
+ av_dict_free(pm);
+ *pm = dst;
+}
+
void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
const char *magic)
{
@@ -124,31 +163,31 @@ void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
avio_wb32(pb, 0);
}
-int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
+static int write_metadata(AVIOContext *pb, AVDictionary **metadata,
+ ID3v2EncContext *id3, int enc)
{
AVDictionaryEntry *t = NULL;
- int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
- ID3v2_ENCODING_UTF8;
-
- ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
- if (id3->version == 4)
- ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
+ int ret;
- while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
- int ret;
+ ff_metadata_conv(metadata, ff_id3v2_34_metadata_conv, NULL);
+ if (id3->version == 3)
+ id3v2_3_metadata_split_date(metadata);
+ else if (id3->version == 4)
+ ff_metadata_conv(metadata, ff_id3v2_4_metadata_conv, NULL);
- if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) {
+ while ((t = av_dict_get(*metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ if ((ret = id3v2_check_write_tag(id3, pb, t, ff_id3v2_tags, enc)) > 0) {
id3->len += ret;
continue;
}
- if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ?
- ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
+ if ((ret = id3v2_check_write_tag(id3, pb, t, id3->version == 3 ?
+ ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
id3->len += ret;
continue;
}
/* unknown tag, write as TXXX frame */
- if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
+ if ((ret = id3v2_put_ttag(id3, pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
return ret;
id3->len += ret;
}
@@ -156,6 +195,64 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
return 0;
}
+static int write_chapter(AVFormatContext *s, ID3v2EncContext *id3, int id, int enc)
+{
+ const AVRational time_base = {1, 1000};
+ AVChapter *ch = s->chapters[id];
+ uint8_t *dyn_buf = NULL;
+ AVIOContext *dyn_bc = NULL;
+ char name[123];
+ int len, start, end, ret;
+
+ if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0)
+ goto fail;
+
+ start = av_rescale_q(ch->start, ch->time_base, time_base);
+ end = av_rescale_q(ch->end, ch->time_base, time_base);
+
+ snprintf(name, 122, "ch%d", id);
+ id3->len += avio_put_str(dyn_bc, name);
+ avio_wb32(dyn_bc, start);
+ avio_wb32(dyn_bc, end);
+ avio_wb32(dyn_bc, 0xFFFFFFFFu);
+ avio_wb32(dyn_bc, 0xFFFFFFFFu);
+
+ if ((ret = write_metadata(dyn_bc, &ch->metadata, id3, enc)) < 0)
+ goto fail;
+
+ len = avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ id3->len += 16 + ID3v2_HEADER_SIZE;
+
+ avio_wb32(s->pb, MKBETAG('C', 'H', 'A', 'P'));
+ avio_wb32(s->pb, len);
+ avio_wb16(s->pb, 0);
+ avio_write(s->pb, dyn_buf, len);
+
+fail:
+ if (dyn_bc && !dyn_buf)
+ avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ av_freep(&dyn_buf);
+
+ return ret;
+}
+
+int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
+{
+ int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
+ ID3v2_ENCODING_UTF8;
+ int i, ret;
+
+ if ((ret = write_metadata(s->pb, &s->metadata, id3, enc)) < 0)
+ return ret;
+
+ for (i = 0; i < s->nb_chapters; i++) {
+ if ((ret = write_chapter(s, id3, i, enc)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
{
AVStream *st = s->streams[pkt->stream_index];
@@ -196,6 +293,10 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
desc = e->value;
+ /* use UTF16 only for non-ASCII strings */
+ if (enc == ID3v2_ENCODING_UTF16BOM && string_is_ascii(desc))
+ enc = ID3v2_ENCODING_ISO8859;
+
/* start writing */
if (avio_open_dyn_buf(&dyn_buf) < 0)
return AVERROR(ENOMEM);
@@ -221,9 +322,25 @@ int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
return 0;
}
-void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb)
+void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb,
+ int padding_bytes)
{
- int64_t cur_pos = avio_tell(pb);
+ int64_t cur_pos;
+
+ if (padding_bytes < 0)
+ padding_bytes = 10;
+
+ /* The ID3v2.3 specification states that 28 bits are used to represent the
+ * size of the whole tag. Therefore the current size of the tag needs to be
+ * subtracted from the upper limit of 2^28-1 to clip the value correctly. */
+ /* The minimum of 10 is an arbitrary amount of padding at the end of the tag
+ * to fix cover art display with some software such as iTunes, Traktor,
+ * Serato, Torq. */
+ padding_bytes = av_clip(padding_bytes, 10, 268435455 - id3->len);
+ ffio_fill(pb, 0, padding_bytes);
+ id3->len += padding_bytes;
+
+ cur_pos = avio_tell(pb);
avio_seek(pb, id3->size_pos, SEEK_SET);
id3v2_put_size(pb, id3->len);
avio_seek(pb, cur_pos, SEEK_SET);
@@ -238,7 +355,7 @@ int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version,
ff_id3v2_start(&id3, s->pb, id3v2_version, magic);
if ((ret = ff_id3v2_write_metadata(s, &id3)) < 0)
return ret;
- ff_id3v2_finish(&id3, s->pb);
+ ff_id3v2_finish(&id3, s->pb, s->metadata_header_padding);
return 0;
}
diff --git a/libavformat/idcin.c b/libavformat/idcin.c
index 3aa0e3ea50..61a27244b0 100644
--- a/libavformat/idcin.c
+++ b/libavformat/idcin.c
@@ -1,21 +1,21 @@
/*
* id Quake II CIN File Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -93,7 +93,9 @@ typedef struct IdcinDemuxContext {
static int idcin_probe(AVProbeData *p)
{
- unsigned int number;
+ unsigned int number, sample_rate;
+ unsigned int w, h;
+ int i;
/*
* This is what you could call a "probabilistic" file check: id CIN
@@ -108,34 +110,41 @@ static int idcin_probe(AVProbeData *p)
/* check we have enough data to do all checks, otherwise the
0-padding may cause a wrong recognition */
- if (p->buf_size < 20)
+ if (p->buf_size < 20 + HUFFMAN_TABLE_SIZE + 12)
return 0;
/* check the video width */
- number = AV_RL32(&p->buf[0]);
- if ((number == 0) || (number > 1024))
+ w = AV_RL32(&p->buf[0]);
+ if ((w == 0) || (w > 1024))
return 0;
/* check the video height */
- number = AV_RL32(&p->buf[4]);
- if ((number == 0) || (number > 1024))
+ h = AV_RL32(&p->buf[4]);
+ if ((h == 0) || (h > 1024))
return 0;
/* check the audio sample rate */
- number = AV_RL32(&p->buf[8]);
- if ((number != 0) && ((number < 8000) | (number > 48000)))
+ sample_rate = AV_RL32(&p->buf[8]);
+ if (sample_rate && (sample_rate < 8000 || sample_rate > 48000))
return 0;
/* check the audio bytes/sample */
number = AV_RL32(&p->buf[12]);
- if (number > 2)
+ if (number > 2 || sample_rate && !number)
return 0;
/* check the audio channels */
number = AV_RL32(&p->buf[16]);
- if (number > 2)
+ if (number > 2 || sample_rate && !number)
return 0;
+ i = 20 + HUFFMAN_TABLE_SIZE;
+ if (AV_RL32(&p->buf[i]) == 1)
+ i += 768;
+
+ if (i+12 > p->buf_size || AV_RL32(&p->buf[i+8]) != w*h)
+ return 1;
+
/* return half certainty since this check is a bit sketchy */
return AVPROBE_SCORE_EXTENSION;
}
@@ -196,15 +205,8 @@ static int idcin_read_header(AVFormatContext *s)
st->codec->height = height;
/* load up the Huffman tables into extradata */
- st->codec->extradata_size = HUFFMAN_TABLE_SIZE;
- st->codec->extradata = av_malloc(HUFFMAN_TABLE_SIZE);
- ret = avio_read(pb, st->codec->extradata, HUFFMAN_TABLE_SIZE);
- if (ret < 0) {
+ if ((ret = ff_get_extradata(st->codec, pb, HUFFMAN_TABLE_SIZE)) < 0)
return ret;
- } else if (ret != HUFFMAN_TABLE_SIZE) {
- av_log(s, AV_LOG_ERROR, "incomplete header\n");
- return AVERROR(EIO);
- }
if (idcin->audio_present) {
idcin->audio_present = 1;
@@ -260,7 +262,7 @@ static int idcin_read_packet(AVFormatContext *s,
unsigned char palette_buffer[768];
uint32_t palette[256];
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return s->pb->error ? s->pb->error : AVERROR_EOF;
if (idcin->next_chunk_is_video) {
@@ -288,7 +290,9 @@ static int idcin_read_packet(AVFormatContext *s,
r = palette_buffer[i * 3 ] << palette_scale;
g = palette_buffer[i * 3 + 1] << palette_scale;
b = palette_buffer[i * 3 + 2] << palette_scale;
- palette[i] = (r << 16) | (g << 8) | (b);
+ palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
+ if (palette_scale == 2)
+ palette[i] |= palette[i] >> 6 & 0x30303;
}
}
@@ -353,7 +357,7 @@ static int idcin_read_seek(AVFormatContext *s, int stream_index,
IdcinDemuxContext *idcin = s->priv_data;
if (idcin->first_pkt_pos > 0) {
- int ret = avio_seek(s->pb, idcin->first_pkt_pos, SEEK_SET);
+ int64_t ret = avio_seek(s->pb, idcin->first_pkt_pos, SEEK_SET);
if (ret < 0)
return ret;
ff_update_cur_dts(s, s->streams[idcin->video_stream_index], 0);
diff --git a/libavformat/idroqdec.c b/libavformat/idroqdec.c
index 82eff24e94..76bb3924b1 100644
--- a/libavformat/idroqdec.c
+++ b/libavformat/idroqdec.c
@@ -1,21 +1,21 @@
/*
* id RoQ (.roq) File Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
+#include "avio_internal.h"
#define RoQ_MAGIC_NUMBER 0x1084
#define RoQ_CHUNK_PREAMBLE_SIZE 8
@@ -105,7 +106,7 @@ static int roq_read_packet(AVFormatContext *s,
while (!packet_read) {
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR(EIO);
/* get the next chunk preamble */
@@ -118,6 +119,8 @@ static int roq_read_packet(AVFormatContext *s,
if(chunk_size > INT_MAX)
return AVERROR_INVALIDDATA;
+ chunk_size = ffio_limit(pb, chunk_size);
+
switch (chunk_type) {
case RoQ_INFO:
diff --git a/libavformat/idroqenc.c b/libavformat/idroqenc.c
index 2ce4d7d493..28a3aba9d4 100644
--- a/libavformat/idroqenc.c
+++ b/libavformat/idroqenc.c
@@ -2,20 +2,20 @@
* id RoQ (.roq) File muxer
* Copyright (c) 2007 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,9 +25,35 @@
static int roq_write_header(struct AVFormatContext *s)
{
- static const uint8_t header[] = {
- 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x00
+ uint8_t header[] = {
+ 0x84, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, /* fps: */ 0x1E, 0x00
};
+ int n;
+ AVCodecContext *avctx;
+
+// set the actual fps
+ for(n=0;n<s->nb_streams;n++) {
+ if ((avctx=s->streams[n]->codec)->codec_type == AVMEDIA_TYPE_VIDEO) {
+ unsigned int fps;
+
+ if (avctx->time_base.num != 1) {
+ av_log(avctx, AV_LOG_ERROR, "Frame rate must be integer\n");
+ return AVERROR(EINVAL);
+ }
+
+ if ((fps=avctx->time_base.den) > 255) {
+ av_log(avctx, AV_LOG_ERROR, "Frame rate may not exceed 255fps\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (fps != 30) {
+ av_log(avctx, AV_LOG_WARNING, "For vintage compatibility fps must be 30\n");
+ }
+
+ header[6] = fps;
+ break;
+ }
+ }
avio_write(s->pb, header, 8);
avio_flush(s->pb);
diff --git a/libavformat/iff.c b/libavformat/iff.c
index bf092152bd..7235bc1c9c 100644
--- a/libavformat/iff.c
+++ b/libavformat/iff.c
@@ -1,23 +1,22 @@
/*
- * IFF (.iff) file demuxer
* Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
* Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,13 +30,20 @@
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
+#include "libavcodec/bytestream.h"
#include "avformat.h"
+#include "id3v2.h"
#include "internal.h"
#define ID_8SVX MKTAG('8','S','V','X')
+#define ID_16SV MKTAG('1','6','S','V')
+#define ID_MAUD MKTAG('M','A','U','D')
+#define ID_MHDR MKTAG('M','H','D','R')
+#define ID_MDAT MKTAG('M','D','A','T')
#define ID_VHDR MKTAG('V','H','D','R')
#define ID_ATAK MKTAG('A','T','A','K')
#define ID_RLSE MKTAG('R','L','S','E')
@@ -45,9 +51,18 @@
#define ID_PBM MKTAG('P','B','M',' ')
#define ID_ILBM MKTAG('I','L','B','M')
#define ID_BMHD MKTAG('B','M','H','D')
+#define ID_DGBL MKTAG('D','G','B','L')
+#define ID_CAMG MKTAG('C','A','M','G')
#define ID_CMAP MKTAG('C','M','A','P')
+#define ID_ACBM MKTAG('A','C','B','M')
+#define ID_DEEP MKTAG('D','E','E','P')
+#define ID_RGB8 MKTAG('R','G','B','8')
+#define ID_RGBN MKTAG('R','G','B','N')
+#define ID_DSD MKTAG('D','S','D',' ')
+#define ID_ANIM MKTAG('A','N','I','M')
#define ID_FORM MKTAG('F','O','R','M')
+#define ID_FRM8 MKTAG('F','R','M','8')
#define ID_ANNO MKTAG('A','N','N','O')
#define ID_AUTH MKTAG('A','U','T','H')
#define ID_CHRS MKTAG('C','H','R','S')
@@ -56,31 +71,50 @@
#define ID_FVER MKTAG('F','V','E','R')
#define ID_NAME MKTAG('N','A','M','E')
#define ID_TEXT MKTAG('T','E','X','T')
+#define ID_ABIT MKTAG('A','B','I','T')
#define ID_BODY MKTAG('B','O','D','Y')
-#define ID_ANNO MKTAG('A','N','N','O')
+#define ID_DBOD MKTAG('D','B','O','D')
+#define ID_DPEL MKTAG('D','P','E','L')
+#define ID_DLOC MKTAG('D','L','O','C')
+#define ID_TVDC MKTAG('T','V','D','C')
#define LEFT 2
#define RIGHT 4
#define STEREO 6
+/**
+ * This number of bytes if added at the beginning of each AVPacket
+ * which contain additional information about video properties
+ * which has to be shared between demuxer and decoder.
+ * This number may change between frames, e.g. the demuxer might
+ * set it to smallest possible size of 2 to indicate that there's
+ * no extradata changing in this frame.
+ */
+#define IFF_EXTRA_VIDEO_SIZE 41
+
typedef enum {
COMP_NONE,
COMP_FIB,
COMP_EXP
} svx8_compression_type;
-typedef enum {
- BITMAP_RAW,
- BITMAP_BYTERUN1
-} bitmap_compression_type;
-
typedef struct IffDemuxContext {
- uint64_t body_pos;
+ int is_64bit; ///< chunk size is 64-bit
+ int64_t body_pos;
+ int64_t body_end;
uint32_t body_size;
- uint32_t sent_bytes;
+ svx8_compression_type svx8_compression;
+ unsigned maud_bits;
+ unsigned maud_compression;
+ unsigned bitmap_compression; ///< delta compression method used
+ unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM)
+ unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise)
+ unsigned flags; ///< 1 for EHB, 0 is no extra half darkening
+ unsigned transparency; ///< transparency color index in palette
+ unsigned masking; ///< masking method used
+ uint8_t tvdc[32]; ///< TVDC lookup table
} IffDemuxContext;
-
/* Metadata string read */
static int get_metadata(AVFormatContext *s,
const char *const tag,
@@ -91,7 +125,7 @@ static int get_metadata(AVFormatContext *s,
if (!buf)
return AVERROR(ENOMEM);
- if (avio_read(s->pb, buf, data_size) < 0) {
+ if (avio_read(s->pb, buf, data_size) != data_size) {
av_free(buf);
return AVERROR(EIO);
}
@@ -104,19 +138,223 @@ static int iff_probe(AVProbeData *p)
{
const uint8_t *d = p->buf;
- if ( AV_RL32(d) == ID_FORM &&
- (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ILBM) )
+ if ( (AV_RL32(d) == ID_FORM &&
+ (AV_RL32(d+8) == ID_8SVX ||
+ AV_RL32(d+8) == ID_16SV ||
+ AV_RL32(d+8) == ID_MAUD ||
+ AV_RL32(d+8) == ID_PBM ||
+ AV_RL32(d+8) == ID_ACBM ||
+ AV_RL32(d+8) == ID_DEEP ||
+ AV_RL32(d+8) == ID_ILBM ||
+ AV_RL32(d+8) == ID_RGB8 ||
+ AV_RL32(d+8) == ID_RGB8 ||
+ AV_RL32(d+8) == ID_ANIM ||
+ AV_RL32(d+8) == ID_RGBN)) ||
+ (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD))
return AVPROBE_SCORE_MAX;
return 0;
}
+static const AVCodecTag dsd_codec_tags[] = {
+ { AV_CODEC_ID_DSD_MSBF, ID_DSD },
+ { AV_CODEC_ID_NONE, 0 },
+};
+
+
+#define DSD_SLFT MKTAG('S','L','F','T')
+#define DSD_SRGT MKTAG('S','R','G','T')
+#define DSD_MLFT MKTAG('M','L','F','T')
+#define DSD_MRGT MKTAG('M','R','G','T')
+#define DSD_C MKTAG('C',' ',' ',' ')
+#define DSD_LS MKTAG('L','S',' ',' ')
+#define DSD_RS MKTAG('R','S',' ',' ')
+#define DSD_LFE MKTAG('L','F','E',' ')
+
+static const uint32_t dsd_stereo[] = { DSD_SLFT, DSD_SRGT };
+static const uint32_t dsd_5point0[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LS, DSD_RS };
+static const uint32_t dsd_5point1[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LFE, DSD_LS, DSD_RS };
+
+typedef struct {
+ uint64_t layout;
+ const uint32_t * dsd_layout;
+} DSDLayoutDesc;
+
+static const DSDLayoutDesc dsd_channel_layout[] = {
+ { AV_CH_LAYOUT_STEREO, dsd_stereo },
+ { AV_CH_LAYOUT_5POINT0, dsd_5point0 },
+ { AV_CH_LAYOUT_5POINT1, dsd_5point1 },
+};
+
+static const uint64_t dsd_loudspeaker_config[] = {
+ AV_CH_LAYOUT_STEREO,
+ 0, 0,
+ AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_5POINT1,
+};
+
+static const char * dsd_source_comment[] = {
+ "dsd_source_comment",
+ "analogue_source_comment",
+ "pcm_source_comment",
+};
+
+static const char * dsd_history_comment[] = {
+ "general_remark",
+ "operator_name",
+ "creating_machine",
+ "timezone",
+ "file_revision"
+};
+
+static int parse_dsd_diin(AVFormatContext *s, AVStream *st, uint64_t eof)
+{
+ AVIOContext *pb = s->pb;
+
+ while (avio_tell(pb) + 12 <= eof) {
+ uint32_t tag = avio_rl32(pb);
+ uint64_t size = avio_rb64(pb);
+ uint64_t orig_pos = avio_tell(pb);
+ const char * metadata_tag = NULL;
+
+ switch(tag) {
+ case MKTAG('D','I','A','R'): metadata_tag = "artist"; break;
+ case MKTAG('D','I','T','I'): metadata_tag = "title"; break;
+ }
+
+ if (metadata_tag && size > 4) {
+ unsigned int tag_size = avio_rb32(pb);
+ int ret = get_metadata(s, metadata_tag, FFMIN(tag_size, size - 4));
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag);
+ return ret;
+ }
+ }
+
+ avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1));
+ }
+
+ return 0;
+}
+
+static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof)
+{
+ AVIOContext *pb = s->pb;
+ char abss[24];
+ int hour, min, sec, i, ret, config;
+ int dsd_layout[6];
+ ID3v2ExtraMeta *id3v2_extra_meta;
+
+ while (avio_tell(pb) + 12 <= eof) {
+ uint32_t tag = avio_rl32(pb);
+ uint64_t size = avio_rb64(pb);
+ uint64_t orig_pos = avio_tell(pb);
+
+ switch(tag) {
+ case MKTAG('A','B','S','S'):
+ if (size < 8)
+ return AVERROR_INVALIDDATA;
+ hour = avio_rb16(pb);
+ min = avio_r8(pb);
+ sec = avio_r8(pb);
+ snprintf(abss, sizeof(abss), "%02dh:%02dm:%02ds:%d", hour, min, sec, avio_rb32(pb));
+ av_dict_set(&st->metadata, "absolute_start_time", abss, 0);
+ break;
+
+ case MKTAG('C','H','N','L'):
+ if (size < 2)
+ return AVERROR_INVALIDDATA;
+ st->codec->channels = avio_rb16(pb);
+ if (size < 2 + st->codec->channels * 4)
+ return AVERROR_INVALIDDATA;
+ st->codec->channel_layout = 0;
+ if (st->codec->channels > FF_ARRAY_ELEMS(dsd_layout)) {
+ avpriv_request_sample(s, "channel layout");
+ break;
+ }
+ for (i = 0; i < st->codec->channels; i++)
+ dsd_layout[i] = avio_rl32(pb);
+ for (i = 0; i < FF_ARRAY_ELEMS(dsd_channel_layout); i++) {
+ const DSDLayoutDesc * d = &dsd_channel_layout[i];
+ if (av_get_channel_layout_nb_channels(d->layout) == st->codec->channels &&
+ !memcmp(d->dsd_layout, dsd_layout, st->codec->channels * sizeof(uint32_t))) {
+ st->codec->channel_layout = d->layout;
+ break;
+ }
+ }
+ break;
+
+ case MKTAG('C','M','P','R'):
+ if (size < 4)
+ return AVERROR_INVALIDDATA;
+ tag = avio_rl32(pb);
+ st->codec->codec_id = ff_codec_get_id(dsd_codec_tags, tag);
+ if (!st->codec->codec_id) {
+ av_log(s, AV_LOG_ERROR, "'%c%c%c%c' compression is not supported\n",
+ tag&0xFF, (tag>>8)&0xFF, (tag>>16)&0xFF, (tag>>24)&0xFF);
+ return AVERROR_PATCHWELCOME;
+ }
+ break;
+
+ case MKTAG('F','S',' ',' '):
+ if (size < 4)
+ return AVERROR_INVALIDDATA;
+ st->codec->sample_rate = avio_rb32(pb) / 8;
+ break;
+
+ case MKTAG('I','D','3',' '):
+ id3v2_extra_meta = NULL;
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size);
+ if (id3v2_extra_meta) {
+ if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) {
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+ return ret;
+ }
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+ }
+
+ if (size < avio_tell(pb) - orig_pos) {
+ av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+
+ case MKTAG('L','S','C','O'):
+ if (size < 2)
+ return AVERROR_INVALIDDATA;
+ config = avio_rb16(pb);
+ if (config != 0xFFFF) {
+ if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config))
+ st->codec->channel_layout = dsd_loudspeaker_config[config];
+ if (!st->codec->channel_layout)
+ avpriv_request_sample(s, "loudspeaker configuration %d", config);
+ }
+ break;
+ }
+
+ avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1));
+ }
+
+ return 0;
+}
+
+static const uint8_t deep_rgb24[] = {0, 0, 0, 3, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8};
+static const uint8_t deep_rgba[] = {0, 0, 0, 4, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8};
+static const uint8_t deep_bgra[] = {0, 0, 0, 4, 0, 3, 0, 8, 0, 2, 0, 8, 0, 1, 0, 8};
+static const uint8_t deep_argb[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 1, 0, 8, 0, 2, 0, 8};
+static const uint8_t deep_abgr[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 3, 0, 8, 0, 2, 0, 8};
+
static int iff_read_header(AVFormatContext *s)
{
IffDemuxContext *iff = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
- uint32_t chunk_id, data_size;
- int compression = -1;
+ uint8_t *buf;
+ uint32_t chunk_id;
+ uint64_t data_size;
+ uint32_t screenmode = 0, num, den;
+ unsigned transparency = 0;
+ unsigned masking = 0; // no mask
+ uint8_t fmt[16];
+ int fmt_size;
st = avformat_new_stream(s, NULL);
if (!st)
@@ -124,16 +362,26 @@ static int iff_read_header(AVFormatContext *s)
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
- avio_skip(pb, 8);
+ iff->is_64bit = avio_rl32(pb) == ID_FRM8;
+ avio_skip(pb, iff->is_64bit ? 8 : 4);
// codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
st->codec->codec_tag = avio_rl32(pb);
+ if (st->codec->codec_tag == ID_ANIM) {
+ avio_skip(pb, 8);
+ st->codec->codec_tag = avio_rl32(pb);
+ }
+ iff->bitmap_compression = -1;
+ iff->svx8_compression = -1;
+ iff->maud_bits = -1;
+ iff->maud_compression = -1;
- while(!pb->eof_reached) {
+ while(!avio_feof(pb)) {
uint64_t orig_pos;
int res;
const char *metadata_tag = NULL;
+ int version, nb_comments, i;
chunk_id = avio_rl32(pb);
- data_size = avio_rb32(pb);
+ data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb);
orig_pos = avio_tell(pb);
switch(chunk_id) {
@@ -146,12 +394,39 @@ static int iff_read_header(AVFormatContext *s)
st->codec->sample_rate = avio_rb16(pb);
if (data_size >= 16) {
avio_skip(pb, 1);
- compression = avio_r8(pb);
+ iff->svx8_compression = avio_r8(pb);
}
break;
+ case ID_MHDR:
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ if (data_size < 32)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 4);
+ iff->maud_bits = avio_rb16(pb);
+ avio_skip(pb, 2);
+ num = avio_rb32(pb);
+ den = avio_rb16(pb);
+ if (!den)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 2);
+ st->codec->sample_rate = num / den;
+ st->codec->channels = avio_rb16(pb);
+ iff->maud_compression = avio_rb16(pb);
+ if (st->codec->channels == 1)
+ st->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ else if (st->codec->channels == 2)
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ break;
+
+ case ID_ABIT:
case ID_BODY:
+ case ID_DBOD:
+ case ID_DSD:
+ case ID_MDAT:
iff->body_pos = avio_tell(pb);
+ iff->body_end = iff->body_pos + data_size;
iff->body_size = data_size;
break;
@@ -167,17 +442,23 @@ static int iff_read_header(AVFormatContext *s)
}
break;
+ case ID_CAMG:
+ if (data_size < 4)
+ return AVERROR_INVALIDDATA;
+ screenmode = avio_rb32(pb);
+ break;
+
case ID_CMAP:
if (data_size < 3 || data_size > 768 || data_size % 3) {
- av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu32"\n",
+ av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu64"\n",
data_size);
return AVERROR_INVALIDDATA;
}
- st->codec->extradata_size = data_size;
- st->codec->extradata = av_malloc(data_size);
+ st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE;
+ st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
if (!st->codec->extradata)
return AVERROR(ENOMEM);
- if (avio_read(pb, st->codec->extradata, data_size) < 0)
+ if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0)
return AVERROR(EIO);
break;
@@ -189,38 +470,156 @@ static int iff_read_header(AVFormatContext *s)
st->codec->height = avio_rb16(pb);
avio_skip(pb, 4); // x, y offset
st->codec->bits_per_coded_sample = avio_r8(pb);
- if (data_size >= 11) {
- avio_skip(pb, 1); // masking
- compression = avio_r8(pb);
+ if (data_size >= 10)
+ masking = avio_r8(pb);
+ if (data_size >= 11)
+ iff->bitmap_compression = avio_r8(pb);
+ if (data_size >= 14) {
+ avio_skip(pb, 1); // padding
+ transparency = avio_rb16(pb);
}
if (data_size >= 16) {
- avio_skip(pb, 3); // paddding, transparent
st->sample_aspect_ratio.num = avio_r8(pb);
st->sample_aspect_ratio.den = avio_r8(pb);
}
break;
+ case ID_DPEL:
+ if (data_size < 4 || (data_size & 3))
+ return AVERROR_INVALIDDATA;
+ if ((fmt_size = avio_read(pb, fmt, sizeof(fmt))) < 0)
+ return fmt_size;
+ if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24)))
+ st->codec->pix_fmt = AV_PIX_FMT_RGB24;
+ else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba)))
+ st->codec->pix_fmt = AV_PIX_FMT_RGBA;
+ else if (fmt_size == sizeof(deep_bgra) && !memcmp(fmt, deep_bgra, sizeof(deep_bgra)))
+ st->codec->pix_fmt = AV_PIX_FMT_BGRA;
+ else if (fmt_size == sizeof(deep_argb) && !memcmp(fmt, deep_argb, sizeof(deep_argb)))
+ st->codec->pix_fmt = AV_PIX_FMT_ARGB;
+ else if (fmt_size == sizeof(deep_abgr) && !memcmp(fmt, deep_abgr, sizeof(deep_abgr)))
+ st->codec->pix_fmt = AV_PIX_FMT_ABGR;
+ else {
+ avpriv_request_sample(s, "color format %.16s", fmt);
+ return AVERROR_PATCHWELCOME;
+ }
+ break;
+
+ case ID_DGBL:
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ if (data_size < 8)
+ return AVERROR_INVALIDDATA;
+ st->codec->width = avio_rb16(pb);
+ st->codec->height = avio_rb16(pb);
+ iff->bitmap_compression = avio_rb16(pb);
+ st->sample_aspect_ratio.num = avio_r8(pb);
+ st->sample_aspect_ratio.den = avio_r8(pb);
+ st->codec->bits_per_coded_sample = 24;
+ break;
+
+ case ID_DLOC:
+ if (data_size < 4)
+ return AVERROR_INVALIDDATA;
+ st->codec->width = avio_rb16(pb);
+ st->codec->height = avio_rb16(pb);
+ break;
+
+ case ID_TVDC:
+ if (data_size < sizeof(iff->tvdc))
+ return AVERROR_INVALIDDATA;
+ res = avio_read(pb, iff->tvdc, sizeof(iff->tvdc));
+ if (res < 0)
+ return res;
+ break;
+
case ID_ANNO:
- case ID_TEXT:
- metadata_tag = "comment";
+ case ID_TEXT: metadata_tag = "comment"; break;
+ case ID_AUTH: metadata_tag = "artist"; break;
+ case ID_COPYRIGHT: metadata_tag = "copyright"; break;
+ case ID_NAME: metadata_tag = "title"; break;
+
+ /* DSD tags */
+
+ case MKTAG('F','V','E','R'):
+ if (data_size < 4)
+ return AVERROR_INVALIDDATA;
+ version = avio_rb32(pb);
+ av_log(s, AV_LOG_DEBUG, "DSIFF v%d.%d.%d.%d\n",version >> 24, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
break;
- case ID_AUTH:
- metadata_tag = "artist";
+ case MKTAG('D','I','I','N'):
+ res = parse_dsd_diin(s, st, orig_pos + data_size);
+ if (res < 0)
+ return res;
break;
- case ID_COPYRIGHT:
- metadata_tag = "copyright";
+ case MKTAG('P','R','O','P'):
+ if (data_size < 4)
+ return AVERROR_INVALIDDATA;
+ if (avio_rl32(pb) != MKTAG('S','N','D',' ')) {
+ avpriv_request_sample(s, "unknown property type");
+ break;
+ }
+ res = parse_dsd_prop(s, st, orig_pos + data_size);
+ if (res < 0)
+ return res;
break;
- case ID_NAME:
- metadata_tag = "title";
+ case MKTAG('C','O','M','T'):
+ if (data_size < 2)
+ return AVERROR_INVALIDDATA;
+ nb_comments = avio_rb16(pb);
+ for (i = 0; i < nb_comments; i++) {
+ int year, mon, day, hour, min, type, ref;
+ char tmp[24];
+ const char *tag;
+ int metadata_size;
+
+ year = avio_rb16(pb);
+ mon = avio_r8(pb);
+ day = avio_r8(pb);
+ hour = avio_r8(pb);
+ min = avio_r8(pb);
+ snprintf(tmp, sizeof(tmp), "%04d-%02d-%02d %02d:%02d", year, mon, day, hour, min);
+ av_dict_set(&st->metadata, "comment_time", tmp, 0);
+
+ type = avio_rb16(pb);
+ ref = avio_rb16(pb);
+ switch (type) {
+ case 1:
+ if (!i)
+ tag = "channel_comment";
+ else {
+ snprintf(tmp, sizeof(tmp), "channel%d_comment", ref);
+ tag = tmp;
+ }
+ break;
+ case 2:
+ tag = ref < FF_ARRAY_ELEMS(dsd_source_comment) ? dsd_source_comment[ref] : "source_comment";
+ break;
+ case 3:
+ tag = ref < FF_ARRAY_ELEMS(dsd_history_comment) ? dsd_history_comment[ref] : "file_history";
+ break;
+ default:
+ tag = "comment";
+ }
+
+ metadata_size = avio_rb32(pb);
+ if ((res = get_metadata(s, tag, metadata_size)) < 0) {
+ av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", tag);
+ return res;
+ }
+
+ if (metadata_size & 1)
+ avio_skip(pb, 1);
+ }
break;
}
if (metadata_tag) {
if ((res = get_metadata(s, metadata_tag, data_size)) < 0) {
- av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!", metadata_tag);
+ av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag);
return res;
}
}
@@ -233,38 +632,71 @@ static int iff_read_header(AVFormatContext *s)
case AVMEDIA_TYPE_AUDIO:
avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate);
- switch(compression) {
- case COMP_NONE:
- st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR;
- break;
- case COMP_FIB:
- st->codec->codec_id = AV_CODEC_ID_8SVX_FIB;
- break;
- case COMP_EXP:
- st->codec->codec_id = AV_CODEC_ID_8SVX_EXP;
- break;
- default:
- av_log(s, AV_LOG_ERROR, "unknown compression method\n");
- return -1;
+ if (st->codec->codec_tag == ID_16SV)
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16BE_PLANAR;
+ else if (st->codec->codec_tag == ID_MAUD) {
+ if (iff->maud_bits == 8 && !iff->maud_compression) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_U8;
+ } else if (iff->maud_bits == 16 && !iff->maud_compression) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16BE;
+ } else if (iff->maud_bits == 8 && iff->maud_compression == 2) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_ALAW;
+ } else if (iff->maud_bits == 8 && iff->maud_compression == 3) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_MULAW;
+ } else {
+ avpriv_request_sample(s, "compression %d and bit depth %d", iff->maud_compression, iff->maud_bits);
+ return AVERROR_PATCHWELCOME;
+ }
+ } else if (st->codec->codec_tag != ID_DSD) {
+ switch (iff->svx8_compression) {
+ case COMP_NONE:
+ st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR;
+ break;
+ case COMP_FIB:
+ st->codec->codec_id = AV_CODEC_ID_8SVX_FIB;
+ break;
+ case COMP_EXP:
+ st->codec->codec_id = AV_CODEC_ID_8SVX_EXP;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR,
+ "Unknown SVX8 compression method '%d'\n", iff->svx8_compression);
+ return -1;
+ }
}
- st->codec->bits_per_coded_sample = 8;
+ st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample;
st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
break;
case AVMEDIA_TYPE_VIDEO:
- switch (compression) {
- case BITMAP_RAW:
- st->codec->codec_id = AV_CODEC_ID_IFF_ILBM;
- break;
- case BITMAP_BYTERUN1:
- st->codec->codec_id = AV_CODEC_ID_IFF_BYTERUN1;
- break;
- default:
- av_log(s, AV_LOG_ERROR, "unknown compression method\n");
- return AVERROR_INVALIDDATA;
+ iff->bpp = st->codec->bits_per_coded_sample;
+ if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) {
+ iff->ham = iff->bpp > 6 ? 6 : 4;
+ st->codec->bits_per_coded_sample = 24;
+ }
+ iff->flags = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8;
+ iff->masking = masking;
+ iff->transparency = transparency;
+
+ if (!st->codec->extradata) {
+ st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE;
+ st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
}
+ av_assert0(st->codec->extradata_size >= IFF_EXTRA_VIDEO_SIZE);
+ buf = st->codec->extradata;
+ bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE);
+ bytestream_put_byte(&buf, iff->bitmap_compression);
+ bytestream_put_byte(&buf, iff->bpp);
+ bytestream_put_byte(&buf, iff->ham);
+ bytestream_put_byte(&buf, iff->flags);
+ bytestream_put_be16(&buf, iff->transparency);
+ bytestream_put_byte(&buf, iff->masking);
+ bytestream_put_buffer(&buf, iff->tvdc, sizeof(iff->tvdc));
+ st->codec->codec_id = AV_CODEC_ID_IFF_ILBM;
break;
default:
return -1;
@@ -278,19 +710,41 @@ static int iff_read_packet(AVFormatContext *s,
{
IffDemuxContext *iff = s->priv_data;
AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[0];
int ret;
+ int64_t pos = avio_tell(pb);
- if(iff->sent_bytes >= iff->body_size)
+ if (pos >= iff->body_end)
return AVERROR_EOF;
- ret = av_get_packet(pb, pkt, iff->body_size);
- if (ret < 0)
- return ret;
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (st->codec->codec_tag == ID_DSD || st->codec->codec_tag == ID_MAUD) {
+ ret = av_get_packet(pb, pkt, FFMIN(iff->body_end - pos, 1024 * st->codec->block_align));
+ } else {
+ ret = av_get_packet(pb, pkt, iff->body_size);
+ }
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ uint8_t *buf;
- if(iff->sent_bytes == 0)
- pkt->flags |= AV_PKT_FLAG_KEY;
- iff->sent_bytes = iff->body_size;
+ if (av_new_packet(pkt, iff->body_size + 2) < 0) {
+ return AVERROR(ENOMEM);
+ }
+
+ buf = pkt->data;
+ bytestream_put_be16(&buf, 2);
+ ret = avio_read(pb, buf, iff->body_size);
+ if (ret<0) {
+ av_free_packet(pkt);
+ } else if (ret < iff->body_size)
+ av_shrink_packet(pkt, ret + 2);
+ } else {
+ av_assert0(0);
+ }
+ if (pos == iff->body_pos)
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ if (ret < 0)
+ return ret;
pkt->stream_index = 0;
return ret;
}
@@ -302,4 +756,5 @@ AVInputFormat ff_iff_demuxer = {
.read_probe = iff_probe,
.read_header = iff_read_header,
.read_packet = iff_read_packet,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK,
};
diff --git a/libavformat/ilbc.c b/libavformat/ilbc.c
index e44af487b2..3f154ce29c 100644
--- a/libavformat/ilbc.c
+++ b/libavformat/ilbc.c
@@ -2,20 +2,20 @@
* iLBC storage file format
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/img2.c b/libavformat/img2.c
index 0a840f8709..cf8a47856f 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@ static const IdStrMap img_tags[] = {
{ 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" },
@@ -49,14 +50,13 @@ static const IdStrMap img_tags[] = {
{ AV_CODEC_ID_MPEG4, "mpg4-img" },
{ AV_CODEC_ID_FFV1, "ffv1-img" },
{ AV_CODEC_ID_RAWVIDEO, "y" },
+ { AV_CODEC_ID_RAWVIDEO, "raw" },
{ AV_CODEC_ID_BMP, "bmp" },
- { AV_CODEC_ID_GIF, "gif" },
{ AV_CODEC_ID_TARGA, "tga" },
{ AV_CODEC_ID_TIFF, "tiff" },
{ AV_CODEC_ID_TIFF, "tif" },
{ AV_CODEC_ID_SGI, "sgi" },
{ AV_CODEC_ID_PTX, "ptx" },
- { AV_CODEC_ID_BRENDER_PIX,"pix" },
{ AV_CODEC_ID_PCX, "pcx" },
{ AV_CODEC_ID_QDRAW, "pic" },
{ AV_CODEC_ID_QDRAW, "pct" },
@@ -67,6 +67,7 @@ static const IdStrMap img_tags[] = {
{ 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_JPEG2000, "j2c" },
{ AV_CODEC_ID_JPEG2000, "jp2" },
@@ -75,8 +76,10 @@ static const IdStrMap img_tags[] = {
{ 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_XFACE, "xface" },
{ AV_CODEC_ID_XWD, "xwd" },
{ AV_CODEC_ID_NONE, NULL }
};
diff --git a/libavformat/img2.h b/libavformat/img2.h
new file mode 100644
index 0000000000..f6b9dd9220
--- /dev/null
+++ b/libavformat/img2.h
@@ -0,0 +1,70 @@
+/*
+ * Image format
+ * Copyright (c) 2014 Michael Niedermayer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_IMG2_H
+#define AVFORMAT_IMG2_H
+
+#include <stdint.h>
+#include "avformat.h"
+#include "libavutil/opt.h"
+
+#if HAVE_GLOB
+#include <glob.h>
+#endif
+
+enum PatternType {
+ PT_GLOB_SEQUENCE,
+ PT_GLOB,
+ PT_SEQUENCE,
+ PT_NONE
+};
+
+typedef struct VideoDemuxData {
+ const AVClass *class; /**< Class for private options. */
+ int img_first;
+ int img_last;
+ int img_number;
+ int64_t pts;
+ int img_count;
+ int is_pipe;
+ int split_planes; /**< use independent file for each Y, U, V plane */
+ char path[1024];
+ char *pixel_format; /**< Set by a private option. */
+ int width, height; /**< Set by a private option. */
+ AVRational framerate; /**< Set by a private option. */
+ int loop;
+ int pattern_type; /**< PatternType */
+ int use_glob;
+#if HAVE_GLOB
+ glob_t globstate;
+#endif
+ int start_number;
+ int start_number_range;
+ int frame_size;
+ int ts_from_file;
+} VideoDemuxData;
+
+extern const AVOption ff_img_options[];
+
+int ff_img_read_header(AVFormatContext *s1);
+
+int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt);
+#endif
diff --git a/libavformat/img2_alias_pix.c b/libavformat/img2_alias_pix.c
new file mode 100644
index 0000000000..c2650ad1b3
--- /dev/null
+++ b/libavformat/img2_alias_pix.c
@@ -0,0 +1,73 @@
+/*
+ * Alias PIX image demuxer
+ * Copyright (c) 2014 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 "img2.h"
+#include "libavcodec/bytestream.h"
+
+static int alias_pix_read_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+ const uint8_t *end = b + p->buf_size;
+ int width = bytestream_get_be16(&b);
+ int height = bytestream_get_be16(&b);
+ av_unused int ox = bytestream_get_be16(&b);
+ av_unused int oy = bytestream_get_be16(&b);
+ int bpp = bytestream_get_be16(&b);
+ int x, y;
+
+ if (!width || !height)
+ return 0;
+
+ if (bpp != 24 && bpp != 8)
+ return 0;
+
+ for (y=0; y<2 && y<height; y++) {
+ for (x=0; x<width; ) {
+ int count = *b++;
+ if (count == 0 || x + count > width)
+ return 0;
+ if (b > end)
+ return AVPROBE_SCORE_MAX / 8;
+ b += bpp / 8;
+ x += count;
+ }
+ }
+
+ return AVPROBE_SCORE_EXTENSION + 1;
+}
+
+static const AVClass image2_alias_pix_class = {
+ .class_name = "alias_pix demuxer",
+ .item_name = av_default_item_name,
+ .option = ff_img_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_image2_alias_pix_demuxer = {
+ .name = "alias_pix",
+ .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"),
+ .priv_data_size = sizeof(VideoDemuxData),
+ .read_probe = alias_pix_read_probe,
+ .read_header = ff_img_read_header,
+ .read_packet = ff_img_read_packet,
+ .raw_codec_id = AV_CODEC_ID_ALIAS_PIX,
+ .priv_class = &image2_alias_pix_class,
+};
diff --git a/libavformat/img2_brender_pix.c b/libavformat/img2_brender_pix.c
new file mode 100644
index 0000000000..ae6b3dd718
--- /dev/null
+++ b/libavformat/img2_brender_pix.c
@@ -0,0 +1,57 @@
+/*
+ * BRender PIX image demuxer
+ * Copyright (c) 2014 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 "img2.h"
+#include "libavutil/intreadwrite.h"
+
+static int brender_read_probe(AVProbeData *p)
+{
+ static const uint8_t brender_magic[16] = {
+ 0,0,0,0x12,0,0,0,8,0,0,0,2,0,0,0,2
+ };
+
+ if (memcmp(p->buf, brender_magic, sizeof(brender_magic)))
+ return 0;
+
+ if (AV_RB32(p->buf+16) != 0x03 &&
+ AV_RB32(p->buf+16) != 0x3D)
+ return 0;
+
+ return AVPROBE_SCORE_MAX-10;
+}
+
+static const AVClass image2_brender_pix_class = {
+ .class_name = "brender_pix demuxer",
+ .item_name = av_default_item_name,
+ .option = ff_img_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_image2_brender_pix_demuxer = {
+ .name = "brender_pix",
+ .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"),
+ .priv_data_size = sizeof(VideoDemuxData),
+ .read_probe = brender_read_probe,
+ .read_header = ff_img_read_header,
+ .read_packet = ff_img_read_packet,
+ .raw_codec_id = AV_CODEC_ID_BRENDER_PIX,
+ .priv_class = &image2_brender_pix_class,
+};
diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c
index fc6da1b7fe..0830f0073c 100644
--- a/libavformat/img2dec.c
+++ b/libavformat/img2dec.c
@@ -3,45 +3,47 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#define _BSD_SOURCE
+#include <sys/stat.h>
#include "libavutil/avstring.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/parseutils.h"
+#include "libavutil/intreadwrite.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
+#include "img2.h"
-typedef struct VideoDemuxData {
- const AVClass *class; /**< Class for private options. */
- int img_first;
- int img_last;
- int img_number;
- int img_count;
- int is_pipe;
- char path[1024];
- char *pixel_format; /**< Set by a private option. */
- char *video_size; /**< Set by a private option. */
- char *framerate; /**< Set by a private option. */
- int loop;
- int start_number;
-} VideoDemuxData;
+#if HAVE_GLOB
+/* Locally define as 0 (bitwise-OR no-op) any missing glob options that
+ are non-posix glibc/bsd extensions. */
+#ifndef GLOB_NOMAGIC
+#define GLOB_NOMAGIC 0
+#endif
+#ifndef GLOB_BRACE
+#define GLOB_BRACE 0
+#endif
+
+#endif /* HAVE_GLOB */
static const int sizes[][2] = {
{ 640, 480 },
@@ -70,15 +72,44 @@ static int infer_size(int *width_ptr, int *height_ptr, int size)
return -1;
}
-/* return -1 if no image found */
+static int is_glob(const char *path)
+{
+#if HAVE_GLOB
+ size_t span = 0;
+ const char *p = path;
+
+ while (p = strchr(p, '%')) {
+ if (*(++p) == '%') {
+ ++p;
+ continue;
+ }
+ if (span = strspn(p, "*?[]{}"))
+ break;
+ }
+ /* Did we hit a glob char or get to the end? */
+ return span != 0;
+#else
+ return 0;
+#endif
+}
+
+/**
+ * Get index range of image files matched by path.
+ *
+ * @param pfirst_index pointer to index updated with the first number in the range
+ * @param plast_index pointer to index updated with the last number in the range
+ * @param path path which has to be matched by the image files in the range
+ * @param start_index minimum accepted value for the first index in the range
+ * @return -1 if no image file could be found
+ */
static int find_image_range(int *pfirst_index, int *plast_index,
- const char *path, int max_start)
+ const char *path, int start_index, int start_index_range)
{
char buf[1024];
int range, last_index, range1, first_index;
/* find the first image */
- for (first_index = 0; first_index < max_start; first_index++) {
+ for (first_index = start_index; first_index < start_index + start_index_range; first_index++) {
if (av_get_frame_filename(buf, sizeof(buf), path, first_index) < 0) {
*pfirst_index =
*plast_index = 1;
@@ -89,7 +120,7 @@ static int find_image_range(int *pfirst_index, int *plast_index,
if (avio_check(buf, AVIO_FLAG_READ) > 0)
break;
}
- if (first_index == 5)
+ if (first_index == start_index + start_index_range)
goto fail;
/* find the last image */
@@ -129,20 +160,26 @@ static int img_read_probe(AVProbeData *p)
if (p->filename && ff_guess_image2_codec(p->filename)) {
if (av_filename_number_test(p->filename))
return AVPROBE_SCORE_MAX;
+ else if (is_glob(p->filename))
+ return AVPROBE_SCORE_MAX;
+ else if (p->filename[strcspn(p->filename, "*?{")]) // probably PT_GLOB
+ return AVPROBE_SCORE_EXTENSION + 2; // score chosen to be a tad above the image pipes
+ else if (p->buf_size == 0)
+ return 0;
+ else if (av_match_ext(p->filename, "raw") || av_match_ext(p->filename, "gif"))
+ return 5;
else
return AVPROBE_SCORE_EXTENSION;
}
return 0;
}
-static int img_read_header(AVFormatContext *s1)
+int ff_img_read_header(AVFormatContext *s1)
{
VideoDemuxData *s = s1->priv_data;
- int first_index, last_index, ret = 0;
- int width = 0, height = 0;
+ int first_index = 1, last_index = 1;
AVStream *st;
enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE;
- AVRational framerate;
s1->ctx_flags |= AVFMTCTX_NOHEADER;
@@ -157,17 +194,6 @@ static int img_read_header(AVFormatContext *s1)
s->pixel_format);
return AVERROR(EINVAL);
}
- if (s->video_size &&
- (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log(s, AV_LOG_ERROR,
- "Could not parse video size: %s.\n", s->video_size);
- return ret;
- }
- if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
- av_log(s, AV_LOG_ERROR,
- "Could not parse framerate: %s.\n", s->framerate);
- return ret;
- }
av_strlcpy(s->path, s1->filename, sizeof(s->path));
s->img_number = 0;
@@ -181,23 +207,94 @@ static int img_read_header(AVFormatContext *s1)
st->need_parsing = AVSTREAM_PARSE_FULL;
}
- avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
+ if (s->ts_from_file == 2) {
+#if !HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+ av_log(s1, AV_LOG_ERROR, "POSIX.1-2008 not supported, nanosecond file timestamps unavailable\n");
+ return AVERROR(ENOSYS);
+#endif
+ avpriv_set_pts_info(st, 64, 1, 1000000000);
+ } else if (s->ts_from_file)
+ avpriv_set_pts_info(st, 64, 1, 1);
+ else
+ avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num);
- if (width && height) {
- st->codec->width = width;
- st->codec->height = height;
+ if (s->width && s->height) {
+ st->codec->width = s->width;
+ st->codec->height = s->height;
}
if (!s->is_pipe) {
- if (find_image_range(&first_index, &last_index, s->path,
- FFMAX(s->start_number, 5)) < 0)
- return AVERROR(ENOENT);
+ if (s->pattern_type == PT_GLOB_SEQUENCE) {
+ s->use_glob = is_glob(s->path);
+ if (s->use_glob) {
+#if HAVE_GLOB
+ char *p = s->path, *q, *dup;
+ int gerr;
+#endif
+
+ av_log(s1, AV_LOG_WARNING, "Pattern type 'glob_sequence' is deprecated: "
+ "use pattern_type 'glob' instead\n");
+#if HAVE_GLOB
+ dup = q = av_strdup(p);
+ while (*q) {
+ /* Do we have room for the next char and a \ insertion? */
+ if ((p - s->path) >= (sizeof(s->path) - 2))
+ break;
+ if (*q == '%' && strspn(q + 1, "%*?[]{}"))
+ ++q;
+ else if (strspn(q, "\\*?[]{}"))
+ *p++ = '\\';
+ *p++ = *q++;
+ }
+ *p = 0;
+ av_free(dup);
+
+ gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC, NULL, &s->globstate);
+ if (gerr != 0) {
+ return AVERROR(ENOENT);
+ }
+ first_index = 0;
+ last_index = s->globstate.gl_pathc - 1;
+#endif
+ }
+ }
+ if ((s->pattern_type == PT_GLOB_SEQUENCE && !s->use_glob) || s->pattern_type == PT_SEQUENCE) {
+ if (find_image_range(&first_index, &last_index, s->path,
+ s->start_number, s->start_number_range) < 0) {
+ av_log(s1, AV_LOG_ERROR,
+ "Could find no file with path '%s' and index in the range %d-%d\n",
+ s->path, s->start_number, s->start_number + s->start_number_range - 1);
+ return AVERROR(ENOENT);
+ }
+ } else if (s->pattern_type == PT_GLOB) {
+#if HAVE_GLOB
+ int gerr;
+ gerr = glob(s->path, GLOB_NOCHECK|GLOB_BRACE|GLOB_NOMAGIC, NULL, &s->globstate);
+ if (gerr != 0) {
+ return AVERROR(ENOENT);
+ }
+ first_index = 0;
+ last_index = s->globstate.gl_pathc - 1;
+ s->use_glob = 1;
+#else
+ av_log(s1, AV_LOG_ERROR,
+ "Pattern type 'glob' was selected but globbing "
+ "is not supported by this libavformat build\n");
+ return AVERROR(ENOSYS);
+#endif
+ } else if (s->pattern_type != PT_GLOB_SEQUENCE && s->pattern_type != PT_NONE) {
+ av_log(s1, AV_LOG_ERROR,
+ "Unknown value '%d' for pattern_type option\n", s->pattern_type);
+ return AVERROR(EINVAL);
+ }
s->img_first = first_index;
s->img_last = last_index;
- s->img_number = s->start_number != 1 ? s->start_number : first_index;
+ s->img_number = first_index;
/* compute duration */
- st->start_time = 0;
- st->duration = last_index - first_index + 1;
+ if (!s->ts_from_file) {
+ st->start_time = 0;
+ st->duration = last_index - first_index + 1;
+ }
}
if (s1->video_codec_id) {
@@ -206,9 +303,55 @@ static int img_read_header(AVFormatContext *s1)
} else if (s1->audio_codec_id) {
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = s1->audio_codec_id;
+ } else if (s1->iformat->raw_codec_id) {
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = s1->iformat->raw_codec_id;
} else {
+ const char *str = strrchr(s->path, '.');
+ s->split_planes = str && !av_strcasecmp(str + 1, "y");
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_id = ff_guess_image2_codec(s->path);
+ if (s1->pb) {
+ int probe_buffer_size = 2048;
+ uint8_t *probe_buffer = av_realloc(NULL, probe_buffer_size + AVPROBE_PADDING_SIZE);
+ AVInputFormat *fmt = NULL;
+ AVProbeData pd = { 0 };
+
+ if (!probe_buffer)
+ return AVERROR(ENOMEM);
+
+ probe_buffer_size = avio_read(s1->pb, probe_buffer, probe_buffer_size);
+ if (probe_buffer_size < 0) {
+ av_free(probe_buffer);
+ return probe_buffer_size;
+ }
+ memset(probe_buffer + probe_buffer_size, 0, AVPROBE_PADDING_SIZE);
+
+ pd.buf = probe_buffer;
+ pd.buf_size = probe_buffer_size;
+ pd.filename = s1->filename;
+
+ while ((fmt = av_iformat_next(fmt))) {
+ if (fmt->read_header != ff_img_read_header ||
+ !fmt->read_probe ||
+ (fmt->flags & AVFMT_NOFILE) ||
+ !fmt->raw_codec_id)
+ continue;
+ if (fmt->read_probe(&pd) > 0) {
+ st->codec->codec_id = fmt->raw_codec_id;
+ break;
+ }
+ }
+ if (s1->flags & AVFMT_FLAG_CUSTOM_IO) {
+ avio_seek(s1->pb, 0, SEEK_SET);
+ } else
+ ffio_rewind_with_probe_data(s1->pb, &probe_buffer, probe_buffer_size);
+ }
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ st->codec->codec_id = ff_guess_image2_codec(s->path);
+ if (st->codec->codec_id == AV_CODEC_ID_LJPEG)
+ st->codec->codec_id = AV_CODEC_ID_MJPEG;
+ if (st->codec->codec_id == AV_CODEC_ID_ALIAS_PIX) // we cannot distingiush this from BRENDER_PIX
+ st->codec->codec_id = AV_CODEC_ID_NONE;
}
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
pix_fmt != AV_PIX_FMT_NONE)
@@ -217,10 +360,11 @@ static int img_read_header(AVFormatContext *s1)
return 0;
}
-static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
+int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
VideoDemuxData *s = s1->priv_data;
- char filename[1024];
+ char filename_bytes[1024];
+ char *filename = filename_bytes;
int i, res;
int size[3] = { 0 }, ret[3] = { 0 };
AVIOContext *f[3] = { NULL };
@@ -233,10 +377,18 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
}
if (s->img_number > s->img_last)
return AVERROR_EOF;
- if (av_get_frame_filename(filename, sizeof(filename),
+ if (s->pattern_type == PT_NONE) {
+ av_strlcpy(filename_bytes, s->path, sizeof(filename_bytes));
+ } else if (s->use_glob) {
+#if HAVE_GLOB
+ filename = s->globstate.gl_pathv[s->img_number];
+#endif
+ } else {
+ if (av_get_frame_filename(filename_bytes, sizeof(filename_bytes),
s->path,
s->img_number) < 0 && s->img_number > 1)
return AVERROR(EIO);
+ }
for (i = 0; i < 3; i++) {
if (avio_open2(&f[i], filename, AVIO_FLAG_READ,
&s1->interrupt_callback, NULL) < 0) {
@@ -248,18 +400,47 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
}
size[i] = avio_size(f[i]);
- if (codec->codec_id != AV_CODEC_ID_RAWVIDEO)
+ if (!s->split_planes)
break;
filename[strlen(filename) - 1] = 'U' + i;
}
+ if (codec->codec_id == AV_CODEC_ID_NONE) {
+ AVProbeData pd = { 0 };
+ AVInputFormat *ifmt;
+ uint8_t header[PROBE_BUF_MIN + AVPROBE_PADDING_SIZE];
+ int ret;
+ int score = 0;
+
+ ret = avio_read(f[0], header, PROBE_BUF_MIN);
+ if (ret < 0)
+ return ret;
+ memset(header + ret, 0, sizeof(header) - ret);
+ avio_skip(f[0], -ret);
+ pd.buf = header;
+ pd.buf_size = ret;
+ pd.filename = filename;
+
+ ifmt = av_probe_input_format3(&pd, 1, &score);
+ if (ifmt && ifmt->read_packet == ff_img_read_packet && ifmt->raw_codec_id)
+ codec->codec_id = ifmt->raw_codec_id;
+ }
+
if (codec->codec_id == AV_CODEC_ID_RAWVIDEO && !codec->width)
infer_size(&codec->width, &codec->height, size[0]);
} else {
f[0] = s1->pb;
- if (f[0]->eof_reached)
- return AVERROR(EIO);
- size[0] = 4096;
+ if (avio_feof(f[0]) && s->loop && s->is_pipe)
+ avio_seek(f[0], 0, SEEK_SET);
+ if (avio_feof(f[0]))
+ return AVERROR_EOF;
+ if (s->frame_size > 0) {
+ size[0] = s->frame_size;
+ } else if (!s1->streams[0]->parser) {
+ size[0] = avio_size(s1->pb);
+ } else {
+ size[0] = 4096;
+ }
}
res = av_new_packet(pkt, size[0] + size[1] + size[2]);
@@ -267,13 +448,35 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
return res;
pkt->stream_index = 0;
pkt->flags |= AV_PKT_FLAG_KEY;
+ if (s->ts_from_file) {
+ struct stat img_stat;
+ if (stat(filename, &img_stat))
+ return AVERROR(EIO);
+ pkt->pts = (int64_t)img_stat.st_mtime;
+#if HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+ if (s->ts_from_file == 2)
+ pkt->pts = 1000000000*pkt->pts + img_stat.st_mtim.tv_nsec;
+#endif
+ av_add_index_entry(s1->streams[0], s->img_number, pkt->pts, 0, 0, AVINDEX_KEYFRAME);
+ } else if (!s->is_pipe) {
+ pkt->pts = s->pts;
+ }
+
+ if (s->is_pipe)
+ pkt->pos = avio_tell(f[0]);
pkt->size = 0;
for (i = 0; i < 3; i++) {
if (f[i]) {
ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]);
+ if (s->loop && s->is_pipe && ret[i] == AVERROR_EOF) {
+ if (avio_seek(f[i], 0, SEEK_SET) >= 0) {
+ pkt->pos = 0;
+ ret[i] = avio_read(f[i], pkt->data + pkt->size, size[i]);
+ }
+ }
if (!s->is_pipe)
- avio_close(f[i]);
+ avio_closep(&f[i]);
if (ret[i] > 0)
pkt->size += ret[i];
}
@@ -281,22 +484,73 @@ static int img_read_packet(AVFormatContext *s1, AVPacket *pkt)
if (ret[0] <= 0 || ret[1] < 0 || ret[2] < 0) {
av_free_packet(pkt);
- return AVERROR(EIO); /* signal EOF */
+ if (ret[0] < 0) {
+ return ret[0];
+ } else if (ret[1] < 0) {
+ return ret[1];
+ } else if (ret[2] < 0)
+ return ret[2];
+ return AVERROR_EOF;
} else {
s->img_count++;
s->img_number++;
+ s->pts++;
+ return 0;
+ }
+}
+
+static int img_read_close(struct AVFormatContext* s1)
+{
+#if HAVE_GLOB
+ VideoDemuxData *s = s1->priv_data;
+ if (s->use_glob) {
+ globfree(&s->globstate);
+ }
+#endif
+ return 0;
+}
+
+static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+ VideoDemuxData *s1 = s->priv_data;
+ AVStream *st = s->streams[0];
+
+ if (s1->ts_from_file) {
+ int index = av_index_search_timestamp(st, timestamp, flags);
+ if(index < 0)
+ return -1;
+ s1->img_number = st->index_entries[index].pos;
return 0;
}
+
+ if (timestamp < 0 || !s1->loop && timestamp > s1->img_last - s1->img_first)
+ return -1;
+ s1->img_number = timestamp%(s1->img_last - s1->img_first + 1) + s1->img_first;
+ s1->pts = timestamp;
+ return 0;
}
#define OFFSET(x) offsetof(VideoDemuxData, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
-static const AVOption options[] = {
- { "pixel_format", "", OFFSET(pixel_format), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, DEC },
- { "video_size", "", OFFSET(video_size), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, DEC },
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, { .str = "25" }, 0, 0, DEC },
- { "loop", "", OFFSET(loop), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC },
- { "start_number", "first number in the sequence", OFFSET(start_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, DEC },
+const AVOption ff_img_options[] = {
+ { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
+ { "loop", "force loop over input file sequence", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, DEC },
+
+ { "pattern_type", "set pattern type", OFFSET(pattern_type), AV_OPT_TYPE_INT, {.i64=PT_GLOB_SEQUENCE}, 0, INT_MAX, DEC, "pattern_type"},
+ { "glob_sequence","select glob/sequence pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_GLOB_SEQUENCE}, INT_MIN, INT_MAX, DEC, "pattern_type" },
+ { "glob", "select glob pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_GLOB }, INT_MIN, INT_MAX, DEC, "pattern_type" },
+ { "sequence", "select sequence pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_SEQUENCE }, INT_MIN, INT_MAX, DEC, "pattern_type" },
+ { "none", "disable pattern matching", 0, AV_OPT_TYPE_CONST, {.i64=PT_NONE }, INT_MIN, INT_MAX, DEC, "pattern_type" },
+
+ { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
+ { "start_number", "set first number in the sequence", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, DEC },
+ { "start_number_range", "set range for looking at the first sequence number", OFFSET(start_number_range), AV_OPT_TYPE_INT, {.i64 = 5}, 1, INT_MAX, DEC },
+ { "video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "frame_size", "force frame size in bytes", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC },
+ { "ts_from_file", "set frame timestamp from file's one", OFFSET(ts_from_file), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "ts_type" },
+ { "none", "none", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 2, DEC, "ts_type" },
+ { "sec", "second precision", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 2, DEC, "ts_type" },
+ { "ns", "nano second precision", 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 2, DEC, "ts_type" },
{ NULL },
};
@@ -304,7 +558,7 @@ static const AVOption options[] = {
static const AVClass img2_class = {
.class_name = "image2 demuxer",
.item_name = av_default_item_name,
- .option = options,
+ .option = ff_img_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVInputFormat ff_image2_demuxer = {
@@ -312,8 +566,10 @@ AVInputFormat ff_image2_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("image2 sequence"),
.priv_data_size = sizeof(VideoDemuxData),
.read_probe = img_read_probe,
- .read_header = img_read_header,
- .read_packet = img_read_packet,
+ .read_header = ff_img_read_header,
+ .read_packet = ff_img_read_packet,
+ .read_close = img_read_close,
+ .read_seek = img_read_seek,
.flags = AVFMT_NOFILE,
.priv_class = &img2_class,
};
@@ -322,15 +578,236 @@ AVInputFormat ff_image2_demuxer = {
static const AVClass img2pipe_class = {
.class_name = "image2pipe demuxer",
.item_name = av_default_item_name,
- .option = options,
+ .option = ff_img_options,
.version = LIBAVUTIL_VERSION_INT,
};
AVInputFormat ff_image2pipe_demuxer = {
.name = "image2pipe",
.long_name = NULL_IF_CONFIG_SMALL("piped image2 sequence"),
.priv_data_size = sizeof(VideoDemuxData),
- .read_header = img_read_header,
- .read_packet = img_read_packet,
+ .read_header = ff_img_read_header,
+ .read_packet = ff_img_read_packet,
.priv_class = &img2pipe_class,
};
#endif
+
+static int bmp_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+ int ihsize;
+
+ if (AV_RB16(b) != 0x424d)
+ return 0;
+
+ ihsize = AV_RL32(b+14);
+ if (ihsize < 12 || ihsize > 255)
+ return 0;
+
+ if (!AV_RN32(b + 6)) {
+ return AVPROBE_SCORE_EXTENSION + 1;
+ }
+ return AVPROBE_SCORE_EXTENSION / 4;
+}
+
+static int dpx_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+ int w, h;
+ int is_big = (AV_RN32(b) == AV_RN32("SDPX"));
+
+ if (p->buf_size < 0x304+8)
+ return 0;
+ w = is_big ? AV_RB32(p->buf + 0x304) : AV_RL32(p->buf + 0x304);
+ h = is_big ? AV_RB32(p->buf + 0x308) : AV_RL32(p->buf + 0x308);
+ if (w <= 0 || h <= 0)
+ return 0;
+
+ if (is_big || AV_RN32(b) == AV_RN32("XPDS"))
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int exr_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RL32(b) == 20000630)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int j2k_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB64(b) == 0x0000000c6a502020 ||
+ AV_RB32(b) == 0xff4fff51)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int jpeg_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+ int i, state = 0xD8, exif_size = 0;
+
+ if (AV_RB16(b) != 0xFFD8 ||
+ AV_RB32(b) == 0xFFD8FFF7)
+ return 0;
+
+ b += 2;
+ if (AV_RB16(b) == 0xFFE1 && AV_RB32(b + 4) == AV_RB32("Exif")) {
+ exif_size = AV_RB16(b + 2) + 2;
+ b += exif_size;
+ }
+ for (i = 0; i + exif_size < p->buf_size - 2; i++) {
+ int c;
+ if (b[i] != 0xFF)
+ continue;
+ c = b[i + 1];
+ switch (c) {
+ case 0xD8:
+ return 0;
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ if (state != 0xD8)
+ return 0;
+ state = 0xC0;
+ break;
+ case 0xDA:
+ if (state != 0xC0)
+ return 0;
+ state = 0xDA;
+ break;
+ case 0xD9:
+ if (state != 0xDA)
+ return 0;
+ state = 0xD9;
+ break;
+ default:
+ if ( (c >= 0x02 && c <= 0xBF)
+ || c == 0xC8)
+ return 0;
+ }
+ }
+
+ if (state == 0xD9)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return AVPROBE_SCORE_EXTENSION / 8;
+}
+
+static int jpegls_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB32(b) == 0xffd8fff7)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int qdraw_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (!b[10] && AV_RB32(b+11) == 0x1102ff0c && !b[15] ||
+ p->buf_size >= 528 && !b[522] && AV_RB32(b+523) == 0x1102ff0c && !b[527])
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int pictor_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RL16(b) == 0x1234)
+ return AVPROBE_SCORE_EXTENSION / 4;
+ return 0;
+}
+
+static int png_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB64(b) == 0x89504e470d0a1a0a)
+ return AVPROBE_SCORE_MAX - 1;
+ return 0;
+}
+
+static int sgi_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB16(b) == 474 &&
+ (b[2] & ~1) == 0 &&
+ (b[3] & ~3) == 0 && b[3] &&
+ (AV_RB16(b + 4) & ~7) == 0 && AV_RB16(b + 4))
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int sunrast_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB32(b) == 0x59a66a95)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int tiff_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB32(b) == 0x49492a00 ||
+ AV_RB32(b) == 0x4D4D002a)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+}
+
+static int webp_probe(AVProbeData *p)
+{
+ const uint8_t *b = p->buf;
+
+ if (AV_RB32(b) == 0x52494646 &&
+ AV_RB32(b + 8) == 0x57454250)
+ return AVPROBE_SCORE_MAX - 1;
+ return 0;
+}
+
+#define IMAGEAUTO_DEMUXER(imgname, codecid)\
+static const AVClass imgname ## _class = {\
+ .class_name = AV_STRINGIFY(imgname) " demuxer",\
+ .item_name = av_default_item_name,\
+ .option = ff_img_options,\
+ .version = LIBAVUTIL_VERSION_INT,\
+};\
+AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {\
+ .name = AV_STRINGIFY(imgname) "_pipe",\
+ .long_name = NULL_IF_CONFIG_SMALL("piped " AV_STRINGIFY(imgname) " sequence"),\
+ .priv_data_size = sizeof(VideoDemuxData),\
+ .read_probe = imgname ## _probe,\
+ .read_header = ff_img_read_header,\
+ .read_packet = ff_img_read_packet,\
+ .priv_class = & imgname ## _class,\
+ .flags = AVFMT_GENERIC_INDEX, \
+ .raw_codec_id = codecid,\
+};
+
+IMAGEAUTO_DEMUXER(bmp, AV_CODEC_ID_BMP)
+IMAGEAUTO_DEMUXER(dpx, AV_CODEC_ID_DPX)
+IMAGEAUTO_DEMUXER(exr, AV_CODEC_ID_EXR)
+IMAGEAUTO_DEMUXER(j2k, AV_CODEC_ID_JPEG2000)
+IMAGEAUTO_DEMUXER(jpeg, AV_CODEC_ID_MJPEG)
+IMAGEAUTO_DEMUXER(jpegls, AV_CODEC_ID_JPEGLS)
+IMAGEAUTO_DEMUXER(pictor, AV_CODEC_ID_PICTOR)
+IMAGEAUTO_DEMUXER(png, AV_CODEC_ID_PNG)
+IMAGEAUTO_DEMUXER(qdraw, AV_CODEC_ID_QDRAW)
+IMAGEAUTO_DEMUXER(sgi, AV_CODEC_ID_SGI)
+IMAGEAUTO_DEMUXER(sunrast, AV_CODEC_ID_SUNRAST)
+IMAGEAUTO_DEMUXER(tiff, AV_CODEC_ID_TIFF)
+IMAGEAUTO_DEMUXER(webp, AV_CODEC_ID_WEBP)
diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c
index eeb19c0e25..f56c39e6d3 100644
--- a/libavformat/img2enc.c
+++ b/libavformat/img2enc.c
@@ -3,42 +3,50 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2004 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/time_internal.h"
#include "avformat.h"
#include "avio_internal.h"
#include "internal.h"
-#include "libavutil/opt.h"
typedef struct VideoMuxData {
const AVClass *class; /**< Class for private options. */
int img_number;
int is_pipe;
+ int split_planes; /**< use independent file for each Y, U, V plane */
char path[1024];
int update;
+ int use_strftime;
+ const char *muxer;
} VideoMuxData;
static int write_header(AVFormatContext *s)
{
VideoMuxData *img = s->priv_data;
+ AVStream *st = s->streams[0];
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codec->pix_fmt);
av_strlcpy(img->path, s->filename, sizeof(img->path));
@@ -48,79 +56,116 @@ static int write_header(AVFormatContext *s)
else
img->is_pipe = 1;
+ if (st->codec->codec_id == AV_CODEC_ID_GIF) {
+ img->muxer = "gif";
+ } else if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ const char *str = strrchr(img->path, '.');
+ img->split_planes = str
+ && !av_strcasecmp(str + 1, "y")
+ && s->nb_streams == 1
+ && desc
+ &&(desc->flags & AV_PIX_FMT_FLAG_PLANAR)
+ && desc->nb_components >= 3;
+ }
return 0;
}
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
VideoMuxData *img = s->priv_data;
- AVIOContext *pb[3];
+ AVIOContext *pb[4];
char filename[1024];
AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(codec->pix_fmt);
int i;
if (!img->is_pipe) {
if (img->update) {
av_strlcpy(filename, img->path, sizeof(filename));
+ } else if (img->use_strftime) {
+ time_t now0;
+ struct tm *tm, tmpbuf;
+ time(&now0);
+ tm = localtime_r(&now0, &tmpbuf);
+ if (!strftime(filename, sizeof(filename), img->path, tm)) {
+ av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n");
+ return AVERROR(EINVAL);
+ }
} else if (av_get_frame_filename(filename, sizeof(filename), img->path, img->img_number) < 0 &&
img->img_number > 1) {
av_log(s, AV_LOG_ERROR,
- "Could not get frame filename number %d from pattern '%s'\n",
+ "Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n",
img->img_number, img->path);
- return AVERROR(EIO);
+ return AVERROR(EINVAL);
}
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
if (avio_open2(&pb[i], filename, AVIO_FLAG_WRITE,
&s->interrupt_callback, NULL) < 0) {
av_log(s, AV_LOG_ERROR, "Could not open file : %s\n", filename);
return AVERROR(EIO);
}
- if (codec->codec_id != AV_CODEC_ID_RAWVIDEO)
+ if (!img->split_planes || i+1 >= desc->nb_components)
break;
- filename[strlen(filename) - 1] = 'U' + i;
+ filename[strlen(filename) - 1] = "UVAx"[i];
}
} else {
pb[0] = s->pb;
}
- if (codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ if (img->split_planes) {
int ysize = codec->width * codec->height;
- avio_write(pb[0], pkt->data, ysize);
- avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize) / 2);
- avio_write(pb[2], pkt->data + ysize + (pkt->size - ysize) / 2, (pkt->size - ysize) / 2);
- avio_close(pb[1]);
- avio_close(pb[2]);
- } else {
- if (ff_guess_image2_codec(s->filename) == AV_CODEC_ID_JPEG2000) {
- AVStream *st = s->streams[0];
- if (st->codec->extradata_size > 8 &&
- AV_RL32(st->codec->extradata + 4) == MKTAG('j', 'p', '2', 'h')) {
- if (pkt->size < 8 ||
- AV_RL32(pkt->data + 4) != MKTAG('j', 'p', '2', 'c'))
- goto error;
- avio_wb32(pb[0], 12);
- ffio_wfourcc(pb[0], "jP ");
- avio_wb32(pb[0], 0x0D0A870A); // signature
- avio_wb32(pb[0], 20);
- ffio_wfourcc(pb[0], "ftyp");
- ffio_wfourcc(pb[0], "jp2 ");
- avio_wb32(pb[0], 0);
- ffio_wfourcc(pb[0], "jp2 ");
- avio_write(pb[0], st->codec->extradata, st->codec->extradata_size);
- } else if (pkt->size < 8 ||
- (!st->codec->extradata_size &&
- AV_RL32(pkt->data + 4) != MKTAG('j', 'P', ' ', ' '))) { // signature
-error:
- av_log(s, AV_LOG_ERROR, "malformed JPEG 2000 codestream\n");
- return -1;
- }
+ int usize = FF_CEIL_RSHIFT(codec->width, desc->log2_chroma_w) * FF_CEIL_RSHIFT(codec->height, desc->log2_chroma_h);
+ if (desc->comp[0].depth_minus1 >= 8) {
+ ysize *= 2;
+ usize *= 2;
+ }
+ avio_write(pb[0], pkt->data , ysize);
+ avio_write(pb[1], pkt->data + ysize , usize);
+ avio_write(pb[2], pkt->data + ysize + usize, usize);
+ avio_closep(&pb[1]);
+ avio_closep(&pb[2]);
+ if (desc->nb_components > 3) {
+ avio_write(pb[3], pkt->data + ysize + 2*usize, ysize);
+ avio_closep(&pb[3]);
}
+ } else if (img->muxer) {
+ int ret;
+ AVStream *st;
+ AVPacket pkt2 = {0};
+ AVFormatContext *fmt = NULL;
+
+ av_assert0(!img->split_planes);
+
+ ret = avformat_alloc_output_context2(&fmt, NULL, img->muxer, s->filename);
+ if (ret < 0)
+ return ret;
+ st = avformat_new_stream(fmt, NULL);
+ if (!st) {
+ avformat_free_context(fmt);
+ return AVERROR(ENOMEM);
+ }
+ st->id = pkt->stream_index;
+
+ fmt->pb = pb[0];
+ if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
+ (ret = av_dup_packet(&pkt2)) < 0 ||
+ (ret = avcodec_copy_context(st->codec, s->streams[0]->codec)) < 0 ||
+ (ret = avformat_write_header(fmt, NULL)) < 0 ||
+ (ret = av_interleaved_write_frame(fmt, &pkt2)) < 0 ||
+ (ret = av_write_trailer(fmt)) < 0) {
+ av_free_packet(&pkt2);
+ avformat_free_context(fmt);
+ return ret;
+ }
+ av_free_packet(&pkt2);
+ avformat_free_context(fmt);
+ } else {
avio_write(pb[0], pkt->data, pkt->size);
}
avio_flush(pb[0]);
if (!img->is_pipe) {
- avio_close(pb[0]);
+ avio_closep(&pb[0]);
}
img->img_number++;
@@ -130,8 +175,10 @@ error:
#define OFFSET(x) offsetof(VideoMuxData, x)
#define ENC AV_OPT_FLAG_ENCODING_PARAM
static const AVOption muxoptions[] = {
- { "start_number", "first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, ENC },
+ { "updatefirst", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
{ "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
+ { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC },
+ { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
{ NULL },
};
@@ -146,9 +193,9 @@ static const AVClass img2mux_class = {
AVOutputFormat ff_image2_muxer = {
.name = "image2",
.long_name = NULL_IF_CONFIG_SMALL("image2 sequence"),
- .extensions = "bmp,dpx,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png,"
- "ppm,sgi,tga,tif,tiff,jp2,xwd,sun,ras,rs,im1,im8,im24,"
- "sunras,webp,xbm,j2c,pix",
+ .extensions = "bmp,dpx,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pgm,pgmyuv,png,"
+ "ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24,"
+ "sunras,xbm,xface,pix,y",
.priv_data_size = sizeof(VideoMuxData),
.video_codec = AV_CODEC_ID_MJPEG,
.write_header = write_header,
diff --git a/libavformat/ingenientdec.c b/libavformat/ingenientdec.c
index 42b29ef6e3..94c549c711 100644
--- a/libavformat/ingenientdec.c
+++ b/libavformat/ingenientdec.c
@@ -2,20 +2,20 @@
* RAW Ingenient MJPEG demuxer
* Copyright (c) 2005 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,17 +44,10 @@ static int ingenient_read_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_DEBUG, "Ingenient packet: size=%d, width=%d, height=%d, unk1=%d unk2=%d\n",
size, w, h, unk1, unk2);
- if (av_new_packet(pkt, size) < 0)
- return AVERROR(ENOMEM);
-
- pkt->pos = avio_tell(s->pb);
- pkt->stream_index = 0;
- ret = avio_read(s->pb, pkt->data, size);
- if (ret < 0) {
- av_free_packet(pkt);
+ ret = av_get_packet(s->pb, pkt, size);
+ if (ret < 0)
return ret;
- }
- pkt->size = ret;
+ pkt->stream_index = 0;
return ret;
}
diff --git a/libavformat/internal.h b/libavformat/internal.h
index f08ad90038..f90df90242 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,10 +27,14 @@
#define MAX_URL_SIZE 4096
+/** size of probe buffer, for guessing file type from file contents */
+#define PROBE_BUF_MIN 2048
+#define PROBE_BUF_MAX (1 << 20)
+
#ifdef DEBUG
# define hex_dump_debug(class, buf, size) av_hex_dump_log(class, AV_LOG_DEBUG, buf, size)
#else
-# define hex_dump_debug(class, buf, size)
+# define hex_dump_debug(class, buf, size) do { if (0) av_hex_dump_log(class, AV_LOG_DEBUG, buf, size); } while(0)
#endif
typedef struct AVCodecTag {
@@ -83,6 +87,7 @@ struct AVFormatInternal {
/**
* Offset to remap timestamps to be non-negative.
* Expressed in timebase units.
+ * @see AVStream.mux_ts_offset
*/
int64_t offset;
@@ -90,9 +95,11 @@ struct AVFormatInternal {
* Timebase for the timestamp offset.
*/
AVRational offset_timebase;
-};
-void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem);
+ int inject_global_side_data;
+
+ int avoid_negative_ts_use_pts;
+};
#ifdef __GNUC__
#define dynarray_add(tab, nb_ptr, elem)\
@@ -100,12 +107,12 @@ do {\
__typeof__(tab) _tab = (tab);\
__typeof__(elem) _elem = (elem);\
(void)sizeof(**_tab == _elem); /* check that types are compatible */\
- ff_dynarray_add((intptr_t **)_tab, nb_ptr, (intptr_t)_elem);\
+ av_dynarray_add(_tab, nb_ptr, _elem);\
} while(0)
#else
#define dynarray_add(tab, nb_ptr, elem)\
do {\
- ff_dynarray_add((intptr_t **)(tab), nb_ptr, (intptr_t)(elem));\
+ av_dynarray_add((tab), nb_ptr, (elem));\
} while(0)
#endif
@@ -128,6 +135,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i
/**
* Add packet to AVFormatContext->packet_buffer list, determining its
* interleaved position using compare() function argument.
+ * @return 0, or < 0 on error
*/
int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
int (*compare)(AVFormatContext *, AVPacket *, AVPacket *));
@@ -171,10 +179,11 @@ void ff_sdp_write_media(char *buff, int size, AVStream *st, int idx,
* @param dst_stream the stream index within dst to write the packet to
* @param pkt the packet to be written
* @param src the muxer the packet originally was intended for
+ * @param interleave 0->use av_write_frame, 1->av_interleaved_write_frame
* @return the value av_write_frame returned
*/
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
- AVFormatContext *src);
+ AVFormatContext *src, int interleave);
/**
* Get the length in bytes which is needed to store val as v.
@@ -293,6 +302,9 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
*/
void ff_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp);
+int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos,
+ int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ));
+
/**
* Perform a binary search using read_timestamp().
*
@@ -362,6 +374,8 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt);
int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
AVPacket *pkt, int flush);
+void ff_free_stream(AVFormatContext *s, AVStream *st);
+
/**
* Return the frame duration in seconds. Return 0 if not available.
*/
@@ -388,6 +402,20 @@ enum AVCodecID ff_codec_get_id(const AVCodecTag *tags, unsigned int tag);
enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags);
/**
+ * Chooses a timebase for muxing the specified stream.
+ *
+ * The chosen timebase allows sample accurate timestamps based
+ * on the framerate or sample rate for audio streams. It also is
+ * at least as precise as 1/min_precision would be.
+ */
+AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precision);
+
+/**
+ * Chooses a timebase for muxing the specified stream.
+ */
+enum AVChromaLocation ff_choose_chroma_location(AVFormatContext *s, AVStream *st);
+
+/**
* Generate standard extradata for AVC-Intra based on width/height and field
* order.
*/
@@ -400,11 +428,15 @@ int ff_generate_avci_extradata(AVStream *st);
* @param newpath destination path
* @return 0 or AVERROR on failure
*/
-static inline int ff_rename(const char *oldpath, const char *newpath)
+static inline int ff_rename(const char *oldpath, const char *newpath, void *logctx)
{
- if (rename(oldpath, newpath) == -1)
- return AVERROR(errno);
- return 0;
+ int ret = 0;
+ if (rename(oldpath, newpath) == -1) {
+ ret = AVERROR(errno);
+ if (logctx)
+ av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s\n", oldpath, newpath);
+ }
+ return ret;
}
/**
@@ -414,4 +446,53 @@ static inline int ff_rename(const char *oldpath, const char *newpath)
uint8_t *ff_stream_new_side_data(AVStream *st, enum AVPacketSideDataType type,
int size);
+/**
+ * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end
+ * which is always set to 0.
+ *
+ * @param size size of extradata
+ * @return 0 if OK, AVERROR_xxx on error
+ */
+int ff_alloc_extradata(AVCodecContext *avctx, int size);
+
+/**
+ * Allocate extradata with additional FF_INPUT_BUFFER_PADDING_SIZE at end
+ * which is always set to 0 and fill it from pb.
+ *
+ * @param size size of extradata
+ * @return >= 0 if OK, AVERROR_xxx on error
+ */
+int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size);
+
+/**
+ * add frame for rfps calculation.
+ *
+ * @param dts timestamp of the i-th frame
+ * @return 0 if OK, AVERROR_xxx on error
+ */
+int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t dts);
+
+void ff_rfps_calculate(AVFormatContext *ic);
+
+/**
+ * Flags for AVFormatContext.write_uncoded_frame()
+ */
+enum AVWriteUncodedFrameFlags {
+
+ /**
+ * Query whether the feature is possible on this stream.
+ * The frame argument is ignored.
+ */
+ AV_WRITE_UNCODED_FRAME_QUERY = 0x0001,
+
+};
+
+/**
+ * Copies the whilelists from one context to the other
+ */
+int ff_copy_whitelists(AVFormatContext *dst, AVFormatContext *src);
+
+int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags,
+ const AVIOInterruptCB *int_cb, AVDictionary **options);
+
#endif /* AVFORMAT_INTERNAL_H */
diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c
index fe8d97b548..af518b59d3 100644
--- a/libavformat/ipmovie.c
+++ b/libavformat/ipmovie.c
@@ -1,21 +1,21 @@
/*
* Interplay MVE File Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -117,7 +117,7 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb,
int chunk_type;
- if (s->audio_chunk_offset) {
+ if (s->audio_chunk_offset && s->audio_channels && s->audio_bits) {
if (s->audio_type == AV_CODEC_ID_NONE) {
av_log(NULL, AV_LOG_ERROR, "Can not read audio packet before"
"audio codec is known\n");
@@ -237,7 +237,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
return chunk_type;
/* read the next chunk, wherever the file happens to be pointing */
- if (pb->eof_reached)
+ if (avio_feof(pb))
return CHUNK_EOF;
if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) !=
CHUNK_PREAMBLE_SIZE)
@@ -283,7 +283,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) {
/* read the next chunk, wherever the file happens to be pointing */
- if (pb->eof_reached) {
+ if (avio_feof(pb)) {
chunk_type = CHUNK_EOF;
break;
}
@@ -321,7 +321,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
case OPCODE_CREATE_TIMER:
av_log(NULL, AV_LOG_TRACE, "create timer\n");
- if ((opcode_version > 0) || (opcode_size > 6)) {
+ if ((opcode_version > 0) || (opcode_size != 6)) {
av_log(NULL, AV_LOG_TRACE, "bad create_timer opcode\n");
chunk_type = CHUNK_BAD;
break;
@@ -339,7 +339,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
case OPCODE_INIT_AUDIO_BUFFERS:
av_log(NULL, AV_LOG_TRACE, "initialize audio buffers\n");
- if ((opcode_version > 1) || (opcode_size > 10)) {
+ if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) {
av_log(NULL, AV_LOG_TRACE, "bad init_audio_buffers opcode\n");
chunk_type = CHUNK_BAD;
break;
@@ -376,7 +376,9 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
case OPCODE_INIT_VIDEO_BUFFERS:
av_log(NULL, AV_LOG_TRACE, "initialize video buffers\n");
- if ((opcode_version > 2) || (opcode_size > 8)) {
+ if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4
+ || opcode_version == 2 && opcode_size < 8
+ ) {
av_log(NULL, AV_LOG_TRACE, "bad init_video_buffers opcode\n");
chunk_type = CHUNK_BAD;
break;
@@ -449,8 +451,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
av_log(NULL, AV_LOG_TRACE, "set palette\n");
/* check for the logical maximum palette size
* (3 * 256 + 4 bytes) */
- if (opcode_size > 0x304) {
- av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode too large\n");
+ if (opcode_size > 0x304 || opcode_size < 4) {
+ av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode with invalid size\n");
chunk_type = CHUNK_BAD;
break;
}
@@ -463,7 +465,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
first_color = AV_RL16(&scratch[0]);
last_color = first_color + AV_RL16(&scratch[2]) - 1;
/* sanity check (since they are 16 bit values) */
- if ((first_color > 0xFF) || (last_color > 0xFF)) {
+ if ( (first_color > 0xFF) || (last_color > 0xFF)
+ || (last_color - first_color + 1)*3 + 4 > opcode_size) {
av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n",
first_color, last_color);
chunk_type = CHUNK_BAD;
@@ -476,7 +479,8 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb,
r = scratch[j++] * 4;
g = scratch[j++] * 4;
b = scratch[j++] * 4;
- s->palette[i] = (r << 16) | (g << 8) | (b);
+ s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
+ s->palette[i] |= s->palette[i] >> 6 & 0x30303;
}
s->has_palette = 1;
break;
@@ -526,11 +530,12 @@ static const char signature[] = "Interplay MVE File\x1A\0\x1A";
static int ipmovie_probe(AVProbeData *p)
{
- uint8_t *b = p->buf;
- uint8_t *b_end = p->buf + p->buf_size - sizeof(signature);
+ const uint8_t *b = p->buf;
+ const uint8_t *b_end = p->buf + p->buf_size - sizeof(signature);
do {
- if (memcmp(b++, signature, sizeof(signature)) == 0)
+ if (b[0] == signature[0] && memcmp(b, signature, sizeof(signature)) == 0)
return AVPROBE_SCORE_MAX;
+ b++;
} while (b < b_end);
return 0;
@@ -543,14 +548,14 @@ static int ipmovie_read_header(AVFormatContext *s)
AVPacket pkt;
AVStream *st;
unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE];
- int chunk_type;
+ int chunk_type, i;
uint8_t signature_buffer[sizeof(signature)];
avio_read(pb, signature_buffer, sizeof(signature_buffer));
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);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
}
/* initialize private context members */
@@ -561,6 +566,9 @@ static int ipmovie_read_header(AVFormatContext *s)
/* on the first read, this will position the stream at the first chunk */
ipmovie->next_chunk_offset = avio_tell(pb) + 4;
+ for (i = 0; i < 256; i++)
+ ipmovie->palette[i] = 0xFFU << 24;
+
/* process the first chunk which should be CHUNK_INIT_VIDEO */
if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO)
return AVERROR_INVALIDDATA;
@@ -622,6 +630,7 @@ static int ipmovie_read_packet(AVFormatContext *s,
AVIOContext *pb = s->pb;
int ret;
+ for (;;) {
ret = process_ipmovie_chunk(ipmovie, pb, pkt);
if (ret == CHUNK_BAD)
ret = AVERROR_INVALIDDATA;
@@ -631,10 +640,13 @@ static int ipmovie_read_packet(AVFormatContext *s,
ret = AVERROR(ENOMEM);
else if (ret == CHUNK_VIDEO)
ret = 0;
+ else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO)
+ continue;
else
ret = -1;
return ret;
+ }
}
AVInputFormat ff_ipmovie_demuxer = {
diff --git a/libavformat/ircam.c b/libavformat/ircam.c
new file mode 100644
index 0000000000..a267c18a08
--- /dev/null
+++ b/libavformat/ircam.c
@@ -0,0 +1,47 @@
+/*
+ * IRCAM common code
+ * Copyright (c) 2012 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
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+const AVCodecTag ff_codec_ircam_le_tags[] = {
+ { AV_CODEC_ID_PCM_ALAW, 0x10001 },
+ { AV_CODEC_ID_PCM_F32LE, 0x00004 },
+ { AV_CODEC_ID_PCM_F64LE, 0x00008 },
+ { AV_CODEC_ID_PCM_MULAW, 0x20001 },
+ { AV_CODEC_ID_PCM_S16LE, 0x00002 },
+ { AV_CODEC_ID_PCM_S24LE, 0x00003 },
+ { AV_CODEC_ID_PCM_S32LE, 0x40004 },
+ { AV_CODEC_ID_PCM_S8, 0x00001 },
+ { AV_CODEC_ID_NONE, 0 },
+};
+
+const AVCodecTag ff_codec_ircam_be_tags[] = {
+ { AV_CODEC_ID_PCM_ALAW, 0x10001 },
+ { AV_CODEC_ID_PCM_F32BE, 0x00004 },
+ { AV_CODEC_ID_PCM_F64BE, 0x00008 },
+ { AV_CODEC_ID_PCM_MULAW, 0x20001 },
+ { AV_CODEC_ID_PCM_S16BE, 0x00002 },
+ { AV_CODEC_ID_PCM_S24BE, 0x00003 },
+ { AV_CODEC_ID_PCM_S32BE, 0x40004 },
+ { AV_CODEC_ID_PCM_S8, 0x00001 },
+ { AV_CODEC_ID_NONE, 0 },
+};
diff --git a/libavformat/ircam.h b/libavformat/ircam.h
new file mode 100644
index 0000000000..f7f9c84b91
--- /dev/null
+++ b/libavformat/ircam.h
@@ -0,0 +1,30 @@
+/*
+ * IRCAM common code
+ * Copyright (c) 2012 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 AVFORMAT_IRCAM_H
+#define AVFORMAT_IRCAM_H
+
+#include "internal.h"
+
+extern const AVCodecTag ff_codec_ircam_be_tags[];
+extern const AVCodecTag ff_codec_ircam_le_tags[];
+
+#endif /* AVFORMAT_IRCAM_H */
diff --git a/libavformat/ircamdec.c b/libavformat/ircamdec.c
new file mode 100644
index 0000000000..f9533ec4a5
--- /dev/null
+++ b/libavformat/ircamdec.c
@@ -0,0 +1,115 @@
+/*
+ * IRCAM demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+#include "ircam.h"
+
+static int ircam_probe(AVProbeData *p)
+{
+ if ((p->buf[0] == 0x64 && p->buf[1] == 0xA3 && p->buf[3] == 0x00 &&
+ p->buf[2] >= 1 && p->buf[2] <= 4) ||
+ (p->buf[3] == 0x64 && p->buf[2] == 0xA3 && p->buf[0] == 0x00 &&
+ p->buf[1] >= 1 && p->buf[1] <= 3) &&
+ AV_RN32(p->buf + 4) && AV_RN32(p->buf + 8))
+ return AVPROBE_SCORE_MAX / 4 * 3;
+ return 0;
+}
+
+static const struct endianess {
+ uint32_t magic;
+ int is_le;
+} table[] = {
+ { 0x64A30100, 0 },
+ { 0x64A30200, 1 },
+ { 0x64A30300, 0 },
+ { 0x64A30400, 1 },
+ { 0x0001A364, 1 },
+ { 0x0002A364, 0 },
+ { 0x0003A364, 1 },
+};
+
+static int ircam_read_header(AVFormatContext *s)
+{
+ uint32_t magic, sample_rate, channels, tag;
+ const AVCodecTag *tags;
+ int le = -1, i;
+ AVStream *st;
+
+ magic = avio_rl32(s->pb);
+ for (i = 0; i < 7; i++) {
+ if (magic == table[i].magic) {
+ le = table[i].is_le;
+ break;
+ }
+ }
+
+ if (le == 1) {
+ sample_rate = av_int2float(avio_rl32(s->pb));
+ channels = avio_rl32(s->pb);
+ tag = avio_rl32(s->pb);
+ tags = ff_codec_ircam_le_tags;
+ } else if (le == 0) {
+ sample_rate = av_int2float(avio_rb32(s->pb));
+ channels = avio_rb32(s->pb);
+ tag = avio_rb32(s->pb);
+ tags = ff_codec_ircam_be_tags;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!channels || !sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->channels = channels;
+ st->codec->sample_rate = sample_rate;
+
+ st->codec->codec_id = ff_codec_get_id(tags, tag);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) {
+ av_log(s, AV_LOG_ERROR, "unknown tag %X\n", tag);
+ return AVERROR_INVALIDDATA;
+ }
+
+ st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id);
+ st->codec->block_align = st->codec->bits_per_coded_sample * st->codec->channels / 8;
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ avio_skip(s->pb, 1008);
+
+ return 0;
+}
+
+AVInputFormat ff_ircam_demuxer = {
+ .name = "ircam",
+ .long_name = NULL_IF_CONFIG_SMALL("Berkeley/IRCAM/CARL Sound Format"),
+ .read_probe = ircam_probe,
+ .read_header = ircam_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "sf,ircam",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/ircamenc.c b/libavformat/ircamenc.c
new file mode 100644
index 0000000000..38f15fbceb
--- /dev/null
+++ b/libavformat/ircamenc.c
@@ -0,0 +1,62 @@
+/*
+ * IRCAM muxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "rawenc.h"
+#include "ircam.h"
+
+static int ircam_write_header(AVFormatContext *s)
+{
+ AVCodecContext *codec = s->streams[0]->codec;
+ uint32_t tag;
+
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+
+ tag = ff_codec_get_tag(ff_codec_ircam_le_tags, codec->codec_id);
+ if (!tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+
+ avio_wl32(s->pb, 0x0001A364);
+ avio_wl32(s->pb, av_float2int(codec->sample_rate));
+ avio_wl32(s->pb, codec->channels);
+ avio_wl32(s->pb, tag);
+ ffio_fill(s->pb, 0, 1008);
+ return 0;
+}
+
+AVOutputFormat ff_ircam_muxer = {
+ .name = "ircam",
+ .extensions = "sf,ircam",
+ .long_name = NULL_IF_CONFIG_SMALL("Berkeley/IRCAM/CARL Sound Format"),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = ircam_write_header,
+ .write_packet = ff_raw_write_packet,
+ .codec_tag = (const AVCodecTag *const []){ ff_codec_ircam_le_tags, 0 },
+};
diff --git a/libavformat/isom.c b/libavformat/isom.c
index f8cc4b2b9e..c99f2dc5db 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -4,20 +4,20 @@
* Copyright (c) 2002 Francois Revol <revol@free.fr>
* Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,6 +57,7 @@ const AVCodecTag ff_mp4_obj_type[] = {
{ AV_CODEC_ID_VC1 , 0xA3 },
{ AV_CODEC_ID_DIRAC , 0xA4 },
{ AV_CODEC_ID_AC3 , 0xA5 },
+ { AV_CODEC_ID_EAC3 , 0xA6 },
{ AV_CODEC_ID_DTS , 0xA9 }, /* mp4ra.org */
{ AV_CODEC_ID_TSCC2 , 0xD0 }, /* non standard, camtasia uses it */
{ AV_CODEC_ID_VORBIS , 0xDD }, /* non standard, gpac uses it */
@@ -72,7 +73,6 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('r', 'a', 'w', ' ') }, /* Uncompressed RGB */
{ AV_CODEC_ID_RAWVIDEO, MKTAG('y', 'u', 'v', '2') }, /* Uncompressed YUV422 */
- { AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'U', 'I') }, /* YUV with alpha-channel (AVID Uncompressed) */
{ AV_CODEC_ID_RAWVIDEO, MKTAG('2', 'v', 'u', 'y') }, /* UNCOMPRESSED 8BIT 4:2:2 */
{ AV_CODEC_ID_RAWVIDEO, MKTAG('y', 'u', 'v', 's') }, /* same as 2vuy but byte swapped */
@@ -96,9 +96,17 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_R10K, MKTAG('R', '1', '0', 'k') }, /* UNCOMPRESSED 10BIT RGB */
{ AV_CODEC_ID_R10K, MKTAG('R', '1', '0', 'g') }, /* UNCOMPRESSED 10BIT RGB */
{ AV_CODEC_ID_R210, MKTAG('r', '2', '1', '0') }, /* UNCOMPRESSED 10BIT RGB */
+ { AV_CODEC_ID_AVUI, MKTAG('A', 'V', 'U', 'I') }, /* AVID Uncompressed deinterleaved UYVY422 */
+ { AV_CODEC_ID_AVRP, MKTAG('A', 'V', 'r', 'p') }, /* Avid 1:1 10-bit RGB Packer */
+ { AV_CODEC_ID_AVRP, MKTAG('S', 'U', 'D', 'S') }, /* Avid DS Uncompressed */
{ AV_CODEC_ID_V210, MKTAG('v', '2', '1', '0') }, /* UNCOMPRESSED 10BIT 4:2:2 */
{ AV_CODEC_ID_V210, MKTAG('b', 'x', 'y', '2') }, /* BOXX 10BIT 4:2:2 */
+ { AV_CODEC_ID_V308, MKTAG('v', '3', '0', '8') }, /* UNCOMPRESSED 8BIT 4:4:4 */
+ { AV_CODEC_ID_V408, MKTAG('v', '4', '0', '8') }, /* UNCOMPRESSED 8BIT 4:4:4:4 */
{ AV_CODEC_ID_V410, MKTAG('v', '4', '1', '0') }, /* UNCOMPRESSED 10BIT 4:4:4 */
+ { AV_CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') }, /* UNCOMPRESSED 12BIT 4:1:1 */
+ { AV_CODEC_ID_YUV4, MKTAG('y', 'u', 'v', '4') }, /* libquicktime packed yuv420p */
+ { AV_CODEC_ID_TARGA_Y216, MKTAG('Y', '2', '1', '6') },
{ AV_CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') }, /* PhotoJPEG */
{ AV_CODEC_ID_MJPEG, MKTAG('m', 'j', 'p', 'a') }, /* Motion-JPEG (format A) */
@@ -302,12 +310,15 @@ const AVCodecTag ff_codec_movaudio_tags[] = {
{ AV_CODEC_ID_SPEEX, MKTAG('s', 'p', 'e', 'x') }, /* Flash Media Server */
{ AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', 'N') }, /* ZygoAudio (quality 10 mode) */
{ AV_CODEC_ID_WMAV2, MKTAG('W', 'M', 'A', '2') },
+ { AV_CODEC_ID_EVRC, MKTAG('s', 'e', 'v', 'c') }, /* 3GPP2 */
+ { AV_CODEC_ID_SMV, MKTAG('s', 's', 'm', 'v') }, /* 3GPP2 */
{ AV_CODEC_ID_NONE, 0 },
};
const AVCodecTag ff_codec_movsubtitle_tags[] = {
{ AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'e', 'x', 't') },
{ AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
+ { AV_CODEC_ID_EIA_608, MKTAG('c', '6', '0', '8') },
{ AV_CODEC_ID_NONE, 0 },
};
@@ -435,14 +446,23 @@ static const AVCodecTag mp4_audio_types[] = {
int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext *pb)
{
+ enum AVCodecID codec_id;
int len, tag;
+ int ret;
int object_type_id = avio_r8(pb);
avio_r8(pb); /* stream type */
avio_rb24(pb); /* buffer size db */
avio_rb32(pb); /* max bitrate */
avio_rb32(pb); /* avg bitrate */
- st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id);
+ if(avcodec_is_open(st->codec)) {
+ av_log(fc, AV_LOG_DEBUG, "codec open in read_dec_config_descr\n");
+ return -1;
+ }
+
+ codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id);
+ if (codec_id)
+ st->codec->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);
if (tag == MP4DecSpecificDescrTag) {
@@ -450,13 +470,10 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext
if (!len || (uint64_t)len > (1<<30))
return -1;
av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
- avio_read(pb, st->codec->extradata, len);
- st->codec->extradata_size = len;
+ if ((ret = ff_get_extradata(st->codec, pb, len)) < 0)
+ return ret;
if (st->codec->codec_id == AV_CODEC_ID_AAC) {
- MPEG4AudioConfig cfg;
+ MPEG4AudioConfig cfg = {0};
avpriv_mpeg4audio_get_config(&cfg, st->codec->extradata,
st->codec->extradata_size * 8, 1);
st->codec->channels = cfg.channels;
@@ -477,3 +494,104 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext
}
return 0;
}
+
+typedef struct MovChannelLayout {
+ int64_t channel_layout;
+ uint32_t layout_tag;
+} MovChannelLayout;
+
+static const MovChannelLayout mov_channel_layout[] = {
+ { AV_CH_LAYOUT_MONO, (100<<16) | 1}, // kCAFChannelLayoutTag_Mono
+ { AV_CH_LAYOUT_STEREO, (101<<16) | 2}, // kCAFChannelLayoutTag_Stereo
+ { AV_CH_LAYOUT_STEREO, (102<<16) | 2}, // kCAFChannelLayoutTag_StereoHeadphones
+ { AV_CH_LAYOUT_2_1, (131<<16) | 3}, // kCAFChannelLayoutTag_ITU_2_1
+ { AV_CH_LAYOUT_QUAD, (132<<16) | 4}, // kCAFChannelLayoutTag_ITU_2_2
+ { AV_CH_LAYOUT_2_2, (132<<16) | 4}, // kCAFChannelLayoutTag_ITU_2_2
+ { AV_CH_LAYOUT_QUAD, (108<<16) | 4}, // kCAFChannelLayoutTag_Quadraphonic
+ { AV_CH_LAYOUT_SURROUND, (113<<16) | 3}, // kCAFChannelLayoutTag_MPEG_3_0_A
+ { AV_CH_LAYOUT_4POINT0, (115<<16) | 4}, // kCAFChannelLayoutTag_MPEG_4_0_A
+ { AV_CH_LAYOUT_5POINT0_BACK, (117<<16) | 5}, // kCAFChannelLayoutTag_MPEG_5_0_A
+ { AV_CH_LAYOUT_5POINT0, (117<<16) | 5}, // kCAFChannelLayoutTag_MPEG_5_0_A
+ { AV_CH_LAYOUT_5POINT1_BACK, (121<<16) | 6}, // kCAFChannelLayoutTag_MPEG_5_1_A
+ { AV_CH_LAYOUT_5POINT1, (121<<16) | 6}, // kCAFChannelLayoutTag_MPEG_5_1_A
+ { AV_CH_LAYOUT_7POINT1, (128<<16) | 8}, // kCAFChannelLayoutTag_MPEG_7_1_C
+ { AV_CH_LAYOUT_7POINT1_WIDE, (126<<16) | 8}, // kCAFChannelLayoutTag_MPEG_7_1_A
+ { AV_CH_LAYOUT_5POINT1_BACK|AV_CH_LAYOUT_STEREO_DOWNMIX, (130<<16) | 8}, // kCAFChannelLayoutTag_SMPTE_DTV
+ { AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY, (133<<16) | 3}, // kCAFChannelLayoutTag_DVD_4
+ { AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY, (134<<16) | 4}, // kCAFChannelLayoutTag_DVD_5
+ { AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY, (135<<16) | 4}, // kCAFChannelLayoutTag_DVD_6
+ { AV_CH_LAYOUT_2_2|AV_CH_LOW_FREQUENCY, (135<<16) | 4}, // kCAFChannelLayoutTag_DVD_6
+ { AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, (136<<16) | 4}, // kCAFChannelLayoutTag_DVD_10
+ { AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, (137<<16) | 5}, // kCAFChannelLayoutTag_DVD_11
+ { 0, 0},
+};
+#if 0
+int ff_mov_read_chan(AVFormatContext *s, AVStream *st, int64_t size)
+{
+ AVCodecContext *codec= st->codec;
+ uint32_t layout_tag;
+ AVIOContext *pb = s->pb;
+ const MovChannelLayout *layouts = mov_channel_layout;
+
+ if (size < 12)
+ return AVERROR_INVALIDDATA;
+
+ layout_tag = avio_rb32(pb);
+ size -= 4;
+ if (layout_tag == 0) { // kCAFChannelLayoutTag_UseChannelDescriptions
+ // Channel descriptions not implemented
+ av_log_ask_for_sample(s, "Unimplemented container channel layout.\n");
+ avio_skip(pb, size);
+ return 0;
+ }
+ if (layout_tag == 0x10000) { // kCAFChannelLayoutTag_UseChannelBitmap
+ codec->channel_layout = avio_rb32(pb);
+ size -= 4;
+ avio_skip(pb, size);
+ return 0;
+ }
+ while (layouts->channel_layout) {
+ if (layout_tag == layouts->layout_tag) {
+ codec->channel_layout = layouts->channel_layout;
+ break;
+ }
+ layouts++;
+ }
+ if (!codec->channel_layout)
+ av_log(s, AV_LOG_WARNING, "Unknown container channel layout.\n");
+ avio_skip(pb, size);
+
+ return 0;
+}
+#endif
+
+void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout)
+{
+ const MovChannelLayout *layouts;
+ uint32_t layout_tag = 0;
+
+ for (layouts = mov_channel_layout; layouts->channel_layout; layouts++)
+ if (channel_layout == layouts->channel_layout) {
+ layout_tag = layouts->layout_tag;
+ break;
+ }
+
+ if (layout_tag) {
+ avio_wb32(pb, layout_tag); // mChannelLayoutTag
+ avio_wb32(pb, 0); // mChannelBitmap
+ } else {
+ avio_wb32(pb, 0x10000); // kCAFChannelLayoutTag_UseChannelBitmap
+ avio_wb32(pb, channel_layout);
+ }
+ avio_wb32(pb, 0); // mNumberChannelDescriptions
+}
+
+const struct AVCodecTag *avformat_get_mov_video_tags(void)
+{
+ return ff_codec_movvideo_tags;
+}
+
+const struct AVCodecTag *avformat_get_mov_audio_tags(void)
+{
+ return ff_codec_movaudio_tags;
+}
diff --git a/libavformat/isom.h b/libavformat/isom.h
index d81d4358a2..5d48989fd9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -4,20 +4,20 @@
* copyright (c) 2002 Francois Revol <revol@free.fr>
* copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -53,6 +53,12 @@ typedef struct MOVStsc {
int id;
} MOVStsc;
+typedef struct MOVElst {
+ int64_t duration;
+ int64_t time;
+ float rate;
+} MOVElst;
+
typedef struct MOVDref {
uint32_t type;
char *path;
@@ -78,6 +84,7 @@ typedef struct MOVFragment {
unsigned duration;
unsigned size;
unsigned flags;
+ int64_t time;
} MOVFragment;
typedef struct MOVTrackExt {
@@ -93,8 +100,21 @@ typedef struct MOVSbgp {
unsigned int index;
} MOVSbgp;
+typedef struct MOVFragmentIndexItem {
+ int64_t moof_offset;
+ int64_t time;
+} MOVFragmentIndexItem;
+
+typedef struct MOVFragmentIndex {
+ unsigned track_id;
+ unsigned item_count;
+ unsigned current_item;
+ MOVFragmentIndexItem *items;
+} MOVFragmentIndex;
+
typedef struct MOVStreamContext {
AVIOContext *pb;
+ int pb_is_copied;
int ffindex; ///< AVStream index
int next_chunk;
unsigned int chunk_count;
@@ -107,16 +127,19 @@ typedef struct MOVStreamContext {
MOVStsc *stsc_data;
unsigned int stps_count;
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
+ MOVElst *elst_data;
+ unsigned int elst_count;
int ctts_index;
int ctts_sample;
- unsigned int sample_size;
+ unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
+ unsigned int stsz_sample_size; ///< always contains sample size from stsz atom
unsigned int sample_count;
int *sample_sizes;
int keyframe_absent;
unsigned int keyframe_count;
int *keyframes;
int time_scale;
- int64_t time_offset; ///< time offset of the first edit list entry
+ int64_t time_offset; ///< time offset of the edit list entries
int current_sample;
unsigned int bytes_per_frame;
unsigned int samples_per_frame;
@@ -126,6 +149,7 @@ typedef struct MOVStreamContext {
unsigned drefs_count;
MOVDref *drefs;
int dref_id;
+ int timecode_track;
int wrong_dts; ///< dts are wrong due to huge ctts offset (iMovie files)
int width; ///< tkhd width
int height; ///< tkhd height
@@ -133,10 +157,15 @@ typedef struct MOVStreamContext {
uint32_t palette[256];
int has_palette;
int64_t data_size;
+ uint32_t tmcd_flags; ///< tmcd track flags
int64_t track_end; ///< used for dts generation in fragmented movie files
+ int start_pad; ///< amount of samples to skip due to enc-dec delay
unsigned int rap_group_count;
MOVSbgp *rap_group;
+ int nb_frames_for_fps;
+ int64_t duration_for_fps;
+
int32_t *display_matrix;
} MOVStreamContext;
@@ -155,10 +184,20 @@ typedef struct MOVContext {
unsigned trex_count;
int itunes_metadata; ///< metadata are itunes style
int chapter_track;
+ int use_absolute_path;
+ int ignore_editlist;
int seek_individually;
int64_t next_root_atom; ///< offset of the next root atom
int export_all;
int export_xmp;
+ int *bitrates; ///< bitrates read before streams creation
+ int bitrates_count;
+ int moov_retry;
+ int use_mfra_for;
+ int has_looked_for_mfra;
+ MOVFragmentIndex** fragment_index_data;
+ unsigned fragment_index_count;
+ int atom_depth;
} MOVContext;
int ff_mp4_read_descr_len(AVIOContext *pb);
@@ -216,6 +255,7 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id);
(tag) == MKTAG('a', 'i', '1', '3') || \
(tag) == MKTAG('a', 'i', '1', '5') || \
(tag) == MKTAG('a', 'i', '1', '6') || \
+ (tag) == MKTAG('a', 'i', 'v', 'x') || \
(tag) == MKTAG('A', 'V', 'i', 'n'))
@@ -223,5 +263,10 @@ int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb);
enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags);
int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries);
+void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout);
+
+#define FF_MOV_FLAG_MFRA_AUTO -1
+#define FF_MOV_FLAG_MFRA_DTS 1
+#define FF_MOV_FLAG_MFRA_PTS 2
#endif /* AVFORMAT_ISOM_H */
diff --git a/libavformat/iss.c b/libavformat/iss.c
index c86b4250c8..fbde505a2d 100644
--- a/libavformat/iss.c
+++ b/libavformat/iss.c
@@ -2,20 +2,20 @@
* ISS (.iss) file demuxer
* Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -76,18 +76,32 @@ static av_cold int iss_read_header(AVFormatContext *s)
get_token(pb, token, sizeof(token)); //"IMA_ADPCM_Sound"
get_token(pb, token, sizeof(token)); //packet size
- sscanf(token, "%d", &iss->packet_size);
+ if (sscanf(token, "%d", &iss->packet_size) != 1) {
+ av_log(s, AV_LOG_ERROR, "Failed parsing packet size\n");
+ return AVERROR_INVALIDDATA;
+ }
get_token(pb, token, sizeof(token)); //File ID
get_token(pb, token, sizeof(token)); //out size
get_token(pb, token, sizeof(token)); //stereo
- sscanf(token, "%d", &stereo);
+ if (sscanf(token, "%d", &stereo) != 1) {
+ av_log(s, AV_LOG_ERROR, "Failed parsing stereo flag\n");
+ return AVERROR_INVALIDDATA;
+ }
get_token(pb, token, sizeof(token)); //Unknown1
get_token(pb, token, sizeof(token)); //RateDivisor
- sscanf(token, "%d", &rate_divisor);
+ if (sscanf(token, "%d", &rate_divisor) != 1) {
+ av_log(s, AV_LOG_ERROR, "Failed parsing rate_divisor\n");
+ return AVERROR_INVALIDDATA;
+ }
get_token(pb, token, sizeof(token)); //Unknown2
get_token(pb, token, sizeof(token)); //Version ID
get_token(pb, token, sizeof(token)); //Size
+ if (iss->packet_size <= 0) {
+ av_log(s, AV_LOG_ERROR, "packet_size %d is invalid\n", iss->packet_size);
+ return AVERROR_INVALIDDATA;
+ }
+
iss->sample_start_pos = avio_tell(pb);
st = avformat_new_stream(s, NULL);
diff --git a/libavformat/iv8.c b/libavformat/iv8.c
index 56909e3a22..38b79609f6 100644
--- a/libavformat/iv8.c
+++ b/libavformat/iv8.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c
index b3555f42a4..c0fdafbf02 100644
--- a/libavformat/ivfdec.c
+++ b/libavformat/ivfdec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c
index 3cd16166c7..1d76c5c7cb 100644
--- a/libavformat/ivfenc.c
+++ b/libavformat/ivfenc.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Reimar Döffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
@@ -30,14 +30,15 @@ static int ivf_write_header(AVFormatContext *s)
return AVERROR(EINVAL);
}
ctx = s->streams[0]->codec;
- if (ctx->codec_type != AVMEDIA_TYPE_VIDEO || ctx->codec_id != AV_CODEC_ID_VP8) {
- av_log(s, AV_LOG_ERROR, "Currently only VP8 is supported!\n");
+ if (ctx->codec_type != AVMEDIA_TYPE_VIDEO ||
+ !(ctx->codec_id == AV_CODEC_ID_VP8 || ctx->codec_id == AV_CODEC_ID_VP9)) {
+ av_log(s, AV_LOG_ERROR, "Currently only VP8 and VP9 are supported!\n");
return AVERROR(EINVAL);
}
avio_write(pb, "DKIF", 4);
avio_wl16(pb, 0); // version
avio_wl16(pb, 32); // header length
- avio_wl32(pb, ctx->codec_tag ? ctx->codec_tag : AV_RL32("VP80"));
+ avio_wl32(pb, ctx->codec_tag ? ctx->codec_tag : ctx->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") : AV_RL32("VP80"));
avio_wl16(pb, ctx->width);
avio_wl16(pb, ctx->height);
avio_wl32(pb, s->streams[0]->time_base.den);
diff --git a/libavformat/jacosubdec.c b/libavformat/jacosubdec.c
new file mode 100644
index 0000000000..1ca0055877
--- /dev/null
+++ b/libavformat/jacosubdec.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * JACOsub subtitle demuxer
+ * @see http://unicorn.us.com/jacosub/jscripts.html
+ * @todo Support P[ALETTE] directive.
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavcodec/internal.h"
+#include "libavcodec/jacosub.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+
+typedef struct {
+ int shift;
+ unsigned timeres;
+ FFDemuxSubtitlesQueue q;
+} JACOsubContext;
+
+static int timed_line(const char *ptr)
+{
+ char c;
+ int fs, fe;
+ return (sscanf(ptr, "%*u:%*u:%*u.%*u %*u:%*u:%*u.%*u %c", &c) == 1 ||
+ (sscanf(ptr, "@%u @%u %c", &fs, &fe, &c) == 3 && fs < fe));
+}
+
+static int jacosub_probe(AVProbeData *p)
+{
+ const char *ptr = p->buf;
+ const char *ptr_end = p->buf + p->buf_size;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+
+ while (ptr < ptr_end) {
+ while (jss_whitespace(*ptr))
+ ptr++;
+ if (*ptr != '#' && *ptr != '\n') {
+ if (timed_line(ptr))
+ return AVPROBE_SCORE_EXTENSION + 1;
+ return 0;
+ }
+ ptr += ff_subtitles_next_line(ptr);
+ }
+ return 0;
+}
+
+static const char * const cmds[] = {
+ "CLOCKPAUSE",
+ "DIRECTIVE",
+ "FONT",
+ "HRES",
+ "INCLUDE",
+ "PALETTE",
+ "QUANTIZE",
+ "RAMP",
+ "SHIFT",
+ "TIMERES",
+};
+
+static int get_jss_cmd(char k)
+{
+ int i;
+
+ k = av_toupper(k);
+ for (i = 0; i < FF_ARRAY_ELEMS(cmds); i++)
+ if (k == cmds[i][0])
+ return i;
+ return -1;
+}
+
+static int jacosub_read_close(AVFormatContext *s)
+{
+ JACOsubContext *jacosub = s->priv_data;
+ ff_subtitles_queue_clean(&jacosub->q);
+ return 0;
+}
+
+static const char *read_ts(JACOsubContext *jacosub, const char *buf,
+ int64_t *start, int *duration)
+{
+ int len;
+ unsigned hs, ms, ss, fs; // hours, minutes, seconds, frame start
+ unsigned he, me, se, fe; // hours, minutes, seconds, frame end
+ int ts_start, ts_end;
+
+ /* timed format */
+ if (sscanf(buf, "%u:%u:%u.%u %u:%u:%u.%u %n",
+ &hs, &ms, &ss, &fs,
+ &he, &me, &se, &fe, &len) == 8) {
+ ts_start = (hs*3600 + ms*60 + ss) * jacosub->timeres + fs;
+ ts_end = (he*3600 + me*60 + se) * jacosub->timeres + fe;
+ goto shift_and_ret;
+ }
+
+ /* timestamps format */
+ if (sscanf(buf, "@%u @%u %n", &ts_start, &ts_end, &len) == 2)
+ goto shift_and_ret;
+
+ return NULL;
+
+shift_and_ret:
+ ts_start = (ts_start + jacosub->shift) * 100 / jacosub->timeres;
+ ts_end = (ts_end + jacosub->shift) * 100 / jacosub->timeres;
+ *start = ts_start;
+ *duration = ts_start + ts_end;
+ return buf + len;
+}
+
+static int get_shift(int timeres, const char *buf)
+{
+ int sign = 1;
+ int a = 0, b = 0, c = 0, d = 0;
+#define SSEP "%*1[.:]"
+ int n = sscanf(buf, "%d"SSEP"%d"SSEP"%d"SSEP"%d", &a, &b, &c, &d);
+#undef SSEP
+
+ if (*buf == '-' || a < 0) {
+ sign = -1;
+ a = FFABS(a);
+ }
+
+ switch (n) {
+ case 4: return sign * ((a*3600 + b*60 + c) * timeres + d);
+ case 3: return sign * (( a*60 + b) * timeres + c);
+ case 2: return sign * (( a) * timeres + b);
+ }
+
+ return 0;
+}
+
+static int jacosub_read_header(AVFormatContext *s)
+{
+ AVBPrint header;
+ AVIOContext *pb = s->pb;
+ char line[JSS_MAX_LINESIZE];
+ JACOsubContext *jacosub = s->priv_data;
+ int shift_set = 0; // only the first shift matters
+ int merge_line = 0;
+ int i, ret;
+
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 100);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_JACOSUB;
+
+ jacosub->timeres = 30;
+
+ av_bprint_init(&header, 1024+FF_INPUT_BUFFER_PADDING_SIZE, 4096);
+
+ while (!avio_feof(pb)) {
+ int cmd_len;
+ const char *p = line;
+ int64_t pos = avio_tell(pb);
+ int len = ff_get_line(pb, line, sizeof(line));
+
+ p = jss_skip_whitespace(p);
+
+ /* queue timed line */
+ if (merge_line || timed_line(p)) {
+ AVPacket *sub;
+
+ sub = ff_subtitles_queue_insert(&jacosub->q, line, len, merge_line);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ merge_line = len > 1 && !strcmp(&line[len - 2], "\\\n");
+ continue;
+ }
+
+ /* skip all non-compiler commands and focus on the command */
+ if (*p != '#')
+ continue;
+ p++;
+ i = get_jss_cmd(p[0]);
+ if (i == -1)
+ continue;
+
+ /* trim command + spaces */
+ cmd_len = strlen(cmds[i]);
+ if (av_strncasecmp(p, cmds[i], cmd_len) == 0)
+ p += cmd_len;
+ else
+ p++;
+ p = jss_skip_whitespace(p);
+
+ /* handle commands which affect the whole script */
+ switch (cmds[i][0]) {
+ case 'S': // SHIFT command affect the whole script...
+ if (!shift_set) {
+ jacosub->shift = get_shift(jacosub->timeres, p);
+ shift_set = 1;
+ }
+ av_bprintf(&header, "#S %s", p);
+ break;
+ case 'T': // ...but must be placed after TIMERES
+ jacosub->timeres = strtol(p, NULL, 10);
+ if (!jacosub->timeres)
+ jacosub->timeres = 30;
+ else
+ av_bprintf(&header, "#T %s", p);
+ break;
+ }
+ }
+
+ /* general/essential directives in the extradata */
+ ret = avpriv_bprint_to_extradata(st->codec, &header);
+ if (ret < 0)
+ goto fail;
+
+ /* SHIFT and TIMERES affect the whole script so packet timing can only be
+ * done in a second pass */
+ for (i = 0; i < jacosub->q.nb_subs; i++) {
+ AVPacket *sub = &jacosub->q.subs[i];
+ read_ts(jacosub, sub->data, &sub->pts, &sub->duration);
+ }
+ ff_subtitles_queue_finalize(&jacosub->q);
+
+ return 0;
+fail:
+ jacosub_read_close(s);
+ return ret;
+}
+
+static int jacosub_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ JACOsubContext *jacosub = s->priv_data;
+ return ff_subtitles_queue_read_packet(&jacosub->q, pkt);
+}
+
+static int jacosub_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ JACOsubContext *jacosub = s->priv_data;
+ return ff_subtitles_queue_seek(&jacosub->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+AVInputFormat ff_jacosub_demuxer = {
+ .name = "jacosub",
+ .long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle format"),
+ .priv_data_size = sizeof(JACOsubContext),
+ .read_probe = jacosub_probe,
+ .read_header = jacosub_read_header,
+ .read_packet = jacosub_read_packet,
+ .read_seek2 = jacosub_read_seek,
+ .read_close = jacosub_read_close,
+};
diff --git a/libavformat/jacosubenc.c b/libavformat/jacosubenc.c
new file mode 100644
index 0000000000..a11e45a4aa
--- /dev/null
+++ b/libavformat/jacosubenc.c
@@ -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
+ */
+
+#include "avformat.h"
+#include "rawenc.h"
+
+static int jacosub_write_header(AVFormatContext *s)
+{
+ const AVCodecContext *avctx = s->streams[0]->codec;
+
+ if (avctx->extradata_size) {
+ avio_write(s->pb, avctx->extradata, avctx->extradata_size - 1);
+ avio_flush(s->pb);
+ }
+ return 0;
+}
+
+AVOutputFormat ff_jacosub_muxer = {
+ .name = "jacosub",
+ .long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle format"),
+ .mime_type = "text/x-jacosub",
+ .extensions = "jss,js",
+ .write_header = jacosub_write_header,
+ .write_packet = ff_raw_write_packet,
+ .flags = AVFMT_TS_NONSTRICT,
+ .subtitle_codec = AV_CODEC_ID_JACOSUB,
+};
diff --git a/libavformat/jvdec.c b/libavformat/jvdec.c
index 8aebbf4de8..64d31e0ee6 100644
--- a/libavformat/jvdec.c
+++ b/libavformat/jvdec.c
@@ -2,20 +2,20 @@
* Bitmap Brothers JV demuxer
* Copyright (c) 2005, 2011 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,10 +34,10 @@
#define JV_PREAMBLE_SIZE 5
typedef struct JVFrame {
- int audio_size; /** audio packet size (bytes) */
- int video_size; /** video packet size (bytes) */
- int palette_size; /** palette size (bytes) */
- int video_type; /** per-frame video compression type */
+ int audio_size; /**< audio packet size (bytes) */
+ int video_size; /**< video packet size (bytes) */
+ int palette_size; /**< palette size (bytes) */
+ int video_type; /**< per-frame video compression type */
} JVFrame;
typedef struct JVDemuxContext {
@@ -54,8 +54,8 @@ typedef struct JVDemuxContext {
static int read_probe(AVProbeData *pd)
{
- if (pd->buf[0] == 'J' && pd->buf[1] == 'V' &&
- !memcmp(pd->buf + 4, MAGIC, FFMIN(strlen(MAGIC), pd->buf_size - 4)))
+ if (pd->buf[0] == 'J' && pd->buf[1] == 'V' && strlen(MAGIC) <= pd->buf_size - 4 &&
+ !memcmp(pd->buf + 4, MAGIC, strlen(MAGIC)))
return AVPROBE_SCORE_MAX;
return 0;
}
@@ -166,7 +166,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
AVStream *ast = s->streams[0];
- while (!s->pb->eof_reached && jv->pts < ast->nb_index_entries) {
+ while (!avio_feof(s->pb) && jv->pts < ast->nb_index_entries) {
const AVIndexEntry *e = ast->index_entries + jv->pts;
const JVFrame *jvf = jv->frames + jv->pts;
diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c
index 5190ac7b20..17dbf33b72 100644
--- a/libavformat/latmenc.c
+++ b/libavformat/latmenc.c
@@ -2,20 +2,20 @@
* LATM/LOAS muxer
* Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,9 @@
#include "libavcodec/mpeg4audio.h"
#include "libavutil/opt.h"
#include "avformat.h"
+#include "rawenc.h"
+
+#define MAX_EXTRADATA_SIZE 1024
typedef struct LATMContext {
AVClass *av_class;
@@ -33,6 +36,7 @@ typedef struct LATMContext {
int object_type;
int counter;
int mod;
+ uint8_t buffer[0x1fff + MAX_EXTRADATA_SIZE + 1024];
} LATMContext;
static const AVOption options[] = {
@@ -50,15 +54,21 @@ static const AVClass latm_muxer_class = {
static int latm_decode_extradata(LATMContext *ctx, uint8_t *buf, int size)
{
- GetBitContext gb;
MPEG4AudioConfig m4ac;
- init_get_bits(&gb, buf, size * 8);
+ if (size > MAX_EXTRADATA_SIZE) {
+ av_log(ctx, AV_LOG_ERROR, "Extradata is larger than currently supported.\n");
+ return AVERROR_INVALIDDATA;
+ }
ctx->off = avpriv_mpeg4audio_get_config(&m4ac, buf, size * 8, 1);
if (ctx->off < 0)
return ctx->off;
- skip_bits_long(&gb, ctx->off);
+ if (ctx->object_type == AOT_ALS && (ctx->off & 7)) {
+ // as long as avpriv_mpeg4audio_get_config works correctly this is impossible
+ av_log(ctx, AV_LOG_ERROR, "BUG: ALS offset is not byte-aligned\n");
+ return AVERROR_INVALIDDATA;
+ }
/* FIXME: are any formats not allowed in LATM? */
if (m4ac.object_type > AOT_SBR && m4ac.object_type != AOT_ALS) {
@@ -76,6 +86,9 @@ static int latm_write_header(AVFormatContext *s)
LATMContext *ctx = s->priv_data;
AVCodecContext *avctx = s->streams[0]->codec;
+ if (avctx->codec_id == AV_CODEC_ID_AAC_LATM)
+ return 0;
+
if (avctx->extradata_size > 0 &&
latm_decode_extradata(ctx, avctx->extradata, avctx->extradata_size) < 0)
return AVERROR_INVALIDDATA;
@@ -83,19 +96,16 @@ static int latm_write_header(AVFormatContext *s)
return 0;
}
-static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
+static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
{
LATMContext *ctx = s->priv_data;
AVCodecContext *avctx = s->streams[0]->codec;
- GetBitContext gb;
int header_size;
/* AudioMuxElement */
put_bits(bs, 1, !!ctx->counter);
if (!ctx->counter) {
- init_get_bits(&gb, avctx->extradata, avctx->extradata_size * 8);
-
/* StreamMuxConfig */
put_bits(bs, 1, 0); /* audioMuxVersion */
put_bits(bs, 1, 1); /* allStreamsSameTimeFraming */
@@ -105,12 +115,17 @@ static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
/* AudioSpecificConfig */
if (ctx->object_type == AOT_ALS) {
- header_size = avctx->extradata_size-(ctx->off + 7) >> 3;
- avpriv_copy_bits(bs, &avctx->extradata[ctx->off], header_size);
+ header_size = avctx->extradata_size-(ctx->off >> 3);
+ avpriv_copy_bits(bs, &avctx->extradata[ctx->off >> 3], header_size);
} else {
+ // + 3 assumes not scalable and dependsOnCoreCoder == 0,
+ // see decode_ga_specific_config in libavcodec/aacdec.c
avpriv_copy_bits(bs, avctx->extradata, ctx->off + 3);
if (!ctx->channel_conf) {
+ GetBitContext gb;
+ init_get_bits8(&gb, avctx->extradata, avctx->extradata_size);
+ skip_bits_long(&gb, ctx->off + 3);
avpriv_copy_pce_data(bs, &gb);
}
}
@@ -124,28 +139,36 @@ static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
ctx->counter++;
ctx->counter %= ctx->mod;
-
- return 0;
}
static int latm_write_packet(AVFormatContext *s, AVPacket *pkt)
{
+ LATMContext *ctx = s->priv_data;
AVIOContext *pb = s->pb;
PutBitContext bs;
int i, len;
uint8_t loas_header[] = "\x56\xe0\x00";
- uint8_t *buf;
+
+ if (s->streams[0]->codec->codec_id == AV_CODEC_ID_AAC_LATM)
+ return ff_raw_write_packet(s, pkt);
if (pkt->size > 2 && pkt->data[0] == 0xff && (pkt->data[1] >> 4) == 0xf) {
av_log(s, AV_LOG_ERROR, "ADTS header detected - ADTS will not be incorrectly muxed into LATM\n");
return AVERROR_INVALIDDATA;
}
- buf = av_malloc(pkt->size+1024);
- if (!buf)
- return AVERROR(ENOMEM);
+ if (!s->streams[0]->codec->extradata) {
+ if(pkt->size > 2 && pkt->data[0] == 0x56 && (pkt->data[1] >> 4) == 0xe &&
+ (AV_RB16(pkt->data + 1) & 0x1FFF) + 3 == pkt->size)
+ return ff_raw_write_packet(s, pkt);
+ else
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (pkt->size > 0x1fff)
+ goto too_large;
- init_put_bits(&bs, buf, pkt->size+1024);
+ init_put_bits(&bs, ctx->buffer, pkt->size+1024+MAX_EXTRADATA_SIZE);
latm_write_frame_header(s, &bs);
@@ -158,30 +181,46 @@ static int latm_write_packet(AVFormatContext *s, AVPacket *pkt)
/* The LATM payload is written unaligned */
/* PayloadMux() */
- for (i = 0; i < pkt->size; i++)
- put_bits(&bs, 8, pkt->data[i]);
+ if (pkt->size && (pkt->data[0] & 0xe1) == 0x81) {
+ // Convert byte-aligned DSE to non-aligned.
+ // Due to the input format encoding we know that
+ // it is naturally byte-aligned in the input stream,
+ // so there are no padding bits to account for.
+ // To avoid having to add padding bits and rearrange
+ // the whole stream we just remove the byte-align flag.
+ // This allows us to remux our FATE AAC samples into latm
+ // files that are still playable with minimal effort.
+ put_bits(&bs, 8, pkt->data[0] & 0xfe);
+ avpriv_copy_bits(&bs, pkt->data + 1, 8*pkt->size - 8);
+ } else
+ avpriv_copy_bits(&bs, pkt->data, 8*pkt->size);
avpriv_align_put_bits(&bs);
flush_put_bits(&bs);
len = put_bits_count(&bs) >> 3;
+ if (len > 0x1fff)
+ goto too_large;
+
loas_header[1] |= (len >> 8) & 0x1f;
loas_header[2] |= len & 0xff;
avio_write(pb, loas_header, 3);
- avio_write(pb, buf, len);
-
- av_free(buf);
+ avio_write(pb, ctx->buffer, len);
return 0;
+
+too_large:
+ av_log(s, AV_LOG_ERROR, "LATM packet size larger than maximum size 0x1fff\n");
+ return AVERROR_INVALIDDATA;
}
AVOutputFormat ff_latm_muxer = {
.name = "latm",
.long_name = NULL_IF_CONFIG_SMALL("LOAS/LATM"),
.mime_type = "audio/MP4A-LATM",
- .extensions = "latm",
+ .extensions = "latm,loas",
.priv_data_size = sizeof(LATMContext),
.audio_codec = AV_CODEC_ID_AAC,
.video_codec = AV_CODEC_ID_NONE,
diff --git a/libavformat/libavformat.v b/libavformat/libavformat.v
index 6f11d600b9..e90aef79ff 100644
--- a/libavformat/libavformat.v
+++ b/libavformat/libavformat.v
@@ -1,4 +1,20 @@
LIBAVFORMAT_$MAJOR {
global: av*;
+ #FIXME those are for ffserver
+ ff_inet_aton;
+ ff_socket_nonblock;
+ ff_rtsp_parse_line;
+ ff_rtp_get_local_rtp_port;
+ ff_rtp_get_local_rtcp_port;
+ ffio_open_dyn_packet_buf;
+ ffio_set_buf_size;
+ ffurl_close;
+ ffurl_open;
+ ffurl_read_complete;
+ ffurl_seek;
+ ffurl_size;
+ ffurl_write;
+ #those are deprecated, remove on next bump
+ url_feof;
local: *;
};
diff --git a/libavformat/libgme.c b/libavformat/libgme.c
new file mode 100644
index 0000000000..276477b308
--- /dev/null
+++ b/libavformat/libgme.c
@@ -0,0 +1,201 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+* libgme demuxer
+*/
+
+#include <gme/gme.h>
+#include "libavutil/avstring.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct GMEContext {
+ const AVClass *class;
+ Music_Emu *music_emu;
+ gme_info_t *info; ///< selected track
+
+ /* options */
+ int track_index;
+ int sample_rate;
+ int64_t max_size;
+} GMEContext;
+
+#define OFFSET(x) offsetof(GMEContext, x)
+#define A AV_OPT_FLAG_AUDIO_PARAM
+#define D AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ {"track_index", "set track that should be played", OFFSET(track_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, A|D},
+ {"sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 44100}, 1000, 999999, A|D},
+ {"max_size", "set max file size supported (in bytes)", OFFSET(max_size), AV_OPT_TYPE_INT64, {.i64 = 50 * 1024 * 1024}, 0, SIZE_MAX, A|D},
+ {NULL}
+};
+
+static void add_meta(AVFormatContext *s, const char *name, const char *value)
+{
+ if (value && value[0])
+ av_dict_set(&s->metadata, name, value, 0);
+}
+
+static int load_metadata(AVFormatContext *s)
+{
+ GMEContext *gme = s->priv_data;
+ gme_info_t *info = gme->info;
+ char buf[30];
+
+ add_meta(s, "system", info->system);
+ add_meta(s, "game", info->game);
+ add_meta(s, "song", info->song);
+ add_meta(s, "author", info->author);
+ add_meta(s, "copyright", info->copyright);
+ add_meta(s, "comment", info->comment);
+ add_meta(s, "dumper", info->dumper);
+
+ snprintf(buf, sizeof(buf), "%d", (int)gme_track_count(gme->music_emu));
+ add_meta(s, "tracks", buf);
+
+ return 0;
+}
+
+#define AUDIO_PKT_SIZE 512
+
+static int read_header_gme(AVFormatContext *s)
+{
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ GMEContext *gme = s->priv_data;
+ int64_t sz = avio_size(pb);
+ char *buf;
+ char dummy;
+
+ if (sz < 0) {
+ av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
+ sz = gme->max_size;
+ } else if (gme->max_size && sz > gme->max_size) {
+ sz = gme->max_size;
+ }
+
+ buf = av_malloc(sz);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ sz = avio_read(pb, buf, sz);
+
+ // Data left means our buffer (the max_size option) is too small
+ if (avio_read(pb, &dummy, 1) == 1) {
+ av_log(s, AV_LOG_ERROR, "File size is larger than max_size option "
+ "value %"PRIi64", consider increasing the max_size option\n",
+ gme->max_size);
+ return AVERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (gme_open_data(buf, sz, &gme->music_emu, gme->sample_rate)) {
+ av_freep(&buf);
+ return AVERROR_INVALIDDATA;
+ }
+ av_freep(&buf);
+
+ if (gme_track_info(gme->music_emu, &gme->info, gme->track_index))
+ return AVERROR_STREAM_NOT_FOUND;
+
+ if (gme_start_track(gme->music_emu, gme->track_index))
+ return AVERROR_UNKNOWN;
+
+ load_metadata(s);
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ if (st->duration > 0)
+ st->duration = gme->info->length;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE);
+ st->codec->channels = 2;
+ st->codec->sample_rate = gme->sample_rate;
+
+ return 0;
+}
+
+static int read_packet_gme(AVFormatContext *s, AVPacket *pkt)
+{
+ GMEContext *gme = s->priv_data;
+ int n_samples = AUDIO_PKT_SIZE / 2;
+ int ret;
+
+ if (gme_track_ended(gme->music_emu))
+ return AVERROR_EOF;
+
+ if ((ret = av_new_packet(pkt, AUDIO_PKT_SIZE)) < 0)
+ return ret;
+
+ if (gme_play(gme->music_emu, n_samples, (short *)pkt->data))
+ return AVERROR_EXTERNAL;
+ pkt->size = AUDIO_PKT_SIZE;
+
+ return 0;
+}
+
+static int read_close_gme(AVFormatContext *s)
+{
+ GMEContext *gme = s->priv_data;
+ gme_free_info(gme->info);
+ gme_delete(gme->music_emu);
+ return 0;
+}
+
+static int read_seek_gme(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
+{
+ GMEContext *gme = s->priv_data;
+ if (!gme_seek(gme->music_emu, (int)ts))
+ return AVERROR_EXTERNAL;
+ return 0;
+}
+
+static int probe_gme(AVProbeData *p)
+{
+ // Reads 4 bytes - returns "" if unknown format.
+ if (gme_identify_header(p->buf)[0]) {
+ if (p->buf_size < 16384)
+ return AVPROBE_SCORE_MAX / 4 ;
+ else
+ return AVPROBE_SCORE_MAX / 2;
+ }
+ return 0;
+}
+
+static const AVClass class_gme = {
+ .class_name = "Game Music Emu demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_libgme_demuxer = {
+ .name = "libgme",
+ .long_name = NULL_IF_CONFIG_SMALL("Game Music Emu demuxer"),
+ .priv_data_size = sizeof(GMEContext),
+ .read_probe = probe_gme,
+ .read_header = read_header_gme,
+ .read_packet = read_packet_gme,
+ .read_close = read_close_gme,
+ .read_seek = read_seek_gme,
+ .priv_class = &class_gme,
+};
diff --git a/libavformat/libmodplug.c b/libavformat/libmodplug.c
new file mode 100644
index 0000000000..158a63039f
--- /dev/null
+++ b/libavformat/libmodplug.c
@@ -0,0 +1,382 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+* ModPlug demuxer
+* @todo better probing than extensions matching
+*/
+
+#define MODPLUG_STATIC
+#include <libmodplug/modplug.h>
+#include "libavutil/avstring.h"
+#include "libavutil/eval.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct ModPlugContext {
+ const AVClass *class;
+ ModPlugFile *f;
+ uint8_t *buf; ///< input file content
+
+ /* options */
+ int noise_reduction;
+ int reverb_depth;
+ int reverb_delay;
+ int bass_amount;
+ int bass_range;
+ int surround_depth;
+ int surround_delay;
+
+ int max_size; ///< max file size to allocate
+
+ /* optional video stream */
+ double ts_per_packet; ///< used to define the pts/dts using packet_count;
+ int packet_count; ///< total number of audio packets
+ int print_textinfo; ///< bool flag for printing speed, tempo, order, ...
+ int video_stream; ///< 1 if the user want a video stream, otherwise 0
+ int w; ///< video stream width in char (one char = 8x8px)
+ int h; ///< video stream height in char (one char = 8x8px)
+ int video_switch; ///< 1 if current packet is video, otherwise 0
+ int fsize; ///< constant frame size
+ int linesize; ///< line size in bytes
+ char *color_eval; ///< color eval user input expression
+ AVExpr *expr; ///< parsed color eval expression
+} ModPlugContext;
+
+static const char * const var_names[] = {
+ "x", "y",
+ "w", "h",
+ "t",
+ "speed", "tempo", "order", "pattern", "row",
+ NULL
+};
+
+enum var_name {
+ VAR_X, VAR_Y,
+ VAR_W, VAR_H,
+ VAR_TIME,
+ VAR_SPEED, VAR_TEMPO, VAR_ORDER, VAR_PATTERN, VAR_ROW,
+ VAR_VARS_NB
+};
+
+#define FF_MODPLUG_MAX_FILE_SIZE (100 * 1<<20) // 100M
+#define FF_MODPLUG_DEF_FILE_SIZE ( 5 * 1<<20) // 5M
+
+#define OFFSET(x) offsetof(ModPlugContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+static const AVOption options[] = {
+ {"noise_reduction", "Enable noise reduction 0(off)-1(on)", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D},
+ {"reverb_depth", "Reverb level 0(quiet)-100(loud)", OFFSET(reverb_depth), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
+ {"reverb_delay", "Reverb delay in ms, usually 40-200ms", OFFSET(reverb_delay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D},
+ {"bass_amount", "XBass level 0(quiet)-100(loud)", OFFSET(bass_amount), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
+ {"bass_range", "XBass cutoff in Hz 10-100", OFFSET(bass_range), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
+ {"surround_depth", "Surround level 0(quiet)-100(heavy)", OFFSET(surround_depth), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, D},
+ {"surround_delay", "Surround delay in ms, usually 5-40ms", OFFSET(surround_delay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D},
+ {"max_size", "Max file size supported (in bytes). Default is 5MB. Set to 0 for no limit (not recommended)",
+ OFFSET(max_size), AV_OPT_TYPE_INT, {.i64 = FF_MODPLUG_DEF_FILE_SIZE}, 0, FF_MODPLUG_MAX_FILE_SIZE, D},
+ {"video_stream_expr", "Color formula", OFFSET(color_eval), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, D},
+ {"video_stream", "Make demuxer output a video stream", OFFSET(video_stream), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D},
+ {"video_stream_w", "Video stream width in char (one char = 8x8px)", OFFSET(w), AV_OPT_TYPE_INT, {.i64 = 30}, 20, 512, D},
+ {"video_stream_h", "Video stream height in char (one char = 8x8px)", OFFSET(h), AV_OPT_TYPE_INT, {.i64 = 30}, 20, 512, D},
+ {"video_stream_ptxt", "Print speed, tempo, order, ... in video stream", OFFSET(print_textinfo), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D},
+ {NULL},
+};
+
+#define SET_OPT_IF_REQUESTED(libopt, opt, flag) do { \
+ if (modplug->opt) { \
+ settings.libopt = modplug->opt; \
+ settings.mFlags |= flag; \
+ } \
+} while (0)
+
+#define ADD_META_MULTIPLE_ENTRIES(entry_name, fname) do { \
+ if (n_## entry_name ##s) { \
+ unsigned i, n = 0; \
+ \
+ for (i = 0; i < n_## entry_name ##s; i++) { \
+ char item_name[64] = {0}; \
+ fname(f, i, item_name); \
+ if (!*item_name) \
+ continue; \
+ if (n) \
+ av_dict_set(&s->metadata, #entry_name, "\n", AV_DICT_APPEND); \
+ av_dict_set(&s->metadata, #entry_name, item_name, AV_DICT_APPEND); \
+ n++; \
+ } \
+ \
+ extra = av_asprintf(", %u/%u " #entry_name "%s", \
+ n, n_## entry_name ##s, n > 1 ? "s" : ""); \
+ if (!extra) \
+ return AVERROR(ENOMEM); \
+ av_dict_set(&s->metadata, "extra info", extra, AV_DICT_APPEND); \
+ av_free(extra); \
+ } \
+} while (0)
+
+static int modplug_load_metadata(AVFormatContext *s)
+{
+ ModPlugContext *modplug = s->priv_data;
+ ModPlugFile *f = modplug->f;
+ char *extra;
+ const char *name = ModPlug_GetName(f);
+ const char *msg = ModPlug_GetMessage(f);
+
+ unsigned n_instruments = ModPlug_NumInstruments(f);
+ unsigned n_samples = ModPlug_NumSamples(f);
+ unsigned n_patterns = ModPlug_NumPatterns(f);
+ unsigned n_channels = ModPlug_NumChannels(f);
+
+ if (name && *name) av_dict_set(&s->metadata, "name", name, 0);
+ if (msg && *msg) av_dict_set(&s->metadata, "message", msg, 0);
+
+ extra = av_asprintf("%u pattern%s, %u channel%s",
+ n_patterns, n_patterns > 1 ? "s" : "",
+ n_channels, n_channels > 1 ? "s" : "");
+ if (!extra)
+ return AVERROR(ENOMEM);
+ av_dict_set(&s->metadata, "extra info", extra, AV_DICT_DONT_STRDUP_VAL);
+
+ ADD_META_MULTIPLE_ENTRIES(instrument, ModPlug_InstrumentName);
+ ADD_META_MULTIPLE_ENTRIES(sample, ModPlug_SampleName);
+
+ return 0;
+}
+
+#define AUDIO_PKT_SIZE 512
+
+static int modplug_read_header(AVFormatContext *s)
+{
+ AVStream *st;
+ AVIOContext *pb = s->pb;
+ ModPlug_Settings settings;
+ ModPlugContext *modplug = s->priv_data;
+ int64_t sz = avio_size(pb);
+
+ if (sz < 0) {
+ av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
+ sz = modplug->max_size;
+ } else if (modplug->max_size && sz > modplug->max_size) {
+ sz = modplug->max_size;
+ av_log(s, AV_LOG_WARNING, "Max file size reach%s, allocating %"PRIi64"B "
+ "but demuxing is likely to fail due to incomplete buffer\n",
+ sz == FF_MODPLUG_DEF_FILE_SIZE ? " (see -max_size)" : "", sz);
+ }
+
+ if (modplug->color_eval) {
+ int r = av_expr_parse(&modplug->expr, modplug->color_eval, var_names,
+ NULL, NULL, NULL, NULL, 0, s);
+ if (r < 0)
+ return r;
+ }
+
+ modplug->buf = av_malloc(modplug->max_size);
+ if (!modplug->buf)
+ return AVERROR(ENOMEM);
+ sz = avio_read(pb, modplug->buf, sz);
+
+ ModPlug_GetSettings(&settings);
+ settings.mChannels = 2;
+ settings.mBits = 16;
+ settings.mFrequency = 44100;
+ settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; // best quality
+ settings.mLoopCount = 0; // prevents looping forever
+
+ if (modplug->noise_reduction) settings.mFlags |= MODPLUG_ENABLE_NOISE_REDUCTION;
+ SET_OPT_IF_REQUESTED(mReverbDepth, reverb_depth, MODPLUG_ENABLE_REVERB);
+ SET_OPT_IF_REQUESTED(mReverbDelay, reverb_delay, MODPLUG_ENABLE_REVERB);
+ SET_OPT_IF_REQUESTED(mBassAmount, bass_amount, MODPLUG_ENABLE_MEGABASS);
+ SET_OPT_IF_REQUESTED(mBassRange, bass_range, MODPLUG_ENABLE_MEGABASS);
+ SET_OPT_IF_REQUESTED(mSurroundDepth, surround_depth, MODPLUG_ENABLE_SURROUND);
+ SET_OPT_IF_REQUESTED(mSurroundDelay, surround_delay, MODPLUG_ENABLE_SURROUND);
+
+ if (modplug->reverb_depth) settings.mReverbDepth = modplug->reverb_depth;
+ if (modplug->reverb_delay) settings.mReverbDelay = modplug->reverb_delay;
+ if (modplug->bass_amount) settings.mBassAmount = modplug->bass_amount;
+ if (modplug->bass_range) settings.mBassRange = modplug->bass_range;
+ if (modplug->surround_depth) settings.mSurroundDepth = modplug->surround_depth;
+ if (modplug->surround_delay) settings.mSurroundDelay = modplug->surround_delay;
+
+ ModPlug_SetSettings(&settings);
+
+ modplug->f = ModPlug_Load(modplug->buf, sz);
+ if (!modplug->f)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ st->duration = ModPlug_GetLength(modplug->f);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+ st->codec->channels = settings.mChannels;
+ st->codec->sample_rate = settings.mFrequency;
+
+ // timebase = 1/1000, 2ch 16bits 44.1kHz-> 2*2*44100
+ modplug->ts_per_packet = 1000*AUDIO_PKT_SIZE / (4*44100.);
+
+ if (modplug->video_stream) {
+ AVStream *vst = avformat_new_stream(s, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(vst, 64, 1, 1000);
+ vst->duration = st->duration;
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = AV_CODEC_ID_XBIN;
+ vst->codec->width = modplug->w << 3;
+ vst->codec->height = modplug->h << 3;
+ modplug->linesize = modplug->w * 3;
+ modplug->fsize = modplug->linesize * modplug->h;
+ }
+
+ return modplug_load_metadata(s);
+}
+
+static void write_text(uint8_t *dst, const char *s, int linesize, int x, int y)
+{
+ int i;
+ dst += y*linesize + x*3;
+ for (i = 0; s[i]; i++, dst += 3) {
+ dst[0] = 0x0; // count - 1
+ dst[1] = s[i]; // char
+ dst[2] = 0x0f; // background / foreground
+ }
+}
+
+#define PRINT_INFO(line, name, idvalue) do { \
+ snprintf(intbuf, sizeof(intbuf), "%.0f", var_values[idvalue]); \
+ write_text(pkt->data, name ":", modplug->linesize, 0+1, line+1); \
+ write_text(pkt->data, intbuf, modplug->linesize, 10+1, line+1); \
+} while (0)
+
+static int modplug_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ ModPlugContext *modplug = s->priv_data;
+
+ if (modplug->video_stream) {
+ modplug->video_switch ^= 1; // one video packet for one audio packet
+ if (modplug->video_switch) {
+ double var_values[VAR_VARS_NB];
+
+ var_values[VAR_W ] = modplug->w;
+ var_values[VAR_H ] = modplug->h;
+ var_values[VAR_TIME ] = modplug->packet_count * modplug->ts_per_packet;
+ var_values[VAR_SPEED ] = ModPlug_GetCurrentSpeed (modplug->f);
+ var_values[VAR_TEMPO ] = ModPlug_GetCurrentTempo (modplug->f);
+ var_values[VAR_ORDER ] = ModPlug_GetCurrentOrder (modplug->f);
+ var_values[VAR_PATTERN] = ModPlug_GetCurrentPattern(modplug->f);
+ var_values[VAR_ROW ] = ModPlug_GetCurrentRow (modplug->f);
+
+ if (av_new_packet(pkt, modplug->fsize) < 0)
+ return AVERROR(ENOMEM);
+ pkt->stream_index = 1;
+ memset(pkt->data, 0, modplug->fsize);
+
+ if (modplug->print_textinfo) {
+ char intbuf[32];
+ PRINT_INFO(0, "speed", VAR_SPEED);
+ PRINT_INFO(1, "tempo", VAR_TEMPO);
+ PRINT_INFO(2, "order", VAR_ORDER);
+ PRINT_INFO(3, "pattern", VAR_PATTERN);
+ PRINT_INFO(4, "row", VAR_ROW);
+ PRINT_INFO(5, "ts", VAR_TIME);
+ }
+
+ if (modplug->expr) {
+ int x, y;
+ for (y = 0; y < modplug->h; y++) {
+ for (x = 0; x < modplug->w; x++) {
+ double color;
+ var_values[VAR_X] = x;
+ var_values[VAR_Y] = y;
+ color = av_expr_eval(modplug->expr, var_values, NULL);
+ pkt->data[y*modplug->linesize + x*3 + 2] |= av_clip((int)color, 0, 0xf)<<4;
+ }
+ }
+ }
+ pkt->pts = pkt->dts = var_values[VAR_TIME];
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ return 0;
+ }
+ }
+
+ if (av_new_packet(pkt, AUDIO_PKT_SIZE) < 0)
+ return AVERROR(ENOMEM);
+
+ if (modplug->video_stream)
+ pkt->pts = pkt->dts = modplug->packet_count++ * modplug->ts_per_packet;
+
+ pkt->size = ModPlug_Read(modplug->f, pkt->data, AUDIO_PKT_SIZE);
+ if (pkt->size <= 0) {
+ av_free_packet(pkt);
+ return pkt->size == 0 ? AVERROR_EOF : AVERROR(EIO);
+ }
+ return 0;
+}
+
+static int modplug_read_close(AVFormatContext *s)
+{
+ ModPlugContext *modplug = s->priv_data;
+ ModPlug_Unload(modplug->f);
+ av_freep(&modplug->buf);
+ return 0;
+}
+
+static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
+{
+ ModPlugContext *modplug = s->priv_data;
+ ModPlug_Seek(modplug->f, (int)ts);
+ if (modplug->video_stream)
+ modplug->packet_count = ts / modplug->ts_per_packet;
+ return 0;
+}
+
+static const char modplug_extensions[] = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm,itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz";
+
+static int modplug_probe(AVProbeData *p)
+{
+ if (av_match_ext(p->filename, modplug_extensions)) {
+ if (p->buf_size < 16384)
+ return AVPROBE_SCORE_EXTENSION/2-1;
+ else
+ return AVPROBE_SCORE_EXTENSION;
+ }
+ return 0;
+}
+
+static const AVClass modplug_class = {
+ .class_name = "ModPlug demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_libmodplug_demuxer = {
+ .name = "libmodplug",
+ .long_name = NULL_IF_CONFIG_SMALL("ModPlug demuxer"),
+ .priv_data_size = sizeof(ModPlugContext),
+ .read_probe = modplug_probe,
+ .read_header = modplug_read_header,
+ .read_packet = modplug_read_packet,
+ .read_close = modplug_read_close,
+ .read_seek = modplug_read_seek,
+ .extensions = modplug_extensions,
+ .priv_class = &modplug_class,
+};
diff --git a/libavformat/libnut.c b/libavformat/libnut.c
new file mode 100644
index 0000000000..4a9a21a766
--- /dev/null
+++ b/libavformat/libnut.c
@@ -0,0 +1,324 @@
+/*
+ * NUT (de)muxing via libnut
+ * copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * NUT demuxing and muxing via libnut.
+ * @author Oded Shimon <ods15@ods15.dyndns.org>
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "riff.h"
+#include <libnut.h>
+
+#define ID_STRING "nut/multimedia container"
+#define ID_LENGTH (strlen(ID_STRING) + 1)
+
+typedef struct {
+ nut_context_tt * nut;
+ nut_stream_header_tt * s;
+} NUTContext;
+
+static const AVCodecTag nut_tags[] = {
+ { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
+ { AV_CODEC_ID_MP3, MKTAG('m', 'p', '3', ' ') },
+ { AV_CODEC_ID_VORBIS, MKTAG('v', 'r', 'b', 's') },
+ { 0, 0 },
+};
+
+#if CONFIG_LIBNUT_MUXER
+static int av_write(void * h, size_t len, const uint8_t * buf) {
+ AVIOContext * bc = h;
+ avio_write(bc, buf, len);
+ //avio_flush(bc);
+ return len;
+}
+
+static int nut_write_header(AVFormatContext * avf) {
+ NUTContext * priv = avf->priv_data;
+ AVIOContext * bc = avf->pb;
+ nut_muxer_opts_tt mopts = {
+ .output = {
+ .priv = bc,
+ .write = av_write,
+ },
+ .alloc = { av_malloc, av_realloc, av_free },
+ .write_index = 1,
+ .realtime_stream = 0,
+ .max_distance = 32768,
+ .fti = NULL,
+ };
+ nut_stream_header_tt * s;
+ int i;
+
+ priv->s = s = av_mallocz_array(avf->nb_streams + 1, sizeof*s);
+ if(!s)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < avf->nb_streams; i++) {
+ AVCodecContext * codec = avf->streams[i]->codec;
+ int j;
+ int fourcc = 0;
+ int num, denom, ssize;
+
+ s[i].type = codec->codec_type == AVMEDIA_TYPE_VIDEO ? NUT_VIDEO_CLASS : NUT_AUDIO_CLASS;
+
+ if (codec->codec_tag) fourcc = codec->codec_tag;
+ else fourcc = ff_codec_get_tag(nut_tags, codec->codec_id);
+
+ if (!fourcc) {
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO) fourcc = ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id);
+ if (codec->codec_type == AVMEDIA_TYPE_AUDIO) fourcc = ff_codec_get_tag(ff_codec_wav_tags, codec->codec_id);
+ }
+
+ s[i].fourcc_len = 4;
+ s[i].fourcc = av_malloc(s[i].fourcc_len);
+ for (j = 0; j < s[i].fourcc_len; j++) s[i].fourcc[j] = (fourcc >> (j*8)) & 0xFF;
+
+ ff_parse_specific_params(codec, &num, &ssize, &denom);
+ avpriv_set_pts_info(avf->streams[i], 60, denom, num);
+
+ s[i].time_base.num = denom;
+ s[i].time_base.den = num;
+
+ s[i].fixed_fps = 0;
+ s[i].decode_delay = codec->has_b_frames;
+ s[i].codec_specific_len = codec->extradata_size;
+ s[i].codec_specific = codec->extradata;
+
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ s[i].width = codec->width;
+ s[i].height = codec->height;
+ s[i].sample_width = 0;
+ s[i].sample_height = 0;
+ s[i].colorspace_type = 0;
+ } else {
+ s[i].samplerate_num = codec->sample_rate;
+ s[i].samplerate_denom = 1;
+ s[i].channel_count = codec->channels;
+ }
+ }
+
+ s[avf->nb_streams].type = -1;
+ priv->nut = nut_muxer_init(&mopts, s, NULL);
+
+ return 0;
+}
+
+static int nut_write_packet(AVFormatContext * avf, AVPacket * pkt) {
+ NUTContext * priv = avf->priv_data;
+ nut_packet_tt p;
+
+ p.len = pkt->size;
+ p.stream = pkt->stream_index;
+ p.pts = pkt->pts;
+ p.flags = pkt->flags & AV_PKT_FLAG_KEY ? NUT_FLAG_KEY : 0;
+ p.next_pts = 0;
+
+ nut_write_frame_reorder(priv->nut, &p, pkt->data);
+
+ return 0;
+}
+
+static int nut_write_trailer(AVFormatContext * avf) {
+ AVIOContext * bc = avf->pb;
+ NUTContext * priv = avf->priv_data;
+ int i;
+
+ nut_muxer_uninit_reorder(priv->nut);
+ avio_flush(bc);
+
+ for(i = 0; priv->s[i].type != -1; i++ ) av_freep(&priv->s[i].fourcc);
+ av_freep(&priv->s);
+
+ return 0;
+}
+
+AVOutputFormat ff_libnut_muxer = {
+ .name = "libnut",
+ .long_name = "nut format",
+ .mime_type = "video/x-nut",
+ .extensions = "nut",
+ .priv_data_size = sizeof(NUTContext),
+ .audio_codec = AV_CODEC_ID_VORBIS,
+ .video_codec = AV_CODEC_ID_MPEG4,
+ .write_header = nut_write_header,
+ .write_packet = nut_write_packet,
+ .write_trailer = nut_write_trailer,
+ .flags = AVFMT_GLOBALHEADER,
+};
+#endif /* CONFIG_LIBNUT_MUXER */
+
+static int nut_probe(AVProbeData *p) {
+ if (!memcmp(p->buf, ID_STRING, ID_LENGTH)) return AVPROBE_SCORE_MAX;
+
+ return 0;
+}
+
+static size_t av_read(void * h, size_t len, uint8_t * buf) {
+ AVIOContext * bc = h;
+ return avio_read(bc, buf, len);
+}
+
+static off_t av_seek(void * h, long long pos, int whence) {
+ AVIOContext * bc = h;
+ if (whence == SEEK_END) {
+ pos = avio_size(bc) + pos;
+ whence = SEEK_SET;
+ }
+ return avio_seek(bc, pos, whence);
+}
+
+static int nut_read_header(AVFormatContext * avf) {
+ NUTContext * priv = avf->priv_data;
+ AVIOContext * bc = avf->pb;
+ nut_demuxer_opts_tt dopts = {
+ .input = {
+ .priv = bc,
+ .seek = av_seek,
+ .read = av_read,
+ .eof = NULL,
+ .file_pos = 0,
+ },
+ .alloc = { av_malloc, av_realloc, av_free },
+ .read_index = 1,
+ .cache_syncpoints = 1,
+ };
+ nut_context_tt * nut = priv->nut = nut_demuxer_init(&dopts);
+ nut_stream_header_tt * s;
+ int ret, i;
+
+ if(!nut)
+ return -1;
+
+ if ((ret = nut_read_headers(nut, &s, NULL))) {
+ av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret));
+ nut_demuxer_uninit(nut);
+ priv->nut = NULL;
+ return -1;
+ }
+
+ priv->s = s;
+
+ for (i = 0; s[i].type != -1 && i < 2; i++) {
+ AVStream * st = avformat_new_stream(avf, NULL);
+ int j;
+
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ for (j = 0; j < s[i].fourcc_len && j < 8; j++) st->codec->codec_tag |= s[i].fourcc[j]<<(j*8);
+
+ st->codec->has_b_frames = s[i].decode_delay;
+
+ st->codec->extradata_size = s[i].codec_specific_len;
+ if (st->codec->extradata_size) {
+ if(ff_alloc_extradata(st->codec, st->codec->extradata_size)){
+ nut_demuxer_uninit(nut);
+ priv->nut = NULL;
+ return AVERROR(ENOMEM);
+ }
+ memcpy(st->codec->extradata, s[i].codec_specific, st->codec->extradata_size);
+ }
+
+ avpriv_set_pts_info(avf->streams[i], 60, s[i].time_base.num, s[i].time_base.den);
+ st->start_time = 0;
+ st->duration = s[i].max_pts;
+
+ st->codec->codec_id = ff_codec_get_id(nut_tags, st->codec->codec_tag);
+
+ switch(s[i].type) {
+ case NUT_AUDIO_CLASS:
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, st->codec->codec_tag);
+
+ st->codec->channels = s[i].channel_count;
+ st->codec->sample_rate = s[i].samplerate_num / s[i].samplerate_denom;
+ break;
+ case NUT_VIDEO_CLASS:
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, st->codec->codec_tag);
+
+ st->codec->width = s[i].width;
+ st->codec->height = s[i].height;
+ st->sample_aspect_ratio.num = s[i].sample_width;
+ st->sample_aspect_ratio.den = s[i].sample_height;
+ break;
+ }
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) av_log(avf, AV_LOG_ERROR, "Unknown codec?!\n");
+ }
+
+ return 0;
+}
+
+static int nut_read_packet(AVFormatContext * avf, AVPacket * pkt) {
+ NUTContext * priv = avf->priv_data;
+ nut_packet_tt pd;
+ int ret;
+
+ ret = nut_read_next_packet(priv->nut, &pd);
+
+ if (ret || av_new_packet(pkt, pd.len) < 0) {
+ if (ret != NUT_ERR_EOF)
+ av_log(avf, AV_LOG_ERROR, " NUT error: %s\n", nut_error(ret));
+ return -1;
+ }
+
+ if (pd.flags & NUT_FLAG_KEY) pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->pts = pd.pts;
+ pkt->stream_index = pd.stream;
+ pkt->pos = avio_tell(avf->pb);
+
+ ret = nut_read_frame(priv->nut, &pd.len, pkt->data);
+
+ return ret;
+}
+
+static int nut_read_seek(AVFormatContext * avf, int stream_index, int64_t target_ts, int flags) {
+ NUTContext * priv = avf->priv_data;
+ int active_streams[] = { stream_index, -1 };
+ double time_pos = target_ts * priv->s[stream_index].time_base.num / (double)priv->s[stream_index].time_base.den;
+
+ if (nut_seek(priv->nut, time_pos, 2*!(flags & AVSEEK_FLAG_BACKWARD), active_streams)) return -1;
+
+ return 0;
+}
+
+static int nut_read_close(AVFormatContext *s) {
+ NUTContext * priv = s->priv_data;
+
+ nut_demuxer_uninit(priv->nut);
+
+ return 0;
+}
+
+AVInputFormat ff_libnut_demuxer = {
+ .name = "libnut",
+ .long_name = NULL_IF_CONFIG_SMALL("NUT format"),
+ .priv_data_size = sizeof(NUTContext),
+ .read_probe = nut_probe,
+ .read_header = nut_read_header,
+ .read_packet = nut_read_packet,
+ .read_close = nut_read_close,
+ .read_seek = nut_read_seek,
+ .extensions = "nut",
+};
diff --git a/libavformat/libquvi.c b/libavformat/libquvi.c
new file mode 100644
index 0000000000..7c5f7a29b7
--- /dev/null
+++ b/libavformat/libquvi.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <quvi/quvi.h>
+
+#include "libavformat/avformat.h"
+#include "libavformat/internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+
+typedef struct {
+ const AVClass *class;
+ char *format;
+ AVFormatContext *fmtctx;
+} LibQuviContext;
+
+#define OFFSET(x) offsetof(LibQuviContext, x)
+#define FLAGS AV_OPT_FLAG_DECODING_PARAM
+static const AVOption libquvi_options[] = {
+ { "format", "request specific format", OFFSET(format), AV_OPT_TYPE_STRING, {.str="best"}, .flags = FLAGS },
+ { NULL }
+};
+
+static const AVClass libquvi_context_class = {
+ .class_name = "libquvi",
+ .item_name = av_default_item_name,
+ .option = libquvi_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int libquvi_close(AVFormatContext *s)
+{
+ LibQuviContext *qc = s->priv_data;
+ if (qc->fmtctx)
+ avformat_close_input(&qc->fmtctx);
+ return 0;
+}
+
+static int libquvi_read_header(AVFormatContext *s)
+{
+ int i, ret;
+ quvi_t q;
+ quvi_media_t m;
+ QUVIcode rc;
+ LibQuviContext *qc = s->priv_data;
+ char *media_url, *pagetitle;
+
+ rc = quvi_init(&q);
+ if (rc != QUVI_OK)
+ goto quvi_fail;
+
+ quvi_setopt(q, QUVIOPT_FORMAT, qc->format);
+
+ rc = quvi_parse(q, s->filename, &m);
+ if (rc != QUVI_OK)
+ goto quvi_fail;
+
+ rc = quvi_getprop(m, QUVIPROP_MEDIAURL, &media_url);
+ if (rc != QUVI_OK)
+ goto quvi_fail;
+
+ if (!(qc->fmtctx = avformat_alloc_context()))
+ goto quvi_fail;
+
+ if ((ret = ff_copy_whitelists(qc->fmtctx, s)) < 0)
+ goto end;
+
+ ret = avformat_open_input(&qc->fmtctx, media_url, NULL, NULL);
+ if (ret < 0)
+ goto end;
+
+ rc = quvi_getprop(m, QUVIPROP_PAGETITLE, &pagetitle);
+ if (rc == QUVI_OK)
+ av_dict_set(&s->metadata, "title", pagetitle, 0);
+
+ for (i = 0; i < qc->fmtctx->nb_streams; i++) {
+ AVStream *st = avformat_new_stream(s, NULL);
+ AVStream *ist = qc->fmtctx->streams[i];
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den);
+ avcodec_copy_context(st->codec, qc->fmtctx->streams[i]->codec);
+ }
+
+ return 0;
+
+quvi_fail:
+ av_log(s, AV_LOG_ERROR, "%s\n", quvi_strerror(q, rc));
+ ret = AVERROR_EXTERNAL;
+
+end:
+ quvi_parse_close(&m);
+ quvi_close(&q);
+ return ret;
+}
+
+static int libquvi_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ LibQuviContext *qc = s->priv_data;
+ return av_read_frame(qc->fmtctx, pkt);
+}
+
+static int libquvi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+ LibQuviContext *qc = s->priv_data;
+ return av_seek_frame(qc->fmtctx, stream_index, timestamp, flags);
+}
+
+static int libquvi_probe(AVProbeData *p)
+{
+ int score;
+ quvi_t q;
+ QUVIcode rc;
+
+ rc = quvi_init(&q);
+ if (rc != QUVI_OK)
+ return AVERROR(ENOMEM);
+ score = quvi_supported(q, (char *)p->filename) == QUVI_OK ? AVPROBE_SCORE_EXTENSION : 0;
+ quvi_close(&q);
+ return score;
+}
+
+AVInputFormat ff_libquvi_demuxer = {
+ .name = "libquvi",
+ .long_name = NULL_IF_CONFIG_SMALL("libquvi demuxer"),
+ .priv_data_size = sizeof(LibQuviContext),
+ .read_probe = libquvi_probe,
+ .read_header = libquvi_read_header,
+ .read_packet = libquvi_read_packet,
+ .read_close = libquvi_close,
+ .read_seek = libquvi_read_seek,
+ .priv_class = &libquvi_context_class,
+ .flags = AVFMT_NOFILE,
+};
diff --git a/libavformat/librtmp.c b/libavformat/librtmp.c
index fac3a35196..bfa9a718f1 100644
--- a/libavformat/librtmp.c
+++ b/libavformat/librtmp.c
@@ -2,20 +2,20 @@
* RTMP network protocol
* Copyright (c) 2010 Howard Chu
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,9 @@
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "avformat.h"
+#if CONFIG_NETWORK
+#include "network.h"
+#endif
#include "url.h"
#include <librtmp/rtmp.h>
@@ -48,6 +51,7 @@ typedef struct LibRTMPContext {
char *client_buffer_time;
int live;
char *temp_filename;
+ int buffer_size;
} LibRTMPContext;
static void rtmp_log(int level, const char *fmt, va_list args)
@@ -230,10 +234,20 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
goto fail;
}
+#if CONFIG_NETWORK
+ if (ctx->buffer_size >= 0 && (flags & AVIO_FLAG_WRITE)) {
+ int tmp = ctx->buffer_size;
+ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp));
+ }
+#endif
+
s->is_streamed = 1;
return 0;
fail:
av_freep(&ctx->temp_filename);
+ if (rc)
+ RTMP_Close(r);
+
return rc;
}
@@ -308,6 +322,9 @@ static const AVOption options[] = {
{"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
{"rtmp_swfverify", "URL to player swf file, compute hash/size automatically. (unimplemented)", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
{"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
+#if CONFIG_NETWORK
+ {"rtmp_buffer_size", "set buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC|ENC },
+#endif
{ NULL },
};
diff --git a/libavformat/libsmbclient.c b/libavformat/libsmbclient.c
new file mode 100644
index 0000000000..1af8163674
--- /dev/null
+++ b/libavformat/libsmbclient.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2014 Lukasz Marek <lukasz.m.luki@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
+ */
+
+#include <libsmbclient.h>
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+
+typedef struct {
+ const AVClass *class;
+ SMBCCTX *ctx;
+ int dh;
+ int fd;
+ int64_t filesize;
+ int trunc;
+ int timeout;
+ char *workgroup;
+} LIBSMBContext;
+
+static void libsmbc_get_auth_data(SMBCCTX *c, const char *server, const char *share,
+ char *workgroup, int workgroup_len,
+ char *username, int username_len,
+ char *password, int password_len)
+{
+ /* Do nothing yet. Credentials are passed via url.
+ * Callback must exists, there might be a segmentation fault otherwise. */
+}
+
+static av_cold int libsmbc_connect(URLContext *h)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+
+ libsmbc->ctx = smbc_new_context();
+ if (!libsmbc->ctx) {
+ int ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Cannot create context: %s.\n", strerror(errno));
+ return ret;
+ }
+ if (!smbc_init_context(libsmbc->ctx)) {
+ int ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Cannot initialize context: %s.\n", strerror(errno));
+ return ret;
+ }
+ smbc_set_context(libsmbc->ctx);
+
+ smbc_setOptionUserData(libsmbc->ctx, h);
+ smbc_setFunctionAuthDataWithContext(libsmbc->ctx, libsmbc_get_auth_data);
+
+ if (libsmbc->timeout != -1)
+ smbc_setTimeout(libsmbc->ctx, libsmbc->timeout);
+ if (libsmbc->workgroup)
+ smbc_setWorkgroup(libsmbc->ctx, libsmbc->workgroup);
+
+ if (smbc_init(NULL, 0) < 0) {
+ int ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Initialization failed: %s\n", strerror(errno));
+ return ret;
+ }
+ return 0;
+}
+
+static av_cold int libsmbc_close(URLContext *h)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ if (libsmbc->fd >= 0) {
+ smbc_close(libsmbc->fd);
+ libsmbc->fd = -1;
+ }
+ if (libsmbc->ctx) {
+ smbc_free_context(libsmbc->ctx, 1);
+ libsmbc->ctx = NULL;
+ }
+ return 0;
+}
+
+static av_cold int libsmbc_open(URLContext *h, const char *url, int flags)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ int access, ret;
+ struct stat st;
+
+ libsmbc->fd = -1;
+ libsmbc->filesize = -1;
+
+ if ((ret = libsmbc_connect(h)) < 0)
+ goto fail;
+
+ if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
+ access = O_CREAT | O_RDWR;
+ if (libsmbc->trunc)
+ access |= O_TRUNC;
+ } else if (flags & AVIO_FLAG_WRITE) {
+ access = O_CREAT | O_WRONLY;
+ if (libsmbc->trunc)
+ access |= O_TRUNC;
+ } else
+ access = O_RDONLY;
+
+ /* 0666 = -rw-rw-rw- = read+write for everyone, minus umask */
+ if ((libsmbc->fd = smbc_open(url, access, 0666)) < 0) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "File open failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ if (smbc_fstat(libsmbc->fd, &st) < 0)
+ av_log(h, AV_LOG_WARNING, "Cannot stat file: %s\n", strerror(errno));
+ else
+ libsmbc->filesize = st.st_size;
+
+ return 0;
+ fail:
+ libsmbc_close(h);
+ return ret;
+}
+
+static int64_t libsmbc_seek(URLContext *h, int64_t pos, int whence)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ int64_t newpos;
+
+ if (whence == AVSEEK_SIZE) {
+ if (libsmbc->filesize == -1) {
+ av_log(h, AV_LOG_ERROR, "Error during seeking: filesize is unknown.\n");
+ return AVERROR(EIO);
+ } else
+ return libsmbc->filesize;
+ }
+
+ if ((newpos = smbc_lseek(libsmbc->fd, pos, whence)) < 0) {
+ int err = errno;
+ av_log(h, AV_LOG_ERROR, "Error during seeking: %s\n", strerror(err));
+ return AVERROR(err);
+ }
+
+ return newpos;
+}
+
+static int libsmbc_read(URLContext *h, unsigned char *buf, int size)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ int bytes_read;
+
+ if ((bytes_read = smbc_read(libsmbc->fd, buf, size)) < 0) {
+ int ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Read error: %s\n", strerror(errno));
+ return ret;
+ }
+
+ return bytes_read;
+}
+
+static int libsmbc_write(URLContext *h, const unsigned char *buf, int size)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ int bytes_written;
+
+ if ((bytes_written = smbc_write(libsmbc->fd, buf, size)) < 0) {
+ int ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Write error: %s\n", strerror(errno));
+ return ret;
+ }
+
+ return bytes_written;
+}
+
+static int libsmbc_open_dir(URLContext *h)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ int ret;
+
+ if ((ret = libsmbc_connect(h)) < 0)
+ goto fail;
+
+ if ((libsmbc->dh = smbc_opendir(h->filename)) < 0) {
+ ret = AVERROR(errno);
+ av_log(h, AV_LOG_ERROR, "Error opening dir: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ libsmbc_close(h);
+ return ret;
+}
+
+static int libsmbc_read_dir(URLContext *h, AVIODirEntry **next)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ AVIODirEntry *entry;
+ struct smbc_dirent *dirent = NULL;
+ char *url = NULL;
+ int skip_entry;
+
+ *next = entry = ff_alloc_dir_entry();
+ if (!entry)
+ return AVERROR(ENOMEM);
+
+ do {
+ skip_entry = 0;
+ dirent = smbc_readdir(libsmbc->dh);
+ if (!dirent) {
+ av_freep(next);
+ return 0;
+ }
+ switch (dirent->smbc_type) {
+ case SMBC_DIR:
+ entry->type = AVIO_ENTRY_DIRECTORY;
+ break;
+ case SMBC_FILE:
+ entry->type = AVIO_ENTRY_FILE;
+ break;
+ case SMBC_FILE_SHARE:
+ entry->type = AVIO_ENTRY_SHARE;
+ break;
+ case SMBC_SERVER:
+ entry->type = AVIO_ENTRY_SERVER;
+ break;
+ case SMBC_WORKGROUP:
+ entry->type = AVIO_ENTRY_WORKGROUP;
+ break;
+ case SMBC_COMMS_SHARE:
+ case SMBC_IPC_SHARE:
+ case SMBC_PRINTER_SHARE:
+ skip_entry = 1;
+ break;
+ case SMBC_LINK:
+ default:
+ entry->type = AVIO_ENTRY_UNKNOWN;
+ break;
+ }
+ } while (skip_entry || !strcmp(dirent->name, ".") ||
+ !strcmp(dirent->name, ".."));
+
+ entry->name = av_strdup(dirent->name);
+ if (!entry->name) {
+ av_freep(next);
+ return AVERROR(ENOMEM);
+ }
+
+ url = av_append_path_component(h->filename, dirent->name);
+ if (url) {
+ struct stat st;
+ if (!smbc_stat(url, &st)) {
+ entry->group_id = st.st_gid;
+ entry->user_id = st.st_uid;
+ entry->size = st.st_size;
+ entry->filemode = st.st_mode & 0777;
+ entry->modification_timestamp = INT64_C(1000000) * st.st_mtime;
+ entry->access_timestamp = INT64_C(1000000) * st.st_atime;
+ entry->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
+ }
+ av_free(url);
+ }
+
+ return 0;
+}
+
+static int libsmbc_close_dir(URLContext *h)
+{
+ LIBSMBContext *libsmbc = h->priv_data;
+ if (libsmbc->dh >= 0) {
+ smbc_closedir(libsmbc->dh);
+ libsmbc->dh = -1;
+ }
+ libsmbc_close(h);
+ return 0;
+}
+
+#define OFFSET(x) offsetof(LIBSMBContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ {"timeout", "set timeout in ms of socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
+ {"truncate", "truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
+ {"workgroup", "set the workgroup used for making connections", OFFSET(workgroup), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
+ {NULL}
+};
+
+static const AVClass libsmbclient_context_class = {
+ .class_name = "libsmbc",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+URLProtocol ff_libsmbclient_protocol = {
+ .name = "smb",
+ .url_open = libsmbc_open,
+ .url_read = libsmbc_read,
+ .url_write = libsmbc_write,
+ .url_seek = libsmbc_seek,
+ .url_close = libsmbc_close,
+ .url_open_dir = libsmbc_open_dir,
+ .url_read_dir = libsmbc_read_dir,
+ .url_close_dir = libsmbc_close_dir,
+ .priv_data_size = sizeof(LIBSMBContext),
+ .priv_data_class = &libsmbclient_context_class,
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
+};
diff --git a/libavformat/libssh.c b/libavformat/libssh.c
new file mode 100644
index 0000000000..fac6114210
--- /dev/null
+++ b/libavformat/libssh.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2013 Lukasz Marek <lukasz.m.luki@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
+ */
+
+#include <fcntl.h>
+#define LIBSSH_STATIC
+#include <libssh/sftp.h>
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "libavutil/attributes.h"
+#include "avformat.h"
+#include "internal.h"
+#include "url.h"
+
+typedef struct {
+ const AVClass *class;
+ ssh_session session;
+ sftp_session sftp;
+ sftp_file file;
+ int64_t filesize;
+ int rw_timeout;
+ int trunc;
+ char *priv_key;
+} LIBSSHContext;
+
+static av_cold int libssh_create_ssh_session(LIBSSHContext *libssh, const char* hostname, unsigned int port)
+{
+ static const int verbosity = SSH_LOG_NOLOG;
+
+ if (!(libssh->session = ssh_new())) {
+ av_log(libssh, AV_LOG_ERROR, "SSH session creation failed: %s\n", ssh_get_error(libssh->session));
+ return AVERROR(ENOMEM);
+ }
+ ssh_options_set(libssh->session, SSH_OPTIONS_HOST, hostname);
+ ssh_options_set(libssh->session, SSH_OPTIONS_PORT, &port);
+ ssh_options_set(libssh->session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ if (libssh->rw_timeout > 0) {
+ long timeout = libssh->rw_timeout * 1000;
+ ssh_options_set(libssh->session, SSH_OPTIONS_TIMEOUT_USEC, &timeout);
+ }
+
+ if (ssh_options_parse_config(libssh->session, NULL) < 0) {
+ av_log(libssh, AV_LOG_WARNING, "Could not parse the config file.\n");
+ }
+
+ if (ssh_connect(libssh->session) != SSH_OK) {
+ av_log(libssh, AV_LOG_ERROR, "Connection failed: %s\n", ssh_get_error(libssh->session));
+ return AVERROR(EIO);
+ }
+
+ return 0;
+}
+
+static av_cold int libssh_authentication(LIBSSHContext *libssh, const char *user, const char *password)
+{
+ int authorized = 0;
+ int auth_methods;
+
+ if (user)
+ ssh_options_set(libssh->session, SSH_OPTIONS_USER, user);
+
+ if (ssh_userauth_none(libssh->session, NULL) == SSH_AUTH_SUCCESS)
+ return 0;
+
+ auth_methods = ssh_userauth_list(libssh->session, NULL);
+
+ if (auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
+ if (libssh->priv_key) {
+ ssh_string pub_key;
+ ssh_private_key priv_key;
+ int type;
+ if (!ssh_try_publickey_from_file(libssh->session, libssh->priv_key, &pub_key, &type)) {
+ priv_key = privatekey_from_file(libssh->session, libssh->priv_key, type, password);
+ if (ssh_userauth_pubkey(libssh->session, NULL, pub_key, priv_key) == SSH_AUTH_SUCCESS) {
+ av_log(libssh, AV_LOG_DEBUG, "Authentication successful with selected private key.\n");
+ authorized = 1;
+ }
+ } else {
+ av_log(libssh, AV_LOG_DEBUG, "Invalid key is provided.\n");
+ return AVERROR(EACCES);
+ }
+ } else if (ssh_userauth_autopubkey(libssh->session, password) == SSH_AUTH_SUCCESS) {
+ av_log(libssh, AV_LOG_DEBUG, "Authentication successful with auto selected key.\n");
+ authorized = 1;
+ }
+ }
+
+ if (!authorized && (auth_methods & SSH_AUTH_METHOD_PASSWORD)) {
+ if (ssh_userauth_password(libssh->session, NULL, password) == SSH_AUTH_SUCCESS) {
+ av_log(libssh, AV_LOG_DEBUG, "Authentication successful with password.\n");
+ authorized = 1;
+ }
+ }
+
+ if (!authorized) {
+ av_log(libssh, AV_LOG_ERROR, "Authentication failed.\n");
+ return AVERROR(EACCES);
+ }
+
+ return 0;
+}
+
+static av_cold int libssh_create_sftp_session(LIBSSHContext *libssh)
+{
+ if (!(libssh->sftp = sftp_new(libssh->session))) {
+ av_log(libssh, AV_LOG_ERROR, "SFTP session creation failed: %s\n", ssh_get_error(libssh->session));
+ return AVERROR(ENOMEM);
+ }
+
+ if (sftp_init(libssh->sftp) != SSH_OK) {
+ av_log(libssh, AV_LOG_ERROR, "Error initializing sftp session: %s\n", ssh_get_error(libssh->session));
+ return AVERROR(EIO);
+ }
+
+ return 0;
+}
+
+static av_cold int libssh_open_file(LIBSSHContext *libssh, int flags, const char *file)
+{
+ int access;
+
+ if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
+ access = O_CREAT | O_RDWR;
+ if (libssh->trunc)
+ access |= O_TRUNC;
+ } else if (flags & AVIO_FLAG_WRITE) {
+ access = O_CREAT | O_WRONLY;
+ if (libssh->trunc)
+ access |= O_TRUNC;
+ } else
+ access = O_RDONLY;
+
+ /* 0666 = -rw-rw-rw- = read+write for everyone, minus umask */
+ if (!(libssh->file = sftp_open(libssh->sftp, file, access, 0666))) {
+ av_log(libssh, AV_LOG_ERROR, "Error opening sftp file: %s\n", ssh_get_error(libssh->session));
+ return AVERROR(EIO);
+ }
+
+ return 0;
+}
+
+static av_cold void libssh_stat_file(LIBSSHContext *libssh)
+{
+ sftp_attributes stat;
+
+ if (!(stat = sftp_fstat(libssh->file))) {
+ av_log(libssh, AV_LOG_WARNING, "Cannot stat remote file.\n");
+ libssh->filesize = -1;
+ } else {
+ libssh->filesize = stat->size;
+ sftp_attributes_free(stat);
+ }
+}
+
+static av_cold int libssh_close(URLContext *h)
+{
+ LIBSSHContext *libssh = h->priv_data;
+ if (libssh->file) {
+ sftp_close(libssh->file);
+ libssh->file = NULL;
+ }
+ if (libssh->sftp) {
+ sftp_free(libssh->sftp);
+ libssh->sftp = NULL;
+ }
+ if (libssh->session) {
+ ssh_disconnect(libssh->session);
+ ssh_free(libssh->session);
+ libssh->session = NULL;
+ }
+ return 0;
+}
+
+static av_cold int libssh_open(URLContext *h, const char *url, int flags)
+{
+ LIBSSHContext *libssh = h->priv_data;
+ char proto[10], path[MAX_URL_SIZE], hostname[1024], credencials[1024];
+ int port, ret;
+ const char *user = NULL, *pass = NULL;
+ char *end = NULL;
+
+ av_url_split(proto, sizeof(proto),
+ credencials, sizeof(credencials),
+ hostname, sizeof(hostname),
+ &port,
+ path, sizeof(path),
+ url);
+
+ // a port of 0 will use a port from ~/.ssh/config or the default value 22
+ if (port < 0 || port > 65535)
+ port = 0;
+
+ if ((ret = libssh_create_ssh_session(libssh, hostname, port)) < 0)
+ goto fail;
+
+ user = av_strtok(credencials, ":", &end);
+ pass = av_strtok(end, ":", &end);
+
+ if ((ret = libssh_authentication(libssh, user, pass)) < 0)
+ goto fail;
+
+ if ((ret = libssh_create_sftp_session(libssh)) < 0)
+ goto fail;
+
+ if ((ret = libssh_open_file(libssh, flags, path)) < 0)
+ goto fail;
+
+ libssh_stat_file(libssh);
+
+ return 0;
+
+ fail:
+ libssh_close(h);
+ return ret;
+}
+
+static int64_t libssh_seek(URLContext *h, int64_t pos, int whence)
+{
+ LIBSSHContext *libssh = h->priv_data;
+ int64_t newpos;
+
+ if (libssh->filesize == -1 && (whence == AVSEEK_SIZE || whence == SEEK_END)) {
+ av_log(h, AV_LOG_ERROR, "Error during seeking.\n");
+ return AVERROR(EIO);
+ }
+
+ switch(whence) {
+ case AVSEEK_SIZE:
+ return libssh->filesize;
+ case SEEK_SET:
+ newpos = pos;
+ break;
+ case SEEK_CUR:
+ newpos = sftp_tell64(libssh->file) + pos;
+ break;
+ case SEEK_END:
+ newpos = libssh->filesize + pos;
+ break;
+ default:
+ return AVERROR(EINVAL);
+ }
+
+ if (newpos < 0) {
+ av_log(h, AV_LOG_ERROR, "Seeking to nagative position.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (sftp_seek64(libssh->file, newpos)) {
+ av_log(h, AV_LOG_ERROR, "Error during seeking.\n");
+ return AVERROR(EIO);
+ }
+
+ return newpos;
+}
+
+static int libssh_read(URLContext *h, unsigned char *buf, int size)
+{
+ LIBSSHContext *libssh = h->priv_data;
+ int bytes_read;
+
+ if ((bytes_read = sftp_read(libssh->file, buf, size)) < 0) {
+ av_log(libssh, AV_LOG_ERROR, "Read error.\n");
+ return AVERROR(EIO);
+ }
+ return bytes_read;
+}
+
+static int libssh_write(URLContext *h, const unsigned char *buf, int size)
+{
+ LIBSSHContext *libssh = h->priv_data;
+ int bytes_written;
+
+ if ((bytes_written = sftp_write(libssh->file, buf, size)) < 0) {
+ av_log(libssh, AV_LOG_ERROR, "Write error.\n");
+ return AVERROR(EIO);
+ }
+ return bytes_written;
+}
+
+#define OFFSET(x) offsetof(LIBSSHContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ {"timeout", "set timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
+ {"truncate", "Truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
+ {"private_key", "set path to private key", OFFSET(priv_key), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D|E },
+ {NULL}
+};
+
+static const AVClass libssh_context_class = {
+ .class_name = "libssh",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+URLProtocol ff_libssh_protocol = {
+ .name = "sftp",
+ .url_open = libssh_open,
+ .url_read = libssh_read,
+ .url_write = libssh_write,
+ .url_seek = libssh_seek,
+ .url_close = libssh_close,
+ .priv_data_size = sizeof(LIBSSHContext),
+ .priv_data_class = &libssh_context_class,
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
+};
diff --git a/libavformat/lmlm4.c b/libavformat/lmlm4.c
index 1fb03e7e11..899f449634 100644
--- a/libavformat/lmlm4.c
+++ b/libavformat/lmlm4.c
@@ -5,20 +5,20 @@
* Due to a lack of sample files, only files with one channel are supported.
* u-law and ADPCM audio are unsupported for the same reason.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -37,7 +37,7 @@
static int lmlm4_probe(AVProbeData *pd)
{
- unsigned char *buf = pd->buf;
+ const unsigned char *buf = pd->buf;
unsigned int frame_type, packet_size;
frame_type = AV_RB16(buf + 2);
@@ -96,8 +96,8 @@ static int lmlm4_read_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "invalid or unsupported frame_type\n");
return AVERROR(EIO);
}
- if (packet_size > LMLM4_MAX_PACKET_SIZE) {
- av_log(s, AV_LOG_ERROR, "packet size exceeds maximum\n");
+ 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);
}
diff --git a/libavformat/loasdec.c b/libavformat/loasdec.c
new file mode 100644
index 0000000000..c41809be00
--- /dev/null
+++ b/libavformat/loasdec.c
@@ -0,0 +1,94 @@
+/*
+ * LOAS AudioSyncStream demuxer
+ * Copyright (c) 2008 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/internal.h"
+#include "avformat.h"
+#include "internal.h"
+#include "rawdec.h"
+
+#define LOAS_SYNC_WORD 0x2b7
+
+static int loas_probe(AVProbeData *p)
+{
+ int max_frames = 0, first_frames = 0;
+ int fsize, frames;
+ const uint8_t *buf0 = p->buf;
+ const uint8_t *buf2;
+ const uint8_t *buf;
+ const uint8_t *end = buf0 + p->buf_size - 3;
+ buf = buf0;
+
+ for (; buf < end; buf = buf2 + 1) {
+ buf2 = buf;
+
+ for (frames = 0; buf2 < end; frames++) {
+ uint32_t header = AV_RB24(buf2);
+ if ((header >> 13) != LOAS_SYNC_WORD)
+ break;
+ fsize = (header & 0x1FFF) + 3;
+ if (fsize < 7)
+ break;
+ fsize = FFMIN(fsize, end - buf2);
+ buf2 += fsize;
+ }
+ max_frames = FFMAX(max_frames, frames);
+ if (buf == buf0)
+ first_frames = frames;
+ }
+
+ if (first_frames >= 3)
+ return AVPROBE_SCORE_EXTENSION + 1;
+ else if (max_frames > 100)
+ return AVPROBE_SCORE_EXTENSION;
+ else if (max_frames >= 3)
+ return AVPROBE_SCORE_EXTENSION / 2;
+ else
+ return 0;
+}
+
+static int loas_read_header(AVFormatContext *s)
+{
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = s->iformat->raw_codec_id;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
+
+ //LCM of all possible AAC sample rates
+ avpriv_set_pts_info(st, 64, 1, 28224000);
+
+ return 0;
+}
+
+AVInputFormat ff_loas_demuxer = {
+ .name = "loas",
+ .long_name = NULL_IF_CONFIG_SMALL("LOAS AudioSyncStream"),
+ .read_probe = loas_probe,
+ .read_header = loas_read_header,
+ .read_packet = ff_raw_read_partial_packet,
+ .flags= AVFMT_GENERIC_INDEX,
+ .raw_codec_id = AV_CODEC_ID_AAC_LATM,
+};
diff --git a/libavformat/lrc.c b/libavformat/lrc.c
new file mode 100644
index 0000000000..139c6506e4
--- /dev/null
+++ b/libavformat/lrc.c
@@ -0,0 +1,34 @@
+/*
+ * LRC lyrics file format decoder
+ * Copyright (c) 2014 StarBrilliant <m13253@hotmail.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
+ */
+
+#include "metadata.h"
+#include "lrc.h"
+
+const AVMetadataConv ff_lrc_metadata_conv[] = {
+ {"ti", "title"},
+ {"al", "album"},
+ {"ar", "artist"},
+ {"au", "author"},
+ {"by", "creator"},
+ {"re", "encoder"},
+ {"ve", "encoder_version"},
+ {0, 0}
+};
diff --git a/libavformat/lrc.h b/libavformat/lrc.h
new file mode 100644
index 0000000000..0297bc1eb1
--- /dev/null
+++ b/libavformat/lrc.h
@@ -0,0 +1,29 @@
+/*
+ * LRC lyrics file format decoder
+ * Copyright (c) 2014 StarBrilliant <m13253@hotmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_LRC_H
+#define AVFORMAT_LRC_H
+
+#include "metadata.h"
+
+extern const AVMetadataConv ff_lrc_metadata_conv[];
+
+#endif
diff --git a/libavformat/lrcdec.c b/libavformat/lrcdec.c
new file mode 100644
index 0000000000..df61853d2b
--- /dev/null
+++ b/libavformat/lrcdec.c
@@ -0,0 +1,248 @@
+/*
+ * LRC lyrics file format decoder
+ * Copyright (c) 2014 StarBrilliant <m13253@hotmail.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
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "avformat.h"
+#include "internal.h"
+#include "lrc.h"
+#include "metadata.h"
+#include "subtitles.h"
+#include "libavutil/bprint.h"
+#include "libavutil/dict.h"
+
+typedef struct LRCContext {
+ FFDemuxSubtitlesQueue q;
+ int64_t ts_offset; // offset metadata item
+} LRCContext;
+
+static int64_t find_header(const char *p)
+{
+ int64_t offset = 0;
+ while(p[offset] == ' ' || p[offset] == '\t') {
+ offset++;
+ }
+ if(p[offset] == '[' && p[offset + 1] >= 'a' && p[offset + 1] <= 'z') {
+ return offset;
+ } else {
+ return -1;
+ }
+}
+
+static int64_t count_ts(const char *p)
+{
+ int64_t offset = 0;
+ int in_brackets = 0;
+
+ for(;;) {
+ if(p[offset] == ' ' || p[offset] == '\t') {
+ offset++;
+ } else if(p[offset] == '[') {
+ offset++;
+ in_brackets++;
+ } else if (p[offset] == ']' && in_brackets) {
+ offset++;
+ in_brackets--;
+ } else if(in_brackets &&
+ (p[offset] == ':' || p[offset] == '.' || p[offset] == '-' ||
+ (p[offset] >= '0' && p[offset] <= '9'))) {
+ offset++;
+ } else {
+ break;
+ }
+ }
+ return offset;
+}
+
+static int64_t read_ts(const char *p, int64_t *start)
+{
+ int64_t offset = 0;
+ uint64_t mm, ss, cs;
+
+ while(p[offset] == ' ' || p[offset] == '\t') {
+ offset++;
+ }
+ if(p[offset] != '[') {
+ return 0;
+ }
+ if(sscanf(p, "[-%"SCNu64":%"SCNu64".%"SCNu64"]", &mm, &ss, &cs) == 3) {
+ /* Just in case negative pts, players may drop it but we won't. */
+ *start = -(int64_t) (mm*60000 + ss*1000 + cs*10);
+ } else if(sscanf(p, "[%"SCNu64":%"SCNu64".%"SCNu64"]", &mm, &ss, &cs) == 3) {
+ *start = mm*60000 + ss*1000 + cs*10;
+ } else {
+ return 0;
+ }
+ do {
+ offset++;
+ } while(p[offset] && p[offset-1] != ']');
+ return offset;
+}
+
+static int64_t read_line(AVBPrint *buf, AVIOContext *pb)
+{
+ int64_t pos = avio_tell(pb);
+
+ av_bprint_clear(buf);
+ while(!avio_feof(pb)) {
+ int c = avio_r8(pb);
+ if(c != '\r') {
+ av_bprint_chars(buf, c, 1);
+ }
+ if(c == '\n') {
+ break;
+ }
+ }
+ return pos;
+}
+
+static int lrc_probe(AVProbeData *p)
+{
+ int64_t offset = 0;
+ int64_t mm;
+ uint64_t ss, cs;
+ const AVMetadataConv *metadata_item;
+
+ if(!memcmp(p->buf, "\xef\xbb\xbf", 3)) { // Skip UTF-8 BOM header
+ offset += 3;
+ }
+ while(p->buf[offset] == '\n' || p->buf[offset] == '\r') {
+ offset++;
+ }
+ if(p->buf[offset] != '[') {
+ return 0;
+ }
+ offset++;
+ // Common metadata item but not exist in ff_lrc_metadata_conv
+ if(!memcmp(p->buf + offset, "offset:", 7)) {
+ return 40;
+ }
+ if(sscanf(p->buf + offset, "%"SCNd64":%"SCNu64".%"SCNu64"]",
+ &mm, &ss, &cs) == 3) {
+ return 50;
+ }
+ // Metadata items exist in ff_lrc_metadata_conv
+ for(metadata_item = ff_lrc_metadata_conv;
+ metadata_item->native; metadata_item++) {
+ size_t metadata_item_len = strlen(metadata_item->native);
+ if(p->buf[offset + metadata_item_len] == ':' &&
+ !memcmp(p->buf + offset, metadata_item->native, metadata_item_len)) {
+ return 40;
+ }
+ }
+ return 5; // Give it 5 scores since it starts with a bracket
+}
+
+static int lrc_read_header(AVFormatContext *s)
+{
+ LRCContext *lrc = s->priv_data;
+ AVBPrint line;
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if(!st) {
+ return AVERROR(ENOMEM);
+ }
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ lrc->ts_offset = 0;
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_TEXT;
+ av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ while(!avio_feof(s->pb)) {
+ int64_t pos = read_line(&line, s->pb);
+ int64_t header_offset = find_header(line.str);
+ if(header_offset >= 0) {
+ char *comma_offset = strchr(line.str, ':');
+ if(comma_offset) {
+ char *right_bracket_offset = strchr(line.str, ']');
+ if(!right_bracket_offset) {
+ continue;
+ }
+
+ *right_bracket_offset = *comma_offset = '\0';
+ if(strcmp(line.str + 1, "offset") ||
+ sscanf(comma_offset + 1, "%"SCNd64, &lrc->ts_offset) != 1) {
+ av_dict_set(&s->metadata, line.str + 1, comma_offset + 1, 0);
+ }
+ *comma_offset = ':';
+ *right_bracket_offset = ']';
+ }
+
+ } else {
+ AVPacket *sub;
+ int64_t ts_start = AV_NOPTS_VALUE;
+ int64_t ts_stroffset = 0;
+ int64_t ts_stroffset_incr = 0;
+ int64_t ts_strlength = count_ts(line.str);
+
+ while((ts_stroffset_incr = read_ts(line.str + ts_stroffset,
+ &ts_start)) != 0) {
+ ts_stroffset += ts_stroffset_incr;
+ sub = ff_subtitles_queue_insert(&lrc->q, line.str + ts_strlength,
+ line.len - ts_strlength, 0);
+ if(!sub) {
+ return AVERROR(ENOMEM);
+ }
+ sub->pos = pos;
+ sub->pts = ts_start - lrc->ts_offset;
+ sub->duration = -1;
+ }
+ }
+ }
+ ff_subtitles_queue_finalize(&lrc->q);
+ ff_metadata_conv_ctx(s, NULL, ff_lrc_metadata_conv);
+ return 0;
+}
+
+static int lrc_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ LRCContext *lrc = s->priv_data;
+ return ff_subtitles_queue_read_packet(&lrc->q, pkt);
+}
+
+static int lrc_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ LRCContext *lrc = s->priv_data;
+ return ff_subtitles_queue_seek(&lrc->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int lrc_read_close(AVFormatContext *s)
+{
+ LRCContext *lrc = s->priv_data;
+ ff_subtitles_queue_clean(&lrc->q);
+ return 0;
+}
+
+AVInputFormat ff_lrc_demuxer = {
+ .name = "lrc",
+ .long_name = NULL_IF_CONFIG_SMALL("LRC lyrics"),
+ .priv_data_size = sizeof (LRCContext),
+ .read_probe = lrc_probe,
+ .read_header = lrc_read_header,
+ .read_packet = lrc_read_packet,
+ .read_close = lrc_read_close,
+ .read_seek2 = lrc_read_seek
+};
diff --git a/libavformat/lrcenc.c b/libavformat/lrcenc.c
new file mode 100644
index 0000000000..b316ccd6d8
--- /dev/null
+++ b/libavformat/lrcenc.c
@@ -0,0 +1,152 @@
+/*
+ * LRC lyrics file format decoder
+ * Copyright (c) 2014 StarBrilliant <m13253@hotmail.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
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "avformat.h"
+#include "internal.h"
+#include "lrc.h"
+#include "metadata.h"
+#include "subtitles.h"
+#include "version.h"
+#include "libavutil/bprint.h"
+#include "libavutil/dict.h"
+#include "libavutil/log.h"
+#include "libavutil/macros.h"
+
+static int lrc_write_header(AVFormatContext *s)
+{
+ const AVDictionaryEntry *metadata_item;
+
+ if(s->nb_streams != 1 ||
+ s->streams[0]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ av_log(s, AV_LOG_ERROR,
+ "LRC supports only a single subtitle stream.\n");
+ return AVERROR(EINVAL);
+ }
+ if(s->streams[0]->codec->codec_id != AV_CODEC_ID_SUBRIP &&
+ s->streams[0]->codec->codec_id != AV_CODEC_ID_TEXT) {
+ av_log(s, AV_LOG_ERROR, "Unsupported subtitle codec: %s\n",
+ avcodec_get_name(s->streams[0]->codec->codec_id));
+ return AVERROR(EINVAL);
+ }
+ avpriv_set_pts_info(s->streams[0], 64, 1, 100);
+
+ ff_metadata_conv_ctx(s, ff_lrc_metadata_conv, NULL);
+ if(!(s->flags & AVFMT_FLAG_BITEXACT)) { // avoid breaking regression tests
+ /* LRC provides a metadata slot for specifying encoder version
+ * in addition to encoder name. We will store LIBAVFORMAT_VERSION
+ * to it.
+ */
+ av_dict_set(&s->metadata, "ve", AV_STRINGIFY(LIBAVFORMAT_VERSION), 0);
+ } else {
+ av_dict_set(&s->metadata, "ve", NULL, 0);
+ }
+ for(metadata_item = NULL;
+ (metadata_item = av_dict_get(s->metadata, "", metadata_item,
+ AV_DICT_IGNORE_SUFFIX));) {
+ char *delim;
+ if(!metadata_item->value[0]) {
+ continue;
+ }
+ while((delim = strchr(metadata_item->value, '\n'))) {
+ *delim = ' ';
+ }
+ while((delim = strchr(metadata_item->value, '\r'))) {
+ *delim = ' ';
+ }
+ avio_printf(s->pb, "[%s:%s]\n",
+ metadata_item->key, metadata_item->value);
+ }
+ avio_printf(s->pb, "\n");
+ return 0;
+}
+
+static int lrc_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ if(pkt->pts != AV_NOPTS_VALUE) {
+ char *data = av_malloc(pkt->size + 1);
+ char *line;
+ char *delim;
+
+ if(!data) {
+ return AVERROR(ENOMEM);
+ }
+ memcpy(data, pkt->data, pkt->size);
+ data[pkt->size] = '\0';
+
+ for(delim = data + pkt->size - 1;
+ delim >= data && (delim[0] == '\n' || delim[0] == '\r'); delim--) {
+ delim[0] = '\0'; // Strip last empty lines
+ }
+ line = data;
+ while(line[0] == '\n' || line[0] == '\r') {
+ line++; // Skip first empty lines
+ }
+
+ while(line) {
+ delim = strchr(line, '\n');
+ if(delim) {
+ if(delim > line && delim[-1] == '\r') {
+ delim[-1] = '\0';
+ }
+ delim[0] = '\0';
+ delim++;
+ }
+ if(line[0] == '[') {
+ av_log(s, AV_LOG_WARNING,
+ "Subtitle starts with '[', may cause problems with LRC format.\n");
+ }
+
+ if(pkt->pts >= 0) {
+ avio_printf(s->pb, "[%02"PRId64":%02"PRId64".%02"PRId64"]",
+ (pkt->pts / 6000),
+ ((pkt->pts / 100) % 60),
+ (pkt->pts % 100));
+ } else {
+ /* Offset feature of LRC can easily make pts negative,
+ * we just output it directly and let the player drop it. */
+ avio_printf(s->pb, "[-%02"PRId64":%02"PRId64".%02"PRId64"]",
+ (-pkt->pts) / 6000,
+ ((-pkt->pts) / 100) % 60,
+ (-pkt->pts) % 100);
+ }
+ avio_printf(s->pb, "%s\n", line);
+ line = delim;
+ }
+ av_free(data);
+ }
+ return 0;
+}
+
+AVOutputFormat ff_lrc_muxer = {
+ .name = "lrc",
+ .long_name = NULL_IF_CONFIG_SMALL("LRC lyrics"),
+ .extensions = "lrc",
+ .priv_data_size = 0,
+ .write_header = lrc_write_header,
+ .write_packet = lrc_write_packet,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_GLOBALHEADER |
+ AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT,
+ .subtitle_codec = AV_CODEC_ID_SUBRIP
+};
diff --git a/libavformat/lvfdec.c b/libavformat/lvfdec.c
new file mode 100644
index 0000000000..81aec599ba
--- /dev/null
+++ b/libavformat/lvfdec.c
@@ -0,0 +1,152 @@
+/*
+ * LVF demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "riff.h"
+
+static int lvf_probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) != MKTAG('L', 'V', 'F', 'F'))
+ return 0;
+
+ if (!AV_RL32(p->buf + 16) || AV_RL32(p->buf + 16) > 256)
+ return AVPROBE_SCORE_MAX / 8;
+
+ return AVPROBE_SCORE_EXTENSION;
+}
+
+static int lvf_read_header(AVFormatContext *s)
+{
+ AVStream *st;
+ int64_t next_offset;
+ unsigned size, nb_streams, id;
+
+ avio_skip(s->pb, 16);
+ nb_streams = avio_rl32(s->pb);
+ if (!nb_streams)
+ return AVERROR_INVALIDDATA;
+ if (nb_streams > 2) {
+ avpriv_request_sample(s, "%d streams", nb_streams);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ avio_skip(s->pb, 1012);
+
+ while (!avio_feof(s->pb)) {
+ id = avio_rl32(s->pb);
+ size = avio_rl32(s->pb);
+ next_offset = avio_tell(s->pb) + size;
+
+ switch (id) {
+ case MKTAG('0', '0', 'f', 'm'):
+ st = avformat_new_stream(s, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ avio_skip(s->pb, 4);
+ st->codec->width = avio_rl32(s->pb);
+ st->codec->height = avio_rl32(s->pb);
+ avio_skip(s->pb, 4);
+ st->codec->codec_tag = avio_rl32(s->pb);
+ st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags,
+ st->codec->codec_tag);
+ avpriv_set_pts_info(st, 32, 1, 1000);
+ break;
+ case MKTAG('0', '1', 'f', 'm'):
+ st = avformat_new_stream(s, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_tag = avio_rl16(s->pb);
+ st->codec->channels = avio_rl16(s->pb);
+ st->codec->sample_rate = avio_rl16(s->pb);
+ avio_skip(s->pb, 8);
+ st->codec->bits_per_coded_sample = avio_r8(s->pb);
+ st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags,
+ st->codec->codec_tag);
+ avpriv_set_pts_info(st, 32, 1, 1000);
+ break;
+ case 0:
+ avio_seek(s->pb, 2048 + 8, SEEK_SET);
+ return 0;
+ default:
+ avpriv_request_sample(s, "id %d", id);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ avio_seek(s->pb, next_offset, SEEK_SET);
+ }
+
+ return AVERROR_EOF;
+}
+
+static int lvf_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ unsigned size, flags, timestamp, id;
+ int64_t pos;
+ int ret, is_video = 0;
+
+ pos = avio_tell(s->pb);
+ while (!avio_feof(s->pb)) {
+ id = avio_rl32(s->pb);
+ size = avio_rl32(s->pb);
+
+ if (size == 0xFFFFFFFFu)
+ return AVERROR_EOF;
+
+ switch (id) {
+ case MKTAG('0', '0', 'd', 'c'):
+ is_video = 1;
+ case MKTAG('0', '1', 'w', 'b'):
+ if (size < 8)
+ return AVERROR_INVALIDDATA;
+ timestamp = avio_rl32(s->pb);
+ flags = avio_rl32(s->pb);
+ ret = av_get_packet(s->pb, pkt, size - 8);
+ if (flags & (1 << 12))
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->stream_index = is_video ? 0 : 1;
+ pkt->pts = timestamp;
+ pkt->pos = pos;
+ return ret;
+ default:
+ ret = avio_skip(s->pb, size);
+ }
+
+ if (ret < 0)
+ return ret;
+ }
+
+ return AVERROR_EOF;
+}
+
+AVInputFormat ff_lvf_demuxer = {
+ .name = "lvf",
+ .long_name = NULL_IF_CONFIG_SMALL("LVF"),
+ .read_probe = lvf_probe,
+ .read_header = lvf_read_header,
+ .read_packet = lvf_read_packet,
+ .extensions = "lvf",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/lxfdec.c b/libavformat/lxfdec.c
index e25f82e0af..ce5da820d0 100644
--- a/libavformat/lxfdec.c
+++ b/libavformat/lxfdec.c
@@ -2,20 +2,20 @@
* LXF demuxer
* Copyright (c) 2010 Tomas Härdin
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -83,7 +83,7 @@ static int check_checksum(const uint8_t *header, int size)
* @param[out] header where to copy the ident to
* @return 0 if an ident was found, < 0 on I/O error
*/
-static int sync(AVFormatContext *s, uint8_t *header)
+static int lxf_sync(AVFormatContext *s, uint8_t *header)
{
uint8_t buf[LXF_IDENT_LENGTH];
int ret;
@@ -92,7 +92,7 @@ static int sync(AVFormatContext *s, uint8_t *header)
return ret < 0 ? ret : AVERROR_EOF;
while (memcmp(buf, LXF_IDENT, LXF_IDENT_LENGTH)) {
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR_EOF;
memmove(buf, &buf[1], LXF_IDENT_LENGTH-1);
@@ -120,7 +120,7 @@ static int get_packet_header(AVFormatContext *s)
const uint8_t *p = header + LXF_IDENT_LENGTH;
//find and read the ident
- if ((ret = sync(s, header)) < 0)
+ if ((ret = lxf_sync(s, header)) < 0)
return ret;
ret = avio_read(pb, header + LXF_IDENT_LENGTH, 8);
@@ -140,8 +140,9 @@ static int get_packet_header(AVFormatContext *s)
}
//read the rest of the packet header
- ret = avio_read(pb, header + (p - header), header_size - (p - header));
- if (ret != header_size - (p - header))
+ if ((ret = avio_read(pb, header + (p - header),
+ header_size - (p - header))) !=
+ header_size - (p - header))
return ret < 0 ? ret : AVERROR_EOF;
if (check_checksum(header, header_size))
@@ -260,6 +261,7 @@ static int lxf_read_header(AVFormatContext *s)
st->codec->bit_rate = 1000000 * ((video_params >> 14) & 0xFF);
st->codec->codec_tag = video_params & 0xF;
st->codec->codec_id = ff_codec_get_id(lxf_tags, st->codec->codec_tag);
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
av_log(s, AV_LOG_DEBUG, "record: %x = %i-%02i-%02i\n",
record_date, 1900 + (record_date & 0x7F), (record_date >> 7) & 0xF,
diff --git a/libavformat/m4vdec.c b/libavformat/m4vdec.c
index 4a0af3c037..d8ee530010 100644
--- a/libavformat/m4vdec.c
+++ b/libavformat/m4vdec.c
@@ -2,20 +2,20 @@
* RAW MPEG-4 video demuxer
* Copyright (c) 2006 Thijs Vermeir <thijs.vermeir@barco.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,16 +33,18 @@ static int mpeg4video_probe(AVProbeData *probe_packet)
for (i = 0; i < probe_packet->buf_size; i++) {
temp_buffer = (temp_buffer << 8) + probe_packet->buf[i];
- if ((temp_buffer & 0xffffff00) != 0x100)
+ if (temp_buffer & 0xfffffe00)
+ continue;
+ if (temp_buffer < 2)
continue;
if (temp_buffer == VOP_START_CODE)
VOP++;
else if (temp_buffer == VISUAL_OBJECT_START_CODE)
VISO++;
- else if (temp_buffer < 0x120)
+ else if (temp_buffer >= 0x100 && temp_buffer < 0x120)
VO++;
- else if (temp_buffer < 0x130)
+ else if (temp_buffer >= 0x120 && temp_buffer < 0x130)
VOL++;
else if (!(0x1AF < temp_buffer && temp_buffer < 0x1B7) &&
!(0x1B9 < temp_buffer && temp_buffer < 0x1C4))
@@ -50,9 +52,9 @@ static int mpeg4video_probe(AVProbeData *probe_packet)
}
if (VOP >= VISO && VOP >= VOL && VO >= VOL && VOL > 0 && res == 0)
- return AVPROBE_SCORE_EXTENSION;
+ return VOP+VO > 4 ? AVPROBE_SCORE_EXTENSION : AVPROBE_SCORE_EXTENSION/2;
return 0;
}
-FF_DEF_RAWVIDEO_DEMUXER(m4v, "raw MPEG-4 video", mpeg4video_probe, "m4v",
- AV_CODEC_ID_MPEG4)
+FF_DEF_RAWVIDEO_DEMUXER2(m4v, "raw MPEG-4 video", mpeg4video_probe, "m4v",
+ AV_CODEC_ID_MPEG4, AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT)
diff --git a/libavformat/matroska.c b/libavformat/matroska.c
index eca1e41f75..faa662d09f 100644
--- a/libavformat/matroska.c
+++ b/libavformat/matroska.c
@@ -1,21 +1,21 @@
/*
* Matroska common data
- * Copyright (c) 2003-2004 The ffmpeg Project
+ * Copyright (c) 2003-2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,9 @@
#include "matroska.h"
+/* If you add a tag here that is not in ff_codec_bmp_tags[]
+ or ff_codec_wav_tags[], add it also to additional_audio_tags[]
+ or additional_video_tags[] in matroskaenc.c */
const CodecTags ff_mkv_codec_tags[]={
{"A_AAC" , AV_CODEC_ID_AAC},
{"A_AC3" , AV_CODEC_ID_AC3},
@@ -35,6 +38,7 @@ const CodecTags ff_mkv_codec_tags[]={
{"A_MPEG/L1" , AV_CODEC_ID_MP2},
{"A_MPEG/L3" , AV_CODEC_ID_MP3},
{"A_OPUS" , AV_CODEC_ID_OPUS},
+ {"A_OPUS/EXPERIMENTAL",AV_CODEC_ID_OPUS},
{"A_PCM/FLOAT/IEEE" , AV_CODEC_ID_PCM_F32LE},
{"A_PCM/FLOAT/IEEE" , AV_CODEC_ID_PCM_F64LE},
{"A_PCM/INT/BIG" , AV_CODEC_ID_PCM_S16BE},
@@ -55,13 +59,18 @@ const CodecTags ff_mkv_codec_tags[]={
{"A_VORBIS" , AV_CODEC_ID_VORBIS},
{"A_WAVPACK4" , AV_CODEC_ID_WAVPACK},
+ {"D_WEBVTT/SUBTITLES" , AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/CAPTIONS" , AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/DESCRIPTIONS", AV_CODEC_ID_WEBVTT},
+ {"D_WEBVTT/METADATA" , AV_CODEC_ID_WEBVTT},
+
+ {"S_TEXT/UTF8" , AV_CODEC_ID_SUBRIP},
{"S_TEXT/UTF8" , AV_CODEC_ID_TEXT},
- {"S_TEXT/UTF8" , AV_CODEC_ID_SRT},
{"S_TEXT/ASCII" , AV_CODEC_ID_TEXT},
- {"S_TEXT/ASS" , AV_CODEC_ID_SSA},
- {"S_TEXT/SSA" , AV_CODEC_ID_SSA},
- {"S_ASS" , AV_CODEC_ID_SSA},
- {"S_SSA" , AV_CODEC_ID_SSA},
+ {"S_TEXT/ASS" , AV_CODEC_ID_ASS},
+ {"S_TEXT/SSA" , AV_CODEC_ID_ASS},
+ {"S_ASS" , AV_CODEC_ID_ASS},
+ {"S_SSA" , AV_CODEC_ID_ASS},
{"S_VOBSUB" , AV_CODEC_ID_DVD_SUBTITLE},
{"S_DVBSUB" , AV_CODEC_ID_DVB_SUBTITLE},
{"S_HDMV/PGS" , AV_CODEC_ID_HDMV_PGS_SUBTITLE},
@@ -81,6 +90,7 @@ const CodecTags ff_mkv_codec_tags[]={
{"V_REAL/RV20" , AV_CODEC_ID_RV20},
{"V_REAL/RV30" , AV_CODEC_ID_RV30},
{"V_REAL/RV40" , AV_CODEC_ID_RV40},
+ {"V_SNOW" , AV_CODEC_ID_SNOW},
{"V_THEORA" , AV_CODEC_ID_THEORA},
{"V_UNCOMPRESSED" , AV_CODEC_ID_RAWVIDEO},
{"V_VP8" , AV_CODEC_ID_VP8},
@@ -102,6 +112,8 @@ const CodecMime ff_mkv_mime_tags[] = {
{"text/plain" , AV_CODEC_ID_TEXT},
{"application/x-truetype-font", AV_CODEC_ID_TTF},
{"application/x-font" , AV_CODEC_ID_TTF},
+ {"application/vnd.ms-opentype", AV_CODEC_ID_OTF},
+ {"binary" , AV_CODEC_ID_BIN_DATA},
{"" , AV_CODEC_ID_NONE}
};
@@ -112,6 +124,30 @@ const AVMetadataConv ff_mkv_metadata_conv[] = {
{ 0 }
};
+const char * const ff_matroska_video_stereo_mode[MATROSKA_VIDEO_STEREOMODE_TYPE_NB] = {
+ "mono",
+ "left_right",
+ "bottom_top",
+ "top_bottom",
+ "checkerboard_rl",
+ "checkerboard_lr",
+ "row_interleaved_rl",
+ "row_interleaved_lr",
+ "col_interleaved_rl",
+ "col_interleaved_lr",
+ "anaglyph_cyan_red",
+ "right_left",
+ "anaglyph_green_magenta",
+ "block_lr",
+ "block_rl",
+};
+
+const char * const ff_matroska_video_stereo_plane[MATROSKA_VIDEO_STEREO_PLANE_COUNT] = {
+ "left",
+ "right",
+ "background",
+};
+
int ff_mkv_stereo3d_conv(AVStream *st, MatroskaVideoStereoModeType stereo_mode)
{
AVPacketSideData *sd, *tmp;
diff --git a/libavformat/matroska.h b/libavformat/matroska.h
index a7a22a96af..344b2c32fa 100644
--- a/libavformat/matroska.h
+++ b/libavformat/matroska.h
@@ -1,21 +1,21 @@
/*
* Matroska constants
- * Copyright (c) 2003-2004 The ffmpeg Project
+ * Copyright (c) 2003-2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -78,8 +78,13 @@
#define MATROSKA_ID_TRACKNUMBER 0xD7
#define MATROSKA_ID_TRACKUID 0x73C5
#define MATROSKA_ID_TRACKTYPE 0x83
-#define MATROSKA_ID_TRACKAUDIO 0xE1
-#define MATROSKA_ID_TRACKVIDEO 0xE0
+#define MATROSKA_ID_TRACKVIDEO 0xE0
+#define MATROSKA_ID_TRACKAUDIO 0xE1
+#define MATROSKA_ID_TRACKOPERATION 0xE2
+#define MATROSKA_ID_TRACKCOMBINEPLANES 0xE3
+#define MATROSKA_ID_TRACKPLANE 0xE4
+#define MATROSKA_ID_TRACKPLANEUID 0xE5
+#define MATROSKA_ID_TRACKPLANETYPE 0xE6
#define MATROSKA_ID_CODECID 0x86
#define MATROSKA_ID_CODECPRIVATE 0x63A2
#define MATROSKA_ID_CODECNAME 0x258688
@@ -87,6 +92,7 @@
#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240
#define MATROSKA_ID_CODECDECODEALL 0xAA
#define MATROSKA_ID_CODECDELAY 0x56AA
+#define MATROSKA_ID_SEEKPREROLL 0x56BB
#define MATROSKA_ID_TRACKNAME 0x536E
#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C
#define MATROSKA_ID_TRACKFLAGENABLED 0xB9
@@ -114,6 +120,7 @@
#define MATROSKA_ID_VIDEODISPLAYUNIT 0x54B2
#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A
#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B8
+#define MATROSKA_ID_VIDEOALPHAMODE 0x53C0
#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3
#define MATROSKA_ID_VIDEOCOLORSPACE 0x2EB524
@@ -132,6 +139,15 @@
#define MATROSKA_ID_ENCODINGCOMPALGO 0x4254
#define MATROSKA_ID_ENCODINGCOMPSETTINGS 0x4255
+#define MATROSKA_ID_ENCODINGENCRYPTION 0x5035
+#define MATROSKA_ID_ENCODINGENCAESSETTINGS 0x47E7
+#define MATROSKA_ID_ENCODINGENCALGO 0x47E1
+#define MATROSKA_ID_ENCODINGENCKEYID 0x47E2
+#define MATROSKA_ID_ENCODINGSIGALGO 0x47E5
+#define MATROSKA_ID_ENCODINGSIGHASHALGO 0x47E6
+#define MATROSKA_ID_ENCODINGSIGKEYID 0x47E4
+#define MATROSKA_ID_ENCODINGSIGNATURE 0x47E3
+
/* ID in the cues master */
#define MATROSKA_ID_POINTENTRY 0xBB
@@ -142,6 +158,8 @@
/* IDs in the cuetrackposition master */
#define MATROSKA_ID_CUETRACK 0xF7
#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1
+#define MATROSKA_ID_CUERELATIVEPOSITION 0xF0
+#define MATROSKA_ID_CUEDURATION 0xB2
#define MATROSKA_ID_CUEBLOCKNUMBER 0x5378
/* IDs in the tags master */
@@ -171,6 +189,10 @@
#define MATROSKA_ID_CLUSTERPOSITION 0xA7
#define MATROSKA_ID_CLUSTERPREVSIZE 0xAB
#define MATROSKA_ID_BLOCKGROUP 0xA0
+#define MATROSKA_ID_BLOCKADDITIONS 0x75A1
+#define MATROSKA_ID_BLOCKMORE 0xA6
+#define MATROSKA_ID_BLOCKADDID 0xEE
+#define MATROSKA_ID_BLOCKADDITIONAL 0xA5
#define MATROSKA_ID_SIMPLEBLOCK 0xA3
/* IDs in the blockgroup master */
@@ -178,6 +200,7 @@
#define MATROSKA_ID_BLOCKDURATION 0x9B
#define MATROSKA_ID_BLOCKREFERENCE 0xFB
#define MATROSKA_ID_CODECSTATE 0xA4
+#define MATROSKA_ID_DISCARDPADDING 0x75A2
/* IDs in the attachments master */
#define MATROSKA_ID_ATTACHEDFILE 0x61A7
@@ -212,6 +235,7 @@ typedef enum {
MATROSKA_TRACK_TYPE_LOGO = 0x10,
MATROSKA_TRACK_TYPE_SUBTITLE = 0x11,
MATROSKA_TRACK_TYPE_CONTROL = 0x20,
+ MATROSKA_TRACK_TYPE_METADATA = 0x21,
} MatroskaTrackType;
typedef enum {
@@ -245,17 +269,33 @@ typedef enum {
*/
typedef struct CodecTags{
- char str[20];
+ char str[22];
enum AVCodecID id;
}CodecTags;
/* max. depth in the EBML tree structure */
#define EBML_MAX_DEPTH 16
+#define MATROSKA_VIDEO_STEREO_PLANE_COUNT 3
+
extern const CodecTags ff_mkv_codec_tags[];
extern const CodecMime ff_mkv_mime_tags[];
extern const CodecMime ff_mkv_image_mime_tags[];
extern const AVMetadataConv ff_mkv_metadata_conv[];
+extern const char * const ff_matroska_video_stereo_mode[MATROSKA_VIDEO_STEREOMODE_TYPE_NB];
+extern const char * const ff_matroska_video_stereo_plane[MATROSKA_VIDEO_STEREO_PLANE_COUNT];
+
+/* AVStream Metadata tag keys for WebM Dash Manifest */
+#define INITIALIZATION_RANGE "webm_dash_manifest_initialization_range"
+#define CUES_START "webm_dash_manifest_cues_start"
+#define CUES_END "webm_dash_manifest_cues_end"
+#define FILENAME "webm_dash_manifest_file_name"
+#define BANDWIDTH "webm_dash_manifest_bandwidth"
+#define DURATION "webm_dash_manifest_duration"
+#define CLUSTER_KEYFRAME "webm_dash_manifest_cluster_keyframe"
+#define CUE_TIMESTAMPS "webm_dash_manifest_cue_timestamps"
+#define TRACK_NUMBER "webm_dash_manifest_track_number"
+#define CODEC_PRIVATE_SIZE "webm_dash_manifest_codec_priv_size"
int ff_mkv_stereo3d_conv(AVStream *st, MatroskaVideoStereoModeType stereo_mode);
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 34bbf37252..16063412de 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1,21 +1,21 @@
/*
* Matroska file demuxer
- * Copyright (c) 2003-2008 The Libav Project
+ * Copyright (c) 2003-2008 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,19 +32,16 @@
#include <inttypes.h>
#include <stdio.h>
-#if CONFIG_BZLIB
-#include <bzlib.h>
-#endif
-#if CONFIG_ZLIB
-#include <zlib.h>
-#endif
#include "libavutil/avstring.h"
+#include "libavutil/base64.h"
#include "libavutil/dict.h"
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/lzo.h"
#include "libavutil/mathematics.h"
+#include "libavutil/opt.h"
+#include "libavutil/time_internal.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/flac.h"
@@ -60,6 +57,13 @@
#include "riff.h"
#include "rmsipr.h"
+#if CONFIG_BZLIB
+#include <bzlib.h>
+#endif
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
typedef enum {
EBML_NONE,
EBML_UINT,
@@ -68,8 +72,10 @@ typedef enum {
EBML_UTF8,
EBML_BIN,
EBML_NEST,
+ EBML_LEVEL1,
EBML_PASS,
EBML_STOP,
+ EBML_SINT,
EBML_TYPE_COUNT
} EbmlType;
@@ -110,10 +116,16 @@ typedef struct MatroskaTrackCompression {
EbmlBin settings;
} MatroskaTrackCompression;
+typedef struct MatroskaTrackEncryption {
+ uint64_t algo;
+ EbmlBin key_id;
+} MatroskaTrackEncryption;
+
typedef struct MatroskaTrackEncoding {
uint64_t scope;
uint64_t type;
MatroskaTrackCompression compression;
+ MatroskaTrackEncryption encryption;
} MatroskaTrackEncoding;
typedef struct MatroskaTrackVideo {
@@ -122,8 +134,9 @@ typedef struct MatroskaTrackVideo {
uint64_t display_height;
uint64_t pixel_width;
uint64_t pixel_height;
- uint64_t fourcc;
+ EbmlBin color_space;
uint64_t stereo_mode;
+ uint64_t alpha_mode;
} MatroskaTrackVideo;
typedef struct MatroskaTrackAudio {
@@ -143,6 +156,15 @@ typedef struct MatroskaTrackAudio {
uint8_t *buf;
} MatroskaTrackAudio;
+typedef struct MatroskaTrackPlane {
+ uint64_t uid;
+ uint64_t type;
+} MatroskaTrackPlane;
+
+typedef struct MatroskaTrackOperation {
+ EbmlList combine_planes;
+} MatroskaTrackOperation;
+
typedef struct MatroskaTrack {
uint64_t num;
uint64_t uid;
@@ -155,14 +177,17 @@ typedef struct MatroskaTrack {
uint64_t default_duration;
uint64_t flag_default;
uint64_t flag_forced;
+ uint64_t seek_preroll;
MatroskaTrackVideo video;
MatroskaTrackAudio audio;
+ MatroskaTrackOperation operation;
EbmlList encodings;
uint64_t codec_delay;
AVStream *stream;
int64_t end_timecode;
int ms_compat;
+ uint64_t max_block_additional_id;
} MatroskaTrack;
typedef struct MatroskaAttachment {
@@ -229,7 +254,14 @@ typedef struct MatroskaCluster {
EbmlList blocks;
} MatroskaCluster;
+typedef struct MatroskaLevel1Element {
+ uint64_t id;
+ uint64_t pos;
+ int parsed;
+} MatroskaLevel1Element;
+
typedef struct MatroskaDemuxContext {
+ const AVClass *class;
AVFormatContext *ctx;
/* EBML stuff */
@@ -241,6 +273,8 @@ typedef struct MatroskaDemuxContext {
uint64_t time_scale;
double duration;
char *title;
+ char *muxingapp;
+ EbmlBin date_utc;
EbmlList tracks;
EbmlList attachments;
EbmlList chapters;
@@ -265,12 +299,19 @@ typedef struct MatroskaDemuxContext {
/* File has a CUES element, but we defer parsing until it is needed. */
int cues_parsing_deferred;
+ /* Level1 elements and whether they were read yet */
+ MatroskaLevel1Element level1_elems[64];
+ int num_level1_elems;
+
int current_cluster_num_blocks;
int64_t current_cluster_pos;
MatroskaCluster current_cluster;
/* File has SSA subtitles which prevent incremental cluster parsing. */
int contains_ssa;
+
+ /* WebM DASH Manifest live flag/ */
+ int is_live;
} MatroskaDemuxContext;
typedef struct MatroskaBlock {
@@ -278,9 +319,12 @@ typedef struct MatroskaBlock {
int64_t reference;
uint64_t non_simple;
EbmlBin bin;
+ uint64_t additional_id;
+ EbmlBin additional;
+ int64_t discard_padding;
} MatroskaBlock;
-static EbmlSyntax ebml_header[] = {
+static const EbmlSyntax ebml_header[] = {
{ EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml, version), { .u = EBML_VERSION } },
{ EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml, max_size), { .u = 8 } },
{ EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, offsetof(Ebml, id_length), { .u = 4 } },
@@ -291,29 +335,30 @@ static EbmlSyntax ebml_header[] = {
{ 0 }
};
-static EbmlSyntax ebml_syntax[] = {
+static const EbmlSyntax ebml_syntax[] = {
{ EBML_ID_HEADER, EBML_NEST, 0, 0, { .n = ebml_header } },
{ 0 }
};
-static EbmlSyntax matroska_info[] = {
+static const EbmlSyntax matroska_info[] = {
{ MATROSKA_ID_TIMECODESCALE, EBML_UINT, 0, offsetof(MatroskaDemuxContext, time_scale), { .u = 1000000 } },
{ MATROSKA_ID_DURATION, EBML_FLOAT, 0, offsetof(MatroskaDemuxContext, duration) },
{ MATROSKA_ID_TITLE, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, title) },
{ MATROSKA_ID_WRITINGAPP, EBML_NONE },
- { MATROSKA_ID_MUXINGAPP, EBML_NONE },
- { MATROSKA_ID_DATEUTC, EBML_NONE },
+ { MATROSKA_ID_MUXINGAPP, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, muxingapp) },
+ { MATROSKA_ID_DATEUTC, EBML_BIN, 0, offsetof(MatroskaDemuxContext, date_utc) },
{ MATROSKA_ID_SEGMENTUID, EBML_NONE },
{ 0 }
};
-static EbmlSyntax matroska_track_video[] = {
+static const EbmlSyntax matroska_track_video[] = {
{ MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT, 0, offsetof(MatroskaTrackVideo, frame_rate) },
- { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_width) },
- { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_height) },
+ { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_width), { .u=-1 } },
+ { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_height), { .u=-1 } },
{ MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, pixel_width) },
{ MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, pixel_height) },
- { MATROSKA_ID_VIDEOCOLORSPACE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, fourcc) },
+ { MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, offsetof(MatroskaTrackVideo, color_space) },
+ { MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, alpha_mode) },
{ MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE },
{ MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE },
{ MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE },
@@ -325,7 +370,7 @@ static EbmlSyntax matroska_track_video[] = {
{ 0 }
};
-static EbmlSyntax matroska_track_audio[] = {
+static const EbmlSyntax matroska_track_audio[] = {
{ MATROSKA_ID_AUDIOSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, samplerate), { .f = 8000.0 } },
{ MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, out_samplerate) },
{ MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, offsetof(MatroskaTrackAudio, bitdepth) },
@@ -333,26 +378,53 @@ static EbmlSyntax matroska_track_audio[] = {
{ 0 }
};
-static EbmlSyntax matroska_track_encoding_compression[] = {
+static const EbmlSyntax matroska_track_encoding_compression[] = {
{ MATROSKA_ID_ENCODINGCOMPALGO, EBML_UINT, 0, offsetof(MatroskaTrackCompression, algo), { .u = 0 } },
{ MATROSKA_ID_ENCODINGCOMPSETTINGS, EBML_BIN, 0, offsetof(MatroskaTrackCompression, settings) },
{ 0 }
};
-static EbmlSyntax matroska_track_encoding[] = {
+static const EbmlSyntax matroska_track_encoding_encryption[] = {
+ { MATROSKA_ID_ENCODINGENCALGO, EBML_UINT, 0, offsetof(MatroskaTrackEncryption,algo), {.u = 0} },
+ { MATROSKA_ID_ENCODINGENCKEYID, EBML_BIN, 0, offsetof(MatroskaTrackEncryption,key_id) },
+ { MATROSKA_ID_ENCODINGENCAESSETTINGS, EBML_NONE },
+ { MATROSKA_ID_ENCODINGSIGALGO, EBML_NONE },
+ { MATROSKA_ID_ENCODINGSIGHASHALGO, EBML_NONE },
+ { MATROSKA_ID_ENCODINGSIGKEYID, EBML_NONE },
+ { MATROSKA_ID_ENCODINGSIGNATURE, EBML_NONE },
+ { 0 }
+};
+static const EbmlSyntax matroska_track_encoding[] = {
{ MATROSKA_ID_ENCODINGSCOPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding, scope), { .u = 1 } },
{ MATROSKA_ID_ENCODINGTYPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding, type), { .u = 0 } },
{ MATROSKA_ID_ENCODINGCOMPRESSION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding, compression), { .n = matroska_track_encoding_compression } },
+ { MATROSKA_ID_ENCODINGENCRYPTION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding, encryption), { .n = matroska_track_encoding_encryption } },
{ MATROSKA_ID_ENCODINGORDER, EBML_NONE },
{ 0 }
};
-static EbmlSyntax matroska_track_encodings[] = {
+static const EbmlSyntax matroska_track_encodings[] = {
{ MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(MatroskaTrackEncoding), offsetof(MatroskaTrack, encodings), { .n = matroska_track_encoding } },
{ 0 }
};
-static EbmlSyntax matroska_track[] = {
+static const EbmlSyntax matroska_track_plane[] = {
+ { MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) },
+ { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) },
+ { 0 }
+};
+
+static const EbmlSyntax matroska_track_combine_planes[] = {
+ { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n = matroska_track_plane} },
+ { 0 }
+};
+
+static const EbmlSyntax matroska_track_operation[] = {
+ { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n = matroska_track_combine_planes} },
+ { 0 }
+};
+
+static const EbmlSyntax matroska_track[] = {
{ MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack, num) },
{ MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack, name) },
{ MATROSKA_ID_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTrack, uid) },
@@ -360,14 +432,17 @@ static EbmlSyntax matroska_track[] = {
{ MATROSKA_ID_CODECID, EBML_STR, 0, offsetof(MatroskaTrack, codec_id) },
{ MATROSKA_ID_CODECPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrack, codec_priv) },
{ MATROSKA_ID_CODECDELAY, EBML_UINT, 0, offsetof(MatroskaTrack, codec_delay) },
- { MATROSKA_ID_TRACKLANGUAGE, EBML_UTF8, 0, offsetof(MatroskaTrack, language), { .s = "eng" } },
+ { MATROSKA_ID_TRACKLANGUAGE, EBML_UTF8, 0, offsetof(MatroskaTrack, language), { .s = "eng" } },
{ MATROSKA_ID_TRACKDEFAULTDURATION, EBML_UINT, 0, offsetof(MatroskaTrack, default_duration) },
- { MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT, 0, offsetof(MatroskaTrack, time_scale), { .f = 1.0 } },
- { MATROSKA_ID_TRACKFLAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTrack, flag_default), { .u = 1 } },
- { MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, offsetof(MatroskaTrack, flag_forced), { .u = 0 } },
+ { MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT, 0, offsetof(MatroskaTrack, time_scale), { .f = 1.0 } },
+ { MATROSKA_ID_TRACKFLAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTrack, flag_default), { .u = 1 } },
+ { MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, offsetof(MatroskaTrack, flag_forced), { .u = 0 } },
{ MATROSKA_ID_TRACKVIDEO, EBML_NEST, 0, offsetof(MatroskaTrack, video), { .n = matroska_track_video } },
{ MATROSKA_ID_TRACKAUDIO, EBML_NEST, 0, offsetof(MatroskaTrack, audio), { .n = matroska_track_audio } },
+ { MATROSKA_ID_TRACKOPERATION, EBML_NEST, 0, offsetof(MatroskaTrack, operation), { .n = matroska_track_operation } },
{ MATROSKA_ID_TRACKCONTENTENCODINGS, EBML_NEST, 0, 0, { .n = matroska_track_encodings } },
+ { MATROSKA_ID_TRACKMAXBLKADDID, EBML_UINT, 0, offsetof(MatroskaTrack, max_block_additional_id) },
+ { MATROSKA_ID_SEEKPREROLL, EBML_UINT, 0, offsetof(MatroskaTrack, seek_preroll) },
{ MATROSKA_ID_TRACKFLAGENABLED, EBML_NONE },
{ MATROSKA_ID_TRACKFLAGLACING, EBML_NONE },
{ MATROSKA_ID_CODECNAME, EBML_NONE },
@@ -376,16 +451,15 @@ static EbmlSyntax matroska_track[] = {
{ MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE },
{ MATROSKA_ID_TRACKMINCACHE, EBML_NONE },
{ MATROSKA_ID_TRACKMAXCACHE, EBML_NONE },
- { MATROSKA_ID_TRACKMAXBLKADDID, EBML_NONE },
{ 0 }
};
-static EbmlSyntax matroska_tracks[] = {
+static const EbmlSyntax matroska_tracks[] = {
{ MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(MatroskaTrack), offsetof(MatroskaDemuxContext, tracks), { .n = matroska_track } },
{ 0 }
};
-static EbmlSyntax matroska_attachment[] = {
+static const EbmlSyntax matroska_attachment[] = {
{ MATROSKA_ID_FILEUID, EBML_UINT, 0, offsetof(MatroskaAttachment, uid) },
{ MATROSKA_ID_FILENAME, EBML_UTF8, 0, offsetof(MatroskaAttachment, filename) },
{ MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, offsetof(MatroskaAttachment, mime) },
@@ -394,18 +468,18 @@ static EbmlSyntax matroska_attachment[] = {
{ 0 }
};
-static EbmlSyntax matroska_attachments[] = {
+static const EbmlSyntax matroska_attachments[] = {
{ MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachment), offsetof(MatroskaDemuxContext, attachments), { .n = matroska_attachment } },
{ 0 }
};
-static EbmlSyntax matroska_chapter_display[] = {
+static const EbmlSyntax matroska_chapter_display[] = {
{ MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, offsetof(MatroskaChapter, title) },
{ MATROSKA_ID_CHAPLANG, EBML_NONE },
{ 0 }
};
-static EbmlSyntax matroska_chapter_entry[] = {
+static const EbmlSyntax matroska_chapter_entry[] = {
{ MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, offsetof(MatroskaChapter, start), { .u = AV_NOPTS_VALUE } },
{ MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, offsetof(MatroskaChapter, end), { .u = AV_NOPTS_VALUE } },
{ MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaChapter, uid) },
@@ -417,7 +491,7 @@ static EbmlSyntax matroska_chapter_entry[] = {
{ 0 }
};
-static EbmlSyntax matroska_chapter[] = {
+static const EbmlSyntax matroska_chapter[] = {
{ MATROSKA_ID_CHAPTERATOM, EBML_NEST, sizeof(MatroskaChapter), offsetof(MatroskaDemuxContext, chapters), { .n = matroska_chapter_entry } },
{ MATROSKA_ID_EDITIONUID, EBML_NONE },
{ MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE },
@@ -426,30 +500,32 @@ static EbmlSyntax matroska_chapter[] = {
{ 0 }
};
-static EbmlSyntax matroska_chapters[] = {
+static const EbmlSyntax matroska_chapters[] = {
{ MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, { .n = matroska_chapter } },
{ 0 }
};
-static EbmlSyntax matroska_index_pos[] = {
+static const EbmlSyntax matroska_index_pos[] = {
{ MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos, track) },
{ MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos, pos) },
+ { MATROSKA_ID_CUERELATIVEPOSITION,EBML_NONE },
+ { MATROSKA_ID_CUEDURATION, EBML_NONE },
{ MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE },
{ 0 }
};
-static EbmlSyntax matroska_index_entry[] = {
+static const EbmlSyntax matroska_index_entry[] = {
{ MATROSKA_ID_CUETIME, EBML_UINT, 0, offsetof(MatroskaIndex, time) },
{ MATROSKA_ID_CUETRACKPOSITION, EBML_NEST, sizeof(MatroskaIndexPos), offsetof(MatroskaIndex, pos), { .n = matroska_index_pos } },
{ 0 }
};
-static EbmlSyntax matroska_index[] = {
+static const EbmlSyntax matroska_index[] = {
{ MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(MatroskaIndex), offsetof(MatroskaDemuxContext, index), { .n = matroska_index_entry } },
{ 0 }
};
-static EbmlSyntax matroska_simpletag[] = {
+static const EbmlSyntax matroska_simpletag[] = {
{ MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag, name) },
{ MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag, string) },
{ MATROSKA_ID_TAGLANG, EBML_STR, 0, offsetof(MatroskaTag, lang), { .s = "und" } },
@@ -459,7 +535,7 @@ static EbmlSyntax matroska_simpletag[] = {
{ 0 }
};
-static EbmlSyntax matroska_tagtargets[] = {
+static const EbmlSyntax matroska_tagtargets[] = {
{ MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, offsetof(MatroskaTagTarget, type) },
{ MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, offsetof(MatroskaTagTarget, typevalue), { .u = 50 } },
{ MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, trackuid) },
@@ -468,56 +544,69 @@ static EbmlSyntax matroska_tagtargets[] = {
{ 0 }
};
-static EbmlSyntax matroska_tag[] = {
+static const EbmlSyntax matroska_tag[] = {
{ MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTags, tag), { .n = matroska_simpletag } },
{ MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, offsetof(MatroskaTags, target), { .n = matroska_tagtargets } },
{ 0 }
};
-static EbmlSyntax matroska_tags[] = {
+static const EbmlSyntax matroska_tags[] = {
{ MATROSKA_ID_TAG, EBML_NEST, sizeof(MatroskaTags), offsetof(MatroskaDemuxContext, tags), { .n = matroska_tag } },
{ 0 }
};
-static EbmlSyntax matroska_seekhead_entry[] = {
+static const EbmlSyntax matroska_seekhead_entry[] = {
{ MATROSKA_ID_SEEKID, EBML_UINT, 0, offsetof(MatroskaSeekhead, id) },
{ MATROSKA_ID_SEEKPOSITION, EBML_UINT, 0, offsetof(MatroskaSeekhead, pos), { .u = -1 } },
{ 0 }
};
-static EbmlSyntax matroska_seekhead[] = {
+static const EbmlSyntax matroska_seekhead[] = {
{ MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(MatroskaSeekhead), offsetof(MatroskaDemuxContext, seekhead), { .n = matroska_seekhead_entry } },
{ 0 }
};
-static EbmlSyntax matroska_segment[] = {
- { MATROSKA_ID_INFO, EBML_NEST, 0, 0, { .n = matroska_info } },
- { MATROSKA_ID_TRACKS, EBML_NEST, 0, 0, { .n = matroska_tracks } },
- { MATROSKA_ID_ATTACHMENTS, EBML_NEST, 0, 0, { .n = matroska_attachments } },
- { MATROSKA_ID_CHAPTERS, EBML_NEST, 0, 0, { .n = matroska_chapters } },
- { MATROSKA_ID_CUES, EBML_NEST, 0, 0, { .n = matroska_index } },
- { MATROSKA_ID_TAGS, EBML_NEST, 0, 0, { .n = matroska_tags } },
- { MATROSKA_ID_SEEKHEAD, EBML_NEST, 0, 0, { .n = matroska_seekhead } },
+static const EbmlSyntax matroska_segment[] = {
+ { MATROSKA_ID_INFO, EBML_LEVEL1, 0, 0, { .n = matroska_info } },
+ { MATROSKA_ID_TRACKS, EBML_LEVEL1, 0, 0, { .n = matroska_tracks } },
+ { MATROSKA_ID_ATTACHMENTS, EBML_LEVEL1, 0, 0, { .n = matroska_attachments } },
+ { MATROSKA_ID_CHAPTERS, EBML_LEVEL1, 0, 0, { .n = matroska_chapters } },
+ { MATROSKA_ID_CUES, EBML_LEVEL1, 0, 0, { .n = matroska_index } },
+ { MATROSKA_ID_TAGS, EBML_LEVEL1, 0, 0, { .n = matroska_tags } },
+ { MATROSKA_ID_SEEKHEAD, EBML_LEVEL1, 0, 0, { .n = matroska_seekhead } },
{ MATROSKA_ID_CLUSTER, EBML_STOP },
{ 0 }
};
-static EbmlSyntax matroska_segments[] = {
+static const EbmlSyntax matroska_segments[] = {
{ MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, { .n = matroska_segment } },
{ 0 }
};
-static EbmlSyntax matroska_blockgroup[] = {
+static const EbmlSyntax matroska_blockmore[] = {
+ { MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, offsetof(MatroskaBlock,additional_id) },
+ { MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, offsetof(MatroskaBlock,additional) },
+ { 0 }
+};
+
+static const EbmlSyntax matroska_blockadditions[] = {
+ { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n = matroska_blockmore} },
+ { 0 }
+};
+
+static const EbmlSyntax matroska_blockgroup[] = {
{ MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) },
+ { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, { .n = matroska_blockadditions} },
{ MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) },
- { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration), { .u = AV_NOPTS_VALUE } },
- { MATROSKA_ID_BLOCKREFERENCE, EBML_UINT, 0, offsetof(MatroskaBlock, reference) },
+ { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration) },
+ { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock, discard_padding) },
+ { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference) },
{ MATROSKA_ID_CODECSTATE, EBML_NONE },
{ 1, EBML_UINT, 0, offsetof(MatroskaBlock, non_simple), { .u = 1 } },
{ 0 }
};
-static EbmlSyntax matroska_cluster[] = {
+static const EbmlSyntax matroska_cluster[] = {
{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) },
{ MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } },
{ MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } },
@@ -526,7 +615,7 @@ static EbmlSyntax matroska_cluster[] = {
{ 0 }
};
-static EbmlSyntax matroska_clusters[] = {
+static const EbmlSyntax matroska_clusters[] = {
{ MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster } },
{ MATROSKA_ID_INFO, EBML_NONE },
{ MATROSKA_ID_CUES, EBML_NONE },
@@ -535,7 +624,7 @@ static EbmlSyntax matroska_clusters[] = {
{ 0 }
};
-static EbmlSyntax matroska_cluster_incremental_parsing[] = {
+static const EbmlSyntax matroska_cluster_incremental_parsing[] = {
{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) },
{ MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } },
{ MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } },
@@ -549,7 +638,7 @@ static EbmlSyntax matroska_cluster_incremental_parsing[] = {
{ 0 }
};
-static EbmlSyntax matroska_cluster_incremental[] = {
+static const EbmlSyntax matroska_cluster_incremental[] = {
{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) },
{ MATROSKA_ID_BLOCKGROUP, EBML_STOP },
{ MATROSKA_ID_SIMPLEBLOCK, EBML_STOP },
@@ -558,7 +647,7 @@ static EbmlSyntax matroska_cluster_incremental[] = {
{ 0 }
};
-static EbmlSyntax matroska_clusters_incremental[] = {
+static const EbmlSyntax matroska_clusters_incremental[] = {
{ MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster_incremental } },
{ MATROSKA_ID_INFO, EBML_NONE },
{ MATROSKA_ID_CUES, EBML_NONE },
@@ -583,7 +672,7 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos)
id = avio_rb32(pb);
// try to find a toplevel element
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS ||
id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS ||
id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS ||
@@ -614,7 +703,7 @@ static int ebml_level_end(MatroskaDemuxContext *matroska)
return 1;
}
}
- return 0;
+ return (matroska->is_live && matroska->ctx->pb->eof_reached) ? 1 : 0;
}
/*
@@ -636,7 +725,7 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, AVIOContext *pb,
* use it safely here to catch EOS. */
if (!(total = avio_r8(pb))) {
/* we might encounter EOS here */
- if (!pb->eof_reached) {
+ if (!avio_feof(pb)) {
int64_t pos = avio_tell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
"Read error at pos. %"PRIu64" (0x%"PRIx64")\n",
@@ -700,6 +789,30 @@ static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num)
}
/*
+ * Read the next element as a signed int.
+ * 0 is success, < 0 is failure.
+ */
+static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num)
+{
+ int n = 1;
+
+ if (size > 8)
+ return AVERROR_INVALIDDATA;
+
+ if (size == 0) {
+ *num = 0;
+ } else {
+ *num = sign_extend(avio_r8(pb), 8);
+
+ /* big-endian ordering; build up number */
+ while (n++ < size)
+ *num = (*num << 8) | avio_r8(pb);
+ }
+
+ return 0;
+}
+
+/*
* Read the next element as a float.
* 0 is success, < 0 is failure.
*/
@@ -746,14 +859,15 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
*/
static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin)
{
- av_free(bin->data);
- if (!(bin->data = av_mallocz(length + FF_INPUT_BUFFER_PADDING_SIZE)))
+ av_fast_padded_malloc(&bin->data, &bin->size, length);
+ if (!bin->data)
return AVERROR(ENOMEM);
bin->size = length;
bin->pos = avio_tell(pb);
if (avio_read(pb, bin->data, length) != length) {
av_freep(&bin->data);
+ bin->size = 0;
return AVERROR(EIO);
}
@@ -829,9 +943,7 @@ static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
matroska->levels[matroska->num_levels - 1].length == 0xffffffffffffff)
return 0; // we reached the end of an unknown size cluster
if (!syntax[i].id && id != EBML_ID_VOID && id != EBML_ID_CRC32) {
- av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%"PRIX32"\n", id);
- if (matroska->ctx->error_recognition & AV_EF_EXPLODE)
- return AVERROR_INVALIDDATA;
+ av_log(matroska->ctx, AV_LOG_DEBUG, "Unknown entry 0x%"PRIX32"\n", id);
}
return ebml_parse_elem(matroska, &syntax[i], data);
}
@@ -842,8 +954,11 @@ static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
if (!matroska->current_id) {
uint64_t id;
int res = ebml_read_num(matroska, matroska->ctx->pb, 4, &id);
- if (res < 0)
- return res;
+ if (res < 0) {
+ // in live mode, finish parsing if EOF is reached.
+ return (matroska->is_live && matroska->ctx->pb->eof_reached &&
+ res == AVERROR_EOF) ? 1 : res;
+ }
matroska->current_id = id | 1 << 7 * res;
}
return ebml_parse_id(matroska, syntax, matroska->current_id, data);
@@ -880,6 +995,42 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax,
return res;
}
+/*
+ * Allocate and return the entry for the level1 element with the given ID. If
+ * an entry already exists, return the existing entry.
+ */
+static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *matroska,
+ uint32_t id)
+{
+ int i;
+ MatroskaLevel1Element *elem;
+
+ // Some files link to all clusters; useless.
+ if (id == MATROSKA_ID_CLUSTER)
+ return NULL;
+
+ // There can be multiple seekheads.
+ if (id != MATROSKA_ID_SEEKHEAD) {
+ for (i = 0; i < matroska->num_level1_elems; i++) {
+ if (matroska->level1_elems[i].id == id)
+ return &matroska->level1_elems[i];
+ }
+ }
+
+ // Only a completely broken file would have more elements.
+ // It also provides a low-effort way to escape from circular seekheads
+ // (every iteration will add a level1 entry).
+ if (matroska->num_level1_elems >= FF_ARRAY_ELEMS(matroska->level1_elems)) {
+ av_log(matroska->ctx, AV_LOG_ERROR, "Too many level1 elements or circular seekheads.\n");
+ return NULL;
+ }
+
+ elem = &matroska->level1_elems[matroska->num_level1_elems++];
+ *elem = (MatroskaLevel1Element){.id = id};
+
+ return elem;
+}
+
static int ebml_parse_elem(MatroskaDemuxContext *matroska,
EbmlSyntax *syntax, void *data)
{
@@ -897,16 +1048,16 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
uint32_t id = syntax->id;
uint64_t length;
int res;
+ void *newelem;
+ MatroskaLevel1Element *level1_elem;
data = (char *) data + syntax->data_offset;
if (syntax->list_elem_size) {
EbmlList *list = data;
- if ((res = av_reallocp_array(&list->elem,
- list->nb_elem + 1,
- syntax->list_elem_size)) < 0) {
- list->nb_elem = 0;
- return res;
- }
+ newelem = av_realloc_array(list->elem, list->nb_elem + 1, syntax->list_elem_size);
+ if (!newelem)
+ return AVERROR(ENOMEM);
+ list->elem = newelem;
data = (char *) list->elem + list->nb_elem * syntax->list_elem_size;
memset(data, 0, syntax->list_elem_size);
list->nb_elem++;
@@ -928,6 +1079,9 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
case EBML_UINT:
res = ebml_read_uint(pb, length, data);
break;
+ case EBML_SINT:
+ res = ebml_read_sint(pb, length, data);
+ break;
case EBML_FLOAT:
res = ebml_read_float(pb, length, data);
break;
@@ -938,17 +1092,28 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
case EBML_BIN:
res = ebml_read_binary(pb, length, data);
break;
+ case EBML_LEVEL1:
case EBML_NEST:
if ((res = ebml_read_master(matroska, length)) < 0)
return res;
if (id == MATROSKA_ID_SEGMENT)
matroska->segment_start = avio_tell(matroska->ctx->pb);
+ if (id == MATROSKA_ID_CUES)
+ matroska->cues_parsing_deferred = 0;
+ if (syntax->type == EBML_LEVEL1 &&
+ (level1_elem = matroska_find_level1_elem(matroska, syntax->id))) {
+ if (level1_elem->parsed)
+ av_log(matroska->ctx, AV_LOG_ERROR, "Duplicate element\n");
+ level1_elem->parsed = 1;
+ }
return ebml_parse_nest(matroska, syntax->def.n, data);
case EBML_PASS:
return ebml_parse_id(matroska, syntax->def.n, id, data);
case EBML_STOP:
return 1;
default:
+ if (ffio_limit(pb, length) != length)
+ return AVERROR(EIO);
return avio_skip(pb, length) < 0 ? AVERROR(EIO) : 0;
}
if (res == AVERROR_INVALIDDATA)
@@ -971,6 +1136,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data)
case EBML_BIN:
av_freep(&((EbmlBin *) data_off)->data);
break;
+ case EBML_LEVEL1:
case EBML_NEST:
if (syntax[i].list_elem_size) {
EbmlList *list = data_off;
@@ -978,7 +1144,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data)
for (j = 0; j < list->nb_elem;
j++, ptr += syntax[i].list_elem_size)
ebml_free(syntax[i].def.n, ptr);
- av_free(list->elem);
+ av_freep(&list->elem);
} else
ebml_free(syntax[i].def.n, data_off);
default:
@@ -1020,7 +1186,7 @@ static int matroska_probe(AVProbeData *p)
* availability of that array of characters inside the header.
* Not fully fool-proof, but good enough. */
for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++) {
- int probelen = strlen(matroska_doctypes[i]);
+ size_t probelen = strlen(matroska_doctypes[i]);
if (total < probelen)
continue;
for (n = 4 + size; n <= 4 + size + total - probelen; n++)
@@ -1058,7 +1224,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
int result = 0;
int olen;
- if (pkt_size >= 10000000)
+ if (pkt_size >= 10000000U)
return AVERROR_INVALIDDATA;
switch (encodings[0].compression.algo) {
@@ -1067,6 +1233,11 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
int header_size = encodings[0].compression.settings.size;
uint8_t *header = encodings[0].compression.settings.data;
+ if (header_size && !header) {
+ av_log(NULL, AV_LOG_ERROR, "Compression size but no data in headerstrip\n");
+ return -1;
+ }
+
if (!header_size)
return 0;
@@ -1111,12 +1282,13 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
newpktdata = av_realloc(pkt_data, pkt_size);
if (!newpktdata) {
inflateEnd(&zstream);
+ result = AVERROR(ENOMEM);
goto failed;
}
pkt_data = newpktdata;
zstream.avail_out = pkt_size - zstream.total_out;
zstream.next_out = pkt_data + zstream.total_out;
- result = inflate(&zstream, Z_NO_FLUSH);
+ result = inflate(&zstream, Z_NO_FLUSH);
} while (result == Z_OK && pkt_size < 10000000);
pkt_size = zstream.total_out;
inflateEnd(&zstream);
@@ -1143,12 +1315,13 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
newpktdata = av_realloc(pkt_data, pkt_size);
if (!newpktdata) {
BZ2_bzDecompressEnd(&bzstream);
+ result = AVERROR(ENOMEM);
goto failed;
}
pkt_data = newpktdata;
bzstream.avail_out = pkt_size - bzstream.total_out_lo32;
bzstream.next_out = pkt_data + bzstream.total_out_lo32;
- result = BZ2_bzDecompress(&bzstream);
+ result = BZ2_bzDecompress(&bzstream);
} while (result == BZ_OK && pkt_size < 10000000);
pkt_size = bzstream.total_out_lo32;
BZ2_bzDecompressEnd(&bzstream);
@@ -1175,63 +1348,6 @@ failed:
return result;
}
-static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
- AVPacket *pkt, uint64_t display_duration)
-{
- AVBufferRef *line;
- char *layer, *ptr = pkt->data, *end = ptr + pkt->size;
-
- for (; *ptr != ',' && ptr < end - 1; ptr++)
- ;
- if (*ptr == ',')
- layer = ++ptr;
- for (; *ptr != ',' && ptr < end - 1; ptr++)
- ;
- if (*ptr == ',') {
- int64_t end_pts = pkt->pts + display_duration;
- int sc = matroska->time_scale * pkt->pts / 10000000;
- int ec = matroska->time_scale * end_pts / 10000000;
- int sh, sm, ss, eh, em, es, len;
- sh = sc / 360000;
- sc -= 360000 * sh;
- sm = sc / 6000;
- sc -= 6000 * sm;
- ss = sc / 100;
- sc -= 100 * ss;
- eh = ec / 360000;
- ec -= 360000 * eh;
- em = ec / 6000;
- ec -= 6000 * em;
- es = ec / 100;
- ec -= 100 * es;
- *ptr++ = '\0';
- len = 50 + end - ptr + FF_INPUT_BUFFER_PADDING_SIZE;
- if (!(line = av_buffer_alloc(len)))
- return;
- snprintf(line->data, len,
- "Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
- layer, sh, sm, ss, sc, eh, em, es, ec, ptr);
- av_buffer_unref(&pkt->buf);
- pkt->buf = line;
- pkt->data = line->data;
- pkt->size = strlen(line->data);
- }
-}
-
-static int matroska_merge_packets(AVPacket *out, AVPacket *in)
-{
- int old_size = out->size;
- int ret = av_grow_packet(out, in->size);
- if (ret < 0)
- return ret;
-
- memcpy(out->data + old_size, in->data, in->size);
-
- av_free_packet(in);
- av_free(in);
- return 0;
-}
-
static void matroska_convert_tag(AVFormatContext *s, EbmlList *list,
AVDictionary **metadata, char *prefix)
{
@@ -1302,24 +1418,17 @@ static void matroska_convert_tags(AVFormatContext *s)
}
static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska,
- int idx)
+ uint64_t pos)
{
- EbmlList *seekhead_list = &matroska->seekhead;
uint32_t level_up = matroska->level_up;
uint32_t saved_id = matroska->current_id;
- MatroskaSeekhead *seekhead = seekhead_list->elem;
int64_t before_pos = avio_tell(matroska->ctx->pb);
MatroskaLevel level;
int64_t offset;
int ret = 0;
- if (idx >= seekhead_list->nb_elem ||
- seekhead[idx].id == MATROSKA_ID_SEEKHEAD ||
- seekhead[idx].id == MATROSKA_ID_CLUSTER)
- return 0;
-
/* seek */
- offset = seekhead[idx].pos + matroska->segment_start;
+ offset = pos + matroska->segment_start;
if (avio_seek(matroska->ctx->pb, offset, SEEK_SET) == offset) {
/* We don't want to lose our seekhead level, so we add
* a dummy. This is a crude hack. */
@@ -1356,45 +1465,46 @@ static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska,
static void matroska_execute_seekhead(MatroskaDemuxContext *matroska)
{
EbmlList *seekhead_list = &matroska->seekhead;
- int64_t before_pos = avio_tell(matroska->ctx->pb);
int i;
// we should not do any seeking in the streaming case
- if (!matroska->ctx->pb->seekable ||
- (matroska->ctx->flags & AVFMT_FLAG_IGNIDX))
+ if (!matroska->ctx->pb->seekable)
return;
for (i = 0; i < seekhead_list->nb_elem; i++) {
- MatroskaSeekhead *seekhead = seekhead_list->elem;
- if (seekhead[i].pos <= before_pos)
+ MatroskaSeekhead *seekheads = seekhead_list->elem;
+ uint32_t id = seekheads[i].id;
+ uint64_t pos = seekheads[i].pos;
+
+ MatroskaLevel1Element *elem = matroska_find_level1_elem(matroska, id);
+ if (!elem || elem->parsed)
continue;
+ elem->pos = pos;
+
// defer cues parsing until we actually need cue data.
- if (seekhead[i].id == MATROSKA_ID_CUES) {
- matroska->cues_parsing_deferred = 1;
+ if (id == MATROSKA_ID_CUES)
continue;
- }
- if (matroska_parse_seekhead_entry(matroska, i) < 0)
+ if (matroska_parse_seekhead_entry(matroska, pos) < 0) {
+ // mark index as broken
+ matroska->cues_parsing_deferred = -1;
break;
+ }
+
+ elem->parsed = 1;
}
}
-static void matroska_parse_cues(MatroskaDemuxContext *matroska)
+static void matroska_add_index_entries(MatroskaDemuxContext *matroska)
{
- EbmlList *seekhead_list = &matroska->seekhead;
- MatroskaSeekhead *seekhead = seekhead_list->elem;
EbmlList *index_list;
MatroskaIndex *index;
- int index_scale = 1;
+ uint64_t index_scale = 1;
int i, j;
- for (i = 0; i < seekhead_list->nb_elem; i++)
- if (seekhead[i].id == MATROSKA_ID_CUES)
- break;
- assert(i <= seekhead_list->nb_elem);
-
- matroska_parse_seekhead_entry(matroska, i);
+ if (matroska->ctx->flags & AVFMT_FLAG_IGNIDX)
+ return;
index_list = &matroska->index;
index = index_list->elem;
@@ -1418,6 +1528,25 @@ static void matroska_parse_cues(MatroskaDemuxContext *matroska)
}
}
+static void matroska_parse_cues(MatroskaDemuxContext *matroska) {
+ int i;
+
+ if (matroska->ctx->flags & AVFMT_FLAG_IGNIDX)
+ return;
+
+ for (i = 0; i < matroska->num_level1_elems; i++) {
+ MatroskaLevel1Element *elem = &matroska->level1_elems[i];
+ if (elem->id == MATROSKA_ID_CUES && !elem->parsed) {
+ if (matroska_parse_seekhead_entry(matroska, elem->pos) < 0)
+ matroska->cues_parsing_deferred = -1;
+ elem->parsed = 1;
+ break;
+ }
+ }
+
+ matroska_add_index_entries(matroska);
+}
+
static int matroska_aac_profile(char *codec_id)
{
static const char *const aac_profiles[] = { "MAIN", "LC", "SSR" };
@@ -1439,6 +1568,17 @@ static int matroska_aac_sri(int samplerate)
return sri;
}
+static void matroska_metadata_creation_time(AVDictionary **metadata, int64_t date_utc)
+{
+ char buffer[32];
+ /* Convert to seconds and adjust by number of seconds between 2001-01-01 and Epoch */
+ time_t creation_time = date_utc / 1000000000 + 978307200;
+ struct tm tmpbuf, *ptm = gmtime_r(&creation_time, &tmpbuf);
+ if (!ptm) return;
+ if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm))
+ av_dict_set(metadata, "creation_time", buffer, 0);
+}
+
static int matroska_parse_flac(AVFormatContext *s,
MatroskaTrack *track,
int *offset)
@@ -1500,6 +1640,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
MatroskaTrack *tracks = matroska->tracks.elem;
AVStream *st;
int i, j, ret;
+ int k;
for (i = 0; i < matroska->tracks.nb_elem; i++) {
MatroskaTrack *track = &tracks[i];
@@ -1509,12 +1650,16 @@ static int matroska_parse_tracks(AVFormatContext *s)
uint8_t *extradata = NULL;
int extradata_size = 0;
int extradata_offset = 0;
+ uint32_t fourcc = 0;
AVIOContext b;
+ char* key_id_base64 = NULL;
+ int bit_depth = -1;
/* Apply some sanity checks. */
if (track->type != MATROSKA_TRACK_TYPE_VIDEO &&
track->type != MATROSKA_TRACK_TYPE_AUDIO &&
- track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
+ track->type != MATROSKA_TRACK_TYPE_SUBTITLE &&
+ track->type != MATROSKA_TRACK_TYPE_METADATA) {
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown or unsupported track type %"PRIu64"\n",
track->type);
@@ -1526,10 +1671,12 @@ static int matroska_parse_tracks(AVFormatContext *s)
if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
if (!track->default_duration && track->video.frame_rate > 0)
track->default_duration = 1000000000 / track->video.frame_rate;
- if (!track->video.display_width)
+ if (track->video.display_width == -1)
track->video.display_width = track->video.pixel_width;
- if (!track->video.display_height)
+ if (track->video.display_height == -1)
track->video.display_height = track->video.pixel_height;
+ if (track->video.color_space.size == 4)
+ fourcc = AV_RL32(track->video.color_space.data);
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
if (!track->audio.out_samplerate)
track->audio.out_samplerate = track->audio.samplerate;
@@ -1538,8 +1685,24 @@ static int matroska_parse_tracks(AVFormatContext *s)
av_log(matroska->ctx, AV_LOG_ERROR,
"Multiple combined encodings not supported");
} else if (encodings_list->nb_elem == 1) {
- if (encodings[0].type ||
- (
+ if (encodings[0].type) {
+ if (encodings[0].encryption.key_id.size > 0) {
+ /* Save the encryption key id to be stored later as a
+ metadata tag. */
+ const int b64_size = AV_BASE64_SIZE(encodings[0].encryption.key_id.size);
+ key_id_base64 = av_malloc(b64_size);
+ if (key_id_base64 == NULL)
+ return AVERROR(ENOMEM);
+
+ av_base64_encode(key_id_base64, b64_size,
+ encodings[0].encryption.key_id.data,
+ encodings[0].encryption.key_id.size);
+ } else {
+ encodings[0].scope = 0;
+ av_log(matroska->ctx, AV_LOG_ERROR,
+ "Unsupported encoding type");
+ }
+ } else if (
#if CONFIG_ZLIB
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB &&
#endif
@@ -1549,7 +1712,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
#if CONFIG_LZO
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO &&
#endif
- encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP)) {
+ encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP) {
encodings[0].scope = 0;
av_log(matroska->ctx, AV_LOG_ERROR,
"Unsupported encoding type");
@@ -1579,16 +1742,28 @@ static int matroska_parse_tracks(AVFormatContext *s)
}
st = track->stream = avformat_new_stream(s, NULL);
- if (!st)
+ if (!st) {
+ av_free(key_id_base64);
return AVERROR(ENOMEM);
+ }
+
+ if (key_id_base64) {
+ /* export encryption key id as base64 metadata tag */
+ av_dict_set(&st->metadata, "enc_key_id", key_id_base64, 0);
+ av_freep(&key_id_base64);
+ }
if (!strcmp(track->codec_id, "V_MS/VFW/FOURCC") &&
- track->codec_priv.size >= 40 &&
+ track->codec_priv.size >= 40 &&
track->codec_priv.data) {
track->ms_compat = 1;
- track->video.fourcc = AV_RL32(track->codec_priv.data + 16);
+ bit_depth = AV_RL16(track->codec_priv.data + 14);
+ fourcc = AV_RL32(track->codec_priv.data + 16);
codec_id = ff_codec_get_id(ff_codec_bmp_tags,
- track->video.fourcc);
+ fourcc);
+ if (!codec_id)
+ codec_id = ff_codec_get_id(ff_codec_movvideo_tags,
+ fourcc);
extradata_offset = 40;
} else if (!strcmp(track->codec_id, "A_MS/ACM") &&
track->codec_priv.size >= 14 &&
@@ -1597,20 +1772,34 @@ static int matroska_parse_tracks(AVFormatContext *s)
ffio_init_context(&b, track->codec_priv.data,
track->codec_priv.size,
0, NULL, NULL, NULL, NULL);
- ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size);
+ ret = ff_get_wav_header(&b, st->codec, track->codec_priv.size, 0);
if (ret < 0)
return ret;
codec_id = st->codec->codec_id;
extradata_offset = FFMIN(track->codec_priv.size, 18);
+ } else if (!strcmp(track->codec_id, "A_QUICKTIME")
+ && (track->codec_priv.size >= 86)
+ && (track->codec_priv.data)) {
+ fourcc = AV_RL32(track->codec_priv.data + 4);
+ codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
+ if (ff_codec_get_id(ff_codec_movaudio_tags, AV_RL32(track->codec_priv.data))) {
+ fourcc = AV_RL32(track->codec_priv.data);
+ codec_id = ff_codec_get_id(ff_codec_movaudio_tags, fourcc);
+ }
} else if (!strcmp(track->codec_id, "V_QUICKTIME") &&
- (track->codec_priv.size >= 86) &&
+ (track->codec_priv.size >= 21) &&
(track->codec_priv.data)) {
- track->video.fourcc = AV_RL32(track->codec_priv.data);
- codec_id = ff_codec_get_id(ff_codec_movvideo_tags,
- track->video.fourcc);
+ fourcc = AV_RL32(track->codec_priv.data + 4);
+ codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc);
+ if (ff_codec_get_id(ff_codec_movvideo_tags, AV_RL32(track->codec_priv.data))) {
+ fourcc = AV_RL32(track->codec_priv.data);
+ codec_id = ff_codec_get_id(ff_codec_movvideo_tags, fourcc);
+ }
+ if (codec_id == AV_CODEC_ID_NONE && AV_RL32(track->codec_priv.data+4) == AV_RL32("SMI "))
+ codec_id = AV_CODEC_ID_SVQ3;
if (codec_id == AV_CODEC_ID_NONE) {
char buf[32];
- av_get_codec_tag_string(buf, sizeof(buf), track->video.fourcc);
+ av_get_codec_tag_string(buf, sizeof(buf), fourcc);
av_log(matroska->ctx, AV_LOG_ERROR,
"mov FourCC not found %s.\n", buf);
}
@@ -1657,7 +1846,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
extradata_size = 5;
} else
extradata_size = 2;
- } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size) {
+ } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size && track->codec_priv.size < INT_MAX - 12 - FF_INPUT_BUFFER_PADDING_SIZE) {
/* Only ALAC's magic cookie is stored in Matroska's track headers.
* Create the "atom size", "tag", and "tag version" fields the
* decoder expects manually. */
@@ -1673,7 +1862,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
track->codec_priv.size);
} else if (codec_id == AV_CODEC_ID_TTA) {
extradata_size = 30;
- extradata = av_mallocz(extradata_size);
+ extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
if (!extradata)
return AVERROR(ENOMEM);
ffio_init_context(&b, extradata, extradata_size, 1,
@@ -1682,9 +1871,12 @@ static int matroska_parse_tracks(AVFormatContext *s)
avio_wl16(&b, 1);
avio_wl16(&b, track->audio.channels);
avio_wl16(&b, track->audio.bitdepth);
+ if (track->audio.out_samplerate < 0 || track->audio.out_samplerate > INT_MAX)
+ return AVERROR_INVALIDDATA;
avio_wl32(&b, track->audio.out_samplerate);
- avio_wl32(&b, matroska->ctx->duration *
- track->audio.out_samplerate);
+ avio_wl32(&b, av_rescale((matroska->duration * matroska->time_scale),
+ track->audio.out_samplerate,
+ AV_TIME_BASE * 1000));
} else if (codec_id == AV_CODEC_ID_RV10 ||
codec_id == AV_CODEC_ID_RV20 ||
codec_id == AV_CODEC_ID_RV30 ||
@@ -1693,11 +1885,13 @@ static int matroska_parse_tracks(AVFormatContext *s)
} else if (codec_id == AV_CODEC_ID_RA_144) {
track->audio.out_samplerate = 8000;
track->audio.channels = 1;
- } else if (codec_id == AV_CODEC_ID_RA_288 ||
- codec_id == AV_CODEC_ID_COOK ||
- codec_id == AV_CODEC_ID_ATRAC3 ||
- codec_id == AV_CODEC_ID_SIPR) {
+ } else if ((codec_id == AV_CODEC_ID_RA_288 ||
+ codec_id == AV_CODEC_ID_COOK ||
+ codec_id == AV_CODEC_ID_ATRAC3 ||
+ codec_id == AV_CODEC_ID_SIPR)
+ && track->codec_priv.data) {
int flavor;
+
ffio_init_context(&b, track->codec_priv.data,
track->codec_priv.size,
0, NULL, NULL, NULL, NULL);
@@ -1708,14 +1902,14 @@ static int matroska_parse_tracks(AVFormatContext *s)
track->audio.sub_packet_h = avio_rb16(&b);
track->audio.frame_size = avio_rb16(&b);
track->audio.sub_packet_size = avio_rb16(&b);
- if (flavor <= 0 ||
+ if (flavor < 0 ||
track->audio.coded_framesize <= 0 ||
track->audio.sub_packet_h <= 0 ||
track->audio.frame_size <= 0 ||
track->audio.sub_packet_size <= 0)
return AVERROR_INVALIDDATA;
- track->audio.buf = av_malloc(track->audio.frame_size *
- track->audio.sub_packet_h);
+ track->audio.buf = av_malloc_array(track->audio.sub_packet_h,
+ track->audio.frame_size);
if (!track->audio.buf)
return AVERROR(ENOMEM);
if (codec_id == AV_CODEC_ID_RA_288) {
@@ -1723,7 +1917,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
track->codec_priv.size = 0;
} else {
if (codec_id == AV_CODEC_ID_SIPR && flavor < 4) {
- const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
+ static const int sipr_bit_rate[4] = { 6504, 8496, 5000, 16000 };
track->audio.sub_packet_size = ff_sipr_subpk_size[flavor];
st->codec->bit_rate = sipr_bit_rate[flavor];
}
@@ -1734,6 +1928,8 @@ static int matroska_parse_tracks(AVFormatContext *s)
ret = matroska_parse_flac(s, track, &extradata_offset);
if (ret < 0)
return ret;
+ } else if (codec_id == AV_CODEC_ID_PRORES && track->codec_priv.size == 4) {
+ fourcc = AV_RL32(track->codec_priv.data);
}
track->codec_priv.size -= extradata_offset;
@@ -1752,7 +1948,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
st->time_base);
st->codec->codec_id = codec_id;
- st->start_time = 0;
+
if (strcmp(track->language, "und"))
av_dict_set(&st->metadata, "language", track->language, 0);
av_dict_set(&st->metadata, "title", track->name, 0);
@@ -1767,11 +1963,8 @@ static int matroska_parse_tracks(AVFormatContext *s)
st->codec->extradata = extradata;
st->codec->extradata_size = extradata_size;
} else if (track->codec_priv.data && track->codec_priv.size > 0) {
- st->codec->extradata = av_mallocz(track->codec_priv.size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, track->codec_priv.size))
return AVERROR(ENOMEM);
- st->codec->extradata_size = track->codec_priv.size;
memcpy(st->codec->extradata,
track->codec_priv.data + extradata_offset,
track->codec_priv.size);
@@ -1779,8 +1972,12 @@ static int matroska_parse_tracks(AVFormatContext *s)
}
if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
+ MatroskaTrackPlane *planes = track->operation.combine_planes.elem;
+
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codec->codec_tag = track->video.fourcc;
+ st->codec->codec_tag = fourcc;
+ if (bit_depth >= 0)
+ st->codec->bits_per_coded_sample = bit_depth;
st->codec->width = track->video.pixel_width;
st->codec->height = track->video.pixel_height;
av_reduce(&st->sample_aspect_ratio.num,
@@ -1788,12 +1985,40 @@ static int matroska_parse_tracks(AVFormatContext *s)
st->codec->height * track->video.display_width,
st->codec->width * track->video.display_height,
255);
- if (st->codec->codec_id != AV_CODEC_ID_H264 &&
- st->codec->codec_id != AV_CODEC_ID_HEVC)
+ if (st->codec->codec_id != AV_CODEC_ID_HEVC)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
+
if (track->default_duration) {
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
1000000000, track->default_duration, 30000);
+#if FF_API_R_FRAME_RATE
+ if ( st->avg_frame_rate.num < st->avg_frame_rate.den * 1000LL
+ && st->avg_frame_rate.num > st->avg_frame_rate.den * 5LL)
+ st->r_frame_rate = st->avg_frame_rate;
+#endif
+ }
+
+ /* export stereo mode flag as metadata tag */
+ if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREOMODE_TYPE_NB)
+ av_dict_set(&st->metadata, "stereo_mode", ff_matroska_video_stereo_mode[track->video.stereo_mode], 0);
+
+ /* export alpha mode flag as metadata tag */
+ if (track->video.alpha_mode)
+ av_dict_set(&st->metadata, "alpha_mode", "1", 0);
+
+ /* if we have virtual track, mark the real tracks */
+ for (j=0; j < track->operation.combine_planes.nb_elem; j++) {
+ char buf[32];
+ if (planes[j].type >= MATROSKA_VIDEO_STEREO_PLANE_COUNT)
+ continue;
+ snprintf(buf, sizeof(buf), "%s_%d",
+ ff_matroska_video_stereo_plane[planes[j].type], i);
+ for (k=0; k < matroska->tracks.nb_elem; k++)
+ if (planes[j].uid == tracks[k].uid && tracks[k].stream) {
+ av_dict_set(&tracks[k].stream->metadata,
+ "stereo_mode", buf, 0);
+ break;
+ }
}
// add stream level stereo3d side data if it is a supported format
if (track->video.stereo_mode < MATROSKA_VIDEO_STEREOMODE_TYPE_NB &&
@@ -1806,11 +2031,34 @@ static int matroska_parse_tracks(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->sample_rate = track->audio.out_samplerate;
st->codec->channels = track->audio.channels;
+ if (!st->codec->bits_per_coded_sample)
+ st->codec->bits_per_coded_sample = track->audio.bitdepth;
if (st->codec->codec_id != AV_CODEC_ID_AAC)
st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ if (track->codec_delay > 0) {
+ st->codec->delay = av_rescale_q(track->codec_delay,
+ st->time_base,
+ (AVRational){1, st->codec->sample_rate});
+ }
+ if (track->seek_preroll > 0) {
+ av_codec_set_seek_preroll(st->codec,
+ av_rescale_q(track->seek_preroll,
+ (AVRational){1, 1000000000},
+ (AVRational){1, st->codec->sample_rate}));
+ }
+ } else if (codec_id == AV_CODEC_ID_WEBVTT) {
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+
+ if (!strcmp(track->codec_id, "D_WEBVTT/CAPTIONS")) {
+ st->disposition |= AV_DISPOSITION_CAPTIONS;
+ } else if (!strcmp(track->codec_id, "D_WEBVTT/DESCRIPTIONS")) {
+ st->disposition |= AV_DISPOSITION_DESCRIPTIONS;
+ } else if (!strcmp(track->codec_id, "D_WEBVTT/METADATA")) {
+ st->disposition |= AV_DISPOSITION_METADATA;
+ }
} else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) {
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- if (st->codec->codec_id == AV_CODEC_ID_SSA)
+ if (st->codec->codec_id == AV_CODEC_ID_ASS)
matroska->contains_ssa = 1;
}
}
@@ -1831,6 +2079,7 @@ static int matroska_read_header(AVFormatContext *s)
int i, j, res;
matroska->ctx = s;
+ matroska->cues_parsing_deferred = 1;
/* First read the EBML header. */
if (ebml_parse(matroska, ebml_syntax, &ebml) || !ebml.doctype) {
@@ -1848,6 +2097,11 @@ static int matroska_read_header(AVFormatContext *s)
ebml.version, ebml.doctype, ebml.doctype_version);
ebml_free(ebml_syntax, &ebml);
return AVERROR_PATCHWELCOME;
+ } else if (ebml.doctype_version == 3) {
+ av_log(matroska->ctx, AV_LOG_WARNING,
+ "EBML header using unsupported features\n"
+ "(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
+ ebml.version, ebml.doctype, ebml.doctype_version);
}
for (i = 0; i < FF_ARRAY_ELEMS(matroska_doctypes); i++)
if (!strcmp(ebml.doctype, matroska_doctypes[i]))
@@ -1880,6 +2134,10 @@ static int matroska_read_header(AVFormatContext *s)
matroska->ctx->duration = matroska->duration * matroska->time_scale *
1000 / AV_TIME_BASE;
av_dict_set(&s->metadata, "title", matroska->title, 0);
+ av_dict_set(&s->metadata, "encoder", matroska->muxingapp, 0);
+
+ if (matroska->date_utc.size == 8)
+ matroska_metadata_creation_time(&s->metadata, AV_RB64(matroska->date_utc.data));
res = matroska_parse_tracks(s);
if (res < 0)
@@ -1920,11 +2178,8 @@ static int matroska_read_header(AVFormatContext *s)
st->attached_pic.flags |= AV_PKT_FLAG_KEY;
} else {
st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_malloc(attachments[j].bin.size);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, attachments[j].bin.size))
break;
-
- st->codec->extradata_size = attachments[j].bin.size;
memcpy(st->codec->extradata, attachments[j].bin.data,
attachments[j].bin.size);
@@ -1948,11 +2203,15 @@ static int matroska_read_header(AVFormatContext *s)
(AVRational) { 1, 1000000000 },
chapters[i].start, chapters[i].end,
chapters[i].title);
- av_dict_set(&chapters[i].chapter->metadata,
- "title", chapters[i].title, 0);
+ if (chapters[i].chapter) {
+ av_dict_set(&chapters[i].chapter->metadata,
+ "title", chapters[i].title, 0);
+ }
max_start = chapters[i].start;
}
+ matroska_add_index_entries(matroska);
+
matroska_convert_tags(s);
return 0;
@@ -1967,7 +2226,7 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
{
if (matroska->num_packets > 0) {
memcpy(pkt, matroska->packets[0], sizeof(AVPacket));
- av_free(matroska->packets[0]);
+ av_freep(&matroska->packets[0]);
if (matroska->num_packets > 1) {
void *newpackets;
memmove(&matroska->packets[0], &matroska->packets[1],
@@ -1998,7 +2257,7 @@ static void matroska_clear_queue(MatroskaDemuxContext *matroska)
int n;
for (n = 0; n < matroska->num_packets; n++) {
av_free_packet(matroska->packets[n]);
- av_free(matroska->packets[n]);
+ av_freep(&matroska->packets[n]);
}
av_freep(&matroska->packets);
matroska->num_packets = 0;
@@ -2023,7 +2282,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
return 0;
}
- assert(size > 0);
+ av_assert0(size > 0);
*laces = *data + 1;
data += 1;
size -= 1;
@@ -2038,18 +2297,18 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
uint32_t total = 0;
for (n = 0; res == 0 && n < *laces - 1; n++) {
while (1) {
- if (size == 0) {
- res = AVERROR_EOF;
+ if (size <= total) {
+ res = AVERROR_INVALIDDATA;
break;
}
temp = *data;
+ total += temp;
lace_size[n] += temp;
data += 1;
size -= 1;
if (temp != 0xff)
break;
}
- total += lace_size[n];
}
if (size <= total) {
res = AVERROR_INVALIDDATA;
@@ -2074,10 +2333,10 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
uint64_t num;
uint64_t total;
n = matroska_ebmlnum_uint(matroska, data, size, &num);
- if (n < 0) {
+ if (n < 0 || num > INT_MAX) {
av_log(matroska->ctx, AV_LOG_INFO,
"EBML block data error\n");
- res = n;
+ res = n<0 ? n : AVERROR_INVALIDDATA;
break;
}
data += n;
@@ -2087,10 +2346,10 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
int64_t snum;
int r;
r = matroska_ebmlnum_sint(matroska, data, size, &snum);
- if (r < 0) {
+ if (r < 0 || lace_size[n - 1] + snum > (uint64_t)INT_MAX) {
av_log(matroska->ctx, AV_LOG_INFO,
"EBML block data error\n");
- res = r;
+ res = r<0 ? r : AVERROR_INVALIDDATA;
break;
}
data += r;
@@ -2117,7 +2376,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
MatroskaTrack *track, AVStream *st,
uint8_t *data, int size, uint64_t timecode,
- uint64_t duration, int64_t pos)
+ int64_t pos)
{
int a = st->codec->block_align;
int sps = track->audio.sub_packet_size;
@@ -2147,7 +2406,7 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
}
memcpy(track->audio.buf + y * w, data, w);
} else {
- if (size < sps * w / sps) {
+ if (size < sps * w / sps || h<=0 || w%sps) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Corrupt generic RM-style audio packet size\n");
return AVERROR_INVALIDDATA;
@@ -2271,18 +2530,136 @@ fail:
return ret;
}
+static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
+ MatroskaTrack *track,
+ AVStream *st,
+ uint8_t *data, int data_len,
+ uint64_t timecode,
+ uint64_t duration,
+ int64_t pos)
+{
+ AVPacket *pkt;
+ uint8_t *id, *settings, *text, *buf;
+ int id_len, settings_len, text_len;
+ uint8_t *p, *q;
+ int err;
+
+ if (data_len <= 0)
+ return AVERROR_INVALIDDATA;
+
+ p = data;
+ q = data + data_len;
+
+ id = p;
+ id_len = -1;
+ while (p < q) {
+ if (*p == '\r' || *p == '\n') {
+ id_len = p - id;
+ if (*p == '\r')
+ p++;
+ break;
+ }
+ p++;
+ }
+
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ settings = p;
+ settings_len = -1;
+ while (p < q) {
+ if (*p == '\r' || *p == '\n') {
+ settings_len = p - settings;
+ if (*p == '\r')
+ p++;
+ break;
+ }
+ p++;
+ }
+
+ if (p >= q || *p != '\n')
+ return AVERROR_INVALIDDATA;
+ p++;
+
+ text = p;
+ text_len = q - p;
+ while (text_len > 0) {
+ const int len = text_len - 1;
+ const uint8_t c = p[len];
+ if (c != '\r' && c != '\n')
+ break;
+ text_len = len;
+ }
+
+ if (text_len <= 0)
+ return AVERROR_INVALIDDATA;
+
+ pkt = av_mallocz(sizeof(*pkt));
+ if (!pkt)
+ return AVERROR(ENOMEM);
+ err = av_new_packet(pkt, text_len);
+ if (err < 0) {
+ av_free(pkt);
+ return AVERROR(err);
+ }
+
+ memcpy(pkt->data, text, text_len);
+
+ if (id_len > 0) {
+ buf = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ id_len);
+ if (!buf) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, id, id_len);
+ }
+
+ if (settings_len > 0) {
+ buf = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_WEBVTT_SETTINGS,
+ settings_len);
+ if (!buf) {
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(buf, settings, settings_len);
+ }
+
+ // Do we need this for subtitles?
+ // pkt->flags = AV_PKT_FLAG_KEY;
+
+ pkt->stream_index = st->index;
+ pkt->pts = timecode;
+
+ // Do we need this for subtitles?
+ // pkt->dts = timecode;
+
+ pkt->duration = duration;
+ pkt->pos = pos;
+
+ dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ matroska->prev_pkt = pkt;
+
+ return 0;
+}
+
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track, AVStream *st,
uint8_t *data, int pkt_size,
- uint64_t timecode, uint64_t duration,
- int64_t pos, int is_keyframe)
+ uint64_t timecode, uint64_t lace_duration,
+ int64_t pos, int is_keyframe,
+ uint8_t *additional, uint64_t additional_id, int additional_size,
+ int64_t discard_padding)
{
MatroskaTrackEncoding *encodings = track->encodings.elem;
uint8_t *pkt_data = data;
int offset = 0, res;
AVPacket *pkt;
- if (encodings && encodings->scope & 1) {
+ if (encodings && !encodings->type && encodings->scope & 1) {
res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
if (res < 0)
return res;
@@ -2301,22 +2678,24 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
pkt_data = wv_data;
}
- if (st->codec->codec_id == AV_CODEC_ID_PRORES)
+ if (st->codec->codec_id == AV_CODEC_ID_PRORES &&
+ AV_RB32(&data[4]) != MKBETAG('i', 'c', 'p', 'f'))
offset = 8;
pkt = av_mallocz(sizeof(AVPacket));
if (!pkt) {
- av_freep(&pkt_data);
+ if (pkt_data != data)
+ av_freep(&pkt_data);
return AVERROR(ENOMEM);
}
/* XXX: prevent data copy... */
if (av_new_packet(pkt, pkt_size + offset) < 0) {
av_free(pkt);
- av_freep(&pkt_data);
- return AVERROR(ENOMEM);
+ res = AVERROR(ENOMEM);
+ goto fail;
}
- if (st->codec->codec_id == AV_CODEC_ID_PRORES) {
+ if (st->codec->codec_id == AV_CODEC_ID_PRORES && offset == 8) {
uint8_t *buf = pkt->data;
bytestream_put_be32(&buf, pkt_size);
bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
@@ -2325,35 +2704,71 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
memcpy(pkt->data + offset, pkt_data, pkt_size);
if (pkt_data != data)
- av_free(pkt_data);
+ av_freep(&pkt_data);
pkt->flags = is_keyframe;
pkt->stream_index = st->index;
+ if (additional_size > 0) {
+ uint8_t *side_data = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
+ additional_size + 8);
+ if (!side_data) {
+ av_free_packet(pkt);
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ AV_WB64(side_data, additional_id);
+ memcpy(side_data + 8, additional, additional_size);
+ }
+
+ if (discard_padding) {
+ uint8_t *side_data = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_SKIP_SAMPLES,
+ 10);
+ if (!side_data) {
+ av_free_packet(pkt);
+ av_free(pkt);
+ return AVERROR(ENOMEM);
+ }
+ AV_WL32(side_data, 0);
+ AV_WL32(side_data + 4, av_rescale_q(discard_padding,
+ (AVRational){1, 1000000000},
+ (AVRational){1, st->codec->sample_rate}));
+ }
+
if (track->ms_compat)
pkt->dts = timecode;
else
pkt->pts = timecode;
pkt->pos = pos;
- if (st->codec->codec_id == AV_CODEC_ID_TEXT)
- pkt->convergence_duration = duration;
- else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE)
- pkt->duration = duration;
-
- if (st->codec->codec_id == AV_CODEC_ID_SSA)
- matroska_fix_ass_packet(matroska, pkt, duration);
-
- if (matroska->prev_pkt &&
- timecode != AV_NOPTS_VALUE &&
- matroska->prev_pkt->pts == timecode &&
- matroska->prev_pkt->stream_index == st->index &&
- st->codec->codec_id == AV_CODEC_ID_SSA)
- matroska_merge_packets(matroska->prev_pkt, pkt);
- else {
- dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
- matroska->prev_pkt = pkt;
+ if (st->codec->codec_id == AV_CODEC_ID_SUBRIP) {
+ /*
+ * For backward compatibility.
+ * Historically, we have put subtitle duration
+ * in convergence_duration, on the off chance
+ * that the time_scale is less than 1us, which
+ * could result in a 32bit overflow on the
+ * normal duration field.
+ */
+ pkt->convergence_duration = lace_duration;
}
+ if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE ||
+ lace_duration <= INT_MAX) {
+ /*
+ * For non subtitle tracks, just store the duration
+ * as normal.
+ *
+ * If it's a subtitle track and duration value does
+ * not overflow a uint32, then also store it normally.
+ */
+ pkt->duration = lace_duration;
+ }
+
+ dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ matroska->prev_pkt = pkt;
+
return 0;
fail:
@@ -2365,7 +2780,8 @@ fail:
static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t block_duration, int is_keyframe,
- int64_t cluster_pos)
+ uint8_t *additional, uint64_t additional_id, int additional_size,
+ int64_t cluster_pos, int64_t discard_padding)
{
uint64_t timecode = AV_NOPTS_VALUE;
MatroskaTrack *track;
@@ -2374,7 +2790,8 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
int16_t block_time;
uint32_t *lace_size = NULL;
int n, flags, laces = 0;
- uint64_t num, duration;
+ uint64_t num;
+ int trust_default_duration = 1;
if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) {
av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n");
@@ -2393,8 +2810,9 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
st = track->stream;
if (st->discard >= AVDISCARD_ALL)
return res;
+ av_assert1(block_duration != AV_NOPTS_VALUE);
- block_time = AV_RB16(data);
+ block_time = sign_extend(AV_RB16(data), 16);
data += 2;
flags = *data++;
size -= 3;
@@ -2414,9 +2832,14 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
if (matroska->skip_to_keyframe &&
track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
- if (!is_keyframe || timecode < matroska->skip_to_timecode)
+ if (timecode < matroska->skip_to_timecode)
return res;
- matroska->skip_to_keyframe = 0;
+ if (is_keyframe)
+ matroska->skip_to_keyframe = 0;
+ else if (!st->skip_to_keyframe) {
+ av_log(matroska->ctx, AV_LOG_ERROR, "File is broken, keyframes not correctly marked!\n");
+ matroska->skip_to_keyframe = 0;
+ }
}
res = matroska_parse_laces(matroska, &data, &size, (flags & 0x06) >> 1,
@@ -2425,22 +2848,29 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
if (res)
goto end;
- if (block_duration != AV_NOPTS_VALUE) {
- duration = block_duration / laces;
- if (block_duration != duration * laces) {
- av_log(matroska->ctx, AV_LOG_WARNING,
- "Incorrect block_duration, possibly corrupted container");
+ if (track->audio.samplerate == 8000) {
+ // If this is needed for more codecs, then add them here
+ if (st->codec->codec_id == AV_CODEC_ID_AC3) {
+ if (track->audio.samplerate != st->codec->sample_rate || !st->codec->frame_size)
+ trust_default_duration = 0;
}
- } else {
- duration = track->default_duration / matroska->time_scale;
- block_duration = duration * laces;
}
- if (timecode != AV_NOPTS_VALUE)
+ if (!block_duration && trust_default_duration)
+ block_duration = track->default_duration * laces / matroska->time_scale;
+
+ if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time))
track->end_timecode =
FFMAX(track->end_timecode, timecode + block_duration);
for (n = 0; n < laces; n++) {
+ int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces;
+
+ if (lace_size[n] > size) {
+ av_log(matroska->ctx, AV_LOG_ERROR, "Invalid packet size\n");
+ break;
+ }
+
if ((st->codec->codec_id == AV_CODEC_ID_RA_288 ||
st->codec->codec_id == AV_CODEC_ID_COOK ||
st->codec->codec_id == AV_CODEC_ID_SIPR ||
@@ -2448,20 +2878,31 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
st->codec->block_align && track->audio.sub_packet_size) {
res = matroska_parse_rm_audio(matroska, track, st, data,
lace_size[n],
- timecode, duration, pos);
+ timecode, pos);
+ if (res)
+ goto end;
+
+ } else if (st->codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ res = matroska_parse_webvtt(matroska, track, st,
+ data, lace_size[n],
+ timecode, lace_duration,
+ pos);
if (res)
goto end;
} else {
res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
- timecode, duration, pos,
- !n ? is_keyframe : 0);
+ timecode, lace_duration, pos,
+ !n ? is_keyframe : 0,
+ additional, additional_id, additional_size,
+ discard_padding);
if (res)
goto end;
}
if (timecode != AV_NOPTS_VALUE)
- timecode = duration ? timecode + duration : AV_NOPTS_VALUE;
+ timecode = lace_duration ? timecode + lace_duration : AV_NOPTS_VALUE;
data += lace_size[n];
+ size -= lace_size[n];
}
end:
@@ -2509,18 +2950,21 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
i = blocks_list->nb_elem - 1;
if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1;
+ uint8_t* additional = blocks[i].additional.size > 0 ?
+ blocks[i].additional.data : NULL;
if (!blocks[i].non_simple)
- blocks[i].duration = AV_NOPTS_VALUE;
+ blocks[i].duration = 0;
res = matroska_parse_block(matroska, blocks[i].bin.data,
blocks[i].bin.size, blocks[i].bin.pos,
matroska->current_cluster.timecode,
blocks[i].duration, is_keyframe,
- matroska->current_cluster_pos);
+ additional, blocks[i].additional_id,
+ blocks[i].additional.size,
+ matroska->current_cluster_pos,
+ blocks[i].discard_padding);
}
}
- if (res < 0)
- matroska->done = 1;
return res;
}
@@ -2541,15 +2985,14 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
res = ebml_parse(matroska, matroska_clusters, &cluster);
blocks_list = &cluster.blocks;
blocks = blocks_list->elem;
- for (i = 0; i < blocks_list->nb_elem && !res; i++)
+ for (i = 0; i < blocks_list->nb_elem; i++)
if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1;
- if (!blocks[i].non_simple)
- blocks[i].duration = AV_NOPTS_VALUE;
res = matroska_parse_block(matroska, blocks[i].bin.data,
blocks[i].bin.size, blocks[i].bin.pos,
cluster.timecode, blocks[i].duration,
- is_keyframe, pos);
+ is_keyframe, NULL, 0, 0, pos,
+ blocks[i].discard_padding);
}
ebml_free(matroska_cluster, &cluster);
return res;
@@ -2558,22 +3001,16 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MatroskaDemuxContext *matroska = s->priv_data;
- int ret = 0;
- while (!ret && matroska_deliver_packet(matroska, pkt)) {
+ while (matroska_deliver_packet(matroska, pkt)) {
int64_t pos = avio_tell(matroska->ctx->pb);
if (matroska->done)
return AVERROR_EOF;
if (matroska_parse_cluster(matroska) < 0)
- ret = matroska_resync(matroska, pos);
+ matroska_resync(matroska, pos);
}
- if (ret == AVERROR_INVALIDDATA && pkt->data) {
- pkt->flags |= AV_PKT_FLAG_CORRUPT;
- return 0;
- }
-
- return ret;
+ return 0;
}
static int matroska_read_seek(AVFormatContext *s, int stream_index,
@@ -2585,20 +3022,20 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
int i, index, index_sub, index_min;
/* Parse the CUES now since we need the index data to seek. */
- if (matroska->cues_parsing_deferred) {
- matroska_parse_cues(matroska);
+ if (matroska->cues_parsing_deferred > 0) {
matroska->cues_parsing_deferred = 0;
+ matroska_parse_cues(matroska);
}
if (!st->nb_index_entries)
- return 0;
+ goto err;
timestamp = FFMAX(timestamp, st->index_entries[0].timestamp);
- if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
+ if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->nb_index_entries - 1) {
avio_seek(s->pb, st->index_entries[st->nb_index_entries - 1].pos,
SEEK_SET);
matroska->current_id = 0;
- while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
+ while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->nb_index_entries - 1) {
matroska_clear_queue(matroska);
if (matroska_parse_cluster(matroska) < 0)
break;
@@ -2606,8 +3043,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
}
matroska_clear_queue(matroska);
- if (index < 0)
- return 0;
+ if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->nb_index_entries - 1))
+ goto err;
index_min = index;
tracks = matroska->tracks.elem;
@@ -2621,21 +3058,38 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
index_sub = av_index_search_timestamp(
tracks[i].stream, st->index_entries[index].timestamp,
AVSEEK_FLAG_BACKWARD);
- if (index_sub >= 0 &&
- st->index_entries[index_sub].pos < st->index_entries[index_min].pos &&
- st->index_entries[index].timestamp -
- st->index_entries[index_sub].timestamp < 30000000000 / matroska->time_scale)
- index_min = index_sub;
+ while (index_sub >= 0 &&
+ index_min > 0 &&
+ tracks[i].stream->index_entries[index_sub].pos < st->index_entries[index_min].pos &&
+ st->index_entries[index].timestamp - tracks[i].stream->index_entries[index_sub].timestamp < 30000000000 / matroska->time_scale)
+ index_min--;
}
}
avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET);
matroska->current_id = 0;
- matroska->skip_to_keyframe = !(flags & AVSEEK_FLAG_ANY);
- matroska->skip_to_timecode = st->index_entries[index].timestamp;
+ if (flags & AVSEEK_FLAG_ANY) {
+ st->skip_to_keyframe = 0;
+ matroska->skip_to_timecode = timestamp;
+ } else {
+ st->skip_to_keyframe = 1;
+ matroska->skip_to_timecode = st->index_entries[index].timestamp;
+ }
+ matroska->skip_to_keyframe = 1;
matroska->done = 0;
+ matroska->num_levels = 0;
ff_update_cur_dts(s, st, st->index_entries[index].timestamp);
return 0;
+err:
+ // slightly hackish but allows proper fallback to
+ // the generic seeking code.
+ matroska_clear_queue(matroska);
+ matroska->current_id = 0;
+ st->skip_to_keyframe =
+ matroska->skip_to_keyframe = 0;
+ matroska->done = 0;
+ matroska->num_levels = 0;
+ return -1;
}
static int matroska_read_close(AVFormatContext *s)
@@ -2648,13 +3102,376 @@ static int matroska_read_close(AVFormatContext *s)
for (n = 0; n < matroska->tracks.nb_elem; n++)
if (tracks[n].type == MATROSKA_TRACK_TYPE_AUDIO)
- av_free(tracks[n].audio.buf);
+ av_freep(&tracks[n].audio.buf);
ebml_free(matroska_cluster, &matroska->current_cluster);
ebml_free(matroska_segment, matroska);
return 0;
}
+typedef struct {
+ int64_t start_time_ns;
+ int64_t end_time_ns;
+ int64_t start_offset;
+ int64_t end_offset;
+} CueDesc;
+
+/* This function searches all the Cues and returns the CueDesc corresponding the
+ * the timestamp ts. Returned CueDesc will be such that start_time_ns <= ts <
+ * end_time_ns. All 4 fields will be set to -1 if ts >= file's duration.
+ */
+static CueDesc get_cue_desc(AVFormatContext *s, int64_t ts, int64_t cues_start) {
+ MatroskaDemuxContext *matroska = s->priv_data;
+ CueDesc cue_desc;
+ int i;
+ int nb_index_entries = s->streams[0]->nb_index_entries;
+ AVIndexEntry *index_entries = s->streams[0]->index_entries;
+ if (ts >= matroska->duration * matroska->time_scale) return (CueDesc) {-1, -1, -1, -1};
+ for (i = 1; i < nb_index_entries; i++) {
+ if (index_entries[i - 1].timestamp * matroska->time_scale <= ts &&
+ index_entries[i].timestamp * matroska->time_scale > ts) {
+ break;
+ }
+ }
+ --i;
+ cue_desc.start_time_ns = index_entries[i].timestamp * matroska->time_scale;
+ cue_desc.start_offset = index_entries[i].pos - matroska->segment_start;
+ if (i != nb_index_entries - 1) {
+ cue_desc.end_time_ns = index_entries[i + 1].timestamp * matroska->time_scale;
+ cue_desc.end_offset = index_entries[i + 1].pos - matroska->segment_start;
+ } else {
+ cue_desc.end_time_ns = matroska->duration * matroska->time_scale;
+ // FIXME: this needs special handling for files where Cues appear
+ // before Clusters. the current logic assumes Cues appear after
+ // Clusters.
+ cue_desc.end_offset = cues_start - matroska->segment_start;
+ }
+ return cue_desc;
+}
+
+static int webm_clusters_start_with_keyframe(AVFormatContext *s)
+{
+ MatroskaDemuxContext *matroska = s->priv_data;
+ int64_t cluster_pos, before_pos;
+ int index, rv = 1;
+ if (s->streams[0]->nb_index_entries <= 0) return 0;
+ // seek to the first cluster using cues.
+ index = av_index_search_timestamp(s->streams[0], 0, 0);
+ if (index < 0) return 0;
+ cluster_pos = s->streams[0]->index_entries[index].pos;
+ before_pos = avio_tell(s->pb);
+ while (1) {
+ int64_t cluster_id = 0, cluster_length = 0;
+ AVPacket *pkt;
+ avio_seek(s->pb, cluster_pos, SEEK_SET);
+ // read cluster id and length
+ ebml_read_num(matroska, matroska->ctx->pb, 4, &cluster_id);
+ ebml_read_length(matroska, matroska->ctx->pb, &cluster_length);
+ if (cluster_id != 0xF43B675) { // done with all clusters
+ break;
+ }
+ avio_seek(s->pb, cluster_pos, SEEK_SET);
+ matroska->current_id = 0;
+ matroska_clear_queue(matroska);
+ if (matroska_parse_cluster(matroska) < 0 ||
+ matroska->num_packets <= 0) {
+ break;
+ }
+ pkt = matroska->packets[0];
+ cluster_pos += cluster_length + 12; // 12 is the offset of the cluster id and length.
+ if (!(pkt->flags & AV_PKT_FLAG_KEY)) {
+ rv = 0;
+ break;
+ }
+ }
+ avio_seek(s->pb, before_pos, SEEK_SET);
+ return rv;
+}
+
+static int buffer_size_after_time_downloaded(int64_t time_ns, double search_sec, int64_t bps,
+ double min_buffer, double* buffer,
+ double* sec_to_download, AVFormatContext *s,
+ int64_t cues_start)
+{
+ double nano_seconds_per_second = 1000000000.0;
+ double time_sec = time_ns / nano_seconds_per_second;
+ int rv = 0;
+ int64_t time_to_search_ns = (int64_t)(search_sec * nano_seconds_per_second);
+ int64_t end_time_ns = time_ns + time_to_search_ns;
+ double sec_downloaded = 0.0;
+ CueDesc desc_curr = get_cue_desc(s, time_ns, cues_start);
+ if (desc_curr.start_time_ns == -1)
+ return -1;
+ *sec_to_download = 0.0;
+
+ // Check for non cue start time.
+ if (time_ns > desc_curr.start_time_ns) {
+ int64_t cue_nano = desc_curr.end_time_ns - time_ns;
+ double percent = (double)(cue_nano) / (desc_curr.end_time_ns - desc_curr.start_time_ns);
+ double cueBytes = (desc_curr.end_offset - desc_curr.start_offset) * percent;
+ double timeToDownload = (cueBytes * 8.0) / bps;
+
+ sec_downloaded += (cue_nano / nano_seconds_per_second) - timeToDownload;
+ *sec_to_download += timeToDownload;
+
+ // Check if the search ends within the first cue.
+ if (desc_curr.end_time_ns >= end_time_ns) {
+ double desc_end_time_sec = desc_curr.end_time_ns / nano_seconds_per_second;
+ double percent_to_sub = search_sec / (desc_end_time_sec - time_sec);
+ sec_downloaded = percent_to_sub * sec_downloaded;
+ *sec_to_download = percent_to_sub * *sec_to_download;
+ }
+
+ if ((sec_downloaded + *buffer) <= min_buffer) {
+ return 1;
+ }
+
+ // Get the next Cue.
+ desc_curr = get_cue_desc(s, desc_curr.end_time_ns, cues_start);
+ }
+
+ while (desc_curr.start_time_ns != -1) {
+ int64_t desc_bytes = desc_curr.end_offset - desc_curr.start_offset;
+ int64_t desc_ns = desc_curr.end_time_ns - desc_curr.start_time_ns;
+ double desc_sec = desc_ns / nano_seconds_per_second;
+ double bits = (desc_bytes * 8.0);
+ double time_to_download = bits / bps;
+
+ sec_downloaded += desc_sec - time_to_download;
+ *sec_to_download += time_to_download;
+
+ if (desc_curr.end_time_ns >= end_time_ns) {
+ double desc_end_time_sec = desc_curr.end_time_ns / nano_seconds_per_second;
+ double percent_to_sub = search_sec / (desc_end_time_sec - time_sec);
+ sec_downloaded = percent_to_sub * sec_downloaded;
+ *sec_to_download = percent_to_sub * *sec_to_download;
+
+ if ((sec_downloaded + *buffer) <= min_buffer)
+ rv = 1;
+ break;
+ }
+
+ if ((sec_downloaded + *buffer) <= min_buffer) {
+ rv = 1;
+ break;
+ }
+
+ desc_curr = get_cue_desc(s, desc_curr.end_time_ns, cues_start);
+ }
+ *buffer = *buffer + sec_downloaded;
+ return rv;
+}
+
+/* This function computes the bandwidth of the WebM file with the help of
+ * buffer_size_after_time_downloaded() function. Both of these functions are
+ * adapted from WebM Tools project and are adapted to work with FFmpeg's
+ * Matroska parsing mechanism.
+ *
+ * Returns the bandwidth of the file on success; -1 on error.
+ * */
+static int64_t webm_dash_manifest_compute_bandwidth(AVFormatContext *s, int64_t cues_start)
+{
+ MatroskaDemuxContext *matroska = s->priv_data;
+ AVStream *st = s->streams[0];
+ double bandwidth = 0.0;
+ int i;
+
+ for (i = 0; i < st->nb_index_entries; i++) {
+ int64_t prebuffer_ns = 1000000000;
+ int64_t time_ns = st->index_entries[i].timestamp * matroska->time_scale;
+ double nano_seconds_per_second = 1000000000.0;
+ int64_t prebuffered_ns = time_ns + prebuffer_ns;
+ double prebuffer_bytes = 0.0;
+ int64_t temp_prebuffer_ns = prebuffer_ns;
+ int64_t pre_bytes, pre_ns;
+ double pre_sec, prebuffer, bits_per_second;
+ CueDesc desc_beg = get_cue_desc(s, time_ns, cues_start);
+
+ // Start with the first Cue.
+ CueDesc desc_end = desc_beg;
+
+ // Figure out how much data we have downloaded for the prebuffer. This will
+ // be used later to adjust the bits per sample to try.
+ while (desc_end.start_time_ns != -1 && desc_end.end_time_ns < prebuffered_ns) {
+ // Prebuffered the entire Cue.
+ prebuffer_bytes += desc_end.end_offset - desc_end.start_offset;
+ temp_prebuffer_ns -= desc_end.end_time_ns - desc_end.start_time_ns;
+ desc_end = get_cue_desc(s, desc_end.end_time_ns, cues_start);
+ }
+ if (desc_end.start_time_ns == -1) {
+ // The prebuffer is larger than the duration.
+ if (matroska->duration * matroska->time_scale >= prebuffered_ns)
+ return -1;
+ bits_per_second = 0.0;
+ } else {
+ // 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;
+ pre_sec = pre_ns / nano_seconds_per_second;
+ prebuffer_bytes +=
+ pre_bytes * ((temp_prebuffer_ns / nano_seconds_per_second) / pre_sec);
+
+ prebuffer = prebuffer_ns / nano_seconds_per_second;
+
+ // Set this to 0.0 in case our prebuffer buffers the entire video.
+ bits_per_second = 0.0;
+ do {
+ 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 = desc_ns / nano_seconds_per_second;
+ double calc_bits_per_second = (desc_bytes * 8) / desc_sec;
+
+ // Drop the bps by the percentage of bytes buffered.
+ double percent = (desc_bytes - prebuffer_bytes) / desc_bytes;
+ double mod_bits_per_second = calc_bits_per_second * percent;
+
+ if (prebuffer < desc_sec) {
+ double search_sec =
+ (double)(matroska->duration * matroska->time_scale) / nano_seconds_per_second;
+
+ // Add 1 so the bits per second should be a little bit greater than file
+ // datarate.
+ int64_t bps = (int64_t)(mod_bits_per_second) + 1;
+ const double min_buffer = 0.0;
+ double buffer = prebuffer;
+ double sec_to_download = 0.0;
+
+ int rv = buffer_size_after_time_downloaded(prebuffered_ns, search_sec, bps,
+ min_buffer, &buffer, &sec_to_download,
+ s, cues_start);
+ if (rv < 0) {
+ return -1;
+ } else if (rv == 0) {
+ bits_per_second = (double)(bps);
+ break;
+ }
+ }
+
+ desc_end = get_cue_desc(s, desc_end.end_time_ns, cues_start);
+ } while (desc_end.start_time_ns != -1);
+ }
+ if (bandwidth < bits_per_second) bandwidth = bits_per_second;
+ }
+ return (int64_t)bandwidth;
+}
+
+static int webm_dash_manifest_cues(AVFormatContext *s)
+{
+ MatroskaDemuxContext *matroska = s->priv_data;
+ EbmlList *seekhead_list = &matroska->seekhead;
+ MatroskaSeekhead *seekhead = seekhead_list->elem;
+ char *buf;
+ int64_t cues_start = -1, cues_end = -1, before_pos, bandwidth;
+ int i;
+
+ // determine cues start and end positions
+ for (i = 0; i < seekhead_list->nb_elem; i++)
+ if (seekhead[i].id == MATROSKA_ID_CUES)
+ break;
+
+ if (i >= seekhead_list->nb_elem) return -1;
+
+ before_pos = avio_tell(matroska->ctx->pb);
+ cues_start = seekhead[i].pos + matroska->segment_start;
+ if (avio_seek(matroska->ctx->pb, cues_start, SEEK_SET) == cues_start) {
+ // cues_end is computed as cues_start + cues_length + length of the
+ // Cues element ID + EBML length of the Cues element. cues_end is
+ // inclusive and the above sum is reduced by 1.
+ uint64_t cues_length = 0, cues_id = 0, bytes_read = 0;
+ bytes_read += ebml_read_num(matroska, matroska->ctx->pb, 4, &cues_id);
+ bytes_read += ebml_read_length(matroska, matroska->ctx->pb, &cues_length);
+ cues_end = cues_start + cues_length + bytes_read - 1;
+ }
+ avio_seek(matroska->ctx->pb, before_pos, SEEK_SET);
+ if (cues_start == -1 || cues_end == -1) return -1;
+
+ // parse the cues
+ matroska_parse_cues(matroska);
+
+ // cues start
+ av_dict_set_int(&s->streams[0]->metadata, CUES_START, cues_start, 0);
+
+ // cues end
+ av_dict_set_int(&s->streams[0]->metadata, CUES_END, cues_end, 0);
+
+ // bandwidth
+ bandwidth = webm_dash_manifest_compute_bandwidth(s, cues_start);
+ if (bandwidth < 0) return -1;
+ av_dict_set_int(&s->streams[0]->metadata, BANDWIDTH, bandwidth, 0);
+
+ // check if all clusters start with key frames
+ av_dict_set_int(&s->streams[0]->metadata, CLUSTER_KEYFRAME, webm_clusters_start_with_keyframe(s), 0);
+
+ // store cue point timestamps as a comma separated list for checking subsegment alignment in
+ // the muxer. assumes that each timestamp cannot be more than 20 characters long.
+ buf = av_malloc_array(s->streams[0]->nb_index_entries, 20 * sizeof(char));
+ if (!buf) return -1;
+ strcpy(buf, "");
+ for (i = 0; i < s->streams[0]->nb_index_entries; i++) {
+ snprintf(buf, (i + 1) * 20 * sizeof(char),
+ "%s%" PRId64, buf, s->streams[0]->index_entries[i].timestamp);
+ if (i != s->streams[0]->nb_index_entries - 1)
+ strncat(buf, ",", sizeof(char));
+ }
+ av_dict_set(&s->streams[0]->metadata, CUE_TIMESTAMPS, buf, 0);
+ av_free(buf);
+
+ return 0;
+}
+
+static int webm_dash_manifest_read_header(AVFormatContext *s)
+{
+ char *buf;
+ int ret = matroska_read_header(s);
+ MatroskaTrack *tracks;
+ MatroskaDemuxContext *matroska = s->priv_data;
+ if (ret) {
+ av_log(s, AV_LOG_ERROR, "Failed to read file headers\n");
+ return -1;
+ }
+
+ if (!matroska->is_live) {
+ buf = av_asprintf("%g", matroska->duration);
+ if (!buf) return AVERROR(ENOMEM);
+ av_dict_set(&s->streams[0]->metadata, DURATION, buf, 0);
+ av_free(buf);
+
+ // initialization range
+ // 5 is the offset of Cluster ID.
+ av_dict_set_int(&s->streams[0]->metadata, INITIALIZATION_RANGE, avio_tell(s->pb) - 5, 0);
+ }
+
+ // basename of the file
+ buf = strrchr(s->filename, '/');
+ av_dict_set(&s->streams[0]->metadata, FILENAME, buf ? ++buf : s->filename, 0);
+
+ // track number
+ tracks = matroska->tracks.elem;
+ av_dict_set_int(&s->streams[0]->metadata, TRACK_NUMBER, tracks[0].num, 0);
+
+ // parse the cues and populate Cue related fields
+ return matroska->is_live ? 0 : webm_dash_manifest_cues(s);
+}
+
+static int webm_dash_manifest_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ return AVERROR_EOF;
+}
+
+#define OFFSET(x) offsetof(MatroskaDemuxContext, x)
+static const AVOption options[] = {
+ { "live", "flag indicating that the input is a live file that only has the headers.", OFFSET(is_live), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass webm_dash_class = {
+ .class_name = "WebM DASH Manifest demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVInputFormat ff_matroska_demuxer = {
.name = "matroska,webm",
.long_name = NULL_IF_CONFIG_SMALL("Matroska / WebM"),
@@ -2667,3 +3484,13 @@ AVInputFormat ff_matroska_demuxer = {
.read_seek = matroska_read_seek,
.mime_type = "audio/webm,audio/x-matroska,video/webm,video/x-matroska"
};
+
+AVInputFormat ff_webm_dash_manifest_demuxer = {
+ .name = "webm_dash_manifest",
+ .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"),
+ .priv_data_size = sizeof(MatroskaDemuxContext),
+ .read_header = webm_dash_manifest_read_header,
+ .read_packet = webm_dash_manifest_read_packet,
+ .read_close = matroska_read_close,
+ .priv_class = &webm_dash_class,
+};
diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 91c4459dad..c4c58f4d09 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -2,20 +2,20 @@
* Matroska muxer
* Copyright (c) 2007 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,12 +24,14 @@
#include "avc.h"
#include "hevc.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "avlanguage.h"
#include "flacenc.h"
#include "internal.h"
#include "isom.h"
#include "matroska.h"
#include "riff.h"
+#include "subtitles.h"
#include "vorbiscomment.h"
#include "wv.h"
@@ -43,10 +45,12 @@
#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
#include "libavutil/samplefmt.h"
+#include "libavutil/sha.h"
#include "libavutil/stereo3d.h"
#include "libavcodec/xiph.h"
#include "libavcodec/mpeg4audio.h"
+#include "libavcodec/internal.h"
typedef struct ebml_master {
int64_t pos; ///< absolute offset in the file where the master's elements start
@@ -69,8 +73,11 @@ typedef struct mkv_seekhead {
typedef struct mkv_cuepoint {
uint64_t pts;
+ int stream_idx;
int tracknum;
int64_t cluster_pos; ///< file offset of the cluster containing the block
+ int64_t relative_pos; ///< relative offset from the position of the cluster containing the block
+ int64_t duration; ///< duration of the block according to time base
} mkv_cuepoint;
typedef struct mkv_cues {
@@ -81,6 +88,7 @@ typedef struct mkv_cues {
typedef struct mkv_track {
int write_dts;
+ int has_cue;
int64_t ts_offset;
} mkv_track;
@@ -110,7 +118,14 @@ typedef struct MatroskaMuxContext {
int cluster_size_limit;
int64_t cues_pos;
int64_t cluster_time_limit;
+ int is_dash;
+ int dash_track_number;
+ int is_live;
+
+ uint32_t chapter_id_offset;
int wrote_chapters;
+
+ int allow_raw_vfw;
} MatroskaMuxContext;
@@ -118,13 +133,16 @@ typedef struct MatroskaMuxContext {
* offset, 4 bytes for target EBML ID */
#define MAX_SEEKENTRY_SIZE 21
-/** per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2
+/** per-cuepoint-track - 5 1-byte EBML IDs, 5 1-byte EBML sizes, 4
* 8-byte uint max */
-#define MAX_CUETRACKPOS_SIZE 22
+#define MAX_CUETRACKPOS_SIZE 42
/** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */
#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE * num_tracks
+/** Seek preroll value for opus */
+#define OPUS_SEEK_PREROLL 80000000
+
static int ebml_id_size(unsigned int id)
{
return (av_log2(id + 1) - 1) / 7 + 1;
@@ -134,7 +152,7 @@ static void put_ebml_id(AVIOContext *pb, unsigned int id)
{
int i = ebml_id_size(id);
while (i--)
- avio_w8(pb, id >> (i * 8));
+ avio_w8(pb, (uint8_t)(id >> (i * 8)));
}
/**
@@ -144,10 +162,9 @@ static void put_ebml_id(AVIOContext *pb, unsigned int id)
*/
static void put_ebml_size_unknown(AVIOContext *pb, int bytes)
{
- assert(bytes <= 8);
+ av_assert0(bytes <= 8);
avio_w8(pb, 0x1ff >> bytes);
- while (--bytes)
- avio_w8(pb, 0xff);
+ ffio_fill(pb, 0xff, bytes - 1);
}
/**
@@ -172,18 +189,18 @@ static void put_ebml_num(AVIOContext *pb, uint64_t num, int bytes)
int i, needed_bytes = ebml_num_size(num);
// sizes larger than this are currently undefined in EBML
- assert(num < (1ULL << 56) - 1);
+ av_assert0(num < (1ULL << 56) - 1);
if (bytes == 0)
// don't care how many bytes are used, so use the min
bytes = needed_bytes;
// the bytes needed to write the given size would exceed the bytes
// that we need to use, so write unknown size. This shouldn't happen.
- assert(bytes >= needed_bytes);
+ av_assert0(bytes >= needed_bytes);
num |= 1ULL << bytes * 7;
for (i = bytes - 1; i >= 0; i--)
- avio_w8(pb, num >> i * 8);
+ avio_w8(pb, (uint8_t)(num >> i * 8));
}
static void put_ebml_uint(AVIOContext *pb, unsigned int elementid, uint64_t val)
@@ -196,7 +213,20 @@ static void put_ebml_uint(AVIOContext *pb, unsigned int elementid, uint64_t val)
put_ebml_id(pb, elementid);
put_ebml_num(pb, bytes, 0);
for (i = bytes - 1; i >= 0; i--)
- avio_w8(pb, val >> i * 8);
+ avio_w8(pb, (uint8_t)(val >> i * 8));
+}
+
+static void put_ebml_sint(AVIOContext *pb, unsigned int elementid, int64_t val)
+{
+ int i, bytes = 1;
+ uint64_t tmp = 2*(val < 0 ? val^-1 : val);
+
+ while (tmp>>=8) bytes++;
+
+ put_ebml_id(pb, elementid);
+ put_ebml_num(pb, bytes, 0);
+ for (i = bytes - 1; i >= 0; i--)
+ avio_w8(pb, (uint8_t)(val >> i * 8));
}
static void put_ebml_float(AVIOContext *pb, unsigned int elementid, double val)
@@ -230,7 +260,7 @@ static void put_ebml_void(AVIOContext *pb, uint64_t size)
{
int64_t currentpos = avio_tell(pb);
- assert(size >= 2);
+ av_assert0(size >= 2);
put_ebml_id(pb, EBML_ID_VOID);
// we need to subtract the length needed to store the size from the
@@ -240,8 +270,7 @@ static void put_ebml_void(AVIOContext *pb, uint64_t size)
put_ebml_num(pb, size - 1, 0);
else
put_ebml_num(pb, size - 9, 8);
- while (avio_tell(pb) < currentpos + size)
- avio_w8(pb, 0);
+ ffio_fill(pb, 0, currentpos + size - avio_tell(pb));
}
static ebml_master start_ebml_master(AVIOContext *pb, unsigned int elementid,
@@ -265,9 +294,7 @@ static void end_ebml_master(AVIOContext *pb, ebml_master master)
static void put_xiph_size(AVIOContext *pb, int size)
{
- int i;
- for (i = 0; i < size / 255; i++)
- avio_w8(pb, 255);
+ ffio_fill(pb, 255, size / 255);
avio_w8(pb, size % 255);
}
@@ -305,17 +332,16 @@ static mkv_seekhead *mkv_start_seekhead(AVIOContext *pb, int64_t segment_offset,
static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos)
{
- int err;
+ mkv_seekhead_entry *entries = seekhead->entries;
// don't store more elements than we reserved space for
if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
return -1;
- if ((err = av_reallocp_array(&seekhead->entries, seekhead->num_entries + 1,
- sizeof(*seekhead->entries))) < 0) {
- seekhead->num_entries = 0;
- return err;
- }
+ entries = av_realloc_array(entries, seekhead->num_entries + 1, sizeof(mkv_seekhead_entry));
+ if (!entries)
+ return AVERROR(ENOMEM);
+ seekhead->entries = entries;
seekhead->entries[seekhead->num_entries].elementid = elementid;
seekhead->entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;
@@ -370,7 +396,7 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, mkv_seekhead *seekhead)
currentpos = seekhead->filepos;
}
fail:
- av_free(seekhead->entries);
+ av_freep(&seekhead->entries);
av_free(seekhead);
return currentpos;
@@ -386,28 +412,32 @@ static mkv_cues *mkv_start_cues(int64_t segment_offset)
return cues;
}
-static int mkv_add_cuepoint(mkv_cues *cues, int stream, int64_t ts, int64_t cluster_pos)
+static int mkv_add_cuepoint(mkv_cues *cues, int stream, int tracknum, int64_t ts,
+ int64_t cluster_pos, int64_t relative_pos, int64_t duration)
{
- int err;
+ mkv_cuepoint *entries = cues->entries;
if (ts < 0)
return 0;
- if ((err = av_reallocp_array(&cues->entries, cues->num_entries + 1,
- sizeof(*cues->entries))) < 0) {
- cues->num_entries = 0;
- return err;
- }
+ entries = av_realloc_array(entries, cues->num_entries + 1, sizeof(mkv_cuepoint));
+ if (!entries)
+ return AVERROR(ENOMEM);
+ cues->entries = entries;
cues->entries[cues->num_entries].pts = ts;
- cues->entries[cues->num_entries].tracknum = stream + 1;
- cues->entries[cues->num_entries++].cluster_pos = cluster_pos - cues->segment_offset;
+ cues->entries[cues->num_entries].stream_idx = stream;
+ cues->entries[cues->num_entries].tracknum = tracknum;
+ cues->entries[cues->num_entries].cluster_pos = cluster_pos - cues->segment_offset;
+ cues->entries[cues->num_entries].relative_pos = relative_pos;
+ cues->entries[cues->num_entries++].duration = duration;
return 0;
}
-static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, int num_tracks)
+static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tracks, int num_tracks)
{
+ AVIOContext *pb = s->pb;
ebml_master cues_element;
int64_t currentpos;
int i, j;
@@ -419,16 +449,39 @@ static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, int num_tracks)
ebml_master cuepoint, track_positions;
mkv_cuepoint *entry = &cues->entries[i];
uint64_t pts = entry->pts;
+ int ctp_nb = 0;
- cuepoint = start_ebml_master(pb, MATROSKA_ID_POINTENTRY, MAX_CUEPOINT_SIZE(num_tracks));
+ // Calculate the number of entries, so we know the element size
+ for (j = 0; j < num_tracks; j++)
+ tracks[j].has_cue = 0;
+ for (j = 0; j < cues->num_entries - i && entry[j].pts == pts; j++) {
+ int tracknum = entry[j].stream_idx;
+ av_assert0(tracknum>=0 && tracknum<num_tracks);
+ if (tracks[tracknum].has_cue && s->streams[tracknum]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ continue;
+ tracks[tracknum].has_cue = 1;
+ ctp_nb ++;
+ }
+
+ cuepoint = start_ebml_master(pb, MATROSKA_ID_POINTENTRY, MAX_CUEPOINT_SIZE(ctp_nb));
put_ebml_uint(pb, MATROSKA_ID_CUETIME, pts);
// put all the entries from different tracks that have the exact same
// timestamp into the same CuePoint
+ for (j = 0; j < num_tracks; j++)
+ tracks[j].has_cue = 0;
for (j = 0; j < cues->num_entries - i && entry[j].pts == pts; j++) {
+ int tracknum = entry[j].stream_idx;
+ av_assert0(tracknum>=0 && tracknum<num_tracks);
+ if (tracks[tracknum].has_cue && s->streams[tracknum]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE)
+ continue;
+ tracks[tracknum].has_cue = 1;
track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE);
- put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum );
- put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION, entry[j].cluster_pos);
+ put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum );
+ put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION , entry[j].cluster_pos);
+ put_ebml_uint(pb, MATROSKA_ID_CUERELATIVEPOSITION, entry[j].relative_pos);
+ if (entry[j].duration != -1)
+ put_ebml_uint(pb, MATROSKA_ID_CUEDURATION , entry[j].duration);
end_ebml_master(pb, track_positions);
}
i += j - 1;
@@ -441,7 +494,7 @@ static int64_t mkv_write_cues(AVIOContext *pb, mkv_cues *cues, int num_tracks)
static int put_xiph_codecpriv(AVFormatContext *s, AVIOContext *pb, AVCodecContext *codec)
{
- uint8_t *header_start[3];
+ const uint8_t *header_start[3];
int header_len[3];
int first_header_size;
int j;
@@ -490,15 +543,18 @@ static int put_flac_codecpriv(AVFormatContext *s,
if (write_comment) {
const char *vendor = (s->flags & AVFMT_FLAG_BITEXACT) ?
- "Libav" : LIBAVFORMAT_IDENT;
+ "Lavf" : LIBAVFORMAT_IDENT;
AVDictionary *dict = NULL;
uint8_t buf[32], *data, *p;
- int len;
+ int64_t len;
snprintf(buf, sizeof(buf), "0x%"PRIx64, codec->channel_layout);
av_dict_set(&dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", buf, 0);
len = ff_vorbiscomment_length(dict, vendor);
+ if (len >= ((1<<24) - 4))
+ return AVERROR(EINVAL);
+
data = av_malloc(len + 4);
if (!data) {
av_dict_free(&dict);
@@ -553,8 +609,9 @@ static int mkv_write_native_codecprivate(AVFormatContext *s,
return ff_isom_write_avcc(dyn_cp, codec->extradata,
codec->extradata_size);
case AV_CODEC_ID_HEVC:
- return ff_isom_write_hvcc(dyn_cp, codec->extradata,
- codec->extradata_size, 0);
+ ff_isom_write_hvcc(dyn_cp, codec->extradata,
+ codec->extradata_size, 0);
+ return 0;
case AV_CODEC_ID_ALAC:
if (codec->extradata_size < 36) {
av_log(s, AV_LOG_ERROR,
@@ -566,8 +623,11 @@ static int mkv_write_native_codecprivate(AVFormatContext *s,
codec->extradata_size - 12);
break;
default:
- if (codec->extradata_size)
- avio_write(dyn_cp, codec->extradata, codec->extradata_size);
+ if (codec->codec_id == AV_CODEC_ID_PRORES &&
+ ff_codec_get_id(ff_codec_movvideo_tags, codec->codec_tag) == AV_CODEC_ID_PRORES) {
+ avio_wl32(dyn_cp, codec->codec_tag);
+ } else if (codec->extradata_size && codec->codec_id != AV_CODEC_ID_TTA)
+ avio_write(dyn_cp, codec->extradata, codec->extradata_size);
}
return 0;
@@ -592,30 +652,46 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb,
if (!codec->codec_tag)
codec->codec_tag = ff_codec_get_tag(ff_codec_movvideo_tags,
codec->codec_id);
- if (codec->extradata_size)
+ if (codec->extradata_size) {
+ if ( ff_codec_get_id(ff_codec_movvideo_tags, codec->codec_tag) == codec->codec_id
+ && ff_codec_get_id(ff_codec_movvideo_tags, AV_RL32(codec->extradata + 4)) != codec->codec_id
+ ) {
+ int i;
+ avio_wb32(dyn_cp, 0x5a + codec->extradata_size);
+ avio_wl32(dyn_cp, codec->codec_tag);
+ for(i = 0; i < 0x5a - 8; i++)
+ avio_w8(dyn_cp, 0);
+ }
avio_write(dyn_cp, codec->extradata, codec->extradata_size);
+ }
} else {
+ if (!ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id))
+ av_log(s, AV_LOG_WARNING, "codec %s is not supported by this format\n",
+ avcodec_get_name(codec->codec_id));
+
if (!codec->codec_tag)
codec->codec_tag = ff_codec_get_tag(ff_codec_bmp_tags,
codec->codec_id);
- if (!codec->codec_tag) {
- av_log(s, AV_LOG_ERROR, "No bmp codec ID found.\n");
- ret = -1;
+ if (!codec->codec_tag && codec->codec_id != AV_CODEC_ID_RAWVIDEO) {
+ av_log(s, AV_LOG_ERROR, "No bmp codec tag found for codec %s\n",
+ avcodec_get_name(codec->codec_id));
+ ret = AVERROR(EINVAL);
}
- ff_put_bmp_header(dyn_cp, codec, ff_codec_bmp_tags, 0);
+ ff_put_bmp_header(dyn_cp, codec, ff_codec_bmp_tags, 0, 0);
}
} else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
unsigned int tag;
tag = ff_codec_get_tag(ff_codec_wav_tags, codec->codec_id);
if (!tag) {
- av_log(s, AV_LOG_ERROR, "No wav codec ID found.\n");
- ret = -1;
+ av_log(s, AV_LOG_ERROR, "No wav codec tag found for codec %s\n",
+ avcodec_get_name(codec->codec_id));
+ ret = AVERROR(EINVAL);
}
if (!codec->codec_tag)
codec->codec_tag = tag;
- ff_put_wav_header(dyn_cp, codec);
+ ff_put_wav_header(dyn_cp, codec, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX);
}
codecpriv_size = avio_close_dyn_buf(dyn_cp, &codecpriv);
@@ -626,19 +702,28 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb,
return ret;
}
+
static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
- AVStream *st, int mode)
+ AVStream *st, int mode, int *h_width, int *h_height)
{
int i;
- int display_width, display_height;
- int h_width = 1, h_height = 1;
- AVCodecContext *codec = st->codec;
+ int ret = 0;
AVDictionaryEntry *tag;
MatroskaVideoStereoModeType format = MATROSKA_VIDEO_STEREOMODE_TYPE_NB;
+ *h_width = 1;
+ *h_height = 1;
// convert metadata into proper side data and add it to the stream
- if ((tag = av_dict_get(s->metadata, "stereo_mode", NULL, 0))) {
+ if ((tag = av_dict_get(st->metadata, "stereo_mode", NULL, 0)) ||
+ (tag = av_dict_get( s->metadata, "stereo_mode", NULL, 0))) {
int stereo_mode = atoi(tag->value);
+
+ for (i=0; i<MATROSKA_VIDEO_STEREOMODE_TYPE_NB; i++)
+ if (!strcmp(tag->value, ff_matroska_video_stereo_mode[i])){
+ stereo_mode = i;
+ break;
+ }
+
if (stereo_mode < MATROSKA_VIDEO_STEREOMODE_TYPE_NB &&
stereo_mode != 10 && stereo_mode != 12) {
int ret = ff_mkv_stereo3d_conv(st, stereo_mode);
@@ -661,13 +746,13 @@ static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
format = (stereo->flags & AV_STEREO3D_FLAG_INVERT)
? MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT
: MATROSKA_VIDEO_STEREOMODE_TYPE_LEFT_RIGHT;
- h_width = 2;
+ *h_width = 2;
break;
case AV_STEREO3D_TOPBOTTOM:
format = MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM;
if (stereo->flags & AV_STEREO3D_FLAG_INVERT)
format--;
- h_height = 2;
+ *h_height = 2;
break;
case AV_STEREO3D_CHECKERBOARD:
format = MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_LR;
@@ -678,13 +763,13 @@ static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
format = MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_LR;
if (stereo->flags & AV_STEREO3D_FLAG_INVERT)
format--;
- h_height = 2;
+ *h_height = 2;
break;
case AV_STEREO3D_COLUMNS:
format = MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_LR;
if (stereo->flags & AV_STEREO3D_FLAG_INVERT)
format--;
- h_width = 2;
+ *h_width = 2;
break;
case AV_STEREO3D_FRAMESEQUENCE:
format = MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_LR;
@@ -692,40 +777,32 @@ static int mkv_write_stereo_mode(AVFormatContext *s, AVIOContext *pb,
format++;
break;
}
-
break;
}
}
+ if (format == MATROSKA_VIDEO_STEREOMODE_TYPE_NB)
+ return ret;
+
// if webm, do not write unsupported modes
- if (mode == MODE_WEBM &&
- (format > MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM &&
- format != MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT))
+ if ((mode == MODE_WEBM &&
+ format > MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM &&
+ format != MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT)
+ || format >= MATROSKA_VIDEO_STEREOMODE_TYPE_NB) {
+ av_log(s, AV_LOG_ERROR,
+ "The specified stereo mode is not valid.\n");
format = MATROSKA_VIDEO_STEREOMODE_TYPE_NB;
+ return AVERROR(EINVAL);
+ }
// write StereoMode if format is valid
- if (format < MATROSKA_VIDEO_STEREOMODE_TYPE_NB)
- put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, format);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEOSTEREOMODE, format);
- // write DisplayWidth and DisplayHeight, they contain the size of
- // a single source view and/or the display aspect ratio
- display_width = codec->width / h_width;
- display_height = codec->height / h_height;
- if (st->sample_aspect_ratio.num) {
- display_width *= av_q2d(st->sample_aspect_ratio);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, 3); // DAR
- }
- if (st->sample_aspect_ratio.num ||
- format < MATROSKA_VIDEO_STEREOMODE_TYPE_NB) {
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH, display_width);
- put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, display_height);
- }
-
- return 0;
+ return ret;
}
static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
- int i, AVIOContext *pb)
+ int i, AVIOContext *pb, int default_stream_exists)
{
AVStream *st = s->streams[i];
AVCodecContext *codec = st->codec;
@@ -735,6 +812,8 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
int bit_depth = av_get_bits_per_sample(codec->codec_id);
int sample_rate = codec->sample_rate;
int output_sample_rate = 0;
+ int display_width_div = 1;
+ int display_height_div = 1;
int j, ret;
AVDictionaryEntry *tag;
@@ -746,8 +825,10 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
return 0;
}
- if (!bit_depth)
+ if (!bit_depth && codec->codec_id != AV_CODEC_ID_ADPCM_G726)
bit_depth = av_get_bytes_per_sample(codec->sample_fmt) << 3;
+ if (!bit_depth)
+ bit_depth = codec->bits_per_coded_sample;
if (codec->codec_id == AV_CODEC_ID_AAC) {
ret = get_aac_sample_rates(s, codec, &sample_rate, &output_sample_rate);
@@ -756,61 +837,103 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
}
track = start_ebml_master(pb, MATROSKA_ID_TRACKENTRY, 0);
- put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER , i + 1);
- put_ebml_uint (pb, MATROSKA_ID_TRACKUID , i + 1);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER,
+ mkv->is_dash ? mkv->dash_track_number : i + 1);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKUID,
+ mkv->is_dash ? mkv->dash_track_number : i + 1);
put_ebml_uint (pb, MATROSKA_ID_TRACKFLAGLACING , 0); // no lacing (yet)
if ((tag = av_dict_get(st->metadata, "title", NULL, 0)))
put_ebml_string(pb, MATROSKA_ID_TRACKNAME, tag->value);
tag = av_dict_get(st->metadata, "language", NULL, 0);
- put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und");
+ if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) {
+ put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag && tag->value ? tag->value:"und");
+ } else if (tag && tag->value) {
+ put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag->value);
+ }
// The default value for TRACKFLAGDEFAULT is 1, so add element
// if we need to clear it.
- if (!(st->disposition & AV_DISPOSITION_DEFAULT))
+ if (default_stream_exists && !(st->disposition & AV_DISPOSITION_DEFAULT))
put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, !!(st->disposition & AV_DISPOSITION_DEFAULT));
+
if (st->disposition & AV_DISPOSITION_FORCED)
- put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, !!(st->disposition & AV_DISPOSITION_FORCED));
+ put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1);
+
+ if (mkv->mode == MODE_WEBM && codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ const char *codec_id;
+ if (st->disposition & AV_DISPOSITION_CAPTIONS) {
+ codec_id = "D_WEBVTT/CAPTIONS";
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+ } else if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) {
+ codec_id = "D_WEBVTT/DESCRIPTIONS";
+ native_id = MATROSKA_TRACK_TYPE_METADATA;
+ } else if (st->disposition & AV_DISPOSITION_METADATA) {
+ codec_id = "D_WEBVTT/METADATA";
+ native_id = MATROSKA_TRACK_TYPE_METADATA;
+ } else {
+ codec_id = "D_WEBVTT/SUBTITLES";
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+ }
+ put_ebml_string(pb, MATROSKA_ID_CODECID, codec_id);
+ } else {
+ // look for a codec ID string specific to mkv to use,
+ // if none are found, use AVI codes
+ for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
+ if (ff_mkv_codec_tags[j].id == codec->codec_id) {
+ put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str);
+ native_id = 1;
+ break;
+ }
+ }
+ if (codec->codec_id == AV_CODEC_ID_RAWVIDEO && !codec->codec_tag) {
+ if (mkv->allow_raw_vfw) {
+ native_id = 0;
+ } else {
+ av_log(s, AV_LOG_ERROR, "Raw RGB is not supported Natively in Matroska, you can use AVI or NUT or\n"
+ "If you would like to store it anyway using VFW mode, enable allow_raw_vfw (-allow_raw_vfw 1)\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ }
- if (codec->codec_type == AVMEDIA_TYPE_AUDIO && codec->initial_padding) {
- mkv->tracks[i].ts_offset = av_rescale_q(codec->initial_padding,
- (AVRational){ 1, codec->sample_rate },
- st->time_base);
+ if (codec->codec_type == AVMEDIA_TYPE_AUDIO && codec->initial_padding && codec->codec_id == AV_CODEC_ID_OPUS) {
+// mkv->tracks[i].ts_offset = av_rescale_q(codec->initial_padding,
+// (AVRational){ 1, codec->sample_rate },
+// st->time_base);
put_ebml_uint(pb, MATROSKA_ID_CODECDELAY,
av_rescale_q(codec->initial_padding,
(AVRational){ 1, codec->sample_rate },
(AVRational){ 1, 1000000000 }));
}
-
- // look for a codec ID string specific to mkv to use,
- // if none are found, use AVI codes
- for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) {
- if (ff_mkv_codec_tags[j].id == codec->codec_id) {
- put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str);
- native_id = 1;
- break;
- }
+ if (codec->codec_id == AV_CODEC_ID_OPUS) {
+ put_ebml_uint(pb, MATROSKA_ID_SEEKPREROLL, OPUS_SEEK_PREROLL);
}
if (mkv->mode == MODE_WEBM && !(codec->codec_id == AV_CODEC_ID_VP8 ||
codec->codec_id == AV_CODEC_ID_VP9 ||
codec->codec_id == AV_CODEC_ID_OPUS ||
- codec->codec_id == AV_CODEC_ID_VORBIS)) {
+ codec->codec_id == AV_CODEC_ID_VORBIS ||
+ codec->codec_id == AV_CODEC_ID_WEBVTT)) {
av_log(s, AV_LOG_ERROR,
- "Only VP8 or VP9 video and Vorbis or Opus audio are supported for WebM.\n");
+ "Only VP8 or VP9 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM.\n");
return AVERROR(EINVAL);
}
switch (codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_VIDEO);
- if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0)
+
+ if( st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0
+ && 1.0/av_q2d(st->avg_frame_rate) > av_q2d(codec->time_base))
put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, 1E9 / av_q2d(st->avg_frame_rate));
+ else
+ put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, av_q2d(codec->time_base)*1E9);
if (!native_id &&
ff_codec_get_tag(ff_codec_movvideo_tags, codec->codec_id) &&
- (!ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id) ||
+ ((!ff_codec_get_tag(ff_codec_bmp_tags, codec->codec_id) && codec->codec_id != AV_CODEC_ID_RAWVIDEO) ||
codec->codec_id == AV_CODEC_ID_SVQ1 ||
codec->codec_id == AV_CODEC_ID_SVQ3 ||
codec->codec_id == AV_CODEC_ID_CINEPAK))
@@ -822,6 +945,7 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
// if there is no mkv-specific codec ID, use VFW mode
put_ebml_string(pb, MATROSKA_ID_CODECID, "V_MS/VFW/FOURCC");
mkv->tracks[i].write_dts = 1;
+ s->internal->avoid_negative_ts_use_pts = 0;
}
subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKVIDEO, 0);
@@ -831,10 +955,38 @@ static int mkv_write_track(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, pb, st, mkv->mode);
+ ret = mkv_write_stereo_mode(s, pb, st, mkv->mode,
+ &display_width_div,
+ &display_height_div);
if (ret < 0)
return ret;
+ if (((tag = av_dict_get(st->metadata, "alpha_mode", NULL, 0)) && atoi(tag->value)) ||
+ ((tag = av_dict_get( s->metadata, "alpha_mode", NULL, 0)) && atoi(tag->value)) ||
+ (codec->pix_fmt == AV_PIX_FMT_YUVA420P)) {
+ put_ebml_uint(pb, MATROSKA_ID_VIDEOALPHAMODE, 1);
+ }
+
+ // 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(codec->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);
+ }
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , d_width / display_width_div);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height / display_height_div);
+ } else if (display_width_div != 1 || display_height_div != 1) {
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , codec->width / display_width_div);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, codec->height / display_height_div);
+ }
+
+ if (codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ uint32_t color_space = av_le2ne32(codec->codec_tag);
+ put_ebml_binary(pb, MATROSKA_ID_VIDEOCOLORSPACE, &color_space, sizeof(color_space));
+ }
+
end_ebml_master(pb, subinfo);
break;
@@ -856,19 +1008,26 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
break;
case AVMEDIA_TYPE_SUBTITLE:
- put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_SUBTITLE);
if (!native_id) {
av_log(s, AV_LOG_ERROR, "Subtitle codec %d is not supported.\n", codec->codec_id);
return AVERROR(ENOSYS);
}
+
+ if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT)
+ native_id = MATROSKA_TRACK_TYPE_SUBTITLE;
+
+ put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, native_id);
break;
default:
av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska.\n");
- break;
+ return AVERROR(EINVAL);
+ }
+
+ if (mkv->mode != MODE_WEBM || codec->codec_id != AV_CODEC_ID_WEBVTT) {
+ ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id);
+ if (ret < 0)
+ return ret;
}
- ret = mkv_write_codecprivate(s, pb, codec, native_id, qt_id);
- if (ret < 0)
- return ret;
end_ebml_master(pb, track);
@@ -880,7 +1039,7 @@ static int mkv_write_tracks(AVFormatContext *s)
MatroskaMuxContext *mkv = s->priv_data;
AVIOContext *pb = s->pb;
ebml_master tracks;
- int i, ret;
+ int i, ret, default_stream_exists = 0;
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, avio_tell(pb));
if (ret < 0)
@@ -888,7 +1047,11 @@ static int mkv_write_tracks(AVFormatContext *s)
tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS, 0);
for (i = 0; i < s->nb_streams; i++) {
- ret = mkv_write_track(s, mkv, i, pb);
+ AVStream *st = s->streams[i];
+ default_stream_exists |= st->disposition & AV_DISPOSITION_DEFAULT;
+ }
+ for (i = 0; i < s->nb_streams; i++) {
+ ret = mkv_write_track(s, mkv, i, pb, default_stream_exists);
if (ret < 0)
return ret;
}
@@ -928,7 +1091,7 @@ static int mkv_write_chapters(AVFormatContext *s)
}
chapteratom = start_ebml_master(pb, MATROSKA_ID_CHAPTERATOM, 0);
- put_ebml_uint(pb, MATROSKA_ID_CHAPTERUID, c->id);
+ put_ebml_uint(pb, MATROSKA_ID_CHAPTERUID, c->id + mkv->chapter_id_offset);
put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMESTART, chapterstart);
put_ebml_uint(pb, MATROSKA_ID_CHAPTERTIMEEND, chapterend);
put_ebml_uint(pb, MATROSKA_ID_CHAPTERFLAGHIDDEN , 0);
@@ -1005,6 +1168,7 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme
while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
if (av_strcasecmp(t->key, "title") &&
+ av_strcasecmp(t->key, "stereo_mode") &&
av_strcasecmp(t->key, "encoding_tool")) {
ret = mkv_write_simpletag(s->pb, t);
if (ret < 0)
@@ -1016,14 +1180,26 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme
return 0;
}
+static int mkv_check_tag(AVDictionary *m)
+{
+ AVDictionaryEntry *t = NULL;
+
+ while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
+ if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode"))
+ return 1;
+
+ return 0;
+}
+
static int mkv_write_tags(AVFormatContext *s)
{
+ MatroskaMuxContext *mkv = s->priv_data;
ebml_master tags = {0};
int i, ret;
ff_metadata_conv_ctx(s, ff_mkv_metadata_conv, NULL);
- if (av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
+ if (mkv_check_tag(s->metadata)) {
ret = mkv_write_tag(s, s->metadata, 0, 0, &tags);
if (ret < 0) return ret;
}
@@ -1031,7 +1207,7 @@ static int mkv_write_tags(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
- if (!av_dict_get(st->metadata, "", 0, AV_DICT_IGNORE_SUFFIX))
+ if (!mkv_check_tag(st->metadata))
continue;
ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tags);
@@ -1041,10 +1217,10 @@ static int mkv_write_tags(AVFormatContext *s)
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *ch = s->chapters[i];
- if (!av_dict_get(ch->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
+ if (!mkv_check_tag(ch->metadata))
continue;
- ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id, &tags);
+ ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset, &tags);
if (ret < 0) return ret;
}
@@ -1076,6 +1252,7 @@ static int mkv_write_attachments(AVFormatContext *s)
ebml_master attached_file;
AVDictionaryEntry *t;
const char *mimetype = NULL;
+ uint64_t fileuid;
if (st->codec->codec_type != AVMEDIA_TYPE_ATTACHMENT)
continue;
@@ -1110,9 +1287,25 @@ static int mkv_write_attachments(AVFormatContext *s)
return AVERROR(EINVAL);
}
+ if (s->flags & AVFMT_FLAG_BITEXACT) {
+ struct AVSHA *sha = av_sha_alloc();
+ uint8_t digest[20];
+ if (!sha)
+ return AVERROR(ENOMEM);
+ av_sha_init(sha, 160);
+ av_sha_update(sha, st->codec->extradata, st->codec->extradata_size);
+ av_sha_final(sha, digest);
+ av_free(sha);
+ fileuid = AV_RL64(digest);
+ } else {
+ fileuid = av_lfg_get(&c);
+ }
+ av_log(s, AV_LOG_VERBOSE, "Using %.16"PRIx64" for attachment %d\n",
+ fileuid, i);
+
put_ebml_string(pb, MATROSKA_ID_FILEMIMETYPE, mimetype);
put_ebml_binary(pb, MATROSKA_ID_FILEDATA, st->codec->extradata, st->codec->extradata_size);
- put_ebml_uint(pb, MATROSKA_ID_FILEUID, av_lfg_get(&c));
+ put_ebml_uint(pb, MATROSKA_ID_FILEUID, fileuid);
end_ebml_master(pb, attached_file);
}
end_ebml_master(pb, attachments);
@@ -1126,14 +1319,42 @@ static int mkv_write_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
ebml_master ebml_header, segment_info;
AVDictionaryEntry *tag;
- int ret, i;
+ int ret, i, version = 2;
if (!strcmp(s->oformat->name, "webm"))
mkv->mode = MODE_WEBM;
else
mkv->mode = MODE_MATROSKAv2;
- mkv->tracks = av_mallocz(s->nb_streams * sizeof(*mkv->tracks));
+ if (s->avoid_negative_ts < 0) {
+ s->avoid_negative_ts = 1;
+ s->internal->avoid_negative_ts_use_pts = 1;
+ }
+
+ if (mkv->mode != MODE_WEBM ||
+ av_dict_get(s->metadata, "stereo_mode", NULL, 0) ||
+ av_dict_get(s->metadata, "alpha_mode", NULL, 0))
+ version = 4;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ if (s->streams[i]->codec->codec_id == AV_CODEC_ID_ATRAC3 ||
+ s->streams[i]->codec->codec_id == AV_CODEC_ID_COOK ||
+ s->streams[i]->codec->codec_id == AV_CODEC_ID_RA_288 ||
+ s->streams[i]->codec->codec_id == AV_CODEC_ID_SIPR ||
+ s->streams[i]->codec->codec_id == AV_CODEC_ID_RV10 ||
+ s->streams[i]->codec->codec_id == AV_CODEC_ID_RV20) {
+ av_log(s, AV_LOG_ERROR,
+ "The Matroska muxer does not yet support muxing %s\n",
+ avcodec_get_name(s->streams[i]->codec->codec_id));
+ return AVERROR_PATCHWELCOME;
+ }
+ if (s->streams[i]->codec->codec_id == AV_CODEC_ID_OPUS ||
+ av_dict_get(s->streams[i]->metadata, "stereo_mode", NULL, 0) ||
+ av_dict_get(s->streams[i]->metadata, "alpha_mode", NULL, 0))
+ version = 4;
+ }
+
+ mkv->tracks = av_mallocz_array(s->nb_streams, sizeof(*mkv->tracks));
if (!mkv->tracks)
return AVERROR(ENOMEM);
@@ -1143,7 +1364,7 @@ static int mkv_write_header(AVFormatContext *s)
put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4);
put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8);
put_ebml_string (pb, EBML_ID_DOCTYPE , s->oformat->name);
- put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2);
+ put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , version);
put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2);
end_ebml_master(pb, ebml_header);
@@ -1181,18 +1402,35 @@ static int mkv_write_header(AVFormatContext *s)
else
put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT);
put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16);
+ } else {
+ const char *ident = "Lavf";
+ put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , ident);
+ put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, ident);
+ }
+
+ if (tag = av_dict_get(s->metadata, "creation_time", NULL, 0)) {
+ // Adjust time so it's relative to 2001-01-01 and convert to nanoseconds.
+ int64_t date_utc = (ff_iso8601_to_unix_time(tag->value) - 978307200) * 1000000000;
+ uint8_t date_utc_buf[8];
+ AV_WB64(date_utc_buf, date_utc);
+ put_ebml_binary(pb, MATROSKA_ID_DATEUTC, date_utc_buf, 8);
}
// reserve space for the duration
mkv->duration = 0;
mkv->duration_offset = avio_tell(pb);
- put_ebml_void(pb, 11); // assumes double-precision float to be written
+ if (!mkv->is_live) {
+ put_ebml_void(pb, 11); // assumes double-precision float to be written
+ }
end_ebml_master(pb, segment_info);
ret = mkv_write_tracks(s);
if (ret < 0)
return ret;
+ for (i = 0; i < s->nb_chapters; i++)
+ mkv->chapter_id_offset = FFMAX(mkv->chapter_id_offset, 1LL - s->chapters[i]->id);
+
if (mkv->mode != MODE_WEBM) {
ret = mkv_write_chapters(s);
if (ret < 0)
@@ -1207,7 +1445,7 @@ static int mkv_write_header(AVFormatContext *s)
return ret;
}
- if (!s->pb->seekable)
+ if (!s->pb->seekable && !mkv->is_live)
mkv_write_seekhead(pb, mkv->main_seekhead);
mkv->cues = mkv_start_cues(mkv->segment_offset);
@@ -1221,6 +1459,7 @@ static int mkv_write_header(AVFormatContext *s)
av_init_packet(&mkv->cur_audio_pkt);
mkv->cur_audio_pkt.size = 0;
+ mkv->cluster_pos = -1;
avio_flush(pb);
@@ -1252,85 +1491,6 @@ static int mkv_blockgroup_size(int pkt_size)
return size;
}
-static int ass_get_duration(AVFormatContext *s, const uint8_t *p)
-{
- int sh, sm, ss, sc, eh, em, es, ec;
- uint64_t start, end;
-
- if (sscanf(p, "%*[^,],%d:%d:%d%*c%d,%d:%d:%d%*c%d",
- &sh, &sm, &ss, &sc, &eh, &em, &es, &ec) != 8)
- return 0;
-
- if (sh > 9 || sm > 59 || ss > 59 || sc > 99 ||
- eh > 9 || em > 59 || es > 59 || ec > 99) {
- av_log(s, AV_LOG_WARNING,
- "Non-standard time reference %d:%d:%d.%d,%d:%d:%d.%d\n",
- sh, sm, ss, sc, eh, em, es, ec);
- return 0;
- }
-
- start = 3600000 * sh + 60000 * sm + 1000 * ss + 10 * sc;
- end = 3600000 * eh + 60000 * em + 1000 * es + 10 * ec;
-
- if (start > end) {
- av_log(s, AV_LOG_WARNING,
- "Unexpected time reference %d:%d:%d.%d,%d:%d:%d.%d\n",
- sh, sm, ss, sc, eh, em, es, ec);
- return 0;
- }
-
- return end - start;
-}
-
-static int mkv_write_ass_blocks(AVFormatContext *s, AVIOContext *pb,
- AVPacket *pkt)
-{
- MatroskaMuxContext *mkv = s->priv_data;
- int i, layer = 0, max_duration = 0, size, line_size, data_size = pkt->size;
- uint8_t *start, *end, *data = pkt->data;
- ebml_master blockgroup;
- char buffer[2048];
-
- while (data_size) {
- int duration = ass_get_duration(s, data);
- max_duration = FFMAX(duration, max_duration);
- end = memchr(data, '\n', data_size);
- size = line_size = end ? end - data + 1 : data_size;
- size -= end ? (end[-1] == '\r') + 1 : 0;
- start = data;
- for (i = 0; i < 3; i++, start++)
- if (!(start = memchr(start, ',', size - (start - data))))
- return max_duration;
- size -= start - data;
- sscanf(data, "Dialogue: %d,", &layer);
- i = snprintf(buffer, sizeof(buffer), "%" PRId64 ",%d,",
- s->streams[pkt->stream_index]->nb_frames, layer);
- size = FFMIN(i + size, sizeof(buffer));
- memcpy(buffer + i, start, size - i);
-
- av_log(s, AV_LOG_DEBUG,
- "Writing block at offset %" PRIu64 ", size %d, "
- "pts %" PRId64 ", duration %d\n",
- avio_tell(pb), size, pkt->pts, duration);
- blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
- mkv_blockgroup_size(size));
- put_ebml_id(pb, MATROSKA_ID_BLOCK);
- put_ebml_num(pb, size + 4, 0);
- // this assumes stream_index is less than 126
- avio_w8(pb, 0x80 | (pkt->stream_index + 1));
- avio_wb16(pb, pkt->pts - mkv->cluster_pts);
- avio_w8(pb, 0);
- avio_write(pb, buffer, size);
- put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration);
- end_ebml_master(pb, blockgroup);
-
- data += line_size;
- data_size -= line_size;
- }
-
- return max_duration;
-}
-
static int mkv_strip_wavpack(const uint8_t *src, uint8_t **pdst, int *size)
{
uint8_t *dst;
@@ -1389,9 +1549,12 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
{
MatroskaMuxContext *mkv = s->priv_data;
AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
- uint8_t *data = NULL;
- int offset = 0, size = pkt->size;
+ uint8_t *data = NULL, *side_data = NULL;
+ int offset = 0, size = pkt->size, side_data_size = 0;
int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
+ uint64_t additional_id = 0;
+ int64_t discard_padding = 0;
+ ebml_master block_group, block_additions, block_more;
av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, "
"pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n",
@@ -1412,63 +1575,102 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb,
} else
data = pkt->data;
- if (codec->codec_id == AV_CODEC_ID_PRORES) {
+ if (codec->codec_id == AV_CODEC_ID_PRORES && size >= 8) {
/* Matroska specification requires to remove the first QuickTime atom
*/
size -= 8;
offset = 8;
}
+ side_data = av_packet_get_side_data(pkt,
+ AV_PKT_DATA_SKIP_SAMPLES,
+ &side_data_size);
+
+ if (side_data && side_data_size >= 10) {
+ discard_padding = av_rescale_q(AV_RL32(side_data + 4),
+ (AVRational){1, codec->sample_rate},
+ (AVRational){1, 1000000000});
+ }
+
+ side_data = av_packet_get_side_data(pkt,
+ AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL,
+ &side_data_size);
+ if (side_data) {
+ additional_id = AV_RB64(side_data);
+ side_data += 8;
+ side_data_size -= 8;
+ }
+
+ if ((side_data_size && additional_id == 1) || discard_padding) {
+ block_group = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, 0);
+ blockid = MATROSKA_ID_BLOCK;
+ }
+
put_ebml_id(pb, blockid);
put_ebml_num(pb, size + 4, 0);
// this assumes stream_index is less than 126
- avio_w8(pb, 0x80 | (pkt->stream_index + 1));
+ avio_w8(pb, 0x80 | (mkv->is_dash ? mkv->dash_track_number : (pkt->stream_index + 1)));
avio_wb16(pb, ts - mkv->cluster_pts);
avio_w8(pb, flags);
avio_write(pb, data + offset, size);
if (data != pkt->data)
av_free(data);
-}
-static int srt_get_duration(uint8_t **buf)
-{
- int i, duration = 0;
-
- for (i = 0; i < 2 && !duration; i++) {
- int s_hour, s_min, s_sec, s_hsec, e_hour, e_min, e_sec, e_hsec;
- if (sscanf(*buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d",
- &s_hour, &s_min, &s_sec, &s_hsec,
- &e_hour, &e_min, &e_sec, &e_hsec) == 8) {
- s_min += 60 * s_hour;
- e_min += 60 * e_hour;
- s_sec += 60 * s_min;
-
- e_sec += 60 * e_min;
- s_hsec += 1000 * s_sec;
- e_hsec += 1000 * e_sec;
-
- duration = e_hsec - s_hsec;
- }
- *buf += strcspn(*buf, "\n") + 1;
+ if (discard_padding) {
+ put_ebml_sint(pb, MATROSKA_ID_DISCARDPADDING, discard_padding);
+ }
+
+ if (side_data_size && additional_id == 1) {
+ block_additions = start_ebml_master(pb, MATROSKA_ID_BLOCKADDITIONS, 0);
+ block_more = start_ebml_master(pb, MATROSKA_ID_BLOCKMORE, 0);
+ put_ebml_uint(pb, MATROSKA_ID_BLOCKADDID, 1);
+ put_ebml_id(pb, MATROSKA_ID_BLOCKADDITIONAL);
+ put_ebml_num(pb, side_data_size, 0);
+ avio_write(pb, side_data, side_data_size);
+ end_ebml_master(pb, block_more);
+ end_ebml_master(pb, block_additions);
+ }
+ if ((side_data_size && additional_id == 1) || discard_padding) {
+ end_ebml_master(pb, block_group);
}
- return duration;
}
-static int mkv_write_srt_blocks(AVFormatContext *s, AVIOContext *pb,
- AVPacket *pkt)
+static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt)
{
+ MatroskaMuxContext *mkv = s->priv_data;
ebml_master blockgroup;
- AVPacket pkt2 = *pkt;
- int64_t duration = srt_get_duration(&pkt2.data);
- pkt2.size -= pkt2.data - pkt->data;
-
- blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
- mkv_blockgroup_size(pkt2.size));
- mkv_write_block(s, pb, MATROSKA_ID_BLOCK, &pkt2, 0);
- put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration);
+ int id_size, settings_size, size;
+ uint8_t *id, *settings;
+ int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
+ const int flags = 0;
+
+ id_size = 0;
+ id = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ &id_size);
+
+ settings_size = 0;
+ settings = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_SETTINGS,
+ &settings_size);
+
+ size = id_size + 1 + settings_size + 1 + pkt->size;
+
+ av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, "
+ "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n",
+ avio_tell(pb), size, pkt->pts, pkt->dts, pkt->duration, flags);
+
+ blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(size));
+
+ put_ebml_id(pb, MATROSKA_ID_BLOCK);
+ put_ebml_num(pb, size + 4, 0);
+ avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126
+ avio_wb16(pb, ts - mkv->cluster_pts);
+ avio_w8(pb, flags);
+ avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data);
+
+ put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, pkt->duration);
end_ebml_master(pb, blockgroup);
- return duration;
+ return pkt->duration;
}
static void mkv_flush_dynbuf(AVFormatContext *s)
@@ -1486,7 +1688,29 @@ static void mkv_flush_dynbuf(AVFormatContext *s)
mkv->dyn_bc = NULL;
}
-static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+static void mkv_start_new_cluster(AVFormatContext *s, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ AVIOContext *pb;
+
+ if (s->pb->seekable) {
+ pb = s->pb;
+ } else {
+ pb = mkv->dyn_bc;
+ }
+
+ av_log(s, AV_LOG_DEBUG,
+ "Starting new cluster at offset %" PRIu64 " bytes, "
+ "pts %" PRIu64 "dts %" PRIu64 "\n",
+ avio_tell(pb), pkt->pts, pkt->dts);
+ end_ebml_master(pb, mkv->cluster);
+ mkv->cluster_pos = -1;
+ if (mkv->dyn_bc)
+ mkv_flush_dynbuf(s);
+ avio_flush(s->pb);
+}
+
+static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_cue)
{
MatroskaMuxContext *mkv = s->priv_data;
AVIOContext *pb = s->pb;
@@ -1495,6 +1719,8 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
int duration = pkt->duration;
int ret;
int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts;
+ int64_t relative_packet_pos;
+ int dash_tracknum = mkv->is_dash ? mkv->dash_track_number : pkt->stream_index + 1;
if (ts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n");
@@ -1502,42 +1728,59 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
}
ts += mkv->tracks[pkt->stream_index].ts_offset;
+ if (mkv->cluster_pos != -1) {
+ int64_t cluster_time = ts - mkv->cluster_pts + mkv->tracks[pkt->stream_index].ts_offset;
+ if ((int16_t)cluster_time != cluster_time) {
+ av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n");
+ mkv_start_new_cluster(s, pkt);
+ }
+ }
+
if (!s->pb->seekable) {
if (!mkv->dyn_bc) {
ret = avio_open_dyn_buf(&mkv->dyn_bc);
- if (ret < 0)
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open dynamic buffer\n");
return ret;
+ }
}
pb = mkv->dyn_bc;
}
- if (!mkv->cluster_pos) {
+ if (mkv->cluster_pos == -1) {
mkv->cluster_pos = avio_tell(s->pb);
mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER, 0);
put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, FFMAX(0, ts));
mkv->cluster_pts = FFMAX(0, ts);
}
+ relative_packet_pos = avio_tell(s->pb) - mkv->cluster.pos;
+
if (codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7);
- } else if (codec->codec_id == AV_CODEC_ID_SSA) {
- duration = mkv_write_ass_blocks(s, pb, pkt);
- } else if (codec->codec_id == AV_CODEC_ID_SRT) {
- duration = mkv_write_srt_blocks(s, pb, pkt);
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe || add_cue) {
+ ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts, mkv->cluster_pos, relative_packet_pos, -1);
+ if (ret < 0) return ret;
+ }
+ } else {
+ if (codec->codec_id == AV_CODEC_ID_WEBVTT) {
+ duration = mkv_write_vtt_blocks(s, pb, pkt);
} else {
ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
mkv_blockgroup_size(pkt->size));
- duration = pkt->convergence_duration;
+ /* For backward compatibility, prefer convergence_duration. */
+ if (pkt->convergence_duration > 0) {
+ duration = pkt->convergence_duration;
+ }
mkv_write_block(s, pb, MATROSKA_ID_BLOCK, pkt, 0);
put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration);
end_ebml_master(pb, blockgroup);
}
- if (codec->codec_type == AVMEDIA_TYPE_VIDEO && keyframe) {
- ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, ts,
- mkv->cluster_pos);
- if (ret < 0)
- return ret;
+ ret = mkv_add_cuepoint(mkv->cues, pkt->stream_index, dash_tracknum, ts,
+ mkv->cluster_pos, relative_packet_pos, duration);
+ if (ret < 0)
+ return ret;
}
mkv->duration = FFMAX(mkv->duration, ts + duration);
@@ -1551,8 +1794,8 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
int keyframe = !!(pkt->flags & AV_PKT_FLAG_KEY);
int cluster_size;
int64_t cluster_time;
- AVIOContext *pb;
int ret;
+ int start_new_cluster;
if (mkv->tracks[pkt->stream_index].write_dts)
cluster_time = pkt->dts - mkv->cluster_pts;
@@ -1563,32 +1806,40 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
// start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or
// after 4k and on a keyframe
if (s->pb->seekable) {
- pb = s->pb;
- cluster_size = avio_tell(pb) - mkv->cluster_pos;
+ cluster_size = avio_tell(s->pb) - mkv->cluster_pos;
} else {
- pb = mkv->dyn_bc;
- cluster_size = avio_tell(pb);
- }
-
- if (mkv->cluster_pos &&
- (cluster_size > mkv->cluster_size_limit ||
- cluster_time > mkv->cluster_time_limit ||
- (codec_type == AVMEDIA_TYPE_VIDEO && keyframe &&
- cluster_size > 4 * 1024))) {
- av_log(s, AV_LOG_DEBUG,
- "Starting new cluster at offset %" PRIu64 " bytes, "
- "pts %" PRIu64 "dts %" PRIu64 "\n",
- avio_tell(pb), pkt->pts, pkt->dts);
- end_ebml_master(pb, mkv->cluster);
- mkv->cluster_pos = 0;
- if (mkv->dyn_bc)
- mkv_flush_dynbuf(s);
- avio_flush(s->pb);
+ cluster_size = avio_tell(mkv->dyn_bc);
+ }
+
+ if (mkv->is_dash && codec_type == AVMEDIA_TYPE_VIDEO) {
+ // WebM DASH specification states that the first block of every cluster
+ // has to be a key frame. So for DASH video, we only create a cluster
+ // on seeing key frames.
+ start_new_cluster = keyframe;
+ } else if (mkv->is_dash && codec_type == AVMEDIA_TYPE_AUDIO &&
+ (mkv->cluster_pos == -1 ||
+ cluster_time > mkv->cluster_time_limit)) {
+ // For DASH audio, we create a Cluster based on cluster_time_limit
+ start_new_cluster = 1;
+ } else if (!mkv->is_dash &&
+ (cluster_size > mkv->cluster_size_limit ||
+ cluster_time > mkv->cluster_time_limit ||
+ (codec_type == AVMEDIA_TYPE_VIDEO && keyframe &&
+ cluster_size > 4 * 1024))) {
+ start_new_cluster = 1;
+ } else {
+ start_new_cluster = 0;
+ }
+
+ if (mkv->cluster_pos != -1 && start_new_cluster) {
+ mkv_start_new_cluster(s, pkt);
}
// check if we have an audio packet cached
if (mkv->cur_audio_pkt.size > 0) {
- ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt);
+ // for DASH audio, a CuePoint has to be added when there is a new cluster.
+ ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt,
+ mkv->is_dash ? start_new_cluster : 0);
av_free_packet(&mkv->cur_audio_pkt);
if (ret < 0) {
av_log(s, AV_LOG_ERROR,
@@ -1606,8 +1857,11 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
ret = mkv->cur_audio_pkt.buf ? 0 : AVERROR(ENOMEM);
} else
ret = av_dup_packet(&mkv->cur_audio_pkt);
+ if (mkv->cur_audio_pkt.side_data_elems > 0) {
+ ret = av_copy_packet_side_data(&mkv->cur_audio_pkt, &mkv->cur_audio_pkt);
+ }
} else
- ret = mkv_write_packet_internal(s, pkt);
+ ret = mkv_write_packet_internal(s, pkt, 0);
return ret;
}
@@ -1620,12 +1874,12 @@ static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt)
else
pb = mkv->dyn_bc;
if (!pkt) {
- if (mkv->cluster_pos) {
+ if (mkv->cluster_pos != -1) {
av_log(s, AV_LOG_DEBUG,
"Flushing cluster at offset %" PRIu64 " bytes\n",
avio_tell(pb));
end_ebml_master(pb, mkv->cluster);
- mkv->cluster_pos = 0;
+ mkv->cluster_pos = -1;
if (mkv->dyn_bc)
mkv_flush_dynbuf(s);
avio_flush(s->pb);
@@ -1644,7 +1898,7 @@ static int mkv_write_trailer(AVFormatContext *s)
// check if we have an audio packet cached
if (mkv->cur_audio_pkt.size > 0) {
- ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt);
+ ret = mkv_write_packet_internal(s, &mkv->cur_audio_pkt, 0);
av_free_packet(&mkv->cur_audio_pkt);
if (ret < 0) {
av_log(s, AV_LOG_ERROR,
@@ -1656,7 +1910,7 @@ static int mkv_write_trailer(AVFormatContext *s)
if (mkv->dyn_bc) {
end_ebml_master(mkv->dyn_bc, mkv->cluster);
mkv_flush_dynbuf(s);
- } else if (mkv->cluster_pos) {
+ } else if (mkv->cluster_pos != -1) {
end_ebml_master(pb, mkv->cluster);
}
@@ -1674,7 +1928,7 @@ static int mkv_write_trailer(AVFormatContext *s)
currentpos = avio_tell(pb);
avio_seek(pb, mkv->cues_pos, SEEK_SET);
- cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams);
+ cuespos = mkv_write_cues(s, mkv->cues, mkv->tracks, s->nb_streams);
cues_end = avio_tell(pb);
if (cues_end > cuespos + mkv->reserve_cues_space) {
av_log(s, AV_LOG_ERROR,
@@ -1690,7 +1944,7 @@ static int mkv_write_trailer(AVFormatContext *s)
avio_seek(pb, currentpos, SEEK_SET);
} else {
- cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams);
+ cuespos = mkv_write_cues(s, mkv->cues, mkv->tracks, s->nb_streams);
}
ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES,
@@ -1710,8 +1964,10 @@ static int mkv_write_trailer(AVFormatContext *s)
avio_seek(pb, currentpos, SEEK_SET);
}
- end_ebml_master(pb, mkv->segment);
- av_free(mkv->tracks);
+ if (!mkv->is_live) {
+ end_ebml_master(pb, mkv->segment);
+ }
+ av_freep(&mkv->tracks);
av_freep(&mkv->cues->entries);
av_freep(&mkv->cues);
@@ -1735,12 +1991,47 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance)
return 0;
}
+static const AVCodecTag additional_audio_tags[] = {
+ { AV_CODEC_ID_ALAC, 0XFFFFFFFF },
+ { AV_CODEC_ID_EAC3, 0XFFFFFFFF },
+ { AV_CODEC_ID_MLP, 0xFFFFFFFF },
+ { AV_CODEC_ID_OPUS, 0xFFFFFFFF },
+ { AV_CODEC_ID_PCM_S16BE, 0xFFFFFFFF },
+ { AV_CODEC_ID_PCM_S24BE, 0xFFFFFFFF },
+ { AV_CODEC_ID_PCM_S32BE, 0xFFFFFFFF },
+ { AV_CODEC_ID_QDM2, 0xFFFFFFFF },
+ { AV_CODEC_ID_RA_144, 0xFFFFFFFF },
+ { AV_CODEC_ID_RA_288, 0xFFFFFFFF },
+ { AV_CODEC_ID_COOK, 0xFFFFFFFF },
+ { AV_CODEC_ID_TRUEHD, 0xFFFFFFFF },
+ { AV_CODEC_ID_NONE, 0xFFFFFFFF }
+};
+
+static const AVCodecTag additional_video_tags[] = {
+ { AV_CODEC_ID_RV10, 0xFFFFFFFF },
+ { AV_CODEC_ID_RV20, 0xFFFFFFFF },
+ { AV_CODEC_ID_RV30, 0xFFFFFFFF },
+ { AV_CODEC_ID_RV40, 0xFFFFFFFF },
+ { AV_CODEC_ID_VP9, 0xFFFFFFFF },
+ { AV_CODEC_ID_NONE, 0xFFFFFFFF }
+};
+
+static const AVCodecTag additional_subtitle_tags[] = {
+ { AV_CODEC_ID_DVB_SUBTITLE, 0xFFFFFFFF },
+ { AV_CODEC_ID_HDMV_PGS_SUBTITLE, 0xFFFFFFFF },
+ { AV_CODEC_ID_NONE, 0xFFFFFFFF }
+};
+
#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 },
{ "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_INT, { .i64 = 0 }, 0, 1, FLAGS },
+ { "dash_track_number", "Track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 127, FLAGS },
+ { "live", "Write files assuming it is a live stream.", OFFSET(is_live), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
+ { "allow_raw_vfw", "allow RAW VFW mode", OFFSET(allow_raw_vfw), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS },
{ NULL },
};
@@ -1768,9 +2059,10 @@ AVOutputFormat ff_matroska_muxer = {
.flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |
AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
.codec_tag = (const AVCodecTag* const []){
- ff_codec_bmp_tags, ff_codec_wav_tags, 0
+ ff_codec_bmp_tags, ff_codec_wav_tags,
+ additional_audio_tags, additional_video_tags, additional_subtitle_tags, 0
},
- .subtitle_codec = AV_CODEC_ID_SSA,
+ .subtitle_codec = AV_CODEC_ID_ASS,
.query_codec = mkv_query_codec,
.priv_class = &matroska_class,
};
@@ -1792,6 +2084,7 @@ AVOutputFormat ff_webm_muxer = {
.priv_data_size = sizeof(MatroskaMuxContext),
.audio_codec = AV_CODEC_ID_VORBIS,
.video_codec = AV_CODEC_ID_VP8,
+ .subtitle_codec = AV_CODEC_ID_WEBVTT,
.write_header = mkv_write_header,
.write_packet = mkv_write_flush_packet,
.write_trailer = mkv_write_trailer,
@@ -1810,7 +2103,7 @@ static const AVClass mka_class = {
};
AVOutputFormat ff_matroska_audio_muxer = {
.name = "matroska",
- .long_name = NULL_IF_CONFIG_SMALL("Matroska"),
+ .long_name = NULL_IF_CONFIG_SMALL("Matroska Audio"),
.mime_type = "audio/x-matroska",
.extensions = "mka",
.priv_data_size = sizeof(MatroskaMuxContext),
@@ -1822,7 +2115,9 @@ AVOutputFormat ff_matroska_audio_muxer = {
.write_trailer = mkv_write_trailer,
.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT |
AVFMT_ALLOW_FLUSH,
- .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+ .codec_tag = (const AVCodecTag* const []){
+ ff_codec_wav_tags, additional_audio_tags, 0
+ },
.priv_class = &mka_class,
};
#endif
diff --git a/libavformat/md5enc.c b/libavformat/md5enc.c
index 92497045eb..8e87f095c9 100644
--- a/libavformat/md5enc.c
+++ b/libavformat/md5enc.c
@@ -2,38 +2,46 @@
* MD5 encoder (for codec/format testing)
* Copyright (c) 2009 Reimar Döffinger, based on crcenc (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/md5.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/hash.h"
+#include "libavutil/opt.h"
#include "avformat.h"
#include "internal.h"
struct MD5Context {
- struct AVMD5 *md5;
+ const AVClass *avclass;
+ struct AVHashContext *hash;
+ char *hash_name;
+ int format_version;
};
static void md5_finish(struct AVFormatContext *s, char *buf)
{
struct MD5Context *c = s->priv_data;
- uint8_t md5[16];
+ uint8_t md5[AV_HASH_MAX_SIZE];
int i, offset = strlen(buf);
- av_md5_final(c->md5, md5);
- for (i = 0; i < sizeof(md5); i++) {
+ int len = av_hash_get_size(c->hash);
+ av_assert0(len > 0 && len <= sizeof(md5));
+ av_hash_final(c->hash, md5);
+ for (i = 0; i < len; i++) {
snprintf(buf + offset, 3, "%02"PRIx8, md5[i]);
offset += 2;
}
@@ -44,39 +52,55 @@ static void md5_finish(struct AVFormatContext *s, char *buf)
avio_flush(s->pb);
}
+#define OFFSET(x) offsetof(struct MD5Context, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption hash_options[] = {
+ { "hash", "set hash to use", OFFSET(hash_name), AV_OPT_TYPE_STRING, {.str = "md5"}, 0, 0, ENC },
+ { "format_version", "file format version", OFFSET(format_version), AV_OPT_TYPE_INT, {.i64 = 1}, 1, 1, ENC },
+ { NULL },
+};
+
+static const AVClass md5enc_class = {
+ .class_name = "hash encoder class",
+ .item_name = av_default_item_name,
+ .option = hash_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
#if CONFIG_MD5_MUXER
static int write_header(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- c->md5 = av_md5_alloc();
- if (!c->md5)
- return AVERROR(ENOMEM);
- av_md5_init(c->md5);
+ int res = av_hash_alloc(&c->hash, c->hash_name);
+ if (res < 0)
+ return res;
+ av_hash_init(c->hash);
return 0;
}
static int write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
struct MD5Context *c = s->priv_data;
- av_md5_update(c->md5, pkt->data, pkt->size);
+ av_hash_update(c->hash, pkt->data, pkt->size);
return 0;
}
static int write_trailer(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- char buf[64] = "MD5=";
+ char buf[256];
+ av_strlcpy(buf, av_hash_get_name(c->hash), sizeof(buf) - 200);
+ av_strlcat(buf, "=", sizeof(buf) - 200);
md5_finish(s, buf);
- av_freep(&c->md5);
+ av_hash_freep(&c->hash);
return 0;
}
AVOutputFormat ff_md5_muxer = {
.name = "md5",
.long_name = NULL_IF_CONFIG_SMALL("MD5 testing"),
- .extensions = "",
.priv_data_size = sizeof(struct MD5Context),
.audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_RAWVIDEO,
@@ -84,6 +108,7 @@ AVOutputFormat ff_md5_muxer = {
.write_packet = write_packet,
.write_trailer = write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
+ .priv_class = &md5enc_class,
};
#endif
@@ -91,18 +116,23 @@ AVOutputFormat ff_md5_muxer = {
static int framemd5_write_header(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- c->md5 = av_md5_alloc();
- if (!c->md5)
- return AVERROR(ENOMEM);
- return ff_framehash_write_header(s);
+ int res = av_hash_alloc(&c->hash, c->hash_name);
+ if (res < 0)
+ return res;
+ avio_printf(s->pb, "#format: frame checksums\n");
+ avio_printf(s->pb, "#version: %d\n", c->format_version);
+ avio_printf(s->pb, "#hash: %s\n", av_hash_get_name(c->hash));
+ ff_framehash_write_header(s);
+ avio_printf(s->pb, "#stream#, dts, pts, duration, size, hash\n");
+ return 0;
}
static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
struct MD5Context *c = s->priv_data;
char buf[256];
- av_md5_init(c->md5);
- av_md5_update(c->md5, pkt->data, pkt->size);
+ av_hash_init(c->hash);
+ av_hash_update(c->hash, pkt->data, pkt->size);
snprintf(buf, sizeof(buf) - 64, "%d, %10"PRId64", %10"PRId64", %8d, %8d, ",
pkt->stream_index, pkt->dts, pkt->pts, pkt->duration, pkt->size);
@@ -113,14 +143,20 @@ static int framemd5_write_packet(struct AVFormatContext *s, AVPacket *pkt)
static int framemd5_write_trailer(struct AVFormatContext *s)
{
struct MD5Context *c = s->priv_data;
- av_freep(&c->md5);
+ av_hash_freep(&c->hash);
return 0;
}
+static const AVClass framemd5_class = {
+ .class_name = "frame hash encoder class",
+ .item_name = av_default_item_name,
+ .option = hash_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_framemd5_muxer = {
.name = "framemd5",
.long_name = NULL_IF_CONFIG_SMALL("Per-frame MD5 testing"),
- .extensions = "",
.priv_data_size = sizeof(struct MD5Context),
.audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_RAWVIDEO,
@@ -129,5 +165,6 @@ AVOutputFormat ff_framemd5_muxer = {
.write_trailer = framemd5_write_trailer,
.flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
AVFMT_TS_NEGATIVE,
+ .priv_class = &framemd5_class,
};
#endif
diff --git a/libavformat/md5proto.c b/libavformat/md5proto.c
index 12ddde3d8c..6af0a6ed26 100644
--- a/libavformat/md5proto.c
+++ b/libavformat/md5proto.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/metadata.c b/libavformat/metadata.c
index 77fb298217..b9b6de7972 100644
--- a/libavformat/metadata.c
+++ b/libavformat/metadata.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2009 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,7 @@ void ff_metadata_conv(AVDictionary **pm, const AVMetadataConv *d_conv,
AVDictionary *dst = NULL;
const char *key;
- if (d_conv == s_conv)
+ if (d_conv == s_conv || !pm)
return;
while ((mtag = av_dict_get(*pm, "", mtag, AV_DICT_IGNORE_SUFFIX))) {
diff --git a/libavformat/metadata.h b/libavformat/metadata.h
index eee3ee4391..6586094e82 100644
--- a/libavformat/metadata.h
+++ b/libavformat/metadata.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2009 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/mgsts.c b/libavformat/mgsts.c
new file mode 100644
index 0000000000..8cbc9521d6
--- /dev/null
+++ b/libavformat/mgsts.c
@@ -0,0 +1,106 @@
+/*
+ * Metar Gear Solid: The Twin Snakes demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/intfloat.h"
+#include "avformat.h"
+#include "riff.h"
+
+static int read_probe(AVProbeData *p)
+{
+ if (AV_RB32(p->buf ) != 0x000E ||
+ AV_RB32(p->buf + 4) != 0x0050 ||
+ AV_RB32(p->buf + 12) != 0x0034)
+ return 0;
+ return AVPROBE_SCORE_MAX;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ AVRational fps;
+ uint32_t chunk_size;
+
+ avio_skip(pb, 4);
+ chunk_size = avio_rb32(pb);
+ if (chunk_size != 80)
+ return AVERROR(EIO);
+ avio_skip(pb, 20);
+
+ st = avformat_new_stream(s, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
+ st->start_time = 0;
+ st->nb_frames =
+ st->duration = avio_rb32(pb);
+ fps = av_d2q(av_int2float(avio_rb32(pb)), INT_MAX);
+ st->codec->width = avio_rb32(pb);
+ st->codec->height = avio_rb32(pb);
+ avio_skip(pb, 12);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_tag = avio_rb32(pb);
+ st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags,
+ st->codec->codec_tag);
+ avpriv_set_pts_info(st, 64, fps.den, fps.num);
+ avio_skip(pb, 20);
+
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ uint32_t chunk_size, payload_size;
+ int ret;
+
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+
+ avio_skip(pb, 4);
+ chunk_size = avio_rb32(pb);
+ avio_skip(pb, 4);
+ payload_size = avio_rb32(pb);
+
+ if (chunk_size < payload_size + 16)
+ return AVERROR(EIO);
+
+ ret = av_get_packet(pb, pkt, payload_size);
+ if (ret < 0)
+ return ret;
+
+ pkt->pos -= 16;
+ pkt->duration = 1;
+ avio_skip(pb, chunk_size - (ret + 16));
+
+ return ret;
+}
+
+AVInputFormat ff_mgsts_demuxer = {
+ .name = "mgsts",
+ .long_name = NULL_IF_CONFIG_SMALL("Metal Gear Solid: The Twin Snakes"),
+ .read_probe = read_probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/microdvddec.c b/libavformat/microdvddec.c
new file mode 100644
index 0000000000..a3839051a4
--- /dev/null
+++ b/libavformat/microdvddec.c
@@ -0,0 +1,204 @@
+/*
+ * MicroDVD subtitle demuxer
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+#define MAX_LINESIZE 2048
+
+
+typedef struct {
+ const AVClass *class;
+ FFDemuxSubtitlesQueue q;
+ AVRational frame_rate;
+} MicroDVDContext;
+
+
+static int microdvd_probe(AVProbeData *p)
+{
+ unsigned char c;
+ const uint8_t *ptr = p->buf;
+ int i;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+
+ for (i=0; i<3; i++) {
+ if (sscanf(ptr, "{%*d}{}%c", &c) != 1 &&
+ sscanf(ptr, "{%*d}{%*d}%c", &c) != 1 &&
+ sscanf(ptr, "{DEFAULT}{}%c", &c) != 1)
+ return 0;
+ ptr += ff_subtitles_next_line(ptr);
+ }
+ return AVPROBE_SCORE_MAX;
+}
+
+static int64_t get_pts(const char *buf)
+{
+ int frame;
+ char c;
+
+ if (sscanf(buf, "{%d}{%c", &frame, &c) == 2)
+ return frame;
+ return AV_NOPTS_VALUE;
+}
+
+static int get_duration(const char *buf)
+{
+ int frame_start, frame_end;
+
+ if (sscanf(buf, "{%d}{%d}", &frame_start, &frame_end) == 2)
+ return frame_end - frame_start;
+ return -1;
+}
+
+static const char *bom = "\xEF\xBB\xBF";
+
+static int microdvd_read_header(AVFormatContext *s)
+{
+ AVRational pts_info = (AVRational){ 2997, 125 }; /* default: 23.976 fps */
+ MicroDVDContext *microdvd = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ int i = 0;
+ char line_buf[MAX_LINESIZE];
+ int has_real_fps = 0;
+
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ while (!avio_feof(s->pb)) {
+ char *p;
+ AVPacket *sub;
+ int64_t pos = avio_tell(s->pb);
+ int len = ff_get_line(s->pb, line_buf, sizeof(line_buf));
+ char *line = line_buf;
+
+ if (!strncmp(line, bom, 3))
+ line += 3;
+ p = line;
+
+ if (!len)
+ break;
+ line[strcspn(line, "\r\n")] = 0;
+ if (i++ < 3) {
+ int frame;
+ double fps;
+ char c;
+
+ if ((sscanf(line, "{%d}{}%6lf", &frame, &fps) == 2 ||
+ sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2)
+ && frame <= 1 && fps > 3 && fps < 100) {
+ pts_info = av_d2q(fps, 100000);
+ has_real_fps = 1;
+ continue;
+ }
+ if (!st->codec->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) {
+ st->codec->extradata = av_strdup(line + 11);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
+ st->codec->extradata_size = strlen(st->codec->extradata) + 1;
+ continue;
+ }
+ }
+#define SKIP_FRAME_ID \
+ p = strchr(p, '}'); \
+ if (!p) { \
+ av_log(s, AV_LOG_WARNING, "Invalid event \"%s\"" \
+ " at line %d\n", line, i); \
+ continue; \
+ } \
+ p++
+ SKIP_FRAME_ID;
+ SKIP_FRAME_ID;
+ if (!*p)
+ continue;
+ sub = ff_subtitles_queue_insert(&microdvd->q, p, strlen(p), 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ sub->pts = get_pts(line);
+ sub->duration = get_duration(line);
+ }
+ ff_subtitles_queue_finalize(&microdvd->q);
+ if (has_real_fps) {
+ /* export the FPS info only if set in the file */
+ microdvd->frame_rate = pts_info;
+ } else if (microdvd->frame_rate.num) {
+ /* fallback on user specified frame rate */
+ pts_info = microdvd->frame_rate;
+ }
+ avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_MICRODVD;
+ return 0;
+}
+
+static int microdvd_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MicroDVDContext *microdvd = s->priv_data;
+ return ff_subtitles_queue_read_packet(&microdvd->q, pkt);
+}
+
+static int microdvd_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ MicroDVDContext *microdvd = s->priv_data;
+ return ff_subtitles_queue_seek(&microdvd->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int microdvd_read_close(AVFormatContext *s)
+{
+ MicroDVDContext *microdvd = s->priv_data;
+ ff_subtitles_queue_clean(&microdvd->q);
+ return 0;
+}
+
+
+#define OFFSET(x) offsetof(MicroDVDContext, x)
+#define SD AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM
+static const AVOption microdvd_options[] = {
+ { "subfps", "set the movie frame rate fallback", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, SD },
+ { NULL }
+};
+
+static const AVClass microdvd_class = {
+ .class_name = "microdvddec",
+ .item_name = av_default_item_name,
+ .option = microdvd_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_microdvd_demuxer = {
+ .name = "microdvd",
+ .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
+ .priv_data_size = sizeof(MicroDVDContext),
+ .read_probe = microdvd_probe,
+ .read_header = microdvd_read_header,
+ .read_packet = microdvd_read_packet,
+ .read_seek2 = microdvd_read_seek,
+ .read_close = microdvd_read_close,
+ .priv_class = &microdvd_class,
+};
diff --git a/libavformat/microdvdenc.c b/libavformat/microdvdenc.c
new file mode 100644
index 0000000000..4d8438437b
--- /dev/null
+++ b/libavformat/microdvdenc.c
@@ -0,0 +1,67 @@
+/*
+ * MicroDVD subtitle muxer
+ * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <inttypes.h>
+#include "avformat.h"
+#include "internal.h"
+
+static int microdvd_write_header(struct AVFormatContext *s)
+{
+ AVCodecContext *avctx = s->streams[0]->codec;
+ AVRational tb = avctx->time_base;
+
+ if (s->nb_streams != 1 || avctx->codec_id != AV_CODEC_ID_MICRODVD) {
+ av_log(s, AV_LOG_ERROR, "Exactly one MicroDVD stream is needed.\n");
+ return -1;
+ }
+
+ if (avctx->extradata && avctx->extradata_size > 0) {
+ avio_write(s->pb, "{DEFAULT}{}", 11);
+ avio_write(s->pb, avctx->extradata, avctx->extradata_size);
+ avio_flush(s->pb);
+ }
+
+ avpriv_set_pts_info(s->streams[0], 64, tb.num, tb.den);
+ return 0;
+}
+
+static int microdvd_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+ avio_printf(avf->pb, "{%"PRId64"}", pkt->pts);
+ if (pkt->duration < 0)
+ avio_write(avf->pb, "{}", 2);
+ else
+ avio_printf(avf->pb, "{%"PRId64"}", pkt->pts + pkt->duration);
+ avio_write(avf->pb, pkt->data, pkt->size);
+ avio_write(avf->pb, "\n", 1);
+ return 0;
+}
+
+AVOutputFormat ff_microdvd_muxer = {
+ .name = "microdvd",
+ .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle format"),
+ .mime_type = "text/x-microdvd",
+ .extensions = "sub",
+ .write_header = microdvd_write_header,
+ .write_packet = microdvd_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+ .subtitle_codec = AV_CODEC_ID_MICRODVD,
+};
diff --git a/libavformat/mkvtimestamp_v2.c b/libavformat/mkvtimestamp_v2.c
new file mode 100644
index 0000000000..7ba6691952
--- /dev/null
+++ b/libavformat/mkvtimestamp_v2.c
@@ -0,0 +1,50 @@
+/*
+ * extract pts as timecode v2, as defined by mkvtoolnix
+ * Copyright (c) 2009 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+
+static int write_header(AVFormatContext *s)
+{
+ static const char *header = "# timecode format v2\n";
+ avio_write(s->pb, header, strlen(header));
+ avpriv_set_pts_info(s->streams[0], 64, 1, 1000);
+ return 0;
+}
+
+static int write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ char buf[256];
+ if (pkt->stream_index)
+ av_log(s, AV_LOG_WARNING, "More than one stream unsupported\n");
+ snprintf(buf, sizeof(buf), "%" PRId64 "\n", pkt->dts);
+ avio_write(s->pb, buf, strlen(buf));
+ return 0;
+}
+
+AVOutputFormat ff_mkvtimestamp_v2_muxer = {
+ .name = "mkvtimestamp_v2",
+ .long_name = NULL_IF_CONFIG_SMALL("extract pts as timecode v2 format, as defined by mkvtoolnix"),
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = write_header,
+ .write_packet = write_packet,
+};
diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c
new file mode 100644
index 0000000000..aa1ba60d37
--- /dev/null
+++ b/libavformat/mlvdec.c
@@ -0,0 +1,465 @@
+/*
+ * Magic Lantern Video (MLV) demuxer
+ * Copyright (c) 2014 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Magic Lantern Video (MLV) demuxer
+ */
+
+#include "libavutil/eval.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/rational.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "riff.h"
+
+#define MLV_VERSION "v2.0"
+
+#define MLV_VIDEO_CLASS_RAW 1
+#define MLV_VIDEO_CLASS_YUV 2
+#define MLV_VIDEO_CLASS_JPEG 3
+#define MLV_VIDEO_CLASS_H264 4
+
+#define MLV_AUDIO_CLASS_WAV 1
+
+#define MLV_CLASS_FLAG_DELTA 0x40
+#define MLV_CLASS_FLAG_LZMA 0x80
+
+typedef struct {
+ AVIOContext *pb[101];
+ int class[2];
+ int stream_index;
+ uint64_t pts;
+} MlvContext;
+
+static int probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) == MKTAG('M','L','V','I') &&
+ AV_RL32(p->buf + 4) >= 52 &&
+ !memcmp(p->buf + 8, MLV_VERSION, 5))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int check_file_header(AVIOContext *pb, uint64_t guid)
+{
+ unsigned int size;
+ uint8_t version[8];
+
+ avio_skip(pb, 4);
+ size = avio_rl32(pb);
+ if (size < 52)
+ return AVERROR_INVALIDDATA;
+ avio_read(pb, version, 8);
+ if (memcmp(version, MLV_VERSION, 5) || avio_rl64(pb) != guid)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, size - 24);
+ return 0;
+}
+
+static void read_string(AVFormatContext *avctx, AVIOContext *pb, const char *tag, int size)
+{
+ char * value = av_malloc(size + 1);
+ if (!value) {
+ avio_skip(pb, size);
+ return;
+ }
+
+ avio_read(pb, value, size);
+ if (!value[0]) {
+ av_free(value);
+ return;
+ }
+
+ value[size] = 0;
+ av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL);
+}
+
+static void read_uint8(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_r8(pb), 0);
+}
+
+static void read_uint16(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_rl16(pb), 0);
+}
+
+static void read_uint32(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_rl32(pb), 0);
+}
+
+static void read_uint64(AVFormatContext *avctx, AVIOContext *pb, const char *tag, const char *fmt)
+{
+ av_dict_set_int(&avctx->metadata, tag, avio_rl64(pb), 0);
+}
+
+static int scan_file(AVFormatContext *avctx, AVStream *vst, AVStream *ast, int file)
+{
+ MlvContext *mlv = avctx->priv_data;
+ AVIOContext *pb = mlv->pb[file];
+ int ret;
+ while (!avio_feof(pb)) {
+ int type;
+ unsigned int size;
+ type = avio_rl32(pb);
+ size = avio_rl32(pb);
+ avio_skip(pb, 8); //timestamp
+ if (size < 16)
+ break;
+ size -= 16;
+ if (vst && type == MKTAG('R','A','W','I') && size >= 164) {
+ vst->codec->width = avio_rl16(pb);
+ vst->codec->height = avio_rl16(pb);
+ if (avio_rl32(pb) != 1)
+ avpriv_request_sample(avctx, "raw api version");
+ avio_skip(pb, 20); // pointer, width, height, pitch, frame_size
+ vst->codec->bits_per_coded_sample = avio_rl32(pb);
+ avio_skip(pb, 8 + 16 + 24); // black_level, white_level, xywh, active_area, exposure_bias
+ if (avio_rl32(pb) != 0x2010100) /* RGGB */
+ avpriv_request_sample(avctx, "cfa_pattern");
+ avio_skip(pb, 80); // calibration_illuminant1, color_matrix1, dynamic_range
+ vst->codec->pix_fmt = AV_PIX_FMT_BAYER_RGGB16LE;
+ vst->codec->codec_tag = MKTAG('B', 'I', 'T', 16);
+ size -= 164;
+ } else if (ast && type == MKTAG('W', 'A', 'V', 'I') && size >= 16) {
+ ret = ff_get_wav_header(pb, ast->codec, 16, 0);
+ if (ret < 0)
+ return ret;
+ size -= 16;
+ } else if (type == MKTAG('I','N','F','O')) {
+ if (size > 0)
+ read_string(avctx, pb, "info", size);
+ continue;
+ } else if (type == MKTAG('I','D','N','T') && size >= 36) {
+ read_string(avctx, pb, "cameraName", 32);
+ read_uint32(avctx, pb, "cameraModel", "0x%"PRIx32);
+ size -= 36;
+ if (size >= 32) {
+ read_string(avctx, pb, "cameraSerial", 32);
+ size -= 32;
+ }
+ } else if (type == MKTAG('L','E','N','S') && size >= 48) {
+ read_uint16(avctx, pb, "focalLength", "%i");
+ read_uint16(avctx, pb, "focalDist", "%i");
+ read_uint16(avctx, pb, "aperture", "%i");
+ read_uint8(avctx, pb, "stabilizerMode", "%i");
+ read_uint8(avctx, pb, "autofocusMode", "%i");
+ read_uint32(avctx, pb, "flags", "0x%"PRIx32);
+ read_uint32(avctx, pb, "lensID", "%"PRIi32);
+ read_string(avctx, pb, "lensName", 32);
+ size -= 48;
+ if (size >= 32) {
+ read_string(avctx, pb, "lensSerial", 32);
+ size -= 32;
+ }
+ } else if (vst && type == MKTAG('V', 'I', 'D', 'F') && size >= 4) {
+ uint64_t pts = avio_rl32(pb);
+ ff_add_index_entry(&vst->index_entries, &vst->nb_index_entries, &vst->index_entries_allocated_size,
+ avio_tell(pb) - 20, pts, file, 0, AVINDEX_KEYFRAME);
+ size -= 4;
+ } else if (ast && type == MKTAG('A', 'U', 'D', 'F') && size >= 4) {
+ uint64_t pts = avio_rl32(pb);
+ ff_add_index_entry(&ast->index_entries, &ast->nb_index_entries, &ast->index_entries_allocated_size,
+ avio_tell(pb) - 20, pts, file, 0, AVINDEX_KEYFRAME);
+ size -= 4;
+ } else if (vst && type == MKTAG('W','B','A','L') && size >= 28) {
+ read_uint32(avctx, pb, "wb_mode", "%"PRIi32);
+ read_uint32(avctx, pb, "kelvin", "%"PRIi32);
+ read_uint32(avctx, pb, "wbgain_r", "%"PRIi32);
+ read_uint32(avctx, pb, "wbgain_g", "%"PRIi32);
+ read_uint32(avctx, pb, "wbgain_b", "%"PRIi32);
+ read_uint32(avctx, pb, "wbs_gm", "%"PRIi32);
+ read_uint32(avctx, pb, "wbs_ba", "%"PRIi32);
+ size -= 28;
+ } else if (type == MKTAG('R','T','C','I') && size >= 20) {
+ char str[32];
+ struct tm time = { 0 };
+ time.tm_sec = avio_rl16(pb);
+ time.tm_min = avio_rl16(pb);
+ time.tm_hour = avio_rl16(pb);
+ time.tm_mday = avio_rl16(pb);
+ time.tm_mon = avio_rl16(pb);
+ time.tm_year = avio_rl16(pb);
+ time.tm_wday = avio_rl16(pb);
+ time.tm_yday = avio_rl16(pb);
+ time.tm_isdst = avio_rl16(pb);
+ avio_skip(pb, 2);
+ if (strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &time))
+ av_dict_set(&avctx->metadata, "time", str, 0);
+ size -= 20;
+ } else if (type == MKTAG('E','X','P','O') && size >= 16) {
+ av_dict_set(&avctx->metadata, "isoMode", avio_rl32(pb) ? "auto" : "manual", 0);
+ read_uint32(avctx, pb, "isoValue", "%"PRIi32);
+ read_uint32(avctx, pb, "isoAnalog", "%"PRIi32);
+ read_uint32(avctx, pb, "digitalGain", "%"PRIi32);
+ size -= 16;
+ if (size >= 8) {
+ read_uint64(avctx, pb, "shutterValue", "%"PRIi64);
+ size -= 8;
+ }
+ } else if (type == MKTAG('S','T','Y','L') && size >= 36) {
+ read_uint32(avctx, pb, "picStyleId", "%"PRIi32);
+ read_uint32(avctx, pb, "contrast", "%"PRIi32);
+ read_uint32(avctx, pb, "sharpness", "%"PRIi32);
+ read_uint32(avctx, pb, "saturation", "%"PRIi32);
+ read_uint32(avctx, pb, "colortone", "%"PRIi32);
+ read_string(avctx, pb, "picStyleName", 16);
+ size -= 36;
+ } else if (type == MKTAG('M','A','R','K')) {
+ } else if (type == MKTAG('N','U','L','L')) {
+ } else if (type == MKTAG('M','L','V','I')) { /* occurs when MLV and Mnn files are concatenated */
+ } else {
+ av_log(avctx, AV_LOG_INFO, "unsupported tag %c%c%c%c, size %u\n", type&0xFF, (type>>8)&0xFF, (type>>16)&0xFF, (type>>24)&0xFF, size);
+ }
+ avio_skip(pb, size);
+ }
+ return 0;
+}
+
+static int read_header(AVFormatContext *avctx)
+{
+ MlvContext *mlv = avctx->priv_data;
+ AVIOContext *pb = avctx->pb;
+ AVStream *vst = NULL, *ast = NULL;
+ int size, ret;
+ unsigned nb_video_frames, nb_audio_frames;
+ uint64_t guid;
+ char guidstr[32];
+
+ avio_skip(pb, 4);
+ size = avio_rl32(pb);
+ if (size < 52)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(pb, 8);
+
+ guid = avio_rl64(pb);
+ snprintf(guidstr, sizeof(guidstr), "0x%"PRIx64, guid);
+ av_dict_set(&avctx->metadata, "guid", guidstr, 0);
+
+ avio_skip(pb, 8); //fileNum, fileCount, fileFlags
+
+ mlv->class[0] = avio_rl16(pb);
+ mlv->class[1] = avio_rl16(pb);
+
+ nb_video_frames = avio_rl32(pb);
+ nb_audio_frames = avio_rl32(pb);
+
+ if (nb_video_frames && mlv->class[0]) {
+ vst = avformat_new_stream(avctx, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ vst->id = 0;
+ vst->nb_frames = nb_video_frames;
+ if ((mlv->class[0] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA)))
+ avpriv_request_sample(avctx, "compression");
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ switch (mlv->class[0] & ~(MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA)) {
+ case MLV_VIDEO_CLASS_RAW:
+ vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ break;
+ case MLV_VIDEO_CLASS_YUV:
+ vst->codec->pix_fmt = AV_PIX_FMT_YUV420P;
+ vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ vst->codec->codec_tag = 0;
+ break;
+ case MLV_VIDEO_CLASS_JPEG:
+ vst->codec->codec_id = AV_CODEC_ID_MJPEG;
+ vst->codec->codec_tag = 0;
+ break;
+ case MLV_VIDEO_CLASS_H264:
+ vst->codec->codec_id = AV_CODEC_ID_H264;
+ vst->codec->codec_tag = 0;
+ break;
+ default:
+ avpriv_request_sample(avctx, "unknown video class");
+ }
+ }
+
+ if (nb_audio_frames && mlv->class[1]) {
+ ast = avformat_new_stream(avctx, NULL);
+ if (!ast)
+ return AVERROR(ENOMEM);
+ ast->id = 1;
+ ast->nb_frames = nb_audio_frames;
+ if ((mlv->class[1] & MLV_CLASS_FLAG_LZMA))
+ avpriv_request_sample(avctx, "compression");
+ if ((mlv->class[1] & ~MLV_CLASS_FLAG_LZMA) != MLV_AUDIO_CLASS_WAV)
+ avpriv_request_sample(avctx, "unknown audio class");
+
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ avpriv_set_pts_info(ast, 33, 1, ast->codec->sample_rate);
+ }
+
+ if (vst) {
+ AVRational framerate;
+ framerate.num = avio_rl32(pb);
+ framerate.den = avio_rl32(pb);
+ avpriv_set_pts_info(vst, 64, framerate.den, framerate.num);
+ } else
+ avio_skip(pb, 8);
+
+ avio_skip(pb, size - 52);
+
+ /* scan primary file */
+ mlv->pb[100] = avctx->pb;
+ ret = scan_file(avctx, vst, ast, 100);
+ if (ret < 0)
+ return ret;
+
+ /* scan secondary files */
+ if (strlen(avctx->filename) > 2) {
+ int i;
+ char *filename = av_strdup(avctx->filename);
+ AVOpenCallback open_func = avctx->open_cb;
+
+ if (!filename)
+ return AVERROR(ENOMEM);
+
+ if (!open_func)
+ open_func = ffio_open2_wrapper;
+
+ for (i = 0; i < 100; i++) {
+ snprintf(filename + strlen(filename) - 2, 3, "%02d", i);
+ if (open_func(avctx, &mlv->pb[i], filename, AVIO_FLAG_READ, &avctx->interrupt_callback, NULL) < 0)
+ break;
+ if (check_file_header(mlv->pb[i], guid) < 0) {
+ av_log(avctx, AV_LOG_WARNING, "ignoring %s; bad format or guid mismatch\n", filename);
+ avio_closep(&mlv->pb[i]);
+ continue;
+ }
+ av_log(avctx, AV_LOG_INFO, "scanning %s\n", filename);
+ ret = scan_file(avctx, vst, ast, i);
+ if (ret < 0) {
+ av_log(avctx, AV_LOG_WARNING, "ignoring %s; %s\n", filename, av_err2str(ret));
+ avio_closep(&mlv->pb[i]);
+ continue;
+ }
+ }
+ av_free(filename);
+ }
+
+ if (vst)
+ vst->duration = vst->nb_index_entries;
+ if (ast)
+ ast->duration = ast->nb_index_entries;
+
+ if (vst && ast)
+ avio_seek(pb, FFMIN(vst->index_entries[0].pos, ast->index_entries[0].pos), SEEK_SET);
+ else if (vst)
+ avio_seek(pb, vst->index_entries[0].pos, SEEK_SET);
+ else if (ast)
+ avio_seek(pb, ast->index_entries[0].pos, SEEK_SET);
+
+ return 0;
+}
+
+static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
+{
+ MlvContext *mlv = avctx->priv_data;
+ AVIOContext *pb;
+ AVStream *st = avctx->streams[mlv->stream_index];
+ int index, ret;
+ unsigned int size, space;
+
+ if (mlv->pts >= st->duration)
+ return AVERROR_EOF;
+
+ index = av_index_search_timestamp(st, mlv->pts, AVSEEK_FLAG_ANY);
+ if (index < 0) {
+ av_log(avctx, AV_LOG_ERROR, "could not find index entry for frame %"PRId64"\n", mlv->pts);
+ return AVERROR(EIO);
+ }
+
+ pb = mlv->pb[st->index_entries[index].size];
+ avio_seek(pb, st->index_entries[index].pos, SEEK_SET);
+
+ avio_skip(pb, 4); // blockType
+ size = avio_rl32(pb);
+ if (size < 16)
+ return AVERROR_INVALIDDATA;
+ avio_skip(pb, 12); //timestamp, frameNumber
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ avio_skip(pb, 8); // cropPosX, cropPosY, panPosX, panPosY
+ space = avio_rl32(pb);
+ avio_skip(pb, space);
+
+ if ((mlv->class[st->id] & (MLV_CLASS_FLAG_DELTA|MLV_CLASS_FLAG_LZMA))) {
+ ret = AVERROR_PATCHWELCOME;
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ ret = av_get_packet(pb, pkt, (st->codec->width * st->codec->height * st->codec->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));
+ }
+
+ if (ret < 0)
+ return ret;
+
+ pkt->stream_index = mlv->stream_index;
+ pkt->pts = mlv->pts;
+
+ mlv->stream_index++;
+ if (mlv->stream_index == avctx->nb_streams) {
+ mlv->stream_index = 0;
+ mlv->pts++;
+ }
+ return 0;
+}
+
+static int read_seek(AVFormatContext *avctx, int stream_index, int64_t timestamp, int flags)
+{
+ MlvContext *mlv = avctx->priv_data;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
+ if (!avctx->pb->seekable)
+ return AVERROR(EIO);
+
+ mlv->pts = timestamp;
+ return 0;
+}
+
+static int read_close(AVFormatContext *s)
+{
+ MlvContext *mlv = s->priv_data;
+ int i;
+ for (i = 0; i < 100; i++)
+ if (mlv->pb[i])
+ avio_closep(&mlv->pb[i]);
+ return 0;
+}
+
+AVInputFormat ff_mlv_demuxer = {
+ .name = "mlv",
+ .long_name = NULL_IF_CONFIG_SMALL("Magic Lantern Video (MLV)"),
+ .priv_data_size = sizeof(MlvContext),
+ .read_probe = probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_close = read_close,
+ .read_seek = read_seek,
+};
diff --git a/libavformat/mm.c b/libavformat/mm.c
index cdf1010dc6..81ae1a510e 100644
--- a/libavformat/mm.c
+++ b/libavformat/mm.c
@@ -2,20 +2,20 @@
* American Laser Games MM Format Demuxer
* Copyright (c) 2006 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -176,7 +176,6 @@ static int read_packet(AVFormatContext *s,
case MM_TYPE_AUDIO :
if (av_get_packet(s->pb, pkt, length)<0)
return AVERROR(ENOMEM);
- pkt->size = length;
pkt->stream_index = 1;
pkt->pts = mm->audio_pts++;
return 0;
diff --git a/libavformat/mmf.c b/libavformat/mmf.c
index 6fb63bf9ab..c2acec91eb 100644
--- a/libavformat/mmf.c
+++ b/libavformat/mmf.c
@@ -2,20 +2,20 @@
* Yamaha SMAF format
* Copyright (c) 2005 Vidar Madsen
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,11 +24,13 @@
#include "avio_internal.h"
#include "internal.h"
#include "pcm.h"
+#include "rawenc.h"
#include "riff.h"
typedef struct MMFContext {
int64_t atrpos, atsqpos, awapos;
- int64_t data_size;
+ int64_t data_end;
+ int stereo;
} MMFContext;
static const int mmf_rates[] = { 4000, 8000, 11025, 22050, 44100 };
@@ -67,26 +69,38 @@ static int mmf_write_header(AVFormatContext *s)
AVIOContext *pb = s->pb;
int64_t pos;
int rate;
+ const char *version = s->flags & AVFMT_FLAG_BITEXACT ?
+ "VN:Lavf," :
+ "VN:"LIBAVFORMAT_IDENT",";
rate = mmf_rate_code(s->streams[0]->codec->sample_rate);
if (rate < 0) {
- av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d\n",
+ av_log(s, AV_LOG_ERROR, "Unsupported sample rate %d, supported are 4000, 8000, 11025, 22050 and 44100\n",
s->streams[0]->codec->sample_rate);
- return -1;
+ return AVERROR(EINVAL);
+ }
+
+ mmf->stereo = s->streams[0]->codec->channels > 1;
+ if (mmf->stereo &&
+ s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+ av_log(s, AV_LOG_ERROR, "Yamaha SMAF stereo is experimental, "
+ "add '-strict %d' if you want to use it.\n",
+ FF_COMPLIANCE_EXPERIMENTAL);
+ return AVERROR(EINVAL);
}
ffio_wfourcc(pb, "MMMD");
avio_wb32(pb, 0);
pos = ff_start_tag(pb, "CNTI");
avio_w8(pb, 0); /* class */
- avio_w8(pb, 0); /* type */
- avio_w8(pb, 0); /* code type */
+ avio_w8(pb, 1); /* type */
+ avio_w8(pb, 1); /* code type */
avio_w8(pb, 0); /* status */
avio_w8(pb, 0); /* counts */
end_tag_be(pb, pos);
pos = ff_start_tag(pb, "OPDA");
- avio_write(pb, "VN:libavcodec,", sizeof("VN:libavcodec,") -1); /* metadata ("ST:songtitle,VN:version,...") */
+ avio_write(pb, version, strlen(version)); /* metadata ("ST:songtitle,VN:version,...") */
end_tag_be(pb, pos);
avio_write(pb, "ATR\x00", 4);
@@ -94,7 +108,7 @@ static int mmf_write_header(AVFormatContext *s)
mmf->atrpos = avio_tell(pb);
avio_w8(pb, 0); /* format type */
avio_w8(pb, 0); /* sequence type */
- avio_w8(pb, (0 << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */
+ avio_w8(pb, (mmf->stereo << 7) | (1 << 4) | rate); /* (channel << 7) | (format << 4) | rate */
avio_w8(pb, 0); /* wave base bit */
avio_w8(pb, 2); /* time base d */
avio_w8(pb, 2); /* time base g */
@@ -114,13 +128,6 @@ static int mmf_write_header(AVFormatContext *s)
return 0;
}
-static int mmf_write_packet(AVFormatContext *s, AVPacket *pkt)
-{
- AVIOContext *pb = s->pb;
- avio_write(pb, pkt->data, pkt->size);
- return 0;
-}
-
/* Write a variable-length symbol */
static void put_varlength(AVIOContext *pb, int val)
{
@@ -154,7 +161,7 @@ static int mmf_write_trailer(AVFormatContext *s)
/* "play wav" */
avio_w8(pb, 0); /* start time */
- avio_w8(pb, 1); /* (channel << 6) | wavenum */
+ avio_w8(pb, (mmf->stereo << 6) | 1); /* (channel << 6) | wavenum */
gatetime = size * 500 / s->streams[0]->codec->sample_rate;
put_varlength(pb, gatetime); /* duration */
@@ -197,7 +204,7 @@ static int mmf_read_header(AVFormatContext *s)
tag = avio_rl32(pb);
if (tag != MKTAG('M', 'M', 'M', 'D'))
- return -1;
+ return AVERROR_INVALIDDATA;
avio_skip(pb, 4); /* file_size */
/* Skip some unused chunks that may or may not be present */
@@ -214,11 +221,11 @@ static int mmf_read_header(AVFormatContext *s)
/* Tag = "ATRx", where "x" = track number */
if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) {
av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n");
- return -1;
+ return AVERROR_PATCHWELCOME;
}
if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) {
av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag);
- return -1;
+ return AVERROR_PATCHWELCOME;
}
avio_r8(pb); /* format type */
@@ -227,7 +234,7 @@ static int mmf_read_header(AVFormatContext *s)
rate = mmf_rate(params & 0x0f);
if (rate < 0) {
av_log(s, AV_LOG_ERROR, "Invalid sample rate\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
avio_r8(pb); /* wave base bit */
avio_r8(pb); /* time base d */
@@ -247,9 +254,9 @@ static int mmf_read_header(AVFormatContext *s)
/* Make sure it's followed by an Awa chunk, aka wave data */
if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) {
av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag);
- return -1;
+ return AVERROR_INVALIDDATA;
}
- mmf->data_size = size;
+ mmf->data_end = avio_tell(pb) + size;
st = avformat_new_stream(s, NULL);
if (!st)
@@ -258,8 +265,8 @@ static int mmf_read_header(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_ADPCM_YAMAHA;
st->codec->sample_rate = rate;
- st->codec->channels = 1;
- st->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ st->codec->channels = (params >> 7) + 1;
+ st->codec->channel_layout = params >> 7 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
st->codec->bits_per_coded_sample = 4;
st->codec->bit_rate = st->codec->sample_rate *
st->codec->bits_per_coded_sample;
@@ -274,29 +281,20 @@ static int mmf_read_header(AVFormatContext *s)
static int mmf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MMFContext *mmf = s->priv_data;
- int ret, size;
-
- if (s->pb->eof_reached)
- return AVERROR(EIO);
+ int64_t left, size;
+ int ret;
- size = MAX_SIZE;
- if (size > mmf->data_size)
- size = mmf->data_size;
+ left = mmf->data_end - avio_tell(s->pb);
+ size = FFMIN(left, MAX_SIZE);
+ if (avio_feof(s->pb) || size <= 0)
+ return AVERROR_EOF;
- if (!size)
- return AVERROR(EIO);
-
- if (av_new_packet(pkt, size))
- return AVERROR(EIO);
- pkt->stream_index = 0;
-
- ret = avio_read(s->pb, pkt->data, pkt->size);
+ ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
- av_free_packet(pkt);
+ return ret;
- mmf->data_size -= ret;
+ pkt->stream_index = 0;
- pkt->size = ret;
return ret;
}
@@ -308,7 +306,7 @@ AVInputFormat ff_mmf_demuxer = {
.read_probe = mmf_probe,
.read_header = mmf_read_header,
.read_packet = mmf_read_packet,
- .read_seek = ff_pcm_read_seek,
+ .flags = AVFMT_GENERIC_INDEX,
};
#endif
@@ -322,7 +320,7 @@ AVOutputFormat ff_mmf_muxer = {
.audio_codec = AV_CODEC_ID_ADPCM_YAMAHA,
.video_codec = AV_CODEC_ID_NONE,
.write_header = mmf_write_header,
- .write_packet = mmf_write_packet,
+ .write_packet = ff_raw_write_packet,
.write_trailer = mmf_write_trailer,
};
#endif
diff --git a/libavformat/mms.c b/libavformat/mms.c
index 92de81d768..807aadef0f 100644
--- a/libavformat/mms.c
+++ b/libavformat/mms.c
@@ -4,20 +4,20 @@
* Copyright (c) 2007 Björn Axelsson
* Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mms.h"
diff --git a/libavformat/mms.h b/libavformat/mms.h
index e89da41bb6..57e3d7e18a 100644
--- a/libavformat/mms.h
+++ b/libavformat/mms.h
@@ -2,20 +2,20 @@
* MMS protocol common definitions.
* Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_MMS_H
diff --git a/libavformat/mmsh.c b/libavformat/mmsh.c
index 9a40002e05..16f07fec0e 100644
--- a/libavformat/mmsh.c
+++ b/libavformat/mmsh.c
@@ -2,20 +2,20 @@
* MMS protocol over HTTP
* Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -56,6 +56,7 @@ typedef enum {
typedef struct MMSHContext {
MMSContext mms;
+ uint8_t location[1024];
int request_seq; ///< request packet sequence
int chunk_seq; ///< data packet sequence
} MMSHContext;
@@ -65,9 +66,9 @@ static int mmsh_close(URLContext *h)
MMSHContext *mmsh = (MMSHContext *)h->priv_data;
MMSContext *mms = &mmsh->mms;
if (mms->mms_hd)
- ffurl_close(mms->mms_hd);
- av_free(mms->streams);
- av_free(mms->asf_header);
+ ffurl_closep(&mms->mms_hd);
+ av_freep(&mms->streams);
+ av_freep(&mms->asf_header);
return 0;
}
@@ -118,7 +119,7 @@ static int read_data_packet(MMSHContext *mmsh, const int len)
int res;
if (len > sizeof(mms->in_buffer)) {
av_log(NULL, AV_LOG_ERROR,
- "Data packet length %d exceeds the in_buffer size %zu\n",
+ "Data packet length %d exceeds the in_buffer size %"SIZE_SPECIFIER"\n",
len, sizeof(mms->in_buffer));
return AVERROR(EIO);
}
@@ -193,7 +194,7 @@ static int get_http_header_data(MMSHContext *mmsh)
if (len) {
if (len > sizeof(mms->in_buffer)) {
av_log(NULL, AV_LOG_ERROR,
- "Other packet len = %d exceed the in_buffer size %zu\n",
+ "Other packet len = %d exceed the in_buffer size %"SIZE_SPECIFIER"\n",
len, sizeof(mms->in_buffer));
return AVERROR(EIO);
}
@@ -210,10 +211,10 @@ static int get_http_header_data(MMSHContext *mmsh)
}
}
-static int mmsh_open(URLContext *h, const char *uri, int flags)
+static int mmsh_open_internal(URLContext *h, const char *uri, int flags, int timestamp, int64_t pos)
{
int i, port, err;
- char httpname[256], path[256], host[128], location[1024];
+ char httpname[256], path[256], host[128];
char *stream_selection = NULL;
char headers[1024];
MMSHContext *mmsh = h->priv_data;
@@ -221,10 +222,10 @@ static int mmsh_open(URLContext *h, const char *uri, int flags)
mmsh->request_seq = h->is_streamed = 1;
mms = &mmsh->mms;
- av_strlcpy(location, uri, sizeof(location));
+ av_strlcpy(mmsh->location, uri, sizeof(mmsh->location));
av_url_split(NULL, 0, NULL, 0,
- host, sizeof(host), &port, path, sizeof(path), location);
+ host, sizeof(host), &port, path, sizeof(path), mmsh->location);
if (port<0)
port = 80; // default mmsh protocol port
ff_url_join(httpname, sizeof(httpname), "http", NULL, host, port, "%s", path);
@@ -241,7 +242,7 @@ static int mmsh_open(URLContext *h, const char *uri, int flags)
"Pragma: no-cache,rate=1.000000,stream-time=0,"
"stream-offset=0:0,request-context=%u,max-duration=0\r\n"
CLIENTGUID
- "Connection: Close\r\n\r\n",
+ "Connection: Close\r\n",
host, port, mmsh->request_seq++);
av_opt_set(mms->mms_hd->priv_data, "headers", headers, 0);
@@ -282,8 +283,9 @@ static int mmsh_open(URLContext *h, const char *uri, int flags)
CLIENTGUID
"Pragma: stream-switch-count=%d\r\n"
"Pragma: stream-switch-entry=%s\r\n"
- "Connection: Close\r\n\r\n",
- host, port, mmsh->request_seq++, mms->stream_num, stream_selection);
+ "Pragma: no-cache,rate=1.000000,stream-time=%u"
+ "Connection: Close\r\n",
+ host, port, mmsh->request_seq++, mms->stream_num, stream_selection, timestamp);
av_freep(&stream_selection);
if (err < 0) {
av_log(NULL, AV_LOG_ERROR, "Build play request failed!\n");
@@ -312,6 +314,11 @@ fail:
return err;
}
+static int mmsh_open(URLContext *h, const char *uri, int flags)
+{
+ return mmsh_open_internal(h, uri, flags, 0, 0);
+}
+
static int handle_chunk_type(MMSHContext *mmsh)
{
MMSContext *mms = &mmsh->mms;
@@ -358,11 +365,49 @@ static int mmsh_read(URLContext *h, uint8_t *buf, int size)
return res;
}
+static int64_t mmsh_read_seek(URLContext *h, int stream_index,
+ int64_t timestamp, int flags)
+{
+ MMSHContext *mmsh_old = h->priv_data;
+ MMSHContext *mmsh = av_mallocz(sizeof(*mmsh));
+ int ret;
+
+ if (!mmsh)
+ return AVERROR(ENOMEM);
+
+ h->priv_data = mmsh;
+ ret= mmsh_open_internal(h, mmsh_old->location, 0, FFMAX(timestamp, 0), 0);
+ if(ret>=0){
+ h->priv_data = mmsh_old;
+ mmsh_close(h);
+ h->priv_data = mmsh;
+ av_free(mmsh_old);
+ mmsh->mms.asf_header_read_size = mmsh->mms.asf_header_size;
+ }else {
+ h->priv_data = mmsh_old;
+ av_free(mmsh);
+ }
+
+ return ret;
+}
+
+static int64_t mmsh_seek(URLContext *h, int64_t pos, int whence)
+{
+ MMSHContext *mmsh = h->priv_data;
+ MMSContext *mms = &mmsh->mms;
+
+ if(pos == 0 && whence == SEEK_CUR)
+ return mms->asf_header_read_size + mms->remaining_in_len + mmsh->chunk_seq * (int64_t)mms->asf_packet_len;
+ return AVERROR(ENOSYS);
+}
+
URLProtocol ff_mmsh_protocol = {
.name = "mmsh",
.url_open = mmsh_open,
.url_read = mmsh_read,
+ .url_seek = mmsh_seek,
.url_close = mmsh_close,
+ .url_read_seek = mmsh_read_seek,
.priv_data_size = sizeof(MMSHContext),
.flags = URL_PROTOCOL_FLAG_NETWORK,
};
diff --git a/libavformat/mmst.c b/libavformat/mmst.c
index b2d9a0d3b8..aa245ea530 100644
--- a/libavformat/mmst.c
+++ b/libavformat/mmst.c
@@ -4,20 +4,20 @@
* Copyright (c) 2007 Björn Axelsson
* Copyright (c) 2010 Zhentan Feng <spyfeng at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -152,7 +152,7 @@ static int send_command_packet(MMSTContext *mmst)
return 0;
}
-static void mms_put_utf16(MMSContext *mms, uint8_t *src)
+static int mms_put_utf16(MMSContext *mms, const uint8_t *src)
{
AVIOContext bic;
int size = mms->write_out_ptr - mms->out_buffer;
@@ -161,7 +161,10 @@ static void mms_put_utf16(MMSContext *mms, uint8_t *src)
sizeof(mms->out_buffer) - size, 1, NULL, NULL, NULL, NULL);
len = avio_put_str16le(&bic, src);
+ if (len < 0)
+ return len;
mms->write_out_ptr += len;
+ return 0;
}
static int send_time_test_data(MMSTContext *mmst)
@@ -173,6 +176,7 @@ static int send_time_test_data(MMSTContext *mmst)
static int send_protocol_select(MMSTContext *mmst)
{
+ int ret;
char data_string[256];
MMSContext *mms = &mmst->mms;
@@ -189,18 +193,21 @@ static int send_protocol_select(MMSTContext *mmst)
"TCP", // or UDP
LOCAL_PORT);
- mms_put_utf16(mms, data_string);
+ if ((ret = mms_put_utf16(mms, data_string)) < 0)
+ return ret;
return send_command_packet(mmst);
}
static int send_media_file_request(MMSTContext *mmst)
{
+ int ret;
MMSContext *mms = &mmst->mms;
start_command_packet(mmst, CS_PKT_MEDIA_FILE_REQUEST);
insert_command_prefixes(mms, 1, 0xffffffff);
bytestream_put_le32(&mms->write_out_ptr, 0);
bytestream_put_le32(&mms->write_out_ptr, 0);
- mms_put_utf16(mms, mmst->path + 1); // +1 for skip "/"
+ if ((ret = mms_put_utf16(mms, mmst->path + 1)) < 0) // +1 for skip "/"
+ return ret;
return send_command_packet(mmst);
}
@@ -277,7 +284,7 @@ static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst)
if (length_remaining < 0
|| length_remaining > sizeof(mms->in_buffer) - 12) {
av_log(NULL, AV_LOG_ERROR,
- "Incoming packet length %d exceeds bufsize %zu\n",
+ "Incoming packet length %d exceeds bufsize %"SIZE_SPECIFIER"\n",
length_remaining, sizeof(mms->in_buffer) - 12);
return AVERROR_INVALIDDATA;
}
@@ -313,7 +320,7 @@ static MMSSCPacketType get_tcp_server_response(MMSTContext *mmst)
if (length_remaining < 0
|| length_remaining > sizeof(mms->in_buffer) - 8) {
av_log(NULL, AV_LOG_ERROR,
- "Data length %d is invalid or too large (max=%zu)\n",
+ "Data length %d is invalid or too large (max=%"SIZE_SPECIFIER")\n",
length_remaining, sizeof(mms->in_buffer));
return AVERROR_INVALIDDATA;
}
@@ -417,6 +424,7 @@ static int send_media_header_request(MMSTContext *mmst)
static int send_startup_packet(MMSTContext *mmst)
{
char data_string[256];
+ int ret;
MMSContext *mms = &mmst->mms;
// SubscriberName is defined in MS specification linked below.
// The guid value can be any valid value.
@@ -429,7 +437,8 @@ static int send_startup_packet(MMSTContext *mmst)
start_command_packet(mmst, CS_PKT_INITIAL);
insert_command_prefixes(mms, 0, 0x0004000b);
bytestream_put_le32(&mms->write_out_ptr, 0x0003001c);
- mms_put_utf16(mms, data_string);
+ if ((ret = mms_put_utf16(mms, data_string)) < 0)
+ return ret;
return send_command_packet(mmst);
}
@@ -468,8 +477,8 @@ static int mms_close(URLContext *h)
}
/* free all separately allocated pointers in mms */
- av_free(mms->streams);
- av_free(mms->asf_header);
+ av_freep(&mms->streams);
+ av_freep(&mms->asf_header);
return 0;
}
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 70fa1e0775..e32f7f436d 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -6,20 +6,20 @@
* first version by Francois Revol <revol@free.fr>
* seek function by Gael Chardon <gael.dev@4now.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,7 +35,9 @@
#include "libavutil/time_internal.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
+#include "libavutil/display.h"
#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#include "libavcodec/ac3tab.h"
#include "avformat.h"
#include "internal.h"
@@ -53,10 +55,6 @@
#include "qtpalette.h"
-
-#undef NDEBUG
-#include <assert.h>
-
/* those functions parse an atom */
/* links atom IDs to parse functions */
typedef struct MOVParseTableEntry {
@@ -65,6 +63,7 @@ typedef struct MOVParseTableEntry {
} MOVParseTableEntry;
static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom);
+static int mov_read_mfra(MOVContext *c, AVIOContext *f);
static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
unsigned len, const char *key)
@@ -89,16 +88,13 @@ static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
static int mov_metadata_int8_bypass_padding(MOVContext *c, AVIOContext *pb,
unsigned len, const char *key)
{
- char buf[16];
-
/* bypass padding bytes */
avio_r8(pb);
avio_r8(pb);
avio_r8(pb);
- snprintf(buf, sizeof(buf), "%d", avio_r8(pb));
c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
- av_dict_set(&c->fc->metadata, key, buf, 0);
+ av_dict_set_int(&c->fc->metadata, key, avio_r8(pb), 0);
return 0;
}
@@ -106,11 +102,8 @@ static int mov_metadata_int8_bypass_padding(MOVContext *c, AVIOContext *pb,
static int mov_metadata_int8_no_padding(MOVContext *c, AVIOContext *pb,
unsigned len, const char *key)
{
- char buf[16];
-
- snprintf(buf, sizeof(buf), "%d", avio_r8(pb));
c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
- av_dict_set(&c->fc->metadata, key, buf, 0);
+ av_dict_set_int(&c->fc->metadata, key, avio_r8(pb), 0);
return 0;
}
@@ -119,16 +112,14 @@ static int mov_metadata_gnre(MOVContext *c, AVIOContext *pb,
unsigned len, const char *key)
{
short genre;
- char buf[20];
avio_r8(pb); // unknown
genre = avio_r8(pb);
if (genre < 1 || genre > ID3v1_GENRE_MAX)
return 0;
- snprintf(buf, sizeof(buf), "%s", ff_id3v1_genre_str[genre-1]);
c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
- av_dict_set(&c->fc->metadata, key, buf, 0);
+ av_dict_set(&c->fc->metadata, key, ff_id3v1_genre_str[genre-1], 0);
return 0;
}
@@ -163,7 +154,7 @@ static int mov_read_mac_string(MOVContext *c, AVIOContext *pb, int len,
uint8_t t, c = avio_r8(pb);
if (c < 0x80 && p < end)
*p++ = c;
- else
+ else if (p < end)
PUT_UTF8(mac_to_unicode[c-0x80], t, if (p < end) *p++ = t;);
}
*p = 0;
@@ -220,8 +211,10 @@ static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len)
double longitude, latitude;
const char *key = "location";
- if (len < 4 + 2 + 1 + 1 + 4 + 4 + 4)
+ if (len < 4 + 2 + 1 + 1 + 4 + 4 + 4) {
+ av_log(c->fc, AV_LOG_ERROR, "loci too short\n");
return AVERROR_INVALIDDATA;
+ }
avio_skip(pb, 4); // version+flags
langcode = avio_rb16(pb);
@@ -229,13 +222,17 @@ static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len)
len -= 6;
len -= avio_get_str(pb, len, buf, sizeof(buf)); // place name
- if (len < 1)
+ if (len < 1) {
+ av_log(c->fc, AV_LOG_ERROR, "place name too long\n");
return AVERROR_INVALIDDATA;
+ }
avio_skip(pb, 1); // role
len -= 1;
- if (len < 14)
+ if (len < 12) {
+ av_log(c->fc, AV_LOG_ERROR, "no space for coordinates left (%d)\n", len);
return AVERROR_INVALIDDATA;
+ }
longitude = ((int32_t) avio_rb32(pb)) / (float) (1 << 16);
latitude = ((int32_t) avio_rb32(pb)) / (float) (1 << 16);
@@ -253,7 +250,8 @@ static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len)
static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
char tmp_key[5];
- char *str, key2[32], language[4] = {0};
+ char key2[32], language[4] = {0};
+ char *str = NULL;
const char *key = NULL;
uint16_t langcode = 0;
uint32_t data_type = 0, str_size, str_size_alloc;
@@ -346,11 +344,11 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
case MKTAG(0xa9,'w','r','t'): key = "composer"; break;
case MKTAG(0xa9,'x','y','z'): key = "location"; break;
}
-
+retry:
if (c->itunes_metadata && atom.size > 8) {
int data_size = avio_rb32(pb);
int tag = avio_rl32(pb);
- if (tag == MKTAG('d','a','t','a')) {
+ if (tag == MKTAG('d','a','t','a') && data_size <= atom.size) {
data_type = avio_rb32(pb); // type
avio_rb32(pb); // unknown
str_size = data_size - 16;
@@ -360,12 +358,18 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
int ret = mov_read_covr(c, pb, data_type, str_size);
if (ret < 0) {
av_log(c->fc, AV_LOG_ERROR, "Error parsing cover art.\n");
- return ret;
}
+ return ret;
}
} else return 0;
} else if (atom.size > 4 && key && !c->itunes_metadata && !raw) {
str_size = avio_rb16(pb); // string length
+ if (str_size > atom.size) {
+ raw = 1;
+ avio_seek(pb, -2, SEEK_CUR);
+ av_log(c->fc, AV_LOG_WARNING, "UDTA parsing failed retrying raw\n");
+ goto retry;
+ }
langcode = avio_rb16(pb);
ff_mov_lang_to_iso639(langcode, language);
atom.size -= 4;
@@ -379,12 +383,12 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!key)
return 0;
- if (atom.size < 0)
+ if (atom.size < 0 || str_size >= INT_MAX/2)
return AVERROR_INVALIDDATA;
- // allocate twice as much as worst-case
+ // worst-case requirement for output string in case of utf8 coded input
str_size_alloc = (raw ? str_size : str_size * 2) + 1;
- str = av_malloc(str_size_alloc);
+ str = av_mallocz(str_size_alloc);
if (!str)
return AVERROR(ENOMEM);
@@ -394,7 +398,11 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!raw && (data_type == 3 || (data_type == 0 && (langcode < 0x400 || langcode == 0x7fff)))) { // MAC Encoded
mov_read_mac_string(c, pb, str_size, str, str_size_alloc);
} else {
- avio_read(pb, str, str_size);
+ int ret = avio_read(pb, str, str_size);
+ if (ret != str_size) {
+ av_freep(&str);
+ return ret < 0 ? ret : AVERROR_INVALIDDATA;
+ }
str[str_size] = 0;
}
c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
@@ -437,7 +445,8 @@ static int mov_read_chpl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((atom.size -= 9+str_len) < 0)
return 0;
- avio_read(pb, str, str_len);
+ if (avio_read(pb, str, str_len) != str_len)
+ return AVERROR_INVALIDDATA;
str[str_len] = 0;
avpriv_new_chapter(c->fc, i, (AVRational){1,10000000}, start, AV_NOPTS_VALUE, str);
}
@@ -462,6 +471,7 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
entries >= UINT_MAX / sizeof(*sc->drefs))
return AVERROR_INVALIDDATA;
av_free(sc->drefs);
+ sc->drefs_count = 0;
sc->drefs = av_mallocz(entries * sizeof(*sc->drefs));
if (!sc->drefs)
return AVERROR(ENOMEM);
@@ -488,7 +498,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
volume_len = avio_r8(pb);
volume_len = FFMIN(volume_len, 27);
- avio_read(pb, dref->volume, 27);
+ if (avio_read(pb, dref->volume, 27) != 27)
+ return AVERROR_INVALIDDATA;
dref->volume[volume_len] = 0;
av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", dref->volume, volume_len);
@@ -496,7 +507,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
len = avio_r8(pb);
len = FFMIN(len, 63);
- avio_read(pb, dref->filename, 63);
+ if (avio_read(pb, dref->filename, 63) != 63)
+ return AVERROR_INVALIDDATA;
dref->filename[len] = 0;
av_log(c->fc, AV_LOG_DEBUG, "filename %s, len %d\n", dref->filename, len);
@@ -511,7 +523,7 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_skip(pb, 16);
for (type = 0; type != -1 && avio_tell(pb) < next; ) {
- if (pb->eof_reached)
+ if(avio_feof(pb))
return AVERROR_EOF;
type = avio_rb16(pb);
len = avio_rb16(pb);
@@ -523,7 +535,10 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
dref->path = av_mallocz(len+1);
if (!dref->path)
return AVERROR(ENOMEM);
- avio_read(pb, dref->path, len);
+ if (avio_read(pb, dref->path, len) != len) {
+ av_freep(&dref->path);
+ return AVERROR_INVALIDDATA;
+ }
if (type == 18) // no additional processing needed
continue;
if (len > volume_len && !strncmp(dref->path, dref->volume, volume_len)) {
@@ -540,7 +555,10 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
dref->dir = av_malloc(len+1);
if (!dref->dir)
return AVERROR(ENOMEM);
- avio_read(pb, dref->dir, len);
+ if (avio_read(pb, dref->dir, len) != len) {
+ av_freep(&dref->dir);
+ return AVERROR_INVALIDDATA;
+ }
dref->dir[len] = 0;
for (j = 0; j < len; j++)
if (dref->dir[j] == ':')
@@ -596,7 +614,10 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
title_str = av_malloc(title_size + 1); /* Add null terminator */
if (!title_str)
return AVERROR(ENOMEM);
- avio_read(pb, title_str, title_size);
+ if (avio_read(pb, title_str, title_size) != title_size) {
+ av_freep(&title_str);
+ return AVERROR_INVALIDDATA;
+ }
title_str[title_size] = 0;
if (title_str[0]) {
int off = (!c->isom && title_str[0] == title_size - 1);
@@ -725,12 +746,16 @@ static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom)
static int mov_read_wfex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
+ int ret;
if (c->fc->nb_streams < 1)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
- return ff_get_wav_header(pb, st->codec, atom.size);
+ if ((ret = ff_get_wav_header(pb, st->codec, atom.size, 0)) < 0)
+ av_log(c->fc, AV_LOG_WARNING, "get_wav_header failed\n");
+
+ return ret;
}
static int mov_read_pasp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -750,8 +775,8 @@ static int mov_read_pasp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
num, den);
} else if (den != 0) {
- st->sample_aspect_ratio.num = num;
- st->sample_aspect_ratio.den = den;
+ av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den,
+ num, den, 32767);
}
return 0;
}
@@ -770,18 +795,17 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
uint32_t minor_ver;
int comp_brand_size;
- char minor_ver_str[11]; /* 32 bit integer -> 10 digits + null */
char* comp_brands_str;
uint8_t type[5] = {0};
- avio_read(pb, type, 4);
+ if (avio_read(pb, type, 4) != 4)
+ return AVERROR_INVALIDDATA;
if (strcmp(type, "qt "))
c->isom = 1;
av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type);
av_dict_set(&c->fc->metadata, "major_brand", type, 0);
minor_ver = avio_rb32(pb); /* minor version */
- snprintf(minor_ver_str, sizeof(minor_ver_str), "%"PRIu32"", minor_ver);
- av_dict_set(&c->fc->metadata, "minor_version", minor_ver_str, 0);
+ av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0);
comp_brand_size = atom.size - 8;
if (comp_brand_size < 0)
@@ -789,7 +813,10 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
comp_brands_str = av_malloc(comp_brand_size + 1); /* Add null terminator */
if (!comp_brands_str)
return AVERROR(ENOMEM);
- avio_read(pb, comp_brands_str, comp_brand_size);
+ if (avio_read(pb, comp_brands_str, comp_brand_size) != comp_brand_size) {
+ av_freep(&comp_brands_str);
+ return AVERROR_INVALIDDATA;
+ }
comp_brands_str[comp_brand_size] = 0;
av_dict_set(&c->fc->metadata, "compatible_brands", comp_brands_str, 0);
av_freep(&comp_brands_str);
@@ -802,6 +829,12 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
int ret;
+ if (c->found_moov) {
+ av_log(c->fc, AV_LOG_WARNING, "Found duplicated MOOV Atom. Skipped it\n");
+ avio_skip(pb, atom.size);
+ return 0;
+ }
+
if ((ret = mov_read_default(c, pb, atom)) < 0)
return ret;
/* we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat' */
@@ -812,18 +845,36 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
+ if (!c->has_looked_for_mfra && c->use_mfra_for > 0) {
+ c->has_looked_for_mfra = 1;
+ if (pb->seekable) {
+ int ret;
+ av_log(c->fc, AV_LOG_VERBOSE, "stream has moof boxes, will look "
+ "for a mfra\n");
+ if ((ret = mov_read_mfra(c, pb)) < 0) {
+ av_log(c->fc, AV_LOG_VERBOSE, "found a moof box but failed to "
+ "read the mfra (may be a live ismv)\n");
+ }
+ } else {
+ av_log(c->fc, AV_LOG_VERBOSE, "found a moof box but stream is not "
+ "seekable, can not look for mfra\n");
+ }
+ }
c->fragment.moof_offset = c->fragment.implicit_offset = avio_tell(pb) - 8;
av_log(c->fc, AV_LOG_TRACE, "moof offset %"PRIx64"\n", c->fragment.moof_offset);
return mov_read_default(c, pb, atom);
}
-static void mov_metadata_creation_time(AVDictionary **metadata, time_t time)
+static void mov_metadata_creation_time(AVDictionary **metadata, int64_t time)
{
char buffer[32];
if (time) {
struct tm *ptm, tmbuf;
- time -= 2082844800; /* seconds between 1904-01-01 and Epoch */
- ptm = gmtime_r(&time, &tmbuf);
+ time_t timet;
+ if(time >= 2082844800)
+ time -= 2082844800; /* seconds between 1904-01-01 and Epoch */
+ timet = time;
+ ptm = gmtime_r(&timet, &tmbuf);
if (!ptm) return;
if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm))
av_dict_set(metadata, "creation_time", buffer, 0);
@@ -837,7 +888,7 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
int version;
char language[4] = {0};
unsigned lang;
- time_t creation_time;
+ int64_t creation_time;
if (c->fc->nb_streams < 1)
return 0;
@@ -877,7 +928,7 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
- time_t creation_time;
+ int64_t creation_time;
int version = avio_r8(pb); /* version */
avio_rb24(pb); /* flags */
@@ -894,6 +945,10 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_log(c->fc, AV_LOG_TRACE, "time scale = %i\n", c->time_scale);
c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */
+ // set the AVCodecContext duration because the duration of individual tracks
+ // may be inaccurate
+ if (c->time_scale > 0 && !c->trex_data)
+ c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
avio_rb32(pb); /* preferred scale */
avio_rb16(pb); /* preferred volume */
@@ -909,31 +964,6 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb); /* selection duration */
avio_rb32(pb); /* current time */
avio_rb32(pb); /* next track ID */
-
- return 0;
-}
-
-static int mov_read_smi(MOVContext *c, AVIOContext *pb, MOVAtom atom)
-{
- AVStream *st;
-
- if (c->fc->nb_streams < 1)
- return 0;
- st = c->fc->streams[c->fc->nb_streams-1];
-
- if ((uint64_t)atom.size > (1<<30))
- return AVERROR_INVALIDDATA;
-
- // currently SVQ3 decoder expect full STSD header - so let's fake it
- // this should be fixed and just SMI header should be passed
- av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size + 0x5a + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
- st->codec->extradata_size = 0x5a + atom.size;
- memcpy(st->codec->extradata, "SVQ3", 4); // fake
- avio_read(pb, st->codec->extradata + 0x5a, atom.size);
- av_log(c->fc, AV_LOG_TRACE, "Reading SMI %"PRId64" %s\n", atom.size, st->codec->extradata + 0x5a);
return 0;
}
@@ -946,7 +976,7 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
- little_endian = !!avio_rb16(pb);
+ little_endian = avio_rb16(pb) & 0xFF;
av_log(c->fc, AV_LOG_TRACE, "enda %d\n", little_endian);
if (little_endian == 1) {
switch (st->codec->codec_id) {
@@ -979,7 +1009,8 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
st = c->fc->streams[c->fc->nb_streams - 1];
- avio_read(pb, color_parameter_type, 4);
+ if (avio_read(pb, color_parameter_type, 4) != 4)
+ return AVERROR_INVALIDDATA;
if (strncmp(color_parameter_type, "nclx", 4) &&
strncmp(color_parameter_type, "nclc", 4)) {
av_log(c->fc, AV_LOG_WARNING, "unsupported color_parameter_type %s\n",
@@ -992,7 +1023,7 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
color_matrix = avio_rb16(pb);
av_log(c->fc, AV_LOG_TRACE,
- "%s: pri %"PRIu16" trc %"PRIu16" matrix %"PRIu16"",
+ "%s: pri %d trc %d matrix %d",
color_parameter_type, color_primaries, color_trc, color_matrix);
if (!strncmp(color_parameter_type, "nclx", 4)) {
@@ -1073,30 +1104,175 @@ static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static int mov_realloc_extradata(AVCodecContext *codec, MOVAtom atom)
+{
+ int err = 0;
+ uint64_t size = (uint64_t)codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE;
+ if (size > INT_MAX || (uint64_t)atom.size > INT_MAX)
+ return AVERROR_INVALIDDATA;
+ if ((err = av_reallocp(&codec->extradata, size)) < 0) {
+ codec->extradata_size = 0;
+ return err;
+ }
+ codec->extradata_size = size - FF_INPUT_BUFFER_PADDING_SIZE;
+ return 0;
+}
+
+/* Read a whole atom into the extradata return the size of the atom read, possibly truncated if != atom.size */
+static int64_t mov_read_atom_into_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom,
+ AVCodecContext *codec, uint8_t *buf)
+{
+ int64_t result = atom.size;
+ int err;
+
+ AV_WB32(buf , atom.size + 8);
+ AV_WL32(buf + 4, atom.type);
+ err = avio_read(pb, buf + 8, atom.size);
+ if (err < 0) {
+ codec->extradata_size -= atom.size;
+ return err;
+ } else if (err < atom.size) {
+ av_log(c->fc, AV_LOG_WARNING, "truncated extradata\n");
+ codec->extradata_size -= atom.size - err;
+ result = err;
+ }
+ memset(buf + 8 + err, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ return result;
+}
+
/* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */
-static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom,
+ enum AVCodecID codec_id)
{
AVStream *st;
- uint64_t size;
- uint8_t *buf;
+ uint64_t original_size;
int err;
if (c->fc->nb_streams < 1) // will happen with jp2 files
return 0;
- st= c->fc->streams[c->fc->nb_streams-1];
- size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE;
- if (size > INT_MAX || (uint64_t)atom.size > INT_MAX)
- return AVERROR_INVALIDDATA;
- if ((err = av_reallocp(&st->codec->extradata, size)) < 0) {
- st->codec->extradata_size = 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+
+ if (st->codec->codec_id != codec_id)
+ return 0; /* unexpected codec_id - don't mess with extradata */
+
+ original_size = st->codec->extradata_size;
+ err = mov_realloc_extradata(st->codec, atom);
+ if (err)
+ return err;
+
+ err = mov_read_atom_into_extradata(c, pb, atom, st->codec, st->codec->extradata + original_size);
+ if (err < 0)
return err;
+ return 0; // Note: this is the original behavior to ignore truncation.
+}
+
+/* wrapper functions for reading ALAC/AVS/MJPEG/MJPEG2000 extradata atoms only for those codecs */
+static int mov_read_alac(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, AV_CODEC_ID_ALAC);
+}
+
+static int mov_read_avss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVS);
+}
+
+static int mov_read_jp2h(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, AV_CODEC_ID_JPEG2000);
+}
+
+static int mov_read_dpxe(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, AV_CODEC_ID_R10K);
+}
+
+static int mov_read_avid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_AVUI);
+ if(ret == 0)
+ ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_DNXHD);
+ return ret;
+}
+
+static int mov_read_targa_y216(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret = mov_read_extradata(c, pb, atom, AV_CODEC_ID_TARGA_Y216);
+
+ if (!ret && c->fc->nb_streams >= 1) {
+ AVCodecContext *avctx = c->fc->streams[c->fc->nb_streams-1]->codec;
+ if (avctx->extradata_size >= 40) {
+ avctx->height = AV_RB16(&avctx->extradata[36]);
+ avctx->width = AV_RB16(&avctx->extradata[38]);
+ }
}
- buf = st->codec->extradata + st->codec->extradata_size;
- st->codec->extradata_size= size - FF_INPUT_BUFFER_PADDING_SIZE;
- AV_WB32( buf , atom.size + 8);
- AV_WL32( buf + 4, atom.type);
- avio_read(pb, buf + 8, atom.size);
- return 0;
+ return ret;
+}
+
+static int mov_read_ares(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ if (c->fc->nb_streams >= 1) {
+ AVCodecContext *codec = c->fc->streams[c->fc->nb_streams-1]->codec;
+ if (codec->codec_tag == MKTAG('A', 'V', 'i', 'n') &&
+ codec->codec_id == AV_CODEC_ID_H264 &&
+ atom.size > 11) {
+ avio_skip(pb, 10);
+ /* For AVID AVCI50, force width of 1440 to be able to select the correct SPS and PPS */
+ if (avio_rb16(pb) == 0xd4d)
+ codec->width = 1440;
+ return 0;
+ }
+ }
+
+ return mov_read_avid(c, pb, atom);
+}
+
+static int mov_read_aclr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret = 0;
+ int length = 0;
+ uint64_t original_size;
+ if (c->fc->nb_streams >= 1) {
+ AVCodecContext *codec = c->fc->streams[c->fc->nb_streams-1]->codec;
+ if (codec->codec_id == AV_CODEC_ID_H264)
+ return 0;
+ if (atom.size == 16) {
+ original_size = codec->extradata_size;
+ ret = mov_realloc_extradata(codec, atom);
+ if (!ret) {
+ length = mov_read_atom_into_extradata(c, pb, atom, codec, codec->extradata + original_size);
+ if (length == atom.size) {
+ const uint8_t range_value = codec->extradata[original_size + 19];
+ switch (range_value) {
+ case 1:
+ codec->color_range = AVCOL_RANGE_MPEG;
+ break;
+ case 2:
+ codec->color_range = AVCOL_RANGE_JPEG;
+ break;
+ default:
+ av_log(c, AV_LOG_WARNING, "ignored unknown aclr value (%d)\n", range_value);
+ break;
+ }
+ av_dlog(c, "color_range: %d\n", codec->color_range);
+ } else {
+ /* For some reason the whole atom was not added to the extradata */
+ av_log(c, AV_LOG_ERROR, "aclr not decoded - incomplete atom\n");
+ }
+ } else {
+ av_log(c, AV_LOG_ERROR, "aclr not decoded - unable to add atom to extradata\n");
+ }
+ } else {
+ av_log(c, AV_LOG_WARNING, "aclr not decoded - unexpected size %"PRId64"\n", atom.size);
+ }
+ }
+
+ return ret;
+}
+
+static int mov_read_svq3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, AV_CODEC_ID_SVQ3);
}
static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -1110,14 +1286,13 @@ static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((uint64_t)atom.size > (1<<30))
return AVERROR_INVALIDDATA;
- if (st->codec->codec_id == AV_CODEC_ID_QDM2 || st->codec->codec_id == AV_CODEC_ID_QDMC) {
+ if (st->codec->codec_id == AV_CODEC_ID_QDM2 ||
+ st->codec->codec_id == AV_CODEC_ID_QDMC ||
+ st->codec->codec_id == AV_CODEC_ID_SPEEX) {
// pass all frma atom to codec, needed at least for QDMC and QDM2
- av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ av_freep(&st->codec->extradata);
+ if (ff_get_extradata(st->codec, pb, atom.size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size;
- avio_read(pb, st->codec->extradata, atom.size);
} else if (atom.size > 8) { /* to read frma, esds atoms */
int ret;
if ((ret = mov_read_default(c, pb, atom)) < 0)
@@ -1151,12 +1326,14 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (type == MKTAG('f','i','e','l') && size == atom.size)
return mov_read_default(c, pb, atom);
}
- av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (st->codec->extradata_size > 1 && st->codec->extradata) {
+ av_log(c, AV_LOG_WARNING, "ignoring multiple glbl\n");
+ return 0;
+ }
+ av_freep(&st->codec->extradata);
+ if (ff_get_extradata(st->codec, pb, atom.size) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size;
- avio_read(pb, st->codec->extradata, atom.size);
+
return 0;
}
@@ -1164,6 +1341,7 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
uint8_t profile_level;
+ int ret;
if (c->fc->nb_streams < 1)
return 0;
@@ -1176,13 +1354,11 @@ static int mov_read_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((profile_level & 0xf0) != 0xc0)
return 0;
- av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size - 7;
avio_seek(pb, 6, SEEK_CUR);
- avio_read(pb, st->codec->extradata, st->codec->extradata_size);
+ av_freep(&st->codec->extradata);
+ if ((ret = ff_get_extradata(st->codec, pb, atom.size - 7)) < 0)
+ return ret;
+
return 0;
}
@@ -1204,13 +1380,10 @@ static int mov_read_strf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if ((uint64_t)atom.size > (1<<30))
return AVERROR_INVALIDDATA;
- av_free(st->codec->extradata);
- st->codec->extradata = av_mallocz(atom.size - 40 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
- return AVERROR(ENOMEM);
- st->codec->extradata_size = atom.size - 40;
avio_skip(pb, 40);
- avio_read(pb, st->codec->extradata, atom.size - 40);
+ av_freep(&st->codec->extradata);
+ if (ff_get_extradata(st->codec, pb, atom.size - 40) < 0)
+ return AVERROR(ENOMEM);
return 0;
}
@@ -1232,10 +1405,12 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!entries)
return 0;
- if (entries >= UINT_MAX/sizeof(int64_t))
- return AVERROR_INVALIDDATA;
- sc->chunk_offsets = av_malloc(entries * sizeof(int64_t));
+ if (sc->chunk_offsets)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated STCO atom\n");
+ av_free(sc->chunk_offsets);
+ sc->chunk_count = 0;
+ sc->chunk_offsets = av_malloc_array(entries, sizeof(*sc->chunk_offsets));
if (!sc->chunk_offsets)
return AVERROR(ENOMEM);
sc->chunk_count = entries;
@@ -1290,7 +1465,9 @@ static int mov_codec_id(AVStream *st, uint32_t format)
id = ff_codec_get_id(ff_codec_bmp_tags, format);
if (id > 0)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) {
+ else if (st->codec->codec_type == AVMEDIA_TYPE_DATA ||
+ (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE &&
+ st->codec->codec_id == AV_CODEC_ID_NONE)) {
id = ff_codec_get_id(ff_codec_movsubtitle_tags, format);
if (id > 0)
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
@@ -1335,8 +1512,11 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
av_dict_set(&st->metadata, "encoder", codec_name, 0);
/* codec_tag YV12 triggers an UV swap in rawdec.c */
- if (!memcmp(codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25))
+ if (!memcmp(codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) {
st->codec->codec_tag = MKTAG('I', '4', '2', '0');
+ st->codec->width &= ~1;
+ st->codec->height &= ~1;
+ }
/* Flash Media Server uses tag H263 with Sorenson Spark */
if (st->codec->codec_tag == MKTAG('H','2','6','3') &&
!memcmp(codec_name, "Sorenson H263", 13))
@@ -1349,12 +1529,15 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
/* figure out the palette situation */
color_depth = st->codec->bits_per_coded_sample & 0x1F;
color_greyscale = st->codec->bits_per_coded_sample & 0x20;
+ /* Do not create a greyscale palette for cinepak */
+ if (color_greyscale && st->codec->codec_id == AV_CODEC_ID_CINEPAK)
+ return;
/* if the depth is 2, 4, or 8 bpp, file is palettized */
if ((color_depth == 2) || (color_depth == 4) || (color_depth == 8)) {
/* for palette traversal */
unsigned int color_start, color_count, color_end;
- unsigned char r, g, b;
+ unsigned char a, r, g, b;
if (color_greyscale) {
int color_index, color_dec;
@@ -1365,7 +1548,7 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
color_dec = 256 / (color_count - 1);
for (j = 0; j < color_count; j++) {
r = g = b = color_index;
- sc->palette[j] = (r << 16) | (g << 8) | (b);
+ sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
color_index -= color_dec;
if (color_index < 0)
color_index = 0;
@@ -1385,7 +1568,7 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
r = color_table[j * 3 + 0];
g = color_table[j * 3 + 1];
b = color_table[j * 3 + 2];
- sc->palette[j] = (r << 16) | (g << 8) | (b);
+ sc->palette[j] = (0xFFU << 24) | (r << 16) | (g << 8) | (b);
}
} else {
/* load the palette from the file */
@@ -1394,10 +1577,9 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
color_end = avio_rb16(pb);
if ((color_start <= 255) && (color_end <= 255)) {
for (j = color_start; j <= color_end; j++) {
- /* each R, G, or B component is 16 bits;
- * only use the top 8 bits; skip alpha bytes
- * up front */
- avio_r8(pb);
+ /* each A, R, G, or B component is 16 bits;
+ * only use the top 8 bits */
+ a = avio_r8(pb);
avio_r8(pb);
r = avio_r8(pb);
avio_r8(pb);
@@ -1405,7 +1587,7 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
avio_r8(pb);
b = avio_r8(pb);
avio_r8(pb);
- sc->palette[j] = (r << 16) | (g << 8) | (b);
+ sc->palette[j] = (a << 24 ) | (r << 16) | (g << 8) | (b);
}
}
}
@@ -1418,6 +1600,7 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
{
int bits_per_sample, flags;
uint16_t version = avio_rb16(pb);
+ AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
avio_rb16(pb); /* revision level */
avio_rb32(pb); /* vendor */
@@ -1433,7 +1616,9 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
// Read QT version 1 fields. In version 0 these do not exist.
av_log(c->fc, AV_LOG_TRACE, "version =%d, isom =%d\n", version, c->isom);
- if (!c->isom) {
+ if (!c->isom ||
+ (compatible_brands && strstr(compatible_brands->value, "qt "))) {
+
if (version == 1) {
sc->samples_per_frame = avio_rb32(pb);
avio_rb32(pb); /* bytes per packet */
@@ -1470,6 +1655,10 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
st->codec->codec_id =
st->codec->codec_id == AV_CODEC_ID_PCM_S16BE ?
AV_CODEC_ID_PCM_S24BE : AV_CODEC_ID_PCM_S24LE;
+ else if (st->codec->bits_per_coded_sample == 32)
+ st->codec->codec_id =
+ st->codec->codec_id == AV_CODEC_ID_PCM_S16BE ?
+ AV_CODEC_ID_PCM_S32BE : AV_CODEC_ID_PCM_S32LE;
break;
/* set values for old format before stsd version 1 appeared */
case AV_CODEC_ID_MACE3:
@@ -1501,7 +1690,7 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb,
static void mov_parse_stsd_subtitle(MOVContext *c, AVIOContext *pb,
AVStream *st, MOVStreamContext *sc,
- int size)
+ int64_t size)
{
// ttxt stsd contains display flags, justification, background
// color, fonts, and default styles, so fake an atom to read it
@@ -1566,14 +1755,48 @@ static int mov_rewrite_dvd_sub_extradata(AVStream *st)
static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb,
AVStream *st, MOVStreamContext *sc,
- int size)
+ int64_t size)
{
if (st->codec->codec_tag == MKTAG('t','m','c','d')) {
- st->codec->extradata_size = size;
- st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if ((int)size != size || ff_get_extradata(st->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- avio_read(pb, st->codec->extradata, size);
+ if (size > 16) {
+ MOVStreamContext *tmcd_ctx = st->priv_data;
+ int val;
+ val = AV_RB32(st->codec->extradata + 4);
+ tmcd_ctx->tmcd_flags = val;
+ if (val & 1)
+ st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
+ st->codec->time_base.den = st->codec->extradata[16]; /* number of frame */
+ st->codec->time_base.num = 1;
+ /* adjust for per frame dur in counter mode */
+ if (tmcd_ctx->tmcd_flags & 0x0008) {
+ int timescale = AV_RB32(st->codec->extradata + 8);
+ int framedur = AV_RB32(st->codec->extradata + 12);
+ st->codec->time_base.den *= timescale;
+ st->codec->time_base.num *= framedur;
+ }
+ if (size > 30) {
+ uint32_t len = AV_RB32(st->codec->extradata + 18); /* name atom length */
+ uint32_t format = AV_RB32(st->codec->extradata + 22);
+ if (format == AV_RB32("name") && (int64_t)size >= (int64_t)len + 18) {
+ uint16_t str_size = AV_RB16(st->codec->extradata + 26); /* string length */
+ if (str_size > 0 && size >= (int)str_size + 26) {
+ char *reel_name = av_malloc(str_size + 1);
+ if (!reel_name)
+ return AVERROR(ENOMEM);
+ memcpy(reel_name, st->codec->extradata + 30, str_size);
+ reel_name[str_size] = 0; /* Add null terminator */
+ /* don't add reel_name if emtpy string */
+ if (*reel_name == 0) {
+ av_free(reel_name);
+ } else {
+ av_dict_set(&st->metadata, "reel_name", reel_name, AV_DICT_DONT_STRDUP_VAL);
+ }
+ }
+ }
+ }
+ }
} else {
/* other codec type, just skip (rtp, mp4s ...) */
avio_skip(pb, size);
@@ -1608,6 +1831,10 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb,
// force sample rate for qcelp when not stored in mov
if (st->codec->codec_tag != MKTAG('Q','c','l','p'))
st->codec->sample_rate = 8000;
+ // FIXME: Why is the following needed for some files?
+ sc->samples_per_frame = 160;
+ if (!sc->bytes_per_frame)
+ sc->bytes_per_frame = 35;
break;
case AV_CODEC_ID_AMR_NB:
st->codec->channels = 1;
@@ -1628,6 +1855,9 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb,
case AV_CODEC_ID_ADPCM_MS:
case AV_CODEC_ID_ADPCM_IMA_WAV:
case AV_CODEC_ID_ILBC:
+ case AV_CODEC_ID_MACE3:
+ case AV_CODEC_ID_MACE6:
+ case AV_CODEC_ID_QDM2:
st->codec->block_align = sc->bytes_per_frame;
break;
case AV_CODEC_ID_ALAC:
@@ -1636,6 +1866,9 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb,
st->codec->sample_rate = AV_RB32(st->codec->extradata + 32);
}
break;
+ case AV_CODEC_ID_AC3:
+ case AV_CODEC_ID_EAC3:
+ case AV_CODEC_ID_MPEG1VIDEO:
case AV_CODEC_ID_VC1:
st->need_parsing = AVSTREAM_PARSE_FULL;
break;
@@ -1647,17 +1880,14 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb,
static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
int codec_tag, int format,
- int size)
+ int64_t size)
{
int video_codec_id = ff_codec_get_id(ff_codec_movvideo_tags, format);
if (codec_tag &&
- (codec_tag == AV_RL32("avc1") ||
- codec_tag == AV_RL32("hvc1") ||
- codec_tag == AV_RL32("hev1") ||
(codec_tag != format &&
(c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id
- : codec_tag != MKTAG('j','p','e','g'))))) {
+ : codec_tag != MKTAG('j','p','e','g')))) {
/* Multiple fourcc, we skip JPEG. This is not correct, we should
* export it as a separate AVStream but this needs a few changes
* in the MOV demuxer, patch welcome. */
@@ -1666,6 +1896,11 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
avio_skip(pb, size);
return 1;
}
+ if ( codec_tag == AV_RL32("avc1") ||
+ codec_tag == AV_RL32("hvc1") ||
+ codec_tag == AV_RL32("hev1")
+ )
+ av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n");
return 0;
}
@@ -1689,15 +1924,15 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
int ret, dref_id = 1;
MOVAtom a = { AV_RL32("stsd") };
int64_t start_pos = avio_tell(pb);
- uint32_t size = avio_rb32(pb); /* size */
+ int64_t size = avio_rb32(pb); /* size */
uint32_t format = avio_rl32(pb); /* data format */
if (size >= 16) {
avio_rb32(pb); /* reserved */
avio_rb16(pb); /* reserved */
dref_id = avio_rb16(pb);
- } else {
- av_log(c->fc, AV_LOG_ERROR, "invalid size %"PRIu32" in stsd\n", size);
+ }else if (size <= 7){
+ av_log(c->fc, AV_LOG_ERROR, "invalid size %"PRId64" in stsd\n", size);
return AVERROR_INVALIDDATA;
}
@@ -1710,7 +1945,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
id = mov_codec_id(st, format);
- av_log(c->fc, AV_LOG_TRACE, "size=%"PRIu32" 4CC= %"PRIu8"%"PRIu8"%"PRIu8"%"PRIu8" codec_type=%d\n", size,
+ av_log(c->fc, AV_LOG_TRACE, "size=%"PRId64" 4CC= %c%c%c%c codec_type=%d\n", size,
(format >> 0) & 0xff, (format >> 8) & 0xff, (format >> 16) & 0xff,
(format >> 24) & 0xff, st->codec->codec_type);
@@ -1776,9 +2011,11 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!entries)
return 0;
- if (entries >= UINT_MAX / sizeof(*sc->stsc_data))
- return AVERROR_INVALIDDATA;
- sc->stsc_data = av_malloc(entries * sizeof(*sc->stsc_data));
+ if (sc->stsc_data)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated STSC atom\n");
+ av_free(sc->stsc_data);
+ sc->stsc_count = 0;
+ sc->stsc_data = av_malloc_array(entries, sizeof(*sc->stsc_data));
if (!sc->stsc_data)
return AVERROR(ENOMEM);
@@ -1810,9 +2047,11 @@ static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb); // version + flags
entries = avio_rb32(pb);
- if (entries >= UINT_MAX / sizeof(*sc->stps_data))
- return AVERROR_INVALIDDATA;
- sc->stps_data = av_malloc(entries * sizeof(*sc->stps_data));
+ if (sc->stps_data)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated STPS atom\n");
+ av_free(sc->stps_data);
+ sc->stps_count = 0;
+ sc->stps_data = av_malloc_array(entries, sizeof(*sc->stps_data));
if (!sc->stps_data)
return AVERROR(ENOMEM);
@@ -1850,12 +2089,17 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!entries)
{
sc->keyframe_absent = 1;
+ if (!st->need_parsing && st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ st->need_parsing = AVSTREAM_PARSE_HEADERS;
return 0;
}
+ if (sc->keyframes)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated STSS atom\n");
if (entries >= UINT_MAX / sizeof(int))
return AVERROR_INVALIDDATA;
av_freep(&sc->keyframes);
- sc->keyframes = av_malloc(entries * sizeof(int));
+ sc->keyframe_count = 0;
+ sc->keyframes = av_malloc_array(entries, sizeof(*sc->keyframes));
if (!sc->keyframes)
return AVERROR(ENOMEM);
@@ -1892,6 +2136,7 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sample_size = avio_rb32(pb);
if (!sc->sample_size) /* do not overwrite value computed in stsd */
sc->sample_size = sample_size;
+ sc->stsz_sample_size = sample_size;
field_size = 32;
} else {
sample_size = 0;
@@ -1913,9 +2158,13 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (!entries)
return 0;
- if (entries >= UINT_MAX / sizeof(int) || entries >= (UINT_MAX - 4) / field_size)
+ if (entries >= (UINT_MAX - 4) / field_size)
return AVERROR_INVALIDDATA;
- sc->sample_sizes = av_malloc(entries * sizeof(int));
+ if (sc->sample_sizes)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated STSZ atom\n");
+ av_free(sc->sample_sizes);
+ sc->sample_count = 0;
+ sc->sample_sizes = av_malloc_array(entries, sizeof(*sc->sample_sizes));
if (!sc->sample_sizes)
return AVERROR(ENOMEM);
@@ -1942,10 +2191,11 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->sample_count = i;
+ av_free(buf);
+
if (pb->eof_reached)
return AVERROR_EOF;
- av_free(buf);
return 0;
}
@@ -1969,13 +2219,11 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_log(c->fc, AV_LOG_TRACE, "track[%i].stts.entries = %i\n",
c->fc->nb_streams-1, entries);
- if (!entries)
- return 0;
- if (entries >= UINT_MAX / sizeof(*sc->stts_data))
- return AVERROR(EINVAL);
-
+ if (sc->stts_data)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated STTS atom\n");
av_free(sc->stts_data);
- sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data));
+ sc->stts_count = 0;
+ sc->stts_data = av_malloc_array(entries, sizeof(*sc->stts_data));
if (!sc->stts_data)
return AVERROR(ENOMEM);
@@ -1985,6 +2233,13 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sample_count=avio_rb32(pb);
sample_duration = avio_rb32(pb);
+
+ /* sample_duration < 0 is invalid based on the spec */
+ if (sample_duration < 0) {
+ av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta %d in STTS, at %d st:%d\n",
+ sample_duration, i, c->fc->nb_streams-1);
+ sample_duration = 1;
+ }
if (sample_count < 0) {
av_log(c->fc, AV_LOG_ERROR, "Invalid sample_count=%d\n", sample_count);
return AVERROR_INVALIDDATA;
@@ -1995,12 +2250,21 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_log(c->fc, AV_LOG_TRACE, "sample_count=%d, sample_duration=%d\n",
sample_count, sample_duration);
+ if ( i+1 == entries
+ && i
+ && sample_count == 1
+ && total_sample_count > 100
+ && sample_duration/10 > duration / total_sample_count)
+ sample_duration = duration / total_sample_count;
duration+=(int64_t)sample_duration*sample_count;
total_sample_count+=sample_count;
}
sc->stts_count = i;
+ sc->duration_for_fps += duration;
+ sc->nb_frames_for_fps += total_sample_count;
+
if (pb->eof_reached)
return AVERROR_EOF;
@@ -2011,6 +2275,13 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static void mov_update_dts_shift(MOVStreamContext *sc, int duration)
+{
+ if (duration < 0) {
+ sc->dts_shift = FFMAX(sc->dts_shift, -duration);
+ }
+}
+
static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
@@ -2032,6 +2303,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
if (entries >= UINT_MAX / sizeof(*sc->ctts_data))
return AVERROR_INVALIDDATA;
+ av_freep(&sc->ctts_data);
sc->ctts_data = av_malloc(entries * sizeof(*sc->ctts_data));
if (!sc->ctts_data)
return AVERROR(ENOMEM);
@@ -2042,8 +2314,19 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->ctts_data[i].count = count;
sc->ctts_data[i].duration= duration;
- if (duration < 0)
- sc->dts_shift = FFMAX(sc->dts_shift, -duration);
+
+ av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n",
+ count, duration);
+
+ if (FFABS(duration) > (1<<28) && i+2<entries) {
+ av_log(c->fc, AV_LOG_WARNING, "CTTS invalid\n");
+ av_freep(&sc->ctts_data);
+ sc->ctts_count = 0;
+ return 0;
+ }
+
+ if (i+2<entries)
+ mov_update_dts_shift(sc, duration);
}
sc->ctts_count = i;
@@ -2080,9 +2363,11 @@ static int mov_read_sbgp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
entries = avio_rb32(pb);
if (!entries)
return 0;
- if (entries >= UINT_MAX / sizeof(*sc->rap_group))
- return AVERROR_INVALIDDATA;
- sc->rap_group = av_malloc(entries * sizeof(*sc->rap_group));
+ if (sc->rap_group)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated SBGP atom\n");
+ av_free(sc->rap_group);
+ sc->rap_group_count = 0;
+ sc->rap_group = av_malloc_array(entries, sizeof(*sc->rap_group));
if (!sc->rap_group)
return AVERROR(ENOMEM);
@@ -2108,17 +2393,40 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
unsigned int i, j;
uint64_t stream_size = 0;
- /* adjust first dts according to edit list */
- if (sc->time_offset && mov->time_scale > 0) {
- if (sc->time_offset < 0)
- sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale);
- current_dts = -sc->time_offset;
- if (sc->ctts_data && sc->stts_data && sc->stts_data[0].duration &&
- sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) {
- /* more than 16 frames delay, dts are likely wrong
- this happens with files created by iMovie */
- sc->wrong_dts = 1;
- st->codec->has_b_frames = 1;
+ if (sc->elst_count) {
+ int i, edit_start_index = 0, unsupported = 0;
+ int64_t empty_duration = 0; // empty duration of the first edit list entry
+ int64_t start_time = 0; // start time of the media
+
+ for (i = 0; i < sc->elst_count; i++) {
+ const MOVElst *e = &sc->elst_data[i];
+ if (i == 0 && e->time == -1) {
+ /* if empty, the first entry is the start time of the stream
+ * relative to the presentation itself */
+ empty_duration = e->duration;
+ edit_start_index = 1;
+ } else if (i == edit_start_index && e->time >= 0) {
+ start_time = e->time;
+ } else
+ unsupported = 1;
+ }
+ if (unsupported)
+ av_log(mov->fc, AV_LOG_WARNING, "multiple edit list entries, "
+ "a/v desync might occur, patch welcome\n");
+
+ /* adjust first dts according to edit list */
+ if ((empty_duration || start_time) && mov->time_scale > 0) {
+ if (empty_duration)
+ empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale);
+ sc->time_offset = start_time - empty_duration;
+ current_dts = -sc->time_offset;
+ if (sc->ctts_count>0 && sc->stts_count>0 &&
+ sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
+ /* more than 16 frames delay, dts are likely wrong
+ this happens with files created by iMovie */
+ sc->wrong_dts = 1;
+ st->codec->has_b_frames = 1;
+ }
}
}
@@ -2132,11 +2440,11 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
unsigned int rap_group_index = 0;
unsigned int rap_group_sample = 0;
int rap_group_present = sc->rap_group_count && sc->rap_group;
- int key_off = (sc->keyframes && sc->keyframes[0] > 0) || (sc->stps_data && sc->stps_data[0] > 0);
+ int key_off = (sc->keyframe_count && sc->keyframes[0] > 0) || (sc->stps_count && sc->stps_data[0] > 0);
current_dts -= sc->dts_shift;
- if (!sc->sample_count)
+ if (!sc->sample_count || st->nb_index_entries)
return;
if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
return;
@@ -2149,10 +2457,22 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries);
for (i = 0; i < sc->chunk_count; i++) {
+ int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX;
current_offset = sc->chunk_offsets[i];
while (stsc_index + 1 < sc->stsc_count &&
i + 1 == sc->stsc_data[stsc_index + 1].first)
stsc_index++;
+
+ if (next_offset > current_offset && sc->sample_size>0 && sc->sample_size < sc->stsz_sample_size &&
+ sc->stsc_data[stsc_index].count * (int64_t)sc->stsz_sample_size > next_offset - current_offset) {
+ av_log(mov->fc, AV_LOG_WARNING, "STSZ sample size %d invalid (too large), ignoring\n", sc->stsz_sample_size);
+ sc->stsz_sample_size = sc->sample_size;
+ }
+ if (sc->stsz_sample_size>0 && sc->stsz_sample_size < sc->sample_size) {
+ av_log(mov->fc, AV_LOG_WARNING, "STSZ sample size %d invalid (too small), ignoring\n", sc->stsz_sample_size);
+ sc->stsz_sample_size = sc->sample_size;
+ }
+
for (j = 0; j < sc->stsc_data[stsc_index].count; j++) {
int keyframe = 0;
if (current_sample >= sc->sample_count) {
@@ -2177,9 +2497,14 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
rap_group_index++;
}
}
+ if (sc->keyframe_absent
+ && !sc->stps_count
+ && !rap_group_present
+ && (st->codec->codec_type == AVMEDIA_TYPE_AUDIO || (i==0 && j==0)))
+ keyframe = 1;
if (keyframe)
distance = 0;
- sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample];
+ sample_size = sc->stsz_sample_size > 0 ? sc->stsz_sample_size : sc->sample_sizes[current_sample];
if (sc->pseudo_stream_id == -1 ||
sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) {
AVIndexEntry *e = &st->index_entries[st->nb_index_entries++];
@@ -2191,6 +2516,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
av_log(mov->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
"size %d, distance %d, keyframe %d\n", st->index, current_sample,
current_offset, current_dts, sample_size, distance, keyframe);
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->nb_index_entries < 100)
+ ff_rfps_add_frame(mov->fc, st, current_dts);
}
current_offset += sample_size;
@@ -2296,14 +2623,19 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
}
}
-static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
+static int mov_open_dref(MOVContext *c, AVIOContext **pb, const char *src, MOVDref *ref,
AVIOInterruptCB *int_cb)
{
+ AVOpenCallback open_func = c->fc->open_cb;
+
+ if (!open_func)
+ open_func = ffio_open2_wrapper;
+
/* try relative path, we do not try the absolute because it can leak information about our
system to an attacker */
if (ref->nlvl_to > 0 && ref->nlvl_from > 0 && ref->path[0] != '/') {
- char filename[1024];
- char *src_path;
+ char filename[1025];
+ const char *src_path;
int i, l;
/* find a source dir */
@@ -2328,18 +2660,46 @@ static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
filename[src_path - src] = 0;
for (i = 1; i < ref->nlvl_from; i++)
- av_strlcat(filename, "../", 1024);
+ av_strlcat(filename, "../", sizeof(filename));
- av_strlcat(filename, ref->path + l + 1, 1024);
+ av_strlcat(filename, ref->path + l + 1, sizeof(filename));
+ if (!c->use_absolute_path && !c->fc->open_cb)
+ if(strstr(ref->path + l + 1, "..") || ref->nlvl_from > 1)
+ return AVERROR(ENOENT);
- if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL))
+ if (strlen(filename) + 1 == sizeof(filename))
+ return AVERROR(ENOENT);
+ if (!open_func(c->fc, pb, filename, AVIO_FLAG_READ, int_cb, NULL))
return 0;
}
+ } else if (c->use_absolute_path) {
+ av_log(c->fc, AV_LOG_WARNING, "Using absolute path on user request, "
+ "this is a possible security issue\n");
+ if (!open_func(c->fc, pb, ref->path, AVIO_FLAG_READ, int_cb, NULL))
+ return 0;
+ } else if (c->fc->open_cb) {
+ if (!open_func(c->fc, pb, ref->path, AVIO_FLAG_READ, int_cb, NULL))
+ return 0;
+ } else {
+ av_log(c->fc, AV_LOG_ERROR,
+ "Absolute path %s not tried for security reasons, "
+ "set demuxer option use_absolute_path to allow absolute paths\n",
+ ref->path);
}
return AVERROR(ENOENT);
}
+static void fix_timescale(MOVContext *c, MOVStreamContext *sc)
+{
+ if (sc->time_scale <= 0) {
+ av_log(c->fc, AV_LOG_WARNING, "stream %d, timescale not set\n", sc->ffindex);
+ sc->time_scale = c->time_scale;
+ if (sc->time_scale <= 0)
+ sc->time_scale = 1;
+ }
+}
+
static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
@@ -2367,12 +2727,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
- if (sc->time_scale <= 0) {
- av_log(c->fc, AV_LOG_WARNING, "stream %d, timescale not set\n", st->index);
- sc->time_scale = c->time_scale;
- if (sc->time_scale <= 0)
- sc->time_scale = 1;
- }
+ fix_timescale(c, sc);
avpriv_set_pts_info(st, 64, 1, sc->time_scale);
@@ -2380,21 +2735,31 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) {
MOVDref *dref = &sc->drefs[sc->dref_id - 1];
- if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback) < 0)
+ if (mov_open_dref(c, &sc->pb, c->fc->filename, dref,
+ &c->fc->interrupt_callback) < 0)
av_log(c->fc, AV_LOG_ERROR,
"stream %d, error opening alias: path='%s', dir='%s', "
"filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n",
st->index, dref->path, dref->dir, dref->filename,
dref->volume, dref->nlvl_from, dref->nlvl_to);
- } else
+ } else {
sc->pb = c->fc->pb;
+ sc->pb_is_copied = 1;
+ }
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (!st->sample_aspect_ratio.num &&
+ if (!st->sample_aspect_ratio.num && st->codec->width && st->codec->height &&
+ sc->height && sc->width &&
(st->codec->width != sc->width || st->codec->height != sc->height)) {
st->sample_aspect_ratio = av_d2q(((double)st->codec->height * sc->width) /
((double)st->codec->width * sc->height), INT_MAX);
}
+
+#if FF_API_R_FRAME_RATE
+ if (sc->stts_count == 1 || (sc->stts_count == 2 && sc->stts_data[1].count == 1))
+ av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den,
+ sc->time_scale, sc->stts_data[0].duration, INT_MAX);
+#endif
}
// done for ai5q, ai52, ai55, ai1q, ai12 and ai15.
@@ -2427,6 +2792,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_freep(&sc->keyframes);
av_freep(&sc->stts_data);
av_freep(&sc->stps_data);
+ av_freep(&sc->elst_data);
av_freep(&sc->rap_group);
return 0;
@@ -2441,11 +2807,18 @@ static int mov_read_ilst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return ret;
}
-static int mov_read_replaygain(MOVContext *c, AVIOContext *pb, int size)
+static int mov_read_custom_2plus(MOVContext *c, AVIOContext *pb, int size)
{
int64_t end = avio_tell(pb) + size;
uint8_t *key = NULL, *val = NULL;
int i;
+ 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;
for (i = 0; i < 2; i++) {
uint8_t **p;
@@ -2474,14 +2847,26 @@ static int mov_read_replaygain(MOVContext *c, AVIOContext *pb, int size)
*p = av_malloc(len + 1);
if (!*p)
break;
- avio_read(pb, *p, len);
+ if (avio_read(pb, *p, len) != len) {
+ av_freep(p);
+ return AVERROR_INVALIDDATA;
+ }
(*p)[len] = 0;
}
if (key && val) {
- av_dict_set(&c->fc->metadata, key, val,
- AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
- key = val = NULL;
+ if (strcmp(key, "iTunSMPB") == 0) {
+ int priming, remainder, samples;
+ if(sscanf(val, "%*X %X %X %X", &priming, &remainder, &samples) == 3){
+ if(priming>0 && priming<16384)
+ sc->start_pad = priming;
+ }
+ }
+ if (strcmp(key, "cdec") != 0) {
+ av_dict_set(&c->fc->metadata, key, val,
+ AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+ key = val = NULL;
+ }
}
avio_seek(pb, end, SEEK_SET);
@@ -2513,8 +2898,7 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom)
domain_len = avio_get_str(pb, len, domain, sizeof(domain));
avio_skip(pb, len - domain_len);
- if (!strcmp(domain, "org.hydrogenaudio.replaygain"))
- return mov_read_replaygain(c, pb, end - avio_tell(pb));
+ return mov_read_custom_2plus(c, pb, end - avio_tell(pb));
}
fail:
@@ -2542,7 +2926,6 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
int i;
int width;
int height;
- int64_t disp_transform[2];
int display_matrix[3][3];
AVStream *st;
MOVStreamContext *sc;
@@ -2593,7 +2976,8 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->width = width >> 16;
sc->height = height >> 16;
- // save the matrix when it is not the default identity
+ // save the matrix and add rotate metadata when it is not the default
+ // identity
if (display_matrix[0][0] != (1 << 16) ||
display_matrix[1][1] != (1 << 16) ||
display_matrix[2][2] != (1 << 30) ||
@@ -2601,6 +2985,7 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
display_matrix[1][0] || display_matrix[1][2] ||
display_matrix[2][0] || display_matrix[2][1]) {
int i, j;
+ double rotate;
av_freep(&sc->display_matrix);
sc->display_matrix = av_malloc(sizeof(int32_t) * 9);
@@ -2610,23 +2995,33 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
sc->display_matrix[i * 3 + j] = display_matrix[i][j];
+
+ rotate = av_display_rotation_get(sc->display_matrix);
+ if (!isnan(rotate)) {
+ char rotate_buf[64];
+ rotate = -rotate;
+ if (rotate < 0) // for backward compatibility
+ rotate += 360;
+ snprintf(rotate_buf, sizeof(rotate_buf), "%g", rotate);
+ av_dict_set(&st->metadata, "rotate", rotate_buf, 0);
+ }
}
// transform the display width/height according to the matrix
- // skip this when the display matrix is the identity one
// to keep the same scale, use [width height 1<<16]
if (width && height && sc->display_matrix) {
+ double disp_transform[2];
+
+#define SQR(a) ((a)*(double)(a))
for (i = 0; i < 2; i++)
- disp_transform[i] =
- (int64_t) width * display_matrix[0][i] +
- (int64_t) height * display_matrix[1][i] +
- ((int64_t) display_matrix[2][i] << 16);
+ disp_transform[i] = sqrt(SQR(display_matrix[i][0]) + SQR(display_matrix[i][1]));
- //sample aspect ratio is new width/height divided by old width/height
- if (disp_transform[0] > 0 && disp_transform[1] > 0)
+ if (disp_transform[0] > 0 && disp_transform[1] > 0 &&
+ disp_transform[0] < (1<<24) && disp_transform[1] < (1<<24) &&
+ fabs((disp_transform[0] / disp_transform[1]) - 1.0) > 0.01)
st->sample_aspect_ratio = av_d2q(
- ((double) disp_transform[0] * height) /
- ((double) disp_transform[1] * width), INT_MAX);
+ disp_transform[0] / disp_transform[1],
+ INT_MAX);
}
return 0;
}
@@ -2635,6 +3030,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
MOVFragment *frag = &c->fragment;
MOVTrackExt *trex = NULL;
+ MOVFragmentIndex* index = NULL;
int flags, track_id, i;
avio_r8(pb); /* version */
@@ -2653,6 +3049,15 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_log(c->fc, AV_LOG_ERROR, "could not find corresponding trex\n");
return AVERROR_INVALIDDATA;
}
+ for (i = 0; i < c->fragment_index_count; i++) {
+ MOVFragmentIndex* candidate = c->fragment_index_data[i];
+ if (candidate->track_id == frag->track_id) {
+ av_log(c->fc, AV_LOG_DEBUG,
+ "found fragment index for track %u\n", frag->track_id);
+ index = candidate;
+ break;
+ }
+ }
frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ?
avio_rb64(pb) : flags & MOV_TFHD_DEFAULT_BASE_IS_MOOF ?
@@ -2665,6 +3070,25 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb) : trex->size;
frag->flags = flags & MOV_TFHD_DEFAULT_FLAGS ?
avio_rb32(pb) : trex->flags;
+ frag->time = AV_NOPTS_VALUE;
+ if (index) {
+ int i, found = 0;
+ for (i = index->current_item; i < index->item_count; i++) {
+ if (frag->implicit_offset == index->items[i].moof_offset) {
+ av_log(c->fc, AV_LOG_DEBUG, "found fragment index entry "
+ "for track %u and moof_offset %"PRId64"\n",
+ frag->track_id, index->items[i].moof_offset);
+ frag->time = index->items[i].time;
+ index->current_item = i + 1;
+ found = 1;
+ }
+ }
+ if (!found) {
+ av_log(c->fc, AV_LOG_WARNING, "track %u has a fragment index "
+ "but it doesn't have an (in-order) entry for moof_offset "
+ "%"PRId64"\n", frag->track_id, frag->implicit_offset);
+ }
+ }
av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags);
return 0;
}
@@ -2687,6 +3111,9 @@ static int mov_read_trex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
c->trex_count = 0;
return err;
}
+
+ c->fc->duration = AV_NOPTS_VALUE; // the duration from mvhd is not representing the whole file when fragments are used.
+
trex = &c->trex_data[c->trex_count++];
avio_r8(pb); /* version */
avio_rb24(pb); /* flags */
@@ -2751,7 +3178,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR_INVALIDDATA;
}
sc = st->priv_data;
- if (sc->pseudo_stream_id+1 != frag->stsd_id)
+ if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1)
return 0;
avio_r8(pb); /* version */
flags = avio_rb24(pb);
@@ -2799,6 +3226,29 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->ctts_data[sc->ctts_count].count = 1;
sc->ctts_data[sc->ctts_count].duration = (flags & MOV_TRUN_SAMPLE_CTS) ?
avio_rb32(pb) : 0;
+ mov_update_dts_shift(sc, sc->ctts_data[sc->ctts_count].duration);
+ if (frag->time != AV_NOPTS_VALUE) {
+ if (c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) {
+ int64_t pts = frag->time;
+ av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64
+ " sc->dts_shift %d ctts.duration %d"
+ " sc->time_offset %"PRId64" flags & MOV_TRUN_SAMPLE_CTS %d\n", pts,
+ sc->dts_shift, sc->ctts_data[sc->ctts_count].duration,
+ sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS);
+ dts = pts - sc->dts_shift;
+ if (flags & MOV_TRUN_SAMPLE_CTS) {
+ dts -= sc->ctts_data[sc->ctts_count].duration;
+ } else {
+ dts -= sc->time_offset;
+ }
+ av_log(c->fc, AV_LOG_DEBUG, "calculated into dts %"PRId64"\n", dts);
+ } else {
+ dts = frag->time;
+ av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64
+ ", using it for dts\n", dts);
+ }
+ frag->time = AV_NOPTS_VALUE;
+ }
sc->ctts_count++;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
keyframe = 1;
@@ -2808,8 +3258,11 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES));
if (keyframe)
distance = 0;
- av_add_index_entry(st, offset, dts, sample_size, distance,
- keyframe ? AVINDEX_KEYFRAME : 0);
+ err = av_add_index_entry(st, offset, dts, sample_size, distance,
+ keyframe ? AVINDEX_KEYFRAME : 0);
+ if (err < 0) {
+ av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n");
+ }
av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
"size %d, distance %d, keyframe %d\n", st->index, sc->sample_count+i,
offset, dts, sample_size, distance, keyframe);
@@ -2817,6 +3270,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
dts += sample_duration;
offset += sample_size;
sc->data_size += sample_size;
+ sc->duration_for_fps += sample_duration;
+ sc->nb_frames_for_fps ++;
}
if (pb->eof_reached)
@@ -2863,7 +3318,7 @@ static int mov_read_cmov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (avio_rl32(pb) != MKTAG('d','c','o','m'))
return AVERROR_INVALIDDATA;
if (avio_rl32(pb) != MKTAG('z','l','i','b')) {
- av_log(c->fc, AV_LOG_ERROR, "unknown compression for cmov atom !");
+ av_log(c->fc, AV_LOG_ERROR, "unknown compression for cmov atom !\n");
return AVERROR_INVALIDDATA;
}
avio_rb32(pb); /* cmvd atom */
@@ -2880,11 +3335,16 @@ static int mov_read_cmov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_free(cmov_data);
return AVERROR(ENOMEM);
}
- avio_read(pb, cmov_data, cmov_len);
+ if (avio_read(pb, cmov_data, cmov_len) != cmov_len) {
+ av_freep(&cmov_data);
+ av_freep(&moov_data);
+ return AVERROR_INVALIDDATA;
+ }
if (uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK)
goto free_and_return;
if (ffio_init_context(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL) != 0)
goto free_and_return;
+ ctx.seekable = AVIO_SEEKABLE_NORMAL;
atom.type = MKTAG('m','o','o','v');
atom.size = moov_len;
ret = mov_read_default(c, &ctx, atom);
@@ -2904,7 +3364,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
MOVStreamContext *sc;
int i, edit_count, version;
- if (c->fc->nb_streams < 1)
+ if (c->fc->nb_streams < 1 || c->ignore_editlist)
return 0;
sc = c->fc->streams[c->fc->nb_streams-1]->priv_data;
@@ -2912,40 +3372,147 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb24(pb); /* flags */
edit_count = avio_rb32(pb); /* entries */
- if ((uint64_t)edit_count*12+8 > atom.size)
- return AVERROR_INVALIDDATA;
+ if (!edit_count)
+ return 0;
+ if (sc->elst_data)
+ av_log(c->fc, AV_LOG_WARNING, "Duplicated ELST atom\n");
+ av_free(sc->elst_data);
+ sc->elst_count = 0;
+ sc->elst_data = av_malloc_array(edit_count, sizeof(*sc->elst_data));
+ if (!sc->elst_data)
+ return AVERROR(ENOMEM);
+
+ av_log(c->fc, AV_LOG_TRACE, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count);
+ for (i = 0; i < edit_count && !pb->eof_reached; i++) {
+ MOVElst *e = &sc->elst_data[i];
- for (i=0; i<edit_count; i++){
- int64_t time;
- int64_t duration;
if (version == 1) {
- duration = avio_rb64(pb);
- time = avio_rb64(pb);
+ e->duration = avio_rb64(pb);
+ e->time = avio_rb64(pb);
} else {
- duration = avio_rb32(pb); /* segment duration */
- time = (int32_t)avio_rb32(pb); /* media time */
+ e->duration = avio_rb32(pb); /* segment duration */
+ e->time = (int32_t)avio_rb32(pb); /* media time */
+ }
+ e->rate = avio_rb32(pb) / 65536.0;
+ av_log(c->fc, AV_LOG_TRACE, "duration=%"PRId64" time=%"PRId64" rate=%f\n",
+ e->duration, e->time, e->rate);
+ }
+ sc->elst_count = i;
+
+ return 0;
+}
+
+static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ MOVStreamContext *sc;
+
+ if (c->fc->nb_streams < 1)
+ return AVERROR_INVALIDDATA;
+ sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data;
+ sc->timecode_track = avio_rb32(pb);
+ return 0;
+}
+
+static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret;
+ uint8_t uuid[16];
+ static const uint8_t uuid_isml_manifest[] = {
+ 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
+ 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
+ };
+
+ if (atom.size < sizeof(uuid) || atom.size == INT64_MAX)
+ return AVERROR_INVALIDDATA;
+
+ ret = avio_read(pb, uuid, sizeof(uuid));
+ if (ret < 0) {
+ return ret;
+ } else if (ret != sizeof(uuid)) {
+ return AVERROR_INVALIDDATA;
+ }
+ if (!memcmp(uuid, uuid_isml_manifest, sizeof(uuid))) {
+ uint8_t *buffer, *ptr;
+ char *endptr;
+ size_t len = atom.size - sizeof(uuid);
+
+ if (len < 4) {
+ return AVERROR_INVALIDDATA;
+ }
+ ret = avio_skip(pb, 4); // zeroes
+ len -= 4;
+
+ buffer = av_mallocz(len + 1);
+ if (!buffer) {
+ return AVERROR(ENOMEM);
+ }
+ ret = avio_read(pb, buffer, len);
+ if (ret < 0) {
+ av_free(buffer);
+ return ret;
+ } else if (ret != len) {
+ av_free(buffer);
+ return AVERROR_INVALIDDATA;
}
- avio_rb32(pb); /* Media rate */
- if (i == 0 && time >= -1) {
- sc->time_offset = time != -1 ? time : -duration;
+
+ ptr = buffer;
+ while ((ptr = av_stristr(ptr, "systemBitrate=\""))) {
+ ptr += sizeof("systemBitrate=\"") - 1;
+ c->bitrates_count++;
+ c->bitrates = av_realloc_f(c->bitrates, c->bitrates_count, sizeof(*c->bitrates));
+ if (!c->bitrates) {
+ c->bitrates_count = 0;
+ av_free(buffer);
+ return AVERROR(ENOMEM);
+ }
+ errno = 0;
+ ret = strtol(ptr, &endptr, 10);
+ if (ret < 0 || errno || *endptr != '"') {
+ c->bitrates[c->bitrates_count - 1] = 0;
+ } else {
+ c->bitrates[c->bitrates_count - 1] = ret;
+ }
}
+
+ av_free(buffer);
}
+ return 0;
+}
- if (edit_count > 1)
- av_log(c->fc, AV_LOG_WARNING, "multiple edit list entries, "
- "a/v desync might occur, patch welcome\n");
+static int mov_read_free(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int ret;
+ uint8_t content[16];
+
+ if (atom.size < 8)
+ return 0;
+
+ ret = avio_read(pb, content, FFMIN(sizeof(content), atom.size));
+ if (ret < 0)
+ return ret;
+
+ if ( !c->found_moov
+ && !c->found_mdat
+ && !memcmp(content, "Anevia\x1A\x1A", 8)
+ && c->use_mfra_for == FF_MOV_FLAG_MFRA_AUTO) {
+ c->use_mfra_for = FF_MOV_FLAG_MFRA_PTS;
+ }
- av_log(c->fc, AV_LOG_TRACE, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count);
return 0;
}
static const MOVParseTableEntry mov_default_parse_table[] = {
-{ MKTAG('a','v','s','s'), mov_read_extradata },
+{ MKTAG('A','C','L','R'), mov_read_aclr },
+{ MKTAG('A','P','R','G'), mov_read_avid },
+{ MKTAG('A','A','L','P'), mov_read_avid },
+{ MKTAG('A','R','E','S'), mov_read_ares },
+{ MKTAG('a','v','s','s'), mov_read_avss },
{ MKTAG('c','h','p','l'), mov_read_chpl },
{ MKTAG('c','o','6','4'), mov_read_stco },
{ MKTAG('c','o','l','r'), mov_read_colr },
{ MKTAG('c','t','t','s'), mov_read_ctts }, /* composition time to sample */
{ MKTAG('d','i','n','f'), mov_read_default },
+{ MKTAG('D','p','x','E'), mov_read_dpxe },
{ MKTAG('d','r','e','f'), mov_read_dref },
{ MKTAG('e','d','t','s'), mov_read_default },
{ MKTAG('e','l','s','t'), mov_read_elst },
@@ -2955,7 +3522,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('g','l','b','l'), mov_read_glbl },
{ MKTAG('h','d','l','r'), mov_read_hdlr },
{ MKTAG('i','l','s','t'), mov_read_ilst },
-{ MKTAG('j','p','2','h'), mov_read_extradata },
+{ MKTAG('j','p','2','h'), mov_read_jp2h },
{ MKTAG('m','d','a','t'), mov_read_mdat },
{ MKTAG('m','d','h','d'), mov_read_mdhd },
{ MKTAG('m','d','i','a'), mov_read_default },
@@ -2965,8 +3532,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('m','o','o','v'), mov_read_moov },
{ MKTAG('m','v','e','x'), mov_read_default },
{ MKTAG('m','v','h','d'), mov_read_mvhd },
-{ MKTAG('S','M','I',' '), mov_read_smi }, /* Sorenson extension ??? */
-{ MKTAG('a','l','a','c'), mov_read_extradata }, /* alac specific atom */
+{ MKTAG('S','M','I',' '), mov_read_svq3 },
+{ 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('s','t','b','l'), mov_read_default },
@@ -2985,6 +3552,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('t','r','a','k'), mov_read_trak },
{ MKTAG('t','r','a','f'), mov_read_default },
{ MKTAG('t','r','e','f'), mov_read_default },
+{ MKTAG('t','m','c','d'), mov_read_tmcd },
{ MKTAG('c','h','a','p'), mov_read_chap },
{ MKTAG('t','r','e','x'), mov_read_trex },
{ MKTAG('t','r','u','n'), mov_read_trun },
@@ -3000,6 +3568,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('d','v','c','1'), mov_read_dvc1 },
{ MKTAG('s','b','g','p'), mov_read_sbgp },
{ MKTAG('h','v','c','C'), mov_read_glbl },
+{ MKTAG('u','u','i','d'), mov_read_uuid },
+{ MKTAG('C','i','n', 0x8e), mov_read_targa_y216 },
+{ MKTAG('f','r','e','e'), mov_read_free },
{ MKTAG('-','-','-','-'), mov_read_custom },
{ 0, NULL }
};
@@ -3010,27 +3581,56 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
MOVAtom a;
int i;
+ if (c->atom_depth > 10) {
+ av_log(c->fc, AV_LOG_ERROR, "Atoms too deeply nested\n");
+ return AVERROR_INVALIDDATA;
+ }
+ c->atom_depth ++;
+
if (atom.size < 0)
atom.size = INT64_MAX;
- while (total_size + 8 < atom.size && !pb->eof_reached) {
+ while (total_size + 8 <= atom.size && !avio_feof(pb)) {
int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL;
a.size = atom.size;
a.type=0;
if (atom.size >= 8) {
a.size = avio_rb32(pb);
a.type = avio_rl32(pb);
+ if (a.type == MKTAG('f','r','e','e') &&
+ a.size >= 8 &&
+ c->moov_retry) {
+ uint8_t buf[8];
+ uint32_t *type = (uint32_t *)buf + 1;
+ if (avio_read(pb, buf, 8) != 8)
+ return AVERROR_INVALIDDATA;
+ avio_seek(pb, -8, SEEK_CUR);
+ if (*type == MKTAG('m','v','h','d') ||
+ *type == MKTAG('c','m','o','v')) {
+ av_log(c->fc, AV_LOG_ERROR, "Detected moov in a free atom.\n");
+ a.type = MKTAG('m','o','o','v');
+ }
+ }
+ if (atom.type != MKTAG('r','o','o','t') &&
+ atom.type != MKTAG('m','o','o','v'))
+ {
+ if (a.type == MKTAG('t','r','a','k') || a.type == MKTAG('m','d','a','t'))
+ {
+ av_log(c->fc, AV_LOG_ERROR, "Broken file, trak/mdat not at top-level\n");
+ avio_skip(pb, -8);
+ c->atom_depth --;
+ return 0;
+ }
+ }
+ total_size += 8;
+ if (a.size == 1 && total_size + 8 <= atom.size) { /* 64 bit extended size */
+ a.size = avio_rb64(pb) - 8;
+ total_size += 8;
+ }
}
av_log(c->fc, AV_LOG_TRACE, "type: %08x '%.4s' parent:'%.4s' sz: %"PRId64" %"PRId64" %"PRId64"\n",
a.type, (char*)&a.type, (char*)&atom.type, a.size, total_size, atom.size);
- total_size += 8;
- if (a.size == 1) { /* 64 bit extended size */
- a.size = avio_rb64(pb) - 8;
- total_size += 8;
- }
if (a.size == 0) {
- a.size = atom.size - total_size;
- if (a.size <= 8)
- break;
+ a.size = atom.size - total_size + 8;
}
a.size -= 8;
if (a.size < 0)
@@ -3054,13 +3654,16 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
int64_t start_pos = avio_tell(pb);
int64_t left;
int err = parse(c, pb, a);
- if (err < 0)
+ if (err < 0) {
+ c->atom_depth --;
return err;
+ }
if (c->found_moov && c->found_mdat &&
((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX) ||
start_pos + a.size == avio_size(pb))) {
if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX)
c->next_root_atom = start_pos + a.size;
+ c->atom_depth --;
return 0;
}
left = a.size - avio_tell(pb) + start_pos;
@@ -3080,51 +3683,91 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (total_size < atom.size && atom.size < 0x7ffff)
avio_skip(pb, atom.size - total_size);
+ c->atom_depth --;
return 0;
}
static int mov_probe(AVProbeData *p)
{
- unsigned int offset;
+ int64_t offset;
uint32_t tag;
int score = 0;
+ int moov_offset = -1;
/* check file header */
offset = 0;
for (;;) {
/* ignore invalid offset */
if ((offset + 8) > (unsigned int)p->buf_size)
- return score;
+ break;
tag = AV_RL32(p->buf + offset + 4);
switch(tag) {
/* check for obvious tags */
- case MKTAG('j','P',' ',' '): /* jpeg 2000 signature */
case MKTAG('m','o','o','v'):
+ moov_offset = offset + 4;
case MKTAG('m','d','a','t'):
case MKTAG('p','n','o','t'): /* detect movs with preview pics like ew.mov and april.mov */
case MKTAG('u','d','t','a'): /* Packet Video PVAuthor adds this and a lot of more junk */
case MKTAG('f','t','y','p'):
- return AVPROBE_SCORE_MAX;
+ if (AV_RB32(p->buf+offset) < 8 &&
+ (AV_RB32(p->buf+offset) != 1 ||
+ offset + 12 > (unsigned int)p->buf_size ||
+ AV_RB64(p->buf+offset + 8) == 0)) {
+ score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
+ } else if (tag == MKTAG('f','t','y','p') &&
+ ( AV_RL32(p->buf + offset + 8) == MKTAG('j','p','2',' ')
+ || AV_RL32(p->buf + offset + 8) == MKTAG('j','p','x',' ')
+ )) {
+ score = FFMAX(score, 5);
+ } else {
+ score = AVPROBE_SCORE_MAX;
+ }
+ offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
+ break;
/* those are more common words, so rate then a bit less */
case MKTAG('e','d','i','w'): /* xdcam files have reverted first tags */
case MKTAG('w','i','d','e'):
case MKTAG('f','r','e','e'):
case MKTAG('j','u','n','k'):
case MKTAG('p','i','c','t'):
- return AVPROBE_SCORE_MAX - 5;
+ score = FFMAX(score, AVPROBE_SCORE_MAX - 5);
+ offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
+ break;
case MKTAG(0x82,0x82,0x7f,0x7d):
case MKTAG('s','k','i','p'):
case MKTAG('u','u','i','d'):
case MKTAG('p','r','f','l'):
- offset = AV_RB32(p->buf+offset) + offset;
/* if we only find those cause probedata is too small at least rate them */
- score = AVPROBE_SCORE_EXTENSION;
+ score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
+ offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
break;
default:
- /* unrecognized tag */
- return score;
+ offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
}
}
+ if(score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) {
+ /* moov atom in the header - we should make sure that this is not a
+ * MOV-packed MPEG-PS */
+ offset = moov_offset;
+
+ while(offset < (p->buf_size - 16)){ /* Sufficient space */
+ /* We found an actual hdlr atom */
+ if(AV_RL32(p->buf + offset ) == MKTAG('h','d','l','r') &&
+ AV_RL32(p->buf + offset + 8) == MKTAG('m','h','l','r') &&
+ AV_RL32(p->buf + offset + 12) == MKTAG('M','P','E','G')){
+ av_log(NULL, AV_LOG_WARNING, "Found media data tag MPEG indicating this is a MOV-packed MPEG-PS.\n");
+ /* We found a media handler reference atom describing an
+ * MPEG-PS-in-MOV, return a
+ * low score to force expanding the probe window until
+ * mpegps_probe finds what it needs */
+ return 5;
+ }else
+ /* Keep looking */
+ offset+=2;
+ }
+ }
+
+ return score;
}
// must be done after parsing all trak because there's no order requirement
@@ -3157,6 +3800,11 @@ static void mov_read_chapters(AVFormatContext *s)
uint16_t ch;
int len, title_len;
+ if (end < sample->timestamp) {
+ av_log(s, AV_LOG_WARNING, "ignoring stream duration which is shorter than chapters\n");
+ end = AV_NOPTS_VALUE;
+ }
+
if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) {
av_log(s, AV_LOG_ERROR, "Chapter %d not found in file\n", i);
goto finish;
@@ -3186,7 +3834,7 @@ static void mov_read_chapters(AVFormatContext *s)
if (len == 1 || len == 2)
title[len] = 0;
else
- avio_get_str(sc->pb, len - 2, title + 2, title_len - 2);
+ avio_get_str(sc->pb, INT_MAX, title + 2, len - 1);
}
}
@@ -3197,6 +3845,49 @@ finish:
avio_seek(sc->pb, cur_pos, SEEK_SET);
}
+static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st,
+ uint32_t value, int flags)
+{
+ AVTimecode tc;
+ char buf[AV_TIMECODE_STR_SIZE];
+ AVRational rate = {st->codec->time_base.den,
+ st->codec->time_base.num};
+ int ret = av_timecode_init(&tc, rate, flags, 0, s);
+ if (ret < 0)
+ return ret;
+ av_dict_set(&st->metadata, "timecode",
+ av_timecode_make_string(&tc, buf, value), 0);
+ return 0;
+}
+
+static int mov_read_timecode_track(AVFormatContext *s, AVStream *st)
+{
+ MOVStreamContext *sc = st->priv_data;
+ int flags = 0;
+ int64_t cur_pos = avio_tell(sc->pb);
+ uint32_t value;
+
+ if (!st->nb_index_entries)
+ return -1;
+
+ avio_seek(sc->pb, st->index_entries->pos, SEEK_SET);
+ value = avio_rb32(s->pb);
+
+ if (sc->tmcd_flags & 0x0001) flags |= AV_TIMECODE_FLAG_DROPFRAME;
+ if (sc->tmcd_flags & 0x0002) flags |= AV_TIMECODE_FLAG_24HOURSMAX;
+ if (sc->tmcd_flags & 0x0004) flags |= AV_TIMECODE_FLAG_ALLOWNEGATIVE;
+
+ /* Assume Counter flag is set to 1 in tmcd track (even though it is likely
+ * not the case) and thus assume "frame number format" instead of QT one.
+ * No sample with tmcd track can be found with a QT timecode at the moment,
+ * despite what the tmcd track "suggests" (Counter flag set to 0 means QT
+ * format). */
+ parse_timecode_in_framenum_format(s, st, value, flags);
+
+ avio_seek(sc->pb, cur_pos, SEEK_SET);
+ return 0;
+}
+
static int mov_read_close(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
@@ -3212,15 +3903,20 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->drefs[j].dir);
}
av_freep(&sc->drefs);
- if (sc->pb && sc->pb != s->pb)
- avio_close(sc->pb);
+ sc->drefs_count = 0;
+
+ if (!sc->pb_is_copied)
+ avio_closep(&sc->pb);
+
+ sc->pb = NULL;
av_freep(&sc->chunk_offsets);
av_freep(&sc->stsc_data);
av_freep(&sc->sample_sizes);
av_freep(&sc->keyframes);
av_freep(&sc->stts_data);
av_freep(&sc->stps_data);
+ av_freep(&sc->elst_data);
av_freep(&sc->rap_group);
av_freep(&sc->display_matrix);
}
@@ -3231,15 +3927,163 @@ static int mov_read_close(AVFormatContext *s)
}
av_freep(&mov->trex_data);
+ av_freep(&mov->bitrates);
+ for (i = 0; i < mov->fragment_index_count; i++) {
+ MOVFragmentIndex* index = mov->fragment_index_data[i];
+ av_freep(&index->items);
+ av_freep(&mov->fragment_index_data[i]);
+ }
+ av_freep(&mov->fragment_index_data);
+
+ return 0;
+}
+
+static int tmcd_is_referenced(AVFormatContext *s, int tmcd_id)
+{
+ int i;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ MOVStreamContext *sc = st->priv_data;
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ sc->timecode_track == tmcd_id)
+ return 1;
+ }
return 0;
}
+/* look for a tmcd track not referenced by any video track, and export it globally */
+static void export_orphan_timecode(AVFormatContext *s)
+{
+ int i;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+
+ if (st->codec->codec_tag == MKTAG('t','m','c','d') &&
+ !tmcd_is_referenced(s, i + 1)) {
+ AVDictionaryEntry *tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
+ if (tcr) {
+ av_dict_set(&s->metadata, "timecode", tcr->value, 0);
+ break;
+ }
+ }
+ }
+}
+
+static int read_tfra(MOVContext *mov, AVIOContext *f)
+{
+ MOVFragmentIndex* index = NULL;
+ int version, fieldlength, i, j;
+ int64_t pos = avio_tell(f);
+ uint32_t size = avio_rb32(f);
+ void *tmp;
+
+ if (avio_rb32(f) != MKBETAG('t', 'f', 'r', 'a')) {
+ return 1;
+ }
+ av_log(mov->fc, AV_LOG_VERBOSE, "found tfra\n");
+ index = av_mallocz(sizeof(MOVFragmentIndex));
+ if (!index) {
+ return AVERROR(ENOMEM);
+ }
+
+ tmp = av_realloc_array(mov->fragment_index_data,
+ mov->fragment_index_count + 1,
+ sizeof(MOVFragmentIndex*));
+ if (!tmp) {
+ av_freep(&index);
+ return AVERROR(ENOMEM);
+ }
+ mov->fragment_index_data = tmp;
+ mov->fragment_index_data[mov->fragment_index_count++] = index;
+
+ version = avio_r8(f);
+ avio_rb24(f);
+ index->track_id = avio_rb32(f);
+ fieldlength = avio_rb32(f);
+ index->item_count = avio_rb32(f);
+ index->items = av_mallocz_array(
+ index->item_count, sizeof(MOVFragmentIndexItem));
+ if (!index->items) {
+ index->item_count = 0;
+ return AVERROR(ENOMEM);
+ }
+ for (i = 0; i < index->item_count; i++) {
+ int64_t time, offset;
+ if (version == 1) {
+ time = avio_rb64(f);
+ offset = avio_rb64(f);
+ } else {
+ time = avio_rb32(f);
+ offset = avio_rb32(f);
+ }
+ index->items[i].time = time;
+ index->items[i].moof_offset = offset;
+ for (j = 0; j < ((fieldlength >> 4) & 3) + 1; j++)
+ avio_r8(f);
+ for (j = 0; j < ((fieldlength >> 2) & 3) + 1; j++)
+ avio_r8(f);
+ for (j = 0; j < ((fieldlength >> 0) & 3) + 1; j++)
+ avio_r8(f);
+ }
+
+ avio_seek(f, pos + size, SEEK_SET);
+ return 0;
+}
+
+static int mov_read_mfra(MOVContext *c, AVIOContext *f)
+{
+ int64_t stream_size = avio_size(f);
+ int64_t original_pos = avio_tell(f);
+ int64_t seek_ret;
+ int32_t mfra_size;
+ int ret = -1;
+ if ((seek_ret = avio_seek(f, stream_size - 4, SEEK_SET)) < 0) {
+ ret = seek_ret;
+ goto fail;
+ }
+ mfra_size = avio_rb32(f);
+ if (mfra_size < 0 || mfra_size > stream_size) {
+ av_log(c->fc, AV_LOG_DEBUG, "doesn't look like mfra (unreasonable size)\n");
+ goto fail;
+ }
+ if ((seek_ret = avio_seek(f, -mfra_size, SEEK_CUR)) < 0) {
+ ret = seek_ret;
+ goto fail;
+ }
+ if (avio_rb32(f) != mfra_size) {
+ av_log(c->fc, AV_LOG_DEBUG, "doesn't look like mfra (size mismatch)\n");
+ goto fail;
+ }
+ if (avio_rb32(f) != MKBETAG('m', 'f', 'r', 'a')) {
+ av_log(c->fc, AV_LOG_DEBUG, "doesn't look like mfra (tag mismatch)\n");
+ goto fail;
+ }
+ av_log(c->fc, AV_LOG_VERBOSE, "stream has mfra\n");
+ do {
+ ret = read_tfra(c, f);
+ if (ret < 0)
+ goto fail;
+ } while (!ret);
+ ret = 0;
+fail:
+ seek_ret = avio_seek(f, original_pos, SEEK_SET);
+ if (seek_ret < 0) {
+ av_log(c->fc, AV_LOG_ERROR,
+ "failed to seek back after looking for mfra\n");
+ ret = seek_ret;
+ }
+ return ret;
+}
+
static int mov_read_header(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
AVIOContext *pb = s->pb;
- int err;
+ int j, err;
MOVAtom atom = { AV_RL32("root") };
int i;
@@ -3251,11 +4095,15 @@ static int mov_read_header(AVFormatContext *s)
atom.size = INT64_MAX;
/* check MOV header */
+ do {
+ if (mov->moov_retry)
+ avio_seek(pb, 0, SEEK_SET);
if ((err = mov_read_default(mov, pb, atom)) < 0) {
- av_log(s, AV_LOG_ERROR, "error reading header: %d\n", err);
+ av_log(s, AV_LOG_ERROR, "error reading header\n");
mov_read_close(s);
return err;
}
+ } while (pb->seekable && !mov->found_moov && !mov->moov_retry++);
if (!mov->found_moov) {
av_log(s, AV_LOG_ERROR, "moov atom not found\n");
mov_read_close(s);
@@ -3263,13 +4111,45 @@ static int mov_read_header(AVFormatContext *s)
}
av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb));
- if (pb->seekable && mov->chapter_track > 0)
- mov_read_chapters(s);
+ if (pb->seekable) {
+ if (mov->chapter_track > 0)
+ mov_read_chapters(s);
+ for (i = 0; i < s->nb_streams; i++)
+ if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd"))
+ mov_read_timecode_track(s, s->streams[i]);
+ }
+ /* copy timecode metadata from tmcd tracks to the related video streams */
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
MOVStreamContext *sc = st->priv_data;
+ if (sc->timecode_track > 0) {
+ AVDictionaryEntry *tcr;
+ int tmcd_st_id = -1;
+ for (j = 0; j < s->nb_streams; j++)
+ if (s->streams[j]->id == sc->timecode_track)
+ tmcd_st_id = j;
+
+ if (tmcd_st_id < 0 || tmcd_st_id == i)
+ continue;
+ tcr = av_dict_get(s->streams[tmcd_st_id]->metadata, "timecode", NULL, 0);
+ if (tcr)
+ av_dict_set(&st->metadata, "timecode", tcr->value, 0);
+ }
+ }
+ export_orphan_timecode(s);
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ MOVStreamContext *sc = st->priv_data;
+ fix_timescale(mov, sc);
+ if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->codec->codec_id == AV_CODEC_ID_AAC) {
+ st->skip_samples = sc->start_pad;
+ }
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && sc->nb_frames_for_fps > 0 && sc->duration_for_fps > 0)
+ av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
+ sc->time_scale*(int64_t)sc->nb_frames_for_fps, sc->duration_for_fps, INT_MAX);
if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (st->codec->width <= 0 || st->codec->height <= 0) {
st->codec->width = sc->width;
@@ -3291,6 +4171,25 @@ static int mov_read_header(AVFormatContext *s)
}
}
+ if (mov->use_mfra_for > 0) {
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ MOVStreamContext *sc = st->priv_data;
+ if (sc->duration_for_fps > 0) {
+ st->codec->bit_rate = sc->data_size * 8 * sc->time_scale /
+ sc->duration_for_fps;
+ }
+ }
+ }
+
+ for (i = 0; i < mov->bitrates_count && i < s->nb_streams; i++) {
+ if (mov->bitrates[i]) {
+ s->streams[i]->codec->bit_rate = mov->bitrates[i];
+ }
+ }
+
+ ff_rfps_calculate(s);
+
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
MOVStreamContext *sc = st->priv_data;
@@ -3361,16 +4260,20 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
AVIndexEntry *sample;
AVStream *st = NULL;
int ret;
+ mov->fc = s;
retry:
sample = mov_find_next_sample(s, &st);
if (!sample) {
mov->found_mdat = 0;
if (!mov->next_root_atom)
return AVERROR_EOF;
- avio_seek(s->pb, mov->next_root_atom, SEEK_SET);
+ if (avio_seek(s->pb, mov->next_root_atom, SEEK_SET) != mov->next_root_atom) {
+ av_log(mov->fc, AV_LOG_ERROR, "next root atom offset 0x%"PRIx64": partial file\n", mov->next_root_atom);
+ return AVERROR_INVALIDDATA;
+ }
mov->next_root_atom = 0;
if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 ||
- s->pb->eof_reached)
+ avio_feof(s->pb))
return AVERROR_EOF;
av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
goto retry;
@@ -3379,6 +4282,11 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
/* must be done just before reading, to avoid infinite loop on sample */
sc->current_sample++;
+ if (mov->next_root_atom) {
+ sample->pos = FFMIN(sample->pos, mov->next_root_atom);
+ sample->size = FFMIN(sample->size, (mov->next_root_atom - sample->pos));
+ }
+
if (st->discard != AVDISCARD_ALL) {
if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) {
av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n",
@@ -3401,8 +4309,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
}
#if CONFIG_DV_DEMUXER
if (mov->dv_demux && sc->dv_audio_container) {
- avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size);
- av_free(pkt->data);
+ avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos);
+ av_freep(&pkt->data);
pkt->size = 0;
ret = avpriv_dv_get_packet(mov->dv_demux, pkt);
if (ret < 0)
@@ -3434,8 +4342,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
goto retry;
pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
pkt->pos = sample->pos;
- av_log(s, AV_LOG_TRACE, "stream %d, pts %"PRId64", dts %"PRId64", pos 0x%"PRIx64", duration %d\n",
- pkt->stream_index, pkt->pts, pkt->dts, pkt->pos, pkt->duration);
+
return 0;
}
@@ -3478,8 +4385,6 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
if (stream_index >= s->nb_streams)
return AVERROR_INVALIDDATA;
- if (sample_time < 0)
- sample_time = 0;
st = s->streams[stream_index];
sample = mov_seek_stream(s, st, sample_time, flags);
@@ -3492,7 +4397,10 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
for (i = 0; i < s->nb_streams; i++) {
int64_t timestamp;
+ MOVStreamContext *sc = s->streams[i]->priv_data;
st = s->streams[i];
+ st->skip_samples = (sample_time <= 0) ? sc->start_pad : 0;
+
if (stream_index == i)
continue;
@@ -3523,10 +4431,27 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
#define OFFSET(x) offsetof(MOVContext, x)
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption mov_options[] = {
+ {"use_absolute_path",
+ "allow using absolute path when opening alias, this is a possible security issue",
+ OFFSET(use_absolute_path), FF_OPT_TYPE_INT, {.i64 = 0},
+ 0, 1, FLAGS},
{"seek_streams_individually",
"Seek each stream individually to the to the closest point",
OFFSET(seek_individually), AV_OPT_TYPE_INT, { .i64 = 1 },
0, 1, FLAGS},
+ {"ignore_editlist", "", OFFSET(ignore_editlist), FF_OPT_TYPE_INT, {.i64 = 0},
+ 0, 1, FLAGS},
+ {"use_mfra_for",
+ "use mfra for fragment timestamps",
+ OFFSET(use_mfra_for), FF_OPT_TYPE_INT, {.i64 = FF_MOV_FLAG_MFRA_AUTO},
+ -1, FF_MOV_FLAG_MFRA_PTS, FLAGS,
+ "use_mfra_for"},
+ {"auto", "auto", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_AUTO}, 0, 0,
+ FLAGS, "use_mfra_for" },
+ {"dts", "dts", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_DTS}, 0, 0,
+ FLAGS, "use_mfra_for" },
+ {"pts", "pts", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_MFRA_PTS}, 0, 0,
+ FLAGS, "use_mfra_for" },
{ "export_all", "Export unrecognized metadata entries", OFFSET(export_all),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = FLAGS },
{ "export_xmp", "Export full XMP metadata", OFFSET(export_xmp),
@@ -3552,4 +4477,5 @@ AVInputFormat ff_mov_demuxer = {
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
+ .flags = AVFMT_NO_BYTE_SEEK,
};
diff --git a/libavformat/mov_chan.c b/libavformat/mov_chan.c
index 2c54920427..a2fa8d641c 100644
--- a/libavformat/mov_chan.c
+++ b/libavformat/mov_chan.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -344,7 +344,7 @@ static const struct MovChannelLayoutMap mov_ch_layout_map_9ch[] = {
{ 0, 0 },
};
-static const struct MovChannelLayoutMap *mov_ch_layout_map[] = {
+static const struct MovChannelLayoutMap * const mov_ch_layout_map[] = {
mov_ch_layout_map_misc,
mov_ch_layout_map_1ch,
mov_ch_layout_map_2ch,
@@ -426,6 +426,7 @@ static const enum MovChannelLayoutTag mov_ch_layouts_wav[] = {
MOV_CH_LAYOUT_MPEG_7_1_A,
MOV_CH_LAYOUT_MPEG_7_1_C,
MOV_CH_LAYOUT_SMPTE_DTV,
+ 0,
};
static const struct {
@@ -565,11 +566,17 @@ int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
label_mask = 0;
for (i = 0; i < num_descr; i++) {
uint32_t label;
+ if (pb->eof_reached) {
+ av_log(s, AV_LOG_ERROR,
+ "reached EOF while reading channel layout\n");
+ return AVERROR_INVALIDDATA;
+ }
label = avio_rb32(pb); // mChannelLabel
avio_rb32(pb); // mChannelFlags
avio_rl32(pb); // mCoordinates[0]
avio_rl32(pb); // mCoordinates[1]
avio_rl32(pb); // mCoordinates[2]
+ size -= 20;
if (layout_tag == 0) {
uint32_t mask_incr = mov_get_channel_label(label);
if (mask_incr == 0) {
@@ -584,6 +591,7 @@ int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
st->codec->channel_layout = label_mask;
} else
st->codec->channel_layout = ff_mov_get_channel_layout(layout_tag, bitmap);
+ avio_skip(pb, size - 12);
return 0;
}
diff --git a/libavformat/mov_chan.h b/libavformat/mov_chan.h
index 3fae93961e..ca28345aef 100644
--- a/libavformat/mov_chan.h
+++ b/libavformat/mov_chan.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Justin Ruggles
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 30d397a349..dc9570b50c 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,25 +31,29 @@
#include "avio.h"
#include "isom.h"
#include "avc.h"
+#include "libavcodec/ac3_parser.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/put_bits.h"
#include "libavcodec/vc1_common.h"
+#include "libavcodec/raw.h"
#include "internal.h"
#include "libavutil/avstring.h"
#include "libavutil/intfloat.h"
#include "libavutil/mathematics.h"
+#include "libavutil/libm.h"
#include "libavutil/opt.h"
#include "libavutil/dict.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/timecode.h"
+#include "libavutil/color_utils.h"
#include "hevc.h"
#include "rtpenc.h"
#include "mov_chan.h"
-#undef NDEBUG
-#include <assert.h>
-
static const AVOption options[] = {
{ "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+ { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 },
{ "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
@@ -62,17 +66,21 @@ static const AVOption options[] = {
{ "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
{ "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+ { "write_colr", "Write colr atom (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, "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, "movflags" },
FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
- { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+ { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
{ "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
{ "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "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},
{ "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
+ { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
{ "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, 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},
{ "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
{ NULL },
};
@@ -85,6 +93,8 @@ static const AVClass flavor ## _muxer_class = {\
.version = LIBAVUTIL_VERSION_INT,\
};
+static int get_moov_size(AVFormatContext *s);
+
static int utf8len(const uint8_t *b)
{
int len = 0;
@@ -121,13 +131,15 @@ static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
int mode64 = co64_required(track); // use 32 bit size variant if possible
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
- if (mode64) {
+ if (mode64)
ffio_wfourcc(pb, "co64");
- } else
+ else
ffio_wfourcc(pb, "stco");
avio_wb32(pb, 0); /* version & flags */
- avio_wb32(pb, track->entry); /* entry count */
+ avio_wb32(pb, track->chunkCount); /* entry count */
for (i = 0; i < track->entry; i++) {
+ if (!track->cluster[i].chunkNum)
+ continue;
if (mode64 == 1)
avio_wb64(pb, track->cluster[i].pos + track->data_offset);
else
@@ -183,10 +195,10 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "stsc");
avio_wb32(pb, 0); // version & flags
entryPos = avio_tell(pb);
- avio_wb32(pb, track->entry); // entry count
+ avio_wb32(pb, track->chunkCount); // entry count
for (i = 0; i < track->entry; i++) {
- if (oldval != track->cluster[i].samples_in_chunk) {
- avio_wb32(pb, i + 1); // first chunk
+ if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
+ avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
avio_wb32(pb, 0x1); // sample description index
oldval = track->cluster[i].samples_in_chunk;
@@ -283,6 +295,214 @@ static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track)
return 11;
}
+struct eac3_info {
+ AVPacket pkt;
+ uint8_t ec3_done;
+ uint8_t num_blocks;
+
+ /* Layout of the EC3SpecificBox */
+ /* maximum bitrate */
+ uint16_t data_rate;
+ /* number of independent substreams */
+ uint8_t num_ind_sub;
+ struct {
+ /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
+ uint8_t fscod;
+ /* bit stream identification 5 bits */
+ uint8_t bsid;
+ /* one bit reserved */
+ /* audio service mixing (not supported yet) 1 bit */
+ /* bit stream mode 3 bits */
+ uint8_t bsmod;
+ /* audio coding mode 3 bits */
+ uint8_t acmod;
+ /* sub woofer on 1 bit */
+ uint8_t lfeon;
+ /* 3 bits reserved */
+ /* number of dependent substreams associated with this substream 4 bits */
+ uint8_t num_dep_sub;
+ /* channel locations of the dependent substream(s), if any, 9 bits */
+ uint16_t chan_loc;
+ /* if there is no dependent substream, then one bit reserved instead */
+ } substream[1]; /* TODO: support 8 independent substreams */
+};
+
+#if CONFIG_AC3_PARSER
+static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
+{
+ GetBitContext gbc;
+ AC3HeaderInfo tmp, *hdr = &tmp;
+ struct eac3_info *info;
+ int num_blocks;
+
+ if (!track->eac3_priv && !(track->eac3_priv = av_mallocz(sizeof(*info))))
+ return AVERROR(ENOMEM);
+ info = track->eac3_priv;
+
+ init_get_bits(&gbc, pkt->data, pkt->size * 8);
+ if (avpriv_ac3_parse_header2(&gbc, &hdr) < 0) {
+ /* drop the packets until we see a good one */
+ if (!track->entry) {
+ av_log(mov, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
+ return 0;
+ }
+ return AVERROR_INVALIDDATA;
+ }
+
+ info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
+ num_blocks = hdr->num_blocks;
+
+ if (!info->ec3_done) {
+ /* AC-3 substream must be the first one */
+ if (hdr->bitstream_id <= 10 && hdr->substreamid != 0)
+ return AVERROR(EINVAL);
+
+ /* this should always be the case, given that our AC-3 parser
+ * concatenates dependent frames to their independent parent */
+ if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) {
+ /* substream ids must be incremental */
+ if (hdr->substreamid > info->num_ind_sub + 1)
+ return AVERROR(EINVAL);
+
+ if (hdr->substreamid == info->num_ind_sub + 1) {
+ //info->num_ind_sub++;
+ avpriv_request_sample(track->enc, "Multiple independent substreams");
+ return AVERROR_PATCHWELCOME;
+ } else if (hdr->substreamid < info->num_ind_sub ||
+ hdr->substreamid == 0 && info->substream[0].bsid) {
+ info->ec3_done = 1;
+ goto concatenate;
+ }
+ }
+
+ /* fill the info needed for the "dec3" atom */
+ info->substream[hdr->substreamid].fscod = hdr->sr_code;
+ info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
+ info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
+ info->substream[hdr->substreamid].acmod = hdr->channel_mode;
+ info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
+
+ /* Parse dependent substream(s), if any */
+ if (pkt->size != hdr->frame_size) {
+ int cumul_size = hdr->frame_size;
+ int parent = hdr->substreamid;
+
+ while (cumul_size != pkt->size) {
+ int i;
+ init_get_bits(&gbc, pkt->data + cumul_size, (pkt->size - cumul_size) * 8);
+ if (avpriv_ac3_parse_header2(&gbc, &hdr) < 0)
+ return AVERROR_INVALIDDATA;
+ if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT)
+ return AVERROR(EINVAL);
+ cumul_size += hdr->frame_size;
+ info->substream[parent].num_dep_sub++;
+
+ /* header is parsed up to lfeon, but custom channel map may be needed */
+ /* skip bsid */
+ skip_bits(&gbc, 5);
+ /* skip volume control params */
+ for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
+ skip_bits(&gbc, 5); // skip dialog normalization
+ if (get_bits1(&gbc)) {
+ skip_bits(&gbc, 8); // skip compression gain word
+ }
+ }
+ /* get the dependent stream channel map, if exists */
+ if (get_bits1(&gbc))
+ info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
+ else
+ info->substream[parent].chan_loc |= hdr->channel_mode;
+ }
+ }
+ }
+
+concatenate:
+ if (!info->num_blocks && num_blocks == 6)
+ return pkt->size;
+ else if (info->num_blocks + num_blocks > 6)
+ return AVERROR_INVALIDDATA;
+
+ if (!info->num_blocks) {
+ int ret;
+ if ((ret = av_copy_packet(&info->pkt, pkt)) < 0)
+ return ret;
+ info->num_blocks = num_blocks;
+ return 0;
+ } else {
+ int ret;
+ if ((ret = av_grow_packet(&info->pkt, pkt->size)) < 0)
+ return ret;
+ memcpy(info->pkt.data + info->pkt.size - pkt->size, pkt->data, pkt->size);
+ info->num_blocks += num_blocks;
+ info->pkt.duration += pkt->duration;
+ if ((ret = av_copy_packet_side_data(&info->pkt, pkt)) < 0)
+ return ret;
+ if (info->num_blocks != 6)
+ return 0;
+ av_free_packet(pkt);
+ if ((ret = av_copy_packet(pkt, &info->pkt)) < 0)
+ return ret;
+ av_free_packet(&info->pkt);
+ info->num_blocks = 0;
+ }
+
+ return pkt->size;
+}
+#endif
+
+static int mov_write_eac3_tag(AVIOContext *pb, MOVTrack *track)
+{
+ PutBitContext pbc;
+ uint8_t *buf;
+ struct eac3_info *info;
+ int size, i;
+
+ if (!track->eac3_priv)
+ return AVERROR(EINVAL);
+
+ info = track->eac3_priv;
+ size = 2 + 4 * (info->num_ind_sub + 1);
+ buf = av_malloc(size);
+ if (!buf) {
+ size = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ init_put_bits(&pbc, buf, size);
+ put_bits(&pbc, 13, info->data_rate);
+ put_bits(&pbc, 3, info->num_ind_sub);
+ for (i = 0; i <= info->num_ind_sub; i++) {
+ put_bits(&pbc, 2, info->substream[i].fscod);
+ put_bits(&pbc, 5, info->substream[i].bsid);
+ put_bits(&pbc, 1, 0); /* reserved */
+ put_bits(&pbc, 1, 0); /* asvc */
+ put_bits(&pbc, 3, info->substream[i].bsmod);
+ put_bits(&pbc, 3, info->substream[i].acmod);
+ put_bits(&pbc, 1, info->substream[i].lfeon);
+ put_bits(&pbc, 5, 0); /* reserved */
+ put_bits(&pbc, 4, info->substream[i].num_dep_sub);
+ if (!info->substream[i].num_dep_sub) {
+ put_bits(&pbc, 1, 0); /* reserved */
+ size--;
+ } else {
+ put_bits(&pbc, 9, info->substream[i].chan_loc);
+ }
+ }
+ flush_put_bits(&pbc);
+
+ avio_wb32(pb, size + 8);
+ ffio_wfourcc(pb, "dec3");
+ avio_write(pb, buf, size);
+
+ av_free(buf);
+
+end:
+ av_free_packet(&info->pkt);
+ av_freep(&track->eac3_priv);
+
+ return size;
+}
+
/**
* This function writes extradata "as is".
* Extradata must be formatted like a valid atom (with size and tag).
@@ -293,6 +513,22 @@ static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
return track->enc->extradata_size;
}
+static int mov_write_enda_tag(AVIOContext *pb)
+{
+ avio_wb32(pb, 10);
+ ffio_wfourcc(pb, "enda");
+ avio_wb16(pb, 1); /* little endian */
+ return 10;
+}
+
+static int mov_write_enda_tag_be(AVIOContext *pb)
+{
+ avio_wb32(pb, 10);
+ ffio_wfourcc(pb, "enda");
+ avio_wb16(pb, 0); /* big endian */
+ return 10;
+}
+
static void put_descr(AVIOContext *pb, int tag, unsigned int size)
{
int i = 3;
@@ -302,10 +538,22 @@ static void put_descr(AVIOContext *pb, int tag, unsigned int size)
avio_w8(pb, size & 0x7F);
}
+static unsigned compute_avg_bitrate(MOVTrack *track)
+{
+ uint64_t size = 0;
+ int i;
+ if (!track->track_duration)
+ return 0;
+ for (i = 0; i < track->entry; i++)
+ size += track->cluster[i].size;
+ return size * 8 * track->timescale / track->track_duration;
+}
+
static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
{
int64_t pos = avio_tell(pb);
int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0;
+ unsigned avg_bitrate;
avio_wb32(pb, 0); // size
ffio_wfourcc(pb, "esds");
@@ -338,12 +586,10 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
avio_wb24(pb, track->enc->rc_buffer_size >> 3); // Buffersize DB
- avio_wb32(pb, FFMAX(track->enc->bit_rate, track->enc->rc_max_rate)); // maxbitrate (FIXME should be max rate in any 1 sec window)
- if (track->enc->rc_max_rate != track->enc->rc_min_rate ||
- track->enc->rc_min_rate == 0)
- avio_wb32(pb, 0); // vbr
- else
- avio_wb32(pb, track->enc->rc_max_rate); // avg bitrate
+ avg_bitrate = compute_avg_bitrate(track);
+ // maxbitrate (FIXME should be max rate in any 1 sec window)
+ avio_wb32(pb, FFMAX3(track->enc->bit_rate, track->enc->rc_max_rate, avg_bitrate));
+ avio_wb32(pb, avg_bitrate);
if (track->vos_len) {
// DecoderSpecific info descriptor
@@ -357,22 +603,42 @@ static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
return update_size(pb, pos);
}
+static int mov_pcm_le_gt16(enum AVCodecID codec_id)
+{
+ return codec_id == AV_CODEC_ID_PCM_S24LE ||
+ codec_id == AV_CODEC_ID_PCM_S32LE ||
+ codec_id == AV_CODEC_ID_PCM_F32LE ||
+ codec_id == AV_CODEC_ID_PCM_F64LE;
+}
+
+static int mov_pcm_be_gt16(enum AVCodecID codec_id)
+{
+ return codec_id == AV_CODEC_ID_PCM_S24BE ||
+ codec_id == AV_CODEC_ID_PCM_S32BE ||
+ codec_id == AV_CODEC_ID_PCM_F32BE ||
+ codec_id == AV_CODEC_ID_PCM_F64BE;
+}
+
static int mov_write_ms_tag(AVIOContext *pb, MOVTrack *track)
{
+ int ret;
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0);
avio_wl32(pb, track->tag); // store it byteswapped
track->enc->codec_tag = av_bswap16(track->tag >> 16);
- ff_put_wav_header(pb, track->enc);
+ if ((ret = ff_put_wav_header(pb, track->enc, 0)) < 0)
+ return ret;
return update_size(pb, pos);
}
static int mov_write_wfex_tag(AVIOContext *pb, MOVTrack *track)
{
+ int ret;
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0);
ffio_wfourcc(pb, "wfex");
- ff_put_wav_header(pb, track->enc);
+ if ((ret = ff_put_wav_header(pb, track->enc, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
+ return ret;
return update_size(pb, pos);
}
@@ -390,6 +656,9 @@ static int mov_write_chan_tag(AVIOContext *pb, MOVTrack *track)
return 0;
}
+ if (track->multichannel_as_mono)
+ return 0;
+
avio_wb32(pb, 0); // Size
ffio_wfourcc(pb, "chan"); // Type
avio_w8(pb, 0); // Version
@@ -408,9 +677,11 @@ static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "wave");
+ if (track->enc->codec_id != AV_CODEC_ID_QDM2) {
avio_wb32(pb, 12); /* size */
ffio_wfourcc(pb, "frma");
avio_wl32(pb, track->tag);
+ }
if (track->enc->codec_id == AV_CODEC_ID_AAC) {
/* useless atom needed by mplayer, ipod, not needed by quicktime */
@@ -418,11 +689,18 @@ static int mov_write_wave_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "mp4a");
avio_wb32(pb, 0);
mov_write_esds_tag(pb, track);
+ } else if (mov_pcm_le_gt16(track->enc->codec_id)) {
+ mov_write_enda_tag(pb);
+ } else if (mov_pcm_be_gt16(track->enc->codec_id)) {
+ mov_write_enda_tag_be(pb);
} else if (track->enc->codec_id == AV_CODEC_ID_AMR_NB) {
mov_write_amr_tag(pb, track);
} else if (track->enc->codec_id == AV_CODEC_ID_AC3) {
mov_write_ac3_tag(pb, track);
- } else if (track->enc->codec_id == AV_CODEC_ID_ALAC) {
+ } else if (track->enc->codec_id == AV_CODEC_ID_EAC3) {
+ mov_write_eac3_tag(pb, track);
+ } else if (track->enc->codec_id == AV_CODEC_ID_ALAC ||
+ track->enc->codec_id == AV_CODEC_ID_QDM2) {
mov_write_extradata_tag(pb, track);
} else if (track->enc->codec_id == AV_CODEC_ID_ADPCM_MS ||
track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
@@ -583,13 +861,20 @@ static int get_cluster_duration(MOVTrack *track, int cluster_idx)
else
next_dts = track->cluster[cluster_idx + 1].dts;
- return next_dts - track->cluster[cluster_idx].dts;
+ next_dts -= track->cluster[cluster_idx].dts;
+
+ av_assert0(next_dts >= 0);
+ av_assert0(next_dts <= INT_MAX);
+
+ return next_dts;
}
static int get_samples_per_packet(MOVTrack *track)
{
int i, first_duration;
+// return track->enc->frame_size;
+
/* use 1 for raw PCM */
if (!track->audio_vbr)
return 1;
@@ -612,9 +897,17 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
uint32_t tag = track->tag;
if (track->mode == MODE_MOV) {
- if (mov_get_lpcm_flags(track->enc->codec_id))
- tag = AV_RL32("lpcm");
- version = 2;
+ if (track->timescale > UINT16_MAX) {
+ if (mov_get_lpcm_flags(track->enc->codec_id))
+ tag = AV_RL32("lpcm");
+ version = 2;
+ } else if (track->audio_vbr || mov_pcm_le_gt16(track->enc->codec_id) ||
+ mov_pcm_be_gt16(track->enc->codec_id) ||
+ track->enc->codec_id == AV_CODEC_ID_ADPCM_MS ||
+ track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
+ track->enc->codec_id == AV_CODEC_ID_QDM2) {
+ version = 1;
+ }
}
avio_wb32(pb, 0); /* size */
@@ -643,10 +936,21 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, track->sample_size);
avio_wb32(pb, get_samples_per_packet(track));
} else {
- /* reserved for mp4/3gp */
- avio_wb16(pb, 2);
- avio_wb16(pb, 16);
- avio_wb16(pb, 0);
+ if (track->mode == MODE_MOV) {
+ avio_wb16(pb, track->enc->channels);
+ if (track->enc->codec_id == AV_CODEC_ID_PCM_U8 ||
+ track->enc->codec_id == AV_CODEC_ID_PCM_S8)
+ avio_wb16(pb, 8); /* bits per sample */
+ else if (track->enc->codec_id == AV_CODEC_ID_ADPCM_G726)
+ avio_wb16(pb, track->enc->bits_per_coded_sample);
+ else
+ avio_wb16(pb, 16);
+ avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
+ } else { /* reserved for mp4/3gp */
+ avio_wb16(pb, 2);
+ avio_wb16(pb, 16);
+ avio_wb16(pb, 0);
+ }
avio_wb16(pb, 0); /* packet size (= 0) */
avio_wb16(pb, track->enc->sample_rate <= UINT16_MAX ?
@@ -654,13 +958,28 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
avio_wb16(pb, 0); /* Reserved */
}
+ if (version == 1) { /* SoundDescription V1 extended info */
+ if (mov_pcm_le_gt16(track->enc->codec_id) ||
+ mov_pcm_be_gt16(track->enc->codec_id))
+ avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
+ else
+ avio_wb32(pb, track->enc->frame_size); /* Samples per packet */
+ avio_wb32(pb, track->sample_size / track->enc->channels); /* Bytes per packet */
+ avio_wb32(pb, track->sample_size); /* Bytes per frame */
+ avio_wb32(pb, 2); /* Bytes per sample */
+ }
+
if (track->mode == MODE_MOV &&
(track->enc->codec_id == AV_CODEC_ID_AAC ||
track->enc->codec_id == AV_CODEC_ID_AC3 ||
+ track->enc->codec_id == AV_CODEC_ID_EAC3 ||
track->enc->codec_id == AV_CODEC_ID_AMR_NB ||
track->enc->codec_id == AV_CODEC_ID_ALAC ||
track->enc->codec_id == AV_CODEC_ID_ADPCM_MS ||
- track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV))
+ track->enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
+ track->enc->codec_id == AV_CODEC_ID_QDM2 ||
+ (mov_pcm_le_gt16(track->enc->codec_id) && version==1) ||
+ (mov_pcm_be_gt16(track->enc->codec_id) && version==1)))
mov_write_wave_tag(pb, track);
else if (track->tag == MKTAG('m','p','4','a'))
mov_write_esds_tag(pb, track);
@@ -668,6 +987,8 @@ static int mov_write_audio_tag(AVIOContext *pb, MOVTrack *track)
mov_write_amr_tag(pb, track);
else if (track->enc->codec_id == AV_CODEC_ID_AC3)
mov_write_ac3_tag(pb, track);
+ else if (track->enc->codec_id == AV_CODEC_ID_EAC3)
+ mov_write_eac3_tag(pb, track);
else if (track->enc->codec_id == AV_CODEC_ID_ALAC)
mov_write_extradata_tag(pb, track);
else if (track->enc->codec_id == AV_CODEC_ID_WMAPRO)
@@ -693,19 +1014,6 @@ static int mov_write_d263_tag(AVIOContext *pb)
return 0xf;
}
-/* TODO: No idea about these values */
-static int mov_write_svq3_tag(AVIOContext *pb)
-{
- avio_wb32(pb, 0x15);
- ffio_wfourcc(pb, "SMI ");
- ffio_wfourcc(pb, "SEQH");
- avio_wb32(pb, 0x5);
- avio_wb32(pb, 0xe2c0211d);
- avio_wb32(pb, 0xc0000000);
- avio_w8(pb, 0);
- return 0x15;
-}
-
static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
@@ -730,11 +1038,37 @@ static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track)
static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
{
int i;
+ int interlaced;
+ int cid;
+
+ if (track->vos_data && track->vos_len > 0x29) {
+ if (track->vos_data[0] == 0x00 &&
+ track->vos_data[1] == 0x00 &&
+ track->vos_data[2] == 0x02 &&
+ track->vos_data[3] == 0x80 &&
+ (track->vos_data[4] == 0x01 || track->vos_data[4] == 0x02)) {
+ /* looks like a DNxHD bit stream */
+ interlaced = (track->vos_data[5] & 2);
+ cid = AV_RB32(track->vos_data + 0x28);
+ } else {
+ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
+ return 0;
+ }
+ } else {
+ av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
+ return 0;
+ }
+
avio_wb32(pb, 24); /* size */
ffio_wfourcc(pb, "ACLR");
ffio_wfourcc(pb, "ACLR");
ffio_wfourcc(pb, "0001");
- avio_wb32(pb, 2); /* yuv range: full 1 / normal 2 */
+ if (track->enc->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
+ track->enc->color_range == AVCOL_RANGE_UNSPECIFIED) {
+ avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
+ } else { /* Full range (0-255) */
+ avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
+ }
avio_wb32(pb, 0); /* unknown */
avio_wb32(pb, 24); /* size */
@@ -748,10 +1082,10 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
ffio_wfourcc(pb, "ARES");
ffio_wfourcc(pb, "ARES");
ffio_wfourcc(pb, "0001");
- avio_wb32(pb, AV_RB32(track->vos_data + 0x28)); /* dnxhd cid, some id ? */
+ avio_wb32(pb, cid); /* dnxhd cid, some id ? */
avio_wb32(pb, track->enc->width);
/* values below are based on samples created with quicktime and avid codecs */
- if (track->vos_data[5] & 2) { // interlaced
+ if (interlaced) {
avio_wb32(pb, track->enc->height / 2);
avio_wb32(pb, 2); /* unknown */
avio_wb32(pb, 0); /* unknown */
@@ -769,8 +1103,19 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
for (i = 0; i < 10; i++)
avio_wb64(pb, 0);
- /* extra padding for stsd needed */
- avio_wb32(pb, 0);
+ return 0;
+}
+
+static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
+{
+ avio_wb32(pb, 12);
+ ffio_wfourcc(pb, "DpxE");
+ if (track->enc->extradata_size >= 12 &&
+ !memcmp(&track->enc->extradata[4], "DpxE", 4)) {
+ avio_wb32(pb, track->enc->extradata[11]);
+ } else {
+ avio_wb32(pb, 1);
+ }
return 0;
}
@@ -784,6 +1129,7 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
if (track->enc->codec_id == AV_CODEC_ID_H264) tag = MKTAG('a','v','c','1');
else if (track->enc->codec_id == AV_CODEC_ID_HEVC) tag = MKTAG('h','e','v','1');
else if (track->enc->codec_id == AV_CODEC_ID_AC3) tag = MKTAG('a','c','-','3');
+ else if (track->enc->codec_id == AV_CODEC_ID_EAC3) tag = MKTAG('e','c','-','3');
else if (track->enc->codec_id == AV_CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c');
else if (track->enc->codec_id == AV_CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g');
else if (track->enc->codec_id == AV_CODEC_ID_VC1) tag = MKTAG('v','c','-','1');
@@ -815,8 +1161,10 @@ static int ipod_get_codec_tag(AVFormatContext *s, MOVTrack *track)
tag == MKTAG('t', 'e', 'x', 't'))))
tag = ff_codec_get_tag(codec_ipod_tags, track->enc->codec_id);
- if (!av_match_ext(s->filename, "m4a") && !av_match_ext(s->filename, "m4v"))
- av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
+ if (!av_match_ext(s->filename, "m4a") &&
+ !av_match_ext(s->filename, "m4b") &&
+ !av_match_ext(s->filename, "m4v"))
+ av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a, .m4v nor .m4b "
"Quicktime/Ipod might not play the file\n");
return tag;
@@ -826,20 +1174,20 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
{
int tag;
- if (track->enc->width == 720) /* SD */
- if (track->enc->height == 480) /* NTSC */
+ if (track->enc->width == 720) { /* SD */
+ if (track->enc->height == 480) { /* NTSC */
if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
else tag = MKTAG('d','v','c',' ');
- else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
+ }else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
else if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
else tag = MKTAG('d','v','p','p');
- else if (track->enc->height == 720) /* HD 720 line */
+ } else if (track->enc->height == 720) { /* HD 720 line */
if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
else tag = MKTAG('d','v','h','p');
- else if (track->enc->height == 1080) /* HD 1080 line */
+ } else if (track->enc->height == 1080) { /* HD 1080 line */
if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
else tag = MKTAG('d','v','h','6');
- else {
+ } else {
av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
return 0;
}
@@ -847,11 +1195,145 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
return tag;
}
+static AVRational find_fps(AVFormatContext *s, AVStream *st)
+{
+ AVRational rate = {st->codec->time_base.den, st->codec->time_base.num};
+ /* if the codec time base makes no sense, try to fallback on stream frame rate */
+ if (av_timecode_check_frame_rate(rate) < 0) {
+ av_log(s, AV_LOG_DEBUG, "timecode: tbc=%d/%d invalid, fallback on %d/%d\n",
+ rate.num, rate.den, st->avg_frame_rate.num, st->avg_frame_rate.den);
+ rate = st->avg_frame_rate;
+ }
+
+ return rate;
+}
+
+static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
+{
+ int tag = track->enc->codec_tag;
+ int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE;
+ AVStream *st = track->st;
+ int rate = av_q2d(find_fps(s, st));
+
+ if (!tag)
+ tag = MKTAG('m', '2', 'v', '1'); //fallback tag
+
+ if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) {
+ if (track->enc->width == 1280 && track->enc->height == 720) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','v','4');
+ else if (rate == 25) tag = MKTAG('x','d','v','5');
+ else if (rate == 30) tag = MKTAG('x','d','v','1');
+ else if (rate == 50) tag = MKTAG('x','d','v','a');
+ else if (rate == 60) tag = MKTAG('x','d','v','9');
+ }
+ } else if (track->enc->width == 1440 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','v','6');
+ else if (rate == 25) tag = MKTAG('x','d','v','7');
+ else if (rate == 30) tag = MKTAG('x','d','v','8');
+ } else {
+ if (rate == 25) tag = MKTAG('x','d','v','3');
+ else if (rate == 30) tag = MKTAG('x','d','v','2');
+ }
+ } else if (track->enc->width == 1920 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','v','d');
+ else if (rate == 25) tag = MKTAG('x','d','v','e');
+ else if (rate == 30) tag = MKTAG('x','d','v','f');
+ } else {
+ if (rate == 25) tag = MKTAG('x','d','v','c');
+ else if (rate == 30) tag = MKTAG('x','d','v','b');
+ }
+ }
+ } else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) {
+ if (track->enc->width == 1280 && track->enc->height == 720) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','5','4');
+ else if (rate == 25) tag = MKTAG('x','d','5','5');
+ else if (rate == 30) tag = MKTAG('x','d','5','1');
+ else if (rate == 50) tag = MKTAG('x','d','5','a');
+ else if (rate == 60) tag = MKTAG('x','d','5','9');
+ }
+ } else if (track->enc->width == 1920 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('x','d','5','d');
+ else if (rate == 25) tag = MKTAG('x','d','5','e');
+ else if (rate == 30) tag = MKTAG('x','d','5','f');
+ } else {
+ if (rate == 25) tag = MKTAG('x','d','5','c');
+ else if (rate == 30) tag = MKTAG('x','d','5','b');
+ }
+ }
+ }
+
+ return tag;
+}
+
+static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
+{
+ int tag = track->enc->codec_tag;
+ int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE;
+ AVStream *st = track->st;
+ int rate = av_q2d(find_fps(s, st));
+
+ if (!tag)
+ tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
+
+ if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P10) {
+ if (track->enc->width == 960 && track->enc->height == 720) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('a','i','5','p');
+ else if (rate == 25) tag = MKTAG('a','i','5','q');
+ else if (rate == 30) tag = MKTAG('a','i','5','p');
+ else if (rate == 50) tag = MKTAG('a','i','5','q');
+ else if (rate == 60) tag = MKTAG('a','i','5','p');
+ }
+ } else if (track->enc->width == 1440 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('a','i','5','3');
+ else if (rate == 25) tag = MKTAG('a','i','5','2');
+ else if (rate == 30) tag = MKTAG('a','i','5','3');
+ } else {
+ if (rate == 50) tag = MKTAG('a','i','5','5');
+ else if (rate == 60) tag = MKTAG('a','i','5','6');
+ }
+ }
+ } else if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P10) {
+ if (track->enc->width == 1280 && track->enc->height == 720) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('a','i','1','p');
+ else if (rate == 25) tag = MKTAG('a','i','1','q');
+ else if (rate == 30) tag = MKTAG('a','i','1','p');
+ else if (rate == 50) tag = MKTAG('a','i','1','q');
+ else if (rate == 60) tag = MKTAG('a','i','1','p');
+ }
+ } else if (track->enc->width == 1920 && track->enc->height == 1080) {
+ if (!interlaced) {
+ if (rate == 24) tag = MKTAG('a','i','1','3');
+ else if (rate == 25) tag = MKTAG('a','i','1','2');
+ else if (rate == 30) tag = MKTAG('a','i','1','3');
+ } else {
+ if (rate == 25) tag = MKTAG('a','i','1','5');
+ else if (rate == 50) tag = MKTAG('a','i','1','5');
+ else if (rate == 60) tag = MKTAG('a','i','1','6');
+ }
+ } else if ( track->enc->width == 4096 && track->enc->height == 2160
+ || track->enc->width == 3840 && track->enc->height == 2160
+ || track->enc->width == 2048 && track->enc->height == 1080) {
+ tag = MKTAG('a','i','v','x');
+ }
+ }
+
+ return tag;
+}
+
static const struct {
enum AVPixelFormat pix_fmt;
uint32_t tag;
unsigned bps;
} mov_pix_fmt_tags[] = {
+ { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
{ AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
{ AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
{ AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
@@ -872,15 +1354,24 @@ static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
{
int tag = track->enc->codec_tag;
int i;
+ enum AVPixelFormat pix_fmt;
for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) {
tag = mov_pix_fmt_tags[i].tag;
track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
- break;
+ if (track->enc->codec_tag == mov_pix_fmt_tags[i].tag)
+ break;
}
}
+ pix_fmt = avpriv_find_pix_fmt(avpriv_pix_fmt_bps_mov,
+ track->enc->bits_per_coded_sample);
+ if (tag == MKTAG('r','a','w',' ') &&
+ track->enc->pix_fmt != pix_fmt &&
+ track->enc->pix_fmt != AV_PIX_FMT_NONE)
+ av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
+ av_get_pix_fmt_name(track->enc->pix_fmt));
return tag;
}
@@ -892,11 +1383,17 @@ static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
(track->enc->codec_id == AV_CODEC_ID_DVVIDEO ||
track->enc->codec_id == AV_CODEC_ID_RAWVIDEO ||
track->enc->codec_id == AV_CODEC_ID_H263 ||
+ track->enc->codec_id == AV_CODEC_ID_H264 ||
+ track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
av_get_bits_per_sample(track->enc->codec_id)))) { // pcm audio
if (track->enc->codec_id == AV_CODEC_ID_DVVIDEO)
tag = mov_get_dv_codec_tag(s, track);
else if (track->enc->codec_id == AV_CODEC_ID_RAWVIDEO)
tag = mov_get_rawvideo_codec_tag(s, track);
+ else if (track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO)
+ tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
+ else if (track->enc->codec_id == AV_CODEC_ID_H264)
+ tag = mov_get_h264_codec_tag(s, track);
else if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->enc->codec_id);
if (!tag) { // if no mac fcc found, try with Microsoft tags
@@ -933,7 +1430,7 @@ static const AVCodecTag codec_3gp_tags[] = {
{ AV_CODEC_ID_NONE, 0 },
};
-static const AVCodecTag codec_f4v_tags[] = {
+static const AVCodecTag codec_f4v_tags[] = { // XXX: add GIF/PNG/JPEG?
{ AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
{ AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
{ AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
@@ -1027,11 +1524,138 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
return 16;
}
-static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_gama_tag(AVIOContext *pb, MOVTrack *track, double gamma)
+{
+ uint32_t gama = 0;
+ if (gamma <= 0.0)
+ {
+ gamma = avpriv_get_gamma_from_trc(track->enc->color_trc);
+ }
+ av_log(pb, AV_LOG_DEBUG, "gamma value %g\n", gamma);
+
+ if (gamma > 1e-6) {
+ gama = (uint32_t)lrint((double)(1<<16) * gamma);
+ av_log(pb, AV_LOG_DEBUG, "writing gama value %d\n", gama);
+
+ av_assert0(track->mode == MODE_MOV);
+ avio_wb32(pb, 12);
+ ffio_wfourcc(pb, "gama");
+ avio_wb32(pb, gama);
+ return 12;
+ }
+ else {
+ av_log(pb, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
+ }
+ return 0;
+}
+
+static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track)
+{
+ // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
+ // Ref (MP4): ISO/IEC 14496-12:2012
+
+ if (track->enc->color_primaries == AVCOL_PRI_UNSPECIFIED &&
+ track->enc->color_trc == AVCOL_TRC_UNSPECIFIED &&
+ track->enc->colorspace == AVCOL_SPC_UNSPECIFIED) {
+ if ((track->enc->width >= 1920 && track->enc->height >= 1080)
+ || (track->enc->width == 1280 && track->enc->height == 720)) {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, assuming bt709\n");
+ track->enc->color_primaries = AVCOL_PRI_BT709;
+ } else if (track->enc->width == 720 && track->height == 576) {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, assuming bt470bg\n");
+ track->enc->color_primaries = AVCOL_PRI_BT470BG;
+ } else if (track->enc->width == 720 &&
+ (track->height == 486 || track->height == 480)) {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, assuming smpte170\n");
+ track->enc->color_primaries = AVCOL_PRI_SMPTE170M;
+ } else {
+ av_log(NULL, AV_LOG_WARNING, "color primaries unspecified, unable to assume anything\n");
+ }
+ switch (track->enc->color_primaries) {
+ case AVCOL_PRI_BT709:
+ track->enc->color_trc = AVCOL_TRC_BT709;
+ track->enc->colorspace = AVCOL_SPC_BT709;
+ break;
+ case AVCOL_PRI_SMPTE170M:
+ case AVCOL_PRI_BT470BG:
+ track->enc->color_trc = AVCOL_TRC_BT709;
+ track->enc->colorspace = AVCOL_SPC_SMPTE170M;
+ break;
+ }
+ }
+
+ /* We should only ever be called by MOV or MP4. */
+ av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4);
+
+ avio_wb32(pb, 18 + (track->mode == MODE_MP4));
+ ffio_wfourcc(pb, "colr");
+ if (track->mode == MODE_MP4)
+ ffio_wfourcc(pb, "nclx");
+ else
+ ffio_wfourcc(pb, "nclc");
+ switch (track->enc->color_primaries) {
+ case AVCOL_PRI_BT709: avio_wb16(pb, 1); break;
+ case AVCOL_PRI_SMPTE170M:
+ case AVCOL_PRI_SMPTE240M: avio_wb16(pb, 6); break;
+ case AVCOL_PRI_BT470BG: avio_wb16(pb, 5); break;
+ default: avio_wb16(pb, 2);
+ }
+ switch (track->enc->color_trc) {
+ case AVCOL_TRC_BT709: avio_wb16(pb, 1); break;
+ case AVCOL_TRC_SMPTE170M: avio_wb16(pb, 1); break; // remapped
+ case AVCOL_TRC_SMPTE240M: avio_wb16(pb, 7); break;
+ default: avio_wb16(pb, 2);
+ }
+ switch (track->enc->colorspace) {
+ case AVCOL_SPC_BT709: avio_wb16(pb, 1); break;
+ case AVCOL_SPC_BT470BG:
+ case AVCOL_SPC_SMPTE170M: avio_wb16(pb, 6); break;
+ case AVCOL_SPC_SMPTE240M: avio_wb16(pb, 7); break;
+ default: avio_wb16(pb, 2);
+ }
+
+ if (track->mode == MODE_MP4) {
+ int full_range = track->enc->color_range == AVCOL_RANGE_JPEG;
+ avio_w8(pb, full_range << 7);
+ return 19;
+ } else {
+ return 18;
+ }
+}
+
+static void find_compressor(char * compressor_name, int len, MOVTrack *track)
{
AVDictionaryEntry *encoder;
+ int xdcam_res = (track->enc->width == 1280 && track->enc->height == 720)
+ || (track->enc->width == 1440 && track->enc->height == 1080)
+ || (track->enc->width == 1920 && track->enc->height == 1080);
+
+ if (track->mode == MODE_MOV &&
+ (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
+ av_strlcpy(compressor_name, encoder->value, 32);
+ } else if (track->enc->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
+ int interlaced = track->enc->field_order > AV_FIELD_PROGRESSIVE;
+ AVStream *st = track->st;
+ int rate = av_q2d(find_fps(NULL, st));
+ av_strlcatf(compressor_name, len, "XDCAM");
+ if (track->enc->pix_fmt == AV_PIX_FMT_YUV422P) {
+ av_strlcatf(compressor_name, len, " HD422");
+ } else if(track->enc->width == 1440) {
+ av_strlcatf(compressor_name, len, " HD");
+ } else
+ av_strlcatf(compressor_name, len, " EX");
+
+ av_strlcatf(compressor_name, len, " %d%c", track->enc->height, interlaced ? 'i' : 'p');
+
+ av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
+ }
+}
+
+static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
+{
int64_t pos = avio_tell(pb);
char compressor_name[32] = { 0 };
+ int avid = 0;
avio_wb32(pb, 0); /* size */
avio_wl32(pb, track->tag); // store it byteswapped
@@ -1063,9 +1687,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
avio_wb16(pb, 1); /* Frame count (= 1) */
/* FIXME not sure, ISO 14496-1 draft where it shall be set to 0 */
- if (track->mode == MODE_MOV &&
- (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0)))
- av_strlcpy(compressor_name, encoder->value, 32);
+ find_compressor(compressor_name, 32, track);
avio_w8(pb, strlen(compressor_name));
avio_write(pb, compressor_name, 31);
@@ -1078,32 +1700,60 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track)
mov_write_esds_tag(pb, track);
else if (track->enc->codec_id == AV_CODEC_ID_H263)
mov_write_d263_tag(pb);
- else if (track->enc->codec_id == AV_CODEC_ID_SVQ3)
- mov_write_svq3_tag(pb);
- else if (track->enc->codec_id == AV_CODEC_ID_DNXHD)
+ else if (track->enc->codec_id == AV_CODEC_ID_AVUI ||
+ track->enc->codec_id == AV_CODEC_ID_SVQ3) {
+ mov_write_extradata_tag(pb, track);
+ avio_wb32(pb, 0);
+ } else if (track->enc->codec_id == AV_CODEC_ID_DNXHD) {
mov_write_avid_tag(pb, track);
- else if (track->enc->codec_id == AV_CODEC_ID_HEVC)
+ avid = 1;
+ } else if (track->enc->codec_id == AV_CODEC_ID_HEVC)
mov_write_hvcc_tag(pb, track);
- else if (track->enc->codec_id == AV_CODEC_ID_H264) {
+ else if (track->enc->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
mov_write_avcc_tag(pb, track);
if (track->mode == MODE_IPOD)
mov_write_uuid_tag_ipod(pb);
- } else if (track->enc->field_order != AV_FIELD_UNKNOWN)
- mov_write_fiel_tag(pb, track);
- else if (track->enc->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
+ } else if (track->enc->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
mov_write_dvc1_tag(pb, track);
else if (track->enc->codec_id == AV_CODEC_ID_VP6F ||
track->enc->codec_id == AV_CODEC_ID_VP6A) {
/* Don't write any potential extradata here - the cropping
* is signalled via the normal width/height fields. */
+ } else if (track->enc->codec_id == AV_CODEC_ID_R10K) {
+ if (track->enc->codec_tag == MKTAG('R','1','0','k'))
+ mov_write_dpxe_tag(pb, track);
} else if (track->vos_len > 0)
mov_write_glbl_tag(pb, track);
+ if (track->enc->codec_id != AV_CODEC_ID_H264 &&
+ track->enc->codec_id != AV_CODEC_ID_MPEG4 &&
+ track->enc->codec_id != AV_CODEC_ID_DNXHD)
+ if (track->enc->field_order != AV_FIELD_UNKNOWN)
+ mov_write_fiel_tag(pb, track);
+
+ if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
+ if (track->mode == MODE_MOV)
+ mov_write_gama_tag(pb, track, mov->gamma);
+ else
+ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
+ }
+ if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
+ if (track->mode == MODE_MOV || track->mode == MODE_MP4)
+ mov_write_colr_tag(pb, track);
+ else
+ av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4.\n");
+ }
+
if (track->enc->sample_aspect_ratio.den && track->enc->sample_aspect_ratio.num &&
track->enc->sample_aspect_ratio.den != track->enc->sample_aspect_ratio.num) {
mov_write_pasp_tag(pb, track);
}
+ /* extra padding for avid stsd */
+ /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
+ if (avid)
+ avio_wb32(pb, 0);
+
return update_size(pb, pos);
}
@@ -1127,9 +1777,57 @@ static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
return update_size(pb, pos);
}
+static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
+{
+ uint64_t str_size =strlen(reel_name);
+ int64_t pos = avio_tell(pb);
+
+ if (str_size >= UINT16_MAX){
+ av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
+ avio_wb16(pb, 0);
+ return AVERROR(EINVAL);
+ }
+
+ avio_wb32(pb, 0); /* size */
+ ffio_wfourcc(pb, "name"); /* Data format */
+ avio_wb16(pb, str_size); /* string size */
+ avio_wb16(pb, track->language); /* langcode */
+ avio_write(pb, reel_name, str_size); /* reel name */
+ return update_size(pb,pos);
+}
+
static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
+#if 1
+ int frame_duration = av_rescale(track->timescale, track->enc->time_base.num, track->enc->time_base.den);
+ int nb_frames = 1.0/av_q2d(track->enc->time_base) + 0.5;
+ AVDictionaryEntry *t = NULL;
+
+ if (nb_frames > 255) {
+ av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
+ return AVERROR(EINVAL);
+ }
+
+ avio_wb32(pb, 0); /* size */
+ ffio_wfourcc(pb, "tmcd"); /* Data format */
+ avio_wb32(pb, 0); /* Reserved */
+ avio_wb32(pb, 1); /* Data reference index */
+ avio_wb32(pb, 0); /* Flags */
+ avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
+ avio_wb32(pb, track->timescale); /* Timescale */
+ avio_wb32(pb, frame_duration); /* Frame duration */
+ avio_w8(pb, nb_frames); /* Number of frames */
+ avio_w8(pb, 0); /* Reserved */
+
+ if (track->st)
+ t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
+
+ if (t && utf8len(t->value))
+ mov_write_source_reference_tag(pb, track, t->value);
+ else
+ avio_wb16(pb, 0); /* zero size */
+#else
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "tmcd"); /* Data format */
@@ -1137,10 +1835,11 @@ static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 1); /* Data reference index */
if (track->enc->extradata_size)
avio_write(pb, track->enc->extradata, track->enc->extradata_size);
+#endif
return update_size(pb, pos);
}
-static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_stsd_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
avio_wb32(pb, 0); /* size */
@@ -1148,7 +1847,7 @@ static int mov_write_stsd_tag(AVIOContext *pb, MOVTrack *track)
avio_wb32(pb, 0); /* version & flags */
avio_wb32(pb, 1); /* entry count */
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
- mov_write_video_tag(pb, track);
+ mov_write_video_tag(pb, mov, track);
else if (track->enc->codec_type == AVMEDIA_TYPE_AUDIO)
mov_write_audio_tag(pb, track);
else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)
@@ -1167,7 +1866,7 @@ static int mov_write_ctts_tag(AVIOContext *pb, MOVTrack *track)
uint32_t atom_size;
int i;
- ctts_entries = av_malloc((track->entry + 1) * sizeof(*ctts_entries)); /* worst case */
+ ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
if (!ctts_entries)
return AVERROR(ENOMEM);
ctts_entries[0].count = 1;
@@ -1212,7 +1911,7 @@ static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
entries = 1;
} else {
if (track->entry) {
- stts_entries = av_malloc(track->entry * sizeof(*stts_entries)); /* worst case */
+ stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
if (!stts_entries)
return AVERROR(ENOMEM);
}
@@ -1249,18 +1948,21 @@ static int mov_write_dref_tag(AVIOContext *pb)
avio_wb32(pb, 1); /* entry count */
avio_wb32(pb, 0xc); /* size */
+ //FIXME add the alis and rsrc atom
ffio_wfourcc(pb, "url ");
avio_wb32(pb, 1); /* version & flags */
return 28;
}
-static int mov_write_stbl_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_stbl_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
+ int ret;
+
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "stbl");
- mov_write_stsd_tag(pb, track);
+ mov_write_stsd_tag(pb, mov, track);
mov_write_stts_tag(pb, track);
if ((track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
track->enc->codec_tag == MKTAG('r','t','p',' ')) &&
@@ -1269,8 +1971,11 @@ static int mov_write_stbl_tag(AVIOContext *pb, MOVTrack *track)
if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO &&
- track->flags & MOV_TRACK_CTTS && track->entry)
- mov_write_ctts_tag(pb, track);
+ track->flags & MOV_TRACK_CTTS && track->entry) {
+
+ if ((ret = mov_write_ctts_tag(pb, track)) < 0)
+ return ret;
+ }
mov_write_stsc_tag(pb, track);
mov_write_stsz_tag(pb, track);
mov_write_stco_tag(pb, track);
@@ -1294,9 +1999,32 @@ static int mov_write_nmhd_tag(AVIOContext *pb)
return 12;
}
-static int mov_write_gmhd_tag(AVIOContext *pb)
+static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
+{
+ int64_t pos = avio_tell(pb);
+ const char *font = "Lucida Grande";
+ avio_wb32(pb, 0); /* size */
+ ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
+ avio_wb32(pb, 0); /* version & flags */
+ avio_wb16(pb, 0); /* text font */
+ avio_wb16(pb, 0); /* text face */
+ avio_wb16(pb, 12); /* text size */
+ avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
+ avio_wb16(pb, 0x0000); /* text color (red) */
+ avio_wb16(pb, 0x0000); /* text color (green) */
+ avio_wb16(pb, 0x0000); /* text color (blue) */
+ avio_wb16(pb, 0xffff); /* background color (red) */
+ avio_wb16(pb, 0xffff); /* background color (green) */
+ avio_wb16(pb, 0xffff); /* background color (blue) */
+ avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
+ avio_write(pb, font, strlen(font)); /* font name */
+ return update_size(pb, pos);
+}
+
+static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
{
- avio_wb32(pb, 0x20); /* size */
+ int64_t pos = avio_tell(pb);
+ avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "gmhd");
avio_wb32(pb, 0x18); /* gmin size */
ffio_wfourcc(pb, "gmin");/* generic media info */
@@ -1307,7 +2035,36 @@ static int mov_write_gmhd_tag(AVIOContext *pb)
avio_wb16(pb, 0x8000); /* opColor (b?) */
avio_wb16(pb, 0); /* balance */
avio_wb16(pb, 0); /* reserved */
- return 0x20;
+
+ /*
+ * This special text atom is required for
+ * Apple Quicktime chapters. The contents
+ * don't appear to be documented, so the
+ * bytes are copied verbatim.
+ */
+ if (track->tag != MKTAG('c','6','0','8')) {
+ avio_wb32(pb, 0x2C); /* size */
+ ffio_wfourcc(pb, "text");
+ avio_wb16(pb, 0x01);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x01);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00);
+ avio_wb32(pb, 0x00004000);
+ avio_wb16(pb, 0x0000);
+ }
+
+ if (track->enc->codec_tag == MKTAG('t','m','c','d')) {
+ int64_t tmcd_pos = avio_tell(pb);
+ avio_wb32(pb, 0); /* size */
+ ffio_wfourcc(pb, "tmcd");
+ mov_write_tcmi_tag(pb, track);
+ update_size(pb, tmcd_pos);
+ }
+ return update_size(pb, pos);
}
static int mov_write_smhd_tag(AVIOContext *pb)
@@ -1353,16 +2110,19 @@ static int mov_write_hdlr_tag(AVIOContext *pb, MOVTrack *track)
hdlr_type = "soun";
descr = "SoundHandler";
} else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- if (track->tag == MKTAG('t','x','3','g')) {
- hdlr_type = "sbtl";
- } else if (track->tag == MKTAG('m','p','4','s')) {
- hdlr_type = "subp";
- } else if (is_clcp_track(track)) {
+ if (is_clcp_track(track)) {
hdlr_type = "clcp";
+ descr = "ClosedCaptionHandler";
} else {
- hdlr_type = "text";
- }
+ if (track->tag == MKTAG('t','x','3','g')) {
+ hdlr_type = "sbtl";
+ } else if (track->tag == MKTAG('m','p','4','s')) {
+ hdlr_type = "subp";
+ } else {
+ hdlr_type = "text";
+ }
descr = "SubtitleHandler";
+ }
} else if (track->enc->codec_tag == MKTAG('r','t','p',' ')) {
hdlr_type = "hint";
descr = "HintHandler";
@@ -1420,9 +2180,11 @@ static int mov_write_hmhd_tag(AVIOContext *pb)
return 28;
}
-static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
+static int mov_write_minf_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
+ int ret;
+
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "minf");
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO)
@@ -1431,19 +2193,20 @@ static int mov_write_minf_tag(AVIOContext *pb, MOVTrack *track)
mov_write_smhd_tag(pb);
else if (track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (track->tag == MKTAG('t','e','x','t') || is_clcp_track(track)) {
- mov_write_gmhd_tag(pb);
+ mov_write_gmhd_tag(pb, track);
} else {
mov_write_nmhd_tag(pb);
}
} else if (track->tag == MKTAG('r','t','p',' ')) {
mov_write_hmhd_tag(pb);
} else if (track->tag == MKTAG('t','m','c','d')) {
- mov_write_gmhd_tag(pb);
+ mov_write_gmhd_tag(pb, track);
}
if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */
mov_write_hdlr_tag(pb, NULL);
mov_write_dinf_tag(pb);
- mov_write_stbl_tag(pb, track);
+ if ((ret = mov_write_stbl_tag(pb, mov, track)) < 0)
+ return ret;
return update_size(pb, pos);
}
@@ -1490,14 +2253,35 @@ static int mov_write_mdia_tag(AVIOContext *pb, MOVMuxContext *mov,
MOVTrack *track)
{
int64_t pos = avio_tell(pb);
+ int ret;
+
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "mdia");
mov_write_mdhd_tag(pb, mov, track);
mov_write_hdlr_tag(pb, track);
- mov_write_minf_tag(pb, track);
+ if ((ret = mov_write_minf_tag(pb, mov, track)) < 0)
+ return ret;
return update_size(pb, pos);
}
+/* transformation matrix
+ |a b u|
+ |c d v|
+ |tx ty w| */
+static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
+ int16_t d, int16_t tx, int16_t ty)
+{
+ avio_wb32(pb, a << 16); /* 16.16 format */
+ avio_wb32(pb, b << 16); /* 16.16 format */
+ avio_wb32(pb, 0); /* u in 2.30 format */
+ avio_wb32(pb, c << 16); /* 16.16 format */
+ avio_wb32(pb, d << 16); /* 16.16 format */
+ avio_wb32(pb, 0); /* v in 2.30 format */
+ avio_wb32(pb, tx << 16); /* 16.16 format */
+ avio_wb32(pb, ty << 16); /* 16.16 format */
+ avio_wb32(pb, 1 << 30); /* w in 2.30 format */
+}
+
static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
MOVTrack *track, AVStream *st)
{
@@ -1505,6 +2289,7 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
track->timescale, AV_ROUND_UP);
int version = duration < INT32_MAX ? 0 : 1;
int flags = MOV_TKHD_FLAG_IN_MOVIE;
+ int rotation = 0;
int group = 0;
uint32_t *display_matrix = NULL;
@@ -1518,7 +2303,7 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
display_matrix = (uint32_t*)av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX,
&display_matrix_size);
- if (display_matrix_size < 9 * sizeof(*display_matrix))
+ if (display_matrix && display_matrix_size < 9 * sizeof(*display_matrix))
display_matrix = NULL;
}
@@ -1560,21 +2345,22 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb16(pb, 0); /* reserved */
/* Matrix structure */
+ if (st && st->metadata) {
+ AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0);
+ rotation = (rot && rot->value) ? atoi(rot->value) : 0;
+ }
if (display_matrix) {
for (i = 0; i < 9; i++)
avio_wb32(pb, display_matrix[i]);
+ } else if (rotation == 90) {
+ write_matrix(pb, 0, 1, -1, 0, track->enc->height, 0);
+ } else if (rotation == 180) {
+ write_matrix(pb, -1, 0, 0, -1, track->enc->width, track->enc->height);
+ } else if (rotation == 270) {
+ write_matrix(pb, 0, -1, 1, 0, 0, track->enc->width);
} else {
- avio_wb32(pb, 0x00010000); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x00010000); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x40000000); /* reserved */
+ write_matrix(pb, 1, 0, 0, 1, 0, 0);
}
-
/* Track width and height, for visual only */
if (st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO ||
track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
@@ -1635,7 +2421,21 @@ static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
int version = duration < INT32_MAX ? 0 : 1;
int entry_size, entry_count, size;
int64_t delay, start_ct = track->start_cts;
- delay = av_rescale_rnd(track->start_dts + start_ct, MOV_TIMESCALE,
+ int64_t start_dts = track->start_dts;
+
+ if (track->entry) {
+ if (start_dts != track->cluster[0].dts || start_ct != track->cluster[0].cts) {
+
+ av_log(mov->fc, AV_LOG_DEBUG,
+ "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
+ track->cluster[0].dts, track->cluster[0].cts,
+ start_dts, start_ct, track->track_id);
+ start_dts = track->cluster[0].dts;
+ start_ct = track->cluster[0].cts;
+ }
+ }
+
+ delay = av_rescale_rnd(start_dts + start_ct, MOV_TIMESCALE,
track->timescale, AV_ROUND_DOWN);
version |= delay < INT32_MAX ? 0 : 1;
@@ -1671,7 +2471,8 @@ static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
* special meaning. Normally start_ct should end up positive or zero
* here, but use FFMIN in case dts is a a small positive integer
* rounded to 0 when represented in MOV_TIMESCALE units. */
- start_ct = -FFMIN(track->start_dts, 0);
+ av_assert0(av_rescale_rnd(start_dts, MOV_TIMESCALE, track->timescale, AV_ROUND_DOWN) <= 0);
+ start_ct = -FFMIN(start_dts, 0);
/* Note, this delay is calculated from the pts of the first sample,
* ensuring that we don't reduce the duration for cases with
* dts<0 pts=0. */
@@ -1793,26 +2594,33 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
{
int64_t pos = avio_tell(pb);
int entry_backup = track->entry;
+ int chunk_backup = track->chunkCount;
+ int ret;
+
/* If we want to have an empty moov, but some samples already have been
* buffered (delay_moov), pretend that no samples have been written yet. */
if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
- track->entry = 0;
+ track->chunkCount = track->entry = 0;
avio_wb32(pb, 0); /* size */
ffio_wfourcc(pb, "trak");
mov_write_tkhd_tag(pb, mov, track, st);
- if (track->start_dts != AV_NOPTS_VALUE &&
- (track->mode == MODE_PSP || track->flags & MOV_TRACK_CTTS ||
- track->start_dts || is_clcp_track(track))) {
+
+ av_assert2(mov->use_editlist >= 0);
+
+ if (track->start_dts != AV_NOPTS_VALUE) {
if (mov->use_editlist)
- mov_write_edts_tag(pb, mov, track); // PSP Movies require edts box
+ mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
av_log(mov->fc, AV_LOG_WARNING,
"Not writing any edit list even though one would have been required\n");
}
+
if (track->tref_tag)
mov_write_tref_tag(pb, track);
- mov_write_mdia_tag(pb, mov, track);
+
+ if ((ret = mov_write_mdia_tag(pb, mov, track)) < 0)
+ return ret;
if (track->mode == MODE_PSP)
mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
if (track->tag == MKTAG('r','t','p',' '))
@@ -1820,16 +2628,17 @@ static int mov_write_trak_tag(AVIOContext *pb, MOVMuxContext *mov,
if (track->mode == MODE_MOV) {
if (track->enc->codec_type == AVMEDIA_TYPE_VIDEO) {
double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
- if ((0.0 != sample_aspect_ratio && 1.0 != sample_aspect_ratio)) {
+ if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
mov_write_tapt_tag(pb, track);
}
}
- if (is_clcp_track(track)) {
+ if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
mov_write_tapt_tag(pb, track);
}
}
mov_write_track_udta_tag(pb, mov, st);
track->entry = entry_backup;
+ track->chunkCount = chunk_backup;
return update_size(pb, pos);
}
@@ -1889,12 +2698,12 @@ static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
{
int max_track_id = 1, i;
- int64_t max_track_len_temp, max_track_len = 0;
+ int64_t max_track_len = 0;
int version;
for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
- max_track_len_temp = av_rescale_rnd(mov->tracks[i].track_duration,
+ int64_t max_track_len_temp = av_rescale_rnd(mov->tracks[i].track_duration,
MOV_TIMESCALE,
mov->tracks[i].timescale,
AV_ROUND_UP);
@@ -1912,7 +2721,8 @@ static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
}
version = max_track_len < UINT32_MAX ? 0 : 1;
- (version == 1) ? avio_wb32(pb, 120) : avio_wb32(pb, 108); /* size */
+ avio_wb32(pb, version == 1 ? 120 : 108); /* size */
+
ffio_wfourcc(pb, "mvhd");
avio_w8(pb, version);
avio_wb24(pb, 0); /* flags */
@@ -1933,15 +2743,7 @@ static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
avio_wb32(pb, 0); /* reserved */
/* Matrix structure */
- avio_wb32(pb, 0x00010000); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x00010000); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x0); /* reserved */
- avio_wb32(pb, 0x40000000); /* reserved */
+ write_matrix(pb, 1, 0, 0, 1, 0, 0);
avio_wb32(pb, 0); /* reserved (preview time) */
avio_wb32(pb, 0); /* reserved (preview duration) */
@@ -2027,28 +2829,79 @@ static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
return mov_write_string_tag(pb, name, t->value, lang, long_style);
}
-/* iTunes track number */
+/* iTunes bpm number */
+static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
+{
+ AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
+ int size = 0, tmpo = t ? atoi(t->value) : 0;
+ if (tmpo) {
+ size = 26;
+ avio_wb32(pb, size);
+ ffio_wfourcc(pb, "tmpo");
+ avio_wb32(pb, size-8); /* size */
+ ffio_wfourcc(pb, "data");
+ avio_wb32(pb, 0x15); //type specifier
+ avio_wb32(pb, 0);
+ avio_wb16(pb, tmpo); // data
+ }
+ return size;
+}
+
+/* iTunes track or disc number */
static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
- AVFormatContext *s)
+ AVFormatContext *s, int disc)
{
- AVDictionaryEntry *t = av_dict_get(s->metadata, "track", NULL, 0);
+ AVDictionaryEntry *t = av_dict_get(s->metadata,
+ disc ? "disc" : "track",
+ NULL, 0);
int size = 0, track = t ? atoi(t->value) : 0;
if (track) {
+ int tracks = 0;
+ char *slash = strchr(t->value, '/');
+ if (slash)
+ tracks = atoi(slash + 1);
avio_wb32(pb, 32); /* size */
- ffio_wfourcc(pb, "trkn");
+ ffio_wfourcc(pb, disc ? "disk" : "trkn");
avio_wb32(pb, 24); /* size */
ffio_wfourcc(pb, "data");
avio_wb32(pb, 0); // 8 bytes empty
avio_wb32(pb, 0);
avio_wb16(pb, 0); // empty
- avio_wb16(pb, track); // track number
- avio_wb16(pb, 0); // total track number
+ avio_wb16(pb, track); // track / disc number
+ avio_wb16(pb, tracks); // total track / disc number
avio_wb16(pb, 0); // empty
size = 32;
}
return size;
}
+static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
+ const char *name, const char *tag,
+ int len)
+{
+ AVDictionaryEntry *t = NULL;
+ uint8_t num;
+ int size = 24 + len;
+
+ if (len != 1 && len != 4)
+ return -1;
+
+ if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
+ return 0;
+ num = atoi(t->value);
+
+ avio_wb32(pb, size);
+ ffio_wfourcc(pb, name);
+ avio_wb32(pb, size - 8);
+ ffio_wfourcc(pb, "data");
+ avio_wb32(pb, 0x15);
+ avio_wb32(pb, 0);
+ if (len==4) avio_wb32(pb, num);
+ else avio_w8 (pb, num);
+
+ return size;
+}
+
/* iTunes meta data list */
static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
AVFormatContext *s)
@@ -2062,7 +2915,8 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
mov_write_string_metadata(s, pb, "\251day", "date" , 1);
- if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1))
+ if (!mov->exact &&
+ !mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1))
mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
@@ -2074,7 +2928,15 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
mov_write_string_metadata(s, pb, "tven", "episode_id",1);
mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
- mov_write_trkn_tag(pb, mov, s);
+ mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
+ mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
+ mov_write_int8_metadata (s, pb, "stik", "media_type",1);
+ mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
+ mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
+ mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
+ mov_write_trkn_tag(pb, mov, s, 0); // track number
+ mov_write_trkn_tag(pb, mov, s, 1); // disc number
+ mov_write_tmpo_tag(pb, s);
return update_size(pb, pos);
}
@@ -2093,6 +2955,26 @@ static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
return size;
}
+static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
+ const char *name, const char *key)
+{
+ int len;
+ AVDictionaryEntry *t;
+
+ if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
+ return 0;
+
+ len = strlen(t->value);
+ if (len > 0) {
+ int size = len + 8;
+ avio_wb32(pb, size);
+ ffio_wfourcc(pb, name);
+ avio_write(pb, t->value, len);
+ return size;
+ }
+ return 0;
+}
+
static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
{
int val;
@@ -2166,9 +3048,6 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
int ret, size;
uint8_t *buf;
- if (s->flags & AVFMT_FLAG_BITEXACT)
- return 0;
-
ret = avio_open_dyn_buf(&pb_buf);
if (ret < 0)
return ret;
@@ -2189,11 +3068,15 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
+ // currently ignored by mov.c
mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
+ // add support for libquicktime, this atom is also actually read by mov.c
+ mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
+ mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
} else {
/* iTunes meta data */
mov_write_meta_tag(pb_buf, mov, s);
@@ -2227,6 +3110,7 @@ static void mov_write_psp_udta_tag(AVIOContext *pb,
static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
{
+ MOVMuxContext *mov = s->priv_data;
AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
int64_t pos, pos2;
@@ -2251,7 +3135,8 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
avio_wb16(pb, 0x0); /* ? */
avio_wb16(pb, 0x021C); /* data */
- mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT, "eng", 0x04);
+ if (!mov->exact)
+ mov_write_psp_udta_tag(pb, LIBAVCODEC_IDENT, "eng", 0x04);
mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
@@ -2262,6 +3147,29 @@ static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
return 0;
}
+static void build_chunks(MOVTrack *trk)
+{
+ int i;
+ MOVIentry *chunk = &trk->cluster[0];
+ uint64_t chunkSize = chunk->size;
+ chunk->chunkNum = 1;
+ if (trk->chunkCount)
+ return;
+ trk->chunkCount = 1;
+ for (i = 1; i<trk->entry; i++){
+ if (chunk->pos + chunkSize == trk->cluster[i].pos &&
+ chunkSize + trk->cluster[i].size < (1<<20)){
+ chunkSize += trk->cluster[i].size;
+ chunk->samples_in_chunk += trk->cluster[i].entries;
+ } else {
+ trk->cluster[i].chunkNum = chunk->chunkNum+1;
+ chunk=&trk->cluster[i];
+ chunkSize = chunk->size;
+ trk->chunkCount++;
+ }
+ }
+}
+
static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
AVFormatContext *s)
{
@@ -2276,6 +3184,9 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
mov->tracks[i].time = mov->time;
mov->tracks[i].track_id = i + 1;
+
+ if (mov->tracks[i].entry)
+ build_chunks(&mov->tracks[i]);
}
if (mov->chapter_track)
@@ -2290,13 +3201,26 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
mov->tracks[mov->tracks[i].src_track].track_id;
}
}
+ for (i = 0; i < mov->nb_streams; i++) {
+ if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
+ int src_trk = mov->tracks[i].src_track;
+ mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
+ mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
+ //src_trk may have a different timescale than the tmcd track
+ mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
+ mov->tracks[i].timescale,
+ mov->tracks[src_trk].timescale);
+ }
+ }
mov_write_mvhd_tag(pb, mov);
if (mov->mode != MODE_MOV && !mov->iods_skip)
mov_write_iods_tag(pb, mov);
for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT) {
- mov_write_trak_tag(pb, mov, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
+ int ret = mov_write_trak_tag(pb, mov, &(mov->tracks[i]), i < s->nb_streams ? s->streams[i] : NULL);
+ if (ret < 0)
+ return ret;
}
}
if (mov->flags & FF_MOV_FLAG_FRAGMENT)
@@ -2333,7 +3257,7 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov)
{
int64_t pos = avio_tell(pb);
int i;
- const uint8_t uuid[] = {
+ static const uint8_t uuid[] = {
0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
};
@@ -2346,7 +3270,8 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov)
avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
avio_printf(pb, "<head>\n");
- avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
+ if (!mov->exact)
+ avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
LIBAVFORMAT_IDENT);
avio_printf(pb, "</head>\n");
avio_printf(pb, "<body>\n");
@@ -2546,7 +3471,7 @@ static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
{
int64_t pos = avio_tell(pb);
- const uint8_t uuid[] = {
+ static const uint8_t uuid[] = {
0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
};
@@ -2569,7 +3494,7 @@ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
{
int n = track->nb_frag_info - 1 - entry, i;
int size = 8 + 16 + 4 + 1 + 16*n;
- const uint8_t uuid[] = {
+ static const uint8_t uuid[] = {
0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
};
@@ -2593,8 +3518,7 @@ static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
int free_size = 16 * (mov->ism_lookahead - n);
avio_wb32(pb, free_size);
ffio_wfourcc(pb, "free");
- for (i = 0; i < free_size - 8; i++)
- avio_w8(pb, 0);
+ ffio_fill(pb, 0, free_size - 8);
}
return 0;
@@ -3046,9 +3970,22 @@ static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
{
MOVMuxContext *mov = s->priv_data;
+ int i;
+
mov_write_ftyp_tag(pb,s);
if (mov->mode == MODE_PSP) {
- if (s->nb_streams != 2) {
+ int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ video_streams_nb++;
+ else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ audio_streams_nb++;
+ else
+ other_streams_nb++;
+ }
+
+ if (video_streams_nb != 1 || audio_streams_nb != 1 || other_streams_nb) {
av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
return AVERROR(EINVAL);
}
@@ -3169,6 +4106,7 @@ static int mov_flush_fragment(AVFormatContext *s)
MOVMuxContext *mov = s->priv_data;
int i, first_track = -1;
int64_t mdat_size = 0;
+ int ret;
if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
return 0;
@@ -3202,10 +4140,8 @@ static int mov_flush_fragment(AVFormatContext *s)
if (!mov->moov_written) {
int64_t pos = avio_tell(s->pb);
- int ret;
- AVIOContext *moov_buf;
uint8_t *buf;
- int buf_size;
+ int buf_size, moov_size;
for (i = 0; i < mov->nb_streams; i++)
if (!mov->tracks[i].entry)
@@ -3214,16 +4150,14 @@ static int mov_flush_fragment(AVFormatContext *s)
if (i < mov->nb_streams)
return 0;
- if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
- return ret;
- mov_write_moov_tag(moov_buf, mov, s);
- buf_size = ffio_close_null_buf(moov_buf);
+ moov_size = get_moov_size(s);
for (i = 0; i < mov->nb_streams; i++)
- mov->tracks[i].data_offset = pos + buf_size + 8;
+ mov->tracks[i].data_offset = pos + moov_size + 8;
if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
mov_write_identification(s->pb, s);
- mov_write_moov_tag(s->pb, mov, s);
+ if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
+ return ret;
if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
if (mov->flags & FF_MOV_FLAG_FASTSTART)
@@ -3361,6 +4295,21 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
int size = pkt->size, ret = 0;
uint8_t *reformatted_data = NULL;
+ if (trk->entry) {
+ int64_t duration = pkt->dts - trk->cluster[trk->entry - 1].dts;
+ if (duration < 0 || duration > INT_MAX) {
+ av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" / timestamp: %"PRId64" is out of range for mov/mp4 format\n",
+ duration, pkt->dts
+ );
+
+ pkt->dts = trk->cluster[trk->entry - 1].dts + 1;
+ pkt->pts = AV_NOPTS_VALUE;
+ }
+ if (pkt->duration < 0) {
+ av_log(s, AV_LOG_ERROR, "Application provided duration: %d is invalid\n", pkt->duration);
+ return AVERROR(EINVAL);
+ }
+ }
if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
int ret;
if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
@@ -3399,13 +4348,18 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
return -1;
}
+ } else if (enc->codec_id == AV_CODEC_ID_ADPCM_MS ||
+ enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
+ samples_in_chunk = enc->frame_size;
} else if (trk->sample_size)
samples_in_chunk = size / trk->sample_size;
else
samples_in_chunk = 1;
/* copy extradata if it exists */
- if (trk->vos_len == 0 && enc->extradata_size > 0) {
+ if (trk->vos_len == 0 && enc->extradata_size > 0 &&
+ !TAG_IS_AVCI(trk->tag) &&
+ (enc->codec_id != AV_CODEC_ID_DNXHD)) {
trk->vos_len = enc->extradata_size;
trk->vos_data = av_malloc(trk->vos_len);
if (!trk->vos_data) {
@@ -3415,7 +4369,17 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(trk->vos_data, enc->extradata, trk->vos_len);
}
- if (enc->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1) {
+ if (enc->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
+ (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
+ if (!s->streams[pkt->stream_index]->nb_frames) {
+ av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
+ "use the audio bitstream filter 'aac_adtstoasc' to fix it "
+ "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
+ return -1;
+ }
+ av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
+ }
+ if (enc->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1 && !TAG_IS_AVCI(trk->tag)) {
/* from x264 or from bytestream h264 */
/* nal reformating needed */
if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) {
@@ -3434,6 +4398,15 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
} else {
size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
}
+#if CONFIG_AC3_PARSER
+ } else if (enc->codec_id == AV_CODEC_ID_EAC3) {
+ size = handle_eac3(mov, pkt, trk);
+ if (size < 0)
+ return size;
+ else if (!size)
+ goto end;
+ avio_write(pb, pkt->data, size);
+#endif
} else {
avio_write(pb, pkt->data, size);
}
@@ -3462,6 +4435,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
trk->cluster[trk->entry].pos = avio_tell(pb) - size;
trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
+ trk->cluster[trk->entry].chunkNum = 0;
trk->cluster[trk->entry].size = size;
trk->cluster[trk->entry].entries = samples_in_chunk;
trk->cluster[trk->entry].dts = pkt->dts;
@@ -3488,6 +4462,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
trk->frag_discont = 0;
}
}
+
if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
/* Not using edit lists and shifting the first track to start from zero.
@@ -3513,6 +4488,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
pkt->stream_index, pkt->dts);
}
trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
+ trk->last_sample_is_subtitle_end = 0;
if (pkt->pts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_WARNING, "pts has no value\n");
@@ -3554,17 +4530,15 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
reformatted_data, size);
+end:
err:
+
av_free(reformatted_data);
return ret;
}
-static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
+static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
{
- if (!pkt) {
- mov_flush_fragment(s);
- return 1;
- } else {
MOVMuxContext *mov = s->priv_data;
MOVTrack *trk = &mov->tracks[pkt->stream_index];
AVCodecContext *enc = trk->enc;
@@ -3581,7 +4555,7 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
}
- if (trk->entry)
+ if (trk->entry && pkt->stream_index < s->nb_streams)
frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
s->streams[pkt->stream_index]->time_base,
AV_TIME_BASE_Q);
@@ -3603,6 +4577,73 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
}
return ff_mov_write_packet(s, pkt);
+}
+
+static int mov_write_subtitle_end_packet(AVFormatContext *s,
+ int stream_index,
+ int64_t dts) {
+ AVPacket end;
+ uint8_t data[2] = {0};
+ int ret;
+
+ av_init_packet(&end);
+ end.size = sizeof(data);
+ end.data = data;
+ end.pts = dts;
+ end.dts = dts;
+ end.duration = 0;
+ end.stream_index = stream_index;
+
+ ret = mov_write_single_packet(s, &end);
+ av_free_packet(&end);
+
+ return ret;
+}
+
+static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ if (!pkt) {
+ mov_flush_fragment(s);
+ return 1;
+ } else {
+ int i;
+ MOVMuxContext *mov = s->priv_data;
+
+ if (!pkt->size) return 0; /* Discard 0 sized packets */
+
+ /*
+ * Subtitles require special handling.
+ *
+ * 1) For full complaince, every track must have a sample at
+ * dts == 0, which is rarely true for subtitles. So, as soon
+ * as we see any packet with dts > 0, write an empty subtitle
+ * at dts == 0 for any subtitle track with no samples in it.
+ *
+ * 2) For each subtitle track, check if the current packet's
+ * dts is past the duration of the last subtitle sample. If
+ * so, we now need to write an end sample for that subtitle.
+ *
+ * This must be done conditionally to allow for subtitles that
+ * immediately replace each other, in which case an end sample
+ * is not needed, and is, in fact, actively harmful.
+ *
+ * 3) See mov_write_trailer for how the final end sample is
+ * handled.
+ */
+ for (i = 0; i < mov->nb_streams; i++) {
+ MOVTrack *trk = &mov->tracks[i];
+ int ret;
+
+ if (trk->enc->codec_id == AV_CODEC_ID_MOV_TEXT &&
+ trk->track_duration < pkt->dts &&
+ (trk->entry == 0 || !trk->last_sample_is_subtitle_end)) {
+ ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
+ if (ret < 0) return ret;
+ trk->last_sample_is_subtitle_end = 1;
+ }
+ }
+
+ return mov_write_single_packet(s, pkt);
}
}
@@ -3610,12 +4651,12 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
// as samples, and a tref pointing from the other tracks to the chapter one.
static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
{
+ AVIOContext *pb;
+
MOVMuxContext *mov = s->priv_data;
MOVTrack *track = &mov->tracks[tracknum];
AVPacket pkt = { .stream_index = tracknum, .flags = AV_PKT_FLAG_KEY };
int i, len;
- // These properties are required to make QT recognize the chapter track
- uint8_t chapter_properties[43] = { 0, 0, 0, 0, 0, 0, 0, 1, };
track->mode = mov->mode;
track->tag = MKTAG('t','e','x','t');
@@ -3624,11 +4665,57 @@ static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
if (!track->enc)
return AVERROR(ENOMEM);
track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE;
- track->enc->extradata = av_malloc(sizeof(chapter_properties));
- if (!track->enc->extradata)
+#if 0
+ // These properties are required to make QT recognize the chapter track
+ uint8_t chapter_properties[43] = { 0, 0, 0, 0, 0, 0, 0, 1, };
+ if (ff_alloc_extradata(track->enc, sizeof(chapter_properties)))
return AVERROR(ENOMEM);
- track->enc->extradata_size = sizeof(chapter_properties);
memcpy(track->enc->extradata, chapter_properties, sizeof(chapter_properties));
+#else
+ if (avio_open_dyn_buf(&pb) >= 0) {
+ int size;
+ uint8_t *buf;
+
+ /* Stub header (usually for Quicktime chapter track) */
+ // TextSampleEntry
+ avio_wb32(pb, 0x01); // displayFlags
+ avio_w8(pb, 0x00); // horizontal justification
+ avio_w8(pb, 0x00); // vertical justification
+ avio_w8(pb, 0x00); // bgColourRed
+ avio_w8(pb, 0x00); // bgColourGreen
+ avio_w8(pb, 0x00); // bgColourBlue
+ avio_w8(pb, 0x00); // bgColourAlpha
+ // BoxRecord
+ avio_wb16(pb, 0x00); // defTextBoxTop
+ avio_wb16(pb, 0x00); // defTextBoxLeft
+ avio_wb16(pb, 0x00); // defTextBoxBottom
+ avio_wb16(pb, 0x00); // defTextBoxRight
+ // StyleRecord
+ avio_wb16(pb, 0x00); // startChar
+ avio_wb16(pb, 0x00); // endChar
+ avio_wb16(pb, 0x01); // fontID
+ avio_w8(pb, 0x00); // fontStyleFlags
+ avio_w8(pb, 0x00); // fontSize
+ avio_w8(pb, 0x00); // fgColourRed
+ avio_w8(pb, 0x00); // fgColourGreen
+ avio_w8(pb, 0x00); // fgColourBlue
+ avio_w8(pb, 0x00); // fgColourAlpha
+ // FontTableBox
+ avio_wb32(pb, 0x0D); // box size
+ ffio_wfourcc(pb, "ftab"); // box atom name
+ avio_wb16(pb, 0x01); // entry count
+ // FontRecord
+ avio_wb16(pb, 0x01); // font ID
+ avio_w8(pb, 0x00); // font name length
+
+ if ((size = avio_close_dyn_buf(pb, &buf)) > 0) {
+ track->enc->extradata = buf;
+ track->enc->extradata_size = size;
+ } else {
+ av_freep(&buf);
+ }
+ }
+#endif
for (i = 0; i < s->nb_chapters; i++) {
AVChapter *c = s->chapters[i];
@@ -3659,6 +4746,50 @@ static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
return 0;
}
+static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, const char *tcstr)
+{
+ int ret;
+ MOVMuxContext *mov = s->priv_data;
+ MOVTrack *track = &mov->tracks[index];
+ AVStream *src_st = s->streams[src_index];
+ AVTimecode tc;
+ AVPacket pkt = {.stream_index = index, .flags = AV_PKT_FLAG_KEY, .size = 4};
+ AVRational rate = find_fps(s, src_st);
+
+ /* compute the frame number */
+ ret = av_timecode_init_from_string(&tc, rate, tcstr, s);
+ if (ret < 0)
+ return ret;
+
+ /* tmcd track based on video stream */
+ track->mode = mov->mode;
+ track->tag = MKTAG('t','m','c','d');
+ track->src_track = src_index;
+ track->timescale = mov->tracks[src_index].timescale;
+ if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
+ track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
+
+ /* set st to src_st for metadata access*/
+ track->st = src_st;
+
+ /* encode context: tmcd data stream */
+ track->enc = avcodec_alloc_context3(NULL);
+ if (!track->enc)
+ return AVERROR(ENOMEM);
+ track->enc->codec_type = AVMEDIA_TYPE_DATA;
+ track->enc->codec_tag = track->tag;
+ track->enc->time_base = av_inv_q(rate);
+
+ /* the tmcd track just contains one packet with the frame number */
+ pkt.data = av_malloc(pkt.size);
+ if (!pkt.data)
+ return AVERROR(ENOMEM);
+ AV_WB32(pkt.data, tc.start);
+ ret = ff_mov_write_packet(s, &pkt);
+ av_free(pkt.data);
+ return ret;
+}
+
/*
* st->disposition controls the "enabled" flag in the tkhd tag.
* QuickTime will not play a track if it is not enabled. So make sure
@@ -3718,18 +4849,20 @@ static void mov_free(AVFormatContext *s)
if (mov->chapter_track) {
if (mov->tracks[mov->chapter_track].enc)
- av_free(mov->tracks[mov->chapter_track].enc->extradata);
+ av_freep(&mov->tracks[mov->chapter_track].enc->extradata);
av_freep(&mov->tracks[mov->chapter_track].enc);
}
for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].tag == MKTAG('r','t','p',' '))
ff_mov_close_hinting(&mov->tracks[i]);
+ else if (mov->tracks[i].tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
+ av_freep(&mov->tracks[i].enc);
av_freep(&mov->tracks[i].cluster);
av_freep(&mov->tracks[i].frag_info);
if (mov->tracks[i].vos_len)
- av_free(mov->tracks[i].vos_data);
+ av_freep(&mov->tracks[i].vos_data);
}
av_freep(&mov->tracks);
@@ -3744,9 +4877,9 @@ static uint32_t rgb_to_yuv(uint32_t rgb)
g = (rgb >> 8) & 0xFF;
b = (rgb ) & 0xFF;
- y = av_clip_uint8( 16. + 0.257 * r + 0.504 * g + 0.098 * b);
- cb = av_clip_uint8(128. - 0.148 * r - 0.291 * g + 0.439 * b);
- cr = av_clip_uint8(128. + 0.439 * r - 0.368 * g - 0.071 * b);
+ y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
+ cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
+ cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
return (y << 16) | (cr << 8) | cb;
}
@@ -3804,8 +4937,8 @@ static int mov_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
MOVMuxContext *mov = s->priv_data;
- AVDictionaryEntry *t;
- int i, ret, hint_track = 0;
+ AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+ int i, ret, hint_track = 0, tmcd_track = 0;
mov->fc = s;
@@ -3822,6 +4955,9 @@ static int mov_write_header(AVFormatContext *s)
else if (!strcmp("f4v", s->oformat->name)) mov->mode = MODE_F4V;
}
+ if (s->flags & AVFMT_FLAG_BITEXACT)
+ mov->exact = 1;
+
if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
@@ -3841,6 +4977,10 @@ static int mov_write_header(AVFormatContext *s)
mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
FF_MOV_FLAG_DEFAULT_BASE_MOOF;
+ if (mov->flags & FF_MOV_FLAG_FASTSTART) {
+ mov->reserved_moov_size = -1;
+ }
+
if (mov->use_editlist < 0) {
mov->use_editlist = 1;
if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
@@ -3883,7 +5023,6 @@ static int mov_write_header(AVFormatContext *s)
return AVERROR(EINVAL);
}
-
if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
if ((ret = mov_write_identification(pb, s)) < 0)
return ret;
@@ -3905,9 +5044,35 @@ static int mov_write_header(AVFormatContext *s)
}
}
+ if (mov->mode == MODE_MOV) {
+ tmcd_track = mov->nb_streams;
+
+ /* +1 tmcd track for each video stream with a timecode */
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ (global_tcr || av_dict_get(st->metadata, "timecode", NULL, 0)))
+ mov->nb_meta_tmcd++;
+ }
+
+ /* check if there is already a tmcd track to remux */
+ if (mov->nb_meta_tmcd) {
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (st->codec->codec_tag == MKTAG('t','m','c','d')) {
+ av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
+ "so timecode metadata are now ignored\n");
+ mov->nb_meta_tmcd = 0;
+ }
+ }
+ }
+
+ mov->nb_streams += mov->nb_meta_tmcd;
+ }
+
// Reserve an extra stream for chapters for the case where chapters
// are written in the trailer
- mov->tracks = av_mallocz((mov->nb_streams + 1) * sizeof(*mov->tracks));
+ mov->tracks = av_mallocz_array((mov->nb_streams + 1), sizeof(*mov->tracks));
if (!mov->tracks)
return AVERROR(ENOMEM);
@@ -3924,8 +5089,10 @@ static int mov_write_header(AVFormatContext *s)
track->mode = mov->mode;
track->tag = mov_find_codec_tag(s, track);
if (!track->tag) {
- av_log(s, AV_LOG_ERROR, "track %d: could not find tag, "
- "codec not currently supported in container\n", i);
+ av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
+ "codec not currently supported in container\n",
+ avcodec_get_name(st->codec->codec_id), i);
+ ret = AVERROR(EINVAL);
goto error;
}
/* If hinting of this track is enabled by a later hint track,
@@ -3940,11 +5107,23 @@ static int mov_write_header(AVFormatContext *s)
track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
if (st->codec->width != 720 || (st->codec->height != 608 && st->codec->height != 512)) {
av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
+ ret = AVERROR(EINVAL);
goto error;
}
track->height = track->tag >> 24 == 'n' ? 486 : 576;
}
- track->timescale = st->time_base.den;
+ if (mov->video_track_timescale) {
+ track->timescale = mov->video_track_timescale;
+ } else {
+ track->timescale = st->time_base.den;
+ while(track->timescale < 10000)
+ track->timescale *= 2;
+ }
+ if (st->codec->width > 65535 || st->codec->height > 65535) {
+ av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codec->width, st->codec->height);
+ ret = AVERROR(EINVAL);
+ goto error;
+ }
if (track->mode == MODE_MOV && track->timescale > 100000)
av_log(s, AV_LOG_WARNING,
"WARNING codec timebase is very high. If duration is too long,\n"
@@ -3952,29 +5131,40 @@ static int mov_write_header(AVFormatContext *s)
"or choose different container.\n");
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
track->timescale = st->codec->sample_rate;
- /* set sample_size for PCM and ADPCM */
- if (av_get_bits_per_sample(st->codec->codec_id) ||
- st->codec->codec_id == AV_CODEC_ID_ILBC) {
+ if (!st->codec->frame_size && !av_get_bits_per_sample(st->codec->codec_id)) {
+ av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
+ track->audio_vbr = 1;
+ }else if (st->codec->codec_id == AV_CODEC_ID_ADPCM_MS ||
+ st->codec->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
+ st->codec->codec_id == AV_CODEC_ID_ILBC){
if (!st->codec->block_align) {
- av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set\n", i);
+ av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
+ ret = AVERROR(EINVAL);
goto error;
}
track->sample_size = st->codec->block_align;
+ }else if (st->codec->frame_size > 1){ /* assume compressed audio */
+ track->audio_vbr = 1;
+ }else{
+ track->sample_size = (av_get_bits_per_sample(st->codec->codec_id) >> 3) * st->codec->channels;
}
- /* set audio_vbr for compressed audio */
- if (av_get_bits_per_sample(st->codec->codec_id) < 8) {
+ if (st->codec->codec_id == AV_CODEC_ID_ILBC ||
+ st->codec->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
track->audio_vbr = 1;
}
if (track->mode != MODE_MOV &&
track->enc->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n",
i, track->enc->sample_rate);
+ ret = AVERROR(EINVAL);
goto error;
}
} else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
track->timescale = st->time_base.den;
} else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) {
track->timescale = st->time_base.den;
+ } else {
+ track->timescale = MOV_TIMESCALE;
}
if (!track->height)
track->height = st->codec->height;
@@ -3989,18 +5179,52 @@ static int mov_write_header(AVFormatContext *s)
if (st->codec->extradata_size) {
if (st->codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
mov_create_dvd_sub_decoder_specific_info(track, st);
- else {
+ else if (!TAG_IS_AVCI(track->tag) && st->codec->codec_id != AV_CODEC_ID_DNXHD) {
track->vos_len = st->codec->extradata_size;
track->vos_data = av_malloc(track->vos_len);
- if (!track->vos_data)
+ if (!track->vos_data) {
+ ret = AVERROR(ENOMEM);
goto error;
+ }
memcpy(track->vos_data, st->codec->extradata, track->vos_len);
}
}
}
+ for (i = 0; i < s->nb_streams; i++) {
+ int j;
+ AVStream *st= s->streams[i];
+ MOVTrack *track= &mov->tracks[i];
+
+ if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO ||
+ track->enc->channel_layout != AV_CH_LAYOUT_MONO)
+ continue;
+
+ for (j = 0; j < s->nb_streams; j++) {
+ AVStream *stj= s->streams[j];
+ MOVTrack *trackj= &mov->tracks[j];
+ if (j == i)
+ continue;
+
+ if (stj->codec->codec_type != AVMEDIA_TYPE_AUDIO ||
+ trackj->enc->channel_layout != AV_CH_LAYOUT_MONO ||
+ trackj->language != track->language ||
+ trackj->tag != track->tag
+ )
+ continue;
+ track->multichannel_as_mono++;
+ }
+ }
+
enable_tracks(s);
+
+ if (mov->reserved_moov_size){
+ mov->reserved_moov_pos= avio_tell(pb);
+ if (mov->reserved_moov_size > 0)
+ avio_skip(pb, mov->reserved_moov_size);
+ }
+
if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
/* If no fragmentation options have been set, set a default. */
if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
@@ -4019,7 +5243,7 @@ static int mov_write_header(AVFormatContext *s)
mov->time += 0x7C25B080; // 1970 based -> 1904 based
if (mov->chapter_track)
- if (mov_create_chapter_track(s, mov->chapter_track) < 0)
+ if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
goto error;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
@@ -4028,12 +5252,31 @@ static int mov_write_header(AVFormatContext *s)
AVStream *st = s->streams[i];
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- ff_mov_init_hinting(s, hint_track, i);
+ if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
+ goto error;
hint_track++;
}
}
}
+ if (mov->nb_meta_tmcd) {
+ /* Initialize the tmcd tracks */
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ t = global_tcr;
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (!t)
+ t = av_dict_get(st->metadata, "timecode", NULL, 0);
+ if (!t)
+ continue;
+ if ((ret = mov_create_timecode_track(s, tmcd_track, i, t->value)) < 0)
+ goto error;
+ tmcd_track++;
+ }
+ }
+ }
+
avio_flush(pb);
if (mov->flags & FF_MOV_FLAG_ISML)
@@ -4041,7 +5284,8 @@ static int mov_write_header(AVFormatContext *s)
if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
- mov_write_moov_tag(pb, mov, s);
+ if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
+ return ret;
mov->moov_written = 1;
if (mov->flags & FF_MOV_FLAG_FASTSTART)
mov->reserved_moov_pos = avio_tell(pb);
@@ -4050,7 +5294,7 @@ static int mov_write_header(AVFormatContext *s)
return 0;
error:
mov_free(s);
- return -1;
+ return ret;
}
static int get_moov_size(AVFormatContext *s)
@@ -4061,7 +5305,8 @@ static int get_moov_size(AVFormatContext *s)
if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
return ret;
- mov_write_moov_tag(moov_buf, mov, s);
+ if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
+ return ret;
return ffio_close_null_buf(moov_buf);
}
@@ -4197,6 +5442,19 @@ static int mov_write_trailer(AVFormatContext *s)
int i;
int64_t moov_pos;
+ /*
+ * Before actually writing the trailer, make sure that there are no
+ * dangling subtitles, that need a terminating sample.
+ */
+ for (i = 0; i < mov->nb_streams; i++) {
+ MOVTrack *trk = &mov->tracks[i];
+ if (trk->enc->codec_id == AV_CODEC_ID_MOV_TEXT &&
+ !trk->last_sample_is_subtitle_end) {
+ mov_write_subtitle_end_packet(s, i, trk->track_duration);
+ trk->last_sample_is_subtitle_end = 1;
+ }
+ }
+
// If there were no chapters when the header was written, but there
// are chapters now, write them in the trailer. This only works
// when we are not doing fragments.
@@ -4224,18 +5482,35 @@ static int mov_write_trailer(AVFormatContext *s)
ffio_wfourcc(pb, "mdat");
avio_wb64(pb, mov->mdat_size + 16);
}
- avio_seek(pb, moov_pos, SEEK_SET);
+ avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_moov_pos : moov_pos, SEEK_SET);
if (mov->flags & FF_MOV_FLAG_FASTSTART) {
av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
res = shift_data(s);
if (res == 0) {
avio_seek(pb, mov->reserved_moov_pos, SEEK_SET);
- mov_write_moov_tag(pb, mov, s);
+ if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
+ goto error;
+ }
+ } else if (mov->reserved_moov_size > 0) {
+ int64_t size;
+ if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
+ goto error;
+ size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos);
+ if (size < 8){
+ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
+ res = AVERROR(EINVAL);
+ goto error;
}
+ avio_wb32(pb, size);
+ ffio_wfourcc(pb, "free");
+ ffio_fill(pb, 0, size - 8);
+ avio_seek(pb, moov_pos, SEEK_SET);
} else {
- mov_write_moov_tag(pb, mov, s);
+ if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
+ goto error;
}
+ res = 0;
} else {
mov_auto_flush_fragment(s);
for (i = 0; i < mov->nb_streams; i++)
@@ -4401,7 +5676,7 @@ AVOutputFormat ff_f4v_muxer = {
.write_header = mov_write_header,
.write_packet = mov_write_packet,
.write_trailer = mov_write_trailer,
- .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
+ .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
.priv_class = &f4v_muxer_class,
};
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index a61cfad273..744d14e5b2 100644
--- a/libavformat/movenc.h
+++ b/libavformat/movenc.h
@@ -4,20 +4,20 @@
* Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,7 +36,7 @@
#define MODE_MOV 0x02
#define MODE_3GP 0x04
#define MODE_PSP 0x08 // example working PSP command line:
-// avconv -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
+// ffmpeg -i testinput.avi -f psp -r 14.985 -s 320x240 -b 768 -ar 24000 -ab 32 M4V00001.MP4
#define MODE_3G2 0x10
#define MODE_IPOD 0x20
#define MODE_ISM 0x40
@@ -47,6 +47,7 @@ typedef struct MOVIentry {
int64_t dts;
unsigned int size;
unsigned int samples_in_chunk;
+ unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 0
unsigned int entries;
int cts;
#define MOV_SYNC_SAMPLE 0x0001
@@ -82,18 +83,25 @@ typedef struct MOVTrack {
unsigned timescale;
uint64_t time;
int64_t track_duration;
+ int last_sample_is_subtitle_end;
long sample_count;
long sample_size;
+ long chunkCount;
int has_keyframes;
#define MOV_TRACK_CTTS 0x0001
#define MOV_TRACK_STPS 0x0002
#define MOV_TRACK_ENABLED 0x0004
uint32_t flags;
+#define MOV_TIMECODE_FLAG_DROPFRAME 0x0001
+#define MOV_TIMECODE_FLAG_24HOURSMAX 0x0002
+#define MOV_TIMECODE_FLAG_ALLOWNEGATIVE 0x0004
+ uint32_t timecode_flags;
int language;
int track_id;
int tag; ///< stsd fourcc
AVStream *st;
AVCodecContext *enc;
+ int multichannel_as_mono;
int vos_len;
uint8_t *vos_data;
@@ -108,7 +116,7 @@ typedef struct MOVTrack {
int64_t end_pts;
int hint_track; ///< the track that hints this track, -1 if no hint track is set
- int src_track; ///< the track that this hint track describes
+ int src_track; ///< the track that this hint (or tmcd) track describes
AVFormatContext *rtp_ctx; ///< the format context for the hinting rtp muxer
uint32_t prev_rtp_ts;
int64_t cur_rtp_ts_unwrapped;
@@ -139,6 +147,8 @@ typedef struct MOVTrack {
int packet_entry;
int slices;
} vc1_info;
+
+ void *eac3_priv;
} MOVTrack;
typedef struct MOVMuxContext {
@@ -146,6 +156,7 @@ typedef struct MOVMuxContext {
int mode;
int64_t time;
int nb_streams;
+ int nb_meta_tmcd; ///< number of new created tmcd track based on metadata (aka not data copy)
int chapter_track; ///< qt chapter track number
int64_t mdat_pos;
uint64_t mdat_size;
@@ -153,6 +164,8 @@ typedef struct MOVMuxContext {
int flags;
int rtp_flags;
+ int exact;
+
int iods_skip;
int iods_video_profile;
int iods_audio_profile;
@@ -166,6 +179,9 @@ typedef struct MOVMuxContext {
AVIOContext *mdat_buf;
int first_trun;
+ int video_track_timescale;
+
+ int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise
int64_t reserved_moov_pos;
char *major_brand;
@@ -174,6 +190,8 @@ typedef struct MOVMuxContext {
AVFormatContext *fc;
int use_editlist;
+ float gamma;
+
int frag_interleave;
int missing_duration_warned;
} MOVMuxContext;
@@ -192,6 +210,8 @@ typedef struct MOVMuxContext {
#define FF_MOV_FLAG_DASH (1 << 11)
#define FF_MOV_FLAG_FRAG_DISCONT (1 << 12)
#define FF_MOV_FLAG_DELAY_MOOV (1 << 13)
+#define FF_MOV_FLAG_WRITE_COLR (1 << 14)
+#define FF_MOV_FLAG_WRITE_GAMA (1 << 15)
int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
diff --git a/libavformat/movenchint.c b/libavformat/movenchint.c
index 73498e4547..9e667edce4 100644
--- a/libavformat/movenchint.c
+++ b/libavformat/movenchint.c
@@ -2,20 +2,20 @@
* MOV, 3GP, MP4 muxer RTP hinting
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,7 +72,7 @@ static void sample_queue_pop(HintSampleQueue *queue)
if (queue->len <= 0)
return;
if (queue->samples[0].own_data)
- av_free(queue->samples[0].data);
+ av_freep(&queue->samples[0].data);
queue->len--;
memmove(queue->samples, queue->samples + 1, sizeof(HintSample)*queue->len);
}
@@ -85,7 +85,7 @@ static void sample_queue_free(HintSampleQueue *queue)
int i;
for (i = 0; i < queue->len; i++)
if (queue->samples[i].own_data)
- av_free(queue->samples[i].data);
+ av_freep(&queue->samples[i].data);
av_freep(&queue->samples);
queue->len = 0;
queue->size = 0;
@@ -104,11 +104,12 @@ static void sample_queue_push(HintSampleQueue *queue, uint8_t *data, int size,
if (size <= 14)
return;
if (!queue->samples || queue->len >= queue->size) {
- queue->size += 10;
- if (av_reallocp(&queue->samples, sizeof(*queue->samples) * queue->size) < 0) {
- queue->len = queue->size = 0;
+ HintSample *samples;
+ samples = av_realloc_array(queue->samples, queue->size + 10, sizeof(HintSample));
+ if (!samples)
return;
- }
+ queue->size += 10;
+ queue->samples = samples;
}
queue->samples[queue->len].data = data;
queue->samples[queue->len].size = size;
@@ -421,7 +422,7 @@ int ff_mov_add_hinted_packet(AVFormatContext *s, AVPacket *pkt,
sample_queue_push(&trk->sample_queue, pkt->data, pkt->size, sample);
/* Feed the packet to the RTP muxer */
- ff_write_chained(rtp_ctx, 0, pkt, s);
+ ff_write_chained(rtp_ctx, 0, pkt, s, 0);
/* Fetch the output from the RTP muxer, open a new output buffer
* for next time. */
diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c
index cba67783f9..abd7fc0bd3 100644
--- a/libavformat/mp3dec.c
+++ b/libavformat/mp3dec.c
@@ -2,23 +2,24 @@
* MP3 demuxer
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/crc.h"
@@ -41,10 +42,15 @@
#define XING_TOC_COUNT 100
-typedef struct MP3DecContext {
+typedef struct {
+ AVClass *class;
+ int64_t filesize;
int xing_toc;
+ int start_pad;
+ int end_pad;
+ int usetoc;
unsigned frames; /* Total number of frames in file */
- unsigned size; /* Total number of bytes in the stream */
+ unsigned header_filesize; /* Total number of bytes in the stream */
int is_cbr;
} MP3DecContext;
@@ -53,9 +59,9 @@ typedef struct MP3DecContext {
static int mp3_read_probe(AVProbeData *p)
{
int max_frames, first_frames = 0;
- int fsize, frames, sample_rate;
+ int fsize, frames;
uint32_t header;
- uint8_t *buf, *buf0, *buf2, *end;
+ const uint8_t *buf, *buf0, *buf2, *end;
AVCodecContext *avctx = avcodec_alloc_context3(NULL);
if (!avctx)
@@ -71,12 +77,14 @@ static int mp3_read_probe(AVProbeData *p)
for(; buf < end; buf= buf2+1) {
buf2 = buf;
+ if(ff_mpa_check_header(AV_RB32(buf2)))
+ continue;
for(frames = 0; buf2 < end; frames++) {
+ int dummy;
header = AV_RB32(buf2);
- fsize = avpriv_mpa_decode_header(avctx, header, &sample_rate,
- &sample_rate, &sample_rate,
- &sample_rate);
+ fsize = avpriv_mpa_decode_header(avctx, header,
+ &dummy, &dummy, &dummy, &dummy);
if(fsize < 0)
break;
buf2 += fsize;
@@ -88,34 +96,13 @@ static int mp3_read_probe(AVProbeData *p)
avcodec_free_context(&avctx);
// keep this in sync with ac3 probe, both need to avoid
// issues with MPEG-files!
- if (first_frames >= 10)
- return AVPROBE_SCORE_EXTENSION + 5;
- if (first_frames >= 4)
- return AVPROBE_SCORE_EXTENSION + 1;
-
- if (max_frames) {
- int pes = 0, i;
- unsigned int code = -1;
-
-#define VIDEO_ID 0x000001e0
-#define AUDIO_ID 0x000001c0
- /* do a search for mpegps headers to be able to properly bias
- * towards mpegps if we detect this stream as both. */
- for (i = 0; i<p->buf_size; i++) {
- code = (code << 8) + p->buf[i];
- if ((code & 0xffffff00) == 0x100) {
- if ((code & 0x1f0) == VIDEO_ID) pes++;
- else if((code & 0x1e0) == AUDIO_ID) pes++;
- }
- }
-
- if (pes)
- max_frames = (max_frames + pes - 1) / pes;
- }
- if (max_frames > 500) return AVPROBE_SCORE_EXTENSION;
- else if (max_frames >= 4) return AVPROBE_SCORE_EXTENSION / 2;
- else if (max_frames >= 1) return 1;
- else return 0;
+ if (first_frames>=4) return AVPROBE_SCORE_EXTENSION + 1;
+ else if(max_frames>200)return AVPROBE_SCORE_EXTENSION;
+ else if(max_frames>=4 && max_frames >= p->buf_size/10000) return AVPROBE_SCORE_EXTENSION / 2;
+ else if(ff_id3v2_match(buf0, ID3v2_DEFAULT_MAGIC) && 2*ff_id3v2_tag_len(buf0) >= p->buf_size)
+ return p->buf_size < PROBE_BUF_MAX ? AVPROBE_SCORE_EXTENSION / 4 : AVPROBE_SCORE_EXTENSION - 2;
+ else if(max_frames>=1 && max_frames >= p->buf_size/10000) return 1;
+ else return 0;
//mpegps_mp3_unrecognized_format.mpg has max_frames=3
}
@@ -123,22 +110,24 @@ static void read_xing_toc(AVFormatContext *s, int64_t filesize, int64_t duration
{
int i;
MP3DecContext *mp3 = s->priv_data;
+ int fill_index = mp3->usetoc == 1 && duration > 0;
if (!filesize &&
!(filesize = avio_size(s->pb))) {
av_log(s, AV_LOG_WARNING, "Cannot determine file size, skipping TOC table.\n");
- return;
+ fill_index = 0;
}
for (i = 0; i < XING_TOC_COUNT; i++) {
uint8_t b = avio_r8(s->pb);
-
- av_add_index_entry(s->streams[0],
+ if (fill_index)
+ av_add_index_entry(s->streams[0],
av_rescale(b, filesize, 256),
av_rescale(i, duration, XING_TOC_COUNT),
0, 0, AVINDEX_KEYFRAME);
}
- mp3->xing_toc = 1;
+ if (fill_index)
+ mp3->xing_toc = 1;
}
static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st,
@@ -156,7 +145,9 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st,
int32_t r_gain = INT32_MIN, a_gain = INT32_MIN;
MP3DecContext *mp3 = s->priv_data;
- const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
+ static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
+ uint64_t fsize = avio_size(s->pb);
+ fsize = fsize >= avio_tell(s->pb) ? fsize - avio_tell(s->pb) : 0;
/* Check for Xing / Info tag */
avio_skip(s->pb, xing_offtbl[c->lsf == 1][c->nb_channels == 1]);
@@ -169,12 +160,24 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st,
if (v & XING_FLAG_FRAMES)
mp3->frames = avio_rb32(s->pb);
if (v & XING_FLAG_SIZE)
- mp3->size = avio_rb32(s->pb);
- if (v & XING_FLAG_TOC && mp3->frames)
- read_xing_toc(s, mp3->size, av_rescale_q(mp3->frames,
+ mp3->header_filesize = avio_rb32(s->pb);
+ if (fsize && mp3->header_filesize) {
+ uint64_t min, delta;
+ min = FFMIN(fsize, mp3->header_filesize);
+ delta = FFMAX(fsize, mp3->header_filesize) - min;
+ if (fsize > mp3->header_filesize && delta > min >> 4) {
+ mp3->frames = 0;
+ av_log(s, AV_LOG_WARNING,
+ "invalid concatenated file detected - using bitrate for duration\n");
+ } else if (delta > min >> 4) {
+ av_log(s, AV_LOG_WARNING,
+ "filesize and duration do not match (growing file?)\n");
+ }
+ }
+ if (v & XING_FLAG_TOC)
+ read_xing_toc(s, mp3->header_filesize, av_rescale_q(mp3->frames,
(AVRational){spf, c->sample_rate},
st->time_base));
-
/* VBR quality */
if (v & XING_FLAC_QSCALE)
avio_rb32(s->pb);
@@ -220,7 +223,25 @@ static void mp3_parse_info_tag(AVFormatContext *s, AVStream *st,
avio_r8(s->pb);
/* Encoder delays */
- avio_rb24(s->pb);
+ v= avio_rb24(s->pb);
+ if(AV_RB32(version) == MKBETAG('L', 'A', 'M', 'E')
+ || AV_RB32(version) == MKBETAG('L', 'a', 'v', 'f')
+ || AV_RB32(version) == MKBETAG('L', 'a', 'v', 'c')
+ ) {
+
+ mp3->start_pad = v>>12;
+ mp3-> end_pad = v&4095;
+ st->start_skip_samples = mp3->start_pad + 528 + 1;
+ if (mp3->frames) {
+ st->first_discard_sample = -mp3->end_pad + 528 + 1 + mp3->frames * (int64_t)spf;
+ st->last_discard_sample = mp3->frames * (int64_t)spf;
+ }
+ if (!st->start_time)
+ st->start_time = av_rescale_q(st->start_skip_samples,
+ (AVRational){1, c->sample_rate},
+ st->time_base);
+ av_log(s, AV_LOG_DEBUG, "pad %d %d\n", mp3->start_pad, mp3-> end_pad);
+ }
/* Misc */
avio_r8(s->pb);
@@ -260,7 +281,7 @@ static void mp3_parse_vbri_tag(AVFormatContext *s, AVStream *st, int64_t base)
if (avio_rb16(s->pb) == 1) {
/* skip delay and quality */
avio_skip(s->pb, 4);
- mp3->size = avio_rb32(s->pb);
+ mp3->header_filesize = avio_rb32(s->pb);
mp3->frames = avio_rb32(s->pb);
}
}
@@ -290,12 +311,12 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
spf = c.lsf ? 576 : 1152; /* Samples per frame, layer 3 */
mp3->frames = 0;
- mp3->size = 0;
+ mp3->header_filesize = 0;
mp3_parse_info_tag(s, st, &c, spf);
mp3_parse_vbri_tag(s, st, base);
- if (!mp3->frames && !mp3->size)
+ if (!mp3->frames && !mp3->header_filesize)
return -1;
/* Skip the vbr tag frame */
@@ -304,17 +325,22 @@ static int mp3_parse_vbr_tags(AVFormatContext *s, AVStream *st, int64_t base)
if (mp3->frames)
st->duration = av_rescale_q(mp3->frames, (AVRational){spf, c.sample_rate},
st->time_base);
- if (mp3->size && mp3->frames && !mp3->is_cbr)
- st->codec->bit_rate = av_rescale(mp3->size, 8 * c.sample_rate, mp3->frames * (int64_t)spf);
+ if (mp3->header_filesize && mp3->frames && !mp3->is_cbr)
+ st->codec->bit_rate = av_rescale(mp3->header_filesize, 8 * c.sample_rate, mp3->frames * (int64_t)spf);
return 0;
}
static int mp3_read_header(AVFormatContext *s)
{
+ MP3DecContext *mp3 = s->priv_data;
AVStream *st;
int64_t off;
int ret;
+ int i;
+
+ if (mp3->usetoc < 0)
+ mp3->usetoc = (s->flags & AVFMT_FLAG_FAST_SEEK) ? 0 : 2;
st = avformat_new_stream(s, NULL);
if (!st)
@@ -322,17 +348,21 @@ static int mp3_read_header(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_MP3;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
st->start_time = 0;
// lcm of all mp3 sample rates
avpriv_set_pts_info(st, 64, 1, 14112000);
+ s->pb->maxsize = -1;
off = avio_tell(s->pb);
if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
ff_id3v1_read(s);
+ if(s->pb->seekable)
+ mp3->filesize = avio_size(s->pb);
+
if (mp3_parse_vbr_tags(s, st, off) < 0)
avio_seek(s->pb, off, SEEK_SET);
@@ -340,6 +370,10 @@ static int mp3_read_header(AVFormatContext *s)
if (ret < 0)
return ret;
+ // the seek index is relative to the end of the xing vbr headers
+ for (i = 0; i < st->nb_index_entries; i++)
+ st->index_entries[i].pos += avio_tell(s->pb);
+
/* the parameters will be extracted from the compressed bitstream */
return 0;
}
@@ -348,15 +382,26 @@ static int mp3_read_header(AVFormatContext *s)
static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt)
{
- int ret;
-
- ret = av_get_packet(s->pb, pkt, MP3_PACKET_SIZE);
- if (ret < 0)
- return ret;
+ MP3DecContext *mp3 = s->priv_data;
+ int ret, size;
+ int64_t pos;
+
+ size= MP3_PACKET_SIZE;
+ pos = avio_tell(s->pb);
+ if(mp3->filesize > ID3v1_TAG_SIZE && pos < mp3->filesize)
+ size= FFMIN(size, mp3->filesize - pos);
+
+ ret= av_get_packet(s->pb, pkt, size);
+ if (ret <= 0) {
+ if(ret<0)
+ return ret;
+ return AVERROR_EOF;
+ }
+ pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
pkt->stream_index = 0;
- if (ret > ID3v1_TAG_SIZE &&
+ if (ret >= ID3v1_TAG_SIZE &&
memcmp(&pkt->data[ret - ID3v1_TAG_SIZE], "TAG", 3) == 0)
ret -= ID3v1_TAG_SIZE;
@@ -366,38 +411,114 @@ static int mp3_read_packet(AVFormatContext *s, AVPacket *pkt)
return ret;
}
+static int check(AVFormatContext *s, int64_t pos)
+{
+ int64_t ret = avio_seek(s->pb, pos, SEEK_SET);
+ unsigned header;
+ MPADecodeHeader sd;
+ if (ret < 0)
+ return ret;
+ header = avio_rb32(s->pb);
+ if (ff_mpa_check_header(header) < 0)
+ return -1;
+ if (avpriv_mpegaudio_decode_header(&sd, header) == 1)
+ return -1;
+ return sd.frame_size;
+}
+
static int mp3_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
int flags)
{
MP3DecContext *mp3 = s->priv_data;
- AVIndexEntry *ie;
+ AVIndexEntry *ie, ie1;
AVStream *st = s->streams[0];
int64_t ret = av_index_search_timestamp(st, timestamp, flags);
- uint32_t header = 0;
-
- if (!mp3->xing_toc)
- return AVERROR(ENOSYS);
+ int i, j;
+ int dir = (flags&AVSEEK_FLAG_BACKWARD) ? -1 : 1;
+ int64_t best_pos;
+ int best_score;
+
+ if (mp3->usetoc == 2)
+ return -1; // generic index code
+
+ if ( mp3->is_cbr
+ && (mp3->usetoc == 0 || !mp3->xing_toc)
+ && st->duration > 0
+ && mp3->header_filesize > s->internal->data_offset
+ && mp3->frames) {
+ ie = &ie1;
+ timestamp = av_clip64(timestamp, 0, st->duration);
+ ie->timestamp = timestamp;
+ ie->pos = av_rescale(timestamp, mp3->header_filesize, st->duration) + s->internal->data_offset;
+ } else if (mp3->xing_toc) {
+ if (ret < 0)
+ return ret;
+
+ ie = &st->index_entries[ret];
+ } else {
+ return -1;
+ }
+ avio_seek(s->pb, FFMAX(ie->pos - 4096, 0), SEEK_SET);
+ ret = avio_seek(s->pb, ie->pos, SEEK_SET);
if (ret < 0)
return ret;
- ie = &st->index_entries[ret];
- ret = avio_seek(s->pb, ie->pos, SEEK_SET);
+#define MIN_VALID 3
+ best_pos = ie->pos;
+ best_score = 999;
+ for(i=0; i<4096; i++) {
+ int64_t pos = ie->pos + (dir > 0 ? i - 1024 : -i);
+ int64_t candidate = -1;
+ int score = 999;
+
+ if (pos < 0)
+ continue;
+
+ for(j=0; j<MIN_VALID; j++) {
+ ret = check(s, pos);
+ if(ret < 0)
+ break;
+ if ((ie->pos - pos)*dir <= 0 && abs(MIN_VALID/2-j) < score) {
+ candidate = pos;
+ score = abs(MIN_VALID/2-j);
+ }
+ pos += ret;
+ }
+ if (best_score > score && j == MIN_VALID) {
+ best_pos = candidate;
+ best_score = score;
+ if(score == 0)
+ break;
+ }
+ }
+
+ ret = avio_seek(s->pb, best_pos, SEEK_SET);
if (ret < 0)
return ret;
- while (!s->pb->eof_reached) {
- header = (header << 8) + avio_r8(s->pb);
- if (ff_mpa_check_header(header) >= 0) {
- ff_update_cur_dts(s, st, ie->timestamp);
- ret = avio_seek(s->pb, -4, SEEK_CUR);
- return (ret >= 0) ? 0 : ret;
- }
+ if (mp3->is_cbr && ie == &ie1) {
+ int frame_duration = av_rescale(st->duration, 1, mp3->frames);
+ ie1.timestamp = frame_duration * av_rescale(best_pos - s->internal->data_offset, mp3->frames, mp3->header_filesize);
}
- return AVERROR_EOF;
+ ff_update_cur_dts(s, st, ie->timestamp);
+ return 0;
}
+static const AVOption options[] = {
+ { "usetoc", "use table of contents", offsetof(MP3DecContext, usetoc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, AV_OPT_FLAG_DECODING_PARAM},
+ { NULL },
+};
+
+static const AVClass demuxer_class = {
+ .class_name = "mp3",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .category = AV_CLASS_CATEGORY_DEMUXER,
+};
+
AVInputFormat ff_mp3_demuxer = {
.name = "mp3",
.long_name = NULL_IF_CONFIG_SMALL("MP2/3 (MPEG audio layer 2/3)"),
@@ -408,4 +529,5 @@ AVInputFormat ff_mp3_demuxer = {
.priv_data_size = sizeof(MP3DecContext),
.flags = AVFMT_GENERIC_INDEX,
.extensions = "mp2,mp3,m2a,mpa", /* XXX: use probe */
+ .priv_class = &demuxer_class,
};
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 9cff9d33e7..d4b6af0204 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -2,20 +2,20 @@
* MP3 muxer
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,11 +54,12 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf)
buf[0] = 'T';
buf[1] = 'A';
buf[2] = 'G';
- count += id3v1_set_string(s, "TIT2", buf + 3, 30); //title
- count += id3v1_set_string(s, "TPE1", buf + 33, 30); //author|artist
- count += id3v1_set_string(s, "TALB", buf + 63, 30); //album
- count += id3v1_set_string(s, "TDRL", buf + 93, 4); //date
- count += id3v1_set_string(s, "comment", buf + 97, 30);
+ /* we knowingly overspecify each tag length by one byte to compensate for the mandatory null byte added by av_strlcpy */
+ count += id3v1_set_string(s, "TIT2", buf + 3, 30 + 1); //title
+ count += id3v1_set_string(s, "TPE1", buf + 33, 30 + 1); //author|artist
+ count += id3v1_set_string(s, "TALB", buf + 63, 30 + 1); //album
+ count += id3v1_set_string(s, "TDRC", buf + 93, 4 + 1); //date
+ count += id3v1_set_string(s, "comment", buf + 97, 30 + 1);
if ((tag = av_dict_get(s->metadata, "TRCK", NULL, 0))) { //track
buf[125] = 0;
buf[126] = atoi(tag->value);
@@ -125,7 +126,7 @@ static const uint8_t xing_offtbl[2][2] = {{32, 17}, {17, 9}};
/*
* Write an empty XING header and initialize respective data.
*/
-static void mp3_write_xing(AVFormatContext *s)
+static int mp3_write_xing(AVFormatContext *s)
{
MP3Context *mp3 = s->priv_data;
AVCodecContext *codec = s->streams[mp3->audio_stream_idx]->codec;
@@ -135,14 +136,14 @@ static void mp3_write_xing(AVFormatContext *s)
MPADecodeHeader mpah;
int srate_idx, i, channels;
int bitrate_idx;
- int best_bitrate_idx;
+ int best_bitrate_idx = -1;
int best_bitrate_error = INT_MAX;
int ret;
int ver = 0;
- int lsf, bytes_needed;
+ int bytes_needed;
if (!s->pb->seekable || !mp3->write_xing)
- return;
+ return 0;
for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) {
const uint16_t base_freq = avpriv_mpa_freq_tab[i];
@@ -156,9 +157,8 @@ static void mp3_write_xing(AVFormatContext *s)
break;
}
if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) {
- av_log(s, AV_LOG_WARNING, "Unsupported sample rate, not writing Xing "
- "header.\n");
- return;
+ av_log(s, AV_LOG_WARNING, "Unsupported sample rate, not writing Xing header.\n");
+ return -1;
}
switch (codec->channels) {
@@ -166,35 +166,35 @@ static void mp3_write_xing(AVFormatContext *s)
case 2: channels = MPA_STEREO; break;
default: av_log(s, AV_LOG_WARNING, "Unsupported number of channels, "
"not writing Xing header.\n");
- return;
+ return -1;
}
/* dummy MPEG audio header */
- header = 0xff << 24; // sync
+ header = 0xffU << 24; // sync
header |= (0x7 << 5 | ver << 3 | 0x1 << 1 | 0x1) << 16; // sync/audio-version/layer 3/no crc*/
header |= (srate_idx << 2) << 8;
header |= channels << 6;
- lsf = !((header & (1 << 20) && header & (1 << 19)));
-
- mp3->xing_offset = xing_offtbl[ver != 3][channels == 1] + 4;
- bytes_needed = mp3->xing_offset + XING_SIZE;
-
for (bitrate_idx = 1; bitrate_idx < 15; bitrate_idx++) {
- int bit_rate = 1000 * avpriv_mpa_bitrate_tab[lsf][3 - 1][bitrate_idx];
+ int bit_rate = 1000 * avpriv_mpa_bitrate_tab[ver != 3][3 - 1][bitrate_idx];
int error = FFABS(bit_rate - codec->bit_rate);
- if (error < best_bitrate_error){
+ if (error < best_bitrate_error) {
best_bitrate_error = error;
best_bitrate_idx = bitrate_idx;
}
}
+ av_assert0(best_bitrate_idx >= 0);
- for (bitrate_idx = best_bitrate_idx; bitrate_idx < 15; bitrate_idx++) {
+ for (bitrate_idx = best_bitrate_idx; ; bitrate_idx++) {
int32_t mask = bitrate_idx << (4 + 8);
+ if (15 == bitrate_idx)
+ return -1;
header |= mask;
avpriv_mpegaudio_decode_header(&mpah, header);
+ mp3->xing_offset = xing_offtbl[mpah.lsf == 1][mpah.nb_channels == 1] + 4;
+ bytes_needed = mp3->xing_offset + XING_SIZE;
if (bytes_needed <= mpah.frame_size)
break;
@@ -204,27 +204,25 @@ static void mp3_write_xing(AVFormatContext *s)
ret = avio_open_dyn_buf(&dyn_ctx);
if (ret < 0)
- return;
+ return ret;
avio_wb32(dyn_ctx, header);
- avpriv_mpegaudio_decode_header(&mpah, header);
-
- av_assert0(mpah.frame_size >= bytes_needed);
-
ffio_fill(dyn_ctx, 0, mp3->xing_offset - 4);
ffio_wfourcc(dyn_ctx, "Xing");
avio_wb32(dyn_ctx, 0x01 | 0x02 | 0x04 | 0x08); // frames / size / TOC / vbr scale
mp3->size = mpah.frame_size;
- mp3->want = 1;
+ mp3->want=1;
+ mp3->seen=0;
+ mp3->pos=0;
avio_wb32(dyn_ctx, 0); // frames
avio_wb32(dyn_ctx, 0); // size
// TOC
for (i = 0; i < XING_TOC_SIZE; i++)
- avio_w8(dyn_ctx, 255 * i / XING_TOC_SIZE);
+ avio_w8(dyn_ctx, (uint8_t)(255 * i / XING_TOC_SIZE));
// vbr quality
// we write it, because some (broken) tools always expect it to be present
@@ -233,10 +231,15 @@ static void mp3_write_xing(AVFormatContext *s)
// encoder short version string
if (enc) {
uint8_t encoder_str[9] = { 0 };
- memcpy(encoder_str, enc->value, FFMIN(strlen(enc->value), sizeof(encoder_str)));
+ if ( strlen(enc->value) > sizeof(encoder_str)
+ && !strcmp("Lavc libmp3lame", enc->value)) {
+ memcpy(encoder_str, "Lavf lame", 9);
+ } else
+ memcpy(encoder_str, enc->value, FFMIN(strlen(enc->value), sizeof(encoder_str)));
+
avio_write(dyn_ctx, encoder_str, sizeof(encoder_str));
} else
- ffio_fill(dyn_ctx, 0, 9);
+ avio_write(dyn_ctx, "Lavf\0\0\0\0\0", 9);
avio_w8(dyn_ctx, 0); // tag revision 0 / unknown vbr method
avio_w8(dyn_ctx, 0); // unknown lowpass filter value
@@ -245,12 +248,10 @@ static void mp3_write_xing(AVFormatContext *s)
avio_w8(dyn_ctx, 0); // unknown abr/minimal bitrate
// encoder delay
- if (codec->initial_padding >= 1 << 12) {
+ if (codec->initial_padding - 528 - 1 >= 1 << 12) {
av_log(s, AV_LOG_WARNING, "Too many samples of initial padding.\n");
- avio_wb24(dyn_ctx, 0);
- } else {
- avio_wb24(dyn_ctx, codec->initial_padding << 12);
}
+ avio_wb24(dyn_ctx, FFMAX(codec->initial_padding - 528 - 1, 0)<<12);
avio_w8(dyn_ctx, 0); // misc
avio_w8(dyn_ctx, 0); // mp3gain
@@ -268,6 +269,8 @@ static void mp3_write_xing(AVFormatContext *s)
avio_write(s->pb, mp3->xing_frame, mp3->xing_frame_size);
mp3->audio_size = mp3->xing_frame_size;
+
+ return 0;
}
/*
@@ -288,7 +291,7 @@ static void mp3_xing_add_frame(MP3Context *mp3, AVPacket *pkt)
if (XING_NUM_BAGS == ++mp3->pos) {
/* shrink table to half size by throwing away each second bag. */
for (i = 1; i < XING_NUM_BAGS; i += 2)
- mp3->bag[i / 2] = mp3->bag[i];
+ mp3->bag[i >> 1] = mp3->bag[i];
/* double wanted amount per bag. */
mp3->want *= 2;
@@ -304,22 +307,43 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt)
{
MP3Context *mp3 = s->priv_data;
- if (mp3->xing_offset && pkt->size >= 4) {
- MPADecodeHeader c;
+ if (pkt->data && pkt->size >= 4) {
+ MPADecodeHeader mpah;
+ int av_unused base;
uint32_t h;
h = AV_RB32(pkt->data);
if (ff_mpa_check_header(h) == 0) {
- avpriv_mpegaudio_decode_header(&c, h);
+ avpriv_mpegaudio_decode_header(&mpah, h);
if (!mp3->initial_bitrate)
- mp3->initial_bitrate = c.bit_rate;
- if ((c.bit_rate == 0) || (mp3->initial_bitrate != c.bit_rate))
+ mp3->initial_bitrate = mpah.bit_rate;
+ if ((mpah.bit_rate == 0) || (mp3->initial_bitrate != mpah.bit_rate))
mp3->has_variable_bitrate = 1;
+ } else {
+ av_log(s, AV_LOG_WARNING, "Audio packet of size %d (starting with %08X...) "
+ "is invalid, writing it anyway.\n", pkt->size, h);
}
- mp3_xing_add_frame(mp3, pkt);
+#ifdef FILTER_VBR_HEADERS
+ /* filter out XING and INFO headers. */
+ base = 4 + xing_offtbl[mpah.lsf == 1][mpah.nb_channels == 1];
+
+ if (base + 4 <= pkt->size) {
+ uint32_t v = AV_RB32(pkt->data + base);
+
+ if (MKBETAG('X','i','n','g') == v || MKBETAG('I','n','f','o') == v)
+ return 0;
+ }
+
+ /* filter out VBRI headers. */
+ base = 4 + 32;
+
+ if (base + 4 <= pkt->size && MKBETAG('V','B','R','I') == AV_RB32(pkt->data + base))
+ return 0;
+#endif
if (mp3->xing_offset) {
+ mp3_xing_add_frame(mp3, pkt);
mp3->audio_size += pkt->size;
mp3->audio_crc = av_crc(av_crc_get_table(AV_CRC_16_ANSI_LE),
mp3->audio_crc, pkt->data, pkt->size);
@@ -335,7 +359,7 @@ static int mp3_queue_flush(AVFormatContext *s)
AVPacketList *pktl;
int ret = 0, write = 1;
- ff_id3v2_finish(&mp3->id3, s->pb);
+ ff_id3v2_finish(&mp3->id3, s->pb, s->metadata_header_padding);
mp3_write_xing(s);
while ((pktl = mp3->queue)) {
@@ -431,6 +455,17 @@ static int mp3_write_trailer(struct AVFormatContext *s)
return 0;
}
+static int query_codec(enum AVCodecID id, int std_compliance)
+{
+ const CodecMime *cm= ff_id3v2_mime_tags;
+ while(cm->id != AV_CODEC_ID_NONE) {
+ if(id == cm->id)
+ return MKTAG('A', 'P', 'I', 'C');
+ cm++;
+ }
+ return -1;
+}
+
#if CONFIG_MP2_MUXER
AVOutputFormat ff_mp2_muxer = {
.name = "mp2",
@@ -471,14 +506,18 @@ static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt)
if (mp3->pics_to_write) {
/* buffer audio packets until we get all the pictures */
AVPacketList *pktl = av_mallocz(sizeof(*pktl));
- if (!pktl)
- return AVERROR(ENOMEM);
+ int ret;
+ if (!pktl) {
+ av_log(s, AV_LOG_WARNING, "Not enough memory to buffer audio. Skipping picture streams\n");
+ mp3->pics_to_write = 0;
+ mp3_queue_flush(s);
+ return mp3_write_audio_packet(s, pkt);
+ }
- pktl->pkt = *pkt;
- pktl->pkt.buf = av_buffer_ref(pkt->buf);
- if (!pktl->pkt.buf) {
+ ret = av_copy_packet(&pktl->pkt, pkt);
+ if (ret < 0) {
av_freep(&pktl);
- return AVERROR(ENOMEM);
+ return ret;
}
if (mp3->queue_end)
@@ -567,7 +606,7 @@ static int mp3_write_header(struct AVFormatContext *s)
if (!mp3->pics_to_write) {
if (mp3->id3v2_version)
- ff_id3v2_finish(&mp3->id3, s->pb);
+ ff_id3v2_finish(&mp3->id3, s->pb, s->metadata_header_padding);
mp3_write_xing(s);
}
@@ -585,6 +624,7 @@ AVOutputFormat ff_mp3_muxer = {
.write_header = mp3_write_header,
.write_packet = mp3_write_packet,
.write_trailer = mp3_write_trailer,
+ .query_codec = query_codec,
.flags = AVFMT_NOTIMESTAMPS,
.priv_class = &mp3_muxer_class,
};
diff --git a/libavformat/mpc.c b/libavformat/mpc.c
index 1c8a295863..a62a3f2723 100644
--- a/libavformat/mpc.c
+++ b/libavformat/mpc.c
@@ -2,20 +2,20 @@
* Musepack demuxer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -95,9 +95,8 @@ static int mpc_read_header(AVFormatContext *s)
st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
st->codec->bits_per_coded_sample = 16;
- st->codec->extradata_size = 16;
- st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
- avio_read(s->pb, st->codec->extradata, 16);
+ if (ff_get_extradata(st->codec, s->pb, 16) < 0)
+ return AVERROR(ENOMEM);
st->codec->sample_rate = mpc_rate[st->codec->extradata[2] & 3];
avpriv_set_pts_info(st, 32, MPC_FRAMESIZE, st->codec->sample_rate);
/* scan for seekpoints */
@@ -153,7 +152,7 @@ static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt)
}
c->curbits = (curbits + size2) & 0x1F;
- if ((ret = av_new_packet(pkt, size)) < 0)
+ if ((ret = av_new_packet(pkt, size + 4)) < 0)
return ret;
pkt->data[0] = curbits;
@@ -196,11 +195,11 @@ static int mpc_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
MPCContext *c = s->priv_data;
AVPacket pkt1, *pkt = &pkt1;
int ret;
- int index = av_index_search_timestamp(st, timestamp - DELAY_FRAMES, flags);
+ int index = av_index_search_timestamp(st, FFMAX(timestamp - DELAY_FRAMES, 0), flags);
uint32_t lastframe;
/* if found, seek there */
- if (index >= 0){
+ if (index >= 0 && st->index_entries[st->nb_index_entries-1].timestamp >= timestamp - DELAY_FRAMES){
c->curframe = st->index_entries[index].pos;
return 0;
}
diff --git a/libavformat/mpc8.c b/libavformat/mpc8.c
index 07f12d291c..0cef65ff7d 100644
--- a/libavformat/mpc8.c
+++ b/libavformat/mpc8.c
@@ -2,20 +2,20 @@
* Musepack SV8 demuxer
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,7 @@
#include "avio_internal.h"
/// Two-byte MPC tag
-#define MKMPCTAG(a, b) (a | (b << 8))
+#define MKMPCTAG(a, b) ((a) | ((b) << 8))
#define TAG_MPCK MKTAG('M','P','C','K')
@@ -55,9 +55,9 @@ typedef struct MPCContext {
int64_t apetag_start;
} MPCContext;
-static inline int64_t bs_get_v(uint8_t **bs)
+static inline int64_t bs_get_v(const uint8_t **bs)
{
- int64_t v = 0;
+ uint64_t v = 0;
int br = 0;
int c;
@@ -75,8 +75,8 @@ static inline int64_t bs_get_v(uint8_t **bs)
static int mpc8_probe(AVProbeData *p)
{
- uint8_t *bs = p->buf + 4;
- uint8_t *bs_end = bs + p->buf_size;
+ const uint8_t *bs = p->buf + 4;
+ const uint8_t *bs_end = bs + p->buf_size;
int64_t size;
if (p->buf_size < 16)
@@ -91,7 +91,7 @@ static int mpc8_probe(AVProbeData *p)
size = bs_get_v(&bs);
if (size < 2)
return 0;
- if (bs + size - 2 >= bs_end)
+ if (size >= bs_end - bs + 2)
return AVPROBE_SCORE_EXTENSION - 1; // seems to be valid MPC but no header yet
if (header_found) {
if (size < 11 || size > 28)
@@ -108,7 +108,7 @@ static int mpc8_probe(AVProbeData *p)
static inline int64_t gb_get_v(GetBitContext *gb)
{
- int64_t v = 0;
+ uint64_t v = 0;
int bits = 0;
while(get_bits1(gb) && bits < 64-7){
v <<= 7;
@@ -136,7 +136,7 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
int tag;
int64_t size, pos, ppos[2];
uint8_t *buf;
- int i, t, seekd;
+ int i, t, seekd, ret;
GetBitContext gb;
if (s->nb_streams == 0) {
@@ -150,13 +150,20 @@ static void mpc8_parse_seektable(AVFormatContext *s, int64_t off)
av_log(s, AV_LOG_ERROR, "No seek table at given position\n");
return;
}
- if (size < 0 || size >= INT_MAX / 2) {
+ if (size > INT_MAX/10 || size<=0) {
av_log(s, AV_LOG_ERROR, "Bad seek table size\n");
return;
}
if(!(buf = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE)))
return;
- avio_read(s->pb, buf, size);
+ ret = avio_read(s->pb, buf, size);
+ if (ret != size) {
+ av_log(s, AV_LOG_ERROR, "seek table truncated\n");
+ av_free(buf);
+ return;
+ }
+ memset(buf+size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
init_get_bits(&gb, buf, size * 8);
size = gb_get_v(&gb);
if(size > UINT_MAX/4 || size > c->samples/1152){
@@ -213,9 +220,13 @@ static int mpc8_read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- while(!pb->eof_reached){
+ while(!avio_feof(pb)){
pos = avio_tell(pb);
mpc8_get_chunk_header(pb, &tag, &size);
+ if (size < 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid chunk length\n");
+ return AVERROR_INVALIDDATA;
+ }
if(tag == TAG_STREAMHDR)
break;
mpc8_handle_chunk(s, tag, pos, size);
@@ -241,9 +252,8 @@ static int mpc8_read_header(AVFormatContext *s)
st->codec->codec_id = AV_CODEC_ID_MUSEPACK8;
st->codec->bits_per_coded_sample = 16;
- st->codec->extradata_size = 2;
- st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- avio_read(pb, st->codec->extradata, st->codec->extradata_size);
+ if (ff_get_extradata(st->codec, pb, 2) < 0)
+ return AVERROR(ENOMEM);
st->codec->channels = (st->codec->extradata[1] >> 4) + 1;
st->codec->sample_rate = mpc8_rate[st->codec->extradata[0] >> 5];
@@ -251,6 +261,8 @@ static int mpc8_read_header(AVFormatContext *s)
st->start_time = 0;
st->duration = c->samples / (1152 << (st->codec->extradata[1]&3)*2);
size -= avio_tell(pb) - pos;
+ if (size > 0)
+ avio_skip(pb, size);
if (pb->seekable) {
int64_t pos = avio_tell(s->pb);
@@ -267,7 +279,7 @@ static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt)
int tag;
int64_t pos, size;
- while(!s->pb->eof_reached){
+ while(!avio_feof(s->pb)){
pos = avio_tell(s->pb);
/* don't return bogus packets with the ape tag data */
diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c
index ffabe28683..edb134f740 100644
--- a/libavformat/mpeg.c
+++ b/libavformat/mpeg.c
@@ -2,20 +2,20 @@
* MPEG1/2 demuxer
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,15 +23,20 @@
#include "internal.h"
#include "mpeg.h"
-#undef NDEBUG
-#include <assert.h>
+#if CONFIG_VOBSUB_DEMUXER
+# include "subtitles.h"
+# include "libavutil/bprint.h"
+# include "libavutil/opt.h"
+#endif
+
+#include "libavutil/avassert.h"
/*********************************************/
/* demux code */
#define MAX_SYNC_SIZE 100000
-static int check_pes(uint8_t *p, uint8_t *end)
+static int check_pes(const uint8_t *p, const uint8_t *end)
{
int pes1;
int pes2 = (p[3] & 0xC0) == 0x80 &&
@@ -64,79 +69,88 @@ static int mpegps_probe(AVProbeData *p)
int i;
int sys = 0, pspack = 0, priv1 = 0, vid = 0;
int audio = 0, invalid = 0, score = 0;
+ int endpes = 0;
for (i = 0; i < p->buf_size; i++) {
code = (code << 8) + p->buf[i];
if ((code & 0xffffff00) == 0x100) {
int len = p->buf[i + 1] << 8 | p->buf[i + 2];
- int pes = check_pes(p->buf + i, p->buf + p->buf_size);
+ int pes = endpes <= i && check_pes(p->buf + i, p->buf + p->buf_size);
int pack = check_pack_header(p->buf + i);
if (code == SYSTEM_HEADER_START_CODE)
sys++;
else if (code == PACK_START_CODE && pack)
pspack++;
- else if ((code & 0xf0) == VIDEO_ID && pes)
+ else if ((code & 0xf0) == VIDEO_ID && pes) {
+ endpes = i + len;
vid++;
+ }
// skip pes payload to avoid start code emulation for private
// and audio streams
- else if ((code & 0xe0) == AUDIO_ID && pes) {
- audio++;
- i += len;
- } else if (code == PRIVATE_STREAM_1 && pes) {
- priv1++;
- i += len;
- } else if ((code & 0xf0) == VIDEO_ID && !pes)
- invalid++;
- else if ((code & 0xe0) == AUDIO_ID && !pes)
- invalid++;
- else if (code == PRIVATE_STREAM_1 && !pes)
- invalid++;
+ else if ((code & 0xe0) == AUDIO_ID && pes) {audio++; i+=len;}
+ else if (code == PRIVATE_STREAM_1 && pes) {priv1++; i+=len;}
+ else if (code == 0x1fd && pes) vid++; //VC1
+
+ else if ((code & 0xf0) == VIDEO_ID && !pes) invalid++;
+ else if ((code & 0xe0) == AUDIO_ID && !pes) invalid++;
+ else if (code == PRIVATE_STREAM_1 && !pes) invalid++;
}
}
- if (vid + audio > invalid) /* invalid VDR files nd short PES streams */
+ if (vid + audio > invalid + 1) /* invalid VDR files nd short PES streams */
score = AVPROBE_SCORE_EXTENSION / 2;
+// av_log(NULL, AV_LOG_ERROR, "vid:%d aud:%d sys:%d pspack:%d invalid:%d size:%d \n",
+// vid, audio, sys, pspack, invalid, p->buf_size);
+
if (sys > invalid && sys * 9 <= pspack * 10)
- return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2
- : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg
+ return (audio > 12 || vid > 3 || pspack > 2) ? AVPROBE_SCORE_EXTENSION + 2
+ : AVPROBE_SCORE_EXTENSION / 2 + 1; // 1 more than mp3
if (pspack > invalid && (priv1 + vid + audio) * 10 >= pspack * 9)
return pspack > 2 ? AVPROBE_SCORE_EXTENSION + 2
: AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg
if ((!!vid ^ !!audio) && (audio > 4 || vid > 1) && !sys &&
!pspack && p->buf_size > 2048 && vid + audio > invalid) /* PES stream */
- return (audio > 12 || vid > 3) ? AVPROBE_SCORE_EXTENSION + 2
- : AVPROBE_SCORE_EXTENSION / 2;
+ return (audio > 12 || vid > 3 + 2 * invalid) ? AVPROBE_SCORE_EXTENSION + 2
+ : AVPROBE_SCORE_EXTENSION / 2;
// 02-Penguin.flac has sys:0 priv1:0 pspack:0 vid:0 audio:1
// mp3_misidentified_2.mp3 has sys:0 priv1:0 pspack:0 vid:0 audio:6
+ // Have\ Yourself\ a\ Merry\ Little\ Christmas.mp3 0 0 0 5 0 1 len:21618
return score;
}
typedef struct MpegDemuxContext {
+ AVClass *class;
int32_t header_state;
unsigned char psm_es_type[256];
int sofdec;
+ int dvd;
+ int imkh_cctv;
+#if CONFIG_VOBSUB_DEMUXER
+ AVFormatContext *sub_ctx;
+ FFDemuxSubtitlesQueue q[32];
+ char *sub_name;
+#endif
} MpegDemuxContext;
static int mpegps_read_header(AVFormatContext *s)
{
MpegDemuxContext *m = s->priv_data;
- const char *sofdec = "Sofdec";
- int v, i = 0;
+ char buffer[7];
+ int64_t last_pos = avio_tell(s->pb);
m->header_state = 0xff;
s->ctx_flags |= AVFMTCTX_NOHEADER;
- m->sofdec = -1;
- do {
- v = avio_r8(s->pb);
- m->header_state = m->header_state << 8 | v;
- m->sofdec++;
- } while (v == sofdec[i] && i++ < 6);
-
- m->sofdec = (m->sofdec == 6) ? 1 : 0;
+ avio_get_str(s->pb, 6, buffer, sizeof(buffer));
+ if (!memcmp("IMKH", buffer, 4)) {
+ m->imkh_cctv = 1;
+ } else if (!memcmp("Sofdec", buffer, 6)) {
+ m->sofdec = 1;
+ } else
+ avio_seek(s->pb, last_pos, SEEK_SET);
/* no need to do more */
return 0;
@@ -161,7 +175,7 @@ static int find_next_start_code(AVIOContext *pb, int *size_ptr,
state = *header_state;
n = *size_ptr;
while (n > 0) {
- if (pb->eof_reached)
+ if (avio_feof(pb))
break;
v = avio_r8(pb);
n--;
@@ -197,7 +211,9 @@ static long mpegps_psm_parse(MpegDemuxContext *m, AVIOContext *pb)
/* skip program_stream_info */
avio_skip(pb, ps_info_length);
- es_map_length = avio_rb16(pb);
+ /*es_map_length = */avio_rb16(pb);
+ /* Ignore es_map_length, trust psm_length */
+ es_map_length = psm_length - ps_info_length - 10;
/* at least one es available? */
while (es_map_length >= 4) {
@@ -237,7 +253,7 @@ redo:
startcode = find_next_start_code(s->pb, &size, &m->header_state);
last_sync = avio_tell(s->pb);
if (startcode < 0) {
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR_EOF;
// FIXME we should remember header_state
return AVERROR(EAGAIN);
@@ -252,21 +268,82 @@ redo:
goto redo;
}
if (startcode == PRIVATE_STREAM_2) {
- len = avio_rb16(s->pb);
if (!m->sofdec) {
- while (len-- >= 6) {
- if (avio_r8(s->pb) == 'S') {
- uint8_t buf[5];
- avio_read(s->pb, buf, sizeof(buf));
- m->sofdec = !memcmp(buf, "ofdec", 5);
- len -= sizeof(buf);
- break;
+ /* Need to detect whether this from a DVD or a 'Sofdec' stream */
+ int len = avio_rb16(s->pb);
+ int bytesread = 0;
+ uint8_t *ps2buf = av_malloc(len);
+
+ if (ps2buf) {
+ bytesread = avio_read(s->pb, ps2buf, len);
+
+ if (bytesread != len) {
+ avio_skip(s->pb, len - bytesread);
+ } else {
+ uint8_t *p = 0;
+ if (len >= 6)
+ p = memchr(ps2buf, 'S', len - 5);
+
+ if (p)
+ m->sofdec = !memcmp(p+1, "ofdec", 5);
+
+ m->sofdec -= !m->sofdec;
+
+ if (m->sofdec < 0) {
+ if (len == 980 && ps2buf[0] == 0) {
+ /* PCI structure? */
+ uint32_t startpts = AV_RB32(ps2buf + 0x0d);
+ uint32_t endpts = AV_RB32(ps2buf + 0x11);
+ uint8_t hours = ((ps2buf[0x19] >> 4) * 10) + (ps2buf[0x19] & 0x0f);
+ uint8_t mins = ((ps2buf[0x1a] >> 4) * 10) + (ps2buf[0x1a] & 0x0f);
+ uint8_t secs = ((ps2buf[0x1b] >> 4) * 10) + (ps2buf[0x1b] & 0x0f);
+
+ m->dvd = (hours <= 23 &&
+ mins <= 59 &&
+ secs <= 59 &&
+ (ps2buf[0x19] & 0x0f) < 10 &&
+ (ps2buf[0x1a] & 0x0f) < 10 &&
+ (ps2buf[0x1b] & 0x0f) < 10 &&
+ endpts >= startpts);
+ } else if (len == 1018 && ps2buf[0] == 1) {
+ /* DSI structure? */
+ uint8_t hours = ((ps2buf[0x1d] >> 4) * 10) + (ps2buf[0x1d] & 0x0f);
+ uint8_t mins = ((ps2buf[0x1e] >> 4) * 10) + (ps2buf[0x1e] & 0x0f);
+ uint8_t secs = ((ps2buf[0x1f] >> 4) * 10) + (ps2buf[0x1f] & 0x0f);
+
+ m->dvd = (hours <= 23 &&
+ mins <= 59 &&
+ secs <= 59 &&
+ (ps2buf[0x1d] & 0x0f) < 10 &&
+ (ps2buf[0x1e] & 0x0f) < 10 &&
+ (ps2buf[0x1f] & 0x0f) < 10);
+ }
+ }
}
+
+ av_free(ps2buf);
+
+ /* If this isn't a DVD packet or no memory
+ * could be allocated, just ignore it.
+ * If we did, move back to the start of the
+ * packet (plus 'length' field) */
+ if (!m->dvd || avio_skip(s->pb, -(len + 2)) < 0) {
+ /* Skip back failed.
+ * This packet will be lost but that can't be helped
+ * if we can't skip back
+ */
+ goto redo;
+ }
+ } else {
+ /* No memory */
+ avio_skip(s->pb, len);
+ goto redo;
}
- m->sofdec -= !m->sofdec;
+ } else if (!m->dvd) {
+ int len = avio_rb16(s->pb);
+ avio_skip(s->pb, len);
+ goto redo;
}
- avio_skip(s->pb, len);
- goto redo;
}
if (startcode == PROGRAM_STREAM_MAP) {
mpegps_psm_parse(m, s->pb);
@@ -276,7 +353,9 @@ redo:
/* find matching stream */
if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
(startcode >= 0x1e0 && startcode <= 0x1ef) ||
- (startcode == 0x1bd) || (startcode == 0x1fd)))
+ (startcode == 0x1bd) ||
+ (startcode == PRIVATE_STREAM_2) ||
+ (startcode == 0x1fd)))
goto redo;
if (ppos) {
*ppos = avio_tell(s->pb) - 4;
@@ -284,6 +363,8 @@ redo:
len = avio_rb16(s->pb);
pts =
dts = AV_NOPTS_VALUE;
+ if (startcode != PRIVATE_STREAM_2)
+ {
/* stuffing */
for (;;) {
if (len < 1)
@@ -358,22 +439,11 @@ redo:
avio_skip(s->pb, header_len);
} else if (c != 0xf)
goto redo;
+ }
- if (startcode == PRIVATE_STREAM_1 && !m->psm_es_type[startcode & 0xff]) {
+ if (startcode == PRIVATE_STREAM_1) {
startcode = avio_r8(s->pb);
len--;
- if (startcode >= 0x80 && startcode <= 0xcf) {
- /* audio: skip header */
- avio_r8(s->pb);
- avio_r8(s->pb);
- avio_r8(s->pb);
- len -= 3;
- if (startcode >= 0xb0 && startcode <= 0xbf) {
- /* MLP/TrueHD audio has a 4-byte header */
- avio_r8(s->pb);
- len--;
- }
- }
}
if (len < 0)
goto error_redo;
@@ -401,20 +471,30 @@ static int mpegps_read_packet(AVFormatContext *s,
MpegDemuxContext *m = s->priv_data;
AVStream *st;
int len, startcode, i, es_type, ret;
+ int lpcm_header_len = -1; //Init to suppress warning
+ int request_probe= 0;
enum AVCodecID codec_id = AV_CODEC_ID_NONE;
enum AVMediaType type;
int64_t pts, dts, dummy_pos; // dummy_pos is needed for the index building to work
- uint8_t av_uninit(dvdaudio_substream_type);
redo:
len = mpegps_read_pes_header(s, &dummy_pos, &startcode, &pts, &dts);
if (len < 0)
return len;
- if (startcode == 0x1bd) {
- dvdaudio_substream_type = avio_r8(s->pb);
- avio_skip(s->pb, 3);
- len -= 4;
+ if (startcode >= 0x80 && startcode <= 0xcf) {
+ if (len < 4)
+ goto skip;
+
+ /* audio: skip header */
+ avio_r8(s->pb);
+ lpcm_header_len = avio_rb16(s->pb);
+ len -= 3;
+ if (startcode >= 0xb0 && startcode <= 0xbf) {
+ /* MLP/TrueHD audio has a 4-byte header */
+ avio_r8(s->pb);
+ len--;
+ }
}
/* now find stream */
@@ -425,7 +505,6 @@ redo:
}
es_type = m->psm_es_type[startcode & 0xff];
- if (es_type > 0 && es_type != STREAM_TYPE_PRIVATE_DATA) {
if (es_type == STREAM_TYPE_VIDEO_MPEG1) {
codec_id = AV_CODEC_ID_MPEG2VIDEO;
type = AVMEDIA_TYPE_VIDEO;
@@ -448,9 +527,9 @@ redo:
} else if (es_type == STREAM_TYPE_AUDIO_AC3) {
codec_id = AV_CODEC_ID_AC3;
type = AVMEDIA_TYPE_AUDIO;
- } else {
- goto skip;
- }
+ } else if (m->imkh_cctv && es_type == 0x91) {
+ codec_id = AV_CODEC_ID_PCM_MULAW;
+ type = AVMEDIA_TYPE_AUDIO;
} else if (startcode >= 0x1e0 && startcode <= 0x1ef) {
static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 };
unsigned char buf[8];
@@ -460,11 +539,25 @@ redo:
if (!memcmp(buf, avs_seqh, 4) && (buf[6] != 0 || buf[7] != 1))
codec_id = AV_CODEC_ID_CAVS;
else
- codec_id = AV_CODEC_ID_PROBE;
+ request_probe= 1;
type = AVMEDIA_TYPE_VIDEO;
+ } else if (startcode == PRIVATE_STREAM_2) {
+ type = AVMEDIA_TYPE_DATA;
+ codec_id = AV_CODEC_ID_DVD_NAV;
} else if (startcode >= 0x1c0 && startcode <= 0x1df) {
type = AVMEDIA_TYPE_AUDIO;
- codec_id = m->sofdec > 0 ? AV_CODEC_ID_ADPCM_ADX : AV_CODEC_ID_MP2;
+ if (m->sofdec > 0) {
+ codec_id = AV_CODEC_ID_ADPCM_ADX;
+ // Auto-detect AC-3
+ request_probe = 50;
+ } else if (m->imkh_cctv && startcode == 0x1c0 && len > 80) {
+ codec_id = AV_CODEC_ID_PCM_ALAW;
+ request_probe = 50;
+ } else {
+ codec_id = AV_CODEC_ID_MP2;
+ if (m->imkh_cctv)
+ request_probe = 25;
+ }
} else if (startcode >= 0x80 && startcode <= 0x87) {
type = AVMEDIA_TYPE_AUDIO;
codec_id = AV_CODEC_ID_AC3;
@@ -475,7 +568,11 @@ redo:
codec_id = AV_CODEC_ID_DTS;
} else if (startcode >= 0xa0 && startcode <= 0xaf) {
type = AVMEDIA_TYPE_AUDIO;
- codec_id = AV_CODEC_ID_PCM_DVD;
+ if (lpcm_header_len == 6) {
+ codec_id = AV_CODEC_ID_MLP;
+ } else {
+ codec_id = AV_CODEC_ID_PCM_DVD;
+ }
} else if (startcode >= 0xb0 && startcode <= 0xbf) {
type = AVMEDIA_TYPE_AUDIO;
codec_id = AV_CODEC_ID_TRUEHD;
@@ -489,23 +586,6 @@ redo:
} else if (startcode >= 0xfd55 && startcode <= 0xfd5f) {
type = AVMEDIA_TYPE_VIDEO;
codec_id = AV_CODEC_ID_VC1;
- } else if (startcode == 0x1bd) {
- // check dvd audio substream type
- type = AVMEDIA_TYPE_AUDIO;
- switch (dvdaudio_substream_type & 0xe0) {
- case 0xa0:
- codec_id = AV_CODEC_ID_PCM_DVD;
- break;
- case 0x80:
- if ((dvdaudio_substream_type & 0xf8) == 0x88)
- codec_id = AV_CODEC_ID_DTS;
- else
- codec_id = AV_CODEC_ID_AC3;
- break;
- default:
- av_log(s, AV_LOG_ERROR, "Unknown 0x1bd sub-stream\n");
- goto skip;
- }
} else {
skip:
/* skip packet */
@@ -519,18 +599,35 @@ skip:
st->id = startcode;
st->codec->codec_type = type;
st->codec->codec_id = codec_id;
+ if ( st->codec->codec_id == AV_CODEC_ID_PCM_MULAW
+ || st->codec->codec_id == AV_CODEC_ID_PCM_ALAW) {
+ st->codec->channels = 1;
+ st->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ st->codec->sample_rate = 8000;
+ }
+ st->request_probe = request_probe;
st->need_parsing = AVSTREAM_PARSE_FULL;
found:
if (st->discard >= AVDISCARD_ALL)
goto skip;
+ if (startcode >= 0xa0 && startcode <= 0xaf) {
+ if (lpcm_header_len == 6 && st->codec->codec_id == AV_CODEC_ID_MLP) {
+ if (len < 6)
+ goto skip;
+ avio_skip(s->pb, 6);
+ len -=6;
+ }
+ }
ret = av_get_packet(s->pb, pkt, len);
pkt->pts = pts;
pkt->dts = dts;
pkt->pos = dummy_pos;
pkt->stream_index = st->index;
- av_log(s, AV_LOG_TRACE, "%d: pts=%0.3f dts=%0.3f size=%d\n",
+
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "%d: pts=%0.3f dts=%0.3f size=%d\n",
pkt->stream_index, pkt->pts / 90000.0, pkt->dts / 90000.0,
pkt->size);
@@ -550,7 +647,8 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
for (;;) {
len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts);
if (len < 0) {
- av_log(s, AV_LOG_TRACE, "none (ret=%d)\n", len);
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "none (ret=%d)\n", len);
return AV_NOPTS_VALUE;
}
if (startcode == s->streams[stream_index]->id &&
@@ -559,7 +657,8 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index,
}
avio_skip(s->pb, len);
}
- av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n",
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n",
pos, dts, dts / 90000.0);
*ppos = pos;
return dts;
@@ -575,3 +674,364 @@ AVInputFormat ff_mpegps_demuxer = {
.read_timestamp = mpegps_read_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
};
+
+#if CONFIG_VOBSUB_DEMUXER
+
+#define REF_STRING "# VobSub index file,"
+#define MAX_LINE_SIZE 2048
+
+static int vobsub_probe(AVProbeData *p)
+{
+ if (!strncmp(p->buf, REF_STRING, sizeof(REF_STRING) - 1))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int vobsub_read_header(AVFormatContext *s)
+{
+ int i, ret = 0, header_parsed = 0, langidx = 0;
+ MpegDemuxContext *vobsub = s->priv_data;
+ size_t fname_len;
+ char *header_str;
+ AVBPrint header;
+ int64_t delay = 0;
+ AVStream *st = NULL;
+ int stream_id = -1;
+ char id[64] = {0};
+ char alt[MAX_LINE_SIZE] = {0};
+ AVInputFormat *iformat;
+
+ if (!vobsub->sub_name) {
+ char *ext;
+ vobsub->sub_name = av_strdup(s->filename);
+ if (!vobsub->sub_name) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ fname_len = strlen(vobsub->sub_name);
+ ext = vobsub->sub_name - 3 + fname_len;
+ if (fname_len < 4 || *(ext - 1) != '.') {
+ av_log(s, AV_LOG_ERROR, "The input index filename is too short "
+ "to guess the associated .SUB file\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+ memcpy(ext, !strncmp(ext, "IDX", 3) ? "SUB" : "sub", 3);
+ av_log(s, AV_LOG_VERBOSE, "IDX/SUB: %s -> %s\n", s->filename, vobsub->sub_name);
+ }
+
+ if (!(iformat = av_find_input_format("mpeg"))) {
+ ret = AVERROR_DEMUXER_NOT_FOUND;
+ goto end;
+ }
+
+ vobsub->sub_ctx = avformat_alloc_context();
+ if (!vobsub->sub_ctx) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ if ((ret = ff_copy_whitelists(vobsub->sub_ctx, s)) < 0)
+ goto end;
+
+ ret = avformat_open_input(&vobsub->sub_ctx, vobsub->sub_name, iformat, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Unable to open %s as MPEG subtitles\n", vobsub->sub_name);
+ goto end;
+ }
+
+ av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
+ while (!avio_feof(s->pb)) {
+ char line[MAX_LINE_SIZE];
+ int len = ff_get_line(s->pb, line, sizeof(line));
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ if (!strncmp(line, "id:", 3)) {
+ if (sscanf(line, "id: %63[^,], index: %u", id, &stream_id) != 2) {
+ av_log(s, AV_LOG_WARNING, "Unable to parse index line '%s', "
+ "assuming 'id: und, index: 0'\n", line);
+ strcpy(id, "und");
+ stream_id = 0;
+ }
+
+ if (stream_id >= FF_ARRAY_ELEMS(vobsub->q)) {
+ av_log(s, AV_LOG_ERROR, "Maximum number of subtitles streams reached\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+
+ header_parsed = 1;
+ alt[0] = '\0';
+ /* We do not create the stream immediately to avoid adding empty
+ * streams. See the following timestamp entry. */
+
+ av_log(s, AV_LOG_DEBUG, "IDX stream[%d] id=%s\n", stream_id, id);
+
+ } else if (!strncmp(line, "timestamp:", 10)) {
+ AVPacket *sub;
+ int hh, mm, ss, ms;
+ int64_t pos, timestamp;
+ const char *p = line + 10;
+
+ if (stream_id == -1) {
+ av_log(s, AV_LOG_ERROR, "Timestamp declared before any stream\n");
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+
+ if (!st || st->id != stream_id) {
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ st->id = stream_id;
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE;
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ av_dict_set(&st->metadata, "language", id, 0);
+ if (alt[0])
+ av_dict_set(&st->metadata, "title", alt, 0);
+ }
+
+ if (sscanf(p, "%02d:%02d:%02d:%03d, filepos: %"SCNx64,
+ &hh, &mm, &ss, &ms, &pos) != 5) {
+ av_log(s, AV_LOG_ERROR, "Unable to parse timestamp line '%s', "
+ "abort parsing\n", line);
+ ret = AVERROR_INVALIDDATA;
+ goto end;
+ }
+ timestamp = (hh*3600LL + mm*60LL + ss) * 1000LL + ms + delay;
+ timestamp = av_rescale_q(timestamp, av_make_q(1, 1000), st->time_base);
+
+ sub = ff_subtitles_queue_insert(&vobsub->q[s->nb_streams - 1], "", 0, 0);
+ if (!sub) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ sub->pos = pos;
+ sub->pts = timestamp;
+ sub->stream_index = s->nb_streams - 1;
+
+ } else if (!strncmp(line, "alt:", 4)) {
+ const char *p = line + 4;
+
+ while (*p == ' ')
+ p++;
+ av_log(s, AV_LOG_DEBUG, "IDX stream[%d] name=%s\n", stream_id, p);
+ av_strlcpy(alt, p, sizeof(alt));
+ header_parsed = 1;
+
+ } else if (!strncmp(line, "delay:", 6)) {
+ int sign = 1, hh = 0, mm = 0, ss = 0, ms = 0;
+ const char *p = line + 6;
+
+ while (*p == ' ')
+ p++;
+ if (*p == '-' || *p == '+') {
+ sign = *p == '-' ? -1 : 1;
+ p++;
+ }
+ sscanf(p, "%d:%d:%d:%d", &hh, &mm, &ss, &ms);
+ delay = ((hh*3600LL + mm*60LL + ss) * 1000LL + ms) * sign;
+
+ } else if (!strncmp(line, "langidx:", 8)) {
+ const char *p = line + 8;
+
+ if (sscanf(p, "%d", &langidx) != 1)
+ av_log(s, AV_LOG_ERROR, "Invalid langidx specified\n");
+
+ } else if (!header_parsed) {
+ if (line[0] && line[0] != '#')
+ av_bprintf(&header, "%s\n", line);
+ }
+ }
+
+ if (langidx < s->nb_streams)
+ s->streams[langidx]->disposition |= AV_DISPOSITION_DEFAULT;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ vobsub->q[i].sort = SUB_SORT_POS_TS;
+ ff_subtitles_queue_finalize(&vobsub->q[i]);
+ }
+
+ if (!av_bprint_is_complete(&header)) {
+ av_bprint_finalize(&header, NULL);
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ av_bprint_finalize(&header, &header_str);
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *sub_st = s->streams[i];
+ sub_st->codec->extradata = av_strdup(header_str);
+ sub_st->codec->extradata_size = header.len;
+ }
+ av_free(header_str);
+
+end:
+ return ret;
+}
+
+static int vobsub_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MpegDemuxContext *vobsub = s->priv_data;
+ FFDemuxSubtitlesQueue *q;
+ AVIOContext *pb = vobsub->sub_ctx->pb;
+ int ret, psize, total_read = 0, i;
+ AVPacket idx_pkt;
+
+ int64_t min_ts = INT64_MAX;
+ int sid = 0;
+ for (i = 0; i < s->nb_streams; i++) {
+ FFDemuxSubtitlesQueue *tmpq = &vobsub->q[i];
+ int64_t ts;
+ av_assert0(tmpq->nb_subs);
+ ts = tmpq->subs[tmpq->current_sub_idx].pts;
+ if (ts < min_ts) {
+ min_ts = ts;
+ sid = i;
+ }
+ }
+ q = &vobsub->q[sid];
+ ret = ff_subtitles_queue_read_packet(q, &idx_pkt);
+ if (ret < 0)
+ return ret;
+
+ /* compute maximum packet size using the next packet position. This is
+ * useful when the len in the header is non-sense */
+ if (q->current_sub_idx < q->nb_subs) {
+ psize = q->subs[q->current_sub_idx].pos - idx_pkt.pos;
+ } else {
+ int64_t fsize = avio_size(pb);
+ psize = fsize < 0 ? 0xffff : fsize - idx_pkt.pos;
+ }
+
+ avio_seek(pb, idx_pkt.pos, SEEK_SET);
+
+ av_init_packet(pkt);
+ pkt->size = 0;
+ pkt->data = NULL;
+
+ do {
+ int n, to_read, startcode;
+ int64_t pts, dts;
+ int64_t old_pos = avio_tell(pb), new_pos;
+ int pkt_size;
+
+ ret = mpegps_read_pes_header(vobsub->sub_ctx, NULL, &startcode, &pts, &dts);
+ if (ret < 0) {
+ if (pkt->size) // raise packet even if incomplete
+ break;
+ goto fail;
+ }
+ to_read = ret & 0xffff;
+ new_pos = avio_tell(pb);
+ pkt_size = ret + (new_pos - old_pos);
+
+ /* this prevents reads above the current packet */
+ if (total_read + pkt_size > psize)
+ break;
+ total_read += pkt_size;
+
+ /* the current chunk doesn't match the stream index (unlikely) */
+ if ((startcode & 0x1f) != idx_pkt.stream_index)
+ break;
+
+ ret = av_grow_packet(pkt, to_read);
+ if (ret < 0)
+ goto fail;
+
+ n = avio_read(pb, pkt->data + (pkt->size - to_read), to_read);
+ if (n < to_read)
+ pkt->size -= to_read - n;
+ } while (total_read < psize);
+
+ pkt->pts = pkt->dts = idx_pkt.pts;
+ pkt->pos = idx_pkt.pos;
+ pkt->stream_index = idx_pkt.stream_index;
+
+ av_free_packet(&idx_pkt);
+ return 0;
+
+fail:
+ av_free_packet(pkt);
+ av_free_packet(&idx_pkt);
+ return ret;
+}
+
+static int vobsub_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ MpegDemuxContext *vobsub = s->priv_data;
+
+ /* Rescale requested timestamps based on the first stream (timebase is the
+ * same for all subtitles stream within a .idx/.sub). Rescaling is done just
+ * like in avformat_seek_file(). */
+ if (stream_index == -1 && s->nb_streams != 1) {
+ int i, ret = 0;
+ AVRational time_base = s->streams[0]->time_base;
+ ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
+ min_ts = av_rescale_rnd(min_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
+ max_ts = av_rescale_rnd(max_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+ for (i = 0; i < s->nb_streams; i++) {
+ int r = ff_subtitles_queue_seek(&vobsub->q[i], s, stream_index,
+ min_ts, ts, max_ts, flags);
+ if (r < 0)
+ ret = r;
+ }
+ return ret;
+ }
+
+ if (stream_index == -1) // only 1 stream
+ stream_index = 0;
+ return ff_subtitles_queue_seek(&vobsub->q[stream_index], s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int vobsub_read_close(AVFormatContext *s)
+{
+ int i;
+ MpegDemuxContext *vobsub = s->priv_data;
+
+ for (i = 0; i < s->nb_streams; i++)
+ ff_subtitles_queue_clean(&vobsub->q[i]);
+ if (vobsub->sub_ctx)
+ avformat_close_input(&vobsub->sub_ctx);
+ return 0;
+}
+
+static const AVOption options[] = {
+ { "sub_name", "URI for .sub file", offsetof(MpegDemuxContext, sub_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL }
+};
+
+static const AVClass vobsub_demuxer_class = {
+ .class_name = "vobsub",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_vobsub_demuxer = {
+ .name = "vobsub",
+ .long_name = NULL_IF_CONFIG_SMALL("VobSub subtitle format"),
+ .priv_data_size = sizeof(MpegDemuxContext),
+ .read_probe = vobsub_probe,
+ .read_header = vobsub_read_header,
+ .read_packet = vobsub_read_packet,
+ .read_seek2 = vobsub_read_seek,
+ .read_close = vobsub_read_close,
+ .flags = AVFMT_SHOW_IDS,
+ .extensions = "idx",
+ .priv_class = &vobsub_demuxer_class,
+};
+#endif
diff --git a/libavformat/mpeg.h b/libavformat/mpeg.h
index d0b36ee153..b43517c30a 100644
--- a/libavformat/mpeg.h
+++ b/libavformat/mpeg.h
@@ -2,20 +2,20 @@
* MPEG1/2 muxer and demuxer common defines
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,7 +42,7 @@
#define VIDEO_ID 0xe0
#define H264_ID 0xe2
#define AC3_ID 0x80
-#define DTS_ID 0x8a
+#define DTS_ID 0x88
#define LPCM_ID 0xa0
#define SUB_ID 0x20
@@ -58,7 +58,6 @@
#define STREAM_TYPE_VIDEO_CAVS 0x42
#define STREAM_TYPE_AUDIO_AC3 0x81
-#define STREAM_TYPE_AUDIO_DTS 0x8a
static const int lpcm_freq_tab[4] = { 48000, 96000, 44100, 32000 };
diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c
index 33eaefd9ff..2520f49db1 100644
--- a/libavformat/mpegenc.c
+++ b/libavformat/mpegenc.c
@@ -2,20 +2,20 @@
* MPEG1/2 muxer
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,9 +35,6 @@
#define MAX_PAYLOAD_SIZE 4096
-#undef NDEBUG
-#include <assert.h>
-
typedef struct PacketDesc {
int64_t pts;
int64_t dts;
@@ -69,6 +66,7 @@ typedef struct MpegMuxContext {
int pack_header_freq; /* frequency (in packets^-1) at which we send pack headers */
int system_header_freq;
int system_header_size;
+ int user_mux_rate; /* bitrate in units of bits/s */
int mux_rate; /* bitrate in units of 50 bytes/s */
/* stream info */
int audio_bound;
@@ -79,7 +77,7 @@ typedef struct MpegMuxContext {
int is_dvd;
int64_t last_scr; /* current system clock */
- double vcd_padding_bitrate; // FIXME floats
+ int64_t vcd_padding_bitrate_num;
int64_t vcd_padding_bytes_written;
int preload;
@@ -268,8 +266,7 @@ static int put_system_header(AVFormatContext *ctx, uint8_t *buf,
flush_put_bits(&pb);
size = put_bits_ptr(&pb) - pb.buf;
/* patch packet size */
- buf[4] = (size - 6) >> 8;
- buf[5] = (size - 6) & 0xff;
+ AV_WB16(buf + 4, size - 6);
return size;
}
@@ -324,10 +321,10 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
} else
s->packet_size = 2048;
if (ctx->max_delay < 0) /* Not set by the caller */
- ctx->max_delay = 0;
+ ctx->max_delay = AV_TIME_BASE*7/10;
s->vcd_padding_bytes_written = 0;
- s->vcd_padding_bitrate = 0;
+ s->vcd_padding_bitrate_num = 0;
s->audio_bound = 0;
s->video_bound = 0;
@@ -351,6 +348,15 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
+ if (!s->is_mpeg2 &&
+ (st->codec->codec_id == AV_CODEC_ID_AC3 ||
+ st->codec->codec_id == AV_CODEC_ID_DTS ||
+ st->codec->codec_id == AV_CODEC_ID_PCM_S16BE))
+ av_log(ctx, AV_LOG_WARNING,
+ "%s in MPEG-1 system streams is not widely supported, "
+ "consider using the vob or the dvd muxer "
+ "to force a MPEG-2 program stream.\n",
+ avcodec_get_name(st->codec->codec_id));
if (st->codec->codec_id == AV_CODEC_ID_AC3) {
stream->id = ac3_id++;
} else if (st->codec->codec_id == AV_CODEC_ID_DTS) {
@@ -387,10 +393,16 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
stream->max_buffer_size = 6 * 1024 + st->codec->rc_buffer_size / 8;
else {
av_log(ctx, AV_LOG_WARNING,
- "VBV buffer size not set, muxing may fail\n");
+ "VBV buffer size not set, using default size of 130KB\n"
+ "If you want the mpeg file to be compliant to some specification\n"
+ "Like DVD, VCD or others, make sure you set the correct buffer size\n");
// FIXME: this is probably too small as default
stream->max_buffer_size = 230 * 1024;
}
+ if (stream->max_buffer_size > 1024 * 8191) {
+ av_log(ctx, AV_LOG_WARNING, "buffer size %d, too large\n", stream->max_buffer_size);
+ stream->max_buffer_size = 1024 * 8191;
+ }
s->video_bound++;
break;
case AVMEDIA_TYPE_SUBTITLE:
@@ -429,16 +441,22 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
video_bitrate += codec_rate;
}
- if (!s->mux_rate) {
+ if (s->user_mux_rate) {
+ s->mux_rate = (s->user_mux_rate + (8 * 50) - 1) / (8 * 50);
+ } else {
/* we increase slightly the bitrate to take into account the
* headers. XXX: compute it exactly */
bitrate += bitrate / 20;
bitrate += 10000;
s->mux_rate = (bitrate + (8 * 50) - 1) / (8 * 50);
+ if (s->mux_rate >= (1<<22)) {
+ av_log(ctx, AV_LOG_WARNING, "mux rate %d is too large\n", s->mux_rate);
+ s->mux_rate = (1<<22) - 1;
+ }
}
if (s->is_vcd) {
- double overhead_rate;
+ int64_t overhead_rate;
/* The VCD standard mandates that the mux_rate field is 3528
* (see standard p. IV-6).
@@ -458,12 +476,12 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
/* Add the header overhead to the data rate.
* 2279 data bytes per audio pack, 2294 data bytes per video pack */
- overhead_rate = ((audio_bitrate / 8.0) / 2279) * (2324 - 2279);
- overhead_rate += ((video_bitrate / 8.0) / 2294) * (2324 - 2294);
- overhead_rate *= 8;
+ overhead_rate = audio_bitrate * 2294LL * (2324 - 2279);
+ overhead_rate += video_bitrate * 2279LL * (2324 - 2294);
/* Add padding so that the full bitrate is 2324*75 bytes/sec */
- s->vcd_padding_bitrate = 2324 * 75 * 8 - (bitrate + overhead_rate);
+ s->vcd_padding_bitrate_num = (2324LL * 75 * 8 - bitrate) * 2279 * 2294 - overhead_rate;
+#define VCD_PADDING_BITRATE_DEN (2279 * 2294)
}
if (s->is_vcd || s->is_mpeg2)
@@ -493,12 +511,12 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx)
stream->packet_number = 0;
}
s->system_header_size = get_system_header_size(ctx);
- s->last_scr = 0;
+ s->last_scr = AV_NOPTS_VALUE;
return 0;
fail:
for (i = 0; i < ctx->nb_streams; i++)
- av_free(ctx->streams[i]->priv_data);
+ av_freep(&ctx->streams[i]->priv_data);
return AVERROR(ENOMEM);
}
@@ -516,12 +534,12 @@ static int get_vcd_padding_size(AVFormatContext *ctx, int64_t pts)
MpegMuxContext *s = ctx->priv_data;
int pad_bytes = 0;
- if (s->vcd_padding_bitrate > 0 && pts != AV_NOPTS_VALUE) {
+ if (s->vcd_padding_bitrate_num > 0 && pts != AV_NOPTS_VALUE) {
int64_t full_pad_bytes;
// FIXME: this is wrong
full_pad_bytes =
- (int64_t)((s->vcd_padding_bitrate * (pts / 90000.0)) / 8.0);
+ av_rescale(s->vcd_padding_bitrate_num, pts, 90000LL * 8 * VCD_PADDING_BITRATE_DEN);
pad_bytes = (int)(full_pad_bytes - s->vcd_padding_bytes_written);
if (pad_bytes < 0)
@@ -852,7 +870,7 @@ static int flush_packet(AVFormatContext *ctx, int stream_index,
}
/* output data */
- assert(payload_size - stuffing_size <= av_fifo_size(stream->fifo));
+ av_assert0(payload_size - stuffing_size <= av_fifo_size(stream->fifo));
av_fifo_generic_read(stream->fifo, ctx->pb,
payload_size - stuffing_size,
(void (*)(void*, void*, int))avio_write);
@@ -920,7 +938,7 @@ static int remove_decoded_packets(AVFormatContext *ctx, int64_t scr)
if (stream->buffer_index < pkt_desc->size ||
stream->predecode_packet == stream->premux_packet) {
av_log(ctx, AV_LOG_ERROR,
- "buffer underflow i=%d bufi=%d size=%d\n",
+ "buffer underflow st=%d bufi=%d size=%d\n",
i, stream->buffer_index, pkt_desc->size);
break;
}
@@ -942,6 +960,7 @@ static int output_packet(AVFormatContext *ctx, int flush)
int best_i = -1;
int best_score = INT_MIN;
int ignore_constraints = 0;
+ int ignore_delay = 0;
int64_t scr = s->last_scr;
PacketDesc *timestamp_packet;
const int64_t max_delay = av_rescale(ctx->max_delay, 90000, AV_TIME_BASE);
@@ -952,7 +971,7 @@ retry:
StreamInfo *stream = st->priv_data;
const int avail_data = av_fifo_size(stream->fifo);
const int space = stream->max_buffer_size - stream->buffer_index;
- int rel_space = 1024 * space / stream->max_buffer_size;
+ int rel_space = 1024LL * space / stream->max_buffer_size;
PacketDesc *next_pkt = stream->premux_packet;
/* for subtitle, a single PES packet must be generated,
@@ -962,14 +981,16 @@ retry:
return 0;
if (avail_data == 0)
continue;
- assert(avail_data > 0);
+ av_assert0(avail_data > 0);
if (space < s->packet_size && !ignore_constraints)
continue;
- if (next_pkt && next_pkt->dts - scr > max_delay)
+ if (next_pkt && next_pkt->dts - scr > max_delay && !ignore_delay)
continue;
-
+ if ( stream->predecode_packet
+ && stream->predecode_packet->size > stream->buffer_index)
+ rel_space += 1<<28;
if (rel_space > best_score) {
best_score = rel_space;
best_i = i;
@@ -979,6 +1000,7 @@ retry:
if (best_i < 0) {
int64_t best_dts = INT64_MAX;
+ int has_premux = 0;
for (i = 0; i < ctx->nb_streams; i++) {
AVStream *st = ctx->streams[i];
@@ -986,32 +1008,40 @@ retry:
PacketDesc *pkt_desc = stream->predecode_packet;
if (pkt_desc && pkt_desc->dts < best_dts)
best_dts = pkt_desc->dts;
+ has_premux |= !!stream->premux_packet;
}
- av_log(ctx, AV_LOG_TRACE, "bumping scr, scr:%f, dts:%f\n",
- scr / 90000.0, best_dts / 90000.0);
- if (best_dts == INT64_MAX)
- return 0;
+ if (best_dts < INT64_MAX) {
+ av_log(ctx, AV_LOG_TRACE, "bumping scr, scr:%f, dts:%f\n",
+ scr / 90000.0, best_dts / 90000.0);
- if (scr >= best_dts + 1 && !ignore_constraints) {
+ if (scr >= best_dts + 1 && !ignore_constraints) {
+ av_log(ctx, AV_LOG_ERROR,
+ "packet too large, ignoring buffer limits to mux it\n");
+ ignore_constraints = 1;
+ }
+ scr = FFMAX(best_dts + 1, scr);
+ if (remove_decoded_packets(ctx, scr) < 0)
+ return -1;
+ } else if (has_premux && flush) {
av_log(ctx, AV_LOG_ERROR,
- "packet too large, ignoring buffer limits to mux it\n");
+ "delay too large, ignoring ...\n");
+ ignore_delay = 1;
ignore_constraints = 1;
- }
- scr = FFMAX(best_dts + 1, scr);
- if (remove_decoded_packets(ctx, scr) < 0)
- return -1;
+ } else
+ return 0;
+
goto retry;
}
- assert(best_i >= 0);
+ av_assert0(best_i >= 0);
st = ctx->streams[best_i];
stream = st->priv_data;
- assert(av_fifo_size(stream->fifo) > 0);
+ av_assert0(av_fifo_size(stream->fifo) > 0);
- assert(avail_space >= s->packet_size || ignore_constraints);
+ av_assert0(avail_space >= s->packet_size || ignore_constraints);
timestamp_packet = stream->premux_packet;
if (timestamp_packet->unwritten_size == timestamp_packet->size) {
@@ -1029,7 +1059,7 @@ retry:
es_size = flush_packet(ctx, best_i, timestamp_packet->pts,
timestamp_packet->dts, scr, trailer_size);
} else {
- assert(av_fifo_size(stream->fifo) == trailer_size);
+ av_assert0(av_fifo_size(stream->fifo) == trailer_size);
es_size = flush_packet(ctx, best_i, AV_NOPTS_VALUE, AV_NOPTS_VALUE, scr,
trailer_size);
}
@@ -1056,8 +1086,10 @@ retry:
es_size -= stream->premux_packet->unwritten_size;
stream->premux_packet = stream->premux_packet->next;
}
- if (stream->premux_packet && es_size)
+ if (es_size) {
+ av_assert0(stream->premux_packet);
stream->premux_packet->unwritten_size -= es_size;
+ }
if (remove_decoded_packets(ctx, s->last_scr) < 0)
return -1;
@@ -1084,14 +1116,22 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt)
pts = pkt->pts;
dts = pkt->dts;
- if (pts != AV_NOPTS_VALUE)
- pts += 2 * preload;
- if (dts != AV_NOPTS_VALUE) {
- if (!s->last_scr)
- s->last_scr = dts + preload;
- dts += 2 * preload;
+ if (s->last_scr == AV_NOPTS_VALUE) {
+ if (dts == AV_NOPTS_VALUE || (dts < preload && ctx->avoid_negative_ts) || s->is_dvd) {
+ if (dts != AV_NOPTS_VALUE)
+ s->preload += av_rescale(-dts, AV_TIME_BASE, 90000);
+ s->last_scr = 0;
+ } else {
+ s->last_scr = dts - preload;
+ s->preload = 0;
+ }
+ preload = av_rescale(s->preload, 90000, AV_TIME_BASE);
+ av_log(ctx, AV_LOG_DEBUG, "First SCR: %"PRId64" First DTS: %"PRId64"\n", s->last_scr, dts + preload);
}
+ if (dts != AV_NOPTS_VALUE) dts += preload;
+ if (pts != AV_NOPTS_VALUE) pts += preload;
+
av_log(ctx, AV_LOG_TRACE, "dts:%f pts:%f flags:%d stream:%d nopts:%d\n",
dts / 90000.0, pts / 90000.0, pkt->flags,
pkt->stream_index, pts != AV_NOPTS_VALUE);
@@ -1152,8 +1192,8 @@ static int mpeg_mux_end(AVFormatContext *ctx)
for (i = 0; i < ctx->nb_streams; i++) {
stream = ctx->streams[i]->priv_data;
- assert(av_fifo_size(stream->fifo) == 0);
- av_fifo_free(stream->fifo);
+ av_assert0(av_fifo_size(stream->fifo) == 0);
+ av_fifo_freep(&stream->fifo);
}
return 0;
}
@@ -1161,7 +1201,7 @@ static int mpeg_mux_end(AVFormatContext *ctx)
#define OFFSET(x) offsetof(MpegMuxContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "muxrate", NULL, OFFSET(mux_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, (1 << 22) - 1, E },
+ { "muxrate", NULL, OFFSET(user_mux_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, ((1<<22) - 1) * (8 * 50), E },
{ "preload", "Initial demux-decode delay in microseconds.", OFFSET(preload), AV_OPT_TYPE_INT, { .i64 = 500000 }, 0, INT_MAX, E },
{ NULL },
};
diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
index 8f61f1727d..613584e4b6 100644
--- a/libavformat/mpegts.c
+++ b/libavformat/mpegts.c
@@ -2,20 +2,20 @@
* MPEG2 transport stream (aka DVB) demuxer
* Copyright (c) 2002-2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/opus.h"
@@ -54,6 +55,7 @@
enum MpegTSFilterType {
MPEGTS_PES,
MPEGTS_SECTION,
+ MPEGTS_PCR,
};
typedef struct MpegTSFilter MpegTSFilter;
@@ -74,6 +76,8 @@ typedef struct MpegTSSectionFilter {
int section_index;
int section_h_size;
int last_ver;
+ unsigned crc;
+ unsigned last_crc;
uint8_t *section_buf;
unsigned int check_crc : 1;
unsigned int end_of_section_reached : 1;
@@ -85,6 +89,7 @@ struct MpegTSFilter {
int pid;
int es_id;
int last_cc; /* last cc code (-1 if first packet) */
+ int64_t last_pcr;
enum MpegTSFilterType type;
union {
MpegTSPESFilter pes_filter;
@@ -97,6 +102,9 @@ struct Program {
unsigned int id; // program id/service id
unsigned int nb_pids;
unsigned int pids[MAX_PIDS_PER_PROGRAM];
+
+ /** have we found pmt for this program */
+ int pmt_found;
};
struct MpegTSContext {
@@ -106,9 +114,11 @@ struct MpegTSContext {
/** raw packet size, including FEC if present */
int raw_packet_size;
- int pos47;
- /** position corresponding to pos47, or 0 if pos47 invalid */
- int64_t pos;
+ int size_stat[3];
+ int size_stat_count;
+#define SIZE_STAT_THRESHOLD 10
+
+ int64_t pos47_full;
/** if true, all pids are analyzed to find streams */
int auto_guess;
@@ -116,6 +126,9 @@ struct MpegTSContext {
/** compute exact PCR for each transport stream packet */
int mpeg2ts_compute_pcr;
+ /** fix dvb teletext pts */
+ int fix_teletext_pts;
+
int64_t cur_pcr; /**< used to estimate the exact PCR */
int pcr_incr; /**< used to estimate the exact PCR */
@@ -127,6 +140,11 @@ struct MpegTSContext {
/** to detect seek */
int64_t last_pos;
+ int skip_changes;
+ int skip_clear;
+
+ int scan_all_pmts;
+
int resync_size;
/******************************************/
@@ -136,15 +154,27 @@ struct MpegTSContext {
unsigned int nb_prg;
struct Program *prg;
+ int8_t crc_validity[NB_PID_MAX];
/** filters for various streams specified by PMT + for the PAT and PMT */
MpegTSFilter *pids[NB_PID_MAX];
+ int current_pid;
};
#define MPEGTS_OPTIONS \
- { "resync_size", "Size limit for looking up a new syncronization.", offsetof(MpegTSContext, resync_size), AV_OPT_TYPE_INT, { .i64 = MAX_RESYNC_SIZE}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }
+ { "resync_size", "Size limit for looking up a new synchronization.", offsetof(MpegTSContext, resync_size), AV_OPT_TYPE_INT, { .i64 = MAX_RESYNC_SIZE}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }
static const AVOption options[] = {
MPEGTS_OPTIONS,
+ {"fix_teletext_pts", "Try to fix pts values of dvb teletext streams.", offsetof(MpegTSContext, fix_teletext_pts), AV_OPT_TYPE_INT,
+ {.i64 = 1}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
+ {"ts_packetsize", "Output option carrying the raw packet size.", offsetof(MpegTSContext, raw_packet_size), AV_OPT_TYPE_INT,
+ {.i64 = 0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
+ {"scan_all_pmts", "Scan and combine all PMTs", offsetof(MpegTSContext, scan_all_pmts), AV_OPT_TYPE_INT,
+ { .i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM },
+ {"skip_changes", "Skip changing / adding streams / programs.", offsetof(MpegTSContext, skip_changes), AV_OPT_TYPE_INT,
+ {.i64 = 0}, 0, 1, 0 },
+ {"skip_clear", "Skip clearing programs.", offsetof(MpegTSContext, skip_clear), AV_OPT_TYPE_INT,
+ {.i64 = 0}, 0, 1, 0 },
{ NULL },
};
@@ -213,13 +243,42 @@ typedef struct PESContext {
extern AVInputFormat ff_mpegts_demuxer;
+static struct Program * get_program(MpegTSContext *ts, unsigned int programid)
+{
+ int i;
+ for (i = 0; i < ts->nb_prg; i++) {
+ if (ts->prg[i].id == programid) {
+ return &ts->prg[i];
+ }
+ }
+ return NULL;
+}
+
+static void clear_avprogram(MpegTSContext *ts, unsigned int programid)
+{
+ AVProgram *prg = NULL;
+ int i;
+
+ for (i = 0; i < ts->stream->nb_programs; i++)
+ if (ts->stream->programs[i]->id == programid) {
+ prg = ts->stream->programs[i];
+ break;
+ }
+ if (!prg)
+ return;
+ prg->nb_stream_indexes = 0;
+}
+
static void clear_program(MpegTSContext *ts, unsigned int programid)
{
int i;
+ clear_avprogram(ts, programid);
for (i = 0; i < ts->nb_prg; i++)
- if (ts->prg[i].id == programid)
+ if (ts->prg[i].id == programid) {
ts->prg[i].nb_pids = 0;
+ ts->prg[i].pmt_found = 0;
+ }
}
static void clear_programs(MpegTSContext *ts)
@@ -238,28 +297,48 @@ static void add_pat_entry(MpegTSContext *ts, unsigned int programid)
p = &ts->prg[ts->nb_prg];
p->id = programid;
p->nb_pids = 0;
+ p->pmt_found = 0;
ts->nb_prg++;
}
static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid,
unsigned int pid)
{
+ struct Program *p = get_program(ts, programid);
int i;
- struct Program *p = NULL;
- for (i = 0; i < ts->nb_prg; i++) {
- if (ts->prg[i].id == programid) {
- p = &ts->prg[i];
- break;
- }
- }
if (!p)
return;
if (p->nb_pids >= MAX_PIDS_PER_PROGRAM)
return;
+
+ for (i = 0; i < p->nb_pids; i++)
+ if (p->pids[i] == pid)
+ return;
+
p->pids[p->nb_pids++] = pid;
}
+static void set_pmt_found(MpegTSContext *ts, unsigned int programid)
+{
+ struct Program *p = get_program(ts, programid);
+ if (!p)
+ return;
+
+ p->pmt_found = 1;
+}
+
+static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid)
+{
+ int i;
+ for (i = 0; i < s->nb_programs; i++) {
+ if (s->programs[i]->id == programid) {
+ s->programs[i]->pcr_pid = pid;
+ break;
+ }
+ }
+}
+
/**
* @brief discard_pid() decides if the pid is to be discarded according
* to caller's programs selection
@@ -337,22 +416,33 @@ static void write_section_data(MpegTSContext *ts, MpegTSFilter *tss1,
if (tss->section_h_size != -1 &&
tss->section_index >= tss->section_h_size) {
+ int crc_valid = 1;
tss->end_of_section_reached = 1;
- if (!tss->check_crc ||
- av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1,
- tss->section_buf, tss->section_h_size) == 0)
+
+ if (tss->check_crc) {
+ crc_valid = !av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, tss->section_buf, tss->section_h_size);
+ if (tss->section_h_size >= 4)
+ tss->crc = AV_RB32(tss->section_buf + tss->section_h_size - 4);
+
+ if (crc_valid) {
+ ts->crc_validity[ tss1->pid ] = 100;
+ }else if (ts->crc_validity[ tss1->pid ] > -10) {
+ ts->crc_validity[ tss1->pid ]--;
+ }else
+ crc_valid = 2;
+ }
+ if (crc_valid) {
tss->section_cb(tss1, tss->section_buf, tss->section_h_size);
+ if (crc_valid != 1)
+ tss->last_ver = -1;
+ }
}
}
-static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts,
- unsigned int pid,
- SectionCallback *section_cb,
- void *opaque,
- int check_crc)
+static MpegTSFilter *mpegts_open_filter(MpegTSContext *ts, unsigned int pid,
+ enum MpegTSFilterType type)
{
MpegTSFilter *filter;
- MpegTSSectionFilter *sec;
av_log(ts->stream, AV_LOG_TRACE, "Filter: pid=0x%x\n", pid);
@@ -363,11 +453,26 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts,
return NULL;
ts->pids[pid] = filter;
- filter->type = MPEGTS_SECTION;
+ filter->type = type;
filter->pid = pid;
filter->es_id = -1;
filter->last_cc = -1;
+ filter->last_pcr= -1;
+ return filter;
+}
+
+static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts,
+ unsigned int pid,
+ SectionCallback *section_cb,
+ void *opaque,
+ int check_crc)
+{
+ MpegTSFilter *filter;
+ MpegTSSectionFilter *sec;
+
+ if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION)))
+ return NULL;
sec = &filter->u.section_filter;
sec->section_cb = section_cb;
sec->opaque = opaque;
@@ -389,24 +494,20 @@ static MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid,
MpegTSFilter *filter;
MpegTSPESFilter *pes;
- if (pid >= NB_PID_MAX || ts->pids[pid])
- return NULL;
- filter = av_mallocz(sizeof(MpegTSFilter));
- if (!filter)
+ if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_PES)))
return NULL;
- ts->pids[pid] = filter;
- filter->type = MPEGTS_PES;
- filter->pid = pid;
- filter->es_id = -1;
- filter->last_cc = -1;
-
pes = &filter->u.pes_filter;
pes->pes_cb = pes_cb;
pes->opaque = opaque;
return filter;
}
+static MpegTSFilter *mpegts_open_pcr_filter(MpegTSContext *ts, unsigned int pid)
+{
+ return mpegts_open_filter(ts, pid, MPEGTS_PCR);
+}
+
static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter)
{
int pid;
@@ -432,29 +533,27 @@ static int analyze(const uint8_t *buf, int size, int packet_size, int *index,
int probe)
{
int stat[TS_MAX_PACKET_SIZE];
+ int stat_all = 0;
int i;
- int x = 0;
int best_score = 0;
- memset(stat, 0, packet_size * sizeof(int));
+ memset(stat, 0, packet_size * sizeof(*stat));
- for (x = i = 0; i < size - 3; i++) {
+ for (i = 0; i < size - 3; i++) {
if (buf[i] == 0x47 &&
- (!probe || (!(buf[i + 1] & 0x80) && (buf[i + 3] & 0x30)))) {
+ (!probe || (!(buf[i + 1] & 0x80) && buf[i + 3] != 0x47))) {
+ int x = i % packet_size;
stat[x]++;
+ stat_all++;
if (stat[x] > best_score) {
best_score = stat[x];
if (index)
*index = x;
}
}
-
- x++;
- if (x == packet_size)
- x = 0;
}
- return best_score;
+ return best_score - FFMAX(stat_all - 10*best_score, 0)/10;
}
/* autodetect fec presence. Must have at least 1024 bytes */
@@ -489,6 +588,17 @@ typedef struct SectionHeader {
uint8_t last_sec_num;
} SectionHeader;
+static int skip_identical(const SectionHeader *h, MpegTSSectionFilter *tssf)
+{
+ if (h->version == tssf->last_ver && tssf->last_crc == tssf->crc)
+ return 1;
+
+ tssf->last_ver = h->version;
+ tssf->last_crc = tssf->crc;
+
+ return 0;
+}
+
static inline int get8(const uint8_t **pp, const uint8_t *p_end)
{
const uint8_t *p;
@@ -508,7 +618,7 @@ static inline int get16(const uint8_t **pp, const uint8_t *p_end)
int c;
p = *pp;
- if ((p + 1) >= p_end)
+ if (1 >= p_end - p)
return AVERROR_INVALIDDATA;
c = AV_RB16(p);
p += 2;
@@ -527,7 +637,7 @@ static char *getstr8(const uint8_t **pp, const uint8_t *p_end)
len = get8(&p, p_end);
if (len < 0)
return NULL;
- if ((p + len) > p_end)
+ if (len > p_end - p)
return NULL;
str = av_malloc(len + 1);
if (!str)
@@ -581,8 +691,13 @@ static const StreamType ISO_types[] = {
{ 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 },
{ 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC },
{ 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 },
+ /* Makito encoder sets stream type 0x11 for AAC,
+ * so auto-detect LOAS/LATM instead of hardcoding it. */
+#if !CONFIG_LOAS_DEMUXER
{ 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */
+#endif
{ 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
+ { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
{ 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
{ 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
{ 0xd1, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC },
@@ -598,6 +713,8 @@ static const StreamType HDMV_types[] = {
{ 0x84, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 },
{ 0x85, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS HD */
{ 0x86, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS HD MASTER*/
+ { 0xa1, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */
+ { 0xa2, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, /* DTS Express Secondary Audio */
{ 0x90, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_HDMV_PGS_SUBTITLE },
{ 0 },
};
@@ -617,11 +734,18 @@ static const StreamType REGD_types[] = {
{ MKTAG('D', 'T', 'S', '2'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ MKTAG('D', 'T', 'S', '3'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
{ MKTAG('H', 'E', 'V', 'C'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
+ { MKTAG('K', 'L', 'V', 'A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV },
{ MKTAG('V', 'C', '-', '1'), AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VC1 },
{ MKTAG('O', 'p', 'u', 's'), AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_OPUS },
{ 0 },
};
+static const StreamType METADATA_types[] = {
+ { MKTAG('K','L','V','A'), AVMEDIA_TYPE_DATA, AV_CODEC_ID_SMPTE_KLV },
+ { MKTAG('I','D','3',' '), AVMEDIA_TYPE_DATA, AV_CODEC_ID_TIMED_ID3 },
+ { 0 },
+};
+
/* descriptor present */
static const StreamType DESC_types[] = {
{ 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */
@@ -636,10 +760,16 @@ static void mpegts_find_stream_type(AVStream *st,
uint32_t stream_type,
const StreamType *types)
{
+ if (avcodec_is_open(st->codec)) {
+ av_log(NULL, AV_LOG_DEBUG, "cannot set stream info, codec is open\n");
+ return;
+ }
+
for (; types->stream_type; types++)
if (stream_type == types->stream_type) {
st->codec->codec_type = types->codec_type;
st->codec->codec_id = types->codec_id;
+ st->request_probe = 0;
return;
}
}
@@ -647,6 +777,14 @@ static void mpegts_find_stream_type(AVStream *st,
static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
uint32_t stream_type, uint32_t prog_reg_desc)
{
+ int old_codec_type = st->codec->codec_type;
+ int old_codec_id = st->codec->codec_id;
+
+ if (avcodec_is_open(st->codec)) {
+ av_log(pes->stream, AV_LOG_DEBUG, "cannot set stream info, codec is open\n");
+ return 0;
+ }
+
avpriv_set_pts_info(st, 33, 1, 90000);
st->priv_data = pes;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
@@ -662,7 +800,8 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
st->codec->codec_tag = pes->stream_type;
mpegts_find_stream_type(st, pes->stream_type, ISO_types);
- if (prog_reg_desc == AV_RL32("HDMV") &&
+ if ((prog_reg_desc == AV_RL32("HDMV") ||
+ prog_reg_desc == AV_RL32("HDPR")) &&
st->codec->codec_id == AV_CODEC_ID_NONE) {
mpegts_find_stream_type(st, pes->stream_type, HDMV_types);
if (pes->stream_type == 0x83) {
@@ -692,10 +831,23 @@ static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
}
if (st->codec->codec_id == AV_CODEC_ID_NONE)
mpegts_find_stream_type(st, pes->stream_type, MISC_types);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE) {
+ st->codec->codec_id = old_codec_id;
+ st->codec->codec_type = old_codec_type;
+ }
return 0;
}
+static void reset_pes_packet_state(PESContext *pes)
+{
+ pes->pts = AV_NOPTS_VALUE;
+ pes->dts = AV_NOPTS_VALUE;
+ pes->data_index = 0;
+ pes->flags = 0;
+ av_buffer_unref(&pes->buffer);
+}
+
static void new_pes_packet(PESContext *pes, AVPacket *pkt)
{
av_init_packet(pkt);
@@ -723,12 +875,15 @@ static void new_pes_packet(PESContext *pes, AVPacket *pkt)
pkt->pos = pes->ts_packet_pos;
pkt->flags = pes->flags;
- /* reset pts values */
- pes->pts = AV_NOPTS_VALUE;
- pes->dts = AV_NOPTS_VALUE;
- pes->buffer = NULL;
- pes->data_index = 0;
- pes->flags = 0;
+ pes->buffer = NULL;
+ reset_pes_packet_state(pes);
+}
+
+static uint64_t get_ts64(GetBitContext *gb, int bits)
+{
+ if (get_bits_left(gb) < bits)
+ return AV_NOPTS_VALUE;
+ return get_bits64(gb, bits);
}
static int read_sl_header(PESContext *pes, SLConfigDescr *sl,
@@ -739,7 +894,12 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl,
int padding_flag = 0, padding_bits = 0, inst_bitrate_flag = 0;
int dts_flag = -1, cts_flag = -1;
int64_t dts = AV_NOPTS_VALUE, cts = AV_NOPTS_VALUE;
- init_get_bits(&gb, buf, buf_size * 8);
+ uint8_t buf_padded[128 + FF_INPUT_BUFFER_PADDING_SIZE];
+ int buf_padded_size = FFMIN(buf_size, sizeof(buf_padded) - FF_INPUT_BUFFER_PADDING_SIZE);
+
+ memcpy(buf_padded, buf, buf_padded_size);
+
+ init_get_bits(&gb, buf_padded, buf_padded_size * 8);
if (sl->use_au_start)
au_start_flag = get_bits1(&gb);
@@ -777,9 +937,9 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl,
if (sl->inst_bitrate_len)
inst_bitrate_flag = get_bits1(&gb);
if (dts_flag == 1)
- dts = get_bits64(&gb, sl->timestamp_len);
+ dts = get_ts64(&gb, sl->timestamp_len);
if (cts_flag == 1)
- cts = get_bits64(&gb, sl->timestamp_len);
+ cts = get_ts64(&gb, sl->timestamp_len);
if (sl->au_len > 0)
skip_bits_long(&gb, sl->au_len);
if (inst_bitrate_flag)
@@ -814,9 +974,10 @@ static int mpegts_push_data(MpegTSFilter *filter,
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) {
new_pes_packet(pes, ts->pkt);
ts->stop_parse = 1;
+ } else {
+ reset_pes_packet_state(pes);
}
pes->state = MPEGTS_HEADER;
- pes->data_index = 0;
pes->ts_packet_pos = pos;
}
p = buf;
@@ -848,6 +1009,9 @@ static int mpegts_push_data(MpegTSFilter *filter,
/* stream not present in PMT */
if (!pes->st) {
+ if (ts->skip_changes)
+ goto skip;
+
pes->st = avformat_new_stream(ts->stream, NULL);
if (!pes->st)
return AVERROR(ENOMEM);
@@ -872,12 +1036,12 @@ static int mpegts_push_data(MpegTSFilter *filter,
code != 0x1ff && code != 0x1f2 && /* program_stream_directory, DSMCC_stream */
code != 0x1f8) { /* ITU-T Rec. H.222.1 type E stream */
pes->state = MPEGTS_PESHEADER;
- if (pes->st->codec->codec_id == AV_CODEC_ID_NONE) {
+ if (pes->st->codec->codec_id == AV_CODEC_ID_NONE && !pes->st->request_probe) {
av_log(pes->stream, AV_LOG_TRACE,
"pid=%x stream_type=%x probing\n",
pes->pid,
pes->stream_type);
- pes->st->codec->codec_id = AV_CODEC_ID_PROBE;
+ pes->st->request_probe = 1;
}
} else {
pes->state = MPEGTS_PAYLOAD;
@@ -961,10 +1125,54 @@ skip:
p += sl_header_bytes;
buf_size -= sl_header_bytes;
}
+ if (pes->stream_type == 0x15 && buf_size >= 5) {
+ /* skip metadata access unit header */
+ pes->pes_header_size += 5;
+ p += 5;
+ buf_size -= 5;
+ }
+ if (pes->ts->fix_teletext_pts && pes->st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
+ AVProgram *p = NULL;
+ while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) {
+ if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) {
+ MpegTSFilter *f = pes->ts->pids[p->pcr_pid];
+ if (f) {
+ AVStream *st = NULL;
+ if (f->type == MPEGTS_PES) {
+ PESContext *pcrpes = f->u.pes_filter.opaque;
+ if (pcrpes)
+ st = pcrpes->st;
+ } else if (f->type == MPEGTS_PCR) {
+ int i;
+ for (i = 0; i < p->nb_stream_indexes; i++) {
+ AVStream *pst = pes->stream->streams[p->stream_index[i]];
+ if (pst->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ st = pst;
+ }
+ }
+ if (f->last_pcr != -1 && st && st->discard != AVDISCARD_ALL) {
+ // teletext packets do not always have correct timestamps,
+ // the standard says they should be handled after 40.6 ms at most,
+ // and the pcr error to this packet should be no more than 100 ms.
+ // TODO: we should interpolate the PCR, not just use the last one
+ int64_t pcr = f->last_pcr / 300;
+ pes->st->pts_wrap_reference = st->pts_wrap_reference;
+ pes->st->pts_wrap_behavior = st->pts_wrap_behavior;
+ if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) {
+ pes->pts = pes->dts = pcr;
+ } else if (pes->dts > pcr + 3654 + 9000) {
+ pes->pts = pes->dts = pcr + 3654 + 9000;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
}
break;
case MPEGTS_PAYLOAD:
- if (buf_size > 0 && pes->buffer) {
+ if (pes->buffer) {
if (pes->data_index > 0 &&
pes->data_index + buf_size > pes->total_size) {
new_pes_packet(pes, ts->pkt);
@@ -982,18 +1190,18 @@ skip:
}
memcpy(pes->buffer->data + pes->data_index, p, buf_size);
pes->data_index += buf_size;
+ /* emit complete packets with known packet size
+ * decreases demuxer delay for infrequent packets like subtitles from
+ * a couple of seconds to milliseconds for properly muxed files.
+ * total_size is the number of bytes following pes_packet_length
+ * in the pes header, i.e. not counting the first PES_START_SIZE bytes */
+ if (!ts->stop_parse && pes->total_size < MAX_PES_PAYLOAD &&
+ pes->pes_header_size + pes->data_index == pes->total_size + PES_START_SIZE) {
+ ts->stop_parse = 1;
+ new_pes_packet(pes, ts->pkt);
+ }
}
buf_size = 0;
- /* emit complete packets with known packet size
- * decreases demuxer delay for infrequent packets like subtitles from
- * a couple of seconds to milliseconds for properly muxed files.
- * total_size is the number of bytes following pes_packet_length
- * in the pes header, i.e. not counting the first PES_START_SIZE bytes */
- if (!ts->stop_parse && pes->total_size < MAX_PES_PAYLOAD &&
- pes->pes_header_size + pes->data_index == pes->total_size + PES_START_SIZE) {
- ts->stop_parse = 1;
- new_pes_packet(pes, ts->pkt);
- }
break;
case MPEGTS_SKIP:
buf_size = 0;
@@ -1037,6 +1245,7 @@ typedef struct MP4DescrParseContext {
int descr_count;
int max_descr_count;
int level;
+ int predefined_SLConfigDescriptor_seen;
} MP4DescrParseContext;
static int init_MP4DescrParseContext(MP4DescrParseContext *d, AVFormatContext *s,
@@ -1160,6 +1369,11 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len)
descr->sl.timestamp_res = avio_rb32(&d->pb);
avio_rb32(&d->pb);
descr->sl.timestamp_len = avio_r8(&d->pb);
+ if (descr->sl.timestamp_len > 64) {
+ avpriv_request_sample(NULL, "timestamp_len > 64");
+ descr->sl.timestamp_len = 64;
+ return AVERROR_PATCHWELCOME;
+ }
descr->sl.ocr_len = avio_r8(&d->pb);
descr->sl.au_len = avio_r8(&d->pb);
descr->sl.inst_bitrate_len = avio_r8(&d->pb);
@@ -1167,8 +1381,9 @@ static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len)
descr->sl.degr_prior_len = lengths >> 12;
descr->sl.au_seq_num_len = (lengths >> 7) & 0x1f;
descr->sl.packet_seq_num_len = (lengths >> 2) & 0x1f;
- } else {
+ } else if (!d->predefined_SLConfigDescriptor_seen){
avpriv_report_missing_feature(d->s, "Predefined SLConfigDescriptor");
+ d->predefined_SLConfigDescriptor_seen = 1;
}
return 0;
}
@@ -1273,9 +1488,8 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section,
return;
if (h.tid != M4OD_TID)
return;
- if (h.version == tssf->last_ver)
+ if (skip_identical(&h, tssf))
return;
- tssf->last_ver = h.version;
mp4_read_od(s, p, (unsigned) (p_end - p), mp4_descr, &mp4_descr_count,
MAX_MP4_DESCR_COUNT);
@@ -1288,7 +1502,7 @@ static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section,
AVStream *st;
if (ts->pids[pid]->es_id != mp4_descr[i].es_id)
continue;
- if (!(ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES)) {
+ if (ts->pids[pid]->type != MPEGTS_PES) {
av_log(s, AV_LOG_ERROR, "pid %x is not PES\n", pid);
continue;
}
@@ -1365,7 +1579,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
av_log(fc, AV_LOG_TRACE, "tag: 0x%02x len=%d\n", desc_tag, desc_len);
- if (st->codec->codec_id == AV_CODEC_ID_NONE &&
+ if ((st->codec->codec_id == AV_CODEC_ID_NONE || st->request_probe > 0) &&
stream_type == STREAM_TYPE_PRIVATE_DATA)
mpegts_find_stream_type(st, desc_tag, DESC_types);
@@ -1395,7 +1609,9 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
if (get16(pp, desc_end) < 0)
break;
if (mp4_descr_count > 0 &&
- st->codec->codec_id == AV_CODEC_ID_AAC_LATM &&
+ (st->codec->codec_id == AV_CODEC_ID_AAC_LATM ||
+ (st->request_probe == 0 && st->codec->codec_id == AV_CODEC_ID_NONE) ||
+ st->request_probe > 0) &&
mp4_descr->dec_config_descr_len && mp4_descr->es_id == pid) {
AVIOContext pb;
ffio_init_context(&pb, mp4_descr->dec_config_descr,
@@ -1403,46 +1619,118 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
NULL, NULL, NULL, NULL);
ff_mp4_read_dec_config_descr(fc, st, &pb);
if (st->codec->codec_id == AV_CODEC_ID_AAC &&
- st->codec->extradata_size > 0)
- st->need_parsing = 0;
+ st->codec->extradata_size > 0) {
+ st->request_probe = st->need_parsing = 0;
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ }
}
break;
case 0x56: /* DVB teletext descriptor */
- language[0] = get8(pp, desc_end);
- language[1] = get8(pp, desc_end);
- language[2] = get8(pp, desc_end);
- language[3] = 0;
- av_dict_set(&st->metadata, "language", language, 0);
+ {
+ uint8_t *extradata = NULL;
+ int language_count = desc_len / 5;
+
+ if (desc_len > 0 && desc_len % 5 != 0)
+ return AVERROR_INVALIDDATA;
+
+ if (language_count > 0) {
+ /* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */
+ if (language_count > sizeof(language) / 4) {
+ language_count = sizeof(language) / 4;
+ }
+
+ if (st->codec->extradata == NULL) {
+ if (ff_alloc_extradata(st->codec, language_count * 2)) {
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (st->codec->extradata_size < language_count * 2)
+ return AVERROR_INVALIDDATA;
+
+ extradata = st->codec->extradata;
+
+ for (i = 0; i < language_count; i++) {
+ language[i * 4 + 0] = get8(pp, desc_end);
+ language[i * 4 + 1] = get8(pp, desc_end);
+ language[i * 4 + 2] = get8(pp, desc_end);
+ language[i * 4 + 3] = ',';
+
+ memcpy(extradata, *pp, 2);
+ extradata += 2;
+
+ *pp += 2;
+ }
+
+ language[i * 4 - 1] = 0;
+ av_dict_set(&st->metadata, "language", language, 0);
+ }
+ }
break;
case 0x59: /* subtitling descriptor */
- language[0] = get8(pp, desc_end);
- language[1] = get8(pp, desc_end);
- language[2] = get8(pp, desc_end);
- language[3] = 0;
- /* hearing impaired subtitles detection */
- switch (get8(pp, desc_end)) {
- case 0x20: /* DVB subtitles (for the hard of hearing) with no monitor aspect ratio criticality */
- case 0x21: /* DVB subtitles (for the hard of hearing) for display on 4:3 aspect ratio monitor */
- case 0x22: /* DVB subtitles (for the hard of hearing) for display on 16:9 aspect ratio monitor */
- case 0x23: /* DVB subtitles (for the hard of hearing) for display on 2.21:1 aspect ratio monitor */
- case 0x24: /* DVB subtitles (for the hard of hearing) for display on a high definition monitor */
- case 0x25: /* DVB subtitles (for the hard of hearing) with plano-stereoscopic disparity for display on a high definition monitor */
- st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
- break;
- }
- if (st->codec->extradata) {
- if (st->codec->extradata_size == 4 &&
- memcmp(st->codec->extradata, *pp, 4))
- avpriv_request_sample(fc, "DVB sub with multiple IDs");
- } else {
- st->codec->extradata = av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (st->codec->extradata) {
- st->codec->extradata_size = 4;
- memcpy(st->codec->extradata, *pp, 4);
+ {
+ /* 8 bytes per DVB subtitle substream data:
+ * ISO_639_language_code (3 bytes),
+ * subtitling_type (1 byte),
+ * composition_page_id (2 bytes),
+ * ancillary_page_id (2 bytes) */
+ int language_count = desc_len / 8;
+
+ if (desc_len > 0 && desc_len % 8 != 0)
+ return AVERROR_INVALIDDATA;
+
+ if (language_count > 1) {
+ avpriv_request_sample(fc, "DVB subtitles with multiple languages");
+ }
+
+ if (language_count > 0) {
+ uint8_t *extradata;
+
+ /* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */
+ if (language_count > sizeof(language) / 4) {
+ language_count = sizeof(language) / 4;
+ }
+
+ if (st->codec->extradata == NULL) {
+ if (ff_alloc_extradata(st->codec, language_count * 5)) {
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (st->codec->extradata_size < language_count * 5)
+ return AVERROR_INVALIDDATA;
+
+ extradata = st->codec->extradata;
+
+ for (i = 0; i < language_count; i++) {
+ language[i * 4 + 0] = get8(pp, desc_end);
+ language[i * 4 + 1] = get8(pp, desc_end);
+ language[i * 4 + 2] = get8(pp, desc_end);
+ language[i * 4 + 3] = ',';
+
+ /* hearing impaired subtitles detection using subtitling_type */
+ switch (*pp[0]) {
+ case 0x20: /* DVB subtitles (for the hard of hearing) with no monitor aspect ratio criticality */
+ case 0x21: /* DVB subtitles (for the hard of hearing) for display on 4:3 aspect ratio monitor */
+ case 0x22: /* DVB subtitles (for the hard of hearing) for display on 16:9 aspect ratio monitor */
+ case 0x23: /* DVB subtitles (for the hard of hearing) for display on 2.21:1 aspect ratio monitor */
+ case 0x24: /* DVB subtitles (for the hard of hearing) for display on a high definition monitor */
+ case 0x25: /* DVB subtitles (for the hard of hearing) with plano-stereoscopic disparity for display on a high definition monitor */
+ st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
+ break;
+ }
+
+ extradata[4] = get8(pp, desc_end); /* subtitling_type */
+ memcpy(extradata, *pp, 4); /* composition_page_id and ancillary_page_id */
+ extradata += 5;
+
+ *pp += 4;
+ }
+
+ language[i * 4 - 1] = 0;
+ av_dict_set(&st->metadata, "language", language, 0);
}
}
- *pp += 4;
- av_dict_set(&st->metadata, "language", language, 0);
break;
case 0x0a: /* ISO 639 language descriptor */
for (i = 0; i + 4 <= desc_len; i += 4) {
@@ -1473,6 +1761,18 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
if (st->codec->codec_id == AV_CODEC_ID_NONE)
mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types);
break;
+ case 0x52: /* stream identifier descriptor */
+ st->stream_identifier = 1 + get8(pp, desc_end);
+ break;
+ case 0x26: /* metadata descriptor */
+ if (get16(pp, desc_end) == 0xFFFF)
+ *pp += 4;
+ if (get8(pp, desc_end) == 0xFF) {
+ st->codec->codec_tag = bytestream_get_le32(pp);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ mpegts_find_stream_type(st, st->codec->codec_tag, METADATA_types);
+ }
+ break;
case 0x7f: /* DVB extension descriptor */
ext_desc_tag = get8(pp, desc_end);
if (ext_desc_tag < 0)
@@ -1493,7 +1793,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
return AVERROR_INVALIDDATA;
if (channel_config_code <= 0x8) {
st->codec->extradata[9] = channels = channel_config_code ? channel_config_code : 2;
- st->codec->extradata[18] = channel_config_code ? (channels > 2) : 255;
+ st->codec->extradata[18] = channel_config_code ? (channels > 2) : /* Dual Mono */ 255;
st->codec->extradata[19] = opus_stream_cnt[channel_config_code];
st->codec->extradata[20] = opus_coupled_stream_cnt[channel_config_code];
memcpy(&st->codec->extradata[21], opus_channel_map[channels - 1], channels);
@@ -1534,22 +1834,26 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
p = section;
if (parse_section_header(h, &p, p_end) < 0)
return;
- if (h->version == tssf->last_ver)
+ if (skip_identical(h, tssf))
return;
- tssf->last_ver = h->version;
- av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x sec_num=%d/%d\n",
- h->id, h->sec_num, h->last_sec_num);
+ av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x sec_num=%d/%d version=%d\n",
+ h->id, h->sec_num, h->last_sec_num, h->version);
if (h->tid != PMT_TID)
return;
+ if (!ts->scan_all_pmts && ts->skip_changes)
+ return;
+
+ if (!ts->skip_clear)
+ clear_program(ts, h->id);
- clear_program(ts, h->id);
pcr_pid = get16(&p, p_end);
if (pcr_pid < 0)
return;
pcr_pid &= 0x1fff;
add_pid_to_pmt(ts, h->id, pcr_pid);
+ set_pcr_pid(ts->stream, h->id, pcr_pid);
av_log(ts->stream, AV_LOG_TRACE, "pcr_pid=0x%x\n", pcr_pid);
@@ -1586,7 +1890,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
// stop parsing after pmt, we found header
if (!ts->stream->nb_streams)
- ts->stop_parse = 1;
+ ts->stop_parse = 2;
+
+ set_pmt_found(ts, h->id);
for (;;) {
@@ -1597,14 +1903,18 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
break;
pid = get16(&p, p_end);
if (pid < 0)
- break;
+ goto out;
pid &= 0x1fff;
+ if (pid == ts->current_pid)
+ goto out;
/* now create stream */
if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) {
pes = ts->pids[pid]->u.pes_filter.opaque;
if (!pes->st) {
pes->st = avformat_new_stream(pes->stream, NULL);
+ if (!pes->st)
+ goto out;
pes->st->id = pes->pid;
}
st = pes->st;
@@ -1614,6 +1924,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
pes = add_pes_stream(ts, pid, pcr_pid);
if (pes) {
st = avformat_new_stream(pes->stream, NULL);
+ if (!st)
+ goto out;
st->id = pes->pid;
}
} else {
@@ -1622,6 +1934,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
st = ts->stream->streams[idx];
} else {
st = avformat_new_stream(ts->stream, NULL);
+ if (!st)
+ goto out;
st->id = pid;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
}
@@ -1639,11 +1953,11 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
desc_list_len = get16(&p, p_end);
if (desc_list_len < 0)
- break;
+ goto out;
desc_list_len &= 0xfff;
desc_list_end = p + desc_list_len;
if (desc_list_end > p_end)
- break;
+ goto out;
for (;;) {
if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p,
desc_list_end, mp4_descr,
@@ -1660,6 +1974,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
p = desc_list_end;
}
+ if (!ts->pids[pcr_pid])
+ mpegts_open_pcr_filter(ts, pcr_pid);
+
out:
for (i = 0; i < mp4_descr_count; i++)
av_free(mp4_descr[i].dec_config_descr);
@@ -1672,6 +1989,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
SectionHeader h1, *h = &h1;
const uint8_t *p, *p_end;
int sid, pmt_pid;
+ AVProgram *program;
av_log(ts->stream, AV_LOG_TRACE, "PAT:\n");
hex_dump_debug(ts->stream, section, section_len);
@@ -1682,9 +2000,12 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
return;
if (h->tid != PAT_TID)
return;
- if (h->version == tssf->last_ver)
+ if (ts->skip_changes)
return;
- tssf->last_ver = h->version;
+
+ if (skip_identical(h, tssf))
+ return;
+ ts->stream->ts_id = h->id;
clear_programs(ts);
for (;;) {
@@ -1696,20 +2017,44 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
break;
pmt_pid &= 0x1fff;
+ if (pmt_pid == ts->current_pid)
+ break;
+
av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x pid=0x%x\n", sid, pmt_pid);
if (sid == 0x0000) {
/* NIT info */
} else {
- av_new_program(ts->stream, sid);
- if (ts->pids[pmt_pid])
- mpegts_close_filter(ts, ts->pids[pmt_pid]);
- mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
+ MpegTSFilter *fil = ts->pids[pmt_pid];
+ program = av_new_program(ts->stream, sid);
+ if (program) {
+ program->program_num = sid;
+ program->pmt_pid = pmt_pid;
+ }
+ if (fil)
+ if ( fil->type != MPEGTS_SECTION
+ || fil->pid != pmt_pid
+ || fil->u.section_filter.section_cb != pmt_cb)
+ mpegts_close_filter(ts, ts->pids[pmt_pid]);
+
+ if (!ts->pids[pmt_pid])
+ mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1);
add_pat_entry(ts, sid);
add_pid_to_pmt(ts, sid, 0); // add pat pid to program
add_pid_to_pmt(ts, sid, pmt_pid);
}
}
+
+ if (sid < 0) {
+ int i,j;
+ for (j=0; j<ts->stream->nb_programs; j++) {
+ for (i = 0; i < ts->nb_prg; i++)
+ if (ts->prg[i].id == ts->stream->programs[j]->id)
+ break;
+ if (i==ts->nb_prg && !ts->skip_clear)
+ clear_avprogram(ts, ts->stream->programs[j]->id);
+ }
+ }
}
static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
@@ -1730,9 +2075,10 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
return;
if (h->tid != SDT_TID)
return;
- if (h->version == tssf->last_ver)
+ if (ts->skip_changes)
+ return;
+ if (skip_identical(h, tssf))
return;
- tssf->last_ver = h->version;
onid = get16(&p, p_end);
if (onid < 0)
@@ -1760,7 +2106,7 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
break;
desc_len = get8(&p, desc_list_end);
desc_end = p + desc_len;
- if (desc_end > desc_list_end)
+ if (desc_len < 0 || desc_end > desc_list_end)
break;
av_log(ts->stream, AV_LOG_TRACE, "tag: 0x%02x len=%d\n",
@@ -1795,6 +2141,9 @@ static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
}
}
+static int parse_pcr(int64_t *ppcr_high, int *ppcr_low,
+ const uint8_t *packet);
+
/* handle one TS packet */
static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
{
@@ -1815,6 +2164,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
}
if (!tss)
return 0;
+ ts->current_pid = pid;
afc = (packet[3] >> 4) & 3;
if (afc == 0) /* reserved value */
@@ -1835,7 +2185,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
tss->last_cc = cc;
if (!cc_ok) {
- av_log(ts->stream, AV_LOG_WARNING,
+ av_log(ts->stream, AV_LOG_DEBUG,
"Continuity check failed for pid %d expected %d got %d\n",
pid, expected_cc, cc);
if (tss->type == MPEGTS_PES) {
@@ -1844,26 +2194,31 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
}
}
- if (!has_payload)
- return 0;
p = packet + 4;
if (has_adaptation) {
+ int64_t pcr_h;
+ int pcr_l;
+ if (parse_pcr(&pcr_h, &pcr_l, packet) == 0)
+ tss->last_pcr = pcr_h * 300 + pcr_l;
/* skip adaptation field */
p += p[0] + 1;
}
/* if past the end of packet, ignore */
p_end = packet + TS_PACKET_SIZE;
- if (p >= p_end)
+ if (p >= p_end || !has_payload)
return 0;
pos = avio_tell(ts->stream->pb);
- MOD_UNLIKELY(ts->pos47, pos, ts->raw_packet_size, ts->pos);
+ if (pos >= 0) {
+ av_assert0(pos >= TS_PACKET_SIZE);
+ ts->pos47_full = pos - TS_PACKET_SIZE;
+ }
if (tss->type == MPEGTS_SECTION) {
if (is_start) {
/* pointer field present */
len = *p++;
- if (p + len > p_end)
+ if (len > p_end - p)
return 0;
if (len && cc_ok) {
/* write remaining section bytes */
@@ -1884,17 +2239,74 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet)
p, p_end - p, 0);
}
}
+
+ // stop find_stream_info from waiting for more streams
+ // when all programs have received a PMT
+ if (ts->stream->ctx_flags & AVFMTCTX_NOHEADER && ts->scan_all_pmts <= 0) {
+ int i;
+ for (i = 0; i < ts->nb_prg; i++) {
+ if (!ts->prg[i].pmt_found)
+ break;
+ }
+ if (i == ts->nb_prg && ts->nb_prg > 0) {
+ int types = 0;
+ for (i = 0; i < ts->stream->nb_streams; i++) {
+ AVStream *st = ts->stream->streams[i];
+ types |= 1<<st->codec->codec_type;
+ }
+ if ((types & (1<<AVMEDIA_TYPE_AUDIO) && types & (1<<AVMEDIA_TYPE_VIDEO)) || pos > 100000) {
+ av_log(ts->stream, AV_LOG_DEBUG, "All programs have pmt, headers found\n");
+ ts->stream->ctx_flags &= ~AVFMTCTX_NOHEADER;
+ }
+ }
+ }
+
} else {
int ret;
// Note: The position here points actually behind the current packet.
- if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,
- pos - ts->raw_packet_size)) < 0)
- return ret;
+ if (tss->type == MPEGTS_PES) {
+ if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start,
+ pos - ts->raw_packet_size)) < 0)
+ return ret;
+ }
}
return 0;
}
+static void reanalyze(MpegTSContext *ts) {
+ AVIOContext *pb = ts->stream->pb;
+ int64_t pos = avio_tell(pb);
+ if (pos < 0)
+ return;
+ pos -= ts->pos47_full;
+ if (pos == TS_PACKET_SIZE) {
+ ts->size_stat[0] ++;
+ } else if (pos == TS_DVHS_PACKET_SIZE) {
+ ts->size_stat[1] ++;
+ } else if (pos == TS_FEC_PACKET_SIZE) {
+ ts->size_stat[2] ++;
+ }
+
+ ts->size_stat_count ++;
+ if (ts->size_stat_count > SIZE_STAT_THRESHOLD) {
+ int newsize = 0;
+ if (ts->size_stat[0] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_PACKET_SIZE;
+ } else if (ts->size_stat[1] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_DVHS_PACKET_SIZE;
+ } else if (ts->size_stat[2] > SIZE_STAT_THRESHOLD) {
+ newsize = TS_FEC_PACKET_SIZE;
+ }
+ if (newsize && newsize != ts->raw_packet_size) {
+ av_log(ts->stream, AV_LOG_WARNING, "changing packet size to %d\n", newsize);
+ ts->raw_packet_size = newsize;
+ }
+ ts->size_stat_count = 0;
+ memset(ts->size_stat, 0, sizeof(ts->size_stat));
+ }
+}
+
/* XXX: try to find a better synchro over several packets (use
* get_packet_size() ?) */
static int mpegts_resync(AVFormatContext *s)
@@ -1905,10 +2317,11 @@ static int mpegts_resync(AVFormatContext *s)
for (i = 0; i < ts->resync_size; i++) {
c = avio_r8(pb);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
if (c == 0x47) {
avio_seek(pb, -1, SEEK_CUR);
+ reanalyze(s->priv_data);
return 0;
}
}
@@ -1932,7 +2345,9 @@ static int read_packet(AVFormatContext *s, uint8_t *buf, int raw_packet_size,
/* check packet sync byte */
if ((*data)[0] != 0x47) {
/* find a new packet start */
- avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR);
+ uint64_t pos = avio_tell(pb);
+ avio_seek(pb, -FFMIN(raw_packet_size, pos), SEEK_CUR);
+
if (mpegts_resync(s) < 0)
return AVERROR(EAGAIN);
else
@@ -1952,12 +2367,13 @@ static void finished_reading_packet(AVFormatContext *s, int raw_packet_size)
avio_skip(pb, skip);
}
-static int handle_packets(MpegTSContext *ts, int nb_packets)
+static int handle_packets(MpegTSContext *ts, int64_t nb_packets)
{
AVFormatContext *s = ts->stream;
uint8_t packet[TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
const uint8_t *data;
- int packet_num, ret = 0;
+ int64_t packet_num;
+ int ret = 0;
if (avio_tell(s->pb) != ts->last_pos) {
int i;
@@ -1970,8 +2386,11 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
av_buffer_unref(&pes->buffer);
pes->data_index = 0;
pes->state = MPEGTS_SKIP; /* skip until pes header */
+ } else if (ts->pids[i]->type == MPEGTS_SECTION) {
+ ts->pids[i]->u.section_filter.last_ver = -1;
}
ts->pids[i]->last_cc = -1;
+ ts->pids[i]->last_pcr = -1;
}
}
}
@@ -1980,11 +2399,15 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
packet_num = 0;
memset(packet + TS_PACKET_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
for (;;) {
- if (ts->stop_parse > 0)
- break;
packet_num++;
- if (nb_packets != 0 && packet_num >= nb_packets)
+ if (nb_packets != 0 && packet_num >= nb_packets ||
+ ts->stop_parse > 1) {
+ ret = AVERROR(EAGAIN);
break;
+ }
+ if (ts->stop_parse > 0)
+ break;
+
ret = read_packet(s, packet, ts->raw_packet_size, &data);
if (ret != 0)
break;
@@ -2000,30 +2423,33 @@ static int handle_packets(MpegTSContext *ts, int nb_packets)
static int mpegts_probe(AVProbeData *p)
{
const int size = p->buf_size;
- int score, fec_score, dvhs_score;
+ int maxscore = 0;
+ int sumscore = 0;
+ int i;
int check_count = size / TS_FEC_PACKET_SIZE;
#define CHECK_COUNT 10
+#define CHECK_BLOCK 100
if (check_count < CHECK_COUNT)
return AVERROR_INVALIDDATA;
- score = analyze(p->buf, TS_PACKET_SIZE * check_count,
- TS_PACKET_SIZE, NULL, 1) * CHECK_COUNT / check_count;
- dvhs_score = analyze(p->buf, TS_DVHS_PACKET_SIZE * check_count,
- TS_DVHS_PACKET_SIZE, NULL, 1) * CHECK_COUNT / check_count;
- fec_score = analyze(p->buf, TS_FEC_PACKET_SIZE * check_count,
- TS_FEC_PACKET_SIZE, NULL, 1) * CHECK_COUNT / check_count;
- av_log(NULL, AV_LOG_TRACE, "score: %d, dvhs_score: %d, fec_score: %d \n",
- score, dvhs_score, fec_score);
+ for (i = 0; i<check_count; i+=CHECK_BLOCK) {
+ int left = FFMIN(check_count - i, CHECK_BLOCK);
+ int score = analyze(p->buf + TS_PACKET_SIZE *i, TS_PACKET_SIZE *left, TS_PACKET_SIZE , NULL, 1);
+ int dvhs_score = analyze(p->buf + TS_DVHS_PACKET_SIZE*i, TS_DVHS_PACKET_SIZE*left, TS_DVHS_PACKET_SIZE, NULL, 1);
+ int fec_score = analyze(p->buf + TS_FEC_PACKET_SIZE *i, TS_FEC_PACKET_SIZE *left, TS_FEC_PACKET_SIZE , NULL, 1);
+ score = FFMAX3(score, dvhs_score, fec_score);
+ sumscore += score;
+ maxscore = FFMAX(maxscore, score);
+ }
+
+ sumscore = sumscore * CHECK_COUNT / check_count;
+ maxscore = maxscore * CHECK_COUNT / CHECK_BLOCK;
+
+ av_dlog(0, "TS score: %d %d\n", sumscore, maxscore);
- /* we need a clear definition for the returned score otherwise
- * things will become messy sooner or later */
- if (score > fec_score && score > dvhs_score && score > 6)
- return AVPROBE_SCORE_MAX + score - CHECK_COUNT;
- else if (dvhs_score > score && dvhs_score > fec_score && dvhs_score > 6)
- return AVPROBE_SCORE_MAX + dvhs_score - CHECK_COUNT;
- else if (fec_score > 6)
- return AVPROBE_SCORE_MAX + fec_score - CHECK_COUNT;
+ if (sumscore > 6) return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT;
+ else if (maxscore > 6) return AVPROBE_SCORE_MAX/2 + sumscore - CHECK_COUNT;
else
return AVERROR_INVALIDDATA;
}
@@ -2056,24 +2482,34 @@ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet)
return 0;
}
+static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) {
+
+ /* NOTE: We attempt to seek on non-seekable files as well, as the
+ * probe buffer usually is big enough. Only warn if the seek failed
+ * on files where the seek should work. */
+ if (avio_seek(pb, pos, SEEK_SET) < 0)
+ av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
+}
+
static int mpegts_read_header(AVFormatContext *s)
{
MpegTSContext *ts = s->priv_data;
AVIOContext *pb = s->pb;
- uint8_t buf[5 * 1024];
+ uint8_t buf[8 * 1024] = {0};
int len;
- int64_t pos;
+ int64_t pos, probesize = s->probesize ? s->probesize : s->probesize2;
- /* read the first 1024 bytes to get packet size */
+ if (ffio_ensure_seekback(pb, probesize) < 0)
+ av_log(s, AV_LOG_WARNING, "Failed to allocate buffers for seekback\n");
+
+ /* read the first 8192 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
- if (len < 0)
- return len;
- if (len != sizeof(buf))
- return AVERROR_BUG;
- ts->raw_packet_size = get_packet_size(buf, sizeof(buf));
- if (ts->raw_packet_size <= 0)
- return AVERROR_INVALIDDATA;
+ ts->raw_packet_size = get_packet_size(buf, len);
+ if (ts->raw_packet_size <= 0) {
+ av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n");
+ ts->raw_packet_size = TS_PACKET_SIZE;
+ }
ts->stream = s;
ts->auto_guess = 0;
@@ -2081,14 +2517,13 @@ static int mpegts_read_header(AVFormatContext *s)
/* normal demux */
/* first do a scan to get all the services */
- if (avio_seek(pb, pos, SEEK_SET) < 0 && pb->seekable)
- av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n");
+ seek_back(s, pb, pos);
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
- handle_packets(ts, s->probesize / ts->raw_packet_size);
+ handle_packets(ts, probesize / ts->raw_packet_size);
/* if could not find service, enable auto_guess */
ts->auto_guess = 1;
@@ -2148,7 +2583,7 @@ static int mpegts_read_header(AVFormatContext *s)
st->start_time / 1000000.0, pcrs[0] / 27e6, ts->pcr_incr);
}
- avio_seek(pb, pos, SEEK_SET);
+ seek_back(s, pb, pos);
return 0;
}
@@ -2211,6 +2646,7 @@ static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt)
ts->pkt = pkt;
ret = handle_packets(ts, 0);
if (ret < 0) {
+ av_free_packet(ts->pkt);
/* flush pes data left */
for (i = 0; i < NB_PID_MAX; i++)
if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) {
@@ -2247,7 +2683,7 @@ static int mpegts_read_close(AVFormatContext *s)
return 0;
}
-static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
+static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
int64_t *ppos, int64_t pos_limit)
{
MpegTSContext *ts = s->priv_data;
@@ -2255,74 +2691,69 @@ static int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pcr_pid =
((PESContext *)s->streams[stream_index]->priv_data)->pcr_pid;
- const int find_next = 1;
+ int pos47 = ts->pos47_full % ts->raw_packet_size;
pos =
- ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) *
- ts->raw_packet_size + ts->pos47;
- if (find_next) {
- for (;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
+ ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) *
+ ts->raw_packet_size + pos47;
+ while(pos < pos_limit) {
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+ if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
+ return AV_NOPTS_VALUE;
+ if (buf[0] != 0x47) {
+ avio_seek(s->pb, -TS_PACKET_SIZE, SEEK_CUR);
+ if (mpegts_resync(s) < 0)
return AV_NOPTS_VALUE;
- if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
- parse_pcr(&timestamp, &pcr_l, buf) == 0) {
- break;
- }
- pos += ts->raw_packet_size;
+ pos = avio_tell(s->pb);
+ continue;
}
- } else {
- for (;;) {
- pos -= ts->raw_packet_size;
- if (pos < 0)
- return AV_NOPTS_VALUE;
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
- return AV_NOPTS_VALUE;
- if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
- parse_pcr(&timestamp, &pcr_l, buf) == 0) {
- break;
- }
+ if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
+ parse_pcr(&timestamp, &pcr_l, buf) == 0) {
+ *ppos = pos;
+ return timestamp;
}
+ pos += ts->raw_packet_size;
}
- *ppos = pos;
- return timestamp;
+ return AV_NOPTS_VALUE;
}
-static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags)
+static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
+ int64_t *ppos, int64_t pos_limit)
{
MpegTSContext *ts = s->priv_data;
- uint8_t buf[TS_PACKET_SIZE];
int64_t pos;
- int ret;
-
- ret = ff_seek_frame_binary(s, stream_index, target_ts, flags);
- if (ret < 0)
- return ret;
-
- pos = avio_tell(s->pb);
-
- for (;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- ret = avio_read(s->pb, buf, TS_PACKET_SIZE);
+ int pos47 = ts->pos47_full % ts->raw_packet_size;
+ pos = ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) * ts->raw_packet_size + pos47;
+ ff_read_frame_flush(s);
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+ while(pos < pos_limit) {
+ int ret;
+ AVPacket pkt;
+ av_init_packet(&pkt);
+ ret = av_read_frame(s, &pkt);
if (ret < 0)
- return ret;
- if (ret != TS_PACKET_SIZE)
- return AVERROR_EOF;
- // pid = AV_RB16(buf + 1) & 0x1fff;
- if (buf[1] & 0x40)
- break;
- pos += ts->raw_packet_size;
+ return AV_NOPTS_VALUE;
+ av_free_packet(&pkt);
+ if (pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0) {
+ ff_reduce_index(s, pkt.stream_index);
+ av_add_index_entry(s->streams[pkt.stream_index], pkt.pos, pkt.dts, 0, 0, AVINDEX_KEYFRAME /* FIXME keyframe? */);
+ if (pkt.stream_index == stream_index && pkt.pos >= *ppos) {
+ *ppos = pkt.pos;
+ return pkt.dts;
+ }
+ }
+ pos = pkt.pos;
}
- avio_seek(s->pb, pos, SEEK_SET);
- return 0;
+ return AV_NOPTS_VALUE;
}
/**************************************************************/
/* parsing functions - called from other demuxers such as RTP */
-MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s)
+MpegTSContext *avpriv_mpegts_parse_open(AVFormatContext *s)
{
MpegTSContext *ts;
@@ -2333,22 +2764,23 @@ MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s)
ts->raw_packet_size = TS_PACKET_SIZE;
ts->stream = s;
ts->auto_guess = 1;
+ mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
+ mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
+
return ts;
}
/* return the consumed length if a packet was output, or -1 if no
* packet is output */
-int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
- const uint8_t *buf, int len)
+int avpriv_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
+ const uint8_t *buf, int len)
{
int len1;
len1 = len;
ts->pkt = pkt;
- ts->stop_parse = 0;
for (;;) {
- if (ts->stop_parse > 0)
- break;
+ ts->stop_parse = 0;
if (len < TS_PACKET_SIZE)
return AVERROR_INVALIDDATA;
if (buf[0] != 0x47) {
@@ -2358,12 +2790,14 @@ int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
handle_packet(ts, buf);
buf += TS_PACKET_SIZE;
len -= TS_PACKET_SIZE;
+ if (ts->stop_parse == 1)
+ break;
}
}
return len1 - len;
}
-void ff_mpegts_parse_close(MpegTSContext *ts)
+void avpriv_mpegts_parse_close(MpegTSContext *ts)
{
mpegts_free(ts);
av_free(ts);
@@ -2377,8 +2811,7 @@ AVInputFormat ff_mpegts_demuxer = {
.read_header = mpegts_read_header,
.read_packet = mpegts_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
.priv_class = &mpegts_class,
};
@@ -2390,8 +2823,7 @@ AVInputFormat ff_mpegtsraw_demuxer = {
.read_header = mpegts_read_header,
.read_packet = mpegts_raw_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
.priv_class = &mpegtsraw_class,
};
diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h
index 7dbbf8dfb0..84f30983c1 100644
--- a/libavformat/mpegts.h
+++ b/libavformat/mpegts.h
@@ -2,20 +2,20 @@
* MPEG2 transport stream defines
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,14 +58,15 @@
#define STREAM_TYPE_VIDEO_DIRAC 0xd1
#define STREAM_TYPE_AUDIO_AC3 0x81
-#define STREAM_TYPE_AUDIO_DTS 0x8a
+#define STREAM_TYPE_AUDIO_DTS 0x82
+#define STREAM_TYPE_AUDIO_TRUEHD 0x83
typedef struct MpegTSContext MpegTSContext;
-MpegTSContext *ff_mpegts_parse_open(AVFormatContext *s);
-int ff_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
- const uint8_t *buf, int len);
-void ff_mpegts_parse_close(MpegTSContext *ts);
+MpegTSContext *avpriv_mpegts_parse_open(AVFormatContext *s);
+int avpriv_mpegts_parse_packet(MpegTSContext *ts, AVPacket *pkt,
+ const uint8_t *buf, int len);
+void avpriv_mpegts_parse_close(MpegTSContext *ts);
typedef struct SLConfigDescr {
int use_au_start;
@@ -105,4 +106,10 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
MpegTSContext *ts);
+/**
+ * Check presence of H264 startcode
+ * @return <0 to stop processing
+ */
+int ff_check_h264_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt);
+
#endif /* AVFORMAT_MPEGTS_H */
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 75c93a7b51..9efa9fc362 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -2,23 +2,24 @@
* MPEG2 transport stream (aka DVB) muxer
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/bswap.h"
#include "libavutil/crc.h"
#include "libavutil/dict.h"
@@ -57,6 +58,16 @@ typedef struct MpegTSService {
int pcr_packet_period;
} MpegTSService;
+// service_type values as defined in ETSI 300 468
+enum {
+ MPEGTS_SERVICE_TYPE_DIGITAL_TV = 0x01,
+ MPEGTS_SERVICE_TYPE_DIGITAL_RADIO = 0x02,
+ MPEGTS_SERVICE_TYPE_TELETEXT = 0x03,
+ MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_RADIO = 0x0A,
+ MPEGTS_SERVICE_TYPE_MPEG2_DIGITAL_HDTV = 0x11,
+ MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_SDTV = 0x16,
+ MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_HDTV = 0x19
+};
typedef struct MpegTSWrite {
const AVClass *av_class;
MpegTSSection pat; /* MPEG2 pat table */
@@ -76,6 +87,7 @@ typedef struct MpegTSWrite {
int transport_stream_id;
int original_network_id;
int service_id;
+ int service_type;
int pmt_start_pid;
int start_pid;
@@ -87,6 +99,10 @@ typedef struct MpegTSWrite {
#define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
#define MPEGTS_FLAG_AAC_LATM 0x02
int flags;
+ int copyts;
+ int tables_version;
+
+ int omit_video_pes_length;
} MpegTSWrite;
/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -185,7 +201,7 @@ static int mpegts_write_section1(MpegTSSection *s, int tid, int id,
/*********************************************/
/* mpegts writer */
-#define DEFAULT_PROVIDER_NAME "Libav"
+#define DEFAULT_PROVIDER_NAME "FFmpeg"
#define DEFAULT_SERVICE_NAME "Service01"
/* we retransmit the SI info at this rate */
@@ -199,6 +215,7 @@ typedef struct MpegTSWriteStream {
int cc;
int payload_size;
int first_pts_check; ///< first pts check needed
+ int prev_payload_key;
int64_t payload_pts;
int64_t payload_dts;
int payload_flags;
@@ -220,11 +237,11 @@ static void mpegts_write_pat(AVFormatContext *s)
put16(&q, service->sid);
put16(&q, 0xe000 | service->pmt.pid);
}
- mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, 0, 0, 0,
+ mpegts_write_section1(&ts->pat, PAT_TID, ts->tsid, ts->tables_version, 0, 0,
data, q - data);
}
-static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
+static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
{
MpegTSWrite *ts = s->priv_data;
uint8_t data[SECTION_LENGTH], *q, *desc_length_ptr, *program_info_length_ptr;
@@ -247,7 +264,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
MpegTSWriteStream *ts_st = st->priv_data;
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
- if (q - data > SECTION_LENGTH - 3 - 2 - 6) {
+ if (q - data > SECTION_LENGTH - 32) {
err = 1;
break;
}
@@ -286,10 +303,17 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
case AV_CODEC_ID_AC3:
stream_type = STREAM_TYPE_AUDIO_AC3;
break;
+ case AV_CODEC_ID_DTS:
+ stream_type = STREAM_TYPE_AUDIO_DTS;
+ break;
+ case AV_CODEC_ID_TRUEHD:
+ stream_type = STREAM_TYPE_AUDIO_TRUEHD;
+ break;
default:
stream_type = STREAM_TYPE_PRIVATE_DATA;
break;
}
+
*q++ = stream_type;
put16(&q, 0xe000 | ts_st->pid);
desc_length_ptr = q;
@@ -298,6 +322,20 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
/* write optional descriptors here */
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
+ if (st->codec->codec_id==AV_CODEC_ID_EAC3) {
+ *q++=0x7a; // EAC3 descriptor see A038 DVB SI
+ *q++=1; // 1 byte, all flags sets to 0
+ *q++=0; // omit all fields...
+ }
+ if (st->codec->codec_id==AV_CODEC_ID_S302M) {
+ *q++ = 0x05; /* MPEG-2 registration descriptor*/
+ *q++ = 4;
+ *q++ = 'B';
+ *q++ = 'S';
+ *q++ = 'S';
+ *q++ = 'D';
+ }
+
if (lang) {
char *p;
char *next = lang->value;
@@ -338,26 +376,82 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
break;
case AVMEDIA_TYPE_SUBTITLE:
{
- const char *language;
- language = lang && strlen(lang->value) == 3 ? lang->value : "eng";
- *q++ = 0x59;
- *q++ = 8;
- *q++ = language[0];
- *q++ = language[1];
- *q++ = language[2];
- *q++ = 0x10; /* normal subtitles (0x20 = if hearing pb) */
-
- if (q - data > SECTION_LENGTH - 4) {
- err = 1;
- break;
- }
-
- if (st->codec->extradata_size == 4) {
- memcpy(q, st->codec->extradata, 4);
- q += 4;
- } else {
- put16(&q, 1); /* page id */
- put16(&q, 1); /* ancillary page id */
+ const char default_language[] = "und";
+ const char *language = lang && strlen(lang->value) >= 3 ? lang->value : default_language;
+
+ if (st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
+ uint8_t *len_ptr;
+ int extradata_copied = 0;
+
+ *q++ = 0x59; /* subtitling_descriptor */
+ len_ptr = q++;
+
+ while (strlen(language) >= 3) {
+ if (sizeof(data) - (q - data) < 8) { /* 8 bytes per DVB subtitle substream data */
+ err = 1;
+ break;
+ }
+ *q++ = *language++;
+ *q++ = *language++;
+ *q++ = *language++;
+ /* Skip comma */
+ if (*language != '\0')
+ language++;
+
+ if (st->codec->extradata_size - extradata_copied >= 5) {
+ *q++ = st->codec->extradata[extradata_copied + 4]; /* subtitling_type */
+ memcpy(q, st->codec->extradata + extradata_copied, 4); /* composition_page_id and ancillary_page_id */
+ extradata_copied += 5;
+ q += 4;
+ } else {
+ /* subtitling_type:
+ * 0x10 - normal with no monitor aspect ratio criticality
+ * 0x20 - for the hard of hearing with no monitor aspect ratio criticality */
+ *q++ = (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED) ? 0x20 : 0x10;
+ if ((st->codec->extradata_size == 4) && (extradata_copied == 0)) {
+ /* support of old 4-byte extradata format */
+ memcpy(q, st->codec->extradata, 4); /* composition_page_id and ancillary_page_id */
+ extradata_copied += 4;
+ q += 4;
+ } else {
+ put16(&q, 1); /* composition_page_id */
+ put16(&q, 1); /* ancillary_page_id */
+ }
+ }
+ }
+
+ *len_ptr = q - len_ptr - 1;
+ } else if (st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
+ uint8_t *len_ptr = NULL;
+ int extradata_copied = 0;
+
+ /* The descriptor tag. teletext_descriptor */
+ *q++ = 0x56;
+ len_ptr = q++;
+
+ while (strlen(language) >= 3 && q - data < sizeof(data) - 6) {
+ *q++ = *language++;
+ *q++ = *language++;
+ *q++ = *language++;
+ /* Skip comma */
+ if (*language != '\0')
+ language++;
+
+ if (st->codec->extradata_size - 1 > extradata_copied) {
+ memcpy(q, st->codec->extradata + extradata_copied, 2);
+ extradata_copied += 2;
+ q += 2;
+ } else {
+ /* The Teletext descriptor:
+ * teletext_type: This 5-bit field indicates the type of Teletext page indicated. (0x01 Initial Teletext page)
+ * teletext_magazine_number: This is a 3-bit field which identifies the magazine number.
+ * teletext_page_number: This is an 8-bit field giving two 4-bit hex digits identifying the page number. */
+ *q++ = 0x08;
+ *q++ = 0x00;
+ }
+ }
+
+ *len_ptr = q - len_ptr - 1;
}
}
break;
@@ -371,6 +465,16 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
*q++ = 'c';
}
break;
+ case AVMEDIA_TYPE_DATA:
+ if (st->codec->codec_id == AV_CODEC_ID_SMPTE_KLV) {
+ *q++ = 0x05; /* MPEG-2 registration descriptor */
+ *q++ = 4;
+ *q++ = 'K';
+ *q++ = 'L';
+ *q++ = 'V';
+ *q++ = 'A';
+ }
+ break;
}
val = 0xf000 | (q - desc_length_ptr - 2);
@@ -384,11 +488,12 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
"Try reducing the number of languages in the audio streams "
"or the total number of streams.\n", i);
- mpegts_write_section1(&service->pmt, PMT_TID, service->sid, 0, 0, 0,
+ mpegts_write_section1(&service->pmt, PMT_TID, service->sid, ts->tables_version, 0, 0,
data, q - data);
+ return 0;
}
-/* NOTE: str == NULL is accepted for an empty string */
+/* NOTE: !str is accepted for an empty string */
static void putstr8(uint8_t **q_ptr, const char *str)
{
uint8_t *q;
@@ -428,7 +533,7 @@ static void mpegts_write_sdt(AVFormatContext *s)
*q++ = 0x48;
desc_len_ptr = q;
q++;
- *q++ = 0x01; /* digital television service */
+ *q++ = ts->service_type;
putstr8(&q, service->provider_name);
putstr8(&q, service->name);
desc_len_ptr[0] = q - desc_len_ptr - 1;
@@ -439,7 +544,7 @@ static void mpegts_write_sdt(AVFormatContext *s)
desc_list_len_ptr[0] = val >> 8;
desc_list_len_ptr[1] = val;
}
- mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, 0, 0, 0,
+ mpegts_write_section1(&ts->sdt, SDT_TID, ts->tsid, ts->tables_version, 0, 0,
data, q - data);
}
@@ -457,14 +562,17 @@ static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid,
service->pcr_pid = 0x1fff;
service->provider_name = av_strdup(provider_name);
service->name = av_strdup(name);
- if (!service->provider_name || !service->name) {
- av_free(service->provider_name);
- av_free(service->name);
- av_free(service);
- return NULL;
- }
- dynarray_add(&ts->services, &ts->nb_services, service);
+ if (!service->provider_name || !service->name)
+ goto fail;
+ if (av_dynarray_add_nofree(&ts->services, &ts->nb_services, service) < 0)
+ goto fail;
+
return service;
+fail:
+ av_freep(&service->provider_name);
+ av_freep(&service->name);
+ av_free(service);
+ return NULL;
}
static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb)
@@ -542,10 +650,10 @@ static int mpegts_write_header(AVFormatContext *s)
ts->sdt.write_packet = section_write_packet;
ts->sdt.opaque = s;
- pids = av_malloc(s->nb_streams * sizeof(*pids));
+ pids = av_malloc_array(s->nb_streams, sizeof(*pids));
if (!pids) {
- av_free(service);
- return AVERROR(ENOMEM);
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
/* assign pids to each stream */
@@ -632,7 +740,7 @@ static int mpegts_write_header(AVFormatContext *s)
}
}
- av_free(pids);
+ av_freep(&pids);
/* if no video stream, use the first stream as PCR */
if (service->pcr_pid == 0x1fff && s->nb_streams > 0) {
@@ -650,9 +758,10 @@ static int mpegts_write_header(AVFormatContext *s)
ts->pat_packet_period = (ts->mux_rate * PAT_RETRANS_TIME) /
(TS_PACKET_SIZE * 8 * 1000);
- ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
+ if (ts->copyts < 1)
+ ts->first_pcr = av_rescale(s->max_delay, PCR_TIME_BASE, AV_TIME_BASE);
} else {
- /* Arbitrary values, PAT/PMT could be written on key frames */
+ /* Arbitrary values, PAT/PMT will also be written on video key frames */
ts->sdt_packet_period = 200;
ts->pat_packet_period = 40;
if (pcr_st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -670,6 +779,8 @@ static int mpegts_write_header(AVFormatContext *s)
service->pcr_packet_period =
ts_st->user_tb.den / (10 * ts_st->user_tb.num);
}
+ if (!service->pcr_packet_period)
+ service->pcr_packet_period = 1;
}
// output a PCR as soon as possible
@@ -694,13 +805,10 @@ static int mpegts_write_header(AVFormatContext *s)
}
}
- avio_flush(s->pb);
-
return 0;
fail:
- av_free(service);
- av_free(pids);
+ av_freep(&pids);
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
ts_st = st->priv_data;
@@ -713,11 +821,19 @@ fail:
}
av_freep(&st->priv_data);
}
+
+ for (i = 0; i < ts->nb_services; i++) {
+ service = ts->services[i];
+ av_freep(&service->provider_name);
+ av_freep(&service->name);
+ av_freep(&service);
+ }
+ av_freep(&ts->services);
return ret;
}
/* send SDT, PAT and PMT tables regulary */
-static void retransmit_si_info(AVFormatContext *s)
+static void retransmit_si_info(AVFormatContext *s, int force_pat)
{
MpegTSWrite *ts = s->priv_data;
int i;
@@ -726,7 +842,7 @@ static void retransmit_si_info(AVFormatContext *s)
ts->sdt_packet_count = 0;
mpegts_write_sdt(s);
}
- if (++ts->pat_packet_count == ts->pat_packet_period) {
+ if (++ts->pat_packet_count == ts->pat_packet_period || force_pat) {
ts->pat_packet_count = 0;
mpegts_write_pat(s);
for (i = 0; i < ts->nb_services; i++)
@@ -808,7 +924,7 @@ static void write_pts(uint8_t *q, int fourbits, int64_t pts)
static void set_af_flag(uint8_t *pkt, int flag)
{
// expect at least one flag to set
- assert(flag);
+ av_assert0(flag);
if ((pkt[3] & 0x20) == 0) {
// no AF yet, set adaptation field flag
@@ -824,7 +940,7 @@ static void set_af_flag(uint8_t *pkt, int flag)
static void extend_af(uint8_t *pkt, int size)
{
// expect already existing adaptation field
- assert(pkt[3] & 0x20);
+ av_assert0(pkt[3] & 0x20);
pkt[4] += size;
}
@@ -849,14 +965,16 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
MpegTSWrite *ts = s->priv_data;
uint8_t buf[TS_PACKET_SIZE];
uint8_t *q;
- int val, is_start, len, header_len, write_pcr, private_code, flags;
+ int val, is_start, len, header_len, write_pcr, is_dvb_subtitle, is_dvb_teletext, flags;
int afc_len, stuffing_len;
int64_t pcr = -1; /* avoid warning */
int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
+ int force_pat = st->codec->codec_type == AVMEDIA_TYPE_VIDEO && key && !ts_st->prev_payload_key;
is_start = 1;
while (payload_size > 0) {
- retransmit_si_info(s);
+ retransmit_si_info(s, force_pat);
+ force_pat = 0;
write_pcr = 0;
if (ts_st->pid == ts_st->service->pcr_pid) {
@@ -912,11 +1030,13 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
}
if (is_start) {
int pes_extension = 0;
+ int pes_header_stuffing_bytes = 0;
/* write PES header */
*q++ = 0x00;
*q++ = 0x00;
*q++ = 0x01;
- private_code = 0;
+ is_dvb_subtitle = 0;
+ is_dvb_teletext = 0;
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
if (st->codec->codec_id == AV_CODEC_ID_DIRAC)
*q++ = 0xfd;
@@ -927,10 +1047,19 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
st->codec->codec_id == AV_CODEC_ID_MP3 ||
st->codec->codec_id == AV_CODEC_ID_AAC)) {
*q++ = 0xc0;
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ st->codec->codec_id == AV_CODEC_ID_AC3 &&
+ ts->m2ts_mode) {
+ *q++ = 0xfd;
} else {
*q++ = 0xbd;
- if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
- private_code = 0x20;
+ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+ if (st->codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE) {
+ is_dvb_subtitle = 1;
+ } else if (st->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
+ is_dvb_teletext = 1;
+ }
+ }
}
header_len = 0;
flags = 0;
@@ -953,16 +1082,37 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
* one byte for extension id */
header_len += 3;
}
+ /* for Blu-ray AC3 Audio the PES Extension flag should be as follow
+ * otherwise it will not play sound on blu-ray
+ */
+ if (ts->m2ts_mode &&
+ st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ st->codec->codec_id == AV_CODEC_ID_AC3) {
+ /* set PES_extension_flag */
+ pes_extension = 1;
+ flags |= 0x01;
+ header_len += 3;
+ }
+ if (is_dvb_teletext) {
+ pes_header_stuffing_bytes = 0x24 - header_len;
+ header_len = 0x24;
+ }
len = payload_size + header_len + 3;
- if (private_code != 0)
- len++;
+ /* 3 extra bytes should be added to DVB subtitle payload: 0x20 0x00 at the beginning and trailing 0xff */
+ if (is_dvb_subtitle) {
+ len += 3;
+ payload_size++;
+ }
if (len > 0xffff)
len = 0;
+ if (ts->omit_video_pes_length && st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ len = 0;
+ }
*q++ = len >> 8;
*q++ = len;
val = 0x80;
- /* data alignment indicator is required for subtitle data */
- if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ /* data alignment indicator is required for subtitle and data streams */
+ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codec->codec_type == AVMEDIA_TYPE_DATA)
val |= 0x04;
*q++ = val;
*q++ = flags;
@@ -983,8 +1133,28 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
* write the extended stream ID. */
*q++ = 0x00 | 0x60;
}
- if (private_code != 0)
- *q++ = private_code;
+ /* For Blu-ray AC3 Audio Setting extended flags */
+ if (ts->m2ts_mode &&
+ pes_extension &&
+ st->codec->codec_id == AV_CODEC_ID_AC3) {
+ flags = 0x01; /* set PES_extension_flag_2 */
+ *q++ = flags;
+ *q++ = 0x80 | 0x01; /* marker bit + extension length */
+ *q++ = 0x00 | 0x71; /* for AC3 Audio (specifically on blue-rays) */
+ }
+
+
+ if (is_dvb_subtitle) {
+ /* First two fields of DVB subtitles PES data:
+ * data_identifier: for DVB subtitle streams shall be coded with the value 0x20
+ * subtitle_stream_id: for DVB subtitle stream shall be identified by the value 0x00 */
+ *q++ = 0x20;
+ *q++ = 0x00;
+ }
+ if (is_dvb_teletext) {
+ memset(q, 0xff, pes_header_stuffing_bytes);
+ q += pes_header_stuffing_bytes;
+ }
is_start = 0;
}
/* header size */
@@ -1015,13 +1185,50 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
}
}
}
- memcpy(buf + TS_PACKET_SIZE - len, payload, len);
+
+ if (is_dvb_subtitle && payload_size == len) {
+ memcpy(buf + TS_PACKET_SIZE - len, payload, len - 1);
+ buf[TS_PACKET_SIZE - 1] = 0xff; /* end_of_PES_data_field_marker: an 8-bit field with fixed contents 0xff for DVB subtitle */
+ } else {
+ memcpy(buf + TS_PACKET_SIZE - len, payload, len);
+ }
+
payload += len;
payload_size -= len;
mpegts_prefix_m2ts_header(s);
avio_write(s->pb, buf, TS_PACKET_SIZE);
}
- avio_flush(s->pb);
+ ts_st->prev_payload_key = key;
+}
+
+int ff_check_h264_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt)
+{
+ if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001 && AV_RB24(pkt->data) != 0x000001) {
+ if (!st->nb_frames) {
+ av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, "
+ "no startcode found, use the video bitstream filter 'h264_mp4toannexb' to fix it "
+ "('-bsf:v h264_mp4toannexb' option with ffmpeg)\n");
+ return AVERROR_INVALIDDATA;
+ }
+ av_log(s, AV_LOG_WARNING, "H.264 bitstream error, startcode missing, size %d", pkt->size);
+ if (pkt->size) av_log(s, AV_LOG_WARNING, " data %08X", AV_RB32(pkt->data));
+ av_log(s, AV_LOG_WARNING, "\n");
+ }
+ return 0;
+}
+
+static int check_hevc_startcode(AVFormatContext *s, const AVStream *st, const AVPacket *pkt)
+{
+ if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001 && AV_RB24(pkt->data) != 0x000001) {
+ if (!st->nb_frames) {
+ av_log(s, AV_LOG_ERROR, "HEVC bitstream malformed, no startcode found\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ av_log(s, AV_LOG_WARNING, "HEVC bitstream error, startcode missing, size %d", pkt->size);
+ if (pkt->size) av_log(s, AV_LOG_WARNING, " data %08X", AV_RB32(pkt->data));
+ av_log(s, AV_LOG_WARNING, "\n");
+ }
+ return 0;
}
static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
@@ -1032,8 +1239,8 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
uint8_t *data = NULL;
MpegTSWrite *ts = s->priv_data;
MpegTSWriteStream *ts_st = st->priv_data;
- const uint64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE) * 2;
- int64_t dts = AV_NOPTS_VALUE, pts = AV_NOPTS_VALUE;
+ const int64_t delay = av_rescale(s->max_delay, 90000, AV_TIME_BASE) * 2;
+ int64_t dts = pkt->dts, pts = pkt->pts;
if (ts->reemit_pat_pmt) {
av_log(s, AV_LOG_WARNING,
@@ -1048,13 +1255,15 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
ts->flags &= ~MPEGTS_FLAG_REEMIT_PAT_PMT;
}
- if (pkt->pts != AV_NOPTS_VALUE)
- pts = pkt->pts + delay;
- if (pkt->dts != AV_NOPTS_VALUE)
- dts = pkt->dts + delay;
+ if (ts->copyts < 1) {
+ if (pts != AV_NOPTS_VALUE)
+ pts += delay;
+ if (dts != AV_NOPTS_VALUE)
+ dts += delay;
+ }
if (ts_st->first_pts_check && pts == AV_NOPTS_VALUE) {
- av_log(s, AV_LOG_ERROR, "first pts value must set\n");
+ av_log(s, AV_LOG_ERROR, "first pts value must be set\n");
return AVERROR_INVALIDDATA;
}
ts_st->first_pts_check = 0;
@@ -1062,29 +1271,35 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
if (st->codec->codec_id == AV_CODEC_ID_H264) {
const uint8_t *p = buf, *buf_end = p + size;
uint32_t state = -1;
+ int extradd = (pkt->flags & AV_PKT_FLAG_KEY) ? st->codec->extradata_size : 0;
+ int ret = ff_check_h264_startcode(s, st, pkt);
+ if (ret < 0)
+ return ret;
- if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) {
- av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, "
- "no startcode found, use -bsf h264_mp4toannexb\n");
- return AVERROR_INVALIDDATA;
- }
+ if (extradd && AV_RB24(st->codec->extradata) > 1)
+ extradd = 0;
do {
p = avpriv_find_start_code(p, buf_end, &state);
av_log(s, AV_LOG_TRACE, "nal %d\n", state & 0x1f);
+ if ((state & 0x1f) == 7)
+ extradd = 0;
} while (p < buf_end && (state & 0x1f) != 9 &&
(state & 0x1f) != 5 && (state & 0x1f) != 1);
+ if ((state & 0x1f) != 5)
+ extradd = 0;
if ((state & 0x1f) != 9) { // AUD NAL
- data = av_malloc(pkt->size + 6);
+ data = av_malloc(pkt->size + 6 + extradd);
if (!data)
return AVERROR(ENOMEM);
- memcpy(data + 6, pkt->data, pkt->size);
+ memcpy(data + 6, st->codec->extradata, extradd);
+ memcpy(data + 6 + extradd, pkt->data, pkt->size);
AV_WB32(data, 0x00000001);
data[4] = 0x09;
data[5] = 0xf0; // any slice type (0xe) + rbsp stop one bit
buf = data;
- size = pkt->size + 6;
+ size = pkt->size + 6 + extradd;
}
} else if (st->codec->codec_id == AV_CODEC_ID_AAC) {
if (pkt->size < 2) {
@@ -1104,6 +1319,8 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
av_init_packet(&pkt2);
pkt2.data = pkt->data;
pkt2.size = pkt->size;
+ av_assert0(pkt->dts != AV_NOPTS_VALUE);
+ pkt2.dts = av_rescale_q(pkt->dts, st->time_base, ts_st->amux->streams[0]->time_base);
ret = avio_open_dyn_buf(&ts_st->amux->pb);
if (ret < 0)
@@ -1118,9 +1335,39 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
ts_st->amux->pb = NULL;
buf = data;
}
+ } else if (st->codec->codec_id == AV_CODEC_ID_HEVC) {
+ int ret = check_hevc_startcode(s, st, pkt);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (pkt->dts != AV_NOPTS_VALUE) {
+ int i;
+ for(i=0; i<s->nb_streams; i++) {
+ AVStream *st2 = s->streams[i];
+ MpegTSWriteStream *ts_st2 = st2->priv_data;
+ if ( ts_st2->payload_size
+ && (ts_st2->payload_dts == AV_NOPTS_VALUE || dts - ts_st2->payload_dts > delay/2)) {
+ mpegts_write_pes(s, st2, ts_st2->payload, ts_st2->payload_size,
+ ts_st2->payload_pts, ts_st2->payload_dts,
+ ts_st2->payload_flags & AV_PKT_FLAG_KEY);
+ ts_st2->payload_size = 0;
+ }
+ }
+ }
+
+ if (ts_st->payload_size && (ts_st->payload_size + size > ts->pes_payload_size ||
+ (dts != AV_NOPTS_VALUE && ts_st->payload_dts != AV_NOPTS_VALUE &&
+ av_compare_ts(dts - ts_st->payload_dts, st->time_base,
+ s->max_delay, AV_TIME_BASE_Q) >= 0))) {
+ mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size,
+ ts_st->payload_pts, ts_st->payload_dts,
+ ts_st->payload_flags & AV_PKT_FLAG_KEY);
+ ts_st->payload_size = 0;
}
- if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO || size > ts->pes_payload_size) {
+ av_assert0(!ts_st->payload_size);
// for video and subtitle, write a single pes packet
mpegts_write_pes(s, st, buf, size, pts, dts,
pkt->flags & AV_PKT_FLAG_KEY);
@@ -1128,24 +1375,6 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
return 0;
}
- if (ts_st->payload_size + size > ts->pes_payload_size ||
- (dts != AV_NOPTS_VALUE && ts_st->payload_dts != AV_NOPTS_VALUE &&
- av_compare_ts(dts - ts_st->payload_dts, st->time_base,
- s->max_delay, AV_TIME_BASE_Q) >= 0)) {
- if (ts_st->payload_size) {
- mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_size,
- ts_st->payload_pts, ts_st->payload_dts,
- ts_st->payload_flags & AV_PKT_FLAG_KEY);
- ts_st->payload_size = 0;
- }
- if (size > ts->pes_payload_size) {
- mpegts_write_pes(s, st, buf, size, pts, dts,
- pkt->flags & AV_PKT_FLAG_KEY);
- av_free(data);
- return 0;
- }
- }
-
if (!ts_st->payload_size) {
ts_st->payload_pts = pts;
ts_st->payload_dts = dts;
@@ -1175,7 +1404,6 @@ static void mpegts_write_flush(AVFormatContext *s)
ts_st->payload_size = 0;
}
}
- avio_flush(s->pb);
}
static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt)
@@ -1211,9 +1439,9 @@ static int mpegts_write_end(AVFormatContext *s)
service = ts->services[i];
av_freep(&service->provider_name);
av_freep(&service->name);
- av_free(service);
+ av_freep(&service);
}
- av_free(ts->services);
+ av_freep(&ts->services);
return 0;
}
@@ -1228,15 +1456,39 @@ static const AVOption options[] = {
{ "mpegts_service_id", "Set service_id field.",
offsetof(MpegTSWrite, service_id), AV_OPT_TYPE_INT,
{ .i64 = 0x0001 }, 0x0001, 0xffff, AV_OPT_FLAG_ENCODING_PARAM },
+ { "mpegts_service_type", "Set service_type field.",
+ offsetof(MpegTSWrite, service_type), AV_OPT_TYPE_INT,
+ { .i64 = 0x01 }, 0x01, 0xff, AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "digital_tv", "Digital Television.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_TV }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "digital_radio", "Digital Radio.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_DIGITAL_RADIO }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "teletext", "Teletext.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_TELETEXT }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "advanced_codec_digital_radio", "Advanced Codec Digital Radio.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_RADIO }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "mpeg2_digital_hdtv", "MPEG2 Digital HDTV.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_MPEG2_DIGITAL_HDTV }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "advanced_codec_digital_sdtv", "Advanced Codec Digital SDTV.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_SDTV }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
+ { "advanced_codec_digital_hdtv", "Advanced Codec Digital HDTV.",
+ 0, AV_OPT_TYPE_CONST, { .i64 = MPEGTS_SERVICE_TYPE_ADVANCED_CODEC_DIGITAL_HDTV }, 0x01, 0xff,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_service_type" },
{ "mpegts_pmt_start_pid", "Set the first pid of the PMT.",
offsetof(MpegTSWrite, pmt_start_pid), AV_OPT_TYPE_INT,
- { .i64 = 0x1000 }, 0x1000, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM },
+ { .i64 = 0x1000 }, 0x0010, 0x1f00, AV_OPT_FLAG_ENCODING_PARAM },
{ "mpegts_start_pid", "Set the first pid.",
offsetof(MpegTSWrite, start_pid), AV_OPT_TYPE_INT,
- { .i64 = 0x0100 }, 0x0100, 0x0f00, AV_OPT_FLAG_ENCODING_PARAM },
- {"mpegts_m2ts_mode", "Enable m2ts mode.",
+ { .i64 = 0x0100 }, 0x0020, 0x0f00, AV_OPT_FLAG_ENCODING_PARAM },
+ { "mpegts_m2ts_mode", "Enable m2ts mode.",
offsetof(MpegTSWrite, m2ts_mode), AV_OPT_TYPE_INT,
- { .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
+ { .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM },
{ "muxrate", NULL,
offsetof(MpegTSWrite, mux_rate), AV_OPT_TYPE_INT,
{ .i64 = 1 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
@@ -1256,6 +1508,15 @@ static const AVOption options[] = {
{ "resend_headers", "Reemit PAT/PMT before writing the next packet",
offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT,
{ .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "mpegts_copyts", "don't offset dts/pts",
+ offsetof(MpegTSWrite, copyts), AV_OPT_TYPE_INT,
+ { .i64 = -1 }, -1, 1, AV_OPT_FLAG_ENCODING_PARAM },
+ { "tables_version", "set PAT, PMT and SDT version",
+ offsetof(MpegTSWrite, tables_version), AV_OPT_TYPE_INT,
+ { .i64 = 0 }, 0, 31, AV_OPT_FLAG_ENCODING_PARAM },
+ { "omit_video_pes_length", "Omit the PES packet length for video packets",
+ offsetof(MpegTSWrite, omit_video_pes_length), AV_OPT_TYPE_INT,
+ { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
{ "pcr_period", "PCR retransmission time",
offsetof(MpegTSWrite, pcr_period), AV_OPT_TYPE_INT,
{ .i64 = PCR_RETRANS_TIME }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
diff --git a/libavformat/mpegvideodec.c b/libavformat/mpegvideodec.c
index 96b95a58f1..aca962123b 100644
--- a/libavformat/mpegvideodec.c
+++ b/libavformat/mpegvideodec.c
@@ -3,26 +3,29 @@
* Copyright (c) 2002-2003 Fabrice Bellard
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "rawdec.h"
+#include "libavutil/intreadwrite.h"
+#include "libavcodec/internal.h"
+
#define SEQ_START_CODE 0x000001b3
#define GOP_START_CODE 0x000001b8
#define PICTURE_START_CODE 0x00000100
@@ -34,24 +37,54 @@
static int mpegvideo_probe(AVProbeData *p)
{
uint32_t code= -1;
- int pic=0, seq=0, slice=0, pspack=0, pes=0;
- int i;
+ int pic=0, seq=0, slice=0, pspack=0, vpes=0, apes=0, res=0, sicle=0;
+ const uint8_t *ptr = p->buf, *end = ptr + p->buf_size;
+ uint32_t last = 0;
+ int j;
- for(i=0; i<p->buf_size; i++){
- code = (code<<8) + p->buf[i];
+ while (ptr < end) {
+ ptr = avpriv_find_start_code(ptr, end, &code);
if ((code & 0xffffff00) == 0x100) {
switch(code){
- case SEQ_START_CODE: seq++; break;
+ case SEQ_START_CODE:
+ if (!(ptr[3 + 1 + 2] & 0x20))
+ break;
+ j = -1;
+ if (ptr[j + 8] & 2)
+ j+= 64;
+ if (j >= end - ptr)
+ break;
+ if (ptr[j + 8] & 1)
+ j+= 64;
+ if (j >= end - ptr)
+ break;
+ if (AV_RB24(ptr + j + 9) & 0xFFFFFE)
+ break;
+ seq++;
+ break;
case PICTURE_START_CODE: pic++; break;
- case SLICE_START_CODE: slice++; break;
case PACK_START_CODE: pspack++; break;
+ case 0x1b6:
+ res++; break;
+ }
+ if (code >= SLICE_START_CODE && code <= 0x1af) {
+ if (last >= SLICE_START_CODE && last <= 0x1af) {
+ if (code >= last) slice++;
+ else sicle++;
+ }else{
+ if (code == SLICE_START_CODE) slice++;
+ else sicle++;
+ }
}
- if ((code & 0x1f0) == VIDEO_ID) pes++;
- else if((code & 0x1e0) == AUDIO_ID) pes++;
+ if ((code & 0x1f0) == VIDEO_ID) vpes++;
+ else if((code & 0x1e0) == AUDIO_ID) apes++;
+ last = code;
}
}
- if(seq && seq*9<=pic*10 && pic*9<=slice*10 && !pspack && !pes)
- return pic>1 ? AVPROBE_SCORE_EXTENSION + 1 : AVPROBE_SCORE_EXTENSION / 2; // 1 more than .mpg
+ if(seq && seq*9<=pic*10 && pic*9<=slice*10 && !pspack && !apes && !res && slice > sicle) {
+ if(vpes) return AVPROBE_SCORE_EXTENSION / 4;
+ else return pic>1 ? AVPROBE_SCORE_EXTENSION + 1 : AVPROBE_SCORE_EXTENSION / 2; // +1 for .mpg
+ }
return 0;
}
diff --git a/libavformat/mpjpeg.c b/libavformat/mpjpeg.c
index 9e21099eaf..7b975e28d6 100644
--- a/libavformat/mpjpeg.c
+++ b/libavformat/mpjpeg.c
@@ -2,33 +2,40 @@
* Multipart JPEG format
* Copyright (c) 2000, 2001, 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avformat.h"
/* Multipart JPEG */
-#define BOUNDARY_TAG "avserver"
+#define BOUNDARY_TAG "ffserver"
+
+typedef struct MPJPEGContext {
+ AVClass *class;
+ char *boundary_tag;
+} MPJPEGContext;
static int mpjpeg_write_header(AVFormatContext *s)
{
+ MPJPEGContext *mpj = s->priv_data;
uint8_t buf1[256];
- snprintf(buf1, sizeof(buf1), "--%s\n", BOUNDARY_TAG);
+ snprintf(buf1, sizeof(buf1), "--%s\r\n", mpj->boundary_tag);
avio_write(s->pb, buf1, strlen(buf1));
avio_flush(s->pb);
return 0;
@@ -36,13 +43,17 @@ static int mpjpeg_write_header(AVFormatContext *s)
static int mpjpeg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
+ MPJPEGContext *mpj = s->priv_data;
uint8_t buf1[256];
- snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\n\n");
+ snprintf(buf1, sizeof(buf1), "Content-type: image/jpeg\r\n");
+ avio_write(s->pb, buf1, strlen(buf1));
+
+ snprintf(buf1, sizeof(buf1), "Content-length: %d\r\n\r\n", pkt->size);
avio_write(s->pb, buf1, strlen(buf1));
avio_write(s->pb, pkt->data, pkt->size);
- snprintf(buf1, sizeof(buf1), "\n--%s\n", BOUNDARY_TAG);
+ snprintf(buf1, sizeof(buf1), "\r\n--%s\r\n", mpj->boundary_tag);
avio_write(s->pb, buf1, strlen(buf1));
return 0;
}
@@ -52,15 +63,29 @@ static int mpjpeg_write_trailer(AVFormatContext *s)
return 0;
}
+static const AVOption options[] = {
+ { "boundary_tag", "Boundary tag", offsetof(MPJPEGContext, boundary_tag), AV_OPT_TYPE_STRING, {.str = BOUNDARY_TAG}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+static const AVClass mpjpeg_muxer_class = {
+ .class_name = "mpjpeg_muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_mpjpeg_muxer = {
.name = "mpjpeg",
.long_name = NULL_IF_CONFIG_SMALL("MIME multipart JPEG"),
.mime_type = "multipart/x-mixed-replace;boundary=" BOUNDARY_TAG,
.extensions = "mjpg",
+ .priv_data_size = sizeof(MPJPEGContext),
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_MJPEG,
.write_header = mpjpeg_write_header,
.write_packet = mpjpeg_write_packet,
.write_trailer = mpjpeg_write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
+ .priv_class = &mpjpeg_muxer_class,
};
diff --git a/libavformat/mpl2dec.c b/libavformat/mpl2dec.c
new file mode 100644
index 0000000000..260b7be0ec
--- /dev/null
+++ b/libavformat/mpl2dec.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * MPL2 subtitles format demuxer
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} MPL2Context;
+
+static int mpl2_probe(AVProbeData *p)
+{
+ int i;
+ char c;
+ int64_t start, end;
+ const unsigned char *ptr = p->buf;
+ const unsigned char *ptr_end = ptr + p->buf_size;
+
+ for (i = 0; i < 2; i++) {
+ if (sscanf(ptr, "[%"SCNd64"][%"SCNd64"]%c", &start, &end, &c) != 3 &&
+ sscanf(ptr, "[%"SCNd64"][]%c", &start, &c) != 2)
+ return 0;
+ ptr += ff_subtitles_next_line(ptr);
+ if (ptr >= ptr_end)
+ return 0;
+ }
+ return AVPROBE_SCORE_MAX;
+}
+
+static int read_ts(char **line, int64_t *pts_start, int *duration)
+{
+ char c;
+ int len;
+ int64_t end;
+
+ if (sscanf(*line, "[%"SCNd64"][]%c%n",
+ pts_start, &c, &len) >= 2) {
+ *duration = -1;
+ *line += len - 1;
+ return 0;
+ }
+ if (sscanf(*line, "[%"SCNd64"][%"SCNd64"]%c%n",
+ pts_start, &end, &c, &len) >= 3) {
+ *duration = end - *pts_start;
+ *line += len - 1;
+ return 0;
+ }
+ return -1;
+}
+
+static int mpl2_read_header(AVFormatContext *s)
+{
+ MPL2Context *mpl2 = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ int res = 0;
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 10);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_MPL2;
+
+ while (!avio_feof(s->pb)) {
+ char line[4096];
+ char *p = line;
+ const int64_t pos = avio_tell(s->pb);
+ int len = ff_get_line(s->pb, line, sizeof(line));
+ int64_t pts_start;
+ int duration;
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ if (!read_ts(&p, &pts_start, &duration)) {
+ AVPacket *sub;
+
+ sub = ff_subtitles_queue_insert(&mpl2->q, p, strlen(p), 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ sub->pts = pts_start;
+ sub->duration = duration;
+ }
+ }
+
+ ff_subtitles_queue_finalize(&mpl2->q);
+ return res;
+}
+
+static int mpl2_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MPL2Context *mpl2 = s->priv_data;
+ return ff_subtitles_queue_read_packet(&mpl2->q, pkt);
+}
+
+static int mpl2_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ MPL2Context *mpl2 = s->priv_data;
+ return ff_subtitles_queue_seek(&mpl2->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int mpl2_read_close(AVFormatContext *s)
+{
+ MPL2Context *mpl2 = s->priv_data;
+ ff_subtitles_queue_clean(&mpl2->q);
+ return 0;
+}
+
+AVInputFormat ff_mpl2_demuxer = {
+ .name = "mpl2",
+ .long_name = NULL_IF_CONFIG_SMALL("MPL2 subtitles"),
+ .priv_data_size = sizeof(MPL2Context),
+ .read_probe = mpl2_probe,
+ .read_header = mpl2_read_header,
+ .read_packet = mpl2_read_packet,
+ .read_seek2 = mpl2_read_seek,
+ .read_close = mpl2_read_close,
+ .extensions = "txt,mpl2",
+};
diff --git a/libavformat/mpsubdec.c b/libavformat/mpsubdec.c
new file mode 100644
index 0000000000..eddc594067
--- /dev/null
+++ b/libavformat/mpsubdec.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * MPlayer subtitles format demuxer
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} MPSubContext;
+
+static int mpsub_probe(AVProbeData *p)
+{
+ const char *ptr = p->buf;
+ const char *ptr_end = p->buf + p->buf_size;
+
+ while (ptr < ptr_end) {
+ int inc;
+
+ if (!memcmp(ptr, "FORMAT=TIME", 11))
+ return AVPROBE_SCORE_EXTENSION;
+ if (!memcmp(ptr, "FORMAT=", 7))
+ return AVPROBE_SCORE_EXTENSION / 3;
+ inc = ff_subtitles_next_line(ptr);
+ if (!inc)
+ break;
+ ptr += inc;
+ }
+ return 0;
+}
+
+static int mpsub_read_header(AVFormatContext *s)
+{
+ MPSubContext *mpsub = s->priv_data;
+ AVStream *st;
+ AVBPrint buf;
+ AVRational pts_info = (AVRational){ 100, 1 }; // ts based by default
+ int res = 0;
+ float multiplier = 100.0;
+ float current_pts = 0;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ while (!avio_feof(s->pb)) {
+ char line[1024];
+ float start, duration;
+ int fps, len = ff_get_line(s->pb, line, sizeof(line));
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ if (sscanf(line, "FORMAT=%d", &fps) == 1 && fps > 3 && fps < 100) {
+ /* frame based timing */
+ pts_info = (AVRational){ fps, 1 };
+ multiplier = 1.0;
+ } else if (sscanf(line, "%f %f", &start, &duration) == 2) {
+ AVPacket *sub;
+ const int64_t pos = avio_tell(s->pb);
+
+ ff_subtitles_read_chunk(s->pb, &buf);
+ if (buf.len) {
+ sub = ff_subtitles_queue_insert(&mpsub->q, buf.str, buf.len, 0);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ sub->pts = (int64_t)(current_pts + start*multiplier);
+ sub->duration = (int)(duration * multiplier);
+ current_pts += (start + duration) * multiplier;
+ sub->pos = pos;
+ }
+ }
+ }
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_TEXT;
+
+ ff_subtitles_queue_finalize(&mpsub->q);
+
+end:
+ av_bprint_finalize(&buf, NULL);
+ return res;
+}
+
+static int mpsub_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MPSubContext *mpsub = s->priv_data;
+ return ff_subtitles_queue_read_packet(&mpsub->q, pkt);
+}
+
+static int mpsub_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ MPSubContext *mpsub = s->priv_data;
+ return ff_subtitles_queue_seek(&mpsub->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int mpsub_read_close(AVFormatContext *s)
+{
+ MPSubContext *mpsub = s->priv_data;
+ ff_subtitles_queue_clean(&mpsub->q);
+ return 0;
+}
+
+AVInputFormat ff_mpsub_demuxer = {
+ .name = "mpsub",
+ .long_name = NULL_IF_CONFIG_SMALL("MPlayer subtitles"),
+ .priv_data_size = sizeof(MPSubContext),
+ .read_probe = mpsub_probe,
+ .read_header = mpsub_read_header,
+ .read_packet = mpsub_read_packet,
+ .read_seek2 = mpsub_read_seek,
+ .read_close = mpsub_read_close,
+ .extensions = "sub",
+};
diff --git a/libavformat/msnwc_tcp.c b/libavformat/msnwc_tcp.c
index b6d30feb9d..60225af61c 100644
--- a/libavformat/msnwc_tcp.c
+++ b/libavformat/msnwc_tcp.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2008 Ramiro Polla
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -89,10 +89,10 @@ static int msnwc_tcp_read_header(AVFormatContext *ctx)
/* Some files start with "connected\r\n\r\n".
* So skip until we find the first byte of struct size */
- while(avio_r8(pb) != HEADER_SIZE && !pb->eof_reached);
+ while(avio_r8(pb) != HEADER_SIZE && !avio_feof(pb));
- if(pb->eof_reached) {
- av_log(ctx, AV_LOG_ERROR, "Could not find valid start.");
+ if(avio_feof(pb)) {
+ av_log(ctx, AV_LOG_ERROR, "Could not find valid start.\n");
return -1;
}
diff --git a/libavformat/mtv.c b/libavformat/mtv.c
index aad30d7a41..a91e4c8649 100644
--- a/libavformat/mtv.c
+++ b/libavformat/mtv.c
@@ -2,20 +2,20 @@
* mtv demuxer
* Copyright (c) 2006 Reynaldo H. Verdejo Pinochet
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,7 +32,8 @@
#define MTV_ASUBCHUNK_DATA_SIZE 500
#define MTV_HEADER_SIZE 512
#define MTV_AUDIO_PADDING_SIZE 12
-#define AUDIO_SAMPLING_RATE 44100
+#define MTV_IMAGE_DEFAULT_BPP 16
+#define MTV_AUDIO_SAMPLING_RATE 44100
typedef struct MTVDemuxContext {
@@ -42,20 +43,30 @@ typedef struct MTVDemuxContext {
unsigned int audio_br; ///< bitrate of audio channel (mp3)
unsigned int img_colorfmt; ///< frame colorfmt rgb 565/555
unsigned int img_bpp; ///< frame bits per pixel
- unsigned int img_width; //
- unsigned int img_height; //
+ unsigned int img_width;
+ unsigned int img_height;
unsigned int img_segment_size; ///< size of image segment
- unsigned int video_fps; //
+ unsigned int video_fps;
unsigned int full_segment_size;
} MTVDemuxContext;
static int mtv_probe(AVProbeData *p)
{
+ /* we need at least 57 bytes from the header
+ * to try parsing all required fields
+ */
+ if (p->buf_size < 57)
+ return 0;
+
/* Magic is 'AMV' */
if (*p->buf != 'A' || *(p->buf + 1) != 'M' || *(p->buf + 2) != 'V')
return 0;
+ /* Audio magic is always MP3 */
+ if (p->buf[43] != 'M' || p->buf[44] != 'P' || p->buf[45] != '3')
+ return 0;
+
/* Check for nonzero in bpp and (width|height) header fields */
if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54])))
return 0;
@@ -69,8 +80,20 @@ static int mtv_probe(AVProbeData *p)
return 0;
}
- if(p->buf[51] != 16)
- return AVPROBE_SCORE_EXTENSION / 2; // But we are going to assume 16bpp anyway ..
+ /* Image bpp is not an absolutely required
+ * field as we latter claim it should be 16
+ * no matter what. All samples in the wild
+ * are RGB565/555.
+ */
+ if(p->buf[51] != MTV_IMAGE_DEFAULT_BPP)
+ return AVPROBE_SCORE_EXTENSION / 2;
+
+ /* We had enough data to parse header values
+ * but we expect to be able to get 512 bytes
+ * of header to be sure.
+ */
+ if (p->buf_size < MTV_HEADER_SIZE)
+ return AVPROBE_SCORE_EXTENSION;
return AVPROBE_SCORE_MAX;
}
@@ -94,6 +117,15 @@ static int mtv_read_header(AVFormatContext *s)
mtv->img_height = avio_rl16(pb);
mtv->img_segment_size = avio_rl16(pb);
+ /* Assume 16bpp even if claimed otherwise.
+ * We know its going to be RGBG565/555 anyway
+ */
+ if (mtv->img_bpp != MTV_IMAGE_DEFAULT_BPP) {
+ av_log (s, AV_LOG_WARNING, "Header claims %dbpp (!= 16). Ignoring\n",
+ mtv->img_bpp);
+ mtv->img_bpp = MTV_IMAGE_DEFAULT_BPP;
+ }
+
/* Calculate width and height if missing from header */
if (!mtv->img_width && mtv->img_height > 0 && mtv->img_bpp >= 8)
@@ -104,8 +136,10 @@ static int mtv_read_header(AVFormatContext *s)
mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
/ mtv->img_width;
- if (!mtv->img_width || !mtv->img_height)
+ if(!mtv->img_height || !mtv->img_width || !mtv->img_segment_size){
+ av_log(s, AV_LOG_ERROR, "width or height or segment_size is invalid and I cannot calculate them from other information\n");
return AVERROR_INVALIDDATA;
+ }
avio_skip(pb, 4);
audio_subsegments = avio_rl16(pb);
@@ -145,7 +179,7 @@ static int mtv_read_header(AVFormatContext *s)
if(!st)
return AVERROR(ENOMEM);
- avpriv_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE);
+ avpriv_set_pts_info(st, 64, 1, MTV_AUDIO_SAMPLING_RATE);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_MP3;
st->codec->bit_rate = mtv->audio_br;
diff --git a/libavformat/mux.c b/libavformat/mux.c
index 25d69d5ef4..f99dbd9c07 100644
--- a/libavformat/mux.c
+++ b/libavformat/mux.c
@@ -1,21 +1,21 @@
/*
- * muxing functions for use within Libav
+ * muxing functions for use within FFmpeg
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/timestamp.h"
#include "metadata.h"
#include "id3v2.h"
#include "libavutil/avassert.h"
@@ -43,20 +44,166 @@
#include "network.h"
#endif
-#undef NDEBUG
-#include <assert.h>
-
/**
* @file
- * muxing functions for use within Libav
+ * muxing functions for use within libavformat
+ */
+
+/* fraction handling */
+
+/**
+ * f = val + (num / den) + 0.5.
+ *
+ * 'num' is normalized so that it is such as 0 <= num < den.
+ *
+ * @param f fractional number
+ * @param val integer value
+ * @param num must be >= 0
+ * @param den must be >= 1
+ */
+static void frac_init(AVFrac *f, int64_t val, int64_t num, int64_t den)
+{
+ num += (den >> 1);
+ if (num >= den) {
+ val += num / den;
+ num = num % den;
+ }
+ f->val = val;
+ f->num = num;
+ f->den = den;
+}
+
+/**
+ * Fractional addition to f: f = f + (incr / f->den).
+ *
+ * @param f fractional number
+ * @param incr increment, can be positive or negative
*/
+static void frac_add(AVFrac *f, int64_t incr)
+{
+ int64_t num, den;
+
+ num = f->num + incr;
+ den = f->den;
+ if (num < 0) {
+ f->val += num / den;
+ num = num % den;
+ if (num < 0) {
+ num += den;
+ f->val--;
+ }
+ } else if (num >= den) {
+ f->val += num / den;
+ num = num % den;
+ }
+ f->num = num;
+}
+
+AVRational ff_choose_timebase(AVFormatContext *s, AVStream *st, int min_precision)
+{
+ AVRational q;
+ int j;
+
+ q = st->time_base;
+
+ for (j=2; j<14; j+= 1+(j>2))
+ while (q.den / q.num < min_precision && q.num % j == 0)
+ q.num /= j;
+ while (q.den / q.num < min_precision && q.den < (1<<24))
+ q.den <<= 1;
+
+ return q;
+}
+
+enum AVChromaLocation ff_choose_chroma_location(AVFormatContext *s, AVStream *st)
+{
+ AVCodecContext *avctx = st->codec;
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+
+ if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED)
+ return avctx->chroma_sample_location;
+
+ if (pix_desc) {
+ if (pix_desc->log2_chroma_h == 0) {
+ return AVCHROMA_LOC_TOPLEFT;
+ } else if (pix_desc->log2_chroma_w == 1 && pix_desc->log2_chroma_h == 1) {
+ if (avctx->field_order == AV_FIELD_UNKNOWN || avctx->field_order == AV_FIELD_PROGRESSIVE) {
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_MJPEG:
+ case AV_CODEC_ID_MPEG1VIDEO: return AVCHROMA_LOC_CENTER;
+ }
+ }
+ if (avctx->field_order == AV_FIELD_UNKNOWN || avctx->field_order != AV_FIELD_PROGRESSIVE) {
+ switch (avctx->codec_id) {
+ case AV_CODEC_ID_MPEG2VIDEO: return AVCHROMA_LOC_LEFT;
+ }
+ }
+ }
+ }
+
+ return AVCHROMA_LOC_UNSPECIFIED;
+
+}
+
+int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat,
+ const char *format, const char *filename)
+{
+ AVFormatContext *s = avformat_alloc_context();
+ int ret = 0;
+
+ *avctx = NULL;
+ if (!s)
+ goto nomem;
+
+ if (!oformat) {
+ if (format) {
+ oformat = av_guess_format(format, NULL, NULL);
+ if (!oformat) {
+ av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
+ ret = AVERROR(EINVAL);
+ goto error;
+ }
+ } else {
+ oformat = av_guess_format(NULL, filename, NULL);
+ if (!oformat) {
+ ret = AVERROR(EINVAL);
+ av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n",
+ filename);
+ goto error;
+ }
+ }
+ }
+
+ s->oformat = oformat;
+ if (s->oformat->priv_data_size > 0) {
+ s->priv_data = av_mallocz(s->oformat->priv_data_size);
+ if (!s->priv_data)
+ goto nomem;
+ if (s->oformat->priv_class) {
+ *(const AVClass**)s->priv_data= s->oformat->priv_class;
+ av_opt_set_defaults(s->priv_data);
+ }
+ } else
+ s->priv_data = NULL;
+
+ if (filename)
+ av_strlcpy(s->filename, filename, sizeof(s->filename));
+ *avctx = s;
+ return 0;
+nomem:
+ av_log(s, AV_LOG_ERROR, "Out of memory\n");
+ ret = AVERROR(ENOMEM);
+error:
+ avformat_free_context(s);
+ return ret;
+}
static int validate_codec_tag(AVFormatContext *s, AVStream *st)
{
const AVCodecTag *avctag;
int n;
enum AVCodecID id = AV_CODEC_ID_NONE;
- unsigned int tag = 0;
+ int64_t tag = -1;
/**
* Check that tag + id is in the table
@@ -79,7 +226,7 @@ static int validate_codec_tag(AVFormatContext *s, AVStream *st)
}
if (id != AV_CODEC_ID_NONE)
return 0;
- if (tag && (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL))
+ if (tag >= 0 && (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL))
return 0;
return 1;
}
@@ -92,12 +239,16 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
AVDictionary *tmp = NULL;
AVCodecContext *codec = NULL;
AVOutputFormat *of = s->oformat;
+ AVDictionaryEntry *e;
if (options)
av_dict_copy(&tmp, *options, 0);
if ((ret = av_opt_set_dict(s, &tmp)) < 0)
goto fail;
+ if (s->priv_data && s->oformat->priv_class && *(const AVClass**)s->priv_data==s->oformat->priv_class &&
+ (ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0)
+ goto fail;
#if FF_API_LAVF_BITEXACT
if (s->nb_streams && s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)
@@ -106,7 +257,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options)
// some sanity checks
if (s->nb_streams == 0 && !(of->flags & AVFMT_NOSTREAMS)) {
- av_log(s, AV_LOG_ERROR, "no streams\n");
+ av_log(s, AV_LOG_ERROR, "No streams to mux were specified\n");
ret = AVERROR(EINVAL);
goto fail;
}
@@ -152,18 +303,18 @@ FF_ENABLE_DEPRECATION_WARNINGS
ret = AVERROR(EINVAL);
goto fail;
}
-
- if (av_cmp_q(st->sample_aspect_ratio,
- codec->sample_aspect_ratio)) {
+ if (av_cmp_q(st->sample_aspect_ratio, codec->sample_aspect_ratio)
+ && FFABS(av_q2d(st->sample_aspect_ratio) - av_q2d(codec->sample_aspect_ratio)) > 0.004*av_q2d(st->sample_aspect_ratio)
+ ) {
if (st->sample_aspect_ratio.num != 0 &&
st->sample_aspect_ratio.den != 0 &&
- codec->sample_aspect_ratio.den != 0 &&
+ codec->sample_aspect_ratio.num != 0 &&
codec->sample_aspect_ratio.den != 0) {
av_log(s, AV_LOG_ERROR, "Aspect ratio mismatch between muxer "
- "(%d/%d) and encoder layer (%d/%d)\n",
- st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
- codec->sample_aspect_ratio.num,
- codec->sample_aspect_ratio.den);
+ "(%d/%d) and encoder layer (%d/%d)\n",
+ st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
+ codec->sample_aspect_ratio.num,
+ codec->sample_aspect_ratio.den);
ret = AVERROR(EINVAL);
goto fail;
}
@@ -172,21 +323,23 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
if (of->codec_tag) {
- if (codec->codec_tag &&
- codec->codec_id == AV_CODEC_ID_RAWVIDEO &&
- !av_codec_get_tag(of->codec_tag, codec->codec_id) &&
- !validate_codec_tag(s, st)) {
+ if ( codec->codec_tag
+ && codec->codec_id == AV_CODEC_ID_RAWVIDEO
+ && ( av_codec_get_tag(of->codec_tag, codec->codec_id) == 0
+ || av_codec_get_tag(of->codec_tag, codec->codec_id) == MKTAG('r', 'a', 'w', ' '))
+ && !validate_codec_tag(s, st)) {
// the current rawvideo encoding system ends up setting
- // the wrong codec_tag for avi, we override it here
+ // the wrong codec_tag for avi/mov, we override it here
codec->codec_tag = 0;
}
if (codec->codec_tag) {
if (!validate_codec_tag(s, st)) {
- char tagbuf[32];
+ char tagbuf[32], tagbuf2[32];
av_get_codec_tag_string(tagbuf, sizeof(tagbuf), codec->codec_tag);
+ av_get_codec_tag_string(tagbuf2, sizeof(tagbuf2), av_codec_get_tag(s->oformat->codec_tag, codec->codec_id));
av_log(s, AV_LOG_ERROR,
- "Tag %s/0x%08x incompatible with output codec id '%d'\n",
- tagbuf, codec->codec_tag, codec->codec_id);
+ "Tag %s/0x%08x incompatible with output codec id '%d' (%s)\n",
+ tagbuf, codec->codec_tag, codec->codec_id, tagbuf2);
ret = AVERROR_INVALIDDATA;
goto fail;
}
@@ -213,7 +366,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (of->priv_class) {
*(const AVClass **)s->priv_data = of->priv_class;
av_opt_set_defaults(s->priv_data);
- if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)
+ if ((ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0)
goto fail;
}
}
@@ -221,6 +374,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
/* set muxer identification string */
if (!(s->flags & AVFMT_FLAG_BITEXACT)) {
av_dict_set(&s->metadata, "encoder", LIBAVFORMAT_IDENT, 0);
+ } else {
+ av_dict_set(&s->metadata, "encoder", NULL, 0);
+ }
+
+ for (e = NULL; e = av_dict_get(s->metadata, "encoder-", e, AV_DICT_IGNORE_SUFFIX); ) {
+ av_dict_set(&s->metadata, e->key, NULL, 0);
}
if (options) {
@@ -235,20 +394,59 @@ fail:
return ret;
}
+static int init_pts(AVFormatContext *s)
+{
+ int i;
+ AVStream *st;
+
+ /* init PTS generation */
+ for (i = 0; i < s->nb_streams; i++) {
+ int64_t den = AV_NOPTS_VALUE;
+ st = s->streams[i];
+
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ den = (int64_t)st->time_base.num * st->codec->sample_rate;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ den = (int64_t)st->time_base.num * st->codec->time_base.den;
+ break;
+ default:
+ break;
+ }
+ if (den != AV_NOPTS_VALUE) {
+ if (den <= 0)
+ return AVERROR_INVALIDDATA;
+
+ frac_init(&st->pts, 0, 0, den);
+ }
+ }
+
+ return 0;
+}
+
int avformat_write_header(AVFormatContext *s, AVDictionary **options)
{
int ret = 0;
- if (ret = init_muxer(s, options))
+ if ((ret = init_muxer(s, options)) < 0)
return ret;
if (s->oformat->write_header) {
ret = s->oformat->write_header(s);
+ if (ret >= 0 && s->pb && s->pb->error < 0)
+ ret = s->pb->error;
if (ret < 0)
return ret;
+ if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
+ avio_flush(s->pb);
}
- if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO) {
+ if ((ret = init_pts(s)) < 0)
+ return ret;
+
+ if (s->avoid_negative_ts < 0) {
+ av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO);
if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) {
s->avoid_negative_ts = 0;
} else
@@ -258,17 +456,31 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options)
return 0;
}
+#define AV_PKT_FLAG_UNCODED_FRAME 0x2000
+
+/* Note: using sizeof(AVFrame) from outside lavu is unsafe in general, but
+ it is only being used internally to this file as a consistency check.
+ The value is chosen to be very unlikely to appear on its own and to cause
+ immediate failure if used anywhere as a real size. */
+#define UNCODED_FRAME_PACKET_SIZE (INT_MIN / 3 * 2 + (int)sizeof(AVFrame))
+
+
//FIXME merge with compute_pkt_fields
static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
{
- int delay = FFMAX(st->codec->has_b_frames, !!st->codec->max_b_frames);
+ int delay = FFMAX(st->codec->has_b_frames, st->codec->max_b_frames > 0);
int num, den, i;
+ int frame_size;
- av_log(s, AV_LOG_TRACE, "compute_pkt_fields2: pts:%" PRId64 " dts:%" PRId64 " cur_dts:%" PRId64 " b:%d size:%d st:%d\n",
- pkt->pts, pkt->dts, st->cur_dts, delay, pkt->size, pkt->stream_index);
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "compute_pkt_fields2: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d\n",
+ av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), delay, pkt->size, pkt->stream_index);
-/* if(pkt->pts == AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE)
- * return AVERROR(EINVAL);*/
+ if (pkt->duration < 0 && st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ av_log(s, AV_LOG_WARNING, "Packet with invalid duration %d in stream %d\n",
+ pkt->duration, pkt->stream_index);
+ pkt->duration = 0;
+ }
/* duration field */
if (pkt->duration == 0) {
@@ -281,6 +493,18 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
if (pkt->pts == AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE && delay == 0)
pkt->pts = pkt->dts;
+ //XXX/FIXME this is a temporary hack until all encoders output pts
+ if ((pkt->pts == 0 || pkt->pts == AV_NOPTS_VALUE) && pkt->dts == AV_NOPTS_VALUE && !delay) {
+ static int warned;
+ if (!warned) {
+ av_log(s, AV_LOG_WARNING, "Encoder did not produce proper pts, making some up.\n");
+ warned = 1;
+ }
+ pkt->dts =
+// pkt->pts= st->cur_dts;
+ pkt->pts = st->pts.val;
+ }
+
//calculate dts from pts
if (pkt->pts != AV_NOPTS_VALUE && pkt->dts == AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) {
st->pts_buffer[0] = pkt->pts;
@@ -294,67 +518,135 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt)
if (st->cur_dts && st->cur_dts != AV_NOPTS_VALUE &&
((!(s->oformat->flags & AVFMT_TS_NONSTRICT) &&
+ st->codec->codec_type != AVMEDIA_TYPE_SUBTITLE &&
st->cur_dts >= pkt->dts) || st->cur_dts > pkt->dts)) {
av_log(s, AV_LOG_ERROR,
- "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %" PRId64 " >= %" PRId64 "\n",
- st->index, st->cur_dts, pkt->dts);
+ "Application provided invalid, non monotonically increasing dts to muxer in stream %d: %s >= %s\n",
+ st->index, av_ts2str(st->cur_dts), av_ts2str(pkt->dts));
return AVERROR(EINVAL);
}
if (pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts < pkt->dts) {
av_log(s, AV_LOG_ERROR,
- "pts %" PRId64 " < dts %" PRId64 " in stream %d\n",
- pkt->pts, pkt->dts,
+ "pts (%s) < dts (%s) in stream %d\n",
+ av_ts2str(pkt->pts), av_ts2str(pkt->dts),
st->index);
return AVERROR(EINVAL);
}
- av_log(s, AV_LOG_TRACE, "av_write_frame: pts2:%"PRId64" dts2:%"PRId64"\n",
- pkt->pts, pkt->dts);
- st->cur_dts = pkt->dts;
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "av_write_frame: pts2:%s dts2:%s\n",
+ av_ts2str(pkt->pts), av_ts2str(pkt->dts));
+ st->cur_dts = pkt->dts;
+ st->pts.val = pkt->dts;
+
+ /* update pts */
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ frame_size = (pkt->flags & AV_PKT_FLAG_UNCODED_FRAME) ?
+ ((AVFrame *)pkt->data)->nb_samples :
+ av_get_audio_frame_duration(st->codec, pkt->size);
+
+ /* HACK/FIXME, we skip the initial 0 size packets as they are most
+ * likely equal to the encoder delay, but it would be better if we
+ * had the real timestamps from the encoder */
+ if (frame_size >= 0 && (pkt->size || st->pts.num != st->pts.den >> 1 || st->pts.val)) {
+ frac_add(&st->pts, (int64_t)st->time_base.den * frame_size);
+ }
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ frac_add(&st->pts, (int64_t)st->time_base.den * st->codec->time_base.num);
+ break;
+ }
return 0;
}
-/*
+/**
+ * Make timestamps non negative, move side data from payload to internal struct, call muxer, and restore
+ * sidedata.
+ *
* FIXME: this function should NEVER get undefined pts/dts beside when the
* AVFMT_NOTIMESTAMPS is set.
* Those additional safety checks should be dropped once the correct checks
* are set in the callers.
*/
-
static int write_packet(AVFormatContext *s, AVPacket *pkt)
{
- int ret;
+ int ret, did_split;
+
+ if (s->output_ts_offset) {
+ AVStream *st = s->streams[pkt->stream_index];
+ int64_t offset = av_rescale_q(s->output_ts_offset, AV_TIME_BASE_Q, st->time_base);
+
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += offset;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += offset;
+ }
+
if (s->avoid_negative_ts > 0) {
- AVRational time_base = s->streams[pkt->stream_index]->time_base;
- int64_t offset = 0;
+ AVStream *st = s->streams[pkt->stream_index];
+ int64_t offset = st->mux_ts_offset;
+ int64_t ts = s->internal->avoid_negative_ts_use_pts ? pkt->pts : pkt->dts;
+
+ if (s->internal->offset == AV_NOPTS_VALUE && ts != AV_NOPTS_VALUE &&
+ (ts < 0 || s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)) {
+ s->internal->offset = -ts;
+ s->internal->offset_timebase = st->time_base;
+ }
- if (s->internal->offset == AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE &&
- (pkt->dts < 0 || s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)) {
- s->internal->offset = -pkt->dts;
- s->internal->offset_timebase = time_base;
+ if (s->internal->offset != AV_NOPTS_VALUE && !offset) {
+ offset = st->mux_ts_offset =
+ av_rescale_q_rnd(s->internal->offset,
+ s->internal->offset_timebase,
+ st->time_base,
+ AV_ROUND_UP);
}
- if (s->internal->offset != AV_NOPTS_VALUE)
- offset = av_rescale_q(s->internal->offset, s->internal->offset_timebase, time_base);
if (pkt->dts != AV_NOPTS_VALUE)
pkt->dts += offset;
if (pkt->pts != AV_NOPTS_VALUE)
pkt->pts += offset;
- if (pkt->dts != AV_NOPTS_VALUE && pkt->dts < 0) {
- av_log(s, AV_LOG_WARNING,
- "Packets poorly interleaved, failed to avoid negative "
- "timestamp %"PRId64" in stream %d.\n"
- "Try -max_interleave_delta 0 as a possible workaround.\n",
- pkt->dts, pkt->stream_index);
+ if (s->internal->avoid_negative_ts_use_pts) {
+ if (pkt->pts != AV_NOPTS_VALUE && pkt->pts < 0) {
+ av_log(s, AV_LOG_WARNING, "failed to avoid negative "
+ "pts %s in stream %d.\n"
+ "Try -avoid_negative_ts 1 as a possible workaround.\n",
+ av_ts2str(pkt->dts),
+ pkt->stream_index
+ );
+ }
+ } else {
+ av_assert2(pkt->dts == AV_NOPTS_VALUE || pkt->dts >= 0 || s->max_interleave_delta > 0);
+ if (pkt->dts != AV_NOPTS_VALUE && pkt->dts < 0) {
+ av_log(s, AV_LOG_WARNING,
+ "Packets poorly interleaved, failed to avoid negative "
+ "timestamp %s in stream %d.\n"
+ "Try -max_interleave_delta 0 as a possible workaround.\n",
+ av_ts2str(pkt->dts),
+ pkt->stream_index
+ );
+ }
}
}
- ret = s->oformat->write_packet(s, pkt);
- if (s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
+ did_split = av_packet_split_side_data(pkt);
+ if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
+ AVFrame *frame = (AVFrame *)pkt->data;
+ av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
+ ret = s->oformat->write_uncoded_frame(s, pkt->stream_index, &frame, 0);
+ av_frame_free(&frame);
+ } else {
+ ret = s->oformat->write_packet(s, pkt);
+ }
+
+ if (s->flush_packets && s->pb && ret >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
avio_flush(s->pb);
+ if (did_split)
+ av_packet_merge_side_data(pkt);
+
return ret;
}
@@ -386,8 +678,14 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
return ret;
if (!pkt) {
- if (s->oformat->flags & AVFMT_ALLOW_FLUSH)
- return s->oformat->write_packet(s, pkt);
+ if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
+ ret = s->oformat->write_packet(s, NULL);
+ if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
+ avio_flush(s->pb);
+ if (ret >= 0 && s->pb && s->pb->error < 0)
+ ret = s->pb->error;
+ return ret;
+ }
return 1;
}
@@ -397,17 +695,23 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt)
return ret;
ret = write_packet(s, pkt);
+ if (ret >= 0 && s->pb && s->pb->error < 0)
+ ret = s->pb->error;
if (ret >= 0)
s->streams[pkt->stream_index]->nb_frames++;
return ret;
}
+#define CHUNK_START 0x1000
+
int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
int (*compare)(AVFormatContext *, AVPacket *, AVPacket *))
{
int ret;
AVPacketList **next_point, *this_pktl;
+ AVStream *st = s->streams[pkt->stream_index];
+ int chunked = s->max_chunk_size || s->max_chunk_duration;
this_pktl = av_mallocz(sizeof(AVPacketList));
if (!this_pktl)
@@ -421,27 +725,56 @@ FF_ENABLE_DEPRECATION_WARNINGS
pkt->buf = NULL;
pkt->side_data = NULL;
pkt->side_data_elems = 0;
- // Duplicate the packet if it uses non-allocated memory
- if ((ret = av_dup_packet(&this_pktl->pkt)) < 0) {
- av_free(this_pktl);
- return ret;
+ if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
+ av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
+ av_assert0(((AVFrame *)pkt->data)->buf);
+ } else {
+ // Duplicate the packet if it uses non-allocated memory
+ if ((ret = av_dup_packet(&this_pktl->pkt)) < 0) {
+ av_free(this_pktl);
+ return ret;
+ }
}
if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
- next_point = &(s->streams[pkt->stream_index]->last_in_packet_buffer->next);
- } else
+ next_point = &(st->last_in_packet_buffer->next);
+ } else {
next_point = &s->internal->packet_buffer;
+ }
+ if (chunked) {
+ uint64_t max= av_rescale_q_rnd(s->max_chunk_duration, AV_TIME_BASE_Q, st->time_base, AV_ROUND_UP);
+ st->interleaver_chunk_size += pkt->size;
+ st->interleaver_chunk_duration += pkt->duration;
+ if ( (s->max_chunk_size && st->interleaver_chunk_size > s->max_chunk_size)
+ || (max && st->interleaver_chunk_duration > max)) {
+ st->interleaver_chunk_size = 0;
+ this_pktl->pkt.flags |= CHUNK_START;
+ if (max && st->interleaver_chunk_duration > max) {
+ int64_t syncoffset = (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)*max/2;
+ int64_t syncto = av_rescale(pkt->dts + syncoffset, 1, max)*max - syncoffset;
+
+ st->interleaver_chunk_duration += (pkt->dts - syncto)/8 - max;
+ } else
+ st->interleaver_chunk_duration = 0;
+ }
+ }
if (*next_point) {
+ if (chunked && !(this_pktl->pkt.flags & CHUNK_START))
+ goto next_non_null;
+
if (compare(s, &s->internal->packet_buffer_end->pkt, pkt)) {
- while (!compare(s, &(*next_point)->pkt, pkt))
+ while ( *next_point
+ && ((chunked && !((*next_point)->pkt.flags&CHUNK_START))
+ || !compare(s, &(*next_point)->pkt, pkt)))
next_point = &(*next_point)->next;
- goto next_non_null;
+ if (*next_point)
+ goto next_non_null;
} else {
next_point = &(s->internal->packet_buffer_end->next);
}
}
- assert(!*next_point);
+ av_assert1(!*next_point);
s->internal->packet_buffer_end = this_pktl;
next_non_null:
@@ -461,6 +794,16 @@ static int interleave_compare_dts(AVFormatContext *s, AVPacket *next,
AVStream *st2 = s->streams[next->stream_index];
int comp = av_compare_ts(next->dts, st2->time_base, pkt->dts,
st->time_base);
+ if (s->audio_preload && ((st->codec->codec_type == AVMEDIA_TYPE_AUDIO) != (st2->codec->codec_type == AVMEDIA_TYPE_AUDIO))) {
+ int64_t ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st ->codec->codec_type == AVMEDIA_TYPE_AUDIO);
+ int64_t ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st2->codec->codec_type == AVMEDIA_TYPE_AUDIO);
+ if (ts == ts2) {
+ ts= ( pkt ->dts* st->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st ->codec->codec_type == AVMEDIA_TYPE_AUDIO)* st->time_base.den)*st2->time_base.den
+ -( next->dts*st2->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st2->codec->codec_type == AVMEDIA_TYPE_AUDIO)*st2->time_base.den)* st->time_base.den;
+ ts2=0;
+ }
+ comp= (ts>ts2) - (ts<ts2);
+ }
if (comp == 0)
return pkt->stream_index < next->stream_index;
@@ -472,6 +815,7 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
{
AVPacketList *pktl;
int stream_count = 0;
+ int noninterleaved_count = 0;
int i, ret;
if (pkt) {
@@ -479,7 +823,24 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
return ret;
}
- if (s->max_interleave_delta > 0 && s->internal->packet_buffer && !flush) {
+ for (i = 0; i < s->nb_streams; i++) {
+ if (s->streams[i]->last_in_packet_buffer) {
+ ++stream_count;
+ } else if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_ATTACHMENT &&
+ s->streams[i]->codec->codec_id != AV_CODEC_ID_VP8 &&
+ s->streams[i]->codec->codec_id != AV_CODEC_ID_VP9) {
+ ++noninterleaved_count;
+ }
+ }
+
+ if (s->internal->nb_interleaved_streams == stream_count)
+ flush = 1;
+
+ if (s->max_interleave_delta > 0 &&
+ s->internal->packet_buffer &&
+ !flush &&
+ s->internal->nb_interleaved_streams == stream_count+noninterleaved_count
+ ) {
AVPacket *top_pkt = &s->internal->packet_buffer->pkt;
int64_t delta_dts = INT64_MIN;
int64_t top_dts = av_rescale_q(top_pkt->dts,
@@ -497,7 +858,6 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
s->streams[i]->time_base,
AV_TIME_BASE_Q);
delta_dts = FFMAX(delta_dts, last_dts - top_dts);
- stream_count++;
}
if (delta_dts > s->max_interleave_delta) {
@@ -507,23 +867,22 @@ int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
delta_dts, s->max_interleave_delta);
flush = 1;
}
- } else {
- for (i = 0; i < s->nb_streams; i++)
- stream_count += !!s->streams[i]->last_in_packet_buffer;
}
-
- if (stream_count && (s->internal->nb_interleaved_streams == stream_count || flush)) {
+ if (stream_count && flush) {
+ AVStream *st;
pktl = s->internal->packet_buffer;
*out = pktl->pkt;
+ st = s->streams[out->stream_index];
s->internal->packet_buffer = pktl->next;
if (!s->internal->packet_buffer)
s->internal->packet_buffer_end = NULL;
- if (s->streams[out->stream_index]->last_in_packet_buffer == pktl)
- s->streams[out->stream_index]->last_in_packet_buffer = NULL;
+ if (st->last_in_packet_buffer == pktl)
+ st->last_in_packet_buffer = NULL;
av_freep(&pktl);
+
return 1;
} else {
av_init_packet(out);
@@ -562,8 +921,10 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
if (pkt) {
AVStream *st = s->streams[pkt->stream_index];
- av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame size:%d dts:%" PRId64 " pts:%" PRId64 "\n",
- pkt->size, pkt->dts, pkt->pts);
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame size:%d dts:%s pts:%s\n",
+ pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts));
+
if ((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
goto fail;
@@ -595,6 +956,8 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
if (ret < 0)
return ret;
+ if(s->pb && s->pb->error)
+ return s->pb->error;
}
fail:
av_packet_unref(pkt);
@@ -608,7 +971,7 @@ int av_write_trailer(AVFormatContext *s)
for (;; ) {
AVPacket pkt;
ret = interleave_packet(s, &pkt, NULL, 1);
- if (ret < 0) //FIXME cleanup needed for ret<0 ?
+ if (ret < 0)
goto fail;
if (!ret)
break;
@@ -621,15 +984,22 @@ int av_write_trailer(AVFormatContext *s)
if (ret < 0)
goto fail;
+ if(s->pb && s->pb->error)
+ goto fail;
}
+fail:
if (s->oformat->write_trailer)
+ if (ret >= 0) {
ret = s->oformat->write_trailer(s);
+ } else {
+ s->oformat->write_trailer(s);
+ }
- if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)
- avio_flush(s->pb);
-
-fail:
+ if (s->pb)
+ avio_flush(s->pb);
+ if (ret == 0)
+ ret = s->pb ? s->pb->error : 0;
for (i = 0; i < s->nb_streams; i++) {
av_freep(&s->streams[i]->priv_data);
av_freep(&s->streams[i]->index_entries);
@@ -640,10 +1010,20 @@ fail:
return ret;
}
+int av_get_output_timestamp(struct AVFormatContext *s, int stream,
+ int64_t *dts, int64_t *wall)
+{
+ if (!s->oformat || !s->oformat->get_output_timestamp)
+ return AVERROR(ENOSYS);
+ s->oformat->get_output_timestamp(s, stream, dts, wall);
+ return 0;
+}
+
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
- AVFormatContext *src)
+ AVFormatContext *src, int interleave)
{
AVPacket local_pkt;
+ int ret;
local_pkt = *pkt;
local_pkt.stream_index = dst_stream;
@@ -655,5 +1035,62 @@ int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt,
local_pkt.dts = av_rescale_q(pkt->dts,
src->streams[pkt->stream_index]->time_base,
dst->streams[dst_stream]->time_base);
- return av_write_frame(dst, &local_pkt);
+ if (pkt->duration)
+ local_pkt.duration = av_rescale_q(pkt->duration,
+ src->streams[pkt->stream_index]->time_base,
+ dst->streams[dst_stream]->time_base);
+
+ if (interleave) ret = av_interleaved_write_frame(dst, &local_pkt);
+ else ret = av_write_frame(dst, &local_pkt);
+ pkt->buf = local_pkt.buf;
+ pkt->destruct = local_pkt.destruct;
+ return ret;
+}
+
+static int av_write_uncoded_frame_internal(AVFormatContext *s, int stream_index,
+ AVFrame *frame, int interleaved)
+{
+ AVPacket pkt, *pktp;
+
+ av_assert0(s->oformat);
+ if (!s->oformat->write_uncoded_frame)
+ return AVERROR(ENOSYS);
+
+ if (!frame) {
+ pktp = NULL;
+ } else {
+ pktp = &pkt;
+ av_init_packet(&pkt);
+ pkt.data = (void *)frame;
+ pkt.size = UNCODED_FRAME_PACKET_SIZE;
+ pkt.pts =
+ pkt.dts = frame->pts;
+ pkt.duration = av_frame_get_pkt_duration(frame);
+ pkt.stream_index = stream_index;
+ pkt.flags |= AV_PKT_FLAG_UNCODED_FRAME;
+ }
+
+ return interleaved ? av_interleaved_write_frame(s, pktp) :
+ av_write_frame(s, pktp);
+}
+
+int av_write_uncoded_frame(AVFormatContext *s, int stream_index,
+ AVFrame *frame)
+{
+ return av_write_uncoded_frame_internal(s, stream_index, frame, 0);
+}
+
+int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index,
+ AVFrame *frame)
+{
+ return av_write_uncoded_frame_internal(s, stream_index, frame, 1);
+}
+
+int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index)
+{
+ av_assert0(s->oformat);
+ if (!s->oformat->write_uncoded_frame)
+ return AVERROR(ENOSYS);
+ return s->oformat->write_uncoded_frame(s, stream_index, NULL,
+ AV_WRITE_UNCODED_FRAME_QUERY);
}
diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c
index e21ec06b74..7aa6452f66 100644
--- a/libavformat/mvdec.c
+++ b/libavformat/mvdec.c
@@ -2,20 +2,20 @@
* Silicon Graphics Movie demuxer
* Copyright (c) 2012 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,7 +57,12 @@ static int mv_probe(AVProbeData *p)
static char *var_read_string(AVIOContext *pb, int size)
{
int n;
- char *str = av_malloc(size + 1);
+ char *str;
+
+ if (size < 0 || size == INT_MAX)
+ return NULL;
+
+ str = av_malloc(size + 1);
if (!str)
return NULL;
n = avio_get_str(pb, size, str, size + 1);
@@ -218,7 +223,7 @@ static int parse_video_var(AVFormatContext *avctx, AVStream *st,
return 0;
}
-static void read_table(AVFormatContext *avctx, AVStream *st,
+static int read_table(AVFormatContext *avctx, AVStream *st,
int (*parse)(AVFormatContext *avctx, AVStream *st,
const char *name, int size))
{
@@ -233,11 +238,16 @@ static void read_table(AVFormatContext *avctx, AVStream *st,
avio_read(pb, name, 16);
name[sizeof(name) - 1] = 0;
size = avio_rb32(pb);
+ if (size < 0) {
+ av_log(avctx, AV_LOG_ERROR, "entry size %d is invalid\n", size);
+ return AVERROR_INVALIDDATA;
+ }
if (parse(avctx, st, name, size) < 0) {
avpriv_request_sample(avctx, "Variable %s", name);
avio_skip(pb, size);
}
}
+ return 0;
}
static void read_index(AVIOContext *pb, AVStream *st)
@@ -261,8 +271,9 @@ static int mv_read_header(AVFormatContext *avctx)
{
MvContext *mv = avctx->priv_data;
AVIOContext *pb = avctx->pb;
- AVStream *ast = NULL, *vst = NULL;
+ AVStream *ast = NULL, *vst = NULL; //initialization to suppress warning
int version, i;
+ int ret;
avio_skip(pb, 4);
@@ -335,7 +346,8 @@ static int mv_read_header(AVFormatContext *avctx)
} else if (!version && avio_rb16(pb) == 3) {
avio_skip(pb, 4);
- read_table(avctx, NULL, parse_global_var);
+ if ((ret = read_table(avctx, NULL, parse_global_var)) < 0)
+ return ret;
if (mv->nb_audio_tracks > 1) {
avpriv_request_sample(avctx, "Multiple audio streams support");
@@ -345,7 +357,8 @@ static int mv_read_header(AVFormatContext *avctx)
if (!ast)
return AVERROR(ENOMEM);
ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- read_table(avctx, ast, parse_audio_var);
+ if ((read_table(avctx, ast, parse_audio_var)) < 0)
+ return ret;
if (mv->acompression == 100 &&
mv->aformat == AUDIO_FORMAT_SIGNED &&
ast->codec->bits_per_coded_sample == 16) {
@@ -371,7 +384,8 @@ static int mv_read_header(AVFormatContext *avctx)
if (!vst)
return AVERROR(ENOMEM);
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- read_table(avctx, vst, parse_video_var);
+ if ((ret = read_table(avctx, vst, parse_video_var))<0)
+ return ret;
}
if (mv->nb_audio_tracks)
@@ -394,7 +408,7 @@ static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
AVStream *st = avctx->streams[mv->stream_index];
const AVIndexEntry *index;
int frame = mv->frame[mv->stream_index];
- int ret;
+ int64_t ret;
uint64_t pos;
if (frame < st->nb_index_entries) {
diff --git a/libavformat/mvi.c b/libavformat/mvi.c
index 03a1f406cf..a7cfcb9a7a 100644
--- a/libavformat/mvi.c
+++ b/libavformat/mvi.c
@@ -2,20 +2,20 @@
* Motion Pixels MVI Demuxer
* Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -54,8 +54,8 @@ static int read_header(AVFormatContext *s)
if (!vst)
return AVERROR(ENOMEM);
- vst->codec->extradata_size = 2;
- vst->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (ff_alloc_extradata(vst->codec, 2))
+ return AVERROR(ENOMEM);
version = avio_r8(pb);
vst->codec->extradata[0] = avio_r8(pb);
diff --git a/libavformat/mxf.c b/libavformat/mxf.c
index 19ee35f3af..ecfb8a2393 100644
--- a/libavformat/mxf.c
+++ b/libavformat/mxf.c
@@ -2,20 +2,20 @@
* MXF
* Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,6 +28,8 @@
const MXFCodecUL ff_mxf_data_definition_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x01,0x00,0x00,0x00 }, 13, AVMEDIA_TYPE_VIDEO },
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x02,0x00,0x00,0x00 }, 13, AVMEDIA_TYPE_AUDIO },
+ { { 0x80,0x7D,0x00,0x60,0x08,0x14,0x3E,0x6F,0x6F,0x3C,0x8C,0xE1,0x6C,0xEF,0x11,0xD2 }, 16, AVMEDIA_TYPE_VIDEO }, /* LegacyPicture Avid Media Composer MXF */
+ { { 0x80,0x7D,0x00,0x60,0x08,0x14,0x3E,0x6F,0x78,0xE1,0xEB,0xE1,0x6C,0xEF,0x11,0xD2 }, 16, AVMEDIA_TYPE_AUDIO }, /* LegacySound Avid Media Composer MXF */
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AVMEDIA_TYPE_DATA },
};
@@ -44,9 +46,11 @@ const MXFCodecUL ff_mxf_codec_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, 15, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed 422 8-bit */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x71,0x00,0x00,0x00 }, 13, AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x03,0x02,0x00,0x00 }, 14, AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD */
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0E,0x04,0x02,0x01,0x02,0x04,0x01,0x00 }, 16, AV_CODEC_ID_DNXHD }, /* SMPTE VC-3/DNxHD Legacy Avid Media Composer MXF */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC SPS/PPS in-band */
- { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x02,0x00 }, 15, AV_CODEC_ID_V210 }, /* V210 */
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x02,0x01 }, 16, AV_CODEC_ID_V210 }, /* V210 */
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0E,0x04,0x02,0x01,0x02,0x11,0x00,0x00 }, 14, AV_CODEC_ID_PRORES }, /* Avid MC7 ProRes */
/* SoundEssenceCompression */
{ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x03,0x04,0x02,0x02,0x02,0x03,0x03,0x01,0x00 }, 14, AV_CODEC_ID_AAC }, /* MPEG2 AAC ADTS (legacy) */
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, 13, AV_CODEC_ID_PCM_S16LE }, /* Uncompressed */
@@ -91,6 +95,7 @@ static const struct {
{AV_PIX_FMT_RGB565BE,{'R', 5, 'G', 6, 'B', 5 }},
{AV_PIX_FMT_RGBA, {'R', 8, 'G', 8, 'B', 8, 'A', 8 }},
{AV_PIX_FMT_PAL8, {'P', 8 }},
+ {AV_PIX_FMT_GRAY8, {'A', 8 }},
};
static const int num_pixel_layouts = FF_ARRAY_ELEMS(ff_mxf_pixel_layouts);
diff --git a/libavformat/mxf.h b/libavformat/mxf.h
index 24432071ee..1763063a69 100644
--- a/libavformat/mxf.h
+++ b/libavformat/mxf.h
@@ -2,20 +2,20 @@
* MXF
* Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_MXF_H
@@ -33,6 +33,7 @@ enum MXFMetadataSetType {
SourcePackage,
SourceClip,
TimecodeComponent,
+ PulldownComponent,
Sequence,
MultipleDescriptor,
Descriptor,
@@ -45,14 +46,16 @@ enum MXFMetadataSetType {
IndexTableSegment,
EssenceContainerData,
TypeBottom,// add metadata type before this
+ EssenceGroup,
+ TaggedValue,
};
enum MXFFrameLayout {
- FullFrame = 0,
- MixedFields,
- OneField,
- SegmentedFrame,
- SeparateFields
+ FullFrame = 0,
+ SeparateFields,
+ OneField,
+ MixedFields,
+ SegmentedFrame,
};
typedef struct KLVPacket {
@@ -67,7 +70,7 @@ typedef struct MXFCodecUL {
int id;
} MXFCodecUL;
-typedef struct MXFSamplesPerFrame {
+typedef struct {
struct AVRational time_base;
int samples_per_frame[6];
} MXFSamplesPerFrame;
@@ -99,24 +102,24 @@ const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRat
"0x%02x,0x%02x,0x%02x,0x%02x," \
"0x%02x,0x%02x,0x%02x,0x%02x," \
"0x%02x,0x%02x,0x%02x,0x%02x ", \
- s, \
- (x)[0], (x)[1], (x)[2], (x)[3], \
- (x)[4], (x)[5], (x)[6], (x)[7], \
- (x)[8], (x)[9], (x)[10], (x)[11], \
- (x)[12], (x)[13], (x)[14], (x)[15]); \
+ s, UID_ARG(x)); \
av_log(pc, AV_LOG_INFO, \
"%s " \
"%02x.%02x.%02x.%02x." \
"%02x.%02x.%02x.%02x." \
"%02x.%02x.%02x.%02x." \
"%02x.%02x.%02x.%02x\n", \
- s, \
- (x)[0], (x)[1], (x)[2], (x)[3], \
- (x)[4], (x)[5], (x)[6], (x)[7], \
- (x)[8], (x)[9], (x)[10], (x)[11], \
- (x)[12], (x)[13], (x)[14], (x)[15])
+ s, UID_ARG(x))
#else
-#define PRINT_KEY(pc, s, x)
+#define PRINT_KEY(pc, s, x) do { if(0) \
+ av_log(pc, AV_LOG_VERBOSE, \
+ "%s " \
+ "0x%02x,0x%02x,0x%02x,0x%02x," \
+ "0x%02x,0x%02x,0x%02x,0x%02x," \
+ "0x%02x,0x%02x,0x%02x,0x%02x," \
+ "0x%02x,0x%02x,0x%02x,0x%02x ", \
+ s, UID_ARG(x)); \
+ }while(0)
#endif
#endif /* AVFORMAT_MXF_H */
diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 25545dc603..c8f1c61f9e 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -2,20 +2,20 @@
* MXF demuxer.
* Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,8 +46,11 @@
#include <inttypes.h>
#include "libavutil/aes.h"
+#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "libavcodec/bytestream.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/timecode.h"
#include "avformat.h"
#include "internal.h"
#include "mxf.h"
@@ -69,7 +72,7 @@ typedef enum {
OP3b,
OP3c,
OPAtom,
- OPSonyOpt, /* FATE sample, violates the spec in places */
+ OPSONYOpt, /* FATE sample, violates the spec in places */
} MXFOP;
typedef struct MXFPartition {
@@ -86,6 +89,7 @@ typedef struct MXFPartition {
int64_t header_byte_count;
int64_t index_byte_count;
int pack_length;
+ int64_t pack_ofs; ///< absolute offset of pack in file, including run-in
} MXFPartition;
typedef struct MXFCryptoContext {
@@ -117,6 +121,36 @@ typedef struct MXFSequence {
typedef struct MXFTrack {
UID uid;
enum MXFMetadataSetType type;
+ int drop_frame;
+ int start_frame;
+ struct AVRational rate;
+ AVTimecode tc;
+} MXFTimecodeComponent;
+
+typedef struct {
+ UID uid;
+ enum MXFMetadataSetType type;
+ UID input_segment_ref;
+} MXFPulldownComponent;
+
+typedef struct {
+ UID uid;
+ enum MXFMetadataSetType type;
+ UID *structural_components_refs;
+ int structural_components_count;
+ int64_t duration;
+} MXFEssenceGroup;
+
+typedef struct {
+ UID uid;
+ enum MXFMetadataSetType type;
+ char *name;
+ char *value;
+} MXFTaggedValue;
+
+typedef struct {
+ UID uid;
+ enum MXFMetadataSetType type;
MXFSequence *sequence; /* mandatory, and only one */
UID sequence_ref;
int track_id;
@@ -142,6 +176,7 @@ typedef struct MXFDescriptor {
int field_dominance;
int channels;
int bits_per_sample;
+ int64_t duration; /* ContainerDuration optional property */
unsigned int component_depth;
unsigned int horiz_subsampling;
unsigned int vert_subsampling;
@@ -172,10 +207,14 @@ typedef struct MXFPackage {
UID uid;
enum MXFMetadataSetType type;
UID package_uid;
+ UID package_ul;
UID *tracks_refs;
int tracks_count;
MXFDescriptor *descriptor; /* only one */
UID descriptor_ref;
+ char *name;
+ UID *comment_refs;
+ int comment_count;
} MXFPackage;
typedef struct MXFMetadataSet {
@@ -207,7 +246,6 @@ typedef struct MXFContext {
struct AVAES *aesc;
uint8_t *local_tags;
int local_tags_count;
- uint64_t last_partition;
uint64_t footer_partition;
KLVPacket current_klv_data;
int current_klv_index;
@@ -237,6 +275,8 @@ typedef struct MXFMetadataReadTableEntry {
enum MXFMetadataSetType type;
} MXFMetadataReadTableEntry;
+static int mxf_read_close(AVFormatContext *s);
+
/* partial keys to match */
static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 };
static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 };
@@ -249,9 +289,51 @@ static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x
static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 };
static const uint8_t mxf_random_index_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x11,0x01,0x00 };
static const uint8_t mxf_sony_mpeg4_extradata[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0e,0x06,0x06,0x02,0x02,0x01,0x00,0x00 };
+static const uint8_t mxf_avid_project_name[] = { 0xa5,0xfb,0x7b,0x25,0xf6,0x15,0x94,0xb9,0x62,0xfc,0x37,0x17,0x49,0x2d,0x42,0xbf };
+static const uint8_t mxf_jp2k_rsiz[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 };
+static const uint8_t mxf_indirect_value_utf16le[] = { 0x4c,0x00,0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 };
+static const uint8_t mxf_indirect_value_utf16be[] = { 0x42,0x01,0x10,0x02,0x00,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 };
#define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y)))
+static void mxf_free_metadataset(MXFMetadataSet **ctx, int freectx)
+{
+ MXFIndexTableSegment *seg;
+ switch ((*ctx)->type) {
+ case Descriptor:
+ av_freep(&((MXFDescriptor *)*ctx)->extradata);
+ break;
+ case MultipleDescriptor:
+ av_freep(&((MXFDescriptor *)*ctx)->sub_descriptors_refs);
+ break;
+ case Sequence:
+ av_freep(&((MXFSequence *)*ctx)->structural_components_refs);
+ break;
+ case EssenceGroup:
+ av_freep(&((MXFEssenceGroup *)*ctx)->structural_components_refs);
+ break;
+ case SourcePackage:
+ case MaterialPackage:
+ av_freep(&((MXFPackage *)*ctx)->tracks_refs);
+ av_freep(&((MXFPackage *)*ctx)->name);
+ av_freep(&((MXFPackage *)*ctx)->comment_refs);
+ break;
+ case TaggedValue:
+ av_freep(&((MXFTaggedValue *)*ctx)->name);
+ av_freep(&((MXFTaggedValue *)*ctx)->value);
+ break;
+ case IndexTableSegment:
+ seg = (MXFIndexTableSegment *)*ctx;
+ av_freep(&seg->temporal_offset_entries);
+ av_freep(&seg->flag_entries);
+ av_freep(&seg->stream_offset_entries);
+ default:
+ break;
+ }
+ if (freectx)
+ av_freep(ctx);
+}
+
static int64_t klv_decode_ber_length(AVIOContext *pb)
{
uint64_t size = avio_r8(pb);
@@ -270,7 +352,7 @@ static int64_t klv_decode_ber_length(AVIOContext *pb)
static int mxf_read_sync(AVIOContext *pb, const uint8_t *key, unsigned size)
{
int i, b;
- for (i = 0; i < size && !pb->eof_reached; i++) {
+ for (i = 0; i < size && !avio_feof(pb); i++) {
b = avio_r8(pb);
if (b == key[0])
i = 0;
@@ -407,12 +489,18 @@ static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, U
avpriv_request_sample(pb, "Primer pack item length %d", item_len);
return AVERROR_PATCHWELCOME;
}
- if (item_num > UINT_MAX / item_len)
+ if (item_num > 65536) {
+ av_log(mxf->fc, AV_LOG_ERROR, "item_num %d is too large\n", item_num);
return AVERROR_INVALIDDATA;
- mxf->local_tags_count = item_num;
- mxf->local_tags = av_malloc(item_num*item_len);
+ }
+ if (mxf->local_tags)
+ av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple primer packs\n");
+ av_free(mxf->local_tags);
+ mxf->local_tags_count = 0;
+ mxf->local_tags = av_calloc(item_num, item_len);
if (!mxf->local_tags)
return AVERROR(ENOMEM);
+ mxf->local_tags_count = item_num;
avio_read(pb, mxf->local_tags, item_num*item_len);
return 0;
}
@@ -420,17 +508,15 @@ static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, U
static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFContext *mxf = arg;
- MXFPartition *partition;
+ MXFPartition *partition, *tmp_part;
UID op;
uint64_t footer_partition;
uint32_t nb_essence_containers;
- int err;
- if ((err = av_reallocp_array(&mxf->partitions, mxf->partitions_count + 1,
- sizeof(*mxf->partitions))) < 0) {
- mxf->partitions_count = 0;
- return err;
- }
+ tmp_part = av_realloc_array(mxf->partitions, mxf->partitions_count + 1, sizeof(*mxf->partitions));
+ if (!tmp_part)
+ return AVERROR(ENOMEM);
+ mxf->partitions = tmp_part;
if (mxf->parsing_backward) {
/* insert the new partition pack in the middle
@@ -447,6 +533,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
memset(partition, 0, sizeof(*partition));
mxf->partitions_count++;
partition->pack_length = avio_tell(pb) - klv_offset + size;
+ partition->pack_ofs = klv_offset;
switch(uid[13]) {
case 2:
@@ -476,7 +563,10 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
partition->index_sid = avio_rb32(pb);
avio_skip(pb, 8);
partition->body_sid = avio_rb32(pb);
- avio_read(pb, op, sizeof(UID));
+ if (avio_read(pb, op, sizeof(UID)) != sizeof(UID)) {
+ av_log(mxf->fc, AV_LOG_ERROR, "Failed reading UID\n");
+ return AVERROR_INVALIDDATA;
+ }
nb_essence_containers = avio_rb32(pb);
if (partition->this_partition &&
@@ -519,6 +609,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
partition->index_sid, partition->body_sid);
/* sanity check PreviousPartition if set */
+ //NOTE: this isn't actually enough, see mxf_seek_to_previous_partition()
if (partition->previous_partition &&
mxf->run_in + partition->previous_partition >= klv_offset) {
av_log(mxf->fc, AV_LOG_ERROR,
@@ -535,7 +626,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
else if (op[12] == 3 && op[13] == 1) mxf->op = OP3a;
else if (op[12] == 3 && op[13] == 2) mxf->op = OP3b;
else if (op[12] == 3 && op[13] == 3) mxf->op = OP3c;
- else if (op[12] == 64&& op[13] == 1) mxf->op = OPSonyOpt;
+ else if (op[12] == 64&& op[13] == 1) mxf->op = OPSONYOpt;
else if (op[12] == 0x10) {
/* SMPTE 390m: "There shall be exactly one essence container"
* The following block deals with files that violate this, namely:
@@ -563,7 +654,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
av_log(mxf->fc, AV_LOG_WARNING, "invalid KAGSize %"PRId32" - guessing ",
partition->kag_size);
- if (mxf->op == OPSonyOpt)
+ if (mxf->op == OPSONYOpt)
partition->kag_size = 512;
else
partition->kag_size = 1;
@@ -576,13 +667,12 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size
static int mxf_add_metadata_set(MXFContext *mxf, void *metadata_set)
{
- int err;
+ MXFMetadataSet **tmp;
- if ((err = av_reallocp_array(&mxf->metadata_sets, mxf->metadata_sets_count + 1,
- sizeof(*mxf->metadata_sets))) < 0) {
- mxf->metadata_sets_count = 0;
- return err;
- }
+ tmp = av_realloc_array(mxf->metadata_sets, mxf->metadata_sets_count + 1, sizeof(*mxf->metadata_sets));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ mxf->metadata_sets = tmp;
mxf->metadata_sets[mxf->metadata_sets_count] = metadata_set;
mxf->metadata_sets_count++;
return 0;
@@ -598,20 +688,28 @@ static int mxf_read_cryptographic_context(void *arg, AVIOContext *pb, int tag, i
return 0;
}
+static int mxf_read_strong_ref_array(AVIOContext *pb, UID **refs, int *count)
+{
+ *count = avio_rb32(pb);
+ *refs = av_calloc(*count, sizeof(UID));
+ if (!*refs) {
+ *count = 0;
+ return AVERROR(ENOMEM);
+ }
+ avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
+ avio_read(pb, (uint8_t *)*refs, *count * sizeof(UID));
+ return 0;
+}
+
static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFContext *mxf = arg;
switch (tag) {
case 0x1901:
- mxf->packages_count = avio_rb32(pb);
- if (mxf->packages_count >= UINT_MAX / sizeof(UID))
- return AVERROR_INVALIDDATA;
- mxf->packages_refs = av_malloc(mxf->packages_count * sizeof(UID));
- if (!mxf->packages_refs)
- return AVERROR(ENOMEM);
- avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
- avio_read(pb, (uint8_t *)mxf->packages_refs, mxf->packages_count * sizeof(UID));
- break;
+ if (mxf->packages_refs)
+ av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple packages_refs\n");
+ av_free(mxf->packages_refs);
+ return mxf_read_strong_ref_array(pb, &mxf->packages_refs, &mxf->packages_count);
}
return 0;
}
@@ -638,19 +736,29 @@ static int mxf_read_source_clip(void *arg, AVIOContext *pb, int tag, int size, U
return 0;
}
-static int mxf_read_material_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+static int mxf_read_timecode_component(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
- MXFPackage *package = arg;
+ MXFTimecodeComponent *mxf_timecode = arg;
switch(tag) {
- case 0x4403:
- package->tracks_count = avio_rb32(pb);
- if (package->tracks_count >= UINT_MAX / sizeof(UID))
- return AVERROR_INVALIDDATA;
- package->tracks_refs = av_malloc(package->tracks_count * sizeof(UID));
- if (!package->tracks_refs)
- return AVERROR(ENOMEM);
- avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
- avio_read(pb, (uint8_t *)package->tracks_refs, package->tracks_count * sizeof(UID));
+ case 0x1501:
+ mxf_timecode->start_frame = avio_rb64(pb);
+ break;
+ case 0x1502:
+ mxf_timecode->rate = (AVRational){avio_rb16(pb), 1};
+ break;
+ case 0x1503:
+ mxf_timecode->drop_frame = avio_r8(pb);
+ break;
+ }
+ return 0;
+}
+
+static int mxf_read_pulldown_component(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+{
+ MXFPulldownComponent *mxf_pulldown = arg;
+ switch(tag) {
+ case 0x0d01:
+ avio_read(pb, mxf_pulldown->input_segment_ref, 16);
break;
}
return 0;
@@ -691,41 +799,81 @@ static int mxf_read_sequence(void *arg, AVIOContext *pb, int tag, int size, UID
sequence->origin = avio_r8(pb);
break;
case 0x1001:
- sequence->structural_components_count = avio_rb32(pb);
- if (sequence->structural_components_count >= UINT_MAX / sizeof(UID))
- return AVERROR_INVALIDDATA;
- sequence->structural_components_refs = av_malloc(sequence->structural_components_count * sizeof(UID));
- if (!sequence->structural_components_refs)
- return AVERROR(ENOMEM);
- avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
- avio_read(pb, (uint8_t *)sequence->structural_components_refs, sequence->structural_components_count * sizeof(UID));
+ return mxf_read_strong_ref_array(pb, &sequence->structural_components_refs,
+ &sequence->structural_components_count);
+ }
+ return 0;
+}
+
+static int mxf_read_essence_group(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+{
+ MXFEssenceGroup *essence_group = arg;
+ switch (tag) {
+ case 0x0202:
+ essence_group->duration = avio_rb64(pb);
break;
+ case 0x0501:
+ return mxf_read_strong_ref_array(pb, &essence_group->structural_components_refs,
+ &essence_group->structural_components_count);
}
return 0;
}
-static int mxf_read_source_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+static inline int mxf_read_utf16_string(AVIOContext *pb, int size, char** str, int be)
+{
+ int ret;
+ size_t buf_size;
+
+ if (size < 0)
+ return AVERROR(EINVAL);
+
+ buf_size = size + size / 2 + 1;
+ *str = av_malloc(buf_size);
+ if (!*str)
+ return AVERROR(ENOMEM);
+
+ if (be)
+ ret = avio_get_str16be(pb, size, *str, buf_size);
+ else
+ ret = avio_get_str16le(pb, size, *str, buf_size);
+
+ if (ret < 0) {
+ av_freep(str);
+ return ret;
+ }
+
+ return ret;
+}
+
+#define READ_STR16(type, big_endian) \
+static int mxf_read_utf16 ## type ##_string(AVIOContext *pb, int size, char** str) \
+{ \
+return mxf_read_utf16_string(pb, size, str, big_endian); \
+}
+READ_STR16(be, 1)
+READ_STR16(le, 0)
+#undef READ_STR16
+
+static int mxf_read_package(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFPackage *package = arg;
switch(tag) {
case 0x4403:
- package->tracks_count = avio_rb32(pb);
- if (package->tracks_count >= UINT_MAX / sizeof(UID))
- return AVERROR_INVALIDDATA;
- package->tracks_refs = av_malloc(package->tracks_count * sizeof(UID));
- if (!package->tracks_refs)
- return AVERROR(ENOMEM);
- avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
- avio_read(pb, (uint8_t *)package->tracks_refs, package->tracks_count * sizeof(UID));
- break;
+ return mxf_read_strong_ref_array(pb, &package->tracks_refs,
+ &package->tracks_count);
case 0x4401:
- /* UMID, only get last 16 bytes */
- avio_skip(pb, 16);
+ /* UMID */
+ avio_read(pb, package->package_ul, 16);
avio_read(pb, package->package_uid, 16);
break;
case 0x4701:
avio_read(pb, package->descriptor_ref, 16);
break;
+ case 0x4402:
+ return mxf_read_utf16be_string(pb, size, &package->name);
+ case 0x4406:
+ return mxf_read_strong_ref_array(pb, &package->comment_refs,
+ &package->comment_count);
}
return 0;
}
@@ -735,27 +883,14 @@ static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *seg
int i, length;
segment->nb_index_entries = avio_rb32(pb);
- if (!segment->nb_index_entries)
- return 0;
- else if (segment->nb_index_entries < 0 ||
- segment->nb_index_entries >
- (INT_MAX / sizeof(*segment->stream_offset_entries)))
- return AVERROR(ENOMEM);
length = avio_rb32(pb);
- segment->temporal_offset_entries = av_mallocz(segment->nb_index_entries *
- sizeof(*segment->temporal_offset_entries));
- segment->flag_entries = av_mallocz(segment->nb_index_entries *
- sizeof(*segment->flag_entries));
- segment->stream_offset_entries = av_mallocz(segment->nb_index_entries *
- sizeof(*segment->stream_offset_entries));
-
- if (!segment->flag_entries || !segment->stream_offset_entries ||
- !segment->temporal_offset_entries) {
- av_freep(&segment->flag_entries);
- av_freep(&segment->stream_offset_entries);
+ if (!(segment->temporal_offset_entries=av_calloc(segment->nb_index_entries, sizeof(*segment->temporal_offset_entries))) ||
+ !(segment->flag_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->flag_entries))) ||
+ !(segment->stream_offset_entries = av_calloc(segment->nb_index_entries, sizeof(*segment->stream_offset_entries)))) {
av_freep(&segment->temporal_offset_entries);
+ av_freep(&segment->flag_entries);
return AVERROR(ENOMEM);
}
@@ -809,7 +944,7 @@ static int mxf_read_index_table_segment(void *arg, AVIOContext *pb, int tag, int
static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor)
{
int code, value, ofs = 0;
- char layout[16] = {0};
+ char layout[16] = {0}; /* not for printing, may end up not terminated on purpose */
do {
code = avio_r8(pb);
@@ -819,7 +954,8 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor)
if (ofs <= 14) {
layout[ofs++] = code;
layout[ofs++] = value;
- }
+ } else
+ break; /* don't read byte by byte on sneaky files filled with lots of non-zeroes */
} while (code != 0); /* SMPTE 377M E.2.46 */
ff_mxf_decode_pixel_layout(layout, &descriptor->pix_fmt);
@@ -828,17 +964,12 @@ static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor)
static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
{
MXFDescriptor *descriptor = arg;
- descriptor->pix_fmt = AV_PIX_FMT_NONE;
switch(tag) {
case 0x3F01:
- descriptor->sub_descriptors_count = avio_rb32(pb);
- if (descriptor->sub_descriptors_count >= UINT_MAX / sizeof(UID))
- return AVERROR_INVALIDDATA;
- descriptor->sub_descriptors_refs = av_malloc(descriptor->sub_descriptors_count * sizeof(UID));
- if (!descriptor->sub_descriptors_refs)
- return AVERROR(ENOMEM);
- avio_skip(pb, 4); /* useless size of objects, always 16 according to specs */
- avio_read(pb, (uint8_t *)descriptor->sub_descriptors_refs, descriptor->sub_descriptors_count * sizeof(UID));
+ return mxf_read_strong_ref_array(pb, &descriptor->sub_descriptors_refs,
+ &descriptor->sub_descriptors_count);
+ case 0x3002: /* ContainerDuration */
+ descriptor->duration = avio_rb64(pb);
break;
case 0x3004:
avio_read(pb, descriptor->essence_container_ul, 16);
@@ -893,19 +1024,57 @@ static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
default:
/* Private uid used by SONY C0023S01.mxf */
if (IS_KLV_KEY(uid, mxf_sony_mpeg4_extradata)) {
+ if (descriptor->extradata)
+ av_log(NULL, AV_LOG_WARNING, "Duplicate sony_mpeg4_extradata\n");
av_free(descriptor->extradata);
descriptor->extradata_size = 0;
- descriptor->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ descriptor->extradata = av_malloc(size);
if (!descriptor->extradata)
return AVERROR(ENOMEM);
descriptor->extradata_size = size;
avio_read(pb, descriptor->extradata, size);
}
+ if (IS_KLV_KEY(uid, mxf_jp2k_rsiz)) {
+ uint32_t rsiz = avio_rb16(pb);
+ if (rsiz == FF_PROFILE_JPEG2000_DCINEMA_2K ||
+ rsiz == FF_PROFILE_JPEG2000_DCINEMA_4K)
+ descriptor->pix_fmt = AV_PIX_FMT_XYZ12;
+ }
break;
}
return 0;
}
+static int mxf_read_indirect_value(void *arg, AVIOContext *pb, int size)
+{
+ MXFTaggedValue *tagged_value = arg;
+ uint8_t key[17];
+
+ if (size <= 17)
+ return 0;
+
+ avio_read(pb, key, 17);
+ /* 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);
+ } else if (memcmp(key, mxf_indirect_value_utf16be, 17) == 0) {
+ return mxf_read_utf16be_string(pb, size - 17, &tagged_value->value);
+ }
+ return 0;
+}
+
+static int mxf_read_tagged_value(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+{
+ MXFTaggedValue *tagged_value = arg;
+ switch (tag){
+ case 0x5001:
+ return mxf_read_utf16be_string(pb, size, &tagged_value->name);
+ case 0x5003:
+ return mxf_read_indirect_value(tagged_value, pb, size);
+ }
+ return 0;
+}
+
/*
* Match an uid independently of the version byte and up to len common bytes
* Returns: boolean
@@ -950,6 +1119,7 @@ static const MXFCodecUL mxf_picture_essence_container_uls[] = {
{ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MPEG-ES Frame wrapped */
{ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO }, /* DV 625 25mbps */
{ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO }, /* Uncompressed Picture */
+ { { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0xff,0x4b,0x46,0x41,0x41,0x00,0x0d,0x4d,0x4f }, 14, AV_CODEC_ID_RAWVIDEO }, /* Legacy ?? Uncompressed Picture */
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE },
};
@@ -978,10 +1148,10 @@ static const MXFCodecUL mxf_sound_essence_container_uls[] = {
static const MXFCodecUL mxf_data_essence_container_uls[] = {
{ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x09,0x0d,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 }, 16, 0 },
- { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x09,0x0d,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 }, 16, AV_CODEC_ID_NONE },
+ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE },
};
-static const char* mxf_data_essence_descriptor[] = {
+static const char* const mxf_data_essence_descriptor[] = {
"vbi_vanc_smpte_436M",
};
@@ -999,9 +1169,8 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment
if (!nb_segments)
return AVERROR_INVALIDDATA;
- *sorted_segments = av_mallocz(nb_segments * sizeof(**sorted_segments));
- unsorted_segments = av_mallocz(nb_segments * sizeof(*unsorted_segments));
- if (!*sorted_segments || !unsorted_segments) {
+ if (!(unsorted_segments = av_calloc(nb_segments, sizeof(*unsorted_segments))) ||
+ !(*sorted_segments = av_calloc(nb_segments, sizeof(**sorted_segments)))) {
av_freep(sorted_segments);
av_free(unsorted_segments);
return AVERROR(ENOMEM);
@@ -1173,14 +1342,8 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta
if (index_table->nb_ptses <= 0)
return 0;
- if (index_table->nb_ptses > INT_MAX / sizeof(AVIndexEntry))
- return AVERROR(ENOMEM);
-
- index_table->ptses = av_mallocz(index_table->nb_ptses *
- sizeof(int64_t));
- index_table->fake_index = av_mallocz(index_table->nb_ptses *
- sizeof(AVIndexEntry));
- if (!index_table->ptses || !index_table->fake_index) {
+ if (!(index_table->ptses = av_calloc(index_table->nb_ptses, sizeof(int64_t))) ||
+ !(index_table->fake_index = av_calloc(index_table->nb_ptses, sizeof(AVIndexEntry)))) {
av_freep(&index_table->ptses);
return AVERROR(ENOMEM);
}
@@ -1355,18 +1518,266 @@ finish_decoding_index:
return ret;
}
-static int mxf_is_intra_only(MXFDescriptor *d)
+static int mxf_is_intra_only(MXFDescriptor *descriptor)
{
return mxf_get_codec_ul(mxf_intra_only_essence_container_uls,
- &d->essence_container_ul)->id != AV_CODEC_ID_NONE ||
+ &descriptor->essence_container_ul)->id != AV_CODEC_ID_NONE ||
mxf_get_codec_ul(mxf_intra_only_picture_essence_coding_uls,
- &d->essence_codec_ul)->id != AV_CODEC_ID_NONE;
+ &descriptor->essence_codec_ul)->id != AV_CODEC_ID_NONE;
+}
+
+static int mxf_uid_to_str(UID uid, char **str)
+{
+ int i;
+ char *p;
+ p = *str = av_mallocz(sizeof(UID) * 2 + 4 + 1);
+ if (!p)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < sizeof(UID); i++) {
+ snprintf(p, 2 + 1, "%.2x", uid[i]);
+ p += 2;
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ snprintf(p, 1 + 1, "-");
+ p++;
+ }
+ }
+ return 0;
+}
+
+static int mxf_umid_to_str(UID ul, UID uid, char **str)
+{
+ int i;
+ char *p;
+ p = *str = av_mallocz(sizeof(UID) * 4 + 2 + 1);
+ if (!p)
+ return AVERROR(ENOMEM);
+ snprintf(p, 2 + 1, "0x");
+ p += 2;
+ for (i = 0; i < sizeof(UID); i++) {
+ snprintf(p, 2 + 1, "%.2X", ul[i]);
+ p += 2;
+
+ }
+ for (i = 0; i < sizeof(UID); i++) {
+ snprintf(p, 2 + 1, "%.2X", uid[i]);
+ p += 2;
+ }
+ return 0;
+}
+
+static int mxf_add_umid_metadata(AVDictionary **pm, const char *key, MXFPackage* package)
+{
+ char *str;
+ int ret;
+ if (!package)
+ return 0;
+ if ((ret = mxf_umid_to_str(package->package_ul, package->package_uid, &str)) < 0)
+ return ret;
+ av_dict_set(pm, key, str, AV_DICT_DONT_STRDUP_VAL);
+ return 0;
+}
+
+static int mxf_add_timecode_metadata(AVDictionary **pm, const char *key, AVTimecode *tc)
+{
+ char buf[AV_TIMECODE_STR_SIZE];
+ av_dict_set(pm, key, av_timecode_make_string(tc, buf, 0), 0);
+
+ return 0;
+}
+
+static MXFTimecodeComponent* mxf_resolve_timecode_component(MXFContext *mxf, UID *strong_ref)
+{
+ MXFStructuralComponent *component = NULL;
+ MXFPulldownComponent *pulldown = NULL;
+
+ component = mxf_resolve_strong_ref(mxf, strong_ref, AnyType);
+ if (!component)
+ return NULL;
+
+ switch (component->type) {
+ case TimecodeComponent:
+ return (MXFTimecodeComponent*)component;
+ case PulldownComponent: /* timcode component may be located on a pulldown component */
+ pulldown = (MXFPulldownComponent*)component;
+ return mxf_resolve_strong_ref(mxf, &pulldown->input_segment_ref, TimecodeComponent);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static MXFPackage* mxf_resolve_source_package(MXFContext *mxf, UID package_uid)
+{
+ MXFPackage *package = NULL;
+ int i;
+
+ for (i = 0; i < mxf->packages_count; i++) {
+ package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[i], SourcePackage);
+ if (!package)
+ continue;
+
+ if (!memcmp(package->package_uid, package_uid, 16))
+ return package;
+ }
+ return NULL;
+}
+
+static MXFDescriptor* mxf_resolve_multidescriptor(MXFContext *mxf, MXFDescriptor *descriptor, int track_id)
+{
+ MXFDescriptor *sub_descriptor = NULL;
+ int i;
+
+ if (!descriptor)
+ return NULL;
+
+ if (descriptor->type == MultipleDescriptor) {
+ for (i = 0; i < descriptor->sub_descriptors_count; i++) {
+ sub_descriptor = mxf_resolve_strong_ref(mxf, &descriptor->sub_descriptors_refs[i], Descriptor);
+
+ if (!sub_descriptor) {
+ av_log(mxf->fc, AV_LOG_ERROR, "could not resolve sub descriptor strong ref\n");
+ continue;
+ }
+ if (sub_descriptor->linked_track_id == track_id) {
+ return sub_descriptor;
+ }
+ }
+ } else if (descriptor->type == Descriptor)
+ return descriptor;
+
+ return NULL;
+}
+
+static MXFStructuralComponent* mxf_resolve_essence_group_choice(MXFContext *mxf, MXFEssenceGroup *essence_group)
+{
+ MXFStructuralComponent *component = NULL;
+ MXFPackage *package = NULL;
+ MXFDescriptor *descriptor = NULL;
+ int i;
+
+ if (!essence_group || !essence_group->structural_components_count)
+ return NULL;
+
+ /* essence groups contains multiple representations of the same media,
+ this return the first components with a valid Descriptor typically index 0 */
+ for (i =0; i < essence_group->structural_components_count; i++){
+ component = mxf_resolve_strong_ref(mxf, &essence_group->structural_components_refs[i], SourceClip);
+ if (!component)
+ continue;
+
+ if (!(package = mxf_resolve_source_package(mxf, component->source_package_uid)))
+ continue;
+
+ descriptor = mxf_resolve_strong_ref(mxf, &package->descriptor_ref, Descriptor);
+ if (descriptor)
+ return component;
+ }
+ return NULL;
+}
+
+static MXFStructuralComponent* mxf_resolve_sourceclip(MXFContext *mxf, UID *strong_ref)
+{
+ MXFStructuralComponent *component = NULL;
+
+ component = mxf_resolve_strong_ref(mxf, strong_ref, AnyType);
+ if (!component)
+ return NULL;
+ switch (component->type) {
+ case SourceClip:
+ return component;
+ case EssenceGroup:
+ return mxf_resolve_essence_group_choice(mxf, (MXFEssenceGroup*) component);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static int mxf_parse_package_comments(MXFContext *mxf, AVDictionary **pm, MXFPackage *package)
+{
+ MXFTaggedValue *tag;
+ int size, i;
+ char *key = NULL;
+
+ for (i = 0; i < package->comment_count; i++) {
+ tag = mxf_resolve_strong_ref(mxf, &package->comment_refs[i], TaggedValue);
+ if (!tag || !tag->name || !tag->value)
+ continue;
+
+ size = strlen(tag->name) + 8 + 1;
+ key = av_mallocz(size);
+ if (!key)
+ return AVERROR(ENOMEM);
+
+ snprintf(key, size, "comment_%s", tag->name);
+ av_dict_set(pm, key, tag->value, AV_DICT_DONT_STRDUP_KEY);
+ }
+ return 0;
+}
+
+static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_track, AVStream *st)
+{
+ MXFPackage *physical_package = NULL;
+ MXFTrack *physical_track = NULL;
+ MXFStructuralComponent *sourceclip = NULL;
+ MXFTimecodeComponent *mxf_tc = NULL;
+ int i, j, k;
+ AVTimecode tc;
+ int flags;
+ int64_t start_position;
+
+ for (i = 0; i < source_track->sequence->structural_components_count; i++) {
+ sourceclip = mxf_resolve_strong_ref(mxf, &source_track->sequence->structural_components_refs[i], SourceClip);
+ if (!sourceclip)
+ continue;
+
+ if (!(physical_package = mxf_resolve_source_package(mxf, sourceclip->source_package_uid)))
+ break;
+
+ mxf_add_umid_metadata(&st->metadata, "reel_umid", physical_package);
+
+ /* the name of physical source package is name of the reel or tape */
+ if (physical_package->name && physical_package->name[0])
+ av_dict_set(&st->metadata, "reel_name", physical_package->name, 0);
+
+ /* the source timecode is calculated by adding the start_position of the sourceclip from the file source package track
+ * to the start_frame of the timecode component located on one of the tracks of the physical source package.
+ */
+ for (j = 0; j < physical_package->tracks_count; j++) {
+ if (!(physical_track = mxf_resolve_strong_ref(mxf, &physical_package->tracks_refs[j], Track))) {
+ av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track strong ref\n");
+ continue;
+ }
+
+ if (!(physical_track->sequence = mxf_resolve_strong_ref(mxf, &physical_track->sequence_ref, Sequence))) {
+ av_log(mxf->fc, AV_LOG_ERROR, "could not resolve source track sequence strong ref\n");
+ continue;
+ }
+
+ for (k = 0; k < physical_track->sequence->structural_components_count; k++) {
+ if (!(mxf_tc = mxf_resolve_timecode_component(mxf, &physical_track->sequence->structural_components_refs[k])))
+ continue;
+
+ flags = mxf_tc->drop_frame == 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0;
+ /* scale sourceclip start_position to match physical track edit rate */
+ start_position = av_rescale_q(sourceclip->start_position,
+ physical_track->edit_rate,
+ source_track->edit_rate);
+
+ 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;
+ }
+ }
+ }
+ }
+
+ return 0;
}
static int mxf_parse_structural_metadata(MXFContext *mxf)
{
MXFPackage *material_package = NULL;
- MXFPackage *temp_package = NULL;
int i, j, k, ret;
av_log(mxf->fc, AV_LOG_TRACE, "metadata sets count %d\n", mxf->metadata_sets_count);
@@ -1380,6 +1791,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
return AVERROR_INVALIDDATA;
}
+ mxf_add_umid_metadata(&mxf->fc->metadata, "material_package_umid", material_package);
+ if (material_package->name && material_package->name[0])
+ 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++) {
MXFPackage *source_package = NULL;
MXFTrack *material_track = NULL;
@@ -1387,38 +1803,53 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
MXFTrack *temp_track = NULL;
MXFDescriptor *descriptor = NULL;
MXFStructuralComponent *component = NULL;
+ MXFTimecodeComponent *mxf_tc = NULL;
UID *essence_container_ul = NULL;
const MXFCodecUL *codec_ul = NULL;
const MXFCodecUL *container_ul = NULL;
const MXFCodecUL *pix_fmt_ul = NULL;
AVStream *st;
+ AVTimecode tc;
+ int flags;
if (!(material_track = mxf_resolve_strong_ref(mxf, &material_package->tracks_refs[i], Track))) {
av_log(mxf->fc, AV_LOG_ERROR, "could not resolve material track strong ref\n");
continue;
}
+ if ((component = mxf_resolve_strong_ref(mxf, &material_track->sequence_ref, TimecodeComponent))) {
+ mxf_tc = (MXFTimecodeComponent*)component;
+ flags = mxf_tc->drop_frame == 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0;
+ if (av_timecode_init(&tc, mxf_tc->rate, flags, mxf_tc->start_frame, mxf->fc) == 0) {
+ mxf_add_timecode_metadata(&mxf->fc->metadata, "timecode", &tc);
+ }
+ }
+
if (!(material_track->sequence = mxf_resolve_strong_ref(mxf, &material_track->sequence_ref, Sequence))) {
av_log(mxf->fc, AV_LOG_ERROR, "could not resolve material track sequence strong ref\n");
continue;
}
- /* TODO: handle multiple source clips */
for (j = 0; j < material_track->sequence->structural_components_count; j++) {
- /* TODO: handle timecode component */
- component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], SourceClip);
+ component = mxf_resolve_strong_ref(mxf, &material_track->sequence->structural_components_refs[j], TimecodeComponent);
if (!component)
continue;
- for (k = 0; k < mxf->packages_count; k++) {
- temp_package = mxf_resolve_strong_ref(mxf, &mxf->packages_refs[k], SourcePackage);
- if (!temp_package)
- continue;
- if (!memcmp(temp_package->package_uid, component->source_package_uid, 16)) {
- source_package = temp_package;
- break;
- }
+ mxf_tc = (MXFTimecodeComponent*)component;
+ flags = mxf_tc->drop_frame == 1 ? AV_TIMECODE_FLAG_DROPFRAME : 0;
+ if (av_timecode_init(&tc, mxf_tc->rate, flags, mxf_tc->start_frame, mxf->fc) == 0) {
+ mxf_add_timecode_metadata(&mxf->fc->metadata, "timecode", &tc);
+ break;
}
+ }
+
+ /* TODO: handle multiple source clips */
+ for (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;
+
+ source_package = mxf_resolve_source_package(mxf, component->source_package_uid);
if (!source_package) {
av_log(mxf->fc, AV_LOG_TRACE, "material track %d: no corresponding source package found\n", material_track->track_id);
break;
@@ -1463,7 +1894,17 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
}
st->id = source_track->track_id;
st->priv_data = source_track;
- source_track->original_duration = st->duration = component->duration;
+
+ source_package->descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor_ref, AnyType);
+ descriptor = mxf_resolve_multidescriptor(mxf, source_package->descriptor, source_track->track_id);
+
+ /* A SourceClip from a EssenceGroup may only be a single frame of essence data. The clips duration is then how many
+ * frames its suppose to repeat for. Descriptor->duration, if present, contains the real duration of the essence data */
+ if (descriptor && descriptor->duration != AV_NOPTS_VALUE)
+ source_track->original_duration = st->duration = FFMIN(descriptor->duration, component->duration);
+ else
+ source_track->original_duration = st->duration = component->duration;
+
if (st->duration == -1)
st->duration = AV_NOPTS_VALUE;
st->start_time = component->start_position;
@@ -1486,24 +1927,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
codec_ul = mxf_get_codec_ul(ff_mxf_data_definition_uls, &source_track->sequence->data_definition_ul);
st->codec->codec_type = codec_ul->id;
- source_package->descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor_ref, AnyType);
- if (source_package->descriptor) {
- if (source_package->descriptor->type == MultipleDescriptor) {
- for (j = 0; j < source_package->descriptor->sub_descriptors_count; j++) {
- MXFDescriptor *sub_descriptor = mxf_resolve_strong_ref(mxf, &source_package->descriptor->sub_descriptors_refs[j], Descriptor);
-
- if (!sub_descriptor) {
- av_log(mxf->fc, AV_LOG_ERROR, "could not resolve sub descriptor strong ref\n");
- continue;
- }
- if (sub_descriptor->linked_track_id == source_track->track_id) {
- descriptor = sub_descriptor;
- break;
- }
- }
- } else if (source_package->descriptor->type == Descriptor)
- descriptor = source_package->descriptor;
- }
if (!descriptor) {
av_log(mxf->fc, AV_LOG_INFO, "source track %d: stream %d, no descriptor found\n", source_track->track_id, st->index);
continue;
@@ -1526,7 +1949,22 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
/* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */
codec_ul = mxf_get_codec_ul(ff_mxf_codec_uls, &descriptor->essence_codec_ul);
- st->codec->codec_id = codec_ul->id;
+ st->codec->codec_id = (enum AVCodecID)codec_ul->id;
+ av_log(mxf->fc, AV_LOG_VERBOSE, "%s: Universal Label: ",
+ avcodec_get_name(st->codec->codec_id));
+ for (k = 0; k < 16; k++) {
+ av_log(mxf->fc, AV_LOG_VERBOSE, "%.2x",
+ descriptor->essence_codec_ul[k]);
+ if (!(k+1 & 19) || k == 5)
+ av_log(mxf->fc, AV_LOG_VERBOSE, ".");
+ }
+ av_log(mxf->fc, AV_LOG_VERBOSE, "\n");
+
+ mxf_add_umid_metadata(&st->metadata, "file_package_umid", source_package);
+ if (source_package->name && source_package->name[0])
+ av_dict_set(&st->metadata, "file_package_name", source_package->name, 0);
+
+ mxf_parse_physical_source_package(mxf, source_track, st);
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
source_track->intra_only = mxf_is_intra_only(descriptor);
@@ -1534,28 +1972,24 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
if (st->codec->codec_id == AV_CODEC_ID_NONE)
st->codec->codec_id = container_ul->id;
st->codec->width = descriptor->width;
- /* Field height, not frame height */
- st->codec->height = descriptor->height;
+ st->codec->height = descriptor->height; /* Field height, not frame height */
switch (descriptor->frame_layout) {
case SegmentedFrame:
/* This one is a weird layout I don't fully understand. */
- av_log(mxf->fc, AV_LOG_INFO,
- "SegmentedFrame layout isn't currently supported\n");
+ av_log(mxf->fc, AV_LOG_INFO, "SegmentedFrame layout isn't currently supported\n");
break;
case FullFrame:
st->codec->field_order = AV_FIELD_PROGRESSIVE;
break;
case OneField:
/* Every other line is stored and needs to be duplicated. */
- av_log(mxf->fc, AV_LOG_INFO,
- "OneField frame layout isn't currently supported\n");
+ av_log(mxf->fc, AV_LOG_INFO, "OneField frame layout isn't currently supported\n");
+ break; /* The correct thing to do here is fall through, but by breaking we might be
+ able to decode some streams at half the vertical resolution, rather than not al all.
+ It's also for compatibility with the old behavior. */
+ case MixedFields:
break;
- /* The correct thing to do here is fall through, but by
- * breaking we might be able to decode some streams at half
- * the vertical resolution, rather than not al all.
- * It's also for compatibility with the old behavior. */
case SeparateFields:
- case MixedFields:
switch (descriptor->field_dominance) {
case MXF_TFF:
st->codec->field_order = AV_FIELD_TT;
@@ -1567,22 +2001,21 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
avpriv_request_sample(mxf->fc,
"Field dominance %d support",
descriptor->field_dominance);
+ case 0: // we already have many samples with field_dominance == unknown
break;
}
/* Turn field height into frame height. */
st->codec->height *= 2;
break;
default:
- av_log(mxf->fc, AV_LOG_INFO,
- "Unknown frame layout type: %d\n",
- descriptor->frame_layout);
+ av_log(mxf->fc, AV_LOG_INFO, "Unknown frame layout type: %d\n", descriptor->frame_layout);
}
if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) {
st->codec->pix_fmt = descriptor->pix_fmt;
if (st->codec->pix_fmt == AV_PIX_FMT_NONE) {
pix_fmt_ul = mxf_get_codec_ul(ff_mxf_pixel_format_uls,
&descriptor->essence_codec_ul);
- st->codec->pix_fmt = pix_fmt_ul->id;
+ st->codec->pix_fmt = (enum AVPixelFormat)pix_fmt_ul->id;
if (st->codec->pix_fmt == AV_PIX_FMT_NONE) {
/* support files created before RP224v10 by defaulting to UYVY422
if subsampling is 4:2:2 and component depth is 8-bit */
@@ -1596,19 +2029,18 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
}
st->need_parsing = AVSTREAM_PARSE_HEADERS;
if (material_track->sequence->origin) {
- char material_origin[3];
- snprintf(material_origin, sizeof(material_origin), "%d", material_track->sequence->origin);
- av_dict_set(&st->metadata, "material_track_origin", material_origin, 0);
+ av_dict_set_int(&st->metadata, "material_track_origin", material_track->sequence->origin, 0);
}
if (source_track->sequence->origin) {
- char source_origin[3];
- snprintf(source_origin, sizeof(source_origin), "%d", source_track->sequence->origin);
- av_dict_set(&st->metadata, "source_track_origin", source_origin, 0);
+ av_dict_set_int(&st->metadata, "source_track_origin", source_track->sequence->origin, 0);
}
+ if (descriptor->aspect_ratio.num && descriptor->aspect_ratio.den)
+ st->display_aspect_ratio = descriptor->aspect_ratio;
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul);
- if (st->codec->codec_id == AV_CODEC_ID_NONE)
- st->codec->codec_id = container_ul->id;
+ /* Only overwrite existing codec ID if it is unset or A-law, which is the default according to SMPTE RP 224. */
+ if (st->codec->codec_id == AV_CODEC_ID_NONE || (st->codec->codec_id == AV_CODEC_ID_PCM_ALAW && (enum AVCodecID)container_ul->id != AV_CODEC_ID_NONE))
+ st->codec->codec_id = (enum AVCodecID)container_ul->id;
st->codec->channels = descriptor->channels;
st->codec->bits_per_coded_sample = descriptor->bits_per_sample;
@@ -1653,10 +2085,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
}
}
if (descriptor->extradata) {
- st->codec->extradata = av_mallocz(descriptor->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (st->codec->extradata) {
+ if (!ff_alloc_extradata(st->codec, descriptor->extradata_size)) {
memcpy(st->codec->extradata, descriptor->extradata, descriptor->extradata_size);
- st->codec->extradata_size = descriptor->extradata_size;
}
} else if (st->codec->codec_id == AV_CODEC_ID_H264) {
ret = ff_generate_avci_extradata(st);
@@ -1674,45 +2104,6 @@ fail_and_free:
return ret;
}
-static int mxf_read_utf16_string(AVIOContext *pb, int size, char** str)
-{
- int ret;
- size_t buf_size;
-
- if (size < 0)
- return AVERROR(EINVAL);
-
- buf_size = size + size / 2 + 1;
- *str = av_malloc(buf_size);
- if (!*str)
- return AVERROR(ENOMEM);
-
- if ((ret = avio_get_str16be(pb, size, *str, buf_size)) < 0) {
- av_freep(str);
- return ret;
- }
-
- return ret;
-}
-
-static int mxf_uid_to_str(UID uid, char **str)
-{
- int i;
- char *p;
- p = *str = av_mallocz(sizeof(UID) * 2 + 4 + 1);
- if (!p)
- return AVERROR(ENOMEM);
- for (i = 0; i < sizeof(UID); i++) {
- snprintf(p, 2 + 1, "%.2x", uid[i]);
- p += 2;
- if (i == 3 || i == 5 || i == 7 || i == 9) {
- snprintf(p, 1 + 1, "-");
- p++;
- }
- }
- return 0;
-}
-
static int mxf_timestamp_to_str(uint64_t timestamp, char **str)
{
struct tm time = { 0 };
@@ -1742,7 +2133,7 @@ static int mxf_timestamp_to_str(uint64_t timestamp, char **str)
}
#define SET_STR_METADATA(pb, name, str) do { \
- if ((ret = mxf_read_utf16_string(pb, size, &str)) < 0) \
+ if ((ret = mxf_read_utf16be_string(pb, size, &str)) < 0) \
return ret; \
av_dict_set(&s->metadata, name, str, AV_DICT_DONT_STRDUP_VAL); \
} while (0)
@@ -1798,9 +2189,21 @@ static int mxf_read_identification_metadata(void *arg, AVIOContext *pb, int tag,
return 0;
}
+static int mxf_read_preface_metadata(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
+{
+ MXFContext *mxf = arg;
+ AVFormatContext *s = mxf->fc;
+ int ret;
+ char *str = NULL;
+
+ if (tag >= 0x8000 && (IS_KLV_KEY(uid, mxf_avid_project_name))) {
+ SET_STR_METADATA(pb, "project_name", str);
+ }
+ return 0;
+}
+
static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x05,0x01,0x00 }, mxf_read_primer_pack },
-// { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x2f,0x00 }, mxf_read_preface_pack },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x01,0x00 }, mxf_read_partition_pack },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x02,0x00 }, mxf_read_partition_pack },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02,0x03,0x00 }, mxf_read_partition_pack },
@@ -1811,12 +2214,15 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x03,0x04,0x00 }, mxf_read_partition_pack },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x02,0x00 }, mxf_read_partition_pack },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }, mxf_read_partition_pack },
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x2f,0x00 }, mxf_read_preface_metadata },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x30,0x00 }, mxf_read_identification_metadata },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x18,0x00 }, mxf_read_content_storage, 0, AnyType },
- { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_source_package, sizeof(MXFPackage), SourcePackage },
- { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_material_package, sizeof(MXFPackage), MaterialPackage },
- { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence },
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x37,0x00 }, mxf_read_package, sizeof(MXFPackage), SourcePackage },
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x36,0x00 }, mxf_read_package, sizeof(MXFPackage), MaterialPackage },
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0f,0x00 }, mxf_read_sequence, sizeof(MXFSequence), Sequence },
+ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x05,0x00 }, mxf_read_essence_group, sizeof(MXFEssenceGroup), EssenceGroup},
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x11,0x00 }, mxf_read_source_clip, sizeof(MXFStructuralComponent), SourceClip },
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3f,0x00 }, mxf_read_tagged_value, sizeof(MXFTaggedValue), TaggedValue },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x44,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), MultipleDescriptor },
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Generic Sound */
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* CDCI */
@@ -1829,11 +2235,27 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = {
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5e,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG2AudioDescriptor */
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */
{ { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent },
+ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0c,0x00 }, mxf_read_pulldown_component, sizeof(MXFPulldownComponent), PulldownComponent },
{ { 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 },
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType },
};
+static int mxf_metadataset_init(MXFMetadataSet *ctx, enum MXFMetadataSetType type)
+{
+ switch (type){
+ case MultipleDescriptor:
+ case Descriptor:
+ ((MXFDescriptor*)ctx)->pix_fmt = AV_PIX_FMT_NONE;
+ ((MXFDescriptor*)ctx)->duration = AV_NOPTS_VALUE;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadFunc *read_child, int ctx_size, enum MXFMetadataSetType type)
{
AVIOContext *pb = mxf->fc->pb;
@@ -1842,7 +2264,8 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF
if (!ctx)
return AVERROR(ENOMEM);
- while (avio_tell(pb) + 4 < klv_end && !pb->eof_reached) {
+ mxf_metadataset_init(ctx, type);
+ while (avio_tell(pb) + 4 < klv_end && !avio_feof(pb)) {
int ret;
int tag = avio_rb16(pb);
int size = avio_rb16(pb); /* KLV specified by 0x53 */
@@ -1865,16 +2288,20 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF
}
}
}
- if (ctx_size && tag == 0x3C0A)
+ if (ctx_size && tag == 0x3C0A) {
avio_read(pb, ctx->uid, 16);
- else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0)
+ } else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0) {
+ mxf_free_metadataset(&ctx, !!ctx_size);
return ret;
+ }
/* Accept the 64k local set limit being exceeded (Avid). Don't accept
* it extending past the end of the KLV though (zzuf5.mxf). */
if (avio_tell(pb) > klv_end) {
- if (ctx_size)
- av_free(ctx);
+ if (ctx_size) {
+ ctx->type = type;
+ mxf_free_metadataset(&ctx, !!ctx_size);
+ }
av_log(mxf->fc, AV_LOG_ERROR,
"local tag %#04x extends past end of local set @ %#"PRIx64"\n",
@@ -1888,23 +2315,98 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF
}
/**
- * Seeks to the previous partition, if possible
+ * Matches any partition pack key, in other words:
+ * - HeaderPartition
+ * - BodyPartition
+ * - FooterPartition
+ * @return non-zero if the key is a partition pack key, zero otherwise
+ */
+static int mxf_is_partition_pack_key(UID key)
+{
+ //NOTE: this is a little lax since it doesn't constraint key[14]
+ return !memcmp(key, mxf_header_partition_pack_key, 13) &&
+ key[13] >= 2 && key[13] <= 4;
+}
+
+/**
+ * Parses a metadata KLV
+ * @return <0 on error, 0 otherwise
+ */
+static int mxf_parse_klv(MXFContext *mxf, KLVPacket klv, MXFMetadataReadFunc *read,
+ int ctx_size, enum MXFMetadataSetType type)
+{
+ AVFormatContext *s = mxf->fc;
+ int res;
+ if (klv.key[5] == 0x53) {
+ res = mxf_read_local_tags(mxf, &klv, read, ctx_size, type);
+ } else {
+ uint64_t next = avio_tell(s->pb) + klv.length;
+ res = read(mxf, s->pb, 0, klv.length, klv.key, klv.offset);
+
+ /* only seek forward, else this can loop for a long time */
+ if (avio_tell(s->pb) > next) {
+ av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n",
+ klv.offset);
+ return AVERROR_INVALIDDATA;
+ }
+
+ avio_seek(s->pb, next, SEEK_SET);
+ }
+ if (res < 0) {
+ av_log(s, AV_LOG_ERROR, "error reading header metadata\n");
+ return res;
+ }
+ return 0;
+}
+
+/**
+ * Seeks to the previous partition and parses it, if possible
* @return <= 0 if we should stop parsing, > 0 if we should keep going
*/
static int mxf_seek_to_previous_partition(MXFContext *mxf)
{
AVIOContext *pb = mxf->fc->pb;
+ KLVPacket klv;
+ int64_t current_partition_ofs;
+ int ret;
if (!mxf->current_partition ||
mxf->run_in + mxf->current_partition->previous_partition <= mxf->last_forward_tell)
return 0; /* we've parsed all partitions */
/* seek to previous partition */
+ current_partition_ofs = mxf->current_partition->pack_ofs; //includes run-in
avio_seek(pb, mxf->run_in + mxf->current_partition->previous_partition, SEEK_SET);
mxf->current_partition = NULL;
av_log(mxf->fc, AV_LOG_TRACE, "seeking to previous partition\n");
+ /* Make sure this is actually a PartitionPack, and if so parse it.
+ * See deadlock2.mxf
+ */
+ if ((ret = klv_read_packet(&klv, pb)) < 0) {
+ av_log(mxf->fc, AV_LOG_ERROR, "failed to read PartitionPack KLV\n");
+ return ret;
+ }
+
+ if (!mxf_is_partition_pack_key(klv.key)) {
+ av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition @ %" PRIx64 " isn't a PartitionPack\n", klv.offset);
+ return AVERROR_INVALIDDATA;
+ }
+
+ /* We can't just check ofs >= current_partition_ofs because PreviousPartition
+ * can point to just before the current partition, causing klv_read_packet()
+ * to sync back up to it. See deadlock3.mxf
+ */
+ if (klv.offset >= current_partition_ofs) {
+ av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition for PartitionPack @ %"
+ PRIx64 " indirectly points to itself\n", current_partition_ofs);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = mxf_parse_klv(mxf, klv, mxf_read_partition_pack, 0, 0)) < 0)
+ return ret;
+
return 1;
}
@@ -1920,30 +2422,27 @@ static int mxf_parse_handle_essence(MXFContext *mxf)
if (mxf->parsing_backward) {
return mxf_seek_to_previous_partition(mxf);
} else {
- uint64_t offset = mxf->footer_partition ? mxf->footer_partition
- : mxf->last_partition;
-
- if (!offset) {
- av_log(mxf->fc, AV_LOG_TRACE, "no last partition\n");
+ if (!mxf->footer_partition) {
+ av_log(mxf->fc, AV_LOG_TRACE, "no FooterPartition\n");
return 0;
}
- av_log(mxf->fc, AV_LOG_TRACE, "seeking to last partition\n");
+ av_log(mxf->fc, AV_LOG_TRACE, "seeking to FooterPartition\n");
/* remember where we were so we don't end up seeking further back than this */
mxf->last_forward_tell = avio_tell(pb);
if (!pb->seekable) {
- av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing last partition\n");
+ av_log(mxf->fc, AV_LOG_INFO, "file is not seekable - not parsing FooterPartition\n");
return -1;
}
- /* seek to last partition and parse backward */
- if ((ret = avio_seek(pb, mxf->run_in + offset, SEEK_SET)) < 0) {
+ /* seek to FooterPartition and parse backward */
+ if ((ret = avio_seek(pb, mxf->run_in + mxf->footer_partition, SEEK_SET)) < 0) {
av_log(mxf->fc, AV_LOG_ERROR,
- "failed to seek to last partition @ 0x%" PRIx64
+ "failed to seek to FooterPartition @ 0x%" PRIx64
" (%"PRId64") - partial file?\n",
- mxf->run_in + offset, ret);
+ mxf->run_in + mxf->footer_partition, ret);
return ret;
}
@@ -1964,8 +2463,7 @@ static int mxf_parse_handle_partition_or_eof(MXFContext *mxf)
}
/**
- * Figure out the proper offset and length of the essence container
- * in each partition
+ * Figures out the proper offset and length of the essence container in each partition
*/
static void mxf_compute_essence_containers(MXFContext *mxf)
{
@@ -1982,7 +2480,7 @@ static void mxf_compute_essence_containers(MXFContext *mxf)
continue; /* BodySID == 0 -> no essence */
if (x >= mxf->partitions_count - 1)
- break; /* last partition - can't compute length (and we don't need to) */
+ break; /* FooterPartition - can't compute length (and we don't need to) */
/* essence container spans to the next partition */
p->essence_length = mxf->partitions[x+1].this_partition - p->essence_offset;
@@ -2005,38 +2503,6 @@ static int64_t round_to_kag(int64_t position, int kag_size)
return ret == position ? ret : ret + kag_size;
}
-static inline void compute_partition_essence_offset(AVFormatContext *s,
- MXFContext *mxf,
- KLVPacket *klv)
-{
- MXFPartition *cur_part = mxf->current_partition;
- /* for OP1a we compute essence_offset
- * for OPAtom we point essence_offset after the KL
- * (usually op1a_essence_offset + 20 or 25)
- * TODO: for OP1a we could eliminate this entire if statement, always
- * stopping parsing at op1a_essence_offset
- * for OPAtom we still need the actual essence_offset though
- * (the KL's length can vary)
- */
- int64_t op1a_essence_offset =
- round_to_kag(cur_part->this_partition + cur_part->pack_length,
- cur_part->kag_size) +
- round_to_kag(cur_part->header_byte_count, cur_part->kag_size) +
- round_to_kag(cur_part->index_byte_count, cur_part->kag_size);
-
- if (mxf->op == OPAtom) {
- /* point essence_offset to the actual data
- * OPAtom has all the essence in one big KLV
- */
- cur_part->essence_offset = avio_tell(s->pb);
- cur_part->essence_length = klv->length;
- } else {
- /* NOTE: op1a_essence_offset may be less than to klv.offset
- * (C0023S01.mxf) */
- cur_part->essence_offset = op1a_essence_offset;
- }
-}
-
static int is_pcm(enum AVCodecID codec_id)
{
/* we only care about "normal" PCM codecs until we get samples */
@@ -2073,20 +2539,95 @@ static void mxf_handle_small_eubc(AVFormatContext *s)
mxf->edit_units_per_packet = 1920;
}
+/**
+ * Deal with the case where OPAtom files does not have any IndexTableSegments.
+ */
+static int mxf_handle_missing_index_segment(MXFContext *mxf)
+{
+ AVFormatContext *s = mxf->fc;
+ AVStream *st = NULL;
+ MXFIndexTableSegment *segment = NULL;
+ MXFPartition *p = NULL;
+ int essence_partition_count = 0;
+ int i, ret;
+
+ if (mxf->op != OPAtom)
+ return 0;
+
+ /* TODO: support raw video without a index if they exist */
+ if (s->nb_streams != 1 || s->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO || !is_pcm(s->streams[0]->codec->codec_id))
+ return 0;
+
+ /* check if file already has a IndexTableSegment */
+ for (i = 0; i < mxf->metadata_sets_count; i++) {
+ if (mxf->metadata_sets[i]->type == IndexTableSegment)
+ return 0;
+ }
+
+ /* find the essence partition */
+ for (i = 0; i < mxf->partitions_count; i++) {
+ /* BodySID == 0 -> no essence */
+ if (!mxf->partitions[i].body_sid)
+ continue;
+
+ p = &mxf->partitions[i];
+ essence_partition_count++;
+ }
+
+ /* only handle files with a single essence partition */
+ if (essence_partition_count != 1)
+ return 0;
+
+ if (!(segment = av_mallocz(sizeof(*segment))))
+ return AVERROR(ENOMEM);
+
+ if ((ret = mxf_add_metadata_set(mxf, segment))) {
+ mxf_free_metadataset((MXFMetadataSet**)&segment, 1);
+ return ret;
+ }
+
+ st = s->streams[0];
+ segment->type = IndexTableSegment;
+ /* stream will be treated as small EditUnitByteCount */
+ segment->edit_unit_byte_count = (av_get_bits_per_sample(st->codec->codec_id) * st->codec->channels) >> 3;
+ segment->index_start_position = 0;
+ segment->index_duration = s->streams[0]->duration;
+ segment->index_sid = p->index_sid;
+ segment->body_sid = p->body_sid;
+ return 0;
+}
+
static void mxf_read_random_index_pack(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
uint32_t length;
- int64_t file_size;
+ int64_t file_size, max_rip_length, min_rip_length;
KLVPacket klv;
if (!s->pb->seekable)
return;
file_size = avio_size(s->pb);
+
+ /* S377m says to check the RIP length for "silly" values, without defining "silly".
+ * The limit below assumes a file with nothing but partition packs and a RIP.
+ * Before changing this, consider that a muxer may place each sample in its own partition.
+ *
+ * 105 is the size of the smallest possible PartitionPack
+ * 12 is the size of each RIP entry
+ * 28 is the size of the RIP header and footer, assuming an 8-byte BER
+ */
+ max_rip_length = ((file_size - mxf->run_in) / 105) * 12 + 28;
+ max_rip_length = FFMIN(max_rip_length, INT_MAX); //2 GiB and up is also silly
+
+ /* We're only interested in RIPs with at least two entries.. */
+ min_rip_length = 16+1+24+4;
+
+ /* See S377m section 11 */
avio_seek(s->pb, file_size - 4, SEEK_SET);
length = avio_rb32(s->pb);
- if (length <= 32 || length >= FFMIN(file_size, INT_MAX))
+
+ if (length < min_rip_length || length > max_rip_length)
goto end;
avio_seek(s->pb, file_size - length, SEEK_SET);
if (klv_read_packet(&klv, s->pb) < 0 ||
@@ -2095,7 +2636,13 @@ static void mxf_read_random_index_pack(AVFormatContext *s)
goto end;
avio_skip(s->pb, klv.length - 12);
- mxf->last_partition = avio_rb64(s->pb);
+ mxf->footer_partition = avio_rb64(s->pb);
+
+ /* sanity check */
+ if (mxf->run_in + mxf->footer_partition >= file_size) {
+ av_log(s, AV_LOG_WARNING, "bad FooterPartition in RIP - ignoring\n");
+ mxf->footer_partition = 0;
+ }
end:
avio_seek(s->pb, mxf->run_in, SEEK_SET);
@@ -2121,8 +2668,7 @@ static int mxf_read_header(AVFormatContext *s)
mxf_read_random_index_pack(s);
- while (!s->pb->eof_reached) {
-
+ while (!avio_feof(s->pb)) {
const MXFMetadataReadTableEntry *metadata;
if (klv_read_packet(&klv, s->pb) < 0) {
@@ -2141,13 +2687,32 @@ static int mxf_read_header(AVFormatContext *s)
IS_KLV_KEY(klv.key, mxf_system_item_key)) {
if (!mxf->current_partition) {
- av_log(mxf->fc, AV_LOG_ERROR,
- "found essence prior to first PartitionPack\n");
+ av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n");
return AVERROR_INVALIDDATA;
}
if (!mxf->current_partition->essence_offset) {
- compute_partition_essence_offset(s, mxf, &klv);
+ /* for OP1a we compute essence_offset
+ * for OPAtom we point essence_offset after the KL (usually op1a_essence_offset + 20 or 25)
+ * TODO: for OP1a we could eliminate this entire if statement, always stopping parsing at op1a_essence_offset
+ * for OPAtom we still need the actual essence_offset though (the KL's length can vary)
+ */
+ int64_t op1a_essence_offset =
+ round_to_kag(mxf->current_partition->this_partition +
+ mxf->current_partition->pack_length, mxf->current_partition->kag_size) +
+ round_to_kag(mxf->current_partition->header_byte_count, mxf->current_partition->kag_size) +
+ round_to_kag(mxf->current_partition->index_byte_count, mxf->current_partition->kag_size);
+
+ if (mxf->op == OPAtom) {
+ /* point essence_offset to the actual data
+ * OPAtom has all the essence in one big KLV
+ */
+ mxf->current_partition->essence_offset = avio_tell(s->pb);
+ mxf->current_partition->essence_length = klv.length;
+ } else {
+ /* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf) */
+ mxf->current_partition->essence_offset = op1a_essence_offset;
+ }
}
if (!essence_offset)
@@ -2157,8 +2722,7 @@ static int mxf_read_header(AVFormatContext *s)
if (mxf_parse_handle_essence(mxf) <= 0)
break;
continue;
- } else if (!memcmp(klv.key, mxf_header_partition_pack_key, 13) &&
- klv.key[13] >= 2 && klv.key[13] <= 4 && mxf->current_partition) {
+ } else if (mxf_is_partition_pack_key(klv.key) && mxf->current_partition) {
/* next partition pack - keep going, seek to previous partition or stop */
if(mxf_parse_handle_partition_or_eof(mxf) <= 0)
break;
@@ -2169,26 +2733,8 @@ static int mxf_read_header(AVFormatContext *s)
for (metadata = mxf_metadata_read_table; metadata->read; metadata++) {
if (IS_KLV_KEY(klv.key, metadata->key)) {
- int res;
- if (klv.key[5] == 0x53) {
- res = mxf_read_local_tags(mxf, &klv, metadata->read, metadata->ctx_size, metadata->type);
- } else {
- uint64_t next = avio_tell(s->pb) + klv.length;
- res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset);
-
- /* only seek forward, else this can loop for a long time */
- if (avio_tell(s->pb) > next) {
- av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n",
- klv.offset);
- return AVERROR_INVALIDDATA;
- }
-
- avio_seek(s->pb, next, SEEK_SET);
- }
- if (res < 0) {
- av_log(s, AV_LOG_ERROR, "error reading header metadata\n");
- return res;
- }
+ if ((ret = mxf_parse_klv(mxf, klv, metadata->read, metadata->ctx_size, metadata->type)) < 0)
+ goto fail;
break;
} else {
av_log(s, AV_LOG_VERBOSE, "Dark key " PRIxUID "\n",
@@ -2201,7 +2747,8 @@ static int mxf_read_header(AVFormatContext *s)
/* FIXME avoid seek */
if (!essence_offset) {
av_log(s, AV_LOG_ERROR, "no essence\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
avio_seek(s->pb, essence_offset, SEEK_SET);
@@ -2210,10 +2757,11 @@ static int mxf_read_header(AVFormatContext *s)
/* we need to do this before computing the index tables
* to be able to fill in zero IndexDurations with st->duration */
if ((ret = mxf_parse_structural_metadata(mxf)) < 0)
- return ret;
+ goto fail;
+ mxf_handle_missing_index_segment(mxf);
if ((ret = mxf_compute_index_tables(mxf)) < 0)
- return ret;
+ goto fail;
if (mxf->nb_index_tables > 1) {
/* TODO: look up which IndexSID to use via EssenceContainerData */
@@ -2221,12 +2769,17 @@ static int mxf_read_header(AVFormatContext *s)
mxf->nb_index_tables, mxf->index_tables[0].index_sid);
} else if (mxf->nb_index_tables == 0 && mxf->op == OPAtom) {
av_log(mxf->fc, AV_LOG_ERROR, "cannot demux OPAtom without an index\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
mxf_handle_small_eubc(s);
return 0;
+fail:
+ mxf_read_close(s);
+
+ return ret;
}
/**
@@ -2243,11 +2796,9 @@ static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset
if (mxf->nb_index_tables <= 0)
return -1;
- /* find mxf->current_edit_unit so that the next edit unit starts ahead
- * of current_offset */
+ /* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */
while (mxf->current_edit_unit >= 0) {
- if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1,
- NULL, &next_ofs, 0) < 0)
+ if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0)
return -1;
if (next_ofs <= last_ofs) {
@@ -2265,8 +2816,7 @@ static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset
mxf->current_edit_unit++;
}
- /* not checking mxf->current_edit_unit >= t->nb_ptses here since CBR files
- * may lack IndexEntryArrays */
+ /* not checking mxf->current_edit_unit >= t->nb_ptses here since CBR files may lack IndexEntryArrays */
if (mxf->current_edit_unit < 0)
return -1;
@@ -2304,8 +2854,7 @@ static int mxf_compute_sample_count(MXFContext *mxf, int stream_index,
size++;
}
- if (!size)
- return 0;
+ av_assert2(size);
*sample_count = (mxf->current_edit_unit / size) * (uint64_t)total;
for (i = 0; i < mxf->current_edit_unit % size; i++) {
@@ -2326,10 +2875,11 @@ static int mxf_set_audio_pts(MXFContext *mxf, AVCodecContext *codec,
pkt->pts = track->sample_count;
- if (codec->channels <= 0 || codec->channels * bits_per_sample < 8)
- return AVERROR_INVALIDDATA;
-
- track->sample_count += pkt->size / (codec->channels * bits_per_sample / 8);
+ if ( codec->channels <= 0
+ || bits_per_sample <= 0
+ || codec->channels * (int64_t)bits_per_sample < 8)
+ return AVERROR(EINVAL);
+ track->sample_count += pkt->size / (codec->channels * (int64_t)bits_per_sample / 8);
return 0;
}
@@ -2339,9 +2889,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
MXFContext *mxf = s->priv_data;
int ret;
- while (!s->pb->eof_reached) {
- if ((ret = klv_read_packet(&klv, s->pb)) < 0)
- return ret;
+ while ((ret = klv_read_packet(&klv, s->pb)) == 0) {
PRINT_KEY(s, "read packet", klv.key);
av_log(s, AV_LOG_TRACE, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset);
if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) {
@@ -2377,9 +2925,8 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
next_ofs = mxf_set_current_edit_unit(mxf, klv.offset);
if (next_ofs >= 0 && next_klv > next_ofs) {
- /* if this check is hit then it's possible OPAtom was treated
- * as OP1a truncate the packet since it's probably very large
- * (>2 GiB is common) */
+ /* if this check is hit then it's possible OPAtom was treated as OP1a
+ * truncate the packet since it's probably very large (>2 GiB is common) */
avpriv_request_sample(s,
"OPAtom misinterpreted as OP1a?"
"KLV for edit unit %i extending into "
@@ -2404,21 +2951,19 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
pkt->stream_index = index;
pkt->pos = klv.offset;
- codec = s->streams[index]->codec;
+ codec = st->codec;
if (codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) {
/* mxf->current_edit_unit good - see if we have an
* index table to derive timestamps from */
MXFIndexTable *t = &mxf->index_tables[0];
- if (mxf->nb_index_tables >= 1 &&
- mxf->current_edit_unit < t->nb_ptses) {
+ if (mxf->nb_index_tables >= 1 && mxf->current_edit_unit < t->nb_ptses) {
pkt->dts = mxf->current_edit_unit + t->first_dts;
pkt->pts = t->ptses[mxf->current_edit_unit];
} else if (track->intra_only) {
/* intra-only -> PTS = EditUnit.
- * let utils.c figure out DTS since it can be
- * < PTS if low_delay = 0 (Sony IMX30) */
+ * let utils.c figure out DTS since it can be < PTS if low_delay = 0 (Sony IMX30) */
pkt->pts = mxf->current_edit_unit;
}
} else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -2435,7 +2980,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt)
skip:
avio_skip(s->pb, klv.length);
}
- return AVERROR_EOF;
+ return avio_feof(s->pb) ? AVERROR_EOF : ret;
}
static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
@@ -2479,8 +3024,8 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0)
return ret64;
- if ((ret = av_get_packet(s->pb, pkt, size)) != size)
- return ret < 0 ? ret : AVERROR_EOF;
+ if ((size = av_get_packet(s->pb, pkt, size)) < 0)
+ return size;
pkt->stream_index = 0;
@@ -2499,11 +3044,9 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
-
static int mxf_read_close(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
- MXFIndexTableSegment *seg;
int i;
av_freep(&mxf->packages_refs);
@@ -2512,40 +3055,19 @@ static int mxf_read_close(AVFormatContext *s)
s->streams[i]->priv_data = NULL;
for (i = 0; i < mxf->metadata_sets_count; i++) {
- switch (mxf->metadata_sets[i]->type) {
- case Descriptor:
- av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->extradata);
- break;
- case MultipleDescriptor:
- av_freep(&((MXFDescriptor *)mxf->metadata_sets[i])->sub_descriptors_refs);
- break;
- case Sequence:
- av_freep(&((MXFSequence *)mxf->metadata_sets[i])->structural_components_refs);
- break;
- case SourcePackage:
- case MaterialPackage:
- av_freep(&((MXFPackage *)mxf->metadata_sets[i])->tracks_refs);
- break;
- case IndexTableSegment:
- seg = (MXFIndexTableSegment *)mxf->metadata_sets[i];
- av_freep(&seg->temporal_offset_entries);
- av_freep(&seg->flag_entries);
- av_freep(&seg->stream_offset_entries);
- break;
- default:
- break;
- }
- av_freep(&mxf->metadata_sets[i]);
+ mxf_free_metadataset(mxf->metadata_sets + i, 1);
}
av_freep(&mxf->partitions);
av_freep(&mxf->metadata_sets);
av_freep(&mxf->aesc);
av_freep(&mxf->local_tags);
- for (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);
+ if (mxf->index_tables) {
+ for (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);
+ }
}
av_freep(&mxf->index_tables);
@@ -2553,18 +3075,27 @@ static int mxf_read_close(AVFormatContext *s)
}
static int mxf_probe(AVProbeData *p) {
- uint8_t *bufp = p->buf;
- uint8_t *end = p->buf + p->buf_size;
+ const uint8_t *bufp = p->buf;
+ const uint8_t *end = p->buf + p->buf_size;
if (p->buf_size < sizeof(mxf_header_partition_pack_key))
return 0;
/* Must skip Run-In Sequence and search for MXF header partition pack key SMPTE 377M 5.5 */
end -= sizeof(mxf_header_partition_pack_key);
- for (; bufp < end; bufp++) {
- if (IS_KLV_KEY(bufp, mxf_header_partition_pack_key))
- return AVPROBE_SCORE_MAX;
+
+ for (; bufp < end;) {
+ if (!((bufp[13] - 1) & 0xF2)){
+ if (AV_RN32(bufp ) == AV_RN32(mxf_header_partition_pack_key ) &&
+ AV_RN32(bufp+ 4) == AV_RN32(mxf_header_partition_pack_key+ 4) &&
+ AV_RN32(bufp+ 8) == AV_RN32(mxf_header_partition_pack_key+ 8) &&
+ AV_RN16(bufp+12) == AV_RN16(mxf_header_partition_pack_key+12))
+ return AVPROBE_SCORE_MAX;
+ bufp ++;
+ } else
+ bufp += 10;
}
+
return 0;
}
@@ -2615,7 +3146,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
sample_time = FFMIN(sample_time, source_track->original_duration - 1);
}
- if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) << 0)
+ if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) < 0)
return ret;
ff_update_cur_dts(s, st, sample_time);
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index f434b4a1a3..adac69efd2 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2008 GUCAS, Zhentan Feng <spyfeng at gmail dot com>
* Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
* SMPTE 377M MXF File Format Specifications
* SMPTE 379M MXF Generic Container
* SMPTE 381M Mapping MPEG Streams into the MXF Generic Container
+ * SMPTE 422M Mapping JPEG 2000 Codestreams into the MXF Generic Container
* SMPTE RP210: SMPTE Metadata Dictionary
* SMPTE RP224: Registry of SMPTE Universal Labels
*/
@@ -34,18 +35,25 @@
#include <math.h>
#include <time.h>
+#include "libavutil/opt.h"
#include "libavutil/random_seed.h"
+#include "libavutil/timecode.h"
+#include "libavutil/avassert.h"
+#include "libavutil/pixdesc.h"
#include "libavutil/time_internal.h"
#include "libavcodec/bytestream.h"
+#include "libavcodec/dnxhddata.h"
+#include "libavcodec/h264.h"
+#include "libavcodec/internal.h"
#include "audiointerleave.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "mxf.h"
-
-static const int NTSC_samples_per_frame[] = { 1602, 1601, 1602, 1601, 1602, 0 };
-static const int PAL_samples_per_frame[] = { 1920, 0 };
+#include "config.h"
extern AVOutputFormat ff_mxf_d10_muxer;
+extern AVOutputFormat ff_mxf_opatom_muxer;
#define EDIT_UNITS_PER_BODY 250
#define KAG_SIZE 512
@@ -69,9 +77,14 @@ typedef struct MXFStreamContext {
const UID *codec_ul;
int order; ///< interleaving order if dts are equal
int interlaced; ///< whether picture is interlaced
+ int field_dominance; ///< tff=1, bff=2
+ int component_depth;
+ int color_siting;
+ int h_chroma_sub_sample;
int temporal_reordering;
AVRational aspect_ratio; ///< display aspect ratio
int closed_gop; ///< gop is closed, used in mpeg-2 frame parsing
+ int video_bit_rate;
} MXFStreamContext;
typedef struct MXFContainerEssenceEntry {
@@ -88,6 +101,10 @@ static const struct {
{ AV_CODEC_ID_MPEG2VIDEO, 0 },
{ AV_CODEC_ID_PCM_S24LE, 1 },
{ AV_CODEC_ID_PCM_S16LE, 1 },
+ { AV_CODEC_ID_DVVIDEO, 15 },
+ { AV_CODEC_ID_DNXHD, 24 },
+ { AV_CODEC_ID_JPEG2000, 34 },
+ { AV_CODEC_ID_H264, 35 },
{ AV_CODEC_ID_NONE }
};
@@ -164,6 +181,111 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x06,0x01,0x10,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 },
mxf_write_generic_sound_desc },
+ // DV Unknown
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x7F,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x00,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DV25 525/60
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x40,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x01,0x00 },
+ mxf_write_cdci_desc },
+ // DV25 625/50
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x41,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x02,0x00 },
+ mxf_write_cdci_desc },
+ // DV50 525/60
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x50,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x03,0x00 },
+ mxf_write_cdci_desc },
+ // DV50 625/50
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x51,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x04,0x00 },
+ mxf_write_cdci_desc },
+ // DV100 1080/60
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x60,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x05,0x00 },
+ mxf_write_cdci_desc },
+ // DV100 1080/50
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x61,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x06,0x00 },
+ mxf_write_cdci_desc },
+ // DV100 720/60
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x62,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x07,0x00 },
+ mxf_write_cdci_desc },
+ // DV100 720/50
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x63,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x08,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 1080p 10bit high
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x01,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 1080p 8bit medium
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x03,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 1080p 8bit high
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x04,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 1080i 10bit high
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x07,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 1080i 8bit medium
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x08,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 1080i 8bit high
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x09,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 720p 10bit
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x10,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 720p 8bit high
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x11,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 720p 8bit medium
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x12,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // DNxHD 720p 8bit low
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x13,0x00,0x00 },
+ mxf_write_cdci_desc },
+ // JPEG2000
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x08,0x00 },
+ { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 },
+ mxf_write_cdci_desc },
+ // H.264
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x10,0x60,0x01 },
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 },
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 },
+ mxf_write_mpegvideo_desc },
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
@@ -171,6 +293,7 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
};
typedef struct MXFContext {
+ AVClass *av_class;
int64_t footer_partition_offset;
int essence_container_count;
AVRational time_base;
@@ -184,14 +307,16 @@ typedef struct MXFContext {
unsigned body_partitions_count;
int last_key_index; ///< index of last key frame
uint64_t duration;
+ AVTimecode tc; ///< timecode context
AVStream *timecode_track;
int timecode_base; ///< rounded time code base (25 or 30)
- int timecode_start; ///< frame number computed from mpeg-2 gop header timecode
- int timecode_drop_frame; ///< time code use drop frame method frop mpeg-2 essence gop header
int edit_unit_byte_count; ///< fixed edit unit byte count
uint64_t body_offset;
uint32_t instance_number;
uint8_t umid[16]; ///< unique material identifier
+ int channel_count;
+ uint32_t tagged_value_count;
+ AVRational audio_edit_rate;
} MXFContext;
static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd };
@@ -201,6 +326,7 @@ static const uint8_t umid_ul[] = { 0x06,0x0A,0x2B,0x34,0x01,0x01,0x
* complete key for operation pattern, partitions, and primer pack
*/
static const uint8_t op1a_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x01,0x09,0x00 };
+static const uint8_t opatom_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x02,0x01,0x10,0x03,0x00,0x00 };
static const uint8_t footer_partition_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x04,0x04,0x00 }; // ClosedComplete
static const uint8_t primer_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x02,0x01,0x01,0x05,0x01,0x00 };
static const uint8_t index_table_segment_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 };
@@ -246,7 +372,9 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x4401, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x01,0x01,0x15,0x10,0x00,0x00,0x00,0x00}}, /* Package UID */
{ 0x4405, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x01,0x03,0x00,0x00}}, /* Package Creation Date */
{ 0x4404, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x02,0x05,0x00,0x00}}, /* Package Modified Date */
+ { 0x4402, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x01,0x03,0x03,0x02,0x01,0x00,0x00,0x00}}, /* Package Name */
{ 0x4403, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x06,0x05,0x00,0x00}}, /* Tracks Strong reference array */
+ { 0x4406, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0C,0x00,0x00,0x00}}, /* User Comments */
{ 0x4701, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x02,0x03,0x00,0x00}}, /* Descriptor */
// Track
{ 0x4801, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x01,0x07,0x01,0x01,0x00,0x00,0x00,0x00}}, /* Track ID */
@@ -266,10 +394,14 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x1501, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x03,0x01,0x05,0x00,0x00}}, /* Start Time Code */
{ 0x1502, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x04,0x01,0x01,0x02,0x06,0x00,0x00}}, /* Rounded Time Code Base */
{ 0x1503, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x04,0x01,0x01,0x05,0x00,0x00,0x00}}, /* Drop Frame */
+ // Tagged Value
+ { 0x5001, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x09,0x01,0x00,0x00}}, /* Name */
+ { 0x5003, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0A,0x01,0x00,0x00}}, /* Value */
// File Descriptor
{ 0x3F01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x06,0x01,0x01,0x04,0x06,0x0B,0x00,0x00}}, /* Sub Descriptors reference array */
{ 0x3006, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x06,0x01,0x01,0x03,0x05,0x00,0x00,0x00}}, /* Linked Track ID */
{ 0x3001, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x06,0x01,0x01,0x00,0x00,0x00,0x00}}, /* SampleRate */
+ { 0x3002, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x06,0x01,0x02,0x00,0x00,0x00,0x00}}, /* ContainerDuration */
{ 0x3004, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x01,0x02,0x00,0x00}}, /* Essence Container */
// Generic Picture Essence Descriptor
{ 0x320C, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x03,0x01,0x04,0x00,0x00,0x00}}, /* Frame Layout */
@@ -278,11 +410,14 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x3202, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x02,0x01,0x00,0x00,0x00}}, /* Stored Height */
{ 0x3209, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0C,0x00,0x00,0x00}}, /* Display Width */
{ 0x3208, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0B,0x00,0x00,0x00}}, /* Display Height */
+ { 0x320B, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0E,0x00,0x00,0x00}}, /* Presentation Y offset */
{ 0x320E, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x00,0x00,0x00}}, /* Aspect Ratio */
{ 0x3201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x06,0x01,0x00,0x00,0x00,0x00}}, /* Picture Essence Coding */
+ { 0x3212, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x03,0x01,0x06,0x00,0x00,0x00}}, /* Field Dominance (Opt) */
// CDCI Picture Essence Descriptor
{ 0x3301, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x03,0x0A,0x00,0x00,0x00}}, /* Component Depth */
{ 0x3302, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x05,0x00,0x00,0x00}}, /* Horizontal Subsampling */
+ { 0x3303, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x06,0x00,0x00,0x00}}, /* Color Siting */
// Generic Sound Essence Descriptor
{ 0x3D02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x04,0x02,0x03,0x01,0x04,0x00,0x00,0x00}}, /* Locked/Unlocked */
{ 0x3D03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x01,0x01,0x01,0x00,0x00}}, /* Audio sampling rate */
@@ -363,6 +498,12 @@ static void klv_encode_ber4_length(AVIOContext *pb, int len)
avio_wb24(pb, len);
}
+static void klv_encode_ber9_length(AVIOContext *pb, uint64_t len)
+{
+ avio_w8(pb, 0x80 + 8);
+ avio_wb64(pb, len);
+}
+
/*
* Get essence container ul index
*/
@@ -427,18 +568,25 @@ static const MXFCodecUL *mxf_get_data_definition_ul(int type)
return uls;
}
+//one EC -> one descriptor. N ECs -> MultipleDescriptor + N descriptors
+#define DESCRIPTOR_COUNT(essence_container_count) \
+ (essence_container_count > 1 ? essence_container_count + 1 : essence_container_count)
+
static void mxf_write_essence_container_refs(AVFormatContext *s)
{
MXFContext *c = s->priv_data;
AVIOContext *pb = s->pb;
int i;
- mxf_write_refs_count(pb, c->essence_container_count);
+ mxf_write_refs_count(pb, DESCRIPTOR_COUNT(c->essence_container_count));
av_log(s,AV_LOG_DEBUG, "essence container count:%d\n", c->essence_container_count);
for (i = 0; i < c->essence_container_count; i++) {
MXFStreamContext *sc = s->streams[i]->priv_data;
avio_write(pb, mxf_essence_container_uls[sc->index].container_ul, 16);
}
+
+ if (c->essence_container_count > 1)
+ avio_write(pb, multiple_desc_ul, 16);
}
static void mxf_write_preface(AVFormatContext *s)
@@ -448,7 +596,7 @@ static void mxf_write_preface(AVFormatContext *s)
mxf_write_metadata_key(pb, 0x012f00);
PRINT_KEY(s, "preface key", pb->buf_ptr - 16);
- klv_encode_ber_length(pb, 130 + 16LL * mxf->essence_container_count);
+ klv_encode_ber_length(pb, 130 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
// write preface set uid
mxf_write_local_tag(pb, 16, 0x3C0A);
@@ -474,10 +622,13 @@ static void mxf_write_preface(AVFormatContext *s)
// operational pattern
mxf_write_local_tag(pb, 16, 0x3B09);
- avio_write(pb, op1a_ul, 16);
+ if (s->oformat == &ff_mxf_opatom_muxer)
+ avio_write(pb, opatom_ul, 16);
+ else
+ avio_write(pb, op1a_ul, 16);
// write essence_container_refs
- mxf_write_local_tag(pb, 8 + 16 * mxf->essence_container_count, 0x3B0A);
+ mxf_write_local_tag(pb, 8 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count), 0x3B0A);
mxf_write_essence_container_refs(s);
// write dm_scheme_refs
@@ -486,22 +637,69 @@ static void mxf_write_preface(AVFormatContext *s)
}
/*
- * Write a local tag containing an ascii string as utf-16
+ * Returns the length of the UTF-16 string, in 16-bit characters, that would result
+ * from decoding the utf-8 string.
+ */
+static uint64_t mxf_utf16len(const char *utf8_str)
+{
+ const uint8_t *q = utf8_str;
+ uint64_t size = 0;
+ while (*q) {
+ uint32_t ch;
+ GET_UTF8(ch, *q++, goto invalid;)
+ if (ch < 0x10000)
+ size++;
+ else
+ size += 2;
+ continue;
+invalid:
+ av_log(NULL, AV_LOG_ERROR, "Invaid UTF8 sequence in mxf_utf16len\n\n");
+ }
+ size += 1;
+ return size;
+}
+
+/*
+ * Returns the calculated length a local tag containing an utf-8 string as utf-16
+ */
+static int mxf_utf16_local_tag_length(const char *utf8_str)
+{
+ uint64_t size;
+
+ if (!utf8_str)
+ return 0;
+
+ size = mxf_utf16len(utf8_str);
+ if (size >= UINT16_MAX/2) {
+ av_log(NULL, AV_LOG_ERROR, "utf16 local tag size %"PRIx64" invalid (too large), ignoring\n", size);
+ return 0;
+ }
+
+ return 4 + size * 2;
+}
+
+/*
+ * Write a local tag containing an utf-8 string as utf-16
*/
static void mxf_write_local_tag_utf16(AVIOContext *pb, int tag, const char *value)
{
- int i, size = strlen(value);
+ uint64_t size = mxf_utf16len(value);
+
+ if (size >= UINT16_MAX/2) {
+ av_log(NULL, AV_LOG_ERROR, "utf16 local tag size %"PRIx64" invalid (too large), ignoring\n", size);
+ return;
+ }
+
mxf_write_local_tag(pb, size*2, tag);
- for (i = 0; i < size; i++)
- avio_wb16(pb, value[i]);
+ avio_put_str16be(pb, value);
}
static void mxf_write_identification(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
- const char *company = "Libav";
- const char *product = "OP1a Muxer";
+ const char *company = "FFmpeg";
+ const char *product = s->oformat != &ff_mxf_opatom_muxer ? "OP1a Muxer" : "OPAtom Muxer";
const char *version;
int length;
@@ -510,7 +708,9 @@ static void mxf_write_identification(AVFormatContext *s)
version = s->flags & AVFMT_FLAG_BITEXACT ?
"0.0.0" : AV_STRINGIFY(LIBAVFORMAT_VERSION);
- length = 84 + (strlen(company)+strlen(product)+strlen(version))*2; // utf-16
+ length = 72 + mxf_utf16_local_tag_length(company) +
+ mxf_utf16_local_tag_length(product) +
+ mxf_utf16_local_tag_length(version);
klv_encode_ber_length(pb, length);
// write uid
@@ -521,7 +721,6 @@ static void mxf_write_identification(AVFormatContext *s)
// write generation uid
mxf_write_local_tag(pb, 16, 0x3C09);
mxf_write_uuid(pb, Identification, 1);
-
mxf_write_local_tag_utf16(pb, 0x3C01, company); // Company Name
mxf_write_local_tag_utf16(pb, 0x3C02, product); // Product Name
mxf_write_local_tag_utf16(pb, 0x3C04, version); // Version String
@@ -587,8 +786,14 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe
avio_write(pb, sc->track_essence_element_key + 12, 4);
mxf_write_local_tag(pb, 8, 0x4B01);
- avio_wb32(pb, mxf->time_base.den);
- avio_wb32(pb, mxf->time_base.num);
+
+ if (st == mxf->timecode_track && s->oformat == &ff_mxf_opatom_muxer){
+ avio_wb32(pb, mxf->tc.rate.num);
+ avio_wb32(pb, mxf->tc.rate.den);
+ } else {
+ avio_wb32(pb, mxf->time_base.den);
+ avio_wb32(pb, mxf->time_base.num);
+ }
// write origin
mxf_write_local_tag(pb, 8, 0x4B02);
@@ -617,7 +822,12 @@ static void mxf_write_common_fields(AVFormatContext *s, AVStream *st)
// write duration
mxf_write_local_tag(pb, 8, 0x0202);
- avio_wb64(pb, mxf->duration);
+
+ if (st != mxf->timecode_track && s->oformat == &ff_mxf_opatom_muxer && st->codec->codec_type == AVMEDIA_TYPE_AUDIO){
+ avio_wb64(pb, mxf->body_offset / mxf->edit_unit_byte_count);
+ } else {
+ avio_wb64(pb, mxf->duration);
+ }
}
static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type)
@@ -665,7 +875,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum
// Start Time Code
mxf_write_local_tag(pb, 8, 0x1501);
- avio_wb64(pb, mxf->timecode_start);
+ avio_wb64(pb, mxf->tc.start);
// Rounded Time Code Base
mxf_write_local_tag(pb, 2, 0x1502);
@@ -673,7 +883,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum
// Drop Frame
mxf_write_local_tag(pb, 1, 0x1503);
- avio_w8(pb, mxf->timecode_drop_frame);
+ avio_w8(pb, !!(mxf->tc.flags & AV_TIMECODE_FLAG_DROPFRAME));
}
static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type)
@@ -785,8 +995,11 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke
int stored_height = (st->codec->height+15)/16*16;
int display_height;
int f1, f2;
+ unsigned desc_size = size+8+8+8+8+8+8+8+5+16+sc->interlaced*4+12+20+5;
+ if (sc->interlaced && sc->field_dominance)
+ desc_size += 5;
- mxf_write_generic_desc(s, st, key, size+8+8+8+8+8+8+5+16+sc->interlaced*4+12+20);
+ mxf_write_generic_desc(s, st, key, desc_size);
mxf_write_local_tag(pb, 4, 0x3203);
avio_wb32(pb, st->codec->width);
@@ -807,13 +1020,21 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke
mxf_write_local_tag(pb, 4, 0x3208);
avio_wb32(pb, display_height>>sc->interlaced);
+ // presentation Y offset
+ mxf_write_local_tag(pb, 4, 0x320B);
+ avio_wb32(pb, (st->codec->height - display_height)>>sc->interlaced);
+
// component depth
mxf_write_local_tag(pb, 4, 0x3301);
- avio_wb32(pb, 8);
+ avio_wb32(pb, sc->component_depth);
// horizontal subsampling
mxf_write_local_tag(pb, 4, 0x3302);
- avio_wb32(pb, 2);
+ avio_wb32(pb, sc->h_chroma_sub_sample);
+
+ // color siting
+ mxf_write_local_tag(pb, 1, 0x3303);
+ avio_w8(pb, sc->color_siting);
// frame layout
mxf_write_local_tag(pb, 1, 0x320C);
@@ -821,9 +1042,9 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke
// video line map
switch (st->codec->height) {
- case 576: f1 = 23; f2 = 336; break;
+ case 576: f1 = 23; f2 = st->codec->codec_id == AV_CODEC_ID_DVVIDEO ? 335 : 336; break;
case 608: f1 = 7; f2 = 320; break;
- case 480: f1 = 20; f2 = 283; break;
+ case 480: f1 = 20; f2 = st->codec->codec_id == AV_CODEC_ID_DVVIDEO ? 285 : 283; break;
case 512: f1 = 7; f2 = 270; break;
case 720: f1 = 26; f2 = 0; break; // progressive
case 1080: f1 = 21; f2 = 584; break;
@@ -848,6 +1069,12 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke
mxf_write_local_tag(pb, 16, 0x3201);
avio_write(pb, *sc->codec_ul, 16);
+
+ if (sc->interlaced && sc->field_dominance) {
+ mxf_write_local_tag(pb, 1, 0x3212);
+ avio_w8(pb, sc->field_dominance);
+ }
+
}
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
@@ -858,26 +1085,42 @@ static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st)
{
AVIOContext *pb = s->pb;
+ MXFStreamContext *sc = st->priv_data;
int profile_and_level = (st->codec->profile<<4) | st->codec->level;
- mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5);
+ if (st->codec->codec_id != AV_CODEC_ID_H264) {
+ mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5);
- // bit rate
- mxf_write_local_tag(pb, 4, 0x8000);
- avio_wb32(pb, st->codec->bit_rate);
+ // bit rate
+ mxf_write_local_tag(pb, 4, 0x8000);
+ avio_wb32(pb, sc->video_bit_rate);
- // profile and level
- mxf_write_local_tag(pb, 1, 0x8007);
- if (!st->codec->profile)
- profile_and_level |= 0x80; // escape bit
- avio_w8(pb, profile_and_level);
+ // profile and level
+ mxf_write_local_tag(pb, 1, 0x8007);
+ if (!st->codec->profile)
+ profile_and_level |= 0x80; // escape bit
+ avio_w8(pb, profile_and_level);
+ } else {
+ mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 0);
+ }
}
static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size)
{
AVIOContext *pb = s->pb;
+ MXFContext *mxf = s->priv_data;
+ int show_warnings = !mxf->footer_partition_offset;
+ int duration_size = 0;
+
+ if (s->oformat == &ff_mxf_opatom_muxer)
+ duration_size = 12;
- mxf_write_generic_desc(s, st, key, size+5+12+8+8);
+ mxf_write_generic_desc(s, st, key, size+duration_size+5+12+8+8);
+
+ if (duration_size > 0){
+ mxf_write_local_tag(pb, 8, 0x3002);
+ avio_wb64(pb, mxf->body_offset / mxf->edit_unit_byte_count);
+ }
// audio locked
mxf_write_local_tag(pb, 1, 0x3D02);
@@ -889,7 +1132,21 @@ static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, con
avio_wb32(pb, 1);
mxf_write_local_tag(pb, 4, 0x3D07);
- avio_wb32(pb, st->codec->channels);
+ if (mxf->channel_count == -1) {
+ if (show_warnings && (s->oformat == &ff_mxf_d10_muxer) && (st->codec->channels != 4) && (st->codec->channels != 8))
+ av_log(s, AV_LOG_WARNING, "the number of audio channels shall be 4 or 8 : the output will not comply to MXF D-10 specs, use -d10_channelcount to fix this\n");
+ avio_wb32(pb, st->codec->channels);
+ } else if (s->oformat == &ff_mxf_d10_muxer) {
+ if (show_warnings && (mxf->channel_count < st->codec->channels))
+ av_log(s, AV_LOG_WARNING, "d10_channelcount < actual number of audio channels : some channels will be discarded\n");
+ if (show_warnings && (mxf->channel_count != 4) && (mxf->channel_count != 8))
+ av_log(s, AV_LOG_WARNING, "d10_channelcount shall be set to 4 or 8 : the output will not comply to MXF D-10 specs\n");
+ avio_wb32(pb, mxf->channel_count);
+ } else {
+ if (show_warnings && mxf->channel_count != -1 && s->oformat != &ff_mxf_opatom_muxer)
+ av_log(s, AV_LOG_ERROR, "-d10_channelcount requires MXF D-10 and will be ignored\n");
+ avio_wb32(pb, st->codec->channels);
+ }
mxf_write_local_tag(pb, 4, 0x3D01);
avio_wb32(pb, av_get_bits_per_sample(st->codec->codec_id));
@@ -924,20 +1181,72 @@ static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st)
mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key, 0);
}
-static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type)
+static const uint8_t mxf_indirect_value_utf16le[] = { 0x4c,0x00,0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 };
+
+static int mxf_write_tagged_value(AVFormatContext *s, const char* name, const char* value)
+{
+ MXFContext *mxf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int name_size = mxf_utf16_local_tag_length(name);
+ int indirect_value_size = 13 + mxf_utf16_local_tag_length(value);
+
+ if (!name_size || indirect_value_size == 13)
+ return 1;
+
+ mxf_write_metadata_key(pb, 0x013f00);
+ klv_encode_ber_length(pb, 24 + name_size + indirect_value_size);
+
+ // write instance UID
+ mxf_write_local_tag(pb, 16, 0x3C0A);
+ mxf_write_uuid(pb, TaggedValue, mxf->tagged_value_count);
+
+ // write name
+ mxf_write_local_tag_utf16(pb, 0x5001, name); // Name
+
+ // write indirect value
+ mxf_write_local_tag(pb, indirect_value_size, 0x5003);
+ avio_write(pb, mxf_indirect_value_utf16le, 17);
+ avio_put_str16le(pb, value);
+
+ mxf->tagged_value_count++;
+ return 0;
+}
+
+static int mxf_write_user_comments(AVFormatContext *s, const AVDictionary *m)
+{
+ MXFContext *mxf = s->priv_data;
+ AVDictionaryEntry *t = NULL;
+ int count = 0;
+
+ while ((t = av_dict_get(m, "comment_", t, AV_DICT_IGNORE_SUFFIX))) {
+ if (mxf->tagged_value_count >= UINT16_MAX) {
+ av_log(s, AV_LOG_ERROR, "too many tagged values, ignoring remaining\n");
+ return count;
+ }
+
+ if (mxf_write_tagged_value(s, t->key + 8, t->value) == 0)
+ count++;
+ }
+ return count;
+}
+
+static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, const char *package_name)
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
int i, track_count = s->nb_streams+1;
+ int name_size = mxf_utf16_local_tag_length(package_name);
+ int user_comment_count = 0;
if (type == MaterialPackage) {
+ user_comment_count = mxf_write_user_comments(s, s->metadata);
mxf_write_metadata_key(pb, 0x013600);
PRINT_KEY(s, "Material Package key", pb->buf_ptr - 16);
- klv_encode_ber_length(pb, 92 + 16*track_count);
+ klv_encode_ber_length(pb, 104 + name_size + (16*track_count) + (16*user_comment_count));
} else {
mxf_write_metadata_key(pb, 0x013700);
PRINT_KEY(s, "Source Package key", pb->buf_ptr - 16);
- klv_encode_ber_length(pb, 112 + 16*track_count); // 20 bytes length for descriptor reference
+ klv_encode_ber_length(pb, 124 + name_size + (16*track_count)); // 20 bytes length for descriptor reference
}
// write uid
@@ -951,6 +1260,10 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type)
mxf_write_umid(s, type == SourcePackage);
PRINT_KEY(s, "package umid second part", pb->buf_ptr - 16);
+ // package name
+ if (name_size)
+ mxf_write_local_tag_utf16(pb, 0x4402, package_name);
+
// package creation date
mxf_write_local_tag(pb, 8, 0x4405);
avio_wb64(pb, mxf->timestamp);
@@ -967,6 +1280,12 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type)
for (i = 0; i < s->nb_streams; i++)
mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, i);
+ // write user comment refs
+ mxf_write_local_tag(pb, user_comment_count*16 + 8, 0x4406);
+ mxf_write_refs_count(pb, user_comment_count);
+ for (i = 0; i < user_comment_count; i++)
+ mxf_write_uuid(pb, TaggedValue, mxf->tagged_value_count - user_comment_count + i);
+
// write multiple descriptor reference
if (type == SourcePackage) {
mxf_write_local_tag(pb, 16, 0x4701);
@@ -1019,11 +1338,33 @@ static int mxf_write_essence_container_data(AVFormatContext *s)
static int mxf_write_header_metadata_sets(AVFormatContext *s)
{
+ const char *material_package_name = NULL;
+ const char *file_package_name = NULL;
+ AVDictionaryEntry *entry = NULL;
+ AVStream *st = NULL;
+ int i;
+
+ if (entry = av_dict_get(s->metadata, "material_package_name", NULL, 0))
+ material_package_name = entry->value;
+
+ if (entry = av_dict_get(s->metadata, "file_package_name", NULL, 0)) {
+ file_package_name = entry->value;
+ } else {
+ /* check if any of the streams contain a file_package_name */
+ for (i = 0; i < s->nb_streams; i++) {
+ st = s->streams[i];
+ if (entry = av_dict_get(st->metadata, "file_package_name", NULL, 0)) {
+ file_package_name = entry->value;
+ break;
+ }
+ }
+ }
+
mxf_write_preface(s);
mxf_write_identification(s);
mxf_write_content_storage(s);
- mxf_write_package(s, MaterialPackage);
- mxf_write_package(s, SourcePackage);
+ mxf_write_package(s, MaterialPackage, material_package_name);
+ mxf_write_package(s, SourcePackage, file_package_name);
mxf_write_essence_container_data(s);
return 0;
}
@@ -1177,9 +1518,8 @@ static void mxf_write_klv_fill(AVFormatContext *s)
avio_write(s->pb, klv_fill_key, 16);
pad -= 16 + 4;
klv_encode_ber4_length(s->pb, pad);
- for (; pad; pad--)
- avio_w8(s->pb, 0);
- assert(!(avio_tell(s->pb) & (KAG_SIZE-1)));
+ ffio_fill(s->pb, 0, pad);
+ av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1)));
}
}
@@ -1206,7 +1546,7 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
index_byte_count += klv_fill_size(index_byte_count);
}
- if (!memcmp(key, body_partition_key, 16)) {
+ if (key && !memcmp(key, body_partition_key, 16)) {
if ((err = av_reallocp_array(&mxf->body_partition_offset, mxf->body_partitions_count + 1,
sizeof(*mxf->body_partition_offset))) < 0) {
mxf->body_partitions_count = 0;
@@ -1216,8 +1556,12 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
}
// write klv
- avio_write(pb, key, 16);
- klv_encode_ber_length(pb, 88 + 16LL * mxf->essence_container_count);
+ if (key)
+ avio_write(pb, key, 16);
+ else
+ avio_write(pb, body_partition_key, 16);
+
+ klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count));
// write partition value
avio_wb16(pb, 1); // majorVersion
@@ -1226,9 +1570,9 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
avio_wb64(pb, partition_offset); // ThisPartition
- if (!memcmp(key, body_partition_key, 16) && mxf->body_partitions_count > 1)
+ if (key && !memcmp(key, body_partition_key, 16) && mxf->body_partitions_count > 1)
avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-2]); // PreviousPartition
- else if (!memcmp(key, footer_partition_key, 16) && mxf->body_partitions_count)
+ else if (key && !memcmp(key, footer_partition_key, 16) && mxf->body_partitions_count)
avio_wb64(pb, mxf->body_partition_offset[mxf->body_partitions_count-1]); // PreviousPartition
else
avio_wb64(pb, 0);
@@ -1244,15 +1588,18 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
avio_wb32(pb, index_byte_count ? indexsid : 0); // indexSID
// BodyOffset
- if (bodysid && mxf->edit_units_count && mxf->body_partitions_count) {
+ if (bodysid && mxf->edit_units_count && mxf->body_partitions_count && s->oformat != &ff_mxf_opatom_muxer)
avio_wb64(pb, mxf->body_offset);
- } else
+ else
avio_wb64(pb, 0);
avio_wb32(pb, bodysid); // bodySID
// operational pattern
- avio_write(pb, op1a_ul, 16);
+ if (s->oformat == &ff_mxf_opatom_muxer)
+ avio_write(pb, opatom_ul, 16);
+ else
+ avio_write(pb, op1a_ul, 16);
// essence container
mxf_write_essence_container_refs(s);
@@ -1275,11 +1622,261 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid,
avio_seek(pb, pos, SEEK_SET);
}
- avio_flush(pb);
+ if(key)
+ avio_flush(pb);
return 0;
}
+static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st,
+AVPacket *pkt)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFStreamContext *sc = st->priv_data;
+ int i, cid;
+ uint8_t* header_cid;
+ int frame_size = 0;
+
+ if (mxf->header_written)
+ return 1;
+
+ if (pkt->size < 43)
+ return -1;
+
+ header_cid = pkt->data + 0x28;
+ cid = header_cid[0] << 24 | header_cid[1] << 16 | header_cid[2] << 8 | header_cid[3];
+
+ if ((frame_size = avpriv_dnxhd_get_frame_size(cid)) < 0)
+ return -1;
+ if ((sc->interlaced = avpriv_dnxhd_get_interlaced(cid)) < 0)
+ return AVERROR_INVALIDDATA;
+
+ switch (cid) {
+ case 1235:
+ sc->index = 24;
+ sc->component_depth = 10;
+ break;
+ case 1237:
+ sc->index = 25;
+ break;
+ case 1238:
+ sc->index = 26;
+ break;
+ case 1241:
+ sc->index = 27;
+ sc->component_depth = 10;
+ break;
+ case 1242:
+ sc->index = 28;
+ break;
+ case 1243:
+ sc->index = 29;
+ break;
+ case 1250:
+ sc->index = 30;
+ sc->component_depth = 10;
+ break;
+ case 1251:
+ sc->index = 31;
+ break;
+ case 1252:
+ sc->index = 32;
+ break;
+ case 1253:
+ sc->index = 33;
+ break;
+ default:
+ return -1;
+ }
+
+ sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
+ sc->aspect_ratio = (AVRational){ 16, 9 };
+
+ if(s->oformat == &ff_mxf_opatom_muxer){
+ mxf->edit_unit_byte_count = frame_size;
+ return 1;
+ }
+
+ mxf->edit_unit_byte_count = KAG_SIZE;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ MXFStreamContext *sc = st->priv_data;
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size;
+ mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ mxf->edit_unit_byte_count += 16 + 4 + frame_size;
+ mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
+ }
+ }
+
+ return 1;
+}
+
+static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFStreamContext *sc = st->priv_data;
+ uint8_t *vs_pack, *vsc_pack;
+ int i, ul_index, frame_size, stype, pal;
+
+ if (mxf->header_written)
+ return 1;
+
+ // Check for minimal frame size
+ if (pkt->size < 120000)
+ return -1;
+
+ vs_pack = pkt->data + 80*5 + 48;
+ vsc_pack = pkt->data + 80*5 + 53;
+ stype = vs_pack[3] & 0x1f;
+ pal = (vs_pack[3] >> 5) & 0x1;
+
+ if ((vs_pack[2] & 0x07) == 0x02)
+ sc->aspect_ratio = (AVRational){ 16, 9 };
+ else
+ sc->aspect_ratio = (AVRational){ 4, 3 };
+
+ sc->interlaced = (vsc_pack[3] >> 4) & 0x01;
+ // TODO: fix dv encoder to set proper FF/FS value in VSC pack
+ // and set field dominance accordingly
+ // av_log(s, AV_LOG_DEBUG, "DV vsc pack ff/ss = %x\n", vsc_pack[2] >> 6);
+
+ switch (stype) {
+ case 0x18: // DV100 720p
+ ul_index = 6 + pal;
+ frame_size = pal ? 288000 : 240000;
+ if (sc->interlaced) {
+ av_log(s, AV_LOG_ERROR, "source marked as interlaced but codec profile is progressive\n");
+ sc->interlaced = 0;
+ }
+ break;
+ case 0x14: // DV100 1080i
+ ul_index = 4 + pal;
+ frame_size = pal ? 576000 : 480000;
+ break;
+ case 0x04: // DV50
+ ul_index = 2 + pal;
+ frame_size = pal ? 288000 : 240000;
+ break;
+ default: // DV25
+ ul_index = 0 + pal;
+ frame_size = pal ? 144000 : 120000;
+ }
+
+ sc->index = ul_index + 16;
+ sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul;
+
+ if(s->oformat == &ff_mxf_opatom_muxer) {
+ mxf->edit_unit_byte_count = frame_size;
+ return 1;
+ }
+
+ mxf->edit_unit_byte_count = KAG_SIZE;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ MXFStreamContext *sc = st->priv_data;
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size;
+ mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ mxf->edit_unit_byte_count += 16 + 4 + frame_size;
+ mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
+ }
+ }
+
+ return 1;
+}
+
+static const struct {
+ UID uid;
+ int frame_size;
+ int profile;
+ uint8_t interlaced;
+} mxf_h264_codec_uls[] = {
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 }, 0, 110, 0 }, // AVC High 10 Intra
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960, 0, 1 }, // AVC Intra 50 1080i60
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088, 0, 1 }, // AVC Intra 50 1080i50
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960, 0, 0 }, // AVC Intra 50 1080p30
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, 281088, 0, 0 }, // AVC Intra 50 1080p25
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736, 0, 0 }, // AVC Intra 50 720p60
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, 140800, 0, 0 }, // AVC Intra 50 720p50
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 }, 0, 122, 0 }, // AVC High 422 Intra
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576, 0, 1 }, // AVC Intra 100 1080i60
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832, 0, 1 }, // AVC Intra 100 1080i50
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576, 0, 0 }, // AVC Intra 100 1080p30
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, 568832, 0, 0 }, // AVC Intra 100 1080p25
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544, 0, 0 }, // AVC Intra 100 720p60
+ {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, 284672, 0, 0 }, // AVC Intra 100 720p50
+};
+
+static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
+ AVPacket *pkt, MXFIndexEntry *e)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFStreamContext *sc = st->priv_data;
+ static const int mxf_h264_num_codec_uls = sizeof(mxf_h264_codec_uls) / sizeof(mxf_h264_codec_uls[0]);
+ const uint8_t *buf = pkt->data;
+ const uint8_t *buf_end = pkt->data + pkt->size;
+ uint32_t state = -1;
+ int extra_size = 512; // support AVC Intra files without SPS/PPS header
+ int i, frame_size;
+ uint8_t uid_found;
+
+ if (pkt->size > extra_size)
+ buf_end -= pkt->size - extra_size; // no need to parse beyond SPS/PPS header
+
+ for (;;) {
+ buf = avpriv_find_start_code(buf, buf_end, &state);
+ if (buf >= buf_end)
+ break;
+ --buf;
+ switch (state & 0x1f) {
+ case NAL_SPS:
+ st->codec->profile = buf[1];
+ e->flags |= 0x40;
+ break;
+ case NAL_PPS:
+ if (e->flags & 0x40) { // sequence header present
+ e->flags |= 0x80; // random access
+ extra_size = 0;
+ buf = buf_end;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (mxf->header_written)
+ return 1;
+
+ sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD
+ sc->component_depth = 10; // AVC Intra is always 10 Bit
+ sc->interlaced = st->codec->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0;
+ if (sc->interlaced)
+ sc->field_dominance = 1; // top field first is mandatory for AVC Intra
+
+ uid_found = 0;
+ frame_size = pkt->size + extra_size;
+ for (i = 0; i < mxf_h264_num_codec_uls; i++) {
+ if (frame_size == mxf_h264_codec_uls[i].frame_size && sc->interlaced == mxf_h264_codec_uls[i].interlaced) {
+ sc->codec_ul = &mxf_h264_codec_uls[i].uid;
+ return 1;
+ } else if (st->codec->profile == mxf_h264_codec_uls[i].profile) {
+ sc->codec_ul = &mxf_h264_codec_uls[i].uid;
+ uid_found = 1;
+ }
+ }
+
+ if (!uid_found) {
+ av_log(s, AV_LOG_ERROR, "AVC Intra 50/100 supported only\n");
+ return 0;
+ }
+
+ return 1;
+}
+
static const UID mxf_mpeg2_codec_uls[] = {
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x10,0x00 }, // MP-ML I-Frame
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x11,0x00 }, // MP-ML Long GOP
@@ -1317,7 +1914,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st,
AVPacket *pkt, MXFIndexEntry *e)
{
MXFStreamContext *sc = st->priv_data;
- MXFContext *mxf = s->priv_data;
uint32_t c = -1;
int i;
@@ -1329,6 +1925,8 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st,
st->codec->level = pkt->data[i+2] >> 4;
} else if (i + 5 < pkt->size && (pkt->data[i+1] & 0xf0) == 0x80) { // pict coding ext
sc->interlaced = !(pkt->data[i+5] & 0x80); // progressive frame
+ if (sc->interlaced)
+ sc->field_dominance = 1 + !(pkt->data[i+4] & 0x80); // top field first
break;
}
} else if (c == 0x1b8) { // gop
@@ -1337,21 +1935,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st,
if (e->flags & 0x40) // sequence header present
e->flags |= 0x80; // random access
}
- if (!mxf->header_written) {
- unsigned hours = (pkt->data[i+1]>>2) & 0x1f;
- unsigned minutes = ((pkt->data[i+1] & 0x03) << 4) | (pkt->data[i+2]>>4);
- unsigned seconds = ((pkt->data[i+2] & 0x07) << 3) | (pkt->data[i+3]>>5);
- unsigned frames = ((pkt->data[i+3] & 0x1f) << 1) | (pkt->data[i+4]>>7);
- mxf->timecode_drop_frame = !!(pkt->data[i+1] & 0x80);
- mxf->timecode_start = (hours*3600 + minutes*60 + seconds) *
- mxf->timecode_base + frames;
- if (mxf->timecode_drop_frame) {
- unsigned tminutes = 60 * hours + minutes;
- mxf->timecode_start -= 2 * (tminutes - tminutes / 10);
- }
- av_log(s, AV_LOG_DEBUG, "frame %d %d:%d:%d%c%d\n", mxf->timecode_start,
- hours, minutes, seconds, mxf->timecode_drop_frame ? ';':':', frames);
- }
} else if (c == 0x1b3) { // seq
e->flags |= 0x40;
switch ((pkt->data[i+4]>>4) & 0xf) {
@@ -1408,21 +1991,39 @@ static void mxf_gen_umid(AVFormatContext *s)
AV_WB64(mxf->umid , umid);
AV_WB64(mxf->umid+8, umid>>8);
- mxf->instance_number = seed;
+ mxf->instance_number = seed & 0xFFFFFF;
+}
+
+static int mxf_init_timecode(AVFormatContext *s, AVStream *st, AVRational rate)
+{
+ MXFContext *mxf = s->priv_data;
+ AVDictionaryEntry *tcr = av_dict_get(s->metadata, "timecode", NULL, 0);
+ if (!tcr)
+ tcr = av_dict_get(st->metadata, "timecode", NULL, 0);
+
+ if (tcr)
+ return av_timecode_init_from_string(&mxf->tc, rate, tcr->value, s);
+ else
+ return av_timecode_init(&mxf->tc, rate, 0, 0, s);
}
static int mxf_write_header(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
- int i;
+ int i, ret;
uint8_t present[FF_ARRAY_ELEMS(mxf_essence_container_uls)] = {0};
- const int *samples_per_frame = NULL;
+ const MXFSamplesPerFrame *spf = NULL;
AVDictionaryEntry *t;
int64_t timestamp = 0;
if (!s->nb_streams)
return -1;
+ if (s->oformat == &ff_mxf_opatom_muxer && s->nb_streams !=1){
+ av_log(s, AV_LOG_ERROR, "there must be exactly one stream for mxf opatom\n");
+ return -1;
+ }
+
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
MXFStreamContext *sc = av_mallocz(sizeof(*sc));
@@ -1430,45 +2031,65 @@ static int mxf_write_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->priv_data = sc;
+ if (((i == 0) ^ (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)) && s->oformat != &ff_mxf_opatom_muxer) {
+ av_log(s, AV_LOG_ERROR, "there must be exactly one video stream and it must be the first one\n");
+ return -1;
+ }
+
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (i != 0) {
- av_log(s, AV_LOG_ERROR, "video stream must be first track\n");
- return -1;
- }
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(st->codec->pix_fmt);
// TODO: should be avg_frame_rate
- if (fabs(av_q2d(st->time_base) - 1/25.0) < 0.0001) {
- samples_per_frame = PAL_samples_per_frame;
- mxf->time_base = (AVRational){ 1, 25 };
- mxf->timecode_base = 25;
- } else if (fabs(av_q2d(st->time_base) - 1001/30000.0) < 0.0001) {
- samples_per_frame = NTSC_samples_per_frame;
- mxf->time_base = (AVRational){ 1001, 30000 };
- mxf->timecode_base = 30;
- } else {
- av_log(s, AV_LOG_ERROR, "unsupported video frame rate\n");
- return -1;
+ AVRational rate, tbc = st->time_base;
+ // Default component depth to 8
+ sc->component_depth = 8;
+ sc->h_chroma_sub_sample = 2;
+ sc->color_siting = 0xFF;
+
+ if (pix_desc) {
+ sc->component_depth = pix_desc->comp[0].depth_minus1 + 1;
+ sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w;
+ }
+ switch (ff_choose_chroma_location(s, st)) {
+ case AVCHROMA_LOC_TOPLEFT: sc->color_siting = 0; break;
+ case AVCHROMA_LOC_LEFT: sc->color_siting = 6; break;
+ case AVCHROMA_LOC_TOP: sc->color_siting = 1; break;
+ case AVCHROMA_LOC_CENTER: sc->color_siting = 3; break;
}
+
+ mxf->timecode_base = (tbc.den + tbc.num/2) / tbc.num;
+ spf = ff_mxf_get_samples_per_frame(s, tbc);
+ if (!spf) {
+ av_log(s, AV_LOG_ERROR, "Unsupported video frame rate %d/%d\n",
+ tbc.den, tbc.num);
+ return AVERROR(EINVAL);
+ }
+ mxf->time_base = spf->time_base;
+ rate = av_inv_q(mxf->time_base);
avpriv_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den);
+ if((ret = mxf_init_timecode(s, st, rate)) < 0)
+ return ret;
+
+ sc->video_bit_rate = st->codec->bit_rate ? st->codec->bit_rate : st->codec->rc_max_rate;
if (s->oformat == &ff_mxf_d10_muxer) {
- if (st->codec->bit_rate == 50000000)
+ if (sc->video_bit_rate == 50000000) {
if (mxf->time_base.den == 25) sc->index = 3;
else sc->index = 5;
- else if (st->codec->bit_rate == 40000000)
+ } else if (sc->video_bit_rate == 40000000) {
if (mxf->time_base.den == 25) sc->index = 7;
else sc->index = 9;
- else if (st->codec->bit_rate == 30000000)
+ } else if (sc->video_bit_rate == 30000000) {
if (mxf->time_base.den == 25) sc->index = 11;
else sc->index = 13;
- else {
+ } else {
av_log(s, AV_LOG_ERROR, "error MXF D-10 only support 30/40/50 mbit/s\n");
return -1;
}
mxf->edit_unit_byte_count = KAG_SIZE; // system element
- mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)st->codec->bit_rate *
+ mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)sc->video_bit_rate *
mxf->time_base.num / (8*mxf->time_base.den);
mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
- mxf->edit_unit_byte_count += 16 + 4 + 4 + samples_per_frame[0]*8*4;
+ mxf->edit_unit_byte_count += 16 + 4 + 4 + spf->samples_per_frame[0]*8*4;
mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count);
}
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -1487,8 +2108,35 @@ static int mxf_write_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "MXF D-10 only support 16 or 24 bits le audio\n");
}
sc->index = ((MXFStreamContext*)s->streams[0]->priv_data)->index + 1;
- } else
- mxf->slice_count = 1;
+ } else if (s->oformat == &ff_mxf_opatom_muxer) {
+ AVRational tbc = av_inv_q(mxf->audio_edit_rate);
+
+ if (st->codec->codec_id != AV_CODEC_ID_PCM_S16LE &&
+ st->codec->codec_id != AV_CODEC_ID_PCM_S24LE) {
+ av_log(s, AV_LOG_ERROR, "Only pcm_s16le and pcm_s24le audio codecs are implemented\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (st->codec->channels != 1) {
+ av_log(s, AV_LOG_ERROR, "MXF OPAtom only supports single channel audio\n");
+ return AVERROR(EINVAL);
+ }
+
+ spf = ff_mxf_get_samples_per_frame(s, tbc);
+ if (!spf){
+ av_log(s, AV_LOG_ERROR, "Unsupported timecode frame rate %d/%d\n", tbc.den, tbc.num);
+ return AVERROR(EINVAL);
+ }
+
+ mxf->time_base = st->time_base;
+ if((ret = mxf_init_timecode(s, st, av_inv_q(spf->time_base))) < 0)
+ return ret;
+
+ mxf->timecode_base = (tbc.den + tbc.num/2) / tbc.num;
+ mxf->edit_unit_byte_count = (av_get_bits_per_sample(st->codec->codec_id) * st->codec->channels) >> 3;
+ sc->index = 2;
+ } else {
+ mxf->slice_count = 1;
+ }
}
if (!sc->index) {
@@ -1511,7 +2159,7 @@ static int mxf_write_header(AVFormatContext *s)
present[sc->index]++;
}
- if (s->oformat == &ff_mxf_d10_muxer) {
+ if (s->oformat == &ff_mxf_d10_muxer || s->oformat == &ff_mxf_opatom_muxer) {
mxf->essence_container_count = 1;
}
@@ -1522,7 +2170,10 @@ static int mxf_write_header(AVFormatContext *s)
MXFStreamContext *sc = s->streams[i]->priv_data;
// update element count
sc->track_essence_element_key[13] = present[sc->index];
- sc->order = AV_RB32(sc->track_essence_element_key+12);
+ if (!memcmp(sc->track_essence_element_key, mxf_essence_container_uls[15].element_ul, 13)) // DV
+ sc->order = (0x15 << 24) | AV_RB32(sc->track_essence_element_key+13);
+ else
+ sc->order = AV_RB32(sc->track_essence_element_key+12);
}
if (t = av_dict_get(s->metadata, "creation_time", NULL, 0))
@@ -1539,10 +2190,10 @@ static int mxf_write_header(AVFormatContext *s)
return AVERROR(ENOMEM);
mxf->timecode_track->index = -1;
- if (!samples_per_frame)
- samples_per_frame = PAL_samples_per_frame;
+ if (!spf)
+ spf = ff_mxf_get_samples_per_frame(s, (AVRational){ 1, 25 });
- if (ff_audio_interleave_init(s, samples_per_frame, mxf->time_base) < 0)
+ if (ff_audio_interleave_init(s, spf->samples_per_frame, mxf->time_base) < 0)
return -1;
return 0;
@@ -1551,24 +2202,6 @@ static int mxf_write_header(AVFormatContext *s)
static const uint8_t system_metadata_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x03,0x01,0x04,0x01,0x01,0x00 };
static const uint8_t system_metadata_package_set_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x43,0x01,0x01,0x0D,0x01,0x03,0x01,0x04,0x01,0x02,0x01 };
-static uint32_t framenum_to_12m_time_code(unsigned frame, int drop, int fps)
-{
- return (0 << 31) | // color frame flag
- (drop << 30) | // drop frame flag
- ( ((frame % fps) / 10) << 28) | // tens of frames
- ( ((frame % fps) % 10) << 24) | // units of frames
- (0 << 23) | // field phase (NTSC), b0 (PAL)
- ((((frame / fps) % 60) / 10) << 20) | // tens of seconds
- ((((frame / fps) % 60) % 10) << 16) | // units of seconds
- (0 << 15) | // b0 (NTSC), b2 (PAL)
- ((((frame / (fps * 60)) % 60) / 10) << 12) | // tens of minutes
- ((((frame / (fps * 60)) % 60) % 10) << 8) | // units of minutes
- (0 << 7) | // b1
- (0 << 6) | // b2 (NTSC), field phase (PAL)
- ((((frame / (fps * 3600) % 24)) / 10) << 4) | // tens of hours
- ( (frame / (fps * 3600) % 24)) % 10; // units of hours
-}
-
static void mxf_write_system_item(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
@@ -1576,7 +2209,7 @@ static void mxf_write_system_item(AVFormatContext *s)
unsigned frame;
uint32_t time_code;
- frame = mxf->timecode_start + mxf->last_indexed_edit_unit + mxf->edit_units_count;
+ frame = mxf->last_indexed_edit_unit + mxf->edit_units_count;
// write system metadata pack
avio_write(pb, system_metadata_pack_key, 16);
@@ -1585,7 +2218,7 @@ static void mxf_write_system_item(AVFormatContext *s)
avio_w8(pb, 0x04); // content package rate
avio_w8(pb, 0x00); // content package type
avio_wb16(pb, 0x00); // channel handle
- avio_wb16(pb, frame); // continuity count
+ avio_wb16(pb, (mxf->tc.start + frame) & 0xFFFF); // continuity count, supposed to overflow
if (mxf->essence_container_count > 1)
avio_write(pb, multiple_desc_ul, 16);
else {
@@ -1597,8 +2230,7 @@ static void mxf_write_system_item(AVFormatContext *s)
avio_wb64(pb, 0); // creation date/time stamp
avio_w8(pb, 0x81); // SMPTE 12M time code
- time_code = framenum_to_12m_time_code(frame, mxf->timecode_drop_frame,
- mxf->timecode_base);
+ time_code = av_timecode_get_smpte_from_framenum(&mxf->tc, frame);
avio_wb32(pb, time_code);
avio_wb32(pb, 0); // binary group data
avio_wb64(pb, 0);
@@ -1615,7 +2247,8 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
- int packet_size = (uint64_t)st->codec->bit_rate*mxf->time_base.num /
+ MXFStreamContext *sc = st->priv_data;
+ int packet_size = (uint64_t)sc->video_bit_rate*mxf->time_base.num /
(8*mxf->time_base.den); // frame size
int pad;
@@ -1631,13 +2264,11 @@ static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacke
avio_write(s->pb, klv_fill_key, 16);
pad -= 16 + 4;
klv_encode_ber4_length(s->pb, pad);
- for (; pad; pad--)
- avio_w8(s->pb, 0);
- assert(!(avio_tell(s->pb) & (KAG_SIZE-1)));
+ ffio_fill(s->pb, 0, pad);
+ av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1)));
} else {
av_log(s, AV_LOG_WARNING, "cannot fill d-10 video packet\n");
- for (; pad > 0; pad--)
- avio_w8(s->pb, 0);
+ ffio_fill(s->pb, 0, pad);
}
}
@@ -1673,6 +2304,57 @@ static void mxf_write_d10_audio_packet(AVFormatContext *s, AVStream *st, AVPacke
}
}
+static int mxf_write_opatom_body_partition(AVFormatContext *s)
+{
+ MXFContext *mxf = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st = s->streams[0];
+ MXFStreamContext *sc = st->priv_data;
+ const uint8_t *key = NULL;
+
+ int err;
+
+ if (!mxf->header_written)
+ key = body_partition_key;
+
+ if ((err = mxf_write_partition(s, 1, 0, key, 0)) < 0)
+ return err;
+ mxf_write_klv_fill(s);
+ avio_write(pb, sc->track_essence_element_key, 16);
+ klv_encode_ber9_length(pb, mxf->body_offset);
+ return 0;
+}
+
+static int mxf_write_opatom_packet(AVFormatContext *s, AVPacket *pkt, MXFIndexEntry *ie)
+{
+ MXFContext *mxf = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ int err;
+
+ if (!mxf->header_written) {
+ if ((err = mxf_write_partition(s, 0, 0, header_open_partition_key, 1)) < 0)
+ return err;
+ mxf_write_klv_fill(s);
+
+ if ((err = mxf_write_opatom_body_partition(s)) < 0)
+ return err;
+ mxf->header_written = 1;
+ }
+
+ if (!mxf->edit_unit_byte_count) {
+ mxf->index_entries[mxf->edit_units_count].offset = mxf->body_offset;
+ mxf->index_entries[mxf->edit_units_count].flags = ie->flags;
+ mxf->index_entries[mxf->edit_units_count].temporal_ref = ie->temporal_ref;
+ }
+ mxf->edit_units_count++;
+ avio_write(pb, pkt->data, pkt->size);
+ mxf->body_offset += pkt->size;
+ avio_flush(pb);
+
+ return 0;
+}
+
static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
{
MXFContext *mxf = s->priv_data;
@@ -1696,8 +2378,26 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "could not get mpeg2 profile and level\n");
return -1;
}
+ } else if (st->codec->codec_id == AV_CODEC_ID_DNXHD) {
+ if (!mxf_parse_dnxhd_frame(s, st, pkt)) {
+ av_log(s, AV_LOG_ERROR, "could not get dnxhd profile\n");
+ return -1;
+ }
+ } else if (st->codec->codec_id == AV_CODEC_ID_DVVIDEO) {
+ if (!mxf_parse_dv_frame(s, st, pkt)) {
+ av_log(s, AV_LOG_ERROR, "could not get dv profile\n");
+ return -1;
+ }
+ } else if (st->codec->codec_id == AV_CODEC_ID_H264) {
+ if (!mxf_parse_h264_frame(s, st, pkt, &ie)) {
+ av_log(s, AV_LOG_ERROR, "could not get h264 profile\n");
+ return -1;
+ }
}
+ if (s->oformat == &ff_mxf_opatom_muxer)
+ return mxf_write_opatom_packet(s, pkt, &ie);
+
if (!mxf->header_written) {
if (mxf->edit_unit_byte_count) {
if ((err = mxf_write_partition(s, 1, 2, header_open_partition_key, 1)) < 0)
@@ -1765,7 +2465,7 @@ static void mxf_write_random_index_pack(AVFormatContext *s)
avio_write(pb, random_index_pack_key, 16);
klv_encode_ber_length(pb, 28 + 12LL*mxf->body_partitions_count);
- if (mxf->edit_unit_byte_count)
+ if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer)
avio_wb32(pb, 1); // BodySID of header partition
else
avio_wb32(pb, 0);
@@ -1786,18 +2486,25 @@ static int mxf_write_footer(AVFormatContext *s)
{
MXFContext *mxf = s->priv_data;
AVIOContext *pb = s->pb;
- int err;
+ int err = 0;
+
+ if (!mxf->header_written ||
+ (s->oformat == &ff_mxf_opatom_muxer && !mxf->body_partition_offset)) {
+ /* reason could be invalid options/not supported codec/out of memory */
+ err = AVERROR_UNKNOWN;
+ goto end;
+ }
mxf->duration = mxf->last_indexed_edit_unit + mxf->edit_units_count;
mxf_write_klv_fill(s);
mxf->footer_partition_offset = avio_tell(pb);
- if (mxf->edit_unit_byte_count) { // no need to repeat index
+ if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) { // no need to repeat index
if ((err = mxf_write_partition(s, 0, 0, footer_partition_key, 0)) < 0)
- return err;
+ goto end;
} else {
if ((err = mxf_write_partition(s, 0, 2, footer_partition_key, 0)) < 0)
- return err;
+ goto end;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
}
@@ -1806,18 +2513,26 @@ static int mxf_write_footer(AVFormatContext *s)
mxf_write_random_index_pack(s);
if (s->pb->seekable) {
+ if (s->oformat == &ff_mxf_opatom_muxer){
+ /* rewrite body partition to update lengths */
+ avio_seek(pb, mxf->body_partition_offset[0], SEEK_SET);
+ if ((err = mxf_write_opatom_body_partition(s)) < 0)
+ goto end;
+ }
+
avio_seek(pb, 0, SEEK_SET);
- if (mxf->edit_unit_byte_count) {
+ if (mxf->edit_unit_byte_count && s->oformat != &ff_mxf_opatom_muxer) {
if ((err = mxf_write_partition(s, 1, 2, header_closed_partition_key, 1)) < 0)
- return err;
+ goto end;
mxf_write_klv_fill(s);
mxf_write_index_table_segment(s);
} else {
if ((err = mxf_write_partition(s, 0, 0, header_closed_partition_key, 1)) < 0)
- return err;
+ goto end;
}
}
+end:
ff_audio_interleave_close(s);
av_freep(&mxf->index_entries);
@@ -1827,7 +2542,7 @@ static int mxf_write_footer(AVFormatContext *s)
mxf_free(s);
- return 0;
+ return err < 0 ? err : 0;
}
static int mxf_interleave_get_packet(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush)
@@ -1900,6 +2615,32 @@ static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int
mxf_interleave_get_packet, mxf_compare_timestamps);
}
+static const AVOption d10_options[] = {
+ { "d10_channelcount", "Force/set channelcount in generic sound essence descriptor",
+ offsetof(MXFContext, channel_count), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 8, AV_OPT_FLAG_ENCODING_PARAM},
+ { NULL },
+};
+
+static const AVClass mxf_d10_muxer_class = {
+ .class_name = "MXF-D10 muxer",
+ .item_name = av_default_item_name,
+ .option = d10_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static const AVOption opatom_options[] = {
+ { "mxf_audio_edit_rate", "Audio edit rate for timecode",
+ offsetof(MXFContext, audio_edit_rate), AV_OPT_TYPE_RATIONAL, {.dbl=25}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+static const AVClass mxf_opatom_muxer_class = {
+ .class_name = "MXF-OPAtom muxer",
+ .item_name = av_default_item_name,
+ .option = opatom_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
AVOutputFormat ff_mxf_muxer = {
.name = "mxf",
.long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"),
@@ -1927,4 +2668,21 @@ AVOutputFormat ff_mxf_d10_muxer = {
.write_trailer = mxf_write_footer,
.flags = AVFMT_NOTIMESTAMPS,
.interleave_packet = mxf_interleave,
+ .priv_class = &mxf_d10_muxer_class,
+};
+
+AVOutputFormat ff_mxf_opatom_muxer = {
+ .name = "mxf_opatom",
+ .long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format) Operational Pattern Atom"),
+ .mime_type = "application/mxf",
+ .extensions = "mxf",
+ .priv_data_size = sizeof(MXFContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_DNXHD,
+ .write_header = mxf_write_header,
+ .write_packet = mxf_write_packet,
+ .write_trailer = mxf_write_footer,
+ .flags = AVFMT_NOTIMESTAMPS,
+ .interleave_packet = mxf_interleave,
+ .priv_class = &mxf_opatom_muxer_class,
};
diff --git a/libavformat/mxg.c b/libavformat/mxg.c
index 1d1488c059..34977b8197 100644
--- a/libavformat/mxg.c
+++ b/libavformat/mxg.c
@@ -2,20 +2,20 @@
* MxPEG clip file demuxer
* Copyright (c) 2010 Anatoly Nenashev
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -75,7 +75,7 @@ static int mxg_read_header(AVFormatContext *s)
static uint8_t* mxg_find_startmarker(uint8_t *p, uint8_t *end)
{
for (; p < end - 3; p += 4) {
- uint32_t x = *(uint32_t*)p;
+ uint32_t x = AV_RN32(p);
if (x & (~(x+0x01010101)) & 0x80808080) {
if (p[0] == 0xff) {
@@ -102,17 +102,19 @@ static int mxg_update_cache(AVFormatContext *s, unsigned int cache_size)
MXGContext *mxg = s->priv_data;
unsigned int current_pos = mxg->buffer_ptr - mxg->buffer;
unsigned int soi_pos;
+ uint8_t *buffer;
int ret;
/* reallocate internal buffer */
if (current_pos > current_pos + cache_size)
return AVERROR(ENOMEM);
- if (mxg->soi_ptr) soi_pos = mxg->soi_ptr - mxg->buffer;
- mxg->buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size,
- current_pos + cache_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!mxg->buffer)
+ soi_pos = mxg->soi_ptr - mxg->buffer;
+ buffer = av_fast_realloc(mxg->buffer, &mxg->buffer_size,
+ current_pos + cache_size +
+ FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!buffer)
return AVERROR(ENOMEM);
+ mxg->buffer = buffer;
mxg->buffer_ptr = mxg->buffer + current_pos;
if (mxg->soi_ptr) mxg->soi_ptr = mxg->buffer + soi_pos;
@@ -134,7 +136,7 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt)
uint8_t *startmarker_ptr, *end, *search_end, marker;
MXGContext *mxg = s->priv_data;
- while (!s->pb->eof_reached && !s->pb->error){
+ while (!avio_feof(s->pb) && !s->pb->error){
if (mxg->cache_size <= OVERREAD_SIZE) {
/* update internal buffer */
ret = mxg_update_cache(s, DEFAULT_PACKET_SIZE + OVERREAD_SIZE);
diff --git a/libavformat/ncdec.c b/libavformat/ncdec.c
index 40d8dac3a7..062899f154 100644
--- a/libavformat/ncdec.c
+++ b/libavformat/ncdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Nicolas Martin (martinic at iro dot umontreal dot ca)
* Edouard Auvinet
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -67,7 +67,7 @@ static int nc_read_packet(AVFormatContext *s, AVPacket *pkt)
uint32_t state=-1;
while (state != NC_VIDEO_FLAG) {
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR(EIO);
state = (state<<8) + avio_r8(s->pb);
}
diff --git a/libavformat/network.c b/libavformat/network.c
index 6d308ebd01..57a5b418e7 100644
--- a/libavformat/network.c
+++ b/libavformat/network.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2007 The Libav Project
+ * Copyright (c) 2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,11 +22,15 @@
#include "network.h"
#include "url.h"
#include "libavcodec/internal.h"
+#include "libavutil/avutil.h"
#include "libavutil/mem.h"
+#include "libavutil/time.h"
#if HAVE_THREADS
#if HAVE_PTHREADS
#include <pthread.h>
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#else
#include "compat/w32pthreads.h"
#endif
@@ -37,7 +41,6 @@
static int openssl_init;
#if HAVE_THREADS
#include <openssl/crypto.h>
-#include "libavutil/avutil.h"
pthread_mutex_t *openssl_mutexes;
static void openssl_lock(int mode, int type, const char *file, int line)
{
@@ -63,7 +66,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
#endif
-void ff_tls_init(void)
+int ff_tls_init(void)
{
avpriv_lock_avformat();
#if CONFIG_OPENSSL
@@ -73,7 +76,11 @@ void ff_tls_init(void)
#if HAVE_THREADS
if (!CRYPTO_get_locking_callback()) {
int i;
- openssl_mutexes = av_malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
+ openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks());
+ if (!openssl_mutexes) {
+ avpriv_unlock_avformat();
+ return AVERROR(ENOMEM);
+ }
for (i = 0; i < CRYPTO_num_locks(); i++)
pthread_mutex_init(&openssl_mutexes[i], NULL);
CRYPTO_set_locking_callback(openssl_lock);
@@ -93,6 +100,8 @@ void ff_tls_init(void)
gnutls_global_init();
#endif
avpriv_unlock_avformat();
+
+ return 0;
}
void ff_tls_deinit(void)
@@ -147,6 +156,26 @@ int ff_network_wait_fd(int fd, int write)
return ret < 0 ? ff_neterrno() : p.revents & (ev | POLLERR | POLLHUP) ? 0 : AVERROR(EAGAIN);
}
+int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
+{
+ int ret;
+ int64_t wait_start = 0;
+
+ while (1) {
+ if (ff_check_interrupt(int_cb))
+ return AVERROR_EXIT;
+ ret = ff_network_wait_fd(fd, write);
+ if (ret != AVERROR(EAGAIN))
+ return ret;
+ if (timeout > 0) {
+ if (!wait_start)
+ wait_start = av_gettime_relative();
+ else if (av_gettime_relative() - wait_start > timeout)
+ return AVERROR(ETIMEDOUT);
+ }
+ }
+}
+
void ff_network_close(void)
{
#if HAVE_WINSOCK2_H
@@ -202,7 +231,7 @@ static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout,
ret = poll(p, nfds, POLLING_TIME);
if (ret != 0)
break;
- } while (timeout < 0 || runs-- > 0);
+ } while (timeout <= 0 || runs-- > 0);
if (!ret)
return AVERROR(ETIMEDOUT);
@@ -222,8 +251,10 @@ int ff_socket(int af, int type, int proto)
{
fd = socket(af, type, proto);
#if HAVE_FCNTL
- if (fd != -1)
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ if (fd != -1) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n");
+ }
#endif
}
return fd;
@@ -235,7 +266,9 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
int ret;
int reuse = 1;
struct pollfd lp = { fd, POLLIN, 0 };
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) {
+ av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_REUSEADDR) failed\n");
+ }
ret = bind(fd, addr, addrlen);
if (ret)
return ff_neterrno();
@@ -254,7 +287,9 @@ int ff_listen_bind(int fd, const struct sockaddr *addr,
closesocket(fd);
- ff_socket_nonblock(ret, 1);
+ if (ff_socket_nonblock(ret, 1) < 0)
+ av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
+
return ret;
}
@@ -266,7 +301,8 @@ int ff_listen_connect(int fd, const struct sockaddr *addr,
int ret;
socklen_t optlen;
- ff_socket_nonblock(fd, 1);
+ if (ff_socket_nonblock(fd, 1) < 0)
+ av_log(NULL, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
while ((ret = connect(fd, addr, addrlen))) {
ret = ff_neterrno();
diff --git a/libavformat/network.h b/libavformat/network.h
index 09cee58a5c..86fb656164 100644
--- a/libavformat/network.h
+++ b/libavformat/network.h
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2007 The Libav Project
+ * Copyright (c) 2007 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "config.h"
#include "libavutil/error.h"
#include "os_support.h"
+#include "avio.h"
#include "url.h"
#if HAVE_UNISTD_H
@@ -77,11 +78,23 @@ extern int ff_network_inited_globally;
int ff_network_init(void);
void ff_network_close(void);
-void ff_tls_init(void);
+int ff_tls_init(void);
void ff_tls_deinit(void);
int ff_network_wait_fd(int fd, int write);
+/**
+ * This works similarly to ff_network_wait_fd, but waits up to 'timeout' microseconds
+ * Uses ff_network_wait_fd in a loop
+ *
+ * @fd Socket descriptor
+ * @write Set 1 to wait for socket able to be read, 0 to be written
+ * @timeout Timeout interval, in microseconds. Actual precision is 100000 mcs, due to ff_network_wait_fd usage
+ * @param int_cb Interrupt callback, is checked before each ff_network_wait_fd call
+ * @return 0 if data can be read/written, AVERROR(ETIMEDOUT) if timeout expired, or negative error code
+ */
+int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb);
+
int ff_inet_aton (const char * str, struct in_addr * add);
#if !HAVE_STRUCT_SOCKADDR_STORAGE
@@ -98,6 +111,14 @@ struct sockaddr_storage {
};
#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+typedef union sockaddr_union {
+ struct sockaddr_storage storage;
+ struct sockaddr_in in;
+#if HAVE_STRUCT_SOCKADDR_IN6
+ struct sockaddr_in6 in6;
+#endif
+} sockaddr_union;
+
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
diff --git a/libavformat/nistspheredec.c b/libavformat/nistspheredec.c
new file mode 100644
index 0000000000..2f17f9eeb0
--- /dev/null
+++ b/libavformat/nistspheredec.c
@@ -0,0 +1,131 @@
+/*
+ * NIST Sphere demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+
+static int nist_probe(AVProbeData *p)
+{
+ if (AV_RL64(p->buf) == AV_RL64("NIST_1A\x0a"))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int nist_read_header(AVFormatContext *s)
+{
+ char buffer[32], coding[32] = "pcm", format[32] = "01";
+ int bps = 0, be = 0;
+ int32_t header_size = -1;
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ ff_get_line(s->pb, buffer, sizeof(buffer));
+ ff_get_line(s->pb, buffer, sizeof(buffer));
+ sscanf(buffer, "%"SCNd32, &header_size);
+ if (header_size <= 0)
+ return AVERROR_INVALIDDATA;
+
+ while (!avio_feof(s->pb)) {
+ ff_get_line(s->pb, buffer, sizeof(buffer));
+
+ if (avio_tell(s->pb) >= header_size)
+ return AVERROR_INVALIDDATA;
+
+ if (!memcmp(buffer, "end_head", 8)) {
+ if (!st->codec->bits_per_coded_sample)
+ st->codec->bits_per_coded_sample = bps << 3;
+
+ if (!av_strcasecmp(coding, "pcm")) {
+ st->codec->codec_id = ff_get_pcm_codec_id(st->codec->bits_per_coded_sample,
+ 0, be, 0xFFFF);
+ } else if (!av_strcasecmp(coding, "alaw")) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_ALAW;
+ } else if (!av_strcasecmp(coding, "ulaw") ||
+ !av_strcasecmp(coding, "mu-law")) {
+ st->codec->codec_id = AV_CODEC_ID_PCM_MULAW;
+ } else {
+ avpriv_request_sample(s, "coding %s", coding);
+ }
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ st->codec->block_align = st->codec->bits_per_coded_sample * st->codec->channels / 8;
+
+ if (avio_tell(s->pb) > header_size)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, header_size - avio_tell(s->pb));
+
+ return 0;
+ } else if (!memcmp(buffer, "channel_count", 13)) {
+ sscanf(buffer, "%*s %*s %"SCNd32, &st->codec->channels);
+ } else if (!memcmp(buffer, "sample_byte_format", 18)) {
+ sscanf(buffer, "%*s %*s %31s", format);
+
+ if (!av_strcasecmp(format, "01")) {
+ be = 0;
+ } else if (!av_strcasecmp(format, "10")) {
+ be = 1;
+ } else if (av_strcasecmp(format, "1")) {
+ avpriv_request_sample(s, "sample byte format %s", format);
+ return AVERROR_PATCHWELCOME;
+ }
+ } else if (!memcmp(buffer, "sample_coding", 13)) {
+ sscanf(buffer, "%*s %*s %31s", coding);
+ } else if (!memcmp(buffer, "sample_count", 12)) {
+ sscanf(buffer, "%*s %*s %"SCNd64, &st->duration);
+ } else if (!memcmp(buffer, "sample_n_bytes", 14)) {
+ sscanf(buffer, "%*s %*s %"SCNd32, &bps);
+ } else if (!memcmp(buffer, "sample_rate", 11)) {
+ sscanf(buffer, "%*s %*s %"SCNd32, &st->codec->sample_rate);
+ } else if (!memcmp(buffer, "sample_sig_bits", 15)) {
+ sscanf(buffer, "%*s %*s %"SCNd32, &st->codec->bits_per_coded_sample);
+ } else {
+ char key[32], value[32];
+ if (sscanf(buffer, "%31s %*s %31s", key, value) == 3) {
+ av_dict_set(&s->metadata, key, value, AV_DICT_APPEND);
+ } else {
+ av_log(s, AV_LOG_ERROR, "Failed to parse '%s' as metadata\n", buffer);
+ }
+ }
+ }
+
+ return AVERROR_EOF;
+}
+
+AVInputFormat ff_nistsphere_demuxer = {
+ .name = "nistsphere",
+ .long_name = NULL_IF_CONFIG_SMALL("NIST SPeech HEader REsources"),
+ .read_probe = nist_probe,
+ .read_header = nist_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "nist,sph",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/noproxy-test.c b/libavformat/noproxy-test.c
index e6cc421413..4524764cbf 100644
--- a/libavformat/noproxy-test.c
+++ b/libavformat/noproxy-test.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/nsvdec.c b/libavformat/nsvdec.c
index 7c8f9e3ad9..de55396508 100644
--- a/libavformat/nsvdec.c
+++ b/libavformat/nsvdec.c
@@ -1,23 +1,23 @@
/*
* NSV demuxer
- * Copyright (c) 2004 The Libav Project
+ * Copyright (c) 2004 The FFmpeg Project
*
* first version by Francois Revol <revol@free.fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,7 @@
#include "avformat.h"
#include "internal.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
/* max bytes to crawl for trying to resync
* stupid streaming servers don't start at chunk boundaries...
@@ -69,11 +70,7 @@
* so the header seems to not be mandatory. (for streaming).
*
* index slice duration check (excepts nsvtrailer.nsv):
- * for f in [^n]*.nsv; do
- * DUR="$(avconv -i "$f" 2> /dev/null | grep 'NSVf duration' | cut -d ' ' -f 4)"
- * IC="$(avconv -i "$f" 2> /dev/null | grep 'INDEX ENTRIES' | cut -d ' ' -f 2)"
- * echo "duration $DUR, slite time $(($DUR/$IC))"
- * done
+ * for f in [^n]*.nsv; do DUR="$(ffmpeg -i "$f" 2>/dev/null | grep 'NSVf duration' | cut -d ' ' -f 4)"; IC="$(ffmpeg -i "$f" 2>/dev/null | grep 'INDEX ENTRIES' | cut -d ' ' -f 2)"; echo "duration $DUR, slite time $(($DUR/$IC))"; done
*/
/*
@@ -99,8 +96,8 @@ struct NSVs_header {
uint32_t chunk_tag; /* 'NSVs' */
uint32_t v4cc; /* or 'NONE' */
uint32_t a4cc; /* or 'NONE' */
- uint16_t vwidth; /* assert(vwidth%16==0) */
- uint16_t vheight; /* assert(vheight%16==0) */
+ uint16_t vwidth; /* av_assert0(vwidth%16==0) */
+ uint16_t vheight; /* av_assert0(vheight%16==0) */
uint8_t framerate; /* value = (framerate&0x80)?frtable[frameratex0x7f]:framerate */
uint16_t unknown;
};
@@ -192,6 +189,7 @@ static const AVCodecTag nsv_codec_video_tags[] = {
{ AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
{ AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
{ AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
+ { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') },
/*
{ AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') },
{ AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') },
@@ -205,6 +203,7 @@ static const AVCodecTag nsv_codec_audio_tags[] = {
{ AV_CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') },
{ AV_CODEC_ID_AAC, MKTAG('A', 'A', 'C', ' ') },
{ AV_CODEC_ID_AAC, MKTAG('A', 'A', 'C', 'P') },
+ { AV_CODEC_ID_AAC, MKTAG('V', 'L', 'B', ' ') },
{ AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', ' ') },
{ AV_CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') },
{ AV_CODEC_ID_NONE, 0 },
@@ -233,7 +232,7 @@ static int nsv_resync(AVFormatContext *s)
//nsv->state = NSV_UNSYNC;
for (i = 0; i < NSV_MAX_RESYNC; i++) {
- if (pb->eof_reached) {
+ if (avio_feof(pb)) {
av_log(s, AV_LOG_TRACE, "NSV EOF\n");
nsv->state = NSV_UNSYNC;
return -1;
@@ -300,7 +299,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s)
table_entries_used = avio_rl32(pb);
av_log(s, AV_LOG_TRACE, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
strings_size, table_entries, table_entries_used);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return -1;
av_log(s, AV_LOG_TRACE, "NSV got header; filepos %"PRId64"\n", avio_tell(pb));
@@ -337,7 +336,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s)
}
av_free(strings);
}
- if (pb->eof_reached)
+ if (avio_feof(pb))
return -1;
av_log(s, AV_LOG_TRACE, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb));
@@ -347,7 +346,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s)
nsv->index_entries = table_entries_used;
if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t))
return -1;
- nsv->nsvs_file_offset = av_malloc((unsigned)table_entries_used * sizeof(uint32_t));
+ nsv->nsvs_file_offset = av_malloc_array((unsigned)table_entries_used, sizeof(uint32_t));
if (!nsv->nsvs_file_offset)
return AVERROR(ENOMEM);
@@ -356,7 +355,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s)
if(table_entries > table_entries_used &&
avio_rl32(pb) == MKTAG('T','O','C','2')) {
- nsv->nsvs_timestamps = av_malloc((unsigned)table_entries_used*sizeof(uint32_t));
+ nsv->nsvs_timestamps = av_malloc_array((unsigned)table_entries_used, sizeof(uint32_t));
if (!nsv->nsvs_timestamps)
return AVERROR(ENOMEM);
for(i=0;i<table_entries_used;i++) {
@@ -369,7 +368,7 @@ static int nsv_parse_NSVf_header(AVFormatContext *s)
avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */
- if (pb->eof_reached)
+ if (avio_feof(pb))
return -1;
nsv->state = NSV_HAS_READ_NSVF;
return 0;
@@ -540,6 +539,7 @@ static int nsv_read_chunk(AVFormatContext *s, int fill_header)
uint32_t vsize;
uint16_t asize;
uint16_t auxsize;
+ int ret;
av_log(s, AV_LOG_TRACE, "%s(%d)\n", __FUNCTION__, fill_header);
@@ -547,7 +547,7 @@ static int nsv_read_chunk(AVFormatContext *s, int fill_header)
return 0; //-1; /* hey! eat what you've in your plate first! */
null_chunk_retry:
- if (pb->eof_reached)
+ if (avio_feof(pb))
return -1;
for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
@@ -582,7 +582,7 @@ null_chunk_retry:
vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t); /* that's becoming braindead */
}
- if (pb->eof_reached)
+ if (avio_feof(pb))
return -1;
if (!vsize && !asize) {
nsv->state = NSV_UNSYNC;
@@ -598,7 +598,8 @@ null_chunk_retry:
if (vsize && st[NSV_ST_VIDEO]) {
nst = st[NSV_ST_VIDEO]->priv_data;
pkt = &nsv->ahead[NSV_ST_VIDEO];
- av_get_packet(pb, pkt, vsize);
+ if ((ret = av_get_packet(pb, pkt, vsize)) < 0)
+ return ret;
pkt->stream_index = st[NSV_ST_VIDEO]->index;//NSV_ST_VIDEO;
pkt->dts = nst->frame_offset;
pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0; /* keyframe only likely on a sync frame */
@@ -639,7 +640,8 @@ null_chunk_retry:
av_log(s, AV_LOG_TRACE, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
}
}
- av_get_packet(pb, pkt, asize);
+ if ((ret = av_get_packet(pb, pkt, asize)) < 0)
+ return ret;
pkt->stream_index = st[NSV_ST_AUDIO]->index;//NSV_ST_AUDIO;
pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0; /* keyframe only likely on a sync frame */
if( nsv->state == NSV_HAS_READ_NSVS && st[NSV_ST_VIDEO] ) {
@@ -719,11 +721,8 @@ static int nsv_read_close(AVFormatContext *s)
static int nsv_probe(AVProbeData *p)
{
- int i;
- int score;
- int vsize, asize, auxcount;
- score = 0;
- av_log(NULL, AV_LOG_TRACE, "nsv_probe(), buf_size %d\n", p->buf_size);
+ int i, score = 0;
+
/* check file header */
/* streamed files might not have any header */
if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
@@ -734,19 +733,14 @@ static int nsv_probe(AVProbeData *p)
/* seems the servers don't bother starting clean chunks... */
/* sometimes even the first header is at 9KB or something :^) */
for (i = 1; i < p->buf_size - 3; i++) {
- if (p->buf[i+0] == 'N' && p->buf[i+1] == 'S' &&
- p->buf[i+2] == 'V' && p->buf[i+3] == 's') {
- score = AVPROBE_SCORE_MAX/5;
+ if (AV_RL32(p->buf + i) == AV_RL32("NSVs")) {
/* Get the chunk size and check if at the end we are getting 0xBEEF */
- auxcount = p->buf[i+19];
- vsize = p->buf[i+20] | p->buf[i+21] << 8;
- asize = p->buf[i+22] | p->buf[i+23] << 8;
- vsize = (vsize << 4) | (auxcount >> 4);
- if ((asize + vsize + i + 23) < p->buf_size - 2) {
- if (p->buf[i+23+asize+vsize+1] == 0xEF &&
- p->buf[i+23+asize+vsize+2] == 0xBE)
- return AVPROBE_SCORE_MAX-20;
- }
+ int vsize = AV_RL24(p->buf+i+19) >> 4;
+ int asize = AV_RL16(p->buf+i+22);
+ int offset = i + 23 + asize + vsize + 1;
+ if (offset <= p->buf_size - 2 && AV_RL16(p->buf + offset) == 0xBEEF)
+ return 4*AVPROBE_SCORE_MAX/5;
+ score = AVPROBE_SCORE_MAX/5;
}
}
/* so we'll have more luck on extension... */
diff --git a/libavformat/nullenc.c b/libavformat/nullenc.c
index 829f2a841e..7c08c396e8 100644
--- a/libavformat/nullenc.c
+++ b/libavformat/nullenc.c
@@ -2,20 +2,20 @@
* RAW null muxer
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,5 +32,5 @@ AVOutputFormat ff_null_muxer = {
.audio_codec = AV_NE(AV_CODEC_ID_PCM_S16BE, AV_CODEC_ID_PCM_S16LE),
.video_codec = AV_CODEC_ID_RAWVIDEO,
.write_packet = null_write_packet,
- .flags = AVFMT_NOFILE | AVFMT_NOTIMESTAMPS | AVFMT_RAWPICTURE,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_NOFILE | AVFMT_NOTIMESTAMPS | AVFMT_RAWPICTURE,
};
diff --git a/libavformat/nut.c b/libavformat/nut.c
index 43ae8a0f0e..c6fdb0bff8 100644
--- a/libavformat/nut.c
+++ b/libavformat/nut.c
@@ -2,20 +2,20 @@
* nut
* Copyright (c) 2004-2007 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,9 +27,10 @@
const AVCodecTag ff_nut_subtitle_tags[] = {
{ AV_CODEC_ID_TEXT, MKTAG('U', 'T', 'F', '8') },
- { AV_CODEC_ID_SSA, MKTAG('S', 'S', 'A', 0) },
+ { AV_CODEC_ID_SSA, MKTAG('S', 'S', 'A', 0 ) },
{ AV_CODEC_ID_DVD_SUBTITLE, MKTAG('D', 'V', 'D', 'S') },
{ AV_CODEC_ID_DVB_SUBTITLE, MKTAG('D', 'V', 'B', 'S') },
+ { AV_CODEC_ID_DVB_TELETEXT, MKTAG('D', 'V', 'B', 'T') },
{ AV_CODEC_ID_NONE, 0 }
};
@@ -39,25 +40,31 @@ const AVCodecTag ff_nut_data_tags[] = {
};
const AVCodecTag ff_nut_video_tags[] = {
+ { AV_CODEC_ID_GIF, MKTAG('G', 'I', 'F', 0 ) },
+ { AV_CODEC_ID_XFACE, MKTAG('X', 'F', 'A', 'C') },
{ AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 16) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(15, 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(15, 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 12) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 12) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(15 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 'R', 'G', 'B') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 'A') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 0 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 'A') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 0 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'B', 'G', 'R') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('A', 'R', 'G', 'B') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 24) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 24) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG( 0 , 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 24 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 24 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('4', '1', '1', 'P') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('4', '2', '2', 'P') },
@@ -67,36 +74,50 @@ const AVCodecTag ff_nut_video_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('4', '4', '4', 'P') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('B', '1', 'W', '0') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('B', '0', 'W', '1') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 8) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 8) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 4) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 4) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 4 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 4 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('B', '4', 'B', 'Y') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('R', '4', 'B', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 48) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 48) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(48, 'B', 'G', 'R') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(48, 'R', 'G', 'B') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 48 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 48 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'B', 'G', 'R') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(48 , 'R', 'G', 'B') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'B', 'A', 64 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'R', 'A', 64 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'R', 'B', 'A') },
{ AV_CODEC_ID_RAWVIDEO, MKTAG(64 , 'B', 'R', 'A') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11, 10) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 11, '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10, 10) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 10, '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0, 10) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 16) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '1', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11, 16) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 11, '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10, 16) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 10, '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0, 16) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '3', 'Y') },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11, 8) },
- { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '2', 0, 8) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 10 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 10 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 10 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 12 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 14 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 14 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 14 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '1', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 11 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 11 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 10 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 10 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '3', 0 , 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 0 , '3', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 11 , 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10 , 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0 , 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '2', 0 , 8 ) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 9) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG(9, 0, '1', 'Y') },
@@ -125,40 +146,77 @@ const AVCodecTag ff_nut_video_tags[] = {
{ AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 16) },
{ AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '4', 'Y') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 8) },
+
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 9) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG( 9, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 10) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 12) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 14) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(14, 0, '3', 'G') },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 16) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '3', 'G') },
+
+ { AV_CODEC_ID_RAWVIDEO, MKTAG('X', 'Y', 'Z' , 36 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(36 , 'Z' , 'Y', 'X') },
+
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'B', 'G', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'B', 'G', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'G', 'B', 0xBA) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'R', 'G', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'R', 'G', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16 , 'G', 'R', 0xBA) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'B', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'B', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 'B', 'G', 0xBA) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'R', 8 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(0xBA, 'G', 'R', 16 ) },
+ { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 'R', 'G', 0xBA) },
+
{ AV_CODEC_ID_NONE, 0 }
};
-const AVCodecTag ff_nut_audio_tags[] = {
+const AVCodecTag ff_nut_audio_extra_tags[] = {
+ { AV_CODEC_ID_COMFORT_NOISE, MKTAG('3', '3', '8', '9') },
{ AV_CODEC_ID_PCM_ALAW, MKTAG('A', 'L', 'A', 'W') },
{ AV_CODEC_ID_PCM_MULAW, MKTAG('U', 'L', 'A', 'W') },
- { AV_CODEC_ID_PCM_F32BE, MKTAG(32, 'D', 'F', 'P') },
- { AV_CODEC_ID_PCM_F32LE, MKTAG('P', 'F', 'D', 32) },
- { AV_CODEC_ID_PCM_F64BE, MKTAG(64, 'D', 'F', 'P') },
- { AV_CODEC_ID_PCM_F64LE, MKTAG('P', 'F', 'D', 64) },
- { AV_CODEC_ID_PCM_S16BE, MKTAG(16, 'D', 'S', 'P') },
- { AV_CODEC_ID_PCM_S16LE, MKTAG('P', 'S', 'D', 16) },
- { AV_CODEC_ID_PCM_S24BE, MKTAG(24, 'D', 'S', 'P') },
- { AV_CODEC_ID_PCM_S24LE, MKTAG('P', 'S', 'D', 24) },
- { AV_CODEC_ID_PCM_S32BE, MKTAG(32, 'D', 'S', 'P') },
- { AV_CODEC_ID_PCM_S32LE, MKTAG('P', 'S', 'D', 32) },
- { AV_CODEC_ID_PCM_S8, MKTAG('P', 'S', 'D', 8) },
- { AV_CODEC_ID_PCM_U16BE, MKTAG(16, 'D', 'U', 'P') },
- { AV_CODEC_ID_PCM_U16LE, MKTAG('P', 'U', 'D', 16) },
- { AV_CODEC_ID_PCM_U24BE, MKTAG(24, 'D', 'U', 'P') },
- { AV_CODEC_ID_PCM_U24LE, MKTAG('P', 'U', 'D', 24) },
- { AV_CODEC_ID_PCM_U32BE, MKTAG(32, 'D', 'U', 'P') },
- { AV_CODEC_ID_PCM_U32LE, MKTAG('P', 'U', 'D', 32) },
- { AV_CODEC_ID_PCM_U8, MKTAG('P', 'U', 'D', 8) },
- { AV_CODEC_ID_PCM_S16LE_PLANAR, MKTAG('P', 'S', 'P', 16) },
- { AV_CODEC_ID_PCM_S24LE_PLANAR, MKTAG('P', 'S', 'P', 24) },
- { AV_CODEC_ID_PCM_S32LE_PLANAR, MKTAG('P', 'S', 'P', 32) },
{ AV_CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') },
- { AV_CODEC_ID_NONE, 0 }
+ { AV_CODEC_ID_WAVPACK, MKTAG('w', 'v', 'p', 'k') },
+ { AV_CODEC_ID_NONE, 0 }
+};
+
+const AVCodecTag ff_nut_audio_tags[] = {
+ { AV_CODEC_ID_PCM_F32BE, MKTAG(32 , 'D', 'F', 'P') },
+ { AV_CODEC_ID_PCM_F32LE, MKTAG('P', 'F', 'D', 32 ) },
+ { AV_CODEC_ID_PCM_F64BE, MKTAG(64 , 'D', 'F', 'P') },
+ { AV_CODEC_ID_PCM_F64LE, MKTAG('P', 'F', 'D', 64 ) },
+ { AV_CODEC_ID_PCM_S16BE, MKTAG(16 , 'D', 'S', 'P') },
+ { AV_CODEC_ID_PCM_S16LE, MKTAG('P', 'S', 'D', 16 ) },
+ { AV_CODEC_ID_PCM_S24BE, MKTAG(24 , 'D', 'S', 'P') },
+ { AV_CODEC_ID_PCM_S24LE, MKTAG('P', 'S', 'D', 24 ) },
+ { AV_CODEC_ID_PCM_S32BE, MKTAG(32 , 'D', 'S', 'P') },
+ { AV_CODEC_ID_PCM_S32LE, MKTAG('P', 'S', 'D', 32 ) },
+ { AV_CODEC_ID_PCM_S8, MKTAG('P', 'S', 'D', 8 ) },
+ { AV_CODEC_ID_PCM_U16BE, MKTAG(16 , 'D', 'U', 'P') },
+ { AV_CODEC_ID_PCM_U16LE, MKTAG('P', 'U', 'D', 16 ) },
+ { AV_CODEC_ID_PCM_U24BE, MKTAG(24 , 'D', 'U', 'P') },
+ { AV_CODEC_ID_PCM_U24LE, MKTAG('P', 'U', 'D', 24 ) },
+ { AV_CODEC_ID_PCM_U32BE, MKTAG(32 , 'D', 'U', 'P') },
+ { AV_CODEC_ID_PCM_U32LE, MKTAG('P', 'U', 'D', 32 ) },
+ { AV_CODEC_ID_PCM_U8, MKTAG('P', 'U', 'D', 8 ) },
+ { AV_CODEC_ID_PCM_S8_PLANAR, MKTAG('P', 'S', 'P', 8 ) },
+ { AV_CODEC_ID_PCM_S16BE_PLANAR, MKTAG(16 , 'P', 'S', 'P') },
+ { AV_CODEC_ID_PCM_S16LE_PLANAR, MKTAG('P', 'S', 'P', 16 ) },
+ { AV_CODEC_ID_PCM_S24LE_PLANAR, MKTAG('P', 'S', 'P', 24 ) },
+ { AV_CODEC_ID_PCM_S32LE_PLANAR, MKTAG('P', 'S', 'P', 32 ) },
+ { AV_CODEC_ID_NONE, 0 }
};
const AVCodecTag * const ff_nut_codec_tags[] = {
ff_nut_video_tags, ff_nut_audio_tags, ff_nut_subtitle_tags,
- ff_codec_bmp_tags, ff_codec_wav_tags, ff_nut_data_tags, 0
+ ff_codec_bmp_tags, ff_codec_wav_tags, ff_nut_audio_extra_tags, ff_nut_data_tags, 0
};
void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val)
@@ -174,7 +232,7 @@ void ff_nut_reset_ts(NUTContext *nut, AVRational time_base, int64_t val)
int64_t ff_lsb2full(StreamContext *stream, int64_t lsb)
{
- int64_t mask = (1 << stream->msb_pts_shift) - 1;
+ int64_t mask = (1ULL << stream->msb_pts_shift) - 1;
int64_t delta = stream->last_pts - mask / 2;
return ((lsb - delta) & mask) + delta;
}
@@ -200,6 +258,8 @@ int ff_nut_add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts)
return AVERROR(ENOMEM);
}
+ nut->sp_count++;
+
sp->pos = pos;
sp->back_ptr = back_ptr;
sp->ts = ts;
diff --git a/libavformat/nut.h b/libavformat/nut.h
index 16f3c123a1..0c678a51b9 100644
--- a/libavformat/nut.h
+++ b/libavformat/nut.h
@@ -2,20 +2,20 @@
* "NUT" Container Format (de)muxer
* Copyright (c) 2006 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,6 +48,7 @@ typedef enum{
FLAG_SIZE_MSB = 32, ///<if set, data_size_msb is at frame header, otherwise data_size_msb is 0
FLAG_CHECKSUM = 64, ///<if set, the frame header contains a checksum
FLAG_RESERVED = 128, ///<if set, reserved_count is coded in the frame header
+ FLAG_SM_DATA = 256, ///<if set, side / meta data is stored in the frame header.
FLAG_HEADER_IDX =1024, ///<If set, header_idx is coded in the frame header.
FLAG_MATCH_TIME =2048, ///<If set, match_time_delta is coded in the frame header
FLAG_CODED =4096, ///<if set, coded_flags are stored in the frame header
@@ -80,6 +81,7 @@ typedef struct StreamContext {
int msb_pts_shift;
int max_pts_distance;
int decode_delay; //FIXME duplicate of has_b_frames
+ int64_t *keyframe_pts;
} StreamContext;
typedef struct ChapterContext {
@@ -100,18 +102,25 @@ typedef struct NUTContext {
unsigned int max_distance;
unsigned int time_base_count;
int64_t last_syncpoint_pos;
+ int64_t last_resync_pos;
int header_count;
AVRational *time_base;
struct AVTreeNode *syncpoints;
+ int sp_count;
+ int write_index;
+ int64_t max_pts;
+ AVRational *max_pts_tb;
#define NUT_BROADCAST 1 // use extended syncpoints
#define NUT_PIPE 2 // do not write syncpoints
int flags;
int version; // version currently in use
+ int minor_version;
} NUTContext;
extern const AVCodecTag ff_nut_subtitle_tags[];
extern const AVCodecTag ff_nut_video_tags[];
extern const AVCodecTag ff_nut_audio_tags[];
+extern const AVCodecTag ff_nut_audio_extra_tags[];
extern const AVCodecTag ff_nut_data_tags[];
extern const AVCodecTag * const ff_nut_codec_tags[];
diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c
index 47f6e318b3..13fb39924d 100644
--- a/libavformat/nutdec.c
+++ b/libavformat/nutdec.c
@@ -3,37 +3,41 @@
* Copyright (c) 2004-2006 Michael Niedermayer
* Copyright (c) 2003 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "libavutil/avassert.h"
#include "libavutil/bswap.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/tree.h"
+#include "libavcodec/bytestream.h"
#include "avio_internal.h"
+#include "isom.h"
#include "nut.h"
#include "riff.h"
-#undef NDEBUG
-#include <assert.h>
-
#define NUT_MAX_STREAMS 256 /* arbitrary sanity check value */
+static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index,
+ int64_t *pos_arg, int64_t pos_limit);
+
static int get_str(AVIOContext *bc, char *string, unsigned int maxlen)
{
unsigned int len = ffio_read_varlen(bc);
@@ -43,11 +47,15 @@ static int get_str(AVIOContext *bc, char *string, unsigned int maxlen)
while (len > maxlen) {
avio_r8(bc);
len--;
+ if (bc->eof_reached)
+ len = maxlen;
}
if (maxlen)
string[FFMIN(len, maxlen - 1)] = 0;
+ if (bc->eof_reached)
+ return AVERROR_EOF;
if (maxlen == len)
return -1;
else
@@ -72,8 +80,10 @@ static uint64_t get_fourcc(AVIOContext *bc)
return avio_rl16(bc);
else if (len == 4)
return avio_rl32(bc);
- else
+ else {
+ av_log(NULL, AV_LOG_ERROR, "Unsupported fourcc length %d\n", len);
return -1;
+ }
}
#ifdef TRACE
@@ -97,8 +107,18 @@ static inline int64_t get_s_trace(AVIOContext *bc, const char *file,
return v;
}
+static inline uint64_t get_4cc_trace(AVIOContext *bc, char *file,
+ char *func, int line)
+{
+ uint64_t v = get_fourcc(bc);
+
+ av_log(NULL, AV_LOG_DEBUG, "get_fourcc %5"PRId64" / %"PRIX64" in %s %s:%d\n",
+ v, v, file, func, line);
+ return v;
+}
#define ffio_read_varlen(bc) get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#define get_s(bc) get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#define get_fourcc(bc) get_4cc_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
#endif
static int get_packetheader(NUTContext *nut, AVIOContext *bc,
@@ -130,7 +150,7 @@ static uint64_t find_any_startcode(AVIOContext *bc, int64_t pos)
/* Note, this may fail if the stream is not seekable, but that should
* not matter, as in this case we simply start where we currently are */
avio_seek(bc, pos, SEEK_SET);
- while (!bc->eof_reached) {
+ while (!avio_feof(bc)) {
state = (state << 8) | avio_r8(bc);
if ((state >> 56) != 'N')
continue;
@@ -168,11 +188,11 @@ static int64_t find_startcode(AVIOContext *bc, uint64_t code, int64_t pos)
static int nut_probe(AVProbeData *p)
{
int i;
- uint64_t code = 0;
- for (i = 0; i < p->buf_size; i++) {
- code = (code << 8) | p->buf[i];
- if (code == MAIN_STARTCODE)
+ for (i = 0; i < p->buf_size-8; i++) {
+ if (AV_RB32(p->buf+i) != MAIN_STARTCODE>>32)
+ continue;
+ if (AV_RB32(p->buf+i+4) == (MAIN_STARTCODE & 0xFFFFFFFF))
return AVPROBE_SCORE_MAX;
}
return 0;
@@ -183,7 +203,8 @@ static int nut_probe(AVProbeData *p)
tmp = ffio_read_varlen(bc); \
if (!(check)) { \
av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp); \
- return AVERROR_INVALIDDATA; \
+ ret = AVERROR_INVALIDDATA; \
+ goto fail; \
} \
dst = tmp; \
} while (0)
@@ -195,8 +216,11 @@ static int skip_reserved(AVIOContext *bc, int64_t pos)
avio_seek(bc, pos, SEEK_CUR);
return AVERROR_INVALIDDATA;
} else {
- while (pos--)
+ while (pos--) {
+ if (bc->eof_reached)
+ return AVERROR_INVALIDDATA;
avio_r8(bc);
+ }
return 0;
}
}
@@ -207,7 +231,7 @@ static int decode_main_header(NUTContext *nut)
AVIOContext *bc = s->pb;
uint64_t tmp, end;
unsigned int stream_count;
- int i, j, count;
+ int i, j, count, ret;
int tmp_stream, tmp_mul, tmp_pts, tmp_size, tmp_res, tmp_head_idx;
end = get_packetheader(nut, bc, 1, MAIN_STARTCODE);
@@ -220,6 +244,8 @@ static int decode_main_header(NUTContext *nut)
nut->version);
return AVERROR(ENOSYS);
}
+ if (nut->version > 3)
+ nut->minor_version = ffio_read_varlen(bc);
GET_V(stream_count, tmp > 0 && tmp <= NUT_MAX_STREAMS);
@@ -230,7 +256,7 @@ static int decode_main_header(NUTContext *nut)
}
GET_V(nut->time_base_count, tmp > 0 && tmp < INT_MAX / sizeof(AVRational));
- nut->time_base = av_malloc(nut->time_base_count * sizeof(AVRational));
+ nut->time_base = av_malloc_array(nut->time_base_count, sizeof(AVRational));
if (!nut->time_base)
return AVERROR(ENOMEM);
@@ -239,7 +265,8 @@ static int decode_main_header(NUTContext *nut)
GET_V(nut->time_base[i].den, tmp > 0 && tmp < (1ULL << 31));
if (av_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1) {
av_log(s, AV_LOG_ERROR, "time base invalid\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
}
tmp_pts = 0;
@@ -273,16 +300,24 @@ static int decode_main_header(NUTContext *nut)
if (tmp_fields > 7)
tmp_head_idx = ffio_read_varlen(bc);
- while (tmp_fields-- > 8)
+ while (tmp_fields-- > 8) {
+ if (bc->eof_reached) {
+ av_log(s, AV_LOG_ERROR, "reached EOF while decoding main header\n");
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
ffio_read_varlen(bc);
+ }
- if (count == 0 || i + count > 256) {
+ if (count <= 0 || count > 256 - (i <= 'N') - i) {
av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
if (tmp_stream >= stream_count) {
av_log(s, AV_LOG_ERROR, "illegal stream number\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
for (j = 0; j < count; j++, i++) {
@@ -300,7 +335,7 @@ static int decode_main_header(NUTContext *nut)
nut->frame_code[i].header_idx = tmp_head_idx;
}
}
- assert(nut->frame_code['N'].flags == FLAG_INVALID);
+ av_assert0(nut->frame_code['N'].flags == FLAG_INVALID);
if (end > avio_tell(bc) + 4) {
int rem = 1024;
@@ -312,34 +347,47 @@ static int decode_main_header(NUTContext *nut)
rem -= nut->header_len[i];
if (rem < 0) {
av_log(s, AV_LOG_ERROR, "invalid elision header\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
hdr = av_malloc(nut->header_len[i]);
- if (!hdr)
- return AVERROR(ENOMEM);
+ if (!hdr) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
avio_read(bc, hdr, nut->header_len[i]);
nut->header[i] = hdr;
}
- assert(nut->header_len[0] == 0);
+ av_assert0(nut->header_len[0] == 0);
}
// flags had been effectively introduced in version 4
- if (nut->version > NUT_STABLE_VERSION) {
+ if (nut->version > 3 && end > avio_tell(bc) + 4) {
nut->flags = ffio_read_varlen(bc);
}
if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
- nut->stream = av_mallocz(sizeof(StreamContext) * stream_count);
- if (!nut->stream)
- return AVERROR(ENOMEM);
+ nut->stream = av_calloc(stream_count, sizeof(StreamContext));
+ if (!nut->stream) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
for (i = 0; i < stream_count; i++)
avformat_new_stream(s, NULL);
return 0;
+fail:
+ av_freep(&nut->time_base);
+ for (i = 1; i < nut->header_count; i++) {
+ av_freep(&nut->header[i]);
+ }
+ nut->header_count = 0;
+ return ret;
}
static int decode_stream_header(NUTContext *nut)
@@ -347,9 +395,9 @@ static int decode_stream_header(NUTContext *nut)
AVFormatContext *s = nut->avf;
AVIOContext *bc = s->pb;
StreamContext *stc;
- int class, stream_id;
+ int class, stream_id, ret;
uint64_t tmp, end;
- AVStream *st;
+ AVStream *st = NULL;
end = get_packetheader(nut, bc, 1, STREAM_STARTCODE);
end += avio_tell(bc);
@@ -369,6 +417,7 @@ static int decode_stream_header(NUTContext *nut)
st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) {
ff_nut_video_tags,
ff_codec_bmp_tags,
+ ff_codec_movvideo_tags,
0
},
tmp);
@@ -378,6 +427,7 @@ static int decode_stream_header(NUTContext *nut)
st->codec->codec_id = av_codec_get_id((const AVCodecTag * const []) {
ff_nut_audio_tags,
ff_codec_wav_tags,
+ ff_nut_audio_extra_tags,
0
},
tmp);
@@ -403,15 +453,13 @@ static int decode_stream_header(NUTContext *nut)
GET_V(stc->msb_pts_shift, tmp < 16);
stc->max_pts_distance = ffio_read_varlen(bc);
GET_V(stc->decode_delay, tmp < 1000); // sanity limit, raise this if Moore's law is true
+ st->codec->has_b_frames = stc->decode_delay;
ffio_read_varlen(bc); // stream flags
GET_V(st->codec->extradata_size, tmp < (1 << 30));
if (st->codec->extradata_size) {
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, bc, st->codec->extradata_size) < 0)
return AVERROR(ENOMEM);
- avio_read(bc, st->codec->extradata, st->codec->extradata_size);
}
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
@@ -422,7 +470,8 @@ static int decode_stream_header(NUTContext *nut)
if ((!st->sample_aspect_ratio.num) != (!st->sample_aspect_ratio.den)) {
av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n",
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
ffio_read_varlen(bc); /* csp type */
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -433,12 +482,19 @@ static int decode_stream_header(NUTContext *nut)
if (skip_reserved(bc, end) || ffio_get_checksum(bc)) {
av_log(s, AV_LOG_ERROR,
"stream header %d checksum mismatch\n", stream_id);
- return AVERROR_INVALIDDATA;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
}
stc->time_base = &nut->time_base[stc->time_base_id];
avpriv_set_pts_info(s->streams[stream_id], 63, stc->time_base->num,
stc->time_base->den);
return 0;
+fail:
+ if (st && st->codec) {
+ av_freep(&st->codec->extradata);
+ st->codec->extradata_size = 0;
+ }
+ return ret;
}
static void set_disposition_bits(AVFormatContext *avf, char *value,
@@ -462,7 +518,7 @@ static int decode_info_header(NUTContext *nut)
AVIOContext *bc = s->pb;
uint64_t tmp, chapter_start, chapter_len;
unsigned int stream_id_plus1, count;
- int chapter_id, i;
+ int chapter_id, i, ret = 0;
int64_t value, end;
char name[256], str_value[1024], type_str[256];
const char *type;
@@ -504,15 +560,25 @@ static int decode_info_header(NUTContext *nut)
}
for (i = 0; i < count; i++) {
- get_str(bc, name, sizeof(name));
+ ret = get_str(bc, name, sizeof(name));
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "get_str failed while decoding info header\n");
+ return ret;
+ }
value = get_s(bc);
+ str_value[0] = 0;
+
if (value == -1) {
type = "UTF-8";
- get_str(bc, str_value, sizeof(str_value));
+ ret = get_str(bc, str_value, sizeof(str_value));
} else if (value == -2) {
- get_str(bc, type_str, sizeof(type_str));
+ ret = get_str(bc, type_str, sizeof(type_str));
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "get_str failed while decoding info header\n");
+ return ret;
+ }
type = type_str;
- get_str(bc, str_value, sizeof(str_value));
+ ret = get_str(bc, str_value, sizeof(str_value));
} else if (value == -3) {
type = "s";
value = get_s(bc);
@@ -526,6 +592,11 @@ static int decode_info_header(NUTContext *nut)
type = "v";
}
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "get_str failed while decoding info header\n");
+ return ret;
+ }
+
if (stream_id_plus1 > s->nb_streams) {
av_log(s, AV_LOG_ERROR, "invalid stream id for info packet\n");
continue;
@@ -536,6 +607,15 @@ static int decode_info_header(NUTContext *nut)
set_disposition_bits(s, str_value, stream_id_plus1 - 1);
continue;
}
+
+ if (stream_id_plus1 && !strcmp(name, "r_frame_rate")) {
+ sscanf(str_value, "%d/%d", &st->r_frame_rate.num, &st->r_frame_rate.den);
+ if (st->r_frame_rate.num >= 1000LL*st->r_frame_rate.den ||
+ st->r_frame_rate.num < 0 || st->r_frame_rate.num < 0)
+ st->r_frame_rate.num = st->r_frame_rate.den = 0;
+ continue;
+ }
+
if (metadata && av_strcasecmp(name, "Uses") &&
av_strcasecmp(name, "Depends") && av_strcasecmp(name, "Replaces")) {
if (event_flags)
@@ -549,14 +629,16 @@ static int decode_info_header(NUTContext *nut)
av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n");
return AVERROR_INVALIDDATA;
}
- return 0;
+fail:
+ return FFMIN(ret, 0);
}
static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
{
AVFormatContext *s = nut->avf;
AVIOContext *bc = s->pb;
- int64_t end, tmp;
+ int64_t end;
+ uint64_t tmp;
int ret;
nut->last_syncpoint_pos = avio_tell(bc) - 8;
@@ -567,7 +649,7 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
tmp = ffio_read_varlen(bc);
*back_ptr = nut->last_syncpoint_pos - 16 * ffio_read_varlen(bc);
if (*back_ptr < 0)
- return -1;
+ return AVERROR_INVALIDDATA;
ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count],
tmp / nut->time_base_count);
@@ -585,8 +667,8 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
return AVERROR_INVALIDDATA;
}
- *ts = tmp / s->nb_streams *
- av_q2d(nut->time_base[tmp % s->nb_streams]) * AV_TIME_BASE;
+ *ts = tmp / nut->time_base_count *
+ av_q2d(nut->time_base[tmp % nut->time_base_count]) * AV_TIME_BASE;
if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts)) < 0)
return ret;
@@ -594,6 +676,19 @@ static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr)
return 0;
}
+//FIXME calculate exactly, this is just a good approximation.
+static int64_t find_duration(NUTContext *nut, int64_t filesize)
+{
+ AVFormatContext *s = nut->avf;
+ int64_t duration = 0;
+
+ ff_find_last_ts(s, -1, &duration, NULL, nut_read_timestamp);
+
+ if(duration > 0)
+ s->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
+ return duration;
+}
+
static int find_and_decode_index(NUTContext *nut)
{
AVFormatContext *s = nut->avf;
@@ -601,24 +696,36 @@ static int find_and_decode_index(NUTContext *nut)
uint64_t tmp, end;
int i, j, syncpoint_count;
int64_t filesize = avio_size(bc);
- int64_t *syncpoints;
- int8_t *has_keyframe;
+ int64_t *syncpoints = NULL;
+ uint64_t max_pts;
+ int8_t *has_keyframe = NULL;
int ret = AVERROR_INVALIDDATA;
+ if(filesize <= 0)
+ return -1;
+
avio_seek(bc, filesize - 12, SEEK_SET);
avio_seek(bc, filesize - avio_rb64(bc), SEEK_SET);
if (avio_rb64(bc) != INDEX_STARTCODE) {
av_log(s, AV_LOG_ERROR, "no index at the end\n");
+
+ if(s->duration<=0)
+ s->duration = find_duration(nut, filesize);
return ret;
}
end = get_packetheader(nut, bc, 1, INDEX_STARTCODE);
end += avio_tell(bc);
- ffio_read_varlen(bc); // max_pts
+ max_pts = ffio_read_varlen(bc);
+ s->duration = av_rescale_q(max_pts / nut->time_base_count,
+ nut->time_base[max_pts % nut->time_base_count],
+ AV_TIME_BASE_Q);
+ s->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
+
GET_V(syncpoint_count, tmp < INT_MAX / 8 && tmp > 0);
- syncpoints = av_malloc(sizeof(int64_t) * syncpoint_count);
- has_keyframe = av_malloc(sizeof(int8_t) * (syncpoint_count + 1));
+ syncpoints = av_malloc_array(syncpoint_count, sizeof(int64_t));
+ has_keyframe = av_malloc_array(syncpoint_count + 1, sizeof(int8_t));
if (!syncpoints || !has_keyframe) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -642,13 +749,17 @@ static int find_and_decode_index(NUTContext *nut)
int flag = x & 1;
x >>= 1;
if (n + x >= syncpoint_count + 1) {
- av_log(s, AV_LOG_ERROR, "index overflow A\n");
+ av_log(s, AV_LOG_ERROR, "index overflow A %d + %"PRIu64" >= %d\n", n, x, syncpoint_count + 1);
goto fail;
}
while (x--)
has_keyframe[n++] = flag;
has_keyframe[n++] = !flag;
} else {
+ if (x <= 1) {
+ av_log(s, AV_LOG_ERROR, "index: x %"PRIu64" is invalid\n", x);
+ goto fail;
+ }
while (x != 1) {
if (n >= syncpoint_count + 1) {
av_log(s, AV_LOG_ERROR, "index overflow B\n");
@@ -662,7 +773,7 @@ static int find_and_decode_index(NUTContext *nut)
av_log(s, AV_LOG_ERROR, "keyframe before first syncpoint in index\n");
goto fail;
}
- assert(n <= syncpoint_count + 1);
+ av_assert0(n <= syncpoint_count + 1);
for (; j < n && j < syncpoint_count; j++) {
if (has_keyframe[j]) {
uint64_t B, A = ffio_read_varlen(bc);
@@ -763,7 +874,7 @@ static int nut_read_header(AVFormatContext *s)
find_and_decode_index(nut);
avio_seek(bc, orig_pos, SEEK_SET);
}
- assert(nut->next_startcode == SYNCPOINT_STARTCODE);
+ av_assert0(nut->next_startcode == SYNCPOINT_STARTCODE);
ff_metadata_conv_ctx(s, NULL, ff_nut_metadata_conv);
@@ -775,13 +886,135 @@ fail:
return AVERROR_INVALIDDATA;
}
+static int read_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int is_meta, int64_t maxpos)
+{
+ 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;
+ int i, ret;
+
+ for (i=0; i<count; i++) {
+ uint8_t name[256], str_value[256], type_str[256];
+ int value;
+ if (avio_tell(bc) >= maxpos)
+ return AVERROR_INVALIDDATA;
+ ret = get_str(bc, name, sizeof(name));
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "get_str failed while reading sm data\n");
+ return ret;
+ }
+ value = get_s(bc);
+
+ if (value == -1) {
+ ret = get_str(bc, str_value, sizeof(str_value));
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "get_str failed while reading sm data\n");
+ return ret;
+ }
+ av_log(s, AV_LOG_WARNING, "Unknown string %s / %s\n", name, str_value);
+ } else if (value == -2) {
+ uint8_t *dst = NULL;
+ int64_t v64, value_len;
+
+ ret = get_str(bc, type_str, sizeof(type_str));
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "get_str failed while reading sm data\n");
+ return ret;
+ }
+ value_len = ffio_read_varlen(bc);
+ if (avio_tell(bc) + value_len >= maxpos)
+ return AVERROR_INVALIDDATA;
+ if (!strcmp(name, "Palette")) {
+ dst = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, value_len);
+ } else if (!strcmp(name, "Extradata")) {
+ dst = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, value_len);
+ } else if (sscanf(name, "CodecSpecificSide%"SCNd64"", &v64) == 1) {
+ dst = av_packet_new_side_data(pkt, AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, value_len + 8);
+ if(!dst)
+ return AVERROR(ENOMEM);
+ AV_WB64(dst, v64);
+ dst += 8;
+ } else if (!strcmp(name, "ChannelLayout") && value_len == 8) {
+ channel_layout = avio_rl64(bc);
+ continue;
+ } else {
+ av_log(s, AV_LOG_WARNING, "Unknown data %s / %s\n", name, type_str);
+ avio_skip(bc, value_len);
+ continue;
+ }
+ if(!dst)
+ return AVERROR(ENOMEM);
+ avio_read(bc, dst, value_len);
+ } else if (value == -3) {
+ value = get_s(bc);
+ } else if (value == -4) {
+ value = ffio_read_varlen(bc);
+ } else if (value < -4) {
+ get_s(bc);
+ } else {
+ if (!strcmp(name, "SkipStart")) {
+ skip_start = value;
+ } else if (!strcmp(name, "SkipEnd")) {
+ skip_end = value;
+ } else if (!strcmp(name, "Channels")) {
+ channels = value;
+ } else if (!strcmp(name, "SampleRate")) {
+ sample_rate = value;
+ } else if (!strcmp(name, "Width")) {
+ width = value;
+ } else if (!strcmp(name, "Height")) {
+ height = value;
+ } else {
+ av_log(s, AV_LOG_WARNING, "Unknown integer %s\n", name);
+ }
+ }
+ }
+
+ if (channels || channel_layout || sample_rate || width || height) {
+ uint8_t *dst = av_packet_new_side_data(pkt, AV_PKT_DATA_PARAM_CHANGE, 28);
+ if (!dst)
+ return AVERROR(ENOMEM);
+ bytestream_put_le32(&dst,
+ AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT*(!!channels) +
+ AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT*(!!channel_layout) +
+ 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){
+ bytestream_put_le32(&dst, width);
+ bytestream_put_le32(&dst, height);
+ }
+ }
+
+ if (skip_start || skip_end) {
+ uint8_t *dst = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+ if (!dst)
+ return AVERROR(ENOMEM);
+ AV_WL32(dst, skip_start);
+ AV_WL32(dst+4, skip_end);
+ }
+
+ return 0;
+}
+
static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id,
uint8_t *header_idx, int frame_code)
{
AVFormatContext *s = nut->avf;
AVIOContext *bc = s->pb;
StreamContext *stc;
- int size, flags, size_mul, pts_delta, i, reserved_count;
+ int size, flags, size_mul, pts_delta, i, reserved_count, ret;
uint64_t tmp;
if (!(nut->flags & NUT_PIPE) &&
@@ -814,7 +1047,7 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id,
if (coded_pts < (1 << stc->msb_pts_shift)) {
*pts = ff_lsb2full(stc, coded_pts);
} else
- *pts = coded_pts - (1 << stc->msb_pts_shift);
+ *pts = coded_pts - (1LL << stc->msb_pts_shift);
} else
*pts = stc->last_pts + pts_delta;
if (flags & FLAG_SIZE_MSB)
@@ -825,8 +1058,13 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id,
*header_idx = ffio_read_varlen(bc);
if (flags & FLAG_RESERVED)
reserved_count = ffio_read_varlen(bc);
- for (i = 0; i < reserved_count; i++)
+ for (i = 0; i < reserved_count; i++) {
+ if (bc->eof_reached) {
+ av_log(s, AV_LOG_ERROR, "reached EOF while decoding frame header\n");
+ return AVERROR_INVALIDDATA;
+ }
ffio_read_varlen(bc);
+ }
if (*header_idx >= (unsigned)nut->header_count) {
av_log(s, AV_LOG_ERROR, "header_idx invalid\n");
@@ -849,6 +1087,8 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id,
stc->last_flags = flags;
return size;
+fail:
+ return ret;
}
static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code)
@@ -885,7 +1125,27 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code)
return ret;
memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]);
pkt->pos = avio_tell(bc); // FIXME
- avio_read(bc, pkt->data + nut->header_len[header_idx], size);
+ if (stc->last_flags & FLAG_SM_DATA) {
+ int sm_size;
+ if (read_sm_data(s, bc, pkt, 0, pkt->pos + size) < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ if (read_sm_data(s, bc, pkt, 1, pkt->pos + size) < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ sm_size = avio_tell(bc) - pkt->pos;
+ size -= sm_size;
+ pkt->size -= sm_size;
+ }
+
+ ret = avio_read(bc, pkt->data + nut->header_len[header_idx], size);
+ if (ret != size) {
+ if (ret < 0)
+ goto fail;
+ }
+ av_shrink_packet(pkt, nut->header_len[header_idx] + ret);
pkt->stream_index = stream_id;
if (stc->last_flags & FLAG_KEY)
@@ -893,6 +1153,9 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code)
pkt->pts = pts;
return 0;
+fail:
+ av_free_packet(pkt);
+ return ret;
}
static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
@@ -911,7 +1174,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
pos -= 8;
} else {
frame_code = avio_r8(bc);
- if (bc->eof_reached)
+ if (avio_feof(bc))
return AVERROR_EOF;
if (frame_code == 'N') {
tmp = frame_code;
@@ -943,7 +1206,8 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
default:
resync:
av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", pos);
- tmp = find_any_startcode(bc, nut->last_syncpoint_pos + 1);
+ tmp = find_any_startcode(bc, FFMAX(nut->last_syncpoint_pos, nut->last_resync_pos) + 1);
+ nut->last_resync_pos = avio_tell(bc);
if (tmp == 0)
return AVERROR_INVALIDDATA;
av_log(s, AV_LOG_DEBUG, "sync\n");
@@ -965,21 +1229,18 @@ static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index,
do {
pos = find_startcode(bc, SYNCPOINT_STARTCODE, pos) + 1;
if (pos < 1) {
- assert(nut->next_startcode == 0);
av_log(s, AV_LOG_ERROR, "read_timestamp failed.\n");
return AV_NOPTS_VALUE;
}
} while (decode_syncpoint(nut, &pts, &back_ptr) < 0);
*pos_arg = pos - 1;
- assert(nut->last_syncpoint_pos == *pos_arg);
+ av_assert0(nut->last_syncpoint_pos == *pos_arg);
av_log(s, AV_LOG_DEBUG, "return %"PRId64" %"PRId64"\n", pts, back_ptr);
- if (stream_index == -1)
- return pts;
- else if (stream_index == -2)
+ if (stream_index == -2)
return back_ptr;
-
- return AV_NOPTS_VALUE;
+ av_assert0(stream_index == -1);
+ return pts;
}
static int read_seek(AVFormatContext *s, int stream_index,
@@ -1000,6 +1261,8 @@ static int read_seek(AVFormatContext *s, int stream_index,
if (st->index_entries) {
int index = av_index_search_timestamp(st, pts, flags);
if (index < 0)
+ index = av_index_search_timestamp(st, pts, flags ^ AVSEEK_FLAG_BACKWARD);
+ if (index < 0)
return -1;
pos2 = st->index_entries[index].pos;
@@ -1032,24 +1295,28 @@ static int read_seek(AVFormatContext *s, int stream_index,
sp = av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp,
NULL);
- assert(sp);
+ av_assert0(sp);
pos2 = sp->back_ptr - 15;
}
av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos2);
pos = find_startcode(s->pb, SYNCPOINT_STARTCODE, pos2);
avio_seek(s->pb, pos, SEEK_SET);
+ nut->last_syncpoint_pos = pos;
av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos);
if (pos2 > pos || pos2 + 15 < pos)
av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n");
for (i = 0; i < s->nb_streams; i++)
nut->stream[i].skip_until_key_frame = 1;
+ nut->last_resync_pos = 0;
+
return 0;
}
AVInputFormat ff_nut_demuxer = {
.name = "nut",
.long_name = NULL_IF_CONFIG_SMALL("NUT"),
+ .flags = AVFMT_SEEK_TO_PTS,
.priv_data_size = sizeof(NUTContext),
.read_probe = nut_probe,
.read_header = nut_read_header,
diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c
index b7b0c9c790..1522a0452f 100644
--- a/libavformat/nutenc.c
+++ b/libavformat/nutenc.c
@@ -2,20 +2,20 @@
* nut muxer
* Copyright (c) 2004-2007 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,8 +25,10 @@
#include "libavutil/mathematics.h"
#include "libavutil/tree.h"
#include "libavutil/dict.h"
+#include "libavutil/avassert.h"
#include "libavutil/time.h"
#include "libavutil/opt.h"
+#include "libavcodec/bytestream.h"
#include "libavcodec/mpegaudiodata.h"
#include "nut.h"
#include "internal.h"
@@ -64,12 +66,9 @@ static int find_expected_header(AVCodecContext *c, int size, int key_frame,
lsf = sample_rate < (24000 + 32000) / 2;
mpeg25 = sample_rate < (12000 + 16000) / 2;
sample_rate <<= lsf + mpeg25;
- if (sample_rate < (32000 + 44100) / 2)
- sample_rate_index = 2;
- else if (sample_rate < (44100 + 48000) / 2)
- sample_rate_index = 0;
- else
- sample_rate_index = 1;
+ if (sample_rate < (32000 + 44100) / 2) sample_rate_index = 2;
+ else if (sample_rate < (44100 + 48000) / 2) sample_rate_index = 0;
+ else sample_rate_index = 1;
sample_rate = avpriv_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25);
@@ -103,8 +102,7 @@ static int find_expected_header(AVCodecContext *c, int size, int key_frame,
return 0;
}
-static int find_header_idx(AVFormatContext *s, AVCodecContext *c, int size,
- int frame_type)
+static int find_header_idx(AVFormatContext *s, AVCodecContext *c, int size, int frame_type)
{
NUTContext *nut = s->priv_data;
uint8_t out[64];
@@ -170,10 +168,22 @@ static void build_frame_code(AVFormatContext *s)
int start2 = start + (end - start) * stream_id / s->nb_streams;
int end2 = start + (end - start) * (stream_id + 1) / s->nb_streams;
AVCodecContext *codec = s->streams[stream_id]->codec;
- const AVCodecDescriptor *desc = avcodec_descriptor_get(codec->codec_id);
int is_audio = codec->codec_type == AVMEDIA_TYPE_AUDIO;
int intra_only = /*codec->intra_only || */ is_audio;
int pred_count;
+ int frame_size = 0;
+
+ if (codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ frame_size = av_get_audio_frame_duration(codec, 0);
+ if (codec->codec_id == AV_CODEC_ID_VORBIS && !frame_size)
+ frame_size = 64;
+ } else {
+ AVRational f = av_div_q(codec->time_base, *nut->stream[stream_id].time_base);
+ if (f.den == 1 && f.num>0)
+ frame_size = f.num;
+ }
+ if (!frame_size)
+ frame_size = 1;
for (key_frame = 0; key_frame < 2; key_frame++) {
if (!intra_only || !keyframe_0_esc || key_frame != 0) {
@@ -189,31 +199,34 @@ static void build_frame_code(AVFormatContext *s)
}
key_frame = intra_only;
+#if 1
if (is_audio) {
int frame_bytes = codec->frame_size * (int64_t)codec->bit_rate /
(8 * codec->sample_rate);
int pts;
- for (pts = 0; pts < 2; pts++)
+ for (pts = 0; pts < 2; pts++) {
for (pred = 0; pred < 2; pred++) {
- FrameCode *ft = &nut->frame_code[start2];
+ FrameCode *ft = &nut->frame_code[start2];
ft->flags = FLAG_KEY * key_frame;
ft->stream_id = stream_id;
ft->size_mul = frame_bytes + 2;
ft->size_lsb = frame_bytes + pred;
- ft->pts_delta = pts;
+ ft->pts_delta = pts * frame_size;
ft->header_idx = find_header_idx(s, codec, frame_bytes + pred, key_frame);
start2++;
}
+ }
} else {
FrameCode *ft = &nut->frame_code[start2];
ft->flags = FLAG_KEY | FLAG_SIZE_MSB;
ft->stream_id = stream_id;
ft->size_mul = 1;
- ft->pts_delta = 1;
+ ft->pts_delta = frame_size;
start2++;
}
+#endif
- if (desc && desc->props & AV_CODEC_PROP_REORDER) {
+ if (codec->has_b_frames) {
pred_count = 5;
pred_table[0] = -2;
pred_table[1] = -1;
@@ -234,6 +247,8 @@ static void build_frame_code(AVFormatContext *s)
int start3 = start2 + (end2 - start2) * pred / pred_count;
int end3 = start2 + (end2 - start2) * (pred + 1) / pred_count;
+ pred_table[pred] *= frame_size;
+
for (index = start3; index < end3; index++) {
FrameCode *ft = &nut->frame_code[index];
ft->flags = FLAG_KEY * key_frame;
@@ -248,15 +263,13 @@ static void build_frame_code(AVFormatContext *s)
}
}
}
- memmove(&nut->frame_code['N' + 1], &nut->frame_code['N'],
- sizeof(FrameCode) * (255 - 'N'));
+ memmove(&nut->frame_code['N' + 1], &nut->frame_code['N'], sizeof(FrameCode) * (255 - 'N'));
nut->frame_code[0].flags =
nut->frame_code[255].flags =
nut->frame_code['N'].flags = FLAG_INVALID;
}
-static void put_tt(NUTContext *nut, AVRational *time_base, AVIOContext *bc,
- uint64_t val)
+static void put_tt(NUTContext *nut, AVRational *time_base, AVIOContext *bc, uint64_t val)
{
val *= nut->time_base_count;
val += time_base - nut->time_base;
@@ -267,7 +280,7 @@ static void put_tt(NUTContext *nut, AVRational *time_base, AVIOContext *bc,
*/
static void put_str(AVIOContext *bc, const char *string)
{
- int len = strlen(string);
+ size_t len = strlen(string);
ff_put_v(bc, len);
avio_write(bc, string, len);
@@ -287,8 +300,7 @@ static inline void ff_put_v_trace(AVIOContext *bc, uint64_t v, const char *file,
ff_put_v(bc, v);
}
-static inline void put_s_trace(AVIOContext *bc, int64_t v, const char *file,
- const char *func, int line)
+static inline void put_s_trace(AVIOContext *bc, int64_t v, const char *file, const char *func, int line)
{
av_log(NULL, AV_LOG_DEBUG, "put_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
@@ -329,6 +341,8 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc)
int64_t tmp_match;
ff_put_v(bc, nut->version);
+ if (nut->version > 3)
+ ff_put_v(bc, nut->minor_version = 1);
ff_put_v(bc, nut->avf->nb_streams);
ff_put_v(bc, nut->max_distance);
ff_put_v(bc, nut->time_base_count);
@@ -347,17 +361,12 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc)
tmp_fields = 0;
tmp_size = 0;
// tmp_res=0;
- if (tmp_pts != nut->frame_code[i].pts_delta)
- tmp_fields = 1;
- if (tmp_mul != nut->frame_code[i].size_mul)
- tmp_fields = 2;
- if (tmp_stream != nut->frame_code[i].stream_id)
- tmp_fields = 3;
- if (tmp_size != nut->frame_code[i].size_lsb)
- tmp_fields = 4;
-// if(tmp_res != nut->frame_code[i].res ) tmp_fields=5;
- if (tmp_head_idx != nut->frame_code[i].header_idx)
- tmp_fields = 8;
+ if (tmp_pts != nut->frame_code[i].pts_delta ) tmp_fields = 1;
+ if (tmp_mul != nut->frame_code[i].size_mul ) tmp_fields = 2;
+ if (tmp_stream != nut->frame_code[i].stream_id ) tmp_fields = 3;
+ if (tmp_size != nut->frame_code[i].size_lsb ) tmp_fields = 4;
+// if (tmp_res != nut->frame_code[i].res ) tmp_fields=5;
+ if (tmp_head_idx != nut->frame_code[i].header_idx) tmp_fields = 8;
tmp_pts = nut->frame_code[i].pts_delta;
tmp_flags = nut->frame_code[i].flags;
@@ -386,22 +395,14 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc)
ff_put_v(bc, tmp_flags);
ff_put_v(bc, tmp_fields);
- if (tmp_fields > 0)
- put_s(bc, tmp_pts);
- if (tmp_fields > 1)
- ff_put_v(bc, tmp_mul);
- if (tmp_fields > 2)
- ff_put_v(bc, tmp_stream);
- if (tmp_fields > 3)
- ff_put_v(bc, tmp_size);
- if (tmp_fields > 4)
- ff_put_v(bc, 0 /*tmp_res*/);
- if (tmp_fields > 5)
- ff_put_v(bc, j);
- if (tmp_fields > 6)
- ff_put_v(bc, tmp_match);
- if (tmp_fields > 7)
- ff_put_v(bc, tmp_head_idx);
+ if (tmp_fields > 0) put_s(bc, tmp_pts);
+ if (tmp_fields > 1) ff_put_v(bc, tmp_mul);
+ if (tmp_fields > 2) ff_put_v(bc, tmp_stream);
+ if (tmp_fields > 3) ff_put_v(bc, tmp_size);
+ if (tmp_fields > 4) ff_put_v(bc, 0 /*tmp_res*/);
+ if (tmp_fields > 5) ff_put_v(bc, j);
+ if (tmp_fields > 6) ff_put_v(bc, tmp_match);
+ if (tmp_fields > 7) ff_put_v(bc, tmp_head_idx);
}
ff_put_v(bc, nut->header_count - 1);
for (i = 1; i < nut->header_count; i++) {
@@ -409,7 +410,7 @@ static void write_mainheader(NUTContext *nut, AVIOContext *bc)
avio_write(bc, nut->header[i], nut->header_len[i]);
}
// flags had been effectively introduced in version 4
- if (nut->version > NUT_STABLE_VERSION)
+ if (nut->version > 3)
ff_put_v(bc, nut->flags);
}
@@ -418,31 +419,17 @@ static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
{
NUTContext *nut = avctx->priv_data;
AVCodecContext *codec = st->codec;
- const AVCodecDescriptor *desc = avcodec_descriptor_get(codec->codec_id);
- unsigned codec_tag = av_codec_get_tag(ff_nut_codec_tags, codec->codec_id);
ff_put_v(bc, i);
switch (codec->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- ff_put_v(bc, 0);
- break;
- case AVMEDIA_TYPE_AUDIO:
- ff_put_v(bc, 1);
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- ff_put_v(bc, 2);
- break;
- default:
- ff_put_v(bc, 3);
- break;
+ case AVMEDIA_TYPE_VIDEO: ff_put_v(bc, 0); break;
+ case AVMEDIA_TYPE_AUDIO: ff_put_v(bc, 1); break;
+ case AVMEDIA_TYPE_SUBTITLE: ff_put_v(bc, 2); break;
+ default: ff_put_v(bc, 3); break;
}
ff_put_v(bc, 4);
-
- if (!codec_tag || codec->codec_id == AV_CODEC_ID_RAWVIDEO)
- codec_tag = codec->codec_tag;
-
- if (codec_tag) {
- avio_wl32(bc, codec_tag);
+ if (codec->codec_tag) {
+ avio_wl32(bc, codec->codec_tag);
} else {
av_log(avctx, AV_LOG_ERROR, "No codec tag defined for stream %d\n", i);
return AVERROR(EINVAL);
@@ -451,7 +438,7 @@ static int write_streamheader(AVFormatContext *avctx, AVIOContext *bc,
ff_put_v(bc, nut->stream[i].time_base - nut->time_base);
ff_put_v(bc, nut->stream[i].msb_pts_shift);
ff_put_v(bc, nut->stream[i].max_pts_distance);
- ff_put_v(bc, (desc && desc->props & AV_CODEC_PROP_REORDER) ? 16 : 0);
+ ff_put_v(bc, codec->has_b_frames);
avio_w8(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */
ff_put_v(bc, codec->extradata_size);
@@ -518,20 +505,31 @@ static int write_globalinfo(NUTContext *nut, AVIOContext *bc)
return 0;
}
-static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id){
+static int write_streaminfo(NUTContext *nut, AVIOContext *bc, int stream_id) {
AVFormatContext *s= nut->avf;
AVStream* st = s->streams[stream_id];
+ AVDictionaryEntry *t = NULL;
AVIOContext *dyn_bc;
uint8_t *dyn_buf=NULL;
int count=0, dyn_size, i;
int ret = avio_open_dyn_buf(&dyn_bc);
- if(ret < 0)
+ if (ret < 0)
return ret;
+ while ((t = av_dict_get(st->metadata, "", t, AV_DICT_IGNORE_SUFFIX)))
+ count += add_info(dyn_bc, t->key, t->value);
for (i=0; ff_nut_dispositions[i].flag; ++i) {
if (st->disposition & ff_nut_dispositions[i].flag)
count += add_info(dyn_bc, "Disposition", ff_nut_dispositions[i].str);
}
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ uint8_t buf[256];
+ if (st->r_frame_rate.num>0 && st->r_frame_rate.den>0)
+ snprintf(buf, sizeof(buf), "%d/%d", st->r_frame_rate.num, st->r_frame_rate.den);
+ else
+ snprintf(buf, sizeof(buf), "%d/%d", st->codec->time_base.den, st->codec->time_base.num);
+ count += add_info(dyn_bc, "r_frame_rate", buf);
+ }
dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
if (count) {
@@ -577,6 +575,58 @@ static int write_chapter(NUTContext *nut, AVIOContext *bc, int id)
return 0;
}
+static int write_index(NUTContext *nut, AVIOContext *bc) {
+ int i;
+ Syncpoint dummy= { .pos= 0 };
+ Syncpoint *next_node[2] = { NULL };
+ int64_t startpos = avio_tell(bc);
+ int64_t payload_size;
+
+ put_tt(nut, nut->max_pts_tb, bc, nut->max_pts);
+
+ ff_put_v(bc, nut->sp_count);
+
+ for (i=0; i<nut->sp_count; i++) {
+ av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp, (void**)next_node);
+ ff_put_v(bc, (next_node[1]->pos >> 4) - (dummy.pos>>4));
+ dummy.pos = next_node[1]->pos;
+ }
+
+ for (i=0; i<nut->avf->nb_streams; i++) {
+ StreamContext *nus= &nut->stream[i];
+ int64_t last_pts= -1;
+ int j, k;
+ for (j=0; j<nut->sp_count; j++) {
+ int flag;
+ int n = 0;
+
+ if (j && nus->keyframe_pts[j] == nus->keyframe_pts[j-1]) {
+ av_log(nut->avf, AV_LOG_WARNING, "Multiple keyframes with same PTS\n");
+ nus->keyframe_pts[j] = AV_NOPTS_VALUE;
+ }
+
+ flag = (nus->keyframe_pts[j] != AV_NOPTS_VALUE) ^ (j+1 == nut->sp_count);
+ for (; j<nut->sp_count && (nus->keyframe_pts[j] != AV_NOPTS_VALUE) == flag; j++)
+ n++;
+
+ ff_put_v(bc, 1 + 2*flag + 4*n);
+ for (k= j - n; k<=j && k<nut->sp_count; k++) {
+ if (nus->keyframe_pts[k] == AV_NOPTS_VALUE)
+ continue;
+ av_assert0(nus->keyframe_pts[k] > last_pts);
+ ff_put_v(bc, nus->keyframe_pts[k] - last_pts);
+ last_pts = nus->keyframe_pts[k];
+ }
+ }
+ }
+
+ payload_size = avio_tell(bc) - startpos + 8 + 4;
+
+ avio_wb64(bc, 8 + payload_size + av_log2(payload_size) / 7 + 1 + 4*(payload_size > 4096));
+
+ return 0;
+}
+
static int write_headers(AVFormatContext *avctx, AVIOContext *bc)
{
NUTContext *nut = avctx->priv_data;
@@ -645,8 +695,8 @@ static int nut_write_header(AVFormatContext *s)
nut->avf = s;
- nut->version = NUT_STABLE_VERSION + !!nut->flags;
- if (nut->flags && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
+ nut->version = FFMAX(NUT_STABLE_VERSION, 3 + !!nut->flags);
+ if (nut->version > 3 && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
av_log(s, AV_LOG_ERROR,
"The additional syncpoint modes require version %d, "
"that is currently not finalized, "
@@ -655,12 +705,11 @@ static int nut_write_header(AVFormatContext *s)
return AVERROR_EXPERIMENTAL;
}
- nut->stream = av_mallocz(sizeof(StreamContext) * s->nb_streams);
- if (s->nb_chapters)
- nut->chapter = av_mallocz(sizeof(ChapterContext) * s->nb_chapters);
- nut->time_base = av_mallocz(sizeof(AVRational) * (s->nb_streams +
- s->nb_chapters));
- if (!nut->stream || (s->nb_chapters && !nut->chapter) || !nut->time_base) {
+ nut->stream = av_calloc(s->nb_streams, sizeof(*nut->stream ));
+ nut->chapter = av_calloc(s->nb_chapters, sizeof(*nut->chapter));
+ nut->time_base= av_calloc(s->nb_streams +
+ s->nb_chapters, sizeof(*nut->time_base));
+ if (!nut->stream || !nut->chapter || !nut->time_base) {
av_freep(&nut->stream);
av_freep(&nut->chapter);
av_freep(&nut->time_base);
@@ -671,8 +720,13 @@ static int nut_write_header(AVFormatContext *s)
AVStream *st = s->streams[i];
int ssize;
AVRational time_base;
- ff_parse_specific_params(st, &time_base.den, &ssize,
- &time_base.num);
+ ff_parse_specific_params(st, &time_base.den, &ssize, &time_base.num);
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->codec->sample_rate) {
+ time_base = (AVRational) {1, st->codec->sample_rate};
+ } else {
+ time_base = ff_choose_timebase(s, st, 48000);
+ }
avpriv_set_pts_info(st, 64, time_base.num, time_base.den);
@@ -709,7 +763,7 @@ static int nut_write_header(AVFormatContext *s)
nut->max_distance = MAX_DISTANCE;
build_elision_headers(s);
build_frame_code(s);
- assert(nut->frame_code['N'].flags == FLAG_INVALID);
+ av_assert0(nut->frame_code['N'].flags == FLAG_INVALID);
avio_write(bc, ID_STRING, strlen(ID_STRING));
avio_w8(bc, 0);
@@ -717,9 +771,10 @@ static int nut_write_header(AVFormatContext *s)
if ((ret = write_headers(s, bc)) < 0)
return ret;
- avio_flush(bc);
+ if (s->avoid_negative_ts < 0)
+ s->avoid_negative_ts = 1;
- //FIXME index
+ avio_flush(bc);
return 0;
}
@@ -737,6 +792,8 @@ static int get_needed_flags(NUTContext *nut, StreamContext *nus, FrameCode *fc,
flags |= FLAG_SIZE_MSB;
if (pkt->pts - nus->last_pts != fc->pts_delta)
flags |= FLAG_CODED_PTS;
+ if (pkt->side_data_elems && nut->version > 3)
+ flags |= FLAG_SM_DATA;
if (pkt->size > 2 * nut->max_distance)
flags |= FLAG_CHECKSUM;
if (FFABS(pkt->pts - nus->last_pts) > nus->max_pts_distance)
@@ -769,24 +826,164 @@ static int find_best_header_idx(NUTContext *nut, AVPacket *pkt)
return best_i;
}
+static int write_sm_data(AVFormatContext *s, AVIOContext *bc, AVPacket *pkt, int is_meta)
+{
+ int ret, i, dyn_size;
+ unsigned flags;
+ AVIOContext *dyn_bc;
+ int sm_data_count = 0;
+ uint8_t tmp[256];
+ uint8_t *dyn_buf;
+
+ ret = avio_open_dyn_buf(&dyn_bc);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i<pkt->side_data_elems; i++) {
+ const uint8_t *data = pkt->side_data[i].data;
+ int size = pkt->side_data[i].size;
+ const uint8_t *data_end = data + size;
+
+ if (is_meta) {
+ if ( pkt->side_data[i].type == AV_PKT_DATA_METADATA_UPDATE
+ || pkt->side_data[i].type == AV_PKT_DATA_STRINGS_METADATA) {
+ if (!size || data[size-1]) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ while (data < data_end) {
+ const uint8_t *key = data;
+ const uint8_t *val = data + strlen(key) + 1;
+
+ if(val >= data_end) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ put_str(dyn_bc, key);
+ put_s(dyn_bc, -1);
+ put_str(dyn_bc, val);
+ data = val + strlen(val) + 1;
+ sm_data_count++;
+ }
+ }
+ } else {
+ switch (pkt->side_data[i].type) {
+ case AV_PKT_DATA_PALETTE:
+ case AV_PKT_DATA_NEW_EXTRADATA:
+ case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL:
+ default:
+ if (pkt->side_data[i].type == AV_PKT_DATA_PALETTE) {
+ put_str(dyn_bc, "Palette");
+ } else if(pkt->side_data[i].type == AV_PKT_DATA_NEW_EXTRADATA) {
+ put_str(dyn_bc, "Extradata");
+ } else if(pkt->side_data[i].type == AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL) {
+ snprintf(tmp, sizeof(tmp), "CodecSpecificSide%"PRId64"", AV_RB64(data));
+ put_str(dyn_bc, tmp);
+ } else {
+ snprintf(tmp, sizeof(tmp), "UserData%s-SD-%d",
+ (s->flags & AVFMT_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT,
+ pkt->side_data[i].type);
+ put_str(dyn_bc, tmp);
+ }
+ put_s(dyn_bc, -2);
+ put_str(dyn_bc, "bin");
+ ff_put_v(dyn_bc, pkt->side_data[i].size);
+ avio_write(dyn_bc, data, pkt->side_data[i].size);
+ sm_data_count++;
+ break;
+ case AV_PKT_DATA_PARAM_CHANGE:
+ flags = bytestream_get_le32(&data);
+ if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) {
+ put_str(dyn_bc, "Channels");
+ put_s(dyn_bc, bytestream_get_le32(&data));
+ sm_data_count++;
+ }
+ if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) {
+ put_str(dyn_bc, "ChannelLayout");
+ put_s(dyn_bc, -2);
+ put_str(dyn_bc, "u64");
+ ff_put_v(bc, 8);
+ avio_write(dyn_bc, data, 8); data+=8;
+ sm_data_count++;
+ }
+ if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) {
+ put_str(dyn_bc, "SampleRate");
+ put_s(dyn_bc, bytestream_get_le32(&data));
+ sm_data_count++;
+ }
+ if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) {
+ put_str(dyn_bc, "Width");
+ put_s(dyn_bc, bytestream_get_le32(&data));
+ put_str(dyn_bc, "Height");
+ put_s(dyn_bc, bytestream_get_le32(&data));
+ sm_data_count+=2;
+ }
+ break;
+ case AV_PKT_DATA_SKIP_SAMPLES:
+ if (AV_RL32(data)) {
+ put_str(dyn_bc, "SkipStart");
+ put_s(dyn_bc, (unsigned)AV_RL32(data));
+ sm_data_count++;
+ }
+ if (AV_RL32(data+4)) {
+ put_str(dyn_bc, "SkipEnd");
+ put_s(dyn_bc, (unsigned)AV_RL32(data+4));
+ sm_data_count++;
+ }
+ break;
+ case AV_PKT_DATA_METADATA_UPDATE:
+ case AV_PKT_DATA_STRINGS_METADATA:
+ // belongs into meta, not side data
+ break;
+ }
+ }
+ }
+
+fail:
+ ff_put_v(bc, sm_data_count);
+ dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
+ avio_write(bc, dyn_buf, dyn_size);
+ av_freep(&dyn_buf);
+
+ return ret;
+}
+
static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
{
NUTContext *nut = s->priv_data;
StreamContext *nus = &nut->stream[pkt->stream_index];
- AVIOContext *bc = s->pb, *dyn_bc;
+ AVIOContext *bc = s->pb, *dyn_bc, *sm_bc = NULL;
FrameCode *fc;
int64_t coded_pts;
- int best_length, frame_code, flags, needed_flags, i, header_idx,
- best_header_idx;
+ int best_length, frame_code, flags, needed_flags, i, header_idx;
+ int best_header_idx;
int key_frame = !!(pkt->flags & AV_PKT_FLAG_KEY);
int store_sp = 0;
- int ret;
+ int ret = 0;
+ int sm_size = 0;
+ int data_size = pkt->size;
+ uint8_t *sm_buf = NULL;
if (pkt->pts < 0) {
av_log(s, AV_LOG_ERROR,
"Negative pts not supported stream %d, pts %"PRId64"\n",
pkt->stream_index, pkt->pts);
- return AVERROR_INVALIDDATA;
+ if (pkt->pts == AV_NOPTS_VALUE)
+ av_log(s, AV_LOG_ERROR, "Try to enable the genpts flag\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (pkt->side_data_elems && nut->version > 3) {
+ ret = avio_open_dyn_buf(&sm_bc);
+ if (ret < 0)
+ return ret;
+ ret = write_sm_data(s, sm_bc, pkt, 0);
+ if (ret >= 0)
+ ret = write_sm_data(s, sm_bc, pkt, 1);
+ sm_size = avio_close_dyn_buf(sm_bc, &sm_buf);
+ if (ret < 0)
+ goto fail;
+ data_size += sm_size;
}
if (1LL << (20 + 3 * nut->header_count) <= avio_tell(bc))
@@ -795,15 +992,14 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
if (key_frame && !(nus->last_flags & FLAG_KEY))
store_sp = 1;
- if (pkt->size + 30 /*FIXME check*/ + avio_tell(bc) >=
- nut->last_syncpoint_pos + nut->max_distance)
+ if (data_size + 30 /*FIXME check*/ + avio_tell(bc) >= nut->last_syncpoint_pos + nut->max_distance)
store_sp = 1;
//FIXME: Ensure store_sp is 1 in the first place.
if (store_sp &&
(!(nut->flags & NUT_PIPE) || nut->last_syncpoint_pos == INT_MIN)) {
- Syncpoint *sp, dummy = { .pos = INT64_MAX };
+ int64_t sp_pos = INT64_MAX;
ff_nut_reset_ts(nut, *nus->time_base, pkt->dts);
for (i = 0; i < s->nb_streams; i++) {
@@ -814,20 +1010,23 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
AV_ROUND_DOWN);
int index = av_index_search_timestamp(st, dts_tb,
AVSEEK_FLAG_BACKWARD);
- if (index >= 0)
- dummy.pos = FFMIN(dummy.pos, st->index_entries[index].pos);
+ if (index >= 0) {
+ sp_pos = FFMIN(sp_pos, st->index_entries[index].pos);
+ if (!nut->write_index && 2*index > st->nb_index_entries) {
+ memmove(st->index_entries,
+ st->index_entries + index,
+ sizeof(*st->index_entries) * (st->nb_index_entries - index));
+ st->nb_index_entries -= index;
+ }
+ }
}
- if (dummy.pos == INT64_MAX)
- dummy.pos = 0;
- sp = av_tree_find(nut->syncpoints, &dummy, (void *)ff_nut_sp_pos_cmp,
- NULL);
nut->last_syncpoint_pos = avio_tell(bc);
ret = avio_open_dyn_buf(&dyn_bc);
if (ret < 0)
- return ret;
+ goto fail;
put_tt(nut, nus->time_base, dyn_bc, pkt->dts);
- ff_put_v(dyn_bc, sp ? (nut->last_syncpoint_pos - sp->pos) >> 4 : 0);
+ ff_put_v(dyn_bc, sp_pos != INT64_MAX ? (nut->last_syncpoint_pos - sp_pos) >> 4 : 0);
if (nut->flags & NUT_BROADCAST) {
put_tt(nut, nus->time_base, dyn_bc,
@@ -835,10 +1034,25 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
}
put_packet(nut, bc, dyn_bc, 1, SYNCPOINT_STARTCODE);
+ if (nut->write_index) {
if ((ret = ff_nut_add_sp(nut, nut->last_syncpoint_pos, 0 /*unused*/, pkt->dts)) < 0)
- return ret;
+ goto fail;
+
+ if ((1ll<<60) % nut->sp_count == 0)
+ for (i=0; i<s->nb_streams; i++) {
+ int j;
+ StreamContext *nus = &nut->stream[i];
+ av_reallocp_array(&nus->keyframe_pts, 2*nut->sp_count, sizeof(*nus->keyframe_pts));
+ if (!nus->keyframe_pts) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ for (j=nut->sp_count == 1 ? 0 : nut->sp_count; j<2*nut->sp_count; j++)
+ nus->keyframe_pts[j] = AV_NOPTS_VALUE;
+ }
+ }
}
- assert(nus->last_pts != AV_NOPTS_VALUE);
+ av_assert0(nus->last_pts != AV_NOPTS_VALUE);
coded_pts = pkt->pts & ((1 << nus->msb_pts_shift) - 1);
if (ff_lsb2full(nus, coded_pts) != pkt->pts)
@@ -871,10 +1085,10 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
if (flags & FLAG_STREAM_ID)
length += ff_get_v_length(pkt->stream_index);
- if (pkt->size % fc->size_mul != fc->size_lsb)
+ if (data_size % fc->size_mul != fc->size_lsb)
continue;
if (flags & FLAG_SIZE_MSB)
- length += ff_get_v_length(pkt->size / fc->size_mul);
+ length += ff_get_v_length(data_size / fc->size_mul);
if (flags & FLAG_CHECKSUM)
length += 4;
@@ -882,9 +1096,8 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
if (flags & FLAG_CODED_PTS)
length += ff_get_v_length(coded_pts);
- if ((flags & FLAG_CODED)
- && nut->header_len[best_header_idx] >
- nut->header_len[fc->header_idx] + 1) {
+ if ( (flags & FLAG_CODED)
+ && nut->header_len[best_header_idx] > nut->header_len[fc->header_idx] + 1) {
flags |= FLAG_HEADER_IDX;
}
@@ -903,9 +1116,7 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
frame_code = i;
}
}
-
- if (frame_code < 0)
- return AVERROR_BUG;
+ av_assert0(frame_code != -1);
fc = &nut->frame_code[frame_code];
flags = fc->flags;
@@ -918,27 +1129,24 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
ff_put_v(bc, (flags ^ needed_flags) & ~(FLAG_CODED));
flags = needed_flags;
}
- if (flags & FLAG_STREAM_ID)
- ff_put_v(bc, pkt->stream_index);
- if (flags & FLAG_CODED_PTS)
- ff_put_v(bc, coded_pts);
- if (flags & FLAG_SIZE_MSB)
- ff_put_v(bc, pkt->size / fc->size_mul);
- if (flags & FLAG_HEADER_IDX)
- ff_put_v(bc, header_idx = best_header_idx);
+ if (flags & FLAG_STREAM_ID) ff_put_v(bc, pkt->stream_index);
+ if (flags & FLAG_CODED_PTS) ff_put_v(bc, coded_pts);
+ if (flags & FLAG_SIZE_MSB ) ff_put_v(bc, data_size / fc->size_mul);
+ if (flags & FLAG_HEADER_IDX) ff_put_v(bc, header_idx = best_header_idx);
- if (flags & FLAG_CHECKSUM)
- avio_wl32(bc, ffio_get_checksum(bc));
- else
- ffio_get_checksum(bc);
+ if (flags & FLAG_CHECKSUM) avio_wl32(bc, ffio_get_checksum(bc));
+ else ffio_get_checksum(bc);
+
+ if (flags & FLAG_SM_DATA) {
+ avio_write(bc, sm_buf, sm_size);
+ }
+ avio_write(bc, pkt->data + nut->header_len[header_idx], pkt->size - nut->header_len[header_idx]);
- avio_write(bc, pkt->data + nut->header_len[header_idx],
- pkt->size - nut->header_len[header_idx]);
nus->last_flags = flags;
nus->last_pts = pkt->pts;
//FIXME just store one per syncpoint
- if (flags & FLAG_KEY && !(nut->flags & NUT_PIPE))
+ if (flags & FLAG_KEY && !(nut->flags & NUT_PIPE)) {
av_add_index_entry(
s->streams[pkt->stream_index],
nut->last_syncpoint_pos,
@@ -946,19 +1154,41 @@ static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
0,
0,
AVINDEX_KEYFRAME);
+ if (nus->keyframe_pts && nus->keyframe_pts[nut->sp_count] == AV_NOPTS_VALUE)
+ nus->keyframe_pts[nut->sp_count] = pkt->pts;
+ }
- return 0;
+ if (!nut->max_pts_tb || av_compare_ts(nut->max_pts, *nut->max_pts_tb, pkt->pts, *nus->time_base) < 0) {
+ nut->max_pts = pkt->pts;
+ nut->max_pts_tb = nus->time_base;
+ }
+
+fail:
+ av_freep(&sm_buf);
+
+ return ret;
}
static int nut_write_trailer(AVFormatContext *s)
{
NUTContext *nut = s->priv_data;
- AVIOContext *bc = s->pb;
+ AVIOContext *bc = s->pb, *dyn_bc;
+ int i, ret;
while (nut->header_count < 3)
write_headers(s, bc);
+ ret = avio_open_dyn_buf(&dyn_bc);
+ if (ret >= 0 && nut->sp_count) {
+ av_assert1(nut->write_index);
+ write_index(nut, dyn_bc);
+ put_packet(nut, bc, dyn_bc, 1, INDEX_STARTCODE);
+ }
+
ff_nut_free_sp(nut);
+ for (i=0; i<s->nb_streams; i++)
+ av_freep(&nut->stream[i].keyframe_pts);
+
av_freep(&nut->stream);
av_freep(&nut->chapter);
av_freep(&nut->time_base);
@@ -973,6 +1203,7 @@ static const AVOption options[] = {
{ "default", "", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, E, "syncpoints" },
{ "none", "Disable syncpoints, low overhead and unseekable", 0, AV_OPT_TYPE_CONST, {.i64 = NUT_PIPE}, INT_MIN, INT_MAX, E, "syncpoints" },
{ "timestamped", "Extend syncpoints with a wallclock timestamp", 0, AV_OPT_TYPE_CONST, {.i64 = NUT_BROADCAST}, INT_MIN, INT_MAX, E, "syncpoints" },
+ { "write_index", "Write index", OFFSET(write_index), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E, },
{ NULL },
};
diff --git a/libavformat/nuv.c b/libavformat/nuv.c
index c9fa38aa5b..001d9c8860 100644
--- a/libavformat/nuv.c
+++ b/libavformat/nuv.c
@@ -2,20 +2,20 @@
* NuppelVideo demuxer.
* Copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -73,7 +73,7 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst,
if (!vst && !myth)
return 1; // no codec data needed
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
int size, subtype;
frametype = avio_r8(pb);
@@ -87,11 +87,8 @@ static int get_codec_data(AVIOContext *pb, AVStream *vst,
av_freep(&vst->codec->extradata);
vst->codec->extradata_size = 0;
}
- vst->codec->extradata = av_malloc(size);
- if (!vst->codec->extradata)
+ if (ff_get_extradata(vst->codec, pb, size) < 0)
return AVERROR(ENOMEM);
- vst->codec->extradata_size = size;
- avio_read(pb, vst->codec->extradata, size);
size = 0;
if (!myth)
return 0;
@@ -200,6 +197,9 @@ static int nuv_header(AVFormatContext *s)
vst->codec->bits_per_coded_sample = 10;
vst->sample_aspect_ratio = av_d2q(aspect * height / width,
10000);
+#if FF_API_R_FRAME_RATE
+ vst->r_frame_rate =
+#endif
vst->avg_frame_rate = av_d2q(fps, 60000);
avpriv_set_pts_info(vst, 32, 1, 1000);
} else
@@ -241,7 +241,7 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt)
nuv_frametype frametype;
int ret, size;
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
int copyhdrsize = ctx->rtjpg_video ? HDRSIZE : 0;
uint64_t pos = avio_tell(pb);
@@ -267,10 +267,9 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt)
ret = av_new_packet(pkt, copyhdrsize + size);
if (ret < 0)
return ret;
- // HACK: we have no idea if it is a keyframe,
- // but if we mark none seeking will not work at all.
- pkt->flags |= AV_PKT_FLAG_KEY;
+
pkt->pos = pos;
+ pkt->flags |= hdr[2] == 0 ? AV_PKT_FLAG_KEY : 0;
pkt->pts = AV_RL32(&hdr[4]);
pkt->stream_index = ctx->v_id;
memcpy(pkt->data, hdr, copyhdrsize);
@@ -308,6 +307,81 @@ static int nuv_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(EIO);
}
+/**
+ * \brief looks for the string RTjjjjjjjjjj in the stream too resync reading
+ * \return 1 if the syncword is found 0 otherwise.
+ */
+static int nuv_resync(AVFormatContext *s, int64_t pos_limit) {
+ AVIOContext *pb = s->pb;
+ uint32_t tag = 0;
+ while(!avio_feof(pb) && avio_tell(pb) < pos_limit) {
+ tag = (tag << 8) | avio_r8(pb);
+ if (tag == MKBETAG('R','T','j','j') &&
+ (tag = avio_rb32(pb)) == MKBETAG('j','j','j','j') &&
+ (tag = avio_rb32(pb)) == MKBETAG('j','j','j','j'))
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * \brief attempts to read a timestamp from stream at the given stream position
+ * \return timestamp if successful and AV_NOPTS_VALUE if failure
+ */
+static int64_t nuv_read_dts(AVFormatContext *s, int stream_index,
+ int64_t *ppos, int64_t pos_limit)
+{
+ NUVContext *ctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ uint8_t hdr[HDRSIZE];
+ nuv_frametype frametype;
+ int size, key, idx;
+ int64_t pos, dts;
+
+ if (avio_seek(pb, *ppos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+
+ if (!nuv_resync(s, pos_limit))
+ return AV_NOPTS_VALUE;
+
+ while (!avio_feof(pb) && avio_tell(pb) < pos_limit) {
+ if (avio_read(pb, hdr, HDRSIZE) < HDRSIZE)
+ return AV_NOPTS_VALUE;
+ frametype = hdr[0];
+ size = PKTSIZE(AV_RL32(&hdr[8]));
+ switch (frametype) {
+ case NUV_SEEKP:
+ break;
+ case NUV_AUDIO:
+ case NUV_VIDEO:
+ if (frametype == NUV_VIDEO) {
+ idx = ctx->v_id;
+ key = hdr[2] == 0;
+ } else {
+ idx = ctx->a_id;
+ key = 1;
+ }
+ if (stream_index == idx) {
+
+ pos = avio_tell(s->pb) - HDRSIZE;
+ dts = AV_RL32(&hdr[4]);
+
+ // TODO - add general support in av_gen_search, so it adds positions after reading timestamps
+ av_add_index_entry(s->streams[stream_index], pos, dts, size + HDRSIZE, 0,
+ key ? AVINDEX_KEYFRAME : 0);
+
+ *ppos = pos;
+ return dts;
+ }
+ default:
+ avio_skip(pb, size);
+ break;
+ }
+ }
+ return AV_NOPTS_VALUE;
+}
+
+
AVInputFormat ff_nuv_demuxer = {
.name = "nuv",
.long_name = NULL_IF_CONFIG_SMALL("NuppelVideo"),
@@ -315,5 +389,6 @@ AVInputFormat ff_nuv_demuxer = {
.read_probe = nuv_probe,
.read_header = nuv_header,
.read_packet = nuv_packet,
+ .read_timestamp = nuv_read_dts,
.flags = AVFMT_GENERIC_INDEX,
};
diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c
index f37c4af826..72d96e829c 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -28,8 +28,9 @@
DEALINGS IN THE SOFTWARE.
*/
-
#include <stdio.h>
+#include "libavutil/avassert.h"
+#include "libavutil/intreadwrite.h"
#include "oggdec.h"
#include "avformat.h"
#include "internal.h"
@@ -57,6 +58,9 @@ static const struct ogg_codec * const ogg_codecs[] = {
NULL
};
+static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
+static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
+
//FIXME We could avoid some structure duplication
static int ogg_save(AVFormatContext *s)
{
@@ -64,8 +68,10 @@ static int ogg_save(AVFormatContext *s)
struct ogg_state *ost =
av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
int i;
+
if (!ost)
return AVERROR(ENOMEM);
+
ost->pos = avio_tell(s->pb);
ost->curidx = ogg->curidx;
ost->next = ogg->state;
@@ -76,6 +82,8 @@ static int ogg_save(AVFormatContext *s)
struct ogg_stream *os = ogg->streams + i;
os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
memcpy(os->buf, ost->streams[i].buf, os->bufpos);
+ os->new_metadata = NULL;
+ os->new_metadata_size = 0;
}
ogg->state = ost;
@@ -98,9 +106,10 @@ static int ogg_restore(AVFormatContext *s, int discard)
if (!discard) {
for (i = 0; i < ogg->nstreams; i++)
- av_free(ogg->streams[i].buf);
+ av_freep(&ogg->streams[i].buf);
avio_seek(bc, ost->pos, SEEK_SET);
+ ogg->page_pos = -1;
ogg->curidx = ost->curidx;
ogg->nstreams = ost->nstreams;
if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
@@ -117,9 +126,11 @@ static int ogg_restore(AVFormatContext *s, int discard)
return 0;
}
-static int ogg_reset(struct ogg *ogg)
+static int ogg_reset(AVFormatContext *s)
{
+ struct ogg *ogg = s->priv_data;
int i;
+ int64_t start_pos = avio_tell(s->pb);
for (i = 0; i < ogg->nstreams; i++) {
struct ogg_stream *os = ogg->streams + i;
@@ -134,8 +145,16 @@ static int ogg_reset(struct ogg *ogg)
os->nsegs = 0;
os->segp = 0;
os->incomplete = 0;
+ os->got_data = 0;
+ if (start_pos <= s->internal->data_offset) {
+ os->lastpts = 0;
+ }
+ os->end_trimming = 0;
+ av_freep(&os->new_metadata);
+ os->new_metadata_size = 0;
}
+ ogg->page_pos = -1;
ogg->curidx = -1;
return 0;
@@ -153,38 +172,105 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
return NULL;
}
-static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
+/**
+ * Replace the current stream with a new one. This is a typical webradio
+ * situation where a new audio stream spawn (identified with a new serial) and
+ * must replace the previous one (track switch).
+ */
+static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
{
struct ogg *ogg = s->priv_data;
- int idx = ogg->nstreams++;
- AVStream *st;
struct ogg_stream *os;
+ const struct ogg_codec *codec;
+ int i = 0;
+
+ if (s->pb->seekable) {
+ uint8_t magic[8];
+ int64_t pos = avio_tell(s->pb);
+ avio_skip(s->pb, nsegs);
+ avio_read(s->pb, magic, sizeof(magic));
+ avio_seek(s->pb, pos, SEEK_SET);
+ codec = ogg_find_codec(magic, sizeof(magic));
+ if (!codec) {
+ av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
+ return AVERROR_INVALIDDATA;
+ }
+ for (i = 0; i < ogg->nstreams; i++) {
+ if (ogg->streams[i].codec == codec)
+ break;
+ }
+ if (i >= ogg->nstreams)
+ return ogg_new_stream(s, serial);
+ } else if (ogg->nstreams != 1) {
+ avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
+ return AVERROR_PATCHWELCOME;
+ }
- os = av_realloc(ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
+ os = &ogg->streams[i];
- if (!os)
- return AVERROR(ENOMEM);
+ os->serial = serial;
+ return i;
- ogg->streams = os;
+#if 0
+ buf = os->buf;
+ bufsize = os->bufsize;
+ codec = os->codec;
+
+ if (!ogg->state || ogg->state->streams[i].private != os->private)
+ av_freep(&ogg->streams[i].private);
- memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
+ /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
+ * also re-use the ogg_stream allocated buffer */
+ memset(os, 0, sizeof(*os));
+ os->serial = serial;
+ os->bufsize = bufsize;
+ os->buf = buf;
+ os->header = -1;
+ os->codec = codec;
+
+ return i;
+#endif
+}
- os = ogg->streams + idx;
+static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
+{
+ struct ogg *ogg = s->priv_data;
+ int idx = ogg->nstreams;
+ AVStream *st;
+ struct ogg_stream *os;
+ size_t size;
+
+ if (ogg->state) {
+ av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
+ "in between Ogg context save/restore operations.\n");
+ return AVERROR_BUG;
+ }
+
+ /* Allocate and init a new Ogg Stream */
+ if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
+ !(os = av_realloc(ogg->streams, size)))
+ return AVERROR(ENOMEM);
+ ogg->streams = os;
+ os = ogg->streams + idx;
+ memset(os, 0, sizeof(*os));
os->serial = serial;
os->bufsize = DECODER_BUFFER_SIZE;
os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
os->header = -1;
os->start_granule = OGG_NOGRANULE_VALUE;
+ if (!os->buf)
+ return AVERROR(ENOMEM);
- if (new_avstream) {
- st = avformat_new_stream(s, NULL);
- if (!st)
- return AVERROR(ENOMEM);
-
- st->id = idx;
- avpriv_set_pts_info(st, 64, 1, 1000000);
+ /* Create the associated AVStream */
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ av_freep(&os->buf);
+ return AVERROR(ENOMEM);
}
+ st->id = idx;
+ avpriv_set_pts_info(st, 64, 1, 1000000);
+ ogg->nstreams++;
return idx;
}
@@ -209,7 +295,17 @@ static int ogg_new_buf(struct ogg *ogg, int idx)
return 0;
}
-static int ogg_read_page(AVFormatContext *s, int *str)
+static int data_packets_seen(const struct ogg *ogg)
+{
+ int i;
+
+ for (i = 0; i < ogg->nstreams; i++)
+ if (ogg->streams[i].got_data)
+ return 1;
+ return 0;
+}
+
+static int ogg_read_page(AVFormatContext *s, int *sid)
{
AVIOContext *bc = s->pb;
struct ogg *ogg = s->priv_data;
@@ -234,9 +330,15 @@ static int ogg_read_page(AVFormatContext *s, int *str)
sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
break;
+ if(!i && bc->seekable && ogg->page_pos > 0) {
+ memset(sync, 0, 4);
+ avio_seek(bc, ogg->page_pos+4, SEEK_SET);
+ ogg->page_pos = -1;
+ }
+
c = avio_r8(bc);
- if (bc->eof_reached)
+ if (avio_feof(bc))
return AVERROR_EOF;
sync[sp++ & 3] = c;
@@ -247,8 +349,10 @@ static int ogg_read_page(AVFormatContext *s, int *str)
return AVERROR_INVALIDDATA;
}
- if (avio_r8(bc) != 0) /* version */
+ if (avio_r8(bc) != 0) { /* version */
+ av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
return AVERROR_INVALIDDATA;
+ }
flags = avio_r8(bc);
gp = avio_rl64(bc);
@@ -258,28 +362,19 @@ static int ogg_read_page(AVFormatContext *s, int *str)
idx = ogg_find_stream(ogg, serial);
if (idx < 0) {
- if (ogg->headers) {
- int n;
-
- for (n = 0; n < ogg->nstreams; n++) {
- av_freep(&ogg->streams[n].buf);
- if (!ogg->state ||
- ogg->state->streams[n].private != ogg->streams[n].private)
- av_freep(&ogg->streams[n].private);
- }
+ if (data_packets_seen(ogg))
+ idx = ogg_replace_stream(s, serial, nsegs);
+ else
+ idx = ogg_new_stream(s, serial);
- ogg->curidx = -1;
- ogg->nstreams = 0;
-
- idx = ogg_new_stream(s, serial, 0);
- } else {
- idx = ogg_new_stream(s, serial, 1);
- }
- if (idx < 0)
+ if (idx < 0) {
+ av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
return idx;
+ }
}
os = ogg->streams + idx;
+ ogg->page_pos =
os->page_pos = avio_tell(bc) - 27;
if (os->psize > 0) {
@@ -299,8 +394,14 @@ static int ogg_read_page(AVFormatContext *s, int *str)
for (i = 0; i < nsegs; i++)
size += os->segments[i];
+ if (!(flags & OGG_FLAG_BOS))
+ os->got_data = 1;
+
if (flags & OGG_FLAG_CONT || os->incomplete) {
if (!os->psize) {
+ // If this is the very first segment we started
+ // playback in the middle of a continuation packet.
+ // Discard it since we missed the start of it.
while (os->segp < os->nsegs) {
int seg = os->segments[os->segp++];
os->pstart += seg;
@@ -332,13 +433,20 @@ static int ogg_read_page(AVFormatContext *s, int *str)
os->flags = flags;
memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- if (str)
- *str = idx;
+ if (sid)
+ *sid = idx;
return 0;
}
-static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
+/**
+ * @brief find the next Ogg packet
+ * @param *sid is set to the stream for the packet or -1 if there is
+ * no matching stream, in that case assume all other return
+ * values to be uninitialized.
+ * @return negative value on error or EOF.
+ */
+static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
int64_t *fpos)
{
struct ogg *ogg = s->priv_data;
@@ -348,6 +456,8 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
int segp = 0, psize = 0;
av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
+ if (sid)
+ *sid = -1;
do {
idx = ogg->curidx;
@@ -398,8 +508,6 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
}
} while (!complete);
- av_log(s, AV_LOG_TRACE, "ogg_packet: idx %i, frame size %i, start %i\n",
- idx, os->psize, os->pstart);
if (os->granule == -1)
av_log(s, AV_LOG_WARNING,
@@ -443,8 +551,8 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
os->pduration = 0;
if (os->codec && os->codec->packet)
os->codec->packet(s, idx);
- if (str)
- *str = idx;
+ if (sid)
+ *sid = idx;
if (dstart)
*dstart = os->pstart;
if (dsize)
@@ -453,6 +561,8 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
*fpos = os->sync_pos;
os->pstart += os->psize;
os->psize = 0;
+ if(os->pstart == os->bufpos)
+ os->bufpos = os->pstart = 0;
os->sync_pos = os->page_pos;
}
@@ -471,43 +581,12 @@ static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
return 0;
}
-static int ogg_get_headers(AVFormatContext *s)
-{
- struct ogg *ogg = s->priv_data;
- int ret, i;
-
- do {
- ret = ogg_packet(s, NULL, NULL, NULL, NULL);
- if (ret < 0)
- return ret;
- } while (!ogg->headers);
-
- for (i = 0; i < ogg->nstreams; i++) {
- struct ogg_stream *os = ogg->streams + i;
-
- if (os->codec && os->codec->nb_header &&
- os->nb_header < os->codec->nb_header) {
- av_log(s, AV_LOG_ERROR,
- "Headers mismatch for stream %d: "
- "expected %d received %d.\n",
- i, os->codec->nb_header, os->nb_header);
- if (s->error_recognition & AV_EF_EXPLODE)
- return AVERROR_INVALIDDATA;
- }
- if (os->start_granule != OGG_NOGRANULE_VALUE)
- os->lastpts = s->streams[i]->start_time =
- ogg_gptopts(s, i, os->start_granule, NULL);
- }
- av_log(s, AV_LOG_TRACE, "found headers\n");
-
- return 0;
-}
-
static int ogg_get_length(AVFormatContext *s)
{
struct ogg *ogg = s->priv_data;
int i, ret;
int64_t size, end;
+ int streams_left=0;
if (!s->pb->seekable)
return 0;
@@ -525,19 +604,47 @@ static int ogg_get_length(AVFormatContext *s)
if (ret < 0)
return ret;
avio_seek(s->pb, end, SEEK_SET);
+ ogg->page_pos = -1;
while (!ogg_read_page(s, &i)) {
if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
ogg->streams[i].codec) {
s->streams[i]->duration =
ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
- if (s->streams[i]->start_time != AV_NOPTS_VALUE)
+ if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
s->streams[i]->duration -= s->streams[i]->start_time;
+ streams_left-= (ogg->streams[i].got_start==-1);
+ ogg->streams[i].got_start= 1;
+ } else if(!ogg->streams[i].got_start) {
+ ogg->streams[i].got_start= -1;
+ streams_left++;
+ }
}
}
ogg_restore(s, 0);
+ ret = ogg_save(s);
+ if (ret < 0)
+ return ret;
+
+ avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
+ ogg_reset(s);
+ while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
+ int64_t pts;
+ if (i < 0) continue;
+ pts = ogg_calc_pts(s, i, NULL);
+ if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
+ s->streams[i]->duration -= pts;
+ ogg->streams[i].got_start= 1;
+ streams_left--;
+ }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
+ ogg->streams[i].got_start= 1;
+ streams_left--;
+ }
+ }
+ ogg_restore (s, 0);
+
return 0;
}
@@ -547,14 +654,18 @@ static int ogg_read_close(AVFormatContext *s)
int i;
for (i = 0; i < ogg->nstreams; i++) {
- av_free(ogg->streams[i].buf);
+ av_freep(&ogg->streams[i].buf);
if (ogg->streams[i].codec &&
ogg->streams[i].codec->cleanup) {
ogg->streams[i].codec->cleanup(s, i);
}
- av_free(ogg->streams[i].private);
+ av_freep(&ogg->streams[i].private);
+ av_freep(&ogg->streams[i].new_metadata);
}
- av_free(ogg->streams);
+
+ ogg->nstreams = 0;
+
+ av_freep(&ogg->streams);
return 0;
}
@@ -562,17 +673,37 @@ static int ogg_read_header(AVFormatContext *s)
{
struct ogg *ogg = s->priv_data;
int ret, i;
+
ogg->curidx = -1;
+
//linear headers seek from start
- ret = ogg_get_headers(s);
- if (ret < 0) {
- ogg_read_close(s);
- return ret;
- }
+ do {
+ ret = ogg_packet(s, NULL, NULL, NULL, NULL);
+ if (ret < 0) {
+ ogg_read_close(s);
+ return ret;
+ }
+ } while (!ogg->headers);
+ av_log(s, AV_LOG_TRACE, "found headers\n");
- for (i = 0; i < ogg->nstreams; i++)
- if (ogg->streams[i].header < 0)
+ for (i = 0; i < ogg->nstreams; i++) {
+ struct ogg_stream *os = ogg->streams + i;
+
+ if (ogg->streams[i].header < 0) {
+ av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
ogg->streams[i].codec = NULL;
+ } else if (os->codec && os->nb_header < os->codec->nb_header) {
+ av_log(s, AV_LOG_WARNING,
+ "Headers mismatch for stream %d: "
+ "expected %d received %d.\n",
+ i, os->codec->nb_header, os->nb_header);
+ if (s->error_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
+ }
+ if (os->start_granule != OGG_NOGRANULE_VALUE)
+ os->lastpts = s->streams[i]->start_time =
+ ogg_gptopts(s, i, os->start_granule, NULL);
+ }
//linear granulepos seek from end
ret = ogg_get_length(s);
@@ -581,7 +712,6 @@ static int ogg_read_header(AVFormatContext *s)
return ret;
}
- //fill the extradata in the per codec callbacks
return 0;
}
@@ -615,14 +745,40 @@ static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
return pts;
}
+static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+ int invalid = 0;
+ if (psize) {
+ switch (s->streams[idx]->codec->codec_id) {
+ case AV_CODEC_ID_THEORA:
+ invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
+ break;
+ case AV_CODEC_ID_VP8:
+ invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
+ }
+ if (invalid) {
+ os->pflags ^= AV_PKT_FLAG_KEY;
+ av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
+ (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
+ }
+ }
+}
+
static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
{
struct ogg *ogg;
struct ogg_stream *os;
- int idx = -1, ret;
+ int idx, ret;
int pstart, psize;
int64_t fpos, pts, dts;
+ if (s->io_repositioned) {
+ ogg_reset(s);
+ s->io_repositioned = 0;
+ }
+
//Get an ogg packet
retry:
do {
@@ -636,6 +792,7 @@ retry:
// pflags might not be set until after this
pts = ogg_calc_pts(s, idx, &dts);
+ ogg_validate_keyframe(s, idx, pstart, psize);
if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
goto retry;
@@ -654,7 +811,32 @@ retry:
pkt->duration = os->pduration;
pkt->pos = fpos;
+ if (os->end_trimming) {
+ uint8_t *side_data = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_SKIP_SAMPLES,
+ 10);
+ if(!side_data)
+ goto fail;
+ AV_WL32(side_data + 4, os->end_trimming);
+ os->end_trimming = 0;
+ }
+
+ if (os->new_metadata) {
+ uint8_t *side_data = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_METADATA_UPDATE,
+ os->new_metadata_size);
+ if(!side_data)
+ goto fail;
+
+ memcpy(side_data, os->new_metadata, os->new_metadata_size);
+ av_freep(&os->new_metadata);
+ os->new_metadata_size = 0;
+ }
+
return psize;
+fail:
+ av_free_packet(pkt);
+ return AVERROR(ENOMEM);
}
static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
@@ -663,22 +845,38 @@ static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
struct ogg *ogg = s->priv_data;
AVIOContext *bc = s->pb;
int64_t pts = AV_NOPTS_VALUE;
- int i = -1;
+ int64_t keypos = -1;
+ int i;
+ int pstart, psize;
avio_seek(bc, *pos_arg, SEEK_SET);
- ogg_reset(ogg);
+ ogg_reset(s);
- while (avio_tell(bc) < pos_limit &&
- !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
+ while ( avio_tell(bc) <= pos_limit
+ && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
if (i == stream_index) {
struct ogg_stream *os = ogg->streams + stream_index;
+ // Do not trust the last timestamps of a ogm video
+ if ( (os->flags & OGG_FLAG_EOS)
+ && !(os->flags & OGG_FLAG_BOS)
+ && os->codec == &ff_ogm_video_codec)
+ continue;
pts = ogg_calc_pts(s, i, NULL);
- if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
- pts = AV_NOPTS_VALUE;
+ ogg_validate_keyframe(s, i, pstart, psize);
+ if (os->pflags & AV_PKT_FLAG_KEY) {
+ keypos = *pos_arg;
+ } else if (os->keyframe_seek) {
+ // if we had a previous keyframe but no pts for it,
+ // return that keyframe with this pts value.
+ if (keypos >= 0)
+ *pos_arg = keypos;
+ else
+ pts = AV_NOPTS_VALUE;
+ }
}
if (pts != AV_NOPTS_VALUE)
break;
}
- ogg_reset(ogg);
+ ogg_reset(s);
return pts;
}
@@ -689,6 +887,11 @@ static int ogg_read_seek(AVFormatContext *s, int stream_index,
struct ogg_stream *os = ogg->streams + stream_index;
int ret;
+ av_assert0(stream_index < ogg->nstreams);
+ // Ensure everything is reset even when seeking via
+ // the generated index.
+ ogg_reset(s);
+
// Try seeking to a keyframe first. If this fails (very possible),
// av_seek_frame will fall back to ignoring keyframes
if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
@@ -720,5 +923,5 @@ AVInputFormat ff_ogg_demuxer = {
.read_seek = ogg_read_seek,
.read_timestamp = ogg_read_timestamp,
.extensions = "ogg",
- .flags = AVFMT_GENERIC_INDEX | AVFMT_NOBINSEARCH,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
};
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index 807ac4a316..7dc7716036 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -81,7 +81,12 @@ struct ogg_stream {
int incomplete; ///< whether we're expecting a continuation in the next page
int page_end; ///< current packet is the last one completed in the page
int keyframe_seek;
+ int got_start;
+ int got_data; ///< 1 if the stream got some data (non-initial packets), 0 otherwise
int nb_header; ///< set to the number of parsed headers
+ int end_trimming; ///< set the number of packets to drop from the end
+ uint8_t *new_metadata;
+ unsigned int new_metadata_size;
void *private;
};
@@ -98,6 +103,7 @@ struct ogg {
int nstreams;
int headers;
int curidx;
+ int64_t page_pos; ///< file offset of the current page
struct ogg_state *state;
};
@@ -105,7 +111,7 @@ struct ogg {
#define OGG_FLAG_BOS 2
#define OGG_FLAG_EOS 4
-#define OGG_NOGRANULE_VALUE -1ull
+#define OGG_NOGRANULE_VALUE (-1ull)
extern const struct ogg_codec ff_celt_codec;
extern const struct ogg_codec ff_dirac_codec;
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index 8f8a08f1bd..873dfacbf6 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -2,20 +2,20 @@
* Ogg muxer
* Copyright (c) 2007 Baptiste Coudurier <baptiste dot coudurier at free dot fr>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -80,6 +80,8 @@ typedef struct OGGContext {
static const AVOption options[] = {
{ "serial_offset", "serial number offset",
OFFSET(serial_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, PARAM },
+ { "oggpagesize", "Set preferred Ogg page size.",
+ OFFSET(pref_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, MAX_PAGE_SIZE, PARAM},
{ "pagesize", "preferred page size in bytes (deprecated)",
OFFSET(pref_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_PAGE_SIZE, PARAM },
{ "page_duration", "preferred page duration, in microseconds",
@@ -87,9 +89,9 @@ static const AVOption options[] = {
{ NULL },
};
-#define OGG_CLASS(flavor)\
+#define OGG_CLASS(flavor, name)\
static const AVClass flavor ## _muxer_class = {\
- .class_name = #flavor " muxer",\
+ .class_name = #name " muxer",\
.item_name = av_default_item_name,\
.option = options,\
.version = LIBAVUTIL_VERSION_INT,\
@@ -142,6 +144,11 @@ static int ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags)
return 0;
}
+static int ogg_key_granule(OGGStreamContext *oggstream, int64_t granule)
+{
+ return oggstream->kfgshift && !(granule & ((1<<oggstream->kfgshift)-1));
+}
+
static int64_t ogg_granule_to_timestamp(OGGStreamContext *oggstream, int64_t granule)
{
if (oggstream->kfgshift)
@@ -212,9 +219,14 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
int i, segments, len, flush = 0;
// Handles VFR by flushing page because this frame needs to have a timestamp
+ // For theora, keyframes also need to have a timestamp to correctly mark
+ // them as such, otherwise seeking will not work correctly at the very
+ // least with old libogg versions.
+ // Do not try to flush header packets though, that will create broken files.
if (st->codec->codec_id == AV_CODEC_ID_THEORA && !header &&
- ogg_granule_to_timestamp(oggstream, granule) >
- ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1) {
+ (ogg_granule_to_timestamp(oggstream, granule) >
+ ogg_granule_to_timestamp(oggstream, oggstream->last_granule) + 1 ||
+ ogg_key_granule(oggstream, granule))) {
if (oggstream->page.granule != -1)
ogg_buffer_page(s, oggstream);
flush = 1;
@@ -270,16 +282,18 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st,
return 0;
}
-static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
+static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact,
int *header_len, AVDictionary **m, int framing_bit)
{
- const char *vendor = bitexact ? "Libav" : LIBAVFORMAT_IDENT;
- int size;
+ const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
+ int64_t size;
uint8_t *p, *p0;
ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL);
size = offset + ff_vorbiscomment_length(*m, vendor) + framing_bit;
+ if (size > INT_MAX)
+ return NULL;
p = av_mallocz(size);
if (!p)
return NULL;
@@ -339,7 +353,7 @@ static int ogg_build_speex_headers(AVCodecContext *avctx,
uint8_t *p;
if (avctx->extradata_size < SPEEX_HEADER_SIZE)
- return -1;
+ return AVERROR_INVALIDDATA;
// first packet: Speex header
p = av_mallocz(SPEEX_HEADER_SIZE);
@@ -368,7 +382,7 @@ static int ogg_build_opus_headers(AVCodecContext *avctx,
uint8_t *p;
if (avctx->extradata_size < OPUS_HEADER_SIZE)
- return -1;
+ return AVERROR_INVALIDDATA;
/* first packet: Opus header */
p = av_mallocz(avctx->extradata_size);
@@ -413,7 +427,7 @@ static void ogg_write_pages(AVFormatContext *s, int flush)
static int ogg_write_header(AVFormatContext *s)
{
OGGContext *ogg = s->priv_data;
- OGGStreamContext *oggstream;
+ OGGStreamContext *oggstream = NULL;
int i, j;
if (ogg->pref_size)
@@ -423,12 +437,13 @@ static int ogg_write_header(AVFormatContext *s)
AVStream *st = s->streams[i];
unsigned serial_num = i + ogg->serial_offset;
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (st->codec->codec_id == AV_CODEC_ID_OPUS)
/* Opus requires a fixed 48kHz clock */
avpriv_set_pts_info(st, 64, 1, 48000);
else
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ }
if (st->codec->codec_id != AV_CODEC_ID_VORBIS &&
st->codec->codec_id != AV_CODEC_ID_THEORA &&
@@ -436,16 +451,17 @@ static int ogg_write_header(AVFormatContext *s)
st->codec->codec_id != AV_CODEC_ID_FLAC &&
st->codec->codec_id != AV_CODEC_ID_OPUS) {
av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i);
- return -1;
+ return AVERROR(EINVAL);
}
if (!st->codec->extradata || !st->codec->extradata_size) {
av_log(s, AV_LOG_ERROR, "No extradata present\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
oggstream = av_mallocz(sizeof(*oggstream));
if (!oggstream)
return AVERROR(ENOMEM);
+
oggstream->page.stream_index = i;
if (!(s->flags & AVFMT_FLAG_BITEXACT))
@@ -459,11 +475,13 @@ static int ogg_write_header(AVFormatContext *s)
} while (j < i);
oggstream->serial_num = serial_num;
+ av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE);
+
st->priv_data = oggstream;
if (st->codec->codec_id == AV_CODEC_ID_FLAC) {
int err = ogg_build_flac_headers(st->codec, oggstream,
s->flags & AVFMT_FLAG_BITEXACT,
- &s->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing FLAC headers\n");
av_freep(&st->priv_data);
@@ -472,7 +490,7 @@ static int ogg_write_header(AVFormatContext *s)
} else if (st->codec->codec_id == AV_CODEC_ID_SPEEX) {
int err = ogg_build_speex_headers(st->codec, oggstream,
s->flags & AVFMT_FLAG_BITEXACT,
- &s->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
av_freep(&st->priv_data);
@@ -481,7 +499,7 @@ static int ogg_write_header(AVFormatContext *s)
} else if (st->codec->codec_id == AV_CODEC_ID_OPUS) {
int err = ogg_build_opus_headers(st->codec, oggstream,
s->flags & AVFMT_FLAG_BITEXACT,
- &s->metadata);
+ &st->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
av_freep(&st->priv_data);
@@ -495,14 +513,14 @@ static int ogg_write_header(AVFormatContext *s)
if (avpriv_split_xiph_headers(st->codec->extradata, st->codec->extradata_size,
st->codec->codec_id == AV_CODEC_ID_VORBIS ? 30 : 42,
- oggstream->header, oggstream->header_len) < 0) {
+ (const uint8_t**)oggstream->header, oggstream->header_len) < 0) {
av_log(s, AV_LOG_ERROR, "Extradata corrupted\n");
av_freep(&st->priv_data);
- return -1;
+ return AVERROR_INVALIDDATA;
}
p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT,
- &oggstream->header_len[1], &s->metadata,
+ &oggstream->header_len[1], &st->metadata,
framing_bit);
oggstream->header[1] = p;
if (!p)
@@ -625,7 +643,7 @@ static int ogg_write_trailer(AVFormatContext *s)
if (st->codec->codec_id == AV_CODEC_ID_FLAC ||
st->codec->codec_id == AV_CODEC_ID_SPEEX ||
st->codec->codec_id == AV_CODEC_ID_OPUS) {
- av_free(oggstream->header[0]);
+ av_freep(&oggstream->header[0]);
}
av_freep(&oggstream->header[1]);
av_freep(&st->priv_data);
@@ -634,12 +652,19 @@ static int ogg_write_trailer(AVFormatContext *s)
}
#if CONFIG_OGG_MUXER
-OGG_CLASS(ogg)
+OGG_CLASS(ogg, Ogg)
AVOutputFormat ff_ogg_muxer = {
.name = "ogg",
.long_name = NULL_IF_CONFIG_SMALL("Ogg"),
.mime_type = "application/ogg",
- .extensions = "ogg,ogv",
+ .extensions = "ogg,ogv"
+#if !CONFIG_SPX_MUXER
+ ",spx"
+#endif
+#if !CONFIG_OPUS_MUXER
+ ",opus"
+#endif
+ ,
.priv_data_size = sizeof(OGGContext),
.audio_codec = CONFIG_LIBVORBIS_ENCODER ?
AV_CODEC_ID_VORBIS : AV_CODEC_ID_FLAC,
@@ -653,7 +678,7 @@ AVOutputFormat ff_ogg_muxer = {
#endif
#if CONFIG_OGA_MUXER
-OGG_CLASS(oga)
+OGG_CLASS(oga, Ogg audio)
AVOutputFormat ff_oga_muxer = {
.name = "oga",
.long_name = NULL_IF_CONFIG_SMALL("Ogg Audio"),
@@ -671,7 +696,7 @@ AVOutputFormat ff_oga_muxer = {
#endif
#if CONFIG_SPX_MUXER
-OGG_CLASS(spx)
+OGG_CLASS(spx, Ogg Speex)
AVOutputFormat ff_spx_muxer = {
.name = "spx",
.long_name = NULL_IF_CONFIG_SMALL("Ogg Speex"),
@@ -688,7 +713,7 @@ AVOutputFormat ff_spx_muxer = {
#endif
#if CONFIG_OPUS_MUXER
-OGG_CLASS(opus)
+OGG_CLASS(opus, Ogg Opus)
AVOutputFormat ff_opus_muxer = {
.name = "opus",
.long_name = NULL_IF_CONFIG_SMALL("Ogg Opus"),
diff --git a/libavformat/oggparsecelt.c b/libavformat/oggparsecelt.c
index 7084e768a3..2c0c511c7b 100644
--- a/libavformat/oggparsecelt.c
+++ b/libavformat/oggparsecelt.c
@@ -1,21 +1,21 @@
/*
- * Xiph CELT / Opus parser for Ogg
+ * Xiph CELT parser for Ogg
* Copyright (c) 2011 Nicolas George
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,13 +44,11 @@ static int celt_header(AVFormatContext *s, int idx)
uint32_t version, sample_rate, nb_channels;
uint32_t overlap, extra_headers;
- uint8_t *extradata;
- extradata = av_malloc(2 * sizeof(uint32_t) +
- FF_INPUT_BUFFER_PADDING_SIZE);
priv = av_malloc(sizeof(struct oggcelt_private));
- if (!extradata || !priv) {
- av_free(extradata);
+ if (!priv)
+ return AVERROR(ENOMEM);
+ if (ff_alloc_extradata(st->codec, 2 * sizeof(uint32_t)) < 0) {
av_free(priv);
return AVERROR(ENOMEM);
}
@@ -61,20 +59,17 @@ static int celt_header(AVFormatContext *s, int idx)
overlap = AV_RL32(p + 48);
/* unused bytes per packet field skipped */
extra_headers = AV_RL32(p + 56);
- av_free(os->private);
- av_free(st->codec->extradata);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_CELT;
st->codec->sample_rate = sample_rate;
st->codec->channels = nb_channels;
- st->codec->extradata = extradata;
- st->codec->extradata_size = 2 * sizeof(uint32_t);
if (sample_rate)
avpriv_set_pts_info(st, 64, 1, sample_rate);
priv->extra_headers_left = 1 + extra_headers;
+ av_free(os->private);
os->private = priv;
- AV_WL32(extradata + 0, overlap);
- AV_WL32(extradata + 4, version);
+ AV_WL32(st->codec->extradata + 0, overlap);
+ AV_WL32(st->codec->extradata + 4, version);
return 1;
} else if (priv && priv->extra_headers_left) {
/* Extra headers (vorbiscomment) */
diff --git a/libavformat/oggparsedirac.c b/libavformat/oggparsedirac.c
index 55a0b59127..10fb07e92d 100644
--- a/libavformat/oggparsedirac.c
+++ b/libavformat/oggparsedirac.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2008 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,7 +43,7 @@ static int dirac_header(AVFormatContext *s, int idx)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_DIRAC;
// dirac in ogg always stores timestamps as though the video were interlaced
- avpriv_set_pts_info(st, 64, st->codec->time_base.num, 2*st->codec->time_base.den);
+ avpriv_set_pts_info(st, 64, st->codec->framerate.den, 2*st->codec->framerate.num);
return 1;
}
diff --git a/libavformat/oggparseflac.c b/libavformat/oggparseflac.c
index 57bba68079..c7fb44618d 100644
--- a/libavformat/oggparseflac.c
+++ b/libavformat/oggparseflac.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2005 Matthieu CASTET
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,10 +61,9 @@ flac_header (AVFormatContext * s, int idx)
st->codec->codec_id = AV_CODEC_ID_FLAC;
st->need_parsing = AVSTREAM_PARSE_HEADERS;
- st->codec->extradata =
- av_malloc(FLAC_STREAMINFO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
- memcpy(st->codec->extradata, streaminfo_start, FLAC_STREAMINFO_SIZE);
- st->codec->extradata_size = FLAC_STREAMINFO_SIZE;
+ if (ff_alloc_extradata(st->codec, FLAC_STREAMINFO_SIZE) < 0)
+ return AVERROR(ENOMEM);
+ memcpy(st->codec->extradata, streaminfo_start, st->codec->extradata_size);
samplerate = AV_RB24(st->codec->extradata + 10) >> 4;
if (!samplerate)
@@ -81,11 +80,32 @@ flac_header (AVFormatContext * s, int idx)
static int
old_flac_header (AVFormatContext * s, int idx)
{
+ struct ogg *ogg = s->priv_data;
AVStream *st = s->streams[idx];
+ struct ogg_stream *os = ogg->streams + idx;
+ AVCodecParserContext *parser = av_parser_init(AV_CODEC_ID_FLAC);
+ int size;
+ uint8_t *data;
+
+ if (!parser)
+ return -1;
+
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_FLAC;
- return 0;
+ parser->flags = PARSER_FLAG_COMPLETE_FRAMES;
+ av_parser_parse2(parser, st->codec,
+ &data, &size, os->buf + os->pstart, os->psize,
+ AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1);
+
+ av_parser_close(parser);
+
+ if (st->codec->sample_rate) {
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ return 0;
+ }
+
+ return 1;
}
const struct ogg_codec ff_flac_codec = {
diff --git a/libavformat/oggparseogm.c b/libavformat/oggparseogm.c
index 913282ab36..54024e0a0a 100644
--- a/libavformat/oggparseogm.c
+++ b/libavformat/oggparseogm.c
@@ -23,6 +23,7 @@
**/
#include <stdlib.h>
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/get_bits.h"
#include "libavcodec/bytestream.h"
@@ -40,6 +41,7 @@ ogm_header(AVFormatContext *s, int idx)
GetByteContext p;
uint64_t time_unit;
uint64_t spu;
+ uint32_t size;
bytestream2_init(&p, os->buf + os->pstart, os->psize);
if (!(bytestream2_peek_byte(&p) & 1))
@@ -68,11 +70,13 @@ ogm_header(AVFormatContext *s, int idx)
acid[4] = 0;
cid = strtol(acid, NULL, 16);
st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, cid);
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ // our parser completely breaks AAC in Ogg
+ if (st->codec->codec_id != AV_CODEC_ID_AAC)
+ st->need_parsing = AVSTREAM_PARSE_FULL;
}
- bytestream2_skip(&p, 4); /* useless size field */
-
+ size = bytestream2_get_le32(&p);
+ size = FFMIN(size, os->psize);
time_unit = bytestream2_get_le64(&p);
spu = bytestream2_get_le64(&p);
if (!time_unit || !spu) {
@@ -93,6 +97,16 @@ ogm_header(AVFormatContext *s, int idx)
st->codec->bit_rate = bytestream2_get_le32(&p) * 8;
st->codec->sample_rate = spu * 10000000 / time_unit;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ if (size >= 56 && st->codec->codec_id == AV_CODEC_ID_AAC) {
+ bytestream2_skip(&p, 4);
+ size -= 4;
+ }
+ if (size > 52) {
+ av_assert0(FF_INPUT_BUFFER_PADDING_SIZE <= 52);
+ size -= 52;
+ ff_alloc_extradata(st->codec, size);
+ bytestream2_get_buffer(&p, st->codec->extradata, st->codec->extradata_size);
+ }
}
} else if (bytestream2_peek_byte(&p) == 3) {
bytestream2_skip(&p, 7);
@@ -117,15 +131,23 @@ ogm_dshow_header(AVFormatContext *s, int idx)
if(*p != 1)
return 1;
+ if (os->psize < 100)
+ return AVERROR_INVALIDDATA;
t = AV_RL32(p + 96);
if(t == 0x05589f80){
+ if (os->psize < 184)
+ return AVERROR_INVALIDDATA;
+
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(p + 68));
avpriv_set_pts_info(st, 64, AV_RL64(p + 164), 10000000);
st->codec->width = AV_RL32(p + 176);
st->codec->height = AV_RL32(p + 180);
} else if(t == 0x05589f81){
+ if (os->psize < 136)
+ return AVERROR_INVALIDDATA;
+
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, AV_RL16(p + 124));
st->codec->channels = AV_RL16(p + 126);
diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c
index 5931ab543b..c8b02fab4d 100644
--- a/libavformat/oggparseopus.c
+++ b/libavformat/oggparseopus.c
@@ -2,20 +2,20 @@
* Opus parser for Ogg
* Copyright (c) 2012 Nicolas George
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,7 @@ struct oggopus_private {
int64_t cur_dts;
};
+#define OPUS_SEEK_PREROLL_MS 80
#define OPUS_HEAD_SIZE 19
static int opus_header(AVFormatContext *avf, int idx)
@@ -41,31 +42,34 @@ static int opus_header(AVFormatContext *avf, int idx)
AVStream *st = avf->streams[idx];
struct oggopus_private *priv = os->private;
uint8_t *packet = os->buf + os->pstart;
- uint8_t *extradata;
if (!priv) {
priv = os->private = av_mallocz(sizeof(*priv));
if (!priv)
return AVERROR(ENOMEM);
}
+
if (os->flags & OGG_FLAG_BOS) {
if (os->psize < OPUS_HEAD_SIZE || (AV_RL8(packet + 8) & 0xF0) != 0)
return AVERROR_INVALIDDATA;
-
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_OPUS;
- st->codec->channels = AV_RL8(packet + 9);
+ st->codec->channels = AV_RL8 (packet + 9);
priv->pre_skip = AV_RL16(packet + 10);
+ st->codec->delay = priv->pre_skip;
+ /*orig_sample_rate = AV_RL32(packet + 12);*/
+ /*gain = AV_RL16(packet + 16);*/
+ /*channel_map = AV_RL8 (packet + 18);*/
- extradata = av_malloc(os->psize + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!extradata)
+ if (ff_alloc_extradata(st->codec, os->psize))
return AVERROR(ENOMEM);
- memcpy(extradata, packet, os->psize);
- st->codec->extradata = extradata;
- st->codec->extradata_size = os->psize;
+ memcpy(st->codec->extradata, packet, os->psize);
st->codec->sample_rate = 48000;
+ av_codec_set_seek_preroll(st->codec,
+ av_rescale(OPUS_SEEK_PREROLL_MS,
+ st->codec->sample_rate, 1000));
avpriv_set_pts_info(st, 64, 1, 48000);
priv->need_comments = 1;
return 1;
@@ -82,6 +86,26 @@ static int opus_header(AVFormatContext *avf, int idx)
return 0;
}
+static int opus_duration(uint8_t *src, int size)
+{
+ unsigned nb_frames = 1;
+ unsigned toc = src[0];
+ unsigned toc_config = toc >> 3;
+ unsigned toc_count = toc & 3;
+ unsigned frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
+ toc_config < 16 ? 480 << (toc_config & 1) :
+ 120 << (toc_config & 3);
+ if (toc_count == 3) {
+ if (size<2)
+ return AVERROR_INVALIDDATA;
+ nb_frames = src[1] & 0x3F;
+ } else if (toc_count) {
+ nb_frames = 2;
+ }
+
+ return frame_size * nb_frames;
+}
+
static int opus_packet(AVFormatContext *avf, int idx)
{
struct ogg *ogg = avf->priv_data;
@@ -89,26 +113,43 @@ static int opus_packet(AVFormatContext *avf, int idx)
AVStream *st = avf->streams[idx];
struct oggopus_private *priv = os->private;
uint8_t *packet = os->buf + os->pstart;
- unsigned toc, toc_config, toc_count, frame_size, nb_frames = 1;
+ int ret;
if (!os->psize)
return AVERROR_INVALIDDATA;
- toc = *packet;
- toc_config = toc >> 3;
- toc_count = toc & 3;
- frame_size = toc_config < 12 ? FFMAX(480, 960 * (toc_config & 3)) :
- toc_config < 16 ? 480 << (toc_config & 1) :
- 120 << (toc_config & 3);
- if (toc_count == 3) {
- if (os->psize < 2)
- return AVERROR_INVALIDDATA;
- nb_frames = packet[1] & 0x3F;
- } else if (toc_count) {
- nb_frames = 2;
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ int seg, d;
+ int duration;
+ uint8_t *last_pkt = os->buf + os->pstart;
+ uint8_t *next_pkt = last_pkt;
+
+ duration = 0;
+ seg = os->segp;
+ d = opus_duration(last_pkt, os->psize);
+ if (d < 0) {
+ os->pflags |= AV_PKT_FLAG_CORRUPT;
+ return 0;
+ }
+ duration += d;
+ last_pkt = next_pkt = next_pkt + os->psize;
+ for (; seg < os->nsegs; seg++) {
+ next_pkt += os->segments[seg];
+ if (os->segments[seg] < 255 && next_pkt != last_pkt) {
+ int d = opus_duration(last_pkt, next_pkt - last_pkt);
+ if (d > 0)
+ duration += d;
+ last_pkt = next_pkt;
+ }
+ }
+ os->lastpts =
+ os->lastdts = os->granule - duration;
}
- os->pduration = frame_size * nb_frames;
+ if ((ret = opus_duration(packet, os->psize)) < 0)
+ return ret;
+
+ os->pduration = ret;
if (os->lastpts != AV_NOPTS_VALUE) {
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = os->lastpts;
@@ -121,10 +162,10 @@ static int opus_packet(AVFormatContext *avf, int idx)
skip = FFMIN(skip, os->pduration);
if (skip > 0) {
os->pduration = skip < os->pduration ? os->pduration - skip : 1;
- av_log(avf, AV_LOG_WARNING,
- "Last packet is truncated to %d (because of unimplemented end trim support).\n",
+ os->end_trimming = skip;
+ av_log(avf, AV_LOG_DEBUG,
+ "Last packet was truncated to %d due to end trimming.\n",
os->pduration);
- return AVERROR_PATCHWELCOME;
}
}
@@ -137,6 +178,5 @@ const struct ogg_codec ff_opus_codec = {
.magicsize = 8,
.header = opus_header,
.packet = opus_packet,
- .granule_is_start = 1,
.nb_header = 1,
};
diff --git a/libavformat/oggparseskeleton.c b/libavformat/oggparseskeleton.c
index 5333e17de6..6c2105f324 100644
--- a/libavformat/oggparseskeleton.c
+++ b/libavformat/oggparseskeleton.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2010 David Conrad
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,6 +36,9 @@ static int skeleton_header(AVFormatContext *s, int idx)
st->codec->codec_type = AVMEDIA_TYPE_DATA;
+ if ((os->flags & OGG_FLAG_EOS) && os->psize == 0)
+ return 1;
+
if (os->psize < 8)
return -1;
@@ -46,7 +49,7 @@ static int skeleton_header(AVFormatContext *s, int idx)
version_major = AV_RL16(buf+8);
version_minor = AV_RL16(buf+10);
- if (version_major != 3) {
+ if (version_major != 3 && version_major != 4) {
av_log(s, AV_LOG_WARNING, "Unknown skeleton version %d.%d\n",
version_major, version_minor);
return -1;
@@ -60,7 +63,7 @@ static int skeleton_header(AVFormatContext *s, int idx)
start_num = AV_RL64(buf+12);
start_den = AV_RL64(buf+20);
- if (start_den) {
+ if (start_den > 0 && start_num > 0) {
int base_den;
av_reduce(&start_time, &base_den, start_num, start_den, INT_MAX);
avpriv_set_pts_info(st, 64, 1, base_den);
@@ -73,12 +76,16 @@ static int skeleton_header(AVFormatContext *s, int idx)
target_idx = ogg_find_stream(ogg, AV_RL32(buf+12));
start_granule = AV_RL64(buf+36);
+ if (target_idx < 0) {
+ av_log(s, AV_LOG_WARNING, "Serial number in fisbone doesn't match any stream\n");
+ return 1;
+ }
+ os = ogg->streams + target_idx;
if (os->start_granule != OGG_NOGRANULE_VALUE) {
- avpriv_report_missing_feature(s,
- "Multiple fisbone for the same stream");
+ av_log(s, AV_LOG_WARNING, "Multiple fisbone for the same stream\n");
return 1;
}
- if (target_idx >= 0 && start_granule != OGG_NOGRANULE_VALUE) {
+ if (start_granule != OGG_NOGRANULE_VALUE) {
os->start_granule = start_granule;
}
}
diff --git a/libavformat/oggparsespeex.c b/libavformat/oggparsespeex.c
index b2779e74c1..9b5c65f453 100644
--- a/libavformat/oggparsespeex.c
+++ b/libavformat/oggparsespeex.c
@@ -58,6 +58,11 @@ static int speex_header(AVFormatContext *s, int idx) {
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_SPEEX;
+ if (os->psize < 68) {
+ av_log(s, AV_LOG_ERROR, "speex packet too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+
st->codec->sample_rate = AV_RL32(p + 36);
st->codec->channels = AV_RL32(p + 48);
if (st->codec->channels < 1 || st->codec->channels > 2) {
@@ -72,9 +77,8 @@ static int speex_header(AVFormatContext *s, int idx) {
if (frames_per_packet)
spxp->packet_size *= frames_per_packet;
- st->codec->extradata_size = os->psize;
- st->codec->extradata = av_malloc(st->codec->extradata_size
- + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (ff_alloc_extradata(st->codec, os->psize) < 0)
+ return AVERROR(ENOMEM);
memcpy(st->codec->extradata, p, st->codec->extradata_size);
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c
index d78f02d67a..91c70dfec9 100644
--- a/libavformat/oggparsetheora.c
+++ b/libavformat/oggparsetheora.c
@@ -122,6 +122,7 @@ static int theora_header(AVFormatContext *s, int idx)
return AVERROR_INVALIDDATA;
break;
default:
+ av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
return AVERROR_INVALIDDATA;
}
@@ -130,6 +131,8 @@ static int theora_header(AVFormatContext *s, int idx)
st->codec->extradata_size = 0;
return err;
}
+ memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
cdp = st->codec->extradata + st->codec->extradata_size;
*cdp++ = os->psize >> 8;
*cdp++ = os->psize & 0xff;
@@ -165,10 +168,47 @@ static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
return iframe + pframe;
}
+static int theora_packet(AVFormatContext *s, int idx)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+ int duration;
+
+ /* first packet handling
+ here we parse the duration of each packet in the first page and compare
+ the total duration to the page granule to find the encoder delay and
+ set the first timestamp */
+
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
+ int seg;
+
+ duration = 1;
+ for (seg = os->segp; seg < os->nsegs; seg++) {
+ if (os->segments[seg] < 255)
+ duration ++;
+ }
+
+ os->lastpts = os->lastdts = theora_gptopts(s, idx, os->granule, NULL) - duration;
+ if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
+ s->streams[idx]->start_time = os->lastpts;
+ if (s->streams[idx]->duration)
+ s->streams[idx]->duration -= s->streams[idx]->start_time;
+ }
+ }
+
+ /* parse packet duration */
+ if (os->psize > 0) {
+ os->pduration = 1;
+ }
+
+ return 0;
+}
+
const struct ogg_codec ff_theora_codec = {
.magic = "\200theora",
.magicsize = 7,
.header = theora_header,
+ .packet = theora_packet,
.gptopts = theora_gptopts,
.nb_header = 3,
};
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index b2f9c8b03e..dd44337437 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -156,9 +156,10 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
char *pict = av_malloc(vl);
if (!pict) {
+ av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n");
av_freep(&tt);
av_freep(&ct);
- return AVERROR(ENOMEM);
+ continue;
}
if ((ret = av_base64_decode(pict, ct, vl)) > 0)
ret = ff_flac_parse_picture(as, pict, ret);
@@ -171,16 +172,20 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m,
}
} else if (!ogm_chapter(as, tt, ct)) {
updates++;
+ if (av_dict_get(*m, tt, NULL, 0)) {
+ av_dict_set(m, tt, ";", AV_DICT_APPEND);
+ }
av_dict_set(m, tt, ct,
AV_DICT_DONT_STRDUP_KEY |
- AV_DICT_DONT_STRDUP_VAL);
+ AV_DICT_APPEND);
+ av_freep(&ct);
}
}
}
if (p != end)
av_log(as, AV_LOG_INFO,
- "%ti bytes of comment header remain\n", end - p);
+ "%"PTRDIFF_SPECIFIER" bytes of comment header remain\n", end - p);
if (n > 0)
av_log(as, AV_LOG_INFO,
"truncated comment header, %i comments not found\n", n);
@@ -218,12 +223,15 @@ static int fixup_vorbis_headers(AVFormatContext *as,
uint8_t **buf)
{
int i, offset, len, err;
+ int buf_len;
unsigned char *ptr;
len = priv->len[0] + priv->len[1] + priv->len[2];
- ptr = *buf = av_mallocz(len + len / 255 + 64);
+ buf_len = len + len / 255 + 64;
+ ptr = *buf = av_realloc(NULL, buf_len);
if (!ptr)
return AVERROR(ENOMEM);
+ memset(*buf, '\0', buf_len);
ptr[0] = 2;
offset = 1;
@@ -252,6 +260,36 @@ static void vorbis_cleanup(AVFormatContext *s, int idx)
}
}
+static int vorbis_update_metadata(AVFormatContext *s, int idx)
+{
+ struct ogg *ogg = s->priv_data;
+ struct ogg_stream *os = ogg->streams + idx;
+ AVStream *st = s->streams[idx];
+ int ret;
+
+ if (os->psize <= 8)
+ return 0;
+
+ /* New metadata packet; release old data. */
+ av_dict_free(&st->metadata);
+ ret = ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7,
+ os->psize - 8);
+ if (ret < 0)
+ return ret;
+
+ /* Update the metadata if possible. */
+ av_freep(&os->new_metadata);
+ if (st->metadata) {
+ os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size);
+ /* Send an empty dictionary to indicate that metadata has been cleared. */
+ } else {
+ os->new_metadata = av_malloc(1);
+ os->new_metadata_size = 0;
+ }
+
+ return ret;
+}
+
static int vorbis_header(AVFormatContext *s, int idx)
{
struct ogg *ogg = s->priv_data;
@@ -266,14 +304,14 @@ static int vorbis_header(AVFormatContext *s, int idx)
return AVERROR(ENOMEM);
}
+ priv = os->private;
+
if (!(pkt_type & 1))
- return 0;
+ return priv->vp ? 0 : AVERROR_INVALIDDATA;
if (os->psize < 1 || pkt_type > 5)
return AVERROR_INVALIDDATA;
- priv = os->private;
-
if (priv->packet[pkt_type >> 1])
return AVERROR_INVALIDDATA;
if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1])
@@ -288,6 +326,7 @@ static int vorbis_header(AVFormatContext *s, int idx)
const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
unsigned blocksize, bs0, bs1;
int srate;
+ int channels;
if (os->psize != 30)
return AVERROR_INVALIDDATA;
@@ -295,7 +334,12 @@ static int vorbis_header(AVFormatContext *s, int idx)
if (bytestream_get_le32(&p) != 0) /* vorbis_version */
return AVERROR_INVALIDDATA;
- st->codec->channels = bytestream_get_byte(&p);
+ channels = bytestream_get_byte(&p);
+ if (st->codec->channels && channels != st->codec->channels) {
+ av_log(s, AV_LOG_ERROR, "Channel change is not supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ st->codec->channels = channels;
srate = bytestream_get_le32(&p);
p += 4; // skip maximum bitrate
st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
@@ -321,9 +365,7 @@ static int vorbis_header(AVFormatContext *s, int idx)
avpriv_set_pts_info(st, 64, 1, srate);
}
} else if (os->buf[os->pstart] == 3) {
- if (os->psize > 8 &&
- ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7,
- os->psize - 8) >= 0) {
+ if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) {
unsigned new_len;
int ret = ff_replaygain_export(st, st->metadata);
@@ -350,7 +392,7 @@ static int vorbis_header(AVFormatContext *s, int idx)
if (!priv->vp) {
av_freep(&st->codec->extradata);
st->codec->extradata_size = 0;
- return ret;
+ return AVERROR_UNKNOWN;
}
}
@@ -362,29 +404,40 @@ static int vorbis_packet(AVFormatContext *s, int idx)
struct ogg *ogg = s->priv_data;
struct ogg_stream *os = ogg->streams + idx;
struct oggvorbis_private *priv = os->private;
- int duration;
+ int duration, flags = 0;
/* first packet handling
* here we parse the duration of each packet in the first page and compare
* the total duration to the page granule to find the encoder delay and
* set the first timestamp */
- if (!os->lastpts) {
- int seg;
+ if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule>=0) {
+ int seg, d;
uint8_t *last_pkt = os->buf + os->pstart;
uint8_t *next_pkt = last_pkt;
- int first_duration = 0;
av_vorbis_parse_reset(priv->vp);
duration = 0;
- for (seg = 0; seg < os->nsegs; seg++) {
+ seg = os->segp;
+ d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags);
+ if (d < 0) {
+ os->pflags |= AV_PKT_FLAG_CORRUPT;
+ return 0;
+ } else if (flags & VORBIS_FLAG_COMMENT) {
+ vorbis_update_metadata(s, idx);
+ flags = 0;
+ }
+ duration += d;
+ last_pkt = next_pkt = next_pkt + os->psize;
+ for (; seg < os->nsegs; seg++) {
if (os->segments[seg] < 255) {
- int d = av_vorbis_parse_frame(priv->vp, last_pkt, 1);
+ int d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags);
if (d < 0) {
duration = os->granule;
break;
+ } else if (flags & VORBIS_FLAG_COMMENT) {
+ vorbis_update_metadata(s, idx);
+ flags = 0;
}
- if (!duration)
- first_duration = d;
duration += d;
last_pkt = next_pkt + os->segments[seg];
}
@@ -392,20 +445,28 @@ static int vorbis_packet(AVFormatContext *s, int idx)
}
os->lastpts =
os->lastdts = os->granule - duration;
- s->streams[idx]->start_time = os->lastpts + first_duration;
- if (s->streams[idx]->duration)
- s->streams[idx]->duration -= s->streams[idx]->start_time;
- s->streams[idx]->cur_dts = AV_NOPTS_VALUE;
+
+ if (!os->granule && duration) //hack to deal with broken files (Ticket3710)
+ os->lastpts = os->lastdts = AV_NOPTS_VALUE;
+
+ if (s->streams[idx]->start_time == AV_NOPTS_VALUE) {
+ s->streams[idx]->start_time = FFMAX(os->lastpts, 0);
+ if (s->streams[idx]->duration != AV_NOPTS_VALUE)
+ s->streams[idx]->duration -= s->streams[idx]->start_time;
+ }
priv->final_pts = AV_NOPTS_VALUE;
av_vorbis_parse_reset(priv->vp);
}
/* parse packet duration */
if (os->psize > 0) {
- duration = av_vorbis_parse_frame(priv->vp, os->buf + os->pstart, 1);
- if (duration <= 0) {
+ duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags);
+ if (duration < 0) {
os->pflags |= AV_PKT_FLAG_CORRUPT;
return 0;
+ } else if (flags & VORBIS_FLAG_COMMENT) {
+ vorbis_update_metadata(s, idx);
+ flags = 0;
}
os->pduration = duration;
}
diff --git a/libavformat/oggparsevp8.c b/libavformat/oggparsevp8.c
index b4f71de017..7aed8abad3 100644
--- a/libavformat/oggparsevp8.c
+++ b/libavformat/oggparsevp8.c
@@ -2,20 +2,20 @@
* On2 VP8 parser for Ogg
* Copyright (C) 2013 James Almer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/oma.c b/libavformat/oma.c
index 27b598857c..27028674db 100644
--- a/libavformat/oma.c
+++ b/libavformat/oma.c
@@ -1,20 +1,20 @@
/*
* Sony OpenMG (OMA) common data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/oma.h b/libavformat/oma.h
index 9a35da2623..e2a187bacc 100644
--- a/libavformat/oma.h
+++ b/libavformat/oma.h
@@ -1,20 +1,20 @@
/*
* Sony OpenMG (OMA) common data
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/omadec.c b/libavformat/omadec.c
index 8dc35d17c2..858ee84f3f 100644
--- a/libavformat/omadec.c
+++ b/libavformat/omadec.c
@@ -5,20 +5,20 @@
* 2008 Benjamin Larsson
* 2011 David Goldwich
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -175,13 +175,9 @@ static int nprobe(AVFormatContext *s, uint8_t *enc_header, unsigned size,
taglen = AV_RB32(&enc_header[pos + 32]);
datalen = AV_RB32(&enc_header[pos + 36]) >> 4;
- pos += 44;
- if (size - pos < taglen)
- return -1;
-
- pos += taglen;
+ pos += 44LL + taglen;
- if (datalen << 4 > size - pos)
+ if (pos + (((uint64_t)datalen) << 4) > size)
return -1;
av_des_init(&av_des, n_val, 192, 1);
@@ -300,7 +296,7 @@ static int oma_read_header(AVFormatContext *s)
ID3v2ExtraMeta *extra_meta = NULL;
OMAContext *oc = s->priv_data;
- ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta);
+ ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta, 0);
ret = avio_read(s->pb, buf, EA3_HEADER_SIZE);
if (ret < EA3_HEADER_SIZE)
return -1;
@@ -356,12 +352,10 @@ static int oma_read_header(AVFormatContext *s)
/* fake the ATRAC3 extradata
* (wav format, makes stream copy to wav work) */
- st->codec->extradata_size = 14;
- edata = av_mallocz(14 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!edata)
+ if (ff_alloc_extradata(st->codec, 14))
return AVERROR(ENOMEM);
- st->codec->extradata = edata;
+ edata = st->codec->extradata;
AV_WL16(&edata[0], 1); // always 1
AV_WL32(&edata[2], samplerate); // samples rate
AV_WL16(&edata[6], jsflag); // coding mode
@@ -391,7 +385,7 @@ static int oma_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, samplerate);
break;
case OMA_CODECID_MP3:
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
framesize = 1024;
break;
case OMA_CODECID_LPCM:
@@ -436,9 +430,9 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->stream_index = 0;
- if (pos > 0) {
+ if (pos >= oc->content_start && byte_rate > 0) {
pkt->pts =
- pkt->dts = av_rescale(pos, st->time_base.den,
+ pkt->dts = av_rescale(pos - oc->content_start, st->time_base.den,
byte_rate * (int64_t)st->time_base.num);
}
@@ -466,7 +460,7 @@ static int oma_read_probe(AVProbeData *p)
/* This check cannot overflow as tag_len has at most 28 bits */
if (p->buf_size < tag_len + 5)
/* EA3 header comes late, might be outside of the probe buffer */
- return tag_len ? AVPROBE_SCORE_EXTENSION : 0;
+ return tag_len ? AVPROBE_SCORE_EXTENSION/2 : 0;
buf += tag_len;
@@ -480,7 +474,7 @@ static int oma_read_seek(struct AVFormatContext *s,
int stream_index, int64_t timestamp, int flags)
{
OMAContext *oc = s->priv_data;
- int err = ff_pcm_read_seek(s, stream_index, timestamp, flags);
+ int64_t err = ff_pcm_read_seek(s, stream_index, timestamp, flags);
if (!oc->encrypted)
return err;
diff --git a/libavformat/omaenc.c b/libavformat/omaenc.c
index bfd552a03d..fe0669f5c9 100644
--- a/libavformat/omaenc.c
+++ b/libavformat/omaenc.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2011 Michael Karcher
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,7 +61,7 @@ static av_cold int oma_write_header(AVFormatContext *s)
switch(format->codec_tag) {
case OMA_CODECID_ATRAC3:
if (format->channels != 2) {
- av_log(s, AV_LOG_ERROR, "ATRAC3 in OMA is only supported with 2 channels");
+ av_log(s, AV_LOG_ERROR, "ATRAC3 in OMA is only supported with 2 channels\n");
return AVERROR(EINVAL);
}
if (format->extradata_size == 14) /* WAV format extradata */
@@ -84,8 +84,9 @@ static av_cold int oma_write_header(AVFormatContext *s)
(format->block_align/8 - 1));
break;
default:
- av_log(s, AV_LOG_ERROR, "OMA: unsupported codec tag %d for write\n",
+ av_log(s, AV_LOG_ERROR, "unsupported codec tag %d for write\n",
format->codec_tag);
+ return AVERROR(EINVAL);
}
for (i = 0; i < (EA3_HEADER_SIZE - 36)/4; i++)
avio_wl32(s->pb, 0); /* Padding */
diff --git a/libavformat/options.c b/libavformat/options.c
index 996dc31274..d238dd5ab7 100644
--- a/libavformat/options.c
+++ b/libavformat/options.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
@@ -77,6 +77,13 @@ static const AVClass *format_child_class_next(const AVClass *prev)
return NULL;
}
+static AVClassCategory get_category(void *ptr)
+{
+ AVFormatContext* s = ptr;
+ if(s->iformat) return AV_CLASS_CATEGORY_DEMUXER;
+ else return AV_CLASS_CATEGORY_MUXER;
+}
+
static const AVClass av_format_context_class = {
.class_name = "AVFormatContext",
.item_name = format_to_name,
@@ -84,6 +91,8 @@ static const AVClass av_format_context_class = {
.version = LIBAVUTIL_VERSION_INT,
.child_next = format_child_next,
.child_class_next = format_child_class_next,
+ .category = AV_CLASS_CATEGORY_MUXER,
+ .get_category = get_category,
};
static void avformat_get_context_defaults(AVFormatContext *s)
@@ -108,10 +117,16 @@ AVFormatContext *avformat_alloc_context(void)
return NULL;
}
ic->internal->offset = AV_NOPTS_VALUE;
+ ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
return ic;
}
+enum AVDurationEstimationMethod av_fmt_ctx_get_duration_estimation_method(const AVFormatContext* ctx)
+{
+ return ctx->duration_estimation_method;
+}
+
const AVClass *avformat_get_class(void)
{
return &av_format_context_class;
diff --git a/libavformat/options_table.h b/libavformat/options_table.h
index 8372ef3650..58670b0035 100644
--- a/libavformat/options_table.h
+++ b/libavformat/options_table.h
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +25,7 @@
#include "libavutil/opt.h"
#include "avformat.h"
+#include "internal.h"
#define OFFSET(x) offsetof(AVFormatContext,x)
#define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C
@@ -31,26 +34,38 @@
#define D AV_OPT_FLAG_DECODING_PARAM
static const AVOption avformat_options[] = {
-{"probesize", "set probing size", OFFSET(probesize), AV_OPT_TYPE_INT, {.i64 = 5000000 }, 32, INT_MAX, D},
+{"avioflags", NULL, OFFSET(avio_flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "avioflags"},
+{"direct", "reduce buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVIO_FLAG_DIRECT }, INT_MIN, INT_MAX, D|E, "avioflags"},
+{"probesize", "set probing size", OFFSET(probesize2), AV_OPT_TYPE_INT64, {.i64 = 5000000 }, 32, INT64_MAX, D},
+{"formatprobesize", "number of bytes to probe file format", OFFSET(format_probesize), AV_OPT_TYPE_INT, {.i64 = PROBE_BUF_MAX}, 0, INT_MAX-1, D},
{"packetsize", "set packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, E},
{"fflags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D|E, "fflags"},
-{"flush_packets", "reduce the latency by flushing out packets immediately", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, D, "fflags"},
+{"flush_packets", "reduce the latency by flushing out packets immediately", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FLUSH_PACKETS }, INT_MIN, INT_MAX, E, "fflags"},
{"ignidx", "ignore index", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNIDX }, INT_MIN, INT_MAX, D, "fflags"},
{"genpts", "generate pts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_GENPTS }, INT_MIN, INT_MAX, D, "fflags"},
{"nofillin", "do not fill in missing values that can be exactly calculated", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOFILLIN }, INT_MIN, INT_MAX, D, "fflags"},
{"noparse", "disable AVParsers, this needs nofillin too", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOPARSE }, INT_MIN, INT_MAX, D, "fflags"},
{"igndts", "ignore dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_IGNDTS }, INT_MIN, INT_MAX, D, "fflags"},
{"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"},
+{"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"},
+{"keepside", "don't merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"},
+{"fastseek", "fast but inaccurate seeks", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FAST_SEEK }, INT_MIN, INT_MAX, D, "fflags"},
+{"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"},
{"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"},
+{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, D},
{"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" },
-{"analyzeduration", "how many microseconds are analyzed to estimate duration", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT, {.i64 = 5*AV_TIME_BASE }, 0, INT_MAX, D},
+{"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration2), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D},
{"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D},
{"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D},
{"rtbufsize", "max memory used for buffering real-time frames", OFFSET(max_picture_buffer), AV_OPT_TYPE_INT, {.i64 = 3041280 }, 0, INT_MAX, D}, /* defaults to 1s of 15fps 352x288 YUYV422 video */
{"fdebug", "print specific debug info", OFFSET(debug), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, E|D, "fdebug"},
{"ts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_FDEBUG_TS }, INT_MIN, INT_MAX, E|D, "fdebug"},
{"max_delay", "maximum muxing or demuxing delay in microseconds", OFFSET(max_delay), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, E|D},
+{"start_time_realtime", "wall-clock time when stream begins (PTS==0)", OFFSET(start_time_realtime), AV_OPT_TYPE_INT64, {.i64 = AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX, E},
{"fpsprobesize", "number of frames used to probe fps", OFFSET(fps_probe_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX-1, D},
+{"audio_preload", "microseconds by which audio packets should be interleaved earlier", OFFSET(audio_preload), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E},
+{"chunk_duration", "microseconds for each chunk", OFFSET(max_chunk_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E},
+{"chunk_size", "size in bytes for each chunk", OFFSET(max_chunk_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, E},
/* this is a crutch for avconv, since it cannot deal with identically named options in different contexts.
* to be removed when avconv is fixed */
{"f_err_detect", "set error detection flags (deprecated; use err_detect, save via avconv)", OFFSET(error_recognition), AV_OPT_TYPE_FLAGS, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, D, "err_detect"},
@@ -59,17 +74,32 @@ static const AVOption avformat_options[] = {
{"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, D, "err_detect"},
{"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, D, "err_detect"},
{"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, D, "err_detect"},
+{"ignore_err", "ignore errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_IGNORE_ERR }, INT_MIN, INT_MAX, D, "err_detect"},
+{"careful", "consider things that violate the spec, are fast to check and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, D, "err_detect"},
+{"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_COMPLIANT }, INT_MIN, INT_MAX, D, "err_detect"},
+{"aggressive", "consider things that a sane encoder shouldn't do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, D, "err_detect"},
+{"use_wallclock_as_timestamps", "use wallclock as timestamps", OFFSET(use_wallclock_as_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX-1, D},
+{"skip_initial_bytes", "set number of bytes to skip before reading header and frames", OFFSET(skip_initial_bytes), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX-1, D},
+{"correct_ts_overflow", "correct single timestamp overflows", OFFSET(correct_ts_overflow), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, D},
+{"flush_packets", "enable flushing of the I/O context after each packet", OFFSET(flush_packets), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E},
+{"metadata_header_padding", "set number of bytes to be written as padding in a metadata header", OFFSET(metadata_header_padding), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, E},
+{"output_ts_offset", "set output timestamp offset", OFFSET(output_ts_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E},
{"max_interleave_delta", "maximum buffering duration for interleaving", OFFSET(max_interleave_delta), AV_OPT_TYPE_INT64, { .i64 = 10000000 }, 0, INT64_MAX, E },
{"f_strict", "how strictly to follow the standards (deprecated; use strict, save via avconv)", OFFSET(strict_std_compliance), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "strict"},
{"strict", "how strictly to follow the standards", OFFSET(strict_std_compliance), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, D|E, "strict"},
{"strict", "strictly conform to all the things in the spec no matter what the consequences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_STRICT }, INT_MIN, INT_MAX, D|E, "strict"},
{"normal", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_NORMAL }, INT_MIN, INT_MAX, D|E, "strict"},
+{"unofficial", "allow unofficial extensions", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_UNOFFICIAL }, INT_MIN, INT_MAX, D|E, "strict"},
{"experimental", "allow non-standardized experimental variants", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_EXPERIMENTAL }, INT_MIN, INT_MAX, D|E, "strict"},
{"max_ts_probe", "maximum number of packets to read while waiting for the first timestamp", OFFSET(max_ts_probe), AV_OPT_TYPE_INT, { .i64 = 50 }, 0, INT_MAX, D },
{"avoid_negative_ts", "shift timestamps so they start at 0", OFFSET(avoid_negative_ts), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, E, "avoid_negative_ts"},
{"auto", "enabled when required by target format", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_AUTO }, INT_MIN, INT_MAX, E, "avoid_negative_ts"},
+{"disabled", "do not change timestamps", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, E, "avoid_negative_ts"},
{"make_non_negative", "shift timestamps so they are non negative", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE }, INT_MIN, INT_MAX, E, "avoid_negative_ts"},
{"make_zero", "shift timestamps so they start at 0", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_AVOID_NEG_TS_MAKE_ZERO }, INT_MIN, INT_MAX, E, "avoid_negative_ts"},
+{"dump_separator", "set information dump field separator", OFFSET(dump_separator), AV_OPT_TYPE_STRING, {.str = ", "}, CHAR_MIN, CHAR_MAX, D|E},
+{"codec_whitelist", "List of decoders that are allowed to be used", OFFSET(codec_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
+{"format_whitelist", "List of demuxers that are allowed to be used", OFFSET(format_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D },
{NULL},
};
diff --git a/libavformat/os_support.c b/libavformat/os_support.c
index 650baea0d0..7950e44889 100644
--- a/libavformat/os_support.c
+++ b/libavformat/os_support.c
@@ -3,24 +3,25 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* copyright (c) 2002 Francois Revol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* needed by inet_aton() */
+#define _DEFAULT_SOURCE
#define _SVID_SOURCE
#include "config.h"
@@ -158,9 +159,9 @@ void ff_freeaddrinfo(struct addrinfo *res)
}
#endif /* HAVE_WINSOCK2_H */
- av_free(res->ai_canonname);
- av_free(res->ai_addr);
- av_free(res);
+ av_freep(&res->ai_canonname);
+ av_freep(&res->ai_addr);
+ av_freep(&res);
}
int ff_getnameinfo(const struct sockaddr *sa, int salen,
diff --git a/libavformat/os_support.h b/libavformat/os_support.h
index 6cc6d9aa2b..a3329119c0 100644
--- a/libavformat/os_support.h
+++ b/libavformat/os_support.h
@@ -2,20 +2,20 @@
* various OS-feature replacement utilities
* copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,14 +42,31 @@
#if defined(_WIN32) && !defined(__MINGW32CE__)
# include <fcntl.h>
-# undef lseek
+# ifdef lseek
+# undef lseek
+# endif
# define lseek(f,p,w) _lseeki64((f), (p), (w))
-# undef stat
+# ifdef stat
+# undef stat
+# endif
# define stat _stati64
-# undef fstat
+# ifdef fstat
+# undef fstat
+# endif
# define fstat(f,s) _fstati64((f), (s))
#endif /* defined(_WIN32) && !defined(__MINGW32CE__) */
+
+#ifdef __ANDROID__
+# if HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+# ifdef lseek
+# undef lseek
+# endif
+# define lseek(f,p,w) lseek64((f), (p), (w))
+#endif
+
static inline int is_dos_path(const char *path)
{
#if HAVE_DOS_PATHS
diff --git a/libavformat/paf.c b/libavformat/paf.c
index 9ee4cd8cb6..4fc5006f40 100644
--- a/libavformat/paf.c
+++ b/libavformat/paf.c
@@ -2,31 +2,29 @@
* Packed Animation File demuxer
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/channel_layout.h"
-
+#include "libavcodec/paf.h"
#include "avformat.h"
#include "internal.h"
#define MAGIC "Packed Animation File V1.0\n(c) 1992-96 Amazing Studio\x0a\x1a"
-#define PAF_SOUND_SAMPLES 2205
-#define PAF_SOUND_FRAME_SIZE ((256 + PAF_SOUND_SAMPLES) * 2)
typedef struct PAFDemuxContext {
uint32_t buffer_size;
@@ -195,10 +193,13 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
PAFDemuxContext *p = s->priv_data;
AVIOContext *pb = s->pb;
- uint32_t count, offset;
- int size, i;
+ uint32_t count, offset;
+ int size, i;
+
+ if (p->current_frame >= p->nb_frames)
+ return AVERROR_EOF;
- if (p->current_frame >= p->nb_frames || pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
if (p->got_audio) {
diff --git a/libavformat/pcm.c b/libavformat/pcm.c
index e4f2a5e627..f62075fc82 100644
--- a/libavformat/pcm.c
+++ b/libavformat/pcm.c
@@ -2,20 +2,20 @@
* PCM common functions
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,24 @@
#include "internal.h"
#include "pcm.h"
+#define RAW_SAMPLES 1024
+
+int ff_pcm_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int ret, size;
+
+ size= RAW_SAMPLES*s->streams[0]->codec->block_align;
+ if (size <= 0)
+ return AVERROR(EINVAL);
+
+ ret= av_get_packet(s->pb, pkt, size);
+
+ pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
int ff_pcm_read_seek(AVFormatContext *s,
int stream_index, int64_t timestamp, int flags)
{
diff --git a/libavformat/pcm.h b/libavformat/pcm.h
index 30cbc86ee3..9af36d5a2e 100644
--- a/libavformat/pcm.h
+++ b/libavformat/pcm.h
@@ -2,20 +2,20 @@
* PCM common functions
* Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include "avformat.h"
+int ff_pcm_read_packet(AVFormatContext *s, AVPacket *pkt);
int ff_pcm_read_seek(AVFormatContext *s,
int stream_index, int64_t timestamp, int flags);
diff --git a/libavformat/pcmdec.c b/libavformat/pcmdec.c
index 1bbbc66d17..2584c33c24 100644
--- a/libavformat/pcmdec.c
+++ b/libavformat/pcmdec.c
@@ -2,20 +2,20 @@
* RAW PCM demuxers
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,8 +24,7 @@
#include "pcm.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
-
-#define RAW_SAMPLES 1024
+#include "libavutil/avassert.h"
typedef struct PCMAudioDemuxerContext {
AVClass *class;
@@ -51,7 +50,7 @@ static int pcm_read_header(AVFormatContext *s)
st->codec->bits_per_coded_sample =
av_get_bits_per_sample(st->codec->codec_id);
- assert(st->codec->bits_per_coded_sample > 0);
+ av_assert0(st->codec->bits_per_coded_sample > 0);
st->codec->block_align =
st->codec->bits_per_coded_sample * st->codec->channels / 8;
@@ -60,33 +59,8 @@ static int pcm_read_header(AVFormatContext *s)
return 0;
}
-static int pcm_read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- int ret, size, bps;
- // AVStream *st = s->streams[0];
-
- size= RAW_SAMPLES*s->streams[0]->codec->block_align;
-
- ret= av_get_packet(s->pb, pkt, size);
-
- pkt->stream_index = 0;
- if (ret < 0)
- return ret;
-
- bps= av_get_bits_per_sample(s->streams[0]->codec->codec_id);
- if (!bps) {
- av_log(s, AV_LOG_ERROR, "Unknown number of bytes per sample.\n");
- return AVERROR(EINVAL);
- }
-
- pkt->dts=
- pkt->pts= pkt->pos*8 / (bps * s->streams[0]->codec->channels);
-
- return ret;
-}
-
static const AVOption pcm_options[] = {
- { "sample_rate", "", offsetof(PCMAudioDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { "sample_rate", "", offsetof(PCMAudioDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 44100}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
{ "channels", "", offsetof(PCMAudioDemuxerContext, channels), AV_OPT_TYPE_INT, {.i64 = 1}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
@@ -103,7 +77,7 @@ AVInputFormat ff_pcm_ ## name_ ## _demuxer = { \
.long_name = NULL_IF_CONFIG_SMALL(long_name_), \
.priv_data_size = sizeof(PCMAudioDemuxerContext), \
.read_header = pcm_read_header, \
- .read_packet = pcm_read_packet, \
+ .read_packet = ff_pcm_read_packet, \
.read_seek = ff_pcm_read_seek, \
.flags = AVFMT_GENERIC_INDEX, \
.extensions = ext, \
@@ -170,3 +144,29 @@ PCMDEF(alaw, "PCM A-law",
PCMDEF(mulaw, "PCM mu-law",
"ul", AV_CODEC_ID_PCM_MULAW)
+
+static const AVOption sln_options[] = {
+ { "sample_rate", "", offsetof(PCMAudioDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 8000}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { "channels", "", offsetof(PCMAudioDemuxerContext, channels), AV_OPT_TYPE_INT, {.i64 = 1}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass sln_demuxer_class = {
+ .class_name = "sln demuxer",
+ .item_name = av_default_item_name,
+ .option = sln_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_sln_demuxer = {
+ .name = "sln",
+ .long_name = NULL_IF_CONFIG_SMALL("Asterisk raw pcm"),
+ .priv_data_size = sizeof(PCMAudioDemuxerContext),
+ .read_header = pcm_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .flags = AVFMT_GENERIC_INDEX,
+ .extensions = "sln",
+ .raw_codec_id = AV_CODEC_ID_PCM_S16LE,
+ .priv_class = &sln_demuxer_class,
+};
diff --git a/libavformat/pcmenc.c b/libavformat/pcmenc.c
index e45ab8412a..3e4f308057 100644
--- a/libavformat/pcmenc.c
+++ b/libavformat/pcmenc.c
@@ -2,20 +2,20 @@
* RAW PCM muxers
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/pjsdec.c b/libavformat/pjsdec.c
new file mode 100644
index 0000000000..5129b70e5f
--- /dev/null
+++ b/libavformat/pjsdec.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * PJS (Phoenix Japanimation Society) subtitles format demuxer
+ *
+ * @see http://subs.com.ru/page.php?al=pjs
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} PJSContext;
+
+static int pjs_probe(AVProbeData *p)
+{
+ char c;
+ int64_t start, end;
+ const unsigned char *ptr = p->buf;
+
+ if (sscanf(ptr, "%"SCNd64",%"SCNd64",%c", &start, &end, &c) == 3) {
+ size_t q1pos = strcspn(ptr, "\"");
+ size_t q2pos = q1pos + strcspn(ptr + q1pos + 1, "\"") + 1;
+ if (strcspn(ptr, "\r\n") > q2pos)
+ return AVPROBE_SCORE_MAX;
+ }
+ return 0;
+}
+
+static int64_t read_ts(char **line, int *duration)
+{
+ int64_t start, end;
+
+ if (sscanf(*line, "%"SCNd64",%"SCNd64, &start, &end) == 2) {
+ *line += strcspn(*line, "\"");
+ *line += !!**line;
+ *duration = end - start;
+ return start;
+ }
+ return AV_NOPTS_VALUE;
+}
+
+static int pjs_read_header(AVFormatContext *s)
+{
+ PJSContext *pjs = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ int res = 0;
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 10);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_PJS;
+
+ while (!avio_feof(s->pb)) {
+ char line[4096];
+ char *p = line;
+ const int64_t pos = avio_tell(s->pb);
+ int len = ff_get_line(s->pb, line, sizeof(line));
+ int64_t pts_start;
+ int duration;
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ pts_start = read_ts(&p, &duration);
+ if (pts_start != AV_NOPTS_VALUE) {
+ AVPacket *sub;
+
+ p[strcspn(p, "\"")] = 0;
+ sub = ff_subtitles_queue_insert(&pjs->q, p, strlen(p), 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ sub->pts = pts_start;
+ sub->duration = duration;
+ }
+ }
+
+ ff_subtitles_queue_finalize(&pjs->q);
+ return res;
+}
+
+static int pjs_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ PJSContext *pjs = s->priv_data;
+ return ff_subtitles_queue_read_packet(&pjs->q, pkt);
+}
+
+static int pjs_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ PJSContext *pjs = s->priv_data;
+ return ff_subtitles_queue_seek(&pjs->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int pjs_read_close(AVFormatContext *s)
+{
+ PJSContext *pjs = s->priv_data;
+ ff_subtitles_queue_clean(&pjs->q);
+ return 0;
+}
+
+AVInputFormat ff_pjs_demuxer = {
+ .name = "pjs",
+ .long_name = NULL_IF_CONFIG_SMALL("PJS (Phoenix Japanimation Society) subtitles"),
+ .priv_data_size = sizeof(PJSContext),
+ .read_probe = pjs_probe,
+ .read_header = pjs_read_header,
+ .read_packet = pjs_read_packet,
+ .read_seek2 = pjs_read_seek,
+ .read_close = pjs_read_close,
+ .extensions = "pjs",
+};
diff --git a/libavformat/pmpdec.c b/libavformat/pmpdec.c
index 8ae147f391..ec966b3e1a 100644
--- a/libavformat/pmpdec.c
+++ b/libavformat/pmpdec.c
@@ -1,21 +1,21 @@
/*
- * PMP demuxer
+ * PMP demuxer.
* Copyright (c) 2011 Reimar Döffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,18 +23,18 @@
#include "avformat.h"
#include "internal.h"
-typedef struct PMPContext {
- int cur_stream;
- int num_streams;
- int audio_packets;
- int current_packet;
+typedef struct {
+ int cur_stream;
+ int num_streams;
+ int audio_packets;
+ int current_packet;
uint32_t *packet_sizes;
- int packet_sizes_alloc;
+ int packet_sizes_alloc;
} PMPContext;
-static int pmp_probe(AVProbeData *p)
-{
- if (!memcmp(p->buf, "pmpm\1\0\0\0", 8))
+static int pmp_probe(AVProbeData *p) {
+ if (AV_RN32(p->buf) == AV_RN32("pmpm") &&
+ AV_RL32(p->buf + 4) == 1)
return AVPROBE_SCORE_MAX;
return 0;
}
@@ -44,11 +44,13 @@ static int pmp_header(AVFormatContext *s)
PMPContext *pmp = s->priv_data;
AVIOContext *pb = s->pb;
int tb_num, tb_den;
- int index_cnt;
+ uint32_t index_cnt;
int audio_codec_id = AV_CODEC_ID_NONE;
int srate, channels;
- int i;
+ unsigned i;
uint64_t pos;
+ int64_t fsize = avio_size(pb);
+
AVStream *vst = avformat_new_stream(s, NULL);
if (!vst)
return AVERROR(ENOMEM);
@@ -65,7 +67,7 @@ static int pmp_header(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "Unsupported video format\n");
break;
}
- index_cnt = avio_rl32(pb);
+ index_cnt = avio_rl32(pb);
vst->codec->width = avio_rl32(pb);
vst->codec->height = avio_rl32(pb);
@@ -73,14 +75,14 @@ static int pmp_header(AVFormatContext *s)
tb_den = avio_rl32(pb);
avpriv_set_pts_info(vst, 32, tb_num, tb_den);
vst->nb_frames = index_cnt;
- vst->duration = index_cnt;
+ vst->duration = index_cnt;
switch (avio_rl32(pb)) {
case 0:
audio_codec_id = AV_CODEC_ID_MP3;
break;
case 1:
- av_log(s, AV_LOG_WARNING, "AAC is not yet correctly supported\n");
+ av_log(s, AV_LOG_ERROR, "AAC not yet correctly supported\n");
audio_codec_id = AV_CODEC_ID_AAC;
break;
default:
@@ -89,26 +91,38 @@ static int pmp_header(AVFormatContext *s)
}
pmp->num_streams = avio_rl16(pb) + 1;
avio_skip(pb, 10);
- srate = avio_rl32(pb);
+ srate = avio_rl32(pb);
channels = avio_rl32(pb) + 1;
+ pos = avio_tell(pb) + 4LL*index_cnt;
+ for (i = 0; i < index_cnt; i++) {
+ uint32_t size = avio_rl32(pb);
+ int flags = size & 1 ? AVINDEX_KEYFRAME : 0;
+ if (avio_feof(pb)) {
+ av_log(s, AV_LOG_FATAL, "Encountered EOF while reading index.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ size >>= 1;
+ if (size < 9 + 4*pmp->num_streams) {
+ av_log(s, AV_LOG_ERROR, "Packet too small\n");
+ return AVERROR_INVALIDDATA;
+ }
+ av_add_index_entry(vst, pos, i, size, 0, flags);
+ pos += size;
+ if (fsize > 0 && i == 0 && pos > fsize) {
+ av_log(s, AV_LOG_ERROR, "File ends before first packet\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
for (i = 1; i < pmp->num_streams; i++) {
AVStream *ast = avformat_new_stream(s, NULL);
if (!ast)
return AVERROR(ENOMEM);
- ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- ast->codec->codec_id = audio_codec_id;
- ast->codec->channels = channels;
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->codec_id = audio_codec_id;
+ ast->codec->channels = channels;
ast->codec->sample_rate = srate;
avpriv_set_pts_info(ast, 32, 1, srate);
}
- pos = avio_tell(pb) + 4 * index_cnt;
- for (i = 0; i < index_cnt; i++) {
- int size = avio_rl32(pb);
- int flags = size & 1 ? AVINDEX_KEYFRAME : 0;
- size >>= 1;
- av_add_index_entry(vst, pos, i, size, 0, flags);
- pos += size;
- }
return 0;
}
@@ -119,11 +133,12 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt)
int ret = 0;
int i;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
if (pmp->cur_stream == 0) {
int num_packets;
pmp->audio_packets = avio_r8(pb);
+
if (!pmp->audio_packets) {
av_log(s, AV_LOG_ERROR, "No audio packets.\n");
return AVERROR_INVALIDDATA;
@@ -143,22 +158,17 @@ static int pmp_packet(AVFormatContext *s, AVPacket *pkt)
pmp->packet_sizes[i] = avio_rl32(pb);
}
ret = av_get_packet(pb, pkt, pmp->packet_sizes[pmp->current_packet]);
- if (ret > 0) {
+ if (ret >= 0) {
ret = 0;
- // FIXME: this is a hack that should be removed once
- // compute_pkt_fields() can handle timestamps properly
- if (pmp->cur_stream == 0)
- pkt->dts = s->streams[0]->cur_dts++;
pkt->stream_index = pmp->cur_stream;
}
- pmp->current_packet++;
- if (pmp->current_packet == 1 || pmp->current_packet > pmp->audio_packets)
+ if (pmp->current_packet % pmp->audio_packets == 0)
pmp->cur_stream = (pmp->cur_stream + 1) % pmp->num_streams;
-
+ pmp->current_packet++;
return ret;
}
-static int pmp_seek(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
+static int pmp_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags)
{
PMPContext *pmp = s->priv_data;
pmp->cur_stream = 0;
diff --git a/libavformat/psxstr.c b/libavformat/psxstr.c
index e662ed788d..fd50e549ae 100644
--- a/libavformat/psxstr.c
+++ b/libavformat/psxstr.c
@@ -1,21 +1,21 @@
/*
* Sony Playstation (PSX) STR File Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,11 +66,13 @@ typedef struct StrDemuxContext {
StrChannel channels[32];
} StrDemuxContext;
-static const char sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00};
+static const uint8_t sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00};
static int str_probe(AVProbeData *p)
{
- uint8_t *sector= p->buf;
+ const uint8_t *sector= p->buf;
+ const uint8_t *end= sector + p->buf_size;
+ int aud=0, vid=0;
if (p->buf_size < RAW_CD_SECTOR_SIZE)
return 0;
@@ -82,20 +84,52 @@ static int str_probe(AVProbeData *p)
sector += RIFF_HEADER_SIZE;
}
- /* look for CD sync header (00, 0xFF x 10, 00) */
- if (memcmp(sector,sync_header,sizeof(sync_header)))
- return 0;
+ while (end - sector >= RAW_CD_SECTOR_SIZE) {
+ /* look for CD sync header (00, 0xFF x 10, 00) */
+ if (memcmp(sector,sync_header,sizeof(sync_header)))
+ return 0;
- if(sector[0x11] >= 32)
- return 0;
- if( (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_VIDEO
- && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_AUDIO
- && (sector[0x12] & CDXA_TYPE_MASK) != CDXA_TYPE_DATA)
- return 0;
+ if (sector[0x11] >= 32)
+ return 0;
+
+ switch (sector[0x12] & CDXA_TYPE_MASK) {
+ case CDXA_TYPE_DATA:
+ case CDXA_TYPE_VIDEO: {
+ int current_sector = AV_RL16(&sector[0x1C]);
+ int sector_count = AV_RL16(&sector[0x1E]);
+ int frame_size = AV_RL32(&sector[0x24]);
+
+ if(!( frame_size>=0
+ && current_sector < sector_count
+ && sector_count*VIDEO_DATA_CHUNK_SIZE >=frame_size)){
+ return 0;
+ }
+ /*st->codec->width = AV_RL16(&sector[0x28]);
+ st->codec->height = AV_RL16(&sector[0x2A]);*/
+
+// if (current_sector == sector_count-1) {
+ vid++;
+// }
+
+ }
+ break;
+ case CDXA_TYPE_AUDIO:
+ if(sector[0x13]&0x2A)
+ return 0;
+ aud++;
+ break;
+ default:
+ if(sector[0x12] & CDXA_TYPE_MASK)
+ return 0;
+ }
+ sector += RAW_CD_SECTOR_SIZE;
+ }
/* MPEG files (like those ripped from VCDs) can also look like this;
* only return half certainty */
- return AVPROBE_SCORE_EXTENSION;
+ if(vid+aud > 3) return AVPROBE_SCORE_EXTENSION;
+ else if(vid+aud) return 1;
+ else return 0;
}
static int str_read_header(AVFormatContext *s)
@@ -187,6 +221,7 @@ static int str_read_packet(AVFormatContext *s,
av_free_packet(pkt);
if (av_new_packet(pkt, sector_count*VIDEO_DATA_CHUNK_SIZE))
return AVERROR(EIO);
+ memset(pkt->data, 0, sector_count*VIDEO_DATA_CHUNK_SIZE);
pkt->pos= avio_tell(pb) - RAW_CD_SECTOR_SIZE;
pkt->stream_index =
@@ -257,7 +292,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
break;
}
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
}
}
diff --git a/libavformat/pva.c b/libavformat/pva.c
index 2c485d6dcf..900ad6133d 100644
--- a/libavformat/pva.c
+++ b/libavformat/pva.c
@@ -2,20 +2,20 @@
* TechnoTrend PVA (.pva) demuxer
* Copyright (c) 2007, 2008 Ivo van Poorten
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,13 +32,26 @@ typedef struct PVAContext {
int continue_pes;
} PVAContext;
+static int pva_check(const uint8_t *p) {
+ int length = AV_RB16(p + 6);
+ if (AV_RB16(p) != PVA_MAGIC || !p[2] || p[2] > 2 || p[4] != 0x55 ||
+ (p[5] & 0xe0) || length > PVA_MAX_PAYLOAD_LENGTH)
+ return -1;
+ return length + 8;
+}
+
static int pva_probe(AVProbeData * pd) {
- unsigned char *buf = pd->buf;
+ const unsigned char *buf = pd->buf;
+ int len = pva_check(buf);
+
+ if (len < 0)
+ return 0;
- if (AV_RB16(buf) == PVA_MAGIC && buf[2] && buf[2] < 3 && buf[4] == 0x55)
+ if (pd->buf_size >= len + 8 &&
+ pva_check(buf + len) >= 0)
return AVPROBE_SCORE_EXTENSION;
- return 0;
+ return AVPROBE_SCORE_MAX / 4;
}
static int pva_read_header(AVFormatContext *s) {
@@ -72,6 +85,7 @@ static int read_part_of_packet(AVFormatContext *s, int64_t *pts,
PVAContext *pvactx = s->priv_data;
int syncword, streamid, reserved, flags, length, pts_flag;
int64_t pva_pts = AV_NOPTS_VALUE, startpos;
+ int ret;
recover:
startpos = avio_tell(pb);
@@ -120,8 +134,8 @@ recover:
pes_flags = avio_rb16(pb);
pes_header_data_length = avio_r8(pb);
- if (pes_signal != 1) {
- pva_log(s, AV_LOG_WARNING, "expected signaled PES packet, "
+ if (pes_signal != 1 || pes_header_data_length == 0) {
+ pva_log(s, AV_LOG_WARNING, "expected non empty signaled PES packet, "
"trying to recover\n");
avio_skip(pb, length - 9);
if (!read_packet)
@@ -129,15 +143,23 @@ recover:
goto recover;
}
- avio_read(pb, pes_header_data, pes_header_data_length);
+ ret = avio_read(pb, pes_header_data, pes_header_data_length);
+ if (ret != pes_header_data_length)
+ return ret < 0 ? ret : AVERROR_INVALIDDATA;
length -= 9 + pes_header_data_length;
pes_packet_length -= 3 + pes_header_data_length;
pvactx->continue_pes = pes_packet_length;
- if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20)
+ if (pes_flags & 0x80 && (pes_header_data[0] & 0xf0) == 0x20) {
+ if (pes_header_data_length < 5) {
+ pva_log(s, AV_LOG_ERROR, "header too short\n");
+ avio_skip(pb, length);
+ return AVERROR_INVALIDDATA;
+ }
pva_pts = ff_parse_pes_pts(pes_header_data);
+ }
}
pvactx->continue_pes -= length;
diff --git a/libavformat/pvfdec.c b/libavformat/pvfdec.c
new file mode 100644
index 0000000000..c678046156
--- /dev/null
+++ b/libavformat/pvfdec.c
@@ -0,0 +1,75 @@
+/*
+ * PVF demuxer
+ * Copyright (c) 2012 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
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "pcm.h"
+
+static int pvf_probe(AVProbeData *p)
+{
+ if (!memcmp(p->buf, "PVF1\n", 5))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int pvf_read_header(AVFormatContext *s)
+{
+ char buffer[32];
+ AVStream *st;
+ int bps, channels, sample_rate;
+
+ avio_skip(s->pb, 5);
+ ff_get_line(s->pb, buffer, sizeof(buffer));
+ if (sscanf(buffer, "%d %d %d",
+ &channels,
+ &sample_rate,
+ &bps) != 3)
+ return AVERROR_INVALIDDATA;
+
+ if (channels <= 0 || bps <= 0 || sample_rate <= 0)
+ return AVERROR_INVALIDDATA;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->channels = channels;
+ st->codec->sample_rate = sample_rate;
+ st->codec->codec_id = ff_get_pcm_codec_id(bps, 0, 1, 0xFFFF);
+ st->codec->bits_per_coded_sample = bps;
+ st->codec->block_align = bps * st->codec->channels / 8;
+
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+
+ return 0;
+}
+
+AVInputFormat ff_pvf_demuxer = {
+ .name = "pvf",
+ .long_name = NULL_IF_CONFIG_SMALL("PVF (Portable Voice Format)"),
+ .read_probe = pvf_probe,
+ .read_header = pvf_read_header,
+ .read_packet = ff_pcm_read_packet,
+ .read_seek = ff_pcm_read_seek,
+ .extensions = "pvf",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/qcp.c b/libavformat/qcp.c
index be06e2f4ec..9e2eedfe85 100644
--- a/libavformat/qcp.c
+++ b/libavformat/qcp.c
@@ -2,20 +2,20 @@
* QCP format (.qcp) demuxer
* Copyright (c) 2009 Kenan Gillet
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,7 @@
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "avformat.h"
+#include "riff.h"
typedef struct QCPContext {
uint32_t data_size; ///< size of data chunk
@@ -102,13 +103,12 @@ static int qcp_read_header(AVFormatContext *s)
if (is_qcelp_13k_guid(buf)) {
st->codec->codec_id = AV_CODEC_ID_QCELP;
} else if (!memcmp(buf, guid_evrc, 16)) {
- av_log(s, AV_LOG_ERROR, "EVRC codec is not supported.\n");
- return AVERROR_PATCHWELCOME;
+ st->codec->codec_id = AV_CODEC_ID_EVRC;
} else if (!memcmp(buf, guid_smv, 16)) {
- av_log(s, AV_LOG_ERROR, "SMV codec is not supported.\n");
- return AVERROR_PATCHWELCOME;
+ st->codec->codec_id = AV_CODEC_ID_SMV;
} else {
- av_log(s, AV_LOG_ERROR, "Unknown codec GUID.\n");
+ av_log(s, AV_LOG_ERROR, "Unknown codec GUID "FF_PRI_GUID".\n",
+ FF_ARG_GUID(buf));
return AVERROR_INVALIDDATA;
}
avio_skip(pb, 2 + 80); // codec-version + codec-name
@@ -141,7 +141,7 @@ static int qcp_read_packet(AVFormatContext *s, AVPacket *pkt)
QCPContext *c = s->priv_data;
unsigned int chunk_size, tag;
- while(!pb->eof_reached) {
+ while(!avio_feof(pb)) {
if (c->data_size) {
int pkt_size, ret, mode = avio_r8(pb);
diff --git a/libavformat/qtpalette.h b/libavformat/qtpalette.h
index ecc85d3408..7d6802f73c 100644
--- a/libavformat/qtpalette.h
+++ b/libavformat/qtpalette.h
@@ -3,20 +3,20 @@
* Automatically generated from a utility derived from XAnim:
* http://xanim.va.pubnix.com/home.html
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/r3d.c b/libavformat/r3d.c
index a99f265fea..f220e3d9c0 100644
--- a/libavformat/r3d.c
+++ b/libavformat/r3d.c
@@ -2,20 +2,20 @@
* R3D REDCODE demuxer
* Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -86,6 +86,9 @@ static int r3d_read_red1(AVFormatContext *s)
framerate.num = avio_rb16(s->pb);
framerate.den = avio_rb16(s->pb);
if (framerate.num > 0 && framerate.den > 0) {
+#if FF_API_R_FRAME_RATE
+ st->r_frame_rate =
+#endif
st->avg_frame_rate = framerate;
}
@@ -136,8 +139,7 @@ static int r3d_read_rdvo(AVFormatContext *s, Atom *atom)
if (st->avg_frame_rate.num)
st->duration = av_rescale_q(r3d->video_offsets_count,
- (AVRational){st->avg_frame_rate.den,
- st->avg_frame_rate.num},
+ av_inv_q(st->avg_frame_rate),
st->time_base);
av_log(s, AV_LOG_TRACE, "duration %"PRId64"\n", st->duration);
@@ -312,7 +314,8 @@ static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom)
pkt->stream_index = 1;
pkt->dts = dts;
- pkt->duration = av_rescale(samples, st->time_base.den, st->codec->sample_rate);
+ if (st->codec->sample_rate)
+ pkt->duration = av_rescale(samples, st->time_base.den, st->codec->sample_rate);
av_log(s, AV_LOG_TRACE, "pkt dts %"PRId64" duration %d samples %d sample rate %d\n",
pkt->dts, pkt->duration, samples, st->codec->sample_rate);
@@ -369,7 +372,7 @@ static int r3d_seek(AVFormatContext *s, int stream_index, int64_t sample_time, i
return -1;
frame_num = av_rescale_q(sample_time, st->time_base,
- (AVRational){st->avg_frame_rate.den, st->avg_frame_rate.num});
+ av_inv_q(st->avg_frame_rate));
av_log(s, AV_LOG_TRACE, "seek frame num %d timestamp %"PRId64"\n",
frame_num, sample_time);
diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c
index 65cb6bb00f..b903e63fb4 100644
--- a/libavformat/rawdec.c
+++ b/libavformat/rawdec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2005 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#define RAW_PACKET_SIZE 1024
@@ -46,12 +47,8 @@ int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt)
if (ret < 0) {
av_free_packet(pkt);
return ret;
- } else if (ret < size) {
- /* initialize end of packet for partial reads to avoid reading
- * uninitialized data on allowed overreads */
- memset(pkt->data + ret, 0, FF_INPUT_BUFFER_PADDING_SIZE);
}
- pkt->size = ret;
+ av_shrink_packet(pkt, ret);
return ret;
}
@@ -62,7 +59,7 @@ int ff_raw_audio_read_header(AVFormatContext *s)
return AVERROR(ENOMEM);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = s->iformat->raw_codec_id;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
st->start_time = 0;
/* the parameters will be extracted from the compressed bitstream */
@@ -74,7 +71,6 @@ int ff_raw_video_read_header(AVFormatContext *s)
{
AVStream *st;
FFRawVideoDemuxerContext *s1 = s->priv_data;
- AVRational framerate;
int ret = 0;
@@ -86,95 +82,128 @@ int ff_raw_video_read_header(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = s->iformat->raw_codec_id;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
- if ((ret = av_parse_video_rate(&framerate, s1->framerate)) < 0) {
- av_log(s, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s1->framerate);
- goto fail;
- }
-
- st->avg_frame_rate = framerate;
- avpriv_set_pts_info(st, 64, framerate.den, framerate.num);
+ st->codec->framerate = s1->framerate;
+ st->codec->time_base = av_inv_q(s1->framerate);
+ avpriv_set_pts_info(st, 64, 1, 1200000);
fail:
return ret;
}
+int ff_raw_data_read_header(AVFormatContext *s)
+{
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_DATA;
+ st->codec->codec_id = s->iformat->raw_codec_id;
+ st->start_time = 0;
+ return 0;
+}
+
/* Note: Do not forget to add new entries to the Makefile as well. */
#define OFFSET(x) offsetof(FFRawVideoDemuxerContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
const AVOption ff_rawvideo_options[] = {
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC},
+ { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC},
{ NULL },
};
-#if CONFIG_LATM_DEMUXER
-
-#define LOAS_SYNC_WORD 0x2b7
-
-static int latm_read_probe(AVProbeData *p)
-{
- int max_frames = 0, first_frames = 0;
- int fsize, frames;
- uint8_t *buf0 = p->buf;
- uint8_t *buf2;
- uint8_t *buf;
- uint8_t *end = buf0 + p->buf_size - 3;
-
- buf = buf0;
-
- for (; buf < end; buf = buf2 + 1) {
- buf2 = buf;
-
- for (frames = 0; buf2 < end; frames++) {
- uint32_t header = AV_RB24(buf2);
- if ((header >> 13) != LOAS_SYNC_WORD) {
- if (buf != buf0) {
- // Found something that isn't a LOAS header, starting
- // from a position other than the start of the buffer.
- // Discard the count we've accumulated so far since it
- // probably was a false positive.
- frames = 0;
- }
- break;
- }
- fsize = (header & 0x1FFF) + 3;
- if (fsize < 7)
- break;
- buf2 += fsize;
- }
- max_frames = FFMAX(max_frames, frames);
- if (buf == buf0)
- first_frames = frames;
- }
+#if CONFIG_DATA_DEMUXER
+AVInputFormat ff_data_demuxer = {
+ .name = "data",
+ .long_name = NULL_IF_CONFIG_SMALL("raw data"),
+ .read_header = ff_raw_data_read_header,
+ .read_packet = ff_raw_read_partial_packet,
+ .raw_codec_id = AV_CODEC_ID_NONE,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
- if (first_frames >= 3)
- return AVPROBE_SCORE_EXTENSION + 1;
- else if (max_frames > 100)
- return AVPROBE_SCORE_EXTENSION;
- else if (max_frames >= 3)
- return AVPROBE_SCORE_EXTENSION / 2;
- else if (max_frames > 1)
- return 1;
- else
- return 0;
-}
+#if CONFIG_LATM_DEMUXER
AVInputFormat ff_latm_demuxer = {
.name = "latm",
.long_name = NULL_IF_CONFIG_SMALL("raw LOAS/LATM"),
- .read_probe = latm_read_probe,
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
- .flags = AVFMT_GENERIC_INDEX,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
.extensions = "latm",
.raw_codec_id = AV_CODEC_ID_AAC_LATM,
};
#endif
#if CONFIG_MJPEG_DEMUXER
-FF_DEF_RAWVIDEO_DEMUXER(mjpeg, "raw MJPEG video", NULL, "mjpg,mjpeg", AV_CODEC_ID_MJPEG)
+static int mjpeg_probe(AVProbeData *p)
+{
+ int i;
+ int state = -1;
+ int nb_invalid = 0;
+ int nb_frames = 0;
+
+ for (i=0; i<p->buf_size-2; i++) {
+ int c;
+ if (p->buf[i] != 0xFF)
+ continue;
+ c = p->buf[i+1];
+ switch (c) {
+ case 0xD8:
+ state = 0xD8;
+ break;
+ case 0xC0:
+ case 0xC1:
+ case 0xC2:
+ case 0xC3:
+ case 0xC5:
+ case 0xC6:
+ case 0xC7:
+ case 0xF7:
+ if (state == 0xD8) {
+ state = 0xC0;
+ } else
+ nb_invalid++;
+ break;
+ case 0xDA:
+ if (state == 0xC0) {
+ state = 0xDA;
+ } else
+ nb_invalid++;
+ break;
+ case 0xD9:
+ if (state == 0xDA) {
+ state = 0xD9;
+ nb_frames++;
+ } else
+ nb_invalid++;
+ break;
+ default:
+ if ( (c >= 0x02 && c <= 0xBF)
+ || c == 0xC8) {
+ nb_invalid++;
+ }
+ }
+ }
+
+ if (nb_invalid*4 + 1 < nb_frames) {
+ static const char ct_jpeg[] = "\r\nContent-Type: image/jpeg\r\n\r\n";
+ int i;
+
+ for (i=0; i<FFMIN(p->buf_size - sizeof(ct_jpeg), 100); i++)
+ if (!memcmp(p->buf + i, ct_jpeg, sizeof(ct_jpeg) - 1))
+ return AVPROBE_SCORE_EXTENSION;
+
+ if (nb_invalid == 0 && nb_frames > 2)
+ return AVPROBE_SCORE_EXTENSION / 2;
+ return AVPROBE_SCORE_EXTENSION / 4;
+ }
+
+ return 0;
+}
+
+FF_DEF_RAWVIDEO_DEMUXER2(mjpeg, "raw MJPEG video", mjpeg_probe, "mjpg,mjpeg,mpo", AV_CODEC_ID_MJPEG, AVFMT_GENERIC_INDEX|AVFMT_NOTIMESTAMPS)
#endif
#if CONFIG_MLP_DEMUXER
@@ -183,7 +212,7 @@ AVInputFormat ff_mlp_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("raw MLP"),
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
- .flags = AVFMT_GENERIC_INDEX,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
.extensions = "mlp",
.raw_codec_id = AV_CODEC_ID_MLP,
};
@@ -195,7 +224,7 @@ AVInputFormat ff_truehd_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("raw TrueHD"),
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
- .flags = AVFMT_GENERIC_INDEX,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS,
.extensions = "thd",
.raw_codec_id = AV_CODEC_ID_TRUEHD,
};
@@ -207,12 +236,12 @@ AVInputFormat ff_shorten_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("raw Shorten"),
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
- .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
+ .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK|AVFMT_NOTIMESTAMPS,
.extensions = "shn",
.raw_codec_id = AV_CODEC_ID_SHORTEN,
};
#endif
#if CONFIG_VC1_DEMUXER
-FF_DEF_RAWVIDEO_DEMUXER(vc1, "raw VC-1", NULL, "vc1", AV_CODEC_ID_VC1)
+FF_DEF_RAWVIDEO_DEMUXER2(vc1, "raw VC-1", NULL, "vc1", AV_CODEC_ID_VC1, AVFMT_GENERIC_INDEX|AVFMT_NOTIMESTAMPS)
#endif
diff --git a/libavformat/rawdec.h b/libavformat/rawdec.h
index a5487784c9..a464bbb432 100644
--- a/libavformat/rawdec.h
+++ b/libavformat/rawdec.h
@@ -2,20 +2,20 @@
* RAW demuxers
* Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,7 +30,7 @@ typedef struct FFRawVideoDemuxerContext {
const AVClass *class; /**< Class for private options. */
char *video_size; /**< String describing video size, set by a private option. */
char *pixel_format; /**< Set by a private option. */
- char *framerate; /**< String describing framerate, set by a private option. */
+ AVRational framerate; /**< AVRational describing framerate, set by a private option. */
} FFRawVideoDemuxerContext;
extern const AVOption ff_rawvideo_options[];
@@ -41,6 +41,8 @@ int ff_raw_audio_read_header(AVFormatContext *s);
int ff_raw_video_read_header(AVFormatContext *s);
+int ff_raw_data_read_header(AVFormatContext *s);
+
#define FF_RAWVIDEO_DEMUXER_CLASS(name)\
static const AVClass name ## _demuxer_class = {\
.class_name = #name " demuxer",\
@@ -49,7 +51,7 @@ static const AVClass name ## _demuxer_class = {\
.version = LIBAVUTIL_VERSION_INT,\
};
-#define FF_DEF_RAWVIDEO_DEMUXER(shortname, longname, probe, ext, id)\
+#define FF_DEF_RAWVIDEO_DEMUXER2(shortname, longname, probe, ext, id, flag)\
FF_RAWVIDEO_DEMUXER_CLASS(shortname)\
AVInputFormat ff_ ## shortname ## _demuxer = {\
.name = #shortname,\
@@ -58,10 +60,36 @@ AVInputFormat ff_ ## shortname ## _demuxer = {\
.read_header = ff_raw_video_read_header,\
.read_packet = ff_raw_read_partial_packet,\
.extensions = ext,\
- .flags = AVFMT_GENERIC_INDEX,\
+ .flags = flag,\
.raw_codec_id = id,\
.priv_data_size = sizeof(FFRawVideoDemuxerContext),\
.priv_class = &shortname ## _demuxer_class,\
};
+#define FF_DEF_RAWVIDEO_DEMUXER(shortname, longname, probe, ext, id)\
+FF_DEF_RAWVIDEO_DEMUXER2(shortname, longname, probe, ext, id, AVFMT_GENERIC_INDEX)
+
+#define FF_RAWSUB_DEMUXER_CLASS(name)\
+static const AVClass name ## _demuxer_class = {\
+ .class_name = #name " demuxer",\
+ .item_name = av_default_item_name,\
+ .option = NULL,\
+ .version = LIBAVUTIL_VERSION_INT,\
+};
+
+#define FF_DEF_RAWSUB_DEMUXER(shortname, longname, probe, ext, id, flag)\
+FF_RAWVIDEO_DEMUXER_CLASS(shortname)\
+AVInputFormat ff_ ## shortname ## _demuxer = {\
+ .name = #shortname,\
+ .long_name = NULL_IF_CONFIG_SMALL(longname),\
+ .read_probe = probe,\
+ .read_header = ff_raw_data_read_header,\
+ .read_packet = ff_raw_read_partial_packet,\
+ .extensions = ext,\
+ .flags = flag,\
+ .raw_codec_id = id,\
+ .priv_data_size = 0,\
+ .priv_class = &shortname ## _demuxer_class,\
+};
+
#endif /* AVFORMAT_RAWDEC_H */
diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c
index 5d6164656d..9b77cdcab2 100644
--- a/libavformat/rawenc.c
+++ b/libavformat/rawenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2005 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,16 @@ int ff_raw_write_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
+static int force_one_stream(AVFormatContext *s)
+{
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "%s files have exactly one stream\n",
+ s->oformat->name);
+ return AVERROR(EINVAL);
+ }
+ return 0;
+}
+
/* Note: Do not forget to add new entries to the Makefile as well. */
#if CONFIG_AC3_MUXER
@@ -39,6 +49,7 @@ AVOutputFormat ff_ac3_muxer = {
.extensions = "ac3",
.audio_codec = AV_CODEC_ID_AC3,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -51,6 +62,7 @@ AVOutputFormat ff_adx_muxer = {
.extensions = "adx",
.audio_codec = AV_CODEC_ID_ADPCM_ADX,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -63,6 +75,17 @@ AVOutputFormat ff_cavsvideo_muxer = {
.extensions = "cavs",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_CAVS,
+ .write_header = force_one_stream,
+ .write_packet = ff_raw_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
+
+#if CONFIG_DATA_MUXER
+AVOutputFormat ff_data_muxer = {
+ .name = "data",
+ .long_name = NULL_IF_CONFIG_SMALL("raw data"),
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -75,6 +98,7 @@ AVOutputFormat ff_dirac_muxer = {
.extensions = "drc",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_DIRAC,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -87,6 +111,7 @@ AVOutputFormat ff_dnxhd_muxer = {
.extensions = "dnxhd",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_DNXHD,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -100,6 +125,7 @@ AVOutputFormat ff_dts_muxer = {
.extensions = "dts",
.audio_codec = AV_CODEC_ID_DTS,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -113,6 +139,7 @@ AVOutputFormat ff_eac3_muxer = {
.extensions = "eac3",
.audio_codec = AV_CODEC_ID_EAC3,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -126,6 +153,21 @@ AVOutputFormat ff_g722_muxer = {
.extensions = "g722",
.audio_codec = AV_CODEC_ID_ADPCM_G722,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
+ .write_packet = ff_raw_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
+
+#if CONFIG_G723_1_MUXER
+AVOutputFormat ff_g723_1_muxer = {
+ .name = "g723_1",
+ .long_name = NULL_IF_CONFIG_SMALL("raw G.723.1"),
+ .mime_type = "audio/g723",
+ .extensions = "tco,rco",
+ .audio_codec = AV_CODEC_ID_G723_1,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -139,6 +181,7 @@ AVOutputFormat ff_h261_muxer = {
.extensions = "h261",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_H261,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -152,6 +195,7 @@ AVOutputFormat ff_h263_muxer = {
.extensions = "h263",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_H263,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -161,9 +205,10 @@ AVOutputFormat ff_h263_muxer = {
AVOutputFormat ff_h264_muxer = {
.name = "h264",
.long_name = NULL_IF_CONFIG_SMALL("raw H.264 video"),
- .extensions = "h264",
+ .extensions = "h264,264",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_H264,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -201,6 +246,7 @@ AVOutputFormat ff_mjpeg_muxer = {
.extensions = "mjpg,mjpeg",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_MJPEG,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -213,6 +259,7 @@ AVOutputFormat ff_mlp_muxer = {
.extensions = "mlp",
.audio_codec = AV_CODEC_ID_MLP,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -226,6 +273,7 @@ AVOutputFormat ff_mpeg1video_muxer = {
.extensions = "mpg,mpeg,m1v",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_MPEG1VIDEO,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -238,6 +286,7 @@ AVOutputFormat ff_mpeg2video_muxer = {
.extensions = "m2v",
.audio_codec = AV_CODEC_ID_NONE,
.video_codec = AV_CODEC_ID_MPEG2VIDEO,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
@@ -255,18 +304,6 @@ AVOutputFormat ff_rawvideo_muxer = {
};
#endif
-#if CONFIG_SRT_MUXER
-AVOutputFormat ff_srt_muxer = {
- .name = "srt",
- .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
- .mime_type = "application/x-subrip",
- .extensions = "srt",
- .write_packet = ff_raw_write_packet,
- .flags = AVFMT_NOTIMESTAMPS,
- .subtitle_codec = AV_CODEC_ID_SRT,
-};
-#endif
-
#if CONFIG_TRUEHD_MUXER
AVOutputFormat ff_truehd_muxer = {
.name = "truehd",
@@ -274,6 +311,20 @@ AVOutputFormat ff_truehd_muxer = {
.extensions = "thd",
.audio_codec = AV_CODEC_ID_TRUEHD,
.video_codec = AV_CODEC_ID_NONE,
+ .write_header = force_one_stream,
+ .write_packet = ff_raw_write_packet,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
+
+#if CONFIG_VC1_MUXER
+AVOutputFormat ff_vc1_muxer = {
+ .name = "vc1",
+ .long_name = NULL_IF_CONFIG_SMALL("raw VC-1 video"),
+ .extensions = "vc1",
+ .audio_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_VC1,
+ .write_header = force_one_stream,
.write_packet = ff_raw_write_packet,
.flags = AVFMT_NOTIMESTAMPS,
};
diff --git a/libavformat/rawenc.h b/libavformat/rawenc.h
index daa5489da8..b5523090b8 100644
--- a/libavformat/rawenc.h
+++ b/libavformat/rawenc.h
@@ -2,20 +2,20 @@
* RAW muxers
* Copyright (C) 2007 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rawvideodec.c b/libavformat/rawvideodec.c
index 5f372c9a2c..cbcae43c72 100644
--- a/libavformat/rawvideodec.c
+++ b/libavformat/rawvideodec.c
@@ -2,20 +2,20 @@
* RAW video demuxer
* Copyright (c) 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,18 +27,16 @@
typedef struct RawVideoDemuxerContext {
const AVClass *class; /**< Class for private options. */
- char *video_size; /**< String describing video size, set by a private option. */
+ int width, height; /**< Integers describing video size, set by a private option. */
char *pixel_format; /**< Set by a private option. */
- char *framerate; /**< String describing framerate, set by a private option. */
+ AVRational framerate; /**< AVRational describing framerate, set by a private option. */
} RawVideoDemuxerContext;
static int rawvideo_read_header(AVFormatContext *ctx)
{
RawVideoDemuxerContext *s = ctx->priv_data;
- int width = 0, height = 0, ret = 0;
enum AVPixelFormat pix_fmt;
- AVRational framerate;
AVStream *st;
st = avformat_new_stream(ctx, NULL);
@@ -49,29 +47,19 @@ static int rawvideo_read_header(AVFormatContext *ctx)
st->codec->codec_id = ctx->iformat->raw_codec_id;
- if (s->video_size &&
- (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Couldn't parse video size.\n");
- return ret;
- }
-
if ((pix_fmt = av_get_pix_fmt(s->pixel_format)) == AV_PIX_FMT_NONE) {
av_log(ctx, AV_LOG_ERROR, "No such pixel format: %s.\n",
s->pixel_format);
return AVERROR(EINVAL);
}
- if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Could not parse framerate: %s.\n",
- s->framerate);
- return ret;
- }
-
- avpriv_set_pts_info(st, 64, framerate.den, framerate.num);
+ avpriv_set_pts_info(st, 64, s->framerate.den, s->framerate.num);
- st->codec->width = width;
- st->codec->height = height;
+ st->codec->width = s->width;
+ st->codec->height = s->height;
st->codec->pix_fmt = pix_fmt;
+ st->codec->bit_rate = av_rescale_q(avpicture_get_size(st->codec->pix_fmt, s->width, s->height),
+ (AVRational){8,1}, st->time_base);
return 0;
}
@@ -101,9 +89,9 @@ static int rawvideo_read_packet(AVFormatContext *s, AVPacket *pkt)
#define OFFSET(x) offsetof(RawVideoDemuxerContext, x)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption rawvideo_options[] = {
- { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "pixel_format", "", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = "yuv420p"}, 0, 0, DEC },
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+ { "video_size", "set frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "pixel_format", "set pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = "yuv420p"}, 0, 0, DEC },
+ { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
{ NULL },
};
diff --git a/libavformat/rdt.c b/libavformat/rdt.c
index 5478f88fc6..bb56a8ba81 100644
--- a/libavformat/rdt.c
+++ b/libavformat/rdt.c
@@ -2,20 +2,20 @@
* Realmedia RTSP protocol (RDT) support.
* Copyright (c) 2007 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -98,7 +98,7 @@ ff_rdt_calc_response_and_checksum(char response[41], char chksum[9],
unsigned char zres[16],
buf[64] = { 0xa1, 0xe9, 0x14, 0x9d, 0x0e, 0x6b, 0x3b, 0x59 };
#define XOR_TABLE_SIZE 37
- const unsigned char xor_table[XOR_TABLE_SIZE] = {
+ static const unsigned char xor_table[XOR_TABLE_SIZE] = {
0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
@@ -176,7 +176,7 @@ rdt_load_mdpr (PayloadContext *rdt, AVStream *st, int rule_nr)
size = rdt->mlti_data_size;
avio_seek(&pb, 0, SEEK_SET);
}
- if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, rdt->rmst[st->index], size) < 0)
+ if (ff_rm_read_mdpr_codecdata(rdt->rmctx, &pb, st, rdt->rmst[st->index], size, NULL) < 0)
return -1;
return 0;
@@ -301,7 +301,7 @@ rdt_parse_packet (AVFormatContext *ctx, PayloadContext *rdt, AVStream *st,
if (rdt->audio_pkt_cnt == 0) {
int pos, rmflags;
- ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
+ ffio_init_context(&pb, (uint8_t *)buf, len, 0, NULL, NULL, NULL, NULL);
rmflags = (flags & RTP_FLAG_KEY) ? 2 : 0;
res = ff_rm_parse_packet (rdt->rmctx, &pb, st, rdt->rmst[st->index], len, pkt,
&seq, rmflags, *timestamp);
@@ -521,8 +521,19 @@ ff_real_parse_sdp_a_line (AVFormatContext *s, int stream_index,
real_parse_asm_rulebook(s, s->streams[stream_index], p);
}
+
+
static av_cold int rdt_init(AVFormatContext *s, int st_index, PayloadContext *rdt)
{
+ int ret;
+
+ rdt->rmctx = avformat_alloc_context();
+ if (!rdt->rmctx)
+ return AVERROR(ENOMEM);
+
+ if ((ret = ff_copy_whitelists(rdt->rmctx, s)) < 0)
+ return ret;
+
return avformat_open_input(&rdt->rmctx, "", &ff_rdt_demuxer, NULL);
}
diff --git a/libavformat/rdt.h b/libavformat/rdt.h
index bd168903f5..ce6026f49c 100644
--- a/libavformat/rdt.h
+++ b/libavformat/rdt.h
@@ -2,20 +2,20 @@
* Realmedia RTSP (RDT) definitions
* Copyright (c) 2007 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/realtextdec.c b/libavformat/realtextdec.c
new file mode 100644
index 0000000000..fff85d6ba9
--- /dev/null
+++ b/libavformat/realtextdec.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * RealText subtitle demuxer
+ * @see http://service.real.com/help/library/guides/ProductionGuide/prodguide/htmfiles/realtext.htm
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} RealTextContext;
+
+static int realtext_probe(AVProbeData *p)
+{
+ char buf[7];
+ FFTextReader tr;
+ ff_text_init_buf(&tr, p->buf, p->buf_size);
+ ff_text_read(&tr, buf, sizeof(buf));
+
+ return !av_strncasecmp(buf, "<window", 7) ? AVPROBE_SCORE_EXTENSION : 0;
+}
+
+static int read_ts(const char *s)
+{
+ int hh, mm, ss, ms;
+
+ if (sscanf(s, "%u:%u:%u.%u", &hh, &mm, &ss, &ms) == 4) return (hh*3600 + mm*60 + ss) * 100 + ms;
+ if (sscanf(s, "%u:%u:%u" , &hh, &mm, &ss ) == 3) return (hh*3600 + mm*60 + ss) * 100;
+ if (sscanf(s, "%u:%u.%u", &mm, &ss, &ms) == 3) return ( mm*60 + ss) * 100 + ms;
+ if (sscanf(s, "%u:%u" , &mm, &ss ) == 2) return ( mm*60 + ss) * 100;
+ if (sscanf(s, "%u.%u", &ss, &ms) == 2) return ( ss) * 100 + ms;
+ return strtol(s, NULL, 10) * 100;
+}
+
+static int realtext_read_header(AVFormatContext *s)
+{
+ RealTextContext *rt = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ AVBPrint buf;
+ char c = 0;
+ int res = 0, duration = read_ts("60"); // default duration is 60 seconds
+ FFTextReader tr;
+ ff_text_init_avio(s, &tr, s->pb);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 100);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_REALTEXT;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ while (!ff_text_eof(&tr)) {
+ AVPacket *sub;
+ const int64_t pos = ff_text_pos(&tr) - (c != 0);
+ int n = ff_smil_extract_next_text_chunk(&tr, &buf, &c);
+
+ if (n == 0)
+ break;
+
+ if (!av_strncasecmp(buf.str, "<window", 7)) {
+ /* save header to extradata */
+ const char *p = ff_smil_get_attr_ptr(buf.str, "duration");
+
+ if (p)
+ duration = read_ts(p);
+ st->codec->extradata = av_strdup(buf.str);
+ if (!st->codec->extradata) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ st->codec->extradata_size = buf.len + 1;
+ } else {
+ /* if we just read a <time> tag, introduce a new event, otherwise merge
+ * with the previous one */
+ int merge = !av_strncasecmp(buf.str, "<time", 5) ? 0 : 1;
+ sub = ff_subtitles_queue_insert(&rt->q, buf.str, buf.len, merge);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ if (!merge) {
+ const char *begin = ff_smil_get_attr_ptr(buf.str, "begin");
+ const char *end = ff_smil_get_attr_ptr(buf.str, "end");
+
+ sub->pos = pos;
+ sub->pts = begin ? read_ts(begin) : 0;
+ sub->duration = end ? (read_ts(end) - sub->pts) : duration;
+ }
+ }
+ av_bprint_clear(&buf);
+ }
+ ff_subtitles_queue_finalize(&rt->q);
+
+end:
+ av_bprint_finalize(&buf, NULL);
+ return res;
+}
+
+static int realtext_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ RealTextContext *rt = s->priv_data;
+ return ff_subtitles_queue_read_packet(&rt->q, pkt);
+}
+
+static int realtext_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ RealTextContext *rt = s->priv_data;
+ return ff_subtitles_queue_seek(&rt->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int realtext_read_close(AVFormatContext *s)
+{
+ RealTextContext *rt = s->priv_data;
+ ff_subtitles_queue_clean(&rt->q);
+ return 0;
+}
+
+AVInputFormat ff_realtext_demuxer = {
+ .name = "realtext",
+ .long_name = NULL_IF_CONFIG_SMALL("RealText subtitle format"),
+ .priv_data_size = sizeof(RealTextContext),
+ .read_probe = realtext_probe,
+ .read_header = realtext_read_header,
+ .read_packet = realtext_read_packet,
+ .read_seek2 = realtext_read_seek,
+ .read_close = realtext_read_close,
+ .extensions = "rt",
+};
diff --git a/libavformat/redspark.c b/libavformat/redspark.c
new file mode 100644
index 0000000000..13a7b37d25
--- /dev/null
+++ b/libavformat/redspark.c
@@ -0,0 +1,170 @@
+/*
+ * RedSpark demuxer
+ * Copyright (c) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/bytestream.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "avio.h"
+#include "internal.h"
+
+#define HEADER_SIZE 4096
+
+typedef struct RedSparkContext {
+ int samples_count;
+} RedSparkContext;
+
+static int redspark_probe(AVProbeData *p)
+{
+ uint32_t key, data;
+ uint8_t header[8];
+
+ /* Decrypt first 8 bytes of the header */
+ data = AV_RB32(p->buf);
+ data = data ^ (key = data ^ 0x52656453);
+ AV_WB32(header, data);
+ key = (key << 11) | (key >> 21);
+
+ data = AV_RB32(p->buf + 4) ^ (((key << 3) | (key >> 29)) + key);
+ AV_WB32(header + 4, data);
+
+ if (AV_RB64(header) == AV_RB64("RedSpark"))
+ return AVPROBE_SCORE_MAX;
+
+ return 0;
+}
+
+static int redspark_read_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ RedSparkContext *redspark = s->priv_data;
+ AVCodecContext *codec;
+ GetByteContext gbc;
+ int i, coef_off, ret = 0;
+ uint32_t key, data;
+ uint8_t *header, *pbc;
+ AVStream *st;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ codec = st->codec;
+
+ header = av_malloc(HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!header)
+ return AVERROR(ENOMEM);
+ pbc = header;
+
+ /* Decrypt header */
+ data = avio_rb32(pb);
+ data = data ^ (key = data ^ 0x52656453);
+ bytestream_put_be32(&pbc, data);
+ key = (key << 11) | (key >> 21);
+
+ for (i = 4; i < HEADER_SIZE; i += 4) {
+ data = avio_rb32(pb) ^ (key = ((key << 3) | (key >> 29)) + key);
+ bytestream_put_be32(&pbc, data);
+ }
+
+ codec->codec_id = AV_CODEC_ID_ADPCM_THP;
+ codec->codec_type = AVMEDIA_TYPE_AUDIO;
+
+ bytestream2_init(&gbc, header, HEADER_SIZE);
+ bytestream2_seek(&gbc, 0x3c, SEEK_SET);
+ codec->sample_rate = bytestream2_get_be32u(&gbc);
+ if (codec->sample_rate <= 0 || codec->sample_rate > 96000) {
+ av_log(s, AV_LOG_ERROR, "Invalid sample rate: %d\n", codec->sample_rate);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ st->duration = bytestream2_get_be32u(&gbc) * 14;
+ redspark->samples_count = 0;
+ bytestream2_skipu(&gbc, 10);
+ codec->channels = bytestream2_get_byteu(&gbc);
+ if (!codec->channels) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ coef_off = 0x54 + codec->channels * 8;
+ if (bytestream2_get_byteu(&gbc)) // Loop flag
+ coef_off += 16;
+
+ if (coef_off + codec->channels * (32 + 14) > HEADER_SIZE) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
+ if (ff_alloc_extradata(codec, 32 * codec->channels)) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ /* Get the ADPCM table */
+ bytestream2_seek(&gbc, coef_off, SEEK_SET);
+ for (i = 0; i < codec->channels; i++) {
+ if (bytestream2_get_bufferu(&gbc, codec->extradata + i * 32, 32) != 32) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ bytestream2_skipu(&gbc, 14);
+ }
+
+ avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
+
+fail:
+ av_free(header);
+
+ return ret;
+}
+
+static int redspark_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVCodecContext *codec = s->streams[0]->codec;
+ RedSparkContext *redspark = s->priv_data;
+ uint32_t size = 8 * codec->channels;
+ int ret;
+
+ if (avio_feof(s->pb) || redspark->samples_count == s->streams[0]->duration)
+ return AVERROR_EOF;
+
+ ret = av_get_packet(s->pb, pkt, size);
+ if (ret != size) {
+ av_free_packet(pkt);
+ return AVERROR(EIO);
+ }
+
+ pkt->duration = 14;
+ redspark->samples_count += pkt->duration;
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_redspark_demuxer = {
+ .name = "redspark",
+ .long_name = NULL_IF_CONFIG_SMALL("RedSpark"),
+ .priv_data_size = sizeof(RedSparkContext),
+ .read_probe = redspark_probe,
+ .read_header = redspark_read_header,
+ .read_packet = redspark_read_packet,
+ .extensions = "rsd",
+};
diff --git a/libavformat/replaygain.c b/libavformat/replaygain.c
index 98e7aad81b..807f851542 100644
--- a/libavformat/replaygain.c
+++ b/libavformat/replaygain.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/replaygain.h b/libavformat/replaygain.h
index ea56c17f06..ceacb21421 100644
--- a/libavformat/replaygain.h
+++ b/libavformat/replaygain.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 6e77453b86..850e2574c4 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -2,20 +2,20 @@
* RIFF common functions and data
* Copyright (c) 2000 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,10 @@
#include "riff.h"
/* Note: When encoding, the first matching tag is used, so order is
- * important if multiple tags are possible for a given codec. */
+ * important if multiple tags are possible for a given codec.
+ * Note also that this list is used for more than just riff, other
+ * files use it as well.
+ */
const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('H', '2', '6', '4') },
{ AV_CODEC_ID_H264, MKTAG('h', '2', '6', '4') },
@@ -40,6 +43,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H264, MKTAG('G', 'A', 'V', 'C') }, /* GeoVision camera */
{ AV_CODEC_ID_H264, MKTAG('U', 'M', 'S', 'V') },
{ AV_CODEC_ID_H264, MKTAG('t', 's', 'h', 'd') },
+ { AV_CODEC_ID_H264, MKTAG('I', 'N', 'M', 'C') },
{ AV_CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
{ AV_CODEC_ID_H263, MKTAG('X', '2', '6', '3') },
{ AV_CODEC_ID_H263, MKTAG('T', '2', '6', '3') },
@@ -51,8 +55,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
{ AV_CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* Intel H.263 */
{ AV_CODEC_ID_H261, MKTAG('H', '2', '6', '1') },
- { AV_CODEC_ID_H263P, MKTAG('U', '2', '6', '3') },
- { AV_CODEC_ID_H263P, MKTAG('v', 'i', 'v', '1') },
+ { AV_CODEC_ID_H263, MKTAG('U', '2', '6', '3') },
{ AV_CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0') },
@@ -91,7 +94,6 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'M', 'K', '2') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'Y', 'M', '4') },
{ AV_CODEC_ID_MPEG4, MKTAG('D', 'I', 'G', 'I') },
- { AV_CODEC_ID_MPEG4, MKTAG('I', 'N', 'M', 'C') },
/* Ephv MPEG-4 */
{ AV_CODEC_ID_MPEG4, MKTAG('E', 'P', 'H', 'V') },
{ AV_CODEC_ID_MPEG4, MKTAG('E', 'M', '4', 'A') },
@@ -183,7 +185,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') },
{ AV_CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') },
{ AV_CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') },
- { AV_CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') },
+ { AV_CODEC_ID_AVRN, MKTAG('A', 'V', 'R', 'n') },
{ AV_CODEC_ID_MJPEG, MKTAG('A', 'C', 'D', 'V') },
{ AV_CODEC_ID_MJPEG, MKTAG('Q', 'I', 'V', 'G') },
/* SL M-JPEG */
@@ -243,7 +245,11 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_R10K, MKTAG('R', '1', '0', 'k') },
{ AV_CODEC_ID_R210, MKTAG('r', '2', '1', '0') },
{ AV_CODEC_ID_V210, MKTAG('v', '2', '1', '0') },
+ { AV_CODEC_ID_V308, MKTAG('v', '3', '0', '8') },
+ { AV_CODEC_ID_V408, MKTAG('v', '4', '0', '8') },
+ { AV_CODEC_ID_AYUV, MKTAG('A', 'Y', 'U', 'V') },
{ AV_CODEC_ID_V410, MKTAG('v', '4', '1', '0') },
+ { AV_CODEC_ID_YUV4, MKTAG('y', 'u', 'v', '4') },
{ AV_CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') },
{ AV_CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') },
{ AV_CODEC_ID_INDEO4, MKTAG('I', 'V', '4', '1') },
@@ -281,6 +287,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_TRUEMOTION1, MKTAG('P', 'V', 'E', 'Z') },
{ AV_CODEC_ID_MSZH, MKTAG('M', 'S', 'Z', 'H') },
{ AV_CODEC_ID_ZLIB, MKTAG('Z', 'L', 'I', 'B') },
+ { AV_CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') },
{ AV_CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') },
{ AV_CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') },
{ AV_CODEC_ID_FLV1, MKTAG('S', '2', '6', '3') },
@@ -331,16 +338,20 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_DPX, MKTAG('d', 'p', 'x', ' ') },
{ AV_CODEC_ID_KGV1, MKTAG('K', 'G', 'V', '1') },
{ AV_CODEC_ID_LAGARITH, MKTAG('L', 'A', 'G', 'S') },
+ { AV_CODEC_ID_AMV, MKTAG('A', 'M', 'V', 'F') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'A') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'R', 'G') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '0') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'Y', '2') },
+ /* Ut Video version 13.0.1 BT.709 codecs */
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '0') },
{ AV_CODEC_ID_UTVIDEO, MKTAG('U', 'L', 'H', '2') },
+ { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'Y', '2') },
{ AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') },
{ AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') },
{ AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') },
{ AV_CODEC_ID_ZEROCODEC, MKTAG('Z', 'E', 'C', 'O') },
+ { AV_CODEC_ID_Y41P, MKTAG('Y', '4', '1', 'P') },
{ AV_CODEC_ID_FLIC, MKTAG('A', 'F', 'L', 'C') },
{ AV_CODEC_ID_MSS1, MKTAG('M', 'S', 'S', '1') },
{ AV_CODEC_ID_MSA1, MKTAG('M', 'S', 'A', '1') },
@@ -349,6 +360,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_CLLC, MKTAG('C', 'L', 'L', 'C') },
{ AV_CODEC_ID_MSS2, MKTAG('M', 'S', 'S', '2') },
{ AV_CODEC_ID_SVQ3, MKTAG('S', 'V', 'Q', '3') },
+ { AV_CODEC_ID_012V, MKTAG('0', '1', '2', 'v') },
+ { AV_CODEC_ID_012V, MKTAG('a', '1', '2', 'v') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '2') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '3') },
{ AV_CODEC_ID_G2M, MKTAG('G', '2', 'M', '4') },
@@ -373,13 +386,15 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_PCM_ALAW, 0x0006 },
{ AV_CODEC_ID_PCM_MULAW, 0x0007 },
{ AV_CODEC_ID_WMAVOICE, 0x000A },
+ { AV_CODEC_ID_ADPCM_IMA_OKI, 0x0010 },
{ AV_CODEC_ID_ADPCM_IMA_WAV, 0x0011 },
/* must come after adpcm_ima_wav in this list */
{ AV_CODEC_ID_PCM_ZORK, 0x0011 },
+ { AV_CODEC_ID_ADPCM_IMA_OKI, 0x0017 },
{ AV_CODEC_ID_ADPCM_YAMAHA, 0x0020 },
{ AV_CODEC_ID_TRUESPEECH, 0x0022 },
{ AV_CODEC_ID_GSM_MS, 0x0031 },
- { AV_CODEC_ID_GSM_MS, 0x0032 },
+ { AV_CODEC_ID_GSM_MS, 0x0032 }, /* msn audio */
{ AV_CODEC_ID_AMR_NB, 0x0038 }, /* rogue format number */
{ AV_CODEC_ID_G723_1, 0x0042 },
{ AV_CODEC_ID_ADPCM_G726, 0x0045 },
@@ -394,7 +409,9 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_ADPCM_G726, 0x0064 },
{ AV_CODEC_ID_ADPCM_IMA_WAV, 0x0069 },
{ AV_CODEC_ID_METASOUND, 0x0075 },
+ { AV_CODEC_ID_G729, 0x0083 },
{ AV_CODEC_ID_AAC, 0x00ff },
+ { AV_CODEC_ID_G723_1, 0x0111 },
{ AV_CODEC_ID_SIPR, 0x0130 },
{ AV_CODEC_ID_WMAV1, 0x0160 },
{ AV_CODEC_ID_WMAV2, 0x0161 },
@@ -413,7 +430,11 @@ const AVCodecTag ff_codec_wav_tags[] = {
{ AV_CODEC_ID_AAC, 0x1600 },
{ AV_CODEC_ID_AAC_LATM, 0x1602 },
{ AV_CODEC_ID_AC3, 0x2000 },
+ /* There is no Microsoft Format Tag for E-AC3, the GUID has to be used */
+ { AV_CODEC_ID_EAC3, 0x2000 },
{ AV_CODEC_ID_DTS, 0x2001 },
+ { AV_CODEC_ID_SONIC, 0x2048 },
+ { AV_CODEC_ID_SONIC_LS, 0x2048 },
{ AV_CODEC_ID_PCM_MULAW, 0x6c75 },
{ AV_CODEC_ID_AAC, 0x706d },
{ AV_CODEC_ID_AAC, 0x4143 },
@@ -454,3 +475,11 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void)
{
return ff_codec_wav_tags;
}
+
+const AVCodecGuid ff_codec_wav_guids[] = {
+ { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } },
+ { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } },
+ { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } },
+ { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } },
+ { AV_CODEC_ID_NONE }
+};
diff --git a/libavformat/riff.h b/libavformat/riff.h
index ddfb0fa664..ae5ecef4c5 100644
--- a/libavformat/riff.h
+++ b/libavformat/riff.h
@@ -2,20 +2,20 @@
* RIFF common functions and data
* copyright (c) 2000 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,14 +43,28 @@ void ff_end_tag(AVIOContext *pb, int64_t start);
* bits_per_encoded_sample fields. Does not read extradata.
* @return codec tag
*/
-int ff_get_bmp_header(AVIOContext *pb, AVStream *st);
+int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize);
+
+void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf, int ignore_extradata);
+
+/**
+ * Tell ff_put_wav_header() to use WAVEFORMATEX even for PCM codecs.
+ */
+#define FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX 0x00000001
+
+/**
+ * Write WAVEFORMAT header structure.
+ *
+ * @param flags a combination of FF_PUT_WAV_HEADER_* constants
+ *
+ * @return the size or -1 on error
+ */
+int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags);
-void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc, const AVCodecTag *tags, int for_asf);
-int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc);
enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps);
-int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size);
+int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, int big_endian);
-extern const AVCodecTag ff_codec_bmp_tags[];
+extern const AVCodecTag ff_codec_bmp_tags[]; // exposed through avformat_get_riff_video_tags()
extern const AVCodecTag ff_codec_wav_tags[];
void ff_parse_specific_params(AVStream *st, int *au_rate, int *au_ssize, int *au_scale);
@@ -77,10 +91,13 @@ typedef struct AVCodecGuid {
extern const AVCodecGuid ff_codec_wav_guids[];
#define FF_PRI_GUID \
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x " \
+ "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}"
#define FF_ARG_GUID(g) \
g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7], \
+ g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15],\
+ g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], \
g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]
#define FF_MEDIASUBTYPE_BASE_GUID \
@@ -91,10 +108,9 @@ static av_always_inline int ff_guidcmp(const void *g1, const void *g2)
return memcmp(g1, g2, sizeof(ff_asf_guid));
}
-static av_always_inline int ff_get_guid(AVIOContext *s, ff_asf_guid *g)
-{
- return avio_read(s, *g, sizeof(*g));
-}
+int ff_get_guid(AVIOContext *s, ff_asf_guid *g);
+void ff_put_guid(AVIOContext *s, const ff_asf_guid *g);
+const ff_asf_guid *ff_get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid);
enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid);
diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c
index 74f93acedf..f44df1e672 100644
--- a/libavformat/riffdec.c
+++ b/libavformat/riffdec.c
@@ -2,20 +2,20 @@
* RIFF demuxing functions and data
* Copyright (c) 2000 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,13 +29,15 @@
#include "avio_internal.h"
#include "riff.h"
-const AVCodecGuid ff_codec_wav_guids[] = {
- { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } },
- { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } },
- { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } },
- { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } },
- { AV_CODEC_ID_NONE }
-};
+int ff_get_guid(AVIOContext *s, ff_asf_guid *g)
+{
+ av_assert0(sizeof(*g) == 16); //compiler will optimize this out
+ if (avio_read(s, *g, sizeof(*g)) < (int)sizeof(*g)) {
+ memset(*g, 0, sizeof(*g));
+ return AVERROR_INVALIDDATA;
+ }
+ return 0;
+}
enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid)
{
@@ -57,7 +59,10 @@ enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid)
static void parse_waveformatex(AVIOContext *pb, AVCodecContext *c)
{
ff_asf_guid subformat;
- c->bits_per_coded_sample = avio_rl16(pb);
+ int bps = avio_rl16(pb);
+ if (bps)
+ c->bits_per_coded_sample = bps;
+
c->channel_layout = avio_rl32(pb); /* dwChannelMask */
ff_get_guid(pb, &subformat);
@@ -75,20 +80,37 @@ static void parse_waveformatex(AVIOContext *pb, AVCodecContext *c)
}
}
-int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size)
+/* "big_endian" values are needed for RIFX file format */
+int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, int big_endian)
{
int id;
- id = avio_rl16(pb);
+ if (size < 14)
+ avpriv_request_sample(codec, "wav header size < 14");
+
codec->codec_type = AVMEDIA_TYPE_AUDIO;
- codec->channels = avio_rl16(pb);
- codec->sample_rate = avio_rl32(pb);
- codec->bit_rate = avio_rl32(pb) * 8;
- codec->block_align = avio_rl16(pb);
+ if (!big_endian) {
+ id = avio_rl16(pb);
+ codec->channels = avio_rl16(pb);
+ codec->sample_rate = avio_rl32(pb);
+ codec->bit_rate = avio_rl32(pb) * 8;
+ codec->block_align = avio_rl16(pb);
+ } else {
+ id = avio_rb16(pb);
+ codec->channels = avio_rb16(pb);
+ codec->sample_rate = avio_rb32(pb);
+ codec->bit_rate = avio_rb32(pb) * 8;
+ codec->block_align = avio_rb16(pb);
+ }
if (size == 14) { /* We're dealing with plain vanilla WAVEFORMAT */
codec->bits_per_coded_sample = 8;
- } else
- codec->bits_per_coded_sample = avio_rl16(pb);
+ } else {
+ if (!big_endian) {
+ codec->bits_per_coded_sample = avio_rl16(pb);
+ } else {
+ codec->bits_per_coded_sample = avio_rb16(pb);
+ }
+ }
if (id == 0xFFFE) {
codec->codec_tag = 0;
} else {
@@ -98,6 +120,10 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size)
}
if (size >= 18) { /* We're obviously dealing with WAVEFORMATEX */
int cbSize = avio_rl16(pb); /* cbSize */
+ if (big_endian) {
+ avpriv_report_missing_feature(codec, "WAVEFORMATEX support for RIFX files\n");
+ return AVERROR_PATCHWELCOME;
+ }
size -= 18;
cbSize = FFMIN(size, cbSize);
if (cbSize >= 22 && id == 0xfffe) { /* WAVEFORMATEXTENSIBLE */
@@ -105,14 +131,10 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size)
cbSize -= 22;
size -= 22;
}
- codec->extradata_size = cbSize;
if (cbSize > 0) {
- av_free(codec->extradata);
- codec->extradata = av_mallocz(codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!codec->extradata)
+ av_freep(&codec->extradata);
+ if (ff_get_extradata(codec, pb, cbSize) < 0)
return AVERROR(ENOMEM);
- avio_read(pb, codec->extradata, codec->extradata_size);
size -= cbSize;
}
@@ -132,7 +154,7 @@ int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size)
codec->sample_rate = 0;
}
/* override bits_per_coded_sample for G.726 */
- if (codec->codec_id == AV_CODEC_ID_ADPCM_G726)
+ if (codec->codec_id == AV_CODEC_ID_ADPCM_G726 && codec->sample_rate)
codec->bits_per_coded_sample = codec->bit_rate / codec->sample_rate;
return 0;
@@ -155,10 +177,11 @@ enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps)
return id;
}
-int ff_get_bmp_header(AVIOContext *pb, AVStream *st)
+int ff_get_bmp_header(AVIOContext *pb, AVStream *st, unsigned *esize)
{
int tag1;
- avio_rl32(pb); /* size */
+ if(esize) *esize = avio_rl32(pb);
+ else avio_rl32(pb);
st->codec->width = avio_rl32(pb);
st->codec->height = (int32_t)avio_rl32(pb);
avio_rl16(pb); /* planes */
@@ -189,12 +212,23 @@ int ff_read_riff_info(AVFormatContext *s, int64_t size)
chunk_code = avio_rl32(pb);
chunk_size = avio_rl32(pb);
-
+ if (avio_feof(pb)) {
+ if (chunk_code || chunk_size) {
+ av_log(s, AV_LOG_WARNING, "INFO subchunk truncated\n");
+ return AVERROR_INVALIDDATA;
+ }
+ return AVERROR_EOF;
+ }
if (chunk_size > end ||
end - chunk_size < cur ||
chunk_size == UINT_MAX) {
- av_log(s, AV_LOG_WARNING, "too big INFO subchunk\n");
- break;
+ avio_seek(pb, -9, SEEK_CUR);
+ chunk_code = avio_rl32(pb);
+ chunk_size = avio_rl32(pb);
+ if (chunk_size > end || end - chunk_size < cur || chunk_size == UINT_MAX) {
+ av_log(s, AV_LOG_WARNING, "too big INFO subchunk\n");
+ return AVERROR_INVALIDDATA;
+ }
}
chunk_size += (chunk_size & 1);
@@ -209,7 +243,7 @@ int ff_read_riff_info(AVFormatContext *s, int64_t size)
continue;
}
- value = av_malloc(chunk_size + 1);
+ value = av_mallocz(chunk_size + 1);
if (!value) {
av_log(s, AV_LOG_ERROR,
"out of memory, unable to read INFO tag\n");
@@ -219,14 +253,10 @@ int ff_read_riff_info(AVFormatContext *s, int64_t size)
AV_WL32(key, chunk_code);
if (avio_read(pb, value, chunk_size) != chunk_size) {
- av_free(value);
av_log(s, AV_LOG_WARNING,
"premature end of file while reading INFO tag\n");
- break;
}
- value[chunk_size] = 0;
-
av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
}
diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c
index 81b3b2da12..d429df0ba3 100644
--- a/libavformat/riffenc.c
+++ b/libavformat/riffenc.c
@@ -2,20 +2,20 @@
* RIFF muxing functions
* Copyright (c) 2000 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,7 @@
int64_t ff_start_tag(AVIOContext *pb, const char *tag)
{
ffio_wfourcc(pb, tag);
- avio_wl32(pb, 0);
+ avio_wl32(pb, -1);
return avio_tell(pb);
}
@@ -39,18 +39,23 @@ void ff_end_tag(AVIOContext *pb, int64_t start)
{
int64_t pos;
+ av_assert0((start&1) == 0);
+
pos = avio_tell(pb);
+ if (pos & 1)
+ avio_w8(pb, 0);
avio_seek(pb, start - 4, SEEK_SET);
avio_wl32(pb, (uint32_t)(pos - start));
- avio_seek(pb, pos, SEEK_SET);
+ avio_seek(pb, FFALIGN(pos, 2), SEEK_SET);
}
/* WAVEFORMATEX header */
/* returns the size or -1 on error */
-int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
+int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags)
{
int bps, blkalign, bytespersec, frame_size;
- int hdrsize = 18;
+ int hdrsize;
+ int64_t hdrstart = avio_tell(pb);
int waveformatextensible;
uint8_t temp[256];
uint8_t *riff_extradata = temp;
@@ -66,6 +71,7 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
waveformatextensible = (enc->channels > 2 && enc->channel_layout) ||
enc->sample_rate > 48000 ||
+ enc->codec_id == AV_CODEC_ID_EAC3 ||
av_get_bits_per_sample(enc->codec_id) > 16;
if (waveformatextensible)
@@ -75,8 +81,10 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
avio_wl16(pb, enc->channels);
avio_wl32(pb, enc->sample_rate);
- if (enc->codec_id == AV_CODEC_ID_MP2 ||
- enc->codec_id == AV_CODEC_ID_MP3 ||
+ if (enc->codec_id == AV_CODEC_ID_ATRAC3 ||
+ enc->codec_id == AV_CODEC_ID_G723_1 ||
+ enc->codec_id == AV_CODEC_ID_MP2 ||
+ enc->codec_id == AV_CODEC_ID_MP3 ||
enc->codec_id == AV_CODEC_ID_GSM_MS) {
bps = 0;
} else {
@@ -97,9 +105,13 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
if (enc->codec_id == AV_CODEC_ID_MP2) {
blkalign = frame_size;
} else if (enc->codec_id == AV_CODEC_ID_MP3) {
- blkalign = 576 * (enc->sample_rate <= 24000 ? 1 : 2);
+ blkalign = 576 * (enc->sample_rate <= (24000 + 32000)/2 ? 1 : 2);
} else if (enc->codec_id == AV_CODEC_ID_AC3) {
blkalign = 3840; /* maximum bytes per frame */
+ } else if (enc->codec_id == AV_CODEC_ID_AAC) {
+ blkalign = 768 * enc->channels; /* maximum bytes per frame */
+ } else if (enc->codec_id == AV_CODEC_ID_G723_1) {
+ blkalign = 24;
} else if (enc->block_align != 0) { /* specified by the codec */
blkalign = enc->block_align;
} else
@@ -111,6 +123,8 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
enc->codec_id == AV_CODEC_ID_PCM_F64LE ||
enc->codec_id == AV_CODEC_ID_PCM_S16LE) {
bytespersec = enc->sample_rate * blkalign;
+ } else if (enc->codec_id == AV_CODEC_ID_G723_1) {
+ bytespersec = 800;
} else {
bytespersec = enc->bit_rate / 8;
}
@@ -118,14 +132,12 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
avio_wl16(pb, blkalign); /* block align */
avio_wl16(pb, bps); /* bits per sample */
if (enc->codec_id == AV_CODEC_ID_MP3) {
- hdrsize += 12;
bytestream_put_le16(&riff_extradata, 1); /* wID */
bytestream_put_le32(&riff_extradata, 2); /* fdwFlags */
bytestream_put_le16(&riff_extradata, 1152); /* nBlockSize */
bytestream_put_le16(&riff_extradata, 1); /* nFramesPerBlock */
bytestream_put_le16(&riff_extradata, 1393); /* nCodecDelay */
} else if (enc->codec_id == AV_CODEC_ID_MP2) {
- hdrsize += 22;
/* fwHeadLayer */
bytestream_put_le16(&riff_extradata, 2);
/* dwHeadBitrate */
@@ -142,34 +154,45 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
bytestream_put_le32(&riff_extradata, 0);
/* dwPTSHigh */
bytestream_put_le32(&riff_extradata, 0);
+ } else if (enc->codec_id == AV_CODEC_ID_G723_1) {
+ bytestream_put_le32(&riff_extradata, 0x9ace0002); /* extradata needed for msacm g723.1 codec */
+ bytestream_put_le32(&riff_extradata, 0xaea2f732);
+ bytestream_put_le16(&riff_extradata, 0xacde);
} else if (enc->codec_id == AV_CODEC_ID_GSM_MS ||
enc->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
- hdrsize += 2;
/* wSamplesPerBlock */
bytestream_put_le16(&riff_extradata, frame_size);
} else if (enc->extradata_size) {
riff_extradata_start = enc->extradata;
riff_extradata = enc->extradata + enc->extradata_size;
- hdrsize += enc->extradata_size;
}
/* write WAVEFORMATEXTENSIBLE extensions */
if (waveformatextensible) {
- hdrsize += 22;
+ int write_channel_mask = enc->strict_std_compliance < FF_COMPLIANCE_NORMAL ||
+ enc->channel_layout < 0x40000;
/* 22 is WAVEFORMATEXTENSIBLE size */
avio_wl16(pb, riff_extradata - riff_extradata_start + 22);
/* ValidBitsPerSample || SamplesPerBlock || Reserved */
avio_wl16(pb, bps);
/* dwChannelMask */
- avio_wl32(pb, enc->channel_layout);
+ avio_wl32(pb, write_channel_mask ? enc->channel_layout : 0);
/* GUID + next 3 */
+ if (enc->codec_id == AV_CODEC_ID_EAC3) {
+ ff_put_guid(pb, ff_get_codec_guid(enc->codec_id, ff_codec_wav_guids));
+ } else {
avio_wl32(pb, enc->codec_tag);
avio_wl32(pb, 0x00100000);
avio_wl32(pb, 0xAA000080);
avio_wl32(pb, 0x719B3800);
- } else {
+ }
+ } else if ((flags & FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX) ||
+ enc->codec_tag != 0x0001 /* PCM */ ||
+ riff_extradata - riff_extradata_start) {
+ /* WAVEFORMATEX */
avio_wl16(pb, riff_extradata - riff_extradata_start); /* cbSize */
- }
+ } /* else PCMWAVEFORMAT */
avio_write(pb, riff_extradata_start, riff_extradata - riff_extradata_start);
+ hdrsize = avio_tell(pb) - hdrstart;
if (hdrsize & 1) {
hdrsize++;
avio_w8(pb, 0);
@@ -180,29 +203,35 @@ int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc)
/* BITMAPINFOHEADER header */
void ff_put_bmp_header(AVIOContext *pb, AVCodecContext *enc,
- const AVCodecTag *tags, int for_asf)
+ const AVCodecTag *tags, int for_asf, int ignore_extradata)
{
+ int keep_height = enc->extradata_size >= 9 &&
+ !memcmp(enc->extradata + enc->extradata_size - 9, "BottomUp", 9);
+ int extradata_size = enc->extradata_size - 9*keep_height;
+
/* size */
- avio_wl32(pb, 40 + enc->extradata_size);
+ avio_wl32(pb, 40 + (ignore_extradata ? 0 :extradata_size));
avio_wl32(pb, enc->width);
//We always store RGB TopDown
- avio_wl32(pb, enc->codec_tag ? enc->height : -enc->height);
+ avio_wl32(pb, enc->codec_tag || keep_height ? enc->height : -enc->height);
/* planes */
avio_wl16(pb, 1);
/* depth */
avio_wl16(pb, enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24);
/* compression type */
avio_wl32(pb, enc->codec_tag);
- avio_wl32(pb, enc->width * enc->height * 3);
+ avio_wl32(pb, (enc->width * enc->height * (enc->bits_per_coded_sample ? enc->bits_per_coded_sample : 24)+7) / 8);
avio_wl32(pb, 0);
avio_wl32(pb, 0);
avio_wl32(pb, 0);
avio_wl32(pb, 0);
- avio_write(pb, enc->extradata, enc->extradata_size);
+ if (!ignore_extradata) {
+ avio_write(pb, enc->extradata, extradata_size);
- if (!for_asf && enc->extradata_size & 1)
- avio_w8(pb, 0);
+ if (!for_asf && extradata_size & 1)
+ avio_w8(pb, 0);
+ }
}
void ff_parse_specific_params(AVStream *st, int *au_rate,
@@ -240,8 +269,8 @@ void ff_parse_specific_params(AVStream *st, int *au_rate,
void ff_riff_write_info_tag(AVIOContext *pb, const char *tag, const char *str)
{
- int len = strlen(str);
- if (len > 0) {
+ size_t len = strlen(str);
+ if (len > 0 && len < UINT32_MAX) {
len++;
ffio_wfourcc(pb, tag);
avio_wl32(pb, len);
@@ -290,3 +319,19 @@ void ff_riff_write_info(AVFormatContext *s)
ff_riff_write_info_tag(s->pb, t->key, t->value);
ff_end_tag(pb, list_pos);
}
+
+void ff_put_guid(AVIOContext *s, const ff_asf_guid *g)
+{
+ av_assert0(sizeof(*g) == 16);
+ avio_write(s, *g, sizeof(*g));
+}
+
+const ff_asf_guid *ff_get_codec_guid(enum AVCodecID id, const AVCodecGuid *av_guid)
+{
+ int i;
+ for (i = 0; av_guid[i].id != AV_CODEC_ID_NONE; i++) {
+ if (id == av_guid[i].id)
+ return &(av_guid[i].guid);
+ }
+ return NULL;
+}
diff --git a/libavformat/rl2.c b/libavformat/rl2.c
index 5d30bf8bd6..d354339ea3 100644
--- a/libavformat/rl2.c
+++ b/libavformat/rl2.c
@@ -2,20 +2,20 @@
* RL2 Format Demuxer
* Copyright (c) 2008 Sascha Sommer (saschasommer@freenet.de)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -109,10 +109,6 @@ static av_cold int rl2_read_header(AVFormatContext *s)
rate = avio_rl16(pb);
channels = avio_rl16(pb);
def_sound_size = avio_rl16(pb);
- if (!channels || channels > 42) {
- av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", channels);
- return AVERROR_INVALIDDATA;
- }
/** setup video stream */
st = avformat_new_stream(s, NULL);
@@ -131,17 +127,16 @@ static av_cold int rl2_read_header(AVFormatContext *s)
if(signature == RLV3_TAG && back_size > 0)
st->codec->extradata_size += back_size;
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if(!st->codec->extradata)
+ if(ff_get_extradata(st->codec, pb, st->codec->extradata_size) < 0)
return AVERROR(ENOMEM);
- if(avio_read(pb,st->codec->extradata,st->codec->extradata_size) !=
- st->codec->extradata_size)
- return AVERROR(EIO);
-
/** setup audio stream if present */
if(sound_rate){
+ if (!channels || channels > 42) {
+ av_log(s, AV_LOG_ERROR, "Invalid number of channels: %d\n", channels);
+ return AVERROR_INVALIDDATA;
+ }
+
pts_num = def_sound_size;
pts_den = rate;
@@ -235,7 +230,7 @@ static int rl2_read_packet(AVFormatContext *s,
}
if(stream_id == -1)
- return AVERROR(EIO);
+ return AVERROR_EOF;
++rl2->index_pos[stream_id];
diff --git a/libavformat/rm.c b/libavformat/rm.c
index 761be3f556..0591a1735a 100644
--- a/libavformat/rm.c
+++ b/libavformat/rm.c
@@ -2,20 +2,20 @@
* "Real" compatible muxer and demuxer common code.
* Copyright (c) 2009 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rm.h b/libavformat/rm.h
index 3aa17732f1..7b080e2a36 100644
--- a/libavformat/rm.h
+++ b/libavformat/rm.h
@@ -2,20 +2,20 @@
* "Real" compatible muxer and demuxer.
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -50,7 +50,7 @@ extern AVInputFormat ff_rdt_demuxer;
*/
int ff_rm_read_mdpr_codecdata (AVFormatContext *s, AVIOContext *pb,
AVStream *st, RMStream *rst,
- unsigned int codec_data_size);
+ unsigned int codec_data_size, const uint8_t *mime);
/**
* Parse one rm-stream packet from the input bytestream.
diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c
index cab75fd338..832f15daa4 100644
--- a/libavformat/rmdec.c
+++ b/libavformat/rmdec.c
@@ -2,31 +2,33 @@
* "Real" compatible demuxer.
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/internal.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "rmsipr.h"
#include "rm.h"
@@ -63,6 +65,8 @@ typedef struct RMDemuxContext {
int audio_pkt_cnt; ///< Output packet counter
} RMDemuxContext;
+static int rm_read_close(AVFormatContext *s);
+
static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len)
{
int i;
@@ -84,14 +88,12 @@ static void get_str8(AVIOContext *pb, char *buf, int buf_size)
static int rm_read_extradata(AVIOContext *pb, AVCodecContext *avctx, unsigned size)
{
- if (size >= 1<<24)
+ if (size >= 1<<24) {
+ av_log(avctx, AV_LOG_ERROR, "extradata size %u too large\n", size);
return -1;
- avctx->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
+ }
+ if (ff_get_extradata(avctx, pb, size) < 0)
return AVERROR(ENOMEM);
- avctx->extradata_size = avio_read(pb, avctx->extradata, size);
- if (avctx->extradata_size != size)
- return AVERROR(EIO);
return 0;
}
@@ -99,6 +101,7 @@ static void rm_read_metadata(AVFormatContext *s, AVIOContext *pb, int wide)
{
char buf[1024];
int i;
+
for (i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
int len = wide ? avio_rb16(pb) : avio_r8(pb);
get_strl(pb, buf, sizeof(buf), len);
@@ -130,9 +133,12 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
/* ra type header */
version = avio_rb16(pb); /* version */
if (version == 3) {
+ unsigned bytes_per_minute;
int header_size = avio_rb16(pb);
int64_t startpos = avio_tell(pb);
- avio_skip(pb, 14);
+ avio_skip(pb, 8);
+ bytes_per_minute = avio_rb16(pb);
+ avio_skip(pb, 4);
rm_read_metadata(s, pb, 0);
if ((startpos + header_size) >= avio_tell(pb) + 2) {
// fourcc (should always be "lpcJ")
@@ -142,6 +148,8 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
// Skip extra header crap (this should never happen)
if ((startpos + header_size) > avio_tell(pb))
avio_skip(pb, header_size + startpos - avio_tell(pb));
+ if (bytes_per_minute)
+ st->codec->bit_rate = 8LL * bytes_per_minute / 60;
st->codec->sample_rate = 8000;
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
@@ -151,6 +159,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
} else {
int flavor, sub_packet_h, coded_framesize, sub_packet_size;
int codecdata_length;
+ unsigned bytes_per_minute;
/* old version (4) */
avio_skip(pb, 2); /* unused */
avio_rb32(pb); /* .ra4 */
@@ -160,7 +169,11 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
flavor= avio_rb16(pb); /* add codec info / flavor */
ast->coded_framesize = coded_framesize = avio_rb32(pb); /* coded frame size */
avio_rb32(pb); /* ??? */
- avio_rb32(pb); /* ??? */
+ bytes_per_minute = avio_rb32(pb);
+ if (version == 4) {
+ if (bytes_per_minute)
+ st->codec->bit_rate = 8LL * bytes_per_minute / 60;
+ }
avio_rb32(pb); /* ??? */
ast->sub_packet_h = sub_packet_h = avio_rb16(pb); /* 1 */
st->codec->block_align= avio_rb16(pb); /* frame size */
@@ -177,6 +190,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
avio_read(pb, buf, 4);
buf[4] = 0;
} else {
+ AV_WL32(buf, 0);
get_str8(pb, buf, sizeof(buf)); /* desc */
ast->deint_id = AV_RL32(buf);
get_str8(pb, buf, sizeof(buf)); /* desc */
@@ -199,13 +213,17 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
st->need_parsing = AVSTREAM_PARSE_HEADERS;
case AV_CODEC_ID_ATRAC3:
case AV_CODEC_ID_SIPR:
- avio_rb16(pb); avio_r8(pb);
- if (version == 5)
- avio_r8(pb);
- codecdata_length = avio_rb32(pb);
- if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){
- av_log(s, AV_LOG_ERROR, "codecdata_length too large\n");
- return -1;
+ if (read_all) {
+ codecdata_length = 0;
+ } else {
+ avio_rb16(pb); avio_r8(pb);
+ if (version == 5)
+ avio_r8(pb);
+ codecdata_length = avio_rb32(pb);
+ if(codecdata_length + FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)codecdata_length){
+ av_log(s, AV_LOG_ERROR, "codecdata_length too large\n");
+ return -1;
+ }
}
ast->audio_framesize = st->codec->block_align;
@@ -225,6 +243,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
}
if ((ret = rm_read_extradata(pb, st->codec, codecdata_length)) < 0)
return ret;
+
break;
case AV_CODEC_ID_AAC:
avio_rb16(pb); avio_r8(pb);
@@ -242,27 +261,23 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
}
break;
}
- if (ast->deint_id == DEINT_ID_INT4 ||
- ast->deint_id == DEINT_ID_GENR ||
- ast->deint_id == DEINT_ID_SIPR) {
- if (st->codec->block_align <= 0 ||
- ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX ||
- ast->audio_framesize * sub_packet_h < st->codec->block_align)
- return AVERROR_INVALIDDATA;
- if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0)
- return AVERROR(ENOMEM);
- }
switch (ast->deint_id) {
case DEINT_ID_INT4:
if (ast->coded_framesize > ast->audio_framesize ||
sub_packet_h <= 1 ||
ast->coded_framesize * sub_packet_h > (2 + (sub_packet_h & 1)) * ast->audio_framesize)
return AVERROR_INVALIDDATA;
+ if (ast->coded_framesize * sub_packet_h != 2*ast->audio_framesize) {
+ avpriv_request_sample(s, "mismatching interleaver parameters");
+ return AVERROR_INVALIDDATA;
+ }
break;
case DEINT_ID_GENR:
if (ast->sub_packet_size <= 0 ||
ast->sub_packet_size > ast->audio_framesize)
return AVERROR_INVALIDDATA;
+ if (ast->audio_framesize % ast->sub_packet_size)
+ return AVERROR_INVALIDDATA;
break;
case DEINT_ID_SIPR:
case DEINT_ID_INT0:
@@ -270,9 +285,19 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
case DEINT_ID_VBRF:
break;
default:
- av_log(NULL, 0 ,"Unknown interleaver %"PRIX32"\n", ast->deint_id);
+ av_log(s, AV_LOG_ERROR ,"Unknown interleaver %"PRIX32"\n", ast->deint_id);
return AVERROR_INVALIDDATA;
}
+ if (ast->deint_id == DEINT_ID_INT4 ||
+ ast->deint_id == DEINT_ID_GENR ||
+ ast->deint_id == DEINT_ID_SIPR) {
+ if (st->codec->block_align <= 0 ||
+ ast->audio_framesize * sub_packet_h > (unsigned)INT_MAX ||
+ ast->audio_framesize * sub_packet_h < st->codec->block_align)
+ return AVERROR_INVALIDDATA;
+ if (av_new_packet(&ast->pkt, ast->audio_framesize * sub_packet_h) < 0)
+ return AVERROR(ENOMEM);
+ }
if (read_all) {
avio_r8(pb);
@@ -286,16 +311,36 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb,
int ff_rm_read_mdpr_codecdata(AVFormatContext *s, AVIOContext *pb,
AVStream *st, RMStream *rst,
- unsigned int codec_data_size)
+ unsigned int codec_data_size, const uint8_t *mime)
{
unsigned int v;
int size;
int64_t codec_pos;
int ret;
+ if (codec_data_size > INT_MAX)
+ return AVERROR_INVALIDDATA;
+ if (codec_data_size == 0)
+ return 0;
+
avpriv_set_pts_info(st, 64, 1, 1000);
codec_pos = avio_tell(pb);
v = avio_rb32(pb);
+
+ if (v == MKBETAG('M', 'L', 'T', 'I')) {
+ int number_of_streams = avio_rb16(pb);
+ int number_of_mdpr;
+ int i;
+ for (i = 0; i<number_of_streams; i++)
+ avio_rb16(pb);
+ number_of_mdpr = avio_rb16(pb);
+ if (number_of_mdpr != 1) {
+ avpriv_request_sample(s, "MLTI with multiple MDPR");
+ }
+ avio_rb32(pb);
+ v = avio_rb32(pb);
+ }
+
if (v == MKTAG(0xfd, 'a', 'r', '.')) {
/* ra type header */
if (rm_read_audio_stream_info(s, pb, st, rst, 0))
@@ -309,6 +354,33 @@ int ff_rm_read_mdpr_codecdata(AVFormatContext *s, AVIOContext *pb,
st->codec->codec_tag = AV_RL32(st->codec->extradata);
st->codec->codec_id = ff_codec_get_id(ff_rm_codec_tags,
st->codec->codec_tag);
+ } else if(mime && !strcmp(mime, "logical-fileinfo")){
+ int stream_count, rule_count, property_count, i;
+ ff_free_stream(s, st);
+ if (avio_rb16(pb) != 0) {
+ av_log(s, AV_LOG_WARNING, "Unsupported version\n");
+ goto skip;
+ }
+ stream_count = avio_rb16(pb);
+ avio_skip(pb, 6*stream_count);
+ rule_count = avio_rb16(pb);
+ avio_skip(pb, 2*rule_count);
+ property_count = avio_rb16(pb);
+ for(i=0; i<property_count; i++){
+ uint8_t name[128], val[128];
+ avio_rb32(pb);
+ if (avio_rb16(pb) != 0) {
+ av_log(s, AV_LOG_WARNING, "Unsupported Name value property version\n");
+ goto skip; //FIXME skip just this one
+ }
+ get_str8(pb, name, sizeof(name));
+ switch(avio_rb32(pb)) {
+ case 2: get_strl(pb, val, sizeof(val), avio_rb16(pb));
+ av_dict_set(&s->metadata, name, val, 0);
+ break;
+ default: avio_skip(pb, avio_rb16(pb));
+ }
+ }
} else {
int fps;
if (avio_rl32(pb) != MKTAG('V', 'I', 'D', 'O')) {
@@ -336,6 +408,9 @@ int ff_rm_read_mdpr_codecdata(AVFormatContext *s, AVIOContext *pb,
if (fps > 0) {
av_reduce(&st->avg_frame_rate.den, &st->avg_frame_rate.num,
0x10000, fps, (1 << 30) - 1);
+#if FF_API_R_FRAME_RATE
+ st->r_frame_rate = st->avg_frame_rate;
+#endif
} else if (s->error_recognition & AV_EF_EXPLODE) {
av_log(s, AV_LOG_ERROR, "Invalid framerate\n");
return AVERROR_INVALIDDATA;
@@ -345,7 +420,11 @@ int ff_rm_read_mdpr_codecdata(AVFormatContext *s, AVIOContext *pb,
skip:
/* skip codec info */
size = avio_tell(pb) - codec_pos;
- avio_skip(pb, codec_data_size - size);
+ if (codec_data_size >= size) {
+ avio_skip(pb, codec_data_size - size);
+ } else {
+ av_log(s, AV_LOG_WARNING, "codec_data_size %u < size %d\n", codec_data_size, size);
+ }
return 0;
}
@@ -432,8 +511,9 @@ static int rm_read_header(AVFormatContext *s)
int tag_size;
unsigned int start_time, duration;
unsigned int data_off = 0, indx_off = 0;
- char buf[128];
+ char buf[128], mime[128];
int flags = 0;
+ int ret = -1;
tag = avio_rl32(pb);
if (tag == MKTAG('.', 'r', 'a', 0xfd)) {
@@ -447,8 +527,8 @@ static int rm_read_header(AVFormatContext *s)
avio_skip(pb, tag_size - 8);
for(;;) {
- if (pb->eof_reached)
- return -1;
+ if (avio_feof(pb))
+ goto fail;
tag = avio_rl32(pb);
tag_size = avio_rb32(pb);
avio_rb16(pb);
@@ -460,7 +540,7 @@ static int rm_read_header(AVFormatContext *s)
tag,
tag_size);
if (tag_size < 10 && tag != MKTAG('D', 'A', 'T', 'A'))
- return -1;
+ goto fail;
switch(tag) {
case MKTAG('P', 'R', 'O', 'P'):
/* file header */
@@ -469,7 +549,8 @@ static int rm_read_header(AVFormatContext *s)
avio_rb32(pb); /* max packet size */
avio_rb32(pb); /* avg packet size */
avio_rb32(pb); /* nb packets */
- avio_rb32(pb); /* duration */
+ duration = avio_rb32(pb); /* duration */
+ s->duration = av_rescale(duration, AV_TIME_BASE, 1000);
avio_rb32(pb); /* preroll */
indx_off = avio_rb32(pb); /* index offset */
data_off = avio_rb32(pb); /* data offset */
@@ -481,8 +562,10 @@ static int rm_read_header(AVFormatContext *s)
break;
case MKTAG('M', 'D', 'P', 'R'):
st = avformat_new_stream(s, NULL);
- if (!st)
- return AVERROR(ENOMEM);
+ if (!st) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
st->id = avio_rb16(pb);
avio_rb32(pb); /* max bit rate */
st->codec->bit_rate = avio_rb32(pb); /* bit rate */
@@ -493,15 +576,17 @@ static int rm_read_header(AVFormatContext *s)
duration = avio_rb32(pb); /* duration */
st->start_time = start_time;
st->duration = duration;
+ if(duration>0)
+ s->duration = AV_NOPTS_VALUE;
get_str8(pb, buf, sizeof(buf)); /* desc */
- get_str8(pb, buf, sizeof(buf)); /* mimetype */
+ get_str8(pb, mime, sizeof(mime)); /* mimetype */
st->codec->codec_type = AVMEDIA_TYPE_DATA;
st->priv_data = ff_rm_alloc_rmstream();
if (!st->priv_data)
return AVERROR(ENOMEM);
if (ff_rm_read_mdpr_codecdata(s, s->pb, st, st->priv_data,
- avio_rb32(pb)) < 0)
- return -1;
+ avio_rb32(pb), mime) < 0)
+ goto fail;
break;
case MKTAG('D', 'A', 'T', 'A'):
goto header_end;
@@ -526,6 +611,10 @@ static int rm_read_header(AVFormatContext *s)
}
return 0;
+
+fail:
+ rm_read_close(s);
+ return ret;
}
static int get_num(AVIOContext *pb, int *len)
@@ -547,13 +636,13 @@ static int get_num(AVIOContext *pb, int *len)
/* multiple of 20 bytes for ra144 (ugly) */
#define RAW_PACKET_SIZE 1000
-static int sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){
+static int rm_sync(AVFormatContext *s, int64_t *timestamp, int *flags, int *stream_index, int64_t *pos){
RMDemuxContext *rm = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
uint32_t state=0xFFFFFFFF;
- while(!pb->eof_reached){
+ while(!avio_feof(pb)){
int len, num, i;
*pos= avio_tell(pb) - 3;
if(rm->remaining_len > 0){
@@ -620,8 +709,10 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
AVPacket *pkt, int len, int *pseq,
int64_t *timestamp)
{
- int hdr, seq, pic_num, len2, pos;
+ int hdr;
+ int seq = 0, pic_num = 0, len2 = 0, pos = 0; //init to silence compiler warning
int type;
+ int ret;
hdr = avio_r8(pb); len--;
type = hdr >> 6;
@@ -634,34 +725,47 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
pos = get_num(pb, &len);
pic_num = avio_r8(pb); len--;
}
- if(len<0)
+ if(len<0) {
+ av_log(s, AV_LOG_ERROR, "Insufficient data\n");
return -1;
+ }
rm->remaining_len = len;
if(type&1){ // frame, not slice
if(type == 3){ // frame as a part of packet
len= len2;
*timestamp = pos;
}
- if(rm->remaining_len < len)
+ if(rm->remaining_len < len) {
+ av_log(s, AV_LOG_ERROR, "Insufficient remaining len\n");
return -1;
+ }
rm->remaining_len -= len;
if(av_new_packet(pkt, len + 9) < 0)
return AVERROR(EIO);
pkt->data[0] = 0;
AV_WL32(pkt->data + 1, 1);
AV_WL32(pkt->data + 5, 0);
- avio_read(pb, pkt->data + 9, len);
+ if ((ret = avio_read(pb, pkt->data + 9, len)) != len) {
+ av_free_packet(pkt);
+ av_log(s, AV_LOG_ERROR, "Failed to read %d bytes\n", len);
+ return ret < 0 ? ret : AVERROR(EIO);
+ }
return 0;
}
//now we have to deal with single slice
*pseq = seq;
if((seq & 0x7F) == 1 || vst->curpic_num != pic_num){
+ if (len2 > ffio_limit(pb, len2)) {
+ av_log(s, AV_LOG_ERROR, "Impossibly sized packet\n");
+ return AVERROR_INVALIDDATA;
+ }
vst->slices = ((hdr & 0x3F) << 1) + 1;
vst->videobufsize = len2 + 8*vst->slices + 1;
av_free_packet(&vst->pkt); //FIXME this should be output.
if(av_new_packet(&vst->pkt, vst->videobufsize) < 0)
return AVERROR(ENOMEM);
+ memset(vst->pkt.data, 0, vst->pkt.size);
vst->videobufpos = 8*vst->slices + 1;
vst->cur_slice = 0;
vst->curpic_num = pic_num;
@@ -670,12 +774,18 @@ static int rm_assemble_video_frame(AVFormatContext *s, AVIOContext *pb,
if(type == 2)
len = FFMIN(len, pos);
- if(++vst->cur_slice > vst->slices)
+ if(++vst->cur_slice > vst->slices) {
+ av_log(s, AV_LOG_ERROR, "cur slice %d, too large\n", vst->cur_slice);
return 1;
+ }
+ if(!vst->pkt.data)
+ return AVERROR(ENOMEM);
AV_WL32(vst->pkt.data - 7 + 8*vst->cur_slice, 1);
AV_WL32(vst->pkt.data - 3 + 8*vst->cur_slice, vst->videobufpos - 8*vst->slices - 1);
- if(vst->videobufpos + len > vst->videobufsize)
+ if(vst->videobufpos + len > vst->videobufsize) {
+ av_log(s, AV_LOG_ERROR, "outside videobufsize\n");
return 1;
+ }
if (avio_read(pb, vst->pkt.data + vst->videobufpos, len) != len)
return AVERROR(EIO);
vst->videobufpos += len;
@@ -720,17 +830,29 @@ rm_ac3_swap_bytes (AVStream *st, AVPacket *pkt)
}
}
+static int readfull(AVFormatContext *s, AVIOContext *pb, uint8_t *dst, int n) {
+ int ret = avio_read(pb, dst, n);
+ if (ret != n) {
+ if (ret >= 0) memset(dst + ret, 0, n - ret);
+ else memset(dst , 0, n);
+ av_log(s, AV_LOG_ERROR, "Failed to fully read block\n");
+ }
+ return ret;
+}
+
int
ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
AVStream *st, RMStream *ast, int len, AVPacket *pkt,
int *seq, int flags, int64_t timestamp)
{
RMDemuxContext *rm = s->priv_data;
+ int ret;
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
rm->current_stream= st->id;
- if(rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, &timestamp))
- return -1; //got partial frame
+ ret = rm_assemble_video_frame(s, pb, rm, ast, pkt, len, seq, &timestamp);
+ if(ret)
+ return ret < 0 ? ret : -1; //got partial frame or error
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if ((ast->deint_id == DEINT_ID_GENR) ||
(ast->deint_id == DEINT_ID_INT4) ||
@@ -750,14 +872,14 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
switch (ast->deint_id) {
case DEINT_ID_INT4:
for (x = 0; x < h/2; x++)
- avio_read(pb, ast->pkt.data+x*2*w+y*cfs, cfs);
+ readfull(s, pb, ast->pkt.data+x*2*w+y*cfs, cfs);
break;
case DEINT_ID_GENR:
for (x = 0; x < w/sps; x++)
- avio_read(pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps);
+ readfull(s, pb, ast->pkt.data+sps*(h*x+((h+1)/2)*(y&1)+(y>>1)), sps);
break;
case DEINT_ID_SIPR:
- avio_read(pb, ast->pkt.data + y * w, w);
+ readfull(s, pb, ast->pkt.data + y * w, w);
break;
}
@@ -782,11 +904,14 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb,
} else
return -1;
} else {
- av_get_packet(pb, pkt, len);
+ if ((ret = av_get_packet(pb, pkt, len)) < 0)
+ return ret;
rm_ac3_swap_bytes(st, pkt);
}
- } else
- av_get_packet(pb, pkt, len);
+ } else {
+ if ((ret = av_get_packet(pb, pkt, len)) < 0)
+ return ret;
+ }
pkt->stream_index = st->index;
@@ -816,12 +941,14 @@ ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb,
{
RMDemuxContext *rm = s->priv_data;
- assert (rm->audio_pkt_cnt > 0);
+ av_assert0 (rm->audio_pkt_cnt > 0);
if (ast->deint_id == DEINT_ID_VBRF ||
- ast->deint_id == DEINT_ID_VBRS)
- av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]);
- else {
+ ast->deint_id == DEINT_ID_VBRS) {
+ int ret = av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]);
+ if (ret < 0)
+ return ret;
+ } else {
int ret = av_new_packet(pkt, st->codec->block_align);
if (ret < 0)
return ret;
@@ -843,7 +970,7 @@ ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb,
static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
RMDemuxContext *rm = s->priv_data;
- AVStream *st;
+ AVStream *st = NULL; // init to silence compiler warning
int i, len, res, seq = 1;
int64_t timestamp, pos;
int flags;
@@ -852,7 +979,9 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
if (rm->audio_pkt_cnt) {
// If there are queued audio packet return them first
st = s->streams[rm->audio_stream_num];
- ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt);
+ res = ff_rm_retrieve_cache(s, s->pb, st, st->priv_data, pkt);
+ if(res < 0)
+ return res;
flags = 0;
} else {
if (rm->old_format) {
@@ -866,16 +995,18 @@ static int rm_read_packet(AVFormatContext *s, AVPacket *pkt)
flags = (seq++ == 1) ? 2 : 0;
pos = avio_tell(s->pb);
} else {
- len=sync(s, &timestamp, &flags, &i, &pos);
+ len = rm_sync(s, &timestamp, &flags, &i, &pos);
if (len > 0)
st = s->streams[i];
}
- if (len <= 0 || s->pb->eof_reached)
+ if (len <= 0 || avio_feof(s->pb))
return AVERROR(EIO);
res = ff_rm_parse_packet (s, s->pb, st, st->priv_data, len, pkt,
&seq, flags, timestamp);
+ if (res < -1)
+ return res;
if((flags&2) && (seq&0x7F) == 1)
av_add_index_entry(st, pos, timestamp, 0, 0, AVINDEX_KEYFRAME);
if (res)
@@ -927,13 +1058,15 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index,
if(rm->old_format)
return AV_NOPTS_VALUE;
- avio_seek(s->pb, pos, SEEK_SET);
+ if (avio_seek(s->pb, pos, SEEK_SET) < 0)
+ return AV_NOPTS_VALUE;
+
rm->remaining_len=0;
for(;;){
int seq=1;
AVStream *st;
- len=sync(s, &dts, &flags, &stream_index2, &pos);
+ len = rm_sync(s, &dts, &flags, &stream_index2, &pos);
if(len<0)
return AV_NOPTS_VALUE;
@@ -959,6 +1092,18 @@ static int64_t rm_read_dts(AVFormatContext *s, int stream_index,
return dts;
}
+static int rm_read_seek(AVFormatContext *s, int stream_index,
+ int64_t pts, int flags)
+{
+ RMDemuxContext *rm = s->priv_data;
+
+ if (ff_seek_frame_binary(s, stream_index, pts, flags) < 0)
+ return -1;
+ rm->audio_pkt_cnt = 0;
+ return 0;
+}
+
+
AVInputFormat ff_rm_demuxer = {
.name = "rm",
.long_name = NULL_IF_CONFIG_SMALL("RealMedia"),
@@ -968,6 +1113,7 @@ AVInputFormat ff_rm_demuxer = {
.read_packet = rm_read_packet,
.read_close = rm_read_close,
.read_timestamp = rm_read_dts,
+ .read_seek = rm_read_seek,
};
AVInputFormat ff_rdt_demuxer = {
diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c
index ad2c17d529..7e4345bac7 100644
--- a/libavformat/rmenc.c
+++ b/libavformat/rmenc.c
@@ -2,20 +2,20 @@
* "Real" compatible muxer.
* Copyright (c) 2000, 2001 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
@@ -102,7 +102,7 @@ static int rv10_write_header(AVFormatContext *ctx,
nb_packets += stream->nb_packets;
packet_total_size += stream->packet_total_size;
/* select maximum duration */
- v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate);
+ v = 1000LL * stream->total_frames / stream->frame_rate;
if (v > duration)
duration = v;
}
@@ -221,8 +221,8 @@ static int rv10_write_header(AVFormatContext *ctx,
coded_frame_size--;
avio_wb32(s, coded_frame_size); /* frame length */
avio_wb32(s, 0x51540); /* unknown */
- avio_wb32(s, 0x249f0); /* unknown */
- avio_wb32(s, 0x249f0); /* unknown */
+ avio_wb32(s, stream->enc->bit_rate / 8 * 60); /* bytes per minute */
+ avio_wb32(s, stream->enc->bit_rate / 8 * 60); /* bytes per minute */
avio_wb16(s, 0x01);
/* frame length : seems to be very important */
avio_wb16(s, coded_frame_size);
@@ -313,6 +313,11 @@ static int rm_write_header(AVFormatContext *s)
int n;
AVCodecContext *codec;
+ if (s->nb_streams > 2) {
+ av_log(s, AV_LOG_ERROR, "At most 2 streams are currently supported for muxing in RM\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
for(n=0;n<s->nb_streams;n++) {
AVStream *st = s->streams[n];
@@ -388,8 +393,8 @@ static int rm_write_video(AVFormatContext *s, const uint8_t *buf, int size, int
not sure I understood everything, but it works !! */
#if 1
if (size > MAX_PACKET_SIZE) {
- avpriv_report_missing_feature(s, "Muxing packets larger than 64 kB");
- return AVERROR(ENOSYS);
+ av_log(s, AV_LOG_ERROR, "Muxing packets larger than 64 kB (%d) is not supported\n", size);
+ return AVERROR_PATCHWELCOME;
}
write_packet_header(s, stream, size + 7 + (size >= 0x4000)*4, key_frame);
/* bit 7: '1' if final packet of a frame converted in several packets */
diff --git a/libavformat/rmsipr.c b/libavformat/rmsipr.c
index 89fbd0e398..14ec8ea606 100644
--- a/libavformat/rmsipr.c
+++ b/libavformat/rmsipr.c
@@ -1,20 +1,20 @@
/*
* tables and functions for demuxing SIPR audio muxed RealMedia style
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rmsipr.h b/libavformat/rmsipr.h
index c8d3d0a236..2837336dbb 100644
--- a/libavformat/rmsipr.h
+++ b/libavformat/rmsipr.h
@@ -1,20 +1,20 @@
/*
* tables and functions for demuxing SIPR audio muxed RealMedia style
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rpl.c b/libavformat/rpl.c
index b72b8d0691..04cb917aef 100644
--- a/libavformat/rpl.c
+++ b/libavformat/rpl.c
@@ -2,20 +2,20 @@
* ARMovie/RPL demuxer
* Copyright (c) 2007 Christian Ohm, 2008 Eli Friedman
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -60,7 +60,7 @@ static int read_line(AVIOContext * pb, char* line, int bufsize)
break;
if (b == '\n') {
line[i] = '\0';
- return 0;
+ return avio_feof(pb) ? -1 : 0;
}
line[i] = b;
}
@@ -170,9 +170,8 @@ static int rpl_read_header(AVFormatContext *s)
vst->codec->codec_id = AV_CODEC_ID_ESCAPE130;
break;
default:
- av_log(s, AV_LOG_WARNING,
- "RPL video format %i not supported yet!\n",
- vst->codec->codec_tag);
+ avpriv_report_missing_feature(s, "Video format %i",
+ vst->codec->codec_tag);
vst->codec->codec_id = AV_CODEC_ID_NONE;
}
@@ -222,11 +221,9 @@ static int rpl_read_header(AVFormatContext *s)
}
break;
}
- if (ast->codec->codec_id == AV_CODEC_ID_NONE) {
- av_log(s, AV_LOG_WARNING,
- "RPL audio format %"PRId32" not supported yet!\n",
- audio_format);
- }
+ if (ast->codec->codec_id == AV_CODEC_ID_NONE)
+ avpriv_request_sample(s, "Audio format %"PRId32,
+ audio_format);
avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate);
} else {
for (i = 0; i < 3; i++)
@@ -254,12 +251,14 @@ static int rpl_read_header(AVFormatContext *s)
// Read the index
avio_seek(pb, chunk_catalog_offset, SEEK_SET);
total_audio_size = 0;
- for (i = 0; i < number_of_chunks; i++) {
+ for (i = 0; !error && i < number_of_chunks; i++) {
int64_t offset, video_size, audio_size;
error |= read_line(pb, line, sizeof(line));
- if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64,
- &offset, &video_size, &audio_size))
+ if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64,
+ &offset, &video_size, &audio_size)) {
error = -1;
+ continue;
+ }
av_add_index_entry(vst, offset, i * rpl->frames_per_chunk,
video_size, rpl->frames_per_chunk, 0);
if (ast)
@@ -279,7 +278,7 @@ static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
AVStream* stream;
AVIndexEntry* index_entry;
- uint32_t ret;
+ int ret;
if (rpl->chunk_part == s->nb_streams) {
rpl->chunk_number++;
@@ -289,7 +288,7 @@ static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
stream = s->streams[rpl->chunk_part];
if (rpl->chunk_number >= stream->nb_index_entries)
- return -1;
+ return AVERROR_EOF;
index_entry = &stream->index_entries[rpl->chunk_number];
@@ -309,6 +308,8 @@ static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(EIO);
ret = av_get_packet(pb, pkt, frame_size);
+ if (ret < 0)
+ return ret;
if (ret != frame_size) {
av_free_packet(pkt);
return AVERROR(EIO);
@@ -324,6 +325,8 @@ static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
}
} else {
ret = av_get_packet(pb, pkt, index_entry->size);
+ if (ret < 0)
+ return ret;
if (ret != index_entry->size) {
av_free_packet(pkt);
return AVERROR(EIO);
diff --git a/libavformat/rsd.c b/libavformat/rsd.c
new file mode 100644
index 0000000000..1eff5de7e6
--- /dev/null
+++ b/libavformat/rsd.c
@@ -0,0 +1,168 @@
+/*
+ * RSD demuxer
+ * Copyright (c) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavcodec/bytestream.h"
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "avio.h"
+#include "internal.h"
+
+static const AVCodecTag rsd_tags[] = {
+ { AV_CODEC_ID_ADPCM_THP, MKTAG('G','A','D','P') },
+ { AV_CODEC_ID_ADPCM_IMA_RAD, MKTAG('R','A','D','P') },
+ { AV_CODEC_ID_PCM_S16BE, MKTAG('P','C','M','B') },
+ { AV_CODEC_ID_PCM_S16LE, MKTAG('P','C','M',' ') },
+ { AV_CODEC_ID_NONE, 0 },
+};
+
+static const uint32_t rsd_unsupported_tags[] = {
+ MKTAG('O','G','G',' '),
+ MKTAG('V','A','G',' '),
+ MKTAG('W','A','D','P'),
+ MKTAG('X','A','D','P'),
+ MKTAG('X','M','A',' '),
+};
+
+static int rsd_probe(AVProbeData *p)
+{
+ if (memcmp(p->buf, "RSD", 3) || p->buf[3] - '0' < 2 || p->buf[3] - '0' > 6)
+ return 0;
+ if (AV_RL32(p->buf + 8) > 256 || !AV_RL32(p->buf + 8))
+ return AVPROBE_SCORE_MAX / 8;
+ if (AV_RL32(p->buf + 16) > 8*48000 || !AV_RL32(p->buf + 16))
+ return AVPROBE_SCORE_MAX / 8;
+ return AVPROBE_SCORE_MAX;
+}
+
+static int rsd_read_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ int i, version, start = 0x800;
+ AVCodecContext *codec;
+ AVStream *st = avformat_new_stream(s, NULL);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(pb, 3); // "RSD"
+ version = avio_r8(pb) - '0';
+
+ codec = st->codec;
+ codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ codec->codec_tag = avio_rl32(pb);
+ codec->codec_id = ff_codec_get_id(rsd_tags, codec->codec_tag);
+ if (!codec->codec_id) {
+ char tag_buf[32];
+
+ av_get_codec_tag_string(tag_buf, sizeof(tag_buf), codec->codec_tag);
+ for (i=0; i < FF_ARRAY_ELEMS(rsd_unsupported_tags); i++) {
+ if (codec->codec_tag == rsd_unsupported_tags[i]) {
+ avpriv_request_sample(s, "Codec tag: %s", tag_buf);
+ return AVERROR_PATCHWELCOME;
+ }
+ }
+ av_log(s, AV_LOG_ERROR, "Unknown codec tag: %s\n", tag_buf);
+ return AVERROR_INVALIDDATA;
+ }
+
+ codec->channels = avio_rl32(pb);
+ if (!codec->channels)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(pb, 4); // Bit depth
+ codec->sample_rate = avio_rl32(pb);
+ if (!codec->sample_rate)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(pb, 4); // Unknown
+
+ switch (codec->codec_id) {
+ case AV_CODEC_ID_ADPCM_IMA_RAD:
+ codec->block_align = 20 * codec->channels;
+ if (pb->seekable)
+ st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start);
+ break;
+ case AV_CODEC_ID_ADPCM_THP:
+ /* RSD3GADP is mono, so only alloc enough memory
+ to store the coeff table for a single channel. */
+
+ start = avio_rl32(pb);
+
+ if (ff_get_extradata(codec, s->pb, 32) < 0)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < 16; i++)
+ AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2));
+
+ if (pb->seekable)
+ st->duration = (avio_size(pb) - start) / 8 * 14;
+ break;
+ case AV_CODEC_ID_PCM_S16LE:
+ case AV_CODEC_ID_PCM_S16BE:
+ if (version != 4)
+ start = avio_rl32(pb);
+
+ if (pb->seekable)
+ st->duration = (avio_size(pb) - start) / 2 / codec->channels;
+ break;
+ }
+
+ avio_skip(pb, start - avio_tell(pb));
+
+ avpriv_set_pts_info(st, 64, 1, codec->sample_rate);
+
+ return 0;
+}
+
+static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVCodecContext *codec = s->streams[0]->codec;
+ int ret, size = 1024;
+
+ if (avio_feof(s->pb))
+ return AVERROR_EOF;
+
+ if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD)
+ ret = av_get_packet(s->pb, pkt, codec->block_align);
+ else
+ ret = av_get_packet(s->pb, pkt, size);
+
+ if (ret != size) {
+ if (ret < 0) {
+ av_free_packet(pkt);
+ return ret;
+ }
+ av_shrink_packet(pkt, ret);
+ }
+ pkt->stream_index = 0;
+
+ return ret;
+}
+
+AVInputFormat ff_rsd_demuxer = {
+ .name = "rsd",
+ .long_name = NULL_IF_CONFIG_SMALL("GameCube RSD"),
+ .read_probe = rsd_probe,
+ .read_header = rsd_read_header,
+ .read_packet = rsd_read_packet,
+ .extensions = "rsd",
+ .codec_tag = (const AVCodecTag* const []){rsd_tags, 0},
+};
diff --git a/libavformat/rso.c b/libavformat/rso.c
index 4ce61e7a10..7d88f0f5bc 100644
--- a/libavformat/rso.c
+++ b/libavformat/rso.c
@@ -2,20 +2,20 @@
* RSO format common data
* Copyright (c) 2010 Rafael Carre
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rso.h b/libavformat/rso.h
index e3e88ea644..1f65dd90c7 100644
--- a/libavformat/rso.h
+++ b/libavformat/rso.h
@@ -2,20 +2,20 @@
* RSO format common data
* Copyright (c) 2010 Rafael Carre
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rsodec.c b/libavformat/rsodec.c
index 1612572b56..6e3ea0a153 100644
--- a/libavformat/rsodec.c
+++ b/libavformat/rsodec.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard (original AU code)
* Copyright (c) 2010 Rafael Carre
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -65,36 +65,19 @@ static int rso_read_header(AVFormatContext *s)
st->codec->channels = 1;
st->codec->channel_layout = AV_CH_LAYOUT_MONO;
st->codec->sample_rate = rate;
+ st->codec->block_align = 1;
avpriv_set_pts_info(st, 64, 1, rate);
return 0;
}
-#define BLOCK_SIZE 1024 /* in samples */
-
-static int rso_read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- int bps = av_get_bits_per_sample(s->streams[0]->codec->codec_id);
- int ret = av_get_packet(s->pb, pkt, BLOCK_SIZE * bps >> 3);
-
- if (ret < 0)
- return ret;
-
- pkt->stream_index = 0;
-
- /* note: we need to modify the packet size here to handle the last packet */
- pkt->size = ret;
-
- return 0;
-}
-
AVInputFormat ff_rso_demuxer = {
.name = "rso",
.long_name = NULL_IF_CONFIG_SMALL("Lego Mindstorms RSO"),
.extensions = "rso",
.read_header = rso_read_header,
- .read_packet = rso_read_packet,
+ .read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
.codec_tag = (const AVCodecTag* const []){ff_codec_rso_tags, 0},
};
diff --git a/libavformat/rsoenc.c b/libavformat/rsoenc.c
index 8ebcf8193b..6da9594fcb 100644
--- a/libavformat/rsoenc.c
+++ b/libavformat/rsoenc.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard (original AU code)
* Copyright (c) 2010 Rafael Carre
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmp.h b/libavformat/rtmp.h
index dc7ba5bdeb..8fc8040d89 100644
--- a/libavformat/rtmp.h
+++ b/libavformat/rtmp.h
@@ -2,20 +2,20 @@
* RTMP definitions
* Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmpcrypt.c b/libavformat/rtmpcrypt.c
index dfdd029a53..2312527d37 100644
--- a/libavformat/rtmpcrypt.c
+++ b/libavformat/rtmpcrypt.c
@@ -4,20 +4,20 @@
* Copyright (c) 2009-2010 Howard Chu
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmpcrypt.h b/libavformat/rtmpcrypt.h
index 27994333df..590a8c81b8 100644
--- a/libavformat/rtmpcrypt.h
+++ b/libavformat/rtmpcrypt.h
@@ -2,20 +2,20 @@
* RTMPE encryption utilities
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmpdh.c b/libavformat/rtmpdh.c
index 38c2f3df63..7d6734daac 100644
--- a/libavformat/rtmpdh.c
+++ b/libavformat/rtmpdh.c
@@ -4,20 +4,20 @@
* Copyright (c) 2009-2010 Howard Chu
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmpdh.h b/libavformat/rtmpdh.h
index 5de8bde821..cf262fc245 100644
--- a/libavformat/rtmpdh.h
+++ b/libavformat/rtmpdh.h
@@ -2,20 +2,20 @@
* RTMP Diffie-Hellmann utilities
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmphttp.c b/libavformat/rtmphttp.c
index 34c68fb437..0334ba558c 100644
--- a/libavformat/rtmphttp.c
+++ b/libavformat/rtmphttp.c
@@ -2,20 +2,20 @@
* RTMP HTTP network protocol
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmppkt.c b/libavformat/rtmppkt.c
index f8c51d01fa..c474fb3d58 100644
--- a/libavformat/rtmppkt.c
+++ b/libavformat/rtmppkt.c
@@ -2,20 +2,20 @@
* RTMP input format
* Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -279,6 +279,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p,
prev->data = p->data;
prev->read = p->read;
prev->offset = p->offset;
+ p->data = NULL;
return AVERROR(EAGAIN);
}
diff --git a/libavformat/rtmppkt.h b/libavformat/rtmppkt.h
index 149c153cad..a082b45f98 100644
--- a/libavformat/rtmppkt.h
+++ b/libavformat/rtmppkt.h
@@ -2,20 +2,20 @@
* RTMP packet utilities
* Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index e75a5190d0..43ddfe8ecc 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -2,20 +2,20 @@
* RTMP network protocol
* Copyright (c) 2009 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,7 +48,7 @@
#include <zlib.h>
#endif
-#define APP_MAX_LENGTH 128
+#define APP_MAX_LENGTH 1024
#define PLAYPATH_MAX_LENGTH 256
#define TCURL_MAX_LENGTH 512
#define FLASHVER_MAX_LENGTH 64
@@ -217,9 +217,8 @@ static void free_tracked_methods(RTMPContext *rt)
int i;
for (i = 0; i < rt->nb_tracked_methods; i ++)
- av_free(rt->tracked_methods[i].name);
- av_free(rt->tracked_methods);
- rt->tracked_methods = NULL;
+ av_freep(&rt->tracked_methods[i].name);
+ av_freep(&rt->tracked_methods);
rt->tracked_methods_size = 0;
rt->nb_tracked_methods = 0;
}
@@ -322,7 +321,7 @@ static int gen_connect(URLContext *s, RTMPContext *rt)
int ret;
if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
- 0, 4096)) < 0)
+ 0, 4096 + APP_MAX_LENGTH)) < 0)
return ret;
p = pkt.data;
@@ -419,6 +418,7 @@ static int read_connect(URLContext *s, RTMPContext *rt)
if (pkt.type == RTMP_PT_CHUNK_SIZE) {
if ((ret = handle_chunk_size(s, &pkt)) < 0)
return ret;
+
ff_rtmp_packet_destroy(&pkt);
if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
&rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
@@ -1767,18 +1767,23 @@ static int handle_connect_error(URLContext *s, const char *desc)
char *value = strchr(ptr, '=');
if (next)
*next++ = '\0';
- if (value)
+ if (value) {
*value++ = '\0';
- if (!strcmp(ptr, "user")) {
- user = value;
- } else if (!strcmp(ptr, "salt")) {
- salt = value;
- } else if (!strcmp(ptr, "opaque")) {
- opaque = value;
- } else if (!strcmp(ptr, "challenge")) {
- challenge = value;
- } else if (!strcmp(ptr, "nonce")) {
- nonce = value;
+ if (!strcmp(ptr, "user")) {
+ user = value;
+ } else if (!strcmp(ptr, "salt")) {
+ salt = value;
+ } else if (!strcmp(ptr, "opaque")) {
+ opaque = value;
+ } else if (!strcmp(ptr, "challenge")) {
+ challenge = value;
+ } else if (!strcmp(ptr, "nonce")) {
+ nonce = value;
+ } else {
+ av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
+ }
+ } else {
+ av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
}
ptr = next;
}
@@ -2429,7 +2434,7 @@ static int get_packet(URLContext *s, int for_header)
rt->last_timestamp = rpkt.timestamp;
rt->bytes_read += ret;
- if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
+ if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
return ret;
@@ -2546,7 +2551,7 @@ static int inject_fake_duration_metadata(RTMPContext *rt)
// Increase the size by the injected packet
rt->flv_size += 55;
// Delete the old FLV data
- av_free(old_flv_data);
+ av_freep(&old_flv_data);
p = rt->flv_data + 13;
bytestream_put_byte(&p, FLV_TAG_TYPE_META);
@@ -2591,7 +2596,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
{
RTMPContext *rt = s->priv_data;
char proto[8], hostname[256], path[1024], auth[100], *fname;
- char *old_app, *qmark, fname_buffer[1024];
+ char *old_app, *qmark, *n, fname_buffer[1024];
uint8_t buf[2048];
int port;
AVDictionary *opts = NULL;
@@ -2606,11 +2611,13 @@ static int rtmp_open(URLContext *s, const char *uri, int flags)
hostname, sizeof(hostname), &port,
path, sizeof(path), s->filename);
- if (strchr(path, ' ')) {
+ n = strchr(path, ' ');
+ if (n) {
av_log(s, AV_LOG_WARNING,
"Detected librtmp style URL parameters, these aren't supported "
"by the libavformat internal RTMP handler currently enabled. "
"See the documentation for the correct way to pass parameters.\n");
+ *n = '\0'; // Trim not supported part
}
if (auth[0]) {
@@ -2709,8 +2716,14 @@ reconnect:
char *next = *path ? path + 1 : path;
char *p = strchr(next, '/');
if (!p) {
- fname = next;
- rt->app[0] = '\0';
+ if (old_app) {
+ // If name of application has been defined by the user, assume that
+ // playpath is provided in the URL
+ fname = next;
+ } else {
+ fname = NULL;
+ av_strlcpy(rt->app, next, APP_MAX_LENGTH);
+ }
} else {
// make sure we do not mismatch a playpath for an application instance
char *c = strchr(p + 1, ':');
@@ -2727,29 +2740,36 @@ reconnect:
if (old_app) {
// The name of application has been defined by the user, override it.
+ if (strlen(old_app) >= APP_MAX_LENGTH) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
av_free(rt->app);
rt->app = old_app;
}
if (!rt->playpath) {
- int len = strlen(fname);
-
rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
if (!rt->playpath) {
ret = AVERROR(ENOMEM);
goto fail;
}
- if (!strchr(fname, ':') && len >= 4 &&
- (!strcmp(fname + len - 4, ".f4v") ||
- !strcmp(fname + len - 4, ".mp4"))) {
- memcpy(rt->playpath, "mp4:", 5);
+ if (fname) {
+ int len = strlen(fname);
+ if (!strchr(fname, ':') && len >= 4 &&
+ (!strcmp(fname + len - 4, ".f4v") ||
+ !strcmp(fname + len - 4, ".mp4"))) {
+ memcpy(rt->playpath, "mp4:", 5);
+ } else {
+ if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
+ fname[len - 4] = '\0';
+ rt->playpath[0] = 0;
+ }
+ av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
} else {
- if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
- fname[len - 4] = '\0';
- rt->playpath[0] = 0;
+ rt->playpath[0] = '\0';
}
- av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
}
if (!rt->tcurl) {
@@ -2951,6 +2971,7 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
if (rt->flv_header_bytes < RTMP_HEADER) {
const uint8_t *header = rt->flv_header;
int channel = RTMP_AUDIO_CHANNEL;
+
copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
rt->flv_header_bytes += copy;
diff --git a/libavformat/rtp.c b/libavformat/rtp.c
index 0a3c411f51..4d41350f3c 100644
--- a/libavformat/rtp.c
+++ b/libavformat/rtp.c
@@ -2,23 +2,24 @@
* RTP input/output format
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "libavutil/opt.h"
#include "avformat.h"
@@ -144,7 +145,7 @@ enum AVCodecID ff_rtp_codec_id(const char *buf, enum AVMediaType codec_type)
int i;
for (i = 0; rtp_payload_types[i].pt >= 0; i++)
- if (!strcmp(buf, rtp_payload_types[i].enc_name) && (codec_type == rtp_payload_types[i].codec_type))
+ if (!av_strcasecmp(buf, rtp_payload_types[i].enc_name) && (codec_type == rtp_payload_types[i].codec_type))
return rtp_payload_types[i].codec_id;
return AV_CODEC_ID_NONE;
diff --git a/libavformat/rtp.h b/libavformat/rtp.h
index feaf167965..66a4f3afbd 100644
--- a/libavformat/rtp.h
+++ b/libavformat/rtp.h
@@ -2,20 +2,20 @@
* RTP definitions
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_RTP_H
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
index 0efcdb9123..fee9547ebf 100644
--- a/libavformat/rtpdec.c
+++ b/libavformat/rtpdec.c
@@ -2,20 +2,20 @@
* RTP input format
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,12 @@
#define MIN_FEEDBACK_INTERVAL 200000 /* 200 ms in us */
+static RTPDynamicProtocolHandler gsm_dynamic_handler = {
+ .enc_name = "GSM",
+ .codec_type = AVMEDIA_TYPE_AUDIO,
+ .codec_id = AV_CODEC_ID_GSM,
+};
+
static RTPDynamicProtocolHandler realmedia_mp3_dynamic_handler = {
.enc_name = "X-MP3-draft-00",
.codec_type = AVMEDIA_TYPE_AUDIO,
@@ -52,7 +58,7 @@ static RTPDynamicProtocolHandler opus_dynamic_handler = {
static RTPDynamicProtocolHandler t140_dynamic_handler = { /* RFC 4103 */
.enc_name = "t140",
- .codec_type = AVMEDIA_TYPE_DATA,
+ .codec_type = AVMEDIA_TYPE_SUBTITLE,
.codec_id = AV_CODEC_ID_TEXT,
};
@@ -102,6 +108,7 @@ void ff_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vp9_dynamic_handler);
+ ff_register_dynamic_payload_handler(&gsm_dynamic_handler);
ff_register_dynamic_payload_handler(&opus_dynamic_handler);
ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler);
ff_register_dynamic_payload_handler(&speex_dynamic_handler);
@@ -671,8 +678,8 @@ void ff_rtp_reset_packet_queue(RTPDemuxContext *s)
{
while (s->queue) {
RTPPacket *next = s->queue->next;
- av_free(s->queue->buf);
- av_free(s->queue);
+ av_freep(&s->queue->buf);
+ av_freep(&s->queue);
s->queue = next;
}
s->seq = 0;
@@ -730,8 +737,8 @@ static int rtp_parse_queued_packet(RTPDemuxContext *s, AVPacket *pkt)
/* Parse the first packet in the queue, and dequeue it */
rv = rtp_parse_packet_internal(s, pkt, s->queue->buf, s->queue->len);
next = s->queue->next;
- av_free(s->queue->buf);
- av_free(s->queue);
+ av_freep(&s->queue->buf);
+ av_freep(&s->queue);
s->queue = next;
s->queue_len--;
return rv;
@@ -853,7 +860,7 @@ int ff_parse_fmtp(AVFormatContext *s,
int value_size = strlen(p) + 1;
if (!(value = av_malloc(value_size))) {
- av_log(NULL, AV_LOG_ERROR, "Failed to allocate data for FMTP.");
+ av_log(NULL, AV_LOG_ERROR, "Failed to allocate data for FMTP.\n");
return AVERROR(ENOMEM);
}
diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h
index 9282c4f636..96cbb5e5ac 100644
--- a/libavformat/rtpdec.h
+++ b/libavformat/rtpdec.h
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Fabrice Bellard
* Copyright (c) 2006 Ryan Martell <rdm4@martellventures.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -175,9 +175,9 @@ struct RTPDemuxContext {
/*@}*/
/* rtcp sender statistics receive */
- int64_t last_rtcp_ntp_time;
+ uint64_t last_rtcp_ntp_time;
int64_t last_rtcp_reception_time;
- int64_t first_rtcp_ntp_time;
+ uint64_t first_rtcp_ntp_time;
uint32_t last_rtcp_timestamp;
int64_t rtcp_ts_offset;
diff --git a/libavformat/rtpdec_ac3.c b/libavformat/rtpdec_ac3.c
index e519b283cb..48b2d9cf98 100644
--- a/libavformat/rtpdec_ac3.c
+++ b/libavformat/rtpdec_ac3.c
@@ -2,20 +2,20 @@
* RTP parser for AC3 payload format (RFC 4184)
* Copyright (c) 2015 Gilles Chanteperdrix <gch@xenomai.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_amr.c b/libavformat/rtpdec_amr.c
index b6a8c29052..848db9d62a 100644
--- a/libavformat/rtpdec_amr.c
+++ b/libavformat/rtpdec_amr.c
@@ -2,20 +2,20 @@
* RTP AMR Depacketizer, RFC 3267
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c
index 3ca3f71972..066bb0ed37 100644
--- a/libavformat/rtpdec_asf.c
+++ b/libavformat/rtpdec_asf.c
@@ -2,20 +2,20 @@
* Microsoft RTP/ASF support.
* Copyright (c) 2008 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
* @author Ronald S. Bultje <rbultje@ronald.bitfreak.net>
*/
+#include "libavutil/avassert.h"
#include "libavutil/base64.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
@@ -53,6 +54,7 @@ static int rtp_asf_fix_header(uint8_t *buf, int len)
p += sizeof(ff_asf_guid) + 14;
do {
uint64_t chunksize = AV_RL64(p + sizeof(ff_asf_guid));
+ int skip = 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
if (memcmp(p, ff_asf_file_header, sizeof(ff_asf_guid))) {
if (chunksize > end - p)
return -1;
@@ -60,9 +62,11 @@ static int rtp_asf_fix_header(uint8_t *buf, int len)
continue;
}
+ if (end - p < 8 + skip)
+ break;
/* skip most of the file header, to min_pktsize */
- p += 6 * 8 + 3 * 4 + sizeof(ff_asf_guid) * 2;
- if (p + 8 <= end && AV_RL32(p) == AV_RL32(p + 4)) {
+ p += skip;
+ if (AV_RL32(p) == AV_RL32(p + 4)) {
/* and set that to zero */
AV_WL32(p, 0);
return 0;
@@ -102,6 +106,8 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
AVDictionary *opts = NULL;
int len = strlen(p) * 6 / 8;
char *buf = av_mallocz(len);
+ AVInputFormat *iformat;
+
av_base64_decode(buf, p, len);
if (rtp_asf_fix_header(buf, len) < 0)
@@ -111,11 +117,19 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p)
if (rt->asf_ctx) {
avformat_close_input(&rt->asf_ctx);
}
+ if (!(iformat = av_find_input_format("asf")))
+ return AVERROR_DEMUXER_NOT_FOUND;
if (!(rt->asf_ctx = avformat_alloc_context()))
return AVERROR(ENOMEM);
rt->asf_ctx->pb = &pb;
av_dict_set(&opts, "no_resync_search", "1", 0);
- ret = avformat_open_input(&rt->asf_ctx, "", &ff_asf_demuxer, &opts);
+
+ if ((ret = ff_copy_whitelists(rt->asf_ctx, s)) < 0) {
+ av_dict_free(&opts);
+ return ret;
+ }
+
+ ret = avformat_open_input(&rt->asf_ctx, "", iformat, &opts);
av_dict_free(&opts);
if (ret < 0)
return ret;
@@ -188,7 +202,7 @@ static int asfrtp_parse_packet(AVFormatContext *s, PayloadContext *asf,
av_freep(&asf->buf);
- ffio_init_context(pb, buf, len, 0, NULL, NULL, NULL, NULL);
+ ffio_init_context(pb, (uint8_t *)buf, len, 0, NULL, NULL, NULL, NULL);
while (avio_tell(pb) + 4 < len) {
int start_off = avio_tell(pb);
diff --git a/libavformat/rtpdec_dv.c b/libavformat/rtpdec_dv.c
index 09d497ad9e..de99d27795 100644
--- a/libavformat/rtpdec_dv.c
+++ b/libavformat/rtpdec_dv.c
@@ -2,20 +2,20 @@
* RTP parser for DV payload format (RFC 6469)
* Copyright (c) 2015 Thomas Volkert <thomas@homer-conferencing.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
index b71b1ae907..50a2f4ca3e 100644
--- a/libavformat/rtpdec_formats.h
+++ b/libavformat/rtpdec_formats.h
@@ -2,20 +2,20 @@
* RTP depacketizer declarations
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,7 +38,7 @@ int ff_h263_handle_packet(AVFormatContext *ctx, PayloadContext *data,
int ff_h264_parse_sprop_parameter_sets(AVFormatContext *s,
uint8_t **data_ptr, int *size_ptr,
const char *value);
-int ff_h264_handle_aggregated_packet(AVFormatContext *ctx, AVPacket *pkt,
+int ff_h264_handle_aggregated_packet(AVFormatContext *ctx, PayloadContext *data, AVPacket *pkt,
const uint8_t *buf, int len,
int start_skip, int *nal_counters,
int nal_mask);
diff --git a/libavformat/rtpdec_g726.c b/libavformat/rtpdec_g726.c
index 7b3f6cbb89..7e9ef56e06 100644
--- a/libavformat/rtpdec_g726.c
+++ b/libavformat/rtpdec_g726.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Miroslav Slugeň <Thunder.m@seznam.cz>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_h261.c b/libavformat/rtpdec_h261.c
index 00086c21c5..9729f21d15 100644
--- a/libavformat/rtpdec_h261.c
+++ b/libavformat/rtpdec_h261.c
@@ -2,20 +2,20 @@
* RTP parser for H.261 payload format (RFC 4587)
* Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_h263.c b/libavformat/rtpdec_h263.c
index 710cfd2096..97aa4add36 100644
--- a/libavformat/rtpdec_h263.c
+++ b/libavformat/rtpdec_h263.c
@@ -2,20 +2,20 @@
* RTP H.263 Depacketizer, RFC 4629
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_h263_rfc2190.c b/libavformat/rtpdec_h263_rfc2190.c
index 3a58aee22f..33712e7b76 100644
--- a/libavformat/rtpdec_h263_rfc2190.c
+++ b/libavformat/rtpdec_h263_rfc2190.c
@@ -8,20 +8,20 @@
* Copyright 2007 Collabora Ltd, Philippe Kalaf
* Copyright 2010 Mark Nauwelaerts
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c
index 1a690115e5..2ac79dbf5e 100644
--- a/libavformat/rtpdec_h264.c
+++ b/libavformat/rtpdec_h264.c
@@ -2,20 +2,20 @@
* RTP H264 Protocol (RFC3984)
* Copyright (c) 2006 Ryan Martell
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -199,7 +199,7 @@ void ff_h264_parse_framesize(AVCodecContext *codec, const char *p)
codec->height = atoi(p + 1); // skip the -
}
-int ff_h264_handle_aggregated_packet(AVFormatContext *ctx, AVPacket *pkt,
+int ff_h264_handle_aggregated_packet(AVFormatContext *ctx, PayloadContext *data, AVPacket *pkt,
const uint8_t *buf, int len,
int skip_between, int *nal_counters,
int nal_mask)
@@ -278,7 +278,7 @@ int ff_h264_handle_frag_packet(AVPacket *pkt, const uint8_t *buf, int len,
return 0;
}
-static int h264_handle_packet_fu_a(AVFormatContext *ctx, AVPacket *pkt,
+static int h264_handle_packet_fu_a(AVFormatContext *ctx, PayloadContext *data, AVPacket *pkt,
const uint8_t *buf, int len,
int *nal_counters, int nal_mask)
{
@@ -339,7 +339,7 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
// consume the STAP-A NAL
buf++;
len--;
- result = ff_h264_handle_aggregated_packet(ctx, pkt, buf, len, 0,
+ result = ff_h264_handle_aggregated_packet(ctx, data, pkt, buf, len, 0,
NAL_COUNTERS, NAL_MASK);
break;
@@ -354,7 +354,7 @@ static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data,
break;
case 28: // FU-A (fragmented nal)
- result = h264_handle_packet_fu_a(ctx, pkt, buf, len,
+ result = h264_handle_packet_fu_a(ctx, data, pkt, buf, len,
NAL_COUNTERS, NAL_MASK);
break;
diff --git a/libavformat/rtpdec_hevc.c b/libavformat/rtpdec_hevc.c
index a4d9c54e0b..51c2094882 100644
--- a/libavformat/rtpdec_hevc.c
+++ b/libavformat/rtpdec_hevc.c
@@ -2,36 +2,39 @@
* RTP parser for HEVC/H.265 payload format (draft version 6)
* Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/avstring.h"
#include "libavutil/base64.h"
+#include "libavcodec/get_bits.h"
#include "avformat.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
-#define RTP_HEVC_PAYLOAD_HEADER_SIZE 2
-#define RTP_HEVC_FU_HEADER_SIZE 1
-#define RTP_HEVC_DONL_FIELD_SIZE 2
-#define RTP_HEVC_DOND_FIELD_SIZE 1
-#define HEVC_SPECIFIED_NAL_UNIT_TYPES 48
+#define RTP_HEVC_PAYLOAD_HEADER_SIZE 2
+#define RTP_HEVC_FU_HEADER_SIZE 1
+#define RTP_HEVC_DONL_FIELD_SIZE 2
+#define RTP_HEVC_DOND_FIELD_SIZE 1
+#define RTP_HEVC_AP_NALU_LENGTH_FIELD_SIZE 2
+#define HEVC_SPECIFIED_NAL_UNIT_TYPES 48
/* SDP out-of-band signaling data */
struct PayloadContext {
@@ -83,7 +86,8 @@ static av_cold int hevc_sdp_parse_fmtp_config(AVFormatContext *s,
} else if (!strcmp(attr, "sprop-sei")) {
data_ptr = &hevc_data->sei;
size_ptr = &hevc_data->sei_size;
- }
+ } else
+ av_assert0(0);
ff_h264_parse_sprop_parameter_sets(s, data_ptr,
size_ptr, value);
@@ -266,7 +270,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
len -= RTP_HEVC_DONL_FIELD_SIZE;
}
- res = ff_h264_handle_aggregated_packet(ctx, pkt, buf, len,
+ res = ff_h264_handle_aggregated_packet(ctx, rtp_hevc_ctx, pkt, buf, len,
rtp_hevc_ctx->using_donl_field ?
RTP_HEVC_DOND_FIELD_SIZE : 0,
NULL, 0);
@@ -307,12 +311,16 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx
av_log(ctx, AV_LOG_TRACE, " FU type %d with %d bytes\n", fu_type, len);
+ /* sanity check for size of input packet: 1 byte payload at least */
if (len <= 0) {
- /* sanity check for size of input packet: 1 byte payload at least */
- av_log(ctx, AV_LOG_ERROR,
- "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
- len, nal_type);
- return AVERROR_INVALIDDATA;
+ if (len < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Too short RTP/HEVC packet, got %d bytes of NAL unit type %d\n",
+ len, nal_type);
+ return AVERROR_INVALIDDATA;
+ } else {
+ return AVERROR(EAGAIN);
+ }
}
if (first_fragment && last_fragment) {
diff --git a/libavformat/rtpdec_ilbc.c b/libavformat/rtpdec_ilbc.c
index f47abc1f96..82109e1344 100644
--- a/libavformat/rtpdec_ilbc.c
+++ b/libavformat/rtpdec_ilbc.c
@@ -2,20 +2,20 @@
* RTP iLBC Depacketizer, RFC 3952
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_jpeg.c b/libavformat/rtpdec_jpeg.c
index 3bee0b2317..6bf88f8c3a 100644
--- a/libavformat/rtpdec_jpeg.c
+++ b/libavformat/rtpdec_jpeg.c
@@ -2,20 +2,20 @@
* RTP JPEG-compressed Video Depacketizer, RFC 2435
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -92,7 +92,8 @@ static void jpeg_put_marker(PutByteContext *pbc, int code)
}
static int jpeg_create_header(uint8_t *buf, int size, uint32_t type, uint32_t w,
- uint32_t h, const uint8_t *qtable, int nb_qtable)
+ uint32_t h, const uint8_t *qtable, int nb_qtable,
+ int dri)
{
PutByteContext pbc;
uint8_t *dht_size_ptr;
@@ -118,6 +119,12 @@ static int jpeg_create_header(uint8_t *buf, int size, uint32_t type, uint32_t w,
bytestream2_put_byte(&pbc, 0);
bytestream2_put_byte(&pbc, 0);
+ if (dri) {
+ jpeg_put_marker(&pbc, DRI);
+ bytestream2_put_be16(&pbc, 4);
+ bytestream2_put_be16(&pbc, dri);
+ }
+
/* DQT */
jpeg_put_marker(&pbc, DQT);
bytestream2_put_be16(&pbc, 2 + nb_qtable * (1 + 64));
@@ -212,7 +219,7 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
const uint8_t *qtables = NULL;
uint16_t qtable_len;
uint32_t off;
- int ret;
+ int ret, dri = 0;
if (len < 8) {
av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
@@ -228,6 +235,16 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
buf += 8;
len -= 8;
+ if (type & 0x40) {
+ if (len < 4) {
+ av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
+ return AVERROR_INVALIDDATA;
+ }
+ dri = AV_RB16(buf);
+ buf += 4;
+ len -= 4;
+ type &= ~0x40;
+ }
/* Parse the restart marker header. */
if (type > 63) {
av_log(ctx, AV_LOG_ERROR,
@@ -318,7 +335,7 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
* interchange format. */
jpeg->hdr_size = jpeg_create_header(hdr, sizeof(hdr), type, width,
height, qtables,
- qtable_len / 64);
+ qtable_len / 64, dri);
/* Copy JPEG header to frame buffer. */
avio_write(jpeg->frame, hdr, jpeg->hdr_size);
diff --git a/libavformat/rtpdec_latm.c b/libavformat/rtpdec_latm.c
index 5c54c202d0..7db92f60fa 100644
--- a/libavformat/rtpdec_latm.c
+++ b/libavformat/rtpdec_latm.c
@@ -2,20 +2,20 @@
* RTP Depacketization of MP4A-LATM, RFC 3016
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,7 +35,7 @@ struct PayloadContext {
static void latm_close_context(PayloadContext *data)
{
ffio_free_dyn_buf(&data->dyn_buf);
- av_free(data->buf);
+ av_freep(&data->buf);
}
static int latm_parse_packet(AVFormatContext *ctx, PayloadContext *data,
@@ -58,7 +58,7 @@ static int latm_parse_packet(AVFormatContext *ctx, PayloadContext *data,
if (!(flags & RTP_FLAG_MARKER))
return AVERROR(EAGAIN);
- av_free(data->buf);
+ av_freep(&data->buf);
data->len = avio_close_dyn_buf(data->dyn_buf, &data->buf);
data->dyn_buf = NULL;
data->pos = 0;
@@ -116,10 +116,7 @@ static int parse_fmtp_config(AVStream *st, const char *value)
goto end;
}
av_freep(&st->codec->extradata);
- st->codec->extradata_size = (get_bits_left(&gb) + 7)/8;
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
+ if (ff_alloc_extradata(st->codec, (get_bits_left(&gb) + 7)/8)) {
ret = AVERROR(ENOMEM);
goto end;
}
diff --git a/libavformat/rtpdec_mpa_robust.c b/libavformat/rtpdec_mpa_robust.c
index 022cfec313..07057fe7ce 100644
--- a/libavformat/rtpdec_mpa_robust.c
+++ b/libavformat/rtpdec_mpa_robust.c
@@ -2,20 +2,20 @@
* RTP parser for loss tolerant payload format for MP3 audio (RFC 5219)
* Copyright (c) 2015 Gilles Chanteperdrix <gch@xenomai.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_mpeg12.c b/libavformat/rtpdec_mpeg12.c
index 2b884be75a..e6185eafa6 100644
--- a/libavformat/rtpdec_mpeg12.c
+++ b/libavformat/rtpdec_mpeg12.c
@@ -2,20 +2,20 @@
* Common code for the RTP depacketization of MPEG-1/2 formats.
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c
index c08242e792..70e51f862c 100644
--- a/libavformat/rtpdec_mpeg4.c
+++ b/libavformat/rtpdec_mpeg4.c
@@ -3,20 +3,20 @@
* Copyright (c) 2010 Fabrice Bellard
* Romain Degez
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -93,19 +93,17 @@ static const AttrNameMap attr_names[] = {
static void close_context(PayloadContext *data)
{
- av_free(data->au_headers);
- av_free(data->mode);
+ av_freep(&data->au_headers);
+ av_freep(&data->mode);
}
static int parse_fmtp_config(AVCodecContext *codec, const char *value)
{
/* decode the hexa encoded parameter */
int len = ff_hex_to_data(NULL, value);
- av_free(codec->extradata);
- codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!codec->extradata)
+ av_freep(&codec->extradata);
+ if (ff_alloc_extradata(codec, len))
return AVERROR(ENOMEM);
- codec->extradata_size = len;
ff_hex_to_data(codec->extradata, value);
return 0;
}
@@ -136,7 +134,7 @@ static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf, int len)
init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
- /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */
+ /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */
au_header_size = data->sizelength + data->indexlength;
if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
return -1;
@@ -167,6 +165,7 @@ static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
{
int ret;
+
if (!buf) {
if (data->cur_au_index > data->nb_au_headers) {
av_log(ctx, AV_LOG_ERROR, "Invalid parser state\n");
diff --git a/libavformat/rtpdec_mpegts.c b/libavformat/rtpdec_mpegts.c
index 0fb0a0d3af..5bf0f186db 100644
--- a/libavformat/rtpdec_mpegts.c
+++ b/libavformat/rtpdec_mpegts.c
@@ -2,20 +2,20 @@
* RTP MPEG2TS depacketizer
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,13 +35,13 @@ static void mpegts_close_context(PayloadContext *data)
if (!data)
return;
if (data->ts)
- ff_mpegts_parse_close(data->ts);
+ avpriv_mpegts_parse_close(data->ts);
}
static av_cold int mpegts_init(AVFormatContext *ctx, int st_index,
PayloadContext *data)
{
- data->ts = ff_mpegts_parse_open(ctx);
+ data->ts = avpriv_mpegts_parse_open(ctx);
if (!data->ts)
return AVERROR(ENOMEM);
return 0;
@@ -63,8 +63,8 @@ static int mpegts_handle_packet(AVFormatContext *ctx, PayloadContext *data,
if (!buf) {
if (data->read_buf_index >= data->read_buf_size)
return AVERROR(EAGAIN);
- ret = ff_mpegts_parse_packet(data->ts, pkt, data->buf + data->read_buf_index,
- data->read_buf_size - data->read_buf_index);
+ ret = avpriv_mpegts_parse_packet(data->ts, pkt, data->buf + data->read_buf_index,
+ data->read_buf_size - data->read_buf_index);
if (ret < 0)
return AVERROR(EAGAIN);
data->read_buf_index += ret;
@@ -74,8 +74,8 @@ static int mpegts_handle_packet(AVFormatContext *ctx, PayloadContext *data,
return 0;
}
- ret = ff_mpegts_parse_packet(data->ts, pkt, buf, len);
- /* The only error that can be returned from ff_mpegts_parse_packet
+ ret = avpriv_mpegts_parse_packet(data->ts, pkt, buf, len);
+ /* The only error that can be returned from avpriv_mpegts_parse_packet
* is "no more data to return from the provided buffer", so return
* AVERROR(EAGAIN) for all errors */
if (ret < 0)
diff --git a/libavformat/rtpdec_qcelp.c b/libavformat/rtpdec_qcelp.c
index d5322d6a71..41cc8263df 100644
--- a/libavformat/rtpdec_qcelp.c
+++ b/libavformat/rtpdec_qcelp.c
@@ -2,20 +2,20 @@
* RTP Depacketization of QCELP/PureVoice, RFC 2658
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_qdm2.c b/libavformat/rtpdec_qdm2.c
index 8eea571460..22b419e7e0 100644
--- a/libavformat/rtpdec_qdm2.c
+++ b/libavformat/rtpdec_qdm2.c
@@ -2,20 +2,20 @@
* QDesign Music 2 (QDM2) payload for RTP
* Copyright (c) 2010 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,8 +26,10 @@
*/
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "libavcodec/avcodec.h"
+#include "internal.h"
#include "rtp.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -103,9 +105,7 @@ static int qdm2_parse_config(PayloadContext *qdm, AVStream *st,
if (item_len < 30)
return AVERROR_INVALIDDATA;
av_freep(&st->codec->extradata);
- st->codec->extradata_size = 26 + item_len;
- if (!(st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE))) {
- st->codec->extradata_size = 0;
+ if (ff_alloc_extradata(st->codec, 26 + item_len)) {
return AVERROR(ENOMEM);
}
AV_WB32(st->codec->extradata, 12);
@@ -189,11 +189,11 @@ static int qdm2_restore_block(PayloadContext *qdm, AVStream *st, AVPacket *pkt)
uint8_t *p, *csum_pos = NULL;
/* create packet to hold subpkts into a superblock */
- assert(qdm->cache > 0);
+ av_assert0(qdm->cache > 0);
for (n = 0; n < 0x80; n++)
if (qdm->len[n] > 0)
break;
- assert(n < 0x80);
+ av_assert0(n < 0x80);
if ((res = av_new_packet(pkt, qdm->block_size)) < 0)
return res;
diff --git a/libavformat/rtpdec_qt.c b/libavformat/rtpdec_qt.c
index 62aee89e50..ba701dc6cf 100644
--- a/libavformat/rtpdec_qt.c
+++ b/libavformat/rtpdec_qt.c
@@ -2,20 +2,20 @@
* RTP/Quicktime support.
* Copyright (c) 2009 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,7 +72,7 @@ static int qt_rtp_parse_packet(AVFormatContext *s, PayloadContext *qt,
* http://developer.apple.com/quicktime/icefloe/dispatch026.html
*/
init_get_bits(&gb, buf, len << 3);
- ffio_init_context(&pb, buf, len, 0, NULL, NULL, NULL, NULL);
+ ffio_init_context(&pb, (uint8_t*)buf, len, 0, NULL, NULL, NULL, NULL);
if (len < 4)
return AVERROR_INVALIDDATA;
diff --git a/libavformat/rtpdec_svq3.c b/libavformat/rtpdec_svq3.c
index 3104795165..bad199fef3 100644
--- a/libavformat/rtpdec_svq3.c
+++ b/libavformat/rtpdec_svq3.c
@@ -2,20 +2,20 @@
* Sorenson-3 (SVQ3/SV3V) payload for RTP
* Copyright (c) 2010 Ronald S. Bultje
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,7 @@
#include <string.h>
#include "libavutil/intreadwrite.h"
#include "avio_internal.h"
+#include "internal.h"
#include "rtp.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -61,11 +62,9 @@ static int svq3_parse_packet (AVFormatContext *s, PayloadContext *sv,
av_freep(&st->codec->extradata);
st->codec->extradata_size = 0;
- if (len < 2 || !(st->codec->extradata =
- av_malloc(len + 8 + FF_INPUT_BUFFER_PADDING_SIZE)))
+ if (len < 2 || ff_alloc_extradata(st->codec, len + 8))
return AVERROR_INVALIDDATA;
- st->codec->extradata_size = len + 8;
memcpy(st->codec->extradata, "SEQH", 4);
AV_WB32(st->codec->extradata + 4, len);
memcpy(st->codec->extradata + 8, buf, len);
diff --git a/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c
index ae2c716397..d1e355d3da 100644
--- a/libavformat/rtpdec_vp8.c
+++ b/libavformat/rtpdec_vp8.c
@@ -3,20 +3,20 @@
* Copyright (c) 2010 Josh Allmann
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_vp9.c b/libavformat/rtpdec_vp9.c
index 71ea480056..e50bedea32 100644
--- a/libavformat/rtpdec_vp9.c
+++ b/libavformat/rtpdec_vp9.c
@@ -2,20 +2,20 @@
* RTP parser for VP9 payload format (draft version 0) - experimental
* Copyright (c) 2015 Thomas Volkert <thomas@homer-conferencing.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpdec_xiph.c b/libavformat/rtpdec_xiph.c
index 66e619149b..eceb840580 100644
--- a/libavformat/rtpdec_xiph.c
+++ b/libavformat/rtpdec_xiph.c
@@ -3,20 +3,20 @@
* Copyright (c) 2009 Colin McQuillian
* Copyright (c) 2010 Josh Allmann
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,13 +28,13 @@
*/
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/base64.h"
#include "libavcodec/bytestream.h"
-#include <assert.h>
-
#include "avio_internal.h"
+#include "internal.h"
#include "rtpdec.h"
#include "rtpdec_formats.h"
@@ -53,7 +53,7 @@ struct PayloadContext {
static void xiph_close_context(PayloadContext * data)
{
ffio_free_dyn_buf(&data->fragment);
- av_free(data->split_buf);
+ av_freep(&data->split_buf);
}
@@ -73,7 +73,7 @@ static int xiph_handle_packet(AVFormatContext *ctx, PayloadContext *data,
}
pkt_len = AV_RB16(data->split_buf + data->split_pos);
data->split_pos += 2;
- if (data->split_pos + pkt_len > data->split_buf_len) {
+ if (pkt_len > data->split_buf_len - data->split_pos) {
av_log(ctx, AV_LOG_ERROR, "Not enough data to return\n");
return AVERROR_INVALIDDATA;
}
@@ -88,7 +88,7 @@ static int xiph_handle_packet(AVFormatContext *ctx, PayloadContext *data,
return data->split_pkts > 0;
}
- if (len < 6) {
+ if (len < 6 || len > INT_MAX/2) {
av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
return AVERROR_INVALIDDATA;
}
@@ -168,7 +168,7 @@ static int xiph_handle_packet(AVFormatContext *ctx, PayloadContext *data,
data->timestamp = *timestamp;
} else {
- assert(fragmented < 4);
+ av_assert1(fragmented < 4);
if (data->timestamp != *timestamp) {
// skip if fragmented timestamp is incorrect;
// a start packet has been lost somewhere
@@ -232,7 +232,7 @@ parse_packed_headers(const uint8_t * packed_headers,
if (packed_headers_end - packed_headers < 9) {
av_log(codec, AV_LOG_ERROR,
- "Invalid %td byte packed header.",
+ "Invalid %"PTRDIFF_SPECIFIER" byte packed header.",
packed_headers_end - packed_headers);
return AVERROR_INVALIDDATA;
}
@@ -254,7 +254,7 @@ parse_packed_headers(const uint8_t * packed_headers,
if (packed_headers_end - packed_headers != length ||
length1 > length || length2 > length - length1) {
av_log(codec, AV_LOG_ERROR,
- "Bad packed header lengths (%d,%d,%td,%d)\n", length1,
+ "Bad packed header lengths (%d,%d,%"PTRDIFF_SPECIFIER",%d)\n", length1,
length2, packed_headers_end - packed_headers, length);
return AVERROR_INVALIDDATA;
}
@@ -265,11 +265,11 @@ parse_packed_headers(const uint8_t * packed_headers,
* -- FF_INPUT_BUFFER_PADDING_SIZE required */
extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
- ptr = codec->extradata = av_malloc(extradata_alloc);
- if (!ptr) {
+ if (ff_alloc_extradata(codec, extradata_alloc)) {
av_log(codec, AV_LOG_ERROR, "Out of memory\n");
return AVERROR(ENOMEM);
}
+ ptr = codec->extradata;
*ptr++ = 2;
ptr += av_xiphlacing(ptr, length1);
ptr += av_xiphlacing(ptr, length2);
diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c
index 6158934900..d09b22f9f8 100644
--- a/libavformat/rtpenc.c
+++ b/libavformat/rtpenc.c
@@ -2,20 +2,20 @@
* RTP output format
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -98,7 +98,7 @@ static int rtp_write_header(AVFormatContext *s1)
}
st = s1->streams[0];
if (!is_supported(st->codec->codec_id)) {
- av_log(s1, AV_LOG_ERROR, "Unsupported codec %x\n", st->codec->codec_id);
+ av_log(s1, AV_LOG_ERROR, "Unsupported codec %s\n", avcodec_get_name(st->codec->codec_id));
return -1;
}
@@ -121,16 +121,19 @@ static int rtp_write_header(AVFormatContext *s1)
s->ssrc = av_get_random_seed();
s->first_packet = 1;
s->first_rtcp_ntp_time = ff_ntp_time();
- if (s1->start_time_realtime)
+ if (s1->start_time_realtime != 0 && s1->start_time_realtime != AV_NOPTS_VALUE)
/* Round the NTP time to whole milliseconds. */
s->first_rtcp_ntp_time = (s1->start_time_realtime / 1000) * 1000 +
NTP_OFFSET_US;
// Pick a random sequence start number, but in the lower end of the
// available range, so that any wraparound doesn't happen immediately.
// (Immediate wraparound would be an issue for SRTP.)
- if (s->seq < 0)
- s->seq = av_get_random_seed() & 0x0fff;
- else
+ if (s->seq < 0) {
+ if (s1->flags & AVFMT_FLAG_BITEXACT) {
+ s->seq = 0;
+ } else
+ s->seq = av_get_random_seed() & 0x0fff;
+ } else
s->seq &= 0xffff; // Use the given parameter, wrapped to the right interval
if (s1->packet_size) {
@@ -558,6 +561,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
const uint8_t *mb_info =
av_packet_get_side_data(pkt, AV_PKT_DATA_H263_MB_INFO,
&mb_info_size);
+ if (!mb_info) {
+ av_log(s1, AV_LOG_ERROR, "failed to allocate side data\n");
+ return AVERROR(ENOMEM);
+ }
ff_rtp_send_h263_rfc2190(s1, pkt->data, size, mb_info, mb_info_size);
break;
}
diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h
index c6ac8da43d..d34153fa67 100644
--- a/libavformat/rtpenc.h
+++ b/libavformat/rtpenc.h
@@ -2,20 +2,20 @@
* RTP muxer definitions
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_RTPENC_H
@@ -94,7 +94,7 @@ void ff_rtp_send_xiph(AVFormatContext *s1, const uint8_t *buff, int size);
void ff_rtp_send_vp8(AVFormatContext *s1, const uint8_t *buff, int size);
void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buff, int size);
-const uint8_t *ff_h263_find_resync_marker_reverse(const uint8_t *restrict start,
- const uint8_t *restrict end);
+const uint8_t *ff_h263_find_resync_marker_reverse(const uint8_t *av_restrict start,
+ const uint8_t *av_restrict end);
#endif /* AVFORMAT_RTPENC_H */
diff --git a/libavformat/rtpenc_aac.c b/libavformat/rtpenc_aac.c
index d0b4ca0964..f835183ac3 100644
--- a/libavformat/rtpenc_aac.c
+++ b/libavformat/rtpenc_aac.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2007 Luca Abeni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_amr.c b/libavformat/rtpenc_amr.c
index 0adbf49a74..8df5a3cf3e 100644
--- a/libavformat/rtpenc_amr.c
+++ b/libavformat/rtpenc_amr.c
@@ -3,20 +3,20 @@
* Copyright (c) 2007 Luca Abeni
* Copyright (c) 2009 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_chain.c b/libavformat/rtpenc_chain.c
index e58eb545b8..74f306eb96 100644
--- a/libavformat/rtpenc_chain.c
+++ b/libavformat/rtpenc_chain.c
@@ -2,27 +2,26 @@
* RTP muxer chaining code
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "avio_internal.h"
#include "rtpenc_chain.h"
-#include "avio_internal.h"
#include "rtp.h"
#include "libavutil/opt.h"
@@ -59,6 +58,8 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s,
rtpctx->max_delay = s->max_delay;
/* Copy other stream parameters. */
rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio;
+ rtpctx->flags |= s->flags & AVFMT_FLAG_MP4A_LATM;
+
/* Get the payload type from the codec */
if (st->id < RTP_PT_PRIVATE)
rtpctx->streams[0]->id =
@@ -66,6 +67,7 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s,
else
rtpctx->streams[0]->id = st->id;
+
if (av_opt_get(s, "rtpflags", AV_OPT_SEARCH_CHILDREN, &rtpflags) >= 0)
av_dict_set(&opts, "rtpflags", rtpflags, AV_DICT_DONT_STRDUP_VAL);
@@ -87,7 +89,7 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s,
if (ret) {
if (handle && rtpctx->pb) {
- avio_close(rtpctx->pb);
+ avio_closep(&rtpctx->pb);
} else if (rtpctx->pb) {
ffio_free_dyn_buf(&rtpctx->pb);
}
diff --git a/libavformat/rtpenc_chain.h b/libavformat/rtpenc_chain.h
index 4117239402..21c27c145d 100644
--- a/libavformat/rtpenc_chain.h
+++ b/libavformat/rtpenc_chain.h
@@ -2,20 +2,20 @@
* RTP muxer chaining code
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_h261.c b/libavformat/rtpenc_h261.c
index 514e7bf9ca..fc50285f5e 100644
--- a/libavformat/rtpenc_h261.c
+++ b/libavformat/rtpenc_h261.c
@@ -2,20 +2,20 @@
* RTP packetization for H.261 video (RFC 4587)
* Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,8 +24,8 @@
#define RTP_H261_HEADER_SIZE 4
-static const uint8_t *find_resync_marker_reverse(const uint8_t *restrict start,
- const uint8_t *restrict end)
+static const uint8_t *find_resync_marker_reverse(const uint8_t *av_restrict start,
+ const uint8_t *av_restrict end)
{
const uint8_t *p = end - 1;
start += 1; /* Make sure we never return the original start. */
diff --git a/libavformat/rtpenc_h263.c b/libavformat/rtpenc_h263.c
index 87f0bd7981..9cea013013 100644
--- a/libavformat/rtpenc_h263.c
+++ b/libavformat/rtpenc_h263.c
@@ -3,28 +3,28 @@
* Copyright (c) 2009 Luca Abeni
* Copyright (c) 2009 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "rtpenc.h"
-const uint8_t *ff_h263_find_resync_marker_reverse(const uint8_t *restrict start,
- const uint8_t *restrict end)
+const uint8_t *ff_h263_find_resync_marker_reverse(const uint8_t *av_restrict start,
+ const uint8_t *av_restrict end)
{
const uint8_t *p = end - 1;
start += 1; /* Make sure we never return the original start. */
diff --git a/libavformat/rtpenc_h263_rfc2190.c b/libavformat/rtpenc_h263_rfc2190.c
index f714d010f4..34b39065b8 100644
--- a/libavformat/rtpenc_h263_rfc2190.c
+++ b/libavformat/rtpenc_h263_rfc2190.c
@@ -2,20 +2,20 @@
* RTP packetization for H.263 video
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -150,9 +150,12 @@ void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size,
}
if (mb_info_pos < mb_info_count) {
const uint8_t *ptr = &mb_info[12*mb_info_pos];
+ /* get position in bits in the input packet at which the next info block should be used */
uint32_t bit_pos = AV_RL32(ptr);
- uint32_t pos = (bit_pos + 7)/8;
- if (pos <= end - buf_base) {
+ /* get position in bytes */
+ uint32_t pos_next_mb_info = (bit_pos + 7)/8;
+ /* check if data from the next MB info block should be used */
+ if (pos_next_mb_info <= end - buf_base) {
state.quant = ptr[4];
state.gobn = ptr[5];
state.mba = AV_RL16(&ptr[6]);
@@ -160,13 +163,9 @@ void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size,
state.vmv1 = (int8_t) ptr[9];
state.hmv2 = (int8_t) ptr[10];
state.vmv2 = (int8_t) ptr[11];
- ebits = 8 * pos - bit_pos;
- len = pos - (buf - buf_base);
+ ebits = 8 * pos_next_mb_info - bit_pos;
+ len = pos_next_mb_info - (buf - buf_base);
mb_info_pos++;
- } else {
- av_log(s1, AV_LOG_ERROR,
- "Unable to split H263 packet, use -mb_info %d "
- "or lower.\n", s->max_payload_size - 8);
}
} else {
av_log(s1, AV_LOG_ERROR, "Unable to split H263 packet, "
diff --git a/libavformat/rtpenc_h264_hevc.c b/libavformat/rtpenc_h264_hevc.c
index 9cfe0e2c64..7234c7ebd9 100644
--- a/libavformat/rtpenc_h264_hevc.c
+++ b/libavformat/rtpenc_h264_hevc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2008 Luca Abeni
* Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_jpeg.c b/libavformat/rtpenc_jpeg.c
index b8c880aadf..7ee26c435e 100644
--- a/libavformat/rtpenc_jpeg.c
+++ b/libavformat/rtpenc_jpeg.c
@@ -2,20 +2,20 @@
* RTP JPEG-compressed video Packetizer, RFC 2435
* Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,8 +40,8 @@ void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size)
s->timestamp = s->cur_timestamp;
/* convert video pixel dimensions from pixels to blocks */
- w = (s1->streams[0]->codec->width + 7) >> 3;
- h = (s1->streams[0]->codec->height + 7) >> 3;
+ w = FF_CEIL_RSHIFT(s1->streams[0]->codec->width, 3);
+ h = FF_CEIL_RSHIFT(s1->streams[0]->codec->height, 3);
/* get the pixel format type or fail */
if (s1->streams[0]->codec->pix_fmt == AV_PIX_FMT_YUVJ422P ||
@@ -84,6 +84,11 @@ void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size)
} else if (buf[i + 1] == SOS) {
/* SOS is last marker in the header */
i += AV_RB16(&buf[i + 2]) + 2;
+ if (i > size) {
+ av_log(s1, AV_LOG_ERROR,
+ "Insufficient data. Aborted!\n");
+ return;
+ }
break;
}
}
diff --git a/libavformat/rtpenc_latm.c b/libavformat/rtpenc_latm.c
index 64676771a7..4430c44afe 100644
--- a/libavformat/rtpenc_latm.c
+++ b/libavformat/rtpenc_latm.c
@@ -2,20 +2,20 @@
* RTP Packetization of MPEG-4 Audio (RFC 3016)
* Copyright (c) 2011 Juan Carlos Rodriguez <ing.juancarlosrodriguez@hotmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_mpegts.c b/libavformat/rtpenc_mpegts.c
index 585d1adc6d..db1680e069 100644
--- a/libavformat/rtpenc_mpegts.c
+++ b/libavformat/rtpenc_mpegts.c
@@ -2,20 +2,20 @@
* RTP/mpegts muxer
* Copyright (c) 2011 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_mpv.c b/libavformat/rtpenc_mpv.c
index 70248c408a..4b45f51772 100644
--- a/libavformat/rtpenc_mpv.c
+++ b/libavformat/rtpenc_mpv.c
@@ -3,20 +3,20 @@
* Copyright (c) 2002 Fabrice Bellard
* Copyright (c) 2007 Luca Abeni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_vp8.c b/libavformat/rtpenc_vp8.c
index d24c8bc40d..671d245758 100644
--- a/libavformat/rtpenc_vp8.c
+++ b/libavformat/rtpenc_vp8.c
@@ -2,20 +2,20 @@
* RTP VP8 Packetizer
* Copyright (c) 2010 Josh Allmann
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtpenc_xiph.c b/libavformat/rtpenc_xiph.c
index 5b171c36a2..b4d950b91d 100644
--- a/libavformat/rtpenc_xiph.c
+++ b/libavformat/rtpenc_xiph.c
@@ -2,23 +2,24 @@
* RTP packetization for Xiph audio and video
* Copyright (c) 2010 Josh Allmann
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/intreadwrite.h"
#include "avformat.h"
@@ -75,7 +76,7 @@ void ff_rtp_send_xiph(AVFormatContext *s1, const uint8_t *buff, int size)
uint8_t *ptr = s->buf_ptr + 2 + size; // what we're going to write
int remaining = end_ptr - ptr;
- assert(s->num_frames <= s->max_frames_per_packet);
+ av_assert1(s->num_frames <= s->max_frames_per_packet);
if (s->num_frames > 0 &&
(remaining < 0 ||
s->num_frames == s->max_frames_per_packet ||
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c
index cab5761f2a..d3e2ca014e 100644
--- a/libavformat/rtpproto.c
+++ b/libavformat/rtpproto.c
@@ -2,20 +2,20 @@
* RTP network protocol
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -55,6 +55,7 @@ typedef struct RTPContext {
int rtcp_port, local_rtpport, local_rtcpport;
int connect;
int pkt_size;
+ int dscp;
char *sources;
char *block;
} RTPContext;
@@ -71,6 +72,7 @@ static const AVOption options[] = {
{ "connect", "Connect socket", OFFSET(connect), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
{ "write_to_source", "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
{ "pkt_size", "Maximum packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
+ { "dscp", "DSCP class", OFFSET(dscp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "sources", "Source list", OFFSET(sources), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
{ "block", "Block list", OFFSET(block), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
{ NULL }
@@ -239,6 +241,9 @@ static void build_udp_url(RTPContext *s,
url_add_option(buf, buf_size, "pkt_size=%d", s->pkt_size);
if (s->connect)
url_add_option(buf, buf_size, "connect=1");
+ if (s->dscp >= 0)
+ url_add_option(buf, buf_size, "dscp=%d", s->dscp);
+ url_add_option(buf, buf_size, "fifo_size=0");
if (include_sources && include_sources[0])
url_add_option(buf, buf_size, "sources=%s", include_sources);
if (exclude_sources && exclude_sources[0])
@@ -298,6 +303,7 @@ static void rtp_parse_addr_list(URLContext *h, char *buf,
* 'sources=ip[,ip]' : list allowed source IP addresses
* 'block=ip[,ip]' : list disallowed source IP addresses
* 'write_to_source=0/1' : send packets to the source address of the latest received packet
+ * 'dscp=n' : set DSCP value to n (QoS)
* deprecated option:
* 'localport=n' : set the local port to n
*
@@ -316,6 +322,7 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
char buf[1024];
char path[1024];
const char *p;
+ int i, max_retry_count = 3;
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
path, sizeof(path), uri);
@@ -349,6 +356,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
s->write_to_source = strtol(buf, NULL, 10);
}
+ if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
+ s->dscp = strtol(buf, NULL, 10);
+ }
if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
av_strlcpy(include_sources, buf, sizeof(include_sources));
@@ -366,17 +376,35 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
}
}
- build_udp_url(s, buf, sizeof(buf),
- hostname, rtp_port, s->local_rtpport, sources, block);
- if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
- goto fail;
- if (s->local_rtpport >= 0 && s->local_rtcpport < 0)
- s->local_rtcpport = ff_udp_get_local_port(s->rtp_hd) + 1;
-
- build_udp_url(s, buf, sizeof(buf),
- hostname, s->rtcp_port, s->local_rtcpport, sources, block);
- if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
- goto fail;
+ for (i = 0; i < max_retry_count; i++) {
+ build_udp_url(s, buf, sizeof(buf),
+ hostname, rtp_port, s->local_rtpport,
+ sources, block);
+ if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
+ goto fail;
+ s->local_rtpport = ff_udp_get_local_port(s->rtp_hd);
+ if(s->local_rtpport == 65535) {
+ s->local_rtpport = -1;
+ continue;
+ }
+ if (s->local_rtcpport < 0) {
+ s->local_rtcpport = s->local_rtpport + 1;
+ build_udp_url(s, buf, sizeof(buf),
+ hostname, s->rtcp_port, s->local_rtcpport,
+ sources, block);
+ if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) {
+ s->local_rtpport = s->local_rtcpport = -1;
+ continue;
+ }
+ break;
+ }
+ build_udp_url(s, buf, sizeof(buf),
+ hostname, s->rtcp_port, s->local_rtcpport,
+ sources, block);
+ if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
+ goto fail;
+ break;
+ }
/* just to ease handle access. XXX: need to suppress direct handle
access */
@@ -519,10 +547,10 @@ static int rtp_close(URLContext *h)
int i;
for (i = 0; i < s->nb_ssm_include_addrs; i++)
- av_free(s->ssm_include_addrs[i]);
+ av_freep(&s->ssm_include_addrs[i]);
av_freep(&s->ssm_include_addrs);
for (i = 0; i < s->nb_ssm_exclude_addrs; i++)
- av_free(s->ssm_exclude_addrs[i]);
+ av_freep(&s->ssm_exclude_addrs[i]);
av_freep(&s->ssm_exclude_addrs);
ffurl_close(s->rtp_hd);
diff --git a/libavformat/rtpproto.h b/libavformat/rtpproto.h
index 7acc80ef8e..5b243fb248 100644
--- a/libavformat/rtpproto.h
+++ b/libavformat/rtpproto.h
@@ -1,20 +1,20 @@
/*
* RTP network protocol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index cbea685dcf..98bd4cbe9a 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -2,23 +2,24 @@
* RTSP/SDP client
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/base64.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
@@ -64,48 +65,52 @@
#define RTSP_FLAG_OPTS(name, longname) \
{ name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \
- { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }
+ { "filter_src", "only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }
#define RTSP_MEDIATYPE_OPTS(name, longname) \
- { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_DATA+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \
+ { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \
{ "video", "Video", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_VIDEO}, 0, 0, DEC, "allowed_media_types" }, \
{ "audio", "Audio", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_AUDIO}, 0, 0, DEC, "allowed_media_types" }, \
- { "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" }
+ { "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" }, \
+ { "subtitle", "Subtitle", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_SUBTITLE}, 0, 0, DEC, "allowed_media_types" }
#define COMMON_OPTS() \
- { "reorder_queue_size", "Number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \
+ { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \
{ "buffer_size", "Underlying protocol send/receive buffer size", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC } \
const AVOption ff_rtsp_options[] = {
- { "initial_pause", "Don't start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
+ { "initial_pause", "do not start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags),
- { "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \
+ { "rtsp_transport", "set RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \
{ "udp", "UDP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
{ "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
{ "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" },
{ "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" },
- RTSP_FLAG_OPTS("rtsp_flags", "RTSP flags"),
- { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
- RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
- { "min_port", "Minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
- { "max_port", "Maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
- { "timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies flag listen", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
+ RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"),
+ { "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
+ { "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" },
+ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
+ { "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
+ { "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
+ { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
+ { "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
COMMON_OPTS(),
+ { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
{ NULL },
};
static const AVOption sdp_options[] = {
RTSP_FLAG_OPTS("sdp_flags", "SDP flags"),
- { "custom_io", "Use custom IO", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" },
- { "rtcp_to_source", "Send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" },
- RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
+ { "custom_io", "use custom I/O", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" },
+ { "rtcp_to_source", "send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" },
+ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
COMMON_OPTS(),
{ NULL },
};
static const AVOption rtp_options[] = {
- RTSP_FLAG_OPTS("rtp_flags", "RTP flags"),
+ RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"),
COMMON_OPTS(),
{ NULL },
};
@@ -174,7 +179,8 @@ static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end)
if (*p == '-') {
p++;
get_word_sep(buf, sizeof(buf), "-", &p);
- av_parse_time(end, buf, 1);
+ if (av_parse_time(end, buf, 1) < 0)
+ av_log(NULL, AV_LOG_DEBUG, "Failed to parse interval end specification '%s'\n", buf);
}
}
@@ -428,8 +434,10 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
codec_type = AVMEDIA_TYPE_AUDIO;
} else if (!strcmp(st_type, "video")) {
codec_type = AVMEDIA_TYPE_VIDEO;
- } else if (!strcmp(st_type, "application") || !strcmp(st_type, "text")) {
+ } else if (!strcmp(st_type, "application")) {
codec_type = AVMEDIA_TYPE_DATA;
+ } else if (!strcmp(st_type, "text")) {
+ codec_type = AVMEDIA_TYPE_SUBTITLE;
}
if (codec_type == AVMEDIA_TYPE_UNKNOWN || !(rt->media_type_mask & (1 << codec_type))) {
s1->skip_media = 1;
@@ -470,7 +478,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
/* no corresponding stream */
if (rt->transport == RTSP_TRANSPORT_RAW) {
if (CONFIG_RTPDEC && !rt->ts)
- rt->ts = ff_mpegts_parse_open(s);
+ rt->ts = avpriv_mpegts_parse_open(s);
} else {
RTPDynamicProtocolHandler *handler;
handler = ff_rtp_handler_find_by_id(
@@ -692,13 +700,13 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
}
for (i = 0; i < s1->nb_default_include_source_addrs; i++)
- av_free(s1->default_include_source_addrs[i]);
+ av_freep(&s1->default_include_source_addrs[i]);
av_freep(&s1->default_include_source_addrs);
for (i = 0; i < s1->nb_default_exclude_source_addrs; i++)
- av_free(s1->default_exclude_source_addrs[i]);
+ av_freep(&s1->default_exclude_source_addrs[i]);
av_freep(&s1->default_exclude_source_addrs);
- rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
+ rt->p = av_malloc_array(rt->nb_rtsp_streams + 1, sizeof(struct pollfd) * 2);
if (!rt->p) return AVERROR(ENOMEM);
return 0;
}
@@ -722,7 +730,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets)
ff_rtsp_tcp_write_packet(s, rtsp_st);
ffio_free_dyn_buf(&rtpctx->pb);
} else {
- avio_close(rtpctx->pb);
+ avio_closep(&rtpctx->pb);
}
avformat_free_context(rtpctx);
} else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT)
@@ -755,23 +763,23 @@ void ff_rtsp_close_streams(AVFormatContext *s)
av_free(rtsp_st->dynamic_protocol_context);
}
for (j = 0; j < rtsp_st->nb_include_source_addrs; j++)
- av_free(rtsp_st->include_source_addrs[j]);
+ av_freep(&rtsp_st->include_source_addrs[j]);
av_freep(&rtsp_st->include_source_addrs);
for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++)
- av_free(rtsp_st->exclude_source_addrs[j]);
+ av_freep(&rtsp_st->exclude_source_addrs[j]);
av_freep(&rtsp_st->exclude_source_addrs);
- av_free(rtsp_st);
+ av_freep(&rtsp_st);
}
}
- av_free(rt->rtsp_streams);
+ av_freep(&rt->rtsp_streams);
if (rt->asf_ctx) {
avformat_close_input(&rt->asf_ctx);
}
if (CONFIG_RTPDEC && rt->ts)
- ff_mpegts_parse_close(rt->ts);
- av_free(rt->p);
- av_free(rt->recvbuf);
+ avpriv_mpegts_parse_close(rt->ts);
+ av_freep(&rt->p);
+ av_freep(&rt->recvbuf);
}
int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
@@ -792,7 +800,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
if (!st)
s->ctx_flags |= AVFMTCTX_NOHEADER;
- if (CONFIG_RTSP_MUXER && s->oformat) {
+ if (CONFIG_RTSP_MUXER && s->oformat && st) {
int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv,
s, st, rtsp_st->rtp_handle,
RTSP_TCP_MAX_PACKET_SIZE,
@@ -804,7 +812,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
st->time_base = ((AVFormatContext*)rtsp_st->transport_priv)->streams[0]->time_base;
} else if (rt->transport == RTSP_TRANSPORT_RAW) {
return 0; // Don't need to open any parser here
- } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT)
+ } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT && st)
rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
rtsp_st->dynamic_protocol_context,
rtsp_st->dynamic_handler);
@@ -1201,7 +1209,7 @@ start:
if (content_ptr)
*content_ptr = content;
else
- av_free(content);
+ av_freep(&content);
if (request) {
char buf[1024];
@@ -1290,7 +1298,7 @@ static int rtsp_send_cmd_with_content_async(AVFormatContext *s,
if (headers)
av_strlcat(buf, headers, sizeof(buf));
av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq);
- av_strlcatf(buf, sizeof(buf), "User-Agent: %s\r\n", LIBAVFORMAT_IDENT);
+ av_strlcatf(buf, sizeof(buf), "User-Agent: %s\r\n", rt->user_agent);
if (rt->session_id[0] != '\0' && (!headers ||
!strstr(headers, "\nIf-Match:"))) {
av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id);
@@ -1401,10 +1409,6 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
/* default timeout: 1 minute */
rt->timeout = 60;
- /* for each stream, make the setup request */
- /* XXX: we assume the same server is used for the control of each
- * RTSP stream */
-
/* Choose a random starting offset within the first half of the
* port range, to allow for a number of ports to try even if the offset
* happens to be at the end of the random range. */
@@ -1464,7 +1468,6 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
if (!err)
goto rtp_opened;
}
-
av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n");
err = AVERROR(EIO);
goto fail;
@@ -1532,7 +1535,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
goto fail;
} else if (reply->status_code != RTSP_STATUS_OK ||
reply->nb_transports != 1) {
- err = AVERROR_INVALIDDATA;
+ err = ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
goto fail;
}
@@ -1784,12 +1787,14 @@ redirect:
goto fail;
}
} else {
+ int ret;
/* open the tcp connection */
ff_url_join(tcpname, sizeof(tcpname), lower_rtsp_proto, NULL,
- host, port, NULL);
- if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
- &s->interrupt_callback, NULL) < 0) {
- err = AVERROR(EIO);
+ host, port,
+ "?timeout=%d", rt->stimeout);
+ if ((ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
+ &s->interrupt_callback, NULL)) < 0) {
+ err = ret;
goto fail;
}
rt->rtsp_hd_out = rt->rtsp_hd;
@@ -1828,7 +1833,7 @@ redirect:
sizeof(cmd));
ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
- err = AVERROR_INVALIDDATA;
+ err = ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
goto fail;
}
@@ -1847,6 +1852,8 @@ redirect:
err = ff_rtsp_setup_input_streams(s, reply);
else if (CONFIG_RTSP_MUXER)
err = ff_rtsp_setup_output_streams(s, host);
+ else
+ av_assert0(0);
if (err)
goto fail;
@@ -1854,6 +1861,10 @@ redirect:
int lower_transport = ff_log2_tab[lower_transport_mask &
~(lower_transport_mask - 1)];
+ if ((lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP))
+ && (rt->rtsp_flags & RTSP_FLAG_PREFER_TCP))
+ lower_transport = RTSP_LOWER_TRANSPORT_TCP;
+
err = ff_rtsp_make_setup_request(s, host, port, lower_transport,
rt->server_type == RTSP_SERVER_REAL ?
real_challenge : NULL);
@@ -1928,7 +1939,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
p[max_p].fd = fds[fdsidx];
p[max_p++].events = POLLIN;
}
- av_free(fds);
+ av_freep(&fds);
}
}
n = poll(p, max_p, POLL_TIMEOUT_MS);
@@ -2038,7 +2049,7 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
} else if (rt->transport == RTSP_TRANSPORT_RTP) {
ret = ff_rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
} else if (CONFIG_RTPDEC && rt->ts) {
- ret = ff_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos);
+ ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos);
if (ret >= 0) {
rt->recvbuf_pos += ret;
ret = rt->recvbuf_pos < rt->recvbuf_len;
@@ -2155,6 +2166,16 @@ redo:
st2->time_base);
}
}
+ // 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);
+ if (rtpctx->st) {
+ s->start_time_realtime -=
+ av_rescale (rtpctx->rtcp_ts_offset,
+ (uint64_t) rtpctx->st->time_base.num * 1000000,
+ rtpctx->st->time_base.den);
+ }
+ }
}
if (ret == -RTCP_BYE) {
rt->nb_byes++;
@@ -2167,7 +2188,7 @@ redo:
}
}
} else if (CONFIG_RTPDEC && rt->ts) {
- ret = ff_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf, len);
+ ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf, len);
if (ret >= 0) {
if (ret < len) {
rt->recvbuf_len = len;
@@ -2199,7 +2220,7 @@ static int sdp_probe(AVProbeData *p1)
/* we look for a line beginning "c=IN IP" */
while (p < p_end && *p != '\0') {
- if (p + sizeof("c=IN IP") - 1 < p_end &&
+ if (sizeof("c=IN IP") - 1 < p_end - p &&
av_strstart(p, "c=IN IP", NULL))
return AVPROBE_SCORE_EXTENSION;
@@ -2252,7 +2273,7 @@ static int sdp_read_header(AVFormatContext *s)
content[size] ='\0';
err = ff_sdp_parse(s, content);
- av_free(content);
+ av_freep(&content);
if (err) goto fail;
/* open each RTP stream */
@@ -2409,7 +2430,7 @@ static int rtp_read_header(AVFormatContext *s)
/* sdp_read_header initializes this again */
ff_network_close();
- rt->media_type_mask = (1 << (AVMEDIA_TYPE_DATA+1)) - 1;
+ rt->media_type_mask = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1;
ret = sdp_read_header(s);
s->pb = NULL;
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 74733361f9..d9e76ec667 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -2,20 +2,20 @@
* RTSP definitions
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_RTSP_H
@@ -76,7 +76,7 @@ enum RTSPControlTransport {
#define RTSP_DEFAULT_NB_AUDIO_CHANNELS 1
#define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100
#define RTSP_RTP_PORT_MIN 5000
-#define RTSP_RTP_PORT_MAX 10000
+#define RTSP_RTP_PORT_MAX 65000
/**
* This describes a single item in the "Transport:" line of one stream as
@@ -392,10 +392,20 @@ typedef struct RTSPState {
int initial_timeout;
/**
+ * timeout of socket i/o operations.
+ */
+ int stimeout;
+
+ /**
* Size of RTP packet reordering queue.
*/
int reordering_queue_size;
+ /**
+ * User-Agent string
+ */
+ char *user_agent;
+
char default_lang[4];
int buffer_size;
} RTSPState;
@@ -407,6 +417,7 @@ typedef struct RTSPState {
#define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */
#define RTSP_FLAG_RTCP_TO_SOURCE 0x8 /**< Send RTCP packets to the source
address of received packets. */
+#define RTSP_FLAG_PREFER_TCP 0x10 /**< Try RTP via TCP first if possible. */
typedef struct RTSPSource {
char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */
diff --git a/libavformat/rtspcodes.h b/libavformat/rtspcodes.h
index 31ab33699c..0ae490a42e 100644
--- a/libavformat/rtspcodes.h
+++ b/libavformat/rtspcodes.h
@@ -1,42 +1,131 @@
/*
* RTSP definitions
* copyright (c) 2002 Fabrice Bellard
+ * copyright (c) 2014 Samsung Electronics. All rights reserved.
+ * @Author: Reynaldo H. Verdejo Pinochet <r.verdejo@sisa.samsung.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_RTSPCODES_H
#define AVFORMAT_RTSPCODES_H
+#include "libavutil/common.h"
+#include "libavformat/http.h"
+
/** RTSP handling */
enum RTSPStatusCode {
-RTSP_STATUS_OK =200, /**< OK */
-RTSP_STATUS_METHOD =405, /**< Method Not Allowed */
-RTSP_STATUS_BANDWIDTH =453, /**< Not Enough Bandwidth */
-RTSP_STATUS_SESSION =454, /**< Session Not Found */
-RTSP_STATUS_STATE =455, /**< Method Not Valid in This State */
-RTSP_STATUS_AGGREGATE =459, /**< Aggregate operation not allowed */
-RTSP_STATUS_ONLY_AGGREGATE =460, /**< Only aggregate operation allowed */
-RTSP_STATUS_TRANSPORT =461, /**< Unsupported transport */
-RTSP_STATUS_INTERNAL =500, /**< Internal Server Error */
-RTSP_STATUS_SERVICE =503, /**< Service Unavailable */
-RTSP_STATUS_VERSION =505, /**< RTSP Version not supported */
+RTSP_STATUS_CONTINUE =100,
+RTSP_STATUS_OK =200,
+RTSP_STATUS_CREATED =201,
+RTSP_STATUS_LOW_ON_STORAGE_SPACE =250,
+RTSP_STATUS_MULTIPLE_CHOICES =300,
+RTSP_STATUS_MOVED_PERMANENTLY =301,
+RTSP_STATUS_MOVED_TEMPORARILY =302,
+RTSP_STATUS_SEE_OTHER =303,
+RTSP_STATUS_NOT_MODIFIED =304,
+RTSP_STATUS_USE_PROXY =305,
+RTSP_STATUS_BAD_REQUEST =400,
+RTSP_STATUS_UNAUTHORIZED =401,
+RTSP_STATUS_PAYMENT_REQUIRED =402,
+RTSP_STATUS_FORBIDDEN =403,
+RTSP_STATUS_NOT_FOUND =404,
+RTSP_STATUS_METHOD =405,
+RTSP_STATUS_NOT_ACCEPTABLE =406,
+RTSP_STATUS_PROXY_AUTH_REQUIRED =407,
+RTSP_STATUS_REQ_TIME_OUT =408,
+RTSP_STATUS_GONE =410,
+RTSP_STATUS_LENGTH_REQUIRED =411,
+RTSP_STATUS_PRECONDITION_FAILED =412,
+RTSP_STATUS_REQ_ENTITY_2LARGE =413,
+RTSP_STATUS_REQ_URI_2LARGE =414,
+RTSP_STATUS_UNSUPPORTED_MTYPE =415,
+RTSP_STATUS_PARAM_NOT_UNDERSTOOD =451,
+RTSP_STATUS_CONFERENCE_NOT_FOUND =452,
+RTSP_STATUS_BANDWIDTH =453,
+RTSP_STATUS_SESSION =454,
+RTSP_STATUS_STATE =455,
+RTSP_STATUS_INVALID_HEADER_FIELD =456,
+RTSP_STATUS_INVALID_RANGE =457,
+RTSP_STATUS_RONLY_PARAMETER =458,
+RTSP_STATUS_AGGREGATE =459,
+RTSP_STATUS_ONLY_AGGREGATE =460,
+RTSP_STATUS_TRANSPORT =461,
+RTSP_STATUS_UNREACHABLE =462,
+RTSP_STATUS_INTERNAL =500,
+RTSP_STATUS_NOT_IMPLEMENTED =501,
+RTSP_STATUS_BAD_GATEWAY =502,
+RTSP_STATUS_SERVICE =503,
+RTSP_STATUS_GATEWAY_TIME_OUT =504,
+RTSP_STATUS_VERSION =505,
+RTSP_STATUS_UNSUPPORTED_OPTION =551,
+};
+
+static const av_unused char * const rtsp_status_strings[] = {
+[RTSP_STATUS_CONTINUE] ="Continue",
+[RTSP_STATUS_OK] ="OK",
+[RTSP_STATUS_CREATED] ="Created",
+[RTSP_STATUS_LOW_ON_STORAGE_SPACE] ="Low on Storage Space",
+[RTSP_STATUS_MULTIPLE_CHOICES] ="Multiple Choices",
+[RTSP_STATUS_MOVED_PERMANENTLY] ="Moved Permanently",
+[RTSP_STATUS_MOVED_TEMPORARILY] ="Moved Temporarily",
+[RTSP_STATUS_SEE_OTHER] ="See Other",
+[RTSP_STATUS_NOT_MODIFIED] ="Not Modified",
+[RTSP_STATUS_USE_PROXY] ="Use Proxy",
+[RTSP_STATUS_BAD_REQUEST] ="Bad Request",
+[RTSP_STATUS_UNAUTHORIZED] ="Unauthorized",
+[RTSP_STATUS_PAYMENT_REQUIRED] ="Payment Required",
+[RTSP_STATUS_FORBIDDEN] ="Forbidden",
+[RTSP_STATUS_NOT_FOUND] ="Not Found",
+[RTSP_STATUS_METHOD] ="Method Not Allowed",
+[RTSP_STATUS_NOT_ACCEPTABLE] ="Not Acceptable",
+[RTSP_STATUS_PROXY_AUTH_REQUIRED] ="Proxy Authentication Required",
+[RTSP_STATUS_REQ_TIME_OUT] ="Request Time-out",
+[RTSP_STATUS_GONE] ="Gone",
+[RTSP_STATUS_LENGTH_REQUIRED] ="Length Required",
+[RTSP_STATUS_PRECONDITION_FAILED] ="Precondition Failed",
+[RTSP_STATUS_REQ_ENTITY_2LARGE] ="Request Entity Too Large",
+[RTSP_STATUS_REQ_URI_2LARGE] ="Request URI Too Large",
+[RTSP_STATUS_UNSUPPORTED_MTYPE] ="Unsupported Media Type",
+[RTSP_STATUS_PARAM_NOT_UNDERSTOOD] ="Parameter Not Understood",
+[RTSP_STATUS_CONFERENCE_NOT_FOUND] ="Conference Not Found",
+[RTSP_STATUS_BANDWIDTH] ="Not Enough Bandwidth",
+[RTSP_STATUS_SESSION] ="Session Not Found",
+[RTSP_STATUS_STATE] ="Method Not Valid in This State",
+[RTSP_STATUS_INVALID_HEADER_FIELD] ="Header Field Not Valid for Resource",
+[RTSP_STATUS_INVALID_RANGE] ="Invalid Range",
+[RTSP_STATUS_RONLY_PARAMETER] ="Parameter Is Read-Only",
+[RTSP_STATUS_AGGREGATE] ="Aggregate Operation no Allowed",
+[RTSP_STATUS_ONLY_AGGREGATE] ="Only Aggregate Operation Allowed",
+[RTSP_STATUS_TRANSPORT] ="Unsupported Transport",
+[RTSP_STATUS_UNREACHABLE] ="Destination Unreachable",
+[RTSP_STATUS_INTERNAL] ="Internal Server Error",
+[RTSP_STATUS_NOT_IMPLEMENTED] ="Not Implemented",
+[RTSP_STATUS_BAD_GATEWAY] ="Bad Gateway",
+[RTSP_STATUS_SERVICE] ="Service Unavailable",
+[RTSP_STATUS_GATEWAY_TIME_OUT] ="Gateway Time-out",
+[RTSP_STATUS_VERSION] ="RTSP Version not Supported",
+[RTSP_STATUS_UNSUPPORTED_OPTION] ="Option not supported",
};
+#define RTSP_STATUS_CODE2STRING(x) (\
+x >= 100 && x < FF_ARRAY_ELEMS(rtsp_status_strings) && rtsp_status_strings[x] \
+)? rtsp_status_strings[x] : NULL
+
enum RTSPMethod {
DESCRIBE,
ANNOUNCE,
@@ -51,4 +140,10 @@ enum RTSPMethod {
RECORD,
UNKNOWN = -1,
};
+
+static inline int ff_rtsp_averror(enum RTSPStatusCode status_code, int default_averror)
+{
+ return ff_http_averror(status_code, default_averror);
+}
+
#endif /* AVFORMAT_RTSPCODES_H */
diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c
index 4b4ae9c794..6b98861a21 100644
--- a/libavformat/rtspdec.c
+++ b/libavformat/rtspdec.c
@@ -2,20 +2,20 @@
* RTSP demuxer
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -366,8 +366,10 @@ static inline int parse_command_line(AVFormatContext *s, const char *line,
const char *linept, *searchlinept;
linept = strchr(line, ' ');
- if (!linept)
+ if (!linept) {
+ av_log(s, AV_LOG_ERROR, "Error parsing method string\n");
return AVERROR_INVALIDDATA;
+ }
if (linept - line > methodsize - 1) {
av_log(s, AV_LOG_ERROR, "Method string too long\n");
@@ -547,7 +549,7 @@ static int rtsp_read_play(AVFormatContext *s)
}
ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
- return -1;
+ return ff_rtsp_averror(reply->status_code, -1);
}
if (rt->transport == RTSP_TRANSPORT_RTP &&
reply->range_start != AV_NOPTS_VALUE) {
@@ -557,6 +559,7 @@ static int rtsp_read_play(AVFormatContext *s)
AVStream *st = NULL;
if (!rtpctx || rtsp_st->stream_index < 0)
continue;
+
st = s->streams[rtsp_st->stream_index];
rtpctx->range_start_offset =
av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
@@ -579,7 +582,7 @@ static int rtsp_read_pause(AVFormatContext *s)
else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
- return -1;
+ return ff_rtsp_averror(reply->status_code, -1);
}
}
rt->state = RTSP_STATE_PAUSED;
@@ -606,12 +609,12 @@ int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
sizeof(cmd));
}
ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content);
- if (!content)
- return AVERROR_INVALIDDATA;
if (reply->status_code != RTSP_STATUS_OK) {
av_freep(&content);
- return AVERROR_INVALIDDATA;
+ return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
}
+ if (!content)
+ return AVERROR_INVALIDDATA;
av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content);
/* now we got the SDP description, we parse it */
@@ -724,7 +727,7 @@ static int rtsp_read_header(AVFormatContext *s)
return ret;
rt->real_setup_cache = !s->nb_streams ? NULL :
- av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
+ av_mallocz_array(s->nb_streams, 2 * sizeof(*rt->real_setup_cache));
if (!rt->real_setup_cache && s->nb_streams)
return AVERROR(ENOMEM);
rt->real_setup = rt->real_setup_cache + s->nb_streams;
@@ -732,10 +735,10 @@ static int rtsp_read_header(AVFormatContext *s)
if (rt->initial_pause) {
/* do not start immediately */
} else {
- if (rtsp_read_play(s) < 0) {
+ if ((ret = rtsp_read_play(s)) < 0) {
ff_rtsp_close_streams(s);
ff_rtsp_close_connections(s);
- return AVERROR_INVALIDDATA;
+ return ret;
}
}
}
@@ -770,7 +773,7 @@ redo:
id = buf[0];
len = AV_RB16(buf + 1);
av_log(s, AV_LOG_TRACE, "id=%d len=%d\n", id, len);
- if (len > buf_size || len < 12)
+ if (len > buf_size || len < 8)
goto redo;
/* get the data */
ret = ffurl_read_complete(rt->rtsp_hd, buf, len);
@@ -829,7 +832,7 @@ retry:
ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK)
- return AVERROR_INVALIDDATA;
+ return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
rt->need_subscription = 1;
}
}
@@ -864,7 +867,7 @@ retry:
ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK)
- return AVERROR_INVALIDDATA;
+ return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
rt->need_subscription = 0;
if (rt->state == RTSP_STATE_STREAMING)
@@ -925,6 +928,7 @@ static int rtsp_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
RTSPState *rt = s->priv_data;
+ int ret;
rt->seek_timestamp = av_rescale_q(timestamp,
s->streams[stream_index]->time_base,
@@ -934,11 +938,11 @@ static int rtsp_read_seek(AVFormatContext *s, int stream_index,
case RTSP_STATE_IDLE:
break;
case RTSP_STATE_STREAMING:
- if (rtsp_read_pause(s) != 0)
- return -1;
+ if ((ret = rtsp_read_pause(s)) != 0)
+ return ret;
rt->state = RTSP_STATE_SEEKING;
- if (rtsp_read_play(s) != 0)
- return -1;
+ if ((ret = rtsp_read_play(s)) != 0)
+ return ret;
break;
case RTSP_STATE_PAUSED:
rt->state = RTSP_STATE_IDLE;
diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c
index 3db53aca07..e7707bb5fb 100644
--- a/libavformat/rtspenc.c
+++ b/libavformat/rtspenc.c
@@ -2,20 +2,20 @@
* RTSP muxer
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,7 +51,8 @@ int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr)
char *sdp;
AVFormatContext sdp_ctx, *ctx_array[1];
- s->start_time_realtime = av_gettime();
+ if (s->start_time_realtime == 0 || s->start_time_realtime == AV_NOPTS_VALUE)
+ s->start_time_realtime = av_gettime();
/* Announce the stream */
sdp = av_mallocz(SDP_MAX_SIZE);
@@ -83,7 +84,7 @@ int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr)
reply, NULL, sdp, strlen(sdp));
av_free(sdp);
if (reply->status_code != RTSP_STATUS_OK)
- return AVERROR_INVALIDDATA;
+ return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
/* Set up the RTSPStreams for each AVStream */
for (i = 0; i < s->nb_streams; i++) {
@@ -115,7 +116,7 @@ static int rtsp_write_record(AVFormatContext *s)
"Range: npt=0.000-\r\n");
ff_rtsp_send_cmd(s, "RECORD", rt->control_uri, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK)
- return -1;
+ return ff_rtsp_averror(reply->status_code, -1);
rt->state = RTSP_STATE_STREAMING;
return 0;
}
@@ -211,7 +212,7 @@ static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt)
rtsp_st = rt->rtsp_streams[pkt->stream_index];
rtpctx = rtsp_st->transport_priv;
- ret = ff_write_chained(rtpctx, 0, pkt, s);
+ ret = ff_write_chained(rtpctx, 0, pkt, s, 0);
/* ff_write_chained does all the RTP packetization. If using TCP as
* transport, rtpctx->pb is only a dyn_packet_buf that queues up the
* packets, so we need to send them out on the TCP connection separately.
diff --git a/libavformat/samidec.c b/libavformat/samidec.c
new file mode 100644
index 0000000000..948e1ed8b1
--- /dev/null
+++ b/libavformat/samidec.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * SAMI subtitle demuxer
+ * @see http://msdn.microsoft.com/en-us/library/ms971327.aspx
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavcodec/internal.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} SAMIContext;
+
+static int sami_probe(AVProbeData *p)
+{
+ char buf[6];
+ FFTextReader tr;
+ ff_text_init_buf(&tr, p->buf, p->buf_size);
+ ff_text_read(&tr, buf, sizeof(buf));
+
+ return !strncmp(buf, "<SAMI>", 6) ? AVPROBE_SCORE_MAX : 0;
+}
+
+static int sami_read_header(AVFormatContext *s)
+{
+ SAMIContext *sami = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ AVBPrint buf, hdr_buf;
+ char c = 0;
+ int res = 0, got_first_sync_point = 0;
+ FFTextReader tr;
+ ff_text_init_avio(s, &tr, s->pb);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_SAMI;
+
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&hdr_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ while (!ff_text_eof(&tr)) {
+ AVPacket *sub;
+ const int64_t pos = ff_text_pos(&tr) - (c != 0);
+ int is_sync, n = ff_smil_extract_next_text_chunk(&tr, &buf, &c);
+
+ if (n == 0)
+ break;
+
+ is_sync = !av_strncasecmp(buf.str, "<SYNC", 5);
+ if (is_sync)
+ got_first_sync_point = 1;
+
+ if (!got_first_sync_point) {
+ av_bprintf(&hdr_buf, "%s", buf.str);
+ } else {
+ sub = ff_subtitles_queue_insert(&sami->q, buf.str, buf.len, !is_sync);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ if (is_sync) {
+ const char *p = ff_smil_get_attr_ptr(buf.str, "Start");
+ sub->pos = pos;
+ sub->pts = p ? strtol(p, NULL, 10) : 0;
+ sub->duration = -1;
+ }
+ }
+ av_bprint_clear(&buf);
+ }
+
+ res = avpriv_bprint_to_extradata(st->codec, &hdr_buf);
+ if (res < 0)
+ goto end;
+
+ ff_subtitles_queue_finalize(&sami->q);
+
+end:
+ av_bprint_finalize(&buf, NULL);
+ return res;
+}
+
+static int sami_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ SAMIContext *sami = s->priv_data;
+ return ff_subtitles_queue_read_packet(&sami->q, pkt);
+}
+
+static int sami_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ SAMIContext *sami = s->priv_data;
+ return ff_subtitles_queue_seek(&sami->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int sami_read_close(AVFormatContext *s)
+{
+ SAMIContext *sami = s->priv_data;
+ ff_subtitles_queue_clean(&sami->q);
+ return 0;
+}
+
+AVInputFormat ff_sami_demuxer = {
+ .name = "sami",
+ .long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle format"),
+ .priv_data_size = sizeof(SAMIContext),
+ .read_probe = sami_probe,
+ .read_header = sami_read_header,
+ .read_packet = sami_read_packet,
+ .read_seek2 = sami_read_seek,
+ .read_close = sami_read_close,
+ .extensions = "smi,sami",
+};
diff --git a/libavformat/sapdec.c b/libavformat/sapdec.c
index 0280cead9c..2dd8524bce 100644
--- a/libavformat/sapdec.c
+++ b/libavformat/sapdec.c
@@ -2,24 +2,25 @@
* Session Announcement Protocol (RFC 2974) demuxer
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "network.h"
@@ -158,6 +159,10 @@ static int sap_read_header(AVFormatContext *s)
sap->sdp_ctx->max_delay = s->max_delay;
sap->sdp_ctx->pb = &sap->sdp_pb;
sap->sdp_ctx->interrupt_callback = s->interrupt_callback;
+
+ if ((ret = ff_copy_whitelists(sap->sdp_ctx, s)) < 0)
+ goto fail;
+
ret = avformat_open_input(&sap->sdp_ctx, "temp.sdp", infmt, NULL);
if (ret < 0)
goto fail;
diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c
index 89f7f99ecc..07fbf48e97 100644
--- a/libavformat/sapenc.c
+++ b/libavformat/sapenc.c
@@ -2,20 +2,20 @@
* Session Announcement Protocol (RFC 2974) muxer
* Copyright (c) 2010 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,7 @@ static int sap_write_close(AVFormatContext *s)
if (!rtpctx)
continue;
av_write_trailer(rtpctx);
- avio_close(rtpctx->pb);
+ avio_closep(&rtpctx->pb);
avformat_free_context(rtpctx);
s->streams[i]->priv_data = NULL;
}
@@ -134,13 +134,14 @@ static int sap_write_header(AVFormatContext *s)
freeaddrinfo(ai);
}
- contexts = av_mallocz(sizeof(AVFormatContext*) * s->nb_streams);
+ contexts = av_mallocz_array(s->nb_streams, sizeof(AVFormatContext*));
if (!contexts) {
ret = AVERROR(ENOMEM);
goto fail;
}
- s->start_time_realtime = av_gettime();
+ if (s->start_time_realtime == 0 || s->start_time_realtime == AV_NOPTS_VALUE)
+ s->start_time_realtime = av_gettime();
for (i = 0; i < s->nb_streams; i++) {
URLContext *fd;
@@ -255,7 +256,7 @@ static int sap_write_packet(AVFormatContext *s, AVPacket *pkt)
sap->last_time = now;
}
rtpctx = s->streams[pkt->stream_index]->priv_data;
- return ff_write_chained(rtpctx, 0, pkt, s);
+ return ff_write_chained(rtpctx, 0, pkt, s, 0);
}
AVOutputFormat ff_sap_muxer = {
diff --git a/libavformat/sauce.c b/libavformat/sauce.c
index a125241335..a2347b0197 100644
--- a/libavformat/sauce.c
+++ b/libavformat/sauce.c
@@ -2,20 +2,20 @@
* SAUCE header parser
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,7 +71,7 @@ int ff_sauce_read(AVFormatContext *avctx, uint64_t *fsize, int *got_width, int g
if (get_height && t2)
avctx->streams[0]->codec->height = t2<<4;
} else if (datatype == 5) {
- if (filetype > 1) {
+ if (filetype) {
avctx->streams[0]->codec->width = (filetype == 1 ? t1 : filetype) << 4;
*got_width = 1;
}
diff --git a/libavformat/sauce.h b/libavformat/sauce.h
index 62d8e688a4..0ba9ae5b4a 100644
--- a/libavformat/sauce.h
+++ b/libavformat/sauce.h
@@ -2,20 +2,20 @@
* SAUCE header parser
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/sbgdec.c b/libavformat/sbgdec.c
new file mode 100644
index 0000000000..23b7ea4489
--- /dev/null
+++ b/libavformat/sbgdec.c
@@ -0,0 +1,1512 @@
+/*
+ * SBG (SBaGen) file format decoder
+ * Copyright (c) 2011 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "libavutil/intreadwrite.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/time_internal.h"
+#include "avformat.h"
+#include "internal.h"
+
+#define SBG_SCALE (1 << 16)
+#define DAY (24 * 60 * 60)
+#define DAY_TS ((int64_t)DAY * AV_TIME_BASE)
+
+struct sbg_demuxer {
+ AVClass *class;
+ int sample_rate;
+ int frame_size;
+ int max_file_size;
+};
+
+struct sbg_string {
+ char *s;
+ char *e;
+};
+
+enum sbg_fade_type {
+ SBG_FADE_SILENCE = 0,
+ SBG_FADE_SAME = 1,
+ SBG_FADE_ADAPT = 3,
+};
+
+struct sbg_fade {
+ int8_t in, out, slide;
+};
+
+enum sbg_synth_type {
+ SBG_TYPE_NONE,
+ SBG_TYPE_SINE,
+ SBG_TYPE_NOISE,
+ SBG_TYPE_BELL,
+ SBG_TYPE_MIX,
+ SBG_TYPE_SPIN,
+};
+
+/* bell: freq constant, ampl decreases exponentially, can be approx lin */
+
+struct sbg_timestamp {
+ int64_t t;
+ char type; /* 0 for relative, 'N' for now, 'T' for absolute */
+};
+
+struct sbg_script_definition {
+ char *name;
+ int name_len;
+ int elements, nb_elements;
+ char type; /* 'S' or 'B' */
+};
+
+struct sbg_script_synth {
+ int carrier;
+ int beat;
+ int vol;
+ enum sbg_synth_type type;
+ struct {
+ int l, r;
+ } ref;
+};
+
+struct sbg_script_tseq {
+ struct sbg_timestamp ts;
+ char *name;
+ int name_len;
+ int lock;
+ struct sbg_fade fade;
+};
+
+struct sbg_script_event {
+ int64_t ts;
+ int64_t ts_int, ts_trans, ts_next;
+ int elements, nb_elements;
+ struct sbg_fade fade;
+};
+
+struct sbg_script {
+ struct sbg_script_definition *def;
+ struct sbg_script_synth *synth;
+ struct sbg_script_tseq *tseq;
+ struct sbg_script_tseq *block_tseq;
+ struct sbg_script_event *events;
+ int nb_def;
+ int nb_tseq;
+ int nb_events;
+ int nb_synth;
+ int64_t start_ts;
+ int64_t end_ts;
+ int64_t opt_fade_time;
+ int64_t opt_duration;
+ char *opt_mix;
+ int sample_rate;
+ uint8_t opt_start_at_first;
+ uint8_t opt_end_at_last;
+};
+
+struct sbg_parser {
+ void *log;
+ char *script, *end;
+ char *cursor;
+ struct sbg_script scs;
+ struct sbg_timestamp current_time;
+ int nb_block_tseq;
+ int nb_def_max, nb_synth_max, nb_tseq_max, nb_block_tseq_max;
+ int line_no;
+ char err_msg[128];
+};
+
+enum ws_interval_type {
+ WS_SINE = MKTAG('S','I','N','E'),
+ WS_NOISE = MKTAG('N','O','I','S'),
+};
+
+struct ws_interval {
+ int64_t ts1, ts2;
+ enum ws_interval_type type;
+ uint32_t channels;
+ int32_t f1, f2;
+ int32_t a1, a2;
+ uint32_t phi;
+};
+
+struct ws_intervals {
+ struct ws_interval *inter;
+ int nb_inter;
+ int max_inter;
+};
+
+static void *alloc_array_elem(void **array, size_t elsize,
+ int *size, int *max_size)
+{
+ void *ret;
+
+ if (*size == *max_size) {
+ int m = FFMAX(32, FFMIN(*max_size, INT_MAX / 2) * 2);
+ if (*size >= m)
+ return NULL;
+ *array = av_realloc_f(*array, m, elsize);
+ if (!*array)
+ return NULL;
+ *max_size = m;
+ }
+ ret = (char *)*array + elsize * *size;
+ memset(ret, 0, elsize);
+ (*size)++;
+ return ret;
+}
+
+static int str_to_time(const char *str, int64_t *rtime)
+{
+ const char *cur = str;
+ char *end;
+ int hours, minutes;
+ double seconds = 0;
+
+ if (*cur < '0' || *cur > '9')
+ return 0;
+ hours = strtol(cur, &end, 10);
+ if (end == cur || *end != ':' || end[1] < '0' || end[1] > '9')
+ return 0;
+ cur = end + 1;
+ minutes = strtol(cur, &end, 10);
+ if (end == cur)
+ return 0;
+ cur = end;
+ if (*end == ':'){
+ seconds = strtod(cur + 1, &end);
+ if (end > cur + 1)
+ cur = end;
+ }
+ *rtime = (hours * 3600 + minutes * 60 + seconds) * AV_TIME_BASE;
+ return cur - str;
+}
+
+static inline int is_space(char c)
+{
+ return c == ' ' || c == '\t' || c == '\r';
+}
+
+static inline int scale_double(void *log, double d, double m, int *r)
+{
+ m *= d * SBG_SCALE;
+ if (m < INT_MIN || m >= INT_MAX) {
+ if (log)
+ av_log(log, AV_LOG_ERROR, "%g is too large\n", d);
+ return AVERROR(EDOM);
+ }
+ *r = m;
+ return 0;
+}
+
+static int lex_space(struct sbg_parser *p)
+{
+ char *c = p->cursor;
+
+ while (p->cursor < p->end && is_space(*p->cursor))
+ p->cursor++;
+ return p->cursor > c;
+}
+
+static int lex_char(struct sbg_parser *p, char c)
+{
+ int r = p->cursor < p->end && *p->cursor == c;
+
+ p->cursor += r;
+ return r;
+}
+
+static int lex_double(struct sbg_parser *p, double *r)
+{
+ double d;
+ char *end;
+
+ if (p->cursor == p->end || is_space(*p->cursor) || *p->cursor == '\n')
+ return 0;
+ d = strtod(p->cursor, &end);
+ if (end > p->cursor) {
+ *r = d;
+ p->cursor = end;
+ return 1;
+ }
+ return 0;
+}
+
+static int lex_fixed(struct sbg_parser *p, const char *t, int l)
+{
+ if (p->end - p->cursor < l || memcmp(p->cursor, t, l))
+ return 0;
+ p->cursor += l;
+ return 1;
+}
+
+static int lex_line_end(struct sbg_parser *p)
+{
+ if (p->cursor < p->end && *p->cursor == '#') {
+ p->cursor++;
+ while (p->cursor < p->end && *p->cursor != '\n')
+ p->cursor++;
+ }
+ if (p->cursor == p->end)
+ /* simulate final LF for files lacking it */
+ return 1;
+ if (*p->cursor != '\n')
+ return 0;
+ p->cursor++;
+ p->line_no++;
+ lex_space(p);
+ return 1;
+}
+
+static int lex_wsword(struct sbg_parser *p, struct sbg_string *rs)
+{
+ char *s = p->cursor, *c = s;
+
+ if (s == p->end || *s == '\n')
+ return 0;
+ while (c < p->end && *c != '\n' && !is_space(*c))
+ c++;
+ rs->s = s;
+ rs->e = p->cursor = c;
+ lex_space(p);
+ return 1;
+}
+
+static int lex_name(struct sbg_parser *p, struct sbg_string *rs)
+{
+ char *s = p->cursor, *c = s;
+
+ while (c < p->end && ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z')
+ || (*c >= '0' && *c <= '9') || *c == '_' || *c == '-'))
+ c++;
+ if (c == s)
+ return 0;
+ rs->s = s;
+ rs->e = p->cursor = c;
+ return 1;
+}
+
+static int lex_time(struct sbg_parser *p, int64_t *rt)
+{
+ int r = str_to_time(p->cursor, rt);
+ p->cursor += r;
+ return r > 0;
+}
+
+#define FORWARD_ERROR(c) \
+ do { \
+ int errcode = c; \
+ if (errcode <= 0) \
+ return errcode ? errcode : AVERROR_INVALIDDATA; \
+ } while (0)
+
+static int parse_immediate(struct sbg_parser *p)
+{
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "immediate sequences not yet implemented");
+ return AVERROR_PATCHWELCOME;
+}
+
+static int parse_preprogrammed(struct sbg_parser *p)
+{
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "preprogrammed sequences not yet implemented");
+ return AVERROR_PATCHWELCOME;
+}
+
+static int parse_optarg(struct sbg_parser *p, char o, struct sbg_string *r)
+{
+ if (!lex_wsword(p, r)) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "option '%c' requires an argument", o);
+ return AVERROR_INVALIDDATA;
+ }
+ return 1;
+}
+
+static int parse_options(struct sbg_parser *p)
+{
+ struct sbg_string ostr, oarg;
+ char mode = 0;
+ int r;
+ char *tptr;
+ double v;
+
+ if (p->cursor == p->end || *p->cursor != '-')
+ return 0;
+ while (lex_char(p, '-') && lex_wsword(p, &ostr)) {
+ for (; ostr.s < ostr.e; ostr.s++) {
+ char opt = *ostr.s;
+ switch (opt) {
+ case 'S':
+ p->scs.opt_start_at_first = 1;
+ break;
+ case 'E':
+ p->scs.opt_end_at_last = 1;
+ break;
+ case 'i':
+ mode = 'i';
+ break;
+ case 'p':
+ mode = 'p';
+ break;
+ case 'F':
+ FORWARD_ERROR(parse_optarg(p, opt, &oarg));
+ v = strtod(oarg.s, &tptr);
+ if (oarg.e != tptr) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "syntax error for option -F");
+ return AVERROR_INVALIDDATA;
+ }
+ p->scs.opt_fade_time = v * AV_TIME_BASE / 1000;
+ break;
+ case 'L':
+ FORWARD_ERROR(parse_optarg(p, opt, &oarg));
+ r = str_to_time(oarg.s, &p->scs.opt_duration);
+ if (oarg.e != oarg.s + r) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "syntax error for option -L");
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ case 'T':
+ FORWARD_ERROR(parse_optarg(p, opt, &oarg));
+ r = str_to_time(oarg.s, &p->scs.start_ts);
+ if (oarg.e != oarg.s + r) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "syntax error for option -T");
+ return AVERROR_INVALIDDATA;
+ }
+ break;
+ case 'm':
+ FORWARD_ERROR(parse_optarg(p, opt, &oarg));
+ tptr = av_malloc(oarg.e - oarg.s + 1);
+ if (!tptr)
+ return AVERROR(ENOMEM);
+ memcpy(tptr, oarg.s, oarg.e - oarg.s);
+ tptr[oarg.e - oarg.s] = 0;
+ av_free(p->scs.opt_mix);
+ p->scs.opt_mix = tptr;
+ break;
+ case 'q':
+ FORWARD_ERROR(parse_optarg(p, opt, &oarg));
+ v = strtod(oarg.s, &tptr);
+ if (oarg.e != tptr) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "syntax error for option -q");
+ return AVERROR_INVALIDDATA;
+ }
+ if (v != 1) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "speed factor other than 1 not supported");
+ return AVERROR_PATCHWELCOME;
+ }
+ break;
+ case 'r':
+ FORWARD_ERROR(parse_optarg(p, opt, &oarg));
+ r = strtol(oarg.s, &tptr, 10);
+ if (oarg.e != tptr) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "syntax error for option -r");
+ return AVERROR_INVALIDDATA;
+ }
+ if (r < 40) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "invalid sample rate");
+ return AVERROR_PATCHWELCOME;
+ }
+ p->scs.sample_rate = r;
+ break;
+ default:
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "unknown option: '%c'", *ostr.s);
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+ switch (mode) {
+ case 'i':
+ return parse_immediate(p);
+ case 'p':
+ return parse_preprogrammed(p);
+ case 0:
+ if (!lex_line_end(p))
+ return AVERROR_INVALIDDATA;
+ return 1;
+ }
+ return AVERROR_BUG;
+}
+
+static int parse_timestamp(struct sbg_parser *p,
+ struct sbg_timestamp *rts, int64_t *rrel)
+{
+ int64_t abs = 0, rel = 0, dt;
+ char type = 0;
+ int r;
+
+ if (lex_fixed(p, "NOW", 3)) {
+ type = 'N';
+ r = 1;
+ } else {
+ r = lex_time(p, &abs);
+ if (r)
+ type = 'T';
+ }
+ while (lex_char(p, '+')) {
+ if (!lex_time(p, &dt))
+ return AVERROR_INVALIDDATA;
+ rel += dt;
+ r = 1;
+ }
+ if (r) {
+ if (!lex_space(p))
+ return AVERROR_INVALIDDATA;
+ rts->type = type;
+ rts->t = abs;
+ *rrel = rel;
+ }
+ return r;
+}
+
+static int parse_fade(struct sbg_parser *p, struct sbg_fade *fr)
+{
+ struct sbg_fade f = {0};
+
+ if (lex_char(p, '<'))
+ f.in = SBG_FADE_SILENCE;
+ else if (lex_char(p, '-'))
+ f.in = SBG_FADE_SAME;
+ else if (lex_char(p, '='))
+ f.in = SBG_FADE_ADAPT;
+ else
+ return 0;
+ if (lex_char(p, '>'))
+ f.out = SBG_FADE_SILENCE;
+ else if (lex_char(p, '-'))
+ f.out = SBG_FADE_SAME;
+ else if (lex_char(p, '='))
+ f.out = SBG_FADE_ADAPT;
+ else
+ return AVERROR_INVALIDDATA;
+ *fr = f;
+ return 1;
+}
+
+static int parse_time_sequence(struct sbg_parser *p, int inblock)
+{
+ struct sbg_timestamp ts;
+ int64_t rel_ts;
+ int r;
+ struct sbg_fade fade = { SBG_FADE_SAME, SBG_FADE_SAME, 0 };
+ struct sbg_string name;
+ struct sbg_script_tseq *tseq;
+
+ r = parse_timestamp(p, &ts, &rel_ts);
+ if (!r)
+ return 0;
+ if (r < 0)
+ return r;
+ if (ts.type) {
+ if (inblock)
+ return AVERROR_INVALIDDATA;
+ p->current_time.type = ts.type;
+ p->current_time.t = ts.t;
+ } else if(!inblock && !p->current_time.type) {
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "relative time without previous absolute time");
+ return AVERROR_INVALIDDATA;
+ }
+ ts.type = p->current_time.type;
+ ts.t = p->current_time.t + rel_ts;
+ r = parse_fade(p, &fade);
+ if (r < 0)
+ return r;
+ lex_space(p);
+ if (!lex_name(p, &name))
+ return AVERROR_INVALIDDATA;
+ lex_space(p);
+ if (lex_fixed(p, "->", 2)) {
+ fade.slide = SBG_FADE_ADAPT;
+ lex_space(p);
+ }
+ if (!lex_line_end(p))
+ return AVERROR_INVALIDDATA;
+ tseq = inblock ?
+ alloc_array_elem((void **)&p->scs.block_tseq, sizeof(*tseq),
+ &p->nb_block_tseq, &p->nb_block_tseq_max) :
+ alloc_array_elem((void **)&p->scs.tseq, sizeof(*tseq),
+ &p->scs.nb_tseq, &p->nb_tseq_max);
+ if (!tseq)
+ return AVERROR(ENOMEM);
+ tseq->ts = ts;
+ tseq->name = name.s;
+ tseq->name_len = name.e - name.s;
+ tseq->fade = fade;
+ return 1;
+}
+
+static int parse_wave_def(struct sbg_parser *p, int wavenum)
+{
+ snprintf(p->err_msg, sizeof(p->err_msg),
+ "waveform definitions not yet implemented");
+ return AVERROR_PATCHWELCOME;
+}
+
+static int parse_block_def(struct sbg_parser *p,
+ struct sbg_script_definition *def)
+{
+ int r, tseq;
+
+ lex_space(p);
+ if (!lex_line_end(p))
+ return AVERROR_INVALIDDATA;
+ tseq = p->nb_block_tseq;
+ while (1) {
+ r = parse_time_sequence(p, 1);
+ if (r < 0)
+ return r;
+ if (!r)
+ break;
+ }
+ if (!lex_char(p, '}'))
+ return AVERROR_INVALIDDATA;
+ lex_space(p);
+ if (!lex_line_end(p))
+ return AVERROR_INVALIDDATA;
+ def->type = 'B';
+ def->elements = tseq;
+ def->nb_elements = p->nb_block_tseq - tseq;
+ if (!def->nb_elements)
+ return AVERROR_INVALIDDATA;
+ return 1;
+}
+
+static int parse_volume(struct sbg_parser *p, int *vol)
+{
+ double v;
+
+ if (!lex_char(p, '/'))
+ return 0;
+ if (!lex_double(p, &v))
+ return AVERROR_INVALIDDATA;
+ if (scale_double(p->log, v, 0.01, vol))
+ return AVERROR(ERANGE);
+ return 1;
+}
+
+static int parse_synth_channel_sine(struct sbg_parser *p,
+ struct sbg_script_synth *synth)
+{
+ double carrierf, beatf;
+ int carrier, beat, vol;
+
+ if (!lex_double(p, &carrierf))
+ return 0;
+ if (!lex_double(p, &beatf))
+ beatf = 0;
+ FORWARD_ERROR(parse_volume(p, &vol));
+ if (scale_double(p->log, carrierf, 1, &carrier) < 0 ||
+ scale_double(p->log, beatf, 1, &beat) < 0)
+ return AVERROR(EDOM);
+ synth->type = SBG_TYPE_SINE;
+ synth->carrier = carrier;
+ synth->beat = beat;
+ synth->vol = vol;
+ return 1;
+}
+
+static int parse_synth_channel_pink(struct sbg_parser *p,
+ struct sbg_script_synth *synth)
+{
+ int vol;
+
+ if (!lex_fixed(p, "pink", 4))
+ return 0;
+ FORWARD_ERROR(parse_volume(p, &vol));
+ synth->type = SBG_TYPE_NOISE;
+ synth->vol = vol;
+ return 1;
+}
+
+static int parse_synth_channel_bell(struct sbg_parser *p,
+ struct sbg_script_synth *synth)
+{
+ double carrierf;
+ int carrier, vol;
+
+ if (!lex_fixed(p, "bell", 4))
+ return 0;
+ if (!lex_double(p, &carrierf))
+ return AVERROR_INVALIDDATA;
+ FORWARD_ERROR(parse_volume(p, &vol));
+ if (scale_double(p->log, carrierf, 1, &carrier) < 0)
+ return AVERROR(EDOM);
+ synth->type = SBG_TYPE_BELL;
+ synth->carrier = carrier;
+ synth->vol = vol;
+ return 1;
+}
+
+static int parse_synth_channel_mix(struct sbg_parser *p,
+ struct sbg_script_synth *synth)
+{
+ int vol;
+
+ if (!lex_fixed(p, "mix", 3))
+ return 0;
+ FORWARD_ERROR(parse_volume(p, &vol));
+ synth->type = SBG_TYPE_MIX;
+ synth->vol = vol;
+ return 1;
+}
+
+static int parse_synth_channel_spin(struct sbg_parser *p,
+ struct sbg_script_synth *synth)
+{
+ double carrierf, beatf;
+ int carrier, beat, vol;
+
+ if (!lex_fixed(p, "spin:", 5))
+ return 0;
+ if (!lex_double(p, &carrierf))
+ return AVERROR_INVALIDDATA;
+ if (!lex_double(p, &beatf))
+ return AVERROR_INVALIDDATA;
+ FORWARD_ERROR(parse_volume(p, &vol));
+ if (scale_double(p->log, carrierf, 1, &carrier) < 0 ||
+ scale_double(p->log, beatf, 1, &beat) < 0)
+ return AVERROR(EDOM);
+ synth->type = SBG_TYPE_SPIN;
+ synth->carrier = carrier;
+ synth->beat = beat;
+ synth->vol = vol;
+ return 1;
+}
+
+static int parse_synth_channel(struct sbg_parser *p)
+{
+ int r;
+ struct sbg_script_synth *synth;
+
+ synth = alloc_array_elem((void **)&p->scs.synth, sizeof(*synth),
+ &p->scs.nb_synth, &p->nb_synth_max);
+ if (!synth)
+ return AVERROR(ENOMEM);
+ r = lex_char(p, '-');
+ if (!r)
+ r = parse_synth_channel_pink(p, synth);
+ if (!r)
+ r = parse_synth_channel_bell(p, synth);
+ if (!r)
+ r = parse_synth_channel_mix(p, synth);
+ if (!r)
+ r = parse_synth_channel_spin(p, synth);
+ /* Unimplemented: wave%d:%f%f/vol (carrier, beat) */
+ if (!r)
+ r = parse_synth_channel_sine(p, synth);
+ if (r <= 0)
+ p->scs.nb_synth--;
+ return r;
+}
+
+static int parse_synth_def(struct sbg_parser *p,
+ struct sbg_script_definition *def)
+{
+ int r, synth;
+
+ synth = p->scs.nb_synth;
+ while (1) {
+ r = parse_synth_channel(p);
+ if (r < 0)
+ return r;
+ if (!r || !lex_space(p))
+ break;
+ }
+ lex_space(p);
+ if (synth == p->scs.nb_synth)
+ return AVERROR_INVALIDDATA;
+ if (!lex_line_end(p))
+ return AVERROR_INVALIDDATA;
+ def->type = 'S';
+ def->elements = synth;
+ def->nb_elements = p->scs.nb_synth - synth;
+ return 1;
+}
+
+static int parse_named_def(struct sbg_parser *p)
+{
+ char *cursor_save = p->cursor;
+ struct sbg_string name;
+ struct sbg_script_definition *def;
+
+ if (!lex_name(p, &name) || !lex_char(p, ':') || !lex_space(p)) {
+ p->cursor = cursor_save;
+ return 0;
+ }
+ if (name.e - name.s == 6 && !memcmp(name.s, "wave", 4) &&
+ name.s[4] >= '0' && name.s[4] <= '9' &&
+ name.s[5] >= '0' && name.s[5] <= '9') {
+ int wavenum = (name.s[4] - '0') * 10 + (name.s[5] - '0');
+ return parse_wave_def(p, wavenum);
+ }
+ def = alloc_array_elem((void **)&p->scs.def, sizeof(*def),
+ &p->scs.nb_def, &p->nb_def_max);
+ if (!def)
+ return AVERROR(ENOMEM);
+ def->name = name.s;
+ def->name_len = name.e - name.s;
+ if (lex_char(p, '{'))
+ return parse_block_def(p, def);
+ return parse_synth_def(p, def);
+}
+
+static void free_script(struct sbg_script *s)
+{
+ av_freep(&s->def);
+ av_freep(&s->synth);
+ av_freep(&s->tseq);
+ av_freep(&s->block_tseq);
+ av_freep(&s->events);
+ av_freep(&s->opt_mix);
+}
+
+static int parse_script(void *log, char *script, int script_len,
+ struct sbg_script *rscript)
+{
+ struct sbg_parser sp = {
+ .log = log,
+ .script = script,
+ .end = script + script_len,
+ .cursor = script,
+ .line_no = 1,
+ .err_msg = "",
+ .scs = {
+ /* default values */
+ .start_ts = AV_NOPTS_VALUE,
+ .sample_rate = 44100,
+ .opt_fade_time = 60 * AV_TIME_BASE,
+ },
+ };
+ int r;
+
+ lex_space(&sp);
+ while (sp.cursor < sp.end) {
+ r = parse_options(&sp);
+ if (r < 0)
+ goto fail;
+ if (!r && !lex_line_end(&sp))
+ break;
+ }
+ while (sp.cursor < sp.end) {
+ r = parse_named_def(&sp);
+ if (!r)
+ r = parse_time_sequence(&sp, 0);
+ if (!r)
+ r = lex_line_end(&sp) ? 1 : AVERROR_INVALIDDATA;
+ if (r < 0)
+ goto fail;
+ }
+ *rscript = sp.scs;
+ return 1;
+fail:
+ free_script(&sp.scs);
+ if (!*sp.err_msg)
+ if (r == AVERROR_INVALIDDATA)
+ snprintf(sp.err_msg, sizeof(sp.err_msg), "syntax error");
+ if (log && *sp.err_msg) {
+ const char *ctx = sp.cursor;
+ const char *ectx = av_x_if_null(memchr(ctx, '\n', sp.end - sp.cursor),
+ sp.end);
+ int lctx = ectx - ctx;
+ const char *quote = "\"";
+ if (lctx > 0 && ctx[lctx - 1] == '\r')
+ lctx--;
+ if (lctx == 0) {
+ ctx = "the end of line";
+ lctx = strlen(ctx);
+ quote = "";
+ }
+ av_log(log, AV_LOG_ERROR, "Error line %d: %s near %s%.*s%s.\n",
+ sp.line_no, sp.err_msg, quote, lctx, ctx, quote);
+ }
+ return r;
+}
+
+static int read_whole_file(AVIOContext *io, int max_size, char **rbuf)
+{
+ char *buf = NULL;
+ int size = 0, bufsize = 0, r;
+
+ while (1) {
+ if (bufsize - size < 1024) {
+ bufsize = FFMIN(FFMAX(2 * bufsize, 8192), max_size);
+ if (bufsize - size < 2) {
+ size = AVERROR(EFBIG);
+ goto fail;
+ }
+ buf = av_realloc_f(buf, bufsize, 1);
+ if (!buf) {
+ size = AVERROR(ENOMEM);
+ goto fail;
+ }
+ }
+ r = avio_read(io, buf, bufsize - size - 1);
+ if (r == AVERROR_EOF)
+ break;
+ if (r < 0)
+ goto fail;
+ size += r;
+ }
+ buf[size] = 0;
+ *rbuf = buf;
+ return size;
+fail:
+ av_free(buf);
+ return size;
+}
+
+static void expand_timestamps(void *log, struct sbg_script *s)
+{
+ int i, nb_rel = 0;
+ int64_t now, cur_ts, delta = 0;
+
+ for (i = 0; i < s->nb_tseq; i++)
+ nb_rel += s->tseq[i].ts.type == 'N';
+ if (nb_rel == s->nb_tseq) {
+ /* All ts are relative to NOW: consider NOW = 0 */
+ now = 0;
+ if (s->start_ts != AV_NOPTS_VALUE)
+ av_log(log, AV_LOG_WARNING,
+ "Start time ignored in a purely relative script.\n");
+ } else if (nb_rel == 0 && s->start_ts != AV_NOPTS_VALUE ||
+ s->opt_start_at_first) {
+ /* All ts are absolute and start time is specified */
+ if (s->start_ts == AV_NOPTS_VALUE)
+ s->start_ts = s->tseq[0].ts.t;
+ now = s->start_ts;
+ } else {
+ /* Mixed relative/absolute ts: expand */
+ time_t now0;
+ struct tm *tm, tmpbuf;
+
+ av_log(log, AV_LOG_WARNING,
+ "Scripts with mixed absolute and relative timestamps can give "
+ "unexpected results (pause, seeking, time zone change).\n");
+#undef time
+ time(&now0);
+ tm = localtime_r(&now0, &tmpbuf);
+ now = tm ? tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec :
+ now0 % DAY;
+ av_log(log, AV_LOG_INFO, "Using %02d:%02d:%02d as NOW.\n",
+ (int)(now / 3600), (int)(now / 60) % 60, (int)now % 60);
+ now *= AV_TIME_BASE;
+ for (i = 0; i < s->nb_tseq; i++) {
+ if (s->tseq[i].ts.type == 'N') {
+ s->tseq[i].ts.t += now;
+ s->tseq[i].ts.type = 'T'; /* not necessary */
+ }
+ }
+ }
+ if (s->start_ts == AV_NOPTS_VALUE)
+ s->start_ts = s->opt_start_at_first ? s->tseq[0].ts.t : now;
+ s->end_ts = s->opt_duration ? s->start_ts + s->opt_duration :
+ AV_NOPTS_VALUE; /* may be overridden later by -E option */
+ cur_ts = now;
+ for (i = 0; i < s->nb_tseq; i++) {
+ if (s->tseq[i].ts.t + delta < cur_ts)
+ delta += DAY_TS;
+ cur_ts = s->tseq[i].ts.t += delta;
+ }
+}
+
+static int expand_tseq(void *log, struct sbg_script *s, int *nb_ev_max,
+ int64_t t0, struct sbg_script_tseq *tseq)
+{
+ int i, r;
+ struct sbg_script_definition *def;
+ struct sbg_script_tseq *be;
+ struct sbg_script_event *ev;
+
+ if (tseq->lock++) {
+ av_log(log, AV_LOG_ERROR, "Recursion loop on \"%.*s\"\n",
+ tseq->name_len, tseq->name);
+ return AVERROR(EINVAL);
+ }
+ t0 += tseq->ts.t;
+ for (i = 0; i < s->nb_def; i++) {
+ if (s->def[i].name_len == tseq->name_len &&
+ !memcmp(s->def[i].name, tseq->name, tseq->name_len))
+ break;
+ }
+ if (i >= s->nb_def) {
+ av_log(log, AV_LOG_ERROR, "Tone-set \"%.*s\" not defined\n",
+ tseq->name_len, tseq->name);
+ return AVERROR(EINVAL);
+ }
+ def = &s->def[i];
+ if (def->type == 'B') {
+ be = s->block_tseq + def->elements;
+ for (i = 0; i < def->nb_elements; i++) {
+ r = expand_tseq(log, s, nb_ev_max, t0, &be[i]);
+ if (r < 0)
+ return r;
+ }
+ } else {
+ ev = alloc_array_elem((void **)&s->events, sizeof(*ev),
+ &s->nb_events, nb_ev_max);
+ ev->ts = tseq->ts.t;
+ ev->elements = def->elements;
+ ev->nb_elements = def->nb_elements;
+ ev->fade = tseq->fade;
+ }
+ tseq->lock--;
+ return 0;
+}
+
+static int expand_script(void *log, struct sbg_script *s)
+{
+ int i, r, nb_events_max = 0;
+
+ expand_timestamps(log, s);
+ for (i = 0; i < s->nb_tseq; i++) {
+ r = expand_tseq(log, s, &nb_events_max, 0, &s->tseq[i]);
+ if (r < 0)
+ return r;
+ }
+ if (!s->nb_events) {
+ av_log(log, AV_LOG_ERROR, "No events in script\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (s->opt_end_at_last)
+ s->end_ts = s->events[s->nb_events - 1].ts;
+ return 0;
+}
+
+static int add_interval(struct ws_intervals *inter,
+ enum ws_interval_type type, uint32_t channels, int ref,
+ int64_t ts1, int32_t f1, int32_t a1,
+ int64_t ts2, int32_t f2, int32_t a2)
+{
+ struct ws_interval *i, *ri;
+
+ if (ref >= 0) {
+ ri = &inter->inter[ref];
+ /* ref and new intervals are constant, identical and adjacent */
+ if (ri->type == type && ri->channels == channels &&
+ ri->f1 == ri->f2 && ri->f2 == f1 && f1 == f2 &&
+ ri->a1 == ri->a2 && ri->a2 == a1 && a1 == a2 &&
+ ri->ts2 == ts1) {
+ ri->ts2 = ts2;
+ return ref;
+ }
+ }
+ i = alloc_array_elem((void **)&inter->inter, sizeof(*i),
+ &inter->nb_inter, &inter->max_inter);
+ if (!i)
+ return AVERROR(ENOMEM);
+ i->ts1 = ts1;
+ i->ts2 = ts2;
+ i->type = type;
+ i->channels = channels;
+ i->f1 = f1;
+ i->f2 = f2;
+ i->a1 = a1;
+ i->a2 = a2;
+ i->phi = ref >= 0 ? ref | 0x80000000 : 0;
+ return i - inter->inter;
+}
+
+static int add_bell(struct ws_intervals *inter, struct sbg_script *s,
+ int64_t ts1, int64_t ts2, int32_t f, int32_t a)
+{
+ /* SBaGen uses an exponential decrease every 50ms.
+ We approximate it with piecewise affine segments. */
+ int32_t cpoints[][2] = {
+ { 2, a },
+ { 4, a - a / 4 },
+ { 8, a / 2 },
+ { 16, a / 4 },
+ { 25, a / 10 },
+ { 50, a / 80 },
+ { 75, 0 },
+ };
+ int i, r;
+ int64_t dt = s->sample_rate / 20, ts3 = ts1, ts4;
+ for (i = 0; i < FF_ARRAY_ELEMS(cpoints); i++) {
+ ts4 = FFMIN(ts2, ts1 + cpoints[i][0] * dt);
+ r = add_interval(inter, WS_SINE, 3, -1,
+ ts3, f, a, ts4, f, cpoints[i][1]);
+ if (r < 0)
+ return r;
+ ts3 = ts4;
+ a = cpoints[i][1];
+ }
+ return 0;
+}
+
+static int generate_interval(void *log, struct sbg_script *s,
+ struct ws_intervals *inter,
+ int64_t ts1, int64_t ts2,
+ struct sbg_script_synth *s1,
+ struct sbg_script_synth *s2,
+ int transition)
+{
+ int r;
+
+ if (ts2 <= ts1 || (s1->vol == 0 && s2->vol == 0))
+ return 0;
+ switch (s1->type) {
+ case SBG_TYPE_NONE:
+ break;
+ case SBG_TYPE_SINE:
+ if (s1->beat == 0 && s2->beat == 0) {
+ r = add_interval(inter, WS_SINE, 3, s1->ref.l,
+ ts1, s1->carrier, s1->vol,
+ ts2, s2->carrier, s2->vol);
+ if (r < 0)
+ return r;
+ s2->ref.l = s2->ref.r = r;
+ } else {
+ r = add_interval(inter, WS_SINE, 1, s1->ref.l,
+ ts1, s1->carrier + s1->beat / 2, s1->vol,
+ ts2, s2->carrier + s2->beat / 2, s2->vol);
+ if (r < 0)
+ return r;
+ s2->ref.l = r;
+ r = add_interval(inter, WS_SINE, 2, s1->ref.r,
+ ts1, s1->carrier - s1->beat / 2, s1->vol,
+ ts2, s2->carrier - s2->beat / 2, s2->vol);
+ if (r < 0)
+ return r;
+ s2->ref.r = r;
+ }
+ break;
+
+ case SBG_TYPE_BELL:
+ if (transition == 2) {
+ r = add_bell(inter, s, ts1, ts2, s1->carrier, s2->vol);
+ if (r < 0)
+ return r;
+ }
+ break;
+
+ case SBG_TYPE_SPIN:
+ av_log(log, AV_LOG_WARNING, "Spinning noise not implemented, "
+ "using pink noise instead.\n");
+ /* fall through */
+ case SBG_TYPE_NOISE:
+ /* SBaGen's pink noise generator uses:
+ - 1 band of white noise, mean square: 1/3;
+ - 9 bands of subsampled white noise with linear
+ interpolation, mean square: 2/3 each;
+ with 1/10 weight each: the total mean square is 7/300.
+ Our pink noise generator uses 8 bands of white noise with
+ rectangular subsampling: the total mean square is 1/24.
+ Therefore, to match SBaGen's volume, we must multiply vol by
+ sqrt((7/300) / (1/24)) = sqrt(14/25) =~ 0.748
+ */
+ r = add_interval(inter, WS_NOISE, 3, s1->ref.l,
+ ts1, 0, s1->vol - s1->vol / 4,
+ ts2, 0, s2->vol - s2->vol / 4);
+ if (r < 0)
+ return r;
+ s2->ref.l = s2->ref.r = r;
+ break;
+
+ case SBG_TYPE_MIX:
+ /* Unimplemented: silence; warning present elsewhere */
+ default:
+ av_log(log, AV_LOG_ERROR,
+ "Type %d is not implemented\n", s1->type);
+ return AVERROR_PATCHWELCOME;
+ }
+ return 0;
+}
+
+static int generate_plateau(void *log, struct sbg_script *s,
+ struct ws_intervals *inter,
+ struct sbg_script_event *ev1)
+{
+ int64_t ts1 = ev1->ts_int, ts2 = ev1->ts_trans;
+ int i, r;
+ struct sbg_script_synth *s1;
+
+ for (i = 0; i < ev1->nb_elements; i++) {
+ s1 = &s->synth[ev1->elements + i];
+ r = generate_interval(log, s, inter, ts1, ts2, s1, s1, 0);
+ if (r < 0)
+ return r;
+ }
+ return 0;
+}
+
+/*
+
+ ts1 ts2 ts1 tsmid ts2
+ | | | | |
+ v v v | v
+____ ____ v ____
+ ''''.... ''.. ..''
+ ''''....____ ''....''
+
+ compatible transition incompatible transition
+ */
+
+static int generate_transition(void *log, struct sbg_script *s,
+ struct ws_intervals *inter,
+ struct sbg_script_event *ev1,
+ struct sbg_script_event *ev2)
+{
+ int64_t ts1 = ev1->ts_trans, ts2 = ev1->ts_next;
+ /* (ts1 + ts2) / 2 without overflow */
+ int64_t tsmid = (ts1 >> 1) + (ts2 >> 1) + (ts1 & ts2 & 1);
+ enum sbg_fade_type type = ev1->fade.slide | (ev1->fade.out & ev2->fade.in);
+ int nb_elements = FFMAX(ev1->nb_elements, ev2->nb_elements);
+ struct sbg_script_synth *s1, *s2, s1mod, s2mod, smid;
+ int pass, i, r;
+
+ for (pass = 0; pass < 2; pass++) {
+ /* pass = 0 -> compatible and first half of incompatible
+ pass = 1 -> second half of incompatible
+ Using two passes like that ensures that the intervals are generated
+ in increasing order according to their start timestamp.
+ Otherwise it would be necessary to sort them
+ while keeping the mutual references.
+ */
+ for (i = 0; i < nb_elements; i++) {
+ s1 = i < ev1->nb_elements ? &s->synth[ev1->elements + i] : &s1mod;
+ s2 = i < ev2->nb_elements ? &s->synth[ev2->elements + i] : &s2mod;
+ s1mod = s1 != &s1mod ? *s1 : (struct sbg_script_synth){ 0 };
+ s2mod = s2 != &s2mod ? *s2 : (struct sbg_script_synth){ 0 };
+ if (ev1->fade.slide) {
+ /* for slides, and only for slides, silence ("-") is equivalent
+ to anything with volume 0 */
+ if (s1mod.type == SBG_TYPE_NONE) {
+ s1mod = s2mod;
+ s1mod.vol = 0;
+ } else if (s2mod.type == SBG_TYPE_NONE) {
+ s2mod = s1mod;
+ s2mod.vol = 0;
+ }
+ }
+ if (s1mod.type == s2mod.type &&
+ s1mod.type != SBG_TYPE_BELL &&
+ (type == SBG_FADE_ADAPT ||
+ (s1mod.carrier == s2mod.carrier &&
+ s1mod.beat == s2mod.beat))) {
+ /* compatible: single transition */
+ if (!pass) {
+ r = generate_interval(log, s, inter,
+ ts1, ts2, &s1mod, &s2mod, 3);
+ if (r < 0)
+ return r;
+ s2->ref = s2mod.ref;
+ }
+ } else {
+ /* incompatible: silence at midpoint */
+ if (!pass) {
+ smid = s1mod;
+ smid.vol = 0;
+ r = generate_interval(log, s, inter,
+ ts1, tsmid, &s1mod, &smid, 1);
+ if (r < 0)
+ return r;
+ } else {
+ smid = s2mod;
+ smid.vol = 0;
+ r = generate_interval(log, s, inter,
+ tsmid, ts2, &smid, &s2mod, 2);
+ if (r < 0)
+ return r;
+ s2->ref = s2mod.ref;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ ev1 trats ev2 intts endts ev3
+ | | | | | |
+ v v v v v v
+ ________________
+.... .... ....
+ '''....________________....''' '''...._______________
+
+\_________/\______________/\_________/\______________/\_________/\_____________/
+ tr x->1 int1 tr 1->2 int2 tr 2->3 int3
+ */
+
+static int generate_intervals(void *log, struct sbg_script *s, int sample_rate,
+ struct ws_intervals *inter)
+{
+ int64_t trans_time = s->opt_fade_time / 2;
+ struct sbg_script_event ev0, *ev1, *ev2;
+ int64_t period;
+ int i, r;
+
+ /* SBaGen handles the time before and after the extremal events,
+ and the corresponding transitions, as if the sequence were cyclic
+ with a 24-hours period. */
+ period = s->events[s->nb_events - 1].ts - s->events[0].ts;
+ period = (period + (DAY_TS - 1)) / DAY_TS * DAY_TS;
+ period = FFMAX(period, DAY_TS);
+
+ /* Prepare timestamps for transitions */
+ for (i = 0; i < s->nb_events; i++) {
+ ev1 = &s->events[i];
+ ev2 = &s->events[(i + 1) % s->nb_events];
+ ev1->ts_int = ev1->ts;
+ ev1->ts_trans = ev1->fade.slide ? ev1->ts
+ : ev2->ts + (ev1 < ev2 ? 0 : period);
+ }
+ for (i = 0; i < s->nb_events; i++) {
+ ev1 = &s->events[i];
+ ev2 = &s->events[(i + 1) % s->nb_events];
+ if (!ev1->fade.slide) {
+ ev1->ts_trans = FFMAX(ev1->ts_int, ev1->ts_trans - trans_time);
+ ev2->ts_int = FFMIN(ev2->ts_trans, ev2->ts_int + trans_time);
+ }
+ ev1->ts_next = ev2->ts_int + (ev1 < ev2 ? 0 : period);
+ }
+
+ /* Pseudo event before the first one */
+ ev0 = s->events[s->nb_events - 1];
+ ev0.ts_int -= period;
+ ev0.ts_trans -= period;
+ ev0.ts_next -= period;
+
+ /* Convert timestamps */
+ for (i = -1; i < s->nb_events; i++) {
+ ev1 = i < 0 ? &ev0 : &s->events[i];
+ ev1->ts_int = av_rescale(ev1->ts_int, sample_rate, AV_TIME_BASE);
+ ev1->ts_trans = av_rescale(ev1->ts_trans, sample_rate, AV_TIME_BASE);
+ ev1->ts_next = av_rescale(ev1->ts_next, sample_rate, AV_TIME_BASE);
+ }
+
+ /* Generate intervals */
+ for (i = 0; i < s->nb_synth; i++)
+ s->synth[i].ref.l = s->synth[i].ref.r = -1;
+ for (i = -1; i < s->nb_events; i++) {
+ ev1 = i < 0 ? &ev0 : &s->events[i];
+ ev2 = &s->events[(i + 1) % s->nb_events];
+ r = generate_plateau(log, s, inter, ev1);
+ if (r < 0)
+ return r;
+ r = generate_transition(log, s, inter, ev1, ev2);
+ if (r < 0)
+ return r;
+ }
+ if (!inter->nb_inter)
+ av_log(log, AV_LOG_WARNING, "Completely silent script.\n");
+ return 0;
+}
+
+static int encode_intervals(struct sbg_script *s, AVCodecContext *avc,
+ struct ws_intervals *inter)
+{
+ int i, edata_size = 4;
+ uint8_t *edata;
+
+ for (i = 0; i < inter->nb_inter; i++) {
+ edata_size += inter->inter[i].type == WS_SINE ? 44 :
+ inter->inter[i].type == WS_NOISE ? 32 : 0;
+ if (edata_size < 0)
+ return AVERROR(ENOMEM);
+ }
+ if (ff_alloc_extradata(avc, edata_size))
+ return AVERROR(ENOMEM);
+ edata = avc->extradata;
+
+#define ADD_EDATA32(v) do { AV_WL32(edata, (v)); edata += 4; } while(0)
+#define ADD_EDATA64(v) do { AV_WL64(edata, (v)); edata += 8; } while(0)
+ ADD_EDATA32(inter->nb_inter);
+ for (i = 0; i < inter->nb_inter; i++) {
+ ADD_EDATA64(inter->inter[i].ts1);
+ ADD_EDATA64(inter->inter[i].ts2);
+ ADD_EDATA32(inter->inter[i].type);
+ ADD_EDATA32(inter->inter[i].channels);
+ switch (inter->inter[i].type) {
+ case WS_SINE:
+ ADD_EDATA32(inter->inter[i].f1);
+ ADD_EDATA32(inter->inter[i].f2);
+ ADD_EDATA32(inter->inter[i].a1);
+ ADD_EDATA32(inter->inter[i].a2);
+ ADD_EDATA32(inter->inter[i].phi);
+ break;
+ case WS_NOISE:
+ ADD_EDATA32(inter->inter[i].a1);
+ ADD_EDATA32(inter->inter[i].a2);
+ break;
+ }
+ }
+ if (edata != avc->extradata + edata_size)
+ return AVERROR_BUG;
+ return 0;
+}
+
+static av_cold int sbg_read_probe(AVProbeData *p)
+{
+ int r, score;
+ struct sbg_script script = { 0 };
+
+ r = parse_script(NULL, p->buf, p->buf_size, &script);
+ score = r < 0 || !script.nb_def || !script.nb_tseq ? 0 :
+ AVPROBE_SCORE_MAX / 3;
+ free_script(&script);
+ return score;
+}
+
+static av_cold int sbg_read_header(AVFormatContext *avf)
+{
+ struct sbg_demuxer *sbg = avf->priv_data;
+ int r;
+ char *buf = NULL;
+ struct sbg_script script = { 0 };
+ AVStream *st;
+ struct ws_intervals inter = { 0 };
+
+ r = read_whole_file(avf->pb, sbg->max_file_size, &buf);
+ if (r < 0)
+ goto fail;
+ r = parse_script(avf, buf, r, &script);
+ if (r < 0)
+ goto fail;
+ if (!sbg->sample_rate)
+ sbg->sample_rate = script.sample_rate;
+ else
+ script.sample_rate = sbg->sample_rate;
+ if (!sbg->frame_size)
+ sbg->frame_size = FFMAX(1, sbg->sample_rate / 10);
+ if (script.opt_mix)
+ av_log(avf, AV_LOG_WARNING, "Mix feature not implemented: "
+ "-m is ignored and mix channels will be silent.\n");
+ r = expand_script(avf, &script);
+ if (r < 0)
+ goto fail;
+ av_freep(&buf);
+ r = generate_intervals(avf, &script, sbg->sample_rate, &inter);
+ if (r < 0)
+ goto fail;
+
+ st = avformat_new_stream(avf, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codec->codec_id = AV_CODEC_ID_FFWAVESYNTH;
+ st->codec->channels = 2;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ st->codec->sample_rate = sbg->sample_rate;
+ st->codec->frame_size = sbg->frame_size;
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ st->probe_packets = 0;
+ st->start_time = av_rescale(script.start_ts,
+ sbg->sample_rate, AV_TIME_BASE);
+ st->duration = script.end_ts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
+ av_rescale(script.end_ts - script.start_ts,
+ sbg->sample_rate, AV_TIME_BASE);
+ st->cur_dts = st->start_time;
+ r = encode_intervals(&script, st->codec, &inter);
+ if (r < 0)
+ goto fail;
+
+ av_free(inter.inter);
+ free_script(&script);
+ return 0;
+
+fail:
+ av_free(inter.inter);
+ free_script(&script);
+ av_free(buf);
+ return r;
+}
+
+static int sbg_read_packet(AVFormatContext *avf, AVPacket *packet)
+{
+ int64_t ts, end_ts;
+
+ ts = avf->streams[0]->cur_dts;
+ end_ts = ts + avf->streams[0]->codec->frame_size;
+ if (avf->streams[0]->duration != AV_NOPTS_VALUE)
+ end_ts = FFMIN(avf->streams[0]->start_time + avf->streams[0]->duration,
+ end_ts);
+ if (end_ts <= ts)
+ return AVERROR_EOF;
+ if (av_new_packet(packet, 12) < 0)
+ return AVERROR(ENOMEM);
+ packet->dts = packet->pts = ts;
+ packet->duration = end_ts - ts;
+ AV_WL64(packet->data + 0, ts);
+ AV_WL32(packet->data + 8, packet->duration);
+ return packet->size;
+}
+
+static int sbg_read_seek2(AVFormatContext *avf, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ if (flags || stream_index > 0)
+ return AVERROR(EINVAL);
+ if (stream_index < 0)
+ ts = av_rescale_q(ts, AV_TIME_BASE_Q, avf->streams[0]->time_base);
+ avf->streams[0]->cur_dts = ts;
+ return 0;
+}
+
+static int sbg_read_seek(AVFormatContext *avf, int stream_index,
+ int64_t ts, int flags)
+{
+ return sbg_read_seek2(avf, stream_index, ts, ts, ts, 0);
+}
+
+static const AVOption sbg_options[] = {
+ { "sample_rate", "", offsetof(struct sbg_demuxer, sample_rate),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX,
+ AV_OPT_FLAG_DECODING_PARAM },
+ { "frame_size", "", offsetof(struct sbg_demuxer, frame_size),
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX,
+ AV_OPT_FLAG_DECODING_PARAM },
+ { "max_file_size", "", offsetof(struct sbg_demuxer, max_file_size),
+ AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX,
+ AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass sbg_demuxer_class = {
+ .class_name = "sbg_demuxer",
+ .item_name = av_default_item_name,
+ .option = sbg_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_sbg_demuxer = {
+ .name = "sbg",
+ .long_name = NULL_IF_CONFIG_SMALL("SBaGen binaural beats script"),
+ .priv_data_size = sizeof(struct sbg_demuxer),
+ .read_probe = sbg_read_probe,
+ .read_header = sbg_read_header,
+ .read_packet = sbg_read_packet,
+ .read_seek = sbg_read_seek,
+ .read_seek2 = sbg_read_seek2,
+ .extensions = "sbg",
+ .priv_class = &sbg_demuxer_class,
+};
diff --git a/libavformat/sctp.c b/libavformat/sctp.c
index 71b3a4b3db..3dae13ec6f 100644
--- a/libavformat/sctp.c
+++ b/libavformat/sctp.c
@@ -2,20 +2,20 @@
* SCTP protocol
* Copyright (c) 2012 Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -99,7 +99,7 @@ static int ff_sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from,
if (msg_flags)
*msg_flags = inmsg.msg_flags;
- for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL;
+ for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg;
cmsg = CMSG_NXTHDR(&inmsg, cmsg)) {
if ((IPPROTO_SCTP == cmsg->cmsg_level) &&
(SCTP_SNDRCV == cmsg->cmsg_type))
@@ -122,7 +122,7 @@ static int ff_sctp_send(int s, const void *msg, size_t len,
outmsg.msg_name = NULL;
outmsg.msg_namelen = 0;
outmsg.msg_iov = &iov;
- iov.iov_base = msg;
+ iov.iov_base = (void*)msg;
iov.iov_len = len;
outmsg.msg_iovlen = 1;
outmsg.msg_controllen = 0;
@@ -335,8 +335,10 @@ static int sctp_write(URLContext *h, const uint8_t *buf, int size)
/*StreamId is introduced as a 2byte code into the stream*/
struct sctp_sndrcvinfo info = { 0 };
info.sinfo_stream = AV_RB16(buf);
- if (info.sinfo_stream > s->max_streams)
+ if (info.sinfo_stream > s->max_streams) {
+ av_log(h, AV_LOG_ERROR, "bad input data\n");
return AVERROR_BUG;
+ }
ret = ff_sctp_send(s->fd, buf + 2, size - 2, &info, MSG_EOR);
} else
ret = send(s->fd, buf, size, MSG_NOSIGNAL);
diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index fe43e04361..4d621c7ffc 100644
--- a/libavformat/sdp.c
+++ b/libavformat/sdp.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2007 Luca Abeni
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -203,7 +203,7 @@ static char *extradata2psets(AVCodecContext *c)
sps_end = r1;
}
if (!av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r)) {
- av_log(c, AV_LOG_ERROR, "Cannot Base64-encode %td %td!\n", MAX_PSET_SIZE - (p - psets), r1 - r);
+ av_log(c, AV_LOG_ERROR, "Cannot Base64-encode %"PTRDIFF_SPECIFIER" %"PTRDIFF_SPECIFIER"!\n", MAX_PSET_SIZE - (p - psets), r1 - r);
av_free(psets);
av_free(tmpbuf);
@@ -348,7 +348,7 @@ static char *extradata2config(AVCodecContext *c)
static char *xiph_extradata2config(AVCodecContext *c)
{
char *config, *encoded_config;
- uint8_t *header_start[3];
+ const uint8_t *header_start[3];
int headers_len, header_len[3], config_len;
int first_header_size;
@@ -544,7 +544,7 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c,
payload_type, config ? config : "");
break;
case AV_CODEC_ID_AAC:
- if (fmt && fmt->oformat->priv_class &&
+ if (fmt && fmt->oformat && fmt->oformat->priv_class &&
av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) {
config = latm_context2config(c);
if (!config)
@@ -681,6 +681,20 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c,
case AV_CODEC_ID_SPEEX:
av_strlcatf(buff, size, "a=rtpmap:%d speex/%d\r\n",
payload_type, c->sample_rate);
+ if (c->codec) {
+ const char *mode;
+ uint64_t vad_option;
+
+ if (c->flags & CODEC_FLAG_QSCALE)
+ mode = "on";
+ else if (!av_opt_get_int(c, "vad", AV_OPT_FLAG_ENCODING_PARAM, &vad_option) && vad_option)
+ mode = "vad";
+ else
+ mode = "off";
+
+ av_strlcatf(buff, size, "a=fmtp:%d vbr=%s\r\n",
+ payload_type, mode);
+ }
break;
case AV_CODEC_ID_OPUS:
/* The opus RTP draft says that all opus streams MUST be declared
diff --git a/libavformat/sdr2.c b/libavformat/sdr2.c
new file mode 100644
index 0000000000..82405f69d1
--- /dev/null
+++ b/libavformat/sdr2.c
@@ -0,0 +1,121 @@
+/*
+ * SDR2 demuxer
+ * Copyright (c) 2014 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
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+
+static int sdr2_probe(AVProbeData *p)
+{
+ if (AV_RL32(p->buf) != MKTAG('S', 'R', 'A', 1))
+ return 0;
+
+ return AVPROBE_SCORE_EXTENSION;
+}
+
+#define FIRST 0xA8
+
+static int sdr2_read_header(AVFormatContext *s)
+{
+ AVStream *st, *ast;
+
+ ast = avformat_new_stream(s, 0);
+ if (!ast)
+ return AVERROR(ENOMEM);
+
+ st = avformat_new_stream(s, 0);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ avio_skip(s->pb, 20);
+ avpriv_set_pts_info(st, 64, 1, avio_rl32(s->pb));
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->width = avio_rl32(s->pb);
+ st->codec->height = avio_rl32(s->pb);
+ st->codec->codec_id = AV_CODEC_ID_H264;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->channels = 1;
+ ast->codec->sample_rate = 8000;
+ ast->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
+ avpriv_set_pts_info(ast, 64, 1, 8000);
+
+ avio_seek(s->pb, FIRST, SEEK_SET);
+
+ return 0;
+}
+
+static const uint8_t header[24] = {
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+ 0xa6, 0x80, 0xb0, 0x7e, 0x40, 0x00, 0x00, 0x00,
+ 0x01, 0x68, 0xce, 0x38, 0x80, 0x00, 0x00, 0x00
+};
+
+static int sdr2_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int64_t pos;
+ unsigned next;
+ int flags, ret = 0, is_video;
+
+ pos = avio_tell(s->pb);
+
+ flags = avio_rl32(s->pb);
+ avio_skip(s->pb, 4);
+
+ next = avio_rl32(s->pb);
+ if (next <= 52)
+ return AVERROR_INVALIDDATA;
+
+ avio_skip(s->pb, 6);
+ is_video = avio_rl32(s->pb);
+ avio_skip(s->pb, 30);
+
+ if (pos == FIRST) {
+ if (av_new_packet(pkt, next - 52 + 24) < 0)
+ return AVERROR(ENOMEM);
+ memcpy(pkt->data, header, 24);
+ ret = avio_read(s->pb, pkt->data + 24, next - 52);
+ if (ret < 0) {
+ av_free_packet(pkt);
+ return ret;
+ }
+ av_shrink_packet(pkt, ret + 24);
+ } else {
+ ret = av_get_packet(s->pb, pkt, next - 52);
+ }
+ pkt->stream_index = !!is_video;
+ pkt->pos = pos;
+ if (flags & (1 << 12))
+ pkt->flags |= AV_PKT_FLAG_KEY;
+
+ return ret;
+}
+
+AVInputFormat ff_sdr2_demuxer = {
+ .name = "sdr2",
+ .long_name = NULL_IF_CONFIG_SMALL("SDR2"),
+ .read_probe = sdr2_probe,
+ .read_header = sdr2_read_header,
+ .read_packet = sdr2_read_packet,
+ .extensions = "sdr2",
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/seek-test.c b/libavformat/seek-test.c
index 143f0b5ace..1dd041d851 100644
--- a/libavformat/seek-test.c
+++ b/libavformat/seek-test.c
@@ -2,20 +2,20 @@
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2007 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,13 +45,12 @@ static const char *ret_str(int v)
static void ts_str(char buffer[60], int64_t ts, AVRational base)
{
- double tsval;
if (ts == AV_NOPTS_VALUE) {
strcpy(buffer, " NOPTS ");
return;
}
- tsval = ts * av_q2d(base);
- snprintf(buffer, 60, "%9f", tsval);
+ ts= av_rescale_q(ts, base, (AVRational){1, 1000000});
+ snprintf(buffer, 60, "%c%"PRId64".%06"PRId64"", ts<0 ? '-' : ' ', FFABS(ts)/1000000, FFABS(ts)%1000000);
}
int main(int argc, char **argv)
@@ -59,8 +58,30 @@ int main(int argc, char **argv)
const char *filename;
AVFormatContext *ic = NULL;
int i, ret, stream_id;
+ int j;
int64_t timestamp;
AVDictionary *format_opts = NULL;
+ int64_t seekfirst = AV_NOPTS_VALUE;
+ int firstback=0;
+ int frame_count = 1;
+ int duration = 4;
+
+ for(i=2; i<argc; i+=2){
+ if (!strcmp(argv[i], "-seekforw")){
+ seekfirst = atoi(argv[i+1]);
+ } else if(!strcmp(argv[i], "-seekback")){
+ seekfirst = atoi(argv[i+1]);
+ firstback = 1;
+ } else if(!strcmp(argv[i], "-frames")){
+ frame_count = atoi(argv[i+1]);
+ } else if(!strcmp(argv[i], "-duration")){
+ duration = atoi(argv[i+1]);
+ } else if(!strcmp(argv[i], "-usetoc")) {
+ av_dict_set(&format_opts, "usetoc", argv[i+1], 0);
+ } else {
+ argc = 1;
+ }
+ }
av_dict_set(&format_opts, "channels", "1", 0);
av_dict_set(&format_opts, "sample_rate", "22050", 0);
@@ -68,7 +89,7 @@ int main(int argc, char **argv)
/* initialize libavcodec, and register all codecs and formats */
av_register_all();
- if (argc != 2) {
+ if (argc < 2) {
printf("usage: %s input_file\n"
"\n", argv[0]);
return 1;
@@ -89,12 +110,17 @@ int main(int argc, char **argv)
return 1;
}
+ if(seekfirst != AV_NOPTS_VALUE){
+ if(firstback) avformat_seek_file(ic, -1, INT64_MIN, seekfirst, seekfirst, 0);
+ else avformat_seek_file(ic, -1, seekfirst, seekfirst, INT64_MAX, 0);
+ }
for(i=0; ; i++){
AVPacket pkt = { 0 };
AVStream *av_uninit(st);
char ts_buf[60];
if(ret>=0){
+ for(j=0; j<frame_count; j++) {
ret= av_read_frame(ic, &pkt);
if(ret>=0){
char dts_buf[60];
@@ -106,12 +132,13 @@ int main(int argc, char **argv)
} else
printf("ret:%s", ret_str(ret)); // necessary to avoid trailing whitespace
printf("\n");
+ }
}
if(i>25) break;
stream_id= (i>>1)%(ic->nb_streams+1) - 1;
- timestamp= (i*19362894167LL) % (4*AV_TIME_BASE) - AV_TIME_BASE;
+ timestamp= (i*19362894167LL) % (duration*AV_TIME_BASE) - AV_TIME_BASE;
if(stream_id>=0){
st= ic->streams[stream_id];
timestamp= av_rescale_q(timestamp, AV_TIME_BASE_Q, st->time_base);
diff --git a/libavformat/segafilm.c b/libavformat/segafilm.c
index 04b817789d..44fa683a71 100644
--- a/libavformat/segafilm.c
+++ b/libavformat/segafilm.c
@@ -1,21 +1,21 @@
/*
* Sega FILM Format (CPK) Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
+#include "avio_internal.h"
#define FILM_TAG MKBETAG('F', 'I', 'L', 'M')
#define FDSC_TAG MKBETAG('F', 'D', 'S', 'C')
@@ -61,10 +62,6 @@ typedef struct FilmDemuxContext {
unsigned int base_clock;
unsigned int version;
-
- /* buffer used for interleaving stereo PCM data */
- unsigned char *stereo_buffer;
- int stereo_buffer_size;
} FilmDemuxContext;
static int film_probe(AVProbeData *p)
@@ -72,6 +69,9 @@ static int film_probe(AVProbeData *p)
if (AV_RB32(&p->buf[0]) != FILM_TAG)
return 0;
+ if (AV_RB32(&p->buf[16]) != FDSC_TAG)
+ return 0;
+
return AVPROBE_SCORE_MAX;
}
@@ -80,7 +80,6 @@ static int film_read_close(AVFormatContext *s)
FilmDemuxContext *film = s->priv_data;
av_freep(&film->sample_table);
- av_freep(&film->stereo_buffer);
return 0;
}
@@ -96,8 +95,6 @@ static int film_read_header(AVFormatContext *s)
unsigned int audio_frame_counter;
film->sample_table = NULL;
- film->stereo_buffer = NULL;
- film->stereo_buffer_size = 0;
/* load the main FILM header */
if (avio_read(pb, scratch, 16) != 16)
@@ -121,19 +118,14 @@ static int film_read_header(AVFormatContext *s)
return AVERROR(EIO);
film->audio_samplerate = AV_RB16(&scratch[24]);
film->audio_channels = scratch[21];
- if (!film->audio_channels || film->audio_channels > 2) {
- av_log(s, AV_LOG_ERROR,
- "Invalid number of channels: %d\n", film->audio_channels);
- return AVERROR_INVALIDDATA;
- }
film->audio_bits = scratch[22];
- if (scratch[23] == 2)
+ if (scratch[23] == 2 && film->audio_channels > 0)
film->audio_type = AV_CODEC_ID_ADPCM_ADX;
else if (film->audio_channels > 0) {
if (film->audio_bits == 8)
- film->audio_type = AV_CODEC_ID_PCM_S8;
+ film->audio_type = AV_CODEC_ID_PCM_S8_PLANAR;
else if (film->audio_bits == 16)
- film->audio_type = AV_CODEC_ID_PCM_S16BE;
+ film->audio_type = AV_CODEC_ID_PCM_S16BE_PLANAR;
else
film->audio_type = AV_CODEC_ID_NONE;
} else
@@ -207,7 +199,7 @@ static int film_read_header(AVFormatContext *s)
film->sample_count = AV_RB32(&scratch[12]);
if(film->sample_count >= UINT_MAX / sizeof(film_sample))
return -1;
- film->sample_table = av_malloc(film->sample_count * sizeof(film_sample));
+ film->sample_table = av_malloc_array(film->sample_count, sizeof(film_sample));
if (!film->sample_table)
return AVERROR(ENOMEM);
@@ -265,66 +257,19 @@ static int film_read_packet(AVFormatContext *s,
AVIOContext *pb = s->pb;
film_sample *sample;
int ret = 0;
- int i;
- int left, right;
if (film->current_sample >= film->sample_count)
- return AVERROR(EIO);
+ return AVERROR_EOF;
sample = &film->sample_table[film->current_sample];
/* position the stream (will probably be there anyway) */
avio_seek(pb, sample->sample_offset, SEEK_SET);
- /* do a special song and dance when loading FILM Cinepak chunks */
- if ((sample->stream == film->video_stream_index) &&
- (film->video_type == AV_CODEC_ID_CINEPAK)) {
- pkt->pos= avio_tell(pb);
- if (av_new_packet(pkt, sample->sample_size))
- return AVERROR(ENOMEM);
- avio_read(pb, pkt->data, sample->sample_size);
- } else if ((sample->stream == film->audio_stream_index) &&
- (film->audio_channels == 2) &&
- (film->audio_type != AV_CODEC_ID_ADPCM_ADX)) {
- /* stereo PCM needs to be interleaved */
-
- if (av_new_packet(pkt, sample->sample_size))
- return AVERROR(ENOMEM);
- /* make sure the interleave buffer is large enough */
- if (sample->sample_size > film->stereo_buffer_size) {
- av_free(film->stereo_buffer);
- film->stereo_buffer_size = sample->sample_size;
- film->stereo_buffer = av_malloc(film->stereo_buffer_size);
- if (!film->stereo_buffer) {
- film->stereo_buffer_size = 0;
- return AVERROR(ENOMEM);
- }
- }
-
- pkt->pos= avio_tell(pb);
- ret = avio_read(pb, film->stereo_buffer, sample->sample_size);
- if (ret != sample->sample_size)
- ret = AVERROR(EIO);
-
- left = 0;
- right = sample->sample_size / 2;
- for (i = 0; i < sample->sample_size; ) {
- if (film->audio_bits == 8) {
- pkt->data[i++] = film->stereo_buffer[left++];
- pkt->data[i++] = film->stereo_buffer[right++];
- } else {
- pkt->data[i++] = film->stereo_buffer[left++];
- pkt->data[i++] = film->stereo_buffer[left++];
- pkt->data[i++] = film->stereo_buffer[right++];
- pkt->data[i++] = film->stereo_buffer[right++];
- }
- }
- } else {
- ret= av_get_packet(pb, pkt, sample->sample_size);
- if (ret != sample->sample_size)
- ret = AVERROR(EIO);
- }
+ ret= av_get_packet(pb, pkt, sample->sample_size);
+ if (ret != sample->sample_size)
+ ret = AVERROR(EIO);
pkt->stream_index = sample->stream;
pkt->pts = sample->pts;
diff --git a/libavformat/segment.c b/libavformat/segment.c
index 55ba6569f2..1162ea2122 100644
--- a/libavformat/segment.c
+++ b/libavformat/segment.c
@@ -1,170 +1,502 @@
/*
- * Generic segmenter
* Copyright (c) 2011, Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/**
+ * @file generic segmenter
+ * M3U8 specification can be find here:
+ * @url{http://tools.ietf.org/id/draft-pantos-http-live-streaming}
+ */
+
+/* #define DEBUG */
+
#include <float.h>
+#include <time.h>
#include "avformat.h"
#include "internal.h"
+#include "libavutil/avassert.h"
#include "libavutil/log.h"
#include "libavutil/opt.h"
#include "libavutil/avstring.h"
#include "libavutil/parseutils.h"
#include "libavutil/mathematics.h"
+#include "libavutil/time.h"
+#include "libavutil/time_internal.h"
+#include "libavutil/timestamp.h"
+
+typedef struct SegmentListEntry {
+ int index;
+ double start_time, end_time;
+ int64_t start_pts;
+ int64_t offset_pts;
+ char *filename;
+ struct SegmentListEntry *next;
+ int64_t last_duration;
+} SegmentListEntry;
+
+typedef enum {
+ LIST_TYPE_UNDEFINED = -1,
+ LIST_TYPE_FLAT = 0,
+ LIST_TYPE_CSV,
+ LIST_TYPE_M3U8,
+ LIST_TYPE_EXT, ///< deprecated
+ LIST_TYPE_FFCONCAT,
+ LIST_TYPE_NB,
+} ListType;
+
+#define SEGMENT_LIST_FLAG_CACHE 1
+#define SEGMENT_LIST_FLAG_LIVE 2
typedef struct SegmentContext {
const AVClass *class; /**< Class for private options. */
- int number;
+ int segment_idx; ///< index of the segment file to write, starting from 0
+ int segment_idx_wrap; ///< number after which the index wraps
+ int segment_idx_wrap_nb; ///< number of time the index has wraped
+ int segment_count; ///< number of segment files already written
AVOutputFormat *oformat;
AVFormatContext *avf;
- char *format; /**< Set by a private option. */
- char *list; /**< Set by a private option. */
- char *entry_prefix; /**< Set by a private option. */
- int list_type; /**< Set by a private option. */
- float time; /**< Set by a private option. */
- int size; /**< Set by a private option. */
- int wrap; /**< Set by a private option. */
+ char *format; ///< format to use for output segment files
+ char *format_options_str; ///< format options to use for output segment files
+ AVDictionary *format_options;
+ char *list; ///< filename for the segment list file
+ int list_flags; ///< flags affecting list generation
+ int list_size; ///< number of entries for the segment list file
+
+ int use_clocktime; ///< flag to cut segments at regular clock time
+ int64_t last_val; ///< remember last time for wrap around detection
+ int64_t last_cut; ///< remember last cut
+ int cut_pending;
+
+ char *entry_prefix; ///< prefix to add to list entry filenames
+ int list_type; ///< set the list type
+ AVIOContext *list_pb; ///< list file put-byte context
+ char *time_str; ///< segment duration specification string
+ int64_t time; ///< segment duration
+ int use_strftime; ///< flag to expand filename with strftime
+
+ char *times_str; ///< segment times specification string
+ int64_t *times; ///< list of segment interval specification
+ int nb_times; ///< number of elments in the times array
+
+ char *frames_str; ///< segment frame numbers specification string
+ int *frames; ///< list of frame number specification
+ int nb_frames; ///< number of elments in the frames array
+ int frame_count; ///< total number of reference frames
+ int segment_frame_count; ///< number of reference frames in the segment
+
+ int64_t time_delta;
int individual_header_trailer; /**< Set by a private option. */
int write_header_trailer; /**< Set by a private option. */
- int64_t offset_time;
- int64_t recording_time;
- int has_video;
- AVIOContext *pb;
+ char *header_filename; ///< filename to write the output header to
+
+ int reset_timestamps; ///< reset timestamps at the begin of each segment
+ int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds
+ char *reference_stream_specifier; ///< reference stream specifier
+ int reference_stream_index;
+
+ SegmentListEntry cur_entry;
+ SegmentListEntry *segment_list_entries;
+ SegmentListEntry *segment_list_entries_end;
} SegmentContext;
-enum {
- LIST_FLAT,
- LIST_HLS
-};
+static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
+{
+ int needs_quoting = !!str[strcspn(str, "\",\n\r")];
+
+ if (needs_quoting)
+ avio_w8(ctx, '"');
+
+ for (; *str; str++) {
+ if (*str == '"')
+ avio_w8(ctx, '"');
+ avio_w8(ctx, *str);
+ }
+ if (needs_quoting)
+ avio_w8(ctx, '"');
+}
static int segment_mux_init(AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
AVFormatContext *oc;
int i;
+ int ret;
- seg->avf = oc = avformat_alloc_context();
- if (!oc)
- return AVERROR(ENOMEM);
+ ret = avformat_alloc_output_context2(&seg->avf, seg->oformat, NULL, NULL);
+ if (ret < 0)
+ return ret;
+ oc = seg->avf;
- oc->oformat = seg->oformat;
oc->interrupt_callback = s->interrupt_callback;
+ oc->max_delay = s->max_delay;
+ av_dict_copy(&oc->metadata, s->metadata, 0);
for (i = 0; i < s->nb_streams; i++) {
AVStream *st;
+ AVCodecContext *icodec, *ocodec;
+
if (!(st = avformat_new_stream(oc, NULL)))
return AVERROR(ENOMEM);
- avcodec_copy_context(st->codec, s->streams[i]->codec);
+ icodec = s->streams[i]->codec;
+ ocodec = st->codec;
+ avcodec_copy_context(ocodec, icodec);
+ if (!oc->oformat->codec_tag ||
+ av_codec_get_id (oc->oformat->codec_tag, icodec->codec_tag) == ocodec->codec_id ||
+ av_codec_get_tag(oc->oformat->codec_tag, icodec->codec_id) <= 0) {
+ ocodec->codec_tag = icodec->codec_tag;
+ } else {
+ ocodec->codec_tag = 0;
+ }
st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
st->time_base = s->streams[i]->time_base;
+ av_dict_copy(&st->metadata, s->streams[i]->metadata, 0);
}
return 0;
}
-static int segment_hls_window(AVFormatContext *s, int last)
+static int set_segment_filename(AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
- int i, ret = 0;
- char buf[1024];
-
- if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
- goto fail;
-
- avio_printf(seg->pb, "#EXTM3U\n");
- avio_printf(seg->pb, "#EXT-X-VERSION:3\n");
- avio_printf(seg->pb, "#EXT-X-TARGETDURATION:%d\n", (int)seg->time);
- avio_printf(seg->pb, "#EXT-X-MEDIA-SEQUENCE:%d\n",
- FFMAX(0, seg->number - seg->size));
-
- av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%d\n",
- FFMAX(0, seg->number - seg->size));
-
- for (i = FFMAX(0, seg->number - seg->size);
- i < seg->number; i++) {
- avio_printf(seg->pb, "#EXTINF:%d,\n", (int)seg->time);
- if (seg->entry_prefix) {
- avio_printf(seg->pb, "%s", seg->entry_prefix);
- }
- ret = av_get_frame_filename(buf, sizeof(buf), s->filename, i);
- if (ret < 0) {
- ret = AVERROR(EINVAL);
- goto fail;
+ AVFormatContext *oc = seg->avf;
+ size_t size;
+
+ if (seg->segment_idx_wrap)
+ seg->segment_idx %= seg->segment_idx_wrap;
+ if (seg->use_strftime) {
+ time_t now0;
+ struct tm *tm, tmpbuf;
+ time(&now0);
+ tm = localtime_r(&now0, &tmpbuf);
+ if (!strftime(oc->filename, sizeof(oc->filename), s->filename, tm)) {
+ av_log(oc, AV_LOG_ERROR, "Could not get segment filename with strftime\n");
+ return AVERROR(EINVAL);
}
- avio_printf(seg->pb, "%s\n", buf);
+ } else if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
+ s->filename, seg->segment_idx) < 0) {
+ av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename);
+ return AVERROR(EINVAL);
}
- if (last)
- avio_printf(seg->pb, "#EXT-X-ENDLIST\n");
-fail:
- avio_closep(&seg->pb);
- return ret;
+ /* copy modified name in list entry */
+ size = strlen(av_basename(oc->filename)) + 1;
+ if (seg->entry_prefix)
+ size += strlen(seg->entry_prefix);
+
+ seg->cur_entry.filename = av_mallocz(size);
+ if (!seg->cur_entry.filename)
+ return AVERROR(ENOMEM);
+ snprintf(seg->cur_entry.filename, size, "%s%s",
+ seg->entry_prefix ? seg->entry_prefix : "",
+ av_basename(oc->filename));
+
+ return 0;
}
static int segment_start(AVFormatContext *s, int write_header)
{
- SegmentContext *c = s->priv_data;
- AVFormatContext *oc = c->avf;
+ SegmentContext *seg = s->priv_data;
+ AVFormatContext *oc = seg->avf;
int err = 0;
if (write_header) {
avformat_free_context(oc);
- c->avf = NULL;
+ seg->avf = NULL;
if ((err = segment_mux_init(s)) < 0)
return err;
- oc = c->avf;
+ oc = seg->avf;
}
- if (c->wrap)
- c->number %= c->wrap;
+ seg->segment_idx++;
+ if ((seg->segment_idx_wrap) && (seg->segment_idx % seg->segment_idx_wrap == 0))
+ seg->segment_idx_wrap_nb++;
- if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- s->filename, c->number++) < 0)
- return AVERROR(EINVAL);
+ if ((err = set_segment_filename(s)) < 0)
+ return err;
if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
+ &s->interrupt_callback, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
return err;
+ }
+ if (!seg->individual_header_trailer)
+ oc->pb->seekable = 0;
if (oc->oformat->priv_class && oc->priv_data)
- av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */
+ av_opt_set(oc->priv_data, "mpegts_flags", "+resend_headers", 0);
if (write_header) {
if ((err = avformat_write_header(oc, NULL)) < 0)
return err;
}
+ seg->segment_frame_count = 0;
return 0;
}
-static int segment_end(AVFormatContext *oc, int write_trailer)
+static int segment_list_open(AVFormatContext *s)
+{
+ SegmentContext *seg = s->priv_data;
+ int ret;
+
+ ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
+ &s->interrupt_callback, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment list '%s'\n", seg->list);
+ return ret;
+ }
+
+ if (seg->list_type == LIST_TYPE_M3U8 && seg->segment_list_entries) {
+ SegmentListEntry *entry;
+ double max_duration = 0;
+
+ avio_printf(seg->list_pb, "#EXTM3U\n");
+ avio_printf(seg->list_pb, "#EXT-X-VERSION:3\n");
+ avio_printf(seg->list_pb, "#EXT-X-MEDIA-SEQUENCE:%d\n", seg->segment_list_entries->index);
+ avio_printf(seg->list_pb, "#EXT-X-ALLOW-CACHE:%s\n",
+ seg->list_flags & SEGMENT_LIST_FLAG_CACHE ? "YES" : "NO");
+
+ av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%d\n",
+ seg->segment_list_entries->index);
+
+ for (entry = seg->segment_list_entries; entry; entry = entry->next)
+ max_duration = FFMAX(max_duration, entry->end_time - entry->start_time);
+ avio_printf(seg->list_pb, "#EXT-X-TARGETDURATION:%"PRId64"\n", (int64_t)ceil(max_duration));
+ } else if (seg->list_type == LIST_TYPE_FFCONCAT) {
+ avio_printf(seg->list_pb, "ffconcat version 1.0\n");
+ }
+
+ return ret;
+}
+
+static void segment_list_print_entry(AVIOContext *list_ioctx,
+ ListType list_type,
+ const SegmentListEntry *list_entry,
+ void *log_ctx)
+{
+ switch (list_type) {
+ case LIST_TYPE_FLAT:
+ avio_printf(list_ioctx, "%s\n", list_entry->filename);
+ break;
+ case LIST_TYPE_CSV:
+ case LIST_TYPE_EXT:
+ print_csv_escaped_str(list_ioctx, list_entry->filename);
+ avio_printf(list_ioctx, ",%f,%f\n", list_entry->start_time, list_entry->end_time);
+ break;
+ case LIST_TYPE_M3U8:
+ avio_printf(list_ioctx, "#EXTINF:%f,\n%s\n",
+ list_entry->end_time - list_entry->start_time, list_entry->filename);
+ break;
+ case LIST_TYPE_FFCONCAT:
+ {
+ char *buf;
+ if (av_escape(&buf, list_entry->filename, NULL, AV_ESCAPE_MODE_AUTO, AV_ESCAPE_FLAG_WHITESPACE) < 0) {
+ av_log(log_ctx, AV_LOG_WARNING,
+ "Error writing list entry '%s' in list file\n", list_entry->filename);
+ return;
+ }
+ avio_printf(list_ioctx, "file %s\n", buf);
+ av_free(buf);
+ break;
+ }
+ default:
+ av_assert0(!"Invalid list type");
+ }
+}
+
+static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
{
+ SegmentContext *seg = s->priv_data;
+ AVFormatContext *oc = seg->avf;
int ret = 0;
av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */
if (write_trailer)
- av_write_trailer(oc);
- avio_close(oc->pb);
+ ret = av_write_trailer(oc);
+
+ if (ret < 0)
+ av_log(s, AV_LOG_ERROR, "Failure occurred when ending segment '%s'\n",
+ oc->filename);
+
+ if (seg->list) {
+ if (seg->list_size || seg->list_type == LIST_TYPE_M3U8) {
+ SegmentListEntry *entry = av_mallocz(sizeof(*entry));
+ if (!entry) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ /* append new element */
+ memcpy(entry, &seg->cur_entry, sizeof(*entry));
+ if (!seg->segment_list_entries)
+ seg->segment_list_entries = seg->segment_list_entries_end = entry;
+ else
+ seg->segment_list_entries_end->next = entry;
+ seg->segment_list_entries_end = entry;
+
+ /* drop first item */
+ if (seg->list_size && seg->segment_count >= seg->list_size) {
+ entry = seg->segment_list_entries;
+ seg->segment_list_entries = seg->segment_list_entries->next;
+ av_freep(&entry->filename);
+ av_freep(&entry);
+ }
+
+ if ((ret = segment_list_open(s)) < 0)
+ goto end;
+ for (entry = seg->segment_list_entries; entry; entry = entry->next)
+ segment_list_print_entry(seg->list_pb, seg->list_type, entry, s);
+ if (seg->list_type == LIST_TYPE_M3U8 && is_last)
+ avio_printf(seg->list_pb, "#EXT-X-ENDLIST\n");
+ avio_closep(&seg->list_pb);
+ } else {
+ segment_list_print_entry(seg->list_pb, seg->list_type, &seg->cur_entry, s);
+ avio_flush(seg->list_pb);
+ }
+ }
+
+ av_log(s, AV_LOG_VERBOSE, "segment:'%s' count:%d ended\n",
+ seg->avf->filename, seg->segment_count);
+ seg->segment_count++;
+
+end:
+ avio_closep(&oc->pb);
+
+ return ret;
+}
+
+static int parse_times(void *log_ctx, int64_t **times, int *nb_times,
+ const char *times_str)
+{
+ char *p;
+ int i, ret = 0;
+ char *times_str1 = av_strdup(times_str);
+ char *saveptr = NULL;
+
+ if (!times_str1)
+ return AVERROR(ENOMEM);
+
+#define FAIL(err) ret = err; goto end
+
+ *nb_times = 1;
+ for (p = times_str1; *p; p++)
+ if (*p == ',')
+ (*nb_times)++;
+
+ *times = av_malloc_array(*nb_times, sizeof(**times));
+ if (!*times) {
+ av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced times array\n");
+ FAIL(AVERROR(ENOMEM));
+ }
+
+ p = times_str1;
+ for (i = 0; i < *nb_times; i++) {
+ int64_t t;
+ char *tstr = av_strtok(p, ",", &saveptr);
+ p = NULL;
+
+ if (!tstr || !tstr[0]) {
+ av_log(log_ctx, AV_LOG_ERROR, "Empty time specification in times list %s\n",
+ times_str);
+ FAIL(AVERROR(EINVAL));
+ }
+
+ ret = av_parse_time(&t, tstr, 1);
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid time duration specification '%s' in times list %s\n", tstr, times_str);
+ FAIL(AVERROR(EINVAL));
+ }
+ (*times)[i] = t;
+
+ /* check on monotonicity */
+ if (i && (*times)[i-1] > (*times)[i]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Specified time %f is greater than the following time %f\n",
+ (float)((*times)[i])/1000000, (float)((*times)[i-1])/1000000);
+ FAIL(AVERROR(EINVAL));
+ }
+ }
+
+end:
+ av_free(times_str1);
+ return ret;
+}
+
+static int parse_frames(void *log_ctx, int **frames, int *nb_frames,
+ const char *frames_str)
+{
+ char *p;
+ int i, ret = 0;
+ char *frames_str1 = av_strdup(frames_str);
+ char *saveptr = NULL;
+
+ if (!frames_str1)
+ return AVERROR(ENOMEM);
+
+#define FAIL(err) ret = err; goto end
+
+ *nb_frames = 1;
+ for (p = frames_str1; *p; p++)
+ if (*p == ',')
+ (*nb_frames)++;
+ *frames = av_malloc_array(*nb_frames, sizeof(**frames));
+ if (!*frames) {
+ av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced frames array\n");
+ FAIL(AVERROR(ENOMEM));
+ }
+
+ p = frames_str1;
+ for (i = 0; i < *nb_frames; i++) {
+ long int f;
+ char *tailptr;
+ char *fstr = av_strtok(p, ",", &saveptr);
+
+ p = NULL;
+ if (!fstr) {
+ av_log(log_ctx, AV_LOG_ERROR, "Empty frame specification in frame list %s\n",
+ frames_str);
+ FAIL(AVERROR(EINVAL));
+ }
+ f = strtol(fstr, &tailptr, 10);
+ if (*tailptr || f <= 0 || f >= INT_MAX) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Invalid argument '%s', must be a positive integer <= INT64_MAX\n",
+ fstr);
+ FAIL(AVERROR(EINVAL));
+ }
+ (*frames)[i] = f;
+
+ /* check on monotonicity */
+ if (i && (*frames)[i-1] > (*frames)[i]) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Specified frame %d is greater than the following frame %d\n",
+ (*frames)[i], (*frames)[i-1]);
+ FAIL(AVERROR(EINVAL));
+ }
+ }
+
+end:
+ av_free(frames_str1);
return ret;
}
@@ -182,15 +514,72 @@ static int open_null_ctx(AVIOContext **ctx)
return 0;
}
-static void close_null_ctx(AVIOContext *pb)
+static void close_null_ctxp(AVIOContext **pb)
{
- av_free(pb->buffer);
- av_free(pb);
+ av_freep(&(*pb)->buffer);
+ av_freep(pb);
+}
+
+static int select_reference_stream(AVFormatContext *s)
+{
+ SegmentContext *seg = s->priv_data;
+ int ret, i;
+
+ seg->reference_stream_index = -1;
+ if (!strcmp(seg->reference_stream_specifier, "auto")) {
+ /* select first index of type with highest priority */
+ int type_index_map[AVMEDIA_TYPE_NB];
+ static const enum AVMediaType type_priority_list[] = {
+ AVMEDIA_TYPE_VIDEO,
+ AVMEDIA_TYPE_AUDIO,
+ AVMEDIA_TYPE_SUBTITLE,
+ AVMEDIA_TYPE_DATA,
+ AVMEDIA_TYPE_ATTACHMENT
+ };
+ enum AVMediaType type;
+
+ for (i = 0; i < AVMEDIA_TYPE_NB; i++)
+ type_index_map[i] = -1;
+
+ /* select first index for each type */
+ for (i = 0; i < s->nb_streams; i++) {
+ type = s->streams[i]->codec->codec_type;
+ if ((unsigned)type < AVMEDIA_TYPE_NB && type_index_map[type] == -1
+ /* ignore attached pictures/cover art streams */
+ && !(s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ type_index_map[type] = i;
+ }
+
+ for (i = 0; i < FF_ARRAY_ELEMS(type_priority_list); i++) {
+ type = type_priority_list[i];
+ if ((seg->reference_stream_index = type_index_map[type]) >= 0)
+ break;
+ }
+ } else {
+ for (i = 0; i < s->nb_streams; i++) {
+ ret = avformat_match_stream_specifier(s, s->streams[i],
+ seg->reference_stream_specifier);
+ if (ret < 0)
+ return ret;
+ if (ret > 0) {
+ seg->reference_stream_index = i;
+ break;
+ }
+ }
+ }
+
+ if (seg->reference_stream_index < 0) {
+ av_log(s, AV_LOG_ERROR, "Could not select stream matching identifier '%s'\n",
+ seg->reference_stream_specifier);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
}
static void seg_free_context(SegmentContext *seg)
{
- avio_closep(&seg->pb);
+ avio_closep(&seg->list_pb);
avformat_free_context(seg->avf);
seg->avf = NULL;
}
@@ -199,27 +588,73 @@ static int seg_write_header(AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
AVFormatContext *oc = NULL;
- int ret, i;
+ AVDictionary *options = NULL;
+ int ret;
+ int i;
- seg->number = 0;
- seg->offset_time = 0;
- seg->recording_time = seg->time * 1000000;
+ seg->segment_count = 0;
if (!seg->write_header_trailer)
seg->individual_header_trailer = 0;
- if (seg->list && seg->list_type != LIST_HLS)
- if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
+ if (seg->header_filename) {
+ seg->write_header_trailer = 1;
+ seg->individual_header_trailer = 0;
+ }
+
+ if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) {
+ av_log(s, AV_LOG_ERROR,
+ "segment_time, segment_times, and segment_frames options "
+ "are mutually exclusive, select just one of them\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (seg->times_str) {
+ if ((ret = parse_times(s, &seg->times, &seg->nb_times, seg->times_str)) < 0)
+ return ret;
+ } else if (seg->frames_str) {
+ if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_str)) < 0)
+ return ret;
+ } else {
+ /* set default value if not specified */
+ if (!seg->time_str)
+ seg->time_str = av_strdup("2");
+ if ((ret = av_parse_time(&seg->time, seg->time_str, 1)) < 0) {
+ av_log(s, AV_LOG_ERROR,
+ "Invalid time duration specification '%s' for segment_time option\n",
+ seg->time_str);
+ return ret;
+ }
+ }
+
+ if (seg->format_options_str) {
+ ret = av_dict_parse_string(&seg->format_options, seg->format_options_str, "=", ":", 0);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n",
+ seg->format_options_str);
goto fail;
+ }
+ }
- for (i = 0; i < s->nb_streams; i++)
- seg->has_video +=
- (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO);
+ if (seg->list) {
+ if (seg->list_type == LIST_TYPE_UNDEFINED) {
+ if (av_match_ext(seg->list, "csv" )) seg->list_type = LIST_TYPE_CSV;
+ else if (av_match_ext(seg->list, "ext" )) seg->list_type = LIST_TYPE_EXT;
+ else if (av_match_ext(seg->list, "m3u8")) seg->list_type = LIST_TYPE_M3U8;
+ else if (av_match_ext(seg->list, "ffcat,ffconcat")) seg->list_type = LIST_TYPE_FFCONCAT;
+ else seg->list_type = LIST_TYPE_FLAT;
+ }
+ if (!seg->list_size && seg->list_type != LIST_TYPE_M3U8)
+ if ((ret = segment_list_open(s)) < 0)
+ goto fail;
+ }
+ if (seg->list_type == LIST_TYPE_EXT)
+ av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n");
- if (seg->has_video > 1)
- av_log(s, AV_LOG_WARNING,
- "More than a single video stream present, "
- "expect issues decoding it.\n");
+ if ((ret = select_reference_stream(s)) < 0)
+ goto fail;
+ av_log(s, AV_LOG_VERBOSE, "Selected stream id:%d type:%s\n",
+ seg->reference_stream_index,
+ av_get_media_type_string(s->streams[seg->reference_stream_index]->codec->codec_type));
seg->oformat = av_guess_format(seg->format, s->filename, NULL);
@@ -238,44 +673,63 @@ static int seg_write_header(AVFormatContext *s)
goto fail;
oc = seg->avf;
- if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
- s->filename, seg->number++) < 0) {
- ret = AVERROR(EINVAL);
+ if ((ret = set_segment_filename(s)) < 0)
goto fail;
- }
if (seg->write_header_trailer) {
- if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
+ if ((ret = avio_open2(&oc->pb, seg->header_filename ? seg->header_filename : oc->filename, AVIO_FLAG_WRITE,
+ &s->interrupt_callback, NULL)) < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
goto fail;
+ }
+ if (!seg->individual_header_trailer)
+ oc->pb->seekable = 0;
} else {
if ((ret = open_null_ctx(&oc->pb)) < 0)
goto fail;
}
- if ((ret = avformat_write_header(oc, NULL)) < 0) {
- avio_close(oc->pb);
+ av_dict_copy(&options, seg->format_options, 0);
+ ret = avformat_write_header(oc, &options);
+ if (av_dict_count(options)) {
+ av_log(s, AV_LOG_ERROR,
+ "Some of the provided format options in '%s' are not recognized\n", seg->format_options_str);
+ ret = AVERROR(EINVAL);
goto fail;
}
- if (!seg->write_header_trailer) {
- close_null_ctx(oc->pb);
- if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
- goto fail;
+ if (ret < 0) {
+ avio_closep(&oc->pb);
+ goto fail;
}
+ seg->segment_frame_count = 0;
- if (seg->list) {
- if (seg->list_type == LIST_HLS) {
- if ((ret = segment_hls_window(s, 0)) < 0)
- goto fail;
+ av_assert0(s->nb_streams == oc->nb_streams);
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *inner_st = oc->streams[i];
+ AVStream *outer_st = s->streams[i];
+ avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den);
+ }
+
+ if (oc->avoid_negative_ts > 0 && s->avoid_negative_ts < 0)
+ s->avoid_negative_ts = 1;
+
+ if (!seg->write_header_trailer || seg->header_filename) {
+ if (seg->header_filename) {
+ av_write_frame(oc, NULL);
+ avio_closep(&oc->pb);
} else {
- avio_printf(seg->pb, "%s\n", oc->filename);
- avio_flush(seg->pb);
+ close_null_ctxp(&oc->pb);
}
+ if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
+ &s->interrupt_callback, NULL)) < 0)
+ goto fail;
+ if (!seg->individual_header_trailer)
+ oc->pb->seekable = 0;
}
fail:
+ av_dict_free(&options);
if (ret < 0)
seg_free_context(seg);
@@ -285,54 +739,107 @@ fail:
static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
{
SegmentContext *seg = s->priv_data;
- AVFormatContext *oc = seg->avf;
AVStream *st = s->streams[pkt->stream_index];
- int64_t end_pts = seg->recording_time * seg->number;
- int ret, can_split = 1;
-
- if (!oc)
+ int64_t end_pts = INT64_MAX, offset;
+ int start_frame = INT_MAX;
+ int ret;
+ struct tm ti;
+ int64_t usecs;
+ int64_t wrapped_val;
+
+ if (!seg->avf)
return AVERROR(EINVAL);
- if (seg->has_video) {
- can_split = st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
- pkt->flags & AV_PKT_FLAG_KEY;
+ if (seg->times) {
+ end_pts = seg->segment_count < seg->nb_times ?
+ seg->times[seg->segment_count] : INT64_MAX;
+ } else if (seg->frames) {
+ start_frame = seg->segment_count < seg->nb_frames ?
+ seg->frames[seg->segment_count] : INT_MAX;
+ } else {
+ if (seg->use_clocktime) {
+ int64_t avgt = av_gettime();
+ time_t sec = avgt / 1000000;
+ localtime_r(&sec, &ti);
+ usecs = (int64_t)(ti.tm_hour * 3600 + ti.tm_min * 60 + ti.tm_sec) * 1000000 + (avgt % 1000000);
+ wrapped_val = usecs % seg->time;
+ if (seg->last_cut != usecs && wrapped_val < seg->last_val) {
+ seg->cut_pending = 1;
+ seg->last_cut = usecs;
+ }
+ seg->last_val = wrapped_val;
+ } else {
+ end_pts = seg->time * (seg->segment_count + 1);
+ }
}
- if (can_split && av_compare_ts(pkt->pts, st->time_base, end_pts,
- AV_TIME_BASE_Q) >= 0) {
- av_log(s, AV_LOG_DEBUG, "Next segment starts at %d %"PRId64"\n",
- pkt->stream_index, pkt->pts);
-
- ret = segment_end(oc, seg->individual_header_trailer);
-
- if (!ret)
- ret = segment_start(s, seg->individual_header_trailer);
+ av_dlog(s, "packet stream:%d pts:%s pts_time:%s duration_time:%s is_key:%d frame:%d\n",
+ pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2timestr(pkt->duration, &st->time_base),
+ pkt->flags & AV_PKT_FLAG_KEY,
+ pkt->stream_index == seg->reference_stream_index ? seg->frame_count : -1);
+
+ if (pkt->stream_index == seg->reference_stream_index &&
+ pkt->flags & AV_PKT_FLAG_KEY &&
+ seg->segment_frame_count > 0 &&
+ (seg->cut_pending || seg->frame_count >= start_frame ||
+ (pkt->pts != AV_NOPTS_VALUE &&
+ av_compare_ts(pkt->pts, st->time_base,
+ end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
+ /* sanitize end time in case last packet didn't have a defined duration */
+ if (seg->cur_entry.last_duration == 0)
+ seg->cur_entry.end_time = (double)pkt->pts * av_q2d(st->time_base);
+
+ if ((ret = segment_end(s, seg->individual_header_trailer, 0)) < 0)
+ goto fail;
- if (ret)
+ if ((ret = segment_start(s, seg->individual_header_trailer)) < 0)
goto fail;
- oc = seg->avf;
+ seg->cut_pending = 0;
+ seg->cur_entry.index = seg->segment_idx + seg->segment_idx_wrap * seg->segment_idx_wrap_nb;
+ seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base);
+ seg->cur_entry.start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);
+ seg->cur_entry.end_time = seg->cur_entry.start_time +
+ pkt->pts != AV_NOPTS_VALUE ? (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base) : 0;
+ } else if (pkt->pts != AV_NOPTS_VALUE && pkt->stream_index == seg->reference_stream_index) {
+ seg->cur_entry.end_time =
+ FFMAX(seg->cur_entry.end_time, (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
+ seg->cur_entry.last_duration = pkt->duration;
+ }
- if (seg->list) {
- if (seg->list_type == LIST_HLS) {
- if ((ret = segment_hls_window(s, 0)) < 0)
- goto fail;
- } else {
- avio_printf(seg->pb, "%s\n", oc->filename);
- avio_flush(seg->pb);
- if (seg->size && !(seg->number % seg->size)) {
- avio_closep(&seg->pb);
- if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
- &s->interrupt_callback, NULL)) < 0)
- goto fail;
- }
- }
- }
+ if (seg->segment_frame_count == 0) {
+ av_log(s, AV_LOG_VERBOSE, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n",
+ seg->avf->filename, pkt->stream_index,
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count);
}
- ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
+ av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s",
+ pkt->stream_index,
+ av_ts2timestr(seg->cur_entry.start_pts, &AV_TIME_BASE_Q),
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
+
+ /* compute new timestamps */
+ offset = av_rescale_q(seg->initial_offset - (seg->reset_timestamps ? seg->cur_entry.start_pts : 0),
+ AV_TIME_BASE_Q, st->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE)
+ pkt->pts += offset;
+ if (pkt->dts != AV_NOPTS_VALUE)
+ pkt->dts += offset;
+
+ av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
+ av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
+ av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
+
+ ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s, seg->initial_offset || seg->reset_timestamps);
fail:
+ if (pkt->stream_index == seg->reference_stream_index) {
+ seg->frame_count++;
+ seg->segment_frame_count++;
+ }
+
if (ret < 0)
seg_free_context(seg);
@@ -343,49 +850,81 @@ static int seg_write_trailer(struct AVFormatContext *s)
{
SegmentContext *seg = s->priv_data;
AVFormatContext *oc = seg->avf;
+ SegmentListEntry *cur, *next;
int ret = 0;
if (!oc)
goto fail;
if (!seg->write_header_trailer) {
- if ((ret = segment_end(oc, 0)) < 0)
+ if ((ret = segment_end(s, 0, 1)) < 0)
goto fail;
open_null_ctx(&oc->pb);
ret = av_write_trailer(oc);
- close_null_ctx(oc->pb);
+ close_null_ctxp(&oc->pb);
} else {
- ret = segment_end(oc, 1);
+ ret = segment_end(s, 1, 1);
}
-
- if (ret < 0)
- goto fail;
-
- if (seg->list && seg->list_type == LIST_HLS) {
- if ((ret = segment_hls_window(s, 1) < 0))
- goto fail;
+fail:
+ if (seg->list)
+ avio_closep(&seg->list_pb);
+
+ av_dict_free(&seg->format_options);
+ av_opt_free(seg);
+ av_freep(&seg->times);
+ av_freep(&seg->frames);
+
+ cur = seg->segment_list_entries;
+ while (cur) {
+ next = cur->next;
+ av_freep(&cur->filename);
+ av_free(cur);
+ cur = next;
}
-fail:
- avio_close(seg->pb);
avformat_free_context(oc);
+ seg->avf = NULL;
return ret;
}
#define OFFSET(x) offsetof(SegmentContext, x)
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "segment_format", "container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
- { "segment_time", "segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E },
- { "segment_list", "output the segment list", OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
- { "segment_list_size", "maximum number of playlist entries", OFFSET(size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E },
- { "segment_list_type", "segment list format", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_FLAT}, 0, 2, E, "list_type" },
- { "flat", "plain list (default)", 0, AV_OPT_TYPE_CONST, {.i64 = LIST_FLAT}, 0, 0, E, "list_type" },
- { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64 = LIST_HLS}, 0, 0, E, "list_type" },
- { "segment_wrap", "number after which the index wraps", OFFSET(wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
- { "segment_list_entry_prefix", "base url prefix for segments", OFFSET(entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "reference_stream", "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, CHAR_MIN, CHAR_MAX, E },
+ { "segment_format", "set container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "segment_format_options", "set list of options for the container format used for the segments", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "segment_list", "set the segment list filename", OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "segment_header_filename", "write a single file containing the header", OFFSET(header_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+
+ { "segment_list_flags","set flags affecting segment list generation", OFFSET(list_flags), AV_OPT_TYPE_FLAGS, {.i64 = SEGMENT_LIST_FLAG_CACHE }, 0, UINT_MAX, E, "list_flags"},
+ { "cache", "allow list caching", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_CACHE }, INT_MIN, INT_MAX, E, "list_flags"},
+ { "live", "enable live-friendly list generation (useful for HLS)", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_LIVE }, INT_MIN, INT_MAX, E, "list_flags"},
+
+ { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+
+ { "segment_list_type", "set the segment list type", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_TYPE_UNDEFINED}, -1, LIST_TYPE_NB-1, E, "list_type" },
+ { "flat", "flat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, E, "list_type" },
+ { "csv", "csv format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_CSV }, INT_MIN, INT_MAX, E, "list_type" },
+ { "ext", "extended format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_EXT }, INT_MIN, INT_MAX, E, "list_type" },
+ { "ffconcat", "ffconcat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FFCONCAT }, INT_MIN, INT_MAX, E, "list_type" },
+ { "m3u8", "M3U8 format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
+ { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
+
+ { "segment_atclocktime", "set segment to be cut at clocktime", OFFSET(use_clocktime), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E},
+ { "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E },
+ { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
+ { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
+ { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "segment_list_entry_prefix", "set base url prefix for segments", OFFSET(entry_prefix), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+ { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "segment_wrap_number", "set the number of wrap before the first segment", OFFSET(segment_idx_wrap_nb), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
+ { "strftime", "set filename expansion with strftime at segment creation", OFFSET(use_strftime), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, E },
+
{ "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
{ "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
+ { "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
+ { "initial_offset", "set initial timestamp offset", OFFSET(initial_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, -INT64_MAX, INT64_MAX, E },
{ NULL },
};
@@ -396,14 +935,31 @@ static const AVClass seg_class = {
.version = LIBAVUTIL_VERSION_INT,
};
-
AVOutputFormat ff_segment_muxer = {
.name = "segment",
.long_name = NULL_IF_CONFIG_SMALL("segment"),
.priv_data_size = sizeof(SegmentContext),
- .flags = AVFMT_NOFILE,
+ .flags = AVFMT_NOFILE|AVFMT_GLOBALHEADER,
.write_header = seg_write_header,
.write_packet = seg_write_packet,
.write_trailer = seg_write_trailer,
.priv_class = &seg_class,
};
+
+static const AVClass sseg_class = {
+ .class_name = "stream_segment muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_stream_segment_muxer = {
+ .name = "stream_segment,ssegment",
+ .long_name = NULL_IF_CONFIG_SMALL("streaming segment muxer"),
+ .priv_data_size = sizeof(SegmentContext),
+ .flags = AVFMT_NOFILE,
+ .write_header = seg_write_header,
+ .write_packet = seg_write_packet,
+ .write_trailer = seg_write_trailer,
+ .priv_class = &sseg_class,
+};
diff --git a/libavformat/sierravmd.c b/libavformat/sierravmd.c
index 279633fe99..1ededc7145 100644
--- a/libavformat/sierravmd.c
+++ b/libavformat/sierravmd.c
@@ -1,21 +1,21 @@
/*
* Sierra VMD Format Demuxer
- * Copyright (c) 2004 The ffmpeg Project
+ * Copyright (c) 2004 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,7 @@
#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
+#include "avio_internal.h"
#define VMD_HEADER_SIZE 0x0330
#define BYTES_PER_FRAME_RECORD 16
@@ -63,8 +64,8 @@ typedef struct VmdDemuxContext {
static int vmd_probe(AVProbeData *p)
{
- int w, h;
- if (p->buf_size < 16)
+ int w, h, sample_rate;
+ if (p->buf_size < 806)
return 0;
/* check if the first 2 bytes of the file contain the appropriate size
* of a VMD header chunk */
@@ -72,7 +73,9 @@ static int vmd_probe(AVProbeData *p)
return 0;
w = AV_RL16(&p->buf[12]);
h = AV_RL16(&p->buf[14]);
- if (!w || w > 2048 || !h || h > 2048)
+ sample_rate = AV_RL16(&p->buf[804]);
+ if ((!w || w > 2048 || !h || h > 2048) &&
+ sample_rate != 22050)
return 0;
/* only return half certainty since this check is a bit sketchy */
@@ -83,12 +86,13 @@ static int vmd_read_header(AVFormatContext *s)
{
VmdDemuxContext *vmd = s->priv_data;
AVIOContext *pb = s->pb;
- AVStream *st = NULL, *vst;
+ AVStream *st = NULL, *vst = NULL;
unsigned int toc_offset;
unsigned char *raw_frame_table;
int raw_frame_table_size;
int64_t current_offset;
int i, j, ret;
+ int width, height;
unsigned int total_frames;
int64_t current_audio_pts = 0;
unsigned char chunk[BYTES_PER_FRAME_RECORD];
@@ -100,28 +104,33 @@ static int vmd_read_header(AVFormatContext *s)
if (avio_read(pb, vmd->vmd_header, VMD_HEADER_SIZE) != VMD_HEADER_SIZE)
return AVERROR(EIO);
- if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3')
- vmd->is_indeo3 = 1;
- else
- vmd->is_indeo3 = 0;
- /* start up the decoders */
- vst = avformat_new_stream(s, NULL);
- if (!vst)
- return AVERROR(ENOMEM);
- avpriv_set_pts_info(vst, 33, 1, 10);
- vmd->video_stream_index = vst->index;
- vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
- vst->codec->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO;
- vst->codec->codec_tag = 0; /* no fourcc */
- vst->codec->width = AV_RL16(&vmd->vmd_header[12]);
- vst->codec->height = AV_RL16(&vmd->vmd_header[14]);
- if(vmd->is_indeo3 && vst->codec->width > 320){
- vst->codec->width >>= 1;
- vst->codec->height >>= 1;
+ width = AV_RL16(&vmd->vmd_header[12]);
+ height = AV_RL16(&vmd->vmd_header[14]);
+ if (width && height) {
+ if(vmd->vmd_header[24] == 'i' && vmd->vmd_header[25] == 'v' && vmd->vmd_header[26] == '3') {
+ vmd->is_indeo3 = 1;
+ } else {
+ vmd->is_indeo3 = 0;
+ }
+ /* start up the decoders */
+ vst = avformat_new_stream(s, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(vst, 33, 1, 10);
+ vmd->video_stream_index = vst->index;
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = vmd->is_indeo3 ? AV_CODEC_ID_INDEO3 : AV_CODEC_ID_VMDVIDEO;
+ vst->codec->codec_tag = 0; /* no fourcc */
+ vst->codec->width = width;
+ vst->codec->height = height;
+ if(vmd->is_indeo3 && vst->codec->width > 320){
+ vst->codec->width >>= 1;
+ vst->codec->height >>= 1;
+ }
+ if (ff_alloc_extradata(vst->codec, VMD_HEADER_SIZE))
+ return AVERROR(ENOMEM);
+ memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE);
}
- vst->codec->extradata_size = VMD_HEADER_SIZE;
- vst->codec->extradata = av_mallocz(VMD_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
- memcpy(vst->codec->extradata, vmd->vmd_header, VMD_HEADER_SIZE);
/* if sample rate is 0, assume no audio */
vmd->sample_rate = AV_RL16(&vmd->vmd_header[804]);
@@ -154,8 +163,9 @@ static int vmd_read_header(AVFormatContext *s)
/* calculate pts */
num = st->codec->block_align;
den = st->codec->sample_rate * st->codec->channels;
- av_reduce(&den, &num, den, num, (1UL<<31)-1);
- avpriv_set_pts_info(vst, 33, num, den);
+ av_reduce(&num, &den, num, den, (1UL<<31)-1);
+ if (vst)
+ avpriv_set_pts_info(vst, 33, num, den);
avpriv_set_pts_info(st, 33, num, den);
}
@@ -173,7 +183,7 @@ static int vmd_read_header(AVFormatContext *s)
return -1;
}
raw_frame_table = av_malloc(raw_frame_table_size);
- vmd->frame_table = av_malloc((vmd->frame_count * vmd->frames_per_block + sound_buffers) * sizeof(vmd_frame));
+ vmd->frame_table = av_malloc_array(vmd->frame_count * vmd->frames_per_block + sound_buffers, sizeof(vmd_frame));
if (!raw_frame_table || !vmd->frame_table) {
ret = AVERROR(ENOMEM);
goto error;
@@ -194,7 +204,12 @@ static int vmd_read_header(AVFormatContext *s)
int type;
uint32_t size;
- avio_read(pb, chunk, BYTES_PER_FRAME_RECORD);
+ if ((ret = avio_read(pb, chunk, BYTES_PER_FRAME_RECORD)) != BYTES_PER_FRAME_RECORD) {
+ av_log(s, AV_LOG_ERROR, "Failed to read frame record\n");
+ if (ret >= 0)
+ ret = AVERROR_INVALIDDATA;
+ goto error;
+ }
type = chunk[0];
size = AV_RL32(&chunk[2]);
if (size > INT_MAX / 2) {
@@ -240,8 +255,8 @@ static int vmd_read_header(AVFormatContext *s)
return 0;
error:
- av_free(raw_frame_table);
- av_free(vmd->frame_table);
+ av_freep(&raw_frame_table);
+ av_freep(&vmd->frame_table);
return ret;
}
@@ -254,12 +269,14 @@ static int vmd_read_packet(AVFormatContext *s,
vmd_frame *frame;
if (vmd->current_frame >= vmd->frame_count)
- return AVERROR(EIO);
+ return AVERROR_EOF;
frame = &vmd->frame_table[vmd->current_frame];
/* position the stream (will probably be there already) */
avio_seek(pb, frame->frame_offset, SEEK_SET);
+ if(ffio_limit(pb, frame->frame_size) != frame->frame_size)
+ return AVERROR(EIO);
if (av_new_packet(pkt, frame->frame_size + BYTES_PER_FRAME_RECORD))
return AVERROR(ENOMEM);
pkt->pos= avio_tell(pb);
@@ -290,7 +307,7 @@ static int vmd_read_close(AVFormatContext *s)
{
VmdDemuxContext *vmd = s->priv_data;
- av_free(vmd->frame_table);
+ av_freep(&vmd->frame_table);
return 0;
}
diff --git a/libavformat/siff.c b/libavformat/siff.c
index d97c8b018c..b6ea390598 100644
--- a/libavformat/siff.c
+++ b/libavformat/siff.c
@@ -2,20 +2,20 @@
* Beam Software SIFF demuxer
* Copyright (c) 2007 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include "avformat.h"
#include "internal.h"
+#include "avio_internal.h"
enum SIFFTags {
TAG_SIFF = MKTAG('S', 'I', 'F', 'F'),
@@ -55,7 +56,7 @@ typedef struct SIFFContext {
int curstrm;
unsigned int pktsize;
int gmcsize;
- int sndsize;
+ unsigned int sndsize;
unsigned int flags;
uint8_t gmc[4];
@@ -128,6 +129,8 @@ static int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, AVIOContext *pb)
st->codec->width = width;
st->codec->height = height;
st->codec->pix_fmt = AV_PIX_FMT_PAL8;
+ st->nb_frames =
+ st->duration = c->frames;
avpriv_set_pts_info(st, 16, 1, 12);
c->cur_frame = 0;
@@ -193,7 +196,7 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (c->has_video) {
unsigned int size;
if (c->cur_frame >= c->frames)
- return AVERROR(EIO);
+ return AVERROR_EOF;
if (c->curstrm == -1) {
c->pktsize = avio_rl32(s->pb) - 4;
c->flags = avio_rl16(s->pb);
@@ -205,13 +208,20 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
}
if (!c->curstrm) {
- size = c->pktsize - c->sndsize;
- if (av_new_packet(pkt, size) < 0)
+ if (c->pktsize < 2LL + c->sndsize + c->gmcsize)
+ return AVERROR_INVALIDDATA;
+
+ size = c->pktsize - c->sndsize - c->gmcsize - 2;
+ size = ffio_limit(s->pb, size);
+ if (av_new_packet(pkt, size + c->gmcsize + 2) < 0)
return AVERROR(ENOMEM);
AV_WL16(pkt->data, c->flags);
if (c->gmcsize)
memcpy(pkt->data + 2, c->gmc, c->gmcsize);
- avio_read(s->pb, pkt->data + 2 + c->gmcsize, size - c->gmcsize - 2);
+ if (avio_read(s->pb, pkt->data + 2 + c->gmcsize, size) != size) {
+ av_free_packet(pkt);
+ return AVERROR_INVALIDDATA;
+ }
pkt->stream_index = 0;
c->curstrm = -1;
} else {
@@ -228,6 +238,8 @@ static int siff_read_packet(AVFormatContext *s, AVPacket *pkt)
c->cur_frame++;
} else {
int pktsize = av_get_packet(s->pb, pkt, c->block_align);
+ if (!pktsize)
+ return AVERROR_EOF;
if (pktsize <= 0)
return AVERROR(EIO);
pkt->duration = pktsize;
diff --git a/libavformat/smacker.c b/libavformat/smacker.c
index 2fa531bf64..5dcf4adafe 100644
--- a/libavformat/smacker.c
+++ b/libavformat/smacker.c
@@ -2,20 +2,20 @@
* Smacker demuxer
* Copyright (c) 2006 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -94,11 +94,14 @@ static const uint8_t smk_pal[64] = {
static int smacker_probe(AVProbeData *p)
{
- if(p->buf[0] == 'S' && p->buf[1] == 'M' && p->buf[2] == 'K'
- && (p->buf[3] == '2' || p->buf[3] == '4'))
- return AVPROBE_SCORE_MAX;
- else
+ if ( AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2')
+ && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4'))
return 0;
+
+ if (AV_RL32(p->buf+4) > 32768U || AV_RL32(p->buf+8) > 32768U)
+ return AVPROBE_SCORE_MAX/4;
+
+ return AVPROBE_SCORE_MAX;
}
static int smacker_read_header(AVFormatContext *s)
@@ -112,7 +115,7 @@ static int smacker_read_header(AVFormatContext *s)
/* read and check header */
smk->magic = avio_rl32(pb);
if (smk->magic != MKTAG('S', 'M', 'K', '2') && smk->magic != MKTAG('S', 'M', 'K', '4'))
- return -1;
+ return AVERROR_INVALIDDATA;
smk->width = avio_rl32(pb);
smk->height = avio_rl32(pb);
smk->frames = avio_rl32(pb);
@@ -126,7 +129,7 @@ static int smacker_read_header(AVFormatContext *s)
if(smk->treesize >= UINT_MAX/4){ // smk->treesize + 16 must not overflow (this check is probably redundant)
av_log(s, AV_LOG_ERROR, "treesize too large\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
//FIXME remove extradata "rebuilding"
@@ -142,10 +145,15 @@ static int smacker_read_header(AVFormatContext *s)
/* setup data */
if(smk->frames > 0xFFFFFF) {
av_log(s, AV_LOG_ERROR, "Too many frames: %"PRIu32"\n", smk->frames);
- return -1;
+ return AVERROR_INVALIDDATA;
}
- smk->frm_size = av_malloc(smk->frames * 4);
+ smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size));
smk->frm_flags = av_malloc(smk->frames);
+ if (!smk->frm_size || !smk->frm_flags) {
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
+ return AVERROR(ENOMEM);
+ }
smk->is_ver4 = (smk->magic != MKTAG('S', 'M', 'K', '2'));
@@ -160,7 +168,7 @@ static int smacker_read_header(AVFormatContext *s)
/* init video codec */
st = avformat_new_stream(s, NULL);
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
smk->videoindex = st->index;
st->codec->width = smk->width;
st->codec->height = smk->height;
@@ -182,6 +190,8 @@ static int smacker_read_header(AVFormatContext *s)
smk->indexes[i] = -1;
if (smk->rates[i]) {
ast[i] = avformat_new_stream(s, NULL);
+ if (!ast[i])
+ return AVERROR(ENOMEM);
smk->indexes[i] = ast[i]->index;
ast[i]->codec->codec_type = AVMEDIA_TYPE_AUDIO;
if (smk->aflags[i] & SMK_AUD_BINKAUD) {
@@ -212,21 +222,18 @@ static int smacker_read_header(AVFormatContext *s)
/* load trees to extradata, they will be unpacked by decoder */
- st->codec->extradata = av_mallocz(smk->treesize + 16 +
- FF_INPUT_BUFFER_PADDING_SIZE);
- st->codec->extradata_size = smk->treesize + 16;
- if(!st->codec->extradata){
+ if(ff_alloc_extradata(st->codec, smk->treesize + 16)){
av_log(s, AV_LOG_ERROR,
"Cannot allocate %"PRIu32" bytes of extradata\n",
smk->treesize + 16);
- av_free(smk->frm_size);
- av_free(smk->frm_flags);
- return -1;
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
+ return AVERROR(ENOMEM);
}
ret = avio_read(pb, st->codec->extradata + 16, st->codec->extradata_size - 16);
if(ret != st->codec->extradata_size - 16){
- av_free(smk->frm_size);
- av_free(smk->frm_flags);
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
return AVERROR(EIO);
}
((int32_t*)st->codec->extradata)[0] = av_le2ne32(smk->mmap_size);
@@ -250,7 +257,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
int frame_size = 0;
int palchange = 0;
- if (s->pb->eof_reached || smk->cur_frame >= smk->frames)
+ if (avio_feof(s->pb) || smk->cur_frame >= smk->frames)
return AVERROR_EOF;
/* if we demuxed all streams, pass another frame */
@@ -267,6 +274,8 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(oldpal, pal, 768);
size = avio_r8(s->pb);
size = size * 4 - 1;
+ if(size + 1 > frame_size)
+ return AVERROR_INVALIDDATA;
frame_size -= size;
frame_size--;
sz = 0;
@@ -312,7 +321,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
int err;
size = avio_rl32(s->pb) - 4;
- if (!size || size > frame_size) {
+ if (!size || size + 4LL > frame_size) {
av_log(s, AV_LOG_ERROR, "Invalid audio part size\n");
return AVERROR_INVALIDDATA;
}
@@ -348,7 +357,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
smk->cur_frame++;
smk->nextpos = avio_tell(s->pb);
} else {
- if (smk->stream_id[smk->curstream] < 0)
+ if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream])
return AVERROR_INVALIDDATA;
if (av_new_packet(pkt, smk->buf_sizes[smk->curstream]))
return AVERROR(ENOMEM);
@@ -369,16 +378,16 @@ static int smacker_read_close(AVFormatContext *s)
int i;
for(i = 0; i < 7; i++)
- av_free(smk->bufs[i]);
- av_free(smk->frm_size);
- av_free(smk->frm_flags);
+ av_freep(&smk->bufs[i]);
+ av_freep(&smk->frm_size);
+ av_freep(&smk->frm_flags);
return 0;
}
AVInputFormat ff_smacker_demuxer = {
.name = "smk",
- .long_name = NULL_IF_CONFIG_SMALL("Smacker video"),
+ .long_name = NULL_IF_CONFIG_SMALL("Smacker"),
.priv_data_size = sizeof(SmackerContext),
.read_probe = smacker_probe,
.read_header = smacker_read_header,
diff --git a/libavformat/smjpeg.c b/libavformat/smjpeg.c
index 52e45e98f0..4edf5e8ac4 100644
--- a/libavformat/smjpeg.c
+++ b/libavformat/smjpeg.c
@@ -2,20 +2,20 @@
* SMJPEG common code
* Copyright (c) 2011-2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/smjpeg.h b/libavformat/smjpeg.h
index c56fe46939..995ddf22da 100644
--- a/libavformat/smjpeg.h
+++ b/libavformat/smjpeg.h
@@ -2,20 +2,20 @@
* SMJPEG common code
* Copyright (c) 2011-2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/smjpegdec.c b/libavformat/smjpegdec.c
index a9ed28e261..99ca2ff8c9 100644
--- a/libavformat/smjpegdec.c
+++ b/libavformat/smjpegdec.c
@@ -2,20 +2,20 @@
* SMJPEG demuxer
* Copyright (c) 2011 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -58,7 +58,7 @@ static int smjpeg_read_header(AVFormatContext *s)
duration = avio_rb32(pb); // in msec
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
htype = avio_rl32(pb);
switch (htype) {
case SMJPEG_TXT:
@@ -108,10 +108,10 @@ static int smjpeg_read_header(AVFormatContext *s)
hlength = avio_rb32(pb);
if (hlength < 12)
return AVERROR_INVALIDDATA;
- avio_skip(pb, 4); // number of frames
vst = avformat_new_stream(s, 0);
if (!vst)
return AVERROR(ENOMEM);
+ vst->nb_frames = avio_rb32(pb);
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->width = avio_rb16(pb);
vst->codec->height = avio_rb16(pb);
@@ -141,7 +141,7 @@ static int smjpeg_read_packet(AVFormatContext *s, AVPacket *pkt)
int64_t pos;
int ret;
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR_EOF;
pos = avio_tell(s->pb);
dtype = avio_rl32(s->pb);
diff --git a/libavformat/smjpegenc.c b/libavformat/smjpegenc.c
index 551af8911d..430a497c6e 100644
--- a/libavformat/smjpegenc.c
+++ b/libavformat/smjpegenc.c
@@ -2,20 +2,20 @@
* SMJPEG muxer
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -66,7 +66,7 @@ static int smjpeg_write_header(AVFormatContext *s)
avio_wl32(pb, SMJPEG_SND);
avio_wb32(pb, 8);
avio_wb16(pb, codec->sample_rate);
- avio_w8(pb, av_get_bits_per_sample(codec->codec_id));
+ avio_w8(pb, codec->bits_per_coded_sample);
avio_w8(pb, codec->channels);
avio_wl32(pb, tag);
avpriv_set_pts_info(st, 32, 1, 1000);
diff --git a/libavformat/smoothstreamingenc.c b/libavformat/smoothstreamingenc.c
index 6af8b3991c..07173a96f9 100644
--- a/libavformat/smoothstreamingenc.c
+++ b/libavformat/smoothstreamingenc.c
@@ -2,20 +2,20 @@
* Live smooth streaming fragmenter
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -179,13 +179,13 @@ static void ism_free(AVFormatContext *s)
if (os->ctx && os->ctx_inited)
av_write_trailer(os->ctx);
if (os->ctx && os->ctx->pb)
- av_free(os->ctx->pb);
+ av_freep(&os->ctx->pb);
if (os->ctx)
avformat_free_context(os->ctx);
- av_free(os->private_str);
+ av_freep(&os->private_str);
for (j = 0; j < os->nb_fragments; j++)
- av_free(os->fragments[j]);
- av_free(os->fragments);
+ av_freep(&os->fragments[j]);
+ av_freep(&os->fragments);
}
av_freep(&c->streams);
}
@@ -283,7 +283,7 @@ static int write_manifest(AVFormatContext *s, int final)
avio_printf(out, "</SmoothStreamingMedia>\n");
avio_flush(out);
avio_close(out);
- return ff_rename(temp_filename, filename);
+ return ff_rename(temp_filename, filename, s);
}
static int ism_write_header(AVFormatContext *s)
@@ -294,6 +294,7 @@ static int ism_write_header(AVFormatContext *s)
if (mkdir(s->filename, 0777) == -1 && errno != EEXIST) {
ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR, "mkdir failed\n");
goto fail;
}
@@ -303,7 +304,7 @@ static int ism_write_header(AVFormatContext *s)
goto fail;
}
- c->streams = av_mallocz(sizeof(*c->streams) * s->nb_streams);
+ c->streams = av_mallocz_array(s->nb_streams, sizeof(*c->streams));
if (!c->streams) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -314,7 +315,6 @@ static int ism_write_header(AVFormatContext *s)
AVFormatContext *ctx;
AVStream *st;
AVDictionary *opts = NULL;
- char buf[10];
if (!s->streams[i]->codec->bit_rate) {
av_log(s, AV_LOG_ERROR, "No bit rate set for stream %d\n", i);
@@ -324,6 +324,7 @@ static int ism_write_header(AVFormatContext *s)
snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%d)", s->filename, s->streams[i]->codec->bit_rate);
if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) {
ret = AVERROR(errno);
+ av_log(s, AV_LOG_ERROR, "mkdir failed\n");
goto fail;
}
@@ -350,8 +351,7 @@ static int ism_write_header(AVFormatContext *s)
goto fail;
}
- snprintf(buf, sizeof(buf), "%d", c->lookahead_count);
- av_dict_set(&opts, "ism_lookahead", buf, 0);
+ av_dict_set_int(&opts, "ism_lookahead", c->lookahead_count, 0);
av_dict_set(&opts, "movflags", "frag_custom", 0);
if ((ret = avformat_write_header(ctx, &opts)) < 0) {
goto fail;
@@ -433,7 +433,7 @@ static int parse_fragment(AVFormatContext *s, const char *filename, int64_t *sta
if (len < 8 || len >= *moof_size)
goto fail;
if (tag == MKTAG('u','u','i','d')) {
- const uint8_t tfxd[] = {
+ static const uint8_t tfxd[] = {
0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
};
@@ -541,7 +541,7 @@ static int ism_flush(AVFormatContext *s, int final)
snprintf(header_filename, sizeof(header_filename), "%s/FragmentInfo(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
snprintf(target_filename, sizeof(target_filename), "%s/Fragments(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts);
copy_moof(s, filename, header_filename, moof_size);
- ret = ff_rename(filename, target_filename);
+ ret = ff_rename(filename, target_filename, s);
if (ret < 0)
break;
add_fragment(os, target_filename, header_filename, start_ts, duration,
@@ -559,7 +559,7 @@ static int ism_flush(AVFormatContext *s, int final)
for (j = 0; j < remove; j++) {
unlink(os->fragments[j]->file);
unlink(os->fragments[j]->infofile);
- av_free(os->fragments[j]);
+ av_freep(&os->fragments[j]);
}
os->nb_fragments -= remove;
memmove(os->fragments, os->fragments + remove, os->nb_fragments * sizeof(*os->fragments));
@@ -596,7 +596,7 @@ static int ism_write_packet(AVFormatContext *s, AVPacket *pkt)
}
os->packets_written++;
- return ff_write_chained(os->ctx, 0, pkt, s);
+ return ff_write_chained(os->ctx, 0, pkt, s, 0);
}
static int ism_write_trailer(AVFormatContext *s)
diff --git a/libavformat/smush.c b/libavformat/smush.c
index 1615b45417..abb6989fe4 100644
--- a/libavformat/smush.c
+++ b/libavformat/smush.c
@@ -2,20 +2,20 @@
* LucasArts Smush demuxer
* Copyright (c) 2006 Cyril Zorin
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -102,7 +102,7 @@ static int smush_read_header(AVFormatContext *ctx)
while (!got_audio && ((read + 8) < size)) {
uint32_t sig, chunk_size;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
sig = avio_rb32(pb);
@@ -158,11 +158,7 @@ static int smush_read_header(AVFormatContext *ctx)
vst->codec->height = height;
if (!smush->version) {
- av_free(vst->codec->extradata);
- vst->codec->extradata_size = 1024 + 2;
- vst->codec->extradata = av_malloc(vst->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!vst->codec->extradata)
+ if (ff_alloc_extradata(vst->codec, 1024 + 2))
return AVERROR(ENOMEM);
AV_WL16(vst->codec->extradata, subversion);
@@ -200,7 +196,7 @@ static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt)
while (!done) {
uint32_t sig, size;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
sig = avio_rb32(pb);
diff --git a/libavformat/sol.c b/libavformat/sol.c
index 30f0547d1d..c9434535ef 100644
--- a/libavformat/sol.c
+++ b/libavformat/sol.c
@@ -2,20 +2,20 @@
* Sierra SOL demuxer
* Copyright Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -128,16 +128,13 @@ static int sol_read_packet(AVFormatContext *s,
{
int ret;
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR(EIO);
ret= av_get_packet(s->pb, pkt, MAX_SIZE);
if (ret < 0)
return ret;
+ pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
pkt->stream_index = 0;
-
- /* note: we need to modify the packet size here to handle the last
- packet */
- pkt->size = ret;
return 0;
}
diff --git a/libavformat/sox.h b/libavformat/sox.h
index e59531bea3..f4a12e93ff 100644
--- a/libavformat/sox.h
+++ b/libavformat/sox.h
@@ -2,20 +2,20 @@
* SoX native format common data
* Copyright (c) 2009 Daniel Verkamp <daniel@drv.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/soxdec.c b/libavformat/soxdec.c
index ec94675830..aec42843cb 100644
--- a/libavformat/soxdec.c
+++ b/libavformat/soxdec.c
@@ -5,20 +5,20 @@
* Based on libSoX sox-fmt.c
* Copyright (c) 2008 robs@users.sourceforge.net
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -75,12 +75,12 @@ static int sox_read_header(AVFormatContext *s)
if (comment_size > 0xFFFFFFFFU - SOX_FIXED_HDR - 4U) {
av_log(s, AV_LOG_ERROR, "invalid comment size (%u)\n", comment_size);
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (sample_rate <= 0 || sample_rate > INT_MAX) {
av_log(s, AV_LOG_ERROR, "invalid sample rate (%f)\n", sample_rate);
- return -1;
+ return AVERROR_INVALIDDATA;
}
sample_rate_frac = sample_rate - floor(sample_rate);
@@ -92,11 +92,13 @@ static int sox_read_header(AVFormatContext *s)
if ((header_size + 4) & 7 || header_size < SOX_FIXED_HDR + comment_size
|| st->codec->channels > 65535) /* Reserve top 16 bits */ {
av_log(s, AV_LOG_ERROR, "invalid header\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
if (comment_size && comment_size < UINT_MAX) {
char *comment = av_malloc(comment_size+1);
+ if(!comment)
+ return AVERROR(ENOMEM);
if (avio_read(pb, comment, comment_size) != comment_size) {
av_freep(&comment);
return AVERROR(EIO);
@@ -122,31 +124,11 @@ static int sox_read_header(AVFormatContext *s)
return 0;
}
-#define SOX_SAMPLES 1024
-
-static int sox_read_packet(AVFormatContext *s,
- AVPacket *pkt)
-{
- int ret, size;
-
- if (s->pb->eof_reached)
- return AVERROR_EOF;
-
- size = SOX_SAMPLES*s->streams[0]->codec->block_align;
- ret = av_get_packet(s->pb, pkt, size);
- if (ret < 0)
- return AVERROR(EIO);
- pkt->stream_index = 0;
- pkt->size = ret;
-
- return 0;
-}
-
AVInputFormat ff_sox_demuxer = {
.name = "sox",
.long_name = NULL_IF_CONFIG_SMALL("SoX native"),
.read_probe = sox_probe,
.read_header = sox_read_header,
- .read_packet = sox_read_packet,
+ .read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
};
diff --git a/libavformat/soxenc.c b/libavformat/soxenc.c
index 17de1789a1..bfa90025e1 100644
--- a/libavformat/soxenc.c
+++ b/libavformat/soxenc.c
@@ -5,20 +5,20 @@
* Based on libSoX sox-fmt.c
* Copyright (c) 2008 robs@users.sourceforge.net
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,6 +34,7 @@
#include "libavutil/dict.h"
#include "avformat.h"
#include "avio_internal.h"
+#include "rawenc.h"
#include "sox.h"
typedef struct SoXContext {
@@ -51,7 +52,7 @@ static int sox_write_header(AVFormatContext *s)
comment = av_dict_get(s->metadata, "comment", NULL, 0);
if (comment)
comment_len = strlen(comment->value);
- comment_size = (comment_len + 7) & ~7;
+ comment_size = FFALIGN(comment_len, 8);
sox->header_size = SOX_FIXED_HDR + comment_size;
@@ -71,27 +72,19 @@ static int sox_write_header(AVFormatContext *s)
avio_wb32(pb, comment_size);
} else {
av_log(s, AV_LOG_ERROR, "invalid codec; use pcm_s32le or pcm_s32be\n");
- return -1;
+ return AVERROR(EINVAL);
}
if (comment_len)
avio_write(pb, comment->value, comment_len);
- for ( ; comment_size > comment_len; comment_len++)
- avio_w8(pb, 0);
+ ffio_fill(pb, 0, comment_size - comment_len);
avio_flush(pb);
return 0;
}
-static int sox_write_packet(AVFormatContext *s, AVPacket *pkt)
-{
- AVIOContext *pb = s->pb;
- avio_write(pb, pkt->data, pkt->size);
- return 0;
-}
-
static int sox_write_trailer(AVFormatContext *s)
{
SoXContext *sox = s->priv_data;
@@ -123,7 +116,7 @@ AVOutputFormat ff_sox_muxer = {
.audio_codec = AV_CODEC_ID_PCM_S32LE,
.video_codec = AV_CODEC_ID_NONE,
.write_header = sox_write_header,
- .write_packet = sox_write_packet,
+ .write_packet = ff_raw_write_packet,
.write_trailer = sox_write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
};
diff --git a/libavformat/spdif.c b/libavformat/spdif.c
index 777ac47ba5..604141a261 100644
--- a/libavformat/spdif.c
+++ b/libavformat/spdif.c
@@ -2,20 +2,20 @@
* IEC 61937 common code
* Copyright (c) 2009 Bartlomiej Wolowiec
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/spdif.h b/libavformat/spdif.h
index f5b15ebbb1..fee4ff710b 100644
--- a/libavformat/spdif.h
+++ b/libavformat/spdif.h
@@ -2,20 +2,20 @@
* IEC 61937 common header
* Copyright (c) 2009 Bartlomiej Wolowiec
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,7 @@
#define AVFORMAT_SPDIF_H
#include <stdint.h>
+#include "avformat.h"
#define SYNCWORD1 0xF872
#define SYNCWORD2 0x4E1F
@@ -58,5 +59,7 @@ static const uint16_t spdif_mpeg_pkt_offset[2][3] = {
};
void ff_spdif_bswap_buf16(uint16_t *dst, const uint16_t *src, int w);
+int ff_spdif_read_packet(AVFormatContext *s, AVPacket *pkt);
+int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec);
#endif /* AVFORMAT_SPDIF_H */
diff --git a/libavformat/spdifdec.c b/libavformat/spdifdec.c
index 2fb94773a5..7c04afaf93 100644
--- a/libavformat/spdifdec.c
+++ b/libavformat/spdifdec.c
@@ -2,20 +2,20 @@
* IEC 61937 demuxer
* Copyright (c) 2010 Anssi Hannula <anssi.hannula at iki.fi>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,7 +57,7 @@ static int spdif_get_offset_and_codec(AVFormatContext *s,
break;
case IEC61937_MPEG2_AAC:
init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8);
- if (avpriv_aac_parse_header(&gbc, &aac_hdr)) {
+ if (avpriv_aac_parse_header(&gbc, &aac_hdr) < 0) {
if (s) /* be silent during a probe */
av_log(s, AV_LOG_ERROR, "Invalid AAC packet in IEC 61937\n");
return AVERROR_INVALIDDATA;
@@ -105,14 +105,19 @@ static int spdif_get_offset_and_codec(AVFormatContext *s,
static int spdif_probe(AVProbeData *p)
{
- const uint8_t *buf = p->buf;
- const uint8_t *probe_end = p->buf + FFMIN(2 * SPDIF_MAX_OFFSET, p->buf_size - 1);
+ enum AVCodecID codec;
+ return ff_spdif_probe (p->buf, p->buf_size, &codec);
+}
+
+int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec)
+{
+ const uint8_t *buf = p_buf;
+ const uint8_t *probe_end = p_buf + FFMIN(2 * SPDIF_MAX_OFFSET, buf_size - 1);
const uint8_t *expected_code = buf + 7;
uint32_t state = 0;
int sync_codes = 0;
int consecutive_codes = 0;
int offset;
- enum AVCodecID codec;
for (; buf < probe_end; buf++) {
state = (state << 8) | *buf;
@@ -127,16 +132,16 @@ static int spdif_probe(AVProbeData *p)
} else
consecutive_codes = 0;
- if (buf + 4 + AAC_ADTS_HEADER_SIZE > p->buf + p->buf_size)
+ if (buf + 4 + AAC_ADTS_HEADER_SIZE > p_buf + buf_size)
break;
/* continue probing to find more sync codes */
- probe_end = FFMIN(buf + SPDIF_MAX_OFFSET, p->buf + p->buf_size - 1);
+ probe_end = FFMIN(buf + SPDIF_MAX_OFFSET, p_buf + buf_size - 1);
/* skip directly to the next sync code */
if (!spdif_get_offset_and_codec(NULL, (buf[2] << 8) | buf[1],
- &buf[5], &offset, &codec)) {
- if (buf + offset >= p->buf + p->buf_size)
+ &buf[5], &offset, codec)) {
+ if (buf + offset >= p_buf + buf_size)
break;
expected_code = buf + offset;
buf = expected_code - 7;
@@ -161,7 +166,7 @@ static int spdif_read_header(AVFormatContext *s)
return 0;
}
-static int spdif_read_packet(AVFormatContext *s, AVPacket *pkt)
+int ff_spdif_read_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
enum IEC61937DataType data_type;
@@ -171,7 +176,7 @@ static int spdif_read_packet(AVFormatContext *s, AVPacket *pkt)
while (state != (AV_BSWAP16C(SYNCWORD1) << 16 | AV_BSWAP16C(SYNCWORD2))) {
state = (state << 8) | avio_r8(pb);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
}
@@ -230,6 +235,6 @@ AVInputFormat ff_spdif_demuxer = {
.long_name = NULL_IF_CONFIG_SMALL("IEC 61937 (compressed data in S/PDIF)"),
.read_probe = spdif_probe,
.read_header = spdif_read_header,
- .read_packet = spdif_read_packet,
+ .read_packet = ff_spdif_read_packet,
.flags = AVFMT_GENERIC_INDEX,
};
diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c
index 432654affd..cdcff24421 100644
--- a/libavformat/spdifenc.c
+++ b/libavformat/spdifenc.c
@@ -4,20 +4,20 @@
* Copyright (c) 2010 Anssi Hannula
* Copyright (c) 2010 Carl Eugen Hoyos
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -95,7 +95,7 @@ static const AVOption options[] = {
{ NULL },
};
-static const AVClass class = {
+static const AVClass spdif_class = {
.class_name = "spdif",
.item_name = av_default_item_name,
.option = options,
@@ -398,15 +398,15 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt)
{
IEC61937Context *ctx = s->priv_data;
int mat_code_length = 0;
- const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 };
+ static const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 };
if (!ctx->hd_buf_count) {
- const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 };
+ static const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 };
mat_code_length = sizeof(mat_start_code) + BURST_HEADER_SIZE;
memcpy(ctx->hd_buf, mat_start_code, sizeof(mat_start_code));
} else if (ctx->hd_buf_count == 12) {
- const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 };
+ static const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 };
mat_code_length = sizeof(mat_middle_code) + MAT_MIDDLE_CODE_OFFSET;
memcpy(&ctx->hd_buf[12 * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + MAT_MIDDLE_CODE_OFFSET],
mat_middle_code, sizeof(mat_middle_code));
@@ -523,13 +523,13 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt)
}
if (ctx->extra_bswap ^ (ctx->spdif_flags & SPDIF_FLAG_BIGENDIAN)) {
- avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1);
+ avio_write(s->pb, ctx->out_buf, ctx->out_bytes & ~1);
} else {
- av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!ctx->buffer)
- return AVERROR(ENOMEM);
- ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1);
- avio_write(s->pb, ctx->buffer, ctx->out_bytes & ~1);
+ av_fast_malloc(&ctx->buffer, &ctx->buffer_size, ctx->out_bytes + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!ctx->buffer)
+ return AVERROR(ENOMEM);
+ ff_spdif_bswap_buf16((uint16_t *)ctx->buffer, (uint16_t *)ctx->out_buf, ctx->out_bytes >> 1);
+ avio_write(s->pb, ctx->buffer, ctx->out_bytes & ~1);
}
/* a final lone byte has to be MSB aligned */
@@ -555,5 +555,5 @@ AVOutputFormat ff_spdif_muxer = {
.write_packet = spdif_write_packet,
.write_trailer = spdif_write_trailer,
.flags = AVFMT_NOTIMESTAMPS,
- .priv_class = &class,
+ .priv_class = &spdif_class,
};
diff --git a/libavformat/srtdec.c b/libavformat/srtdec.c
index 9db5133a21..b35e50fc36 100644
--- a/libavformat/srtdec.c
+++ b/libavformat/srtdec.c
@@ -2,101 +2,173 @@
* SubRip subtitle demuxer
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "internal.h"
+#include "subtitles.h"
+#include "libavutil/bprint.h"
#include "libavutil/intreadwrite.h"
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} SRTContext;
+
static int srt_probe(AVProbeData *p)
{
- unsigned char *ptr = p->buf;
- int i, v, num = 0;
+ int v;
+ char buf[64], *pbuf;
+ FFTextReader tr;
+
+ ff_text_init_buf(&tr, p->buf, p->buf_size);
+
+ while (ff_text_peek_r8(&tr) == '\r' || ff_text_peek_r8(&tr) == '\n')
+ ff_text_r8(&tr);
+
+ /* Check if the first non-empty line is a number. We do not check what the
+ * number is because in practice it can be anything. */
+ if (ff_subtitles_read_line(&tr, buf, sizeof(buf)) < 0 ||
+ strtol(buf, &pbuf, 10) < 0 || *pbuf)
+ return 0;
+
+ /* Check if the next line matches a SRT timestamp */
+ if (ff_subtitles_read_line(&tr, buf, sizeof(buf)) < 0)
+ return 0;
+ if (buf[0] >= '0' && buf[1] <= '9' && strstr(buf, " --> ")
+ && sscanf(buf, "%*d:%*2d:%*2d%*1[,.]%*3d --> %*d:%*2d:%*2d%*1[,.]%3d", &v) == 1)
+ return AVPROBE_SCORE_MAX;
+
+ return 0;
+}
- if (AV_RB24(ptr) == 0xEFBBBF)
- ptr += 3; /* skip UTF-8 BOM */
+static int64_t get_pts(const char **buf, int *duration,
+ int32_t *x1, int32_t *y1, int32_t *x2, int32_t *y2)
+{
+ int i;
for (i=0; i<2; i++) {
- if (num == i && sscanf(ptr, "%*d:%*2d:%*2d%*1[,.]%*3d --> %*d:%*2d:%*2d%*1[,.]%3d", &v) == 1)
- return AVPROBE_SCORE_MAX;
- num = atoi(ptr);
- ptr += strcspn(ptr, "\n") + 1;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+ if (sscanf(*buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
+ "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
+ &hh1, &mm1, &ss1, &ms1,
+ &hh2, &mm2, &ss2, &ms2,
+ x1, x2, y1, y2) >= 8) {
+ int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
+ int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
+ *duration = end - start;
+ *buf += ff_subtitles_next_line(*buf);
+ return start;
+ }
+ *buf += ff_subtitles_next_line(*buf);
}
- return 0;
+ return AV_NOPTS_VALUE;
}
static int srt_read_header(AVFormatContext *s)
{
+ SRTContext *srt = s->priv_data;
+ AVBPrint buf;
AVStream *st = avformat_new_stream(s, NULL);
+ int res = 0;
+ FFTextReader tr;
+ ff_text_init_avio(s, &tr, s->pb);
+
if (!st)
- return -1;
+ return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 64, 1, 1000);
st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
- st->codec->codec_id = AV_CODEC_ID_SRT;
- return 0;
-}
+ st->codec->codec_id = AV_CODEC_ID_SUBRIP;
-static int64_t get_pts(const char *buf)
-{
- int i, v, hour, min, sec, hsec;
+ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
- for (i=0; i<2; i++) {
- if (sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %*d:%*2d:%*2d%*1[,.]%3d",
- &hour, &min, &sec, &hsec, &v) == 5) {
- min += 60*hour;
- sec += 60*min;
- return sec*1000+hsec;
+ while (!ff_text_eof(&tr)) {
+ ff_subtitles_read_text_chunk(&tr, &buf);
+
+ if (buf.len) {
+ int64_t pos = ff_text_pos(&tr);
+ int64_t pts;
+ int duration;
+ const char *ptr = buf.str;
+ int32_t x1 = -1, y1 = -1, x2 = -1, y2 = -1;
+ AVPacket *sub;
+
+ pts = get_pts(&ptr, &duration, &x1, &y1, &x2, &y2);
+ if (pts != AV_NOPTS_VALUE) {
+ int len = buf.len - (ptr - buf.str);
+ if (len <= 0)
+ continue;
+ sub = ff_subtitles_queue_insert(&srt->q, ptr, len, 0);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ sub->pos = pos;
+ sub->pts = pts;
+ sub->duration = duration;
+ if (x1 != -1) {
+ uint8_t *p = av_packet_new_side_data(sub, AV_PKT_DATA_SUBTITLE_POSITION, 16);
+ if (p) {
+ AV_WL32(p, x1);
+ AV_WL32(p + 4, y1);
+ AV_WL32(p + 8, x2);
+ AV_WL32(p + 12, y2);
+ }
+ }
+ }
}
- buf += strcspn(buf, "\n") + 1;
}
- return AV_NOPTS_VALUE;
+
+ ff_subtitles_queue_finalize(&srt->q);
+
+end:
+ av_bprint_finalize(&buf, NULL);
+ return res;
}
-static inline int is_eol(char c)
+static int srt_read_packet(AVFormatContext *s, AVPacket *pkt)
{
- return c == '\r' || c == '\n';
+ SRTContext *srt = s->priv_data;
+ return ff_subtitles_queue_read_packet(&srt->q, pkt);
}
-static int srt_read_packet(AVFormatContext *s, AVPacket *pkt)
+static int srt_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
{
- char buffer[2048], *ptr = buffer, *ptr2;
- int64_t pos = avio_tell(s->pb);
- int res = AVERROR_EOF;
-
- do {
- ptr2 = ptr;
- ptr += ff_get_line(s->pb, ptr, sizeof(buffer)+buffer-ptr);
- } while (!is_eol(*ptr2) && !s->pb->eof_reached && ptr-buffer<sizeof(buffer)-1);
-
- if (buffer[0] && !(res = av_new_packet(pkt, ptr-buffer))) {
- memcpy(pkt->data, buffer, pkt->size);
- pkt->flags |= AV_PKT_FLAG_KEY;
- pkt->pos = pos;
- pkt->pts = pkt->dts = get_pts(pkt->data);
- }
- return res;
+ SRTContext *srt = s->priv_data;
+ return ff_subtitles_queue_seek(&srt->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int srt_read_close(AVFormatContext *s)
+{
+ SRTContext *srt = s->priv_data;
+ ff_subtitles_queue_clean(&srt->q);
+ return 0;
}
AVInputFormat ff_srt_demuxer = {
.name = "srt",
.long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
+ .priv_data_size = sizeof(SRTContext),
.read_probe = srt_probe,
.read_header = srt_read_header,
.read_packet = srt_read_packet,
- .flags = AVFMT_GENERIC_INDEX,
+ .read_seek2 = srt_read_seek,
+ .read_close = srt_read_close,
};
diff --git a/libavformat/srtenc.c b/libavformat/srtenc.c
new file mode 100644
index 0000000000..9bb83d645d
--- /dev/null
+++ b/libavformat/srtenc.c
@@ -0,0 +1,112 @@
+/*
+ * SubRip subtitle muxer
+ * Copyright (c) 2012 Nicolas George <nicolas.george@normalesup.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+#include "libavutil/log.h"
+#include "libavutil/intreadwrite.h"
+
+/* TODO: add options for:
+ - character encoding;
+ - LF / CRLF;
+ - byte order mark.
+ */
+
+typedef struct SRTContext{
+ unsigned index;
+} SRTContext;
+
+static int srt_write_header(AVFormatContext *avf)
+{
+ SRTContext *srt = avf->priv_data;
+
+ if (avf->nb_streams != 1 ||
+ avf->streams[0]->codec->codec_type != AVMEDIA_TYPE_SUBTITLE) {
+ av_log(avf, AV_LOG_ERROR,
+ "SRT supports only a single subtitles stream.\n");
+ return AVERROR(EINVAL);
+ }
+ if (avf->streams[0]->codec->codec_id != AV_CODEC_ID_TEXT &&
+ avf->streams[0]->codec->codec_id != AV_CODEC_ID_SUBRIP) {
+ av_log(avf, AV_LOG_ERROR,
+ "Unsupported subtitles codec: %s\n",
+ avcodec_get_name(avf->streams[0]->codec->codec_id));
+ return AVERROR(EINVAL);
+ }
+ avpriv_set_pts_info(avf->streams[0], 64, 1, 1000);
+ srt->index = 1;
+ return 0;
+}
+
+static int srt_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+ SRTContext *srt = avf->priv_data;
+
+ // TODO: reindent
+ int64_t s = pkt->pts, e, d = pkt->duration;
+ int size, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
+ const uint8_t *p;
+
+ p = av_packet_get_side_data(pkt, AV_PKT_DATA_SUBTITLE_POSITION, &size);
+ if (p && size == 16) {
+ x1 = AV_RL32(p );
+ y1 = AV_RL32(p + 4);
+ x2 = AV_RL32(p + 8);
+ y2 = AV_RL32(p + 12);
+ }
+
+ if (d <= 0)
+ /* For backward compatibility, fallback to convergence_duration. */
+ d = pkt->convergence_duration;
+ if (s == AV_NOPTS_VALUE || d < 0) {
+ av_log(avf, AV_LOG_WARNING,
+ "Insufficient timestamps in event number %d.\n", srt->index);
+ return 0;
+ }
+ e = s + d;
+ avio_printf(avf->pb, "%d\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
+ srt->index,
+ (int)(s / 3600000), (int)(s / 60000) % 60,
+ (int)(s / 1000) % 60, (int)(s % 1000),
+ (int)(e / 3600000), (int)(e / 60000) % 60,
+ (int)(e / 1000) % 60, (int)(e % 1000));
+ if (p)
+ avio_printf(avf->pb, " X1:%03d X2:%03d Y1:%03d Y2:%03d",
+ x1, x2, y1, y2);
+ avio_printf(avf->pb, "\n");
+
+ avio_write(avf->pb, pkt->data, pkt->size);
+ avio_write(avf->pb, "\n\n", 2);
+ srt->index++;
+ return 0;
+}
+
+AVOutputFormat ff_srt_muxer = {
+ .name = "srt",
+ .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
+ .mime_type = "application/x-subrip",
+ .extensions = "srt",
+ .priv_data_size = sizeof(SRTContext),
+ .write_header = srt_write_header,
+ .write_packet = srt_write_packet,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+ .subtitle_codec = AV_CODEC_ID_SUBRIP,
+};
diff --git a/libavformat/srtp.c b/libavformat/srtp.c
index 6659bfc5c9..b6e821115c 100644
--- a/libavformat/srtp.c
+++ b/libavformat/srtp.c
@@ -2,20 +2,20 @@
* SRTP encryption/decryption
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/srtp.h b/libavformat/srtp.h
index 18ed177af5..3189f8f54b 100644
--- a/libavformat/srtp.h
+++ b/libavformat/srtp.h
@@ -2,20 +2,20 @@
* SRTP encryption/decryption
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/srtpproto.c b/libavformat/srtpproto.c
index 1f818d78b4..0124696ad0 100644
--- a/libavformat/srtpproto.c
+++ b/libavformat/srtpproto.c
@@ -2,20 +2,20 @@
* SRTP network protocol
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/stldec.c b/libavformat/stldec.c
new file mode 100644
index 0000000000..b84c7e9eb0
--- /dev/null
+++ b/libavformat/stldec.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014 Eejya Singh
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * STL subtitles format demuxer
+ * @see https://documentation.apple.com/en/dvdstudiopro/usermanual/index.html#chapter=19%26section=13%26tasks=true
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/avstring.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} STLContext;
+
+static int stl_probe(AVProbeData *p)
+{
+ char c;
+ const unsigned char *ptr = p->buf;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+
+ while (*ptr == '\r' || *ptr == '\n' || *ptr == '$' || !strncmp(ptr, "//" , 2))
+ ptr += ff_subtitles_next_line(ptr);
+
+ if (sscanf(ptr, "%*d:%*d:%*d:%*d , %*d:%*d:%*d:%*d , %c", &c) == 1)
+ return AVPROBE_SCORE_MAX;
+
+ return 0;
+}
+
+static int64_t get_pts(char **buf, int *duration)
+{
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+ int len = 0;
+
+ if (sscanf(*buf, "%2d:%2d:%2d:%2d , %2d:%2d:%2d:%2d , %n",
+ &hh1, &mm1, &ss1, &ms1,
+ &hh2, &mm2, &ss2, &ms2, &len) >= 8 && len > 0) {
+ int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
+ int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
+ *duration = end - start;
+ *buf += len;
+ return start;
+ }
+ return AV_NOPTS_VALUE;
+}
+
+static int stl_read_header(AVFormatContext *s)
+{
+ STLContext *stl = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 100);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_STL;
+
+ while (!avio_feof(s->pb)) {
+ char line[4096];
+ char *p = line;
+ const int64_t pos = avio_tell(s->pb);
+ int len = ff_get_line(s->pb, line, sizeof(line));
+ int64_t pts_start;
+ int duration;
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+ pts_start = get_pts(&p , &duration);
+
+ if (pts_start != AV_NOPTS_VALUE) {
+ AVPacket *sub;
+ sub = ff_subtitles_queue_insert(&stl->q, p, strlen(p), 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ sub->pts = pts_start;
+ sub->duration = duration;
+ }
+ }
+ ff_subtitles_queue_finalize(&stl->q);
+ return 0;
+}
+static int stl_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ STLContext *stl = s->priv_data;
+ return ff_subtitles_queue_read_packet(&stl->q, pkt);
+}
+
+static int stl_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ STLContext *stl = s->priv_data;
+ return ff_subtitles_queue_seek(&stl->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int stl_read_close(AVFormatContext *s)
+{
+ STLContext *stl = s->priv_data;
+ ff_subtitles_queue_clean(&stl->q);
+ return 0;
+}
+
+AVInputFormat ff_stl_demuxer = {
+ .name = "stl",
+ .long_name = NULL_IF_CONFIG_SMALL("Spruce subtitle format"),
+ .priv_data_size = sizeof(STLContext),
+ .read_probe = stl_probe,
+ .read_header = stl_read_header,
+ .read_packet = stl_read_packet,
+ .read_seek2 = stl_read_seek,
+ .read_close = stl_read_close,
+ .extensions = "stl",
+};
diff --git a/libavformat/subfile.c b/libavformat/subfile.c
new file mode 100644
index 0000000000..0e84384600
--- /dev/null
+++ b/libavformat/subfile.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "url.h"
+
+typedef struct SubfileContext {
+ const AVClass *class;
+ URLContext *h;
+ int64_t start;
+ int64_t end;
+ int64_t pos;
+} SubfileContext;
+
+#define OFFSET(field) offsetof(SubfileContext, field)
+#define D AV_OPT_FLAG_DECODING_PARAM
+
+static const AVOption subfile_options[] = {
+ { "start", "start offset", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D },
+ { "end", "end offset", OFFSET(end), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, D },
+ { NULL }
+};
+
+#undef OFFSET
+#undef D
+
+static const AVClass subfile_class = {
+ .class_name = "subfile",
+ .item_name = av_default_item_name,
+ .option = subfile_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int slave_seek(URLContext *h)
+{
+ SubfileContext *c = h->priv_data;
+ int64_t ret;
+
+ if ((ret = ffurl_seek(c->h, c->pos, SEEK_SET)) != c->pos) {
+ if (ret >= 0)
+ ret = AVERROR_BUG;
+ av_log(h, AV_LOG_ERROR, "Impossible to seek in file: %s\n",
+ av_err2str(ret));
+ return ret;
+ }
+ return 0;
+}
+
+static int subfile_open(URLContext *h, const char *filename, int flags,
+ AVDictionary **options)
+{
+ SubfileContext *c = h->priv_data;
+ int ret;
+
+ if (c->end <= c->start) {
+ av_log(h, AV_LOG_ERROR, "end before start\n");
+ return AVERROR(EINVAL);
+ }
+ av_strstart(filename, "subfile:", &filename);
+ ret = ffurl_open(&c->h, filename, flags, &h->interrupt_callback, options);
+ if (ret < 0)
+ return ret;
+ c->pos = c->start;
+ if ((ret = slave_seek(h)) < 0) {
+ ffurl_close(c->h);
+ return ret;
+ }
+ return 0;
+}
+
+static int subfile_close(URLContext *h)
+{
+ SubfileContext *c = h->priv_data;
+ return ffurl_close(c->h);
+}
+
+static int subfile_read(URLContext *h, unsigned char *buf, int size)
+{
+ SubfileContext *c = h->priv_data;
+ int64_t rest = c->end - c->pos;
+ int ret;
+
+ if (rest <= 0)
+ return 0;
+ size = FFMIN(size, rest);
+ ret = ffurl_read(c->h, buf, size);
+ if (ret >= 0)
+ c->pos += ret;
+ return ret;
+}
+
+static int64_t subfile_seek(URLContext *h, int64_t pos, int whence)
+{
+ SubfileContext *c = h->priv_data;
+ int64_t new_pos = -1;
+ int ret;
+
+ if (whence == AVSEEK_SIZE)
+ return c->end - c->start;
+ switch (whence) {
+ case SEEK_SET:
+ new_pos = c->start + pos;
+ break;
+ case SEEK_CUR:
+ new_pos += pos;
+ break;
+ case SEEK_END:
+ new_pos = c->end + c->pos;
+ break;
+ }
+ if (new_pos < c->start)
+ return AVERROR(EINVAL);
+ c->pos = new_pos;
+ if ((ret = slave_seek(h)) < 0)
+ return ret;
+ return c->pos - c->start;
+}
+
+URLProtocol ff_subfile_protocol = {
+ .name = "subfile",
+ .url_open2 = subfile_open,
+ .url_read = subfile_read,
+ .url_seek = subfile_seek,
+ .url_close = subfile_close,
+ .priv_data_size = sizeof(SubfileContext),
+ .priv_data_class = &subfile_class,
+};
diff --git a/libavformat/subtitles.c b/libavformat/subtitles.c
new file mode 100644
index 0000000000..5bdbc8dc51
--- /dev/null
+++ b/libavformat/subtitles.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2012-2013 ClĂ©ment BÅ“sch <u pkh me>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "subtitles.h"
+#include "avio_internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/avstring.h"
+
+void ff_text_init_avio(void *s, FFTextReader *r, AVIOContext *pb)
+{
+ int i;
+ r->pb = pb;
+ r->buf_pos = r->buf_len = 0;
+ r->type = FF_UTF_8;
+ for (i = 0; i < 2; i++)
+ r->buf[r->buf_len++] = avio_r8(r->pb);
+ if (strncmp("\xFF\xFE", r->buf, 2) == 0) {
+ r->type = FF_UTF16LE;
+ r->buf_pos += 2;
+ } else if (strncmp("\xFE\xFF", r->buf, 2) == 0) {
+ r->type = FF_UTF16BE;
+ r->buf_pos += 2;
+ } else {
+ r->buf[r->buf_len++] = avio_r8(r->pb);
+ if (strncmp("\xEF\xBB\xBF", r->buf, 3) == 0) {
+ // UTF8
+ r->buf_pos += 3;
+ }
+ }
+ if (s && (r->type == FF_UTF16LE || r->type == FF_UTF16BE))
+ av_log(s, AV_LOG_INFO,
+ "UTF16 is automatically converted to UTF8, do not specify a character encoding\n");
+}
+
+void ff_text_init_buf(FFTextReader *r, void *buf, size_t size)
+{
+ memset(&r->buf_pb, 0, sizeof(r->buf_pb));
+ ffio_init_context(&r->buf_pb, buf, size, 0, NULL, NULL, NULL, NULL);
+ ff_text_init_avio(NULL, r, &r->buf_pb);
+}
+
+int64_t ff_text_pos(FFTextReader *r)
+{
+ return avio_tell(r->pb) - r->buf_len + r->buf_pos;
+}
+
+int ff_text_r8(FFTextReader *r)
+{
+ uint32_t val;
+ uint8_t tmp;
+ if (r->buf_pos < r->buf_len)
+ return r->buf[r->buf_pos++];
+ if (r->type == FF_UTF16LE) {
+ GET_UTF16(val, avio_rl16(r->pb), return 0;)
+ } else if (r->type == FF_UTF16BE) {
+ GET_UTF16(val, avio_rb16(r->pb), return 0;)
+ } else {
+ return avio_r8(r->pb);
+ }
+ if (!val)
+ return 0;
+ r->buf_pos = 0;
+ r->buf_len = 0;
+ PUT_UTF8(val, tmp, r->buf[r->buf_len++] = tmp;)
+ return r->buf[r->buf_pos++]; // buf_len is at least 1
+}
+
+void ff_text_read(FFTextReader *r, char *buf, size_t size)
+{
+ for ( ; size > 0; size--)
+ *buf++ = ff_text_r8(r);
+}
+
+int ff_text_eof(FFTextReader *r)
+{
+ return r->buf_pos >= r->buf_len && avio_feof(r->pb);
+}
+
+int ff_text_peek_r8(FFTextReader *r)
+{
+ int c;
+ if (r->buf_pos < r->buf_len)
+ return r->buf[r->buf_pos];
+ c = ff_text_r8(r);
+ if (!avio_feof(r->pb)) {
+ r->buf_pos = 0;
+ r->buf_len = 1;
+ r->buf[0] = c;
+ }
+ return c;
+}
+
+AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q,
+ const uint8_t *event, size_t len, int merge)
+{
+ AVPacket *subs, *sub;
+
+ 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);
+ } else {
+ /* new event */
+
+ if (q->nb_subs >= INT_MAX/sizeof(*q->subs) - 1)
+ return NULL;
+ subs = av_fast_realloc(q->subs, &q->allocated_size,
+ (q->nb_subs + 1) * sizeof(*q->subs));
+ if (!subs)
+ return NULL;
+ q->subs = subs;
+ sub = &subs[q->nb_subs++];
+ if (av_new_packet(sub, len) < 0)
+ return NULL;
+ sub->flags |= AV_PKT_FLAG_KEY;
+ sub->pts = sub->dts = 0;
+ memcpy(sub->data, event, len);
+ }
+ return sub;
+}
+
+static int cmp_pkt_sub_ts_pos(const void *a, const void *b)
+{
+ const AVPacket *s1 = a;
+ const AVPacket *s2 = b;
+ if (s1->pts == s2->pts) {
+ if (s1->pos == s2->pos)
+ return 0;
+ return s1->pos > s2->pos ? 1 : -1;
+ }
+ return s1->pts > s2->pts ? 1 : -1;
+}
+
+static int cmp_pkt_sub_pos_ts(const void *a, const void *b)
+{
+ const AVPacket *s1 = a;
+ const AVPacket *s2 = b;
+ if (s1->pos == s2->pos) {
+ if (s1->pts == s2->pts)
+ return 0;
+ return s1->pts > s2->pts ? 1 : -1;
+ }
+ return s1->pos > s2->pos ? 1 : -1;
+}
+
+void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q)
+{
+ int i;
+
+ qsort(q->subs, q->nb_subs, sizeof(*q->subs),
+ q->sort == SUB_SORT_TS_POS ? cmp_pkt_sub_ts_pos
+ : cmp_pkt_sub_pos_ts);
+ for (i = 0; i < q->nb_subs; i++)
+ if (q->subs[i].duration == -1 && i < q->nb_subs - 1)
+ q->subs[i].duration = q->subs[i + 1].pts - q->subs[i].pts;
+}
+
+int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt)
+{
+ AVPacket *sub = q->subs + q->current_sub_idx;
+
+ if (q->current_sub_idx == q->nb_subs)
+ return AVERROR_EOF;
+ if (av_copy_packet(pkt, sub) < 0) {
+ return AVERROR(ENOMEM);
+ }
+
+ pkt->dts = pkt->pts;
+ q->current_sub_idx++;
+ return 0;
+}
+
+static int search_sub_ts(const FFDemuxSubtitlesQueue *q, int64_t ts)
+{
+ int s1 = 0, s2 = q->nb_subs - 1;
+
+ if (s2 < s1)
+ return AVERROR(ERANGE);
+
+ for (;;) {
+ int mid;
+
+ if (s1 == s2)
+ return s1;
+ if (s1 == s2 - 1)
+ return q->subs[s1].pts <= q->subs[s2].pts ? s1 : s2;
+ mid = (s1 + s2) / 2;
+ if (q->subs[mid].pts <= ts)
+ s1 = mid;
+ else
+ s2 = mid;
+ }
+}
+
+int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ if (flags & AVSEEK_FLAG_BYTE) {
+ return AVERROR(ENOSYS);
+ } else if (flags & AVSEEK_FLAG_FRAME) {
+ if (ts < 0 || ts >= q->nb_subs)
+ return AVERROR(ERANGE);
+ q->current_sub_idx = ts;
+ } else {
+ int i, idx = search_sub_ts(q, ts);
+ int64_t ts_selected;
+
+ if (idx < 0)
+ return idx;
+ for (i = idx; i < q->nb_subs && q->subs[i].pts < min_ts; i++)
+ if (stream_index == -1 || q->subs[i].stream_index == stream_index)
+ idx = i;
+ for (i = idx; i > 0 && q->subs[i].pts > max_ts; i--)
+ if (stream_index == -1 || q->subs[i].stream_index == stream_index)
+ idx = i;
+
+ ts_selected = q->subs[idx].pts;
+ if (ts_selected < min_ts || ts_selected > max_ts)
+ return AVERROR(ERANGE);
+
+ /* look back in the latest subtitles for overlapping subtitles */
+ for (i = idx - 1; i >= 0; i--) {
+ int64_t pts = q->subs[i].pts;
+ if (q->subs[i].duration <= 0 ||
+ (stream_index != -1 && q->subs[i].stream_index != stream_index))
+ continue;
+ if (pts >= min_ts && pts > ts_selected - q->subs[i].duration)
+ idx = i;
+ else
+ break;
+ }
+
+ /* If the queue is used to store multiple subtitles streams (like with
+ * VobSub) and the stream index is not specified, we need to make sure
+ * to focus on the smallest file position offset for a same timestamp;
+ * queue is ordered by pts and then filepos, so we can take the first
+ * entry for a given timestamp. */
+ if (stream_index == -1)
+ while (idx > 0 && q->subs[idx - 1].pts == q->subs[idx].pts)
+ idx--;
+
+ q->current_sub_idx = idx;
+ }
+ return 0;
+}
+
+void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q)
+{
+ int i;
+
+ for (i = 0; i < q->nb_subs; i++)
+ av_free_packet(&q->subs[i]);
+ av_freep(&q->subs);
+ q->nb_subs = q->allocated_size = q->current_sub_idx = 0;
+}
+
+int ff_smil_extract_next_text_chunk(FFTextReader *tr, AVBPrint *buf, char *c)
+{
+ int i = 0;
+ char end_chr;
+
+ if (!*c) // cached char?
+ *c = ff_text_r8(tr);
+ if (!*c)
+ return 0;
+
+ end_chr = *c == '<' ? '>' : '<';
+ do {
+ av_bprint_chars(buf, *c, 1);
+ *c = ff_text_r8(tr);
+ i++;
+ } while (*c != end_chr && *c);
+ if (end_chr == '>') {
+ av_bprint_chars(buf, '>', 1);
+ *c = 0;
+ }
+ return i;
+}
+
+const char *ff_smil_get_attr_ptr(const char *s, const char *attr)
+{
+ int in_quotes = 0;
+ const size_t len = strlen(attr);
+
+ while (*s) {
+ while (*s) {
+ if (!in_quotes && av_isspace(*s))
+ break;
+ in_quotes ^= *s == '"'; // XXX: support escaping?
+ s++;
+ }
+ while (av_isspace(*s))
+ s++;
+ if (!av_strncasecmp(s, attr, len) && s[len] == '=')
+ return s + len + 1 + (s[len + 1] == '"');
+ }
+ return NULL;
+}
+
+static inline int is_eol(char c)
+{
+ return c == '\r' || c == '\n';
+}
+
+void ff_subtitles_read_text_chunk(FFTextReader *tr, AVBPrint *buf)
+{
+ char eol_buf[5], last_was_cr = 0;
+ int n = 0, i = 0, nb_eol = 0;
+
+ av_bprint_clear(buf);
+
+ for (;;) {
+ char c = ff_text_r8(tr);
+
+ if (!c)
+ break;
+
+ /* ignore all initial line breaks */
+ if (n == 0 && is_eol(c))
+ continue;
+
+ /* line break buffering: we don't want to add the trailing \r\n */
+ if (is_eol(c)) {
+ nb_eol += c == '\n' || last_was_cr;
+ if (nb_eol == 2)
+ break;
+ eol_buf[i++] = c;
+ if (i == sizeof(eol_buf) - 1)
+ break;
+ last_was_cr = c == '\r';
+ continue;
+ }
+
+ /* only one line break followed by data: we flush the line breaks
+ * buffer */
+ if (i) {
+ eol_buf[i] = 0;
+ av_bprintf(buf, "%s", eol_buf);
+ i = nb_eol = 0;
+ }
+
+ av_bprint_chars(buf, c, 1);
+ n++;
+ }
+}
+
+void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf)
+{
+ FFTextReader tr;
+ tr.buf_pos = tr.buf_len = 0;
+ tr.type = 0;
+ tr.pb = pb;
+ ff_subtitles_read_text_chunk(&tr, buf);
+}
+
+ptrdiff_t ff_subtitles_read_line(FFTextReader *tr, char *buf, size_t size)
+{
+ size_t cur = 0;
+ if (!size)
+ return 0;
+ while (cur + 1 < size) {
+ unsigned char c = ff_text_r8(tr);
+ if (!c)
+ return ff_text_eof(tr) ? cur : AVERROR_INVALIDDATA;
+ if (c == '\r' || c == '\n')
+ break;
+ buf[cur++] = c;
+ buf[cur] = '\0';
+ }
+ if (ff_text_peek_r8(tr) == '\r')
+ ff_text_r8(tr);
+ if (ff_text_peek_r8(tr) == '\n')
+ ff_text_r8(tr);
+ return cur;
+}
diff --git a/libavformat/subtitles.h b/libavformat/subtitles.h
new file mode 100644
index 0000000000..885285cc47
--- /dev/null
+++ b/libavformat/subtitles.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_SUBTITLES_H
+#define AVFORMAT_SUBTITLES_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "avformat.h"
+#include "libavutil/bprint.h"
+
+enum sub_sort {
+ SUB_SORT_TS_POS = 0, ///< sort by timestamps, then position
+ SUB_SORT_POS_TS, ///< sort by position, then timestamps
+};
+
+enum ff_utf_type {
+ FF_UTF_8, // or other 8 bit encodings
+ FF_UTF16LE,
+ FF_UTF16BE,
+};
+
+typedef struct {
+ int type;
+ AVIOContext *pb;
+ unsigned char buf[8];
+ int buf_pos, buf_len;
+ AVIOContext buf_pb;
+} FFTextReader;
+
+/**
+ * Initialize the FFTextReader from the given AVIOContext. This function will
+ * read some bytes from pb, and test for UTF-8 or UTF-16 BOMs. Further accesses
+ * to FFTextReader will read more data from pb.
+ * If s is not NULL, the user will be warned if a UTF-16 conversion takes place.
+ *
+ * The purpose of FFTextReader is to transparently convert read data to UTF-8
+ * if the stream had a UTF-16 BOM.
+ *
+ * @param s Pointer to provide av_log context
+ * @param r object which will be initialized
+ * @param pb stream to read from (referenced as long as FFTextReader is in use)
+ */
+void ff_text_init_avio(void *s, FFTextReader *r, AVIOContext *pb);
+
+/**
+ * Similar to ff_text_init_avio(), but sets it up to read from a bounded buffer.
+ *
+ * @param r object which will be initialized
+ * @param buf buffer to read from (referenced as long as FFTextReader is in use)
+ * @param size size of buf
+ */
+void ff_text_init_buf(FFTextReader *r, void *buf, size_t size);
+
+/**
+ * Return the byte position of the next byte returned by ff_text_r8(). For
+ * UTF-16 source streams, this will return the original position, but it will
+ * be incorrect if a codepoint was only partially read with ff_text_r8().
+ */
+int64_t ff_text_pos(FFTextReader *r);
+
+/**
+ * Return the next byte. The return value is always 0 - 255. Returns 0 on EOF.
+ * If the source stream is UTF-16, this reads from the stream converted to
+ * UTF-8. On invalid UTF-16, 0 is returned.
+ */
+int ff_text_r8(FFTextReader *r);
+
+/**
+ * Return non-zero if EOF was reached.
+ */
+int ff_text_eof(FFTextReader *r);
+
+/**
+ * Like ff_text_r8(), but don't remove the byte from the buffer.
+ */
+int ff_text_peek_r8(FFTextReader *r);
+
+/**
+ * Read the given number of bytes (in UTF-8). On error or EOF, \0 bytes are
+ * written.
+ */
+void ff_text_read(FFTextReader *r, char *buf, size_t size);
+
+typedef struct {
+ AVPacket *subs; ///< array of subtitles packets
+ int nb_subs; ///< number of subtitles packets
+ int allocated_size; ///< allocated size for subs
+ int current_sub_idx; ///< current position for the read packet callback
+ enum sub_sort sort; ///< sort method to use when finalizing subtitles
+} FFDemuxSubtitlesQueue;
+
+/**
+ * Insert a new subtitle event.
+ *
+ * @param event the subtitle line, may not be zero terminated
+ * @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
+ */
+AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q,
+ const uint8_t *event, size_t len, int merge);
+
+/**
+ * Set missing durations and sort subtitles by PTS, and then byte position.
+ */
+void ff_subtitles_queue_finalize(FFDemuxSubtitlesQueue *q);
+
+/**
+ * Generic read_packet() callback for subtitles demuxers using this queue
+ * system.
+ */
+int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt);
+
+/**
+ * Update current_sub_idx to emulate a seek. Except the first parameter, it
+ * matches AVInputFormat->read_seek2 prototypes.
+ */
+int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags);
+
+/**
+ * Remove and destroy all the subtitles packets.
+ */
+void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q);
+
+/**
+ * SMIL helper to load next chunk ("<...>" or untagged content) in buf.
+ *
+ * @param c cached character, to avoid a backward seek
+ */
+int ff_smil_extract_next_text_chunk(FFTextReader *tr, AVBPrint *buf, char *c);
+
+/**
+ * SMIL helper to point on the value of an attribute in the given tag.
+ *
+ * @param s SMIL tag ("<...>")
+ * @param attr the attribute to look for
+ */
+const char *ff_smil_get_attr_ptr(const char *s, const char *attr);
+
+/**
+ * @brief Same as ff_subtitles_read_text_chunk(), but read from an AVIOContext.
+ */
+void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf);
+
+/**
+ * @brief Read a subtitles chunk from FFTextReader.
+ *
+ * A chunk is defined by a multiline "event", ending with a second line break.
+ * The trailing line breaks are trimmed. CRLF are supported.
+ * Example: "foo\r\nbar\r\n\r\nnext" will print "foo\r\nbar" into buf, and pb
+ * will focus on the 'n' of the "next" string.
+ *
+ * @param tr I/O context
+ * @param buf an initialized buf where the chunk is written
+ *
+ * @note buf is cleared before writing into it.
+ */
+void ff_subtitles_read_text_chunk(FFTextReader *tr, AVBPrint *buf);
+
+/**
+ * Get the number of characters to increment to jump to the next line, or to
+ * the end of the string.
+ * The function handles the following line breaks schemes:
+ * LF, CRLF (MS), or standalone CR (old MacOS).
+ */
+static av_always_inline int ff_subtitles_next_line(const char *ptr)
+{
+ int n = strcspn(ptr, "\r\n");
+ ptr += n;
+ if (*ptr == '\r') {
+ ptr++;
+ n++;
+ }
+ if (*ptr == '\n')
+ n++;
+ return n;
+}
+
+/**
+ * Read a line of text. Discards line ending characters.
+ * The function handles the following line breaks schemes:
+ * LF, CRLF (MS), or standalone CR (old MacOS).
+ *
+ * Returns the number of bytes written to buf. Always writes a terminating 0,
+ * similar as with snprintf.
+ *
+ * @note returns a negative error code if a \0 byte is found
+ */
+ptrdiff_t ff_subtitles_read_line(FFTextReader *tr, char *buf, size_t size);
+
+#endif /* AVFORMAT_SUBTITLES_H */
diff --git a/libavformat/subviewer1dec.c b/libavformat/subviewer1dec.c
new file mode 100644
index 0000000000..6b38533a88
--- /dev/null
+++ b/libavformat/subviewer1dec.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * SubViewer v1 subtitle demuxer
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} SubViewer1Context;
+
+static int subviewer1_probe(AVProbeData *p)
+{
+ const unsigned char *ptr = p->buf;
+
+ if (strstr(ptr, "******** START SCRIPT ********"))
+ return AVPROBE_SCORE_EXTENSION;
+ return 0;
+}
+
+static int subviewer1_read_header(AVFormatContext *s)
+{
+ int delay = 0;
+ AVPacket *sub = NULL;
+ SubViewer1Context *subviewer1 = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_SUBVIEWER1;
+
+ while (!avio_feof(s->pb)) {
+ char line[4096];
+ int len = ff_get_line(s->pb, line, sizeof(line));
+ int hh, mm, ss;
+
+ if (!len)
+ break;
+
+ if (!strncmp(line, "[DELAY]", 7)) {
+ ff_get_line(s->pb, line, sizeof(line));
+ sscanf(line, "%d", &delay);
+ }
+
+ if (sscanf(line, "[%d:%d:%d]", &hh, &mm, &ss) == 3) {
+ const int64_t pos = avio_tell(s->pb);
+ int64_t pts_start = hh*3600LL + mm*60LL + ss + delay;
+
+ len = ff_get_line(s->pb, line, sizeof(line));
+ line[strcspn(line, "\r\n")] = 0;
+ if (!*line) {
+ if (sub)
+ sub->duration = pts_start - sub->pts;
+ } else {
+ sub = ff_subtitles_queue_insert(&subviewer1->q, line, len, 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ sub->pts = pts_start;
+ sub->duration = -1;
+ }
+ }
+ }
+
+ ff_subtitles_queue_finalize(&subviewer1->q);
+ return 0;
+}
+
+static int subviewer1_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ SubViewer1Context *subviewer1 = s->priv_data;
+ return ff_subtitles_queue_read_packet(&subviewer1->q, pkt);
+}
+
+static int subviewer1_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ SubViewer1Context *subviewer1 = s->priv_data;
+ return ff_subtitles_queue_seek(&subviewer1->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int subviewer1_read_close(AVFormatContext *s)
+{
+ SubViewer1Context *subviewer1 = s->priv_data;
+ ff_subtitles_queue_clean(&subviewer1->q);
+ return 0;
+}
+
+AVInputFormat ff_subviewer1_demuxer = {
+ .name = "subviewer1",
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer v1 subtitle format"),
+ .priv_data_size = sizeof(SubViewer1Context),
+ .read_probe = subviewer1_probe,
+ .read_header = subviewer1_read_header,
+ .read_packet = subviewer1_read_packet,
+ .read_seek2 = subviewer1_read_seek,
+ .read_close = subviewer1_read_close,
+ .extensions = "sub",
+};
diff --git a/libavformat/subviewerdec.c b/libavformat/subviewerdec.c
new file mode 100644
index 0000000000..f1b0fdf0a5
--- /dev/null
+++ b/libavformat/subviewerdec.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * SubViewer subtitle demuxer
+ * @see https://en.wikipedia.org/wiki/SubViewer
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavcodec/internal.h"
+#include "libavutil/avstring.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} SubViewerContext;
+
+static int subviewer_probe(AVProbeData *p)
+{
+ char c;
+ const unsigned char *ptr = p->buf;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+ if (sscanf(ptr, "%*u:%*u:%*u.%*u,%*u:%*u:%*u.%*u%c", &c) == 1)
+ return AVPROBE_SCORE_EXTENSION;
+ if (!strncmp(ptr, "[INFORMATION]", 13))
+ return AVPROBE_SCORE_MAX/3;
+ return 0;
+}
+
+static int read_ts(const char *s, int64_t *start, int *duration)
+{
+ int64_t end;
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+
+ if (sscanf(s, "%u:%u:%u.%u,%u:%u:%u.%u",
+ &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2) == 8) {
+ end = (hh2*3600LL + mm2*60LL + ss2) * 100LL + ms2;
+ *start = (hh1*3600LL + mm1*60LL + ss1) * 100LL + ms1;
+ *duration = end - *start;
+ return 0;
+ }
+ return -1;
+}
+
+static int subviewer_read_header(AVFormatContext *s)
+{
+ SubViewerContext *subviewer = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+ AVBPrint header;
+ int res = 0, new_event = 1;
+ int64_t pts_start = AV_NOPTS_VALUE;
+ int duration = -1;
+ AVPacket *sub = NULL;
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 100);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_SUBVIEWER;
+
+ av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ while (!avio_feof(s->pb)) {
+ char line[2048];
+ int64_t pos = 0;
+ int len = ff_get_line(s->pb, line, sizeof(line));
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ if (line[0] == '[' && strncmp(line, "[br]", 4)) {
+
+ /* ignore event style, XXX: add to side_data? */
+ if (strstr(line, "[COLF]") || strstr(line, "[SIZE]") ||
+ strstr(line, "[FONT]") || strstr(line, "[STYLE]"))
+ continue;
+
+ if (!st->codec->extradata) { // header not finalized yet
+ av_bprintf(&header, "%s\n", line);
+ if (!strncmp(line, "[END INFORMATION]", 17) || !strncmp(line, "[SUBTITLE]", 10)) {
+ /* end of header */
+ res = avpriv_bprint_to_extradata(st->codec, &header);
+ if (res < 0)
+ goto end;
+ } else if (strncmp(line, "[INFORMATION]", 13)) {
+ /* assume file metadata at this point */
+ int i, j = 0;
+ char key[32], value[128];
+
+ for (i = 1; i < sizeof(key) - 1 && line[i] && line[i] != ']'; i++)
+ key[i - 1] = av_tolower(line[i]);
+ key[i - 1] = 0;
+
+ if (line[i] == ']')
+ i++;
+ while (line[i] == ' ')
+ i++;
+ while (j < sizeof(value) - 1 && line[i] && line[i] != ']')
+ value[j++] = line[i++];
+ value[j] = 0;
+
+ av_dict_set(&s->metadata, key, value, 0);
+ }
+ }
+ } else if (read_ts(line, &pts_start, &duration) >= 0) {
+ new_event = 1;
+ pos = avio_tell(s->pb);
+ } else if (*line) {
+ if (!new_event) {
+ sub = ff_subtitles_queue_insert(&subviewer->q, "\n", 1, 1);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ }
+ sub = ff_subtitles_queue_insert(&subviewer->q, line, strlen(line), !new_event);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ if (new_event) {
+ sub->pos = pos;
+ sub->pts = pts_start;
+ sub->duration = duration;
+ }
+ new_event = 0;
+ }
+ }
+
+ ff_subtitles_queue_finalize(&subviewer->q);
+
+end:
+ av_bprint_finalize(&header, NULL);
+ return res;
+}
+
+static int subviewer_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ SubViewerContext *subviewer = s->priv_data;
+ return ff_subtitles_queue_read_packet(&subviewer->q, pkt);
+}
+
+static int subviewer_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ SubViewerContext *subviewer = s->priv_data;
+ return ff_subtitles_queue_seek(&subviewer->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int subviewer_read_close(AVFormatContext *s)
+{
+ SubViewerContext *subviewer = s->priv_data;
+ ff_subtitles_queue_clean(&subviewer->q);
+ return 0;
+}
+
+AVInputFormat ff_subviewer_demuxer = {
+ .name = "subviewer",
+ .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle format"),
+ .priv_data_size = sizeof(SubViewerContext),
+ .read_probe = subviewer_probe,
+ .read_header = subviewer_read_header,
+ .read_packet = subviewer_read_packet,
+ .read_seek2 = subviewer_read_seek,
+ .read_close = subviewer_read_close,
+ .extensions = "sub",
+};
diff --git a/libavformat/supdec.c b/libavformat/supdec.c
new file mode 100644
index 0000000000..48083b2c53
--- /dev/null
+++ b/libavformat/supdec.c
@@ -0,0 +1,109 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "avformat.h"
+#include "internal.h"
+#include "libavutil/intreadwrite.h"
+
+#define SUP_PGS_MAGIC 0x5047 /* "PG", big endian */
+
+static int sup_read_header(AVFormatContext *s)
+{
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_HDMV_PGS_SUBTITLE;
+ avpriv_set_pts_info(st, 32, 1, 90000);
+
+ return 0;
+}
+
+static int sup_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ int64_t pts, dts, pos;
+ int ret;
+
+ pos = avio_tell(s->pb);
+
+ if (avio_rb16(s->pb) != SUP_PGS_MAGIC)
+ return avio_feof(s->pb) ? AVERROR_EOF : AVERROR_INVALIDDATA;
+
+ pts = avio_rb32(s->pb);
+ dts = avio_rb32(s->pb);
+
+ if ((ret = av_get_packet(s->pb, pkt, 3)) < 0)
+ return ret;
+
+ pkt->stream_index = 0;
+ pkt->flags |= AV_PKT_FLAG_KEY;
+ pkt->pos = pos;
+ pkt->pts = pts;
+ // Many files have DTS set to 0 for all packets, so assume 0 means unset.
+ pkt->dts = dts ? dts : AV_NOPTS_VALUE;
+
+ if (pkt->size >= 3) {
+ // The full packet size is stored as part of the packet.
+ size_t len = AV_RB16(pkt->data + 1);
+
+ if ((ret = av_append_packet(s->pb, pkt, len)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sup_probe(AVProbeData *p)
+{
+ unsigned char *buf = p->buf;
+ size_t buf_size = p->buf_size;
+ int nb_packets;
+
+ for (nb_packets = 0; nb_packets < 10; nb_packets++) {
+ size_t full_packet_size;
+ if (buf_size < 10 + 3)
+ break;
+ if (AV_RB16(buf) != SUP_PGS_MAGIC)
+ return 0;
+ full_packet_size = AV_RB16(buf + 10 + 1) + 10 + 3;
+ if (buf_size < full_packet_size)
+ break;
+ buf += full_packet_size;
+ buf_size -= full_packet_size;
+ }
+ if (!nb_packets)
+ return 0;
+ if (nb_packets < 2)
+ return AVPROBE_SCORE_RETRY / 2;
+ if (nb_packets < 4)
+ return AVPROBE_SCORE_RETRY;
+ if (nb_packets < 10)
+ return AVPROBE_SCORE_EXTENSION;
+ return AVPROBE_SCORE_MAX;
+}
+
+AVInputFormat ff_sup_demuxer = {
+ .name = "sup",
+ .long_name = NULL_IF_CONFIG_SMALL("raw HDMV Presentation Graphic Stream subtitles"),
+ .extensions = "sup",
+ .mime_type = "application/x-pgs",
+ .read_probe = sup_probe,
+ .read_header = sup_read_header,
+ .read_packet = sup_read_packet,
+ .flags = AVFMT_GENERIC_INDEX,
+};
diff --git a/libavformat/swf.c b/libavformat/swf.c
index e6adf69c02..1aa434a0ea 100644
--- a/libavformat/swf.c
+++ b/libavformat/swf.c
@@ -3,20 +3,20 @@
* Copyright (c) 2000 Fabrice Bellard
* Copyright (c) 2003 Tinic Uro
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/swf.h b/libavformat/swf.h
index 8eb3f70541..93a094c26d 100644
--- a/libavformat/swf.h
+++ b/libavformat/swf.h
@@ -3,26 +3,32 @@
* Copyright (c) 2000 Fabrice Bellard
* Copyright (c) 2003 Tinic Uro
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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_SWF_H
#define AVFORMAT_SWF_H
+#include "config.h"
+
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
#include "libavutil/fifo.h"
#include "avformat.h"
#include "avio.h"
@@ -32,20 +38,73 @@
#define DUMMY_FILE_SIZE (100 * 1024 * 1024)
#define DUMMY_DURATION 600 /* in seconds */
-#define TAG_END 0
-#define TAG_SHOWFRAME 1
-#define TAG_DEFINESHAPE 2
-#define TAG_FREECHARACTER 3
-#define TAG_PLACEOBJECT 4
-#define TAG_REMOVEOBJECT 5
-#define TAG_STREAMHEAD 18
-#define TAG_STREAMBLOCK 19
-#define TAG_JPEG2 21
-#define TAG_PLACEOBJECT2 26
-#define TAG_STREAMHEAD2 45
-#define TAG_VIDEOSTREAM 60
-#define TAG_VIDEOFRAME 61
-#define TAG_FILEATTRIBUTES 69
+enum {
+ TAG_END = 0,
+ TAG_SHOWFRAME = 1,
+ TAG_DEFINESHAPE = 2,
+ TAG_FREECHARACTER = 3,
+ TAG_PLACEOBJECT = 4,
+ TAG_REMOVEOBJECT = 5,
+ TAG_DEFINEBITS = 6,
+ TAG_DEFINEBUTTON = 7,
+ TAG_JPEGTABLES = 8,
+ TAG_SETBACKGROUNDCOLOR = 9,
+ TAG_DEFINEFONT = 10,
+ TAG_DEFINETEXT = 11,
+ TAG_DOACTION = 12,
+ TAG_DEFINEFONTINFO = 13,
+ TAG_DEFINESOUND = 14,
+ TAG_STARTSOUND = 15,
+ TAG_DEFINEBUTTONSOUND = 17,
+ TAG_STREAMHEAD = 18,
+ TAG_STREAMBLOCK = 19,
+ TAG_DEFINEBITSLOSSLESS = 20,
+ TAG_JPEG2 = 21,
+ TAG_DEFINESHAPE2 = 22,
+ TAG_DEFINEBUTTONCXFORM = 23,
+ TAG_PROTECT = 24,
+ TAG_PLACEOBJECT2 = 26,
+ TAG_REMOVEOBJECT2 = 28,
+ TAG_DEFINESHAPE3 = 32,
+ TAG_DEFINETEXT2 = 33,
+ TAG_DEFINEBUTTON2 = 34,
+ TAG_DEFINEBITSJPEG3 = 35,
+ TAG_DEFINEBITSLOSSLESS2 = 36,
+ TAG_DEFINEEDITTEXT = 37,
+ TAG_DEFINESPRITE = 39,
+ TAG_FRAMELABEL = 43,
+ TAG_STREAMHEAD2 = 45,
+ TAG_DEFINEMORPHSHAPE = 46,
+ TAG_DEFINEFONT2 = 48,
+ TAG_EXPORTASSETS = 56,
+ TAG_IMPORTASSETS = 57,
+ TAG_ENABLEDEBUGGER = 58,
+ TAG_DOINITACTION = 59,
+ TAG_VIDEOSTREAM = 60,
+ TAG_VIDEOFRAME = 61,
+ TAG_DEFINEFONTINFO2 = 62,
+ TAG_ENABLEDEBUGGER2 = 64,
+ TAG_SCRIPTLIMITS = 65,
+ TAG_SETTABINDEX = 66,
+ TAG_FILEATTRIBUTES = 69,
+ TAG_PLACEOBJECT3 = 70,
+ TAG_IMPORTASSETS2 = 71,
+ TAG_DEFINEFONTALIGNZONES = 73,
+ TAG_CSMTEXTSETTINGS = 74,
+ TAG_DEFINEFONT3 = 75,
+ TAG_SYMBOLCLASS = 76,
+ TAG_METADATA = 77,
+ TAG_DEFINESCALINGGRID = 78,
+ TAG_DOABC = 82,
+ TAG_DEFINESHAPE4 = 83,
+ TAG_DEFINEMORPHSHAPE2 = 84,
+ TAG_DEFINESCENEANDFRAMELABELDATA = 86,
+ TAG_DEFINEBINARYDATA = 87,
+ TAG_DEFINEFONTNAME = 88,
+ TAG_STARTSOUND2 = 89,
+ TAG_DEFINEBITSJPEG4 = 90,
+ TAG_DEFINEFONT4 = 91,
+};
#define TAG_LONG 0x100
@@ -61,9 +120,6 @@
#define VIDEO_ID 0
#define SHAPE_ID 1
-#undef NDEBUG
-#include <assert.h>
-
typedef struct SWFContext {
int64_t duration_pos;
int64_t tag_pos;
@@ -77,6 +133,13 @@ typedef struct SWFContext {
AVFifoBuffer *audio_fifo;
AVCodecContext *audio_enc, *video_enc;
AVStream *video_st;
+#if CONFIG_ZLIB
+ AVIOContext *zpb;
+#define ZBUF_SIZE 4096
+ uint8_t *zbuf_in;
+ uint8_t *zbuf_out;
+ z_stream zstream;
+#endif
} SWFContext;
extern const AVCodecTag ff_swf_codec_tags[];
diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c
index d7a53145c6..d34d3d90df 100644
--- a/libavformat/swfdec.c
+++ b/libavformat/swfdec.c
@@ -3,25 +3,28 @@
* Copyright (c) 2000 Fabrice Bellard
* Copyright (c) 2003 Tinic Uro
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/channel_layout.h"
+#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
+#include "libavcodec/get_bits.h"
#include "swf.h"
static const AVCodecTag swf_audio_codec_tags[] = {
@@ -37,8 +40,8 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr)
{
int tag, len;
- if (pb->eof_reached)
- return -1;
+ if (avio_feof(pb))
+ return AVERROR_EOF;
tag = avio_rl16(pb);
len = tag & 0x3f;
@@ -53,13 +56,68 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr)
static int swf_probe(AVProbeData *p)
{
+ GetBitContext gb;
+ int len, xmin, xmax, ymin, ymax;
+
+ if(p->buf_size < 15)
+ return 0;
+
/* check file header */
- if ((p->buf[0] == 'F' || p->buf[0] == 'C') && p->buf[1] == 'W' &&
- p->buf[2] == 'S')
- return AVPROBE_SCORE_MAX;
- else
+ if ( AV_RB24(p->buf) != AV_RB24("CWS")
+ && AV_RB24(p->buf) != AV_RB24("FWS"))
+ return 0;
+
+ init_get_bits8(&gb, p->buf + 3, p->buf_size - 3);
+
+ skip_bits(&gb, 40);
+ len = get_bits(&gb, 5);
+ if (!len)
return 0;
+ xmin = get_bits_long(&gb, len);
+ xmax = get_bits_long(&gb, len);
+ ymin = get_bits_long(&gb, len);
+ ymax = get_bits_long(&gb, len);
+ if (xmin || ymin || !xmax || !ymax)
+ return 0;
+
+ if (p->buf[3] >= 20 || xmax < 16 || ymax < 16)
+ return AVPROBE_SCORE_MAX / 4;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+#if CONFIG_ZLIB
+static int zlib_refill(void *opaque, uint8_t *buf, int buf_size)
+{
+ AVFormatContext *s = opaque;
+ SWFContext *swf = s->priv_data;
+ z_stream *z = &swf->zstream;
+ int ret;
+
+retry:
+ if (!z->avail_in) {
+ int n = avio_read(s->pb, swf->zbuf_in, ZBUF_SIZE);
+ if (n < 0)
+ return n;
+ z->next_in = swf->zbuf_in;
+ z->avail_in = n;
+ }
+
+ z->next_out = buf;
+ z->avail_out = buf_size;
+
+ ret = inflate(z, Z_NO_FLUSH);
+ if (ret < 0)
+ return AVERROR(EINVAL);
+ if (ret == Z_STREAM_END)
+ return AVERROR_EOF;
+
+ if (buf_size - z->avail_out == 0)
+ goto retry;
+
+ return buf_size - z->avail_out;
}
+#endif
static int swf_read_header(AVFormatContext *s)
{
@@ -68,14 +126,29 @@ static int swf_read_header(AVFormatContext *s)
int nbits, len, tag;
tag = avio_rb32(pb) & 0xffffff00;
+ avio_rl32(pb);
if (tag == MKBETAG('C', 'W', 'S', 0)) {
- av_log(s, AV_LOG_ERROR, "Compressed SWF format not supported\n");
+ av_log(s, AV_LOG_INFO, "SWF compressed file detected\n");
+#if CONFIG_ZLIB
+ swf->zbuf_in = av_malloc(ZBUF_SIZE);
+ swf->zbuf_out = av_malloc(ZBUF_SIZE);
+ swf->zpb = avio_alloc_context(swf->zbuf_out, ZBUF_SIZE, 0, s,
+ zlib_refill, NULL, NULL);
+ if (!swf->zbuf_in || !swf->zbuf_out || !swf->zpb)
+ return AVERROR(ENOMEM);
+ swf->zpb->seekable = 0;
+ if (inflateInit(&swf->zstream) != Z_OK) {
+ av_log(s, AV_LOG_ERROR, "Unable to init zlib context\n");
+ return AVERROR(EINVAL);
+ }
+ pb = swf->zpb;
+#else
+ av_log(s, AV_LOG_ERROR, "zlib support is required to read SWF compressed files\n");
return AVERROR(EIO);
- }
- if (tag != MKBETAG('F', 'W', 'S', 0))
+#endif
+ } else if (tag != MKBETAG('F', 'W', 'S', 0))
return AVERROR(EIO);
- avio_rl32(pb);
/* skip rectangle size */
nbits = avio_r8(pb) >> 3;
len = (4 * nbits - 3 + 7) / 8;
@@ -88,6 +161,32 @@ static int swf_read_header(AVFormatContext *s)
return 0;
}
+static AVStream *create_new_audio_stream(AVFormatContext *s, int id, int info)
+{
+ int sample_rate_code, sample_size_code;
+ AVStream *ast = avformat_new_stream(s, NULL);
+ if (!ast)
+ return NULL;
+ ast->id = id;
+ if (info & 1) {
+ ast->codec->channels = 2;
+ ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ } else {
+ ast->codec->channels = 1;
+ ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ }
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->codec_id = ff_codec_get_id(swf_audio_codec_tags, info>>4 & 15);
+ ast->need_parsing = AVSTREAM_PARSE_FULL;
+ sample_rate_code = info>>2 & 3;
+ sample_size_code = info>>1 & 1;
+ if (!sample_size_code && ast->codec->codec_id == AV_CODEC_ID_PCM_S16LE)
+ ast->codec->codec_id = AV_CODEC_ID_PCM_U8;
+ ast->codec->sample_rate = 44100 >> (3 - sample_rate_code);
+ avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
+ return ast;
+}
+
static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
{
SWFContext *swf = s->priv_data;
@@ -95,11 +194,16 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *vst = NULL, *ast = NULL, *st = 0;
int tag, len, i, frame, v, res;
+#if CONFIG_ZLIB
+ if (swf->zpb)
+ pb = swf->zpb;
+#endif
+
for(;;) {
uint64_t pos = avio_tell(pb);
tag = get_swf_tag(pb, &len);
if (tag < 0)
- return AVERROR(EIO);
+ return tag;
if (len < 0) {
av_log(s, AV_LOG_ERROR, "invalid tag length: %d\n", len);
return AVERROR_INVALIDDATA;
@@ -121,7 +225,7 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
/* Check for FLV1 */
vst = avformat_new_stream(s, NULL);
if (!vst)
- return -1;
+ return AVERROR(ENOMEM);
vst->id = ch_id;
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = ff_codec_get_id(ff_swf_codec_tags, avio_r8(pb));
@@ -129,7 +233,6 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
len -= 8;
} else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
/* streaming found */
- int sample_rate_code;
for (i=0; i<s->nb_streams; i++) {
st = s->streams[i];
@@ -140,24 +243,38 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
avio_r8(pb);
v = avio_r8(pb);
swf->samples_per_frame = avio_rl16(pb);
- ast = avformat_new_stream(s, NULL);
+ ast = create_new_audio_stream(s, -1, v); /* -1 to avoid clash with video stream ch_id */
if (!ast)
- return -1;
- ast->id = -1; /* -1 to avoid clash with video stream ch_id */
- if (v & 1) {
- ast->codec->channels = 2;
- ast->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- } else {
- ast->codec->channels = 1;
- ast->codec->channel_layout = AV_CH_LAYOUT_MONO;
- }
- ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- ast->codec->codec_id = ff_codec_get_id(swf_audio_codec_tags, (v>>4) & 15);
- ast->need_parsing = AVSTREAM_PARSE_FULL;
- sample_rate_code= (v>>2) & 3;
- ast->codec->sample_rate = 44100 >> (3 - sample_rate_code);
- avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
+ return AVERROR(ENOMEM);
len -= 4;
+ } else if (tag == TAG_DEFINESOUND) {
+ /* audio stream */
+ int ch_id = avio_rl16(pb);
+
+ for (i=0; i<s->nb_streams; i++) {
+ st = s->streams[i];
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO && st->id == ch_id)
+ goto skip;
+ }
+
+ // FIXME: The entire audio stream is stored in a single chunk/tag. Normally,
+ // these are smaller audio streams in DEFINESOUND tags, but it's technically
+ // possible they could be huge. Break it up into multiple packets if it's big.
+ v = avio_r8(pb);
+ ast = create_new_audio_stream(s, ch_id, v);
+ if (!ast)
+ return AVERROR(ENOMEM);
+ ast->duration = avio_rl32(pb); // number of samples
+ if (((v>>4) & 15) == 2) { // MP3 sound data record
+ ast->skip_samples = avio_rl16(pb);
+ len -= 2;
+ }
+ len -= 7;
+ if ((res = av_get_packet(pb, pkt, len)) < 0)
+ return res;
+ pkt->pos = pos;
+ pkt->stream_index = ast->index;
+ return pkt->size;
} else if (tag == TAG_VIDEOFRAME) {
int ch_id = avio_rl16(pb);
len -= 2;
@@ -176,6 +293,143 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
return pkt->size;
}
}
+ } else if (tag == TAG_DEFINEBITSLOSSLESS || tag == TAG_DEFINEBITSLOSSLESS2) {
+#if CONFIG_ZLIB
+ long out_len;
+ uint8_t *buf = NULL, *zbuf = NULL, *pal;
+ uint32_t colormap[AVPALETTE_COUNT] = {0};
+ const int alpha_bmp = tag == TAG_DEFINEBITSLOSSLESS2;
+ const int colormapbpp = 3 + alpha_bmp;
+ int linesize, colormapsize = 0;
+
+ const int ch_id = avio_rl16(pb);
+ const int bmp_fmt = avio_r8(pb);
+ const int width = avio_rl16(pb);
+ const int height = avio_rl16(pb);
+ int pix_fmt;
+
+ len -= 2+1+2+2;
+
+ switch (bmp_fmt) {
+ case 3: // PAL-8
+ linesize = width;
+ colormapsize = avio_r8(pb) + 1;
+ len--;
+ break;
+ case 4: // RGB15
+ linesize = width * 2;
+ break;
+ case 5: // RGB24 (0RGB)
+ linesize = width * 4;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "invalid bitmap format %d, skipped\n", bmp_fmt);
+ goto bitmap_end_skip;
+ }
+
+ linesize = FFALIGN(linesize, 4);
+
+ if (av_image_check_size(width, height, 0, s) < 0 ||
+ linesize >= INT_MAX / height ||
+ linesize * height >= INT_MAX - colormapsize * colormapbpp) {
+ av_log(s, AV_LOG_ERROR, "invalid frame size %dx%d\n", width, height);
+ goto bitmap_end_skip;
+ }
+
+ out_len = colormapsize * colormapbpp + linesize * height;
+
+ av_dlog(s, "bitmap: ch=%d fmt=%d %dx%d (linesize=%d) len=%d->%ld pal=%d\n",
+ ch_id, bmp_fmt, width, height, linesize, len, out_len, colormapsize);
+
+ zbuf = av_malloc(len);
+ buf = av_malloc(out_len);
+ if (!zbuf || !buf) {
+ res = AVERROR(ENOMEM);
+ goto bitmap_end;
+ }
+
+ len = avio_read(pb, zbuf, len);
+ if (len < 0 || (res = uncompress(buf, &out_len, zbuf, len)) != Z_OK) {
+ av_log(s, AV_LOG_WARNING, "Failed to uncompress one bitmap\n");
+ goto bitmap_end_skip;
+ }
+
+ for (i = 0; i < s->nb_streams; i++) {
+ st = s->streams[i];
+ if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && st->id == -3)
+ break;
+ }
+ if (i == s->nb_streams) {
+ vst = avformat_new_stream(s, NULL);
+ if (!vst) {
+ res = AVERROR(ENOMEM);
+ goto bitmap_end;
+ }
+ vst->id = -3; /* -3 to avoid clash with video stream and audio stream */
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
+ st = vst;
+ }
+
+ if ((res = av_new_packet(pkt, out_len - colormapsize * colormapbpp)) < 0)
+ goto bitmap_end;
+ if (!st->codec->width && !st->codec->height) {
+ st->codec->width = width;
+ st->codec->height = height;
+ } else {
+ ff_add_param_change(pkt, 0, 0, 0, width, height);
+ }
+ pkt->pos = pos;
+ pkt->stream_index = st->index;
+
+ switch (bmp_fmt) {
+ case 3:
+ pix_fmt = AV_PIX_FMT_PAL8;
+ for (i = 0; i < colormapsize; i++)
+ if (alpha_bmp) colormap[i] = buf[3]<<24 | AV_RB24(buf + 4*i);
+ else colormap[i] = 0xffU <<24 | AV_RB24(buf + 3*i);
+ pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+ if (!pal) {
+ res = AVERROR(ENOMEM);
+ goto bitmap_end;
+ }
+ memcpy(pal, colormap, AVPALETTE_SIZE);
+ break;
+ case 4:
+ pix_fmt = AV_PIX_FMT_RGB555;
+ break;
+ case 5:
+ pix_fmt = alpha_bmp ? AV_PIX_FMT_ARGB : AV_PIX_FMT_0RGB;
+ break;
+ default:
+ av_assert0(0);
+ }
+ if (st->codec->pix_fmt != AV_PIX_FMT_NONE && st->codec->pix_fmt != pix_fmt) {
+ av_log(s, AV_LOG_ERROR, "pixel format change unsupported\n");
+ res = AVERROR_PATCHWELCOME;
+ goto bitmap_end;
+ }
+ st->codec->pix_fmt = pix_fmt;
+
+ if (linesize * height > pkt->size) {
+ res = AVERROR_INVALIDDATA;
+ goto bitmap_end;
+ }
+ memcpy(pkt->data, buf + colormapsize*colormapbpp, linesize * height);
+
+ res = pkt->size;
+
+bitmap_end:
+ av_freep(&zbuf);
+ av_freep(&buf);
+ return res;
+bitmap_end_skip:
+ av_freep(&zbuf);
+ av_freep(&buf);
+#else
+ av_log(s, AV_LOG_ERROR, "this file requires zlib support compiled in\n");
+#endif
} else if (tag == TAG_STREAMBLOCK) {
for (i = 0; i < s->nb_streams; i++) {
st = s->streams[i];
@@ -207,7 +461,7 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
if (i == s->nb_streams) {
vst = avformat_new_stream(s, NULL);
if (!vst)
- return -1;
+ return AVERROR(ENOMEM);
vst->id = -2; /* -2 to avoid clash with video stream and audio stream */
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = AV_CODEC_ID_MJPEG;
@@ -220,26 +474,56 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
goto skip;
if ((res = av_new_packet(pkt, len)) < 0)
return res;
- avio_read(pb, pkt->data, 4);
+ if (avio_read(pb, pkt->data, 4) != 4) {
+ av_free_packet(pkt);
+ return AVERROR_INVALIDDATA;
+ }
if (AV_RB32(pkt->data) == 0xffd8ffd9 ||
AV_RB32(pkt->data) == 0xffd9ffd8) {
/* old SWF files containing SOI/EOI as data start */
/* files created by swink have reversed tag */
pkt->size -= 4;
- avio_read(pb, pkt->data, pkt->size);
+ memset(pkt->data+pkt->size, 0, 4);
+ res = avio_read(pb, pkt->data, pkt->size);
} else {
- avio_read(pb, pkt->data + 4, pkt->size - 4);
+ res = avio_read(pb, pkt->data + 4, pkt->size - 4);
+ if (res >= 0)
+ res += 4;
+ }
+ if (res != pkt->size) {
+ if (res < 0) {
+ av_free_packet(pkt);
+ return res;
+ }
+ av_shrink_packet(pkt, res);
}
+
pkt->pos = pos;
pkt->stream_index = st->index;
return pkt->size;
+ } else {
+ av_log(s, AV_LOG_DEBUG, "Unknown tag: %d\n", tag);
}
skip:
+ if(len<0)
+ av_log(s, AV_LOG_WARNING, "Cliping len %d\n", len);
len = FFMAX(0, len);
avio_skip(pb, len);
}
}
+#if CONFIG_ZLIB
+static av_cold int swf_read_close(AVFormatContext *avctx)
+{
+ SWFContext *s = avctx->priv_data;
+ inflateEnd(&s->zstream);
+ av_freep(&s->zbuf_in);
+ av_freep(&s->zbuf_out);
+ av_freep(&s->zpb);
+ return 0;
+}
+#endif
+
AVInputFormat ff_swf_demuxer = {
.name = "swf",
.long_name = NULL_IF_CONFIG_SMALL("SWF (ShockWave Flash)"),
@@ -247,4 +531,7 @@ AVInputFormat ff_swf_demuxer = {
.read_probe = swf_probe,
.read_header = swf_read_header,
.read_packet = swf_read_packet,
+#if CONFIG_ZLIB
+ .read_close = swf_read_close,
+#endif
};
diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c
index 877c847acb..56d9879017 100644
--- a/libavformat/swfenc.c
+++ b/libavformat/swfenc.c
@@ -3,24 +3,25 @@
* Copyright (c) 2000 Fabrice Bellard
* Copyright (c) 2003 Tinic Uro
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/put_bits.h"
+#include "libavutil/avassert.h"
#include "avformat.h"
#include "swf.h"
@@ -56,7 +57,7 @@ static void put_swf_end_tag(AVFormatContext *s)
avio_wl16(pb, (tag << 6) | 0x3f);
avio_wl32(pb, tag_len - 4);
} else {
- assert(tag_len < 0x3f);
+ av_assert0(tag_len < 0x3f);
avio_wl16(pb, (tag << 6) | tag_len);
}
avio_seek(pb, pos, SEEK_SET);
@@ -191,6 +192,10 @@ static int swf_write_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
if (enc->codec_id == AV_CODEC_ID_MP3) {
+ if (!enc->frame_size) {
+ av_log(s, AV_LOG_ERROR, "audio frame size not set\n");
+ return -1;
+ }
swf->audio_enc = enc;
swf->audio_fifo= av_fifo_alloc(AUDIO_FIFO_SIZE);
if (!swf->audio_fifo)
@@ -231,7 +236,7 @@ static int swf_write_header(AVFormatContext *s)
}
if (!swf->audio_enc)
- swf->samples_per_frame = (44100.0 * rate_base) / rate;
+ swf->samples_per_frame = (44100LL * rate_base) / rate;
else
swf->samples_per_frame = (swf->audio_enc->sample_rate * rate_base) / rate;
@@ -274,8 +279,8 @@ static int swf_write_header(AVFormatContext *s)
avio_w8(pb, 0x41); /* clipped bitmap fill */
avio_wl16(pb, BITMAP_ID); /* bitmap ID */
/* position of the bitmap */
- put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0,
- 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0);
+ put_swf_matrix(pb, 1 << FRAC_BITS, 0,
+ 0, 1 << FRAC_BITS, 0, 0);
avio_w8(pb, 0); /* no line style */
/* shape drawing */
@@ -427,8 +432,7 @@ static int swf_write_video(AVFormatContext *s,
put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG);
avio_wl16(pb, swf->sound_samples);
avio_wl16(pb, 0); // seek samples
- av_fifo_generic_read(swf->audio_fifo, pb, frame_size,
- (void (*)(void *, void *, int)) &avio_write);
+ av_fifo_generic_read(swf->audio_fifo, pb, frame_size, (void*)avio_write);
put_swf_end_tag(s);
/* update FIFO */
@@ -457,7 +461,7 @@ static int swf_write_audio(AVFormatContext *s,
}
av_fifo_generic_write(swf->audio_fifo, buf, size, NULL);
- swf->sound_samples += av_get_audio_frame_duration(enc, size);
+ swf->sound_samples += enc->frame_size;
/* if audio only stream make sure we add swf frames */
if (!swf->video_enc)
@@ -487,8 +491,9 @@ static int swf_write_trailer(AVFormatContext *s)
enc = s->streams[i]->codec;
if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
video_enc = enc;
- else
- av_fifo_free(swf->audio_fifo);
+ else {
+ av_fifo_freep(&swf->audio_fifo);
+ }
}
put_swf_tag(s, TAG_END);
@@ -501,8 +506,10 @@ static int swf_write_trailer(AVFormatContext *s)
avio_wl32(pb, file_size);
avio_seek(pb, swf->duration_pos, SEEK_SET);
avio_wl16(pb, swf->video_frame_number);
+ if (swf->vframes_pos) {
avio_seek(pb, swf->vframes_pos, SEEK_SET);
avio_wl16(pb, swf->video_frame_number);
+ }
avio_seek(pb, file_size, SEEK_SET);
}
return 0;
diff --git a/libavformat/takdec.c b/libavformat/takdec.c
index 584cbccb50..3eb1a8ec2d 100644
--- a/libavformat/takdec.c
+++ b/libavformat/takdec.c
@@ -2,25 +2,27 @@
* Raw TAK demuxer
* Copyright (c) 2012 Paul B Mahol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/crc.h"
#include "libavcodec/tak.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "rawdec.h"
#include "apetag.h"
@@ -37,6 +39,12 @@ static int tak_probe(AVProbeData *p)
return 0;
}
+static unsigned long tak_check_crc(unsigned long checksum, const uint8_t *buf,
+ unsigned int len)
+{
+ return av_crc(av_crc_get_table(AV_CRC_24_IEEE), checksum, buf, len);
+}
+
static int tak_read_header(AVFormatContext *s)
{
TAKDemuxContext *tc = s->priv_data;
@@ -52,7 +60,7 @@ static int tak_read_header(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_TAK;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
tc->mlast_frame = 0;
if (avio_rl32(pb) != MKTAG('t', 'B', 'a', 'K')) {
@@ -60,7 +68,7 @@ static int tak_read_header(AVFormatContext *s)
return 0;
}
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
enum TAKMetaDataType type;
int size;
@@ -71,16 +79,28 @@ static int tak_read_header(AVFormatContext *s)
case TAK_METADATA_STREAMINFO:
case TAK_METADATA_LAST_FRAME:
case TAK_METADATA_ENCODER:
- buffer = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (size <= 3)
+ return AVERROR_INVALIDDATA;
+
+ buffer = av_malloc(size - 3 + FF_INPUT_BUFFER_PADDING_SIZE);
if (!buffer)
return AVERROR(ENOMEM);
+ memset(buffer + size - 3, 0, FF_INPUT_BUFFER_PADDING_SIZE);
- if (avio_read(pb, buffer, size) != size) {
+ ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U);
+ if (avio_read(pb, buffer, size - 3) != size - 3) {
av_freep(&buffer);
return AVERROR(EIO);
}
+ if (ffio_get_checksum(s->pb) != avio_rb24(pb)) {
+ av_log(s, AV_LOG_ERROR, "%d metadata block CRC error.\n", type);
+ if (s->error_recognition & AV_EF_EXPLODE) {
+ av_freep(&buffer);
+ return AVERROR_INVALIDDATA;
+ }
+ }
- init_get_bits(&gb, buffer, size * 8);
+ init_get_bits8(&gb, buffer, size - 3);
break;
case TAK_METADATA_MD5: {
uint8_t md5[16];
@@ -88,8 +108,14 @@ static int tak_read_header(AVFormatContext *s)
if (size != 19)
return AVERROR_INVALIDDATA;
+ ffio_init_checksum(pb, tak_check_crc, 0xCE04B7U);
avio_read(pb, md5, 16);
- avio_skip(pb, 3);
+ if (ffio_get_checksum(s->pb) != avio_rb24(pb)) {
+ av_log(s, AV_LOG_ERROR, "MD5 metadata block CRC error.\n");
+ if (s->error_recognition & AV_EF_EXPLODE)
+ return AVERROR_INVALIDDATA;
+ }
+
av_log(s, AV_LOG_VERBOSE, "MD5=");
for (i = 0; i < 16; i++)
av_log(s, AV_LOG_VERBOSE, "%02x", md5[i]);
@@ -127,7 +153,7 @@ static int tak_read_header(AVFormatContext *s)
st->start_time = 0;
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
st->codec->extradata = buffer;
- st->codec->extradata_size = size;
+ st->codec->extradata_size = size - 3;
buffer = NULL;
} else if (type == TAK_METADATA_LAST_FRAME) {
if (size != 11)
@@ -155,7 +181,7 @@ static int raw_read_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
int64_t size, left;
- left = tc->data_end - avio_tell(s->pb);
+ left = tc->data_end - avio_tell(pb);
size = FFMIN(left, 1024);
if (size <= 0)
return AVERROR_EOF;
diff --git a/libavformat/tcp.c b/libavformat/tcp.c
index 5badf4f438..f24cad2080 100644
--- a/libavformat/tcp.c
+++ b/libavformat/tcp.c
@@ -2,25 +2,26 @@
* TCP protocol
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
#include "libavutil/parseutils.h"
#include "libavutil/opt.h"
+#include "libavutil/time.h"
#include "internal.h"
#include "network.h"
@@ -34,7 +35,8 @@ typedef struct TCPContext {
const AVClass *class;
int fd;
int listen;
- int timeout;
+ int open_timeout;
+ int rw_timeout;
int listen_timeout;
} TCPContext;
@@ -43,8 +45,8 @@ typedef struct TCPContext {
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
- { "timeout", "Connection timeout (in milliseconds)", OFFSET(timeout), AV_OPT_TYPE_INT, { .i64 = 10000 }, INT_MIN, INT_MAX, .flags = D|E },
- { "listen_timeout", "Bind timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX, .flags = D|E },
+ { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
+ { "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ NULL }
};
@@ -66,6 +68,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
int ret;
char hostname[1024],proto[1024],path[1024];
char portstr[10];
+ s->open_timeout = 5000000;
av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
&port, path, sizeof(path), uri);
@@ -77,15 +80,24 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
}
p = strchr(uri, '?');
if (p) {
- if (av_find_info_tag(buf, sizeof(buf), "listen", p))
- s->listen = 1;
+ if (av_find_info_tag(buf, sizeof(buf), "listen", p)) {
+ char *endptr = NULL;
+ s->listen = strtol(buf, &endptr, 10);
+ /* assume if no digits were found it is a request to enable it */
+ if (buf == endptr)
+ s->listen = 1;
+ }
if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
- s->timeout = strtol(buf, NULL, 10) * 100;
+ s->rw_timeout = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
s->listen_timeout = strtol(buf, NULL, 10);
}
}
+ if (s->rw_timeout >= 0) {
+ s->open_timeout =
+ h->rw_timeout = s->rw_timeout;
+ }
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%d", port);
@@ -121,7 +133,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags)
fd = ret;
} else {
if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
- s->timeout, h, !!cur_ai->ai_next)) < 0) {
+ s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) {
if (ret == AVERROR_EXIT)
goto fail1;
@@ -157,8 +169,8 @@ static int tcp_read(URLContext *h, uint8_t *buf, int size)
int ret;
if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
- ret = ff_network_wait_fd(s->fd, 0);
- if (ret < 0)
+ ret = ff_network_wait_fd_timeout(s->fd, 0, h->rw_timeout, &h->interrupt_callback);
+ if (ret)
return ret;
}
ret = recv(s->fd, buf, size, 0);
@@ -171,8 +183,8 @@ static int tcp_write(URLContext *h, const uint8_t *buf, int size)
int ret;
if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
- ret = ff_network_wait_fd(s->fd, 1);
- if (ret < 0)
+ ret = ff_network_wait_fd_timeout(s->fd, 1, h->rw_timeout, &h->interrupt_callback);
+ if (ret)
return ret;
}
ret = send(s->fd, buf, size, MSG_NOSIGNAL);
diff --git a/libavformat/tedcaptionsdec.c b/libavformat/tedcaptionsdec.c
new file mode 100644
index 0000000000..fb578ebc03
--- /dev/null
+++ b/libavformat/tedcaptionsdec.c
@@ -0,0 +1,366 @@
+/*
+ * TED Talks captions format decoder
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/bprint.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+
+typedef struct {
+ AVClass *class;
+ int64_t start_time;
+ FFDemuxSubtitlesQueue subs;
+} TEDCaptionsDemuxer;
+
+static const AVOption tedcaptions_options[] = {
+ { "start_time", "set the start time (offset) of the subtitles, in ms",
+ offsetof(TEDCaptionsDemuxer, start_time), FF_OPT_TYPE_INT64,
+ { .i64 = 15000 }, INT64_MIN, INT64_MAX,
+ AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM },
+ { NULL },
+};
+
+static const AVClass tedcaptions_demuxer_class = {
+ .class_name = "tedcaptions_demuxer",
+ .item_name = av_default_item_name,
+ .option = tedcaptions_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+#define BETWEEN(a, amin, amax) ((unsigned)((a) - (amin)) <= (amax) - (amin))
+
+#define HEX_DIGIT_TEST(c) (BETWEEN(c, '0', '9') || BETWEEN((c) | 32, 'a', 'z'))
+#define HEX_DIGIT_VAL(c) ((c) <= '9' ? (c) - '0' : ((c) | 32) - 'a' + 10)
+#define ERR_CODE(c) ((c) < 0 ? (c) : AVERROR_INVALIDDATA)
+
+static void av_bprint_utf8(AVBPrint *bp, unsigned c)
+{
+ int bytes, i;
+
+ if (c <= 0x7F) {
+ av_bprint_chars(bp, c, 1);
+ return;
+ }
+ bytes = (av_log2(c) - 2) / 5;
+ av_bprint_chars(bp, (c >> (bytes * 6)) | ((0xFF80 >> bytes) & 0xFF), 1);
+ for (i = bytes - 1; i >= 0; i--)
+ av_bprint_chars(bp, ((c >> (i * 6)) & 0x3F) | 0x80, 1);
+}
+
+static void next_byte(AVIOContext *pb, int *cur_byte)
+{
+ uint8_t b;
+ int ret = avio_read(pb, &b, 1);
+ *cur_byte = ret > 0 ? b : ret == 0 ? AVERROR_EOF : ret;
+}
+
+static void skip_spaces(AVIOContext *pb, int *cur_byte)
+{
+ while (*cur_byte == ' ' || *cur_byte == '\t' ||
+ *cur_byte == '\n' || *cur_byte == '\r')
+ next_byte(pb, cur_byte);
+}
+
+static int expect_byte(AVIOContext *pb, int *cur_byte, uint8_t c)
+{
+ skip_spaces(pb, cur_byte);
+ if (*cur_byte != c)
+ return ERR_CODE(*cur_byte);
+ next_byte(pb, cur_byte);
+ return 0;
+}
+
+static int parse_string(AVIOContext *pb, int *cur_byte, AVBPrint *bp, int full)
+{
+ int ret;
+
+ av_bprint_init(bp, 0, full ? -1 : 1);
+ ret = expect_byte(pb, cur_byte, '"');
+ if (ret < 0)
+ goto fail;
+ while (*cur_byte > 0 && *cur_byte != '"') {
+ if (*cur_byte == '\\') {
+ next_byte(pb, cur_byte);
+ if (*cur_byte < 0) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ if ((*cur_byte | 32) == 'u') {
+ unsigned chr = 0, i;
+ for (i = 0; i < 4; i++) {
+ next_byte(pb, cur_byte);
+ if (!HEX_DIGIT_TEST(*cur_byte)) {
+ ret = ERR_CODE(*cur_byte);
+ goto fail;
+ }
+ chr = chr * 16 + HEX_DIGIT_VAL(*cur_byte);
+ }
+ av_bprint_utf8(bp, chr);
+ } else {
+ av_bprint_chars(bp, *cur_byte, 1);
+ }
+ } else {
+ av_bprint_chars(bp, *cur_byte, 1);
+ }
+ next_byte(pb, cur_byte);
+ }
+ ret = expect_byte(pb, cur_byte, '"');
+ if (ret < 0)
+ goto fail;
+ if (full && !av_bprint_is_complete(bp)) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ av_bprint_finalize(bp, NULL);
+ return ret;
+}
+
+static int parse_label(AVIOContext *pb, int *cur_byte, AVBPrint *bp)
+{
+ int ret;
+
+ ret = parse_string(pb, cur_byte, bp, 0);
+ if (ret < 0)
+ return ret;
+ ret = expect_byte(pb, cur_byte, ':');
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int parse_boolean(AVIOContext *pb, int *cur_byte, int *result)
+{
+ static const char * const text[] = { "false", "true" };
+ const char *p;
+ int i;
+
+ skip_spaces(pb, cur_byte);
+ for (i = 0; i < 2; i++) {
+ p = text[i];
+ if (*cur_byte != *p)
+ continue;
+ for (; *p; p++, next_byte(pb, cur_byte))
+ if (*cur_byte != *p)
+ return AVERROR_INVALIDDATA;
+ if (BETWEEN(*cur_byte | 32, 'a', 'z'))
+ return AVERROR_INVALIDDATA;
+ *result = i;
+ return 0;
+ }
+ return AVERROR_INVALIDDATA;
+}
+
+static int parse_int(AVIOContext *pb, int *cur_byte, int64_t *result)
+{
+ int64_t val = 0;
+
+ skip_spaces(pb, cur_byte);
+ if ((unsigned)*cur_byte - '0' > 9)
+ return AVERROR_INVALIDDATA;
+ while (BETWEEN(*cur_byte, '0', '9')) {
+ val = val * 10 + (*cur_byte - '0');
+ next_byte(pb, cur_byte);
+ }
+ *result = val;
+ return 0;
+}
+
+static int parse_file(AVIOContext *pb, FFDemuxSubtitlesQueue *subs)
+{
+ int ret, cur_byte, start_of_par;
+ AVBPrint label, content;
+ int64_t pos, start, duration;
+ AVPacket *pkt;
+
+ next_byte(pb, &cur_byte);
+ ret = expect_byte(pb, &cur_byte, '{');
+ if (ret < 0)
+ return AVERROR_INVALIDDATA;
+ ret = parse_label(pb, &cur_byte, &label);
+ if (ret < 0 || strcmp(label.str, "captions"))
+ return AVERROR_INVALIDDATA;
+ ret = expect_byte(pb, &cur_byte, '[');
+ if (ret < 0)
+ return AVERROR_INVALIDDATA;
+ while (1) {
+ content.size = 0;
+ start = duration = AV_NOPTS_VALUE;
+ ret = expect_byte(pb, &cur_byte, '{');
+ if (ret < 0)
+ return ret;
+ pos = avio_tell(pb) - 1;
+ while (1) {
+ ret = parse_label(pb, &cur_byte, &label);
+ if (ret < 0)
+ return ret;
+ if (!strcmp(label.str, "startOfParagraph")) {
+ ret = parse_boolean(pb, &cur_byte, &start_of_par);
+ if (ret < 0)
+ return ret;
+ } else if (!strcmp(label.str, "content")) {
+ ret = parse_string(pb, &cur_byte, &content, 1);
+ if (ret < 0)
+ return ret;
+ } else if (!strcmp(label.str, "startTime")) {
+ ret = parse_int(pb, &cur_byte, &start);
+ if (ret < 0)
+ return ret;
+ } else if (!strcmp(label.str, "duration")) {
+ ret = parse_int(pb, &cur_byte, &duration);
+ if (ret < 0)
+ return ret;
+ } else {
+ return AVERROR_INVALIDDATA;
+ }
+ skip_spaces(pb, &cur_byte);
+ if (cur_byte != ',')
+ break;
+ next_byte(pb, &cur_byte);
+ }
+ ret = expect_byte(pb, &cur_byte, '}');
+ if (ret < 0)
+ return ret;
+
+ if (!content.size || start == AV_NOPTS_VALUE ||
+ duration == AV_NOPTS_VALUE)
+ return AVERROR_INVALIDDATA;
+ pkt = ff_subtitles_queue_insert(subs, content.str, content.len, 0);
+ if (!pkt)
+ return AVERROR(ENOMEM);
+ pkt->pos = pos;
+ pkt->pts = start;
+ pkt->duration = duration;
+ av_bprint_finalize(&content, NULL);
+
+ skip_spaces(pb, &cur_byte);
+ if (cur_byte != ',')
+ break;
+ next_byte(pb, &cur_byte);
+ }
+ ret = expect_byte(pb, &cur_byte, ']');
+ if (ret < 0)
+ return ret;
+ ret = expect_byte(pb, &cur_byte, '}');
+ if (ret < 0)
+ return ret;
+ skip_spaces(pb, &cur_byte);
+ if (cur_byte != AVERROR_EOF)
+ return ERR_CODE(cur_byte);
+ return 0;
+}
+
+static av_cold int tedcaptions_read_header(AVFormatContext *avf)
+{
+ TEDCaptionsDemuxer *tc = avf->priv_data;
+ AVStream *st;
+ int ret, i;
+ AVPacket *last;
+
+ ret = parse_file(avf->pb, &tc->subs);
+ if (ret < 0) {
+ if (ret == AVERROR_INVALIDDATA)
+ av_log(avf, AV_LOG_ERROR, "Syntax error near offset %"PRId64".\n",
+ avio_tell(avf->pb));
+ ff_subtitles_queue_clean(&tc->subs);
+ return ret;
+ }
+ ff_subtitles_queue_finalize(&tc->subs);
+ for (i = 0; i < tc->subs.nb_subs; i++)
+ tc->subs.subs[i].pts += tc->start_time;
+
+ last = &tc->subs.subs[tc->subs.nb_subs - 1];
+ st = avformat_new_stream(avf, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_TEXT;
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ st->probe_packets = 0;
+ st->start_time = 0;
+ st->duration = last->pts + last->duration;
+ st->cur_dts = 0;
+
+ return 0;
+}
+
+static int tedcaptions_read_packet(AVFormatContext *avf, AVPacket *packet)
+{
+ TEDCaptionsDemuxer *tc = avf->priv_data;
+
+ return ff_subtitles_queue_read_packet(&tc->subs, packet);
+}
+
+static int tedcaptions_read_close(AVFormatContext *avf)
+{
+ TEDCaptionsDemuxer *tc = avf->priv_data;
+
+ ff_subtitles_queue_clean(&tc->subs);
+ return 0;
+}
+
+static av_cold int tedcaptions_read_probe(AVProbeData *p)
+{
+ static const char *const tags[] = {
+ "\"captions\"", "\"duration\"", "\"content\"",
+ "\"startOfParagraph\"", "\"startTime\"",
+ };
+ unsigned i, count = 0;
+ const char *t;
+
+ if (p->buf[strspn(p->buf, " \t\r\n")] != '{')
+ return 0;
+ for (i = 0; i < FF_ARRAY_ELEMS(tags); i++) {
+ if (!(t = strstr(p->buf, tags[i])))
+ continue;
+ t += strlen(tags[i]);
+ t += strspn(t, " \t\r\n");
+ if (*t == ':')
+ count++;
+ }
+ return count == FF_ARRAY_ELEMS(tags) ? AVPROBE_SCORE_MAX :
+ count ? AVPROBE_SCORE_EXTENSION : 0;
+}
+
+static int tedcaptions_read_seek(AVFormatContext *avf, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts,
+ int flags)
+{
+ TEDCaptionsDemuxer *tc = avf->priv_data;
+ return ff_subtitles_queue_seek(&tc->subs, avf, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+AVInputFormat ff_tedcaptions_demuxer = {
+ .name = "tedcaptions",
+ .long_name = NULL_IF_CONFIG_SMALL("TED Talks captions"),
+ .priv_data_size = sizeof(TEDCaptionsDemuxer),
+ .priv_class = &tedcaptions_demuxer_class,
+ .read_header = tedcaptions_read_header,
+ .read_packet = tedcaptions_read_packet,
+ .read_close = tedcaptions_read_close,
+ .read_probe = tedcaptions_read_probe,
+ .read_seek2 = tedcaptions_read_seek,
+};
diff --git a/libavformat/tee.c b/libavformat/tee.c
new file mode 100644
index 0000000000..e3d466a3eb
--- /dev/null
+++ b/libavformat/tee.c
@@ -0,0 +1,495 @@
+/*
+ * Tee pseudo-muxer
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "libavutil/avutil.h"
+#include "libavutil/avstring.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+
+#define MAX_SLAVES 16
+
+typedef struct {
+ AVFormatContext *avf;
+ AVBitStreamFilterContext **bsfs; ///< bitstream filters per stream
+
+ /** map from input to output streams indexes,
+ * disabled output streams are set to -1 */
+ int *stream_map;
+} TeeSlave;
+
+typedef struct TeeContext {
+ const AVClass *class;
+ unsigned nb_slaves;
+ TeeSlave slaves[MAX_SLAVES];
+} TeeContext;
+
+static const char *const slave_delim = "|";
+static const char *const slave_opt_open = "[";
+static const char *const slave_opt_close = "]";
+static const char *const slave_opt_delim = ":]"; /* must have the close too */
+static const char *const slave_bsfs_spec_sep = "/";
+
+static const AVClass tee_muxer_class = {
+ .class_name = "Tee muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int parse_slave_options(void *log, char *slave,
+ AVDictionary **options, char **filename)
+{
+ const char *p;
+ char *key, *val;
+ int ret;
+
+ if (!strspn(slave, slave_opt_open)) {
+ *filename = slave;
+ return 0;
+ }
+ p = slave + 1;
+ if (strspn(p, slave_opt_close)) {
+ *filename = (char *)p + 1;
+ return 0;
+ }
+ while (1) {
+ ret = av_opt_get_key_value(&p, "=", slave_opt_delim, 0, &key, &val);
+ if (ret < 0) {
+ av_log(log, AV_LOG_ERROR, "No option found near \"%s\"\n", p);
+ goto fail;
+ }
+ ret = av_dict_set(options, key, val,
+ AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+ if (ret < 0)
+ goto fail;
+ if (strspn(p, slave_opt_close))
+ break;
+ p++;
+ }
+ *filename = (char *)p + 1;
+ return 0;
+
+fail:
+ av_dict_free(options);
+ return ret;
+}
+
+/**
+ * Parse list of bitstream filters and add them to the list of filters
+ * pointed to by bsfs.
+ *
+ * The list must be specified in the form:
+ * BSFS ::= BSF[,BSFS]
+ */
+static int parse_bsfs(void *log_ctx, const char *bsfs_spec,
+ AVBitStreamFilterContext **bsfs)
+{
+ char *bsf_name, *buf, *dup, *saveptr;
+ int ret = 0;
+
+ if (!(dup = buf = av_strdup(bsfs_spec)))
+ return AVERROR(ENOMEM);
+
+ while (bsf_name = av_strtok(buf, ",", &saveptr)) {
+ AVBitStreamFilterContext *bsf = av_bitstream_filter_init(bsf_name);
+
+ if (!bsf) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Cannot initialize bitstream filter with name '%s', "
+ "unknown filter or internal error happened\n",
+ bsf_name);
+ ret = AVERROR_UNKNOWN;
+ goto end;
+ }
+
+ /* append bsf context to the list of bsf contexts */
+ *bsfs = bsf;
+ bsfs = &bsf->next;
+
+ buf = NULL;
+ }
+
+end:
+ av_free(dup);
+ return ret;
+}
+
+static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
+{
+ int i, ret;
+ AVDictionary *options = NULL;
+ AVDictionaryEntry *entry;
+ char *filename;
+ char *format = NULL, *select = NULL;
+ AVFormatContext *avf2 = NULL;
+ AVStream *st, *st2;
+ int stream_count;
+
+ if ((ret = parse_slave_options(avf, slave, &options, &filename)) < 0)
+ return ret;
+
+#define STEAL_OPTION(option, field) do { \
+ if ((entry = av_dict_get(options, option, NULL, 0))) { \
+ field = entry->value; \
+ entry->value = NULL; /* prevent it from being freed */ \
+ av_dict_set(&options, option, NULL, 0); \
+ } \
+ } while (0)
+
+ STEAL_OPTION("f", format);
+ STEAL_OPTION("select", select);
+
+ ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
+ if (ret < 0)
+ goto end;
+ av_dict_copy(&avf2->metadata, avf->metadata, 0);
+
+ tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map));
+ if (!tee_slave->stream_map) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ stream_count = 0;
+ for (i = 0; i < avf->nb_streams; i++) {
+ st = avf->streams[i];
+ if (select) {
+ ret = avformat_match_stream_specifier(avf, avf->streams[i], select);
+ if (ret < 0) {
+ av_log(avf, AV_LOG_ERROR,
+ "Invalid stream specifier '%s' for output '%s'\n",
+ select, slave);
+ goto end;
+ }
+
+ if (ret == 0) { /* no match */
+ tee_slave->stream_map[i] = -1;
+ continue;
+ }
+ }
+ tee_slave->stream_map[i] = stream_count++;
+
+ if (!(st2 = avformat_new_stream(avf2, NULL))) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ st2->id = st->id;
+ st2->r_frame_rate = st->r_frame_rate;
+ st2->time_base = st->time_base;
+ st2->start_time = st->start_time;
+ st2->duration = st->duration;
+ st2->nb_frames = st->nb_frames;
+ st2->disposition = st->disposition;
+ st2->sample_aspect_ratio = st->sample_aspect_ratio;
+ st2->avg_frame_rate = st->avg_frame_rate;
+ av_dict_copy(&st2->metadata, st->metadata, 0);
+ if ((ret = avcodec_copy_context(st2->codec, st->codec)) < 0)
+ goto end;
+ }
+
+ if (!(avf2->oformat->flags & AVFMT_NOFILE)) {
+ if ((ret = avio_open(&avf2->pb, filename, AVIO_FLAG_WRITE)) < 0) {
+ av_log(avf, AV_LOG_ERROR, "Slave '%s': error opening: %s\n",
+ slave, av_err2str(ret));
+ goto end;
+ }
+ }
+
+ if ((ret = avformat_write_header(avf2, &options)) < 0) {
+ av_log(avf, AV_LOG_ERROR, "Slave '%s': error writing header: %s\n",
+ slave, av_err2str(ret));
+ goto end;
+ }
+
+ tee_slave->avf = avf2;
+ tee_slave->bsfs = av_calloc(avf2->nb_streams, sizeof(TeeSlave));
+ if (!tee_slave->bsfs) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+
+ entry = NULL;
+ while (entry = av_dict_get(options, "bsfs", NULL, AV_DICT_IGNORE_SUFFIX)) {
+ const char *spec = entry->key + strlen("bsfs");
+ if (*spec) {
+ if (strspn(spec, slave_bsfs_spec_sep) != 1) {
+ av_log(avf, AV_LOG_ERROR,
+ "Specifier separator in '%s' is '%c', but only characters '%s' "
+ "are allowed\n", entry->key, *spec, slave_bsfs_spec_sep);
+ return AVERROR(EINVAL);
+ }
+ spec++; /* consume separator */
+ }
+
+ for (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,
+ "Invalid stream specifier '%s' in bsfs option '%s' for slave "
+ "output '%s'\n", spec, entry->key, filename);
+ goto end;
+ }
+
+ if (ret > 0) {
+ av_log(avf, AV_LOG_DEBUG, "spec:%s bsfs:%s matches stream %d of slave "
+ "output '%s'\n", spec, entry->value, i, filename);
+ if (tee_slave->bsfs[i]) {
+ av_log(avf, AV_LOG_WARNING,
+ "Duplicate bsfs specification associated to stream %d of slave "
+ "output '%s', filters will be ignored\n", i, filename);
+ continue;
+ }
+ ret = parse_bsfs(avf, entry->value, &tee_slave->bsfs[i]);
+ if (ret < 0) {
+ av_log(avf, AV_LOG_ERROR,
+ "Error parsing bitstream filter sequence '%s' associated to "
+ "stream %d of slave output '%s'\n", entry->value, i, filename);
+ goto end;
+ }
+ }
+ }
+
+ av_dict_set(&options, entry->key, NULL, 0);
+ }
+
+ if (options) {
+ entry = NULL;
+ while ((entry = av_dict_get(options, "", entry, AV_DICT_IGNORE_SUFFIX)))
+ av_log(avf2, AV_LOG_ERROR, "Unknown option '%s'\n", entry->key);
+ ret = AVERROR_OPTION_NOT_FOUND;
+ goto end;
+ }
+
+end:
+ av_free(format);
+ av_free(select);
+ av_dict_free(&options);
+ return ret;
+}
+
+static void close_slaves(AVFormatContext *avf)
+{
+ TeeContext *tee = avf->priv_data;
+ AVFormatContext *avf2;
+ unsigned i, j;
+
+ for (i = 0; i < tee->nb_slaves; i++) {
+ avf2 = tee->slaves[i].avf;
+
+ for (j = 0; j < avf2->nb_streams; j++) {
+ AVBitStreamFilterContext *bsf_next, *bsf = tee->slaves[i].bsfs[j];
+ while (bsf) {
+ bsf_next = bsf->next;
+ av_bitstream_filter_close(bsf);
+ bsf = bsf_next;
+ }
+ }
+ av_freep(&tee->slaves[i].stream_map);
+ av_freep(&tee->slaves[i].bsfs);
+
+ avio_closep(&avf2->pb);
+ avformat_free_context(avf2);
+ tee->slaves[i].avf = NULL;
+ }
+}
+
+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->filename, slave->avf->oformat->name);
+ for (i = 0; i < slave->avf->nb_streams; i++) {
+ AVStream *st = slave->avf->streams[i];
+ AVBitStreamFilterContext *bsf = slave->bsfs[i];
+
+ av_log(log_ctx, log_level, " stream:%d codec:%s type:%s",
+ i, avcodec_get_name(st->codec->codec_id),
+ av_get_media_type_string(st->codec->codec_type));
+ if (bsf) {
+ av_log(log_ctx, log_level, " bsfs:");
+ while (bsf) {
+ av_log(log_ctx, log_level, "%s%s",
+ bsf->filter->name, bsf->next ? "," : "");
+ bsf = bsf->next;
+ }
+ }
+ av_log(log_ctx, log_level, "\n");
+ }
+}
+
+static int tee_write_header(AVFormatContext *avf)
+{
+ TeeContext *tee = avf->priv_data;
+ unsigned nb_slaves = 0, i;
+ const char *filename = avf->filename;
+ char *slaves[MAX_SLAVES];
+ int ret;
+
+ while (*filename) {
+ if (nb_slaves == MAX_SLAVES) {
+ av_log(avf, AV_LOG_ERROR, "Maximum %d slave muxers reached.\n",
+ MAX_SLAVES);
+ ret = AVERROR_PATCHWELCOME;
+ goto fail;
+ }
+ if (!(slaves[nb_slaves++] = av_get_token(&filename, slave_delim))) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ if (strspn(filename, slave_delim))
+ filename++;
+ }
+
+ for (i = 0; i < nb_slaves; i++) {
+ if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0)
+ goto fail;
+ log_slave(&tee->slaves[i], avf, AV_LOG_VERBOSE);
+ av_freep(&slaves[i]);
+ }
+
+ tee->nb_slaves = nb_slaves;
+
+ for (i = 0; i < avf->nb_streams; i++) {
+ int j, mapped = 0;
+ for (j = 0; j < tee->nb_slaves; j++)
+ mapped += tee->slaves[j].stream_map[i] >= 0;
+ if (!mapped)
+ av_log(avf, AV_LOG_WARNING, "Input stream #%d is not mapped "
+ "to any slave.\n", i);
+ }
+ return 0;
+
+fail:
+ for (i = 0; i < nb_slaves; i++)
+ av_freep(&slaves[i]);
+ close_slaves(avf);
+ return ret;
+}
+
+static int filter_packet(void *log_ctx, AVPacket *pkt,
+ AVFormatContext *fmt_ctx, AVBitStreamFilterContext *bsf_ctx)
+{
+ AVCodecContext *enc_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
+ int ret = 0;
+
+ while (bsf_ctx) {
+ AVPacket new_pkt = *pkt;
+ ret = av_bitstream_filter_filter(bsf_ctx, enc_ctx, NULL,
+ &new_pkt.data, &new_pkt.size,
+ pkt->data, pkt->size,
+ pkt->flags & AV_PKT_FLAG_KEY);
+ if (ret == 0 && new_pkt.data != pkt->data && new_pkt.destruct) {
+ if ((ret = av_copy_packet(&new_pkt, pkt)) < 0)
+ break;
+ ret = 1;
+ }
+
+ if (ret > 0) {
+ av_free_packet(pkt);
+ new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
+ av_buffer_default_free, NULL, 0);
+ if (!new_pkt.buf)
+ break;
+ }
+ if (ret < 0) {
+ av_log(log_ctx, AV_LOG_ERROR,
+ "Failed to filter bitstream with filter %s for stream %d in file '%s' with codec %s\n",
+ bsf_ctx->filter->name, pkt->stream_index, fmt_ctx->filename,
+ avcodec_get_name(enc_ctx->codec_id));
+ }
+ *pkt = new_pkt;
+
+ bsf_ctx = bsf_ctx->next;
+ }
+
+ return ret;
+}
+
+static int tee_write_trailer(AVFormatContext *avf)
+{
+ TeeContext *tee = avf->priv_data;
+ AVFormatContext *avf2;
+ int ret_all = 0, ret;
+ unsigned i;
+
+ for (i = 0; i < tee->nb_slaves; i++) {
+ avf2 = tee->slaves[i].avf;
+ if ((ret = av_write_trailer(avf2)) < 0)
+ if (!ret_all)
+ ret_all = ret;
+ if (!(avf2->oformat->flags & AVFMT_NOFILE)) {
+ if ((ret = avio_closep(&avf2->pb)) < 0)
+ if (!ret_all)
+ ret_all = ret;
+ }
+ }
+ close_slaves(avf);
+ return ret_all;
+}
+
+static int tee_write_packet(AVFormatContext *avf, AVPacket *pkt)
+{
+ TeeContext *tee = avf->priv_data;
+ AVFormatContext *avf2;
+ AVPacket pkt2;
+ int ret_all = 0, ret;
+ unsigned i, s;
+ int s2;
+ AVRational tb, tb2;
+
+ for (i = 0; i < tee->nb_slaves; i++) {
+ avf2 = tee->slaves[i].avf;
+ s = pkt->stream_index;
+ s2 = tee->slaves[i].stream_map[s];
+ if (s2 < 0)
+ continue;
+
+ if ((ret = av_copy_packet(&pkt2, pkt)) < 0 ||
+ (ret = av_dup_packet(&pkt2))< 0)
+ if (!ret_all) {
+ ret_all = ret;
+ continue;
+ }
+ tb = avf ->streams[s ]->time_base;
+ tb2 = avf2->streams[s2]->time_base;
+ pkt2.pts = av_rescale_q(pkt->pts, tb, tb2);
+ pkt2.dts = av_rescale_q(pkt->dts, tb, tb2);
+ pkt2.duration = av_rescale_q(pkt->duration, tb, tb2);
+ pkt2.stream_index = s2;
+
+ filter_packet(avf2, &pkt2, avf2, tee->slaves[i].bsfs[s2]);
+ if ((ret = av_interleaved_write_frame(avf2, &pkt2)) < 0)
+ if (!ret_all)
+ ret_all = ret;
+ }
+ return ret_all;
+}
+
+AVOutputFormat ff_tee_muxer = {
+ .name = "tee",
+ .long_name = NULL_IF_CONFIG_SMALL("Multiple muxer tee"),
+ .priv_data_size = sizeof(TeeContext),
+ .write_header = tee_write_header,
+ .write_trailer = tee_write_trailer,
+ .write_packet = tee_write_packet,
+ .priv_class = &tee_muxer_class,
+ .flags = AVFMT_NOFILE,
+};
diff --git a/libavformat/thp.c b/libavformat/thp.c
index e8ca04f939..727fb5095c 100644
--- a/libavformat/thp.c
+++ b/libavformat/thp.c
@@ -2,20 +2,20 @@
* THP Demuxer
* Copyright (c) 2007 Marco Gerards
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,32 +26,37 @@
typedef struct ThpDemuxContext {
int version;
- int first_frame;
- int first_framesz;
- int last_frame;
+ unsigned first_frame;
+ unsigned first_framesz;
+ unsigned last_frame;
int compoff;
- int framecnt;
+ unsigned framecnt;
AVRational fps;
- int frame;
- int next_frame;
- int next_framesz;
+ unsigned frame;
+ int64_t next_frame;
+ unsigned next_framesz;
int video_stream_index;
int audio_stream_index;
int compcount;
unsigned char components[16];
AVStream* vst;
int has_audio;
- int audiosize;
+ unsigned audiosize;
} ThpDemuxContext;
static int thp_probe(AVProbeData *p)
{
+ double d;
/* check file header */
- if (AV_RL32(p->buf) == MKTAG('T', 'H', 'P', '\0'))
- return AVPROBE_SCORE_MAX;
- else
+ if (AV_RL32(p->buf) != MKTAG('T', 'H', 'P', '\0'))
return 0;
+
+ d = av_int2float(AV_RB32(p->buf + 16));
+ if (d < 0.1 || d > 1000 || isnan(d))
+ return AVPROBE_SCORE_MAX/4;
+
+ return AVPROBE_SCORE_MAX;
}
static int thp_read_header(AVFormatContext *s)
@@ -59,6 +64,7 @@ static int thp_read_header(AVFormatContext *s)
ThpDemuxContext *thp = s->priv_data;
AVStream *st;
AVIOContext *pb = s->pb;
+ int64_t fsize= avio_size(pb);
int i;
/* Read the file header. */
@@ -71,7 +77,9 @@ static int thp_read_header(AVFormatContext *s)
thp->fps = av_d2q(av_int2float(avio_rb32(pb)), INT_MAX);
thp->framecnt = avio_rb32(pb);
thp->first_framesz = avio_rb32(pb);
- avio_rb32(pb); /* Data size. */
+ pb->maxsize = avio_rb32(pb);
+ if(fsize>0 && (!pb->maxsize || fsize < pb->maxsize))
+ pb->maxsize= fsize;
thp->compoff = avio_rb32(pb);
avio_rb32(pb); /* offsetDataOffset. */
@@ -90,7 +98,7 @@ static int thp_read_header(AVFormatContext *s)
for (i = 0; i < thp->compcount; i++) {
if (thp->components[i] == 0) {
- if (thp->vst != 0)
+ if (thp->vst)
break;
/* Video component. */
@@ -106,7 +114,8 @@ static int thp_read_header(AVFormatContext *s)
st->codec->codec_tag = 0; /* no fourcc */
st->codec->width = avio_rb32(pb);
st->codec->height = avio_rb32(pb);
- st->codec->sample_rate = av_q2d(thp->fps);
+ st->nb_frames =
+ st->duration = thp->framecnt;
thp->vst = st;
thp->video_stream_index = st->index;
@@ -142,18 +151,18 @@ static int thp_read_packet(AVFormatContext *s,
{
ThpDemuxContext *thp = s->priv_data;
AVIOContext *pb = s->pb;
- int size;
+ unsigned int size;
int ret;
if (thp->audiosize == 0) {
/* Terminate when last frame is reached. */
if (thp->frame >= thp->framecnt)
- return AVERROR(EIO);
+ return AVERROR_EOF;
avio_seek(pb, thp->next_frame, SEEK_SET);
/* Locate the next frame and read out its size. */
- thp->next_frame += thp->next_framesz;
+ thp->next_frame += FFMAX(thp->next_framesz, 1);
thp->next_framesz = avio_rb32(pb);
avio_rb32(pb); /* Previous total size. */
@@ -167,6 +176,8 @@ static int thp_read_packet(AVFormatContext *s,
thp->frame++;
ret = av_get_packet(pb, pkt, size);
+ if (ret < 0)
+ return ret;
if (ret != size) {
av_free_packet(pkt);
return AVERROR(EIO);
@@ -175,6 +186,8 @@ static int thp_read_packet(AVFormatContext *s,
pkt->stream_index = thp->video_stream_index;
} else {
ret = av_get_packet(pb, pkt, thp->audiosize);
+ if (ret < 0)
+ return ret;
if (ret != thp->audiosize) {
av_free_packet(pkt);
return AVERROR(EIO);
diff --git a/libavformat/tiertexseq.c b/libavformat/tiertexseq.c
index 45300f9e8a..659ba06dd7 100644
--- a/libavformat/tiertexseq.c
+++ b/libavformat/tiertexseq.c
@@ -2,20 +2,20 @@
* Tiertex Limited SEQ File Demuxer
* Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -301,7 +301,7 @@ static int seq_read_close(AVFormatContext *s)
SeqDemuxContext *seq = s->priv_data;
for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++)
- av_free(seq->frame_buffers[i].data);
+ av_freep(&seq->frame_buffers[i].data);
return 0;
}
diff --git a/libavformat/tls.c b/libavformat/tls.c
index 00fe876a42..449504a96d 100644
--- a/libavformat/tls.c
+++ b/libavformat/tls.c
@@ -2,20 +2,20 @@
* TLS/SSL Protocol
* Copyright (c) 2011 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,17 +24,20 @@
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
+#include "network.h"
+#include "os_support.h"
+#include "internal.h"
#if CONFIG_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
-#define TLS_read(c, buf, size) gnutls_record_recv(c->session, buf, size)
-#define TLS_write(c, buf, size) gnutls_record_send(c->session, buf, size)
-#define TLS_shutdown(c) gnutls_bye(c->session, GNUTLS_SHUT_RDWR)
+#define TLS_read(c, buf, size) gnutls_record_recv((c)->session, (buf), (size))
+#define TLS_write(c, buf, size) gnutls_record_send((c)->session, (buf), (size))
+#define TLS_shutdown(c) gnutls_bye((c)->session, GNUTLS_SHUT_RDWR)
#define TLS_free(c) do { \
- if (c->session) \
- gnutls_deinit(c->session); \
- if (c->cred) \
- gnutls_certificate_free_credentials(c->cred); \
+ if ((c)->session) \
+ gnutls_deinit((c)->session); \
+ if ((c)->cred) \
+ gnutls_certificate_free_credentials((c)->cred); \
} while (0)
static ssize_t gnutls_url_pull(gnutls_transport_ptr_t transport,
@@ -65,14 +68,14 @@ static ssize_t gnutls_url_push(gnutls_transport_ptr_t transport,
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
-#define TLS_read(c, buf, size) SSL_read(c->ssl, buf, size)
-#define TLS_write(c, buf, size) SSL_write(c->ssl, buf, size)
-#define TLS_shutdown(c) SSL_shutdown(c->ssl)
+#define TLS_read(c, buf, size) SSL_read((c)->ssl, (buf), (size))
+#define TLS_write(c, buf, size) SSL_write((c)->ssl, (buf), (size))
+#define TLS_shutdown(c) SSL_shutdown((c)->ssl)
#define TLS_free(c) do { \
- if (c->ssl) \
- SSL_free(c->ssl); \
- if (c->ctx) \
- SSL_CTX_free(c->ctx); \
+ if ((c)->ssl) \
+ SSL_free((c)->ssl); \
+ if ((c)->ctx) \
+ SSL_CTX_free((c)->ctx); \
} while (0)
static int url_bio_create(BIO *b)
@@ -139,9 +142,6 @@ static BIO_METHOD url_bio_method = {
};
#endif
-#include "network.h"
-#include "os_support.h"
-#include "internal.h"
#if HAVE_POLL_H
#include <poll.h>
#endif
@@ -168,6 +168,7 @@ typedef struct TLSContext {
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{"ca_file", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E },
+ {"cafile", "Certificate Authority database file", OFFSET(ca_file), AV_OPT_TYPE_STRING, .flags = D|E },
{"tls_verify", "Verify the peer certificate", OFFSET(verify), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
{"cert_file", "Certificate file", OFFSET(cert_file), AV_OPT_TYPE_STRING, .flags = D|E },
{"key_file", "Private key file", OFFSET(key_file), AV_OPT_TYPE_STRING, .flags = D|E },
@@ -202,6 +203,31 @@ static int print_tls_error(URLContext *h, int ret)
return AVERROR(EIO);
}
+static void set_options(URLContext *h, const char *uri)
+{
+ TLSContext *c = h->priv_data;
+ char buf[1024];
+ const char *p = strchr(uri, '?');
+ if (!p)
+ return;
+
+ if (!c->ca_file && av_find_info_tag(buf, sizeof(buf), "cafile", p))
+ c->ca_file = av_strdup(buf);
+
+ if (!c->verify && av_find_info_tag(buf, sizeof(buf), "verify", p)) {
+ char *endptr = NULL;
+ c->verify = strtol(buf, &endptr, 10);
+ if (buf == endptr)
+ c->verify = 1;
+ }
+
+ if (!c->cert_file && av_find_info_tag(buf, sizeof(buf), "cert", p))
+ c->cert_file = av_strdup(buf);
+
+ if (!c->key_file && av_find_info_tag(buf, sizeof(buf), "key", p))
+ c->key_file = av_strdup(buf);
+}
+
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
TLSContext *c = h->priv_data;
@@ -217,7 +243,8 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
BIO *bio;
#endif
- ff_tls_init();
+ if ((ret = ff_tls_init()) < 0)
+ return ret;
if (c->listen)
snprintf(opts, sizeof(opts), "?listen=1");
@@ -266,8 +293,12 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
if (!c->listen && !numerichost)
gnutls_server_name_set(c->session, GNUTLS_NAME_DNS, host, strlen(host));
gnutls_certificate_allocate_credentials(&c->cred);
- if (c->ca_file)
- gnutls_certificate_set_x509_trust_file(c->cred, c->ca_file, GNUTLS_X509_FMT_PEM);
+ set_options(h, uri);
+ if (c->ca_file) {
+ ret = gnutls_certificate_set_x509_trust_file(c->cred, c->ca_file, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ av_log(h, AV_LOG_ERROR, "%s\n", gnutls_strerror(ret));
+ }
#if GNUTLS_VERSION_MAJOR >= 3
else
gnutls_certificate_set_x509_system_trust(c->cred);
@@ -285,7 +316,8 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
ret = AVERROR(EIO);
goto fail;
}
- }
+ } else if (c->cert_file || c->key_file)
+ av_log(h, AV_LOG_ERROR, "cert and key required\n");
gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, c->cred);
gnutls_transport_set_pull_function(c->session, gnutls_url_pull);
gnutls_transport_set_push_function(c->session, gnutls_url_push);
@@ -335,8 +367,11 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
ret = AVERROR(EIO);
goto fail;
}
- if (c->ca_file)
- SSL_CTX_load_verify_locations(c->ctx, c->ca_file, NULL);
+ set_options(h, uri);
+ if (c->ca_file) {
+ if (!SSL_CTX_load_verify_locations(c->ctx, c->ca_file, NULL))
+ av_log(h, AV_LOG_ERROR, "SSL_CTX_load_verify_locations %s\n", ERR_error_string(ERR_get_error(), NULL));
+ }
if (c->cert_file && !SSL_CTX_use_certificate_chain_file(c->ctx, c->cert_file)) {
av_log(h, AV_LOG_ERROR, "Unable to load cert file %s: %s\n",
c->cert_file, ERR_error_string(ERR_get_error(), NULL));
@@ -352,7 +387,7 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op
// Note, this doesn't check that the peer certificate actually matches
// the requested hostname.
if (c->verify)
- SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER, NULL);
+ SSL_CTX_set_verify(c->ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
c->ssl = SSL_new(c->ctx);
if (!c->ssl) {
av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL));
diff --git a/libavformat/tmv.c b/libavformat/tmv.c
index 103ac4af20..ad172f4308 100644
--- a/libavformat/tmv.c
+++ b/libavformat/tmv.c
@@ -2,20 +2,20 @@
* 8088flex TMV file demuxer
* Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -154,7 +154,7 @@ static int tmv_read_packet(AVFormatContext *s, AVPacket *pkt)
int ret, pkt_size = tmv->stream_index ?
tmv->audio_chunk_size : tmv->video_chunk_size;
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR_EOF;
ret = av_get_packet(pb, pkt, pkt_size);
diff --git a/libavformat/tta.c b/libavformat/tta.c
index bc86a777b3..7566939d48 100644
--- a/libavformat/tta.c
+++ b/libavformat/tta.c
@@ -2,27 +2,30 @@
* TTA demuxer
* Copyright (c) 2006 Alex Beregszaszi
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/get_bits.h"
+#include "apetag.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "id3v1.h"
+#include "libavutil/crc.h"
#include "libavutil/dict.h"
typedef struct TTAContext {
@@ -31,11 +34,19 @@ typedef struct TTAContext {
int last_frame_size;
} TTAContext;
-static int tta_probe(AVProbeData *p)
+static unsigned long tta_check_crc(unsigned long checksum, const uint8_t *buf,
+ unsigned int len)
{
- const uint8_t *d = p->buf;
+ return av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), checksum, buf, len);
+}
- if (d[0] == 'T' && d[1] == 'T' && d[2] == 'A' && d[3] == '1')
+static int tta_probe(AVProbeData *p)
+{
+ if (AV_RL32(&p->buf[0]) == MKTAG('T', 'T', 'A', '1') &&
+ (AV_RL16(&p->buf[4]) == 1 || AV_RL16(&p->buf[4]) == 2) &&
+ AV_RL16(&p->buf[6]) > 0 &&
+ AV_RL16(&p->buf[8]) > 0 &&
+ AV_RL32(&p->buf[10]) > 0)
return AVPROBE_SCORE_EXTENSION + 30;
return 0;
}
@@ -44,17 +55,18 @@ static int tta_read_header(AVFormatContext *s)
{
TTAContext *c = s->priv_data;
AVStream *st;
- int i, channels, bps, samplerate, datalen;
+ int i, channels, bps, samplerate;
int64_t framepos, start_offset;
+ uint32_t nb_samples, crc;
- if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX))
- ff_id3v1_read(s);
+ ff_id3v1_read(s);
start_offset = avio_tell(s->pb);
if (start_offset < 0)
return start_offset;
+ ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX);
if (avio_rl32(s->pb) != AV_RL32("TTA1"))
- return -1; // not tta file
+ return AVERROR_INVALIDDATA;
avio_skip(s->pb, 2); // FIXME: flags
channels = avio_rl16(s->pb);
@@ -62,27 +74,31 @@ static int tta_read_header(AVFormatContext *s)
samplerate = avio_rl32(s->pb);
if(samplerate <= 0 || samplerate > 1000000){
av_log(s, AV_LOG_ERROR, "nonsense samplerate\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
- datalen = avio_rl32(s->pb);
- if(datalen < 0){
- av_log(s, AV_LOG_ERROR, "nonsense datalen\n");
- return -1;
+ nb_samples = avio_rl32(s->pb);
+ if (!nb_samples) {
+ av_log(s, AV_LOG_ERROR, "invalid number of samples\n");
+ return AVERROR_INVALIDDATA;
}
- avio_skip(s->pb, 4); // header crc
+ crc = ffio_get_checksum(s->pb) ^ UINT32_MAX;
+ if (crc != avio_rl32(s->pb) && s->error_recognition & AV_EF_CRCCHECK) {
+ av_log(s, AV_LOG_ERROR, "Header CRC error\n");
+ return AVERROR_INVALIDDATA;
+ }
c->frame_size = samplerate * 256 / 245;
- c->last_frame_size = datalen % c->frame_size;
+ c->last_frame_size = nb_samples % c->frame_size;
if (!c->last_frame_size)
c->last_frame_size = c->frame_size;
- c->totalframes = datalen / c->frame_size + (c->last_frame_size < c->frame_size);
+ c->totalframes = nb_samples / c->frame_size + (c->last_frame_size < c->frame_size);
c->currentframe = 0;
- if(c->totalframes >= UINT_MAX/sizeof(uint32_t)){
- av_log(s, AV_LOG_ERROR, "totalframes too large\n");
- return -1;
+ if(c->totalframes >= UINT_MAX/sizeof(uint32_t) || c->totalframes <= 0){
+ av_log(s, AV_LOG_ERROR, "totalframes %d invalid\n", c->totalframes);
+ return AVERROR_INVALIDDATA;
}
st = avformat_new_stream(s, NULL);
@@ -91,20 +107,33 @@ static int tta_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, 1, samplerate);
st->start_time = 0;
- st->duration = datalen;
+ st->duration = nb_samples;
framepos = avio_tell(s->pb);
if (framepos < 0)
return framepos;
framepos += 4 * c->totalframes + 4;
+ if (ff_alloc_extradata(st->codec, avio_tell(s->pb) - start_offset))
+ return AVERROR(ENOMEM);
+
+ avio_seek(s->pb, start_offset, SEEK_SET);
+ avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
+
+ ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX);
for (i = 0; i < c->totalframes; i++) {
uint32_t size = avio_rl32(s->pb);
- av_add_index_entry(st, framepos, i * c->frame_size, size, 0,
- AVINDEX_KEYFRAME);
+ int r;
+ if ((r = av_add_index_entry(st, framepos, i * c->frame_size, size, 0,
+ AVINDEX_KEYFRAME)) < 0)
+ return r;
framepos += size;
}
- avio_skip(s->pb, 4); // seektable crc
+ crc = ffio_get_checksum(s->pb) ^ UINT32_MAX;
+ if (crc != avio_rl32(s->pb) && s->error_recognition & AV_EF_CRCCHECK) {
+ av_log(s, AV_LOG_ERROR, "Seek table CRC error\n");
+ return AVERROR_INVALIDDATA;
+ }
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_id = AV_CODEC_ID_TTA;
@@ -112,19 +141,11 @@ static int tta_read_header(AVFormatContext *s)
st->codec->sample_rate = samplerate;
st->codec->bits_per_coded_sample = bps;
- st->codec->extradata_size = avio_tell(s->pb) - start_offset;
- if(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){
- //this check is redundant as avio_read should fail
- av_log(s, AV_LOG_ERROR, "extradata_size too large\n");
- return -1;
- }
- st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata) {
- st->codec->extradata_size = 0;
- return AVERROR(ENOMEM);
+ if (s->pb->seekable) {
+ int64_t pos = avio_tell(s->pb);
+ ff_ape_parse_tag(s);
+ avio_seek(s->pb, pos, SEEK_SET);
}
- avio_seek(s->pb, start_offset, SEEK_SET);
- avio_read(s->pb, st->codec->extradata, st->codec->extradata_size);
return 0;
}
@@ -139,6 +160,11 @@ static int tta_read_packet(AVFormatContext *s, AVPacket *pkt)
if (c->currentframe >= c->totalframes)
return AVERROR_EOF;
+ if (st->nb_index_entries < c->totalframes) {
+ av_log(s, AV_LOG_ERROR, "Index entry disappeared\n");
+ return AVERROR_INVALIDDATA;
+ }
+
size = st->index_entries[c->currentframe].size;
ret = av_get_packet(s->pb, pkt, size);
diff --git a/libavformat/tty.c b/libavformat/tty.c
index 3a34dd865a..9022e915fa 100644
--- a/libavformat/tty.c
+++ b/libavformat/tty.c
@@ -2,20 +2,20 @@
* Tele-typewriter demuxer
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -38,8 +38,8 @@ typedef struct TtyDemuxContext {
AVClass *class;
int chars_per_frame;
uint64_t fsize; /**< file size less metadata buffer */
- char *video_size;/**< A string describing video size, set by a private option. */
- char *framerate; /**< Set by a private option. */
+ int width, height; /**< Set by a private option. */
+ AVRational framerate; /**< Set by a private option. */
} TtyDemuxContext;
/**
@@ -75,9 +75,8 @@ static int efi_read(AVFormatContext *avctx, uint64_t start_pos)
static int read_header(AVFormatContext *avctx)
{
TtyDemuxContext *s = avctx->priv_data;
- int width = 0, height = 0, ret = 0;
+ int ret = 0;
AVStream *st = avformat_new_stream(avctx, NULL);
- AVRational framerate;
if (!st) {
ret = AVERROR(ENOMEM);
@@ -87,18 +86,10 @@ static int read_header(AVFormatContext *avctx)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_ANSI;
- if (s->video_size && (ret = av_parse_video_size(&width, &height, s->video_size)) < 0) {
- av_log (avctx, AV_LOG_ERROR, "Couldn't parse video size.\n");
- goto fail;
- }
- if ((ret = av_parse_video_rate(&framerate, s->framerate)) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not parse framerate: %s.\n", s->framerate);
- goto fail;
- }
- st->codec->width = width;
- st->codec->height = height;
- avpriv_set_pts_info(st, 60, framerate.den, framerate.num);
- st->avg_frame_rate = framerate;
+ st->codec->width = s->width;
+ st->codec->height = s->height;
+ avpriv_set_pts_info(st, 60, s->framerate.den, s->framerate.num);
+ st->avg_frame_rate = s->framerate;
/* simulate tty display speed */
s->chars_per_frame = FFMAX(av_q2d(st->time_base)*s->chars_per_frame, 1);
@@ -122,20 +113,22 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
TtyDemuxContext *s = avctx->priv_data;
int n;
- if (avctx->pb->eof_reached)
+ if (avio_feof(avctx->pb))
return AVERROR_EOF;
n = s->chars_per_frame;
if (s->fsize) {
// ignore metadata buffer
uint64_t p = avio_tell(avctx->pb);
+ if (p == s->fsize)
+ return AVERROR_EOF;
if (p + s->chars_per_frame > s->fsize)
n = s->fsize - p;
}
pkt->size = av_get_packet(avctx->pb, pkt, n);
- if (pkt->size <= 0)
- return AVERROR(EIO);
+ if (pkt->size < 0)
+ return pkt->size;
pkt->flags |= AV_PKT_FLAG_KEY;
return 0;
}
@@ -144,8 +137,8 @@ static int read_packet(AVFormatContext *avctx, AVPacket *pkt)
#define DEC AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
{ "chars_per_frame", "", offsetof(TtyDemuxContext, chars_per_frame), AV_OPT_TYPE_INT, {.i64 = 6000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM},
- { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
- { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+ { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
+ { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, DEC },
{ NULL },
};
diff --git a/libavformat/txd.c b/libavformat/txd.c
index e6522c3a73..cac37d54b4 100644
--- a/libavformat/txd.c
+++ b/libavformat/txd.c
@@ -2,20 +2,20 @@
* Renderware TeXture Dictionary (.txd) demuxer
* Copyright (c) 2007 Ivo van Poorten
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,6 +49,7 @@ static int txd_read_header(AVFormatContext *s) {
avpriv_set_pts_info(st, 64, 1, 5);
st->avg_frame_rate = av_inv_q(st->time_base);
/* the parameters will be extracted from the compressed bitstream */
+
return 0;
}
@@ -62,7 +63,7 @@ next_chunk:
chunk_size = avio_rl32(pb);
marker = avio_rl32(pb);
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR_EOF;
if (marker != TXD_MARKER && marker != TXD_MARKER2) {
av_log(s, AV_LOG_ERROR, "marker does not match\n");
@@ -70,17 +71,17 @@ next_chunk:
}
switch (id) {
- case TXD_INFO:
- if (chunk_size > 100)
- break;
- case TXD_EXTRA:
- avio_skip(s->pb, chunk_size);
- case TXD_FILE:
- case TXD_TEXTURE:
- goto next_chunk;
- default:
- av_log(s, AV_LOG_ERROR, "unknown chunk id %i\n", id);
- return AVERROR_INVALIDDATA;
+ case TXD_INFO:
+ if (chunk_size > 100)
+ break;
+ case TXD_EXTRA:
+ avio_skip(s->pb, chunk_size);
+ case TXD_FILE:
+ case TXD_TEXTURE:
+ goto next_chunk;
+ default:
+ av_log(s, AV_LOG_ERROR, "unknown chunk id %i\n", id);
+ return AVERROR_INVALIDDATA;
}
ret = av_get_packet(s->pb, pkt, chunk_size);
diff --git a/libavformat/udp.c b/libavformat/udp.c
index dfc3b5aaab..d40ea973fe 100644
--- a/libavformat/udp.c
+++ b/libavformat/udp.c
@@ -2,20 +2,20 @@
* UDP prototype streaming system
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,49 +29,101 @@
#include "avformat.h"
#include "avio_internal.h"
#include "libavutil/parseutils.h"
+#include "libavutil/fifo.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/avstring.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"
+#if HAVE_UDPLITE_H
+#include "udplite.h"
+#else
+/* On many Linux systems, udplite.h is missing but the kernel supports UDP-Lite.
+ * So, we provide a fallback here.
+ */
+#define UDPLITE_SEND_CSCOV 10
+#define UDPLITE_RECV_CSCOV 11
+#endif
+
+#ifndef IPPROTO_UDPLITE
+#define IPPROTO_UDPLITE 136
+#endif
+
+#if HAVE_PTHREAD_CANCEL
+#include <pthread.h>
+#endif
+
+#ifndef HAVE_PTHREAD_CANCEL
+#define HAVE_PTHREAD_CANCEL 0
+#endif
+
#ifndef IPV6_ADD_MEMBERSHIP
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
+#define UDP_TX_BUF_SIZE 32768
+#define UDP_MAX_PKT_SIZE 65536
+#define UDP_HEADER_SIZE 8
+
typedef struct UDPContext {
const AVClass *class;
int udp_fd;
int ttl;
+ int udplite_coverage;
int buffer_size;
int pkt_size;
int is_multicast;
+ int is_broadcast;
int local_port;
int reuse_socket;
+ int overrun_nonfatal;
struct sockaddr_storage dest_addr;
int dest_addr_len;
int is_connected;
+
+ /* Circular Buffer variables for use in UDP receive code */
+ int circular_buffer_size;
+ AVFifoBuffer *fifo;
+ int circular_buffer_error;
+#if HAVE_PTHREAD_CANCEL
+ pthread_t circular_buffer_thread;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int thread_started;
+#endif
+ uint8_t tmp[UDP_MAX_PKT_SIZE+4];
+ int remaining_in_dg;
char *localaddr;
+ int timeout;
+ struct sockaddr_storage local_addr_storage;
char *sources;
char *block;
} UDPContext;
-#define UDP_TX_BUF_SIZE 32768
-#define UDP_MAX_PKT_SIZE 65536
-
#define OFFSET(x) offsetof(UDPContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "ttl", "Time to live (in milliseconds, multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, .flags = D|E },
{ "buffer_size", "System data size (in bytes)", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
+ { "localport", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, D|E },
{ "local_port", "Local port", OFFSET(local_port), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
- { "reuse_socket", "Reuse socket", OFFSET(reuse_socket), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
- { "connect", "Connect socket", OFFSET(is_connected), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
- { "pkt_size", "Maximum packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
{ "localaddr", "Local address", OFFSET(localaddr), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
+ { "udplite_coverage", "choose UDPLite head size which should be validated by checksum", OFFSET(udplite_coverage), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, D|E },
+ { "pkt_size", "Maximum UDP packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = 1472 }, -1, INT_MAX, .flags = D|E },
+ { "reuse", "explicitly allow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, D|E },
+ { "reuse_socket", "explicitly allow reusing UDP sockets", OFFSET(reuse_socket), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
+ { "broadcast", "explicitly allow or disallow broadcast destination", OFFSET(is_broadcast), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
+ { "ttl", "Time to live (multicast only)", OFFSET(ttl), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, E },
+ { "connect", "set if connect() should be called on socket", OFFSET(is_connected), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E },
+ { "fifo_size", "set the UDP receiving circular buffer size, expressed as a number of packets with size of 188 bytes", OFFSET(circular_buffer_size), AV_OPT_TYPE_INT, {.i64 = 7*4096}, 0, INT_MAX, D },
+ { "overrun_nonfatal", "survive in case of UDP receiving circular buffer overrun", OFFSET(overrun_nonfatal), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, D },
+ { "timeout", "set raise error timeout (only in read mode)", OFFSET(timeout), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
{ "sources", "Source list", OFFSET(sources), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
{ "block", "Block list", OFFSET(block), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
{ NULL }
@@ -84,6 +136,13 @@ static const AVClass udp_class = {
.version = LIBAVUTIL_VERSION_INT,
};
+static const AVClass udplite_context_class = {
+ .class_name = "udplite",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
static void log_net_error(void *ctx, int level, const char* prefix)
{
char errbuf[100];
@@ -113,14 +172,17 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL,
return 0;
}
-static int udp_join_multicast_group(int sockfd, struct sockaddr *addr)
+static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,struct sockaddr *local_addr)
{
#ifdef IP_ADD_MEMBERSHIP
if (addr->sa_family == AF_INET) {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
- mreq.imr_interface.s_addr= INADDR_ANY;
+ if (local_addr)
+ mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr;
+ else
+ mreq.imr_interface.s_addr= INADDR_ANY;
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)");
return -1;
@@ -142,14 +204,17 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr)
return 0;
}
-static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr)
+static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,struct sockaddr *local_addr)
{
#ifdef IP_DROP_MEMBERSHIP
if (addr->sa_family == AF_INET) {
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
- mreq.imr_interface.s_addr= INADDR_ANY;
+ if (local_addr)
+ mreq.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr;
+ else
+ mreq.imr_interface.s_addr= INADDR_ANY;
if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP)");
return -1;
@@ -277,7 +342,7 @@ static int udp_set_url(struct sockaddr_storage *addr,
int addr_len;
res0 = udp_resolve_host(hostname, port, SOCK_DGRAM, AF_UNSPEC, 0);
- if (res0 == 0) return AVERROR(EIO);
+ if (!res0) return AVERROR(EIO);
memcpy(addr, res0->ai_addr, res0->ai_addrlen);
addr_len = res0->ai_addrlen;
freeaddrinfo(res0);
@@ -289,17 +354,20 @@ static int udp_socket_create(UDPContext *s, struct sockaddr_storage *addr,
socklen_t *addr_len, const char *localaddr)
{
int udp_fd = -1;
- struct addrinfo *res0 = NULL, *res = NULL;
+ struct addrinfo *res0, *res;
int family = AF_UNSPEC;
if (((struct sockaddr *) &s->dest_addr)->sa_family)
family = ((struct sockaddr *) &s->dest_addr)->sa_family;
res0 = udp_resolve_host((localaddr && localaddr[0]) ? localaddr : NULL, s->local_port,
SOCK_DGRAM, family, AI_PASSIVE);
- if (res0 == 0)
+ if (!res0)
goto fail;
for (res = res0; res; res=res->ai_next) {
- udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0);
+ if (s->udplite_coverage)
+ udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, IPPROTO_UDPLITE);
+ else
+ udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0);
if (udp_fd != -1) break;
log_net_error(NULL, AV_LOG_ERROR, "socket");
}
@@ -346,6 +414,7 @@ static int udp_port(struct sockaddr_storage *addr, int addr_len)
* 'localport=n' : set the local port
* 'pkt_size=n' : set max packet size
* 'reuse=1' : enable reusing the socket
+ * 'overrun_nonfatal=1': survive in case of circular buffer overrun
*
* @param h media file context
* @param uri of the remote server
@@ -407,6 +476,65 @@ static int udp_get_file_handle(URLContext *h)
return s->udp_fd;
}
+#if HAVE_PTHREAD_CANCEL
+static void *circular_buffer_task( void *_URLContext)
+{
+ URLContext *h = _URLContext;
+ UDPContext *s = h->priv_data;
+ int old_cancelstate;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate);
+ pthread_mutex_lock(&s->mutex);
+ if (ff_socket_nonblock(s->udp_fd, 0) < 0) {
+ av_log(h, AV_LOG_ERROR, "Failed to set blocking mode");
+ s->circular_buffer_error = AVERROR(EIO);
+ goto end;
+ }
+ while(1) {
+ int len;
+
+ pthread_mutex_unlock(&s->mutex);
+ /* Blocking operations are always cancellation points;
+ see "General Information" / "Thread Cancelation Overview"
+ in Single Unix. */
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate);
+ len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate);
+ pthread_mutex_lock(&s->mutex);
+ if (len < 0) {
+ if (ff_neterrno() != AVERROR(EAGAIN) && ff_neterrno() != AVERROR(EINTR)) {
+ s->circular_buffer_error = ff_neterrno();
+ goto end;
+ }
+ continue;
+ }
+ AV_WL32(s->tmp, len);
+
+ if(av_fifo_space(s->fifo) < len + 4) {
+ /* No Space left */
+ if (s->overrun_nonfatal) {
+ av_log(h, AV_LOG_WARNING, "Circular buffer overrun. "
+ "Surviving due to overrun_nonfatal option\n");
+ continue;
+ } else {
+ av_log(h, AV_LOG_ERROR, "Circular buffer overrun. "
+ "To avoid, increase fifo_size URL option. "
+ "To survive in such case, use overrun_nonfatal option\n");
+ s->circular_buffer_error = AVERROR(EIO);
+ goto end;
+ }
+ }
+ av_fifo_generic_write(s->fifo, s->tmp, len+4, NULL);
+ pthread_cond_signal(&s->cond);
+ }
+
+end:
+ pthread_cond_signal(&s->cond);
+ pthread_mutex_unlock(&s->mutex);
+ return NULL;
+}
+#endif
+
static int parse_source_list(char *buf, char **sources, int *num_sources,
int max_sources)
{
@@ -433,7 +561,7 @@ static int parse_source_list(char *buf, char **sources, int *num_sources,
static int udp_open(URLContext *h, const char *uri, int flags)
{
char hostname[1024], localaddr[1024] = "";
- int port, udp_fd = -1, tmp, bind_ret = -1;
+ int port, udp_fd = -1, tmp, bind_ret = -1, dscp = -1;
UDPContext *s = h->priv_data;
int is_output;
const char *p;
@@ -444,10 +572,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
char *include_sources[32], *exclude_sources[32];
h->is_streamed = 1;
- h->max_packet_size = 1472;
is_output = !(flags & AVIO_FLAG_READ);
-
if (s->buffer_size < 0)
s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE;
@@ -476,14 +602,28 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (buf == endptr)
s->reuse_socket = 1;
}
+ if (av_find_info_tag(buf, sizeof(buf), "overrun_nonfatal", p)) {
+ char *endptr = NULL;
+ s->overrun_nonfatal = strtol(buf, &endptr, 10);
+ /* assume if no digits were found it is a request to enable it */
+ if (buf == endptr)
+ s->overrun_nonfatal = 1;
+ if (!HAVE_PTHREAD_CANCEL)
+ av_log(h, AV_LOG_WARNING,
+ "'overrun_nonfatal' option was set but it is not supported "
+ "on this build (pthread support is required)\n");
+ }
if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
s->ttl = strtol(buf, NULL, 10);
}
+ if (av_find_info_tag(buf, sizeof(buf), "udplite_coverage", p)) {
+ s->udplite_coverage = strtol(buf, NULL, 10);
+ }
if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
s->local_port = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
- h->max_packet_size = strtol(buf, NULL, 10);
+ s->pkt_size = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "buffer_size", p)) {
s->buffer_size = strtol(buf, NULL, 10);
@@ -491,6 +631,16 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
s->is_connected = strtol(buf, NULL, 10);
}
+ if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
+ dscp = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "fifo_size", p)) {
+ s->circular_buffer_size = strtol(buf, NULL, 10);
+ if (!HAVE_PTHREAD_CANCEL)
+ av_log(h, AV_LOG_WARNING,
+ "'circular_buffer_size' option was set but it is not supported "
+ "on this build (pthread support is required)\n");
+ }
if (av_find_info_tag(buf, sizeof(buf), "localaddr", p)) {
av_strlcpy(localaddr, buf, sizeof(localaddr));
}
@@ -504,7 +654,19 @@ static int udp_open(URLContext *h, const char *uri, int flags)
FF_ARRAY_ELEMS(exclude_sources)))
goto fail;
}
+ if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p))
+ s->timeout = strtol(buf, NULL, 10);
+ if (is_output && av_find_info_tag(buf, sizeof(buf), "broadcast", p))
+ s->is_broadcast = strtol(buf, NULL, 10);
}
+ /* handling needed to support options picking from both AVOption and URL */
+ s->circular_buffer_size *= 188;
+ if (flags & AVIO_FLAG_WRITE) {
+ h->max_packet_size = s->pkt_size;
+ } else {
+ h->max_packet_size = UDP_MAX_PKT_SIZE;
+ }
+ h->rw_timeout = s->timeout;
/* fill the dest addr */
av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port, NULL, 0, uri);
@@ -519,7 +681,7 @@ static int udp_open(URLContext *h, const char *uri, int flags)
goto fail;
}
- if ((s->is_multicast || !s->local_port) && (h->flags & AVIO_FLAG_READ))
+ if ((s->is_multicast || s->local_port <= 0) && (h->flags & AVIO_FLAG_READ))
s->local_port = port;
if (localaddr[0])
@@ -529,6 +691,8 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (udp_fd < 0)
goto fail;
+ s->local_addr_storage=my_addr; //store for future multicast join
+
/* Follow the requested reuse option, unless it's multicast in which
* case enable reuse unless explicitly disabled.
*/
@@ -538,6 +702,31 @@ static int udp_open(URLContext *h, const char *uri, int flags)
goto fail;
}
+ if (s->is_broadcast) {
+#ifdef SO_BROADCAST
+ if (setsockopt (udp_fd, SOL_SOCKET, SO_BROADCAST, &(s->is_broadcast), sizeof(s->is_broadcast)) != 0)
+#endif
+ goto fail;
+ }
+
+ /* Set the checksum coverage for UDP-Lite (RFC 3828) for sending and receiving.
+ * The receiver coverage has to be less than or equal to the sender coverage.
+ * Otherwise, the receiver will drop all packets.
+ */
+ if (s->udplite_coverage) {
+ if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0)
+ av_log(h, AV_LOG_WARNING, "socket option UDPLITE_SEND_CSCOV not available");
+
+ if (setsockopt (udp_fd, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV, &(s->udplite_coverage), sizeof(s->udplite_coverage)) != 0)
+ av_log(h, AV_LOG_WARNING, "socket option UDPLITE_RECV_CSCOV not available");
+ }
+
+ if (dscp >= 0) {
+ dscp <<= 2;
+ if (setsockopt (udp_fd, IPPROTO_IP, IP_TOS, &dscp, sizeof(dscp)) != 0)
+ goto fail;
+ }
+
/* If multicast, try binding the multicast address first, to avoid
* receiving UDP packets from other sources aimed at the same UDP
* port. This fails on windows. This makes sending to the same address
@@ -573,7 +762,7 @@ static int udp_open(URLContext *h, const char *uri, int flags)
if (udp_set_multicast_sources(udp_fd, (struct sockaddr *)&s->dest_addr, s->dest_addr_len, include_sources, num_include_sources, 1) < 0)
goto fail;
} else {
- if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr) < 0)
+ if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0)
goto fail;
}
if (num_exclude_sources) {
@@ -591,12 +780,20 @@ static int udp_open(URLContext *h, const char *uri, int flags)
goto fail;
}
} else {
- /* set udp recv buffer size to the largest possible udp packet size to
- * avoid losing data on OSes that set this too low by default. */
+ /* set udp recv buffer size to the requested value (default 64K) */
tmp = s->buffer_size;
if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) {
log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)");
}
+ len = sizeof(tmp);
+ if (getsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) {
+ log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)");
+ } else {
+ av_log(h, AV_LOG_DEBUG, "end receive buffer size reported is %d\n", tmp);
+ if(tmp < s->buffer_size)
+ av_log(h, AV_LOG_WARNING, "attempted to set receive buffer to size %d but it only ended up set as %d", s->buffer_size, tmp);
+ }
+
/* make the socket non-blocking */
ff_socket_nonblock(udp_fd, 1);
}
@@ -613,10 +810,43 @@ static int udp_open(URLContext *h, const char *uri, int flags)
av_freep(&exclude_sources[i]);
s->udp_fd = udp_fd;
+
+#if HAVE_PTHREAD_CANCEL
+ if (!is_output && s->circular_buffer_size) {
+ int ret;
+
+ /* start the task going */
+ s->fifo = av_fifo_alloc(s->circular_buffer_size);
+ ret = pthread_mutex_init(&s->mutex, NULL);
+ if (ret != 0) {
+ av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", strerror(ret));
+ goto fail;
+ }
+ ret = pthread_cond_init(&s->cond, NULL);
+ if (ret != 0) {
+ av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", strerror(ret));
+ goto cond_fail;
+ }
+ ret = pthread_create(&s->circular_buffer_thread, NULL, circular_buffer_task, h);
+ if (ret != 0) {
+ av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", strerror(ret));
+ goto thread_fail;
+ }
+ s->thread_started = 1;
+ }
+#endif
+
return 0;
+#if HAVE_PTHREAD_CANCEL
+ thread_fail:
+ pthread_cond_destroy(&s->cond);
+ cond_fail:
+ pthread_mutex_destroy(&s->mutex);
+#endif
fail:
if (udp_fd >= 0)
closesocket(udp_fd);
+ av_fifo_freep(&s->fifo);
for (i = 0; i < num_include_sources; i++)
av_freep(&include_sources[i]);
for (i = 0; i < num_exclude_sources; i++)
@@ -624,10 +854,64 @@ static int udp_open(URLContext *h, const char *uri, int flags)
return AVERROR(EIO);
}
+static int udplite_open(URLContext *h, const char *uri, int flags)
+{
+ UDPContext *s = h->priv_data;
+
+ // set default checksum coverage
+ s->udplite_coverage = UDP_HEADER_SIZE;
+
+ return udp_open(h, uri, flags);
+}
+
static int udp_read(URLContext *h, uint8_t *buf, int size)
{
UDPContext *s = h->priv_data;
int ret;
+#if HAVE_PTHREAD_CANCEL
+ int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK;
+
+ if (s->fifo) {
+ pthread_mutex_lock(&s->mutex);
+ do {
+ avail = av_fifo_size(s->fifo);
+ if (avail) { // >=size) {
+ uint8_t tmp[4];
+
+ av_fifo_generic_read(s->fifo, tmp, 4, NULL);
+ avail= AV_RL32(tmp);
+ if(avail > size){
+ av_log(h, AV_LOG_WARNING, "Part of datagram lost due to insufficient buffer size\n");
+ avail= size;
+ }
+
+ av_fifo_generic_read(s->fifo, buf, avail, NULL);
+ av_fifo_drain(s->fifo, AV_RL32(tmp) - avail);
+ pthread_mutex_unlock(&s->mutex);
+ return avail;
+ } else if(s->circular_buffer_error){
+ int err = s->circular_buffer_error;
+ pthread_mutex_unlock(&s->mutex);
+ return err;
+ } else if(nonblock) {
+ pthread_mutex_unlock(&s->mutex);
+ return AVERROR(EAGAIN);
+ }
+ else {
+ /* FIXME: using the monotonic clock would be better,
+ but it does not exist on all supported platforms. */
+ int64_t t = av_gettime() + 100000;
+ struct timespec tv = { .tv_sec = t / 1000000,
+ .tv_nsec = (t % 1000000) * 1000 };
+ if (pthread_cond_timedwait(&s->cond, &s->mutex, &tv) < 0) {
+ pthread_mutex_unlock(&s->mutex);
+ return AVERROR(errno == ETIMEDOUT ? EAGAIN : errno);
+ }
+ nonblock = 1;
+ }
+ } while( 1);
+ }
+#endif
if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
ret = ff_network_wait_fd(s->udp_fd, 0);
@@ -635,6 +919,7 @@ static int udp_read(URLContext *h, uint8_t *buf, int size)
return ret;
}
ret = recv(s->udp_fd, buf, size, 0);
+
return ret < 0 ? ff_neterrno() : ret;
}
@@ -664,8 +949,20 @@ static int udp_close(URLContext *h)
UDPContext *s = h->priv_data;
if (s->is_multicast && (h->flags & AVIO_FLAG_READ))
- udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr);
+ udp_leave_multicast_group(s->udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage);
closesocket(s->udp_fd);
+#if HAVE_PTHREAD_CANCEL
+ if (s->thread_started) {
+ int ret;
+ pthread_cancel(s->circular_buffer_thread);
+ ret = pthread_join(s->circular_buffer_thread, NULL);
+ if (ret != 0)
+ av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", strerror(ret));
+ pthread_mutex_destroy(&s->mutex);
+ pthread_cond_destroy(&s->cond);
+ }
+#endif
+ av_fifo_freep(&s->fifo);
return 0;
}
@@ -677,6 +974,18 @@ URLProtocol ff_udp_protocol = {
.url_close = udp_close,
.url_get_file_handle = udp_get_file_handle,
.priv_data_size = sizeof(UDPContext),
- .flags = URL_PROTOCOL_FLAG_NETWORK,
.priv_data_class = &udp_class,
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
+};
+
+URLProtocol ff_udplite_protocol = {
+ .name = "udplite",
+ .url_open = udplite_open,
+ .url_read = udp_read,
+ .url_write = udp_write,
+ .url_close = udp_close,
+ .url_get_file_handle = udp_get_file_handle,
+ .priv_data_size = sizeof(UDPContext),
+ .priv_data_class = &udplite_context_class,
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
};
diff --git a/libavformat/uncodedframecrcenc.c b/libavformat/uncodedframecrcenc.c
new file mode 100644
index 0000000000..414683fe23
--- /dev/null
+++ b/libavformat/uncodedframecrcenc.c
@@ -0,0 +1,172 @@
+/*
+* Copyright (c) 2013 Nicolas George
+*
+* This file is part of FFmpeg.
+*
+* FFmpeg is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public License
+* as published by the Free Software Foundation; either
+* version 2.1 of the License, or (at your option) any later version.
+*
+* FFmpeg is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "libavutil/adler32.h"
+#include "libavutil/avassert.h"
+#include "libavutil/bprint.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/pixdesc.h"
+#include "avformat.h"
+#include "internal.h"
+
+/* Identical to Adler32 when the type is uint8_t. */
+#define DEFINE_CKSUM_LINE(name, type, conv) \
+static void cksum_line_ ## name(unsigned *cksum, void *data, unsigned size) \
+{ \
+ type *p = data; \
+ unsigned a = *cksum & 0xFFFF, b = *cksum >> 16; \
+ for (; size > 0; size--, p++) { \
+ a = (a + (unsigned)(conv)) % 65521; \
+ b = (b + a) % 65521; \
+ } \
+ *cksum = a | (b << 16); \
+}
+
+DEFINE_CKSUM_LINE(u8, uint8_t, *p)
+DEFINE_CKSUM_LINE(s16, int16_t, *p + 0x8000)
+DEFINE_CKSUM_LINE(s32, int32_t, *p + 0x80000000)
+DEFINE_CKSUM_LINE(flt, float, *p * 0x80000000 + 0x80000000)
+DEFINE_CKSUM_LINE(dbl, double, *p * 0x80000000 + 0x80000000)
+
+static void video_frame_cksum(AVBPrint *bp, AVFrame *frame)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
+ int i, y;
+ uint8_t *data;
+ int linesize[5] = { 0 };
+
+ av_bprintf(bp, ", %d x %d", frame->width, frame->height);
+ if (!desc) {
+ av_bprintf(bp, ", unknown");
+ return;
+ }
+ if (av_image_fill_linesizes(linesize, frame->format, frame->width) < 0)
+ return;
+ av_bprintf(bp, ", %s", desc->name);
+ for (i = 0; linesize[i]; i++) {
+ unsigned cksum = 0;
+ int h = frame->height;
+ if ((i == 1 || i == 2) && desc->nb_components >= 3)
+ h = -((-h) >> desc->log2_chroma_h);
+ data = frame->data[i];
+ for (y = 0; y < h; y++) {
+ cksum = av_adler32_update(cksum, data, linesize[i]);
+ data += frame->linesize[i];
+ }
+ av_bprintf(bp, ", 0x%08x", cksum);
+ }
+}
+
+static void audio_frame_cksum(AVBPrint *bp, AVFrame *frame)
+{
+ int nb_planes, nb_samples, p;
+ const char *name;
+
+ nb_planes = av_frame_get_channels(frame);
+ nb_samples = frame->nb_samples;
+ if (!av_sample_fmt_is_planar(frame->format)) {
+ nb_samples *= nb_planes;
+ nb_planes = 1;
+ }
+ name = av_get_sample_fmt_name(frame->format);
+ av_bprintf(bp, ", %d samples", frame->nb_samples);
+ av_bprintf(bp, ", %s", name ? name : "unknown");
+ for (p = 0; p < nb_planes; p++) {
+ uint32_t cksum = 0;
+ void *d = frame->extended_data[p];
+ switch (frame->format) {
+ case AV_SAMPLE_FMT_U8:
+ case AV_SAMPLE_FMT_U8P:
+ cksum_line_u8(&cksum, d, nb_samples);
+ break;
+ case AV_SAMPLE_FMT_S16:
+ case AV_SAMPLE_FMT_S16P:
+ cksum_line_s16(&cksum, d, nb_samples);
+ break;
+ case AV_SAMPLE_FMT_S32:
+ case AV_SAMPLE_FMT_S32P:
+ cksum_line_s32(&cksum, d, nb_samples);
+ break;
+ case AV_SAMPLE_FMT_FLT:
+ case AV_SAMPLE_FMT_FLTP:
+ cksum_line_flt(&cksum, d, nb_samples);
+ break;
+ case AV_SAMPLE_FMT_DBL:
+ case AV_SAMPLE_FMT_DBLP:
+ cksum_line_dbl(&cksum, d, nb_samples);
+ break;
+ default:
+ av_assert0(!"reached");
+ }
+ av_bprintf(bp, ", 0x%08x", cksum);
+ }
+}
+
+static int write_frame(struct AVFormatContext *s, int stream_index,
+ AVFrame **frame, unsigned flags)
+{
+ AVBPrint bp;
+ int ret = 0;
+ enum AVMediaType type;
+ const char *type_name;
+
+ if ((flags & AV_WRITE_UNCODED_FRAME_QUERY))
+ return 0;
+
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&bp, "%d, %10"PRId64"",
+ stream_index, (*frame)->pts);
+ type = s->streams[stream_index]->codec->codec_type;
+ type_name = av_get_media_type_string(type);
+ av_bprintf(&bp, ", %s", type_name ? type_name : "unknown");
+ switch (type) {
+ case AVMEDIA_TYPE_VIDEO:
+ video_frame_cksum(&bp, *frame);
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ audio_frame_cksum(&bp, *frame);
+ break;
+ }
+
+ av_bprint_chars(&bp, '\n', 1);
+ if (av_bprint_is_complete(&bp))
+ avio_write(s->pb, bp.str, bp.len);
+ else
+ ret = AVERROR(ENOMEM);
+ av_bprint_finalize(&bp, NULL);
+ return ret;
+}
+
+static int write_packet(struct AVFormatContext *s, AVPacket *pkt)
+{
+ return AVERROR(ENOSYS);
+}
+
+AVOutputFormat ff_uncodedframecrc_muxer = {
+ .name = "uncodedframecrc",
+ .long_name = NULL_IF_CONFIG_SMALL("uncoded framecrc testing"),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_RAWVIDEO,
+ .write_header = ff_framehash_write_header,
+ .write_packet = write_packet,
+ .write_uncoded_frame = write_frame,
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT |
+ AVFMT_TS_NEGATIVE,
+};
diff --git a/libavformat/unix.c b/libavformat/unix.c
index 72b8fcdbbb..63d1db248f 100644
--- a/libavformat/unix.c
+++ b/libavformat/unix.c
@@ -2,20 +2,20 @@
* Unix socket protocol
* Copyright (c) 2013 Luca Barbato
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,12 +26,11 @@
*
*/
-#include <sys/un.h>
-
#include "libavutil/avstring.h"
#include "libavutil/opt.h"
#include "os_support.h"
#include "network.h"
+#include <sys/un.h>
#include "url.h"
typedef struct UnixContext {
diff --git a/libavformat/url-test.c b/libavformat/url-test.c
index 503b36e572..a1da82e493 100644
--- a/libavformat/url-test.c
+++ b/libavformat/url-test.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/url.c b/libavformat/url.c
index 92cd5f183a..596fb49cfc 100644
--- a/libavformat/url.c
+++ b/libavformat/url.c
@@ -2,20 +2,20 @@
* URL utility functions
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -68,7 +68,7 @@ int ff_url_join(char *str, int size, const char *proto,
av_strlcatf(str, size, ":%d", port);
if (fmt) {
va_list vl;
- int len = strlen(str);
+ size_t len = strlen(str);
va_start(vl, fmt);
vsnprintf(str + len, size > len ? size - len : 0, fmt, vl);
@@ -145,3 +145,19 @@ void ff_make_absolute_url(char *buf, int size, const char *base,
}
av_strlcat(buf, rel, size);
}
+
+AVIODirEntry *ff_alloc_dir_entry(void)
+{
+ AVIODirEntry *entry = av_mallocz(sizeof(AVIODirEntry));
+ if (entry) {
+ entry->type = AVIO_ENTRY_UNKNOWN;
+ entry->size = -1;
+ entry->modification_timestamp = -1;
+ entry->access_timestamp = -1;
+ entry->status_change_timestamp = -1;
+ entry->user_id = -1;
+ entry->group_id = -1;
+ entry->filemode = -1;
+ }
+ return entry;
+}
diff --git a/libavformat/url.h b/libavformat/url.h
index ca252aa7c2..1a845b77e7 100644
--- a/libavformat/url.h
+++ b/libavformat/url.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,6 +46,7 @@ typedef struct URLContext {
int is_streamed; /**< true if streamed (no seek possible), default = false */
int is_connected;
AVIOInterruptCB interrupt_callback;
+ int64_t rw_timeout; /**< maximum time to wait for (network) read/write operation completion, in mcs */
} URLContext;
typedef struct URLProtocol {
@@ -86,6 +87,9 @@ typedef struct URLProtocol {
const AVClass *priv_data_class;
int flags;
int (*url_check)(URLContext *h, int mask);
+ int (*url_open_dir)(URLContext *h);
+ int (*url_read_dir)(URLContext *h, AVIODirEntry **next);
+ int (*url_close_dir)(URLContext *h);
} URLProtocol;
/**
@@ -98,7 +102,7 @@ typedef struct URLProtocol {
* is to be opened
* @param int_cb interrupt callback to use for the URLContext, may be
* NULL
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffurl_alloc(URLContext **puc, const char *filename, int flags,
@@ -127,7 +131,7 @@ int ffurl_connect(URLContext *uc, AVDictionary **options);
* @param options A dictionary filled with protocol-private options. On return
* this parameter will be destroyed and replaced with a dict containing options
* that were not found. May be NULL.
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code in case of failure
*/
int ffurl_open(URLContext **puc, const char *filename, int flags,
@@ -179,11 +183,12 @@ int64_t ffurl_seek(URLContext *h, int64_t pos, int whence);
/**
* Close the resource accessed by the URLContext h, and free the
- * memory used by it.
+ * memory used by it. Also set the URLContext pointer to NULL.
*
* @return a negative value if an error condition occurred, 0
* otherwise
*/
+int ffurl_closep(URLContext **h);
int ffurl_close(URLContext *h);
/**
@@ -267,7 +272,7 @@ int ff_url_join(char *str, int size, const char *proto,
const char *authorization, const char *hostname,
int port, const char *fmt, ...) av_printf_format(7, 8);
-/*
+/**
* Convert a relative url into an absolute url, given a base url.
*
* @param buf the buffer where output absolute url is written
@@ -278,5 +283,12 @@ int ff_url_join(char *str, int size, const char *proto,
void ff_make_absolute_url(char *buf, int size, const char *base,
const char *rel);
+/**
+ * Allocate directory entry with default values.
+ *
+ * @return entry or NULL on error
+ */
+AVIODirEntry *ff_alloc_dir_entry(void);
+
#endif /* AVFORMAT_URL_H */
diff --git a/libavformat/urldecode.c b/libavformat/urldecode.c
index 49af9ba1e0..283d912671 100644
--- a/libavformat/urldecode.c
+++ b/libavformat/urldecode.c
@@ -9,20 +9,20 @@
* based on http://www.icosaedro.it/apache/urldecode.c
* from Umberto Salsi (salsi@icosaedro.it)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/urldecode.h b/libavformat/urldecode.h
index b43f319c9e..cb81ebc6f7 100644
--- a/libavformat/urldecode.h
+++ b/libavformat/urldecode.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 18cd0d72d7..db2b4f6768 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1,26 +1,24 @@
/*
- * various utility functions for use within Libav
+ * various utility functions for use within FFmpeg
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#undef NDEBUG
-#include <assert.h>
#include <stdarg.h>
#include <stdint.h>
@@ -35,12 +33,15 @@
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/time.h"
+#include "libavutil/timestamp.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/internal.h"
+#include "libavcodec/raw.h"
#include "audiointerleave.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "id3v2.h"
#include "internal.h"
#include "metadata.h"
@@ -50,38 +51,157 @@
#include "riff.h"
#include "url.h"
+#include "libavutil/ffversion.h"
+const char av_format_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
/**
* @file
- * various utility functions for use within Libav
+ * various utility functions for use within FFmpeg
*/
unsigned avformat_version(void)
{
+ av_assert0(LIBAVFORMAT_VERSION_MICRO >= 100);
return LIBAVFORMAT_VERSION_INT;
}
const char *avformat_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char *avformat_license(void)
{
#define LICENSE_PREFIX "libavformat license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+}
+
+#define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48))
+
+static int is_relative(int64_t ts) {
+ return ts > (RELATIVE_TS_BASE - (1LL<<48));
+}
+
+/**
+ * Wrap a given time stamp, if there is an indication for an overflow
+ *
+ * @param st stream
+ * @param timestamp the time stamp to wrap
+ * @return resulting time stamp
+ */
+static int64_t wrap_timestamp(AVStream *st, int64_t timestamp)
+{
+ if (st->pts_wrap_behavior != AV_PTS_WRAP_IGNORE &&
+ st->pts_wrap_reference != AV_NOPTS_VALUE && timestamp != AV_NOPTS_VALUE) {
+ if (st->pts_wrap_behavior == AV_PTS_WRAP_ADD_OFFSET &&
+ timestamp < st->pts_wrap_reference)
+ return timestamp + (1ULL << st->pts_wrap_bits);
+ else if (st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET &&
+ timestamp >= st->pts_wrap_reference)
+ return timestamp - (1ULL << st->pts_wrap_bits);
+ }
+ return timestamp;
+}
+
+MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate)
+MAKE_ACCESSORS(AVStream, stream, char *, recommended_encoder_configuration)
+MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec)
+MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec)
+MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec)
+MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, data_codec)
+MAKE_ACCESSORS(AVFormatContext, format, int, metadata_header_padding)
+MAKE_ACCESSORS(AVFormatContext, format, void *, opaque)
+MAKE_ACCESSORS(AVFormatContext, format, av_format_control_message, control_message_cb)
+MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb)
+
+int64_t av_stream_get_end_pts(const AVStream *st)
+{
+ return st->pts.val;
+}
+
+struct AVCodecParserContext *av_stream_get_parser(const AVStream *st)
+{
+ return st->parser;
+}
+
+void av_format_inject_global_side_data(AVFormatContext *s)
+{
+ int i;
+ s->internal->inject_global_side_data = 1;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ st->inject_global_side_data = 1;
+ }
+}
+
+int ff_copy_whitelists(AVFormatContext *dst, AVFormatContext *src)
+{
+ av_assert0(!dst->codec_whitelist && !dst->format_whitelist);
+ dst-> codec_whitelist = av_strdup(src->codec_whitelist);
+ dst->format_whitelist = av_strdup(src->format_whitelist);
+ if ( (src-> codec_whitelist && !dst-> codec_whitelist)
+ || (src->format_whitelist && !dst->format_whitelist)) {
+ av_log(dst, AV_LOG_ERROR, "Failed to duplicate whitelist\n");
+ return AVERROR(ENOMEM);
+ }
+ return 0;
+}
+
+static const AVCodec *find_decoder(AVFormatContext *s, AVStream *st, enum AVCodecID codec_id)
+{
+ if (st->codec->codec)
+ return st->codec->codec;
+
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (s->video_codec) return s->video_codec;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if (s->audio_codec) return s->audio_codec;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (s->subtitle_codec) return s->subtitle_codec;
+ break;
+ }
+
+ return avcodec_find_decoder(codec_id);
+}
+
+int av_format_get_probe_score(const AVFormatContext *s)
+{
+ return s->probe_score;
}
/* an arbitrarily chosen "sane" max packet size -- 50M */
#define SANE_CHUNK_SIZE (50000000)
+int ffio_limit(AVIOContext *s, int size)
+{
+ if (s->maxsize>= 0) {
+ int64_t remaining= s->maxsize - avio_tell(s);
+ if (remaining < size) {
+ int64_t newsize = avio_size(s);
+ if (!s->maxsize || s->maxsize<newsize)
+ s->maxsize = newsize - !newsize;
+ remaining= s->maxsize - avio_tell(s);
+ remaining= FFMAX(remaining, 0);
+ }
+
+ if (s->maxsize>= 0 && remaining+1 < size) {
+ av_log(NULL, remaining ? AV_LOG_ERROR : AV_LOG_DEBUG, "Truncating packet of size %d to %"PRId64"\n", size, remaining+1);
+ size = remaining+1;
+ }
+ }
+ return size;
+}
+
/* Read the data in sane-sized chunks and append to pkt.
* Return the number of bytes read or an error. */
static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size)
{
- int64_t chunk_size = size;
int64_t orig_pos = pkt->pos; // av_grow_packet might reset pos
int orig_size = pkt->size;
- int ret = 0;
+ int ret;
do {
int prev_size = pkt->size;
@@ -89,11 +209,13 @@ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size)
/* When the caller requests a lot of data, limit it to the amount
* left in file or SANE_CHUNK_SIZE when it is not known. */
- if (size > SANE_CHUNK_SIZE) {
- int64_t filesize = avio_size(s) - avio_tell(s);
- chunk_size = FFMAX(filesize, SANE_CHUNK_SIZE);
+ read_size = size;
+ if (read_size > SANE_CHUNK_SIZE/10) {
+ read_size = ffio_limit(s, read_size);
+ // If filesize/maxsize is unknown, limit to SANE_CHUNK_SIZE
+ if (s->maxsize < 0)
+ read_size = FFMIN(read_size, SANE_CHUNK_SIZE);
}
- read_size = FFMIN(size, chunk_size);
ret = av_grow_packet(pkt, read_size);
if (ret < 0)
@@ -107,6 +229,8 @@ static int append_packet_chunked(AVIOContext *s, AVPacket *pkt, int size)
size -= read_size;
} while (size > 0);
+ if (size > 0)
+ pkt->flags |= AV_PKT_FLAG_CORRUPT;
pkt->pos = orig_pos;
if (!pkt->size)
@@ -139,7 +263,7 @@ int av_filename_number_test(const char *filename)
}
static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st,
- AVProbeData *pd, int score)
+ AVProbeData *pd)
{
static const struct {
const char *name;
@@ -149,17 +273,20 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st,
{ "aac", AV_CODEC_ID_AAC, AVMEDIA_TYPE_AUDIO },
{ "ac3", AV_CODEC_ID_AC3, AVMEDIA_TYPE_AUDIO },
{ "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO },
+ { "dvbsub", AV_CODEC_ID_DVB_SUBTITLE,AVMEDIA_TYPE_SUBTITLE },
{ "eac3", AV_CODEC_ID_EAC3, AVMEDIA_TYPE_AUDIO },
{ "h264", AV_CODEC_ID_H264, AVMEDIA_TYPE_VIDEO },
- { "latm", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO },
+ { "hevc", AV_CODEC_ID_HEVC, AVMEDIA_TYPE_VIDEO },
+ { "loas", AV_CODEC_ID_AAC_LATM, AVMEDIA_TYPE_AUDIO },
{ "m4v", AV_CODEC_ID_MPEG4, AVMEDIA_TYPE_VIDEO },
{ "mp3", AV_CODEC_ID_MP3, AVMEDIA_TYPE_AUDIO },
{ "mpegvideo", AV_CODEC_ID_MPEG2VIDEO, AVMEDIA_TYPE_VIDEO },
{ 0 }
};
- AVInputFormat *fmt = av_probe_input_format2(pd, 1, &score);
+ int score;
+ AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score);
- if (fmt) {
+ if (fmt && st->request_probe <= score) {
int i;
av_log(s, AV_LOG_DEBUG,
"Probe with size=%d, packets=%d detected %s with score=%d\n",
@@ -169,44 +296,66 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st,
if (!strcmp(fmt->name, fmt_id_type[i].name)) {
st->codec->codec_id = fmt_id_type[i].id;
st->codec->codec_type = fmt_id_type[i].type;
- break;
+ return score;
}
}
}
- return !!fmt;
+ return 0;
}
/************************************************************/
/* input media file */
+int av_demuxer_open(AVFormatContext *ic) {
+ int err;
+
+ if (ic->format_whitelist && av_match_list(ic->iformat->name, ic->format_whitelist, ',') <= 0) {
+ av_log(ic, AV_LOG_ERROR, "Format not on whitelist\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (ic->iformat->read_header) {
+ err = ic->iformat->read_header(ic);
+ if (err < 0)
+ return err;
+ }
+
+ if (ic->pb && !ic->internal->data_offset)
+ ic->internal->data_offset = avio_tell(ic->pb);
+
+ return 0;
+}
+
/* Open input file and probe the format if necessary. */
static int init_input(AVFormatContext *s, const char *filename,
AVDictionary **options)
{
int ret;
AVProbeData pd = { filename, NULL, 0 };
+ int score = AVPROBE_SCORE_RETRY;
if (s->pb) {
s->flags |= AVFMT_FLAG_CUSTOM_IO;
if (!s->iformat)
- return av_probe_input_buffer(s->pb, &s->iformat, filename,
- s, 0, s->probesize);
+ return av_probe_input_buffer2(s->pb, &s->iformat, filename,
+ s, 0, s->format_probesize);
else if (s->iformat->flags & AVFMT_NOFILE)
- return AVERROR(EINVAL);
+ av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
+ "will be ignored with AVFMT_NOFILE format.\n");
return 0;
}
if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
- (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0))))
- return 0;
+ (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
+ return score;
- if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ,
+ if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,
&s->interrupt_callback, options)) < 0)
return ret;
if (s->iformat)
return 0;
- return av_probe_input_buffer(s->pb, &s->iformat, filename,
- s, 0, s->probesize);
+ return av_probe_input_buffer2(s->pb, &s->iformat, filename,
+ s, 0, s->format_probesize);
}
static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
@@ -227,13 +376,19 @@ static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
return &pktl->pkt;
}
-static int queue_attached_pictures(AVFormatContext *s)
+int avformat_queue_attached_pictures(AVFormatContext *s)
{
int i;
for (i = 0; i < s->nb_streams; i++)
if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC &&
s->streams[i]->discard < AVDISCARD_ALL) {
AVPacket copy = s->streams[i]->attached_pic;
+ if (copy.size <= 0) {
+ av_log(s, AV_LOG_WARNING,
+ "Attached picture on stream %d has invalid size, "
+ "ignoring\n", i);
+ continue;
+ }
copy.buf = av_buffer_ref(copy.buf);
if (!copy.buf)
return AVERROR(ENOMEM);
@@ -254,17 +409,33 @@ int avformat_open_input(AVFormatContext **ps, const char *filename,
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
+ if (!s->av_class) {
+ av_log(NULL, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");
+ return AVERROR(EINVAL);
+ }
if (fmt)
s->iformat = fmt;
if (options)
av_dict_copy(&tmp, *options, 0);
+ if (s->pb) // must be before any goto fail
+ s->flags |= AVFMT_FLAG_CUSTOM_IO;
+
if ((ret = av_opt_set_dict(s, &tmp)) < 0)
goto fail;
if ((ret = init_input(s, filename, &tmp)) < 0)
goto fail;
+ s->probe_score = ret;
+
+ if (s->format_whitelist && av_match_list(s->iformat->name, s->format_whitelist, ',') <= 0) {
+ av_log(s, AV_LOG_ERROR, "Format not on whitelist\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ avio_skip(s->pb, s->skip_initial_bytes);
/* Check filename in case an image number is expected. */
if (s->iformat->flags & AVFMT_NEEDNUMBER) {
@@ -293,21 +464,26 @@ int avformat_open_input(AVFormatContext **ps, const char *filename,
/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if (s->pb)
- ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, 0);
- if (s->iformat->read_header)
+ if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
- if (id3v2_extra_meta &&
- (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
- goto fail;
+ if (id3v2_extra_meta) {
+ if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") ||
+ !strcmp(s->iformat->name, "tta")) {
+ if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
+ goto fail;
+ } else
+ av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n");
+ }
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
- if ((ret = queue_attached_pictures(s)) < 0)
+ if ((ret = avformat_queue_attached_pictures(s)) < 0)
goto fail;
- if (s->pb && !s->internal->data_offset)
+ if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->internal->data_offset)
s->internal->data_offset = avio_tell(s->pb);
s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
@@ -323,7 +499,7 @@ fail:
ff_id3v2_free_extra_meta(&id3v2_extra_meta);
av_dict_free(&tmp);
if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
- avio_close(s->pb);
+ avio_closep(&s->pb);
avformat_free_context(s);
*ps = NULL;
return ret;
@@ -331,44 +507,140 @@ fail:
/*******************************************************/
+static void force_codec_ids(AVFormatContext *s, AVStream *st)
+{
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ if (s->video_codec_id)
+ st->codec->codec_id = s->video_codec_id;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ if (s->audio_codec_id)
+ st->codec->codec_id = s->audio_codec_id;
+ break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (s->subtitle_codec_id)
+ st->codec->codec_id = s->subtitle_codec_id;
+ break;
+ }
+}
+
static int probe_codec(AVFormatContext *s, AVStream *st, const AVPacket *pkt)
{
- if (st->codec->codec_id == AV_CODEC_ID_PROBE) {
+ if (st->request_probe>0) {
AVProbeData *pd = &st->probe_data;
- av_log(s, AV_LOG_DEBUG, "probing stream %d\n", st->index);
+ int end;
+ av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets);
--st->probe_packets;
if (pkt) {
- int err;
- if ((err = av_reallocp(&pd->buf, pd->buf_size + pkt->size +
- AVPROBE_PADDING_SIZE)) < 0)
- return err;
+ uint8_t *new_buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);
+ if (!new_buf) {
+ av_log(s, AV_LOG_WARNING,
+ "Failed to reallocate probe buffer for stream %d\n",
+ st->index);
+ goto no_packet;
+ }
+ pd->buf = new_buf;
memcpy(pd->buf + pd->buf_size, pkt->data, pkt->size);
pd->buf_size += pkt->size;
memset(pd->buf + pd->buf_size, 0, AVPROBE_PADDING_SIZE);
} else {
+no_packet:
st->probe_packets = 0;
if (!pd->buf_size) {
- av_log(s, AV_LOG_ERROR,
+ av_log(s, AV_LOG_WARNING,
"nothing to probe for stream %d\n", st->index);
- return 0;
}
}
- if (!st->probe_packets ||
- av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) {
- set_codec_from_probe_data(s, st, pd, st->probe_packets > 0
- ? AVPROBE_SCORE_MAX / 4 : 0);
- if (st->codec->codec_id != AV_CODEC_ID_PROBE) {
+ end= s->internal->raw_packet_buffer_remaining_size <= 0
+ || st->probe_packets<= 0;
+
+ if (end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)) {
+ int score = set_codec_from_probe_data(s, st, pd);
+ if ( (st->codec->codec_id != AV_CODEC_ID_NONE && score > AVPROBE_SCORE_STREAM_RETRY)
+ || end) {
pd->buf_size = 0;
av_freep(&pd->buf);
- av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
+ st->request_probe = -1;
+ if (st->codec->codec_id != AV_CODEC_ID_NONE) {
+ av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);
+ } else
+ av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index);
}
+ force_codec_ids(s, st);
}
}
return 0;
}
+static int update_wrap_reference(AVFormatContext *s, AVStream *st, int stream_index, AVPacket *pkt)
+{
+ int64_t ref = pkt->dts;
+ int i, pts_wrap_behavior;
+ int64_t pts_wrap_reference;
+ AVProgram *first_program;
+
+ if (ref == AV_NOPTS_VALUE)
+ ref = pkt->pts;
+ if (st->pts_wrap_reference != AV_NOPTS_VALUE || st->pts_wrap_bits >= 63 || ref == AV_NOPTS_VALUE || !s->correct_ts_overflow)
+ return 0;
+ ref &= (1LL << st->pts_wrap_bits)-1;
+
+ // reference time stamp should be 60 s before first time stamp
+ pts_wrap_reference = ref - av_rescale(60, st->time_base.den, st->time_base.num);
+ // if first time stamp is not more than 1/8 and 60s before the wrap point, subtract rather than add wrap offset
+ pts_wrap_behavior = (ref < (1LL << st->pts_wrap_bits) - (1LL << st->pts_wrap_bits-3)) ||
+ (ref < (1LL << st->pts_wrap_bits) - av_rescale(60, st->time_base.den, st->time_base.num)) ?
+ AV_PTS_WRAP_ADD_OFFSET : AV_PTS_WRAP_SUB_OFFSET;
+
+ first_program = av_find_program_from_stream(s, NULL, stream_index);
+
+ if (!first_program) {
+ int default_stream_index = av_find_default_stream_index(s);
+ if (s->streams[default_stream_index]->pts_wrap_reference == AV_NOPTS_VALUE) {
+ for (i = 0; i < s->nb_streams; i++) {
+ if (av_find_program_from_stream(s, NULL, i))
+ continue;
+ s->streams[i]->pts_wrap_reference = pts_wrap_reference;
+ s->streams[i]->pts_wrap_behavior = pts_wrap_behavior;
+ }
+ }
+ else {
+ st->pts_wrap_reference = s->streams[default_stream_index]->pts_wrap_reference;
+ st->pts_wrap_behavior = s->streams[default_stream_index]->pts_wrap_behavior;
+ }
+ }
+ else {
+ AVProgram *program = first_program;
+ while (program) {
+ if (program->pts_wrap_reference != AV_NOPTS_VALUE) {
+ pts_wrap_reference = program->pts_wrap_reference;
+ pts_wrap_behavior = program->pts_wrap_behavior;
+ break;
+ }
+ program = av_find_program_from_stream(s, program, stream_index);
+ }
+
+ // update every program with differing pts_wrap_reference
+ program = first_program;
+ while (program) {
+ if (program->pts_wrap_reference != pts_wrap_reference) {
+ for (i = 0; i<program->nb_stream_indexes; i++) {
+ s->streams[program->stream_index[i]]->pts_wrap_reference = pts_wrap_reference;
+ s->streams[program->stream_index[i]]->pts_wrap_behavior = pts_wrap_behavior;
+ }
+
+ program->pts_wrap_reference = pts_wrap_reference;
+ program->pts_wrap_behavior = pts_wrap_behavior;
+ }
+ program = av_find_program_from_stream(s, program, stream_index);
+ }
+ }
+ return 1;
+}
+
int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, i, err;
@@ -380,16 +652,10 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (pktl) {
*pkt = pktl->pkt;
st = s->streams[pkt->stream_index];
- if (st->codec->codec_id != AV_CODEC_ID_PROBE ||
- !st->probe_packets ||
- s->internal->raw_packet_buffer_remaining_size < pkt->size) {
- AVProbeData *pd;
- if (st->probe_packets)
- if ((err = probe_codec(s, st, NULL)) < 0)
- return err;
- pd = &st->probe_data;
- av_freep(&pd->buf);
- pd->buf_size = 0;
+ if (s->internal->raw_packet_buffer_remaining_size <= 0)
+ if ((err = probe_codec(s, st, NULL)) < 0)
+ return err;
+ if (st->request_probe <= 0) {
s->internal->raw_packet_buffer = pktl->next;
s->internal->raw_packet_buffer_remaining_size += pkt->size;
av_free(pktl);
@@ -409,6 +675,7 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (st->probe_packets)
if ((err = probe_codec(s, st, NULL)) < 0)
return err;
+ av_assert0(st->request_probe <= 0);
}
continue;
}
@@ -422,25 +689,33 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
continue;
}
+ if (pkt->stream_index >= (unsigned)s->nb_streams) {
+ av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index);
+ continue;
+ }
+
st = s->streams[pkt->stream_index];
- switch (st->codec->codec_type) {
- case AVMEDIA_TYPE_VIDEO:
- if (s->video_codec_id)
- st->codec->codec_id = s->video_codec_id;
- break;
- case AVMEDIA_TYPE_AUDIO:
- if (s->audio_codec_id)
- st->codec->codec_id = s->audio_codec_id;
- break;
- case AVMEDIA_TYPE_SUBTITLE:
- if (s->subtitle_codec_id)
- st->codec->codec_id = s->subtitle_codec_id;
- break;
+ if (update_wrap_reference(s, st, pkt->stream_index, pkt) && st->pts_wrap_behavior == AV_PTS_WRAP_SUB_OFFSET) {
+ // correct first time stamps to negative values
+ if (!is_relative(st->first_dts))
+ st->first_dts = wrap_timestamp(st, st->first_dts);
+ if (!is_relative(st->start_time))
+ st->start_time = wrap_timestamp(st, st->start_time);
+ if (!is_relative(st->cur_dts))
+ st->cur_dts = wrap_timestamp(st, st->cur_dts);
}
- if (!pktl && (st->codec->codec_id != AV_CODEC_ID_PROBE ||
- !st->probe_packets))
+ pkt->dts = wrap_timestamp(st, pkt->dts);
+ pkt->pts = wrap_timestamp(st, pkt->pts);
+
+ force_codec_ids(s, st);
+
+ /* TODO: audio: time filter; video: frame reordering (pts != dts) */
+ if (s->use_wallclock_as_timestamps)
+ pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
+
+ if (!pktl && st->request_probe <= 0)
return ret;
add_to_pktbuf(&s->internal->raw_packet_buffer, pkt,
@@ -452,8 +727,20 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
}
}
+
/**********************************************************/
+static int determinable_frame_size(AVCodecContext *avctx)
+{
+ if (/*avctx->codec_id == AV_CODEC_ID_AAC ||*/
+ avctx->codec_id == AV_CODEC_ID_MP1 ||
+ avctx->codec_id == AV_CODEC_ID_MP2 ||
+ avctx->codec_id == AV_CODEC_ID_MP3/* ||
+ avctx->codec_id == AV_CODEC_ID_CELT*/)
+ return 1;
+ return 0;
+}
+
/**
* Return the frame duration in seconds. Return 0 if not available.
*/
@@ -461,27 +748,32 @@ void ff_compute_frame_duration(AVFormatContext *s, int *pnum, int *pden, AVStrea
AVCodecParserContext *pc, AVPacket *pkt)
{
AVRational codec_framerate = s->iformat ? st->codec->framerate :
- av_inv_q(st->codec->time_base);
+ av_mul_q(av_inv_q(st->codec->time_base), (AVRational){1, st->codec->ticks_per_frame});
int frame_size;
*pnum = 0;
*pden = 0;
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_VIDEO:
- if (st->avg_frame_rate.num) {
- *pnum = st->avg_frame_rate.den;
- *pden = st->avg_frame_rate.num;
+ if (st->r_frame_rate.num && !pc && s->iformat) {
+ *pnum = st->r_frame_rate.den;
+ *pden = st->r_frame_rate.num;
} else if (st->time_base.num * 1000LL > st->time_base.den) {
*pnum = st->time_base.num;
*pden = st->time_base.den;
} else if (codec_framerate.den * 1000LL > codec_framerate.num) {
- *pnum = codec_framerate.den;
- *pden = codec_framerate.num;
+ av_assert0(st->codec->ticks_per_frame);
+ av_reduce(pnum, pden,
+ codec_framerate.den,
+ codec_framerate.num * (int64_t)st->codec->ticks_per_frame,
+ INT_MAX);
+
if (pc && pc->repeat_pict) {
- if (*pnum > INT_MAX / (1 + pc->repeat_pict))
- *pden /= 1 + pc->repeat_pict;
- else
- *pnum *= 1 + pc->repeat_pict;
+ av_assert0(s->iformat); // this may be wrong for interlaced encoding but its not used for that case
+ av_reduce(pnum, pden,
+ (*pnum) * (1LL + pc->repeat_pict),
+ (*pden),
+ INT_MAX);
}
/* If this codec can be interlaced or progressive then we need
* a parser to compute duration of a packet. Thus if we have
@@ -502,43 +794,138 @@ void ff_compute_frame_duration(AVFormatContext *s, int *pnum, int *pden, AVStrea
}
}
-static int is_intra_only(enum AVCodecID id)
+static int is_intra_only(AVCodecContext *enc) {
+ const AVCodecDescriptor *desc;
+
+ if (enc->codec_type != AVMEDIA_TYPE_VIDEO)
+ return 1;
+
+ desc = av_codec_get_codec_descriptor(enc);
+ if (!desc) {
+ desc = avcodec_descriptor_get(enc->codec_id);
+ av_codec_set_codec_descriptor(enc, desc);
+ }
+ if (desc)
+ return !!(desc->props & AV_CODEC_PROP_INTRA_ONLY);
+ return 0;
+}
+
+static int has_decode_delay_been_guessed(AVStream *st)
{
- const AVCodecDescriptor *d = avcodec_descriptor_get(id);
- if (!d)
- return 0;
- if (d->type == AVMEDIA_TYPE_VIDEO && !(d->props & AV_CODEC_PROP_INTRA_ONLY))
- return 0;
- return 1;
+ if (st->codec->codec_id != AV_CODEC_ID_H264) return 1;
+ if (!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy
+ return 1;
+#if CONFIG_H264_DECODER
+ if (st->codec->has_b_frames &&
+ avpriv_h264_has_num_reorder_frames(st->codec) == st->codec->has_b_frames)
+ return 1;
+#endif
+ if (st->codec->has_b_frames<3)
+ return st->nb_decoded_frames >= 7;
+ else if (st->codec->has_b_frames<4)
+ return st->nb_decoded_frames >= 18;
+ else
+ return st->nb_decoded_frames >= 20;
+}
+
+static AVPacketList *get_next_pkt(AVFormatContext *s, AVStream *st, AVPacketList *pktl)
+{
+ if (pktl->next)
+ return pktl->next;
+ if (pktl == s->internal->packet_buffer_end)
+ return s->internal->parse_queue;
+ return NULL;
+}
+
+static int64_t select_from_pts_buffer(AVStream *st, int64_t *pts_buffer, int64_t dts) {
+ int onein_oneout = st->codec->codec_id != AV_CODEC_ID_H264 &&
+ st->codec->codec_id != AV_CODEC_ID_HEVC;
+
+ if(!onein_oneout) {
+ int delay = st->codec->has_b_frames;
+ int i;
+
+ if (dts == AV_NOPTS_VALUE) {
+ int64_t best_score = INT64_MAX;
+ for (i = 0; i<delay; i++) {
+ if (st->pts_reorder_error_count[i]) {
+ int64_t score = st->pts_reorder_error[i] / st->pts_reorder_error_count[i];
+ if (score < best_score) {
+ best_score = score;
+ dts = pts_buffer[i];
+ }
+ }
+ }
+ } else {
+ for (i = 0; i<delay; i++) {
+ if (pts_buffer[i] != AV_NOPTS_VALUE) {
+ int64_t diff = FFABS(pts_buffer[i] - dts)
+ + (uint64_t)st->pts_reorder_error[i];
+ diff = FFMAX(diff, st->pts_reorder_error[i]);
+ st->pts_reorder_error[i] = diff;
+ st->pts_reorder_error_count[i]++;
+ if (st->pts_reorder_error_count[i] > 250) {
+ st->pts_reorder_error[i] >>= 1;
+ st->pts_reorder_error_count[i] >>= 1;
+ }
+ }
+ }
+ }
+ }
+
+ if (dts == AV_NOPTS_VALUE)
+ dts = pts_buffer[0];
+
+ return dts;
}
static void update_initial_timestamps(AVFormatContext *s, int stream_index,
- int64_t dts, int64_t pts)
+ int64_t dts, int64_t pts, AVPacket *pkt)
{
AVStream *st = s->streams[stream_index];
- AVPacketList *pktl = s->internal->packet_buffer;
+ AVPacketList *pktl = s->internal->packet_buffer ? s->internal->packet_buffer : s->internal->parse_queue;
+ int64_t pts_buffer[MAX_REORDER_DELAY+1];
+ int64_t shift;
+ int i, delay;
if (st->first_dts != AV_NOPTS_VALUE ||
dts == AV_NOPTS_VALUE ||
- st->cur_dts == AV_NOPTS_VALUE)
+ st->cur_dts == AV_NOPTS_VALUE ||
+ is_relative(dts))
return;
- st->first_dts = dts - st->cur_dts;
+ delay = st->codec->has_b_frames;
+ st->first_dts = dts - (st->cur_dts - RELATIVE_TS_BASE);
st->cur_dts = dts;
+ shift = st->first_dts - RELATIVE_TS_BASE;
- for (; pktl; pktl = pktl->next) {
+ for (i = 0; i<MAX_REORDER_DELAY+1; i++)
+ pts_buffer[i] = AV_NOPTS_VALUE;
+
+ if (is_relative(pts))
+ pts += shift;
+
+ for (; pktl; pktl = get_next_pkt(s, st, pktl)) {
if (pktl->pkt.stream_index != stream_index)
continue;
- // FIXME: think more about this check
- if (pktl->pkt.pts != AV_NOPTS_VALUE && pktl->pkt.pts == pktl->pkt.dts)
- pktl->pkt.pts += st->first_dts;
+ if (is_relative(pktl->pkt.pts))
+ pktl->pkt.pts += shift;
- if (pktl->pkt.dts != AV_NOPTS_VALUE)
- pktl->pkt.dts += st->first_dts;
+ if (is_relative(pktl->pkt.dts))
+ pktl->pkt.dts += shift;
if (st->start_time == AV_NOPTS_VALUE && pktl->pkt.pts != AV_NOPTS_VALUE)
st->start_time = pktl->pkt.pts;
+
+ if (pktl->pkt.pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)) {
+ pts_buffer[0] = pktl->pkt.pts;
+ for (i = 0; i<delay && pts_buffer[i] > pts_buffer[i + 1]; i++)
+ FFSWAP(int64_t, pts_buffer[i], pts_buffer[i + 1]);
+
+ pktl->pkt.dts = select_from_pts_buffer(st, pts_buffer, pktl->pkt.dts);
+ }
}
+
if (st->start_time == AV_NOPTS_VALUE)
st->start_time = pts;
}
@@ -546,12 +933,15 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
static void update_initial_durations(AVFormatContext *s, AVStream *st,
int stream_index, int duration)
{
- AVPacketList *pktl = s->internal->packet_buffer;
- int64_t cur_dts = 0;
+ AVPacketList *pktl = s->internal->packet_buffer ? s->internal->packet_buffer : s->internal->parse_queue;
+ int64_t cur_dts = RELATIVE_TS_BASE;
if (st->first_dts != AV_NOPTS_VALUE) {
+ if (st->update_initial_durations_done)
+ return;
+ st->update_initial_durations_done = 1;
cur_dts = st->first_dts;
- for (; pktl; pktl = pktl->next) {
+ for (; pktl; pktl = get_next_pkt(s, st, pktl)) {
if (pktl->pkt.stream_index == stream_index) {
if (pktl->pkt.pts != pktl->pkt.dts ||
pktl->pkt.dts != AV_NOPTS_VALUE ||
@@ -560,42 +950,82 @@ static void update_initial_durations(AVFormatContext *s, AVStream *st,
cur_dts -= duration;
}
}
- pktl = s->internal->packet_buffer;
+ if (pktl && pktl->pkt.dts != st->first_dts) {
+ av_log(s, AV_LOG_DEBUG, "first_dts %s not matching first dts %s (pts %s, duration %d) in the queue\n",
+ av_ts2str(st->first_dts), av_ts2str(pktl->pkt.dts), av_ts2str(pktl->pkt.pts), pktl->pkt.duration);
+ return;
+ }
+ if (!pktl) {
+ av_log(s, AV_LOG_DEBUG, "first_dts %s but no packet with dts in the queue\n", av_ts2str(st->first_dts));
+ return;
+ }
+ pktl = s->internal->packet_buffer ? s->internal->packet_buffer : s->internal->parse_queue;
st->first_dts = cur_dts;
- } else if (st->cur_dts)
+ } else if (st->cur_dts != RELATIVE_TS_BASE)
return;
- for (; pktl; pktl = pktl->next) {
+ for (; pktl; pktl = get_next_pkt(s, st, pktl)) {
if (pktl->pkt.stream_index != stream_index)
continue;
if (pktl->pkt.pts == pktl->pkt.dts &&
- pktl->pkt.dts == AV_NOPTS_VALUE &&
+ (pktl->pkt.dts == AV_NOPTS_VALUE || pktl->pkt.dts == st->first_dts) &&
!pktl->pkt.duration) {
pktl->pkt.dts = cur_dts;
if (!st->codec->has_b_frames)
pktl->pkt.pts = cur_dts;
- cur_dts += duration;
- if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
+// if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO)
pktl->pkt.duration = duration;
} else
break;
+ cur_dts = pktl->pkt.dts + pktl->pkt.duration;
}
- if (st->first_dts == AV_NOPTS_VALUE)
+ if (!pktl)
st->cur_dts = cur_dts;
}
static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
- AVCodecParserContext *pc, AVPacket *pkt)
+ AVCodecParserContext *pc, AVPacket *pkt,
+ int64_t next_dts, int64_t next_pts)
{
int num, den, presentation_delayed, delay, i;
int64_t offset;
+ AVRational duration;
+ int onein_oneout = st->codec->codec_id != AV_CODEC_ID_H264 &&
+ st->codec->codec_id != AV_CODEC_ID_HEVC;
if (s->flags & AVFMT_FLAG_NOFILLIN)
return;
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && pkt->dts != AV_NOPTS_VALUE) {
+ if (pkt->dts == pkt->pts && st->last_dts_for_order_check != AV_NOPTS_VALUE) {
+ if (st->last_dts_for_order_check <= pkt->dts) {
+ st->dts_ordered++;
+ } else {
+ av_log(s, st->dts_misordered ? AV_LOG_DEBUG : AV_LOG_WARNING,
+ "DTS %"PRIi64" < %"PRIi64" out of order\n",
+ pkt->dts,
+ st->last_dts_for_order_check);
+ st->dts_misordered++;
+ }
+ if (st->dts_ordered + st->dts_misordered > 250) {
+ st->dts_ordered >>= 1;
+ st->dts_misordered >>= 1;
+ }
+ }
+
+ st->last_dts_for_order_check = pkt->dts;
+ if (st->dts_ordered < 8*st->dts_misordered && pkt->dts == pkt->pts)
+ pkt->dts = AV_NOPTS_VALUE;
+ }
+
if ((s->flags & AVFMT_FLAG_IGNDTS) && pkt->pts != AV_NOPTS_VALUE)
pkt->dts = AV_NOPTS_VALUE;
+ if (pc && pc->pict_type == AV_PICTURE_TYPE_B
+ && !st->codec->has_b_frames)
+ //FIXME Set low_delay = 0 when has_b_frames = 1
+ st->codec->has_b_frames = 1;
+
/* do we have a video B-frame ? */
delay = st->codec->has_b_frames;
presentation_delayed = 0;
@@ -609,7 +1039,10 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
if (pkt->pts != AV_NOPTS_VALUE && pkt->dts != AV_NOPTS_VALUE &&
st->pts_wrap_bits < 63 &&
pkt->dts - (1LL << (st->pts_wrap_bits - 1)) > pkt->pts) {
- pkt->dts -= 1LL << st->pts_wrap_bits;
+ if (is_relative(st->cur_dts) || pkt->dts - (1LL<<(st->pts_wrap_bits - 1)) > st->cur_dts) {
+ pkt->dts -= 1LL << st->pts_wrap_bits;
+ } else
+ pkt->pts += 1LL << st->pts_wrap_bits;
}
/* Some MPEG-2 in MPEG-PS lack dts (issue #171 / input_file.mpg).
@@ -618,23 +1051,27 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
* presentation_delayed is not set correctly. */
if (delay == 1 && pkt->dts == pkt->pts &&
pkt->dts != AV_NOPTS_VALUE && presentation_delayed) {
- av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination\n");
- pkt->dts = AV_NOPTS_VALUE;
+ av_log(s, AV_LOG_DEBUG, "invalid dts/pts combination %"PRIi64"\n", pkt->dts);
+ if ( strcmp(s->iformat->name, "mov,mp4,m4a,3gp,3g2,mj2")
+ && strcmp(s->iformat->name, "flv")) // otherwise we discard correct timestamps for vc1-wmapro.ism
+ pkt->dts = AV_NOPTS_VALUE;
}
- if (pkt->duration == 0 && st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
+ duration = av_mul_q((AVRational) {pkt->duration, 1}, st->time_base);
+ if (pkt->duration == 0) {
ff_compute_frame_duration(s, &num, &den, st, pc, pkt);
if (den && num) {
- pkt->duration = av_rescale_rnd(1, num * (int64_t) st->time_base.den,
+ duration = (AVRational) {num, den};
+ pkt->duration = av_rescale_rnd(1,
+ num * (int64_t) st->time_base.den,
den * (int64_t) st->time_base.num,
AV_ROUND_DOWN);
-
- if (pkt->duration != 0 && s->internal->packet_buffer)
- update_initial_durations(s, st, pkt->stream_index,
- pkt->duration);
}
}
+ if (pkt->duration != 0 && (s->internal->packet_buffer || s->internal->parse_queue))
+ update_initial_durations(s, st, pkt->stream_index, pkt->duration);
+
/* Correct timestamps with byte offset if demuxers only have timestamps
* on packet boundaries */
if (pc && st->need_parsing == AVSTREAM_PARSE_TIMESTAMPS && pkt->size) {
@@ -652,21 +1089,22 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
pkt->pts > pkt->dts)
presentation_delayed = 1;
- av_log(NULL, AV_LOG_TRACE,
- "IN delayed:%d pts:%"PRId64", dts:%"PRId64" "
- "cur_dts:%"PRId64" st:%d pc:%p\n",
- presentation_delayed, pkt->pts, pkt->dts, st->cur_dts,
- pkt->stream_index, pc);
- /* Interpolate PTS and DTS if they are not present. We skip H.264
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE,
+ "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%d delay:%d onein_oneout:%d\n",
+ presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts),
+ pkt->stream_index, pc, pkt->duration, delay, onein_oneout);
+
+ /* Interpolate PTS and DTS if they are not present. We skip H264
* currently because delay and has_b_frames are not reliably set. */
if ((delay == 0 || (delay == 1 && pc)) &&
- st->codec->codec_id != AV_CODEC_ID_H264) {
+ onein_oneout) {
if (presentation_delayed) {
/* DTS = decompression timestamp */
/* PTS = presentation timestamp */
if (pkt->dts == AV_NOPTS_VALUE)
pkt->dts = st->last_IP_pts;
- update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
+ update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt);
if (pkt->dts == AV_NOPTS_VALUE)
pkt->dts = st->cur_dts;
@@ -676,64 +1114,55 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st,
st->last_IP_duration = pkt->duration;
if (pkt->dts != AV_NOPTS_VALUE)
st->cur_dts = pkt->dts + st->last_IP_duration;
+ if (pkt->dts != AV_NOPTS_VALUE &&
+ pkt->pts == AV_NOPTS_VALUE &&
+ st->last_IP_duration > 0 &&
+ ((uint64_t)st->cur_dts - (uint64_t)next_dts + 1) <= 2 &&
+ next_dts != next_pts &&
+ next_pts != AV_NOPTS_VALUE)
+ pkt->pts = next_dts;
+
st->last_IP_duration = pkt->duration;
st->last_IP_pts = pkt->pts;
/* Cannot compute PTS if not present (we can compute it only
* by knowing the future. */
} else if (pkt->pts != AV_NOPTS_VALUE ||
pkt->dts != AV_NOPTS_VALUE ||
- pkt->duration ||
- st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- int duration = pkt->duration;
- if (!duration && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- ff_compute_frame_duration(s, &num, &den, st, pc, pkt);
- if (den && num) {
- duration = av_rescale_rnd(1,
- num * (int64_t) st->time_base.den,
- den * (int64_t) st->time_base.num,
- AV_ROUND_DOWN);
- if (duration != 0 && s->internal->packet_buffer)
- update_initial_durations(s, st, pkt->stream_index,
- duration);
- }
- }
-
- if (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE ||
- duration) {
- /* presentation is not delayed : PTS and DTS are the same */
- if (pkt->pts == AV_NOPTS_VALUE)
- pkt->pts = pkt->dts;
- update_initial_timestamps(s, pkt->stream_index, pkt->pts,
- pkt->pts);
- if (pkt->pts == AV_NOPTS_VALUE)
- pkt->pts = st->cur_dts;
- pkt->dts = pkt->pts;
- if (pkt->pts != AV_NOPTS_VALUE)
- st->cur_dts = pkt->pts + duration;
- }
+ pkt->duration ) {
+
+ /* presentation is not delayed : PTS and DTS are the same */
+ if (pkt->pts == AV_NOPTS_VALUE)
+ pkt->pts = pkt->dts;
+ update_initial_timestamps(s, pkt->stream_index, pkt->pts,
+ pkt->pts, pkt);
+ if (pkt->pts == AV_NOPTS_VALUE)
+ pkt->pts = st->cur_dts;
+ pkt->dts = pkt->pts;
+ if (pkt->pts != AV_NOPTS_VALUE)
+ st->cur_dts = av_add_stable(st->time_base, pkt->pts, duration, 1);
}
}
- if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY) {
+ if (pkt->pts != AV_NOPTS_VALUE && delay <= MAX_REORDER_DELAY && has_decode_delay_been_guessed(st)) {
st->pts_buffer[0] = pkt->pts;
for (i = 0; i<delay && st->pts_buffer[i] > st->pts_buffer[i + 1]; i++)
FFSWAP(int64_t, st->pts_buffer[i], st->pts_buffer[i + 1]);
- if (pkt->dts == AV_NOPTS_VALUE)
- pkt->dts = st->pts_buffer[0];
- // We skipped it above so we try here.
- if (st->codec->codec_id == AV_CODEC_ID_H264)
- // This should happen on the first packet
- update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts);
- if (pkt->dts > st->cur_dts)
- st->cur_dts = pkt->dts;
+
+ pkt->dts = select_from_pts_buffer(st, st->pts_buffer, pkt->dts);
}
+ // We skipped it above so we try here.
+ if (!onein_oneout)
+ // This should happen on the first packet
+ update_initial_timestamps(s, pkt->stream_index, pkt->dts, pkt->pts, pkt);
+ if (pkt->dts > st->cur_dts)
+ st->cur_dts = pkt->dts;
- av_log(NULL, AV_LOG_TRACE,
- "OUTdelayed:%d/%d pts:%"PRId64", dts:%"PRId64" cur_dts:%"PRId64"\n",
- presentation_delayed, delay, pkt->pts, pkt->dts, st->cur_dts);
+ if (s->debug & FF_FDEBUG_TS)
+ av_log(s, AV_LOG_TRACE, "OUTdelayed:%d/%d pts:%s, dts:%s cur_dts:%s\n",
+ presentation_delayed, delay, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts));
/* update flags */
- if (is_intra_only(st->codec->codec_id))
+ if (is_intra_only(st->codec))
pkt->flags |= AV_PKT_FLAG_KEY;
if (pc)
pkt->convergence_duration = pc->convergence_duration;
@@ -767,10 +1196,15 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
av_init_packet(&flush_pkt);
pkt = &flush_pkt;
got_output = 1;
+ } else if (!size && st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) {
+ // preserve 0-size sync packets
+ compute_pkt_fields(s, st, st->parser, pkt, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
}
while (size > 0 || (pkt == &flush_pkt && got_output)) {
int len;
+ int64_t next_pts = pkt->pts;
+ int64_t next_dts = pkt->dts;
av_init_packet(&out_pkt);
len = av_parser_parse2(st->parser, st->codec,
@@ -778,6 +1212,7 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
pkt->pts, pkt->dts, pkt->pos);
pkt->pts = pkt->dts = AV_NOPTS_VALUE;
+ pkt->pos = -1;
/* increment read pointer */
data += len;
size -= len;
@@ -795,7 +1230,7 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
}
/* set the duration */
- out_pkt.duration = 0;
+ out_pkt.duration = (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->duration : 0;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (st->codec->sample_rate > 0) {
out_pkt.duration =
@@ -811,19 +1246,18 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
out_pkt.dts = st->parser->dts;
out_pkt.pos = st->parser->pos;
+ if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW)
+ out_pkt.pos = st->parser->frame_offset;
+
if (st->parser->key_frame == 1 ||
(st->parser->key_frame == -1 &&
st->parser->pict_type == AV_PICTURE_TYPE_I))
out_pkt.flags |= AV_PKT_FLAG_KEY;
- compute_pkt_fields(s, st, st->parser, &out_pkt);
+ if (st->parser->key_frame == -1 && st->parser->pict_type ==AV_PICTURE_TYPE_NONE && (pkt->flags&AV_PKT_FLAG_KEY))
+ out_pkt.flags |= AV_PKT_FLAG_KEY;
- if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
- out_pkt.flags & AV_PKT_FLAG_KEY) {
- ff_reduce_index(s, st->index);
- av_add_index_entry(st, st->parser->frame_offset, out_pkt.dts,
- 0, 0, AVINDEX_KEYFRAME);
- }
+ compute_pkt_fields(s, st, st->parser, &out_pkt, next_dts, next_pts);
if (out_pkt.data == pkt->data && out_pkt.size == pkt->size) {
out_pkt.buf = pkt->buf;
@@ -871,6 +1305,11 @@ static int read_from_packet_buffer(AVPacketList **pkt_buffer,
return 0;
}
+static int64_t ts_to_samples(AVStream *st, int64_t ts)
+{
+ return av_rescale(ts, st->time_base.num * st->codec->sample_rate, st->time_base.den);
+}
+
static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{
int ret = 0, i, got_packet = 0;
@@ -904,33 +1343,40 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
cur_pkt.dts != AV_NOPTS_VALUE &&
cur_pkt.pts < cur_pkt.dts) {
av_log(s, AV_LOG_WARNING,
- "Invalid timestamps stream=%d, pts=%"PRId64", "
- "dts=%"PRId64", size=%d\n",
- cur_pkt.stream_index, cur_pkt.pts,
- cur_pkt.dts, cur_pkt.size);
+ "Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n",
+ cur_pkt.stream_index,
+ av_ts2str(cur_pkt.pts),
+ av_ts2str(cur_pkt.dts),
+ cur_pkt.size);
}
if (s->debug & FF_FDEBUG_TS)
av_log(s, AV_LOG_DEBUG,
- "ff_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", "
- "size=%d, duration=%d, flags=%d\n",
- cur_pkt.stream_index, cur_pkt.pts, cur_pkt.dts,
+ "ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n",
+ cur_pkt.stream_index,
+ av_ts2str(cur_pkt.pts),
+ av_ts2str(cur_pkt.dts),
cur_pkt.size, cur_pkt.duration, cur_pkt.flags);
if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {
st->parser = av_parser_init(st->codec->codec_id);
- if (!st->parser)
+ if (!st->parser) {
+ av_log(s, AV_LOG_VERBOSE, "parser not found for codec "
+ "%s, packets or times may be invalid.\n",
+ avcodec_get_name(st->codec->codec_id));
/* no parser available: just output the raw packets */
st->need_parsing = AVSTREAM_PARSE_NONE;
- else if (st->need_parsing == AVSTREAM_PARSE_HEADERS)
+ } else if (st->need_parsing == AVSTREAM_PARSE_HEADERS)
st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
else if (st->need_parsing == AVSTREAM_PARSE_FULL_ONCE)
st->parser->flags |= PARSER_FLAG_ONCE;
+ else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW)
+ st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
}
if (!st->need_parsing || !st->parser) {
/* no parsing needed: we just output the packet as is */
*pkt = cur_pkt;
- compute_pkt_fields(s, st, NULL, pkt);
+ compute_pkt_fields(s, st, NULL, pkt, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&
(pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {
ff_reduce_index(s, st->index);
@@ -945,11 +1391,67 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
/* free packet */
av_free_packet(&cur_pkt);
}
+ if (pkt->flags & AV_PKT_FLAG_KEY)
+ st->skip_to_keyframe = 0;
+ if (st->skip_to_keyframe) {
+ av_free_packet(&cur_pkt);
+ if (got_packet) {
+ *pkt = cur_pkt;
+ }
+ got_packet = 0;
+ }
}
if (!got_packet && s->internal->parse_queue)
ret = read_from_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt);
+ if (ret >= 0) {
+ AVStream *st = s->streams[pkt->stream_index];
+ int discard_padding = 0;
+ if (st->first_discard_sample && pkt->pts != AV_NOPTS_VALUE) {
+ int64_t pts = pkt->pts - (is_relative(pkt->pts) ? RELATIVE_TS_BASE : 0);
+ int64_t sample = ts_to_samples(st, pts);
+ int duration = ts_to_samples(st, pkt->duration);
+ int64_t end_sample = sample + duration;
+ if (duration > 0 && end_sample >= st->first_discard_sample &&
+ sample < st->last_discard_sample)
+ discard_padding = FFMIN(end_sample - st->first_discard_sample, duration);
+ }
+ if (st->start_skip_samples && (pkt->pts == 0 || pkt->pts == RELATIVE_TS_BASE))
+ st->skip_samples = st->start_skip_samples;
+ if (st->skip_samples || discard_padding) {
+ uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+ if (p) {
+ AV_WL32(p, st->skip_samples);
+ AV_WL32(p + 4, discard_padding);
+ av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d / discard %d\n", st->skip_samples, discard_padding);
+ }
+ st->skip_samples = 0;
+ }
+
+ if (st->inject_global_side_data) {
+ for (i = 0; i < st->nb_side_data; i++) {
+ AVPacketSideData *src_sd = &st->side_data[i];
+ uint8_t *dst_data;
+
+ if (av_packet_get_side_data(pkt, src_sd->type, NULL))
+ continue;
+
+ dst_data = av_packet_new_side_data(pkt, src_sd->type, src_sd->size);
+ if (!dst_data) {
+ av_log(s, AV_LOG_WARNING, "Could not inject global side data\n");
+ continue;
+ }
+
+ memcpy(dst_data, src_sd->data, src_sd->size);
+ }
+ st->inject_global_side_data = 0;
+ }
+
+ if (!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))
+ av_packet_merge_side_data(pkt);
+ }
+
av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata);
if (metadata) {
s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
@@ -960,9 +1462,11 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
if (s->debug & FF_FDEBUG_TS)
av_log(s, AV_LOG_DEBUG,
- "read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", "
+ "read_frame_internal stream=%d, pts=%s, dts=%s, "
"size=%d, duration=%d, flags=%d\n",
- pkt->stream_index, pkt->pts, pkt->dts,
+ pkt->stream_index,
+ av_ts2str(pkt->pts),
+ av_ts2str(pkt->dts),
pkt->size, pkt->duration, pkt->flags);
return ret;
@@ -972,15 +1476,20 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
{
const int genpts = s->flags & AVFMT_FLAG_GENPTS;
int eof = 0;
+ int ret;
+ AVStream *st;
- if (!genpts)
- return s->internal->packet_buffer
- ? read_from_packet_buffer(&s->internal->packet_buffer,
- &s->internal->packet_buffer_end, pkt)
- : read_frame_internal(s, pkt);
+ if (!genpts) {
+ ret = s->internal->packet_buffer
+ ? read_from_packet_buffer(&s->internal->packet_buffer,
+ &s->internal->packet_buffer_end, pkt)
+ : read_frame_internal(s, pkt);
+ if (ret < 0)
+ return ret;
+ goto return_packet;
+ }
for (;;) {
- int ret;
AVPacketList *pktl = s->internal->packet_buffer;
if (pktl) {
@@ -988,23 +1497,42 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
if (next_pkt->dts != AV_NOPTS_VALUE) {
int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;
+ // last dts seen for this stream. if any of packets following
+ // current one had no dts, we will set this to AV_NOPTS_VALUE.
+ int64_t last_dts = next_pkt->dts;
while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {
if (pktl->pkt.stream_index == next_pkt->stream_index &&
- (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0) &&
- av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) {
- // not B-frame
- next_pkt->pts = pktl->pkt.dts;
+ (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) {
+ if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) {
+ // not B-frame
+ next_pkt->pts = pktl->pkt.dts;
+ }
+ if (last_dts != AV_NOPTS_VALUE) {
+ // Once last dts was set to AV_NOPTS_VALUE, we don't change it.
+ last_dts = pktl->pkt.dts;
+ }
}
pktl = pktl->next;
}
+ if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
+ // Fixing the last reference frame had none pts issue (For MXF etc).
+ // We only do this when
+ // 1. eof.
+ // 2. we are not able to resolve a pts value for current packet.
+ // 3. the packets for this stream at the end of the files had valid dts.
+ next_pkt->pts = last_dts + next_pkt->duration;
+ }
pktl = s->internal->packet_buffer;
}
/* read packet from packet buffer, if there is data */
- if (!(next_pkt->pts == AV_NOPTS_VALUE &&
- next_pkt->dts != AV_NOPTS_VALUE && !eof))
- return read_from_packet_buffer(&s->internal->packet_buffer,
+ st = s->streams[next_pkt->stream_index];
+ if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL &&
+ next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
+ ret = read_from_packet_buffer(&s->internal->packet_buffer,
&s->internal->packet_buffer_end, pkt);
+ goto return_packet;
+ }
}
ret = read_frame_internal(s, pkt);
@@ -1020,11 +1548,28 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
&s->internal->packet_buffer_end)) < 0)
return AVERROR(ENOMEM);
}
+
+return_packet:
+
+ st = s->streams[pkt->stream_index];
+ if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {
+ ff_reduce_index(s, st->index);
+ av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);
+ }
+
+ if (is_relative(pkt->dts))
+ pkt->dts -= RELATIVE_TS_BASE;
+ if (is_relative(pkt->pts))
+ pkt->pts -= RELATIVE_TS_BASE;
+
+ return ret;
}
/* XXX: suppress the packet queue */
static void flush_packet_queue(AVFormatContext *s)
{
+ if (!s->internal)
+ return;
free_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end);
free_packet_buffer(&s->internal->packet_buffer, &s->internal->packet_buffer_end);
free_packet_buffer(&s->internal->raw_packet_buffer, &s->internal->raw_packet_buffer_end);
@@ -1037,23 +1582,39 @@ static void flush_packet_queue(AVFormatContext *s)
int av_find_default_stream_index(AVFormatContext *s)
{
- int first_audio_index = -1;
int i;
AVStream *st;
+ int best_stream = 0;
+ int best_score = -1;
if (s->nb_streams <= 0)
return -1;
for (i = 0; i < s->nb_streams; i++) {
+ int score = 0;
st = s->streams[i];
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
- return i;
+ if (!st->codec->width && !st->codec->height && !st->codec_info_nb_frames)
+ score += 25;
+ else
+ score += 100;
+ }
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (!st->codec->sample_rate && !st->codec_info_nb_frames)
+ score += 12;
+ else
+ score += 50;
+ }
+
+ if (st->discard != AVDISCARD_ALL)
+ score += 200;
+
+ if (score > best_score) {
+ best_score = score;
+ best_stream = i;
}
- if (first_audio_index < 0 &&
- st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- first_audio_index = i;
}
- return first_audio_index >= 0 ? first_audio_index : 0;
+ return best_stream;
}
/** Flush the frame reader. */
@@ -1073,13 +1634,22 @@ void ff_read_frame_flush(AVFormatContext *s)
st->parser = NULL;
}
st->last_IP_pts = AV_NOPTS_VALUE;
- /* We set the current DTS to an unspecified origin. */
- st->cur_dts = AV_NOPTS_VALUE;
+ st->last_dts_for_order_check = AV_NOPTS_VALUE;
+ if (st->first_dts == AV_NOPTS_VALUE)
+ st->cur_dts = RELATIVE_TS_BASE;
+ else
+ /* We set the current DTS to an unspecified origin. */
+ st->cur_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
for (j = 0; j < MAX_REORDER_DELAY + 1; j++)
st->pts_buffer[j] = AV_NOPTS_VALUE;
+
+ if (s->internal->inject_global_side_data)
+ st->inject_global_side_data = 1;
+
+ st->skip_samples = 0;
}
}
@@ -1122,6 +1692,15 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
return -1;
+ if (timestamp == AV_NOPTS_VALUE)
+ return AVERROR(EINVAL);
+
+ if (size < 0 || size > 0x3FFFFFFF)
+ return AVERROR(EINVAL);
+
+ if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
+ timestamp -= RELATIVE_TS_BASE;
+
entries = av_fast_realloc(*index_entries,
index_entries_allocated_size,
(*nb_index_entries + 1) *
@@ -1137,7 +1716,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
if (index < 0) {
index = (*nb_index_entries)++;
ie = &entries[index];
- assert(index == 0 || ie[-1].timestamp < timestamp);
+ av_assert0(index == 0 || ie[-1].timestamp < timestamp);
} else {
ie = &entries[index];
if (ie->timestamp != timestamp) {
@@ -1163,6 +1742,7 @@ int ff_add_index_entry(AVIndexEntry **index_entries,
int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
int size, int distance, int flags)
{
+ timestamp = wrap_timestamp(st, timestamp);
return ff_add_index_entry(&st->index_entries, &st->nb_index_entries,
&st->index_entries_allocated_size, pos,
timestamp, size, distance, flags);
@@ -1207,6 +1787,15 @@ int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
wanted_timestamp, flags);
}
+static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
+ int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
+{
+ int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit);
+ if (stream_index >= 0)
+ ts = wrap_timestamp(s->streams[stream_index], ts);
+ return ts;
+}
+
int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
int64_t target_ts, int flags)
{
@@ -1220,7 +1809,7 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
if (stream_index < 0)
return -1;
- av_log(s, AV_LOG_TRACE, "read_seek: %d %"PRId64"\n", stream_index, target_ts);
+ av_log(s, AV_LOG_TRACE, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts));
ts_max =
ts_min = AV_NOPTS_VALUE;
@@ -1240,23 +1829,23 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
if (e->timestamp <= target_ts || e->pos == e->min_distance) {
pos_min = e->pos;
ts_min = e->timestamp;
- av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%"PRId64"\n",
- pos_min, ts_min);
+ av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%s\n",
+ pos_min, av_ts2str(ts_min));
} else {
- assert(index == 0);
+ av_assert1(index == 0);
}
index = av_index_search_timestamp(st, target_ts,
flags & ~AVSEEK_FLAG_BACKWARD);
- assert(index < st->nb_index_entries);
+ av_assert0(index < st->nb_index_entries);
if (index >= 0) {
e = &st->index_entries[index];
- assert(e->timestamp >= target_ts);
+ av_assert1(e->timestamp >= target_ts);
pos_max = e->pos;
ts_max = e->timestamp;
pos_limit = pos_max - e->min_distance;
av_log(s, AV_LOG_TRACE, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64
- " dts_max=%"PRId64"\n", pos_max, pos_limit, ts_max);
+ " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max));
}
}
@@ -1269,11 +1858,50 @@ int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0)
return ret;
+ ff_read_frame_flush(s);
ff_update_cur_dts(s, st, ts);
return 0;
}
+int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos,
+ int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
+{
+ int64_t step = 1024;
+ int64_t limit, ts_max;
+ int64_t filesize = avio_size(s->pb);
+ int64_t pos_max = filesize - 1;
+ do {
+ limit = pos_max;
+ pos_max = FFMAX(0, (pos_max) - step);
+ ts_max = ff_read_timestamp(s, stream_index,
+ &pos_max, limit, read_timestamp);
+ step += step;
+ } while (ts_max == AV_NOPTS_VALUE && 2*limit > step);
+ if (ts_max == AV_NOPTS_VALUE)
+ return -1;
+
+ for (;;) {
+ int64_t tmp_pos = pos_max + 1;
+ int64_t tmp_ts = ff_read_timestamp(s, stream_index,
+ &tmp_pos, INT64_MAX, read_timestamp);
+ if (tmp_ts == AV_NOPTS_VALUE)
+ break;
+ av_assert0(tmp_pos > pos_max);
+ ts_max = tmp_ts;
+ pos_max = tmp_pos;
+ if (tmp_pos >= filesize)
+ break;
+ }
+
+ if (ts)
+ *ts = ts_max;
+ if (pos)
+ *pos = pos_max;
+
+ return 0;
+}
+
int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
int64_t pos_min, int64_t pos_max, int64_t pos_limit,
int64_t ts_min, int64_t ts_max,
@@ -1282,55 +1910,43 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
int64_t *, int64_t))
{
int64_t pos, ts;
- int64_t start_pos, filesize;
+ int64_t start_pos;
int no_change;
+ int ret;
- av_log(s, AV_LOG_TRACE, "gen_seek: %d %"PRId64"\n", stream_index, target_ts);
+ av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
if (ts_min == AV_NOPTS_VALUE) {
pos_min = s->internal->data_offset;
- ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
+ ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
if (ts_min == AV_NOPTS_VALUE)
return -1;
}
- if (ts_max == AV_NOPTS_VALUE) {
- int step = 1024;
- filesize = avio_size(s->pb);
- pos_max = filesize - 1;
- do {
- pos_max -= step;
- ts_max = read_timestamp(s, stream_index, &pos_max,
- pos_max + step);
- step += step;
- } while (ts_max == AV_NOPTS_VALUE && pos_max >= step);
- if (ts_max == AV_NOPTS_VALUE)
- return -1;
+ if (ts_min >= target_ts) {
+ *ts_ret = ts_min;
+ return pos_min;
+ }
- for (;;) {
- int64_t tmp_pos = pos_max + 1;
- int64_t tmp_ts = read_timestamp(s, stream_index,
- &tmp_pos, INT64_MAX);
- if (tmp_ts == AV_NOPTS_VALUE)
- break;
- ts_max = tmp_ts;
- pos_max = tmp_pos;
- if (tmp_pos >= filesize)
- break;
- }
+ if (ts_max == AV_NOPTS_VALUE) {
+ if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0)
+ return ret;
pos_limit = pos_max;
}
- if (ts_min > ts_max)
- return -1;
- else if (ts_min == ts_max)
- pos_limit = pos_min;
+ if (ts_max <= target_ts) {
+ *ts_ret = ts_max;
+ return pos_max;
+ }
+
+ av_assert0(ts_min < ts_max);
no_change = 0;
while (pos_min < pos_limit) {
- av_log(s, AV_LOG_TRACE, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%"PRId64
- " dts_max=%"PRId64"\n", pos_min, pos_max, ts_min, ts_max);
- assert(pos_limit <= pos_max);
+ av_log(s, AV_LOG_TRACE,
+ "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n",
+ pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max));
+ av_assert0(pos_limit <= pos_max);
if (no_change == 0) {
int64_t approximate_keyframe_distance = pos_max - pos_limit;
@@ -1353,20 +1969,20 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
start_pos = pos;
// May pass pos_limit instead of -1.
- ts = read_timestamp(s, stream_index, &pos, INT64_MAX);
+ ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp);
if (pos == pos_max)
no_change++;
else
no_change = 0;
- av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %"PRId64" %"PRId64" %"PRId64
- " target:%"PRId64" limit:%"PRId64" start:%"PRId64" noc:%d\n",
- pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts,
+ av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s"
+ " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n",
+ pos_min, pos, pos_max,
+ av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts),
pos_limit, start_pos, no_change);
if (ts == AV_NOPTS_VALUE) {
av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
return -1;
}
- assert(ts != AV_NOPTS_VALUE);
if (target_ts <= ts) {
pos_limit = start_pos - 1;
pos_max = pos;
@@ -1380,12 +1996,14 @@ int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
ts = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min : ts_max;
+#if 0
pos_min = pos;
- ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
+ ts_min = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
pos_min++;
- ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
- av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n",
- pos, ts_min, target_ts, ts_max);
+ ts_max = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
+ av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %s<=%s<=%s\n",
+ pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
+#endif
*ts_ret = ts;
return pos;
}
@@ -1405,6 +2023,8 @@ static int seek_frame_byte(AVFormatContext *s, int stream_index,
avio_seek(s->pb, pos, SEEK_SET);
+ s->io_repositioned = 1;
+
return 0;
}
@@ -1426,9 +2046,10 @@ static int seek_frame_generic(AVFormatContext *s, int stream_index,
if (index < 0 || index == st->nb_index_entries - 1) {
AVPacket pkt;
+ int nonkey = 0;
if (st->nb_index_entries) {
- assert(st->index_entries);
+ av_assert0(st->index_entries);
ie = &st->index_entries[st->nb_index_entries - 1];
if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
return ret;
@@ -1445,9 +2066,14 @@ static int seek_frame_generic(AVFormatContext *s, int stream_index,
if (read_status < 0)
break;
av_free_packet(&pkt);
- if (stream_index == pkt.stream_index)
- if ((pkt.flags & AV_PKT_FLAG_KEY) && pkt.dts > timestamp)
+ if (stream_index == pkt.stream_index && pkt.dts > timestamp) {
+ if (pkt.flags & AV_PKT_FLAG_KEY)
+ break;
+ if (nonkey++ > 1000 && st->codec->codec_id != AV_CODEC_ID_CDGRAPHICS) {
+ av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey);
break;
+ }
+ }
}
index = av_index_search_timestamp(st, timestamp, flags);
}
@@ -1513,10 +2139,22 @@ static int seek_frame_internal(AVFormatContext *s, int stream_index,
int av_seek_frame(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
- int ret = seek_frame_internal(s, stream_index, timestamp, flags);
+ int ret;
+
+ if (s->iformat->read_seek2 && !s->iformat->read_seek) {
+ int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
+ if ((flags & AVSEEK_FLAG_BACKWARD))
+ max_ts = timestamp;
+ else
+ min_ts = timestamp;
+ return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
+ flags & ~AVSEEK_FLAG_BACKWARD);
+ }
+
+ ret = seek_frame_internal(s, stream_index, timestamp, flags);
if (ret >= 0)
- ret = queue_attached_pictures(s);
+ ret = avformat_queue_attached_pictures(s);
return ret;
}
@@ -1526,15 +2164,33 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
{
if (min_ts > ts || max_ts < ts)
return -1;
+ if (stream_index < -1 || stream_index >= (int)s->nb_streams)
+ return AVERROR(EINVAL);
+
+ if (s->seek2any>0)
+ flags |= AVSEEK_FLAG_ANY;
+ flags &= ~AVSEEK_FLAG_BACKWARD;
if (s->iformat->read_seek2) {
int ret;
ff_read_frame_flush(s);
+
+ if (stream_index == -1 && s->nb_streams == 1) {
+ AVRational time_base = s->streams[0]->time_base;
+ ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
+ min_ts = av_rescale_rnd(min_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_UP | AV_ROUND_PASS_MINMAX);
+ max_ts = av_rescale_rnd(max_ts, time_base.den,
+ time_base.num * (int64_t)AV_TIME_BASE,
+ AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+ }
+
ret = s->iformat->read_seek2(s, stream_index, min_ts,
ts, max_ts, flags);
if (ret >= 0)
- ret = queue_attached_pictures(s);
+ ret = avformat_queue_attached_pictures(s);
return ret;
}
@@ -1544,13 +2200,25 @@ int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
// Fall back on old API if new is not implemented but old is.
// Note the old API has somewhat different semantics.
- if (s->iformat->read_seek || 1)
- return av_seek_frame(s, stream_index, ts,
- flags | ((uint64_t) ts - min_ts >
- (uint64_t) max_ts - ts
- ? AVSEEK_FLAG_BACKWARD : 0));
+ if (s->iformat->read_seek || 1) {
+ int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
+ int ret = av_seek_frame(s, stream_index, ts, flags | dir);
+ if (ret<0 && ts != min_ts && max_ts != ts) {
+ ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
+ if (ret >= 0)
+ ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
+ }
+ return ret;
+ }
// try some generic seek like seek_frame_generic() but with new ts semantics
+ return -1; //unreachable
+}
+
+int avformat_flush(AVFormatContext *s)
+{
+ ff_read_frame_flush(s);
+ return 0;
}
/*******************************************************/
@@ -1582,12 +2250,14 @@ static int has_duration(AVFormatContext *ic)
*/
static void update_stream_timings(AVFormatContext *ic)
{
- int64_t start_time, start_time1, end_time, end_time1;
+ int64_t start_time, start_time1, start_time_text, end_time, end_time1;
int64_t duration, duration1, filesize;
int i;
AVStream *st;
+ AVProgram *p;
start_time = INT64_MAX;
+ start_time_text = INT64_MAX;
end_time = INT64_MIN;
duration = INT64_MIN;
for (i = 0; i < ic->nb_streams; i++) {
@@ -1595,13 +2265,24 @@ static void update_stream_timings(AVFormatContext *ic)
if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
start_time1 = av_rescale_q(st->start_time, st->time_base,
AV_TIME_BASE_Q);
- start_time = FFMIN(start_time, start_time1);
+ if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codec->codec_type == AVMEDIA_TYPE_DATA) {
+ if (start_time1 < start_time_text)
+ start_time_text = start_time1;
+ } else
+ start_time = FFMIN(start_time, start_time1);
+ end_time1 = AV_NOPTS_VALUE;
if (st->duration != AV_NOPTS_VALUE) {
end_time1 = start_time1 +
av_rescale_q(st->duration, st->time_base,
AV_TIME_BASE_Q);
end_time = FFMAX(end_time, end_time1);
}
+ for (p = NULL; (p = av_find_program_from_stream(ic, p, i)); ) {
+ if (p->start_time == AV_NOPTS_VALUE || p->start_time > start_time1)
+ p->start_time = start_time1;
+ if (p->end_time < end_time1)
+ p->end_time = end_time1;
+ }
}
if (st->duration != AV_NOPTS_VALUE) {
duration1 = av_rescale_q(st->duration, st->time_base,
@@ -1609,17 +2290,33 @@ static void update_stream_timings(AVFormatContext *ic)
duration = FFMAX(duration, duration1);
}
}
+ if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE))
+ start_time = start_time_text;
+ else if (start_time > start_time_text)
+ av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE);
+
if (start_time != INT64_MAX) {
ic->start_time = start_time;
- if (end_time != INT64_MIN)
- duration = FFMAX(duration, end_time - start_time);
+ if (end_time != INT64_MIN) {
+ if (ic->nb_programs) {
+ for (i = 0; i < ic->nb_programs; i++) {
+ p = ic->programs[i];
+ if (p->start_time != AV_NOPTS_VALUE && p->end_time > p->start_time)
+ duration = FFMAX(duration, p->end_time - p->start_time);
+ }
+ } else
+ duration = FFMAX(duration, end_time - start_time);
+ }
}
- if (duration != INT64_MIN) {
+ if (duration != INT64_MIN && duration > 0 && ic->duration == AV_NOPTS_VALUE) {
ic->duration = duration;
- if (ic->pb && (filesize = avio_size(ic->pb)) > 0)
- /* compute the bitrate */
- ic->bit_rate = (double) filesize * 8.0 * AV_TIME_BASE /
- (double) ic->duration;
+ }
+ if (ic->pb && (filesize = avio_size(ic->pb)) > 0 && ic->duration != AV_NOPTS_VALUE) {
+ /* compute the bitrate */
+ double bitrate = (double) filesize * 8.0 * AV_TIME_BASE /
+ (double) ic->duration;
+ if (bitrate >= 0 && bitrate <= INT_MAX)
+ ic->bit_rate = bitrate;
}
}
@@ -1645,7 +2342,7 @@ static void fill_all_stream_timings(AVFormatContext *ic)
static void estimate_timings_from_bit_rate(AVFormatContext *ic)
{
int64_t filesize, duration;
- int i;
+ int i, show_warning = 0;
AVStream *st;
/* if bit_rate is already set, we believe it */
@@ -1659,6 +2356,11 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic)
break;
}
bit_rate += st->codec->bit_rate;
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 1) {
+ // If we have a videostream with packets but without a bitrate
+ // then consider the sum not known
+ bit_rate = 0;
+ break;
}
}
ic->bit_rate = bit_rate;
@@ -1668,29 +2370,37 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic)
if (ic->duration == AV_NOPTS_VALUE &&
ic->bit_rate != 0) {
filesize = ic->pb ? avio_size(ic->pb) : 0;
- if (filesize > 0) {
+ if (filesize > ic->internal->data_offset) {
+ filesize -= ic->internal->data_offset;
for (i = 0; i < ic->nb_streams; i++) {
- st = ic->streams[i];
- duration = av_rescale(8 * filesize, st->time_base.den,
- ic->bit_rate *
- (int64_t) st->time_base.num);
- if (st->duration == AV_NOPTS_VALUE)
+ st = ic->streams[i];
+ if ( st->time_base.num <= INT64_MAX / ic->bit_rate
+ && st->duration == AV_NOPTS_VALUE) {
+ duration = av_rescale(8 * filesize, st->time_base.den,
+ ic->bit_rate *
+ (int64_t) st->time_base.num);
st->duration = duration;
+ show_warning = 1;
+ }
}
}
}
+ if (show_warning)
+ av_log(ic, AV_LOG_WARNING,
+ "Estimating duration from bitrate, this may be inaccurate\n");
}
-#define DURATION_MAX_READ_SIZE 250000
-#define DURATION_MAX_RETRY 3
+#define DURATION_MAX_READ_SIZE 250000LL
+#define DURATION_MAX_RETRY 4
/* only usable for MPEG-PS streams */
static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
{
AVPacket pkt1, *pkt = &pkt1;
AVStream *st;
- int read_size, i, ret;
- int64_t end_time;
+ int num, den, read_size, i, ret;
+ int found_duration = 0;
+ int is_end;
int64_t filesize, offset, duration;
int retry = 0;
@@ -1699,9 +2409,11 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
for (i = 0; i < ic->nb_streams; i++) {
st = ic->streams[i];
- if (st->start_time == AV_NOPTS_VALUE && st->first_dts == AV_NOPTS_VALUE)
+ if (st->start_time == AV_NOPTS_VALUE &&
+ st->first_dts == AV_NOPTS_VALUE &&
+ st->codec->codec_type != AVMEDIA_TYPE_UNKNOWN)
av_log(st->codec, AV_LOG_WARNING,
- "start time is not set in estimate_timings_from_pts\n");
+ "start time for stream %d is not set in estimate_timings_from_pts\n", i);
if (st->parser) {
av_parser_close(st->parser);
@@ -1709,11 +2421,12 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
}
}
+ av_opt_set(ic, "skip_changes", "1", AV_OPT_SEARCH_CHILDREN);
/* estimate the end time (duration) */
/* XXX: may need to support wrapping */
filesize = ic->pb ? avio_size(ic->pb) : 0;
- end_time = AV_NOPTS_VALUE;
do {
+ is_end = found_duration;
offset = filesize - (DURATION_MAX_READ_SIZE << retry);
if (offset < 0)
offset = 0;
@@ -1734,31 +2447,76 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
if (pkt->pts != AV_NOPTS_VALUE &&
(st->start_time != AV_NOPTS_VALUE ||
st->first_dts != AV_NOPTS_VALUE)) {
- duration = end_time = pkt->pts;
+ if (pkt->duration == 0) {
+ ff_compute_frame_duration(ic, &num, &den, st, st->parser, pkt);
+ if (den && num) {
+ pkt->duration = av_rescale_rnd(1,
+ num * (int64_t) st->time_base.den,
+ den * (int64_t) st->time_base.num,
+ AV_ROUND_DOWN);
+ }
+ }
+ duration = pkt->pts + pkt->duration;
+ found_duration = 1;
if (st->start_time != AV_NOPTS_VALUE)
duration -= st->start_time;
else
duration -= st->first_dts;
- if (duration < 0)
- duration += 1LL << st->pts_wrap_bits;
if (duration > 0) {
- if (st->duration == AV_NOPTS_VALUE || st->duration < duration)
+ if (st->duration == AV_NOPTS_VALUE || st->info->last_duration<= 0 ||
+ (st->duration < duration && FFABS(duration - st->info->last_duration) < 60LL*st->time_base.den / st->time_base.num))
st->duration = duration;
+ st->info->last_duration = duration;
}
}
av_free_packet(pkt);
}
- } while (end_time == AV_NOPTS_VALUE &&
- filesize > (DURATION_MAX_READ_SIZE << retry) &&
+
+ /* check if all audio/video streams have valid duration */
+ if (!is_end) {
+ is_end = 1;
+ for (i = 0; i < ic->nb_streams; i++) {
+ st = ic->streams[i];
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_AUDIO:
+ if (st->duration == AV_NOPTS_VALUE)
+ is_end = 0;
+ }
+ }
+ }
+ } while (!is_end &&
+ offset &&
++retry <= DURATION_MAX_RETRY);
+ av_opt_set(ic, "skip_changes", "0", AV_OPT_SEARCH_CHILDREN);
+
+ /* warn about audio/video streams which duration could not be estimated */
+ for (i = 0; i < ic->nb_streams; i++) {
+ st = ic->streams[i];
+ if (st->duration == AV_NOPTS_VALUE) {
+ switch (st->codec->codec_type) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_AUDIO:
+ if (st->start_time != AV_NOPTS_VALUE || st->first_dts != AV_NOPTS_VALUE) {
+ av_log(ic, AV_LOG_DEBUG, "stream %d : no PTS found at end of file, duration not set\n", i);
+ } else
+ av_log(ic, AV_LOG_DEBUG, "stream %d : no TS found at start of file, duration not set\n", i);
+ }
+ }
+ }
fill_all_stream_timings(ic);
avio_seek(ic->pb, old_offset, SEEK_SET);
for (i = 0; i < ic->nb_streams; i++) {
+ int j;
+
st = ic->streams[i];
st->cur_dts = st->first_dts;
st->last_IP_pts = AV_NOPTS_VALUE;
+ st->last_dts_for_order_check = AV_NOPTS_VALUE;
+ for (j = 0; j < MAX_REORDER_DELAY + 1; j++)
+ st->pts_buffer[j] = AV_NOPTS_VALUE;
}
}
@@ -1779,15 +2537,16 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
file_size && ic->pb->seekable) {
/* get accurate estimate from the PTSes */
estimate_timings_from_pts(ic, old_offset);
+ ic->duration_estimation_method = AVFMT_DURATION_FROM_PTS;
} else if (has_duration(ic)) {
/* at least one component has timings - we use them for all
* the components */
fill_all_stream_timings(ic);
+ ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM;
} else {
- av_log(ic, AV_LOG_WARNING,
- "Estimating duration from bitrate, this may be inaccurate\n");
/* less precise: use bitrate info */
estimate_timings_from_bit_rate(ic);
+ ic->duration_estimation_method = AVFMT_DURATION_FROM_BITRATE;
}
update_stream_timings(ic);
@@ -1808,56 +2567,75 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
}
}
-static int has_codec_parameters(AVStream *st)
+static int has_codec_parameters(AVStream *st, const char **errmsg_ptr)
{
AVCodecContext *avctx = st->codec;
- int val;
+#define FAIL(errmsg) do { \
+ if (errmsg_ptr) \
+ *errmsg_ptr = errmsg; \
+ return 0; \
+ } while (0)
+
+ if ( avctx->codec_id == AV_CODEC_ID_NONE
+ && avctx->codec_type != AVMEDIA_TYPE_DATA)
+ FAIL("unknown codec");
switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
- val = avctx->sample_rate && avctx->channels;
+ if (!avctx->frame_size && determinable_frame_size(avctx))
+ FAIL("unspecified frame size");
if (st->info->found_decoder >= 0 &&
avctx->sample_fmt == AV_SAMPLE_FMT_NONE)
- return 0;
+ FAIL("unspecified sample format");
+ if (!avctx->sample_rate)
+ FAIL("unspecified sample rate");
+ if (!avctx->channels)
+ FAIL("unspecified number of channels");
+ if (st->info->found_decoder >= 0 && !st->nb_decoded_frames && avctx->codec_id == AV_CODEC_ID_DTS)
+ FAIL("no decodable DTS frames");
break;
case AVMEDIA_TYPE_VIDEO:
- val = avctx->width;
+ if (!avctx->width)
+ FAIL("unspecified size");
if (st->info->found_decoder >= 0 && avctx->pix_fmt == AV_PIX_FMT_NONE)
- return 0;
+ FAIL("unspecified pixel format");
+ if (st->codec->codec_id == AV_CODEC_ID_RV30 || st->codec->codec_id == AV_CODEC_ID_RV40)
+ if (!st->sample_aspect_ratio.num && !st->codec->sample_aspect_ratio.num && !st->codec_info_nb_frames)
+ FAIL("no frame in rv30/40 and no sar");
break;
- default:
- val = 1;
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (avctx->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && !avctx->width)
+ FAIL("unspecified size");
break;
+ case AVMEDIA_TYPE_DATA:
+ if (avctx->codec_id == AV_CODEC_ID_NONE) return 1;
}
- return avctx->codec_id != AV_CODEC_ID_NONE && val != 0;
-}
-static int has_decode_delay_been_guessed(AVStream *st)
-{
- return st->codec->codec_id != AV_CODEC_ID_H264 ||
- st->info->nb_decoded_frames >= 6;
+ return 1;
}
/* returns 1 or 0 if or if not decoded data was returned, or a negative error */
-static int try_decode_frame(AVStream *st, AVPacket *avpkt,
+static int try_decode_frame(AVFormatContext *s, AVStream *st, AVPacket *avpkt,
AVDictionary **options)
{
const AVCodec *codec;
int got_picture = 1, ret = 0;
AVFrame *frame = av_frame_alloc();
+ AVSubtitle subtitle;
AVPacket pkt = *avpkt;
if (!frame)
return AVERROR(ENOMEM);
- if (!avcodec_is_open(st->codec) && !st->info->found_decoder) {
+ if (!avcodec_is_open(st->codec) &&
+ st->info->found_decoder <= 0 &&
+ (st->codec->codec_id != -st->info->found_decoder || !st->codec->codec_id)) {
AVDictionary *thread_opt = NULL;
- codec = st->codec->codec ? st->codec->codec
- : avcodec_find_decoder(st->codec->codec_id);
+ codec = find_decoder(s, st, st->codec->codec_id);
if (!codec) {
- st->info->found_decoder = -1;
+ st->info->found_decoder = -st->codec->codec_id;
ret = -1;
goto fail;
}
@@ -1865,11 +2643,13 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt,
/* Force thread count to 1 since the H.264 decoder will not extract
* SPS and PPS to extradata during multi-threaded decoding. */
av_dict_set(options ? options : &thread_opt, "threads", "1", 0);
+ if (s->codec_whitelist)
+ av_dict_set(options ? options : &thread_opt, "codec_whitelist", s->codec_whitelist, 0);
ret = avcodec_open2(st->codec, codec, options ? options : &thread_opt);
if (!options)
av_dict_free(&thread_opt);
if (ret < 0) {
- st->info->found_decoder = -1;
+ st->info->found_decoder = -st->codec->codec_id;
goto fail;
}
st->info->found_decoder = 1;
@@ -1883,7 +2663,7 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt,
while ((pkt.size > 0 || (!pkt.data && got_picture)) &&
ret >= 0 &&
- (!has_codec_parameters(st) || !has_decode_delay_been_guessed(st) ||
+ (!has_codec_parameters(st, NULL) || !has_decode_delay_been_guessed(st) ||
(!st->codec_info_nb_frames &&
st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF))) {
got_picture = 0;
@@ -1895,18 +2675,26 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt,
case AVMEDIA_TYPE_AUDIO:
ret = avcodec_decode_audio4(st->codec, frame, &got_picture, &pkt);
break;
+ case AVMEDIA_TYPE_SUBTITLE:
+ ret = avcodec_decode_subtitle2(st->codec, &subtitle,
+ &got_picture, &pkt);
+ ret = pkt.size;
+ break;
default:
break;
}
if (ret >= 0) {
if (got_picture)
- st->info->nb_decoded_frames++;
+ st->nb_decoded_frames++;
pkt.data += ret;
pkt.size -= ret;
ret = got_picture;
}
}
+ if (!pkt.data && !got_picture)
+ ret = -1;
+
fail:
av_frame_free(&frame);
return ret;
@@ -1946,6 +2734,7 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags)
return AV_CODEC_ID_NONE;
}
} else {
+ bps += 7;
bps >>= 3;
if (sflags & (1 << (bps - 1))) {
switch (bps) {
@@ -1979,11 +2768,25 @@ enum AVCodecID ff_get_pcm_codec_id(int bps, int flt, int be, int sflags)
unsigned int av_codec_get_tag(const AVCodecTag *const *tags, enum AVCodecID id)
{
+ unsigned int tag;
+ if (!av_codec_get_tag2(tags, id, &tag))
+ return 0;
+ return tag;
+}
+
+int av_codec_get_tag2(const AVCodecTag * const *tags, enum AVCodecID id,
+ unsigned int *tag)
+{
int i;
for (i = 0; tags && tags[i]; i++) {
- int tag = ff_codec_get_tag(tags[i], id);
- if (tag)
- return tag;
+ const AVCodecTag *codec_tags = tags[i];
+ while (codec_tags->id != AV_CODEC_ID_NONE) {
+ if (codec_tags->id == id) {
+ *tag = codec_tags->tag;
+ return 1;
+ }
+ codec_tags++;
+ }
}
return 0;
}
@@ -2025,56 +2828,292 @@ static void compute_chapters_end(AVFormatContext *s)
static int get_std_framerate(int i)
{
- if (i < 60 * 12)
+ if (i < 30*12)
return (i + 1) * 1001;
- else
- return ((const int[]) { 24, 30, 60, 12, 15 })[i - 60 * 12] * 1000 * 12;
+ i -= 30*12;
+
+ if (i < 7)
+ return ((const int[]) { 40, 48, 50, 60, 80, 120, 240})[i] * 1001 * 12;
+
+ i -= 7;
+
+ return ((const int[]) { 24, 30, 60, 12, 15, 48 })[i] * 1000 * 12;
+}
+
+/* Is the time base unreliable?
+ * This is a heuristic to balance between quick acceptance of the values in
+ * the headers vs. some extra checks.
+ * Old DivX and Xvid often have nonsense timebases like 1fps or 2fps.
+ * MPEG-2 commonly misuses field repeat flags to store different framerates.
+ * And there are "variable" fps files this needs to detect as well. */
+static int tb_unreliable(AVCodecContext *c)
+{
+ if (c->time_base.den >= 101LL * c->time_base.num ||
+ c->time_base.den < 5LL * c->time_base.num ||
+ // c->codec_tag == AV_RL32("DIVX") ||
+ // c->codec_tag == AV_RL32("XVID") ||
+ c->codec_tag == AV_RL32("mp4v") ||
+ c->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
+ c->codec_id == AV_CODEC_ID_GIF ||
+ c->codec_id == AV_CODEC_ID_HEVC ||
+ c->codec_id == AV_CODEC_ID_H264)
+ return 1;
+ return 0;
+}
+
+int ff_alloc_extradata(AVCodecContext *avctx, int size)
+{
+ int ret;
+
+ if (size < 0 || size >= INT32_MAX - FF_INPUT_BUFFER_PADDING_SIZE) {
+ avctx->extradata = NULL;
+ avctx->extradata_size = 0;
+ return AVERROR(EINVAL);
+ }
+ avctx->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (avctx->extradata) {
+ memset(avctx->extradata + size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+ avctx->extradata_size = size;
+ ret = 0;
+ } else {
+ avctx->extradata_size = 0;
+ ret = AVERROR(ENOMEM);
+ }
+ return ret;
+}
+
+int ff_get_extradata(AVCodecContext *avctx, AVIOContext *pb, int size)
+{
+ int ret = ff_alloc_extradata(avctx, size);
+ if (ret < 0)
+ return ret;
+ ret = avio_read(pb, avctx->extradata, size);
+ if (ret != size) {
+ av_freep(&avctx->extradata);
+ avctx->extradata_size = 0;
+ av_log(avctx, AV_LOG_ERROR, "Failed to read extradata of size %d\n", size);
+ return ret < 0 ? ret : AVERROR_INVALIDDATA;
+ }
+
+ return ret;
+}
+
+int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts)
+{
+ int i, j;
+ int64_t last = st->info->last_dts;
+
+ if ( ts != AV_NOPTS_VALUE && last != AV_NOPTS_VALUE && ts > last
+ && ts - (uint64_t)last < INT64_MAX) {
+ double dts = (is_relative(ts) ? ts - RELATIVE_TS_BASE : ts) * av_q2d(st->time_base);
+ int64_t duration = ts - last;
+
+ if (!st->info->duration_error)
+ st->info->duration_error = av_mallocz(sizeof(st->info->duration_error[0])*2);
+ if (!st->info->duration_error)
+ return AVERROR(ENOMEM);
+
+// if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+// av_log(NULL, AV_LOG_ERROR, "%f\n", dts);
+ for (i = 0; i<MAX_STD_TIMEBASES; i++) {
+ if (st->info->duration_error[0][1][i] < 1e10) {
+ int framerate = get_std_framerate(i);
+ double sdts = dts*framerate/(1001*12);
+ for (j= 0; j<2; j++) {
+ int64_t ticks = llrint(sdts+j*0.5);
+ double error= sdts - ticks + j*0.5;
+ st->info->duration_error[j][0][i] += error;
+ st->info->duration_error[j][1][i] += error*error;
+ }
+ }
+ }
+ st->info->duration_count++;
+ st->info->rfps_duration_sum += duration;
+
+ if (st->info->duration_count % 10 == 0) {
+ int n = st->info->duration_count;
+ for (i = 0; i<MAX_STD_TIMEBASES; i++) {
+ if (st->info->duration_error[0][1][i] < 1e10) {
+ double a0 = st->info->duration_error[0][0][i] / n;
+ double error0 = st->info->duration_error[0][1][i] / n - a0*a0;
+ double a1 = st->info->duration_error[1][0][i] / n;
+ double error1 = st->info->duration_error[1][1][i] / n - a1*a1;
+ if (error0 > 0.04 && error1 > 0.04) {
+ st->info->duration_error[0][1][i] = 2e10;
+ st->info->duration_error[1][1][i] = 2e10;
+ }
+ }
+ }
+ }
+
+ // ignore the first 4 values, they might have some random jitter
+ if (st->info->duration_count > 3 && is_relative(ts) == is_relative(last))
+ st->info->duration_gcd = av_gcd(st->info->duration_gcd, duration);
+ }
+ if (ts != AV_NOPTS_VALUE)
+ st->info->last_dts = ts;
+
+ return 0;
+}
+
+void ff_rfps_calculate(AVFormatContext *ic)
+{
+ int i, j;
+
+ for (i = 0; i < ic->nb_streams; i++) {
+ AVStream *st = ic->streams[i];
+
+ if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO)
+ continue;
+ // the check for tb_unreliable() is not completely correct, since this is not about handling
+ // a unreliable/inexact time base, but a time base that is finer than necessary, as e.g.
+ // ipmovie.c produces.
+ if (tb_unreliable(st->codec) && st->info->duration_count > 15 && st->info->duration_gcd > FFMAX(1, st->time_base.den/(500LL*st->time_base.num)) && !st->r_frame_rate.num)
+ av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, st->time_base.den, st->time_base.num * st->info->duration_gcd, INT_MAX);
+ if (st->info->duration_count>1 && !st->r_frame_rate.num
+ && tb_unreliable(st->codec)) {
+ int num = 0;
+ double best_error= 0.01;
+ AVRational ref_rate = st->r_frame_rate.num ? st->r_frame_rate : av_inv_q(st->time_base);
+
+ for (j= 0; j<MAX_STD_TIMEBASES; j++) {
+ int k;
+
+ if (st->info->codec_info_duration && st->info->codec_info_duration*av_q2d(st->time_base) < (1001*12.0)/get_std_framerate(j))
+ continue;
+ if (!st->info->codec_info_duration && 1.0 < (1001*12.0)/get_std_framerate(j))
+ continue;
+
+ if (av_q2d(st->time_base) * st->info->rfps_duration_sum / st->info->duration_count < (1001*12.0 * 0.8)/get_std_framerate(j))
+ continue;
+
+ for (k= 0; k<2; k++) {
+ int n = st->info->duration_count;
+ double a= st->info->duration_error[k][0][j] / n;
+ double error= st->info->duration_error[k][1][j]/n - a*a;
+
+ if (error < best_error && best_error> 0.000000001) {
+ best_error= error;
+ num = get_std_framerate(j);
+ }
+ if (error < 0.02)
+ av_log(ic, AV_LOG_DEBUG, "rfps: %f %f\n", get_std_framerate(j) / 12.0/1001, error);
+ }
+ }
+ // do not increase frame rate by more than 1 % in order to match a standard rate.
+ if (num && (!ref_rate.num || (double)num/(12*1001) < 1.01 * av_q2d(ref_rate)))
+ av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, num, 12*1001, INT_MAX);
+ }
+ if ( !st->avg_frame_rate.num
+ && st->r_frame_rate.num && st->info->rfps_duration_sum
+ && st->info->codec_info_duration <= 0
+ && st->info->duration_count > 2
+ && fabs(1.0 / (av_q2d(st->r_frame_rate) * av_q2d(st->time_base)) - st->info->rfps_duration_sum / (double)st->info->duration_count) <= 1.0
+ ) {
+ av_log(ic, AV_LOG_DEBUG, "Setting avg frame rate based on r frame rate\n");
+ st->avg_frame_rate = st->r_frame_rate;
+ }
+
+ av_freep(&st->info->duration_error);
+ st->info->last_dts = AV_NOPTS_VALUE;
+ st->info->duration_count = 0;
+ st->info->rfps_duration_sum = 0;
+ }
}
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
- int i, count, ret, read_size, j;
+ int i, count, ret = 0, j;
+ int64_t read_size;
AVStream *st;
AVPacket pkt1, *pkt;
int64_t old_offset = avio_tell(ic->pb);
// new streams might appear, no options for those
int orig_nb_streams = ic->nb_streams;
+ int flush_codecs;
+ int64_t max_analyze_duration = ic->max_analyze_duration2;
+ int64_t max_stream_analyze_duration;
+ int64_t probesize = ic->probesize2;
+
+ if (!max_analyze_duration)
+ max_analyze_duration = ic->max_analyze_duration;
+ if (ic->probesize)
+ probesize = ic->probesize;
+ flush_codecs = probesize > 0;
+
+ av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN);
+
+ max_stream_analyze_duration = max_analyze_duration;
+ if (!max_analyze_duration) {
+ max_stream_analyze_duration =
+ max_analyze_duration = 5*AV_TIME_BASE;
+ if (!strcmp(ic->iformat->name, "flv"))
+ max_stream_analyze_duration = 30*AV_TIME_BASE;
+ }
+
+ if (ic->pb)
+ av_log(ic, AV_LOG_DEBUG, "Before avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d\n",
+ avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count);
for (i = 0; i < ic->nb_streams; i++) {
const AVCodec *codec;
AVDictionary *thread_opt = NULL;
st = ic->streams[i];
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
+ st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
+/* if (!st->time_base.num)
+ st->time_base = */
+ if (!st->codec->time_base.num)
+ st->codec->time_base = st->time_base;
+ }
// only for the split stuff
if (!st->parser && !(ic->flags & AVFMT_FLAG_NOPARSE)) {
st->parser = av_parser_init(st->codec->codec_id);
- if (st->need_parsing == AVSTREAM_PARSE_HEADERS && st->parser)
- st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
+ if (st->parser) {
+ if (st->need_parsing == AVSTREAM_PARSE_HEADERS) {
+ st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
+ } else if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) {
+ st->parser->flags |= PARSER_FLAG_USE_CODEC_TS;
+ }
+ } else if (st->need_parsing) {
+ av_log(ic, AV_LOG_VERBOSE, "parser not found for codec "
+ "%s, packets or times may be invalid.\n",
+ avcodec_get_name(st->codec->codec_id));
+ }
}
- codec = st->codec->codec ? st->codec->codec
- : avcodec_find_decoder(st->codec->codec_id);
+ codec = find_decoder(ic, st, st->codec->codec_id);
/* Force thread count to 1 since the H.264 decoder will not extract
* SPS and PPS to extradata during multi-threaded decoding. */
av_dict_set(options ? &options[i] : &thread_opt, "threads", "1", 0);
+ if (ic->codec_whitelist)
+ av_dict_set(options ? &options[i] : &thread_opt, "codec_whitelist", ic->codec_whitelist, 0);
+
/* Ensure that subtitle_header is properly set. */
if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE
- && codec && !st->codec->codec)
- avcodec_open2(st->codec, codec,
- options ? &options[i] : &thread_opt);
+ && codec && !st->codec->codec) {
+ if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0)
+ av_log(ic, AV_LOG_WARNING,
+ "Failed to open codec in av_find_stream_info\n");
+ }
// Try to just open decoders, in case this is enough to get parameters.
- if (!has_codec_parameters(st)) {
+ if (!has_codec_parameters(st, NULL) && st->request_probe <= 0) {
if (codec && !st->codec->codec)
- avcodec_open2(st->codec, codec,
- options ? &options[i] : &thread_opt);
+ if (avcodec_open2(st->codec, codec, options ? &options[i] : &thread_opt) < 0)
+ av_log(ic, AV_LOG_WARNING,
+ "Failed to open codec in av_find_stream_info\n");
}
if (!options)
av_dict_free(&thread_opt);
}
for (i = 0; i < ic->nb_streams; i++) {
+#if FF_API_R_FRAME_RATE
+ ic->streams[i]->info->last_dts = AV_NOPTS_VALUE;
+#endif
ic->streams[i]->info->fps_first_dts = AV_NOPTS_VALUE;
ic->streams[i]->info->fps_last_dts = AV_NOPTS_VALUE;
}
@@ -2082,6 +3121,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
count = 0;
read_size = 0;
for (;;) {
+ int analyzed_all_streams;
if (ff_check_interrupt(&ic->interrupt_callback)) {
ret = AVERROR_EXIT;
av_log(ic, AV_LOG_DEBUG, "interrupted\n");
@@ -2093,44 +3133,64 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
int fps_analyze_framecount = 20;
st = ic->streams[i];
- if (!has_codec_parameters(st))
+ if (!has_codec_parameters(st, NULL))
break;
/* If the timebase is coarse (like the usual millisecond precision
* of mkv), we need to analyze more frames to reliably arrive at
* the correct fps. */
if (av_q2d(st->time_base) > 0.0005)
fps_analyze_framecount *= 2;
+ if (!tb_unreliable(st->codec))
+ fps_analyze_framecount = 0;
if (ic->fps_probe_size >= 0)
fps_analyze_framecount = ic->fps_probe_size;
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ fps_analyze_framecount = 0;
/* variable fps and no guess at the real fps */
- if (!st->avg_frame_rate.num &&
- st->codec_info_nb_frames < fps_analyze_framecount &&
- st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- break;
+ if (!(st->r_frame_rate.num && st->avg_frame_rate.num) &&
+ st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ int count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ?
+ st->info->codec_info_duration_fields/2 :
+ st->info->duration_count;
+ if (count < fps_analyze_framecount)
+ break;
+ }
if (st->parser && st->parser->parser->split &&
!st->codec->extradata)
break;
if (st->first_dts == AV_NOPTS_VALUE &&
+ !(ic->iformat->flags & AVFMT_NOTIMESTAMPS) &&
st->codec_info_nb_frames < ic->max_ts_probe &&
(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
st->codec->codec_type == AVMEDIA_TYPE_AUDIO))
break;
}
+ analyzed_all_streams = 0;
if (i == ic->nb_streams) {
+ analyzed_all_streams = 1;
/* NOTE: If the format has no header, then we need to read some
* packets to get most of the streams, so we cannot stop here. */
if (!(ic->ctx_flags & AVFMTCTX_NOHEADER)) {
/* If we found the info for all the codecs, we can stop. */
ret = count;
av_log(ic, AV_LOG_DEBUG, "All info found\n");
+ flush_codecs = 0;
break;
}
}
/* We did not get all the codec info, but we read too much data. */
- if (read_size >= ic->probesize) {
+ if (read_size >= probesize) {
ret = count;
av_log(ic, AV_LOG_DEBUG,
- "Probe buffer size limit %d reached\n", ic->probesize);
+ "Probe buffer size limit of %"PRId64" bytes reached\n", probesize);
+ for (i = 0; i < ic->nb_streams; i++)
+ if (!ic->streams[i]->r_frame_rate.num &&
+ ic->streams[i]->info->duration_count <= 1 &&
+ ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ strcmp(ic->iformat->name, "image2"))
+ av_log(ic, AV_LOG_WARNING,
+ "Stream #%d: not enough frames to estimate rate; "
+ "consider increasing probesize\n", i);
break;
}
@@ -2142,56 +3202,32 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
if (ret < 0) {
/* EOF or error*/
- AVPacket empty_pkt = { 0 };
- int err = 0;
- av_init_packet(&empty_pkt);
-
- /* We could not have all the codec parameters before EOF. */
- ret = -1;
- for (i = 0; i < ic->nb_streams; i++) {
- st = ic->streams[i];
-
- /* flush the decoders */
- if (st->info->found_decoder == 1) {
- do {
- err = try_decode_frame(st, &empty_pkt,
- (options && i < orig_nb_streams)
- ? &options[i] : NULL);
- } while (err > 0 && !has_codec_parameters(st));
- }
-
- if (err < 0) {
- av_log(ic, AV_LOG_WARNING,
- "decoding for stream %d failed\n", st->index);
- } else if (!has_codec_parameters(st)) {
- char buf[256];
- avcodec_string(buf, sizeof(buf), st->codec, 0);
- av_log(ic, AV_LOG_WARNING,
- "Could not find codec parameters (%s)\n", buf);
- } else {
- ret = 0;
- }
- }
break;
}
- if (ic->flags & AVFMT_FLAG_NOBUFFER) {
- pkt = &pkt1;
- } else {
+ if (ic->flags & AVFMT_FLAG_NOBUFFER)
+ free_packet_buffer(&ic->internal->packet_buffer,
+ &ic->internal->packet_buffer_end);
+ {
pkt = add_to_pktbuf(&ic->internal->packet_buffer, &pkt1,
&ic->internal->packet_buffer_end);
+ if (!pkt) {
+ ret = AVERROR(ENOMEM);
+ goto find_stream_info_err;
+ }
if ((ret = av_dup_packet(pkt)) < 0)
goto find_stream_info_err;
}
- read_size += pkt->size;
-
st = ic->streams[pkt->stream_index];
+ if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ read_size += pkt->size;
+
if (pkt->dts != AV_NOPTS_VALUE && st->codec_info_nb_frames > 1) {
/* check for non-increasing dts */
if (st->info->fps_last_dts != AV_NOPTS_VALUE &&
st->info->fps_last_dts >= pkt->dts) {
- av_log(ic, AV_LOG_WARNING,
+ av_log(ic, AV_LOG_DEBUG,
"Non-increasing DTS in stream %d: packet %d with DTS "
"%"PRId64", packet %d with DTS %"PRId64"\n",
st->index, st->info->fps_last_dts_idx,
@@ -2225,24 +3261,42 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
}
st->info->fps_last_dts = pkt->dts;
st->info->fps_last_dts_idx = st->codec_info_nb_frames;
-
- /* check max_analyze_duration */
- if (av_rescale_q(pkt->dts - st->info->fps_first_dts, st->time_base,
- AV_TIME_BASE_Q) >= ic->max_analyze_duration) {
- av_log(ic, AV_LOG_WARNING, "max_analyze_duration %d reached\n",
- ic->max_analyze_duration);
+ }
+ if (st->codec_info_nb_frames>1) {
+ int64_t t = 0;
+
+ if (st->time_base.den > 0)
+ t = av_rescale_q(st->info->codec_info_duration, st->time_base, AV_TIME_BASE_Q);
+ if (st->avg_frame_rate.num > 0)
+ t = FFMAX(t, av_rescale_q(st->codec_info_nb_frames, av_inv_q(st->avg_frame_rate), AV_TIME_BASE_Q));
+
+ if ( t == 0
+ && st->codec_info_nb_frames>30
+ && st->info->fps_first_dts != AV_NOPTS_VALUE
+ && st->info->fps_last_dts != AV_NOPTS_VALUE)
+ t = FFMAX(t, av_rescale_q(st->info->fps_last_dts - st->info->fps_first_dts, st->time_base, AV_TIME_BASE_Q));
+
+ if (t >= (analyzed_all_streams ? max_analyze_duration : max_stream_analyze_duration)) {
+ av_log(ic, AV_LOG_VERBOSE, "max_analyze_duration %"PRId64" reached at %"PRId64" microseconds\n",
+ max_analyze_duration,
+ t);
if (ic->flags & AVFMT_FLAG_NOBUFFER)
av_packet_unref(pkt);
break;
}
+ if (pkt->duration) {
+ st->info->codec_info_duration += pkt->duration;
+ st->info->codec_info_duration_fields += st->parser && st->need_parsing && st->codec->ticks_per_frame ==2 ? st->parser->repeat_pict + 1 : 2;
+ }
}
+#if FF_API_R_FRAME_RATE
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+ ff_rfps_add_frame(ic, st, pkt->dts);
+#endif
if (st->parser && st->parser->parser->split && !st->codec->extradata) {
int i = st->parser->parser->split(st->codec, pkt->data, pkt->size);
if (i > 0 && i < FF_MAX_EXTRADATA_SIZE) {
- st->codec->extradata_size = i;
- st->codec->extradata = av_mallocz(st->codec->extradata_size +
- FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, i))
return AVERROR(ENOMEM);
memcpy(st->codec->extradata, pkt->data,
st->codec->extradata_size);
@@ -2258,7 +3312,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
* least one frame of codec data, this makes sure the codec initializes
* the channel configuration and does not only trust the values from
* the container. */
- try_decode_frame(st, pkt,
+ try_decode_frame(ic, st, pkt,
(options && i < orig_nb_streams) ? &options[i] : NULL);
if (ic->flags & AVFMT_FLAG_NOBUFFER)
@@ -2268,31 +3322,62 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
count++;
}
+ if (flush_codecs) {
+ AVPacket empty_pkt = { 0 };
+ int err = 0;
+ av_init_packet(&empty_pkt);
+
+ for (i = 0; i < ic->nb_streams; i++) {
+
+ st = ic->streams[i];
+
+ /* flush the decoders */
+ if (st->info->found_decoder == 1) {
+ do {
+ err = try_decode_frame(ic, st, &empty_pkt,
+ (options && i < orig_nb_streams)
+ ? &options[i] : NULL);
+ } while (err > 0 && !has_codec_parameters(st, NULL));
+
+ if (err < 0) {
+ av_log(ic, AV_LOG_INFO,
+ "decoding for stream %d failed\n", st->index);
+ }
+ }
+ }
+ }
+
// close codecs which were opened in try_decode_frame()
for (i = 0; i < ic->nb_streams; i++) {
st = ic->streams[i];
avcodec_close(st->codec);
}
+
+ ff_rfps_calculate(ic);
+
for (i = 0; i < ic->nb_streams; i++) {
st = ic->streams[i];
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO && !st->codec->codec_tag && !st->codec->bits_per_coded_sample) {
+ uint32_t tag= avcodec_pix_fmt_to_codec_tag(st->codec->pix_fmt);
+ if (avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), tag) == st->codec->pix_fmt)
+ st->codec->codec_tag= tag;
+ }
+
/* estimate average framerate if not set by demuxer */
- if (!st->avg_frame_rate.num &&
- st->info->fps_last_dts != st->info->fps_first_dts) {
- int64_t delta_dts = st->info->fps_last_dts -
- st->info->fps_first_dts;
- int delta_packets = st->info->fps_last_dts_idx -
- st->info->fps_first_dts_idx;
+ if (st->info->codec_info_duration_fields &&
+ !st->avg_frame_rate.num &&
+ st->info->codec_info_duration) {
int best_fps = 0;
double best_error = 0.01;
- if (delta_dts >= INT64_MAX / st->time_base.num ||
- delta_packets >= INT64_MAX / st->time_base.den ||
- delta_dts < 0)
+ if (st->info->codec_info_duration >= INT64_MAX / st->time_base.num / 2||
+ st->info->codec_info_duration_fields >= INT64_MAX / st->time_base.den ||
+ st->info->codec_info_duration < 0)
continue;
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
- delta_packets * (int64_t) st->time_base.den,
- delta_dts * (int64_t) st->time_base.num, 60000);
+ st->info->codec_info_duration_fields * (int64_t) st->time_base.den,
+ st->info->codec_info_duration * 2 * (int64_t) st->time_base.num, 60000);
/* Round guessed framerate to a "standard" framerate if it's
* within 1% of the original estimate. */
@@ -2310,6 +3395,22 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
best_fps, 12 * 1001, INT_MAX);
}
+
+ if (!st->r_frame_rate.num) {
+ if ( st->codec->time_base.den * (int64_t) st->time_base.num
+ <= st->codec->time_base.num * st->codec->ticks_per_frame * (int64_t) st->time_base.den) {
+ st->r_frame_rate.num = st->codec->time_base.den;
+ st->r_frame_rate.den = st->codec->time_base.num * st->codec->ticks_per_frame;
+ } else {
+ st->r_frame_rate.num = st->time_base.den;
+ st->r_frame_rate.den = st->time_base.num;
+ }
+ }
+ if (st->display_aspect_ratio.num && st->display_aspect_ratio.den) {
+ AVRational hw_ratio = { st->codec->height, st->codec->width };
+ st->sample_aspect_ratio = av_mul_q(st->display_aspect_ratio,
+ hw_ratio);
+ }
} else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
if (!st->codec->bits_per_coded_sample)
st->codec->bits_per_coded_sample =
@@ -2335,26 +3436,60 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
}
}
+ if (probesize)
estimate_timings(ic, old_offset);
+ av_opt_set(ic, "skip_clear", "0", AV_OPT_SEARCH_CHILDREN);
+
+ if (ret >= 0 && ic->nb_streams)
+ /* We could not have all the codec parameters before EOF. */
+ ret = -1;
+ for (i = 0; i < ic->nb_streams; i++) {
+ const char *errmsg;
+ st = ic->streams[i];
+ if (!has_codec_parameters(st, &errmsg)) {
+ char buf[256];
+ avcodec_string(buf, sizeof(buf), st->codec, 0);
+ av_log(ic, AV_LOG_WARNING,
+ "Could not find codec parameters for stream %d (%s): %s\n"
+ "Consider increasing the value for the 'analyzeduration' and 'probesize' options\n",
+ i, buf, errmsg);
+ } else {
+ ret = 0;
+ }
+ }
+
compute_chapters_end(ic);
find_stream_info_err:
for (i = 0; i < ic->nb_streams; i++) {
- ic->streams[i]->codec->thread_count = 0;
+ st = ic->streams[i];
+ if (ic->streams[i]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
+ ic->streams[i]->codec->thread_count = 0;
+ if (st->info)
+ av_freep(&st->info->duration_error);
av_freep(&ic->streams[i]->info);
}
+ if (ic->pb)
+ av_log(ic, AV_LOG_DEBUG, "After avformat_find_stream_info() pos: %"PRId64" bytes read:%"PRId64" seeks:%d frames:%d\n",
+ avio_tell(ic->pb), ic->pb->bytes_read, ic->pb->seek_count, count);
return ret;
}
-static AVProgram *find_program_from_stream(AVFormatContext *ic, int s)
+AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s)
{
int i, j;
- for (i = 0; i < ic->nb_programs; i++)
- for (j = 0; j < ic->programs[i]->nb_stream_indexes; j++)
- if (ic->programs[i]->stream_index[j] == s)
- return ic->programs[i];
+ for (i = 0; i < ic->nb_programs; i++) {
+ if (ic->programs[i] == last) {
+ last = NULL;
+ } else {
+ if (!last)
+ for (j = 0; j < ic->programs[i]->nb_stream_indexes; j++)
+ if (ic->programs[i]->stream_index[j] == s)
+ return ic->programs[i];
+ }
+ }
return NULL;
}
@@ -2363,12 +3498,12 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,
AVCodec **decoder_ret, int flags)
{
int i, nb_streams = ic->nb_streams;
- int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1;
+ int ret = AVERROR_STREAM_NOT_FOUND, best_count = -1, best_bitrate = -1, best_multiframe = -1, count, bitrate, multiframe;
unsigned *program = NULL;
- AVCodec *decoder = NULL, *best_decoder = NULL;
+ const AVCodec *decoder = NULL, *best_decoder = NULL;
if (related_stream >= 0 && wanted_stream_nb < 0) {
- AVProgram *p = find_program_from_stream(ic, related_stream);
+ AVProgram *p = av_find_program_from_stream(ic, NULL, related_stream);
if (p) {
program = p->stream_index;
nb_streams = p->nb_stream_indexes;
@@ -2382,20 +3517,32 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,
continue;
if (wanted_stream_nb >= 0 && real_stream_index != wanted_stream_nb)
continue;
- if (st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED |
+ if (wanted_stream_nb != real_stream_index &&
+ st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED |
AV_DISPOSITION_VISUAL_IMPAIRED))
continue;
+ if (type == AVMEDIA_TYPE_AUDIO && !avctx->channels)
+ continue;
if (decoder_ret) {
- decoder = avcodec_find_decoder(st->codec->codec_id);
+ decoder = find_decoder(ic, st, st->codec->codec_id);
if (!decoder) {
if (ret < 0)
ret = AVERROR_DECODER_NOT_FOUND;
continue;
}
}
- if (best_count >= st->codec_info_nb_frames)
+ count = st->codec_info_nb_frames;
+ bitrate = avctx->bit_rate;
+ if (!bitrate)
+ bitrate = avctx->rc_max_rate;
+ multiframe = FFMIN(5, count);
+ if ((best_multiframe > multiframe) ||
+ (best_multiframe == multiframe && best_bitrate > bitrate) ||
+ (best_multiframe == multiframe && best_bitrate == bitrate && best_count >= count))
continue;
- best_count = st->codec_info_nb_frames;
+ best_count = count;
+ best_bitrate = bitrate;
+ best_multiframe = multiframe;
ret = real_stream_index;
best_decoder = decoder;
if (program && i == nb_streams - 1 && ret < 0) {
@@ -2406,7 +3553,7 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,
}
}
if (decoder_ret)
- *decoder_ret = best_decoder;
+ *decoder_ret = (AVCodec*)best_decoder;
return ret;
}
@@ -2430,10 +3577,38 @@ int av_read_pause(AVFormatContext *s)
return AVERROR(ENOSYS);
}
+void ff_free_stream(AVFormatContext *s, AVStream *st) {
+ int j;
+ av_assert0(s->nb_streams>0);
+ av_assert0(s->streams[ s->nb_streams - 1 ] == st);
+
+ for (j = 0; j < st->nb_side_data; j++)
+ av_freep(&st->side_data[j].data);
+ av_freep(&st->side_data);
+ st->nb_side_data = 0;
+
+ if (st->parser) {
+ av_parser_close(st->parser);
+ }
+ if (st->attached_pic.data)
+ av_free_packet(&st->attached_pic);
+ av_dict_free(&st->metadata);
+ av_freep(&st->probe_data.buf);
+ av_freep(&st->index_entries);
+ av_freep(&st->codec->extradata);
+ av_freep(&st->codec->subtitle_header);
+ av_freep(&st->codec);
+ av_freep(&st->priv_data);
+ if (st->info)
+ av_freep(&st->info->duration_error);
+ av_freep(&st->info);
+ av_freep(&st->recommended_encoder_configuration);
+ av_freep(&s->streams[ --s->nb_streams ]);
+}
+
void avformat_free_context(AVFormatContext *s)
{
- int i, j;
- AVStream *st;
+ int i;
if (!s)
return;
@@ -2441,30 +3616,11 @@ void avformat_free_context(AVFormatContext *s)
av_opt_free(s);
if (s->iformat && s->iformat->priv_class && s->priv_data)
av_opt_free(s->priv_data);
+ if (s->oformat && s->oformat->priv_class && s->priv_data)
+ av_opt_free(s->priv_data);
- for (i = 0; i < s->nb_streams; i++) {
- /* free all data in a stream component */
- st = s->streams[i];
-
- for (j = 0; j < st->nb_side_data; j++)
- av_freep(&st->side_data[j].data);
- av_freep(&st->side_data);
- st->nb_side_data = 0;
-
- if (st->parser) {
- av_parser_close(st->parser);
- }
- if (st->attached_pic.data)
- av_free_packet(&st->attached_pic);
- av_dict_free(&st->metadata);
- av_freep(&st->probe_data.buf);
- av_free(st->index_entries);
- av_free(st->codec->extradata);
- av_free(st->codec->subtitle_header);
- av_free(st->codec);
- av_free(st->priv_data);
- av_free(st->info);
- av_free(st);
+ for (i = s->nb_streams - 1; i >= 0; i--) {
+ ff_free_stream(s, s->streams[i]);
}
for (i = s->nb_programs - 1; i >= 0; i--) {
av_dict_free(&s->programs[i]->metadata);
@@ -2475,21 +3631,28 @@ void avformat_free_context(AVFormatContext *s)
av_freep(&s->priv_data);
while (s->nb_chapters--) {
av_dict_free(&s->chapters[s->nb_chapters]->metadata);
- av_free(s->chapters[s->nb_chapters]);
+ av_freep(&s->chapters[s->nb_chapters]);
}
av_freep(&s->chapters);
av_dict_free(&s->metadata);
av_freep(&s->streams);
av_freep(&s->internal);
+ flush_packet_queue(s);
av_free(s);
}
void avformat_close_input(AVFormatContext **ps)
{
- AVFormatContext *s = *ps;
- AVIOContext *pb = s->pb;
+ AVFormatContext *s;
+ AVIOContext *pb;
- if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
+ if (!ps || !*ps)
+ return;
+
+ s = *ps;
+ pb = s->pb;
+
+ if ((s->iformat && strcmp(s->iformat->name, "image2") && s->iformat->flags & AVFMT_NOFILE) ||
(s->flags & AVFMT_FLAG_CUSTOM_IO))
pb = NULL;
@@ -2510,12 +3673,14 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
{
AVStream *st;
int i;
+ AVStream **streams;
- if (av_reallocp_array(&s->streams, s->nb_streams + 1,
- sizeof(*s->streams)) < 0) {
- s->nb_streams = 0;
+ if (s->nb_streams >= INT_MAX/sizeof(*streams))
return NULL;
- }
+ streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));
+ if (!streams)
+ return NULL;
+ s->streams = streams;
st = av_mallocz(sizeof(AVStream));
if (!st)
@@ -2524,6 +3689,7 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
av_free(st);
return NULL;
}
+ st->info->last_dts = AV_NOPTS_VALUE;
st->codec = avcodec_alloc_context3(c);
if (!st->codec) {
@@ -2546,19 +3712,27 @@ AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
* but durations get some timestamps, formats with some unknown
* timestamps have their first few packets buffered and the
* timestamps corrected before they are returned to the user */
- st->cur_dts = 0;
+ st->cur_dts = s->iformat ? RELATIVE_TS_BASE : 0;
st->first_dts = AV_NOPTS_VALUE;
st->probe_packets = MAX_PROBE_PACKETS;
+ st->pts_wrap_reference = AV_NOPTS_VALUE;
+ st->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;
st->last_IP_pts = AV_NOPTS_VALUE;
+ st->last_dts_for_order_check = AV_NOPTS_VALUE;
for (i = 0; i < MAX_REORDER_DELAY + 1; i++)
st->pts_buffer[i] = AV_NOPTS_VALUE;
st->sample_aspect_ratio = (AVRational) { 0, 1 };
+#if FF_API_R_FRAME_RATE
+ st->info->last_dts = AV_NOPTS_VALUE;
+#endif
st->info->fps_first_dts = AV_NOPTS_VALUE;
st->info->fps_last_dts = AV_NOPTS_VALUE;
+ st->inject_global_side_data = s->internal->inject_global_side_data;
+
s->streams[s->nb_streams++] = st;
return st;
}
@@ -2582,6 +3756,11 @@ AVProgram *av_new_program(AVFormatContext *ac, int id)
program->discard = AVDISCARD_NONE;
}
program->id = id;
+ program->pts_wrap_reference = AV_NOPTS_VALUE;
+ program->pts_wrap_behavior = AV_PTS_WRAP_IGNORE;
+
+ program->start_time =
+ program->end_time = AV_NOPTS_VALUE;
return program;
}
@@ -2592,6 +3771,11 @@ AVChapter *avpriv_new_chapter(AVFormatContext *s, int id, AVRational time_base,
AVChapter *chapter = NULL;
int i;
+ if (end != AV_NOPTS_VALUE && start > end) {
+ av_log(s, AV_LOG_ERROR, "Chapter end time %"PRId64" before start %"PRId64"\n", end, start);
+ return NULL;
+ }
+
for (i = 0; i < s->nb_chapters; i++)
if (s->chapters[i]->id == id)
chapter = s->chapters[i];
@@ -2615,6 +3799,7 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx)
{
int i, j;
AVProgram *program = NULL;
+ void *tmp;
if (idx >= ac->nb_streams) {
av_log(ac, AV_LOG_ERROR, "stream index %d is not valid\n", idx);
@@ -2629,12 +3814,10 @@ void ff_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx)
if (program->stream_index[j] == idx)
return;
- if (av_reallocp_array(&program->stream_index,
- program->nb_stream_indexes + 1,
- sizeof(*program->stream_index)) < 0) {
- program->nb_stream_indexes = 0;
+ tmp = av_realloc_array(program->stream_index, program->nb_stream_indexes+1, sizeof(unsigned int));
+ if (!tmp)
return;
- }
+ program->stream_index = tmp;
program->stream_index[program->nb_stream_indexes++] = idx;
return;
}
@@ -2673,6 +3856,8 @@ int av_get_frame_filename(char *buf, int buf_size, const char *path, int number)
if (percentd_found)
goto fail;
percentd_found = 1;
+ if (number < 0)
+ nd += 1;
snprintf(buf1, sizeof(buf1), "%0*d", nd, number);
len = strlen(buf1);
if ((q - buf + len) > buf_size - 1)
@@ -2703,7 +3888,7 @@ void av_url_split(char *proto, int proto_size,
char *hostname, int hostname_size,
int *port_ptr, char *path, int path_size, const char *url)
{
- const char *p, *ls, *at, *col, *brk;
+ const char *p, *ls, *ls2, *at, *at2, *col, *brk;
if (port_ptr)
*port_ptr = -1;
@@ -2732,8 +3917,11 @@ void av_url_split(char *proto, int proto_size,
/* separate path from hostname */
ls = strchr(p, '/');
+ ls2 = strchr(p, '?');
if (!ls)
- ls = strchr(p, '?');
+ ls = ls2;
+ else if (ls && ls2)
+ ls = FFMIN(ls, ls2);
if (ls)
av_strlcpy(path, ls, path_size);
else
@@ -2742,9 +3930,10 @@ void av_url_split(char *proto, int proto_size,
/* the rest is hostname, use that to parse auth/port */
if (ls != p) {
/* authorization (user[:pass]@hostname) */
- if ((at = strchr(p, '@')) && at < ls) {
- av_strlcpy(authorization, p,
- FFMIN(authorization_size, at + 1 - p));
+ at2 = p;
+ while ((at = strchr(p, '@')) && at < ls) {
+ av_strlcpy(authorization, at2,
+ FFMIN(authorization_size, at + 1 - at2));
p = at + 1; /* skip '@' */
}
@@ -2829,11 +4018,13 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits,
if (new_tb.num <= 0 || new_tb.den <= 0) {
av_log(NULL, AV_LOG_ERROR,
- "Ignoring attempt to set invalid timebase for st:%d\n",
+ "Ignoring attempt to set invalid timebase %d/%d for st:%d\n",
+ new_tb.num, new_tb.den,
s->index);
return;
}
s->time_base = new_tb;
+ av_codec_set_pkt_timebase(s->codec, new_tb);
s->pts_wrap_bits = pts_wrap_bits;
}
@@ -2935,7 +4126,8 @@ int avformat_network_init(void)
ff_network_inited_globally = 1;
if ((ret = ff_network_init()) < 0)
return ret;
- ff_tls_init();
+ if ((ret = ff_tls_init()) < 0)
+ return ret;
#endif
return 0;
}
@@ -2945,6 +4137,7 @@ int avformat_network_deinit(void)
#if CONFIG_NETWORK
ff_network_close();
ff_tls_deinit();
+ ff_network_inited_globally = 0;
#endif
return 0;
}
@@ -2991,6 +4184,158 @@ int ff_add_param_change(AVPacket *pkt, int32_t channels,
return 0;
}
+AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame)
+{
+ AVRational undef = {0, 1};
+ AVRational stream_sample_aspect_ratio = stream ? stream->sample_aspect_ratio : undef;
+ AVRational codec_sample_aspect_ratio = stream && stream->codec ? stream->codec->sample_aspect_ratio : undef;
+ AVRational frame_sample_aspect_ratio = frame ? frame->sample_aspect_ratio : codec_sample_aspect_ratio;
+
+ av_reduce(&stream_sample_aspect_ratio.num, &stream_sample_aspect_ratio.den,
+ stream_sample_aspect_ratio.num, stream_sample_aspect_ratio.den, INT_MAX);
+ if (stream_sample_aspect_ratio.num <= 0 || stream_sample_aspect_ratio.den <= 0)
+ stream_sample_aspect_ratio = undef;
+
+ av_reduce(&frame_sample_aspect_ratio.num, &frame_sample_aspect_ratio.den,
+ frame_sample_aspect_ratio.num, frame_sample_aspect_ratio.den, INT_MAX);
+ if (frame_sample_aspect_ratio.num <= 0 || frame_sample_aspect_ratio.den <= 0)
+ frame_sample_aspect_ratio = undef;
+
+ if (stream_sample_aspect_ratio.num)
+ return stream_sample_aspect_ratio;
+ else
+ return frame_sample_aspect_ratio;
+}
+
+AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *frame)
+{
+ AVRational fr = st->r_frame_rate;
+ AVRational codec_fr = st->codec->framerate;
+ AVRational avg_fr = st->avg_frame_rate;
+
+ if (avg_fr.num > 0 && avg_fr.den > 0 && fr.num > 0 && fr.den > 0 &&
+ av_q2d(avg_fr) < 70 && av_q2d(fr) > 210) {
+ fr = avg_fr;
+ }
+
+
+ if (st->codec->ticks_per_frame > 1) {
+ if ( codec_fr.num > 0 && codec_fr.den > 0 &&
+ (fr.num == 0 || av_q2d(codec_fr) < av_q2d(fr)*0.7 && fabs(1.0 - av_q2d(av_div_q(avg_fr, fr))) > 0.1))
+ fr = codec_fr;
+ }
+
+ return fr;
+}
+
+int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st,
+ const char *spec)
+{
+ if (*spec <= '9' && *spec >= '0') /* opt:index */
+ return strtol(spec, NULL, 0) == st->index;
+ else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' ||
+ *spec == 't') { /* opt:[vasdt] */
+ enum AVMediaType type;
+
+ switch (*spec++) {
+ case 'v': type = AVMEDIA_TYPE_VIDEO; break;
+ case 'a': type = AVMEDIA_TYPE_AUDIO; break;
+ case 's': type = AVMEDIA_TYPE_SUBTITLE; break;
+ case 'd': type = AVMEDIA_TYPE_DATA; break;
+ case 't': type = AVMEDIA_TYPE_ATTACHMENT; break;
+ default: av_assert0(0);
+ }
+ if (type != st->codec->codec_type)
+ return 0;
+ if (*spec++ == ':') { /* possibly followed by :index */
+ int i, index = strtol(spec, NULL, 0);
+ for (i = 0; i < s->nb_streams; i++)
+ if (s->streams[i]->codec->codec_type == type && index-- == 0)
+ return i == st->index;
+ return 0;
+ }
+ return 1;
+ } else if (*spec == 'p' && *(spec + 1) == ':') {
+ int prog_id, i, j;
+ char *endptr;
+ spec += 2;
+ prog_id = strtol(spec, &endptr, 0);
+ for (i = 0; i < s->nb_programs; i++) {
+ if (s->programs[i]->id != prog_id)
+ continue;
+
+ if (*endptr++ == ':') {
+ int stream_idx = strtol(endptr, NULL, 0);
+ return stream_idx >= 0 &&
+ stream_idx < s->programs[i]->nb_stream_indexes &&
+ st->index == s->programs[i]->stream_index[stream_idx];
+ }
+
+ for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
+ if (st->index == s->programs[i]->stream_index[j])
+ return 1;
+ }
+ return 0;
+ } else if (*spec == '#' ||
+ (*spec == 'i' && *(spec + 1) == ':')) {
+ int stream_id;
+ char *endptr;
+ spec += 1 + (*spec == 'i');
+ stream_id = strtol(spec, &endptr, 0);
+ if (!*endptr)
+ return stream_id == st->id;
+ } else if (*spec == 'm' && *(spec + 1) == ':') {
+ AVDictionaryEntry *tag;
+ char *key, *val;
+ int ret;
+
+ spec += 2;
+ val = strchr(spec, ':');
+
+ key = val ? av_strndup(spec, val - spec) : av_strdup(spec);
+ if (!key)
+ return AVERROR(ENOMEM);
+
+ tag = av_dict_get(st->metadata, key, NULL, 0);
+ if (tag) {
+ if (!val || !strcmp(tag->value, val + 1))
+ ret = 1;
+ else
+ ret = 0;
+ } else
+ ret = 0;
+
+ av_freep(&key);
+ return ret;
+ } else if (*spec == 'u') {
+ AVCodecContext *avctx = st->codec;
+ int val;
+ switch (avctx->codec_type) {
+ case AVMEDIA_TYPE_AUDIO:
+ val = avctx->sample_rate && avctx->channels;
+ if (avctx->sample_fmt == AV_SAMPLE_FMT_NONE)
+ return 0;
+ break;
+ case AVMEDIA_TYPE_VIDEO:
+ val = avctx->width && avctx->height;
+ if (avctx->pix_fmt == AV_PIX_FMT_NONE)
+ return 0;
+ break;
+ case AVMEDIA_TYPE_UNKNOWN:
+ val = 0;
+ break;
+ default:
+ val = 1;
+ break;
+ }
+ return avctx->codec_id != AV_CODEC_ID_NONE && val != 0;
+ } else if (!*spec) /* empty specifier, matches everything */
+ return 1;
+
+ av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
+ return AVERROR(EINVAL);
+}
+
int ff_generate_avci_extradata(AVStream *st)
{
static const uint8_t avci100_1080p_extradata[] = {
@@ -3020,11 +4365,26 @@ int ff_generate_avci_extradata(AVStream *st)
0x11, 0x12, 0x08, 0xc6, 0x8c, 0x04, 0x41, 0x28,
0x4c, 0x34, 0xf0, 0x1e, 0x01, 0x13, 0xf2, 0xe0,
0x3c, 0x60, 0x20, 0x20, 0x28, 0x00, 0x00, 0x03,
- 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x94, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x94, 0x20,
// PPS
0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x33, 0x48,
0xd0
};
+ static const uint8_t avci50_1080p_extradata[] = {
+ // SPS
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x6e, 0x10, 0x28,
+ 0xa6, 0xd4, 0x20, 0x32, 0x33, 0x0c, 0x71, 0x18,
+ 0x88, 0x62, 0x10, 0x19, 0x19, 0x86, 0x38, 0x8c,
+ 0x44, 0x30, 0x21, 0x02, 0x56, 0x4e, 0x6f, 0x37,
+ 0xcd, 0xf9, 0xbf, 0x81, 0x6b, 0xf3, 0x7c, 0xde,
+ 0x6e, 0x6c, 0xd3, 0x3c, 0x05, 0xa0, 0x22, 0x7e,
+ 0x5f, 0xfc, 0x00, 0x0c, 0x00, 0x13, 0x8c, 0x04,
+ 0x04, 0x05, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00,
+ 0x00, 0x03, 0x00, 0x32, 0x84, 0x00, 0x00, 0x00,
+ // PPS
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x31, 0x12,
+ 0x11
+ };
static const uint8_t avci50_1080i_extradata[] = {
// SPS
0x00, 0x00, 0x00, 0x01, 0x67, 0x6e, 0x10, 0x28,
@@ -3035,8 +4395,8 @@ int ff_generate_avci_extradata(AVStream *st)
0x9c, 0x0b, 0x73, 0xe6, 0xc0, 0xb5, 0x18, 0x63,
0x0d, 0x39, 0xe0, 0x5b, 0x02, 0xd4, 0xc6, 0x19,
0x1a, 0x79, 0x8c, 0x32, 0x34, 0x24, 0xf0, 0x16,
- 0x81, 0x13, 0xf7, 0xff, 0x80, 0x01, 0x80, 0x02,
- 0x71, 0x80, 0x80, 0x80, 0xa0, 0x00, 0x00, 0x03,
+ 0x81, 0x13, 0xf7, 0xff, 0x80, 0x02, 0x00, 0x01,
+ 0xf1, 0x80, 0x80, 0x80, 0xa0, 0x00, 0x00, 0x03,
0x00, 0x20, 0x00, 0x00, 0x06, 0x50, 0x80, 0x00,
// PPS
0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x31, 0x12,
@@ -3058,6 +4418,21 @@ int ff_generate_avci_extradata(AVStream *st)
0x00, 0x00, 0x00, 0x01, 0x68, 0xce, 0x31, 0x12,
0x11
};
+ static const uint8_t avci50_720p_extradata[] = {
+ // SPS
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x6e, 0x10, 0x20,
+ 0xa6, 0xd4, 0x20, 0x32, 0x33, 0x0c, 0x71, 0x18,
+ 0x88, 0x62, 0x10, 0x19, 0x19, 0x86, 0x38, 0x8c,
+ 0x44, 0x30, 0x21, 0x02, 0x56, 0x4e, 0x6f, 0x37,
+ 0xcd, 0xf9, 0xbf, 0x81, 0x6b, 0xf3, 0x7c, 0xde,
+ 0x6e, 0x6c, 0xd3, 0x3c, 0x0f, 0x01, 0x6e, 0xff,
+ 0xc0, 0x00, 0xc0, 0x01, 0x38, 0xc0, 0x40, 0x40,
+ 0x50, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00,
+ 0x06, 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // PPS
+ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x31, 0x12,
+ 0x11
+ };
const uint8_t *data = NULL;
int size = 0;
@@ -3071,24 +4446,28 @@ int ff_generate_avci_extradata(AVStream *st)
size = sizeof(avci100_1080i_extradata);
}
} else if (st->codec->width == 1440) {
- data = avci50_1080i_extradata;
- size = sizeof(avci50_1080i_extradata);
+ if (st->codec->field_order == AV_FIELD_PROGRESSIVE) {
+ data = avci50_1080p_extradata;
+ size = sizeof(avci50_1080p_extradata);
+ } else {
+ data = avci50_1080i_extradata;
+ size = sizeof(avci50_1080i_extradata);
+ }
} else if (st->codec->width == 1280) {
data = avci100_720p_extradata;
size = sizeof(avci100_720p_extradata);
+ } else if (st->codec->width == 960) {
+ data = avci50_720p_extradata;
+ size = sizeof(avci50_720p_extradata);
}
if (!size)
return 0;
av_freep(&st->codec->extradata);
- st->codec->extradata_size = 0;
- st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, size))
return AVERROR(ENOMEM);
-
memcpy(st->codec->extradata, data, size);
- st->codec->extradata_size = size;
return 0;
}
diff --git a/libavformat/vc1test.c b/libavformat/vc1test.c
index f302c2b12a..3afe398d8b 100644
--- a/libavformat/vc1test.c
+++ b/libavformat/vc1test.c
@@ -2,20 +2,20 @@
* VC1 Test Bitstreams Format Demuxer
* Copyright (c) 2006, 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -61,11 +61,8 @@ static int vc1t_read_header(AVFormatContext *s)
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_WMV3;
- st->codec->extradata = av_malloc(VC1_EXTRADATA_SIZE);
- if (!st->codec->extradata)
+ if (ff_get_extradata(st->codec, pb, VC1_EXTRADATA_SIZE) < 0)
return AVERROR(ENOMEM);
- st->codec->extradata_size = VC1_EXTRADATA_SIZE;
- avio_read(pb, st->codec->extradata, VC1_EXTRADATA_SIZE);
st->codec->height = avio_rl32(pb);
st->codec->width = avio_rl32(pb);
if(avio_rl32(pb) != 0xC)
@@ -94,7 +91,7 @@ static int vc1t_read_packet(AVFormatContext *s,
int keyframe = 0;
uint32_t pts;
- if(pb->eof_reached)
+ if(avio_feof(pb))
return AVERROR(EIO);
frame_size = avio_rl24(pb);
diff --git a/libavformat/vc1testenc.c b/libavformat/vc1testenc.c
index 9d55fee46d..751333a4b8 100644
--- a/libavformat/vc1testenc.c
+++ b/libavformat/vc1testenc.c
@@ -2,20 +2,20 @@
* VC-1 test bitstreams format muxer.
* Copyright (c) 2008 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avformat.h"
@@ -82,9 +82,8 @@ static int vc1test_write_trailer(AVFormatContext *s)
}
AVOutputFormat ff_vc1t_muxer = {
- .name = "rcv",
+ .name = "vc1test",
.long_name = NULL_IF_CONFIG_SMALL("VC-1 test bitstream"),
- .mime_type = "",
.extensions = "rcv",
.priv_data_size = sizeof(RCVContext),
.audio_codec = AV_CODEC_ID_NONE,
diff --git a/libavformat/version.h b/libavformat/version.h
index 495302ab87..e16d316286 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -1,20 +1,20 @@
/*
* Version macros.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,8 +30,8 @@
#include "libavutil/version.h"
#define LIBAVFORMAT_VERSION_MAJOR 56
-#define LIBAVFORMAT_VERSION_MINOR 18
-#define LIBAVFORMAT_VERSION_MICRO 0
+#define LIBAVFORMAT_VERSION_MINOR 33
+#define LIBAVFORMAT_VERSION_MICRO 101
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
@@ -57,5 +57,11 @@
#ifndef FF_API_LAVF_CODEC_TB
#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 57)
#endif
+#ifndef FF_API_URL_FEOF
+#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 57)
+#endif
+#ifndef FF_API_R_FRAME_RATE
+#define FF_API_R_FRAME_RATE 1
+#endif
#endif /* AVFORMAT_VERSION_H */
diff --git a/libavformat/vivo.c b/libavformat/vivo.c
new file mode 100644
index 0000000000..7287379801
--- /dev/null
+++ b/libavformat/vivo.c
@@ -0,0 +1,313 @@
+/*
+ * Vivo stream demuxer
+ * Copyright (c) 2009 Daniel Verkamp <daniel at drv.nu>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @brief Vivo stream demuxer
+ * @author Daniel Verkamp <daniel at drv.nu>
+ * @sa http://wiki.multimedia.cx/index.php?title=Vivo
+ */
+
+#include "libavutil/parseutils.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct VivoContext {
+ int version;
+
+ int type;
+ int sequence;
+ int length;
+
+ uint8_t text[1024 + 1];
+} VivoContext;
+
+static int vivo_probe(AVProbeData *p)
+{
+ const unsigned char *buf = p->buf;
+ unsigned c, length = 0;
+
+ // stream must start with packet of type 0 and sequence number 0
+ if (*buf++ != 0)
+ return 0;
+
+ // read at most 2 bytes of coded length
+ c = *buf++;
+ length = c & 0x7F;
+ if (c & 0x80) {
+ c = *buf++;
+ length = (length << 7) | (c & 0x7F);
+ }
+ if (c & 0x80 || length > 1024 || length < 21)
+ return 0;
+
+ if (memcmp(buf, "\r\nVersion:Vivo/", 15))
+ return 0;
+ buf += 15;
+
+ if (*buf < '0' && *buf > '2')
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+static int vivo_get_packet_header(AVFormatContext *s)
+{
+ VivoContext *vivo = s->priv_data;
+ AVIOContext *pb = s->pb;
+ unsigned c, get_length = 0;
+
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+
+ c = avio_r8(pb);
+ if (c == 0x82) {
+ get_length = 1;
+ c = avio_r8(pb);
+ }
+
+ vivo->type = c >> 4;
+ vivo->sequence = c & 0xF;
+
+ switch (vivo->type) {
+ case 0: get_length = 1; break;
+ case 1: vivo->length = 128; break;
+ case 2: get_length = 1; break;
+ case 3: vivo->length = 40; break;
+ case 4: vivo->length = 24; break;
+ default:
+ av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (get_length) {
+ c = avio_r8(pb);
+ vivo->length = c & 0x7F;
+ if (c & 0x80) {
+ c = avio_r8(pb);
+ vivo->length = (vivo->length << 7) | (c & 0x7F);
+
+ if (c & 0x80) {
+ av_log(s, AV_LOG_ERROR, "coded length is more than two bytes\n");
+ return AVERROR_INVALIDDATA;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int vivo_read_header(AVFormatContext *s)
+{
+ VivoContext *vivo = s->priv_data;
+ AVRational fps = { 1, 25};
+ AVStream *ast, *vst;
+ unsigned char *line, *line_end, *key, *value;
+ long value_int;
+ int ret, value_used;
+ int64_t duration = 0;
+ char *end_value;
+
+ vst = avformat_new_stream(s, NULL);
+ ast = avformat_new_stream(s, NULL);
+ if (!ast || !vst)
+ return AVERROR(ENOMEM);
+
+ ast->codec->sample_rate = 8000;
+
+ while (1) {
+ if ((ret = vivo_get_packet_header(s)) < 0)
+ return ret;
+
+ // done reading all text header packets?
+ if (vivo->sequence || vivo->type)
+ break;
+
+ if (vivo->length <= 1024) {
+ avio_read(s->pb, vivo->text, vivo->length);
+ vivo->text[vivo->length] = 0;
+ } else {
+ av_log(s, AV_LOG_WARNING, "too big header, skipping\n");
+ avio_skip(s->pb, vivo->length);
+ continue;
+ }
+
+ line = vivo->text;
+ while (*line) {
+ line_end = strstr(line, "\r\n");
+ if (!line_end)
+ break;
+
+ *line_end = 0;
+ key = line;
+ line = line_end + 2; // skip \r\n
+
+ if (line_end == key) // skip blank lines
+ continue;
+
+ value = strchr(key, ':');
+ if (!value) {
+ av_log(s, AV_LOG_WARNING, "missing colon in key:value pair '%s'\n",
+ value);
+ continue;
+ }
+
+ *value++ = 0;
+
+ av_log(s, AV_LOG_DEBUG, "header: '%s' = '%s'\n", key, value);
+
+ value_int = strtol(value, &end_value, 10);
+ value_used = 0;
+ if (*end_value == 0) { // valid integer
+ av_log(s, AV_LOG_DEBUG, "got a valid integer (%ld)\n", value_int);
+ value_used = 1;
+ if (!strcmp(key, "Duration")) {
+ duration = value_int;
+ } else if (!strcmp(key, "Width")) {
+ vst->codec->width = value_int;
+ } else if (!strcmp(key, "Height")) {
+ vst->codec->height = value_int;
+ } else if (!strcmp(key, "TimeUnitNumerator")) {
+ fps.num = value_int / 1000;
+ } else if (!strcmp(key, "TimeUnitDenominator")) {
+ fps.den = value_int;
+ } else if (!strcmp(key, "SamplingFrequency")) {
+ ast->codec->sample_rate = value_int;
+ } else if (!strcmp(key, "NominalBitrate")) {
+ } else if (!strcmp(key, "Length")) {
+ // size of file
+ } else {
+ value_used = 0;
+ }
+ }
+
+ if (!strcmp(key, "Version")) {
+ if (sscanf(value, "Vivo/%d.", &vivo->version) != 1)
+ return AVERROR_INVALIDDATA;
+ value_used = 1;
+ } else if (!strcmp(key, "FPS")) {
+ AVRational tmp;
+
+ value_used = 1;
+ if (!av_parse_ratio(&tmp, value, 10000, AV_LOG_WARNING, s))
+ fps = av_inv_q(tmp);
+ }
+
+ if (!value_used)
+ av_dict_set(&s->metadata, key, value, 0);
+ }
+ }
+
+ avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
+ avpriv_set_pts_info(vst, 64, fps.num, fps.den);
+ if (duration)
+ s->duration = av_rescale(duration, 1000, 1);
+
+ vst->start_time = 0;
+ vst->codec->codec_tag = 0;
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+
+ if (vivo->version == 1) {
+ vst->codec->codec_id = AV_CODEC_ID_H263;
+ ast->codec->codec_id = AV_CODEC_ID_G723_1;
+ ast->codec->bits_per_coded_sample = 8;
+ ast->codec->block_align = 24;
+ ast->codec->bit_rate = 6400;
+ }
+
+ ast->start_time = 0;
+ ast->codec->codec_tag = 0;
+ ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ ast->codec->channels = 1;
+
+ return 0;
+}
+
+static int vivo_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ VivoContext *vivo = s->priv_data;
+ AVIOContext *pb = s->pb;
+ unsigned old_sequence = vivo->sequence, old_type = vivo->type;
+ int stream_index, ret = 0;
+
+restart:
+
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+
+ switch (vivo->type) {
+ case 0:
+ avio_skip(pb, vivo->length);
+ if ((ret = vivo_get_packet_header(s)) < 0)
+ return ret;
+ goto restart;
+ case 1:
+ case 2: // video
+ stream_index = 0;
+ break;
+ case 3:
+ case 4: // audio
+ stream_index = 1;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "unknown packet type %d\n", vivo->type);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if ((ret = av_get_packet(pb, pkt, vivo->length)) < 0)
+ goto fail;
+
+ // get next packet header
+ if ((ret = vivo_get_packet_header(s)) < 0)
+ goto fail;
+
+ while (vivo->sequence == old_sequence &&
+ (((vivo->type - 1) >> 1) == ((old_type - 1) >> 1))) {
+ if (avio_feof(pb)) {
+ ret = AVERROR_EOF;
+ break;
+ }
+
+ if ((ret = av_append_packet(pb, pkt, vivo->length)) < 0)
+ break;
+
+ // get next packet header
+ if ((ret = vivo_get_packet_header(s)) < 0)
+ break;
+ }
+
+ pkt->stream_index = stream_index;
+
+fail:
+ if (ret < 0)
+ av_free_packet(pkt);
+ return ret;
+}
+
+AVInputFormat ff_vivo_demuxer = {
+ .name = "vivo",
+ .long_name = NULL_IF_CONFIG_SMALL("Vivo"),
+ .priv_data_size = sizeof(VivoContext),
+ .read_probe = vivo_probe,
+ .read_header = vivo_read_header,
+ .read_packet = vivo_read_packet,
+ .extensions = "viv",
+};
diff --git a/libavformat/voc.c b/libavformat/voc.c
index 1b7d499278..2a972344d3 100644
--- a/libavformat/voc.c
+++ b/libavformat/voc.c
@@ -2,20 +2,20 @@
* Creative Voice File common data.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/voc.h b/libavformat/voc.h
index d2c0cb46cb..1f9a8be000 100644
--- a/libavformat/voc.h
+++ b/libavformat/voc.h
@@ -2,20 +2,20 @@
* Creative Voice File demuxer.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
typedef struct voc_dec_context {
int64_t remaining_size;
+ int64_t pts;
} VocDecContext;
typedef enum voc_type {
diff --git a/libavformat/vocdec.c b/libavformat/vocdec.c
index 2fb8440931..c49ed163cb 100644
--- a/libavformat/vocdec.c
+++ b/libavformat/vocdec.c
@@ -2,20 +2,20 @@
* Creative Voice File demuxer.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -71,11 +71,20 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
int size, tmp_codec=-1;
int sample_rate = 0;
int channels = 1;
+ int64_t duration;
+ int ret;
+
+ av_add_index_entry(st,
+ avio_tell(pb),
+ voc->pts,
+ voc->remaining_size,
+ 0,
+ AVINDEX_KEYFRAME);
while (!voc->remaining_size) {
type = avio_r8(pb);
if (type == VOC_TYPE_EOF)
- return AVERROR(EIO);
+ return AVERROR_EOF;
voc->remaining_size = avio_rl24(pb);
if (!voc->remaining_size) {
if (!s->pb->seekable)
@@ -150,13 +159,23 @@ ff_voc_get_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st, int max_size)
}
}
- dec->bit_rate = dec->sample_rate * dec->bits_per_coded_sample;
+ dec->bit_rate = dec->sample_rate * dec->channels * dec->bits_per_coded_sample;
if (max_size <= 0)
max_size = 2048;
size = FFMIN(voc->remaining_size, max_size);
voc->remaining_size -= size;
- return av_get_packet(pb, pkt, size);
+
+ ret = av_get_packet(pb, pkt, size);
+ pkt->dts = pkt->pts = voc->pts;
+
+ duration = av_get_audio_frame_duration(st->codec, size);
+ if (duration > 0 && voc->pts != AV_NOPTS_VALUE)
+ voc->pts += duration;
+ else
+ voc->pts = AV_NOPTS_VALUE;
+
+ return ret;
}
static int voc_read_packet(AVFormatContext *s, AVPacket *pkt)
@@ -164,6 +183,28 @@ static int voc_read_packet(AVFormatContext *s, AVPacket *pkt)
return ff_voc_get_packet(s, pkt, s->streams[0], 0);
}
+static int voc_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags)
+{
+ VocDecContext *voc = s->priv_data;
+ AVStream *st = s->streams[stream_index];
+ int index = av_index_search_timestamp(st, timestamp, flags);
+
+ if (index >= 0 && index < st->nb_index_entries - 1) {
+ AVIndexEntry *e = &st->index_entries[index];
+ avio_seek(s->pb, e->pos, SEEK_SET);
+ voc->pts = e->timestamp;
+ voc->remaining_size = e->size;
+ return 0;
+ } else if (st->nb_index_entries && st->index_entries[0].timestamp <= timestamp) {
+ AVIndexEntry *e = &st->index_entries[st->nb_index_entries - 1];
+ // prepare context for seek_frame_generic()
+ voc->pts = e->timestamp;
+ voc->remaining_size = e->size;
+ }
+ return -1;
+}
+
AVInputFormat ff_voc_demuxer = {
.name = "voc",
.long_name = NULL_IF_CONFIG_SMALL("Creative Voice"),
@@ -171,5 +212,6 @@ AVInputFormat ff_voc_demuxer = {
.read_probe = voc_probe,
.read_header = voc_read_header,
.read_packet = voc_read_packet,
+ .read_seek = voc_read_seek,
.codec_tag = (const AVCodecTag* const []){ ff_voc_codec_tags, 0 },
};
diff --git a/libavformat/vocenc.c b/libavformat/vocenc.c
index ed10a96f7a..0bb532e0c6 100644
--- a/libavformat/vocenc.c
+++ b/libavformat/vocenc.c
@@ -2,20 +2,20 @@
* Creative Voice File muxer.
* Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,7 @@ typedef struct voc_enc_context {
static int voc_write_header(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
+ AVCodecContext *enc = s->streams[0]->codec;
const int header_size = 26;
const int version = 0x0114;
@@ -37,6 +38,11 @@ static int voc_write_header(AVFormatContext *s)
|| s->streams[0]->codec->codec_type != AVMEDIA_TYPE_AUDIO)
return AVERROR_PATCHWELCOME;
+ if (!enc->codec_tag && enc->codec_id != AV_CODEC_ID_PCM_U8) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+ return AVERROR(EINVAL);
+ }
+
avio_write(pb, ff_voc_magic, sizeof(ff_voc_magic) - 1);
avio_wl16(pb, header_size);
avio_wl16(pb, version);
@@ -52,7 +58,7 @@ static int voc_write_packet(AVFormatContext *s, AVPacket *pkt)
AVIOContext *pb = s->pb;
if (!voc->param_written) {
- if (enc->codec_tag > 0xFF) {
+ if (enc->codec_tag > 3) {
avio_w8(pb, VOC_TYPE_NEW_VOICE_DATA);
avio_wl24(pb, pkt->size + 12);
avio_wl32(pb, enc->sample_rate);
@@ -64,13 +70,13 @@ static int voc_write_packet(AVFormatContext *s, AVPacket *pkt)
if (s->streams[0]->codec->channels > 1) {
avio_w8(pb, VOC_TYPE_EXTENDED);
avio_wl24(pb, 4);
- avio_wl16(pb, 65536-256000000/(enc->sample_rate*enc->channels));
+ avio_wl16(pb, 65536-(256000000 + enc->sample_rate*enc->channels/2)/(enc->sample_rate*enc->channels));
avio_w8(pb, enc->codec_tag);
avio_w8(pb, enc->channels - 1);
}
avio_w8(pb, VOC_TYPE_VOICE_DATA);
avio_wl24(pb, pkt->size + 2);
- avio_w8(pb, 256 - 1000000 / enc->sample_rate);
+ avio_w8(pb, 256 - (1000000 + enc->sample_rate/2) / enc->sample_rate);
avio_w8(pb, enc->codec_tag);
}
voc->param_written = 1;
@@ -95,7 +101,7 @@ AVOutputFormat ff_voc_muxer = {
.mime_type = "audio/x-voc",
.extensions = "voc",
.priv_data_size = sizeof(VocEncContext),
- .audio_codec = AV_CODEC_ID_PCM_U8,
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
.video_codec = AV_CODEC_ID_NONE,
.write_header = voc_write_header,
.write_packet = voc_write_packet,
diff --git a/libavformat/vorbiscomment.c b/libavformat/vorbiscomment.c
index ee06a57336..575dd13328 100644
--- a/libavformat/vorbiscomment.c
+++ b/libavformat/vorbiscomment.c
@@ -2,20 +2,20 @@
* VorbisComment writer
* Copyright (c) 2009 James Darnley
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,12 +34,13 @@ const AVMetadataConv ff_vorbiscomment_metadata_conv[] = {
{ "ALBUMARTIST", "album_artist"},
{ "TRACKNUMBER", "track" },
{ "DISCNUMBER", "disc" },
+ { "DESCRIPTION", "comment" },
{ 0 }
};
-int ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string)
+int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string)
{
- int len = 8;
+ int64_t len = 8;
len += strlen(vendor_string);
if (m) {
AVDictionaryEntry *tag = NULL;
@@ -60,8 +61,10 @@ int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m,
AVDictionaryEntry *tag = NULL;
bytestream_put_le32(p, count);
while ((tag = av_dict_get(*m, "", tag, AV_DICT_IGNORE_SUFFIX))) {
- unsigned int len1 = strlen(tag->key);
- unsigned int len2 = strlen(tag->value);
+ int64_t len1 = strlen(tag->key);
+ int64_t len2 = strlen(tag->value);
+ if (len1+1+len2 > UINT32_MAX)
+ return AVERROR(EINVAL);
bytestream_put_le32(p, len1+1+len2);
bytestream_put_buffer(p, tag->key, len1);
bytestream_put_byte(p, '=');
diff --git a/libavformat/vorbiscomment.h b/libavformat/vorbiscomment.h
index d9ec099b3f..e0d30b14a7 100644
--- a/libavformat/vorbiscomment.h
+++ b/libavformat/vorbiscomment.h
@@ -2,20 +2,20 @@
* VorbisComment writer
* Copyright (c) 2009 James Darnley
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,7 +34,7 @@
* For no string, set to an empty string.
* @return The length in bytes.
*/
-int ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string);
+int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string);
/**
* Write a VorbisComment into a buffer. The buffer, p, must have enough
diff --git a/libavformat/vplayerdec.c b/libavformat/vplayerdec.c
new file mode 100644
index 0000000000..619ccfd4f0
--- /dev/null
+++ b/libavformat/vplayerdec.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * VPlayer subtitles format demuxer
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+
+typedef struct {
+ FFDemuxSubtitlesQueue q;
+} VPlayerContext;
+
+static int vplayer_probe(AVProbeData *p)
+{
+ char c;
+ const unsigned char *ptr = p->buf;
+
+ if (sscanf(ptr, "%*d:%*d:%*d.%*d%c", &c) == 1 && strchr(": =", c))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int64_t read_ts(char **line)
+{
+ char c;
+ int hh, mm, ss, ms, len;
+
+ if (sscanf(*line, "%d:%d:%d.%d%c%n",
+ &hh, &mm, &ss, &ms, &c, &len) >= 5) {
+ *line += len;
+ return (hh*3600LL + mm*60LL + ss) * 100LL + ms;
+ }
+ return AV_NOPTS_VALUE;
+}
+
+static int vplayer_read_header(AVFormatContext *s)
+{
+ VPlayerContext *vplayer = s->priv_data;
+ AVStream *st = avformat_new_stream(s, NULL);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 100);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_VPLAYER;
+
+ while (!avio_feof(s->pb)) {
+ char line[4096];
+ char *p = line;
+ const int64_t pos = avio_tell(s->pb);
+ int len = ff_get_line(s->pb, line, sizeof(line));
+ int64_t pts_start;
+
+ if (!len)
+ break;
+
+ line[strcspn(line, "\r\n")] = 0;
+
+ pts_start = read_ts(&p);
+ if (pts_start != AV_NOPTS_VALUE) {
+ AVPacket *sub;
+
+ sub = ff_subtitles_queue_insert(&vplayer->q, p, strlen(p), 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ sub->pos = pos;
+ sub->pts = pts_start;
+ sub->duration = -1;
+ }
+ }
+
+ ff_subtitles_queue_finalize(&vplayer->q);
+ return 0;
+}
+
+static int vplayer_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ VPlayerContext *vplayer = s->priv_data;
+ return ff_subtitles_queue_read_packet(&vplayer->q, pkt);
+}
+
+static int vplayer_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ VPlayerContext *vplayer = s->priv_data;
+ return ff_subtitles_queue_seek(&vplayer->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int vplayer_read_close(AVFormatContext *s)
+{
+ VPlayerContext *vplayer = s->priv_data;
+ ff_subtitles_queue_clean(&vplayer->q);
+ return 0;
+}
+
+AVInputFormat ff_vplayer_demuxer = {
+ .name = "vplayer",
+ .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitles"),
+ .priv_data_size = sizeof(VPlayerContext),
+ .read_probe = vplayer_probe,
+ .read_header = vplayer_read_header,
+ .read_packet = vplayer_read_packet,
+ .read_seek2 = vplayer_read_seek,
+ .read_close = vplayer_read_close,
+ .extensions = "txt",
+};
diff --git a/libavformat/vqf.c b/libavformat/vqf.c
index c04ffe74ee..29c726dae9 100644
--- a/libavformat/vqf.c
+++ b/libavformat/vqf.c
@@ -2,20 +2,20 @@
* VQF demuxer
* Copyright (c) 2009 Vitor Sessak
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,6 +43,9 @@ static int vqf_probe(AVProbeData *probe_packet)
if (!memcmp(probe_packet->buf + 4, "00052200", 8))
return AVPROBE_SCORE_MAX;
+ if (AV_RL32(probe_packet->buf + 12) > (1<<27))
+ return AVPROBE_SCORE_EXTENSION/2;
+
return AVPROBE_SCORE_EXTENSION;
}
@@ -132,15 +135,16 @@ static int vqf_read_header(AVFormatContext *s)
rate_flag = AV_RB32(comm_chunk + 8);
avio_skip(s->pb, len-12);
+ if (st->codec->channels <= 0) {
+ av_log(s, AV_LOG_ERROR, "Invalid number of channels\n");
+ return AVERROR_INVALIDDATA;
+ }
+
st->codec->bit_rate = read_bitrate*1000;
break;
case MKTAG('D','S','I','Z'): // size of compressed data
{
- char buf[8] = {0};
- int size = avio_rb32(s->pb);
-
- snprintf(buf, sizeof(buf), "%d", size);
- av_dict_set(&s->metadata, "size", buf, 0);
+ av_dict_set_int(&s->metadata, "size", avio_rb32(s->pb), 0);
}
break;
case MKTAG('Y','E','A','R'): // recording date
@@ -158,7 +162,7 @@ static int vqf_read_header(AVFormatContext *s)
header_size -= len;
- } while (header_size >= 0);
+ } while (header_size >= 0 && !avio_feof(s->pb));
switch (rate_flag) {
case -1:
@@ -215,9 +219,8 @@ static int vqf_read_header(AVFormatContext *s)
avpriv_set_pts_info(st, 64, size, st->codec->sample_rate);
/* put first 12 bytes of COMM chunk in extradata */
- if (!(st->codec->extradata = av_malloc(12 + FF_INPUT_BUFFER_PADDING_SIZE)))
+ if (ff_alloc_extradata(st->codec, 12))
return AVERROR(ENOMEM);
- st->codec->extradata_size = 12;
memcpy(st->codec->extradata, comm_chunk, 12);
ff_metadata_conv_ctx(s, NULL, vqf_metadata_conv);
@@ -242,7 +245,7 @@ static int vqf_read_packet(AVFormatContext *s, AVPacket *pkt)
pkt->data[1] = c->last_frame_bits;
ret = avio_read(s->pb, pkt->data+2, size);
- if (ret<=0) {
+ if (ret != size) {
av_free_packet(pkt);
return AVERROR(EIO);
}
@@ -258,7 +261,7 @@ static int vqf_read_seek(AVFormatContext *s,
{
VqfContext *c = s->priv_data;
AVStream *st;
- int ret;
+ int64_t ret;
int64_t pos;
st = s->streams[stream_index];
diff --git a/libavformat/w64.c b/libavformat/w64.c
new file mode 100644
index 0000000000..ef2d90a600
--- /dev/null
+++ b/libavformat/w64.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2009 Daniel Verkamp
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "w64.h"
+
+const uint8_t ff_w64_guid_riff[16] = {
+ 'r', 'i', 'f', 'f',
+ 0x2E, 0x91, 0xCF, 0x11, 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
+};
+
+const uint8_t ff_w64_guid_wave[16] = {
+ 'w', 'a', 'v', 'e',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_fmt [16] = {
+ 'f', 'm', 't', ' ',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_fact[16] = { 'f', 'a', 'c', 't',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_data[16] = {
+ 'd', 'a', 't', 'a',
+ 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
+
+const uint8_t ff_w64_guid_summarylist[16] = {
+ 0xBC, 0x94, 0x5F, 0x92,
+ 0x5A, 0x52, 0xD2, 0x11, 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
+};
diff --git a/libavformat/w64.h b/libavformat/w64.h
new file mode 100644
index 0000000000..0ec3fa9141
--- /dev/null
+++ b/libavformat/w64.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_W64_H
+#define AVFORMAT_W64_H
+
+#include <stdint.h>
+
+extern const uint8_t ff_w64_guid_riff[16];
+extern const uint8_t ff_w64_guid_wave[16];
+extern const uint8_t ff_w64_guid_fmt [16];
+extern const uint8_t ff_w64_guid_fact[16];
+extern const uint8_t ff_w64_guid_data[16];
+extern const uint8_t ff_w64_guid_summarylist[16];
+
+#endif /* AVFORMAT_W64_H */
diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c
index f65a66a006..864185f989 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -6,20 +6,20 @@
* RF64 demuxer
* Copyright (c) 2009 Daniel Verkamp
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "libavutil/avassert.h"
#include "libavutil/dict.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -37,39 +38,61 @@
#include "metadata.h"
#include "pcm.h"
#include "riff.h"
+#include "w64.h"
+#include "spdif.h"
typedef struct WAVDemuxContext {
+ const AVClass *class;
int64_t data_end;
int w64;
+ int64_t smv_data_ofs;
+ int smv_block_size;
+ int smv_frames_per_jpeg;
+ int smv_block;
+ int smv_last_stream;
+ int smv_eof;
+ int audio_eof;
+ int ignore_length;
+ int spdif;
+ int smv_cur_pt;
+ int smv_given_first;
+ int unaligned; // e.g. if an odd number of bytes ID3 tag was prepended
+ int rifx; // RIFX: integer byte order for parameters is big endian
} WAVDemuxContext;
#if CONFIG_WAV_DEMUXER
-static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
+static int64_t next_tag(AVIOContext *pb, uint32_t *tag, int big_endian)
{
*tag = avio_rl32(pb);
- return avio_rl32(pb);
+ if (!big_endian) {
+ return avio_rl32(pb);
+ } else {
+ return avio_rb32(pb);
+ }
}
-/* RIFF chunks are always on a even offset. */
-static int64_t wav_seek_tag(AVIOContext *s, int64_t offset, int whence)
+/* RIFF chunks are always at even offsets relative to where they start. */
+static int64_t wav_seek_tag(WAVDemuxContext * wav, AVIOContext *s, int64_t offset, int whence)
{
- return avio_seek(s, offset + (offset & 1), whence);
+ offset += offset < INT64_MAX && offset + wav->unaligned & 1;
+
+ return avio_seek(s, offset, whence);
}
/* return the size of the found tag */
-static int64_t find_tag(AVIOContext *pb, uint32_t tag1)
+static int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1)
{
unsigned int tag;
int64_t size;
for (;;) {
- if (pb->eof_reached)
- return -1;
- size = next_tag(pb, &tag);
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+ size = next_tag(pb, &tag, wav->rifx);
if (tag == tag1)
break;
- wav_seek_tag(pb, size, SEEK_CUR);
+ wav_seek_tag(wav, pb, size, SEEK_CUR);
}
return size;
}
@@ -80,7 +103,7 @@ static int wav_probe(AVProbeData *p)
if (p->buf_size <= 32)
return 0;
if (!memcmp(p->buf + 8, "WAVE", 4)) {
- if (!memcmp(p->buf, "RIFF", 4))
+ if (!memcmp(p->buf, "RIFF", 4) || !memcmp(p->buf, "RIFX", 4))
/* Since the ACT demuxer has a standard WAV header at the top of
* its own, the returned score is decreased to avoid a probe
* conflict between ACT and WAV. */
@@ -92,9 +115,18 @@ static int wav_probe(AVProbeData *p)
return 0;
}
+static void handle_stream_probing(AVStream *st)
+{
+ if (st->codec->codec_id == AV_CODEC_ID_PCM_S16LE) {
+ st->request_probe = AVPROBE_SCORE_EXTENSION;
+ st->probe_packets = FFMIN(st->probe_packets, 32);
+ }
+}
+
static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st)
{
AVIOContext *pb = s->pb;
+ WAVDemuxContext *wav = s->priv_data;
int ret;
/* parse fmt header */
@@ -102,10 +134,12 @@ static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st)
if (!*st)
return AVERROR(ENOMEM);
- ret = ff_get_wav_header(pb, (*st)->codec, size);
+ ret = ff_get_wav_header(pb, (*st)->codec, size, wav->rifx);
if (ret < 0)
return ret;
- (*st)->need_parsing = AVSTREAM_PARSE_FULL;
+ handle_stream_probing(*st);
+
+ (*st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
avpriv_set_pts_info(*st, 64, 1, (*st)->codec->sample_rate);
@@ -167,7 +201,7 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size)
/* extended UMID */
snprintf(temp, sizeof(temp),
"0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64
- "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
+ "%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64,
umid_parts[0], umid_parts[1],
umid_parts[2], umid_parts[3],
umid_parts[4], umid_parts[5],
@@ -214,7 +248,8 @@ static int wav_read_header(AVFormatContext *s)
{
int64_t size, av_uninit(data_size);
int64_t sample_count = 0;
- int rf64;
+ int rf64 = 0;
+ char start_code[32];
uint32_t tag;
AVIOContext *pb = s->pb;
AVStream *st = NULL;
@@ -222,22 +257,41 @@ static int wav_read_header(AVFormatContext *s)
int ret, got_fmt = 0;
int64_t next_tag_ofs, data_ofs = -1;
- /* check RIFF header */
- tag = avio_rl32(pb);
+ wav->unaligned = avio_tell(s->pb) & 1;
- rf64 = tag == MKTAG('R', 'F', '6', '4');
- if (!rf64 && tag != MKTAG('R', 'I', 'F', 'F'))
- return AVERROR_INVALIDDATA;
- avio_rl32(pb); /* file size */
+ wav->smv_data_ofs = -1;
+
+ /* read chunk ID */
tag = avio_rl32(pb);
- if (tag != MKTAG('W', 'A', 'V', 'E'))
+ switch (tag) {
+ case MKTAG('R', 'I', 'F', 'F'):
+ break;
+ case MKTAG('R', 'I', 'F', 'X'):
+ wav->rifx = 1;
+ break;
+ case MKTAG('R', 'F', '6', '4'):
+ rf64 = 1;
+ break;
+ default:
+ av_get_codec_tag_string(start_code, sizeof(start_code), tag);
+ av_log(s, AV_LOG_ERROR, "invalid start code %s in RIFF header\n", start_code);
return AVERROR_INVALIDDATA;
+ }
+
+ /* read chunk size */
+ avio_rl32(pb);
+
+ /* read format */
+ if (avio_rl32(pb) != MKTAG('W', 'A', 'V', 'E')) {
+ av_log(s, AV_LOG_ERROR, "invalid format in RIFF header\n");
+ return AVERROR_INVALIDDATA;
+ }
if (rf64) {
if (avio_rl32(pb) != MKTAG('d', 's', '6', '4'))
return AVERROR_INVALIDDATA;
size = avio_rl32(pb);
- if (size < 16)
+ if (size < 24)
return AVERROR_INVALIDDATA;
avio_rl64(pb); /* RIFF size */
@@ -250,20 +304,22 @@ static int wav_read_header(AVFormatContext *s)
data_size, sample_count);
return AVERROR_INVALIDDATA;
}
- avio_skip(pb, size - 16); /* skip rest of ds64 chunk */
+ avio_skip(pb, size - 24); /* skip rest of ds64 chunk */
+
}
for (;;) {
- size = next_tag(pb, &tag);
+ AVStream *vst;
+ size = next_tag(pb, &tag, wav->rifx);
next_tag_ofs = avio_tell(pb) + size;
- if (pb->eof_reached)
+ if (avio_feof(pb))
break;
switch (tag) {
case MKTAG('f', 'm', 't', ' '):
/* only parse the first 'fmt ' tag found */
- if (!got_fmt && (ret = wav_parse_fmt_tag(s, size, &st) < 0)) {
+ if (!got_fmt && (ret = wav_parse_fmt_tag(s, size, &st)) < 0) {
return ret;
} else if (got_fmt)
av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n");
@@ -279,9 +335,14 @@ static int wav_read_header(AVFormatContext *s)
if (rf64) {
next_tag_ofs = wav->data_end = avio_tell(pb) + data_size;
- } else {
+ } else if (size != 0xFFFFFFFF) {
data_size = size;
next_tag_ofs = wav->data_end = size ? next_tag_ofs : INT64_MAX;
+ } else {
+ av_log(s, AV_LOG_WARNING, "Ignoring maximum wav data size, "
+ "file may be invalid\n");
+ data_size = 0;
+ next_tag_ofs = wav->data_end = INT64_MAX;
}
data_ofs = avio_tell(pb);
@@ -294,28 +355,68 @@ static int wav_read_header(AVFormatContext *s)
break;
case MKTAG('f', 'a', 'c', 't'):
if (!sample_count)
- sample_count = avio_rl32(pb);
+ sample_count = (!wav->rifx ? avio_rl32(pb) : avio_rb32(pb));
break;
case MKTAG('b', 'e', 'x', 't'):
if ((ret = wav_parse_bext_tag(s, size)) < 0)
return ret;
break;
+ case MKTAG('S','M','V','0'):
+ if (!got_fmt) {
+ av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'SMV0' tag\n");
+ return AVERROR_INVALIDDATA;
+ }
+ // SMV file, a wav file with video appended.
+ if (size != MKTAG('0','2','0','0')) {
+ av_log(s, AV_LOG_ERROR, "Unknown SMV version found\n");
+ goto break_loop;
+ }
+ av_log(s, AV_LOG_DEBUG, "Found SMV data\n");
+ wav->smv_given_first = 0;
+ vst = avformat_new_stream(s, NULL);
+ if (!vst)
+ return AVERROR(ENOMEM);
+ avio_r8(pb);
+ vst->id = 1;
+ vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ vst->codec->codec_id = AV_CODEC_ID_SMVJPEG;
+ vst->codec->width = avio_rl24(pb);
+ vst->codec->height = avio_rl24(pb);
+ if (ff_alloc_extradata(vst->codec, 4)) {
+ av_log(s, AV_LOG_ERROR, "Could not allocate extradata.\n");
+ return AVERROR(ENOMEM);
+ }
+ size = avio_rl24(pb);
+ wav->smv_data_ofs = avio_tell(pb) + (size - 5) * 3;
+ avio_rl24(pb);
+ wav->smv_block_size = avio_rl24(pb);
+ avpriv_set_pts_info(vst, 32, 1, avio_rl24(pb));
+ vst->duration = avio_rl24(pb);
+ avio_rl24(pb);
+ avio_rl24(pb);
+ wav->smv_frames_per_jpeg = avio_rl24(pb);
+ if (wav->smv_frames_per_jpeg > 65536) {
+ av_log(s, AV_LOG_ERROR, "too many frames per jpeg\n");
+ return AVERROR_INVALIDDATA;
+ }
+ AV_WL32(vst->codec->extradata, wav->smv_frames_per_jpeg);
+ wav->smv_cur_pt = 0;
+ goto break_loop;
case MKTAG('L', 'I', 'S', 'T'):
if (size < 4) {
- av_log(s, AV_LOG_ERROR, "too short LIST");
+ av_log(s, AV_LOG_ERROR, "too short LIST tag\n");
return AVERROR_INVALIDDATA;
}
switch (avio_rl32(pb)) {
case MKTAG('I', 'N', 'F', 'O'):
- if ((ret = ff_read_riff_info(s, size - 4)) < 0)
- return ret;
+ ff_read_riff_info(s, size - 4);
}
break;
}
/* seek to next tag unless we know that we'll run into EOF */
if ((avio_size(pb) > 0 && next_tag_ofs >= avio_size(pb)) ||
- wav_seek_tag(pb, next_tag_ofs, SEEK_SET) < 0) {
+ wav_seek_tag(wav, pb, next_tag_ofs, SEEK_SET) < 0) {
break;
}
}
@@ -328,11 +429,21 @@ break_loop:
avio_seek(pb, data_ofs, SEEK_SET);
- if (!sample_count && st->codec->channels &&
- av_get_bits_per_sample(st->codec->codec_id))
- sample_count = (data_size << 3) /
- (st->codec->channels *
- (uint64_t)av_get_bits_per_sample(st->codec->codec_id));
+ if ( data_size > 0 && sample_count && st->codec->channels
+ && data_size / sample_count / st->codec->channels > 8) {
+ av_log(s, AV_LOG_WARNING, "ignoring wrong sample_count %"PRId64"\n", sample_count);
+ sample_count = 0;
+ }
+
+ if (!sample_count || av_get_exact_bits_per_sample(st->codec->codec_id) > 0)
+ if ( st->codec->channels
+ && data_size
+ && av_get_bits_per_sample(st->codec->codec_id)
+ && wav->data_end <= avio_size(pb))
+ sample_count = (data_size << 3)
+ /
+ (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id));
+
if (sample_count)
st->duration = sample_count;
@@ -351,23 +462,18 @@ static int64_t find_guid(AVIOContext *pb, const uint8_t guid1[16])
uint8_t guid[16];
int64_t size;
- while (!pb->eof_reached) {
+ while (!avio_feof(pb)) {
avio_read(pb, guid, 16);
size = avio_rl64(pb);
if (size <= 24)
- return -1;
+ return AVERROR_INVALIDDATA;
if (!memcmp(guid, guid1, 16))
return size;
avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
}
- return -1;
+ return AVERROR_EOF;
}
-static const uint8_t guid_data[16] = {
- 'd', 'a', 't', 'a',
- 0xF3, 0xAC, 0xD3, 0x11,0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
-};
-
#define MAX_SIZE 4096
static int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
@@ -377,16 +483,84 @@ static int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
AVStream *st;
WAVDemuxContext *wav = s->priv_data;
+ if (CONFIG_SPDIF_DEMUXER && wav->spdif == 0 &&
+ s->streams[0]->codec->codec_tag == 1) {
+ enum AVCodecID codec;
+ ret = ff_spdif_probe(s->pb->buffer, s->pb->buf_end - s->pb->buffer,
+ &codec);
+ if (ret > AVPROBE_SCORE_EXTENSION) {
+ s->streams[0]->codec->codec_id = codec;
+ wav->spdif = 1;
+ } else {
+ wav->spdif = -1;
+ }
+ }
+ if (CONFIG_SPDIF_DEMUXER && wav->spdif == 1)
+ return ff_spdif_read_packet(s, pkt);
+
+ if (wav->smv_data_ofs > 0) {
+ int64_t audio_dts, video_dts;
+smv_retry:
+ audio_dts = (int32_t)s->streams[0]->cur_dts;
+ video_dts = (int32_t)s->streams[1]->cur_dts;
+
+ if (audio_dts != AV_NOPTS_VALUE && video_dts != AV_NOPTS_VALUE) {
+ /*We always return a video frame first to get the pixel format first*/
+ wav->smv_last_stream = wav->smv_given_first ?
+ av_compare_ts(video_dts, s->streams[1]->time_base,
+ audio_dts, s->streams[0]->time_base) > 0 : 0;
+ wav->smv_given_first = 1;
+ }
+ wav->smv_last_stream = !wav->smv_last_stream;
+ wav->smv_last_stream |= wav->audio_eof;
+ wav->smv_last_stream &= !wav->smv_eof;
+ if (wav->smv_last_stream) {
+ uint64_t old_pos = avio_tell(s->pb);
+ uint64_t new_pos = wav->smv_data_ofs +
+ wav->smv_block * wav->smv_block_size;
+ if (avio_seek(s->pb, new_pos, SEEK_SET) < 0) {
+ ret = AVERROR_EOF;
+ goto smv_out;
+ }
+ size = avio_rl24(s->pb);
+ ret = av_get_packet(s->pb, pkt, size);
+ if (ret < 0)
+ goto smv_out;
+ pkt->pos -= 3;
+ pkt->pts = wav->smv_block * wav->smv_frames_per_jpeg + wav->smv_cur_pt;
+ wav->smv_cur_pt++;
+ if (wav->smv_frames_per_jpeg > 0)
+ wav->smv_cur_pt %= wav->smv_frames_per_jpeg;
+ if (!wav->smv_cur_pt)
+ wav->smv_block++;
+
+ pkt->stream_index = 1;
+smv_out:
+ avio_seek(s->pb, old_pos, SEEK_SET);
+ if (ret == AVERROR_EOF) {
+ wav->smv_eof = 1;
+ goto smv_retry;
+ }
+ return ret;
+ }
+ }
+
st = s->streams[0];
left = wav->data_end - avio_tell(s->pb);
+ if (wav->ignore_length)
+ left = INT_MAX;
if (left <= 0) {
if (CONFIG_W64_DEMUXER && wav->w64)
- left = find_guid(s->pb, guid_data) - 24;
+ left = find_guid(s->pb, ff_w64_guid_data) - 24;
else
- left = find_tag(s->pb, MKTAG('d', 'a', 't', 'a'));
- if (left < 0)
+ left = find_tag(wav, s->pb, MKTAG('d', 'a', 't', 'a'));
+ if (left < 0) {
+ wav->audio_eof = 1;
+ if (wav->smv_data_ofs > 0 && !wav->smv_eof)
+ goto smv_retry;
return AVERROR_EOF;
+ }
wav->data_end = avio_tell(s->pb) + left;
}
@@ -408,7 +582,21 @@ static int wav_read_packet(AVFormatContext *s, AVPacket *pkt)
static int wav_read_seek(AVFormatContext *s,
int stream_index, int64_t timestamp, int flags)
{
+ WAVDemuxContext *wav = s->priv_data;
AVStream *st;
+ wav->smv_eof = 0;
+ wav->audio_eof = 0;
+ if (wav->smv_data_ofs > 0) {
+ int64_t smv_timestamp = timestamp;
+ if (stream_index == 0)
+ smv_timestamp = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[1]->time_base);
+ else
+ timestamp = av_rescale_q(smv_timestamp, s->streams[1]->time_base, s->streams[0]->time_base);
+ if (wav->smv_frames_per_jpeg > 0) {
+ wav->smv_block = smv_timestamp / wav->smv_frames_per_jpeg;
+ wav->smv_cur_pt = smv_timestamp % wav->smv_frames_per_jpeg;
+ }
+ }
st = s->streams[0];
switch (st->codec->codec_id) {
@@ -424,6 +612,19 @@ static int wav_read_seek(AVFormatContext *s,
return ff_pcm_read_seek(s, stream_index, timestamp, flags);
}
+#define OFFSET(x) offsetof(WAVDemuxContext, x)
+#define DEC AV_OPT_FLAG_DECODING_PARAM
+static const AVOption demux_options[] = {
+ { "ignore_length", "Ignore length", OFFSET(ignore_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC },
+ { NULL },
+};
+
+static const AVClass wav_demuxer_class = {
+ .class_name = "WAV demuxer",
+ .item_name = av_default_item_name,
+ .option = demux_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
AVInputFormat ff_wav_demuxer = {
.name = "wav",
.long_name = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"),
@@ -434,31 +635,17 @@ AVInputFormat ff_wav_demuxer = {
.read_seek = wav_read_seek,
.flags = AVFMT_GENERIC_INDEX,
.codec_tag = (const AVCodecTag * const []) { ff_codec_wav_tags, 0 },
+ .priv_class = &wav_demuxer_class,
};
#endif /* CONFIG_WAV_DEMUXER */
#if CONFIG_W64_DEMUXER
-static const uint8_t guid_riff[16] = {
- 'r', 'i', 'f', 'f',
- 0x2E, 0x91, 0xCF, 0x11,0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00
-};
-
-static const uint8_t guid_wave[16] = {
- 'w', 'a', 'v', 'e',
- 0xF3, 0xAC, 0xD3, 0x11,0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
-};
-
-static const uint8_t guid_fmt[16] = {
- 'f', 'm', 't', ' ',
- 0xF3, 0xAC, 0xD3, 0x11,0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
-};
-
static int w64_probe(AVProbeData *p)
{
if (p->buf_size <= 40)
return 0;
- if (!memcmp(p->buf, guid_riff, 16) &&
- !memcmp(p->buf + 24, guid_wave, 16))
+ if (!memcmp(p->buf, ff_w64_guid_riff, 16) &&
+ !memcmp(p->buf + 24, ff_w64_guid_wave, 16))
return AVPROBE_SCORE_MAX;
else
return 0;
@@ -466,7 +653,7 @@ static int w64_probe(AVProbeData *p)
static int w64_read_header(AVFormatContext *s)
{
- int64_t size;
+ int64_t size, data_ofs = 0;
AVIOContext *pb = s->pb;
WAVDemuxContext *wav = s->priv_data;
AVStream *st;
@@ -474,7 +661,7 @@ static int w64_read_header(AVFormatContext *s)
int ret;
avio_read(pb, guid, 16);
- if (memcmp(guid, guid_riff, 16))
+ if (memcmp(guid, ff_w64_guid_riff, 16))
return AVERROR_INVALIDDATA;
/* riff + wave + fmt + sizes */
@@ -482,38 +669,91 @@ static int w64_read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
avio_read(pb, guid, 16);
- if (memcmp(guid, guid_wave, 16)) {
+ if (memcmp(guid, ff_w64_guid_wave, 16)) {
av_log(s, AV_LOG_ERROR, "could not find wave guid\n");
return AVERROR_INVALIDDATA;
}
- size = find_guid(pb, guid_fmt);
- if (size < 0) {
- av_log(s, AV_LOG_ERROR, "could not find fmt guid\n");
- return AVERROR_INVALIDDATA;
- }
+ wav->w64 = 1;
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
- /* subtract chunk header size - normal wav file doesn't count it */
- ret = ff_get_wav_header(pb, st->codec, size - 24);
- if (ret < 0)
- return ret;
- avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
+ while (!avio_feof(pb)) {
+ if (avio_read(pb, guid, 16) != 16)
+ break;
+ size = avio_rl64(pb);
+ if (size <= 24 || INT64_MAX - size < avio_tell(pb))
+ return AVERROR_INVALIDDATA;
- st->need_parsing = AVSTREAM_PARSE_FULL;
+ if (!memcmp(guid, ff_w64_guid_fmt, 16)) {
+ /* subtract chunk header size - normal wav file doesn't count it */
+ ret = ff_get_wav_header(pb, st->codec, size - 24, 0);
+ if (ret < 0)
+ return ret;
+ avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
- avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
+ } else if (!memcmp(guid, ff_w64_guid_fact, 16)) {
+ int64_t samples;
- size = find_guid(pb, guid_data);
- if (size < 0) {
- av_log(s, AV_LOG_ERROR, "could not find data guid\n");
- return AVERROR_INVALIDDATA;
+ samples = avio_rl64(pb);
+ if (samples > 0)
+ st->duration = samples;
+ } else if (!memcmp(guid, ff_w64_guid_data, 16)) {
+ wav->data_end = avio_tell(pb) + size - 24;
+
+ data_ofs = avio_tell(pb);
+ if (!pb->seekable)
+ break;
+
+ avio_skip(pb, size - 24);
+ } else if (!memcmp(guid, ff_w64_guid_summarylist, 16)) {
+ int64_t start, end, cur;
+ uint32_t count, chunk_size, i;
+
+ start = avio_tell(pb);
+ end = start + FFALIGN(size, INT64_C(8)) - 24;
+ count = avio_rl32(pb);
+
+ for (i = 0; i < count; i++) {
+ char chunk_key[5], *value;
+
+ if (avio_feof(pb) || (cur = avio_tell(pb)) < 0 || cur > end - 8 /* = tag + size */)
+ break;
+
+ chunk_key[4] = 0;
+ avio_read(pb, chunk_key, 4);
+ chunk_size = avio_rl32(pb);
+
+ value = av_mallocz(chunk_size + 1);
+ if (!value)
+ return AVERROR(ENOMEM);
+
+ ret = avio_get_str16le(pb, chunk_size, value, chunk_size);
+ avio_skip(pb, chunk_size - ret);
+
+ av_dict_set(&s->metadata, chunk_key, value, AV_DICT_DONT_STRDUP_VAL);
+ }
+
+ avio_skip(pb, end - avio_tell(pb));
+ } else {
+ av_log(s, AV_LOG_DEBUG, "unknown guid: "FF_PRI_GUID"\n", FF_ARG_GUID(guid));
+ avio_skip(pb, FFALIGN(size, INT64_C(8)) - 24);
+ }
}
- wav->data_end = avio_tell(pb) + size - 24;
- wav->w64 = 1;
+
+ if (!data_ofs)
+ return AVERROR_EOF;
+
+ ff_metadata_conv_ctx(s, NULL, wav_metadata_conv);
+ ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv);
+
+ handle_stream_probing(st);
+ st->need_parsing = AVSTREAM_PARSE_FULL_RAW;
+
+ avio_seek(pb, data_ofs, SEEK_SET);
return 0;
}
diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c
index 25f6ffcde0..f89c91e8c7 100644
--- a/libavformat/wavenc.c
+++ b/libavformat/wavenc.c
@@ -2,30 +2,43 @@
* WAV muxer
* Copyright (c) 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * Sony Wave64 muxer
+ * Copyright (c) 2012 Paul B Mahol
*
- * Libav is free software; you can redistribute it and/or
+ * WAV muxer RF64 support
+ * Copyright (c) 2013 Daniel Verkamp <daniel@drv.nu>
+ *
+ * EBU Tech 3285 - Supplement 3 - Peak Envelope Chunk encoder
+ * Copyright (c) 2014 Georg Lippitsch <georg.lippitsch@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <string.h>
+#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/time.h"
+#include "libavutil/time_internal.h"
#include "avformat.h"
#include "avio.h"
@@ -33,20 +46,53 @@
#include "internal.h"
#include "riff.h"
+#define RF64_AUTO (-1)
+#define RF64_NEVER 0
+#define RF64_ALWAYS 1
+
+#define PEAK_BUFFER_SIZE 1024
+
+typedef enum {
+ PEAK_OFF = 0,
+ PEAK_ON,
+ PEAK_ONLY
+} PeakType;
+
+typedef enum {
+ PEAK_FORMAT_UINT8 = 1,
+ PEAK_FORMAT_UINT16
+} PeakFormat;
+
typedef struct WAVMuxContext {
const AVClass *class;
int64_t data;
int64_t fact_pos;
+ int64_t ds64;
int64_t minpts;
int64_t maxpts;
+ int16_t *peak_maxpos, *peak_maxneg;
+ uint32_t peak_num_frames;
+ uint32_t peak_outbuf_size;
+ uint32_t peak_outbuf_bytes;
+ uint32_t peak_pos_pop;
+ uint16_t peak_pop;
+ uint8_t *peak_output;
int last_duration;
int write_bext;
+ int write_peak;
+ int rf64;
+ int peak_block_size;
+ int peak_format;
+ int peak_block_pos;
+ int peak_ppv;
+ int peak_bps;
} WAVMuxContext;
+#if CONFIG_WAV_MUXER
static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen)
{
AVDictionaryEntry *tag;
- int len = 0;
+ size_t len = 0;
if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
len = strlen(tag->value);
@@ -74,11 +120,11 @@ static void bwf_write_bext_chunk(AVFormatContext *s)
avio_wl64(s->pb, time_reference);
avio_wl16(s->pb, 1); // set version to 1
- if (tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) {
+ if ((tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) && strlen(tmp_tag->value) > 2) {
unsigned char umidpart_str[17] = {0};
- int i;
+ int64_t i;
uint64_t umidpart;
- int len = strlen(tmp_tag->value+2);
+ size_t len = strlen(tmp_tag->value+2);
for (i = 0; i < len/16; i++) {
memcpy(umidpart_str, tmp_tag->value + 2 + (i*16), 16);
@@ -97,25 +143,204 @@ static void bwf_write_bext_chunk(AVFormatContext *s)
ff_end_tag(s->pb, bext);
}
+static av_cold void peak_free_buffers(AVFormatContext *s)
+{
+ WAVMuxContext *wav = s->priv_data;
+
+ av_freep(&wav->peak_maxpos);
+ av_freep(&wav->peak_maxneg);
+ av_freep(&wav->peak_output);
+}
+
+static av_cold int peak_init_writer(AVFormatContext *s)
+{
+ WAVMuxContext *wav = s->priv_data;
+ AVCodecContext *enc = s->streams[0]->codec;
+
+ if (enc->codec_id != AV_CODEC_ID_PCM_S8 &&
+ enc->codec_id != AV_CODEC_ID_PCM_S16LE &&
+ enc->codec_id != AV_CODEC_ID_PCM_U8 &&
+ enc->codec_id != AV_CODEC_ID_PCM_U16LE) {
+ av_log(s, AV_LOG_ERROR, "%s codec not supported for Peak Chunk\n",
+ s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE");
+ return -1;
+ }
+
+ wav->peak_bps = av_get_bits_per_sample(enc->codec_id) / 8;
+
+ if (wav->peak_bps == 1 && wav->peak_format == PEAK_FORMAT_UINT16) {
+ av_log(s, AV_LOG_ERROR,
+ "Writing 16 bit peak for 8 bit audio does not make sense\n");
+ return AVERROR(EINVAL);
+ }
+
+ wav->peak_maxpos = av_mallocz_array(enc->channels, sizeof(*wav->peak_maxpos));
+ wav->peak_maxneg = av_mallocz_array(enc->channels, sizeof(*wav->peak_maxneg));
+ wav->peak_output = av_malloc(PEAK_BUFFER_SIZE);
+ if (!wav->peak_maxpos || !wav->peak_maxneg || !wav->peak_output)
+ goto nomem;
+
+ wav->peak_outbuf_size = PEAK_BUFFER_SIZE;
+
+ return 0;
+
+nomem:
+ av_log(s, AV_LOG_ERROR, "Out of memory\n");
+ peak_free_buffers(s);
+ return AVERROR(ENOMEM);
+}
+
+static void peak_write_frame(AVFormatContext *s)
+{
+ WAVMuxContext *wav = s->priv_data;
+ AVCodecContext *enc = s->streams[0]->codec;
+ int peak_of_peaks;
+ int c;
+
+ if (!wav->peak_output)
+ return;
+
+ for (c = 0; c < enc->channels; c++) {
+ wav->peak_maxneg[c] = -wav->peak_maxneg[c];
+
+ if (wav->peak_bps == 2 && wav->peak_format == PEAK_FORMAT_UINT8) {
+ wav->peak_maxpos[c] = wav->peak_maxpos[c] / 256;
+ wav->peak_maxneg[c] = wav->peak_maxneg[c] / 256;
+ }
+
+ if (wav->peak_ppv == 1)
+ wav->peak_maxpos[c] =
+ FFMAX(wav->peak_maxpos[c], wav->peak_maxneg[c]);
+
+ peak_of_peaks = FFMAX3(wav->peak_maxpos[c], wav->peak_maxneg[c],
+ wav->peak_pop);
+ if (peak_of_peaks > wav->peak_pop)
+ wav->peak_pos_pop = wav->peak_num_frames;
+ wav->peak_pop = peak_of_peaks;
+
+ if (wav->peak_outbuf_size - wav->peak_outbuf_bytes <
+ wav->peak_format * wav->peak_ppv) {
+ wav->peak_outbuf_size += PEAK_BUFFER_SIZE;
+ wav->peak_output = av_realloc(wav->peak_output,
+ wav->peak_outbuf_size);
+ if (!wav->peak_output) {
+ av_log(s, AV_LOG_ERROR, "No memory for peak data\n");
+ return;
+ }
+ }
+
+ if (wav->peak_format == PEAK_FORMAT_UINT8) {
+ wav->peak_output[wav->peak_outbuf_bytes++] =
+ wav->peak_maxpos[c];
+ if (wav->peak_ppv == 2) {
+ wav->peak_output[wav->peak_outbuf_bytes++] =
+ wav->peak_maxneg[c];
+ }
+ } else {
+ AV_WL16(wav->peak_output + wav->peak_outbuf_bytes,
+ wav->peak_maxpos[c]);
+ wav->peak_outbuf_bytes += 2;
+ if (wav->peak_ppv == 2) {
+ AV_WL16(wav->peak_output + wav->peak_outbuf_bytes,
+ wav->peak_maxneg[c]);
+ wav->peak_outbuf_bytes += 2;
+ }
+ }
+ wav->peak_maxpos[c] = 0;
+ wav->peak_maxneg[c] = 0;
+ }
+ wav->peak_num_frames++;
+}
+
+static int peak_write_chunk(AVFormatContext *s)
+{
+ WAVMuxContext *wav = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVCodecContext *enc = s->streams[0]->codec;
+ int64_t peak = ff_start_tag(s->pb, "levl");
+ int64_t now0;
+ time_t now_secs;
+ char timestamp[28];
+
+ /* Peak frame of incomplete block at end */
+ if (wav->peak_block_pos)
+ peak_write_frame(s);
+
+ memset(timestamp, 0, sizeof(timestamp));
+ if (!(s->flags & AVFMT_FLAG_BITEXACT)) {
+ struct tm tmpbuf;
+ av_log(s, AV_LOG_INFO, "Writing local time and date to Peak Envelope Chunk\n");
+ now0 = av_gettime();
+ now_secs = now0 / 1000000;
+ if (strftime(timestamp, sizeof(timestamp), "%Y:%m:%d:%H:%M:%S:", localtime_r(&now_secs, &tmpbuf))) {
+ av_strlcatf(timestamp, sizeof(timestamp), "%03d", (int)((now0 / 1000) % 1000));
+ } else {
+ av_log(s, AV_LOG_ERROR, "Failed to write timestamp\n");
+ return -1;
+ }
+ }
+
+ avio_wl32(pb, 1); /* version */
+ avio_wl32(pb, wav->peak_format); /* 8 or 16 bit */
+ avio_wl32(pb, wav->peak_ppv); /* positive and negative */
+ avio_wl32(pb, wav->peak_block_size); /* frames per value */
+ avio_wl32(pb, enc->channels); /* number of channels */
+ avio_wl32(pb, wav->peak_num_frames); /* number of peak frames */
+ avio_wl32(pb, wav->peak_pos_pop); /* audio sample frame index */
+ avio_wl32(pb, 128); /* equal to size of header */
+ avio_write(pb, timestamp, 28); /* ASCII time stamp */
+ ffio_fill(pb, 0, 60);
+
+ avio_write(pb, wav->peak_output, wav->peak_outbuf_bytes);
+
+ ff_end_tag(pb, peak);
+
+ if (!wav->data)
+ wav->data = peak;
+
+ return 0;
+}
+
static int wav_write_header(AVFormatContext *s)
{
WAVMuxContext *wav = s->priv_data;
AVIOContext *pb = s->pb;
int64_t fmt;
- ffio_wfourcc(pb, "RIFF");
- avio_wl32(pb, 0); /* file length */
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "WAVE files have exactly one stream\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (wav->rf64 == RF64_ALWAYS) {
+ ffio_wfourcc(pb, "RF64");
+ avio_wl32(pb, -1); /* RF64 chunk size: use size in ds64 */
+ } else {
+ ffio_wfourcc(pb, "RIFF");
+ avio_wl32(pb, -1); /* file length */
+ }
+
ffio_wfourcc(pb, "WAVE");
- /* format header */
- fmt = ff_start_tag(pb, "fmt ");
- if (ff_put_wav_header(pb, s->streams[0]->codec) < 0) {
- const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codec->codec_id);
- av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
- desc ? desc->name : "unknown");
- return AVERROR(ENOSYS);
+ if (wav->rf64 != RF64_NEVER) {
+ /* write empty ds64 chunk or JUNK chunk to reserve space for ds64 */
+ ffio_wfourcc(pb, wav->rf64 == RF64_ALWAYS ? "ds64" : "JUNK");
+ avio_wl32(pb, 28); /* chunk size */
+ wav->ds64 = avio_tell(pb);
+ ffio_fill(pb, 0, 28);
+ }
+
+ if (wav->write_peak != 2) {
+ /* format header */
+ fmt = ff_start_tag(pb, "fmt ");
+ if (ff_put_wav_header(pb, s->streams[0]->codec, 0) < 0) {
+ const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codec->codec_id);
+ av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
+ desc ? desc->name : "unknown");
+ return AVERROR(ENOSYS);
+ }
+ ff_end_tag(pb, fmt);
}
- ff_end_tag(pb, fmt);
if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */
&& s->pb->seekable) {
@@ -127,15 +352,23 @@ static int wav_write_header(AVFormatContext *s)
if (wav->write_bext)
bwf_write_bext_chunk(s);
+ if (wav->write_peak) {
+ int ret;
+ if ((ret = peak_init_writer(s)) < 0)
+ return ret;
+ }
+
avpriv_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
wav->maxpts = wav->last_duration = 0;
wav->minpts = INT64_MAX;
- /* info header */
- ff_riff_write_info(s);
+ if (wav->write_peak != 2) {
+ /* info header */
+ ff_riff_write_info(s);
- /* data header */
- wav->data = ff_start_tag(pb, "data");
+ /* data header */
+ wav->data = ff_start_tag(pb, "data");
+ }
avio_flush(pb);
@@ -146,7 +379,31 @@ static int wav_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVIOContext *pb = s->pb;
WAVMuxContext *wav = s->priv_data;
- avio_write(pb, pkt->data, pkt->size);
+
+ if (wav->write_peak != 2)
+ avio_write(pb, pkt->data, pkt->size);
+
+ if (wav->write_peak) {
+ int c = 0;
+ int i;
+ for (i = 0; i < pkt->size; i += wav->peak_bps) {
+ if (wav->peak_bps == 1) {
+ wav->peak_maxpos[c] = FFMAX(wav->peak_maxpos[c], *(int8_t*)(pkt->data + i));
+ wav->peak_maxneg[c] = FFMIN(wav->peak_maxneg[c], *(int8_t*)(pkt->data + i));
+ } else {
+ wav->peak_maxpos[c] = FFMAX(wav->peak_maxpos[c], (int16_t)AV_RL16(pkt->data + i));
+ wav->peak_maxneg[c] = FFMIN(wav->peak_maxneg[c], (int16_t)AV_RL16(pkt->data + i));
+ }
+ if (++c == s->streams[0]->codec->channels) {
+ c = 0;
+ if (++wav->peak_block_pos == wav->peak_block_size) {
+ peak_write_frame(s);
+ wav->peak_block_pos = 0;
+ }
+ }
+ }
+ }
+
if(pkt->pts != AV_NOPTS_VALUE) {
wav->minpts = FFMIN(wav->minpts, pkt->pts);
wav->maxpts = FFMAX(wav->maxpts, pkt->pts);
@@ -160,40 +417,103 @@ static int wav_write_trailer(AVFormatContext *s)
{
AVIOContext *pb = s->pb;
WAVMuxContext *wav = s->priv_data;
- int64_t file_size;
+ int64_t file_size, data_size;
+ int64_t number_of_samples = 0;
+ int rf64 = 0;
+ int ret = 0;
avio_flush(pb);
if (s->pb->seekable) {
- ff_end_tag(pb, wav->data);
+ if (wav->write_peak != 2 && avio_tell(pb) - wav->data < UINT32_MAX) {
+ ff_end_tag(pb, wav->data);
+ avio_flush(pb);
+ }
+
+ if (wav->write_peak && wav->peak_output) {
+ ret = peak_write_chunk(s);
+ avio_flush(pb);
+ }
/* update file size */
file_size = avio_tell(pb);
- avio_seek(pb, 4, SEEK_SET);
- avio_wl32(pb, (uint32_t)(file_size - 8));
- avio_seek(pb, file_size, SEEK_SET);
+ data_size = file_size - wav->data;
+ if (wav->rf64 == RF64_ALWAYS || (wav->rf64 == RF64_AUTO && file_size - 8 > UINT32_MAX)) {
+ rf64 = 1;
+ } else if (file_size - 8 <= UINT32_MAX) {
+ avio_seek(pb, 4, SEEK_SET);
+ avio_wl32(pb, (uint32_t)(file_size - 8));
+ avio_seek(pb, file_size, SEEK_SET);
- avio_flush(pb);
+ avio_flush(pb);
+ } else {
+ av_log(s, AV_LOG_ERROR,
+ "Filesize %"PRId64" invalid for wav, output file will be broken\n",
+ file_size);
+ }
+
+ number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
+ s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
+ s->streams[0]->time_base.den);
if(s->streams[0]->codec->codec_tag != 0x01) {
/* Update num_samps in fact chunk */
- int number_of_samples;
- number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
- s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
- s->streams[0]->time_base.den);
avio_seek(pb, wav->fact_pos, SEEK_SET);
- avio_wl32(pb, number_of_samples);
+ if (rf64 || (wav->rf64 == RF64_AUTO && number_of_samples > UINT32_MAX)) {
+ rf64 = 1;
+ avio_wl32(pb, -1);
+ } else {
+ avio_wl32(pb, number_of_samples);
+ avio_seek(pb, file_size, SEEK_SET);
+ avio_flush(pb);
+ }
+ }
+
+ if (rf64) {
+ /* overwrite RIFF with RF64 */
+ avio_seek(pb, 0, SEEK_SET);
+ ffio_wfourcc(pb, "RF64");
+ avio_wl32(pb, -1);
+
+ /* write ds64 chunk (overwrite JUNK if rf64 == RF64_AUTO) */
+ avio_seek(pb, wav->ds64 - 8, SEEK_SET);
+ ffio_wfourcc(pb, "ds64");
+ avio_wl32(pb, 28); /* ds64 chunk size */
+ avio_wl64(pb, file_size - 8); /* RF64 chunk size */
+ avio_wl64(pb, data_size); /* data chunk size */
+ avio_wl64(pb, number_of_samples); /* fact chunk number of samples */
+ avio_wl32(pb, 0); /* number of table entries for non-'data' chunks */
+
+ /* write -1 in data chunk size */
+ avio_seek(pb, wav->data - 4, SEEK_SET);
+ avio_wl32(pb, -1);
+
avio_seek(pb, file_size, SEEK_SET);
avio_flush(pb);
}
}
- return 0;
+
+ if (wav->write_peak)
+ peak_free_buffers(s);
+
+ return ret;
}
#define OFFSET(x) offsetof(WAVMuxContext, x)
#define ENC AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
{ "write_bext", "Write BEXT chunk.", OFFSET(write_bext), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC },
+ { "write_peak", "Write Peak Envelope chunk.", OFFSET(write_peak), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, ENC, "peak" },
+ { "off", "Do not write peak chunk.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_OFF }, 0, 0, ENC, "peak" },
+ { "on", "Append peak chunk after wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ON }, 0, 0, ENC, "peak" },
+ { "only", "Write only peak chunk, omit wav data.", 0, AV_OPT_TYPE_CONST, { .i64 = PEAK_ONLY }, 0, 0, ENC, "peak" },
+ { "rf64", "Use RF64 header rather than RIFF for large files.", OFFSET(rf64), AV_OPT_TYPE_INT, { .i64 = RF64_NEVER },-1, 1, ENC, "rf64" },
+ { "auto", "Write RF64 header if file grows large enough.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_AUTO }, 0, 0, ENC, "rf64" },
+ { "always", "Always write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_ALWAYS }, 0, 0, ENC, "rf64" },
+ { "never", "Never write RF64 header regardless of file size.", 0, AV_OPT_TYPE_CONST, { .i64 = RF64_NEVER }, 0, 0, ENC, "rf64" },
+ { "peak_block_size", "Number of audio samples used to generate each peak frame.", OFFSET(peak_block_size), AV_OPT_TYPE_INT, { .i64 = 256 }, 0, 65536, ENC },
+ { "peak_format", "The format of the peak envelope data (1: uint8, 2: uint16).", OFFSET(peak_format), AV_OPT_TYPE_INT, { .i64 = PEAK_FORMAT_UINT16 }, PEAK_FORMAT_UINT8, PEAK_FORMAT_UINT16, ENC },
+ { "peak_ppv", "Number of peak points per peak value (1 or 2).", OFFSET(peak_ppv), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, 2, ENC },
{ NULL },
};
@@ -219,3 +539,101 @@ AVOutputFormat ff_wav_muxer = {
.codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
.priv_class = &wav_muxer_class,
};
+#endif /* CONFIG_WAV_MUXER */
+
+#if CONFIG_W64_MUXER
+#include "w64.h"
+
+static void start_guid(AVIOContext *pb, const uint8_t *guid, int64_t *pos)
+{
+ *pos = avio_tell(pb);
+
+ avio_write(pb, guid, 16);
+ avio_wl64(pb, INT64_MAX);
+}
+
+static void end_guid(AVIOContext *pb, int64_t start)
+{
+ int64_t end, pos = avio_tell(pb);
+
+ end = FFALIGN(pos, 8);
+ ffio_fill(pb, 0, end - pos);
+ avio_seek(pb, start + 16, SEEK_SET);
+ avio_wl64(pb, end - start);
+ avio_seek(pb, end, SEEK_SET);
+}
+
+static int w64_write_header(AVFormatContext *s)
+{
+ WAVMuxContext *wav = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t start;
+ int ret;
+
+ avio_write(pb, ff_w64_guid_riff, sizeof(ff_w64_guid_riff));
+ avio_wl64(pb, -1);
+ avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave));
+ start_guid(pb, ff_w64_guid_fmt, &start);
+ if ((ret = ff_put_wav_header(pb, s->streams[0]->codec, 0)) < 0) {
+ av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
+ s->streams[0]->codec->codec ? s->streams[0]->codec->codec->name : "NONE");
+ return ret;
+ }
+ end_guid(pb, start);
+
+ if (s->streams[0]->codec->codec_tag != 0x01 /* hence for all other than PCM */
+ && s->pb->seekable) {
+ start_guid(pb, ff_w64_guid_fact, &wav->fact_pos);
+ avio_wl64(pb, 0);
+ end_guid(pb, wav->fact_pos);
+ }
+
+ start_guid(pb, ff_w64_guid_data, &wav->data);
+
+ return 0;
+}
+
+static int w64_write_trailer(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WAVMuxContext *wav = s->priv_data;
+ int64_t file_size;
+
+ if (pb->seekable) {
+ end_guid(pb, wav->data);
+
+ file_size = avio_tell(pb);
+ avio_seek(pb, 16, SEEK_SET);
+ avio_wl64(pb, file_size);
+
+ if (s->streams[0]->codec->codec_tag != 0x01) {
+ int64_t number_of_samples;
+
+ number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
+ s->streams[0]->codec->sample_rate * (int64_t)s->streams[0]->time_base.num,
+ s->streams[0]->time_base.den);
+ avio_seek(pb, wav->fact_pos + 24, SEEK_SET);
+ avio_wl64(pb, number_of_samples);
+ }
+
+ avio_seek(pb, file_size, SEEK_SET);
+ avio_flush(pb);
+ }
+
+ return 0;
+}
+
+AVOutputFormat ff_w64_muxer = {
+ .name = "w64",
+ .long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"),
+ .extensions = "w64",
+ .priv_data_size = sizeof(WAVMuxContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16LE,
+ .video_codec = AV_CODEC_ID_NONE,
+ .write_header = w64_write_header,
+ .write_packet = wav_write_packet,
+ .write_trailer = w64_write_trailer,
+ .flags = AVFMT_TS_NONSTRICT,
+ .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+};
+#endif /* CONFIG_W64_MUXER */
diff --git a/libavformat/wc3movie.c b/libavformat/wc3movie.c
index c8942537cb..7bd09e3f17 100644
--- a/libavformat/wc3movie.c
+++ b/libavformat/wc3movie.c
@@ -1,21 +1,21 @@
/*
* Wing Commander III Movie (.mve) File Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
* http://www.pcisys.net/~melanson/codecs/
*/
+#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
@@ -158,7 +159,7 @@ static int wc3_read_header(AVFormatContext *s)
fourcc_tag = avio_rl32(pb);
/* chunk sizes are 16-bit aligned */
size = (avio_rb32(pb) + 1) & (~1);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
} while (fourcc_tag != BRCH_TAG);
@@ -210,7 +211,7 @@ static int wc3_read_packet(AVFormatContext *s,
fourcc_tag = avio_rl32(pb);
/* chunk sizes are 16-bit aligned */
size = (avio_rb32(pb) + 1) & (~1);
- if (pb->eof_reached)
+ if (avio_feof(pb))
return AVERROR(EIO);
switch (fourcc_tag) {
@@ -249,10 +250,16 @@ static int wc3_read_packet(AVFormatContext *s,
else {
int i = 0;
av_log (s, AV_LOG_DEBUG, "Subtitle time!\n");
+ if (i >= size || av_strnlen(&text[i + 1], size - i - 1) >= size - i - 1)
+ return AVERROR_INVALIDDATA;
av_log (s, AV_LOG_DEBUG, " inglish: %s\n", &text[i + 1]);
i += text[i] + 1;
+ if (i >= size || av_strnlen(&text[i + 1], size - i - 1) >= size - i - 1)
+ return AVERROR_INVALIDDATA;
av_log (s, AV_LOG_DEBUG, " doytsch: %s\n", &text[i + 1]);
i += text[i] + 1;
+ if (i >= size || av_strnlen(&text[i + 1], size - i - 1) >= size - i - 1)
+ return AVERROR_INVALIDDATA;
av_log (s, AV_LOG_DEBUG, " fronsay: %s\n", &text[i + 1]);
}
#endif
diff --git a/libavformat/webm_chunk.c b/libavformat/webm_chunk.c
new file mode 100644
index 0000000000..c7cc0b8ff3
--- /dev/null
+++ b/libavformat/webm_chunk.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015, Vignesh Venkatasubramanian
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 WebM Chunk Muxer
+ * The chunk muxer enables writing WebM Live chunks where there is a header
+ * chunk, followed by data chunks where each Cluster is written out as a Chunk.
+ */
+
+#include <float.h>
+#include <time.h>
+
+#include "avformat.h"
+#include "avio.h"
+#include "internal.h"
+
+#include "libavutil/avassert.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavutil/avstring.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/time.h"
+#include "libavutil/time_internal.h"
+#include "libavutil/timestamp.h"
+
+#define MAX_FILENAME_SIZE 1024
+
+typedef struct WebMChunkContext {
+ const AVClass *class;
+ int chunk_start_index;
+ char *header_filename;
+ int chunk_duration;
+ int chunk_index;
+ uint64_t duration_written;
+ int prev_pts;
+ AVOutputFormat *oformat;
+ AVFormatContext *avf;
+} WebMChunkContext;
+
+static int chunk_mux_init(AVFormatContext *s)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc;
+ int ret;
+
+ ret = avformat_alloc_output_context2(&wc->avf, wc->oformat, NULL, NULL);
+ if (ret < 0)
+ return ret;
+ oc = wc->avf;
+
+ oc->interrupt_callback = s->interrupt_callback;
+ oc->max_delay = s->max_delay;
+ av_dict_copy(&oc->metadata, s->metadata, 0);
+
+ *(const AVClass**)oc->priv_data = oc->oformat->priv_class;
+ av_opt_set_defaults(oc->priv_data);
+ av_opt_set_int(oc->priv_data, "dash", 1, 0);
+ av_opt_set_int(oc->priv_data, "cluster_time_limit", wc->chunk_duration, 0);
+ av_opt_set_int(oc->priv_data, "live", 1, 0);
+
+ oc->streams = s->streams;
+ oc->nb_streams = s->nb_streams;
+
+ return 0;
+}
+
+static int get_chunk_filename(AVFormatContext *s, int is_header, char *filename)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc = wc->avf;
+ if (!filename) {
+ return AVERROR(EINVAL);
+ }
+ if (is_header) {
+ if (!wc->header_filename) {
+ return AVERROR(EINVAL);
+ }
+ av_strlcpy(filename, wc->header_filename, strlen(wc->header_filename) + 1);
+ } else {
+ if (av_get_frame_filename(filename, MAX_FILENAME_SIZE,
+ s->filename, wc->chunk_index - 1) < 0) {
+ av_log(oc, AV_LOG_ERROR, "Invalid chunk filename template '%s'\n", s->filename);
+ return AVERROR(EINVAL);
+ }
+ }
+ return 0;
+}
+
+static int webm_chunk_write_header(AVFormatContext *s)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc = NULL;
+ int ret;
+
+ // DASH Streams can only have either one track per file.
+ if (s->nb_streams != 1) { return AVERROR_INVALIDDATA; }
+
+ wc->chunk_index = wc->chunk_start_index;
+ wc->oformat = av_guess_format("webm", s->filename, "video/webm");
+ if (!wc->oformat)
+ return AVERROR_MUXER_NOT_FOUND;
+
+ ret = chunk_mux_init(s);
+ if (ret < 0)
+ return ret;
+ oc = wc->avf;
+ ret = get_chunk_filename(s, 1, oc->filename);
+ if (ret < 0)
+ return ret;
+ ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
+ &s->interrupt_callback, NULL);
+ if (ret < 0)
+ return ret;
+
+ oc->pb->seekable = 0;
+ ret = oc->oformat->write_header(oc);
+ if (ret < 0)
+ return ret;
+ avio_close(oc->pb);
+ return 0;
+}
+
+static int chunk_start(AVFormatContext *s)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc = wc->avf;
+ int ret;
+
+ ret = avio_open_dyn_buf(&oc->pb);
+ if (ret < 0)
+ return ret;
+ wc->chunk_index++;
+ return 0;
+}
+
+static int chunk_end(AVFormatContext *s)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc = wc->avf;
+ int ret;
+ int buffer_size;
+ uint8_t *buffer;
+ AVIOContext *pb;
+ char filename[MAX_FILENAME_SIZE];
+
+ if (wc->chunk_start_index == wc->chunk_index)
+ return 0;
+ // Flush the cluster in WebM muxer.
+ oc->oformat->write_packet(oc, NULL);
+ buffer_size = avio_close_dyn_buf(oc->pb, &buffer);
+ ret = get_chunk_filename(s, 0, filename);
+ if (ret < 0)
+ goto fail;
+ ret = avio_open2(&pb, filename, AVIO_FLAG_WRITE, &s->interrupt_callback, NULL);
+ if (ret < 0)
+ goto fail;
+ avio_write(pb, buffer, buffer_size);
+ ret = avio_close(pb);
+ if (ret < 0)
+ goto fail;
+ oc->pb = NULL;
+fail:
+ av_free(buffer);
+ return (ret < 0) ? ret : 0;
+}
+
+static int webm_chunk_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc = wc->avf;
+ AVStream *st = s->streams[pkt->stream_index];
+ int ret;
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ wc->duration_written += av_rescale_q(pkt->pts - wc->prev_pts,
+ st->time_base,
+ (AVRational) {1, 1000});
+ wc->prev_pts = pkt->pts;
+ }
+
+ // For video, a new chunk is started only on key frames. For audio, a new
+ // chunk is started based on chunk_duration.
+ if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
+ (pkt->flags & AV_PKT_FLAG_KEY)) ||
+ (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
+ (pkt->pts == 0 || wc->duration_written >= wc->chunk_duration))) {
+ wc->duration_written = 0;
+ if ((ret = chunk_end(s)) < 0 || (ret = chunk_start(s)) < 0) {
+ goto fail;
+ }
+ }
+
+ ret = oc->oformat->write_packet(oc, pkt);
+ if (ret < 0)
+ goto fail;
+
+fail:
+ if (ret < 0) {
+ oc->streams = NULL;
+ oc->nb_streams = 0;
+ avformat_free_context(oc);
+ }
+
+ return ret;
+}
+
+static int webm_chunk_write_trailer(AVFormatContext *s)
+{
+ WebMChunkContext *wc = s->priv_data;
+ AVFormatContext *oc = wc->avf;
+ oc->oformat->write_trailer(oc);
+ chunk_end(s);
+ oc->streams = NULL;
+ oc->nb_streams = 0;
+ avformat_free_context(oc);
+ return 0;
+}
+
+#define OFFSET(x) offsetof(WebMChunkContext, x)
+static const AVOption options[] = {
+ { "chunk_start_index", "start index of the chunk", OFFSET(chunk_start_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "header", "filename of the header where the initialization data will be written", OFFSET(header_filename), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "audio_chunk_duration", "duration of each chunk in milliseconds", OFFSET(chunk_duration), AV_OPT_TYPE_INT, {.i64 = 5000}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+#if CONFIG_WEBM_CHUNK_MUXER
+static const AVClass webm_chunk_class = {
+ .class_name = "WebM Chunk Muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_webm_chunk_muxer = {
+ .name = "webm_chunk",
+ .long_name = NULL_IF_CONFIG_SMALL("WebM Chunk Muxer"),
+ .mime_type = "video/webm",
+ .extensions = "chk",
+ .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_NEEDNUMBER |
+ AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH,
+ .priv_data_size = sizeof(WebMChunkContext),
+ .write_header = webm_chunk_write_header,
+ .write_packet = webm_chunk_write_packet,
+ .write_trailer = webm_chunk_write_trailer,
+ .priv_class = &webm_chunk_class,
+};
+#endif
diff --git a/libavformat/webmdashenc.c b/libavformat/webmdashenc.c
new file mode 100644
index 0000000000..76ea4237e2
--- /dev/null
+++ b/libavformat/webmdashenc.c
@@ -0,0 +1,550 @@
+/*
+ * WebM DASH Manifest XML muxer
+ * Copyright (c) 2014 Vignesh Venkatasubramanian
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * WebM DASH Specification:
+ * https://sites.google.com/a/webmproject.org/wiki/adaptive-streaming/webm-dash-specification
+ * ISO DASH Specification:
+ * http://standards.iso.org/ittf/PubliclyAvailableStandards/c065274_ISO_IEC_23009-1_2014.zip
+ */
+
+#include <float.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "avformat.h"
+#include "avio_internal.h"
+#include "matroska.h"
+
+#include "libavutil/avstring.h"
+#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "libavutil/time_internal.h"
+
+typedef struct AdaptationSet {
+ char id[10];
+ int *streams;
+ int nb_streams;
+} AdaptationSet;
+
+typedef struct WebMDashMuxContext {
+ const AVClass *class;
+ char *adaptation_sets;
+ AdaptationSet *as;
+ int nb_as;
+ int representation_id;
+ int is_live;
+ int chunk_start_index;
+ int chunk_duration;
+ char *utc_timing_url;
+ double time_shift_buffer_depth;
+ int minimum_update_period;
+ int debug_mode;
+} WebMDashMuxContext;
+
+static const char *get_codec_name(int codec_id)
+{
+ switch (codec_id) {
+ case AV_CODEC_ID_VP8:
+ return "vp8";
+ case AV_CODEC_ID_VP9:
+ return "vp9";
+ case AV_CODEC_ID_VORBIS:
+ return "vorbis";
+ case AV_CODEC_ID_OPUS:
+ return "opus";
+ }
+ return NULL;
+}
+
+static double get_duration(AVFormatContext *s)
+{
+ int i = 0;
+ double max = 0.0;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata,
+ DURATION, NULL, 0);
+ if (!duration || atof(duration->value) < 0) continue;
+ if (atof(duration->value) > max) max = atof(duration->value);
+ }
+ return max / 1000;
+}
+
+static int write_header(AVFormatContext *s)
+{
+ WebMDashMuxContext *w = s->priv_data;
+ double min_buffer_time = 1.0;
+ avio_printf(s->pb, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ avio_printf(s->pb, "<MPD\n");
+ avio_printf(s->pb, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
+ avio_printf(s->pb, " xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
+ avio_printf(s->pb, " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
+ avio_printf(s->pb, " type=\"%s\"\n", w->is_live ? "dynamic" : "static");
+ if (!w->is_live) {
+ avio_printf(s->pb, " mediaPresentationDuration=\"PT%gS\"\n",
+ get_duration(s));
+ }
+ avio_printf(s->pb, " minBufferTime=\"PT%gS\"\n", min_buffer_time);
+ avio_printf(s->pb, " profiles=\"%s\"%s",
+ w->is_live ? "urn:mpeg:dash:profile:isoff-live:2011" : "urn:webm:dash:profile:webm-on-demand:2012",
+ w->is_live ? "\n" : ">\n");
+ if (w->is_live) {
+ time_t local_time = time(NULL);
+ struct tm gmt_buffer;
+ struct tm *gmt = gmtime_r(&local_time, &gmt_buffer);
+ char gmt_iso[21];
+ if (!strftime(gmt_iso, 21, "%Y-%m-%dT%H:%M:%SZ", gmt)) {
+ return AVERROR_UNKNOWN;
+ }
+ if (w->debug_mode) {
+ av_strlcpy(gmt_iso, "", 1);
+ }
+ avio_printf(s->pb, " availabilityStartTime=\"%s\"\n", gmt_iso);
+ avio_printf(s->pb, " timeShiftBufferDepth=\"PT%gS\"\n", w->time_shift_buffer_depth);
+ avio_printf(s->pb, " minimumUpdatePeriod=\"PT%dS\"", w->minimum_update_period);
+ avio_printf(s->pb, ">\n");
+ if (w->utc_timing_url) {
+ avio_printf(s->pb, "<UTCTiming\n");
+ avio_printf(s->pb, " schemeIdUri=\"urn:mpeg:dash:utc:http-iso:2014\"\n");
+ avio_printf(s->pb, " value=\"%s\"/>\n", w->utc_timing_url);
+ }
+ }
+ return 0;
+}
+
+static void write_footer(AVFormatContext *s)
+{
+ avio_printf(s->pb, "</MPD>\n");
+}
+
+static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as) {
+ int i;
+ AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata,
+ CUE_TIMESTAMPS, NULL, 0);
+ if (!gold) return 0;
+ for (i = 1; i < as->nb_streams; i++) {
+ AVDictionaryEntry *ts = av_dict_get(s->streams[as->streams[i]]->metadata,
+ CUE_TIMESTAMPS, NULL, 0);
+ if (!ts || strncmp(gold->value, ts->value, strlen(gold->value))) return 0;
+ }
+ return 1;
+}
+
+static int bitstream_switching(AVFormatContext *s, AdaptationSet *as) {
+ int i;
+ AVDictionaryEntry *gold_track_num = av_dict_get(s->streams[as->streams[0]]->metadata,
+ TRACK_NUMBER, NULL, 0);
+ AVCodecContext *gold_codec = s->streams[as->streams[0]]->codec;
+ if (!gold_track_num) return 0;
+ for (i = 1; i < as->nb_streams; i++) {
+ AVDictionaryEntry *track_num = av_dict_get(s->streams[as->streams[i]]->metadata,
+ TRACK_NUMBER, NULL, 0);
+ AVCodecContext *codec = s->streams[as->streams[i]]->codec;
+ if (!track_num ||
+ strncmp(gold_track_num->value, track_num->value, strlen(gold_track_num->value)) ||
+ gold_codec->codec_id != codec->codec_id ||
+ gold_codec->extradata_size != codec->extradata_size ||
+ memcmp(gold_codec->extradata, codec->extradata, codec->extradata_size)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Writes a Representation within an Adaptation Set. Returns 0 on success and
+ * < 0 on failure.
+ */
+static int write_representation(AVFormatContext *s, AVStream *stream, char *id,
+ int output_width, int output_height,
+ int output_sample_rate) {
+ WebMDashMuxContext *w = s->priv_data;
+ AVDictionaryEntry *irange = av_dict_get(stream->metadata, INITIALIZATION_RANGE, NULL, 0);
+ AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0);
+ AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0);
+ AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0);
+ AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0);
+ if ((w->is_live && (!filename)) ||
+ (!w->is_live && (!irange || !cues_start || !cues_end || !filename || !bandwidth))) {
+ return AVERROR_INVALIDDATA;
+ }
+ avio_printf(s->pb, "<Representation id=\"%s\"", id);
+ // FIXME: For live, This should be obtained from the input file or as an AVOption.
+ avio_printf(s->pb, " bandwidth=\"%s\"",
+ w->is_live ? (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO ? "128000" : "1000000") : bandwidth->value);
+ if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && output_width)
+ avio_printf(s->pb, " width=\"%d\"", stream->codec->width);
+ if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && output_height)
+ avio_printf(s->pb, " height=\"%d\"", stream->codec->height);
+ if (stream->codec->codec_type = AVMEDIA_TYPE_AUDIO && output_sample_rate)
+ avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codec->sample_rate);
+ if (w->is_live) {
+ // For live streams, Codec and Mime Type always go in the Representation tag.
+ avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(stream->codec->codec_id));
+ avio_printf(s->pb, " mimeType=\"%s/webm\"",
+ stream->codec->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
+ // For live streams, subsegments always start with key frames. So this
+ // is always 1.
+ avio_printf(s->pb, " startsWithSAP=\"1\"");
+ avio_printf(s->pb, ">");
+ } else {
+ avio_printf(s->pb, ">\n");
+ avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value);
+ avio_printf(s->pb, "<SegmentBase\n");
+ avio_printf(s->pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value);
+ avio_printf(s->pb, "<Initialization\n");
+ avio_printf(s->pb, " range=\"0-%s\" />\n", irange->value);
+ avio_printf(s->pb, "</SegmentBase>\n");
+ }
+ avio_printf(s->pb, "</Representation>\n");
+ return 0;
+}
+
+/*
+ * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise.
+ */
+static int check_matching_width(AVFormatContext *s, AdaptationSet *as) {
+ int first_width, i;
+ if (as->nb_streams < 2) return 1;
+ first_width = s->streams[as->streams[0]]->codec->width;
+ for (i = 1; i < as->nb_streams; i++)
+ if (first_width != s->streams[as->streams[i]]->codec->width)
+ return 0;
+ return 1;
+}
+
+/*
+ * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise.
+ */
+static int check_matching_height(AVFormatContext *s, AdaptationSet *as) {
+ int first_height, i;
+ if (as->nb_streams < 2) return 1;
+ first_height = s->streams[as->streams[0]]->codec->height;
+ for (i = 1; i < as->nb_streams; i++)
+ if (first_height != s->streams[as->streams[i]]->codec->height)
+ return 0;
+ return 1;
+}
+
+/*
+ * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise.
+ */
+static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as) {
+ int first_sample_rate, i;
+ if (as->nb_streams < 2) return 1;
+ first_sample_rate = s->streams[as->streams[0]]->codec->sample_rate;
+ for (i = 1; i < as->nb_streams; i++)
+ if (first_sample_rate != s->streams[as->streams[i]]->codec->sample_rate)
+ return 0;
+ return 1;
+}
+
+static void free_adaptation_sets(AVFormatContext *s) {
+ WebMDashMuxContext *w = s->priv_data;
+ int i;
+ for (i = 0; i < w->nb_as; i++) {
+ av_freep(&w->as[i].streams);
+ }
+ av_freep(&w->as);
+ w->nb_as = 0;
+}
+
+/*
+ * Parses a live header filename and computes the representation id,
+ * initialization pattern and the media pattern. Pass NULL if you don't want to
+ * compute any of those 3. Returns 0 on success and non-zero on failure.
+ *
+ * Name of the header file should conform to the following pattern:
+ * <file_description>_<representation_id>.hdr where <file_description> can be
+ * anything. The chunks should be named according to the following pattern:
+ * <file_description>_<representation_id>_<chunk_number>.chk
+ */
+static int parse_filename(char *filename, char **representation_id,
+ char **initialization_pattern, char **media_pattern) {
+ char *underscore_pos = NULL;
+ char *period_pos = NULL;
+ char *temp_pos = NULL;
+ char *filename_str = av_strdup(filename);
+ if (!filename_str) return AVERROR(ENOMEM);
+ temp_pos = av_stristr(filename_str, "_");
+ while (temp_pos) {
+ underscore_pos = temp_pos + 1;
+ temp_pos = av_stristr(temp_pos + 1, "_");
+ }
+ if (!underscore_pos) return AVERROR_INVALIDDATA;
+ period_pos = av_stristr(underscore_pos, ".");
+ if (!period_pos) return AVERROR_INVALIDDATA;
+ *(underscore_pos - 1) = 0;
+ if (representation_id) {
+ *representation_id = av_malloc(period_pos - underscore_pos + 1);
+ if (!(*representation_id)) return AVERROR(ENOMEM);
+ av_strlcpy(*representation_id, underscore_pos, period_pos - underscore_pos + 1);
+ }
+ if (initialization_pattern) {
+ *initialization_pattern = av_asprintf("%s_$RepresentationID$.hdr",
+ filename_str);
+ if (!(*initialization_pattern)) return AVERROR(ENOMEM);
+ }
+ if (media_pattern) {
+ *media_pattern = av_asprintf("%s_$RepresentationID$_$Number$.chk",
+ filename_str);
+ if (!(*media_pattern)) return AVERROR(ENOMEM);
+ }
+ av_free(filename_str);
+ return 0;
+}
+
+/*
+ * Writes an Adaptation Set. Returns 0 on success and < 0 on failure.
+ */
+static int write_adaptation_set(AVFormatContext *s, int as_index)
+{
+ WebMDashMuxContext *w = s->priv_data;
+ AdaptationSet *as = &w->as[as_index];
+ AVCodecContext *codec = s->streams[as->streams[0]]->codec;
+ AVDictionaryEntry *lang;
+ int i;
+ static const char boolean[2][6] = { "false", "true" };
+ int subsegmentStartsWithSAP = 1;
+
+ // Width, Height and Sample Rate will go in the AdaptationSet tag if they
+ // are the same for all contained Representations. otherwise, they will go
+ // on their respective Representation tag. For live streams, they always go
+ // in the Representation tag.
+ int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ width_in_as = !w->is_live && check_matching_width(s, as);
+ height_in_as = !w->is_live && check_matching_height(s, as);
+ } else {
+ sample_rate_in_as = !w->is_live && check_matching_sample_rate(s, as);
+ }
+
+ avio_printf(s->pb, "<AdaptationSet id=\"%s\"", as->id);
+ avio_printf(s->pb, " mimeType=\"%s/webm\"",
+ codec->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
+ avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(codec->codec_id));
+
+ lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0);
+ if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value);
+
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as)
+ avio_printf(s->pb, " width=\"%d\"", codec->width);
+ if (codec->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as)
+ avio_printf(s->pb, " height=\"%d\"", codec->height);
+ if (codec->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as)
+ avio_printf(s->pb, " audioSamplingRate=\"%d\"", codec->sample_rate);
+
+ avio_printf(s->pb, " bitstreamSwitching=\"%s\"",
+ boolean[bitstream_switching(s, as)]);
+ avio_printf(s->pb, " subsegmentAlignment=\"%s\"",
+ boolean[w->is_live || subsegment_alignment(s, as)]);
+
+ for (i = 0; i < as->nb_streams; i++) {
+ AVDictionaryEntry *kf = av_dict_get(s->streams[as->streams[i]]->metadata,
+ CLUSTER_KEYFRAME, NULL, 0);
+ if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0;
+ }
+ avio_printf(s->pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
+ avio_printf(s->pb, ">\n");
+
+ if (w->is_live) {
+ AVDictionaryEntry *filename =
+ av_dict_get(s->streams[as->streams[0]]->metadata, FILENAME, NULL, 0);
+ char *initialization_pattern = NULL;
+ char *media_pattern = NULL;
+ int ret = parse_filename(filename->value, NULL, &initialization_pattern,
+ &media_pattern);
+ if (ret) return ret;
+ avio_printf(s->pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n",
+ codec->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
+ avio_printf(s->pb, "<SegmentTemplate");
+ avio_printf(s->pb, " timescale=\"1000\"");
+ avio_printf(s->pb, " duration=\"%d\"", w->chunk_duration);
+ avio_printf(s->pb, " media=\"%s\"", media_pattern);
+ avio_printf(s->pb, " startNumber=\"%d\"", w->chunk_start_index);
+ avio_printf(s->pb, " initialization=\"%s\"", initialization_pattern);
+ avio_printf(s->pb, "/>\n");
+ av_free(initialization_pattern);
+ av_free(media_pattern);
+ }
+
+ for (i = 0; i < as->nb_streams; i++) {
+ char *representation_id = NULL;
+ int ret;
+ if (w->is_live) {
+ AVDictionaryEntry *filename =
+ av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0);
+ if (!filename ||
+ (ret = parse_filename(filename->value, &representation_id, NULL, NULL))) {
+ return ret;
+ }
+ } else {
+ representation_id = av_asprintf("%d", w->representation_id++);
+ if (!representation_id) return AVERROR(ENOMEM);
+ }
+ ret = write_representation(s, s->streams[as->streams[i]],
+ representation_id, !width_in_as,
+ !height_in_as, !sample_rate_in_as);
+ av_free(representation_id);
+ if (ret) return ret;
+ }
+ avio_printf(s->pb, "</AdaptationSet>\n");
+ return 0;
+}
+
+static int to_integer(char *p, int len)
+{
+ int ret;
+ char *q = av_malloc(sizeof(char) * len);
+ if (!q)
+ return AVERROR(ENOMEM);
+ av_strlcpy(q, p, len);
+ ret = atoi(q);
+ av_free(q);
+ return ret;
+}
+
+static int parse_adaptation_sets(AVFormatContext *s)
+{
+ WebMDashMuxContext *w = s->priv_data;
+ char *p = w->adaptation_sets;
+ char *q;
+ enum { new_set, parsed_id, parsing_streams } state;
+ // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
+ state = new_set;
+ while (p < w->adaptation_sets + strlen(w->adaptation_sets)) {
+ if (*p == ' ')
+ continue;
+ else if (state == new_set && !strncmp(p, "id=", 3)) {
+ void *mem = av_realloc(w->as, sizeof(*w->as) * (w->nb_as + 1));
+ if (mem == NULL)
+ return AVERROR(ENOMEM);
+ w->as = mem;
+ ++w->nb_as;
+ w->as[w->nb_as - 1].nb_streams = 0;
+ w->as[w->nb_as - 1].streams = NULL;
+ p += 3; // consume "id="
+ q = w->as[w->nb_as - 1].id;
+ while (*p != ',') *q++ = *p++;
+ *q = 0;
+ p++;
+ state = parsed_id;
+ } else if (state == parsed_id && !strncmp(p, "streams=", 8)) {
+ p += 8; // consume "streams="
+ state = parsing_streams;
+ } else if (state == parsing_streams) {
+ struct AdaptationSet *as = &w->as[w->nb_as - 1];
+ q = p;
+ while (*q != '\0' && *q != ',' && *q != ' ') q++;
+ as->streams = av_realloc(as->streams, sizeof(*as->streams) * ++as->nb_streams);
+ if (as->streams == NULL)
+ return AVERROR(ENOMEM);
+ as->streams[as->nb_streams - 1] = to_integer(p, q - p + 1);
+ if (as->streams[as->nb_streams - 1] < 0) return -1;
+ if (*q == '\0') break;
+ if (*q == ' ') state = new_set;
+ p = ++q;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int webm_dash_manifest_write_header(AVFormatContext *s)
+{
+ int i;
+ double start = 0.0;
+ int ret;
+ WebMDashMuxContext *w = s->priv_data;
+ ret = parse_adaptation_sets(s);
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = write_header(s);
+ if (ret < 0) {
+ goto fail;
+ }
+ avio_printf(s->pb, "<Period id=\"0\"");
+ avio_printf(s->pb, " start=\"PT%gS\"", start);
+ if (!w->is_live) {
+ avio_printf(s->pb, " duration=\"PT%gS\"", get_duration(s));
+ }
+ avio_printf(s->pb, " >\n");
+
+ for (i = 0; i < w->nb_as; i++) {
+ ret = write_adaptation_set(s, i);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ avio_printf(s->pb, "</Period>\n");
+ write_footer(s);
+fail:
+ free_adaptation_sets(s);
+ return ret < 0 ? ret : 0;
+}
+
+static int webm_dash_manifest_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ return AVERROR_EOF;
+}
+
+static int webm_dash_manifest_write_trailer(AVFormatContext *s)
+{
+ free_adaptation_sets(s);
+ return 0;
+}
+
+#define OFFSET(x) offsetof(WebMDashMuxContext, x)
+static const AVOption options[] = {
+ { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "debug_mode", "[private option - users should never set this]. set this to 1 to create deterministic output", OFFSET(debug_mode), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
+ { "live", "set this to 1 to create a live stream manifest", OFFSET(is_live), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
+ { "chunk_start_index", "start index of the chunk", OFFSET(chunk_start_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "chunk_duration_ms", "duration of each chunk (in milliseconds)", OFFSET(chunk_duration), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
+ { "time_shift_buffer_depth", "Smallest time (in seconds) shifting buffer for which any Representation is guaranteed to be available.", OFFSET(time_shift_buffer_depth), AV_OPT_TYPE_DOUBLE, { .dbl = 60.0 }, 1.0, DBL_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { "minimum_update_period", "Minimum Update Period (in seconds) of the manifest.", OFFSET(minimum_update_period), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
+ { NULL },
+};
+
+#if CONFIG_WEBM_DASH_MANIFEST_MUXER
+static const AVClass webm_dash_class = {
+ .class_name = "WebM DASH Manifest muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_webm_dash_manifest_muxer = {
+ .name = "webm_dash_manifest",
+ .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"),
+ .mime_type = "application/xml",
+ .extensions = "xml",
+ .priv_data_size = sizeof(WebMDashMuxContext),
+ .write_header = webm_dash_manifest_write_header,
+ .write_packet = webm_dash_manifest_write_packet,
+ .write_trailer = webm_dash_manifest_write_trailer,
+ .priv_class = &webm_dash_class,
+};
+#endif
diff --git a/libavformat/webpenc.c b/libavformat/webpenc.c
new file mode 100644
index 0000000000..69270c63c4
--- /dev/null
+++ b/libavformat/webpenc.c
@@ -0,0 +1,218 @@
+/*
+ * webp muxer
+ * Copyright (c) 2014 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 "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "avformat.h"
+#include "internal.h"
+
+typedef struct WebpContext{
+ AVClass *class;
+ int frame_count;
+ AVPacket last_pkt;
+ int loop;
+ int wrote_webp_header;
+ int using_webp_anim_encoder;
+} WebpContext;
+
+static int webp_write_header(AVFormatContext *s)
+{
+ AVStream *st;
+
+ if (s->nb_streams != 1) {
+ av_log(s, AV_LOG_ERROR, "Only exactly 1 stream is supported\n");
+ return AVERROR(EINVAL);
+ }
+ st = s->streams[0];
+ if (st->codec->codec_id != AV_CODEC_ID_WEBP) {
+ av_log(s, AV_LOG_ERROR, "Only WebP is supported\n");
+ return AVERROR(EINVAL);
+ }
+ avpriv_set_pts_info(st, 24, 1, 1000);
+
+ return 0;
+}
+
+static int is_animated_webp_packet(AVPacket *pkt)
+{
+ if (pkt->size) {
+ int skip = 0;
+ unsigned flags = 0;
+
+ if (pkt->size < 4)
+ return 0;
+ if (AV_RL32(pkt->data) == AV_RL32("RIFF"))
+ skip = 12;
+
+ if (pkt->size < skip + 4)
+ return 0;
+ if (AV_RL32(pkt->data + skip) == AV_RL32("VP8X")) {
+ flags |= pkt->data[skip + 4 + 4];
+ }
+
+ if (flags & 2) // ANIMATION_FLAG is on
+ return 1;
+ }
+ return 0;
+}
+
+static int flush(AVFormatContext *s, int trailer, int64_t pts)
+{
+ WebpContext *w = s->priv_data;
+ AVStream *st = s->streams[0];
+
+ if (w->last_pkt.size) {
+ int skip = 0;
+ unsigned flags = 0;
+ int vp8x = 0;
+
+ if (w->last_pkt.size < 4)
+ return 0;
+ if (AV_RL32(w->last_pkt.data) == AV_RL32("RIFF"))
+ skip = 12;
+
+ if (w->last_pkt.size < skip + 4)
+ return 0; // Safe to do this as a valid WebP bitstream is >=30 bytes.
+ if (AV_RL32(w->last_pkt.data + skip) == AV_RL32("VP8X")) {
+ flags |= w->last_pkt.data[skip + 4 + 4];
+ vp8x = 1;
+ skip += AV_RL32(w->last_pkt.data + skip + 4) + 8;
+ }
+
+ if (!w->wrote_webp_header) {
+ avio_write(s->pb, "RIFF\0\0\0\0WEBP", 12);
+ w->wrote_webp_header = 1;
+ if (w->frame_count > 1) // first non-empty packet
+ w->frame_count = 1; // so we don't count previous empty packets.
+ }
+
+ if (w->frame_count == 1) {
+ if (!trailer) {
+ vp8x = 1;
+ flags |= 2 + 16;
+ }
+
+ if (vp8x) {
+ avio_write(s->pb, "VP8X", 4);
+ avio_wl32(s->pb, 10);
+ avio_w8(s->pb, flags);
+ avio_wl24(s->pb, 0);
+ avio_wl24(s->pb, st->codec->width - 1);
+ avio_wl24(s->pb, st->codec->height - 1);
+ }
+ if (!trailer) {
+ avio_write(s->pb, "ANIM", 4);
+ avio_wl32(s->pb, 6);
+ avio_wl32(s->pb, 0xFFFFFFFF);
+ avio_wl16(s->pb, w->loop);
+ }
+ }
+
+ if (w->frame_count > trailer) {
+ avio_write(s->pb, "ANMF", 4);
+ avio_wl32(s->pb, 16 + w->last_pkt.size - skip);
+ avio_wl24(s->pb, 0);
+ avio_wl24(s->pb, 0);
+ avio_wl24(s->pb, st->codec->width - 1);
+ avio_wl24(s->pb, st->codec->height - 1);
+ if (w->last_pkt.pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE) {
+ avio_wl24(s->pb, pts - w->last_pkt.pts);
+ } else
+ avio_wl24(s->pb, w->last_pkt.duration);
+ avio_w8(s->pb, 0);
+ }
+ avio_write(s->pb, w->last_pkt.data + skip, w->last_pkt.size - skip);
+ av_free_packet(&w->last_pkt);
+ }
+
+ return 0;
+}
+
+static int webp_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ WebpContext *w = s->priv_data;
+ w->using_webp_anim_encoder |= is_animated_webp_packet(pkt);
+
+ if (w->using_webp_anim_encoder) {
+ avio_write(s->pb, pkt->data, pkt->size);
+ w->wrote_webp_header = 1; // for good measure
+ } else {
+ int ret;
+ if ((ret = flush(s, 0, pkt->pts)) < 0)
+ return ret;
+ av_copy_packet(&w->last_pkt, pkt);
+ }
+ ++w->frame_count;
+
+ return 0;
+}
+
+static int webp_write_trailer(AVFormatContext *s)
+{
+ unsigned filesize;
+ WebpContext *w = s->priv_data;
+
+ if (w->using_webp_anim_encoder) {
+ if ((w->frame_count > 1) && w->loop) { // Write loop count.
+ avio_seek(s->pb, 42, SEEK_SET);
+ avio_wl16(s->pb, w->loop);
+ }
+ } else {
+ int ret;
+ if ((ret = flush(s, 1, AV_NOPTS_VALUE)) < 0)
+ return ret;
+
+ filesize = avio_tell(s->pb);
+ avio_seek(s->pb, 4, SEEK_SET);
+ avio_wl32(s->pb, filesize - 8);
+ // Note: without the following, avio only writes 8 bytes to the file.
+ avio_seek(s->pb, filesize, SEEK_SET);
+ }
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(WebpContext, x)
+#define ENC AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+ { "loop", "Number of times to loop the output: 0 - infinite loop", OFFSET(loop),
+ AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 65535, ENC },
+ { NULL },
+};
+
+static const AVClass webp_muxer_class = {
+ .class_name = "WebP muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .option = options,
+};
+AVOutputFormat ff_webp_muxer = {
+ .name = "webp",
+ .long_name = NULL_IF_CONFIG_SMALL("WebP"),
+ .extensions = "webp",
+ .priv_data_size = sizeof(WebpContext),
+ .video_codec = AV_CODEC_ID_WEBP,
+ .write_header = webp_write_header,
+ .write_packet = webp_write_packet,
+ .write_trailer = webp_write_trailer,
+ .priv_class = &webp_muxer_class,
+ .flags = AVFMT_VARIABLE_FPS,
+};
diff --git a/libavformat/webvttdec.c b/libavformat/webvttdec.c
new file mode 100644
index 0000000000..e457e8f6d2
--- /dev/null
+++ b/libavformat/webvttdec.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2012 ClĂ©ment BÅ“sch
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * WebVTT subtitle demuxer
+ * @see http://dev.w3.org/html5/webvtt/
+ */
+
+#include "avformat.h"
+#include "internal.h"
+#include "subtitles.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+typedef struct {
+ const AVClass *class;
+ FFDemuxSubtitlesQueue q;
+ int kind;
+} WebVTTContext;
+
+static int webvtt_probe(AVProbeData *p)
+{
+ const uint8_t *ptr = p->buf;
+
+ if (AV_RB24(ptr) == 0xEFBBBF)
+ ptr += 3; /* skip UTF-8 BOM */
+ if (!strncmp(ptr, "WEBVTT", 6) &&
+ (!ptr[6] || strchr("\n\r\t ", ptr[6])))
+ return AVPROBE_SCORE_MAX;
+ return 0;
+}
+
+static int64_t read_ts(const char *s)
+{
+ int hh, mm, ss, ms;
+ if (sscanf(s, "%u:%u:%u.%u", &hh, &mm, &ss, &ms) == 4) return (hh*3600LL + mm*60LL + ss) * 1000LL + ms;
+ if (sscanf(s, "%u:%u.%u", &mm, &ss, &ms) == 3) return ( mm*60LL + ss) * 1000LL + ms;
+ return AV_NOPTS_VALUE;
+}
+
+static int webvtt_read_header(AVFormatContext *s)
+{
+ WebVTTContext *webvtt = s->priv_data;
+ AVBPrint header, cue;
+ int res = 0;
+ AVStream *st = avformat_new_stream(s, NULL);
+
+ if (!st)
+ return AVERROR(ENOMEM);
+ avpriv_set_pts_info(st, 64, 1, 1000);
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
+ st->codec->codec_id = AV_CODEC_ID_WEBVTT;
+ st->disposition |= webvtt->kind;
+
+ av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_init(&cue, 0, AV_BPRINT_SIZE_UNLIMITED);
+
+ for (;;) {
+ int i;
+ int64_t pos;
+ AVPacket *sub;
+ const char *p, *identifier, *settings;
+ int identifier_len, settings_len;
+ int64_t ts_start, ts_end;
+
+ ff_subtitles_read_chunk(s->pb, &cue);
+
+ if (!cue.len)
+ break;
+
+ p = identifier = cue.str;
+ pos = avio_tell(s->pb);
+
+ /* ignore header chunk */
+ if (!strncmp(p, "\xEF\xBB\xBFWEBVTT", 9) ||
+ !strncmp(p, "WEBVTT", 6))
+ continue;
+
+ /* optional cue identifier (can be a number like in SRT or some kind of
+ * chaptering id) */
+ for (i = 0; p[i] && p[i] != '\n' && p[i] != '\r'; i++) {
+ if (!strncmp(p + i, "-->", 3)) {
+ identifier = NULL;
+ break;
+ }
+ }
+ if (!identifier)
+ identifier_len = 0;
+ else {
+ identifier_len = strcspn(p, "\r\n");
+ p += identifier_len;
+ if (*p == '\r')
+ p++;
+ if (*p == '\n')
+ p++;
+ }
+
+ /* cue timestamps */
+ if ((ts_start = read_ts(p)) == AV_NOPTS_VALUE)
+ break;
+ if (!(p = strstr(p, "-->")))
+ break;
+ p += 2;
+ do p++; while (*p == ' ' || *p == '\t');
+ if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE)
+ break;
+
+ /* optional cue settings */
+ p += strcspn(p, "\n\t ");
+ while (*p == '\t' || *p == ' ')
+ p++;
+ settings = p;
+ settings_len = strcspn(p, "\r\n");
+ p += settings_len;
+ if (*p == '\r')
+ p++;
+ if (*p == '\n')
+ p++;
+
+ /* create packet */
+ sub = ff_subtitles_queue_insert(&webvtt->q, p, strlen(p), 0);
+ if (!sub) {
+ res = AVERROR(ENOMEM);
+ goto end;
+ }
+ sub->pos = pos;
+ sub->pts = ts_start;
+ sub->duration = ts_end - ts_start;
+
+#define SET_SIDE_DATA(name, type) do { \
+ if (name##_len) { \
+ uint8_t *buf = av_packet_new_side_data(sub, type, name##_len); \
+ if (!buf) { \
+ res = AVERROR(ENOMEM); \
+ goto end; \
+ } \
+ memcpy(buf, name, name##_len); \
+ } \
+} while (0)
+
+ SET_SIDE_DATA(identifier, AV_PKT_DATA_WEBVTT_IDENTIFIER);
+ SET_SIDE_DATA(settings, AV_PKT_DATA_WEBVTT_SETTINGS);
+ }
+
+ ff_subtitles_queue_finalize(&webvtt->q);
+
+end:
+ av_bprint_finalize(&cue, NULL);
+ av_bprint_finalize(&header, NULL);
+ return res;
+}
+
+static int webvtt_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ WebVTTContext *webvtt = s->priv_data;
+ return ff_subtitles_queue_read_packet(&webvtt->q, pkt);
+}
+
+static int webvtt_read_seek(AVFormatContext *s, int stream_index,
+ int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
+{
+ WebVTTContext *webvtt = s->priv_data;
+ return ff_subtitles_queue_seek(&webvtt->q, s, stream_index,
+ min_ts, ts, max_ts, flags);
+}
+
+static int webvtt_read_close(AVFormatContext *s)
+{
+ WebVTTContext *webvtt = s->priv_data;
+ ff_subtitles_queue_clean(&webvtt->q);
+ return 0;
+}
+
+#define OFFSET(x) offsetof(WebVTTContext, x)
+#define KIND_FLAGS AV_OPT_FLAG_SUBTITLE_PARAM
+
+static const AVOption options[] = {
+ { "kind", "Set kind of WebVTT track", OFFSET(kind), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, KIND_FLAGS, "webvtt_kind" },
+ { "subtitles", "WebVTT subtitles kind", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, 0, "webvtt_kind" },
+ { NULL }
+};
+
+static const AVClass webvtt_demuxer_class = {
+ .class_name = "WebVTT demuxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVInputFormat ff_webvtt_demuxer = {
+ .name = "webvtt",
+ .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
+ .priv_data_size = sizeof(WebVTTContext),
+ .read_probe = webvtt_probe,
+ .read_header = webvtt_read_header,
+ .read_packet = webvtt_read_packet,
+ .read_seek2 = webvtt_read_seek,
+ .read_close = webvtt_read_close,
+ .extensions = "vtt",
+ .priv_class = &webvtt_demuxer_class,
+};
diff --git a/libavformat/webvttenc.c b/libavformat/webvttenc.c
new file mode 100644
index 0000000000..b93993d55c
--- /dev/null
+++ b/libavformat/webvttenc.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013 Matthew Heaney
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * WebVTT subtitle muxer
+ * @see http://dev.w3.org/html5/webvtt/
+ */
+
+#include "avformat.h"
+#include "internal.h"
+
+static void webvtt_write_time(AVIOContext *pb, int64_t millisec)
+{
+ int64_t sec, min, hour;
+ sec = millisec / 1000;
+ millisec -= 1000 * sec;
+ min = sec / 60;
+ sec -= 60 * min;
+ hour = min / 60;
+ min -= 60 * hour;
+
+ if (hour > 0)
+ avio_printf(pb, "%"PRId64":", hour);
+
+ avio_printf(pb, "%02"PRId64":%02"PRId64".%03"PRId64"", min, sec, millisec);
+}
+
+static int webvtt_write_header(AVFormatContext *ctx)
+{
+ AVStream *s = ctx->streams[0];
+ AVIOContext *pb = ctx->pb;
+
+ avpriv_set_pts_info(s, 64, 1, 1000);
+
+ avio_printf(pb, "WEBVTT\n");
+ avio_flush(pb);
+
+ return 0;
+}
+
+static int webvtt_write_packet(AVFormatContext *ctx, AVPacket *pkt)
+{
+ AVIOContext *pb = ctx->pb;
+ int id_size, settings_size;
+ uint8_t *id, *settings;
+
+ avio_printf(pb, "\n");
+
+ id = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_IDENTIFIER,
+ &id_size);
+
+ if (id && id_size > 0)
+ avio_printf(pb, "%.*s\n", id_size, id);
+
+ webvtt_write_time(pb, pkt->pts);
+ avio_printf(pb, " --> ");
+ webvtt_write_time(pb, pkt->pts + pkt->duration);
+
+ settings = av_packet_get_side_data(pkt, AV_PKT_DATA_WEBVTT_SETTINGS,
+ &settings_size);
+
+ if (settings && settings_size > 0)
+ avio_printf(pb, " %.*s", settings_size, settings);
+
+ avio_printf(pb, "\n");
+
+ avio_write(pb, pkt->data, pkt->size);
+ avio_printf(pb, "\n");
+
+ return 0;
+}
+
+AVOutputFormat ff_webvtt_muxer = {
+ .name = "webvtt",
+ .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
+ .extensions = "vtt",
+ .mime_type = "text/vtt",
+ .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT,
+ .subtitle_codec = AV_CODEC_ID_WEBVTT,
+ .write_header = webvtt_write_header,
+ .write_packet = webvtt_write_packet,
+};
diff --git a/libavformat/westwood_aud.c b/libavformat/westwood_aud.c
index 611d223238..6d8dbdbd35 100644
--- a/libavformat/westwood_aud.c
+++ b/libavformat/westwood_aud.c
@@ -1,21 +1,21 @@
/*
* Westwood Studios AUD Format Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,8 +69,6 @@ static int wsaud_probe(AVProbeData *p)
if (p->buf[10] & 0xFC)
return 0;
- /* note: only check for WS IMA (type 99) right now since there is no
- * support for type 1 */
if (p->buf[11] != 99 && p->buf[11] != 1)
return 0;
@@ -153,7 +151,7 @@ static int wsaud_read_packet(AVFormatContext *s,
Specifically, this is needed to signal when a packet should be
decoding as raw 8-bit pcm or variable-size ADPCM. */
int out_size = AV_RL16(&preamble[2]);
- if ((ret = av_new_packet(pkt, chunk_size + 4)))
+ if ((ret = av_new_packet(pkt, chunk_size + 4)) < 0)
return ret;
if ((ret = avio_read(pb, &pkt->data[4], chunk_size)) != chunk_size)
return ret < 0 ? ret : AVERROR(EIO);
diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c
index 77da375e70..546164c692 100644
--- a/libavformat/westwood_vqa.c
+++ b/libavformat/westwood_vqa.c
@@ -1,21 +1,21 @@
/*
* Westwood Studios VQA Format Demuxer
- * Copyright (c) 2003 The ffmpeg Project
+ * Copyright (c) 2003 The FFmpeg Project
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -81,10 +81,10 @@ static int wsvqa_read_header(AVFormatContext *s)
WsVqaDemuxContext *wsvqa = s->priv_data;
AVIOContext *pb = s->pb;
AVStream *st;
- unsigned char *header;
- unsigned char scratch[VQA_PREAMBLE_SIZE];
- unsigned int chunk_tag;
- unsigned int chunk_size;
+ uint8_t *header;
+ uint8_t scratch[VQA_PREAMBLE_SIZE];
+ uint32_t chunk_tag;
+ uint32_t chunk_size;
int fps;
/* initialize the video decoder stream */
@@ -101,13 +101,9 @@ static int wsvqa_read_header(AVFormatContext *s)
avio_seek(pb, 20, SEEK_SET);
/* the VQA header needs to go to the decoder */
- st->codec->extradata_size = VQA_HEADER_SIZE;
- st->codec->extradata = av_mallocz(VQA_HEADER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
- header = (unsigned char *)st->codec->extradata;
- if (avio_read(pb, st->codec->extradata, VQA_HEADER_SIZE) !=
- VQA_HEADER_SIZE) {
- return AVERROR(EIO);
- }
+ if (ff_get_extradata(st->codec, pb, VQA_HEADER_SIZE) < 0)
+ return AVERROR(ENOMEM);
+ header = st->codec->extradata;
st->codec->width = AV_RL16(&header[6]);
st->codec->height = AV_RL16(&header[8]);
fps = header[12];
@@ -130,9 +126,8 @@ static int wsvqa_read_header(AVFormatContext *s)
/* there are 0 or more chunks before the FINF chunk; iterate until
* FINF has been skipped and the file will be ready to be demuxed */
do {
- if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE) {
+ if (avio_read(pb, scratch, VQA_PREAMBLE_SIZE) != VQA_PREAMBLE_SIZE)
return AVERROR(EIO);
- }
chunk_tag = AV_RB32(&scratch[0]);
chunk_size = AV_RB32(&scratch[4]);
@@ -167,26 +162,23 @@ static int wsvqa_read_packet(AVFormatContext *s,
WsVqaDemuxContext *wsvqa = s->priv_data;
AVIOContext *pb = s->pb;
int ret = -1;
- unsigned char preamble[VQA_PREAMBLE_SIZE];
- unsigned int chunk_type;
- unsigned int chunk_size;
+ uint8_t preamble[VQA_PREAMBLE_SIZE];
+ uint32_t chunk_type;
+ uint32_t chunk_size;
int skip_byte;
while (avio_read(pb, preamble, VQA_PREAMBLE_SIZE) == VQA_PREAMBLE_SIZE) {
chunk_type = AV_RB32(&preamble[0]);
chunk_size = AV_RB32(&preamble[4]);
+
skip_byte = chunk_size & 0x01;
if ((chunk_type == SND0_TAG) || (chunk_type == SND1_TAG) ||
(chunk_type == SND2_TAG) || (chunk_type == VQFR_TAG)) {
- if (av_new_packet(pkt, chunk_size))
- return AVERROR(EIO);
- ret = avio_read(pb, pkt->data, chunk_size);
- if (ret != chunk_size) {
- av_free_packet(pkt);
+ ret= av_get_packet(pb, pkt, chunk_size);
+ if (ret<0)
return AVERROR(EIO);
- }
switch (chunk_type) {
case SND0_TAG:
@@ -223,9 +215,7 @@ static int wsvqa_read_packet(AVFormatContext *s,
break;
case SND2_TAG:
st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_WS;
- st->codec->extradata_size = 2;
- st->codec->extradata = av_mallocz(2 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 2))
return AVERROR(ENOMEM);
AV_WL16(st->codec->extradata, wsvqa->version);
break;
@@ -236,7 +226,8 @@ static int wsvqa_read_packet(AVFormatContext *s,
switch (chunk_type) {
case SND1_TAG:
/* unpacked size is stored in header */
- pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
+ if(pkt->data)
+ pkt->duration = AV_RL16(pkt->data) / wsvqa->channels;
break;
case SND2_TAG:
/* 2 samples/byte, 1 or 2 samples per frame depending on stereo */
diff --git a/libavformat/wtv.c b/libavformat/wtv.c
deleted file mode 100644
index 7fe737ed53..0000000000
--- a/libavformat/wtv.c
+++ /dev/null
@@ -1,1128 +0,0 @@
-/*
- * Windows Television (WTV) demuxer
- * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
- *
- * This file is part of Libav.
- *
- * Libav is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * Libav is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/**
- * @file
- * Windows Television (WTV) demuxer
- * @author Peter Ross <pross@xvid.org>
- */
-
-#include <inttypes.h>
-
-#include "libavutil/channel_layout.h"
-#include "libavutil/intreadwrite.h"
-#include "libavutil/intfloat.h"
-#include "libavutil/dict.h"
-#include "libavutil/time_internal.h"
-#include "avformat.h"
-#include "internal.h"
-#include "riff.h"
-#include "asf.h"
-#include "mpegts.h"
-
-/* Macros for formating GUIDs */
-#define PRI_PRETTY_GUID \
- "%08"PRIx32"-%04"PRIx16"-%04"PRIx16"-%02x%02x%02x%02x%02x%02x%02x%02x"
-#define ARG_PRETTY_GUID(g) \
- AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15]
-#define LEN_PRETTY_GUID 34
-
-/*
- *
- * File system routines
- *
- */
-
-#define WTV_SECTOR_BITS 12
-#define WTV_SECTOR_SIZE (1 << WTV_SECTOR_BITS)
-#define WTV_BIGSECTOR_BITS 18
-
-#define SHIFT_SECTOR_BITS(a) ((int64_t)(a) << WTV_SECTOR_BITS)
-
-typedef struct WtvFile {
- AVIOContext *pb_filesystem; /** file system (AVFormatContext->pb) */
-
- int sector_bits; /** sector shift bits; used to convert sector number into pb_filesystem offset */
- uint32_t *sectors; /** file allocation table */
- int nb_sectors; /** number of sectors */
-
- int error;
- int64_t position;
- int64_t length;
-} WtvFile;
-
-static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
-{
- return avio_seek(pb, SHIFT_SECTOR_BITS(sector) + offset, SEEK_SET);
-}
-
-/**
- * @return bytes read, 0 on end of file, or <0 on error
- */
-static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
-{
- WtvFile *wf = opaque;
- AVIOContext *pb = wf->pb_filesystem;
- int nread = 0;
-
- if (wf->error || pb->error)
- return -1;
- if (wf->position >= wf->length || pb->eof_reached)
- return 0;
-
- buf_size = FFMIN(buf_size, wf->length - wf->position);
- while(nread < buf_size) {
- int n;
- int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1));
- int read_request = FFMIN(buf_size - nread, remaining_in_sector);
-
- n = avio_read(pb, buf, read_request);
- if (n <= 0)
- break;
- nread += n;
- buf += n;
- wf->position += n;
- if (n == remaining_in_sector) {
- int i = wf->position >> wf->sector_bits;
- if (i >= wf->nb_sectors ||
- (wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) &&
- seek_by_sector(pb, wf->sectors[i], 0) < 0)) {
- wf->error = 1;
- break;
- }
- }
- }
- return nread;
-}
-
-/**
- * @return position (or file length)
- */
-static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence)
-{
- WtvFile *wf = opaque;
- AVIOContext *pb = wf->pb_filesystem;
-
- if (whence == AVSEEK_SIZE)
- return wf->length;
- else if (whence == SEEK_CUR)
- offset = wf->position + offset;
- else if (whence == SEEK_END)
- offset = wf->length;
-
- wf->error = offset < 0 || offset >= wf->length ||
- seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits],
- offset & ((1 << wf->sector_bits) - 1)) < 0;
- wf->position = offset;
- return offset;
-}
-
-/**
- * read non-zero integers (le32) from input stream
- * @param pb
- * @param[out] data destination
- * @param count maximum number of integers to read
- * @return total number of integers read
- */
-static int read_ints(AVIOContext *pb, uint32_t *data, int count)
-{
- int i, total = 0;
- for (i = 0; i < count; i++) {
- if ((data[total] = avio_rl32(pb)))
- total++;
- }
- return total;
-}
-
-/**
- * Open file
- * @param first_sector First sector
- * @param length Length of file (bytes)
- * @param depth File allocation table depth
- * @return NULL on error
- */
-static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s)
-{
- AVIOContext *pb;
- WtvFile *wf;
- uint8_t *buffer;
-
- if (seek_by_sector(s->pb, first_sector, 0) < 0)
- return NULL;
-
- wf = av_mallocz(sizeof(WtvFile));
- if (!wf)
- return NULL;
-
- if (depth == 0) {
- wf->sectors = av_malloc(sizeof(uint32_t));
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->sectors[0] = first_sector;
- wf->nb_sectors = 1;
- wf->sector_bits = WTV_SECTOR_BITS;
- } else if (depth == 1) {
- wf->sectors = av_malloc(WTV_SECTOR_SIZE);
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4);
- wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
- } else if (depth == 2) {
- uint32_t sectors1[WTV_SECTOR_SIZE / 4];
- int nb_sectors1 = read_ints(s->pb, sectors1, WTV_SECTOR_SIZE / 4);
- int i;
-
- wf->sectors = av_malloc(SHIFT_SECTOR_BITS(nb_sectors1));
- if (!wf->sectors) {
- av_free(wf);
- return NULL;
- }
- wf->nb_sectors = 0;
- for (i = 0; i < nb_sectors1; i++) {
- if (seek_by_sector(s->pb, sectors1[i], 0) < 0)
- break;
- wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4);
- }
- wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
- } else {
- av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth);
- av_free(wf);
- return NULL;
- }
-
- if (!wf->nb_sectors) {
- av_free(wf->sectors);
- av_free(wf);
- return NULL;
- }
-
- /* check length */
- length &= 0xFFFFFFFFFFFF;
- if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) {
- av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits);
- length = (int64_t)wf->nb_sectors << wf->sector_bits;
- }
- wf->length = length;
-
- /* seek to initial sector */
- wf->position = 0;
- if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
- av_free(wf->sectors);
- av_free(wf);
- return NULL;
- }
-
- wf->pb_filesystem = s->pb;
- buffer = av_malloc(1 << wf->sector_bits);
- if (!buffer) {
- av_free(wf->sectors);
- av_free(wf);
- return NULL;
- }
-
- pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf,
- wtvfile_read_packet, NULL, wtvfile_seek);
- if (!pb) {
- av_free(buffer);
- av_free(wf->sectors);
- av_free(wf);
- }
- return pb;
-}
-
-static const ff_asf_guid dir_entry_guid =
- {0x92,0xB7,0x74,0x91,0x59,0x70,0x70,0x44,0x88,0xDF,0x06,0x3B,0x82,0xCC,0x21,0x3D};
-
-/**
- * Open file using filename
- * @param[in] buf directory buffer
- * @param buf_size directory buffer size
- * @param[in] filename
- * @param filename_size size of filename
- * @return NULL on error
- */
-static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size)
-{
- const uint8_t *buf_end = buf + buf_size;
-
- while(buf + 48 <= buf_end) {
- int dir_length, name_size, first_sector, depth;
- uint64_t file_length;
- const uint8_t *name;
- if (ff_guidcmp(buf, dir_entry_guid)) {
- av_log(s, AV_LOG_ERROR, "unknown guid "FF_PRI_GUID", expected dir_entry_guid; "
- "remaining directory entries ignored\n", FF_ARG_GUID(buf));
- break;
- }
- dir_length = AV_RL16(buf + 16);
- file_length = AV_RL64(buf + 24);
- name_size = 2 * AV_RL32(buf + 32);
- if (name_size < 0) {
- av_log(s, AV_LOG_ERROR,
- "bad filename length, remaining directory entries ignored\n");
- break;
- }
- if (48 + name_size > buf_end - buf) {
- av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n");
- break;
- }
- first_sector = AV_RL32(buf + 40 + name_size);
- depth = AV_RL32(buf + 44 + name_size);
-
- /* compare file name; test optional null terminator */
- name = buf + 40;
- if (name_size >= filename_size &&
- !memcmp(name, filename, filename_size) &&
- (name_size < filename_size + 2 || !AV_RN16(name + filename_size)))
- return wtvfile_open_sector(first_sector, file_length, depth, s);
-
- buf += dir_length;
- }
- return 0;
-}
-
-#define wtvfile_open(s, buf, buf_size, filename) \
- wtvfile_open2(s, buf, buf_size, filename, sizeof(filename))
-
-/**
- * Close file opened with wtvfile_open_sector(), or wtv_open()
- */
-static void wtvfile_close(AVIOContext *pb)
-{
- WtvFile *wf = pb->opaque;
- av_free(wf->sectors);
- av_free(wf);
- av_free(pb->buffer);
- av_free(pb);
-}
-
-/*
- *
- * Main demuxer
- *
- */
-
-typedef struct WtvStream {
- int seen_data;
-} WtvStream;
-
-typedef struct WtvContext {
- AVIOContext *pb; /** timeline file */
- int64_t epoch;
- int64_t pts; /** pts for next data chunk */
- int64_t last_valid_pts; /** latest valid pts, used for interative seeking */
-
- /* maintain private seek index, as the AVIndexEntry->pos is relative to the
- start of the 'timeline' file, not the file system (AVFormatContext->pb) */
- AVIndexEntry *index_entries;
- int nb_index_entries;
- unsigned int index_entries_allocated_size;
-} WtvContext;
-
-/* WTV GUIDs */
-static const ff_asf_guid wtv_guid =
- {0xB7,0xD8,0x00,0x20,0x37,0x49,0xDA,0x11,0xA6,0x4E,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-static const ff_asf_guid metadata_guid =
- {0x5A,0xFE,0xD7,0x6D,0xC8,0x1D,0x8F,0x4A,0x99,0x22,0xFA,0xB1,0x1C,0x38,0x14,0x53};
-static const ff_asf_guid timestamp_guid =
- {0x5B,0x05,0xE6,0x1B,0x97,0xA9,0x49,0x43,0x88,0x17,0x1A,0x65,0x5A,0x29,0x8A,0x97};
-static const ff_asf_guid data_guid =
- {0x95,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-static const ff_asf_guid stream_guid =
- {0xED,0xA4,0x13,0x23,0x2D,0xBF,0x4F,0x45,0xAD,0x8A,0xD9,0x5B,0xA7,0xF9,0x1F,0xEE};
-static const ff_asf_guid stream2_guid =
- {0xA2,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
-static const ff_asf_guid EVENTID_SubtitleSpanningEvent =
- {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A};
-static const ff_asf_guid EVENTID_LanguageSpanningEvent =
- {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95};
-static const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent =
- {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E};
-static const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent =
- {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24};
-static const ff_asf_guid EVENTID_CSDescriptorSpanningEvent =
- {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66};
-static const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent =
- {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B};
-static const ff_asf_guid EVENTID_StreamIDSpanningEvent =
- {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE};
-static const ff_asf_guid EVENTID_TeletextSpanningEvent =
- {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3};
-static const ff_asf_guid EVENTID_AudioTypeSpanningEvent =
- {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3};
-
-/* Windows media GUIDs */
-
-/* Media types */
-static const ff_asf_guid mediatype_audio =
- {'a','u','d','s',FF_MEDIASUBTYPE_BASE_GUID};
-static const ff_asf_guid mediatype_video =
- {'v','i','d','s',FF_MEDIASUBTYPE_BASE_GUID};
-static const ff_asf_guid mediasubtype_mpeg1payload =
- {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70};
-static const ff_asf_guid mediatype_mpeg2_sections =
- {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5};
-static const ff_asf_guid mediatype_mpeg2_pes =
- {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
-static const ff_asf_guid mediatype_mstvcaption =
- {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1};
-
-/* Media subtypes */
-static const ff_asf_guid mediasubtype_cpfilters_processed =
- {0x28,0xBD,0xAD,0x46,0xD0,0x6F,0x96,0x47,0x93,0xB2,0x15,0x5C,0x51,0xDC,0x04,0x8D};
-static const ff_asf_guid mediasubtype_dvb_subtitle =
- {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F};
-static const ff_asf_guid mediasubtype_teletext =
- {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
-static const ff_asf_guid mediasubtype_dtvccdata =
- {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A};
-static const ff_asf_guid mediasubtype_mpeg2_sections =
- {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61};
-
-/* Formats */
-static const ff_asf_guid format_cpfilters_processed =
- {0x6F,0xB3,0x39,0x67,0x5F,0x1D,0xC2,0x4A,0x81,0x92,0x28,0xBB,0x0E,0x73,0xD1,0x6A};
-static const ff_asf_guid format_waveformatex =
- {0x81,0x9F,0x58,0x05,0x56,0xC3,0xCE,0x11,0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A};
-static const ff_asf_guid format_videoinfo2 =
- {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
-static const ff_asf_guid format_mpeg2_video =
- {0xE3,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
-static const ff_asf_guid format_none =
- {0xD6,0x17,0x64,0x0F,0x18,0xC3,0xD0,0x11,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96};
-
-static const AVCodecGuid video_guids[] = {
- {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}},
- {AV_CODEC_ID_NONE}
-};
-
-static int read_probe(AVProbeData *p)
-{
- return ff_guidcmp(p->buf, wtv_guid) ? 0 : AVPROBE_SCORE_MAX;
-}
-
-/**
- * Convert win32 FILETIME to ISO-8601 string
- */
-static void filetime_to_iso8601(char *buf, int buf_size, int64_t value)
-{
- time_t t = (value / 10000000LL) - 11644473600LL;
- struct tm tmbuf;
- struct tm *tm = gmtime_r(&t, &tmbuf);
- if (tm) {
- if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
- buf[0] = '\0';
- } else
- buf[0] = '\0';
-}
-
-/**
- * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string
- */
-static void crazytime_to_iso8601(char *buf, int buf_size, int64_t value)
-{
- time_t t = (value / 10000000LL) - 719162LL*86400LL;
- struct tm tmbuf;
- struct tm *tm = gmtime_r(&t, &tmbuf);
- if (tm) {
- if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
- buf[0] = '\0';
- } else
- buf[0] = '\0';
-}
-
-/**
- * Convert OLE DATE to ISO-8601 string
- */
-static void oledate_to_iso8601(char *buf, int buf_size, int64_t value)
-{
- time_t t = 631112400LL + 86400*av_int2double(value);
- struct tm tmbuf;
- struct tm *tm = gmtime_r(&t, &tmbuf);
- if (tm) {
- if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
- buf[0] = '\0';
- } else
- buf[0] = '\0';
-}
-
-static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
-{
- char mime[1024];
- char description[1024];
- unsigned int filesize;
- AVStream *st;
- int64_t pos = avio_tell(pb);
-
- avio_get_str16le(pb, INT_MAX, mime, sizeof(mime));
- if (strcmp(mime, "image/jpeg"))
- goto done;
-
- avio_r8(pb);
- avio_get_str16le(pb, INT_MAX, description, sizeof(description));
- filesize = avio_rl32(pb);
- if (!filesize)
- goto done;
-
- st = avformat_new_stream(s, NULL);
- if (!st)
- goto done;
- av_dict_set(&st->metadata, "title", description, 0);
- st->codec->codec_id = AV_CODEC_ID_MJPEG;
- st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT;
- st->codec->extradata = av_mallocz(filesize);
- st->id = -1;
- if (!st->codec->extradata)
- goto done;
- st->codec->extradata_size = filesize;
- avio_read(pb, st->codec->extradata, filesize);
-done:
- avio_seek(pb, pos + length, SEEK_SET);
-}
-
-static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length)
-{
- int buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1;
- char *buf = av_malloc(buf_size);
- if (!buf)
- return;
-
- if (type == 0 && length == 4) {
- snprintf(buf, buf_size, "%u", avio_rl32(pb));
- } else if (type == 1) {
- avio_get_str16le(pb, length, buf, buf_size);
- if (!strlen(buf)) {
- av_free(buf);
- return;
- }
- } else if (type == 3 && length == 4) {
- strcpy(buf, avio_rl32(pb) ? "true" : "false");
- } else if (type == 4 && length == 8) {
- int64_t num = avio_rl64(pb);
- if (!strcmp(key, "WM/EncodingTime") ||
- !strcmp(key, "WM/MediaOriginalBroadcastDateTime"))
- filetime_to_iso8601(buf, buf_size, num);
- else if (!strcmp(key, "WM/WMRVEncodeTime") ||
- !strcmp(key, "WM/WMRVEndTime"))
- crazytime_to_iso8601(buf, buf_size, num);
- else if (!strcmp(key, "WM/WMRVExpirationDate"))
- oledate_to_iso8601(buf, buf_size, num);
- else if (!strcmp(key, "WM/WMRVBitrate"))
- snprintf(buf, buf_size, "%f", av_int2double(num));
- else
- snprintf(buf, buf_size, "%"PRIi64, num);
- } else if (type == 5 && length == 2) {
- snprintf(buf, buf_size, "%u", avio_rl16(pb));
- } else if (type == 6 && length == 16) {
- ff_asf_guid guid;
- avio_read(pb, guid, 16);
- snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid));
- } else if (type == 2 && !strcmp(key, "WM/Picture")) {
- get_attachment(s, pb, length);
- av_freep(&buf);
- return;
- } else {
- av_freep(&buf);
- av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length);
- avio_skip(pb, length);
- return;
- }
-
- av_dict_set(&s->metadata, key, buf, 0);
- av_freep(&buf);
-}
-
-/**
- * Parse metadata entries
- */
-static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
-{
- ff_asf_guid guid;
- int length, type;
- while(!pb->eof_reached) {
- char key[1024];
- ff_get_guid(pb, &guid);
- type = avio_rl32(pb);
- length = avio_rl32(pb);
- if (!length)
- break;
- if (ff_guidcmp(&guid, metadata_guid)) {
- av_log(s, AV_LOG_WARNING, "unknown guid "FF_PRI_GUID", expected metadata_guid; "
- "remaining metadata entries ignored\n", FF_ARG_GUID(guid));
- break;
- }
- avio_get_str16le(pb, INT_MAX, key, sizeof(key));
- get_tag(s, pb, key, type, length);
- }
-
- ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv);
-}
-
-/**
- * parse VIDEOINFOHEADER2 structure
- * @return bytes consumed
- */
-static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
-
- avio_skip(pb, 72); // picture aspect ratio is unreliable
- ff_get_bmp_header(pb, st);
-
- return 72 + 40;
-}
-
-/**
- * Parse MPEG1WAVEFORMATEX extradata structure
- */
-static void parse_mpeg1waveformatex(AVStream *st)
-{
- /* fwHeadLayer */
- switch (AV_RL16(st->codec->extradata)) {
- case 0x0001 : st->codec->codec_id = AV_CODEC_ID_MP1; break;
- case 0x0002 : st->codec->codec_id = AV_CODEC_ID_MP2; break;
- case 0x0004 : st->codec->codec_id = AV_CODEC_ID_MP3; break;
- }
-
- st->codec->bit_rate = AV_RL32(st->codec->extradata + 2); /* dwHeadBitrate */
-
- /* dwHeadMode */
- switch (AV_RL16(st->codec->extradata + 6)) {
- case 1 :
- case 2 :
- case 4 : st->codec->channels = 2;
- st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
- break;
- case 8 : st->codec->channels = 1;
- st->codec->channel_layout = AV_CH_LAYOUT_MONO;
- break;
- }
-}
-
-/**
- * Initialise stream
- * @param st Stream to initialise, or NULL to create and initialise new stream
- * @return NULL on error
- */
-static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type)
-{
- if (st) {
- if (st->codec->extradata) {
- av_freep(&st->codec->extradata);
- st->codec->extradata_size = 0;
- }
- } else {
- WtvStream *wst = av_mallocz(sizeof(WtvStream));
- if (!wst)
- return NULL;
- st = avformat_new_stream(s, NULL);
- if (!st) {
- av_free(wst);
- return NULL;
- }
- st->id = sid;
- st->priv_data = wst;
- }
- st->codec->codec_type = codec_type;
- st->need_parsing = AVSTREAM_PARSE_FULL;
- avpriv_set_pts_info(st, 64, 1, 10000000);
- return st;
-}
-
-/**
- * parse Media Type structure and populate stream
- * @param st Stream, or NULL to create new stream
- * @param mediatype Mediatype GUID
- * @param subtype Subtype GUID
- * @param formattype Format GUID
- * @param size Size of format buffer
- * @return NULL on error
- */
-static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
- ff_asf_guid mediatype, ff_asf_guid subtype,
- ff_asf_guid formattype, int size)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- if (!ff_guidcmp(subtype, mediasubtype_cpfilters_processed) &&
- !ff_guidcmp(formattype, format_cpfilters_processed)) {
- ff_asf_guid actual_subtype;
- ff_asf_guid actual_formattype;
-
- if (size < 32) {
- av_log(s, AV_LOG_WARNING, "format buffer size underflow\n");
- avio_skip(pb, size);
- return NULL;
- }
-
- avio_skip(pb, size - 32);
- ff_get_guid(pb, &actual_subtype);
- ff_get_guid(pb, &actual_formattype);
- avio_seek(pb, -size, SEEK_CUR);
-
- st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32);
- avio_skip(pb, 32);
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_audio)) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO);
- if (!st)
- return NULL;
- if (!ff_guidcmp(formattype, format_waveformatex)) {
- int ret = ff_get_wav_header(pb, st->codec, size);
- if (ret < 0)
- return NULL;
- } else {
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- }
-
- if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
- st->codec->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codec->bits_per_coded_sample);
- } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) {
- if (st->codec->extradata && st->codec->extradata_size >= 22)
- parse_mpeg1waveformatex(st);
- else
- av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n");
- } else {
- st->codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subtype);
- if (st->codec->codec_id == AV_CODEC_ID_NONE)
- av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
- }
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_video)) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO);
- if (!st)
- return NULL;
- if (!ff_guidcmp(formattype, format_videoinfo2)) {
- int consumed = parse_videoinfoheader2(s, st);
- avio_skip(pb, FFMAX(size - consumed, 0));
- } else if (!ff_guidcmp(formattype, format_mpeg2_video)) {
- int consumed = parse_videoinfoheader2(s, st);
- avio_skip(pb, FFMAX(size - consumed, 0));
- } else {
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- }
-
- if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
- st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype));
- } else {
- st->codec->codec_id = ff_codec_guid_get_id(video_guids, subtype);
- }
- if (st->codec->codec_id == AV_CODEC_ID_NONE)
- av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) &&
- !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
- if (!st)
- return NULL;
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- st->codec->codec_id = AV_CODEC_ID_DVB_SUBTITLE;
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) &&
- (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) {
- st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
- if (!st)
- return NULL;
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- st->codec->codec_id = AV_CODEC_ID_DVB_TELETEXT;
- return st;
- } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) &&
- !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) {
- if (ff_guidcmp(formattype, format_none))
- av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- return NULL;
- }
-
- av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"FF_PRI_GUID
- ", subtype:"FF_PRI_GUID", formattype:"FF_PRI_GUID"\n",
- FF_ARG_GUID(mediatype), FF_ARG_GUID(subtype), FF_ARG_GUID(formattype));
- avio_skip(pb, size);
- return NULL;
-}
-
-enum {
- SEEK_TO_DATA = 0,
- SEEK_TO_PTS,
-};
-
-/**
- * Parse WTV chunks
- * @param mode SEEK_TO_DATA or SEEK_TO_PTS
- * @param seekts timestamp
- * @param[out] len_ptr Length of data chunk
- * @return stream index of data chunk, or <0 on error
- */
-static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- while (!pb->eof_reached) {
- ff_asf_guid g;
- int len, sid, consumed;
-
- ff_get_guid(pb, &g);
- len = avio_rl32(pb);
- if (len < 32)
- break;
- sid = avio_rl32(pb) & 0x7FFF;
- avio_skip(pb, 8);
- consumed = 32;
-
- if (!ff_guidcmp(g, stream_guid)) {
- if (ff_find_stream_index(s, sid) < 0) {
- ff_asf_guid mediatype, subtype, formattype;
- int size;
- avio_skip(pb, 28);
- ff_get_guid(pb, &mediatype);
- ff_get_guid(pb, &subtype);
- avio_skip(pb, 12);
- ff_get_guid(pb, &formattype);
- size = avio_rl32(pb);
- parse_media_type(s, 0, sid, mediatype, subtype, formattype, size);
- consumed += 92 + size;
- }
- } else if (!ff_guidcmp(g, stream2_guid)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0 && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) {
- ff_asf_guid mediatype, subtype, formattype;
- int size;
- avio_skip(pb, 12);
- ff_get_guid(pb, &mediatype);
- ff_get_guid(pb, &subtype);
- avio_skip(pb, 12);
- ff_get_guid(pb, &formattype);
- size = avio_rl32(pb);
- parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size);
- consumed += 76 + size;
- }
- } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- AVStream *st = s->streams[stream_index];
- uint8_t buf[258];
- const uint8_t *pbuf = buf;
- int buf_size;
-
- avio_skip(pb, 8);
- consumed += 8;
- if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
- !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) {
- avio_skip(pb, 6);
- consumed += 6;
- }
-
- buf_size = FFMIN(len - consumed, sizeof(buf));
- avio_read(pb, buf, buf_size);
- consumed += buf_size;
- ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL);
- }
- } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- AVStream *st = s->streams[stream_index];
- int audio_type;
- avio_skip(pb, 8);
- audio_type = avio_r8(pb);
- if (audio_type == 2)
- st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
- else if (audio_type == 3)
- st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
- consumed += 9;
- }
- } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- avio_skip(pb, 12);
- if (avio_rl32(pb))
- av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index);
- consumed += 16;
- }
- } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- AVStream *st = s->streams[stream_index];
- uint8_t language[4];
- avio_skip(pb, 12);
- avio_read(pb, language, 3);
- if (language[0]) {
- language[3] = 0;
- av_dict_set(&st->metadata, "language", language, 0);
- if (!strcmp(language, "nar") || !strcmp(language, "NAR"))
- st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
- }
- consumed += 15;
- }
- } else if (!ff_guidcmp(g, timestamp_guid)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (stream_index >= 0) {
- avio_skip(pb, 8);
- wtv->pts = avio_rl64(pb);
- consumed += 16;
- if (wtv->pts == -1)
- wtv->pts = AV_NOPTS_VALUE;
- else {
- wtv->last_valid_pts = wtv->pts;
- if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch)
- wtv->epoch = wtv->pts;
- if (mode == SEEK_TO_PTS && wtv->pts >= seekts) {
-#define WTV_PAD8(x) (((x) + 7) & ~7)
- avio_skip(pb, WTV_PAD8(len) - consumed);
- return 0;
- }
- }
- }
- } else if (!ff_guidcmp(g, data_guid)) {
- int stream_index = ff_find_stream_index(s, sid);
- if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32) {
- WtvStream *wst = s->streams[stream_index]->priv_data;
- wst->seen_data = 1;
- if (len_ptr) {
- *len_ptr = len;
- }
- return stream_index;
- }
- } else if (
- !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) ||
- !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) ||
- !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ (const ff_asf_guid){0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A}) ||
- !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) ||
- !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) ||
- !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) ||
- !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) ||
- !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) ||
- !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) ||
- !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
- !ff_guidcmp(g, (const ff_asf_guid){0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D})) {
- //ignore known guids
- } else
- av_log(s, AV_LOG_WARNING, "unsupported chunk:"FF_PRI_GUID"\n", FF_ARG_GUID(g));
-
- avio_skip(pb, WTV_PAD8(len) - consumed);
- }
- return AVERROR_EOF;
-}
-
-/* declare utf16le strings */
-#define _ , 0,
-static const uint8_t timeline_le16[] =
- {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0};
-static const uint8_t table_0_entries_legacy_attrib_le16[] =
- {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
-static const uint8_t table_0_entries_time_le16[] =
- {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'t'_'i'_'m'_'e', 0};
-static const uint8_t timeline_table_0_entries_Events_le16[] =
- {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
-#undef _
-
-static int read_header(AVFormatContext *s)
-{
- WtvContext *wtv = s->priv_data;
- int root_sector, root_size;
- uint8_t root[WTV_SECTOR_SIZE];
- AVIOContext *pb;
- int64_t timeline_pos;
- int ret;
-
- wtv->epoch =
- wtv->pts =
- wtv->last_valid_pts = AV_NOPTS_VALUE;
-
- /* read root directory sector */
- avio_skip(s->pb, 0x30);
- root_size = avio_rl32(s->pb);
- if (root_size > sizeof(root)) {
- av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n");
- return AVERROR_INVALIDDATA;
- }
- avio_skip(s->pb, 4);
- root_sector = avio_rl32(s->pb);
-
- ret = seek_by_sector(s->pb, root_sector, 0);
- if (ret < 0)
- return ret;
- root_size = avio_read(s->pb, root, root_size);
- if (root_size < 0)
- return AVERROR_INVALIDDATA;
-
- /* parse chunks up until first data chunk */
- wtv->pb = wtvfile_open(s, root, root_size, timeline_le16);
- if (!wtv->pb) {
- av_log(s, AV_LOG_ERROR, "timeline data missing\n");
- return AVERROR_INVALIDDATA;
- }
-
- ret = parse_chunks(s, SEEK_TO_DATA, 0, 0);
- if (ret < 0)
- return ret;
- avio_seek(wtv->pb, -32, SEEK_CUR);
-
- timeline_pos = avio_tell(s->pb); // save before opening another file
-
- /* read metadata */
- pb = wtvfile_open(s, root, root_size, table_0_entries_legacy_attrib_le16);
- if (pb) {
- parse_legacy_attrib(s, pb);
- wtvfile_close(pb);
- }
-
- /* read seek index */
- if (s->nb_streams) {
- AVStream *st = s->streams[0];
- pb = wtvfile_open(s, root, root_size, table_0_entries_time_le16);
- if (pb) {
- while(1) {
- uint64_t timestamp = avio_rl64(pb);
- uint64_t frame_nb = avio_rl64(pb);
- if (pb->eof_reached)
- break;
- ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size,
- 0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME);
- }
- wtvfile_close(pb);
-
- if (wtv->nb_index_entries) {
- pb = wtvfile_open(s, root, root_size, timeline_table_0_entries_Events_le16);
- if (pb) {
- int i;
- while (1) {
- uint64_t frame_nb = avio_rl64(pb);
- uint64_t position = avio_rl64(pb);
- if (pb->eof_reached)
- break;
- for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
- AVIndexEntry *e = wtv->index_entries + i;
- if (frame_nb > e->size)
- break;
- if (position > e->pos)
- e->pos = position;
- }
- }
- wtvfile_close(pb);
- st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
- }
- }
- }
- }
-
- avio_seek(s->pb, timeline_pos, SEEK_SET);
- return 0;
-}
-
-static int read_packet(AVFormatContext *s, AVPacket *pkt)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- int stream_index, len, ret;
-
- stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
- if (stream_index < 0)
- return stream_index;
-
- ret = av_get_packet(pb, pkt, len - 32);
- if (ret < 0)
- return ret;
- pkt->stream_index = stream_index;
- pkt->pts = wtv->pts;
- avio_skip(pb, WTV_PAD8(len) - len);
- return 0;
-}
-
-static int read_seek(AVFormatContext *s, int stream_index,
- int64_t ts, int flags)
-{
- WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
- AVStream *st = s->streams[0];
- int64_t ts_relative;
- int i;
-
- if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
- return AVERROR(ENOSYS);
-
- /* timestamp adjustment is required because wtv->pts values are absolute,
- * whereas AVIndexEntry->timestamp values are relative to epoch. */
- ts_relative = ts;
- if (wtv->epoch != AV_NOPTS_VALUE)
- ts_relative -= wtv->epoch;
-
- i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags);
- if (i < 0) {
- if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts)
- avio_seek(pb, 0, SEEK_SET);
- else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries)
- avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET);
- if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0)
- return AVERROR(ERANGE);
- return 0;
- }
- wtv->pts = wtv->index_entries[i].timestamp;
- if (wtv->epoch != AV_NOPTS_VALUE)
- wtv->pts += wtv->epoch;
- wtv->last_valid_pts = wtv->pts;
- avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET);
- return 0;
-}
-
-static int read_close(AVFormatContext *s)
-{
- WtvContext *wtv = s->priv_data;
- av_free(wtv->index_entries);
- wtvfile_close(wtv->pb);
- return 0;
-}
-
-AVInputFormat ff_wtv_demuxer = {
- .name = "wtv",
- .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
- .priv_data_size = sizeof(WtvContext),
- .read_probe = read_probe,
- .read_header = read_header,
- .read_packet = read_packet,
- .read_seek = read_seek,
- .read_close = read_close,
- .flags = AVFMT_SHOW_IDS,
-};
diff --git a/libavformat/wtv.h b/libavformat/wtv.h
new file mode 100644
index 0000000000..f26ad5efb9
--- /dev/null
+++ b/libavformat/wtv.h
@@ -0,0 +1,60 @@
+/*
+ * Windows Television (WTV)
+ * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_WTV_H
+#define AVFORMAT_WTV_H
+
+#include "riff.h"
+#include "asf.h"
+
+#define WTV_SECTOR_BITS 12
+#define WTV_SECTOR_SIZE (1 << WTV_SECTOR_BITS)
+#define WTV_BIGSECTOR_BITS 18
+#define WTV_PAD8(x) (((x) + 7) & ~7)
+
+extern const uint8_t ff_timeline_le16[16];
+extern const uint8_t ff_timeline_table_0_entries_Events_le16[62];
+extern const uint8_t ff_table_0_entries_legacy_attrib_le16[58];
+extern const uint8_t ff_table_0_entries_time_le16[40];
+
+extern const ff_asf_guid ff_dir_entry_guid;
+extern const ff_asf_guid ff_wtv_guid;
+extern const ff_asf_guid ff_timestamp_guid;
+extern const ff_asf_guid ff_data_guid;
+extern const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT;
+extern const ff_asf_guid ff_stream1_guid;
+extern const ff_asf_guid ff_sync_guid;
+extern const ff_asf_guid ff_index_guid;
+extern const ff_asf_guid ff_mediatype_audio;
+extern const ff_asf_guid ff_mediatype_video;
+extern const ff_asf_guid ff_format_none;
+extern const AVCodecGuid ff_video_guids[];
+
+extern const ff_asf_guid ff_DSATTRIB_TRANSPORT_PROPERTIES;
+extern const ff_asf_guid ff_metadata_guid;
+extern const ff_asf_guid ff_stream2_guid;
+extern const ff_asf_guid ff_mediasubtype_cpfilters_processed;
+extern const ff_asf_guid ff_format_cpfilters_processed;
+extern const ff_asf_guid ff_format_waveformatex;
+extern const ff_asf_guid ff_format_mpeg2_video;
+extern const ff_asf_guid ff_format_videoinfo2;
+
+#endif /* AVFORMAT_WTV_H */
diff --git a/libavformat/wtv_common.c b/libavformat/wtv_common.c
new file mode 100644
index 0000000000..ce4349dce5
--- /dev/null
+++ b/libavformat/wtv_common.c
@@ -0,0 +1,84 @@
+/*
+ * Windows Television (WTV)
+ * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "wtv.h"
+
+/* WTV GUIDs*/
+const ff_asf_guid ff_dir_entry_guid =
+ {0x92,0xB7,0x74,0x91,0x59,0x70,0x70,0x44,0x88,0xDF,0x06,0x3B,0x82,0xCC,0x21,0x3D};
+const ff_asf_guid ff_wtv_guid =
+ {0xB7,0xD8,0x00,0x20,0x37,0x49,0xDA,0x11,0xA6,0x4E,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+const ff_asf_guid ff_timestamp_guid =
+ {0x5B,0x05,0xE6,0x1B,0x97,0xA9,0x49,0x43,0x88,0x17,0x1A,0x65,0x5A,0x29,0x8A,0x97};
+const ff_asf_guid ff_data_guid =
+ {0x95,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+const ff_asf_guid ff_SBE2_STREAM_DESC_EVENT =
+ {0xED,0xA4,0x13,0x23,0x2D,0xBF,0x4F,0x45,0xAD,0x8A,0xD9,0x5B,0xA7,0xF9,0x1F,0xEE};
+const ff_asf_guid ff_stream1_guid =
+ {0xA1,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+const ff_asf_guid ff_sync_guid =
+ {0x97,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+const ff_asf_guid ff_index_guid =
+ {0x96,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+const ff_asf_guid ff_mediatype_audio =
+ {'a','u','d','s',FF_MEDIASUBTYPE_BASE_GUID};
+const ff_asf_guid ff_mediatype_video =
+ {'v','i','d','s',FF_MEDIASUBTYPE_BASE_GUID};
+const ff_asf_guid ff_format_none =
+ {0xD6,0x17,0x64,0x0F,0x18,0xC3,0xD0,0x11,0xA4,0x3F,0x00,0xA0,0xC9,0x22,0x31,0x96};
+
+/* declare utf16le strings */
+#define _ , 0,
+const uint8_t ff_timeline_le16[] =
+ {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e', 0};
+const uint8_t ff_timeline_table_0_entries_Events_le16[] =
+ {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
+const uint8_t ff_table_0_entries_legacy_attrib_le16[] =
+ {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
+const uint8_t ff_table_0_entries_time_le16[] =
+ {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'e'_'n'_'t'_'r'_'i'_'e'_'s'_'.'_'t'_'i'_'m'_'e', 0};
+#undef _
+
+const ff_asf_guid ff_DSATTRIB_TRANSPORT_PROPERTIES =
+ {0x12,0xF6,0x22,0xB6,0xAD,0x47,0x71,0x46,0xAD,0x6C,0x05,0xA9,0x8E,0x65,0xDE,0x3A};
+const ff_asf_guid ff_metadata_guid =
+ {0x5A,0xFE,0xD7,0x6D,0xC8,0x1D,0x8F,0x4A,0x99,0x22,0xFA,0xB1,0x1C,0x38,0x14,0x53};
+const ff_asf_guid ff_stream2_guid =
+ {0xA2,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+
+/* Media subtypes */
+const ff_asf_guid ff_mediasubtype_cpfilters_processed =
+ {0x28,0xBD,0xAD,0x46,0xD0,0x6F,0x96,0x47,0x93,0xB2,0x15,0x5C,0x51,0xDC,0x04,0x8D};
+
+/* Formats */
+const ff_asf_guid ff_format_cpfilters_processed =
+ {0x6F,0xB3,0x39,0x67,0x5F,0x1D,0xC2,0x4A,0x81,0x92,0x28,0xBB,0x0E,0x73,0xD1,0x6A};
+const ff_asf_guid ff_format_waveformatex =
+ {0x81,0x9F,0x58,0x05,0x56,0xC3,0xCE,0x11,0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A};
+const ff_asf_guid ff_format_mpeg2_video =
+ {0xE3,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
+const ff_asf_guid ff_format_videoinfo2 =
+ {0xA0,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
+
+const AVCodecGuid ff_video_guids[] = {
+ {AV_CODEC_ID_MPEG2VIDEO, {0x26,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA}},
+ {AV_CODEC_ID_NONE}
+};
diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c
new file mode 100644
index 0000000000..e226690283
--- /dev/null
+++ b/libavformat/wtvdec.c
@@ -0,0 +1,1132 @@
+/*
+ * Windows Television (WTV) demuxer
+ * Copyright (c) 2010-2011 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Windows Television (WTV) demuxer
+ * @author Peter Ross <pross@xvid.org>
+ */
+
+#include <inttypes.h>
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/intfloat.h"
+#include "libavutil/time_internal.h"
+#include "avformat.h"
+#include "internal.h"
+#include "wtv.h"
+#include "mpegts.h"
+
+/* Macros for formating GUIDs */
+#define PRI_PRETTY_GUID \
+ "%08"PRIx32"-%04"PRIx16"-%04"PRIx16"-%02x%02x%02x%02x%02x%02x%02x%02x"
+#define ARG_PRETTY_GUID(g) \
+ AV_RL32(g),AV_RL16(g+4),AV_RL16(g+6),g[8],g[9],g[10],g[11],g[12],g[13],g[14],g[15]
+#define LEN_PRETTY_GUID 34
+
+/*
+ *
+ * File system routines
+ *
+ */
+
+typedef struct WtvFile {
+ AVIOContext *pb_filesystem; /**< file system (AVFormatContext->pb) */
+
+ int sector_bits; /**< sector shift bits; used to convert sector number into pb_filesystem offset */
+ uint32_t *sectors; /**< file allocation table */
+ int nb_sectors; /**< number of sectors */
+
+ int error;
+ int64_t position;
+ int64_t length;
+} WtvFile;
+
+static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
+{
+ return avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET);
+}
+
+/**
+ * @return bytes read, 0 on end of file, or <0 on error
+ */
+static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size)
+{
+ WtvFile *wf = opaque;
+ AVIOContext *pb = wf->pb_filesystem;
+ int nread = 0;
+
+ if (wf->error || pb->error)
+ return -1;
+ if (wf->position >= wf->length || avio_feof(pb))
+ return 0;
+
+ buf_size = FFMIN(buf_size, wf->length - wf->position);
+ while(nread < buf_size) {
+ int n;
+ int remaining_in_sector = (1 << wf->sector_bits) - (wf->position & ((1 << wf->sector_bits) - 1));
+ int read_request = FFMIN(buf_size - nread, remaining_in_sector);
+
+ n = avio_read(pb, buf, read_request);
+ if (n <= 0)
+ break;
+ nread += n;
+ buf += n;
+ wf->position += n;
+ if (n == remaining_in_sector) {
+ int i = wf->position >> wf->sector_bits;
+ if (i >= wf->nb_sectors ||
+ (wf->sectors[i] != wf->sectors[i - 1] + (1 << (wf->sector_bits - WTV_SECTOR_BITS)) &&
+ seek_by_sector(pb, wf->sectors[i], 0) < 0)) {
+ wf->error = 1;
+ break;
+ }
+ }
+ }
+ return nread;
+}
+
+/**
+ * @return position (or file length)
+ */
+static int64_t wtvfile_seek(void *opaque, int64_t offset, int whence)
+{
+ WtvFile *wf = opaque;
+ AVIOContext *pb = wf->pb_filesystem;
+
+ if (whence == AVSEEK_SIZE)
+ return wf->length;
+ else if (whence == SEEK_CUR)
+ offset = wf->position + offset;
+ else if (whence == SEEK_END)
+ offset = wf->length;
+
+ wf->error = offset < 0 || offset >= wf->length ||
+ seek_by_sector(pb, wf->sectors[offset >> wf->sector_bits],
+ offset & ((1 << wf->sector_bits) - 1)) < 0;
+ wf->position = offset;
+ return offset;
+}
+
+/**
+ * read non-zero integers (le32) from input stream
+ * @param pb
+ * @param[out] data destination
+ * @param count maximum number of integers to read
+ * @return total number of integers read
+ */
+static int read_ints(AVIOContext *pb, uint32_t *data, int count)
+{
+ int i, total = 0;
+ for (i = 0; i < count; i++) {
+ if ((data[total] = avio_rl32(pb)))
+ total++;
+ }
+ return total;
+}
+
+/**
+ * Open file
+ * @param first_sector First sector
+ * @param length Length of file (bytes)
+ * @param depth File allocation table depth
+ * @return NULL on error
+ */
+static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s)
+{
+ AVIOContext *pb;
+ WtvFile *wf;
+ uint8_t *buffer;
+ int64_t size;
+
+ if (seek_by_sector(s->pb, first_sector, 0) < 0)
+ return NULL;
+
+ wf = av_mallocz(sizeof(WtvFile));
+ if (!wf)
+ return NULL;
+
+ if (depth == 0) {
+ wf->sectors = av_malloc(sizeof(uint32_t));
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->sectors[0] = first_sector;
+ wf->nb_sectors = 1;
+ } else if (depth == 1) {
+ wf->sectors = av_malloc(WTV_SECTOR_SIZE);
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4);
+ } else if (depth == 2) {
+ uint32_t sectors1[WTV_SECTOR_SIZE / 4];
+ 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);
+ if (!wf->sectors) {
+ av_free(wf);
+ return NULL;
+ }
+ wf->nb_sectors = 0;
+ for (i = 0; i < nb_sectors1; i++) {
+ if (seek_by_sector(s->pb, sectors1[i], 0) < 0)
+ break;
+ wf->nb_sectors += read_ints(s->pb, wf->sectors + i * WTV_SECTOR_SIZE / 4, WTV_SECTOR_SIZE / 4);
+ }
+ } else {
+ av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth);
+ av_free(wf);
+ return NULL;
+ }
+ wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
+
+ if (!wf->nb_sectors) {
+ av_freep(&wf->sectors);
+ av_freep(&wf);
+ return NULL;
+ }
+
+ size = avio_size(s->pb);
+ if (size >= 0 && (int64_t)wf->sectors[wf->nb_sectors - 1] << WTV_SECTOR_BITS > size)
+ av_log(s, AV_LOG_WARNING, "truncated file\n");
+
+ /* check length */
+ length &= 0xFFFFFFFFFFFF;
+ if (length > ((int64_t)wf->nb_sectors << wf->sector_bits)) {
+ av_log(s, AV_LOG_WARNING, "reported file length (0x%"PRIx64") exceeds number of available sectors (0x%"PRIx64")\n", length, (int64_t)wf->nb_sectors << wf->sector_bits);
+ length = (int64_t)wf->nb_sectors << wf->sector_bits;
+ }
+ wf->length = length;
+
+ /* seek to initial sector */
+ wf->position = 0;
+ if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
+ av_freep(&wf->sectors);
+ av_freep(&wf);
+ return NULL;
+ }
+
+ wf->pb_filesystem = s->pb;
+ buffer = av_malloc(1 << wf->sector_bits);
+ if (!buffer) {
+ av_freep(&wf->sectors);
+ av_freep(&wf);
+ return NULL;
+ }
+
+ pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf,
+ wtvfile_read_packet, NULL, wtvfile_seek);
+ if (!pb) {
+ av_freep(&buffer);
+ av_freep(&wf->sectors);
+ av_freep(&wf);
+ }
+ return pb;
+}
+
+/**
+ * Open file using filename
+ * @param[in] buf directory buffer
+ * @param buf_size directory buffer size
+ * @param[in] filename
+ * @param filename_size size of filename
+ * @return NULL on error
+ */
+static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size)
+{
+ const uint8_t *buf_end = buf + buf_size;
+
+ while(buf + 48 <= buf_end) {
+ int dir_length, name_size, first_sector, depth;
+ uint64_t file_length;
+ const uint8_t *name;
+ if (ff_guidcmp(buf, ff_dir_entry_guid)) {
+ av_log(s, AV_LOG_ERROR, "unknown guid "FF_PRI_GUID", expected dir_entry_guid; "
+ "remaining directory entries ignored\n", FF_ARG_GUID(buf));
+ break;
+ }
+ dir_length = AV_RL16(buf + 16);
+ file_length = AV_RL64(buf + 24);
+ name_size = 2 * AV_RL32(buf + 32);
+ if (name_size < 0) {
+ av_log(s, AV_LOG_ERROR,
+ "bad filename length, remaining directory entries ignored\n");
+ break;
+ }
+ if (48 + (int64_t)name_size > buf_end - buf) {
+ av_log(s, AV_LOG_ERROR, "filename exceeds buffer size; remaining directory entries ignored\n");
+ break;
+ }
+ first_sector = AV_RL32(buf + 40 + name_size);
+ depth = AV_RL32(buf + 44 + name_size);
+
+ /* compare file name; test optional null terminator */
+ name = buf + 40;
+ if (name_size >= filename_size &&
+ !memcmp(name, filename, filename_size) &&
+ (name_size < filename_size + 2 || !AV_RN16(name + filename_size)))
+ return wtvfile_open_sector(first_sector, file_length, depth, s);
+
+ buf += dir_length;
+ }
+ return 0;
+}
+
+#define wtvfile_open(s, buf, buf_size, filename) \
+ wtvfile_open2(s, buf, buf_size, filename, sizeof(filename))
+
+/**
+ * Close file opened with wtvfile_open_sector(), or wtv_open()
+ */
+static void wtvfile_close(AVIOContext *pb)
+{
+ WtvFile *wf = pb->opaque;
+ av_freep(&wf->sectors);
+ av_freep(&pb->opaque);
+ av_freep(&pb->buffer);
+ av_free(pb);
+}
+
+/*
+ *
+ * Main demuxer
+ *
+ */
+
+typedef struct WtvStream {
+ int seen_data;
+} WtvStream;
+
+typedef struct WtvContext {
+ AVIOContext *pb; /**< timeline file */
+ int64_t epoch;
+ int64_t pts; /**< pts for next data chunk */
+ int64_t last_valid_pts; /**< latest valid pts, used for interative seeking */
+
+ /* maintain private seek index, as the AVIndexEntry->pos is relative to the
+ start of the 'timeline' file, not the file system (AVFormatContext->pb) */
+ AVIndexEntry *index_entries;
+ int nb_index_entries;
+ unsigned int index_entries_allocated_size;
+} WtvContext;
+
+/* WTV GUIDs */
+static const ff_asf_guid EVENTID_SubtitleSpanningEvent =
+ {0x48,0xC0,0xCE,0x5D,0xB9,0xD0,0x63,0x41,0x87,0x2C,0x4F,0x32,0x22,0x3B,0xE8,0x8A};
+static const ff_asf_guid EVENTID_LanguageSpanningEvent =
+ {0x6D,0x66,0x92,0xE2,0x02,0x9C,0x8D,0x44,0xAA,0x8D,0x78,0x1A,0x93,0xFD,0xC3,0x95};
+static const ff_asf_guid EVENTID_AudioDescriptorSpanningEvent =
+ {0x1C,0xD4,0x7B,0x10,0xDA,0xA6,0x91,0x46,0x83,0x69,0x11,0xB2,0xCD,0xAA,0x28,0x8E};
+static const ff_asf_guid EVENTID_CtxADescriptorSpanningEvent =
+ {0xE6,0xA2,0xB4,0x3A,0x47,0x42,0x34,0x4B,0x89,0x6C,0x30,0xAF,0xA5,0xD2,0x1C,0x24};
+static const ff_asf_guid EVENTID_CSDescriptorSpanningEvent =
+ {0xD9,0x79,0xE7,0xEf,0xF0,0x97,0x86,0x47,0x80,0x0D,0x95,0xCF,0x50,0x5D,0xDC,0x66};
+static const ff_asf_guid EVENTID_DVBScramblingControlSpanningEvent =
+ {0xC4,0xE1,0xD4,0x4B,0xA1,0x90,0x09,0x41,0x82,0x36,0x27,0xF0,0x0E,0x7D,0xCC,0x5B};
+static const ff_asf_guid EVENTID_StreamIDSpanningEvent =
+ {0x68,0xAB,0xF1,0xCA,0x53,0xE1,0x41,0x4D,0xA6,0xB3,0xA7,0xC9,0x98,0xDB,0x75,0xEE};
+static const ff_asf_guid EVENTID_TeletextSpanningEvent =
+ {0x50,0xD9,0x99,0x95,0x33,0x5F,0x17,0x46,0xAF,0x7C,0x1E,0x54,0xB5,0x10,0xDA,0xA3};
+static const ff_asf_guid EVENTID_AudioTypeSpanningEvent =
+ {0xBE,0xBF,0x1C,0x50,0x49,0xB8,0xCE,0x42,0x9B,0xE9,0x3D,0xB8,0x69,0xFB,0x82,0xB3};
+
+/* Windows media GUIDs */
+
+/* Media types */
+static const ff_asf_guid mediasubtype_mpeg1payload =
+ {0x81,0xEB,0x36,0xE4,0x4F,0x52,0xCE,0x11,0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70};
+static const ff_asf_guid mediatype_mpeg2_sections =
+ {0x6C,0x17,0x5F,0x45,0x06,0x4B,0xCE,0x47,0x9A,0xEF,0x8C,0xAE,0xF7,0x3D,0xF7,0xB5};
+static const ff_asf_guid mediatype_mpeg2_pes =
+ {0x20,0x80,0x6D,0xE0,0x46,0xDB,0xCF,0x11,0xB4,0xD1,0x00,0x80,0x5F,0x6C,0xBB,0xEA};
+static const ff_asf_guid mediatype_mstvcaption =
+ {0x89,0x8A,0x8B,0xB8,0x49,0xB0,0x80,0x4C,0xAD,0xCF,0x58,0x98,0x98,0x5E,0x22,0xC1};
+
+/* Media subtypes */
+static const ff_asf_guid mediasubtype_dvb_subtitle =
+ {0xC3,0xCB,0xFF,0x34,0xB3,0xD5,0x71,0x41,0x90,0x02,0xD4,0xC6,0x03,0x01,0x69,0x7F};
+static const ff_asf_guid mediasubtype_teletext =
+ {0xE3,0x76,0x2A,0xF7,0x0A,0xEB,0xD0,0x11,0xAC,0xE4,0x00,0x00,0xC0,0xCC,0x16,0xBA};
+static const ff_asf_guid mediasubtype_dtvccdata =
+ {0xAA,0xDD,0x2A,0xF5,0xF0,0x36,0xF5,0x43,0x95,0xEA,0x6D,0x86,0x64,0x84,0x26,0x2A};
+static const ff_asf_guid mediasubtype_mpeg2_sections =
+ {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61};
+
+static int read_probe(AVProbeData *p)
+{
+ return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX;
+}
+
+/**
+ * Convert win32 FILETIME to ISO-8601 string
+ * @return <0 on error
+ */
+static int filetime_to_iso8601(char *buf, int buf_size, int64_t value)
+{
+ time_t t = (value / 10000000LL) - 11644473600LL;
+ struct tm tmbuf;
+ struct tm *tm = gmtime_r(&t, &tmbuf);
+ if (!tm)
+ return -1;
+ if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
+ return -1;
+ return 0;
+}
+
+/**
+ * Convert crazy time (100ns since 1 Jan 0001) to ISO-8601 string
+ * @return <0 on error
+ */
+static int crazytime_to_iso8601(char *buf, int buf_size, int64_t value)
+{
+ time_t t = (value / 10000000LL) - 719162LL*86400LL;
+ struct tm tmbuf;
+ struct tm *tm = gmtime_r(&t, &tmbuf);
+ if (!tm)
+ return -1;
+ if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
+ return -1;
+ return 0;
+}
+
+/**
+ * Convert OLE DATE to ISO-8601 string
+ * @return <0 on error
+ */
+static int oledate_to_iso8601(char *buf, int buf_size, int64_t value)
+{
+ time_t t = (av_int2double(value) - 25569.0) * 86400;
+ struct tm tmbuf;
+ struct tm *tm= gmtime_r(&t, &tmbuf);
+ if (!tm)
+ return -1;
+ if (!strftime(buf, buf_size, "%Y-%m-%d %H:%M:%S", tm))
+ return -1;
+ return 0;
+}
+
+static void get_attachment(AVFormatContext *s, AVIOContext *pb, int length)
+{
+ char mime[1024];
+ char description[1024];
+ unsigned int filesize;
+ AVStream *st;
+ int ret;
+ int64_t pos = avio_tell(pb);
+
+ avio_get_str16le(pb, INT_MAX, mime, sizeof(mime));
+ if (strcmp(mime, "image/jpeg"))
+ goto done;
+
+ avio_r8(pb);
+ avio_get_str16le(pb, INT_MAX, description, sizeof(description));
+ filesize = avio_rl32(pb);
+ if (!filesize)
+ goto done;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ goto done;
+ av_dict_set(&st->metadata, "title", description, 0);
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = AV_CODEC_ID_MJPEG;
+ st->id = -1;
+ ret = av_get_packet(pb, &st->attached_pic, filesize);
+ if (ret < 0)
+ goto done;
+ st->attached_pic.stream_index = st->index;
+ st->attached_pic.flags |= AV_PKT_FLAG_KEY;
+ st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
+done:
+ avio_seek(pb, pos + length, SEEK_SET);
+}
+
+static void get_tag(AVFormatContext *s, AVIOContext *pb, const char *key, int type, int length)
+{
+ int buf_size;
+ char *buf;
+
+ if (!strcmp(key, "WM/MediaThumbType")) {
+ avio_skip(pb, length);
+ return;
+ }
+
+ buf_size = FFMAX(2*length, LEN_PRETTY_GUID) + 1;
+ buf = av_malloc(buf_size);
+ if (!buf)
+ return;
+
+ if (type == 0 && length == 4) {
+ snprintf(buf, buf_size, "%u", avio_rl32(pb));
+ } else if (type == 1) {
+ avio_get_str16le(pb, length, buf, buf_size);
+ if (!strlen(buf)) {
+ av_free(buf);
+ return;
+ }
+ } else if (type == 3 && length == 4) {
+ strcpy(buf, avio_rl32(pb) ? "true" : "false");
+ } else if (type == 4 && length == 8) {
+ int64_t num = avio_rl64(pb);
+ if (!strcmp(key, "WM/EncodingTime") ||
+ !strcmp(key, "WM/MediaOriginalBroadcastDateTime")) {
+ if (filetime_to_iso8601(buf, buf_size, num) < 0) {
+ av_free(buf);
+ return;
+ }
+ } else if (!strcmp(key, "WM/WMRVEncodeTime") ||
+ !strcmp(key, "WM/WMRVEndTime")) {
+ if (crazytime_to_iso8601(buf, buf_size, num) < 0) {
+ av_free(buf);
+ return;
+ }
+ } else if (!strcmp(key, "WM/WMRVExpirationDate")) {
+ if (oledate_to_iso8601(buf, buf_size, num) < 0 ) {
+ av_free(buf);
+ return;
+ }
+ } else if (!strcmp(key, "WM/WMRVBitrate"))
+ snprintf(buf, buf_size, "%f", av_int2double(num));
+ else
+ snprintf(buf, buf_size, "%"PRIi64, num);
+ } else if (type == 5 && length == 2) {
+ snprintf(buf, buf_size, "%u", avio_rl16(pb));
+ } else if (type == 6 && length == 16) {
+ ff_asf_guid guid;
+ avio_read(pb, guid, 16);
+ snprintf(buf, buf_size, PRI_PRETTY_GUID, ARG_PRETTY_GUID(guid));
+ } else if (type == 2 && !strcmp(key, "WM/Picture")) {
+ get_attachment(s, pb, length);
+ av_freep(&buf);
+ return;
+ } else {
+ av_freep(&buf);
+ av_log(s, AV_LOG_WARNING, "unsupported metadata entry; key:%s, type:%d, length:0x%x\n", key, type, length);
+ avio_skip(pb, length);
+ return;
+ }
+
+ av_dict_set(&s->metadata, key, buf, 0);
+ av_freep(&buf);
+}
+
+/**
+ * Parse metadata entries
+ */
+static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
+{
+ ff_asf_guid guid;
+ int length, type;
+ while(!avio_feof(pb)) {
+ char key[1024];
+ ff_get_guid(pb, &guid);
+ type = avio_rl32(pb);
+ length = avio_rl32(pb);
+ if (!length)
+ break;
+ if (ff_guidcmp(&guid, ff_metadata_guid)) {
+ av_log(s, AV_LOG_WARNING, "unknown guid "FF_PRI_GUID", expected metadata_guid; "
+ "remaining metadata entries ignored\n", FF_ARG_GUID(guid));
+ break;
+ }
+ avio_get_str16le(pb, INT_MAX, key, sizeof(key));
+ get_tag(s, pb, key, type, length);
+ }
+
+ ff_metadata_conv(&s->metadata, NULL, ff_asf_metadata_conv);
+}
+
+/**
+ * parse VIDEOINFOHEADER2 structure
+ * @return bytes consumed
+ */
+static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+
+ avio_skip(pb, 72); // picture aspect ratio is unreliable
+ st->codec->codec_tag = ff_get_bmp_header(pb, st, NULL);
+
+ return 72 + 40;
+}
+
+/**
+ * Parse MPEG1WAVEFORMATEX extradata structure
+ */
+static void parse_mpeg1waveformatex(AVStream *st)
+{
+ /* fwHeadLayer */
+ switch (AV_RL16(st->codec->extradata)) {
+ case 0x0001 : st->codec->codec_id = AV_CODEC_ID_MP1; break;
+ case 0x0002 : st->codec->codec_id = AV_CODEC_ID_MP2; break;
+ case 0x0004 : st->codec->codec_id = AV_CODEC_ID_MP3; break;
+ }
+
+ st->codec->bit_rate = AV_RL32(st->codec->extradata + 2); /* dwHeadBitrate */
+
+ /* dwHeadMode */
+ switch (AV_RL16(st->codec->extradata + 6)) {
+ case 1 :
+ case 2 :
+ case 4 : st->codec->channels = 2;
+ st->codec->channel_layout = AV_CH_LAYOUT_STEREO;
+ break;
+ case 8 : st->codec->channels = 1;
+ st->codec->channel_layout = AV_CH_LAYOUT_MONO;
+ break;
+ }
+}
+
+/**
+ * Initialise stream
+ * @param st Stream to initialise, or NULL to create and initialise new stream
+ * @return NULL on error
+ */
+static AVStream * new_stream(AVFormatContext *s, AVStream *st, int sid, int codec_type)
+{
+ if (st) {
+ if (st->codec->extradata) {
+ av_freep(&st->codec->extradata);
+ st->codec->extradata_size = 0;
+ }
+ } else {
+ WtvStream *wst = av_mallocz(sizeof(WtvStream));
+ if (!wst)
+ return NULL;
+ st = avformat_new_stream(s, NULL);
+ if (!st) {
+ av_free(wst);
+ return NULL;
+ }
+ st->id = sid;
+ st->priv_data = wst;
+ }
+ st->codec->codec_type = codec_type;
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ avpriv_set_pts_info(st, 64, 1, 10000000);
+ return st;
+}
+
+/**
+ * parse Media Type structure and populate stream
+ * @param st Stream, or NULL to create new stream
+ * @param mediatype Mediatype GUID
+ * @param subtype Subtype GUID
+ * @param formattype Format GUID
+ * @param size Size of format buffer
+ * @return NULL on error
+ */
+static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
+ ff_asf_guid mediatype, ff_asf_guid subtype,
+ ff_asf_guid formattype, uint64_t size)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ if (!ff_guidcmp(subtype, ff_mediasubtype_cpfilters_processed) &&
+ !ff_guidcmp(formattype, ff_format_cpfilters_processed)) {
+ ff_asf_guid actual_subtype;
+ ff_asf_guid actual_formattype;
+
+ if (size < 32) {
+ av_log(s, AV_LOG_WARNING, "format buffer size underflow\n");
+ avio_skip(pb, size);
+ return NULL;
+ }
+
+ avio_skip(pb, size - 32);
+ ff_get_guid(pb, &actual_subtype);
+ ff_get_guid(pb, &actual_formattype);
+ avio_seek(pb, -size, SEEK_CUR);
+
+ st = parse_media_type(s, st, sid, mediatype, actual_subtype, actual_formattype, size - 32);
+ avio_skip(pb, 32);
+ return st;
+ } else if (!ff_guidcmp(mediatype, ff_mediatype_audio)) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_AUDIO);
+ if (!st)
+ return NULL;
+ if (!ff_guidcmp(formattype, ff_format_waveformatex)) {
+ int ret = ff_get_wav_header(pb, st->codec, size, 0);
+ if (ret < 0)
+ return NULL;
+ } else {
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ }
+
+ if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
+ st->codec->codec_id = ff_wav_codec_get_id(AV_RL32(subtype), st->codec->bits_per_coded_sample);
+ } else if (!ff_guidcmp(subtype, mediasubtype_mpeg1payload)) {
+ if (st->codec->extradata && st->codec->extradata_size >= 22)
+ parse_mpeg1waveformatex(st);
+ else
+ av_log(s, AV_LOG_WARNING, "MPEG1WAVEFORMATEX underflow\n");
+ } else {
+ st->codec->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subtype);
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
+ }
+ return st;
+ } else if (!ff_guidcmp(mediatype, ff_mediatype_video)) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_VIDEO);
+ if (!st)
+ return NULL;
+ if (!ff_guidcmp(formattype, ff_format_videoinfo2)) {
+ int consumed = parse_videoinfoheader2(s, st);
+ avio_skip(pb, FFMAX(size - consumed, 0));
+ } else if (!ff_guidcmp(formattype, ff_format_mpeg2_video)) {
+ uint64_t consumed = parse_videoinfoheader2(s, st);
+ /* ignore extradata; files produced by windows media center contain meaningless mpeg1 sequence header */
+ avio_skip(pb, FFMAX(size - consumed, 0));
+ } else {
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ }
+
+ if (!memcmp(subtype + 4, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12)) {
+ st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, AV_RL32(subtype));
+ } else {
+ st->codec->codec_id = ff_codec_guid_get_id(ff_video_guids, subtype);
+ }
+ if (st->codec->codec_id == AV_CODEC_ID_NONE)
+ av_log(s, AV_LOG_WARNING, "unknown subtype:"FF_PRI_GUID"\n", FF_ARG_GUID(subtype));
+ return st;
+ } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_pes) &&
+ !ff_guidcmp(subtype, mediasubtype_dvb_subtitle)) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
+ if (!st)
+ return NULL;
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ st->codec->codec_id = AV_CODEC_ID_DVB_SUBTITLE;
+ return st;
+ } else if (!ff_guidcmp(mediatype, mediatype_mstvcaption) &&
+ (!ff_guidcmp(subtype, mediasubtype_teletext) || !ff_guidcmp(subtype, mediasubtype_dtvccdata))) {
+ st = new_stream(s, st, sid, AVMEDIA_TYPE_SUBTITLE);
+ if (!st)
+ return NULL;
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ st->codec->codec_id = !ff_guidcmp(subtype, mediasubtype_teletext) ? AV_CODEC_ID_DVB_TELETEXT : AV_CODEC_ID_EIA_608;
+ return st;
+ } else if (!ff_guidcmp(mediatype, mediatype_mpeg2_sections) &&
+ !ff_guidcmp(subtype, mediasubtype_mpeg2_sections)) {
+ if (ff_guidcmp(formattype, ff_format_none))
+ av_log(s, AV_LOG_WARNING, "unknown formattype:"FF_PRI_GUID"\n", FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ return NULL;
+ }
+
+ av_log(s, AV_LOG_WARNING, "unknown media type, mediatype:"FF_PRI_GUID
+ ", subtype:"FF_PRI_GUID", formattype:"FF_PRI_GUID"\n",
+ FF_ARG_GUID(mediatype), FF_ARG_GUID(subtype), FF_ARG_GUID(formattype));
+ avio_skip(pb, size);
+ return NULL;
+}
+
+enum {
+ SEEK_TO_DATA = 0,
+ SEEK_TO_PTS,
+};
+
+/**
+ * Try to seek over a broken chunk
+ * @return <0 on error
+ */
+static int recover(WtvContext *wtv, uint64_t broken_pos)
+{
+ AVIOContext *pb = wtv->pb;
+ int i;
+ for (i = 0; i < wtv->nb_index_entries; i++) {
+ if (wtv->index_entries[i].pos > broken_pos) {
+ int64_t ret = avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET);
+ if (ret < 0)
+ return ret;
+ wtv->pts = wtv->index_entries[i].timestamp;
+ return 0;
+ }
+ }
+ return AVERROR(EIO);
+}
+
+/**
+ * Parse WTV chunks
+ * @param mode SEEK_TO_DATA or SEEK_TO_PTS
+ * @param seekts timestamp
+ * @param[out] len_ptr Length of data chunk
+ * @return stream index of data chunk, or <0 on error
+ */
+static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ while (!avio_feof(pb)) {
+ ff_asf_guid g;
+ int len, sid, consumed;
+
+ ff_get_guid(pb, &g);
+ len = avio_rl32(pb);
+ if (len < 32) {
+ int ret;
+ if (avio_feof(pb))
+ return AVERROR_EOF;
+ av_log(s, AV_LOG_WARNING, "encountered broken chunk\n");
+ if ((ret = recover(wtv, avio_tell(pb) - 20)) < 0)
+ return ret;
+ continue;
+ }
+ sid = avio_rl32(pb) & 0x7FFF;
+ avio_skip(pb, 8);
+ consumed = 32;
+
+ if (!ff_guidcmp(g, ff_SBE2_STREAM_DESC_EVENT)) {
+ if (ff_find_stream_index(s, sid) < 0) {
+ ff_asf_guid mediatype, subtype, formattype;
+ int size;
+ avio_skip(pb, 28);
+ ff_get_guid(pb, &mediatype);
+ ff_get_guid(pb, &subtype);
+ avio_skip(pb, 12);
+ ff_get_guid(pb, &formattype);
+ size = avio_rl32(pb);
+ parse_media_type(s, 0, sid, mediatype, subtype, formattype, size);
+ consumed += 92 + size;
+ }
+ } else if (!ff_guidcmp(g, ff_stream2_guid)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0 && s->streams[stream_index]->priv_data && !((WtvStream*)s->streams[stream_index]->priv_data)->seen_data) {
+ ff_asf_guid mediatype, subtype, formattype;
+ int size;
+ avio_skip(pb, 12);
+ ff_get_guid(pb, &mediatype);
+ ff_get_guid(pb, &subtype);
+ avio_skip(pb, 12);
+ ff_get_guid(pb, &formattype);
+ size = avio_rl32(pb);
+ parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size);
+ consumed += 76 + size;
+ }
+ } else if (!ff_guidcmp(g, EVENTID_AudioDescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_StreamIDSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_SubtitleSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_TeletextSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ AVStream *st = s->streams[stream_index];
+ uint8_t buf[258];
+ const uint8_t *pbuf = buf;
+ int buf_size;
+
+ avio_skip(pb, 8);
+ consumed += 8;
+ if (!ff_guidcmp(g, EVENTID_CtxADescriptorSpanningEvent) ||
+ !ff_guidcmp(g, EVENTID_CSDescriptorSpanningEvent)) {
+ avio_skip(pb, 6);
+ consumed += 6;
+ }
+
+ buf_size = FFMIN(len - consumed, sizeof(buf));
+ avio_read(pb, buf, buf_size);
+ consumed += buf_size;
+ ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL);
+ }
+ } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ AVStream *st = s->streams[stream_index];
+ int audio_type;
+ avio_skip(pb, 8);
+ audio_type = avio_r8(pb);
+ if (audio_type == 2)
+ st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED;
+ else if (audio_type == 3)
+ st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+ consumed += 9;
+ }
+ } else if (!ff_guidcmp(g, EVENTID_DVBScramblingControlSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ avio_skip(pb, 12);
+ if (avio_rl32(pb))
+ av_log(s, AV_LOG_WARNING, "DVB scrambled stream detected (st:%d), decoding will likely fail\n", stream_index);
+ consumed += 16;
+ }
+ } else if (!ff_guidcmp(g, EVENTID_LanguageSpanningEvent)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ AVStream *st = s->streams[stream_index];
+ uint8_t language[4];
+ avio_skip(pb, 12);
+ avio_read(pb, language, 3);
+ if (language[0]) {
+ language[3] = 0;
+ av_dict_set(&st->metadata, "language", language, 0);
+ if (!strcmp(language, "nar") || !strcmp(language, "NAR"))
+ st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED;
+ }
+ consumed += 15;
+ }
+ } else if (!ff_guidcmp(g, ff_timestamp_guid)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0) {
+ avio_skip(pb, 8);
+ wtv->pts = avio_rl64(pb);
+ consumed += 16;
+ if (wtv->pts == -1)
+ wtv->pts = AV_NOPTS_VALUE;
+ else {
+ wtv->last_valid_pts = wtv->pts;
+ if (wtv->epoch == AV_NOPTS_VALUE || wtv->pts < wtv->epoch)
+ wtv->epoch = wtv->pts;
+ if (mode == SEEK_TO_PTS && wtv->pts >= seekts) {
+ avio_skip(pb, WTV_PAD8(len) - consumed);
+ return 0;
+ }
+ }
+ }
+ } else if (!ff_guidcmp(g, ff_data_guid)) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (mode == SEEK_TO_DATA && stream_index >= 0 && len > 32 && s->streams[stream_index]->priv_data) {
+ WtvStream *wst = s->streams[stream_index]->priv_data;
+ wst->seen_data = 1;
+ if (len_ptr) {
+ *len_ptr = len;
+ }
+ return stream_index;
+ }
+ } else if (!ff_guidcmp(g, /* DSATTRIB_WMDRMProtectionInfo */ (const ff_asf_guid){0x83,0x95,0x74,0x40,0x9D,0x6B,0xEC,0x4E,0xB4,0x3C,0x67,0xA1,0x80,0x1E,0x1A,0x9B})) {
+ int stream_index = ff_find_stream_index(s, sid);
+ if (stream_index >= 0)
+ av_log(s, AV_LOG_WARNING, "encrypted stream detected (st:%d), decoding will likely fail\n", stream_index);
+ } else if (
+ !ff_guidcmp(g, /* DSATTRIB_CAPTURE_STREAMTIME */ (const ff_asf_guid){0x14,0x56,0x1A,0x0C,0xCD,0x30,0x40,0x4F,0xBC,0xBF,0xD0,0x3E,0x52,0x30,0x62,0x07}) ||
+ !ff_guidcmp(g, /* DSATTRIB_PBDATAG_ATTRIBUTE */ (const ff_asf_guid){0x79,0x66,0xB5,0xE0,0xB9,0x12,0xCC,0x43,0xB7,0xDF,0x57,0x8C,0xAA,0x5A,0x7B,0x63}) ||
+ !ff_guidcmp(g, /* DSATTRIB_PicSampleSeq */ (const ff_asf_guid){0x02,0xAE,0x5B,0x2F,0x8F,0x7B,0x60,0x4F,0x82,0xD6,0xE4,0xEA,0x2F,0x1F,0x4C,0x99}) ||
+ !ff_guidcmp(g, /* DSATTRIB_TRANSPORT_PROPERTIES */ ff_DSATTRIB_TRANSPORT_PROPERTIES) ||
+ !ff_guidcmp(g, /* dvr_ms_vid_frame_rep_data */ (const ff_asf_guid){0xCC,0x32,0x64,0xDD,0x29,0xE2,0xDB,0x40,0x80,0xF6,0xD2,0x63,0x28,0xD2,0x76,0x1F}) ||
+ !ff_guidcmp(g, /* EVENTID_ChannelChangeSpanningEvent */ (const ff_asf_guid){0xE5,0xC5,0x67,0x90,0x5C,0x4C,0x05,0x42,0x86,0xC8,0x7A,0xFE,0x20,0xFE,0x1E,0xFA}) ||
+ !ff_guidcmp(g, /* EVENTID_ChannelInfoSpanningEvent */ (const ff_asf_guid){0x80,0x6D,0xF3,0x41,0x32,0x41,0xC2,0x4C,0xB1,0x21,0x01,0xA4,0x32,0x19,0xD8,0x1B}) ||
+ !ff_guidcmp(g, /* EVENTID_ChannelTypeSpanningEvent */ (const ff_asf_guid){0x51,0x1D,0xAB,0x72,0xD2,0x87,0x9B,0x48,0xBA,0x11,0x0E,0x08,0xDC,0x21,0x02,0x43}) ||
+ !ff_guidcmp(g, /* EVENTID_PIDListSpanningEvent */ (const ff_asf_guid){0x65,0x8F,0xFC,0x47,0xBB,0xE2,0x34,0x46,0x9C,0xEF,0xFD,0xBF,0xE6,0x26,0x1D,0x5C}) ||
+ !ff_guidcmp(g, /* EVENTID_SignalAndServiceStatusSpanningEvent */ (const ff_asf_guid){0xCB,0xC5,0x68,0x80,0x04,0x3C,0x2B,0x49,0xB4,0x7D,0x03,0x08,0x82,0x0D,0xCE,0x51}) ||
+ !ff_guidcmp(g, /* EVENTID_StreamTypeSpanningEvent */ (const ff_asf_guid){0xBC,0x2E,0xAF,0x82,0xA6,0x30,0x64,0x42,0xA8,0x0B,0xAD,0x2E,0x13,0x72,0xAC,0x60}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x1E,0xBE,0xC3,0xC5,0x43,0x92,0xDC,0x11,0x85,0xE5,0x00,0x12,0x3F,0x6F,0x73,0xB9}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x3B,0x86,0xA2,0xB1,0xEB,0x1E,0xC3,0x44,0x8C,0x88,0x1C,0xA3,0xFF,0xE3,0xE7,0x6A}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x4E,0x7F,0x4C,0x5B,0xC4,0xD0,0x38,0x4B,0xA8,0x3E,0x21,0x7F,0x7B,0xBF,0x52,0xE7}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x63,0x36,0xEB,0xFE,0xA1,0x7E,0xD9,0x11,0x83,0x08,0x00,0x07,0xE9,0x5E,0xAD,0x8D}) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0x70,0xE9,0xF1,0xF8,0x89,0xA4,0x4C,0x4D,0x83,0x73,0xB8,0x12,0xE0,0xD5,0xF8,0x1E}) ||
+ !ff_guidcmp(g, ff_index_guid) ||
+ !ff_guidcmp(g, ff_sync_guid) ||
+ !ff_guidcmp(g, ff_stream1_guid) ||
+ !ff_guidcmp(g, (const ff_asf_guid){0xF7,0x10,0x02,0xB9,0xEE,0x7C,0xED,0x4E,0xBD,0x7F,0x05,0x40,0x35,0x86,0x18,0xA1})) {
+ //ignore known guids
+ } else
+ av_log(s, AV_LOG_WARNING, "unsupported chunk:"FF_PRI_GUID"\n", FF_ARG_GUID(g));
+
+ avio_skip(pb, WTV_PAD8(len) - consumed);
+ }
+ return AVERROR_EOF;
+}
+
+static int read_header(AVFormatContext *s)
+{
+ WtvContext *wtv = s->priv_data;
+ int root_sector, root_size;
+ uint8_t root[WTV_SECTOR_SIZE];
+ AVIOContext *pb;
+ int64_t timeline_pos;
+ int64_t ret;
+
+ wtv->epoch =
+ wtv->pts =
+ wtv->last_valid_pts = AV_NOPTS_VALUE;
+
+ /* read root directory sector */
+ avio_skip(s->pb, 0x30);
+ root_size = avio_rl32(s->pb);
+ if (root_size > sizeof(root)) {
+ av_log(s, AV_LOG_ERROR, "root directory size exceeds sector size\n");
+ return AVERROR_INVALIDDATA;
+ }
+ avio_skip(s->pb, 4);
+ root_sector = avio_rl32(s->pb);
+
+ ret = seek_by_sector(s->pb, root_sector, 0);
+ if (ret < 0)
+ return ret;
+ root_size = avio_read(s->pb, root, root_size);
+ if (root_size < 0)
+ return AVERROR_INVALIDDATA;
+
+ /* parse chunks up until first data chunk */
+ wtv->pb = wtvfile_open(s, root, root_size, ff_timeline_le16);
+ if (!wtv->pb) {
+ av_log(s, AV_LOG_ERROR, "timeline data missing\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ret = parse_chunks(s, SEEK_TO_DATA, 0, 0);
+ if (ret < 0)
+ return ret;
+ avio_seek(wtv->pb, -32, SEEK_CUR);
+
+ timeline_pos = avio_tell(s->pb); // save before opening another file
+
+ /* read metadata */
+ pb = wtvfile_open(s, root, root_size, ff_table_0_entries_legacy_attrib_le16);
+ if (pb) {
+ parse_legacy_attrib(s, pb);
+ wtvfile_close(pb);
+ }
+
+ /* read seek index */
+ if (s->nb_streams) {
+ AVStream *st = s->streams[0];
+ pb = wtvfile_open(s, root, root_size, ff_table_0_entries_time_le16);
+ if (pb) {
+ while(1) {
+ uint64_t timestamp = avio_rl64(pb);
+ uint64_t frame_nb = avio_rl64(pb);
+ if (avio_feof(pb))
+ break;
+ ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size,
+ 0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME);
+ }
+ wtvfile_close(pb);
+
+ if (wtv->nb_index_entries) {
+ pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
+ if (pb) {
+ int i;
+ while (1) {
+ uint64_t frame_nb = avio_rl64(pb);
+ uint64_t position = avio_rl64(pb);
+ if (avio_feof(pb))
+ break;
+ for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
+ AVIndexEntry *e = wtv->index_entries + i;
+ if (frame_nb > e->size)
+ break;
+ if (position > e->pos)
+ e->pos = position;
+ }
+ }
+ wtvfile_close(pb);
+ st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
+ }
+ }
+ }
+ }
+
+ avio_seek(s->pb, timeline_pos, SEEK_SET);
+ return 0;
+}
+
+static int read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ int stream_index, len, ret;
+
+ stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
+ if (stream_index < 0)
+ return stream_index;
+
+ ret = av_get_packet(pb, pkt, len - 32);
+ if (ret < 0)
+ return ret;
+ pkt->stream_index = stream_index;
+ pkt->pts = wtv->pts;
+ avio_skip(pb, WTV_PAD8(len) - len);
+ return 0;
+}
+
+static int read_seek(AVFormatContext *s, int stream_index,
+ int64_t ts, int flags)
+{
+ WtvContext *wtv = s->priv_data;
+ AVIOContext *pb = wtv->pb;
+ AVStream *st = s->streams[0];
+ int64_t ts_relative;
+ int i;
+
+ if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
+ return AVERROR(ENOSYS);
+
+ /* timestamp adjustment is required because wtv->pts values are absolute,
+ * whereas AVIndexEntry->timestamp values are relative to epoch. */
+ ts_relative = ts;
+ if (wtv->epoch != AV_NOPTS_VALUE)
+ ts_relative -= wtv->epoch;
+
+ i = ff_index_search_timestamp(wtv->index_entries, wtv->nb_index_entries, ts_relative, flags);
+ if (i < 0) {
+ if (wtv->last_valid_pts == AV_NOPTS_VALUE || ts < wtv->last_valid_pts) {
+ if (avio_seek(pb, 0, SEEK_SET) < 0)
+ return -1;
+ } else if (st->duration != AV_NOPTS_VALUE && ts_relative > st->duration && wtv->nb_index_entries) {
+ if (avio_seek(pb, wtv->index_entries[wtv->nb_index_entries - 1].pos, SEEK_SET) < 0)
+ return -1;
+ }
+ if (parse_chunks(s, SEEK_TO_PTS, ts, 0) < 0)
+ return AVERROR(ERANGE);
+ return 0;
+ }
+ if (avio_seek(pb, wtv->index_entries[i].pos, SEEK_SET) < 0)
+ return -1;
+ wtv->pts = wtv->index_entries[i].timestamp;
+ if (wtv->epoch != AV_NOPTS_VALUE)
+ wtv->pts += wtv->epoch;
+ wtv->last_valid_pts = wtv->pts;
+ return 0;
+}
+
+static int read_close(AVFormatContext *s)
+{
+ WtvContext *wtv = s->priv_data;
+ av_freep(&wtv->index_entries);
+ wtvfile_close(wtv->pb);
+ return 0;
+}
+
+AVInputFormat ff_wtv_demuxer = {
+ .name = "wtv",
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
+ .priv_data_size = sizeof(WtvContext),
+ .read_probe = read_probe,
+ .read_header = read_header,
+ .read_packet = read_packet,
+ .read_seek = read_seek,
+ .read_close = read_close,
+ .flags = AVFMT_SHOW_IDS,
+};
diff --git a/libavformat/wtvenc.c b/libavformat/wtvenc.c
new file mode 100644
index 0000000000..8aebdddf03
--- /dev/null
+++ b/libavformat/wtvenc.c
@@ -0,0 +1,845 @@
+/*
+ * Windows Television (WTV) muxer
+ * Copyright (c) 2011 Zhentan Feng <spyfeng at gmail dot com>
+ * Copyright (c) 2011 Peter Ross <pross@xvid.org>
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * Windows Television (WTV) demuxer
+ * @author Zhentan Feng <spyfeng at gmail dot com>
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "libavutil/avassert.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "mpegts.h"
+#include "wtv.h"
+
+#define WTV_BIGSECTOR_SIZE (1 << WTV_BIGSECTOR_BITS)
+#define INDEX_BASE 0x2
+#define MAX_NB_INDEX 10
+
+/* declare utf16le strings */
+#define _ , 0,
+static const uint8_t timeline_table_0_header_events[] =
+ {'t'_'i'_'m'_'e'_'l'_'i'_'n'_'e'_'.'_'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'E'_'v'_'e'_'n'_'t'_'s', 0};
+static const uint8_t table_0_header_legacy_attrib[] =
+ {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
+static const uint8_t table_0_redirector_legacy_attrib[] =
+ {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'r'_'e'_'d'_'i'_'r'_'e'_'c'_'t'_'o'_'r'_'.'_'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
+static const uint8_t table_0_header_time[] =
+ {'t'_'a'_'b'_'l'_'e'_'.'_'0'_'.'_'h'_'e'_'a'_'d'_'e'_'r'_'.'_'t'_'i'_'m'_'e', 0};
+static const uint8_t legacy_attrib[] =
+ {'l'_'e'_'g'_'a'_'c'_'y'_'_'_'a'_'t'_'t'_'r'_'i'_'b', 0};
+#undef _
+
+static const ff_asf_guid sub_wtv_guid =
+ {0x8C,0xC3,0xD2,0xC2,0x7E,0x9A,0xDA,0x11,0x8B,0xF7,0x00,0x07,0xE9,0x5E,0xAD,0x8D};
+
+enum WtvFileIndex {
+ WTV_TIMELINE_TABLE_0_HEADER_EVENTS = 0,
+ WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS,
+ WTV_TIMELINE,
+ WTV_TABLE_0_HEADER_LEGACY_ATTRIB,
+ WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB,
+ WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB,
+ WTV_TABLE_0_HEADER_TIME,
+ WTV_TABLE_0_ENTRIES_TIME,
+ WTV_FILES
+};
+
+typedef struct {
+ int64_t length;
+ const void *header;
+ int depth;
+ int first_sector;
+} WtvFile;
+
+typedef struct {
+ int64_t pos;
+ int64_t serial;
+ const ff_asf_guid * guid;
+ int stream_id;
+} WtvChunkEntry;
+
+typedef struct {
+ int64_t serial;
+ int64_t value;
+} WtvSyncEntry;
+
+typedef struct {
+ int64_t timeline_start_pos;
+ WtvFile file[WTV_FILES];
+ int64_t serial; /**< chunk serial number */
+ int64_t last_chunk_pos; /**< last chunk position */
+ int64_t last_timestamp_pos; /**< last timestamp chunk position */
+ int64_t first_index_pos; /**< first index_chunk position */
+
+ WtvChunkEntry index[MAX_NB_INDEX];
+ int nb_index;
+ int first_video_flag;
+
+ WtvSyncEntry *st_pairs; /* (serial, timestamp) pairs */
+ int nb_st_pairs;
+ WtvSyncEntry *sp_pairs; /* (serial, position) pairs */
+ int nb_sp_pairs;
+
+ int64_t last_pts;
+ int64_t last_serial;
+
+ AVPacket thumbnail;
+} WtvContext;
+
+
+static void add_serial_pair(WtvSyncEntry ** list, int * count, int64_t serial, int64_t value)
+{
+ int new_count = *count + 1;
+ WtvSyncEntry *new_list = av_realloc_array(*list, new_count, sizeof(WtvSyncEntry));
+ if (!new_list)
+ return;
+ new_list[*count] = (WtvSyncEntry){serial, value};
+ *list = new_list;
+ *count = new_count;
+}
+
+typedef int WTVHeaderWriteFunc(AVIOContext *pb);
+
+typedef struct {
+ const uint8_t *header;
+ int header_size;
+ WTVHeaderWriteFunc *write_header;
+} WTVRootEntryTable;
+
+#define write_pad(pb, size) ffio_fill(pb, 0, size)
+
+/**
+ * Write chunk header. If header chunk (0x80000000 set) then add to list of header chunks
+ */
+static void write_chunk_header(AVFormatContext *s, const ff_asf_guid *guid, int length, int stream_id)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ wctx->last_chunk_pos = avio_tell(pb) - wctx->timeline_start_pos;
+ ff_put_guid(pb, guid);
+ avio_wl32(pb, 32 + length);
+ avio_wl32(pb, stream_id);
+ avio_wl64(pb, wctx->serial);
+
+ if ((stream_id & 0x80000000) && guid != &ff_index_guid) {
+ WtvChunkEntry *t = wctx->index + wctx->nb_index;
+ av_assert0(wctx->nb_index < MAX_NB_INDEX);
+ t->pos = wctx->last_chunk_pos;
+ t->serial = wctx->serial;
+ t->guid = guid;
+ t->stream_id = stream_id & 0x3FFFFFFF;
+ wctx->nb_index++;
+ }
+}
+
+static void write_chunk_header2(AVFormatContext *s, const ff_asf_guid *guid, int stream_id)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ int64_t last_chunk_pos = wctx->last_chunk_pos;
+ write_chunk_header(s, guid, 0, stream_id); // length updated later
+ avio_wl64(pb, last_chunk_pos);
+}
+
+static void finish_chunk_noindex(AVFormatContext *s)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+
+ // update the chunk_len field and pad.
+ int64_t chunk_len = avio_tell(pb) - (wctx->last_chunk_pos + wctx->timeline_start_pos);
+ avio_seek(pb, -(chunk_len - 16), SEEK_CUR);
+ avio_wl32(pb, chunk_len);
+ avio_seek(pb, chunk_len - (16 + 4), SEEK_CUR);
+
+ write_pad(pb, WTV_PAD8(chunk_len) - chunk_len);
+ wctx->serial++;
+}
+
+static void write_index(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ int i;
+
+ write_chunk_header2(s, &ff_index_guid, 0x80000000);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+
+ for (i = 0; i < wctx->nb_index; i++) {
+ WtvChunkEntry *t = wctx->index + i;
+ ff_put_guid(pb, t->guid);
+ avio_wl64(pb, t->pos);
+ avio_wl32(pb, t->stream_id);
+ avio_wl32(pb, 0); // checksum?
+ avio_wl64(pb, t->serial);
+ }
+ wctx->nb_index = 0; // reset index
+ finish_chunk_noindex(s);
+
+ if (!wctx->first_index_pos)
+ wctx->first_index_pos = wctx->last_chunk_pos;
+}
+
+static void finish_chunk(AVFormatContext *s)
+{
+ WtvContext *wctx = s->priv_data;
+ finish_chunk_noindex(s);
+ if (wctx->nb_index == MAX_NB_INDEX)
+ write_index(s);
+}
+
+static void put_videoinfoheader2(AVIOContext *pb, AVStream *st)
+{
+ AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational){st->codec->width, st->codec->height});
+ unsigned int num, den;
+ av_reduce(&num, &den, dar.num, dar.den, 0xFFFFFFFF);
+
+ /* VIDEOINFOHEADER2 */
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, st->codec->width);
+ avio_wl32(pb, st->codec->height);
+
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+
+ avio_wl32(pb, st->codec->bit_rate);
+ avio_wl32(pb, 0);
+ avio_wl64(pb, st->avg_frame_rate.num && st->avg_frame_rate.den ? INT64_C(10000000) / av_q2d(st->avg_frame_rate) : 0);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+
+ avio_wl32(pb, num);
+ avio_wl32(pb, den);
+ avio_wl32(pb, 0);
+ avio_wl32(pb, 0);
+
+ ff_put_bmp_header(pb, st->codec, ff_codec_bmp_tags, 0, 1);
+
+ if (st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
+ int padding = (st->codec->extradata_size & 3) ? 4 - (st->codec->extradata_size & 3) : 0;
+ /* MPEG2VIDEOINFO */
+ avio_wl32(pb, 0);
+ avio_wl32(pb, st->codec->extradata_size + padding);
+ avio_wl32(pb, -1);
+ avio_wl32(pb, -1);
+ avio_wl32(pb, 0);
+ avio_write(pb, st->codec->extradata, st->codec->extradata_size);
+ ffio_fill(pb, 0, padding);
+ }
+}
+
+static int write_stream_codec_info(AVFormatContext *s, AVStream *st)
+{
+ const ff_asf_guid *g, *media_type, *format_type;
+ const AVCodecTag *tags;
+ AVIOContext *pb = s->pb;
+ int64_t hdr_pos_start;
+ int hdr_size = 0;
+
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ g = ff_get_codec_guid(st->codec->codec_id, ff_video_guids);
+ media_type = &ff_mediatype_video;
+ format_type = st->codec->codec_id == AV_CODEC_ID_MPEG2VIDEO ? &ff_format_mpeg2_video : &ff_format_videoinfo2;
+ tags = ff_codec_bmp_tags;
+ } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ g = ff_get_codec_guid(st->codec->codec_id, ff_codec_wav_guids);
+ media_type = &ff_mediatype_audio;
+ format_type = &ff_format_waveformatex;
+ tags = ff_codec_wav_tags;
+ } else {
+ av_log(s, AV_LOG_ERROR, "unknown codec_type (0x%x)\n", st->codec->codec_type);
+ return -1;
+ }
+
+ ff_put_guid(pb, media_type); // mediatype
+ ff_put_guid(pb, &ff_mediasubtype_cpfilters_processed); // subtype
+ write_pad(pb, 12);
+ ff_put_guid(pb,&ff_format_cpfilters_processed); // format type
+ avio_wl32(pb, 0); // size
+
+ hdr_pos_start = avio_tell(pb);
+ if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ put_videoinfoheader2(pb, st);
+ } else {
+ if (ff_put_wav_header(pb, st->codec, 0) < 0)
+ format_type = &ff_format_none;
+ }
+ hdr_size = avio_tell(pb) - hdr_pos_start;
+
+ // seek back write hdr_size
+ avio_seek(pb, -(hdr_size + 4), SEEK_CUR);
+ avio_wl32(pb, hdr_size + 32);
+ avio_seek(pb, hdr_size, SEEK_CUR);
+ if (g) {
+ ff_put_guid(pb, g); // actual_subtype
+ } else {
+ int tag = ff_codec_get_tag(tags, st->codec->codec_id);
+ if (!tag) {
+ av_log(s, AV_LOG_ERROR, "unsupported codec_id (0x%x)\n", st->codec->codec_id);
+ return -1;
+ }
+ avio_wl32(pb, tag);
+ avio_write(pb, (const uint8_t[]){FF_MEDIASUBTYPE_BASE_GUID}, 12);
+ }
+ ff_put_guid(pb, format_type); // actual_formattype
+
+ return 0;
+}
+
+static int write_stream_codec(AVFormatContext *s, AVStream * st)
+{
+ AVIOContext *pb = s->pb;
+ int ret;
+ write_chunk_header2(s, &ff_stream1_guid, 0x80000000 | 0x01);
+
+ avio_wl32(pb, 0x01);
+ write_pad(pb, 4);
+ write_pad(pb, 4);
+
+ ret = write_stream_codec_info(s, st);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
+ return -1;
+ }
+
+ finish_chunk(s);
+ return 0;
+}
+
+static void write_sync(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ int64_t last_chunk_pos = wctx->last_chunk_pos;
+
+ write_chunk_header(s, &ff_sync_guid, 0x18, 0);
+ avio_wl64(pb, wctx->first_index_pos);
+ avio_wl64(pb, wctx->last_timestamp_pos);
+ avio_wl64(pb, 0);
+
+ finish_chunk(s);
+ add_serial_pair(&wctx->sp_pairs, &wctx->nb_sp_pairs, wctx->serial, wctx->last_chunk_pos);
+
+ wctx->last_chunk_pos = last_chunk_pos;
+}
+
+static int write_stream_data(AVFormatContext *s, AVStream *st)
+{
+ AVIOContext *pb = s->pb;
+ int ret;
+
+ write_chunk_header2(s, &ff_SBE2_STREAM_DESC_EVENT, 0x80000000 | (st->index + INDEX_BASE));
+ avio_wl32(pb, 0x00000001);
+ avio_wl32(pb, st->index + INDEX_BASE); //stream_id
+ avio_wl32(pb, 0x00000001);
+ write_pad(pb, 8);
+
+ ret = write_stream_codec_info(s, st);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "write stream codec info failed codec_type(0x%x)\n", st->codec->codec_type);
+ return -1;
+ }
+ finish_chunk(s);
+
+ avpriv_set_pts_info(st, 64, 1, 10000000);
+
+ return 0;
+}
+
+static int write_header(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ int i, pad, ret;
+ AVStream *st;
+
+ wctx->last_chunk_pos = -1;
+ wctx->last_timestamp_pos = -1;
+
+ ff_put_guid(pb, &ff_wtv_guid);
+ ff_put_guid(pb, &sub_wtv_guid);
+
+ avio_wl32(pb, 0x01);
+ avio_wl32(pb, 0x02);
+ avio_wl32(pb, 1 << WTV_SECTOR_BITS);
+ avio_wl32(pb, 1 << WTV_BIGSECTOR_BITS);
+
+ //write initial root fields
+ avio_wl32(pb, 0); // root_size, update later
+ write_pad(pb, 4);
+ avio_wl32(pb, 0); // root_sector, update it later.
+
+ write_pad(pb, 32);
+ avio_wl32(pb, 0); // file ends pointer, update it later.
+
+ pad = (1 << WTV_SECTOR_BITS) - avio_tell(pb);
+ write_pad(pb, pad);
+
+ wctx->timeline_start_pos = avio_tell(pb);
+
+ wctx->serial = 1;
+ wctx->last_chunk_pos = -1;
+ wctx->first_video_flag = 1;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ st = s->streams[i];
+ if (st->codec->codec_id == AV_CODEC_ID_MJPEG)
+ continue;
+ ret = write_stream_codec(s, st);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "write stream codec failed codec_type(0x%x)\n", st->codec->codec_type);
+ return -1;
+ }
+ if (!i)
+ write_sync(s);
+ }
+
+ for (i = 0; i < s->nb_streams; i++) {
+ st = s->streams[i];
+ if (st->codec->codec_id == AV_CODEC_ID_MJPEG)
+ continue;
+ ret = write_stream_data(s, st);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "write stream data failed codec_type(0x%x)\n", st->codec->codec_type);
+ return -1;
+ }
+ }
+
+ if (wctx->nb_index)
+ write_index(s);
+
+ return 0;
+}
+
+static void write_timestamp(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ AVCodecContext *enc = s->streams[pkt->stream_index]->codec;
+
+ write_chunk_header(s, &ff_timestamp_guid, 56, 0x40000000 | (INDEX_BASE + pkt->stream_index));
+ write_pad(pb, 8);
+ avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
+ avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
+ avio_wl64(pb, pkt->pts == AV_NOPTS_VALUE ? -1 : pkt->pts);
+ avio_wl64(pb, 0);
+ avio_wl64(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO && (pkt->flags & AV_PKT_FLAG_KEY) ? 1 : 0);
+ avio_wl64(pb, 0);
+
+ wctx->last_timestamp_pos = wctx->last_chunk_pos;
+}
+
+static int write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ AVStream *st = s->streams[pkt->stream_index];
+
+ if (st->codec->codec_id == AV_CODEC_ID_MJPEG && !wctx->thumbnail.size) {
+ av_copy_packet(&wctx->thumbnail, pkt);
+ return 0;
+ } else if (st->codec->codec_id == AV_CODEC_ID_H264) {
+ int ret = ff_check_h264_startcode(s, st, pkt);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* emit sync chunk and 'timeline.table.0.entries.Event' record every 50 frames */
+ if (wctx->serial - (wctx->nb_sp_pairs ? wctx->sp_pairs[wctx->nb_sp_pairs - 1].serial : 0) >= 50)
+ write_sync(s);
+
+ /* emit 'table.0.entries.time' record every 500ms */
+ if (pkt->pts != AV_NOPTS_VALUE && pkt->pts - (wctx->nb_st_pairs ? wctx->st_pairs[wctx->nb_st_pairs - 1].value : 0) >= 5000000)
+ add_serial_pair(&wctx->st_pairs, &wctx->nb_st_pairs, wctx->serial, pkt->pts);
+
+ if (pkt->pts != AV_NOPTS_VALUE && pkt->pts > wctx->last_pts) {
+ wctx->last_pts = pkt->pts;
+ wctx->last_serial = wctx->serial;
+ }
+
+ // write timestamp chunk
+ write_timestamp(s, pkt);
+
+ write_chunk_header(s, &ff_data_guid, pkt->size, INDEX_BASE + pkt->stream_index);
+ avio_write(pb, pkt->data, pkt->size);
+ write_pad(pb, WTV_PAD8(pkt->size) - pkt->size);
+
+ wctx->serial++;
+ return 0;
+}
+
+static int write_table0_header_events(AVIOContext *pb)
+{
+ avio_wl32(pb, 0x10);
+ write_pad(pb, 84);
+ avio_wl64(pb, 0x32);
+ return 96;
+}
+
+static int write_table0_header_legacy_attrib(AVIOContext *pb)
+{
+ int pad = 0;
+ avio_wl32(pb, 0xFFFFFFFF);
+ write_pad(pb, 12);
+ avio_write(pb, legacy_attrib, sizeof(legacy_attrib));
+ pad = WTV_PAD8(sizeof(legacy_attrib)) - sizeof(legacy_attrib);
+ write_pad(pb, pad);
+ write_pad(pb, 32);
+ return 48 + WTV_PAD8(sizeof(legacy_attrib));
+}
+
+static int write_table0_header_time(AVIOContext *pb)
+{
+ avio_wl32(pb, 0x10);
+ write_pad(pb, 76);
+ avio_wl64(pb, 0x40);
+ return 88;
+}
+
+static const WTVRootEntryTable wtv_root_entry_table[] = {
+ { timeline_table_0_header_events, sizeof(timeline_table_0_header_events), write_table0_header_events},
+ { ff_timeline_table_0_entries_Events_le16, sizeof(ff_timeline_table_0_entries_Events_le16), NULL},
+ { ff_timeline_le16, sizeof(ff_timeline_le16), NULL},
+ { table_0_header_legacy_attrib, sizeof(table_0_header_legacy_attrib), write_table0_header_legacy_attrib},
+ { ff_table_0_entries_legacy_attrib_le16, sizeof(ff_table_0_entries_legacy_attrib_le16), NULL},
+ { table_0_redirector_legacy_attrib, sizeof(table_0_redirector_legacy_attrib), NULL},
+ { table_0_header_time, sizeof(table_0_header_time), write_table0_header_time},
+ { ff_table_0_entries_time_le16, sizeof(ff_table_0_entries_time_le16), NULL},
+};
+
+static int write_root_table(AVFormatContext *s, int64_t sector_pos)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ int size, pad;
+ int i;
+
+ const WTVRootEntryTable *h = wtv_root_entry_table;
+ for (i = 0; i < sizeof(wtv_root_entry_table)/sizeof(WTVRootEntryTable); i++, h++) {
+ WtvFile *w = &wctx->file[i];
+ int filename_padding = WTV_PAD8(h->header_size) - h->header_size;
+ WTVHeaderWriteFunc *write = h->write_header;
+ int len = 0;
+ int64_t len_pos;
+
+ ff_put_guid(pb, &ff_dir_entry_guid);
+ len_pos = avio_tell(pb);
+ avio_wl16(pb, 40 + h->header_size + filename_padding + 8); // maybe updated later
+ write_pad(pb, 6);
+ avio_wl64(pb, write ? 0 : w->length);// maybe update later
+ avio_wl32(pb, (h->header_size + filename_padding) >> 1);
+ write_pad(pb, 4);
+
+ avio_write(pb, h->header, h->header_size);
+ write_pad(pb, filename_padding);
+
+ if (write) {
+ len = write(pb);
+ // update length field
+ avio_seek(pb, len_pos, SEEK_SET);
+ avio_wl64(pb, 40 + h->header_size + filename_padding + len);
+ avio_wl64(pb, len |(1ULL<<62) | (1ULL<<60));
+ avio_seek(pb, 8 + h->header_size + filename_padding + len, SEEK_CUR);
+ } else {
+ avio_wl32(pb, w->first_sector);
+ avio_wl32(pb, w->depth);
+ }
+ }
+
+ // caculate root table size
+ size = avio_tell(pb) - sector_pos;
+ pad = WTV_SECTOR_SIZE- size;
+ write_pad(pb, pad);
+
+ return size;
+}
+
+static void write_fat(AVIOContext *pb, int start_sector, int nb_sectors, int shift)
+{
+ int i;
+ for (i = 0; i < nb_sectors; i++) {
+ avio_wl32(pb, start_sector + (i << shift));
+ }
+ // pad left sector pointer size
+ write_pad(pb, WTV_SECTOR_SIZE - ((nb_sectors << 2) % WTV_SECTOR_SIZE));
+}
+
+static int64_t write_fat_sector(AVFormatContext *s, int64_t start_pos, int nb_sectors, int sector_bits, int depth)
+{
+ int64_t start_sector = start_pos >> WTV_SECTOR_BITS;
+ int shift = sector_bits - WTV_SECTOR_BITS;
+
+ int64_t fat = avio_tell(s->pb);
+ write_fat(s->pb, start_sector, nb_sectors, shift);
+
+ if (depth == 2) {
+ int64_t start_sector1 = fat >> WTV_SECTOR_BITS;
+ int nb_sectors1 = ((nb_sectors << 2) + WTV_SECTOR_SIZE - 1) / WTV_SECTOR_SIZE;
+ int64_t fat1 = avio_tell(s->pb);
+
+ write_fat(s->pb, start_sector1, nb_sectors1, 0);
+ return fat1;
+ }
+
+ return fat;
+}
+
+static void write_table_entries_events(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ int i;
+ for (i = 0; i < wctx->nb_sp_pairs; i++) {
+ avio_wl64(pb, wctx->sp_pairs[i].serial);
+ avio_wl64(pb, wctx->sp_pairs[i].value);
+ }
+}
+
+static void write_table_entries_time(AVFormatContext *s)
+{
+ AVIOContext *pb = s->pb;
+ WtvContext *wctx = s->priv_data;
+ int i;
+ for (i = 0; i < wctx->nb_st_pairs; i++) {
+ avio_wl64(pb, wctx->st_pairs[i].value);
+ avio_wl64(pb, wctx->st_pairs[i].serial);
+ }
+ avio_wl64(pb, wctx->last_pts);
+ avio_wl64(pb, wctx->last_serial);
+}
+
+static void write_metadata_header(AVIOContext *pb, int type, const char *key, int value_size)
+{
+ ff_put_guid(pb, &ff_metadata_guid);
+ avio_wl32(pb, type);
+ avio_wl32(pb, value_size);
+ avio_put_str16le(pb, key);
+}
+
+static int metadata_header_size(const char *key)
+{
+ return 16 + 4 + 4 + strlen(key)*2 + 2;
+}
+
+static void write_tag_int32(AVIOContext *pb, const char *key, int value)
+{
+ write_metadata_header(pb, 0, key, 4);
+ avio_wl32(pb, value);
+}
+
+static void write_tag(AVIOContext *pb, const char *key, const char *value)
+{
+ write_metadata_header(pb, 1, key, strlen(value)*2 + 2);
+ avio_put_str16le(pb, value);
+}
+
+static int attachment_value_size(const AVPacket *pkt, const AVDictionaryEntry *e)
+{
+ return strlen("image/jpeg")*2 + 2 + 1 + (e ? strlen(e->value)*2 : 0) + 2 + 4 + pkt->size;
+}
+
+static void write_table_entries_attrib(AVFormatContext *s)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVDictionaryEntry *tag = 0;
+
+ //FIXME: translate special tags (e.g. WM/Bitrate) to binary representation
+ ff_metadata_conv(&s->metadata, ff_asf_metadata_conv, NULL);
+ while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX)))
+ write_tag(pb, tag->key, tag->value);
+
+ if (wctx->thumbnail.size) {
+ AVStream *st = s->streams[wctx->thumbnail.stream_index];
+ tag = av_dict_get(st->metadata, "title", NULL, 0);
+ write_metadata_header(pb, 2, "WM/Picture", attachment_value_size(&wctx->thumbnail, tag));
+
+ avio_put_str16le(pb, "image/jpeg");
+ avio_w8(pb, 0x10);
+ avio_put_str16le(pb, tag ? tag->value : "");
+
+ avio_wl32(pb, wctx->thumbnail.size);
+ avio_write(pb, wctx->thumbnail.data, wctx->thumbnail.size);
+
+ write_tag_int32(pb, "WM/MediaThumbType", 2);
+ }
+}
+
+static void write_table_redirector_legacy_attrib(AVFormatContext *s)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVDictionaryEntry *tag = 0;
+ int64_t pos = 0;
+
+ //FIXME: translate special tags to binary representation
+ while ((tag = av_dict_get(s->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+ avio_wl64(pb, pos);
+ pos += metadata_header_size(tag->key) + strlen(tag->value)*2 + 2;
+ }
+
+ if (wctx->thumbnail.size) {
+ AVStream *st = s->streams[wctx->thumbnail.stream_index];
+ avio_wl64(pb, pos);
+ pos += metadata_header_size("WM/Picture") + attachment_value_size(&wctx->thumbnail, av_dict_get(st->metadata, "title", NULL, 0));
+
+ avio_wl64(pb, pos);
+ pos += metadata_header_size("WM/MediaThumbType") + 4;
+ }
+}
+
+/**
+ * Pad the remainder of a file
+ * Write out fat table
+ * @return <0 on error
+ */
+static int finish_file(AVFormatContext *s, enum WtvFileIndex index, int64_t start_pos)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ WtvFile *w = &wctx->file[index];
+ int64_t end_pos = avio_tell(pb);
+ int sector_bits, nb_sectors, pad;
+
+ av_assert0(index < WTV_FILES);
+
+ w->length = (end_pos - start_pos);
+
+ // determine optimal fat table depth, sector_bits, nb_sectors
+ if (w->length <= WTV_SECTOR_SIZE) {
+ w->depth = 0;
+ sector_bits = WTV_SECTOR_BITS;
+ } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
+ w->depth = 1;
+ sector_bits = WTV_SECTOR_BITS;
+ } else if (w->length <= (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
+ w->depth = 1;
+ sector_bits = WTV_BIGSECTOR_BITS;
+ } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_SECTOR_SIZE) {
+ w->depth = 2;
+ sector_bits = WTV_SECTOR_BITS;
+ } else if (w->length <= (int64_t)(WTV_SECTOR_SIZE / 4) * (WTV_SECTOR_SIZE / 4) * WTV_BIGSECTOR_SIZE) {
+ w->depth = 2;
+ sector_bits = WTV_BIGSECTOR_BITS;
+ } else {
+ av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (%"PRIi64" bytes)\n", w->length);
+ return -1;
+ }
+
+ // determine the nb_sectors
+ nb_sectors = (int)(w->length >> sector_bits);
+
+ // pad sector of timeline
+ pad = (1 << sector_bits) - (w->length % (1 << sector_bits));
+ if (pad) {
+ nb_sectors++;
+ write_pad(pb, pad);
+ }
+
+ //write fat table
+ if (w->depth > 0) {
+ w->first_sector = write_fat_sector(s, start_pos, nb_sectors, sector_bits, w->depth) >> WTV_SECTOR_BITS;
+ } else {
+ w->first_sector = start_pos >> WTV_SECTOR_BITS;
+ }
+
+ w->length |= 1ULL<<60;
+ if (sector_bits == WTV_SECTOR_BITS)
+ w->length |= 1ULL<<63;
+
+ return 0;
+}
+
+static int write_trailer(AVFormatContext *s)
+{
+ WtvContext *wctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ int root_size;
+ int64_t sector_pos;
+ int64_t start_pos, file_end_pos;
+
+ if (finish_file(s, WTV_TIMELINE, wctx->timeline_start_pos) < 0)
+ return -1;
+
+ start_pos = avio_tell(pb);
+ write_table_entries_events(s);
+ if (finish_file(s, WTV_TIMELINE_TABLE_0_ENTRIES_EVENTS, start_pos) < 0)
+ return -1;
+
+ start_pos = avio_tell(pb);
+ write_table_entries_attrib(s);
+ if (finish_file(s, WTV_TABLE_0_ENTRIES_LEGACY_ATTRIB, start_pos) < 0)
+ return -1;
+
+ start_pos = avio_tell(pb);
+ write_table_redirector_legacy_attrib(s);
+ if (finish_file(s, WTV_TABLE_0_REDIRECTOR_LEGACY_ATTRIB, start_pos) < 0)
+ return -1;
+
+ start_pos = avio_tell(pb);
+ write_table_entries_time(s);
+ if (finish_file(s, WTV_TABLE_0_ENTRIES_TIME, start_pos) < 0)
+ return -1;
+
+ // write root table
+ sector_pos = avio_tell(pb);
+ root_size = write_root_table(s, sector_pos);
+
+ file_end_pos = avio_tell(pb);
+ // update root value
+ avio_seek(pb, 0x30, SEEK_SET);
+ avio_wl32(pb, root_size);
+ avio_seek(pb, 4, SEEK_CUR);
+ avio_wl32(pb, sector_pos >> WTV_SECTOR_BITS);
+ avio_seek(pb, 0x5c, SEEK_SET);
+ avio_wl32(pb, file_end_pos >> WTV_SECTOR_BITS);
+
+ avio_flush(pb);
+
+ av_free(wctx->sp_pairs);
+ av_free(wctx->st_pairs);
+ av_free_packet(&wctx->thumbnail);
+ return 0;
+}
+
+AVOutputFormat ff_wtv_muxer = {
+ .name = "wtv",
+ .long_name = NULL_IF_CONFIG_SMALL("Windows Television (WTV)"),
+ .extensions = "wtv",
+ .priv_data_size = sizeof(WtvContext),
+ .audio_codec = AV_CODEC_ID_AC3,
+ .video_codec = AV_CODEC_ID_MPEG2VIDEO,
+ .write_header = write_header,
+ .write_packet = write_packet,
+ .write_trailer = write_trailer,
+ .codec_tag = (const AVCodecTag* const []){ ff_codec_bmp_tags,
+ ff_codec_wav_tags, 0 },
+};
diff --git a/libavformat/wv.c b/libavformat/wv.c
index 724256b19c..0f4f80761a 100644
--- a/libavformat/wv.c
+++ b/libavformat/wv.c
@@ -1,20 +1,20 @@
/*
* WavPack shared functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/wv.h b/libavformat/wv.h
index ef285d2ebc..07d2e1bc0a 100644
--- a/libavformat/wv.h
+++ b/libavformat/wv.h
@@ -1,20 +1,20 @@
/*
* WavPack shared functions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/wvdec.c b/libavformat/wvdec.c
index 75eddd2f50..96a631fcf3 100644
--- a/libavformat/wvdec.c
+++ b/libavformat/wvdec.c
@@ -2,20 +2,20 @@
* WavPack demuxer
* Copyright (c) 2006,2011 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,8 +64,11 @@ static int wv_probe(AVProbeData *p)
/* check file header */
if (p->buf_size <= 32)
return 0;
- if (p->buf[0] == 'w' && p->buf[1] == 'v' &&
- p->buf[2] == 'p' && p->buf[3] == 'k')
+ if (AV_RL32(&p->buf[0]) == MKTAG('w', 'v', 'p', 'k') &&
+ AV_RL32(&p->buf[4]) >= 24 &&
+ AV_RL32(&p->buf[4]) <= WV_BLOCK_LIMIT &&
+ AV_RL16(&p->buf[8]) >= 0x402 &&
+ AV_RL16(&p->buf[8]) <= 0x410)
return AVPROBE_SCORE_MAX;
else
return 0;
@@ -121,7 +124,7 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb)
"Cannot determine additional parameters\n");
return AVERROR_INVALIDDATA;
}
- while (avio_tell(pb) < block_end) {
+ while (avio_tell(pb) < block_end && !avio_feof(pb)) {
int id, size;
id = avio_r8(pb);
size = (id & 0x80) ? avio_rl24(pb) : avio_r8(pb);
@@ -235,7 +238,8 @@ static int wv_read_header(AVFormatContext *s)
st->codec->bits_per_coded_sample = wc->bpp;
avpriv_set_pts_info(st, 64, 1, wc->rate);
st->start_time = 0;
- st->duration = wc->header.total_samples;
+ if (wc->header.total_samples != 0xFFFFFFFFu)
+ st->duration = wc->header.total_samples;
if (s->pb->seekable) {
int64_t cur = avio_tell(s->pb);
@@ -256,7 +260,7 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt)
int64_t pos;
uint32_t block_samples;
- if (s->pb->eof_reached)
+ if (avio_feof(s->pb))
return AVERROR_EOF;
if (wc->block_parsed) {
if ((ret = wv_read_block_header(s, s->pb)) < 0)
@@ -292,6 +296,7 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt)
}
}
pkt->stream_index = 0;
+ pkt->pos = pos;
wc->block_parsed = 1;
pkt->pts = wc->header.block_idx;
block_samples = wc->header.samples;
@@ -301,41 +306,6 @@ static int wv_read_packet(AVFormatContext *s, AVPacket *pkt)
else
pkt->duration = block_samples;
- av_add_index_entry(s->streams[0], pos, pkt->pts, 0, 0, AVINDEX_KEYFRAME);
- return 0;
-}
-
-static int wv_read_seek(AVFormatContext *s, int stream_index,
- int64_t timestamp, int flags)
-{
- AVStream *st = s->streams[stream_index];
- WVContext *wc = s->priv_data;
- AVPacket pkt1, *pkt = &pkt1;
- int ret;
- int index = av_index_search_timestamp(st, timestamp, flags);
- int64_t pos, pts;
-
- /* if found, seek there */
- if (index >= 0 &&
- timestamp <= st->index_entries[st->nb_index_entries - 1].timestamp) {
- wc->block_parsed = 1;
- avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET);
- return 0;
- }
- /* if timestamp is out of bounds, return error */
- if (timestamp < 0 || timestamp >= s->duration)
- return AVERROR(EINVAL);
-
- pos = avio_tell(s->pb);
- do {
- ret = av_read_frame(s, pkt);
- if (ret < 0) {
- avio_seek(s->pb, pos, SEEK_SET);
- return ret;
- }
- pts = pkt->pts;
- av_free_packet(pkt);
- } while(pts < timestamp);
return 0;
}
@@ -346,5 +316,5 @@ AVInputFormat ff_wv_demuxer = {
.read_probe = wv_probe,
.read_header = wv_read_header,
.read_packet = wv_read_packet,
- .read_seek = wv_read_seek,
+ .flags = AVFMT_GENERIC_INDEX,
};
diff --git a/libavformat/wvenc.c b/libavformat/wvenc.c
index 2e150e1a7a..b0d74caaec 100644
--- a/libavformat/wvenc.c
+++ b/libavformat/wvenc.c
@@ -1,18 +1,22 @@
/*
- * This file is part of Libav.
+ * WavPack muxer
+ * Copyright (c) 2013 Konstantin Shishkov <kostya.shishkov@gmail.com>
+ * Copyright (c) 2012 Paul B Mahol
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/xa.c b/libavformat/xa.c
index 57a36bcbe2..43661dea43 100644
--- a/libavformat/xa.c
+++ b/libavformat/xa.c
@@ -2,20 +2,20 @@
* Maxis XA (.xa) File Demuxer
* Copyright (c) 2008 Robert Marston
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -84,6 +84,9 @@ static int xa_read_header(AVFormatContext *s)
avio_skip(pb, 2); /* Skip block align */
avio_skip(pb, 2); /* Skip bits-per-sample */
+ if (!st->codec->channels || !st->codec->sample_rate)
+ return AVERROR_INVALIDDATA;
+
st->codec->bit_rate = av_clip(15LL * st->codec->channels * 8 *
st->codec->sample_rate / 28, 0, INT_MAX);
diff --git a/libavformat/xmv.c b/libavformat/xmv.c
index bcb17f8893..45c24642cc 100644
--- a/libavformat/xmv.c
+++ b/libavformat/xmv.c
@@ -3,20 +3,20 @@
* Copyright (c) 2011 Sven Hesse <drmccoy@drmccoy.de>
* Copyright (c) 2011 Matthew Hoops <clone2727@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,83 +32,81 @@
#include "avformat.h"
#include "internal.h"
#include "riff.h"
+#include "libavutil/avassert.h"
+/** The min size of an XMV header. */
#define XMV_MIN_HEADER_SIZE 36
+/** Audio flag: ADPCM'd 5.1 stream, front left / right channels */
#define XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT 1
+/** Audio flag: ADPCM'd 5.1 stream, front center / low frequency channels */
#define XMV_AUDIO_ADPCM51_FRONTCENTERLOW 2
+/** Audio flag: ADPCM'd 5.1 stream, rear left / right channels */
#define XMV_AUDIO_ADPCM51_REARLEFTRIGHT 4
+/** Audio flag: Any of the ADPCM'd 5.1 stream flags. */
#define XMV_AUDIO_ADPCM51 (XMV_AUDIO_ADPCM51_FRONTLEFTRIGHT | \
XMV_AUDIO_ADPCM51_FRONTCENTERLOW | \
XMV_AUDIO_ADPCM51_REARLEFTRIGHT)
#define XMV_BLOCK_ALIGN_SIZE 36
-typedef struct XMVAudioTrack {
- uint16_t compression;
- uint16_t channels;
- uint32_t sample_rate;
- uint16_t bits_per_sample;
- uint32_t bit_rate;
- uint16_t flags;
- uint16_t block_align;
- uint16_t block_samples;
-
- enum AVCodecID codec_id;
-} XMVAudioTrack;
-
+/** A video packet with an XMV file. */
typedef struct XMVVideoPacket {
- /* The decoder stream index for this video packet. */
- int stream_index;
+ int stream_index; ///< The decoder stream index for this video packet.
- uint32_t data_size;
- uint32_t data_offset;
+ uint32_t data_size; ///< The size of the remaining video data.
+ uint64_t data_offset; ///< The offset of the video data within the file.
- uint32_t current_frame;
- uint32_t frame_count;
+ uint32_t current_frame; ///< The current frame within this video packet.
+ uint32_t frame_count; ///< The amount of frames within this video packet.
- /* Does the video packet contain extra data? */
- int has_extradata;
+ int has_extradata; ///< Does the video packet contain extra data?
+ uint8_t extradata[4]; ///< The extra data
- /* Extra data */
- uint8_t extradata[4];
-
- int64_t last_pts;
- int64_t pts;
+ int64_t last_pts; ///< PTS of the last video frame.
+ int64_t pts; ///< PTS of the most current video frame.
} XMVVideoPacket;
+/** An audio packet with an XMV file. */
typedef struct XMVAudioPacket {
- /* The decoder stream index for this audio packet. */
- int stream_index;
+ int stream_index; ///< The decoder stream index for this audio packet.
- /* The audio track this packet encodes. */
- XMVAudioTrack *track;
+ /* Stream format properties. */
+ uint16_t compression; ///< The type of compression.
+ uint16_t channels; ///< Number of channels.
+ uint32_t sample_rate; ///< Sampling rate.
+ uint16_t bits_per_sample; ///< Bits per compressed sample.
+ uint32_t bit_rate; ///< Bits of compressed data per second.
+ uint16_t flags; ///< Flags
+ unsigned block_align; ///< Bytes per compressed block.
+ uint16_t block_samples; ///< Decompressed samples per compressed block.
- uint32_t data_size;
- uint32_t data_offset;
+ enum AVCodecID codec_id; ///< The codec ID of the compression scheme.
- uint32_t frame_size;
+ uint32_t data_size; ///< The size of the remaining audio data.
+ uint64_t data_offset; ///< The offset of the audio data within the file.
- uint32_t block_count;
+ uint32_t frame_size; ///< Number of bytes to put into an audio frame.
+
+ uint64_t block_count; ///< Running counter of decompressed audio block.
} XMVAudioPacket;
+/** Context for demuxing an XMV file. */
typedef struct XMVDemuxContext {
- uint16_t audio_track_count;
+ uint16_t audio_track_count; ///< Number of audio track in this file.
- XMVAudioTrack *audio_tracks;
-
- uint32_t this_packet_size;
- uint32_t next_packet_size;
+ uint32_t this_packet_size; ///< Size of the current packet.
+ uint32_t next_packet_size; ///< Size of the next packet.
- uint32_t this_packet_offset;
- uint32_t next_packet_offset;
+ uint64_t this_packet_offset; ///< Offset of the current packet.
+ uint64_t next_packet_offset; ///< Offset of the next packet.
- uint16_t current_stream;
- uint16_t stream_count;
+ uint16_t current_stream; ///< The index of the stream currently handling.
+ uint16_t stream_count; ///< The number of streams in this file.
- XMVVideoPacket video;
- XMVAudioPacket *audio;
+ XMVVideoPacket video; ///< The video packet contained in each packet.
+ XMVAudioPacket *audio; ///< The audio packets contained in each packet.
} XMVDemuxContext;
static int xmv_probe(AVProbeData *p)
@@ -132,8 +130,7 @@ static int xmv_read_close(AVFormatContext *s)
{
XMVDemuxContext *xmv = s->priv_data;
- av_free(xmv->audio);
- av_free(xmv->audio_tracks);
+ av_freep(&xmv->audio);
return 0;
}
@@ -185,36 +182,30 @@ static int xmv_read_header(AVFormatContext *s)
avio_skip(pb, 2); /* Unknown (padding?) */
- xmv->audio_tracks = av_malloc(xmv->audio_track_count * sizeof(XMVAudioTrack));
- if (!xmv->audio_tracks)
- return AVERROR(ENOMEM);
-
- xmv->audio = av_malloc(xmv->audio_track_count * sizeof(XMVAudioPacket));
+ xmv->audio = av_malloc_array(xmv->audio_track_count, sizeof(XMVAudioPacket));
if (!xmv->audio) {
ret = AVERROR(ENOMEM);
goto fail;
}
for (audio_track = 0; audio_track < xmv->audio_track_count; audio_track++) {
- XMVAudioTrack *track = &xmv->audio_tracks[audio_track];
- XMVAudioPacket *packet = &xmv->audio [audio_track];
+ XMVAudioPacket *packet = &xmv->audio[audio_track];
AVStream *ast = NULL;
- track->compression = avio_rl16(pb);
- track->channels = avio_rl16(pb);
- track->sample_rate = avio_rl32(pb);
- track->bits_per_sample = avio_rl16(pb);
- track->flags = avio_rl16(pb);
-
- track->bit_rate = track->bits_per_sample *
- track->sample_rate *
- track->channels;
- track->block_align = XMV_BLOCK_ALIGN_SIZE * track->channels;
- track->block_samples = 64;
- track->codec_id = ff_wav_codec_get_id(track->compression,
- track->bits_per_sample);
-
- packet->track = track;
+ packet->compression = avio_rl16(pb);
+ packet->channels = avio_rl16(pb);
+ packet->sample_rate = avio_rl32(pb);
+ packet->bits_per_sample = avio_rl16(pb);
+ packet->flags = avio_rl16(pb);
+
+ packet->bit_rate = packet->bits_per_sample *
+ packet->sample_rate *
+ packet->channels;
+ packet->block_align = XMV_BLOCK_ALIGN_SIZE * packet->channels;
+ packet->block_samples = 64;
+ packet->codec_id = ff_wav_codec_get_id(packet->compression,
+ packet->bits_per_sample);
+
packet->stream_index = -1;
packet->frame_size = 0;
@@ -222,12 +213,12 @@ static int xmv_read_header(AVFormatContext *s)
/* TODO: ADPCM'd 5.1 sound is encoded in three separate streams.
* Those need to be interleaved to a proper 5.1 stream. */
- if (track->flags & XMV_AUDIO_ADPCM51)
+ if (packet->flags & XMV_AUDIO_ADPCM51)
av_log(s, AV_LOG_WARNING, "Unsupported 5.1 ADPCM audio stream "
- "(0x%04X)\n", track->flags);
+ "(0x%04X)\n", packet->flags);
- if (!track->channels || !track->sample_rate ||
- track->channels >= UINT16_MAX / XMV_BLOCK_ALIGN_SIZE) {
+ if (!packet->channels || !packet->sample_rate ||
+ packet->channels >= UINT16_MAX / XMV_BLOCK_ALIGN_SIZE) {
av_log(s, AV_LOG_ERROR, "Invalid parameters for audio track %"PRIu16".\n",
audio_track);
ret = AVERROR_INVALIDDATA;
@@ -241,15 +232,15 @@ static int xmv_read_header(AVFormatContext *s)
}
ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
- ast->codec->codec_id = track->codec_id;
- ast->codec->codec_tag = track->compression;
- ast->codec->channels = track->channels;
- ast->codec->sample_rate = track->sample_rate;
- ast->codec->bits_per_coded_sample = track->bits_per_sample;
- ast->codec->bit_rate = track->bit_rate;
- ast->codec->block_align = 36 * track->channels;
+ ast->codec->codec_id = packet->codec_id;
+ ast->codec->codec_tag = packet->compression;
+ ast->codec->channels = packet->channels;
+ ast->codec->sample_rate = packet->sample_rate;
+ ast->codec->bits_per_coded_sample = packet->bits_per_sample;
+ ast->codec->bit_rate = packet->bit_rate;
+ ast->codec->block_align = 36 * packet->channels;
- avpriv_set_pts_info(ast, 32, track->block_samples, track->sample_rate);
+ avpriv_set_pts_info(ast, 32, packet->block_samples, packet->sample_rate);
packet->stream_index = ast->index;
@@ -257,7 +248,7 @@ static int xmv_read_header(AVFormatContext *s)
}
- /** Initialize the packet context */
+ /* Initialize the packet context */
xmv->next_packet_offset = avio_tell(pb);
xmv->next_packet_size = this_packet_size - xmv->next_packet_offset;
@@ -303,10 +294,11 @@ static int xmv_process_packet_header(AVFormatContext *s)
{
XMVDemuxContext *xmv = s->priv_data;
AVIOContext *pb = s->pb;
+ int ret;
uint8_t data[8];
uint16_t audio_track;
- uint32_t data_offset;
+ uint64_t data_offset;
/* Next packet size */
xmv->next_packet_size = avio_rl32(pb);
@@ -337,7 +329,7 @@ static int xmv_process_packet_header(AVFormatContext *s)
xmv->current_stream = 0;
if (!xmv->video.frame_count) {
xmv->video.frame_count = 1;
- xmv->current_stream = 1;
+ xmv->current_stream = xmv->stream_count > 1;
}
/* Packet audio header */
@@ -357,9 +349,9 @@ static int xmv_process_packet_header(AVFormatContext *s)
*/
packet->data_size = xmv->audio[audio_track - 1].data_size;
- /** Carve up the audio data in frame_count slices */
+ /* Carve up the audio data in frame_count slices */
packet->frame_size = packet->data_size / xmv->video.frame_count;
- packet->frame_size -= packet->frame_size % packet->track->block_align;
+ packet->frame_size -= packet->frame_size % packet->block_align;
}
/* Packet data offsets */
@@ -387,14 +379,13 @@ static int xmv_process_packet_header(AVFormatContext *s)
if (xmv->video.stream_index >= 0) {
AVStream *vst = s->streams[xmv->video.stream_index];
- assert(xmv->video.stream_index < s->nb_streams);
+ av_assert0(xmv->video.stream_index < s->nb_streams);
if (vst->codec->extradata_size < 4) {
- av_free(vst->codec->extradata);
+ av_freep(&vst->codec->extradata);
- vst->codec->extradata =
- av_malloc(4 + FF_INPUT_BUFFER_PADDING_SIZE);
- vst->codec->extradata_size = 4;
+ if ((ret = ff_alloc_extradata(vst->codec, 4)) < 0)
+ return ret;
}
memcpy(vst->codec->extradata, xmv->video.extradata, 4);
@@ -411,6 +402,9 @@ static int xmv_fetch_new_packet(AVFormatContext *s)
AVIOContext *pb = s->pb;
int result;
+ if (xmv->this_packet_offset == xmv->next_packet_offset)
+ return AVERROR_EOF;
+
/* Seek to it */
xmv->this_packet_offset = xmv->next_packet_offset;
if (avio_seek(pb, xmv->this_packet_offset, SEEK_SET) != xmv->this_packet_offset)
@@ -463,7 +457,7 @@ static int xmv_fetch_audio_packet(AVFormatContext *s,
/* Calculate the PTS */
- block_count = data_size / audio->track->block_align;
+ block_count = data_size / audio->block_align;
pkt->duration = block_count;
pkt->pts = audio->block_count;
@@ -488,7 +482,7 @@ static int xmv_fetch_video_packet(AVFormatContext *s,
int result;
uint32_t frame_header;
uint32_t frame_size, frame_timestamp;
- uint32_t i;
+ uint8_t *data, *end;
/* Seek to it */
if (avio_seek(pb, video->data_offset, SEEK_SET) != video->data_offset)
@@ -503,17 +497,17 @@ static int xmv_fetch_video_packet(AVFormatContext *s,
if ((frame_size + 4) > video->data_size)
return AVERROR(EIO);
- /* Create the packet */
- result = av_new_packet(pkt, frame_size);
- if (result)
+ /* Get the packet data */
+ result = av_get_packet(pb, pkt, frame_size);
+ if (result != frame_size)
return result;
/* Contrary to normal WMV2 video, the bit stream in XMV's
* WMV2 is little-endian.
* TODO: This manual swap is of course suboptimal.
*/
- for (i = 0; i < frame_size; i += 4)
- AV_WB32(pkt->data + i, avio_rl32(pb));
+ for (data = pkt->data, end = pkt->data + frame_size; data < end; data += 4)
+ AV_WB32(data, AV_RL32(data));
pkt->stream_index = video->stream_index;
diff --git a/libavformat/xwma.c b/libavformat/xwma.c
index 4a30001f76..683d3d0d4d 100644
--- a/libavformat/xwma.c
+++ b/libavformat/xwma.c
@@ -2,20 +2,20 @@
* xWMA demuxer
* Copyright (c) 2011 Max Horn
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,7 +46,7 @@ static int xwma_read_header(AVFormatContext *s)
int64_t size;
int ret = 0;
uint32_t dpds_table_size = 0;
- uint32_t *dpds_table = 0;
+ uint32_t *dpds_table = NULL;
unsigned int tag;
AVIOContext *pb = s->pb;
AVStream *st;
@@ -75,7 +75,7 @@ static int xwma_read_header(AVFormatContext *s)
if (!st)
return AVERROR(ENOMEM);
- ret = ff_get_wav_header(pb, st->codec, size);
+ ret = ff_get_wav_header(pb, st->codec, size, 0);
if (ret < 0)
return ret;
st->need_parsing = AVSTREAM_PARSE_NONE;
@@ -104,11 +104,10 @@ static int xwma_read_header(AVFormatContext *s)
avpriv_request_sample(s, "Unexpected extradata (%d bytes)",
st->codec->extradata_size);
} else {
- st->codec->extradata_size = 6;
- st->codec->extradata = av_mallocz(6 + FF_INPUT_BUFFER_PADDING_SIZE);
- if (!st->codec->extradata)
+ if (ff_alloc_extradata(st->codec, 6))
return AVERROR(ENOMEM);
+ memset(st->codec->extradata, 0, st->codec->extradata_size);
/* setup extradata with our experimentally obtained value */
st->codec->extradata[4] = 31;
}
@@ -131,7 +130,7 @@ static int xwma_read_header(AVFormatContext *s)
/* parse the remaining RIFF chunks */
for (;;) {
if (pb->eof_reached) {
- ret = AVERROR_INVALIDDATA;
+ ret = AVERROR_EOF;
goto fail;
}
/* read next chunk tag */
@@ -167,13 +166,13 @@ static int xwma_read_header(AVFormatContext *s)
if (dpds_table_size == 0 || dpds_table_size >= INT_MAX / 4) {
av_log(s, AV_LOG_ERROR,
"dpds chunk size %"PRId64" invalid\n", size);
- return -1;
+ return AVERROR_INVALIDDATA;
}
/* Allocate some temporary storage to keep the dpds data around.
* for processing later on.
*/
- dpds_table = av_malloc(dpds_table_size * sizeof(uint32_t));
+ dpds_table = av_malloc_array(dpds_table_size, sizeof(uint32_t));
if (!dpds_table) {
return AVERROR(ENOMEM);
}
diff --git a/libavformat/yop.c b/libavformat/yop.c
index 08fcc19e3c..81b3cc2b32 100644
--- a/libavformat/yop.c
+++ b/libavformat/yop.c
@@ -5,20 +5,20 @@
* derived from the code by
* Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -39,10 +39,15 @@ typedef struct yop_dec_context {
static int yop_probe(AVProbeData *probe_packet)
{
if (AV_RB16(probe_packet->buf) == AV_RB16("YO") &&
+ probe_packet->buf[2]<10 &&
+ probe_packet->buf[3]<10 &&
probe_packet->buf[6] &&
probe_packet->buf[7] &&
!(probe_packet->buf[8] & 1) &&
- !(probe_packet->buf[10] & 1))
+ !(probe_packet->buf[10] & 1) &&
+ AV_RL16(probe_packet->buf + 12 + 6) >= 920 &&
+ AV_RL16(probe_packet->buf + 12 + 6) < probe_packet->buf[12] * 3 + 4 + probe_packet->buf[7] * 2048
+ )
return AVPROBE_SCORE_MAX * 3 / 4;
return 0;
@@ -60,14 +65,12 @@ static int yop_read_header(AVFormatContext *s)
audio_stream = avformat_new_stream(s, NULL);
video_stream = avformat_new_stream(s, NULL);
+ if (!audio_stream || !video_stream)
+ return AVERROR(ENOMEM);
// Extra data that will be passed to the decoder
-
- video_stream->codec->extradata = av_mallocz(8 + FF_INPUT_BUFFER_PADDING_SIZE);
-
- if (!video_stream->codec->extradata)
+ if (ff_alloc_extradata(video_stream->codec, 8))
return AVERROR(ENOMEM);
- video_stream->codec->extradata_size = 8;
// Audio
audio_dec = audio_stream->codec;
@@ -98,6 +101,8 @@ static int yop_read_header(AVFormatContext *s)
yop->palette_size = video_dec->extradata[0] * 3 + 4;
yop->audio_block_length = AV_RL16(video_dec->extradata + 6);
+ video_dec->bit_rate = 8 * (yop->frame_size - yop->audio_block_length) * frame_rate;
+
// 1840 samples per frame, 1 nibble per sample; hence 1840/2 = 920
if (yop->audio_block_length < 920 ||
yop->audio_block_length + yop->palette_size >= yop->frame_size) {
diff --git a/libavformat/yuv4mpeg.h b/libavformat/yuv4mpeg.h
index 7891ed60a7..750f498407 100644
--- a/libavformat/yuv4mpeg.h
+++ b/libavformat/yuv4mpeg.h
@@ -1,20 +1,20 @@
/*
* YUV4MPEG common definitions
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavformat/yuv4mpegdec.c b/libavformat/yuv4mpegdec.c
index dd81358608..7613c3cdc3 100644
--- a/libavformat/yuv4mpegdec.c
+++ b/libavformat/yuv4mpegdec.c
@@ -2,20 +2,20 @@
* YUV4MPEG demuxer
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -79,20 +79,52 @@ static int yuv4_read_header(AVFormatContext *s)
} else if (strncmp("420paldv", tokstart, 8) == 0) {
pix_fmt = AV_PIX_FMT_YUV420P;
chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
+ } else if (strncmp("420p16", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV420P16;
+ } else if (strncmp("422p16", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV422P16;
+ } else if (strncmp("444p16", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV444P16;
+ } else if (strncmp("420p14", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV420P14;
+ } else if (strncmp("422p14", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV422P14;
+ } else if (strncmp("444p14", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV444P14;
+ } else if (strncmp("420p12", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV420P12;
+ } else if (strncmp("422p12", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV422P12;
+ } else if (strncmp("444p12", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV444P12;
+ } else if (strncmp("420p10", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV420P10;
+ } else if (strncmp("422p10", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV422P10;
+ } else if (strncmp("444p10", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV444P10;
+ } else if (strncmp("420p9", tokstart, 5) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV420P9;
+ } else if (strncmp("422p9", tokstart, 5) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV422P9;
+ } else if (strncmp("444p9", tokstart, 5) == 0) {
+ pix_fmt = AV_PIX_FMT_YUV444P9;
} else if (strncmp("420", tokstart, 3) == 0) {
pix_fmt = AV_PIX_FMT_YUV420P;
chroma_sample_location = AVCHROMA_LOC_CENTER;
- } else if (strncmp("411", tokstart, 3) == 0)
+ } else if (strncmp("411", tokstart, 3) == 0) {
pix_fmt = AV_PIX_FMT_YUV411P;
- else if (strncmp("422", tokstart, 3) == 0)
+ } else if (strncmp("422", tokstart, 3) == 0) {
pix_fmt = AV_PIX_FMT_YUV422P;
- else if (strncmp("444alpha", tokstart, 8) == 0 ) {
+ } else if (strncmp("444alpha", tokstart, 8) == 0 ) {
av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 "
"YUV4MPEG stream.\n");
return -1;
- } else if (strncmp("444", tokstart, 3) == 0)
+ } else if (strncmp("444", tokstart, 3) == 0) {
pix_fmt = AV_PIX_FMT_YUV444P;
- else if (strncmp("mono", tokstart, 4) == 0) {
+ } else if (strncmp("mono16", tokstart, 6) == 0) {
+ pix_fmt = AV_PIX_FMT_GRAY16;
+ } else if (strncmp("mono", tokstart, 4) == 0) {
pix_fmt = AV_PIX_FMT_GRAY8;
} else {
av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown "
@@ -119,10 +151,9 @@ static int yuv4_read_header(AVFormatContext *s)
case 'm':
av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed "
"interlaced and non-interlaced frames.\n");
- return -1;
default:
av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
- return -1;
+ return AVERROR(EINVAL);
}
break;
case 'F': // Frame rate
@@ -145,6 +176,36 @@ static int yuv4_read_header(AVFormatContext *s)
alt_pix_fmt = AV_PIX_FMT_YUV420P;
else if (strncmp("420PALDV", tokstart, 8) == 0)
alt_pix_fmt = AV_PIX_FMT_YUV420P;
+ else if (strncmp("420P9", tokstart, 5) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV420P9;
+ else if (strncmp("422P9", tokstart, 5) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV422P9;
+ else if (strncmp("444P9", tokstart, 5) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV444P9;
+ else if (strncmp("420P10", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV420P10;
+ else if (strncmp("422P10", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV422P10;
+ else if (strncmp("444P10", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV444P10;
+ else if (strncmp("420P12", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV420P12;
+ else if (strncmp("422P12", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV422P12;
+ else if (strncmp("444P12", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV444P12;
+ else if (strncmp("420P14", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV420P14;
+ else if (strncmp("422P14", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV422P14;
+ else if (strncmp("444P14", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV444P14;
+ else if (strncmp("420P16", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV420P16;
+ else if (strncmp("422P16", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV422P16;
+ else if (strncmp("444P16", tokstart, 6) == 0)
+ alt_pix_fmt = AV_PIX_FMT_YUV444P16;
else if (strncmp("411", tokstart, 3) == 0)
alt_pix_fmt = AV_PIX_FMT_YUV411P;
else if (strncmp("422", tokstart, 3) == 0)
diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
index 2caa364908..cc954fcc63 100644
--- a/libavformat/yuv4mpegenc.c
+++ b/libavformat/yuv4mpegenc.c
@@ -2,20 +2,20 @@
* YUV4MPEG muxer
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,9 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
aspectd = 0; // 0:0 means unknown
switch (st->codec->field_order) {
+ case AV_FIELD_TB:
case AV_FIELD_TT: inter = 't'; break;
+ case AV_FIELD_BT:
case AV_FIELD_BB: inter = 'b'; break;
default: inter = 'p'; break;
}
@@ -58,6 +60,9 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
case AV_PIX_FMT_GRAY8:
colorspace = " Cmono";
break;
+ case AV_PIX_FMT_GRAY16:
+ colorspace = " Cmono16";
+ break;
case AV_PIX_FMT_YUV411P:
colorspace = " C411 XYSCSS=411";
break;
@@ -74,6 +79,51 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf)
case AV_PIX_FMT_YUV444P:
colorspace = " C444 XYSCSS=444";
break;
+ case AV_PIX_FMT_YUV420P9:
+ colorspace = " C420p9 XYSCSS=420P9";
+ break;
+ case AV_PIX_FMT_YUV422P9:
+ colorspace = " C422p9 XYSCSS=422P9";
+ break;
+ case AV_PIX_FMT_YUV444P9:
+ colorspace = " C444p9 XYSCSS=444P9";
+ break;
+ case AV_PIX_FMT_YUV420P10:
+ colorspace = " C420p10 XYSCSS=420P10";
+ break;
+ case AV_PIX_FMT_YUV422P10:
+ colorspace = " C422p10 XYSCSS=422P10";
+ break;
+ case AV_PIX_FMT_YUV444P10:
+ colorspace = " C444p10 XYSCSS=444P10";
+ break;
+ case AV_PIX_FMT_YUV420P12:
+ colorspace = " C420p12 XYSCSS=420P12";
+ break;
+ case AV_PIX_FMT_YUV422P12:
+ colorspace = " C422p12 XYSCSS=422P12";
+ break;
+ case AV_PIX_FMT_YUV444P12:
+ colorspace = " C444p12 XYSCSS=444P12";
+ break;
+ case AV_PIX_FMT_YUV420P14:
+ colorspace = " C420p14 XYSCSS=420P14";
+ break;
+ case AV_PIX_FMT_YUV422P14:
+ colorspace = " C422p14 XYSCSS=422P14";
+ break;
+ case AV_PIX_FMT_YUV444P14:
+ colorspace = " C444p14 XYSCSS=444P14";
+ break;
+ case AV_PIX_FMT_YUV420P16:
+ colorspace = " C420p16 XYSCSS=420P16";
+ break;
+ case AV_PIX_FMT_YUV422P16:
+ colorspace = " C422p16 XYSCSS=422P16";
+ break;
+ case AV_PIX_FMT_YUV444P16:
+ colorspace = " C444p16 XYSCSS=444P16";
+ break;
}
/* construct stream header, if this is the first frame */
@@ -88,7 +138,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVStream *st = s->streams[pkt->stream_index];
AVIOContext *pb = s->pb;
- AVPicture *picture;
+ AVPicture *picture, picture_tmp;
int* first_pkt = s->priv_data;
int width, height, h_chroma_shift, v_chroma_shift;
int i;
@@ -96,7 +146,8 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
char buf1[20];
uint8_t *ptr, *ptr1, *ptr2;
- picture = (AVPicture *)pkt->data;
+ memcpy(&picture_tmp, pkt->data, sizeof(AVPicture));
+ picture = &picture_tmp;
/* for the first packet we have to output the header as well */
if (*first_pkt) {
@@ -119,18 +170,50 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
height = st->codec->height;
ptr = picture->data[0];
+
+ switch (st->codec->pix_fmt) {
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_YUV411P:
+ case AV_PIX_FMT_YUV420P:
+ case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUV444P:
+ break;
+ case AV_PIX_FMT_GRAY16:
+ case AV_PIX_FMT_YUV420P9:
+ case AV_PIX_FMT_YUV422P9:
+ case AV_PIX_FMT_YUV444P9:
+ case AV_PIX_FMT_YUV420P10:
+ case AV_PIX_FMT_YUV422P10:
+ case AV_PIX_FMT_YUV444P10:
+ case AV_PIX_FMT_YUV420P12:
+ case AV_PIX_FMT_YUV422P12:
+ case AV_PIX_FMT_YUV444P12:
+ case AV_PIX_FMT_YUV420P14:
+ case AV_PIX_FMT_YUV422P14:
+ case AV_PIX_FMT_YUV444P14:
+ case AV_PIX_FMT_YUV420P16:
+ case AV_PIX_FMT_YUV422P16:
+ case AV_PIX_FMT_YUV444P16:
+ width *= 2;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "The pixel format '%s' is not supported.\n",
+ av_get_pix_fmt_name(st->codec->pix_fmt));
+ return AVERROR(EINVAL);
+ }
+
for (i = 0; i < height; i++) {
avio_write(pb, ptr, width);
ptr += picture->linesize[0];
}
- if (st->codec->pix_fmt != AV_PIX_FMT_GRAY8) {
+ if (st->codec->pix_fmt != AV_PIX_FMT_GRAY8 &&
+ st->codec->pix_fmt != AV_PIX_FMT_GRAY16) {
// Adjust for smaller Cb and Cr planes
av_pix_fmt_get_chroma_sub_sample(st->codec->pix_fmt, &h_chroma_shift,
&v_chroma_shift);
- // Shift right, rounding up
- width = -(-width >> h_chroma_shift);
- height = -(-height >> v_chroma_shift);
+ width = FF_CEIL_RSHIFT(width, h_chroma_shift);
+ height = FF_CEIL_RSHIFT(height, v_chroma_shift);
ptr1 = picture->data[1];
ptr2 = picture->data[2];
@@ -143,6 +226,7 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
ptr2 += picture->linesize[2];
}
}
+
return 0;
}
@@ -158,15 +242,50 @@ static int yuv4_write_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- if (s->streams[0]->codec->pix_fmt == AV_PIX_FMT_YUV411P) {
- av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV "
+ switch (s->streams[0]->codec->pix_fmt) {
+ case AV_PIX_FMT_YUV411P:
+ av_log(s, AV_LOG_WARNING, "Warning: generating rarely used 4:1:1 YUV "
"stream, some mjpegtools might not work.\n");
- } else if ((s->streams[0]->codec->pix_fmt != AV_PIX_FMT_YUV420P) &&
- (s->streams[0]->codec->pix_fmt != AV_PIX_FMT_YUV422P) &&
- (s->streams[0]->codec->pix_fmt != AV_PIX_FMT_GRAY8) &&
- (s->streams[0]->codec->pix_fmt != AV_PIX_FMT_YUV444P)) {
- av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg only handles yuv444p, "
- "yuv422p, yuv420p, yuv411p and gray pixel formats. "
+ break;
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_GRAY16:
+ case AV_PIX_FMT_YUV420P:
+ case AV_PIX_FMT_YUV422P:
+ case AV_PIX_FMT_YUV444P:
+ break;
+ case AV_PIX_FMT_YUV420P9:
+ case AV_PIX_FMT_YUV422P9:
+ case AV_PIX_FMT_YUV444P9:
+ case AV_PIX_FMT_YUV420P10:
+ case AV_PIX_FMT_YUV422P10:
+ case AV_PIX_FMT_YUV444P10:
+ case AV_PIX_FMT_YUV420P12:
+ case AV_PIX_FMT_YUV422P12:
+ case AV_PIX_FMT_YUV444P12:
+ case AV_PIX_FMT_YUV420P14:
+ case AV_PIX_FMT_YUV422P14:
+ case AV_PIX_FMT_YUV444P14:
+ case AV_PIX_FMT_YUV420P16:
+ case AV_PIX_FMT_YUV422P16:
+ case AV_PIX_FMT_YUV444P16:
+ if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
+ av_log(s, AV_LOG_ERROR, "'%s' is not a official yuv4mpegpipe pixel format. "
+ "Use '-strict -1' to encode to this pixel format.\n",
+ av_get_pix_fmt_name(s->streams[0]->codec->pix_fmt));
+ return AVERROR(EINVAL);
+ }
+ av_log(s, AV_LOG_WARNING, "Warning: generating non standard YUV stream. "
+ "Mjpegtools will not work.\n");
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg can only handle "
+ "yuv444p, yuv422p, yuv420p, yuv411p and gray8 pixel formats. "
+ "And using 'strict -1' also yuv444p9, yuv422p9, yuv420p9, "
+ "yuv444p10, yuv422p10, yuv420p10, "
+ "yuv444p12, yuv422p12, yuv420p12, "
+ "yuv444p14, yuv422p14, yuv420p14, "
+ "yuv444p16, yuv422p16, yuv420p16 "
+ "and gray16 pixel formats. "
"Use -pix_fmt to select one.\n");
return AVERROR(EIO);
}
@@ -178,7 +297,6 @@ static int yuv4_write_header(AVFormatContext *s)
AVOutputFormat ff_yuv4mpegpipe_muxer = {
.name = "yuv4mpegpipe",
.long_name = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
- .mime_type = "",
.extensions = "y4m",
.priv_data_size = sizeof(int),
.audio_codec = AV_CODEC_ID_NONE,
diff --git a/libavresample/Makefile b/libavresample/Makefile
index b9ca491194..7d857a0e36 100644
--- a/libavresample/Makefile
+++ b/libavresample/Makefile
@@ -12,4 +12,7 @@ OBJS = audio_convert.o \
resample.o \
utils.o \
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avresampleres.o
+
TESTPROGS = avresample
diff --git a/libavresample/aarch64/asm-offsets.h b/libavresample/aarch64/asm-offsets.h
index 856f191b23..0b582446f6 100644
--- a/libavresample/aarch64/asm-offsets.h
+++ b/libavresample/aarch64/asm-offsets.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/aarch64/audio_convert_init.c b/libavresample/aarch64/audio_convert_init.c
index 020dd6124a..b5b0d1eee0 100644
--- a/libavresample/aarch64/audio_convert_init.c
+++ b/libavresample/aarch64/audio_convert_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/aarch64/audio_convert_neon.S b/libavresample/aarch64/audio_convert_neon.S
index 198cf86208..e13e277e61 100644
--- a/libavresample/aarch64/audio_convert_neon.S
+++ b/libavresample/aarch64/audio_convert_neon.S
@@ -2,20 +2,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/aarch64/neontest.c b/libavresample/aarch64/neontest.c
index 20e563dfa6..e956ee6b0d 100644
--- a/libavresample/aarch64/neontest.c
+++ b/libavresample/aarch64/neontest.c
@@ -2,20 +2,20 @@
* check NEON registers for clobbers
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/aarch64/resample_init.c b/libavresample/aarch64/resample_init.c
index ec321a35bc..e21c600286 100644
--- a/libavresample/aarch64/resample_init.c
+++ b/libavresample/aarch64/resample_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/aarch64/resample_neon.S b/libavresample/aarch64/resample_neon.S
index 94aec58887..d3c2cbf561 100644
--- a/libavresample/aarch64/resample_neon.S
+++ b/libavresample/aarch64/resample_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/arm/asm-offsets.h b/libavresample/arm/asm-offsets.h
index a1623ed68b..4d3d116dc0 100644
--- a/libavresample/arm/asm-offsets.h
+++ b/libavresample/arm/asm-offsets.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/arm/audio_convert_init.c b/libavresample/arm/audio_convert_init.c
index bbb7bae514..3d19a0e0e5 100644
--- a/libavresample/arm/audio_convert_init.c
+++ b/libavresample/arm/audio_convert_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/arm/audio_convert_neon.S b/libavresample/arm/audio_convert_neon.S
index 98945c4a64..a120e8793b 100644
--- a/libavresample/arm/audio_convert_neon.S
+++ b/libavresample/arm/audio_convert_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/arm/neontest.c b/libavresample/arm/neontest.c
index d96d4d288e..22afedbc60 100644
--- a/libavresample/arm/neontest.c
+++ b/libavresample/arm/neontest.c
@@ -2,20 +2,20 @@
* check NEON registers for clobbers
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/arm/resample_init.c b/libavresample/arm/resample_init.c
index 540177ed0b..10af09cb91 100644
--- a/libavresample/arm/resample_init.c
+++ b/libavresample/arm/resample_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/arm/resample_neon.S b/libavresample/arm/resample_neon.S
index a8181e55ce..7ee8497a5c 100644
--- a/libavresample/arm/resample_neon.S
+++ b/libavresample/arm/resample_neon.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/audio_convert.c b/libavresample/audio_convert.c
index eabcd86a96..f2888cdd17 100644
--- a/libavresample/audio_convert.c
+++ b/libavresample/audio_convert.c
@@ -2,20 +2,20 @@
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/audio_convert.h b/libavresample/audio_convert.h
index d8e42d0afc..df15442c18 100644
--- a/libavresample/audio_convert.h
+++ b/libavresample/audio_convert.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/audio_data.c b/libavresample/audio_data.c
index 7a6fe74551..c2f545013c 100644
--- a/libavresample/audio_data.c
+++ b/libavresample/audio_data.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/audio_data.h b/libavresample/audio_data.h
index 1541976583..b50bd40600 100644
--- a/libavresample/audio_data.h
+++ b/libavresample/audio_data.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c
index 8ff82a2b94..7ae0aeb74d 100644
--- a/libavresample/audio_mix.c
+++ b/libavresample/audio_mix.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,7 +28,7 @@
#include "audio_data.h"
#include "audio_mix.h"
-static const char *coeff_type_names[] = { "q8", "q15", "flt" };
+static const char * const coeff_type_names[] = { "q8", "q15", "flt" };
struct AudioMix {
AVAudioResampleContext *avr;
diff --git a/libavresample/audio_mix.h b/libavresample/audio_mix.h
index 5bae5ab6da..0187d0f9e0 100644
--- a/libavresample/audio_mix.h
+++ b/libavresample/audio_mix.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/audio_mix_matrix.c b/libavresample/audio_mix_matrix.c
index 5182ae1bf9..5d92351a0e 100644
--- a/libavresample/audio_mix_matrix.c
+++ b/libavresample/audio_mix_matrix.c
@@ -2,20 +2,20 @@
* Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at)
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/avresample-test.c b/libavresample/avresample-test.c
index 697b4ba799..290ae947fd 100644
--- a/libavresample/avresample-test.c
+++ b/libavresample/avresample-test.c
@@ -2,20 +2,20 @@
* Copyright (c) 2002 Fabrice Bellard
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/avresample.h b/libavresample/avresample.h
index b705a45cde..5eb55cb6db 100644
--- a/libavresample/avresample.h
+++ b/libavresample/avresample.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -285,7 +285,7 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
*
* Examples:
*
- * Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to Libav order (L,R,C,LFE,Ls,Rs):
+ * Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to FFmpeg order (L,R,C,LFE,Ls,Rs):
* { 1, 2, 0, 5, 3, 4 }
*
* Muting the 3rd channel in 4-channel input:
diff --git a/libavresample/avresampleres.rc b/libavresample/avresampleres.rc
new file mode 100644
index 0000000000..e6d0d151e1
--- /dev/null
+++ b/libavresample/avresampleres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libavresample
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libavresample/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBAVRESAMPLE_VERSION_MAJOR, LIBAVRESAMPLE_VERSION_MINOR, LIBAVRESAMPLE_VERSION_MICRO, 0
+PRODUCTVERSION LIBAVRESAMPLE_VERSION_MAJOR, LIBAVRESAMPLE_VERSION_MINOR, LIBAVRESAMPLE_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "Libav audio resampling library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBAVRESAMPLE_VERSION)
+ VALUE "InternalName", "libavresample"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "avresample" BUILDSUF "-" AV_STRINGIFY(LIBAVRESAMPLE_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libavresample/dither.c b/libavresample/dither.c
index 17de8291ea..2ae8d338be 100644
--- a/libavresample/dither.c
+++ b/libavresample/dither.c
@@ -4,20 +4,20 @@
* Triangular with Noise Shaping is based on opusfile.
* Copyright (c) 1994-2012 by the Xiph.Org Foundation and contributors
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/dither.h b/libavresample/dither.h
index 8db37146fa..c53e822e4c 100644
--- a/libavresample/dither.h
+++ b/libavresample/dither.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/internal.h b/libavresample/internal.h
index b88b7587aa..2fc3f6da67 100644
--- a/libavresample/internal.h
+++ b/libavresample/internal.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/options.c b/libavresample/options.c
index 6249f90115..5f08cd7e52 100644
--- a/libavresample/options.c
+++ b/libavresample/options.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/resample.c b/libavresample/resample.c
index 86a761b5d0..01fc50014d 100644
--- a/libavresample/resample.c
+++ b/libavresample/resample.c
@@ -2,20 +2,20 @@
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/resample.h b/libavresample/resample.h
index 7e02cb1285..be9f562791 100644
--- a/libavresample/resample.h
+++ b/libavresample/resample.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/resample_template.c b/libavresample/resample_template.c
index d8ddcc988a..863852a3fd 100644
--- a/libavresample/resample_template.c
+++ b/libavresample/resample_template.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/utils.c b/libavresample/utils.c
index 172aadb6c9..e3185873d9 100644
--- a/libavresample/utils.c
+++ b/libavresample/utils.c
@@ -1,26 +1,26 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/dict.h"
-#include "libavutil/error.h"
+// #include "libavutil/error.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/mem.h"
@@ -783,10 +783,10 @@ unsigned avresample_version(void)
const char *avresample_license(void)
{
#define LICENSE_PREFIX "libavresample license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
}
const char *avresample_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
diff --git a/libavresample/version.h b/libavresample/version.h
index 34623a138c..33ff2a2afa 100644
--- a/libavresample/version.h
+++ b/libavresample/version.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/x86/audio_convert.asm b/libavresample/x86/audio_convert.asm
index 1af1429bae..3e21f268a7 100644
--- a/libavresample/x86/audio_convert.asm
+++ b/libavresample/x86/audio_convert.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2008 Loren Merritt
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -155,8 +155,10 @@ cglobal conv_s32_to_flt, 3,3,3, dst, src, len
INIT_XMM sse2
CONV_S32_TO_FLT
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
CONV_S32_TO_FLT
+%endif
;------------------------------------------------------------------------------
; void ff_conv_flt_to_s16(int16_t *dst, const float *src, int len);
@@ -226,8 +228,10 @@ cglobal conv_flt_to_s32, 3,3,6, dst, src, len
INIT_XMM sse2
CONV_FLT_TO_S32
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
CONV_FLT_TO_S32
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16p_to_s16_2ch(int16_t *dst, int16_t *const *src, int len,
@@ -261,8 +265,10 @@ cglobal conv_s16p_to_s16_2ch, 3,4,5, dst, src0, len, src1
INIT_XMM sse2
CONV_S16P_TO_S16_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16P_TO_S16_2CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16p_to_s16_6ch(int16_t *dst, int16_t *const *src, int len,
@@ -382,8 +388,10 @@ INIT_XMM sse2
CONV_S16P_TO_S16_6CH
INIT_XMM sse2slow
CONV_S16P_TO_S16_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16P_TO_S16_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16p_to_flt_2ch(float *dst, int16_t *const *src, int len,
@@ -429,8 +437,10 @@ cglobal conv_s16p_to_flt_2ch, 3,4,6, dst, src0, len, src1
INIT_XMM sse2
CONV_S16P_TO_FLT_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16P_TO_FLT_2CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16p_to_flt_6ch(float *dst, int16_t *const *src, int len,
@@ -531,8 +541,10 @@ INIT_XMM sse2
CONV_S16P_TO_FLT_6CH
INIT_XMM ssse3
CONV_S16P_TO_FLT_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16P_TO_FLT_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_fltp_to_s16_2ch(int16_t *dst, float *const *src, int len,
@@ -685,8 +697,10 @@ INIT_MMX sse
CONV_FLTP_TO_S16_6CH
INIT_XMM sse2
CONV_FLTP_TO_S16_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLTP_TO_S16_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_fltp_to_flt_2ch(float *dst, float *const *src, int len,
@@ -720,8 +734,10 @@ cglobal conv_fltp_to_flt_2ch, 3,4,5, dst, src0, len, src1
INIT_XMM sse
CONV_FLTP_TO_FLT_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLTP_TO_FLT_2CH
+%endif
;-----------------------------------------------------------------------------
; void ff_conv_fltp_to_flt_6ch(float *dst, float *const *src, int len,
@@ -799,8 +815,10 @@ INIT_MMX mmx
CONV_FLTP_TO_FLT_6CH
INIT_XMM sse4
CONV_FLTP_TO_FLT_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLTP_TO_FLT_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16_to_s16p_2ch(int16_t *const *dst, int16_t *src, int len,
@@ -846,8 +864,10 @@ INIT_XMM sse2
CONV_S16_TO_S16P_2CH
INIT_XMM ssse3
CONV_S16_TO_S16P_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16_TO_S16P_2CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16_to_s16p_6ch(int16_t *const *dst, int16_t *src, int len,
@@ -903,8 +923,10 @@ INIT_XMM sse2
CONV_S16_TO_S16P_6CH
INIT_XMM ssse3
CONV_S16_TO_S16P_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16_TO_S16P_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16_to_fltp_2ch(float *const *dst, int16_t *src, int len,
@@ -939,8 +961,10 @@ cglobal conv_s16_to_fltp_2ch, 3,4,5, dst0, src, len, dst1
INIT_XMM sse2
CONV_S16_TO_FLTP_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16_TO_FLTP_2CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_s16_to_fltp_6ch(float *const *dst, int16_t *src, int len,
@@ -1018,8 +1042,10 @@ INIT_XMM ssse3
CONV_S16_TO_FLTP_6CH
INIT_XMM sse4
CONV_S16_TO_FLTP_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_S16_TO_FLTP_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_flt_to_s16p_2ch(int16_t *const *dst, float *src, int len,
@@ -1062,8 +1088,10 @@ cglobal conv_flt_to_s16p_2ch, 3,4,6, dst0, src, len, dst1
INIT_XMM sse2
CONV_FLT_TO_S16P_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLT_TO_S16P_2CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_flt_to_s16p_6ch(int16_t *const *dst, float *src, int len,
@@ -1132,8 +1160,10 @@ INIT_XMM sse2
CONV_FLT_TO_S16P_6CH
INIT_XMM ssse3
CONV_FLT_TO_S16P_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLT_TO_S16P_6CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_flt_to_fltp_2ch(float *const *dst, float *src, int len,
@@ -1162,8 +1192,10 @@ cglobal conv_flt_to_fltp_2ch, 3,4,3, dst0, src, len, dst1
INIT_XMM sse
CONV_FLT_TO_FLTP_2CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLT_TO_FLTP_2CH
+%endif
;------------------------------------------------------------------------------
; void ff_conv_flt_to_fltp_6ch(float *const *dst, float *src, int len,
@@ -1223,5 +1255,7 @@ cglobal conv_flt_to_fltp_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5
INIT_XMM sse2
CONV_FLT_TO_FLTP_6CH
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
CONV_FLT_TO_FLTP_6CH
+%endif
diff --git a/libavresample/x86/audio_convert_init.c b/libavresample/x86/audio_convert_init.c
index d85ca8405f..d88ddac2e5 100644
--- a/libavresample/x86/audio_convert_init.c
+++ b/libavresample/x86/audio_convert_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/x86/audio_mix.asm b/libavresample/x86/audio_mix.asm
index 2c657b50d4..64ab0399f8 100644
--- a/libavresample/x86/audio_mix.asm
+++ b/libavresample/x86/audio_mix.asm
@@ -2,20 +2,20 @@
;* x86 optimized channel mixing
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -55,8 +55,10 @@ cglobal mix_2_to_1_fltp_flt, 3,4,6, src, matrix, len, src1
INIT_XMM sse
MIX_2_TO_1_FLTP_FLT
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
MIX_2_TO_1_FLTP_FLT
+%endif
;-----------------------------------------------------------------------------
; void ff_mix_2_to_1_s16p_flt(int16_t **src, float **matrix, int len,
@@ -172,8 +174,10 @@ cglobal mix_1_to_2_fltp_flt, 3,5,4, src0, matrix0, len, src1, matrix1
INIT_XMM sse
MIX_1_TO_2_FLTP_FLT
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
MIX_1_TO_2_FLTP_FLT
+%endif
;-----------------------------------------------------------------------------
; void ff_mix_1_to_2_s16p_flt(int16_t **src, float **matrix, int len,
@@ -217,8 +221,10 @@ INIT_XMM sse2
MIX_1_TO_2_S16P_FLT
INIT_XMM sse4
MIX_1_TO_2_S16P_FLT
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
MIX_1_TO_2_S16P_FLT
+%endif
;-----------------------------------------------------------------------------
; void ff_mix_3_8_to_1_2_fltp/s16p_flt(float/int16_t **src, float **matrix,
@@ -474,6 +480,7 @@ cglobal mix_%1_to_%2_%3_flt, 3,in_channels+2,needed_mmregs+matrix_elements_mm, n
MIX_3_8_TO_1_2_FLT %%i, 1, s16p
MIX_3_8_TO_1_2_FLT %%i, 2, s16p
; do not use ymm AVX or FMA4 in x86-32 for 6 or more channels due to stack alignment issues
+ %if HAVE_AVX_EXTERNAL
%if ARCH_X86_64 || %%i < 6
INIT_YMM avx
%else
@@ -484,6 +491,7 @@ cglobal mix_%1_to_%2_%3_flt, 3,in_channels+2,needed_mmregs+matrix_elements_mm, n
INIT_XMM avx
MIX_3_8_TO_1_2_FLT %%i, 1, s16p
MIX_3_8_TO_1_2_FLT %%i, 2, s16p
+ %endif
%if HAVE_FMA4_EXTERNAL
%if ARCH_X86_64 || %%i < 6
INIT_YMM fma4
diff --git a/libavresample/x86/audio_mix_init.c b/libavresample/x86/audio_mix_init.c
index 7fc530ebc4..2f05eee81a 100644
--- a/libavresample/x86/audio_mix_init.c
+++ b/libavresample/x86/audio_mix_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/x86/dither.asm b/libavresample/x86/dither.asm
index 2192e98eb4..757f2800bc 100644
--- a/libavresample/x86/dither.asm
+++ b/libavresample/x86/dither.asm
@@ -2,20 +2,20 @@
;* x86 optimized dithering format conversion
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavresample/x86/dither_init.c b/libavresample/x86/dither_init.c
index 8349d5efc8..816d4b05d0 100644
--- a/libavresample/x86/dither_init.c
+++ b/libavresample/x86/dither_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavresample/x86/util.asm b/libavresample/x86/util.asm
index 0ce953159c..187a4a21ba 100644
--- a/libavresample/x86/util.asm
+++ b/libavresample/x86/util.asm
@@ -2,20 +2,20 @@
;* x86 utility macros for libavresample
;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavresample/x86/w64xmmtest.c b/libavresample/x86/w64xmmtest.c
index 51a400e0d1..0f42bd185c 100644
--- a/libavresample/x86/w64xmmtest.c
+++ b/libavresample/x86/w64xmmtest.c
@@ -2,20 +2,20 @@
* check XMM registers for clobbers on Win64
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 0f8ed08d61..df85cd1a79 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -1,3 +1,5 @@
+include $(SUBDIR)../config.mak
+
NAME = avutil
HEADERS = adler32.h \
@@ -10,8 +12,11 @@ HEADERS = adler32.h \
avutil.h \
base64.h \
blowfish.h \
+ bprint.h \
bswap.h \
buffer.h \
+ cast5.h \
+ camellia.h \
channel_layout.h \
common.h \
cpu.h \
@@ -23,6 +28,7 @@ HEADERS = adler32.h \
fifo.h \
file.h \
frame.h \
+ hash.h \
hmac.h \
imgutils.h \
intfloat.h \
@@ -33,30 +39,42 @@ HEADERS = adler32.h \
mathematics.h \
md5.h \
mem.h \
+ motion_vector.h \
+ murmur3.h \
dict.h \
old_pix_fmts.h \
opt.h \
parseutils.h \
pixdesc.h \
+ pixelutils.h \
pixfmt.h \
random_seed.h \
replaygain.h \
rational.h \
+ ripemd.h \
samplefmt.h \
sha.h \
+ sha512.h \
stereo3d.h \
+ threadmessage.h \
time.h \
+ timecode.h \
+ timestamp.h \
+ twofish.h \
version.h \
xtea.h \
HEADERS-$(CONFIG_LZO) += lzo.h
+HEADERS-$(CONFIG_OPENCL) += opencl.h
+
ARCH_HEADERS = bswap.h \
intmath.h \
intreadwrite.h \
timer.h \
-BUILT_HEADERS = avconfig.h
+BUILT_HEADERS = avconfig.h \
+ ffversion.h
OBJS = adler32.o \
aes.o \
@@ -65,8 +83,12 @@ OBJS = adler32.o \
avstring.o \
base64.o \
blowfish.o \
+ bprint.o \
buffer.o \
+ cast5.o \
+ camellia.o \
channel_layout.o \
+ color_utils.o \
cpu.o \
crc.o \
des.o \
@@ -78,7 +100,9 @@ OBJS = adler32.o \
file.o \
file_open.o \
float_dsp.o \
+ fixed_dsp.o \
frame.o \
+ hash.o \
hmac.o \
imgutils.o \
intmath.o \
@@ -89,30 +113,43 @@ OBJS = adler32.o \
mathematics.o \
md5.o \
mem.o \
+ murmur3.o \
dict.o \
opt.o \
parseutils.o \
pixdesc.o \
+ pixelutils.o \
random_seed.o \
rational.o \
rc4.o \
+ ripemd.o \
samplefmt.o \
sha.o \
+ sha512.o \
stereo3d.o \
+ threadmessage.o \
time.o \
+ timecode.o \
tree.o \
+ twofish.o \
utils.o \
+ xga_font_data.o \
xtea.o \
OBJS-$(CONFIG_LZO) += lzo.o
+OBJS-$(CONFIG_OPENCL) += opencl.o opencl_internal.o
OBJS += $(COMPAT_OBJS:%=../compat/%)
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o
+
SKIPHEADERS = old_pix_fmts.h
SKIPHEADERS-$(HAVE_ATOMICS_GCC) += atomic_gcc.h
SKIPHEADERS-$(HAVE_ATOMICS_SUNCC) += atomic_suncc.h
SKIPHEADERS-$(HAVE_ATOMICS_WIN32) += atomic_win32.h
+SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h
TESTPROGS = adler32 \
aes \
@@ -120,18 +157,45 @@ TESTPROGS = adler32 \
avstring \
base64 \
blowfish \
+ bprint \
+ cast5 \
+ camellia \
cpu \
crc \
des \
+ dict \
+ error \
eval \
+ file \
fifo \
float_dsp \
hmac \
lfg \
lls \
+ log \
md5 \
+ murmur3 \
opt \
+ pca \
parseutils \
+ pixdesc \
+ pixelutils \
+ random_seed \
+ rational \
+ ripemd \
sha \
+ sha512 \
+ softfloat \
tree \
+ twofish \
+ utf8 \
xtea \
+
+TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo
+
+TOOLS = crypto_bench ffhash ffeval ffescape
+
+tools/crypto_bench$(EXESUF): ELIBS += $(if $(VERSUS),$(subst +, -l,+$(VERSUS)),)
+tools/crypto_bench$(EXESUF): CFLAGS += -DUSE_EXT_LIBS=0$(if $(VERSUS),$(subst +,+USE_,+$(VERSUS)),)
+
+$(SUBDIR)lzo-test$(EXESUF): ELIBS = -llzo2
diff --git a/libavutil/aarch64/asm.S b/libavutil/aarch64/asm.S
index 6a7f506d13..ff34e7a5e5 100644
--- a/libavutil/aarch64/asm.S
+++ b/libavutil/aarch64/asm.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aarch64/bswap.h b/libavutil/aarch64/bswap.h
index 0c001cec19..1e735c52cf 100644
--- a/libavutil/aarch64/bswap.h
+++ b/libavutil/aarch64/bswap.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aarch64/cpu.c b/libavutil/aarch64/cpu.c
index 37a7d8defa..8ef077aaea 100644
--- a/libavutil/aarch64/cpu.c
+++ b/libavutil/aarch64/cpu.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aarch64/cpu.h b/libavutil/aarch64/cpu.h
index f5b1d89132..cf1b9cc516 100644
--- a/libavutil/aarch64/cpu.h
+++ b/libavutil/aarch64/cpu.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aarch64/float_dsp_init.c b/libavutil/aarch64/float_dsp_init.c
index 37d34c96d0..4325071821 100644
--- a/libavutil/aarch64/float_dsp_init.c
+++ b/libavutil/aarch64/float_dsp_init.c
@@ -2,20 +2,20 @@
* ARM NEON optimised Float DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aarch64/float_dsp_neon.S b/libavutil/aarch64/float_dsp_neon.S
index 776542c4a9..02d790c0cc 100644
--- a/libavutil/aarch64/float_dsp_neon.S
+++ b/libavutil/aarch64/float_dsp_neon.S
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
* Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aarch64/neontest.h b/libavutil/aarch64/neontest.h
index de841bbbae..b9d4986072 100644
--- a/libavutil/aarch64/neontest.h
+++ b/libavutil/aarch64/neontest.h
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Ramiro Polla <ramiro.polla@gmail.com>
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/adler32.c b/libavutil/adler32.c
index 8a8065c4a3..579d022978 100644
--- a/libavutil/adler32.c
+++ b/libavutil/adler32.c
@@ -32,6 +32,8 @@
#include "config.h"
#include "adler32.h"
+#include "common.h"
+#include "intreadwrite.h"
#define BASE 65521L /* largest prime smaller than 65536 */
@@ -46,16 +48,46 @@ unsigned long av_adler32_update(unsigned long adler, const uint8_t * buf,
unsigned long s2 = adler >> 16;
while (len > 0) {
-#if CONFIG_SMALL
+#if HAVE_FAST_64BIT && HAVE_FAST_UNALIGNED && !CONFIG_SMALL
+ unsigned len2 = FFMIN((len-1) & ~7, 23*8);
+ if (len2) {
+ uint64_t a1= 0;
+ uint64_t a2= 0;
+ uint64_t b1= 0;
+ uint64_t b2= 0;
+ len -= len2;
+ s2 += s1*len2;
+ while (len2 >= 8) {
+ uint64_t v = AV_RN64(buf);
+ a2 += a1;
+ b2 += b1;
+ a1 += v &0x00FF00FF00FF00FF;
+ b1 += (v>>8)&0x00FF00FF00FF00FF;
+ len2 -= 8;
+ buf+=8;
+ }
+
+ //We combine the 8 interleaved adler32 checksums without overflows
+ //Decreasing the number of iterations would allow below code to be
+ //simplified but would likely be slower due to the fewer iterations
+ //of the inner loop
+ s1 += ((a1+b1)*0x1000100010001)>>48;
+ s2 += ((((a2&0xFFFF0000FFFF)+(b2&0xFFFF0000FFFF)+((a2>>16)&0xFFFF0000FFFF)+((b2>>16)&0xFFFF0000FFFF))*0x800000008)>>32)
+#if HAVE_BIGENDIAN
+ + 2*((b1*0x1000200030004)>>48)
+ + ((a1*0x1000100010001)>>48)
+ + 2*((a1*0x0000100020003)>>48);
+#else
+ + 2*((a1*0x4000300020001)>>48)
+ + ((b1*0x1000100010001)>>48)
+ + 2*((b1*0x3000200010000)>>48);
+#endif
+ }
+#else
while (len > 4 && s2 < (1U << 31)) {
DO4(buf);
len -= 4;
}
-#else
- while (len > 16 && s2 < (1U << 31)) {
- DO16(buf);
- len -= 16;
- }
#endif
DO1(buf); len--;
s1 %= BASE;
@@ -65,6 +97,7 @@ unsigned long av_adler32_update(unsigned long adler, const uint8_t * buf,
}
#ifdef TEST
+// LCOV_EXCL_START
#include <string.h>
#include "log.h"
#include "timer.h"
@@ -95,4 +128,5 @@ int main(int argc, char **argv)
av_log(NULL, AV_LOG_DEBUG, "%X (expected 50E6E508)\n", checksum);
return checksum == 0x50e6e508 ? 0 : 1;
}
+// LCOV_EXCL_STOP
#endif
diff --git a/libavutil/adler32.h b/libavutil/adler32.h
index 53e3dbf51d..0dc69ec0a8 100644
--- a/libavutil/adler32.h
+++ b/libavutil/adler32.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/aes.c b/libavutil/aes.c
index 3ba5e9aef4..fd8706089c 100644
--- a/libavutil/aes.c
+++ b/libavutil/aes.c
@@ -3,20 +3,20 @@
*
* some optimization ideas from aes128.c by Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,9 +40,7 @@ typedef struct AVAES {
int rounds;
} AVAES;
-#if FF_API_CONTEXT_SIZE
const int av_aes_size= sizeof(AVAES);
-#endif
struct AVAES *av_aes_alloc(void)
{
@@ -64,9 +62,9 @@ static uint32_t dec_multbl[4][256];
#endif
#if HAVE_BIGENDIAN
-# define ROT(x, s) ((x >> s) | (x << (32-s)))
+# define ROT(x, s) (((x) >> (s)) | ((x) << (32-(s))))
#else
-# define ROT(x, s) ((x << s) | (x >> (32-s)))
+# define ROT(x, s) (((x) << (s)) | ((x) >> (32-(s))))
#endif
static inline void addkey(av_aes_block *dst, const av_aes_block *src,
@@ -129,7 +127,7 @@ static inline void mix(av_aes_block state[2], uint32_t multbl[][256], int s1, in
state[0].u32[3] = mix_core(multbl, src[3][0], src[s1-1][1], src[1][2], src[s3-1][3]);
}
-static inline void crypt(AVAES *a, int s, const uint8_t *sbox,
+static inline void aes_crypt(AVAES *a, int s, const uint8_t *sbox,
uint32_t multbl[][256])
{
int r;
@@ -148,7 +146,7 @@ void av_aes_crypt(AVAES *a, uint8_t *dst, const uint8_t *src,
while (count--) {
addkey_s(&a->state[1], src, &a->round_key[a->rounds]);
if (decrypt) {
- crypt(a, 0, inv_sbox, dec_multbl);
+ aes_crypt(a, 0, inv_sbox, dec_multbl);
if (iv) {
addkey_s(&a->state[0], iv, &a->state[0]);
memcpy(iv, src, 16);
@@ -157,7 +155,7 @@ void av_aes_crypt(AVAES *a, uint8_t *dst, const uint8_t *src,
} else {
if (iv)
addkey_s(&a->state[1], iv, &a->state[1]);
- crypt(a, 2, sbox, enc_multbl);
+ aes_crypt(a, 2, sbox, enc_multbl);
addkey_d(dst, &a->state[0], &a->round_key[0]);
if (iv)
memcpy(iv, dst, 16);
@@ -267,6 +265,7 @@ int av_aes_init(AVAES *a, const uint8_t *key, int key_bits, int decrypt)
}
#ifdef TEST
+// LCOV_EXCL_START
#include <string.h>
#include "lfg.h"
#include "log.h"
@@ -339,4 +338,5 @@ int main(int argc, char **argv)
}
return err;
}
+// LCOV_EXCL_STOP
#endif
diff --git a/libavutil/aes.h b/libavutil/aes.h
index edff275b7a..09efbda107 100644
--- a/libavutil/aes.h
+++ b/libavutil/aes.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2007 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,9 +32,7 @@
* @{
*/
-#if FF_API_CONTEXT_SIZE
-extern attribute_deprecated const int av_aes_size;
-#endif
+extern const int av_aes_size;
struct AVAES;
diff --git a/libavutil/arm/asm.S b/libavutil/arm/asm.S
index 943c1cea3f..e9b0bcabdb 100644
--- a/libavutil/arm/asm.S
+++ b/libavutil/arm/asm.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/bswap.h b/libavutil/arm/bswap.h
index 8bc7d9a8f7..ae5fdb7eb8 100644
--- a/libavutil/arm/bswap.h
+++ b/libavutil/arm/bswap.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/cpu.c b/libavutil/arm/cpu.c
index 8bdaa88469..f1683e8d76 100644
--- a/libavutil/arm/cpu.c
+++ b/libavutil/arm/cpu.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -128,6 +128,12 @@ int ff_get_cpu_flags_arm(void)
trickle down. */
if (flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON))
flags |= AV_CPU_FLAG_ARMV6T2;
+ else
+ /* Some functions use the 'setend' instruction which is deprecated on ARMv8
+ * and serializing on some ARMv7 cores. This ensures such functions
+ * are only enabled on ARMv6. */
+ flags |= AV_CPU_FLAG_SETEND;
+
if (flags & AV_CPU_FLAG_ARMV6T2)
flags |= AV_CPU_FLAG_ARMV6;
@@ -143,7 +149,8 @@ int ff_get_cpu_flags_arm(void)
AV_CPU_FLAG_ARMV6T2 * HAVE_ARMV6T2 |
AV_CPU_FLAG_VFP * HAVE_VFP |
AV_CPU_FLAG_VFPV3 * HAVE_VFPV3 |
- AV_CPU_FLAG_NEON * HAVE_NEON;
+ AV_CPU_FLAG_NEON * HAVE_NEON |
+ AV_CPU_FLAG_SETEND * !(HAVE_NEON | HAVE_VFPV3);
}
#endif
diff --git a/libavutil/arm/cpu.h b/libavutil/arm/cpu.h
index 224409afee..9b3b6ff58b 100644
--- a/libavutil/arm/cpu.h
+++ b/libavutil/arm/cpu.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,11 +29,6 @@
#define have_vfp(flags) CPUEXT(flags, VFP)
#define have_vfpv3(flags) CPUEXT(flags, VFPV3)
#define have_neon(flags) CPUEXT(flags, NEON)
-
-/* Some functions use the 'setend' instruction which is deprecated on ARMv8
- * and serializing on some ARMv7 cores. This macro ensures such functions
- * are only enabled on ARMv6. */
-#define have_setend(flags) \
- (have_armv6(flags) && !(have_vfpv3(flags) || have_neon(flags)))
+#define have_setend(flags) CPUEXT(flags, SETEND)
#endif /* AVUTIL_ARM_CPU_H */
diff --git a/libavutil/arm/float_dsp_arm.h b/libavutil/arm/float_dsp_arm.h
index ec925ecf5c..fe311cc0d2 100644
--- a/libavutil/arm/float_dsp_arm.h
+++ b/libavutil/arm/float_dsp_arm.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/float_dsp_init_arm.c b/libavutil/arm/float_dsp_init_arm.c
index ff0105c5c9..678762862e 100644
--- a/libavutil/arm/float_dsp_init_arm.c
+++ b/libavutil/arm/float_dsp_init_arm.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/float_dsp_init_neon.c b/libavutil/arm/float_dsp_init_neon.c
index 617bf5d576..689aa77c7b 100644
--- a/libavutil/arm/float_dsp_init_neon.c
+++ b/libavutil/arm/float_dsp_init_neon.c
@@ -2,20 +2,20 @@
* ARM NEON optimised Float DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/float_dsp_init_vfp.c b/libavutil/arm/float_dsp_init_vfp.c
index 61ff2ed38e..e15abf3f54 100644
--- a/libavutil/arm/float_dsp_init_vfp.c
+++ b/libavutil/arm/float_dsp_init_vfp.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Siarhei Siamashka <ssvb@users.sourceforge.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,7 +32,7 @@ void ff_vector_fmul_window_vfp(float *dst, const float *src0,
void ff_vector_fmul_reverse_vfp(float *dst, const float *src0,
const float *src1, int len);
-void ff_butterflies_float_vfp(float *restrict v1, float *restrict v2, int len);
+void ff_butterflies_float_vfp(float *av_restrict v1, float *av_restrict v2, int len);
av_cold void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags)
{
diff --git a/libavutil/arm/float_dsp_neon.S b/libavutil/arm/float_dsp_neon.S
index 559b565628..3823227608 100644
--- a/libavutil/arm/float_dsp_neon.S
+++ b/libavutil/arm/float_dsp_neon.S
@@ -2,20 +2,20 @@
* ARM NEON optimised Float DSP functions
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/float_dsp_vfp.S b/libavutil/arm/float_dsp_vfp.S
index 9f920aae70..7db2452284 100644
--- a/libavutil/arm/float_dsp_vfp.S
+++ b/libavutil/arm/float_dsp_vfp.S
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Siarhei Siamashka <ssvb@users.sourceforge.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/intmath.h b/libavutil/arm/intmath.h
index 2b15ba0593..3216af003a 100644
--- a/libavutil/arm/intmath.h
+++ b/libavutil/arm/intmath.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/intreadwrite.h b/libavutil/arm/intreadwrite.h
index 6eff7332fb..2340a9a935 100644
--- a/libavutil/arm/intreadwrite.h
+++ b/libavutil/arm/intreadwrite.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/neontest.h b/libavutil/arm/neontest.h
index eb46df8e0b..f668c00733 100644
--- a/libavutil/arm/neontest.h
+++ b/libavutil/arm/neontest.h
@@ -3,20 +3,20 @@
* Copyright (c) 2008 Ramiro Polla <ramiro.polla@gmail.com>
* Copyright (c) 2013 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/arm/timer.h b/libavutil/arm/timer.h
index 4bca877d00..5e8bc8edd0 100644
--- a/libavutil/arm/timer.h
+++ b/libavutil/arm/timer.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/atomic.c b/libavutil/atomic.c
index 83740396d4..b13725d14f 100644
--- a/libavutil/atomic.c
+++ b/libavutil/atomic.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -64,7 +64,7 @@ void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
void *ret;
pthread_mutex_lock(&atomic_lock);
ret = *ptr;
- if (*ptr == oldval)
+ if (ret == oldval)
*ptr = newval;
pthread_mutex_unlock(&atomic_lock);
return ret;
@@ -109,7 +109,7 @@ void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval)
#endif /* !HAVE_ATOMICS_NATIVE */
#ifdef TEST
-#include <assert.h>
+#include "avassert.h"
int main(void)
{
@@ -117,10 +117,10 @@ int main(void)
int res;
res = avpriv_atomic_int_add_and_fetch(&val, 1);
- assert(res == 2);
+ av_assert0(res == 2);
avpriv_atomic_int_set(&val, 3);
res = avpriv_atomic_int_get(&val);
- assert(res == 3);
+ av_assert0(res == 3);
return 0;
}
diff --git a/libavutil/atomic.h b/libavutil/atomic.h
index 57a0c19fcb..15906d24c9 100644
--- a/libavutil/atomic.h
+++ b/libavutil/atomic.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/atomic_gcc.h b/libavutil/atomic_gcc.h
index 9470e8e50b..5f9fc49ba0 100644
--- a/libavutil/atomic_gcc.h
+++ b/libavutil/atomic_gcc.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,27 +28,40 @@
#define avpriv_atomic_int_get atomic_int_get_gcc
static inline int atomic_int_get_gcc(volatile int *ptr)
{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+ return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
+#else
__sync_synchronize();
return *ptr;
+#endif
}
#define avpriv_atomic_int_set atomic_int_set_gcc
static inline void atomic_int_set_gcc(volatile int *ptr, int val)
{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+ __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
+#else
*ptr = val;
__sync_synchronize();
+#endif
}
#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_gcc
static inline int atomic_int_add_and_fetch_gcc(volatile int *ptr, int inc)
{
+#if HAVE_ATOMIC_COMPARE_EXCHANGE
+ return __atomic_add_fetch(ptr, inc, __ATOMIC_SEQ_CST);
+#else
return __sync_add_and_fetch(ptr, inc);
+#endif
}
#define avpriv_atomic_ptr_cas atomic_ptr_cas_gcc
static inline void *atomic_ptr_cas_gcc(void * volatile *ptr,
void *oldval, void *newval)
{
+#if HAVE_SYNC_VAL_COMPARE_AND_SWAP
#ifdef __ARMCC_VERSION
// armcc will throw an error if ptr is not an integer type
volatile uintptr_t *tmp = (volatile uintptr_t*)ptr;
@@ -56,6 +69,10 @@ static inline void *atomic_ptr_cas_gcc(void * volatile *ptr,
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
+#else
+ __atomic_compare_exchange_n(ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ return oldval;
+#endif
}
#endif /* AVUTIL_ATOMIC_GCC_H */
diff --git a/libavutil/atomic_suncc.h b/libavutil/atomic_suncc.h
index 5c11b5704a..3cad24a051 100644
--- a/libavutil/atomic_suncc.h
+++ b/libavutil/atomic_suncc.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/atomic_win32.h b/libavutil/atomic_win32.h
index 00c66cfc1d..f7299336f6 100644
--- a/libavutil/atomic_win32.h
+++ b/libavutil/atomic_win32.h
@@ -1,26 +1,27 @@
/*
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_ATOMIC_WIN32_H
#define AVUTIL_ATOMIC_WIN32_H
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define avpriv_atomic_int_get atomic_int_get_win32
diff --git a/libavutil/attributes.h b/libavutil/attributes.h
index d7f2bb5c6f..ebcdd6b88c 100644
--- a/libavutil/attributes.h
+++ b/libavutil/attributes.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,11 +27,12 @@
#define AVUTIL_ATTRIBUTES_H
#ifdef __GNUC__
-# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > x || __GNUC__ == x && __GNUC_MINOR__ >= y)
+# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else
# define AV_GCC_VERSION_AT_LEAST(x,y) 0
#endif
+#ifndef av_always_inline
#if AV_GCC_VERSION_AT_LEAST(3,1)
# define av_always_inline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
@@ -39,6 +40,15 @@
#else
# define av_always_inline inline
#endif
+#endif
+
+#ifndef av_extern_inline
+#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__)
+# define av_extern_inline extern inline
+#else
+# define av_extern_inline inline
+#endif
+#endif
#if AV_GCC_VERSION_AT_LEAST(3,1)
# define av_noinline __attribute__((noinline))
@@ -80,6 +90,30 @@
# define attribute_deprecated
#endif
+/**
+ * Disable warnings about deprecated features
+ * This is useful for sections of code kept for backward compatibility and
+ * scheduled for removal.
+ */
+#ifndef AV_NOWARN_DEPRECATED
+#if AV_GCC_VERSION_AT_LEAST(4,6)
+# define AV_NOWARN_DEPRECATED(code) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
+ code \
+ _Pragma("GCC diagnostic pop")
+#elif defined(_MSC_VER)
+# define AV_NOWARN_DEPRECATED(code) \
+ __pragma(warning(push)) \
+ __pragma(warning(disable : 4996)) \
+ code; \
+ __pragma(warning(pop))
+#else
+# define AV_NOWARN_DEPRECATED(code) code
+#endif
+#endif
+
+
#if defined(__GNUC__)
# define av_unused __attribute__((unused))
#else
@@ -103,7 +137,7 @@
# define av_alias
#endif
-#if defined(__GNUC__) && !defined(__ICC)
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__)
# define av_uninit(x) x=x
#else
# define av_uninit(x) x
diff --git a/libavutil/audio_fifo.c b/libavutil/audio_fifo.c
index b562537cf6..574907aa32 100644
--- a/libavutil/audio_fifo.c
+++ b/libavutil/audio_fifo.c
@@ -2,20 +2,20 @@
* Audio FIFO
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,7 +51,7 @@ void av_audio_fifo_free(AVAudioFifo *af)
if (af->buf[i])
av_fifo_free(af->buf[i]);
}
- av_free(af->buf);
+ av_freep(&af->buf);
}
av_free(af);
}
@@ -76,7 +76,7 @@ AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels,
af->sample_size = buf_size / nb_samples;
af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1;
- af->buf = av_mallocz(af->nb_buffers * sizeof(*af->buf));
+ af->buf = av_mallocz_array(af->nb_buffers, sizeof(*af->buf));
if (!af->buf)
goto error;
diff --git a/libavutil/audio_fifo.h b/libavutil/audio_fifo.h
index e73123d864..d21e6a1318 100644
--- a/libavutil/audio_fifo.h
+++ b/libavutil/audio_fifo.h
@@ -2,20 +2,20 @@
* Audio FIFO
* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -88,7 +88,8 @@ int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples);
* @param data audio data plane pointers
* @param nb_samples number of samples to write
* @return number of samples actually written, or negative AVERROR
- * code on failure.
+ * code on failure. If successful, the number of samples
+ * actually written will always be nb_samples.
*/
int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples);
@@ -102,7 +103,9 @@ int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples);
* @param data audio data plane pointers
* @param nb_samples number of samples to read
* @return number of samples actually read, or negative AVERROR code
- * on failure.
+ * on failure. The number of samples actually read will not
+ * be greater than nb_samples, and will only be less than
+ * nb_samples if av_audio_fifo_size is less than nb_samples.
*/
int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples);
diff --git a/libavutil/avassert.h b/libavutil/avassert.h
index b223d26e8d..41f5e0eea7 100644
--- a/libavutil/avassert.h
+++ b/libavutil/avassert.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2010 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,7 +36,7 @@
*/
#define av_assert0(cond) do { \
if (!(cond)) { \
- av_log(NULL, AV_LOG_FATAL, "Assertion %s failed at %s:%d\n", \
+ av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \
AV_STRINGIFY(cond), __FILE__, __LINE__); \
abort(); \
} \
diff --git a/libavutil/avr32/bswap.h b/libavutil/avr32/bswap.h
index 857f024054..e79d53f369 100644
--- a/libavutil/avr32/bswap.h
+++ b/libavutil/avr32/bswap.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/avr32/intreadwrite.h b/libavutil/avr32/intreadwrite.h
index e0049feb09..c6fd3aa470 100644
--- a/libavutil/avr32/intreadwrite.h
+++ b/libavutil/avr32/intreadwrite.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/avstring.c b/libavutil/avstring.c
index eb5c95a01c..f785816063 100644
--- a/libavutil/avstring.c
+++ b/libavutil/avstring.c
@@ -2,20 +2,20 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2007 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,7 +27,9 @@
#include "config.h"
#include "common.h"
#include "mem.h"
+#include "avassert.h"
#include "avstring.h"
+#include "bprint.h"
int av_strstart(const char *str, const char *pfx, const char **ptr)
{
@@ -54,11 +56,11 @@ int av_stristart(const char *str, const char *pfx, const char **ptr)
char *av_stristr(const char *s1, const char *s2)
{
if (!*s2)
- return s1;
+ return (char*)(intptr_t)s1;
do
if (av_stristart(s1, s2, NULL))
- return s1;
+ return (char*)(intptr_t)s1;
while (*s1++);
return NULL;
@@ -68,11 +70,11 @@ char *av_strnstr(const char *haystack, const char *needle, size_t hay_length)
{
size_t needle_len = strlen(needle);
if (!needle_len)
- return haystack;
+ return (char*)haystack;
while (hay_length >= needle_len) {
hay_length--;
if (!memcmp(haystack, needle, needle_len))
- return haystack;
+ return (char*)haystack;
haystack++;
}
return NULL;
@@ -98,7 +100,7 @@ size_t av_strlcat(char *dst, const char *src, size_t size)
size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...)
{
- int len = strlen(dst);
+ size_t len = strlen(dst);
va_list vl;
va_start(vl, fmt);
@@ -108,6 +110,32 @@ size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...)
return len;
}
+char *av_asprintf(const char *fmt, ...)
+{
+ char *p = NULL;
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = vsnprintf(NULL, 0, fmt, va);
+ va_end(va);
+ if (len < 0)
+ goto end;
+
+ p = av_malloc(len + 1);
+ if (!p)
+ goto end;
+
+ va_start(va, fmt);
+ len = vsnprintf(p, len + 1, fmt, va);
+ va_end(va);
+ if (len < 0)
+ av_freep(&p);
+
+end:
+ return p;
+}
+
char *av_d2str(double d)
{
char *str = av_malloc(16);
@@ -153,6 +181,35 @@ char *av_get_token(const char **buf, const char *term)
return ret;
}
+char *av_strtok(char *s, const char *delim, char **saveptr)
+{
+ char *tok;
+
+ if (!s && !(s = *saveptr))
+ return NULL;
+
+ /* skip leading delimiters */
+ s += strspn(s, delim);
+
+ /* s now points to the first non delimiter char, or to the end of the string */
+ if (!*s) {
+ *saveptr = NULL;
+ return NULL;
+ }
+ tok = s++;
+
+ /* skip non delimiters */
+ s += strcspn(s, delim);
+ if (*s) {
+ *s = 0;
+ *saveptr = s+1;
+ } else {
+ *saveptr = NULL;
+ }
+
+ return tok;
+}
+
int av_strcasecmp(const char *a, const char *b)
{
uint8_t c1, c2;
@@ -212,6 +269,54 @@ const char *av_dirname(char *path)
return path;
}
+char *av_append_path_component(const char *path, const char *component)
+{
+ size_t p_len, c_len;
+ char *fullpath;
+
+ if (!path)
+ return av_strdup(component);
+ if (!component)
+ return av_strdup(path);
+
+ p_len = strlen(path);
+ c_len = strlen(component);
+ if (p_len > SIZE_MAX - c_len || p_len + c_len > SIZE_MAX - 2)
+ return NULL;
+ fullpath = av_malloc(p_len + c_len + 2);
+ if (fullpath) {
+ if (p_len) {
+ av_strlcpy(fullpath, path, p_len + 1);
+ if (c_len) {
+ if (fullpath[p_len - 1] != '/' && component[0] != '/')
+ fullpath[p_len++] = '/';
+ else if (fullpath[p_len - 1] == '/' && component[0] == '/')
+ p_len--;
+ }
+ }
+ av_strlcpy(&fullpath[p_len], component, c_len + 1);
+ fullpath[p_len + c_len] = 0;
+ }
+ return fullpath;
+}
+
+int av_escape(char **dst, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags)
+{
+ AVBPrint dstbuf;
+
+ av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprint_escape(&dstbuf, src, special_chars, mode, flags);
+
+ if (!av_bprint_is_complete(&dstbuf)) {
+ av_bprint_finalize(&dstbuf, NULL);
+ return AVERROR(ENOMEM);
+ } else {
+ av_bprint_finalize(&dstbuf, dst);
+ return dstbuf.len;
+ }
+}
+
int av_isdigit(int c)
{
return c >= '0' && c <= '9';
@@ -252,14 +357,109 @@ int av_match_name(const char *name, const char *names)
return !av_strcasecmp(name, names);
}
+int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end,
+ unsigned int flags)
+{
+ const uint8_t *p = *bufp;
+ uint32_t top;
+ uint64_t code;
+ int ret = 0, tail_len;
+ uint32_t overlong_encoding_mins[6] = {
+ 0x00000000, 0x00000080, 0x00000800, 0x00010000, 0x00200000, 0x04000000,
+ };
+ if (p >= buf_end)
+ return 0;
+
+ code = *p++;
+
+ /* first sequence byte starts with 10, or is 1111-1110 or 1111-1111,
+ which is not admitted */
+ if ((code & 0xc0) == 0x80 || code >= 0xFE) {
+ ret = AVERROR(EILSEQ);
+ goto end;
+ }
+ top = (code & 128) >> 1;
+
+ tail_len = 0;
+ while (code & top) {
+ int tmp;
+ tail_len++;
+ if (p >= buf_end) {
+ (*bufp) ++;
+ return AVERROR(EILSEQ); /* incomplete sequence */
+ }
+
+ /* we assume the byte to be in the form 10xx-xxxx */
+ tmp = *p++ - 128; /* strip leading 1 */
+ if (tmp>>6) {
+ (*bufp) ++;
+ return AVERROR(EILSEQ);
+ }
+ code = (code<<6) + tmp;
+ top <<= 5;
+ }
+ code &= (top << 1) - 1;
+
+ /* check for overlong encodings */
+ av_assert0(tail_len <= 5);
+ if (code < overlong_encoding_mins[tail_len]) {
+ ret = AVERROR(EILSEQ);
+ goto end;
+ }
+
+ if (code >= 1<<31) {
+ ret = AVERROR(EILSEQ); /* out-of-range value */
+ goto end;
+ }
+
+ *codep = code;
+
+ if (code > 0x10FFFF &&
+ !(flags & AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES))
+ ret = AVERROR(EILSEQ);
+ if (code < 0x20 && code != 0x9 && code != 0xA && code != 0xD &&
+ flags & AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES)
+ ret = AVERROR(EILSEQ);
+ if (code >= 0xD800 && code <= 0xDFFF &&
+ !(flags & AV_UTF8_FLAG_ACCEPT_SURROGATES))
+ ret = AVERROR(EILSEQ);
+ if ((code == 0xFFFE || code == 0xFFFF) &&
+ !(flags & AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS))
+ ret = AVERROR(EILSEQ);
+
+end:
+ *bufp = p;
+ return ret;
+}
+
+int av_match_list(const char *name, const char *list, char separator)
+{
+ const char *p, *q;
+
+ for (p = name; p && *p; ) {
+ for (q = list; q && *q; ) {
+ int k;
+ for (k = 0; p[k] == q[k] || (p[k]*q[k] == 0 && p[k]+q[k] == separator); k++)
+ if (k && (!p[k] || p[k] == separator))
+ return 1;
+ q = strchr(q, separator);
+ q += !!q;
+ }
+ p = strchr(p, separator);
+ p += !!p;
+ }
+
+ return 0;
+}
#ifdef TEST
int main(void)
{
int i;
- const char *strings[] = {
+ char *fullpath;
+ static const char * const strings[] = {
"''",
"",
":",
@@ -299,6 +499,19 @@ int main(void)
av_free(q);
}
+ printf("Testing av_append_path_component()\n");
+ #define TEST_APPEND_PATH_COMPONENT(path, component, expected) \
+ fullpath = av_append_path_component((path), (component)); \
+ printf("%s = %s\n", fullpath, expected); \
+ av_free(fullpath);
+ TEST_APPEND_PATH_COMPONENT(NULL, NULL, "(null)")
+ TEST_APPEND_PATH_COMPONENT("path", NULL, "path");
+ TEST_APPEND_PATH_COMPONENT(NULL, "comp", "comp");
+ TEST_APPEND_PATH_COMPONENT("path", "comp", "path/comp");
+ TEST_APPEND_PATH_COMPONENT("path/", "comp", "path/comp");
+ TEST_APPEND_PATH_COMPONENT("path", "/comp", "path/comp");
+ TEST_APPEND_PATH_COMPONENT("path/", "/comp", "path/comp");
+ TEST_APPEND_PATH_COMPONENT("path/path2/", "/comp/comp2", "path/path2/comp/comp2");
return 0;
}
diff --git a/libavutil/avstring.h b/libavutil/avstring.h
index 7c30ee18c6..466edaf968 100644
--- a/libavutil/avstring.h
+++ b/libavutil/avstring.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,6 +22,7 @@
#define AVUTIL_AVSTRING_H
#include <stddef.h>
+#include <stdint.h>
#include "attributes.h"
/**
@@ -131,6 +132,30 @@ size_t av_strlcat(char *dst, const char *src, size_t size);
size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4);
/**
+ * Get the count of continuous non zero chars starting from the beginning.
+ *
+ * @param len maximum number of characters to check in the string, that
+ * is the maximum value which is returned by the function
+ */
+static inline size_t av_strnlen(const char *s, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len && s[i]; i++)
+ ;
+ return i;
+}
+
+/**
+ * Print arguments following specified format into a large enough auto
+ * allocated buffer. It is similar to GNU asprintf().
+ * @param fmt printf-compatible format string, specifying how the
+ * following parameters are used.
+ * @return the allocated string
+ * @note You have to free the string yourself with av_free().
+ */
+char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2);
+
+/**
* Convert a number to a av_malloced string.
*/
char *av_d2str(double d);
@@ -152,6 +177,30 @@ char *av_d2str(double d);
char *av_get_token(const char **buf, const char *term);
/**
+ * Split the string into several tokens which can be accessed by
+ * successive calls to av_strtok().
+ *
+ * A token is defined as a sequence of characters not belonging to the
+ * set specified in delim.
+ *
+ * On the first call to av_strtok(), s should point to the string to
+ * parse, and the value of saveptr is ignored. In subsequent calls, s
+ * should be NULL, and saveptr should be unchanged since the previous
+ * call.
+ *
+ * This function is similar to strtok_r() defined in POSIX.1.
+ *
+ * @param s the string to parse, may be NULL
+ * @param delim 0-terminated list of token delimiters, must be non-NULL
+ * @param saveptr user-provided pointer which points to stored
+ * information necessary for av_strtok() to continue scanning the same
+ * string. saveptr is updated to point to the next character after the
+ * first delimiter found, or to NULL if the string was terminated
+ * @return the found token, or NULL when no token is found
+ */
+char *av_strtok(char *s, const char *delim, char **saveptr);
+
+/**
* Locale-independent conversion of ASCII isdigit.
*/
av_const int av_isdigit(int c);
@@ -191,7 +240,7 @@ static inline av_const int av_tolower(int c)
*/
av_const int av_isxdigit(int c);
-/*
+/**
* Locale-independent case-insensitive compare.
* @note This means only ASCII-range characters are case-insensitive
*/
@@ -219,7 +268,6 @@ const char *av_basename(const char *path);
*/
const char *av_dirname(char *path);
-
/**
* Match instances of a name in a comma-separated list of names.
* @param name Name to look for.
@@ -229,6 +277,104 @@ const char *av_dirname(char *path);
int av_match_name(const char *name, const char *names);
/**
+ * Append path component to the existing path.
+ * Path separator '/' is placed between when needed.
+ * Resulting string have to be freed with av_free().
+ * @param path base path
+ * @param component component to be appended
+ * @return new path or NULL on error.
+ */
+char *av_append_path_component(const char *path, const char *component);
+
+enum AVEscapeMode {
+ AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode.
+ AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping.
+ AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping.
+};
+
+/**
+ * Consider spaces special and escape them even in the middle of the
+ * string.
+ *
+ * This is equivalent to adding the whitespace characters to the special
+ * characters lists, except it is guaranteed to use the exact same list
+ * of whitespace characters as the rest of libavutil.
+ */
+#define AV_ESCAPE_FLAG_WHITESPACE 0x01
+
+/**
+ * Escape only specified special characters.
+ * Without this flag, escape also any characters that may be considered
+ * special by av_get_token(), such as the single quote.
+ */
+#define AV_ESCAPE_FLAG_STRICT 0x02
+
+/**
+ * Escape string in src, and put the escaped string in an allocated
+ * string in *dst, which must be freed with av_free().
+ *
+ * @param dst pointer where an allocated string is put
+ * @param src string to escape, must be non-NULL
+ * @param special_chars string containing the special characters which
+ * need to be escaped, can be NULL
+ * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
+ * Any unknown value for mode will be considered equivalent to
+ * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
+ * notice.
+ * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros
+ * @return the length of the allocated string, or a negative error code in case of error
+ * @see av_bprint_escape()
+ */
+int av_escape(char **dst, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags);
+
+#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF
+#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF
+#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes
+#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML
+
+#define AV_UTF8_FLAG_ACCEPT_ALL \
+ AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES
+
+/**
+ * Read and decode a single UTF-8 code point (character) from the
+ * buffer in *buf, and update *buf to point to the next byte to
+ * decode.
+ *
+ * In case of an invalid byte sequence, the pointer will be updated to
+ * the next byte after the invalid sequence and the function will
+ * return an error code.
+ *
+ * Depending on the specified flags, the function will also fail in
+ * case the decoded code point does not belong to a valid range.
+ *
+ * @note For speed-relevant code a carefully implemented use of
+ * GET_UTF8() may be preferred.
+ *
+ * @param codep pointer used to return the parsed code in case of success.
+ * The value in *codep is set even in case the range check fails.
+ * @param bufp pointer to the address the first byte of the sequence
+ * to decode, updated by the function to point to the
+ * byte next after the decoded sequence
+ * @param buf_end pointer to the end of the buffer, points to the next
+ * byte past the last in the buffer. This is used to
+ * avoid buffer overreads (in case of an unfinished
+ * UTF-8 sequence towards the end of the buffer).
+ * @param flags a collection of AV_UTF8_FLAG_* flags
+ * @return >= 0 in case a sequence was successfully read, a negative
+ * value in case of invalid sequence
+ */
+int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end,
+ unsigned int flags);
+
+/**
+ * Check if a name is in a list.
+ * @returns 0 if not found, or the 1 based index where it has been found in the
+ * list.
+ */
+int av_match_list(const char *name, const char *list, char separator);
+
+/**
* @}
*/
diff --git a/libavutil/avutil.h b/libavutil/avutil.h
index f056415f09..e6ebb6c43c 100644
--- a/libavutil/avutil.h
+++ b/libavutil/avutil.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,22 +29,23 @@
/**
* @mainpage
*
- * @section libav_intro Introduction
+ * @section ffmpeg_intro Introduction
*
* This document describes the usage of the different libraries
- * provided by Libav.
+ * provided by FFmpeg.
*
* @li @ref libavc "libavcodec" encoding/decoding library
* @li @ref lavfi "libavfilter" graph-based frame editing library
* @li @ref libavf "libavformat" I/O and muxing/demuxing library
* @li @ref lavd "libavdevice" special devices muxing/demuxing library
* @li @ref lavu "libavutil" common utility library
- * @li @ref lavr "libavresample" audio resampling, format conversion and mixing
- * @li @ref libsws "libswscale" color conversion and scaling library
+ * @li @ref lswr "libswresample" audio resampling, format conversion and mixing
+ * @li @ref lpp "libpostproc" post processing library
+ * @li @ref libsws "libswscale" color conversion and scaling library
*
- * @section libav_versioning Versioning and compatibility
+ * @section ffmpeg_versioning Versioning and compatibility
*
- * Each of the Libav libraries contains a version.h header, which defines a
+ * Each of the FFmpeg libraries contains a version.h header, which defines a
* major, minor and micro version number with the
* <em>LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO}</em> macros. The major version
* number is incremented with backward incompatible changes - e.g. removing
@@ -55,22 +56,22 @@
* might still want to check for - e.g. changing behavior in a previously
* unspecified situation.
*
- * Libav guarantees backward API and ABI compatibility for each library as long
+ * FFmpeg guarantees backward API and ABI compatibility for each library as long
* as its major version number is unchanged. This means that no public symbols
* will be removed or renamed. Types and names of the public struct members and
* values of public macros and enums will remain the same (unless they were
* explicitly declared as not part of the public API). Documented behavior will
* not change.
*
- * In other words, any correct program that works with a given Libav snapshot
+ * In other words, any correct program that works with a given FFmpeg snapshot
* should work just as well without any changes with any later snapshot with the
* same major versions. This applies to both rebuilding the program against new
- * Libav versions or to replacing the dynamic Libav libraries that a program
+ * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program
* links against.
*
* However, new public symbols may be added and new members may be appended to
* public structs whose size is not part of public ABI (most public structs in
- * Libav). New macros and enum values may be added. Behavior in undocumented
+ * FFmpeg). New macros and enum values may be added. Behavior in undocumented
* situations may change slightly (and be documented). All those are accompanied
* by an entry in doc/APIchanges and incrementing either the minor or micro
* version number.
@@ -80,7 +81,7 @@
* @defgroup lavu Common utility functions
*
* @brief
- * libavutil contains the code shared across all the other Libav
+ * libavutil contains the code shared across all the other FFmpeg
* libraries
*
* @note In order to use the functions provided by avutil you must include
@@ -150,6 +151,12 @@
* @{
*
* @}
+ *
+ * @defgroup version_utils Library Version Macros
+ *
+ * @{
+ *
+ * @}
*/
@@ -193,6 +200,12 @@ enum AVMediaType {
};
/**
+ * Return a string describing the media_type enum, NULL if media_type
+ * is unknown.
+ */
+const char *av_get_media_type_string(enum AVMediaType media_type);
+
+/**
* @defgroup lavu_const Constants
* @{
*
@@ -213,7 +226,7 @@ enum AVMediaType {
* @}
* @defgroup lavu_time Timestamp specific
*
- * Libav internal timebase and timestamp definitions
+ * FFmpeg internal timebase and timestamp definitions
*
* @{
*/
@@ -225,7 +238,7 @@ enum AVMediaType {
* either pts or dts.
*/
-#define AV_NOPTS_VALUE INT64_C(0x8000000000000000)
+#define AV_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000))
/**
* Internal time base represented as integer
@@ -250,7 +263,8 @@ enum AVMediaType {
*/
enum AVPictureType {
- AV_PICTURE_TYPE_I = 1, ///< Intra
+ AV_PICTURE_TYPE_NONE = 0, ///< Undefined
+ AV_PICTURE_TYPE_I, ///< Intra
AV_PICTURE_TYPE_P, ///< Predicted
AV_PICTURE_TYPE_B, ///< Bi-dir predicted
AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG4
@@ -272,10 +286,50 @@ char av_get_picture_type_char(enum AVPictureType pict_type);
* @}
*/
+#include "common.h"
#include "error.h"
#include "rational.h"
#include "version.h"
#include "macros.h"
+#include "mathematics.h"
+#include "log.h"
+#include "pixfmt.h"
+
+/**
+ * Return x default pointer in case p is NULL.
+ */
+static inline void *av_x_if_null(const void *p, const void *x)
+{
+ return (void *)(intptr_t)(p ? p : x);
+}
+
+/**
+ * Compute the length of an integer list.
+ *
+ * @param elsize size in bytes of each list element (only 1, 2, 4 or 8)
+ * @param term list terminator (usually 0 or -1)
+ * @param list pointer to the list
+ * @return length of the list, in elements, not counting the terminator
+ */
+unsigned av_int_list_length_for_size(unsigned elsize,
+ const void *list, uint64_t term) av_pure;
+
+/**
+ * Compute the length of an integer list.
+ *
+ * @param term list terminator (usually 0 or -1)
+ * @param list pointer to the list
+ * @return length of the list, in elements, not counting the terminator
+ */
+#define av_int_list_length(list, term) \
+ av_int_list_length_for_size(sizeof(*(list)), list, term)
+
+/**
+ * Open a file using a UTF-8 filename.
+ * The API of this function matches POSIX fopen(), errors are returned through
+ * errno.
+ */
+FILE *av_fopen_utf8(const char *path, const char *mode);
/**
* Return the fractional representation of the internal time base.
diff --git a/libavutil/avutilres.rc b/libavutil/avutilres.rc
new file mode 100644
index 0000000000..40a75eb377
--- /dev/null
+++ b/libavutil/avutilres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libavutil
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libavutil/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO, 0
+PRODUCTVERSION LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg utility library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBAVUTIL_VERSION)
+ VALUE "InternalName", "libavutil"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "avutil" BUILDSUF "-" AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libavutil/base64.c b/libavutil/base64.c
index 725b03504d..03ebce8b80 100644
--- a/libavutil/base64.c
+++ b/libavutil/base64.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,41 +26,107 @@
#include "common.h"
#include "base64.h"
+#include "intreadwrite.h"
+#include "timer.h"
/* ---------------- private code */
-static const uint8_t map2[] =
+static const uint8_t map2[256] =
{
+ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff,
+
0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36,
0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01,
+ 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
- 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33
+ 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
+
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
-int av_base64_decode(uint8_t *out, const char *in, int out_size)
+#define BASE64_DEC_STEP(i) do { \
+ bits = map2[in[i]]; \
+ if (bits & 0x80) \
+ goto out ## i; \
+ v = i ? (v << 6) + bits : bits; \
+} while(0)
+
+int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
{
- int i;
- unsigned v = 0;
uint8_t *dst = out;
+ uint8_t *end = out + out_size;
+ // no sign extension
+ const uint8_t *in = in_str;
+ unsigned bits = 0xff;
+ unsigned v;
- for (i = 0; in[i] && in[i] != '='; i++) {
- unsigned int index= in[i]-43;
- if (index>=FF_ARRAY_ELEMS(map2) || map2[index] == 0xff)
- return -1;
- v = (v << 6) + map2[index];
- if (i & 3) {
- if (dst - out < out_size) {
- *dst++ = v >> (6 - 2 * (i & 3));
- }
- }
+ while (end - dst > 3) {
+ BASE64_DEC_STEP(0);
+ BASE64_DEC_STEP(1);
+ BASE64_DEC_STEP(2);
+ BASE64_DEC_STEP(3);
+ // Using AV_WB32 directly confuses compiler
+ v = av_be2ne32(v << 8);
+ AV_WN32(dst, v);
+ dst += 3;
+ in += 4;
+ }
+ if (end - dst) {
+ BASE64_DEC_STEP(0);
+ BASE64_DEC_STEP(1);
+ BASE64_DEC_STEP(2);
+ BASE64_DEC_STEP(3);
+ *dst++ = v >> 16;
+ if (end - dst)
+ *dst++ = v >> 8;
+ if (end - dst)
+ *dst++ = v;
+ in += 4;
+ }
+ while (1) {
+ BASE64_DEC_STEP(0);
+ in++;
+ BASE64_DEC_STEP(0);
+ in++;
+ BASE64_DEC_STEP(0);
+ in++;
+ BASE64_DEC_STEP(0);
+ in++;
}
- return dst - out;
+out3:
+ *dst++ = v >> 10;
+ v <<= 2;
+out2:
+ *dst++ = v >> 4;
+out1:
+out0:
+ return bits & 1 ? AVERROR_INVALIDDATA : dst - out;
}
/*****************************************************************************
@@ -82,15 +148,23 @@ char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
out_size < AV_BASE64_SIZE(in_size))
return NULL;
ret = dst = out;
+ while (bytes_remaining > 3) {
+ i_bits = AV_RB32(in);
+ in += 3; bytes_remaining -= 3;
+ *dst++ = b64[ i_bits>>26 ];
+ *dst++ = b64[(i_bits>>20) & 0x3F];
+ *dst++ = b64[(i_bits>>14) & 0x3F];
+ *dst++ = b64[(i_bits>>8 ) & 0x3F];
+ }
+ i_bits = 0;
while (bytes_remaining) {
i_bits = (i_bits << 8) + *in++;
bytes_remaining--;
i_shift += 8;
-
- do {
- *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
- i_shift -= 6;
- } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0));
+ }
+ while (i_shift > 0) {
+ *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
+ i_shift -= 6;
}
while ((dst - ret) & 3)
*dst++ = '=';
@@ -100,6 +174,7 @@ char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
}
#ifdef TEST
+// LCOV_EXCL_START
#define MAX_DATA_SIZE 1024
#define MAX_ENCODED_SIZE 2048
@@ -121,21 +196,40 @@ static int test_encode_decode(const uint8_t *data, unsigned int data_size,
return 1;
}
- if ((data2_size = av_base64_decode(data2, encoded, max_data2_size)) < 0) {
+ if ((data2_size = av_base64_decode(data2, encoded, max_data2_size)) != data_size) {
printf("Failed: cannot decode the encoded string\n"
"Encoded:\n%s\n", encoded);
return 1;
}
+ if ((data2_size = av_base64_decode(data2, encoded, data_size)) != data_size) {
+ printf("Failed: cannot decode with minimal buffer\n"
+ "Encoded:\n%s\n", encoded);
+ return 1;
+ }
if (memcmp(data2, data, data_size)) {
printf("Failed: encoded/decoded data differs from original data\n");
return 1;
}
+ if (av_base64_decode(NULL, encoded, 0) != 0) {
+ printf("Failed: decode to NULL buffer\n");
+ return 1;
+ }
+ if (strlen(encoded)) {
+ char *end = strchr(encoded, '=');
+ if (!end)
+ end = encoded + strlen(encoded) - 1;
+ *end = '%';
+ if (av_base64_decode(NULL, encoded, 0) >= 0) {
+ printf("Failed: error detection\n");
+ return 1;
+ }
+ }
printf("Passed!\n");
return 0;
}
-int main(void)
+int main(int argc, char ** argv)
{
int i, error_count = 0;
struct test {
@@ -151,15 +245,37 @@ int main(void)
{ "666666", "NjY2NjY2"},
{ "abc:def", "YWJjOmRlZg=="},
};
+ char in[1024], out[2048];
printf("Encoding/decoding tests\n");
for (i = 0; i < FF_ARRAY_ELEMS(tests); i++)
error_count += test_encode_decode(tests[i].data, strlen(tests[i].data), tests[i].encoded_ref);
+ if (argc>1 && !strcmp(argv[1], "-t")) {
+ memset(in, 123, sizeof(in));
+ for(i=0; i<10000; i++){
+ START_TIMER
+ av_base64_encode(out, sizeof(out), in, sizeof(in));
+ STOP_TIMER("encode")
+ }
+ for(i=0; i<10000; i++){
+ START_TIMER
+ av_base64_decode(in, out, sizeof(in));
+ STOP_TIMER("decode")
+ }
+
+ for(i=0; i<10000; i++){
+ START_TIMER
+ av_base64_decode(NULL, out, 0);
+ STOP_TIMER("syntax check")
+ }
+ }
+
if (error_count)
printf("Error Count: %d.\n", error_count);
return !!error_count;
}
+// LCOV_EXCL_STOP
#endif
diff --git a/libavutil/base64.h b/libavutil/base64.h
index 4750cf5c72..514498eac8 100644
--- a/libavutil/base64.h
+++ b/libavutil/base64.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,15 +46,17 @@ int av_base64_decode(uint8_t *out, const char *in, int out_size);
* Encode data to base64 and null-terminate.
*
* @param out buffer for encoded data
- * @param out_size size in bytes of the output buffer, must be at
- * least AV_BASE64_SIZE(in_size)
- * @param in_size size in bytes of the 'in' buffer
- * @return 'out' or NULL in case of error
+ * @param out_size size in bytes of the out buffer (including the
+ * null terminator), must be at least AV_BASE64_SIZE(in_size)
+ * @param in input buffer containing the data to encode
+ * @param in_size size in bytes of the in buffer
+ * @return out or NULL in case of error
*/
char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size);
/**
- * Calculate the output size needed to base64-encode x bytes.
+ * Calculate the output size needed to base64-encode x bytes to a
+ * null-terminated string.
*/
#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1)
diff --git a/libavutil/bfin/bswap.h b/libavutil/bfin/bswap.h
index 2837a2f7e1..363ed40bc5 100644
--- a/libavutil/bfin/bswap.h
+++ b/libavutil/bfin/bswap.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2007 Marc Hoffman
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/bfin/timer.h b/libavutil/bfin/timer.h
index 49d32a8f6b..644573daec 100644
--- a/libavutil/bfin/timer.h
+++ b/libavutil/bfin/timer.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2007 Marc Hoffman
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/blowfish.c b/libavutil/blowfish.c
index 8437dd6f94..3821427570 100644
--- a/libavutil/blowfish.c
+++ b/libavutil/blowfish.c
@@ -4,20 +4,20 @@
*
* loosely based on Paul Kocher's implementation
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -293,24 +293,12 @@ static const uint32_t orig_s[4][256] = {
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 }
};
-static void F(AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, int i)
-{
- uint32_t Xl, Xr;
- uint32_t y;
-
- Xl = *xl;
- Xr = *xr;
-
- Xl ^= ctx->p[i];
- y = ctx->s[0][(Xl >> 24) & 0xFF];
- y += ctx->s[1][(Xl >> 16) & 0xFF];
- y ^= ctx->s[2][(Xl >> 8) & 0xFF];
- y += ctx->s[3][ Xl & 0xFF];
- Xr ^= y;
-
- *xl = Xr;
- *xr = Xl;
-}
+#define F(Xl, Xr, P) \
+ Xr ^=((( ctx->s[0][ Xl >> 24 ] \
+ + ctx->s[1][(Xl >> 16) & 0xFF])\
+ ^ ctx->s[2][(Xl >> 8) & 0xFF])\
+ + ctx->s[3][ Xl & 0xFF])\
+ ^ P;
av_cold void av_blowfish_init(AVBlowfish *ctx, const uint8_t *key, int key_len)
{
@@ -357,17 +345,21 @@ void av_blowfish_crypt_ecb(AVBlowfish *ctx, uint32_t *xl, uint32_t *xr,
Xr = *xr;
if (decrypt) {
- for (i = AV_BF_ROUNDS + 1; i > 1; --i)
- F(ctx, &Xl, &Xr, i);
+ Xl ^= ctx->p[AV_BF_ROUNDS + 1];
+ for (i = AV_BF_ROUNDS; i > 0; i-=2) {
+ F(Xl, Xr, ctx->p[i ]);
+ F(Xr, Xl, ctx->p[i-1]);
+ }
- Xl = Xl ^ ctx->p[1];
- Xr = Xr ^ ctx->p[0];
+ Xr ^= ctx->p[0];
} else {
- for (i = 0; i < AV_BF_ROUNDS; ++i)
- F(ctx, &Xl, &Xr, i);
+ Xl ^= ctx->p[0];
+ for (i = 1; i < AV_BF_ROUNDS+1; i+=2){
+ F(Xl, Xr, ctx->p[i ]);
+ F(Xr, Xl, ctx->p[i+1]);
+ }
- Xl = Xl ^ ctx->p[AV_BF_ROUNDS];
- Xr = Xr ^ ctx->p[AV_BF_ROUNDS + 1];
+ Xr ^= ctx->p[AV_BF_ROUNDS + 1];
}
*xl = Xr;
diff --git a/libavutil/blowfish.h b/libavutil/blowfish.h
index 8c29536cfe..0b004532de 100644
--- a/libavutil/blowfish.h
+++ b/libavutil/blowfish.h
@@ -1,20 +1,21 @@
/*
* Blowfish algorithm
+ * Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/bprint.c b/libavutil/bprint.c
new file mode 100644
index 0000000000..0a0d07861b
--- /dev/null
+++ b/libavutil/bprint.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "avassert.h"
+#include "avstring.h"
+#include "bprint.h"
+#include "common.h"
+#include "compat/va_copy.h"
+#include "error.h"
+#include "mem.h"
+
+#define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size))
+#define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer)
+
+static int av_bprint_alloc(AVBPrint *buf, unsigned room)
+{
+ char *old_str, *new_str;
+ unsigned min_size, new_size;
+
+ if (buf->size == buf->size_max)
+ return AVERROR(EIO);
+ if (!av_bprint_is_complete(buf))
+ return AVERROR_INVALIDDATA; /* it is already truncated anyway */
+ min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room);
+ new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2;
+ if (new_size < min_size)
+ new_size = FFMIN(buf->size_max, min_size);
+ old_str = av_bprint_is_allocated(buf) ? buf->str : NULL;
+ new_str = av_realloc(old_str, new_size);
+ if (!new_str)
+ return AVERROR(ENOMEM);
+ if (!old_str)
+ memcpy(new_str, buf->str, buf->len + 1);
+ buf->str = new_str;
+ buf->size = new_size;
+ return 0;
+}
+
+static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
+{
+ /* arbitrary margin to avoid small overflows */
+ extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len);
+ buf->len += extra_len;
+ if (buf->size)
+ buf->str[FFMIN(buf->len, buf->size - 1)] = 0;
+}
+
+void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
+{
+ unsigned size_auto = (char *)buf + sizeof(*buf) -
+ buf->reserved_internal_buffer;
+
+ if (size_max == 1)
+ size_max = size_auto;
+ buf->str = buf->reserved_internal_buffer;
+ buf->len = 0;
+ buf->size = FFMIN(size_auto, size_max);
+ buf->size_max = size_max;
+ *buf->str = 0;
+ if (size_init > buf->size)
+ av_bprint_alloc(buf, size_init - 1);
+}
+
+void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
+{
+ buf->str = buffer;
+ buf->len = 0;
+ buf->size = size;
+ buf->size_max = size;
+ *buf->str = 0;
+}
+
+void av_bprintf(AVBPrint *buf, const char *fmt, ...)
+{
+ unsigned room;
+ char *dst;
+ va_list vl;
+ int extra_len;
+
+ while (1) {
+ room = av_bprint_room(buf);
+ dst = room ? buf->str + buf->len : NULL;
+ va_start(vl, fmt);
+ extra_len = vsnprintf(dst, room, fmt, vl);
+ va_end(vl);
+ if (extra_len <= 0)
+ return;
+ if (extra_len < room)
+ break;
+ if (av_bprint_alloc(buf, extra_len))
+ break;
+ }
+ av_bprint_grow(buf, extra_len);
+}
+
+void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
+{
+ unsigned room;
+ char *dst;
+ int extra_len;
+ va_list vl;
+
+ while (1) {
+ room = av_bprint_room(buf);
+ dst = room ? buf->str + buf->len : NULL;
+ va_copy(vl, vl_arg);
+ extra_len = vsnprintf(dst, room, fmt, vl);
+ va_end(vl);
+ if (extra_len <= 0)
+ return;
+ if (extra_len < room)
+ break;
+ if (av_bprint_alloc(buf, extra_len))
+ break;
+ }
+ av_bprint_grow(buf, extra_len);
+}
+
+void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
+{
+ unsigned room, real_n;
+
+ while (1) {
+ room = av_bprint_room(buf);
+ if (n < room)
+ break;
+ if (av_bprint_alloc(buf, n))
+ break;
+ }
+ if (room) {
+ real_n = FFMIN(n, room - 1);
+ memset(buf->str + buf->len, c, real_n);
+ }
+ av_bprint_grow(buf, n);
+}
+
+void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
+{
+ unsigned room, real_n;
+
+ while (1) {
+ room = av_bprint_room(buf);
+ if (size < room)
+ break;
+ if (av_bprint_alloc(buf, size))
+ break;
+ }
+ if (room) {
+ real_n = FFMIN(size, room - 1);
+ memcpy(buf->str + buf->len, data, real_n);
+ }
+ av_bprint_grow(buf, size);
+}
+
+void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
+{
+ unsigned room;
+ size_t l;
+
+ if (!*fmt)
+ return;
+ while (1) {
+ room = av_bprint_room(buf);
+ if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
+ break;
+ /* strftime does not tell us how much room it would need: let us
+ retry with twice as much until the buffer is large enough */
+ room = !room ? strlen(fmt) + 1 :
+ room <= INT_MAX / 2 ? room * 2 : INT_MAX;
+ if (av_bprint_alloc(buf, room)) {
+ /* impossible to grow, try to manage something useful anyway */
+ room = av_bprint_room(buf);
+ if (room < 1024) {
+ /* if strftime fails because the buffer has (almost) reached
+ its maximum size, let us try in a local buffer; 1k should
+ be enough to format any real date+time string */
+ char buf2[1024];
+ if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
+ av_bprintf(buf, "%s", buf2);
+ return;
+ }
+ }
+ if (room) {
+ /* if anything else failed and the buffer is not already
+ truncated, let us add a stock string and force truncation */
+ static const char txt[] = "[truncated strftime output]";
+ memset(buf->str + buf->len, '!', room);
+ memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room));
+ av_bprint_grow(buf, room); /* force truncation */
+ }
+ return;
+ }
+ }
+ av_bprint_grow(buf, l);
+}
+
+void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
+ unsigned char **mem, unsigned *actual_size)
+{
+ if (size > av_bprint_room(buf))
+ av_bprint_alloc(buf, size);
+ *actual_size = av_bprint_room(buf);
+ *mem = *actual_size ? buf->str + buf->len : NULL;
+}
+
+void av_bprint_clear(AVBPrint *buf)
+{
+ if (buf->len) {
+ *buf->str = 0;
+ buf->len = 0;
+ }
+}
+
+int av_bprint_finalize(AVBPrint *buf, char **ret_str)
+{
+ unsigned real_size = FFMIN(buf->len + 1, buf->size);
+ char *str;
+ int ret = 0;
+
+ if (ret_str) {
+ if (av_bprint_is_allocated(buf)) {
+ str = av_realloc(buf->str, real_size);
+ if (!str)
+ str = buf->str;
+ buf->str = NULL;
+ } else {
+ str = av_malloc(real_size);
+ if (str)
+ memcpy(str, buf->str, real_size);
+ else
+ ret = AVERROR(ENOMEM);
+ }
+ *ret_str = str;
+ } else {
+ if (av_bprint_is_allocated(buf))
+ av_freep(&buf->str);
+ }
+ buf->size = real_size;
+ return ret;
+}
+
+#define WHITESPACES " \n\t"
+
+void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags)
+{
+ const char *src0 = src;
+
+ if (mode == AV_ESCAPE_MODE_AUTO)
+ mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
+
+ switch (mode) {
+ case AV_ESCAPE_MODE_QUOTE:
+ /* enclose the string between '' */
+ av_bprint_chars(dstbuf, '\'', 1);
+ for (; *src; src++) {
+ if (*src == '\'')
+ av_bprintf(dstbuf, "'\\''");
+ else
+ av_bprint_chars(dstbuf, *src, 1);
+ }
+ av_bprint_chars(dstbuf, '\'', 1);
+ break;
+
+ /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
+ default:
+ /* \-escape characters */
+ for (; *src; src++) {
+ int is_first_last = src == src0 || !*(src+1);
+ int is_ws = !!strchr(WHITESPACES, *src);
+ int is_strictly_special = special_chars && strchr(special_chars, *src);
+ int is_special =
+ is_strictly_special || strchr("'\\", *src) ||
+ (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
+
+ if (is_strictly_special ||
+ (!(flags & AV_ESCAPE_FLAG_STRICT) &&
+ (is_special || (is_ws && is_first_last))))
+ av_bprint_chars(dstbuf, '\\', 1);
+ av_bprint_chars(dstbuf, *src, 1);
+ }
+ break;
+ }
+}
+
+#ifdef TEST
+
+#undef printf
+
+static void bprint_pascal(AVBPrint *b, unsigned size)
+{
+ unsigned i, j;
+ unsigned p[42];
+
+ av_assert0(size < FF_ARRAY_ELEMS(p));
+
+ p[0] = 1;
+ av_bprintf(b, "%8d\n", 1);
+ for (i = 1; i <= size; i++) {
+ p[i] = 1;
+ for (j = i - 1; j > 0; j--)
+ p[j] = p[j] + p[j - 1];
+ for (j = 0; j <= i; j++)
+ av_bprintf(b, "%8d", p[j]);
+ av_bprintf(b, "\n");
+ }
+}
+
+int main(void)
+{
+ AVBPrint b;
+ char buf[256];
+ struct tm testtime = { .tm_year = 100, .tm_mon = 11, .tm_mday = 20 };
+
+ av_bprint_init(&b, 0, -1);
+ bprint_pascal(&b, 5);
+ printf("Short text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
+ printf("%s\n", b.str);
+ av_bprint_finalize(&b, NULL);
+
+ av_bprint_init(&b, 0, -1);
+ bprint_pascal(&b, 25);
+ printf("Long text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
+ av_bprint_finalize(&b, NULL);
+
+ av_bprint_init(&b, 0, 2048);
+ bprint_pascal(&b, 25);
+ printf("Long text in limited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
+ av_bprint_finalize(&b, NULL);
+
+ av_bprint_init(&b, 0, 1);
+ bprint_pascal(&b, 5);
+ printf("Short text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
+
+ av_bprint_init(&b, 0, 1);
+ bprint_pascal(&b, 25);
+ printf("Long text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str)/8*8, b.len);
+ /* Note that the size of the automatic buffer is arch-dependent. */
+
+ av_bprint_init(&b, 0, 0);
+ bprint_pascal(&b, 25);
+ printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
+
+ av_bprint_init_for_buffer(&b, buf, sizeof(buf));
+ bprint_pascal(&b, 25);
+ printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf), b.len);
+
+ av_bprint_init(&b, 0, -1);
+ av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
+ printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
+ av_bprint_finalize(&b, NULL);
+
+ av_bprint_init(&b, 0, 8);
+ av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
+ printf("strftime truncated: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
+
+ return 0;
+}
+
+#endif
diff --git a/libavutil/bprint.h b/libavutil/bprint.h
new file mode 100644
index 0000000000..c09b1ac1e1
--- /dev/null
+++ b/libavutil/bprint.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2012 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_BPRINT_H
+#define AVUTIL_BPRINT_H
+
+#include <stdarg.h>
+
+#include "attributes.h"
+#include "avstring.h"
+
+/**
+ * Define a structure with extra padding to a fixed size
+ * This helps ensuring binary compatibility with future versions.
+ */
+
+#define FF_PAD_STRUCTURE(name, size, ...) \
+struct ff_pad_helper_##name { __VA_ARGS__ }; \
+typedef struct name { \
+ __VA_ARGS__ \
+ char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \
+} name;
+
+/**
+ * Buffer to print data progressively
+ *
+ * The string buffer grows as necessary and is always 0-terminated.
+ * The content of the string is never accessed, and thus is
+ * encoding-agnostic and can even hold binary data.
+ *
+ * Small buffers are kept in the structure itself, and thus require no
+ * memory allocation at all (unless the contents of the buffer is needed
+ * after the structure goes out of scope). This is almost as lightweight as
+ * declaring a local "char buf[512]".
+ *
+ * The length of the string can go beyond the allocated size: the buffer is
+ * then truncated, but the functions still keep account of the actual total
+ * length.
+ *
+ * In other words, buf->len can be greater than buf->size and records the
+ * total length of what would have been to the buffer if there had been
+ * enough memory.
+ *
+ * Append operations do not need to be tested for failure: if a memory
+ * allocation fails, data stop being appended to the buffer, but the length
+ * is still updated. This situation can be tested with
+ * av_bprint_is_complete().
+ *
+ * The size_max field determines several possible behaviours:
+ *
+ * size_max = -1 (= UINT_MAX) or any large value will let the buffer be
+ * reallocated as necessary, with an amortized linear cost.
+ *
+ * size_max = 0 prevents writing anything to the buffer: only the total
+ * length is computed. The write operations can then possibly be repeated in
+ * a buffer with exactly the necessary size
+ * (using size_init = size_max = len + 1).
+ *
+ * size_max = 1 is automatically replaced by the exact size available in the
+ * structure itself, thus ensuring no dynamic memory allocation. The
+ * internal buffer is large enough to hold a reasonable paragraph of text,
+ * such as the current paragraph.
+ */
+
+FF_PAD_STRUCTURE(AVBPrint, 1024,
+ char *str; /**< string so far */
+ unsigned len; /**< length so far */
+ unsigned size; /**< allocated memory */
+ unsigned size_max; /**< maximum allocated memory */
+ char reserved_internal_buffer[1];
+)
+
+/**
+ * Convenience macros for special values for av_bprint_init() size_max
+ * parameter.
+ */
+#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1)
+#define AV_BPRINT_SIZE_AUTOMATIC 1
+#define AV_BPRINT_SIZE_COUNT_ONLY 0
+
+/**
+ * Init a print buffer.
+ *
+ * @param buf buffer to init
+ * @param size_init initial size (including the final 0)
+ * @param size_max maximum size;
+ * 0 means do not write anything, just count the length;
+ * 1 is replaced by the maximum value for automatic storage;
+ * any large value means that the internal buffer will be
+ * reallocated as needed up to that limit; -1 is converted to
+ * UINT_MAX, the largest limit possible.
+ * Check also AV_BPRINT_SIZE_* macros.
+ */
+void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
+
+/**
+ * Init a print buffer using a pre-existing buffer.
+ *
+ * The buffer will not be reallocated.
+ *
+ * @param buf buffer structure to init
+ * @param buffer byte buffer to use for the string data
+ * @param size size of buffer
+ */
+void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size);
+
+/**
+ * Append a formatted string to a print buffer.
+ */
+void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3);
+
+/**
+ * Append a formatted string to a print buffer.
+ */
+void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg);
+
+/**
+ * Append char c n times to a print buffer.
+ */
+void av_bprint_chars(AVBPrint *buf, char c, unsigned n);
+
+/**
+ * Append data to a print buffer.
+ *
+ * param buf bprint buffer to use
+ * param data pointer to data
+ * param size size of data
+ */
+void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size);
+
+struct tm;
+/**
+ * Append a formatted date and time to a print buffer.
+ *
+ * param buf bprint buffer to use
+ * param fmt date and time format string, see strftime()
+ * param tm broken-down time structure to translate
+ *
+ * @note due to poor design of the standard strftime function, it may
+ * produce poor results if the format string expands to a very long text and
+ * the bprint buffer is near the limit stated by the size_max option.
+ */
+void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm);
+
+/**
+ * Allocate bytes in the buffer for external use.
+ *
+ * @param[in] buf buffer structure
+ * @param[in] size required size
+ * @param[out] mem pointer to the memory area
+ * @param[out] actual_size size of the memory area after allocation;
+ * can be larger or smaller than size
+ */
+void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
+ unsigned char **mem, unsigned *actual_size);
+
+/**
+ * Reset the string to "" but keep internal allocated data.
+ */
+void av_bprint_clear(AVBPrint *buf);
+
+/**
+ * Test if the print buffer is complete (not truncated).
+ *
+ * It may have been truncated due to a memory allocation failure
+ * or the size_max limit (compare size and size_max if necessary).
+ */
+static inline int av_bprint_is_complete(const AVBPrint *buf)
+{
+ return buf->len < buf->size;
+}
+
+/**
+ * Finalize a print buffer.
+ *
+ * The print buffer can no longer be used afterwards,
+ * but the len and size fields are still valid.
+ *
+ * @arg[out] ret_str if not NULL, used to return a permanent copy of the
+ * buffer contents, or NULL if memory allocation fails;
+ * if NULL, the buffer is discarded and freed
+ * @return 0 for success or error code (probably AVERROR(ENOMEM))
+ */
+int av_bprint_finalize(AVBPrint *buf, char **ret_str);
+
+/**
+ * Escape the content in src and append it to dstbuf.
+ *
+ * @param dstbuf already inited destination bprint buffer
+ * @param src string containing the text to escape
+ * @param special_chars string containing the special characters which
+ * need to be escaped, can be NULL
+ * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros.
+ * Any unknown value for mode will be considered equivalent to
+ * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without
+ * notice.
+ * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros
+ */
+void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
+ enum AVEscapeMode mode, int flags);
+
+#endif /* AVUTIL_BPRINT_H */
diff --git a/libavutil/bswap.h b/libavutil/bswap.h
index 93a6016b8c..91cb79538d 100644
--- a/libavutil/bswap.h
+++ b/libavutil/bswap.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,8 +40,6 @@
# include "arm/bswap.h"
#elif ARCH_AVR32
# include "avr32/bswap.h"
-#elif ARCH_BFIN
-# include "bfin/bswap.h"
#elif ARCH_SH4
# include "sh4/bswap.h"
#elif ARCH_X86
diff --git a/libavutil/buffer.c b/libavutil/buffer.c
index 1bc4a93f38..bb112c238e 100644
--- a/libavutil/buffer.c
+++ b/libavutil/buffer.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -103,14 +103,17 @@ AVBufferRef *av_buffer_ref(AVBufferRef *buf)
return ret;
}
-void av_buffer_unref(AVBufferRef **buf)
+static void buffer_replace(AVBufferRef **dst, AVBufferRef **src)
{
AVBuffer *b;
- if (!buf || !*buf)
- return;
- b = (*buf)->buffer;
- av_freep(buf);
+ b = (*dst)->buffer;
+
+ if (src) {
+ **dst = **src;
+ av_freep(src);
+ } else
+ av_freep(dst);
if (!avpriv_atomic_int_add_and_fetch(&b->refcount, -1)) {
b->free(b->opaque, b->data);
@@ -118,12 +121,30 @@ void av_buffer_unref(AVBufferRef **buf)
}
}
+void av_buffer_unref(AVBufferRef **buf)
+{
+ if (!buf || !*buf)
+ return;
+
+ buffer_replace(buf, NULL);
+}
+
int av_buffer_is_writable(const AVBufferRef *buf)
{
if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY)
return 0;
- return avpriv_atomic_int_add_and_fetch(&buf->buffer->refcount, 0) == 1;
+ return avpriv_atomic_int_get(&buf->buffer->refcount) == 1;
+}
+
+void *av_buffer_get_opaque(const AVBufferRef *buf)
+{
+ return buf->buffer->opaque;
+}
+
+int av_buffer_get_ref_count(const AVBufferRef *buf)
+{
+ return buf->buffer->refcount;
}
int av_buffer_make_writable(AVBufferRef **pbuf)
@@ -138,8 +159,8 @@ int av_buffer_make_writable(AVBufferRef **pbuf)
return AVERROR(ENOMEM);
memcpy(newbuf->data, buf->data, buf->size);
- av_buffer_unref(pbuf);
- *pbuf = newbuf;
+
+ buffer_replace(pbuf, &newbuf);
return 0;
}
@@ -180,8 +201,7 @@ int av_buffer_realloc(AVBufferRef **pbuf, int size)
memcpy(new->data, buf->data, FFMIN(size, buf->size));
- av_buffer_unref(pbuf);
- *pbuf = new;
+ buffer_replace(pbuf, &new);
return 0;
}
@@ -240,15 +260,60 @@ void av_buffer_pool_uninit(AVBufferPool **ppool)
buffer_pool_free(pool);
}
+#if USE_ATOMICS
+/* remove the whole buffer list from the pool and return it */
+static BufferPoolEntry *get_pool(AVBufferPool *pool)
+{
+ BufferPoolEntry *cur = *(void * volatile *)&pool->pool, *last = NULL;
+
+ while (cur != last) {
+ last = cur;
+ cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL);
+ if (!cur)
+ return NULL;
+ }
+
+ return cur;
+}
+
+static void add_to_pool(BufferPoolEntry *buf)
+{
+ AVBufferPool *pool;
+ BufferPoolEntry *cur, *end = buf;
+
+ if (!buf)
+ return;
+ pool = buf->pool;
+
+ while (end->next)
+ end = end->next;
+
+ while (avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf)) {
+ /* pool is not empty, retrieve it and append it to our list */
+ cur = get_pool(pool);
+ end->next = cur;
+ while (end->next)
+ end = end->next;
+ }
+}
+#endif
+
static void pool_release_buffer(void *opaque, uint8_t *data)
{
BufferPoolEntry *buf = opaque;
AVBufferPool *pool = buf->pool;
+ if(CONFIG_MEMORY_POISONING)
+ memset(buf->data, FF_MEMORY_POISON, pool->size);
+
+#if USE_ATOMICS
+ add_to_pool(buf);
+#else
ff_mutex_lock(&pool->mutex);
buf->next = pool->pool;
pool->pool = buf;
ff_mutex_unlock(&pool->mutex);
+#endif
if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
buffer_pool_free(pool);
@@ -279,6 +344,11 @@ static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool)
ret->buffer->opaque = buf;
ret->buffer->free = pool_release_buffer;
+#if USE_ATOMICS
+ avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
+ avpriv_atomic_int_add_and_fetch(&pool->nb_allocated, 1);
+#endif
+
return ret;
}
@@ -287,6 +357,29 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool)
AVBufferRef *ret;
BufferPoolEntry *buf;
+#if USE_ATOMICS
+ /* check whether the pool is empty */
+ buf = get_pool(pool);
+ if (!buf && pool->refcount <= pool->nb_allocated) {
+ av_log(NULL, AV_LOG_DEBUG, "Pool race dectected, spining to avoid overallocation and eventual OOM\n");
+ while (!buf && avpriv_atomic_int_get(&pool->refcount) <= avpriv_atomic_int_get(&pool->nb_allocated))
+ buf = get_pool(pool);
+ }
+
+ if (!buf)
+ return pool_alloc_buffer(pool);
+
+ /* keep the first entry, return the rest of the list to the pool */
+ add_to_pool(buf->next);
+ buf->next = NULL;
+
+ ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
+ buf, 0);
+ if (!ret) {
+ add_to_pool(buf);
+ return NULL;
+ }
+#else
ff_mutex_lock(&pool->mutex);
buf = pool->pool;
if (buf) {
@@ -300,6 +393,7 @@ AVBufferRef *av_buffer_pool_get(AVBufferPool *pool)
ret = pool_alloc_buffer(pool);
}
ff_mutex_unlock(&pool->mutex);
+#endif
if (ret)
avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
diff --git a/libavutil/buffer.h b/libavutil/buffer.h
index 56b4d020e5..b4399fd39f 100644
--- a/libavutil/buffer.h
+++ b/libavutil/buffer.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -49,7 +49,7 @@
* Use av_buffer_unref() to free a reference (this will automatically free the
* data once all the references are freed).
*
- * The convention throughout this API and the rest of Libav is such that the
+ * The convention throughout this API and the rest of FFmpeg is such that the
* buffer is considered writable if there exists only one reference to it (and
* it has not been marked as read-only). The av_buffer_is_writable() function is
* provided to check whether this is true and av_buffer_make_writable() will
@@ -122,7 +122,7 @@ AVBufferRef *av_buffer_allocz(int size);
* @param data data array
* @param size size of data in bytes
* @param free a callback for freeing this buffer's data
- * @param opaque parameter to be passed to free
+ * @param opaque parameter to be got for processing or passed to free
* @param flags a combination of AV_BUFFER_FLAG_*
*
* @return an AVBufferRef referring to data on success, NULL on failure.
@@ -163,6 +163,13 @@ void av_buffer_unref(AVBufferRef **buf);
int av_buffer_is_writable(const AVBufferRef *buf);
/**
+ * @return the opaque parameter set by av_buffer_create.
+ */
+void *av_buffer_get_opaque(const AVBufferRef *buf);
+
+int av_buffer_get_ref_count(const AVBufferRef *buf);
+
+/**
* Create a writable reference from a given buffer reference, avoiding data copy
* if possible.
*
diff --git a/libavutil/buffer_internal.h b/libavutil/buffer_internal.h
index 1032a543e5..e6530485d3 100644
--- a/libavutil/buffer_internal.h
+++ b/libavutil/buffer_internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -87,6 +87,8 @@ struct AVBufferPool {
*/
volatile int refcount;
+ volatile int nb_allocated;
+
int size;
AVBufferRef* (*alloc)(int size);
};
diff --git a/libavutil/camellia.c b/libavutil/camellia.c
new file mode 100644
index 0000000000..483eed22f0
--- /dev/null
+++ b/libavutil/camellia.c
@@ -0,0 +1,470 @@
+/*
+ * An implementation of the CAMELLIA algorithm as mentioned in RFC3713
+ * Copyright (c) 2014 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "camellia.h"
+#include "common.h"
+#include "intreadwrite.h"
+#include "attributes.h"
+
+#define LR32(x,c) ((x) << (c) | (x) >> (32 - (c)))
+#define RR32(x,c) ((x) >> (c) | (x) << (32 - (c)))
+
+#define MASK8 0xff
+#define MASK32 0xffffffff
+#define MASK64 0xffffffffffffffff
+
+#define Sigma1 0xA09E667F3BCC908B
+#define Sigma2 0xB67AE8584CAA73B2
+#define Sigma3 0xC6EF372FE94F82BE
+#define Sigma4 0x54FF53A5F1D36F1C
+#define Sigma5 0x10E527FADE682D1D
+#define Sigma6 0xB05688C2B3E6C1FD
+
+static uint64_t SP[8][256];
+
+typedef struct AVCAMELLIA {
+ uint64_t Kw[4];
+ uint64_t Ke[6];
+ uint64_t K[24];
+ int key_bits;
+} AVCAMELLIA;
+
+static const uint8_t SBOX1[256] = {
+112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65,
+ 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189,
+134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26,
+166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77,
+139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153,
+223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215,
+ 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34,
+254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80,
+170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210,
+ 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148,
+135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226,
+ 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46,
+233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89,
+120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250,
+114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164,
+ 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158
+};
+
+static const uint8_t SBOX2[256] = {
+224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130,
+ 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123,
+ 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52,
+ 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154,
+ 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51,
+191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175,
+ 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68,
+253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160,
+ 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165,
+ 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41,
+ 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197,
+164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92,
+211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178,
+240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245,
+228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73,
+128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61
+};
+
+static const uint8_t SBOX3[256] = {
+ 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160,
+145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222,
+ 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13,
+ 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166,
+197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204,
+239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235,
+ 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17,
+127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40,
+ 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105,
+ 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74,
+195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113,
+ 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23,
+244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172,
+ 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125,
+ 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82,
+ 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79
+};
+
+static const uint8_t SBOX4[256] = {
+112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146,
+134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108,
+139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4,
+ 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105,
+170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221,
+135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99,
+233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141,
+114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128,
+130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189,
+184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77,
+ 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215,
+ 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80,
+208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148,
+ 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46,
+121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250,
+ 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158
+};
+
+const int av_camellia_size = sizeof(AVCAMELLIA);
+
+static void LR128(uint64_t d[2], const uint64_t K[2], int x)
+{
+ int i = 0;
+ if (64 <= x && x < 128) {
+ i = 1;
+ x -= 64;
+ }
+ if (x <= 0 || x >= 128) {
+ d[0] = K[i];
+ d[1] = K[!i];
+ return;
+ }
+ d[0] = (K[i] << x | K[!i] >> (64 - x));
+ d[1] = (K[!i] << x | K[i] >> (64 - x));
+}
+
+static uint64_t F(uint64_t F_IN, uint64_t KE)
+{
+ KE ^= F_IN;
+ F_IN=SP[0][KE >> 56]^SP[1][(KE >> 48) & MASK8]^SP[2][(KE >> 40) & MASK8]^SP[3][(KE >> 32) & MASK8]^SP[4][(KE >> 24) & MASK8]^SP[5][(KE >> 16) & MASK8]^SP[6][(KE >> 8) & MASK8]^SP[7][KE & MASK8];
+ return F_IN;
+}
+
+static uint64_t FL(uint64_t FL_IN, uint64_t KE)
+{
+ uint32_t x1, x2, k1, k2;
+ x1 = FL_IN >> 32;
+ x2 = FL_IN & MASK32;
+ k1 = KE >> 32;
+ k2 = KE & MASK32;
+ x2 = x2 ^ LR32((x1 & k1), 1);
+ x1 = x1 ^ (x2 | k2);
+ return ((uint64_t)x1 << 32) | (uint64_t)x2;
+}
+
+static uint64_t FLINV(uint64_t FLINV_IN, uint64_t KE)
+{
+ uint32_t x1, x2, k1, k2;
+ x1 = FLINV_IN >> 32;
+ x2 = FLINV_IN & MASK32;
+ k1 = KE >> 32;
+ k2 = KE & MASK32;
+ x1 = x1 ^ (x2 | k2);
+ x2 = x2 ^ LR32((x1 & k1), 1);
+ return ((uint64_t)x1 << 32) | (uint64_t)x2;
+}
+
+static const uint8_t shifts[2][12] = {
+ {0, 15, 15, 45, 45, 60, 94, 94, 111},
+ {0, 15, 15, 30, 45, 45, 60, 60, 77, 94, 94, 111}
+};
+
+static const uint8_t vars[2][12] = {
+ {2, 0, 2, 0, 2, 2, 0, 2, 0},
+ {3, 1, 2, 3, 0, 2, 1, 3, 0, 1, 2, 0}
+};
+
+static void generate_round_keys(AVCAMELLIA *cs, uint64_t Kl[2], uint64_t Kr[2], uint64_t Ka[2], uint64_t Kb[2])
+{
+ int i;
+ uint64_t *Kd[4], d[2];
+ Kd[0] = Kl;
+ Kd[1] = Kr;
+ Kd[2] = Ka;
+ Kd[3] = Kb;
+ cs->Kw[0] = Kl[0];
+ cs->Kw[1] = Kl[1];
+ if (cs->key_bits == 128) {
+ for (i = 0; i < 9; i++) {
+ LR128(d, Kd[vars[0][i]], shifts[0][i]);
+ cs->K[2*i] = d[0];
+ cs->K[2*i+1] = d[1];
+ }
+ LR128(d, Kd[0], 60);
+ cs->K[9] = d[1];
+ LR128(d, Kd[2], 30);
+ cs->Ke[0] = d[0];
+ cs->Ke[1] = d[1];
+ LR128(d, Kd[0], 77);
+ cs->Ke[2] = d[0];
+ cs->Ke[3] = d[1];
+ LR128(d, Kd[2], 111);
+ cs->Kw[2] = d[0];
+ cs->Kw[3] = d[1];
+ } else {
+ for (i = 0; i < 12; i++) {
+ LR128(d, Kd[vars[1][i]], shifts[1][i]);
+ cs->K[2*i] = d[0];
+ cs->K[2*i+1] = d[1];
+ }
+ LR128(d, Kd[1], 30);
+ cs->Ke[0] = d[0];
+ cs->Ke[1] = d[1];
+ LR128(d, Kd[0], 60);
+ cs->Ke[2] = d[0];
+ cs->Ke[3] = d[1];
+ LR128(d, Kd[2], 77);
+ cs->Ke[4] = d[0];
+ cs->Ke[5] = d[1];
+ LR128(d, Kd[3], 111);
+ cs->Kw[2] = d[0];
+ cs->Kw[3] = d[1];
+ }
+}
+
+static void camellia_encrypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src)
+{
+ uint64_t D1, D2;
+ D1 = AV_RB64(src);
+ D2 = AV_RB64(src + 8);
+ D1 ^= cs->Kw[0];
+ D2 ^= cs->Kw[1];
+ D2 ^= F(D1, cs->K[0]);
+ D1 ^= F(D2, cs->K[1]);
+ D2 ^= F(D1, cs->K[2]);
+ D1 ^= F(D2, cs->K[3]);
+ D2 ^= F(D1, cs->K[4]);
+ D1 ^= F(D2, cs->K[5]);
+ D1 = FL(D1, cs->Ke[0]);
+ D2 = FLINV(D2, cs->Ke[1]);
+ D2 ^= F(D1, cs->K[6]);
+ D1 ^= F(D2, cs->K[7]);
+ D2 ^= F(D1, cs->K[8]);
+ D1 ^= F(D2, cs->K[9]);
+ D2 ^= F(D1, cs->K[10]);
+ D1 ^= F(D2, cs->K[11]);
+ D1 = FL(D1, cs->Ke[2]);
+ D2 = FLINV(D2, cs->Ke[3]);
+ D2 ^= F(D1, cs->K[12]);
+ D1 ^= F(D2, cs->K[13]);
+ D2 ^= F(D1, cs->K[14]);
+ D1 ^= F(D2, cs->K[15]);
+ D2 ^= F(D1, cs->K[16]);
+ D1 ^= F(D2, cs->K[17]);
+ if (cs->key_bits != 128) {
+ D1 = FL(D1, cs->Ke[4]);
+ D2 = FLINV(D2, cs->Ke[5]);
+ D2 ^= F(D1, cs->K[18]);
+ D1 ^= F(D2, cs->K[19]);
+ D2 ^= F(D1, cs->K[20]);
+ D1 ^= F(D2, cs->K[21]);
+ D2 ^= F(D1, cs->K[22]);
+ D1 ^= F(D2, cs->K[23]);
+ }
+ D2 ^= cs->Kw[2];
+ D1 ^= cs->Kw[3];
+ AV_WB64(dst, D2);
+ AV_WB64(dst + 8, D1);
+}
+
+static void camellia_decrypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src, uint8_t *iv)
+{
+ uint64_t D1, D2;
+ D1 = AV_RB64(src);
+ D2 = AV_RB64(src + 8);
+ D1 ^= cs->Kw[2];
+ D2 ^= cs->Kw[3];
+ if (cs->key_bits != 128) {
+ D2 ^= F(D1, cs->K[23]);
+ D1 ^= F(D2, cs->K[22]);
+ D2 ^= F(D1, cs->K[21]);
+ D1 ^= F(D2, cs->K[20]);
+ D2 ^= F(D1, cs->K[19]);
+ D1 ^= F(D2, cs->K[18]);
+ D1 = FL(D1, cs->Ke[5]);
+ D2 = FLINV(D2, cs->Ke[4]);
+ }
+ D2 ^= F(D1, cs->K[17]);
+ D1 ^= F(D2, cs->K[16]);
+ D2 ^= F(D1, cs->K[15]);
+ D1 ^= F(D2, cs->K[14]);
+ D2 ^= F(D1, cs->K[13]);
+ D1 ^= F(D2, cs->K[12]);
+ D1 = FL(D1, cs->Ke[3]);
+ D2 = FLINV(D2, cs->Ke[2]);
+ D2 ^= F(D1, cs->K[11]);
+ D1 ^= F(D2, cs->K[10]);
+ D2 ^= F(D1, cs->K[9]);
+ D1 ^= F(D2, cs->K[8]);
+ D2 ^= F(D1, cs->K[7]);
+ D1 ^= F(D2, cs->K[6]);
+ D1 = FL(D1, cs->Ke[1]);
+ D2 = FLINV(D2, cs->Ke[0]);
+ D2 ^= F(D1, cs->K[5]);
+ D1 ^= F(D2, cs->K[4]);
+ D2 ^= F(D1, cs->K[3]);
+ D1 ^= F(D2, cs->K[2]);
+ D2 ^= F(D1, cs->K[1]);
+ D1 ^= F(D2, cs->K[0]);
+ D2 ^= cs->Kw[0];
+ D1 ^= cs->Kw[1];
+ if (iv) {
+ D2 ^= AV_RB64(iv);
+ D1 ^= AV_RB64(iv + 8);
+ memcpy(iv, src, 16);
+ }
+ AV_WB64(dst, D2);
+ AV_WB64(dst + 8, D1);
+}
+
+static void computeSP(void)
+{
+ uint64_t z;
+ int i;
+ for (i = 0; i < 256; i++) {
+ z = SBOX1[i];
+ SP[0][i] = (z << 56) ^ (z << 48) ^ (z << 40) ^ (z << 24) ^ z;
+ SP[7][i] = (z << 56) ^ (z << 48) ^ (z << 40) ^ (z << 24) ^ (z << 16) ^ (z << 8);
+ z = SBOX2[i];
+ SP[1][i] = (z << 48) ^ (z << 40) ^ (z << 32) ^ (z << 24) ^ (z << 16);
+ SP[4][i] = (z << 48) ^ (z << 40) ^ (z << 32) ^ (z << 16) ^ (z << 8) ^ z;
+ z = SBOX3[i];
+ SP[2][i] = (z << 56) ^ (z << 40) ^ (z << 32) ^ (z << 16) ^ (z << 8);
+ SP[5][i] = (z << 56) ^ (z << 40) ^ (z << 32) ^ (z << 24) ^ (z << 8) ^ z;
+ z = SBOX4[i];
+ SP[3][i] = (z << 56) ^ (z << 48) ^ (z << 32) ^ (z << 8) ^ z;
+ SP[6][i] = (z << 56) ^ (z << 48) ^ (z << 32) ^ (z << 24) ^ (z << 16) ^ z;
+ }
+}
+
+struct AVCAMELLIA *av_camellia_alloc(void)
+{
+ return av_mallocz(sizeof(struct AVCAMELLIA));
+}
+
+av_cold int av_camellia_init(AVCAMELLIA *cs, const uint8_t *key, int key_bits)
+{
+ uint64_t Kl[2], Kr[2], Ka[2], Kb[2];
+ uint64_t D1, D2;
+ if (key_bits != 128 && key_bits != 192 && key_bits != 256)
+ return -1;
+ memset(Kb, 0, sizeof(Kb));
+ memset(Kr, 0, sizeof(Kr));
+ cs->key_bits = key_bits;
+ Kl[0] = AV_RB64(key);
+ Kl[1] = AV_RB64(key + 8);
+ if (key_bits == 192) {
+ Kr[0] = AV_RB64(key + 16);
+ Kr[1] = ~Kr[0];
+ } else if (key_bits == 256) {
+ Kr[0] = AV_RB64(key + 16);
+ Kr[1] = AV_RB64(key + 24);
+ }
+ computeSP();
+ D1 = Kl[0] ^ Kr[0];
+ D2 = Kl[1] ^ Kr[1];
+ D2 ^= F(D1, Sigma1);
+ D1 ^= F(D2, Sigma2);
+ D1 ^= Kl[0];
+ D2 ^= Kl[1];
+ D2 ^= F(D1, Sigma3);
+ D1 ^= F(D2, Sigma4);
+ Ka[0] = D1;
+ Ka[1] = D2;
+ if (key_bits != 128) {
+ D1 = Ka[0] ^ Kr[0];
+ D2 = Ka[1] ^ Kr[1];
+ D2 ^= F(D1, Sigma5);
+ D1 ^= F(D2, Sigma6);
+ Kb[0] = D1;
+ Kb[1] = D2;
+ }
+ generate_round_keys(cs, Kl, Kr, Ka, Kb);
+ return 0;
+}
+
+void av_camellia_crypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt)
+{
+ int i;
+ while (count--) {
+ if (decrypt) {
+ camellia_decrypt(cs, dst, src, iv);
+ } else {
+ if (iv) {
+ for (i = 0; i < 16; i++)
+ dst[i] = src[i] ^ iv[i];
+ camellia_encrypt(cs, dst, dst);
+ memcpy(iv, dst, 16);
+ } else {
+ camellia_encrypt(cs, dst, src);
+ }
+ }
+ src = src + 16;
+ dst = dst + 16;
+ }
+}
+
+#ifdef TEST
+#include<stdio.h>
+#include<stdlib.h>
+#include"log.h"
+
+int main(int argc, char *argv[])
+{
+ const uint8_t Key[3][32] = {
+ {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77},
+ {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}
+ };
+ const uint8_t rct[3][16] = {
+ {0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43},
+ {0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9,0x96, 0xf8, 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9},
+ {0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09}
+ };
+ const uint8_t rpt[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
+ const int kbits[3] = {128, 192, 256};
+ int i, j, err = 0;
+ uint8_t temp[32], iv[16];
+ AVCAMELLIA *cs;
+ cs = av_camellia_alloc();
+ if (!cs)
+ return 1;
+ for (j = 0; j < 3; j++) {
+ av_camellia_init(cs, Key[j], kbits[j]);
+ av_camellia_crypt(cs, temp, rpt, 1, NULL, 0);
+ for (i = 0; i < 16; i++) {
+ if (rct[j][i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rct[j][i], temp[i]);
+ err = 1;
+ }
+ }
+ av_camellia_crypt(cs, temp, rct[j], 1, NULL, 1);
+ for (i = 0; i < 16; i++) {
+ if (rpt[i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rpt[i], temp[i]);
+ err = 1;
+ }
+ }
+ }
+ av_camellia_init(cs, Key[0], 128);
+ memcpy(iv, "HALLO123HALLO123", 16);
+ av_camellia_crypt(cs, temp, rpt, 2, iv, 0);
+ memcpy(iv, "HALLO123HALLO123", 16);
+ av_camellia_crypt(cs, temp, temp, 2, iv, 1);
+ for (i = 0; i < 32; i++) {
+ if (rpt[i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rpt[i], temp[i]);
+ err = 1;
+ }
+ }
+ av_free(cs);
+ return err;
+}
+#endif
diff --git a/libavutil/camellia.h b/libavutil/camellia.h
new file mode 100644
index 0000000000..e674c9b9a4
--- /dev/null
+++ b/libavutil/camellia.h
@@ -0,0 +1,70 @@
+/*
+ * An implementation of the CAMELLIA algorithm as mentioned in RFC3713
+ * Copyright (c) 2014 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_CAMELLIA_H
+#define AVUTIL_CAMELLIA_H
+
+#include <stdint.h>
+
+
+/**
+ * @file
+ * @brief Public header for libavutil CAMELLIA algorithm
+ * @defgroup lavu_camellia CAMELLIA
+ * @ingroup lavu_crypto
+ * @{
+ */
+
+extern const int av_camellia_size;
+
+struct AVCAMELLIA;
+
+/**
+ * Allocate an AVCAMELLIA context
+ * To free the struct: av_free(ptr)
+ */
+struct AVCAMELLIA *av_camellia_alloc(void);
+
+/**
+ * Initialize an AVCAMELLIA context.
+ *
+ * @param ctx an AVCAMELLIA context
+ * @param key a key of 16, 24, 32 bytes used for encryption/decryption
+ * @param key_bits number of keybits: possible are 128, 192, 256
+ */
+int av_camellia_init(struct AVCAMELLIA *ctx, const uint8_t *key, int key_bits);
+
+/**
+ * Encrypt or decrypt a buffer using a previously initialized context
+ *
+ * @param ctx an AVCAMELLIA context
+ * @param dst destination array, can be equal to src
+ * @param src source array, can be equal to dst
+ * @param count number of 16 byte blocks
+ * @paran iv initialization vector for CBC mode, NULL for ECB mode
+ * @param decrypt 0 for encryption, 1 for decryption
+ */
+void av_camellia_crypt(struct AVCAMELLIA *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt);
+
+/**
+ * @}
+ */
+#endif /* AVUTIL_CAMELLIA_H */
diff --git a/libavutil/cast5.c b/libavutil/cast5.c
new file mode 100644
index 0000000000..98aa19d630
--- /dev/null
+++ b/libavutil/cast5.c
@@ -0,0 +1,593 @@
+/*
+ * An implementation of the CAST128 algorithm as mentioned in RFC2144
+ * Copyright (c) 2014 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "cast5.h"
+#include "common.h"
+#include "intreadwrite.h"
+#include "attributes.h"
+
+#define IA(x) ((x) >> 24)
+#define IB(x) (((x) >> 16) & 0xff)
+#define IC(x) (((x) >> 8) & 0xff)
+#define ID(x) ((x) & 0xff)
+
+#define LR(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+
+#define F3(l, r, i) \
+ do { \
+ I = LR(cs->Km[i] - r, cs->Kr[i]); \
+ f = ((S1[IA(I)] + S2[IB(I)]) ^ S3[IC(I)]) - S4[ID(I)]; \
+ l = f ^ l; \
+ } while (0)
+
+#define F2(l, r, i) \
+ do { \
+ I = LR(cs->Km[i] ^ r, cs->Kr[i]); \
+ f = ((S1[IA(I)] - S2[IB(I)]) + S3[IC(I)]) ^ S4[ID(I)]; \
+ l = f ^ l; \
+ } while (0)
+
+#define F1(l, r, i) \
+ do { \
+ I = LR(cs->Km[i] + r, cs->Kr[i]); \
+ f = ((S1[IA(I)] ^ S2[IB(I)]) - S3[IC(I)]) + S4[ID(I)]; \
+ l = f ^ l; \
+ } while (0)
+
+#define COMPUTE_Z \
+ do { \
+ z[0] = x[0] ^ S5[IB(x[3])] ^ S6[ID(x[3])] ^ S7[IA(x[3])] ^ S8[IC(x[3])] ^ S7[IA(x[2])]; \
+ z[1] = x[2] ^ S5[IA(z[0])] ^ S6[IC(z[0])] ^ S7[IB(z[0])] ^ S8[ID(z[0])] ^ S8[IC(x[2])]; \
+ z[2] = x[3] ^ S5[ID(z[1])] ^ S6[IC(z[1])] ^ S7[IB(z[1])] ^ S8[IA(z[1])] ^ S5[IB(x[2])]; \
+ z[3] = x[1] ^ S5[IC(z[2])] ^ S6[IB(z[2])] ^ S7[ID(z[2])] ^ S8[IA(z[2])] ^ S6[ID(x[2])]; \
+ } while (0)
+
+#define COMPUTE_X \
+ do { \
+ x[0] = z[2] ^ S5[IB(z[1])] ^ S6[ID(z[1])] ^ S7[IA(z[1])] ^ S8[IC(z[1])] ^ S7[IA(z[0])]; \
+ x[1] = z[0] ^ S5[IA(x[0])] ^ S6[IC(x[0])] ^ S7[IB(x[0])] ^ S8[ID(x[0])] ^ S8[IC(z[0])]; \
+ x[2] = z[1] ^ S5[ID(x[1])] ^ S6[IC(x[1])] ^ S7[IB(x[1])] ^ S8[IA(x[1])] ^ S5[IB(z[0])]; \
+ x[3] = z[3] ^ S5[IC(x[2])] ^ S6[IB(x[2])] ^ S7[ID(x[2])] ^ S8[IA(x[2])] ^ S6[ID(z[0])]; \
+ } while (0)
+
+
+typedef struct AVCAST5 {
+ uint32_t Km[17];
+ uint32_t Kr[17];
+ int rounds;
+} AVCAST5;
+
+const int av_cast5_size = sizeof(AVCAST5);
+
+static const uint32_t S1[256] = {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+ 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+ 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+ 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+ 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+ 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+ 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+ 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+ 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+ 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+ 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+ 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+ 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+ 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+ 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+ 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+ 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+ 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+ 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+ 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+ 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+ 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+};
+
+static const uint32_t S2[256] = {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+ 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+ 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+ 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+ 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+ 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+ 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+ 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+ 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+ 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+ 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+ 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+ 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+ 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+ 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+ 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+ 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+ 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+ 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+ 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+ 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+ 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
+};
+
+static const uint32_t S3[256] = {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+ 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+ 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+ 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+ 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+ 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+ 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+ 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+ 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+ 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+ 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+ 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+ 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+ 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+ 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+ 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+ 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+ 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+ 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+ 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+ 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+ 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
+};
+
+static const uint32_t S4[256] = {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+ 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+ 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+ 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+ 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+ 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+ 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+ 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+ 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+ 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+ 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+ 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+ 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+ 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+ 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+ 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+ 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+ 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+ 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+ 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+ 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+ 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+};
+
+static const uint32_t S5[256] = {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+ 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+ 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+ 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+ 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+ 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+ 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+ 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+ 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+ 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+ 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+ 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+ 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+ 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+ 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+ 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+ 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+ 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+ 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+ 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+ 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+ 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
+};
+
+static const uint32_t S6[256] = {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+ 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+ 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+ 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+ 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+ 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+ 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+ 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+ 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+ 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+ 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+ 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+ 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+ 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+ 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+ 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+ 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+ 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+ 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+ 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+ 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+ 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
+};
+
+static const uint32_t S7[256] = {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+ 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+ 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+ 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+ 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+ 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+ 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+ 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+ 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+ 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+ 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+ 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+ 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+ 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+ 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+ 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+ 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+ 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+ 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+ 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+ 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+ 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
+};
+
+static const uint32_t S8[256] = {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+ 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+ 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+ 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+ 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+ 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+ 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+ 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+ 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+ 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+ 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+ 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+ 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+ 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+ 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+ 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+ 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+ 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+ 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+ 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+ 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+ 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
+};
+
+static void generate_round_keys(int rnds, uint32_t* K, uint32_t* x, uint32_t* z)
+{
+ COMPUTE_Z;
+
+ K[1] = S5[IA(z[2])] ^ S6[IB(z[2])] ^ S7[ID(z[1])] ^ S8[IC(z[1])] ^ S5[IC(z[0])];
+ K[2] = S5[IC(z[2])] ^ S6[ID(z[2])] ^ S7[IB(z[1])] ^ S8[IA(z[1])] ^ S6[IC(z[1])];
+ K[3] = S5[IA(z[3])] ^ S6[IB(z[3])] ^ S7[ID(z[0])] ^ S8[IC(z[0])] ^ S7[IB(z[2])];
+ K[4] = S5[IC(z[3])] ^ S6[ID(z[3])] ^ S7[IB(z[0])] ^ S8[IA(z[0])] ^ S8[IA(z[3])];
+
+ COMPUTE_X;
+
+ K[5] = S5[ID(x[0])] ^ S6[IC(x[0])] ^ S7[IA(x[3])] ^ S8[IB(x[3])] ^ S5[IA(x[2])];
+ K[6] = S5[IB(x[0])] ^ S6[IA(x[0])] ^ S7[IC(x[3])] ^ S8[ID(x[3])] ^ S6[IB(x[3])];
+ K[7] = S5[ID(x[1])] ^ S6[IC(x[1])] ^ S7[IA(x[2])] ^ S8[IB(x[2])] ^ S7[ID(x[0])];
+ K[8] = S5[IB(x[1])] ^ S6[IA(x[1])] ^ S7[IC(x[2])] ^ S8[ID(x[2])] ^ S8[ID(x[1])];
+
+ COMPUTE_Z;
+
+ K[9] = S5[ID(z[0])] ^ S6[IC(z[0])] ^ S7[IA(z[3])] ^ S8[IB(z[3])] ^ S5[IB(z[2])];
+ K[10] = S5[IB(z[0])] ^ S6[IA(z[0])] ^ S7[IC(z[3])] ^ S8[ID(z[3])] ^ S6[IA(z[3])];
+ K[11] = S5[ID(z[1])] ^ S6[IC(z[1])] ^ S7[IA(z[2])] ^ S8[IB(z[2])] ^ S7[IC(z[0])];
+ K[12] = S5[IB(z[1])] ^ S6[IA(z[1])] ^ S7[IC(z[2])] ^ S8[ID(z[2])] ^ S8[IC(z[1])];
+
+ COMPUTE_X;
+
+ if (rnds == 16) {
+ K[13] = S5[IA(x[2])] ^ S6[IB(x[2])] ^ S7[ID(x[1])] ^ S8[IC(x[1])] ^ S5[ID(x[0])];
+ K[14] = S5[IC(x[2])] ^ S6[ID(x[2])] ^ S7[IB(x[1])] ^ S8[IA(x[1])] ^ S6[ID(x[1])];
+ K[15] = S5[IA(x[3])] ^ S6[IB(x[3])] ^ S7[ID(x[0])] ^ S8[IC(x[0])] ^ S7[IA(x[2])];
+ K[16] = S5[IC(x[3])] ^ S6[ID(x[3])] ^ S7[IB(x[0])] ^ S8[IA(x[0])] ^ S8[IB(x[3])];
+ }
+}
+
+static void encipher(AVCAST5* cs, uint8_t* dst, const uint8_t* src)
+{
+ uint32_t r, l, f, I;
+ l = AV_RB32(src);
+ r = AV_RB32(src + 4);
+ F1(l, r, 1);
+ F2(r, l, 2);
+ F3(l, r, 3);
+ F1(r, l, 4);
+ F2(l, r, 5);
+ F3(r, l, 6);
+ F1(l, r, 7);
+ F2(r, l, 8);
+ F3(l, r, 9);
+ F1(r, l, 10);
+ F2(l, r, 11);
+ F3(r, l, 12);
+ if (cs->rounds == 16) {
+ F1(l, r, 13);
+ F2(r, l, 14);
+ F3(l, r, 15);
+ F1(r, l, 16);
+ }
+ AV_WB32(dst, r);
+ AV_WB32(dst + 4, l);
+}
+
+static void decipher(AVCAST5* cs, uint8_t* dst, const uint8_t* src, uint8_t *iv)
+{
+ uint32_t f, I, r, l;
+ l = AV_RB32(src);
+ r = AV_RB32(src + 4);
+ if (cs->rounds == 16) {
+ F1(l, r, 16);
+ F3(r, l, 15);
+ F2(l, r, 14);
+ F1(r, l, 13);
+ }
+ F3(l, r, 12);
+ F2(r, l, 11);
+ F1(l, r, 10);
+ F3(r, l, 9);
+ F2(l, r, 8);
+ F1(r, l, 7);
+ F3(l, r, 6);
+ F2(r, l, 5);
+ F1(l, r, 4);
+ F3(r, l, 3);
+ F2(l, r, 2);
+ F1(r, l, 1);
+ if (iv) {
+ r ^= AV_RB32(iv);
+ l ^= AV_RB32(iv + 4);
+ memcpy(iv, src, 8);
+ }
+ AV_WB32(dst, r);
+ AV_WB32(dst + 4, l);
+}
+
+struct AVCAST5 *av_cast5_alloc(void)
+{
+ return av_mallocz(sizeof(struct AVCAST5));
+}
+
+av_cold int av_cast5_init(AVCAST5* cs, const uint8_t *key, int key_bits)
+{
+ uint8_t newKey[16];
+ int i;
+ uint32_t p[4], q[4];
+ if (key_bits % 8 || key_bits < 40 || key_bits > 128)
+ return -1;
+ memset(newKey, 0, sizeof(newKey));
+ memcpy(newKey, key, key_bits >> 3);
+
+ cs->rounds = key_bits <= 80 ? 12 : 16;
+ for (i = 0; i < 4; i++)
+ q[i] = AV_RB32(newKey + (4 * i));
+ generate_round_keys(cs->rounds, cs->Km, q, p);
+ generate_round_keys(cs->rounds, cs->Kr, q, p);
+ for (i = 0; i <= cs->rounds; i++)
+ cs->Kr[i] = cs->Kr[i] & 0x1f;
+ return 0;
+}
+
+void av_cast5_crypt2(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, uint8_t *iv, int decrypt)
+{
+ int i;
+ while (count--) {
+ if (decrypt) {
+ decipher(cs, dst, src, iv);
+ } else {
+ if (iv) {
+ for (i = 0; i < 8; i++)
+ dst[i] = src[i] ^ iv[i];
+ encipher(cs, dst, dst);
+ memcpy(iv, dst, 8);
+ } else {
+ encipher(cs, dst, src);
+ }
+ }
+ src = src + 8;
+ dst = dst + 8;
+ }
+}
+void av_cast5_crypt(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, int decrypt)
+{
+ while (count--) {
+ if (decrypt){
+ decipher(cs, dst, src, NULL);
+ } else {
+ encipher(cs, dst, src);
+ }
+ src = src + 8;
+ dst = dst + 8;
+ }
+}
+
+#ifdef TEST
+#include<stdio.h>
+#include<stdlib.h>
+#include"log.h"
+
+int main(int argc, char** argv)
+{
+
+ static const uint8_t Key[3][16] = {
+ {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9a},
+ {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45},
+ {0x01, 0x23, 0x45, 0x67, 0x12}
+ };
+ static const uint8_t rpt[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ static const uint8_t rct[3][8] = {
+ {0x23, 0x8b, 0x4f, 0xe5, 0x84, 0x7e, 0x44, 0xb2},
+ {0xeb, 0x6a, 0x71, 0x1a, 0x2c, 0x02, 0x27, 0x1b},
+ {0x7a, 0xc8, 0x16, 0xd1, 0x6e, 0x9b, 0x30, 0x2e}
+ };
+ static const uint8_t rct2[2][16] = {
+ {0xee, 0xa9, 0xd0, 0xa2, 0x49, 0xfd, 0x3b, 0xa6, 0xb3, 0x43, 0x6f, 0xb8, 0x9d, 0x6d, 0xca, 0x92},
+ {0xb2, 0xc9, 0x5e, 0xb0, 0x0c, 0x31, 0xad, 0x71, 0x80, 0xac, 0x05, 0xb8, 0xe8, 0x3d, 0x69, 0x6e}
+ };
+ static const uint8_t iv[8] = {0xee, 0xa9, 0xd0, 0xa2, 0x49, 0xfd, 0x3b, 0xa6};
+ static uint8_t rpt2[2][16];
+ int i, j, err = 0;
+ static const int key_bits[3] = {128, 80, 40};
+ uint8_t temp[8];
+ AVCAST5 *cs;
+ cs = av_cast5_alloc();
+ if (!cs)
+ return 1;
+ for (j = 0; j < 3; j++){
+
+ av_cast5_init(cs, Key[j], key_bits[j]);
+ av_cast5_crypt(cs, temp, rpt, 1, 0);
+ for (i = 0;i < 8; i++){
+ if (rct[j][i] != temp[i]){
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rct[j][i], temp[i]);
+ err = 1;
+ }
+ }
+
+ av_cast5_crypt(cs, temp, rct[j], 1, 1);
+ for (i =0; i < 8; i++) {
+ if (rpt[i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rpt[i], temp[i]);
+ err = 1;
+ }
+ }
+ }
+ memcpy(rpt2[0], Key[0], 16);
+ memcpy(rpt2[1], Key[0], 16);
+ for (i = 0; i < 1000000; i++){
+ av_cast5_init(cs, rpt2[1], 128);
+ av_cast5_crypt(cs, rpt2[0], rpt2[0], 2, 0);
+ av_cast5_init(cs, rpt2[0], 128);
+ av_cast5_crypt(cs, rpt2[1], rpt2[1], 2, 0);
+ }
+ for (j = 0; j < 2; j++) {
+ for (i = 0; i < 16; i++) {
+ if (rct2[j][i] != rpt2[j][i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rct2[j][i], rpt2[j][i]);
+ err = 1;
+ }
+ }
+ }
+ for (j = 0; j < 3; j++) {
+
+ av_cast5_init(cs, Key[j], key_bits[j]);
+ memcpy(temp, iv, 8);
+ av_cast5_crypt2(cs, rpt2[0], rct2[0], 2, temp, 0);
+ memcpy(temp, iv, 8);
+ av_cast5_crypt2(cs, rpt2[0], rpt2[0], 2, temp, 1);
+ for (i = 0; i < 16; i++) {
+ if (rct2[0][i] != rpt2[0][i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rct2[0][i], rpt2[0][i]);
+ err = 1;
+ }
+ }
+ }
+ av_free(cs);
+ return err;
+}
+#endif
diff --git a/libavutil/cast5.h b/libavutil/cast5.h
new file mode 100644
index 0000000000..e5cc8b1102
--- /dev/null
+++ b/libavutil/cast5.h
@@ -0,0 +1,79 @@
+/*
+ * An implementation of the CAST128 algorithm as mentioned in RFC2144
+ * Copyright (c) 2014 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_CAST5_H
+#define AVUTIL_CAST5_H
+
+#include <stdint.h>
+
+
+/**
+ * @file
+ * @brief Public header for libavutil CAST5 algorithm
+ * @defgroup lavu_cast5 CAST5
+ * @ingroup lavu_crypto
+ * @{
+ */
+
+extern const int av_cast5_size;
+
+struct AVCAST5;
+
+/**
+ * Allocate an AVCAST5 context
+ * To free the struct: av_free(ptr)
+ */
+struct AVCAST5 *av_cast5_alloc(void);
+/**
+ * Initialize an AVCAST5 context.
+ *
+ * @param ctx an AVCAST5 context
+ * @param key a key of 5,6,...16 bytes used for encryption/decryption
+ * @param key_bits number of keybits: possible are 40,48,...,128
+ */
+int av_cast5_init(struct AVCAST5 *ctx, const uint8_t *key, int key_bits);
+
+/**
+ * Encrypt or decrypt a buffer using a previously initialized context, ECB mode only
+ *
+ * @param ctx an AVCAST5 context
+ * @param dst destination array, can be equal to src
+ * @param src source array, can be equal to dst
+ * @param count number of 8 byte blocks
+ * @param decrypt 0 for encryption, 1 for decryption
+ */
+void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, int decrypt);
+
+/**
+ * Encrypt or decrypt a buffer using a previously initialized context
+ *
+ * @param ctx an AVCAST5 context
+ * @param dst destination array, can be equal to src
+ * @param src source array, can be equal to dst
+ * @param count number of 8 byte blocks
+ * @param iv initialization vector for CBC mode, NULL for ECB mode
+ * @param decrypt 0 for encryption, 1 for decryption
+ */
+void av_cast5_crypt2(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt);
+/**
+ * @}
+ */
+#endif /* AVUTIL_CAST5_H */
diff --git a/libavutil/channel_layout.c b/libavutil/channel_layout.c
index 253c495f4f..4c0677f794 100644
--- a/libavutil/channel_layout.c
+++ b/libavutil/channel_layout.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,41 +28,47 @@
#include "avstring.h"
#include "avutil.h"
#include "channel_layout.h"
+#include "bprint.h"
#include "common.h"
-static const char * const channel_names[] = {
- [0] = "FL", /* front left */
- [1] = "FR", /* front right */
- [2] = "FC", /* front center */
- [3] = "LFE", /* low frequency */
- [4] = "BL", /* back left */
- [5] = "BR", /* back right */
- [6] = "FLC", /* front left-of-center */
- [7] = "FRC", /* front right-of-center */
- [8] = "BC", /* back-center */
- [9] = "SL", /* side left */
- [10] = "SR", /* side right */
- [11] = "TC", /* top center */
- [12] = "TFL", /* top front left */
- [13] = "TFC", /* top front center */
- [14] = "TFR", /* top front right */
- [15] = "TBL", /* top back left */
- [16] = "TBC", /* top back center */
- [17] = "TBR", /* top back right */
- [29] = "DL", /* downmix left */
- [30] = "DR", /* downmix right */
- [31] = "WL", /* wide left */
- [32] = "WR", /* wide right */
- [33] = "SDL", /* surround direct left */
- [34] = "SDR", /* surround direct right */
- [35] = "LFE2", /* low frequency 2 */
+struct channel_name {
+ const char *name;
+ const char *description;
+};
+
+static const struct channel_name channel_names[] = {
+ [0] = { "FL", "front left" },
+ [1] = { "FR", "front right" },
+ [2] = { "FC", "front center" },
+ [3] = { "LFE", "low frequency" },
+ [4] = { "BL", "back left" },
+ [5] = { "BR", "back right" },
+ [6] = { "FLC", "front left-of-center" },
+ [7] = { "FRC", "front right-of-center" },
+ [8] = { "BC", "back center" },
+ [9] = { "SL", "side left" },
+ [10] = { "SR", "side right" },
+ [11] = { "TC", "top center" },
+ [12] = { "TFL", "top front left" },
+ [13] = { "TFC", "top front center" },
+ [14] = { "TFR", "top front right" },
+ [15] = { "TBL", "top back left" },
+ [16] = { "TBC", "top back center" },
+ [17] = { "TBR", "top back right" },
+ [29] = { "DL", "downmix left" },
+ [30] = { "DR", "downmix right" },
+ [31] = { "WL", "wide left" },
+ [32] = { "WR", "wide right" },
+ [33] = { "SDL", "surround direct left" },
+ [34] = { "SDR", "surround direct right" },
+ [35] = { "LFE2", "low frequency 2" },
};
static const char *get_channel_name(int channel_id)
{
if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
return NULL;
- return channel_names[channel_id];
+ return channel_names[channel_id].name;
}
static const struct {
@@ -72,19 +78,18 @@ static const struct {
} channel_layout_map[] = {
{ "mono", 1, AV_CH_LAYOUT_MONO },
{ "stereo", 2, AV_CH_LAYOUT_STEREO },
- { "stereo", 2, AV_CH_LAYOUT_STEREO_DOWNMIX },
{ "2.1", 3, AV_CH_LAYOUT_2POINT1 },
{ "3.0", 3, AV_CH_LAYOUT_SURROUND },
{ "3.0(back)", 3, AV_CH_LAYOUT_2_1 },
- { "3.1", 4, AV_CH_LAYOUT_3POINT1 },
{ "4.0", 4, AV_CH_LAYOUT_4POINT0 },
{ "quad", 4, AV_CH_LAYOUT_QUAD },
{ "quad(side)", 4, AV_CH_LAYOUT_2_2 },
- { "4.1", 5, AV_CH_LAYOUT_4POINT1 },
- { "5.0", 5, AV_CH_LAYOUT_5POINT0 },
+ { "3.1", 4, AV_CH_LAYOUT_3POINT1 },
{ "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK },
- { "5.1", 6, AV_CH_LAYOUT_5POINT1 },
+ { "5.0(side)", 5, AV_CH_LAYOUT_5POINT0 },
+ { "4.1", 5, AV_CH_LAYOUT_4POINT1 },
{ "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
+ { "5.1(side)", 6, AV_CH_LAYOUT_5POINT1 },
{ "6.0", 6, AV_CH_LAYOUT_6POINT0 },
{ "6.0(front)", 6, AV_CH_LAYOUT_6POINT0_FRONT },
{ "hexagonal", 6, AV_CH_LAYOUT_HEXAGONAL },
@@ -94,40 +99,67 @@ static const struct {
{ "7.0", 7, AV_CH_LAYOUT_7POINT0 },
{ "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT },
{ "7.1", 8, AV_CH_LAYOUT_7POINT1 },
- { "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
{ "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE_BACK },
+ { "7.1(wide-side)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
{ "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL },
{ "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, },
- { 0 }
};
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+static uint64_t get_channel_layout_single(const char *name, int name_len, int compat)
+#else
static uint64_t get_channel_layout_single(const char *name, int name_len)
+#endif
{
int i;
char *end;
int64_t layout;
- for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map) - 1; i++) {
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
if (strlen(channel_layout_map[i].name) == name_len &&
!memcmp(channel_layout_map[i].name, name, name_len))
return channel_layout_map[i].layout;
}
for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
- if (channel_names[i] &&
- strlen(channel_names[i]) == name_len &&
- !memcmp(channel_names[i], name, name_len))
+ if (channel_names[i].name &&
+ strlen(channel_names[i].name) == name_len &&
+ !memcmp(channel_names[i].name, name, name_len))
return (int64_t)1 << i;
i = strtol(name, &end, 10);
- if (end - name == name_len ||
- (end + 1 - name == name_len && *end == 'c'))
+
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+ if (compat) {
+ if (end - name == name_len ||
+ (end + 1 - name == name_len && *end == 'c')) {
+ layout = av_get_default_channel_layout(i);
+ if (end - name == name_len) {
+ av_log(NULL, AV_LOG_WARNING,
+ "Single channel layout '%.*s' is interpreted as a number of channels, "
+ "switch to the syntax '%.*sc' otherwise it will be interpreted as a "
+ "channel layout number in a later version\n",
+ name_len, name, name_len, name);
+ return layout;
+ }
+ }
+ } else {
+#endif
+ if ((end + 1 - name == name_len && *end == 'c'))
return av_get_default_channel_layout(i);
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+ }
+#endif
+
layout = strtoll(name, &end, 0);
if (end - name == name_len)
return FFMAX(layout, 0);
return 0;
}
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+uint64_t ff_get_channel_layout(const char *name, int compat)
+#else
uint64_t av_get_channel_layout(const char *name)
+#endif
{
const char *n, *e;
const char *name_end = name + strlen(name);
@@ -135,7 +167,11 @@ uint64_t av_get_channel_layout(const char *name)
for (n = name; n < name_end; n = e + 1) {
for (e = n; e < name_end && *e != '+' && *e != '|'; e++);
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+ layout_single = get_channel_layout_single(n, e - n, compat);
+#else
layout_single = get_channel_layout_single(n, e - n);
+#endif
if (!layout_single)
return 0;
layout |= layout_single;
@@ -143,58 +179,67 @@ uint64_t av_get_channel_layout(const char *name)
return layout;
}
-void av_get_channel_layout_string(char *buf, int buf_size,
- int nb_channels, uint64_t channel_layout)
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+uint64_t av_get_channel_layout(const char *name)
+{
+ return ff_get_channel_layout(name, 1);
+}
+#endif
+
+void av_bprint_channel_layout(struct AVBPrint *bp,
+ int nb_channels, uint64_t channel_layout)
{
int i;
if (nb_channels <= 0)
nb_channels = av_get_channel_layout_nb_channels(channel_layout);
- for (i = 0; channel_layout_map[i].name; i++)
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
if (nb_channels == channel_layout_map[i].nb_channels &&
channel_layout == channel_layout_map[i].layout) {
- av_strlcpy(buf, channel_layout_map[i].name, buf_size);
+ av_bprintf(bp, "%s", channel_layout_map[i].name);
return;
}
- snprintf(buf, buf_size, "%d channels", nb_channels);
+ av_bprintf(bp, "%d channels", nb_channels);
if (channel_layout) {
int i, ch;
- av_strlcat(buf, " (", buf_size);
+ av_bprintf(bp, " (");
for (i = 0, ch = 0; i < 64; i++) {
if ((channel_layout & (UINT64_C(1) << i))) {
const char *name = get_channel_name(i);
if (name) {
if (ch > 0)
- av_strlcat(buf, "|", buf_size);
- av_strlcat(buf, name, buf_size);
+ av_bprintf(bp, "+");
+ av_bprintf(bp, "%s", name);
}
ch++;
}
}
- av_strlcat(buf, ")", buf_size);
+ av_bprintf(bp, ")");
}
}
+void av_get_channel_layout_string(char *buf, int buf_size,
+ int nb_channels, uint64_t channel_layout)
+{
+ AVBPrint bp;
+
+ av_bprint_init_for_buffer(&bp, buf, buf_size);
+ av_bprint_channel_layout(&bp, nb_channels, channel_layout);
+}
+
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
{
return av_popcount64(channel_layout);
}
-uint64_t av_get_default_channel_layout(int nb_channels)
-{
- switch(nb_channels) {
- case 1: return AV_CH_LAYOUT_MONO;
- case 2: return AV_CH_LAYOUT_STEREO;
- case 3: return AV_CH_LAYOUT_SURROUND;
- case 4: return AV_CH_LAYOUT_QUAD;
- case 5: return AV_CH_LAYOUT_5POINT0;
- case 6: return AV_CH_LAYOUT_5POINT1;
- case 7: return AV_CH_LAYOUT_6POINT1;
- case 8: return AV_CH_LAYOUT_7POINT1;
- default: return 0;
- }
+int64_t av_get_default_channel_layout(int nb_channels) {
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
+ if (nb_channels == channel_layout_map[i].nb_channels)
+ return channel_layout_map[i].layout;
+ return 0;
}
int av_get_channel_layout_channel_index(uint64_t channel_layout,
@@ -218,6 +263,17 @@ const char *av_get_channel_name(uint64_t channel)
return NULL;
}
+const char *av_get_channel_description(uint64_t channel)
+{
+ int i;
+ if (av_get_channel_layout_nb_channels(channel) != 1)
+ return NULL;
+ for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
+ if ((1ULL<<i) & channel)
+ return channel_names[i].description;
+ return NULL;
+}
+
uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
{
int i;
@@ -231,3 +287,13 @@ uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
}
return 0;
}
+
+int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
+ const char **name)
+{
+ if (index >= FF_ARRAY_ELEMS(channel_layout_map))
+ return AVERROR_EOF;
+ if (layout) *layout = channel_layout_map[index].layout;
+ if (name) *name = channel_layout_map[index].name;
+ return 0;
+}
diff --git a/libavutil/channel_layout.h b/libavutil/channel_layout.h
index 6a1f83005a..dea4d6093d 100644
--- a/libavutil/channel_layout.h
+++ b/libavutil/channel_layout.h
@@ -2,20 +2,20 @@
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2008 Peter Ross
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,6 +36,14 @@
/**
* @defgroup channel_masks Audio channel masks
+ *
+ * A channel layout is a 64-bits integer with a bit set for every channel.
+ * The number of bits set must be equal to the number of channels.
+ * The value 0 means that the channel layout is not known.
+ * @note this data structure is not powerful enough to handle channels
+ * combinations that have the same channel multiple times, such as
+ * dual-mono.
+ *
* @{
*/
#define AV_CH_FRONT_LEFT 0x00000001
@@ -71,7 +79,7 @@
/**
* @}
- * @defgroup channel_mask_c Audio channel convenience macros
+ * @defgroup channel_mask_c Audio channel layouts
* @{
* */
#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER)
@@ -114,10 +122,6 @@ enum AVMatrixEncoding {
};
/**
- * @}
- */
-
-/**
* Return a channel layout id that matches name, or 0 if no match is found.
*
* name can be one or several of the following notations,
@@ -132,7 +136,12 @@ enum AVMatrixEncoding {
* - a channel layout mask, in hexadecimal starting with "0x" (see the
* AV_CH_* macros).
*
- * Example: "stereo+FC" = "2+FC" = "2c+1c" = "0x7"
+ * @warning Starting from the next major bump the trailing character
+ * 'c' to specify a number of channels will be required, while a
+ * channel layout mask could also be specified as a decimal number
+ * (if and only if not followed by "c").
+ *
+ * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7"
*/
uint64_t av_get_channel_layout(const char *name);
@@ -145,6 +154,12 @@ uint64_t av_get_channel_layout(const char *name);
*/
void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout);
+struct AVBPrint;
+/**
+ * Append a description of a channel layout to a bprint buffer.
+ */
+void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout);
+
/**
* Return the number of channels in the channel layout.
*/
@@ -153,7 +168,7 @@ int av_get_channel_layout_nb_channels(uint64_t channel_layout);
/**
* Return default channel layout for a given number of channels.
*/
-uint64_t av_get_default_channel_layout(int nb_channels);
+int64_t av_get_default_channel_layout(int nb_channels);
/**
* Get the index of a channel in channel_layout.
@@ -180,6 +195,27 @@ uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index);
const char *av_get_channel_name(uint64_t channel);
/**
+ * Get the description of a given channel.
+ *
+ * @param channel a channel layout with a single channel
+ * @return channel description on success, NULL on error
+ */
+const char *av_get_channel_description(uint64_t channel);
+
+/**
+ * Get the value and name of a standard channel layout.
+ *
+ * @param[in] index index in an internal list, starting at 0
+ * @param[out] layout channel layout mask
+ * @param[out] name name of the layout
+ * @return 0 if the layout exists,
+ * <0 if index is beyond the limits
+ */
+int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
+ const char **name);
+
+/**
+ * @}
* @}
*/
diff --git a/libavutil/color_utils.c b/libavutil/color_utils.c
new file mode 100644
index 0000000000..59146be8c2
--- /dev/null
+++ b/libavutil/color_utils.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley@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
+ */
+
+#include "libavutil/color_utils.h"
+#include "libavutil/pixfmt.h"
+
+double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc)
+{
+ double gamma;
+ switch (trc) {
+ case AVCOL_TRC_BT709:
+ case AVCOL_TRC_SMPTE170M:
+ case AVCOL_TRC_SMPTE240M:
+ case AVCOL_TRC_BT1361_ECG:
+ case AVCOL_TRC_BT2020_10:
+ case AVCOL_TRC_BT2020_12:
+ /* these share a segmented TRC, but gamma 1.961 is a close
+ approximation, and also more correct for decoding content */
+ gamma = 1.961;
+ break;
+ case AVCOL_TRC_GAMMA22:
+ case AVCOL_TRC_IEC61966_2_1:
+ gamma = 2.2;
+ break;
+ case AVCOL_TRC_GAMMA28:
+ gamma = 2.8;
+ break;
+ case AVCOL_TRC_LINEAR:
+ gamma = 1.0;
+ break;
+ default:
+ gamma = 0.0; // Unknown value representation
+ }
+ return gamma;
+}
diff --git a/libavutil/color_utils.h b/libavutil/color_utils.h
new file mode 100644
index 0000000000..3600a72d10
--- /dev/null
+++ b/libavutil/color_utils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley@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
+ */
+
+#ifndef AVUTIL_COLOR_UTILS_H
+#define AVUTIL_COLOR_UTILS_H
+
+
+#include "libavutil/pixfmt.h"
+
+/**
+ * Determine a suitable 'gamma' value to match the supplied
+ * AVColorTransferCharacteristic.
+ *
+ * See Apple Technical Note TN2257 (https://developer.apple.com/library/mac/technotes/tn2257/_index.html)
+ *
+ * @return Will return an approximation to the simple gamma function matching
+ * the supplied Transfer Characteristic, Will return 0.0 for any
+ * we cannot reasonably match against.
+ */
+double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc);
+
+#endif
diff --git a/libavutil/colorspace.h b/libavutil/colorspace.h
index 8757566c78..f438159811 100644
--- a/libavutil/colorspace.h
+++ b/libavutil/colorspace.h
@@ -2,20 +2,20 @@
* Colorspace conversion defines
* Copyright (c) 2001, 2002, 2003 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/common.h b/libavutil/common.h
index 3265f9cca4..3e62b6d5b7 100644
--- a/libavutil/common.h
+++ b/libavutil/common.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,10 @@
#ifndef AVUTIL_COMMON_H
#define AVUTIL_COMMON_H
+#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C)
+#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS
+#endif
+
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
@@ -49,6 +53,11 @@
#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))
/* assume b>0 */
#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))
+/* assume a>0 and b>0 */
+#define FF_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \
+ : ((a) + (1<<(b)) - 1) >> (b))
+#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b))
+#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b))
#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))
#define FFSIGN(a) ((a) > 0 ? 1 : -1)
@@ -63,6 +72,9 @@
/* misc math functions */
+/**
+ * Reverse the order of the bits of an 8-bits unsigned integer.
+ */
#if FF_API_AV_REVERSE
extern attribute_deprecated const uint8_t av_reverse[256];
#endif
@@ -92,6 +104,26 @@ av_const int av_log2_16bit(unsigned v);
*/
static av_always_inline av_const int av_clip_c(int a, int amin, int amax)
{
+#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2
+ if (amin > amax) abort();
+#endif
+ if (a < amin) return amin;
+ else if (a > amax) return amax;
+ else return a;
+}
+
+/**
+ * Clip a signed 64bit integer value into the amin-amax range.
+ * @param a value to clip
+ * @param amin minimum value of the clip range
+ * @param amax maximum value of the clip range
+ * @return clipped value
+ */
+static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)
+{
+#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2
+ if (amin > amax) abort();
+#endif
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
@@ -115,7 +147,7 @@ static av_always_inline av_const uint8_t av_clip_uint8_c(int a)
*/
static av_always_inline av_const int8_t av_clip_int8_c(int a)
{
- if ((a+0x80) & ~0xFF) return (a>>31) ^ 0x7F;
+ if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F;
else return a;
}
@@ -137,7 +169,7 @@ static av_always_inline av_const uint16_t av_clip_uint16_c(int a)
*/
static av_always_inline av_const int16_t av_clip_int16_c(int a)
{
- if ((a+0x8000) & ~0xFFFF) return (a>>31) ^ 0x7FFF;
+ if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF;
else return a;
}
@@ -148,8 +180,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 (a>>63) ^ 0x7FFFFFFF;
- else return a;
+ if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF);
+ else return (int32_t)a;
}
/**
@@ -160,7 +192,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 ((a + (1 << p)) & ~((1 << (p + 1)) - 1))
+ if ((a + (1 << p)) & ~((2 << p) - 1))
return (a >> 31) ^ ((1 << p) - 1);
else
return a;
@@ -179,6 +211,17 @@ static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p)
}
/**
+ * Clear high bits from an unsigned integer starting with specific bit position
+ * @param a value to clip
+ * @param p bit position to clip at
+ * @return clipped value
+ */
+static av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p)
+{
+ return a & ((1 << p) - 1);
+}
+
+/**
* Add two signed 32-bit values with saturation.
*
* @param a one value
@@ -211,6 +254,26 @@ static av_always_inline int av_sat_dadd32_c(int a, int b)
*/
static av_always_inline av_const float av_clipf_c(float a, float amin, float amax)
{
+#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2
+ if (amin > amax) abort();
+#endif
+ if (a < amin) return amin;
+ else if (a > amax) return amax;
+ else return a;
+}
+
+/**
+ * Clip a double value into the amin-amax range.
+ * @param a value to clip
+ * @param amin minimum value of the clip range
+ * @param amax maximum value of the clip range
+ * @return clipped value
+ */
+static av_always_inline av_const double av_clipd_c(double a, double amin, double amax)
+{
+#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2
+ if (amin > amax) abort();
+#endif
if (a < amin) return amin;
else if (a > amax) return amax;
else return a;
@@ -246,7 +309,7 @@ static av_always_inline av_const int av_popcount_c(uint32_t x)
*/
static av_always_inline av_const int av_popcount64_c(uint64_t x)
{
- return av_popcount(x) + av_popcount(x >> 32);
+ return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32));
}
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
@@ -262,12 +325,17 @@ static av_always_inline av_const int av_popcount64_c(uint64_t x)
* input, this could be *ptr++.
* @param ERROR Expression to be evaluated on invalid input,
* typically a goto statement.
+ *
+ * @warning ERROR should not contain a loop control statement which
+ * could interact with the internal while loop, and should force an
+ * exit from the macro code (e.g. through a goto or a return) in order
+ * to prevent undefined results.
*/
#define GET_UTF8(val, GET_BYTE, ERROR)\
val= GET_BYTE;\
{\
uint32_t top = (val & 128) >> 1;\
- if ((val & 0xc0) == 0x80)\
+ if ((val & 0xc0) == 0x80 || val >= 0xFE)\
ERROR\
while (val & top) {\
int tmp= GET_BYTE - 128;\
@@ -385,6 +453,9 @@ static av_always_inline av_const int av_popcount64_c(uint64_t x)
#ifndef av_clip
# define av_clip av_clip_c
#endif
+#ifndef av_clip64
+# define av_clip64 av_clip64_c
+#endif
#ifndef av_clip_uint8
# define av_clip_uint8 av_clip_uint8_c
#endif
@@ -406,6 +477,9 @@ static av_always_inline av_const int av_popcount64_c(uint64_t x)
#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
@@ -415,6 +489,9 @@ static av_always_inline av_const int av_popcount64_c(uint64_t x)
#ifndef av_clipf
# define av_clipf av_clipf_c
#endif
+#ifndef av_clipd
+# define av_clipd av_clipd_c
+#endif
#ifndef av_popcount
# define av_popcount av_popcount_c
#endif
diff --git a/libavutil/cpu.c b/libavutil/cpu.c
index 4e8ef61f03..765577d177 100644
--- a/libavutil/cpu.c
+++ b/libavutil/cpu.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,7 +25,9 @@
#include "common.h"
#if HAVE_SCHED_GETAFFINITY
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include <sched.h>
#endif
#if HAVE_GETPROCESSAFFINITYMASK
@@ -38,16 +40,40 @@
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
-#if HAVE_SYSCONF
+#if HAVE_UNISTD_H
#include <unistd.h>
#endif
-static int cpuflags_mask = -1, checked;
+static int flags, checked;
+
+void av_force_cpu_flags(int arg){
+ if ( (arg & ( AV_CPU_FLAG_3DNOW |
+ AV_CPU_FLAG_3DNOWEXT |
+ AV_CPU_FLAG_MMXEXT |
+ AV_CPU_FLAG_SSE |
+ AV_CPU_FLAG_SSE2 |
+ AV_CPU_FLAG_SSE2SLOW |
+ AV_CPU_FLAG_SSE3 |
+ AV_CPU_FLAG_SSE3SLOW |
+ AV_CPU_FLAG_SSSE3 |
+ AV_CPU_FLAG_SSE4 |
+ AV_CPU_FLAG_SSE42 |
+ AV_CPU_FLAG_AVX |
+ AV_CPU_FLAG_XOP |
+ AV_CPU_FLAG_FMA3 |
+ AV_CPU_FLAG_FMA4 |
+ AV_CPU_FLAG_AVX2 ))
+ && !(arg & AV_CPU_FLAG_MMX)) {
+ av_log(NULL, AV_LOG_WARNING, "MMX implied by specified flags\n");
+ arg |= AV_CPU_FLAG_MMX;
+ }
+
+ flags = arg;
+ checked = arg != -1;
+}
int av_get_cpu_flags(void)
{
- static int flags;
-
if (checked)
return flags;
@@ -60,16 +86,15 @@ int av_get_cpu_flags(void)
if (ARCH_X86)
flags = ff_get_cpu_flags_x86();
- flags &= cpuflags_mask;
checked = 1;
-
return flags;
}
void av_set_cpu_flags_mask(int mask)
{
- cpuflags_mask = mask;
checked = 0;
+ flags = av_get_cpu_flags() & mask;
+ checked = 1;
}
int av_parse_cpu_flags(const char *s)
@@ -147,8 +172,82 @@ int av_parse_cpu_flags(const char *s)
return flags & INT_MAX;
}
+int av_parse_cpu_caps(unsigned *flags, const char *s)
+{
+ static const AVOption cpuflags_opts[] = {
+ { "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" },
+#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" },
+ { "mmxext" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" },
+ { "sse" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE }, .unit = "flags" },
+ { "sse2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2 }, .unit = "flags" },
+ { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2SLOW }, .unit = "flags" },
+ { "sse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3 }, .unit = "flags" },
+ { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3SLOW }, .unit = "flags" },
+ { "ssse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSSE3 }, .unit = "flags" },
+ { "atom" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ATOM }, .unit = "flags" },
+ { "sse4.1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE4 }, .unit = "flags" },
+ { "sse4.2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE42 }, .unit = "flags" },
+ { "avx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX }, .unit = "flags" },
+ { "xop" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_XOP }, .unit = "flags" },
+ { "fma3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA3 }, .unit = "flags" },
+ { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA4 }, .unit = "flags" },
+ { "avx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX2 }, .unit = "flags" },
+ { "bmi1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI1 }, .unit = "flags" },
+ { "bmi2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI2 }, .unit = "flags" },
+ { "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOW }, .unit = "flags" },
+ { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOWEXT }, .unit = "flags" },
+ { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" },
+
+#define CPU_FLAG_P2 AV_CPU_FLAG_CMOV | AV_CPU_FLAG_MMX
+#define CPU_FLAG_P3 CPU_FLAG_P2 | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE
+#define CPU_FLAG_P4 CPU_FLAG_P3| AV_CPU_FLAG_SSE2
+ { "pentium2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P2 }, .unit = "flags" },
+ { "pentium3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P3 }, .unit = "flags" },
+ { "pentium4", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P4 }, .unit = "flags" },
+
+#define CPU_FLAG_K62 AV_CPU_FLAG_MMX | AV_CPU_FLAG_3DNOW
+#define CPU_FLAG_ATHLON CPU_FLAG_K62 | AV_CPU_FLAG_CMOV | AV_CPU_FLAG_3DNOWEXT | AV_CPU_FLAG_MMX2
+#define CPU_FLAG_ATHLONXP CPU_FLAG_ATHLON | AV_CPU_FLAG_SSE
+#define CPU_FLAG_K8 CPU_FLAG_ATHLONXP | AV_CPU_FLAG_SSE2
+ { "k6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" },
+ { "k62", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K62 }, .unit = "flags" },
+ { "athlon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLON }, .unit = "flags" },
+ { "athlonxp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLONXP }, .unit = "flags" },
+ { "k8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K8 }, .unit = "flags" },
+#elif ARCH_ARM
+ { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" },
+ { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" },
+ { "armv6t2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6T2 }, .unit = "flags" },
+ { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" },
+ { "vfpv3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFPV3 }, .unit = "flags" },
+ { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" },
+ { "setend", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SETEND }, .unit = "flags" },
+#elif ARCH_AARCH64
+ { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" },
+ { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" },
+ { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" },
+#endif
+ { NULL },
+ };
+ static const AVClass class = {
+ .class_name = "cpuflags",
+ .item_name = av_default_item_name,
+ .option = cpuflags_opts,
+ .version = LIBAVUTIL_VERSION_INT,
+ };
+ const AVClass *pclass = &class;
+
+ return av_opt_eval_flags(&pclass, &cpuflags_opts[0], s, flags);
+}
+
int av_cpu_count(void)
{
+ static volatile int printed;
+
int nb_cpus = 1;
#if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT)
cpu_set_t cpuset;
@@ -173,16 +272,17 @@ int av_cpu_count(void)
nb_cpus = sysconf(_SC_NPROCESSORS_ONLN);
#endif
+ if (!printed) {
+ av_log(NULL, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus);
+ printed = 1;
+ }
+
return nb_cpus;
}
#ifdef TEST
#include <stdio.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
#include "avstring.h"
#if !HAVE_GETOPT
@@ -204,6 +304,7 @@ static const struct {
{ AV_CPU_FLAG_VFP, "vfp" },
{ AV_CPU_FLAG_VFPV3, "vfpv3" },
{ AV_CPU_FLAG_NEON, "neon" },
+ { AV_CPU_FLAG_SETEND, "setend" },
#elif ARCH_PPC
{ AV_CPU_FLAG_ALTIVEC, "altivec" },
#elif ARCH_X86
@@ -211,9 +312,9 @@ static const struct {
{ AV_CPU_FLAG_MMXEXT, "mmxext" },
{ AV_CPU_FLAG_SSE, "sse" },
{ AV_CPU_FLAG_SSE2, "sse2" },
- { AV_CPU_FLAG_SSE2SLOW, "sse2(slow)" },
+ { AV_CPU_FLAG_SSE2SLOW, "sse2slow" },
{ AV_CPU_FLAG_SSE3, "sse3" },
- { AV_CPU_FLAG_SSE3SLOW, "sse3(slow)" },
+ { AV_CPU_FLAG_SSE3SLOW, "sse3slow" },
{ AV_CPU_FLAG_SSSE3, "ssse3" },
{ AV_CPU_FLAG_ATOM, "atom" },
{ AV_CPU_FLAG_SSE4, "sse4.1" },
@@ -236,12 +337,12 @@ static void print_cpu_flags(int cpu_flags, const char *type)
{
int i;
- fprintf(stderr, "cpu_flags(%s) = 0x%08X\n", type, cpu_flags);
- fprintf(stderr, "cpu_flags_str(%s) =", type);
+ printf("cpu_flags(%s) = 0x%08X\n", type, cpu_flags);
+ printf("cpu_flags_str(%s) =", type);
for (i = 0; cpu_flag_tab[i].flag; i++)
if (cpu_flags & cpu_flag_tab[i].flag)
- fprintf(stderr, " %s", cpu_flag_tab[i].name);
- fprintf(stderr, "\n");
+ printf(" %s", cpu_flag_tab[i].name);
+ printf("\n");
}
@@ -251,6 +352,15 @@ int main(int argc, char **argv)
int cpu_flags_eff;
int cpu_count = av_cpu_count();
char threads[5] = "auto";
+ int i;
+
+ for(i = 0; cpu_flag_tab[i].flag; i++) {
+ unsigned tmp = 0;
+ if (av_parse_cpu_caps(&tmp, cpu_flag_tab[i].name) < 0) {
+ fprintf(stderr, "Table missing %s\n", cpu_flag_tab[i].name);
+ return 4;
+ }
+ }
if (cpu_flags_raw < 0)
return 1;
@@ -262,10 +372,11 @@ int main(int argc, char **argv)
switch (c) {
case 'c':
{
- int cpuflags = av_parse_cpu_flags(optarg);
- if (cpuflags < 0)
+ unsigned flags = av_get_cpu_flags();
+ if (av_parse_cpu_caps(&flags, optarg) < 0)
return 2;
- av_set_cpu_flags_mask(cpuflags);
+
+ av_force_cpu_flags(flags);
break;
}
case 't':
@@ -286,7 +397,7 @@ int main(int argc, char **argv)
print_cpu_flags(cpu_flags_raw, "raw");
print_cpu_flags(cpu_flags_eff, "effective");
- fprintf(stderr, "threads = %s (cpu_count = %d)\n", threads, cpu_count);
+ printf("threads = %s (cpu_count = %d)\n", threads, cpu_count);
return 0;
}
diff --git a/libavutil/cpu.h b/libavutil/cpu.h
index 7cecccc9c4..277e489788 100644
--- a/libavutil/cpu.h
+++ b/libavutil/cpu.h
@@ -1,36 +1,34 @@
/*
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_CPU_H
#define AVUTIL_CPU_H
-#include "version.h"
+#include "attributes.h"
#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */
/* lower 16 bits - CPU features */
#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX
#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext
-#if FF_API_CPU_FLAG_MMX2
#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext
-#endif
#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW
#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions
#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions
@@ -47,7 +45,11 @@
#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used
#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions
#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions
-#define AV_CPU_FLAG_CMOV 0x1000 ///< i686 cmov
+// #if LIBAVUTIL_VERSION_MAJOR <52
+#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction
+// #else
+// #define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction
+// #endif
#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used
#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions
#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1
@@ -62,28 +64,51 @@
#define AV_CPU_FLAG_VFPV3 (1 << 4)
#define AV_CPU_FLAG_NEON (1 << 5)
#define AV_CPU_FLAG_ARMV8 (1 << 6)
+#define AV_CPU_FLAG_SETEND (1 <<16)
/**
* Return the flags which specify extensions supported by the CPU.
+ * The returned value is affected by av_force_cpu_flags() if that was used
+ * before. So av_get_cpu_flags() can easily be used in a application to
+ * detect the enabled cpu flags.
*/
int av_get_cpu_flags(void);
/**
+ * Disables cpu detection and forces the specified flags.
+ * -1 is a special case that disables forcing of specific flags.
+ */
+void av_force_cpu_flags(int flags);
+
+/**
* Set a mask on flags returned by av_get_cpu_flags().
* This function is mainly useful for testing.
+ * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible
*
* @warning this function is not thread safe.
*/
-void av_set_cpu_flags_mask(int mask);
+attribute_deprecated void av_set_cpu_flags_mask(int mask);
/**
* Parse CPU flags from a string.
*
+ * The returned flags contain the specified flags as well as related unspecified flags.
+ *
+ * This function exists only for compatibility with libav.
+ * Please use av_parse_cpu_caps() when possible.
* @return a combination of AV_CPU_* flags, negative on error.
*/
+attribute_deprecated
int av_parse_cpu_flags(const char *s);
/**
+ * Parse CPU caps from a string and update the given AV_CPU_* flags based on that.
+ *
+ * @return negative on error.
+ */
+int av_parse_cpu_caps(unsigned *flags, const char *s);
+
+/**
* @return the number of logical CPU cores present.
*/
int av_cpu_count(void);
diff --git a/libavutil/cpu_internal.h b/libavutil/cpu_internal.h
index 3bfe8a82d8..3c6ce6d079 100644
--- a/libavutil/cpu_internal.h
+++ b/libavutil/cpu_internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/crc.c b/libavutil/crc.c
index eb22e33ada..d8b1c99d1c 100644
--- a/libavutil/crc.c
+++ b/libavutil/crc.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -119,6 +119,45 @@ static const AVCRC av_crc_table[AV_CRC_MAX][257] = {
0x176E, 0x367E, 0x554E, 0x745E, 0x932E, 0xB23E, 0xD10E, 0xF01E,
0x0001
},
+ [AV_CRC_24_IEEE] = {
+ 0x000000, 0xFB4C86, 0x0DD58A, 0xF6990C, 0xE1E693, 0x1AAA15, 0xEC3319,
+ 0x177F9F, 0x3981A1, 0xC2CD27, 0x34542B, 0xCF18AD, 0xD86732, 0x232BB4,
+ 0xD5B2B8, 0x2EFE3E, 0x894EC5, 0x720243, 0x849B4F, 0x7FD7C9, 0x68A856,
+ 0x93E4D0, 0x657DDC, 0x9E315A, 0xB0CF64, 0x4B83E2, 0xBD1AEE, 0x465668,
+ 0x5129F7, 0xAA6571, 0x5CFC7D, 0xA7B0FB, 0xE9D10C, 0x129D8A, 0xE40486,
+ 0x1F4800, 0x08379F, 0xF37B19, 0x05E215, 0xFEAE93, 0xD050AD, 0x2B1C2B,
+ 0xDD8527, 0x26C9A1, 0x31B63E, 0xCAFAB8, 0x3C63B4, 0xC72F32, 0x609FC9,
+ 0x9BD34F, 0x6D4A43, 0x9606C5, 0x81795A, 0x7A35DC, 0x8CACD0, 0x77E056,
+ 0x591E68, 0xA252EE, 0x54CBE2, 0xAF8764, 0xB8F8FB, 0x43B47D, 0xB52D71,
+ 0x4E61F7, 0xD2A319, 0x29EF9F, 0xDF7693, 0x243A15, 0x33458A, 0xC8090C,
+ 0x3E9000, 0xC5DC86, 0xEB22B8, 0x106E3E, 0xE6F732, 0x1DBBB4, 0x0AC42B,
+ 0xF188AD, 0x0711A1, 0xFC5D27, 0x5BEDDC, 0xA0A15A, 0x563856, 0xAD74D0,
+ 0xBA0B4F, 0x4147C9, 0xB7DEC5, 0x4C9243, 0x626C7D, 0x9920FB, 0x6FB9F7,
+ 0x94F571, 0x838AEE, 0x78C668, 0x8E5F64, 0x7513E2, 0x3B7215, 0xC03E93,
+ 0x36A79F, 0xCDEB19, 0xDA9486, 0x21D800, 0xD7410C, 0x2C0D8A, 0x02F3B4,
+ 0xF9BF32, 0x0F263E, 0xF46AB8, 0xE31527, 0x1859A1, 0xEEC0AD, 0x158C2B,
+ 0xB23CD0, 0x497056, 0xBFE95A, 0x44A5DC, 0x53DA43, 0xA896C5, 0x5E0FC9,
+ 0xA5434F, 0x8BBD71, 0x70F1F7, 0x8668FB, 0x7D247D, 0x6A5BE2, 0x911764,
+ 0x678E68, 0x9CC2EE, 0xA44733, 0x5F0BB5, 0xA992B9, 0x52DE3F, 0x45A1A0,
+ 0xBEED26, 0x48742A, 0xB338AC, 0x9DC692, 0x668A14, 0x901318, 0x6B5F9E,
+ 0x7C2001, 0x876C87, 0x71F58B, 0x8AB90D, 0x2D09F6, 0xD64570, 0x20DC7C,
+ 0xDB90FA, 0xCCEF65, 0x37A3E3, 0xC13AEF, 0x3A7669, 0x148857, 0xEFC4D1,
+ 0x195DDD, 0xE2115B, 0xF56EC4, 0x0E2242, 0xF8BB4E, 0x03F7C8, 0x4D963F,
+ 0xB6DAB9, 0x4043B5, 0xBB0F33, 0xAC70AC, 0x573C2A, 0xA1A526, 0x5AE9A0,
+ 0x74179E, 0x8F5B18, 0x79C214, 0x828E92, 0x95F10D, 0x6EBD8B, 0x982487,
+ 0x636801, 0xC4D8FA, 0x3F947C, 0xC90D70, 0x3241F6, 0x253E69, 0xDE72EF,
+ 0x28EBE3, 0xD3A765, 0xFD595B, 0x0615DD, 0xF08CD1, 0x0BC057, 0x1CBFC8,
+ 0xE7F34E, 0x116A42, 0xEA26C4, 0x76E42A, 0x8DA8AC, 0x7B31A0, 0x807D26,
+ 0x9702B9, 0x6C4E3F, 0x9AD733, 0x619BB5, 0x4F658B, 0xB4290D, 0x42B001,
+ 0xB9FC87, 0xAE8318, 0x55CF9E, 0xA35692, 0x581A14, 0xFFAAEF, 0x04E669,
+ 0xF27F65, 0x0933E3, 0x1E4C7C, 0xE500FA, 0x1399F6, 0xE8D570, 0xC62B4E,
+ 0x3D67C8, 0xCBFEC4, 0x30B242, 0x27CDDD, 0xDC815B, 0x2A1857, 0xD154D1,
+ 0x9F3526, 0x6479A0, 0x92E0AC, 0x69AC2A, 0x7ED3B5, 0x859F33, 0x73063F,
+ 0x884AB9, 0xA6B487, 0x5DF801, 0xAB610D, 0x502D8B, 0x475214, 0xBC1E92,
+ 0x4A879E, 0xB1CB18, 0x167BE3, 0xED3765, 0x1BAE69, 0xE0E2EF, 0xF79D70,
+ 0x0CD1F6, 0xFA48FA, 0x01047C, 0x2FFA42, 0xD4B6C4, 0x222FC8, 0xD9634E,
+ 0xCE1CD1, 0x355057, 0xC3C95B, 0x3885DD, 0x000001,
+ },
[AV_CRC_32_IEEE] = {
0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517,
0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B,
@@ -246,6 +285,11 @@ static const AVCRC av_crc_table[AV_CRC_MAX][257] = {
},
};
#else
+#if CONFIG_SMALL
+#define CRC_TABLE_SIZE 257
+#else
+#define CRC_TABLE_SIZE 1024
+#endif
static struct {
uint8_t le;
uint8_t bits;
@@ -254,11 +298,12 @@ static struct {
[AV_CRC_8_ATM] = { 0, 8, 0x07 },
[AV_CRC_16_ANSI] = { 0, 16, 0x8005 },
[AV_CRC_16_CCITT] = { 0, 16, 0x1021 },
+ [AV_CRC_24_IEEE] = { 0, 24, 0x864CFB },
[AV_CRC_32_IEEE] = { 0, 32, 0x04C11DB7 },
[AV_CRC_32_IEEE_LE] = { 1, 32, 0xEDB88320 },
[AV_CRC_16_ANSI_LE] = { 1, 16, 0xA001 },
};
-static AVCRC av_crc_table[AV_CRC_MAX][257];
+static AVCRC av_crc_table[AV_CRC_MAX][CRC_TABLE_SIZE];
#endif
int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size)
@@ -338,8 +383,9 @@ int main(void)
{
uint8_t buf[1999];
int i;
- int p[5][3] = { { AV_CRC_32_IEEE_LE, 0xEDB88320, 0x3D5CDD04 },
+ int p[6][3] = { { AV_CRC_32_IEEE_LE, 0xEDB88320, 0x3D5CDD04 },
{ AV_CRC_32_IEEE , 0x04C11DB7, 0xC0F5BAE0 },
+ { AV_CRC_24_IEEE , 0x864CFB , 0xB704CE },
{ AV_CRC_16_ANSI_LE, 0xA001 , 0xBFD8 },
{ AV_CRC_16_ANSI , 0x8005 , 0x1FBB },
{ AV_CRC_8_ATM , 0x07 , 0xE3 }
@@ -349,7 +395,7 @@ int main(void)
for (i = 0; i < sizeof(buf); i++)
buf[i] = i + i * i;
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < 6; i++) {
ctx = av_crc_get_table(p[i][0]);
printf("crc %08X = %X\n", p[i][1], av_crc(ctx, 0, buf, sizeof(buf)));
}
diff --git a/libavutil/crc.h b/libavutil/crc.h
index dcb7e2c7d7..e86bf1deba 100644
--- a/libavutil/crc.h
+++ b/libavutil/crc.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,12 @@
#include <stddef.h>
#include "attributes.h"
+/**
+ * @defgroup lavu_crc32 CRC32
+ * @ingroup lavu_crypto
+ * @{
+ */
+
typedef uint32_t AVCRC;
typedef enum {
@@ -34,6 +40,7 @@ typedef enum {
AV_CRC_32_IEEE,
AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */
AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */
+ AV_CRC_24_IEEE = 12,
AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */
}AVCRCId;
@@ -72,4 +79,8 @@ const AVCRC *av_crc_get_table(AVCRCId crc_id);
uint32_t av_crc(const AVCRC *ctx, uint32_t crc,
const uint8_t *buffer, size_t length) av_pure;
+/**
+ * @}
+ */
+
#endif /* AVUTIL_CRC_H */
diff --git a/libavutil/des.c b/libavutil/des.c
index ab0fc2f8bc..57ad0a4fff 100644
--- a/libavutil/des.c
+++ b/libavutil/des.c
@@ -2,20 +2,20 @@
* DES encryption/decryption
* Copyright (c) 2007 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
@@ -286,7 +286,7 @@ static uint64_t des_encdec(uint64_t in, uint64_t K[16], int decrypt) {
return in;
}
-int av_des_init(AVDES *d, const uint8_t *key, int key_bits, int decrypt) {
+int av_des_init(AVDES *d, const uint8_t *key, int key_bits, av_unused int decrypt) {
if (key_bits != 64 && key_bits != 192)
return -1;
d->triple_des = key_bits > 64;
@@ -413,10 +413,10 @@ int main(void) {
for (i = 0; i < 1000; i++) {
key[0] = rand64(); key[1] = rand64(); key[2] = rand64();
data = rand64();
- av_des_init(&d, key, 192, 0);
- av_des_crypt(&d, &ct, &data, 1, NULL, 0);
- av_des_init(&d, key, 192, 1);
- av_des_crypt(&d, &ct, &ct, 1, NULL, 1);
+ av_des_init(&d, (uint8_t*)key, 192, 0);
+ av_des_crypt(&d, (uint8_t*)&ct, (uint8_t*)&data, 1, NULL, 0);
+ av_des_init(&d, (uint8_t*)key, 192, 1);
+ av_des_crypt(&d, (uint8_t*)&ct, (uint8_t*)&ct, 1, NULL, 1);
if (ct != data) {
printf("Test 2 failed\n");
return 1;
diff --git a/libavutil/des.h b/libavutil/des.h
index cda98122d3..2feb0468db 100644
--- a/libavutil/des.h
+++ b/libavutil/des.h
@@ -2,20 +2,20 @@
* DES encryption/decryption
* Copyright (c) 2007 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/dict.c b/libavutil/dict.c
index 7f4832092a..6ff1af5215 100644
--- a/libavutil/dict.c
+++ b/libavutil/dict.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2009 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,7 @@
#include "dict.h"
#include "internal.h"
#include "mem.h"
+#include "bprint.h"
struct AVDictionary {
int count;
@@ -70,18 +71,25 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
{
AVDictionary *m = *pm;
AVDictionaryEntry *tag = av_dict_get(m, key, NULL, flags);
- char *oldval = NULL;
- int allocated = !!m;
+ char *oldval = NULL, *copy_key = NULL, *copy_value = NULL;
+ if (flags & AV_DICT_DONT_STRDUP_KEY)
+ copy_key = (void *)key;
+ else
+ copy_key = av_strdup(key);
+ if (flags & AV_DICT_DONT_STRDUP_VAL)
+ copy_value = (void *)value;
+ else if (copy_key)
+ copy_value = av_strdup(value);
if (!m)
m = *pm = av_mallocz(sizeof(*m));
- if (!m)
- return AVERROR(ENOMEM);
+ if (!m || (key && !copy_key) || (value && !copy_value))
+ goto err_out;
if (tag) {
if (flags & AV_DICT_DONT_OVERWRITE) {
- if (flags & AV_DICT_DONT_STRDUP_KEY) av_free(key);
- if (flags & AV_DICT_DONT_STRDUP_VAL) av_free(value);
+ av_free(copy_key);
+ av_free(copy_value);
return 0;
}
if (flags & AV_DICT_APPEND)
@@ -91,38 +99,54 @@ int av_dict_set(AVDictionary **pm, const char *key, const char *value,
av_free(tag->key);
*tag = m->elems[--m->count];
} else {
- int ret = av_reallocp_array(&m->elems,
- m->count + 1, sizeof(*m->elems));
- if (ret < 0) {
- if (allocated)
- av_freep(pm);
-
- return ret;
- }
+ AVDictionaryEntry *tmp = av_realloc(m->elems,
+ (m->count + 1) * sizeof(*m->elems));
+ if (!tmp)
+ goto err_out;
+ m->elems = tmp;
}
- if (value) {
- if (flags & AV_DICT_DONT_STRDUP_KEY)
- m->elems[m->count].key = key;
- else
- m->elems[m->count].key = av_strdup(key);
- if (flags & AV_DICT_DONT_STRDUP_VAL) {
- m->elems[m->count].value = value;
- } else if (oldval && flags & AV_DICT_APPEND) {
- int len = strlen(oldval) + strlen(value) + 1;
- if (!(oldval = av_realloc(oldval, len)))
- return AVERROR(ENOMEM);
- av_strlcat(oldval, value, len);
- m->elems[m->count].value = oldval;
- } else
- m->elems[m->count].value = av_strdup(value);
+ if (copy_value) {
+ m->elems[m->count].key = copy_key;
+ m->elems[m->count].value = copy_value;
+ if (oldval && flags & AV_DICT_APPEND) {
+ size_t len = strlen(oldval) + strlen(copy_value) + 1;
+ char *newval = av_mallocz(len);
+ if (!newval)
+ goto err_out;
+ av_strlcat(newval, oldval, len);
+ av_freep(&oldval);
+ av_strlcat(newval, copy_value, len);
+ m->elems[m->count].value = newval;
+ av_freep(&copy_value);
+ }
m->count++;
+ } else {
+ av_freep(&copy_key);
}
if (!m->count) {
- av_free(m->elems);
+ av_freep(&m->elems);
av_freep(pm);
}
return 0;
+
+err_out:
+ if (m && !m->count) {
+ av_freep(&m->elems);
+ av_freep(pm);
+ }
+ av_free(copy_key);
+ av_free(copy_value);
+ return AVERROR(ENOMEM);
+}
+
+int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value,
+ int flags)
+{
+ char valuestr[22];
+ snprintf(valuestr, sizeof(valuestr), "%"PRId64, value);
+ flags &= ~AV_DICT_DONT_STRDUP_VAL;
+ return av_dict_set(pm, key, valuestr, flags);
}
static int parse_key_value_pair(AVDictionary **pm, const char **buf,
@@ -178,10 +202,10 @@ void av_dict_free(AVDictionary **pm)
if (m) {
while (m->count--) {
- av_free(m->elems[m->count].key);
- av_free(m->elems[m->count].value);
+ av_freep(&m->elems[m->count].key);
+ av_freep(&m->elems[m->count].value);
}
- av_free(m->elems);
+ av_freep(&m->elems);
}
av_freep(pm);
}
@@ -193,3 +217,145 @@ void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX)))
av_dict_set(dst, t->key, t->value, flags);
}
+
+int av_dict_get_string(const AVDictionary *m, char **buffer,
+ const char key_val_sep, const char pairs_sep)
+{
+ AVDictionaryEntry *t = NULL;
+ AVBPrint bprint;
+ int cnt = 0;
+ char special_chars[] = {pairs_sep, key_val_sep, '\0'};
+
+ if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep ||
+ pairs_sep == '\\' || key_val_sep == '\\')
+ return AVERROR(EINVAL);
+
+ if (!av_dict_count(m)) {
+ *buffer = av_strdup("");
+ return *buffer ? 0 : AVERROR(ENOMEM);
+ }
+
+ av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
+ while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
+ if (cnt++)
+ av_bprint_append_data(&bprint, &pairs_sep, 1);
+ av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
+ av_bprint_append_data(&bprint, &key_val_sep, 1);
+ av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0);
+ }
+ return av_bprint_finalize(&bprint, buffer);
+}
+
+#ifdef TEST
+static void print_dict(const AVDictionary *m)
+{
+ AVDictionaryEntry *t = NULL;
+ while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
+ printf("%s %s ", t->key, t->value);
+ printf("\n");
+}
+
+static void test_separators(const AVDictionary *m, const char pair, const char val)
+{
+ AVDictionary *dict = NULL;
+ char pairs[] = {pair , '\0'};
+ char vals[] = {val, '\0'};
+
+ char *buffer = NULL;
+ av_dict_copy(&dict, m, 0);
+ print_dict(dict);
+ av_dict_get_string(dict, &buffer, val, pair);
+ printf("%s\n", buffer);
+ av_dict_free(&dict);
+ av_dict_parse_string(&dict, buffer, vals, pairs, 0);
+ av_freep(&buffer);
+ print_dict(dict);
+ av_dict_free(&dict);
+}
+
+int main(void)
+{
+ AVDictionary *dict = NULL;
+ AVDictionaryEntry *e;
+ char *buffer = NULL;
+
+ printf("Testing av_dict_get_string() and av_dict_parse_string()\n");
+ av_dict_get_string(dict, &buffer, '=', ',');
+ printf("%s\n", buffer);
+ av_freep(&buffer);
+ av_dict_set(&dict, "aaa", "aaa", 0);
+ av_dict_set(&dict, "b,b", "bbb", 0);
+ av_dict_set(&dict, "c=c", "ccc", 0);
+ av_dict_set(&dict, "ddd", "d,d", 0);
+ av_dict_set(&dict, "eee", "e=e", 0);
+ av_dict_set(&dict, "f,f", "f=f", 0);
+ av_dict_set(&dict, "g=g", "g,g", 0);
+ test_separators(dict, ',', '=');
+ av_dict_free(&dict);
+ av_dict_set(&dict, "aaa", "aaa", 0);
+ av_dict_set(&dict, "bbb", "bbb", 0);
+ av_dict_set(&dict, "ccc", "ccc", 0);
+ av_dict_set(&dict, "\\,=\'\"", "\\,=\'\"", 0);
+ test_separators(dict, '"', '=');
+ test_separators(dict, '\'', '=');
+ test_separators(dict, ',', '"');
+ test_separators(dict, ',', '\'');
+ test_separators(dict, '\'', '"');
+ test_separators(dict, '"', '\'');
+ av_dict_free(&dict);
+
+ printf("\nTesting av_dict_set()\n");
+ av_dict_set(&dict, "a", "a", 0);
+ av_dict_set(&dict, "b", av_strdup("b"), AV_DICT_DONT_STRDUP_VAL);
+ av_dict_set(&dict, av_strdup("c"), "c", AV_DICT_DONT_STRDUP_KEY);
+ av_dict_set(&dict, av_strdup("d"), av_strdup("d"), AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+ av_dict_set(&dict, "e", "e", AV_DICT_DONT_OVERWRITE);
+ av_dict_set(&dict, "e", "f", AV_DICT_DONT_OVERWRITE);
+ av_dict_set(&dict, "f", "f", 0);
+ av_dict_set(&dict, "f", NULL, 0);
+ av_dict_set(&dict, "ff", "f", 0);
+ av_dict_set(&dict, "ff", "f", AV_DICT_APPEND);
+ e = NULL;
+ while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX)))
+ printf("%s %s\n", e->key, e->value);
+ av_dict_free(&dict);
+
+ av_dict_set(&dict, NULL, "a", 0);
+ av_dict_set(&dict, NULL, "b", 0);
+ av_dict_get(dict, NULL, NULL, 0);
+ e = NULL;
+ while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX)))
+ printf("'%s' '%s'\n", e->key, e->value);
+ av_dict_free(&dict);
+
+
+ //valgrind sensible test
+ printf("\nTesting av_dict_set_int()\n");
+ av_dict_set_int(&dict, "1", 1, AV_DICT_DONT_STRDUP_VAL);
+ av_dict_set_int(&dict, av_strdup("2"), 2, AV_DICT_DONT_STRDUP_KEY);
+ av_dict_set_int(&dict, av_strdup("3"), 3, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
+ av_dict_set_int(&dict, "4", 4, 0);
+ av_dict_set_int(&dict, "5", 5, AV_DICT_DONT_OVERWRITE);
+ av_dict_set_int(&dict, "5", 6, AV_DICT_DONT_OVERWRITE);
+ av_dict_set_int(&dict, "12", 1, 0);
+ av_dict_set_int(&dict, "12", 2, AV_DICT_APPEND);
+ e = NULL;
+ while ((e = av_dict_get(dict, "", e, AV_DICT_IGNORE_SUFFIX)))
+ printf("%s %s\n", e->key, e->value);
+ av_dict_free(&dict);
+
+ //valgrind sensible test
+ printf("\nTesting av_dict_set() with existing AVDictionaryEntry.key as key\n");
+ av_dict_set(&dict, "key", "old", 0);
+ e = av_dict_get(dict, "key", NULL, 0);
+ av_dict_set(&dict, e->key, "new val OK", 0);
+ e = av_dict_get(dict, "key", NULL, 0);
+ printf("%s\n", e->value);
+ av_dict_set(&dict, e->key, e->value, 0);
+ e = av_dict_get(dict, "key", NULL, 0);
+ printf("%s\n", e->value);
+ av_dict_free(&dict);
+
+ return 0;
+}
+#endif
diff --git a/libavutil/dict.h b/libavutil/dict.h
index e4aee27ca3..f2df687c03 100644
--- a/libavutil/dict.h
+++ b/libavutil/dict.h
@@ -1,30 +1,40 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Public dictionary API.
+ * @deprecated
+ * AVDictionary is provided for compatibility with libav. It is both in
+ * implementation as well as API inefficient. It does not scale and is
+ * extremely slow with large dictionaries.
+ * It is recommended that new code uses our tree container from tree.c/h
+ * where applicable, which uses AVL trees to achieve O(log n) performance.
*/
#ifndef AVUTIL_DICT_H
#define AVUTIL_DICT_H
+#include <stdint.h>
+
+#include "version.h"
+
/**
* @addtogroup lavu_dict AVDictionary
* @ingroup lavu_data
@@ -58,12 +68,13 @@
*
*/
-#define AV_DICT_MATCH_CASE 1
-#define AV_DICT_IGNORE_SUFFIX 2
+#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */
+#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key,
+ ignoring the suffix of the found key string. Only relevant in av_dict_get(). */
#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been
- allocated with av_malloc() and children. */
+ allocated with av_malloc() or another memory allocation function. */
#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been
- allocated with av_malloc() and chilren. */
+ allocated with av_malloc() or another memory allocation function. */
#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries.
#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no
delimiter is added, the strings are simply concatenated. */
@@ -78,10 +89,17 @@ typedef struct AVDictionary AVDictionary;
/**
* Get a dictionary entry with matching key.
*
+ * The returned entry key or value must not be changed, or it will
+ * cause undefined behavior.
+ *
+ * To iterate through all the dictionary entries, you can set the matching key
+ * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag.
+ *
* @param prev Set to the previous matching element to find the next.
* If set to NULL the first matching element is returned.
- * @param flags Allows case as well as suffix-insensitive comparisons.
- * @return Found entry or NULL, changing key or value leads to undefined behavior.
+ * @param key matching key
+ * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved
+ * @return found entry or NULL in case no matching entry was found in the dictionary
*/
AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key,
const AVDictionaryEntry *prev, int flags);
@@ -97,6 +115,9 @@ int av_dict_count(const AVDictionary *m);
/**
* Set the given entry in *pm, overwriting an existing entry.
*
+ * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set,
+ * these arguments will be freed on error.
+ *
* @param pm pointer to a pointer to a dictionary struct. If *pm is NULL
* a dictionary struct is allocated and put in *pm.
* @param key entry key to add to *pm (will be av_strduped depending on flags)
@@ -107,7 +128,18 @@ int av_dict_count(const AVDictionary *m);
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags);
/**
- * Parse the key/value pairs list and add to a dictionary.
+ * Convenience wrapper for av_dict_set that converts the value to a string
+ * and stores it.
+ *
+ * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error.
+ */
+int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags);
+
+/**
+ * Parse the key/value pairs list and add the parsed entries to a dictionary.
+ *
+ * In case of failure, all the successfully set entries are stored in
+ * *pm. You may need to manually free the created dictionary.
*
* @param key_val_sep a 0-terminated list of characters used to separate
* key from value
@@ -140,6 +172,24 @@ void av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags);
void av_dict_free(AVDictionary **m);
/**
+ * Get dictionary entries as a string.
+ *
+ * Create a string containing dictionary's entries.
+ * Such string may be passed back to av_dict_parse_string().
+ * @note String is escaped with backslashes ('\').
+ *
+ * @param[in] m dictionary
+ * @param[out] buffer Pointer to buffer that will be allocated with string containg entries.
+ * Buffer must be freed by the caller when is no longer needed.
+ * @param[in] key_val_sep character used to separate key from value
+ * @param[in] pairs_sep character used to separate two pairs from each other
+ * @return >= 0 on success, negative on error
+ * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same.
+ */
+int av_dict_get_string(const AVDictionary *m, char **buffer,
+ const char key_val_sep, const char pairs_sep);
+
+/**
* @}
*/
diff --git a/libavutil/display.c b/libavutil/display.c
index f7500948ff..a0076e067b 100644
--- a/libavutil/display.c
+++ b/libavutil/display.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -35,10 +35,8 @@ double av_display_rotation_get(const int32_t matrix[9])
{
double rotation, scale[2];
- scale[0] = sqrt(CONV_FP(matrix[0]) * CONV_FP(matrix[0]) +
- CONV_FP(matrix[3]) * CONV_FP(matrix[3]));
- scale[1] = sqrt(CONV_FP(matrix[1]) * CONV_FP(matrix[1]) +
- CONV_FP(matrix[4]) * CONV_FP(matrix[4]));
+ scale[0] = hypot(CONV_FP(matrix[0]), CONV_FP(matrix[3]));
+ scale[1] = hypot(CONV_FP(matrix[1]), CONV_FP(matrix[4]));
if (scale[0] == 0.0 || scale[1] == 0.0)
return NAN;
diff --git a/libavutil/display.h b/libavutil/display.h
index dba3b1e60d..c0cfee326d 100644
--- a/libavutil/display.h
+++ b/libavutil/display.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/downmix_info.c b/libavutil/downmix_info.c
index 51505c8e04..c634c6a79f 100644
--- a/libavutil/downmix_info.c
+++ b/libavutil/downmix_info.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/downmix_info.h b/libavutil/downmix_info.h
index 69969f6fbd..221cf5bf9b 100644
--- a/libavutil/downmix_info.h
+++ b/libavutil/downmix_info.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -95,11 +95,12 @@ typedef struct AVDownmixInfo {
/**
* Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing.
*
- * The side data is created and added to the frame if it's absent.
+ * If the side data is absent, it is created and added to the frame.
*
- * @param frame the frame for which the side data is to be obtained.
+ * @param frame the frame for which the side data is to be obtained or created
*
- * @return the AVDownmixInfo structure to be edited by the caller.
+ * @return the AVDownmixInfo structure to be edited by the caller, or NULL if
+ * the structure cannot be allocated.
*/
AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame);
diff --git a/libavutil/dynarray.h b/libavutil/dynarray.h
new file mode 100644
index 0000000000..4947d93dc8
--- /dev/null
+++ b/libavutil/dynarray.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_DYNARRAY_H
+#define AVUTIL_DYNARRAY_H
+
+#include "log.h"
+#include "mem.h"
+
+/**
+ * Add an element of to a dynamic array.
+ *
+ * The array is reallocated when its number of elements reaches powers of 2.
+ * Therefore, the amortized cost of adding an element is constant.
+ *
+ * In case of success, the pointer to the array is updated in order to
+ * point to the new grown array, and the size is incremented.
+ *
+ * @param av_size_max maximum size of the array, usually the MAX macro of
+ * the type of the size
+ * @param av_elt_size size of the elements in the array, in bytes
+ * @param av_array pointer to the array, must be a lvalue
+ * @param av_size size of the array, must be an integer lvalue
+ * @param av_success statement to execute on success; at this point, the
+ * size variable is not yet incremented
+ * @param av_failure statement to execute on failure; if this happens, the
+ * array and size are not changed; the statement can end
+ * with a return or a goto
+ */
+#define AV_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, \
+ av_success, av_failure) \
+ do { \
+ size_t av_size_new = (av_size); \
+ if (!((av_size) & ((av_size) - 1))) { \
+ av_size_new = (av_size) ? (av_size) << 1 : 1; \
+ if (av_size_new > (av_size_max) / (av_elt_size)) { \
+ av_size_new = 0; \
+ } else { \
+ void *av_array_new = \
+ av_realloc((av_array), av_size_new * (av_elt_size)); \
+ if (!av_array_new) \
+ av_size_new = 0; \
+ else \
+ (av_array) = av_array_new; \
+ } \
+ } \
+ if (av_size_new) { \
+ { av_success } \
+ (av_size)++; \
+ } else { \
+ av_failure \
+ } \
+ } while (0)
+
+#endif /* AVUTIL_DYNARRAY_H */
diff --git a/libavutil/error.c b/libavutil/error.c
index 6803d2d4cd..44259682eb 100644
--- a/libavutil/error.c
+++ b/libavutil/error.c
@@ -1,54 +1,86 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#undef _GNU_SOURCE
+#define _XOPEN_SOURCE 600 /* XSI-compliant version of strerror_r */
#include "avutil.h"
#include "avstring.h"
#include "common.h"
+struct error_entry {
+ int num;
+ const char *tag;
+ const char *str;
+};
+
+#define ERROR_TAG(tag) AVERROR_##tag, #tag
+#define EERROR_TAG(tag) AVERROR(tag), #tag
+#define AVERROR_INPUT_AND_OUTPUT_CHANGED (AVERROR_INPUT_CHANGED | AVERROR_OUTPUT_CHANGED)
+static const struct error_entry error_entries[] = {
+ { ERROR_TAG(BSF_NOT_FOUND), "Bitstream filter not found" },
+ { ERROR_TAG(BUG), "Internal bug, should not have happened" },
+ { ERROR_TAG(BUG2), "Internal bug, should not have happened" },
+ { ERROR_TAG(BUFFER_TOO_SMALL), "Buffer too small" },
+ { ERROR_TAG(DECODER_NOT_FOUND), "Decoder not found" },
+ { ERROR_TAG(DEMUXER_NOT_FOUND), "Demuxer not found" },
+ { ERROR_TAG(ENCODER_NOT_FOUND), "Encoder not found" },
+ { ERROR_TAG(EOF), "End of file" },
+ { ERROR_TAG(EXIT), "Immediate exit requested" },
+ { ERROR_TAG(EXTERNAL), "Generic error in an external library" },
+ { ERROR_TAG(FILTER_NOT_FOUND), "Filter not found" },
+ { ERROR_TAG(INPUT_CHANGED), "Input changed" },
+ { ERROR_TAG(INVALIDDATA), "Invalid data found when processing input" },
+ { ERROR_TAG(MUXER_NOT_FOUND), "Muxer not found" },
+ { ERROR_TAG(OPTION_NOT_FOUND), "Option not found" },
+ { ERROR_TAG(OUTPUT_CHANGED), "Output changed" },
+ { ERROR_TAG(PATCHWELCOME), "Not yet implemented in FFmpeg, patches welcome" },
+ { ERROR_TAG(PROTOCOL_NOT_FOUND), "Protocol not found" },
+ { ERROR_TAG(STREAM_NOT_FOUND), "Stream not found" },
+ { ERROR_TAG(UNKNOWN), "Unknown error occurred" },
+ { ERROR_TAG(EXPERIMENTAL), "Experimental feature" },
+ { ERROR_TAG(INPUT_AND_OUTPUT_CHANGED), "Input and output changed" },
+ { ERROR_TAG(HTTP_BAD_REQUEST), "Server returned 400 Bad Request" },
+ { 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_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
+ { EERROR_TAG(EINVAL), "Invalid argument" },
+#endif
+};
+
int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
{
- int ret = 0;
- const char *errstr = NULL;
-
- switch (errnum) {
- case AVERROR_BSF_NOT_FOUND: errstr = "Bitstream filter not found" ; break;
- case AVERROR_DECODER_NOT_FOUND: errstr = "Decoder not found" ; break;
- case AVERROR_DEMUXER_NOT_FOUND: errstr = "Demuxer not found" ; break;
- case AVERROR_ENCODER_NOT_FOUND: errstr = "Encoder not found" ; break;
- case AVERROR_EOF: errstr = "End of file" ; break;
- case AVERROR_EXIT: errstr = "Immediate exit requested" ; break;
- case AVERROR_FILTER_NOT_FOUND: errstr = "Filter not found" ; break;
- case AVERROR_INVALIDDATA: errstr = "Invalid data found when processing input" ; break;
- case AVERROR_MUXER_NOT_FOUND: errstr = "Muxer not found" ; break;
- case AVERROR_OPTION_NOT_FOUND: errstr = "Option not found" ; break;
- case AVERROR_PATCHWELCOME: errstr = "Not yet implemented in Libav, patches welcome"; break;
- case AVERROR_PROTOCOL_NOT_FOUND:errstr = "Protocol not found" ; break;
- case AVERROR_STREAM_NOT_FOUND: errstr = "Stream not found" ; break;
- case AVERROR_BUG: errstr = "Bug detected, please report the issue" ; break;
- case AVERROR_UNKNOWN: errstr = "Unknown error occurred" ; break;
- case AVERROR_EXPERIMENTAL: errstr = "Experimental feature" ; break;
- }
+ int ret = 0, i;
+ const struct error_entry *entry = NULL;
- if (errstr) {
- av_strlcpy(errbuf, errstr, errbuf_size);
+ for (i = 0; i < FF_ARRAY_ELEMS(error_entries); i++) {
+ if (errnum == error_entries[i].num) {
+ entry = &error_entries[i];
+ break;
+ }
+ }
+ if (entry) {
+ av_strlcpy(errbuf, entry->str, errbuf_size);
} else {
#if HAVE_STRERROR_R
- ret = strerror_r(AVUNERROR(errnum), errbuf, errbuf_size);
+ ret = AVERROR(strerror_r(AVUNERROR(errnum), errbuf, errbuf_size));
#else
ret = -1;
#endif
@@ -58,3 +90,25 @@ int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
return ret;
}
+
+#ifdef TEST
+
+#undef printf
+
+int main(void)
+{
+ int i;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(error_entries); i++) {
+ const struct error_entry *entry = &error_entries[i];
+ printf("%d: %s [%s]\n", entry->num, av_err2str(entry->num), entry->tag);
+ }
+
+ for (i = 0; i < 256; i++) {
+ printf("%d: %s\n", -i, av_err2str(-i));
+ }
+
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/libavutil/error.h b/libavutil/error.h
index 8be87cbeba..71df4da353 100644
--- a/libavutil/error.h
+++ b/libavutil/error.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -44,24 +44,43 @@
#define AVUNERROR(e) (e)
#endif
-#define AVERROR_BSF_NOT_FOUND (-0x39acbd08) ///< Bitstream filter not found
-#define AVERROR_DECODER_NOT_FOUND (-0x3cbabb08) ///< Decoder not found
-#define AVERROR_DEMUXER_NOT_FOUND (-0x32babb08) ///< Demuxer not found
-#define AVERROR_ENCODER_NOT_FOUND (-0x3cb1ba08) ///< Encoder not found
-#define AVERROR_EOF (-0x5fb9b0bb) ///< End of file
-#define AVERROR_EXIT (-0x2bb6a7bb) ///< Immediate exit was requested; the called function should not be restarted
-#define AVERROR_FILTER_NOT_FOUND (-0x33b6b908) ///< Filter not found
-#define AVERROR_INVALIDDATA (-0x3ebbb1b7) ///< Invalid data found when processing input
-#define AVERROR_MUXER_NOT_FOUND (-0x27aab208) ///< Muxer not found
-#define AVERROR_OPTION_NOT_FOUND (-0x2bafb008) ///< Option not found
-#define AVERROR_PATCHWELCOME (-0x3aa8beb0) ///< Not yet implemented in Libav, patches welcome
-#define AVERROR_PROTOCOL_NOT_FOUND (-0x30adaf08) ///< Protocol not found
-#define AVERROR_STREAM_NOT_FOUND (-0x2dabac08) ///< Stream not found
-#define AVERROR_BUG (-0x5fb8aabe) ///< Bug detected, please report the issue
-#define AVERROR_UNKNOWN (-0x31b4b1ab) ///< Unknown error, typically from an external library
+#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d))
+
+#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found
+#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2
+#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small
+#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found
+#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found
+#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found
+#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file
+#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted
+#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library
+#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found
+#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input
+#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found
+#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found
+#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome
+#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found
+
+#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found
+/**
+ * This is semantically identical to AVERROR_BUG
+ * it has been introduced in Libav after our AVERROR_BUG and with a modified value.
+ */
+#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ')
+#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library
#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it.
#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED)
#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED)
+/* HTTP & RTSP errors */
+#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0')
+#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1')
+#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3')
+#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4')
+#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X')
+#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X')
+
+#define AV_ERROR_MAX_STRING_SIZE 64
/**
* Put a description of the AVERROR code errnum in errbuf.
@@ -78,6 +97,29 @@
int av_strerror(int errnum, char *errbuf, size_t errbuf_size);
/**
+ * Fill the provided buffer with a string containing an error string
+ * corresponding to the AVERROR code errnum.
+ *
+ * @param errbuf a buffer
+ * @param errbuf_size size in bytes of errbuf
+ * @param errnum error code to describe
+ * @return the buffer in input, filled with the error description
+ * @see av_strerror()
+ */
+static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum)
+{
+ av_strerror(errnum, errbuf, errbuf_size);
+ return errbuf;
+}
+
+/**
+ * Convenience macro, the return value should be used only directly in
+ * function arguments but never stand-alone.
+ */
+#define av_err2str(errnum) \
+ av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum)
+
+/**
* @}
*/
diff --git a/libavutil/eval.c b/libavutil/eval.c
index 31e9ebbc9c..1dfcbef7bb 100644
--- a/libavutil/eval.c
+++ b/libavutil/eval.c
@@ -2,20 +2,20 @@
* Copyright (c) 2002-2006 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,12 +26,14 @@
* see http://joe.hotchkiss.com/programming/eval/eval.html
*/
+#include <float.h>
#include "attributes.h"
#include "avutil.h"
#include "common.h"
#include "eval.h"
#include "log.h"
#include "mathematics.h"
+#include "time.h"
#include "avstring.h"
#include "timer.h"
@@ -49,10 +51,10 @@ typedef struct Parser {
int log_offset;
void *log_ctx;
#define VARS 10
- double var[VARS];
+ double *var;
} Parser;
-static const AVClass class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) };
+static const AVClass eval_class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) };
static const int8_t si_prefixes['z' - 'E' + 1] = {
['y'-'E']= -24,
@@ -77,11 +79,24 @@ static const int8_t si_prefixes['z' - 'E' + 1] = {
['Y'-'E']= 24,
};
+static const struct {
+ const char *name;
+ double value;
+} constants[] = {
+ { "E", M_E },
+ { "PI", M_PI },
+ { "PHI", M_PHI },
+ { "QP2LAMBDA", FF_QP2LAMBDA },
+};
+
double av_strtod(const char *numstr, char **tail)
{
double d;
char *next;
- d = strtod(numstr, &next);
+ if(numstr[0]=='0' && (numstr[1]|0x20)=='x') {
+ d = strtoul(numstr, &next, 16);
+ } else
+ d = strtod(numstr, &next);
/* if parsing succeeded, check for and interpret postfixes */
if (next!=numstr) {
if (next[0] == 'd' && next[1] == 'B') {
@@ -129,10 +144,11 @@ struct AVExpr {
enum {
e_value, e_const, e_func0, e_func1, e_func2,
e_squish, e_gauss, e_ld, e_isnan, e_isinf,
- e_mod, e_max, e_min, e_eq, e_gt, e_gte,
+ e_mod, e_max, e_min, e_eq, e_gt, e_gte, e_lte, e_lt,
e_pow, e_mul, e_div, e_add,
- e_last, e_st, e_while, e_floor, e_ceil, e_trunc,
- e_sqrt, e_not,
+ e_last, e_st, e_while, e_taylor, e_root, e_floor, e_ceil, e_trunc,
+ e_sqrt, e_not, e_random, e_hypot, e_gcd,
+ e_if, e_ifnot, e_print, e_bitand, e_bitor, e_between, e_clip
} type;
double value; // is sign in other types
union {
@@ -141,9 +157,15 @@ struct AVExpr {
double (*func1)(void *, double);
double (*func2)(void *, double, double);
} a;
- struct AVExpr *param[2];
+ struct AVExpr *param[3];
+ double *var;
};
+static double etime(double v)
+{
+ return av_gettime() * 0.000001;
+}
+
static double eval_expr(Parser *p, AVExpr *e)
{
switch (e->type) {
@@ -161,29 +183,124 @@ static double eval_expr(Parser *p, AVExpr *e)
case e_ceil : return e->value * ceil (eval_expr(p, e->param[0]));
case e_trunc: return e->value * trunc(eval_expr(p, e->param[0]));
case e_sqrt: return e->value * sqrt (eval_expr(p, e->param[0]));
- case e_not: return e->value * eval_expr(p, e->param[0]) == 0;
+ case e_not: return e->value * (eval_expr(p, e->param[0]) == 0);
+ case e_if: return e->value * (eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) :
+ e->param[2] ? eval_expr(p, e->param[2]) : 0);
+ case e_ifnot: return e->value * (!eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) :
+ e->param[2] ? eval_expr(p, e->param[2]) : 0);
+ case e_clip: {
+ double x = eval_expr(p, e->param[0]);
+ double min = eval_expr(p, e->param[1]), max = eval_expr(p, e->param[2]);
+ if (isnan(min) || isnan(max) || isnan(x) || min > max)
+ return NAN;
+ return e->value * av_clipd(eval_expr(p, e->param[0]), min, max);
+ }
+ case e_between: {
+ double d = eval_expr(p, e->param[0]);
+ return e->value * (d >= eval_expr(p, e->param[1]) &&
+ d <= eval_expr(p, e->param[2]));
+ }
+ case e_print: {
+ double x = eval_expr(p, e->param[0]);
+ int level = e->param[1] ? av_clip(eval_expr(p, e->param[1]), INT_MIN, INT_MAX) : AV_LOG_INFO;
+ av_log(p, level, "%f\n", x);
+ return x;
+ }
+ case e_random:{
+ int idx= av_clip(eval_expr(p, e->param[0]), 0, VARS-1);
+ uint64_t r= isnan(p->var[idx]) ? 0 : p->var[idx];
+ r= r*1664525+1013904223;
+ p->var[idx]= r;
+ return e->value * (r * (1.0/UINT64_MAX));
+ }
case e_while: {
double d = NAN;
while (eval_expr(p, e->param[0]))
d=eval_expr(p, e->param[1]);
return d;
}
+ case e_taylor: {
+ double t = 1, d = 0, v;
+ double x = eval_expr(p, e->param[1]);
+ int id = e->param[2] ? av_clip(eval_expr(p, e->param[2]), 0, VARS-1) : 0;
+ int i;
+ double var0 = p->var[id];
+ for(i=0; i<1000; i++) {
+ double ld = d;
+ p->var[id] = i;
+ v = eval_expr(p, e->param[0]);
+ d += t*v;
+ if(ld==d && v)
+ break;
+ t *= x / (i+1);
+ }
+ p->var[id] = var0;
+ return d;
+ }
+ case e_root: {
+ int i, j;
+ double low = -1, high = -1, v, low_v = -DBL_MAX, high_v = DBL_MAX;
+ double var0 = p->var[0];
+ double x_max = eval_expr(p, e->param[1]);
+ for(i=-1; i<1024; i++) {
+ if(i<255) {
+ p->var[0] = av_reverse[i&255]*x_max/255;
+ } else {
+ p->var[0] = x_max*pow(0.9, i-255);
+ if (i&1) p->var[0] *= -1;
+ if (i&2) p->var[0] += low;
+ else p->var[0] += high;
+ }
+ v = eval_expr(p, e->param[0]);
+ if (v<=0 && v>low_v) {
+ low = p->var[0];
+ low_v = v;
+ }
+ if (v>=0 && v<high_v) {
+ high = p->var[0];
+ high_v = v;
+ }
+ if (low>=0 && high>=0){
+ for (j=0; j<1000; j++) {
+ p->var[0] = (low+high)*0.5;
+ if (low == p->var[0] || high == p->var[0])
+ break;
+ v = eval_expr(p, e->param[0]);
+ if (v<=0) low = p->var[0];
+ if (v>=0) high= p->var[0];
+ if (isnan(v)) {
+ low = high = v;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ p->var[0] = var0;
+ return -low_v<high_v ? low : high;
+ }
default: {
double d = eval_expr(p, e->param[0]);
double d2 = eval_expr(p, e->param[1]);
switch (e->type) {
- case e_mod: return e->value * (d - floor(d/d2)*d2);
+ case e_mod: return e->value * (d - floor((!CONFIG_FTRAPV || d2) ? d / d2 : d * INFINITY) * d2);
+ case e_gcd: return e->value * av_gcd(d,d2);
case e_max: return e->value * (d > d2 ? d : d2);
case e_min: return e->value * (d < d2 ? d : d2);
case e_eq: return e->value * (d == d2 ? 1.0 : 0.0);
case e_gt: return e->value * (d > d2 ? 1.0 : 0.0);
case e_gte: return e->value * (d >= d2 ? 1.0 : 0.0);
+ case e_lt: return e->value * (d < d2 ? 1.0 : 0.0);
+ case e_lte: return e->value * (d <= d2 ? 1.0 : 0.0);
case e_pow: return e->value * pow(d, d2);
case e_mul: return e->value * (d * d2);
- case e_div: return e->value * (d / d2);
+ case e_div: return e->value * ((!CONFIG_FTRAPV || d2 ) ? (d / d2) : d * INFINITY);
case e_add: return e->value * (d + d2);
case e_last:return e->value * d2;
case e_st : return e->value * (p->var[av_clip(d, 0, VARS-1)]= d2);
+ case e_hypot:return e->value * (sqrt(d*d + d2*d2));
+ case e_bitand: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d & (long int)d2);
+ case e_bitor: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d | (long int)d2);
}
}
}
@@ -197,6 +314,8 @@ void av_expr_free(AVExpr *e)
if (!e) return;
av_expr_free(e->param[0]);
av_expr_free(e->param[1]);
+ av_expr_free(e->param[2]);
+ av_freep(&e->var);
av_freep(&e);
}
@@ -229,6 +348,15 @@ static int parse_primary(AVExpr **e, Parser *p)
return 0;
}
}
+ for (i = 0; i < FF_ARRAY_ELEMS(constants); i++) {
+ if (strmatch(p->s, constants[i].name)) {
+ p->s += strlen(constants[i].name);
+ d->type = e_value;
+ d->value = constants[i].value;
+ *e = d;
+ return 0;
+ }
+ }
p->s= strchr(p->s, '(');
if (!p->s) {
@@ -259,6 +387,10 @@ static int parse_primary(AVExpr **e, Parser *p)
p->s++; // ","
parse_expr(&d->param[1], p);
}
+ if (p->s[0]== ',') {
+ p->s++; // ","
+ parse_expr(&d->param[2], p);
+ }
if (p->s[0] != ')') {
av_log(p, AV_LOG_ERROR, "Missing ')' or too many args in '%s'\n", s0);
av_expr_free(d);
@@ -279,6 +411,7 @@ static int parse_primary(AVExpr **e, Parser *p)
else if (strmatch(next, "exp" )) d->a.func0 = exp;
else if (strmatch(next, "log" )) d->a.func0 = log;
else if (strmatch(next, "abs" )) d->a.func0 = fabs;
+ else if (strmatch(next, "time" )) d->a.func0 = etime;
else if (strmatch(next, "squish")) d->type = e_squish;
else if (strmatch(next, "gauss" )) d->type = e_gauss;
else if (strmatch(next, "mod" )) d->type = e_mod;
@@ -287,18 +420,31 @@ static int parse_primary(AVExpr **e, Parser *p)
else if (strmatch(next, "eq" )) d->type = e_eq;
else if (strmatch(next, "gte" )) d->type = e_gte;
else if (strmatch(next, "gt" )) d->type = e_gt;
- else if (strmatch(next, "lte" )) { AVExpr *tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gte; }
- else if (strmatch(next, "lt" )) { AVExpr *tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gt; }
+ else if (strmatch(next, "lte" )) d->type = e_lte;
+ else if (strmatch(next, "lt" )) d->type = e_lt;
else if (strmatch(next, "ld" )) d->type = e_ld;
else if (strmatch(next, "isnan" )) d->type = e_isnan;
else if (strmatch(next, "isinf" )) d->type = e_isinf;
else if (strmatch(next, "st" )) d->type = e_st;
else if (strmatch(next, "while" )) d->type = e_while;
+ else if (strmatch(next, "taylor")) d->type = e_taylor;
+ else if (strmatch(next, "root" )) d->type = e_root;
else if (strmatch(next, "floor" )) d->type = e_floor;
else if (strmatch(next, "ceil" )) d->type = e_ceil;
else if (strmatch(next, "trunc" )) d->type = e_trunc;
else if (strmatch(next, "sqrt" )) d->type = e_sqrt;
else if (strmatch(next, "not" )) d->type = e_not;
+ else if (strmatch(next, "pow" )) d->type = e_pow;
+ else if (strmatch(next, "print" )) d->type = e_print;
+ else if (strmatch(next, "random")) d->type = e_random;
+ else if (strmatch(next, "hypot" )) d->type = e_hypot;
+ else if (strmatch(next, "gcd" )) d->type = e_gcd;
+ else if (strmatch(next, "if" )) d->type = e_if;
+ else if (strmatch(next, "ifnot" )) d->type = e_ifnot;
+ else if (strmatch(next, "bitand")) d->type = e_bitand;
+ else if (strmatch(next, "bitor" )) d->type = e_bitor;
+ else if (strmatch(next, "between"))d->type = e_between;
+ else if (strmatch(next, "clip" )) d->type = e_clip;
else {
for (i=0; p->func1_names && p->func1_names[i]; i++) {
if (strmatch(next, p->func1_names[i])) {
@@ -327,7 +473,7 @@ static int parse_primary(AVExpr **e, Parser *p)
return 0;
}
-static AVExpr *new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1)
+static AVExpr *make_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1)
{
AVExpr *e = av_mallocz(sizeof(AVExpr));
if (!e)
@@ -374,7 +520,7 @@ static int parse_factor(AVExpr **e, Parser *p)
av_expr_free(e1);
return ret;
}
- e0 = new_eval_expr(e_pow, 1, e1, e2);
+ e0 = make_eval_expr(e_pow, 1, e1, e2);
if (!e0) {
av_expr_free(e1);
av_expr_free(e2);
@@ -401,7 +547,7 @@ static int parse_term(AVExpr **e, Parser *p)
av_expr_free(e1);
return ret;
}
- e0 = new_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2);
+ e0 = make_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2);
if (!e0) {
av_expr_free(e1);
av_expr_free(e2);
@@ -424,7 +570,7 @@ static int parse_subexpr(AVExpr **e, Parser *p)
av_expr_free(e1);
return ret;
}
- e0 = new_eval_expr(e_add, 1, e1, e2);
+ e0 = make_eval_expr(e_add, 1, e1, e2);
if (!e0) {
av_expr_free(e1);
av_expr_free(e2);
@@ -453,7 +599,7 @@ static int parse_expr(AVExpr **e, Parser *p)
av_expr_free(e1);
return ret;
}
- e0 = new_eval_expr(e_last, 1, e1, e2);
+ e0 = make_eval_expr(e_last, 1, e1, e2);
if (!e0) {
av_expr_free(e1);
av_expr_free(e2);
@@ -484,8 +630,22 @@ static int verify_expr(AVExpr *e)
case e_trunc:
case e_sqrt:
case e_not:
- return verify_expr(e->param[0]);
- default: return verify_expr(e->param[0]) && verify_expr(e->param[1]);
+ case e_random:
+ return verify_expr(e->param[0]) && !e->param[1];
+ case e_print:
+ return verify_expr(e->param[0])
+ && (!e->param[1] || verify_expr(e->param[1]));
+ case e_if:
+ case e_ifnot:
+ case e_taylor:
+ return verify_expr(e->param[0]) && verify_expr(e->param[1])
+ && (!e->param[2] || verify_expr(e->param[2]));
+ case e_between:
+ case e_clip:
+ return verify_expr(e->param[0]) &&
+ verify_expr(e->param[1]) &&
+ verify_expr(e->param[2]);
+ default: return verify_expr(e->param[0]) && verify_expr(e->param[1]) && !e->param[2];
}
}
@@ -509,7 +669,7 @@ int av_expr_parse(AVExpr **expr, const char *s,
if (!av_isspace(*s++)) *wp++ = s[-1];
*wp++ = 0;
- p.class = &class;
+ p.class = &eval_class;
p.stack_index=100;
p.s= w;
p.const_names = const_names;
@@ -523,18 +683,23 @@ int av_expr_parse(AVExpr **expr, const char *s,
if ((ret = parse_expr(&e, &p)) < 0)
goto end;
if (*p.s) {
- av_expr_free(e);
av_log(&p, AV_LOG_ERROR, "Invalid chars '%s' at the end of expression '%s'\n", p.s, s0);
ret = AVERROR(EINVAL);
goto end;
}
if (!verify_expr(e)) {
- av_expr_free(e);
ret = AVERROR(EINVAL);
goto end;
}
+ e->var= av_mallocz(sizeof(double) *VARS);
+ if (!e->var) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
*expr = e;
+ e = NULL;
end:
+ av_expr_free(e);
av_free(w);
return ret;
}
@@ -542,6 +707,7 @@ end:
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
{
Parser p = { 0 };
+ p.var= e->var;
p.const_values = const_values;
p.opaque = opaque;
@@ -653,6 +819,35 @@ int main(int argc, char **argv)
"not(0)",
"6.0206dB",
"-3.0103dB",
+ "pow(0,1.23)",
+ "pow(PI,1.23)",
+ "PI^1.23",
+ "pow(-1,1.23)",
+ "if(1, 2)",
+ "if(1, 1, 2)",
+ "if(0, 1, 2)",
+ "ifnot(0, 23)",
+ "ifnot(1, NaN) + if(0, 1)",
+ "ifnot(1, 1, 2)",
+ "ifnot(0, 1, 2)",
+ "taylor(1, 1)",
+ "taylor(eq(mod(ld(1),4),1)-eq(mod(ld(1),4),3), PI/2, 1)",
+ "root(sin(ld(0))-1, 2)",
+ "root(sin(ld(0))+6+sin(ld(0)/12)-log(ld(0)), 100)",
+ "7000000B*random(0)",
+ "squish(2)",
+ "gauss(0.1)",
+ "hypot(4,3)",
+ "gcd(30,55)*print(min(9,1))",
+ "bitor(42, 12)",
+ "bitand(42, 12)",
+ "bitand(NAN, 1)",
+ "between(10, -3, 10)",
+ "between(-4, -2, -1)",
+ "between(1,2)",
+ "clip(0, 2, 1)",
+ "clip(0/0, 1, 2)",
+ "clip(0, 0/0, 1)",
NULL
};
diff --git a/libavutil/eval.h b/libavutil/eval.h
index ccb29e7a33..6159b0fe58 100644
--- a/libavutil/eval.h
+++ b/libavutil/eval.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,7 +45,7 @@ typedef struct AVExpr AVExpr;
* @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments
* @param opaque a pointer which will be passed to all functions from funcs1 and funcs2
* @param log_ctx parent logging context
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code otherwise
*/
int av_expr_parse_and_eval(double *res, const char *s,
@@ -68,7 +68,7 @@ int av_expr_parse_and_eval(double *res, const char *s,
* @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers
* @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments
* @param log_ctx parent logging context
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code otherwise
*/
int av_expr_parse(AVExpr **expr, const char *s,
diff --git a/libavutil/fifo.c b/libavutil/fifo.c
index dffaf54533..4ff3194c5f 100644
--- a/libavutil/fifo.c
+++ b/libavutil/fifo.c
@@ -3,58 +3,83 @@
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2006 Roman Shaposhnik
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+
+#include "avassert.h"
#include "common.h"
#include "fifo.h"
-AVFifoBuffer *av_fifo_alloc(unsigned int size)
+static AVFifoBuffer *fifo_alloc_common(void *buffer, size_t size)
{
- AVFifoBuffer *f = av_mallocz(sizeof(AVFifoBuffer));
- if (!f)
+ AVFifoBuffer *f;
+ if (!buffer)
return NULL;
- f->buffer = av_malloc(size);
+ f = av_mallocz(sizeof(AVFifoBuffer));
+ if (!f) {
+ av_free(buffer);
+ return NULL;
+ }
+ f->buffer = buffer;
f->end = f->buffer + size;
av_fifo_reset(f);
- if (!f->buffer)
- av_freep(&f);
return f;
}
+AVFifoBuffer *av_fifo_alloc(unsigned int size)
+{
+ void *buffer = av_malloc(size);
+ return fifo_alloc_common(buffer, size);
+}
+
+AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size)
+{
+ void *buffer = av_malloc_array(nmemb, size);
+ return fifo_alloc_common(buffer, nmemb * size);
+}
+
void av_fifo_free(AVFifoBuffer *f)
{
if (f) {
- av_free(f->buffer);
+ av_freep(&f->buffer);
av_free(f);
}
}
+void av_fifo_freep(AVFifoBuffer **f)
+{
+ if (f) {
+ av_fifo_free(*f);
+ *f = NULL;
+ }
+}
+
void av_fifo_reset(AVFifoBuffer *f)
{
f->wptr = f->rptr = f->buffer;
f->wndx = f->rndx = 0;
}
-int av_fifo_size(AVFifoBuffer *f)
+int av_fifo_size(const AVFifoBuffer *f)
{
return (uint32_t)(f->wndx - f->rndx);
}
-int av_fifo_space(AVFifoBuffer *f)
+int av_fifo_space(const AVFifoBuffer *f)
{
return f->end - f->buffer - av_fifo_size(f);
}
@@ -68,7 +93,7 @@ int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
AVFifoBuffer *f2 = av_fifo_alloc(new_size);
if (!f2)
- return -1;
+ return AVERROR(ENOMEM);
av_fifo_generic_read(f, f2->buffer, len, NULL);
f2->wptr += len;
f2->wndx += len;
@@ -79,28 +104,46 @@ int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
return 0;
}
+int av_fifo_grow(AVFifoBuffer *f, unsigned int size)
+{
+ unsigned int old_size = f->end - f->buffer;
+ if(size + (unsigned)av_fifo_size(f) < size)
+ return AVERROR(EINVAL);
+
+ size += av_fifo_size(f);
+
+ if (old_size < size)
+ return av_fifo_realloc2(f, FFMAX(size, 2*size));
+ return 0;
+}
+
/* src must NOT be const as it can be a context for func that may need
* updating (like a pointer or byte counter) */
int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size,
int (*func)(void *, void *, int))
{
int total = size;
+ uint32_t wndx= f->wndx;
+ uint8_t *wptr= f->wptr;
+
do {
- int len = FFMIN(f->end - f->wptr, size);
+ int len = FFMIN(f->end - wptr, size);
if (func) {
- if (func(src, f->wptr, len) <= 0)
+ if (func(src, wptr, len) <= 0)
break;
} else {
- memcpy(f->wptr, src, len);
+ memcpy(wptr, src, len);
src = (uint8_t *)src + len;
}
// Write memory barrier needed for SMP here in theory
- f->wptr += len;
- if (f->wptr >= f->end)
- f->wptr = f->buffer;
- f->wndx += len;
+ wptr += len;
+ if (wptr >= f->end)
+ wptr = f->buffer;
+ wndx += len;
size -= len;
} while (size > 0);
+ f->wndx= wndx;
+ f->wptr= wptr;
return total - size;
}
@@ -126,6 +169,7 @@ int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size,
/** Discard data from the FIFO. */
void av_fifo_drain(AVFifoBuffer *f, int size)
{
+ av_assert2(av_fifo_size(f) >= size);
f->rptr += size;
if (f->rptr >= f->end)
f->rptr -= f->end - f->buffer;
diff --git a/libavutil/fifo.h b/libavutil/fifo.h
index ea30f5d2bd..f3bdcbceb4 100644
--- a/libavutil/fifo.h
+++ b/libavutil/fifo.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,12 +42,26 @@ typedef struct AVFifoBuffer {
AVFifoBuffer *av_fifo_alloc(unsigned int size);
/**
+ * Initialize an AVFifoBuffer.
+ * @param nmemb number of elements
+ * @param size size of the single element
+ * @return AVFifoBuffer or NULL in case of memory allocation failure
+ */
+AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size);
+
+/**
* Free an AVFifoBuffer.
* @param f AVFifoBuffer to free
*/
void av_fifo_free(AVFifoBuffer *f);
/**
+ * Free an AVFifoBuffer and reset pointer to NULL.
+ * @param f AVFifoBuffer to free
+ */
+void av_fifo_freep(AVFifoBuffer **f);
+
+/**
* Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied.
* @param f AVFifoBuffer to reset
*/
@@ -59,7 +73,7 @@ void av_fifo_reset(AVFifoBuffer *f);
* @param f AVFifoBuffer to read from
* @return size
*/
-int av_fifo_size(AVFifoBuffer *f);
+int av_fifo_size(const AVFifoBuffer *f);
/**
* Return the amount of space in bytes in the AVFifoBuffer, that is the
@@ -67,7 +81,7 @@ int av_fifo_size(AVFifoBuffer *f);
* @param f AVFifoBuffer to write into
* @return size
*/
-int av_fifo_space(AVFifoBuffer *f);
+int av_fifo_space(const AVFifoBuffer *f);
/**
* Feed data from an AVFifoBuffer to a user-supplied callback.
@@ -95,6 +109,8 @@ int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void
/**
* Resize an AVFifoBuffer.
+ * In case of reallocation failure, the old FIFO is kept unchanged.
+ *
* @param f AVFifoBuffer to resize
* @param size new AVFifoBuffer size in bytes
* @return <0 for failure, >=0 otherwise
@@ -102,6 +118,17 @@ int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void
int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size);
/**
+ * Enlarge an AVFifoBuffer.
+ * In case of reallocation failure, the old FIFO is kept unchanged.
+ * The new fifo size may be larger than the requested size.
+ *
+ * @param f AVFifoBuffer to resize
+ * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size()
+ * @return <0 for failure, >=0 otherwise
+ */
+int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space);
+
+/**
* Read and discard the specified amount of data from an AVFifoBuffer.
* @param f AVFifoBuffer to read from
* @param size amount of data to read in bytes
diff --git a/libavutil/file.c b/libavutil/file.c
index 18a110aeeb..2a06be4398 100644
--- a/libavutil/file.c
+++ b/libavutil/file.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -136,3 +136,70 @@ void av_file_unmap(uint8_t *bufptr, size_t size)
av_free(bufptr);
#endif
}
+
+int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx)
+{
+ FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx };
+ int fd = -1;
+#if !HAVE_MKSTEMP
+ void *ptr= tempnam(NULL, prefix);
+ if(!ptr)
+ ptr= tempnam(".", prefix);
+ *filename = av_strdup(ptr);
+#undef free
+ free(ptr);
+#else
+ size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */
+ *filename = av_malloc(len);
+#endif
+ /* -----common section-----*/
+ if (!*filename) {
+ av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot allocate file name\n");
+ return AVERROR(ENOMEM);
+ }
+#if !HAVE_MKSTEMP
+# ifndef O_BINARY
+# define O_BINARY 0
+# endif
+# ifndef O_EXCL
+# define O_EXCL 0
+# endif
+ fd = open(*filename, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600);
+#else
+ snprintf(*filename, len, "/tmp/%sXXXXXX", prefix);
+ fd = mkstemp(*filename);
+#ifdef _WIN32
+ if (fd < 0) {
+ snprintf(*filename, len, "./%sXXXXXX", prefix);
+ fd = mkstemp(*filename);
+ }
+#endif
+#endif
+ /* -----common section-----*/
+ if (fd < 0) {
+ int err = AVERROR(errno);
+ av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot open temporary file %s\n", *filename);
+ av_freep(filename);
+ return err;
+ }
+ return fd; /* success */
+}
+
+#ifdef TEST
+
+#undef printf
+
+int main(void)
+{
+ uint8_t *buf;
+ size_t size;
+ if (av_file_map("file.c", &buf, &size, 0, NULL) < 0)
+ return 1;
+
+ buf[0] = 's';
+ printf("%s", buf);
+ av_file_unmap(buf, size);
+ return 0;
+}
+#endif
+
diff --git a/libavutil/file.h b/libavutil/file.h
index e3f02a8308..1cae2951be 100644
--- a/libavutil/file.h
+++ b/libavutil/file.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -51,4 +51,17 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size,
*/
void av_file_unmap(uint8_t *bufptr, size_t size);
+/**
+ * Wrapper to work around the lack of mkstemp() on mingw.
+ * Also, tries to create file in /tmp first, if possible.
+ * *prefix can be a character constant; *filename will be allocated internally.
+ * @return file descriptor of opened file (or negative value corresponding to an
+ * AVERROR code on error)
+ * and opened file name in **filename.
+ * @note On very old libcs it is necessary to set a secure umask before
+ * calling this, av_tempfile() can't call umask itself as it is used in
+ * libraries and could interfere with the calling application.
+ */
+int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx);
+
#endif /* AVUTIL_FILE_H */
diff --git a/libavutil/file_open.c b/libavutil/file_open.c
index f14ea70862..3f9a67c3fc 100644
--- a/libavutil/file_open.c
+++ b/libavutil/file_open.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -57,7 +57,7 @@ static int win32_open(const char *filename_utf8, int oflag, int pmode)
return fd;
fallback:
- /* filename may be be in CP_ACP */
+ /* filename may be in CP_ACP */
return _sopen(filename_utf8, oflag, SH_DENYNO, pmode);
}
#define open win32_open
@@ -80,9 +80,45 @@ int avpriv_open(const char *filename, int flags, ...)
fd = open(filename, flags, mode);
#if HAVE_FCNTL
- if (fd != -1)
- fcntl(fd, F_SETFD, FD_CLOEXEC);
+ if (fd != -1) {
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n");
+ }
#endif
return fd;
}
+
+FILE *av_fopen_utf8(const char *path, const char *mode)
+{
+ int fd;
+ int access;
+ const char *m = mode;
+
+ switch (*m++) {
+ case 'r': access = O_RDONLY; break;
+ case 'w': access = O_CREAT|O_WRONLY|O_TRUNC; break;
+ case 'a': access = O_CREAT|O_WRONLY|O_APPEND; break;
+ default :
+ errno = EINVAL;
+ return NULL;
+ }
+ while (*m) {
+ if (*m == '+') {
+ access &= ~(O_RDONLY | O_WRONLY);
+ access |= O_RDWR;
+ } else if (*m == 'b') {
+#ifdef O_BINARY
+ access |= O_BINARY;
+#endif
+ } else if (*m) {
+ errno = EINVAL;
+ return NULL;
+ }
+ m++;
+ }
+ fd = avpriv_open(path, access, 0666);
+ if (fd == -1)
+ return NULL;
+ return fdopen(fd, mode);
+}
diff --git a/libavutil/fixed_dsp.c b/libavutil/fixed_dsp.c
new file mode 100644
index 0000000000..9f2e841046
--- /dev/null
+++ b/libavutil/fixed_dsp.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "fixed_dsp.h"
+
+static void vector_fmul_window_fixed_scaled_c(int16_t *dst, const int32_t *src0,
+ const int32_t *src1, const int32_t *win,
+ int len, uint8_t bits)
+{
+ int32_t s0, s1, wi, wj, i,j, round;
+
+ dst += len;
+ win += len;
+ src0+= len;
+ round = bits? 1 << (bits-1) : 0;
+
+ for (i=-len, j=len-1; i<0; i++, j--) {
+ s0 = src0[i];
+ s1 = src1[j];
+ wi = win[i];
+ wj = win[j];
+ dst[i] = av_clip_int16(((((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31) + round) >> bits);
+ dst[j] = av_clip_int16(((((int64_t)s0*wi + (int64_t)s1*wj + 0x40000000) >> 31) + round) >> bits);
+ }
+}
+
+static void vector_fmul_window_fixed_c(int32_t *dst, const int32_t *src0,
+ const int32_t *src1, const int32_t *win,
+ int len)
+{
+ int32_t s0, s1, wi, wj, i, j;
+
+ dst += len;
+ win += len;
+ src0+= len;
+
+ for (i=-len, j=len-1; i<0; i++, j--) {
+ s0 = src0[i];
+ s1 = src1[j];
+ wi = win[i];
+ wj = win[j];
+ dst[i] = ((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31;
+ dst[j] = ((int64_t)s0*wi + (int64_t)s1*wj + 0x40000000) >> 31;
+ }
+}
+
+AVFixedDSPContext * avpriv_alloc_fixed_dsp(int bit_exact)
+{
+ AVFixedDSPContext * fdsp = av_malloc(sizeof(AVFixedDSPContext));
+
+ if (!fdsp)
+ return NULL;
+
+ fdsp->vector_fmul_window_scaled = vector_fmul_window_fixed_scaled_c;
+ fdsp->vector_fmul_window = vector_fmul_window_fixed_c;
+
+ return fdsp;
+}
diff --git a/libavutil/fixed_dsp.h b/libavutil/fixed_dsp.h
new file mode 100644
index 0000000000..ff6f36599a
--- /dev/null
+++ b/libavutil/fixed_dsp.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_FIXED_DSP_H
+#define AVUTIL_FIXED_DSP_H
+
+#include <stdint.h>
+#include "attributes.h"
+#include "common.h"
+#include "libavcodec/mathops.h"
+
+typedef struct AVFixedDSPContext {
+ /**
+ * Overlap/add with window function.
+ * Used primarily by MDCT-based audio codecs.
+ * Source and destination vectors must overlap exactly or not at all.
+ *
+ * @param dst result vector
+ * constraints: 16-byte aligned
+ * @param src0 first source vector
+ * constraints: 16-byte aligned
+ * @param src1 second source vector
+ * constraints: 16-byte aligned
+ * @param win half-window vector
+ * constraints: 16-byte aligned
+ * @param len length of vector
+ * constraints: multiple of 4
+ * @param bits scaling parameter
+ *
+ */
+ void (*vector_fmul_window_scaled)(int16_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len, uint8_t bits);
+
+ /**
+ * Overlap/add with window function.
+ * Used primarily by MDCT-based audio codecs.
+ * Source and destination vectors must overlap exactly or not at all.
+ *
+ * @param dst result vector
+ * constraints: 32-byte aligned
+ * @param src0 first source vector
+ * constraints: 16-byte aligned
+ * @param src1 second source vector
+ * constraints: 16-byte aligned
+ * @param win half-window vector
+ * constraints: 16-byte aligned
+ * @param len length of vector
+ * constraints: multiple of 4
+ */
+ void (*vector_fmul_window)(int32_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len);
+
+} AVFixedDSPContext;
+
+/**
+ * Allocate and initialize a fixed DSP context.
+ * note: should be freed with a av_free call when no longer needed.
+ *
+ * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant
+ */
+AVFixedDSPContext * avpriv_alloc_fixed_dsp(int strict);
+
+/**
+ * Calculate the square root
+ *
+ * @param x input fixed point number
+ *
+ * @param bits format of fixed point number (32 - bits).bits
+ *
+ * note: input is normalized to (0, 1) fixed point value
+ */
+
+static av_always_inline int fixed_sqrt(int x, int bits)
+{
+ int retval, bit_mask, guess, square, i;
+ int64_t accu;
+ int shift1 = 30 - bits;
+ int shift2 = bits - 15;
+
+ if (shift1 > 0) retval = ff_sqrt(x << shift1);
+ else retval = ff_sqrt(x >> -shift1);
+
+ if (shift2 > 0) {
+ retval = retval << shift2;
+ bit_mask = (1 << (shift2 - 1));
+
+ for (i=0; i<shift2; i++){
+ guess = retval + bit_mask;
+ accu = (int64_t)guess * guess;
+ square = (int)((accu + bit_mask) >> bits);
+ if (x >= square)
+ retval += bit_mask;
+ bit_mask >>= 1;
+ }
+
+ }
+ else retval >>= (-shift2);
+
+ return retval;
+}
+
+#endif /* AVUTIL_FIXED_DSP_H */
diff --git a/libavutil/float_dsp.c b/libavutil/float_dsp.c
index aabc800db6..467d7a74c1 100644
--- a/libavutil/float_dsp.c
+++ b/libavutil/float_dsp.c
@@ -1,24 +1,28 @@
/*
- * This file is part of Libav.
+ * Copyright 2005 Balatoni Denes
+ * Copyright 2006 Loren Merritt
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "attributes.h"
#include "float_dsp.h"
+#include "mem.h"
static void vector_fmul_c(float *dst, const float *src0, const float *src1,
int len)
@@ -89,7 +93,7 @@ static void vector_fmul_reverse_c(float *dst, const float *src0,
dst[i] = src0[i] * src1[-i];
}
-static void butterflies_float_c(float *restrict v1, float *restrict v2,
+static void butterflies_float_c(float *av_restrict v1, float *av_restrict v2,
int len)
{
int i;
@@ -132,8 +136,19 @@ av_cold void avpriv_float_dsp_init(AVFloatDSPContext *fdsp, int bit_exact)
ff_float_dsp_init_ppc(fdsp, bit_exact);
if (ARCH_X86)
ff_float_dsp_init_x86(fdsp);
+ if (ARCH_MIPS)
+ ff_float_dsp_init_mips(fdsp);
+}
+
+av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact)
+{
+ AVFloatDSPContext *ret = av_mallocz(sizeof(AVFloatDSPContext));
+ if (ret)
+ avpriv_float_dsp_init(ret, bit_exact);
+ return ret;
}
+
#ifdef TEST
#include <float.h>
@@ -141,13 +156,18 @@ av_cold void avpriv_float_dsp_init(AVFloatDSPContext *fdsp, int bit_exact)
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h> /* for getopt */
+#endif
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
#include "common.h"
#include "cpu.h"
#include "internal.h"
#include "lfg.h"
#include "log.h"
-#include "mem.h"
#include "random_seed.h"
#define LEN 240
@@ -364,7 +384,7 @@ static int test_scalarproduct_float(AVFloatDSPContext *fdsp, AVFloatDSPContext *
int main(int argc, char **argv)
{
- int ret = 0;
+ int ret = 0, seeded = 0;
uint32_t seed;
AVFloatDSPContext fdsp, cdsp;
AVLFG lfg;
@@ -375,12 +395,31 @@ int main(int argc, char **argv)
LOCAL_ALIGNED(32, double, dbl_src0, [LEN]);
LOCAL_ALIGNED(32, double, dbl_src1, [LEN]);
- if (argc > 2 && !strcmp(argv[1], "-s"))
- seed = strtoul(argv[2], NULL, 10);
- else
+ for (;;) {
+ int arg = getopt(argc, argv, "s:c:");
+ if (arg == -1)
+ break;
+ switch (arg) {
+ case 's':
+ seed = strtoul(optarg, NULL, 10);
+ seeded = 1;
+ break;
+ case 'c':
+ {
+ int cpuflags = av_get_cpu_flags();
+
+ if (av_parse_cpu_caps(&cpuflags, optarg) < 0)
+ return 1;
+
+ av_force_cpu_flags(cpuflags);
+ break;
+ }
+ }
+ }
+ if (!seeded)
seed = av_get_random_seed();
- av_log(NULL, AV_LOG_INFO, "float_dsp-test: random seed %u\n", seed);
+ av_log(NULL, AV_LOG_INFO, "float_dsp-test: %s %u\n", seeded ? "seed" : "random seed", seed);
av_lfg_init(&lfg, seed);
diff --git a/libavutil/float_dsp.h b/libavutil/float_dsp.h
index 3142df4fd3..543f7014ee 100644
--- a/libavutil/float_dsp.h
+++ b/libavutil/float_dsp.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -145,7 +145,7 @@ typedef struct AVFloatDSPContext {
* @param v2 second input vector, difference output, 16-byte aligned
* @param len length of vectors, multiple of 4
*/
- void (*butterflies_float)(float *restrict v1, float *restrict v2, int len);
+ void (*butterflies_float)(float *av_restrict v1, float *av_restrict v2, int len);
/**
* Calculate the scalar product of two vectors of floats.
@@ -183,5 +183,13 @@ void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp);
void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp);
void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict);
void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp);
+void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp);
+
+/**
+ * Allocate a float DSP context.
+ *
+ * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant
+ */
+AVFloatDSPContext *avpriv_float_dsp_alloc(int strict);
#endif /* AVUTIL_FLOAT_DSP_H */
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 32ec47066b..4596927f97 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -1,23 +1,24 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "channel_layout.h"
+#include "avassert.h"
#include "buffer.h"
#include "common.h"
#include "dict.h"
@@ -26,6 +27,65 @@
#include "mem.h"
#include "samplefmt.h"
+MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp)
+MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_duration)
+MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_pos)
+MAKE_ACCESSORS(AVFrame, frame, int64_t, channel_layout)
+MAKE_ACCESSORS(AVFrame, frame, int, channels)
+MAKE_ACCESSORS(AVFrame, frame, int, sample_rate)
+MAKE_ACCESSORS(AVFrame, frame, AVDictionary *, metadata)
+MAKE_ACCESSORS(AVFrame, frame, int, decode_error_flags)
+MAKE_ACCESSORS(AVFrame, frame, int, pkt_size)
+MAKE_ACCESSORS(AVFrame, frame, enum AVColorSpace, colorspace)
+MAKE_ACCESSORS(AVFrame, frame, enum AVColorRange, color_range)
+
+#define CHECK_CHANNELS_CONSISTENCY(frame) \
+ av_assert2(!(frame)->channel_layout || \
+ (frame)->channels == \
+ av_get_channel_layout_nb_channels((frame)->channel_layout))
+
+AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame) {return &frame->metadata;};
+
+int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int qp_type)
+{
+ av_buffer_unref(&f->qp_table_buf);
+
+ f->qp_table_buf = buf;
+
+ f->qscale_table = buf->data;
+ f->qstride = stride;
+ f->qscale_type = qp_type;
+
+ return 0;
+}
+
+int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type)
+{
+ *stride = f->qstride;
+ *type = f->qscale_type;
+
+ if (!f->qp_table_buf)
+ return NULL;
+
+ return f->qp_table_buf->data;
+}
+
+const char *av_get_colorspace_name(enum AVColorSpace val)
+{
+ static const char * const name[] = {
+ [AVCOL_SPC_RGB] = "GBR",
+ [AVCOL_SPC_BT709] = "bt709",
+ [AVCOL_SPC_FCC] = "fcc",
+ [AVCOL_SPC_BT470BG] = "bt470bg",
+ [AVCOL_SPC_SMPTE170M] = "smpte170m",
+ [AVCOL_SPC_SMPTE240M] = "smpte240m",
+ [AVCOL_SPC_YCOCG] = "YCgCo",
+ };
+ if ((unsigned)val >= FF_ARRAY_ELEMS(name))
+ return NULL;
+ return name[val];
+}
+
static void get_frame_defaults(AVFrame *frame)
{
if (frame->extended_data != frame->data)
@@ -33,7 +93,13 @@ static void get_frame_defaults(AVFrame *frame)
memset(frame, 0, sizeof(*frame));
- frame->pts = AV_NOPTS_VALUE;
+ frame->pts =
+ frame->pkt_dts =
+ frame->pkt_pts = AV_NOPTS_VALUE;
+ av_frame_set_best_effort_timestamp(frame, AV_NOPTS_VALUE);
+ av_frame_set_pkt_duration (frame, 0);
+ av_frame_set_pkt_pos (frame, -1);
+ av_frame_set_pkt_size (frame, -1);
frame->key_frame = 1;
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
frame->format = -1; /* unknown */
@@ -49,7 +115,7 @@ static void free_side_data(AVFrameSideData **ptr_sd)
{
AVFrameSideData *sd = *ptr_sd;
- av_freep(&sd->data);
+ av_buffer_unref(&sd->buf);
av_dict_free(&sd->metadata);
av_freep(ptr_sd);
}
@@ -73,6 +139,7 @@ AVFrame *av_frame_alloc(void)
if (!frame)
return NULL;
+ frame->extended_data = NULL;
get_frame_defaults(frame);
return frame;
@@ -99,21 +166,25 @@ static int get_video_buffer(AVFrame *frame, int align)
return ret;
if (!frame->linesize[0]) {
- ret = av_image_fill_linesizes(frame->linesize, frame->format,
- frame->width);
- if (ret < 0)
- return ret;
+ for(i=1; i<=align; i+=i) {
+ ret = av_image_fill_linesizes(frame->linesize, frame->format,
+ FFALIGN(frame->width, i));
+ if (ret < 0)
+ return ret;
+ if (!(frame->linesize[0] & (align-1)))
+ break;
+ }
for (i = 0; i < 4 && frame->linesize[i]; i++)
frame->linesize[i] = FFALIGN(frame->linesize[i], align);
}
for (i = 0; i < 4 && frame->linesize[i]; i++) {
- int h = frame->height;
+ int h = FFALIGN(frame->height, 32);
if (i == 1 || i == 2)
- h = -((-h) >> desc->log2_chroma_h);
+ h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h);
- frame->buf[i] = av_buffer_alloc(frame->linesize[i] * h);
+ frame->buf[i] = av_buffer_alloc(frame->linesize[i] * h + 16 + 16/*STRIDE_ALIGN*/ - 1);
if (!frame->buf[i])
goto fail;
@@ -137,11 +208,18 @@ fail:
static int get_audio_buffer(AVFrame *frame, int align)
{
- int channels = av_get_channel_layout_nb_channels(frame->channel_layout);
+ int channels;
int planar = av_sample_fmt_is_planar(frame->format);
- int planes = planar ? channels : 1;
+ int planes;
int ret, i;
+ if (!frame->channels)
+ frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);
+
+ channels = frame->channels;
+ planes = planar ? channels : 1;
+
+ CHECK_CHANNELS_CONSISTENCY(frame);
if (!frame->linesize[0]) {
ret = av_samples_get_buffer_size(&frame->linesize[0], channels,
frame->nb_samples, frame->format,
@@ -151,9 +229,9 @@ static int get_audio_buffer(AVFrame *frame, int align)
}
if (planes > AV_NUM_DATA_POINTERS) {
- frame->extended_data = av_mallocz(planes *
+ frame->extended_data = av_mallocz_array(planes,
sizeof(*frame->extended_data));
- frame->extended_buf = av_mallocz((planes - AV_NUM_DATA_POINTERS) *
+ frame->extended_buf = av_mallocz_array((planes - AV_NUM_DATA_POINTERS),
sizeof(*frame->extended_buf));
if (!frame->extended_data || !frame->extended_buf) {
av_freep(&frame->extended_data);
@@ -191,12 +269,97 @@ int av_frame_get_buffer(AVFrame *frame, int align)
if (frame->width > 0 && frame->height > 0)
return get_video_buffer(frame, align);
- else if (frame->nb_samples > 0 && frame->channel_layout)
+ else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0))
return get_audio_buffer(frame, align);
return AVERROR(EINVAL);
}
+static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy)
+{
+ int i;
+
+ dst->key_frame = src->key_frame;
+ dst->pict_type = src->pict_type;
+ dst->sample_aspect_ratio = src->sample_aspect_ratio;
+ dst->pts = src->pts;
+ dst->repeat_pict = src->repeat_pict;
+ dst->interlaced_frame = src->interlaced_frame;
+ dst->top_field_first = src->top_field_first;
+ dst->palette_has_changed = src->palette_has_changed;
+ dst->sample_rate = src->sample_rate;
+ dst->opaque = src->opaque;
+#if FF_API_AVFRAME_LAVC
+ dst->type = src->type;
+#endif
+ dst->pkt_pts = src->pkt_pts;
+ dst->pkt_dts = src->pkt_dts;
+ dst->pkt_pos = src->pkt_pos;
+ dst->pkt_size = src->pkt_size;
+ dst->pkt_duration = src->pkt_duration;
+ dst->reordered_opaque = src->reordered_opaque;
+ dst->quality = src->quality;
+ dst->best_effort_timestamp = src->best_effort_timestamp;
+ dst->coded_picture_number = src->coded_picture_number;
+ dst->display_picture_number = src->display_picture_number;
+ dst->flags = src->flags;
+ dst->decode_error_flags = src->decode_error_flags;
+ dst->color_primaries = src->color_primaries;
+ dst->color_trc = src->color_trc;
+ dst->colorspace = src->colorspace;
+ dst->color_range = src->color_range;
+ dst->chroma_location = src->chroma_location;
+
+ av_dict_copy(&dst->metadata, src->metadata, 0);
+
+ memcpy(dst->error, src->error, sizeof(dst->error));
+
+ for (i = 0; i < src->nb_side_data; i++) {
+ const AVFrameSideData *sd_src = src->side_data[i];
+ AVFrameSideData *sd_dst;
+ if ( sd_src->type == AV_FRAME_DATA_PANSCAN
+ && (src->width != dst->width || src->height != dst->height))
+ continue;
+ if (force_copy) {
+ sd_dst = av_frame_new_side_data(dst, sd_src->type,
+ sd_src->size);
+ if (!sd_dst) {
+ wipe_side_data(dst);
+ return AVERROR(ENOMEM);
+ }
+ memcpy(sd_dst->data, sd_src->data, sd_src->size);
+ } else {
+ sd_dst = av_frame_new_side_data(dst, sd_src->type, 0);
+ if (!sd_dst) {
+ wipe_side_data(dst);
+ return AVERROR(ENOMEM);
+ }
+ sd_dst->buf = av_buffer_ref(sd_src->buf);
+ if (!sd_dst->buf) {
+ wipe_side_data(dst);
+ return AVERROR(ENOMEM);
+ }
+ sd_dst->data = sd_dst->buf->data;
+ sd_dst->size = sd_dst->buf->size;
+ }
+ av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0);
+ }
+
+ dst->qscale_table = NULL;
+ dst->qstride = 0;
+ dst->qscale_type = 0;
+ if (src->qp_table_buf) {
+ dst->qp_table_buf = av_buffer_ref(src->qp_table_buf);
+ if (dst->qp_table_buf) {
+ dst->qscale_table = dst->qp_table_buf->data;
+ dst->qstride = src->qstride;
+ dst->qscale_type = src->qscale_type;
+ }
+ }
+
+ return 0;
+}
+
int av_frame_ref(AVFrame *dst, const AVFrame *src)
{
int i, ret = 0;
@@ -204,10 +367,11 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
dst->format = src->format;
dst->width = src->width;
dst->height = src->height;
+ dst->channels = src->channels;
dst->channel_layout = src->channel_layout;
dst->nb_samples = src->nb_samples;
- ret = av_frame_copy_props(dst, src);
+ ret = frame_copy_props(dst, src, 0);
if (ret < 0)
return ret;
@@ -225,7 +389,9 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
}
/* ref the buffers */
- for (i = 0; i < FF_ARRAY_ELEMS(src->buf) && src->buf[i]; i++) {
+ for (i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) {
+ if (!src->buf[i])
+ continue;
dst->buf[i] = av_buffer_ref(src->buf[i]);
if (!dst->buf[i]) {
ret = AVERROR(ENOMEM);
@@ -234,7 +400,7 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
}
if (src->extended_buf) {
- dst->extended_buf = av_mallocz(sizeof(*dst->extended_buf) *
+ dst->extended_buf = av_mallocz_array(sizeof(*dst->extended_buf),
src->nb_extended_buf);
if (!dst->extended_buf) {
ret = AVERROR(ENOMEM);
@@ -253,14 +419,15 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
/* duplicate extended data */
if (src->extended_data != src->data) {
- int ch = av_get_channel_layout_nb_channels(src->channel_layout);
+ int ch = src->channels;
if (!ch) {
ret = AVERROR(EINVAL);
goto fail;
}
+ CHECK_CHANNELS_CONSISTENCY(src);
- dst->extended_data = av_malloc(sizeof(*dst->extended_data) * ch);
+ dst->extended_data = av_malloc_array(sizeof(*dst->extended_data), ch);
if (!dst->extended_data) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -303,6 +470,9 @@ void av_frame_unref(AVFrame *frame)
for (i = 0; i < frame->nb_extended_buf; i++)
av_buffer_unref(&frame->extended_buf[i]);
av_freep(&frame->extended_buf);
+ av_dict_free(&frame->metadata);
+ av_buffer_unref(&frame->qp_table_buf);
+
get_frame_defaults(frame);
}
@@ -323,8 +493,9 @@ int av_frame_is_writable(AVFrame *frame)
if (!frame->buf[0])
return 0;
- for (i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++)
- ret &= !!av_buffer_is_writable(frame->buf[i]);
+ for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++)
+ if (frame->buf[i])
+ ret &= !!av_buffer_is_writable(frame->buf[i]);
for (i = 0; i < frame->nb_extended_buf; i++)
ret &= !!av_buffer_is_writable(frame->extended_buf[i]);
@@ -346,6 +517,7 @@ int av_frame_make_writable(AVFrame *frame)
tmp.format = frame->format;
tmp.width = frame->width;
tmp.height = frame->height;
+ tmp.channels = frame->channels;
tmp.channel_layout = frame->channel_layout;
tmp.nb_samples = frame->nb_samples;
ret = av_frame_get_buffer(&tmp, 32);
@@ -375,46 +547,7 @@ int av_frame_make_writable(AVFrame *frame)
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
{
- int i;
-
- dst->key_frame = src->key_frame;
- dst->pict_type = src->pict_type;
- dst->sample_aspect_ratio = src->sample_aspect_ratio;
- dst->pts = src->pts;
- dst->repeat_pict = src->repeat_pict;
- dst->interlaced_frame = src->interlaced_frame;
- dst->top_field_first = src->top_field_first;
- dst->palette_has_changed = src->palette_has_changed;
- dst->sample_rate = src->sample_rate;
- dst->opaque = src->opaque;
- dst->pkt_pts = src->pkt_pts;
- dst->pkt_dts = src->pkt_dts;
- dst->reordered_opaque = src->reordered_opaque;
- dst->quality = src->quality;
- dst->coded_picture_number = src->coded_picture_number;
- dst->display_picture_number = src->display_picture_number;
- dst->flags = src->flags;
- dst->color_primaries = src->color_primaries;
- dst->color_trc = src->color_trc;
- dst->colorspace = src->colorspace;
- dst->color_range = src->color_range;
- dst->chroma_location = src->chroma_location;
-
- memcpy(dst->error, src->error, sizeof(dst->error));
-
- for (i = 0; i < src->nb_side_data; i++) {
- const AVFrameSideData *sd_src = src->side_data[i];
- AVFrameSideData *sd_dst = av_frame_new_side_data(dst, sd_src->type,
- sd_src->size);
- if (!sd_dst) {
- wipe_side_data(dst);
- return AVERROR(ENOMEM);
- }
- memcpy(sd_dst->data, sd_src->data, sd_src->size);
- av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0);
- }
-
- return 0;
+ return frame_copy_props(dst, src, 1);
}
AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane)
@@ -423,9 +556,10 @@ AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane)
int planes, i;
if (frame->nb_samples) {
- int channels = av_get_channel_layout_nb_channels(frame->channel_layout);
+ int channels = frame->channels;
if (!channels)
return NULL;
+ CHECK_CHANNELS_CONSISTENCY(frame);
planes = av_sample_fmt_is_planar(frame->format) ? channels : 1;
} else
planes = 4;
@@ -466,13 +600,16 @@ AVFrameSideData *av_frame_new_side_data(AVFrame *frame,
if (!ret)
return NULL;
- ret->data = av_malloc(size);
- if (!ret->data) {
- av_freep(&ret);
- return NULL;
- }
+ if (size > 0) {
+ ret->buf = av_buffer_alloc(size);
+ if (!ret->buf) {
+ av_freep(&ret);
+ return NULL;
+ }
- ret->size = size;
+ ret->data = ret->buf->data;
+ ret->size = size;
+ }
ret->type = type;
frame->side_data[frame->nb_side_data++] = ret;
@@ -497,8 +634,8 @@ static int frame_copy_video(AVFrame *dst, const AVFrame *src)
const uint8_t *src_data[4];
int i, planes;
- if (dst->width != src->width ||
- dst->height != src->height)
+ if (dst->width < src->width ||
+ dst->height < src->height)
return AVERROR(EINVAL);
planes = av_pix_fmt_count_planes(dst->format);
@@ -509,7 +646,7 @@ static int frame_copy_video(AVFrame *dst, const AVFrame *src)
memcpy(src_data, src->data, sizeof(src_data));
av_image_copy(dst->data, dst->linesize,
src_data, src->linesize,
- dst->format, dst->width, dst->height);
+ dst->format, src->width, src->height);
return 0;
}
@@ -517,14 +654,17 @@ static int frame_copy_video(AVFrame *dst, const AVFrame *src)
static int frame_copy_audio(AVFrame *dst, const AVFrame *src)
{
int planar = av_sample_fmt_is_planar(dst->format);
- int channels = av_get_channel_layout_nb_channels(dst->channel_layout);
+ int channels = dst->channels;
int planes = planar ? channels : 1;
int i;
if (dst->nb_samples != src->nb_samples ||
+ dst->channels != src->channels ||
dst->channel_layout != src->channel_layout)
return AVERROR(EINVAL);
+ CHECK_CHANNELS_CONSISTENCY(src);
+
for (i = 0; i < planes; i++)
if (!dst->extended_data[i] || !src->extended_data[i])
return AVERROR(EINVAL);
@@ -561,3 +701,18 @@ void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type)
}
}
}
+
+const char *av_frame_side_data_name(enum AVFrameSideDataType type)
+{
+ switch(type) {
+ case AV_FRAME_DATA_PANSCAN: return "AVPanScan";
+ case AV_FRAME_DATA_A53_CC: return "ATSC A53 Part 4 Closed Captions";
+ case AV_FRAME_DATA_STEREO3D: return "Stereoscopic 3d metadata";
+ case AV_FRAME_DATA_MATRIXENCODING: return "AVMatrixEncoding";
+ case AV_FRAME_DATA_DOWNMIX_INFO: return "Metadata relevant to a downmix procedure";
+ case AV_FRAME_DATA_REPLAYGAIN: return "AVReplayGain";
+ case AV_FRAME_DATA_DISPLAYMATRIX: return "3x3 displaymatrix";
+ case AV_FRAME_DATA_MOTION_VECTORS: return "Motion vectors";
+ }
+ return NULL;
+}
diff --git a/libavutil/frame.h b/libavutil/frame.h
index addcb25a50..e910b517e2 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -84,9 +84,28 @@ enum AVFrameSideDataType {
AV_FRAME_DATA_DISPLAYMATRIX,
/**
* Active Format Description data consisting of a single byte as specified
- * in ETSI TS 101 154 using enum AVActiveFormatDescription.
+ * in ETSI TS 101 154 using AVActiveFormatDescription enum.
*/
AV_FRAME_DATA_AFD,
+ /**
+ * Motion vectors exported by some codecs (on demand through the export_mvs
+ * flag set in the libavcodec AVCodecContext flags2 option).
+ * The data is the AVMotionVector struct defined in
+ * libavutil/motion_vector.h.
+ */
+ AV_FRAME_DATA_MOTION_VECTORS,
+ /**
+ * Recommmends skipping the specified number of samples. This is exported
+ * only if the "skip_manual" AVOption is set in libavcodec.
+ * This has the same format as AV_PKT_DATA_SKIP_SAMPLES.
+ * @code
+ * u32le number of samples to skip from start of this packet
+ * u32le number of samples to skip from end of this packet
+ * u8 reason for start skip
+ * u8 reason for end skip (0=padding silence, 1=convergence)
+ * @endcode
+ */
+ AV_FRAME_DATA_SKIP_SAMPLES,
/**
* This side data must be associated with an audio frame and corresponds to
@@ -105,11 +124,19 @@ enum AVActiveFormatDescription {
AV_AFD_SP_4_3 = 15,
};
+
+/**
+ * Structure to hold side data for an AVFrame.
+ *
+ * sizeof(AVFrameSideData) is not a part of the public ABI, so new fields may be added
+ * to the end with a minor bump.
+ */
typedef struct AVFrameSideData {
enum AVFrameSideDataType type;
uint8_t *data;
int size;
AVDictionary *metadata;
+ AVBufferRef *buf;
} AVFrameSideData;
/**
@@ -137,12 +164,20 @@ typedef struct AVFrameSideData {
*
* sizeof(AVFrame) is not a part of the public ABI, so new fields may be added
* to the end with a minor bump.
+ * Similarly fields that are marked as to be only accessed by
+ * av_opt_ptr() can be reordered. This allows 2 forks to add fields
+ * without breaking compatibility with each other.
*/
typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
/**
* pointer to the picture/channel planes.
* This might be different from the first allocated byte
+ *
+ * Some decoders access areas outside 0,0 - width,height, please
+ * see avcodec_align_dimensions2(). Some filters and swscale can read
+ * up to 16 bytes beyond the planes, if these filters are to be used,
+ * then 16 extra bytes must be allocated.
*/
uint8_t *data[AV_NUM_DATA_POINTERS];
@@ -153,6 +188,11 @@ typedef struct AVFrame {
* For audio, only linesize[0] may be set. For planar audio, each channel
* plane must be the same size.
*
+ * For video the linesizes should be multiples of the CPUs alignment
+ * preference, this is 16 or 32 for modern desktop CPUs.
+ * Some code requires such alignment other code can be slower without
+ * correct alignment, for yet other it makes no difference.
+ *
* @note The linesize may be larger than the size of usable data -- there
* may be extra padding present for performance reasons.
*/
@@ -222,7 +262,9 @@ typedef struct AVFrame {
int64_t pkt_pts;
/**
- * DTS copied from the AVPacket that triggered returning this frame.
+ * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used)
+ * This is also the Presentation time of this AVFrame calculated from
+ * only AVPacket.dts values without pts values.
*/
int64_t pkt_dts;
@@ -275,7 +317,6 @@ typedef struct AVFrame {
* motion_val[direction][x + y*mv_stride][0->mv_x, 1->mv_y];
* @endcode
*/
- attribute_deprecated
int16_t (*motion_val[2])[2];
/**
@@ -372,7 +413,6 @@ typedef struct AVFrame {
* log2 of the size of the block which a single vector in motion_val represents:
* (4->16x16, 3->8x8, 2-> 4x4, 1-> 2x2)
*/
- attribute_deprecated
uint8_t motion_subsample_log2;
#endif
@@ -441,18 +481,143 @@ typedef struct AVFrame {
*/
int flags;
+ /**
+ * MPEG vs JPEG YUV range.
+ * It must be accessed using av_frame_get_color_range() and
+ * av_frame_set_color_range().
+ * - encoding: Set by user
+ * - decoding: Set by libavcodec
+ */
enum AVColorRange color_range;
enum AVColorPrimaries color_primaries;
enum AVColorTransferCharacteristic color_trc;
+ /**
+ * YUV colorspace type.
+ * It must be accessed using av_frame_get_colorspace() and
+ * av_frame_set_colorspace().
+ * - encoding: Set by user
+ * - decoding: Set by libavcodec
+ */
enum AVColorSpace colorspace;
enum AVChromaLocation chroma_location;
+
+ /**
+ * frame timestamp estimated using various heuristics, in stream time base
+ * Code outside libavcodec should access this field using:
+ * av_frame_get_best_effort_timestamp(frame)
+ * - encoding: unused
+ * - decoding: set by libavcodec, read by user.
+ */
+ int64_t best_effort_timestamp;
+
+ /**
+ * reordered pos from the last AVPacket that has been input into the decoder
+ * Code outside libavcodec should access this field using:
+ * av_frame_get_pkt_pos(frame)
+ * - encoding: unused
+ * - decoding: Read by user.
+ */
+ int64_t pkt_pos;
+
+ /**
+ * duration of the corresponding packet, expressed in
+ * AVStream->time_base units, 0 if unknown.
+ * Code outside libavcodec should access this field using:
+ * av_frame_get_pkt_duration(frame)
+ * - encoding: unused
+ * - decoding: Read by user.
+ */
+ int64_t pkt_duration;
+
+ /**
+ * metadata.
+ * Code outside libavcodec should access this field using:
+ * av_frame_get_metadata(frame)
+ * - encoding: Set by user.
+ * - decoding: Set by libavcodec.
+ */
+ AVDictionary *metadata;
+
+ /**
+ * decode error flags of the frame, set to a combination of
+ * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there
+ * were errors during the decoding.
+ * Code outside libavcodec should access this field using:
+ * av_frame_get_decode_error_flags(frame)
+ * - encoding: unused
+ * - decoding: set by libavcodec, read by user.
+ */
+ int decode_error_flags;
+#define FF_DECODE_ERROR_INVALID_BITSTREAM 1
+#define FF_DECODE_ERROR_MISSING_REFERENCE 2
+
+ /**
+ * number of audio channels, only used for audio.
+ * Code outside libavcodec should access this field using:
+ * av_frame_get_channels(frame)
+ * - encoding: unused
+ * - decoding: Read by user.
+ */
+ int channels;
+
+ /**
+ * size of the corresponding packet containing the compressed
+ * frame. It must be accessed using av_frame_get_pkt_size() and
+ * av_frame_set_pkt_size().
+ * It is set to a negative value if unknown.
+ * - encoding: unused
+ * - decoding: set by libavcodec, read by user.
+ */
+ int pkt_size;
+
+ /**
+ * Not to be accessed directly from outside libavutil
+ */
+ AVBufferRef *qp_table_buf;
} AVFrame;
/**
+ * Accessors for some AVFrame fields.
+ * The position of these field in the structure is not part of the ABI,
+ * they should not be accessed directly outside libavcodec.
+ */
+int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame);
+void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val);
+int64_t av_frame_get_pkt_duration (const AVFrame *frame);
+void av_frame_set_pkt_duration (AVFrame *frame, int64_t val);
+int64_t av_frame_get_pkt_pos (const AVFrame *frame);
+void av_frame_set_pkt_pos (AVFrame *frame, int64_t val);
+int64_t av_frame_get_channel_layout (const AVFrame *frame);
+void av_frame_set_channel_layout (AVFrame *frame, int64_t val);
+int av_frame_get_channels (const AVFrame *frame);
+void av_frame_set_channels (AVFrame *frame, int val);
+int av_frame_get_sample_rate (const AVFrame *frame);
+void av_frame_set_sample_rate (AVFrame *frame, int val);
+AVDictionary *av_frame_get_metadata (const AVFrame *frame);
+void av_frame_set_metadata (AVFrame *frame, AVDictionary *val);
+int av_frame_get_decode_error_flags (const AVFrame *frame);
+void av_frame_set_decode_error_flags (AVFrame *frame, int val);
+int av_frame_get_pkt_size(const AVFrame *frame);
+void av_frame_set_pkt_size(AVFrame *frame, int val);
+AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame);
+int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type);
+int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type);
+enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame);
+void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val);
+enum AVColorRange av_frame_get_color_range(const AVFrame *frame);
+void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val);
+
+/**
+ * Get the name of a colorspace.
+ * @return a static string identifying the colorspace; can be NULL.
+ */
+const char *av_get_colorspace_name(enum AVColorSpace val);
+
+/**
* Allocate an AVFrame and set its fields to default values. The resulting
* struct must be freed using av_frame_free().
*
@@ -501,7 +666,7 @@ AVFrame *av_frame_clone(const AVFrame *src);
void av_frame_unref(AVFrame *frame);
/**
- * Move everythnig contained in src to dst and reset src.
+ * Move everything contained in src to dst and reset src.
*/
void av_frame_move_ref(AVFrame *dst, AVFrame *src);
@@ -611,6 +776,11 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame,
void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type);
/**
+ * @return a string identifying the side data type
+ */
+const char *av_frame_side_data_name(enum AVFrameSideDataType type);
+
+/**
* @}
*/
diff --git a/libavutil/hash.c b/libavutil/hash.c
new file mode 100644
index 0000000000..7037b0d6ff
--- /dev/null
+++ b/libavutil/hash.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdint.h>
+#include "hash.h"
+
+#include "adler32.h"
+#include "crc.h"
+#include "md5.h"
+#include "murmur3.h"
+#include "ripemd.h"
+#include "sha.h"
+#include "sha512.h"
+
+#include "avstring.h"
+#include "base64.h"
+#include "error.h"
+#include "intreadwrite.h"
+#include "mem.h"
+
+enum hashtype {
+ MD5,
+ MURMUR3,
+ RIPEMD128,
+ RIPEMD160,
+ RIPEMD256,
+ RIPEMD320,
+ SHA160,
+ SHA224,
+ SHA256,
+ SHA512_224,
+ SHA512_256,
+ SHA384,
+ SHA512,
+ CRC32,
+ ADLER32,
+ NUM_HASHES
+};
+
+typedef struct AVHashContext {
+ void *ctx;
+ enum hashtype type;
+ const AVCRC *crctab;
+ uint32_t crc;
+} AVHashContext;
+
+static const struct {
+ const char *name;
+ int size;
+} hashdesc[] = {
+ [MD5] = {"MD5", 16},
+ [MURMUR3] = {"murmur3", 16},
+ [RIPEMD128] = {"RIPEMD128", 16},
+ [RIPEMD160] = {"RIPEMD160", 20},
+ [RIPEMD256] = {"RIPEMD256", 32},
+ [RIPEMD320] = {"RIPEMD320", 40},
+ [SHA160] = {"SHA160", 20},
+ [SHA224] = {"SHA224", 28},
+ [SHA256] = {"SHA256", 32},
+ [SHA512_224] = {"SHA512/224", 28},
+ [SHA512_256] = {"SHA512/256", 32},
+ [SHA384] = {"SHA384", 48},
+ [SHA512] = {"SHA512", 64},
+ [CRC32] = {"CRC32", 4},
+ [ADLER32] = {"adler32", 4},
+};
+
+const char *av_hash_names(int i)
+{
+ if (i < 0 || i >= NUM_HASHES) return NULL;
+ return hashdesc[i].name;
+}
+
+const char *av_hash_get_name(const AVHashContext *ctx)
+{
+ return hashdesc[ctx->type].name;
+}
+
+int av_hash_get_size(const AVHashContext *ctx)
+{
+ return hashdesc[ctx->type].size;
+}
+
+int av_hash_alloc(AVHashContext **ctx, const char *name)
+{
+ AVHashContext *res;
+ int i;
+ *ctx = NULL;
+ for (i = 0; i < NUM_HASHES; i++)
+ if (av_strcasecmp(name, hashdesc[i].name) == 0)
+ break;
+ if (i >= NUM_HASHES) return AVERROR(EINVAL);
+ res = av_mallocz(sizeof(*res));
+ if (!res) return AVERROR(ENOMEM);
+ res->type = i;
+ switch (i) {
+ case MD5: res->ctx = av_md5_alloc(); break;
+ case MURMUR3: res->ctx = av_murmur3_alloc(); break;
+ case RIPEMD128:
+ case RIPEMD160:
+ case RIPEMD256:
+ case RIPEMD320: res->ctx = av_ripemd_alloc(); break;
+ case SHA160:
+ case SHA224:
+ case SHA256: res->ctx = av_sha_alloc(); break;
+ case SHA512_224:
+ case SHA512_256:
+ case SHA384:
+ case SHA512: res->ctx = av_sha512_alloc(); break;
+ case CRC32: res->crctab = av_crc_get_table(AV_CRC_32_IEEE_LE); break;
+ case ADLER32: break;
+ }
+ if (i != ADLER32 && i != CRC32 && !res->ctx) {
+ av_free(res);
+ return AVERROR(ENOMEM);
+ }
+ *ctx = res;
+ return 0;
+}
+
+void av_hash_init(AVHashContext *ctx)
+{
+ switch (ctx->type) {
+ case MD5: av_md5_init(ctx->ctx); break;
+ case MURMUR3: av_murmur3_init(ctx->ctx); break;
+ case RIPEMD128: av_ripemd_init(ctx->ctx, 128); break;
+ case RIPEMD160: av_ripemd_init(ctx->ctx, 160); break;
+ case RIPEMD256: av_ripemd_init(ctx->ctx, 256); break;
+ case RIPEMD320: av_ripemd_init(ctx->ctx, 320); break;
+ case SHA160: av_sha_init(ctx->ctx, 160); break;
+ case SHA224: av_sha_init(ctx->ctx, 224); break;
+ case SHA256: av_sha_init(ctx->ctx, 256); break;
+ case SHA512_224: av_sha512_init(ctx->ctx, 224); break;
+ case SHA512_256: av_sha512_init(ctx->ctx, 256); break;
+ case SHA384: av_sha512_init(ctx->ctx, 384); break;
+ case SHA512: av_sha512_init(ctx->ctx, 512); break;
+ case CRC32: ctx->crc = UINT32_MAX; break;
+ case ADLER32: ctx->crc = 1; break;
+ }
+}
+
+void av_hash_update(AVHashContext *ctx, const uint8_t *src, int len)
+{
+ switch (ctx->type) {
+ case MD5: av_md5_update(ctx->ctx, src, len); break;
+ case MURMUR3: av_murmur3_update(ctx->ctx, src, len); break;
+ case RIPEMD128:
+ case RIPEMD160:
+ case RIPEMD256:
+ case RIPEMD320: av_ripemd_update(ctx->ctx, src, len); break;
+ case SHA160:
+ case SHA224:
+ case SHA256: av_sha_update(ctx->ctx, src, len); break;
+ case SHA512_224:
+ case SHA512_256:
+ case SHA384:
+ case SHA512: av_sha512_update(ctx->ctx, src, len); break;
+ case CRC32: ctx->crc = av_crc(ctx->crctab, ctx->crc, src, len); break;
+ case ADLER32: ctx->crc = av_adler32_update(ctx->crc, src, len); break;
+ }
+}
+
+void av_hash_final(AVHashContext *ctx, uint8_t *dst)
+{
+ switch (ctx->type) {
+ case MD5: av_md5_final(ctx->ctx, dst); break;
+ case MURMUR3: av_murmur3_final(ctx->ctx, dst); break;
+ case RIPEMD128:
+ case RIPEMD160:
+ case RIPEMD256:
+ case RIPEMD320: av_ripemd_final(ctx->ctx, dst); break;
+ case SHA160:
+ case SHA224:
+ case SHA256: av_sha_final(ctx->ctx, dst); break;
+ case SHA512_224:
+ case SHA512_256:
+ case SHA384:
+ case SHA512: av_sha512_final(ctx->ctx, dst); break;
+ case CRC32: AV_WB32(dst, ctx->crc ^ UINT32_MAX); break;
+ case ADLER32: AV_WB32(dst, ctx->crc); break;
+ }
+}
+
+void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size)
+{
+ uint8_t buf[AV_HASH_MAX_SIZE];
+ unsigned rsize = av_hash_get_size(ctx);
+
+ av_hash_final(ctx, buf);
+ memcpy(dst, buf, FFMIN(size, rsize));
+ if (size > rsize)
+ memset(dst + rsize, 0, size - rsize);
+}
+
+void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size)
+{
+ uint8_t buf[AV_HASH_MAX_SIZE];
+ unsigned rsize = av_hash_get_size(ctx), i;
+
+ av_hash_final(ctx, buf);
+ for (i = 0; i < FFMIN(rsize, size / 2); i++)
+ snprintf(dst + i * 2, size - i * 2, "%02x", buf[i]);
+}
+
+void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size)
+{
+ uint8_t buf[AV_HASH_MAX_SIZE], b64[AV_BASE64_SIZE(AV_HASH_MAX_SIZE)];
+ unsigned rsize = av_hash_get_size(ctx), osize;
+
+ av_hash_final(ctx, buf);
+ av_base64_encode(b64, sizeof(b64), buf, rsize);
+ osize = AV_BASE64_SIZE(rsize);
+ memcpy(dst, b64, FFMIN(osize, size));
+ if (size < osize)
+ dst[size - 1] = 0;
+}
+
+void av_hash_freep(AVHashContext **ctx)
+{
+ if (*ctx)
+ av_freep(&(*ctx)->ctx);
+ av_freep(ctx);
+}
diff --git a/libavutil/hash.h b/libavutil/hash.h
new file mode 100644
index 0000000000..d4bcbf8cc8
--- /dev/null
+++ b/libavutil/hash.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_HASH_H
+#define AVUTIL_HASH_H
+
+#include <stdint.h>
+
+struct AVHashContext;
+
+/**
+ * Allocate a hash context for the algorithm specified by name.
+ *
+ * @return >= 0 for success, a negative error code for failure
+ * @note The context is not initialized, you must call av_hash_init().
+ */
+int av_hash_alloc(struct AVHashContext **ctx, const char *name);
+
+/**
+ * Get the names of available hash algorithms.
+ *
+ * This function can be used to enumerate the algorithms.
+ *
+ * @param i index of the hash algorithm, starting from 0
+ * @return a pointer to a static string or NULL if i is out of range
+ */
+const char *av_hash_names(int i);
+
+/**
+ * Get the name of the algorithm corresponding to the given hash context.
+ */
+const char *av_hash_get_name(const struct AVHashContext *ctx);
+
+/**
+ * Maximum value that av_hash_get_size will currently return.
+ *
+ * You can use this if you absolutely want or need to use static allocation
+ * and are fine with not supporting hashes newly added to libavutil without
+ * recompilation.
+ * Note that you still need to check against av_hash_get_size, adding new hashes
+ * with larger sizes will not be considered an ABI change and should not cause
+ * your code to overflow a buffer.
+ */
+#define AV_HASH_MAX_SIZE 64
+
+/**
+ * Get the size of the resulting hash value in bytes.
+ *
+ * The pointer passed to av_hash_final have space for at least this many bytes.
+ */
+int av_hash_get_size(const struct AVHashContext *ctx);
+
+/**
+ * Initialize or reset a hash context.
+ */
+void av_hash_init(struct AVHashContext *ctx);
+
+/**
+ * Update a hash context with additional data.
+ */
+void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len);
+
+/**
+ * Finalize a hash context and compute the actual hash value.
+ */
+void av_hash_final(struct AVHashContext *ctx, uint8_t *dst);
+
+/**
+ * Finalize a hash context and compute the actual hash value.
+ * If size is smaller than the hash size, the hash is truncated;
+ * if size is larger, the buffer is padded with 0.
+ */
+void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size);
+
+/**
+ * Finalize a hash context and compute the actual hash value as a hex string.
+ * The string is always 0-terminated.
+ * If size is smaller than 2 * hash_size + 1, the hex string is truncated.
+ */
+void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size);
+
+/**
+ * Finalize a hash context and compute the actual hash value as a base64 string.
+ * The string is always 0-terminated.
+ * If size is smaller than AV_BASE64_SIZE(hash_size), the base64 string is
+ * truncated.
+ */
+void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size);
+
+/**
+ * Free hash context.
+ */
+void av_hash_freep(struct AVHashContext **ctx);
+
+#endif /* AVUTIL_HASH_H */
diff --git a/libavutil/hmac.c b/libavutil/hmac.c
index f87728e181..b63d1b250e 100644
--- a/libavutil/hmac.c
+++ b/libavutil/hmac.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,10 +24,11 @@
#include "hmac.h"
#include "md5.h"
#include "sha.h"
+#include "sha512.h"
#include "mem.h"
-#define MAX_HASHLEN 20
-#define MAX_BLOCKLEN 64
+#define MAX_HASHLEN 64
+#define MAX_BLOCKLEN 128
struct AVHMAC {
void *hash;
@@ -39,11 +40,24 @@ struct AVHMAC {
int keylen;
};
-static av_cold void sha1_init(void *ctx)
-{
- av_sha_init(ctx, 160);
+#define DEFINE_SHA(bits) \
+static av_cold void sha ## bits ##_init(void *ctx) \
+{ \
+ av_sha_init(ctx, bits); \
+}
+
+#define DEFINE_SHA512(bits) \
+static av_cold void sha ## bits ##_init(void *ctx) \
+{ \
+ av_sha512_init(ctx, bits); \
}
+DEFINE_SHA(160)
+DEFINE_SHA(224)
+DEFINE_SHA(256)
+DEFINE_SHA512(384)
+DEFINE_SHA512(512)
+
AVHMAC *av_hmac_alloc(enum AVHMACType type)
{
AVHMAC *c = av_mallocz(sizeof(*c));
@@ -53,19 +67,51 @@ AVHMAC *av_hmac_alloc(enum AVHMACType type)
case AV_HMAC_MD5:
c->blocklen = 64;
c->hashlen = 16;
- c->init = av_md5_init;
- c->update = av_md5_update;
- c->final = av_md5_final;
+ c->init = (void*)av_md5_init;
+ c->update = (void*)av_md5_update;
+ c->final = (void*)av_md5_final;
c->hash = av_md5_alloc();
break;
case AV_HMAC_SHA1:
c->blocklen = 64;
c->hashlen = 20;
- c->init = sha1_init;
- c->update = av_sha_update;
- c->final = av_sha_final;
+ c->init = sha160_init;
+ c->update = (void*)av_sha_update;
+ c->final = (void*)av_sha_final;
+ c->hash = av_sha_alloc();
+ break;
+ case AV_HMAC_SHA224:
+ c->blocklen = 64;
+ c->hashlen = 28;
+ c->init = sha224_init;
+ c->update = (void*)av_sha_update;
+ c->final = (void*)av_sha_final;
+ c->hash = av_sha_alloc();
+ break;
+ case AV_HMAC_SHA256:
+ c->blocklen = 64;
+ c->hashlen = 32;
+ c->init = sha256_init;
+ c->update = (void*)av_sha_update;
+ c->final = (void*)av_sha_final;
c->hash = av_sha_alloc();
break;
+ case AV_HMAC_SHA384:
+ c->blocklen = 128;
+ c->hashlen = 48;
+ c->init = sha384_init;
+ c->update = (void*)av_sha512_update;
+ c->final = (void*)av_sha512_final;
+ c->hash = av_sha512_alloc();
+ break;
+ case AV_HMAC_SHA512:
+ c->blocklen = 128;
+ c->hashlen = 64;
+ c->init = sha512_init;
+ c->update = (void*)av_sha512_update;
+ c->final = (void*)av_sha512_final;
+ c->hash = av_sha512_alloc();
+ break;
default:
av_free(c);
return NULL;
@@ -81,7 +127,7 @@ void av_hmac_free(AVHMAC *c)
{
if (!c)
return;
- av_free(c->hash);
+ av_freep(&c->hash);
av_free(c);
}
@@ -160,28 +206,56 @@ static void test(AVHMAC *hmac, const uint8_t *key, int keylen,
int main(void)
{
- uint8_t key1[16], key3[16], data3[50], key4[63], key5[64], key6[65];
- const uint8_t key2[] = "Jefe";
- const uint8_t data1[] = "Hi There";
- const uint8_t data2[] = "what do ya want for nothing?";
+ uint8_t key1[20], key3[131], data3[50];
+ enum AVHMACType i = AV_HMAC_SHA224;
+ static const uint8_t key2[] = "Jefe";
+ static const uint8_t data1[] = "Hi There";
+ static const uint8_t data2[] = "what do ya want for nothing?";
+ static const uint8_t data4[] = "Test Using Larger Than Block-Size Key - Hash Key First";
+ static const uint8_t data5[] = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data";
+ static const uint8_t data6[] = "This is a test using a larger than block-size key and a larger "
+ "than block-size data. The key needs to be hashed before being used"
+ " by the HMAC algorithm.";
AVHMAC *hmac = av_hmac_alloc(AV_HMAC_MD5);
if (!hmac)
return 1;
memset(key1, 0x0b, sizeof(key1));
memset(key3, 0xaa, sizeof(key3));
- memset(key4, 0x44, sizeof(key4));
- memset(key5, 0x55, sizeof(key5));
- memset(key6, 0x66, sizeof(key6));
memset(data3, 0xdd, sizeof(data3));
- // RFC 2104 test vectors
+ // RFC 2202 test vectors
+ test(hmac, key1, 16, data1, sizeof(data1));
+ test(hmac, key2, sizeof(key2), data2, sizeof(data2));
+ test(hmac, key3, 16, data3, sizeof(data3));
+ test(hmac, key3, 80, data4, sizeof(data4));
+ test(hmac, key3, 80, data5, sizeof(data5));
+ av_hmac_free(hmac);
+
+ /* SHA-1 */
+ hmac = av_hmac_alloc(AV_HMAC_SHA1);
+ if (!hmac)
+ return 1;
+ // RFC 2202 test vectors
test(hmac, key1, sizeof(key1), data1, sizeof(data1));
test(hmac, key2, sizeof(key2), data2, sizeof(data2));
- test(hmac, key3, sizeof(key3), data3, sizeof(data3));
- // Additional tests, to test cases where the key is too long
- test(hmac, key4, sizeof(key4), data1, sizeof(data1));
- test(hmac, key5, sizeof(key5), data2, sizeof(data2));
- test(hmac, key6, sizeof(key6), data3, sizeof(data3));
+ test(hmac, key3, 20, data3, sizeof(data3));
+ test(hmac, key3, 80, data4, sizeof(data4));
+ test(hmac, key3, 80, data5, sizeof(data5));
av_hmac_free(hmac);
+
+ /* SHA-2 */
+ while (i <= AV_HMAC_SHA512) {
+ hmac = av_hmac_alloc(i);
+ if (!hmac)
+ return 1;
+ // RFC 4231 test vectors
+ test(hmac, key1, sizeof(key1), data1, sizeof(data1));
+ test(hmac, key2, sizeof(key2), data2, sizeof(data2));
+ test(hmac, key3, 20, data3, sizeof(data3));
+ test(hmac, key3, sizeof(key3), data4, sizeof(data4));
+ test(hmac, key3, sizeof(key3), data6, sizeof(data6));
+ av_hmac_free(hmac);
+ i++;
+ }
return 0;
}
#endif /* TEST */
diff --git a/libavutil/hmac.h b/libavutil/hmac.h
index 28c2062b1b..d36d4de19e 100644
--- a/libavutil/hmac.h
+++ b/libavutil/hmac.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,10 @@
enum AVHMACType {
AV_HMAC_MD5,
AV_HMAC_SHA1,
+ AV_HMAC_SHA224 = 10,
+ AV_HMAC_SHA256,
+ AV_HMAC_SHA384,
+ AV_HMAC_SHA512,
};
typedef struct AVHMAC AVHMAC;
diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
index 948a6f784a..ef0e67154b 100644
--- a/libavutil/imgutils.c
+++ b/libavutil/imgutils.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,6 +21,7 @@
* misc image utilities
*/
+#include "avassert.h"
#include "common.h"
#include "imgutils.h"
#include "internal.h"
@@ -48,27 +49,45 @@ void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4],
}
}
+static inline
+int image_get_linesize(int width, int plane,
+ int max_step, int max_step_comp,
+ const AVPixFmtDescriptor *desc)
+{
+ int s, shifted_w, linesize;
+
+ if (!desc)
+ return AVERROR(EINVAL);
+
+ if (width < 0)
+ return AVERROR(EINVAL);
+ s = (max_step_comp == 1 || max_step_comp == 2) ? desc->log2_chroma_w : 0;
+ shifted_w = ((width + (1 << s) - 1)) >> s;
+ if (shifted_w && max_step > INT_MAX / shifted_w)
+ return AVERROR(EINVAL);
+ linesize = max_step * shifted_w;
+
+ if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM)
+ linesize = (linesize + 7) >> 3;
+ return linesize;
+}
+
int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
int max_step [4]; /* max pixel step for each plane */
int max_step_comp[4]; /* the component for each plane which has the max pixel step */
- int s;
- if (!desc)
+ if ((unsigned)pix_fmt >= AV_PIX_FMT_NB || desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
return AVERROR(EINVAL);
- if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM)
- return (width * (desc->comp[0].step_minus1+1) + 7) >> 3;
-
av_image_fill_max_pixsteps(max_step, max_step_comp, desc);
- s = (max_step_comp[plane] == 1 || max_step_comp[plane] == 2) ? desc->log2_chroma_w : 0;
- return max_step[plane] * (((width + (1 << s) - 1)) >> s);
+ return image_get_linesize(width, plane, max_step[plane], max_step_comp[plane], desc);
}
int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width)
{
- int i;
+ int i, ret;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
int max_step [4]; /* max pixel step for each plane */
int max_step_comp[4]; /* the component for each plane which has the max pixel step */
@@ -78,20 +97,11 @@ int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int wi
if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
return AVERROR(EINVAL);
- if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) {
- if (width > (INT_MAX -7) / (desc->comp[0].step_minus1+1))
- return AVERROR(EINVAL);
- linesizes[0] = (width * (desc->comp[0].step_minus1+1) + 7) >> 3;
- return 0;
- }
-
av_image_fill_max_pixsteps(max_step, max_step_comp, desc);
for (i = 0; i < 4; i++) {
- int s = (max_step_comp[i] == 1 || max_step_comp[i] == 2) ? desc->log2_chroma_w : 0;
- int shifted_w = ((width + (1 << s) - 1)) >> s;
- if (max_step[i] > INT_MAX / shifted_w)
- return AVERROR(EINVAL);
- linesizes[i] = max_step[i] * shifted_w;
+ if ((ret = image_get_linesize(width, i, max_step[i], max_step_comp[i], desc)) < 0)
+ return ret;
+ linesizes[i] = ret;
}
return 0;
@@ -191,7 +201,7 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
if ((ret = av_image_check_size(w, h, 0, NULL)) < 0)
return ret;
- if ((ret = av_image_fill_linesizes(linesizes, pix_fmt, w)) < 0)
+ if ((ret = av_image_fill_linesizes(linesizes, pix_fmt, align>7 ? FFALIGN(w, 8) : w)) < 0)
return ret;
for (i = 0; i < 4; i++)
@@ -209,6 +219,14 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)
avpriv_set_systematic_pal2((uint32_t*)pointers[1], pix_fmt);
+ if ((desc->flags & AV_PIX_FMT_FLAG_PAL ||
+ desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) &&
+ pointers[1] - pointers[0] > linesizes[0] * h) {
+ /* zero-initialize the padding before the palette */
+ memset(pointers[0] + linesizes[0] * h, 0,
+ pointers[1] - pointers[0] - linesizes[0] * h);
+ }
+
return ret;
}
@@ -235,7 +253,7 @@ int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar)
{
int64_t scaled_dim;
- if (!sar.den)
+ if (sar.den <= 0 || sar.num < 0)
return AVERROR(EINVAL);
if (!sar.num || sar.num == sar.den)
@@ -258,6 +276,8 @@ void av_image_copy_plane(uint8_t *dst, int dst_linesize,
{
if (!dst || !src)
return;
+ av_assert0(abs(src_linesize) >= bytewidth);
+ av_assert0(abs(dst_linesize) >= bytewidth);
for (;height > 0; height--) {
memcpy(dst, src, bytewidth);
dst += dst_linesize;
@@ -290,8 +310,12 @@ void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4],
for (i = 0; i < planes_nb; i++) {
int h = height;
int bwidth = av_image_get_linesize(pix_fmt, width, i);
+ if (bwidth < 0) {
+ av_log(NULL, AV_LOG_ERROR, "av_image_get_linesize failed\n");
+ return;
+ }
if (i == 1 || i == 2) {
- h= -((-height)>>desc->log2_chroma_h);
+ h = FF_CEIL_RSHIFT(height, desc->log2_chroma_h);
}
av_image_copy_plane(dst_data[i], dst_linesizes[i],
src_data[i], src_linesizes[i],
@@ -317,7 +341,7 @@ int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
for (i = 0; i < 4; i++)
dst_linesize[i] = FFALIGN(dst_linesize[i], align);
- return av_image_fill_pointers(dst_data, pix_fmt, height, src, dst_linesize);
+ return av_image_fill_pointers(dst_data, pix_fmt, height, (uint8_t *)src, dst_linesize);
}
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt,
@@ -328,7 +352,7 @@ int av_image_get_buffer_size(enum AVPixelFormat pix_fmt,
int ret;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
if (!desc)
- return AVERROR_BUG;
+ return AVERROR(EINVAL);
ret = av_image_check_size(width, height, 0, NULL);
if (ret < 0)
@@ -373,9 +397,11 @@ int av_image_copy_to_buffer(uint8_t *dst, int dst_size,
}
}
- if (desc->flags & AV_PIX_FMT_FLAG_PAL)
- memcpy((unsigned char *)(((size_t)dst + 3) & ~3),
- src_data[1], 256 * 4);
+ if (desc->flags & AV_PIX_FMT_FLAG_PAL) {
+ uint32_t *d32 = (uint32_t *)(((size_t)dst + 3) & ~3);
+ for (i = 0; i<256; i++)
+ AV_WL32(d32 + i, AV_RN32(src_data[1] + 4*i));
+ }
return size;
}
diff --git a/libavutil/imgutils.h b/libavutil/imgutils.h
index 04d6138f67..23282a38fa 100644
--- a/libavutil/imgutils.h
+++ b/libavutil/imgutils.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -100,6 +100,9 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
* The first byte of each successive line is separated by *_linesize
* bytes.
*
+ * bytewidth must be contained by both absolute values of dst_linesize
+ * and src_linesize, otherwise the function behavior is undefined.
+ *
* @param dst_linesize linesize for the image plane in dst
* @param src_linesize linesize for the image plane in src
*/
diff --git a/libavutil/integer.c b/libavutil/integer.c
new file mode 100644
index 0000000000..5bcde0dc6e
--- /dev/null
+++ b/libavutil/integer.c
@@ -0,0 +1,196 @@
+/*
+ * arbitrary precision integers
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * arbitrary precision integers
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "common.h"
+#include "integer.h"
+#include "avassert.h"
+
+AVInteger av_add_i(AVInteger a, AVInteger b){
+ int i, carry=0;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ carry= (carry>>16) + a.v[i] + b.v[i];
+ a.v[i]= carry;
+ }
+ return a;
+}
+
+AVInteger av_sub_i(AVInteger a, AVInteger b){
+ int i, carry=0;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ carry= (carry>>16) + a.v[i] - b.v[i];
+ a.v[i]= carry;
+ }
+ return a;
+}
+
+int av_log2_i(AVInteger a){
+ int i;
+
+ for(i=AV_INTEGER_SIZE-1; i>=0; i--){
+ if(a.v[i])
+ return av_log2_16bit(a.v[i]) + 16*i;
+ }
+ return -1;
+}
+
+AVInteger av_mul_i(AVInteger a, AVInteger b){
+ AVInteger out;
+ int i, j;
+ int na= (av_log2_i(a)+16) >> 4;
+ int nb= (av_log2_i(b)+16) >> 4;
+
+ memset(&out, 0, sizeof(out));
+
+ for(i=0; i<na; i++){
+ unsigned int carry=0;
+
+ if(a.v[i])
+ for(j=i; j<AV_INTEGER_SIZE && j-i<=nb; j++){
+ carry= (carry>>16) + out.v[j] + a.v[i]*b.v[j-i];
+ out.v[j]= carry;
+ }
+ }
+
+ return out;
+}
+
+int av_cmp_i(AVInteger a, AVInteger b){
+ int i;
+ int v= (int16_t)a.v[AV_INTEGER_SIZE-1] - (int16_t)b.v[AV_INTEGER_SIZE-1];
+ if(v) return (v>>16)|1;
+
+ for(i=AV_INTEGER_SIZE-2; i>=0; i--){
+ int v= a.v[i] - b.v[i];
+ if(v) return (v>>16)|1;
+ }
+ return 0;
+}
+
+AVInteger av_shr_i(AVInteger a, int s){
+ AVInteger out;
+ int i;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ unsigned int index= i + (s>>4);
+ unsigned int v=0;
+ if(index+1<AV_INTEGER_SIZE) v = a.v[index+1]<<16;
+ if(index <AV_INTEGER_SIZE) v+= a.v[index ];
+ out.v[i]= v >> (s&15);
+ }
+ return out;
+}
+
+AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b){
+ int i= av_log2_i(a) - av_log2_i(b);
+ AVInteger quot_temp;
+ if(!quot) quot = &quot_temp;
+
+ av_assert2((int16_t)a.v[AV_INTEGER_SIZE-1] >= 0 && (int16_t)b.v[AV_INTEGER_SIZE-1] >= 0);
+ av_assert2(av_log2_i(b)>=0);
+
+ if(i > 0)
+ b= av_shr_i(b, -i);
+
+ memset(quot, 0, sizeof(AVInteger));
+
+ while(i-- >= 0){
+ *quot= av_shr_i(*quot, -1);
+ if(av_cmp_i(a, b) >= 0){
+ a= av_sub_i(a, b);
+ quot->v[0] += 1;
+ }
+ b= av_shr_i(b, 1);
+ }
+ return a;
+}
+
+AVInteger av_div_i(AVInteger a, AVInteger b){
+ AVInteger quot;
+ av_mod_i(&quot, a, b);
+ return quot;
+}
+
+AVInteger av_int2i(int64_t a){
+ AVInteger out;
+ int i;
+
+ for(i=0; i<AV_INTEGER_SIZE; i++){
+ out.v[i]= a;
+ a>>=16;
+ }
+ return out;
+}
+
+int64_t av_i2int(AVInteger a){
+ int i;
+ int64_t out=(int8_t)a.v[AV_INTEGER_SIZE-1];
+
+ for(i= AV_INTEGER_SIZE-2; i>=0; i--){
+ out = (out<<16) + a.v[i];
+ }
+ return out;
+}
+
+#ifdef TEST
+
+const uint8_t ff_log2_tab[256]={
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+int main(void){
+ int64_t a,b;
+
+ for(a=7; a<256*256*256; a+=13215){
+ for(b=3; b<256*256*256; b+=27118){
+ AVInteger ai= av_int2i(a);
+ AVInteger bi= av_int2i(b);
+
+ av_assert0(av_i2int(ai) == a);
+ av_assert0(av_i2int(bi) == b);
+ av_assert0(av_i2int(av_add_i(ai,bi)) == a+b);
+ av_assert0(av_i2int(av_sub_i(ai,bi)) == a-b);
+ av_assert0(av_i2int(av_mul_i(ai,bi)) == a*b);
+ av_assert0(av_i2int(av_shr_i(ai, 9)) == a>>9);
+ av_assert0(av_i2int(av_shr_i(ai,-9)) == a<<9);
+ av_assert0(av_i2int(av_shr_i(ai, 17)) == a>>17);
+ av_assert0(av_i2int(av_shr_i(ai,-17)) == a<<17);
+ av_assert0(av_log2_i(ai) == av_log2(a));
+ av_assert0(av_i2int(av_div_i(ai,bi)) == a/b);
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/libavutil/integer.h b/libavutil/integer.h
new file mode 100644
index 0000000000..45f733c04c
--- /dev/null
+++ b/libavutil/integer.h
@@ -0,0 +1,86 @@
+/*
+ * arbitrary precision integers
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * arbitrary precision integers
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#ifndef AVUTIL_INTEGER_H
+#define AVUTIL_INTEGER_H
+
+#include <stdint.h>
+#include "common.h"
+
+#define AV_INTEGER_SIZE 8
+
+typedef struct AVInteger{
+ uint16_t v[AV_INTEGER_SIZE];
+} AVInteger;
+
+AVInteger av_add_i(AVInteger a, AVInteger b) av_const;
+AVInteger av_sub_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * Return the rounded-down value of the base 2 logarithm of the given
+ * AVInteger. This is simply the index of the most significant bit
+ * which is 1, or 0 if all bits are 0.
+ */
+int av_log2_i(AVInteger a) av_const;
+AVInteger av_mul_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * Return 0 if a==b, 1 if a>b and -1 if a<b.
+ */
+int av_cmp_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * bitwise shift
+ * @param s the number of bits by which the value should be shifted right,
+ may be negative for shifting left
+ */
+AVInteger av_shr_i(AVInteger a, int s) av_const;
+
+/**
+ * Return a % b.
+ * @param quot a/b will be stored here.
+ */
+AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b);
+
+/**
+ * Return a/b.
+ */
+AVInteger av_div_i(AVInteger a, AVInteger b) av_const;
+
+/**
+ * Convert the given int64_t to an AVInteger.
+ */
+AVInteger av_int2i(int64_t a) av_const;
+
+/**
+ * Convert the given AVInteger to an int64_t.
+ * If the AVInteger is too large to fit into an int64_t,
+ * then only the least significant 64 bits will be used.
+ */
+int64_t av_i2int(AVInteger a) av_const;
+
+#endif /* AVUTIL_INTEGER_H */
diff --git a/libavutil/internal.h b/libavutil/internal.h
index 800680a7f2..61bc027630 100644
--- a/libavutil/internal.h
+++ b/libavutil/internal.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,15 +36,18 @@
#include <assert.h>
#include "config.h"
#include "attributes.h"
+#include "timer.h"
+#include "cpu.h"
#include "dict.h"
#include "pixfmt.h"
+#include "version.h"
#if ARCH_X86
# include "x86/emms.h"
#endif
#ifndef emms_c
-# define emms_c()
+# define emms_c() while(0)
#endif
#ifndef attribute_align_arg
@@ -62,7 +65,7 @@
#endif
#if HAVE_PRAGMA_DEPRECATED
-# if defined(__ICL)
+# if defined(__ICL) || defined (__INTEL_COMPILER)
# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478))
# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop))
# elif defined(_MSC_VER)
@@ -77,6 +80,13 @@
# define FF_ENABLE_DEPRECATION_WARNINGS
#endif
+
+#define FF_MEMORY_POISON 0x2a
+
+#define MAKE_ACCESSORS(str, name, type, field) \
+ type av_##name##_get_##field(const str *s) { return s->field; } \
+ void av_##name##_set_##field(str *s, type v) { s->field = v; }
+
// Some broken preprocessors need a second expansion
// to be forced to tokenize __VA_ARGS__
#define E1(x) x
@@ -110,6 +120,12 @@
# define LOCAL_ALIGNED_16(t, v, ...) LOCAL_ALIGNED(16, t, v, __VA_ARGS__)
#endif
+#if HAVE_LOCAL_ALIGNED_32
+# define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_D(32, t, v, __VA_ARGS__,,))
+#else
+# define LOCAL_ALIGNED_32(t, v, ...) LOCAL_ALIGNED(32, t, v, __VA_ARGS__)
+#endif
+
#define FF_ALLOC_OR_GOTO(ctx, p, size, label)\
{\
p = av_malloc(size);\
@@ -128,9 +144,27 @@
}\
}
+#define FF_ALLOC_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\
+{\
+ p = av_malloc_array(nelem, elsize);\
+ if (!p) {\
+ av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\
+ goto label;\
+ }\
+}
+
+#define FF_ALLOCZ_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\
+{\
+ p = av_mallocz_array(nelem, elsize);\
+ if (!p) {\
+ av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\
+ goto label;\
+ }\
+}
+
#include "libm.h"
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && _MSC_VER < 1900
#pragma comment(linker, "/include:"EXTERN_PREFIX"avpriv_strtod")
#pragma comment(linker, "/include:"EXTERN_PREFIX"avpriv_snprintf")
#endif
@@ -146,12 +180,11 @@
# define NULL_IF_CONFIG_SMALL(x) x
#endif
-
/**
* Define a function with only the non-default version specified.
*
* On systems with ELF shared libraries, all symbols exported from
- * Libav libraries are tagged with the name and major version of the
+ * FFmpeg libraries are tagged with the name and major version of the
* library to which they belong. If a function is moved from one
* library to another, a wrapper must be retained in the original
* location to preserve binary compatibility.
@@ -209,6 +242,11 @@ void avpriv_request_sample(void *avc,
#if HAVE_LIBC_MSVCRT
#define avpriv_open ff_open
+#define PTRDIFF_SPECIFIER "Id"
+#define SIZE_SPECIFIER "Iu"
+#else
+#define PTRDIFF_SPECIFIER "td"
+#define SIZE_SPECIFIER "zu"
#endif
/**
@@ -218,4 +256,23 @@ int avpriv_open(const char *filename, int flags, ...);
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)
+ return 0;
+
+ while ((unsigned)x > (unsigned)w) {
+ x = -x;
+ if (x < 0)
+ x += 2 * w;
+ }
+ return x;
+}
+
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+uint64_t ff_get_channel_layout(const char *name, int compat);
+#endif
+
+void ff_check_pixfmt_descriptors(void);
+
#endif /* AVUTIL_INTERNAL_H */
diff --git a/libavutil/intfloat.h b/libavutil/intfloat.h
index 38d26ad87e..fe3d7ec4a5 100644
--- a/libavutil/intfloat.h
+++ b/libavutil/intfloat.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2011 Mans Rullgard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/intmath.c b/libavutil/intmath.c
index 8db425c6e9..1f725c741f 100644
--- a/libavutil/intmath.c
+++ b/libavutil/intmath.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/intmath.h b/libavutil/intmath.h
index a5ee6525ee..f5ecc77b7d 100644
--- a/libavutil/intmath.h
+++ b/libavutil/intmath.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,27 +29,38 @@
#if ARCH_ARM
# include "arm/intmath.h"
#endif
+#if ARCH_X86
+# include "x86/intmath.h"
+#endif
/**
* @addtogroup lavu_internal
* @{
*/
-#if HAVE_FAST_CLZ && AV_GCC_VERSION_AT_LEAST(3,4)
-
+#if HAVE_FAST_CLZ
+#if AV_GCC_VERSION_AT_LEAST(3,4)
#ifndef ff_log2
# define ff_log2(x) (31 - __builtin_clz((x)|1))
# ifndef ff_log2_16bit
# define ff_log2_16bit av_log2
# endif
#endif /* ff_log2 */
-
+#elif defined( __INTEL_COMPILER )
+#ifndef ff_log2
+# define ff_log2(x) (_bit_scan_reverse((x)|1))
+# ifndef ff_log2_16bit
+# define ff_log2_16bit av_log2
+# endif
+#endif /* ff_log2 */
+#endif
#endif /* AV_GCC_VERSION_AT_LEAST(3,4) */
extern const uint8_t ff_log2_tab[256];
#ifndef ff_log2
#define ff_log2 ff_log2_c
+#if !defined( _MSC_VER )
static av_always_inline av_const int ff_log2_c(unsigned int v)
{
int n = 0;
@@ -65,6 +76,15 @@ static av_always_inline av_const int ff_log2_c(unsigned int v)
return n;
}
+#else
+static av_always_inline av_const int ff_log2_c(unsigned int v)
+{
+ unsigned long n;
+ _BitScanReverse(&n, v|1);
+ return n;
+}
+#define ff_log2_16bit av_log2
+#endif
#endif
#ifndef ff_log2_16bit
@@ -94,14 +114,21 @@ static av_always_inline av_const int ff_log2_16bit_c(unsigned int v)
* @{
*/
-#if HAVE_FAST_CLZ && AV_GCC_VERSION_AT_LEAST(3,4)
+#if HAVE_FAST_CLZ
+#if AV_GCC_VERSION_AT_LEAST(3,4)
#ifndef ff_ctz
#define ff_ctz(v) __builtin_ctz(v)
#endif
+#elif defined( __INTEL_COMPILER )
+#ifndef ff_ctz
+#define ff_ctz(v) _bit_scan_forward(v)
+#endif
+#endif
#endif
#ifndef ff_ctz
#define ff_ctz ff_ctz_c
+#if !defined( _MSC_VER )
static av_always_inline av_const int ff_ctz_c(int v)
{
int c;
@@ -130,6 +157,14 @@ static av_always_inline av_const int ff_ctz_c(int v)
return c;
}
+#else
+static av_always_inline av_const int ff_ctz_c( int v )
+{
+ unsigned long c;
+ _BitScanForward(&c, v);
+ return c;
+}
+#endif
#endif
/**
diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h
index f77fd60f38..51fbe30a23 100644
--- a/libavutil/intreadwrite.h
+++ b/libavutil/intreadwrite.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,9 +47,17 @@ typedef union {
/*
* Arch-specific headers can provide any combination of
- * AV_[RW][BLN](16|24|32|64) and AV_(COPY|SWAP|ZERO)(64|128) macros.
+ * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros.
* Preprocessor symbols must be defined, even if these are implemented
* as inline functions.
+ *
+ * R/W means read/write, B/L/N means big/little/native endianness.
+ * The following macros require aligned access, compared to their
+ * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A.
+ * Incorrect usage may range from abysmal performance to crash
+ * depending on the platform.
+ *
+ * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U.
*/
#ifdef HAVE_AV_CONFIG_H
@@ -114,6 +122,18 @@ typedef union {
# define AV_WN32(p, v) AV_WB32(p, v)
# endif
+# if defined(AV_RN48) && !defined(AV_RB48)
+# define AV_RB48(p) AV_RN48(p)
+# elif !defined(AV_RN48) && defined(AV_RB48)
+# define AV_RN48(p) AV_RB48(p)
+# endif
+
+# if defined(AV_WN48) && !defined(AV_WB48)
+# define AV_WB48(p, v) AV_WN48(p, v)
+# elif !defined(AV_WN48) && defined(AV_WB48)
+# define AV_WN48(p, v) AV_WB48(p, v)
+# endif
+
# if defined(AV_RN64) && !defined(AV_RB64)
# define AV_RB64(p) AV_RN64(p)
# elif !defined(AV_RN64) && defined(AV_RB64)
@@ -164,6 +184,18 @@ typedef union {
# define AV_WN32(p, v) AV_WL32(p, v)
# endif
+# if defined(AV_RN48) && !defined(AV_RL48)
+# define AV_RL48(p) AV_RN48(p)
+# elif !defined(AV_RN48) && defined(AV_RL48)
+# define AV_RN48(p) AV_RL48(p)
+# endif
+
+# if defined(AV_WN48) && !defined(AV_WL48)
+# define AV_WL48(p, v) AV_WN48(p, v)
+# elif !defined(AV_WN48) && defined(AV_WL48)
+# define AV_WN48(p, v) AV_WL48(p, v)
+# endif
+
# if defined(AV_RN64) && !defined(AV_RL64)
# define AV_RL64(p) AV_RN64(p)
# elif !defined(AV_RN64) && defined(AV_RL64)
@@ -210,7 +242,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
((const uint8_t*)(x))[1])
#endif
#ifndef AV_WB16
-# define AV_WB16(p, d) do { \
+# define AV_WB16(p, darg) do { \
+ unsigned d = (darg); \
((uint8_t*)(p))[1] = (d); \
((uint8_t*)(p))[0] = (d)>>8; \
} while(0)
@@ -222,7 +255,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
((const uint8_t*)(x))[0])
#endif
#ifndef AV_WL16
-# define AV_WL16(p, d) do { \
+# define AV_WL16(p, darg) do { \
+ unsigned d = (darg); \
((uint8_t*)(p))[0] = (d); \
((uint8_t*)(p))[1] = (d)>>8; \
} while(0)
@@ -236,7 +270,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
((const uint8_t*)(x))[3])
#endif
#ifndef AV_WB32
-# define AV_WB32(p, d) do { \
+# define AV_WB32(p, darg) do { \
+ unsigned d = (darg); \
((uint8_t*)(p))[3] = (d); \
((uint8_t*)(p))[2] = (d)>>8; \
((uint8_t*)(p))[1] = (d)>>16; \
@@ -252,7 +287,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
((const uint8_t*)(x))[0])
#endif
#ifndef AV_WL32
-# define AV_WL32(p, d) do { \
+# define AV_WL32(p, darg) do { \
+ unsigned d = (darg); \
((uint8_t*)(p))[0] = (d); \
((uint8_t*)(p))[1] = (d)>>8; \
((uint8_t*)(p))[2] = (d)>>16; \
@@ -272,7 +308,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
(uint64_t)((const uint8_t*)(x))[7])
#endif
#ifndef AV_WB64
-# define AV_WB64(p, d) do { \
+# define AV_WB64(p, darg) do { \
+ uint64_t d = (darg); \
((uint8_t*)(p))[7] = (d); \
((uint8_t*)(p))[6] = (d)>>8; \
((uint8_t*)(p))[5] = (d)>>16; \
@@ -296,7 +333,8 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
(uint64_t)((const uint8_t*)(x))[0])
#endif
#ifndef AV_WL64
-# define AV_WL64(p, d) do { \
+# define AV_WL64(p, darg) do { \
+ uint64_t d = (darg); \
((uint8_t*)(p))[0] = (d); \
((uint8_t*)(p))[1] = (d)>>8; \
((uint8_t*)(p))[2] = (d)>>16; \
@@ -430,6 +468,48 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias;
} while(0)
#endif
+#ifndef AV_RB48
+# define AV_RB48(x) \
+ (((uint64_t)((const uint8_t*)(x))[0] << 40) | \
+ ((uint64_t)((const uint8_t*)(x))[1] << 32) | \
+ ((uint64_t)((const uint8_t*)(x))[2] << 24) | \
+ ((uint64_t)((const uint8_t*)(x))[3] << 16) | \
+ ((uint64_t)((const uint8_t*)(x))[4] << 8) | \
+ (uint64_t)((const uint8_t*)(x))[5])
+#endif
+#ifndef AV_WB48
+# define AV_WB48(p, darg) do { \
+ uint64_t d = (darg); \
+ ((uint8_t*)(p))[5] = (d); \
+ ((uint8_t*)(p))[4] = (d)>>8; \
+ ((uint8_t*)(p))[3] = (d)>>16; \
+ ((uint8_t*)(p))[2] = (d)>>24; \
+ ((uint8_t*)(p))[1] = (d)>>32; \
+ ((uint8_t*)(p))[0] = (d)>>40; \
+ } while(0)
+#endif
+
+#ifndef AV_RL48
+# define AV_RL48(x) \
+ (((uint64_t)((const uint8_t*)(x))[5] << 40) | \
+ ((uint64_t)((const uint8_t*)(x))[4] << 32) | \
+ ((uint64_t)((const uint8_t*)(x))[3] << 24) | \
+ ((uint64_t)((const uint8_t*)(x))[2] << 16) | \
+ ((uint64_t)((const uint8_t*)(x))[1] << 8) | \
+ (uint64_t)((const uint8_t*)(x))[0])
+#endif
+#ifndef AV_WL48
+# define AV_WL48(p, darg) do { \
+ uint64_t d = (darg); \
+ ((uint8_t*)(p))[0] = (d); \
+ ((uint8_t*)(p))[1] = (d)>>8; \
+ ((uint8_t*)(p))[2] = (d)>>16; \
+ ((uint8_t*)(p))[3] = (d)>>24; \
+ ((uint8_t*)(p))[4] = (d)>>32; \
+ ((uint8_t*)(p))[5] = (d)>>40; \
+ } while(0)
+#endif
+
/*
* The AV_[RW]NA macros access naturally aligned data
* in a type-safe way.
diff --git a/libavutil/lfg.c b/libavutil/lfg.c
index 4221e6228b..ffa2f1fd3d 100644
--- a/libavutil/lfg.c
+++ b/libavutil/lfg.c
@@ -2,20 +2,20 @@
* Lagged Fibonacci PRNG
* Copyright (c) 2008 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,8 +72,10 @@ int main(void)
av_lfg_init(&state, 0xdeadbeef);
for (j = 0; j < 10000; j++) {
START_TIMER
- for (i = 0; i < 624; i++)
+ for (i = 0; i < 624; i++) {
+ //av_log(NULL, AV_LOG_ERROR, "%X\n", av_lfg_get(&state));
x += av_lfg_get(&state);
+ }
STOP_TIMER("624 calls of av_lfg_get");
}
av_log(NULL, AV_LOG_ERROR, "final value:%X\n", x);
diff --git a/libavutil/lfg.h b/libavutil/lfg.h
index 5e526c1dae..ec90562cf2 100644
--- a/libavutil/lfg.h
+++ b/libavutil/lfg.h
@@ -2,20 +2,20 @@
* Lagged Fibonacci PRNG
* Copyright (c) 2008 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/libm.h b/libavutil/libm.h
index d6c2cf8623..6c17b287b4 100644
--- a/libavutil/libm.h
+++ b/libavutil/libm.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,10 @@
#include "attributes.h"
#include "intfloat.h"
+#if HAVE_MIPSFPU && HAVE_INLINE_ASM
+#include "libavutil/mips/libm_mips.h"
+#endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM*/
+
#if !HAVE_ATANF
#undef atanf
#define atanf(x) ((float)atan(x))
@@ -44,6 +48,13 @@
#define powf(x, y) ((float)pow(x, y))
#endif
+#if !HAVE_CBRT
+static av_always_inline double cbrt(double x)
+{
+ return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0);
+}
+#endif
+
#if !HAVE_CBRTF
static av_always_inline float cbrtf(float x)
{
diff --git a/libavutil/lls.c b/libavutil/lls.c
index f87c2cd153..f77043bc4a 100644
--- a/libavutil/lls.c
+++ b/libavutil/lls.c
@@ -3,20 +3,20 @@
*
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,7 +32,7 @@
#include "version.h"
#include "lls.h"
-static void update_lls(LLSModel *m, double *var)
+static void update_lls(LLSModel *m, const double *var)
{
int i, j;
@@ -100,7 +100,7 @@ void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order)
}
}
-static double evaluate_lls(LLSModel *m, double *param, int order)
+static double evaluate_lls(LLSModel *m, const double *param, int order)
{
int i;
double out = 0;
@@ -121,25 +121,6 @@ av_cold void avpriv_init_lls(LLSModel *m, int indep_count)
ff_init_lls_x86(m);
}
-#if FF_API_LLS_PRIVATE
-av_cold void av_init_lls(LLSModel *m, int indep_count)
-{
- avpriv_init_lls(m, indep_count);
-}
-void av_update_lls(LLSModel *m, double *param, double decay)
-{
- m->update_lls(m, param);
-}
-void av_solve_lls(LLSModel *m, double threshold, int min_order)
-{
- avpriv_solve_lls(m, threshold, min_order);
-}
-double av_evaluate_lls(LLSModel *m, double *param, int order)
-{
- return m->evaluate_lls(m, param, order);
-}
-#endif /* FF_API_LLS_PRIVATE */
-
#ifdef TEST
#include <stdio.h>
diff --git a/libavutil/lls.h b/libavutil/lls.h
index 27c0d5e3fe..5635b5b2fd 100644
--- a/libavutil/lls.h
+++ b/libavutil/lls.h
@@ -3,20 +3,20 @@
*
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -47,25 +47,18 @@ typedef struct LLSModel {
* 32-byte aligned, and any padding elements must be initialized
* (i.e not denormal/nan).
*/
- void (*update_lls)(struct LLSModel *m, double *var);
+ void (*update_lls)(struct LLSModel *m, const double *var);
/**
* Inner product of var[] and the LPC coefs.
* @param m this context
* @param var training samples, excluding the value to be predicted. unaligned.
* @param order lpc order
*/
- double (*evaluate_lls)(struct LLSModel *m, double *var, int order);
+ double (*evaluate_lls)(struct LLSModel *m, const double *var, int order);
} LLSModel;
void avpriv_init_lls(LLSModel *m, int indep_count);
void ff_init_lls_x86(LLSModel *m);
void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order);
-#if FF_API_LLS_PRIVATE
-void av_init_lls(LLSModel *m, int indep_count);
-void av_update_lls(LLSModel *m, double *param, double decay);
-void av_solve_lls(LLSModel *m, double threshold, int min_order);
-double av_evaluate_lls(LLSModel *m, double *param, int order);
-#endif /* FF_API_LLS_PRIVATE */
-
#endif /* AVUTIL_LLS_H */
diff --git a/libavutil/log.c b/libavutil/log.c
index 37427efaf1..b2bc65cd8b 100644
--- a/libavutil/log.c
+++ b/libavutil/log.c
@@ -2,20 +2,20 @@
* log functions
* Copyright (c) 2003 Michel Bardiaux
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,12 +34,19 @@
#endif
#include <stdarg.h>
#include <stdlib.h>
-#include "avstring.h"
#include "avutil.h"
+#include "bprint.h"
#include "common.h"
#include "internal.h"
#include "log.h"
+#if HAVE_PTHREADS
+#include <pthread.h>
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#define LINE_SZ 1024
+
#if HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
/* this is the log level at which valgrind will output a full backtrace */
@@ -50,27 +57,74 @@ static int av_log_level = AV_LOG_INFO;
static int flags;
#define NB_LEVELS 8
-#if HAVE_SETCONSOLETEXTATTRIBUTE
+#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
#include <windows.h>
-static const uint8_t color[NB_LEVELS] = { 12, 12, 12, 14, 7, 10, 11, 8};
+static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = {
+ [AV_LOG_PANIC /8] = 12,
+ [AV_LOG_FATAL /8] = 12,
+ [AV_LOG_ERROR /8] = 12,
+ [AV_LOG_WARNING/8] = 14,
+ [AV_LOG_INFO /8] = 7,
+ [AV_LOG_VERBOSE/8] = 10,
+ [AV_LOG_DEBUG /8] = 10,
+ [AV_LOG_TRACE /8] = 8,
+ [16+AV_CLASS_CATEGORY_NA ] = 7,
+ [16+AV_CLASS_CATEGORY_INPUT ] = 13,
+ [16+AV_CLASS_CATEGORY_OUTPUT ] = 5,
+ [16+AV_CLASS_CATEGORY_MUXER ] = 13,
+ [16+AV_CLASS_CATEGORY_DEMUXER ] = 5,
+ [16+AV_CLASS_CATEGORY_ENCODER ] = 11,
+ [16+AV_CLASS_CATEGORY_DECODER ] = 3,
+ [16+AV_CLASS_CATEGORY_FILTER ] = 10,
+ [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 9,
+ [16+AV_CLASS_CATEGORY_SWSCALER ] = 7,
+ [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 7,
+ [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 13,
+ [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 5,
+ [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 13,
+ [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 5,
+ [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 13,
+ [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 5,
+};
+
static int16_t background, attr_orig;
static HANDLE con;
-#define set_color(x) SetConsoleTextAttribute(con, background | color[x])
-#define reset_color() SetConsoleTextAttribute(con, attr_orig)
-#define print_256color(x)
#else
-static const uint8_t color[NB_LEVELS] = {
- 0x41, 0x41, 0x11, 0x03, 9, 0x02, 0x06, 0x07
+
+static const uint32_t color[16 + AV_CLASS_CATEGORY_NB] = {
+ [AV_LOG_PANIC /8] = 52 << 16 | 196 << 8 | 0x41,
+ [AV_LOG_FATAL /8] = 208 << 8 | 0x41,
+ [AV_LOG_ERROR /8] = 196 << 8 | 0x11,
+ [AV_LOG_WARNING/8] = 226 << 8 | 0x03,
+ [AV_LOG_INFO /8] = 253 << 8 | 0x09,
+ [AV_LOG_VERBOSE/8] = 40 << 8 | 0x02,
+ [AV_LOG_DEBUG /8] = 34 << 8 | 0x02,
+ [AV_LOG_TRACE /8] = 34 << 8 | 0x07,
+ [16+AV_CLASS_CATEGORY_NA ] = 250 << 8 | 0x09,
+ [16+AV_CLASS_CATEGORY_INPUT ] = 219 << 8 | 0x15,
+ [16+AV_CLASS_CATEGORY_OUTPUT ] = 201 << 8 | 0x05,
+ [16+AV_CLASS_CATEGORY_MUXER ] = 213 << 8 | 0x15,
+ [16+AV_CLASS_CATEGORY_DEMUXER ] = 207 << 8 | 0x05,
+ [16+AV_CLASS_CATEGORY_ENCODER ] = 51 << 8 | 0x16,
+ [16+AV_CLASS_CATEGORY_DECODER ] = 39 << 8 | 0x06,
+ [16+AV_CLASS_CATEGORY_FILTER ] = 155 << 8 | 0x12,
+ [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 192 << 8 | 0x14,
+ [16+AV_CLASS_CATEGORY_SWSCALER ] = 153 << 8 | 0x14,
+ [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 147 << 8 | 0x14,
+ [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 213 << 8 | 0x15,
+ [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 207 << 8 | 0x05,
+ [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 213 << 8 | 0x15,
+ [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 207 << 8 | 0x05,
+ [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 213 << 8 | 0x15,
+ [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 207 << 8 | 0x05,
};
-#define set_color(x) fprintf(stderr, "\033[%d;3%dm", color[x] >> 4, color[x]&15)
-#define print_256color(x) fprintf(stderr, "\033[38;5;%dm", x)
-#define reset_color() fprintf(stderr, "\033[0m")
+
#endif
static int use_color = -1;
static void check_color_terminal(void)
{
-#if HAVE_SETCONSOLETEXTATTRIBUTE
+#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
CONSOLE_SCREEN_BUFFER_INFO con_info;
con = GetStdHandle(STD_ERROR_HANDLE);
use_color = (con != INVALID_HANDLE_VALUE) && !getenv("NO_COLOR") &&
@@ -84,8 +138,9 @@ static void check_color_terminal(void)
char *term = getenv("TERM");
use_color = !getenv("NO_COLOR") && !getenv("AV_LOG_FORCE_NOCOLOR") &&
(getenv("TERM") && isatty(2) || getenv("AV_LOG_FORCE_COLOR"));
- if (use_color)
- use_color += term && strstr(term, "256color");
+ if ( getenv("AV_LOG_FORCE_256COLOR")
+ || (term && strstr(term, "256color")))
+ use_color *= 256;
#else
use_color = getenv("AV_LOG_FORCE_COLOR") && !getenv("NO_COLOR") &&
!getenv("AV_LOG_FORCE_NOCOLOR");
@@ -94,25 +149,45 @@ static void check_color_terminal(void)
static void colored_fputs(int level, int tint, const char *str)
{
+ int local_use_color;
+ if (!*str)
+ return;
+
if (use_color < 0)
check_color_terminal();
- switch (use_color) {
- case 1:
- set_color(level);
- break;
- case 2:
- set_color(level);
- if (tint)
- print_256color(tint);
- break;
- default:
- break;
- }
+ if (level == AV_LOG_INFO/8) local_use_color = 0;
+ else local_use_color = use_color;
+
+#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE
+ if (local_use_color)
+ SetConsoleTextAttribute(con, background | color[level]);
fputs(str, stderr);
- if (use_color) {
- reset_color();
- }
+ if (local_use_color)
+ SetConsoleTextAttribute(con, attr_orig);
+#else
+ if (local_use_color == 1) {
+ fprintf(stderr,
+ "\033[%d;3%dm%s\033[0m",
+ (color[level] >> 4) & 15,
+ color[level] & 15,
+ str);
+ } else if (tint && use_color == 256) {
+ fprintf(stderr,
+ "\033[48;5;%dm\033[38;5;%dm%s\033[0m",
+ (color[level] >> 16) & 0xff,
+ tint,
+ str);
+ } else if (local_use_color == 256) {
+ fprintf(stderr,
+ "\033[48;5;%dm\033[38;5;%dm%s\033[0m",
+ (color[level] >> 16) & 0xff,
+ (color[level] >> 8) & 0xff,
+ str);
+ } else
+ fputs(str, stderr);
+#endif
+
}
const char *av_default_item_name(void *ptr)
@@ -120,61 +195,161 @@ const char *av_default_item_name(void *ptr)
return (*(AVClass **) ptr)->class_name;
}
-void av_log_default_callback(void *avcl, int level, const char *fmt, va_list vl)
+AVClassCategory av_default_get_category(void *ptr)
{
- static int print_prefix = 1;
- static int count;
- static char prev[1024];
- char line[1024];
- static int is_atty;
- AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
- unsigned tint = level & 0xff00;
+ return (*(AVClass **) ptr)->category;
+}
- level &= 0xff;
+static void sanitize(uint8_t *line){
+ while(*line){
+ if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
+ *line='?';
+ line++;
+ }
+}
- if (level > av_log_level)
- return;
- line[0] = 0;
- if (print_prefix && avc) {
+static int get_category(void *ptr){
+ AVClass *avc = *(AVClass **) ptr;
+ if( !avc
+ || (avc->version&0xFF)<100
+ || avc->version < (51 << 16 | 59 << 8)
+ || avc->category >= AV_CLASS_CATEGORY_NB) return AV_CLASS_CATEGORY_NA + 16;
+
+ if(avc->get_category)
+ return avc->get_category(ptr) + 16;
+
+ return avc->category + 16;
+}
+
+static const char *get_level_str(int level)
+{
+ switch (level) {
+ case AV_LOG_QUIET:
+ return "quiet";
+ case AV_LOG_DEBUG:
+ return "debug";
+ case AV_LOG_VERBOSE:
+ return "verbose";
+ case AV_LOG_INFO:
+ return "info";
+ case AV_LOG_WARNING:
+ return "warning";
+ case AV_LOG_ERROR:
+ return "error";
+ case AV_LOG_FATAL:
+ return "fatal";
+ case AV_LOG_PANIC:
+ return "panic";
+ default:
+ return "";
+ }
+}
+
+static void format_line(void *avcl, int level, const char *fmt, va_list vl,
+ AVBPrint part[4], int *print_prefix, int type[2])
+{
+ AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
+ av_bprint_init(part+0, 0, 1);
+ av_bprint_init(part+1, 0, 1);
+ av_bprint_init(part+2, 0, 1);
+ av_bprint_init(part+3, 0, 65536);
+
+ if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16;
+ if (*print_prefix && avc) {
if (avc->parent_log_context_offset) {
AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
avc->parent_log_context_offset);
if (parent && *parent) {
- snprintf(line, sizeof(line), "[%s @ %p] ",
+ av_bprintf(part+0, "[%s @ %p] ",
(*parent)->item_name(parent), parent);
+ if(type) type[0] = get_category(parent);
}
}
- snprintf(line + strlen(line), sizeof(line) - strlen(line), "[%s @ %p] ",
+ av_bprintf(part+1, "[%s @ %p] ",
avc->item_name(avcl), avcl);
+ if(type) type[1] = get_category(avcl);
+
+ if (flags & AV_LOG_PRINT_LEVEL)
+ av_bprintf(part+2, "[%s] ", get_level_str(level));
+ }
+
+ av_vbprintf(part+3, fmt, vl);
+
+ if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
+ char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
+ *print_prefix = lastc == '\n' || lastc == '\r';
+ }
+}
+
+void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
+ char *line, int line_size, int *print_prefix)
+{
+ AVBPrint part[4];
+ format_line(ptr, level, fmt, vl, part, print_prefix, NULL);
+ snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
+ av_bprint_finalize(part+3, NULL);
+}
+
+void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
+{
+ static int print_prefix = 1;
+ static int count;
+ static char prev[LINE_SZ];
+ AVBPrint part[4];
+ char line[LINE_SZ];
+ static int is_atty;
+ int type[2];
+ unsigned tint = 0;
+
+ if (level >= 0) {
+ tint = level & 0xff00;
+ level &= 0xff;
}
- vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, vl);
+ if (level > av_log_level)
+ return;
+#if HAVE_PTHREADS
+ pthread_mutex_lock(&mutex);
+#endif
- print_prefix = strlen(line) && line[strlen(line) - 1] == '\n';
+ format_line(ptr, level, fmt, vl, part, &print_prefix, type);
+ snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
#if HAVE_ISATTY
if (!is_atty)
is_atty = isatty(2) ? 1 : -1;
#endif
- if (print_prefix && (flags & AV_LOG_SKIP_REPEATED) &&
- !strncmp(line, prev, sizeof line)) {
+ if (print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) &&
+ *line && line[strlen(line) - 1] != '\r'){
count++;
if (is_atty == 1)
fprintf(stderr, " Last message repeated %d times\r", count);
- return;
+ goto end;
}
if (count > 0) {
fprintf(stderr, " Last message repeated %d times\n", count);
count = 0;
}
- colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, line);
- av_strlcpy(prev, line, sizeof line);
+ strcpy(prev, line);
+ sanitize(part[0].str);
+ colored_fputs(type[0], 0, part[0].str);
+ sanitize(part[1].str);
+ colored_fputs(type[1], 0, part[1].str);
+ sanitize(part[2].str);
+ colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str);
+ sanitize(part[3].str);
+ colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str);
#if CONFIG_VALGRIND_BACKTRACE
if (level <= BACKTRACE_LOGLEVEL)
VALGRIND_PRINTF_BACKTRACE("");
#endif
+end:
+ av_bprint_finalize(part+3, NULL);
+#if HAVE_PTHREADS
+ pthread_mutex_unlock(&mutex);
+#endif
}
static void (*av_log_callback)(void*, int, const char*, va_list) =
@@ -194,7 +369,9 @@ void av_log(void* avcl, int level, const char *fmt, ...)
void av_vlog(void* avcl, int level, const char *fmt, va_list vl)
{
- av_log_callback(avcl, level, fmt, vl);
+ void (*log_callback)(void*, int, const char*, va_list) = av_log_callback;
+ if (log_callback)
+ log_callback(avcl, level, fmt, vl);
}
int av_log_get_level(void)
@@ -212,6 +389,11 @@ void av_log_set_flags(int arg)
flags = arg;
}
+int av_log_get_flags(void)
+{
+ return flags;
+}
+
void av_log_set_callback(void (*callback)(void*, int, const char*, va_list))
{
av_log_callback = callback;
@@ -221,14 +403,14 @@ static void missing_feature_sample(int sample, void *avc, const char *msg,
va_list argument_list)
{
av_vlog(avc, AV_LOG_WARNING, msg, argument_list);
- av_log(avc, AV_LOG_WARNING, " is not implemented. Update your Libav "
+ av_log(avc, AV_LOG_WARNING, " is not implemented. Update your FFmpeg "
"version to the newest one from Git. If the problem still "
"occurs, it means that your file has a feature which has not "
"been implemented.\n");
if (sample)
av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample "
- "of this file to ftp://upload.libav.org/incoming/ "
- "and contact the libav-devel mailing list.\n");
+ "of this file to ftp://upload.ffmpeg.org/incoming/ "
+ "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n");
}
void avpriv_request_sample(void *avc, const char *msg, ...)
@@ -248,3 +430,26 @@ void avpriv_report_missing_feature(void *avc, const char *msg, ...)
missing_feature_sample(0, avc, msg, argument_list);
va_end(argument_list);
}
+
+#ifdef TEST
+// LCOV_EXCL_START
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ int i;
+ av_log_set_level(AV_LOG_DEBUG);
+ for (use_color=0; use_color<=256; use_color = 255*use_color+1) {
+ av_log(NULL, AV_LOG_FATAL, "use_color: %d\n", use_color);
+ for (i = AV_LOG_DEBUG; i>=AV_LOG_QUIET; i-=8) {
+ av_log(NULL, i, " %d", i);
+ av_log(NULL, AV_LOG_INFO, "e ");
+ av_log(NULL, i + 256*123, "C%d", i);
+ av_log(NULL, AV_LOG_INFO, "e");
+ }
+ av_log(NULL, AV_LOG_PANIC, "\n");
+ }
+ return 0;
+}
+// LCOV_EXCL_STOP
+#endif
diff --git a/libavutil/log.h b/libavutil/log.h
index d4daea9c1a..57769b803c 100644
--- a/libavutil/log.h
+++ b/libavutil/log.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -26,6 +26,39 @@
#include "attributes.h"
#include "version.h"
+typedef enum {
+ AV_CLASS_CATEGORY_NA = 0,
+ AV_CLASS_CATEGORY_INPUT,
+ AV_CLASS_CATEGORY_OUTPUT,
+ AV_CLASS_CATEGORY_MUXER,
+ AV_CLASS_CATEGORY_DEMUXER,
+ AV_CLASS_CATEGORY_ENCODER,
+ AV_CLASS_CATEGORY_DECODER,
+ AV_CLASS_CATEGORY_FILTER,
+ AV_CLASS_CATEGORY_BITSTREAM_FILTER,
+ AV_CLASS_CATEGORY_SWSCALER,
+ AV_CLASS_CATEGORY_SWRESAMPLER,
+ AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40,
+ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT,
+ AV_CLASS_CATEGORY_DEVICE_OUTPUT,
+ AV_CLASS_CATEGORY_DEVICE_INPUT,
+ AV_CLASS_CATEGORY_NB, ///< not part of ABI/API
+}AVClassCategory;
+
+#define AV_IS_INPUT_DEVICE(category) \
+ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT))
+
+#define AV_IS_OUTPUT_DEVICE(category) \
+ (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \
+ ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT))
+
+struct AVOptionRanges;
+
/**
* Describe the class of an AVClass context structure. That is an
* arbitrary struct of which the first field is a pointer to an
@@ -88,6 +121,25 @@ typedef struct AVClass {
* child_class_next iterates over _all possible_ children.
*/
const struct AVClass* (*child_class_next)(const struct AVClass *prev);
+
+ /**
+ * Category used for visualization (like color)
+ * This is only set if the category is equal for all objects using this class.
+ * available since version (51 << 16 | 56 << 8 | 100)
+ */
+ AVClassCategory category;
+
+ /**
+ * Callback to return the category.
+ * available since version (51 << 16 | 59 << 8 | 100)
+ */
+ AVClassCategory (*get_category)(void* ctx);
+
+ /**
+ * Callback to return the supported/allowed ranges.
+ * available since version (52.12)
+ */
+ int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags);
} AVClass;
/**
@@ -144,6 +196,8 @@ typedef struct AVClass {
*/
#define AV_LOG_DEBUG 48
+#define AV_LOG_MAX_OFFSET (AV_LOG_DEBUG - AV_LOG_QUIET)
+
/**
* Extremely verbose debugging, useful for libav* development.
*/
@@ -161,7 +215,7 @@ typedef struct AVClass {
* Requires 256color terminal support. Uses outside debugging is not
* recommended.
*/
-#define AV_LOG_C(x) (x << 8)
+#define AV_LOG_C(x) ((x) << 8)
/**
* Send the specified message to the log if the level is less than or equal
@@ -171,7 +225,7 @@ typedef struct AVClass {
* @see av_log_set_callback
*
* @param avcl A pointer to an arbitrary struct of which the first field is a
- * pointer to an AVClass struct.
+ * pointer to an AVClass struct or NULL if general log.
* @param level The importance level of the message expressed using a @ref
* lavu_log_constants "Logging Constant".
* @param fmt The format string (printf-compatible) that specifies how
@@ -218,6 +272,9 @@ void av_log_set_level(int level);
/**
* Set the logging callback
*
+ * @note The callback must be thread safe, even if the application does not use
+ * threads itself as some codecs are multithreaded.
+ *
* @see av_log_default_callback
*
* @param callback A logging function with a compatible signature.
@@ -248,6 +305,17 @@ void av_log_default_callback(void *avcl, int level, const char *fmt,
* @return The AVClass class_name
*/
const char* av_default_item_name(void* ctx);
+AVClassCategory av_default_get_category(void *ptr);
+
+/**
+ * Format a line of log the same way as the default callback.
+ * @param line buffer to receive the formated line
+ * @param line_size size of the buffer
+ * @param print_prefix used to store whether the prefix must be printed;
+ * must point to a persistent integer initially set to 1
+ */
+void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
+ char *line, int line_size, int *print_prefix);
#if FF_API_DLOG
/**
@@ -259,7 +327,7 @@ const char* av_default_item_name(void* ctx);
#ifdef DEBUG
# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__)
#else
-# define av_dlog(pctx, ...)
+# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0)
#endif
#endif /* FF_API_DLOG */
@@ -269,10 +337,20 @@ const char* av_default_item_name(void* ctx);
* "Last message repeated x times" messages below (f)printf messages with some
* bad luck.
* Also to receive the last, "last repeated" line if any, the user app must
- * call av_log(NULL, AV_LOG_QUIET, ""); at the end
+ * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end
*/
#define AV_LOG_SKIP_REPEATED 1
+
+/**
+ * Include the log severity in messages originating from codecs.
+ *
+ * Results in messages such as:
+ * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts
+ */
+#define AV_LOG_PRINT_LEVEL 2
+
void av_log_set_flags(int arg);
+int av_log_get_flags(void);
/**
* @}
diff --git a/libavutil/log2_tab.c b/libavutil/log2_tab.c
index f6cbe79063..0dbf07d74c 100644
--- a/libavutil/log2_tab.c
+++ b/libavutil/log2_tab.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2003-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/lzo.c b/libavutil/lzo.c
index e458165261..bca10ec3e0 100644
--- a/libavutil/lzo.c
+++ b/libavutil/lzo.c
@@ -2,26 +2,27 @@
* LZO 1x decompression
* Copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h>
#include "avutil.h"
+#include "avassert.h"
#include "common.h"
#include "intreadwrite.h"
#include "lzo.h"
@@ -65,8 +66,13 @@ static inline int get_len(LZOContext *c, int x, int mask)
{
int cnt = x & mask;
if (!cnt) {
- while (!(x = get_byte(c)))
+ while (!(x = get_byte(c))) {
+ if (cnt >= INT_MAX - 1000) {
+ c->error |= AV_LZO_ERROR;
+ break;
+ }
cnt += 255;
+ }
cnt += mask + x;
}
return cnt;
@@ -80,10 +86,7 @@ static inline void copy(LZOContext *c, int cnt)
{
register const uint8_t *src = c->in;
register uint8_t *dst = c->out;
- if (cnt < 0) {
- c->error |= AV_LZO_ERROR;
- return;
- }
+ av_assert0(cnt >= 0);
if (cnt > c->in_end - src) {
cnt = FFMAX(c->in_end - src, 0);
c->error |= AV_LZO_INPUT_DEPLETED;
@@ -106,7 +109,7 @@ static inline void copy(LZOContext *c, int cnt)
/**
* @brief Copies previously decoded bytes to current position.
- * @param back how many bytes back we start
+ * @param back how many bytes back we start, must be > 0
* @param cnt number of bytes to copy, must be > 0
*
* cnt > back is valid, this will copy the bytes we just copied,
@@ -115,10 +118,7 @@ static inline void copy(LZOContext *c, int cnt)
static inline void copy_backptr(LZOContext *c, int back, int cnt)
{
register uint8_t *dst = c->out;
- if (cnt <= 0) {
- c->error |= AV_LZO_ERROR;
- return;
- }
+ av_assert0(cnt > 0);
if (dst - c->out_start < back) {
c->error |= AV_LZO_INVALID_BACKPTR;
return;
@@ -136,11 +136,11 @@ int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen)
int state = 0;
int x;
LZOContext c;
- if (!*outlen || !*inlen) {
+ if (*outlen <= 0 || *inlen <= 0) {
int res = 0;
- if (!*outlen)
+ if (*outlen <= 0)
res |= AV_LZO_OUTPUT_FULL;
- if (!*inlen)
+ if (*inlen <= 0)
res |= AV_LZO_INPUT_DEPLETED;
return res;
}
@@ -203,3 +203,58 @@ int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen)
*outlen = c.out_end - c.out;
return c.error;
}
+
+#ifdef TEST
+#include <stdio.h>
+#include <lzo/lzo1x.h>
+#include "log.h"
+#define MAXSZ (10*1024*1024)
+
+/* Define one of these to 1 if you wish to benchmark liblzo
+ * instead of our native implementation. */
+#define BENCHMARK_LIBLZO_SAFE 0
+#define BENCHMARK_LIBLZO_UNSAFE 0
+
+int main(int argc, char *argv[]) {
+ FILE *in = fopen(argv[1], "rb");
+ int comp_level = argc > 2 ? atoi(argv[2]) : 0;
+ uint8_t *orig = av_malloc(MAXSZ + 16);
+ uint8_t *comp = av_malloc(2*MAXSZ + 16);
+ uint8_t *decomp = av_malloc(MAXSZ + 16);
+ size_t s = fread(orig, 1, MAXSZ, in);
+ lzo_uint clen = 0;
+ long tmp[LZO1X_MEM_COMPRESS];
+ int inlen, outlen;
+ int i;
+ av_log_set_level(AV_LOG_DEBUG);
+ if (comp_level == 0) {
+ lzo1x_1_compress(orig, s, comp, &clen, tmp);
+ } else if (comp_level == 11) {
+ lzo1x_1_11_compress(orig, s, comp, &clen, tmp);
+ } else if (comp_level == 12) {
+ lzo1x_1_12_compress(orig, s, comp, &clen, tmp);
+ } else if (comp_level == 15) {
+ lzo1x_1_15_compress(orig, s, comp, &clen, tmp);
+ } else
+ lzo1x_999_compress(orig, s, comp, &clen, tmp);
+ for (i = 0; i < 300; i++) {
+START_TIMER
+ inlen = clen; outlen = MAXSZ;
+#if BENCHMARK_LIBLZO_SAFE
+ if (lzo1x_decompress_safe(comp, inlen, decomp, &outlen, NULL))
+#elif BENCHMARK_LIBLZO_UNSAFE
+ if (lzo1x_decompress(comp, inlen, decomp, &outlen, NULL))
+#else
+ if (av_lzo1x_decode(decomp, &outlen, comp, &inlen))
+#endif
+ av_log(NULL, AV_LOG_ERROR, "decompression error\n");
+STOP_TIMER("lzod")
+ }
+ if (memcmp(orig, decomp, s))
+ av_log(NULL, AV_LOG_ERROR, "decompression incorrect\n");
+ else
+ av_log(NULL, AV_LOG_ERROR, "decompression OK\n");
+ fclose(in);
+ return 0;
+}
+#endif
diff --git a/libavutil/lzo.h b/libavutil/lzo.h
index 9d7e8f1dc1..c03403992d 100644
--- a/libavutil/lzo.h
+++ b/libavutil/lzo.h
@@ -2,20 +2,20 @@
* LZO 1x decompression
* copyright (c) 2006 Reimar Doeffinger
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/macros.h b/libavutil/macros.h
index bf3eb9b9a4..446532377a 100644
--- a/libavutil/macros.h
+++ b/libavutil/macros.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/mathematics.c b/libavutil/mathematics.c
index f36623a0b9..126cffc3f0 100644
--- a/libavutil/mathematics.c
+++ b/libavutil/mathematics.c
@@ -1,20 +1,20 @@
/*
- * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2005-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,8 @@
#include <limits.h>
#include "mathematics.h"
+#include "libavutil/common.h"
+#include "avassert.h"
#include "version.h"
#if FF_API_AV_REVERSE
@@ -61,10 +63,19 @@ int64_t av_gcd(int64_t a, int64_t b)
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
{
int64_t r = 0;
+ av_assert2(c > 0);
+ av_assert2(b >=0);
+ av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4);
- if (c <= 0 || b < 0 || rnd == 4 || rnd > 5)
+ if (c <= 0 || b < 0 || !((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4))
return INT64_MIN;
+ if (rnd & AV_ROUND_PASS_MINMAX) {
+ if (a == INT64_MIN || a == INT64_MAX)
+ return a;
+ rnd -= AV_ROUND_PASS_MINMAX;
+ }
+
if (a < 0 && a != INT64_MIN)
return -av_rescale_rnd(-a, b, c, rnd ^ ((rnd >> 1) & 1));
@@ -135,6 +146,8 @@ int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
{
int64_t a = tb_a.num * (int64_t)tb_b.den;
int64_t b = tb_b.num * (int64_t)tb_a.den;
+ if ((FFABS(ts_a)|a|FFABS(ts_b)|b) <= INT_MAX)
+ return (ts_a*a > ts_b*b) - (ts_a*a < ts_b*b);
if (av_rescale_rnd(ts_a, a, b, AV_ROUND_DOWN) < ts_b)
return -1;
if (av_rescale_rnd(ts_b, b, a, AV_ROUND_DOWN) < ts_a)
@@ -149,3 +162,48 @@ int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod)
c -= mod;
return c;
}
+
+int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
+ int64_t a, b, this;
+
+ av_assert0(in_ts != AV_NOPTS_VALUE);
+ av_assert0(duration >= 0);
+
+ if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) {
+simple_round:
+ *last = av_rescale_q(in_ts, in_tb, fs_tb) + duration;
+ return av_rescale_q(in_ts, in_tb, out_tb);
+ }
+
+ a = av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN) >>1;
+ b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP )+1)>>1;
+ if (*last < 2*a - b || *last > 2*b - a)
+ goto simple_round;
+
+ this = av_clip64(*last, a, b);
+ *last = this + duration;
+
+ return av_rescale_q(this, fs_tb, out_tb);
+}
+
+int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc)
+{
+ int64_t m, d;
+
+ if (inc != 1)
+ inc_tb = av_mul_q(inc_tb, (AVRational) {inc, 1});
+
+ m = inc_tb.num * (int64_t)ts_tb.den;
+ d = inc_tb.den * (int64_t)ts_tb.num;
+
+ if (m % d == 0)
+ return ts + m / d;
+ if (m < d)
+ return ts;
+
+ {
+ int64_t old = av_rescale_q(ts, ts_tb, inc_tb);
+ int64_t old_ts = av_rescale_q(old, inc_tb, ts_tb);
+ return av_rescale_q(old + 1, inc_tb, ts_tb) + (ts - old_ts);
+ }
+}
diff --git a/libavutil/mathematics.h b/libavutil/mathematics.h
index 043dd0fafe..ac94488729 100644
--- a/libavutil/mathematics.h
+++ b/libavutil/mathematics.h
@@ -1,20 +1,20 @@
/*
- * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
+ * copyright (c) 2005-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,12 +27,33 @@
#include "rational.h"
#include "intfloat.h"
+#ifndef M_E
+#define M_E 2.7182818284590452354 /* e */
+#endif
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942 /* log_e 2 */
+#endif
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402 /* log_e 10 */
+#endif
#ifndef M_LOG2_10
#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */
#endif
#ifndef M_PHI
#define M_PHI 1.61803398874989484820 /* phi / golden ratio */
#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 /* pi */
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
+#endif
#ifndef NAN
#define NAN av_int2float(0x7fc00000)
#endif
@@ -52,6 +73,7 @@ enum AVRounding {
AV_ROUND_DOWN = 2, ///< Round toward -infinity.
AV_ROUND_UP = 3, ///< Round toward +infinity.
AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero.
+ AV_ROUND_PASS_MINMAX = 8192, ///< Flag to pass INT64_MIN/MAX through instead of rescaling, this avoids special cases for AV_NOPTS_VALUE
};
/**
@@ -70,6 +92,9 @@ int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const;
/**
* Rescale a 64-bit integer with specified rounding.
* A simple a*b/c isn't possible as it can overflow.
+ *
+ * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is
+ * INT64_MIN or INT64_MAX then a is passed through unchanged.
*/
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const;
@@ -80,6 +105,9 @@ int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
/**
* Rescale a 64-bit integer by 2 rational numbers with specified rounding.
+ *
+ * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is
+ * INT64_MIN or INT64_MAX then a is passed through unchanged.
*/
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,
enum AVRounding) av_const;
@@ -105,6 +133,31 @@ int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b);
int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod);
/**
+ * Rescale a timestamp while preserving known durations.
+ *
+ * @param in_ts Input timestamp
+ * @param in_tb Input timebase
+ * @param fs_tb Duration and *last timebase
+ * @param duration duration till the next call
+ * @param out_tb Output timebase
+ */
+int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb);
+
+/**
+ * Add a value to a timestamp.
+ *
+ * This function guarantees that when the same value is repeatly added that
+ * no accumulation of rounding errors occurs.
+ *
+ * @param ts Input timestamp
+ * @param ts_tb Input timestamp timebase
+ * @param inc value to add to ts
+ * @param inc_tb inc timebase
+ */
+int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc);
+
+
+ /**
* @}
*/
diff --git a/libavutil/md5.c b/libavutil/md5.c
index efb993e605..876bd557d4 100644
--- a/libavutil/md5.c
+++ b/libavutil/md5.c
@@ -13,20 +13,20 @@
* If you use gcc, then version 4.1 or later and -fomit-frame-pointer is
* strongly recommended.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -42,9 +42,7 @@ typedef struct AVMD5{
uint32_t ABCD[4];
} AVMD5;
-#if FF_API_CONTEXT_SIZE
const int av_md5_size = sizeof(AVMD5);
-#endif
struct AVMD5 *av_md5_alloc(void)
{
@@ -85,50 +83,56 @@ static const uint32_t T[64] = { // T[i]= fabs(sin(i+1)<<32)
a += T[i]; \
\
if (i < 32) { \
- if (i < 16) a += (d ^ (b & (c ^ d))) + X[ i & 15]; \
- else a += (c ^ (d & (c ^ b))) + X[(1 + 5*i) & 15]; \
+ if (i < 16) a += (d ^ (b & (c ^ d))) + X[ i & 15]; \
+ else a += ((d & b) | (~d & c)) + X[(1 + 5*i) & 15]; \
} else { \
- if (i < 48) a += (b ^ c ^ d) + X[(5 + 3*i) & 15]; \
- else a += (c ^ (b | ~d)) + X[( 7*i) & 15]; \
+ if (i < 48) a += (b ^ c ^ d) + X[(5 + 3*i) & 15]; \
+ else a += (c ^ (b | ~d)) + X[( 7*i) & 15]; \
} \
a = b + (a << t | a >> (32 - t)); \
} while (0)
-static void body(uint32_t ABCD[4], uint32_t X[16])
+static void body(uint32_t ABCD[4], uint32_t *src, int nblocks)
{
- int t;
int i av_unused;
- unsigned int a = ABCD[3];
- unsigned int b = ABCD[2];
- unsigned int c = ABCD[1];
- unsigned int d = ABCD[0];
+ int n;
+ uint32_t a, b, c, d, t, *X;
+
+ for (n = 0; n < nblocks; n++) {
+ a = ABCD[3];
+ b = ABCD[2];
+ c = ABCD[1];
+ d = ABCD[0];
+
+ X = src + n * 16;
#if HAVE_BIGENDIAN
- for (i = 0; i < 16; i++)
- X[i] = av_bswap32(X[i]);
+ for (i = 0; i < 16; i++)
+ X[i] = av_bswap32(X[i]);
#endif
#if CONFIG_SMALL
- for (i = 0; i < 64; i++) {
- CORE(i, a, b, c, d);
- t = d;
- d = c;
- c = b;
- b = a;
- a = t;
- }
+ for (i = 0; i < 64; i++) {
+ CORE(i, a, b, c, d);
+ t = d;
+ d = c;
+ c = b;
+ b = a;
+ a = t;
+ }
#else
#define CORE2(i) \
- CORE( i, a,b,c,d); CORE((i+1),d,a,b,c); \
- CORE((i+2),c,d,a,b); CORE((i+3),b,c,d,a)
+ CORE( i, a,b,c,d); CORE((i+1),d,a,b,c); \
+ CORE((i+2),c,d,a,b); CORE((i+3),b,c,d,a)
#define CORE4(i) CORE2(i); CORE2((i+4)); CORE2((i+8)); CORE2((i+12))
- CORE4(0); CORE4(16); CORE4(32); CORE4(48);
+ CORE4(0); CORE4(16); CORE4(32); CORE4(48);
#endif
- ABCD[0] += d;
- ABCD[1] += c;
- ABCD[2] += b;
- ABCD[3] += a;
+ ABCD[0] += d;
+ ABCD[1] += c;
+ ABCD[2] += b;
+ ABCD[3] += a;
+ }
}
void av_md5_init(AVMD5 *ctx)
@@ -141,20 +145,39 @@ void av_md5_init(AVMD5 *ctx)
ctx->ABCD[3] = 0x67452301;
}
-void av_md5_update(AVMD5 *ctx, const uint8_t *src, const int len)
+void av_md5_update(AVMD5 *ctx, const uint8_t *src, int len)
{
- int i, j;
+ const uint8_t *end;
+ int j;
j = ctx->len & 63;
ctx->len += len;
- for (i = 0; i < len; i++) {
- ctx->block[j++] = src[i];
- if (j == 64) {
- body(ctx->ABCD, (uint32_t *) ctx->block);
- j = 0;
+ if (j) {
+ int cnt = FFMIN(len, 64 - j);
+ memcpy(ctx->block + j, src, cnt);
+ src += cnt;
+ len -= cnt;
+ if (j + cnt < 64)
+ return;
+ body(ctx->ABCD, (uint32_t *)ctx->block, 1);
+ }
+
+ end = src + (len & ~63);
+ if (HAVE_BIGENDIAN || (!HAVE_FAST_UNALIGNED && ((intptr_t)src & 3))) {
+ while (src < end) {
+ memcpy(ctx->block, src, 64);
+ body(ctx->ABCD, (uint32_t *) ctx->block, 1);
+ src += 64;
}
+ } else {
+ int nblocks = len / 64;
+ body(ctx->ABCD, (uint32_t *)src, nblocks);
+ src = end;
}
+ len &= 63;
+ if (len > 0)
+ memcpy(ctx->block, src, len);
}
void av_md5_final(AVMD5 *ctx, uint8_t *dst)
@@ -195,7 +218,8 @@ static void print_md5(uint8_t *md5)
int main(void){
uint8_t md5val[16];
int i;
- uint8_t in[1000];
+ volatile uint8_t in[1000]; // volatile to workaround http://llvm.org/bugs/show_bug.cgi?id=20849
+ // FIXME remove volatile once it has been fixed and all fate clients are updated
for (i = 0; i < 1000; i++)
in[i] = i * i;
diff --git a/libavutil/md5.h b/libavutil/md5.h
index 29e4e7c2ba..79702c88c2 100644
--- a/libavutil/md5.h
+++ b/libavutil/md5.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,16 +32,46 @@
* @{
*/
-#if FF_API_CONTEXT_SIZE
-extern attribute_deprecated const int av_md5_size;
-#endif
+extern const int av_md5_size;
struct AVMD5;
+/**
+ * Allocate an AVMD5 context.
+ */
struct AVMD5 *av_md5_alloc(void);
+
+/**
+ * Initialize MD5 hashing.
+ *
+ * @param ctx pointer to the function context (of size av_md5_size)
+ */
void av_md5_init(struct AVMD5 *ctx);
-void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, const int len);
+
+/**
+ * Update hash value.
+ *
+ * @param ctx hash function context
+ * @param src input data to update hash with
+ * @param len input data length
+ */
+void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len);
+
+/**
+ * Finish hashing and output digest value.
+ *
+ * @param ctx hash function context
+ * @param dst buffer where output digest value is stored
+ */
void av_md5_final(struct AVMD5 *ctx, uint8_t *dst);
+
+/**
+ * Hash an array of data.
+ *
+ * @param dst The output buffer to write the digest into
+ * @param src The data to hash
+ * @param len The length of the data, in bytes
+ */
void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len);
/**
diff --git a/libavutil/mem.c b/libavutil/mem.c
index 15c28808c1..da291fb970 100644
--- a/libavutil/mem.c
+++ b/libavutil/mem.c
@@ -2,20 +2,20 @@
* default memory allocator for libavutil
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,6 +24,8 @@
* default memory allocator for libavutil
*/
+#define _XOPEN_SOURCE 600
+
#include "config.h"
#include <limits.h>
@@ -34,8 +36,10 @@
#include <malloc.h>
#endif
+#include "avassert.h"
#include "avutil.h"
#include "common.h"
+#include "dynarray.h"
#include "intreadwrite.h"
#include "mem.h"
@@ -55,9 +59,18 @@ void free(void *ptr);
#endif /* MALLOC_PREFIX */
-/* You can redefine av_malloc and av_free in your project to use your
- * memory allocator. You do not need to suppress this file because the
- * linker will do it automatically. */
+#define ALIGN (HAVE_AVX ? 32 : 16)
+
+/* NOTE: if you want to override these functions with your own
+ * implementations (not recommended) you have to link libav* as
+ * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags.
+ * Note that this will cost performance. */
+
+static size_t max_alloc_size= INT_MAX;
+
+void av_max_alloc(size_t max){
+ max_alloc_size = max;
+}
void *av_malloc(size_t size)
{
@@ -67,23 +80,28 @@ void *av_malloc(size_t size)
#endif
/* let's disallow possibly ambiguous cases */
- if (size > (INT_MAX - 32) || !size)
+ if (size > (max_alloc_size - 32))
return NULL;
#if CONFIG_MEMALIGN_HACK
- ptr = malloc(size + 32);
+ ptr = malloc(size + ALIGN);
if (!ptr)
return ptr;
- diff = ((-(long)ptr - 1) & 31) + 1;
+ diff = ((~(long)ptr)&(ALIGN - 1)) + 1;
ptr = (char *)ptr + diff;
((char *)ptr)[-1] = diff;
#elif HAVE_POSIX_MEMALIGN
- if (posix_memalign(&ptr, 32, size))
+ if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation
+ if (posix_memalign(&ptr, ALIGN, size))
ptr = NULL;
#elif HAVE_ALIGNED_MALLOC
- ptr = _aligned_malloc(size, 32);
+ ptr = _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
- ptr = memalign(32, size);
+#ifndef __DJGPP__
+ ptr = memalign(ALIGN, size);
+#else
+ ptr = memalign(size, ALIGN);
+#endif
/* Why 64?
* Indeed, we should align it:
* on 4 for 386
@@ -111,6 +129,14 @@ void *av_malloc(size_t size)
#else
ptr = malloc(size);
#endif
+ if(!ptr && !size) {
+ size = 1;
+ ptr= av_malloc(1);
+ }
+#if CONFIG_MEMORY_POISONING
+ if (ptr)
+ memset(ptr, FF_MEMORY_POISON, size);
+#endif
return ptr;
}
@@ -121,7 +147,7 @@ void *av_realloc(void *ptr, size_t size)
#endif
/* let's disallow possibly ambiguous cases */
- if (size > (INT_MAX - 16))
+ if (size > (max_alloc_size - 32))
return NULL;
#if CONFIG_MEMALIGN_HACK
@@ -129,14 +155,33 @@ void *av_realloc(void *ptr, size_t size)
if (!ptr)
return av_malloc(size);
diff = ((char *)ptr)[-1];
- return (char *)realloc((char *)ptr - diff, size + diff) + diff;
+ av_assert0(diff>0 && diff<=ALIGN);
+ ptr = realloc((char *)ptr - diff, size + diff);
+ if (ptr)
+ ptr = (char *)ptr + diff;
+ return ptr;
#elif HAVE_ALIGNED_MALLOC
- return _aligned_realloc(ptr, size, 32);
+ return _aligned_realloc(ptr, size + !size, ALIGN);
#else
- return realloc(ptr, size);
+ return realloc(ptr, size + !size);
#endif
}
+void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
+{
+ size_t size;
+ void *r;
+
+ if (av_size_mult(elsize, nelem, &size)) {
+ av_free(ptr);
+ return NULL;
+ }
+ r = av_realloc(ptr, size);
+ if (!r && size)
+ av_free(ptr);
+ return r;
+}
+
int av_reallocp(void *ptr, size_t size)
{
void *val;
@@ -169,29 +214,23 @@ int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
{
void *val;
- if (!size || nmemb >= INT_MAX / size)
- return AVERROR(ENOMEM);
- if (!nmemb) {
- av_freep(ptr);
- return 0;
- }
-
memcpy(&val, ptr, sizeof(val));
- val = av_realloc(val, nmemb * size);
- if (!val) {
- av_freep(ptr);
+ val = av_realloc_f(val, nmemb, size);
+ memcpy(ptr, &val, sizeof(val));
+ if (!val && nmemb && size)
return AVERROR(ENOMEM);
- }
- memcpy(ptr, &val, sizeof(val));
return 0;
}
void av_free(void *ptr)
{
#if CONFIG_MEMALIGN_HACK
- if (ptr)
- free((char *)ptr - ((char *)ptr)[-1]);
+ if (ptr) {
+ int v= ((char *)ptr)[-1];
+ av_assert0(v>0 && v<=ALIGN);
+ free((char *)ptr - v);
+ }
#elif HAVE_ALIGNED_MALLOC
_aligned_free(ptr);
#else
@@ -216,11 +255,18 @@ void *av_mallocz(size_t size)
return ptr;
}
+void *av_calloc(size_t nmemb, size_t size)
+{
+ if (size <= 0 || nmemb >= INT_MAX / size)
+ return NULL;
+ return av_mallocz(nmemb * size);
+}
+
char *av_strdup(const char *s)
{
char *ptr = NULL;
if (s) {
- int len = strlen(s) + 1;
+ size_t len = strlen(s) + 1;
ptr = av_realloc(NULL, len);
if (ptr)
memcpy(ptr, s, len);
@@ -248,6 +294,63 @@ char *av_strndup(const char *s, size_t len)
return ret;
}
+void *av_memdup(const void *p, size_t size)
+{
+ void *ptr = NULL;
+ if (p) {
+ ptr = av_malloc(size);
+ if (ptr)
+ memcpy(ptr, p, size);
+ }
+ return ptr;
+}
+
+int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
+{
+ void **tab;
+ memcpy(&tab, tab_ptr, sizeof(tab));
+
+ AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
+ tab[*nb_ptr] = elem;
+ memcpy(tab_ptr, &tab, sizeof(tab));
+ }, {
+ return AVERROR(ENOMEM);
+ });
+ return 0;
+}
+
+void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
+{
+ void **tab;
+ memcpy(&tab, tab_ptr, sizeof(tab));
+
+ AV_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, {
+ tab[*nb_ptr] = elem;
+ memcpy(tab_ptr, &tab, sizeof(tab));
+ }, {
+ *nb_ptr = 0;
+ av_freep(tab_ptr);
+ });
+}
+
+void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
+ const uint8_t *elem_data)
+{
+ uint8_t *tab_elem_data = NULL;
+
+ AV_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, {
+ tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size;
+ if (elem_data)
+ memcpy(tab_elem_data, elem_data, elem_size);
+ else if (CONFIG_MEMORY_POISONING)
+ memset(tab_elem_data, FF_MEMORY_POISON, elem_size);
+ }, {
+ av_freep(tab_ptr);
+ *nb_ptr = 0;
+ });
+ return tab_elem_data;
+}
+
static void fill16(uint8_t *dst, int len)
{
uint32_t v = AV_RN16(dst - 2);
@@ -391,15 +494,24 @@ void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
return ptr;
}
-void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
+static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc)
{
- void **p = ptr;
+ void *val;
+
if (min_size < *size)
- return;
+ return 0;
min_size = FFMAX(17 * min_size / 16 + 32, min_size);
- av_free(*p);
- *p = av_malloc(min_size);
- if (!*p)
+ av_freep(ptr);
+ val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size);
+ memcpy(ptr, &val, sizeof(val));
+ if (!val)
min_size = 0;
*size = min_size;
+ return 1;
+}
+
+void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
+{
+ ff_fast_malloc(ptr, size, min_size, 0);
}
+
diff --git a/libavutil/mem.h b/libavutil/mem.h
index 9f667c270b..2a1e36d69f 100644
--- a/libavutil/mem.h
+++ b/libavutil/mem.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,7 @@
#include <stdint.h>
#include "attributes.h"
+#include "error.h"
#include "avutil.h"
/**
@@ -38,7 +39,7 @@
*/
-#if defined(__ICC) && __ICC < 1200 || defined(__SUNPRO_C)
+#if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C)
#define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v
#define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v
#elif defined(__TI_COMPILER_VERSION__)
@@ -118,6 +119,16 @@ void *av_realloc(void *ptr, size_t size) av_alloc_size(2);
/**
* Allocate or reallocate a block of memory.
+ * This function does the same thing as av_realloc, except:
+ * - It takes two arguments and checks the result of the multiplication for
+ * integer overflow.
+ * - It frees the input block in case of failure, thus avoiding the memory
+ * leak with the classic "buf = realloc(buf); if (!buf) return -1;".
+ */
+void *av_realloc_f(void *ptr, size_t nelem, size_t elsize);
+
+/**
+ * Allocate or reallocate a block of memory.
* If *ptr is NULL and size > 0, allocate a new block. If
* size is zero, free the memory block pointed to by ptr.
* @param ptr Pointer to a pointer to a memory block already allocated
@@ -194,6 +205,18 @@ void av_free(void *ptr);
void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1);
/**
+ * Allocate a block of nmemb * size bytes with alignment suitable for all
+ * memory accesses (including vectors if available on the CPU) and
+ * zero all the bytes of the block.
+ * The allocation will fail if nmemb * size is greater than or equal
+ * to INT_MAX.
+ * @param nmemb
+ * @param size
+ * @return Pointer to the allocated block, NULL if it cannot be allocated.
+ */
+void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib;
+
+/**
* Allocate a block of size * nmemb bytes with av_mallocz().
* @param nmemb Number of elements
* @param size Size of the single element
@@ -228,18 +251,109 @@ char *av_strdup(const char *s) av_malloc_attrib;
char *av_strndup(const char *s, size_t len) av_malloc_attrib;
/**
+ * Duplicate the buffer p.
+ * @param p buffer to be duplicated
+ * @return Pointer to a newly allocated buffer containing a
+ * copy of p or NULL if the buffer cannot be allocated.
+ */
+void *av_memdup(const void *p, size_t size);
+
+/**
* Free a memory block which has been allocated with av_malloc(z)() or
* av_realloc() and set the pointer pointing to it to NULL.
* @param ptr Pointer to the pointer to the memory block which should
* be freed.
+ * @note passing a pointer to a NULL pointer is safe and leads to no action.
* @see av_free()
*/
void av_freep(void *ptr);
/**
+ * Add an element to a dynamic array.
+ *
+ * The array to grow is supposed to be an array of pointers to
+ * structures, and the element to add must be a pointer to an already
+ * allocated structure.
+ *
+ * The array is reallocated when its size reaches powers of 2.
+ * Therefore, the amortized cost of adding an element is constant.
+ *
+ * In case of success, the pointer to the array is updated in order to
+ * point to the new grown array, and the number pointed to by nb_ptr
+ * is incremented.
+ * In case of failure, the array is freed, *tab_ptr is set to NULL and
+ * *nb_ptr is set to 0.
+ *
+ * @param tab_ptr pointer to the array to grow
+ * @param nb_ptr pointer to the number of elements in the array
+ * @param elem element to add
+ * @see av_dynarray_add_nofree(), av_dynarray2_add()
+ */
+void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem);
+
+/**
+ * Add an element to a dynamic array.
+ *
+ * Function has the same functionality as av_dynarray_add(),
+ * but it doesn't free memory on fails. It returns error code
+ * instead and leave current buffer untouched.
+ *
+ * @param tab_ptr pointer to the array to grow
+ * @param nb_ptr pointer to the number of elements in the array
+ * @param elem element to add
+ * @return >=0 on success, negative otherwise.
+ * @see av_dynarray_add(), av_dynarray2_add()
+ */
+int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem);
+
+/**
+ * Add an element of size elem_size to a dynamic array.
+ *
+ * The array is reallocated when its number of elements reaches powers of 2.
+ * Therefore, the amortized cost of adding an element is constant.
+ *
+ * In case of success, the pointer to the array is updated in order to
+ * point to the new grown array, and the number pointed to by nb_ptr
+ * is incremented.
+ * In case of failure, the array is freed, *tab_ptr is set to NULL and
+ * *nb_ptr is set to 0.
+ *
+ * @param tab_ptr pointer to the array to grow
+ * @param nb_ptr pointer to the number of elements in the array
+ * @param elem_size size in bytes of the elements in the array
+ * @param elem_data pointer to the data of the element to add. If NULL, the space of
+ * the new added element is not filled.
+ * @return pointer to the data of the element to copy in the new allocated space.
+ * If NULL, the new allocated space is left uninitialized."
+ * @see av_dynarray_add(), av_dynarray_add_nofree()
+ */
+void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size,
+ const uint8_t *elem_data);
+
+/**
+ * Multiply two size_t values checking for overflow.
+ * @return 0 if success, AVERROR(EINVAL) if overflow.
+ */
+static inline int av_size_mult(size_t a, size_t b, size_t *r)
+{
+ size_t t = a * b;
+ /* Hack inspired from glibc: only try the division if nelem and elsize
+ * are both greater than sqrt(SIZE_MAX). */
+ if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b)
+ return AVERROR(EINVAL);
+ *r = t;
+ return 0;
+}
+
+/**
+ * Set the maximum size that may me allocated in one block.
+ */
+void av_max_alloc(size_t max);
+
+/**
* deliberately overlapping memcpy implementation
* @param dst destination buffer
- * @param back how many bytes back we start (the initial size of the overlapping window)
+ * @param back how many bytes back we start (the initial size of the overlapping window), must be > 0
* @param cnt number of bytes to copy, must be >= 0
*
* cnt > back is valid, this will copy the bytes we just copied,
diff --git a/libavutil/mips/Makefile b/libavutil/mips/Makefile
new file mode 100644
index 0000000000..dbfa5aa341
--- /dev/null
+++ b/libavutil/mips/Makefile
@@ -0,0 +1 @@
+OBJS += mips/float_dsp_mips.o
diff --git a/libavutil/mips/asmdefs.h b/libavutil/mips/asmdefs.h
new file mode 100644
index 0000000000..fdf82a0107
--- /dev/null
+++ b/libavutil/mips/asmdefs.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Imagination Technologies Ltd
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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
+ * MIPS assembly defines from sys/asm.h but rewritten for use with C inline
+ * assembly (rather than from within .s files).
+ */
+
+#ifndef AVUTIL_MIPS_ASMDEFS_H
+#define AVUTIL_MIPS_ASMDEFS_H
+
+#if defined(_ABI64) && _MIPS_SIM == _ABI64
+# define PTRSIZE " 8 "
+# define PTRLOG " 3 "
+# define PTR_ADDU "daddu "
+# define PTR_ADDIU "daddiu "
+# define PTR_SUBU "dsubu "
+# define PTR_L "ld "
+#else
+# define PTRSIZE " 4 "
+# define PTRLOG " 2 "
+# define PTR_ADDU "addu "
+# define PTR_ADDIU "addiu "
+# define PTR_SUBU "subu "
+# define PTR_L "lw "
+#endif
+
+#endif /* AVCODEC_MIPS_ASMDEFS_H */
diff --git a/libavutil/mips/float_dsp_mips.c b/libavutil/mips/float_dsp_mips.c
new file mode 100644
index 0000000000..b3a812ceeb
--- /dev/null
+++ b/libavutil/mips/float_dsp_mips.c
@@ -0,0 +1,352 @@
+/*
+ * 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: Branimir Vasic (bvasic@mips.com)
+ * Author: Zoran Lukic (zoranl@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: libavutil/float_dsp.c
+ */
+
+#include "config.h"
+#include "libavutil/float_dsp.h"
+#include "libavutil/mips/asmdefs.h"
+
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+static void vector_fmul_mips(float *dst, const float *src0, const float *src1,
+ int len)
+{
+ int i;
+
+ if (len & 3) {
+ for (i = 0; i < len; i++)
+ dst[i] = src0[i] * src1[i];
+ } else {
+ float *d = (float *)dst;
+ float *d_end = d + len;
+ float *s0 = (float *)src0;
+ float *s1 = (float *)src1;
+
+ float src0_0, src0_1, src0_2, src0_3;
+ float src1_0, src1_1, src1_2, src1_3;
+
+ __asm__ volatile (
+ "1: \n\t"
+ "lwc1 %[src0_0], 0(%[s0]) \n\t"
+ "lwc1 %[src1_0], 0(%[s1]) \n\t"
+ "lwc1 %[src0_1], 4(%[s0]) \n\t"
+ "lwc1 %[src1_1], 4(%[s1]) \n\t"
+ "lwc1 %[src0_2], 8(%[s0]) \n\t"
+ "lwc1 %[src1_2], 8(%[s1]) \n\t"
+ "lwc1 %[src0_3], 12(%[s0]) \n\t"
+ "lwc1 %[src1_3], 12(%[s1]) \n\t"
+ "mul.s %[src0_0], %[src0_0], %[src1_0] \n\t"
+ "mul.s %[src0_1], %[src0_1], %[src1_1] \n\t"
+ "mul.s %[src0_2], %[src0_2], %[src1_2] \n\t"
+ "mul.s %[src0_3], %[src0_3], %[src1_3] \n\t"
+ "swc1 %[src0_0], 0(%[d]) \n\t"
+ "swc1 %[src0_1], 4(%[d]) \n\t"
+ "swc1 %[src0_2], 8(%[d]) \n\t"
+ "swc1 %[src0_3], 12(%[d]) \n\t"
+ PTR_ADDIU "%[s0], %[s0], 16 \n\t"
+ PTR_ADDIU "%[s1], %[s1], 16 \n\t"
+ PTR_ADDIU "%[d], %[d], 16 \n\t"
+ "bne %[d], %[d_end], 1b \n\t"
+
+ : [src0_0]"=&f"(src0_0), [src0_1]"=&f"(src0_1),
+ [src0_2]"=&f"(src0_2), [src0_3]"=&f"(src0_3),
+ [src1_0]"=&f"(src1_0), [src1_1]"=&f"(src1_1),
+ [src1_2]"=&f"(src1_2), [src1_3]"=&f"(src1_3),
+ [d]"+r"(d), [s0]"+r"(s0), [s1]"+r"(s1)
+ : [d_end]"r"(d_end)
+ : "memory"
+ );
+ }
+}
+
+static void vector_fmul_scalar_mips(float *dst, const float *src, float mul,
+ int len)
+{
+ float temp0, temp1, temp2, temp3;
+ float *local_src = (float*)src;
+ float *end = local_src + len;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "lwc1 %[temp0], 0(%[src]) \n\t"
+ "lwc1 %[temp1], 4(%[src]) \n\t"
+ "lwc1 %[temp2], 8(%[src]) \n\t"
+ "lwc1 %[temp3], 12(%[src]) \n\t"
+ PTR_ADDIU "%[dst], %[dst], 16 \n\t"
+ "mul.s %[temp0], %[temp0], %[mul] \n\t"
+ "mul.s %[temp1], %[temp1], %[mul] \n\t"
+ "mul.s %[temp2], %[temp2], %[mul] \n\t"
+ "mul.s %[temp3], %[temp3], %[mul] \n\t"
+ PTR_ADDIU "%[src], %[src], 16 \n\t"
+ "swc1 %[temp0], -16(%[dst]) \n\t"
+ "swc1 %[temp1], -12(%[dst]) \n\t"
+ "swc1 %[temp2], -8(%[dst]) \n\t"
+ "bne %[src], %[end], 1b \n\t"
+ " swc1 %[temp3], -4(%[dst]) \n\t"
+ ".set pop \n\t"
+
+ : [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),
+ [temp2]"=&f"(temp2), [temp3]"=&f"(temp3),
+ [dst]"+r"(dst), [src]"+r"(local_src)
+ : [end]"r"(end), [mul]"f"(mul)
+ : "memory"
+ );
+}
+
+static void vector_fmul_window_mips(float *dst, const float *src0,
+ const float *src1, const float *win, int len)
+{
+ float * dst_j, *win_j, *src0_i, *src1_j, *dst_i, *win_i;
+ float temp, temp1, temp2, temp3;
+ float s0, s01, s1, s11;
+ float wi, wi1, wi2, wi3;
+ float wj, wj1, wj2, wj3;
+ const float * lp_end = win + len;
+
+ win_i = (float *)win;
+ win_j = (float *)(win + 2 * len -1);
+ src1_j = (float *)(src1 + len - 1);
+ src0_i = (float *)src0;
+ dst_i = (float *)dst;
+ dst_j = (float *)(dst + 2 * len -1);
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "1:"
+ "lwc1 %[s1], 0(%[src1_j]) \n\t"
+ "lwc1 %[wi], 0(%[win_i]) \n\t"
+ "lwc1 %[wj], 0(%[win_j]) \n\t"
+ "lwc1 %[s11], -4(%[src1_j]) \n\t"
+ "lwc1 %[wi1], 4(%[win_i]) \n\t"
+ "lwc1 %[wj1], -4(%[win_j]) \n\t"
+ "lwc1 %[s0], 0(%[src0_i]) \n\t"
+ "lwc1 %[s01], 4(%[src0_i]) \n\t"
+ "mul.s %[temp], %[s1], %[wi] \n\t"
+ "mul.s %[temp1], %[s1], %[wj] \n\t"
+ "mul.s %[temp2], %[s11], %[wi1] \n\t"
+ "mul.s %[temp3], %[s11], %[wj1] \n\t"
+ "lwc1 %[s1], -8(%[src1_j]) \n\t"
+ "lwc1 %[wi2], 8(%[win_i]) \n\t"
+ "lwc1 %[wj2], -8(%[win_j]) \n\t"
+ "lwc1 %[s11], -12(%[src1_j]) \n\t"
+ "msub.s %[temp], %[temp], %[s0], %[wj] \n\t"
+ "madd.s %[temp1], %[temp1], %[s0], %[wi] \n\t"
+ "msub.s %[temp2], %[temp2], %[s01], %[wj1] \n\t"
+ "madd.s %[temp3], %[temp3], %[s01], %[wi1] \n\t"
+ "lwc1 %[wi3], 12(%[win_i]) \n\t"
+ "lwc1 %[wj3], -12(%[win_j]) \n\t"
+ "lwc1 %[s0], 8(%[src0_i]) \n\t"
+ "lwc1 %[s01], 12(%[src0_i]) \n\t"
+ PTR_ADDIU "%[src1_j],-16 \n\t"
+ PTR_ADDIU "%[win_i],16 \n\t"
+ PTR_ADDIU "%[win_j],-16 \n\t"
+ PTR_ADDIU "%[src0_i],16 \n\t"
+ "swc1 %[temp], 0(%[dst_i]) \n\t" /* dst[i] = s0*wj - s1*wi; */
+ "swc1 %[temp1], 0(%[dst_j]) \n\t" /* dst[j] = s0*wi + s1*wj; */
+ "swc1 %[temp2], 4(%[dst_i]) \n\t" /* dst[i+1] = s01*wj1 - s11*wi1; */
+ "swc1 %[temp3], -4(%[dst_j]) \n\t" /* dst[j-1] = s01*wi1 + s11*wj1; */
+ "mul.s %[temp], %[s1], %[wi2] \n\t"
+ "mul.s %[temp1], %[s1], %[wj2] \n\t"
+ "mul.s %[temp2], %[s11], %[wi3] \n\t"
+ "mul.s %[temp3], %[s11], %[wj3] \n\t"
+ "msub.s %[temp], %[temp], %[s0], %[wj2] \n\t"
+ "madd.s %[temp1], %[temp1], %[s0], %[wi2] \n\t"
+ "msub.s %[temp2], %[temp2], %[s01], %[wj3] \n\t"
+ "madd.s %[temp3], %[temp3], %[s01], %[wi3] \n\t"
+ "swc1 %[temp], 8(%[dst_i]) \n\t" /* dst[i+2] = s0*wj2 - s1*wi2; */
+ "swc1 %[temp1], -8(%[dst_j]) \n\t" /* dst[j-2] = s0*wi2 + s1*wj2; */
+ "swc1 %[temp2], 12(%[dst_i]) \n\t" /* dst[i+2] = s01*wj3 - s11*wi3; */
+ "swc1 %[temp3], -12(%[dst_j]) \n\t" /* dst[j-3] = s01*wi3 + s11*wj3; */
+ PTR_ADDIU "%[dst_i],16 \n\t"
+ PTR_ADDIU "%[dst_j],-16 \n\t"
+ "bne %[win_i], %[lp_end], 1b \n\t"
+ : [temp]"=&f"(temp), [temp1]"=&f"(temp1), [temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [src0_i]"+r"(src0_i), [win_i]"+r"(win_i),
+ [src1_j]"+r"(src1_j), [win_j]"+r"(win_j), [dst_i]"+r"(dst_i),
+ [dst_j]"+r"(dst_j), [s0] "=&f"(s0), [s01]"=&f"(s01), [s1] "=&f"(s1),
+ [s11]"=&f"(s11), [wi] "=&f"(wi), [wj] "=&f"(wj), [wi2]"=&f"(wi2),
+ [wj2]"=&f"(wj2), [wi3]"=&f"(wi3), [wj3]"=&f"(wj3), [wi1]"=&f"(wi1),
+ [wj1]"=&f"(wj1)
+ : [lp_end]"r"(lp_end)
+ : "memory"
+ );
+}
+
+static void butterflies_float_mips(float *av_restrict v1, float *av_restrict v2,
+ int len)
+{
+ float temp0, temp1, temp2, temp3, temp4;
+ float temp5, temp6, temp7, temp8, temp9;
+ float temp10, temp11, temp12, temp13, temp14, temp15;
+ int pom;
+ pom = (len >> 2)-1;
+
+ /* loop unrolled 4 times */
+ __asm__ volatile (
+ "lwc1 %[temp0], 0(%[v1]) \n\t"
+ "lwc1 %[temp1], 4(%[v1]) \n\t"
+ "lwc1 %[temp2], 8(%[v1]) \n\t"
+ "lwc1 %[temp3], 12(%[v1]) \n\t"
+ "lwc1 %[temp4], 0(%[v2]) \n\t"
+ "lwc1 %[temp5], 4(%[v2]) \n\t"
+ "lwc1 %[temp6], 8(%[v2]) \n\t"
+ "lwc1 %[temp7], 12(%[v2]) \n\t"
+ "beq %[pom], $zero, 2f \n\t"
+ "1: \n\t"
+ "sub.s %[temp8], %[temp0], %[temp4] \n\t"
+ "add.s %[temp9], %[temp0], %[temp4] \n\t"
+ "sub.s %[temp10], %[temp1], %[temp5] \n\t"
+ "add.s %[temp11], %[temp1], %[temp5] \n\t"
+ "sub.s %[temp12], %[temp2], %[temp6] \n\t"
+ "add.s %[temp13], %[temp2], %[temp6] \n\t"
+ "sub.s %[temp14], %[temp3], %[temp7] \n\t"
+ "add.s %[temp15], %[temp3], %[temp7] \n\t"
+ PTR_ADDIU "%[v1], %[v1], 16 \n\t"
+ PTR_ADDIU "%[v2], %[v2], 16 \n\t"
+ "addiu %[pom], %[pom], -1 \n\t"
+ "lwc1 %[temp0], 0(%[v1]) \n\t"
+ "lwc1 %[temp1], 4(%[v1]) \n\t"
+ "lwc1 %[temp2], 8(%[v1]) \n\t"
+ "lwc1 %[temp3], 12(%[v1]) \n\t"
+ "lwc1 %[temp4], 0(%[v2]) \n\t"
+ "lwc1 %[temp5], 4(%[v2]) \n\t"
+ "lwc1 %[temp6], 8(%[v2]) \n\t"
+ "lwc1 %[temp7], 12(%[v2]) \n\t"
+ "swc1 %[temp9], -16(%[v1]) \n\t"
+ "swc1 %[temp8], -16(%[v2]) \n\t"
+ "swc1 %[temp11], -12(%[v1]) \n\t"
+ "swc1 %[temp10], -12(%[v2]) \n\t"
+ "swc1 %[temp13], -8(%[v1]) \n\t"
+ "swc1 %[temp12], -8(%[v2]) \n\t"
+ "swc1 %[temp15], -4(%[v1]) \n\t"
+ "swc1 %[temp14], -4(%[v2]) \n\t"
+ "bgtz %[pom], 1b \n\t"
+ "2: \n\t"
+ "sub.s %[temp8], %[temp0], %[temp4] \n\t"
+ "add.s %[temp9], %[temp0], %[temp4] \n\t"
+ "sub.s %[temp10], %[temp1], %[temp5] \n\t"
+ "add.s %[temp11], %[temp1], %[temp5] \n\t"
+ "sub.s %[temp12], %[temp2], %[temp6] \n\t"
+ "add.s %[temp13], %[temp2], %[temp6] \n\t"
+ "sub.s %[temp14], %[temp3], %[temp7] \n\t"
+ "add.s %[temp15], %[temp3], %[temp7] \n\t"
+ "swc1 %[temp9], 0(%[v1]) \n\t"
+ "swc1 %[temp8], 0(%[v2]) \n\t"
+ "swc1 %[temp11], 4(%[v1]) \n\t"
+ "swc1 %[temp10], 4(%[v2]) \n\t"
+ "swc1 %[temp13], 8(%[v1]) \n\t"
+ "swc1 %[temp12], 8(%[v2]) \n\t"
+ "swc1 %[temp15], 12(%[v1]) \n\t"
+ "swc1 %[temp14], 12(%[v2]) \n\t"
+
+ : [v1]"+r"(v1), [v2]"+r"(v2), [pom]"+r"(pom), [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)
+ :
+ : "memory"
+ );
+}
+
+static void vector_fmul_reverse_mips(float *dst, const float *src0, const float *src1, int len){
+ int i;
+ float temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ src1 += len-1;
+
+ for(i=0; i<(len>>2); i++)
+ {
+ /* loop unrolled 4 times */
+ __asm__ volatile(
+ "lwc1 %[temp0], 0(%[src0]) \n\t"
+ "lwc1 %[temp1], 0(%[src1]) \n\t"
+ "lwc1 %[temp2], 4(%[src0]) \n\t"
+ "lwc1 %[temp3], -4(%[src1]) \n\t"
+ "lwc1 %[temp4], 8(%[src0]) \n\t"
+ "lwc1 %[temp5], -8(%[src1]) \n\t"
+ "lwc1 %[temp6], 12(%[src0]) \n\t"
+ "lwc1 %[temp7], -12(%[src1]) \n\t"
+ "mul.s %[temp0], %[temp1], %[temp0] \n\t"
+ "mul.s %[temp2], %[temp3], %[temp2] \n\t"
+ "mul.s %[temp4], %[temp5], %[temp4] \n\t"
+ "mul.s %[temp6], %[temp7], %[temp6] \n\t"
+ PTR_ADDIU "%[src0], %[src0], 16 \n\t"
+ PTR_ADDIU "%[src1], %[src1], -16 \n\t"
+ PTR_ADDIU "%[dst], %[dst], 16 \n\t"
+ "swc1 %[temp0], -16(%[dst]) \n\t"
+ "swc1 %[temp2], -12(%[dst]) \n\t"
+ "swc1 %[temp4], -8(%[dst]) \n\t"
+ "swc1 %[temp6], -4(%[dst]) \n\t"
+
+ : [dst]"+r"(dst), [src0]"+r"(src0), [src1]"+r"(src1),
+ [temp0]"=&f"(temp0), [temp1]"=&f"(temp1),[temp2]"=&f"(temp2),
+ [temp3]"=&f"(temp3), [temp4]"=&f"(temp4), [temp5]"=&f"(temp5),
+ [temp6]"=&f"(temp6), [temp7]"=&f"(temp7)
+ :
+ : "memory"
+ );
+ }
+}
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+
+void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp) {
+#if HAVE_INLINE_ASM && HAVE_MIPSFPU
+ fdsp->vector_fmul = vector_fmul_mips;
+ fdsp->vector_fmul_scalar = vector_fmul_scalar_mips;
+ fdsp->vector_fmul_window = vector_fmul_window_mips;
+ fdsp->butterflies_float = butterflies_float_mips;
+ fdsp->vector_fmul_reverse = vector_fmul_reverse_mips;
+#endif /* HAVE_INLINE_ASM && HAVE_MIPSFPU */
+}
diff --git a/libavutil/mips/generic_macros_msa.h b/libavutil/mips/generic_macros_msa.h
new file mode 100644
index 0000000000..48dc78e1b0
--- /dev/null
+++ b/libavutil/mips/generic_macros_msa.h
@@ -0,0 +1,1426 @@
+/*
+ * 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
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_MIPS_GENERIC_MACROS_MSA_H
+#define AVUTIL_MIPS_GENERIC_MACROS_MSA_H
+
+#include <stdint.h>
+#include <msa.h>
+
+#define LOAD_UB(psrc) \
+( { \
+ v16u8 out_m; \
+ out_m = *((v16u8 *) (psrc)); \
+ out_m; \
+} )
+
+#define LOAD_SB(psrc) \
+( { \
+ v16i8 out_m; \
+ out_m = *((v16i8 *) (psrc)); \
+ out_m; \
+} )
+
+#define LOAD_UH(psrc) *((const v8u16 *)(psrc))
+
+#define LOAD_SH(psrc) \
+( { \
+ v8i16 out_m; \
+ out_m = *((v8i16 *) (psrc)); \
+ out_m; \
+} )
+
+#define LOAD_SW(psrc) *((const v4i32 *)(psrc))
+
+#define STORE_UB(vec, pdest) *((v16u8 *)(pdest)) = (vec)
+#define STORE_SB(vec, pdest) *((v16i8 *)(pdest)) = (vec)
+
+#define STORE_SH(vec, pdest) \
+{ \
+ *((v8i16 *) (pdest)) = (vec); \
+}
+
+#define STORE_SW(vec, pdest) \
+{ \
+ *((v4i32 *) (pdest)) = (vec); \
+}
+
+#if (__mips_isa_rev >= 6)
+ #define LOAD_WORD(psrc) \
+ ( { \
+ uint8_t *src_m = (uint8_t *) (psrc); \
+ uint32_t val_m; \
+ \
+ __asm__ volatile ( \
+ "lw %[val_m], %[src_m] \n\t" \
+ \
+ : [val_m] "=r" (val_m) \
+ : [src_m] "m" (*src_m) \
+ ); \
+ \
+ val_m; \
+ } )
+
+ #if (__mips == 64)
+ #define LOAD_DWORD(psrc) \
+ ( { \
+ uint8_t *src_m = (uint8_t *) (psrc); \
+ uint64_t val_m = 0; \
+ \
+ __asm__ volatile ( \
+ "ld %[val_m], %[src_m] \n\t" \
+ \
+ : [val_m] "=r" (val_m) \
+ : [src_m] "m" (*src_m) \
+ ); \
+ \
+ val_m; \
+ } )
+ #else
+ #define LOAD_DWORD(psrc) \
+ ( { \
+ uint8_t *src1_m = (uint8_t *) (psrc); \
+ uint8_t *src2_m = ((uint8_t *) (psrc)) + 4; \
+ uint32_t val0_m, val1_m; \
+ uint64_t genval_m = 0; \
+ \
+ __asm__ volatile ( \
+ "lw %[val0_m], %[src1_m] \n\t" \
+ \
+ : [val0_m] "=r" (val0_m) \
+ : [src1_m] "m" (*src1_m) \
+ ); \
+ \
+ __asm__ volatile ( \
+ "lw %[val1_m], %[src2_m] \n\t" \
+ \
+ : [val1_m] "=r" (val1_m) \
+ : [src2_m] "m" (*src2_m) \
+ ); \
+ \
+ genval_m = (uint64_t) (val1_m); \
+ genval_m = (uint64_t) ((genval_m << 32) & 0xFFFFFFFF00000000); \
+ genval_m = (uint64_t) (genval_m | (uint64_t) val0_m); \
+ \
+ genval_m; \
+ } )
+ #endif
+
+ #define STORE_WORD(pdst, val) \
+ { \
+ uint8_t *dst_ptr_m = (uint8_t *) (pdst); \
+ uint32_t val_m = (val); \
+ \
+ __asm__ volatile ( \
+ "sw %[val_m], %[dst_ptr_m] \n\t" \
+ \
+ : [dst_ptr_m] "=m" (*dst_ptr_m) \
+ : [val_m] "r" (val_m) \
+ ); \
+ }
+
+ #define STORE_DWORD(pdst, val) \
+ { \
+ uint8_t *dst_ptr_m = (uint8_t *) (pdst); \
+ uint64_t val_m = (val); \
+ \
+ __asm__ volatile ( \
+ "sd %[val_m], %[dst_ptr_m] \n\t" \
+ \
+ : [dst_ptr_m] "=m" (*dst_ptr_m) \
+ : [val_m] "r" (val_m) \
+ ); \
+ }
+ #define STORE_HWORD(pdst, val) \
+ { \
+ uint8_t *dst_ptr_m = (uint8_t *) (pdst); \
+ uint16_t val_m = (val); \
+ \
+ __asm__ volatile ( \
+ "sh %[val_m], %[dst_ptr_m] \n\t" \
+ \
+ : [dst_ptr_m] "=m" (*dst_ptr_m) \
+ : [val_m] "r" (val_m) \
+ ); \
+ }
+
+#else
+ #define LOAD_WORD(psrc) \
+ ( { \
+ uint8_t *src_m = (uint8_t *) (psrc); \
+ uint32_t val_m; \
+ \
+ __asm__ volatile ( \
+ "ulw %[val_m], %[src_m] \n\t" \
+ \
+ : [val_m] "=r" (val_m) \
+ : [src_m] "m" (*src_m) \
+ ); \
+ \
+ val_m; \
+ } )
+
+ #if (__mips == 64)
+ #define LOAD_DWORD(psrc) \
+ ( { \
+ uint8_t *src_m = (uint8_t *) (psrc); \
+ uint64_t val_m = 0; \
+ \
+ __asm__ volatile ( \
+ "uld %[val_m], %[src_m] \n\t" \
+ \
+ : [val_m] "=r" (val_m) \
+ : [src_m] "m" (*src_m) \
+ ); \
+ \
+ val_m; \
+ } )
+ #else
+ #define LOAD_DWORD(psrc) \
+ ( { \
+ uint8_t *src1_m = (uint8_t *) (psrc); \
+ uint8_t *src2_m = ((uint8_t *) (psrc)) + 4; \
+ uint32_t val0_m, val1_m; \
+ uint64_t genval_m = 0; \
+ \
+ __asm__ volatile ( \
+ "ulw %[val0_m], %[src1_m] \n\t" \
+ \
+ : [val0_m] "=r" (val0_m) \
+ : [src1_m] "m" (*src1_m) \
+ ); \
+ \
+ __asm__ volatile ( \
+ "ulw %[val1_m], %[src2_m] \n\t" \
+ \
+ : [val1_m] "=r" (val1_m) \
+ : [src2_m] "m" (*src2_m) \
+ ); \
+ \
+ genval_m = (uint64_t) (val1_m); \
+ genval_m = (uint64_t) ((genval_m << 32) & 0xFFFFFFFF00000000); \
+ genval_m = (uint64_t) (genval_m | (uint64_t) val0_m); \
+ \
+ genval_m; \
+ } )
+ #endif
+
+ #define STORE_WORD(pdst, val) \
+ { \
+ uint8_t *dst_ptr_m = (uint8_t *) (pdst); \
+ uint32_t val_m = (val); \
+ \
+ __asm__ volatile ( \
+ "usw %[val_m], %[dst_ptr_m] \n\t" \
+ \
+ : [dst_ptr_m] "=m" (*dst_ptr_m) \
+ : [val_m] "r" (val_m) \
+ ); \
+ }
+
+ #define STORE_DWORD(pdst, val) \
+ { \
+ uint8_t *dst1_m = (uint8_t *) (pdst); \
+ uint8_t *dst2_m = ((uint8_t *) (pdst)) + 4; \
+ uint32_t val0_m, val1_m; \
+ \
+ val0_m = (uint32_t) ((val) & 0x00000000FFFFFFFF); \
+ val1_m = (uint32_t) (((val) >> 32) & 0x00000000FFFFFFFF); \
+ \
+ __asm__ volatile ( \
+ "usw %[val0_m], %[dst1_m] \n\t" \
+ "usw %[val1_m], %[dst2_m] \n\t" \
+ \
+ : [dst1_m] "=m" (*dst1_m), [dst2_m] "=m" (*dst2_m) \
+ : [val0_m] "r" (val0_m), [val1_m] "r" (val1_m) \
+ ); \
+ }
+
+ #define STORE_HWORD(pdst, val) \
+ { \
+ uint8_t *dst_ptr_m = (uint8_t *) (pdst); \
+ uint16_t val_m = (val); \
+ \
+ __asm__ volatile ( \
+ "ush %[val_m], %[dst_ptr_m] \n\t" \
+ \
+ : [dst_ptr_m] "=m" (*dst_ptr_m) \
+ : [val_m] "r" (val_m) \
+ ); \
+ }
+
+#endif
+
+#define LOAD_4WORDS_WITH_STRIDE(psrc, src_stride, \
+ src0, src1, src2, src3) \
+{ \
+ src0 = LOAD_WORD(psrc + 0 * src_stride); \
+ src1 = LOAD_WORD(psrc + 1 * src_stride); \
+ src2 = LOAD_WORD(psrc + 2 * src_stride); \
+ src3 = LOAD_WORD(psrc + 3 * src_stride); \
+}
+
+#define LOAD_2VECS_UB(psrc, stride, \
+ val0, val1) \
+{ \
+ val0 = LOAD_UB(psrc + 0 * stride); \
+ val1 = LOAD_UB(psrc + 1 * stride); \
+}
+
+#define LOAD_2VECS_SB(psrc, stride, \
+ val0, val1) \
+{ \
+ val0 = LOAD_SB(psrc + 0 * stride); \
+ val1 = LOAD_SB(psrc + 1 * stride); \
+}
+
+#define LOAD_3VECS_UB(psrc, stride, \
+ val0, val1, val2) \
+{ \
+ val0 = LOAD_UB(psrc + 0 * stride); \
+ val1 = LOAD_UB(psrc + 1 * stride); \
+ val2 = LOAD_UB(psrc + 2 * stride); \
+}
+
+#define LOAD_3VECS_SB(psrc, stride, \
+ val0, val1, val2) \
+{ \
+ val0 = LOAD_SB(psrc + 0 * stride); \
+ val1 = LOAD_SB(psrc + 1 * stride); \
+ val2 = LOAD_SB(psrc + 2 * stride); \
+}
+
+#define LOAD_4VECS_UB(psrc, stride, \
+ val0, val1, val2, val3) \
+{ \
+ val0 = LOAD_UB(psrc + 0 * stride); \
+ val1 = LOAD_UB(psrc + 1 * stride); \
+ val2 = LOAD_UB(psrc + 2 * stride); \
+ val3 = LOAD_UB(psrc + 3 * stride); \
+}
+
+#define LOAD_4VECS_SB(psrc, stride, \
+ val0, val1, val2, val3) \
+{ \
+ val0 = LOAD_SB(psrc + 0 * stride); \
+ val1 = LOAD_SB(psrc + 1 * stride); \
+ val2 = LOAD_SB(psrc + 2 * stride); \
+ val3 = LOAD_SB(psrc + 3 * stride); \
+}
+
+#define LOAD_5VECS_UB(psrc, stride, \
+ out0, out1, out2, out3, out4) \
+{ \
+ LOAD_4VECS_UB((psrc), (stride), \
+ (out0), (out1), (out2), (out3)); \
+ out4 = LOAD_UB(psrc + 4 * stride); \
+}
+
+#define LOAD_5VECS_SB(psrc, stride, \
+ out0, out1, out2, out3, out4) \
+{ \
+ LOAD_4VECS_SB((psrc), (stride), \
+ (out0), (out1), (out2), (out3)); \
+ out4 = LOAD_SB(psrc + 4 * stride); \
+}
+
+#define LOAD_6VECS_SB(psrc, stride, \
+ out0, out1, out2, out3, out4, out5) \
+{ \
+ LOAD_4VECS_SB((psrc), (stride), \
+ (out0), (out1), (out2), (out3)); \
+ LOAD_2VECS_SB((psrc + 4 * stride), (stride), \
+ (out4), (out5)); \
+}
+
+#define LOAD_7VECS_UB(psrc, stride, \
+ val0, val1, val2, val3, \
+ val4, val5, val6) \
+{ \
+ val0 = LOAD_UB((psrc) + 0 * (stride)); \
+ val1 = LOAD_UB((psrc) + 1 * (stride)); \
+ val2 = LOAD_UB((psrc) + 2 * (stride)); \
+ val3 = LOAD_UB((psrc) + 3 * (stride)); \
+ val4 = LOAD_UB((psrc) + 4 * (stride)); \
+ val5 = LOAD_UB((psrc) + 5 * (stride)); \
+ val6 = LOAD_UB((psrc) + 6 * (stride)); \
+}
+
+#define LOAD_7VECS_SB(psrc, stride, \
+ val0, val1, val2, val3, \
+ val4, val5, val6) \
+{ \
+ val0 = LOAD_SB((psrc) + 0 * (stride)); \
+ val1 = LOAD_SB((psrc) + 1 * (stride)); \
+ val2 = LOAD_SB((psrc) + 2 * (stride)); \
+ val3 = LOAD_SB((psrc) + 3 * (stride)); \
+ val4 = LOAD_SB((psrc) + 4 * (stride)); \
+ val5 = LOAD_SB((psrc) + 5 * (stride)); \
+ val6 = LOAD_SB((psrc) + 6 * (stride)); \
+}
+
+#define LOAD_8VECS_UB(psrc, stride, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ LOAD_4VECS_UB((psrc), (stride), \
+ (out0), (out1), (out2), (out3)); \
+ LOAD_4VECS_UB((psrc + 4 * stride), (stride), \
+ (out4), (out5), (out6), (out7)); \
+}
+
+#define LOAD_8VECS_SB(psrc, stride, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ LOAD_4VECS_SB((psrc), (stride), \
+ (out0), (out1), (out2), (out3)); \
+ LOAD_4VECS_SB((psrc + 4 * stride), (stride), \
+ (out4), (out5), (out6), (out7)); \
+}
+
+#define LOAD_2VECS_UH(psrc, stride, \
+ val0, val1) \
+{ \
+ val0 = LOAD_UH((psrc) + 0 * (stride)); \
+ val1 = LOAD_UH((psrc) + 1 * (stride)); \
+}
+
+#define LOAD_2VECS_SH(psrc, stride, \
+ val0, val1) \
+{ \
+ val0 = LOAD_SH((psrc) + 0 * (stride)); \
+ val1 = LOAD_SH((psrc) + 1 * (stride)); \
+}
+
+#define LOAD_4VECS_UH(psrc, stride, \
+ val0, val1, val2, val3) \
+{ \
+ LOAD_2VECS_UH((psrc), (stride), val0, val1); \
+ LOAD_2VECS_UH((psrc + 2 * stride), (stride), val2, val3); \
+}
+
+#define LOAD_4VECS_SH(psrc, stride, \
+ val0, val1, val2, val3) \
+{ \
+ LOAD_2VECS_SH((psrc), (stride), val0, val1); \
+ LOAD_2VECS_SH((psrc + 2 * stride), (stride), val2, val3); \
+}
+
+#define LOAD_6VECS_SH(psrc, stride, \
+ val0, val1, val2, val3, val4, val5) \
+{ \
+ LOAD_2VECS_SH((psrc), (stride), val0, val1); \
+ LOAD_2VECS_SH((psrc + 2 * stride), (stride), val2, val3); \
+ LOAD_2VECS_SH((psrc + 4 * stride), (stride), val4, val5); \
+}
+
+#define LOAD_8VECS_UH(psrc, stride, \
+ val0, val1, val2, val3, \
+ val4, val5, val6, val7) \
+{ \
+ LOAD_4VECS_UH((psrc), (stride), \
+ val0, val1, val2, val3); \
+ LOAD_4VECS_UH((psrc + 4 * stride), (stride), \
+ val4, val5, val6, val7); \
+}
+
+#define LOAD_8VECS_SH(psrc, stride, \
+ val0, val1, val2, val3, \
+ val4, val5, val6, val7) \
+{ \
+ LOAD_4VECS_SH((psrc), (stride), \
+ val0, val1, val2, val3); \
+ LOAD_4VECS_SH((psrc + 4 * stride), (stride), \
+ val4, val5, val6, val7); \
+}
+
+#define LOAD_16VECS_SH(psrc, stride, \
+ val0, val1, val2, val3, \
+ val4, val5, val6, val7, \
+ val8, val9, val10, val11, \
+ val12, val13, val14, val15) \
+{ \
+ LOAD_8VECS_SH((psrc), (stride), \
+ val0, val1, val2, val3, \
+ val4, val5, val6, val7); \
+ LOAD_8VECS_SH((psrc + 8 * (stride)), (stride), \
+ val8, val9, val10, val11, \
+ val12, val13, val14, val15); \
+}
+
+#define STORE_4VECS_UB(dst_out, pitch, \
+ in0, in1, in2, in3) \
+{ \
+ STORE_UB((in0), (dst_out)); \
+ STORE_UB((in1), ((dst_out) + (pitch))); \
+ STORE_UB((in2), ((dst_out) + 2 * (pitch))); \
+ STORE_UB((in3), ((dst_out) + 3 * (pitch))); \
+}
+
+#define STORE_4VECS_SB(dst_out, pitch, \
+ in0, in1, in2, in3) \
+{ \
+ STORE_SB((in0), (dst_out)); \
+ STORE_SB((in1), ((dst_out) + (pitch))); \
+ STORE_SB((in2), ((dst_out) + 2 * (pitch))); \
+ STORE_SB((in3), ((dst_out) + 3 * (pitch))); \
+}
+
+#define STORE_8VECS_UB(dst_out, pitch_in, \
+ in0, in1, in2, in3, \
+ in4, in5, in6, in7) \
+{ \
+ STORE_4VECS_UB(dst_out, pitch_in, \
+ in0, in1, in2, in3); \
+ STORE_4VECS_UB((dst_out + 4 * (pitch_in)), pitch_in, \
+ in4, in5, in6, in7); \
+}
+
+#define STORE_2VECS_SH(ptr, stride, \
+ in0, in1) \
+{ \
+ STORE_SH(in0, ((ptr) + 0 * stride)); \
+ STORE_SH(in1, ((ptr) + 1 * stride)); \
+}
+
+#define STORE_4VECS_SH(ptr, stride, \
+ in0, in1, in2, in3) \
+{ \
+ STORE_SH(in0, ((ptr) + 0 * stride)); \
+ STORE_SH(in1, ((ptr) + 1 * stride)); \
+ STORE_SH(in2, ((ptr) + 2 * stride)); \
+ STORE_SH(in3, ((ptr) + 3 * stride)); \
+}
+
+#define STORE_6VECS_SH(ptr, stride, \
+ in0, in1, in2, in3, \
+ in4, in5) \
+{ \
+ STORE_SH(in0, ((ptr) + 0 * stride)); \
+ STORE_SH(in1, ((ptr) + 1 * stride)); \
+ STORE_SH(in2, ((ptr) + 2 * stride)); \
+ STORE_SH(in3, ((ptr) + 3 * stride)); \
+ STORE_SH(in4, ((ptr) + 4 * stride)); \
+ STORE_SH(in5, ((ptr) + 5 * stride)); \
+}
+
+#define STORE_8VECS_SH(ptr, stride, \
+ in0, in1, in2, in3, \
+ in4, in5, in6, in7) \
+{ \
+ STORE_SH(in0, ((ptr) + 0 * stride)); \
+ STORE_SH(in1, ((ptr) + 1 * stride)); \
+ STORE_SH(in2, ((ptr) + 2 * stride)); \
+ STORE_SH(in3, ((ptr) + 3 * stride)); \
+ STORE_SH(in4, ((ptr) + 4 * stride)); \
+ STORE_SH(in5, ((ptr) + 5 * stride)); \
+ STORE_SH(in6, ((ptr) + 6 * stride)); \
+ STORE_SH(in7, ((ptr) + 7 * stride)); \
+}
+
+#define CLIP_MIN_TO_MAX_H(in, min, max) \
+( { \
+ v8i16 out_m; \
+ \
+ out_m = __msa_max_s_h((v8i16) (min), (v8i16) (in)); \
+ out_m = __msa_min_s_h((v8i16) (max), (v8i16) out_m); \
+ out_m; \
+} )
+
+#define CLIP_UNSIGNED_CHAR_H(in) \
+( { \
+ v8i16 max_m = __msa_ldi_h(255); \
+ v8i16 out_m; \
+ \
+ out_m = __msa_maxi_s_h((v8i16) (in), 0); \
+ out_m = __msa_min_s_h((v8i16) max_m, (v8i16) out_m); \
+ out_m; \
+} )
+
+#define CLIP_UNSIGNED_CHAR_W(in) \
+( { \
+ v4i32 max_m = __msa_ldi_w(255); \
+ v4i32 out_m; \
+ \
+ out_m = __msa_maxi_s_w((v4i32) (in), 0); \
+ out_m = __msa_min_s_w((v4i32) max_m, (v4i32) out_m); \
+ out_m; \
+} )
+
+#define TRANSPOSE4x4_B_UB(in0, in1, in2, in3, \
+ out0, out1, out2, out3) \
+{ \
+ v16i8 zero_m = { 0 }; \
+ v16i8 s0_m, s1_m, s2_m, s3_m; \
+ \
+ s0_m = (v16i8) __msa_ilvr_d((v2i64) (in1), (v2i64) (in0)); \
+ s1_m = (v16i8) __msa_ilvr_d((v2i64) (in3), (v2i64) (in2)); \
+ s2_m = __msa_ilvr_b(s1_m, s0_m); \
+ s3_m = __msa_ilvl_b(s1_m, s0_m); \
+ \
+ out0 = (v16u8) __msa_ilvr_b(s3_m, s2_m); \
+ out1 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out0, 4); \
+ out2 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out1, 4); \
+ out3 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out2, 4); \
+}
+
+#define TRANSPOSE8x4_B_UB(in0, in1, in2, in3, \
+ in4, in5, in6, in7, \
+ out0, out1, out2, out3) \
+{ \
+ v16i8 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \
+ \
+ tmp0_m = (v16i8) __msa_ilvev_w((v4i32) (in4), (v4i32) (in0)); \
+ tmp1_m = (v16i8) __msa_ilvev_w((v4i32) (in5), (v4i32) (in1)); \
+ tmp2_m = __msa_ilvr_b(tmp1_m, tmp0_m); \
+ tmp0_m = (v16i8) __msa_ilvev_w((v4i32) (in6), (v4i32) (in2)); \
+ tmp1_m = (v16i8) __msa_ilvev_w((v4i32) (in7), (v4i32) (in3)); \
+ \
+ tmp3_m = __msa_ilvr_b(tmp1_m, tmp0_m); \
+ tmp0_m = (v16i8) __msa_ilvr_h((v8i16) tmp3_m, (v8i16) tmp2_m); \
+ tmp1_m = (v16i8) __msa_ilvl_h((v8i16) tmp3_m, (v8i16) tmp2_m); \
+ \
+ out0 = (v16u8) __msa_ilvr_w((v4i32) tmp1_m, (v4i32) tmp0_m); \
+ out2 = (v16u8) __msa_ilvl_w((v4i32) tmp1_m, (v4i32) tmp0_m); \
+ out1 = (v16u8) __msa_ilvl_d((v2i64) out2, (v2i64) out0); \
+ out3 = (v16u8) __msa_ilvl_d((v2i64) out0, (v2i64) out2); \
+}
+
+#define TRANSPOSE8x4_B_UH(in0, in1, in2, in3, \
+ in4, in5, in6, in7, \
+ out0, out1, out2, out3) \
+{ \
+ v16i8 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \
+ \
+ tmp0_m = (v16i8) __msa_ilvev_w((v4i32) (in4), (v4i32) (in0)); \
+ tmp1_m = (v16i8) __msa_ilvev_w((v4i32) (in5), (v4i32) (in1)); \
+ tmp2_m = __msa_ilvr_b(tmp1_m, tmp0_m); \
+ tmp0_m = (v16i8) __msa_ilvev_w((v4i32) (in6), (v4i32) (in2)); \
+ tmp1_m = (v16i8) __msa_ilvev_w((v4i32) (in7), (v4i32) (in3)); \
+ \
+ tmp3_m = __msa_ilvr_b(tmp1_m, tmp0_m); \
+ tmp0_m = (v16i8) __msa_ilvr_h((v8i16) tmp3_m, (v8i16) tmp2_m); \
+ tmp1_m = (v16i8) __msa_ilvl_h((v8i16) tmp3_m, (v8i16) tmp2_m); \
+ \
+ out0 = (v8u16) __msa_ilvr_w((v4i32) tmp1_m, (v4i32) tmp0_m); \
+ out2 = (v8u16) __msa_ilvl_w((v4i32) tmp1_m, (v4i32) tmp0_m); \
+ out1 = (v8u16) __msa_ilvl_d((v2i64) out2, (v2i64) out0); \
+ out3 = (v8u16) __msa_ilvl_d((v2i64) out0, (v2i64) out2); \
+}
+
+#define TRANSPOSE8x8_B_UB(in0, in1, in2, in3, \
+ in4, in5, in6, in7, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ v16i8 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \
+ v16i8 tmp4_m, tmp5_m, tmp6_m, tmp7_m; \
+ v16i8 zero_m = { 0 }; \
+ \
+ tmp0_m = __msa_ilvr_b((v16i8) (in2), (v16i8) (in0)); \
+ tmp1_m = __msa_ilvr_b((v16i8) (in3), (v16i8) (in1)); \
+ tmp2_m = __msa_ilvr_b((v16i8) (in6), (v16i8) (in4)); \
+ tmp3_m = __msa_ilvr_b((v16i8) (in7), (v16i8) (in5)); \
+ \
+ tmp4_m = __msa_ilvr_b((v16i8) tmp1_m, (v16i8) tmp0_m); \
+ tmp5_m = __msa_ilvl_b((v16i8) tmp1_m, (v16i8) tmp0_m); \
+ tmp6_m = __msa_ilvr_b((v16i8) tmp3_m, (v16i8) tmp2_m); \
+ tmp7_m = __msa_ilvl_b((v16i8) tmp3_m, (v16i8) tmp2_m); \
+ \
+ out0 = (v16u8) __msa_ilvr_w((v4i32) tmp6_m, (v4i32) tmp4_m); \
+ out2 = (v16u8) __msa_ilvl_w((v4i32) tmp6_m, (v4i32) tmp4_m); \
+ out4 = (v16u8) __msa_ilvr_w((v4i32) tmp7_m, (v4i32) tmp5_m); \
+ out6 = (v16u8) __msa_ilvl_w((v4i32) tmp7_m, (v4i32) tmp5_m); \
+ \
+ out1 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out0, 8); \
+ out3 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out2, 8); \
+ out5 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out4, 8); \
+ out7 = (v16u8) __msa_sldi_b(zero_m, (v16i8) out6, 8); \
+}
+
+#define TRANSPOSE8x8_B_UH(in0, in1, in2, in3, \
+ in4, in5, in6, in7, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ v16i8 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \
+ v16i8 tmp4_m, tmp5_m, tmp6_m, tmp7_m; \
+ v16i8 zero_m = { 0 }; \
+ \
+ tmp0_m = __msa_ilvr_b((v16i8) (in2), (v16i8) (in0)); \
+ tmp1_m = __msa_ilvr_b((v16i8) (in3), (v16i8) (in1)); \
+ tmp2_m = __msa_ilvr_b((v16i8) (in6), (v16i8) (in4)); \
+ tmp3_m = __msa_ilvr_b((v16i8) (in7), (v16i8) (in5)); \
+ \
+ tmp4_m = __msa_ilvr_b((v16i8) tmp1_m, (v16i8) tmp0_m); \
+ tmp5_m = __msa_ilvl_b((v16i8) tmp1_m, (v16i8) tmp0_m); \
+ tmp6_m = __msa_ilvr_b((v16i8) tmp3_m, (v16i8) tmp2_m); \
+ tmp7_m = __msa_ilvl_b((v16i8) tmp3_m, (v16i8) tmp2_m); \
+ \
+ out0 = (v8u16) __msa_ilvr_w((v4i32) tmp6_m, (v4i32) tmp4_m); \
+ out2 = (v8u16) __msa_ilvl_w((v4i32) tmp6_m, (v4i32) tmp4_m); \
+ out4 = (v8u16) __msa_ilvr_w((v4i32) tmp7_m, (v4i32) tmp5_m); \
+ out6 = (v8u16) __msa_ilvl_w((v4i32) tmp7_m, (v4i32) tmp5_m); \
+ out1 = (v8u16) __msa_sldi_b(zero_m, (v16i8) out0, 8); \
+ out3 = (v8u16) __msa_sldi_b(zero_m, (v16i8) out2, 8); \
+ out5 = (v8u16) __msa_sldi_b(zero_m, (v16i8) out4, 8); \
+ out7 = (v8u16) __msa_sldi_b(zero_m, (v16i8) out6, 8); \
+}
+
+#define TRANSPOSE16x8_B_UB(in0, in1, in2, in3, \
+ in4, in5, in6, in7, \
+ in8, in9, in10, in11, \
+ in12, in13, in14, in15, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ v16u8 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \
+ v16u8 tmp4_m, tmp5_m, tmp6_m, tmp7_m; \
+ \
+ (out7) = (v16u8) __msa_ilvev_d((v2i64) (in8), (v2i64) (in0)); \
+ (out6) = (v16u8) __msa_ilvev_d((v2i64) (in9), (v2i64) (in1)); \
+ (out5) = (v16u8) __msa_ilvev_d((v2i64) (in10), (v2i64) (in2)); \
+ (out4) = (v16u8) __msa_ilvev_d((v2i64) (in11), (v2i64) (in3)); \
+ (out3) = (v16u8) __msa_ilvev_d((v2i64) (in12), (v2i64) (in4)); \
+ (out2) = (v16u8) __msa_ilvev_d((v2i64) (in13), (v2i64) (in5)); \
+ (out1) = (v16u8) __msa_ilvev_d((v2i64) (in14), (v2i64) (in6)); \
+ (out0) = (v16u8) __msa_ilvev_d((v2i64) (in15), (v2i64) (in7)); \
+ \
+ tmp0_m = (v16u8) __msa_ilvev_b((v16i8) (out6), (v16i8) (out7)); \
+ tmp4_m = (v16u8) __msa_ilvod_b((v16i8) (out6), (v16i8) (out7)); \
+ tmp1_m = (v16u8) __msa_ilvev_b((v16i8) (out4), (v16i8) (out5)); \
+ tmp5_m = (v16u8) __msa_ilvod_b((v16i8) (out4), (v16i8) (out5)); \
+ (out5) = (v16u8) __msa_ilvev_b((v16i8) (out2), (v16i8) (out3)); \
+ tmp6_m = (v16u8) __msa_ilvod_b((v16i8) (out2), (v16i8) (out3)); \
+ (out7) = (v16u8) __msa_ilvev_b((v16i8) (out0), (v16i8) (out1)); \
+ tmp7_m = (v16u8) __msa_ilvod_b((v16i8) (out0), (v16i8) (out1)); \
+ \
+ tmp2_m = (v16u8) __msa_ilvev_h((v8i16) tmp1_m, (v8i16) tmp0_m); \
+ tmp3_m = (v16u8) __msa_ilvev_h((v8i16) (out7), (v8i16) (out5)); \
+ (out0) = (v16u8) __msa_ilvev_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ (out4) = (v16u8) __msa_ilvod_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ \
+ tmp2_m = (v16u8) __msa_ilvod_h((v8i16) tmp1_m, (v8i16) tmp0_m); \
+ tmp3_m = (v16u8) __msa_ilvod_h((v8i16) (out7), (v8i16) (out5)); \
+ (out2) = (v16u8) __msa_ilvev_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ (out6) = (v16u8) __msa_ilvod_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ \
+ tmp2_m = (v16u8) __msa_ilvev_h((v8i16) tmp5_m, (v8i16) tmp4_m); \
+ tmp3_m = (v16u8) __msa_ilvev_h((v8i16) tmp7_m, (v8i16) tmp6_m); \
+ (out1) = (v16u8) __msa_ilvev_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ (out5) = (v16u8) __msa_ilvod_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ \
+ tmp2_m = (v16u8) __msa_ilvod_h((v8i16) tmp5_m, (v8i16) tmp4_m); \
+ tmp2_m = (v16u8) __msa_ilvod_h((v8i16) tmp5_m, (v8i16) tmp4_m); \
+ tmp3_m = (v16u8) __msa_ilvod_h((v8i16) tmp7_m, (v8i16) tmp6_m); \
+ tmp3_m = (v16u8) __msa_ilvod_h((v8i16) tmp7_m, (v8i16) tmp6_m); \
+ (out3) = (v16u8) __msa_ilvev_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+ (out7) = (v16u8) __msa_ilvod_w((v4i32) tmp3_m, (v4i32) tmp2_m); \
+}
+
+#define TRANSPOSE8x8_H_SH(in0, in1, in2, in3, \
+ in4, in5, in6, in7, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ v8i16 s0_m, s1_m; \
+ v8i16 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \
+ v8i16 tmp4_m, tmp5_m, tmp6_m, tmp7_m; \
+ \
+ s0_m = __msa_ilvr_h((v8i16) (in6), (v8i16) (in4)); \
+ s1_m = __msa_ilvr_h((v8i16) (in7), (v8i16) (in5)); \
+ tmp0_m = __msa_ilvr_h((v8i16) s1_m, (v8i16) s0_m); \
+ tmp1_m = __msa_ilvl_h((v8i16) s1_m, (v8i16) s0_m); \
+ \
+ s0_m = __msa_ilvl_h((v8i16) (in6), (v8i16) (in4)); \
+ s1_m = __msa_ilvl_h((v8i16) (in7), (v8i16) (in5)); \
+ tmp2_m = __msa_ilvr_h((v8i16) s1_m, (v8i16) s0_m); \
+ tmp3_m = __msa_ilvl_h((v8i16) s1_m, (v8i16) s0_m); \
+ \
+ s0_m = __msa_ilvr_h((v8i16) (in2), (v8i16) (in0)); \
+ s1_m = __msa_ilvr_h((v8i16) (in3), (v8i16) (in1)); \
+ tmp4_m = __msa_ilvr_h((v8i16) s1_m, (v8i16) s0_m); \
+ tmp5_m = __msa_ilvl_h((v8i16) s1_m, (v8i16) s0_m); \
+ \
+ s0_m = __msa_ilvl_h((v8i16) (in2), (v8i16) (in0)); \
+ s1_m = __msa_ilvl_h((v8i16) (in3), (v8i16) (in1)); \
+ tmp6_m = __msa_ilvr_h((v8i16) s1_m, (v8i16) s0_m); \
+ tmp7_m = __msa_ilvl_h((v8i16) s1_m, (v8i16) s0_m); \
+ \
+ out0 = (v8i16) __msa_pckev_d((v2i64) tmp0_m, (v2i64) tmp4_m); \
+ out1 = (v8i16) __msa_pckod_d((v2i64) tmp0_m, (v2i64) tmp4_m); \
+ out2 = (v8i16) __msa_pckev_d((v2i64) tmp1_m, (v2i64) tmp5_m); \
+ out3 = (v8i16) __msa_pckod_d((v2i64) tmp1_m, (v2i64) tmp5_m); \
+ out4 = (v8i16) __msa_pckev_d((v2i64) tmp2_m, (v2i64) tmp6_m); \
+ out5 = (v8i16) __msa_pckod_d((v2i64) tmp2_m, (v2i64) tmp6_m); \
+ out6 = (v8i16) __msa_pckev_d((v2i64) tmp3_m, (v2i64) tmp7_m); \
+ out7 = (v8i16) __msa_pckod_d((v2i64) tmp3_m, (v2i64) tmp7_m); \
+}
+
+#define TRANSPOSE4x4_W(in0, in1, in2, in3, \
+ out0, out1, out2, out3) \
+{ \
+ v4i32 s0_m, s1_m, s2_m, s3_m; \
+ \
+ s0_m = __msa_ilvr_w((v4i32) (in1), (v4i32) (in0)); \
+ s1_m = __msa_ilvl_w((v4i32) (in1), (v4i32) (in0)); \
+ s2_m = __msa_ilvr_w((v4i32) (in3), (v4i32) (in2)); \
+ s3_m = __msa_ilvl_w((v4i32) (in3), (v4i32) (in2)); \
+ \
+ out0 = (v4i32) __msa_ilvr_d((v2i64) s2_m, (v2i64) s0_m); \
+ out1 = (v4i32) __msa_ilvl_d((v2i64) s2_m, (v2i64) s0_m); \
+ out2 = (v4i32) __msa_ilvr_d((v2i64) s3_m, (v2i64) s1_m); \
+ out3 = (v4i32) __msa_ilvl_d((v2i64) s3_m, (v2i64) s1_m); \
+}
+
+#define ILV_B_LRLR_SB(in0, in1, in2, in3, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = __msa_ilvl_b((v16i8) (in1), (v16i8) (in0)); \
+ out1 = __msa_ilvr_b((v16i8) (in1), (v16i8) (in0)); \
+ out2 = __msa_ilvl_b((v16i8) (in3), (v16i8) (in2)); \
+ out3 = __msa_ilvr_b((v16i8) (in3), (v16i8) (in2)); \
+}
+
+#define ILV_B_LRLR_UH(in0, in1, in2, in3, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = (v8u16) __msa_ilvl_b((v16i8) (in1), (v16i8) (in0)); \
+ out1 = (v8u16) __msa_ilvr_b((v16i8) (in1), (v16i8) (in0)); \
+ out2 = (v8u16) __msa_ilvl_b((v16i8) (in3), (v16i8) (in2)); \
+ out3 = (v8u16) __msa_ilvr_b((v16i8) (in3), (v16i8) (in2)); \
+}
+
+#define ILV_B_LRLR_SH(in0, in1, in2, in3, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = (v8i16) __msa_ilvl_b((v16i8) (in1), (v16i8) (in0)); \
+ out1 = (v8i16) __msa_ilvr_b((v16i8) (in1), (v16i8) (in0)); \
+ out2 = (v8i16) __msa_ilvl_b((v16i8) (in3), (v16i8) (in2)); \
+ out3 = (v8i16) __msa_ilvr_b((v16i8) (in3), (v16i8) (in2)); \
+}
+
+#define ILV_H_LRLR_SW(in0, in1, in2, in3, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = (v4i32) __msa_ilvl_h((v8i16) (in1), (v8i16) (in0)); \
+ out1 = (v4i32) __msa_ilvr_h((v8i16) (in1), (v8i16) (in0)); \
+ out2 = (v4i32) __msa_ilvl_h((v8i16) (in3), (v8i16) (in2)); \
+ out3 = (v4i32) __msa_ilvr_h((v8i16) (in3), (v8i16) (in2)); \
+}
+
+#define ILVR_B_2VECS_UB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = (v16u8) __msa_ilvr_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = (v16u8) __msa_ilvr_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+}
+
+#define ILVR_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = __msa_ilvr_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = __msa_ilvr_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+}
+
+#define ILVR_B_4VECS_SB(in0_r, in1_r, in2_r, in3_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ out0, out1, out2, out3) \
+{ \
+ ILVR_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_B_2VECS_SB(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+}
+
+#define ILVR_B_6VECS_SB(in0_r, in1_r, in2_r, \
+ in3_r, in4_r, in5_r, \
+ in0_l, in1_l, in2_l, \
+ in3_l, in4_l, in5_l, \
+ out0, out1, out2, \
+ out3, out4, out5) \
+{ \
+ ILVR_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_B_2VECS_SB(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVR_B_2VECS_SB(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+}
+
+#define ILVR_B_8VECS_SB(in0_r, in1_r, in2_r, in3_r, \
+ in4_r, in5_r, in6_r, in7_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ in4_l, in5_l, in6_l, in7_l, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ ILVR_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_B_2VECS_SB(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVR_B_2VECS_SB(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+ ILVR_B_2VECS_SB(in6_r, in7_r, in6_l, in7_l, \
+ out6, out7); \
+}
+
+#define ILVR_B_2VECS_UH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = (v8u16) __msa_ilvr_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = (v8u16) __msa_ilvr_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+}
+
+#define ILVR_B_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = (v8i16) __msa_ilvr_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = (v8i16) __msa_ilvr_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+}
+
+#define ILVR_B_3VECS_SH(in0_r, in1_r, in2_r, in0_l, in1_l, in2_l, \
+ out0, out1, out2) \
+{ \
+ ILVR_B_2VECS_SH(in0_r, in1_r, in0_l, in1_l, out0, out1); \
+ out2 = (v8i16) __msa_ilvr_b((v16i8) (in2_l), (v16i8) (in2_r)); \
+}
+
+#define ILVR_B_4VECS_UH(in0_r, in1_r, in2_r, in3_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ out0, out1, out2, out3) \
+{ \
+ ILVR_B_2VECS_UH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_B_2VECS_UH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+}
+
+#define ILVR_B_4VECS_SH(in0_r, in1_r, in2_r, in3_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ out0, out1, out2, out3) \
+{ \
+ ILVR_B_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_B_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+}
+
+#define ILVR_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = __msa_ilvr_h((v8i16) (in0_l), (v8i16) (in0_r)); \
+ out1 = __msa_ilvr_h((v8i16) (in1_l), (v8i16) (in1_r)); \
+}
+
+#define ILVR_H_4VECS_SH(in0_r, in1_r, in2_r, in3_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ out0, out1, out2, out3) \
+{ \
+ ILVR_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_H_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+}
+
+#define ILVR_H_6VECS_SH(in0_r, in1_r, in2_r, \
+ in3_r, in4_r, in5_r, \
+ in0_l, in1_l, in2_l, \
+ in3_l, in4_l, in5_l, \
+ out0, out1, out2, \
+ out3, out4, out5) \
+{ \
+ ILVR_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_H_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVR_H_2VECS_SH(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+}
+
+#define ILVR_H_8VECS_SH(in0_r, in1_r, in2_r, in3_r, \
+ in4_r, in5_r, in6_r, in7_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ in4_l, in5_l, in6_l, in7_l, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ ILVR_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVR_H_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVR_H_2VECS_SH(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+ ILVR_H_2VECS_SH(in6_r, in7_r, in6_l, in7_l, \
+ out6, out7); \
+}
+
+#define ILVL_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = __msa_ilvl_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = __msa_ilvl_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+}
+
+#define ILVL_B_4VECS_SB(in0_r, in1_r, in2_r, in3_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ out0, out1, out2, out3) \
+{ \
+ ILVL_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVL_B_2VECS_SB(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+}
+
+#define ILVL_B_6VECS_SB(in0_r, in1_r, in2_r, \
+ in3_r, in4_r, in5_r, \
+ in0_l, in1_l, in2_l, \
+ in3_l, in4_l, in5_l, \
+ out0, out1, out2, \
+ out3, out4, out5) \
+{ \
+ ILVL_B_2VECS_SB(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVL_B_2VECS_SB(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVL_B_2VECS_SB(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+}
+
+#define ILVL_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1) \
+{ \
+ out0 = __msa_ilvl_h((v8i16) (in0_l), (v8i16) (in0_r)); \
+ out1 = __msa_ilvl_h((v8i16) (in1_l), (v8i16) (in1_r)); \
+}
+
+#define ILVL_H_4VECS_SH(in0_r, in1_r, in2_r, in3_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ out0, out1, out2, out3) \
+{ \
+ ILVL_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVL_H_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+}
+
+#define ILVL_H_6VECS_SH(in0_r, in1_r, in2_r, \
+ in3_r, in4_r, in5_r, \
+ in0_l, in1_l, in2_l, \
+ in3_l, in4_l, in5_l, \
+ out0, out1, out2, \
+ out3, out4, out5) \
+{ \
+ ILVL_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVL_H_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVL_H_2VECS_SH(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+}
+
+#define ILVL_H_8VECS_SH(in0_r, in1_r, in2_r, in3_r, \
+ in4_r, in5_r, in6_r, in7_r, \
+ in0_l, in1_l, in2_l, in3_l, \
+ in4_l, in5_l, in6_l, in7_l, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7) \
+{ \
+ ILVL_H_2VECS_SH(in0_r, in1_r, in0_l, in1_l, \
+ out0, out1); \
+ ILVL_H_2VECS_SH(in2_r, in3_r, in2_l, in3_l, \
+ out2, out3); \
+ ILVL_H_2VECS_SH(in4_r, in5_r, in4_l, in5_l, \
+ out4, out5); \
+ ILVL_H_2VECS_SH(in6_r, in7_r, in6_l, in7_l, \
+ out6, out7); \
+}
+
+#define ILVR_D_2VECS_SB(out0, in0_l, in0_r, \
+ out1, in1_l, in1_r) \
+{ \
+ out0 = (v16i8) __msa_ilvr_d((v2i64) (in0_l), (v2i64) (in0_r)); \
+ out1 = (v16i8) __msa_ilvr_d((v2i64) (in1_l), (v2i64) (in1_r)); \
+}
+
+#define ILVR_D_3VECS_SB(out0, in0_l, in0_r, \
+ out1, in1_l, in1_r, \
+ out2, in2_l, in2_r) \
+{ \
+ ILVR_D_2VECS_SB(out0, in0_l, in0_r, \
+ out1, in1_l, in1_r); \
+ out2 = (v16i8) __msa_ilvr_d((v2i64) (in2_l), (v2i64) (in2_r)); \
+}
+
+#define ILVR_D_4VECS_SB(out0, in0_l, in0_r, \
+ out1, in1_l, in1_r, \
+ out2, in2_l, in2_r, \
+ out3, in3_l, in3_r) \
+{ \
+ ILVR_D_2VECS_SB(out0, in0_l, in0_r, \
+ out1, in1_l, in1_r); \
+ ILVR_D_2VECS_SB(out2, in2_l, in2_r, \
+ out3, in3_l, in3_r); \
+}
+
+#define MAXI_S_H_4VECS_UH(vec0, vec1, vec2, vec3, max_value) \
+{ \
+ vec0 = (v8u16) __msa_maxi_s_h((v8i16) (vec0), (max_value)); \
+ vec1 = (v8u16) __msa_maxi_s_h((v8i16) (vec1), (max_value)); \
+ vec2 = (v8u16) __msa_maxi_s_h((v8i16) (vec2), (max_value)); \
+ vec3 = (v8u16) __msa_maxi_s_h((v8i16) (vec3), (max_value)); \
+}
+
+#define SAT_U_H_4VECS_UH(vec0, vec1, vec2, vec3, sat_value) \
+{ \
+ vec0 = __msa_sat_u_h((v8u16) (vec0), (sat_value)); \
+ vec1 = __msa_sat_u_h((v8u16) (vec1), (sat_value)); \
+ vec2 = __msa_sat_u_h((v8u16) (vec2), (sat_value)); \
+ vec3 = __msa_sat_u_h((v8u16) (vec3), (sat_value)); \
+}
+
+#define PCKEV_B_4VECS_UB(in0_l, in1_l, in2_l, in3_l, \
+ in0_r, in1_r, in2_r, in3_r, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = (v16u8) __msa_pckev_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = (v16u8) __msa_pckev_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+ out2 = (v16u8) __msa_pckev_b((v16i8) (in2_l), (v16i8) (in2_r)); \
+ out3 = (v16u8) __msa_pckev_b((v16i8) (in3_l), (v16i8) (in3_r)); \
+}
+
+#define PCKEV_B_4VECS_SB(in0_l, in1_l, in2_l, in3_l, \
+ in0_r, in1_r, in2_r, in3_r, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = __msa_pckev_b((v16i8) (in0_l), (v16i8) (in0_r)); \
+ out1 = __msa_pckev_b((v16i8) (in1_l), (v16i8) (in1_r)); \
+ out2 = __msa_pckev_b((v16i8) (in2_l), (v16i8) (in2_r)); \
+ out3 = __msa_pckev_b((v16i8) (in3_l), (v16i8) (in3_r)); \
+}
+
+#define XORI_B_2VECS_UB(val0, val1, out0, out1, xor_val) \
+{ \
+ out0 = __msa_xori_b((v16u8) (val0), (xor_val)); \
+ out1 = __msa_xori_b((v16u8) (val1), (xor_val)); \
+}
+
+#define XORI_B_2VECS_SB(val0, val1, \
+ out0, out1, xor_val) \
+{ \
+ out0 = (v16i8) __msa_xori_b((v16u8) (val0), (xor_val)); \
+ out1 = (v16i8) __msa_xori_b((v16u8) (val1), (xor_val)); \
+}
+
+#define XORI_B_3VECS_SB(val0, val1, val2, \
+ out0, out1, out2, \
+ xor_val) \
+{ \
+ XORI_B_2VECS_SB(val0, val1, \
+ out0, out1, xor_val); \
+ out2 = (v16i8) __msa_xori_b((v16u8) (val2), (xor_val)); \
+}
+
+#define XORI_B_4VECS_UB(val0, val1, val2, val3, \
+ out0, out1, out2, out3, xor_val) \
+{ \
+ XORI_B_2VECS_UB(val0, val1, out0, out1, xor_val); \
+ XORI_B_2VECS_UB(val2, val3, out2, out3, xor_val); \
+}
+
+#define XORI_B_4VECS_SB(val0, val1, val2, val3, \
+ out0, out1, out2, out3, \
+ xor_val) \
+{ \
+ XORI_B_2VECS_SB(val0, val1, \
+ out0, out1, xor_val); \
+ XORI_B_2VECS_SB(val2, val3, \
+ out2, out3, xor_val); \
+}
+
+#define XORI_B_5VECS_SB(val0, val1, val2, val3, val4, \
+ out0, out1, out2, out3, out4, \
+ xor_val) \
+{ \
+ XORI_B_3VECS_SB(val0, val1, val2, \
+ out0, out1, out2, xor_val); \
+ XORI_B_2VECS_SB(val3, val4, \
+ out3, out4, xor_val); \
+}
+
+#define XORI_B_6VECS_SB(val0, val1, val2, val3, val4, val5, \
+ out0, out1, out2, out3, out4, out5, \
+ xor_val) \
+{ \
+ XORI_B_4VECS_SB(val0, val1, val2, val3, \
+ out0, out1, out2, out3, xor_val); \
+ XORI_B_2VECS_SB(val4, val5,out4, out5, xor_val); \
+}
+
+#define XORI_B_7VECS_SB(val0, val1, val2, val3, \
+ val4, val5, val6, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, \
+ xor_val) \
+{ \
+ XORI_B_4VECS_SB(val0, val1, val2, val3, \
+ out0, out1, out2, out3, xor_val); \
+ XORI_B_3VECS_SB(val4, val5, val6, \
+ out4, out5, out6, xor_val); \
+}
+
+#define XORI_B_8VECS_SB(val0, val1, val2, val3, \
+ val4, val5, val6, val7, \
+ out0, out1, out2, out3, \
+ out4, out5, out6, out7, xor_val) \
+{ \
+ XORI_B_4VECS_SB(val0, val1, val2, val3, \
+ out0, out1, out2, out3, xor_val); \
+ XORI_B_4VECS_SB(val4, val5, val6, val7, \
+ out4, out5, out6, out7, xor_val); \
+}
+#define ADDS_S_H_4VECS_UH(in0, in1, in2, in3, in4, in5, in6, in7, \
+ out0, out1, out2, out3) \
+{ \
+ out0 = (v8u16) __msa_adds_s_h((v8i16) (in0), (v8i16) (in1)); \
+ out1 = (v8u16) __msa_adds_s_h((v8i16) (in2), (v8i16) (in3)); \
+ out2 = (v8u16) __msa_adds_s_h((v8i16) (in4), (v8i16) (in5)); \
+ out3 = (v8u16) __msa_adds_s_h((v8i16) (in6), (v8i16) (in7)); \
+}
+#define SRA_4VECS(in0, in1, in2, in3, \
+ out0, out1, out2, out3, \
+ shift_right_vec) \
+{ \
+ out0 = (in0) >> (shift_right_vec); \
+ out1 = (in1) >> (shift_right_vec); \
+ out2 = (in2) >> (shift_right_vec); \
+ out3 = (in3) >> (shift_right_vec); \
+}
+
+#define SRL_H_4VECS_UH(in0, in1, in2, in3, \
+ out0, out1, out2, out3, \
+ shift_right_vec) \
+{ \
+ out0 = (v8u16) __msa_srl_h((v8i16) (in0), (v8i16) (shift_right_vec)); \
+ out1 = (v8u16) __msa_srl_h((v8i16) (in1), (v8i16) (shift_right_vec)); \
+ out2 = (v8u16) __msa_srl_h((v8i16) (in2), (v8i16) (shift_right_vec)); \
+ out3 = (v8u16) __msa_srl_h((v8i16) (in3), (v8i16) (shift_right_vec)); \
+}
+
+#define SRAR_SATURATE_SIGNED_H(input, right_shift_vec, sat_val) \
+( { \
+ v8i16 out_m; \
+ \
+ out_m = __msa_srar_h((v8i16) (input), (v8i16) (right_shift_vec)); \
+ out_m = __msa_sat_s_h(out_m, (sat_val)); \
+ out_m; \
+} )
+
+#define PCKEV_2B_XORI128_STORE_4_BYTES_4(in1, in2, \
+ pdst, stride) \
+{ \
+ uint32_t out0_m, out1_m, out2_m, out3_m; \
+ v16i8 tmp0_m; \
+ uint8_t *dst_m = (uint8_t *) (pdst); \
+ \
+ tmp0_m = __msa_pckev_b((v16i8) (in2), (v16i8) (in1)); \
+ tmp0_m = (v16i8) __msa_xori_b((v16u8) tmp0_m, 128); \
+ \
+ out0_m = __msa_copy_u_w((v4i32) tmp0_m, 0); \
+ out1_m = __msa_copy_u_w((v4i32) tmp0_m, 1); \
+ out2_m = __msa_copy_u_w((v4i32) tmp0_m, 2); \
+ out3_m = __msa_copy_u_w((v4i32) tmp0_m, 3); \
+ \
+ STORE_WORD(dst_m, out0_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out1_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out2_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out3_m); \
+}
+
+#define PCKEV_B_XORI128_STORE_8_BYTES(in1, in2, pdest) \
+{ \
+ uint64_t out_m; \
+ v16i8 tmp_m; \
+ \
+ tmp_m = __msa_pckev_b((v16i8) (in1), (v16i8) (in2)); \
+ tmp_m = (v16i8) __msa_xori_b((v16u8) tmp_m, 128); \
+ out_m = __msa_copy_u_d((v2i64) tmp_m, 0); \
+ STORE_DWORD((pdest), out_m); \
+}
+
+#define PCKEV_B_XORI128_STORE_8_BYTES_2(in1, in2, \
+ pdst, stride) \
+{ \
+ uint64_t out0_m, out1_m; \
+ v16i8 tmp0_m; \
+ uint8_t *dst_m = (uint8_t *) (pdst); \
+ \
+ tmp0_m = __msa_pckev_b((v16i8) (in2), (v16i8) (in1)); \
+ tmp0_m = (v16i8) __msa_xori_b((v16u8) tmp0_m, 128); \
+ \
+ out0_m = __msa_copy_u_d((v2i64) tmp0_m, 0); \
+ out1_m = __msa_copy_u_d((v2i64) tmp0_m, 1); \
+ \
+ STORE_DWORD(dst_m, out0_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out1_m); \
+}
+
+#define PCKEV_B_XORI128_STORE_6_BYTES_4(in1, in2, in3, in4, \
+ pdst, stride) \
+{ \
+ uint32_t out0_m, out1_m, out2_m, out3_m; \
+ uint16_t out4_m, out5_m, out6_m, out7_m; \
+ v16i8 tmp0_m, tmp1_m; \
+ uint8_t *dst_m = (uint8_t *) (pdst); \
+ \
+ tmp0_m = __msa_pckev_b((v16i8) (in2), (v16i8) (in1)); \
+ tmp1_m = __msa_pckev_b((v16i8) (in4), (v16i8) (in3)); \
+ \
+ tmp0_m = (v16i8) __msa_xori_b((v16u8) tmp0_m, 128); \
+ tmp1_m = (v16i8) __msa_xori_b((v16u8) tmp1_m, 128); \
+ \
+ out0_m = __msa_copy_u_w((v4i32) tmp0_m, 0); \
+ out1_m = __msa_copy_u_w((v4i32) tmp0_m, 2); \
+ out2_m = __msa_copy_u_w((v4i32) tmp1_m, 0); \
+ out3_m = __msa_copy_u_w((v4i32) tmp1_m, 2); \
+ \
+ out4_m = __msa_copy_u_h((v8i16) tmp0_m, 2); \
+ out5_m = __msa_copy_u_h((v8i16) tmp0_m, 6); \
+ out6_m = __msa_copy_u_h((v8i16) tmp1_m, 2); \
+ out7_m = __msa_copy_u_h((v8i16) tmp1_m, 6); \
+ \
+ STORE_WORD(dst_m, out0_m); \
+ STORE_HWORD((dst_m + 4), out4_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out1_m); \
+ STORE_HWORD((dst_m + 4), out5_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out2_m); \
+ STORE_HWORD((dst_m + 4), out6_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out3_m); \
+ STORE_HWORD((dst_m + 4), out7_m); \
+}
+
+#define PCKEV_B_4_XORI128_STORE_8_BYTES_4(in1, in2, in3, in4, \
+ pdst, stride) \
+{ \
+ uint64_t out0_m, out1_m, out2_m, out3_m; \
+ v16i8 tmp0_m, tmp1_m; \
+ uint8_t *dst_m = (uint8_t *) (pdst); \
+ \
+ tmp0_m = __msa_pckev_b((v16i8) (in2), (v16i8) (in1)); \
+ tmp1_m = __msa_pckev_b((v16i8) (in4), (v16i8) (in3)); \
+ \
+ tmp0_m = (v16i8) __msa_xori_b((v16u8) tmp0_m, 128); \
+ tmp1_m = (v16i8) __msa_xori_b((v16u8) tmp1_m, 128); \
+ \
+ out0_m = __msa_copy_u_d((v2i64) tmp0_m, 0); \
+ out1_m = __msa_copy_u_d((v2i64) tmp0_m, 1); \
+ out2_m = __msa_copy_u_d((v2i64) tmp1_m, 0); \
+ out3_m = __msa_copy_u_d((v2i64) tmp1_m, 1); \
+ \
+ STORE_DWORD(dst_m, out0_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out1_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out2_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out3_m); \
+}
+#define PCKEV_B_XORI128_STORE_VEC(in1, in2, pdest) \
+{ \
+ v16i8 tmp_m; \
+ \
+ tmp_m = __msa_pckev_b((v16i8) (in1), (v16i8) (in2)); \
+ tmp_m = (v16i8) __msa_xori_b((v16u8) tmp_m, 128); \
+ STORE_SB(tmp_m, (pdest)); \
+}
+
+#define PCKEV_B_STORE_4_BYTES_4(in1, in2, in3, in4, \
+ pdst, stride) \
+{ \
+ uint32_t out0_m, out1_m, out2_m, out3_m; \
+ v16i8 tmp0_m, tmp1_m; \
+ uint8_t *dst_m = (uint8_t *) (pdst); \
+ \
+ tmp0_m = __msa_pckev_b((v16i8) (in2), (v16i8) (in1)); \
+ tmp1_m = __msa_pckev_b((v16i8) (in4), (v16i8) (in3)); \
+ \
+ out0_m = __msa_copy_u_w((v4i32) tmp0_m, 0); \
+ out1_m = __msa_copy_u_w((v4i32) tmp0_m, 2); \
+ out2_m = __msa_copy_u_w((v4i32) tmp1_m, 0); \
+ out3_m = __msa_copy_u_w((v4i32) tmp1_m, 2); \
+ \
+ STORE_WORD(dst_m, out0_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out1_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out2_m); \
+ dst_m += stride; \
+ STORE_WORD(dst_m, out3_m); \
+}
+
+#define PCKEV_B_STORE_8_BYTES_4(in1, in2, in3, in4, \
+ pdst, stride) \
+{ \
+ uint64_t out0_m, out1_m, out2_m, out3_m; \
+ v16i8 tmp0_m, tmp1_m; \
+ uint8_t *dst_m = (uint8_t *) (pdst); \
+ \
+ tmp0_m = __msa_pckev_b((v16i8) (in2), (v16i8) (in1)); \
+ tmp1_m = __msa_pckev_b((v16i8) (in4), (v16i8) (in3)); \
+ \
+ out0_m = __msa_copy_u_d((v2i64) tmp0_m, 0); \
+ out1_m = __msa_copy_u_d((v2i64) tmp0_m, 1); \
+ out2_m = __msa_copy_u_d((v2i64) tmp1_m, 0); \
+ out3_m = __msa_copy_u_d((v2i64) tmp1_m, 1); \
+ \
+ STORE_DWORD(dst_m, out0_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out1_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out2_m); \
+ dst_m += stride; \
+ STORE_DWORD(dst_m, out3_m); \
+}
+
+#define UNPCK_SIGNED_B_TO_H(in, out1, out2) \
+{ \
+ v16i8 tmp_m; \
+ \
+ tmp_m = __msa_clti_s_b((v16i8) (in), 0); \
+ out1 = (v8i16) __msa_ilvr_b(tmp_m, (v16i8) (in)); \
+ out2 = (v8i16) __msa_ilvl_b(tmp_m, (v16i8) (in)); \
+}
+
+#define SWAP_VECS(Vec0, Vec1) \
+{ \
+ Vec0 = Vec0 ^ Vec1; \
+ Vec1 = Vec0 ^ Vec1; \
+ Vec0 = Vec0 ^ Vec1; \
+}
+
+#endif /* AVUTIL_MIPS_GENERIC_MACROS_MSA_H */
diff --git a/libavutil/mips/intreadwrite.h b/libavutil/mips/intreadwrite.h
index 4dabbe6819..32084f68f6 100644
--- a/libavutil/mips/intreadwrite.h
+++ b/libavutil/mips/intreadwrite.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,7 +24,7 @@
#include <stdint.h>
#include "config.h"
-#if ARCH_MIPS64 && HAVE_INLINE_ASM
+#if ARCH_MIPS64 && HAVE_INLINE_ASM && !HAVE_MIPS64R6
#define AV_RN32 AV_RN32
static av_always_inline uint32_t AV_RN32(const void *p)
@@ -41,6 +41,6 @@ static av_always_inline uint32_t AV_RN32(const void *p)
return v;
}
-#endif /* ARCH_MIPS64 && HAVE_INLINE_ASM */
+#endif /* ARCH_MIPS64 && HAVE_INLINE_ASM && !HAVE_MIPS64R6 */
#endif /* AVUTIL_MIPS_INTREADWRITE_H */
diff --git a/libavutil/mips/libm_mips.h b/libavutil/mips/libm_mips.h
new file mode 100644
index 0000000000..8853bbc751
--- /dev/null
+++ b/libavutil/mips/libm_mips.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012
+ * MIPS Technologies, Inc., California.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Author: Nedeljko Babic (nbabic@mips.com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * MIPS optimization for some libm functions
+ */
+
+#ifndef AVUTIL_LIBM_MIPS_H
+#define AVUTIL_LIBM_MIPS_H
+
+static av_always_inline av_const long int lrintf_mips(float x)
+{
+ register int ret_int;
+
+ __asm__ volatile (
+ "cvt.w.s %[x], %[x] \n\t"
+ "mfc1 %[ret_int], %[x] \n\t"
+
+ :[x]"+f"(x), [ret_int]"=r"(ret_int)
+ );
+ return ret_int;
+}
+
+#undef lrintf
+#define lrintf(x) lrintf_mips(x)
+
+#define HAVE_LRINTF 1
+#endif /* AVUTIL_LIBM_MIPS_H */
diff --git a/libavutil/motion_vector.h b/libavutil/motion_vector.h
new file mode 100644
index 0000000000..30cfb994b7
--- /dev/null
+++ b/libavutil/motion_vector.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_MOTION_VECTOR_H
+#define AVUTIL_MOTION_VECTOR_H
+
+#include <stdint.h>
+
+typedef struct AVMotionVector {
+ /**
+ * Where the current macroblock comes from; negative value when it comes
+ * from the past, positive value when it comes from the future.
+ * XXX: set exact relative ref frame reference instead of a +/- 1 "direction".
+ */
+ int32_t source;
+ /**
+ * Width and height of the block.
+ */
+ uint8_t w, h;
+ /**
+ * Absolute source position. Can be outside the frame area.
+ */
+ int16_t src_x, src_y;
+ /**
+ * Absolute destination position. Can be outside the frame area.
+ */
+ int16_t dst_x, dst_y;
+ /**
+ * Extra flag information.
+ * Currently unused.
+ */
+ uint64_t flags;
+} AVMotionVector;
+
+#endif /* AVUTIL_MOTION_VECTOR_H */
diff --git a/libavutil/murmur3.c b/libavutil/murmur3.c
new file mode 100644
index 0000000000..c4d8dcb529
--- /dev/null
+++ b/libavutil/murmur3.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <stdint.h>
+#include "mem.h"
+#include "intreadwrite.h"
+#include "murmur3.h"
+
+typedef struct AVMurMur3 {
+ uint64_t h1, h2;
+ uint8_t state[16];
+ int state_pos;
+ uint64_t len;
+} AVMurMur3;
+
+AVMurMur3 *av_murmur3_alloc(void)
+{
+ return av_mallocz(sizeof(AVMurMur3));
+}
+
+void av_murmur3_init_seeded(AVMurMur3 *c, uint64_t seed)
+{
+ memset(c, 0, sizeof(*c));
+ c->h1 = c->h2 = seed;
+}
+
+void av_murmur3_init(AVMurMur3 *c)
+{
+ // arbitrary random number as seed
+ av_murmur3_init_seeded(c, 0x725acc55daddca55);
+}
+
+static const uint64_t c1 = UINT64_C(0x87c37b91114253d5);
+static const uint64_t c2 = UINT64_C(0x4cf5ad432745937f);
+
+#define ROT(a, b) (((a) << (b)) | ((a) >> (64 - (b))))
+
+static uint64_t inline get_k1(const uint8_t *src)
+{
+ uint64_t k = AV_RL64(src);
+ k *= c1;
+ k = ROT(k, 31);
+ k *= c2;
+ return k;
+}
+
+static uint64_t inline get_k2(const uint8_t *src)
+{
+ uint64_t k = AV_RL64(src + 8);
+ k *= c2;
+ k = ROT(k, 33);
+ k *= c1;
+ return k;
+}
+
+static uint64_t inline update_h1(uint64_t k, uint64_t h1, uint64_t h2)
+{
+ k ^= h1;
+ k = ROT(k, 27);
+ k += h2;
+ k *= 5;
+ k += 0x52dce729;
+ return k;
+}
+
+static uint64_t inline update_h2(uint64_t k, uint64_t h1, uint64_t h2)
+{
+ k ^= h2;
+ k = ROT(k, 31);
+ k += h1;
+ k *= 5;
+ k += 0x38495ab5;
+ return k;
+}
+
+void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, int len)
+{
+ const uint8_t *end;
+ uint64_t h1 = c->h1, h2 = c->h2;
+ uint64_t k1, k2;
+ if (len <= 0) return;
+ c->len += len;
+ if (c->state_pos > 0) {
+ while (c->state_pos < 16) {
+ c->state[c->state_pos++] = *src++;
+ if (--len <= 0) return;
+ }
+ c->state_pos = 0;
+ k1 = get_k1(c->state);
+ k2 = get_k2(c->state);
+ h1 = update_h1(k1, h1, h2);
+ h2 = update_h2(k2, h1, h2);
+ }
+
+ end = src + (len & ~15);
+ while (src < end) {
+ // These could be done sequentially instead
+ // of interleaved, but like this is over 10% faster
+ k1 = get_k1(src);
+ k2 = get_k2(src);
+ h1 = update_h1(k1, h1, h2);
+ h2 = update_h2(k2, h1, h2);
+ src += 16;
+ }
+ c->h1 = h1;
+ c->h2 = h2;
+
+ len &= 15;
+ if (len > 0) {
+ memcpy(c->state, src, len);
+ c->state_pos = len;
+ }
+}
+
+static inline uint64_t fmix(uint64_t k)
+{
+ k ^= k >> 33;
+ k *= UINT64_C(0xff51afd7ed558ccd);
+ k ^= k >> 33;
+ k *= UINT64_C(0xc4ceb9fe1a85ec53);
+ k ^= k >> 33;
+ return k;
+}
+
+void av_murmur3_final(AVMurMur3 *c, uint8_t dst[16])
+{
+ uint64_t h1 = c->h1, h2 = c->h2;
+ memset(c->state + c->state_pos, 0, sizeof(c->state) - c->state_pos);
+ h1 ^= get_k1(c->state) ^ c->len;
+ h2 ^= get_k2(c->state) ^ c->len;
+ h1 += h2;
+ h2 += h1;
+ h1 = fmix(h1);
+ h2 = fmix(h2);
+ h1 += h2;
+ h2 += h1;
+ AV_WL64(dst, h1);
+ AV_WL64(dst + 8, h2);
+}
+
+#ifdef TEST
+int main(void)
+{
+ int i;
+ uint8_t hash_result[16] = {0};
+ AVMurMur3 *ctx = av_murmur3_alloc();
+#if 1
+ uint8_t in[256] = {0};
+ uint8_t *hashes = av_mallocz(256 * 16);
+ for (i = 0; i < 256; i++)
+ {
+ in[i] = i;
+ av_murmur3_init_seeded(ctx, 256 - i);
+ // Note: this actually tests hashing 0 bytes
+ av_murmur3_update(ctx, in, i);
+ av_murmur3_final(ctx, hashes + 16 * i);
+ }
+ av_murmur3_init_seeded(ctx, 0);
+ av_murmur3_update(ctx, hashes, 256 * 16);
+ av_murmur3_final(ctx, hash_result);
+ av_free(hashes);
+ av_freep(&ctx);
+ printf("result: 0x%"PRIx64" 0x%"PRIx64"\n", AV_RL64(hash_result), AV_RL64(hash_result + 8));
+ // official reference value is 32 bit
+ return AV_RL32(hash_result) != 0x6384ba69;
+#else
+ uint8_t *in = av_mallocz(512*1024);
+ av_murmur3_init(ctx);
+ for (i = 0; i < 40*1024; i++)
+ av_murmur3_update(ctx, in, 512*1024);
+ av_murmur3_final(ctx, hash_result);
+ av_free(in);
+ return hash_result[0];
+#endif
+}
+#endif
diff --git a/libavutil/murmur3.h b/libavutil/murmur3.h
new file mode 100644
index 0000000000..f29ed973e9
--- /dev/null
+++ b/libavutil/murmur3.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_MURMUR3_H
+#define AVUTIL_MURMUR3_H
+
+#include <stdint.h>
+
+struct AVMurMur3 *av_murmur3_alloc(void);
+void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed);
+void av_murmur3_init(struct AVMurMur3 *c);
+void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len);
+void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]);
+
+#endif /* AVUTIL_MURMUR3_H */
diff --git a/libavutil/old_pix_fmts.h b/libavutil/old_pix_fmts.h
index d3e1e5b24d..cd1ed7c19f 100644
--- a/libavutil/old_pix_fmts.h
+++ b/libavutil/old_pix_fmts.h
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * copyright (c) 2006-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -106,9 +108,13 @@
PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0
PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1
PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1
- PIX_FMT_Y400A, ///< 8bit gray, 8bit alpha
+ PIX_FMT_GRAY8A, ///< 8bit gray, 8bit alpha
PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian
PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian
+
+ //the following 10 formats have the disadvantage of needing 1 format for each bit depth, thus
+ //If you want to support multiple bit depths, then using PIX_FMT_YUV420P16* with the bpp stored separately
+ //is better
PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
@@ -122,6 +128,13 @@
PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
PIX_FMT_VDA_VLD, ///< hardware decoding through VDA
+
+#ifdef AV_PIX_FMT_ABI_GIT_MASTER
+ PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+#endif
PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp
PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big endian
PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little endian
@@ -129,6 +142,36 @@
PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little endian
PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big endian
PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little endian
- PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
+#ifndef AV_PIX_FMT_ABI_GIT_MASTER
+ PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+#endif
+ PIX_FMT_0RGB=0x123+4, ///< packed RGB 8:8:8, 32bpp, 0RGB0RGB...
+ PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGB0RGB0...
+ PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, 0BGR0BGR...
+ PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGR0BGR0...
+ PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
+ PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
+
+ PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big endian
+ PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little endian
+ PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big endian
+ PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little endian
+
+ PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
#endif /* AVUTIL_OLD_PIX_FMTS_H */
diff --git a/libavutil/opencl.c b/libavutil/opencl.c
new file mode 100644
index 0000000000..1d78214588
--- /dev/null
+++ b/libavutil/opencl.c
@@ -0,0 +1,853 @@
+/*
+ * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com>
+ * Copyright (C) 2012 Li Cao <li@multicorewareinc.com>
+ * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com>
+ * Copyright (C) 2013 Lenny Wang <lwanghpc@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
+ */
+
+#include "opencl.h"
+#include "avstring.h"
+#include "log.h"
+#include "avassert.h"
+#include "opt.h"
+
+#if HAVE_THREADS
+#if HAVE_PTHREADS
+#include <pthread.h>
+#elif HAVE_W32THREADS
+#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
+#endif
+#include "atomic.h"
+
+static volatile pthread_mutex_t *atomic_opencl_lock = NULL;
+#define LOCK_OPENCL pthread_mutex_lock(atomic_opencl_lock)
+#define UNLOCK_OPENCL pthread_mutex_unlock(atomic_opencl_lock)
+#else
+#define LOCK_OPENCL
+#define UNLOCK_OPENCL
+#endif
+
+#define MAX_KERNEL_CODE_NUM 200
+
+typedef struct {
+ int is_compiled;
+ const char *kernel_string;
+} KernelCode;
+
+typedef struct {
+ const AVClass *class;
+ int log_offset;
+ void *log_ctx;
+ int init_count;
+ int opt_init_flag;
+ /**
+ * if set to 1, the OpenCL environment was created by the user and
+ * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper.
+ */
+ int is_user_created;
+ int platform_idx;
+ int device_idx;
+ cl_platform_id platform_id;
+ cl_device_type device_type;
+ cl_context context;
+ cl_device_id device_id;
+ cl_command_queue command_queue;
+ int kernel_code_count;
+ KernelCode kernel_code[MAX_KERNEL_CODE_NUM];
+ AVOpenCLDeviceList device_list;
+} OpenclContext;
+
+#define OFFSET(x) offsetof(OpenclContext, x)
+
+static const AVOption opencl_options[] = {
+ { "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
+ { "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX},
+ { NULL }
+};
+
+static const AVClass openclutils_class = {
+ .class_name = "OPENCLUTILS",
+ .option = opencl_options,
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+ .log_level_offset_offset = offsetof(OpenclContext, log_offset),
+ .parent_log_context_offset = offsetof(OpenclContext, log_ctx),
+};
+
+static OpenclContext opencl_ctx = {&openclutils_class};
+
+static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU};
+
+typedef struct {
+ int err_code;
+ const char *err_str;
+} OpenclErrorMsg;
+
+static const OpenclErrorMsg opencl_err_msg[] = {
+ {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"},
+ {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"},
+ {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"},
+ {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"},
+ {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"},
+ {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"},
+ {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"},
+ {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"},
+ {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"},
+ {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"},
+ {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"},
+ {CL_MAP_FAILURE, "MAP FAILURE"},
+ {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"},
+ {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"},
+ {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"},
+ {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"},
+ {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"},
+ {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"},
+ {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"},
+ {CL_INVALID_VALUE, "INVALID VALUE"},
+ {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"},
+ {CL_INVALID_PLATFORM, "INVALID PLATFORM"},
+ {CL_INVALID_DEVICE, "INVALID DEVICE"},
+ {CL_INVALID_CONTEXT, "INVALID CONTEXT"},
+ {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"},
+ {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"},
+ {CL_INVALID_HOST_PTR, "INVALID HOST PTR"},
+ {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"},
+ {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"},
+ {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"},
+ {CL_INVALID_SAMPLER, "INVALID SAMPLER"},
+ {CL_INVALID_BINARY, "INVALID BINARY"},
+ {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"},
+ {CL_INVALID_PROGRAM, "INVALID PROGRAM"},
+ {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"},
+ {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"},
+ {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"},
+ {CL_INVALID_KERNEL, "INVALID KERNEL"},
+ {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"},
+ {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"},
+ {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"},
+ {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"},
+ {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"},
+ {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"},
+ {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"},
+ {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"},
+ {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"},
+ {CL_INVALID_EVENT, "INVALID EVENT"},
+ {CL_INVALID_OPERATION, "INVALID OPERATION"},
+ {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"},
+ {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"},
+ {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"},
+ {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"},
+ {CL_INVALID_PROPERTY, "INVALID PROPERTY"},
+ {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"},
+ {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"},
+ {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"},
+ {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"},
+};
+
+const char *av_opencl_errstr(cl_int status)
+{
+ int i;
+ for (i = 0; i < FF_ARRAY_ELEMS(opencl_err_msg); i++) {
+ if (opencl_err_msg[i].err_code == status)
+ return opencl_err_msg[i].err_str;
+ }
+ return "unknown error";
+}
+
+static void free_device_list(AVOpenCLDeviceList *device_list)
+{
+ int i, j;
+ if (!device_list)
+ return;
+ for (i = 0; i < device_list->platform_num; i++) {
+ if (!device_list->platform_node[i])
+ continue;
+ for (j = 0; j < device_list->platform_node[i]->device_num; j++) {
+ av_freep(&(device_list->platform_node[i]->device_node[j]->device_name));
+ av_freep(&(device_list->platform_node[i]->device_node[j]));
+ }
+ av_freep(&device_list->platform_node[i]->device_node);
+ av_freep(&(device_list->platform_node[i]->platform_name));
+ av_freep(&device_list->platform_node[i]);
+ }
+ av_freep(&device_list->platform_node);
+ device_list->platform_num = 0;
+}
+
+static int get_device_list(AVOpenCLDeviceList *device_list)
+{
+ cl_int status;
+ int i, j, k, device_num, total_devices_num, ret = 0;
+ int *devices_num;
+ cl_platform_id *platform_ids = NULL;
+ cl_device_id *device_ids = NULL;
+ AVOpenCLDeviceNode *device_node = NULL;
+ size_t platform_name_size = 0;
+ size_t device_name_size = 0;
+ status = clGetPlatformIDs(0, NULL, &device_list->platform_num);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ platform_ids = av_mallocz_array(device_list->platform_num, sizeof(cl_platform_id));
+ if (!platform_ids)
+ return AVERROR(ENOMEM);
+ status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status));
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ device_list->platform_node = av_mallocz_array(device_list->platform_num, sizeof(AVOpenCLPlatformNode *));
+ if (!device_list->platform_node) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type));
+ if (!devices_num) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ for (i = 0; i < device_list->platform_num; i++) {
+ device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode));
+ if (!device_list->platform_node[i]) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ device_list->platform_node[i]->platform_id = platform_ids[i];
+ status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
+ 0, NULL, &platform_name_size);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not get size of platform name: %s\n", av_opencl_errstr(status));
+ } else {
+ device_list->platform_node[i]->platform_name = av_malloc(platform_name_size * sizeof(char));
+ if (!device_list->platform_node[i]->platform_name) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not allocate memory for device name: %s\n", av_opencl_errstr(status));
+ } else {
+ status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR,
+ platform_name_size * sizeof(char),
+ device_list->platform_node[i]->platform_name, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not get platform name: %s\n", av_opencl_errstr(status));
+ }
+ }
+ }
+ total_devices_num = 0;
+ for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
+ status = clGetDeviceIDs(device_list->platform_node[i]->platform_id,
+ device_type[j], 0, NULL, &devices_num[j]);
+ total_devices_num += devices_num[j];
+ }
+ device_list->platform_node[i]->device_node = av_mallocz_array(total_devices_num, sizeof(AVOpenCLDeviceNode *));
+ if (!device_list->platform_node[i]->device_node) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) {
+ if (devices_num[j]) {
+ device_ids = av_mallocz_array(devices_num[j], sizeof(cl_device_id));
+ if (!device_ids) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j],
+ devices_num[j], device_ids, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not get device ID: %s:\n", av_opencl_errstr(status));
+ av_freep(&device_ids);
+ continue;
+ }
+ for (k = 0; k < devices_num[j]; k++) {
+ device_num = device_list->platform_node[i]->device_num;
+ device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode));
+ if (!device_list->platform_node[i]->device_node[device_num]) {
+ ret = AVERROR(ENOMEM);
+ goto end;
+ }
+ device_node = device_list->platform_node[i]->device_node[device_num];
+ device_node->device_id = device_ids[k];
+ device_node->device_type = device_type[j];
+ status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
+ 0, NULL, &device_name_size);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not get size of device name: %s\n", av_opencl_errstr(status));
+ continue;
+ }
+ device_node->device_name = av_malloc(device_name_size * sizeof(char));
+ if (!device_node->device_name) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not allocate memory for device name: %s\n", av_opencl_errstr(status));
+ continue;
+ }
+ status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME,
+ device_name_size * sizeof(char),
+ device_node->device_name, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_WARNING,
+ "Could not get device name: %s\n", av_opencl_errstr(status));
+ continue;
+ }
+ device_list->platform_node[i]->device_num++;
+ }
+ av_freep(&device_ids);
+ }
+ }
+ }
+end:
+ av_freep(&platform_ids);
+ av_freep(&devices_num);
+ av_freep(&device_ids);
+ if (ret < 0)
+ free_device_list(device_list);
+ return ret;
+}
+
+int av_opencl_get_device_list(AVOpenCLDeviceList **device_list)
+{
+ int ret = 0;
+ *device_list = av_mallocz(sizeof(AVOpenCLDeviceList));
+ if (!(*device_list)) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n");
+ return AVERROR(ENOMEM);
+ }
+ ret = get_device_list(*device_list);
+ if (ret < 0) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n");
+ free_device_list(*device_list);
+ av_freep(device_list);
+ return ret;
+ }
+ return ret;
+}
+
+void av_opencl_free_device_list(AVOpenCLDeviceList **device_list)
+{
+ free_device_list(*device_list);
+ av_freep(device_list);
+}
+
+static inline int init_opencl_mtx(void)
+{
+#if HAVE_THREADS
+ if (!atomic_opencl_lock) {
+ int err;
+ pthread_mutex_t *tmp = av_malloc(sizeof(pthread_mutex_t));
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ if ((err = pthread_mutex_init(tmp, NULL))) {
+ av_free(tmp);
+ return AVERROR(err);
+ }
+ if (avpriv_atomic_ptr_cas(&atomic_opencl_lock, NULL, tmp)) {
+ pthread_mutex_destroy(tmp);
+ av_free(tmp);
+ }
+ }
+#endif
+ return 0;
+}
+
+int av_opencl_set_option(const char *key, const char *val)
+{
+ int ret = init_opencl_mtx( );
+ if (ret < 0)
+ return ret;
+ LOCK_OPENCL;
+ if (!opencl_ctx.opt_init_flag) {
+ av_opt_set_defaults(&opencl_ctx);
+ opencl_ctx.opt_init_flag = 1;
+ }
+ ret = av_opt_set(&opencl_ctx, key, val, 0);
+ UNLOCK_OPENCL;
+ return ret;
+}
+
+int av_opencl_get_option(const char *key, uint8_t **out_val)
+{
+ int ret = 0;
+ LOCK_OPENCL;
+ ret = av_opt_get(&opencl_ctx, key, 0, out_val);
+ UNLOCK_OPENCL;
+ return ret;
+}
+
+void av_opencl_free_option(void)
+{
+ /*FIXME: free openclutils context*/
+ LOCK_OPENCL;
+ av_opt_free(&opencl_ctx);
+ UNLOCK_OPENCL;
+}
+
+AVOpenCLExternalEnv *av_opencl_alloc_external_env(void)
+{
+ AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv));
+ if (!ext) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not malloc external opencl environment data space\n");
+ }
+ return ext;
+}
+
+void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env)
+{
+ av_freep(ext_opencl_env);
+}
+
+int av_opencl_register_kernel_code(const char *kernel_code)
+{
+ int i, ret = init_opencl_mtx( );
+ if (ret < 0)
+ return ret;
+ LOCK_OPENCL;
+ if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not register kernel code, maximum number of registered kernel code %d already reached\n",
+ MAX_KERNEL_CODE_NUM);
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
+ if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) {
+ av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n");
+ goto end;
+ }
+ }
+ opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code;
+ opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0;
+ opencl_ctx.kernel_code_count++;
+end:
+ UNLOCK_OPENCL;
+ return ret;
+}
+
+cl_program av_opencl_compile(const char *program_name, const char *build_opts)
+{
+ int i;
+ cl_int status;
+ int kernel_code_idx = 0;
+ const char *kernel_source;
+ size_t kernel_code_len;
+ char* ptr = NULL;
+ cl_program program = NULL;
+
+ LOCK_OPENCL;
+ for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
+ // identify a program using a unique name within the kernel source
+ ptr = av_stristr(opencl_ctx.kernel_code[i].kernel_string, program_name);
+ if (ptr && !opencl_ctx.kernel_code[i].is_compiled) {
+ kernel_source = opencl_ctx.kernel_code[i].kernel_string;
+ kernel_code_len = strlen(opencl_ctx.kernel_code[i].kernel_string);
+ kernel_code_idx = i;
+ break;
+ }
+ }
+ if (!kernel_source) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Unable to find OpenCL kernel source '%s'\n", program_name);
+ goto end;
+ }
+
+ /* create a CL program from kernel source */
+ program = clCreateProgramWithSource(opencl_ctx.context, 1, &kernel_source, &kernel_code_len, &status);
+ if(status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Unable to create OpenCL program '%s': %s\n", program_name, av_opencl_errstr(status));
+ program = NULL;
+ goto end;
+ }
+ status = clBuildProgram(program, 1, &(opencl_ctx.device_id), build_opts, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Compilation failed with OpenCL program: %s\n", program_name);
+ program = NULL;
+ goto end;
+ }
+
+ opencl_ctx.kernel_code[kernel_code_idx].is_compiled = 1;
+end:
+ UNLOCK_OPENCL;
+ return program;
+}
+
+cl_command_queue av_opencl_get_command_queue(void)
+{
+ return opencl_ctx.command_queue;
+}
+
+static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env)
+{
+ cl_int status;
+ cl_context_properties cps[3];
+ int i, ret = 0;
+ AVOpenCLDeviceNode *device_node = NULL;
+
+ if (ext_opencl_env) {
+ if (opencl_ctx->is_user_created)
+ return 0;
+ opencl_ctx->platform_id = ext_opencl_env->platform_id;
+ opencl_ctx->is_user_created = 1;
+ opencl_ctx->command_queue = ext_opencl_env->command_queue;
+ opencl_ctx->context = ext_opencl_env->context;
+ opencl_ctx->device_id = ext_opencl_env->device_id;
+ opencl_ctx->device_type = ext_opencl_env->device_type;
+ } else {
+ if (!opencl_ctx->is_user_created) {
+ if (!opencl_ctx->device_list.platform_num) {
+ ret = get_device_list(&opencl_ctx->device_list);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ if (opencl_ctx->platform_idx >= 0) {
+ if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) {
+ av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n");
+ return AVERROR(EINVAL);
+ }
+ if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) {
+ av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n",
+ opencl_ctx->platform_idx);
+ return AVERROR(EINVAL);
+ }
+ opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id;
+ } else {
+ /* get a usable platform by default*/
+ for (i = 0; i < opencl_ctx->device_list.platform_num; i++) {
+ if (opencl_ctx->device_list.platform_node[i]->device_num) {
+ opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id;
+ opencl_ctx->platform_idx = i;
+ break;
+ }
+ }
+ }
+ if (!opencl_ctx->platform_id) {
+ av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n");
+ return AVERROR_EXTERNAL;
+ }
+ /* get a usable device*/
+ if (opencl_ctx->device_idx >= 0) {
+ if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) {
+ av_log(opencl_ctx, AV_LOG_ERROR,
+ "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx);
+ return AVERROR(EINVAL);
+ }
+ } else {
+ opencl_ctx->device_idx = 0;
+ }
+
+ device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx];
+ opencl_ctx->device_id = device_node->device_id;
+ opencl_ctx->device_type = device_node->device_type;
+
+ /*
+ * Use available platform.
+ */
+ av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, Device Name: %s\n",
+ opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name,
+ device_node->device_name);
+ cps[0] = CL_CONTEXT_PLATFORM;
+ cps[1] = (cl_context_properties)opencl_ctx->platform_id;
+ cps[2] = 0;
+
+ opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type,
+ NULL, NULL, &status);
+ if (status != CL_SUCCESS) {
+ av_log(opencl_ctx, AV_LOG_ERROR,
+ "Could not get OpenCL context from device type: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id,
+ 0, &status);
+ if (status != CL_SUCCESS) {
+ av_log(opencl_ctx, AV_LOG_ERROR,
+ "Could not create OpenCL command queue: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ }
+ }
+ return ret;
+}
+
+int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env)
+{
+ int ret = init_opencl_mtx( );
+ if (ret < 0)
+ return ret;
+ LOCK_OPENCL;
+ if (!opencl_ctx.init_count) {
+ if (!opencl_ctx.opt_init_flag) {
+ av_opt_set_defaults(&opencl_ctx);
+ opencl_ctx.opt_init_flag = 1;
+ }
+ ret = init_opencl_env(&opencl_ctx, ext_opencl_env);
+ if (ret < 0)
+ goto end;
+ if (opencl_ctx.kernel_code_count <= 0) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "No kernel code is registered, compile kernel file failed\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ }
+ opencl_ctx.init_count++;
+end:
+ UNLOCK_OPENCL;
+ return ret;
+}
+
+void av_opencl_uninit(void)
+{
+ int i;
+ cl_int status;
+ LOCK_OPENCL;
+ opencl_ctx.init_count--;
+ if (opencl_ctx.is_user_created)
+ goto end;
+ if (opencl_ctx.init_count > 0)
+ goto end;
+ if (opencl_ctx.command_queue) {
+ status = clReleaseCommandQueue(opencl_ctx.command_queue);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not release OpenCL command queue: %s\n", av_opencl_errstr(status));
+ }
+ opencl_ctx.command_queue = NULL;
+ }
+ if (opencl_ctx.context) {
+ status = clReleaseContext(opencl_ctx.context);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not release OpenCL context: %s\n", av_opencl_errstr(status));
+ }
+ opencl_ctx.context = NULL;
+ }
+ for (i = 0; i < opencl_ctx.kernel_code_count; i++) {
+ opencl_ctx.kernel_code[i].is_compiled = 0;
+ }
+ free_device_list(&opencl_ctx.device_list);
+end:
+ if (opencl_ctx.init_count <= 0)
+ av_opt_free(&opencl_ctx); //FIXME: free openclutils context
+ UNLOCK_OPENCL;
+}
+
+int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr)
+{
+ cl_int status;
+ *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+void av_opencl_buffer_release(cl_mem *cl_buf)
+{
+ cl_int status = 0;
+ if (!cl_buf)
+ return;
+ status = clReleaseMemObject(*cl_buf);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not release OpenCL buffer: %s\n", av_opencl_errstr(status));
+ }
+ memset(cl_buf, 0, sizeof(*cl_buf));
+}
+
+int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size)
+{
+ cl_int status;
+ void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
+ CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size,
+ 0, NULL, NULL, &status);
+
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ memcpy(mapped, src_buf, buf_size);
+
+ status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size)
+{
+ cl_int status;
+ void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
+ CL_TRUE, CL_MAP_READ, 0, buf_size,
+ 0, NULL, NULL, &status);
+
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ memcpy(dst_buf, mapped, buf_size);
+
+ status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
+ uint8_t **src_data, int *plane_size, int plane_num)
+{
+ int i, buffer_size = 0;
+ uint8_t *temp;
+ cl_int status;
+ void *mapped;
+ if ((unsigned int)plane_num > 8) {
+ return AVERROR(EINVAL);
+ }
+ for (i = 0;i < plane_num;i++) {
+ buffer_size += plane_size[i];
+ }
+ if (buffer_size > cl_buffer_size) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Cannot write image to OpenCL buffer: buffer too small\n");
+ return AVERROR(EINVAL);
+ }
+ mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf,
+ CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset,
+ 0, NULL, NULL, &status);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ temp = mapped;
+ temp += dst_cl_offset;
+ for (i = 0; i < plane_num; i++) {
+ memcpy(temp, src_data[i], plane_size[i]);
+ temp += plane_size[i];
+ }
+ status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
+ cl_mem src_cl_buf, size_t cl_buffer_size)
+{
+ int i,buffer_size = 0,ret = 0;
+ uint8_t *temp;
+ void *mapped;
+ cl_int status;
+ if ((unsigned int)plane_num > 8) {
+ return AVERROR(EINVAL);
+ }
+ for (i = 0; i < plane_num; i++) {
+ buffer_size += plane_size[i];
+ }
+ if (buffer_size > cl_buffer_size) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Cannot write image to CPU buffer: OpenCL buffer too small\n");
+ return AVERROR(EINVAL);
+ }
+ mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf,
+ CL_TRUE, CL_MAP_READ, 0, buffer_size,
+ 0, NULL, NULL, &status);
+
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ temp = mapped;
+ if (ret >= 0) {
+ for (i = 0; i < plane_num; i++) {
+ memcpy(dst_data[i], temp, plane_size[i]);
+ temp += plane_size[i];
+ }
+ }
+ status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL);
+ if (status != CL_SUCCESS) {
+ av_log(&opencl_ctx, AV_LOG_ERROR,
+ "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status));
+ return AVERROR_EXTERNAL;
+ }
+ return 0;
+}
+
+int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device_node, cl_platform_id platform,
+ int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env))
+{
+ int64_t ret = 0;
+ cl_int status;
+ cl_context_properties cps[3];
+ AVOpenCLExternalEnv *ext_opencl_env = NULL;
+
+ ext_opencl_env = av_opencl_alloc_external_env();
+ ext_opencl_env->device_id = device_node->device_id;
+ ext_opencl_env->device_type = device_node->device_type;
+ av_log(&opencl_ctx, AV_LOG_VERBOSE, "Performing test on OpenCL device %s\n",
+ device_node->device_name);
+
+ cps[0] = CL_CONTEXT_PLATFORM;
+ cps[1] = (cl_context_properties)platform;
+ cps[2] = 0;
+ ext_opencl_env->context = clCreateContextFromType(cps, ext_opencl_env->device_type,
+ NULL, NULL, &status);
+ if (status != CL_SUCCESS || !ext_opencl_env->context) {
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ ext_opencl_env->command_queue = clCreateCommandQueue(ext_opencl_env->context,
+ ext_opencl_env->device_id, 0, &status);
+ if (status != CL_SUCCESS || !ext_opencl_env->command_queue) {
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ ret = benchmark(ext_opencl_env);
+ if (ret < 0)
+ av_log(&opencl_ctx, AV_LOG_ERROR, "Benchmark failed with OpenCL device %s\n",
+ device_node->device_name);
+end:
+ if (ext_opencl_env->command_queue)
+ clReleaseCommandQueue(ext_opencl_env->command_queue);
+ if (ext_opencl_env->context)
+ clReleaseContext(ext_opencl_env->context);
+ av_opencl_free_external_env(&ext_opencl_env);
+ return ret;
+}
diff --git a/libavutil/opencl.h b/libavutil/opencl.h
new file mode 100644
index 0000000000..e423e5588a
--- /dev/null
+++ b/libavutil/opencl.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com>
+ * Copyright (C) 2012 Li Cao <li@multicorewareinc.com>
+ * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.com>
+ * Copyright (C) 2013 Lenny Wang <lwanghpc@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
+ * OpenCL wrapper
+ *
+ * This interface is considered still experimental and its API and ABI may
+ * change without prior notice.
+ */
+
+#ifndef LIBAVUTIL_OPENCL_H
+#define LIBAVUTIL_OPENCL_H
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <stdint.h>
+#include "dict.h"
+
+#include "libavutil/version.h"
+
+#define AV_OPENCL_KERNEL( ... )# __VA_ARGS__
+
+typedef struct {
+ int device_type;
+ char *device_name;
+ cl_device_id device_id;
+} AVOpenCLDeviceNode;
+
+typedef struct {
+ cl_platform_id platform_id;
+ char *platform_name;
+ int device_num;
+ AVOpenCLDeviceNode **device_node;
+} AVOpenCLPlatformNode;
+
+typedef struct {
+ int platform_num;
+ AVOpenCLPlatformNode **platform_node;
+} AVOpenCLDeviceList;
+
+typedef struct {
+ cl_platform_id platform_id;
+ cl_device_type device_type;
+ cl_context context;
+ cl_device_id device_id;
+ cl_command_queue command_queue;
+ char *platform_name;
+} AVOpenCLExternalEnv;
+
+/**
+ * Get OpenCL device list.
+ *
+ * It must be freed with av_opencl_free_device_list().
+ *
+ * @param device_list pointer to OpenCL environment device list,
+ * should be released by av_opencl_free_device_list()
+ *
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_get_device_list(AVOpenCLDeviceList **device_list);
+
+/**
+ * Free OpenCL device list.
+ *
+ * @param device_list pointer to OpenCL environment device list
+ * created by av_opencl_get_device_list()
+ */
+void av_opencl_free_device_list(AVOpenCLDeviceList **device_list);
+
+/**
+ * Set option in the global OpenCL context.
+ *
+ * This options affect the operation performed by the next
+ * av_opencl_init() operation.
+ *
+ * The currently accepted options are:
+ * - platform: set index of platform in device list
+ * - device: set index of device in device list
+ *
+ * See reference "OpenCL Specification Version: 1.2 chapter 5.6.4".
+ *
+ * @param key option key
+ * @param val option value
+ * @return >=0 on success, a negative error code in case of failure
+ * @see av_opencl_get_option()
+ */
+int av_opencl_set_option(const char *key, const char *val);
+
+/**
+ * Get option value from the global OpenCL context.
+ *
+ * @param key option key
+ * @param out_val pointer to location where option value will be
+ * written, must be freed with av_freep()
+ * @return >=0 on success, a negative error code in case of failure
+ * @see av_opencl_set_option()
+ */
+int av_opencl_get_option(const char *key, uint8_t **out_val);
+
+/**
+ * Free option values of the global OpenCL context.
+ *
+ */
+void av_opencl_free_option(void);
+
+/**
+ * Allocate OpenCL external environment.
+ *
+ * It must be freed with av_opencl_free_external_env().
+ *
+ * @return pointer to allocated OpenCL external environment
+ */
+AVOpenCLExternalEnv *av_opencl_alloc_external_env(void);
+
+/**
+ * Free OpenCL external environment.
+ *
+ * @param ext_opencl_env pointer to OpenCL external environment
+ * created by av_opencl_alloc_external_env()
+ */
+void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env);
+
+/**
+ * Get OpenCL error string.
+ *
+ * @param status OpenCL error code
+ * @return OpenCL error string
+ */
+const char *av_opencl_errstr(cl_int status);
+
+/**
+ * Register kernel code.
+ *
+ * The registered kernel code is stored in a global context, and compiled
+ * in the runtime environment when av_opencl_init() is called.
+ *
+ * @param kernel_code kernel code to be compiled in the OpenCL runtime environment
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_register_kernel_code(const char *kernel_code);
+
+/**
+ * Initialize the run time OpenCL environment
+ *
+ * @param ext_opencl_env external OpenCL environment, created by an
+ * application program, ignored if set to NULL
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env);
+
+/**
+ * compile specific OpenCL kernel source
+ *
+ * @param program_name pointer to a program name used for identification
+ * @param build_opts pointer to a string that describes the preprocessor
+ * build options to be used for building the program
+ * @return a cl_program object
+ */
+cl_program av_opencl_compile(const char *program_name, const char* build_opts);
+
+/**
+ * get OpenCL command queue
+ *
+ * @return a cl_command_queue object
+ */
+cl_command_queue av_opencl_get_command_queue(void);
+
+/**
+ * Create OpenCL buffer.
+ *
+ * The buffer is used to save the data used or created by an OpenCL
+ * kernel.
+ * The created buffer must be released with av_opencl_buffer_release().
+ *
+ * See clCreateBuffer() function reference for more information about
+ * the parameters.
+ *
+ * @param cl_buf pointer to OpenCL buffer
+ * @param cl_buf_size size in bytes of the OpenCL buffer to create
+ * @param flags flags used to control buffer attributes
+ * @param host_ptr host pointer of the OpenCL buffer
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr);
+
+/**
+ * Write OpenCL buffer with data from src_buf.
+ *
+ * @param dst_cl_buf pointer to OpenCL destination buffer
+ * @param src_buf pointer to source buffer
+ * @param buf_size size in bytes of the source and destination buffers
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size);
+
+/**
+ * Read data from OpenCL buffer to memory buffer.
+ *
+ * @param dst_buf pointer to destination buffer (CPU memory)
+ * @param src_cl_buf pointer to source OpenCL buffer
+ * @param buf_size size in bytes of the source and destination buffers
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size);
+
+/**
+ * Write image data from memory to OpenCL buffer.
+ *
+ * The source must be an array of pointers to image plane buffers.
+ *
+ * @param dst_cl_buf pointer to destination OpenCL buffer
+ * @param dst_cl_buf_size size in bytes of OpenCL buffer
+ * @param dst_cl_buf_offset the offset of the OpenCL buffer start position
+ * @param src_data array of pointers to source plane buffers
+ * @param src_plane_sizes array of sizes in bytes of the source plane buffers
+ * @param src_plane_num number of source image planes
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset,
+ uint8_t **src_data, int *plane_size, int plane_num);
+
+/**
+ * Read image data from OpenCL buffer.
+ *
+ * @param dst_data array of pointers to destination plane buffers
+ * @param dst_plane_sizes array of pointers to destination plane buffers
+ * @param dst_plane_num number of destination image planes
+ * @param src_cl_buf pointer to source OpenCL buffer
+ * @param src_cl_buf_size size in bytes of OpenCL buffer
+ * @return >=0 on success, a negative error code in case of failure
+ */
+int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num,
+ cl_mem src_cl_buf, size_t cl_buffer_size);
+
+/**
+ * Release OpenCL buffer.
+ *
+ * @param cl_buf pointer to OpenCL buffer to release, which was
+ * previously filled with av_opencl_buffer_create()
+ */
+void av_opencl_buffer_release(cl_mem *cl_buf);
+
+/**
+ * Release OpenCL environment.
+ *
+ * The OpenCL environment is effectively released only if all the created
+ * kernels had been released with av_opencl_release_kernel().
+ */
+void av_opencl_uninit(void);
+
+/**
+ * Benchmark an OpenCL device with a user defined callback function. This function
+ * sets up an external OpenCL environment including context and command queue on
+ * the device then tears it down in the end. The callback function should perform
+ * the rest of the work.
+ *
+ * @param device pointer to the OpenCL device to be used
+ * @param platform cl_platform_id handle to which the device belongs to
+ * @param benchmark callback function to perform the benchmark, return a
+ * negative value in case of failure
+ * @return the score passed from the callback function, a negative error code in case
+ * of failure
+ */
+int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device, cl_platform_id platform,
+ int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env));
+
+#endif /* LIBAVUTIL_OPENCL_H */
diff --git a/libavutil/opencl_internal.c b/libavutil/opencl_internal.c
new file mode 100644
index 0000000000..bdb41936fa
--- /dev/null
+++ b/libavutil/opencl_internal.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com>
+ * Copyright (C) 2012 Li Cao <li@multicorewareinc.com>
+ * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.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
+ */
+
+#include "opencl_internal.h"
+#include "libavutil/log.h"
+
+int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...)
+{
+ int ret = 0;
+ va_list arg_ptr;
+ void *param;
+ size_t param_size;
+ cl_int status;
+ if (!opencl_param->kernel) {
+ av_log(opencl_param->ctx, AV_LOG_ERROR, "OpenCL kernel must be set\n");
+ return AVERROR(EINVAL);
+ }
+ va_start(arg_ptr, opencl_param);
+ do {
+ param = va_arg(arg_ptr, void *);
+ if (!param)
+ break;
+ param_size = va_arg(arg_ptr, size_t);
+ if (!param_size) {
+ av_log(opencl_param->ctx, AV_LOG_ERROR, "Parameter size must not be 0\n");
+ ret = AVERROR(EINVAL);
+ goto end;
+ }
+ status = clSetKernelArg(opencl_param->kernel, opencl_param->param_num, param_size, param);
+ if (status != CL_SUCCESS) {
+ av_log(opencl_param->ctx, AV_LOG_ERROR, "Cannot set kernel argument: %s\n", av_opencl_errstr(status));
+ ret = AVERROR_EXTERNAL;
+ goto end;
+ }
+ opencl_param->param_num++;
+ } while (param && param_size);
+end:
+ va_end(arg_ptr);
+ return ret;
+}
diff --git a/libavutil/opencl_internal.h b/libavutil/opencl_internal.h
new file mode 100644
index 0000000000..dacd930ac9
--- /dev/null
+++ b/libavutil/opencl_internal.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Peng Gao <peng@multicorewareinc.com>
+ * Copyright (C) 2012 Li Cao <li@multicorewareinc.com>
+ * Copyright (C) 2012 Wei Gao <weigao@multicorewareinc.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
+ */
+
+#include "opencl.h"
+
+#define FF_OPENCL_PARAM_INFO(a) ((void*)(&(a))), (sizeof(a))
+
+typedef struct {
+ cl_kernel kernel;
+ int param_num;
+ void *ctx;
+} FFOpenclParam;
+
+int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...);
diff --git a/libavutil/opt.c b/libavutil/opt.c
index b3435e0f0e..62db1b50b7 100644
--- a/libavutil/opt.c
+++ b/libavutil/opt.c
@@ -2,20 +2,20 @@
* AVOptions
* Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,34 +27,56 @@
#include "avutil.h"
#include "avstring.h"
+#include "channel_layout.h"
#include "common.h"
#include "opt.h"
#include "eval.h"
#include "dict.h"
#include "log.h"
+#include "parseutils.h"
+#include "pixdesc.h"
#include "mathematics.h"
+#include "samplefmt.h"
+#include "bprint.h"
-const AVOption *av_opt_next(void *obj, const AVOption *last)
+#include <float.h>
+
+#if FF_API_OLD_AVOPTIONS
+const AVOption *av_next_option(FF_CONST_AVUTIL55 void *obj, const AVOption *last)
+{
+ return av_opt_next(obj, last);
+}
+#endif
+
+const AVOption *av_opt_next(FF_CONST_AVUTIL55 void *obj, const AVOption *last)
{
- AVClass *class = *(AVClass**)obj;
- if (!last && class->option && class->option[0].name)
+ const AVClass *class;
+ if (!obj)
+ return NULL;
+ class = *(const AVClass**)obj;
+ if (!last && class && class->option && class->option[0].name)
return class->option;
if (last && last[1].name)
return ++last;
return NULL;
}
-static int read_number(const AVOption *o, void *dst, double *num, int *den, int64_t *intnum)
+static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum)
{
switch (o->type) {
case AV_OPT_TYPE_FLAGS: *intnum = *(unsigned int*)dst;return 0;
+ case AV_OPT_TYPE_PIXEL_FMT: *intnum = *(enum AVPixelFormat *)dst;return 0;
+ case AV_OPT_TYPE_SAMPLE_FMT:*intnum = *(enum AVSampleFormat*)dst;return 0;
case AV_OPT_TYPE_INT: *intnum = *(int *)dst;return 0;
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ case AV_OPT_TYPE_DURATION:
case AV_OPT_TYPE_INT64: *intnum = *(int64_t *)dst;return 0;
case AV_OPT_TYPE_FLOAT: *num = *(float *)dst;return 0;
case AV_OPT_TYPE_DOUBLE: *num = *(double *)dst;return 0;
case AV_OPT_TYPE_RATIONAL: *intnum = ((AVRational*)dst)->num;
*den = ((AVRational*)dst)->den;
return 0;
+ case AV_OPT_TYPE_CONST: *num = o->default_val.dbl; return 0;
}
return AVERROR(EINVAL);
}
@@ -63,14 +85,28 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int
{
if (o->type != AV_OPT_TYPE_FLAGS &&
(o->max * den < num * intnum || o->min * den > num * intnum)) {
- av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range\n",
- num*intnum/den, o->name);
+ num = den ? num*intnum/den : (num*intnum ? INFINITY : NAN);
+ av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n",
+ num, o->name, o->min, o->max);
return AVERROR(ERANGE);
}
+ if (o->type == AV_OPT_TYPE_FLAGS) {
+ double d = num*intnum/den;
+ if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) {
+ av_log(obj, AV_LOG_ERROR,
+ "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n",
+ num*intnum/den, o->name);
+ return AVERROR(ERANGE);
+ }
+ }
switch (o->type) {
+ case AV_OPT_TYPE_PIXEL_FMT: *(enum AVPixelFormat *)dst = llrint(num/den) * intnum; break;
+ case AV_OPT_TYPE_SAMPLE_FMT:*(enum AVSampleFormat*)dst = llrint(num/den) * intnum; break;
case AV_OPT_TYPE_FLAGS:
case AV_OPT_TYPE_INT: *(int *)dst= llrint(num/den)*intnum; break;
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
case AV_OPT_TYPE_INT64: *(int64_t *)dst= llrint(num/den)*intnum; break;
case AV_OPT_TYPE_FLOAT: *(float *)dst= num*intnum/den; break;
case AV_OPT_TYPE_DOUBLE:*(double *)dst= num*intnum/den; break;
@@ -84,20 +120,6 @@ static int write_number(void *obj, const AVOption *o, void *dst, double num, int
return 0;
}
-static const double const_values[] = {
- M_PI,
- M_E,
- FF_QP2LAMBDA,
- 0
-};
-
-static const char * const const_names[] = {
- "PI",
- "E",
- "QP2LAMBDA",
- 0
-};
-
static int hexchar2int(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
@@ -109,11 +131,14 @@ static int set_string_binary(void *obj, const AVOption *o, const char *val, uint
{
int *lendst = (int *)(dst + 1);
uint8_t *bin, *ptr;
- int len = strlen(val);
+ int len;
av_freep(dst);
*lendst = 0;
+ if (!val || !(len = strlen(val)))
+ return 0;
+
if (len & 1)
return AVERROR(EINVAL);
len /= 2;
@@ -151,37 +176,69 @@ static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **d
static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst)
{
- int ret = 0, notfirst = 0;
+ int ret = 0;
+ int num, den;
+ char c;
+
+ if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) {
+ if ((ret = write_number(obj, o, dst, 1, den, num)) >= 0)
+ return ret;
+ ret = 0;
+ }
+
for (;;) {
- int i, den = 1;
+ int i = 0;
char buf[256];
int cmd = 0;
- double d, num = 1;
+ double d;
int64_t intnum = 1;
- i = 0;
- if (*val == '+' || *val == '-') {
- if (o->type == AV_OPT_TYPE_FLAGS)
+ if (o->type == AV_OPT_TYPE_FLAGS) {
+ if (*val == '+' || *val == '-')
cmd = *(val++);
- else if (!notfirst)
- buf[i++] = *val;
+ for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
+ buf[i] = val[i];
+ buf[i] = 0;
}
- for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++)
- buf[i] = val[i];
- buf[i] = 0;
-
{
- const AVOption *o_named = av_opt_find(target_obj, buf, o->unit, 0, 0);
+ const AVOption *o_named = av_opt_find(target_obj, i ? buf : val, o->unit, 0, 0);
+ int res;
+ int ci = 0;
+ double const_values[64];
+ const char * const_names[64];
if (o_named && o_named->type == AV_OPT_TYPE_CONST)
d = DEFAULT_NUMVAL(o_named);
- else if (!strcmp(buf, "default")) d = DEFAULT_NUMVAL(o);
- else if (!strcmp(buf, "max" )) d = o->max;
- else if (!strcmp(buf, "min" )) d = o->min;
- else if (!strcmp(buf, "none" )) d = 0;
- else if (!strcmp(buf, "all" )) d = ~0;
else {
- int res = av_expr_parse_and_eval(&d, buf, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, obj);
+ if (o->unit) {
+ for (o_named = NULL; o_named = av_opt_next(target_obj, o_named); ) {
+ if (o_named->type == AV_OPT_TYPE_CONST &&
+ o_named->unit &&
+ !strcmp(o_named->unit, o->unit)) {
+ if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) {
+ av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit);
+ return AVERROR_PATCHWELCOME;
+ }
+ const_names [ci ] = o_named->name;
+ const_values[ci++] = DEFAULT_NUMVAL(o_named);
+ }
+ }
+ }
+ const_names [ci ] = "default";
+ const_values[ci++] = DEFAULT_NUMVAL(o);
+ const_names [ci ] = "max";
+ const_values[ci++] = o->max;
+ const_names [ci ] = "min";
+ const_values[ci++] = o->min;
+ const_names [ci ] = "none";
+ const_values[ci++] = 0;
+ const_names [ci ] = "all";
+ const_values[ci++] = ~0;
+ const_names [ci] = NULL;
+ const_values[ci] = 0;
+
+ res = av_expr_parse_and_eval(&d, i ? buf : val, const_names,
+ const_values, NULL, NULL, NULL, NULL, NULL, 0, obj);
if (res < 0) {
av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val);
return res;
@@ -192,30 +249,138 @@ static int set_string_number(void *obj, void *target_obj, const AVOption *o, con
read_number(o, dst, NULL, NULL, &intnum);
if (cmd == '+') d = intnum | (int64_t)d;
else if (cmd == '-') d = intnum &~(int64_t)d;
- } else {
- read_number(o, dst, &num, &den, &intnum);
- if (cmd == '+') d = notfirst*num*intnum/den + d;
- else if (cmd == '-') d = notfirst*num*intnum/den - d;
}
if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0)
return ret;
val += i;
- if (!*val)
+ if (!i || !*val)
return 0;
- notfirst = 1;
}
return 0;
}
+static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst)
+{
+ int ret;
+
+ if (!val || !strcmp(val, "none")) {
+ dst[0] =
+ dst[1] = 0;
+ return 0;
+ }
+ ret = av_parse_video_size(dst, dst + 1, val);
+ if (ret < 0)
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as image size\n", val);
+ return ret;
+}
+
+static int set_string_video_rate(void *obj, const AVOption *o, const char *val, AVRational *dst)
+{
+ int ret;
+ if (!val) {
+ ret = AVERROR(EINVAL);
+ } else {
+ ret = av_parse_video_rate(dst, val);
+ }
+ if (ret < 0)
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as video rate\n", val);
+ return ret;
+}
+
+static int set_string_color(void *obj, const AVOption *o, const char *val, uint8_t *dst)
+{
+ int ret;
+
+ if (!val) {
+ return 0;
+ } else {
+ ret = av_parse_color(dst, val, -1, obj);
+ if (ret < 0)
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as color\n", val);
+ return ret;
+ }
+ return 0;
+}
+
+static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst,
+ int fmt_nb, int ((*get_fmt)(const char *)), const char *desc)
+{
+ int fmt, min, max;
+
+ if (!val || !strcmp(val, "none")) {
+ fmt = -1;
+ } else {
+ fmt = get_fmt(val);
+ if (fmt == -1) {
+ char *tail;
+ fmt = strtol(val, &tail, 0);
+ if (*tail || (unsigned)fmt >= fmt_nb) {
+ av_log(obj, AV_LOG_ERROR,
+ "Unable to parse option value \"%s\" as %s\n", val, desc);
+ return AVERROR(EINVAL);
+ }
+ }
+ }
+
+ min = FFMAX(o->min, -1);
+ max = FFMIN(o->max, fmt_nb-1);
+
+ // hack for compatibility with old ffmpeg
+ if(min == 0 && max == 0) {
+ min = -1;
+ max = fmt_nb-1;
+ }
+
+ if (fmt < min || fmt > max) {
+ av_log(obj, AV_LOG_ERROR,
+ "Value %d for parameter '%s' out of %s format range [%d - %d]\n",
+ fmt, o->name, desc, min, max);
+ return AVERROR(ERANGE);
+ }
+
+ *(int *)dst = fmt;
+ return 0;
+}
+
+static int set_string_pixel_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst)
+{
+ return set_string_fmt(obj, o, val, dst,
+ AV_PIX_FMT_NB, av_get_pix_fmt, "pixel format");
+}
+
+static int set_string_sample_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst)
+{
+ return set_string_fmt(obj, o, val, dst,
+ AV_SAMPLE_FMT_NB, av_get_sample_fmt, "sample format");
+}
+
+#if FF_API_OLD_AVOPTIONS
+int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out)
+{
+ const AVOption *o = av_opt_find(obj, name, NULL, 0, 0);
+ if (o_out)
+ *o_out = o;
+ return av_opt_set(obj, name, val, 0);
+}
+#endif
+
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
+ int ret = 0;
void *dst, *target_obj;
const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
if (!o || !target_obj)
return AVERROR_OPTION_NOT_FOUND;
- if (!val || o->flags & AV_OPT_FLAG_READONLY)
+ if (!val && (o->type != AV_OPT_TYPE_STRING &&
+ o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT &&
+ o->type != AV_OPT_TYPE_IMAGE_SIZE && o->type != AV_OPT_TYPE_VIDEO_RATE &&
+ o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR &&
+ o->type != AV_OPT_TYPE_CHANNEL_LAYOUT))
+ return AVERROR(EINVAL);
+
+ if (o->flags & AV_OPT_FLAG_READONLY)
return AVERROR(EINVAL);
dst = ((uint8_t*)target_obj) + o->offset;
@@ -228,6 +393,38 @@ int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
case AV_OPT_TYPE_FLOAT:
case AV_OPT_TYPE_DOUBLE:
case AV_OPT_TYPE_RATIONAL: return set_string_number(obj, target_obj, o, val, dst);
+ case AV_OPT_TYPE_IMAGE_SIZE: return set_string_image_size(obj, o, val, dst);
+ case AV_OPT_TYPE_VIDEO_RATE: return set_string_video_rate(obj, o, val, dst);
+ case AV_OPT_TYPE_PIXEL_FMT: return set_string_pixel_fmt(obj, o, val, dst);
+ case AV_OPT_TYPE_SAMPLE_FMT: return set_string_sample_fmt(obj, o, val, dst);
+ case AV_OPT_TYPE_DURATION:
+ if (!val) {
+ *(int64_t *)dst = 0;
+ return 0;
+ } else {
+ if ((ret = av_parse_time(dst, val, 1)) < 0)
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val);
+ return ret;
+ }
+ break;
+ case AV_OPT_TYPE_COLOR: return set_string_color(obj, o, val, dst);
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ if (!val || !strcmp(val, "none")) {
+ *(int64_t *)dst = 0;
+ } else {
+#if FF_API_GET_CHANNEL_LAYOUT_COMPAT
+ int64_t cl = ff_get_channel_layout(val, 0);
+#else
+ int64_t cl = av_get_channel_layout(val);
+#endif
+ if (!cl) {
+ av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val);
+ ret = AVERROR(EINVAL);
+ }
+ *(int64_t *)dst = cl;
+ return ret;
+ }
+ break;
}
av_log(obj, AV_LOG_ERROR, "Invalid option type.\n");
@@ -265,6 +462,32 @@ static int set_number(void *obj, const char *name, double num, int den, int64_t
return write_number(obj, o, dst, num, den, intnum);
}
+#if FF_API_OLD_AVOPTIONS
+const AVOption *av_set_double(void *obj, const char *name, double n)
+{
+ const AVOption *o = av_opt_find(obj, name, NULL, 0, 0);
+ if (set_number(obj, name, n, 1, 1, 0) < 0)
+ return NULL;
+ return o;
+}
+
+const AVOption *av_set_q(void *obj, const char *name, AVRational n)
+{
+ const AVOption *o = av_opt_find(obj, name, NULL, 0, 0);
+ if (set_number(obj, name, n.num, n.den, 1, 0) < 0)
+ return NULL;
+ return o;
+}
+
+const AVOption *av_set_int(void *obj, const char *name, int64_t n)
+{
+ const AVOption *o = av_opt_find(obj, name, NULL, 0, 0);
+ if (set_number(obj, name, 1, 1, n, 0) < 0)
+ return NULL;
+ return o;
+}
+#endif
+
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
{
return set_number(obj, name, 1, 1, val, search_flags);
@@ -294,8 +517,8 @@ int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int
if (o->type != AV_OPT_TYPE_BINARY || o->flags & AV_OPT_FLAG_READONLY)
return AVERROR(EINVAL);
- ptr = av_malloc(len);
- if (!ptr)
+ ptr = len ? av_malloc(len) : NULL;
+ if (len && !ptr)
return AVERROR(ENOMEM);
dst = (uint8_t **)(((uint8_t *)target_obj) + o->offset);
@@ -304,11 +527,147 @@ int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int
av_free(*dst);
*dst = ptr;
*lendst = len;
- memcpy(ptr, val, len);
+ if (len)
+ memcpy(ptr, val, len);
+
+ return 0;
+}
+
+int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags)
+{
+ void *target_obj;
+ const AVOption *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_IMAGE_SIZE) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value set by option '%s' is not an image size.\n", o->name);
+ return AVERROR(EINVAL);
+ }
+ if (w<0 || h<0) {
+ av_log(obj, AV_LOG_ERROR,
+ "Invalid negative size value %dx%d for size '%s'\n", w, h, o->name);
+ return AVERROR(EINVAL);
+ }
+ *(int *)(((uint8_t *)target_obj) + o->offset) = w;
+ *(int *)(((uint8_t *)target_obj+sizeof(int)) + o->offset) = h;
+ return 0;
+}
+
+int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags)
+{
+ void *target_obj;
+ const AVOption *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_VIDEO_RATE) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value set by option '%s' is not a video rate.\n", o->name);
+ return AVERROR(EINVAL);
+ }
+ if (val.num <= 0 || val.den <= 0)
+ return AVERROR(EINVAL);
+ return set_number(obj, name, val.num, val.den, 1, search_flags);
+}
+
+static int set_format(void *obj, const char *name, int fmt, int search_flags,
+ enum AVOptionType type, const char *desc, int nb_fmts)
+{
+ void *target_obj;
+ const AVOption *o = av_opt_find2(obj, name, NULL, 0,
+ search_flags, &target_obj);
+ int min, max;
+
+ if (!o || !target_obj)
+ return AVERROR_OPTION_NOT_FOUND;
+ if (o->type != type) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value set by option '%s' is not a %s format", name, desc);
+ return AVERROR(EINVAL);
+ }
+
+ min = FFMAX(o->min, -1);
+ max = FFMIN(o->max, nb_fmts-1);
+
+ if (fmt < min || fmt > max) {
+ av_log(obj, AV_LOG_ERROR,
+ "Value %d for parameter '%s' out of %s format range [%d - %d]\n",
+ fmt, name, desc, min, max);
+ return AVERROR(ERANGE);
+ }
+ *(int *)(((uint8_t *)target_obj) + o->offset) = fmt;
+ return 0;
+}
+
+int av_opt_set_pixel_fmt(void *obj, const char *name, enum AVPixelFormat fmt, int search_flags)
+{
+ return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_PIXEL_FMT, "pixel", AV_PIX_FMT_NB);
+}
+int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags)
+{
+ return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_SAMPLE_FMT, "sample", AV_SAMPLE_FMT_NB);
+}
+
+int av_opt_set_channel_layout(void *obj, const char *name, int64_t cl, int search_flags)
+{
+ void *target_obj;
+ const AVOption *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_CHANNEL_LAYOUT) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value set by option '%s' is not a channel layout.\n", o->name);
+ return AVERROR(EINVAL);
+ }
+ *(int64_t *)(((uint8_t *)target_obj) + o->offset) = cl;
return 0;
}
+#if FF_API_OLD_AVOPTIONS
+/**
+ *
+ * @param buf a buffer which is used for returning non string values as strings, can be NULL
+ * @param buf_len allocated length in bytes of buf
+ */
+const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len)
+{
+ const AVOption *o = av_opt_find(obj, name, NULL, 0, AV_OPT_SEARCH_CHILDREN);
+ void *dst;
+ uint8_t *bin;
+ int len, i;
+ if (!o)
+ return NULL;
+ if (o->type != AV_OPT_TYPE_STRING && (!buf || !buf_len))
+ return NULL;
+
+ dst= ((uint8_t*)obj) + o->offset;
+ if (o_out) *o_out= o;
+
+ switch (o->type) {
+ case AV_OPT_TYPE_FLAGS: snprintf(buf, buf_len, "0x%08X",*(int *)dst);break;
+ case AV_OPT_TYPE_INT: snprintf(buf, buf_len, "%d" , *(int *)dst);break;
+ case AV_OPT_TYPE_INT64: snprintf(buf, buf_len, "%"PRId64, *(int64_t*)dst);break;
+ case AV_OPT_TYPE_FLOAT: snprintf(buf, buf_len, "%f" , *(float *)dst);break;
+ case AV_OPT_TYPE_DOUBLE: snprintf(buf, buf_len, "%f" , *(double *)dst);break;
+ case AV_OPT_TYPE_RATIONAL: snprintf(buf, buf_len, "%d/%d", ((AVRational*)dst)->num, ((AVRational*)dst)->den);break;
+ case AV_OPT_TYPE_CONST: snprintf(buf, buf_len, "%f" , o->default_val.dbl);break;
+ case AV_OPT_TYPE_STRING: return *(void**)dst;
+ case AV_OPT_TYPE_BINARY:
+ len = *(int*)(((uint8_t *)dst) + sizeof(uint8_t *));
+ if (len >= (buf_len + 1)/2) return NULL;
+ bin = *(uint8_t**)dst;
+ for (i = 0; i < len; i++) snprintf(buf + i*2, 3, "%02X", bin[i]);
+ break;
+ default: return NULL;
+ }
+ return buf;
+}
+#endif
+
int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags)
{
void *target_obj;
@@ -333,8 +692,9 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
uint8_t *bin, buf[128];
int len, i, ret;
+ int64_t i64;
- if (!o || !target_obj)
+ if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST))
return AVERROR_OPTION_NOT_FOUND;
dst = (uint8_t*)target_obj + o->offset;
@@ -346,7 +706,9 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
case AV_OPT_TYPE_INT64: ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t*)dst);break;
case AV_OPT_TYPE_FLOAT: ret = snprintf(buf, sizeof(buf), "%f" , *(float *)dst);break;
case AV_OPT_TYPE_DOUBLE: ret = snprintf(buf, sizeof(buf), "%f" , *(double *)dst);break;
+ case AV_OPT_TYPE_VIDEO_RATE:
case AV_OPT_TYPE_RATIONAL: ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational*)dst)->num, ((AVRational*)dst)->den);break;
+ case AV_OPT_TYPE_CONST: ret = snprintf(buf, sizeof(buf), "%f" , o->default_val.dbl);break;
case AV_OPT_TYPE_STRING:
if (*(uint8_t**)dst)
*out_val = av_strdup(*(uint8_t**)dst);
@@ -359,10 +721,38 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
return AVERROR(EINVAL);
if (!(*out_val = av_malloc(len*2 + 1)))
return AVERROR(ENOMEM);
+ if (!len) {
+ *out_val[0] = '\0';
+ return 0;
+ }
bin = *(uint8_t**)dst;
for (i = 0; i < len; i++)
snprintf(*out_val + i*2, 3, "%02X", bin[i]);
return 0;
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ ret = snprintf(buf, sizeof(buf), "%dx%d", ((int *)dst)[0], ((int *)dst)[1]);
+ break;
+ case AV_OPT_TYPE_PIXEL_FMT:
+ ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none"));
+ break;
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none"));
+ break;
+ case AV_OPT_TYPE_DURATION:
+ i64 = *(int64_t *)dst;
+ ret = snprintf(buf, sizeof(buf), "%"PRIi64":%02d:%02d.%06d",
+ i64 / 3600000000, (int)((i64 / 60000000) % 60),
+ (int)((i64 / 1000000) % 60), (int)(i64 % 1000000));
+ break;
+ case AV_OPT_TYPE_COLOR:
+ ret = snprintf(buf, sizeof(buf), "0x%02x%02x%02x%02x",
+ (int)((uint8_t *)dst)[0], (int)((uint8_t *)dst)[1],
+ (int)((uint8_t *)dst)[2], (int)((uint8_t *)dst)[3]);
+ break;
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ i64 = *(int64_t *)dst;
+ ret = snprintf(buf, sizeof(buf), "0x%"PRIx64, i64);
+ break;
default:
return AVERROR(EINVAL);
}
@@ -373,7 +763,7 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
return *out_val ? 0 : AVERROR(ENOMEM);
}
-static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum,
+static int get_number(void *obj, const char *name, const AVOption **o_out, double *num, int *den, int64_t *intnum,
int search_flags)
{
void *dst, *target_obj;
@@ -383,6 +773,8 @@ static int get_number(void *obj, const char *name, double *num, int *den, int64_
dst = ((uint8_t*)target_obj) + o->offset;
+ if (o_out) *o_out= o;
+
return read_number(o, dst, num, den, intnum);
error:
@@ -390,13 +782,51 @@ error:
return -1;
}
+#if FF_API_OLD_AVOPTIONS
+double av_get_double(void *obj, const char *name, const AVOption **o_out)
+{
+ int64_t intnum=1;
+ double num=1;
+ int den=1;
+
+ if (get_number(obj, name, o_out, &num, &den, &intnum, 0) < 0)
+ return NAN;
+ return num*intnum/den;
+}
+
+AVRational av_get_q(void *obj, const char *name, const AVOption **o_out)
+{
+ int64_t intnum=1;
+ double num=1;
+ int den=1;
+
+ if (get_number(obj, name, o_out, &num, &den, &intnum, 0) < 0)
+ return (AVRational){0, 0};
+ if (num == 1.0 && (int)intnum == intnum)
+ return (AVRational){intnum, den};
+ else
+ return av_d2q(num*intnum/den, 1<<24);
+}
+
+int64_t av_get_int(void *obj, const char *name, const AVOption **o_out)
+{
+ int64_t intnum=1;
+ double num=1;
+ int den=1;
+
+ if (get_number(obj, name, o_out, &num, &den, &intnum, 0) < 0)
+ return -1;
+ return num*intnum/den;
+}
+#endif
+
int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *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)
+ if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0)
return ret;
*out_val = num*intnum/den;
return 0;
@@ -408,7 +838,7 @@ int av_opt_get_double(void *obj, const char *name, int search_flags, double *out
double num = 1;
int ret, den = 1;
- if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
+ if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0)
return ret;
*out_val = num*intnum/den;
return 0;
@@ -420,7 +850,41 @@ int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_
double num = 1;
int ret, den = 1;
- if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0)
+ if ((ret = get_number(obj, name, NULL, &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;
+}
+
+int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out)
+{
+ void *dst, *target_obj;
+ const AVOption *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_IMAGE_SIZE) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value for option '%s' is not an image size.\n", name);
+ return AVERROR(EINVAL);
+ }
+
+ dst = ((uint8_t*)target_obj) + o->offset;
+ if (w_out) *w_out = *(int *)dst;
+ if (h_out) *h_out = *((int *)dst+1);
+ return 0;
+}
+
+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, NULL, &num, &den, &intnum, search_flags)) < 0)
return ret;
if (num == 1.0 && (int)intnum == intnum)
@@ -430,6 +894,51 @@ int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_
return 0;
}
+static int get_format(void *obj, const char *name, int search_flags, int *out_fmt,
+ enum AVOptionType type, const char *desc)
+{
+ void *dst, *target_obj;
+ const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj);
+ if (!o || !target_obj)
+ return AVERROR_OPTION_NOT_FOUND;
+ if (o->type != type) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value for option '%s' is not a %s format.\n", desc, name);
+ return AVERROR(EINVAL);
+ }
+
+ dst = ((uint8_t*)target_obj) + o->offset;
+ *out_fmt = *(int *)dst;
+ return 0;
+}
+
+int av_opt_get_pixel_fmt(void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt)
+{
+ return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_PIXEL_FMT, "pixel");
+}
+
+int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt)
+{
+ return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample");
+}
+
+int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *cl)
+{
+ void *dst, *target_obj;
+ const AVOption *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_CHANNEL_LAYOUT) {
+ av_log(obj, AV_LOG_ERROR,
+ "The value for option '%s' is not a channel layout.\n", name);
+ return AVERROR(EINVAL);
+ }
+
+ dst = ((uint8_t*)target_obj) + o->offset;
+ *cl = *(int64_t *)dst;
+ return 0;
+}
+
int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val)
{
void *target_obj;
@@ -460,10 +969,45 @@ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name)
return res & flag->default_val.i64;
}
+static void log_value(void *av_log_obj, int level, double d)
+{
+ if (d == INT_MAX) {
+ av_log(av_log_obj, level, "INT_MAX");
+ } else if (d == INT_MIN) {
+ av_log(av_log_obj, level, "INT_MIN");
+ } else if (d == UINT32_MAX) {
+ av_log(av_log_obj, level, "UINT32_MAX");
+ } else if (d == (double)INT64_MAX) {
+ av_log(av_log_obj, level, "I64_MAX");
+ } else if (d == INT64_MIN) {
+ av_log(av_log_obj, level, "I64_MIN");
+ } else if (d == FLT_MAX) {
+ av_log(av_log_obj, level, "FLT_MAX");
+ } else if (d == FLT_MIN) {
+ av_log(av_log_obj, level, "FLT_MIN");
+ } else if (d == -FLT_MAX) {
+ av_log(av_log_obj, level, "-FLT_MAX");
+ } else if (d == -FLT_MIN) {
+ av_log(av_log_obj, level, "-FLT_MIN");
+ } else if (d == DBL_MAX) {
+ av_log(av_log_obj, level, "DBL_MAX");
+ } else if (d == DBL_MIN) {
+ av_log(av_log_obj, level, "DBL_MIN");
+ } else if (d == -DBL_MAX) {
+ av_log(av_log_obj, level, "-DBL_MAX");
+ } else if (d == -DBL_MIN) {
+ av_log(av_log_obj, level, "-DBL_MIN");
+ } else {
+ av_log(av_log_obj, level, "%g", d);
+ }
+}
+
static void opt_list(void *obj, void *av_log_obj, const char *unit,
int req_flags, int rej_flags)
{
const AVOption *opt=NULL;
+ AVOptionRanges *r;
+ int i;
while ((opt = av_opt_next(obj, opt))) {
if (!(opt->flags & req_flags) || (opt->flags & rej_flags))
@@ -480,42 +1024,66 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit,
else if (unit && opt->type==AV_OPT_TYPE_CONST && strcmp(unit, opt->unit))
continue;
else if (unit && opt->type == AV_OPT_TYPE_CONST)
- av_log(av_log_obj, AV_LOG_INFO, " %-15s ", opt->name);
+ av_log(av_log_obj, AV_LOG_INFO, " %-15s ", opt->name);
else
- av_log(av_log_obj, AV_LOG_INFO, "-%-17s ", opt->name);
+ av_log(av_log_obj, AV_LOG_INFO, " %s%-17s ",
+ (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? "" : "-",
+ opt->name);
switch (opt->type) {
case AV_OPT_TYPE_FLAGS:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<flags>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<flags>");
break;
case AV_OPT_TYPE_INT:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int>");
break;
case AV_OPT_TYPE_INT64:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<int64>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<int64>");
break;
case AV_OPT_TYPE_DOUBLE:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<double>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<double>");
break;
case AV_OPT_TYPE_FLOAT:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<float>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<float>");
break;
case AV_OPT_TYPE_STRING:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<string>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<string>");
break;
case AV_OPT_TYPE_RATIONAL:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<rational>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<rational>");
break;
case AV_OPT_TYPE_BINARY:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "<binary>");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<binary>");
+ break;
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<image_size>");
+ break;
+ case AV_OPT_TYPE_VIDEO_RATE:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<video_rate>");
+ break;
+ case AV_OPT_TYPE_PIXEL_FMT:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<pix_fmt>");
+ break;
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<sample_fmt>");
+ break;
+ case AV_OPT_TYPE_DURATION:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<duration>");
+ break;
+ case AV_OPT_TYPE_COLOR:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<color>");
+ break;
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "<channel_layout>");
break;
case AV_OPT_TYPE_CONST:
default:
- av_log(av_log_obj, AV_LOG_INFO, "%-7s ", "");
+ av_log(av_log_obj, AV_LOG_INFO, "%-12s ", "");
break;
}
av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.');
av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.');
+ av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_FILTERING_PARAM)? 'F' : '.');
av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_VIDEO_PARAM ) ? 'V' : '.');
av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_AUDIO_PARAM ) ? 'A' : '.');
av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.');
@@ -524,6 +1092,70 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit,
if (opt->help)
av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help);
+
+ 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_INT64:
+ case AV_OPT_TYPE_DOUBLE:
+ case AV_OPT_TYPE_FLOAT:
+ case AV_OPT_TYPE_RATIONAL:
+ for (i = 0; i < r->nb_ranges; i++) {
+ av_log(av_log_obj, AV_LOG_INFO, " (from ");
+ log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_min);
+ av_log(av_log_obj, AV_LOG_INFO, " to ");
+ log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_max);
+ av_log(av_log_obj, AV_LOG_INFO, ")");
+ }
+ break;
+ }
+ av_opt_freep_ranges(&r);
+ }
+
+ if (opt->type != AV_OPT_TYPE_CONST &&
+ opt->type != AV_OPT_TYPE_BINARY &&
+ !((opt->type == AV_OPT_TYPE_COLOR ||
+ opt->type == AV_OPT_TYPE_IMAGE_SIZE ||
+ opt->type == AV_OPT_TYPE_STRING ||
+ opt->type == AV_OPT_TYPE_VIDEO_RATE) &&
+ !opt->default_val.str)) {
+ av_log(av_log_obj, AV_LOG_INFO, " (default ");
+ switch (opt->type) {
+ case AV_OPT_TYPE_FLAGS:
+ av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64);
+ break;
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_INT64:
+ log_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64);
+ break;
+ case AV_OPT_TYPE_DOUBLE:
+ case AV_OPT_TYPE_FLOAT:
+ log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl);
+ break;
+ case AV_OPT_TYPE_RATIONAL: {
+ AVRational q = av_d2q(opt->default_val.dbl, INT_MAX);
+ av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); }
+ break;
+ case AV_OPT_TYPE_PIXEL_FMT:
+ av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none"));
+ break;
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none"));
+ break;
+ case AV_OPT_TYPE_COLOR:
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ case AV_OPT_TYPE_STRING:
+ case AV_OPT_TYPE_VIDEO_RATE:
+ av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str);
+ break;
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ av_log(av_log_obj, AV_LOG_INFO, "0x%"PRIx64, opt->default_val.i64);
+ break;
+ }
+ av_log(av_log_obj, AV_LOG_INFO, ")");
+ }
+
av_log(av_log_obj, AV_LOG_INFO, "\n");
if (opt->unit && opt->type != AV_OPT_TYPE_CONST) {
opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags);
@@ -545,8 +1177,21 @@ int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags)
void av_opt_set_defaults(void *s)
{
+#if FF_API_OLD_AVOPTIONS
+ av_opt_set_defaults2(s, 0, 0);
+}
+
+void av_opt_set_defaults2(void *s, int mask, int flags)
+{
+#endif
const AVOption *opt = NULL;
while ((opt = av_opt_next(s, opt))) {
+ void *dst = ((uint8_t*)s) + opt->offset;
+#if FF_API_OLD_AVOPTIONS
+ if ((opt->flags & mask) != flags)
+ continue;
+#endif
+
if (opt->flags & AV_OPT_FLAG_READONLY)
continue;
@@ -557,25 +1202,44 @@ void av_opt_set_defaults(void *s)
case AV_OPT_TYPE_FLAGS:
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
- av_opt_set_int(s, opt->name, opt->default_val.i64, 0);
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ write_number(s, opt, dst, 1, 1, opt->default_val.i64);
break;
case AV_OPT_TYPE_DOUBLE:
case AV_OPT_TYPE_FLOAT: {
double val;
val = opt->default_val.dbl;
- av_opt_set_double(s, opt->name, val, 0);
+ write_number(s, opt, dst, val, 1, 1);
}
break;
case AV_OPT_TYPE_RATIONAL: {
AVRational val;
val = av_d2q(opt->default_val.dbl, INT_MAX);
- av_opt_set_q(s, opt->name, val, 0);
+ write_number(s, opt, dst, 1, val.den, val.num);
}
break;
+ case AV_OPT_TYPE_COLOR:
+ set_string_color(s, opt, opt->default_val.str, dst);
+ break;
case AV_OPT_TYPE_STRING:
- av_opt_set(s, opt->name, opt->default_val.str, 0);
+ set_string(s, opt, opt->default_val.str, dst);
+ break;
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ set_string_image_size(s, opt, opt->default_val.str, dst);
+ break;
+ case AV_OPT_TYPE_VIDEO_RATE:
+ set_string_video_rate(s, opt, opt->default_val.str, dst);
+ break;
+ case AV_OPT_TYPE_PIXEL_FMT:
+ write_number(s, opt, dst, 1, 1, opt->default_val.i64);
+ break;
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ write_number(s, opt, dst, 1, 1, opt->default_val.i64);
break;
case AV_OPT_TYPE_BINARY:
+ set_string_binary(s, opt, opt->default_val.str, dst);
+ break;
case AV_OPT_TYPE_DICT:
/* Cannot set defaults for these types */
break;
@@ -625,7 +1289,7 @@ static int parse_key_value_pair(void *ctx, const char **buf,
return AVERROR(EINVAL);
}
- av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
+ av_log(ctx, AV_LOG_DEBUG, "Setting entry with key '%s' to value '%s'\n", key, val);
ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN);
if (ret == AVERROR_OPTION_NOT_FOUND)
@@ -656,6 +1320,118 @@ int av_set_options_string(void *ctx, const char *opts,
return count;
}
+#define WHITESPACES " \n\t"
+
+static int is_key_char(char c)
+{
+ return (unsigned)((c | 32) - 'a') < 26 ||
+ (unsigned)(c - '0') < 10 ||
+ c == '-' || c == '_' || c == '/' || c == '.';
+}
+
+/**
+ * Read a key from a string.
+ *
+ * The key consists of is_key_char characters and must be terminated by a
+ * character from the delim string; spaces are ignored.
+ *
+ * @return 0 for success (even with ellipsis), <0 for failure
+ */
+static int get_key(const char **ropts, const char *delim, char **rkey)
+{
+ const char *opts = *ropts;
+ const char *key_start, *key_end;
+
+ key_start = opts += strspn(opts, WHITESPACES);
+ while (is_key_char(*opts))
+ opts++;
+ key_end = opts;
+ opts += strspn(opts, WHITESPACES);
+ if (!*opts || !strchr(delim, *opts))
+ return AVERROR(EINVAL);
+ opts++;
+ if (!(*rkey = av_malloc(key_end - key_start + 1)))
+ return AVERROR(ENOMEM);
+ memcpy(*rkey, key_start, key_end - key_start);
+ (*rkey)[key_end - key_start] = 0;
+ *ropts = opts;
+ return 0;
+}
+
+int av_opt_get_key_value(const char **ropts,
+ const char *key_val_sep, const char *pairs_sep,
+ unsigned flags,
+ char **rkey, char **rval)
+{
+ int ret;
+ char *key = NULL, *val;
+ const char *opts = *ropts;
+
+ if ((ret = get_key(&opts, key_val_sep, &key)) < 0 &&
+ !(flags & AV_OPT_FLAG_IMPLICIT_KEY))
+ return AVERROR(EINVAL);
+ if (!(val = av_get_token(&opts, pairs_sep))) {
+ av_free(key);
+ return AVERROR(ENOMEM);
+ }
+ *ropts = opts;
+ *rkey = key;
+ *rval = val;
+ return 0;
+}
+
+int av_opt_set_from_string(void *ctx, const char *opts,
+ const char *const *shorthand,
+ const char *key_val_sep, const char *pairs_sep)
+{
+ int ret, count = 0;
+ const char *dummy_shorthand = NULL;
+ char *av_uninit(parsed_key), *av_uninit(value);
+ const char *key;
+
+ if (!opts)
+ return 0;
+ if (!shorthand)
+ shorthand = &dummy_shorthand;
+
+ while (*opts) {
+ ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep,
+ *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0,
+ &parsed_key, &value);
+ if (ret < 0) {
+ if (ret == AVERROR(EINVAL))
+ av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", opts);
+ else
+ av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", opts,
+ av_err2str(ret));
+ return ret;
+ }
+ if (*opts)
+ opts++;
+ if (parsed_key) {
+ key = parsed_key;
+ while (*shorthand) /* discard all remaining shorthand */
+ shorthand++;
+ } else {
+ key = *(shorthand++);
+ }
+
+ av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value);
+ if ((ret = av_opt_set(ctx, key, value, 0)) < 0) {
+ if (ret == AVERROR_OPTION_NOT_FOUND)
+ av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key);
+ av_free(value);
+ av_free(parsed_key);
+ return ret;
+ }
+
+ av_free(value);
+ av_free(parsed_key);
+ count++;
+ }
+ return count;
+}
+
void av_opt_free(void *obj)
{
const AVOption *o = NULL;
@@ -676,14 +1452,17 @@ void av_opt_free(void *obj)
}
}
-int av_opt_set_dict(void *obj, AVDictionary **options)
+int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags)
{
AVDictionaryEntry *t = NULL;
AVDictionary *tmp = NULL;
int ret = 0;
+ if (!options)
+ return 0;
+
while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) {
- ret = av_opt_set(obj, t->key, t->value, 0);
+ ret = av_opt_set(obj, t->key, t->value, search_flags);
if (ret == AVERROR_OPTION_NOT_FOUND)
av_dict_set(&tmp, t->key, t->value, 0);
else if (ret < 0) {
@@ -697,6 +1476,11 @@ int av_opt_set_dict(void *obj, AVDictionary **options)
return ret;
}
+int av_opt_set_dict(void *obj, AVDictionary **options)
+{
+ return av_opt_set_dict2(obj, options, 0);
+}
+
const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
int opt_flags, int search_flags)
{
@@ -706,9 +1490,14 @@ const AVOption *av_opt_find(void *obj, const char *name, const char *unit,
const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
int opt_flags, int search_flags, void **target_obj)
{
- const AVClass *c = *(AVClass**)obj;
+ const AVClass *c;
const AVOption *o = NULL;
+ if(!obj)
+ return NULL;
+
+ c= *(AVClass**)obj;
+
if (!c)
return NULL;
@@ -729,7 +1518,7 @@ const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
while (o = av_opt_next(obj, o)) {
if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags &&
((!unit && o->type != AV_OPT_TYPE_CONST) ||
- (unit && o->unit && !strcmp(o->unit, unit)))) {
+ (unit && o->type == AV_OPT_TYPE_CONST && o->unit && !strcmp(o->unit, unit)))) {
if (target_obj) {
if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ))
*target_obj = obj;
@@ -757,6 +1546,353 @@ const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *pre
return NULL;
}
+void *av_opt_ptr(const AVClass *class, void *obj, const char *name)
+{
+ const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL);
+ if(!opt)
+ return NULL;
+ return (uint8_t*)obj + opt->offset;
+}
+
+static int opt_size(enum AVOptionType type)
+{
+ switch(type) {
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_FLAGS: return sizeof(int);
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ case AV_OPT_TYPE_INT64: return sizeof(int64_t);
+ case AV_OPT_TYPE_DOUBLE: return sizeof(double);
+ case AV_OPT_TYPE_FLOAT: return sizeof(float);
+ case AV_OPT_TYPE_STRING: return sizeof(uint8_t*);
+ case AV_OPT_TYPE_VIDEO_RATE:
+ case AV_OPT_TYPE_RATIONAL: return sizeof(AVRational);
+ case AV_OPT_TYPE_BINARY: return sizeof(uint8_t*) + sizeof(int);
+ case AV_OPT_TYPE_IMAGE_SIZE:return sizeof(int[2]);
+ case AV_OPT_TYPE_PIXEL_FMT: return sizeof(enum AVPixelFormat);
+ case AV_OPT_TYPE_SAMPLE_FMT:return sizeof(enum AVSampleFormat);
+ case AV_OPT_TYPE_COLOR: return 4;
+ }
+ return 0;
+}
+
+int av_opt_copy(void *dst, FF_CONST_AVUTIL55 void *src)
+{
+ const AVOption *o = NULL;
+ const AVClass *c;
+ int ret = 0;
+
+ if (!src)
+ return 0;
+
+ c = *(AVClass**)src;
+ if (*(AVClass**)dst && c != *(AVClass**)dst)
+ return AVERROR(EINVAL);
+
+ while ((o = av_opt_next(src, o))) {
+ void *field_dst = ((uint8_t*)dst) + o->offset;
+ void *field_src = ((uint8_t*)src) + o->offset;
+ uint8_t **field_dst8 = (uint8_t**)field_dst;
+ uint8_t **field_src8 = (uint8_t**)field_src;
+
+ if (o->type == AV_OPT_TYPE_STRING) {
+ if (*field_dst8 != *field_src8)
+ av_freep(field_dst8);
+ *field_dst8 = av_strdup(*field_src8);
+ if (*field_src8 && !*field_dst8)
+ ret = AVERROR(ENOMEM);
+ } else if (o->type == AV_OPT_TYPE_BINARY) {
+ int len = *(int*)(field_src8 + 1);
+ if (*field_dst8 != *field_src8)
+ av_freep(field_dst8);
+ *field_dst8 = av_memdup(*field_src8, len);
+ if (len && !*field_dst8) {
+ ret = AVERROR(ENOMEM);
+ len = 0;
+ }
+ *(int*)(field_dst8 + 1) = len;
+ } else if (o->type == AV_OPT_TYPE_CONST) {
+ // do nothing
+ } else if (o->type == AV_OPT_TYPE_DICT) {
+ AVDictionary **sdict = (AVDictionary **) field_src;
+ AVDictionary **ddict = (AVDictionary **) field_dst;
+ if (*sdict != *ddict)
+ av_dict_free(ddict);
+ *ddict = NULL;
+ av_dict_copy(ddict, *sdict, 0);
+ if (av_dict_count(*sdict) != av_dict_count(*ddict))
+ ret = AVERROR(ENOMEM);
+ } else {
+ memcpy(field_dst, field_src, opt_size(o->type));
+ }
+ }
+ return ret;
+}
+
+int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags)
+{
+ int ret;
+ const AVClass *c = *(AVClass**)obj;
+ int (*callback)(AVOptionRanges **, void *obj, const char *key, int flags) = NULL;
+
+ if (c->version > (52 << 16 | 11 << 8))
+ callback = c->query_ranges;
+
+ if (!callback)
+ callback = av_opt_query_ranges_default;
+
+ ret = callback(ranges_arg, obj, key, flags);
+ if (ret >= 0) {
+ if (!(flags & AV_OPT_MULTI_COMPONENT_RANGE))
+ ret = 1;
+ (*ranges_arg)->nb_components = ret;
+ }
+ return ret;
+}
+
+int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags)
+{
+ AVOptionRanges *ranges = av_mallocz(sizeof(*ranges));
+ AVOptionRange **range_array = av_mallocz(sizeof(void*));
+ AVOptionRange *range = av_mallocz(sizeof(*range));
+ const AVOption *field = av_opt_find(obj, key, NULL, 0, flags);
+ int ret;
+
+ *ranges_arg = NULL;
+
+ if (!ranges || !range || !range_array || !field) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ranges->range = range_array;
+ ranges->range[0] = range;
+ ranges->nb_ranges = 1;
+ ranges->nb_components = 1;
+ range->is_range = 1;
+ range->value_min = field->min;
+ range->value_max = field->max;
+
+ switch (field->type) {
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_INT64:
+ case AV_OPT_TYPE_PIXEL_FMT:
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ case AV_OPT_TYPE_FLOAT:
+ case AV_OPT_TYPE_DOUBLE:
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_COLOR:
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ break;
+ case AV_OPT_TYPE_STRING:
+ range->component_min = 0;
+ range->component_max = 0x10FFFF; // max unicode value
+ range->value_min = -1;
+ range->value_max = INT_MAX;
+ break;
+ case AV_OPT_TYPE_RATIONAL:
+ range->component_min = INT_MIN;
+ range->component_max = INT_MAX;
+ break;
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ range->component_min = 0;
+ range->component_max = INT_MAX/128/8;
+ range->value_min = 0;
+ range->value_max = INT_MAX/8;
+ break;
+ case AV_OPT_TYPE_VIDEO_RATE:
+ range->component_min = 1;
+ range->component_max = INT_MAX;
+ range->value_min = 1;
+ range->value_max = INT_MAX;
+ break;
+ default:
+ ret = AVERROR(ENOSYS);
+ goto fail;
+ }
+
+ *ranges_arg = ranges;
+ return 1;
+fail:
+ av_free(ranges);
+ av_free(range);
+ av_free(range_array);
+ return ret;
+}
+
+void av_opt_freep_ranges(AVOptionRanges **rangesp)
+{
+ int i;
+ AVOptionRanges *ranges = *rangesp;
+
+ if (!ranges)
+ return;
+
+ for (i = 0; i < ranges->nb_ranges * ranges->nb_components; i++) {
+ AVOptionRange *range = ranges->range[i];
+ if (range) {
+ av_freep(&range->str);
+ av_freep(&ranges->range[i]);
+ }
+ }
+ av_freep(&ranges->range);
+ av_freep(rangesp);
+}
+
+int av_opt_is_set_to_default(void *obj, const AVOption *o)
+{
+ int64_t i64;
+ double d, d2;
+ float f;
+ AVRational q;
+ int ret, w, h;
+ char *str;
+ void *dst;
+
+ if (!o || !obj)
+ return AVERROR(EINVAL);
+
+ dst = ((uint8_t*)obj) + o->offset;
+
+ switch (o->type) {
+ case AV_OPT_TYPE_CONST:
+ return 1;
+ case AV_OPT_TYPE_FLAGS:
+ case AV_OPT_TYPE_PIXEL_FMT:
+ case AV_OPT_TYPE_SAMPLE_FMT:
+ case AV_OPT_TYPE_INT:
+ case AV_OPT_TYPE_CHANNEL_LAYOUT:
+ case AV_OPT_TYPE_DURATION:
+ case AV_OPT_TYPE_INT64:
+ read_number(o, dst, NULL, NULL, &i64);
+ return o->default_val.i64 == i64;
+ case AV_OPT_TYPE_STRING:
+ str = *(char **)dst;
+ if (str == o->default_val.str) //2 NULLs
+ return 1;
+ if (!str || !o->default_val.str) //1 NULL
+ return 0;
+ return !strcmp(str, o->default_val.str);
+ case AV_OPT_TYPE_DOUBLE:
+ read_number(o, dst, &d, NULL, NULL);
+ return o->default_val.dbl == d;
+ case AV_OPT_TYPE_FLOAT:
+ read_number(o, dst, &d, NULL, NULL);
+ f = o->default_val.dbl;
+ d2 = f;
+ return d2 == d;
+ case AV_OPT_TYPE_RATIONAL:
+ q = av_d2q(o->default_val.dbl, INT_MAX);
+ return !av_cmp_q(*(AVRational*)dst, q);
+ case AV_OPT_TYPE_BINARY: {
+ struct {
+ uint8_t *data;
+ int size;
+ } tmp = {0};
+ int opt_size = *(int *)((void **)dst + 1);
+ void *opt_ptr = *(void **)dst;
+ if (!opt_size && (!o->default_val.str || !strlen(o->default_val.str)))
+ return 1;
+ if (!opt_size || !o->default_val.str || !strlen(o->default_val.str ))
+ return 0;
+ if (opt_size != strlen(o->default_val.str) / 2)
+ return 0;
+ ret = set_string_binary(NULL, NULL, o->default_val.str, &tmp.data);
+ if (!ret)
+ ret = !memcmp(opt_ptr, tmp.data, tmp.size);
+ av_free(tmp.data);
+ return ret;
+ }
+ case AV_OPT_TYPE_DICT:
+ /* Binary and dict have not default support yet. Any pointer is not default. */
+ return !!(*(void **)dst);
+ case AV_OPT_TYPE_IMAGE_SIZE:
+ if (!o->default_val.str || !strcmp(o->default_val.str, "none"))
+ w = h = 0;
+ else if ((ret = av_parse_video_size(&w, &h, o->default_val.str)) < 0)
+ return ret;
+ return (w == *(int *)dst) && (h == *((int *)dst+1));
+ case AV_OPT_TYPE_VIDEO_RATE:
+ q = (AVRational){0, 0};
+ if (o->default_val.str) {
+ if ((ret = av_parse_video_rate(&q, o->default_val.str)) < 0)
+ return ret;
+ }
+ return !av_cmp_q(*(AVRational*)dst, q);
+ case AV_OPT_TYPE_COLOR: {
+ uint8_t color[4] = {0, 0, 0, 0};
+ if (o->default_val.str) {
+ if ((ret = av_parse_color(color, o->default_val.str, -1, NULL)) < 0)
+ return ret;
+ }
+ return !memcmp(color, dst, sizeof(color));
+ }
+ default:
+ av_log(obj, AV_LOG_WARNING, "Not supported option type: %d, option name: %s\n", o->type, o->name);
+ break;
+ }
+ return AVERROR_PATCHWELCOME;
+}
+
+int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags)
+{
+ const AVOption *o;
+ void *target;
+ if (!obj)
+ return AVERROR(EINVAL);
+ o = av_opt_find2(obj, name, NULL, 0, search_flags, &target);
+ if (!o)
+ return AVERROR_OPTION_NOT_FOUND;
+ return av_opt_is_set_to_default(target, o);
+}
+
+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 == '\\') {
+ av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found.");
+ return AVERROR(EINVAL);
+ }
+
+ if (!obj || !buffer)
+ return AVERROR(EINVAL);
+
+ *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);
+ }
+ }
+ av_bprint_finalize(&bprint, buffer);
+ return 0;
+}
+
#ifdef TEST
typedef struct TestContext
@@ -767,6 +1903,23 @@ typedef struct TestContext
char *string;
int flags;
AVRational rational;
+ AVRational video_rate;
+ int w, h;
+ enum AVPixelFormat pix_fmt;
+ enum AVSampleFormat sample_fmt;
+ int64_t duration;
+ uint8_t color[4];
+ int64_t channel_layout;
+ void *binary;
+ int binary_size;
+ void *binary1;
+ int binary_size1;
+ void *binary2;
+ int binary_size2;
+ int64_t num64;
+ float flt;
+ double dbl;
+ char *escape;
} TestContext;
#define OFFSET(x) offsetof(TestContext, x)
@@ -776,14 +1929,28 @@ typedef struct TestContext
#define TEST_FLAG_MU 04
static const AVOption test_options[]= {
-{"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100 },
-{"toggle", "set toggle", OFFSET(toggle), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1 },
-{"rational", "set rational", OFFSET(rational), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, 10 },
-{"string", "set string", OFFSET(string), AV_OPT_TYPE_STRING, {0}, CHAR_MIN, CHAR_MAX },
-{"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
-{"cool", "set cool flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_COOL}, INT_MIN, INT_MAX, 0, "flags" },
-{"lame", "set lame flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_LAME}, INT_MIN, INT_MAX, 0, "flags" },
-{"mu", "set mu flag ", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_MU}, INT_MIN, INT_MAX, 0, "flags" },
+{"num", "set num", OFFSET(num), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 100, 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 },
+{"escape", "set escape str", OFFSET(escape), AV_OPT_TYPE_STRING, {.str = "\\=,"}, CHAR_MIN, CHAR_MAX, 1 },
+{"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 1}, 0, INT_MAX, 1, "flags" },
+{"cool", "set cool flag", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_COOL}, INT_MIN, INT_MAX, 1, "flags" },
+{"lame", "set lame flag", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_LAME}, INT_MIN, INT_MAX, 1, "flags" },
+{"mu", "set mu flag", 0, AV_OPT_TYPE_CONST, {.i64 = TEST_FLAG_MU}, INT_MIN, INT_MAX, 1, "flags" },
+{"size", "set size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE,{.str="200x300"}, 0, 0, 1},
+{"pix_fmt", "set pixfmt", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_0BGR}, -1, INT_MAX, 1},
+{"sample_fmt", "set samplefmt", OFFSET(sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, {.i64 = AV_SAMPLE_FMT_S16}, -1, INT_MAX, 1},
+{"video_rate", "set videorate", OFFSET(video_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0 , 1},
+{"duration", "set duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 1000}, 0, INT64_MAX, 1},
+{"color", "set color", OFFSET(color), AV_OPT_TYPE_COLOR, {.str = "pink"}, 0, 0, 1},
+{"cl", "set channel layout", OFFSET(channel_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64 = AV_CH_LAYOUT_HEXAGONAL}, 0, INT64_MAX, 1},
+{"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 },
+{"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 },
{NULL},
};
@@ -798,14 +1965,98 @@ static const AVClass test_class = {
test_options
};
+static void log_callback_help(void *ptr, int level, const char *fmt, va_list vl)
+{
+ vfprintf(stdout, fmt, vl);
+}
+
int main(void)
{
int i;
+ av_log_set_level(AV_LOG_DEBUG);
+ av_log_set_callback(log_callback_help);
+
+ printf("Testing default values\n");
+ {
+ TestContext test_ctx = { 0 };
+ test_ctx.class = &test_class;
+ av_opt_set_defaults(&test_ctx);
+
+ printf("num=%d\n", test_ctx.num);
+ printf("toggle=%d\n", test_ctx.toggle);
+ printf("string=%s\n", test_ctx.string);
+ printf("escape=%s\n", test_ctx.escape);
+ printf("flags=%d\n", test_ctx.flags);
+ printf("rational=%d/%d\n", test_ctx.rational.num, test_ctx.rational.den);
+ printf("video_rate=%d/%d\n", test_ctx.video_rate.num, test_ctx.video_rate.den);
+ printf("width=%d height=%d\n", test_ctx.w, test_ctx.h);
+ printf("pix_fmt=%s\n", av_get_pix_fmt_name(test_ctx.pix_fmt));
+ printf("sample_fmt=%s\n", av_get_sample_fmt_name(test_ctx.sample_fmt));
+ printf("duration=%"PRId64"\n", test_ctx.duration);
+ printf("color=%d %d %d %d\n", test_ctx.color[0], test_ctx.color[1], test_ctx.color[2], test_ctx.color[3]);
+ printf("channel_layout=%"PRId64"=%"PRId64"\n", test_ctx.channel_layout, (int64_t)AV_CH_LAYOUT_HEXAGONAL);
+ if (test_ctx.binary)
+ printf("binary=%x %x %x %x\n", ((uint8_t*)test_ctx.binary)[0], ((uint8_t*)test_ctx.binary)[1], ((uint8_t*)test_ctx.binary)[2], ((uint8_t*)test_ctx.binary)[3]);
+ printf("binary_size=%d\n", test_ctx.binary_size);
+ printf("num64=%"PRId64"\n", test_ctx.num64);
+ printf("flt=%.6f\n", test_ctx.flt);
+ printf("dbl=%.6f\n", test_ctx.dbl);
+
+ av_opt_show2(&test_ctx, NULL, -1, 0);
+
+ av_opt_free(&test_ctx);
+ }
+
+ printf("\nTesting av_opt_is_set_to_default()\n");
+ {
+ int ret;
+ TestContext test_ctx = { 0 };
+ const AVOption *o = NULL;
+ test_ctx.class = &test_class;
+
+ av_log_set_level(AV_LOG_QUIET);
+
+ while (o = av_opt_next(&test_ctx, o)) {
+ ret = av_opt_is_set_to_default_by_name(&test_ctx, o->name, 0);
+ printf("name:%10s default:%d error:%s\n", o->name, !!ret, ret < 0 ? av_err2str(ret) : "");
+ }
+ av_opt_set_defaults(&test_ctx);
+ while (o = av_opt_next(&test_ctx, o)) {
+ ret = av_opt_is_set_to_default_by_name(&test_ctx, o->name, 0);
+ printf("name:%10s default:%d error:%s\n", o->name, !!ret, ret < 0 ? av_err2str(ret) : "");
+ }
+ av_opt_free(&test_ctx);
+ }
+
+ printf("\nTest av_opt_serialize()\n");
+ {
+ TestContext test_ctx = { 0 };
+ char *buf;
+ test_ctx.class = &test_class;
+
+ av_log_set_level(AV_LOG_QUIET);
+
+ av_opt_set_defaults(&test_ctx);
+ if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) {
+ printf("%s\n", buf);
+ av_opt_free(&test_ctx);
+ memset(&test_ctx, 0, sizeof(test_ctx));
+ test_ctx.class = &test_class;
+ av_set_options_string(&test_ctx, buf, "=", ",");
+ av_free(buf);
+ if (av_opt_serialize(&test_ctx, 0, 0, &buf, '=', ',') >= 0) {
+ printf("%s\n", buf);
+ av_free(buf);
+ }
+ }
+ av_opt_free(&test_ctx);
+ }
+
printf("\nTesting av_set_options_string()\n");
{
- TestContext test_ctx;
- const char *options[] = {
+ TestContext test_ctx = { 0 };
+ static const char * const options[] = {
"",
":",
"=",
@@ -825,22 +2076,96 @@ int main(void)
"num=42 : string=blahblah",
"rational=0 : rational=1/2 : rational=1/-1",
"rational=-1/0",
+ "size=1024x768",
+ "size=pal",
+ "size=bogus",
+ "pix_fmt=yuv420p",
+ "pix_fmt=2",
+ "pix_fmt=bogus",
+ "sample_fmt=s16",
+ "sample_fmt=2",
+ "sample_fmt=bogus",
+ "video_rate=pal",
+ "video_rate=25",
+ "video_rate=30000/1001",
+ "video_rate=30/1.001",
+ "video_rate=bogus",
+ "duration=bogus",
+ "duration=123.45",
+ "duration=1\\:23\\:45.67",
+ "color=blue",
+ "color=0x223300",
+ "color=0x42FF07AA",
+ "cl=stereo+downmix",
+ "cl=foo",
+ "bin=boguss",
+ "bin=111",
+ "bin=ffff",
+ "num64=bogus",
+ "num64=44",
+ "num64=44.4",
+ "num64=-1",
+ "num64=101",
+ "flt=bogus",
+ "flt=2",
+ "flt=2.2",
+ "flt=-1",
+ "flt=101",
+ "dbl=bogus",
+ "dbl=2",
+ "dbl=2.2",
+ "dbl=-1",
+ "dbl=101",
};
test_ctx.class = &test_class;
av_opt_set_defaults(&test_ctx);
- test_ctx.string = av_strdup("default");
- if (!test_ctx.string)
- return AVERROR(ENOMEM);
- av_log_set_level(AV_LOG_DEBUG);
+ av_log_set_level(AV_LOG_QUIET);
for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
+ int silence_log = !strcmp(options[i], "rational=-1/0"); // inf formating differs between platforms
av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
+ if (silence_log)
+ av_log_set_callback(NULL);
if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
- av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
- printf("\n");
+ printf("Error '%s'\n", options[i]);
+ else
+ printf("OK '%s'\n", options[i]);
+ av_log_set_callback(log_callback_help);
+ }
+ av_opt_free(&test_ctx);
+ }
+
+ printf("\nTesting av_opt_set_from_string()\n");
+ {
+ TestContext test_ctx = { 0 };
+ static const char * const options[] = {
+ "",
+ "5",
+ "5:hello",
+ "5:hello:size=pal",
+ "5:size=pal:hello",
+ ":",
+ "=",
+ " 5 : hello : size = pal ",
+ "a_very_long_option_name_that_will_need_to_be_ellipsized_around_here=42"
+ };
+ static const char * const shorthand[] = { "num", "string", NULL };
+
+ test_ctx.class = &test_class;
+ av_opt_set_defaults(&test_ctx);
+
+ av_log_set_level(AV_LOG_QUIET);
+
+ for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
+ av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
+ if (av_opt_set_from_string(&test_ctx, options[i], shorthand, "=", ":") < 0)
+ printf("Error '%s'\n", options[i]);
+ else
+ printf("OK '%s'\n", options[i]);
}
+ av_opt_free(&test_ctx);
}
return 0;
diff --git a/libavutil/opt.h b/libavutil/opt.h
index 8413206179..5fc8a9b58a 100644
--- a/libavutil/opt.h
+++ b/libavutil/opt.h
@@ -2,20 +2,20 @@
* AVOptions
* copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,6 +31,9 @@
#include "avutil.h"
#include "dict.h"
#include "log.h"
+#include "pixfmt.h"
+#include "samplefmt.h"
+#include "version.h"
/**
* @defgroup avoptions AVOptions
@@ -44,7 +47,7 @@
* This section describes how to add AVOptions capabilities to a struct.
*
* All AVOptions-related information is stored in an AVClass. Therefore
- * the first member of the struct must be a pointer to an AVClass describing it.
+ * the first member of the struct should be a pointer to an AVClass describing it.
* The option field of the AVClass must be set to a NULL-terminated static array
* of AVOptions. Each AVOption must have a non-empty name, a type, a default
* value and for number-type AVOptions also a range of allowed values. It must
@@ -81,7 +84,7 @@
* @endcode
*
* Next, when allocating your struct, you must ensure that the AVClass pointer
- * is set to the correct value. Then, av_opt_set_defaults() must be called to
+ * is set to the correct value. Then, av_opt_set_defaults() can be called to
* initialize defaults. After that the struct is ready to be used with the
* AVOptions API.
*
@@ -161,7 +164,7 @@
*
* @subsection avoptions_implement_named_constants Named constants
* It is possible to create named constants for options. Simply set the unit
- * field of the option the constants should apply to to a string and
+ * field of the option the constants should apply to a string and
* create the constants themselves as options of type AV_OPT_TYPE_CONST
* with their unit field set to the same string.
* Their default_val field should contain the value of the named
@@ -176,7 +179,7 @@
*
* @section avoptions_use Using AVOptions
* This section deals with accessing options in an AVOptions-enabled struct.
- * Such structs in Libav are e.g. AVCodecContext in libavcodec or
+ * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or
* AVFormatContext in libavformat.
*
* @subsection avoptions_use_examine Examining AVOptions
@@ -226,6 +229,24 @@ enum AVOptionType{
AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length
AV_OPT_TYPE_DICT,
AV_OPT_TYPE_CONST = 128,
+ AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers
+ AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'),
+ AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'),
+ AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational
+ AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '),
+ AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'),
+ AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'),
+#if FF_API_OLD_AVOPTIONS
+ FF_OPT_TYPE_FLAGS = 0,
+ FF_OPT_TYPE_INT,
+ FF_OPT_TYPE_INT64,
+ FF_OPT_TYPE_DOUBLE,
+ FF_OPT_TYPE_FLOAT,
+ FF_OPT_TYPE_STRING,
+ FF_OPT_TYPE_RATIONAL,
+ FF_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length
+ FF_OPT_TYPE_CONST=128,
+#endif
};
/**
@@ -278,6 +299,7 @@ typedef struct AVOption {
* This flag only makes sense when AV_OPT_FLAG_EXPORT is also set.
*/
#define AV_OPT_FLAG_READONLY 128
+#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering
//FIXME think about enc-audio, ... style flags
/**
@@ -289,6 +311,116 @@ typedef struct AVOption {
} AVOption;
/**
+ * A single allowed range of values, or a single allowed value.
+ */
+typedef struct AVOptionRange {
+ const char *str;
+ /**
+ * Value range.
+ * For string ranges this represents the min/max length.
+ * For dimensions this represents the min/max pixel count or width/height in multi-component case.
+ */
+ double value_min, value_max;
+ /**
+ * Value's component range.
+ * For string this represents the unicode range for chars, 0-127 limits to ASCII.
+ */
+ double component_min, component_max;
+ /**
+ * Range flag.
+ * If set to 1 the struct encodes a range, if set to 0 a single value.
+ */
+ int is_range;
+} AVOptionRange;
+
+/**
+ * List of AVOptionRange structs.
+ */
+typedef struct AVOptionRanges {
+ /**
+ * Array of option ranges.
+ *
+ * Most of option types use just one component.
+ * Following describes multi-component option types:
+ *
+ * AV_OPT_TYPE_IMAGE_SIZE:
+ * component index 0: range of pixel count (width * height).
+ * component index 1: range of width.
+ * component index 2: range of height.
+ *
+ * @note To obtain multi-component version of this structure, user must
+ * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or
+ * av_opt_query_ranges_default function.
+ *
+ * Multi-component range can be read as in following example:
+ *
+ * @code
+ * int range_index, component_index;
+ * AVOptionRanges *ranges;
+ * AVOptionRange *range[3]; //may require more than 3 in the future.
+ * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE);
+ * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) {
+ * for (component_index = 0; component_index < ranges->nb_components; component_index++)
+ * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index];
+ * //do something with range here.
+ * }
+ * av_opt_freep_ranges(&ranges);
+ * @endcode
+ */
+ AVOptionRange **range;
+ /**
+ * Number of ranges per component.
+ */
+ int nb_ranges;
+ /**
+ * Number of componentes.
+ */
+ int nb_components;
+} AVOptionRanges;
+
+
+#if FF_API_OLD_AVOPTIONS
+/**
+ * Set the field of obj with the given name to value.
+ *
+ * @param[in] obj A struct whose first element is a pointer to an
+ * AVClass.
+ * @param[in] name the name of the field to set
+ * @param[in] val The value to set. If the field is not of a string
+ * type, then the given string is parsed.
+ * SI postfixes and some named scalars are supported.
+ * If the field is of a numeric type, it has to be a numeric or named
+ * scalar. Behavior with more than one scalar and +- infix operators
+ * is undefined.
+ * If the field is of a flags type, it has to be a sequence of numeric
+ * scalars or named flags separated by '+' or '-'. Prefixing a flag
+ * with '+' causes it to be set without affecting the other flags;
+ * similarly, '-' unsets a flag.
+ * @param[out] o_out if non-NULL put here a pointer to the AVOption
+ * found
+ * @param alloc this parameter is currently ignored
+ * @return 0 if the value has been set, or an AVERROR code in case of
+ * error:
+ * AVERROR_OPTION_NOT_FOUND if no matching option exists
+ * AVERROR(ERANGE) if the value is out of range
+ * AVERROR(EINVAL) if the value is not valid
+ * @deprecated use av_opt_set()
+ */
+attribute_deprecated
+int av_set_string3(void *obj, const char *name, const char *val, int alloc, const AVOption **o_out);
+
+attribute_deprecated const AVOption *av_set_double(void *obj, const char *name, double n);
+attribute_deprecated const AVOption *av_set_q(void *obj, const char *name, AVRational n);
+attribute_deprecated const AVOption *av_set_int(void *obj, const char *name, int64_t n);
+
+double av_get_double(void *obj, const char *name, const AVOption **o_out);
+AVRational av_get_q(void *obj, const char *name, const AVOption **o_out);
+int64_t av_get_int(void *obj, const char *name, const AVOption **o_out);
+attribute_deprecated const char *av_get_string(void *obj, const char *name, const AVOption **o_out, char *buf, int buf_len);
+attribute_deprecated const AVOption *av_next_option(FF_CONST_AVUTIL55 void *obj, const AVOption *last);
+#endif
+
+/**
* Show the obj options.
*
* @param req_flags requested flags for the options to show. Show only the
@@ -306,12 +438,18 @@ int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags);
*/
void av_opt_set_defaults(void *s);
+#if FF_API_OLD_AVOPTIONS
+attribute_deprecated
+void av_opt_set_defaults2(void *s, int mask, int flags);
+#endif
+
/**
* Parse the key/value pairs list in opts. For each key/value pair
* found, stores the value in the field in ctx that is named like the
* key. ctx must be an AVClass context, storing is done using
* AVOptions.
*
+ * @param opts options string to parse, may be NULL
* @param key_val_sep a 0-terminated list of characters used to
* separate key from value
* @param pairs_sep a 0-terminated list of characters used to separate
@@ -326,6 +464,36 @@ int av_set_options_string(void *ctx, const char *opts,
const char *key_val_sep, const char *pairs_sep);
/**
+ * Parse the key-value pairs list in opts. For each key=value pair found,
+ * set the value of the corresponding option in ctx.
+ *
+ * @param ctx the AVClass object to set options on
+ * @param opts the options string, key-value pairs separated by a
+ * delimiter
+ * @param shorthand a NULL-terminated array of options names for shorthand
+ * notation: if the first field in opts has no key part,
+ * the key is taken from the first element of shorthand;
+ * then again for the second, etc., until either opts is
+ * finished, shorthand is finished or a named option is
+ * found; after that, all options must be named
+ * @param key_val_sep a 0-terminated list of characters used to separate
+ * key from value, for example '='
+ * @param pairs_sep a 0-terminated list of characters used to separate
+ * two pairs from each other, for example ':' or ','
+ * @return the number of successfully set key=value pairs, or a negative
+ * value corresponding to an AVERROR code in case of error:
+ * AVERROR(EINVAL) if opts cannot be parsed,
+ * the error code issued by av_set_string3() if a key/value pair
+ * cannot be set
+ *
+ * Options names must use only the following characters: a-z A-Z 0-9 - . / _
+ * Separators must use characters distinct from option names and from each
+ * other.
+ */
+int av_opt_set_from_string(void *ctx, const char *opts,
+ const char *const *shorthand,
+ const char *key_val_sep, const char *pairs_sep);
+/**
* Free all allocated objects in obj.
*/
void av_opt_free(void *obj);
@@ -340,7 +508,7 @@ void av_opt_free(void *obj);
*/
int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name);
-/*
+/**
* Set all the options from a given dictionary on an object.
*
* @param obj a struct whose first element is a pointer to AVClass
@@ -356,6 +524,57 @@ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name)
*/
int av_opt_set_dict(void *obj, struct AVDictionary **options);
+
+/**
+ * Set all the options from a given dictionary on an object.
+ *
+ * @param obj a struct whose first element is a pointer to AVClass
+ * @param options options to process. This dictionary will be freed and replaced
+ * by a new one containing all options not found in obj.
+ * Of course this new dictionary needs to be freed by caller
+ * with av_dict_free().
+ * @param search_flags A combination of AV_OPT_SEARCH_*.
+ *
+ * @return 0 on success, a negative AVERROR if some option was found in obj,
+ * but could not be set.
+ *
+ * @see av_dict_copy()
+ */
+int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags);
+
+/**
+ * Extract a key-value pair from the beginning of a string.
+ *
+ * @param ropts pointer to the options string, will be updated to
+ * point to the rest of the string (one of the pairs_sep
+ * or the final NUL)
+ * @param key_val_sep a 0-terminated list of characters used to separate
+ * key from value, for example '='
+ * @param pairs_sep a 0-terminated list of characters used to separate
+ * two pairs from each other, for example ':' or ','
+ * @param flags flags; see the AV_OPT_FLAG_* values below
+ * @param rkey parsed key; must be freed using av_free()
+ * @param rval parsed value; must be freed using av_free()
+ *
+ * @return >=0 for success, or a negative value corresponding to an
+ * AVERROR code in case of error; in particular:
+ * AVERROR(EINVAL) if no key is present
+ *
+ */
+int av_opt_get_key_value(const char **ropts,
+ const char *key_val_sep, const char *pairs_sep,
+ unsigned flags,
+ char **rkey, char **rval);
+
+enum {
+
+ /**
+ * Accept to parse a value without a key; the key will then be returned
+ * as NULL.
+ */
+ AV_OPT_FLAG_IMPLICIT_KEY = 1,
+};
+
/**
* @defgroup opt_eval_funcs Evaluating option strings
* @{
@@ -391,6 +610,13 @@ int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational
#define AV_OPT_SEARCH_FAKE_OBJ 0x0002
/**
+ * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than
+ * one component for certain option types.
+ * @see AVOptionRanges for details.
+ */
+#define AV_OPT_MULTI_COMPONENT_RANGE 0x1000
+
+/**
* Look for an option in an object. Consider only options which
* have all the specified flags set.
*
@@ -448,7 +674,7 @@ const AVOption *av_opt_find2(void *obj, const char *name, const char *unit,
* or NULL
* @return next AVOption or NULL
*/
-const AVOption *av_opt_next(void *obj, const AVOption *prev);
+const AVOption *av_opt_next(FF_CONST_AVUTIL55 void *obj, const AVOption *prev);
/**
* Iterate over AVOptions-enabled children of obj.
@@ -497,11 +723,33 @@ int av_opt_set_int (void *obj, const char *name, int64_t val, int search
int av_opt_set_double (void *obj, const char *name, double val, int search_flags);
int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags);
int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags);
+int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags);
+int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags);
+int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags);
+int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags);
+int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags);
/**
* @note Any old dictionary present is discarded and replaced with a copy of the new one. The
* caller still owns val is and responsible for freeing it.
*/
int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags);
+
+/**
+ * Set a binary option to an integer list.
+ *
+ * @param obj AVClass object to set options on
+ * @param name name of the binary option
+ * @param val pointer to an integer list (must have the correct type with
+ * regard to the contents of the list)
+ * @param term list terminator (usually 0 or -1)
+ * @param flags search flags
+ */
+#define av_opt_set_int_list(obj, name, val, term, flags) \
+ (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \
+ AVERROR(EINVAL) : \
+ av_opt_set_bin(obj, name, (const uint8_t *)(val), \
+ av_int_list_length(val, term) * sizeof(*(val)), flags))
+
/**
* @}
*/
@@ -516,15 +764,20 @@ int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, in
* @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN
* is passed here, then the option may be found in a child of obj.
* @param[out] out_val value of the option will be written here
- * @return 0 on success, a negative error code otherwise
+ * @return >=0 on success, a negative error code otherwise
*/
/**
- * @note the returned string will av_malloc()ed and must be av_free()ed by the caller
+ * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller
*/
int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val);
int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val);
int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val);
int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val);
+int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out);
+int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt);
+int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt);
+int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val);
+int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout);
/**
* @param[out] out_val The returned dictionary is a copy of the actual value and must
* be freed with av_dict_free() by the caller
@@ -532,6 +785,116 @@ int av_opt_get_q (void *obj, const char *name, int search_flags, AVRationa
int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val);
/**
* @}
+ */
+/**
+ * Gets a pointer to the requested field in a struct.
+ * This function allows accessing a struct even when its fields are moved or
+ * renamed since the application making the access has been compiled,
+ *
+ * @returns a pointer to the field, it can be cast to the correct type and read
+ * or written to.
+ */
+void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name);
+
+/**
+ * Free an AVOptionRanges struct and set it to NULL.
+ */
+void av_opt_freep_ranges(AVOptionRanges **ranges);
+
+/**
+ * Get a list of allowed ranges for the given option.
+ *
+ * The returned list may depend on other fields in obj like for example profile.
+ *
+ * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored
+ * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance
+ * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges
+ *
+ * The result must be freed with av_opt_freep_ranges.
+ *
+ * @return number of compontents returned on success, a negative errro code otherwise
+ */
+int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags);
+
+/**
+ * Copy options from src object into dest object.
+ *
+ * Options that require memory allocation (e.g. string or binary) are malloc'ed in dest object.
+ * Original memory allocated for such options is freed unless both src and dest options points to the same memory.
+ *
+ * @param dest Object to copy from
+ * @param src Object to copy into
+ * @return 0 on success, negative on error
+ */
+int av_opt_copy(void *dest, FF_CONST_AVUTIL55 void *src);
+
+/**
+ * Get a default list of allowed ranges for the given option.
+ *
+ * This list is constructed without using the AVClass.query_ranges() callback
+ * and can be used as fallback from within the callback.
+ *
+ * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored
+ * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance
+ * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges
+ *
+ * The result must be freed with av_opt_free_ranges.
+ *
+ * @return number of compontents returned on success, a negative errro code otherwise
+ */
+int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags);
+
+/**
+ * Check if given option is set to its default value.
+ *
+ * Options o must belong to the obj. This function must not be called to check child's options state.
+ * @see av_opt_is_set_to_default_by_name().
+ *
+ * @param obj AVClass object to check option on
+ * @param o option to be checked
+ * @return >0 when option is set to its default,
+ * 0 when option is not set its default,
+ * <0 on error
+ */
+int av_opt_is_set_to_default(void *obj, const AVOption *o);
+
+/**
+ * Check if given option is set to its default value.
+ *
+ * @param obj AVClass object to check option on
+ * @param name option name
+ * @param search_flags combination of AV_OPT_SEARCH_*
+ * @return >0 when option is set to its default,
+ * 0 when option is not set its default,
+ * <0 on error
+ */
+int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags);
+
+
+#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only.
+#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only.
+
+/**
+ * Serialize object's options.
+ *
+ * Create a string containing object's serialized options.
+ * Such string may be passed back to av_opt_set_from_string() in order to restore option values.
+ * A key/value or pairs separator occurring in the serialized value or
+ * name string are escaped through the av_escape() function.
+ *
+ * @param[in] obj AVClass object to serialize
+ * @param[in] opt_flags serialize options with all the specified flags set (AV_OPT_FLAG)
+ * @param[in] flags combination of AV_OPT_SERIALIZE_* flags
+ * @param[out] buffer Pointer to buffer that will be allocated with string containg serialized options.
+ * Buffer must be freed by the caller when is no longer needed.
+ * @param[in] key_val_sep character used to separate key from value
+ * @param[in] pairs_sep character used to separate two pairs from each other
+ * @return >= 0 on success, negative on error
+ * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same.
+ */
+int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer,
+ const char key_val_sep, const char pairs_sep);
+/**
* @}
*/
diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c
index be238f0dde..98858394ea 100644
--- a/libavutil/parseutils.c
+++ b/libavutil/parseutils.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,6 +32,36 @@
#include "time_internal.h"
#include "parseutils.h"
+#ifdef TEST
+
+#define av_get_random_seed av_get_random_seed_deterministic
+static uint32_t av_get_random_seed_deterministic(void);
+
+#define time(t) 1331972053
+
+#endif
+
+int av_parse_ratio(AVRational *q, const char *str, int max,
+ int log_offset, void *log_ctx)
+{
+ char c;
+ int ret;
+
+ if (sscanf(str, "%d:%d%c", &q->num, &q->den, &c) != 2) {
+ double d;
+ ret = av_expr_parse_and_eval(&d, str, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, log_offset, log_ctx);
+ if (ret < 0)
+ return ret;
+ *q = av_d2q(d, max);
+ } else {
+ av_reduce(&q->num, &q->den, q->num, q->den, max);
+ }
+
+ return 0;
+}
+
typedef struct VideoSizeAbbr {
const char *abbr;
int width, height;
@@ -80,6 +110,18 @@ static const VideoSizeAbbr video_size_abbrs[] = {
{ "hd480", 852, 480 },
{ "hd720", 1280, 720 },
{ "hd1080", 1920,1080 },
+ { "2k", 2048,1080 }, /* Digital Cinema System Specification */
+ { "2kflat", 1998,1080 },
+ { "2kscope", 2048, 858 },
+ { "4k", 4096,2160 }, /* Digital Cinema System Specification */
+ { "4kflat", 3996,2160 },
+ { "4kscope", 4096,1716 },
+ { "nhd", 640,360 },
+ { "hqvga", 240,160 },
+ { "wqvga", 400,240 },
+ { "fwqvga", 432,240 },
+ { "hvga", 480,320 },
+ { "qhd", 960,540 },
};
static const VideoRateAbbr video_rate_abbrs[]= {
@@ -97,7 +139,7 @@ int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
{
int i;
int n = FF_ARRAY_ELEMS(video_size_abbrs);
- char *p;
+ const char *p;
int width = 0, height = 0;
for (i = 0; i < n; i++) {
@@ -108,10 +150,14 @@ int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
}
}
if (i == n) {
- width = strtol(str, &p, 10);
+ width = strtol(str, (void*)&p, 10);
if (*p)
p++;
- height = strtol(p, &p, 10);
+ height = strtol(p, (void*)&p, 10);
+
+ /* trailing extraneous data detected, like in 123x345foobar */
+ if (*p)
+ return AVERROR(EINVAL);
}
if (width <= 0 || height <= 0)
return AVERROR(EINVAL);
@@ -124,7 +170,6 @@ int av_parse_video_rate(AVRational *rate, const char *arg)
{
int i, ret;
int n = FF_ARRAY_ELEMS(video_rate_abbrs);
- double res;
/* First, we check our abbreviation table */
for (i = 0; i < n; ++i)
@@ -134,10 +179,8 @@ int av_parse_video_rate(AVRational *rate, const char *arg)
}
/* Then, we try to parse it as fraction */
- if ((ret = av_expr_parse_and_eval(&res, arg, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, 0, NULL)) < 0)
+ if ((ret = av_parse_ratio_quiet(rate, arg, 1001000)) < 0)
return ret;
- *rate = av_d2q(res, 1001000);
if (rate->num <= 0 || rate->den <= 0)
return AVERROR(EINVAL);
return 0;
@@ -148,7 +191,7 @@ typedef struct ColorEntry {
uint8_t rgb_color[3]; ///< RGB values for the color
} ColorEntry;
-static ColorEntry color_table[] = {
+static const ColorEntry color_table[] = {
{ "AliceBlue", { 0xF0, 0xF8, 0xFF } },
{ "AntiqueWhite", { 0xFA, 0xEB, 0xD7 } },
{ "Aqua", { 0x00, 0xFF, 0xFF } },
@@ -216,8 +259,8 @@ static ColorEntry color_table[] = {
{ "LightCoral", { 0xF0, 0x80, 0x80 } },
{ "LightCyan", { 0xE0, 0xFF, 0xFF } },
{ "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
- { "LightGrey", { 0xD3, 0xD3, 0xD3 } },
{ "LightGreen", { 0x90, 0xEE, 0x90 } },
+ { "LightGrey", { 0xD3, 0xD3, 0xD3 } },
{ "LightPink", { 0xFF, 0xB6, 0xC1 } },
{ "LightSalmon", { 0xFF, 0xA0, 0x7A } },
{ "LightSeaGreen", { 0x20, 0xB2, 0xAA } },
@@ -360,7 +403,11 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
if (!strncmp(alpha_string, "0x", 2)) {
alpha = strtoul(alpha_string, &tail, 16);
} else {
- alpha = 255 * strtod(alpha_string, &tail);
+ double norm_alpha = strtod(alpha_string, &tail);
+ if (norm_alpha < 0.0 || norm_alpha > 1.0)
+ alpha = 256;
+ else
+ alpha = 255 * norm_alpha;
}
if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) {
@@ -374,6 +421,20 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
return 0;
}
+const char *av_get_known_color_name(int color_idx, const uint8_t **rgbp)
+{
+ const ColorEntry *color;
+
+ if ((unsigned)color_idx >= FF_ARRAY_ELEMS(color_table))
+ return NULL;
+
+ color = &color_table[color_idx];
+ if (rgbp)
+ *rgbp = color->rgb_color;
+
+ return color->name;
+}
+
/* get a positive number between n_min and n_max, for a maximum length
of len_max. Return -1 if error. */
static int date_get_num(const char **pp,
@@ -400,7 +461,7 @@ static int date_get_num(const char **pp,
return val;
}
-const char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
+char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
{
int c, val;
@@ -417,7 +478,9 @@ const char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
c = *fmt++;
switch(c) {
case 'H':
- val = date_get_num(&p, 0, 23, 2);
+ case 'J':
+ val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, 2);
+
if (val == -1)
return NULL;
dt->tm_hour = val;
@@ -466,7 +529,7 @@ const char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
}
}
- return p;
+ return (char*)p;
}
time_t av_timegm(struct tm *tm)
@@ -480,7 +543,7 @@ time_t av_timegm(struct tm *tm)
y--;
}
- t = 86400 *
+ t = 86400LL *
(d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
@@ -490,9 +553,11 @@ time_t av_timegm(struct tm *tm)
int av_parse_time(int64_t *timeval, const char *timestr, int duration)
{
- const char *p;
+ const char *p, *q;
int64_t t;
+ time_t now;
struct tm dt = { 0 }, tmbuf;
+ int today = 0, negative = 0, microseconds = 0;
int i;
static const char * const date_fmt[] = {
"%Y-%m-%d",
@@ -502,24 +567,14 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
"%H:%M:%S",
"%H%M%S",
};
- const char *q;
- int is_utc, len;
- char lastch;
- int negative = 0;
-
- time_t now = time(0);
-
- len = strlen(timestr);
- if (len > 0)
- lastch = timestr[len - 1];
- else
- lastch = '\0';
- is_utc = (lastch == 'z' || lastch == 'Z');
p = timestr;
q = NULL;
+ *timeval = INT64_MIN;
if (!duration) {
- if (!av_strncasecmp(timestr, "now", len)) {
+ now = time(0);
+
+ if (!av_strcasecmp(timestr, "now")) {
*timeval = (int64_t) now * 1000000;
return 0;
}
@@ -527,23 +582,17 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
/* parse the year-month-day part */
for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
q = av_small_strptime(p, date_fmt[i], &dt);
- if (q) {
+ if (q)
break;
- }
}
/* if the year-month-day part is missing, then take the
* current year-month-day time */
if (!q) {
- if (is_utc) {
- dt = *gmtime_r(&now, &tmbuf);
- } else {
- dt = *localtime_r(&now, &tmbuf);
- }
- dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
- } else {
- p = q;
+ today = 1;
+ q = p;
}
+ p = q;
if (*p == 'T' || *p == 't' || *p == ' ')
p++;
@@ -551,9 +600,8 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
/* parse the hour-minute-second part */
for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
q = av_small_strptime(p, time_fmt[i], &dt);
- if (q) {
+ if (q)
break;
- }
}
} else {
/* parse timestr as a duration */
@@ -562,16 +610,18 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
++p;
}
/* parse timestr as HH:MM:SS */
- q = av_small_strptime(p, time_fmt[0], &dt);
+ q = av_small_strptime(p, "%J:%M:%S", &dt);
+ if (!q) {
+ /* parse timestr as MM:SS */
+ q = av_small_strptime(p, "%M:%S", &dt);
+ dt.tm_hour = 0;
+ }
if (!q) {
char *o;
/* parse timestr as S+ */
dt.tm_sec = strtol(p, &o, 10);
- if (o == p) {
- /* the parsing didn't succeed */
- *timeval = INT64_MIN;
+ if (o == p) /* the parsing didn't succeed */
return AVERROR(EINVAL);
- }
dt.tm_min = 0;
dt.tm_hour = 0;
q = o;
@@ -579,35 +629,43 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
}
/* Now we have all the fields that we can get */
- if (!q) {
- *timeval = INT64_MIN;
+ if (!q)
return AVERROR(EINVAL);
+
+ /* parse the .m... part */
+ if (*q == '.') {
+ int n;
+ q++;
+ for (n = 100000; n >= 1; n /= 10, q++) {
+ if (!av_isdigit(*q))
+ break;
+ microseconds += n * (*q - '0');
+ }
+ while (av_isdigit(*q))
+ q++;
}
if (duration) {
t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
} else {
- dt.tm_isdst = -1; /* unknown */
- if (is_utc) {
- t = av_timegm(&dt);
- } else {
- t = mktime(&dt);
+ int is_utc = *q == 'Z' || *q == 'z';
+ q += is_utc;
+ if (today) { /* fill in today's date */
+ struct tm dt2 = is_utc ? *gmtime_r(&now, &tmbuf) : *localtime_r(&now, &tmbuf);
+ dt2.tm_hour = dt.tm_hour;
+ dt2.tm_min = dt.tm_min;
+ dt2.tm_sec = dt.tm_sec;
+ dt = dt2;
}
+ t = is_utc ? av_timegm(&dt) : mktime(&dt);
}
- t *= 1000000;
+ /* Check that we are at the end of the string */
+ if (*q)
+ return AVERROR(EINVAL);
- /* parse the .m... part */
- if (*q == '.') {
- int val, n;
- q++;
- for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
- if (!av_isdigit(*q))
- break;
- val += n * (*q - '0');
- }
- t += val;
- }
+ t *= 1000000;
+ t += microseconds;
*timeval = negative ? -t : t;
return 0;
}
@@ -653,6 +711,13 @@ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info
#ifdef TEST
+static uint32_t randomv = MKTAG('L','A','V','U');
+
+static uint32_t av_get_random_seed_deterministic(void)
+{
+ return randomv = randomv * 1664525 + 1013904223;
+}
+
int main(void)
{
printf("Testing av_parse_video_rate()\n");
@@ -700,6 +765,8 @@ int main(void)
int i;
uint8_t rgba[4];
static const char *const color_names[] = {
+ "bikeshed",
+ "RaNdOm",
"foo",
"red",
"Red ",
@@ -742,6 +809,84 @@ int main(void)
if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
printf("%s -> R(%d) G(%d) B(%d) A(%d)\n",
color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
+ else
+ printf("%s -> error\n", color_names[i]);
+ }
+ }
+
+ printf("\nTesting av_small_strptime()\n");
+ {
+ int i;
+ struct tm tm = { 0 };
+ struct fmt_timespec_entry {
+ const char *fmt, *timespec;
+ } fmt_timespec_entries[] = {
+ { "%Y-%m-%d", "2012-12-21" },
+ { "%Y - %m - %d", "2012-12-21" },
+ { "%Y-%m-%d %H:%M:%S", "2012-12-21 20:12:21" },
+ { " %Y - %m - %d %H : %M : %S", " 2012 - 12 - 21 20 : 12 : 21" },
+ };
+
+ av_log_set_level(AV_LOG_DEBUG);
+ for (i = 0; i < FF_ARRAY_ELEMS(fmt_timespec_entries); i++) {
+ char *p;
+ struct fmt_timespec_entry *e = &fmt_timespec_entries[i];
+ printf("fmt:'%s' spec:'%s' -> ", e->fmt, e->timespec);
+ p = av_small_strptime(e->timespec, e->fmt, &tm);
+ if (p) {
+ printf("%04d-%02d-%2d %02d:%02d:%02d\n",
+ 1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+ } else {
+ printf("error\n");
+ }
+ }
+ }
+
+ printf("\nTesting av_parse_time()\n");
+ {
+ int i;
+ int64_t tv;
+ time_t tvi;
+ struct tm *tm;
+ static char tzstr[] = "TZ=CET-1";
+ static const char * const time_string[] = {
+ "now",
+ "12:35:46",
+ "2000-12-20 0:02:47.5z",
+ "2000-12-20T010247.6",
+ };
+ static const char * const duration_string[] = {
+ "2:34:56.79",
+ "-1:23:45.67",
+ "42.1729",
+ "-1729.42",
+ "12:34",
+ };
+
+ av_log_set_level(AV_LOG_DEBUG);
+ putenv(tzstr);
+ printf("(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)\n");
+ for (i = 0; i < FF_ARRAY_ELEMS(time_string); i++) {
+ printf("%-24s -> ", time_string[i]);
+ if (av_parse_time(&tv, time_string[i], 0)) {
+ printf("error\n");
+ } else {
+ tvi = tv / 1000000;
+ tm = gmtime(&tvi);
+ printf("%14"PRIi64".%06d = %04d-%02d-%02dT%02d:%02d:%02dZ\n",
+ tv / 1000000, (int)(tv % 1000000),
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ }
+ }
+ for (i = 0; i < FF_ARRAY_ELEMS(duration_string); i++) {
+ printf("%-24s -> ", duration_string[i]);
+ if (av_parse_time(&tv, duration_string[i], 1)) {
+ printf("error\n");
+ } else {
+ printf("%+21"PRIi64"\n", tv);
+ }
}
}
diff --git a/libavutil/parseutils.h b/libavutil/parseutils.h
index 8e99634773..e66d24b76e 100644
--- a/libavutil/parseutils.h
+++ b/libavutil/parseutils.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,6 +29,30 @@
*/
/**
+ * Parse str and store the parsed ratio in q.
+ *
+ * Note that a ratio with infinite (1/0) or negative value is
+ * considered valid, so you should check on the returned value if you
+ * want to exclude those values.
+ *
+ * The undefined value can be expressed using the "0:0" string.
+ *
+ * @param[in,out] q pointer to the AVRational which will contain the ratio
+ * @param[in] str the string to parse: it has to be a string in the format
+ * num:den, a float number or an expression
+ * @param[in] max the maximum allowed numerator and denominator
+ * @param[in] log_offset log level offset which is applied to the log
+ * level of log_ctx
+ * @param[in] log_ctx parent logging context
+ * @return >= 0 on success, a negative error code otherwise
+ */
+int av_parse_ratio(AVRational *q, const char *str, int max,
+ int log_offset, void *log_ctx);
+
+#define av_parse_ratio_quiet(rate, str, max) \
+ av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL)
+
+/**
* Parse str and put in width_ptr and height_ptr the detected values.
*
* @param[in,out] width_ptr pointer to the variable which will contain the detected
@@ -75,6 +99,19 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
void *log_ctx);
/**
+ * Get the name of a color from the internal table of hard-coded named
+ * colors.
+ *
+ * This function is meant to enumerate the color names recognized by
+ * av_parse_color().
+ *
+ * @param color_idx index of the requested color, starting from 0
+ * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB
+ * @return the color name string or NULL if color_idx is not in the array
+ */
+const char *av_get_known_color_name(int color_idx, const uint8_t **rgb);
+
+/**
* Parse timestr and return in *time a corresponding number of
* microseconds.
*
@@ -88,7 +125,7 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
* @param timestr a string representing a date or a duration.
* - If a date the syntax is:
* @code
- * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH[:MM[:SS[.m...]]]}|{HH[MM[SS[.m...]]]}}[Z]
+ * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z]
* now
* @endcode
* If the value is "now" it takes the current time.
@@ -98,12 +135,12 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
* year-month-day.
* - If a duration the syntax is:
* @code
- * [-]HH[:MM[:SS[.m...]]]
+ * [-][HH:]MM:SS[.m...]
* [-]S+[.m...]
* @endcode
* @param duration flag which tells how to interpret timestr, if not
* zero timestr is interpreted as a duration, otherwise as a date
- * @return 0 in case of success, a negative value corresponding to an
+ * @return >= 0 in case of success, a negative value corresponding to an
* AVERROR code otherwise
*/
int av_parse_time(int64_t *timeval, const char *timestr, int duration);
@@ -121,12 +158,13 @@ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info
*
* Parse the input string p according to the format string fmt and
* store its results in the structure dt.
- *
- * Neither text and locale's alternative representation are supported.
+ * This implementation supports only a subset of the formats supported
+ * by the standard strptime().
*
* The supported input field descriptors are listed below.
* - %H: the hour as a decimal number, using a 24-hour clock, in the
* range '00' through '23'
+ * - %J: hours as a decimal number, in the range '0' through INT_MAX
* - %M: the minute as a decimal number, using a 24-hour clock, in the
* range '00' through '59'
* - %S: the second as a decimal number, using a 24-hour clock, in the
@@ -145,7 +183,7 @@ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info
* is consumed the return value points to the null byte at the end of
* the string. On failure NULL is returned.
*/
-const char *av_small_strptime(const char *p, const char *fmt, struct tm *dt);
+char *av_small_strptime(const char *p, const char *fmt, struct tm *dt);
/**
* Convert the decomposed UTC time in tm to a time_t value.
diff --git a/libavutil/pca.c b/libavutil/pca.c
new file mode 100644
index 0000000000..1d88ff300a
--- /dev/null
+++ b/libavutil/pca.c
@@ -0,0 +1,256 @@
+/*
+ * principal component analysis (PCA)
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * principal component analysis (PCA)
+ */
+
+#include "common.h"
+#include "pca.h"
+
+typedef struct PCA{
+ int count;
+ int n;
+ double *covariance;
+ double *mean;
+ double *z;
+}PCA;
+
+PCA *ff_pca_init(int n){
+ PCA *pca;
+ if(n<=0)
+ return NULL;
+
+ pca= av_mallocz(sizeof(*pca));
+ if (!pca)
+ return NULL;
+
+ pca->n= n;
+ pca->z = av_malloc_array(n, sizeof(*pca->z));
+ pca->count=0;
+ pca->covariance= av_calloc(n*n, sizeof(double));
+ pca->mean= av_calloc(n, sizeof(double));
+
+ if (!pca->z || !pca->covariance || !pca->mean) {
+ ff_pca_free(pca);
+ return NULL;
+ }
+
+ return pca;
+}
+
+void ff_pca_free(PCA *pca){
+ av_freep(&pca->covariance);
+ av_freep(&pca->mean);
+ av_freep(&pca->z);
+ av_free(pca);
+}
+
+void ff_pca_add(PCA *pca, const double *v){
+ int i, j;
+ const int n= pca->n;
+
+ for(i=0; i<n; i++){
+ pca->mean[i] += v[i];
+ for(j=i; j<n; j++)
+ pca->covariance[j + i*n] += v[i]*v[j];
+ }
+ pca->count++;
+}
+
+int ff_pca(PCA *pca, double *eigenvector, double *eigenvalue){
+ int i, j, pass;
+ int k=0;
+ const int n= pca->n;
+ double *z = pca->z;
+
+ memset(eigenvector, 0, sizeof(double)*n*n);
+
+ for(j=0; j<n; j++){
+ pca->mean[j] /= pca->count;
+ eigenvector[j + j*n] = 1.0;
+ for(i=0; i<=j; i++){
+ pca->covariance[j + i*n] /= pca->count;
+ pca->covariance[j + i*n] -= pca->mean[i] * pca->mean[j];
+ pca->covariance[i + j*n] = pca->covariance[j + i*n];
+ }
+ eigenvalue[j]= pca->covariance[j + j*n];
+ z[j]= 0;
+ }
+
+ for(pass=0; pass < 50; pass++){
+ double sum=0;
+
+ for(i=0; i<n; i++)
+ for(j=i+1; j<n; j++)
+ sum += fabs(pca->covariance[j + i*n]);
+
+ if(sum == 0){
+ for(i=0; i<n; i++){
+ double maxvalue= -1;
+ for(j=i; j<n; j++){
+ if(eigenvalue[j] > maxvalue){
+ maxvalue= eigenvalue[j];
+ k= j;
+ }
+ }
+ eigenvalue[k]= eigenvalue[i];
+ eigenvalue[i]= maxvalue;
+ for(j=0; j<n; j++){
+ double tmp= eigenvector[k + j*n];
+ eigenvector[k + j*n]= eigenvector[i + j*n];
+ eigenvector[i + j*n]= tmp;
+ }
+ }
+ return pass;
+ }
+
+ for(i=0; i<n; i++){
+ for(j=i+1; j<n; j++){
+ double covar= pca->covariance[j + i*n];
+ double t,c,s,tau,theta, h;
+
+ if(pass < 3 && fabs(covar) < sum / (5*n*n)) //FIXME why pass < 3
+ continue;
+ if(fabs(covar) == 0.0) //FIXME should not be needed
+ continue;
+ if(pass >=3 && fabs((eigenvalue[j]+z[j])/covar) > (1LL<<32) && fabs((eigenvalue[i]+z[i])/covar) > (1LL<<32)){
+ pca->covariance[j + i*n]=0.0;
+ continue;
+ }
+
+ h= (eigenvalue[j]+z[j]) - (eigenvalue[i]+z[i]);
+ theta=0.5*h/covar;
+ t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
+ if(theta < 0.0) t = -t;
+
+ c=1.0/sqrt(1+t*t);
+ s=t*c;
+ tau=s/(1.0+c);
+ z[i] -= t*covar;
+ z[j] += t*covar;
+
+#define ROTATE(a,i,j,k,l) {\
+ double g=a[j + i*n];\
+ double h=a[l + k*n];\
+ a[j + i*n]=g-s*(h+g*tau);\
+ a[l + k*n]=h+s*(g-h*tau); }
+ for(k=0; k<n; k++) {
+ if(k!=i && k!=j){
+ ROTATE(pca->covariance,FFMIN(k,i),FFMAX(k,i),FFMIN(k,j),FFMAX(k,j))
+ }
+ ROTATE(eigenvector,k,i,k,j)
+ }
+ pca->covariance[j + i*n]=0.0;
+ }
+ }
+ for (i=0; i<n; i++) {
+ eigenvalue[i] += z[i];
+ z[i]=0.0;
+ }
+ }
+
+ return -1;
+}
+
+#ifdef TEST
+
+#undef printf
+#include <stdio.h>
+#include <stdlib.h>
+#include "lfg.h"
+
+int main(void){
+ PCA *pca;
+ int i, j, k;
+#define LEN 8
+ double eigenvector[LEN*LEN];
+ double eigenvalue[LEN];
+ AVLFG prng;
+
+ av_lfg_init(&prng, 1);
+
+ pca= ff_pca_init(LEN);
+
+ for(i=0; i<9000000; i++){
+ double v[2*LEN+100];
+ double sum=0;
+ int pos = av_lfg_get(&prng) % LEN;
+ int v2 = av_lfg_get(&prng) % 101 - 50;
+ v[0] = av_lfg_get(&prng) % 101 - 50;
+ for(j=1; j<8; j++){
+ if(j<=pos) v[j]= v[0];
+ else v[j]= v2;
+ sum += v[j];
+ }
+/* for(j=0; j<LEN; j++){
+ v[j] -= v[pos];
+ }*/
+// sum += av_lfg_get(&prng) % 10;
+/* for(j=0; j<LEN; j++){
+ v[j] -= sum/LEN;
+ }*/
+// lbt1(v+100,v+100,LEN);
+ ff_pca_add(pca, v);
+ }
+
+
+ ff_pca(pca, eigenvector, eigenvalue);
+ for(i=0; i<LEN; i++){
+ pca->count= 1;
+ pca->mean[i]= 0;
+
+// (0.5^|x|)^2 = 0.5^2|x| = 0.25^|x|
+
+
+// pca.covariance[i + i*LEN]= pow(0.5, fabs
+ for(j=i; j<LEN; j++){
+ printf("%f ", pca->covariance[i + j*LEN]);
+ }
+ printf("\n");
+ }
+
+ for(i=0; i<LEN; i++){
+ double v[LEN];
+ double error=0;
+ memset(v, 0, sizeof(v));
+ for(j=0; j<LEN; j++){
+ for(k=0; k<LEN; k++){
+ v[j] += pca->covariance[FFMIN(k,j) + FFMAX(k,j)*LEN] * eigenvector[i + k*LEN];
+ }
+ v[j] /= eigenvalue[i];
+ error += fabs(v[j] - eigenvector[i + j*LEN]);
+ }
+ printf("%f ", error);
+ }
+ printf("\n");
+
+ for(i=0; i<LEN; i++){
+ for(j=0; j<LEN; j++){
+ printf("%9.6f ", eigenvector[i + j*LEN]);
+ }
+ printf(" %9.1f %f\n", eigenvalue[i], eigenvalue[i]/eigenvalue[0]);
+ }
+
+ return 0;
+}
+#endif
diff --git a/libavutil/pca.h b/libavutil/pca.h
new file mode 100644
index 0000000000..992bb2eb25
--- /dev/null
+++ b/libavutil/pca.h
@@ -0,0 +1,35 @@
+/*
+ * principal component analysis (PCA)
+ * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * principal component analysis (PCA)
+ */
+
+#ifndef AVUTIL_PCA_H
+#define AVUTIL_PCA_H
+
+struct PCA *ff_pca_init(int n);
+void ff_pca_free(struct PCA *pca);
+void ff_pca_add(struct PCA *pca, const double *v);
+int ff_pca(struct PCA *pca, double *eigenvector, double *eigenvalue);
+
+#endif /* AVUTIL_PCA_H */
diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index c2c0157e7a..32dc4b80ab 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -2,26 +2,27 @@
* pixel format descriptor
* Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
+#include "avassert.h"
#include "avstring.h"
#include "common.h"
#include "pixfmt.h"
@@ -182,9 +183,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 2, 1, 0, 7 }, /* B */
- { 0, 2, 2, 0, 7 }, /* G */
{ 0, 2, 3, 0, 7 }, /* R */
+ { 0, 2, 2, 0, 7 }, /* G */
+ { 0, 2, 1, 0, 7 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB,
},
@@ -236,6 +237,18 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_PLANAR,
},
+ [AV_PIX_FMT_YUVJ411P] = {
+ .name = "yuvj411p",
+ .nb_components = 3,
+ .log2_chroma_w = 2,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 0, 1, 0, 7 }, /* Y */
+ { 1, 0, 1, 0, 7 }, /* U */
+ { 2, 0, 1, 0, 7 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
[AV_PIX_FMT_GRAY8] = {
.name = "gray",
.nb_components = 1,
@@ -307,9 +320,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- {0, 0, 1, 0, 7}, /* Y */
- {1, 0, 1, 0, 7}, /* U */
- {2, 0, 1, 0, 7}, /* V */
+ { 0, 0, 1, 0, 7 }, /* Y */
+ { 1, 0, 1, 0, 7 }, /* U */
+ { 2, 0, 1, 0, 7 }, /* V */
},
.flags = AV_PIX_FMT_FLAG_PLANAR,
},
@@ -323,6 +336,12 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.flags = AV_PIX_FMT_FLAG_HWACCEL,
},
#endif /* FF_API_XVMC */
+#if !FF_API_XVMC
+ [AV_PIX_FMT_XVMC] = {
+ .name = "xvmc",
+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
+ },
+#endif /* !FF_API_XVMC */
[AV_PIX_FMT_UYVY422] = {
.name = "uyvy422",
.nb_components = 3,
@@ -351,9 +370,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 0, 1, 6, 1 }, /* B */
- { 0, 0, 1, 3, 2 }, /* G */
{ 0, 0, 1, 0, 2 }, /* R */
+ { 0, 0, 1, 3, 2 }, /* G */
+ { 0, 0, 1, 6, 1 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL,
},
@@ -363,9 +382,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 3, 1, 0, 0 }, /* B */
- { 0, 3, 2, 0, 1 }, /* G */
{ 0, 3, 4, 0, 0 }, /* R */
+ { 0, 3, 2, 0, 1 }, /* G */
+ { 0, 3, 1, 0, 0 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_RGB,
},
@@ -375,9 +394,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 0, 1, 3, 0 }, /* B */
- { 0, 0, 1, 1, 1 }, /* G */
{ 0, 0, 1, 0, 0 }, /* R */
+ { 0, 0, 1, 1, 1 }, /* G */
+ { 0, 0, 1, 3, 0 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL,
},
@@ -436,8 +455,8 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_h = 1,
.comp = {
{ 0, 0, 1, 0, 7 }, /* Y */
- { 1, 1, 1, 0, 7 }, /* V */
{ 1, 1, 2, 0, 7 }, /* U */
+ { 1, 1, 1, 0, 7 }, /* V */
},
.flags = AV_PIX_FMT_FLAG_PLANAR,
},
@@ -447,10 +466,10 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 3, 1, 0, 7 }, /* A */
{ 0, 3, 2, 0, 7 }, /* R */
{ 0, 3, 3, 0, 7 }, /* G */
{ 0, 3, 4, 0, 7 }, /* B */
+ { 0, 3, 1, 0, 7 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
},
@@ -473,10 +492,10 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 3, 1, 0, 7 }, /* A */
- { 0, 3, 2, 0, 7 }, /* B */
- { 0, 3, 3, 0, 7 }, /* G */
{ 0, 3, 4, 0, 7 }, /* R */
+ { 0, 3, 3, 0, 7 }, /* G */
+ { 0, 3, 2, 0, 7 }, /* B */
+ { 0, 3, 1, 0, 7 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
},
@@ -486,13 +505,61 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 3, 1, 0, 7 }, /* B */
- { 0, 3, 2, 0, 7 }, /* G */
{ 0, 3, 3, 0, 7 }, /* R */
+ { 0, 3, 2, 0, 7 }, /* G */
+ { 0, 3, 1, 0, 7 }, /* B */
{ 0, 3, 4, 0, 7 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
},
+ [AV_PIX_FMT_0RGB] = {
+ .name = "0rgb",
+ .nb_components= 3,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 0, 3, 2, 0, 7 }, /* R */
+ { 0, 3, 3, 0, 7 }, /* G */
+ { 0, 3, 4, 0, 7 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_RGB0] = {
+ .name = "rgb0",
+ .nb_components= 3,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 0, 3, 1, 0, 7 }, /* R */
+ { 0, 3, 2, 0, 7 }, /* G */
+ { 0, 3, 3, 0, 7 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_0BGR] = {
+ .name = "0bgr",
+ .nb_components= 3,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 0, 3, 4, 0, 7 }, /* R */
+ { 0, 3, 3, 0, 7 }, /* G */
+ { 0, 3, 2, 0, 7 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BGR0] = {
+ .name = "bgr0",
+ .nb_components= 3,
+ .log2_chroma_w= 0,
+ .log2_chroma_h= 0,
+ .comp = {
+ { 0, 3, 3, 0, 7 }, /* R */
+ { 0, 3, 2, 0, 7 }, /* G */
+ { 0, 3, 1, 0, 7 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
[AV_PIX_FMT_GRAY16BE] = {
.name = "gray16be",
.nb_components = 1,
@@ -538,6 +605,54 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_PLANAR,
},
+ [AV_PIX_FMT_YUV440P10LE] = {
+ .name = "yuv440p10le",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 9 }, /* Y */
+ { 1, 1, 1, 0, 9 }, /* U */
+ { 2, 1, 1, 0, 9 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV440P10BE] = {
+ .name = "yuv440p10be",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 9 }, /* Y */
+ { 1, 1, 1, 0, 9 }, /* U */
+ { 2, 1, 1, 0, 9 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV440P12LE] = {
+ .name = "yuv440p12le",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV440P12BE] = {
+ .name = "yuv440p12be",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
[AV_PIX_FMT_YUVA420P] = {
.name = "yuva420p",
.nb_components = 4,
@@ -551,7 +666,7 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA,
},
- [AV_PIX_FMT_YUVA422P] = {
+ [AV_PIX_FMT_YUVA422P] = {
.name = "yuva422p",
.nb_components = 4,
.log2_chroma_w = 1,
@@ -588,7 +703,7 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
{ 2, 1, 1, 0, 8 }, /* V */
{ 3, 1, 1, 0, 8 }, /* A */
},
- .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA,
},
[AV_PIX_FMT_YUVA420P9LE] = {
.name = "yuva420p9le",
@@ -977,9 +1092,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 5, 1, 0, 15 }, /* B */
- { 0, 5, 3, 0, 15 }, /* G */
{ 0, 5, 5, 0, 15 }, /* R */
+ { 0, 5, 3, 0, 15 }, /* G */
+ { 0, 5, 1, 0, 15 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
},
@@ -989,9 +1104,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 5, 1, 0, 15 }, /* B */
- { 0, 5, 3, 0, 15 }, /* G */
{ 0, 5, 5, 0, 15 }, /* R */
+ { 0, 5, 3, 0, 15 }, /* G */
+ { 0, 5, 1, 0, 15 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB,
},
@@ -1001,10 +1116,10 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 5, 1, 0, 15 }, /* B */
- { 0, 5, 3, 0, 15 }, /* G */
- { 0, 5, 5, 0, 15 }, /* R */
- { 0, 5, 7, 0, 15 }, /* A */
+ { 0, 7, 5, 0, 15 }, /* R */
+ { 0, 7, 3, 0, 15 }, /* G */
+ { 0, 7, 1, 0, 15 }, /* B */
+ { 0, 7, 7, 0, 15 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
},
@@ -1014,10 +1129,10 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 5, 1, 0, 15 }, /* B */
- { 0, 5, 3, 0, 15 }, /* G */
- { 0, 5, 5, 0, 15 }, /* R */
- { 0, 5, 7, 0, 15 }, /* A */
+ { 0, 7, 5, 0, 15 }, /* R */
+ { 0, 7, 3, 0, 15 }, /* G */
+ { 0, 7, 1, 0, 15 }, /* B */
+ { 0, 7, 7, 0, 15 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA,
},
@@ -1027,9 +1142,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 1, 0, 3, 4 }, /* B */
- { 0, 1, 1, 5, 5 }, /* G */
{ 0, 1, 1, 0, 4 }, /* R */
+ { 0, 1, 1, 5, 5 }, /* G */
+ { 0, 1, 0, 3, 4 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
},
@@ -1039,9 +1154,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 1, 2, 3, 4 }, /* B */
- { 0, 1, 1, 5, 5 }, /* G */
{ 0, 1, 1, 0, 4 }, /* R */
+ { 0, 1, 1, 5, 5 }, /* G */
+ { 0, 1, 2, 3, 4 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB,
},
@@ -1051,9 +1166,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 1, 0, 2, 4 }, /* B */
- { 0, 1, 1, 5, 4 }, /* G */
{ 0, 1, 1, 0, 4 }, /* R */
+ { 0, 1, 1, 5, 4 }, /* G */
+ { 0, 1, 0, 2, 4 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
},
@@ -1063,9 +1178,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 1, 2, 2, 4 }, /* B */
- { 0, 1, 1, 5, 4 }, /* G */
{ 0, 1, 1, 0, 4 }, /* R */
+ { 0, 1, 1, 5, 4 }, /* G */
+ { 0, 1, 2, 2, 4 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB,
},
@@ -1075,9 +1190,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 1, 0, 0, 3 }, /* B */
- { 0, 1, 1, 4, 3 }, /* G */
{ 0, 1, 1, 0, 3 }, /* R */
+ { 0, 1, 1, 4, 3 }, /* G */
+ { 0, 1, 0, 0, 3 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
},
@@ -1087,9 +1202,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
- { 0, 1, 2, 0, 3 }, /* B */
- { 0, 1, 1, 4, 3 }, /* G */
{ 0, 1, 1, 0, 3 }, /* R */
+ { 0, 1, 1, 4, 3 }, /* G */
+ { 0, 1, 2, 0, 3 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_RGB,
},
@@ -1111,12 +1226,6 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_h = 1,
.flags = AV_PIX_FMT_FLAG_HWACCEL,
},
- [AV_PIX_FMT_VDA_VLD] = {
- .name = "vda_vld",
- .log2_chroma_w = 1,
- .log2_chroma_h = 1,
- .flags = AV_PIX_FMT_FLAG_HWACCEL,
- },
[AV_PIX_FMT_YUV420P9LE] = {
.name = "yuv420p9le",
.nb_components = 3,
@@ -1165,6 +1274,54 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
},
+ [AV_PIX_FMT_YUV420P12LE] = {
+ .name = "yuv420p12le",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV420P12BE] = {
+ .name = "yuv420p12be",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV420P14LE] = {
+ .name = "yuv420p14le",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 13 }, /* Y */
+ { 1, 1, 1, 0, 13 }, /* U */
+ { 2, 1, 1, 0, 13 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV420P14BE] = {
+ .name = "yuv420p14be",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 1,
+ .comp = {
+ { 0, 1, 1, 0, 13 }, /* Y */
+ { 1, 1, 1, 0, 13 }, /* U */
+ { 2, 1, 1, 0, 13 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
[AV_PIX_FMT_YUV420P16LE] = {
.name = "yuv420p16le",
.nb_components = 3,
@@ -1237,6 +1394,54 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
},
+ [AV_PIX_FMT_YUV422P12LE] = {
+ .name = "yuv422p12le",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV422P12BE] = {
+ .name = "yuv422p12be",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV422P14LE] = {
+ .name = "yuv422p14le",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 13 }, /* Y */
+ { 1, 1, 1, 0, 13 }, /* U */
+ { 2, 1, 1, 0, 13 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV422P14BE] = {
+ .name = "yuv422p14be",
+ .nb_components = 3,
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 13 }, /* Y */
+ { 1, 1, 1, 0, 13 }, /* U */
+ { 2, 1, 1, 0, 13 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
[AV_PIX_FMT_YUV422P16LE] = {
.name = "yuv422p16le",
.nb_components = 3,
@@ -1333,6 +1538,54 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
},
+ [AV_PIX_FMT_YUV444P12LE] = {
+ .name = "yuv444p12le",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV444P12BE] = {
+ .name = "yuv444p12be",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 11 }, /* Y */
+ { 1, 1, 1, 0, 11 }, /* U */
+ { 2, 1, 1, 0, 11 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV444P14LE] = {
+ .name = "yuv444p14le",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 13 }, /* Y */
+ { 1, 1, 1, 0, 13 }, /* U */
+ { 2, 1, 1, 0, 13 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR,
+ },
+ [AV_PIX_FMT_YUV444P14BE] = {
+ .name = "yuv444p14be",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 0, 1, 1, 0, 13 }, /* Y */
+ { 1, 1, 1, 0, 13 }, /* U */
+ { 2, 1, 1, 0, 13 }, /* V */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR,
+ },
[AV_PIX_FMT_D3D11VA_VLD] = {
.name = "d3d11va_vld",
.log2_chroma_w = 1,
@@ -1345,6 +1598,12 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_h = 1,
.flags = AV_PIX_FMT_FLAG_HWACCEL,
},
+ [AV_PIX_FMT_VDA_VLD] = {
+ .name = "vda_vld",
+ .log2_chroma_w = 1,
+ .log2_chroma_h = 1,
+ .flags = AV_PIX_FMT_FLAG_HWACCEL,
+ },
[AV_PIX_FMT_YA8] = {
.name = "ya8",
.nb_components = 2,
@@ -1379,9 +1638,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 0, 1, 0, 7 }, /* R */
{ 0, 0, 1, 0, 7 }, /* G */
{ 1, 0, 1, 0, 7 }, /* B */
- { 2, 0, 1, 0, 7 }, /* R */
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1391,9 +1650,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 8 }, /* R */
{ 0, 1, 1, 0, 8 }, /* G */
{ 1, 1, 1, 0, 8 }, /* B */
- { 2, 1, 1, 0, 8 }, /* R */
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1403,9 +1662,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 8 }, /* R */
{ 0, 1, 1, 0, 8 }, /* G */
{ 1, 1, 1, 0, 8 }, /* B */
- { 2, 1, 1, 0, 8 }, /* R */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1415,9 +1674,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 9 }, /* R */
{ 0, 1, 1, 0, 9 }, /* G */
{ 1, 1, 1, 0, 9 }, /* B */
- { 2, 1, 1, 0, 9 }, /* R */
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1427,9 +1686,57 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 9 }, /* R */
{ 0, 1, 1, 0, 9 }, /* G */
{ 1, 1, 1, 0, 9 }, /* B */
- { 2, 1, 1, 0, 9 }, /* R */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_GBRP12LE] = {
+ .name = "gbrp12le",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 2, 1, 1, 0, 11 }, /* R */
+ { 0, 1, 1, 0, 11 }, /* G */
+ { 1, 1, 1, 0, 11 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_GBRP12BE] = {
+ .name = "gbrp12be",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 2, 1, 1, 0, 11 }, /* R */
+ { 0, 1, 1, 0, 11 }, /* G */
+ { 1, 1, 1, 0, 11 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_GBRP14LE] = {
+ .name = "gbrp14le",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 2, 1, 1, 0, 13 }, /* R */
+ { 0, 1, 1, 0, 13 }, /* G */
+ { 1, 1, 1, 0, 13 }, /* B */
+ },
+ .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_GBRP14BE] = {
+ .name = "gbrp14be",
+ .nb_components = 3,
+ .log2_chroma_w = 0,
+ .log2_chroma_h = 0,
+ .comp = {
+ { 2, 1, 1, 0, 13 }, /* R */
+ { 0, 1, 1, 0, 13 }, /* G */
+ { 1, 1, 1, 0, 13 }, /* B */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1439,9 +1746,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 15 }, /* R */
{ 0, 1, 1, 0, 15 }, /* G */
{ 1, 1, 1, 0, 15 }, /* B */
- { 2, 1, 1, 0, 15 }, /* R */
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1451,9 +1758,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 15 }, /* R */
{ 0, 1, 1, 0, 15 }, /* G */
{ 1, 1, 1, 0, 15 }, /* B */
- { 2, 1, 1, 0, 15 }, /* R */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB,
},
@@ -1463,9 +1770,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 0, 1, 0, 7 }, /* R */
{ 0, 0, 1, 0, 7 }, /* G */
{ 1, 0, 1, 0, 7 }, /* B */
- { 2, 0, 1, 0, 7 }, /* R */
{ 3, 0, 1, 0, 7 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB |
@@ -1477,9 +1784,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 15 }, /* R */
{ 0, 1, 1, 0, 15 }, /* G */
{ 1, 1, 1, 0, 15 }, /* B */
- { 2, 1, 1, 0, 15 }, /* R */
{ 3, 1, 1, 0, 15 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB |
@@ -1491,9 +1798,9 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
.log2_chroma_w = 0,
.log2_chroma_h = 0,
.comp = {
+ { 2, 1, 1, 0, 15 }, /* R */
{ 0, 1, 1, 0, 15 }, /* G */
{ 1, 1, 1, 0, 15 }, /* B */
- { 2, 1, 1, 0, 15 }, /* R */
{ 3, 1, 1, 0, 15 }, /* A */
},
.flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR |
@@ -1529,6 +1836,87 @@ const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
},
.flags = AV_PIX_FMT_FLAG_BE,
},
+
+#define BAYER8_DESC_COMMON \
+ .nb_components= 3, \
+ .log2_chroma_w= 0, \
+ .log2_chroma_h= 0, \
+ .comp = { \
+ {0,0,0,0,1}, \
+ {0,0,0,0,3}, \
+ {0,0,0,0,1}, \
+ }, \
+
+#define BAYER16_DESC_COMMON \
+ .nb_components= 3, \
+ .log2_chroma_w= 0, \
+ .log2_chroma_h= 0, \
+ .comp = { \
+ {0,1,0,0, 3}, \
+ {0,1,0,0, 7}, \
+ {0,1,0,0, 3}, \
+ }, \
+
+ [AV_PIX_FMT_BAYER_BGGR8] = {
+ .name = "bayer_bggr8",
+ BAYER8_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_BGGR16LE] = {
+ .name = "bayer_bggr16le",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_BGGR16BE] = {
+ .name = "bayer_bggr16be",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_RGGB8] = {
+ .name = "bayer_rggb8",
+ BAYER8_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_RGGB16LE] = {
+ .name = "bayer_rggb16le",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_RGGB16BE] = {
+ .name = "bayer_rggb16be",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_GBRG8] = {
+ .name = "bayer_gbrg8",
+ BAYER8_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_GBRG16LE] = {
+ .name = "bayer_gbrg16le",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_GBRG16BE] = {
+ .name = "bayer_gbrg16be",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_GRBG8] = {
+ .name = "bayer_grbg8",
+ BAYER8_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_GRBG16LE] = {
+ .name = "bayer_grbg16le",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_RGB,
+ },
+ [AV_PIX_FMT_BAYER_GRBG16BE] = {
+ .name = "bayer_grbg16be",
+ BAYER16_DESC_COMMON
+ .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB,
+ },
[AV_PIX_FMT_NV16] = {
.name = "nv16",
.nb_components = 3,
@@ -1664,6 +2052,26 @@ int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
return bits >> log2_pixels;
}
+int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
+{
+ int c, bits = 0;
+ int log2_pixels = pixdesc->log2_chroma_w + pixdesc->log2_chroma_h;
+ int steps[4] = {0};
+
+ for (c = 0; c < pixdesc->nb_components; c++) {
+ const AVComponentDescriptor *comp = &pixdesc->comp[c];
+ int s = c == 1 || c == 2 ? 0 : log2_pixels;
+ steps[comp->plane] = (comp->step_minus1 + 1) << s;
+ }
+ for (c = 0; c < 4; c++)
+ bits += steps[c];
+
+ if(!(pixdesc->flags & AV_PIX_FMT_FLAG_BITSTREAM))
+ bits *= 8;
+
+ return bits >> log2_pixels;
+}
+
char *av_get_pix_fmt_string(char *buf, int buf_size,
enum AVPixelFormat pix_fmt)
{
@@ -1690,8 +2098,11 @@ const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev)
{
if (!prev)
return &av_pix_fmt_descriptors[0];
- if (prev - av_pix_fmt_descriptors < FF_ARRAY_ELEMS(av_pix_fmt_descriptors) - 1)
- return prev + 1;
+ while (prev - av_pix_fmt_descriptors < FF_ARRAY_ELEMS(av_pix_fmt_descriptors) - 1) {
+ prev++;
+ if (prev->name)
+ return prev;
+ }
return NULL;
}
@@ -1703,7 +2114,6 @@ enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc)
return desc - av_pix_fmt_descriptors;
}
-FF_ENABLE_DEPRECATION_WARNINGS
int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt,
int *h_shift, int *v_shift)
@@ -1732,56 +2142,259 @@ int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
return ret;
}
+void ff_check_pixfmt_descriptors(void){
+ int i, j;
+
+ for (i=0; i<FF_ARRAY_ELEMS(av_pix_fmt_descriptors); i++) {
+ const AVPixFmtDescriptor *d = &av_pix_fmt_descriptors[i];
+ uint8_t fill[4][8+6+3] = {{0}};
+ uint8_t *data[4] = {fill[0], fill[1], fill[2], fill[3]};
+ int linesize[4] = {0,0,0,0};
+ uint16_t tmp[2];
+
+ if (!d->name && !d->nb_components && !d->log2_chroma_w && !d->log2_chroma_h && !d->flags)
+ continue;
+// av_log(NULL, AV_LOG_DEBUG, "Checking: %s\n", d->name);
+ av_assert0(d->log2_chroma_w <= 3);
+ av_assert0(d->log2_chroma_h <= 3);
+ av_assert0(d->nb_components <= 4);
+ av_assert0(d->name && d->name[0]);
+ av_assert0((d->nb_components==4 || d->nb_components==2) == !!(d->flags & AV_PIX_FMT_FLAG_ALPHA));
+ av_assert2(av_get_pix_fmt(d->name) == i);
+
+ for (j=0; j<FF_ARRAY_ELEMS(d->comp); j++) {
+ const AVComponentDescriptor *c = &d->comp[j];
+ if(j>=d->nb_components) {
+ av_assert0(!c->plane && !c->step_minus1 && !c->offset_plus1 && !c->shift && !c->depth_minus1);
+ continue;
+ }
+ if (d->flags & AV_PIX_FMT_FLAG_BITSTREAM) {
+ av_assert0(c->step_minus1 >= c->depth_minus1);
+ } else {
+ av_assert0(8*(c->step_minus1+1) >= c->depth_minus1+1);
+ }
+ if (!strncmp(d->name, "bayer_", 6))
+ continue;
+ av_read_image_line(tmp, (void*)data, linesize, d, 0, 0, j, 2, 0);
+ av_assert0(tmp[0] == 0 && tmp[1] == 0);
+ tmp[0] = tmp[1] = (1<<(c->depth_minus1 + 1)) - 1;
+ av_write_image_line(tmp, data, linesize, d, 0, 0, j, 2);
+ }
+ }
+}
+FF_ENABLE_DEPRECATION_WARNINGS
+
enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt)
{
-#define PIX_FMT_SWAP_ENDIANNESS(fmt) \
- case AV_PIX_FMT_ ## fmt ## BE: return AV_PIX_FMT_ ## fmt ## LE; \
- case AV_PIX_FMT_ ## fmt ## LE: return AV_PIX_FMT_ ## fmt ## BE
-
- switch (pix_fmt) {
- PIX_FMT_SWAP_ENDIANNESS(GRAY16);
- PIX_FMT_SWAP_ENDIANNESS(YA16);
- PIX_FMT_SWAP_ENDIANNESS(RGB48);
- PIX_FMT_SWAP_ENDIANNESS(RGB565);
- PIX_FMT_SWAP_ENDIANNESS(RGB555);
- PIX_FMT_SWAP_ENDIANNESS(RGB444);
- PIX_FMT_SWAP_ENDIANNESS(BGR48);
- PIX_FMT_SWAP_ENDIANNESS(BGR565);
- PIX_FMT_SWAP_ENDIANNESS(BGR555);
- PIX_FMT_SWAP_ENDIANNESS(BGR444);
-
- PIX_FMT_SWAP_ENDIANNESS(YUV420P9);
- PIX_FMT_SWAP_ENDIANNESS(YUV422P9);
- PIX_FMT_SWAP_ENDIANNESS(YUV444P9);
- PIX_FMT_SWAP_ENDIANNESS(YUV420P10);
- PIX_FMT_SWAP_ENDIANNESS(YUV422P10);
- PIX_FMT_SWAP_ENDIANNESS(YUV444P10);
- PIX_FMT_SWAP_ENDIANNESS(YUV420P16);
- PIX_FMT_SWAP_ENDIANNESS(YUV422P16);
- PIX_FMT_SWAP_ENDIANNESS(YUV444P16);
-
- PIX_FMT_SWAP_ENDIANNESS(GBRP9);
- PIX_FMT_SWAP_ENDIANNESS(GBRP10);
- PIX_FMT_SWAP_ENDIANNESS(GBRP16);
- PIX_FMT_SWAP_ENDIANNESS(YUVA420P9);
- PIX_FMT_SWAP_ENDIANNESS(YUVA422P9);
- PIX_FMT_SWAP_ENDIANNESS(YUVA444P9);
- PIX_FMT_SWAP_ENDIANNESS(YUVA420P10);
- PIX_FMT_SWAP_ENDIANNESS(YUVA422P10);
- PIX_FMT_SWAP_ENDIANNESS(YUVA444P10);
- PIX_FMT_SWAP_ENDIANNESS(YUVA420P16);
- PIX_FMT_SWAP_ENDIANNESS(YUVA422P16);
- PIX_FMT_SWAP_ENDIANNESS(YUVA444P16);
-
- PIX_FMT_SWAP_ENDIANNESS(XYZ12);
- PIX_FMT_SWAP_ENDIANNESS(NV20);
- PIX_FMT_SWAP_ENDIANNESS(RGBA64);
- PIX_FMT_SWAP_ENDIANNESS(BGRA64);
- default:
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ char name[16];
+ int i;
+
+ if (!desc || strlen(desc->name) < 2)
+ return AV_PIX_FMT_NONE;
+ av_strlcpy(name, desc->name, sizeof(name));
+ i = strlen(name) - 2;
+ if (strcmp(name + i, "be") && strcmp(name + i, "le"))
return AV_PIX_FMT_NONE;
+
+ name[i] ^= 'b' ^ 'l';
+
+ return get_pix_fmt_internal(name);
+}
+
+#define FF_COLOR_NA -1
+#define FF_COLOR_RGB 0 /**< RGB color space */
+#define FF_COLOR_GRAY 1 /**< gray color space */
+#define FF_COLOR_YUV 2 /**< YUV color space. 16 <= Y <= 235, 16 <= U, V <= 240 */
+#define FF_COLOR_YUV_JPEG 3 /**< YUV color space. 0 <= Y <= 255, 0 <= U, V <= 255 */
+
+#define pixdesc_has_alpha(pixdesc) \
+ ((pixdesc)->nb_components == 2 || (pixdesc)->nb_components == 4 || (pixdesc)->flags & AV_PIX_FMT_FLAG_PAL)
+
+
+static int get_color_type(const AVPixFmtDescriptor *desc) {
+ if (desc->flags & AV_PIX_FMT_FLAG_PAL)
+ return FF_COLOR_RGB;
+
+ if(desc->nb_components == 1 || desc->nb_components == 2)
+ return FF_COLOR_GRAY;
+
+ if(desc->name && !strncmp(desc->name, "yuvj", 4))
+ return FF_COLOR_YUV_JPEG;
+
+ if(desc->flags & AV_PIX_FMT_FLAG_RGB)
+ return FF_COLOR_RGB;
+
+ if(desc->nb_components == 0)
+ return FF_COLOR_NA;
+
+ return FF_COLOR_YUV;
+}
+
+static int get_pix_fmt_depth(int *min, int *max, enum AVPixelFormat pix_fmt)
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ int i;
+
+ if (!desc || !desc->nb_components) {
+ *min = *max = 0;
+ return AVERROR(EINVAL);
+ }
+
+ *min = INT_MAX, *max = -INT_MAX;
+ for (i = 0; i < desc->nb_components; i++) {
+ *min = FFMIN(desc->comp[i].depth_minus1+1, *min);
+ *max = FFMAX(desc->comp[i].depth_minus1+1, *max);
+ }
+ return 0;
+}
+
+static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt,
+ enum AVPixelFormat src_pix_fmt,
+ unsigned *lossp, unsigned consider)
+{
+ const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
+ const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
+ int src_color, dst_color;
+ int src_min_depth, src_max_depth, dst_min_depth, dst_max_depth;
+ int ret, loss, i, nb_components;
+ int score = INT_MAX - 1;
+
+ if (dst_pix_fmt >= AV_PIX_FMT_NB || dst_pix_fmt <= AV_PIX_FMT_NONE)
+ return ~0;
+
+ /* compute loss */
+ *lossp = loss = 0;
+
+ if (dst_pix_fmt == src_pix_fmt)
+ return INT_MAX;
+
+ if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0)
+ return ret;
+ if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0)
+ return ret;
+
+ src_color = get_color_type(src_desc);
+ dst_color = get_color_type(dst_desc);
+ if (dst_pix_fmt == AV_PIX_FMT_PAL8)
+ nb_components = FFMIN(src_desc->nb_components, 4);
+ else
+ nb_components = FFMIN(src_desc->nb_components, dst_desc->nb_components);
+
+ for (i = 0; i < nb_components; i++) {
+ int depth_minus1 = (dst_pix_fmt == AV_PIX_FMT_PAL8) ? 7/nb_components : dst_desc->comp[i].depth_minus1;
+ if (src_desc->comp[i].depth_minus1 > depth_minus1 && (consider & FF_LOSS_DEPTH)) {
+ loss |= FF_LOSS_DEPTH;
+ score -= 65536 >> depth_minus1;
+ }
+ }
+
+ if (consider & FF_LOSS_RESOLUTION) {
+ if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w) {
+ loss |= FF_LOSS_RESOLUTION;
+ score -= 256 << dst_desc->log2_chroma_w;
+ }
+ if (dst_desc->log2_chroma_h > src_desc->log2_chroma_h) {
+ loss |= FF_LOSS_RESOLUTION;
+ score -= 256 << dst_desc->log2_chroma_h;
+ }
+ // don't favor 422 over 420 if downsampling is needed, because 420 has much better support on the decoder side
+ if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 0 &&
+ dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 0 ) {
+ score += 512;
+ }
+ }
+
+ if(consider & FF_LOSS_COLORSPACE)
+ switch(dst_color) {
+ case FF_COLOR_RGB:
+ if (src_color != FF_COLOR_RGB &&
+ src_color != FF_COLOR_GRAY)
+ loss |= FF_LOSS_COLORSPACE;
+ break;
+ case FF_COLOR_GRAY:
+ if (src_color != FF_COLOR_GRAY)
+ loss |= FF_LOSS_COLORSPACE;
+ break;
+ case FF_COLOR_YUV:
+ if (src_color != FF_COLOR_YUV)
+ loss |= FF_LOSS_COLORSPACE;
+ break;
+ case FF_COLOR_YUV_JPEG:
+ if (src_color != FF_COLOR_YUV_JPEG &&
+ src_color != FF_COLOR_YUV &&
+ src_color != FF_COLOR_GRAY)
+ loss |= FF_LOSS_COLORSPACE;
+ break;
+ default:
+ /* fail safe test */
+ if (src_color != dst_color)
+ loss |= FF_LOSS_COLORSPACE;
+ break;
+ }
+ if(loss & FF_LOSS_COLORSPACE)
+ score -= (nb_components * 65536) >> FFMIN(dst_desc->comp[0].depth_minus1, src_desc->comp[0].depth_minus1);
+
+ if (dst_color == FF_COLOR_GRAY &&
+ src_color != FF_COLOR_GRAY && (consider & FF_LOSS_CHROMA)) {
+ loss |= FF_LOSS_CHROMA;
+ score -= 2 * 65536;
+ }
+ if (!pixdesc_has_alpha(dst_desc) && (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))) {
+ loss |= FF_LOSS_ALPHA;
+ score -= 65536;
}
-#undef PIX_FMT_SWAP_ENDIANNESS
+ if (dst_pix_fmt == AV_PIX_FMT_PAL8 && (consider & FF_LOSS_COLORQUANT) &&
+ (src_pix_fmt != AV_PIX_FMT_PAL8 && (src_color != FF_COLOR_GRAY || (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))))) {
+ loss |= FF_LOSS_COLORQUANT;
+ score -= 65536;
+ }
+
+ *lossp = loss;
+ return score;
+}
+
+int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
+ enum AVPixelFormat src_pix_fmt,
+ int has_alpha)
+{
+ int loss;
+ int ret = get_pix_fmt_score(dst_pix_fmt, src_pix_fmt, &loss, has_alpha ? ~0 : ~FF_LOSS_ALPHA);
+ if (ret < 0)
+ return ret;
+ return loss;
+}
+
+enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
+ enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr)
+{
+ enum AVPixelFormat dst_pix_fmt;
+ int loss1, loss2, loss_mask;
+ const AVPixFmtDescriptor *desc1 = av_pix_fmt_desc_get(dst_pix_fmt1);
+ const AVPixFmtDescriptor *desc2 = av_pix_fmt_desc_get(dst_pix_fmt2);
+ int score1, score2;
+
+ loss_mask= loss_ptr?~*loss_ptr:~0; /* use loss mask if provided */
+ if(!has_alpha)
+ loss_mask &= ~FF_LOSS_ALPHA;
+
+ score1 = get_pix_fmt_score(dst_pix_fmt1, src_pix_fmt, &loss1, loss_mask);
+ score2 = get_pix_fmt_score(dst_pix_fmt2, src_pix_fmt, &loss2, loss_mask);
+
+ if (score1 == score2) {
+ if(av_get_padded_bits_per_pixel(desc2) != av_get_padded_bits_per_pixel(desc1)) {
+ dst_pix_fmt = av_get_padded_bits_per_pixel(desc2) < av_get_padded_bits_per_pixel(desc1) ? dst_pix_fmt2 : dst_pix_fmt1;
+ } else {
+ dst_pix_fmt = desc2->nb_components < desc1->nb_components ? dst_pix_fmt2 : dst_pix_fmt1;
+ }
+ } else {
+ dst_pix_fmt = score1 < score2 ? dst_pix_fmt2 : dst_pix_fmt1;
+ }
+
+ if (loss_ptr)
+ *loss_ptr = av_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha);
+ return dst_pix_fmt;
}
const char *av_color_range_name(enum AVColorRange range)
@@ -1814,3 +2427,31 @@ const char *av_chroma_location_name(enum AVChromaLocation location)
chroma_location_names[location] : NULL;
}
+#ifdef TEST
+
+int main(void){
+ int i;
+ int err=0;
+ int skip = 0;
+
+ for (i=0; i<AV_PIX_FMT_NB*2; i++) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(i);
+ if(!desc || !desc->name) {
+ skip ++;
+ continue;
+ }
+ if (skip) {
+ av_log(NULL, AV_LOG_INFO, "%3d unused pixel format values\n", skip);
+ skip = 0;
+ }
+ av_log(NULL, AV_LOG_INFO, "pix fmt %s avg_bpp:%d colortype:%d\n", desc->name, av_get_padded_bits_per_pixel(desc), get_color_type(desc));
+ if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) != (desc->nb_components != 2 && desc->nb_components != 4)) {
+ av_log(NULL, AV_LOG_ERROR, "Alpha flag mismatch\n");
+ err = 1;
+ }
+ }
+ return err;
+}
+
+#endif
+
diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h
index 23dc009a12..78f8d559c4 100644
--- a/libavutil/pixdesc.h
+++ b/libavutil/pixdesc.h
@@ -2,20 +2,20 @@
* pixel format descriptor
* Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -90,9 +90,12 @@ typedef struct AVPixFmtDescriptor {
uint8_t flags;
/**
- * Parameters that describe how pixels are packed. If the format
- * has chroma components, they must be stored in comp[1] and
- * comp[2].
+ * Parameters that describe how pixels are packed.
+ * If the format has 2 or 4 components, then alpha is last.
+ * If the format has 1 or 2 components, then luma is 0.
+ * If the format has 3 or 4 components:
+ * if the RGB flag is set then 0 is red, 1 is green and 2 is blue;
+ * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V.
*/
AVComponentDescriptor comp[4];
@@ -126,14 +129,29 @@ typedef struct AVPixFmtDescriptor {
* The pixel format contains RGB-like data (as opposed to YUV/grayscale).
*/
#define AV_PIX_FMT_FLAG_RGB (1 << 5)
+
/**
- * The pixel format is "pseudo-paletted". This means that Libav treats it as
- * paletted internally, but the palette is generated by the decoder and is not
- * stored in the file.
+ * The pixel format is "pseudo-paletted". This means that it contains a
+ * fixed palette in the 2nd plane but the palette is fixed/constant for each
+ * PIX_FMT. This allows interpreting the data as if it was PAL8, which can
+ * in some cases be simpler. Or the data can be interpreted purely based on
+ * the pixel format without using the palette.
+ * An example of a pseudo-paletted format is AV_PIX_FMT_GRAY8
*/
#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6)
+
/**
- * The pixel format has an alpha channel.
+ * The pixel format has an alpha channel. This is set on all formats that
+ * support alpha in some way. The exception is AV_PIX_FMT_PAL8, which can
+ * carry alpha as part of the palette. Details are explained in the
+ * AVPixelFormat enum, and are also encoded in the corresponding
+ * AVPixFmtDescriptor.
+ *
+ * The alpha is always straight, never pre-multiplied.
+ *
+ * If a codec or a filter does not support alpha, it should set all alpha to
+ * opaque, or use the equivalent pixel formats without alpha component, e.g.
+ * AV_PIX_FMT_RGB0 (or AV_PIX_FMT_RGB24 etc.) instead of AV_PIX_FMT_RGBA.
*/
#define AV_PIX_FMT_FLAG_ALPHA (1 << 7)
@@ -205,7 +223,7 @@ void av_write_image_line(const uint16_t *src, uint8_t *data[4],
* For example in a little-endian system, first looks for "gray16",
* then for "gray16le".
*
- * Finally if no pixel format has been found, returns PIX_FMT_NONE.
+ * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE.
*/
enum AVPixelFormat av_get_pix_fmt(const char *name);
@@ -219,7 +237,7 @@ const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt);
/**
* Print in buf the string corresponding to the pixel format with
- * number pix_fmt, or an header if pix_fmt is negative.
+ * number pix_fmt, or a header if pix_fmt is negative.
*
* @param buf the buffer where to write the string
* @param buf_size the size of buf
@@ -242,6 +260,12 @@ char *av_get_pix_fmt_string(char *buf, int buf_size,
int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc);
/**
+ * Return the number of bits per pixel for the pixel format
+ * described by pixdesc, including any padding or unused bits.
+ */
+int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc);
+
+/**
* @return a pixel format descriptor for provided pixel format or NULL if
* this pixel format is unknown.
*/
@@ -266,9 +290,14 @@ enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc);
* Utility function to access log2_chroma_w log2_chroma_h from
* the pixel format AVPixFmtDescriptor.
*
+ * See av_get_chroma_sub_sample() for a function that asserts a
+ * valid pixel format instead of returning an error code.
+ * Its recommended that you use avcodec_get_chroma_sub_sample unless
+ * you do check the return code!
+ *
* @param[in] pix_fmt the pixel format
- * @param[out] h_shift store log2_chroma_h
- * @param[out] v_shift store log2_chroma_w
+ * @param[out] h_shift store log2_chroma_w
+ * @param[out] v_shift store log2_chroma_h
*
* @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format
*/
@@ -291,6 +320,56 @@ int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt);
*/
enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt);
+#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */
+#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */
+#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */
+#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */
+#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */
+#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */
+
+/**
+ * Compute what kind of losses will occur when converting from one specific
+ * pixel format to another.
+ * When converting from one pixel format to another, information loss may occur.
+ * For example, when converting from RGB24 to GRAY, the color information will
+ * be lost. Similarly, other losses occur when converting from some formats to
+ * other formats. These losses can involve loss of chroma, but also loss of
+ * resolution, loss of color depth, loss due to the color space conversion, loss
+ * of the alpha bits or loss due to color quantization.
+ * av_get_fix_fmt_loss() informs you about the various types of losses
+ * which will occur when converting from one pixel format to another.
+ *
+ * @param[in] dst_pix_fmt destination pixel format
+ * @param[in] src_pix_fmt source pixel format
+ * @param[in] has_alpha Whether the source pixel format alpha channel is used.
+ * @return Combination of flags informing you what kind of losses will occur
+ * (maximum loss for an invalid dst_pix_fmt).
+ */
+int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt,
+ enum AVPixelFormat src_pix_fmt,
+ int has_alpha);
+
+/**
+ * Compute what kind of losses will occur when converting from one specific
+ * pixel format to another.
+ * When converting from one pixel format to another, information loss may occur.
+ * For example, when converting from RGB24 to GRAY, the color information will
+ * be lost. Similarly, other losses occur when converting from some formats to
+ * other formats. These losses can involve loss of chroma, but also loss of
+ * resolution, loss of color depth, loss due to the color space conversion, loss
+ * of the alpha bits or loss due to color quantization.
+ * av_get_fix_fmt_loss() informs you about the various types of losses
+ * which will occur when converting from one pixel format to another.
+ *
+ * @param[in] dst_pix_fmt destination pixel format
+ * @param[in] src_pix_fmt source pixel format
+ * @param[in] has_alpha Whether the source pixel format alpha channel is used.
+ * @return Combination of flags informing you what kind of losses will occur
+ * (maximum loss for an invalid dst_pix_fmt).
+ */
+enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2,
+ enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr);
+
/**
* @return the name for provided color range or NULL if unknown.
*/
diff --git a/libavutil/pixelutils.c b/libavutil/pixelutils.c
new file mode 100644
index 0000000000..1ec4fbb0ec
--- /dev/null
+++ b/libavutil/pixelutils.c
@@ -0,0 +1,222 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "common.h"
+#include "pixelutils.h"
+#include "internal.h"
+
+#if CONFIG_PIXELUTILS
+
+#include "x86/pixelutils.h"
+
+static av_always_inline int sad_wxh(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2,
+ int w, int h)
+{
+ int x, y, sum = 0;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++)
+ sum += abs(src1[x] - src2[x]);
+ src1 += stride1;
+ src2 += stride2;
+ }
+ return sum;
+}
+
+#define DECLARE_BLOCK_FUNCTIONS(size) \
+static int block_sad_##size##x##size##_c(const uint8_t *src1, ptrdiff_t stride1, \
+ const uint8_t *src2, ptrdiff_t stride2) \
+{ \
+ return sad_wxh(src1, stride1, src2, stride2, size, size); \
+}
+
+DECLARE_BLOCK_FUNCTIONS(2)
+DECLARE_BLOCK_FUNCTIONS(4)
+DECLARE_BLOCK_FUNCTIONS(8)
+DECLARE_BLOCK_FUNCTIONS(16)
+
+static const av_pixelutils_sad_fn sad_c[] = {
+ block_sad_2x2_c,
+ block_sad_4x4_c,
+ block_sad_8x8_c,
+ block_sad_16x16_c,
+};
+
+#endif /* CONFIG_PIXELUTILS */
+
+av_pixelutils_sad_fn av_pixelutils_get_sad_fn(int w_bits, int h_bits, int aligned, void *log_ctx)
+{
+#if !CONFIG_PIXELUTILS
+ av_log(log_ctx, AV_LOG_ERROR, "pixelutils support is required "
+ "but libavutil is not compiled with it\n");
+ return NULL;
+#else
+ av_pixelutils_sad_fn sad[FF_ARRAY_ELEMS(sad_c)];
+
+ memcpy(sad, sad_c, sizeof(sad));
+
+ if (w_bits < 1 || w_bits > FF_ARRAY_ELEMS(sad) ||
+ h_bits < 1 || h_bits > FF_ARRAY_ELEMS(sad))
+ return NULL;
+ if (w_bits != h_bits) // only squared sad for now
+ return NULL;
+
+#if ARCH_X86
+ ff_pixelutils_sad_init_x86(sad, aligned);
+#endif
+
+ return sad[w_bits - 1];
+#endif
+}
+
+#ifdef TEST
+#define W1 320
+#define H1 240
+#define W2 640
+#define H2 480
+
+static int run_single_test(const char *test,
+ const uint8_t *block1, ptrdiff_t stride1,
+ const uint8_t *block2, ptrdiff_t stride2,
+ int align, int n)
+{
+ int out, ref;
+ av_pixelutils_sad_fn f_ref = sad_c[n - 1];
+ av_pixelutils_sad_fn f_out = av_pixelutils_get_sad_fn(n, n, align, NULL);
+
+ switch (align) {
+ case 0: block1++; block2++; break;
+ case 1: block2++; break;
+ case 2: break;
+ }
+
+ out = f_out(block1, stride1, block2, stride2);
+ ref = f_ref(block1, stride1, block2, stride2);
+ printf("[%s] [%c%c] SAD [%s] %dx%d=%d ref=%d\n",
+ out == ref ? "OK" : "FAIL",
+ align ? 'A' : 'U', align == 2 ? 'A' : 'U',
+ test, 1<<n, 1<<n, out, ref);
+ return out != ref;
+}
+
+static int run_test(const char *test,
+ const uint8_t *b1, const uint8_t *b2)
+{
+ int i, a, ret = 0;
+
+ for (a = 0; a < 3; a++) {
+ const uint8_t *block1 = b1;
+ const uint8_t *block2 = b2;
+
+ switch (a) {
+ case 0: block1++; block2++; break;
+ case 1: block2++; break;
+ case 2: break;
+ }
+ for (i = 1; i <= FF_ARRAY_ELEMS(sad_c); i++) {
+ int r = run_single_test(test, b1, W1, b2, W2, a, i);
+ if (r)
+ ret = r;
+ }
+ }
+ return ret;
+}
+
+int main(void)
+{
+ int i, align, ret;
+ uint8_t *buf1 = av_malloc(W1*H1);
+ uint8_t *buf2 = av_malloc(W2*H2);
+ uint32_t state = 0;
+
+ if (!buf1 || !buf2) {
+ fprintf(stderr, "malloc failure\n");
+ ret = 1;
+ goto end;
+ }
+
+ ff_check_pixfmt_descriptors();
+
+#define RANDOM_INIT(buf, size) do { \
+ int k; \
+ for (k = 0; k < size; k++) { \
+ state = state * 1664525 + 1013904223; \
+ buf[k] = state>>24; \
+ } \
+} while (0)
+
+ /* Normal test with different strides */
+ RANDOM_INIT(buf1, W1*H1);
+ RANDOM_INIT(buf2, W2*H2);
+ ret = run_test("random", buf1, buf2);
+ if (ret < 0)
+ goto end;
+
+ /* Check for maximum SAD */
+ memset(buf1, 0xff, W1*H1);
+ memset(buf2, 0x00, W2*H2);
+ ret = run_test("max", buf1, buf2);
+ if (ret < 0)
+ goto end;
+
+ /* Check for minimum SAD */
+ memset(buf1, 0x90, W1*H1);
+ memset(buf2, 0x90, W2*H2);
+ ret = run_test("min", buf1, buf2);
+ if (ret < 0)
+ goto end;
+
+ /* Exact buffer sizes, to check for overreads */
+ for (i = 1; i <= 4; i++) {
+ for (align = 0; align < 3; align++) {
+ int size1, size2;
+
+ av_freep(&buf1);
+ av_freep(&buf2);
+
+ size1 = size2 = 1 << (i << 1);
+
+ switch (align) {
+ case 0: size1++; size2++; break;
+ case 1: size2++; break;
+ case 2: break;
+ }
+
+ buf1 = av_malloc(size1);
+ buf2 = av_malloc(size2);
+ if (!buf1 || !buf2) {
+ fprintf(stderr, "malloc failure\n");
+ ret = 1;
+ goto end;
+ }
+ RANDOM_INIT(buf1, size1);
+ RANDOM_INIT(buf2, size2);
+ ret = run_single_test("small", buf1, 1<<i, buf2, 1<<i, align, i);
+ if (ret < 0)
+ goto end;
+ }
+ }
+
+end:
+ av_free(buf1);
+ av_free(buf2);
+ return ret;
+}
+#endif /* TEST */
diff --git a/libavutil/pixelutils.h b/libavutil/pixelutils.h
new file mode 100644
index 0000000000..a8dbc157e1
--- /dev/null
+++ b/libavutil/pixelutils.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_PIXELUTILS_H
+#define AVUTIL_PIXELUTILS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include "common.h"
+
+/**
+ * Sum of abs(src1[x] - src2[x])
+ */
+typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+
+/**
+ * Get a potentially optimized pointer to a Sum-of-absolute-differences
+ * function (see the av_pixelutils_sad_fn prototype).
+ *
+ * @param w_bits 1<<w_bits is the requested width of the block size
+ * @param h_bits 1<<h_bits is the requested height of the block size
+ * @param aligned If set to 2, the returned sad function will assume src1 and
+ * src2 addresses are aligned on the block size.
+ * If set to 1, the returned sad function will assume src1 is
+ * aligned on the block size.
+ * If set to 0, the returned sad function assume no particular
+ * alignment.
+ * @param log_ctx context used for logging, can be NULL
+ *
+ * @return a pointer to the SAD function or NULL in case of error (because of
+ * invalid parameters)
+ */
+av_pixelutils_sad_fn av_pixelutils_get_sad_fn(int w_bits, int h_bits,
+ int aligned, void *log_ctx);
+
+#endif /* AVUTIL_PIXELUTILS_H */
diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
index 360015ca1f..3ddd30f0d8 100644
--- a/libavutil/pixfmt.h
+++ b/libavutil/pixfmt.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,9 @@
#include "libavutil/avconfig.h"
#include "version.h"
+#define AVPALETTE_SIZE 1024
+#define AVPALETTE_COUNT 256
+
/**
* Pixel format.
*
@@ -41,11 +44,11 @@
* big-endian CPUs.
*
* @par
- * When the pixel format is palettized RGB (AV_PIX_FMT_PAL8), the palettized
+ * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized
* image data is stored in AVFrame.data[0]. The palette is transported in
* AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is
* formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is
- * also endian-specific). Note also that the individual RGB palette
+ * also endian-specific). Note also that the individual RGB32 palette
* components stored in AVFrame.data[1] should be in the range 0..255.
* This is important as many custom PAL8 video codecs that were designed
* to run on the IBM VGA graphics adapter use 6-bit palette components.
@@ -56,8 +59,8 @@
* allocating the picture.
*
* @note
- * Make sure that all newly added big-endian formats have pix_fmt & 1 == 1
- * and that all newly added little-endian formats have pix_fmt & 1 == 0.
+ * Make sure that all newly added big-endian formats have (pix_fmt & 1) == 1
+ * and that all newly added little-endian formats have (pix_fmt & 1) == 0.
* This allows simpler detection of big vs little-endian.
*/
enum AVPixelFormat {
@@ -80,6 +83,7 @@ enum AVPixelFormat {
#if FF_API_XVMC
AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing
AV_PIX_FMT_XVMC_MPEG2_IDCT,
+#define AV_PIX_FMT_XVMC AV_PIX_FMT_XVMC_MPEG2_IDCT
#endif /* FF_API_XVMC */
AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3
@@ -114,13 +118,13 @@ enum AVPixelFormat {
AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
- AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), big-endian, most significant bit to 0
- AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), little-endian, most significant bit to 0
+ AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined
+ AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined
AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian
AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian
- AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), big-endian, most significant bit to 1
- AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), little-endian, most significant bit to 1
+ AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined
+ AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined
AV_PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers
AV_PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers
@@ -137,16 +141,23 @@ enum AVPixelFormat {
#endif
AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer
- AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), little-endian, most significant bits to 0
- AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4A 4R 4G 4B(lsb), big-endian, most significant bits to 0
- AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), little-endian, most significant bits to 1
- AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4A 4B 4G 4R(lsb), big-endian, most significant bits to 1
+ AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined
+ AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), big-endian, X=unused/undefined
+ AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), little-endian, X=unused/undefined
+ AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), big-endian, X=unused/undefined
AV_PIX_FMT_YA8, ///< 8bit gray, 8bit alpha
AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8
+ AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8
AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian
AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian
+
+ /**
+ * The following 12 formats have the disadvantage of needing 1 format for each bit depth.
+ * Notice that each 9/10 bits sample is stored in 16 bits with extra padding.
+ * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better.
+ */
AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
@@ -160,6 +171,13 @@ enum AVPixelFormat {
AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
AV_PIX_FMT_VDA_VLD, ///< hardware decoding through VDA
+
+#ifdef AV_PIX_FMT_ABI_GIT_MASTER
+ AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+#endif
AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp
AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian
AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian
@@ -167,8 +185,15 @@ enum AVPixelFormat {
AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian
AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian
AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian
- AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
- AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
+
+ /**
+ * duplicated pixel formats for compatibility with libav.
+ * FFmpeg supports these formats since May 8 2012 and Jan 28 2012 (commits f9ca1ac7 and 143a5c55)
+ * Libav added them Oct 12 2012 with incompatible values (commit 6d5600e85)
+ */
+ AV_PIX_FMT_YUVA422P_LIBAV, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
+ AV_PIX_FMT_YUVA444P_LIBAV, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
+
AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian
AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian
AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian
@@ -187,17 +212,25 @@ enum AVPixelFormat {
AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian)
AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian)
AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian)
+
AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface
+
AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0
AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0
AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
- AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
- AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
- AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
- AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ /**
+ * duplicated pixel formats for compatibility with libav.
+ * FFmpeg supports these formats since Sat Sep 24 06:01:45 2011 +0200 (commits 9569a3c9f41387a8c7d1ce97d8693520477a66c3)
+ * also see Fri Nov 25 01:38:21 2011 +0100 92afb431621c79155fcb7171d26f137eb1bee028
+ * Libav added them Sun Mar 16 23:05:47 2014 +0100 with incompatible values (commit 1481d24c3a0abf81e1d7a514547bd5305232be30)
+ */
+ AV_PIX_FMT_RGBA64BE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_RGBA64LE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ AV_PIX_FMT_BGRA64BE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_BGRA64LE_LIBAV, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb
@@ -206,9 +239,14 @@ enum AVPixelFormat {
AV_PIX_FMT_YA16BE, ///< 16bit gray, 16bit alpha (big-endian)
AV_PIX_FMT_YA16LE, ///< 16bit gray, 16bit alpha (little-endian)
- AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp
- AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian
- AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian
+ /**
+ * duplicated pixel formats for compatibility with libav.
+ * FFmpeg supports these formats since May 3 2013 (commit e6d4e687558d08187e7a415a7725e4b1a416f782)
+ * Libav added them Jan 14 2015 with incompatible values (commit 0e6c7dfa650e8b0497bfa7a06394b7a462ddc33a)
+ */
+ AV_PIX_FMT_GBRAP_LIBAV, ///< planar GBRA 4:4:4:4 32bpp
+ AV_PIX_FMT_GBRAP16BE_LIBAV, ///< planar GBRA 4:4:4:4 64bpp, big-endian
+ AV_PIX_FMT_GBRAP16LE_LIBAV, ///< planar GBRA 4:4:4:4 64bpp, little-endian
/**
* HW acceleration through QSV, data[3] contains a pointer to the
* mfxFrameSurface1 structure.
@@ -222,6 +260,60 @@ enum AVPixelFormat {
AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer
+#ifndef AV_PIX_FMT_ABI_GIT_MASTER
+ AV_PIX_FMT_RGBA64BE=0x123, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+ AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian
+ AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian
+#endif
+ AV_PIX_FMT_0RGB=0x123+4,///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
+ AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
+ AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
+ AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
+ AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
+ AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
+
+ AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian
+ AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
+ AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian
+ AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
+ AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian
+ AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
+ AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian
+ AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian
+ AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian
+ AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian
+ AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp
+ AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian
+ AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian
+ AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV411P and setting color_range
+
+ AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */
+ AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */
+ AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */
+ AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */
+ AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */
+ AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */
+#if !FF_API_XVMC
+ AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing
+#endif /* !FF_API_XVMC */
+ AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian
+ AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian
+ AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian
+ AV_PIX_FMT_YUV440P12BE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian
+
AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions
#if FF_API_PIX_FMT
@@ -229,6 +321,22 @@ enum AVPixelFormat {
#endif
};
+#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI
+#define AV_PIX_FMT_YUVA422P AV_PIX_FMT_YUVA422P_LIBAV
+#define AV_PIX_FMT_YUVA444P AV_PIX_FMT_YUVA444P_LIBAV
+#define AV_PIX_FMT_RGBA64BE AV_PIX_FMT_RGBA64BE_LIBAV
+#define AV_PIX_FMT_RGBA64LE AV_PIX_FMT_RGBA64LE_LIBAV
+#define AV_PIX_FMT_BGRA64BE AV_PIX_FMT_BGRA64BE_LIBAV
+#define AV_PIX_FMT_BGRA64LE AV_PIX_FMT_BGRA64LE_LIBAV
+#define AV_PIX_FMT_GBRAP AV_PIX_FMT_GBRAP_LIBAV
+#define AV_PIX_FMT_GBRAP16BE AV_PIX_FMT_GBRAP16BE_LIBAV
+#define AV_PIX_FMT_GBRAP16LE AV_PIX_FMT_GBRAP16LE_LIBAV
+#endif
+
+
+#define AV_PIX_FMT_Y400A AV_PIX_FMT_GRAY8A
+#define AV_PIX_FMT_GBR24P AV_PIX_FMT_GBRP
+
#if AV_HAVE_BIGENDIAN
# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be
#else
@@ -239,6 +347,8 @@ enum AVPixelFormat {
#define AV_PIX_FMT_RGB32_1 AV_PIX_FMT_NE(RGBA, ABGR)
#define AV_PIX_FMT_BGR32 AV_PIX_FMT_NE(ABGR, RGBA)
#define AV_PIX_FMT_BGR32_1 AV_PIX_FMT_NE(BGRA, ARGB)
+#define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0)
+#define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0)
#define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE)
#define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE)
@@ -258,17 +368,32 @@ enum AVPixelFormat {
#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE)
#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE)
#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE)
+#define AV_PIX_FMT_YUV440P10 AV_PIX_FMT_NE(YUV440P10BE, YUV440P10LE)
#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE)
+#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE)
+#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE)
+#define AV_PIX_FMT_YUV440P12 AV_PIX_FMT_NE(YUV440P12BE, YUV440P12LE)
+#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE)
+#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE)
+#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE)
+#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE)
#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE)
#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE)
#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE)
#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE)
#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE)
+#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE)
+#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE)
#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE)
-
#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE)
+#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE)
+#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE)
+#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE)
+#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE)
+
+
#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE)
#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE)
#define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE)
@@ -286,12 +411,17 @@ enum AVPixelFormat {
#if FF_API_PIX_FMT
#define PixelFormat AVPixelFormat
+#define PIX_FMT_Y400A AV_PIX_FMT_Y400A
+#define PIX_FMT_GBR24P AV_PIX_FMT_GBR24P
+
#define PIX_FMT_NE(be, le) AV_PIX_FMT_NE(be, le)
#define PIX_FMT_RGB32 AV_PIX_FMT_RGB32
#define PIX_FMT_RGB32_1 AV_PIX_FMT_RGB32_1
#define PIX_FMT_BGR32 AV_PIX_FMT_BGR32
#define PIX_FMT_BGR32_1 AV_PIX_FMT_BGR32_1
+#define PIX_FMT_0RGB32 AV_PIX_FMT_0RGB32
+#define PIX_FMT_0BGR32 AV_PIX_FMT_0BGR32
#define PIX_FMT_GRAY16 AV_PIX_FMT_GRAY16
#define PIX_FMT_RGB48 AV_PIX_FMT_RGB48
@@ -309,12 +439,22 @@ enum AVPixelFormat {
#define PIX_FMT_YUV420P10 AV_PIX_FMT_YUV420P10
#define PIX_FMT_YUV422P10 AV_PIX_FMT_YUV422P10
#define PIX_FMT_YUV444P10 AV_PIX_FMT_YUV444P10
+#define PIX_FMT_YUV420P12 AV_PIX_FMT_YUV420P12
+#define PIX_FMT_YUV422P12 AV_PIX_FMT_YUV422P12
+#define PIX_FMT_YUV444P12 AV_PIX_FMT_YUV444P12
+#define PIX_FMT_YUV420P14 AV_PIX_FMT_YUV420P14
+#define PIX_FMT_YUV422P14 AV_PIX_FMT_YUV422P14
+#define PIX_FMT_YUV444P14 AV_PIX_FMT_YUV444P14
#define PIX_FMT_YUV420P16 AV_PIX_FMT_YUV420P16
#define PIX_FMT_YUV422P16 AV_PIX_FMT_YUV422P16
#define PIX_FMT_YUV444P16 AV_PIX_FMT_YUV444P16
+#define PIX_FMT_RGBA64 AV_PIX_FMT_RGBA64
+#define PIX_FMT_BGRA64 AV_PIX_FMT_BGRA64
#define PIX_FMT_GBRP9 AV_PIX_FMT_GBRP9
#define PIX_FMT_GBRP10 AV_PIX_FMT_GBRP10
+#define PIX_FMT_GBRP12 AV_PIX_FMT_GBRP12
+#define PIX_FMT_GBRP14 AV_PIX_FMT_GBRP14
#define PIX_FMT_GBRP16 AV_PIX_FMT_GBRP16
#endif
@@ -376,6 +516,8 @@ enum AVColorSpace {
AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system
AVCOL_SPC_NB, ///< Not part of ABI
};
+#define AVCOL_SPC_YCGCO AVCOL_SPC_YCOCG
+
/**
* MPEG vs JPEG YUV range.
@@ -390,15 +532,23 @@ enum AVColorRange {
/**
* Location of chroma samples.
*
- * X X 3 4 X X are luma samples,
- * 1 2 1-6 are possible chroma positions
- * X X 5 6 X 0 is undefined/unknown position
+ * Illustration showing the location of the first (top left) chroma sample of the
+ * image, the left shows only luma, the right
+ * shows the location of the chroma sample, the 2 could be imagined to overlay
+ * each other but are drawn seperately due to limitations of ASCII
+ *
+ * 1st 2nd 1st 2nd horizontal luma sample positions
+ * v v v v
+ * ______ ______
+ *1st luma line > |X X ... |3 4 X ... X are luma samples,
+ * | |1 2 1-6 are possible chroma positions
+ *2nd luma line > |X X ... |5 6 X ... 0 is undefined/unknown position
*/
enum AVChromaLocation {
AVCHROMA_LOC_UNSPECIFIED = 0,
- AVCHROMA_LOC_LEFT = 1, ///< mpeg2/4, h264 default
- AVCHROMA_LOC_CENTER = 2, ///< mpeg1, jpeg, h263
- AVCHROMA_LOC_TOPLEFT = 3, ///< DV
+ AVCHROMA_LOC_LEFT = 1, ///< mpeg2/4 4:2:0, h264 default for 4:2:0
+ AVCHROMA_LOC_CENTER = 2, ///< mpeg1 4:2:0, jpeg 4:2:0, h263 4:2:0
+ AVCHROMA_LOC_TOPLEFT = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2
AVCHROMA_LOC_TOP = 4,
AVCHROMA_LOC_BOTTOMLEFT = 5,
AVCHROMA_LOC_BOTTOM = 6,
diff --git a/libavutil/ppc/cpu.c b/libavutil/ppc/cpu.c
index 50107e1fca..d51e3fa659 100644
--- a/libavutil/ppc/cpu.c
+++ b/libavutil/ppc/cpu.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -62,7 +62,7 @@ int ff_get_cpu_flags_ppc(void)
if (err == 0)
return has_vu ? AV_CPU_FLAG_ALTIVEC : 0;
return 0;
-#elif CONFIG_RUNTIME_CPUDETECT
+#elif CONFIG_RUNTIME_CPUDETECT && defined(__linux__) && !ARCH_PPC64
int proc_ver;
// Support of mfspr PVR emulation added in Linux 2.6.17.
__asm__ volatile("mfspr %0, 287" : "=r" (proc_ver));
diff --git a/libavutil/ppc/cpu.h b/libavutil/ppc/cpu.h
index f8fae58698..0a212f33cb 100644
--- a/libavutil/ppc/cpu.h
+++ b/libavutil/ppc/cpu.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/ppc/float_dsp_altivec.c b/libavutil/ppc/float_dsp_altivec.c
index fee4e7c7db..49af9f9abf 100644
--- a/libavutil/ppc/float_dsp_altivec.c
+++ b/libavutil/ppc/float_dsp_altivec.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -75,20 +75,18 @@ void ff_vector_fmul_add_altivec(float *dst, const float *src0,
int len)
{
int i;
- vector float d, s0, s1, s2, t0, t1, edges;
- vector unsigned char align = vec_lvsr(0,dst),
- mask = vec_lvsl(0, dst);
+ vector float d, ss0, ss1, ss2, t0, t1, edges;
for (i = 0; i < len - 3; i += 4) {
t0 = vec_ld(0, dst + i);
t1 = vec_ld(15, dst + i);
- s0 = vec_ld(0, src0 + i);
- s1 = vec_ld(0, src1 + i);
- s2 = vec_ld(0, src2 + i);
- edges = vec_perm(t1, t0, mask);
- d = vec_madd(s0, s1, s2);
- t1 = vec_perm(d, edges, align);
- t0 = vec_perm(edges, d, align);
+ ss0 = vec_ld(0, src0 + i);
+ ss1 = vec_ld(0, src1 + i);
+ ss2 = vec_ld(0, src2 + i);
+ edges = vec_perm(t1, t0, vcprm(0, 1, 2, 3));
+ d = vec_madd(ss0, ss1, ss2);
+ t1 = vec_perm(d, edges, vcprm(s0,s1,s2,s3));
+ t0 = vec_perm(edges, d, vcprm(s0,s1,s2,s3));
vec_st(t1, 15, dst + i);
vec_st(t0, 0, dst + i);
}
diff --git a/libavutil/ppc/float_dsp_altivec.h b/libavutil/ppc/float_dsp_altivec.h
index 87d50a8878..e1d530afa5 100644
--- a/libavutil/ppc/float_dsp_altivec.h
+++ b/libavutil/ppc/float_dsp_altivec.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/ppc/float_dsp_init.c b/libavutil/ppc/float_dsp_init.c
index 60d0f19aca..9dd2072b7a 100644
--- a/libavutil/ppc/float_dsp_init.c
+++ b/libavutil/ppc/float_dsp_init.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/ppc/intreadwrite.h b/libavutil/ppc/intreadwrite.h
index 4471c6a31e..7671676ce9 100644
--- a/libavutil/ppc/intreadwrite.h
+++ b/libavutil/ppc/intreadwrite.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,20 +24,6 @@
#include <stdint.h>
#include "config.h"
-/*
- * -O0 would compile the packed struct version, which is used by
- * default, in an overly verbose fashion, so we override it here.
- */
-#if HAVE_BIGENDIAN
-#define AV_RB64(p) (*(const uint64_t *)(p))
-#define AV_WB64(p, v) (*(uint64_t *)(p) = (v))
-
-#else
-#define AV_RL64(p) (*(const uint64_t *)(p))
-#define AV_WL64(p, v) (*(uint64_t *)(p) = (v))
-
-#endif
-
#if HAVE_XFORM_ASM
#if HAVE_BIGENDIAN
diff --git a/libavutil/ppc/timer.h b/libavutil/ppc/timer.h
index 8d08d2835b..b28e624566 100644
--- a/libavutil/ppc/timer.h
+++ b/libavutil/ppc/timer.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2005 Luca Barbato <lu_zero@gentoo.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,8 +25,6 @@
#include "config.h"
-#if HAVE_INLINE_ASM_LABELS
-
#define AV_READ_TIME read_time
static inline uint64_t read_time(void)
@@ -35,12 +33,11 @@ static inline uint64_t read_time(void)
/* from section 2.2.1 of the 32-bit PowerPC PEM */
__asm__ volatile(
- "1:\n"
"mftbu %2\n"
"mftb %0\n"
"mftbu %1\n"
"cmpw %2,%1\n"
- "bne 1b\n"
+ "bne $-0x10\n"
: "=r"(tbl), "=r"(tbu), "=r"(temp)
:
: "cc");
@@ -48,6 +45,4 @@ static inline uint64_t read_time(void)
return (((uint64_t)tbu)<<32) | (uint64_t)tbl;
}
-#endif /* HAVE_INLINE_ASM_LABELS */
-
#endif /* AVUTIL_PPC_TIMER_H */
diff --git a/libavutil/ppc/types_altivec.h b/libavutil/ppc/types_altivec.h
index 0a4eaf885f..69d8957509 100644
--- a/libavutil/ppc/types_altivec.h
+++ b/libavutil/ppc/types_altivec.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2006 Guillaume Poirier <gpoirier@mplayerhq.hu>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/ppc/util_altivec.h b/libavutil/ppc/util_altivec.h
index 5624ac5523..51a4e8ca58 100644
--- a/libavutil/ppc/util_altivec.h
+++ b/libavutil/ppc/util_altivec.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,9 +46,21 @@
#define WORD_s1 0x14,0x15,0x16,0x17
#define WORD_s2 0x18,0x19,0x1a,0x1b
#define WORD_s3 0x1c,0x1d,0x1e,0x1f
-
#define vcprm(a,b,c,d) (const vector unsigned char){WORD_ ## a, WORD_ ## b, WORD_ ## c, WORD_ ## d}
+#define SWP_W2S0 0x02,0x03,0x00,0x01
+#define SWP_W2S1 0x06,0x07,0x04,0x05
+#define SWP_W2S2 0x0a,0x0b,0x08,0x09
+#define SWP_W2S3 0x0e,0x0f,0x0c,0x0d
+#define SWP_W2Ss0 0x12,0x13,0x10,0x11
+#define SWP_W2Ss1 0x16,0x17,0x14,0x15
+#define SWP_W2Ss2 0x1a,0x1b,0x18,0x19
+#define SWP_W2Ss3 0x1e,0x1f,0x1c,0x1d
+#define vcswapi2s(a,b,c,d) (const vector unsigned char){SWP_W2S ## a, SWP_W2S ## b, SWP_W2S ## c, SWP_W2S ## d}
+
+#define vcswapc() \
+ (const vector unsigned char){0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00}
+
// Transpose 8x8 matrix of 16-bit elements (in-place)
#define TRANSPOSE8(a,b,c,d,e,f,g,h) \
@@ -85,29 +97,68 @@ do { \
} while (0)
+#if HAVE_BIGENDIAN
+#define VEC_LD(offset,b) \
+ vec_perm(vec_ld(offset, b), vec_ld((offset)+15, b), vec_lvsl(offset, b))
+#else
+#define VEC_LD(offset,b) \
+ vec_vsx_ld(offset, b)
+#endif
+
/** @brief loads unaligned vector @a *src with offset @a offset
and returns it */
-static inline vector unsigned char unaligned_load(int offset, uint8_t *src)
+#if HAVE_BIGENDIAN
+static inline vector unsigned char unaligned_load(int offset, const uint8_t *src)
{
register vector unsigned char first = vec_ld(offset, src);
register vector unsigned char second = vec_ld(offset+15, src);
register vector unsigned char mask = vec_lvsl(offset, src);
return vec_perm(first, second, mask);
}
-
-/**
- * loads vector known misalignment
- * @param perm_vec the align permute vector to combine the two loads from lvsl
- */
-static inline vec_u8 load_with_perm_vec(int offset, uint8_t *src, vec_u8 perm_vec)
+static inline vec_u8 load_with_perm_vec(int offset, const uint8_t *src, vec_u8 perm_vec)
{
vec_u8 a = vec_ld(offset, src);
vec_u8 b = vec_ld(offset+15, src);
return vec_perm(a, b, perm_vec);
}
+#else
+#define unaligned_load(a,b) VEC_LD(a,b)
+#define load_with_perm_vec(a,b,c) VEC_LD(a,b)
+#endif
+
-#define vec_unaligned_load(b) \
- vec_perm(vec_ld(0, b), vec_ld(15, b), vec_lvsl(0, b));
+/**
+ * loads vector known misalignment
+ * @param perm_vec the align permute vector to combine the two loads from lvsl
+ */
+
+#define vec_unaligned_load(b) VEC_LD(0, b)
+
+#if HAVE_BIGENDIAN
+#define VEC_MERGEH(a, b) vec_mergeh(a, b)
+#define VEC_MERGEL(a, b) vec_mergel(a, b)
+#else
+#define VEC_MERGEH(a, b) vec_mergeh(b, a)
+#define VEC_MERGEL(a, b) vec_mergel(b, a)
+#endif
+
+#if HAVE_BIGENDIAN
+#define VEC_ST(a,b,c) vec_st(a,b,c)
+#else
+#define VEC_ST(a,b,c) vec_vsx_st(a,b,c)
+#endif
+
+#if HAVE_BIGENDIAN
+#define VEC_SPLAT16(a,b) vec_splat((vec_s16)(a), b)
+#else
+#define VEC_SPLAT16(a,b) vec_splat((vec_s16)(vec_perm(a, a, vcswapi2s(0,1,2,3))), b)
+#endif
+
+#if HAVE_BIGENDIAN
+#define VEC_SLD16(a,b,c) vec_sld(a, b, c)
+#else
+#define VEC_SLD16(a,b,c) vec_sld(b, a, c)
+#endif
#endif /* HAVE_ALTIVEC */
diff --git a/libavutil/qsort.h b/libavutil/qsort.h
new file mode 100644
index 0000000000..30edcc8371
--- /dev/null
+++ b/libavutil/qsort.h
@@ -0,0 +1,117 @@
+/*
+ * copyright (c) 2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "common.h"
+
+
+/**
+ * Quicksort
+ * This sort is fast, and fully inplace but not stable and it is possible
+ * to construct input that requires O(n^2) time but this is very unlikely to
+ * happen with non constructed input.
+ */
+#define AV_QSORT(p, num, type, cmp) {\
+ void *stack[64][2];\
+ int sp= 1;\
+ stack[0][0] = p;\
+ stack[0][1] = (p)+(num)-1;\
+ while(sp){\
+ type *start= stack[--sp][0];\
+ type *end = stack[ sp][1];\
+ while(start < end){\
+ if(start < end-1) {\
+ int checksort=0;\
+ type *right = end-2;\
+ type *left = start+1;\
+ type *mid = start + ((end-start)>>1);\
+ if(cmp(start, end) > 0) {\
+ if(cmp( end, mid) > 0) FFSWAP(type, *start, *mid);\
+ else FFSWAP(type, *start, *end);\
+ }else{\
+ if(cmp(start, mid) > 0) FFSWAP(type, *start, *mid);\
+ else checksort= 1;\
+ }\
+ if(cmp(mid, end) > 0){ \
+ FFSWAP(type, *mid, *end);\
+ checksort=0;\
+ }\
+ if(start == end-2) break;\
+ FFSWAP(type, end[-1], *mid);\
+ while(left <= right){\
+ while(left<=right && cmp(left, end-1) < 0)\
+ left++;\
+ while(left<=right && cmp(right, end-1) > 0)\
+ right--;\
+ if(left <= right){\
+ FFSWAP(type, *left, *right);\
+ left++;\
+ right--;\
+ }\
+ }\
+ FFSWAP(type, end[-1], *left);\
+ if(checksort && (mid == left-1 || mid == left)){\
+ mid= start;\
+ while(mid<end && cmp(mid, mid+1) <= 0)\
+ mid++;\
+ if(mid==end)\
+ break;\
+ }\
+ if(end-left < left-start){\
+ stack[sp ][0]= start;\
+ stack[sp++][1]= right;\
+ start = left+1;\
+ }else{\
+ stack[sp ][0]= left+1;\
+ stack[sp++][1]= end;\
+ end = right;\
+ }\
+ }else{\
+ if(cmp(start, end) > 0)\
+ FFSWAP(type, *start, *end);\
+ break;\
+ }\
+ }\
+ }\
+}
+
+/**
+ * Merge sort, this sort requires a temporary buffer and is stable, its worst
+ * case time is O(n log n)
+ * @param p must be a lvalue pointer, this function may exchange it with tmp
+ * @param tmp must be a lvalue pointer, this function may exchange it with p
+ */
+#define AV_MSORT(p, tmp, num, type, cmp) {\
+ unsigned i, j, step;\
+ for(step=1; step<(num); step+=step){\
+ for(i=0; i<(num); i+=2*step){\
+ unsigned a[2] = {i, i+step};\
+ unsigned end = FFMIN(i+2*step, (num));\
+ for(j=i; a[0]<i+step && a[1]<end; j++){\
+ int idx= cmp(p+a[0], p+a[1]) > 0;\
+ tmp[j] = p[ a[idx]++ ];\
+ }\
+ if(a[0]>=i+step) a[0] = a[1];\
+ for(; j<end; j++){\
+ tmp[j] = p[ a[0]++ ];\
+ }\
+ }\
+ FFSWAP(type*, p, tmp);\
+ }\
+}
diff --git a/libavutil/random_seed.c b/libavutil/random_seed.c
index 26884cbcd6..8aa8c3879b 100644
--- a/libavutil/random_seed.c
+++ b/libavutil/random_seed.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,9 @@
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
+#if HAVE_IO_H
+#include <io.h>
+#endif
#if HAVE_CRYPTGENRANDOM
#include <windows.h>
#include <wincrypt.h>
@@ -30,13 +33,18 @@
#include <fcntl.h>
#include <math.h>
#include <time.h>
+#include <string.h>
+#include "avassert.h"
#include "internal.h"
#include "intreadwrite.h"
-#include "mem.h"
#include "timer.h"
#include "random_seed.h"
#include "sha.h"
+#ifndef TEST
+#define TEST 0
+#endif
+
static int read_random(uint32_t *dst, const char *file)
{
#if HAVE_UNISTD_H
@@ -56,13 +64,26 @@ static int read_random(uint32_t *dst, const char *file)
static uint32_t get_generic_seed(void)
{
- struct AVSHA *sha = av_sha_alloc();
+ uint8_t tmp[120];
+ struct AVSHA *sha = (void*)tmp;
clock_t last_t = 0;
static uint64_t i = 0;
static uint32_t buffer[512] = { 0 };
unsigned char digest[20];
uint64_t last_i = i;
+ av_assert0(sizeof(tmp) >= av_sha_size);
+
+ if(TEST){
+ memset(buffer, 0, sizeof(buffer));
+ last_i = i = 0;
+ }else{
+#ifdef AV_READ_TIME
+ buffer[13] ^= AV_READ_TIME();
+ buffer[41] ^= AV_READ_TIME()>>32;
+#endif
+ }
+
for (;;) {
clock_t t = clock();
@@ -70,25 +91,18 @@ static uint32_t get_generic_seed(void)
buffer[i & 511]++;
} else {
buffer[++i & 511] += (t - last_t) % 3294638521U;
- if (last_i && i - last_i > 4 || i - last_i > 64)
+ if (last_i && i - last_i > 4 || i - last_i > 64 || TEST && i - last_i > 8)
break;
}
last_t = t;
}
- if (!sha) {
- uint32_t seed = 0;
- int j;
- // Unable to allocate an sha context, just xor the buffer together
- // to create something hopefully unique.
- for (j = 0; j < 512; j++)
- seed ^= buffer[j];
- return seed;
- }
+ if(TEST)
+ buffer[0] = buffer[1] = 0;
+
av_sha_init(sha, 160);
- av_sha_update(sha, (const uint8_t *) buffer, sizeof(buffer));
+ av_sha_update(sha, (const uint8_t *)buffer, sizeof(buffer));
av_sha_final(sha, digest);
- av_free(sha);
return AV_RB32(digest) + AV_RB32(digest + 16);
}
@@ -113,3 +127,29 @@ uint32_t av_get_random_seed(void)
return seed;
return get_generic_seed();
}
+
+#if TEST
+#undef printf
+#define N 256
+#include <stdio.h>
+
+int main(void)
+{
+ int i, j, retry;
+ uint32_t seeds[N];
+
+ for (retry=0; retry<3; retry++){
+ for (i=0; i<N; i++){
+ seeds[i] = av_get_random_seed();
+ for (j=0; j<i; j++)
+ if (seeds[j] == seeds[i])
+ goto retry;
+ }
+ printf("seeds OK\n");
+ return 0;
+ retry:;
+ }
+ printf("FAIL at %d with %X\n", j, seeds[j]);
+ return 1;
+}
+#endif
diff --git a/libavutil/random_seed.h b/libavutil/random_seed.h
index b1fad13d07..0462a048e0 100644
--- a/libavutil/random_seed.h
+++ b/libavutil/random_seed.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,12 +28,11 @@
*/
/**
- * Get random data.
- *
- * This function can be called repeatedly to generate more random bits
- * as needed. It is generally quite slow, and usually used to seed a
- * PRNG. As it uses /dev/urandom and /dev/random, the quality of the
- * returned random data depends on the platform.
+ * Get a seed to use in conjunction with random functions.
+ * This function tries to provide a good seed at a best effort bases.
+ * Its possible to call this function multiple times if more bits are needed.
+ * It can be quite slow, which is why it should only be used as seed for a faster
+ * PRNG. The quality of the seed depends on the platform.
*/
uint32_t av_get_random_seed(void);
diff --git a/libavutil/rational.c b/libavutil/rational.c
index 4053936194..594a6f81e6 100644
--- a/libavutil/rational.c
+++ b/libavutil/rational.c
@@ -2,20 +2,20 @@
* rational numbers
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -69,6 +69,7 @@ int av_reduce(int *dst_num, int *dst_den,
den = next_den;
}
av_assert2(av_gcd(a1.num, a1.den) <= 1U);
+ av_assert2(a1.num <= max && a1.den <= max);
*dst_num = sign ? -a1.num : a1.num;
*dst_den = a1.den;
@@ -110,11 +111,14 @@ AVRational av_d2q(double d, int max)
int64_t den;
if (isnan(d))
return (AVRational) { 0,0 };
- if (isinf(d))
+ if (fabs(d) > INT_MAX + 3LL)
return (AVRational) { d < 0 ? -1 : 1, 0 };
exponent = FFMAX( (int)(log(fabs(d) + 1e-20)/LOG2), 0);
den = 1LL << (61 - exponent);
- av_reduce(&a.num, &a.den, (int64_t)(d * den + 0.5), den, max);
+ // (int64_t)rint() and llrint() do not work with gcc on ia64 and sparc64
+ av_reduce(&a.num, &a.den, floor(d * den + 0.5), den, max);
+ if ((!a.num || !a.den) && d && max>0 && max<INT_MAX)
+ av_reduce(&a.num, &a.den, floor(d * den + 0.5), den, INT_MAX);
return a;
}
@@ -143,3 +147,61 @@ int av_find_nearest_q_idx(AVRational q, const AVRational* q_list)
return nearest_q_idx;
}
+
+#ifdef TEST
+int main(void)
+{
+ AVRational a,b,r;
+ for (a.num = -2; a.num <= 2; a.num++) {
+ for (a.den = -2; a.den <= 2; a.den++) {
+ for (b.num = -2; b.num <= 2; b.num++) {
+ for (b.den = -2; b.den <= 2; b.den++) {
+ int c = av_cmp_q(a,b);
+ double d = av_q2d(a) == av_q2d(b) ?
+ 0 : (av_q2d(a) - av_q2d(b));
+ if (d > 0) d = 1;
+ else if (d < 0) d = -1;
+ else if (d != d) d = INT_MIN;
+ if (c != d)
+ av_log(NULL, AV_LOG_ERROR, "%d/%d %d/%d, %d %f\n", a.num,
+ a.den, b.num, b.den, c,d);
+ r = av_sub_q(av_add_q(b,a), b);
+ if(b.den && (r.num*a.den != a.num*r.den || !r.num != !a.num || !r.den != !a.den))
+ av_log(NULL, AV_LOG_ERROR, "%d/%d ", r.num, r.den);
+ }
+ }
+ }
+ }
+
+ for (a.num = 1; a.num <= 10; a.num++) {
+ for (a.den = 1; a.den <= 10; a.den++) {
+ if (av_gcd(a.num, a.den) > 1)
+ continue;
+ for (b.num = 1; b.num <= 10; b.num++) {
+ for (b.den = 1; b.den <= 10; b.den++) {
+ int start;
+ if (av_gcd(b.num, b.den) > 1)
+ continue;
+ if (av_cmp_q(b, a) < 0)
+ continue;
+ for (start = 0; start < 10 ; start++) {
+ int acc= start;
+ int i;
+
+ for (i = 0; i<100; i++) {
+ int exact = start + av_rescale_q(i+1, b, a);
+ acc = av_add_stable(a, acc, b, 1);
+ if (FFABS(acc - exact) > 2) {
+ av_log(NULL, AV_LOG_ERROR, "%d/%d %d/%d, %d %d\n", a.num,
+ a.den, b.num, b.den, acc, exact);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/libavutil/rational.h b/libavutil/rational.h
index 5d7dab7fd0..7439701db2 100644
--- a/libavutil/rational.h
+++ b/libavutil/rational.h
@@ -2,20 +2,20 @@
* rational numbers
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,6 +46,17 @@ typedef struct AVRational{
} AVRational;
/**
+ * Create a rational.
+ * Useful for compilers that do not support compound literals.
+ * @note The return value is not reduced.
+ */
+static inline AVRational av_make_q(int num, int den)
+{
+ AVRational r = { num, den };
+ return r;
+}
+
+/**
* Compare two rationals.
* @param a first rational
* @param b second rational
@@ -55,7 +66,7 @@ typedef struct AVRational{
static inline int av_cmp_q(AVRational a, AVRational b){
const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den;
- if(tmp) return ((tmp ^ a.den ^ b.den)>>63)|1;
+ if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1;
else if(b.den && a.den) return 0;
else if(a.num && b.num) return (a.num>>31) - (b.num>>31);
else return INT_MIN;
diff --git a/libavutil/rc4.c b/libavutil/rc4.c
index 3bf710f3f1..4e52ba5ac1 100644
--- a/libavutil/rc4.c
+++ b/libavutil/rc4.c
@@ -4,20 +4,20 @@
*
* loosely based on LibTomCrypt by Tom St Denis
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "avutil.h"
diff --git a/libavutil/rc4.h b/libavutil/rc4.h
index ec3b47cc8a..9362fd8880 100644
--- a/libavutil/rc4.h
+++ b/libavutil/rc4.h
@@ -1,20 +1,20 @@
/*
* RC4 encryption/decryption/pseudo-random number generator
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/replaygain.h b/libavutil/replaygain.h
index 7871d2c762..5c03e1993d 100644
--- a/libavutil/replaygain.h
+++ b/libavutil/replaygain.h
@@ -1,19 +1,19 @@
/*
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/ripemd.c b/libavutil/ripemd.c
new file mode 100644
index 0000000000..00848605ec
--- /dev/null
+++ b/libavutil/ripemd.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+
+#include "attributes.h"
+#include "avutil.h"
+#include "bswap.h"
+#include "intreadwrite.h"
+#include "ripemd.h"
+#include "mem.h"
+
+/** hash context */
+typedef struct AVRIPEMD {
+ uint8_t digest_len; ///< digest length in 32-bit words
+ uint64_t count; ///< number of bytes in buffer
+ uint8_t buffer[64]; ///< 512-bit buffer of input values used in hash updating
+ uint32_t state[10]; ///< current hash value
+ /** function used to update hash for 512-bit input block */
+ void (*transform)(uint32_t *state, const uint8_t buffer[64]);
+} AVRIPEMD;
+
+const int av_ripemd_size = sizeof(AVRIPEMD);
+
+struct AVRIPEMD *av_ripemd_alloc(void)
+{
+ return av_mallocz(sizeof(struct AVRIPEMD));
+}
+
+static const uint32_t KA[4] = {
+ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e
+};
+
+static const uint32_t KB[4] = {
+ 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9
+};
+
+static const int ROTA[80] = {
+ 11, 14, 15, 12, 5, 8, 7 , 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7 , 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+};
+
+static const int ROTB[80] = {
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+};
+
+static const int WA[80] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+};
+
+static const int WB[80] = {
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+};
+
+#define rol(value, bits) ((value << bits) | (value >> (32 - bits)))
+
+#define ROUND128_0_TO_15(a,b,c,d,e,f,g,h) \
+ a = rol(a + (( b ^ c ^ d) + block[WA[n]]), ROTA[n]); \
+ e = rol(e + ((((f ^ g) & h) ^ g) + block[WB[n]] + KB[0]), ROTB[n]); \
+ n++
+
+#define ROUND128_16_TO_31(a,b,c,d,e,f,g,h) \
+ a = rol(a + ((((c ^ d) & b) ^ d) + block[WA[n]] + KA[0]), ROTA[n]); \
+ e = rol(e + (((~g | f) ^ h) + block[WB[n]] + KB[1]), ROTB[n]); \
+ n++
+
+#define ROUND128_32_TO_47(a,b,c,d,e,f,g,h) \
+ a = rol(a + (((~c | b) ^ d) + block[WA[n]] + KA[1]), ROTA[n]); \
+ e = rol(e + ((((g ^ h) & f) ^ h) + block[WB[n]] + KB[2]), ROTB[n]); \
+ n++
+
+#define ROUND128_48_TO_63(a,b,c,d,e,f,g,h) \
+ a = rol(a + ((((b ^ c) & d) ^ c) + block[WA[n]] + KA[2]), ROTA[n]); \
+ e = rol(e + (( f ^ g ^ h) + block[WB[n]]), ROTB[n]); \
+ n++
+
+#define R128_0 \
+ ROUND128_0_TO_15(a,b,c,d,e,f,g,h); \
+ ROUND128_0_TO_15(d,a,b,c,h,e,f,g); \
+ ROUND128_0_TO_15(c,d,a,b,g,h,e,f); \
+ ROUND128_0_TO_15(b,c,d,a,f,g,h,e)
+
+#define R128_16 \
+ ROUND128_16_TO_31(a,b,c,d,e,f,g,h); \
+ ROUND128_16_TO_31(d,a,b,c,h,e,f,g); \
+ ROUND128_16_TO_31(c,d,a,b,g,h,e,f); \
+ ROUND128_16_TO_31(b,c,d,a,f,g,h,e)
+
+#define R128_32 \
+ ROUND128_32_TO_47(a,b,c,d,e,f,g,h); \
+ ROUND128_32_TO_47(d,a,b,c,h,e,f,g); \
+ ROUND128_32_TO_47(c,d,a,b,g,h,e,f); \
+ ROUND128_32_TO_47(b,c,d,a,f,g,h,e)
+
+#define R128_48 \
+ ROUND128_48_TO_63(a,b,c,d,e,f,g,h); \
+ ROUND128_48_TO_63(d,a,b,c,h,e,f,g); \
+ ROUND128_48_TO_63(c,d,a,b,g,h,e,f); \
+ ROUND128_48_TO_63(b,c,d,a,f,g,h,e)
+
+static void ripemd128_transform(uint32_t *state, const uint8_t buffer[64])
+{
+ uint32_t a, b, c, d, e, f, g, h, av_unused t;
+ uint32_t block[16];
+ int n;
+
+ a = e = state[0];
+ b = f = state[1];
+ c = g = state[2];
+ d = h = state[3];
+
+ for (n = 0; n < 16; n++)
+ block[n] = AV_RL32(buffer + 4 * n);
+ n = 0;
+
+#if CONFIG_SMALL
+ for (; n < 16;) {
+ ROUND128_0_TO_15(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+
+ for (; n < 32;) {
+ ROUND128_16_TO_31(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+
+ for (; n < 48;) {
+ ROUND128_32_TO_47(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+
+ for (; n < 64;) {
+ ROUND128_48_TO_63(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+#else
+
+ R128_0; R128_0; R128_0; R128_0;
+
+ R128_16; R128_16; R128_16; R128_16;
+
+ R128_32; R128_32; R128_32; R128_32;
+
+ R128_48; R128_48; R128_48; R128_48;
+#endif
+
+ h += c + state[1];
+ state[1] = state[2] + d + e;
+ state[2] = state[3] + a + f;
+ state[3] = state[0] + b + g;
+ state[0] = h;
+}
+
+static void ripemd256_transform(uint32_t *state, const uint8_t buffer[64])
+{
+ uint32_t a, b, c, d, e, f, g, h, av_unused t;
+ uint32_t block[16];
+ int n;
+
+ a = state[0]; b = state[1]; c = state[2]; d = state[3];
+ e = state[4]; f = state[5]; g = state[6]; h = state[7];
+
+ for (n = 0; n < 16; n++)
+ block[n] = AV_RL32(buffer + 4 * n);
+ n = 0;
+
+#if CONFIG_SMALL
+ for (; n < 16;) {
+ ROUND128_0_TO_15(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+ FFSWAP(uint32_t, a, e);
+
+ for (; n < 32;) {
+ ROUND128_16_TO_31(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+ FFSWAP(uint32_t, b, f);
+
+ for (; n < 48;) {
+ ROUND128_32_TO_47(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+ FFSWAP(uint32_t, c, g);
+
+ for (; n < 64;) {
+ ROUND128_48_TO_63(a,b,c,d,e,f,g,h);
+ t = d; d = c; c = b; b = a; a = t;
+ t = h; h = g; g = f; f = e; e = t;
+ }
+ FFSWAP(uint32_t, d, h);
+#else
+
+ R128_0; R128_0; R128_0; R128_0;
+ FFSWAP(uint32_t, a, e);
+
+ R128_16; R128_16; R128_16; R128_16;
+ FFSWAP(uint32_t, b, f);
+
+ R128_32; R128_32; R128_32; R128_32;
+ FFSWAP(uint32_t, c, g);
+
+ R128_48; R128_48; R128_48; R128_48;
+ FFSWAP(uint32_t, d, h);
+#endif
+
+ state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+ state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+}
+
+#define ROTATE(x,y) \
+ x = rol(x, 10); \
+ y = rol(y, 10); \
+ n++
+
+#define ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j) \
+ a = rol(a + (( b ^ c ^ d) + block[WA[n]]), ROTA[n]) + e; \
+ f = rol(f + (((~i | h) ^ g) + block[WB[n]] + KB[0]), ROTB[n]) + j; \
+ ROTATE(c,h)
+
+#define ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j) \
+ a = rol(a + ((((c ^ d) & b) ^ d) + block[WA[n]] + KA[0]), ROTA[n]) + e; \
+ f = rol(f + ((((g ^ h) & i) ^ h) + block[WB[n]] + KB[1]), ROTB[n]) + j; \
+ ROTATE(c,h)
+
+#define ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j) \
+ a = rol(a + (((~c | b) ^ d) + block[WA[n]] + KA[1]), ROTA[n]) + e; \
+ f = rol(f + (((~h | g) ^ i) + block[WB[n]] + KB[2]), ROTB[n]) + j; \
+ ROTATE(c,h)
+
+#define ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j) \
+ a = rol(a + ((((b ^ c) & d) ^ c) + block[WA[n]] + KA[2]), ROTA[n]) + e; \
+ f = rol(f + ((((h ^ i) & g) ^ i) + block[WB[n]] + KB[3]), ROTB[n]) + j; \
+ ROTATE(c,h)
+
+#define ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j) \
+ a = rol(a + (((~d | c) ^ b) + block[WA[n]] + KA[3]), ROTA[n]) + e; \
+ f = rol(f + (( g ^ h ^ i) + block[WB[n]]), ROTB[n]) + j; \
+ ROTATE(c,h)
+
+#define R160_0 \
+ ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); \
+ ROUND160_0_TO_15(e,a,b,c,d,j,f,g,h,i); \
+ ROUND160_0_TO_15(d,e,a,b,c,i,j,f,g,h); \
+ ROUND160_0_TO_15(c,d,e,a,b,h,i,j,f,g); \
+ ROUND160_0_TO_15(b,c,d,e,a,g,h,i,j,f)
+
+#define R160_16 \
+ ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); \
+ ROUND160_16_TO_31(d,e,a,b,c,i,j,f,g,h); \
+ ROUND160_16_TO_31(c,d,e,a,b,h,i,j,f,g); \
+ ROUND160_16_TO_31(b,c,d,e,a,g,h,i,j,f); \
+ ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j)
+
+#define R160_32 \
+ ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); \
+ ROUND160_32_TO_47(c,d,e,a,b,h,i,j,f,g); \
+ ROUND160_32_TO_47(b,c,d,e,a,g,h,i,j,f); \
+ ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); \
+ ROUND160_32_TO_47(e,a,b,c,d,j,f,g,h,i)
+
+#define R160_48 \
+ ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); \
+ ROUND160_48_TO_63(b,c,d,e,a,g,h,i,j,f); \
+ ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); \
+ ROUND160_48_TO_63(e,a,b,c,d,j,f,g,h,i); \
+ ROUND160_48_TO_63(d,e,a,b,c,i,j,f,g,h)
+
+#define R160_64 \
+ ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); \
+ ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); \
+ ROUND160_64_TO_79(e,a,b,c,d,j,f,g,h,i); \
+ ROUND160_64_TO_79(d,e,a,b,c,i,j,f,g,h); \
+ ROUND160_64_TO_79(c,d,e,a,b,h,i,j,f,g)
+
+static void ripemd160_transform(uint32_t *state, const uint8_t buffer[64])
+{
+ uint32_t a, b, c, d, e, f, g, h, i, j, av_unused t;
+ uint32_t block[16];
+ int n;
+
+ a = f = state[0];
+ b = g = state[1];
+ c = h = state[2];
+ d = i = state[3];
+ e = j = state[4];
+
+ for (n = 0; n < 16; n++)
+ block[n] = AV_RL32(buffer + 4 * n);
+ n = 0;
+
+#if CONFIG_SMALL
+ for (; n < 16;) {
+ ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+
+ for (; n < 32;) {
+ ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+
+ for (; n < 48;) {
+ ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+
+ for (; n < 64;) {
+ ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+
+ for (; n < 80;) {
+ ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+#else
+
+ R160_0; R160_0; R160_0;
+ ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j);
+
+ R160_16; R160_16; R160_16;
+ ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i);
+
+ R160_32; R160_32; R160_32;
+ ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h);
+
+ R160_48; R160_48; R160_48;
+ ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g);
+
+ R160_64; R160_64; R160_64;
+ ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f);
+#endif
+
+ i += c + state[1];
+ state[1] = state[2] + d + j;
+ state[2] = state[3] + e + f;
+ state[3] = state[4] + a + g;
+ state[4] = state[0] + b + h;
+ state[0] = i;
+}
+
+static void ripemd320_transform(uint32_t *state, const uint8_t buffer[64])
+{
+ uint32_t a, b, c, d, e, f, g, h, i, j, av_unused t;
+ uint32_t block[16];
+ int n;
+
+ a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4];
+ f = state[5]; g = state[6]; h = state[7]; i = state[8]; j = state[9];
+
+ for (n = 0; n < 16; n++)
+ block[n] = AV_RL32(buffer + 4 * n);
+ n = 0;
+
+#if CONFIG_SMALL
+ for (; n < 16;) {
+ ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+ FFSWAP(uint32_t, b, g);
+
+ for (; n < 32;) {
+ ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+ FFSWAP(uint32_t, d, i);
+
+ for (; n < 48;) {
+ ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+ FFSWAP(uint32_t, a, f);
+
+ for (; n < 64;) {
+ ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+ FFSWAP(uint32_t, c, h);
+
+ for (; n < 80;) {
+ ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j);
+ t = e; e = d; d = c; c = b; b = a; a = t;
+ t = j; j = i; i = h; h = g; g = f; f = t;
+ }
+ FFSWAP(uint32_t, e, j);
+#else
+
+ R160_0; R160_0; R160_0;
+ ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j);
+ FFSWAP(uint32_t, a, f);
+
+ R160_16; R160_16; R160_16;
+ ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i);
+ FFSWAP(uint32_t, b, g);
+
+ R160_32; R160_32; R160_32;
+ ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h);
+ FFSWAP(uint32_t, c, h);
+
+ R160_48; R160_48; R160_48;
+ ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g);
+ FFSWAP(uint32_t, d, i);
+
+ R160_64; R160_64; R160_64;
+ ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f);
+ FFSWAP(uint32_t, e, j);
+#endif
+
+ state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e;
+ state[5] += f; state[6] += g; state[7] += h; state[8] += i; state[9] += j;
+}
+
+av_cold int av_ripemd_init(AVRIPEMD *ctx, int bits)
+{
+ ctx->digest_len = bits >> 5;
+ switch (bits) {
+ case 128: // RIPEMD-128
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->transform = ripemd128_transform;
+ break;
+ case 160: // RIPEMD-160
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+ ctx->transform = ripemd160_transform;
+ break;
+ case 256: // RIPEMD-256
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0x76543210;
+ ctx->state[5] = 0xFEDCBA98;
+ ctx->state[6] = 0x89ABCDEF;
+ ctx->state[7] = 0x01234567;
+ ctx->transform = ripemd256_transform;
+ break;
+ case 320: // RIPEMD-320
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+ ctx->state[5] = 0x76543210;
+ ctx->state[6] = 0xFEDCBA98;
+ ctx->state[7] = 0x89ABCDEF;
+ ctx->state[8] = 0x01234567;
+ ctx->state[9] = 0x3C2D1E0F;
+ ctx->transform = ripemd320_transform;
+ break;
+ default:
+ return -1;
+ }
+ ctx->count = 0;
+ return 0;
+}
+
+void av_ripemd_update(AVRIPEMD* ctx, const uint8_t* data, unsigned int len)
+{
+ unsigned int i, j;
+
+ j = ctx->count & 63;
+ ctx->count += len;
+#if CONFIG_SMALL
+ for (i = 0; i < len; i++) {
+ ctx->buffer[j++] = data[i];
+ if (64 == j) {
+ ctx->transform(ctx->state, ctx->buffer);
+ j = 0;
+ }
+ }
+#else
+ if ((j + len) > 63) {
+ memcpy(&ctx->buffer[j], data, (i = 64 - j));
+ ctx->transform(ctx->state, ctx->buffer);
+ for (; i + 63 < len; i += 64)
+ ctx->transform(ctx->state, &data[i]);
+ j = 0;
+ } else
+ i = 0;
+ memcpy(&ctx->buffer[j], &data[i], len - i);
+#endif
+}
+
+void av_ripemd_final(AVRIPEMD* ctx, uint8_t *digest)
+{
+ int i;
+ uint64_t finalcount = av_le2ne64(ctx->count << 3);
+
+ av_ripemd_update(ctx, "\200", 1);
+ while ((ctx->count & 63) != 56)
+ av_ripemd_update(ctx, "", 1);
+ av_ripemd_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */
+ for (i = 0; i < ctx->digest_len; i++)
+ AV_WL32(digest + i*4, ctx->state[i]);
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+int main(void)
+{
+ int i, j, k;
+ AVRIPEMD ctx;
+ unsigned char digest[40];
+ static const int lengths[4] = { 128, 160, 256, 320 };
+
+ for (j = 0; j < 4; j++) {
+ printf("Testing RIPEMD-%d\n", lengths[j]);
+ for (k = 0; k < 3; k++) {
+ av_ripemd_init(&ctx, lengths[j]);
+ if (k == 0)
+ av_ripemd_update(&ctx, "abc", 3);
+ else if (k == 1)
+ av_ripemd_update(&ctx, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56);
+ else
+ for (i = 0; i < 1000*1000; i++)
+ av_ripemd_update(&ctx, "a", 1);
+ av_ripemd_final(&ctx, digest);
+ for (i = 0; i < lengths[j] >> 3; i++)
+ printf("%02X", digest[i]);
+ putchar('\n');
+ }
+ switch (j) { //test vectors (from ISO:IEC 10118-3 (2004) and http://homes.esat.kuleuven.be/~bosselae/ripemd160.html)
+ case 0:
+ printf("c14a1219 9c66e4ba 84636b0f 69144c77\n"
+ "a1aa0689 d0fafa2d dc22e88b 49133a06\n"
+ "4a7f5723 f954eba1 216c9d8f 6320431f\n");
+ break;
+ case 1:
+ printf("8eb208f7 e05d987a 9b044a8e 98c6b087 f15a0bfc\n"
+ "12a05338 4a9c0c88 e405a06c 27dcf49a da62eb2b\n"
+ "52783243 c1697bdb e16d37f9 7f68f083 25dc1528\n");
+ break;
+ case 2:
+ printf("afbd6e22 8b9d8cbb cef5ca2d 03e6dba1 0ac0bc7d cbe4680e 1e42d2e9 75459b65\n"
+ "38430455 83aac6c8 c8d91285 73e7a980 9afb2a0f 34ccc36e a9e72f16 f6368e3f\n"
+ "ac953744 e10e3151 4c150d4d 8d7b6773 42e33399 788296e4 3ae4850c e4f97978\n");
+ break;
+ case 3:
+ printf("de4c01b3 054f8930 a79d09ae 738e9230 1e5a1708 5beffdc1 b8d11671 3e74f82f a942d64c dbc4682d\n"
+ "d034a795 0cf72202 1ba4b84d f769a5de 2060e259 df4c9bb4 a4268c0e 935bbc74 70a969c9 d072a1ac\n"
+ "bdee37f4 371e2064 6b8b0d86 2dda1629 2ae36f40 965e8c85 09e63d1d bddecc50 3e2b63eb 9245bb66\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/libavutil/ripemd.h b/libavutil/ripemd.h
new file mode 100644
index 0000000000..7b0c8bc89c
--- /dev/null
+++ b/libavutil/ripemd.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2013 James Almer <jamrial@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
+ */
+
+#ifndef AVUTIL_RIPEMD_H
+#define AVUTIL_RIPEMD_H
+
+#include <stdint.h>
+
+#include "attributes.h"
+#include "version.h"
+
+/**
+ * @defgroup lavu_ripemd RIPEMD
+ * @ingroup lavu_crypto
+ * @{
+ */
+
+extern const int av_ripemd_size;
+
+struct AVRIPEMD;
+
+/**
+ * Allocate an AVRIPEMD context.
+ */
+struct AVRIPEMD *av_ripemd_alloc(void);
+
+/**
+ * Initialize RIPEMD hashing.
+ *
+ * @param context pointer to the function context (of size av_ripemd_size)
+ * @param bits number of bits in digest (128, 160, 256 or 320 bits)
+ * @return zero if initialization succeeded, -1 otherwise
+ */
+int av_ripemd_init(struct AVRIPEMD* context, int bits);
+
+/**
+ * Update hash value.
+ *
+ * @param context hash function context
+ * @param data input data to update hash with
+ * @param len input data length
+ */
+void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len);
+
+/**
+ * Finish hashing and output digest value.
+ *
+ * @param context hash function context
+ * @param digest buffer where output digest value is stored
+ */
+void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest);
+
+/**
+ * @}
+ */
+
+#endif /* AVUTIL_RIPEMD_H */
diff --git a/libavutil/samplefmt.c b/libavutil/samplefmt.c
index bff600447c..c605b5ebdf 100644
--- a/libavutil/samplefmt.c
+++ b/libavutil/samplefmt.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,7 +24,7 @@
#include <string.h>
typedef struct SampleFmtInfo {
- const char *name;
+ char name[8];
int bits;
int planar;
enum AVSampleFormat altform; ///< planar<->packed alternative form
@@ -61,6 +61,15 @@ enum AVSampleFormat av_get_sample_fmt(const char *name)
return AV_SAMPLE_FMT_NONE;
}
+enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar)
+{
+ if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
+ return AV_SAMPLE_FMT_NONE;
+ if (sample_fmt_info[sample_fmt].planar == planar)
+ return sample_fmt;
+ return sample_fmt_info[sample_fmt].altform;
+}
+
enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt)
{
if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
@@ -149,14 +158,14 @@ int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
if (buf_size < 0)
return buf_size;
- audio_data[0] = buf;
+ audio_data[0] = (uint8_t *)buf;
for (ch = 1; planar && ch < nb_channels; ch++)
audio_data[ch] = audio_data[ch-1] + line_size;
if (linesize)
*linesize = line_size;
- return 0;
+ return buf_size;
}
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
@@ -181,7 +190,22 @@ int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt);
- return 0;
+ return size;
+}
+
+int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
+ int nb_samples, enum AVSampleFormat sample_fmt, int align)
+{
+ int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1;
+
+ *audio_data = av_calloc(nb_planes, sizeof(**audio_data));
+ if (!*audio_data)
+ return AVERROR(ENOMEM);
+ ret = av_samples_alloc(*audio_data, linesize, nb_channels,
+ nb_samples, sample_fmt, align);
+ if (ret < 0)
+ av_freep(audio_data);
+ return ret;
}
int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,
@@ -197,8 +221,13 @@ int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,
dst_offset *= block_align;
src_offset *= block_align;
- for (i = 0; i < planes; i++)
- memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size);
+ if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) {
+ for (i = 0; i < planes; i++)
+ memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size);
+ } else {
+ for (i = 0; i < planes; i++)
+ memmove(dst[i] + dst_offset, src[i] + src_offset, data_size);
+ }
return 0;
}
diff --git a/libavutil/samplefmt.h b/libavutil/samplefmt.h
index 8347fac29c..6a8a031c02 100644
--- a/libavutil/samplefmt.h
+++ b/libavutil/samplefmt.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,20 +36,17 @@
*/
/**
- * Audio Sample Formats
+ * Audio sample formats
*
- * @par
- * The data described by the sample format is always in native-endian order.
- * Sample values can be expressed by native C types, hence the lack of a signed
- * 24-bit sample format even though it is a common raw audio data format.
+ * - The data described by the sample format is always in native-endian order.
+ * Sample values can be expressed by native C types, hence the lack of a signed
+ * 24-bit sample format even though it is a common raw audio data format.
*
- * @par
- * The floating-point formats are based on full volume being in the range
- * [-1.0, 1.0]. Any values outside this range are beyond full volume level.
+ * - The floating-point formats are based on full volume being in the range
+ * [-1.0, 1.0]. Any values outside this range are beyond full volume level.
*
- * @par
- * The data layout as used in av_samples_fill_arrays() and elsewhere in Libav
- * (such as AVFrame in libavcodec) is as follows:
+ * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg
+ * (such as AVFrame in libavcodec) is as follows:
*
* @par
* For planar sample formats, each audio channel is in a separate data plane,
@@ -57,6 +54,7 @@
* planes must be the same size. For packed sample formats, only the first data
* plane is used, and samples for each channel are interleaved. In this case,
* linesize is the buffer size, in bytes, for the 1 plane.
+ *
*/
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
@@ -88,6 +86,14 @@ const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt);
enum AVSampleFormat av_get_sample_fmt(const char *name);
/**
+ * Return the planar<->packed alternative form of the given sample format, or
+ * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the
+ * requested planar/packed format, the format returned is the same as the
+ * input.
+ */
+enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar);
+
+/**
* Get the packed alternative form of the given sample format.
*
* If the passed sample_fmt is already in packed format, the format returned is
@@ -163,16 +169,20 @@ int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
*/
/**
- * Fill channel data pointers and linesize for samples with sample
+ * Fill plane data pointers and linesize for samples with sample
* format sample_fmt.
*
- * The pointers array is filled with the pointers to the samples data:
+ * The audio_data array is filled with the pointers to the samples data planes:
* for planar, set the start point of each channel's data within the buffer,
* for packed, set the start point of the entire buffer only.
*
- * The linesize array is filled with the aligned size of each channel's data
- * buffer for planar layout, or the aligned size of the buffer for all channels
- * for packed layout.
+ * The value pointed to by linesize is set to the aligned size of each
+ * channel's data buffer for planar layout, or to the aligned size of the
+ * buffer for all channels for packed layout.
+ *
+ * The buffer in buf must be big enough to contain all the samples
+ * (use av_samples_get_buffer_size() to compute its minimum size),
+ * otherwise the audio_data pointers will point to invalid data.
*
* @see enum AVSampleFormat
* The documentation for AVSampleFormat describes the data layout.
@@ -184,7 +194,9 @@ int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
* @param nb_samples the number of samples in a single channel
* @param sample_fmt the sample format
* @param align buffer size alignment (0 = default, 1 = no alignment)
- * @return 0 on success or a negative error code on failure
+ * @return >=0 on success or a negative error code on failure
+ * @todo return minimum size in bytes required for the buffer in case
+ * of success at the next bump
*/
int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
const uint8_t *buf,
@@ -205,13 +217,27 @@ int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
* @param nb_channels number of audio channels
* @param nb_samples number of samples per channel
* @param align buffer size alignment (0 = default, 1 = no alignment)
- * @return 0 on success or a negative error code on failure
+ * @return >=0 on success or a negative error code on failure
+ * @todo return the size of the allocated buffer in case of success at the next bump
* @see av_samples_fill_arrays()
+ * @see av_samples_alloc_array_and_samples()
*/
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
int nb_samples, enum AVSampleFormat sample_fmt, int align);
/**
+ * Allocate a data pointers array, samples buffer for nb_samples
+ * samples, and fill data pointers and linesize accordingly.
+ *
+ * This is the same as av_samples_alloc(), but also allocates the data
+ * pointers array.
+ *
+ * @see av_samples_alloc()
+ */
+int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
+ int nb_samples, enum AVSampleFormat sample_fmt, int align);
+
+/**
* Copy samples from src to dst.
*
* @param dst destination array of pointers to data planes
diff --git a/libavutil/sh4/bswap.h b/libavutil/sh4/bswap.h
index 1ff1bfdd37..48dd27f806 100644
--- a/libavutil/sh4/bswap.h
+++ b/libavutil/sh4/bswap.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/sha.c b/libavutil/sha.c
index 2d9b58cda6..9963043fa0 100644
--- a/libavutil/sha.c
+++ b/libavutil/sha.c
@@ -4,20 +4,20 @@
* based on public domain SHA-1 code by Steve Reid <steve@edmweb.com>
* and on BSD-licensed SHA-2 code by Aaron D. Gifford
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,9 +40,7 @@ typedef struct AVSHA {
void (*transform)(uint32_t *state, const uint8_t buffer[64]);
} AVSHA;
-#if FF_API_CONTEXT_SIZE
const int av_sha_size = sizeof(AVSHA);
-#endif
struct AVSHA *av_sha_alloc(void)
{
@@ -53,13 +51,13 @@ struct AVSHA *av_sha_alloc(void)
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define blk0(i) (block[i] = AV_RB32(buffer + 4 * (i)))
-#define blk(i) (block[i] = rol(block[i-3] ^ block[i-8] ^ block[i-14] ^ block[i-16], 1))
+#define blk(i) (block[i] = rol(block[(i)-3] ^ block[(i)-8] ^ block[(i)-14] ^ block[(i)-16], 1))
-#define R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk0(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30);
-#define R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk (i) + 0x5A827999 + rol(v, 5); w = rol(w, 30);
-#define R2(v,w,x,y,z,i) z += ( w^x ^y) + blk (i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
-#define R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + blk (i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30);
-#define R4(v,w,x,y,z,i) z += ( w^x ^y) + blk (i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30);
+#define R0(v,w,x,y,z,i) z += (((w)&((x)^(y)))^(y)) + blk0(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30);
+#define R1(v,w,x,y,z,i) z += (((w)&((x)^(y)))^(y)) + blk (i) + 0x5A827999 + rol(v, 5); w = rol(w, 30);
+#define R2(v,w,x,y,z,i) z += ( (w)^(x) ^(y)) + blk (i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
+#define R3(v,w,x,y,z,i) z += ((((w)|(x))&(y))|((w)&(x))) + blk (i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30);
+#define R4(v,w,x,y,z,i) z += ( (w)^(x) ^(y)) + blk (i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
@@ -100,39 +98,53 @@ static void sha1_transform(uint32_t state[5], const uint8_t buffer[64])
a = t;
}
#else
- for (i = 0; i < 15; i += 5) {
- R0(a, b, c, d, e, 0 + i);
- R0(e, a, b, c, d, 1 + i);
- R0(d, e, a, b, c, 2 + i);
- R0(c, d, e, a, b, 3 + i);
- R0(b, c, d, e, a, 4 + i);
- }
+
+#define R1_0 \
+ R0(a, b, c, d, e, 0 + i); \
+ R0(e, a, b, c, d, 1 + i); \
+ R0(d, e, a, b, c, 2 + i); \
+ R0(c, d, e, a, b, 3 + i); \
+ R0(b, c, d, e, a, 4 + i); \
+ i += 5
+
+ i = 0;
+ R1_0; R1_0; R1_0;
R0(a, b, c, d, e, 15);
R1(e, a, b, c, d, 16);
R1(d, e, a, b, c, 17);
R1(c, d, e, a, b, 18);
R1(b, c, d, e, a, 19);
- for (i = 20; i < 40; i += 5) {
- R2(a, b, c, d, e, 0 + i);
- R2(e, a, b, c, d, 1 + i);
- R2(d, e, a, b, c, 2 + i);
- R2(c, d, e, a, b, 3 + i);
- R2(b, c, d, e, a, 4 + i);
- }
- for (; i < 60; i += 5) {
- R3(a, b, c, d, e, 0 + i);
- R3(e, a, b, c, d, 1 + i);
- R3(d, e, a, b, c, 2 + i);
- R3(c, d, e, a, b, 3 + i);
- R3(b, c, d, e, a, 4 + i);
- }
- for (; i < 80; i += 5) {
- R4(a, b, c, d, e, 0 + i);
- R4(e, a, b, c, d, 1 + i);
- R4(d, e, a, b, c, 2 + i);
- R4(c, d, e, a, b, 3 + i);
- R4(b, c, d, e, a, 4 + i);
- }
+
+#define R1_20 \
+ R2(a, b, c, d, e, 0 + i); \
+ R2(e, a, b, c, d, 1 + i); \
+ R2(d, e, a, b, c, 2 + i); \
+ R2(c, d, e, a, b, 3 + i); \
+ R2(b, c, d, e, a, 4 + i); \
+ i += 5
+
+ i = 20;
+ R1_20; R1_20; R1_20; R1_20;
+
+#define R1_40 \
+ R3(a, b, c, d, e, 0 + i); \
+ R3(e, a, b, c, d, 1 + i); \
+ R3(d, e, a, b, c, 2 + i); \
+ R3(c, d, e, a, b, 3 + i); \
+ R3(b, c, d, e, a, 4 + i); \
+ i += 5
+
+ R1_40; R1_40; R1_40; R1_40;
+
+#define R1_60 \
+ R4(a, b, c, d, e, 0 + i); \
+ R4(e, a, b, c, d, 1 + i); \
+ R4(d, e, a, b, c, 2 + i); \
+ R4(c, d, e, a, b, 3 + i); \
+ R4(b, c, d, e, a, 4 + i); \
+ i += 5
+
+ R1_60; R1_60; R1_60; R1_60;
#endif
state[0] += a;
state[1] += b;
@@ -162,7 +174,7 @@ static const uint32_t K256[64] = {
#define Ch(x,y,z) (((x) & ((y) ^ (z))) ^ (z))
-#define Maj(x,y,z) ((((x) | (y)) & (z)) | ((x) & (y)))
+#define Maj(z,y,x) ((((x) | (y)) & (z)) | ((x) & (y)))
#define Sigma0_256(x) (rol((x), 30) ^ rol((x), 19) ^ rol((x), 10))
#define Sigma1_256(x) (rol((x), 26) ^ rol((x), 21) ^ rol((x), 7))
@@ -220,27 +232,32 @@ static void sha256_transform(uint32_t *state, const uint8_t buffer[64])
a = T1 + T2;
}
#else
- for (i = 0; i < 16;) {
- ROUND256_0_TO_15(a, b, c, d, e, f, g, h);
- ROUND256_0_TO_15(h, a, b, c, d, e, f, g);
- ROUND256_0_TO_15(g, h, a, b, c, d, e, f);
- ROUND256_0_TO_15(f, g, h, a, b, c, d, e);
- ROUND256_0_TO_15(e, f, g, h, a, b, c, d);
- ROUND256_0_TO_15(d, e, f, g, h, a, b, c);
- ROUND256_0_TO_15(c, d, e, f, g, h, a, b);
- ROUND256_0_TO_15(b, c, d, e, f, g, h, a);
- }
- for (; i < 64;) {
- ROUND256_16_TO_63(a, b, c, d, e, f, g, h);
- ROUND256_16_TO_63(h, a, b, c, d, e, f, g);
- ROUND256_16_TO_63(g, h, a, b, c, d, e, f);
- ROUND256_16_TO_63(f, g, h, a, b, c, d, e);
- ROUND256_16_TO_63(e, f, g, h, a, b, c, d);
- ROUND256_16_TO_63(d, e, f, g, h, a, b, c);
- ROUND256_16_TO_63(c, d, e, f, g, h, a, b);
- ROUND256_16_TO_63(b, c, d, e, f, g, h, a);
- }
+ i = 0;
+#define R256_0 \
+ ROUND256_0_TO_15(a, b, c, d, e, f, g, h); \
+ ROUND256_0_TO_15(h, a, b, c, d, e, f, g); \
+ ROUND256_0_TO_15(g, h, a, b, c, d, e, f); \
+ ROUND256_0_TO_15(f, g, h, a, b, c, d, e); \
+ ROUND256_0_TO_15(e, f, g, h, a, b, c, d); \
+ ROUND256_0_TO_15(d, e, f, g, h, a, b, c); \
+ ROUND256_0_TO_15(c, d, e, f, g, h, a, b); \
+ ROUND256_0_TO_15(b, c, d, e, f, g, h, a)
+
+ R256_0; R256_0;
+
+#define R256_16 \
+ ROUND256_16_TO_63(a, b, c, d, e, f, g, h); \
+ ROUND256_16_TO_63(h, a, b, c, d, e, f, g); \
+ ROUND256_16_TO_63(g, h, a, b, c, d, e, f); \
+ ROUND256_16_TO_63(f, g, h, a, b, c, d, e); \
+ ROUND256_16_TO_63(e, f, g, h, a, b, c, d); \
+ ROUND256_16_TO_63(d, e, f, g, h, a, b, c); \
+ ROUND256_16_TO_63(c, d, e, f, g, h, a, b); \
+ ROUND256_16_TO_63(b, c, d, e, f, g, h, a)
+
+ R256_16; R256_16; R256_16;
+ R256_16; R256_16; R256_16;
#endif
state[0] += a;
state[1] += b;
@@ -342,7 +359,7 @@ int main(void)
int i, j, k;
AVSHA ctx;
unsigned char digest[32];
- const int lengths[3] = { 160, 224, 256 };
+ static const int lengths[3] = { 160, 224, 256 };
for (j = 0; j < 3; j++) {
printf("Testing SHA-%d\n", lengths[j]);
diff --git a/libavutil/sha.h b/libavutil/sha.h
index 4c9a0c9095..bf4377e51b 100644
--- a/libavutil/sha.h
+++ b/libavutil/sha.h
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -32,9 +32,7 @@
* @{
*/
-#if FF_API_CONTEXT_SIZE
-extern attribute_deprecated const int av_sha_size;
-#endif
+extern const int av_sha_size;
struct AVSHA;
diff --git a/libavutil/sha512.c b/libavutil/sha512.c
new file mode 100644
index 0000000000..66a864f1a6
--- /dev/null
+++ b/libavutil/sha512.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2009 Konstantin Shishkov
+ * Copyright (C) 2013 James Almer
+ * based on BSD-licensed SHA-2 code by Aaron D. Gifford
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <string.h>
+
+#include "attributes.h"
+#include "avutil.h"
+#include "bswap.h"
+#include "sha512.h"
+#include "intreadwrite.h"
+#include "mem.h"
+
+/** hash context */
+typedef struct AVSHA512 {
+ uint8_t digest_len; ///< digest length in 64-bit words
+ uint64_t count; ///< number of bytes in buffer
+ uint8_t buffer[128]; ///< 1024-bit buffer of input values used in hash updating
+ uint64_t state[8]; ///< current hash value
+} AVSHA512;
+
+const int av_sha512_size = sizeof(AVSHA512);
+
+struct AVSHA512 *av_sha512_alloc(void)
+{
+ return av_mallocz(sizeof(struct AVSHA512));
+}
+
+static const uint64_t K512[80] = {
+ UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
+ UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
+ UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
+ UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
+ UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
+ UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
+ UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
+ UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
+ UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
+ UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
+ UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
+ UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
+ UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
+ UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
+ UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
+ UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
+ UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
+ UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
+ UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
+ UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
+ UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
+ UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
+ UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
+ UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
+ UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
+ UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
+ UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
+ UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
+ UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
+ UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
+ UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
+ UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
+ UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
+ UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
+ UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
+ UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
+ UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
+ UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
+ UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
+ UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817),
+};
+
+#define ror(value, bits) (((value) >> (bits)) | ((value) << (64 - (bits))))
+
+#define Ch(x,y,z) (((x) & ((y) ^ (z))) ^ (z))
+#define Maj(z,y,x) ((((x) | (y)) & (z)) | ((x) & (y)))
+
+#define Sigma0_512(x) (ror((x), 28) ^ ror((x), 34) ^ ror((x), 39))
+#define Sigma1_512(x) (ror((x), 14) ^ ror((x), 18) ^ ror((x), 41))
+#define sigma0_512(x) (ror((x), 1) ^ ror((x), 8) ^ ((x) >> 7))
+#define sigma1_512(x) (ror((x), 19) ^ ror((x), 61) ^ ((x) >> 6))
+
+#define blk0(i) (block[i] = AV_RB64(buffer + 8 * (i)))
+#define blk(i) (block[i] = block[i - 16] + sigma0_512(block[i - 15]) + \
+ sigma1_512(block[i - 2]) + block[i - 7])
+
+#define ROUND512(a,b,c,d,e,f,g,h) \
+ T1 += (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[i]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \
+ i++
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = blk0(i); \
+ ROUND512(a,b,c,d,e,f,g,h)
+
+#define ROUND512_16_TO_80(a,b,c,d,e,f,g,h) \
+ T1 = blk(i); \
+ ROUND512(a,b,c,d,e,f,g,h)
+
+static void sha512_transform(uint64_t *state, const uint8_t buffer[128])
+{
+ uint64_t a, b, c, d, e, f, g, h;
+ uint64_t block[80];
+ uint64_t T1;
+ int i;
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ f = state[5];
+ g = state[6];
+ h = state[7];
+#if CONFIG_SMALL
+ for (i = 0; i < 80; i++) {
+ uint64_t T2;
+ if (i < 16)
+ T1 = blk0(i);
+ else
+ T1 = blk(i);
+ T1 += h + Sigma1_512(e) + Ch(e, f, g) + K512[i];
+ T2 = Sigma0_512(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+#else
+
+#define R512_0 \
+ ROUND512_0_TO_15(a, b, c, d, e, f, g, h); \
+ ROUND512_0_TO_15(h, a, b, c, d, e, f, g); \
+ ROUND512_0_TO_15(g, h, a, b, c, d, e, f); \
+ ROUND512_0_TO_15(f, g, h, a, b, c, d, e); \
+ ROUND512_0_TO_15(e, f, g, h, a, b, c, d); \
+ ROUND512_0_TO_15(d, e, f, g, h, a, b, c); \
+ ROUND512_0_TO_15(c, d, e, f, g, h, a, b); \
+ ROUND512_0_TO_15(b, c, d, e, f, g, h, a)
+
+ i = 0;
+ R512_0; R512_0;
+
+#define R512_16 \
+ ROUND512_16_TO_80(a, b, c, d, e, f, g, h); \
+ ROUND512_16_TO_80(h, a, b, c, d, e, f, g); \
+ ROUND512_16_TO_80(g, h, a, b, c, d, e, f); \
+ ROUND512_16_TO_80(f, g, h, a, b, c, d, e); \
+ ROUND512_16_TO_80(e, f, g, h, a, b, c, d); \
+ ROUND512_16_TO_80(d, e, f, g, h, a, b, c); \
+ ROUND512_16_TO_80(c, d, e, f, g, h, a, b); \
+ ROUND512_16_TO_80(b, c, d, e, f, g, h, a)
+
+ R512_16; R512_16; R512_16; R512_16;
+ R512_16; R512_16; R512_16; R512_16;
+#endif
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ state[5] += f;
+ state[6] += g;
+ state[7] += h;
+}
+
+
+av_cold int av_sha512_init(AVSHA512 *ctx, int bits)
+{
+ ctx->digest_len = bits >> 6;
+ switch (bits) {
+ case 224: // SHA-512/224
+ ctx->state[0] = UINT64_C(0x8C3D37C819544DA2);
+ ctx->state[1] = UINT64_C(0x73E1996689DCD4D6);
+ ctx->state[2] = UINT64_C(0x1DFAB7AE32FF9C82);
+ ctx->state[3] = UINT64_C(0x679DD514582F9FCF);
+ ctx->state[4] = UINT64_C(0x0F6D2B697BD44DA8);
+ ctx->state[5] = UINT64_C(0x77E36F7304C48942);
+ ctx->state[6] = UINT64_C(0x3F9D85A86A1D36C8);
+ ctx->state[7] = UINT64_C(0x1112E6AD91D692A1);
+ break;
+ case 256: // SHA-512/256
+ ctx->state[0] = UINT64_C(0x22312194FC2BF72C);
+ ctx->state[1] = UINT64_C(0x9F555FA3C84C64C2);
+ ctx->state[2] = UINT64_C(0x2393B86B6F53B151);
+ ctx->state[3] = UINT64_C(0x963877195940EABD);
+ ctx->state[4] = UINT64_C(0x96283EE2A88EFFE3);
+ ctx->state[5] = UINT64_C(0xBE5E1E2553863992);
+ ctx->state[6] = UINT64_C(0x2B0199FC2C85B8AA);
+ ctx->state[7] = UINT64_C(0x0EB72DDC81C52CA2);
+ break;
+ case 384: // SHA-384
+ ctx->state[0] = UINT64_C(0xCBBB9D5DC1059ED8);
+ ctx->state[1] = UINT64_C(0x629A292A367CD507);
+ ctx->state[2] = UINT64_C(0x9159015A3070DD17);
+ ctx->state[3] = UINT64_C(0x152FECD8F70E5939);
+ ctx->state[4] = UINT64_C(0x67332667FFC00B31);
+ ctx->state[5] = UINT64_C(0x8EB44A8768581511);
+ ctx->state[6] = UINT64_C(0xDB0C2E0D64F98FA7);
+ ctx->state[7] = UINT64_C(0x47B5481DBEFA4FA4);
+ break;
+ case 512: // SHA-512
+ ctx->state[0] = UINT64_C(0x6A09E667F3BCC908);
+ ctx->state[1] = UINT64_C(0xBB67AE8584CAA73B);
+ ctx->state[2] = UINT64_C(0x3C6EF372FE94F82B);
+ ctx->state[3] = UINT64_C(0xA54FF53A5F1D36F1);
+ ctx->state[4] = UINT64_C(0x510E527FADE682D1);
+ ctx->state[5] = UINT64_C(0x9B05688C2B3E6C1F);
+ ctx->state[6] = UINT64_C(0x1F83D9ABFB41BD6B);
+ ctx->state[7] = UINT64_C(0x5BE0CD19137E2179);
+ break;
+ default:
+ return -1;
+ }
+ ctx->count = 0;
+ return 0;
+}
+
+void av_sha512_update(AVSHA512* ctx, const uint8_t* data, unsigned int len)
+{
+ unsigned int i, j;
+
+ j = ctx->count & 127;
+ ctx->count += len;
+#if CONFIG_SMALL
+ for (i = 0; i < len; i++) {
+ ctx->buffer[j++] = data[i];
+ if (128 == j) {
+ sha512_transform(ctx->state, ctx->buffer);
+ j = 0;
+ }
+ }
+#else
+ if ((j + len) > 127) {
+ memcpy(&ctx->buffer[j], data, (i = 128 - j));
+ sha512_transform(ctx->state, ctx->buffer);
+ for (; i + 127 < len; i += 128)
+ sha512_transform(ctx->state, &data[i]);
+ j = 0;
+ } else
+ i = 0;
+ memcpy(&ctx->buffer[j], &data[i], len - i);
+#endif
+}
+
+void av_sha512_final(AVSHA512* ctx, uint8_t *digest)
+{
+ uint64_t i = 0;
+ uint64_t finalcount = av_be2ne64(ctx->count << 3);
+
+ av_sha512_update(ctx, "\200", 1);
+ while ((ctx->count & 127) != 112)
+ av_sha512_update(ctx, "", 1);
+ av_sha512_update(ctx, (uint8_t *)&i, 8);
+ av_sha512_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */
+ for (i = 0; i < ctx->digest_len; i++)
+ AV_WB64(digest + i*8, ctx->state[i]);
+ if (ctx->digest_len & 1) /* SHA512/224 is 28 bytes, and is not divisible by 8. */
+ AV_WB32(digest + i*8, ctx->state[i] >> 32);
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+int main(void)
+{
+ int i, j, k;
+ AVSHA512 ctx;
+ unsigned char digest[64];
+ static const int lengths[4] = { 224, 256, 384, 512 };
+
+ for (j = 0; j < 4; j++) {
+ if (j < 2) printf("Testing SHA-512/%d\n", lengths[j]);
+ else printf("Testing SHA-%d\n", lengths[j]);
+ for (k = 0; k < 3; k++) {
+ av_sha512_init(&ctx, lengths[j]);
+ if (k == 0)
+ av_sha512_update(&ctx, "abc", 3);
+ else if (k == 1)
+ av_sha512_update(&ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112);
+ else
+ for (i = 0; i < 1000*1000; i++)
+ av_sha512_update(&ctx, "a", 1);
+ av_sha512_final(&ctx, digest);
+ for (i = 0; i < lengths[j] >> 3; i++)
+ printf("%02X", digest[i]);
+ putchar('\n');
+ }
+ switch (j) { //test vectors (from FIPS PUB 180-4 Apendix A)
+ case 0:
+ printf("4634270f 707b6a54 daae7530 460842e2 0e37ed26 5ceee9a4 3e8924aa\n"
+ "23fec5bb 94d60b23 30819264 0b0c4533 35d66473 4fe40e72 68674af9\n"
+ "37ab331d 76f0d36d e422bd0e deb22a28 accd487b 7a8453ae 965dd287\n");
+ break;
+ case 1:
+ printf("53048e26 81941ef9 9b2e29b7 6b4c7dab e4c2d0c6 34fc6d46 e0e2f131 07e7af23\n"
+ "3928e184 fb8690f8 40da3988 121d31be 65cb9d3e f83ee614 6feac861 e19b563a\n"
+ "9a59a052 930187a9 7038cae6 92f30708 aa649192 3ef51943 94dc68d5 6c74fb21\n");
+ break;
+ case 2:
+ printf("cb00753f 45a35e8b b5a03d69 9ac65007 272c32ab 0eded163 "
+ "1a8b605a 43ff5bed 8086072b a1e7cc23 58baeca1 34c825a7\n"
+ "09330c33 f71147e8 3d192fc7 82cd1b47 53111b17 3b3b05d2 "
+ "2fa08086 e3b0f712 fcc7c71a 557e2db9 66c3e9fa 91746039\n"
+ "9d0e1809 716474cb 086e834e 310a4a1c ed149e9c 00f24852 "
+ "7972cec5 704c2a5b 07b8b3dc 38ecc4eb ae97ddd8 7f3d8985\n");
+ break;
+ case 3:
+ printf("ddaf35a1 93617aba cc417349 ae204131 12e6fa4e 89a97ea2 0a9eeee6 4b55d39a "
+ "2192992a 274fc1a8 36ba3c23 a3feebbd 454d4423 643ce80e 2a9ac94f a54ca49f\n"
+ "8e959b75 dae313da 8cf4f728 14fc143f 8f7779c6 eb9f7fa1 7299aead b6889018 "
+ "501d289e 4900f7e4 331b99de c4b5433a c7d329ee b6dd2654 5e96e55b 874be909\n"
+ "e718483d 0ce76964 4e2e42c7 bc15b463 8e1f98b1 3b204428 5632a803 afa973eb "
+ "de0ff244 877ea60a 4cb0432c e577c31b eb009c5c 2c49aa2e 4eadb217 ad8cc09b\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/libavutil/sha512.h b/libavutil/sha512.h
new file mode 100644
index 0000000000..7b08701477
--- /dev/null
+++ b/libavutil/sha512.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2013 James Almer <jamrial@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
+ */
+
+#ifndef AVUTIL_SHA512_H
+#define AVUTIL_SHA512_H
+
+#include <stdint.h>
+
+#include "attributes.h"
+#include "version.h"
+
+/**
+ * @defgroup lavu_sha512 SHA512
+ * @ingroup lavu_crypto
+ * @{
+ */
+
+extern const int av_sha512_size;
+
+struct AVSHA512;
+
+/**
+ * Allocate an AVSHA512 context.
+ */
+struct AVSHA512 *av_sha512_alloc(void);
+
+/**
+ * Initialize SHA-2 512 hashing.
+ *
+ * @param context pointer to the function context (of size av_sha512_size)
+ * @param bits number of bits in digest (224, 256, 384 or 512 bits)
+ * @return zero if initialization succeeded, -1 otherwise
+ */
+int av_sha512_init(struct AVSHA512* context, int bits);
+
+/**
+ * Update hash value.
+ *
+ * @param context hash function context
+ * @param data input data to update hash with
+ * @param len input data length
+ */
+void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len);
+
+/**
+ * Finish hashing and output digest value.
+ *
+ * @param context hash function context
+ * @param digest buffer where output digest value is stored
+ */
+void av_sha512_final(struct AVSHA512* context, uint8_t *digest);
+
+/**
+ * @}
+ */
+
+#endif /* AVUTIL_SHA512_H */
diff --git a/libavutil/softfloat.c b/libavutil/softfloat.c
new file mode 100644
index 0000000000..b6e1f35d4d
--- /dev/null
+++ b/libavutil/softfloat.c
@@ -0,0 +1,98 @@
+/*
+ * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <inttypes.h>
+#include <stdio.h>
+#include "softfloat.h"
+#include "common.h"
+#include "log.h"
+
+#undef printf
+
+static const SoftFloat FLOAT_0_017776489257 = {0x1234, 12};
+static const SoftFloat FLOAT_1374_40625 = {0xabcd, 25};
+static const SoftFloat FLOAT_0_1249694824218 = {0xFFF, 15};
+
+
+static av_const double av_sf2double(SoftFloat v) {
+ v.exp -= ONE_BITS +1;
+ if(v.exp > 0) return (double)v.mant * (double)(1 << v.exp);
+ else return (double)v.mant / (double)(1 << (-v.exp));
+}
+
+int main(void){
+ SoftFloat one= av_int2sf(1, 0);
+ SoftFloat sf1, sf2, sf3;
+ double d1, d2, d3;
+ int i, j;
+ av_log_set_level(AV_LOG_DEBUG);
+
+ d1= 1;
+ for(i= 0; i<10; i++){
+ d1= 1/(d1+1);
+ }
+ printf("test1 double=%d\n", (int)(d1 * (1<<24)));
+
+ sf1= one;
+ for(i= 0; i<10; i++){
+ sf1= av_div_sf(one, av_normalize_sf(av_add_sf(one, sf1)));
+ }
+ printf("test1 sf =%d\n", av_sf2int(sf1, 24));
+
+
+ for(i= 0; i<100; i++){
+ START_TIMER
+ d1= i;
+ d2= i/100.0;
+ for(j= 0; j<1000; j++){
+ d1= (d1+1)*d2;
+ }
+ STOP_TIMER("float add mul")
+ }
+ printf("test2 double=%d\n", (int)(d1 * (1<<24)));
+
+ for(i= 0; i<100; i++){
+ START_TIMER
+ sf1= av_int2sf(i, 0);
+ sf2= av_div_sf(av_int2sf(i, 2), av_int2sf(200, 3));
+ for(j= 0; j<1000; j++){
+ sf1= av_mul_sf(av_add_sf(sf1, one),sf2);
+ }
+ STOP_TIMER("softfloat add mul")
+ }
+ printf("test2 sf =%d (%d %d)\n", av_sf2int(sf1, 24), sf1.exp, sf1.mant);
+
+ d1 = 0.0177764893;
+ d2 = 1374.40625;
+ d3 = 0.1249694824;
+ d2 += d1;
+ d3 += d2;
+ printf("test3 double: %.10lf\n", d3);
+
+ sf1 = FLOAT_0_017776489257;
+ sf2 = FLOAT_1374_40625;
+ sf3 = FLOAT_0_1249694824218;
+ sf2 = av_add_sf(sf1, sf2);
+ sf3 = av_add_sf(sf3, sf2);
+ printf("test3 softfloat: %.10lf (0x%08x %d)\n", (double)av_sf2double(sf3), sf3.mant, sf3.exp);
+
+ return 0;
+
+}
diff --git a/libavutil/softfloat.h b/libavutil/softfloat.h
new file mode 100644
index 0000000000..d6cfc3cacc
--- /dev/null
+++ b/libavutil/softfloat.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_SOFTFLOAT_H
+#define AVUTIL_SOFTFLOAT_H
+
+#include <stdint.h>
+#include "common.h"
+
+#include "avassert.h"
+#include "softfloat_tables.h"
+
+#define MIN_EXP -126
+#define MAX_EXP 126
+#define ONE_BITS 29
+
+typedef struct SoftFloat{
+ int32_t mant;
+ int32_t exp;
+}SoftFloat;
+
+static av_const SoftFloat av_normalize_sf(SoftFloat a){
+ if(a.mant){
+#if 1
+ while((a.mant + 0x20000000U)<0x40000000U){
+ a.mant += a.mant;
+ a.exp -= 1;
+ }
+#else
+ int s=ONE_BITS + 1 - av_log2(a.mant ^ (a.mant<<1));
+ a.exp -= s;
+ a.mant <<= s;
+#endif
+ if(a.exp < MIN_EXP){
+ a.exp = MIN_EXP;
+ a.mant= 0;
+ }
+ }else{
+ a.exp= MIN_EXP;
+ }
+ return a;
+}
+
+static inline av_const SoftFloat av_normalize1_sf(SoftFloat a){
+#if 1
+ if((int32_t)(a.mant + 0x40000000U) < 0){
+ a.exp++;
+ a.mant>>=1;
+ }
+ av_assert2(a.mant < 0x40000000 && a.mant > -0x40000000);
+ return a;
+#elif 1
+ int t= a.mant + 0x40000000 < 0;
+ return (SoftFloat){ a.mant>>t, a.exp+t};
+#else
+ int t= (a.mant + 0x40000000U)>>31;
+ return (SoftFloat){a.mant>>t, a.exp+t};
+#endif
+}
+
+/**
+ * @return Will not be more denormalized than a+b. So if either input is
+ * normalized, then the output will not be worse then the other input.
+ * If both are normalized, then the output will be normalized.
+ */
+static inline av_const SoftFloat av_mul_sf(SoftFloat a, SoftFloat b){
+ a.exp += b.exp;
+ av_assert2((int32_t)((a.mant * (int64_t)b.mant) >> ONE_BITS) == (a.mant * (int64_t)b.mant) >> ONE_BITS);
+ a.mant = (a.mant * (int64_t)b.mant) >> ONE_BITS;
+ return av_normalize1_sf((SoftFloat){a.mant, a.exp - 1});
+}
+
+/**
+ * b has to be normalized and not zero.
+ * @return Will not be more denormalized than a.
+ */
+static av_const SoftFloat av_div_sf(SoftFloat a, SoftFloat b){
+ a.exp -= b.exp;
+ a.mant = ((int64_t)a.mant<<(ONE_BITS+1)) / b.mant;
+ return av_normalize1_sf(a);
+}
+
+static inline av_const int av_cmp_sf(SoftFloat a, SoftFloat b){
+ int t= a.exp - b.exp;
+ if(t<0) return (a.mant >> (-t)) - b.mant ;
+ else return a.mant - (b.mant >> t);
+}
+
+static inline av_const int av_gt_sf(SoftFloat a, SoftFloat b)
+{
+ int t= a.exp - b.exp;
+ if(t<0) return (a.mant >> (-t)) > b.mant ;
+ else return a.mant > (b.mant >> t);
+}
+
+static inline av_const SoftFloat av_add_sf(SoftFloat a, SoftFloat b){
+ int t= a.exp - b.exp;
+ if (t <-31) return b;
+ else if (t < 0) return av_normalize_sf(av_normalize1_sf((SoftFloat){ b.mant + (a.mant >> (-t)), b.exp}));
+ else if (t < 32) return av_normalize_sf(av_normalize1_sf((SoftFloat){ a.mant + (b.mant >> t ), a.exp}));
+ else return a;
+}
+
+static inline av_const SoftFloat av_sub_sf(SoftFloat a, SoftFloat b){
+ return av_add_sf(a, (SoftFloat){ -b.mant, b.exp});
+}
+
+//FIXME log, exp, pow
+
+/**
+ * Converts a mantisse and exponent to a SoftFloat
+ * @returns a SoftFloat with value v * 2^frac_bits
+ */
+static inline av_const SoftFloat av_int2sf(int v, int frac_bits){
+ return av_normalize_sf((SoftFloat){v, ONE_BITS + 1 - frac_bits});
+}
+
+/**
+ * Rounding is to -inf.
+ */
+static inline av_const int av_sf2int(SoftFloat v, int frac_bits){
+ v.exp += frac_bits - (ONE_BITS + 1);
+ if(v.exp >= 0) return v.mant << v.exp ;
+ else return v.mant >>(-v.exp);
+}
+
+/**
+ * Rounding-to-nearest used.
+ */
+static av_always_inline SoftFloat av_sqrt_sf(SoftFloat val)
+{
+ int tabIndex, rem;
+
+ if (val.mant == 0)
+ val.exp = 0;
+ else
+ {
+ tabIndex = (val.mant - 0x20000000) >> 20;
+
+ rem = val.mant & 0xFFFFF;
+ val.mant = (int)(((int64_t)av_sqrttbl_sf[tabIndex] * (0x100000 - rem) +
+ (int64_t)av_sqrttbl_sf[tabIndex + 1] * rem +
+ 0x80000) >> 20);
+ val.mant = (int)(((int64_t)av_sqr_exp_multbl_sf[val.exp & 1] * val.mant +
+ 0x10000000) >> 29);
+
+ if (val.mant < 0x40000000)
+ val.exp -= 2;
+ else
+ val.mant >>= 1;
+
+ val.exp = (val.exp >> 1) + 1;
+ }
+
+ return val;
+}
+
+/**
+ * Rounding-to-nearest used.
+ */
+static av_always_inline void av_sincos_sf(int a, int *s, int *c)
+{
+ int idx, sign;
+ int sv, cv;
+ int st, ct;
+
+ idx = a >> 26;
+ sign = (idx << 27) >> 31;
+ cv = av_costbl_1_sf[idx & 0xf];
+ cv = (cv ^ sign) - sign;
+
+ idx -= 8;
+ sign = (idx << 27) >> 31;
+ sv = av_costbl_1_sf[idx & 0xf];
+ sv = (sv ^ sign) - sign;
+
+ idx = a >> 21;
+ ct = av_costbl_2_sf[idx & 0x1f];
+ st = av_sintbl_2_sf[idx & 0x1f];
+
+ idx = (int)(((int64_t)cv * ct - (int64_t)sv * st + 0x20000000) >> 30);
+
+ sv = (int)(((int64_t)cv * st + (int64_t)sv * ct + 0x20000000) >> 30);
+
+ cv = idx;
+
+ idx = a >> 16;
+ ct = av_costbl_3_sf[idx & 0x1f];
+ st = av_sintbl_3_sf[idx & 0x1f];
+
+ idx = (int)(((int64_t)cv * ct - (int64_t)sv * st + 0x20000000) >> 30);
+
+ sv = (int)(((int64_t)cv * st + (int64_t)sv * ct + 0x20000000) >> 30);
+ cv = idx;
+
+ idx = a >> 11;
+
+ ct = (int)(((int64_t)av_costbl_4_sf[idx & 0x1f] * (0x800 - (a & 0x7ff)) +
+ (int64_t)av_costbl_4_sf[(idx & 0x1f)+1]*(a & 0x7ff) +
+ 0x400) >> 11);
+ st = (int)(((int64_t)av_sintbl_4_sf[idx & 0x1f] * (0x800 - (a & 0x7ff)) +
+ (int64_t)av_sintbl_4_sf[(idx & 0x1f) + 1] * (a & 0x7ff) +
+ 0x400) >> 11);
+
+ *c = (int)(((int64_t)cv * ct + (int64_t)sv * st + 0x20000000) >> 30);
+
+ *s = (int)(((int64_t)cv * st + (int64_t)sv * ct + 0x20000000) >> 30);
+}
+
+#endif /* AVUTIL_SOFTFLOAT_H */
diff --git a/libavutil/softfloat_tables.h b/libavutil/softfloat_tables.h
new file mode 100644
index 0000000000..461f2b221d
--- /dev/null
+++ b/libavutil/softfloat_tables.h
@@ -0,0 +1,262 @@
+/*
+ * 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 is
+ * 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: Stanislav Ocovaj (stanislav.ocovaj imgtec com)
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef AVUTIL_SOFTFLOAT_TABLES_H
+#define AVUTIL_SOFTFLOAT_TABLES_H
+
+#include <stdint.h>
+
+static const int32_t av_sqrttbl_sf[512+1] = { /* sqrt(x), 0.5<=x<1 */
+ 0x2d413ccd,0x2d4c8bb3,0x2d57d7c6,0x2d63210a,
+ 0x2d6e677f,0x2d79ab2a,0x2d84ec0b,0x2d902a23,
+ 0x2d9b6578,0x2da69e08,0x2db1d3d6,0x2dbd06e6,
+ 0x2dc83738,0x2dd364ce,0x2dde8fac,0x2de9b7d2,
+ 0x2df4dd43,0x2e000000,0x2e0b200c,0x2e163d68,
+ 0x2e215816,0x2e2c701a,0x2e378573,0x2e429824,
+ 0x2e4da830,0x2e58b598,0x2e63c05d,0x2e6ec883,
+ 0x2e79ce0a,0x2e84d0f5,0x2e8fd144,0x2e9acefb,
+ 0x2ea5ca1b,0x2eb0c2a7,0x2ebbb89e,0x2ec6ac04,
+ 0x2ed19cda,0x2edc8b23,0x2ee776df,0x2ef26012,
+ 0x2efd46bb,0x2f082add,0x2f130c7b,0x2f1deb95,
+ 0x2f28c82e,0x2f33a246,0x2f3e79e1,0x2f494eff,
+ 0x2f5421a3,0x2f5ef1ce,0x2f69bf81,0x2f748abe,
+ 0x2f7f5388,0x2f8a19e0,0x2f94ddc7,0x2f9f9f3e,
+ 0x2faa5e48,0x2fb51ae8,0x2fbfd51c,0x2fca8ce9,
+ 0x2fd5424e,0x2fdff54e,0x2feaa5eb,0x2ff55426,
+ 0x30000000,0x300aa97b,0x3015509a,0x301ff55c,
+ 0x302a97c5,0x303537d5,0x303fd58e,0x304a70f2,
+ 0x30550a01,0x305fa0be,0x306a352a,0x3074c747,
+ 0x307f5716,0x3089e499,0x30946fd2,0x309ef8c0,
+ 0x30a97f67,0x30b403c7,0x30be85e2,0x30c905bb,
+ 0x30d38351,0x30ddfea6,0x30e877bc,0x30f2ee96,
+ 0x30fd6332,0x3107d594,0x311245bc,0x311cb3ad,
+ 0x31271f67,0x313188ec,0x313bf03d,0x3146555c,
+ 0x3150b84a,0x315b1909,0x31657798,0x316fd3fc,
+ 0x317a2e34,0x31848642,0x318edc28,0x31992fe5,
+ 0x31a3817d,0x31add0f0,0x31b81e40,0x31c2696e,
+ 0x31ccb27b,0x31d6f969,0x31e13e38,0x31eb80eb,
+ 0x31f5c182,0x32000000,0x320a3c65,0x321476b1,
+ 0x321eaee8,0x3228e50a,0x32331917,0x323d4b13,
+ 0x32477afc,0x3251a8d6,0x325bd4a2,0x3265fe5f,
+ 0x32702611,0x327a4bb8,0x32846f55,0x328e90e9,
+ 0x3298b076,0x32a2cdfd,0x32ace97e,0x32b702fd,
+ 0x32c11a79,0x32cb2ff3,0x32d5436d,0x32df54e9,
+ 0x32e96466,0x32f371e8,0x32fd7d6d,0x330786f9,
+ 0x33118e8c,0x331b9426,0x332597cb,0x332f9979,
+ 0x33399933,0x334396fa,0x334d92cf,0x33578cb2,
+ 0x336184a6,0x336b7aab,0x33756ec3,0x337f60ed,
+ 0x3389512d,0x33933f83,0x339d2bef,0x33a71672,
+ 0x33b0ff10,0x33bae5c7,0x33c4ca99,0x33cead88,
+ 0x33d88e95,0x33e26dbf,0x33ec4b09,0x33f62673,
+ 0x34000000,0x3409d7af,0x3413ad82,0x341d817a,
+ 0x34275397,0x343123db,0x343af248,0x3444bedd,
+ 0x344e899d,0x34585288,0x3462199f,0x346bdee3,
+ 0x3475a254,0x347f63f5,0x348923c6,0x3492e1c9,
+ 0x349c9dfe,0x34a65865,0x34b01101,0x34b9c7d2,
+ 0x34c37cda,0x34cd3018,0x34d6e18f,0x34e0913f,
+ 0x34ea3f29,0x34f3eb4d,0x34fd95ae,0x35073e4c,
+ 0x3510e528,0x351a8a43,0x35242d9d,0x352dcf39,
+ 0x35376f16,0x35410d36,0x354aa99a,0x35544442,
+ 0x355ddd2f,0x35677463,0x357109df,0x357a9da2,
+ 0x35842fb0,0x358dc007,0x35974ea9,0x35a0db98,
+ 0x35aa66d3,0x35b3f05c,0x35bd7833,0x35c6fe5a,
+ 0x35d082d3,0x35da059c,0x35e386b7,0x35ed0626,
+ 0x35f683e8,0x36000000,0x36097a6e,0x3612f331,
+ 0x361c6a4d,0x3625dfc1,0x362f538f,0x3638c5b7,
+ 0x36423639,0x364ba518,0x36551252,0x365e7deb,
+ 0x3667e7e2,0x36715039,0x367ab6f0,0x36841c07,
+ 0x368d7f81,0x3696e15d,0x36a0419d,0x36a9a040,
+ 0x36b2fd49,0x36bc58b8,0x36c5b28e,0x36cf0acb,
+ 0x36d86170,0x36e1b680,0x36eb09f8,0x36f45bdc,
+ 0x36fdac2b,0x3706fae7,0x37104810,0x371993a7,
+ 0x3722ddad,0x372c2622,0x37356d08,0x373eb25f,
+ 0x3747f629,0x37513865,0x375a7914,0x3763b838,
+ 0x376cf5d0,0x377631e0,0x377f6c64,0x3788a561,
+ 0x3791dcd6,0x379b12c4,0x37a4472c,0x37ad7a0e,
+ 0x37b6ab6a,0x37bfdb44,0x37c90999,0x37d2366d,
+ 0x37db61be,0x37e48b8e,0x37edb3de,0x37f6daae,
+ 0x38000000,0x380923d3,0x3812462a,0x381b6703,
+ 0x38248660,0x382da442,0x3836c0aa,0x383fdb97,
+ 0x3848f50c,0x38520d09,0x385b238d,0x3864389b,
+ 0x386d4c33,0x38765e55,0x387f6f01,0x38887e3b,
+ 0x38918c00,0x389a9853,0x38a3a334,0x38acaca3,
+ 0x38b5b4a3,0x38bebb32,0x38c7c051,0x38d0c402,
+ 0x38d9c645,0x38e2c71b,0x38ebc685,0x38f4c482,
+ 0x38fdc114,0x3906bc3c,0x390fb5fa,0x3918ae4f,
+ 0x3921a53a,0x392a9abe,0x39338edb,0x393c8192,
+ 0x394572e2,0x394e62ce,0x39575155,0x39603e77,
+ 0x39692a36,0x39721494,0x397afd8f,0x3983e527,
+ 0x398ccb60,0x3995b039,0x399e93b2,0x39a775cc,
+ 0x39b05689,0x39b935e8,0x39c213e9,0x39caf08e,
+ 0x39d3cbd9,0x39dca5c7,0x39e57e5b,0x39ee5596,
+ 0x39f72b77,0x3a000000,0x3a08d331,0x3a11a50a,
+ 0x3a1a758d,0x3a2344ba,0x3a2c1291,0x3a34df13,
+ 0x3a3daa41,0x3a46741b,0x3a4f3ca3,0x3a5803d7,
+ 0x3a60c9ba,0x3a698e4b,0x3a72518b,0x3a7b137c,
+ 0x3a83d41d,0x3a8c936f,0x3a955173,0x3a9e0e29,
+ 0x3aa6c992,0x3aaf83ae,0x3ab83c7e,0x3ac0f403,
+ 0x3ac9aa3c,0x3ad25f2c,0x3adb12d1,0x3ae3c52d,
+ 0x3aec7642,0x3af5260e,0x3afdd492,0x3b0681d0,
+ 0x3b0f2dc6,0x3b17d878,0x3b2081e4,0x3b292a0c,
+ 0x3b31d0f0,0x3b3a7690,0x3b431aec,0x3b4bbe06,
+ 0x3b545fdf,0x3b5d0077,0x3b659fcd,0x3b6e3de4,
+ 0x3b76daba,0x3b7f7651,0x3b8810aa,0x3b90a9c4,
+ 0x3b9941a1,0x3ba1d842,0x3baa6da5,0x3bb301cd,
+ 0x3bbb94b9,0x3bc4266a,0x3bccb6e2,0x3bd5461f,
+ 0x3bddd423,0x3be660ee,0x3beeec81,0x3bf776dc,
+ 0x3c000000,0x3c0887ed,0x3c110ea4,0x3c199426,
+ 0x3c221872,0x3c2a9b8a,0x3c331d6e,0x3c3b9e1d,
+ 0x3c441d9a,0x3c4c9be5,0x3c5518fd,0x3c5d94e3,
+ 0x3c660f98,0x3c6e891d,0x3c770172,0x3c7f7898,
+ 0x3c87ee8e,0x3c906356,0x3c98d6ef,0x3ca1495b,
+ 0x3ca9ba9a,0x3cb22aac,0x3cba9992,0x3cc3074c,
+ 0x3ccb73dc,0x3cd3df41,0x3cdc497b,0x3ce4b28c,
+ 0x3ced1a73,0x3cf58132,0x3cfde6c8,0x3d064b37,
+ 0x3d0eae7f,0x3d17109f,0x3d1f719a,0x3d27d16e,
+ 0x3d30301d,0x3d388da8,0x3d40ea0d,0x3d49454f,
+ 0x3d519f6d,0x3d59f867,0x3d625040,0x3d6aa6f6,
+ 0x3d72fc8b,0x3d7b50fe,0x3d83a451,0x3d8bf683,
+ 0x3d944796,0x3d9c9788,0x3da4e65c,0x3dad3412,
+ 0x3db580a9,0x3dbdcc24,0x3dc61680,0x3dce5fc0,
+ 0x3dd6a7e4,0x3ddeeeed,0x3de734d9,0x3def79ab,
+ 0x3df7bd62,0x3e000000,0x3e084184,0x3e1081ee,
+ 0x3e18c140,0x3e20ff7a,0x3e293c9c,0x3e3178a7,
+ 0x3e39b39a,0x3e41ed77,0x3e4a263d,0x3e525def,
+ 0x3e5a948b,0x3e62ca12,0x3e6afe85,0x3e7331e4,
+ 0x3e7b642f,0x3e839567,0x3e8bc58c,0x3e93f49f,
+ 0x3e9c22a1,0x3ea44f91,0x3eac7b6f,0x3eb4a63e,
+ 0x3ebccffb,0x3ec4f8aa,0x3ecd2049,0x3ed546d9,
+ 0x3edd6c5a,0x3ee590cd,0x3eedb433,0x3ef5d68c,
+ 0x3efdf7d7,0x3f061816,0x3f0e3749,0x3f165570,
+ 0x3f1e728c,0x3f268e9d,0x3f2ea9a4,0x3f36c3a0,
+ 0x3f3edc93,0x3f46f47c,0x3f4f0b5d,0x3f572135,
+ 0x3f5f3606,0x3f6749cf,0x3f6f5c90,0x3f776e4a,
+ 0x3f7f7efe,0x3f878eab,0x3f8f9d53,0x3f97aaf6,
+ 0x3f9fb793,0x3fa7c32c,0x3fafcdc1,0x3fb7d752,
+ 0x3fbfdfe0,0x3fc7e76b,0x3fcfedf3,0x3fd7f378,
+ 0x3fdff7fc,0x3fe7fb7f,0x3feffe00,0x3ff7ff80,
+ 0x3fffffff,
+};
+
+static const int32_t av_sqr_exp_multbl_sf[2] = {
+ 0x20000000,0x2d413ccd,
+};
+
+static const int32_t av_costbl_1_sf[16] = {
+ 0x40000000,0x3ec52fa0,0x3b20d79e,0x3536cc52,
+ 0x2d413ccd,0x238e7673,0x187de2a7,0x0c7c5c1e,
+ 0x00000000,0xf383a3e3,0xe7821d5a,0xdc71898e,
+ 0xd2bec334,0xcac933af,0xc4df2863,0xc13ad061,
+};
+
+static const int32_t av_costbl_2_sf[32] = {
+ 0x40000000,0x3fffb10b,0x3ffec42d,0x3ffd3969,
+ 0x3ffb10c1,0x3ff84a3c,0x3ff4e5e0,0x3ff0e3b6,
+ 0x3fec43c7,0x3fe7061f,0x3fe12acb,0x3fdab1d9,
+ 0x3fd39b5a,0x3fcbe75e,0x3fc395f9,0x3fbaa740,
+ 0x3fb11b48,0x3fa6f228,0x3f9c2bfb,0x3f90c8da,
+ 0x3f84c8e2,0x3f782c30,0x3f6af2e3,0x3f5d1d1d,
+ 0x3f4eaafe,0x3f3f9cab,0x3f2ff24a,0x3f1fabff,
+ 0x3f0ec9f5,0x3efd4c54,0x3eeb3347,0x3ed87efc,
+};
+
+static const int32_t av_sintbl_2_sf[32] = {
+ 0x00000000,0x006487c4,0x00c90e90,0x012d936c,
+ 0x0192155f,0x01f69373,0x025b0caf,0x02bf801a,
+ 0x0323ecbe,0x038851a2,0x03ecadcf,0x0451004d,
+ 0x04b54825,0x0519845e,0x057db403,0x05e1d61b,
+ 0x0645e9af,0x06a9edc9,0x070de172,0x0771c3b3,
+ 0x07d59396,0x08395024,0x089cf867,0x09008b6a,
+ 0x09640837,0x09c76dd8,0x0a2abb59,0x0a8defc3,
+ 0x0af10a22,0x0b540982,0x0bb6ecef,0x0c19b374,
+};
+
+static const int32_t av_costbl_3_sf[32] = {
+ 0x40000000,0x3fffffec,0x3fffffb1,0x3fffff4e,
+ 0x3ffffec4,0x3ffffe13,0x3ffffd39,0x3ffffc39,
+ 0x3ffffb11,0x3ffff9c1,0x3ffff84a,0x3ffff6ac,
+ 0x3ffff4e6,0x3ffff2f8,0x3ffff0e3,0x3fffeea7,
+ 0x3fffec43,0x3fffe9b7,0x3fffe705,0x3fffe42a,
+ 0x3fffe128,0x3fffddff,0x3fffdaae,0x3fffd736,
+ 0x3fffd396,0x3fffcfcf,0x3fffcbe0,0x3fffc7ca,
+ 0x3fffc38c,0x3fffbf27,0x3fffba9b,0x3fffb5e7,
+};
+
+static const int32_t av_sintbl_3_sf[32] = {
+ 0x00000000,0x0003243f,0x0006487f,0x00096cbe,
+ 0x000c90fe,0x000fb53d,0x0012d97c,0x0015fdbb,
+ 0x001921fb,0x001c463a,0x001f6a79,0x00228eb8,
+ 0x0025b2f7,0x0028d736,0x002bfb74,0x002f1fb3,
+ 0x003243f1,0x00356830,0x00388c6e,0x003bb0ac,
+ 0x003ed4ea,0x0041f928,0x00451d66,0x004841a3,
+ 0x004b65e1,0x004e8a1e,0x0051ae5b,0x0054d297,
+ 0x0057f6d4,0x005b1b10,0x005e3f4c,0x00616388,
+};
+
+static const int32_t av_costbl_4_sf[33] = {
+ 0x40000000,0x40000000,0x40000000,0x40000000,
+ 0x40000000,0x40000000,0x3fffffff,0x3fffffff,
+ 0x3fffffff,0x3ffffffe,0x3ffffffe,0x3ffffffe,
+ 0x3ffffffd,0x3ffffffd,0x3ffffffc,0x3ffffffc,
+ 0x3ffffffb,0x3ffffffa,0x3ffffffa,0x3ffffff9,
+ 0x3ffffff8,0x3ffffff7,0x3ffffff7,0x3ffffff6,
+ 0x3ffffff5,0x3ffffff4,0x3ffffff3,0x3ffffff2,
+ 0x3ffffff1,0x3ffffff0,0x3fffffef,0x3fffffed,
+ 0x3fffffec,
+};
+
+static const int32_t av_sintbl_4_sf[33] = {
+ 0x00000000,0x00001922,0x00003244,0x00004b66,
+ 0x00006488,0x00007daa,0x000096cc,0x0000afee,
+ 0x0000c910,0x0000e232,0x0000fb54,0x00011476,
+ 0x00012d98,0x000146ba,0x00015fdc,0x000178fe,
+ 0x00019220,0x0001ab42,0x0001c464,0x0001dd86,
+ 0x0001f6a8,0x00020fca,0x000228ec,0x0002420e,
+ 0x00025b30,0x00027452,0x00028d74,0x0002a696,
+ 0x0002bfb7,0x0002d8d9,0x0002f1fb,0x00030b1d,
+ 0x0003243f,
+};
+#endif /* AVUTIL_SOFTFLOAT_TABLES_H */
diff --git a/libavutil/stereo3d.c b/libavutil/stereo3d.c
index 2dcfddf14b..50cd928de4 100644
--- a/libavutil/stereo3d.c
+++ b/libavutil/stereo3d.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/stereo3d.h b/libavutil/stereo3d.h
index b1910b1f87..1135dc9ddc 100644
--- a/libavutil/stereo3d.h
+++ b/libavutil/stereo3d.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/thread.h b/libavutil/thread.h
index 35565440f2..297b5b9a52 100644
--- a/libavutil/thread.h
+++ b/libavutil/thread.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,10 +24,14 @@
#include "config.h"
-#if HAVE_PTHREADS || HAVE_W32THREADS
+#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS
+
+#define USE_ATOMICS 0
#if HAVE_PTHREADS
#include <pthread.h>
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
#else
#include "compat/w32pthreads.h"
#endif
@@ -41,6 +45,8 @@
#else
+#define USE_ATOMICS 1
+
#define AVMutex char
#define ff_mutex_init(mutex, attr) (0)
diff --git a/libavutil/threadmessage.c b/libavutil/threadmessage.c
new file mode 100644
index 0000000000..b7fcbe28c0
--- /dev/null
+++ b/libavutil/threadmessage.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2014 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "fifo.h"
+#include "threadmessage.h"
+#if HAVE_THREADS
+#if HAVE_PTHREADS
+#include <pthread.h>
+#elif HAVE_W32THREADS
+#include "compat/w32pthreads.h"
+#elif HAVE_OS2THREADS
+#include "compat/os2threads.h"
+#else
+#error "Unknown threads implementation"
+#endif
+#endif
+
+struct AVThreadMessageQueue {
+#if HAVE_THREADS
+ AVFifoBuffer *fifo;
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ int err_send;
+ int err_recv;
+ unsigned elsize;
+#else
+ int dummy;
+#endif
+};
+
+int av_thread_message_queue_alloc(AVThreadMessageQueue **mq,
+ unsigned nelem,
+ unsigned elsize)
+{
+#if HAVE_THREADS
+ AVThreadMessageQueue *rmq;
+ int ret = 0;
+
+ if (nelem > INT_MAX / elsize)
+ return AVERROR(EINVAL);
+ if (!(rmq = av_mallocz(sizeof(*rmq))))
+ return AVERROR(ENOMEM);
+ if ((ret = pthread_mutex_init(&rmq->lock, NULL))) {
+ av_free(rmq);
+ return AVERROR(ret);
+ }
+ if ((ret = pthread_cond_init(&rmq->cond, NULL))) {
+ pthread_mutex_destroy(&rmq->lock);
+ av_free(rmq);
+ return AVERROR(ret);
+ }
+ if (!(rmq->fifo = av_fifo_alloc(elsize * nelem))) {
+ pthread_cond_destroy(&rmq->cond);
+ pthread_mutex_destroy(&rmq->lock);
+ av_free(rmq);
+ return AVERROR(ret);
+ }
+ rmq->elsize = elsize;
+ *mq = rmq;
+ return 0;
+#else
+ *mq = NULL;
+ return AVERROR(ENOSYS);
+#endif /* HAVE_THREADS */
+}
+
+void av_thread_message_queue_free(AVThreadMessageQueue **mq)
+{
+#if HAVE_THREADS
+ if (*mq) {
+ av_fifo_freep(&(*mq)->fifo);
+ pthread_cond_destroy(&(*mq)->cond);
+ pthread_mutex_destroy(&(*mq)->lock);
+ av_freep(mq);
+ }
+#endif
+}
+
+#if HAVE_THREADS
+
+static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags)
+{
+ while (!mq->err_send && av_fifo_space(mq->fifo) < mq->elsize) {
+ if ((flags & AV_THREAD_MESSAGE_NONBLOCK))
+ return AVERROR(EAGAIN);
+ pthread_cond_wait(&mq->cond, &mq->lock);
+ }
+ if (mq->err_send)
+ return mq->err_send;
+ av_fifo_generic_write(mq->fifo, msg, mq->elsize, NULL);
+ pthread_cond_signal(&mq->cond);
+ return 0;
+}
+
+static int av_thread_message_queue_recv_locked(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags)
+{
+ while (!mq->err_recv && av_fifo_size(mq->fifo) < mq->elsize) {
+ if ((flags & AV_THREAD_MESSAGE_NONBLOCK))
+ return AVERROR(EAGAIN);
+ pthread_cond_wait(&mq->cond, &mq->lock);
+ }
+ if (av_fifo_size(mq->fifo) < mq->elsize)
+ return mq->err_recv;
+ av_fifo_generic_read(mq->fifo, msg, mq->elsize, NULL);
+ pthread_cond_signal(&mq->cond);
+ return 0;
+}
+
+#endif /* HAVE_THREADS */
+
+int av_thread_message_queue_send(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags)
+{
+#if HAVE_THREADS
+ int ret;
+
+ pthread_mutex_lock(&mq->lock);
+ ret = av_thread_message_queue_send_locked(mq, msg, flags);
+ pthread_mutex_unlock(&mq->lock);
+ return ret;
+#else
+ return AVERROR(ENOSYS);
+#endif /* HAVE_THREADS */
+}
+
+int av_thread_message_queue_recv(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags)
+{
+#if HAVE_THREADS
+ int ret;
+
+ pthread_mutex_lock(&mq->lock);
+ ret = av_thread_message_queue_recv_locked(mq, msg, flags);
+ pthread_mutex_unlock(&mq->lock);
+ return ret;
+#else
+ return AVERROR(ENOSYS);
+#endif /* HAVE_THREADS */
+}
+
+void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
+ int err)
+{
+#if HAVE_THREADS
+ pthread_mutex_lock(&mq->lock);
+ mq->err_send = err;
+ pthread_cond_broadcast(&mq->cond);
+ pthread_mutex_unlock(&mq->lock);
+#endif /* HAVE_THREADS */
+}
+
+void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq,
+ int err)
+{
+#if HAVE_THREADS
+ pthread_mutex_lock(&mq->lock);
+ mq->err_recv = err;
+ pthread_cond_broadcast(&mq->cond);
+ pthread_mutex_unlock(&mq->lock);
+#endif /* HAVE_THREADS */
+}
diff --git a/libavutil/threadmessage.h b/libavutil/threadmessage.h
new file mode 100644
index 0000000000..a8481d8ec3
--- /dev/null
+++ b/libavutil/threadmessage.h
@@ -0,0 +1,91 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_THREADMESSAGE_H
+#define AVUTIL_THREADMESSAGE_H
+
+typedef struct AVThreadMessageQueue AVThreadMessageQueue;
+
+typedef enum AVThreadMessageFlags {
+
+ /**
+ * Perform non-blocking operation.
+ * If this flag is set, send and recv operations are non-blocking and
+ * return AVERROR(EAGAIN) immediately if they can not proceed.
+ */
+ AV_THREAD_MESSAGE_NONBLOCK = 1,
+
+} AVThreadMessageFlags;
+
+/**
+ * Allocate a new message queue.
+ *
+ * @param mq pointer to the message queue
+ * @param nelem maximum number of elements in the queue
+ * @param elsize size of each element in the queue
+ * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if
+ * lavu was built without thread support
+ */
+int av_thread_message_queue_alloc(AVThreadMessageQueue **mq,
+ unsigned nelem,
+ unsigned elsize);
+
+/**
+ * Free a message queue.
+ *
+ * The message queue must no longer be in use by another thread.
+ */
+void av_thread_message_queue_free(AVThreadMessageQueue **mq);
+
+/**
+ * Send a message on the queue.
+ */
+int av_thread_message_queue_send(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags);
+
+/**
+ * Receive a message from the queue.
+ */
+int av_thread_message_queue_recv(AVThreadMessageQueue *mq,
+ void *msg,
+ unsigned flags);
+
+/**
+ * Set the sending error code.
+ *
+ * If the error code is set to non-zero, av_thread_message_queue_recv() will
+ * return it immediately when there are no longer available messages.
+ * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used
+ * to cause the receiving thread to stop or suspend its operation.
+ */
+void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq,
+ int err);
+
+/**
+ * Set the receiving error code.
+ *
+ * If the error code is set to non-zero, av_thread_message_queue_send() will
+ * return it immediately. Conventional values, such as AVERROR_EOF or
+ * AVERROR(EAGAIN), can be used to cause the sending thread to stop or
+ * suspend its operation.
+ */
+void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq,
+ int err);
+
+#endif /* AVUTIL_THREADMESSAGE_H */
diff --git a/libavutil/time.c b/libavutil/time.c
index 7a3604e651..dbaee0264c 100644
--- a/libavutil/time.c
+++ b/libavutil/time.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2000-2003 Fabrice Bellard
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,9 +23,6 @@
#include <stddef.h>
#include <stdint.h>
#include <time.h>
-#if HAVE_CLOCK_GETTIME
-#include <time.h>
-#endif
#if HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif
@@ -56,7 +55,7 @@ int64_t av_gettime(void)
int64_t av_gettime_relative(void)
{
-#if HAVE_CLOCK_GETTIME
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
@@ -65,6 +64,15 @@ int64_t av_gettime_relative(void)
#endif
}
+int av_gettime_relative_is_monotonic(void)
+{
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
int av_usleep(unsigned usec)
{
#if HAVE_NANOSLEEP
diff --git a/libavutil/time.h b/libavutil/time.h
index 463bcfcdcf..dc169b064a 100644
--- a/libavutil/time.h
+++ b/libavutil/time.h
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * Copyright (c) 2000-2003 Fabrice Bellard
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -36,6 +38,12 @@ int64_t av_gettime(void);
int64_t av_gettime_relative(void);
/**
+ * Indicates with a boolean result if the av_gettime_relative() time source
+ * is monotonic.
+ */
+int av_gettime_relative_is_monotonic(void);
+
+/**
* Sleep for a period of time. Although the duration is expressed in
* microseconds, the actual delay may be rounded to the precision of the
* system timer.
diff --git a/libavutil/time_internal.h b/libavutil/time_internal.h
index 829fefb007..612a75a041 100644
--- a/libavutil/time_internal.h
+++ b/libavutil/time_internal.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,7 +22,7 @@
#include <time.h>
#include "config.h"
-#if !HAVE_GMTIME_R
+#if !HAVE_GMTIME_R && !defined(gmtime_r)
static inline struct tm *gmtime_r(const time_t* clock, struct tm *result)
{
struct tm *ptr = gmtime(clock);
@@ -33,7 +33,7 @@ static inline struct tm *gmtime_r(const time_t* clock, struct tm *result)
}
#endif
-#if !HAVE_LOCALTIME_R
+#if !HAVE_LOCALTIME_R && !defined(localtime_r)
static inline struct tm *localtime_r(const time_t* clock, struct tm *result)
{
struct tm *ptr = localtime(clock);
diff --git a/libavutil/timecode.c b/libavutil/timecode.c
new file mode 100644
index 0000000000..1dfd040868
--- /dev/null
+++ b/libavutil/timecode.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com>
+ * Copyright (c) 2011-2012 Smartjog S.A.S, ClĂ©ment BÅ“sch <clement.boesch@smartjog.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
+ * Timecode helpers
+ * @see https://en.wikipedia.org/wiki/SMPTE_time_code
+ * @see http://www.dropframetimecode.org
+ */
+
+#include <stdio.h>
+#include "timecode.h"
+#include "log.h"
+#include "error.h"
+
+int av_timecode_adjust_ntsc_framenum2(int framenum, int fps)
+{
+ /* only works for NTSC 29.97 and 59.94 */
+ int drop_frames = 0;
+ int d, m, frames_per_10mins;
+
+ if (fps == 30) {
+ drop_frames = 2;
+ frames_per_10mins = 17982;
+ } else if (fps == 60) {
+ drop_frames = 4;
+ frames_per_10mins = 35964;
+ } else
+ return framenum;
+
+ d = framenum / frames_per_10mins;
+ m = framenum % frames_per_10mins;
+
+ return framenum + 9 * drop_frames * d + drop_frames * ((m - drop_frames) / (frames_per_10mins / 10));
+}
+
+uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum)
+{
+ unsigned fps = tc->fps;
+ int drop = !!(tc->flags & AV_TIMECODE_FLAG_DROPFRAME);
+ int hh, mm, ss, ff;
+
+ framenum += tc->start;
+ if (drop)
+ 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;
+ return 0 << 31 | // color frame flag (0: unsync mode, 1: sync mode)
+ drop << 30 | // drop frame flag (0: non drop, 1: drop)
+ (ff / 10) << 28 | // tens of frames
+ (ff % 10) << 24 | // units of frames
+ 0 << 23 | // PC (NTSC) or BGF0 (PAL)
+ (ss / 10) << 20 | // tens of seconds
+ (ss % 10) << 16 | // units of seconds
+ 0 << 15 | // BGF0 (NTSC) or BGF2 (PAL)
+ (mm / 10) << 12 | // tens of minutes
+ (mm % 10) << 8 | // units of minutes
+ 0 << 7 | // BGF2 (NTSC) or PC (PAL)
+ 0 << 6 | // BGF1
+ (hh / 10) << 4 | // tens of hours
+ (hh % 10); // units of hours
+}
+
+char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
+{
+ int fps = tc->fps;
+ int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME;
+ int hh, mm, ss, ff, neg = 0;
+
+ framenum += tc->start;
+ if (drop)
+ framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps);
+ if (framenum < 0) {
+ framenum = -framenum;
+ neg = tc->flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE;
+ }
+ ff = framenum % fps;
+ ss = framenum / fps % 60;
+ mm = framenum / (fps*60) % 60;
+ hh = framenum / (fps*3600);
+ if (tc->flags & AV_TIMECODE_FLAG_24HOURSMAX)
+ hh = hh % 24;
+ snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%02d",
+ neg ? "-" : "",
+ hh, mm, ss, drop ? ';' : ':', ff);
+ return buf;
+}
+
+static unsigned bcd2uint(uint8_t bcd)
+{
+ unsigned low = bcd & 0xf;
+ unsigned high = bcd >> 4;
+ if (low > 9 || high > 9)
+ return 0;
+ return low + 10*high;
+}
+
+char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df)
+{
+ unsigned hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours
+ unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes
+ unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds
+ unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames
+ unsigned drop = tcsmpte & 1<<30 && !prevent_df; // 1-bit drop if not arbitrary bit
+ snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u",
+ hh, mm, ss, drop ? ';' : ':', ff);
+ return buf;
+}
+
+char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
+{
+ snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u",
+ tc25bit>>19 & 0x1f, // 5-bit hours
+ tc25bit>>13 & 0x3f, // 6-bit minutes
+ tc25bit>>6 & 0x3f, // 6-bit seconds
+ tc25bit & 1<<24 ? ';' : ':', // 1-bit drop flag
+ tc25bit & 0x3f); // 6-bit frames
+ return buf;
+}
+
+static int check_fps(int fps)
+{
+ int i;
+ static const int supported_fps[] = {24, 25, 30, 48, 50, 60};
+
+ for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++)
+ if (fps == supported_fps[i])
+ return 0;
+ return -1;
+}
+
+static int check_timecode(void *log_ctx, AVTimecode *tc)
+{
+ if (tc->fps <= 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate must be specified\n");
+ return AVERROR(EINVAL);
+ }
+ if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps != 30 && tc->fps != 60) {
+ av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 or 60000/1001 FPS\n");
+ return AVERROR(EINVAL);
+ }
+ if (check_fps(tc->fps) < 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate %d/%d not supported\n",
+ tc->rate.num, tc->rate.den);
+ return AVERROR_PATCHWELCOME;
+ }
+ return 0;
+}
+
+static int fps_from_frame_rate(AVRational rate)
+{
+ if (!rate.den || !rate.num)
+ return -1;
+ return (rate.num + rate.den/2) / rate.den;
+}
+
+int av_timecode_check_frame_rate(AVRational rate)
+{
+ return check_fps(fps_from_frame_rate(rate));
+}
+
+int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
+{
+ memset(tc, 0, sizeof(*tc));
+ tc->start = frame_start;
+ tc->flags = flags;
+ tc->rate = rate;
+ tc->fps = fps_from_frame_rate(rate);
+ return check_timecode(log_ctx, tc);
+}
+
+int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
+{
+ char c;
+ int hh, mm, ss, ff, ret;
+
+ if (sscanf(str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) {
+ av_log(log_ctx, AV_LOG_ERROR, "Unable to parse timecode, "
+ "syntax: hh:mm:ss[:;.]ff\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ memset(tc, 0, sizeof(*tc));
+ tc->flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0; // drop if ';', '.', ...
+ tc->rate = rate;
+ tc->fps = fps_from_frame_rate(rate);
+
+ ret = check_timecode(log_ctx, tc);
+ if (ret < 0)
+ return ret;
+
+ tc->start = (hh*3600 + mm*60 + ss) * tc->fps + ff;
+ if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) { /* adjust frame number */
+ int tmins = 60*hh + mm;
+ tc->start -= 2 * (tmins - tmins/10);
+ }
+ return 0;
+}
diff --git a/libavutil/timecode.h b/libavutil/timecode.h
new file mode 100644
index 0000000000..56e3975fd8
--- /dev/null
+++ b/libavutil/timecode.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com>
+ * Copyright (c) 2011-2012 Smartjog S.A.S, ClĂ©ment BÅ“sch <clement.boesch@smartjog.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
+ * Timecode helpers header
+ */
+
+#ifndef AVUTIL_TIMECODE_H
+#define AVUTIL_TIMECODE_H
+
+#include <stdint.h>
+#include "rational.h"
+
+#define AV_TIMECODE_STR_SIZE 16
+
+enum AVTimecodeFlag {
+ AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame
+ AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours
+ AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed
+};
+
+typedef struct {
+ int start; ///< timecode frame start (first base frame number)
+ uint32_t flags; ///< flags such as drop frame, +24 hours support, ...
+ AVRational rate; ///< frame rate in rational form
+ unsigned fps; ///< frame per second; must be consistent with the rate field
+} AVTimecode;
+
+/**
+ * Adjust frame number for NTSC drop frame time code.
+ *
+ * @param framenum frame number to adjust
+ * @param fps frame per second, 30 or 60
+ * @return adjusted frame number
+ * @warning adjustment is only valid in NTSC 29.97 and 59.94
+ */
+int av_timecode_adjust_ntsc_framenum2(int framenum, int fps);
+
+/**
+ * Convert frame number to SMPTE 12M binary representation.
+ *
+ * @param tc timecode data correctly initialized
+ * @param framenum frame number
+ * @return the SMPTE binary representation
+ *
+ * @note Frame number adjustment is automatically done in case of drop timecode,
+ * you do NOT have to call av_timecode_adjust_ntsc_framenum2().
+ * @note The frame number is relative to tc->start.
+ * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity
+ * correction (PC) bits are set to zero.
+ */
+uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum);
+
+/**
+ * Load timecode string in buf.
+ *
+ * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long
+ * @param tc timecode data correctly initialized
+ * @param framenum frame number
+ * @return the buf parameter
+ *
+ * @note Timecode representation can be a negative timecode and have more than
+ * 24 hours, but will only be honored if the flags are correctly set.
+ * @note The frame number is relative to tc->start.
+ */
+char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum);
+
+/**
+ * Get the timecode string from the SMPTE timecode format.
+ *
+ * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long
+ * @param tcsmpte the 32-bit SMPTE timecode
+ * @param prevent_df prevent the use of a drop flag when it is known the DF bit
+ * is arbitrary
+ * @return the buf parameter
+ */
+char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df);
+
+/**
+ * Get the timecode string from the 25-bit timecode format (MPEG GOP format).
+ *
+ * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long
+ * @param tc25bit the 25-bits timecode
+ * @return the buf parameter
+ */
+char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit);
+
+/**
+ * Init a timecode struct with the passed parameters.
+ *
+ * @param log_ctx a pointer to an arbitrary struct of which the first field
+ * is a pointer to an AVClass struct (used for av_log)
+ * @param tc pointer to an allocated AVTimecode
+ * @param rate frame rate in rational form
+ * @param flags miscellaneous flags such as drop frame, +24 hours, ...
+ * (see AVTimecodeFlag)
+ * @param frame_start the first frame number
+ * @return 0 on success, AVERROR otherwise
+ */
+int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx);
+
+/**
+ * Parse timecode representation (hh:mm:ss[:;.]ff).
+ *
+ * @param log_ctx a pointer to an arbitrary struct of which the first field is a
+ * pointer to an AVClass struct (used for av_log).
+ * @param tc pointer to an allocated AVTimecode
+ * @param rate frame rate in rational form
+ * @param str timecode string which will determine the frame start
+ * @return 0 on success, AVERROR otherwise
+ */
+int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx);
+
+/**
+ * Check if the timecode feature is available for the given frame rate
+ *
+ * @return 0 if supported, <0 otherwise
+ */
+int av_timecode_check_frame_rate(AVRational rate);
+
+#endif /* AVUTIL_TIMECODE_H */
diff --git a/libavutil/timer.h b/libavutil/timer.h
index 0d93d7c0ef..e21f6552bd 100644
--- a/libavutil/timer.h
+++ b/libavutil/timer.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -40,8 +40,6 @@
#if ARCH_ARM
# include "arm/timer.h"
-#elif ARCH_BFIN
-# include "bfin/timer.h"
#elif ARCH_PPC
# include "ppc/timer.h"
#elif ARCH_X86
@@ -56,6 +54,10 @@
# endif
#endif
+#ifndef FF_TIMER_UNITS
+# define FF_TIMER_UNITS "UNITS"
+#endif
+
#ifdef AV_READ_TIME
#define START_TIMER \
uint64_t tend; \
@@ -67,6 +69,8 @@
static uint64_t tsum = 0; \
static int tcount = 0; \
static int tskip_count = 0; \
+ static int thistogram[32] = {0}; \
+ thistogram[av_log2(tend - tstart)]++; \
if (tcount < 2 || \
tend - tstart < 8 * tsum / tcount || \
tend - tstart < 2000) { \
@@ -75,9 +79,13 @@
} else \
tskip_count++; \
if (((tcount + tskip_count) & (tcount + tskip_count - 1)) == 0) { \
+ int i; \
av_log(NULL, AV_LOG_ERROR, \
- "%"PRIu64" UNITS in %s, %d runs, %d skips\n", \
+ "%7"PRIu64" " FF_TIMER_UNITS " in %s,%8d runs,%7d skips", \
tsum * 10 / tcount, id, tcount, tskip_count); \
+ for (i = 0; i < 32; i++) \
+ av_log(NULL, AV_LOG_VERBOSE, " %2d", av_log2(2*thistogram[i]));\
+ av_log(NULL, AV_LOG_ERROR, "\n"); \
} \
}
#else
diff --git a/libavutil/timestamp.h b/libavutil/timestamp.h
new file mode 100644
index 0000000000..f010a7ee38
--- /dev/null
+++ b/libavutil/timestamp.h
@@ -0,0 +1,78 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * timestamp utils, mostly useful for debugging/logging purposes
+ */
+
+#ifndef AVUTIL_TIMESTAMP_H
+#define AVUTIL_TIMESTAMP_H
+
+#include "common.h"
+
+#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64)
+#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS
+#endif
+
+#define AV_TS_MAX_STRING_SIZE 32
+
+/**
+ * Fill the provided buffer with a string containing a timestamp
+ * representation.
+ *
+ * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE
+ * @param ts the timestamp to represent
+ * @return the buffer in input
+ */
+static inline char *av_ts_make_string(char *buf, int64_t ts)
+{
+ if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS");
+ else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%"PRId64, ts);
+ return buf;
+}
+
+/**
+ * Convenience macro, the return value should be used only directly in
+ * function arguments but never stand-alone.
+ */
+#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts)
+
+/**
+ * Fill the provided buffer with a string containing a timestamp time
+ * representation.
+ *
+ * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE
+ * @param ts the timestamp to represent
+ * @param tb the timebase of the timestamp
+ * @return the buffer in input
+ */
+static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb)
+{
+ if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS");
+ else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts);
+ return buf;
+}
+
+/**
+ * Convenience macro, the return value should be used only directly in
+ * function arguments but never stand-alone.
+ */
+#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb)
+
+#endif /* AVUTIL_TIMESTAMP_H */
diff --git a/libavutil/tomi/intreadwrite.h b/libavutil/tomi/intreadwrite.h
index baf592a7e1..7dec4158d3 100644
--- a/libavutil/tomi/intreadwrite.h
+++ b/libavutil/tomi/intreadwrite.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Mans Rullgard <mans@mansr.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/tree.c b/libavutil/tree.c
index d48d01af5b..d0b67efc5d 100644
--- a/libavutil/tree.c
+++ b/libavutil/tree.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,9 +29,7 @@ typedef struct AVTreeNode {
int state;
} AVTreeNode;
-#if FF_API_CONTEXT_SIZE
const int av_tree_node_size = sizeof(AVTreeNode);
-#endif
struct AVTreeNode *av_tree_node_alloc(void)
{
@@ -209,29 +207,27 @@ static int cmp(void *a, const void *b)
return (uint8_t *) a - (const uint8_t *) b;
}
-int main(void)
+int main(int argc, char **argv)
{
int i;
+ void *k;
AVTreeNode *root = NULL, *node = NULL;
AVLFG prng;
+ int log_level = argc <= 1 ? AV_LOG_INFO : atoi(argv[1]);
+
+ av_log_set_level(log_level);
av_lfg_init(&prng, 1);
for (i = 0; i < 10000; i++) {
- AVTreeNode *node2 = NULL;
intptr_t j = av_lfg_get(&prng) % 86294;
- void *ret, *jj = (void *)(j + 1);
-
- while (ret = av_tree_find(root, jj, cmp, NULL)) {
- j = av_lfg_get(&prng) % 86294;
- jj = (void *)(j + 1);
- }
if (check(root) > 999) {
av_log(NULL, AV_LOG_ERROR, "FATAL error %d\n", i);
print(root, 0);
return 1;
}
+ av_log(NULL, AV_LOG_DEBUG, "inserting %4d\n", (int)j);
if (!node)
node = av_tree_node_alloc();
@@ -239,20 +235,20 @@ int main(void)
av_log(NULL, AV_LOG_ERROR, "Memory allocation failure.\n");
return 1;
}
- av_tree_insert(&root, jj, cmp, &node);
+ av_tree_insert(&root, (void *)(j + 1), cmp, &node);
- while (ret = av_tree_find(root, jj, cmp, NULL)) {
- j = av_lfg_get(&prng) % 86294;
- jj = (void *)(j + 1);
+ j = av_lfg_get(&prng) % 86294;
+ {
+ AVTreeNode *node2 = NULL;
+ av_log(NULL, AV_LOG_DEBUG, "removing %4d\n", (int)j);
+ av_tree_insert(&root, (void *)(j + 1), cmp, &node2);
+ k = av_tree_find(root, (void *)(j + 1), cmp, NULL);
+ if (k)
+ av_log(NULL, AV_LOG_ERROR, "removal failure %d\n", i);
+ av_free(node2);
}
-
- ret = av_tree_insert(&root, jj, cmp, &node2);
- if (ret != jj)
- av_tree_destroy(node2);
- ret = av_tree_find(root, jj, cmp, NULL);
- if (ret)
- av_log(NULL, AV_LOG_ERROR, "removal failure %d\n", i);
}
+ av_free(node);
av_tree_destroy(root);
diff --git a/libavutil/tree.h b/libavutil/tree.h
index 424656e06a..a14fa9156a 100644
--- a/libavutil/tree.h
+++ b/libavutil/tree.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -43,9 +43,7 @@
struct AVTreeNode;
-#if FF_API_CONTEXT_SIZE
-extern attribute_deprecated const int av_tree_node_size;
-#endif
+extern const int av_tree_node_size;
/**
* Allocate an AVTreeNode.
@@ -66,18 +64,21 @@ void *av_tree_find(const struct AVTreeNode *root, void *key,
/**
* Insert or remove an element.
+ *
* If *next is NULL, then the supplied element will be removed if it exists.
- * If *next is not NULL, then the supplied element will be inserted, unless
+ * If *next is non-NULL, then the supplied element will be inserted, unless
* it already exists in the tree.
+ *
* @param rootp A pointer to a pointer to the root node of the tree; note that
* the root node can change during insertions, this is required
* to keep the tree balanced.
+ * @param key pointer to the element key to insert in the tree
* @param next Used to allocate and free AVTreeNodes. For insertion the user
* must set it to an allocated and zeroed object of at least
* av_tree_node_size bytes size. av_tree_insert() will set it to
* NULL if it has been consumed.
* For deleting elements *next is set to NULL by the user and
- * av_tree_node_size() will set it to the AVTreeNode which was
+ * av_tree_insert() will set it to the AVTreeNode which was
* used for the removed element.
* This allows the use of flat arrays, which have
* lower overhead compared to many malloced elements.
@@ -98,6 +99,7 @@ void *av_tree_find(const struct AVTreeNode *root, void *key,
* return av_tree_insert(rootp, key, cmp, next);
* }
* @endcode
+ * @param cmp compare function used to compare elements in the tree
* @return If no insertion happened, the found element; if an insertion or
* removal happened, then either key or NULL will be returned.
* Which one it is depends on the tree state and the implementation. You
diff --git a/libavutil/twofish.c b/libavutil/twofish.c
new file mode 100644
index 0000000000..f735a1fb14
--- /dev/null
+++ b/libavutil/twofish.c
@@ -0,0 +1,405 @@
+/*
+ * An implementation of the TwoFish algorithm
+ * Copyright (c) 2015 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "twofish.h"
+#include "common.h"
+#include "intreadwrite.h"
+#include "attributes.h"
+
+#define LR(x, n) ((x) << (n) | (x) >> (32 - (n)))
+#define RR(x, n) ((x) >> (n) | (x) << (32 - (n)))
+
+typedef struct AVTWOFISH {
+ uint32_t K[40];
+ uint32_t S[4];
+ int ksize;
+ uint32_t MDS1[256];
+ uint32_t MDS2[256];
+ uint32_t MDS3[256];
+ uint32_t MDS4[256];
+} AVTWOFISH;
+
+static const uint8_t MD1[256] = {
+ 0x00, 0x5b, 0xb6, 0xed, 0x05, 0x5e, 0xb3, 0xe8, 0x0a, 0x51, 0xbc, 0xe7, 0x0f, 0x54, 0xb9, 0xe2,
+ 0x14, 0x4f, 0xa2, 0xf9, 0x11, 0x4a, 0xa7, 0xfc, 0x1e, 0x45, 0xa8, 0xf3, 0x1b, 0x40, 0xad, 0xf6,
+ 0x28, 0x73, 0x9e, 0xc5, 0x2d, 0x76, 0x9b, 0xc0, 0x22, 0x79, 0x94, 0xcf, 0x27, 0x7c, 0x91, 0xca,
+ 0x3c, 0x67, 0x8a, 0xd1, 0x39, 0x62, 0x8f, 0xd4, 0x36, 0x6d, 0x80, 0xdb, 0x33, 0x68, 0x85, 0xde,
+ 0x50, 0x0b, 0xe6, 0xbd, 0x55, 0x0e, 0xe3, 0xb8, 0x5a, 0x01, 0xec, 0xb7, 0x5f, 0x04, 0xe9, 0xb2,
+ 0x44, 0x1f, 0xf2, 0xa9, 0x41, 0x1a, 0xf7, 0xac, 0x4e, 0x15, 0xf8, 0xa3, 0x4b, 0x10, 0xfd, 0xa6,
+ 0x78, 0x23, 0xce, 0x95, 0x7d, 0x26, 0xcb, 0x90, 0x72, 0x29, 0xc4, 0x9f, 0x77, 0x2c, 0xc1, 0x9a,
+ 0x6c, 0x37, 0xda, 0x81, 0x69, 0x32, 0xdf, 0x84, 0x66, 0x3d, 0xd0, 0x8b, 0x63, 0x38, 0xd5, 0x8e,
+ 0xa0, 0xfb, 0x16, 0x4d, 0xa5, 0xfe, 0x13, 0x48, 0xaa, 0xf1, 0x1c, 0x47, 0xaf, 0xf4, 0x19, 0x42,
+ 0xb4, 0xef, 0x02, 0x59, 0xb1, 0xea, 0x07, 0x5c, 0xbe, 0xe5, 0x08, 0x53, 0xbb, 0xe0, 0x0d, 0x56,
+ 0x88, 0xd3, 0x3e, 0x65, 0x8d, 0xd6, 0x3b, 0x60, 0x82, 0xd9, 0x34, 0x6f, 0x87, 0xdc, 0x31, 0x6a,
+ 0x9c, 0xc7, 0x2a, 0x71, 0x99, 0xc2, 0x2f, 0x74, 0x96, 0xcd, 0x20, 0x7b, 0x93, 0xc8, 0x25, 0x7e,
+ 0xf0, 0xab, 0x46, 0x1d, 0xf5, 0xae, 0x43, 0x18, 0xfa, 0xa1, 0x4c, 0x17, 0xff, 0xa4, 0x49, 0x12,
+ 0xe4, 0xbf, 0x52, 0x09, 0xe1, 0xba, 0x57, 0x0c, 0xee, 0xb5, 0x58, 0x03, 0xeb, 0xb0, 0x5d, 0x06,
+ 0xd8, 0x83, 0x6e, 0x35, 0xdd, 0x86, 0x6b, 0x30, 0xd2, 0x89, 0x64, 0x3f, 0xd7, 0x8c, 0x61, 0x3a,
+ 0xcc, 0x97, 0x7a, 0x21, 0xc9, 0x92, 0x7f, 0x24, 0xc6, 0x9d, 0x70, 0x2b, 0xc3, 0x98, 0x75, 0x2e
+};
+
+static const uint8_t MD2[256] = {
+ 0x00, 0xef, 0xb7, 0x58, 0x07, 0xe8, 0xb0, 0x5f, 0x0e, 0xe1, 0xb9, 0x56, 0x09, 0xe6, 0xbe, 0x51,
+ 0x1c, 0xf3, 0xab, 0x44, 0x1b, 0xf4, 0xac, 0x43, 0x12, 0xfd, 0xa5, 0x4a, 0x15, 0xfa, 0xa2, 0x4d,
+ 0x38, 0xd7, 0x8f, 0x60, 0x3f, 0xd0, 0x88, 0x67, 0x36, 0xd9, 0x81, 0x6e, 0x31, 0xde, 0x86, 0x69,
+ 0x24, 0xcb, 0x93, 0x7c, 0x23, 0xcc, 0x94, 0x7b, 0x2a, 0xc5, 0x9d, 0x72, 0x2d, 0xc2, 0x9a, 0x75,
+ 0x70, 0x9f, 0xc7, 0x28, 0x77, 0x98, 0xc0, 0x2f, 0x7e, 0x91, 0xc9, 0x26, 0x79, 0x96, 0xce, 0x21,
+ 0x6c, 0x83, 0xdb, 0x34, 0x6b, 0x84, 0xdc, 0x33, 0x62, 0x8d, 0xd5, 0x3a, 0x65, 0x8a, 0xd2, 0x3d,
+ 0x48, 0xa7, 0xff, 0x10, 0x4f, 0xa0, 0xf8, 0x17, 0x46, 0xa9, 0xf1, 0x1e, 0x41, 0xae, 0xf6, 0x19,
+ 0x54, 0xbb, 0xe3, 0x0c, 0x53, 0xbc, 0xe4, 0x0b, 0x5a, 0xb5, 0xed, 0x02, 0x5d, 0xb2, 0xea, 0x05,
+ 0xe0, 0x0f, 0x57, 0xb8, 0xe7, 0x08, 0x50, 0xbf, 0xee, 0x01, 0x59, 0xb6, 0xe9, 0x06, 0x5e, 0xb1,
+ 0xfc, 0x13, 0x4b, 0xa4, 0xfb, 0x14, 0x4c, 0xa3, 0xf2, 0x1d, 0x45, 0xaa, 0xf5, 0x1a, 0x42, 0xad,
+ 0xd8, 0x37, 0x6f, 0x80, 0xdf, 0x30, 0x68, 0x87, 0xd6, 0x39, 0x61, 0x8e, 0xd1, 0x3e, 0x66, 0x89,
+ 0xc4, 0x2b, 0x73, 0x9c, 0xc3, 0x2c, 0x74, 0x9b, 0xca, 0x25, 0x7d, 0x92, 0xcd, 0x22, 0x7a, 0x95,
+ 0x90, 0x7f, 0x27, 0xc8, 0x97, 0x78, 0x20, 0xcf, 0x9e, 0x71, 0x29, 0xc6, 0x99, 0x76, 0x2e, 0xc1,
+ 0x8c, 0x63, 0x3b, 0xd4, 0x8b, 0x64, 0x3c, 0xd3, 0x82, 0x6d, 0x35, 0xda, 0x85, 0x6a, 0x32, 0xdd,
+ 0xa8, 0x47, 0x1f, 0xf0, 0xaf, 0x40, 0x18, 0xf7, 0xa6, 0x49, 0x11, 0xfe, 0xa1, 0x4e, 0x16, 0xf9,
+ 0xb4, 0x5b, 0x03, 0xec, 0xb3, 0x5c, 0x04, 0xeb, 0xba, 0x55, 0x0d, 0xe2, 0xbd, 0x52, 0x0a, 0xe5
+};
+
+static const uint8_t q0[256] = {
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
+ 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
+ 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
+ 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
+ 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
+ 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
+ 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
+ 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
+ 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
+ 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
+ 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
+ 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
+ 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0
+};
+
+static const uint8_t q1[256] = {
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
+ 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
+ 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
+ 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
+ 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
+ 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
+ 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
+ 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
+ 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
+ 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
+ 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
+ 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
+ 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91
+};
+
+struct AVTWOFISH *av_twofish_alloc(void)
+{
+ return av_mallocz(sizeof(struct AVTWOFISH));
+}
+
+const int av_twofish_size = sizeof(AVTWOFISH);
+
+static uint8_t gfmul(uint8_t a, uint8_t b)
+{
+ uint8_t r = 0, t;
+ while (a && b) {
+ if (a & 1)
+ r = r ^ b;
+ t = b & 0x80;
+ b = b << 1;
+ if (t)
+ b = b ^ 0x4d;
+ a = a >> 1;
+ }
+ return r;
+}
+
+static uint32_t tf_RS(uint32_t k0, uint32_t k1)
+{
+ uint8_t s[4], m[8];
+ AV_WL32(m, k0);
+ AV_WL32(m + 4, k1);
+ s[0] = gfmul(0x01, m[0]) ^ gfmul(0xa4, m[1]) ^ gfmul(0x55, m[2]) ^ gfmul(0x87, m[3]) ^ gfmul(0x5a, m[4]) ^ gfmul(0x58, m[5]) ^ gfmul(0xdb, m[6]) ^ gfmul(0x9e, m[7]);
+ s[1] = gfmul(0xa4, m[0]) ^ gfmul(0x56, m[1]) ^ gfmul(0x82, m[2]) ^ gfmul(0xf3, m[3]) ^ gfmul(0x1e, m[4]) ^ gfmul(0xc6, m[5]) ^ gfmul(0x68, m[6]) ^ gfmul(0xe5, m[7]);
+ s[2] = gfmul(0x02, m[0]) ^ gfmul(0xa1, m[1]) ^ gfmul(0xfc, m[2]) ^ gfmul(0xc1, m[3]) ^ gfmul(0x47, m[4]) ^ gfmul(0xae, m[5]) ^ gfmul(0x3d, m[6]) ^ gfmul(0x19, m[7]);
+ s[3] = gfmul(0xa4, m[0]) ^ gfmul(0x55, m[1]) ^ gfmul(0x87, m[2]) ^ gfmul(0x5a, m[3]) ^ gfmul(0x58, m[4]) ^ gfmul(0xdb, m[5]) ^ gfmul(0x9e, m[6]) ^ gfmul(0x03, m[7]);
+ return AV_RL32(s);
+}
+
+static void tf_h0(uint8_t y[4], uint32_t L[4], int k)
+{
+ uint8_t l[4];
+ if (k == 4) {
+ AV_WL32(l, L[3]);
+ y[0] = q1[y[0]] ^ l[0];
+ y[1] = q0[y[1]] ^ l[1];
+ y[2] = q0[y[2]] ^ l[2];
+ y[3] = q1[y[3]] ^ l[3];
+ }
+ if (k >= 3) {
+ AV_WL32(l, L[2]);
+ y[0] = q1[y[0]] ^ l[0];
+ y[1] = q1[y[1]] ^ l[1];
+ y[2] = q0[y[2]] ^ l[2];
+ y[3] = q0[y[3]] ^ l[3];
+ }
+ AV_WL32(l, L[1]);
+ y[0] = q1[q0[q0[y[0]] ^ l[0]] ^ (L[0] & 0xff)];
+ y[1] = q0[q0[q1[y[1]] ^ l[1]] ^ ((L[0] >> 8) & 0xff)];
+ y[2] = q1[q1[q0[y[2]] ^ l[2]] ^ ((L[0] >> 16) & 0xff)];
+ y[3] = q0[q1[q1[y[3]] ^ l[3]] ^ (L[0] >> 24)];
+}
+
+static uint32_t tf_h(uint32_t X, uint32_t L[4], int k)
+{
+ uint8_t y[4], l[4];
+ AV_WL32(y, X);
+ tf_h0(y, L, k);
+
+ l[0] = y[0] ^ MD2[y[1]] ^ MD1[y[2]] ^ MD1[y[3]];
+ l[1] = MD1[y[0]] ^ MD2[y[1]] ^ MD2[y[2]] ^ y[3];
+ l[2] = MD2[y[0]] ^ MD1[y[1]] ^ y[2] ^ MD2[y[3]];
+ l[3] = MD2[y[0]] ^ y[1] ^ MD2[y[2]] ^ MD1[y[3]];
+
+ return AV_RL32(l);
+}
+
+static uint32_t MDS_mul(AVTWOFISH *cs, uint32_t X)
+{
+ return cs->MDS1[(X) & 0xff] ^ cs->MDS2[((X) >> 8) & 0xff] ^ cs->MDS3[((X) >> 16) & 0xff] ^ cs->MDS4[(X) >> 24];
+}
+
+static void precomputeMDS(AVTWOFISH *cs)
+{
+ uint8_t y[4];
+ int i;
+ for (i = 0; i < 256; i++) {
+ y[0] = y[1] = y[2] = y[3] = i;
+ tf_h0(y, cs->S, cs->ksize);
+ cs->MDS1[i] = ((uint32_t)y[0]) ^ ((uint32_t)MD1[y[0]] << 8) ^ ((uint32_t)MD2[y[0]] << 16) ^ ((uint32_t)MD2[y[0]] << 24);
+ cs->MDS2[i] = ((uint32_t)MD2[y[1]]) ^ ((uint32_t)MD2[y[1]] << 8) ^ ((uint32_t)MD1[y[1]] << 16) ^ ((uint32_t)y[1] << 24);
+ cs->MDS3[i] = ((uint32_t)MD1[y[2]]) ^ ((uint32_t)MD2[y[2]] << 8) ^ ((uint32_t)y[2] << 16) ^ ((uint32_t)MD2[y[2]] << 24);
+ cs->MDS4[i] = ((uint32_t)MD1[y[3]]) ^ ((uint32_t)y[3] << 8) ^ ((uint32_t)MD2[y[3]] << 16) ^ ((uint32_t)MD1[y[3]] << 24);
+ }
+}
+
+static void twofish_encrypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src)
+{
+ uint32_t P[4], t0, t1;
+ int i;
+ P[0] = AV_RL32(src) ^ cs->K[0];
+ P[1] = AV_RL32(src + 4) ^ cs->K[1];
+ P[2] = AV_RL32(src + 8) ^ cs->K[2];
+ P[3] = AV_RL32(src + 12) ^ cs->K[3];
+ for (i = 0; i < 16; i += 2) {
+ t0 = MDS_mul(cs, P[0]);
+ t1 = MDS_mul(cs, LR(P[1], 8));
+ P[2] = RR(P[2] ^ (t0 + t1 + cs->K[2 * i + 8]), 1);
+ P[3] = LR(P[3], 1) ^ (t0 + 2 * t1 + cs->K[2 * i + 9]);
+ t0 = MDS_mul(cs, P[2]);
+ t1 = MDS_mul(cs, LR(P[3], 8));
+ P[0] = RR(P[0] ^ (t0 + t1 + cs->K[2 * i + 10]), 1);
+ P[1] = LR(P[1], 1) ^ (t0 + 2 * t1 + cs->K[2 * i + 11]);
+ }
+ P[2] ^= cs->K[4];
+ P[3] ^= cs->K[5];
+ P[0] ^= cs->K[6];
+ P[1] ^= cs->K[7];
+ AV_WL32(dst, P[2]);
+ AV_WL32(dst + 4, P[3]);
+ AV_WL32(dst + 8, P[0]);
+ AV_WL32(dst + 12, P[1]);
+}
+
+static void twofish_decrypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src, uint8_t *iv)
+{
+ uint32_t P[4], t0, t1;
+ int i;
+ P[2] = AV_RL32(src) ^ cs->K[4];
+ P[3] = AV_RL32(src + 4) ^ cs->K[5];
+ P[0] = AV_RL32(src + 8) ^ cs->K[6];
+ P[1] = AV_RL32(src + 12) ^ cs->K[7];
+ for (i = 15; i >= 0; i -= 2) {
+ t0 = MDS_mul(cs, P[2]);
+ t1 = MDS_mul(cs, LR(P[3], 8));
+ P[0] = LR(P[0], 1) ^ (t0 + t1 + cs->K[2 * i + 8]);
+ P[1] = RR(P[1] ^ (t0 + 2 * t1 + cs->K[2 * i + 9]), 1);
+ t0 = MDS_mul(cs, P[0]);
+ t1 = MDS_mul(cs, LR(P[1], 8));
+ P[2] = LR(P[2], 1) ^ (t0 + t1 + cs->K[2 * i + 6]);
+ P[3] = RR(P[3] ^ (t0 + 2 * t1 + cs->K[2 * i + 7]), 1);
+ }
+ P[0] ^= cs->K[0];
+ P[1] ^= cs->K[1];
+ P[2] ^= cs->K[2];
+ P[3] ^= cs->K[3];
+ if (iv) {
+ P[0] ^= AV_RL32(iv);
+ P[1] ^= AV_RL32(iv + 4);
+ P[2] ^= AV_RL32(iv + 8);
+ P[3] ^= AV_RL32(iv + 12);
+ memcpy(iv, src, 16);
+ }
+ AV_WL32(dst, P[2]);
+ AV_WL32(dst + 4, P[3]);
+ AV_WL32(dst + 8, P[0]);
+ AV_WL32(dst + 12, P[1]);
+}
+
+av_cold int av_twofish_init(AVTWOFISH *cs, const uint8_t *key, int key_bits)
+{
+ int i;
+ uint8_t keypad[32];
+ uint32_t Key[8], Me[4], Mo[4], A, B;
+ const uint32_t rho = 0x01010101;
+ if (key_bits < 0)
+ return -1;
+ if (key_bits <= 128) {
+ cs->ksize = 2;
+ } else if (key_bits <= 192) {
+ cs->ksize = 3;
+ } else {
+ cs->ksize = 4;
+ }
+ memset(keypad, 0, sizeof(keypad));
+ if (key_bits <= 256) {
+ memcpy(keypad, key, key_bits >> 3);
+ } else {
+ memcpy(keypad, key, 32);
+ }
+ for (i = 0; i < 2 * cs->ksize ; i++)
+ Key[i] = AV_RL32(keypad + 4 * i);
+ for (i = 0; i < cs->ksize; i++) {
+ Me[i] = Key[2 * i];
+ Mo[i] = Key[2 * i + 1];
+ cs->S[cs->ksize - i - 1] = tf_RS(Me[i], Mo[i]);
+ }
+ precomputeMDS(cs);
+ for (i = 0; i < 20; i++) {
+ A = tf_h((2 * i) * rho, Me, cs->ksize);
+ B = tf_h((2 * i + 1) * rho, Mo, cs->ksize);
+ B = LR(B, 8);
+ cs->K[2 * i] = A + B;
+ cs->K[2 * i + 1] = LR((A + (2 * B)), 9);
+ }
+ if (cs->ksize << 6 != key_bits) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void av_twofish_crypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt)
+{
+ int i;
+ while (count--) {
+ if (decrypt) {
+ twofish_decrypt(cs, dst, src, iv);
+ } else {
+ if (iv) {
+ for (i = 0; i < 16; i++)
+ dst[i] = src[i] ^ iv[i];
+ twofish_encrypt(cs, dst, dst);
+ memcpy(iv, dst, 16);
+ } else {
+ twofish_encrypt(cs, dst, src);
+ }
+ }
+ src = src + 16;
+ dst = dst + 16;
+ }
+}
+
+#ifdef TEST
+#include<stdio.h>
+#include<stdlib.h>
+#include"log.h"
+
+int main(int argc, char *argv[])
+{
+ uint8_t Key[32] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ const uint8_t rct[6][16] = {
+ {0x9f, 0x58, 0x9f, 0x5c, 0xf6, 0x12, 0x2c, 0x32, 0xb6, 0xbf, 0xec, 0x2f, 0x2a, 0xe8, 0xc3, 0x5a},
+ {0xcf, 0xd1, 0xd2, 0xe5, 0xa9, 0xbe, 0x9c, 0xdf, 0x50, 0x1f, 0x13, 0xb8, 0x92, 0xbd, 0x22, 0x48},
+ {0x37, 0x52, 0x7b, 0xe0, 0x05, 0x23, 0x34, 0xb8, 0x9f, 0x0c, 0xfc, 0xca, 0xe8, 0x7c, 0xfa, 0x20},
+ {0x5d, 0x9d, 0x4e, 0xef, 0xfa, 0x91, 0x51, 0x57, 0x55, 0x24, 0xf1, 0x15, 0x81, 0x5a, 0x12, 0xe0},
+ {0xe7, 0x54, 0x49, 0x21, 0x2b, 0xee, 0xf9, 0xf4, 0xa3, 0x90, 0xbd, 0x86, 0x0a, 0x64, 0x09, 0x41},
+ {0x37, 0xfe, 0x26, 0xff, 0x1c, 0xf6, 0x61, 0x75, 0xf5, 0xdd, 0xf4, 0xc3, 0x3b, 0x97, 0xa2, 0x05}
+ };
+ uint8_t temp[32], iv[16], rpt[32] = {0};
+ const int kbits[3] = {128, 192, 256};
+ int i, j, err = 0;
+ AVTWOFISH *cs;
+ cs = av_twofish_alloc();
+ if (!cs)
+ return 1;
+ for (j = 1; j < 3; j++) {
+ av_twofish_init(cs, Key, kbits[j]);
+ av_twofish_crypt(cs, temp, rpt, 1, NULL, 0);
+ for (i = 0; i < 16; i++) {
+ if (rct[j][i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rct[j][i], temp[i]);
+ err = 1;
+ }
+ }
+ av_twofish_crypt(cs, temp, rct[j], 1, NULL, 1);
+ for (i = 0; i < 16; i++) {
+ if (rpt[i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rpt[i], temp[i]);
+ err = 1;
+ }
+ }
+ }
+ for (j = 0; j < 3; j++) {
+ memset(Key, 0, sizeof(Key));
+ memset(rpt, 0, sizeof(rpt));
+ for (i = 1; i < 50; i++) {
+ av_twofish_init(cs, Key, kbits[j]);
+ av_twofish_crypt(cs, temp, rpt, 1, NULL, 0);
+ memcpy(Key+16,Key,(kbits[j]-128) >> 3);
+ memcpy(Key,rpt,16);
+ memcpy(rpt,temp,16);
+ }
+ for (i = 0; i < 16; i++) {
+ if (rct[3 + j][i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rct[3 + j][i], temp[i]);
+ err = 1;
+ }
+ }
+ }
+ memset(rpt, 0, sizeof(rpt));
+ memcpy(iv, "HALLO123HALLO123", 16);
+ av_twofish_crypt(cs, temp, rpt, 2, iv, 0);
+ memcpy(iv, "HALLO123HALLO123", 16);
+ av_twofish_crypt(cs, temp, temp, 2, iv, 1);
+ for (i = 0; i < 32; i++) {
+ if (rpt[i] != temp[i]) {
+ av_log(NULL, AV_LOG_ERROR, "%d %02x %02x\n", i, rpt[i], temp[i]);
+ err = 1;
+ }
+ }
+ av_free(cs);
+ return err;
+}
+#endif
diff --git a/libavutil/twofish.h b/libavutil/twofish.h
new file mode 100644
index 0000000000..813cfecdf8
--- /dev/null
+++ b/libavutil/twofish.h
@@ -0,0 +1,70 @@
+/*
+ * An implementation of the TwoFish algorithm
+ * Copyright (c) 2015 Supraja Meedinti
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_TWOFISH_H
+#define AVUTIL_TWOFISH_H
+
+#include <stdint.h>
+
+
+/**
+ * @file
+ * @brief Public header for libavutil TWOFISH algorithm
+ * @defgroup lavu_twofish TWOFISH
+ * @ingroup lavu_crypto
+ * @{
+ */
+
+extern const int av_twofish_size;
+
+struct AVTWOFISH;
+
+/**
+ * Allocate an AVTWOFISH context
+ * To free the struct: av_free(ptr)
+ */
+struct AVTWOFISH *av_twofish_alloc(void);
+
+/**
+ * Initialize an AVTWOFISH context.
+ *
+ * @param ctx an AVTWOFISH context
+ * @param key a key of size ranging from 1 to 32 bytes used for encryption/decryption
+ * @param key_bits number of keybits: 128, 192, 256 If less than the required, padded with zeroes to nearest valid value; return value is 0 if key_bits is 128/192/256, -1 if less than 0, 1 otherwise
+ */
+int av_twofish_init(struct AVTWOFISH *ctx, const uint8_t *key, int key_bits);
+
+/**
+ * Encrypt or decrypt a buffer using a previously initialized context
+ *
+ * @param ctx an AVTWOFISH context
+ * @param dst destination array, can be equal to src
+ * @param src source array, can be equal to dst
+ * @param count number of 16 byte blocks
+ * @paran iv initialization vector for CBC mode, NULL for ECB mode
+ * @param decrypt 0 for encryption, 1 for decryption
+ */
+void av_twofish_crypt(struct AVTWOFISH *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt);
+
+/**
+ * @}
+ */
+#endif /* AVUTIL_TWOFISH_H */
diff --git a/libavutil/utf8.c b/libavutil/utf8.c
new file mode 100644
index 0000000000..3447a5192b
--- /dev/null
+++ b/libavutil/utf8.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef TEST
+#include <stdio.h>
+
+#include "libavutil/avstring.h"
+#include "libavutil/file.h"
+
+static void print_sequence(const char *p, int l, int indent)
+{
+ int i;
+ for (i = 0; i < l; i++)
+ printf("%02X", (uint8_t)p[i]);
+ printf("%*s", indent-l*2, "");
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ char *filename = argv[1];
+ uint8_t *file_buf;
+ size_t file_buf_size;
+ uint32_t code;
+ const uint8_t *p, *endp;
+
+ ret = av_file_map(filename, &file_buf, &file_buf_size, 0, NULL);
+ if (ret < 0)
+ return 1;
+
+ p = file_buf;
+ endp = file_buf + file_buf_size;
+ while (p < endp) {
+ int l, r;
+ const uint8_t *p0 = p;
+ code = UINT32_MAX;
+ r = av_utf8_decode(&code, &p, endp, 0);
+ l = (int)(p-p0);
+ print_sequence(p0, l, 20);
+ if (code != UINT32_MAX) {
+ printf("%-10d 0x%-10X %-5d ", code, code, l);
+ if (r >= 0) {
+ if (*p0 == '\n') printf("\\n\n");
+ else printf ("%.*s\n", l, p0);
+ } else {
+ printf("invalid code range\n");
+ }
+ } else {
+ printf("invalid sequence\n");
+ }
+ }
+
+ av_file_unmap(file_buf, file_buf_size);
+ return 0;
+}
+#endif
diff --git a/libavutil/utils.c b/libavutil/utils.c
index c8c161dccb..0b765ed0de 100644
--- a/libavutil/utils.c
+++ b/libavutil/utils.c
@@ -1,43 +1,84 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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 "avutil.h"
+#include "avassert.h"
+#include "samplefmt.h"
+#include "internal.h"
/**
* @file
* various utility functions
*/
+#include "libavutil/ffversion.h"
+const char av_util_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
unsigned avutil_version(void)
{
+ static int checks_done;
+ if (checks_done)
+ return LIBAVUTIL_VERSION_INT;
+
+ av_assert0(AV_PIX_FMT_VDA_VLD == 81); //check if the pix fmt enum has not had anything inserted or removed by mistake
+ 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);
+ av_assert0(HAVE_MMX2 == HAVE_MMXEXT);
+
+ av_assert0(((size_t)-1) > 0); // C guarantees this but if false on a platform we care about revert at least b284e1ffe343d6697fb950d1ee517bafda8a9844
+
+ if (av_sat_dadd32(1, 2) != 5) {
+ av_log(NULL, AV_LOG_FATAL, "Libavutil has been build with a broken binutils, please upgrade binutils and rebuild\n");
+ abort();
+ }
+
+ if (llrint(1LL<<60) != 1LL<<60) {
+ av_log(NULL, AV_LOG_ERROR, "Libavutil has been linked to a broken llrint()\n");
+ }
+
+ checks_done = 1;
return LIBAVUTIL_VERSION_INT;
}
const char *avutil_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char *avutil_license(void)
{
#define LICENSE_PREFIX "libavutil license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+}
+
+const char *av_get_media_type_string(enum AVMediaType media_type)
+{
+ switch (media_type) {
+ case AVMEDIA_TYPE_VIDEO: return "video";
+ case AVMEDIA_TYPE_AUDIO: return "audio";
+ case AVMEDIA_TYPE_DATA: return "data";
+ case AVMEDIA_TYPE_SUBTITLE: return "subtitle";
+ case AVMEDIA_TYPE_ATTACHMENT: return "attachment";
+ default: return NULL;
+ }
}
char av_get_picture_type_char(enum AVPictureType pict_type)
@@ -54,6 +95,25 @@ char av_get_picture_type_char(enum AVPictureType pict_type)
}
}
+unsigned av_int_list_length_for_size(unsigned elsize,
+ const void *list, uint64_t term)
+{
+ unsigned i;
+
+ if (!list)
+ return 0;
+#define LIST_LENGTH(type) \
+ { type t = term, *l = (type *)list; for (i = 0; l[i] != t; i++); }
+ switch (elsize) {
+ case 1: LIST_LENGTH(uint8_t); break;
+ case 2: LIST_LENGTH(uint16_t); break;
+ case 4: LIST_LENGTH(uint32_t); break;
+ case 8: LIST_LENGTH(uint64_t); break;
+ default: av_assert0(!"valid element size");
+ }
+ return i;
+}
+
AVRational av_get_time_base_q(void)
{
return (AVRational){1, AV_TIME_BASE};
diff --git a/libavutil/version.h b/libavutil/version.h
index 13bb6f0ab3..eeafcfab6c 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * copyright (c) 2003 Fabrice Bellard
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,7 +24,7 @@
#include "macros.h"
/**
- * @defgroup version_utils Library Version Macros
+ * @addtogroup version_utils
*
* Useful to check and match library version in order to maintain
* backward compatibility.
@@ -30,7 +32,7 @@
* @{
*/
-#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
+#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c))
#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
@@ -53,9 +55,9 @@
* @{
*/
-#define LIBAVUTIL_VERSION_MAJOR 54
-#define LIBAVUTIL_VERSION_MINOR 13
-#define LIBAVUTIL_VERSION_MICRO 1
+#define LIBAVUTIL_VERSION_MAJOR 54
+#define LIBAVUTIL_VERSION_MINOR 24
+#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
LIBAVUTIL_VERSION_MINOR, \
@@ -78,6 +80,9 @@
* @{
*/
+#ifndef FF_API_OLD_AVOPTIONS
+#define FF_API_OLD_AVOPTIONS (LIBAVUTIL_VERSION_MAJOR < 55)
+#endif
#ifndef FF_API_PIX_FMT
#define FF_API_PIX_FMT (LIBAVUTIL_VERSION_MAJOR < 55)
#endif
@@ -105,6 +110,9 @@
#ifndef FF_API_VDPAU
#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 55)
#endif
+#ifndef FF_API_GET_CHANNEL_LAYOUT_COMPAT
+#define FF_API_GET_CHANNEL_LAYOUT_COMPAT (LIBAVUTIL_VERSION_MAJOR < 55)
+#endif
#ifndef FF_API_XVMC
#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 55)
#endif
@@ -115,9 +123,17 @@
#define FF_API_DLOG (LIBAVUTIL_VERSION_MAJOR < 55)
#endif
+#ifndef FF_CONST_AVUTIL55
+#if LIBAVUTIL_VERSION_MAJOR >= 55
+#define FF_CONST_AVUTIL55 const
+#else
+#define FF_CONST_AVUTIL55
+#endif
+#endif
/**
* @}
*/
#endif /* AVUTIL_VERSION_H */
+
diff --git a/libavutil/wchar_filename.h b/libavutil/wchar_filename.h
index 2781773dee..c553c46f4f 100644
--- a/libavutil/wchar_filename.h
+++ b/libavutil/wchar_filename.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -31,7 +31,7 @@ static inline int utf8towchar(const char *filename_utf8, wchar_t **filename_w)
*filename_w = NULL;
return 0;
}
- *filename_w = av_mallocz(sizeof(wchar_t) * num_chars);
+ *filename_w = (wchar_t *)av_mallocz_array(num_chars, sizeof(wchar_t));
if (!*filename_w) {
errno = ENOMEM;
return -1;
diff --git a/libavutil/x86/Makefile b/libavutil/x86/Makefile
index 1e19082233..eb70a62eaa 100644
--- a/libavutil/x86/Makefile
+++ b/libavutil/x86/Makefile
@@ -2,7 +2,13 @@ OBJS += x86/cpu.o \
x86/float_dsp_init.o \
x86/lls_init.o \
+OBJS-$(CONFIG_PIXELUTILS) += x86/pixelutils_init.o \
+
+EMMS_OBJS_$(HAVE_MMX_INLINE)_$(HAVE_MMX_EXTERNAL)_$(HAVE_MM_EMPTY) = x86/emms.o
+
YASM-OBJS += x86/cpuid.o \
- x86/emms.o \
+ $(EMMS_OBJS__yes_) \
x86/float_dsp.o \
x86/lls.o \
+
+YASM-OBJS-$(CONFIG_PIXELUTILS) += x86/pixelutils.o \
diff --git a/libavutil/x86/asm.h b/libavutil/x86/asm.h
index e30f5dbaf7..616ad6c96f 100644
--- a/libavutil/x86/asm.h
+++ b/libavutil/x86/asm.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
#include "config.h"
typedef struct xmm_reg { uint64_t a, b; } xmm_reg;
+typedef struct ymm_reg { uint64_t a, b, c, d; } ymm_reg;
#if ARCH_X86_64
# define OPSIZE "q"
@@ -107,6 +108,46 @@ typedef int x86_reg;
# define LOCAL_MANGLE(a) #a
#endif
-#define MANGLE(a) EXTERN_PREFIX LOCAL_MANGLE(a)
+#if HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS
+# define MANGLE(a) EXTERN_PREFIX LOCAL_MANGLE(a)
+# define NAMED_CONSTRAINTS_ADD(...)
+# define NAMED_CONSTRAINTS(...)
+# define NAMED_CONSTRAINTS_ARRAY_ADD(...)
+# define NAMED_CONSTRAINTS_ARRAY(...)
+#else
+ /* When direct symbol references are used in code passed to a compiler that does not support them
+ * then these references need to be converted to named asm constraints instead.
+ * Instead of returning a direct symbol MANGLE now returns a named constraint for that specific symbol.
+ * In order for this to work there must also be a corresponding entry in the asm-interface. To add this
+ * entry use the macro NAMED_CONSTRAINTS() and pass in a list of each symbol reference used in the
+ * corresponding block of code. (e.g. NAMED_CONSTRAINTS(var1,var2,var3) where var1 is the first symbol etc. ).
+ * If there are already existing constraints then use NAMED_CONSTRAINTS_ADD to add to the existing constraint list.
+ */
+# define MANGLE(a) "%["#a"]"
+ // Intel/MSVC does not correctly expand va-args so we need a rather ugly hack in order to get it to work
+# define FE_0(P,X) P(X)
+# define FE_1(P,X,X1) P(X), FE_0(P,X1)
+# define FE_2(P,X,X1,X2) P(X), FE_1(P,X1,X2)
+# define FE_3(P,X,X1,X2,X3) P(X), FE_2(P,X1,X2,X3)
+# define FE_4(P,X,X1,X2,X3,X4) P(X), FE_3(P,X1,X2,X3,X4)
+# define FE_5(P,X,X1,X2,X3,X4,X5) P(X), FE_4(P,X1,X2,X3,X4,X5)
+# define FE_6(P,X,X1,X2,X3,X4,X5,X6) P(X), FE_5(P,X1,X2,X3,X4,X5,X6)
+# define FE_7(P,X,X1,X2,X3,X4,X5,X6,X7) P(X), FE_6(P,X1,X2,X3,X4,X5,X6,X7)
+# define FE_8(P,X,X1,X2,X3,X4,X5,X6,X7,X8) P(X), FE_7(P,X1,X2,X3,X4,X5,X6,X7,X8)
+# define FE_9(P,X,X1,X2,X3,X4,X5,X6,X7,X8,X9) P(X), FE_8(P,X1,X2,X3,X4,X5,X6,X7,X8,X9)
+# define GET_FE_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME
+# define GET_FE(A) GET_FE_IMPL A
+# define GET_FE_GLUE(x, y) x y
+# define FOR_EACH_VA(P,...) GET_FE_GLUE(GET_FE((__VA_ARGS__,FE_9,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)), (P,__VA_ARGS__))
+# define NAME_CONSTRAINT(x) [x] "m"(x)
+ // Parameters are a list of each symbol reference required
+# define NAMED_CONSTRAINTS_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT,__VA_ARGS__)
+ // Same but without comma for when there are no previously defined constraints
+# define NAMED_CONSTRAINTS(...) FOR_EACH_VA(NAME_CONSTRAINT,__VA_ARGS__)
+ // Same as above NAMED_CONSTRAINTS except used for passing arrays/pointers instead of normal variables
+# define NAME_CONSTRAINT_ARRAY(x) [x] "m"(*x)
+# define NAMED_CONSTRAINTS_ARRAY_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT_ARRAY,__VA_ARGS__)
+# define NAMED_CONSTRAINTS_ARRAY(...) FOR_EACH_VA(NAME_CONSTRAINT_ARRAY,__VA_ARGS__)
+#endif
#endif /* AVUTIL_X86_ASM_H */
diff --git a/libavutil/x86/bswap.h b/libavutil/x86/bswap.h
index c73be9af81..08e2a62520 100644
--- a/libavutil/x86/bswap.h
+++ b/libavutil/x86/bswap.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/x86/cpu.c b/libavutil/x86/cpu.c
index 8be6d94742..2b62e92479 100644
--- a/libavutil/x86/cpu.c
+++ b/libavutil/x86/cpu.c
@@ -3,20 +3,20 @@
* (c)1997-99 by H. Dietz and R. Fisher
* Converted to C and improved by Fabrice Bellard.
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,7 +45,7 @@
"cpuid \n\t" \
"xchg %%"REG_b", %%"REG_S \
: "=a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx) \
- : "0" (index))
+ : "0" (index), "2"(0))
#define xgetbv(index, eax, edx) \
__asm__ (".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c" (index))
@@ -143,7 +143,7 @@ int ff_get_cpu_flags_x86(void)
if (max_std_level >= 7) {
cpuid(7, eax, ebx, ecx, edx);
#if HAVE_AVX2
- if (ebx & 0x00000020)
+ if ((rval & AV_CPU_FLAG_AVX) && (ebx & 0x00000020))
rval |= AV_CPU_FLAG_AVX2;
#endif /* HAVE_AVX2 */
/* BMI1/2 don't need OS support */
diff --git a/libavutil/x86/cpu.h b/libavutil/x86/cpu.h
index 50da30e389..bc64b1b3bd 100644
--- a/libavutil/x86/cpu.h
+++ b/libavutil/x86/cpu.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/x86/cpuid.asm b/libavutil/x86/cpuid.asm
index 1cb8e94ea3..c3f7866ec7 100644
--- a/libavutil/x86/cpuid.asm
+++ b/libavutil/x86/cpuid.asm
@@ -4,20 +4,20 @@
;* Authors: Loren Merritt <lorenm@u.washington.edu>
;* Fiona Glaser <fiona@x264.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavutil/x86/emms.asm b/libavutil/x86/emms.asm
index a6851acc99..0aad34af3f 100644
--- a/libavutil/x86/emms.asm
+++ b/libavutil/x86/emms.asm
@@ -1,20 +1,20 @@
;*****************************************************************************
;* Copyright (C) 2013 Martin Storsjo
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
diff --git a/libavutil/x86/emms.h b/libavutil/x86/emms.h
index 2ed9e5d09d..a529b6bbbe 100644
--- a/libavutil/x86/emms.h
+++ b/libavutil/x86/emms.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -21,6 +21,7 @@
#include "config.h"
#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
void avpriv_emms_yasm(void);
@@ -33,7 +34,8 @@ void avpriv_emms_yasm(void);
*/
static av_always_inline void emms_c(void)
{
- __asm__ volatile ("emms" ::: "memory");
+ if(av_get_cpu_flags() & AV_CPU_FLAG_MMX)
+ __asm__ volatile ("emms" ::: "memory");
}
#elif HAVE_MMX && HAVE_MM_EMPTY
# include <mmintrin.h>
diff --git a/libavutil/x86/float_dsp.asm b/libavutil/x86/float_dsp.asm
index d96249978a..ec3d22b230 100644
--- a/libavutil/x86/float_dsp.asm
+++ b/libavutil/x86/float_dsp.asm
@@ -1,20 +1,22 @@
;*****************************************************************************
;* x86-optimized Float DSP functions
;*
-;* This file is part of Libav.
+;* Copyright 2006 Loren Merritt
;*
-;* Libav is free software; you can redistribute it and/or
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -48,8 +50,10 @@ ALIGN 16
INIT_XMM sse
VECTOR_FMUL
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
VECTOR_FMUL
+%endif
;------------------------------------------------------------------------------
; void ff_vector_fmac_scalar(float *dst, const float *src, float mul, int len)
@@ -57,33 +61,48 @@ VECTOR_FMUL
%macro VECTOR_FMAC_SCALAR 0
%if UNIX64
-cglobal vector_fmac_scalar, 3,3,3, dst, src, len
+cglobal vector_fmac_scalar, 3,3,5, dst, src, len
%else
-cglobal vector_fmac_scalar, 4,4,3, dst, src, mul, len
+cglobal vector_fmac_scalar, 4,4,5, dst, src, mul, len
%endif
%if ARCH_X86_32
VBROADCASTSS m0, mulm
%else
%if WIN64
- mova xmm0, xmm2
+ SWAP 0, 2
%endif
- shufps xmm0, xmm0, 0
+ shufps xm0, xm0, 0
%if cpuflag(avx)
- vinsertf128 m0, m0, xmm0, 1
+ vinsertf128 m0, m0, xm0, 1
%endif
%endif
lea lenq, [lend*4-64]
.loop:
-%assign a 0
-%rep 32/mmsize
- mulps m1, m0, [srcq+lenq+(a+0)*mmsize]
- mulps m2, m0, [srcq+lenq+(a+1)*mmsize]
- addps m1, m1, [dstq+lenq+(a+0)*mmsize]
- addps m2, m2, [dstq+lenq+(a+1)*mmsize]
- mova [dstq+lenq+(a+0)*mmsize], m1
- mova [dstq+lenq+(a+1)*mmsize], m2
-%assign a a+2
-%endrep
+%if cpuflag(fma3)
+ mova m1, [dstq+lenq]
+ mova m2, [dstq+lenq+1*mmsize]
+ fmaddps m1, m0, [srcq+lenq], m1
+ fmaddps m2, m0, [srcq+lenq+1*mmsize], m2
+%else ; cpuflag
+ mulps m1, m0, [srcq+lenq]
+ mulps m2, m0, [srcq+lenq+1*mmsize]
+%if mmsize < 32
+ mulps m3, m0, [srcq+lenq+2*mmsize]
+ mulps m4, m0, [srcq+lenq+3*mmsize]
+%endif ; mmsize
+ addps m1, m1, [dstq+lenq]
+ addps m2, m2, [dstq+lenq+1*mmsize]
+%if mmsize < 32
+ addps m3, m3, [dstq+lenq+2*mmsize]
+ addps m4, m4, [dstq+lenq+3*mmsize]
+%endif ; mmsize
+%endif ; cpuflag
+ mova [dstq+lenq], m1
+ mova [dstq+lenq+1*mmsize], m2
+%if mmsize < 32
+ mova [dstq+lenq+2*mmsize], m3
+ mova [dstq+lenq+3*mmsize], m4
+%endif ; mmsize
sub lenq, 64
jge .loop
REP_RET
@@ -91,8 +110,14 @@ cglobal vector_fmac_scalar, 4,4,3, dst, src, mul, len
INIT_XMM sse
VECTOR_FMAC_SCALAR
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
VECTOR_FMAC_SCALAR
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+VECTOR_FMAC_SCALAR
+%endif
;------------------------------------------------------------------------------
; void ff_vector_fmul_scalar(float *dst, const float *src, float mul, int len)
@@ -141,16 +166,11 @@ cglobal vector_dmul_scalar, 4,4,3, dst, src, mul, len
VBROADCASTSD m0, mulm
%else
%if WIN64
- movlhps xmm2, xmm2
-%if cpuflag(avx)
- vinsertf128 ymm2, ymm2, xmm2, 1
-%endif
SWAP 0, 2
-%else
- movlhps xmm0, xmm0
-%if cpuflag(avx)
- vinsertf128 ymm0, ymm0, xmm0, 1
%endif
+ movlhps xm0, xm0
+%if cpuflag(avx)
+ vinsertf128 ym0, ym0, xm0, 1
%endif
%endif
lea lenq, [lend*8-2*mmsize]
@@ -172,20 +192,85 @@ VECTOR_DMUL_SCALAR
%endif
;-----------------------------------------------------------------------------
+; vector_fmul_window(float *dst, const float *src0,
+; const float *src1, const float *win, int len);
+;-----------------------------------------------------------------------------
+%macro VECTOR_FMUL_WINDOW 0
+cglobal vector_fmul_window, 5, 6, 6, dst, src0, src1, win, len, len1
+ shl lend, 2
+ lea len1q, [lenq - mmsize]
+ add src0q, lenq
+ add dstq, lenq
+ add winq, lenq
+ neg lenq
+.loop
+ mova m0, [winq + lenq]
+ mova m4, [src0q + lenq]
+%if cpuflag(sse)
+ mova m1, [winq + len1q]
+ mova m5, [src1q + len1q]
+ shufps m1, m1, 0x1b
+ shufps m5, m5, 0x1b
+ mova m2, m0
+ mova m3, m1
+ mulps m2, m4
+ mulps m3, m5
+ mulps m1, m4
+ mulps m0, m5
+ addps m2, m3
+ subps m1, m0
+ shufps m2, m2, 0x1b
+%else
+ pswapd m1, [winq + len1q]
+ pswapd m5, [src1q + len1q]
+ mova m2, m0
+ mova m3, m1
+ pfmul m2, m4
+ pfmul m3, m5
+ pfmul m1, m4
+ pfmul m0, m5
+ pfadd m2, m3
+ pfsub m1, m0
+ pswapd m2, m2
+%endif
+ mova [dstq + lenq], m1
+ mova [dstq + len1q], m2
+ sub len1q, mmsize
+ add lenq, mmsize
+ jl .loop
+%if mmsize == 8
+ femms
+%endif
+ REP_RET
+%endmacro
+
+INIT_MMX 3dnowext
+VECTOR_FMUL_WINDOW
+INIT_XMM sse
+VECTOR_FMUL_WINDOW
+
+;-----------------------------------------------------------------------------
; vector_fmul_add(float *dst, const float *src0, const float *src1,
; const float *src2, int len)
;-----------------------------------------------------------------------------
%macro VECTOR_FMUL_ADD 0
-cglobal vector_fmul_add, 5,5,2, dst, src0, src1, src2, len
+cglobal vector_fmul_add, 5,5,4, dst, src0, src1, src2, len
lea lenq, [lend*4 - 2*mmsize]
ALIGN 16
.loop:
mova m0, [src0q + lenq]
mova m1, [src0q + lenq + mmsize]
+%if cpuflag(fma3)
+ mova m2, [src2q + lenq]
+ mova m3, [src2q + lenq + mmsize]
+ fmaddps m0, m0, [src1q + lenq], m2
+ fmaddps m1, m1, [src1q + lenq + mmsize], m3
+%else
mulps m0, m0, [src1q + lenq]
mulps m1, m1, [src1q + lenq + mmsize]
addps m0, m0, [src2q + lenq]
addps m1, m1, [src2q + lenq + mmsize]
+%endif
mova [dstq + lenq], m0
mova [dstq + lenq + mmsize], m1
@@ -196,8 +281,14 @@ ALIGN 16
INIT_XMM sse
VECTOR_FMUL_ADD
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
VECTOR_FMUL_ADD
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+VECTOR_FMUL_ADD
+%endif
;-----------------------------------------------------------------------------
; void vector_fmul_reverse(float *dst, const float *src0, const float *src1,
@@ -233,8 +324,10 @@ ALIGN 16
INIT_XMM sse
VECTOR_FMUL_REVERSE
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
VECTOR_FMUL_REVERSE
+%endif
; float scalarproduct_float_sse(const float *v1, const float *v2, int len)
INIT_XMM sse
@@ -272,8 +365,8 @@ cglobal butterflies_float, 3,3,3, src0, src1, len
test lenq, lenq
jz .end
shl lenq, 2
- lea src0q, [src0q + lenq]
- lea src1q, [src1q + lenq]
+ add src0q, lenq
+ add src1q, lenq
neg lenq
.loop:
mova m0, [src0q + lenq]
diff --git a/libavutil/x86/float_dsp_init.c b/libavutil/x86/float_dsp_init.c
index a04d91c923..64b3a4d6bd 100644
--- a/libavutil/x86/float_dsp_init.c
+++ b/libavutil/x86/float_dsp_init.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,6 +33,8 @@ void ff_vector_fmac_scalar_sse(float *dst, const float *src, float mul,
int len);
void ff_vector_fmac_scalar_avx(float *dst, const float *src, float mul,
int len);
+void ff_vector_fmac_scalar_fma3(float *dst, const float *src, float mul,
+ int len);
void ff_vector_fmul_scalar_sse(float *dst, const float *src, float mul,
int len);
@@ -42,10 +44,17 @@ void ff_vector_dmul_scalar_sse2(double *dst, const double *src,
void ff_vector_dmul_scalar_avx(double *dst, const double *src,
double mul, int len);
+void ff_vector_fmul_window_3dnowext(float *dst, const float *src0,
+ const float *src1, const float *win, int len);
+void ff_vector_fmul_window_sse(float *dst, const float *src0,
+ const float *src1, const float *win, int len);
+
void ff_vector_fmul_add_sse(float *dst, const float *src0, const float *src1,
const float *src2, int len);
void ff_vector_fmul_add_avx(float *dst, const float *src0, const float *src1,
const float *src2, int len);
+void ff_vector_fmul_add_fma3(float *dst, const float *src0, const float *src1,
+ const float *src2, int len);
void ff_vector_fmul_reverse_sse(float *dst, const float *src0,
const float *src1, int len);
@@ -56,88 +65,18 @@ float ff_scalarproduct_float_sse(const float *v1, const float *v2, int order);
void ff_butterflies_float_sse(float *src0, float *src1, int len);
-#if HAVE_6REGS && HAVE_INLINE_ASM
-static void vector_fmul_window_3dnowext(float *dst, const float *src0,
- const float *src1, const float *win,
- int len)
-{
- x86_reg i = -len * 4;
- x86_reg j = len * 4 - 8;
- __asm__ volatile (
- "1: \n"
- "pswapd (%5, %1), %%mm1 \n"
- "movq (%5, %0), %%mm0 \n"
- "pswapd (%4, %1), %%mm5 \n"
- "movq (%3, %0), %%mm4 \n"
- "movq %%mm0, %%mm2 \n"
- "movq %%mm1, %%mm3 \n"
- "pfmul %%mm4, %%mm2 \n" // src0[len + i] * win[len + i]
- "pfmul %%mm5, %%mm3 \n" // src1[j] * win[len + j]
- "pfmul %%mm4, %%mm1 \n" // src0[len + i] * win[len + j]
- "pfmul %%mm5, %%mm0 \n" // src1[j] * win[len + i]
- "pfadd %%mm3, %%mm2 \n"
- "pfsub %%mm0, %%mm1 \n"
- "pswapd %%mm2, %%mm2 \n"
- "movq %%mm1, (%2, %0) \n"
- "movq %%mm2, (%2, %1) \n"
- "sub $8, %1 \n"
- "add $8, %0 \n"
- "jl 1b \n"
- "femms \n"
- : "+r"(i), "+r"(j)
- : "r"(dst + len), "r"(src0 + len), "r"(src1), "r"(win + len)
- );
-}
-
-static void vector_fmul_window_sse(float *dst, const float *src0,
- const float *src1, const float *win, int len)
-{
- x86_reg i = -len * 4;
- x86_reg j = len * 4 - 16;
- __asm__ volatile (
- "1: \n"
- "movaps (%5, %1), %%xmm1 \n"
- "movaps (%5, %0), %%xmm0 \n"
- "movaps (%4, %1), %%xmm5 \n"
- "movaps (%3, %0), %%xmm4 \n"
- "shufps $0x1b, %%xmm1, %%xmm1 \n"
- "shufps $0x1b, %%xmm5, %%xmm5 \n"
- "movaps %%xmm0, %%xmm2 \n"
- "movaps %%xmm1, %%xmm3 \n"
- "mulps %%xmm4, %%xmm2 \n" // src0[len + i] * win[len + i]
- "mulps %%xmm5, %%xmm3 \n" // src1[j] * win[len + j]
- "mulps %%xmm4, %%xmm1 \n" // src0[len + i] * win[len + j]
- "mulps %%xmm5, %%xmm0 \n" // src1[j] * win[len + i]
- "addps %%xmm3, %%xmm2 \n"
- "subps %%xmm0, %%xmm1 \n"
- "shufps $0x1b, %%xmm2, %%xmm2 \n"
- "movaps %%xmm1, (%2, %0) \n"
- "movaps %%xmm2, (%2, %1) \n"
- "sub $16, %1 \n"
- "add $16, %0 \n"
- "jl 1b \n"
- : "+r"(i), "+r"(j)
- : "r"(dst + len), "r"(src0 + len), "r"(src1), "r"(win + len)
- );
-}
-#endif /* HAVE_6REGS && HAVE_INLINE_ASM */
-
av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp)
{
int cpu_flags = av_get_cpu_flags();
-#if HAVE_6REGS && HAVE_INLINE_ASM
- if (INLINE_AMD3DNOWEXT(cpu_flags)) {
- fdsp->vector_fmul_window = vector_fmul_window_3dnowext;
+ if (EXTERNAL_AMD3DNOWEXT(cpu_flags)) {
+ fdsp->vector_fmul_window = ff_vector_fmul_window_3dnowext;
}
- if (INLINE_SSE(cpu_flags)) {
- fdsp->vector_fmul_window = vector_fmul_window_sse;
- }
-#endif
if (EXTERNAL_SSE(cpu_flags)) {
fdsp->vector_fmul = ff_vector_fmul_sse;
fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_sse;
fdsp->vector_fmul_scalar = ff_vector_fmul_scalar_sse;
+ fdsp->vector_fmul_window = ff_vector_fmul_window_sse;
fdsp->vector_fmul_add = ff_vector_fmul_add_sse;
fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_sse;
fdsp->scalarproduct_float = ff_scalarproduct_float_sse;
@@ -153,4 +92,8 @@ av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp)
fdsp->vector_fmul_add = ff_vector_fmul_add_avx;
fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx;
}
+ if (EXTERNAL_FMA3(cpu_flags)) {
+ fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_fma3;
+ fdsp->vector_fmul_add = ff_vector_fmul_add_fma3;
+ }
}
diff --git a/libavutil/x86/intmath.h b/libavutil/x86/intmath.h
new file mode 100644
index 0000000000..c42fa8352b
--- /dev/null
+++ b/libavutil/x86/intmath.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_X86_INTMATH_H
+#define AVUTIL_X86_INTMATH_H
+
+#include <stdint.h>
+#include "config.h"
+
+#if defined(__GNUC__)
+
+/* Our generic version of av_popcount is faster than GCC's built-in on
+ * CPUs that don't support the popcnt instruction.
+ */
+#if defined(__POPCNT__)
+ #define av_popcount __builtin_popcount
+#if ARCH_X86_64
+ #define av_popcount64 __builtin_popcountll
+#endif
+
+#endif /* __POPCNT__ */
+
+#if defined(__BMI2__)
+
+#define av_mod_uintp2 av_mod_uintp2_bmi2
+static av_always_inline av_const unsigned av_mod_uintp2_bmi2(unsigned a, unsigned p)
+{
+ if (av_builtin_constant_p(p))
+ return a & ((1 << p) - 1);
+ else {
+ unsigned x;
+ __asm__ ("bzhi %2, %1, %0 \n\t" : "=r"(x) : "rm"(a), "r"(p));
+ return x;
+ }
+}
+
+#endif /* __BMI2__ */
+
+#endif /* __GNUC__ */
+
+#endif /* AVUTIL_X86_INTMATH_H */
diff --git a/libavutil/x86/intreadwrite.h b/libavutil/x86/intreadwrite.h
index 635096e569..4061d19231 100644
--- a/libavutil/x86/intreadwrite.h
+++ b/libavutil/x86/intreadwrite.h
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2010 Alexander Strange <astrange@ithinksw.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/x86/lls.asm b/libavutil/x86/lls.asm
index eab85ed050..769befb769 100644
--- a/libavutil/x86/lls.asm
+++ b/libavutil/x86/lls.asm
@@ -3,20 +3,20 @@
;*
;* Copyright (c) 2013 Loren Merritt
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -125,6 +125,7 @@ cglobal update_lls, 2,5,8, ctx, var, i, j, covar2
.ret:
REP_RET
+%if HAVE_AVX_EXTERNAL
INIT_YMM avx
cglobal update_lls, 3,6,8, ctx, var, count, i, j, count2
%define covarq ctxq
@@ -194,7 +195,7 @@ cglobal update_lls, 3,6,8, ctx, var, count, i, j, count2
jle .loop2x1
.ret:
REP_RET
-
+%endif
INIT_XMM sse2
cglobal evaluate_lls, 3,4,2, ctx, var, order, i
diff --git a/libavutil/x86/lls_init.c b/libavutil/x86/lls_init.c
index 888bc54a39..f53190488a 100644
--- a/libavutil/x86/lls_init.c
+++ b/libavutil/x86/lls_init.c
@@ -3,29 +3,29 @@
*
* Copyright (c) 2013 Loren Merritt
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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/lls.h"
#include "libavutil/x86/cpu.h"
-void ff_update_lls_sse2(LLSModel *m, double *var);
-void ff_update_lls_avx(LLSModel *m, double *var);
-double ff_evaluate_lls_sse2(LLSModel *m, double *var, int order);
+void ff_update_lls_sse2(LLSModel *m, const double *var);
+void ff_update_lls_avx(LLSModel *m, const double *var);
+double ff_evaluate_lls_sse2(LLSModel *m, const double *var, int order);
av_cold void ff_init_lls_x86(LLSModel *m)
{
diff --git a/libavutil/x86/pixelutils.asm b/libavutil/x86/pixelutils.asm
new file mode 100644
index 0000000000..7522f24a42
--- /dev/null
+++ b/libavutil/x86/pixelutils.asm
@@ -0,0 +1,165 @@
+;******************************************************************************
+;* Pixel utilities SIMD
+;*
+;* Copyright (C) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
+;* Copyright (C) 2014 ClĂ©ment BÅ“sch <u pkh me>
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General 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 "x86util.asm"
+
+SECTION_TEXT
+
+;-------------------------------------------------------------------------------
+; int ff_pixelutils_sad_8x8_mmx(const uint8_t *src1, ptrdiff_t stride1,
+; const uint8_t *src2, ptrdiff_t stride2);
+;-------------------------------------------------------------------------------
+INIT_MMX mmx
+cglobal pixelutils_sad_8x8, 4,4,0, src1, stride1, src2, stride2
+ pxor m7, m7
+ pxor m6, m6
+%rep 4
+ mova m0, [src1q]
+ mova m2, [src1q + stride1q]
+ mova m1, [src2q]
+ mova m3, [src2q + stride2q]
+ psubusb m4, m0, m1
+ psubusb m5, m2, m3
+ psubusb m1, m0
+ psubusb m3, m2
+ por m1, m4
+ por m3, m5
+ punpcklbw m0, m1, m7
+ punpcklbw m2, m3, m7
+ punpckhbw m1, m7
+ punpckhbw m3, m7
+ paddw m0, m1
+ paddw m2, m3
+ paddw m0, m2
+ paddw m6, m0
+ lea src1q, [src1q + 2*stride1q]
+ lea src2q, [src2q + 2*stride2q]
+%endrep
+ psrlq m0, m6, 32
+ paddw m6, m0
+ psrlq m0, m6, 16
+ paddw m6, m0
+ movd eax, m6
+ movzx eax, ax
+ RET
+
+;-------------------------------------------------------------------------------
+; int ff_pixelutils_sad_8x8_mmxext(const uint8_t *src1, ptrdiff_t stride1,
+; const uint8_t *src2, ptrdiff_t stride2);
+;-------------------------------------------------------------------------------
+INIT_MMX mmxext
+cglobal pixelutils_sad_8x8, 4,4,0, src1, stride1, src2, stride2
+ pxor m2, m2
+%rep 4
+ mova m0, [src1q]
+ mova m1, [src1q + stride1q]
+ psadbw m0, [src2q]
+ psadbw m1, [src2q + stride2q]
+ paddw m2, m0
+ paddw m2, m1
+ lea src1q, [src1q + 2*stride1q]
+ lea src2q, [src2q + 2*stride2q]
+%endrep
+ movd eax, m2
+ RET
+
+;-------------------------------------------------------------------------------
+; int ff_pixelutils_sad_16x16_mmxext(const uint8_t *src1, ptrdiff_t stride1,
+; const uint8_t *src2, ptrdiff_t stride2);
+;-------------------------------------------------------------------------------
+INIT_MMX mmxext
+cglobal pixelutils_sad_16x16, 4,4,0, src1, stride1, src2, stride2
+ pxor m2, m2
+%rep 16
+ mova m0, [src1q]
+ mova m1, [src1q + 8]
+ psadbw m0, [src2q]
+ psadbw m1, [src2q + 8]
+ paddw m2, m0
+ paddw m2, m1
+ add src1q, stride1q
+ add src2q, stride2q
+%endrep
+ movd eax, m2
+ RET
+
+;-------------------------------------------------------------------------------
+; int ff_pixelutils_sad_16x16_sse(const uint8_t *src1, ptrdiff_t stride1,
+; const uint8_t *src2, ptrdiff_t stride2);
+;-------------------------------------------------------------------------------
+INIT_XMM sse2
+cglobal pixelutils_sad_16x16, 4,4,5, src1, stride1, src2, stride2
+ movu m4, [src1q]
+ movu m2, [src2q]
+ movu m1, [src1q + stride1q]
+ movu m3, [src2q + stride2q]
+ psadbw m4, m2
+ psadbw m1, m3
+ paddw m4, m1
+%rep 7
+ lea src1q, [src1q + 2*stride1q]
+ lea src2q, [src2q + 2*stride2q]
+ movu m0, [src1q]
+ movu m2, [src2q]
+ movu m1, [src1q + stride1q]
+ movu m3, [src2q + stride2q]
+ psadbw m0, m2
+ psadbw m1, m3
+ paddw m4, m0
+ paddw m4, m1
+%endrep
+ movhlps m0, m4
+ paddw m4, m0
+ movd eax, m4
+ RET
+
+;-------------------------------------------------------------------------------
+; int ff_pixelutils_sad_[au]_16x16_sse(const uint8_t *src1, ptrdiff_t stride1,
+; const uint8_t *src2, ptrdiff_t stride2);
+;-------------------------------------------------------------------------------
+%macro SAD_XMM_16x16 1
+INIT_XMM sse2
+cglobal pixelutils_sad_%1_16x16, 4,4,3, src1, stride1, src2, stride2
+ mov%1 m2, [src2q]
+ psadbw m2, [src1q]
+ mov%1 m1, [src2q + stride2q]
+ psadbw m1, [src1q + stride1q]
+ paddw m2, m1
+%rep 7
+ lea src1q, [src1q + 2*stride1q]
+ lea src2q, [src2q + 2*stride2q]
+ mov%1 m0, [src2q]
+ psadbw m0, [src1q]
+ mov%1 m1, [src2q + stride2q]
+ psadbw m1, [src1q + stride1q]
+ paddw m2, m0
+ paddw m2, m1
+%endrep
+ movhlps m0, m2
+ paddw m2, m0
+ movd eax, m2
+ RET
+%endmacro
+
+SAD_XMM_16x16 a
+SAD_XMM_16x16 u
diff --git a/libavutil/x86/pixelutils.h b/libavutil/x86/pixelutils.h
new file mode 100644
index 0000000000..876cf46053
--- /dev/null
+++ b/libavutil/x86/pixelutils.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_X86_PIXELUTILS_H
+#define AVUTIL_X86_PIXELUTILS_H
+
+#include "libavutil/pixelutils.h"
+
+void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned);
+
+#endif /* AVUTIL_X86_PIXELUTILS_H */
diff --git a/libavutil/x86/pixelutils_init.c b/libavutil/x86/pixelutils_init.c
new file mode 100644
index 0000000000..c24a533aea
--- /dev/null
+++ b/libavutil/x86/pixelutils_init.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "pixelutils.h"
+#include "cpu.h"
+
+int ff_pixelutils_sad_8x8_mmx(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+int ff_pixelutils_sad_8x8_mmxext(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+
+int ff_pixelutils_sad_16x16_mmxext(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+int ff_pixelutils_sad_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+int ff_pixelutils_sad_a_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+int ff_pixelutils_sad_u_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1,
+ const uint8_t *src2, ptrdiff_t stride2);
+
+void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ if (EXTERNAL_MMX(cpu_flags)) {
+ sad[2] = ff_pixelutils_sad_8x8_mmx;
+ }
+
+ // The best way to use SSE2 would be to do 2 SADs in parallel,
+ // but we'd have to modify the pixelutils API to return SIMD functions.
+
+ // It's probably not faster to shuffle data around
+ // to get two lines of 8 pixels into a single 16byte register,
+ // so just use the MMX 8x8 version even when SSE2 is available.
+ if (EXTERNAL_MMXEXT(cpu_flags)) {
+ sad[2] = ff_pixelutils_sad_8x8_mmxext;
+ sad[3] = ff_pixelutils_sad_16x16_mmxext;
+ }
+
+ if (EXTERNAL_SSE2(cpu_flags)) {
+ switch (aligned) {
+ case 0: sad[3] = ff_pixelutils_sad_16x16_sse2; break; // src1 unaligned, src2 unaligned
+ case 1: sad[3] = ff_pixelutils_sad_u_16x16_sse2; break; // src1 aligned, src2 unaligned
+ case 2: sad[3] = ff_pixelutils_sad_a_16x16_sse2; break; // src1 aligned, src2 aligned
+ }
+ }
+}
diff --git a/libavutil/x86/timer.h b/libavutil/x86/timer.h
index cdd67ddbb5..5b24b511c1 100644
--- a/libavutil/x86/timer.h
+++ b/libavutil/x86/timer.h
@@ -1,20 +1,20 @@
/*
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,7 @@
#if HAVE_INLINE_ASM
+#define FF_TIMER_UNITS "decicycles"
#define AV_READ_TIME read_time
static inline uint64_t read_time(void)
diff --git a/libavutil/x86/w64xmmtest.h b/libavutil/x86/w64xmmtest.h
index b4ce7d3daf..9df499f7f6 100644
--- a/libavutil/x86/w64xmmtest.h
+++ b/libavutil/x86/w64xmmtest.h
@@ -2,20 +2,20 @@
* check XMM registers for clobbers on Win64
* Copyright (c) 2008 Ramiro Polla <ramiro.polla@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libavutil/x86/x86inc.asm b/libavutil/x86/x86inc.asm
index e3ed3813e0..f1b4b85a87 100644
--- a/libavutil/x86/x86inc.asm
+++ b/libavutil/x86/x86inc.asm
@@ -871,7 +871,7 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits
%assign %%i 0
%rep num_mmregs
CAT_XDEFINE m, %%i, ymm %+ %%i
- CAT_XDEFINE nymm, %%i, %%i
+ CAT_XDEFINE nnymm, %%i, %%i
%assign %%i %%i+1
%endrep
INIT_CPUFLAGS %1
@@ -1047,15 +1047,16 @@ INIT_XMM
%endmacro
;%1 == instruction
-;%2 == 1 if float, 0 if int
-;%3 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise
-;%4 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
-;%5+: operands
-%macro RUN_AVX_INSTR 5-8+
- %ifnum sizeof%6
+;%2 == minimal instruction set
+;%3 == 1 if float, 0 if int
+;%4 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise
+;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
+;%6+: operands
+%macro RUN_AVX_INSTR 6-9+
+ %ifnum sizeof%7
+ %assign __sizeofreg sizeof%7
+ %elifnum sizeof%6
%assign __sizeofreg sizeof%6
- %elifnum sizeof%5
- %assign __sizeofreg sizeof%5
%else
%assign __sizeofreg mmsize
%endif
@@ -1064,325 +1065,335 @@ INIT_XMM
%xdefine __instr v%1
%else
%xdefine __instr %1
- %if %0 >= 7+%3
+ %if %0 >= 8+%4
%assign __emulate_avx 1
%endif
%endif
+ %ifnidn %2, fnord
+ %ifdef cpuname
+ %if notcpuflag(%2)
+ %error use of ``%1'' %2 instruction in cpuname function: current_function
+ %elif cpuflags_%2 < cpuflags_sse && notcpuflag(sse2) && __sizeofreg > 8
+ %error use of ``%1'' sse2 instruction in cpuname function: current_function
+ %endif
+ %endif
+ %endif
%if __emulate_avx
- %xdefine __src1 %6
- %xdefine __src2 %7
- %ifnidn %5, %6
- %if %0 >= 8
- CHECK_AVX_INSTR_EMU {%1 %5, %6, %7, %8}, %5, %7, %8
+ %xdefine __src1 %7
+ %xdefine __src2 %8
+ %ifnidn %6, %7
+ %if %0 >= 9
+ CHECK_AVX_INSTR_EMU {%1 %6, %7, %8, %9}, %6, %8, %9
%else
- CHECK_AVX_INSTR_EMU {%1 %5, %6, %7}, %5, %7
+ CHECK_AVX_INSTR_EMU {%1 %6, %7, %8}, %6, %8
%endif
- %if %4 && %3 == 0
- %ifnid %7
+ %if %5 && %4 == 0
+ %ifnid %8
; 3-operand AVX instructions with a memory arg can only have it in src2,
; whereas SSE emulation prefers to have it in src1 (i.e. the mov).
; So, if the instruction is commutative with a memory arg, swap them.
- %xdefine __src1 %7
- %xdefine __src2 %6
+ %xdefine __src1 %8
+ %xdefine __src2 %7
%endif
%endif
%if __sizeofreg == 8
- MOVQ %5, __src1
- %elif %2
- MOVAPS %5, __src1
+ MOVQ %6, __src1
+ %elif %3
+ MOVAPS %6, __src1
%else
- MOVDQA %5, __src1
+ MOVDQA %6, __src1
%endif
%endif
- %if %0 >= 8
- %1 %5, __src2, %8
+ %if %0 >= 9
+ %1 %6, __src2, %9
%else
- %1 %5, __src2
+ %1 %6, __src2
%endif
- %elif %0 >= 8
- __instr %5, %6, %7, %8
+ %elif %0 >= 9
+ __instr %6, %7, %8, %9
+ %elif %0 == 8
+ __instr %6, %7, %8
%elif %0 == 7
- __instr %5, %6, %7
- %elif %0 == 6
- __instr %5, %6
+ __instr %6, %7
%else
- __instr %5
+ __instr %6
%endif
%endmacro
;%1 == instruction
-;%2 == 1 if float, 0 if int
-;%3 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise
-;%4 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
-%macro AVX_INSTR 1-4 0, 1, 0
- %macro %1 1-9 fnord, fnord, fnord, fnord, %1, %2, %3, %4
+;%2 == minimal instruction set
+;%3 == 1 if float, 0 if int
+;%4 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise
+;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
+%macro AVX_INSTR 1-5 fnord, 0, 1, 0
+ %macro %1 1-10 fnord, fnord, fnord, fnord, %1, %2, %3, %4, %5
%ifidn %2, fnord
- RUN_AVX_INSTR %6, %7, %8, %9, %1
+ RUN_AVX_INSTR %6, %7, %8, %9, %10, %1
%elifidn %3, fnord
- RUN_AVX_INSTR %6, %7, %8, %9, %1, %2
+ RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2
%elifidn %4, fnord
- RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3
+ RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3
%elifidn %5, fnord
- RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3, %4
+ RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4
%else
- RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3, %4, %5
+ RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4, %5
%endif
%endmacro
%endmacro
; Instructions with both VEX and non-VEX encodings
; Non-destructive instructions are written without parameters
-AVX_INSTR addpd, 1, 0, 1
-AVX_INSTR addps, 1, 0, 1
-AVX_INSTR addsd, 1, 0, 1
-AVX_INSTR addss, 1, 0, 1
-AVX_INSTR addsubpd, 1, 0, 0
-AVX_INSTR addsubps, 1, 0, 0
-AVX_INSTR aesdec, 0, 0, 0
-AVX_INSTR aesdeclast, 0, 0, 0
-AVX_INSTR aesenc, 0, 0, 0
-AVX_INSTR aesenclast, 0, 0, 0
+AVX_INSTR addpd, sse2, 1, 0, 1
+AVX_INSTR addps, sse, 1, 0, 1
+AVX_INSTR addsd, sse2, 1, 0, 1
+AVX_INSTR addss, sse, 1, 0, 1
+AVX_INSTR addsubpd, sse3, 1, 0, 0
+AVX_INSTR addsubps, sse3, 1, 0, 0
+AVX_INSTR aesdec, fnord, 0, 0, 0
+AVX_INSTR aesdeclast, fnord, 0, 0, 0
+AVX_INSTR aesenc, fnord, 0, 0, 0
+AVX_INSTR aesenclast, fnord, 0, 0, 0
AVX_INSTR aesimc
AVX_INSTR aeskeygenassist
-AVX_INSTR andnpd, 1, 0, 0
-AVX_INSTR andnps, 1, 0, 0
-AVX_INSTR andpd, 1, 0, 1
-AVX_INSTR andps, 1, 0, 1
-AVX_INSTR blendpd, 1, 0, 0
-AVX_INSTR blendps, 1, 0, 0
-AVX_INSTR blendvpd, 1, 0, 0
-AVX_INSTR blendvps, 1, 0, 0
-AVX_INSTR cmppd, 1, 1, 0
-AVX_INSTR cmpps, 1, 1, 0
-AVX_INSTR cmpsd, 1, 1, 0
-AVX_INSTR cmpss, 1, 1, 0
-AVX_INSTR comisd
-AVX_INSTR comiss
-AVX_INSTR cvtdq2pd
-AVX_INSTR cvtdq2ps
-AVX_INSTR cvtpd2dq
-AVX_INSTR cvtpd2ps
-AVX_INSTR cvtps2dq
-AVX_INSTR cvtps2pd
-AVX_INSTR cvtsd2si
-AVX_INSTR cvtsd2ss
-AVX_INSTR cvtsi2sd
-AVX_INSTR cvtsi2ss
-AVX_INSTR cvtss2sd
-AVX_INSTR cvtss2si
-AVX_INSTR cvttpd2dq
-AVX_INSTR cvttps2dq
-AVX_INSTR cvttsd2si
-AVX_INSTR cvttss2si
-AVX_INSTR divpd, 1, 0, 0
-AVX_INSTR divps, 1, 0, 0
-AVX_INSTR divsd, 1, 0, 0
-AVX_INSTR divss, 1, 0, 0
-AVX_INSTR dppd, 1, 1, 0
-AVX_INSTR dpps, 1, 1, 0
-AVX_INSTR extractps
-AVX_INSTR haddpd, 1, 0, 0
-AVX_INSTR haddps, 1, 0, 0
-AVX_INSTR hsubpd, 1, 0, 0
-AVX_INSTR hsubps, 1, 0, 0
-AVX_INSTR insertps, 1, 1, 0
-AVX_INSTR lddqu
-AVX_INSTR ldmxcsr
-AVX_INSTR maskmovdqu
-AVX_INSTR maxpd, 1, 0, 1
-AVX_INSTR maxps, 1, 0, 1
-AVX_INSTR maxsd, 1, 0, 1
-AVX_INSTR maxss, 1, 0, 1
-AVX_INSTR minpd, 1, 0, 1
-AVX_INSTR minps, 1, 0, 1
-AVX_INSTR minsd, 1, 0, 1
-AVX_INSTR minss, 1, 0, 1
-AVX_INSTR movapd
-AVX_INSTR movaps
-AVX_INSTR movd
-AVX_INSTR movddup
-AVX_INSTR movdqa
-AVX_INSTR movdqu
-AVX_INSTR movhlps, 1, 0, 0
-AVX_INSTR movhpd, 1, 0, 0
-AVX_INSTR movhps, 1, 0, 0
-AVX_INSTR movlhps, 1, 0, 0
-AVX_INSTR movlpd, 1, 0, 0
-AVX_INSTR movlps, 1, 0, 0
-AVX_INSTR movmskpd
-AVX_INSTR movmskps
-AVX_INSTR movntdq
-AVX_INSTR movntdqa
-AVX_INSTR movntpd
-AVX_INSTR movntps
-AVX_INSTR movq
-AVX_INSTR movsd, 1, 0, 0
-AVX_INSTR movshdup
-AVX_INSTR movsldup
-AVX_INSTR movss, 1, 0, 0
-AVX_INSTR movupd
-AVX_INSTR movups
-AVX_INSTR mpsadbw, 0, 1, 0
-AVX_INSTR mulpd, 1, 0, 1
-AVX_INSTR mulps, 1, 0, 1
-AVX_INSTR mulsd, 1, 0, 1
-AVX_INSTR mulss, 1, 0, 1
-AVX_INSTR orpd, 1, 0, 1
-AVX_INSTR orps, 1, 0, 1
-AVX_INSTR pabsb
-AVX_INSTR pabsd
-AVX_INSTR pabsw
-AVX_INSTR packsswb, 0, 0, 0
-AVX_INSTR packssdw, 0, 0, 0
-AVX_INSTR packuswb, 0, 0, 0
-AVX_INSTR packusdw, 0, 0, 0
-AVX_INSTR paddb, 0, 0, 1
-AVX_INSTR paddw, 0, 0, 1
-AVX_INSTR paddd, 0, 0, 1
-AVX_INSTR paddq, 0, 0, 1
-AVX_INSTR paddsb, 0, 0, 1
-AVX_INSTR paddsw, 0, 0, 1
-AVX_INSTR paddusb, 0, 0, 1
-AVX_INSTR paddusw, 0, 0, 1
-AVX_INSTR palignr, 0, 1, 0
-AVX_INSTR pand, 0, 0, 1
-AVX_INSTR pandn, 0, 0, 0
-AVX_INSTR pavgb, 0, 0, 1
-AVX_INSTR pavgw, 0, 0, 1
-AVX_INSTR pblendvb, 0, 0, 0
-AVX_INSTR pblendw, 0, 1, 0
-AVX_INSTR pclmulqdq, 0, 1, 0
-AVX_INSTR pcmpestri
-AVX_INSTR pcmpestrm
-AVX_INSTR pcmpistri
-AVX_INSTR pcmpistrm
-AVX_INSTR pcmpeqb, 0, 0, 1
-AVX_INSTR pcmpeqw, 0, 0, 1
-AVX_INSTR pcmpeqd, 0, 0, 1
-AVX_INSTR pcmpeqq, 0, 0, 1
-AVX_INSTR pcmpgtb, 0, 0, 0
-AVX_INSTR pcmpgtw, 0, 0, 0
-AVX_INSTR pcmpgtd, 0, 0, 0
-AVX_INSTR pcmpgtq, 0, 0, 0
-AVX_INSTR pextrb
-AVX_INSTR pextrd
-AVX_INSTR pextrq
-AVX_INSTR pextrw
-AVX_INSTR phaddw, 0, 0, 0
-AVX_INSTR phaddd, 0, 0, 0
-AVX_INSTR phaddsw, 0, 0, 0
-AVX_INSTR phminposuw
-AVX_INSTR phsubw, 0, 0, 0
-AVX_INSTR phsubd, 0, 0, 0
-AVX_INSTR phsubsw, 0, 0, 0
-AVX_INSTR pinsrb, 0, 1, 0
-AVX_INSTR pinsrd, 0, 1, 0
-AVX_INSTR pinsrq, 0, 1, 0
-AVX_INSTR pinsrw, 0, 1, 0
-AVX_INSTR pmaddwd, 0, 0, 1
-AVX_INSTR pmaddubsw, 0, 0, 0
-AVX_INSTR pmaxsb, 0, 0, 1
-AVX_INSTR pmaxsw, 0, 0, 1
-AVX_INSTR pmaxsd, 0, 0, 1
-AVX_INSTR pmaxub, 0, 0, 1
-AVX_INSTR pmaxuw, 0, 0, 1
-AVX_INSTR pmaxud, 0, 0, 1
-AVX_INSTR pminsb, 0, 0, 1
-AVX_INSTR pminsw, 0, 0, 1
-AVX_INSTR pminsd, 0, 0, 1
-AVX_INSTR pminub, 0, 0, 1
-AVX_INSTR pminuw, 0, 0, 1
-AVX_INSTR pminud, 0, 0, 1
-AVX_INSTR pmovmskb
-AVX_INSTR pmovsxbw
-AVX_INSTR pmovsxbd
-AVX_INSTR pmovsxbq
-AVX_INSTR pmovsxwd
-AVX_INSTR pmovsxwq
-AVX_INSTR pmovsxdq
-AVX_INSTR pmovzxbw
-AVX_INSTR pmovzxbd
-AVX_INSTR pmovzxbq
-AVX_INSTR pmovzxwd
-AVX_INSTR pmovzxwq
-AVX_INSTR pmovzxdq
-AVX_INSTR pmuldq, 0, 0, 1
-AVX_INSTR pmulhrsw, 0, 0, 1
-AVX_INSTR pmulhuw, 0, 0, 1
-AVX_INSTR pmulhw, 0, 0, 1
-AVX_INSTR pmullw, 0, 0, 1
-AVX_INSTR pmulld, 0, 0, 1
-AVX_INSTR pmuludq, 0, 0, 1
-AVX_INSTR por, 0, 0, 1
-AVX_INSTR psadbw, 0, 0, 1
-AVX_INSTR pshufb, 0, 0, 0
-AVX_INSTR pshufd
-AVX_INSTR pshufhw
-AVX_INSTR pshuflw
-AVX_INSTR psignb, 0, 0, 0
-AVX_INSTR psignw, 0, 0, 0
-AVX_INSTR psignd, 0, 0, 0
-AVX_INSTR psllw, 0, 0, 0
-AVX_INSTR pslld, 0, 0, 0
-AVX_INSTR psllq, 0, 0, 0
-AVX_INSTR pslldq, 0, 0, 0
-AVX_INSTR psraw, 0, 0, 0
-AVX_INSTR psrad, 0, 0, 0
-AVX_INSTR psrlw, 0, 0, 0
-AVX_INSTR psrld, 0, 0, 0
-AVX_INSTR psrlq, 0, 0, 0
-AVX_INSTR psrldq, 0, 0, 0
-AVX_INSTR psubb, 0, 0, 0
-AVX_INSTR psubw, 0, 0, 0
-AVX_INSTR psubd, 0, 0, 0
-AVX_INSTR psubq, 0, 0, 0
-AVX_INSTR psubsb, 0, 0, 0
-AVX_INSTR psubsw, 0, 0, 0
-AVX_INSTR psubusb, 0, 0, 0
-AVX_INSTR psubusw, 0, 0, 0
-AVX_INSTR ptest
-AVX_INSTR punpckhbw, 0, 0, 0
-AVX_INSTR punpckhwd, 0, 0, 0
-AVX_INSTR punpckhdq, 0, 0, 0
-AVX_INSTR punpckhqdq, 0, 0, 0
-AVX_INSTR punpcklbw, 0, 0, 0
-AVX_INSTR punpcklwd, 0, 0, 0
-AVX_INSTR punpckldq, 0, 0, 0
-AVX_INSTR punpcklqdq, 0, 0, 0
-AVX_INSTR pxor, 0, 0, 1
-AVX_INSTR rcpps, 1, 0, 0
-AVX_INSTR rcpss, 1, 0, 0
-AVX_INSTR roundpd
-AVX_INSTR roundps
-AVX_INSTR roundsd
-AVX_INSTR roundss
-AVX_INSTR rsqrtps, 1, 0, 0
-AVX_INSTR rsqrtss, 1, 0, 0
-AVX_INSTR shufpd, 1, 1, 0
-AVX_INSTR shufps, 1, 1, 0
-AVX_INSTR sqrtpd, 1, 0, 0
-AVX_INSTR sqrtps, 1, 0, 0
-AVX_INSTR sqrtsd, 1, 0, 0
-AVX_INSTR sqrtss, 1, 0, 0
-AVX_INSTR stmxcsr
-AVX_INSTR subpd, 1, 0, 0
-AVX_INSTR subps, 1, 0, 0
-AVX_INSTR subsd, 1, 0, 0
-AVX_INSTR subss, 1, 0, 0
-AVX_INSTR ucomisd
-AVX_INSTR ucomiss
-AVX_INSTR unpckhpd, 1, 0, 0
-AVX_INSTR unpckhps, 1, 0, 0
-AVX_INSTR unpcklpd, 1, 0, 0
-AVX_INSTR unpcklps, 1, 0, 0
-AVX_INSTR xorpd, 1, 0, 1
-AVX_INSTR xorps, 1, 0, 1
+AVX_INSTR andnpd, sse2, 1, 0, 0
+AVX_INSTR andnps, sse, 1, 0, 0
+AVX_INSTR andpd, sse2, 1, 0, 1
+AVX_INSTR andps, sse, 1, 0, 1
+AVX_INSTR blendpd, sse4, 1, 0, 0
+AVX_INSTR blendps, sse4, 1, 0, 0
+AVX_INSTR blendvpd, sse4, 1, 0, 0
+AVX_INSTR blendvps, sse4, 1, 0, 0
+AVX_INSTR cmppd, sse2, 1, 1, 0
+AVX_INSTR cmpps, sse, 1, 1, 0
+AVX_INSTR cmpsd, sse2, 1, 1, 0
+AVX_INSTR cmpss, sse, 1, 1, 0
+AVX_INSTR comisd, sse2
+AVX_INSTR comiss, sse
+AVX_INSTR cvtdq2pd, sse2
+AVX_INSTR cvtdq2ps, sse2
+AVX_INSTR cvtpd2dq, sse2
+AVX_INSTR cvtpd2ps, sse2
+AVX_INSTR cvtps2dq, sse2
+AVX_INSTR cvtps2pd, sse2
+AVX_INSTR cvtsd2si, sse2
+AVX_INSTR cvtsd2ss, sse2
+AVX_INSTR cvtsi2sd, sse2
+AVX_INSTR cvtsi2ss, sse
+AVX_INSTR cvtss2sd, sse2
+AVX_INSTR cvtss2si, sse
+AVX_INSTR cvttpd2dq, sse2
+AVX_INSTR cvttps2dq, sse2
+AVX_INSTR cvttsd2si, sse2
+AVX_INSTR cvttss2si, sse
+AVX_INSTR divpd, sse2, 1, 0, 0
+AVX_INSTR divps, sse, 1, 0, 0
+AVX_INSTR divsd, sse2, 1, 0, 0
+AVX_INSTR divss, sse, 1, 0, 0
+AVX_INSTR dppd, sse4, 1, 1, 0
+AVX_INSTR dpps, sse4, 1, 1, 0
+AVX_INSTR extractps, sse4
+AVX_INSTR haddpd, sse3, 1, 0, 0
+AVX_INSTR haddps, sse3, 1, 0, 0
+AVX_INSTR hsubpd, sse3, 1, 0, 0
+AVX_INSTR hsubps, sse3, 1, 0, 0
+AVX_INSTR insertps, sse4, 1, 1, 0
+AVX_INSTR lddqu, sse3
+AVX_INSTR ldmxcsr, sse
+AVX_INSTR maskmovdqu, sse2
+AVX_INSTR maxpd, sse2, 1, 0, 1
+AVX_INSTR maxps, sse, 1, 0, 1
+AVX_INSTR maxsd, sse2, 1, 0, 1
+AVX_INSTR maxss, sse, 1, 0, 1
+AVX_INSTR minpd, sse2, 1, 0, 1
+AVX_INSTR minps, sse, 1, 0, 1
+AVX_INSTR minsd, sse2, 1, 0, 1
+AVX_INSTR minss, sse, 1, 0, 1
+AVX_INSTR movapd, sse2
+AVX_INSTR movaps, sse
+AVX_INSTR movd, mmx
+AVX_INSTR movddup, sse3
+AVX_INSTR movdqa, sse2
+AVX_INSTR movdqu, sse2
+AVX_INSTR movhlps, sse, 1, 0, 0
+AVX_INSTR movhpd, sse2, 1, 0, 0
+AVX_INSTR movhps, sse, 1, 0, 0
+AVX_INSTR movlhps, sse, 1, 0, 0
+AVX_INSTR movlpd, sse2, 1, 0, 0
+AVX_INSTR movlps, sse, 1, 0, 0
+AVX_INSTR movmskpd, sse2
+AVX_INSTR movmskps, sse
+AVX_INSTR movntdq, sse2
+AVX_INSTR movntdqa, sse4
+AVX_INSTR movntpd, sse2
+AVX_INSTR movntps, sse
+AVX_INSTR movq, mmx
+AVX_INSTR movsd, sse2, 1, 0, 0
+AVX_INSTR movshdup, sse3
+AVX_INSTR movsldup, sse3
+AVX_INSTR movss, sse, 1, 0, 0
+AVX_INSTR movupd, sse2
+AVX_INSTR movups, sse
+AVX_INSTR mpsadbw, sse4
+AVX_INSTR mulpd, sse2, 1, 0, 1
+AVX_INSTR mulps, sse, 1, 0, 1
+AVX_INSTR mulsd, sse2, 1, 0, 1
+AVX_INSTR mulss, sse, 1, 0, 1
+AVX_INSTR orpd, sse2, 1, 0, 1
+AVX_INSTR orps, sse, 1, 0, 1
+AVX_INSTR pabsb, ssse3
+AVX_INSTR pabsd, ssse3
+AVX_INSTR pabsw, ssse3
+AVX_INSTR packsswb, mmx, 0, 0, 0
+AVX_INSTR packssdw, mmx, 0, 0, 0
+AVX_INSTR packuswb, mmx, 0, 0, 0
+AVX_INSTR packusdw, sse4, 0, 0, 0
+AVX_INSTR paddb, mmx, 0, 0, 1
+AVX_INSTR paddw, mmx, 0, 0, 1
+AVX_INSTR paddd, mmx, 0, 0, 1
+AVX_INSTR paddq, sse2, 0, 0, 1
+AVX_INSTR paddsb, mmx, 0, 0, 1
+AVX_INSTR paddsw, mmx, 0, 0, 1
+AVX_INSTR paddusb, mmx, 0, 0, 1
+AVX_INSTR paddusw, mmx, 0, 0, 1
+AVX_INSTR palignr, ssse3
+AVX_INSTR pand, mmx, 0, 0, 1
+AVX_INSTR pandn, mmx, 0, 0, 0
+AVX_INSTR pavgb, mmx2, 0, 0, 1
+AVX_INSTR pavgw, mmx2, 0, 0, 1
+AVX_INSTR pblendvb, sse4, 0, 0, 0
+AVX_INSTR pblendw, sse4
+AVX_INSTR pclmulqdq
+AVX_INSTR pcmpestri, sse42
+AVX_INSTR pcmpestrm, sse42
+AVX_INSTR pcmpistri, sse42
+AVX_INSTR pcmpistrm, sse42
+AVX_INSTR pcmpeqb, mmx, 0, 0, 1
+AVX_INSTR pcmpeqw, mmx, 0, 0, 1
+AVX_INSTR pcmpeqd, mmx, 0, 0, 1
+AVX_INSTR pcmpeqq, sse4, 0, 0, 1
+AVX_INSTR pcmpgtb, mmx, 0, 0, 0
+AVX_INSTR pcmpgtw, mmx, 0, 0, 0
+AVX_INSTR pcmpgtd, mmx, 0, 0, 0
+AVX_INSTR pcmpgtq, sse42, 0, 0, 0
+AVX_INSTR pextrb, sse4
+AVX_INSTR pextrd, sse4
+AVX_INSTR pextrq, sse4
+AVX_INSTR pextrw, mmx2
+AVX_INSTR phaddw, ssse3, 0, 0, 0
+AVX_INSTR phaddd, ssse3, 0, 0, 0
+AVX_INSTR phaddsw, ssse3, 0, 0, 0
+AVX_INSTR phminposuw, sse4
+AVX_INSTR phsubw, ssse3, 0, 0, 0
+AVX_INSTR phsubd, ssse3, 0, 0, 0
+AVX_INSTR phsubsw, ssse3, 0, 0, 0
+AVX_INSTR pinsrb, sse4
+AVX_INSTR pinsrd, sse4
+AVX_INSTR pinsrq, sse4
+AVX_INSTR pinsrw, mmx2
+AVX_INSTR pmaddwd, mmx, 0, 0, 1
+AVX_INSTR pmaddubsw, ssse3, 0, 0, 0
+AVX_INSTR pmaxsb, sse4, 0, 0, 1
+AVX_INSTR pmaxsw, mmx2, 0, 0, 1
+AVX_INSTR pmaxsd, sse4, 0, 0, 1
+AVX_INSTR pmaxub, mmx2, 0, 0, 1
+AVX_INSTR pmaxuw, sse4, 0, 0, 1
+AVX_INSTR pmaxud, sse4, 0, 0, 1
+AVX_INSTR pminsb, sse4, 0, 0, 1
+AVX_INSTR pminsw, mmx2, 0, 0, 1
+AVX_INSTR pminsd, sse4, 0, 0, 1
+AVX_INSTR pminub, mmx2, 0, 0, 1
+AVX_INSTR pminuw, sse4, 0, 0, 1
+AVX_INSTR pminud, sse4, 0, 0, 1
+AVX_INSTR pmovmskb, mmx2
+AVX_INSTR pmovsxbw, sse4
+AVX_INSTR pmovsxbd, sse4
+AVX_INSTR pmovsxbq, sse4
+AVX_INSTR pmovsxwd, sse4
+AVX_INSTR pmovsxwq, sse4
+AVX_INSTR pmovsxdq, sse4
+AVX_INSTR pmovzxbw, sse4
+AVX_INSTR pmovzxbd, sse4
+AVX_INSTR pmovzxbq, sse4
+AVX_INSTR pmovzxwd, sse4
+AVX_INSTR pmovzxwq, sse4
+AVX_INSTR pmovzxdq, sse4
+AVX_INSTR pmuldq, sse4, 0, 0, 1
+AVX_INSTR pmulhrsw, ssse3, 0, 0, 1
+AVX_INSTR pmulhuw, mmx2, 0, 0, 1
+AVX_INSTR pmulhw, mmx, 0, 0, 1
+AVX_INSTR pmullw, mmx, 0, 0, 1
+AVX_INSTR pmulld, sse4, 0, 0, 1
+AVX_INSTR pmuludq, sse2, 0, 0, 1
+AVX_INSTR por, mmx, 0, 0, 1
+AVX_INSTR psadbw, mmx2, 0, 0, 1
+AVX_INSTR pshufb, ssse3, 0, 0, 0
+AVX_INSTR pshufd, sse2
+AVX_INSTR pshufhw, sse2
+AVX_INSTR pshuflw, sse2
+AVX_INSTR psignb, ssse3, 0, 0, 0
+AVX_INSTR psignw, ssse3, 0, 0, 0
+AVX_INSTR psignd, ssse3, 0, 0, 0
+AVX_INSTR psllw, mmx, 0, 0, 0
+AVX_INSTR pslld, mmx, 0, 0, 0
+AVX_INSTR psllq, mmx, 0, 0, 0
+AVX_INSTR pslldq, sse2, 0, 0, 0
+AVX_INSTR psraw, mmx, 0, 0, 0
+AVX_INSTR psrad, mmx, 0, 0, 0
+AVX_INSTR psrlw, mmx, 0, 0, 0
+AVX_INSTR psrld, mmx, 0, 0, 0
+AVX_INSTR psrlq, mmx, 0, 0, 0
+AVX_INSTR psrldq, sse2, 0, 0, 0
+AVX_INSTR psubb, mmx, 0, 0, 0
+AVX_INSTR psubw, mmx, 0, 0, 0
+AVX_INSTR psubd, mmx, 0, 0, 0
+AVX_INSTR psubq, sse2, 0, 0, 0
+AVX_INSTR psubsb, mmx, 0, 0, 0
+AVX_INSTR psubsw, mmx, 0, 0, 0
+AVX_INSTR psubusb, mmx, 0, 0, 0
+AVX_INSTR psubusw, mmx, 0, 0, 0
+AVX_INSTR ptest, sse4
+AVX_INSTR punpckhbw, mmx, 0, 0, 0
+AVX_INSTR punpckhwd, mmx, 0, 0, 0
+AVX_INSTR punpckhdq, mmx, 0, 0, 0
+AVX_INSTR punpckhqdq, sse2, 0, 0, 0
+AVX_INSTR punpcklbw, mmx, 0, 0, 0
+AVX_INSTR punpcklwd, mmx, 0, 0, 0
+AVX_INSTR punpckldq, mmx, 0, 0, 0
+AVX_INSTR punpcklqdq, sse2, 0, 0, 0
+AVX_INSTR pxor, mmx, 0, 0, 1
+AVX_INSTR rcpps, sse, 1, 0, 0
+AVX_INSTR rcpss, sse, 1, 0, 0
+AVX_INSTR roundpd, sse4
+AVX_INSTR roundps, sse4
+AVX_INSTR roundsd, sse4
+AVX_INSTR roundss, sse4
+AVX_INSTR rsqrtps, sse, 1, 0, 0
+AVX_INSTR rsqrtss, sse, 1, 0, 0
+AVX_INSTR shufpd, sse2, 1, 1, 0
+AVX_INSTR shufps, sse, 1, 1, 0
+AVX_INSTR sqrtpd, sse2, 1, 0, 0
+AVX_INSTR sqrtps, sse, 1, 0, 0
+AVX_INSTR sqrtsd, sse2, 1, 0, 0
+AVX_INSTR sqrtss, sse, 1, 0, 0
+AVX_INSTR stmxcsr, sse
+AVX_INSTR subpd, sse2, 1, 0, 0
+AVX_INSTR subps, sse, 1, 0, 0
+AVX_INSTR subsd, sse2, 1, 0, 0
+AVX_INSTR subss, sse, 1, 0, 0
+AVX_INSTR ucomisd, sse2
+AVX_INSTR ucomiss, sse
+AVX_INSTR unpckhpd, sse2, 1, 0, 0
+AVX_INSTR unpckhps, sse, 1, 0, 0
+AVX_INSTR unpcklpd, sse2, 1, 0, 0
+AVX_INSTR unpcklps, sse, 1, 0, 0
+AVX_INSTR xorpd, sse2, 1, 0, 1
+AVX_INSTR xorps, sse, 1, 0, 1
; 3DNow instructions, for sharing code between AVX, SSE and 3DN
-AVX_INSTR pfadd, 1, 0, 1
-AVX_INSTR pfsub, 1, 0, 0
-AVX_INSTR pfmul, 1, 0, 1
+AVX_INSTR pfadd, 3dnow, 1, 0, 1
+AVX_INSTR pfsub, 3dnow, 1, 0, 0
+AVX_INSTR pfmul, 3dnow, 1, 0, 1
; base-4 constants for shuffles
%assign i 0
@@ -1402,21 +1413,6 @@ AVX_INSTR pfmul, 1, 0, 1
%undef i
%undef j
-%macro FMA_INSTR 3
- %macro %1 4-7 %1, %2, %3
- %if cpuflag(xop)
- v%5 %1, %2, %3, %4
- %else
- %6 %1, %2, %3
- %7 %1, %4
- %endif
- %endmacro
-%endmacro
-
-FMA_INSTR pmacsdd, pmulld, paddd
-FMA_INSTR pmacsww, pmullw, paddw
-FMA_INSTR pmadcswd, pmaddwd, paddd
-
; tzcnt is equivalent to "rep bsf" and is backwards-compatible with bsf.
; This lets us use tzcnt without bumping the yasm version requirement yet.
%define tzcnt rep bsf
diff --git a/libavutil/x86/x86util.asm b/libavutil/x86/x86util.asm
index 9f64dd13e1..d6702c1466 100644
--- a/libavutil/x86/x86util.asm
+++ b/libavutil/x86/x86util.asm
@@ -6,20 +6,20 @@
;* Authors: Loren Merritt <lorenm@u.washington.edu>
;* Holger Lubitz <holger@lubitz.org>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -69,6 +69,15 @@
SWAP %2, %3
%endmacro
+%macro TRANSPOSE2x4x4B 5
+ SBUTTERFLY bw, %1, %2, %5
+ SBUTTERFLY bw, %3, %4, %5
+ SBUTTERFLY wd, %1, %3, %5
+ SBUTTERFLY wd, %2, %4, %5
+ SBUTTERFLY dq, %1, %2, %5
+ SBUTTERFLY dq, %3, %4, %5
+%endmacro
+
%macro TRANSPOSE2x4x4W 5
SBUTTERFLY wd, %1, %2, %5
SBUTTERFLY wd, %3, %4, %5
@@ -98,6 +107,43 @@
SWAP %5, %2, %3
%endmacro
+%macro TRANSPOSE8x4D 9-11
+%if ARCH_X86_64
+ SBUTTERFLY dq, %1, %2, %9
+ SBUTTERFLY dq, %3, %4, %9
+ SBUTTERFLY dq, %5, %6, %9
+ SBUTTERFLY dq, %7, %8, %9
+ SBUTTERFLY qdq, %1, %3, %9
+ SBUTTERFLY qdq, %2, %4, %9
+ SBUTTERFLY qdq, %5, %7, %9
+ SBUTTERFLY qdq, %6, %8, %9
+ SWAP %2, %5
+ SWAP %4, %7
+%else
+; in: m0..m7
+; out: m0..m7, unless %11 in which case m2 is in %9
+; spills into %9 and %10
+ movdqa %9, m%7
+ SBUTTERFLY dq, %1, %2, %7
+ movdqa %10, m%2
+ movdqa m%7, %9
+ SBUTTERFLY dq, %3, %4, %2
+ SBUTTERFLY dq, %5, %6, %2
+ SBUTTERFLY dq, %7, %8, %2
+ SBUTTERFLY qdq, %1, %3, %2
+ movdqa %9, m%3
+ movdqa m%2, %10
+ SBUTTERFLY qdq, %2, %4, %3
+ SBUTTERFLY qdq, %5, %7, %3
+ SBUTTERFLY qdq, %6, %8, %3
+ SWAP %2, %5
+ SWAP %4, %7
+%if %0<11
+ movdqa m%3, %9
+%endif
+%endif
+%endmacro
+
%macro TRANSPOSE8x8W 9-11
%if ARCH_X86_64
SBUTTERFLY wd, %1, %2, %9
@@ -273,6 +319,44 @@
%endif
%endmacro
+%macro HADDD 2 ; sum junk
+%if sizeof%1 == 32
+%define %2 xmm%2
+ vextracti128 %2, %1, 1
+%define %1 xmm%1
+ paddd %1, %2
+%endif
+%if mmsize >= 16
+%if cpuflag(xop) && sizeof%1 == 16
+ vphadddq %1, %1
+%endif
+ movhlps %2, %1
+ paddd %1, %2
+%endif
+%if notcpuflag(xop) || sizeof%1 != 16
+%if cpuflag(mmxext)
+ PSHUFLW %2, %1, q0032
+%else ; mmx
+ mova %2, %1
+ psrlq %2, 32
+%endif
+ paddd %1, %2
+%endif
+%undef %1
+%undef %2
+%endmacro
+
+%macro HADDW 2 ; reg, tmp
+%if cpuflag(xop) && sizeof%1 == 16
+ vphaddwq %1, %1
+ movhlps %2, %1
+ paddd %1, %2
+%else
+ pmaddwd %1, [pw_1]
+ HADDD %1, %2
+%endif
+%endmacro
+
%macro PALIGNR 4-5
%if cpuflag(ssse3)
%if %0==5
@@ -302,11 +386,19 @@
%endif
%endmacro
-%macro PAVGB 2
+%macro PAVGB 2-4
%if cpuflag(mmxext)
pavgb %1, %2
%elif cpuflag(3dnow)
pavgusb %1, %2
+%elif cpuflag(mmx)
+ movu %3, %2
+ por %3, %1
+ pxor %1, %2
+ pand %1, %4
+ psrlq %1, 1
+ psubb %3, %1
+ SWAP %1, %3
%endif
%endmacro
@@ -552,7 +644,9 @@
%endmacro
%macro SPLATW 2-3 0
-%if mmsize == 16
+%if cpuflag(avx2) && %3 == 0
+ vpbroadcastw %1, %2
+%elif mmsize == 16
pshuflw %1, %2, (%3)*0x55
punpcklqdq %1, %1
%elif cpuflag(mmxext)
@@ -671,6 +765,25 @@
%endif
%endmacro
+%macro PMA_EMU 4
+ %macro %1 5-8 %2, %3, %4
+ %if cpuflag(xop)
+ v%6 %1, %2, %3, %4
+ %elifidn %1, %4
+ %7 %5, %2, %3
+ %8 %1, %4, %5
+ %else
+ %7 %1, %2, %3
+ %8 %1, %4
+ %endif
+ %endmacro
+%endmacro
+
+PMA_EMU PMACSWW, pmacsww, pmullw, paddw
+PMA_EMU PMACSDD, pmacsdd, pmulld, paddd ; sse4 emulation
+PMA_EMU PMACSDQL, pmacsdql, pmuldq, paddq ; sse4 emulation
+PMA_EMU PMADCSWD, pmadcswd, pmaddwd, paddd
+
; Wrapper for non-FMA version of fmaddps
%macro FMULADD_PS 5
%if cpuflag(fma3) || cpuflag(fma4)
@@ -683,3 +796,19 @@
addps %1, %4
%endif
%endmacro
+
+%macro LSHIFT 2
+%if mmsize > 8
+ pslldq %1, %2
+%else
+ psllq %1, 8*(%2)
+%endif
+%endmacro
+
+%macro RSHIFT 2
+%if mmsize > 8
+ psrldq %1, %2
+%else
+ psrlq %1, 8*(%2)
+%endif
+%endmacro
diff --git a/libavutil/x86_cpu.h b/libavutil/x86_cpu.h
new file mode 100644
index 0000000000..bec1c77776
--- /dev/null
+++ b/libavutil/x86_cpu.h
@@ -0,0 +1 @@
+#include "libavutil/x86/asm.h"
diff --git a/libavutil/xga_font_data.c b/libavutil/xga_font_data.c
new file mode 100644
index 0000000000..3aed3142cf
--- /dev/null
+++ b/libavutil/xga_font_data.c
@@ -0,0 +1,417 @@
+/*
+ * CGA/EGA/VGA ROM font data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * CGA/EGA/VGA ROM font data
+ */
+
+#include <stdint.h>
+#include "xga_font_data.h"
+
+const uint8_t avpriv_cga_font[2048] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
+ 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
+ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c,
+ 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
+ 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
+ 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
+ 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0,
+ 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99,
+ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff,
+ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
+ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
+ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,
+ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00,
+ 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,
+ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,
+ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
+ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,
+ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
+ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,
+ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
+ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
+ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
+ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,
+ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,
+ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00,
+ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,
+ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,
+ 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
+ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,
+ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
+ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,
+ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
+ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,
+ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
+ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,
+ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
+ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,
+ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
+ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00,
+ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00,
+ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38,
+ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,
+ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00,
+ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00,
+ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,
+ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00,
+ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18,
+ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,
+ 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
+ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00,
+ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
+ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f,
+ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,
+ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0,
+ 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00,
+ 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00,
+ 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0,
+ 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,
+ 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,
+ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,
+ 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
+ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
+ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c,
+ 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const uint8_t avpriv_vga16_font[4096] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
+ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
+ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
+ 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
+ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/libavutil/xga_font_data.h b/libavutil/xga_font_data.h
new file mode 100644
index 0000000000..5e40f542e4
--- /dev/null
+++ b/libavutil/xga_font_data.h
@@ -0,0 +1,35 @@
+/*
+ * CGA/EGA/VGA ROM font data
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * CGA/EGA/VGA ROM font data
+ */
+
+#ifndef AVUTIL_XGA_FONT_DATA_H
+#define AVUTIL_XGA_FONT_DATA_H
+
+#include <stdint.h>
+#include "internal.h"
+
+extern av_export const uint8_t avpriv_cga_font[2048];
+extern av_export const uint8_t avpriv_vga16_font[4096];
+
+#endif /* AVUTIL_XGA_FONT_DATA_H */
diff --git a/libavutil/xtea.c b/libavutil/xtea.c
index 53c0bfe603..1750cbc45a 100644
--- a/libavutil/xtea.c
+++ b/libavutil/xtea.c
@@ -4,20 +4,20 @@
*
* loosely based on the implementation of David Wheeler and Roger Needham
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -45,32 +45,116 @@ static void xtea_crypt_ecb(AVXTEA *ctx, uint8_t *dst, const uint8_t *src,
int decrypt, uint8_t *iv)
{
uint32_t v0, v1;
- int i;
+#if !CONFIG_SMALL
+ uint32_t k0 = ctx->key[0];
+ uint32_t k1 = ctx->key[1];
+ uint32_t k2 = ctx->key[2];
+ uint32_t k3 = ctx->key[3];
+#endif
v0 = AV_RB32(src);
v1 = AV_RB32(src + 4);
if (decrypt) {
- uint32_t delta = 0x9E3779B9, sum = delta * 32;
+#if CONFIG_SMALL
+ int i;
+ uint32_t delta = 0x9E3779B9U, sum = delta * 32;
for (i = 0; i < 32; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]);
}
+#else
+#define DSTEP(SUM, K0, K1) \
+ v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (SUM + K0); \
+ v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (SUM - 0x9E3779B9U + K1)
+
+ DSTEP(0xC6EF3720U, k2, k3);
+ DSTEP(0x28B7BD67U, k3, k2);
+ DSTEP(0x8A8043AEU, k0, k1);
+ DSTEP(0xEC48C9F5U, k1, k0);
+ DSTEP(0x4E11503CU, k2, k3);
+ DSTEP(0xAFD9D683U, k2, k2);
+ DSTEP(0x11A25CCAU, k3, k1);
+ DSTEP(0x736AE311U, k0, k0);
+ DSTEP(0xD5336958U, k1, k3);
+ DSTEP(0x36FBEF9FU, k1, k2);
+ DSTEP(0x98C475E6U, k2, k1);
+ DSTEP(0xFA8CFC2DU, k3, k0);
+ DSTEP(0x5C558274U, k0, k3);
+ DSTEP(0xBE1E08BBU, k1, k2);
+ DSTEP(0x1FE68F02U, k1, k1);
+ DSTEP(0x81AF1549U, k2, k0);
+ DSTEP(0xE3779B90U, k3, k3);
+ DSTEP(0x454021D7U, k0, k2);
+ DSTEP(0xA708A81EU, k1, k1);
+ DSTEP(0x08D12E65U, k1, k0);
+ DSTEP(0x6A99B4ACU, k2, k3);
+ DSTEP(0xCC623AF3U, k3, k2);
+ DSTEP(0x2E2AC13AU, k0, k1);
+ DSTEP(0x8FF34781U, k0, k0);
+ DSTEP(0xF1BBCDC8U, k1, k3);
+ DSTEP(0x5384540FU, k2, k2);
+ DSTEP(0xB54CDA56U, k3, k1);
+ DSTEP(0x1715609DU, k0, k0);
+ DSTEP(0x78DDE6E4U, k0, k3);
+ DSTEP(0xDAA66D2BU, k1, k2);
+ DSTEP(0x3C6EF372U, k2, k1);
+ DSTEP(0x9E3779B9U, k3, k0);
+#endif
if (iv) {
v0 ^= AV_RB32(iv);
v1 ^= AV_RB32(iv + 4);
memcpy(iv, src, 8);
}
} else {
- uint32_t sum = 0, delta = 0x9E3779B9;
+#if CONFIG_SMALL
+ int i;
+ uint32_t sum = 0, delta = 0x9E3779B9U;
for (i = 0; i < 32; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]);
}
+#else
+#define ESTEP(SUM, K0, K1) \
+ v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (SUM + K0);\
+ v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (SUM + 0x9E3779B9U + K1)
+ ESTEP(0x00000000U, k0, k3);
+ ESTEP(0x9E3779B9U, k1, k2);
+ ESTEP(0x3C6EF372U, k2, k1);
+ ESTEP(0xDAA66D2BU, k3, k0);
+ ESTEP(0x78DDE6E4U, k0, k0);
+ ESTEP(0x1715609DU, k1, k3);
+ ESTEP(0xB54CDA56U, k2, k2);
+ ESTEP(0x5384540FU, k3, k1);
+ ESTEP(0xF1BBCDC8U, k0, k0);
+ ESTEP(0x8FF34781U, k1, k0);
+ ESTEP(0x2E2AC13AU, k2, k3);
+ ESTEP(0xCC623AF3U, k3, k2);
+ ESTEP(0x6A99B4ACU, k0, k1);
+ ESTEP(0x08D12E65U, k1, k1);
+ ESTEP(0xA708A81EU, k2, k0);
+ ESTEP(0x454021D7U, k3, k3);
+ ESTEP(0xE3779B90U, k0, k2);
+ ESTEP(0x81AF1549U, k1, k1);
+ ESTEP(0x1FE68F02U, k2, k1);
+ ESTEP(0xBE1E08BBU, k3, k0);
+ ESTEP(0x5C558274U, k0, k3);
+ ESTEP(0xFA8CFC2DU, k1, k2);
+ ESTEP(0x98C475E6U, k2, k1);
+ ESTEP(0x36FBEF9FU, k3, k1);
+ ESTEP(0xD5336958U, k0, k0);
+ ESTEP(0x736AE311U, k1, k3);
+ ESTEP(0x11A25CCAU, k2, k2);
+ ESTEP(0xAFD9D683U, k3, k2);
+ ESTEP(0x4E11503CU, k0, k1);
+ ESTEP(0xEC48C9F5U, k1, k0);
+ ESTEP(0x8A8043AEU, k2, k3);
+ ESTEP(0x28B7BD67U, k3, k2);
+#endif
}
AV_WB32(dst, v0);
@@ -166,7 +250,7 @@ int main(void)
AVXTEA ctx;
uint8_t buf[8], iv[8];
int i;
- const uint8_t src[32] = "HelloWorldHelloWorldHelloWorld";
+ static const uint8_t src[32] = "HelloWorldHelloWorldHelloWorld";
uint8_t ct[32];
uint8_t pl[32];
@@ -187,6 +271,7 @@ int main(void)
memcpy(iv, "HALLO123", 8);
test_xtea(&ctx, ct, ct, src, 4, iv, 1, "CBC inplace decryption");
}
+
printf("Test encryption/decryption success.\n");
return 0;
diff --git a/libavutil/xtea.h b/libavutil/xtea.h
index 0fc3810dd2..6f1e71e345 100644
--- a/libavutil/xtea.h
+++ b/libavutil/xtea.h
@@ -1,20 +1,21 @@
/*
* A 32-bit implementation of the XTEA algorithm
+ * Copyright (c) 2012 Samuel Pitoiset
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libpostproc/Makefile b/libpostproc/Makefile
new file mode 100644
index 0000000000..b9bb4beb8a
--- /dev/null
+++ b/libpostproc/Makefile
@@ -0,0 +1,12 @@
+include $(SUBDIR)../config.mak
+
+NAME = postproc
+FFLIBS = avutil
+
+HEADERS = postprocess.h \
+ version.h \
+
+OBJS = postprocess.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += postprocres.o
diff --git a/libpostproc/libpostproc.v b/libpostproc/libpostproc.v
new file mode 100644
index 0000000000..e65d76f4f6
--- /dev/null
+++ b/libpostproc/libpostproc.v
@@ -0,0 +1,4 @@
+LIBPOSTPROC_$MAJOR {
+ global: postproc_*; pp_*;
+ local: *;
+};
diff --git a/libpostproc/postprocess.c b/libpostproc/postprocess.c
new file mode 100644
index 0000000000..acce0f273b
--- /dev/null
+++ b/libpostproc/postprocess.c
@@ -0,0 +1,1043 @@
+/*
+ * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * AltiVec optimizations (C) 2004 Romain Dolbeau <romain@dolbeau.org>
+ *
+ * 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
+ * postprocessing.
+ */
+
+/*
+ C MMX MMX2 3DNow AltiVec
+isVertDC Ec Ec Ec
+isVertMinMaxOk Ec Ec Ec
+doVertLowPass E e e Ec
+doVertDefFilter Ec Ec e e Ec
+isHorizDC Ec Ec Ec
+isHorizMinMaxOk a E Ec
+doHorizLowPass E e e Ec
+doHorizDefFilter Ec Ec e e Ec
+do_a_deblock Ec E Ec E
+deRing E e e* Ecp
+Vertical RKAlgo1 E a a
+Horizontal RKAlgo1 a a
+Vertical X1# a E E
+Horizontal X1# a E E
+LinIpolDeinterlace e E E*
+CubicIpolDeinterlace a e e*
+LinBlendDeinterlace e E E*
+MedianDeinterlace# E Ec Ec
+TempDeNoiser# E e e Ec
+
+* I do not have a 3DNow! CPU -> it is untested, but no one said it does not work so it seems to work
+# more or less selfinvented filters so the exactness is not too meaningful
+E = Exact implementation
+e = almost exact implementation (slightly different rounding,...)
+a = alternative / approximate impl
+c = checked against the other implementations (-vo md5)
+p = partially optimized, still some work to do
+*/
+
+/*
+TODO:
+reduce the time wasted on the mem transfer
+unroll stuff if instructions depend too much on the prior one
+move YScale thing to the end instead of fixing QP
+write a faster and higher quality deblocking filter :)
+make the mainloop more flexible (variable number of blocks at once
+ (the if/else stuff per block is slowing things down)
+compare the quality & speed of all filters
+split this huge file
+optimize c versions
+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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+//#undef HAVE_MMXEXT_INLINE
+//#define HAVE_AMD3DNOW_INLINE
+//#undef HAVE_MMX_INLINE
+//#undef ARCH_X86
+//#define DEBUG_BRIGHTNESS
+#include "postprocess.h"
+#include "postprocess_internal.h"
+#include "libavutil/avstring.h"
+
+#include "libavutil/ffversion.h"
+const char postproc_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
+unsigned postproc_version(void)
+{
+ av_assert0(LIBPOSTPROC_VERSION_MICRO >= 100);
+ return LIBPOSTPROC_VERSION_INT;
+}
+
+const char *postproc_configuration(void)
+{
+ return FFMPEG_CONFIGURATION;
+}
+
+const char *postproc_license(void)
+{
+#define LICENSE_PREFIX "libpostproc license: "
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+}
+
+#if HAVE_ALTIVEC_H
+#include <altivec.h>
+#endif
+
+#define GET_MODE_BUFFER_SIZE 500
+#define OPTIONS_ARRAY_SIZE 10
+#define BLOCK_SIZE 8
+#define TEMP_STRIDE 8
+//#define NUM_BLOCKS_AT_ONCE 16 //not used yet
+
+#if ARCH_X86 && HAVE_INLINE_ASM
+DECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL;
+DECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL;
+DECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL;
+DECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL;
+DECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL;
+DECLARE_ASM_CONST(8, uint64_t, b02)= 0x0202020202020202LL;
+DECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL;
+DECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL;
+#endif
+
+DECLARE_ASM_CONST(8, int, deringThreshold)= 20;
+
+
+static const struct PPFilter filters[]=
+{
+ {"hb", "hdeblock", 1, 1, 3, H_DEBLOCK},
+ {"vb", "vdeblock", 1, 2, 4, V_DEBLOCK},
+/* {"hr", "rkhdeblock", 1, 1, 3, H_RK1_FILTER},
+ {"vr", "rkvdeblock", 1, 2, 4, V_RK1_FILTER},*/
+ {"h1", "x1hdeblock", 1, 1, 3, H_X1_FILTER},
+ {"v1", "x1vdeblock", 1, 2, 4, V_X1_FILTER},
+ {"ha", "ahdeblock", 1, 1, 3, H_A_DEBLOCK},
+ {"va", "avdeblock", 1, 2, 4, V_A_DEBLOCK},
+ {"dr", "dering", 1, 5, 6, DERING},
+ {"al", "autolevels", 0, 1, 2, LEVEL_FIX},
+ {"lb", "linblenddeint", 1, 1, 4, LINEAR_BLEND_DEINT_FILTER},
+ {"li", "linipoldeint", 1, 1, 4, LINEAR_IPOL_DEINT_FILTER},
+ {"ci", "cubicipoldeint", 1, 1, 4, CUBIC_IPOL_DEINT_FILTER},
+ {"md", "mediandeint", 1, 1, 4, MEDIAN_DEINT_FILTER},
+ {"fd", "ffmpegdeint", 1, 1, 4, FFMPEG_DEINT_FILTER},
+ {"l5", "lowpass5", 1, 1, 4, LOWPASS5_DEINT_FILTER},
+ {"tn", "tmpnoise", 1, 7, 8, TEMP_NOISE_FILTER},
+ {"fq", "forcequant", 1, 0, 0, FORCE_QUANT},
+ {"be", "bitexact", 1, 0, 0, BITEXACT},
+ {"vi", "visualize", 1, 0, 0, VISUALIZE},
+ {NULL, NULL,0,0,0,0} //End Marker
+};
+
+static const char * const replaceTable[]=
+{
+ "default", "hb:a,vb:a,dr:a",
+ "de", "hb:a,vb:a,dr:a",
+ "fast", "h1:a,v1:a,dr:a",
+ "fa", "h1:a,v1:a,dr:a",
+ "ac", "ha:a:128:7,va:a,dr:a",
+ NULL //End Marker
+};
+
+/* The horizontal functions exist only in C because the MMX
+ * code is faster with vertical filters and transposing. */
+
+/**
+ * Check if the given 8x8 Block is mostly "flat"
+ */
+static inline int isHorizDC_C(const uint8_t src[], int stride, const PPContext *c)
+{
+ int numEq= 0;
+ int y;
+ const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
+ const int dcThreshold= dcOffset*2 + 1;
+
+ for(y=0; y<BLOCK_SIZE; y++){
+ numEq += ((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold;
+ src+= stride;
+ }
+ return numEq > c->ppMode.flatnessThreshold;
+}
+
+/**
+ * Check if the middle 8x8 Block in the given 8x16 block is flat
+ */
+static inline int isVertDC_C(const uint8_t src[], int stride, const PPContext *c)
+{
+ int numEq= 0;
+ int y;
+ const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
+ const int dcThreshold= dcOffset*2 + 1;
+
+ src+= stride*4; // src points to begin of the 8x8 Block
+ for(y=0; y<BLOCK_SIZE-1; y++){
+ numEq += ((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold;
+ src+= stride;
+ }
+ return numEq > c->ppMode.flatnessThreshold;
+}
+
+static inline int isHorizMinMaxOk_C(const uint8_t src[], int stride, int QP)
+{
+ int i;
+ for(i=0; i<2; i++){
+ if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;
+ src += stride;
+ if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;
+ src += stride;
+ if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;
+ src += stride;
+ if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;
+ src += stride;
+ }
+ return 1;
+}
+
+static inline int isVertMinMaxOk_C(const uint8_t src[], int stride, int QP)
+{
+ int x;
+ src+= stride*4;
+ for(x=0; x<BLOCK_SIZE; x+=4){
+ if((unsigned)(src[ x + 0*stride] - src[ x + 5*stride] + 2*QP) > 4*QP) return 0;
+ if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;
+ if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;
+ if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;
+ }
+ return 1;
+}
+
+static inline int horizClassify_C(const uint8_t src[], int stride, const PPContext *c)
+{
+ if( isHorizDC_C(src, stride, c) ){
+ return isHorizMinMaxOk_C(src, stride, c->QP);
+ }else{
+ return 2;
+ }
+}
+
+static inline int vertClassify_C(const uint8_t src[], int stride, const PPContext *c)
+{
+ if( isVertDC_C(src, stride, c) ){
+ return isVertMinMaxOk_C(src, stride, c->QP);
+ }else{
+ return 2;
+ }
+}
+
+static inline void doHorizDefFilter_C(uint8_t dst[], int stride, const PPContext *c)
+{
+ int y;
+ for(y=0; y<BLOCK_SIZE; y++){
+ const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);
+
+ if(FFABS(middleEnergy) < 8*c->QP){
+ const int q=(dst[3] - dst[4])/2;
+ const int leftEnergy= 5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);
+ const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);
+
+ int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
+ d= FFMAX(d, 0);
+
+ d= (5*d + 32) >> 6;
+ d*= FFSIGN(-middleEnergy);
+
+ if(q>0)
+ {
+ d = FFMAX(d, 0);
+ d = FFMIN(d, q);
+ }
+ else
+ {
+ d = FFMIN(d, 0);
+ d = FFMAX(d, q);
+ }
+
+ dst[3]-= d;
+ dst[4]+= d;
+ }
+ dst+= stride;
+ }
+}
+
+/**
+ * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block)
+ * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
+ */
+static inline void doHorizLowPass_C(uint8_t dst[], int stride, const PPContext *c)
+{
+ int y;
+ for(y=0; y<BLOCK_SIZE; y++){
+ const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];
+ const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];
+
+ int sums[10];
+ sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;
+ sums[1] = sums[0] - first + dst[3];
+ sums[2] = sums[1] - first + dst[4];
+ sums[3] = sums[2] - first + dst[5];
+ sums[4] = sums[3] - first + dst[6];
+ sums[5] = sums[4] - dst[0] + dst[7];
+ sums[6] = sums[5] - dst[1] + last;
+ sums[7] = sums[6] - dst[2] + last;
+ sums[8] = sums[7] - dst[3] + last;
+ sums[9] = sums[8] - dst[4] + last;
+
+ dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;
+ dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;
+ dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;
+ dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;
+ dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;
+ dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;
+ dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;
+ dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;
+
+ dst+= stride;
+ }
+}
+
+/**
+ * Experimental Filter 1 (Horizontal)
+ * will not damage linear gradients
+ * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter
+ * can only smooth blocks at the expected locations (it cannot smooth them if they did move)
+ * MMX2 version does correct clipping C version does not
+ * not identical with the vertical one
+ */
+static inline void horizX1Filter(uint8_t *src, int stride, int QP)
+{
+ int y;
+ static uint64_t lut[256];
+ if(!lut[255])
+ {
+ int i;
+ for(i=0; i<256; i++)
+ {
+ int v= i < 128 ? 2*i : 2*(i-256);
+/*
+//Simulate 112242211 9-Tap filter
+ uint64_t a= (v/16) & 0xFF;
+ uint64_t b= (v/8) & 0xFF;
+ uint64_t c= (v/4) & 0xFF;
+ uint64_t d= (3*v/8) & 0xFF;
+*/
+//Simulate piecewise linear interpolation
+ uint64_t a= (v/16) & 0xFF;
+ uint64_t b= (v*3/16) & 0xFF;
+ uint64_t c= (v*5/16) & 0xFF;
+ uint64_t d= (7*v/16) & 0xFF;
+ uint64_t A= (0x100 - a)&0xFF;
+ uint64_t B= (0x100 - b)&0xFF;
+ uint64_t C= (0x100 - c)&0xFF;
+ uint64_t D= (0x100 - c)&0xFF;
+
+ lut[i] = (a<<56) | (b<<48) | (c<<40) | (d<<32) |
+ (D<<24) | (C<<16) | (B<<8) | (A);
+ //lut[i] = (v<<32) | (v<<24);
+ }
+ }
+
+ for(y=0; y<BLOCK_SIZE; y++){
+ int a= src[1] - src[2];
+ int b= src[3] - src[4];
+ int c= src[5] - src[6];
+
+ int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);
+
+ if(d < QP){
+ int v = d * FFSIGN(-b);
+
+ src[1] +=v/8;
+ src[2] +=v/4;
+ src[3] +=3*v/8;
+ src[4] -=3*v/8;
+ src[5] -=v/4;
+ src[6] -=v/8;
+ }
+ src+=stride;
+ }
+}
+
+/**
+ * accurate deblock filter
+ */
+static av_always_inline void do_a_deblock_C(uint8_t *src, int step,
+ int stride, const PPContext *c, int mode)
+{
+ int y;
+ const int QP= c->QP;
+ const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
+ const int dcThreshold= dcOffset*2 + 1;
+//START_TIMER
+ src+= step*4; // src points to begin of the 8x8 Block
+ for(y=0; y<8; y++){
+ int numEq= 0;
+
+ numEq += ((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold;
+ numEq += ((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold;
+ if(numEq > c->ppMode.flatnessThreshold){
+ int min, max, x;
+
+ if(src[0] > src[step]){
+ max= src[0];
+ min= src[step];
+ }else{
+ max= src[step];
+ min= src[0];
+ }
+ for(x=2; x<8; x+=2){
+ if(src[x*step] > src[(x+1)*step]){
+ if(src[x *step] > max) max= src[ x *step];
+ if(src[(x+1)*step] < min) min= src[(x+1)*step];
+ }else{
+ if(src[(x+1)*step] > max) max= src[(x+1)*step];
+ if(src[ x *step] < min) min= src[ x *step];
+ }
+ }
+ if(max-min < 2*QP){
+ const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];
+ const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];
+
+ int sums[10];
+ sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;
+ sums[1] = sums[0] - first + src[3*step];
+ sums[2] = sums[1] - first + src[4*step];
+ sums[3] = sums[2] - first + src[5*step];
+ sums[4] = sums[3] - first + src[6*step];
+ sums[5] = sums[4] - src[0*step] + src[7*step];
+ sums[6] = sums[5] - src[1*step] + last;
+ sums[7] = sums[6] - src[2*step] + last;
+ sums[8] = sums[7] - src[3*step] + last;
+ sums[9] = sums[8] - src[4*step] + last;
+
+ if (mode & VISUALIZE) {
+ src[0*step] =
+ src[1*step] =
+ src[2*step] =
+ src[3*step] =
+ src[4*step] =
+ src[5*step] =
+ src[6*step] =
+ src[7*step] = 128;
+ }
+ src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;
+ src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;
+ src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;
+ src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;
+ src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;
+ src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;
+ src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;
+ src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;
+ }
+ }else{
+ const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);
+
+ if(FFABS(middleEnergy) < 8*QP){
+ const int q=(src[3*step] - src[4*step])/2;
+ const int leftEnergy= 5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);
+ const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);
+
+ int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
+ d= FFMAX(d, 0);
+
+ d= (5*d + 32) >> 6;
+ d*= FFSIGN(-middleEnergy);
+
+ if(q>0){
+ d = FFMAX(d, 0);
+ d = FFMIN(d, q);
+ }else{
+ d = FFMIN(d, 0);
+ d = FFMAX(d, q);
+ }
+
+ if ((mode & VISUALIZE) && d) {
+ d= (d < 0) ? 32 : -32;
+ src[3*step]= av_clip_uint8(src[3*step] - d);
+ src[4*step]= av_clip_uint8(src[4*step] + d);
+ d = 0;
+ }
+
+ src[3*step]-= d;
+ src[4*step]+= d;
+ }
+ }
+
+ src += stride;
+ }
+/*if(step==16){
+ STOP_TIMER("step16")
+}else{
+ STOP_TIMER("stepX")
+}*/
+}
+
+//Note: we have C, MMX, MMX2, 3DNOW version there is no 3DNOW+MMX2 one
+//Plain C versions
+//we always compile C for testing which needs bitexactness
+#define TEMPLATE_PP_C 1
+#include "postprocess_template.c"
+
+#if HAVE_ALTIVEC
+# define TEMPLATE_PP_ALTIVEC 1
+# include "postprocess_altivec_template.c"
+# include "postprocess_template.c"
+#endif
+
+#if ARCH_X86 && HAVE_INLINE_ASM
+# if CONFIG_RUNTIME_CPUDETECT
+# define TEMPLATE_PP_MMX 1
+# include "postprocess_template.c"
+# define TEMPLATE_PP_MMXEXT 1
+# include "postprocess_template.c"
+# define TEMPLATE_PP_3DNOW 1
+# include "postprocess_template.c"
+# define TEMPLATE_PP_SSE2 1
+# include "postprocess_template.c"
+# else
+# if HAVE_SSE2_INLINE
+# define TEMPLATE_PP_SSE2 1
+# include "postprocess_template.c"
+# elif HAVE_MMXEXT_INLINE
+# define TEMPLATE_PP_MMXEXT 1
+# include "postprocess_template.c"
+# elif HAVE_AMD3DNOW_INLINE
+# define TEMPLATE_PP_3DNOW 1
+# include "postprocess_template.c"
+# elif HAVE_MMX_INLINE
+# define TEMPLATE_PP_MMX 1
+# include "postprocess_template.c"
+# endif
+# endif
+#endif
+
+typedef void (*pp_fn)(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
+ const QP_STORE_T QPs[], int QPStride, int isColor, PPContext *c2);
+
+static inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
+ const QP_STORE_T QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc)
+{
+ pp_fn pp = postProcess_C;
+ PPContext *c= (PPContext *)vc;
+ PPMode *ppMode= (PPMode *)vm;
+ c->ppMode= *ppMode; //FIXME
+
+ if (!(ppMode->lumMode & BITEXACT)) {
+#if CONFIG_RUNTIME_CPUDETECT
+#if ARCH_X86 && HAVE_INLINE_ASM
+ // ordered per speed fastest first
+ if (c->cpuCaps & AV_CPU_FLAG_SSE2) pp = postProcess_SSE2;
+ else if (c->cpuCaps & AV_CPU_FLAG_MMXEXT) pp = postProcess_MMX2;
+ else if (c->cpuCaps & AV_CPU_FLAG_3DNOW) pp = postProcess_3DNow;
+ else if (c->cpuCaps & AV_CPU_FLAG_MMX) pp = postProcess_MMX;
+#elif HAVE_ALTIVEC
+ if (c->cpuCaps & AV_CPU_FLAG_ALTIVEC) pp = postProcess_altivec;
+#endif
+#else /* CONFIG_RUNTIME_CPUDETECT */
+#if HAVE_SSE2_INLINE
+ pp = postProcess_SSE2;
+#elif HAVE_MMXEXT_INLINE
+ pp = postProcess_MMX2;
+#elif HAVE_AMD3DNOW_INLINE
+ pp = postProcess_3DNow;
+#elif HAVE_MMX_INLINE
+ pp = postProcess_MMX;
+#elif HAVE_ALTIVEC
+ pp = postProcess_altivec;
+#endif
+#endif /* !CONFIG_RUNTIME_CPUDETECT */
+ }
+
+ pp(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
+}
+
+/* -pp Command line Help
+*/
+const char pp_help[] =
+"Available postprocessing filters:\n"
+"Filters Options\n"
+"short long name short long option Description\n"
+"* * a autoq CPU power dependent enabler\n"
+" c chrom chrominance filtering enabled\n"
+" y nochrom chrominance filtering disabled\n"
+" n noluma luma filtering disabled\n"
+"hb hdeblock (2 threshold) horizontal deblocking filter\n"
+" 1. difference factor: default=32, higher -> more deblocking\n"
+" 2. flatness threshold: default=39, lower -> more deblocking\n"
+" the h & v deblocking filters share these\n"
+" so you can't set different thresholds for h / v\n"
+"vb vdeblock (2 threshold) vertical deblocking filter\n"
+"ha hadeblock (2 threshold) horizontal deblocking filter\n"
+"va vadeblock (2 threshold) vertical deblocking filter\n"
+"h1 x1hdeblock experimental h deblock filter 1\n"
+"v1 x1vdeblock experimental v deblock filter 1\n"
+"dr dering deringing filter\n"
+"al autolevels automatic brightness / contrast\n"
+" f fullyrange stretch luminance to (0..255)\n"
+"lb linblenddeint linear blend deinterlacer\n"
+"li linipoldeint linear interpolating deinterlace\n"
+"ci cubicipoldeint cubic interpolating deinterlacer\n"
+"md mediandeint median deinterlacer\n"
+"fd ffmpegdeint ffmpeg deinterlacer\n"
+"l5 lowpass5 FIR lowpass deinterlacer\n"
+"de default hb:a,vb:a,dr:a\n"
+"fa fast h1:a,v1:a,dr:a\n"
+"ac ha:a:128:7,va:a,dr:a\n"
+"tn tmpnoise (3 threshold) temporal noise reducer\n"
+" 1. <= 2. <= 3. larger -> stronger filtering\n"
+"fq forceQuant <quantizer> force quantizer\n"
+"Usage:\n"
+"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n"
+"long form example:\n"
+"vdeblock:autoq/hdeblock:autoq/linblenddeint default,-vdeblock\n"
+"short form example:\n"
+"vb:a/hb:a/lb de,-vb\n"
+"more examples:\n"
+"tn:64:128:256\n"
+"\n"
+;
+
+pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)
+{
+ char temp[GET_MODE_BUFFER_SIZE];
+ char *p= temp;
+ static const char filterDelimiters[] = ",/";
+ static const char optionDelimiters[] = ":|";
+ struct PPMode *ppMode;
+ char *filterToken;
+
+ if (!name) {
+ av_log(NULL, AV_LOG_ERROR, "pp: Missing argument\n");
+ return NULL;
+ }
+
+ if (!strcmp(name, "help")) {
+ const char *p;
+ for (p = pp_help; strchr(p, '\n'); p = strchr(p, '\n') + 1) {
+ av_strlcpy(temp, p, FFMIN(sizeof(temp), strchr(p, '\n') - p + 2));
+ av_log(NULL, AV_LOG_INFO, "%s", temp);
+ }
+ return NULL;
+ }
+
+ ppMode= av_malloc(sizeof(PPMode));
+ if (!ppMode)
+ return NULL;
+
+ ppMode->lumMode= 0;
+ ppMode->chromMode= 0;
+ ppMode->maxTmpNoise[0]= 700;
+ ppMode->maxTmpNoise[1]= 1500;
+ ppMode->maxTmpNoise[2]= 3000;
+ ppMode->maxAllowedY= 234;
+ ppMode->minAllowedY= 16;
+ ppMode->baseDcDiff= 256/8;
+ ppMode->flatnessThreshold= 56-16-1;
+ ppMode->maxClippedThreshold= 0.01;
+ ppMode->error=0;
+
+ memset(temp, 0, GET_MODE_BUFFER_SIZE);
+ av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE - 1);
+
+ av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);
+
+ for(;;){
+ const char *filterName;
+ int q= 1000000; //PP_QUALITY_MAX;
+ int chrom=-1;
+ int luma=-1;
+ const char *option;
+ const char *options[OPTIONS_ARRAY_SIZE];
+ int i;
+ int filterNameOk=0;
+ int numOfUnknownOptions=0;
+ int enable=1; //does the user want us to enabled or disabled the filter
+ char *tokstate;
+
+ filterToken= av_strtok(p, filterDelimiters, &tokstate);
+ if(!filterToken) break;
+ p+= strlen(filterToken) + 1; // p points to next filterToken
+ filterName= av_strtok(filterToken, optionDelimiters, &tokstate);
+ if (!filterName) {
+ ppMode->error++;
+ break;
+ }
+ av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
+
+ if(*filterName == '-'){
+ enable=0;
+ filterName++;
+ }
+
+ for(;;){ //for all options
+ option= av_strtok(NULL, optionDelimiters, &tokstate);
+ if(!option) break;
+
+ av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);
+ if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;
+ else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;
+ else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;
+ else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;
+ else{
+ options[numOfUnknownOptions] = option;
+ numOfUnknownOptions++;
+ }
+ if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;
+ }
+ options[numOfUnknownOptions] = NULL;
+
+ /* replace stuff from the replace Table */
+ for(i=0; replaceTable[2*i]; i++){
+ if(!strcmp(replaceTable[2*i], filterName)){
+ size_t newlen = strlen(replaceTable[2*i + 1]);
+ int plen;
+ int spaceLeft;
+
+ p--, *p=',';
+
+ plen= strlen(p);
+ spaceLeft= p - temp + plen;
+ if(spaceLeft + newlen >= GET_MODE_BUFFER_SIZE - 1){
+ ppMode->error++;
+ break;
+ }
+ memmove(p + newlen, p, plen+1);
+ memcpy(p, replaceTable[2*i + 1], newlen);
+ filterNameOk=1;
+ }
+ }
+
+ for(i=0; filters[i].shortName; i++){
+ if( !strcmp(filters[i].longName, filterName)
+ || !strcmp(filters[i].shortName, filterName)){
+ ppMode->lumMode &= ~filters[i].mask;
+ ppMode->chromMode &= ~filters[i].mask;
+
+ filterNameOk=1;
+ if(!enable) break; // user wants to disable it
+
+ if(q >= filters[i].minLumQuality && luma)
+ ppMode->lumMode|= filters[i].mask;
+ if(chrom==1 || (chrom==-1 && filters[i].chromDefault))
+ if(q >= filters[i].minChromQuality)
+ ppMode->chromMode|= filters[i].mask;
+
+ if(filters[i].mask == LEVEL_FIX){
+ int o;
+ ppMode->minAllowedY= 16;
+ ppMode->maxAllowedY= 234;
+ for(o=0; options[o]; o++){
+ if( !strcmp(options[o],"fullyrange")
+ ||!strcmp(options[o],"f")){
+ ppMode->minAllowedY= 0;
+ ppMode->maxAllowedY= 255;
+ numOfUnknownOptions--;
+ }
+ }
+ }
+ else if(filters[i].mask == TEMP_NOISE_FILTER)
+ {
+ int o;
+ int numOfNoises=0;
+
+ for(o=0; options[o]; o++){
+ char *tail;
+ ppMode->maxTmpNoise[numOfNoises]=
+ strtol(options[o], &tail, 0);
+ if(tail!=options[o]){
+ numOfNoises++;
+ numOfUnknownOptions--;
+ if(numOfNoises >= 3) break;
+ }
+ }
+ }
+ else if(filters[i].mask == V_DEBLOCK || filters[i].mask == H_DEBLOCK
+ || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){
+ int o;
+
+ for(o=0; options[o] && o<2; o++){
+ char *tail;
+ int val= strtol(options[o], &tail, 0);
+ if(tail==options[o]) break;
+
+ numOfUnknownOptions--;
+ if(o==0) ppMode->baseDcDiff= val;
+ else ppMode->flatnessThreshold= val;
+ }
+ }
+ else if(filters[i].mask == FORCE_QUANT){
+ int o;
+ ppMode->forcedQuant= 15;
+
+ for(o=0; options[o] && o<1; o++){
+ char *tail;
+ int val= strtol(options[o], &tail, 0);
+ if(tail==options[o]) break;
+
+ numOfUnknownOptions--;
+ ppMode->forcedQuant= val;
+ }
+ }
+ }
+ }
+ if(!filterNameOk) ppMode->error++;
+ ppMode->error += numOfUnknownOptions;
+ }
+
+ av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);
+ if(ppMode->error){
+ av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);
+ av_free(ppMode);
+ return NULL;
+ }
+ return ppMode;
+}
+
+void pp_free_mode(pp_mode *mode){
+ av_free(mode);
+}
+
+static void reallocAlign(void **p, int size){
+ av_free(*p);
+ *p= av_mallocz(size);
+}
+
+static void reallocBuffers(PPContext *c, int width, int height, int stride, int qpStride){
+ int mbWidth = (width+15)>>4;
+ int mbHeight= (height+15)>>4;
+ int i;
+
+ c->stride= stride;
+ c->qpStride= qpStride;
+
+ reallocAlign((void **)&c->tempDst, stride*24+32);
+ reallocAlign((void **)&c->tempSrc, stride*24);
+ reallocAlign((void **)&c->tempBlocks, 2*16*8);
+ reallocAlign((void **)&c->yHistogram, 256*sizeof(uint64_t));
+ for(i=0; i<256; i++)
+ c->yHistogram[i]= width*height/64*15/256;
+
+ for(i=0; i<3; i++){
+ //Note: The +17*1024 is just there so I do not have to worry about r/w over the end.
+ reallocAlign((void **)&c->tempBlurred[i], stride*mbHeight*16 + 17*1024);
+ reallocAlign((void **)&c->tempBlurredPast[i], 256*((height+7)&(~7))/2 + 17*1024);//FIXME size
+ }
+
+ reallocAlign((void **)&c->deintTemp, 2*width+32);
+ reallocAlign((void **)&c->nonBQPTable, qpStride*mbHeight*sizeof(QP_STORE_T));
+ reallocAlign((void **)&c->stdQPTable, qpStride*mbHeight*sizeof(QP_STORE_T));
+ reallocAlign((void **)&c->forcedQPTable, mbWidth*sizeof(QP_STORE_T));
+}
+
+static const char * context_to_name(void * ptr) {
+ return "postproc";
+}
+
+static const AVClass av_codec_context_class = { "Postproc", context_to_name, NULL };
+
+av_cold pp_context *pp_get_context(int width, int height, int cpuCaps){
+ PPContext *c= av_mallocz(sizeof(PPContext));
+ int stride= FFALIGN(width, 16); //assumed / will realloc if needed
+ int qpStride= (width+15)/16 + 2; //assumed / will realloc if needed
+
+ if (!c)
+ return NULL;
+
+ c->av_class = &av_codec_context_class;
+ if(cpuCaps&PP_FORMAT){
+ c->hChromaSubSample= cpuCaps&0x3;
+ c->vChromaSubSample= (cpuCaps>>4)&0x3;
+ }else{
+ c->hChromaSubSample= 1;
+ c->vChromaSubSample= 1;
+ }
+ if (cpuCaps & PP_CPU_CAPS_AUTO) {
+ c->cpuCaps = av_get_cpu_flags();
+ } else {
+ c->cpuCaps = 0;
+ if (cpuCaps & PP_CPU_CAPS_MMX) c->cpuCaps |= AV_CPU_FLAG_MMX;
+ if (cpuCaps & PP_CPU_CAPS_MMX2) c->cpuCaps |= AV_CPU_FLAG_MMXEXT;
+ if (cpuCaps & PP_CPU_CAPS_3DNOW) c->cpuCaps |= AV_CPU_FLAG_3DNOW;
+ if (cpuCaps & PP_CPU_CAPS_ALTIVEC) c->cpuCaps |= AV_CPU_FLAG_ALTIVEC;
+ }
+
+ reallocBuffers(c, width, height, stride, qpStride);
+
+ c->frameNum=-1;
+
+ return c;
+}
+
+av_cold void pp_free_context(void *vc){
+ PPContext *c = (PPContext*)vc;
+ int i;
+
+ for(i=0; i<FF_ARRAY_ELEMS(c->tempBlurred); i++)
+ av_free(c->tempBlurred[i]);
+ for(i=0; i<FF_ARRAY_ELEMS(c->tempBlurredPast); i++)
+ av_free(c->tempBlurredPast[i]);
+
+ av_free(c->tempBlocks);
+ av_free(c->yHistogram);
+ av_free(c->tempDst);
+ av_free(c->tempSrc);
+ av_free(c->deintTemp);
+ av_free(c->stdQPTable);
+ av_free(c->nonBQPTable);
+ av_free(c->forcedQPTable);
+
+ memset(c, 0, sizeof(PPContext));
+
+ av_free(c);
+}
+
+void pp_postprocess(const uint8_t * src[3], const int srcStride[3],
+ uint8_t * dst[3], const int dstStride[3],
+ int width, int height,
+ const QP_STORE_T *QP_store, int QPStride,
+ pp_mode *vm, void *vc, int pict_type)
+{
+ int mbWidth = (width+15)>>4;
+ int mbHeight= (height+15)>>4;
+ PPMode *mode = vm;
+ PPContext *c = vc;
+ int minStride= FFMAX(FFABS(srcStride[0]), FFABS(dstStride[0]));
+ int absQPStride = FFABS(QPStride);
+
+ // c->stride and c->QPStride are always positive
+ if(c->stride < minStride || c->qpStride < absQPStride)
+ reallocBuffers(c, width, height,
+ FFMAX(minStride, c->stride),
+ FFMAX(c->qpStride, absQPStride));
+
+ if(!QP_store || (mode->lumMode & FORCE_QUANT)){
+ int i;
+ QP_store= c->forcedQPTable;
+ absQPStride = QPStride = 0;
+ if(mode->lumMode & FORCE_QUANT)
+ for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= mode->forcedQuant;
+ else
+ for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= 1;
+ }
+
+ if(pict_type & PP_PICT_TYPE_QP2){
+ int i;
+ const int count= FFMAX(mbHeight * absQPStride, mbWidth);
+ for(i=0; i<(count>>2); i++){
+ ((uint32_t*)c->stdQPTable)[i] = (((const uint32_t*)QP_store)[i]>>1) & 0x7F7F7F7F;
+ }
+ for(i<<=2; i<count; i++){
+ c->stdQPTable[i] = QP_store[i]>>1;
+ }
+ QP_store= c->stdQPTable;
+ QPStride= absQPStride;
+ }
+
+ if(0){
+ int x,y;
+ for(y=0; y<mbHeight; y++){
+ for(x=0; x<mbWidth; x++){
+ av_log(c, AV_LOG_INFO, "%2d ", QP_store[x + y*QPStride]);
+ }
+ av_log(c, AV_LOG_INFO, "\n");
+ }
+ av_log(c, AV_LOG_INFO, "\n");
+ }
+
+ if((pict_type&7)!=3){
+ if (QPStride >= 0){
+ int i;
+ const int count= FFMAX(mbHeight * QPStride, mbWidth);
+ for(i=0; i<(count>>2); i++){
+ ((uint32_t*)c->nonBQPTable)[i] = ((const uint32_t*)QP_store)[i] & 0x3F3F3F3F;
+ }
+ for(i<<=2; i<count; i++){
+ c->nonBQPTable[i] = QP_store[i] & 0x3F;
+ }
+ } else {
+ int i,j;
+ for(i=0; i<mbHeight; i++) {
+ for(j=0; j<absQPStride; j++) {
+ c->nonBQPTable[i*absQPStride+j] = QP_store[i*QPStride+j] & 0x3F;
+ }
+ }
+ }
+ }
+
+ av_log(c, AV_LOG_DEBUG, "using npp filters 0x%X/0x%X\n",
+ mode->lumMode, mode->chromMode);
+
+ postProcess(src[0], srcStride[0], dst[0], dstStride[0],
+ width, height, QP_store, QPStride, 0, mode, c);
+
+ if (!(src[1] && src[2] && dst[1] && dst[2]))
+ return;
+
+ width = (width )>>c->hChromaSubSample;
+ height = (height)>>c->vChromaSubSample;
+
+ if(mode->chromMode){
+ postProcess(src[1], srcStride[1], dst[1], dstStride[1],
+ width, height, QP_store, QPStride, 1, mode, c);
+ postProcess(src[2], srcStride[2], dst[2], dstStride[2],
+ width, height, QP_store, QPStride, 2, mode, c);
+ }
+ else if(srcStride[1] == dstStride[1] && srcStride[2] == dstStride[2]){
+ linecpy(dst[1], src[1], height, srcStride[1]);
+ linecpy(dst[2], src[2], height, srcStride[2]);
+ }else{
+ int y;
+ for(y=0; y<height; y++){
+ memcpy(&(dst[1][y*dstStride[1]]), &(src[1][y*srcStride[1]]), width);
+ memcpy(&(dst[2][y*dstStride[2]]), &(src[2][y*srcStride[2]]), width);
+ }
+ }
+}
diff --git a/libpostproc/postprocess.h b/libpostproc/postprocess.h
new file mode 100644
index 0000000000..e00ed968d7
--- /dev/null
+++ b/libpostproc/postprocess.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * 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
+ */
+
+#ifndef POSTPROC_POSTPROCESS_H
+#define POSTPROC_POSTPROCESS_H
+
+/**
+ * @file
+ * @ingroup lpp
+ * external API header
+ */
+
+/**
+ * @defgroup lpp Libpostproc
+ * @{
+ */
+
+#include "libpostproc/version.h"
+
+/**
+ * Return the LIBPOSTPROC_VERSION_INT constant.
+ */
+unsigned postproc_version(void);
+
+/**
+ * Return the libpostproc build-time configuration.
+ */
+const char *postproc_configuration(void);
+
+/**
+ * Return the libpostproc license.
+ */
+const char *postproc_license(void);
+
+#define PP_QUALITY_MAX 6
+
+#define QP_STORE_T int8_t
+
+#include <inttypes.h>
+
+typedef void pp_context;
+typedef void pp_mode;
+
+#if LIBPOSTPROC_VERSION_INT < (52<<16)
+typedef pp_context pp_context_t;
+typedef pp_mode pp_mode_t;
+extern const char *const pp_help; ///< a simple help text
+#else
+extern const char pp_help[]; ///< a simple help text
+#endif
+
+void pp_postprocess(const uint8_t * src[3], const int srcStride[3],
+ uint8_t * dst[3], const int dstStride[3],
+ int horizontalSize, int verticalSize,
+ const QP_STORE_T *QP_store, int QP_stride,
+ pp_mode *mode, pp_context *ppContext, int pict_type);
+
+
+/**
+ * Return a pp_mode or NULL if an error occurred.
+ *
+ * @param name the string after "-pp" on the command line
+ * @param quality a number from 0 to PP_QUALITY_MAX
+ */
+pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality);
+void pp_free_mode(pp_mode *mode);
+
+pp_context *pp_get_context(int width, int height, int flags);
+void pp_free_context(pp_context *ppContext);
+
+#define PP_CPU_CAPS_MMX 0x80000000
+#define PP_CPU_CAPS_MMX2 0x20000000
+#define PP_CPU_CAPS_3DNOW 0x40000000
+#define PP_CPU_CAPS_ALTIVEC 0x10000000
+#define PP_CPU_CAPS_AUTO 0x00080000
+
+#define PP_FORMAT 0x00000008
+#define PP_FORMAT_420 (0x00000011|PP_FORMAT)
+#define PP_FORMAT_422 (0x00000001|PP_FORMAT)
+#define PP_FORMAT_411 (0x00000002|PP_FORMAT)
+#define PP_FORMAT_444 (0x00000000|PP_FORMAT)
+#define PP_FORMAT_440 (0x00000010|PP_FORMAT)
+
+#define PP_PICT_TYPE_QP2 0x00000010 ///< MPEG2 style QScale
+
+/**
+ * @}
+ */
+
+#endif /* POSTPROC_POSTPROCESS_H */
diff --git a/libpostproc/postprocess_altivec_template.c b/libpostproc/postprocess_altivec_template.c
new file mode 100644
index 0000000000..fa6ebe279d
--- /dev/null
+++ b/libpostproc/postprocess_altivec_template.c
@@ -0,0 +1,1210 @@
+/*
+ * AltiVec optimizations (C) 2004 Romain Dolbeau <romain@dolbeau.org>
+ *
+ * based on code by Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * 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/avutil.h"
+
+#define ALTIVEC_TRANSPOSE_8x8_SHORT(src_a,src_b,src_c,src_d,src_e,src_f,src_g,src_h) \
+ do { \
+ __typeof__(src_a) tempA1, tempB1, tempC1, tempD1; \
+ __typeof__(src_a) tempE1, tempF1, tempG1, tempH1; \
+ __typeof__(src_a) tempA2, tempB2, tempC2, tempD2; \
+ __typeof__(src_a) tempE2, tempF2, tempG2, tempH2; \
+ tempA1 = vec_mergeh (src_a, src_e); \
+ tempB1 = vec_mergel (src_a, src_e); \
+ tempC1 = vec_mergeh (src_b, src_f); \
+ tempD1 = vec_mergel (src_b, src_f); \
+ tempE1 = vec_mergeh (src_c, src_g); \
+ tempF1 = vec_mergel (src_c, src_g); \
+ tempG1 = vec_mergeh (src_d, src_h); \
+ tempH1 = vec_mergel (src_d, src_h); \
+ tempA2 = vec_mergeh (tempA1, tempE1); \
+ tempB2 = vec_mergel (tempA1, tempE1); \
+ tempC2 = vec_mergeh (tempB1, tempF1); \
+ tempD2 = vec_mergel (tempB1, tempF1); \
+ tempE2 = vec_mergeh (tempC1, tempG1); \
+ tempF2 = vec_mergel (tempC1, tempG1); \
+ tempG2 = vec_mergeh (tempD1, tempH1); \
+ tempH2 = vec_mergel (tempD1, tempH1); \
+ src_a = vec_mergeh (tempA2, tempE2); \
+ src_b = vec_mergel (tempA2, tempE2); \
+ src_c = vec_mergeh (tempB2, tempF2); \
+ src_d = vec_mergel (tempB2, tempF2); \
+ src_e = vec_mergeh (tempC2, tempG2); \
+ src_f = vec_mergel (tempC2, tempG2); \
+ src_g = vec_mergeh (tempD2, tempH2); \
+ src_h = vec_mergel (tempD2, tempH2); \
+ } while (0)
+
+
+static inline int vertClassify_altivec(uint8_t src[], int stride, PPContext *c) {
+ /*
+ this code makes no assumption on src or stride.
+ One could remove the recomputation of the perm
+ vector by assuming (stride % 16) == 0, unfortunately
+ this is not always true.
+ */
+ short data_0 = ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
+ DECLARE_ALIGNED(16, short, data)[8] =
+ {
+ data_0,
+ data_0 * 2 + 1,
+ c->QP * 2,
+ c->QP * 4
+ };
+ int numEq;
+ uint8_t *src2 = src;
+ vector signed short v_dcOffset;
+ vector signed short v2QP;
+ vector unsigned short v4QP;
+ vector unsigned short v_dcThreshold;
+ const int properStride = (stride % 16);
+ const int srcAlign = ((unsigned long)src2 % 16);
+ const int two_vectors = ((srcAlign > 8) || properStride) ? 1 : 0;
+ const vector signed int zero = vec_splat_s32(0);
+ const vector signed short mask = vec_splat_s16(1);
+ vector signed int v_numEq = vec_splat_s32(0);
+ vector signed short v_data = vec_ld(0, data);
+ vector signed short v_srcAss0, v_srcAss1, v_srcAss2, v_srcAss3,
+ v_srcAss4, v_srcAss5, v_srcAss6, v_srcAss7;
+//FIXME avoid this mess if possible
+ register int j0 = 0,
+ j1 = stride,
+ j2 = 2 * stride,
+ j3 = 3 * stride,
+ j4 = 4 * stride,
+ j5 = 5 * stride,
+ j6 = 6 * stride,
+ j7 = 7 * stride;
+ vector unsigned char v_srcA0, v_srcA1, v_srcA2, v_srcA3,
+ v_srcA4, v_srcA5, v_srcA6, v_srcA7;
+
+ v_dcOffset = vec_splat(v_data, 0);
+ v_dcThreshold = (vector unsigned short)vec_splat(v_data, 1);
+ v2QP = vec_splat(v_data, 2);
+ v4QP = (vector unsigned short)vec_splat(v_data, 3);
+
+ src2 += stride * 4;
+
+#define LOAD_LINE(i) \
+ { \
+ vector unsigned char perm##i = vec_lvsl(j##i, src2); \
+ vector unsigned char v_srcA2##i; \
+ vector unsigned char v_srcA1##i = vec_ld(j##i, src2); \
+ if (two_vectors) \
+ v_srcA2##i = vec_ld(j##i + 16, src2); \
+ v_srcA##i = \
+ vec_perm(v_srcA1##i, v_srcA2##i, perm##i); \
+ v_srcAss##i = \
+ (vector signed short)vec_mergeh((vector signed char)zero, \
+ (vector signed char)v_srcA##i); }
+
+#define LOAD_LINE_ALIGNED(i) \
+ v_srcA##i = vec_ld(j##i, src2); \
+ v_srcAss##i = \
+ (vector signed short)vec_mergeh((vector signed char)zero, \
+ (vector signed char)v_srcA##i)
+
+ /* Special-casing the aligned case is worthwhile, as all calls from
+ * the (transposed) horizontable deblocks will be aligned, in addition
+ * to the naturally aligned vertical deblocks. */
+ if (properStride && srcAlign) {
+ LOAD_LINE_ALIGNED(0);
+ LOAD_LINE_ALIGNED(1);
+ LOAD_LINE_ALIGNED(2);
+ LOAD_LINE_ALIGNED(3);
+ LOAD_LINE_ALIGNED(4);
+ LOAD_LINE_ALIGNED(5);
+ LOAD_LINE_ALIGNED(6);
+ LOAD_LINE_ALIGNED(7);
+ } else {
+ LOAD_LINE(0);
+ LOAD_LINE(1);
+ LOAD_LINE(2);
+ LOAD_LINE(3);
+ LOAD_LINE(4);
+ LOAD_LINE(5);
+ LOAD_LINE(6);
+ LOAD_LINE(7);
+ }
+#undef LOAD_LINE
+#undef LOAD_LINE_ALIGNED
+
+#define ITER(i, j) \
+ const vector signed short v_diff##i = \
+ vec_sub(v_srcAss##i, v_srcAss##j); \
+ const vector signed short v_sum##i = \
+ vec_add(v_diff##i, v_dcOffset); \
+ const vector signed short v_comp##i = \
+ (vector signed short)vec_cmplt((vector unsigned short)v_sum##i, \
+ v_dcThreshold); \
+ const vector signed short v_part##i = vec_and(mask, v_comp##i);
+
+ {
+ ITER(0, 1)
+ ITER(1, 2)
+ ITER(2, 3)
+ ITER(3, 4)
+ ITER(4, 5)
+ ITER(5, 6)
+ ITER(6, 7)
+
+ v_numEq = vec_sum4s(v_part0, v_numEq);
+ v_numEq = vec_sum4s(v_part1, v_numEq);
+ v_numEq = vec_sum4s(v_part2, v_numEq);
+ v_numEq = vec_sum4s(v_part3, v_numEq);
+ v_numEq = vec_sum4s(v_part4, v_numEq);
+ v_numEq = vec_sum4s(v_part5, v_numEq);
+ v_numEq = vec_sum4s(v_part6, v_numEq);
+ }
+
+#undef ITER
+
+ v_numEq = vec_sums(v_numEq, zero);
+
+ v_numEq = vec_splat(v_numEq, 3);
+ vec_ste(v_numEq, 0, &numEq);
+
+ if (numEq > c->ppMode.flatnessThreshold){
+ const vector unsigned char mmoP1 = (const vector unsigned char)
+ {0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
+ 0x00, 0x01, 0x12, 0x13, 0x08, 0x09, 0x1A, 0x1B};
+ const vector unsigned char mmoP2 = (const vector unsigned char)
+ {0x04, 0x05, 0x16, 0x17, 0x0C, 0x0D, 0x1E, 0x1F,
+ 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f};
+ const vector unsigned char mmoP = (const vector unsigned char)
+ vec_lvsl(8, (unsigned char*)0);
+
+ vector signed short mmoL1 = vec_perm(v_srcAss0, v_srcAss2, mmoP1);
+ vector signed short mmoL2 = vec_perm(v_srcAss4, v_srcAss6, mmoP2);
+ vector signed short mmoL = vec_perm(mmoL1, mmoL2, mmoP);
+ vector signed short mmoR1 = vec_perm(v_srcAss5, v_srcAss7, mmoP1);
+ vector signed short mmoR2 = vec_perm(v_srcAss1, v_srcAss3, mmoP2);
+ vector signed short mmoR = vec_perm(mmoR1, mmoR2, mmoP);
+ vector signed short mmoDiff = vec_sub(mmoL, mmoR);
+ vector unsigned short mmoSum = (vector unsigned short)vec_add(mmoDiff, v2QP);
+
+ if (vec_any_gt(mmoSum, v4QP))
+ return 0;
+ else
+ return 1;
+ }
+ else return 2;
+}
+
+static inline void doVertLowPass_altivec(uint8_t *src, int stride, PPContext *c) {
+ /*
+ this code makes no assumption on src or stride.
+ One could remove the recomputation of the perm
+ vector by assuming (stride % 16) == 0, unfortunately
+ this is not always true. Quite a lot of load/stores
+ can be removed by assuming proper alignment of
+ src & stride :-(
+ */
+ uint8_t *src2 = src;
+ const vector signed int zero = vec_splat_s32(0);
+ const int properStride = (stride % 16);
+ const int srcAlign = ((unsigned long)src2 % 16);
+ DECLARE_ALIGNED(16, short, qp)[8] = {c->QP};
+ vector signed short vqp = vec_ld(0, qp);
+ vector signed short vb0, vb1, vb2, vb3, vb4, vb5, vb6, vb7, vb8, vb9;
+ vector unsigned char vbA0, av_uninit(vbA1), av_uninit(vbA2), av_uninit(vbA3), av_uninit(vbA4), av_uninit(vbA5), av_uninit(vbA6), av_uninit(vbA7), av_uninit(vbA8), vbA9;
+ vector unsigned char vbB0, av_uninit(vbB1), av_uninit(vbB2), av_uninit(vbB3), av_uninit(vbB4), av_uninit(vbB5), av_uninit(vbB6), av_uninit(vbB7), av_uninit(vbB8), vbB9;
+ vector unsigned char vbT0, vbT1, vbT2, vbT3, vbT4, vbT5, vbT6, vbT7, vbT8, vbT9;
+ vector unsigned char perml0, perml1, perml2, perml3, perml4,
+ perml5, perml6, perml7, perml8, perml9;
+ register int j0 = 0,
+ j1 = stride,
+ j2 = 2 * stride,
+ j3 = 3 * stride,
+ j4 = 4 * stride,
+ j5 = 5 * stride,
+ j6 = 6 * stride,
+ j7 = 7 * stride,
+ j8 = 8 * stride,
+ j9 = 9 * stride;
+
+ vqp = vec_splat(vqp, 0);
+
+ src2 += stride*3;
+
+#define LOAD_LINE(i) \
+ perml##i = vec_lvsl(i * stride, src2); \
+ vbA##i = vec_ld(i * stride, src2); \
+ vbB##i = vec_ld(i * stride + 16, src2); \
+ vbT##i = vec_perm(vbA##i, vbB##i, perml##i); \
+ vb##i = \
+ (vector signed short)vec_mergeh((vector unsigned char)zero, \
+ (vector unsigned char)vbT##i)
+
+#define LOAD_LINE_ALIGNED(i) \
+ vbT##i = vec_ld(j##i, src2); \
+ vb##i = \
+ (vector signed short)vec_mergeh((vector signed char)zero, \
+ (vector signed char)vbT##i)
+
+ /* Special-casing the aligned case is worthwhile, as all calls from
+ * the (transposed) horizontable deblocks will be aligned, in addition
+ * to the naturally aligned vertical deblocks. */
+ if (properStride && srcAlign) {
+ LOAD_LINE_ALIGNED(0);
+ LOAD_LINE_ALIGNED(1);
+ LOAD_LINE_ALIGNED(2);
+ LOAD_LINE_ALIGNED(3);
+ LOAD_LINE_ALIGNED(4);
+ LOAD_LINE_ALIGNED(5);
+ LOAD_LINE_ALIGNED(6);
+ LOAD_LINE_ALIGNED(7);
+ LOAD_LINE_ALIGNED(8);
+ LOAD_LINE_ALIGNED(9);
+ } else {
+ LOAD_LINE(0);
+ LOAD_LINE(1);
+ LOAD_LINE(2);
+ LOAD_LINE(3);
+ LOAD_LINE(4);
+ LOAD_LINE(5);
+ LOAD_LINE(6);
+ LOAD_LINE(7);
+ LOAD_LINE(8);
+ LOAD_LINE(9);
+ }
+#undef LOAD_LINE
+#undef LOAD_LINE_ALIGNED
+ {
+ const vector unsigned short v_2 = vec_splat_u16(2);
+ const vector unsigned short v_4 = vec_splat_u16(4);
+
+ const vector signed short v_diff01 = vec_sub(vb0, vb1);
+ const vector unsigned short v_cmp01 =
+ (const vector unsigned short) vec_cmplt(vec_abs(v_diff01), vqp);
+ const vector signed short v_first = vec_sel(vb1, vb0, v_cmp01);
+ const vector signed short v_diff89 = vec_sub(vb8, vb9);
+ const vector unsigned short v_cmp89 =
+ (const vector unsigned short) vec_cmplt(vec_abs(v_diff89), vqp);
+ const vector signed short v_last = vec_sel(vb8, vb9, v_cmp89);
+
+ const vector signed short temp01 = vec_mladd(v_first, (vector signed short)v_4, vb1);
+ const vector signed short temp02 = vec_add(vb2, vb3);
+ const vector signed short temp03 = vec_add(temp01, (vector signed short)v_4);
+ const vector signed short v_sumsB0 = vec_add(temp02, temp03);
+
+ const vector signed short temp11 = vec_sub(v_sumsB0, v_first);
+ const vector signed short v_sumsB1 = vec_add(temp11, vb4);
+
+ const vector signed short temp21 = vec_sub(v_sumsB1, v_first);
+ const vector signed short v_sumsB2 = vec_add(temp21, vb5);
+
+ const vector signed short temp31 = vec_sub(v_sumsB2, v_first);
+ const vector signed short v_sumsB3 = vec_add(temp31, vb6);
+
+ const vector signed short temp41 = vec_sub(v_sumsB3, v_first);
+ const vector signed short v_sumsB4 = vec_add(temp41, vb7);
+
+ const vector signed short temp51 = vec_sub(v_sumsB4, vb1);
+ const vector signed short v_sumsB5 = vec_add(temp51, vb8);
+
+ const vector signed short temp61 = vec_sub(v_sumsB5, vb2);
+ const vector signed short v_sumsB6 = vec_add(temp61, v_last);
+
+ const vector signed short temp71 = vec_sub(v_sumsB6, vb3);
+ const vector signed short v_sumsB7 = vec_add(temp71, v_last);
+
+ const vector signed short temp81 = vec_sub(v_sumsB7, vb4);
+ const vector signed short v_sumsB8 = vec_add(temp81, v_last);
+
+ const vector signed short temp91 = vec_sub(v_sumsB8, vb5);
+ const vector signed short v_sumsB9 = vec_add(temp91, v_last);
+
+ #define COMPUTE_VR(i, j, k) \
+ const vector signed short temps1##i = \
+ vec_add(v_sumsB##i, v_sumsB##k); \
+ const vector signed short temps2##i = \
+ vec_mladd(vb##j, (vector signed short)v_2, temps1##i); \
+ const vector signed short vr##j = vec_sra(temps2##i, v_4)
+
+ COMPUTE_VR(0, 1, 2);
+ COMPUTE_VR(1, 2, 3);
+ COMPUTE_VR(2, 3, 4);
+ COMPUTE_VR(3, 4, 5);
+ COMPUTE_VR(4, 5, 6);
+ COMPUTE_VR(5, 6, 7);
+ COMPUTE_VR(6, 7, 8);
+ COMPUTE_VR(7, 8, 9);
+
+ const vector signed char neg1 = vec_splat_s8(-1);
+ const vector unsigned char permHH = (const vector unsigned char){0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
+
+#define PACK_AND_STORE(i) \
+{ const vector unsigned char perms##i = \
+ vec_lvsr(i * stride, src2); \
+ const vector unsigned char vf##i = \
+ vec_packsu(vr##i, (vector signed short)zero); \
+ const vector unsigned char vg##i = \
+ vec_perm(vf##i, vbT##i, permHH); \
+ const vector unsigned char mask##i = \
+ vec_perm((vector unsigned char)zero, (vector unsigned char)neg1, perms##i); \
+ const vector unsigned char vg2##i = \
+ vec_perm(vg##i, vg##i, perms##i); \
+ const vector unsigned char svA##i = \
+ vec_sel(vbA##i, vg2##i, mask##i); \
+ const vector unsigned char svB##i = \
+ vec_sel(vg2##i, vbB##i, mask##i); \
+ vec_st(svA##i, i * stride, src2); \
+ vec_st(svB##i, i * stride + 16, src2);}
+
+#define PACK_AND_STORE_ALIGNED(i) \
+{ const vector unsigned char vf##i = \
+ vec_packsu(vr##i, (vector signed short)zero); \
+ const vector unsigned char vg##i = \
+ vec_perm(vf##i, vbT##i, permHH); \
+ vec_st(vg##i, i * stride, src2);}
+
+ /* Special-casing the aligned case is worthwhile, as all calls from
+ * the (transposed) horizontable deblocks will be aligned, in addition
+ * to the naturally aligned vertical deblocks. */
+ if (properStride && srcAlign) {
+ PACK_AND_STORE_ALIGNED(1)
+ PACK_AND_STORE_ALIGNED(2)
+ PACK_AND_STORE_ALIGNED(3)
+ PACK_AND_STORE_ALIGNED(4)
+ PACK_AND_STORE_ALIGNED(5)
+ PACK_AND_STORE_ALIGNED(6)
+ PACK_AND_STORE_ALIGNED(7)
+ PACK_AND_STORE_ALIGNED(8)
+ } else {
+ PACK_AND_STORE(1)
+ PACK_AND_STORE(2)
+ PACK_AND_STORE(3)
+ PACK_AND_STORE(4)
+ PACK_AND_STORE(5)
+ PACK_AND_STORE(6)
+ PACK_AND_STORE(7)
+ PACK_AND_STORE(8)
+ }
+ #undef PACK_AND_STORE
+ #undef PACK_AND_STORE_ALIGNED
+ }
+}
+
+
+
+static inline void doVertDefFilter_altivec(uint8_t src[], int stride, PPContext *c) {
+ /*
+ this code makes no assumption on src or stride.
+ One could remove the recomputation of the perm
+ vector by assuming (stride % 16) == 0, unfortunately
+ this is not always true. Quite a lot of load/stores
+ can be removed by assuming proper alignment of
+ src & stride :-(
+ */
+ uint8_t *src2 = src + stride*3;
+ const vector signed int zero = vec_splat_s32(0);
+ DECLARE_ALIGNED(16, short, qp)[8] = {8*c->QP};
+ vector signed short vqp = vec_splat(
+ (vector signed short)vec_ld(0, qp), 0);
+
+#define LOAD_LINE(i) \
+ const vector unsigned char perm##i = \
+ vec_lvsl(i * stride, src2); \
+ const vector unsigned char vbA##i = \
+ vec_ld(i * stride, src2); \
+ const vector unsigned char vbB##i = \
+ vec_ld(i * stride + 16, src2); \
+ const vector unsigned char vbT##i = \
+ vec_perm(vbA##i, vbB##i, perm##i); \
+ const vector signed short vb##i = \
+ (vector signed short)vec_mergeh((vector unsigned char)zero, \
+ (vector unsigned char)vbT##i)
+
+ LOAD_LINE(1);
+ LOAD_LINE(2);
+ LOAD_LINE(3);
+ LOAD_LINE(4);
+ LOAD_LINE(5);
+ LOAD_LINE(6);
+ LOAD_LINE(7);
+ LOAD_LINE(8);
+#undef LOAD_LINE
+
+ const vector signed short v_1 = vec_splat_s16(1);
+ const vector signed short v_2 = vec_splat_s16(2);
+ const vector signed short v_5 = vec_splat_s16(5);
+ const vector signed short v_32 = vec_sl(v_1,
+ (vector unsigned short)v_5);
+ /* middle energy */
+ const vector signed short l3minusl6 = vec_sub(vb3, vb6);
+ const vector signed short l5minusl4 = vec_sub(vb5, vb4);
+ const vector signed short twotimes_l3minusl6 = vec_mladd(v_2, l3minusl6, (vector signed short)zero);
+ const vector signed short mE = vec_mladd(v_5, l5minusl4, twotimes_l3minusl6);
+ const vector signed short absmE = vec_abs(mE);
+ /* left & right energy */
+ const vector signed short l1minusl4 = vec_sub(vb1, vb4);
+ const vector signed short l3minusl2 = vec_sub(vb3, vb2);
+ const vector signed short l5minusl8 = vec_sub(vb5, vb8);
+ const vector signed short l7minusl6 = vec_sub(vb7, vb6);
+ const vector signed short twotimes_l1minusl4 = vec_mladd(v_2, l1minusl4, (vector signed short)zero);
+ const vector signed short twotimes_l5minusl8 = vec_mladd(v_2, l5minusl8, (vector signed short)zero);
+ const vector signed short lE = vec_mladd(v_5, l3minusl2, twotimes_l1minusl4);
+ const vector signed short rE = vec_mladd(v_5, l7minusl6, twotimes_l5minusl8);
+ /* d */
+ const vector signed short ddiff = vec_sub(absmE,
+ vec_min(vec_abs(lE),
+ vec_abs(rE)));
+ const vector signed short ddiffclamp = vec_max(ddiff, (vector signed short)zero);
+ const vector signed short dtimes64 = vec_mladd(v_5, ddiffclamp, v_32);
+ const vector signed short d = vec_sra(dtimes64, vec_splat_u16(6));
+ const vector signed short minusd = vec_sub((vector signed short)zero, d);
+ const vector signed short finald = vec_sel(minusd,
+ d,
+ vec_cmpgt(vec_sub((vector signed short)zero, mE),
+ (vector signed short)zero));
+ /* q */
+ const vector signed short qtimes2 = vec_sub(vb4, vb5);
+ /* for a shift right to behave like /2, we need to add one
+ to all negative integer */
+ const vector signed short rounddown = vec_sel((vector signed short)zero,
+ v_1,
+ vec_cmplt(qtimes2, (vector signed short)zero));
+ const vector signed short q = vec_sra(vec_add(qtimes2, rounddown), vec_splat_u16(1));
+ /* clamp */
+ const vector signed short dclamp_P1 = vec_max((vector signed short)zero, finald);
+ const vector signed short dclamp_P = vec_min(dclamp_P1, q);
+ const vector signed short dclamp_N1 = vec_min((vector signed short)zero, finald);
+ const vector signed short dclamp_N = vec_max(dclamp_N1, q);
+
+ const vector signed short dclampedfinal = vec_sel(dclamp_N,
+ dclamp_P,
+ vec_cmpgt(q, (vector signed short)zero));
+ const vector signed short dornotd = vec_sel((vector signed short)zero,
+ dclampedfinal,
+ vec_cmplt(absmE, vqp));
+ /* add/subtract to l4 and l5 */
+ const vector signed short vb4minusd = vec_sub(vb4, dornotd);
+ const vector signed short vb5plusd = vec_add(vb5, dornotd);
+ /* finally, stores */
+ const vector unsigned char st4 = vec_packsu(vb4minusd, (vector signed short)zero);
+ const vector unsigned char st5 = vec_packsu(vb5plusd, (vector signed short)zero);
+
+ const vector signed char neg1 = vec_splat_s8(-1);
+ const vector unsigned char permHH = (const vector unsigned char){0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
+
+#define STORE(i) \
+{ const vector unsigned char perms##i = \
+ vec_lvsr(i * stride, src2); \
+ const vector unsigned char vg##i = \
+ vec_perm(st##i, vbT##i, permHH); \
+ const vector unsigned char mask##i = \
+ vec_perm((vector unsigned char)zero, (vector unsigned char)neg1, perms##i); \
+ const vector unsigned char vg2##i = \
+ vec_perm(vg##i, vg##i, perms##i); \
+ const vector unsigned char svA##i = \
+ vec_sel(vbA##i, vg2##i, mask##i); \
+ const vector unsigned char svB##i = \
+ vec_sel(vg2##i, vbB##i, mask##i); \
+ vec_st(svA##i, i * stride, src2); \
+ vec_st(svB##i, i * stride + 16, src2);}
+
+ STORE(4)
+ STORE(5)
+}
+
+static inline void dering_altivec(uint8_t src[], int stride, PPContext *c) {
+ const vector signed int vsint32_8 = vec_splat_s32(8);
+ const vector unsigned int vuint32_4 = vec_splat_u32(4);
+ const vector signed char neg1 = vec_splat_s8(-1);
+
+ const vector unsigned char permA1 = (vector unsigned char)
+ {0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x1F, 0x1F,
+ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
+ const vector unsigned char permA2 = (vector unsigned char)
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x10, 0x11,
+ 0x12, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
+ const vector unsigned char permA1inc = (vector unsigned char)
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const vector unsigned char permA2inc = (vector unsigned char)
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const vector unsigned char magic = (vector unsigned char)
+ {0x01, 0x02, 0x01, 0x02, 0x04, 0x02, 0x01, 0x02,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const vector unsigned char extractPerm = (vector unsigned char)
+ {0x10, 0x10, 0x10, 0x01, 0x10, 0x10, 0x10, 0x01,
+ 0x10, 0x10, 0x10, 0x01, 0x10, 0x10, 0x10, 0x01};
+ const vector unsigned char extractPermInc = (vector unsigned char)
+ {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01};
+ const vector unsigned char identity = vec_lvsl(0,(unsigned char *)0);
+ const vector unsigned char tenRight = (vector unsigned char)
+ {0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ const vector unsigned char eightLeft = (vector unsigned char)
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08};
+
+ /*
+ this code makes no assumption on src or stride.
+ One could remove the recomputation of the perm
+ vector by assuming (stride % 16) == 0, unfortunately
+ this is not always true. Quite a lot of load/stores
+ can be removed by assuming proper alignment of
+ src & stride :-(
+ */
+ uint8_t *srcCopy = src;
+ DECLARE_ALIGNED(16, uint8_t, dt)[16] = { deringThreshold };
+ const vector signed int zero = vec_splat_s32(0);
+ vector unsigned char v_dt = vec_splat(vec_ld(0, dt), 0);
+
+#define LOAD_LINE(i) \
+ const vector unsigned char perm##i = \
+ vec_lvsl(i * stride, srcCopy); \
+ vector unsigned char sA##i = vec_ld(i * stride, srcCopy); \
+ vector unsigned char sB##i = vec_ld(i * stride + 16, srcCopy); \
+ vector unsigned char src##i = vec_perm(sA##i, sB##i, perm##i)
+
+ LOAD_LINE(0);
+ LOAD_LINE(1);
+ LOAD_LINE(2);
+ LOAD_LINE(3);
+ LOAD_LINE(4);
+ LOAD_LINE(5);
+ LOAD_LINE(6);
+ LOAD_LINE(7);
+ LOAD_LINE(8);
+ LOAD_LINE(9);
+#undef LOAD_LINE
+
+ vector unsigned char v_avg;
+ DECLARE_ALIGNED(16, signed int, S)[8];
+ DECLARE_ALIGNED(16, int, tQP2)[4] = { c->QP/2 + 1 };
+ vector signed int vQP2 = vec_ld(0, tQP2);
+ vQP2 = vec_splat(vQP2, 0);
+
+ {
+ const vector unsigned char trunc_perm = (vector unsigned char)
+ {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};
+ const vector unsigned char trunc_src12 = vec_perm(src1, src2, trunc_perm);
+ const vector unsigned char trunc_src34 = vec_perm(src3, src4, trunc_perm);
+ const vector unsigned char trunc_src56 = vec_perm(src5, src6, trunc_perm);
+ const vector unsigned char trunc_src78 = vec_perm(src7, src8, trunc_perm);
+
+#define EXTRACT(op) do { \
+ const vector unsigned char s_1 = vec_##op(trunc_src12, trunc_src34); \
+ const vector unsigned char s_2 = vec_##op(trunc_src56, trunc_src78); \
+ const vector unsigned char s_6 = vec_##op(s_1, s_2); \
+ const vector unsigned char s_8h = vec_mergeh(s_6, s_6); \
+ const vector unsigned char s_8l = vec_mergel(s_6, s_6); \
+ const vector unsigned char s_9 = vec_##op(s_8h, s_8l); \
+ const vector unsigned char s_9h = vec_mergeh(s_9, s_9); \
+ const vector unsigned char s_9l = vec_mergel(s_9, s_9); \
+ const vector unsigned char s_10 = vec_##op(s_9h, s_9l); \
+ const vector unsigned char s_10h = vec_mergeh(s_10, s_10); \
+ const vector unsigned char s_10l = vec_mergel(s_10, s_10); \
+ const vector unsigned char s_11 = vec_##op(s_10h, s_10l); \
+ const vector unsigned char s_11h = vec_mergeh(s_11, s_11); \
+ const vector unsigned char s_11l = vec_mergel(s_11, s_11); \
+ v_##op = vec_##op(s_11h, s_11l); \
+} while (0)
+
+ vector unsigned char v_min;
+ vector unsigned char v_max;
+ EXTRACT(min);
+ EXTRACT(max);
+#undef EXTRACT
+
+ if (vec_all_lt(vec_sub(v_max, v_min), v_dt))
+ return;
+
+ v_avg = vec_avg(v_min, v_max);
+ }
+
+ {
+ const vector unsigned short mask1 = (vector unsigned short)
+ {0x0001, 0x0002, 0x0004, 0x0008,
+ 0x0010, 0x0020, 0x0040, 0x0080};
+ const vector unsigned short mask2 = (vector unsigned short)
+ {0x0100, 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000};
+
+ const vector unsigned int vuint32_16 = vec_sl(vec_splat_u32(1), vec_splat_u32(4));
+ const vector unsigned int vuint32_1 = vec_splat_u32(1);
+
+ vector signed int sumA2;
+ vector signed int sumB2;
+ vector signed int sum0, sum1, sum2, sum3, sum4;
+ vector signed int sum5, sum6, sum7, sum8, sum9;
+
+#define COMPARE(i) \
+ do { \
+ const vector unsigned char cmp = \
+ (vector unsigned char)vec_cmpgt(src##i, v_avg); \
+ const vector unsigned short cmpHi = \
+ (vector unsigned short)vec_mergeh(cmp, cmp); \
+ const vector unsigned short cmpLi = \
+ (vector unsigned short)vec_mergel(cmp, cmp); \
+ const vector signed short cmpHf = \
+ (vector signed short)vec_and(cmpHi, mask1); \
+ const vector signed short cmpLf = \
+ (vector signed short)vec_and(cmpLi, mask2); \
+ const vector signed int sump = vec_sum4s(cmpHf, zero); \
+ const vector signed int sumq = vec_sum4s(cmpLf, sump); \
+ sum##i = vec_sums(sumq, zero); \
+ } while (0)
+
+ COMPARE(0);
+ COMPARE(1);
+ COMPARE(2);
+ COMPARE(3);
+ COMPARE(4);
+ COMPARE(5);
+ COMPARE(6);
+ COMPARE(7);
+ COMPARE(8);
+ COMPARE(9);
+#undef COMPARE
+
+ {
+ const vector signed int sump02 = vec_mergel(sum0, sum2);
+ const vector signed int sump13 = vec_mergel(sum1, sum3);
+ const vector signed int sumA = vec_mergel(sump02, sump13);
+
+ const vector signed int sump46 = vec_mergel(sum4, sum6);
+ const vector signed int sump57 = vec_mergel(sum5, sum7);
+ const vector signed int sumB = vec_mergel(sump46, sump57);
+
+ const vector signed int sump8A = vec_mergel(sum8, zero);
+ const vector signed int sump9B = vec_mergel(sum9, zero);
+ const vector signed int sumC = vec_mergel(sump8A, sump9B);
+
+ const vector signed int tA = vec_sl(vec_nor(zero, sumA), vuint32_16);
+ const vector signed int tB = vec_sl(vec_nor(zero, sumB), vuint32_16);
+ const vector signed int tC = vec_sl(vec_nor(zero, sumC), vuint32_16);
+ const vector signed int t2A = vec_or(sumA, tA);
+ const vector signed int t2B = vec_or(sumB, tB);
+ const vector signed int t2C = vec_or(sumC, tC);
+ const vector signed int t3A = vec_and(vec_sra(t2A, vuint32_1),
+ vec_sl(t2A, vuint32_1));
+ const vector signed int t3B = vec_and(vec_sra(t2B, vuint32_1),
+ vec_sl(t2B, vuint32_1));
+ const vector signed int t3C = vec_and(vec_sra(t2C, vuint32_1),
+ vec_sl(t2C, vuint32_1));
+ const vector signed int yA = vec_and(t2A, t3A);
+ const vector signed int yB = vec_and(t2B, t3B);
+ const vector signed int yC = vec_and(t2C, t3C);
+
+ const vector unsigned char strangeperm1 = vec_lvsl(4, (unsigned char*)0);
+ const vector unsigned char strangeperm2 = vec_lvsl(8, (unsigned char*)0);
+ const vector signed int sumAd4 = vec_perm(yA, yB, strangeperm1);
+ const vector signed int sumAd8 = vec_perm(yA, yB, strangeperm2);
+ const vector signed int sumBd4 = vec_perm(yB, yC, strangeperm1);
+ const vector signed int sumBd8 = vec_perm(yB, yC, strangeperm2);
+ const vector signed int sumAp = vec_and(yA,
+ vec_and(sumAd4,sumAd8));
+ const vector signed int sumBp = vec_and(yB,
+ vec_and(sumBd4,sumBd8));
+ sumA2 = vec_or(sumAp,
+ vec_sra(sumAp,
+ vuint32_16));
+ sumB2 = vec_or(sumBp,
+ vec_sra(sumBp,
+ vuint32_16));
+ }
+ vec_st(sumA2, 0, S);
+ vec_st(sumB2, 16, S);
+ }
+
+ /* I'm not sure the following is actually faster
+ than straight, unvectorized C code :-( */
+
+#define F_INIT() \
+ vector unsigned char tenRightM = tenRight; \
+ vector unsigned char permA1M = permA1; \
+ vector unsigned char permA2M = permA2; \
+ vector unsigned char extractPermM = extractPerm
+
+#define F2(i, j, k, l) \
+ if (S[i] & (1 << (l+1))) { \
+ const vector unsigned char a_A = vec_perm(src##i, src##j, permA1M); \
+ const vector unsigned char a_B = vec_perm(a_A, src##k, permA2M); \
+ const vector signed int a_sump = \
+ (vector signed int)vec_msum(a_B, magic, (vector unsigned int)zero);\
+ vector signed int F = vec_sr(vec_sums(a_sump, vsint32_8), vuint32_4); \
+ const vector signed int p = \
+ (vector signed int)vec_perm(src##j, (vector unsigned char)zero, \
+ extractPermM); \
+ const vector signed int sum = vec_add(p, vQP2); \
+ const vector signed int diff = vec_sub(p, vQP2); \
+ vector signed int newpm; \
+ vector unsigned char newpm2, mask; \
+ F = vec_splat(F, 3); \
+ if (vec_all_lt(sum, F)) \
+ newpm = sum; \
+ else if (vec_all_gt(diff, F)) \
+ newpm = diff; \
+ else newpm = F; \
+ newpm2 = vec_splat((vector unsigned char)newpm, 15); \
+ mask = vec_add(identity, tenRightM); \
+ src##j = vec_perm(src##j, newpm2, mask); \
+ } \
+ permA1M = vec_add(permA1M, permA1inc); \
+ permA2M = vec_add(permA2M, permA2inc); \
+ tenRightM = vec_sro(tenRightM, eightLeft); \
+ extractPermM = vec_add(extractPermM, extractPermInc)
+
+#define ITER(i, j, k) do { \
+ F_INIT(); \
+ F2(i, j, k, 0); \
+ F2(i, j, k, 1); \
+ F2(i, j, k, 2); \
+ F2(i, j, k, 3); \
+ F2(i, j, k, 4); \
+ F2(i, j, k, 5); \
+ F2(i, j, k, 6); \
+ F2(i, j, k, 7); \
+} while (0)
+
+ ITER(0, 1, 2);
+ ITER(1, 2, 3);
+ ITER(2, 3, 4);
+ ITER(3, 4, 5);
+ ITER(4, 5, 6);
+ ITER(5, 6, 7);
+ ITER(6, 7, 8);
+ ITER(7, 8, 9);
+
+#define STORE_LINE(i) do { \
+ const vector unsigned char permST = \
+ vec_lvsr(i * stride, srcCopy); \
+ const vector unsigned char maskST = \
+ vec_perm((vector unsigned char)zero, \
+ (vector unsigned char)neg1, permST); \
+ src##i = vec_perm(src##i ,src##i, permST); \
+ sA##i= vec_sel(sA##i, src##i, maskST); \
+ sB##i= vec_sel(src##i, sB##i, maskST); \
+ vec_st(sA##i, i * stride, srcCopy); \
+ vec_st(sB##i, i * stride + 16, srcCopy); \
+} while (0)
+
+ STORE_LINE(1);
+ STORE_LINE(2);
+ STORE_LINE(3);
+ STORE_LINE(4);
+ STORE_LINE(5);
+ STORE_LINE(6);
+ STORE_LINE(7);
+ STORE_LINE(8);
+
+#undef STORE_LINE
+#undef ITER
+#undef F2
+}
+
+#define doHorizLowPass_altivec(a...) doHorizLowPass_C(a)
+#define doHorizDefFilter_altivec(a...) doHorizDefFilter_C(a)
+#define do_a_deblock_altivec(a...) do_a_deblock_C(a)
+
+static inline void tempNoiseReducer_altivec(uint8_t *src, int stride,
+ uint8_t *tempBlurred, uint32_t *tempBlurredPast, int *maxNoise)
+{
+ const vector signed char neg1 = vec_splat_s8(-1);
+ const vector unsigned char permHH = (const vector unsigned char){0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
+
+ const vector signed int zero = vec_splat_s32(0);
+ const vector signed short vsint16_1 = vec_splat_s16(1);
+ vector signed int v_dp = zero;
+ vector signed int v_sysdp = zero;
+ int d, sysd, i;
+
+#define LOAD_LINE(src, i) \
+ register int j##src##i = i * stride; \
+ vector unsigned char perm##src##i = vec_lvsl(j##src##i, src); \
+ const vector unsigned char v_##src##A1##i = vec_ld(j##src##i, src); \
+ const vector unsigned char v_##src##A2##i = vec_ld(j##src##i + 16, src); \
+ const vector unsigned char v_##src##A##i = \
+ vec_perm(v_##src##A1##i, v_##src##A2##i, perm##src##i); \
+ vector signed short v_##src##Ass##i = \
+ (vector signed short)vec_mergeh((vector signed char)zero, \
+ (vector signed char)v_##src##A##i)
+
+ LOAD_LINE(src, 0);
+ LOAD_LINE(src, 1);
+ LOAD_LINE(src, 2);
+ LOAD_LINE(src, 3);
+ LOAD_LINE(src, 4);
+ LOAD_LINE(src, 5);
+ LOAD_LINE(src, 6);
+ LOAD_LINE(src, 7);
+
+ LOAD_LINE(tempBlurred, 0);
+ LOAD_LINE(tempBlurred, 1);
+ LOAD_LINE(tempBlurred, 2);
+ LOAD_LINE(tempBlurred, 3);
+ LOAD_LINE(tempBlurred, 4);
+ LOAD_LINE(tempBlurred, 5);
+ LOAD_LINE(tempBlurred, 6);
+ LOAD_LINE(tempBlurred, 7);
+#undef LOAD_LINE
+
+#define ACCUMULATE_DIFFS(i) do { \
+ vector signed short v_d = vec_sub(v_tempBlurredAss##i, \
+ v_srcAss##i); \
+ v_dp = vec_msums(v_d, v_d, v_dp); \
+ v_sysdp = vec_msums(v_d, vsint16_1, v_sysdp); \
+ } while (0)
+
+ ACCUMULATE_DIFFS(0);
+ ACCUMULATE_DIFFS(1);
+ ACCUMULATE_DIFFS(2);
+ ACCUMULATE_DIFFS(3);
+ ACCUMULATE_DIFFS(4);
+ ACCUMULATE_DIFFS(5);
+ ACCUMULATE_DIFFS(6);
+ ACCUMULATE_DIFFS(7);
+#undef ACCUMULATE_DIFFS
+
+ tempBlurredPast[127]= maxNoise[0];
+ tempBlurredPast[128]= maxNoise[1];
+ tempBlurredPast[129]= maxNoise[2];
+
+ v_dp = vec_sums(v_dp, zero);
+ v_sysdp = vec_sums(v_sysdp, zero);
+
+ v_dp = vec_splat(v_dp, 3);
+ v_sysdp = vec_splat(v_sysdp, 3);
+
+ vec_ste(v_dp, 0, &d);
+ vec_ste(v_sysdp, 0, &sysd);
+
+ i = d;
+ d = (4*d
+ +(*(tempBlurredPast-256))
+ +(*(tempBlurredPast-1))+ (*(tempBlurredPast+1))
+ +(*(tempBlurredPast+256))
+ +4)>>3;
+
+ *tempBlurredPast=i;
+
+ if (d > maxNoise[1]) {
+ if (d < maxNoise[2]) {
+#define OP(i) v_tempBlurredAss##i = vec_avg(v_tempBlurredAss##i, v_srcAss##i);
+
+ OP(0);
+ OP(1);
+ OP(2);
+ OP(3);
+ OP(4);
+ OP(5);
+ OP(6);
+ OP(7);
+#undef OP
+ } else {
+#define OP(i) v_tempBlurredAss##i = v_srcAss##i;
+
+ OP(0);
+ OP(1);
+ OP(2);
+ OP(3);
+ OP(4);
+ OP(5);
+ OP(6);
+ OP(7);
+#undef OP
+ }
+ } else {
+ if (d < maxNoise[0]) {
+ const vector signed short vsint16_7 = vec_splat_s16(7);
+ const vector signed short vsint16_4 = vec_splat_s16(4);
+ const vector unsigned short vuint16_3 = vec_splat_u16(3);
+
+#define OP(i) do { \
+ const vector signed short v_temp = \
+ vec_mladd(v_tempBlurredAss##i, vsint16_7, v_srcAss##i); \
+ const vector signed short v_temp2 = vec_add(v_temp, vsint16_4); \
+ v_tempBlurredAss##i = vec_sr(v_temp2, vuint16_3); \
+ } while (0)
+
+ OP(0);
+ OP(1);
+ OP(2);
+ OP(3);
+ OP(4);
+ OP(5);
+ OP(6);
+ OP(7);
+#undef OP
+ } else {
+ const vector signed short vsint16_3 = vec_splat_s16(3);
+ const vector signed short vsint16_2 = vec_splat_s16(2);
+
+#define OP(i) do { \
+ const vector signed short v_temp = \
+ vec_mladd(v_tempBlurredAss##i, vsint16_3, v_srcAss##i); \
+ const vector signed short v_temp2 = vec_add(v_temp, vsint16_2); \
+ v_tempBlurredAss##i = \
+ vec_sr(v_temp2, (vector unsigned short)vsint16_2); \
+ } while (0)
+
+ OP(0);
+ OP(1);
+ OP(2);
+ OP(3);
+ OP(4);
+ OP(5);
+ OP(6);
+ OP(7);
+#undef OP
+ }
+ }
+
+#define PACK_AND_STORE(src, i) do { \
+ const vector unsigned char perms = vec_lvsr(i * stride, src); \
+ const vector unsigned char vf = \
+ vec_packsu(v_tempBlurredAss##1, (vector signed short)zero); \
+ const vector unsigned char vg = vec_perm(vf, v_##src##A##i, permHH); \
+ const vector unsigned char mask = \
+ vec_perm((vector unsigned char)zero, (vector unsigned char)neg1, perms); \
+ const vector unsigned char vg2 = vec_perm(vg, vg, perms); \
+ const vector unsigned char svA = vec_sel(v_##src##A1##i, vg2, mask); \
+ const vector unsigned char svB = vec_sel(vg2, v_##src##A2##i, mask); \
+ vec_st(svA, i * stride, src); \
+ vec_st(svB, i * stride + 16, src); \
+} while (0)
+
+ PACK_AND_STORE(src, 0);
+ PACK_AND_STORE(src, 1);
+ PACK_AND_STORE(src, 2);
+ PACK_AND_STORE(src, 3);
+ PACK_AND_STORE(src, 4);
+ PACK_AND_STORE(src, 5);
+ PACK_AND_STORE(src, 6);
+ PACK_AND_STORE(src, 7);
+ PACK_AND_STORE(tempBlurred, 0);
+ PACK_AND_STORE(tempBlurred, 1);
+ PACK_AND_STORE(tempBlurred, 2);
+ PACK_AND_STORE(tempBlurred, 3);
+ PACK_AND_STORE(tempBlurred, 4);
+ PACK_AND_STORE(tempBlurred, 5);
+ PACK_AND_STORE(tempBlurred, 6);
+ PACK_AND_STORE(tempBlurred, 7);
+#undef PACK_AND_STORE
+}
+
+static inline void transpose_16x8_char_toPackedAlign_altivec(unsigned char* dst, unsigned char* src, int stride) {
+ const vector unsigned char zero = vec_splat_u8(0);
+
+#define LOAD_DOUBLE_LINE(i, j) \
+ vector unsigned char perm1##i = vec_lvsl(i * stride, src); \
+ vector unsigned char perm2##i = vec_lvsl(j * stride, src); \
+ vector unsigned char srcA##i = vec_ld(i * stride, src); \
+ vector unsigned char srcB##i = vec_ld(i * stride + 16, src); \
+ vector unsigned char srcC##i = vec_ld(j * stride, src); \
+ vector unsigned char srcD##i = vec_ld(j * stride+ 16, src); \
+ vector unsigned char src##i = vec_perm(srcA##i, srcB##i, perm1##i); \
+ vector unsigned char src##j = vec_perm(srcC##i, srcD##i, perm2##i)
+
+ LOAD_DOUBLE_LINE(0, 1);
+ LOAD_DOUBLE_LINE(2, 3);
+ LOAD_DOUBLE_LINE(4, 5);
+ LOAD_DOUBLE_LINE(6, 7);
+#undef LOAD_DOUBLE_LINE
+
+ vector unsigned char tempA = vec_mergeh(src0, zero);
+ vector unsigned char tempB = vec_mergel(src0, zero);
+ vector unsigned char tempC = vec_mergeh(src1, zero);
+ vector unsigned char tempD = vec_mergel(src1, zero);
+ vector unsigned char tempE = vec_mergeh(src2, zero);
+ vector unsigned char tempF = vec_mergel(src2, zero);
+ vector unsigned char tempG = vec_mergeh(src3, zero);
+ vector unsigned char tempH = vec_mergel(src3, zero);
+ vector unsigned char tempI = vec_mergeh(src4, zero);
+ vector unsigned char tempJ = vec_mergel(src4, zero);
+ vector unsigned char tempK = vec_mergeh(src5, zero);
+ vector unsigned char tempL = vec_mergel(src5, zero);
+ vector unsigned char tempM = vec_mergeh(src6, zero);
+ vector unsigned char tempN = vec_mergel(src6, zero);
+ vector unsigned char tempO = vec_mergeh(src7, zero);
+ vector unsigned char tempP = vec_mergel(src7, zero);
+
+ vector unsigned char temp0 = vec_mergeh(tempA, tempI);
+ vector unsigned char temp1 = vec_mergel(tempA, tempI);
+ vector unsigned char temp2 = vec_mergeh(tempB, tempJ);
+ vector unsigned char temp3 = vec_mergel(tempB, tempJ);
+ vector unsigned char temp4 = vec_mergeh(tempC, tempK);
+ vector unsigned char temp5 = vec_mergel(tempC, tempK);
+ vector unsigned char temp6 = vec_mergeh(tempD, tempL);
+ vector unsigned char temp7 = vec_mergel(tempD, tempL);
+ vector unsigned char temp8 = vec_mergeh(tempE, tempM);
+ vector unsigned char temp9 = vec_mergel(tempE, tempM);
+ vector unsigned char temp10 = vec_mergeh(tempF, tempN);
+ vector unsigned char temp11 = vec_mergel(tempF, tempN);
+ vector unsigned char temp12 = vec_mergeh(tempG, tempO);
+ vector unsigned char temp13 = vec_mergel(tempG, tempO);
+ vector unsigned char temp14 = vec_mergeh(tempH, tempP);
+ vector unsigned char temp15 = vec_mergel(tempH, tempP);
+
+ tempA = vec_mergeh(temp0, temp8);
+ tempB = vec_mergel(temp0, temp8);
+ tempC = vec_mergeh(temp1, temp9);
+ tempD = vec_mergel(temp1, temp9);
+ tempE = vec_mergeh(temp2, temp10);
+ tempF = vec_mergel(temp2, temp10);
+ tempG = vec_mergeh(temp3, temp11);
+ tempH = vec_mergel(temp3, temp11);
+ tempI = vec_mergeh(temp4, temp12);
+ tempJ = vec_mergel(temp4, temp12);
+ tempK = vec_mergeh(temp5, temp13);
+ tempL = vec_mergel(temp5, temp13);
+ tempM = vec_mergeh(temp6, temp14);
+ tempN = vec_mergel(temp6, temp14);
+ tempO = vec_mergeh(temp7, temp15);
+ tempP = vec_mergel(temp7, temp15);
+
+ temp0 = vec_mergeh(tempA, tempI);
+ temp1 = vec_mergel(tempA, tempI);
+ temp2 = vec_mergeh(tempB, tempJ);
+ temp3 = vec_mergel(tempB, tempJ);
+ temp4 = vec_mergeh(tempC, tempK);
+ temp5 = vec_mergel(tempC, tempK);
+ temp6 = vec_mergeh(tempD, tempL);
+ temp7 = vec_mergel(tempD, tempL);
+ temp8 = vec_mergeh(tempE, tempM);
+ temp9 = vec_mergel(tempE, tempM);
+ temp10 = vec_mergeh(tempF, tempN);
+ temp11 = vec_mergel(tempF, tempN);
+ temp12 = vec_mergeh(tempG, tempO);
+ temp13 = vec_mergel(tempG, tempO);
+ temp14 = vec_mergeh(tempH, tempP);
+ temp15 = vec_mergel(tempH, tempP);
+
+ vec_st(temp0, 0, dst);
+ vec_st(temp1, 16, dst);
+ vec_st(temp2, 32, dst);
+ vec_st(temp3, 48, dst);
+ vec_st(temp4, 64, dst);
+ vec_st(temp5, 80, dst);
+ vec_st(temp6, 96, dst);
+ vec_st(temp7, 112, dst);
+ vec_st(temp8, 128, dst);
+ vec_st(temp9, 144, dst);
+ vec_st(temp10, 160, dst);
+ vec_st(temp11, 176, dst);
+ vec_st(temp12, 192, dst);
+ vec_st(temp13, 208, dst);
+ vec_st(temp14, 224, dst);
+ vec_st(temp15, 240, dst);
+}
+
+static inline void transpose_8x16_char_fromPackedAlign_altivec(unsigned char* dst, unsigned char* src, int stride) {
+ const vector unsigned char zero = vec_splat_u8(0);
+ const vector signed char neg1 = vec_splat_s8(-1);
+
+#define LOAD_DOUBLE_LINE(i, j) \
+ vector unsigned char src##i = vec_ld(i * 16, src); \
+ vector unsigned char src##j = vec_ld(j * 16, src)
+
+ LOAD_DOUBLE_LINE(0, 1);
+ LOAD_DOUBLE_LINE(2, 3);
+ LOAD_DOUBLE_LINE(4, 5);
+ LOAD_DOUBLE_LINE(6, 7);
+ LOAD_DOUBLE_LINE(8, 9);
+ LOAD_DOUBLE_LINE(10, 11);
+ LOAD_DOUBLE_LINE(12, 13);
+ LOAD_DOUBLE_LINE(14, 15);
+#undef LOAD_DOUBLE_LINE
+
+ vector unsigned char tempA = vec_mergeh(src0, src8);
+ vector unsigned char tempB;
+ vector unsigned char tempC = vec_mergeh(src1, src9);
+ vector unsigned char tempD;
+ vector unsigned char tempE = vec_mergeh(src2, src10);
+ vector unsigned char tempG = vec_mergeh(src3, src11);
+ vector unsigned char tempI = vec_mergeh(src4, src12);
+ vector unsigned char tempJ;
+ vector unsigned char tempK = vec_mergeh(src5, src13);
+ vector unsigned char tempL;
+ vector unsigned char tempM = vec_mergeh(src6, src14);
+ vector unsigned char tempO = vec_mergeh(src7, src15);
+
+ vector unsigned char temp0 = vec_mergeh(tempA, tempI);
+ vector unsigned char temp1 = vec_mergel(tempA, tempI);
+ vector unsigned char temp2;
+ vector unsigned char temp3;
+ vector unsigned char temp4 = vec_mergeh(tempC, tempK);
+ vector unsigned char temp5 = vec_mergel(tempC, tempK);
+ vector unsigned char temp6;
+ vector unsigned char temp7;
+ vector unsigned char temp8 = vec_mergeh(tempE, tempM);
+ vector unsigned char temp9 = vec_mergel(tempE, tempM);
+ vector unsigned char temp12 = vec_mergeh(tempG, tempO);
+ vector unsigned char temp13 = vec_mergel(tempG, tempO);
+
+ tempA = vec_mergeh(temp0, temp8);
+ tempB = vec_mergel(temp0, temp8);
+ tempC = vec_mergeh(temp1, temp9);
+ tempD = vec_mergel(temp1, temp9);
+ tempI = vec_mergeh(temp4, temp12);
+ tempJ = vec_mergel(temp4, temp12);
+ tempK = vec_mergeh(temp5, temp13);
+ tempL = vec_mergel(temp5, temp13);
+
+ temp0 = vec_mergeh(tempA, tempI);
+ temp1 = vec_mergel(tempA, tempI);
+ temp2 = vec_mergeh(tempB, tempJ);
+ temp3 = vec_mergel(tempB, tempJ);
+ temp4 = vec_mergeh(tempC, tempK);
+ temp5 = vec_mergel(tempC, tempK);
+ temp6 = vec_mergeh(tempD, tempL);
+ temp7 = vec_mergel(tempD, tempL);
+
+
+#define STORE_DOUBLE_LINE(i, j) do { \
+ vector unsigned char dstAi = vec_ld(i * stride, dst); \
+ vector unsigned char dstBi = vec_ld(i * stride + 16, dst); \
+ vector unsigned char dstAj = vec_ld(j * stride, dst); \
+ vector unsigned char dstBj = vec_ld(j * stride+ 16, dst); \
+ vector unsigned char aligni = vec_lvsr(i * stride, dst); \
+ vector unsigned char alignj = vec_lvsr(j * stride, dst); \
+ vector unsigned char maski = \
+ vec_perm(zero, (vector unsigned char)neg1, aligni); \
+ vector unsigned char maskj = \
+ vec_perm(zero, (vector unsigned char)neg1, alignj); \
+ vector unsigned char dstRi = vec_perm(temp##i, temp##i, aligni); \
+ vector unsigned char dstRj = vec_perm(temp##j, temp##j, alignj); \
+ vector unsigned char dstAFi = vec_sel(dstAi, dstRi, maski); \
+ vector unsigned char dstBFi = vec_sel(dstRi, dstBi, maski); \
+ vector unsigned char dstAFj = vec_sel(dstAj, dstRj, maskj); \
+ vector unsigned char dstBFj = vec_sel(dstRj, dstBj, maskj); \
+ vec_st(dstAFi, i * stride, dst); \
+ vec_st(dstBFi, i * stride + 16, dst); \
+ vec_st(dstAFj, j * stride, dst); \
+ vec_st(dstBFj, j * stride + 16, dst); \
+} while (0)
+
+ STORE_DOUBLE_LINE(0,1);
+ STORE_DOUBLE_LINE(2,3);
+ STORE_DOUBLE_LINE(4,5);
+ STORE_DOUBLE_LINE(6,7);
+}
diff --git a/libpostproc/postprocess_internal.h b/libpostproc/postprocess_internal.h
new file mode 100644
index 0000000000..c1a306dd32
--- /dev/null
+++ b/libpostproc/postprocess_internal.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2001-2002 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * 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
+ * internal API header.
+ */
+
+#ifndef POSTPROC_POSTPROCESS_INTERNAL_H
+#define POSTPROC_POSTPROCESS_INTERNAL_H
+
+#include <string.h>
+#include "libavutil/avutil.h"
+#include "libavutil/intmath.h"
+#include "libavutil/log.h"
+#include "postprocess.h"
+
+#define V_DEBLOCK 0x01
+#define H_DEBLOCK 0x02
+#define DERING 0x04
+#define LEVEL_FIX 0x08 ///< Brightness & Contrast
+
+#define LUM_V_DEBLOCK V_DEBLOCK // 1
+#define LUM_H_DEBLOCK H_DEBLOCK // 2
+#define CHROM_V_DEBLOCK (V_DEBLOCK<<4) // 16
+#define CHROM_H_DEBLOCK (H_DEBLOCK<<4) // 32
+#define LUM_DERING DERING // 4
+#define CHROM_DERING (DERING<<4) // 64
+#define LUM_LEVEL_FIX LEVEL_FIX // 8
+#define CHROM_LEVEL_FIX (LEVEL_FIX<<4) // 128 (not implemented yet)
+
+// Experimental vertical filters
+#define V_X1_FILTER 0x0200 // 512
+#define V_A_DEBLOCK 0x0400
+
+// Experimental horizontal filters
+#define H_X1_FILTER 0x2000 // 8192
+#define H_A_DEBLOCK 0x4000
+
+/// select between full y range (255-0) or standard one (234-16)
+#define FULL_Y_RANGE 0x8000 // 32768
+
+//Deinterlacing Filters
+#define LINEAR_IPOL_DEINT_FILTER 0x10000 // 65536
+#define LINEAR_BLEND_DEINT_FILTER 0x20000 // 131072
+#define CUBIC_BLEND_DEINT_FILTER 0x8000 // (not implemented yet)
+#define CUBIC_IPOL_DEINT_FILTER 0x40000 // 262144
+#define MEDIAN_DEINT_FILTER 0x80000 // 524288
+#define FFMPEG_DEINT_FILTER 0x400000
+#define LOWPASS5_DEINT_FILTER 0x800000
+
+#define TEMP_NOISE_FILTER 0x100000
+#define FORCE_QUANT 0x200000
+#define BITEXACT 0x1000000
+#define VISUALIZE 0x2000000
+
+//use if you want a faster postprocessing code
+//cannot differentiate between chroma & luma filters (both on or both off)
+//obviously the -pp option on the command line has no effect except turning the here selected
+//filters on
+//#define COMPILE_TIME_MODE 0x77
+
+/**
+ * Postprocessing filter.
+ */
+struct PPFilter{
+ const char *shortName;
+ const char *longName;
+ int chromDefault; ///< is chrominance filtering on by default if this filter is manually activated
+ int minLumQuality; ///< minimum quality to turn luminance filtering on
+ int minChromQuality; ///< minimum quality to turn chrominance filtering on
+ int mask; ///< Bitmask to turn this filter on
+};
+
+/**
+ * Postprocessing mode.
+ */
+typedef struct PPMode{
+ int lumMode; ///< activates filters for luminance
+ int chromMode; ///< activates filters for chrominance
+ int error; ///< non zero on error
+
+ int minAllowedY; ///< for brightness correction
+ int maxAllowedY; ///< for brightness correction
+ float maxClippedThreshold; ///< amount of "black" you are willing to lose to get a brightness-corrected picture
+
+ int maxTmpNoise[3]; ///< for Temporal Noise Reducing filter (Maximal sum of abs differences)
+
+ int baseDcDiff;
+ int flatnessThreshold;
+
+ int forcedQuant; ///< quantizer if FORCE_QUANT is used
+} PPMode;
+
+/**
+ * postprocess context.
+ */
+typedef struct PPContext{
+ /**
+ * info on struct for av_log
+ */
+ const AVClass *av_class;
+
+ uint8_t *tempBlocks; ///<used for the horizontal code
+
+ /**
+ * luma histogram.
+ * we need 64bit here otherwise we'll going to have a problem
+ * after watching a black picture for 5 hours
+ */
+ uint64_t *yHistogram;
+
+ DECLARE_ALIGNED(8, uint64_t, packedYOffset);
+ DECLARE_ALIGNED(8, uint64_t, packedYScale);
+
+ /** Temporal noise reducing buffers */
+ uint8_t *tempBlurred[3];
+ int32_t *tempBlurredPast[3];
+
+ /** Temporary buffers for handling the last row(s) */
+ uint8_t *tempDst;
+ uint8_t *tempSrc;
+
+ uint8_t *deintTemp;
+
+ DECLARE_ALIGNED(8, uint64_t, pQPb);
+ DECLARE_ALIGNED(8, uint64_t, pQPb2);
+
+ DECLARE_ALIGNED(32, uint64_t, pQPb_block)[4];
+ DECLARE_ALIGNED(32, uint64_t, pQPb2_block)[4];
+
+ DECLARE_ALIGNED(32, uint64_t, mmxDcOffset)[64];
+ DECLARE_ALIGNED(32, uint64_t, mmxDcThreshold)[64];
+
+ QP_STORE_T *stdQPTable; ///< used to fix MPEG2 style qscale
+ QP_STORE_T *nonBQPTable;
+ QP_STORE_T *forcedQPTable;
+
+ int QP;
+ int nonBQP;
+
+ DECLARE_ALIGNED(32, int, QP_block)[4];
+ DECLARE_ALIGNED(32, int, nonBQP_block)[4];
+
+ int frameNum;
+
+ int cpuCaps;
+
+ int qpStride; ///<size of qp buffers (needed to realloc them if needed)
+ int stride; ///<size of some buffers (needed to realloc them if needed)
+
+ int hChromaSubSample;
+ int vChromaSubSample;
+
+ PPMode ppMode;
+} PPContext;
+
+
+static inline void linecpy(void *dest, const void *src, int lines, int stride) {
+ if (stride > 0) {
+ memcpy(dest, src, lines*stride);
+ } else {
+ memcpy((uint8_t*)dest+(lines-1)*stride, (const uint8_t*)src+(lines-1)*stride, -lines*stride);
+ }
+}
+
+#endif /* POSTPROC_POSTPROCESS_INTERNAL_H */
diff --git a/libpostproc/postprocess_template.c b/libpostproc/postprocess_template.c
new file mode 100644
index 0000000000..b7296c4da1
--- /dev/null
+++ b/libpostproc/postprocess_template.c
@@ -0,0 +1,3746 @@
+/*
+ * Copyright (C) 2001-2002 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * 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
+ * mmx/mmx2/3dnow postprocess code.
+ */
+
+#include "libavutil/x86/asm.h"
+
+/* 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
+ * (like MMX2 depending on MMX), and will define to 0 all the others. Every
+ * TEMPLATE_PP_* need to be undef at the end. */
+
+#ifdef TEMPLATE_PP_C
+# define RENAME(a) a ## _C
+#else
+# define TEMPLATE_PP_C 0
+#endif
+
+#ifdef TEMPLATE_PP_ALTIVEC
+# define RENAME(a) a ## _altivec
+#else
+# define TEMPLATE_PP_ALTIVEC 0
+#endif
+
+#ifdef TEMPLATE_PP_MMX
+# define RENAME(a) a ## _MMX
+#else
+# define TEMPLATE_PP_MMX 0
+#endif
+
+#ifdef TEMPLATE_PP_MMXEXT
+# undef TEMPLATE_PP_MMX
+# define TEMPLATE_PP_MMX 1
+# define RENAME(a) a ## _MMX2
+#else
+# define TEMPLATE_PP_MMXEXT 0
+#endif
+
+#ifdef TEMPLATE_PP_3DNOW
+# undef TEMPLATE_PP_MMX
+# define TEMPLATE_PP_MMX 1
+# define RENAME(a) a ## _3DNow
+#else
+# define TEMPLATE_PP_3DNOW 0
+#endif
+
+#ifdef TEMPLATE_PP_SSE2
+# undef TEMPLATE_PP_MMX
+# define TEMPLATE_PP_MMX 1
+# undef TEMPLATE_PP_MMXEXT
+# define TEMPLATE_PP_MMXEXT 1
+# define RENAME(a) a ## _SSE2
+#else
+# define TEMPLATE_PP_SSE2 0
+#endif
+
+#undef REAL_PAVGB
+#undef PAVGB
+#undef PMINUB
+#undef PMAXUB
+
+#if TEMPLATE_PP_MMXEXT
+#define REAL_PAVGB(a,b) "pavgb " #a ", " #b " \n\t"
+#elif TEMPLATE_PP_3DNOW
+#define REAL_PAVGB(a,b) "pavgusb " #a ", " #b " \n\t"
+#endif
+#define PAVGB(a,b) REAL_PAVGB(a,b)
+
+#if TEMPLATE_PP_MMXEXT
+#define PMINUB(a,b,t) "pminub " #a ", " #b " \n\t"
+#elif TEMPLATE_PP_MMX
+#define PMINUB(b,a,t) \
+ "movq " #a ", " #t " \n\t"\
+ "psubusb " #b ", " #t " \n\t"\
+ "psubb " #t ", " #a " \n\t"
+#endif
+
+#if TEMPLATE_PP_MMXEXT
+#define PMAXUB(a,b) "pmaxub " #a ", " #b " \n\t"
+#elif TEMPLATE_PP_MMX
+#define PMAXUB(a,b) \
+ "psubusb " #a ", " #b " \n\t"\
+ "paddb " #a ", " #b " \n\t"
+#endif
+
+//FIXME? |255-0| = 1 (should not be a problem ...)
+#if TEMPLATE_PP_MMX
+/**
+ * Check if the middle 8x8 Block in the given 8x16 block is flat
+ */
+static inline int RENAME(vertClassify)(const uint8_t src[], int stride, PPContext *c){
+ int numEq= 0, dcOk;
+ src+= stride*4; // src points to begin of the 8x8 Block
+ __asm__ volatile(
+ "movq %0, %%mm7 \n\t"
+ "movq %1, %%mm6 \n\t"
+ : : "m" (c->mmxDcOffset[c->nonBQP]), "m" (c->mmxDcThreshold[c->nonBQP])
+ );
+
+ __asm__ volatile(
+ "lea (%2, %3), %%"REG_a" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %1 eax eax+%2 eax+2%2 %1+4%2 ecx ecx+%2 ecx+2%2 %1+8%2 ecx+4%2
+
+ "movq (%2), %%mm0 \n\t"
+ "movq (%%"REG_a"), %%mm1 \n\t"
+ "movq %%mm0, %%mm3 \n\t"
+ "movq %%mm0, %%mm4 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm0 \n\t" // mm0 = difference
+ "paddb %%mm7, %%mm0 \n\t"
+ "pcmpgtb %%mm6, %%mm0 \n\t"
+
+ "movq (%%"REG_a",%3), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3, 2), %%mm1 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+
+ "lea (%%"REG_a", %3, 4), %%"REG_a" \n\t"
+
+ "movq (%2, %3, 4), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a"), %%mm1 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3, 2), %%mm1 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+ "psubusb %%mm3, %%mm4 \n\t"
+
+ " \n\t"
+#if TEMPLATE_PP_MMXEXT
+ "pxor %%mm7, %%mm7 \n\t"
+ "psadbw %%mm7, %%mm0 \n\t"
+#else
+ "movq %%mm0, %%mm1 \n\t"
+ "psrlw $8, %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "psrlq $16, %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "psrlq $32, %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+#endif
+ "movq %4, %%mm7 \n\t" // QP,..., QP
+ "paddusb %%mm7, %%mm7 \n\t" // 2QP ... 2QP
+ "psubusb %%mm7, %%mm4 \n\t" // Diff <= 2QP -> 0
+ "packssdw %%mm4, %%mm4 \n\t"
+ "movd %%mm0, %0 \n\t"
+ "movd %%mm4, %1 \n\t"
+
+ : "=r" (numEq), "=r" (dcOk)
+ : "r" (src), "r" ((x86_reg)stride), "m" (c->pQPb)
+ : "%"REG_a
+ );
+
+ numEq= (-numEq) &0xFF;
+ if(numEq > c->ppMode.flatnessThreshold){
+ if(dcOk) return 0;
+ else return 1;
+ }else{
+ return 2;
+ }
+}
+#endif //TEMPLATE_PP_MMX
+
+/**
+ * Do a vertical low pass filter on the 8x16 block (only write to the 8x8 block in the middle)
+ * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16
+ */
+#if !TEMPLATE_PP_ALTIVEC
+static inline void RENAME(doVertLowPass)(uint8_t *src, int stride, PPContext *c)
+{
+#if TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ src+= stride*3;
+ __asm__ volatile( //"movv %0 %1 %2\n\t"
+ "movq %2, %%mm0 \n\t" // QP,..., QP
+ "pxor %%mm4, %%mm4 \n\t"
+
+ "movq (%0), %%mm6 \n\t"
+ "movq (%0, %1), %%mm5 \n\t"
+ "movq %%mm5, %%mm1 \n\t"
+ "movq %%mm6, %%mm2 \n\t"
+ "psubusb %%mm6, %%mm5 \n\t"
+ "psubusb %%mm1, %%mm2 \n\t"
+ "por %%mm5, %%mm2 \n\t" // ABS Diff of lines
+ "psubusb %%mm0, %%mm2 \n\t" // diff <= QP -> 0
+ "pcmpeqb %%mm4, %%mm2 \n\t" // diff <= QP -> FF
+
+ "pand %%mm2, %%mm6 \n\t"
+ "pandn %%mm1, %%mm2 \n\t"
+ "por %%mm2, %%mm6 \n\t"// First Line to Filter
+
+ "movq (%0, %1, 8), %%mm5 \n\t"
+ "lea (%0, %1, 4), %%"REG_a" \n\t"
+ "lea (%0, %1, 8), %%"REG_c" \n\t"
+ "sub %1, %%"REG_c" \n\t"
+ "add %1, %0 \n\t" // %0 points to line 1 not 0
+ "movq (%0, %1, 8), %%mm7 \n\t"
+ "movq %%mm5, %%mm1 \n\t"
+ "movq %%mm7, %%mm2 \n\t"
+ "psubusb %%mm7, %%mm5 \n\t"
+ "psubusb %%mm1, %%mm2 \n\t"
+ "por %%mm5, %%mm2 \n\t" // ABS Diff of lines
+ "psubusb %%mm0, %%mm2 \n\t" // diff <= QP -> 0
+ "pcmpeqb %%mm4, %%mm2 \n\t" // diff <= QP -> FF
+
+ "pand %%mm2, %%mm7 \n\t"
+ "pandn %%mm1, %%mm2 \n\t"
+ "por %%mm2, %%mm7 \n\t" // First Line to Filter
+
+
+ // 1 2 3 4 5 6 7 8
+ // %0 %0+%1 %0+2%1 eax %0+4%1 eax+2%1 ecx eax+4%1
+ // 6 4 2 2 1 1
+ // 6 4 4 2
+ // 6 8 2
+
+ "movq (%0, %1), %%mm0 \n\t" // 1
+ "movq %%mm0, %%mm1 \n\t" // 1
+ PAVGB(%%mm6, %%mm0) //1 1 /2
+ PAVGB(%%mm6, %%mm0) //3 1 /4
+
+ "movq (%0, %1, 4), %%mm2 \n\t" // 1
+ "movq %%mm2, %%mm5 \n\t" // 1
+ PAVGB((%%REGa), %%mm2) // 11 /2
+ PAVGB((%0, %1, 2), %%mm2) // 211 /4
+ "movq %%mm2, %%mm3 \n\t" // 211 /4
+ "movq (%0), %%mm4 \n\t" // 1
+ PAVGB(%%mm4, %%mm3) // 4 211 /8
+ PAVGB(%%mm0, %%mm3) //642211 /16
+ "movq %%mm3, (%0) \n\t" // X
+ // mm1=2 mm2=3(211) mm4=1 mm5=5 mm6=0 mm7=9
+ "movq %%mm1, %%mm0 \n\t" // 1
+ PAVGB(%%mm6, %%mm0) //1 1 /2
+ "movq %%mm4, %%mm3 \n\t" // 1
+ PAVGB((%0,%1,2), %%mm3) // 1 1 /2
+ PAVGB((%%REGa,%1,2), %%mm5) // 11 /2
+ PAVGB((%%REGa), %%mm5) // 211 /4
+ PAVGB(%%mm5, %%mm3) // 2 2211 /8
+ PAVGB(%%mm0, %%mm3) //4242211 /16
+ "movq %%mm3, (%0,%1) \n\t" // X
+ // mm1=2 mm2=3(211) mm4=1 mm5=4(211) mm6=0 mm7=9
+ PAVGB(%%mm4, %%mm6) //11 /2
+ "movq (%%"REG_c"), %%mm0 \n\t" // 1
+ PAVGB((%%REGa, %1, 2), %%mm0) // 11/2
+ "movq %%mm0, %%mm3 \n\t" // 11/2
+ PAVGB(%%mm1, %%mm0) // 2 11/4
+ PAVGB(%%mm6, %%mm0) //222 11/8
+ PAVGB(%%mm2, %%mm0) //22242211/16
+ "movq (%0, %1, 2), %%mm2 \n\t" // 1
+ "movq %%mm0, (%0, %1, 2) \n\t" // X
+ // mm1=2 mm2=3 mm3=6(11) mm4=1 mm5=4(211) mm6=0(11) mm7=9
+ "movq (%%"REG_a", %1, 4), %%mm0 \n\t" // 1
+ PAVGB((%%REGc), %%mm0) // 11 /2
+ PAVGB(%%mm0, %%mm6) //11 11 /4
+ PAVGB(%%mm1, %%mm4) // 11 /2
+ PAVGB(%%mm2, %%mm1) // 11 /2
+ PAVGB(%%mm1, %%mm6) //1122 11 /8
+ PAVGB(%%mm5, %%mm6) //112242211 /16
+ "movq (%%"REG_a"), %%mm5 \n\t" // 1
+ "movq %%mm6, (%%"REG_a") \n\t" // X
+ // mm0=7(11) mm1=2(11) mm2=3 mm3=6(11) mm4=1(11) mm5=4 mm7=9
+ "movq (%%"REG_a", %1, 4), %%mm6 \n\t" // 1
+ PAVGB(%%mm7, %%mm6) // 11 /2
+ PAVGB(%%mm4, %%mm6) // 11 11 /4
+ PAVGB(%%mm3, %%mm6) // 11 2211 /8
+ PAVGB(%%mm5, %%mm2) // 11 /2
+ "movq (%0, %1, 4), %%mm4 \n\t" // 1
+ PAVGB(%%mm4, %%mm2) // 112 /4
+ PAVGB(%%mm2, %%mm6) // 112242211 /16
+ "movq %%mm6, (%0, %1, 4) \n\t" // X
+ // mm0=7(11) mm1=2(11) mm2=3(112) mm3=6(11) mm4=5 mm5=4 mm7=9
+ PAVGB(%%mm7, %%mm1) // 11 2 /4
+ PAVGB(%%mm4, %%mm5) // 11 /2
+ PAVGB(%%mm5, %%mm0) // 11 11 /4
+ "movq (%%"REG_a", %1, 2), %%mm6 \n\t" // 1
+ PAVGB(%%mm6, %%mm1) // 11 4 2 /8
+ PAVGB(%%mm0, %%mm1) // 11224222 /16
+ "movq %%mm1, (%%"REG_a", %1, 2) \n\t" // X
+ // mm2=3(112) mm3=6(11) mm4=5 mm5=4(11) mm6=6 mm7=9
+ PAVGB((%%REGc), %%mm2) // 112 4 /8
+ "movq (%%"REG_a", %1, 4), %%mm0 \n\t" // 1
+ PAVGB(%%mm0, %%mm6) // 1 1 /2
+ PAVGB(%%mm7, %%mm6) // 1 12 /4
+ PAVGB(%%mm2, %%mm6) // 1122424 /4
+ "movq %%mm6, (%%"REG_c") \n\t" // X
+ // mm0=8 mm3=6(11) mm4=5 mm5=4(11) mm7=9
+ PAVGB(%%mm7, %%mm5) // 11 2 /4
+ PAVGB(%%mm7, %%mm5) // 11 6 /8
+
+ PAVGB(%%mm3, %%mm0) // 112 /4
+ PAVGB(%%mm0, %%mm5) // 112246 /16
+ "movq %%mm5, (%%"REG_a", %1, 4) \n\t" // X
+ "sub %1, %0 \n\t"
+
+ :
+ : "r" (src), "r" ((x86_reg)stride), "m" (c->pQPb)
+ : "%"REG_a, "%"REG_c
+ );
+#else //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ const int l1= stride;
+ const int l2= stride + l1;
+ const int l3= stride + l2;
+ const int l4= stride + l3;
+ const int l5= stride + l4;
+ const int l6= stride + l5;
+ const int l7= stride + l6;
+ const int l8= stride + l7;
+ const int l9= stride + l8;
+ int x;
+ src+= stride*3;
+ for(x=0; x<BLOCK_SIZE; x++){
+ const int first= FFABS(src[0] - src[l1]) < c->QP ? src[0] : src[l1];
+ const int last= FFABS(src[l8] - src[l9]) < c->QP ? src[l9] : src[l8];
+
+ int sums[10];
+ sums[0] = 4*first + src[l1] + src[l2] + src[l3] + 4;
+ sums[1] = sums[0] - first + src[l4];
+ sums[2] = sums[1] - first + src[l5];
+ sums[3] = sums[2] - first + src[l6];
+ sums[4] = sums[3] - first + src[l7];
+ sums[5] = sums[4] - src[l1] + src[l8];
+ sums[6] = sums[5] - src[l2] + last;
+ sums[7] = sums[6] - src[l3] + last;
+ sums[8] = sums[7] - src[l4] + last;
+ sums[9] = sums[8] - src[l5] + last;
+
+ src[l1]= (sums[0] + sums[2] + 2*src[l1])>>4;
+ src[l2]= (sums[1] + sums[3] + 2*src[l2])>>4;
+ src[l3]= (sums[2] + sums[4] + 2*src[l3])>>4;
+ src[l4]= (sums[3] + sums[5] + 2*src[l4])>>4;
+ src[l5]= (sums[4] + sums[6] + 2*src[l5])>>4;
+ src[l6]= (sums[5] + sums[7] + 2*src[l6])>>4;
+ src[l7]= (sums[6] + sums[8] + 2*src[l7])>>4;
+ src[l8]= (sums[7] + sums[9] + 2*src[l8])>>4;
+
+ src++;
+ }
+#endif //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+#endif //TEMPLATE_PP_ALTIVEC
+
+/**
+ * Experimental Filter 1
+ * will not damage linear gradients
+ * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter
+ * can only smooth blocks at the expected locations (it cannot smooth them if they did move)
+ * MMX2 version does correct clipping C version does not
+ */
+static inline void RENAME(vertX1Filter)(uint8_t *src, int stride, PPContext *co)
+{
+#if TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ src+= stride*3;
+
+ __asm__ volatile(
+ "pxor %%mm7, %%mm7 \n\t" // 0
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_c" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 ecx ecx+%1 ecx+2%1 %0+8%1 ecx+4%1
+ "movq (%%"REG_a", %1, 2), %%mm0 \n\t" // line 3
+ "movq (%0, %1, 4), %%mm1 \n\t" // line 4
+ "movq %%mm1, %%mm2 \n\t" // line 4
+ "psubusb %%mm0, %%mm1 \n\t"
+ "psubusb %%mm2, %%mm0 \n\t"
+ "por %%mm1, %%mm0 \n\t" // |l2 - l3|
+ "movq (%%"REG_c"), %%mm3 \n\t" // line 5
+ "movq (%%"REG_c", %1), %%mm4 \n\t" // line 6
+ "movq %%mm3, %%mm5 \n\t" // line 5
+ "psubusb %%mm4, %%mm3 \n\t"
+ "psubusb %%mm5, %%mm4 \n\t"
+ "por %%mm4, %%mm3 \n\t" // |l5 - l6|
+ PAVGB(%%mm3, %%mm0) // (|l2 - l3| + |l5 - l6|)/2
+ "movq %%mm2, %%mm1 \n\t" // line 4
+ "psubusb %%mm5, %%mm2 \n\t"
+ "movq %%mm2, %%mm4 \n\t"
+ "pcmpeqb %%mm7, %%mm2 \n\t" // (l4 - l5) <= 0 ? -1 : 0
+ "psubusb %%mm1, %%mm5 \n\t"
+ "por %%mm5, %%mm4 \n\t" // |l4 - l5|
+ "psubusb %%mm0, %%mm4 \n\t" //d = MAX(0, |l4-l5| - (|l2-l3| + |l5-l6|)/2)
+ "movq %%mm4, %%mm3 \n\t" // d
+ "movq %2, %%mm0 \n\t"
+ "paddusb %%mm0, %%mm0 \n\t"
+ "psubusb %%mm0, %%mm4 \n\t"
+ "pcmpeqb %%mm7, %%mm4 \n\t" // d <= QP ? -1 : 0
+ "psubusb "MANGLE(b01)", %%mm3 \n\t"
+ "pand %%mm4, %%mm3 \n\t" // d <= QP ? d : 0
+
+ PAVGB(%%mm7, %%mm3) // d/2
+ "movq %%mm3, %%mm1 \n\t" // d/2
+ PAVGB(%%mm7, %%mm3) // d/4
+ PAVGB(%%mm1, %%mm3) // 3*d/8
+
+ "movq (%0, %1, 4), %%mm0 \n\t" // line 4
+ "pxor %%mm2, %%mm0 \n\t" //(l4 - l5) <= 0 ? -l4-1 : l4
+ "psubusb %%mm3, %%mm0 \n\t"
+ "pxor %%mm2, %%mm0 \n\t"
+ "movq %%mm0, (%0, %1, 4) \n\t" // line 4
+
+ "movq (%%"REG_c"), %%mm0 \n\t" // line 5
+ "pxor %%mm2, %%mm0 \n\t" //(l4 - l5) <= 0 ? -l5-1 : l5
+ "paddusb %%mm3, %%mm0 \n\t"
+ "pxor %%mm2, %%mm0 \n\t"
+ "movq %%mm0, (%%"REG_c") \n\t" // line 5
+
+ PAVGB(%%mm7, %%mm1) // d/4
+
+ "movq (%%"REG_a", %1, 2), %%mm0 \n\t" // line 3
+ "pxor %%mm2, %%mm0 \n\t" //(l4 - l5) <= 0 ? -l4-1 : l4
+ "psubusb %%mm1, %%mm0 \n\t"
+ "pxor %%mm2, %%mm0 \n\t"
+ "movq %%mm0, (%%"REG_a", %1, 2) \n\t" // line 3
+
+ "movq (%%"REG_c", %1), %%mm0 \n\t" // line 6
+ "pxor %%mm2, %%mm0 \n\t" //(l4 - l5) <= 0 ? -l5-1 : l5
+ "paddusb %%mm1, %%mm0 \n\t"
+ "pxor %%mm2, %%mm0 \n\t"
+ "movq %%mm0, (%%"REG_c", %1) \n\t" // line 6
+
+ PAVGB(%%mm7, %%mm1) // d/8
+
+ "movq (%%"REG_a", %1), %%mm0 \n\t" // line 2
+ "pxor %%mm2, %%mm0 \n\t" //(l4 - l5) <= 0 ? -l2-1 : l2
+ "psubusb %%mm1, %%mm0 \n\t"
+ "pxor %%mm2, %%mm0 \n\t"
+ "movq %%mm0, (%%"REG_a", %1) \n\t" // line 2
+
+ "movq (%%"REG_c", %1, 2), %%mm0 \n\t" // line 7
+ "pxor %%mm2, %%mm0 \n\t" //(l4 - l5) <= 0 ? -l7-1 : l7
+ "paddusb %%mm1, %%mm0 \n\t"
+ "pxor %%mm2, %%mm0 \n\t"
+ "movq %%mm0, (%%"REG_c", %1, 2) \n\t" // line 7
+
+ :
+ : "r" (src), "r" ((x86_reg)stride), "m" (co->pQPb)
+ NAMED_CONSTRAINTS_ADD(b01)
+ : "%"REG_a, "%"REG_c
+ );
+#else //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+
+ const int l1= stride;
+ const int l2= stride + l1;
+ const int l3= stride + l2;
+ const int l4= stride + l3;
+ const int l5= stride + l4;
+ const int l6= stride + l5;
+ const int l7= stride + l6;
+// const int l8= stride + l7;
+// const int l9= stride + l8;
+ int x;
+
+ src+= stride*3;
+ for(x=0; x<BLOCK_SIZE; x++){
+ int a= src[l3] - src[l4];
+ int b= src[l4] - src[l5];
+ int c= src[l5] - src[l6];
+
+ int d= FFABS(b) - ((FFABS(a) + FFABS(c))>>1);
+ d= FFMAX(d, 0);
+
+ if(d < co->QP*2){
+ int v = d * FFSIGN(-b);
+
+ src[l2] +=v>>3;
+ src[l3] +=v>>2;
+ src[l4] +=(3*v)>>3;
+ src[l5] -=(3*v)>>3;
+ src[l6] -=v>>2;
+ src[l7] -=v>>3;
+ }
+ src++;
+ }
+#endif //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+
+#if !TEMPLATE_PP_ALTIVEC
+static inline void RENAME(doVertDefFilter)(uint8_t src[], int stride, PPContext *c)
+{
+#if TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+/*
+ uint8_t tmp[16];
+ const int l1= stride;
+ const int l2= stride + l1;
+ const int l3= stride + l2;
+ const int l4= (int)tmp - (int)src - stride*3;
+ const int l5= (int)tmp - (int)src - stride*3 + 8;
+ const int l6= stride*3 + l3;
+ const int l7= stride + l6;
+ const int l8= stride + l7;
+
+ memcpy(tmp, src+stride*7, 8);
+ memcpy(tmp+8, src+stride*8, 8);
+*/
+ src+= stride*4;
+ __asm__ volatile(
+
+#if 0 //slightly more accurate and slightly slower
+ "pxor %%mm7, %%mm7 \n\t" // 0
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_c" \n\t"
+// 0 1 2 3 4 5 6 7
+// %0 %0+%1 %0+2%1 eax+2%1 %0+4%1 eax+4%1 ecx+%1 ecx+2%1
+// %0 eax eax+%1 eax+2%1 %0+4%1 ecx ecx+%1 ecx+2%1
+
+
+ "movq (%0, %1, 2), %%mm0 \n\t" // l2
+ "movq (%0), %%mm1 \n\t" // l0
+ "movq %%mm0, %%mm2 \n\t" // l2
+ PAVGB(%%mm7, %%mm0) // ~l2/2
+ PAVGB(%%mm1, %%mm0) // ~(l2 + 2l0)/4
+ PAVGB(%%mm2, %%mm0) // ~(5l2 + 2l0)/8
+
+ "movq (%%"REG_a"), %%mm1 \n\t" // l1
+ "movq (%%"REG_a", %1, 2), %%mm3 \n\t" // l3
+ "movq %%mm1, %%mm4 \n\t" // l1
+ PAVGB(%%mm7, %%mm1) // ~l1/2
+ PAVGB(%%mm3, %%mm1) // ~(l1 + 2l3)/4
+ PAVGB(%%mm4, %%mm1) // ~(5l1 + 2l3)/8
+
+ "movq %%mm0, %%mm4 \n\t" // ~(5l2 + 2l0)/8
+ "psubusb %%mm1, %%mm0 \n\t"
+ "psubusb %%mm4, %%mm1 \n\t"
+ "por %%mm0, %%mm1 \n\t" // ~|2l0 - 5l1 + 5l2 - 2l3|/8
+// mm1= |lenergy|, mm2= l2, mm3= l3, mm7=0
+
+ "movq (%0, %1, 4), %%mm0 \n\t" // l4
+ "movq %%mm0, %%mm4 \n\t" // l4
+ PAVGB(%%mm7, %%mm0) // ~l4/2
+ PAVGB(%%mm2, %%mm0) // ~(l4 + 2l2)/4
+ PAVGB(%%mm4, %%mm0) // ~(5l4 + 2l2)/8
+
+ "movq (%%"REG_c"), %%mm2 \n\t" // l5
+ "movq %%mm3, %%mm5 \n\t" // l3
+ PAVGB(%%mm7, %%mm3) // ~l3/2
+ PAVGB(%%mm2, %%mm3) // ~(l3 + 2l5)/4
+ PAVGB(%%mm5, %%mm3) // ~(5l3 + 2l5)/8
+
+ "movq %%mm0, %%mm6 \n\t" // ~(5l4 + 2l2)/8
+ "psubusb %%mm3, %%mm0 \n\t"
+ "psubusb %%mm6, %%mm3 \n\t"
+ "por %%mm0, %%mm3 \n\t" // ~|2l2 - 5l3 + 5l4 - 2l5|/8
+ "pcmpeqb %%mm7, %%mm0 \n\t" // SIGN(2l2 - 5l3 + 5l4 - 2l5)
+// mm0= SIGN(menergy), mm1= |lenergy|, mm2= l5, mm3= |menergy|, mm4=l4, mm5= l3, mm7=0
+
+ "movq (%%"REG_c", %1), %%mm6 \n\t" // l6
+ "movq %%mm6, %%mm5 \n\t" // l6
+ PAVGB(%%mm7, %%mm6) // ~l6/2
+ PAVGB(%%mm4, %%mm6) // ~(l6 + 2l4)/4
+ PAVGB(%%mm5, %%mm6) // ~(5l6 + 2l4)/8
+
+ "movq (%%"REG_c", %1, 2), %%mm5 \n\t" // l7
+ "movq %%mm2, %%mm4 \n\t" // l5
+ PAVGB(%%mm7, %%mm2) // ~l5/2
+ PAVGB(%%mm5, %%mm2) // ~(l5 + 2l7)/4
+ PAVGB(%%mm4, %%mm2) // ~(5l5 + 2l7)/8
+
+ "movq %%mm6, %%mm4 \n\t" // ~(5l6 + 2l4)/8
+ "psubusb %%mm2, %%mm6 \n\t"
+ "psubusb %%mm4, %%mm2 \n\t"
+ "por %%mm6, %%mm2 \n\t" // ~|2l4 - 5l5 + 5l6 - 2l7|/8
+// mm0= SIGN(menergy), mm1= |lenergy|/8, mm2= |renergy|/8, mm3= |menergy|/8, mm7=0
+
+
+ PMINUB(%%mm2, %%mm1, %%mm4) // MIN(|lenergy|,|renergy|)/8
+ "movq %2, %%mm4 \n\t" // QP //FIXME QP+1 ?
+ "paddusb "MANGLE(b01)", %%mm4 \n\t"
+ "pcmpgtb %%mm3, %%mm4 \n\t" // |menergy|/8 < QP
+ "psubusb %%mm1, %%mm3 \n\t" // d=|menergy|/8-MIN(|lenergy|,|renergy|)/8
+ "pand %%mm4, %%mm3 \n\t"
+
+ "movq %%mm3, %%mm1 \n\t"
+// "psubusb "MANGLE(b01)", %%mm3 \n\t"
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm7, %%mm3)
+ "paddusb %%mm1, %%mm3 \n\t"
+// "paddusb "MANGLE(b01)", %%mm3 \n\t"
+
+ "movq (%%"REG_a", %1, 2), %%mm6 \n\t" //l3
+ "movq (%0, %1, 4), %%mm5 \n\t" //l4
+ "movq (%0, %1, 4), %%mm4 \n\t" //l4
+ "psubusb %%mm6, %%mm5 \n\t"
+ "psubusb %%mm4, %%mm6 \n\t"
+ "por %%mm6, %%mm5 \n\t" // |l3-l4|
+ "pcmpeqb %%mm7, %%mm6 \n\t" // SIGN(l3-l4)
+ "pxor %%mm6, %%mm0 \n\t"
+ "pand %%mm0, %%mm3 \n\t"
+ PMINUB(%%mm5, %%mm3, %%mm0)
+
+ "psubusb "MANGLE(b01)", %%mm3 \n\t"
+ PAVGB(%%mm7, %%mm3)
+
+ "movq (%%"REG_a", %1, 2), %%mm0 \n\t"
+ "movq (%0, %1, 4), %%mm2 \n\t"
+ "pxor %%mm6, %%mm0 \n\t"
+ "pxor %%mm6, %%mm2 \n\t"
+ "psubb %%mm3, %%mm0 \n\t"
+ "paddb %%mm3, %%mm2 \n\t"
+ "pxor %%mm6, %%mm0 \n\t"
+ "pxor %%mm6, %%mm2 \n\t"
+ "movq %%mm0, (%%"REG_a", %1, 2) \n\t"
+ "movq %%mm2, (%0, %1, 4) \n\t"
+#endif //0
+
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "pcmpeqb %%mm6, %%mm6 \n\t" // -1
+// 0 1 2 3 4 5 6 7
+// %0 %0+%1 %0+2%1 eax+2%1 %0+4%1 eax+4%1 ecx+%1 ecx+2%1
+// %0 eax eax+%1 eax+2%1 %0+4%1 ecx ecx+%1 ecx+2%1
+
+
+ "movq (%%"REG_a", %1, 2), %%mm1 \n\t" // l3
+ "movq (%0, %1, 4), %%mm0 \n\t" // l4
+ "pxor %%mm6, %%mm1 \n\t" // -l3-1
+ PAVGB(%%mm1, %%mm0) // -q+128 = (l4-l3+256)/2
+// mm1=-l3-1, mm0=128-q
+
+ "movq (%%"REG_a", %1, 4), %%mm2 \n\t" // l5
+ "movq (%%"REG_a", %1), %%mm3 \n\t" // l2
+ "pxor %%mm6, %%mm2 \n\t" // -l5-1
+ "movq %%mm2, %%mm5 \n\t" // -l5-1
+ "movq "MANGLE(b80)", %%mm4 \n\t" // 128
+ "lea (%%"REG_a", %1, 4), %%"REG_c" \n\t"
+ PAVGB(%%mm3, %%mm2) // (l2-l5+256)/2
+ PAVGB(%%mm0, %%mm4) // ~(l4-l3)/4 + 128
+ PAVGB(%%mm2, %%mm4) // ~(l2-l5)/4 +(l4-l3)/8 + 128
+ PAVGB(%%mm0, %%mm4) // ~(l2-l5)/8 +5(l4-l3)/16 + 128
+// mm1=-l3-1, mm0=128-q, mm3=l2, mm4=menergy/16 + 128, mm5= -l5-1
+
+ "movq (%%"REG_a"), %%mm2 \n\t" // l1
+ "pxor %%mm6, %%mm2 \n\t" // -l1-1
+ PAVGB(%%mm3, %%mm2) // (l2-l1+256)/2
+ PAVGB((%0), %%mm1) // (l0-l3+256)/2
+ "movq "MANGLE(b80)", %%mm3 \n\t" // 128
+ PAVGB(%%mm2, %%mm3) // ~(l2-l1)/4 + 128
+ PAVGB(%%mm1, %%mm3) // ~(l0-l3)/4 +(l2-l1)/8 + 128
+ PAVGB(%%mm2, %%mm3) // ~(l0-l3)/8 +5(l2-l1)/16 + 128
+// mm0=128-q, mm3=lenergy/16 + 128, mm4= menergy/16 + 128, mm5= -l5-1
+
+ PAVGB((%%REGc, %1), %%mm5) // (l6-l5+256)/2
+ "movq (%%"REG_c", %1, 2), %%mm1 \n\t" // l7
+ "pxor %%mm6, %%mm1 \n\t" // -l7-1
+ PAVGB((%0, %1, 4), %%mm1) // (l4-l7+256)/2
+ "movq "MANGLE(b80)", %%mm2 \n\t" // 128
+ PAVGB(%%mm5, %%mm2) // ~(l6-l5)/4 + 128
+ PAVGB(%%mm1, %%mm2) // ~(l4-l7)/4 +(l6-l5)/8 + 128
+ PAVGB(%%mm5, %%mm2) // ~(l4-l7)/8 +5(l6-l5)/16 + 128
+// mm0=128-q, mm2=renergy/16 + 128, mm3=lenergy/16 + 128, mm4= menergy/16 + 128
+
+ "movq "MANGLE(b00)", %%mm1 \n\t" // 0
+ "movq "MANGLE(b00)", %%mm5 \n\t" // 0
+ "psubb %%mm2, %%mm1 \n\t" // 128 - renergy/16
+ "psubb %%mm3, %%mm5 \n\t" // 128 - lenergy/16
+ PMAXUB(%%mm1, %%mm2) // 128 + |renergy/16|
+ PMAXUB(%%mm5, %%mm3) // 128 + |lenergy/16|
+ PMINUB(%%mm2, %%mm3, %%mm1) // 128 + MIN(|lenergy|,|renergy|)/16
+
+// mm0=128-q, mm3=128 + MIN(|lenergy|,|renergy|)/16, mm4= menergy/16 + 128
+
+ "movq "MANGLE(b00)", %%mm7 \n\t" // 0
+ "movq %2, %%mm2 \n\t" // QP
+ PAVGB(%%mm6, %%mm2) // 128 + QP/2
+ "psubb %%mm6, %%mm2 \n\t"
+
+ "movq %%mm4, %%mm1 \n\t"
+ "pcmpgtb %%mm7, %%mm1 \n\t" // SIGN(menergy)
+ "pxor %%mm1, %%mm4 \n\t"
+ "psubb %%mm1, %%mm4 \n\t" // 128 + |menergy|/16
+ "pcmpgtb %%mm4, %%mm2 \n\t" // |menergy|/16 < QP/2
+ "psubusb %%mm3, %%mm4 \n\t" //d=|menergy|/16 - MIN(|lenergy|,|renergy|)/16
+// mm0=128-q, mm1= SIGN(menergy), mm2= |menergy|/16 < QP/2, mm4= d/16
+
+ "movq %%mm4, %%mm3 \n\t" // d
+ "psubusb "MANGLE(b01)", %%mm4 \n\t"
+ PAVGB(%%mm7, %%mm4) // d/32
+ PAVGB(%%mm7, %%mm4) // (d + 32)/64
+ "paddb %%mm3, %%mm4 \n\t" // 5d/64
+ "pand %%mm2, %%mm4 \n\t"
+
+ "movq "MANGLE(b80)", %%mm5 \n\t" // 128
+ "psubb %%mm0, %%mm5 \n\t" // q
+ "paddsb %%mm6, %%mm5 \n\t" // fix bad rounding
+ "pcmpgtb %%mm5, %%mm7 \n\t" // SIGN(q)
+ "pxor %%mm7, %%mm5 \n\t"
+
+ PMINUB(%%mm5, %%mm4, %%mm3) // MIN(|q|, 5d/64)
+ "pxor %%mm1, %%mm7 \n\t" // SIGN(d*q)
+
+ "pand %%mm7, %%mm4 \n\t"
+ "movq (%%"REG_a", %1, 2), %%mm0 \n\t"
+ "movq (%0, %1, 4), %%mm2 \n\t"
+ "pxor %%mm1, %%mm0 \n\t"
+ "pxor %%mm1, %%mm2 \n\t"
+ "paddb %%mm4, %%mm0 \n\t"
+ "psubb %%mm4, %%mm2 \n\t"
+ "pxor %%mm1, %%mm0 \n\t"
+ "pxor %%mm1, %%mm2 \n\t"
+ "movq %%mm0, (%%"REG_a", %1, 2) \n\t"
+ "movq %%mm2, (%0, %1, 4) \n\t"
+
+ :
+ : "r" (src), "r" ((x86_reg)stride), "m" (c->pQPb)
+ NAMED_CONSTRAINTS_ADD(b80,b00,b01)
+ : "%"REG_a, "%"REG_c
+ );
+
+/*
+ {
+ int x;
+ src-= stride;
+ for(x=0; x<BLOCK_SIZE; x++){
+ const int middleEnergy= 5*(src[l5] - src[l4]) + 2*(src[l3] - src[l6]);
+ if(FFABS(middleEnergy)< 8*QP){
+ const int q=(src[l4] - src[l5])/2;
+ const int leftEnergy= 5*(src[l3] - src[l2]) + 2*(src[l1] - src[l4]);
+ const int rightEnergy= 5*(src[l7] - src[l6]) + 2*(src[l5] - src[l8]);
+
+ int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
+ d= FFMAX(d, 0);
+
+ d= (5*d + 32) >> 6;
+ d*= FFSIGN(-middleEnergy);
+
+ if(q>0){
+ d= d<0 ? 0 : d;
+ d= d>q ? q : d;
+ }else{
+ d= d>0 ? 0 : d;
+ d= d<q ? q : d;
+ }
+
+ src[l4]-= d;
+ src[l5]+= d;
+ }
+ src++;
+ }
+ src-=8;
+ for(x=0; x<8; x++){
+ int y;
+ for(y=4; y<6; y++){
+ int d= src[x+y*stride] - tmp[x+(y-4)*8];
+ int ad= FFABS(d);
+ static int max=0;
+ static int sum=0;
+ static int num=0;
+ static int bias=0;
+
+ if(max<ad) max=ad;
+ sum+= ad>3 ? 1 : 0;
+ if(ad>3){
+ src[0] = src[7] = src[stride*7] = src[(stride+1)*7]=255;
+ }
+ if(y==4) bias+=d;
+ num++;
+ if(num%1000000 == 0){
+ av_log(c, AV_LOG_INFO, " %d %d %d %d\n", num, sum, max, bias);
+ }
+ }
+ }
+}
+*/
+#elif TEMPLATE_PP_MMX
+ DECLARE_ALIGNED(8, uint64_t, tmp)[4]; // make space for 4 8-byte vars
+ src+= stride*4;
+ __asm__ volatile(
+ "pxor %%mm7, %%mm7 \n\t"
+// 0 1 2 3 4 5 6 7
+// %0 %0+%1 %0+2%1 eax+2%1 %0+4%1 eax+4%1 edx+%1 edx+2%1
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1
+
+ "movq (%0), %%mm0 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t" // low part of line 0
+ "punpckhbw %%mm7, %%mm1 \n\t" // high part of line 0
+
+ "movq (%0, %1), %%mm2 \n\t"
+ "lea (%0, %1, 2), %%"REG_a" \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // low part of line 1
+ "punpckhbw %%mm7, %%mm3 \n\t" // high part of line 1
+
+ "movq (%%"REG_a"), %%mm4 \n\t"
+ "movq %%mm4, %%mm5 \n\t"
+ "punpcklbw %%mm7, %%mm4 \n\t" // low part of line 2
+ "punpckhbw %%mm7, %%mm5 \n\t" // high part of line 2
+
+ "paddw %%mm0, %%mm0 \n\t" // 2L0
+ "paddw %%mm1, %%mm1 \n\t" // 2H0
+ "psubw %%mm4, %%mm2 \n\t" // L1 - L2
+ "psubw %%mm5, %%mm3 \n\t" // H1 - H2
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - L1 + L2
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - H1 + H2
+
+ "psllw $2, %%mm2 \n\t" // 4L1 - 4L2
+ "psllw $2, %%mm3 \n\t" // 4H1 - 4H2
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - 5L1 + 5L2
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - 5H1 + 5H2
+
+ "movq (%%"REG_a", %1), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // L3
+ "punpckhbw %%mm7, %%mm3 \n\t" // H3
+
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - 5L1 + 5L2 - L3
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - 5H1 + 5H2 - H3
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - 5L1 + 5L2 - 2L3
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - 5H1 + 5H2 - 2H3
+ "movq %%mm0, (%3) \n\t" // 2L0 - 5L1 + 5L2 - 2L3
+ "movq %%mm1, 8(%3) \n\t" // 2H0 - 5H1 + 5H2 - 2H3
+
+ "movq (%%"REG_a", %1, 2), %%mm0 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t" // L4
+ "punpckhbw %%mm7, %%mm1 \n\t" // H4
+
+ "psubw %%mm0, %%mm2 \n\t" // L3 - L4
+ "psubw %%mm1, %%mm3 \n\t" // H3 - H4
+ "movq %%mm2, 16(%3) \n\t" // L3 - L4
+ "movq %%mm3, 24(%3) \n\t" // H3 - H4
+ "paddw %%mm4, %%mm4 \n\t" // 2L2
+ "paddw %%mm5, %%mm5 \n\t" // 2H2
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - L3 + L4
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - H3 + H4
+
+ "lea (%%"REG_a", %1), %0 \n\t"
+ "psllw $2, %%mm2 \n\t" // 4L3 - 4L4
+ "psllw $2, %%mm3 \n\t" // 4H3 - 4H4
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - 5L3 + 5L4
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - 5H3 + 5H4
+//50 opcodes so far
+ "movq (%0, %1, 2), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // L5
+ "punpckhbw %%mm7, %%mm3 \n\t" // H5
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - 5L3 + 5L4 - L5
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - 5H3 + 5H4 - H5
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - 5L3 + 5L4 - 2L5
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - 5H3 + 5H4 - 2H5
+
+ "movq (%%"REG_a", %1, 4), %%mm6 \n\t"
+ "punpcklbw %%mm7, %%mm6 \n\t" // L6
+ "psubw %%mm6, %%mm2 \n\t" // L5 - L6
+ "movq (%%"REG_a", %1, 4), %%mm6 \n\t"
+ "punpckhbw %%mm7, %%mm6 \n\t" // H6
+ "psubw %%mm6, %%mm3 \n\t" // H5 - H6
+
+ "paddw %%mm0, %%mm0 \n\t" // 2L4
+ "paddw %%mm1, %%mm1 \n\t" // 2H4
+ "psubw %%mm2, %%mm0 \n\t" // 2L4 - L5 + L6
+ "psubw %%mm3, %%mm1 \n\t" // 2H4 - H5 + H6
+
+ "psllw $2, %%mm2 \n\t" // 4L5 - 4L6
+ "psllw $2, %%mm3 \n\t" // 4H5 - 4H6
+ "psubw %%mm2, %%mm0 \n\t" // 2L4 - 5L5 + 5L6
+ "psubw %%mm3, %%mm1 \n\t" // 2H4 - 5H5 + 5H6
+
+ "movq (%0, %1, 4), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // L7
+ "punpckhbw %%mm7, %%mm3 \n\t" // H7
+
+ "paddw %%mm2, %%mm2 \n\t" // 2L7
+ "paddw %%mm3, %%mm3 \n\t" // 2H7
+ "psubw %%mm2, %%mm0 \n\t" // 2L4 - 5L5 + 5L6 - 2L7
+ "psubw %%mm3, %%mm1 \n\t" // 2H4 - 5H5 + 5H6 - 2H7
+
+ "movq (%3), %%mm2 \n\t" // 2L0 - 5L1 + 5L2 - 2L3
+ "movq 8(%3), %%mm3 \n\t" // 2H0 - 5H1 + 5H2 - 2H3
+
+#if TEMPLATE_PP_MMXEXT
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm0, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm0 \n\t" // |2L4 - 5L5 + 5L6 - 2L7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm1, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm1 \n\t" // |2H4 - 5H5 + 5H6 - 2H7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm2, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm2 \n\t" // |2L0 - 5L1 + 5L2 - 2L3|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm3, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm3 \n\t" // |2H0 - 5H1 + 5H2 - 2H3|
+#else
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm0, %%mm6 \n\t"
+ "pxor %%mm6, %%mm0 \n\t"
+ "psubw %%mm6, %%mm0 \n\t" // |2L4 - 5L5 + 5L6 - 2L7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm1, %%mm6 \n\t"
+ "pxor %%mm6, %%mm1 \n\t"
+ "psubw %%mm6, %%mm1 \n\t" // |2H4 - 5H5 + 5H6 - 2H7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm2, %%mm6 \n\t"
+ "pxor %%mm6, %%mm2 \n\t"
+ "psubw %%mm6, %%mm2 \n\t" // |2L0 - 5L1 + 5L2 - 2L3|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm3, %%mm6 \n\t"
+ "pxor %%mm6, %%mm3 \n\t"
+ "psubw %%mm6, %%mm3 \n\t" // |2H0 - 5H1 + 5H2 - 2H3|
+#endif
+
+#if TEMPLATE_PP_MMXEXT
+ "pminsw %%mm2, %%mm0 \n\t"
+ "pminsw %%mm3, %%mm1 \n\t"
+#else
+ "movq %%mm0, %%mm6 \n\t"
+ "psubusw %%mm2, %%mm6 \n\t"
+ "psubw %%mm6, %%mm0 \n\t"
+ "movq %%mm1, %%mm6 \n\t"
+ "psubusw %%mm3, %%mm6 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+#endif
+
+ "movd %2, %%mm2 \n\t" // QP
+ "punpcklbw %%mm7, %%mm2 \n\t"
+
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm4, %%mm6 \n\t" // sign(2L2 - 5L3 + 5L4 - 2L5)
+ "pxor %%mm6, %%mm4 \n\t"
+ "psubw %%mm6, %%mm4 \n\t" // |2L2 - 5L3 + 5L4 - 2L5|
+ "pcmpgtw %%mm5, %%mm7 \n\t" // sign(2H2 - 5H3 + 5H4 - 2H5)
+ "pxor %%mm7, %%mm5 \n\t"
+ "psubw %%mm7, %%mm5 \n\t" // |2H2 - 5H3 + 5H4 - 2H5|
+// 100 opcodes
+ "psllw $3, %%mm2 \n\t" // 8QP
+ "movq %%mm2, %%mm3 \n\t" // 8QP
+ "pcmpgtw %%mm4, %%mm2 \n\t"
+ "pcmpgtw %%mm5, %%mm3 \n\t"
+ "pand %%mm2, %%mm4 \n\t"
+ "pand %%mm3, %%mm5 \n\t"
+
+
+ "psubusw %%mm0, %%mm4 \n\t" // hd
+ "psubusw %%mm1, %%mm5 \n\t" // ld
+
+
+ "movq "MANGLE(w05)", %%mm2 \n\t" // 5
+ "pmullw %%mm2, %%mm4 \n\t"
+ "pmullw %%mm2, %%mm5 \n\t"
+ "movq "MANGLE(w20)", %%mm2 \n\t" // 32
+ "paddw %%mm2, %%mm4 \n\t"
+ "paddw %%mm2, %%mm5 \n\t"
+ "psrlw $6, %%mm4 \n\t"
+ "psrlw $6, %%mm5 \n\t"
+
+ "movq 16(%3), %%mm0 \n\t" // L3 - L4
+ "movq 24(%3), %%mm1 \n\t" // H3 - H4
+
+ "pxor %%mm2, %%mm2 \n\t"
+ "pxor %%mm3, %%mm3 \n\t"
+
+ "pcmpgtw %%mm0, %%mm2 \n\t" // sign (L3-L4)
+ "pcmpgtw %%mm1, %%mm3 \n\t" // sign (H3-H4)
+ "pxor %%mm2, %%mm0 \n\t"
+ "pxor %%mm3, %%mm1 \n\t"
+ "psubw %%mm2, %%mm0 \n\t" // |L3-L4|
+ "psubw %%mm3, %%mm1 \n\t" // |H3-H4|
+ "psrlw $1, %%mm0 \n\t" // |L3 - L4|/2
+ "psrlw $1, %%mm1 \n\t" // |H3 - H4|/2
+
+ "pxor %%mm6, %%mm2 \n\t"
+ "pxor %%mm7, %%mm3 \n\t"
+ "pand %%mm2, %%mm4 \n\t"
+ "pand %%mm3, %%mm5 \n\t"
+
+#if TEMPLATE_PP_MMXEXT
+ "pminsw %%mm0, %%mm4 \n\t"
+ "pminsw %%mm1, %%mm5 \n\t"
+#else
+ "movq %%mm4, %%mm2 \n\t"
+ "psubusw %%mm0, %%mm2 \n\t"
+ "psubw %%mm2, %%mm4 \n\t"
+ "movq %%mm5, %%mm2 \n\t"
+ "psubusw %%mm1, %%mm2 \n\t"
+ "psubw %%mm2, %%mm5 \n\t"
+#endif
+ "pxor %%mm6, %%mm4 \n\t"
+ "pxor %%mm7, %%mm5 \n\t"
+ "psubw %%mm6, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "packsswb %%mm5, %%mm4 \n\t"
+ "movq (%0), %%mm0 \n\t"
+ "paddb %%mm4, %%mm0 \n\t"
+ "movq %%mm0, (%0) \n\t"
+ "movq (%0, %1), %%mm0 \n\t"
+ "psubb %%mm4, %%mm0 \n\t"
+ "movq %%mm0, (%0, %1) \n\t"
+
+ : "+r" (src)
+ : "r" ((x86_reg)stride), "m" (c->pQPb), "r"(tmp)
+ NAMED_CONSTRAINTS_ADD(w05,w20)
+ : "%"REG_a
+ );
+#else //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ const int l1= stride;
+ const int l2= stride + l1;
+ const int l3= stride + l2;
+ const int l4= stride + l3;
+ const int l5= stride + l4;
+ const int l6= stride + l5;
+ const int l7= stride + l6;
+ const int l8= stride + l7;
+// const int l9= stride + l8;
+ int x;
+ src+= stride*3;
+ for(x=0; x<BLOCK_SIZE; x++){
+ const int middleEnergy= 5*(src[l5] - src[l4]) + 2*(src[l3] - src[l6]);
+ if(FFABS(middleEnergy) < 8*c->QP){
+ const int q=(src[l4] - src[l5])/2;
+ const int leftEnergy= 5*(src[l3] - src[l2]) + 2*(src[l1] - src[l4]);
+ const int rightEnergy= 5*(src[l7] - src[l6]) + 2*(src[l5] - src[l8]);
+
+ int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
+ d= FFMAX(d, 0);
+
+ d= (5*d + 32) >> 6;
+ d*= FFSIGN(-middleEnergy);
+
+ if(q>0){
+ d = FFMAX(d, 0);
+ d = FFMIN(d, q);
+ }else{
+ d = FFMIN(d, 0);
+ d = FFMAX(d, q);
+ }
+
+ src[l4]-= d;
+ src[l5]+= d;
+ }
+ src++;
+ }
+#endif //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+#endif //TEMPLATE_PP_ALTIVEC
+
+#if !TEMPLATE_PP_ALTIVEC
+static inline void RENAME(dering)(uint8_t src[], int stride, PPContext *c)
+{
+#if HAVE_7REGS && (TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW)
+ DECLARE_ALIGNED(8, uint64_t, tmp)[3];
+ __asm__ volatile(
+ "pxor %%mm6, %%mm6 \n\t"
+ "pcmpeqb %%mm7, %%mm7 \n\t"
+ "movq %2, %%mm0 \n\t"
+ "punpcklbw %%mm6, %%mm0 \n\t"
+ "psrlw $1, %%mm0 \n\t"
+ "psubw %%mm7, %%mm0 \n\t"
+ "packuswb %%mm0, %%mm0 \n\t"
+ "movq %%mm0, %3 \n\t"
+
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1
+
+#undef REAL_FIND_MIN_MAX
+#undef FIND_MIN_MAX
+#if TEMPLATE_PP_MMXEXT
+#define REAL_FIND_MIN_MAX(addr)\
+ "movq " #addr ", %%mm0 \n\t"\
+ "pminub %%mm0, %%mm7 \n\t"\
+ "pmaxub %%mm0, %%mm6 \n\t"
+#else
+#define REAL_FIND_MIN_MAX(addr)\
+ "movq " #addr ", %%mm0 \n\t"\
+ "movq %%mm7, %%mm1 \n\t"\
+ "psubusb %%mm0, %%mm6 \n\t"\
+ "paddb %%mm0, %%mm6 \n\t"\
+ "psubusb %%mm0, %%mm1 \n\t"\
+ "psubb %%mm1, %%mm7 \n\t"
+#endif
+#define FIND_MIN_MAX(addr) REAL_FIND_MIN_MAX(addr)
+
+FIND_MIN_MAX((%%REGa))
+FIND_MIN_MAX((%%REGa, %1))
+FIND_MIN_MAX((%%REGa, %1, 2))
+FIND_MIN_MAX((%0, %1, 4))
+FIND_MIN_MAX((%%REGd))
+FIND_MIN_MAX((%%REGd, %1))
+FIND_MIN_MAX((%%REGd, %1, 2))
+FIND_MIN_MAX((%0, %1, 8))
+
+ "movq %%mm7, %%mm4 \n\t"
+ "psrlq $8, %%mm7 \n\t"
+#if TEMPLATE_PP_MMXEXT
+ "pminub %%mm4, %%mm7 \n\t" // min of pixels
+ "pshufw $0xF9, %%mm7, %%mm4 \n\t"
+ "pminub %%mm4, %%mm7 \n\t" // min of pixels
+ "pshufw $0xFE, %%mm7, %%mm4 \n\t"
+ "pminub %%mm4, %%mm7 \n\t"
+#else
+ "movq %%mm7, %%mm1 \n\t"
+ "psubusb %%mm4, %%mm1 \n\t"
+ "psubb %%mm1, %%mm7 \n\t"
+ "movq %%mm7, %%mm4 \n\t"
+ "psrlq $16, %%mm7 \n\t"
+ "movq %%mm7, %%mm1 \n\t"
+ "psubusb %%mm4, %%mm1 \n\t"
+ "psubb %%mm1, %%mm7 \n\t"
+ "movq %%mm7, %%mm4 \n\t"
+ "psrlq $32, %%mm7 \n\t"
+ "movq %%mm7, %%mm1 \n\t"
+ "psubusb %%mm4, %%mm1 \n\t"
+ "psubb %%mm1, %%mm7 \n\t"
+#endif
+
+
+ "movq %%mm6, %%mm4 \n\t"
+ "psrlq $8, %%mm6 \n\t"
+#if TEMPLATE_PP_MMXEXT
+ "pmaxub %%mm4, %%mm6 \n\t" // max of pixels
+ "pshufw $0xF9, %%mm6, %%mm4 \n\t"
+ "pmaxub %%mm4, %%mm6 \n\t"
+ "pshufw $0xFE, %%mm6, %%mm4 \n\t"
+ "pmaxub %%mm4, %%mm6 \n\t"
+#else
+ "psubusb %%mm4, %%mm6 \n\t"
+ "paddb %%mm4, %%mm6 \n\t"
+ "movq %%mm6, %%mm4 \n\t"
+ "psrlq $16, %%mm6 \n\t"
+ "psubusb %%mm4, %%mm6 \n\t"
+ "paddb %%mm4, %%mm6 \n\t"
+ "movq %%mm6, %%mm4 \n\t"
+ "psrlq $32, %%mm6 \n\t"
+ "psubusb %%mm4, %%mm6 \n\t"
+ "paddb %%mm4, %%mm6 \n\t"
+#endif
+ "movq %%mm6, %%mm0 \n\t" // max
+ "psubb %%mm7, %%mm6 \n\t" // max - min
+ "push %4 \n\t"
+ "movd %%mm6, %k4 \n\t"
+ "cmpb "MANGLE(deringThreshold)", %b4 \n\t"
+ "pop %4 \n\t"
+ " jb 1f \n\t"
+ PAVGB(%%mm0, %%mm7) // a=(max + min)/2
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "movq %%mm7, (%4) \n\t"
+
+ "movq (%0), %%mm0 \n\t" // L10
+ "movq %%mm0, %%mm1 \n\t" // L10
+ "movq %%mm0, %%mm2 \n\t" // L10
+ "psllq $8, %%mm1 \n\t"
+ "psrlq $8, %%mm2 \n\t"
+ "movd -4(%0), %%mm3 \n\t"
+ "movd 8(%0), %%mm4 \n\t"
+ "psrlq $24, %%mm3 \n\t"
+ "psllq $56, %%mm4 \n\t"
+ "por %%mm3, %%mm1 \n\t" // L00
+ "por %%mm4, %%mm2 \n\t" // L20
+ "movq %%mm1, %%mm3 \n\t" // L00
+ PAVGB(%%mm2, %%mm1) // (L20 + L00)/2
+ PAVGB(%%mm0, %%mm1) // (L20 + L00 + 2L10)/4
+ "psubusb %%mm7, %%mm0 \n\t"
+ "psubusb %%mm7, %%mm2 \n\t"
+ "psubusb %%mm7, %%mm3 \n\t"
+ "pcmpeqb "MANGLE(b00)", %%mm0 \n\t" // L10 > a ? 0 : -1
+ "pcmpeqb "MANGLE(b00)", %%mm2 \n\t" // L20 > a ? 0 : -1
+ "pcmpeqb "MANGLE(b00)", %%mm3 \n\t" // L00 > a ? 0 : -1
+ "paddb %%mm2, %%mm0 \n\t"
+ "paddb %%mm3, %%mm0 \n\t"
+
+ "movq (%%"REG_a"), %%mm2 \n\t" // L11
+ "movq %%mm2, %%mm3 \n\t" // L11
+ "movq %%mm2, %%mm4 \n\t" // L11
+ "psllq $8, %%mm3 \n\t"
+ "psrlq $8, %%mm4 \n\t"
+ "movd -4(%%"REG_a"), %%mm5 \n\t"
+ "movd 8(%%"REG_a"), %%mm6 \n\t"
+ "psrlq $24, %%mm5 \n\t"
+ "psllq $56, %%mm6 \n\t"
+ "por %%mm5, %%mm3 \n\t" // L01
+ "por %%mm6, %%mm4 \n\t" // L21
+ "movq %%mm3, %%mm5 \n\t" // L01
+ PAVGB(%%mm4, %%mm3) // (L21 + L01)/2
+ PAVGB(%%mm2, %%mm3) // (L21 + L01 + 2L11)/4
+ "psubusb %%mm7, %%mm2 \n\t"
+ "psubusb %%mm7, %%mm4 \n\t"
+ "psubusb %%mm7, %%mm5 \n\t"
+ "pcmpeqb "MANGLE(b00)", %%mm2 \n\t" // L11 > a ? 0 : -1
+ "pcmpeqb "MANGLE(b00)", %%mm4 \n\t" // L21 > a ? 0 : -1
+ "pcmpeqb "MANGLE(b00)", %%mm5 \n\t" // L01 > a ? 0 : -1
+ "paddb %%mm4, %%mm2 \n\t"
+ "paddb %%mm5, %%mm2 \n\t"
+// 0, 2, 3, 1
+#define REAL_DERING_CORE(dst,src,ppsx,psx,sx,pplx,plx,lx,t0,t1) \
+ "movq " #src ", " #sx " \n\t" /* src[0] */\
+ "movq " #sx ", " #lx " \n\t" /* src[0] */\
+ "movq " #sx ", " #t0 " \n\t" /* src[0] */\
+ "psllq $8, " #lx " \n\t"\
+ "psrlq $8, " #t0 " \n\t"\
+ "movd -4" #src ", " #t1 " \n\t"\
+ "psrlq $24, " #t1 " \n\t"\
+ "por " #t1 ", " #lx " \n\t" /* src[-1] */\
+ "movd 8" #src ", " #t1 " \n\t"\
+ "psllq $56, " #t1 " \n\t"\
+ "por " #t1 ", " #t0 " \n\t" /* src[+1] */\
+ "movq " #lx ", " #t1 " \n\t" /* src[-1] */\
+ PAVGB(t0, lx) /* (src[-1] + src[+1])/2 */\
+ PAVGB(sx, lx) /* (src[-1] + 2src[0] + src[+1])/4 */\
+ PAVGB(lx, pplx) \
+ "movq " #lx ", 8(%4) \n\t"\
+ "movq (%4), " #lx " \n\t"\
+ "psubusb " #lx ", " #t1 " \n\t"\
+ "psubusb " #lx ", " #t0 " \n\t"\
+ "psubusb " #lx ", " #sx " \n\t"\
+ "movq "MANGLE(b00)", " #lx " \n\t"\
+ "pcmpeqb " #lx ", " #t1 " \n\t" /* src[-1] > a ? 0 : -1*/\
+ "pcmpeqb " #lx ", " #t0 " \n\t" /* src[+1] > a ? 0 : -1*/\
+ "pcmpeqb " #lx ", " #sx " \n\t" /* src[0] > a ? 0 : -1*/\
+ "paddb " #t1 ", " #t0 " \n\t"\
+ "paddb " #t0 ", " #sx " \n\t"\
+\
+ PAVGB(plx, pplx) /* filtered */\
+ "movq " #dst ", " #t0 " \n\t" /* dst */\
+ "movq " #t0 ", " #t1 " \n\t" /* dst */\
+ "psubusb %3, " #t0 " \n\t"\
+ "paddusb %3, " #t1 " \n\t"\
+ PMAXUB(t0, pplx)\
+ PMINUB(t1, pplx, t0)\
+ "paddb " #sx ", " #ppsx " \n\t"\
+ "paddb " #psx ", " #ppsx " \n\t"\
+ "#paddb "MANGLE(b02)", " #ppsx " \n\t"\
+ "pand "MANGLE(b08)", " #ppsx " \n\t"\
+ "pcmpeqb " #lx ", " #ppsx " \n\t"\
+ "pand " #ppsx ", " #pplx " \n\t"\
+ "pandn " #dst ", " #ppsx " \n\t"\
+ "por " #pplx ", " #ppsx " \n\t"\
+ "movq " #ppsx ", " #dst " \n\t"\
+ "movq 8(%4), " #lx " \n\t"
+
+#define DERING_CORE(dst,src,ppsx,psx,sx,pplx,plx,lx,t0,t1) \
+ REAL_DERING_CORE(dst,src,ppsx,psx,sx,pplx,plx,lx,t0,t1)
+/*
+0000000
+1111111
+
+1111110
+1111101
+1111100
+1111011
+1111010
+1111001
+
+1111000
+1110111
+
+*/
+//DERING_CORE(dst ,src ,ppsx ,psx ,sx ,pplx ,plx ,lx ,t0 ,t1)
+DERING_CORE((%%REGa) ,(%%REGa, %1) ,%%mm0,%%mm2,%%mm4,%%mm1,%%mm3,%%mm5,%%mm6,%%mm7)
+DERING_CORE((%%REGa, %1) ,(%%REGa, %1, 2),%%mm2,%%mm4,%%mm0,%%mm3,%%mm5,%%mm1,%%mm6,%%mm7)
+DERING_CORE((%%REGa, %1, 2),(%0, %1, 4) ,%%mm4,%%mm0,%%mm2,%%mm5,%%mm1,%%mm3,%%mm6,%%mm7)
+DERING_CORE((%0, %1, 4) ,(%%REGd) ,%%mm0,%%mm2,%%mm4,%%mm1,%%mm3,%%mm5,%%mm6,%%mm7)
+DERING_CORE((%%REGd) ,(%%REGd, %1) ,%%mm2,%%mm4,%%mm0,%%mm3,%%mm5,%%mm1,%%mm6,%%mm7)
+DERING_CORE((%%REGd, %1) ,(%%REGd, %1, 2),%%mm4,%%mm0,%%mm2,%%mm5,%%mm1,%%mm3,%%mm6,%%mm7)
+DERING_CORE((%%REGd, %1, 2),(%0, %1, 8) ,%%mm0,%%mm2,%%mm4,%%mm1,%%mm3,%%mm5,%%mm6,%%mm7)
+DERING_CORE((%0, %1, 8) ,(%%REGd, %1, 4),%%mm2,%%mm4,%%mm0,%%mm3,%%mm5,%%mm1,%%mm6,%%mm7)
+
+ "1: \n\t"
+ : : "r" (src), "r" ((x86_reg)stride), "m" (c->pQPb), "m"(c->pQPb2), "q"(tmp)
+ NAMED_CONSTRAINTS_ADD(deringThreshold,b00,b02,b08)
+ : "%"REG_a, "%"REG_d, "%"REG_SP
+ );
+#else // HAVE_7REGS && (TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW)
+ int y;
+ int min=255;
+ int max=0;
+ int avg;
+ uint8_t *p;
+ int s[10];
+ const int QP2= c->QP/2 + 1;
+
+ src --;
+ for(y=1; y<9; y++){
+ int x;
+ p= src + stride*y;
+ for(x=1; x<9; x++){
+ p++;
+ if(*p > max) max= *p;
+ if(*p < min) min= *p;
+ }
+ }
+ avg= (min + max + 1)>>1;
+
+ if(max - min <deringThreshold) return;
+
+ for(y=0; y<10; y++){
+ int t = 0;
+
+ if(src[stride*y + 0] > avg) t+= 1;
+ if(src[stride*y + 1] > avg) t+= 2;
+ if(src[stride*y + 2] > avg) t+= 4;
+ if(src[stride*y + 3] > avg) t+= 8;
+ if(src[stride*y + 4] > avg) t+= 16;
+ if(src[stride*y + 5] > avg) t+= 32;
+ if(src[stride*y + 6] > avg) t+= 64;
+ if(src[stride*y + 7] > avg) t+= 128;
+ if(src[stride*y + 8] > avg) t+= 256;
+ if(src[stride*y + 9] > avg) t+= 512;
+
+ t |= (~t)<<16;
+ t &= (t<<1) & (t>>1);
+ s[y] = t;
+ }
+
+ for(y=1; y<9; y++){
+ int t = s[y-1] & s[y] & s[y+1];
+ t|= t>>16;
+ s[y-1]= t;
+ }
+
+ for(y=1; y<9; y++){
+ int x;
+ int t = s[y-1];
+
+ p= src + stride*y;
+ for(x=1; x<9; x++){
+ p++;
+ if(t & (1<<x)){
+ int f= (*(p-stride-1)) + 2*(*(p-stride)) + (*(p-stride+1))
+ +2*(*(p -1)) + 4*(*p ) + 2*(*(p +1))
+ +(*(p+stride-1)) + 2*(*(p+stride)) + (*(p+stride+1));
+ f= (f + 8)>>4;
+
+#ifdef DEBUG_DERING_THRESHOLD
+ __asm__ volatile("emms\n\t":);
+ {
+ static long long numPixels=0;
+ if(x!=1 && x!=8 && y!=1 && y!=8) numPixels++;
+// if((max-min)<20 || (max-min)*QP<200)
+// if((max-min)*QP < 500)
+// if(max-min<QP/2)
+ if(max-min < 20){
+ static int numSkipped=0;
+ static int errorSum=0;
+ static int worstQP=0;
+ static int worstRange=0;
+ static int worstDiff=0;
+ int diff= (f - *p);
+ int absDiff= FFABS(diff);
+ int error= diff*diff;
+
+ if(x==1 || x==8 || y==1 || y==8) continue;
+
+ numSkipped++;
+ if(absDiff > worstDiff){
+ worstDiff= absDiff;
+ worstQP= QP;
+ worstRange= max-min;
+ }
+ errorSum+= error;
+
+ if(1024LL*1024LL*1024LL % numSkipped == 0){
+ av_log(c, AV_LOG_INFO, "sum:%1.3f, skip:%d, wQP:%d, "
+ "wRange:%d, wDiff:%d, relSkip:%1.3f\n",
+ (float)errorSum/numSkipped, numSkipped, worstQP, worstRange,
+ worstDiff, (float)numSkipped/numPixels);
+ }
+ }
+ }
+#endif
+ if (*p + QP2 < f) *p= *p + QP2;
+ else if(*p - QP2 > f) *p= *p - QP2;
+ else *p=f;
+ }
+ }
+ }
+#ifdef DEBUG_DERING_THRESHOLD
+ if(max-min < 20){
+ for(y=1; y<9; y++){
+ int x;
+ int t = 0;
+ p= src + stride*y;
+ for(x=1; x<9; x++){
+ p++;
+ *p = FFMIN(*p + 20, 255);
+ }
+ }
+// src[0] = src[7]=src[stride*7]=src[stride*7 + 7]=255;
+ }
+#endif
+#endif //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+#endif //TEMPLATE_PP_ALTIVEC
+
+/**
+ * Deinterlace the given block by linearly interpolating every second line.
+ * will be called for every 8x8 block and can read & write from line 4-15
+ * lines 0-3 have been passed through the deblock / dering filters already, but can be read, too.
+ * lines 4-12 will be read into the deblocking filter and should be deinterlaced
+ */
+static inline void RENAME(deInterlaceInterpolateLinear)(uint8_t src[], int stride)
+{
+#if TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ src+= 4*stride;
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_c" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 ecx ecx+%1 ecx+2%1 %0+8%1 ecx+4%1
+
+ "movq (%0), %%mm0 \n\t"
+ "movq (%%"REG_a", %1), %%mm1 \n\t"
+ PAVGB(%%mm1, %%mm0)
+ "movq %%mm0, (%%"REG_a") \n\t"
+ "movq (%0, %1, 4), %%mm0 \n\t"
+ PAVGB(%%mm0, %%mm1)
+ "movq %%mm1, (%%"REG_a", %1, 2) \n\t"
+ "movq (%%"REG_c", %1), %%mm1 \n\t"
+ PAVGB(%%mm1, %%mm0)
+ "movq %%mm0, (%%"REG_c") \n\t"
+ "movq (%0, %1, 8), %%mm0 \n\t"
+ PAVGB(%%mm0, %%mm1)
+ "movq %%mm1, (%%"REG_c", %1, 2) \n\t"
+
+ : : "r" (src), "r" ((x86_reg)stride)
+ : "%"REG_a, "%"REG_c
+ );
+#else
+ int a, b, x;
+ src+= 4*stride;
+
+ for(x=0; x<2; x++){
+ a= *(uint32_t*)&src[stride*0];
+ b= *(uint32_t*)&src[stride*2];
+ *(uint32_t*)&src[stride*1]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+ a= *(uint32_t*)&src[stride*4];
+ *(uint32_t*)&src[stride*3]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+ b= *(uint32_t*)&src[stride*6];
+ *(uint32_t*)&src[stride*5]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+ a= *(uint32_t*)&src[stride*8];
+ *(uint32_t*)&src[stride*7]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+ src += 4;
+ }
+#endif
+}
+
+/**
+ * Deinterlace the given block by cubic interpolating every second line.
+ * will be called for every 8x8 block and can read & write from line 4-15
+ * lines 0-3 have been passed through the deblock / dering filters already, but can be read, too.
+ * lines 4-12 will be read into the deblocking filter and should be deinterlaced
+ * this filter will read lines 3-15 and write 7-13
+ */
+static inline void RENAME(deInterlaceInterpolateCubic)(uint8_t src[], int stride)
+{
+#if TEMPLATE_PP_SSE2 || TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ src+= stride*3;
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+ "lea (%%"REG_d", %1, 4), %%"REG_c" \n\t"
+ "add %1, %%"REG_c" \n\t"
+#if TEMPLATE_PP_SSE2
+ "pxor %%xmm7, %%xmm7 \n\t"
+#define REAL_DEINT_CUBIC(a,b,c,d,e)\
+ "movq " #a ", %%xmm0 \n\t"\
+ "movq " #b ", %%xmm1 \n\t"\
+ "movq " #d ", %%xmm2 \n\t"\
+ "movq " #e ", %%xmm3 \n\t"\
+ "pavgb %%xmm2, %%xmm1 \n\t"\
+ "pavgb %%xmm3, %%xmm0 \n\t"\
+ "punpcklbw %%xmm7, %%xmm0 \n\t"\
+ "punpcklbw %%xmm7, %%xmm1 \n\t"\
+ "psubw %%xmm1, %%xmm0 \n\t"\
+ "psraw $3, %%xmm0 \n\t"\
+ "psubw %%xmm0, %%xmm1 \n\t"\
+ "packuswb %%xmm1, %%xmm1 \n\t"\
+ "movlps %%xmm1, " #c " \n\t"
+#else //TEMPLATE_PP_SSE2
+ "pxor %%mm7, %%mm7 \n\t"
+// 0 1 2 3 4 5 6 7 8 9 10
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1 ecx
+
+#define REAL_DEINT_CUBIC(a,b,c,d,e)\
+ "movq " #a ", %%mm0 \n\t"\
+ "movq " #b ", %%mm1 \n\t"\
+ "movq " #d ", %%mm2 \n\t"\
+ "movq " #e ", %%mm3 \n\t"\
+ PAVGB(%%mm2, %%mm1) /* (b+d) /2 */\
+ PAVGB(%%mm3, %%mm0) /* (a+e) /2 */\
+ "movq %%mm0, %%mm2 \n\t"\
+ "punpcklbw %%mm7, %%mm0 \n\t"\
+ "punpckhbw %%mm7, %%mm2 \n\t"\
+ "movq %%mm1, %%mm3 \n\t"\
+ "punpcklbw %%mm7, %%mm1 \n\t"\
+ "punpckhbw %%mm7, %%mm3 \n\t"\
+ "psubw %%mm1, %%mm0 \n\t" /* L(a+e - (b+d))/2 */\
+ "psubw %%mm3, %%mm2 \n\t" /* H(a+e - (b+d))/2 */\
+ "psraw $3, %%mm0 \n\t" /* L(a+e - (b+d))/16 */\
+ "psraw $3, %%mm2 \n\t" /* H(a+e - (b+d))/16 */\
+ "psubw %%mm0, %%mm1 \n\t" /* L(9b + 9d - a - e)/16 */\
+ "psubw %%mm2, %%mm3 \n\t" /* H(9b + 9d - a - e)/16 */\
+ "packuswb %%mm3, %%mm1 \n\t"\
+ "movq %%mm1, " #c " \n\t"
+#endif //TEMPLATE_PP_SSE2
+#define DEINT_CUBIC(a,b,c,d,e) REAL_DEINT_CUBIC(a,b,c,d,e)
+
+DEINT_CUBIC((%0) , (%%REGa, %1), (%%REGa, %1, 2), (%0, %1, 4) , (%%REGd, %1))
+DEINT_CUBIC((%%REGa, %1), (%0, %1, 4) , (%%REGd) , (%%REGd, %1), (%0, %1, 8))
+DEINT_CUBIC((%0, %1, 4) , (%%REGd, %1), (%%REGd, %1, 2), (%0, %1, 8) , (%%REGc))
+DEINT_CUBIC((%%REGd, %1), (%0, %1, 8) , (%%REGd, %1, 4), (%%REGc) , (%%REGc, %1, 2))
+
+ : : "r" (src), "r" ((x86_reg)stride)
+ :
+#if TEMPLATE_PP_SSE2
+ XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm7",)
+#endif
+ "%"REG_a, "%"REG_d, "%"REG_c
+ );
+#undef REAL_DEINT_CUBIC
+#else //TEMPLATE_PP_SSE2 || TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ int x;
+ src+= stride*3;
+ for(x=0; x<8; x++){
+ src[stride*3] = av_clip_uint8((-src[0] + 9*src[stride*2] + 9*src[stride*4] - src[stride*6])>>4);
+ src[stride*5] = av_clip_uint8((-src[stride*2] + 9*src[stride*4] + 9*src[stride*6] - src[stride*8])>>4);
+ src[stride*7] = av_clip_uint8((-src[stride*4] + 9*src[stride*6] + 9*src[stride*8] - src[stride*10])>>4);
+ src[stride*9] = av_clip_uint8((-src[stride*6] + 9*src[stride*8] + 9*src[stride*10] - src[stride*12])>>4);
+ src++;
+ }
+#endif //TEMPLATE_PP_SSE2 || TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+
+/**
+ * Deinterlace the given block by filtering every second line with a (-1 4 2 4 -1) filter.
+ * will be called for every 8x8 block and can read & write from line 4-15
+ * lines 0-3 have been passed through the deblock / dering filters already, but can be read, too.
+ * lines 4-12 will be read into the deblocking filter and should be deinterlaced
+ * this filter will read lines 4-13 and write 5-11
+ */
+static inline void RENAME(deInterlaceFF)(uint8_t src[], int stride, uint8_t *tmp)
+{
+#if TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ src+= stride*4;
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ "movq (%2), %%mm0 \n\t"
+// 0 1 2 3 4 5 6 7 8 9 10
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1 ecx
+
+#define REAL_DEINT_FF(a,b,c,d)\
+ "movq " #a ", %%mm1 \n\t"\
+ "movq " #b ", %%mm2 \n\t"\
+ "movq " #c ", %%mm3 \n\t"\
+ "movq " #d ", %%mm4 \n\t"\
+ PAVGB(%%mm3, %%mm1) \
+ PAVGB(%%mm4, %%mm0) \
+ "movq %%mm0, %%mm3 \n\t"\
+ "punpcklbw %%mm7, %%mm0 \n\t"\
+ "punpckhbw %%mm7, %%mm3 \n\t"\
+ "movq %%mm1, %%mm4 \n\t"\
+ "punpcklbw %%mm7, %%mm1 \n\t"\
+ "punpckhbw %%mm7, %%mm4 \n\t"\
+ "psllw $2, %%mm1 \n\t"\
+ "psllw $2, %%mm4 \n\t"\
+ "psubw %%mm0, %%mm1 \n\t"\
+ "psubw %%mm3, %%mm4 \n\t"\
+ "movq %%mm2, %%mm5 \n\t"\
+ "movq %%mm2, %%mm0 \n\t"\
+ "punpcklbw %%mm7, %%mm2 \n\t"\
+ "punpckhbw %%mm7, %%mm5 \n\t"\
+ "paddw %%mm2, %%mm1 \n\t"\
+ "paddw %%mm5, %%mm4 \n\t"\
+ "psraw $2, %%mm1 \n\t"\
+ "psraw $2, %%mm4 \n\t"\
+ "packuswb %%mm4, %%mm1 \n\t"\
+ "movq %%mm1, " #b " \n\t"\
+
+#define DEINT_FF(a,b,c,d) REAL_DEINT_FF(a,b,c,d)
+
+DEINT_FF((%0) , (%%REGa) , (%%REGa, %1), (%%REGa, %1, 2))
+DEINT_FF((%%REGa, %1), (%%REGa, %1, 2), (%0, %1, 4) , (%%REGd) )
+DEINT_FF((%0, %1, 4) , (%%REGd) , (%%REGd, %1), (%%REGd, %1, 2))
+DEINT_FF((%%REGd, %1), (%%REGd, %1, 2), (%0, %1, 8) , (%%REGd, %1, 4))
+
+ "movq %%mm0, (%2) \n\t"
+ : : "r" (src), "r" ((x86_reg)stride), "r"(tmp)
+ : "%"REG_a, "%"REG_d
+ );
+#else //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ int x;
+ src+= stride*4;
+ for(x=0; x<8; x++){
+ int t1= tmp[x];
+ int t2= src[stride*1];
+
+ src[stride*1]= av_clip_uint8((-t1 + 4*src[stride*0] + 2*t2 + 4*src[stride*2] - src[stride*3] + 4)>>3);
+ t1= src[stride*4];
+ src[stride*3]= av_clip_uint8((-t2 + 4*src[stride*2] + 2*t1 + 4*src[stride*4] - src[stride*5] + 4)>>3);
+ t2= src[stride*6];
+ src[stride*5]= av_clip_uint8((-t1 + 4*src[stride*4] + 2*t2 + 4*src[stride*6] - src[stride*7] + 4)>>3);
+ t1= src[stride*8];
+ src[stride*7]= av_clip_uint8((-t2 + 4*src[stride*6] + 2*t1 + 4*src[stride*8] - src[stride*9] + 4)>>3);
+ tmp[x]= t1;
+
+ src++;
+ }
+#endif //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+
+/**
+ * Deinterlace the given block by filtering every line with a (-1 2 6 2 -1) filter.
+ * will be called for every 8x8 block and can read & write from line 4-15
+ * lines 0-3 have been passed through the deblock / dering filters already, but can be read, too.
+ * lines 4-12 will be read into the deblocking filter and should be deinterlaced
+ * this filter will read lines 4-13 and write 4-11
+ */
+static inline void RENAME(deInterlaceL5)(uint8_t src[], int stride, uint8_t *tmp, uint8_t *tmp2)
+{
+#if (TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW) && HAVE_6REGS
+ src+= stride*4;
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ "movq (%2), %%mm0 \n\t"
+ "movq (%3), %%mm1 \n\t"
+// 0 1 2 3 4 5 6 7 8 9 10
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1 ecx
+
+#define REAL_DEINT_L5(t1,t2,a,b,c)\
+ "movq " #a ", %%mm2 \n\t"\
+ "movq " #b ", %%mm3 \n\t"\
+ "movq " #c ", %%mm4 \n\t"\
+ PAVGB(t2, %%mm3) \
+ PAVGB(t1, %%mm4) \
+ "movq %%mm2, %%mm5 \n\t"\
+ "movq %%mm2, " #t1 " \n\t"\
+ "punpcklbw %%mm7, %%mm2 \n\t"\
+ "punpckhbw %%mm7, %%mm5 \n\t"\
+ "movq %%mm2, %%mm6 \n\t"\
+ "paddw %%mm2, %%mm2 \n\t"\
+ "paddw %%mm6, %%mm2 \n\t"\
+ "movq %%mm5, %%mm6 \n\t"\
+ "paddw %%mm5, %%mm5 \n\t"\
+ "paddw %%mm6, %%mm5 \n\t"\
+ "movq %%mm3, %%mm6 \n\t"\
+ "punpcklbw %%mm7, %%mm3 \n\t"\
+ "punpckhbw %%mm7, %%mm6 \n\t"\
+ "paddw %%mm3, %%mm3 \n\t"\
+ "paddw %%mm6, %%mm6 \n\t"\
+ "paddw %%mm3, %%mm2 \n\t"\
+ "paddw %%mm6, %%mm5 \n\t"\
+ "movq %%mm4, %%mm6 \n\t"\
+ "punpcklbw %%mm7, %%mm4 \n\t"\
+ "punpckhbw %%mm7, %%mm6 \n\t"\
+ "psubw %%mm4, %%mm2 \n\t"\
+ "psubw %%mm6, %%mm5 \n\t"\
+ "psraw $2, %%mm2 \n\t"\
+ "psraw $2, %%mm5 \n\t"\
+ "packuswb %%mm5, %%mm2 \n\t"\
+ "movq %%mm2, " #a " \n\t"\
+
+#define DEINT_L5(t1,t2,a,b,c) REAL_DEINT_L5(t1,t2,a,b,c)
+
+DEINT_L5(%%mm0, %%mm1, (%0) , (%%REGa) , (%%REGa, %1) )
+DEINT_L5(%%mm1, %%mm0, (%%REGa) , (%%REGa, %1) , (%%REGa, %1, 2))
+DEINT_L5(%%mm0, %%mm1, (%%REGa, %1) , (%%REGa, %1, 2), (%0, %1, 4) )
+DEINT_L5(%%mm1, %%mm0, (%%REGa, %1, 2), (%0, %1, 4) , (%%REGd) )
+DEINT_L5(%%mm0, %%mm1, (%0, %1, 4) , (%%REGd) , (%%REGd, %1) )
+DEINT_L5(%%mm1, %%mm0, (%%REGd) , (%%REGd, %1) , (%%REGd, %1, 2))
+DEINT_L5(%%mm0, %%mm1, (%%REGd, %1) , (%%REGd, %1, 2), (%0, %1, 8) )
+DEINT_L5(%%mm1, %%mm0, (%%REGd, %1, 2), (%0, %1, 8) , (%%REGd, %1, 4))
+
+ "movq %%mm0, (%2) \n\t"
+ "movq %%mm1, (%3) \n\t"
+ : : "r" (src), "r" ((x86_reg)stride), "r"(tmp), "r"(tmp2)
+ : "%"REG_a, "%"REG_d
+ );
+#else //(TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW) && HAVE_6REGS
+ int x;
+ src+= stride*4;
+ for(x=0; x<8; x++){
+ int t1= tmp[x];
+ int t2= tmp2[x];
+ int t3= src[0];
+
+ src[stride*0]= av_clip_uint8((-(t1 + src[stride*2]) + 2*(t2 + src[stride*1]) + 6*t3 + 4)>>3);
+ t1= src[stride*1];
+ src[stride*1]= av_clip_uint8((-(t2 + src[stride*3]) + 2*(t3 + src[stride*2]) + 6*t1 + 4)>>3);
+ t2= src[stride*2];
+ src[stride*2]= av_clip_uint8((-(t3 + src[stride*4]) + 2*(t1 + src[stride*3]) + 6*t2 + 4)>>3);
+ t3= src[stride*3];
+ src[stride*3]= av_clip_uint8((-(t1 + src[stride*5]) + 2*(t2 + src[stride*4]) + 6*t3 + 4)>>3);
+ t1= src[stride*4];
+ src[stride*4]= av_clip_uint8((-(t2 + src[stride*6]) + 2*(t3 + src[stride*5]) + 6*t1 + 4)>>3);
+ t2= src[stride*5];
+ src[stride*5]= av_clip_uint8((-(t3 + src[stride*7]) + 2*(t1 + src[stride*6]) + 6*t2 + 4)>>3);
+ t3= src[stride*6];
+ src[stride*6]= av_clip_uint8((-(t1 + src[stride*8]) + 2*(t2 + src[stride*7]) + 6*t3 + 4)>>3);
+ t1= src[stride*7];
+ src[stride*7]= av_clip_uint8((-(t2 + src[stride*9]) + 2*(t3 + src[stride*8]) + 6*t1 + 4)>>3);
+
+ tmp[x]= t3;
+ tmp2[x]= t1;
+
+ src++;
+ }
+#endif //(TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW) && HAVE_6REGS
+}
+
+/**
+ * Deinterlace the given block by filtering all lines with a (1 2 1) filter.
+ * will be called for every 8x8 block and can read & write from line 4-15
+ * lines 0-3 have been passed through the deblock / dering filters already, but can be read, too.
+ * lines 4-12 will be read into the deblocking filter and should be deinterlaced
+ * this filter will read lines 4-13 and write 4-11
+ */
+static inline void RENAME(deInterlaceBlendLinear)(uint8_t src[], int stride, uint8_t *tmp)
+{
+#if TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ src+= 4*stride;
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1
+
+ "movq (%2), %%mm0 \n\t" // L0
+ "movq (%%"REG_a"), %%mm1 \n\t" // L2
+ PAVGB(%%mm1, %%mm0) // L0+L2
+ "movq (%0), %%mm2 \n\t" // L1
+ PAVGB(%%mm2, %%mm0)
+ "movq %%mm0, (%0) \n\t"
+ "movq (%%"REG_a", %1), %%mm0 \n\t" // L3
+ PAVGB(%%mm0, %%mm2) // L1+L3
+ PAVGB(%%mm1, %%mm2) // 2L2 + L1 + L3
+ "movq %%mm2, (%%"REG_a") \n\t"
+ "movq (%%"REG_a", %1, 2), %%mm2 \n\t" // L4
+ PAVGB(%%mm2, %%mm1) // L2+L4
+ PAVGB(%%mm0, %%mm1) // 2L3 + L2 + L4
+ "movq %%mm1, (%%"REG_a", %1) \n\t"
+ "movq (%0, %1, 4), %%mm1 \n\t" // L5
+ PAVGB(%%mm1, %%mm0) // L3+L5
+ PAVGB(%%mm2, %%mm0) // 2L4 + L3 + L5
+ "movq %%mm0, (%%"REG_a", %1, 2) \n\t"
+ "movq (%%"REG_d"), %%mm0 \n\t" // L6
+ PAVGB(%%mm0, %%mm2) // L4+L6
+ PAVGB(%%mm1, %%mm2) // 2L5 + L4 + L6
+ "movq %%mm2, (%0, %1, 4) \n\t"
+ "movq (%%"REG_d", %1), %%mm2 \n\t" // L7
+ PAVGB(%%mm2, %%mm1) // L5+L7
+ PAVGB(%%mm0, %%mm1) // 2L6 + L5 + L7
+ "movq %%mm1, (%%"REG_d") \n\t"
+ "movq (%%"REG_d", %1, 2), %%mm1 \n\t" // L8
+ PAVGB(%%mm1, %%mm0) // L6+L8
+ PAVGB(%%mm2, %%mm0) // 2L7 + L6 + L8
+ "movq %%mm0, (%%"REG_d", %1) \n\t"
+ "movq (%0, %1, 8), %%mm0 \n\t" // L9
+ PAVGB(%%mm0, %%mm2) // L7+L9
+ PAVGB(%%mm1, %%mm2) // 2L8 + L7 + L9
+ "movq %%mm2, (%%"REG_d", %1, 2) \n\t"
+ "movq %%mm1, (%2) \n\t"
+
+ : : "r" (src), "r" ((x86_reg)stride), "r" (tmp)
+ : "%"REG_a, "%"REG_d
+ );
+#else //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+ int a, b, c, x;
+ src+= 4*stride;
+
+ for(x=0; x<2; x++){
+ a= *(uint32_t*)&tmp[stride*0];
+ b= *(uint32_t*)&src[stride*0];
+ c= *(uint32_t*)&src[stride*1];
+ a= (a&c) + (((a^c)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*0]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+
+ a= *(uint32_t*)&src[stride*2];
+ b= (a&b) + (((a^b)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*1]= (c|b) - (((c^b)&0xFEFEFEFEUL)>>1);
+
+ b= *(uint32_t*)&src[stride*3];
+ c= (b&c) + (((b^c)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*2]= (c|a) - (((c^a)&0xFEFEFEFEUL)>>1);
+
+ c= *(uint32_t*)&src[stride*4];
+ a= (a&c) + (((a^c)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*3]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+
+ a= *(uint32_t*)&src[stride*5];
+ b= (a&b) + (((a^b)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*4]= (c|b) - (((c^b)&0xFEFEFEFEUL)>>1);
+
+ b= *(uint32_t*)&src[stride*6];
+ c= (b&c) + (((b^c)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*5]= (c|a) - (((c^a)&0xFEFEFEFEUL)>>1);
+
+ c= *(uint32_t*)&src[stride*7];
+ a= (a&c) + (((a^c)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*6]= (a|b) - (((a^b)&0xFEFEFEFEUL)>>1);
+
+ a= *(uint32_t*)&src[stride*8];
+ b= (a&b) + (((a^b)&0xFEFEFEFEUL)>>1);
+ *(uint32_t*)&src[stride*7]= (c|b) - (((c^b)&0xFEFEFEFEUL)>>1);
+
+ *(uint32_t*)&tmp[stride*0]= c;
+ src += 4;
+ tmp += 4;
+ }
+#endif //TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW
+}
+
+/**
+ * Deinterlace the given block by applying a median filter to every second line.
+ * will be called for every 8x8 block and can read & write from line 4-15,
+ * lines 0-3 have been passed through the deblock / dering filters already, but can be read, too.
+ * lines 4-12 will be read into the deblocking filter and should be deinterlaced
+ */
+static inline void RENAME(deInterlaceMedian)(uint8_t src[], int stride)
+{
+#if TEMPLATE_PP_MMX
+ src+= 4*stride;
+#if TEMPLATE_PP_MMXEXT
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1
+
+ "movq (%0), %%mm0 \n\t"
+ "movq (%%"REG_a", %1), %%mm2 \n\t"
+ "movq (%%"REG_a"), %%mm1 \n\t"
+ "movq %%mm0, %%mm3 \n\t"
+ "pmaxub %%mm1, %%mm0 \n\t"
+ "pminub %%mm3, %%mm1 \n\t"
+ "pmaxub %%mm2, %%mm1 \n\t"
+ "pminub %%mm1, %%mm0 \n\t"
+ "movq %%mm0, (%%"REG_a") \n\t"
+
+ "movq (%0, %1, 4), %%mm0 \n\t"
+ "movq (%%"REG_a", %1, 2), %%mm1 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "pmaxub %%mm1, %%mm2 \n\t"
+ "pminub %%mm3, %%mm1 \n\t"
+ "pmaxub %%mm0, %%mm1 \n\t"
+ "pminub %%mm1, %%mm2 \n\t"
+ "movq %%mm2, (%%"REG_a", %1, 2) \n\t"
+
+ "movq (%%"REG_d"), %%mm2 \n\t"
+ "movq (%%"REG_d", %1), %%mm1 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "pmaxub %%mm0, %%mm2 \n\t"
+ "pminub %%mm3, %%mm0 \n\t"
+ "pmaxub %%mm1, %%mm0 \n\t"
+ "pminub %%mm0, %%mm2 \n\t"
+ "movq %%mm2, (%%"REG_d") \n\t"
+
+ "movq (%%"REG_d", %1, 2), %%mm2 \n\t"
+ "movq (%0, %1, 8), %%mm0 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "pmaxub %%mm0, %%mm2 \n\t"
+ "pminub %%mm3, %%mm0 \n\t"
+ "pmaxub %%mm1, %%mm0 \n\t"
+ "pminub %%mm0, %%mm2 \n\t"
+ "movq %%mm2, (%%"REG_d", %1, 2) \n\t"
+
+
+ : : "r" (src), "r" ((x86_reg)stride)
+ : "%"REG_a, "%"REG_d
+ );
+
+#else // MMX without MMX2
+ __asm__ volatile(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a", %1, 4), %%"REG_d" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1
+ "pxor %%mm7, %%mm7 \n\t"
+
+#define REAL_MEDIAN(a,b,c)\
+ "movq " #a ", %%mm0 \n\t"\
+ "movq " #b ", %%mm2 \n\t"\
+ "movq " #c ", %%mm1 \n\t"\
+ "movq %%mm0, %%mm3 \n\t"\
+ "movq %%mm1, %%mm4 \n\t"\
+ "movq %%mm2, %%mm5 \n\t"\
+ "psubusb %%mm1, %%mm3 \n\t"\
+ "psubusb %%mm2, %%mm4 \n\t"\
+ "psubusb %%mm0, %%mm5 \n\t"\
+ "pcmpeqb %%mm7, %%mm3 \n\t"\
+ "pcmpeqb %%mm7, %%mm4 \n\t"\
+ "pcmpeqb %%mm7, %%mm5 \n\t"\
+ "movq %%mm3, %%mm6 \n\t"\
+ "pxor %%mm4, %%mm3 \n\t"\
+ "pxor %%mm5, %%mm4 \n\t"\
+ "pxor %%mm6, %%mm5 \n\t"\
+ "por %%mm3, %%mm1 \n\t"\
+ "por %%mm4, %%mm2 \n\t"\
+ "por %%mm5, %%mm0 \n\t"\
+ "pand %%mm2, %%mm0 \n\t"\
+ "pand %%mm1, %%mm0 \n\t"\
+ "movq %%mm0, " #b " \n\t"
+#define MEDIAN(a,b,c) REAL_MEDIAN(a,b,c)
+
+MEDIAN((%0) , (%%REGa) , (%%REGa, %1))
+MEDIAN((%%REGa, %1), (%%REGa, %1, 2), (%0, %1, 4))
+MEDIAN((%0, %1, 4) , (%%REGd) , (%%REGd, %1))
+MEDIAN((%%REGd, %1), (%%REGd, %1, 2), (%0, %1, 8))
+
+ : : "r" (src), "r" ((x86_reg)stride)
+ : "%"REG_a, "%"REG_d
+ );
+#endif //TEMPLATE_PP_MMXEXT
+#else //TEMPLATE_PP_MMX
+ int x, y;
+ src+= 4*stride;
+ // FIXME - there should be a way to do a few columns in parallel like w/mmx
+ for(x=0; x<8; x++){
+ uint8_t *colsrc = src;
+ for (y=0; y<4; y++){
+ int a, b, c, d, e, f;
+ a = colsrc[0 ];
+ b = colsrc[stride ];
+ c = colsrc[stride*2];
+ d = (a-b)>>31;
+ e = (b-c)>>31;
+ f = (c-a)>>31;
+ colsrc[stride ] = (a|(d^f)) & (b|(d^e)) & (c|(e^f));
+ colsrc += stride*2;
+ }
+ src++;
+ }
+#endif //TEMPLATE_PP_MMX
+}
+
+#if TEMPLATE_PP_MMX
+/**
+ * Transpose and shift the given 8x8 Block into dst1 and dst2.
+ */
+static inline void RENAME(transpose1)(uint8_t *dst1, uint8_t *dst2, const uint8_t *src, int srcStride)
+{
+ __asm__(
+ "lea (%0, %1), %%"REG_a" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1
+ "movq (%0), %%mm0 \n\t" // 12345678
+ "movq (%%"REG_a"), %%mm1 \n\t" // abcdefgh
+ "movq %%mm0, %%mm2 \n\t" // 12345678
+ "punpcklbw %%mm1, %%mm0 \n\t" // 1a2b3c4d
+ "punpckhbw %%mm1, %%mm2 \n\t" // 5e6f7g8h
+
+ "movq (%%"REG_a", %1), %%mm1 \n\t"
+ "movq (%%"REG_a", %1, 2), %%mm3 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+ "punpcklbw %%mm3, %%mm1 \n\t"
+ "punpckhbw %%mm3, %%mm4 \n\t"
+
+ "movq %%mm0, %%mm3 \n\t"
+ "punpcklwd %%mm1, %%mm0 \n\t"
+ "punpckhwd %%mm1, %%mm3 \n\t"
+ "movq %%mm2, %%mm1 \n\t"
+ "punpcklwd %%mm4, %%mm2 \n\t"
+ "punpckhwd %%mm4, %%mm1 \n\t"
+
+ "movd %%mm0, 128(%2) \n\t"
+ "psrlq $32, %%mm0 \n\t"
+ "movd %%mm0, 144(%2) \n\t"
+ "movd %%mm3, 160(%2) \n\t"
+ "psrlq $32, %%mm3 \n\t"
+ "movd %%mm3, 176(%2) \n\t"
+ "movd %%mm3, 48(%3) \n\t"
+ "movd %%mm2, 192(%2) \n\t"
+ "movd %%mm2, 64(%3) \n\t"
+ "psrlq $32, %%mm2 \n\t"
+ "movd %%mm2, 80(%3) \n\t"
+ "movd %%mm1, 96(%3) \n\t"
+ "psrlq $32, %%mm1 \n\t"
+ "movd %%mm1, 112(%3) \n\t"
+
+ "lea (%%"REG_a", %1, 4), %%"REG_a" \n\t"
+
+ "movq (%0, %1, 4), %%mm0 \n\t" // 12345678
+ "movq (%%"REG_a"), %%mm1 \n\t" // abcdefgh
+ "movq %%mm0, %%mm2 \n\t" // 12345678
+ "punpcklbw %%mm1, %%mm0 \n\t" // 1a2b3c4d
+ "punpckhbw %%mm1, %%mm2 \n\t" // 5e6f7g8h
+
+ "movq (%%"REG_a", %1), %%mm1 \n\t"
+ "movq (%%"REG_a", %1, 2), %%mm3 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+ "punpcklbw %%mm3, %%mm1 \n\t"
+ "punpckhbw %%mm3, %%mm4 \n\t"
+
+ "movq %%mm0, %%mm3 \n\t"
+ "punpcklwd %%mm1, %%mm0 \n\t"
+ "punpckhwd %%mm1, %%mm3 \n\t"
+ "movq %%mm2, %%mm1 \n\t"
+ "punpcklwd %%mm4, %%mm2 \n\t"
+ "punpckhwd %%mm4, %%mm1 \n\t"
+
+ "movd %%mm0, 132(%2) \n\t"
+ "psrlq $32, %%mm0 \n\t"
+ "movd %%mm0, 148(%2) \n\t"
+ "movd %%mm3, 164(%2) \n\t"
+ "psrlq $32, %%mm3 \n\t"
+ "movd %%mm3, 180(%2) \n\t"
+ "movd %%mm3, 52(%3) \n\t"
+ "movd %%mm2, 196(%2) \n\t"
+ "movd %%mm2, 68(%3) \n\t"
+ "psrlq $32, %%mm2 \n\t"
+ "movd %%mm2, 84(%3) \n\t"
+ "movd %%mm1, 100(%3) \n\t"
+ "psrlq $32, %%mm1 \n\t"
+ "movd %%mm1, 116(%3) \n\t"
+
+
+ :: "r" (src), "r" ((x86_reg)srcStride), "r" (dst1), "r" (dst2)
+ : "%"REG_a
+ );
+}
+
+/**
+ * Transpose the given 8x8 block.
+ */
+static inline void RENAME(transpose2)(uint8_t *dst, int dstStride, const uint8_t *src)
+{
+ __asm__(
+ "lea (%0, %1), %%"REG_a" \n\t"
+ "lea (%%"REG_a",%1,4), %%"REG_d" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 edx edx+%1 edx+2%1 %0+8%1 edx+4%1
+ "movq (%2), %%mm0 \n\t" // 12345678
+ "movq 16(%2), %%mm1 \n\t" // abcdefgh
+ "movq %%mm0, %%mm2 \n\t" // 12345678
+ "punpcklbw %%mm1, %%mm0 \n\t" // 1a2b3c4d
+ "punpckhbw %%mm1, %%mm2 \n\t" // 5e6f7g8h
+
+ "movq 32(%2), %%mm1 \n\t"
+ "movq 48(%2), %%mm3 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+ "punpcklbw %%mm3, %%mm1 \n\t"
+ "punpckhbw %%mm3, %%mm4 \n\t"
+
+ "movq %%mm0, %%mm3 \n\t"
+ "punpcklwd %%mm1, %%mm0 \n\t"
+ "punpckhwd %%mm1, %%mm3 \n\t"
+ "movq %%mm2, %%mm1 \n\t"
+ "punpcklwd %%mm4, %%mm2 \n\t"
+ "punpckhwd %%mm4, %%mm1 \n\t"
+
+ "movd %%mm0, (%0) \n\t"
+ "psrlq $32, %%mm0 \n\t"
+ "movd %%mm0, (%%"REG_a") \n\t"
+ "movd %%mm3, (%%"REG_a", %1) \n\t"
+ "psrlq $32, %%mm3 \n\t"
+ "movd %%mm3, (%%"REG_a", %1, 2) \n\t"
+ "movd %%mm2, (%0, %1, 4) \n\t"
+ "psrlq $32, %%mm2 \n\t"
+ "movd %%mm2, (%%"REG_d") \n\t"
+ "movd %%mm1, (%%"REG_d", %1) \n\t"
+ "psrlq $32, %%mm1 \n\t"
+ "movd %%mm1, (%%"REG_d", %1, 2) \n\t"
+
+
+ "movq 64(%2), %%mm0 \n\t" // 12345678
+ "movq 80(%2), %%mm1 \n\t" // abcdefgh
+ "movq %%mm0, %%mm2 \n\t" // 12345678
+ "punpcklbw %%mm1, %%mm0 \n\t" // 1a2b3c4d
+ "punpckhbw %%mm1, %%mm2 \n\t" // 5e6f7g8h
+
+ "movq 96(%2), %%mm1 \n\t"
+ "movq 112(%2), %%mm3 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+ "punpcklbw %%mm3, %%mm1 \n\t"
+ "punpckhbw %%mm3, %%mm4 \n\t"
+
+ "movq %%mm0, %%mm3 \n\t"
+ "punpcklwd %%mm1, %%mm0 \n\t"
+ "punpckhwd %%mm1, %%mm3 \n\t"
+ "movq %%mm2, %%mm1 \n\t"
+ "punpcklwd %%mm4, %%mm2 \n\t"
+ "punpckhwd %%mm4, %%mm1 \n\t"
+
+ "movd %%mm0, 4(%0) \n\t"
+ "psrlq $32, %%mm0 \n\t"
+ "movd %%mm0, 4(%%"REG_a") \n\t"
+ "movd %%mm3, 4(%%"REG_a", %1) \n\t"
+ "psrlq $32, %%mm3 \n\t"
+ "movd %%mm3, 4(%%"REG_a", %1, 2) \n\t"
+ "movd %%mm2, 4(%0, %1, 4) \n\t"
+ "psrlq $32, %%mm2 \n\t"
+ "movd %%mm2, 4(%%"REG_d") \n\t"
+ "movd %%mm1, 4(%%"REG_d", %1) \n\t"
+ "psrlq $32, %%mm1 \n\t"
+ "movd %%mm1, 4(%%"REG_d", %1, 2) \n\t"
+
+ :: "r" (dst), "r" ((x86_reg)dstStride), "r" (src)
+ : "%"REG_a, "%"REG_d
+ );
+}
+#endif //TEMPLATE_PP_MMX
+//static long test=0;
+
+#if !TEMPLATE_PP_ALTIVEC
+static inline void RENAME(tempNoiseReducer)(uint8_t *src, int stride,
+ uint8_t *tempBlurred, uint32_t *tempBlurredPast, const int *maxNoise)
+{
+ // to save a register (FIXME do this outside of the loops)
+ tempBlurredPast[127]= maxNoise[0];
+ tempBlurredPast[128]= maxNoise[1];
+ tempBlurredPast[129]= maxNoise[2];
+
+#define FAST_L2_DIFF
+//#define L1_DIFF //u should change the thresholds too if u try that one
+#if (TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW) && HAVE_6REGS
+ __asm__ volatile(
+ "lea (%2, %2, 2), %%"REG_a" \n\t" // 3*stride
+ "lea (%2, %2, 4), %%"REG_d" \n\t" // 5*stride
+ "lea (%%"REG_d", %2, 2), %%"REG_c" \n\t" // 7*stride
+// 0 1 2 3 4 5 6 7 8 9
+// %x %x+%2 %x+2%2 %x+eax %x+4%2 %x+edx %x+2eax %x+ecx %x+8%2
+//FIXME reorder?
+#ifdef L1_DIFF //needs mmx2
+ "movq (%0), %%mm0 \n\t" // L0
+ "psadbw (%1), %%mm0 \n\t" // |L0-R0|
+ "movq (%0, %2), %%mm1 \n\t" // L1
+ "psadbw (%1, %2), %%mm1 \n\t" // |L1-R1|
+ "movq (%0, %2, 2), %%mm2 \n\t" // L2
+ "psadbw (%1, %2, 2), %%mm2 \n\t" // |L2-R2|
+ "movq (%0, %%"REG_a"), %%mm3 \n\t" // L3
+ "psadbw (%1, %%"REG_a"), %%mm3 \n\t" // |L3-R3|
+
+ "movq (%0, %2, 4), %%mm4 \n\t" // L4
+ "paddw %%mm1, %%mm0 \n\t"
+ "psadbw (%1, %2, 4), %%mm4 \n\t" // |L4-R4|
+ "movq (%0, %%"REG_d"), %%mm5 \n\t" // L5
+ "paddw %%mm2, %%mm0 \n\t"
+ "psadbw (%1, %%"REG_d"), %%mm5 \n\t" // |L5-R5|
+ "movq (%0, %%"REG_a", 2), %%mm6 \n\t" // L6
+ "paddw %%mm3, %%mm0 \n\t"
+ "psadbw (%1, %%"REG_a", 2), %%mm6 \n\t" // |L6-R6|
+ "movq (%0, %%"REG_c"), %%mm7 \n\t" // L7
+ "paddw %%mm4, %%mm0 \n\t"
+ "psadbw (%1, %%"REG_c"), %%mm7 \n\t" // |L7-R7|
+ "paddw %%mm5, %%mm6 \n\t"
+ "paddw %%mm7, %%mm6 \n\t"
+ "paddw %%mm6, %%mm0 \n\t"
+#else //L1_DIFF
+#if defined (FAST_L2_DIFF)
+ "pcmpeqb %%mm7, %%mm7 \n\t"
+ "movq "MANGLE(b80)", %%mm6 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+#define REAL_L2_DIFF_CORE(a, b)\
+ "movq " #a ", %%mm5 \n\t"\
+ "movq " #b ", %%mm2 \n\t"\
+ "pxor %%mm7, %%mm2 \n\t"\
+ PAVGB(%%mm2, %%mm5)\
+ "paddb %%mm6, %%mm5 \n\t"\
+ "movq %%mm5, %%mm2 \n\t"\
+ "psllw $8, %%mm5 \n\t"\
+ "pmaddwd %%mm5, %%mm5 \n\t"\
+ "pmaddwd %%mm2, %%mm2 \n\t"\
+ "paddd %%mm2, %%mm5 \n\t"\
+ "psrld $14, %%mm5 \n\t"\
+ "paddd %%mm5, %%mm0 \n\t"
+
+#else //defined (FAST_L2_DIFF)
+ "pxor %%mm7, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+#define REAL_L2_DIFF_CORE(a, b)\
+ "movq " #a ", %%mm5 \n\t"\
+ "movq " #b ", %%mm2 \n\t"\
+ "movq %%mm5, %%mm1 \n\t"\
+ "movq %%mm2, %%mm3 \n\t"\
+ "punpcklbw %%mm7, %%mm5 \n\t"\
+ "punpckhbw %%mm7, %%mm1 \n\t"\
+ "punpcklbw %%mm7, %%mm2 \n\t"\
+ "punpckhbw %%mm7, %%mm3 \n\t"\
+ "psubw %%mm2, %%mm5 \n\t"\
+ "psubw %%mm3, %%mm1 \n\t"\
+ "pmaddwd %%mm5, %%mm5 \n\t"\
+ "pmaddwd %%mm1, %%mm1 \n\t"\
+ "paddd %%mm1, %%mm5 \n\t"\
+ "paddd %%mm5, %%mm0 \n\t"
+
+#endif //defined (FAST_L2_DIFF)
+
+#define L2_DIFF_CORE(a, b) REAL_L2_DIFF_CORE(a, b)
+
+L2_DIFF_CORE((%0) , (%1))
+L2_DIFF_CORE((%0, %2) , (%1, %2))
+L2_DIFF_CORE((%0, %2, 2) , (%1, %2, 2))
+L2_DIFF_CORE((%0, %%REGa) , (%1, %%REGa))
+L2_DIFF_CORE((%0, %2, 4) , (%1, %2, 4))
+L2_DIFF_CORE((%0, %%REGd) , (%1, %%REGd))
+L2_DIFF_CORE((%0, %%REGa,2), (%1, %%REGa,2))
+L2_DIFF_CORE((%0, %%REGc) , (%1, %%REGc))
+
+#endif //L1_DIFF
+
+ "movq %%mm0, %%mm4 \n\t"
+ "psrlq $32, %%mm0 \n\t"
+ "paddd %%mm0, %%mm4 \n\t"
+ "movd %%mm4, %%ecx \n\t"
+ "shll $2, %%ecx \n\t"
+ "mov %3, %%"REG_d" \n\t"
+ "addl -4(%%"REG_d"), %%ecx \n\t"
+ "addl 4(%%"REG_d"), %%ecx \n\t"
+ "addl -1024(%%"REG_d"), %%ecx \n\t"
+ "addl $4, %%ecx \n\t"
+ "addl 1024(%%"REG_d"), %%ecx \n\t"
+ "shrl $3, %%ecx \n\t"
+ "movl %%ecx, (%%"REG_d") \n\t"
+
+// "mov %3, %%"REG_c" \n\t"
+// "mov %%"REG_c", test \n\t"
+// "jmp 4f \n\t"
+ "cmpl 512(%%"REG_d"), %%ecx \n\t"
+ " jb 2f \n\t"
+ "cmpl 516(%%"REG_d"), %%ecx \n\t"
+ " jb 1f \n\t"
+
+ "lea (%%"REG_a", %2, 2), %%"REG_d" \n\t" // 5*stride
+ "lea (%%"REG_d", %2, 2), %%"REG_c" \n\t" // 7*stride
+ "movq (%0), %%mm0 \n\t" // L0
+ "movq (%0, %2), %%mm1 \n\t" // L1
+ "movq (%0, %2, 2), %%mm2 \n\t" // L2
+ "movq (%0, %%"REG_a"), %%mm3 \n\t" // L3
+ "movq (%0, %2, 4), %%mm4 \n\t" // L4
+ "movq (%0, %%"REG_d"), %%mm5 \n\t" // L5
+ "movq (%0, %%"REG_a", 2), %%mm6 \n\t" // L6
+ "movq (%0, %%"REG_c"), %%mm7 \n\t" // L7
+ "movq %%mm0, (%1) \n\t" // L0
+ "movq %%mm1, (%1, %2) \n\t" // L1
+ "movq %%mm2, (%1, %2, 2) \n\t" // L2
+ "movq %%mm3, (%1, %%"REG_a") \n\t" // L3
+ "movq %%mm4, (%1, %2, 4) \n\t" // L4
+ "movq %%mm5, (%1, %%"REG_d") \n\t" // L5
+ "movq %%mm6, (%1, %%"REG_a", 2) \n\t" // L6
+ "movq %%mm7, (%1, %%"REG_c") \n\t" // L7
+ "jmp 4f \n\t"
+
+ "1: \n\t"
+ "lea (%%"REG_a", %2, 2), %%"REG_d" \n\t" // 5*stride
+ "lea (%%"REG_d", %2, 2), %%"REG_c" \n\t" // 7*stride
+ "movq (%0), %%mm0 \n\t" // L0
+ PAVGB((%1), %%mm0) // L0
+ "movq (%0, %2), %%mm1 \n\t" // L1
+ PAVGB((%1, %2), %%mm1) // L1
+ "movq (%0, %2, 2), %%mm2 \n\t" // L2
+ PAVGB((%1, %2, 2), %%mm2) // L2
+ "movq (%0, %%"REG_a"), %%mm3 \n\t" // L3
+ PAVGB((%1, %%REGa), %%mm3) // L3
+ "movq (%0, %2, 4), %%mm4 \n\t" // L4
+ PAVGB((%1, %2, 4), %%mm4) // L4
+ "movq (%0, %%"REG_d"), %%mm5 \n\t" // L5
+ PAVGB((%1, %%REGd), %%mm5) // L5
+ "movq (%0, %%"REG_a", 2), %%mm6 \n\t" // L6
+ PAVGB((%1, %%REGa, 2), %%mm6) // L6
+ "movq (%0, %%"REG_c"), %%mm7 \n\t" // L7
+ PAVGB((%1, %%REGc), %%mm7) // L7
+ "movq %%mm0, (%1) \n\t" // R0
+ "movq %%mm1, (%1, %2) \n\t" // R1
+ "movq %%mm2, (%1, %2, 2) \n\t" // R2
+ "movq %%mm3, (%1, %%"REG_a") \n\t" // R3
+ "movq %%mm4, (%1, %2, 4) \n\t" // R4
+ "movq %%mm5, (%1, %%"REG_d") \n\t" // R5
+ "movq %%mm6, (%1, %%"REG_a", 2) \n\t" // R6
+ "movq %%mm7, (%1, %%"REG_c") \n\t" // R7
+ "movq %%mm0, (%0) \n\t" // L0
+ "movq %%mm1, (%0, %2) \n\t" // L1
+ "movq %%mm2, (%0, %2, 2) \n\t" // L2
+ "movq %%mm3, (%0, %%"REG_a") \n\t" // L3
+ "movq %%mm4, (%0, %2, 4) \n\t" // L4
+ "movq %%mm5, (%0, %%"REG_d") \n\t" // L5
+ "movq %%mm6, (%0, %%"REG_a", 2) \n\t" // L6
+ "movq %%mm7, (%0, %%"REG_c") \n\t" // L7
+ "jmp 4f \n\t"
+
+ "2: \n\t"
+ "cmpl 508(%%"REG_d"), %%ecx \n\t"
+ " jb 3f \n\t"
+
+ "lea (%%"REG_a", %2, 2), %%"REG_d" \n\t" // 5*stride
+ "lea (%%"REG_d", %2, 2), %%"REG_c" \n\t" // 7*stride
+ "movq (%0), %%mm0 \n\t" // L0
+ "movq (%0, %2), %%mm1 \n\t" // L1
+ "movq (%0, %2, 2), %%mm2 \n\t" // L2
+ "movq (%0, %%"REG_a"), %%mm3 \n\t" // L3
+ "movq (%1), %%mm4 \n\t" // R0
+ "movq (%1, %2), %%mm5 \n\t" // R1
+ "movq (%1, %2, 2), %%mm6 \n\t" // R2
+ "movq (%1, %%"REG_a"), %%mm7 \n\t" // R3
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ "movq %%mm0, (%1) \n\t" // R0
+ "movq %%mm1, (%1, %2) \n\t" // R1
+ "movq %%mm2, (%1, %2, 2) \n\t" // R2
+ "movq %%mm3, (%1, %%"REG_a") \n\t" // R3
+ "movq %%mm0, (%0) \n\t" // L0
+ "movq %%mm1, (%0, %2) \n\t" // L1
+ "movq %%mm2, (%0, %2, 2) \n\t" // L2
+ "movq %%mm3, (%0, %%"REG_a") \n\t" // L3
+
+ "movq (%0, %2, 4), %%mm0 \n\t" // L4
+ "movq (%0, %%"REG_d"), %%mm1 \n\t" // L5
+ "movq (%0, %%"REG_a", 2), %%mm2 \n\t" // L6
+ "movq (%0, %%"REG_c"), %%mm3 \n\t" // L7
+ "movq (%1, %2, 4), %%mm4 \n\t" // R4
+ "movq (%1, %%"REG_d"), %%mm5 \n\t" // R5
+ "movq (%1, %%"REG_a", 2), %%mm6 \n\t" // R6
+ "movq (%1, %%"REG_c"), %%mm7 \n\t" // R7
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ "movq %%mm0, (%1, %2, 4) \n\t" // R4
+ "movq %%mm1, (%1, %%"REG_d") \n\t" // R5
+ "movq %%mm2, (%1, %%"REG_a", 2) \n\t" // R6
+ "movq %%mm3, (%1, %%"REG_c") \n\t" // R7
+ "movq %%mm0, (%0, %2, 4) \n\t" // L4
+ "movq %%mm1, (%0, %%"REG_d") \n\t" // L5
+ "movq %%mm2, (%0, %%"REG_a", 2) \n\t" // L6
+ "movq %%mm3, (%0, %%"REG_c") \n\t" // L7
+ "jmp 4f \n\t"
+
+ "3: \n\t"
+ "lea (%%"REG_a", %2, 2), %%"REG_d" \n\t" // 5*stride
+ "lea (%%"REG_d", %2, 2), %%"REG_c" \n\t" // 7*stride
+ "movq (%0), %%mm0 \n\t" // L0
+ "movq (%0, %2), %%mm1 \n\t" // L1
+ "movq (%0, %2, 2), %%mm2 \n\t" // L2
+ "movq (%0, %%"REG_a"), %%mm3 \n\t" // L3
+ "movq (%1), %%mm4 \n\t" // R0
+ "movq (%1, %2), %%mm5 \n\t" // R1
+ "movq (%1, %2, 2), %%mm6 \n\t" // R2
+ "movq (%1, %%"REG_a"), %%mm7 \n\t" // R3
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ "movq %%mm0, (%1) \n\t" // R0
+ "movq %%mm1, (%1, %2) \n\t" // R1
+ "movq %%mm2, (%1, %2, 2) \n\t" // R2
+ "movq %%mm3, (%1, %%"REG_a") \n\t" // R3
+ "movq %%mm0, (%0) \n\t" // L0
+ "movq %%mm1, (%0, %2) \n\t" // L1
+ "movq %%mm2, (%0, %2, 2) \n\t" // L2
+ "movq %%mm3, (%0, %%"REG_a") \n\t" // L3
+
+ "movq (%0, %2, 4), %%mm0 \n\t" // L4
+ "movq (%0, %%"REG_d"), %%mm1 \n\t" // L5
+ "movq (%0, %%"REG_a", 2), %%mm2 \n\t" // L6
+ "movq (%0, %%"REG_c"), %%mm3 \n\t" // L7
+ "movq (%1, %2, 4), %%mm4 \n\t" // R4
+ "movq (%1, %%"REG_d"), %%mm5 \n\t" // R5
+ "movq (%1, %%"REG_a", 2), %%mm6 \n\t" // R6
+ "movq (%1, %%"REG_c"), %%mm7 \n\t" // R7
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ PAVGB(%%mm4, %%mm0)
+ PAVGB(%%mm5, %%mm1)
+ PAVGB(%%mm6, %%mm2)
+ PAVGB(%%mm7, %%mm3)
+ "movq %%mm0, (%1, %2, 4) \n\t" // R4
+ "movq %%mm1, (%1, %%"REG_d") \n\t" // R5
+ "movq %%mm2, (%1, %%"REG_a", 2) \n\t" // R6
+ "movq %%mm3, (%1, %%"REG_c") \n\t" // R7
+ "movq %%mm0, (%0, %2, 4) \n\t" // L4
+ "movq %%mm1, (%0, %%"REG_d") \n\t" // L5
+ "movq %%mm2, (%0, %%"REG_a", 2) \n\t" // L6
+ "movq %%mm3, (%0, %%"REG_c") \n\t" // L7
+
+ "4: \n\t"
+
+ :: "r" (src), "r" (tempBlurred), "r"((x86_reg)stride), "m" (tempBlurredPast)
+ NAMED_CONSTRAINTS_ADD(b80)
+ : "%"REG_a, "%"REG_d, "%"REG_c, "memory"
+ );
+#else //(TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW) && HAVE_6REGS
+{
+ int y;
+ int d=0;
+// int sysd=0;
+ int i;
+
+ for(y=0; y<8; y++){
+ int x;
+ for(x=0; x<8; x++){
+ int ref= tempBlurred[ x + y*stride ];
+ int cur= src[ x + y*stride ];
+ int d1=ref - cur;
+// if(x==0 || x==7) d1+= d1>>1;
+// if(y==0 || y==7) d1+= d1>>1;
+// d+= FFABS(d1);
+ d+= d1*d1;
+// sysd+= d1;
+ }
+ }
+ i=d;
+ d= (
+ 4*d
+ +(*(tempBlurredPast-256))
+ +(*(tempBlurredPast-1))+ (*(tempBlurredPast+1))
+ +(*(tempBlurredPast+256))
+ +4)>>3;
+ *tempBlurredPast=i;
+// ((*tempBlurredPast)*3 + d + 2)>>2;
+
+/*
+Switch between
+ 1 0 0 0 0 0 0 (0)
+64 32 16 8 4 2 1 (1)
+64 48 36 27 20 15 11 (33) (approx)
+64 56 49 43 37 33 29 (200) (approx)
+*/
+ if(d > maxNoise[1]){
+ if(d < maxNoise[2]){
+ for(y=0; y<8; y++){
+ int x;
+ for(x=0; x<8; x++){
+ int ref= tempBlurred[ x + y*stride ];
+ int cur= src[ x + y*stride ];
+ tempBlurred[ x + y*stride ]=
+ src[ x + y*stride ]=
+ (ref + cur + 1)>>1;
+ }
+ }
+ }else{
+ for(y=0; y<8; y++){
+ int x;
+ for(x=0; x<8; x++){
+ tempBlurred[ x + y*stride ]= src[ x + y*stride ];
+ }
+ }
+ }
+ }else{
+ if(d < maxNoise[0]){
+ for(y=0; y<8; y++){
+ int x;
+ for(x=0; x<8; x++){
+ int ref= tempBlurred[ x + y*stride ];
+ int cur= src[ x + y*stride ];
+ tempBlurred[ x + y*stride ]=
+ src[ x + y*stride ]=
+ (ref*7 + cur + 4)>>3;
+ }
+ }
+ }else{
+ for(y=0; y<8; y++){
+ int x;
+ for(x=0; x<8; x++){
+ int ref= tempBlurred[ x + y*stride ];
+ int cur= src[ x + y*stride ];
+ tempBlurred[ x + y*stride ]=
+ src[ x + y*stride ]=
+ (ref*3 + cur + 2)>>2;
+ }
+ }
+ }
+ }
+}
+#endif //(TEMPLATE_PP_MMXEXT || TEMPLATE_PP_3DNOW) && HAVE_6REGS
+}
+#endif //TEMPLATE_PP_ALTIVEC
+
+#if TEMPLATE_PP_MMX
+/**
+ * accurate deblock filter
+ */
+static av_always_inline void RENAME(do_a_deblock)(uint8_t *src, int step, int stride, const PPContext *c, int mode){
+ int64_t dc_mask, eq_mask, both_masks;
+ int64_t sums[10*8*2];
+ src+= step*3; // src points to begin of the 8x8 Block
+ //{ START_TIMER
+ __asm__ volatile(
+ "movq %0, %%mm7 \n\t"
+ "movq %1, %%mm6 \n\t"
+ : : "m" (c->mmxDcOffset[c->nonBQP]), "m" (c->mmxDcThreshold[c->nonBQP])
+ );
+
+ __asm__ volatile(
+ "lea (%2, %3), %%"REG_a" \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %1 eax eax+%2 eax+2%2 %1+4%2 ecx ecx+%2 ecx+2%2 %1+8%2 ecx+4%2
+
+ "movq (%2), %%mm0 \n\t"
+ "movq (%%"REG_a"), %%mm1 \n\t"
+ "movq %%mm1, %%mm3 \n\t"
+ "movq %%mm1, %%mm4 \n\t"
+ "psubb %%mm1, %%mm0 \n\t" // mm0 = difference
+ "paddb %%mm7, %%mm0 \n\t"
+ "pcmpgtb %%mm6, %%mm0 \n\t"
+
+ "movq (%%"REG_a",%3), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3, 2), %%mm1 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+
+ "lea (%%"REG_a", %3, 4), %%"REG_a" \n\t"
+
+ "movq (%2, %3, 4), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a"), %%mm1 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3, 2), %%mm1 \n\t"
+ PMAXUB(%%mm1, %%mm4)
+ PMINUB(%%mm1, %%mm3, %%mm5)
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+
+ "movq (%2, %3, 8), %%mm2 \n\t"
+ PMAXUB(%%mm2, %%mm4)
+ PMINUB(%%mm2, %%mm3, %%mm5)
+ "psubb %%mm2, %%mm1 \n\t"
+ "paddb %%mm7, %%mm1 \n\t"
+ "pcmpgtb %%mm6, %%mm1 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "movq (%%"REG_a", %3, 4), %%mm1 \n\t"
+ "psubb %%mm1, %%mm2 \n\t"
+ "paddb %%mm7, %%mm2 \n\t"
+ "pcmpgtb %%mm6, %%mm2 \n\t"
+ "paddb %%mm2, %%mm0 \n\t"
+ "psubusb %%mm3, %%mm4 \n\t"
+
+ "pxor %%mm6, %%mm6 \n\t"
+ "movq %4, %%mm7 \n\t" // QP,..., QP
+ "paddusb %%mm7, %%mm7 \n\t" // 2QP ... 2QP
+ "psubusb %%mm4, %%mm7 \n\t" // Diff >=2QP -> 0
+ "pcmpeqb %%mm6, %%mm7 \n\t" // Diff < 2QP -> 0
+ "pcmpeqb %%mm6, %%mm7 \n\t" // Diff < 2QP -> 0
+ "movq %%mm7, %1 \n\t"
+
+ "movq %5, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "psubb %%mm0, %%mm6 \n\t"
+ "pcmpgtb %%mm7, %%mm6 \n\t"
+ "movq %%mm6, %0 \n\t"
+
+ : "=m" (eq_mask), "=m" (dc_mask)
+ : "r" (src), "r" ((x86_reg)step), "m" (c->pQPb), "m"(c->ppMode.flatnessThreshold)
+ : "%"REG_a
+ );
+
+ both_masks = dc_mask & eq_mask;
+
+ if(both_masks){
+ x86_reg offset= -8*step;
+ int64_t *temp_sums= sums;
+
+ __asm__ volatile(
+ "movq %2, %%mm0 \n\t" // QP,..., QP
+ "pxor %%mm4, %%mm4 \n\t"
+
+ "movq (%0), %%mm6 \n\t"
+ "movq (%0, %1), %%mm5 \n\t"
+ "movq %%mm5, %%mm1 \n\t"
+ "movq %%mm6, %%mm2 \n\t"
+ "psubusb %%mm6, %%mm5 \n\t"
+ "psubusb %%mm1, %%mm2 \n\t"
+ "por %%mm5, %%mm2 \n\t" // ABS Diff of lines
+ "psubusb %%mm2, %%mm0 \n\t" // diff >= QP -> 0
+ "pcmpeqb %%mm4, %%mm0 \n\t" // diff >= QP -> FF
+
+ "pxor %%mm6, %%mm1 \n\t"
+ "pand %%mm0, %%mm1 \n\t"
+ "pxor %%mm1, %%mm6 \n\t"
+ // 0:QP 6:First
+
+ "movq (%0, %1, 8), %%mm5 \n\t"
+ "add %1, %0 \n\t" // %0 points to line 1 not 0
+ "movq (%0, %1, 8), %%mm7 \n\t"
+ "movq %%mm5, %%mm1 \n\t"
+ "movq %%mm7, %%mm2 \n\t"
+ "psubusb %%mm7, %%mm5 \n\t"
+ "psubusb %%mm1, %%mm2 \n\t"
+ "por %%mm5, %%mm2 \n\t" // ABS Diff of lines
+ "movq %2, %%mm0 \n\t" // QP,..., QP
+ "psubusb %%mm2, %%mm0 \n\t" // diff >= QP -> 0
+ "pcmpeqb %%mm4, %%mm0 \n\t" // diff >= QP -> FF
+
+ "pxor %%mm7, %%mm1 \n\t"
+ "pand %%mm0, %%mm1 \n\t"
+ "pxor %%mm1, %%mm7 \n\t"
+
+ "movq %%mm6, %%mm5 \n\t"
+ "punpckhbw %%mm4, %%mm6 \n\t"
+ "punpcklbw %%mm4, %%mm5 \n\t"
+ // 4:0 5/6:First 7:Last
+
+ "movq %%mm5, %%mm0 \n\t"
+ "movq %%mm6, %%mm1 \n\t"
+ "psllw $2, %%mm0 \n\t"
+ "psllw $2, %%mm1 \n\t"
+ "paddw "MANGLE(w04)", %%mm0 \n\t"
+ "paddw "MANGLE(w04)", %%mm1 \n\t"
+
+#define NEXT\
+ "movq (%0), %%mm2 \n\t"\
+ "movq (%0), %%mm3 \n\t"\
+ "add %1, %0 \n\t"\
+ "punpcklbw %%mm4, %%mm2 \n\t"\
+ "punpckhbw %%mm4, %%mm3 \n\t"\
+ "paddw %%mm2, %%mm0 \n\t"\
+ "paddw %%mm3, %%mm1 \n\t"
+
+#define PREV\
+ "movq (%0), %%mm2 \n\t"\
+ "movq (%0), %%mm3 \n\t"\
+ "add %1, %0 \n\t"\
+ "punpcklbw %%mm4, %%mm2 \n\t"\
+ "punpckhbw %%mm4, %%mm3 \n\t"\
+ "psubw %%mm2, %%mm0 \n\t"\
+ "psubw %%mm3, %%mm1 \n\t"
+
+
+ NEXT //0
+ NEXT //1
+ NEXT //2
+ "movq %%mm0, (%3) \n\t"
+ "movq %%mm1, 8(%3) \n\t"
+
+ NEXT //3
+ "psubw %%mm5, %%mm0 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+ "movq %%mm0, 16(%3) \n\t"
+ "movq %%mm1, 24(%3) \n\t"
+
+ NEXT //4
+ "psubw %%mm5, %%mm0 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+ "movq %%mm0, 32(%3) \n\t"
+ "movq %%mm1, 40(%3) \n\t"
+
+ NEXT //5
+ "psubw %%mm5, %%mm0 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+ "movq %%mm0, 48(%3) \n\t"
+ "movq %%mm1, 56(%3) \n\t"
+
+ NEXT //6
+ "psubw %%mm5, %%mm0 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+ "movq %%mm0, 64(%3) \n\t"
+ "movq %%mm1, 72(%3) \n\t"
+
+ "movq %%mm7, %%mm6 \n\t"
+ "punpckhbw %%mm4, %%mm7 \n\t"
+ "punpcklbw %%mm4, %%mm6 \n\t"
+
+ NEXT //7
+ "mov %4, %0 \n\t"
+ "add %1, %0 \n\t"
+ PREV //0
+ "movq %%mm0, 80(%3) \n\t"
+ "movq %%mm1, 88(%3) \n\t"
+
+ PREV //1
+ "paddw %%mm6, %%mm0 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "movq %%mm0, 96(%3) \n\t"
+ "movq %%mm1, 104(%3) \n\t"
+
+ PREV //2
+ "paddw %%mm6, %%mm0 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "movq %%mm0, 112(%3) \n\t"
+ "movq %%mm1, 120(%3) \n\t"
+
+ PREV //3
+ "paddw %%mm6, %%mm0 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "movq %%mm0, 128(%3) \n\t"
+ "movq %%mm1, 136(%3) \n\t"
+
+ PREV //4
+ "paddw %%mm6, %%mm0 \n\t"
+ "paddw %%mm7, %%mm1 \n\t"
+ "movq %%mm0, 144(%3) \n\t"
+ "movq %%mm1, 152(%3) \n\t"
+
+ "mov %4, %0 \n\t" //FIXME
+
+ : "+&r"(src)
+ : "r" ((x86_reg)step), "m" (c->pQPb), "r"(sums), "g"(src)
+ NAMED_CONSTRAINTS_ADD(w04)
+ );
+
+ src+= step; // src points to begin of the 8x8 Block
+
+ __asm__ volatile(
+ "movq %4, %%mm6 \n\t"
+ "pcmpeqb %%mm5, %%mm5 \n\t"
+ "pxor %%mm6, %%mm5 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+
+ "1: \n\t"
+ "movq (%1), %%mm0 \n\t"
+ "movq 8(%1), %%mm1 \n\t"
+ "paddw 32(%1), %%mm0 \n\t"
+ "paddw 40(%1), %%mm1 \n\t"
+ "movq (%0, %3), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t"
+ "punpckhbw %%mm7, %%mm3 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ "paddw %%mm3, %%mm1 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ "paddw %%mm3, %%mm1 \n\t"
+ "psrlw $4, %%mm0 \n\t"
+ "psrlw $4, %%mm1 \n\t"
+ "packuswb %%mm1, %%mm0 \n\t"
+ "pand %%mm6, %%mm0 \n\t"
+ "pand %%mm5, %%mm4 \n\t"
+ "por %%mm4, %%mm0 \n\t"
+ "movq %%mm0, (%0, %3) \n\t"
+ "add $16, %1 \n\t"
+ "add %2, %0 \n\t"
+ " js 1b \n\t"
+
+ : "+r"(offset), "+r"(temp_sums)
+ : "r" ((x86_reg)step), "r"(src - offset), "m"(both_masks)
+ );
+ }else
+ src+= step; // src points to begin of the 8x8 Block
+
+ if(eq_mask != -1LL){
+ uint8_t *temp_src= src;
+ DECLARE_ALIGNED(8, uint64_t, tmp)[4]; // make space for 4 8-byte vars
+ __asm__ volatile(
+ "pxor %%mm7, %%mm7 \n\t"
+// 0 1 2 3 4 5 6 7 8 9
+// %0 eax eax+%1 eax+2%1 %0+4%1 ecx ecx+%1 ecx+2%1 %1+8%1 ecx+4%1
+
+ "movq (%0), %%mm0 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t" // low part of line 0
+ "punpckhbw %%mm7, %%mm1 \n\t" // high part of line 0
+
+ "movq (%0, %1), %%mm2 \n\t"
+ "lea (%0, %1, 2), %%"REG_a" \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // low part of line 1
+ "punpckhbw %%mm7, %%mm3 \n\t" // high part of line 1
+
+ "movq (%%"REG_a"), %%mm4 \n\t"
+ "movq %%mm4, %%mm5 \n\t"
+ "punpcklbw %%mm7, %%mm4 \n\t" // low part of line 2
+ "punpckhbw %%mm7, %%mm5 \n\t" // high part of line 2
+
+ "paddw %%mm0, %%mm0 \n\t" // 2L0
+ "paddw %%mm1, %%mm1 \n\t" // 2H0
+ "psubw %%mm4, %%mm2 \n\t" // L1 - L2
+ "psubw %%mm5, %%mm3 \n\t" // H1 - H2
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - L1 + L2
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - H1 + H2
+
+ "psllw $2, %%mm2 \n\t" // 4L1 - 4L2
+ "psllw $2, %%mm3 \n\t" // 4H1 - 4H2
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - 5L1 + 5L2
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - 5H1 + 5H2
+
+ "movq (%%"REG_a", %1), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // L3
+ "punpckhbw %%mm7, %%mm3 \n\t" // H3
+
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - 5L1 + 5L2 - L3
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - 5H1 + 5H2 - H3
+ "psubw %%mm2, %%mm0 \n\t" // 2L0 - 5L1 + 5L2 - 2L3
+ "psubw %%mm3, %%mm1 \n\t" // 2H0 - 5H1 + 5H2 - 2H3
+ "movq %%mm0, (%4) \n\t" // 2L0 - 5L1 + 5L2 - 2L3
+ "movq %%mm1, 8(%4) \n\t" // 2H0 - 5H1 + 5H2 - 2H3
+
+ "movq (%%"REG_a", %1, 2), %%mm0 \n\t"
+ "movq %%mm0, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t" // L4
+ "punpckhbw %%mm7, %%mm1 \n\t" // H4
+
+ "psubw %%mm0, %%mm2 \n\t" // L3 - L4
+ "psubw %%mm1, %%mm3 \n\t" // H3 - H4
+ "movq %%mm2, 16(%4) \n\t" // L3 - L4
+ "movq %%mm3, 24(%4) \n\t" // H3 - H4
+ "paddw %%mm4, %%mm4 \n\t" // 2L2
+ "paddw %%mm5, %%mm5 \n\t" // 2H2
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - L3 + L4
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - H3 + H4
+
+ "lea (%%"REG_a", %1), %0 \n\t"
+ "psllw $2, %%mm2 \n\t" // 4L3 - 4L4
+ "psllw $2, %%mm3 \n\t" // 4H3 - 4H4
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - 5L3 + 5L4
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - 5H3 + 5H4
+//50 opcodes so far
+ "movq (%0, %1, 2), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // L5
+ "punpckhbw %%mm7, %%mm3 \n\t" // H5
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - 5L3 + 5L4 - L5
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - 5H3 + 5H4 - H5
+ "psubw %%mm2, %%mm4 \n\t" // 2L2 - 5L3 + 5L4 - 2L5
+ "psubw %%mm3, %%mm5 \n\t" // 2H2 - 5H3 + 5H4 - 2H5
+
+ "movq (%%"REG_a", %1, 4), %%mm6 \n\t"
+ "punpcklbw %%mm7, %%mm6 \n\t" // L6
+ "psubw %%mm6, %%mm2 \n\t" // L5 - L6
+ "movq (%%"REG_a", %1, 4), %%mm6 \n\t"
+ "punpckhbw %%mm7, %%mm6 \n\t" // H6
+ "psubw %%mm6, %%mm3 \n\t" // H5 - H6
+
+ "paddw %%mm0, %%mm0 \n\t" // 2L4
+ "paddw %%mm1, %%mm1 \n\t" // 2H4
+ "psubw %%mm2, %%mm0 \n\t" // 2L4 - L5 + L6
+ "psubw %%mm3, %%mm1 \n\t" // 2H4 - H5 + H6
+
+ "psllw $2, %%mm2 \n\t" // 4L5 - 4L6
+ "psllw $2, %%mm3 \n\t" // 4H5 - 4H6
+ "psubw %%mm2, %%mm0 \n\t" // 2L4 - 5L5 + 5L6
+ "psubw %%mm3, %%mm1 \n\t" // 2H4 - 5H5 + 5H6
+
+ "movq (%0, %1, 4), %%mm2 \n\t"
+ "movq %%mm2, %%mm3 \n\t"
+ "punpcklbw %%mm7, %%mm2 \n\t" // L7
+ "punpckhbw %%mm7, %%mm3 \n\t" // H7
+
+ "paddw %%mm2, %%mm2 \n\t" // 2L7
+ "paddw %%mm3, %%mm3 \n\t" // 2H7
+ "psubw %%mm2, %%mm0 \n\t" // 2L4 - 5L5 + 5L6 - 2L7
+ "psubw %%mm3, %%mm1 \n\t" // 2H4 - 5H5 + 5H6 - 2H7
+
+ "movq (%4), %%mm2 \n\t" // 2L0 - 5L1 + 5L2 - 2L3
+ "movq 8(%4), %%mm3 \n\t" // 2H0 - 5H1 + 5H2 - 2H3
+
+#if TEMPLATE_PP_MMXEXT
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm0, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm0 \n\t" // |2L4 - 5L5 + 5L6 - 2L7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm1, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm1 \n\t" // |2H4 - 5H5 + 5H6 - 2H7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm2, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm2 \n\t" // |2L0 - 5L1 + 5L2 - 2L3|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "psubw %%mm3, %%mm6 \n\t"
+ "pmaxsw %%mm6, %%mm3 \n\t" // |2H0 - 5H1 + 5H2 - 2H3|
+#else
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm0, %%mm6 \n\t"
+ "pxor %%mm6, %%mm0 \n\t"
+ "psubw %%mm6, %%mm0 \n\t" // |2L4 - 5L5 + 5L6 - 2L7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm1, %%mm6 \n\t"
+ "pxor %%mm6, %%mm1 \n\t"
+ "psubw %%mm6, %%mm1 \n\t" // |2H4 - 5H5 + 5H6 - 2H7|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm2, %%mm6 \n\t"
+ "pxor %%mm6, %%mm2 \n\t"
+ "psubw %%mm6, %%mm2 \n\t" // |2L0 - 5L1 + 5L2 - 2L3|
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm3, %%mm6 \n\t"
+ "pxor %%mm6, %%mm3 \n\t"
+ "psubw %%mm6, %%mm3 \n\t" // |2H0 - 5H1 + 5H2 - 2H3|
+#endif
+
+#if TEMPLATE_PP_MMXEXT
+ "pminsw %%mm2, %%mm0 \n\t"
+ "pminsw %%mm3, %%mm1 \n\t"
+#else
+ "movq %%mm0, %%mm6 \n\t"
+ "psubusw %%mm2, %%mm6 \n\t"
+ "psubw %%mm6, %%mm0 \n\t"
+ "movq %%mm1, %%mm6 \n\t"
+ "psubusw %%mm3, %%mm6 \n\t"
+ "psubw %%mm6, %%mm1 \n\t"
+#endif
+
+ "movd %2, %%mm2 \n\t" // QP
+ "punpcklbw %%mm7, %%mm2 \n\t"
+
+ "movq %%mm7, %%mm6 \n\t" // 0
+ "pcmpgtw %%mm4, %%mm6 \n\t" // sign(2L2 - 5L3 + 5L4 - 2L5)
+ "pxor %%mm6, %%mm4 \n\t"
+ "psubw %%mm6, %%mm4 \n\t" // |2L2 - 5L3 + 5L4 - 2L5|
+ "pcmpgtw %%mm5, %%mm7 \n\t" // sign(2H2 - 5H3 + 5H4 - 2H5)
+ "pxor %%mm7, %%mm5 \n\t"
+ "psubw %%mm7, %%mm5 \n\t" // |2H2 - 5H3 + 5H4 - 2H5|
+// 100 opcodes
+ "psllw $3, %%mm2 \n\t" // 8QP
+ "movq %%mm2, %%mm3 \n\t" // 8QP
+ "pcmpgtw %%mm4, %%mm2 \n\t"
+ "pcmpgtw %%mm5, %%mm3 \n\t"
+ "pand %%mm2, %%mm4 \n\t"
+ "pand %%mm3, %%mm5 \n\t"
+
+
+ "psubusw %%mm0, %%mm4 \n\t" // hd
+ "psubusw %%mm1, %%mm5 \n\t" // ld
+
+
+ "movq "MANGLE(w05)", %%mm2 \n\t" // 5
+ "pmullw %%mm2, %%mm4 \n\t"
+ "pmullw %%mm2, %%mm5 \n\t"
+ "movq "MANGLE(w20)", %%mm2 \n\t" // 32
+ "paddw %%mm2, %%mm4 \n\t"
+ "paddw %%mm2, %%mm5 \n\t"
+ "psrlw $6, %%mm4 \n\t"
+ "psrlw $6, %%mm5 \n\t"
+
+ "movq 16(%4), %%mm0 \n\t" // L3 - L4
+ "movq 24(%4), %%mm1 \n\t" // H3 - H4
+
+ "pxor %%mm2, %%mm2 \n\t"
+ "pxor %%mm3, %%mm3 \n\t"
+
+ "pcmpgtw %%mm0, %%mm2 \n\t" // sign (L3-L4)
+ "pcmpgtw %%mm1, %%mm3 \n\t" // sign (H3-H4)
+ "pxor %%mm2, %%mm0 \n\t"
+ "pxor %%mm3, %%mm1 \n\t"
+ "psubw %%mm2, %%mm0 \n\t" // |L3-L4|
+ "psubw %%mm3, %%mm1 \n\t" // |H3-H4|
+ "psrlw $1, %%mm0 \n\t" // |L3 - L4|/2
+ "psrlw $1, %%mm1 \n\t" // |H3 - H4|/2
+
+ "pxor %%mm6, %%mm2 \n\t"
+ "pxor %%mm7, %%mm3 \n\t"
+ "pand %%mm2, %%mm4 \n\t"
+ "pand %%mm3, %%mm5 \n\t"
+
+#if TEMPLATE_PP_MMXEXT
+ "pminsw %%mm0, %%mm4 \n\t"
+ "pminsw %%mm1, %%mm5 \n\t"
+#else
+ "movq %%mm4, %%mm2 \n\t"
+ "psubusw %%mm0, %%mm2 \n\t"
+ "psubw %%mm2, %%mm4 \n\t"
+ "movq %%mm5, %%mm2 \n\t"
+ "psubusw %%mm1, %%mm2 \n\t"
+ "psubw %%mm2, %%mm5 \n\t"
+#endif
+ "pxor %%mm6, %%mm4 \n\t"
+ "pxor %%mm7, %%mm5 \n\t"
+ "psubw %%mm6, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "packsswb %%mm5, %%mm4 \n\t"
+ "movq %3, %%mm1 \n\t"
+ "pandn %%mm4, %%mm1 \n\t"
+ "movq (%0), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq %%mm0, (%0) \n\t"
+ "movq (%0, %1), %%mm0 \n\t"
+ "psubb %%mm1, %%mm0 \n\t"
+ "movq %%mm0, (%0, %1) \n\t"
+
+ : "+r" (temp_src)
+ : "r" ((x86_reg)step), "m" (c->pQPb), "m"(eq_mask), "r"(tmp)
+ NAMED_CONSTRAINTS_ADD(w05,w20)
+ : "%"REG_a
+ );
+ }
+/*if(step==16){
+ STOP_TIMER("step16")
+}else{
+ STOP_TIMER("stepX")
+}
+ } */
+}
+#endif //TEMPLATE_PP_MMX
+
+static void RENAME(postProcess)(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
+ const QP_STORE_T QPs[], int QPStride, int isColor, PPContext *c);
+
+/**
+ * Copy a block from src to dst and fixes the blacklevel.
+ * levelFix == 0 -> do not touch the brightness & contrast
+ */
+#undef REAL_SCALED_CPY
+#undef SCALED_CPY
+
+static inline void RENAME(blockCopy)(uint8_t dst[], int dstStride, const uint8_t src[], int srcStride,
+ int levelFix, int64_t *packedOffsetAndScale)
+{
+#if !TEMPLATE_PP_MMX || !HAVE_6REGS
+ int i;
+#endif
+ if(levelFix){
+#if TEMPLATE_PP_MMX && HAVE_6REGS
+ __asm__ volatile(
+ "movq (%%"REG_a"), %%mm2 \n\t" // packedYOffset
+ "movq 8(%%"REG_a"), %%mm3 \n\t" // packedYScale
+ "lea (%2,%4), %%"REG_a" \n\t"
+ "lea (%3,%5), %%"REG_d" \n\t"
+ "pxor %%mm4, %%mm4 \n\t"
+#if TEMPLATE_PP_MMXEXT
+#define REAL_SCALED_CPY(src1, src2, dst1, dst2) \
+ "movq " #src1 ", %%mm0 \n\t"\
+ "movq " #src1 ", %%mm5 \n\t"\
+ "movq " #src2 ", %%mm1 \n\t"\
+ "movq " #src2 ", %%mm6 \n\t"\
+ "punpcklbw %%mm0, %%mm0 \n\t"\
+ "punpckhbw %%mm5, %%mm5 \n\t"\
+ "punpcklbw %%mm1, %%mm1 \n\t"\
+ "punpckhbw %%mm6, %%mm6 \n\t"\
+ "pmulhuw %%mm3, %%mm0 \n\t"\
+ "pmulhuw %%mm3, %%mm5 \n\t"\
+ "pmulhuw %%mm3, %%mm1 \n\t"\
+ "pmulhuw %%mm3, %%mm6 \n\t"\
+ "psubw %%mm2, %%mm0 \n\t"\
+ "psubw %%mm2, %%mm5 \n\t"\
+ "psubw %%mm2, %%mm1 \n\t"\
+ "psubw %%mm2, %%mm6 \n\t"\
+ "packuswb %%mm5, %%mm0 \n\t"\
+ "packuswb %%mm6, %%mm1 \n\t"\
+ "movq %%mm0, " #dst1 " \n\t"\
+ "movq %%mm1, " #dst2 " \n\t"\
+
+#else //TEMPLATE_PP_MMXEXT
+#define REAL_SCALED_CPY(src1, src2, dst1, dst2) \
+ "movq " #src1 ", %%mm0 \n\t"\
+ "movq " #src1 ", %%mm5 \n\t"\
+ "punpcklbw %%mm4, %%mm0 \n\t"\
+ "punpckhbw %%mm4, %%mm5 \n\t"\
+ "psubw %%mm2, %%mm0 \n\t"\
+ "psubw %%mm2, %%mm5 \n\t"\
+ "movq " #src2 ", %%mm1 \n\t"\
+ "psllw $6, %%mm0 \n\t"\
+ "psllw $6, %%mm5 \n\t"\
+ "pmulhw %%mm3, %%mm0 \n\t"\
+ "movq " #src2 ", %%mm6 \n\t"\
+ "pmulhw %%mm3, %%mm5 \n\t"\
+ "punpcklbw %%mm4, %%mm1 \n\t"\
+ "punpckhbw %%mm4, %%mm6 \n\t"\
+ "psubw %%mm2, %%mm1 \n\t"\
+ "psubw %%mm2, %%mm6 \n\t"\
+ "psllw $6, %%mm1 \n\t"\
+ "psllw $6, %%mm6 \n\t"\
+ "pmulhw %%mm3, %%mm1 \n\t"\
+ "pmulhw %%mm3, %%mm6 \n\t"\
+ "packuswb %%mm5, %%mm0 \n\t"\
+ "packuswb %%mm6, %%mm1 \n\t"\
+ "movq %%mm0, " #dst1 " \n\t"\
+ "movq %%mm1, " #dst2 " \n\t"\
+
+#endif //TEMPLATE_PP_MMXEXT
+#define SCALED_CPY(src1, src2, dst1, dst2)\
+ REAL_SCALED_CPY(src1, src2, dst1, dst2)
+
+SCALED_CPY((%2) , (%2, %4) , (%3) , (%3, %5))
+SCALED_CPY((%2, %4, 2), (%%REGa, %4, 2), (%3, %5, 2), (%%REGd, %5, 2))
+SCALED_CPY((%2, %4, 4), (%%REGa, %4, 4), (%3, %5, 4), (%%REGd, %5, 4))
+ "lea (%%"REG_a",%4,4), %%"REG_a" \n\t"
+ "lea (%%"REG_d",%5,4), %%"REG_d" \n\t"
+SCALED_CPY((%%REGa, %4), (%%REGa, %4, 2), (%%REGd, %5), (%%REGd, %5, 2))
+
+
+ : "=&a" (packedOffsetAndScale)
+ : "0" (packedOffsetAndScale),
+ "r"(src),
+ "r"(dst),
+ "r" ((x86_reg)srcStride),
+ "r" ((x86_reg)dstStride)
+ : "%"REG_d
+ );
+#else //TEMPLATE_PP_MMX && HAVE_6REGS
+ for(i=0; i<8; i++)
+ memcpy( &(dst[dstStride*i]),
+ &(src[srcStride*i]), BLOCK_SIZE);
+#endif //TEMPLATE_PP_MMX && HAVE_6REGS
+ }else{
+#if TEMPLATE_PP_MMX && HAVE_6REGS
+ __asm__ volatile(
+ "lea (%0,%2), %%"REG_a" \n\t"
+ "lea (%1,%3), %%"REG_d" \n\t"
+
+#define REAL_SIMPLE_CPY(src1, src2, dst1, dst2) \
+ "movq " #src1 ", %%mm0 \n\t"\
+ "movq " #src2 ", %%mm1 \n\t"\
+ "movq %%mm0, " #dst1 " \n\t"\
+ "movq %%mm1, " #dst2 " \n\t"\
+
+#define SIMPLE_CPY(src1, src2, dst1, dst2)\
+ REAL_SIMPLE_CPY(src1, src2, dst1, dst2)
+
+SIMPLE_CPY((%0) , (%0, %2) , (%1) , (%1, %3))
+SIMPLE_CPY((%0, %2, 2), (%%REGa, %2, 2), (%1, %3, 2), (%%REGd, %3, 2))
+SIMPLE_CPY((%0, %2, 4), (%%REGa, %2, 4), (%1, %3, 4), (%%REGd, %3, 4))
+ "lea (%%"REG_a",%2,4), %%"REG_a" \n\t"
+ "lea (%%"REG_d",%3,4), %%"REG_d" \n\t"
+SIMPLE_CPY((%%REGa, %2), (%%REGa, %2, 2), (%%REGd, %3), (%%REGd, %3, 2))
+
+ : : "r" (src),
+ "r" (dst),
+ "r" ((x86_reg)srcStride),
+ "r" ((x86_reg)dstStride)
+ : "%"REG_a, "%"REG_d
+ );
+#else //TEMPLATE_PP_MMX && HAVE_6REGS
+ for(i=0; i<8; i++)
+ memcpy( &(dst[dstStride*i]),
+ &(src[srcStride*i]), BLOCK_SIZE);
+#endif //TEMPLATE_PP_MMX && HAVE_6REGS
+ }
+}
+
+/**
+ * Duplicate the given 8 src pixels ? times upward
+ */
+static inline void RENAME(duplicate)(uint8_t src[], int stride)
+{
+#if TEMPLATE_PP_MMX
+ __asm__ volatile(
+ "movq (%0), %%mm0 \n\t"
+ "movq %%mm0, (%0, %1, 4) \n\t"
+ "add %1, %0 \n\t"
+ "movq %%mm0, (%0) \n\t"
+ "movq %%mm0, (%0, %1) \n\t"
+ "movq %%mm0, (%0, %1, 2) \n\t"
+ "movq %%mm0, (%0, %1, 4) \n\t"
+ : "+r" (src)
+ : "r" ((x86_reg)-stride)
+ );
+#else
+ int i;
+ uint8_t *p=src;
+ for(i=0; i<5; i++){
+ p-= stride;
+ memcpy(p, src, 8);
+ }
+#endif
+}
+
+#if ARCH_X86 && TEMPLATE_PP_MMXEXT
+static inline void RENAME(prefetchnta)(const void *p)
+{
+ __asm__ volatile( "prefetchnta (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void RENAME(prefetcht0)(const void *p)
+{
+ __asm__ volatile( "prefetcht0 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void RENAME(prefetcht1)(const void *p)
+{
+ __asm__ volatile( "prefetcht1 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+
+static inline void RENAME(prefetcht2)(const void *p)
+{
+ __asm__ volatile( "prefetcht2 (%0)\n\t"
+ : : "r" (p)
+ );
+}
+#elif !ARCH_X86 && AV_GCC_VERSION_AT_LEAST(3,2)
+static inline void RENAME(prefetchnta)(const void *p)
+{
+ __builtin_prefetch(p,0,0);
+}
+static inline void RENAME(prefetcht0)(const void *p)
+{
+ __builtin_prefetch(p,0,1);
+}
+static inline void RENAME(prefetcht1)(const void *p)
+{
+ __builtin_prefetch(p,0,2);
+}
+static inline void RENAME(prefetcht2)(const void *p)
+{
+ __builtin_prefetch(p,0,3);
+}
+#else
+static inline void RENAME(prefetchnta)(const void *p)
+{
+ return;
+}
+static inline void RENAME(prefetcht0)(const void *p)
+{
+ return;
+}
+static inline void RENAME(prefetcht1)(const void *p)
+{
+ return;
+}
+static inline void RENAME(prefetcht2)(const void *p)
+{
+ return;
+}
+#endif
+/**
+ * Filter array of bytes (Y or U or V values)
+ */
+static void RENAME(postProcess)(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
+ const QP_STORE_T QPs[], int QPStride, int isColor, PPContext *c2)
+{
+ DECLARE_ALIGNED(8, PPContext, c)= *c2; //copy to stack for faster access
+ int x,y;
+#ifdef TEMPLATE_PP_TIME_MODE
+ const int mode= TEMPLATE_PP_TIME_MODE;
+#else
+ const int mode= isColor ? c.ppMode.chromMode : c.ppMode.lumMode;
+#endif
+ int black=0, white=255; // blackest black and whitest white in the picture
+ int QPCorrecture= 256*256;
+
+ int copyAhead;
+#if TEMPLATE_PP_MMX
+ int i;
+#endif
+
+ const int qpHShift= isColor ? 4-c.hChromaSubSample : 4;
+ const int qpVShift= isColor ? 4-c.vChromaSubSample : 4;
+
+ //FIXME remove
+ uint64_t * const yHistogram= c.yHistogram;
+ uint8_t * const tempSrc= srcStride > 0 ? c.tempSrc : c.tempSrc - 23*srcStride;
+ uint8_t * const tempDst= (dstStride > 0 ? c.tempDst : c.tempDst - 23*dstStride) + 32;
+ //const int mbWidth= isColor ? (width+7)>>3 : (width+15)>>4;
+
+ if (mode & VISUALIZE){
+ if(!(mode & (V_A_DEBLOCK | H_A_DEBLOCK)) || TEMPLATE_PP_MMX) {
+ av_log(c2, AV_LOG_WARNING, "Visualization is currently only supported with the accurate deblock filter without SIMD\n");
+ }
+ }
+
+#if TEMPLATE_PP_MMX
+ for(i=0; i<57; i++){
+ int offset= ((i*c.ppMode.baseDcDiff)>>8) + 1;
+ int threshold= offset*2 + 1;
+ c.mmxDcOffset[i]= 0x7F - offset;
+ c.mmxDcThreshold[i]= 0x7F - threshold;
+ c.mmxDcOffset[i]*= 0x0101010101010101LL;
+ c.mmxDcThreshold[i]*= 0x0101010101010101LL;
+ }
+#endif
+
+ if(mode & CUBIC_IPOL_DEINT_FILTER) copyAhead=16;
+ else if( (mode & LINEAR_BLEND_DEINT_FILTER)
+ || (mode & FFMPEG_DEINT_FILTER)
+ || (mode & LOWPASS5_DEINT_FILTER)) copyAhead=14;
+ else if( (mode & V_DEBLOCK)
+ || (mode & LINEAR_IPOL_DEINT_FILTER)
+ || (mode & MEDIAN_DEINT_FILTER)
+ || (mode & V_A_DEBLOCK)) copyAhead=13;
+ else if(mode & V_X1_FILTER) copyAhead=11;
+// else if(mode & V_RK1_FILTER) copyAhead=10;
+ else if(mode & DERING) copyAhead=9;
+ else copyAhead=8;
+
+ copyAhead-= 8;
+
+ if(!isColor){
+ uint64_t sum= 0;
+ int i;
+ uint64_t maxClipped;
+ uint64_t clipped;
+ double scale;
+
+ c.frameNum++;
+ // first frame is fscked so we ignore it
+ if(c.frameNum == 1) yHistogram[0]= width*(uint64_t)height/64*15/256;
+
+ for(i=0; i<256; i++){
+ sum+= yHistogram[i];
+ }
+
+ /* We always get a completely black picture first. */
+ maxClipped= (uint64_t)(sum * c.ppMode.maxClippedThreshold);
+
+ clipped= sum;
+ for(black=255; black>0; black--){
+ if(clipped < maxClipped) break;
+ clipped-= yHistogram[black];
+ }
+
+ clipped= sum;
+ for(white=0; white<256; white++){
+ if(clipped < maxClipped) break;
+ clipped-= yHistogram[white];
+ }
+
+ scale= (double)(c.ppMode.maxAllowedY - c.ppMode.minAllowedY) / (double)(white-black);
+
+#if TEMPLATE_PP_MMXEXT
+ c.packedYScale= (uint16_t)(scale*256.0 + 0.5);
+ c.packedYOffset= (((black*c.packedYScale)>>8) - c.ppMode.minAllowedY) & 0xFFFF;
+#else
+ c.packedYScale= (uint16_t)(scale*1024.0 + 0.5);
+ c.packedYOffset= (black - c.ppMode.minAllowedY) & 0xFFFF;
+#endif
+
+ c.packedYOffset|= c.packedYOffset<<32;
+ c.packedYOffset|= c.packedYOffset<<16;
+
+ c.packedYScale|= c.packedYScale<<32;
+ c.packedYScale|= c.packedYScale<<16;
+
+ if(mode & LEVEL_FIX) QPCorrecture= (int)(scale*256*256 + 0.5);
+ else QPCorrecture= 256*256;
+ }else{
+ c.packedYScale= 0x0100010001000100LL;
+ c.packedYOffset= 0;
+ QPCorrecture= 256*256;
+ }
+
+ /* copy & deinterlace first row of blocks */
+ y=-BLOCK_SIZE;
+ {
+ const uint8_t *srcBlock= &(src[y*srcStride]);
+ uint8_t *dstBlock= tempDst + dstStride;
+
+ // From this point on it is guaranteed that we can read and write 16 lines downward
+ // finish 1 block before the next otherwise we might have a problem
+ // with the L1 Cache of the P4 ... or only a few blocks at a time or something
+ for(x=0; x<width; x+=BLOCK_SIZE){
+ RENAME(prefetchnta)(srcBlock + (((x>>2)&6) + copyAhead)*srcStride + 32);
+ RENAME(prefetchnta)(srcBlock + (((x>>2)&6) + copyAhead+1)*srcStride + 32);
+ RENAME(prefetcht0)(dstBlock + (((x>>2)&6) + copyAhead)*dstStride + 32);
+ RENAME(prefetcht0)(dstBlock + (((x>>2)&6) + copyAhead+1)*dstStride + 32);
+
+ RENAME(blockCopy)(dstBlock + dstStride*8, dstStride,
+ srcBlock + srcStride*8, srcStride, mode & LEVEL_FIX, &c.packedYOffset);
+
+ RENAME(duplicate)(dstBlock + dstStride*8, dstStride);
+
+ if(mode & LINEAR_IPOL_DEINT_FILTER)
+ RENAME(deInterlaceInterpolateLinear)(dstBlock, dstStride);
+ else if(mode & LINEAR_BLEND_DEINT_FILTER)
+ RENAME(deInterlaceBlendLinear)(dstBlock, dstStride, c.deintTemp + x);
+ else if(mode & MEDIAN_DEINT_FILTER)
+ RENAME(deInterlaceMedian)(dstBlock, dstStride);
+ else if(mode & CUBIC_IPOL_DEINT_FILTER)
+ RENAME(deInterlaceInterpolateCubic)(dstBlock, dstStride);
+ else if(mode & FFMPEG_DEINT_FILTER)
+ RENAME(deInterlaceFF)(dstBlock, dstStride, c.deintTemp + x);
+ else if(mode & LOWPASS5_DEINT_FILTER)
+ RENAME(deInterlaceL5)(dstBlock, dstStride, c.deintTemp + x, c.deintTemp + width + x);
+/* else if(mode & CUBIC_BLEND_DEINT_FILTER)
+ RENAME(deInterlaceBlendCubic)(dstBlock, dstStride);
+*/
+ dstBlock+=8;
+ srcBlock+=8;
+ }
+ if(width==FFABS(dstStride))
+ linecpy(dst, tempDst + 9*dstStride, copyAhead, dstStride);
+ else{
+ int i;
+ for(i=0; i<copyAhead; i++){
+ memcpy(dst + i*dstStride, tempDst + (9+i)*dstStride, width);
+ }
+ }
+ }
+
+ for(y=0; y<height; y+=BLOCK_SIZE){
+ //1% speedup if these are here instead of the inner loop
+ const uint8_t *srcBlock= &(src[y*srcStride]);
+ uint8_t *dstBlock= &(dst[y*dstStride]);
+#if TEMPLATE_PP_MMX
+ uint8_t *tempBlock1= c.tempBlocks;
+ uint8_t *tempBlock2= c.tempBlocks + 8;
+#endif
+ const int8_t *QPptr= &QPs[(y>>qpVShift)*QPStride];
+ int8_t *nonBQPptr= &c.nonBQPTable[(y>>qpVShift)*FFABS(QPStride)];
+ int QP=0, nonBQP=0;
+ /* can we mess with a 8x16 block from srcBlock/dstBlock downwards and 1 line upwards
+ if not than use a temporary buffer */
+ if(y+15 >= height){
+ int i;
+ /* copy from line (copyAhead) to (copyAhead+7) of src, these will be copied with
+ blockcopy to dst later */
+ linecpy(tempSrc + srcStride*copyAhead, srcBlock + srcStride*copyAhead,
+ FFMAX(height-y-copyAhead, 0), srcStride);
+
+ /* duplicate last line of src to fill the void up to line (copyAhead+7) */
+ for(i=FFMAX(height-y, 8); i<copyAhead+8; i++)
+ memcpy(tempSrc + srcStride*i, src + srcStride*(height-1), FFABS(srcStride));
+
+ /* copy up to (copyAhead+1) lines of dst (line -1 to (copyAhead-1))*/
+ linecpy(tempDst, dstBlock - dstStride, FFMIN(height-y+1, copyAhead+1), dstStride);
+
+ /* duplicate last line of dst to fill the void up to line (copyAhead) */
+ for(i=height-y+1; i<=copyAhead; i++)
+ memcpy(tempDst + dstStride*i, dst + dstStride*(height-1), FFABS(dstStride));
+
+ dstBlock= tempDst + dstStride;
+ srcBlock= tempSrc;
+ }
+
+ // From this point on it is guaranteed that we can read and write 16 lines downward
+ // finish 1 block before the next otherwise we might have a problem
+ // with the L1 Cache of the P4 ... or only a few blocks at a time or something
+ for(x=0; x<width; ){
+ int startx = x;
+ int endx = FFMIN(width, x+32);
+ uint8_t *dstBlockStart = dstBlock;
+ const uint8_t *srcBlockStart = srcBlock;
+ int qp_index = 0;
+ for(qp_index=0; qp_index < (endx-startx)/BLOCK_SIZE; qp_index++){
+ QP = QPptr[(x+qp_index*BLOCK_SIZE)>>qpHShift];
+ nonBQP = nonBQPptr[(x+qp_index*BLOCK_SIZE)>>qpHShift];
+ if(!isColor){
+ QP= (QP* QPCorrecture + 256*128)>>16;
+ nonBQP= (nonBQP* QPCorrecture + 256*128)>>16;
+ yHistogram[(srcBlock+qp_index*8)[srcStride*12 + 4]]++;
+ }
+ c.QP_block[qp_index] = QP;
+ c.nonBQP_block[qp_index] = nonBQP;
+#if TEMPLATE_PP_MMX
+ __asm__ volatile(
+ "movd %1, %%mm7 \n\t"
+ "packuswb %%mm7, %%mm7 \n\t" // 0, 0, 0, QP, 0, 0, 0, QP
+ "packuswb %%mm7, %%mm7 \n\t" // 0,QP, 0, QP, 0,QP, 0, QP
+ "packuswb %%mm7, %%mm7 \n\t" // QP,..., QP
+ "movq %%mm7, %0 \n\t"
+ : "=m" (c.pQPb_block[qp_index])
+ : "r" (QP)
+ );
+#endif
+ }
+ for(; x < endx; x+=BLOCK_SIZE){
+ RENAME(prefetchnta)(srcBlock + (((x>>2)&6) + copyAhead)*srcStride + 32);
+ RENAME(prefetchnta)(srcBlock + (((x>>2)&6) + copyAhead+1)*srcStride + 32);
+ RENAME(prefetcht0)(dstBlock + (((x>>2)&6) + copyAhead)*dstStride + 32);
+ RENAME(prefetcht0)(dstBlock + (((x>>2)&6) + copyAhead+1)*dstStride + 32);
+
+ RENAME(blockCopy)(dstBlock + dstStride*copyAhead, dstStride,
+ srcBlock + srcStride*copyAhead, srcStride, mode & LEVEL_FIX, &c.packedYOffset);
+
+ if(mode & LINEAR_IPOL_DEINT_FILTER)
+ RENAME(deInterlaceInterpolateLinear)(dstBlock, dstStride);
+ else if(mode & LINEAR_BLEND_DEINT_FILTER)
+ RENAME(deInterlaceBlendLinear)(dstBlock, dstStride, c.deintTemp + x);
+ else if(mode & MEDIAN_DEINT_FILTER)
+ RENAME(deInterlaceMedian)(dstBlock, dstStride);
+ else if(mode & CUBIC_IPOL_DEINT_FILTER)
+ RENAME(deInterlaceInterpolateCubic)(dstBlock, dstStride);
+ else if(mode & FFMPEG_DEINT_FILTER)
+ RENAME(deInterlaceFF)(dstBlock, dstStride, c.deintTemp + x);
+ else if(mode & LOWPASS5_DEINT_FILTER)
+ RENAME(deInterlaceL5)(dstBlock, dstStride, c.deintTemp + x, c.deintTemp + width + x);
+/* else if(mode & CUBIC_BLEND_DEINT_FILTER)
+ RENAME(deInterlaceBlendCubic)(dstBlock, dstStride);
+*/
+ dstBlock+=8;
+ srcBlock+=8;
+ }
+
+ dstBlock = dstBlockStart;
+ srcBlock = srcBlockStart;
+
+ for(x = startx, qp_index = 0; x < endx; x+=BLOCK_SIZE, qp_index++){
+ const int stride= dstStride;
+ //temporary while changing QP stuff to make things continue to work
+ //eventually QP,nonBQP,etc will be arrays and this will be unnecessary
+ c.QP = c.QP_block[qp_index];
+ c.nonBQP = c.nonBQP_block[qp_index];
+ c.pQPb = c.pQPb_block[qp_index];
+ c.pQPb2 = c.pQPb2_block[qp_index];
+
+ /* only deblock if we have 2 blocks */
+ if(y + 8 < height){
+ if(mode & V_X1_FILTER)
+ RENAME(vertX1Filter)(dstBlock, stride, &c);
+ else if(mode & V_DEBLOCK){
+ const int t= RENAME(vertClassify)(dstBlock, stride, &c);
+
+ if(t==1)
+ RENAME(doVertLowPass)(dstBlock, stride, &c);
+ else if(t==2)
+ RENAME(doVertDefFilter)(dstBlock, stride, &c);
+ }else if(mode & V_A_DEBLOCK){
+ RENAME(do_a_deblock)(dstBlock, stride, 1, &c, mode);
+ }
+ }
+
+ dstBlock+=8;
+ srcBlock+=8;
+ }
+
+ dstBlock = dstBlockStart;
+ srcBlock = srcBlockStart;
+
+ for(x = startx, qp_index=0; x < endx; x+=BLOCK_SIZE, qp_index++){
+ const int stride= dstStride;
+ av_unused uint8_t *tmpXchg;
+ c.QP = c.QP_block[qp_index];
+ c.nonBQP = c.nonBQP_block[qp_index];
+ c.pQPb = c.pQPb_block[qp_index];
+ c.pQPb2 = c.pQPb2_block[qp_index];
+#if TEMPLATE_PP_MMX
+ RENAME(transpose1)(tempBlock1, tempBlock2, dstBlock, dstStride);
+#endif
+ /* check if we have a previous block to deblock it with dstBlock */
+ if(x - 8 >= 0){
+#if TEMPLATE_PP_MMX
+ if(mode & H_X1_FILTER)
+ RENAME(vertX1Filter)(tempBlock1, 16, &c);
+ else if(mode & H_DEBLOCK){
+ const int t= RENAME(vertClassify)(tempBlock1, 16, &c);
+ if(t==1)
+ RENAME(doVertLowPass)(tempBlock1, 16, &c);
+ else if(t==2)
+ RENAME(doVertDefFilter)(tempBlock1, 16, &c);
+ }else if(mode & H_A_DEBLOCK){
+ RENAME(do_a_deblock)(tempBlock1, 16, 1, &c, mode);
+ }
+
+ RENAME(transpose2)(dstBlock-4, dstStride, tempBlock1 + 4*16);
+
+#else
+ if(mode & H_X1_FILTER)
+ horizX1Filter(dstBlock-4, stride, c.QP);
+ else if(mode & H_DEBLOCK){
+#if TEMPLATE_PP_ALTIVEC
+ DECLARE_ALIGNED(16, unsigned char, tempBlock)[272];
+ int t;
+ transpose_16x8_char_toPackedAlign_altivec(tempBlock, dstBlock - (4 + 1), stride);
+
+ t = vertClassify_altivec(tempBlock-48, 16, &c);
+ if(t==1) {
+ doVertLowPass_altivec(tempBlock-48, 16, &c);
+ transpose_8x16_char_fromPackedAlign_altivec(dstBlock - (4 + 1), tempBlock, stride);
+ }
+ else if(t==2) {
+ doVertDefFilter_altivec(tempBlock-48, 16, &c);
+ transpose_8x16_char_fromPackedAlign_altivec(dstBlock - (4 + 1), tempBlock, stride);
+ }
+#else
+ const int t= RENAME(horizClassify)(dstBlock-4, stride, &c);
+
+ if(t==1)
+ RENAME(doHorizLowPass)(dstBlock-4, stride, &c);
+ else if(t==2)
+ RENAME(doHorizDefFilter)(dstBlock-4, stride, &c);
+#endif
+ }else if(mode & H_A_DEBLOCK){
+ RENAME(do_a_deblock)(dstBlock-8, 1, stride, &c, mode);
+ }
+#endif //TEMPLATE_PP_MMX
+ if(mode & DERING){
+ //FIXME filter first line
+ if(y>0) RENAME(dering)(dstBlock - stride - 8, stride, &c);
+ }
+
+ if(mode & TEMP_NOISE_FILTER)
+ {
+ RENAME(tempNoiseReducer)(dstBlock-8, stride,
+ c.tempBlurred[isColor] + y*dstStride + x,
+ c.tempBlurredPast[isColor] + (y>>3)*256 + (x>>3) + 256,
+ c.ppMode.maxTmpNoise);
+ }
+ }
+
+ dstBlock+=8;
+ srcBlock+=8;
+
+#if TEMPLATE_PP_MMX
+ tmpXchg= tempBlock1;
+ tempBlock1= tempBlock2;
+ tempBlock2 = tmpXchg;
+#endif
+ }
+ }
+
+ if(mode & DERING){
+ if(y > 0) RENAME(dering)(dstBlock - dstStride - 8, dstStride, &c);
+ }
+
+ if((mode & TEMP_NOISE_FILTER)){
+ RENAME(tempNoiseReducer)(dstBlock-8, dstStride,
+ c.tempBlurred[isColor] + y*dstStride + x,
+ c.tempBlurredPast[isColor] + (y>>3)*256 + (x>>3) + 256,
+ c.ppMode.maxTmpNoise);
+ }
+
+ /* did we use a tmp buffer for the last lines*/
+ if(y+15 >= height){
+ uint8_t *dstBlock= &(dst[y*dstStride]);
+ if(width==FFABS(dstStride))
+ linecpy(dstBlock, tempDst + dstStride, height-y, dstStride);
+ else{
+ int i;
+ for(i=0; i<height-y; i++){
+ memcpy(dstBlock + i*dstStride, tempDst + (i+1)*dstStride, width);
+ }
+ }
+ }
+ }
+#if TEMPLATE_PP_3DNOW
+ __asm__ volatile("femms");
+#elif TEMPLATE_PP_MMX
+ __asm__ volatile("emms");
+#endif
+
+#ifdef DEBUG_BRIGHTNESS
+ if(!isColor){
+ int max=1;
+ int i;
+ for(i=0; i<256; i++)
+ if(yHistogram[i] > max) max=yHistogram[i];
+
+ for(i=1; i<256; i++){
+ int x;
+ int start=yHistogram[i-1]/(max/256+1);
+ int end=yHistogram[i]/(max/256+1);
+ int inc= end > start ? 1 : -1;
+ for(x=start; x!=end+inc; x+=inc)
+ dst[ i*dstStride + x]+=128;
+ }
+
+ for(i=0; i<100; i+=2){
+ dst[ (white)*dstStride + i]+=128;
+ dst[ (black)*dstStride + i]+=128;
+ }
+ }
+#endif
+
+ *c2= c; //copy local context back
+
+}
+
+#undef RENAME
+#undef TEMPLATE_PP_C
+#undef TEMPLATE_PP_ALTIVEC
+#undef TEMPLATE_PP_MMX
+#undef TEMPLATE_PP_MMXEXT
+#undef TEMPLATE_PP_3DNOW
+#undef TEMPLATE_PP_SSE2
diff --git a/libpostproc/postprocres.rc b/libpostproc/postprocres.rc
new file mode 100644
index 0000000000..e6104ac88b
--- /dev/null
+++ b/libpostproc/postprocres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libpostproc
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libpostproc/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBPOSTPROC_VERSION_MAJOR, LIBPOSTPROC_VERSION_MINOR, LIBPOSTPROC_VERSION_MICRO, 0
+PRODUCTVERSION LIBPOSTPROC_VERSION_MAJOR, LIBPOSTPROC_VERSION_MINOR, LIBPOSTPROC_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg postprocessing library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBPOSTPROC_VERSION)
+ VALUE "InternalName", "libpostproc"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "postproc" BUILDSUF "-" AV_STRINGIFY(LIBPOSTPROC_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libpostproc/version.h b/libpostproc/version.h
new file mode 100644
index 0000000000..59c24660f8
--- /dev/null
+++ b/libpostproc/version.h
@@ -0,0 +1,45 @@
+/*
+ * Version macros.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef POSTPROC_POSTPROCESS_VERSION_H
+#define POSTPROC_POSTPROCESS_VERSION_H
+
+/**
+ * @file
+ * Libpostproc version macros
+ */
+
+#include "libavutil/avutil.h"
+
+#define LIBPOSTPROC_VERSION_MAJOR 53
+#define LIBPOSTPROC_VERSION_MINOR 3
+#define LIBPOSTPROC_VERSION_MICRO 100
+
+#define LIBPOSTPROC_VERSION_INT AV_VERSION_INT(LIBPOSTPROC_VERSION_MAJOR, \
+ LIBPOSTPROC_VERSION_MINOR, \
+ LIBPOSTPROC_VERSION_MICRO)
+#define LIBPOSTPROC_VERSION AV_VERSION(LIBPOSTPROC_VERSION_MAJOR, \
+ LIBPOSTPROC_VERSION_MINOR, \
+ LIBPOSTPROC_VERSION_MICRO)
+#define LIBPOSTPROC_BUILD LIBPOSTPROC_VERSION_INT
+
+#define LIBPOSTPROC_IDENT "postproc" AV_STRINGIFY(LIBPOSTPROC_VERSION)
+
+#endif /* POSTPROC_POSTPROCESS_VERSION_H */
diff --git a/library.mak b/library.mak
index 3da14b6abb..e23abd2251 100644
--- a/library.mak
+++ b/library.mak
@@ -22,13 +22,17 @@ $(SUBDIR)%-test.i: $(SUBDIR)%-test.c
$(SUBDIR)%-test.i: $(SUBDIR)%.c
$(CC) $(CCFLAGS) $(CC_E) $<
-$(SUBDIR)x86/%.o: $(SUBDIR)x86/%.asm
+$(SUBDIR)x86/%$(DEFAULT_YASMD).asm: $(SUBDIR)x86/%.asm
+ $(DEPYASM) $(YASMFLAGS) -I $(<D)/ -M -o $@ $< > $(@:.asm=.d)
+ $(YASM) $(YASMFLAGS) -I $(<D)/ -e $< | sed '/^%/d;/^$$/d;' > $@
+
+$(SUBDIR)x86/%.o: $(SUBDIR)x86/%$(YASMD).asm
$(DEPYASM) $(YASMFLAGS) -I $(<D)/ -M -o $@ $< > $(@:.o=.d)
$(YASM) $(YASMFLAGS) -I $(<D)/ -o $@ $<
- -$(STRIP) $(STRIPFLAGS) $@
+ -$(if $(ASMSTRIPFLAGS), $(STRIP) $(ASMSTRIPFLAGS) $@)
LIBOBJS := $(OBJS) $(SUBDIR)%.h.o $(TESTOBJS)
-$(LIBOBJS) $(LIBOBJS:.o=.i): CPPFLAGS += -DHAVE_AV_CONFIG_H
+$(LIBOBJS) $(LIBOBJS:.o=.s) $(LIBOBJS:.o=.i): CPPFLAGS += -DHAVE_AV_CONFIG_H
$(TESTOBJS) $(TESTOBJS:.o=.i): CPPFLAGS += -DTEST
$(SUBDIR)$(LIBNAME): $(OBJS)
@@ -51,11 +55,15 @@ $(TESTPROGS) $(TOOLS): %$(EXESUF): %.o $(EXEOBJS)
$(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR)
$(Q)cd ./$(SUBDIR) && $(LN_S) $(SLIBNAME_WITH_MAJOR) $(SLIBNAME)
-$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SUBDIR)lib$(NAME).ver $(DEP_LIBS)
+$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver
$(SLIB_CREATE_DEF_CMD)
$$(LD) $(SHFLAGS) $(LDFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS)
$(SLIB_EXTRA_CMD)
+ifdef SUBDIR
+$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(DEP_LIBS)
+endif
+
clean::
$(RM) $(addprefix $(SUBDIR),*-test$(EXESUF) $(CLEANFILES) $(CLEANSUFFIXES) $(LIBSUFFIXES)) \
$(CLEANSUFFIXES:%=$(SUBDIR)$(ARCH)/%)
@@ -66,7 +74,8 @@ distclean:: clean
install-lib$(NAME)-shared: $(SUBDIR)$(SLIBNAME)
$(Q)mkdir -p "$(SHLIBDIR)"
$$(INSTALL) -m 755 $$< "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)"
- $(Q)$(foreach F,$(SLIB_INSTALL_LINKS),cd "$(SHLIBDIR)" && $(LN_S) $(SLIB_INSTALL_NAME) $(F);)
+ $$(STRIP) "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)"
+ $(Q)$(foreach F,$(SLIB_INSTALL_LINKS),(cd "$(SHLIBDIR)" && $(LN_S) $(SLIB_INSTALL_NAME) $(F));)
$(if $(SLIB_INSTALL_EXTRA_SHLIB),$$(INSTALL) -m 644 $(SLIB_INSTALL_EXTRA_SHLIB:%=$(SUBDIR)%) "$(SHLIBDIR)")
$(if $(SLIB_INSTALL_EXTRA_LIB),$(Q)mkdir -p "$(LIBDIR)")
$(if $(SLIB_INSTALL_EXTRA_LIB),$$(INSTALL) -m 644 $(SLIB_INSTALL_EXTRA_LIB:%=$(SUBDIR)%) "$(LIBDIR)")
@@ -80,7 +89,7 @@ install-lib$(NAME)-headers: $(addprefix $(SUBDIR),$(HEADERS) $(BUILT_HEADERS))
$(Q)mkdir -p "$(INCINSTDIR)"
$$(INSTALL) -m 644 $$^ "$(INCINSTDIR)"
-install-lib$(NAME)-pkgconfig: $(SUBDIR)lib$(NAME).pc
+install-lib$(NAME)-pkgconfig: $(SUBDIR)lib$(FULLNAME).pc
$(Q)mkdir -p "$(LIBDIR)/pkgconfig"
$$(INSTALL) -m 644 $$^ "$(LIBDIR)/pkgconfig"
@@ -88,13 +97,13 @@ uninstall-libs::
-$(RM) "$(SHLIBDIR)/$(SLIBNAME_WITH_MAJOR)" \
"$(SHLIBDIR)/$(SLIBNAME)" \
"$(SHLIBDIR)/$(SLIBNAME_WITH_VERSION)"
- -$(RM) $(SLIB_INSTALL_EXTRA_SHLIB:%="$(SHLIBDIR)"%)
- -$(RM) $(SLIB_INSTALL_EXTRA_LIB:%="$(LIBDIR)"%)
+ -$(RM) $(SLIB_INSTALL_EXTRA_SHLIB:%="$(SHLIBDIR)/%")
+ -$(RM) $(SLIB_INSTALL_EXTRA_LIB:%="$(LIBDIR)/%")
-$(RM) "$(LIBDIR)/$(LIBNAME)"
uninstall-headers::
$(RM) $(addprefix "$(INCINSTDIR)/",$(HEADERS) $(BUILT_HEADERS))
- $(RM) "$(LIBDIR)/pkgconfig/lib$(NAME).pc"
+ $(RM) "$(LIBDIR)/pkgconfig/lib$(FULLNAME).pc"
-rmdir "$(INCINSTDIR)"
endef
diff --git a/libswresample/Makefile b/libswresample/Makefile
new file mode 100644
index 0000000000..120ee3385d
--- /dev/null
+++ b/libswresample/Makefile
@@ -0,0 +1,24 @@
+include $(SUBDIR)../config.mak
+
+NAME = swresample
+FFLIBS = avutil
+
+HEADERS = swresample.h \
+ version.h \
+
+OBJS = audioconvert.o \
+ dither.o \
+ options.o \
+ rematrix.o \
+ resample.o \
+ resample_dsp.o \
+ swresample.o \
+ swresample_frame.o \
+
+OBJS-$(CONFIG_LIBSOXR) += soxr_resample.o
+OBJS-$(CONFIG_SHARED) += log2_tab.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += swresampleres.o
+
+TESTPROGS = swresample
diff --git a/libswresample/aarch64/Makefile b/libswresample/aarch64/Makefile
new file mode 100644
index 0000000000..320ed67e82
--- /dev/null
+++ b/libswresample/aarch64/Makefile
@@ -0,0 +1,5 @@
+OBJS += aarch64/audio_convert_init.o
+
+OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o
+
+NEON-OBJS += aarch64/audio_convert_neon.o
diff --git a/libswresample/aarch64/audio_convert_init.c b/libswresample/aarch64/audio_convert_init.c
new file mode 100644
index 0000000000..60e24adb1c
--- /dev/null
+++ b/libswresample/aarch64/audio_convert_init.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of libswresample.
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/aarch64/cpu.h"
+#include "libavutil/samplefmt.h"
+#include "libswresample/swresample_internal.h"
+#include "libswresample/audioconvert.h"
+
+void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len);
+void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels);
+void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels);
+
+static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){
+ swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len);
+}
+
+static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){
+ swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2);
+}
+
+static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){
+ int channels;
+ for(channels=3; channels<SWR_CH_MAX && src[channels]; channels++)
+ ;
+ swri_oldapi_conv_fltp_to_s16_nch_neon((int16_t*)*dst, (float *const*)src, len, channels);
+}
+
+av_cold void swri_audio_convert_init_aarch64(struct AudioConvert *ac,
+ enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ ac->simd_f= NULL;
+
+ if (have_neon(cpu_flags)) {
+ if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = conv_flt_to_s16_neon;
+ if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2)
+ ac->simd_f = conv_fltp_to_s16_2ch_neon;
+ if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels > 2)
+ ac->simd_f = conv_fltp_to_s16_nch_neon;
+ if(ac->simd_f)
+ ac->in_simd_align_mask = ac->out_simd_align_mask = 15;
+ }
+}
diff --git a/libswresample/aarch64/audio_convert_neon.S b/libswresample/aarch64/audio_convert_neon.S
new file mode 100644
index 0000000000..74feff448a
--- /dev/null
+++ b/libswresample/aarch64/audio_convert_neon.S
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ * Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/aarch64/asm.S"
+
+function swri_oldapi_conv_flt_to_s16_neon, export=1
+ subs x2, x2, #8
+ ld1 {v0.4s}, [x1], #16
+ fcvtzs v4.4s, v0.4s, #31
+ ld1 {v1.4s}, [x1], #16
+ fcvtzs v5.4s, v1.4s, #31
+ b.eq 3f
+ ands x12, x2, #~15
+ b.eq 2f
+1: subs x12, x12, #16
+ sqrshrn v4.4h, v4.4s, #16
+ ld1 {v2.4s}, [x1], #16
+ fcvtzs v6.4s, v2.4s, #31
+ sqrshrn2 v4.8h, v5.4s, #16
+ ld1 {v3.4s}, [x1], #16
+ fcvtzs v7.4s, v3.4s, #31
+ sqrshrn v6.4h, v6.4s, #16
+ st1 {v4.8h}, [x0], #16
+ sqrshrn2 v6.8h, v7.4s, #16
+ ld1 {v0.4s}, [x1], #16
+ fcvtzs v4.4s, v0.4s, #31
+ ld1 {v1.4s}, [x1], #16
+ fcvtzs v5.4s, v1.4s, #31
+ st1 {v6.8h}, [x0], #16
+ b.ne 1b
+ ands x2, x2, #15
+ b.eq 3f
+2: ld1 {v2.4s}, [x1], #16
+ sqrshrn v4.4h, v4.4s, #16
+ fcvtzs v6.4s, v2.4s, #31
+ ld1 {v3.4s}, [x1], #16
+ sqrshrn2 v4.8h, v5.4s, #16
+ fcvtzs v7.4s, v3.4s, #31
+ sqrshrn v6.4h, v6.4s, #16
+ st1 {v4.8h}, [x0], #16
+ sqrshrn2 v6.8h, v7.4s, #16
+ st1 {v6.8h}, [x0]
+ ret
+3: sqrshrn v4.4h, v4.4s, #16
+ sqrshrn2 v4.8h, v5.4s, #16
+ st1 {v4.8h}, [x0]
+ ret
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_2ch_neon, export=1
+ ldp x4, x5, [x1]
+ subs x2, x2, #8
+ ld1 {v0.4s}, [x4], #16
+ fcvtzs v4.4s, v0.4s, #31
+ ld1 {v1.4s}, [x4], #16
+ fcvtzs v5.4s, v1.4s, #31
+ ld1 {v2.4s}, [x5], #16
+ fcvtzs v6.4s, v2.4s, #31
+ ld1 {v3.4s}, [x5], #16
+ fcvtzs v7.4s, v3.4s, #31
+ b.eq 3f
+ ands x12, x2, #~15
+ b.eq 2f
+1: subs x12, x12, #16
+ ld1 {v16.4s}, [x4], #16
+ fcvtzs v20.4s, v16.4s, #31
+ sri v6.4s, v4.4s, #16
+ ld1 {v17.4s}, [x4], #16
+ fcvtzs v21.4s, v17.4s, #31
+ ld1 {v18.4s}, [x5], #16
+ fcvtzs v22.4s, v18.4s, #31
+ ld1 {v19.4s}, [x5], #16
+ sri v7.4s, v5.4s, #16
+ st1 {v6.4s}, [x0], #16
+ fcvtzs v23.4s, v19.4s, #31
+ st1 {v7.4s}, [x0], #16
+ sri v22.4s, v20.4s, #16
+ ld1 {v0.4s}, [x4], #16
+ sri v23.4s, v21.4s, #16
+ st1 {v22.4s}, [x0], #16
+ fcvtzs v4.4s, v0.4s, #31
+ ld1 {v1.4s}, [x4], #16
+ fcvtzs v5.4s, v1.4s, #31
+ ld1 {v2.4s}, [x5], #16
+ fcvtzs v6.4s, v2.4s, #31
+ ld1 {v3.4s}, [x5], #16
+ fcvtzs v7.4s, v3.4s, #31
+ st1 {v23.4s}, [x0], #16
+ b.ne 1b
+ ands x2, x2, #15
+ b.eq 3f
+2: sri v6.4s, v4.4s, #16
+ ld1 {v0.4s}, [x4], #16
+ fcvtzs v0.4s, v0.4s, #31
+ ld1 {v1.4s}, [x4], #16
+ fcvtzs v1.4s, v1.4s, #31
+ ld1 {v2.4s}, [x5], #16
+ fcvtzs v2.4s, v2.4s, #31
+ sri v7.4s, v5.4s, #16
+ ld1 {v3.4s}, [x5], #16
+ fcvtzs v3.4s, v3.4s, #31
+ sri v2.4s, v0.4s, #16
+ st1 {v6.4s,v7.4s}, [x0], #32
+ sri v3.4s, v1.4s, #16
+ st1 {v2.4s,v3.4s}, [x0], #32
+ ret
+3: sri v6.4s, v4.4s, #16
+ sri v7.4s, v5.4s, #16
+ st1 {v6.4s,v7.4s}, [x0]
+ ret
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_nch_neon, export=1
+ cmp w3, #2
+ b.eq X(swri_oldapi_conv_fltp_to_s16_2ch_neon)
+ b.gt 1f
+ ldr x1, [x1]
+ b X(swri_oldapi_conv_flt_to_s16_neon)
+1:
+ cmp w3, #4
+ lsl x12, x3, #1
+ b.lt 4f
+
+5: // 4 channels
+ ldp x4, x5, [x1], #16
+ ldp x6, x7, [x1], #16
+ mov w9, w2
+ mov x8, x0
+ ld1 {v4.4s}, [x4], #16
+ fcvtzs v4.4s, v4.4s, #31
+ ld1 {v5.4s}, [x5], #16
+ fcvtzs v5.4s, v5.4s, #31
+ ld1 {v6.4s}, [x6], #16
+ fcvtzs v6.4s, v6.4s, #31
+ ld1 {v7.4s}, [x7], #16
+ fcvtzs v7.4s, v7.4s, #31
+6:
+ subs w9, w9, #8
+ ld1 {v0.4s}, [x4], #16
+ fcvtzs v0.4s, v0.4s, #31
+ sri v5.4s, v4.4s, #16
+ ld1 {v1.4s}, [x5], #16
+ fcvtzs v1.4s, v1.4s, #31
+ sri v7.4s, v6.4s, #16
+ ld1 {v2.4s}, [x6], #16
+ fcvtzs v2.4s, v2.4s, #31
+ zip1 v16.4s, v5.4s, v7.4s
+ ld1 {v3.4s}, [x7], #16
+ fcvtzs v3.4s, v3.4s, #31
+ zip2 v17.4s, v5.4s, v7.4s
+ st1 {v16.d}[0], [x8], x12
+ sri v1.4s, v0.4s, #16
+ st1 {v16.d}[1], [x8], x12
+ sri v3.4s, v2.4s, #16
+ st1 {v17.d}[0], [x8], x12
+ zip1 v18.4s, v1.4s, v3.4s
+ st1 {v17.d}[1], [x8], x12
+ zip2 v19.4s, v1.4s, v3.4s
+ b.eq 7f
+ ld1 {v4.4s}, [x4], #16
+ fcvtzs v4.4s, v4.4s, #31
+ st1 {v18.d}[0], [x8], x12
+ ld1 {v5.4s}, [x5], #16
+ fcvtzs v5.4s, v5.4s, #31
+ st1 {v18.d}[1], [x8], x12
+ ld1 {v6.4s}, [x6], #16
+ fcvtzs v6.4s, v6.4s, #31
+ st1 {v19.d}[0], [x8], x12
+ ld1 {v7.4s}, [x7], #16
+ fcvtzs v7.4s, v7.4s, #31
+ st1 {v19.d}[1], [x8], x12
+ b 6b
+7:
+ st1 {v18.d}[0], [x8], x12
+ st1 {v18.d}[1], [x8], x12
+ st1 {v19.d}[0], [x8], x12
+ st1 {v19.d}[1], [x8], x12
+ subs w3, w3, #4
+ b.eq end
+ cmp w3, #4
+ add x0, x0, #8
+ b.ge 5b
+
+4: // 2 channels
+ cmp w3, #2
+ b.lt 4f
+ ldp x4, x5, [x1], #16
+ mov w9, w2
+ mov x8, x0
+ tst w9, #8
+ ld1 {v4.4s}, [x4], #16
+ fcvtzs v4.4s, v4.4s, #31
+ ld1 {v5.4s}, [x5], #16
+ fcvtzs v5.4s, v5.4s, #31
+ ld1 {v6.4s}, [x4], #16
+ fcvtzs v6.4s, v6.4s, #31
+ ld1 {v7.4s}, [x5], #16
+ fcvtzs v7.4s, v7.4s, #31
+ b.eq 6f
+ subs w9, w9, #8
+ b.eq 7f
+ sri v5.4s, v4.4s, #16
+ ld1 {v4.4s}, [x4], #16
+ fcvtzs v4.4s, v4.4s, #31
+ st1 {v5.s}[0], [x8], x12
+ sri v7.4s, v6.4s, #16
+ st1 {v5.s}[1], [x8], x12
+ ld1 {v6.4s}, [x4], #16
+ fcvtzs v6.4s, v6.4s, #31
+ st1 {v5.s}[2], [x8], x12
+ st1 {v5.s}[3], [x8], x12
+ st1 {v7.s}[0], [x8], x12
+ st1 {v7.s}[1], [x8], x12
+ ld1 {v5.4s}, [x5], #16
+ fcvtzs v5.4s, v5.4s, #31
+ st1 {v7.s}[2], [x8], x12
+ st1 {v7.s}[3], [x8], x12
+ ld1 {v7.4s}, [x5], #16
+ fcvtzs v7.4s, v7.4s, #31
+6:
+ subs w9, w9, #16
+ ld1 {v0.4s}, [x4], #16
+ sri v5.4s, v4.4s, #16
+ fcvtzs v0.4s, v0.4s, #31
+ ld1 {v1.4s}, [x5], #16
+ sri v7.4s, v6.4s, #16
+ st1 {v5.s}[0], [x8], x12
+ st1 {v5.s}[1], [x8], x12
+ fcvtzs v1.4s, v1.4s, #31
+ st1 {v5.s}[2], [x8], x12
+ st1 {v5.s}[3], [x8], x12
+ ld1 {v2.4s}, [x4], #16
+ st1 {v7.s}[0], [x8], x12
+ fcvtzs v2.4s, v2.4s, #31
+ st1 {v7.s}[1], [x8], x12
+ ld1 {v3.4s}, [x5], #16
+ st1 {v7.s}[2], [x8], x12
+ fcvtzs v3.4s, v3.4s, #31
+ st1 {v7.s}[3], [x8], x12
+ sri v1.4s, v0.4s, #16
+ sri v3.4s, v2.4s, #16
+ b.eq 6f
+ ld1 {v4.4s}, [x4], #16
+ st1 {v1.s}[0], [x8], x12
+ fcvtzs v4.4s, v4.4s, #31
+ st1 {v1.s}[1], [x8], x12
+ ld1 {v5.4s}, [x5], #16
+ st1 {v1.s}[2], [x8], x12
+ fcvtzs v5.4s, v5.4s, #31
+ st1 {v1.s}[3], [x8], x12
+ ld1 {v6.4s}, [x4], #16
+ st1 {v3.s}[0], [x8], x12
+ fcvtzs v6.4s, v6.4s, #31
+ st1 {v3.s}[1], [x8], x12
+ ld1 {v7.4s}, [x5], #16
+ st1 {v3.s}[2], [x8], x12
+ fcvtzs v7.4s, v7.4s, #31
+ st1 {v3.s}[3], [x8], x12
+ b.gt 6b
+6:
+ st1 {v1.s}[0], [x8], x12
+ st1 {v1.s}[1], [x8], x12
+ st1 {v1.s}[2], [x8], x12
+ st1 {v1.s}[3], [x8], x12
+ st1 {v3.s}[0], [x8], x12
+ st1 {v3.s}[1], [x8], x12
+ st1 {v3.s}[2], [x8], x12
+ st1 {v3.s}[3], [x8], x12
+ b 8f
+7:
+ sri v5.4s, v4.4s, #16
+ sri v7.4s, v6.4s, #16
+ st1 {v5.s}[0], [x8], x12
+ st1 {v5.s}[1], [x8], x12
+ st1 {v5.s}[2], [x8], x12
+ st1 {v5.s}[3], [x8], x12
+ st1 {v7.s}[0], [x8], x12
+ st1 {v7.s}[1], [x8], x12
+ st1 {v7.s}[2], [x8], x12
+ st1 {v7.s}[3], [x8], x12
+8:
+ subs w3, w3, #2
+ add x0, x0, #4
+ b.eq end
+
+4: // 1 channel
+ ldr x4, [x1]
+ tst w2, #8
+ mov w9, w2
+ mov x5, x0
+ ld1 {v0.4s}, [x4], #16
+ fcvtzs v0.4s, v0.4s, #31
+ ld1 {v1.4s}, [x4], #16
+ fcvtzs v1.4s, v1.4s, #31
+ b.ne 8f
+6:
+ subs w9, w9, #16
+ ld1 {v2.4s}, [x4], #16
+ fcvtzs v2.4s, v2.4s, #31
+ ld1 {v3.4s}, [x4], #16
+ fcvtzs v3.4s, v3.4s, #31
+ st1 {v0.h}[1], [x5], x12
+ st1 {v0.h}[3], [x5], x12
+ st1 {v0.h}[5], [x5], x12
+ st1 {v0.h}[7], [x5], x12
+ st1 {v1.h}[1], [x5], x12
+ st1 {v1.h}[3], [x5], x12
+ st1 {v1.h}[5], [x5], x12
+ st1 {v1.h}[7], [x5], x12
+ b.eq 7f
+ ld1 {v0.4s}, [x4], #16
+ fcvtzs v0.4s, v0.4s, #31
+ ld1 {v1.4s}, [x4], #16
+ fcvtzs v1.4s, v1.4s, #31
+7:
+ st1 {v2.h}[1], [x5], x12
+ st1 {v2.h}[3], [x5], x12
+ st1 {v2.h}[5], [x5], x12
+ st1 {v2.h}[7], [x5], x12
+ st1 {v3.h}[1], [x5], x12
+ st1 {v3.h}[3], [x5], x12
+ st1 {v3.h}[5], [x5], x12
+ st1 {v3.h}[7], [x5], x12
+ b.gt 6b
+ ret
+8:
+ subs w9, w9, #8
+ st1 {v0.h}[1], [x5], x12
+ st1 {v0.h}[3], [x5], x12
+ st1 {v0.h}[5], [x5], x12
+ st1 {v0.h}[7], [x5], x12
+ st1 {v1.h}[1], [x5], x12
+ st1 {v1.h}[3], [x5], x12
+ st1 {v1.h}[5], [x5], x12
+ st1 {v1.h}[7], [x5], x12
+ b.eq end
+ ld1 {v0.4s}, [x4], #16
+ fcvtzs v0.4s, v0.4s, #31
+ ld1 {v1.4s}, [x4], #16
+ fcvtzs v1.4s, v1.4s, #31
+ b 6b
+end:
+ ret
+endfunc
diff --git a/libswresample/aarch64/neontest.c b/libswresample/aarch64/neontest.c
new file mode 100644
index 0000000000..85c71bf4c9
--- /dev/null
+++ b/libswresample/aarch64/neontest.c
@@ -0,0 +1,29 @@
+/*
+ * check NEON registers for clobbers
+ * Copyright (c) 2013 Martin Storsjo
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libswresample/swresample.h"
+#include "libavutil/aarch64/neontest.h"
+
+wrap(swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
+ const uint8_t **in , int in_count))
+{
+ testneonclobbers(swr_convert, s, out, out_count, in, in_count);
+}
diff --git a/libswresample/arm/Makefile b/libswresample/arm/Makefile
new file mode 100644
index 0000000000..60f3f6d6b8
--- /dev/null
+++ b/libswresample/arm/Makefile
@@ -0,0 +1,5 @@
+OBJS += arm/audio_convert_init.o
+
+OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o
+
+NEON-OBJS += arm/audio_convert_neon.o
diff --git a/libswresample/arm/audio_convert_init.c b/libswresample/arm/audio_convert_init.c
new file mode 100644
index 0000000000..ec9e62ede7
--- /dev/null
+++ b/libswresample/arm/audio_convert_init.c
@@ -0,0 +1,67 @@
+/*
+ * This file is part of libswresample.
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/arm/cpu.h"
+#include "libavutil/samplefmt.h"
+#include "libswresample/swresample_internal.h"
+#include "libswresample/audioconvert.h"
+
+void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len);
+void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels);
+void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels);
+
+static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){
+ swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len);
+}
+
+static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){
+ swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2);
+}
+
+static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){
+ int channels;
+ for(channels=3; channels<SWR_CH_MAX && src[channels]; channels++)
+ ;
+ swri_oldapi_conv_fltp_to_s16_nch_neon((int16_t*)*dst, (float *const*)src, len, channels);
+}
+
+av_cold void swri_audio_convert_init_arm(struct AudioConvert *ac,
+ enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels)
+{
+ int cpu_flags = av_get_cpu_flags();
+
+ ac->simd_f= NULL;
+
+ if (have_neon(cpu_flags)) {
+ if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = conv_flt_to_s16_neon;
+ if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2)
+ ac->simd_f = conv_fltp_to_s16_2ch_neon;
+ if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels > 2)
+ ac->simd_f = conv_fltp_to_s16_nch_neon;
+ if(ac->simd_f)
+ ac->in_simd_align_mask = ac->out_simd_align_mask = 15;
+ }
+}
diff --git a/libswresample/arm/audio_convert_neon.S b/libswresample/arm/audio_convert_neon.S
new file mode 100644
index 0000000000..1f88316dde
--- /dev/null
+++ b/libswresample/arm/audio_convert_neon.S
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ *
+ * This file is part of libswresample.
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "libavutil/arm/asm.S"
+
+function swri_oldapi_conv_flt_to_s16_neon, export=1
+ subs r2, r2, #8
+ vld1.32 {q0}, [r1,:128]!
+ vcvt.s32.f32 q8, q0, #31
+ vld1.32 {q1}, [r1,:128]!
+ vcvt.s32.f32 q9, q1, #31
+ beq 3f
+ bics r12, r2, #15
+ beq 2f
+1: subs r12, r12, #16
+ vqrshrn.s32 d4, q8, #16
+ vld1.32 {q0}, [r1,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vqrshrn.s32 d5, q9, #16
+ vld1.32 {q1}, [r1,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ vqrshrn.s32 d6, q0, #16
+ vst1.16 {q2}, [r0,:128]!
+ vqrshrn.s32 d7, q1, #16
+ vld1.32 {q8}, [r1,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vld1.32 {q9}, [r1,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vst1.16 {q3}, [r0,:128]!
+ bne 1b
+ ands r2, r2, #15
+ beq 3f
+2: vld1.32 {q0}, [r1,:128]!
+ vqrshrn.s32 d4, q8, #16
+ vcvt.s32.f32 q0, q0, #31
+ vld1.32 {q1}, [r1,:128]!
+ vqrshrn.s32 d5, q9, #16
+ vcvt.s32.f32 q1, q1, #31
+ vqrshrn.s32 d6, q0, #16
+ vst1.16 {q2}, [r0,:128]!
+ vqrshrn.s32 d7, q1, #16
+ vst1.16 {q3}, [r0,:128]!
+ bx lr
+3: vqrshrn.s32 d4, q8, #16
+ vqrshrn.s32 d5, q9, #16
+ vst1.16 {q2}, [r0,:128]!
+ bx lr
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_2ch_neon, export=1
+ ldm r1, {r1, r3}
+ subs r2, r2, #8
+ vld1.32 {q0}, [r1,:128]!
+ vcvt.s32.f32 q8, q0, #31
+ vld1.32 {q1}, [r1,:128]!
+ vcvt.s32.f32 q9, q1, #31
+ vld1.32 {q10}, [r3,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vld1.32 {q11}, [r3,:128]!
+ vcvt.s32.f32 q11, q11, #31
+ beq 3f
+ bics r12, r2, #15
+ beq 2f
+1: subs r12, r12, #16
+ vld1.32 {q0}, [r1,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vsri.32 q10, q8, #16
+ vld1.32 {q1}, [r1,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ vld1.32 {q12}, [r3,:128]!
+ vcvt.s32.f32 q12, q12, #31
+ vld1.32 {q13}, [r3,:128]!
+ vsri.32 q11, q9, #16
+ vst1.16 {q10}, [r0,:128]!
+ vcvt.s32.f32 q13, q13, #31
+ vst1.16 {q11}, [r0,:128]!
+ vsri.32 q12, q0, #16
+ vld1.32 {q8}, [r1,:128]!
+ vsri.32 q13, q1, #16
+ vst1.16 {q12}, [r0,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vld1.32 {q9}, [r1,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vld1.32 {q10}, [r3,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vld1.32 {q11}, [r3,:128]!
+ vcvt.s32.f32 q11, q11, #31
+ vst1.16 {q13}, [r0,:128]!
+ bne 1b
+ ands r2, r2, #15
+ beq 3f
+2: vsri.32 q10, q8, #16
+ vld1.32 {q0}, [r1,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vld1.32 {q1}, [r1,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ vld1.32 {q12}, [r3,:128]!
+ vcvt.s32.f32 q12, q12, #31
+ vsri.32 q11, q9, #16
+ vld1.32 {q13}, [r3,:128]!
+ vcvt.s32.f32 q13, q13, #31
+ vst1.16 {q10}, [r0,:128]!
+ vsri.32 q12, q0, #16
+ vst1.16 {q11}, [r0,:128]!
+ vsri.32 q13, q1, #16
+ vst1.16 {q12-q13},[r0,:128]!
+ bx lr
+3: vsri.32 q10, q8, #16
+ vsri.32 q11, q9, #16
+ vst1.16 {q10-q11},[r0,:128]!
+ bx lr
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_nch_neon, export=1
+ cmp r3, #2
+ itt lt
+ ldrlt r1, [r1]
+ blt X(swri_oldapi_conv_flt_to_s16_neon)
+ beq X(swri_oldapi_conv_fltp_to_s16_2ch_neon)
+
+ push {r4-r8, lr}
+ cmp r3, #4
+ lsl r12, r3, #1
+ blt 4f
+
+ @ 4 channels
+5: ldm r1!, {r4-r7}
+ mov lr, r2
+ mov r8, r0
+ vld1.32 {q8}, [r4,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vld1.32 {q9}, [r5,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vld1.32 {q10}, [r6,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vld1.32 {q11}, [r7,:128]!
+ vcvt.s32.f32 q11, q11, #31
+6: subs lr, lr, #8
+ vld1.32 {q0}, [r4,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vsri.32 q9, q8, #16
+ vld1.32 {q1}, [r5,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ vsri.32 q11, q10, #16
+ vld1.32 {q2}, [r6,:128]!
+ vcvt.s32.f32 q2, q2, #31
+ vzip.32 d18, d22
+ vld1.32 {q3}, [r7,:128]!
+ vcvt.s32.f32 q3, q3, #31
+ vzip.32 d19, d23
+ vst1.16 {d18}, [r8], r12
+ vsri.32 q1, q0, #16
+ vst1.16 {d22}, [r8], r12
+ vsri.32 q3, q2, #16
+ vst1.16 {d19}, [r8], r12
+ vzip.32 d2, d6
+ vst1.16 {d23}, [r8], r12
+ vzip.32 d3, d7
+ beq 7f
+ vld1.32 {q8}, [r4,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vst1.16 {d2}, [r8], r12
+ vld1.32 {q9}, [r5,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vst1.16 {d6}, [r8], r12
+ vld1.32 {q10}, [r6,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vst1.16 {d3}, [r8], r12
+ vld1.32 {q11}, [r7,:128]!
+ vcvt.s32.f32 q11, q11, #31
+ vst1.16 {d7}, [r8], r12
+ b 6b
+7: vst1.16 {d2}, [r8], r12
+ vst1.16 {d6}, [r8], r12
+ vst1.16 {d3}, [r8], r12
+ vst1.16 {d7}, [r8], r12
+ subs r3, r3, #4
+ it eq
+ popeq {r4-r8, pc}
+ cmp r3, #4
+ add r0, r0, #8
+ bge 5b
+
+ @ 2 channels
+4: cmp r3, #2
+ blt 4f
+ ldm r1!, {r4-r5}
+ mov lr, r2
+ mov r8, r0
+ tst lr, #8
+ vld1.32 {q8}, [r4,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vld1.32 {q9}, [r5,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vld1.32 {q10}, [r4,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vld1.32 {q11}, [r5,:128]!
+ vcvt.s32.f32 q11, q11, #31
+ beq 6f
+ subs lr, lr, #8
+ beq 7f
+ vsri.32 d18, d16, #16
+ vsri.32 d19, d17, #16
+ vld1.32 {q8}, [r4,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vst1.32 {d18[0]}, [r8], r12
+ vsri.32 d22, d20, #16
+ vst1.32 {d18[1]}, [r8], r12
+ vsri.32 d23, d21, #16
+ vst1.32 {d19[0]}, [r8], r12
+ vst1.32 {d19[1]}, [r8], r12
+ vld1.32 {q9}, [r5,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vst1.32 {d22[0]}, [r8], r12
+ vst1.32 {d22[1]}, [r8], r12
+ vld1.32 {q10}, [r4,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vst1.32 {d23[0]}, [r8], r12
+ vst1.32 {d23[1]}, [r8], r12
+ vld1.32 {q11}, [r5,:128]!
+ vcvt.s32.f32 q11, q11, #31
+6: subs lr, lr, #16
+ vld1.32 {q0}, [r4,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vsri.32 d18, d16, #16
+ vld1.32 {q1}, [r5,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ vsri.32 d19, d17, #16
+ vld1.32 {q2}, [r4,:128]!
+ vcvt.s32.f32 q2, q2, #31
+ vld1.32 {q3}, [r5,:128]!
+ vcvt.s32.f32 q3, q3, #31
+ vst1.32 {d18[0]}, [r8], r12
+ vsri.32 d22, d20, #16
+ vst1.32 {d18[1]}, [r8], r12
+ vsri.32 d23, d21, #16
+ vst1.32 {d19[0]}, [r8], r12
+ vsri.32 d2, d0, #16
+ vst1.32 {d19[1]}, [r8], r12
+ vsri.32 d3, d1, #16
+ vst1.32 {d22[0]}, [r8], r12
+ vsri.32 d6, d4, #16
+ vst1.32 {d22[1]}, [r8], r12
+ vsri.32 d7, d5, #16
+ vst1.32 {d23[0]}, [r8], r12
+ vst1.32 {d23[1]}, [r8], r12
+ beq 6f
+ vld1.32 {q8}, [r4,:128]!
+ vcvt.s32.f32 q8, q8, #31
+ vst1.32 {d2[0]}, [r8], r12
+ vst1.32 {d2[1]}, [r8], r12
+ vld1.32 {q9}, [r5,:128]!
+ vcvt.s32.f32 q9, q9, #31
+ vst1.32 {d3[0]}, [r8], r12
+ vst1.32 {d3[1]}, [r8], r12
+ vld1.32 {q10}, [r4,:128]!
+ vcvt.s32.f32 q10, q10, #31
+ vst1.32 {d6[0]}, [r8], r12
+ vst1.32 {d6[1]}, [r8], r12
+ vld1.32 {q11}, [r5,:128]!
+ vcvt.s32.f32 q11, q11, #31
+ vst1.32 {d7[0]}, [r8], r12
+ vst1.32 {d7[1]}, [r8], r12
+ bgt 6b
+6: vst1.32 {d2[0]}, [r8], r12
+ vst1.32 {d2[1]}, [r8], r12
+ vst1.32 {d3[0]}, [r8], r12
+ vst1.32 {d3[1]}, [r8], r12
+ vst1.32 {d6[0]}, [r8], r12
+ vst1.32 {d6[1]}, [r8], r12
+ vst1.32 {d7[0]}, [r8], r12
+ vst1.32 {d7[1]}, [r8], r12
+ b 8f
+7: vsri.32 d18, d16, #16
+ vsri.32 d19, d17, #16
+ vst1.32 {d18[0]}, [r8], r12
+ vsri.32 d22, d20, #16
+ vst1.32 {d18[1]}, [r8], r12
+ vsri.32 d23, d21, #16
+ vst1.32 {d19[0]}, [r8], r12
+ vst1.32 {d19[1]}, [r8], r12
+ vst1.32 {d22[0]}, [r8], r12
+ vst1.32 {d22[1]}, [r8], r12
+ vst1.32 {d23[0]}, [r8], r12
+ vst1.32 {d23[1]}, [r8], r12
+8: subs r3, r3, #2
+ add r0, r0, #4
+ it eq
+ popeq {r4-r8, pc}
+
+ @ 1 channel
+4: ldr r4, [r1]
+ tst r2, #8
+ mov lr, r2
+ mov r5, r0
+ vld1.32 {q0}, [r4,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vld1.32 {q1}, [r4,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ bne 8f
+6: subs lr, lr, #16
+ vld1.32 {q2}, [r4,:128]!
+ vcvt.s32.f32 q2, q2, #31
+ vld1.32 {q3}, [r4,:128]!
+ vcvt.s32.f32 q3, q3, #31
+ vst1.16 {d0[1]}, [r5,:16], r12
+ vst1.16 {d0[3]}, [r5,:16], r12
+ vst1.16 {d1[1]}, [r5,:16], r12
+ vst1.16 {d1[3]}, [r5,:16], r12
+ vst1.16 {d2[1]}, [r5,:16], r12
+ vst1.16 {d2[3]}, [r5,:16], r12
+ vst1.16 {d3[1]}, [r5,:16], r12
+ vst1.16 {d3[3]}, [r5,:16], r12
+ beq 7f
+ vld1.32 {q0}, [r4,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vld1.32 {q1}, [r4,:128]!
+ vcvt.s32.f32 q1, q1, #31
+7: vst1.16 {d4[1]}, [r5,:16], r12
+ vst1.16 {d4[3]}, [r5,:16], r12
+ vst1.16 {d5[1]}, [r5,:16], r12
+ vst1.16 {d5[3]}, [r5,:16], r12
+ vst1.16 {d6[1]}, [r5,:16], r12
+ vst1.16 {d6[3]}, [r5,:16], r12
+ vst1.16 {d7[1]}, [r5,:16], r12
+ vst1.16 {d7[3]}, [r5,:16], r12
+ bgt 6b
+ pop {r4-r8, pc}
+8: subs lr, lr, #8
+ vst1.16 {d0[1]}, [r5,:16], r12
+ vst1.16 {d0[3]}, [r5,:16], r12
+ vst1.16 {d1[1]}, [r5,:16], r12
+ vst1.16 {d1[3]}, [r5,:16], r12
+ vst1.16 {d2[1]}, [r5,:16], r12
+ vst1.16 {d2[3]}, [r5,:16], r12
+ vst1.16 {d3[1]}, [r5,:16], r12
+ vst1.16 {d3[3]}, [r5,:16], r12
+ it eq
+ popeq {r4-r8, pc}
+ vld1.32 {q0}, [r4,:128]!
+ vcvt.s32.f32 q0, q0, #31
+ vld1.32 {q1}, [r4,:128]!
+ vcvt.s32.f32 q1, q1, #31
+ b 6b
+endfunc
diff --git a/libswresample/arm/neontest.c b/libswresample/arm/neontest.c
new file mode 100644
index 0000000000..2abbbc2367
--- /dev/null
+++ b/libswresample/arm/neontest.c
@@ -0,0 +1,29 @@
+/*
+ * check NEON registers for clobbers
+ * Copyright (c) 2013 Martin Storsjo
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libswresample/swresample.h"
+#include "libavutil/arm/neontest.h"
+
+wrap(swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
+ const uint8_t **in , int in_count))
+{
+ testneonclobbers(swr_convert, s, out, out_count, in, in_count);
+}
diff --git a/libswresample/audioconvert.c b/libswresample/audioconvert.c
new file mode 100644
index 0000000000..58b0bf33e9
--- /dev/null
+++ b/libswresample/audioconvert.c
@@ -0,0 +1,225 @@
+/*
+ * audio conversion
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio conversion
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "libavutil/avstring.h"
+#include "libavutil/avassert.h"
+#include "libavutil/libm.h"
+#include "libavutil/samplefmt.h"
+#include "audioconvert.h"
+
+
+#define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt
+
+//FIXME rounding ?
+#define CONV_FUNC(ofmt, otype, ifmt, expr)\
+static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\
+{\
+ uint8_t *end2 = end - 3*os;\
+ while(po < end2){\
+ *(otype*)po = expr; pi += is; po += os;\
+ *(otype*)po = expr; pi += is; po += os;\
+ *(otype*)po = expr; pi += is; po += os;\
+ *(otype*)po = expr; pi += is; po += os;\
+ }\
+ while(po < end){\
+ *(otype*)po = expr; pi += is; po += os;\
+ }\
+}
+
+//FIXME put things below under ifdefs so we do not waste space for cases no codec will need
+CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi)
+CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80U)<<8)
+CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80U)<<24)
+CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0f/ (1<<7)))
+CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7)))
+CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80)
+CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi)
+CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16)
+CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0f/ (1<<15)))
+CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15)))
+CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80)
+CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16)
+CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi)
+CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0f/ (1U<<31)))
+CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31)))
+CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80))
+CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15))))
+CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31))))
+CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi)
+CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi)
+CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80))
+CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15))))
+CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31))))
+CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi)
+CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi)
+
+#define FMT_PAIR_FUNC(out, in) [(out) + AV_SAMPLE_FMT_NB*(in)] = CONV_FUNC_NAME(out, in)
+
+static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAMPLE_FMT_NB] = {
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_U8 ),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8 ),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8 ),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8 ),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8 ),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S16),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S32),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_FLT),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_DBL),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL),
+ FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL),
+};
+
+static void cpy1(uint8_t **dst, const uint8_t **src, int len){
+ memcpy(*dst, *src, len);
+}
+static void cpy2(uint8_t **dst, const uint8_t **src, int len){
+ memcpy(*dst, *src, 2*len);
+}
+static void cpy4(uint8_t **dst, const uint8_t **src, int len){
+ memcpy(*dst, *src, 4*len);
+}
+static void cpy8(uint8_t **dst, const uint8_t **src, int len){
+ memcpy(*dst, *src, 8*len);
+}
+
+AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels, const int *ch_map,
+ int flags)
+{
+ AudioConvert *ctx;
+ conv_func_type *f = fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt) + AV_SAMPLE_FMT_NB*av_get_packed_sample_fmt(in_fmt)];
+
+ if (!f)
+ return NULL;
+ ctx = av_mallocz(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+
+ if(channels == 1){
+ in_fmt = av_get_planar_sample_fmt( in_fmt);
+ out_fmt = av_get_planar_sample_fmt(out_fmt);
+ }
+
+ ctx->channels = channels;
+ ctx->conv_f = f;
+ ctx->ch_map = ch_map;
+ if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P)
+ memset(ctx->silence, 0x80, sizeof(ctx->silence));
+
+ if(out_fmt == in_fmt && !ch_map) {
+ switch(av_get_bytes_per_sample(in_fmt)){
+ case 1:ctx->simd_f = cpy1; break;
+ case 2:ctx->simd_f = cpy2; break;
+ case 4:ctx->simd_f = cpy4; break;
+ case 8:ctx->simd_f = cpy8; break;
+ }
+ }
+
+ if(HAVE_YASM && HAVE_MMX) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels);
+ if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels);
+ if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels);
+
+ return ctx;
+}
+
+void swri_audio_convert_free(AudioConvert **ctx)
+{
+ av_freep(ctx);
+}
+
+int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len)
+{
+ int ch;
+ int off=0;
+ const int os= (out->planar ? 1 :out->ch_count) *out->bps;
+ unsigned misaligned = 0;
+
+ av_assert0(ctx->channels == out->ch_count);
+
+ if (ctx->in_simd_align_mask) {
+ int planes = in->planar ? in->ch_count : 1;
+ unsigned m = 0;
+ for (ch = 0; ch < planes; ch++)
+ m |= (intptr_t)in->ch[ch];
+ misaligned |= m & ctx->in_simd_align_mask;
+ }
+ if (ctx->out_simd_align_mask) {
+ int planes = out->planar ? out->ch_count : 1;
+ unsigned m = 0;
+ for (ch = 0; ch < planes; ch++)
+ m |= (intptr_t)out->ch[ch];
+ misaligned |= m & ctx->out_simd_align_mask;
+ }
+
+ //FIXME optimize common cases
+
+ if(ctx->simd_f && !ctx->ch_map && !misaligned){
+ off = len&~15;
+ av_assert1(off>=0);
+ av_assert1(off<=len);
+ av_assert2(ctx->channels == SWR_CH_MAX || !in->ch[ctx->channels]);
+ if(off>0){
+ if(out->planar == in->planar){
+ int planes = out->planar ? out->ch_count : 1;
+ for(ch=0; ch<planes; ch++){
+ ctx->simd_f(out->ch+ch, (const uint8_t **)in->ch+ch, off * (out->planar ? 1 :out->ch_count));
+ }
+ }else{
+ ctx->simd_f(out->ch, (const uint8_t **)in->ch, off);
+ }
+ }
+ if(off == len)
+ return 0;
+ }
+
+ for(ch=0; ch<ctx->channels; ch++){
+ const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch;
+ const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps;
+ const uint8_t *pi= ich < 0 ? ctx->silence : in->ch[ich];
+ uint8_t *po= out->ch[ch];
+ uint8_t *end= po + os*len;
+ if(!po)
+ continue;
+ ctx->conv_f(po+off*os, pi+off*is, is, os, end);
+ }
+ return 0;
+}
diff --git a/libswresample/audioconvert.h b/libswresample/audioconvert.h
new file mode 100644
index 0000000000..2e983df286
--- /dev/null
+++ b/libswresample/audioconvert.h
@@ -0,0 +1,78 @@
+/*
+ * audio conversion
+ * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (c) 2008 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SWR_AUDIOCONVERT_H
+#define SWR_AUDIOCONVERT_H
+
+/**
+ * @file
+ * Audio format conversion routines
+ */
+
+
+#include "swresample_internal.h"
+#include "libavutil/cpu.h"
+
+
+typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end);
+typedef void (simd_func_type)(uint8_t **dst, const uint8_t **src, int len);
+
+typedef struct AudioConvert {
+ int channels;
+ int in_simd_align_mask;
+ int out_simd_align_mask;
+ conv_func_type *conv_f;
+ simd_func_type *simd_f;
+ const int *ch_map;
+ uint8_t silence[8]; ///< silence input sample
+}AudioConvert;
+
+/**
+ * Create an audio sample format converter context
+ * @param out_fmt Output sample format
+ * @param in_fmt Input sample format
+ * @param channels Number of channels
+ * @param flags See AV_CPU_FLAG_xx
+ * @param ch_map list of the channels id to pick from the source stream, NULL
+ * if all channels must be selected
+ * @return NULL on error
+ */
+AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels, const int *ch_map,
+ int flags);
+
+/**
+ * Free audio sample format converter context.
+ * and set the pointer to NULL
+ */
+void swri_audio_convert_free(AudioConvert **ctx);
+
+/**
+ * Convert between audio sample formats
+ * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel.
+ * @param[in] in array of input buffers for each channel
+ * @param len length of audio frame size (measured in samples)
+ */
+int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len);
+
+#endif /* AUDIOCONVERT_H */
diff --git a/libswresample/dither.c b/libswresample/dither.c
new file mode 100644
index 0000000000..ca09e67f4d
--- /dev/null
+++ b/libswresample/dither.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2012-2013 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/avassert.h"
+#include "swresample_internal.h"
+
+#include "noise_shaping_data.c"
+
+void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt) {
+ double scale = s->dither.noise_scale;
+#define TMP_EXTRA 2
+ double *tmp = av_malloc_array(len + TMP_EXTRA, sizeof(double));
+ int i;
+
+ for(i=0; i<len + TMP_EXTRA; i++){
+ double v;
+ seed = seed* 1664525 + 1013904223;
+
+ switch(s->dither.method){
+ case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break;
+ default:
+ av_assert0(s->dither.method < SWR_DITHER_NB);
+ v = ((double)seed) / UINT_MAX;
+ seed = seed*1664525 + 1013904223;
+ v-= ((double)seed) / UINT_MAX;
+ break;
+ }
+ tmp[i] = v;
+ }
+
+ for(i=0; i<len; i++){
+ double v;
+
+ switch(s->dither.method){
+ default:
+ av_assert0(s->dither.method < SWR_DITHER_NB);
+ v = tmp[i];
+ break;
+ case SWR_DITHER_TRIANGULAR_HIGHPASS :
+ v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6);
+ break;
+ }
+
+ v*= scale;
+
+ switch(noise_fmt){
+ case AV_SAMPLE_FMT_S16P: ((int16_t*)dst)[i] = v; break;
+ case AV_SAMPLE_FMT_S32P: ((int32_t*)dst)[i] = v; break;
+ case AV_SAMPLE_FMT_FLTP: ((float *)dst)[i] = v; break;
+ case AV_SAMPLE_FMT_DBLP: ((double *)dst)[i] = v; break;
+ default: av_assert0(0);
+ }
+ }
+
+ av_free(tmp);
+}
+
+av_cold int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt)
+{
+ int i;
+ double scale = 0;
+
+ if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS)
+ return AVERROR(EINVAL);
+
+ out_fmt = av_get_packed_sample_fmt(out_fmt);
+ in_fmt = av_get_packed_sample_fmt( in_fmt);
+
+ if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){
+ if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1LL<<31);
+ if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1LL<<15);
+ if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1LL<< 7);
+ }
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S32 && (s->dither.output_sample_bits&31)) scale = 1;
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1<<16;
+ if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<24;
+ if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<8;
+
+ scale *= s->dither.scale;
+
+ if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits)
+ scale *= 1<<(32-s->dither.output_sample_bits);
+
+ s->dither.ns_pos = 0;
+ s->dither.noise_scale= scale;
+ s->dither.ns_scale = scale;
+ s->dither.ns_scale_1 = scale ? 1/scale : 0;
+ memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors));
+ for (i=0; filters[i].coefs; i++) {
+ const filter_t *f = &filters[i];
+ if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither.method) {
+ int j;
+ s->dither.ns_taps = f->len;
+ for (j=0; j<f->len; j++)
+ s->dither.ns_coeffs[j] = f->coefs[j];
+ s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt)));
+ break;
+ }
+ }
+ if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) {
+ av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n");
+ s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS;
+ }
+
+ av_assert0(!s->preout.count);
+ s->dither.noise = s->preout;
+ s->dither.temp = s->preout;
+ if (s->dither.method > SWR_DITHER_NS) {
+ s->dither.noise.bps = 4;
+ s->dither.noise.fmt = AV_SAMPLE_FMT_FLTP;
+ s->dither.noise_scale = 1;
+ }
+
+ return 0;
+}
+
+#define TEMPLATE_DITHER_S16
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_S16
+
+#define TEMPLATE_DITHER_S32
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_S32
+
+#define TEMPLATE_DITHER_FLT
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_FLT
+
+#define TEMPLATE_DITHER_DBL
+#include "dither_template.c"
+#undef TEMPLATE_DITHER_DBL
diff --git a/libswresample/dither_template.c b/libswresample/dither_template.c
new file mode 100644
index 0000000000..1e35dfb040
--- /dev/null
+++ b/libswresample/dither_template.c
@@ -0,0 +1,67 @@
+
+#if defined(TEMPLATE_DITHER_DBL)
+# define RENAME(N) N ## _double
+# define DELEM double
+# define CLIP(v) while(0)
+
+#elif defined(TEMPLATE_DITHER_FLT)
+# define RENAME(N) N ## _float
+# define DELEM float
+# define CLIP(v) while(0)
+
+#elif defined(TEMPLATE_DITHER_S32)
+# define RENAME(N) N ## _int32
+# define DELEM int32_t
+# define CLIP(v) v = FFMAX(FFMIN(v, INT32_MAX), INT32_MIN)
+
+#elif defined(TEMPLATE_DITHER_S16)
+# define RENAME(N) N ## _int16
+# define DELEM int16_t
+# define CLIP(v) v = FFMAX(FFMIN(v, INT16_MAX), INT16_MIN)
+
+#else
+ERROR
+#endif
+
+void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count){
+ int pos = s->dither.ns_pos;
+ int i, j, ch;
+ int taps = s->dither.ns_taps;
+ float S = s->dither.ns_scale;
+ float S_1 = s->dither.ns_scale_1;
+
+ av_assert2((taps&3) != 2);
+ av_assert2((taps&3) != 3 || s->dither.ns_coeffs[taps] == 0);
+
+ for (ch=0; ch<srcs->ch_count; ch++) {
+ const float *noise = ((const float *)noises->ch[ch]) + s->dither.noise_pos;
+ const DELEM *src = (const DELEM*)srcs->ch[ch];
+ DELEM *dst = (DELEM*)dsts->ch[ch];
+ float *ns_errors = s->dither.ns_errors[ch];
+ const float *ns_coeffs = s->dither.ns_coeffs;
+ pos = s->dither.ns_pos;
+ for (i=0; i<count; i++) {
+ double d1, d = src[i]*S_1;
+ for(j=0; j<taps-2; j+=4) {
+ d -= ns_coeffs[j ] * ns_errors[pos + j ]
+ +ns_coeffs[j + 1] * ns_errors[pos + j + 1]
+ +ns_coeffs[j + 2] * ns_errors[pos + j + 2]
+ +ns_coeffs[j + 3] * ns_errors[pos + j + 3];
+ }
+ if(j < taps)
+ d -= ns_coeffs[j] * ns_errors[pos + j];
+ pos = pos ? pos - 1 : taps - 1;
+ d1 = rint(d + noise[i]);
+ ns_errors[pos + taps] = ns_errors[pos] = d1 - d;
+ d1 *= S;
+ CLIP(d1);
+ dst[i] = d1;
+ }
+ }
+
+ s->dither.ns_pos = pos;
+}
+
+#undef RENAME
+#undef DELEM
+#undef CLIP
diff --git a/libswresample/libswresample.v b/libswresample/libswresample.v
new file mode 100644
index 0000000000..0d5efe4706
--- /dev/null
+++ b/libswresample/libswresample.v
@@ -0,0 +1,4 @@
+LIBSWRESAMPLE_$MAJOR {
+ global: swr_*; swresample_*;
+ local: *;
+};
diff --git a/libswresample/log2_tab.c b/libswresample/log2_tab.c
new file mode 100644
index 0000000000..47a1df03b7
--- /dev/null
+++ b/libswresample/log2_tab.c
@@ -0,0 +1 @@
+#include "libavutil/log2_tab.c"
diff --git a/libswresample/noise_shaping_data.c b/libswresample/noise_shaping_data.c
new file mode 100644
index 0000000000..77e0f2eafc
--- /dev/null
+++ b/libswresample/noise_shaping_data.c
@@ -0,0 +1,224 @@
+/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser 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 library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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 library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+typedef struct {
+ int rate;
+ enum {fir, iir} type;
+ size_t len;
+ int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */
+ double const * coefs;
+ enum SwrDitherType name;
+} filter_t;
+
+static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149};
+static double const fwe44[] = {
+ 2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847};
+static double const mew44[] = {
+ 1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524};
+static double const iew44[] = {
+ 2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191};
+static double const ges44[] = {
+ 2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738};
+static double const ges48[] = {
+ 2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571};
+
+static double const shi48[] = {
+ 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406,
+ -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812,
+ -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922,
+ 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609,
+ 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002,
+ -0.023473845794796943665,
+};
+static double const shi44[] = {
+ 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875,
+ -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344,
+ 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391,
+ 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297,
+ -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181,
+ -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348,
+ 0.17496839165687561035, -0.060908168554306030273,
+};
+static double const shi38[] = {
+ 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219,
+ -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695,
+ 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002,
+ 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416,
+ -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203,
+ 0.016833892092108726501,
+};
+static double const shi32[] =
+{ /* dmaker 32000: bestmax=4.99659 (inverted) */
+0.82118552923202515,
+-1.0063692331314087,
+0.62341964244842529,
+-1.0447187423706055,
+0.64532512426376343,
+-0.87615132331848145,
+0.52219754457473755,
+-0.67434263229370117,
+0.44954317808151245,
+-0.52557498216629028,
+0.34567299485206604,
+-0.39618203043937683,
+0.26791760325431824,
+-0.28936097025871277,
+0.1883765310049057,
+-0.19097308814525604,
+0.10431359708309174,
+-0.10633844882249832,
+0.046832218766212463,
+-0.039653312414884567,
+};
+static double const shi22[] =
+{ /* dmaker 22050: bestmax=5.77762 (inverted) */
+0.056581053882837296,
+-0.56956905126571655,
+-0.40727734565734863,
+-0.33870288729667664,
+-0.29810553789138794,
+-0.19039161503314972,
+-0.16510021686553955,
+-0.13468159735202789,
+-0.096633769571781158,
+-0.081049129366874695,
+-0.064953058958053589,
+-0.054459091275930405,
+-0.043378707021474838,
+-0.03660014271736145,
+-0.026256965473294258,
+-0.018786206841468811,
+-0.013387725688517094,
+-0.0090983230620622635,
+-0.0026585909072309732,
+-0.00042083300650119781,
+};
+static double const shi16[] =
+{ /* dmaker 16000: bestmax=5.97128 (inverted) */
+-0.37251132726669312,
+-0.81423574686050415,
+-0.55010956525802612,
+-0.47405767440795898,
+-0.32624706625938416,
+-0.3161766529083252,
+-0.2286367267370224,
+-0.22916607558727264,
+-0.19565616548061371,
+-0.18160104751586914,
+-0.15423151850700378,
+-0.14104481041431427,
+-0.11844276636838913,
+-0.097583092749118805,
+-0.076493598520755768,
+-0.068106919527053833,
+-0.041881654411554337,
+-0.036922425031661987,
+-0.019364040344953537,
+-0.014994367957115173,
+};
+static double const shi11[] =
+{ /* dmaker 11025: bestmax=5.9406 (inverted) */
+-0.9264228343963623,
+-0.98695987462997437,
+-0.631156325340271,
+-0.51966935396194458,
+-0.39738872647285461,
+-0.35679301619529724,
+-0.29720726609230042,
+-0.26310476660728455,
+-0.21719355881214142,
+-0.18561814725399017,
+-0.15404847264289856,
+-0.12687471508979797,
+-0.10339745879173279,
+-0.083688631653785706,
+-0.05875682458281517,
+-0.046893671154975891,
+-0.027950936928391457,
+-0.020740609616041183,
+-0.009366452693939209,
+-0.0060260160826146603,
+};
+static double const shi08[] =
+{ /* dmaker 8000: bestmax=5.56234 (inverted) */
+-1.202863335609436,
+-0.94103097915649414,
+-0.67878556251525879,
+-0.57650017738342285,
+-0.50004476308822632,
+-0.44349345564842224,
+-0.37833768129348755,
+-0.34028723835945129,
+-0.29413089156150818,
+-0.24994957447052002,
+-0.21715600788593292,
+-0.18792112171649933,
+-0.15268312394618988,
+-0.12135542929172516,
+-0.099610626697540283,
+-0.075273610651493073,
+-0.048787496984004974,
+-0.042586319148540497,
+-0.028991291299462318,
+-0.011869125068187714,
+};
+static double const shl48[] = {
+ 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469,
+ -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531,
+ -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924,
+ -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559,
+ -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035,
+ 0.068674825131893157959,
+};
+static double const shl44[] = {
+ 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109,
+ -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709,
+ -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906,
+ 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996,
+ 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005,
+ 0,
+};
+static double const shh44[] = {
+ 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375,
+ -11.824929237365722656, 12.767142295837402344, -11.917946815490722656,
+ 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758,
+ 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031,
+ -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656,
+ 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543,
+ -0.16519790887832641602, 0.023217858746647834778,
+};
+
+static const filter_t filters[] = {
+ {44100, fir, 5, 210, lip44, SWR_DITHER_NS_LIPSHITZ},
+ {46000, fir, 9, 276, fwe44, SWR_DITHER_NS_F_WEIGHTED},
+ {46000, fir, 9, 160, mew44, SWR_DITHER_NS_MODIFIED_E_WEIGHTED},
+ {46000, fir, 9, 321, iew44, SWR_DITHER_NS_IMPROVED_E_WEIGHTED},
+// {48000, iir, 4, 220, ges48, SWR_DITHER_NS_GESEMANN},
+// {44100, iir, 4, 230, ges44, SWR_DITHER_NS_GESEMANN},
+ {48000, fir, 16, 301, shi48, SWR_DITHER_NS_SHIBATA},
+ {44100, fir, 20, 333, shi44, SWR_DITHER_NS_SHIBATA},
+ {37800, fir, 16, 240, shi38, SWR_DITHER_NS_SHIBATA},
+ {32000, fir, 20, 240/*TBD*/, shi32, SWR_DITHER_NS_SHIBATA},
+ {22050, fir, 20, 240/*TBD*/, shi22, SWR_DITHER_NS_SHIBATA},
+ {16000, fir, 20, 240/*TBD*/, shi16, SWR_DITHER_NS_SHIBATA},
+ {11025, fir, 20, 240/*TBD*/, shi11, SWR_DITHER_NS_SHIBATA},
+ { 8000, fir, 20, 240/*TBD*/, shi08, SWR_DITHER_NS_SHIBATA},
+ {48000, fir, 16, 250, shl48, SWR_DITHER_NS_LOW_SHIBATA},
+ {44100, fir, 15, 250, shl44, SWR_DITHER_NS_LOW_SHIBATA},
+ {44100, fir, 20, 383, shh44, SWR_DITHER_NS_HIGH_SHIBATA},
+ { 0, fir, 0, 0, NULL, SWR_DITHER_NONE},
+};
diff --git a/libswresample/options.c b/libswresample/options.c
new file mode 100644
index 0000000000..de84672834
--- /dev/null
+++ b/libswresample/options.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/opt.h"
+#include "swresample_internal.h"
+
+#include <float.h>
+
+#define C30DB M_SQRT2
+#define C15DB 1.189207115
+#define C__0DB 1.0
+#define C_15DB 0.840896415
+#define C_30DB M_SQRT1_2
+#define C_45DB 0.594603558
+#define C_60DB 0.5
+
+#define OFFSET(x) offsetof(SwrContext,x)
+#define PARAM AV_OPT_FLAG_AUDIO_PARAM
+
+static const AVOption options[]={
+{"ich" , "set input channel count" , OFFSET(user_in_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"in_channel_count" , "set input channel count" , OFFSET(user_in_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"och" , "set output channel count" , OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"out_channel_count" , "set output channel count" , OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"uch" , "set used channel count" , OFFSET(user_used_ch_count), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"used_channel_count" , "set used channel count" , OFFSET(user_used_ch_count), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM},
+{"isr" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM},
+{"in_sample_rate" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM},
+{"osr" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM},
+{"out_sample_rate" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM},
+{"isf" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM},
+{"in_sample_fmt" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM},
+{"osf" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM},
+{"out_sample_fmt" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM},
+{"tsf" , "set internal sample format" , OFFSET(int_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM},
+{"internal_sample_fmt" , "set internal sample format" , OFFSET(int_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM},
+{"icl" , "set input channel layout" , OFFSET(user_in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"in_channel_layout" , "set input channel layout" , OFFSET(user_in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"ocl" , "set output channel layout" , OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"out_channel_layout" , "set output channel layout" , OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, 0 , INT64_MAX , PARAM, "channel_layout"},
+{"clev" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM},
+{"center_mix_level" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM},
+{"slev" , "set surround mix level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM},
+{"surround_mix_level" , "set surround mix Level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM},
+{"lfe_mix_level" , "set LFE mix level" , OFFSET(lfe_mix_level ), AV_OPT_TYPE_FLOAT, {.dbl=0 }, -32 , 32 , PARAM},
+{"rmvol" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM},
+{"rematrix_volume" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM},
+{"rematrix_maxval" , "set rematrix maxval" , OFFSET(rematrix_maxval), AV_OPT_TYPE_FLOAT, {.dbl=0.0 }, 0 , 1000 , PARAM},
+
+{"flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"},
+{"swr_flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"},
+{"res" , "force resampling" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_FLAG_RESAMPLE }, INT_MIN, INT_MAX , PARAM, "flags"},
+
+{"dither_scale" , "set dither scale" , OFFSET(dither.scale ), AV_OPT_TYPE_FLOAT, {.dbl=1 }, 0 , INT_MAX , PARAM},
+
+{"dither_method" , "set dither method" , OFFSET(dither.method ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"},
+{"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"},
+{"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"},
+{"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"lipshitz" , "select lipshitz noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LIPSHITZ}, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"shibata" , "select shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"low_shibata" , "select low shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LOW_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"high_shibata" , "select high shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_HIGH_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"f_weighted" , "select f-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_F_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"modified_e_weighted" , "select modified-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_MODIFIED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+{"improved_e_weighted" , "select improved-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_IMPROVED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"},
+
+{"filter_size" , "set swr resampling filter size", OFFSET(filter_size) , AV_OPT_TYPE_INT , {.i64=32 }, 0 , INT_MAX , PARAM },
+{"phase_shift" , "set swr resampling phase shift", OFFSET(phase_shift) , AV_OPT_TYPE_INT , {.i64=10 }, 0 , 24 , PARAM },
+{"linear_interp" , "enable linear interpolation" , OFFSET(linear_interp) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , 1 , PARAM },
+{"cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM },
+
+/* duplicate option in order to work with avconv */
+{"resample_cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM },
+
+{"resampler" , "set resampling Engine" , OFFSET(engine) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_ENGINE_NB-1, PARAM, "resampler"},
+{"swr" , "select SW Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SWR }, INT_MIN, INT_MAX , PARAM, "resampler"},
+{"soxr" , "select SoX Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SOXR }, INT_MIN, INT_MAX , PARAM, "resampler"},
+{"precision" , "set soxr resampling precision (in bits)"
+ , OFFSET(precision) , AV_OPT_TYPE_DOUBLE,{.dbl=20.0 }, 15.0 , 33.0 , PARAM },
+{"cheby" , "enable soxr Chebyshev passband & higher-precision irrational ratio approximation"
+ , OFFSET(cheby) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , 1 , PARAM },
+{"min_comp" , "set minimum difference between timestamps and audio data (in seconds) below which no timestamp compensation of either kind is applied"
+ , OFFSET(min_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=FLT_MAX }, 0 , FLT_MAX , PARAM },
+{"min_hard_comp" , "set minimum difference between timestamps and audio data (in seconds) to trigger padding/trimming the data."
+ , OFFSET(min_hard_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0.1 }, 0 , INT_MAX , PARAM },
+{"comp_duration" , "set duration (in seconds) over which data is stretched/squeezed to make it match the timestamps."
+ , OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1 }, 0 , INT_MAX , PARAM },
+{"max_soft_comp" , "set maximum factor by which data is stretched/squeezed to make it match the timestamps."
+ , OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM },
+{"async" , "simplified 1 parameter audio timestamp matching, 0(disabled), 1(filling and trimming), >1(maximum stretch/squeeze in samples per second)"
+ , OFFSET(async) , AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM },
+{"first_pts" , "Assume the first pts should be this value (in samples)."
+ , OFFSET(firstpts_in_samples), AV_OPT_TYPE_INT64 ,{.i64=AV_NOPTS_VALUE }, INT64_MIN,INT64_MAX, PARAM },
+
+{ "matrix_encoding" , "set matrixed stereo encoding" , OFFSET(matrix_encoding), AV_OPT_TYPE_INT ,{.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_NB-1, PARAM, "matrix_encoding" },
+ { "none", "select none", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
+ { "dolby", "select Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
+ { "dplii", "select Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" },
+
+{ "filter_type" , "select swr filter type" , OFFSET(filter_type) , AV_OPT_TYPE_INT , { .i64 = SWR_FILTER_TYPE_KAISER }, SWR_FILTER_TYPE_CUBIC, SWR_FILTER_TYPE_KAISER, PARAM, "filter_type" },
+ { "cubic" , "select cubic" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" },
+ { "blackman_nuttall", "select Blackman Nuttall Windowed Sinc", 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" },
+ { "kaiser" , "select Kaiser Windowed Sinc" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" },
+
+{ "kaiser_beta" , "set swr Kaiser Window Beta" , OFFSET(kaiser_beta) , AV_OPT_TYPE_INT , {.i64=9 }, 2 , 16 , PARAM },
+
+{ "output_sample_bits" , "set swr number of output sample bits", OFFSET(dither.output_sample_bits), AV_OPT_TYPE_INT , {.i64=0 }, 0 , 64 , PARAM },
+{0}
+};
+
+static const char* context_to_name(void* ptr) {
+ return "SWR";
+}
+
+static const AVClass av_class = {
+ .class_name = "SWResampler",
+ .item_name = context_to_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+ .log_level_offset_offset = OFFSET(log_level_offset),
+ .parent_log_context_offset = OFFSET(log_ctx),
+ .category = AV_CLASS_CATEGORY_SWRESAMPLER,
+};
+
+const AVClass *swr_get_class(void)
+{
+ return &av_class;
+}
+
+av_cold struct SwrContext *swr_alloc(void){
+ SwrContext *s= av_mallocz(sizeof(SwrContext));
+ if(s){
+ s->av_class= &av_class;
+ av_opt_set_defaults(s);
+ }
+ return s;
+}
diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c
new file mode 100644
index 0000000000..4569558138
--- /dev/null
+++ b/libswresample/rematrix.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "swresample_internal.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+
+#define TEMPLATE_REMATRIX_FLT
+#include "rematrix_template.c"
+#undef TEMPLATE_REMATRIX_FLT
+
+#define TEMPLATE_REMATRIX_DBL
+#include "rematrix_template.c"
+#undef TEMPLATE_REMATRIX_DBL
+
+#define TEMPLATE_REMATRIX_S16
+#include "rematrix_template.c"
+#undef TEMPLATE_REMATRIX_S16
+
+#define TEMPLATE_REMATRIX_S32
+#include "rematrix_template.c"
+#undef TEMPLATE_REMATRIX_S32
+
+#define FRONT_LEFT 0
+#define FRONT_RIGHT 1
+#define FRONT_CENTER 2
+#define LOW_FREQUENCY 3
+#define BACK_LEFT 4
+#define BACK_RIGHT 5
+#define FRONT_LEFT_OF_CENTER 6
+#define FRONT_RIGHT_OF_CENTER 7
+#define BACK_CENTER 8
+#define SIDE_LEFT 9
+#define SIDE_RIGHT 10
+#define TOP_CENTER 11
+#define TOP_FRONT_LEFT 12
+#define TOP_FRONT_CENTER 13
+#define TOP_FRONT_RIGHT 14
+#define TOP_BACK_LEFT 15
+#define TOP_BACK_CENTER 16
+#define TOP_BACK_RIGHT 17
+#define NUM_NAMED_CHANNELS 18
+
+int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride)
+{
+ int nb_in, nb_out, in, out;
+
+ if (!s || s->in_convert) // s needs to be allocated but not initialized
+ return AVERROR(EINVAL);
+ memset(s->matrix, 0, sizeof(s->matrix));
+ nb_in = av_get_channel_layout_nb_channels(s->user_in_ch_layout);
+ nb_out = av_get_channel_layout_nb_channels(s->user_out_ch_layout);
+ for (out = 0; out < nb_out; out++) {
+ for (in = 0; in < nb_in; in++)
+ s->matrix[out][in] = matrix[in];
+ matrix += stride;
+ }
+ s->rematrix_custom = 1;
+ return 0;
+}
+
+static int even(int64_t layout){
+ if(!layout) return 1;
+ if(layout&(layout-1)) return 1;
+ return 0;
+}
+
+static int clean_layout(SwrContext *s, int64_t layout){
+ if(layout && layout != AV_CH_FRONT_CENTER && !(layout&(layout-1))) {
+ char buf[128];
+ av_get_channel_layout_string(buf, sizeof(buf), -1, layout);
+ av_log(s, AV_LOG_VERBOSE, "Treating %s as mono\n", buf);
+ return AV_CH_FRONT_CENTER;
+ }
+
+ return layout;
+}
+
+static int sane_layout(int64_t layout){
+ if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker
+ return 0;
+ if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front
+ return 0;
+ if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT))) // no asymetric side
+ return 0;
+ if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)))
+ return 0;
+ if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)))
+ return 0;
+ if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX)
+ return 0;
+
+ return 1;
+}
+
+av_cold static int auto_matrix(SwrContext *s)
+{
+ int i, j, out_i;
+ double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}};
+ int64_t unaccounted, in_ch_layout, out_ch_layout;
+ double maxcoef=0;
+ char buf[128];
+ const int matrix_encoding = s->matrix_encoding;
+ float maxval;
+
+ in_ch_layout = clean_layout(s, s->in_ch_layout);
+ out_ch_layout = clean_layout(s, s->out_ch_layout);
+
+ if( out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX
+ && (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0
+ )
+ out_ch_layout = AV_CH_LAYOUT_STEREO;
+
+ if( in_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX
+ && (out_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0
+ )
+ in_ch_layout = AV_CH_LAYOUT_STEREO;
+
+ if(!sane_layout(in_ch_layout)){
+ av_get_channel_layout_string(buf, sizeof(buf), -1, s->in_ch_layout);
+ av_log(s, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf);
+ return AVERROR(EINVAL);
+ }
+
+ if(!sane_layout(out_ch_layout)){
+ av_get_channel_layout_string(buf, sizeof(buf), -1, s->out_ch_layout);
+ av_log(s, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf);
+ return AVERROR(EINVAL);
+ }
+
+ memset(s->matrix, 0, sizeof(s->matrix));
+ for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){
+ if(in_ch_layout & out_ch_layout & (1ULL<<i))
+ matrix[i][i]= 1.0;
+ }
+
+ unaccounted= in_ch_layout & ~out_ch_layout;
+
+//FIXME implement dolby surround
+//FIXME implement full ac3
+
+
+ if(unaccounted & AV_CH_FRONT_CENTER){
+ if((out_ch_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO){
+ if(in_ch_layout & AV_CH_LAYOUT_STEREO) {
+ matrix[ FRONT_LEFT][FRONT_CENTER]+= s->clev;
+ matrix[FRONT_RIGHT][FRONT_CENTER]+= s->clev;
+ } else {
+ matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2;
+ matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2;
+ }
+ }else
+ av_assert0(0);
+ }
+ if(unaccounted & AV_CH_LAYOUT_STEREO){
+ if(out_ch_layout & AV_CH_FRONT_CENTER){
+ matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2;
+ matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2;
+ if(in_ch_layout & AV_CH_FRONT_CENTER)
+ matrix[FRONT_CENTER][ FRONT_CENTER] = s->clev*sqrt(2);
+ }else
+ av_assert0(0);
+ }
+
+ if(unaccounted & AV_CH_BACK_CENTER){
+ if(out_ch_layout & AV_CH_BACK_LEFT){
+ matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2;
+ matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2;
+ }else if(out_ch_layout & AV_CH_SIDE_LEFT){
+ matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2;
+ matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2;
+ }else if(out_ch_layout & AV_CH_FRONT_LEFT){
+ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY ||
+ matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+ if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) {
+ matrix[FRONT_LEFT ][BACK_CENTER] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][BACK_CENTER] += s->slev * M_SQRT1_2;
+ } else {
+ matrix[FRONT_LEFT ][BACK_CENTER] -= s->slev;
+ matrix[FRONT_RIGHT][BACK_CENTER] += s->slev;
+ }
+ } else {
+ matrix[ FRONT_LEFT][BACK_CENTER]+= s->slev*M_SQRT1_2;
+ matrix[FRONT_RIGHT][BACK_CENTER]+= s->slev*M_SQRT1_2;
+ }
+ }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+ matrix[ FRONT_CENTER][BACK_CENTER]+= s->slev*M_SQRT1_2;
+ }else
+ av_assert0(0);
+ }
+ if(unaccounted & AV_CH_BACK_LEFT){
+ if(out_ch_layout & AV_CH_BACK_CENTER){
+ matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2;
+ matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2;
+ }else if(out_ch_layout & AV_CH_SIDE_LEFT){
+ if(in_ch_layout & AV_CH_SIDE_LEFT){
+ matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2;
+ matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2;
+ }else{
+ matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0;
+ matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0;
+ }
+ }else if(out_ch_layout & AV_CH_FRONT_LEFT){
+ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
+ matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * M_SQRT1_2;
+ } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+ matrix[FRONT_LEFT ][BACK_LEFT ] -= s->slev * SQRT3_2;
+ matrix[FRONT_LEFT ][BACK_RIGHT] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][BACK_LEFT ] += s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev * SQRT3_2;
+ } else {
+ matrix[ FRONT_LEFT][ BACK_LEFT] += s->slev;
+ matrix[FRONT_RIGHT][BACK_RIGHT] += s->slev;
+ }
+ }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+ matrix[ FRONT_CENTER][BACK_LEFT ]+= s->slev*M_SQRT1_2;
+ matrix[ FRONT_CENTER][BACK_RIGHT]+= s->slev*M_SQRT1_2;
+ }else
+ av_assert0(0);
+ }
+
+ if(unaccounted & AV_CH_SIDE_LEFT){
+ if(out_ch_layout & AV_CH_BACK_LEFT){
+ /* if back channels do not exist in the input, just copy side
+ channels to back channels, otherwise mix side into back */
+ if (in_ch_layout & AV_CH_BACK_LEFT) {
+ matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2;
+ matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2;
+ } else {
+ matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0;
+ matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
+ }
+ }else if(out_ch_layout & AV_CH_BACK_CENTER){
+ matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2;
+ matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2;
+ }else if(out_ch_layout & AV_CH_FRONT_LEFT){
+ if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) {
+ matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * M_SQRT1_2;
+ } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) {
+ matrix[FRONT_LEFT ][SIDE_LEFT ] -= s->slev * SQRT3_2;
+ matrix[FRONT_LEFT ][SIDE_RIGHT] -= s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][SIDE_LEFT ] += s->slev * M_SQRT1_2;
+ matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev * SQRT3_2;
+ } else {
+ matrix[ FRONT_LEFT][ SIDE_LEFT] += s->slev;
+ matrix[FRONT_RIGHT][SIDE_RIGHT] += s->slev;
+ }
+ }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+ matrix[ FRONT_CENTER][SIDE_LEFT ]+= s->slev*M_SQRT1_2;
+ matrix[ FRONT_CENTER][SIDE_RIGHT]+= s->slev*M_SQRT1_2;
+ }else
+ av_assert0(0);
+ }
+
+ if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){
+ if(out_ch_layout & AV_CH_FRONT_LEFT){
+ matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0;
+ matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0;
+ }else if(out_ch_layout & AV_CH_FRONT_CENTER){
+ matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2;
+ matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2;
+ }else
+ av_assert0(0);
+ }
+ /* mix LFE into front left/right or center */
+ if (unaccounted & AV_CH_LOW_FREQUENCY) {
+ if (out_ch_layout & AV_CH_FRONT_CENTER) {
+ matrix[FRONT_CENTER][LOW_FREQUENCY] += s->lfe_mix_level;
+ } else if (out_ch_layout & AV_CH_FRONT_LEFT) {
+ matrix[FRONT_LEFT ][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2;
+ matrix[FRONT_RIGHT][LOW_FREQUENCY] += s->lfe_mix_level * M_SQRT1_2;
+ } else
+ av_assert0(0);
+ }
+
+ for(out_i=i=0; i<64; i++){
+ double sum=0;
+ int in_i=0;
+ if((out_ch_layout & (1ULL<<i)) == 0)
+ continue;
+ for(j=0; j<64; j++){
+ if((in_ch_layout & (1ULL<<j)) == 0)
+ continue;
+ if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0]))
+ s->matrix[out_i][in_i]= matrix[i][j];
+ else
+ s->matrix[out_i][in_i]= i == j && (in_ch_layout & out_ch_layout & (1ULL<<i));
+ sum += fabs(s->matrix[out_i][in_i]);
+ in_i++;
+ }
+ maxcoef= FFMAX(maxcoef, sum);
+ out_i++;
+ }
+ if(s->rematrix_volume < 0)
+ maxcoef = -s->rematrix_volume;
+
+ if (s->rematrix_maxval > 0) {
+ maxval = s->rematrix_maxval;
+ } else if ( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT
+ || av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) {
+ maxval = 1.0;
+ } else
+ maxval = INT_MAX;
+
+ if(maxcoef > maxval || s->rematrix_volume < 0){
+ maxcoef /= maxval;
+ for(i=0; i<SWR_CH_MAX; i++)
+ for(j=0; j<SWR_CH_MAX; j++){
+ s->matrix[i][j] /= maxcoef;
+ }
+ }
+
+ if(s->rematrix_volume > 0){
+ for(i=0; i<SWR_CH_MAX; i++)
+ for(j=0; j<SWR_CH_MAX; j++){
+ s->matrix[i][j] *= s->rematrix_volume;
+ }
+ }
+
+ for(i=0; i<av_get_channel_layout_nb_channels(out_ch_layout); i++){
+ for(j=0; j<av_get_channel_layout_nb_channels(in_ch_layout); j++){
+ av_log(NULL, AV_LOG_DEBUG, "%f ", s->matrix[i][j]);
+ }
+ av_log(NULL, AV_LOG_DEBUG, "\n");
+ }
+ return 0;
+}
+
+av_cold int swri_rematrix_init(SwrContext *s){
+ int i, j;
+ int nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout);
+ int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout);
+
+ s->mix_any_f = NULL;
+
+ if (!s->rematrix_custom) {
+ int r = auto_matrix(s);
+ if (r)
+ return r;
+ }
+ if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){
+ s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int));
+ s->native_one = av_mallocz(sizeof(int));
+ for (i = 0; i < nb_out; i++)
+ for (j = 0; j < nb_in; j++)
+ ((int*)s->native_matrix)[i * nb_in + j] = lrintf(s->matrix[i][j] * 32768);
+ *((int*)s->native_one) = 32768;
+ s->mix_1_1_f = (mix_1_1_func_type*)copy_s16;
+ s->mix_2_1_f = (mix_2_1_func_type*)sum2_s16;
+ s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s16(s);
+ }else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){
+ s->native_matrix = av_calloc(nb_in * nb_out, sizeof(float));
+ s->native_one = av_mallocz(sizeof(float));
+ for (i = 0; i < nb_out; i++)
+ for (j = 0; j < nb_in; j++)
+ ((float*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j];
+ *((float*)s->native_one) = 1.0;
+ s->mix_1_1_f = (mix_1_1_func_type*)copy_float;
+ s->mix_2_1_f = (mix_2_1_func_type*)sum2_float;
+ s->mix_any_f = (mix_any_func_type*)get_mix_any_func_float(s);
+ }else if(s->midbuf.fmt == AV_SAMPLE_FMT_DBLP){
+ s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double));
+ s->native_one = av_mallocz(sizeof(double));
+ for (i = 0; i < nb_out; i++)
+ for (j = 0; j < nb_in; j++)
+ ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j];
+ *((double*)s->native_one) = 1.0;
+ s->mix_1_1_f = (mix_1_1_func_type*)copy_double;
+ s->mix_2_1_f = (mix_2_1_func_type*)sum2_double;
+ s->mix_any_f = (mix_any_func_type*)get_mix_any_func_double(s);
+ }else if(s->midbuf.fmt == AV_SAMPLE_FMT_S32P){
+ // Only for dithering currently
+// s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double));
+ s->native_one = av_mallocz(sizeof(int));
+// for (i = 0; i < nb_out; i++)
+// for (j = 0; j < nb_in; j++)
+// ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j];
+ *((int*)s->native_one) = 32768;
+ s->mix_1_1_f = (mix_1_1_func_type*)copy_s32;
+ s->mix_2_1_f = (mix_2_1_func_type*)sum2_s32;
+ s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s32(s);
+ }else
+ av_assert0(0);
+ //FIXME quantize for integeres
+ for (i = 0; i < SWR_CH_MAX; i++) {
+ int ch_in=0;
+ for (j = 0; j < SWR_CH_MAX; j++) {
+ s->matrix32[i][j]= lrintf(s->matrix[i][j] * 32768);
+ if(s->matrix[i][j])
+ s->matrix_ch[i][++ch_in]= j;
+ }
+ s->matrix_ch[i][0]= ch_in;
+ }
+
+ if(HAVE_YASM && HAVE_MMX)
+ return swri_rematrix_init_x86(s);
+
+ return 0;
+}
+
+av_cold void swri_rematrix_free(SwrContext *s){
+ av_freep(&s->native_matrix);
+ av_freep(&s->native_one);
+ av_freep(&s->native_simd_matrix);
+ av_freep(&s->native_simd_one);
+}
+
+int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){
+ int out_i, in_i, i, j;
+ int len1 = 0;
+ int off = 0;
+
+ if(s->mix_any_f) {
+ s->mix_any_f(out->ch, (const uint8_t **)in->ch, s->native_matrix, len);
+ return 0;
+ }
+
+ if(s->mix_2_1_simd || s->mix_1_1_simd){
+ len1= len&~15;
+ off = len1 * out->bps;
+ }
+
+ av_assert0(!s->out_ch_layout || out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout));
+ av_assert0(!s-> in_ch_layout || in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout));
+
+ for(out_i=0; out_i<out->ch_count; out_i++){
+ switch(s->matrix_ch[out_i][0]){
+ case 0:
+ if(mustcopy)
+ memset(out->ch[out_i], 0, len * av_get_bytes_per_sample(s->int_sample_fmt));
+ break;
+ case 1:
+ in_i= s->matrix_ch[out_i][1];
+ if(s->matrix[out_i][in_i]!=1.0){
+ if(s->mix_1_1_simd && len1)
+ s->mix_1_1_simd(out->ch[out_i] , in->ch[in_i] , s->native_simd_matrix, in->ch_count*out_i + in_i, len1);
+ if(len != len1)
+ s->mix_1_1_f (out->ch[out_i]+off, in->ch[in_i]+off, s->native_matrix, in->ch_count*out_i + in_i, len-len1);
+ }else if(mustcopy){
+ memcpy(out->ch[out_i], in->ch[in_i], len*out->bps);
+ }else{
+ out->ch[out_i]= in->ch[in_i];
+ }
+ break;
+ case 2: {
+ int in_i1 = s->matrix_ch[out_i][1];
+ int in_i2 = s->matrix_ch[out_i][2];
+ if(s->mix_2_1_simd && len1)
+ s->mix_2_1_simd(out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_simd_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1);
+ else
+ s->mix_2_1_f (out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1);
+ if(len != len1)
+ s->mix_2_1_f (out->ch[out_i]+off, in->ch[in_i1]+off, in->ch[in_i2]+off, s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len-len1);
+ break;}
+ default:
+ if(s->int_sample_fmt == AV_SAMPLE_FMT_FLTP){
+ for(i=0; i<len; i++){
+ float v=0;
+ for(j=0; j<s->matrix_ch[out_i][0]; j++){
+ in_i= s->matrix_ch[out_i][1+j];
+ v+= ((float*)in->ch[in_i])[i] * s->matrix[out_i][in_i];
+ }
+ ((float*)out->ch[out_i])[i]= v;
+ }
+ }else if(s->int_sample_fmt == AV_SAMPLE_FMT_DBLP){
+ for(i=0; i<len; i++){
+ double v=0;
+ for(j=0; j<s->matrix_ch[out_i][0]; j++){
+ in_i= s->matrix_ch[out_i][1+j];
+ v+= ((double*)in->ch[in_i])[i] * s->matrix[out_i][in_i];
+ }
+ ((double*)out->ch[out_i])[i]= v;
+ }
+ }else{
+ for(i=0; i<len; i++){
+ int v=0;
+ for(j=0; j<s->matrix_ch[out_i][0]; j++){
+ in_i= s->matrix_ch[out_i][1+j];
+ v+= ((int16_t*)in->ch[in_i])[i] * s->matrix32[out_i][in_i];
+ }
+ ((int16_t*)out->ch[out_i])[i]= (v + 16384)>>15;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/libswresample/rematrix_template.c b/libswresample/rematrix_template.c
new file mode 100644
index 0000000000..95a3b9a8c0
--- /dev/null
+++ b/libswresample/rematrix_template.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if defined(TEMPLATE_REMATRIX_FLT)
+# define R(x) x
+# define SAMPLE float
+# define COEFF float
+# define INTER float
+# define RENAME(x) x ## _float
+#elif defined(TEMPLATE_REMATRIX_DBL)
+# define R(x) x
+# define SAMPLE double
+# define COEFF double
+# define INTER double
+# define RENAME(x) x ## _double
+#elif defined(TEMPLATE_REMATRIX_S16)
+# define R(x) (((x) + 16384)>>15)
+# define SAMPLE int16_t
+# define COEFF int
+# define INTER int
+# define RENAME(x) x ## _s16
+#elif defined(TEMPLATE_REMATRIX_S32)
+# define R(x) (((x) + 16384)>>15)
+# define SAMPLE int32_t
+# define COEFF int
+# define INTER int64_t
+# define RENAME(x) x ## _s32
+#endif
+
+typedef void (RENAME(mix_any_func_type))(SAMPLE **out, const SAMPLE **in1, COEFF *coeffp, integer len);
+
+static void RENAME(sum2)(SAMPLE *out, const SAMPLE *in1, const SAMPLE *in2, COEFF *coeffp, integer index1, integer index2, integer len){
+ int i;
+ INTER coeff1 = coeffp[index1];
+ INTER coeff2 = coeffp[index2];
+
+ for(i=0; i<len; i++)
+ out[i] = R(coeff1*in1[i] + coeff2*in2[i]);
+}
+
+static void RENAME(copy)(SAMPLE *out, const SAMPLE *in, COEFF *coeffp, integer index, integer len){
+ int i;
+ INTER coeff = coeffp[index];
+ for(i=0; i<len; i++)
+ out[i] = R(coeff*in[i]);
+}
+
+static void RENAME(mix6to2)(SAMPLE **out, const SAMPLE **in, COEFF *coeffp, integer len){
+ int i;
+
+ for(i=0; i<len; i++) {
+ INTER t = in[2][i]*(INTER)coeffp[0*6+2] + in[3][i]*(INTER)coeffp[0*6+3];
+ out[0][i] = R(t + in[0][i]*(INTER)coeffp[0*6+0] + in[4][i]*(INTER)coeffp[0*6+4]);
+ out[1][i] = R(t + in[1][i]*(INTER)coeffp[1*6+1] + in[5][i]*(INTER)coeffp[1*6+5]);
+ }
+}
+
+static void RENAME(mix8to2)(SAMPLE **out, const SAMPLE **in, COEFF *coeffp, integer len){
+ int i;
+
+ for(i=0; i<len; i++) {
+ INTER t = in[2][i]*(INTER)coeffp[0*8+2] + in[3][i]*(INTER)coeffp[0*8+3];
+ out[0][i] = R(t + in[0][i]*(INTER)coeffp[0*8+0] + in[4][i]*(INTER)coeffp[0*8+4] + in[6][i]*(INTER)coeffp[0*8+6]);
+ out[1][i] = R(t + in[1][i]*(INTER)coeffp[1*8+1] + in[5][i]*(INTER)coeffp[1*8+5] + in[7][i]*(INTER)coeffp[1*8+7]);
+ }
+}
+
+static RENAME(mix_any_func_type) *RENAME(get_mix_any_func)(SwrContext *s){
+ if( s->out_ch_layout == AV_CH_LAYOUT_STEREO && (s->in_ch_layout == AV_CH_LAYOUT_5POINT1 || s->in_ch_layout == AV_CH_LAYOUT_5POINT1_BACK)
+ && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3]
+ && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4]
+ )
+ return RENAME(mix6to2);
+
+ if( s->out_ch_layout == AV_CH_LAYOUT_STEREO && s->in_ch_layout == AV_CH_LAYOUT_7POINT1
+ && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3]
+ && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4]
+ && !s->matrix[0][7] && !s->matrix[1][6]
+ )
+ return RENAME(mix8to2);
+
+ return NULL;
+}
+
+#undef R
+#undef SAMPLE
+#undef COEFF
+#undef INTER
+#undef RENAME
diff --git a/libswresample/resample.c b/libswresample/resample.c
new file mode 100644
index 0000000000..d4c7d06794
--- /dev/null
+++ b/libswresample/resample.c
@@ -0,0 +1,417 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio resampling
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "libavutil/avassert.h"
+#include "resample.h"
+
+/**
+ * 0th order modified bessel function of the first kind.
+ */
+static double bessel(double x){
+ double v=1;
+ double lastv=0;
+ double t=1;
+ int i;
+ static const double inv[100]={
+ 1.0/( 1* 1), 1.0/( 2* 2), 1.0/( 3* 3), 1.0/( 4* 4), 1.0/( 5* 5), 1.0/( 6* 6), 1.0/( 7* 7), 1.0/( 8* 8), 1.0/( 9* 9), 1.0/(10*10),
+ 1.0/(11*11), 1.0/(12*12), 1.0/(13*13), 1.0/(14*14), 1.0/(15*15), 1.0/(16*16), 1.0/(17*17), 1.0/(18*18), 1.0/(19*19), 1.0/(20*20),
+ 1.0/(21*21), 1.0/(22*22), 1.0/(23*23), 1.0/(24*24), 1.0/(25*25), 1.0/(26*26), 1.0/(27*27), 1.0/(28*28), 1.0/(29*29), 1.0/(30*30),
+ 1.0/(31*31), 1.0/(32*32), 1.0/(33*33), 1.0/(34*34), 1.0/(35*35), 1.0/(36*36), 1.0/(37*37), 1.0/(38*38), 1.0/(39*39), 1.0/(40*40),
+ 1.0/(41*41), 1.0/(42*42), 1.0/(43*43), 1.0/(44*44), 1.0/(45*45), 1.0/(46*46), 1.0/(47*47), 1.0/(48*48), 1.0/(49*49), 1.0/(50*50),
+ 1.0/(51*51), 1.0/(52*52), 1.0/(53*53), 1.0/(54*54), 1.0/(55*55), 1.0/(56*56), 1.0/(57*57), 1.0/(58*58), 1.0/(59*59), 1.0/(60*60),
+ 1.0/(61*61), 1.0/(62*62), 1.0/(63*63), 1.0/(64*64), 1.0/(65*65), 1.0/(66*66), 1.0/(67*67), 1.0/(68*68), 1.0/(69*69), 1.0/(70*70),
+ 1.0/(71*71), 1.0/(72*72), 1.0/(73*73), 1.0/(74*74), 1.0/(75*75), 1.0/(76*76), 1.0/(77*77), 1.0/(78*78), 1.0/(79*79), 1.0/(80*80),
+ 1.0/(81*81), 1.0/(82*82), 1.0/(83*83), 1.0/(84*84), 1.0/(85*85), 1.0/(86*86), 1.0/(87*87), 1.0/(88*88), 1.0/(89*89), 1.0/(90*90),
+ 1.0/(91*91), 1.0/(92*92), 1.0/(93*93), 1.0/(94*94), 1.0/(95*95), 1.0/(96*96), 1.0/(97*97), 1.0/(98*98), 1.0/(99*99), 1.0/(10000)
+ };
+
+ x= x*x/4;
+ for(i=0; v != lastv; i++){
+ lastv=v;
+ t *= x*inv[i];
+ v += t;
+ av_assert2(i<99);
+ }
+ return v;
+}
+
+/**
+ * builds a polyphase filterbank.
+ * @param factor resampling factor
+ * @param scale wanted sum of coefficients for each filter
+ * @param filter_type filter type
+ * @param kaiser_beta kaiser window beta
+ * @return 0 on success, negative on error
+ */
+static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale,
+ int filter_type, int kaiser_beta){
+ int ph, i;
+ double x, y, w;
+ double *tab = av_malloc_array(tap_count, sizeof(*tab));
+ const int center= (tap_count-1)/2;
+
+ if (!tab)
+ return AVERROR(ENOMEM);
+
+ /* if upsampling, only need to interpolate, no filter */
+ if (factor > 1.0)
+ factor = 1.0;
+
+ for(ph=0;ph<phase_count;ph++) {
+ double norm = 0;
+ for(i=0;i<tap_count;i++) {
+ x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor;
+ if (x == 0) y = 1.0;
+ else y = sin(x) / x;
+ switch(filter_type){
+ case SWR_FILTER_TYPE_CUBIC:{
+ const float d= -0.5; //first order derivative = -0.5
+ x = fabs(((double)(i - center) - (double)ph / phase_count) * factor);
+ if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x);
+ else y= d*(-4 + 8*x - 5*x*x + x*x*x);
+ break;}
+ case SWR_FILTER_TYPE_BLACKMAN_NUTTALL:
+ w = 2.0*x / (factor*tap_count) + M_PI;
+ y *= 0.3635819 - 0.4891775 * cos(w) + 0.1365995 * cos(2*w) - 0.0106411 * cos(3*w);
+ break;
+ case SWR_FILTER_TYPE_KAISER:
+ w = 2.0*x / (factor*tap_count*M_PI);
+ y *= bessel(kaiser_beta*sqrt(FFMAX(1-w*w, 0)));
+ break;
+ default:
+ av_assert0(0);
+ }
+
+ tab[i] = y;
+ norm += y;
+ }
+
+ /* normalize so that an uniform color remains the same */
+ switch(c->format){
+ case AV_SAMPLE_FMT_S16P:
+ for(i=0;i<tap_count;i++)
+ ((int16_t*)filter)[ph * alloc + i] = av_clip(lrintf(tab[i] * scale / norm), INT16_MIN, INT16_MAX);
+ break;
+ case AV_SAMPLE_FMT_S32P:
+ for(i=0;i<tap_count;i++)
+ ((int32_t*)filter)[ph * alloc + i] = av_clipl_int32(llrint(tab[i] * scale / norm));
+ break;
+ case AV_SAMPLE_FMT_FLTP:
+ for(i=0;i<tap_count;i++)
+ ((float*)filter)[ph * alloc + i] = tab[i] * scale / norm;
+ break;
+ case AV_SAMPLE_FMT_DBLP:
+ for(i=0;i<tap_count;i++)
+ ((double*)filter)[ph * alloc + i] = tab[i] * scale / norm;
+ break;
+ }
+ }
+#if 0
+ {
+#define LEN 1024
+ int j,k;
+ double sine[LEN + tap_count];
+ double filtered[LEN];
+ double maxff=-2, minff=2, maxsf=-2, minsf=2;
+ for(i=0; i<LEN; i++){
+ double ss=0, sf=0, ff=0;
+ for(j=0; j<LEN+tap_count; j++)
+ sine[j]= cos(i*j*M_PI/LEN);
+ for(j=0; j<LEN; j++){
+ double sum=0;
+ ph=0;
+ for(k=0; k<tap_count; k++)
+ sum += filter[ph * tap_count + k] * sine[k+j];
+ filtered[j]= sum / (1<<FILTER_SHIFT);
+ ss+= sine[j + center] * sine[j + center];
+ ff+= filtered[j] * filtered[j];
+ sf+= sine[j + center] * filtered[j];
+ }
+ ss= sqrt(2*ss/LEN);
+ ff= sqrt(2*ff/LEN);
+ sf= 2*sf/LEN;
+ maxff= FFMAX(maxff, ff);
+ minff= FFMIN(minff, ff);
+ maxsf= FFMAX(maxsf, sf);
+ minsf= FFMIN(minsf, sf);
+ if(i%11==0){
+ av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf);
+ minff=minsf= 2;
+ maxff=maxsf= -2;
+ }
+ }
+ }
+#endif
+
+ av_free(tab);
+ return 0;
+}
+
+static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear,
+ double cutoff0, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta,
+ double precision, int cheby)
+{
+ double cutoff = cutoff0? cutoff0 : 0.97;
+ double factor= FFMIN(out_rate * cutoff / in_rate, 1.0);
+ int phase_count= 1<<phase_shift;
+
+ if (!c || c->phase_shift != phase_shift || c->linear!=linear || c->factor != factor
+ || c->filter_length != FFMAX((int)ceil(filter_size/factor), 1) || c->format != format
+ || c->filter_type != filter_type || c->kaiser_beta != kaiser_beta) {
+ c = av_mallocz(sizeof(*c));
+ if (!c)
+ return NULL;
+
+ c->format= format;
+
+ c->felem_size= av_get_bytes_per_sample(c->format);
+
+ switch(c->format){
+ case AV_SAMPLE_FMT_S16P:
+ c->filter_shift = 15;
+ break;
+ case AV_SAMPLE_FMT_S32P:
+ c->filter_shift = 30;
+ break;
+ case AV_SAMPLE_FMT_FLTP:
+ case AV_SAMPLE_FMT_DBLP:
+ c->filter_shift = 0;
+ break;
+ default:
+ av_log(NULL, AV_LOG_ERROR, "Unsupported sample format\n");
+ av_assert0(0);
+ }
+
+ if (filter_size/factor > INT32_MAX/256) {
+ av_log(NULL, AV_LOG_ERROR, "Filter length too large\n");
+ goto error;
+ }
+
+ c->phase_shift = phase_shift;
+ c->phase_mask = phase_count - 1;
+ c->linear = linear;
+ c->factor = factor;
+ c->filter_length = FFMAX((int)ceil(filter_size/factor), 1);
+ c->filter_alloc = FFALIGN(c->filter_length, 8);
+ c->filter_bank = av_calloc(c->filter_alloc, (phase_count+1)*c->felem_size);
+ c->filter_type = filter_type;
+ c->kaiser_beta = kaiser_beta;
+ if (!c->filter_bank)
+ goto error;
+ if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<<c->filter_shift, filter_type, kaiser_beta))
+ goto error;
+ memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size);
+ memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size);
+ }
+
+ c->compensation_distance= 0;
+ if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2))
+ goto error;
+ c->ideal_dst_incr = c->dst_incr;
+ c->dst_incr_div = c->dst_incr / c->src_incr;
+ c->dst_incr_mod = c->dst_incr % c->src_incr;
+
+ c->index= -phase_count*((c->filter_length-1)/2);
+ c->frac= 0;
+
+ swri_resample_dsp_init(c);
+
+ return c;
+error:
+ av_freep(&c->filter_bank);
+ av_free(c);
+ return NULL;
+}
+
+static void resample_free(ResampleContext **c){
+ if(!*c)
+ return;
+ av_freep(&(*c)->filter_bank);
+ av_freep(c);
+}
+
+static int set_compensation(ResampleContext *c, int sample_delta, int compensation_distance){
+ c->compensation_distance= compensation_distance;
+ if (compensation_distance)
+ c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance;
+ else
+ c->dst_incr = c->ideal_dst_incr;
+
+ c->dst_incr_div = c->dst_incr / c->src_incr;
+ c->dst_incr_mod = c->dst_incr % c->src_incr;
+
+ return 0;
+}
+
+static int swri_resample(ResampleContext *c,
+ uint8_t *dst, const uint8_t *src, int *consumed,
+ int src_size, int dst_size, int update_ctx)
+{
+ if (c->filter_length == 1 && c->phase_shift == 0) {
+ int index= c->index;
+ int frac= c->frac;
+ int64_t index2= (1LL<<32)*c->frac/c->src_incr + (1LL<<32)*index;
+ int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr;
+ int new_size = (src_size * (int64_t)c->src_incr - frac + c->dst_incr - 1) / c->dst_incr;
+
+ dst_size= FFMIN(dst_size, new_size);
+ c->dsp.resample_one(dst, src, dst_size, index2, incr);
+
+ index += dst_size * c->dst_incr_div;
+ index += (frac + dst_size * (int64_t)c->dst_incr_mod) / c->src_incr;
+ av_assert2(index >= 0);
+ *consumed= index;
+ if (update_ctx) {
+ c->frac = (frac + dst_size * (int64_t)c->dst_incr_mod) % c->src_incr;
+ c->index = 0;
+ }
+ } else {
+ int64_t end_index = (1LL + src_size - c->filter_length) << c->phase_shift;
+ int64_t delta_frac = (end_index - c->index) * c->src_incr - c->frac;
+ int delta_n = (delta_frac + c->dst_incr - 1) / c->dst_incr;
+
+ dst_size = FFMIN(dst_size, delta_n);
+ if (dst_size > 0) {
+ *consumed = c->dsp.resample(c, dst, src, dst_size, update_ctx);
+ } else {
+ *consumed = 0;
+ }
+ }
+
+ return dst_size;
+}
+
+static int multiple_resample(ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed){
+ int i, ret= -1;
+ int av_unused mm_flags = av_get_cpu_flags();
+ int need_emms = c->format == AV_SAMPLE_FMT_S16P && ARCH_X86_32 &&
+ (mm_flags & (AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE2)) == AV_CPU_FLAG_MMX2;
+ int64_t max_src_size = (INT64_MAX >> (c->phase_shift+1)) / c->src_incr;
+
+ if (c->compensation_distance)
+ dst_size = FFMIN(dst_size, c->compensation_distance);
+ src_size = FFMIN(src_size, max_src_size);
+
+ for(i=0; i<dst->ch_count; i++){
+ ret= swri_resample(c, dst->ch[i], src->ch[i],
+ consumed, src_size, dst_size, i+1==dst->ch_count);
+ }
+ if(need_emms)
+ emms_c();
+
+ if (c->compensation_distance) {
+ c->compensation_distance -= ret;
+ if (!c->compensation_distance) {
+ c->dst_incr = c->ideal_dst_incr;
+ c->dst_incr_div = c->dst_incr / c->src_incr;
+ c->dst_incr_mod = c->dst_incr % c->src_incr;
+ }
+ }
+
+ return ret;
+}
+
+static int64_t get_delay(struct SwrContext *s, int64_t base){
+ ResampleContext *c = s->resample;
+ int64_t num = s->in_buffer_count - (c->filter_length-1)/2;
+ num *= 1 << c->phase_shift;
+ num -= c->index;
+ num *= c->src_incr;
+ num -= c->frac;
+ return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr << c->phase_shift);
+}
+
+static int resample_flush(struct SwrContext *s) {
+ AudioData *a= &s->in_buffer;
+ int i, j, ret;
+ if((ret = swri_realloc_audio(a, s->in_buffer_index + 2*s->in_buffer_count)) < 0)
+ return ret;
+ av_assert0(a->planar);
+ for(i=0; i<a->ch_count; i++){
+ for(j=0; j<s->in_buffer_count; j++){
+ memcpy(a->ch[i] + (s->in_buffer_index+s->in_buffer_count+j )*a->bps,
+ a->ch[i] + (s->in_buffer_index+s->in_buffer_count-j-1)*a->bps, a->bps);
+ }
+ }
+ s->in_buffer_count += (s->in_buffer_count+1)/2;
+ return 0;
+}
+
+// in fact the whole handle multiple ridiculously small buffers might need more thinking...
+static int invert_initial_buffer(ResampleContext *c, AudioData *dst, const AudioData *src,
+ int in_count, int *out_idx, int *out_sz)
+{
+ int n, ch, num = FFMIN(in_count + *out_sz, c->filter_length + 1), res;
+
+ if (c->index >= 0)
+ return 0;
+
+ if ((res = swri_realloc_audio(dst, c->filter_length * 2 + 1)) < 0)
+ return res;
+
+ // copy
+ for (n = *out_sz; n < num; n++) {
+ for (ch = 0; ch < src->ch_count; ch++) {
+ memcpy(dst->ch[ch] + ((c->filter_length + n) * c->felem_size),
+ src->ch[ch] + ((n - *out_sz) * c->felem_size), c->felem_size);
+ }
+ }
+
+ // if not enough data is in, return and wait for more
+ if (num < c->filter_length + 1) {
+ *out_sz = num;
+ *out_idx = c->filter_length;
+ return INT_MAX;
+ }
+
+ // else invert
+ for (n = 1; n <= c->filter_length; n++) {
+ for (ch = 0; ch < src->ch_count; ch++) {
+ memcpy(dst->ch[ch] + ((c->filter_length - n) * c->felem_size),
+ dst->ch[ch] + ((c->filter_length + n) * c->felem_size),
+ c->felem_size);
+ }
+ }
+
+ res = num - *out_sz;
+ *out_idx = c->filter_length + (c->index >> c->phase_shift);
+ *out_sz = FFMAX(*out_sz + c->filter_length,
+ 1 + c->filter_length * 2) - *out_idx;
+ c->index &= c->phase_mask;
+
+ return FFMAX(res, 0);
+}
+
+struct Resampler const swri_resampler={
+ resample_init,
+ resample_free,
+ multiple_resample,
+ resample_flush,
+ set_compensation,
+ get_delay,
+ invert_initial_buffer,
+};
diff --git a/libswresample/resample.h b/libswresample/resample.h
new file mode 100644
index 0000000000..99a89b7945
--- /dev/null
+++ b/libswresample/resample.h
@@ -0,0 +1,64 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 SWRESAMPLE_RESAMPLE_H
+#define SWRESAMPLE_RESAMPLE_H
+
+#include "libavutil/log.h"
+#include "libavutil/samplefmt.h"
+
+#include "swresample_internal.h"
+
+typedef struct ResampleContext {
+ const AVClass *av_class;
+ uint8_t *filter_bank;
+ int filter_length;
+ int filter_alloc;
+ int ideal_dst_incr;
+ int dst_incr;
+ int dst_incr_div;
+ int dst_incr_mod;
+ int index;
+ int frac;
+ int src_incr;
+ int compensation_distance;
+ int phase_shift;
+ int phase_mask;
+ int linear;
+ enum SwrFilterType filter_type;
+ int kaiser_beta;
+ double factor;
+ enum AVSampleFormat format;
+ int felem_size;
+ int filter_shift;
+
+ struct {
+ void (*resample_one)(void *dst, const void *src,
+ int n, int64_t index, int64_t incr);
+ int (*resample)(struct ResampleContext *c, void *dst,
+ const void *src, int n, int update_ctx);
+ } dsp;
+} ResampleContext;
+
+void swri_resample_dsp_init(ResampleContext *c);
+void swri_resample_dsp_x86_init(ResampleContext *c);
+
+#endif /* SWRESAMPLE_RESAMPLE_H */
diff --git a/libswresample/resample_dsp.c b/libswresample/resample_dsp.c
new file mode 100644
index 0000000000..a811b8b6fa
--- /dev/null
+++ b/libswresample/resample_dsp.c
@@ -0,0 +1,68 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio resampling
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "resample.h"
+
+#define TEMPLATE_RESAMPLE_S16
+#include "resample_template.c"
+#undef TEMPLATE_RESAMPLE_S16
+
+#define TEMPLATE_RESAMPLE_S32
+#include "resample_template.c"
+#undef TEMPLATE_RESAMPLE_S32
+
+#define TEMPLATE_RESAMPLE_FLT
+#include "resample_template.c"
+#undef TEMPLATE_RESAMPLE_FLT
+
+#define TEMPLATE_RESAMPLE_DBL
+#include "resample_template.c"
+#undef TEMPLATE_RESAMPLE_DBL
+
+void swri_resample_dsp_init(ResampleContext *c)
+{
+ switch(c->format){
+ case AV_SAMPLE_FMT_S16P:
+ c->dsp.resample_one = resample_one_int16;
+ c->dsp.resample = c->linear ? resample_linear_int16 : resample_common_int16;
+ break;
+ case AV_SAMPLE_FMT_S32P:
+ c->dsp.resample_one = resample_one_int32;
+ c->dsp.resample = c->linear ? resample_linear_int32 : resample_common_int32;
+ break;
+ case AV_SAMPLE_FMT_FLTP:
+ c->dsp.resample_one = resample_one_float;
+ c->dsp.resample = c->linear ? resample_linear_float : resample_common_float;
+ break;
+ case AV_SAMPLE_FMT_DBLP:
+ c->dsp.resample_one = resample_one_double;
+ c->dsp.resample = c->linear ? resample_linear_double : resample_common_double;
+ break;
+ }
+
+ if (ARCH_X86) swri_resample_dsp_x86_init(c);
+}
diff --git a/libswresample/resample_template.c b/libswresample/resample_template.c
new file mode 100644
index 0000000000..d71efd63c0
--- /dev/null
+++ b/libswresample/resample_template.c
@@ -0,0 +1,187 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio resampling
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#if defined(TEMPLATE_RESAMPLE_DBL)
+
+# define RENAME(N) N ## _double
+# define FILTER_SHIFT 0
+# define DELEM double
+# define FELEM double
+# define FELEM2 double
+# define OUT(d, v) d = v
+
+#elif defined(TEMPLATE_RESAMPLE_FLT)
+
+# define RENAME(N) N ## _float
+# define FILTER_SHIFT 0
+# define DELEM float
+# define FELEM float
+# define FELEM2 float
+# define OUT(d, v) d = v
+
+#elif defined(TEMPLATE_RESAMPLE_S32)
+
+# define RENAME(N) N ## _int32
+# define FILTER_SHIFT 30
+# define DELEM int32_t
+# define FELEM int32_t
+# define FELEM2 int64_t
+# define FELEM_MAX INT32_MAX
+# define FELEM_MIN INT32_MIN
+# define OUT(d, v) (v) = ((v) + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;\
+ (d) = av_clipl_int32(v)
+
+#elif defined(TEMPLATE_RESAMPLE_S16)
+
+# define RENAME(N) N ## _int16
+# define FILTER_SHIFT 15
+# define DELEM int16_t
+# define FELEM int16_t
+# define FELEM2 int32_t
+# define FELEML int64_t
+# define FELEM_MAX INT16_MAX
+# define FELEM_MIN INT16_MIN
+# define OUT(d, v) (v) = ((v) + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;\
+ (d) = av_clip_int16(v)
+
+#endif
+
+static void RENAME(resample_one)(void *dest, const void *source,
+ int dst_size, int64_t index2, int64_t incr)
+{
+ DELEM *dst = dest;
+ const DELEM *src = source;
+ int dst_index;
+
+ for (dst_index = 0; dst_index < dst_size; dst_index++) {
+ dst[dst_index] = src[index2 >> 32];
+ index2 += incr;
+ }
+}
+
+static int RENAME(resample_common)(ResampleContext *c,
+ void *dest, const void *source,
+ int n, int update_ctx)
+{
+ DELEM *dst = dest;
+ const DELEM *src = source;
+ int dst_index;
+ int index= c->index;
+ int frac= c->frac;
+ int sample_index = index >> c->phase_shift;
+
+ index &= c->phase_mask;
+ for (dst_index = 0; dst_index < n; dst_index++) {
+ FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index;
+
+ FELEM2 val=0;
+ int i;
+ for (i = 0; i < c->filter_length; i++) {
+ val += src[sample_index + i] * (FELEM2)filter[i];
+ }
+ OUT(dst[dst_index], val);
+
+ frac += c->dst_incr_mod;
+ index += c->dst_incr_div;
+ if (frac >= c->src_incr) {
+ frac -= c->src_incr;
+ index++;
+ }
+ sample_index += index >> c->phase_shift;
+ index &= c->phase_mask;
+ }
+
+ if(update_ctx){
+ c->frac= frac;
+ c->index= index;
+ }
+
+ return sample_index;
+}
+
+static int RENAME(resample_linear)(ResampleContext *c,
+ void *dest, const void *source,
+ int n, int update_ctx)
+{
+ DELEM *dst = dest;
+ const DELEM *src = source;
+ int dst_index;
+ int index= c->index;
+ int frac= c->frac;
+ int sample_index = index >> c->phase_shift;
+#if FILTER_SHIFT == 0
+ double inv_src_incr = 1.0 / c->src_incr;
+#endif
+
+ index &= c->phase_mask;
+ for (dst_index = 0; dst_index < n; dst_index++) {
+ FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index;
+ FELEM2 val=0, v2 = 0;
+
+ int i;
+ for (i = 0; i < c->filter_length; i++) {
+ val += src[sample_index + i] * (FELEM2)filter[i];
+ v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_alloc];
+ }
+#ifdef FELEML
+ val += (v2 - val) * (FELEML) frac / c->src_incr;
+#else
+# if FILTER_SHIFT == 0
+ val += (v2 - val) * inv_src_incr * frac;
+# else
+ val += (v2 - val) / c->src_incr * frac;
+# endif
+#endif
+ OUT(dst[dst_index], val);
+
+ frac += c->dst_incr_mod;
+ index += c->dst_incr_div;
+ if (frac >= c->src_incr) {
+ frac -= c->src_incr;
+ index++;
+ }
+ sample_index += index >> c->phase_shift;
+ index &= c->phase_mask;
+ }
+
+ if(update_ctx){
+ c->frac= frac;
+ c->index= index;
+ }
+
+ return sample_index;
+}
+
+#undef RENAME
+#undef FILTER_SHIFT
+#undef DELEM
+#undef FELEM
+#undef FELEM2
+#undef FELEML
+#undef FELEM_MAX
+#undef FELEM_MIN
+#undef OUT
diff --git a/libswresample/soxr_resample.c b/libswresample/soxr_resample.c
new file mode 100644
index 0000000000..0f75bc554c
--- /dev/null
+++ b/libswresample/soxr_resample.c
@@ -0,0 +1,104 @@
+/*
+ * audio resampling with soxr
+ * Copyright (c) 2012 Rob Sykes <robs@users.sourceforge.net>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio resampling with soxr
+ */
+
+#include "libavutil/log.h"
+#include "swresample_internal.h"
+
+#include <soxr.h>
+
+static struct ResampleContext *create(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear,
+ double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta, double precision, int cheby){
+ soxr_error_t error;
+
+ soxr_datatype_t type =
+ format == AV_SAMPLE_FMT_S16P? SOXR_INT16_S :
+ format == AV_SAMPLE_FMT_S16 ? SOXR_INT16_I :
+ format == AV_SAMPLE_FMT_S32P? SOXR_INT32_S :
+ format == AV_SAMPLE_FMT_S32 ? SOXR_INT32_I :
+ format == AV_SAMPLE_FMT_FLTP? SOXR_FLOAT32_S :
+ format == AV_SAMPLE_FMT_FLT ? SOXR_FLOAT32_I :
+ format == AV_SAMPLE_FMT_DBLP? SOXR_FLOAT64_S :
+ format == AV_SAMPLE_FMT_DBL ? SOXR_FLOAT64_I : (soxr_datatype_t)-1;
+
+ soxr_io_spec_t io_spec = soxr_io_spec(type, type);
+
+ soxr_quality_spec_t q_spec = soxr_quality_spec((int)((precision-2)/4), (SOXR_HI_PREC_CLOCK|SOXR_ROLLOFF_NONE)*!!cheby);
+ q_spec.precision = linear? 0 : precision;
+#if !defined SOXR_VERSION /* Deprecated @ March 2013: */
+ q_spec.bw_pc = cutoff? FFMAX(FFMIN(cutoff,.995),.8)*100 : q_spec.bw_pc;
+#else
+ q_spec.passband_end = cutoff? FFMAX(FFMIN(cutoff,.995),.8) : q_spec.passband_end;
+#endif
+
+ soxr_delete((soxr_t)c);
+ c = (struct ResampleContext *)
+ soxr_create(in_rate, out_rate, 0, &error, &io_spec, &q_spec, 0);
+ if (!c)
+ av_log(NULL, AV_LOG_ERROR, "soxr_create: %s\n", error);
+ return c;
+}
+
+static void destroy(struct ResampleContext * *c){
+ soxr_delete((soxr_t)*c);
+ *c = NULL;
+}
+
+static int flush(struct SwrContext *s){
+ soxr_process((soxr_t)s->resample, NULL, 0, NULL, NULL, 0, NULL);
+ return 0;
+}
+
+static int process(
+ struct ResampleContext * c, AudioData *dst, int dst_size,
+ AudioData *src, int src_size, int *consumed){
+ size_t idone, odone;
+ soxr_error_t error = soxr_set_error((soxr_t)c, soxr_set_num_channels((soxr_t)c, src->ch_count));
+ if (!error)
+ error = soxr_process((soxr_t)c, src->ch, (size_t)src_size,
+ &idone, dst->ch, (size_t)dst_size, &odone);
+ else
+ idone = 0;
+
+ *consumed = (int)idone;
+ return error? -1 : odone;
+}
+
+static int64_t get_delay(struct SwrContext *s, int64_t base){
+ double delay_s = soxr_delay((soxr_t)s->resample) / s->out_sample_rate;
+ return (int64_t)(delay_s * base + .5);
+}
+
+static int invert_initial_buffer(struct ResampleContext *c, AudioData *dst, const AudioData *src,
+ int in_count, int *out_idx, int *out_sz)
+{
+ return 0;
+}
+
+struct Resampler const swri_soxr_resampler={
+ create, destroy, process, flush, NULL /* set_compensation */, get_delay,
+ invert_initial_buffer,
+};
+
diff --git a/libswresample/swresample-test.c b/libswresample/swresample-test.c
new file mode 100644
index 0000000000..7e2854da7c
--- /dev/null
+++ b/libswresample/swresample-test.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at)
+ * Copyright (c) 2002 Fabrice Bellard
+ *
+ * This file is part of libswresample
+ *
+ * libswresample 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.
+ *
+ * libswresample is distributed in the hope that 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 libswresample; 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/channel_layout.h"
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "swresample.h"
+
+#undef time
+#include "time.h"
+#undef fprintf
+
+#define SAMPLES 1000
+
+#define SWR_CH_MAX 32
+
+#define ASSERT_LEVEL 2
+
+static double get(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f){
+ const uint8_t *p;
+ if(av_sample_fmt_is_planar(f)){
+ f= av_get_alt_sample_fmt(f, 0);
+ p= a[ch];
+ }else{
+ p= a[0];
+ index= ch + index*ch_count;
+ }
+
+ switch(f){
+ case AV_SAMPLE_FMT_U8 : return ((const uint8_t*)p)[index]/127.0-1.0;
+ case AV_SAMPLE_FMT_S16: return ((const int16_t*)p)[index]/32767.0;
+ case AV_SAMPLE_FMT_S32: return ((const int32_t*)p)[index]/2147483647.0;
+ case AV_SAMPLE_FMT_FLT: return ((const float *)p)[index];
+ case AV_SAMPLE_FMT_DBL: return ((const double *)p)[index];
+ default: av_assert0(0);
+ }
+}
+
+static void set(uint8_t *a[], int ch, int index, int ch_count, enum AVSampleFormat f, double v){
+ uint8_t *p;
+ if(av_sample_fmt_is_planar(f)){
+ f= av_get_alt_sample_fmt(f, 0);
+ p= a[ch];
+ }else{
+ p= a[0];
+ index= ch + index*ch_count;
+ }
+ switch(f){
+ case AV_SAMPLE_FMT_U8 : ((uint8_t*)p)[index]= av_clip_uint8 (lrint((v+1.0)*127)); break;
+ case AV_SAMPLE_FMT_S16: ((int16_t*)p)[index]= av_clip_int16 (lrint(v*32767)); break;
+ case AV_SAMPLE_FMT_S32: ((int32_t*)p)[index]= av_clipl_int32(llrint(v*2147483647)); break;
+ case AV_SAMPLE_FMT_FLT: ((float *)p)[index]= v; break;
+ case AV_SAMPLE_FMT_DBL: ((double *)p)[index]= v; break;
+ default: av_assert2(0);
+ }
+}
+
+static void shift(uint8_t *a[], int index, int ch_count, enum AVSampleFormat f){
+ int ch;
+
+ if(av_sample_fmt_is_planar(f)){
+ f= av_get_alt_sample_fmt(f, 0);
+ for(ch= 0; ch<ch_count; ch++)
+ a[ch] += index*av_get_bytes_per_sample(f);
+ }else{
+ a[0] += index*ch_count*av_get_bytes_per_sample(f);
+ }
+}
+
+static const enum AVSampleFormat formats[] = {
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_S32P,
+ AV_SAMPLE_FMT_S32,
+ AV_SAMPLE_FMT_U8P,
+ AV_SAMPLE_FMT_U8,
+ AV_SAMPLE_FMT_DBLP,
+ AV_SAMPLE_FMT_DBL,
+};
+
+static const int rates[] = {
+ 8000,
+ 11025,
+ 16000,
+ 22050,
+ 32000,
+ 48000,
+};
+
+uint64_t layouts[]={
+ AV_CH_LAYOUT_MONO ,
+ AV_CH_LAYOUT_STEREO ,
+ AV_CH_LAYOUT_2_1 ,
+ AV_CH_LAYOUT_SURROUND ,
+ AV_CH_LAYOUT_4POINT0 ,
+ AV_CH_LAYOUT_2_2 ,
+ AV_CH_LAYOUT_QUAD ,
+ AV_CH_LAYOUT_5POINT0 ,
+ AV_CH_LAYOUT_5POINT1 ,
+ AV_CH_LAYOUT_5POINT0_BACK ,
+ AV_CH_LAYOUT_5POINT1_BACK ,
+ AV_CH_LAYOUT_7POINT0 ,
+ AV_CH_LAYOUT_7POINT1 ,
+ AV_CH_LAYOUT_7POINT1_WIDE ,
+};
+
+static void setup_array(uint8_t *out[SWR_CH_MAX], uint8_t *in, enum AVSampleFormat format, int samples){
+ if(av_sample_fmt_is_planar(format)){
+ int i;
+ int plane_size= av_get_bytes_per_sample(format&0xFF)*samples;
+ format&=0xFF;
+ for(i=0; i<SWR_CH_MAX; i++){
+ out[i]= in + i*plane_size;
+ }
+ }else{
+ out[0]= in;
+ }
+}
+
+static int cmp(const int *a, const int *b){
+ return *a - *b;
+}
+
+static void audiogen(void *data, enum AVSampleFormat sample_fmt,
+ int channels, int sample_rate, int nb_samples)
+{
+ int i, ch, k;
+ double v, f, a, ampa;
+ double tabf1[SWR_CH_MAX];
+ double tabf2[SWR_CH_MAX];
+ double taba[SWR_CH_MAX];
+ unsigned static rnd;
+
+#define PUT_SAMPLE set(data, ch, k, channels, sample_fmt, v);
+#define uint_rand(x) ((x) = (x) * 1664525 + 1013904223)
+#define dbl_rand(x) (uint_rand(x)*2.0 / (double)UINT_MAX - 1)
+ k = 0;
+
+ /* 1 second of single freq sinus at 1000 Hz */
+ a = 0;
+ for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) {
+ v = sin(a) * 0.30;
+ for (ch = 0; ch < channels; ch++)
+ PUT_SAMPLE
+ a += M_PI * 1000.0 * 2.0 / sample_rate;
+ }
+
+ /* 1 second of varying frequency between 100 and 10000 Hz */
+ a = 0;
+ for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) {
+ v = sin(a) * 0.30;
+ for (ch = 0; ch < channels; ch++)
+ PUT_SAMPLE
+ f = 100.0 + (((10000.0 - 100.0) * i) / sample_rate);
+ a += M_PI * f * 2.0 / sample_rate;
+ }
+
+ /* 0.5 second of low amplitude white noise */
+ for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) {
+ v = dbl_rand(rnd) * 0.30;
+ for (ch = 0; ch < channels; ch++)
+ PUT_SAMPLE
+ }
+
+ /* 0.5 second of high amplitude white noise */
+ for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) {
+ v = dbl_rand(rnd);
+ for (ch = 0; ch < channels; ch++)
+ PUT_SAMPLE
+ }
+
+ /* 1 second of unrelated ramps for each channel */
+ for (ch = 0; ch < channels; ch++) {
+ taba[ch] = 0;
+ tabf1[ch] = 100 + uint_rand(rnd) % 5000;
+ tabf2[ch] = 100 + uint_rand(rnd) % 5000;
+ }
+ for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) {
+ for (ch = 0; ch < channels; ch++) {
+ v = sin(taba[ch]) * 0.30;
+ PUT_SAMPLE
+ f = tabf1[ch] + (((tabf2[ch] - tabf1[ch]) * i) / sample_rate);
+ taba[ch] += M_PI * f * 2.0 / sample_rate;
+ }
+ }
+
+ /* 2 seconds of 500 Hz with varying volume */
+ a = 0;
+ ampa = 0;
+ for (i = 0; i < 2 * sample_rate && k < nb_samples; i++, k++) {
+ for (ch = 0; ch < channels; ch++) {
+ double amp = (1.0 + sin(ampa)) * 0.15;
+ if (ch & 1)
+ amp = 0.30 - amp;
+ v = sin(a) * amp;
+ PUT_SAMPLE
+ a += M_PI * 500.0 * 2.0 / sample_rate;
+ ampa += M_PI * 2.0 / sample_rate;
+ }
+ }
+}
+
+int main(int argc, char **argv){
+ int in_sample_rate, out_sample_rate, ch ,i, flush_count;
+ uint64_t in_ch_layout, out_ch_layout;
+ enum AVSampleFormat in_sample_fmt, out_sample_fmt;
+ uint8_t array_in[SAMPLES*8*8];
+ uint8_t array_mid[SAMPLES*8*8*3];
+ uint8_t array_out[SAMPLES*8*8+100];
+ uint8_t *ain[SWR_CH_MAX];
+ uint8_t *aout[SWR_CH_MAX];
+ uint8_t *amid[SWR_CH_MAX];
+ int flush_i=0;
+ int mode;
+ int num_tests = 10000;
+ uint32_t seed = 0;
+ uint32_t rand_seed = 0;
+ int remaining_tests[FF_ARRAY_ELEMS(rates) * FF_ARRAY_ELEMS(layouts) * FF_ARRAY_ELEMS(formats) * FF_ARRAY_ELEMS(layouts) * FF_ARRAY_ELEMS(formats)];
+ int max_tests = FF_ARRAY_ELEMS(remaining_tests);
+ int test;
+ int specific_test= -1;
+
+ struct SwrContext * forw_ctx= NULL;
+ struct SwrContext *backw_ctx= NULL;
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ av_log(NULL, AV_LOG_INFO, "Usage: swresample-test [<num_tests>[ <test>]] \n"
+ "num_tests Default is %d\n", num_tests);
+ return 0;
+ }
+ num_tests = strtol(argv[1], NULL, 0);
+ if(num_tests < 0) {
+ num_tests = -num_tests;
+ rand_seed = time(0);
+ }
+ if(num_tests<= 0 || num_tests>max_tests)
+ num_tests = max_tests;
+ if(argc > 2) {
+ specific_test = strtol(argv[1], NULL, 0);
+ }
+ }
+
+ for(i=0; i<max_tests; i++)
+ remaining_tests[i] = i;
+
+ for(test=0; test<num_tests; test++){
+ unsigned r;
+ uint_rand(seed);
+ r = (seed * (uint64_t)(max_tests - test)) >>32;
+ FFSWAP(int, remaining_tests[r], remaining_tests[max_tests - test - 1]);
+ }
+ qsort(remaining_tests + max_tests - num_tests, num_tests, sizeof(remaining_tests[0]), (void*)cmp);
+ in_sample_rate=16000;
+ for(test=0; test<num_tests; test++){
+ char in_layout_string[256];
+ char out_layout_string[256];
+ unsigned vector= remaining_tests[max_tests - test - 1];
+ int in_ch_count;
+ int out_count, mid_count, out_ch_count;
+
+ in_ch_layout = layouts[vector % FF_ARRAY_ELEMS(layouts)]; vector /= FF_ARRAY_ELEMS(layouts);
+ out_ch_layout = layouts[vector % FF_ARRAY_ELEMS(layouts)]; vector /= FF_ARRAY_ELEMS(layouts);
+ in_sample_fmt = formats[vector % FF_ARRAY_ELEMS(formats)]; vector /= FF_ARRAY_ELEMS(formats);
+ out_sample_fmt = formats[vector % FF_ARRAY_ELEMS(formats)]; vector /= FF_ARRAY_ELEMS(formats);
+ out_sample_rate = rates [vector % FF_ARRAY_ELEMS(rates )]; vector /= FF_ARRAY_ELEMS(rates);
+ av_assert0(!vector);
+
+ if(specific_test == 0){
+ if(out_sample_rate != in_sample_rate || in_ch_layout != out_ch_layout)
+ continue;
+ }
+
+ in_ch_count= av_get_channel_layout_nb_channels(in_ch_layout);
+ out_ch_count= av_get_channel_layout_nb_channels(out_ch_layout);
+ av_get_channel_layout_string( in_layout_string, sizeof( in_layout_string), in_ch_count, in_ch_layout);
+ av_get_channel_layout_string(out_layout_string, sizeof(out_layout_string), out_ch_count, out_ch_layout);
+ fprintf(stderr, "TEST: %s->%s, rate:%5d->%5d, fmt:%s->%s\n",
+ in_layout_string, out_layout_string,
+ in_sample_rate, out_sample_rate,
+ av_get_sample_fmt_name(in_sample_fmt), av_get_sample_fmt_name(out_sample_fmt));
+ forw_ctx = swr_alloc_set_opts(forw_ctx, out_ch_layout, out_sample_fmt, out_sample_rate,
+ in_ch_layout, in_sample_fmt, in_sample_rate,
+ 0, 0);
+ backw_ctx = swr_alloc_set_opts(backw_ctx, in_ch_layout, in_sample_fmt, in_sample_rate,
+ out_ch_layout, out_sample_fmt, out_sample_rate,
+ 0, 0);
+ if(!forw_ctx) {
+ fprintf(stderr, "Failed to init forw_cts\n");
+ return 1;
+ }
+ if(!backw_ctx) {
+ fprintf(stderr, "Failed to init backw_ctx\n");
+ return 1;
+ }
+ if (uint_rand(rand_seed) % 3 == 0)
+ av_opt_set_int(forw_ctx, "ich", 0, 0);
+ if (uint_rand(rand_seed) % 3 == 0)
+ av_opt_set_int(forw_ctx, "och", 0, 0);
+
+ if(swr_init( forw_ctx) < 0)
+ fprintf(stderr, "swr_init(->) failed\n");
+ if(swr_init(backw_ctx) < 0)
+ fprintf(stderr, "swr_init(<-) failed\n");
+ //FIXME test planar
+ setup_array(ain , array_in , in_sample_fmt, SAMPLES);
+ setup_array(amid, array_mid, out_sample_fmt, 3*SAMPLES);
+ setup_array(aout, array_out, in_sample_fmt , SAMPLES);
+#if 0
+ for(ch=0; ch<in_ch_count; ch++){
+ for(i=0; i<SAMPLES; i++)
+ set(ain, ch, i, in_ch_count, in_sample_fmt, sin(i*i*3/SAMPLES));
+ }
+#else
+ audiogen(ain, in_sample_fmt, in_ch_count, SAMPLES/6+1, SAMPLES);
+#endif
+ mode = uint_rand(rand_seed) % 3;
+ if(mode==0 /*|| out_sample_rate == in_sample_rate*/) {
+ mid_count= swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, SAMPLES);
+ } else if(mode==1){
+ mid_count= swr_convert(forw_ctx, amid, 0, (const uint8_t **)ain, SAMPLES);
+ mid_count+=swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, 0);
+ } else {
+ int tmp_count;
+ mid_count= swr_convert(forw_ctx, amid, 0, (const uint8_t **)ain, 1);
+ av_assert0(mid_count==0);
+ shift(ain, 1, in_ch_count, in_sample_fmt);
+ mid_count+=swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, 0);
+ shift(amid, mid_count, out_ch_count, out_sample_fmt); tmp_count = mid_count;
+ mid_count+=swr_convert(forw_ctx, amid, 2, (const uint8_t **)ain, 2);
+ shift(amid, mid_count-tmp_count, out_ch_count, out_sample_fmt); tmp_count = mid_count;
+ shift(ain, 2, in_ch_count, in_sample_fmt);
+ mid_count+=swr_convert(forw_ctx, amid, 1, (const uint8_t **)ain, SAMPLES-3);
+ shift(amid, mid_count-tmp_count, out_ch_count, out_sample_fmt); tmp_count = mid_count;
+ shift(ain, -3, in_ch_count, in_sample_fmt);
+ mid_count+=swr_convert(forw_ctx, amid, 3*SAMPLES, (const uint8_t **)ain, 0);
+ shift(amid, -tmp_count, out_ch_count, out_sample_fmt);
+ }
+ out_count= swr_convert(backw_ctx,aout, SAMPLES, (const uint8_t **)amid, mid_count);
+
+ for(ch=0; ch<in_ch_count; ch++){
+ double sse, maxdiff=0;
+ double sum_a= 0;
+ double sum_b= 0;
+ double sum_aa= 0;
+ double sum_bb= 0;
+ double sum_ab= 0;
+ for(i=0; i<out_count; i++){
+ double a= get(ain , ch, i, in_ch_count, in_sample_fmt);
+ double b= get(aout, ch, i, in_ch_count, in_sample_fmt);
+ sum_a += a;
+ sum_b += b;
+ sum_aa+= a*a;
+ sum_bb+= b*b;
+ sum_ab+= a*b;
+ maxdiff= FFMAX(maxdiff, FFABS(a-b));
+ }
+ sse= sum_aa + sum_bb - 2*sum_ab;
+ if(sse < 0 && sse > -0.00001) sse=0; //fix rounding error
+
+ fprintf(stderr, "[e:%f c:%f max:%f] len:%5d\n", out_count ? sqrt(sse/out_count) : 0, sum_ab/(sqrt(sum_aa*sum_bb)), maxdiff, out_count);
+ }
+
+ flush_i++;
+ flush_i%=21;
+ flush_count = swr_convert(backw_ctx,aout, flush_i, 0, 0);
+ shift(aout, flush_i, in_ch_count, in_sample_fmt);
+ flush_count+= swr_convert(backw_ctx,aout, SAMPLES-flush_i, 0, 0);
+ shift(aout, -flush_i, in_ch_count, in_sample_fmt);
+ if(flush_count){
+ for(ch=0; ch<in_ch_count; ch++){
+ double sse, maxdiff=0;
+ double sum_a= 0;
+ double sum_b= 0;
+ double sum_aa= 0;
+ double sum_bb= 0;
+ double sum_ab= 0;
+ for(i=0; i<flush_count; i++){
+ double a= get(ain , ch, i+out_count, in_ch_count, in_sample_fmt);
+ double b= get(aout, ch, i, in_ch_count, in_sample_fmt);
+ sum_a += a;
+ sum_b += b;
+ sum_aa+= a*a;
+ sum_bb+= b*b;
+ sum_ab+= a*b;
+ maxdiff= FFMAX(maxdiff, FFABS(a-b));
+ }
+ sse= sum_aa + sum_bb - 2*sum_ab;
+ if(sse < 0 && sse > -0.00001) sse=0; //fix rounding error
+
+ fprintf(stderr, "[e:%f c:%f max:%f] len:%5d F:%3d\n", sqrt(sse/flush_count), sum_ab/(sqrt(sum_aa*sum_bb)), maxdiff, flush_count, flush_i);
+ }
+ }
+
+
+ fprintf(stderr, "\n");
+ }
+
+ return 0;
+}
diff --git a/libswresample/swresample.c b/libswresample/swresample.c
new file mode 100644
index 0000000000..76b7a84956
--- /dev/null
+++ b/libswresample/swresample.c
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/opt.h"
+#include "swresample_internal.h"
+#include "audioconvert.h"
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/internal.h"
+
+#include <float.h>
+
+#define ALIGN 32
+
+#include "libavutil/ffversion.h"
+const char swr_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
+
+unsigned swresample_version(void)
+{
+ av_assert0(LIBSWRESAMPLE_VERSION_MICRO >= 100);
+ return LIBSWRESAMPLE_VERSION_INT;
+}
+
+const char *swresample_configuration(void)
+{
+ return FFMPEG_CONFIGURATION;
+}
+
+const char *swresample_license(void)
+{
+#define LICENSE_PREFIX "libswresample license: "
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+}
+
+int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map){
+ if(!s || s->in_convert) // s needs to be allocated but not initialized
+ return AVERROR(EINVAL);
+ s->channel_map = channel_map;
+ return 0;
+}
+
+struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
+ int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
+ int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
+ int log_offset, void *log_ctx){
+ if(!s) s= swr_alloc();
+ if(!s) return NULL;
+
+ s->log_level_offset= log_offset;
+ s->log_ctx= log_ctx;
+
+ if (av_opt_set_int(s, "ocl", out_ch_layout, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "osf", out_sample_fmt, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "osr", out_sample_rate, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "icl", in_ch_layout, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "isf", in_sample_fmt, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "isr", in_sample_rate, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "tsf", AV_SAMPLE_FMT_NONE, 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "ich", av_get_channel_layout_nb_channels(s-> user_in_ch_layout), 0) < 0)
+ goto fail;
+
+ if (av_opt_set_int(s, "och", av_get_channel_layout_nb_channels(s->user_out_ch_layout), 0) < 0)
+ goto fail;
+
+ av_opt_set_int(s, "uch", 0, 0);
+ return s;
+fail:
+ av_log(s, AV_LOG_ERROR, "Failed to set option\n");
+ swr_free(&s);
+ return NULL;
+}
+
+static void set_audiodata_fmt(AudioData *a, enum AVSampleFormat fmt){
+ a->fmt = fmt;
+ a->bps = av_get_bytes_per_sample(fmt);
+ a->planar= av_sample_fmt_is_planar(fmt);
+ if (a->ch_count == 1)
+ a->planar = 1;
+}
+
+static void free_temp(AudioData *a){
+ av_free(a->data);
+ memset(a, 0, sizeof(*a));
+}
+
+static void clear_context(SwrContext *s){
+ s->in_buffer_index= 0;
+ s->in_buffer_count= 0;
+ s->resample_in_constraint= 0;
+ memset(s->in.ch, 0, sizeof(s->in.ch));
+ memset(s->out.ch, 0, sizeof(s->out.ch));
+ free_temp(&s->postin);
+ free_temp(&s->midbuf);
+ free_temp(&s->preout);
+ free_temp(&s->in_buffer);
+ free_temp(&s->silence);
+ free_temp(&s->drop_temp);
+ free_temp(&s->dither.noise);
+ free_temp(&s->dither.temp);
+ swri_audio_convert_free(&s-> in_convert);
+ swri_audio_convert_free(&s->out_convert);
+ swri_audio_convert_free(&s->full_convert);
+ swri_rematrix_free(s);
+
+ s->flushed = 0;
+}
+
+av_cold void swr_free(SwrContext **ss){
+ SwrContext *s= *ss;
+ if(s){
+ clear_context(s);
+ if (s->resampler)
+ s->resampler->free(&s->resample);
+ }
+
+ av_freep(ss);
+}
+
+av_cold void swr_close(SwrContext *s){
+ clear_context(s);
+}
+
+av_cold int swr_init(struct SwrContext *s){
+ int ret;
+ char l1[1024], l2[1024];
+
+ clear_context(s);
+
+ if(s-> in_sample_fmt >= AV_SAMPLE_FMT_NB){
+ av_log(s, AV_LOG_ERROR, "Requested input sample format %d is invalid\n", s->in_sample_fmt);
+ return AVERROR(EINVAL);
+ }
+ if(s->out_sample_fmt >= AV_SAMPLE_FMT_NB){
+ av_log(s, AV_LOG_ERROR, "Requested output sample format %d is invalid\n", s->out_sample_fmt);
+ return AVERROR(EINVAL);
+ }
+
+ s->out.ch_count = s-> user_out_ch_count;
+ s-> in.ch_count = s-> user_in_ch_count;
+ s->used_ch_count = s->user_used_ch_count;
+
+ s-> in_ch_layout = s-> user_in_ch_layout;
+ s->out_ch_layout = s->user_out_ch_layout;
+
+ if(av_get_channel_layout_nb_channels(s-> in_ch_layout) > SWR_CH_MAX) {
+ av_log(s, AV_LOG_WARNING, "Input channel layout 0x%"PRIx64" is invalid or unsupported.\n", s-> in_ch_layout);
+ s->in_ch_layout = 0;
+ }
+
+ if(av_get_channel_layout_nb_channels(s->out_ch_layout) > SWR_CH_MAX) {
+ av_log(s, AV_LOG_WARNING, "Output channel layout 0x%"PRIx64" is invalid or unsupported.\n", s->out_ch_layout);
+ s->out_ch_layout = 0;
+ }
+
+ switch(s->engine){
+#if CONFIG_LIBSOXR
+ case SWR_ENGINE_SOXR: s->resampler = &swri_soxr_resampler; break;
+#endif
+ case SWR_ENGINE_SWR : s->resampler = &swri_resampler; break;
+ default:
+ av_log(s, AV_LOG_ERROR, "Requested resampling engine is unavailable\n");
+ return AVERROR(EINVAL);
+ }
+
+ if(!s->used_ch_count)
+ s->used_ch_count= s->in.ch_count;
+
+ if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){
+ av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n");
+ s-> in_ch_layout= 0;
+ }
+
+ if(!s-> in_ch_layout)
+ s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count);
+ if(!s->out_ch_layout)
+ s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count);
+
+ s->rematrix= s->out_ch_layout !=s->in_ch_layout || s->rematrix_volume!=1.0 ||
+ s->rematrix_custom;
+
+ if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){
+ if(av_get_planar_sample_fmt(s->in_sample_fmt) <= AV_SAMPLE_FMT_S16P){
+ s->int_sample_fmt= AV_SAMPLE_FMT_S16P;
+ }else if( av_get_planar_sample_fmt(s-> in_sample_fmt) == AV_SAMPLE_FMT_S32P
+ && av_get_planar_sample_fmt(s->out_sample_fmt) == AV_SAMPLE_FMT_S32P
+ && !s->rematrix
+ && s->engine != SWR_ENGINE_SOXR){
+ s->int_sample_fmt= AV_SAMPLE_FMT_S32P;
+ }else if(av_get_planar_sample_fmt(s->in_sample_fmt) <= AV_SAMPLE_FMT_FLTP){
+ s->int_sample_fmt= AV_SAMPLE_FMT_FLTP;
+ }else{
+ av_log(s, AV_LOG_DEBUG, "Using double precision mode\n");
+ s->int_sample_fmt= AV_SAMPLE_FMT_DBLP;
+ }
+ }
+
+ if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P
+ &&s->int_sample_fmt != AV_SAMPLE_FMT_S32P
+ &&s->int_sample_fmt != AV_SAMPLE_FMT_FLTP
+ &&s->int_sample_fmt != AV_SAMPLE_FMT_DBLP){
+ av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, S16/S32/FLT/DBL is supported\n", av_get_sample_fmt_name(s->int_sample_fmt));
+ return AVERROR(EINVAL);
+ }
+
+ set_audiodata_fmt(&s-> in, s-> in_sample_fmt);
+ set_audiodata_fmt(&s->out, s->out_sample_fmt);
+
+ if (s->firstpts_in_samples != AV_NOPTS_VALUE) {
+ if (!s->async && s->min_compensation >= FLT_MAX/2)
+ s->async = 1;
+ s->firstpts =
+ s->outpts = s->firstpts_in_samples * s->out_sample_rate;
+ } else
+ s->firstpts = AV_NOPTS_VALUE;
+
+ if (s->async) {
+ if (s->min_compensation >= FLT_MAX/2)
+ s->min_compensation = 0.001;
+ if (s->async > 1.0001) {
+ s->max_soft_compensation = s->async / (double) s->in_sample_rate;
+ }
+ }
+
+ if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){
+ s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby);
+ }else
+ s->resampler->free(&s->resample);
+ if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P
+ && s->int_sample_fmt != AV_SAMPLE_FMT_S32P
+ && s->int_sample_fmt != AV_SAMPLE_FMT_FLTP
+ && s->int_sample_fmt != AV_SAMPLE_FMT_DBLP
+ && s->resample){
+ av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16/s32/flt/dbl\n");
+ return -1;
+ }
+
+#define RSC 1 //FIXME finetune
+ if(!s-> in.ch_count)
+ s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout);
+ if(!s->used_ch_count)
+ s->used_ch_count= s->in.ch_count;
+ if(!s->out.ch_count)
+ s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout);
+
+ if(!s-> in.ch_count){
+ av_assert0(!s->in_ch_layout);
+ av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n");
+ return -1;
+ }
+
+ av_get_channel_layout_string(l1, sizeof(l1), s-> in.ch_count, s-> in_ch_layout);
+ av_get_channel_layout_string(l2, sizeof(l2), s->out.ch_count, s->out_ch_layout);
+ if (s->out_ch_layout && s->out.ch_count != av_get_channel_layout_nb_channels(s->out_ch_layout)) {
+ av_log(s, AV_LOG_ERROR, "Output channel layout %s mismatches specified channel count %d\n", l2, s->out.ch_count);
+ return AVERROR(EINVAL);
+ }
+ if (s->in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s->in_ch_layout)) {
+ av_log(s, AV_LOG_ERROR, "Input channel layout %s mismatches specified channel count %d\n", l1, s->used_ch_count);
+ return AVERROR(EINVAL);
+ }
+
+ if ((!s->out_ch_layout || !s->in_ch_layout) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) {
+ av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s "
+ "but there is not enough information to do it\n", l1, l2);
+ return -1;
+ }
+
+av_assert0(s->used_ch_count);
+av_assert0(s->out.ch_count);
+ s->resample_first= RSC*s->out.ch_count/s->in.ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0;
+
+ s->in_buffer= s->in;
+ s->silence = s->in;
+ s->drop_temp= s->out;
+
+ if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){
+ s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt,
+ s-> in_sample_fmt, s-> in.ch_count, NULL, 0);
+ return 0;
+ }
+
+ s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt,
+ s-> in_sample_fmt, s->used_ch_count, s->channel_map, 0);
+ s->out_convert= swri_audio_convert_alloc(s->out_sample_fmt,
+ s->int_sample_fmt, s->out.ch_count, NULL, 0);
+
+ if (!s->in_convert || !s->out_convert)
+ return AVERROR(ENOMEM);
+
+ s->postin= s->in;
+ s->preout= s->out;
+ s->midbuf= s->in;
+
+ if(s->channel_map){
+ s->postin.ch_count=
+ s->midbuf.ch_count= s->used_ch_count;
+ if(s->resample)
+ s->in_buffer.ch_count= s->used_ch_count;
+ }
+ if(!s->resample_first){
+ s->midbuf.ch_count= s->out.ch_count;
+ if(s->resample)
+ s->in_buffer.ch_count = s->out.ch_count;
+ }
+
+ set_audiodata_fmt(&s->postin, s->int_sample_fmt);
+ set_audiodata_fmt(&s->midbuf, s->int_sample_fmt);
+ set_audiodata_fmt(&s->preout, s->int_sample_fmt);
+
+ if(s->resample){
+ set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt);
+ }
+
+ if ((ret = swri_dither_init(s, s->out_sample_fmt, s->int_sample_fmt)) < 0)
+ return ret;
+
+ if(s->rematrix || s->dither.method)
+ return swri_rematrix_init(s);
+
+ return 0;
+}
+
+int swri_realloc_audio(AudioData *a, int count){
+ int i, countb;
+ AudioData old;
+
+ if(count < 0 || count > INT_MAX/2/a->bps/a->ch_count)
+ return AVERROR(EINVAL);
+
+ if(a->count >= count)
+ return 0;
+
+ count*=2;
+
+ countb= FFALIGN(count*a->bps, ALIGN);
+ old= *a;
+
+ av_assert0(a->bps);
+ av_assert0(a->ch_count);
+
+ a->data= av_mallocz_array(countb, a->ch_count);
+ if(!a->data)
+ return AVERROR(ENOMEM);
+ for(i=0; i<a->ch_count; i++){
+ a->ch[i]= a->data + i*(a->planar ? countb : a->bps);
+ if(a->planar) memcpy(a->ch[i], old.ch[i], a->count*a->bps);
+ }
+ if(!a->planar) memcpy(a->ch[0], old.ch[0], a->count*a->ch_count*a->bps);
+ av_freep(&old.data);
+ a->count= count;
+
+ return 1;
+}
+
+static void copy(AudioData *out, AudioData *in,
+ int count){
+ av_assert0(out->planar == in->planar);
+ av_assert0(out->bps == in->bps);
+ av_assert0(out->ch_count == in->ch_count);
+ if(out->planar){
+ int ch;
+ for(ch=0; ch<out->ch_count; ch++)
+ memcpy(out->ch[ch], in->ch[ch], count*out->bps);
+ }else
+ memcpy(out->ch[0], in->ch[0], count*out->ch_count*out->bps);
+}
+
+static void fill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){
+ int i;
+ if(!in_arg){
+ memset(out->ch, 0, sizeof(out->ch));
+ }else if(out->planar){
+ for(i=0; i<out->ch_count; i++)
+ out->ch[i]= in_arg[i];
+ }else{
+ for(i=0; i<out->ch_count; i++)
+ out->ch[i]= in_arg[0] + i*out->bps;
+ }
+}
+
+static void reversefill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){
+ int i;
+ if(out->planar){
+ for(i=0; i<out->ch_count; i++)
+ in_arg[i]= out->ch[i];
+ }else{
+ in_arg[0]= out->ch[0];
+ }
+}
+
+/**
+ *
+ * out may be equal in.
+ */
+static void buf_set(AudioData *out, AudioData *in, int count){
+ int ch;
+ if(in->planar){
+ for(ch=0; ch<out->ch_count; ch++)
+ out->ch[ch]= in->ch[ch] + count*out->bps;
+ }else{
+ for(ch=out->ch_count-1; ch>=0; ch--)
+ out->ch[ch]= in->ch[0] + (ch + count*out->ch_count) * out->bps;
+ }
+}
+
+/**
+ *
+ * @return number of samples output per channel
+ */
+static int resample(SwrContext *s, AudioData *out_param, int out_count,
+ const AudioData * in_param, int in_count){
+ AudioData in, out, tmp;
+ int ret_sum=0;
+ int border=0;
+ int padless = ARCH_X86 && s->engine == SWR_ENGINE_SWR ? 7 : 0;
+
+ av_assert1(s->in_buffer.ch_count == in_param->ch_count);
+ av_assert1(s->in_buffer.planar == in_param->planar);
+ av_assert1(s->in_buffer.fmt == in_param->fmt);
+
+ tmp=out=*out_param;
+ in = *in_param;
+
+ border = s->resampler->invert_initial_buffer(s->resample, &s->in_buffer,
+ &in, in_count, &s->in_buffer_index, &s->in_buffer_count);
+ if (border == INT_MAX) {
+ return 0;
+ } else if (border < 0) {
+ return border;
+ } else if (border) {
+ buf_set(&in, &in, border);
+ in_count -= border;
+ s->resample_in_constraint = 0;
+ }
+
+ do{
+ int ret, size, consumed;
+ if(!s->resample_in_constraint && s->in_buffer_count){
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index);
+ ret= s->resampler->multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed);
+ out_count -= ret;
+ ret_sum += ret;
+ buf_set(&out, &out, ret);
+ s->in_buffer_count -= consumed;
+ s->in_buffer_index += consumed;
+
+ if(!in_count)
+ break;
+ if(s->in_buffer_count <= border){
+ buf_set(&in, &in, -s->in_buffer_count);
+ in_count += s->in_buffer_count;
+ s->in_buffer_count=0;
+ s->in_buffer_index=0;
+ border = 0;
+ }
+ }
+
+ if((s->flushed || in_count > padless) && !s->in_buffer_count){
+ s->in_buffer_index=0;
+ ret= s->resampler->multiple_resample(s->resample, &out, out_count, &in, FFMAX(in_count-padless, 0), &consumed);
+ out_count -= ret;
+ ret_sum += ret;
+ buf_set(&out, &out, ret);
+ in_count -= consumed;
+ buf_set(&in, &in, consumed);
+ }
+
+ //TODO is this check sane considering the advanced copy avoidance below
+ size= s->in_buffer_index + s->in_buffer_count + in_count;
+ if( size > s->in_buffer.count
+ && s->in_buffer_count + in_count <= s->in_buffer_index){
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index);
+ copy(&s->in_buffer, &tmp, s->in_buffer_count);
+ s->in_buffer_index=0;
+ }else
+ if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0)
+ return ret;
+
+ if(in_count){
+ int count= in_count;
+ if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2;
+
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count);
+ copy(&tmp, &in, /*in_*/count);
+ s->in_buffer_count += count;
+ in_count -= count;
+ border += count;
+ buf_set(&in, &in, count);
+ s->resample_in_constraint= 0;
+ if(s->in_buffer_count != count || in_count)
+ continue;
+ if (padless) {
+ padless = 0;
+ continue;
+ }
+ }
+ break;
+ }while(1);
+
+ s->resample_in_constraint= !!out_count;
+
+ return ret_sum;
+}
+
+static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_count,
+ AudioData *in , int in_count){
+ AudioData *postin, *midbuf, *preout;
+ int ret/*, in_max*/;
+ AudioData preout_tmp, midbuf_tmp;
+
+ if(s->full_convert){
+ av_assert0(!s->resample);
+ swri_audio_convert(s->full_convert, out, in, in_count);
+ return out_count;
+ }
+
+// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps;
+// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count);
+
+ if((ret=swri_realloc_audio(&s->postin, in_count))<0)
+ return ret;
+ if(s->resample_first){
+ av_assert0(s->midbuf.ch_count == s->used_ch_count);
+ if((ret=swri_realloc_audio(&s->midbuf, out_count))<0)
+ return ret;
+ }else{
+ av_assert0(s->midbuf.ch_count == s->out.ch_count);
+ if((ret=swri_realloc_audio(&s->midbuf, in_count))<0)
+ return ret;
+ }
+ if((ret=swri_realloc_audio(&s->preout, out_count))<0)
+ return ret;
+
+ postin= &s->postin;
+
+ midbuf_tmp= s->midbuf;
+ midbuf= &midbuf_tmp;
+ preout_tmp= s->preout;
+ preout= &preout_tmp;
+
+ if(s->int_sample_fmt == s-> in_sample_fmt && s->in.planar && !s->channel_map)
+ postin= in;
+
+ if(s->resample_first ? !s->resample : !s->rematrix)
+ midbuf= postin;
+
+ if(s->resample_first ? !s->rematrix : !s->resample)
+ preout= midbuf;
+
+ if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar
+ && !(s->out_sample_fmt==AV_SAMPLE_FMT_S32P && (s->dither.output_sample_bits&31))){
+ if(preout==in){
+ out_count= FFMIN(out_count, in_count); //TODO check at the end if this is needed or redundant
+ av_assert0(s->in.planar); //we only support planar internally so it has to be, we support copying non planar though
+ copy(out, in, out_count);
+ return out_count;
+ }
+ else if(preout==postin) preout= midbuf= postin= out;
+ else if(preout==midbuf) preout= midbuf= out;
+ else preout= out;
+ }
+
+ if(in != postin){
+ swri_audio_convert(s->in_convert, postin, in, in_count);
+ }
+
+ if(s->resample_first){
+ if(postin != midbuf)
+ out_count= resample(s, midbuf, out_count, postin, in_count);
+ if(midbuf != preout)
+ swri_rematrix(s, preout, midbuf, out_count, preout==out);
+ }else{
+ if(postin != midbuf)
+ swri_rematrix(s, midbuf, postin, in_count, midbuf==out);
+ if(midbuf != preout)
+ out_count= resample(s, preout, out_count, midbuf, in_count);
+ }
+
+ if(preout != out && out_count){
+ AudioData *conv_src = preout;
+ if(s->dither.method){
+ int ch;
+ int dither_count= FFMAX(out_count, 1<<16);
+
+ if (preout == in) {
+ conv_src = &s->dither.temp;
+ if((ret=swri_realloc_audio(&s->dither.temp, dither_count))<0)
+ return ret;
+ }
+
+ if((ret=swri_realloc_audio(&s->dither.noise, dither_count))<0)
+ return ret;
+ if(ret)
+ for(ch=0; ch<s->dither.noise.ch_count; ch++)
+ swri_get_dither(s, s->dither.noise.ch[ch], s->dither.noise.count, 12345678913579<<ch, s->dither.noise.fmt);
+ av_assert0(s->dither.noise.ch_count == preout->ch_count);
+
+ if(s->dither.noise_pos + out_count > s->dither.noise.count)
+ s->dither.noise_pos = 0;
+
+ if (s->dither.method < SWR_DITHER_NS){
+ if (s->mix_2_1_simd) {
+ int len1= out_count&~15;
+ int off = len1 * preout->bps;
+
+ if(len1)
+ for(ch=0; ch<preout->ch_count; ch++)
+ s->mix_2_1_simd(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_simd_one, 0, 0, len1);
+ if(out_count != len1)
+ for(ch=0; ch<preout->ch_count; ch++)
+ s->mix_2_1_f(conv_src->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos + off + len1, s->native_one, 0, 0, out_count - len1);
+ } else {
+ for(ch=0; ch<preout->ch_count; ch++)
+ s->mix_2_1_f(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_one, 0, 0, out_count);
+ }
+ } else {
+ switch(s->int_sample_fmt) {
+ case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, conv_src, preout, &s->dither.noise, out_count); break;
+ case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, conv_src, preout, &s->dither.noise, out_count); break;
+ case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, conv_src, preout, &s->dither.noise, out_count); break;
+ case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,conv_src, preout, &s->dither.noise, out_count); break;
+ }
+ }
+ s->dither.noise_pos += out_count;
+ }
+//FIXME packed doesn't need more than 1 chan here!
+ swri_audio_convert(s->out_convert, out, conv_src, out_count);
+ }
+ return out_count;
+}
+
+int swr_is_initialized(struct SwrContext *s) {
+ return !!s->in_buffer.ch_count;
+}
+
+int attribute_align_arg swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count,
+ const uint8_t *in_arg [SWR_CH_MAX], int in_count){
+ AudioData * in= &s->in;
+ AudioData *out= &s->out;
+
+ if (!swr_is_initialized(s)) {
+ av_log(s, AV_LOG_ERROR, "Context has not been initialized\n");
+ return AVERROR(EINVAL);
+ }
+
+ while(s->drop_output > 0){
+ int ret;
+ uint8_t *tmp_arg[SWR_CH_MAX];
+#define MAX_DROP_STEP 16384
+ if((ret=swri_realloc_audio(&s->drop_temp, FFMIN(s->drop_output, MAX_DROP_STEP)))<0)
+ return ret;
+
+ reversefill_audiodata(&s->drop_temp, tmp_arg);
+ s->drop_output *= -1; //FIXME find a less hackish solution
+ ret = swr_convert(s, tmp_arg, FFMIN(-s->drop_output, MAX_DROP_STEP), in_arg, in_count); //FIXME optimize but this is as good as never called so maybe it doesn't matter
+ s->drop_output *= -1;
+ in_count = 0;
+ if(ret>0) {
+ s->drop_output -= ret;
+ if (!s->drop_output && !out_arg)
+ return 0;
+ continue;
+ }
+
+ av_assert0(s->drop_output);
+ return 0;
+ }
+
+ if(!in_arg){
+ if(s->resample){
+ if (!s->flushed)
+ s->resampler->flush(s);
+ s->resample_in_constraint = 0;
+ s->flushed = 1;
+ }else if(!s->in_buffer_count){
+ return 0;
+ }
+ }else
+ fill_audiodata(in , (void*)in_arg);
+
+ fill_audiodata(out, out_arg);
+
+ if(s->resample){
+ int ret = swr_convert_internal(s, out, out_count, in, in_count);
+ if(ret>0 && !s->drop_output)
+ s->outpts += ret * (int64_t)s->in_sample_rate;
+ return ret;
+ }else{
+ AudioData tmp= *in;
+ int ret2=0;
+ int ret, size;
+ size = FFMIN(out_count, s->in_buffer_count);
+ if(size){
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index);
+ ret= swr_convert_internal(s, out, size, &tmp, size);
+ if(ret<0)
+ return ret;
+ ret2= ret;
+ s->in_buffer_count -= ret;
+ s->in_buffer_index += ret;
+ buf_set(out, out, ret);
+ out_count -= ret;
+ if(!s->in_buffer_count)
+ s->in_buffer_index = 0;
+ }
+
+ if(in_count){
+ size= s->in_buffer_index + s->in_buffer_count + in_count - out_count;
+
+ if(in_count > out_count) { //FIXME move after swr_convert_internal
+ if( size > s->in_buffer.count
+ && s->in_buffer_count + in_count - out_count <= s->in_buffer_index){
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index);
+ copy(&s->in_buffer, &tmp, s->in_buffer_count);
+ s->in_buffer_index=0;
+ }else
+ if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0)
+ return ret;
+ }
+
+ if(out_count){
+ size = FFMIN(in_count, out_count);
+ ret= swr_convert_internal(s, out, size, in, size);
+ if(ret<0)
+ return ret;
+ buf_set(in, in, ret);
+ in_count -= ret;
+ ret2 += ret;
+ }
+ if(in_count){
+ buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count);
+ copy(&tmp, in, in_count);
+ s->in_buffer_count += in_count;
+ }
+ }
+ if(ret2>0 && !s->drop_output)
+ s->outpts += ret2 * (int64_t)s->in_sample_rate;
+ return ret2;
+ }
+}
+
+int swr_drop_output(struct SwrContext *s, int count){
+ const uint8_t *tmp_arg[SWR_CH_MAX];
+ s->drop_output += count;
+
+ if(s->drop_output <= 0)
+ return 0;
+
+ av_log(s, AV_LOG_VERBOSE, "discarding %d audio samples\n", count);
+ return swr_convert(s, NULL, s->drop_output, tmp_arg, 0);
+}
+
+int swr_inject_silence(struct SwrContext *s, int count){
+ int ret, i;
+ uint8_t *tmp_arg[SWR_CH_MAX];
+
+ if(count <= 0)
+ return 0;
+
+#define MAX_SILENCE_STEP 16384
+ while (count > MAX_SILENCE_STEP) {
+ if ((ret = swr_inject_silence(s, MAX_SILENCE_STEP)) < 0)
+ return ret;
+ count -= MAX_SILENCE_STEP;
+ }
+
+ if((ret=swri_realloc_audio(&s->silence, count))<0)
+ return ret;
+
+ if(s->silence.planar) for(i=0; i<s->silence.ch_count; i++) {
+ memset(s->silence.ch[i], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps);
+ } else
+ memset(s->silence.ch[0], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps*s->silence.ch_count);
+
+ reversefill_audiodata(&s->silence, tmp_arg);
+ av_log(s, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", count);
+ ret = swr_convert(s, NULL, 0, (const uint8_t**)tmp_arg, count);
+ return ret;
+}
+
+int64_t swr_get_delay(struct SwrContext *s, int64_t base){
+ if (s->resampler && s->resample){
+ return s->resampler->get_delay(s, base);
+ }else{
+ return (s->in_buffer_count*base + (s->in_sample_rate>>1))/ s->in_sample_rate;
+ }
+}
+
+int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance){
+ int ret;
+
+ if (!s || compensation_distance < 0)
+ return AVERROR(EINVAL);
+ if (!compensation_distance && sample_delta)
+ return AVERROR(EINVAL);
+ if (!s->resample) {
+ s->flags |= SWR_FLAG_RESAMPLE;
+ ret = swr_init(s);
+ if (ret < 0)
+ return ret;
+ }
+ if (!s->resampler->set_compensation){
+ return AVERROR(EINVAL);
+ }else{
+ return s->resampler->set_compensation(s->resample, sample_delta, compensation_distance);
+ }
+}
+
+int64_t swr_next_pts(struct SwrContext *s, int64_t pts){
+ if(pts == INT64_MIN)
+ return s->outpts;
+
+ if (s->firstpts == AV_NOPTS_VALUE)
+ s->outpts = s->firstpts = pts;
+
+ if(s->min_compensation >= FLT_MAX) {
+ return (s->outpts = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate));
+ } else {
+ int64_t delta = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate) - s->outpts + s->drop_output*(int64_t)s->in_sample_rate;
+ double fdelta = delta /(double)(s->in_sample_rate * (int64_t)s->out_sample_rate);
+
+ if(fabs(fdelta) > s->min_compensation) {
+ if(s->outpts == s->firstpts || fabs(fdelta) > s->min_hard_compensation){
+ int ret;
+ if(delta > 0) ret = swr_inject_silence(s, delta / s->out_sample_rate);
+ else ret = swr_drop_output (s, -delta / s-> in_sample_rate);
+ if(ret<0){
+ av_log(s, AV_LOG_ERROR, "Failed to compensate for timestamp delta of %f\n", fdelta);
+ }
+ } else if(s->soft_compensation_duration && s->max_soft_compensation) {
+ int duration = s->out_sample_rate * s->soft_compensation_duration;
+ double max_soft_compensation = s->max_soft_compensation / (s->max_soft_compensation < 0 ? -s->in_sample_rate : 1);
+ int comp = av_clipf(fdelta, -max_soft_compensation, max_soft_compensation) * duration ;
+ av_log(s, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", fdelta, comp, duration);
+ swr_set_compensation(s, comp, duration);
+ }
+ }
+
+ return s->outpts;
+ }
+}
diff --git a/libswresample/swresample.h b/libswresample/swresample.h
new file mode 100644
index 0000000000..37656a667d
--- /dev/null
+++ b/libswresample/swresample.h
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SWRESAMPLE_SWRESAMPLE_H
+#define SWRESAMPLE_SWRESAMPLE_H
+
+/**
+ * @file
+ * @ingroup lswr
+ * libswresample public header
+ */
+
+/**
+ * @defgroup lswr Libswresample
+ * @{
+ *
+ * Libswresample (lswr) is a library that handles audio resampling, sample
+ * format conversion and mixing.
+ *
+ * Interaction with lswr is done through SwrContext, which is
+ * allocated with swr_alloc() or swr_alloc_set_opts(). It is opaque, so all parameters
+ * must be set with the @ref avoptions API.
+ *
+ * The first thing you will need to do in order to use lswr is to allocate
+ * SwrContext. This can be done with swr_alloc() or swr_alloc_set_opts(). If you
+ * are using the former, you must set options through the @ref avoptions API.
+ * The latter function provides the same feature, but it allows you to set some
+ * common options in the same statement.
+ *
+ * For example the following code will setup conversion from planar float sample
+ * format to interleaved signed 16-bit integer, downsampling from 48kHz to
+ * 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing
+ * 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_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);
+ * av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+ * @endcode
+ *
+ * The same job can be done using swr_alloc_set_opts() as well:
+ * @code
+ * SwrContext *swr = swr_alloc_set_opts(NULL, // we're allocating a new context
+ * AV_CH_LAYOUT_STEREO, // out_ch_layout
+ * AV_SAMPLE_FMT_S16, // out_sample_fmt
+ * 44100, // out_sample_rate
+ * AV_CH_LAYOUT_5POINT1, // in_ch_layout
+ * AV_SAMPLE_FMT_FLTP, // in_sample_fmt
+ * 48000, // in_sample_rate
+ * 0, // log_offset
+ * NULL); // log_ctx
+ * @endcode
+ *
+ * Once all values have been set, it must be initialized with swr_init(). If
+ * you need to change the conversion parameters, you can change the parameters
+ * using @ref AVOptions, as described above in the first example; or by using
+ * swr_alloc_set_opts(), but with the first argument the allocated context.
+ * You must then call swr_init() again.
+ *
+ * The conversion itself is done by repeatedly calling swr_convert().
+ * Note that the samples may get buffered in swr if you provide insufficient
+ * output space or if sample rate conversion is done, which requires "future"
+ * samples. Samples that do not require future input can be retrieved at any
+ * time by using swr_convert() (in_count can be set to 0).
+ * At the end of conversion the resampling buffer can be flushed by calling
+ * swr_convert() with NULL in and 0 in_count.
+ *
+ * The samples used in the conversion process can be managed with the libavutil
+ * @ref lavu_sampmanip "samples manipulation" API, including av_samples_alloc()
+ * function used in the following example.
+ *
+ * The delay between input and output, can at any time be found by using
+ * swr_get_delay().
+ *
+ * The following code demonstrates the conversion loop assuming the parameters
+ * from above and caller-defined functions get_input() and handle_output():
+ * @code
+ * uint8_t **input;
+ * int in_samples;
+ *
+ * while (get_input(&input, &in_samples)) {
+ * uint8_t *output;
+ * int out_samples = av_rescale_rnd(swr_get_delay(swr, 48000) +
+ * in_samples, 44100, 48000, AV_ROUND_UP);
+ * av_samples_alloc(&output, NULL, 2, out_samples,
+ * AV_SAMPLE_FMT_S16, 0);
+ * out_samples = swr_convert(swr, &output, out_samples,
+ * input, in_samples);
+ * handle_output(output, out_samples);
+ * av_freep(&output);
+ * }
+ * @endcode
+ *
+ * When the conversion is finished, the conversion
+ * context and everything associated with it must be freed with swr_free().
+ * A swr_close() function is also available, but it exists mainly for
+ * compatibility with libavresample, and is not required to be called.
+ *
+ * There will be no memory leak if the data is not completely flushed before
+ * swr_free().
+ */
+
+#include <stdint.h>
+#include "libavutil/frame.h"
+#include "libavutil/samplefmt.h"
+
+#include "libswresample/version.h"
+
+#if LIBSWRESAMPLE_VERSION_MAJOR < 1
+#define SWR_CH_MAX 32 ///< Maximum number of channels
+#endif
+
+/**
+ * @name Option constants
+ * These constants are used for the @ref avoptions interface for lswr.
+ * @{
+ *
+ */
+
+#define SWR_FLAG_RESAMPLE 1 ///< Force resampling even if equal sample rate
+//TODO use int resample ?
+//long term TODO can we enable this dynamically?
+
+/** Dithering algorithms */
+enum SwrDitherType {
+ SWR_DITHER_NONE = 0,
+ SWR_DITHER_RECTANGULAR,
+ SWR_DITHER_TRIANGULAR,
+ SWR_DITHER_TRIANGULAR_HIGHPASS,
+
+ SWR_DITHER_NS = 64, ///< not part of API/ABI
+ SWR_DITHER_NS_LIPSHITZ,
+ SWR_DITHER_NS_F_WEIGHTED,
+ SWR_DITHER_NS_MODIFIED_E_WEIGHTED,
+ SWR_DITHER_NS_IMPROVED_E_WEIGHTED,
+ SWR_DITHER_NS_SHIBATA,
+ SWR_DITHER_NS_LOW_SHIBATA,
+ SWR_DITHER_NS_HIGH_SHIBATA,
+ SWR_DITHER_NB, ///< not part of API/ABI
+};
+
+/** Resampling Engines */
+enum SwrEngine {
+ SWR_ENGINE_SWR, /**< SW Resampler */
+ SWR_ENGINE_SOXR, /**< SoX Resampler */
+ SWR_ENGINE_NB, ///< not part of API/ABI
+};
+
+/** Resampling Filter Types */
+enum SwrFilterType {
+ SWR_FILTER_TYPE_CUBIC, /**< Cubic */
+ SWR_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */
+ SWR_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */
+};
+
+/**
+ * @}
+ */
+
+/**
+ * The libswresample context. Unlike libavcodec and libavformat, this structure
+ * is opaque. This means that if you would like to set options, you must use
+ * the @ref avoptions API and cannot directly set values to members of the
+ * structure.
+ */
+typedef struct SwrContext SwrContext;
+
+/**
+ * Get the AVClass for SwrContext. It can be used in combination with
+ * AV_OPT_SEARCH_FAKE_OBJ for examining options.
+ *
+ * @see av_opt_find().
+ * @return the AVClass of SwrContext
+ */
+const AVClass *swr_get_class(void);
+
+/**
+ * @name SwrContext constructor functions
+ * @{
+ */
+
+/**
+ * Allocate SwrContext.
+ *
+ * If you use this function you will need to set the parameters (manually or
+ * with swr_alloc_set_opts()) before calling swr_init().
+ *
+ * @see swr_alloc_set_opts(), swr_init(), swr_free()
+ * @return NULL on error, allocated context otherwise
+ */
+struct SwrContext *swr_alloc(void);
+
+/**
+ * Initialize context after user parameters have been set.
+ * @note The context must be configured using the AVOption API.
+ *
+ * @see av_opt_set_int()
+ * @see av_opt_set_dict()
+ *
+ * @param[in,out] s Swr context to initialize
+ * @return AVERROR error code in case of failure.
+ */
+int swr_init(struct SwrContext *s);
+
+/**
+ * Check whether an swr context has been initialized or not.
+ *
+ * @param[in] s Swr context to check
+ * @see swr_init()
+ * @return positive if it has been initialized, 0 if not initialized
+ */
+int swr_is_initialized(struct SwrContext *s);
+
+/**
+ * Allocate SwrContext if needed and set/reset common parameters.
+ *
+ * This function does not require s to be allocated with swr_alloc(). On the
+ * other hand, swr_alloc() can use swr_alloc_set_opts() to set the parameters
+ * on the allocated context.
+ *
+ * @param s existing Swr context if available, or NULL if not
+ * @param out_ch_layout output channel layout (AV_CH_LAYOUT_*)
+ * @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*).
+ * @param out_sample_rate output sample rate (frequency in Hz)
+ * @param in_ch_layout input channel layout (AV_CH_LAYOUT_*)
+ * @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*).
+ * @param in_sample_rate input sample rate (frequency in Hz)
+ * @param log_offset logging level offset
+ * @param log_ctx parent logging context, can be NULL
+ *
+ * @see swr_init(), swr_free()
+ * @return NULL on error, allocated context otherwise
+ */
+struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
+ int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
+ int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
+ int log_offset, void *log_ctx);
+
+/**
+ * @}
+ *
+ * @name SwrContext destructor functions
+ * @{
+ */
+
+/**
+ * Free the given SwrContext and set the pointer to NULL.
+ *
+ * @param[in] s a pointer to a pointer to Swr context
+ */
+void swr_free(struct SwrContext **s);
+
+/**
+ * Closes the context so that swr_is_initialized() returns 0.
+ *
+ * The context can be brought back to life by running swr_init(),
+ * swr_init() can also be used without swr_close().
+ * This function is mainly provided for simplifying the usecase
+ * where one tries to support libavresample and libswresample.
+ *
+ * @param[in,out] s Swr context to be closed
+ */
+void swr_close(struct SwrContext *s);
+
+/**
+ * @}
+ *
+ * @name Core conversion functions
+ * @{
+ */
+
+/** Convert audio.
+ *
+ * in and in_count can be set to 0 to flush the last few samples out at the
+ * end.
+ *
+ * If more input is provided than output space then the input will be buffered.
+ * You can avoid this buffering by providing more output space than input.
+ * Conversion will run directly without copying whenever possible.
+ *
+ * @param s allocated Swr context, with parameters set
+ * @param out output buffers, only the first one need be set in case of packed audio
+ * @param out_count amount of space available for output in samples per channel
+ * @param in input buffers, only the first one need to be set in case of packed audio
+ * @param in_count number of input samples available in one channel
+ *
+ * @return number of samples output per channel, negative value on error
+ */
+int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
+ const uint8_t **in , int in_count);
+
+/**
+ * Convert the next timestamp from input to output
+ * timestamps are in 1/(in_sample_rate * out_sample_rate) units.
+ *
+ * @note There are 2 slightly differently behaving modes.
+ * @li When automatic timestamp compensation is not used, (min_compensation >= FLT_MAX)
+ * in this case timestamps will be passed through with delays compensated
+ * @li When automatic timestamp compensation is used, (min_compensation < FLT_MAX)
+ * in this case the output timestamps will match output sample numbers.
+ * See ffmpeg-resampler(1) for the two modes of compensation.
+ *
+ * @param s[in] initialized Swr context
+ * @param pts[in] timestamp for the next input sample, INT64_MIN if unknown
+ * @see swr_set_compensation(), swr_drop_output(), and swr_inject_silence() are
+ * function used internally for timestamp compensation.
+ * @return the output timestamp for the next output sample
+ */
+int64_t swr_next_pts(struct SwrContext *s, int64_t pts);
+
+/**
+ * @}
+ *
+ * @name Low-level option setting functions
+ * These functons provide a means to set low-level options that is not possible
+ * with the AVOption API.
+ * @{
+ */
+
+/**
+ * Activate resampling compensation ("soft" compensation). This function is
+ * internally called when needed in swr_next_pts().
+ *
+ * @param[in,out] s allocated Swr context. If it is not initialized,
+ * or SWR_FLAG_RESAMPLE is not set, swr_init() is
+ * called with the flag set.
+ * @param[in] sample_delta delta in PTS per sample
+ * @param[in] compensation_distance number of samples to compensate for
+ * @return >= 0 on success, AVERROR error codes if:
+ * @li @c s is NULL,
+ * @li @c compensation_distance is less than 0,
+ * @li @c compensation_distance is 0 but sample_delta is not,
+ * @li compensation unsupported by resampler, or
+ * @li swr_init() fails when called.
+ */
+int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance);
+
+/**
+ * Set a customized input channel mapping.
+ *
+ * @param[in,out] s allocated Swr context, not yet initialized
+ * @param[in] channel_map customized input channel mapping (array of channel
+ * indexes, -1 for a muted channel)
+ * @return >= 0 on success, or AVERROR error code in case of failure.
+ */
+int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map);
+
+/**
+ * Set a customized remix matrix.
+ *
+ * @param s allocated Swr context, not yet initialized
+ * @param matrix remix coefficients; matrix[i + stride * o] is
+ * the weight of input channel i in output channel o
+ * @param stride offset between lines of the matrix
+ * @return >= 0 on success, or AVERROR error code in case of failure.
+ */
+int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride);
+
+/**
+ * @}
+ *
+ * @name Sample handling functions
+ * @{
+ */
+
+/**
+ * Drops the specified number of output samples.
+ *
+ * This function, along with swr_inject_silence(), is called by swr_next_pts()
+ * if needed for "hard" compensation.
+ *
+ * @param s allocated Swr context
+ * @param count number of samples to be dropped
+ *
+ * @return >= 0 on success, or a negative AVERROR code on failure
+ */
+int swr_drop_output(struct SwrContext *s, int count);
+
+/**
+ * Injects the specified number of silence samples.
+ *
+ * This function, along with swr_drop_output(), is called by swr_next_pts()
+ * if needed for "hard" compensation.
+ *
+ * @param s allocated Swr context
+ * @param count number of samples to be dropped
+ *
+ * @return >= 0 on success, or a negative AVERROR code on failure
+ */
+int swr_inject_silence(struct SwrContext *s, int count);
+
+/**
+ * Gets the delay the next input sample will experience relative to the next output sample.
+ *
+ * Swresample can buffer data if more input has been provided than available
+ * output space, also converting between sample rates needs a delay.
+ * This function returns the sum of all such delays.
+ * The exact delay is not necessarily an integer value in either input or
+ * output sample rate. Especially when downsampling by a large value, the
+ * output sample rate may be a poor choice to represent the delay, similarly
+ * for upsampling and the input sample rate.
+ *
+ * @param s swr context
+ * @param base timebase in which the returned delay will be:
+ * @li if it's set to 1 the returned delay is in seconds
+ * @li if it's set to 1000 the returned delay is in milliseconds
+ * @li if it's set to the input sample rate then the returned
+ * delay is in input samples
+ * @li if it's set to the output sample rate then the returned
+ * delay is in output samples
+ * @li if it's the least common multiple of in_sample_rate and
+ * out_sample_rate then an exact rounding-free delay will be
+ * returned
+ * @returns the delay in 1 / @c base units.
+ */
+int64_t swr_get_delay(struct SwrContext *s, int64_t base);
+
+/**
+ * @}
+ *
+ * @name Configuration accessors
+ * @{
+ */
+
+/**
+ * Return the @ref LIBSWRESAMPLE_VERSION_INT constant.
+ *
+ * This is useful to check if the build-time libswresample has the same version
+ * as the run-time one.
+ *
+ * @returns the unsigned int-typed version
+ */
+unsigned swresample_version(void);
+
+/**
+ * Return the swr build-time configuration.
+ *
+ * @returns the build-time @c ./configure flags
+ */
+const char *swresample_configuration(void);
+
+/**
+ * Return the swr license.
+ *
+ * @returns the license of libswresample, determined at build-time
+ */
+const char *swresample_license(void);
+
+/**
+ * @}
+ *
+ * @name AVFrame based API
+ * @{
+ */
+
+/**
+ * Convert the samples in the input AVFrame and write them to the output AVFrame.
+ *
+ * Input and output AVFrames must have channel_layout, sample_rate and format set.
+ *
+ * If the output AVFrame does not have the data pointers allocated the nb_samples
+ * field will be set using av_frame_get_buffer()
+ * is called to allocate the frame.
+ *
+ * The output AVFrame can be NULL or have fewer allocated samples than required.
+ * In this case, any remaining samples not written to the output will be added
+ * to an internal FIFO buffer, to be returned at the next call to this function
+ * or to swr_convert().
+ *
+ * If converting sample rate, there may be data remaining in the internal
+ * resampling delay buffer. swr_get_delay() tells the number of
+ * remaining samples. To get this data as output, call this function or
+ * swr_convert() with NULL input.
+ *
+ * If the SwrContext configuration does not match the output and
+ * input AVFrame settings the conversion does not take place and depending on
+ * which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED
+ * or the result of a bitwise-OR of them is returned.
+ *
+ * @see swr_delay()
+ * @see swr_convert()
+ * @see swr_get_delay()
+ *
+ * @param swr audio resample context
+ * @param output output AVFrame
+ * @param input input AVFrame
+ * @return 0 on success, AVERROR on failure or nonmatching
+ * configuration.
+ */
+int swr_convert_frame(SwrContext *swr,
+ AVFrame *output, const AVFrame *input);
+
+/**
+ * Configure or reconfigure the SwrContext using the information
+ * provided by the AVFrames.
+ *
+ * The original resampling context is reset even on failure.
+ * The function calls swr_close() internally if the context is open.
+ *
+ * @see swr_close();
+ *
+ * @param swr audio resample context
+ * @param output output AVFrame
+ * @param input input AVFrame
+ * @return 0 on success, AVERROR on failure.
+ */
+int swr_config_frame(SwrContext *swr, const AVFrame *out, const AVFrame *in);
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* SWRESAMPLE_SWRESAMPLE_H */
diff --git a/libswresample/swresample_frame.c b/libswresample/swresample_frame.c
new file mode 100644
index 0000000000..71d3ed711a
--- /dev/null
+++ b/libswresample/swresample_frame.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014 Luca Barbato <lu_zero@gentoo.org>
+ * Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "swresample_internal.h"
+#include "libavutil/frame.h"
+#include "libavutil/opt.h"
+
+int swr_config_frame(SwrContext *s, const AVFrame *out, const AVFrame *in)
+{
+ swr_close(s);
+
+ if (in) {
+ if (av_opt_set_int(s, "icl", in->channel_layout, 0) < 0)
+ goto fail;
+ if (av_opt_set_int(s, "isf", in->format, 0) < 0)
+ goto fail;
+ if (av_opt_set_int(s, "isr", in->sample_rate, 0) < 0)
+ goto fail;
+ }
+
+ if (out) {
+ if (av_opt_set_int(s, "ocl", out->channel_layout, 0) < 0)
+ goto fail;
+ if (av_opt_set_int(s, "osf", out->format, 0) < 0)
+ goto fail;
+ if (av_opt_set_int(s, "osr", out->sample_rate, 0) < 0)
+ goto fail;
+ }
+
+ return 0;
+fail:
+ av_log(s, AV_LOG_ERROR, "Failed to set option\n");
+ return AVERROR(EINVAL);
+}
+
+static int config_changed(SwrContext *s,
+ const AVFrame *out, const AVFrame *in)
+{
+ int ret = 0;
+
+ if (in) {
+ if (s->in_ch_layout != in->channel_layout ||
+ s->in_sample_rate != in->sample_rate ||
+ s->in_sample_fmt != in->format) {
+ ret |= AVERROR_INPUT_CHANGED;
+ }
+ }
+
+ if (out) {
+ if (s->out_ch_layout != out->channel_layout ||
+ s->out_sample_rate != out->sample_rate ||
+ s->out_sample_fmt != out->format) {
+ ret |= AVERROR_OUTPUT_CHANGED;
+ }
+ }
+
+ return ret;
+}
+
+static inline int convert_frame(SwrContext *s,
+ AVFrame *out, const AVFrame *in)
+{
+ int ret;
+ uint8_t **out_data = NULL;
+ const uint8_t **in_data = NULL;
+ int out_nb_samples = 0, in_nb_samples = 0;
+
+ if (out) {
+ out_data = out->extended_data;
+ out_nb_samples = out->nb_samples;
+ }
+
+ if (in) {
+ in_data = (const uint8_t **)in->extended_data;
+ in_nb_samples = in->nb_samples;
+ }
+
+ ret = swr_convert(s, out_data, out_nb_samples, in_data, in_nb_samples);
+
+ if (ret < 0) {
+ if (out)
+ out->nb_samples = 0;
+ return ret;
+ }
+
+ if (out)
+ out->nb_samples = ret;
+
+ return 0;
+}
+
+static inline int available_samples(AVFrame *out)
+{
+ int bytes_per_sample = av_get_bytes_per_sample(out->format);
+ int samples = out->linesize[0] / bytes_per_sample;
+
+ if (av_sample_fmt_is_planar(out->format)) {
+ return samples;
+ } else {
+ int channels = av_get_channel_layout_nb_channels(out->channel_layout);
+ return samples / channels;
+ }
+}
+
+int swr_convert_frame(SwrContext *s,
+ AVFrame *out, const AVFrame *in)
+{
+ int ret, setup = 0;
+
+ if (!swr_is_initialized(s)) {
+ if ((ret = swr_config_frame(s, out, in)) < 0)
+ return ret;
+ if ((ret = swr_init(s)) < 0)
+ return ret;
+ setup = 1;
+ } else {
+ // return as is or reconfigure for input changes?
+ if ((ret = config_changed(s, out, in)))
+ return ret;
+ }
+
+ if (out) {
+ if (!out->linesize[0]) {
+ out->nb_samples = swr_get_delay(s, s->out_sample_rate)
+ + in->nb_samples*(int64_t)s->out_sample_rate / s->in_sample_rate
+ + 3;
+ if ((ret = av_frame_get_buffer(out, 0)) < 0) {
+ if (setup)
+ swr_close(s);
+ return ret;
+ }
+ } else {
+ if (!out->nb_samples)
+ out->nb_samples = available_samples(out);
+ }
+ }
+
+ return convert_frame(s, out, in);
+}
+
diff --git a/libswresample/swresample_internal.h b/libswresample/swresample_internal.h
new file mode 100644
index 0000000000..7296a3f772
--- /dev/null
+++ b/libswresample/swresample_internal.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SWR_INTERNAL_H
+#define SWR_INTERNAL_H
+
+#include "swresample.h"
+#include "libavutil/channel_layout.h"
+#include "config.h"
+
+#define SWR_CH_MAX 32
+
+#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */
+
+#define NS_TAPS 20
+
+#if ARCH_X86_64
+typedef int64_t integer;
+#else
+typedef int integer;
+#endif
+
+typedef void (mix_1_1_func_type)(void *out, const void *in, void *coeffp, integer index, integer len);
+typedef void (mix_2_1_func_type)(void *out, const void *in1, const void *in2, void *coeffp, integer index1, integer index2, integer len);
+
+typedef void (mix_any_func_type)(uint8_t **out, const uint8_t **in1, void *coeffp, integer len);
+
+typedef struct AudioData{
+ uint8_t *ch[SWR_CH_MAX]; ///< samples buffer per channel
+ uint8_t *data; ///< samples buffer
+ int ch_count; ///< number of channels
+ int bps; ///< bytes per sample
+ int count; ///< number of samples
+ int planar; ///< 1 if planar audio, 0 otherwise
+ enum AVSampleFormat fmt; ///< sample format
+} AudioData;
+
+struct DitherContext {
+ int method;
+ int noise_pos;
+ float scale;
+ float noise_scale; ///< Noise scale
+ int ns_taps; ///< Noise shaping dither taps
+ float ns_scale; ///< Noise shaping dither scale
+ float ns_scale_1; ///< Noise shaping dither scale^-1
+ int ns_pos; ///< Noise shaping dither position
+ float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients
+ float ns_errors[SWR_CH_MAX][2*NS_TAPS];
+ AudioData noise; ///< noise used for dithering
+ AudioData temp; ///< temporary storage when writing into the input buffer isn't possible
+ int output_sample_bits; ///< the number of used output bits, needed to scale dither correctly
+};
+
+typedef struct ResampleContext * (* resample_init_func)(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear,
+ double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, int kaiser_beta, double precision, int cheby);
+typedef void (* resample_free_func)(struct ResampleContext **c);
+typedef int (* multiple_resample_func)(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed);
+typedef int (* resample_flush_func)(struct SwrContext *c);
+typedef int (* set_compensation_func)(struct ResampleContext *c, int sample_delta, int compensation_distance);
+typedef int64_t (* get_delay_func)(struct SwrContext *s, int64_t base);
+typedef int (* invert_initial_buffer_func)(struct ResampleContext *c, AudioData *dst, const AudioData *src, int src_size, int *dst_idx, int *dst_count);
+
+struct Resampler {
+ resample_init_func init;
+ resample_free_func free;
+ multiple_resample_func multiple_resample;
+ resample_flush_func flush;
+ set_compensation_func set_compensation;
+ get_delay_func get_delay;
+ invert_initial_buffer_func invert_initial_buffer;
+};
+
+extern struct Resampler const swri_resampler;
+extern struct Resampler const swri_soxr_resampler;
+
+struct SwrContext {
+ const AVClass *av_class; ///< AVClass used for AVOption and av_log()
+ int log_level_offset; ///< logging level offset
+ void *log_ctx; ///< parent logging context
+ enum AVSampleFormat in_sample_fmt; ///< input sample format
+ enum AVSampleFormat int_sample_fmt; ///< internal sample format (AV_SAMPLE_FMT_FLTP or AV_SAMPLE_FMT_S16P)
+ enum AVSampleFormat out_sample_fmt; ///< output sample format
+ int64_t in_ch_layout; ///< input channel layout
+ int64_t out_ch_layout; ///< output channel layout
+ int in_sample_rate; ///< input sample rate
+ int out_sample_rate; ///< output sample rate
+ int flags; ///< miscellaneous flags such as SWR_FLAG_RESAMPLE
+ float slev; ///< surround mixing level
+ float clev; ///< center mixing level
+ float lfe_mix_level; ///< LFE mixing level
+ float rematrix_volume; ///< rematrixing volume coefficient
+ float rematrix_maxval; ///< maximum value for rematrixing output
+ int matrix_encoding; /**< matrixed stereo encoding */
+ const int *channel_map; ///< channel index (or -1 if muted channel) map
+ int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count)
+ int engine;
+
+ int user_in_ch_count; ///< User set input channel count
+ int user_out_ch_count; ///< User set output channel count
+ int user_used_ch_count; ///< User set used channel count
+ int64_t user_in_ch_layout; ///< User set input channel layout
+ int64_t user_out_ch_layout; ///< User set output channel layout
+
+ struct DitherContext dither;
+
+ int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
+ int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */
+ int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */
+ double cutoff; /**< resampling cutoff frequency (swr: 6dB point; soxr: 0dB point). 1.0 corresponds to half the output sample rate */
+ int filter_type; /**< swr resampling filter type */
+ int kaiser_beta; /**< swr beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */
+ double precision; /**< soxr resampling precision (in bits) */
+ int cheby; /**< soxr: if 1 then passband rolloff will be none (Chebyshev) & irrational ratio approximation precision will be higher */
+
+ float min_compensation; ///< swr minimum below which no compensation will happen
+ float min_hard_compensation; ///< swr minimum below which no silence inject / sample drop will happen
+ float soft_compensation_duration; ///< swr duration over which soft compensation is applied
+ float max_soft_compensation; ///< swr maximum soft compensation in seconds over soft_compensation_duration
+ float async; ///< swr simple 1 parameter async, similar to ffmpegs -async
+ int64_t firstpts_in_samples; ///< swr first pts in samples
+
+ int resample_first; ///< 1 if resampling must come first, 0 if rematrixing
+ int rematrix; ///< flag to indicate if rematrixing is needed (basically if input and output layouts mismatch)
+ int rematrix_custom; ///< flag to indicate that a custom matrix has been defined
+
+ AudioData in; ///< input audio data
+ AudioData postin; ///< post-input audio data: used for rematrix/resample
+ AudioData midbuf; ///< intermediate audio data (postin/preout)
+ AudioData preout; ///< pre-output audio data: used for rematrix/resample
+ AudioData out; ///< converted output audio data
+ AudioData in_buffer; ///< cached audio data (convert and resample purpose)
+ AudioData silence; ///< temporary with silence
+ AudioData drop_temp; ///< temporary used to discard output
+ int in_buffer_index; ///< cached buffer position
+ int in_buffer_count; ///< cached buffer length
+ int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise
+ int flushed; ///< 1 if data is to be flushed and no further input is expected
+ int64_t outpts; ///< output PTS
+ int64_t firstpts; ///< first PTS
+ int drop_output; ///< number of output samples to drop
+
+ struct AudioConvert *in_convert; ///< input conversion context
+ struct AudioConvert *out_convert; ///< output conversion context
+ struct AudioConvert *full_convert; ///< full conversion context (single conversion for input and output)
+ struct ResampleContext *resample; ///< resampling context
+ struct Resampler const *resampler; ///< resampler virtual function table
+
+ float matrix[SWR_CH_MAX][SWR_CH_MAX]; ///< floating point rematrixing coefficients
+ uint8_t *native_matrix;
+ uint8_t *native_one;
+ uint8_t *native_simd_one;
+ uint8_t *native_simd_matrix;
+ int32_t matrix32[SWR_CH_MAX][SWR_CH_MAX]; ///< 17.15 fixed point rematrixing coefficients
+ uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1]; ///< Lists of input channels per output channel that have non zero rematrixing coefficients
+ mix_1_1_func_type *mix_1_1_f;
+ mix_1_1_func_type *mix_1_1_simd;
+
+ mix_2_1_func_type *mix_2_1_f;
+ mix_2_1_func_type *mix_2_1_simd;
+
+ mix_any_func_type *mix_any_f;
+
+ /* TODO: callbacks for ASM optimizations */
+};
+
+int swri_realloc_audio(AudioData *a, int count);
+
+void swri_noise_shaping_int16 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count);
+void swri_noise_shaping_int32 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count);
+void swri_noise_shaping_float (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count);
+void swri_noise_shaping_double(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count);
+
+int swri_rematrix_init(SwrContext *s);
+void swri_rematrix_free(SwrContext *s);
+int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy);
+int swri_rematrix_init_x86(struct SwrContext *s);
+
+void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt);
+int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt);
+
+void swri_audio_convert_init_aarch64(struct AudioConvert *ac,
+ enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels);
+void swri_audio_convert_init_arm(struct AudioConvert *ac,
+ enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels);
+void swri_audio_convert_init_x86(struct AudioConvert *ac,
+ enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels);
+
+#endif
diff --git a/libswresample/swresampleres.rc b/libswresample/swresampleres.rc
new file mode 100644
index 0000000000..1320f78b9a
--- /dev/null
+++ b/libswresample/swresampleres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libswresample
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libswresample/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, 0
+PRODUCTVERSION LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg audio resampling library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBSWRESAMPLE_VERSION)
+ VALUE "InternalName", "libswresample"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "swresample" BUILDSUF "-" AV_STRINGIFY(LIBSWRESAMPLE_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libswresample/version.h b/libswresample/version.h
new file mode 100644
index 0000000000..61c76fa2f4
--- /dev/null
+++ b/libswresample/version.h
@@ -0,0 +1,45 @@
+/*
+ * Version macros.
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SWR_VERSION_H
+#define SWR_VERSION_H
+
+/**
+ * @file
+ * Libswresample version macros
+ */
+
+#include "libavutil/avutil.h"
+
+#define LIBSWRESAMPLE_VERSION_MAJOR 1
+#define LIBSWRESAMPLE_VERSION_MINOR 1
+#define LIBSWRESAMPLE_VERSION_MICRO 100
+
+#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \
+ LIBSWRESAMPLE_VERSION_MINOR, \
+ LIBSWRESAMPLE_VERSION_MICRO)
+#define LIBSWRESAMPLE_VERSION AV_VERSION(LIBSWRESAMPLE_VERSION_MAJOR, \
+ LIBSWRESAMPLE_VERSION_MINOR, \
+ LIBSWRESAMPLE_VERSION_MICRO)
+#define LIBSWRESAMPLE_BUILD LIBSWRESAMPLE_VERSION_INT
+
+#define LIBSWRESAMPLE_IDENT "SwR" AV_STRINGIFY(LIBSWRESAMPLE_VERSION)
+
+#endif /* SWR_VERSION_H */
diff --git a/libswresample/x86/Makefile b/libswresample/x86/Makefile
new file mode 100644
index 0000000000..be44df56aa
--- /dev/null
+++ b/libswresample/x86/Makefile
@@ -0,0 +1,9 @@
+YASM-OBJS += x86/audio_convert.o\
+ x86/rematrix.o\
+ x86/resample.o\
+
+OBJS += x86/audio_convert_init.o\
+ x86/rematrix_init.o\
+ x86/resample_init.o\
+
+OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
diff --git a/libswresample/x86/audio_convert.asm b/libswresample/x86/audio_convert.asm
new file mode 100644
index 0000000000..69e4f0538b
--- /dev/null
+++ b/libswresample/x86/audio_convert.asm
@@ -0,0 +1,739 @@
+;******************************************************************************
+;* Copyright (c) 2012 Michael Niedermayer
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+flt2pm31: times 8 dd 4.6566129e-10
+flt2p31 : times 8 dd 2147483648.0
+flt2p15 : times 8 dd 32768.0
+
+word_unpack_shuf : db 0, 1, 4, 5, 8, 9,12,13, 2, 3, 6, 7,10,11,14,15
+
+SECTION .text
+
+
+;to, from, a/u, log2_outsize, log_intsize, const
+%macro PACK_2CH 5-7
+cglobal pack_2ch_%2_to_%1_%3, 3, 4, 6, dst, src, len, src2
+ mov src2q , [srcq+gprsize]
+ mov srcq , [srcq]
+ mov dstq , [dstq]
+%ifidn %3, a
+ test dstq, mmsize-1
+ jne pack_2ch_%2_to_%1_u_int %+ SUFFIX
+ test srcq, mmsize-1
+ jne pack_2ch_%2_to_%1_u_int %+ SUFFIX
+ test src2q, mmsize-1
+ jne pack_2ch_%2_to_%1_u_int %+ SUFFIX
+%else
+pack_2ch_%2_to_%1_u_int %+ SUFFIX
+%endif
+ lea srcq , [srcq + (1<<%5)*lenq]
+ lea src2q, [src2q + (1<<%5)*lenq]
+ lea dstq , [dstq + (2<<%4)*lenq]
+ neg lenq
+ %7 m0,m1,m2,m3,m4,m5
+.next:
+%if %4 >= %5
+ mov%3 m0, [ srcq +(1<<%5)*lenq]
+ mova m1, m0
+ mov%3 m2, [ src2q+(1<<%5)*lenq]
+%if %5 == 1
+ punpcklwd m0, m2
+ punpckhwd m1, m2
+%else
+ punpckldq m0, m2
+ punpckhdq m1, m2
+%endif
+ %6 m0,m1,m2,m3,m4,m5
+%else
+ mov%3 m0, [ srcq +(1<<%5)*lenq]
+ mov%3 m1, [mmsize + srcq +(1<<%5)*lenq]
+ mov%3 m2, [ src2q+(1<<%5)*lenq]
+ mov%3 m3, [mmsize + src2q+(1<<%5)*lenq]
+ %6 m0,m1,m2,m3,m4,m5
+ mova m2, m0
+ punpcklwd m0, m1
+ punpckhwd m2, m1
+ SWAP 1,2
+%endif
+ mov%3 [ dstq+(2<<%4)*lenq], m0
+ mov%3 [ mmsize + dstq+(2<<%4)*lenq], m1
+%if %4 > %5
+ mov%3 [2*mmsize + dstq+(2<<%4)*lenq], m2
+ mov%3 [3*mmsize + dstq+(2<<%4)*lenq], m3
+ add lenq, 4*mmsize/(2<<%4)
+%else
+ add lenq, 2*mmsize/(2<<%4)
+%endif
+ jl .next
+ REP_RET
+%endmacro
+
+%macro UNPACK_2CH 5-7
+cglobal unpack_2ch_%2_to_%1_%3, 3, 4, 7, dst, src, len, dst2
+ mov dst2q , [dstq+gprsize]
+ mov srcq , [srcq]
+ mov dstq , [dstq]
+%ifidn %3, a
+ test dstq, mmsize-1
+ jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+ test srcq, mmsize-1
+ jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+ test dst2q, mmsize-1
+ jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+%else
+unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+%endif
+ lea srcq , [srcq + (2<<%5)*lenq]
+ lea dstq , [dstq + (1<<%4)*lenq]
+ lea dst2q, [dst2q + (1<<%4)*lenq]
+ neg lenq
+ %7 m0,m1,m2,m3,m4,m5
+ mova m6, [word_unpack_shuf]
+.next:
+ mov%3 m0, [ srcq +(2<<%5)*lenq]
+ mov%3 m2, [ mmsize + srcq +(2<<%5)*lenq]
+%if %5 == 1
+%ifidn SUFFIX, _ssse3
+ pshufb m0, m6
+ mova m1, m0
+ pshufb m2, m6
+ punpcklqdq m0,m2
+ punpckhqdq m1,m2
+%else
+ mova m1, m0
+ punpcklwd m0,m2
+ punpckhwd m1,m2
+
+ mova m2, m0
+ punpcklwd m0,m1
+ punpckhwd m2,m1
+
+ mova m1, m0
+ punpcklwd m0,m2
+ punpckhwd m1,m2
+%endif
+%else
+ mova m1, m0
+ shufps m0, m2, 10001000b
+ shufps m1, m2, 11011101b
+%endif
+%if %4 < %5
+ mov%3 m2, [2*mmsize + srcq +(2<<%5)*lenq]
+ mova m3, m2
+ mov%3 m4, [3*mmsize + srcq +(2<<%5)*lenq]
+ shufps m2, m4, 10001000b
+ shufps m3, m4, 11011101b
+ SWAP 1,2
+%endif
+ %6 m0,m1,m2,m3,m4,m5
+ mov%3 [ dstq+(1<<%4)*lenq], m0
+%if %4 > %5
+ mov%3 [ dst2q+(1<<%4)*lenq], m2
+ mov%3 [ mmsize + dstq+(1<<%4)*lenq], m1
+ mov%3 [ mmsize + dst2q+(1<<%4)*lenq], m3
+ add lenq, 2*mmsize/(1<<%4)
+%else
+ mov%3 [ dst2q+(1<<%4)*lenq], m1
+ add lenq, mmsize/(1<<%4)
+%endif
+ jl .next
+ REP_RET
+%endmacro
+
+%macro CONV 5-7
+cglobal %2_to_%1_%3, 3, 3, 6, dst, src, len
+ mov srcq , [srcq]
+ mov dstq , [dstq]
+%ifidn %3, a
+ test dstq, mmsize-1
+ jne %2_to_%1_u_int %+ SUFFIX
+ test srcq, mmsize-1
+ jne %2_to_%1_u_int %+ SUFFIX
+%else
+%2_to_%1_u_int %+ SUFFIX
+%endif
+ lea srcq , [srcq + (1<<%5)*lenq]
+ lea dstq , [dstq + (1<<%4)*lenq]
+ neg lenq
+ %7 m0,m1,m2,m3,m4,m5
+.next:
+ mov%3 m0, [ srcq +(1<<%5)*lenq]
+ mov%3 m1, [ mmsize + srcq +(1<<%5)*lenq]
+%if %4 < %5
+ mov%3 m2, [2*mmsize + srcq +(1<<%5)*lenq]
+ mov%3 m3, [3*mmsize + srcq +(1<<%5)*lenq]
+%endif
+ %6 m0,m1,m2,m3,m4,m5
+ mov%3 [ dstq+(1<<%4)*lenq], m0
+ mov%3 [ mmsize + dstq+(1<<%4)*lenq], m1
+%if %4 > %5
+ mov%3 [2*mmsize + dstq+(1<<%4)*lenq], m2
+ mov%3 [3*mmsize + dstq+(1<<%4)*lenq], m3
+ add lenq, 4*mmsize/(1<<%4)
+%else
+ add lenq, 2*mmsize/(1<<%4)
+%endif
+ jl .next
+%if mmsize == 8
+ emms
+ RET
+%else
+ REP_RET
+%endif
+%endmacro
+
+%macro PACK_6CH 5-7
+cglobal pack_6ch_%2_to_%1_%3, 2,8,7, dst, src, src1, src2, src3, src4, src5, len
+%if ARCH_X86_64
+ mov lend, r2d
+%else
+ %define lend dword r2m
+%endif
+ mov src1q, [srcq+1*gprsize]
+ mov src2q, [srcq+2*gprsize]
+ mov src3q, [srcq+3*gprsize]
+ mov src4q, [srcq+4*gprsize]
+ mov src5q, [srcq+5*gprsize]
+ mov srcq, [srcq]
+ mov dstq, [dstq]
+%ifidn %3, a
+ test dstq, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test srcq, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test src1q, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test src2q, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test src3q, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test src4q, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test src5q, mmsize-1
+ jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+%else
+pack_6ch_%2_to_%1_u_int %+ SUFFIX
+%endif
+ sub src1q, srcq
+ sub src2q, srcq
+ sub src3q, srcq
+ sub src4q, srcq
+ sub src5q, srcq
+ %7 x,x,x,x,m7,x
+.loop:
+ mov%3 m0, [srcq ]
+ mov%3 m1, [srcq+src1q]
+ mov%3 m2, [srcq+src2q]
+ mov%3 m3, [srcq+src3q]
+ mov%3 m4, [srcq+src4q]
+ mov%3 m5, [srcq+src5q]
+%if cpuflag(sse)
+ SBUTTERFLYPS 0, 1, 6
+ SBUTTERFLYPS 2, 3, 6
+ SBUTTERFLYPS 4, 5, 6
+
+%if cpuflag(avx)
+ blendps m6, m4, m0, 1100b
+%else
+ movaps m6, m4
+ shufps m4, m0, q3210
+ SWAP 4,6
+%endif
+ movlhps m0, m2
+ movhlps m4, m2
+%if cpuflag(avx)
+ blendps m2, m5, m1, 1100b
+%else
+ movaps m2, m5
+ shufps m5, m1, q3210
+ SWAP 2,5
+%endif
+ movlhps m1, m3
+ movhlps m5, m3
+
+ %6 m0,m6,x,x,m7,m3
+ %6 m4,m1,x,x,m7,m3
+ %6 m2,m5,x,x,m7,m3
+
+ mov %+ %3 %+ ps [dstq ], m0
+ mov %+ %3 %+ ps [dstq+16], m6
+ mov %+ %3 %+ ps [dstq+32], m4
+ mov %+ %3 %+ ps [dstq+48], m1
+ mov %+ %3 %+ ps [dstq+64], m2
+ mov %+ %3 %+ ps [dstq+80], m5
+%else ; mmx
+ SBUTTERFLY dq, 0, 1, 6
+ SBUTTERFLY dq, 2, 3, 6
+ SBUTTERFLY dq, 4, 5, 6
+
+ movq [dstq ], m0
+ movq [dstq+ 8], m2
+ movq [dstq+16], m4
+ movq [dstq+24], m1
+ movq [dstq+32], m3
+ movq [dstq+40], m5
+%endif
+ add srcq, mmsize
+ add dstq, mmsize*6
+ sub lend, mmsize/4
+ jg .loop
+%if mmsize == 8
+ emms
+ RET
+%else
+ REP_RET
+%endif
+%endmacro
+
+%macro UNPACK_6CH 5-7
+cglobal unpack_6ch_%2_to_%1_%3, 2, 8, 8, dst, src, dst1, dst2, dst3, dst4, dst5, len
+%if ARCH_X86_64
+ mov lend, r2d
+%else
+ %define lend dword r2m
+%endif
+ mov dst1q, [dstq+1*gprsize]
+ mov dst2q, [dstq+2*gprsize]
+ mov dst3q, [dstq+3*gprsize]
+ mov dst4q, [dstq+4*gprsize]
+ mov dst5q, [dstq+5*gprsize]
+ mov dstq, [dstq]
+ mov srcq, [srcq]
+%ifidn %3, a
+ test dstq, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test srcq, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test dst1q, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test dst2q, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test dst3q, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test dst4q, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+ test dst5q, mmsize-1
+ jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+%else
+unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+%endif
+ sub dst1q, dstq
+ sub dst2q, dstq
+ sub dst3q, dstq
+ sub dst4q, dstq
+ sub dst5q, dstq
+ %7 x,x,x,x,m7,x
+.loop:
+ mov%3 m0, [srcq ]
+ mov%3 m1, [srcq+16]
+ mov%3 m2, [srcq+32]
+ mov%3 m3, [srcq+48]
+ mov%3 m4, [srcq+64]
+ mov%3 m5, [srcq+80]
+
+ SBUTTERFLYPS 0, 3, 6
+ SBUTTERFLYPS 1, 4, 6
+ SBUTTERFLYPS 2, 5, 6
+ SBUTTERFLYPS 0, 4, 6
+ SBUTTERFLYPS 3, 2, 6
+ SBUTTERFLYPS 1, 5, 6
+ SWAP 1, 4
+ SWAP 2, 3
+
+ %6 m0,m1,x,x,m7,m6
+ %6 m2,m3,x,x,m7,m6
+ %6 m4,m5,x,x,m7,m6
+
+ mov %+ %3 %+ ps [dstq ], m0
+ mov %+ %3 %+ ps [dstq+dst1q], m1
+ mov %+ %3 %+ ps [dstq+dst2q], m2
+ mov %+ %3 %+ ps [dstq+dst3q], m3
+ mov %+ %3 %+ ps [dstq+dst4q], m4
+ mov %+ %3 %+ ps [dstq+dst5q], m5
+
+ add srcq, mmsize*6
+ add dstq, mmsize
+ sub lend, mmsize/4
+ jg .loop
+ REP_RET
+%endmacro
+
+%define PACK_8CH_GPRS (10 * ARCH_X86_64) + ((6 + HAVE_ALIGNED_STACK) * ARCH_X86_32)
+
+%macro PACK_8CH 5-7
+cglobal pack_8ch_%2_to_%1_%3, 2,PACK_8CH_GPRS,10, ARCH_X86_32*48, dst, src, len, src1, src2, src3, src4, src5, src6, src7
+ mov dstq, [dstq]
+%if ARCH_X86_32
+ DEFINE_ARGS dst, src, src2, src3, src4, src5, src6
+ %define lend dword r2m
+ %define src1q r0q
+ %define src1m dword [rsp+32]
+%if HAVE_ALIGNED_STACK == 0
+ DEFINE_ARGS dst, src, src2, src3, src5, src6
+ %define src4q r0q
+ %define src4m dword [rsp+36]
+%endif
+ %define src7q r0q
+ %define src7m dword [rsp+40]
+ mov dstm, dstq
+%endif
+ mov src7q, [srcq+7*gprsize]
+ mov src6q, [srcq+6*gprsize]
+%if ARCH_X86_32
+ mov src7m, src7q
+%endif
+ mov src5q, [srcq+5*gprsize]
+ mov src4q, [srcq+4*gprsize]
+ mov src3q, [srcq+3*gprsize]
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+ mov src4m, src4q
+%endif
+ mov src2q, [srcq+2*gprsize]
+ mov src1q, [srcq+1*gprsize]
+ mov srcq, [srcq]
+%ifidn %3, a
+%if ARCH_X86_32
+ test dstmp, mmsize-1
+%else
+ test dstq, mmsize-1
+%endif
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+ test srcq, mmsize-1
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+ test src1q, mmsize-1
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+ test src2q, mmsize-1
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+ test src3q, mmsize-1
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+ test src4m, mmsize-1
+%else
+ test src4q, mmsize-1
+%endif
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+ test src5q, mmsize-1
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+ test src6q, mmsize-1
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%if ARCH_X86_32
+ test src7m, mmsize-1
+%else
+ test src7q, mmsize-1
+%endif
+ jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%else
+pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%endif
+ sub src1q, srcq
+ sub src2q, srcq
+ sub src3q, srcq
+%if ARCH_X86_64 || HAVE_ALIGNED_STACK
+ sub src4q, srcq
+%else
+ sub src4m, srcq
+%endif
+ sub src5q, srcq
+ sub src6q, srcq
+%if ARCH_X86_64
+ sub src7q, srcq
+%else
+ mov src1m, src1q
+ sub src7m, srcq
+%endif
+
+%if ARCH_X86_64
+ %7 x,x,x,x,m9,x
+%elifidn %1, int32
+ %define m9 [flt2p31]
+%else
+ %define m9 [flt2pm31]
+%endif
+
+.loop:
+ mov%3 m0, [srcq ]
+ mov%3 m1, [srcq+src1q]
+ mov%3 m2, [srcq+src2q]
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+ mov src4q, src4m
+%endif
+ mov%3 m3, [srcq+src3q]
+ mov%3 m4, [srcq+src4q]
+ mov%3 m5, [srcq+src5q]
+%if ARCH_X86_32
+ mov src7q, src7m
+%endif
+ mov%3 m6, [srcq+src6q]
+ mov%3 m7, [srcq+src7q]
+
+%if ARCH_X86_64
+ TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, 8
+
+ %6 m0,m1,x,x,m9,m8
+ %6 m2,m3,x,x,m9,m8
+ %6 m4,m5,x,x,m9,m8
+ %6 m6,m7,x,x,m9,m8
+
+ mov%3 [dstq], m0
+%else
+ mov dstq, dstm
+
+ TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, [rsp], [rsp+16], 1
+
+ %6 m0,m1,x,x,m9,m2
+ mova m2, [rsp]
+ mov%3 [dstq], m0
+ %6 m2,m3,x,x,m9,m0
+ %6 m4,m5,x,x,m9,m0
+ %6 m6,m7,x,x,m9,m0
+
+%endif
+
+ mov%3 [dstq+16], m1
+ mov%3 [dstq+32], m2
+ mov%3 [dstq+48], m3
+ mov%3 [dstq+64], m4
+ mov%3 [dstq+80], m5
+ mov%3 [dstq+96], m6
+ mov%3 [dstq+112], m7
+
+ add srcq, mmsize
+ add dstq, mmsize*8
+%if ARCH_X86_32
+ mov dstm, dstq
+ mov src1q, src1m
+%endif
+ sub lend, mmsize/4
+ jg .loop
+ REP_RET
+%endmacro
+
+%macro INT16_TO_INT32_N 6
+ pxor m2, m2
+ pxor m3, m3
+ punpcklwd m2, m1
+ punpckhwd m3, m1
+ SWAP 4,0
+ pxor m0, m0
+ pxor m1, m1
+ punpcklwd m0, m4
+ punpckhwd m1, m4
+%endmacro
+
+%macro INT32_TO_INT16_N 6
+ psrad m0, 16
+ psrad m1, 16
+ psrad m2, 16
+ psrad m3, 16
+ packssdw m0, m1
+ packssdw m2, m3
+ SWAP 1,2
+%endmacro
+
+%macro INT32_TO_FLOAT_INIT 6
+ mova %5, [flt2pm31]
+%endmacro
+%macro INT32_TO_FLOAT_N 6
+ cvtdq2ps %1, %1
+ cvtdq2ps %2, %2
+ mulps %1, %1, %5
+ mulps %2, %2, %5
+%endmacro
+
+%macro FLOAT_TO_INT32_INIT 6
+ mova %5, [flt2p31]
+%endmacro
+%macro FLOAT_TO_INT32_N 6
+ mulps %1, %5
+ mulps %2, %5
+ cvtps2dq %6, %1
+ cmpps %1, %1, %5, 5
+ paddd %1, %6
+ cvtps2dq %6, %2
+ cmpps %2, %2, %5, 5
+ paddd %2, %6
+%endmacro
+
+%macro INT16_TO_FLOAT_INIT 6
+ mova m5, [flt2pm31]
+%endmacro
+%macro INT16_TO_FLOAT_N 6
+ INT16_TO_INT32_N %1,%2,%3,%4,%5,%6
+ cvtdq2ps m0, m0
+ cvtdq2ps m1, m1
+ cvtdq2ps m2, m2
+ cvtdq2ps m3, m3
+ mulps m0, m0, m5
+ mulps m1, m1, m5
+ mulps m2, m2, m5
+ mulps m3, m3, m5
+%endmacro
+
+%macro FLOAT_TO_INT16_INIT 6
+ mova m5, [flt2p15]
+%endmacro
+%macro FLOAT_TO_INT16_N 6
+ mulps m0, m5
+ mulps m1, m5
+ mulps m2, m5
+ mulps m3, m5
+ cvtps2dq m0, m0
+ cvtps2dq m1, m1
+ packssdw m0, m1
+ cvtps2dq m1, m2
+ cvtps2dq m3, m3
+ packssdw m1, m3
+%endmacro
+
+%macro NOP_N 0-6
+%endmacro
+
+INIT_MMX mmx
+CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+PACK_6CH float, float, u, 2, 2, NOP_N, NOP_N
+PACK_6CH float, float, a, 2, 2, NOP_N, NOP_N
+
+INIT_XMM sse
+PACK_6CH float, float, u, 2, 2, NOP_N, NOP_N
+PACK_6CH float, float, a, 2, 2, NOP_N, NOP_N
+
+UNPACK_6CH float, float, u, 2, 2, NOP_N, NOP_N
+UNPACK_6CH float, float, a, 2, 2, NOP_N, NOP_N
+
+INIT_XMM sse2
+CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+PACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N
+PACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N
+PACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N
+PACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N
+PACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+PACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+PACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+PACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N
+UNPACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N
+UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+UNPACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+CONV float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+CONV float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+CONV int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+CONV int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+
+PACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+PACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+PACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+PACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+
+UNPACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+UNPACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+UNPACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+
+PACK_6CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_6CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+UNPACK_6CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_6CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+PACK_8CH float, float, u, 2, 2, NOP_N, NOP_N
+PACK_8CH float, float, a, 2, 2, NOP_N, NOP_N
+
+PACK_8CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_8CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+INIT_XMM ssse3
+UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+PACK_6CH float, float, u, 2, 2, NOP_N, NOP_N
+PACK_6CH float, float, a, 2, 2, NOP_N, NOP_N
+
+UNPACK_6CH float, float, u, 2, 2, NOP_N, NOP_N
+UNPACK_6CH float, float, a, 2, 2, NOP_N, NOP_N
+
+PACK_6CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_6CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+UNPACK_6CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_6CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+PACK_8CH float, float, u, 2, 2, NOP_N, NOP_N
+PACK_8CH float, float, a, 2, 2, NOP_N, NOP_N
+
+PACK_8CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_8CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+INIT_YMM avx
+CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+%endif
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+%endif
diff --git a/libswresample/x86/audio_convert_init.c b/libswresample/x86/audio_convert_init.c
new file mode 100644
index 0000000000..7f25d981a9
--- /dev/null
+++ b/libswresample/x86/audio_convert_init.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/x86/cpu.h"
+#include "libswresample/swresample_internal.h"
+#include "libswresample/audioconvert.h"
+
+#define PROTO(pre, in, out, cap) void ff ## pre ## in## _to_ ##out## _a_ ##cap(uint8_t **dst, const uint8_t **src, int len);
+#define PROTO2(pre, out, cap) PROTO(pre, int16, out, cap) PROTO(pre, int32, out, cap) PROTO(pre, float, out, cap)
+#define PROTO3(pre, cap) PROTO2(pre, int16, cap) PROTO2(pre, int32, cap) PROTO2(pre, float, cap)
+#define PROTO4(pre) PROTO3(pre, mmx) PROTO3(pre, sse) PROTO3(pre, sse2) PROTO3(pre, ssse3) PROTO3(pre, sse4) PROTO3(pre, avx) PROTO3(pre, avx2)
+PROTO4(_)
+PROTO4(_pack_2ch_)
+PROTO4(_pack_6ch_)
+PROTO4(_pack_8ch_)
+PROTO4(_unpack_2ch_)
+PROTO4(_unpack_6ch_)
+
+av_cold void swri_audio_convert_init_x86(struct AudioConvert *ac,
+ enum AVSampleFormat out_fmt,
+ enum AVSampleFormat in_fmt,
+ int channels){
+ int mm_flags = av_get_cpu_flags();
+
+ ac->simd_f= NULL;
+
+//FIXME add memcpy case
+
+#define MULTI_CAPS_FUNC(flag, cap) \
+ if (EXTERNAL_##flag(mm_flags)) {\
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16P)\
+ ac->simd_f = ff_int16_to_int32_a_ ## cap;\
+ if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32P)\
+ ac->simd_f = ff_int32_to_int16_a_ ## cap;\
+ }
+
+MULTI_CAPS_FUNC(MMX, mmx)
+MULTI_CAPS_FUNC(SSE2, sse2)
+
+ if(EXTERNAL_MMX(mm_flags)) {
+ if(channels == 6) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_6ch_float_to_float_a_mmx;
+ }
+ }
+ if(EXTERNAL_SSE(mm_flags)) {
+ if(channels == 6) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_6ch_float_to_float_a_sse;
+
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_6ch_float_to_float_a_sse;
+ }
+ }
+ if(EXTERNAL_SSE2(mm_flags)) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_int32_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16P)
+ ac->simd_f = ff_int16_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_float_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_float_to_int16_a_sse2;
+
+ if(channels == 2) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_2ch_int32_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S16P)
+ ac->simd_f = ff_pack_2ch_int16_to_int16_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16P)
+ ac->simd_f = ff_pack_2ch_int16_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_2ch_int32_to_int16_a_sse2;
+
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_2ch_int32_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S16)
+ ac->simd_f = ff_unpack_2ch_int16_to_int16_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16)
+ ac->simd_f = ff_unpack_2ch_int16_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_2ch_int32_to_int16_a_sse2;
+
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_2ch_int32_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_2ch_float_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S16P)
+ ac->simd_f = ff_pack_2ch_int16_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_2ch_float_to_int16_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_2ch_int32_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT)
+ ac->simd_f = ff_unpack_2ch_float_to_int32_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16)
+ ac->simd_f = ff_unpack_2ch_int16_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLT)
+ ac->simd_f = ff_unpack_2ch_float_to_int16_a_sse2;
+ }
+ if(channels == 6) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_6ch_int32_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_6ch_float_to_int32_a_sse2;
+
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_6ch_int32_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT)
+ ac->simd_f = ff_unpack_6ch_float_to_int32_a_sse2;
+ }
+ if(channels == 8) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_8ch_float_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_8ch_int32_to_float_a_sse2;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_8ch_float_to_int32_a_sse2;
+ }
+ }
+ if(EXTERNAL_SSSE3(mm_flags)) {
+ if(channels == 2) {
+ if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S16)
+ ac->simd_f = ff_unpack_2ch_int16_to_int16_a_ssse3;
+ if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16)
+ ac->simd_f = ff_unpack_2ch_int16_to_int32_a_ssse3;
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16)
+ ac->simd_f = ff_unpack_2ch_int16_to_float_a_ssse3;
+ }
+ }
+ if(EXTERNAL_AVX(mm_flags)) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_int32_to_float_a_avx;
+ if(channels == 6) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_6ch_float_to_float_a_avx;
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_6ch_int32_to_float_a_avx;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_6ch_float_to_int32_a_avx;
+
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_6ch_float_to_float_a_avx;
+ if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32)
+ ac->simd_f = ff_unpack_6ch_int32_to_float_a_avx;
+ if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT)
+ ac->simd_f = ff_unpack_6ch_float_to_int32_a_avx;
+ }
+ if(channels == 8) {
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_8ch_float_to_float_a_avx;
+ if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P)
+ ac->simd_f = ff_pack_8ch_int32_to_float_a_avx;
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_pack_8ch_float_to_int32_a_avx;
+ }
+ }
+ if(EXTERNAL_AVX2(mm_flags)) {
+ if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP)
+ ac->simd_f = ff_float_to_int32_a_avx2;
+ }
+}
diff --git a/libswresample/x86/rematrix.asm b/libswresample/x86/rematrix.asm
new file mode 100644
index 0000000000..f0ae9599a2
--- /dev/null
+++ b/libswresample/x86/rematrix.asm
@@ -0,0 +1,250 @@
+;******************************************************************************
+;* Copyright (c) 2012 Michael Niedermayer
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+
+SECTION_RODATA 32
+dw1: times 8 dd 1
+w1 : times 16 dw 1
+
+SECTION .text
+
+%macro MIX2_FLT 1
+cglobal mix_2_1_%1_float, 7, 7, 6, out, in1, in2, coeffp, index1, index2, len
+%ifidn %1, a
+ test in1q, mmsize-1
+ jne mix_2_1_float_u_int %+ SUFFIX
+ test in2q, mmsize-1
+ jne mix_2_1_float_u_int %+ SUFFIX
+ test outq, mmsize-1
+ jne mix_2_1_float_u_int %+ SUFFIX
+%else
+mix_2_1_float_u_int %+ SUFFIX
+%endif
+ VBROADCASTSS m4, [coeffpq + 4*index1q]
+ VBROADCASTSS m5, [coeffpq + 4*index2q]
+ shl lend , 2
+ add in1q , lenq
+ add in2q , lenq
+ add outq , lenq
+ neg lenq
+.next:
+%ifidn %1, a
+ mulps m0, m4, [in1q + lenq ]
+ mulps m1, m5, [in2q + lenq ]
+ mulps m2, m4, [in1q + lenq + mmsize]
+ mulps m3, m5, [in2q + lenq + mmsize]
+%else
+ movu m0, [in1q + lenq ]
+ movu m1, [in2q + lenq ]
+ movu m2, [in1q + lenq + mmsize]
+ movu m3, [in2q + lenq + mmsize]
+ mulps m0, m0, m4
+ mulps m1, m1, m5
+ mulps m2, m2, m4
+ mulps m3, m3, m5
+%endif
+ addps m0, m0, m1
+ addps m2, m2, m3
+ mov%1 [outq + lenq ], m0
+ mov%1 [outq + lenq + mmsize], m2
+ add lenq, mmsize*2
+ jl .next
+ REP_RET
+%endmacro
+
+%macro MIX1_FLT 1
+cglobal mix_1_1_%1_float, 5, 5, 3, out, in, coeffp, index, len
+%ifidn %1, a
+ test inq, mmsize-1
+ jne mix_1_1_float_u_int %+ SUFFIX
+ test outq, mmsize-1
+ jne mix_1_1_float_u_int %+ SUFFIX
+%else
+mix_1_1_float_u_int %+ SUFFIX
+%endif
+ VBROADCASTSS m2, [coeffpq + 4*indexq]
+ shl lenq , 2
+ add inq , lenq
+ add outq , lenq
+ neg lenq
+.next:
+%ifidn %1, a
+ mulps m0, m2, [inq + lenq ]
+ mulps m1, m2, [inq + lenq + mmsize]
+%else
+ movu m0, [inq + lenq ]
+ movu m1, [inq + lenq + mmsize]
+ mulps m0, m0, m2
+ mulps m1, m1, m2
+%endif
+ mov%1 [outq + lenq ], m0
+ mov%1 [outq + lenq + mmsize], m1
+ add lenq, mmsize*2
+ jl .next
+ REP_RET
+%endmacro
+
+%macro MIX1_INT16 1
+cglobal mix_1_1_%1_int16, 5, 5, 6, out, in, coeffp, index, len
+%ifidn %1, a
+ test inq, mmsize-1
+ jne mix_1_1_int16_u_int %+ SUFFIX
+ test outq, mmsize-1
+ jne mix_1_1_int16_u_int %+ SUFFIX
+%else
+mix_1_1_int16_u_int %+ SUFFIX
+%endif
+ movd m4, [coeffpq + 4*indexq]
+ SPLATW m5, m4
+ psllq m4, 32
+ psrlq m4, 48
+ mova m0, [w1]
+ psllw m0, m4
+ psrlw m0, 1
+ punpcklwd m5, m0
+ add lenq , lenq
+ add inq , lenq
+ add outq , lenq
+ neg lenq
+.next:
+ mov%1 m0, [inq + lenq ]
+ mov%1 m2, [inq + lenq + mmsize]
+ mova m1, m0
+ mova m3, m2
+ punpcklwd m0, [w1]
+ punpckhwd m1, [w1]
+ punpcklwd m2, [w1]
+ punpckhwd m3, [w1]
+ pmaddwd m0, m5
+ pmaddwd m1, m5
+ pmaddwd m2, m5
+ pmaddwd m3, m5
+ psrad m0, m4
+ psrad m1, m4
+ psrad m2, m4
+ psrad m3, m4
+ packssdw m0, m1
+ packssdw m2, m3
+ mov%1 [outq + lenq ], m0
+ mov%1 [outq + lenq + mmsize], m2
+ add lenq, mmsize*2
+ jl .next
+%if mmsize == 8
+ emms
+ RET
+%else
+ REP_RET
+%endif
+%endmacro
+
+%macro MIX2_INT16 1
+cglobal mix_2_1_%1_int16, 7, 7, 8, out, in1, in2, coeffp, index1, index2, len
+%ifidn %1, a
+ test in1q, mmsize-1
+ jne mix_2_1_int16_u_int %+ SUFFIX
+ test in2q, mmsize-1
+ jne mix_2_1_int16_u_int %+ SUFFIX
+ test outq, mmsize-1
+ jne mix_2_1_int16_u_int %+ SUFFIX
+%else
+mix_2_1_int16_u_int %+ SUFFIX
+%endif
+ movd m4, [coeffpq + 4*index1q]
+ movd m6, [coeffpq + 4*index2q]
+ SPLATW m5, m4
+ SPLATW m6, m6
+ psllq m4, 32
+ psrlq m4, 48
+ mova m7, [dw1]
+ pslld m7, m4
+ psrld m7, 1
+ punpcklwd m5, m6
+ add lend , lend
+ add in1q , lenq
+ add in2q , lenq
+ add outq , lenq
+ neg lenq
+.next:
+ mov%1 m0, [in1q + lenq ]
+ mov%1 m2, [in2q + lenq ]
+ mova m1, m0
+ punpcklwd m0, m2
+ punpckhwd m1, m2
+
+ mov%1 m2, [in1q + lenq + mmsize]
+ mov%1 m6, [in2q + lenq + mmsize]
+ mova m3, m2
+ punpcklwd m2, m6
+ punpckhwd m3, m6
+
+ pmaddwd m0, m5
+ pmaddwd m1, m5
+ pmaddwd m2, m5
+ pmaddwd m3, m5
+ paddd m0, m7
+ paddd m1, m7
+ paddd m2, m7
+ paddd m3, m7
+ psrad m0, m4
+ psrad m1, m4
+ psrad m2, m4
+ psrad m3, m4
+ packssdw m0, m1
+ packssdw m2, m3
+ mov%1 [outq + lenq ], m0
+ mov%1 [outq + lenq + mmsize], m2
+ add lenq, mmsize*2
+ jl .next
+%if mmsize == 8
+ emms
+ RET
+%else
+ REP_RET
+%endif
+%endmacro
+
+
+INIT_MMX mmx
+MIX1_INT16 u
+MIX1_INT16 a
+MIX2_INT16 u
+MIX2_INT16 a
+
+INIT_XMM sse
+MIX2_FLT u
+MIX2_FLT a
+MIX1_FLT u
+MIX1_FLT a
+
+INIT_XMM sse2
+MIX1_INT16 u
+MIX1_INT16 a
+MIX2_INT16 u
+MIX2_INT16 a
+
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+MIX2_FLT u
+MIX2_FLT a
+MIX1_FLT u
+MIX1_FLT a
+%endif
diff --git a/libswresample/x86/rematrix_init.c b/libswresample/x86/rematrix_init.c
new file mode 100644
index 0000000000..918479a4a8
--- /dev/null
+++ b/libswresample/x86/rematrix_init.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at)
+ *
+ * This file is part of libswresample
+ *
+ * libswresample is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libswresample is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with libswresample; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/x86/cpu.h"
+#include "libswresample/swresample_internal.h"
+
+#define D(type, simd) \
+mix_1_1_func_type ff_mix_1_1_a_## type ## _ ## simd;\
+mix_2_1_func_type ff_mix_2_1_a_## type ## _ ## simd;
+
+D(float, sse)
+D(float, avx)
+D(int16, mmx)
+D(int16, sse2)
+
+av_cold int swri_rematrix_init_x86(struct SwrContext *s){
+#if HAVE_YASM
+ int mm_flags = av_get_cpu_flags();
+ int nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout);
+ int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout);
+ int num = nb_in * nb_out;
+ int i,j;
+
+ s->mix_1_1_simd = NULL;
+ s->mix_2_1_simd = NULL;
+
+ if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){
+ if(EXTERNAL_MMX(mm_flags)) {
+ s->mix_1_1_simd = ff_mix_1_1_a_int16_mmx;
+ s->mix_2_1_simd = ff_mix_2_1_a_int16_mmx;
+ }
+ if(EXTERNAL_SSE2(mm_flags)) {
+ s->mix_1_1_simd = ff_mix_1_1_a_int16_sse2;
+ s->mix_2_1_simd = ff_mix_2_1_a_int16_sse2;
+ }
+ s->native_simd_matrix = av_mallocz_array(num, 2 * sizeof(int16_t));
+ s->native_simd_one = av_mallocz(2 * sizeof(int16_t));
+ if (!s->native_simd_matrix || !s->native_simd_one)
+ return AVERROR(ENOMEM);
+
+ for(i=0; i<nb_out; i++){
+ int sh = 0;
+ for(j=0; j<nb_in; j++)
+ sh = FFMAX(sh, FFABS(((int*)s->native_matrix)[i * nb_in + j]));
+ sh = FFMAX(av_log2(sh) - 14, 0);
+ for(j=0; j<nb_in; j++) {
+ ((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)+1] = 15 - sh;
+ ((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)] =
+ ((((int*)s->native_matrix)[i * nb_in + j]) + (1<<sh>>1)) >> sh;
+ }
+ }
+ ((int16_t*)s->native_simd_one)[1] = 14;
+ ((int16_t*)s->native_simd_one)[0] = 16384;
+ } else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){
+ if(EXTERNAL_SSE(mm_flags)) {
+ s->mix_1_1_simd = ff_mix_1_1_a_float_sse;
+ s->mix_2_1_simd = ff_mix_2_1_a_float_sse;
+ }
+ if(EXTERNAL_AVX(mm_flags)) {
+ s->mix_1_1_simd = ff_mix_1_1_a_float_avx;
+ s->mix_2_1_simd = ff_mix_2_1_a_float_avx;
+ }
+ s->native_simd_matrix = av_mallocz_array(num, sizeof(float));
+ s->native_simd_one = av_mallocz(sizeof(float));
+ if (!s->native_simd_matrix || !s->native_simd_one)
+ return AVERROR(ENOMEM);
+ memcpy(s->native_simd_matrix, s->native_matrix, num * sizeof(float));
+ memcpy(s->native_simd_one, s->native_one, sizeof(float));
+ }
+#endif
+
+ return 0;
+}
diff --git a/libswresample/x86/resample.asm b/libswresample/x86/resample.asm
new file mode 100644
index 0000000000..a57ff37bb9
--- /dev/null
+++ b/libswresample/x86/resample.asm
@@ -0,0 +1,600 @@
+;******************************************************************************
+;* Copyright (c) 2012 Michael Niedermayer
+;* Copyright (c) 2014 James Almer <jamrial <at> gmail.com>
+;* Copyright (c) 2014 Ronald S. Bultje <rsbultje@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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+%if ARCH_X86_64
+%define pointer resq
+%else
+%define pointer resd
+%endif
+
+struc ResampleContext
+ .av_class: pointer 1
+ .filter_bank: pointer 1
+ .filter_length: resd 1
+ .filter_alloc: resd 1
+ .ideal_dst_incr: resd 1
+ .dst_incr: resd 1
+ .dst_incr_div: resd 1
+ .dst_incr_mod: resd 1
+ .index: resd 1
+ .frac: resd 1
+ .src_incr: resd 1
+ .compensation_distance: resd 1
+ .phase_shift: resd 1
+ .phase_mask: resd 1
+
+ ; there's a few more here but we only care about the first few
+endstruc
+
+SECTION_RODATA
+
+pf_1: dd 1.0
+pdbl_1: dq 1.0
+pd_0x4000: dd 0x4000
+
+SECTION .text
+
+%macro RESAMPLE_FNS 3-5 ; format [float or int16], bps, log2_bps, float op suffix [s or d], 1.0 constant
+; int resample_common_$format(ResampleContext *ctx, $format *dst,
+; const $format *src, int size, int update_ctx)
+%if ARCH_X86_64 ; unix64 and win64
+cglobal resample_common_%1, 0, 15, 2, ctx, dst, src, phase_shift, index, frac, \
+ dst_incr_mod, size, min_filter_count_x4, \
+ min_filter_len_x4, dst_incr_div, src_incr, \
+ phase_mask, dst_end, filter_bank
+
+ ; use red-zone for variable storage
+%define ctx_stackq [rsp-0x8]
+%define src_stackq [rsp-0x10]
+%if WIN64
+%define update_context_stackd r4m
+%else ; unix64
+%define update_context_stackd [rsp-0x14]
+%endif
+
+ ; load as many variables in registers as possible; for the rest, store
+ ; on stack so that we have 'ctx' available as one extra register
+ mov sized, r3d
+ mov phase_maskd, [ctxq+ResampleContext.phase_mask]
+%if UNIX64
+ mov update_context_stackd, r4d
+%endif
+ mov indexd, [ctxq+ResampleContext.index]
+ mov fracd, [ctxq+ResampleContext.frac]
+ mov dst_incr_modd, [ctxq+ResampleContext.dst_incr_mod]
+ mov filter_bankq, [ctxq+ResampleContext.filter_bank]
+ mov src_incrd, [ctxq+ResampleContext.src_incr]
+ mov ctx_stackq, ctxq
+ mov min_filter_len_x4d, [ctxq+ResampleContext.filter_length]
+ mov dst_incr_divd, [ctxq+ResampleContext.dst_incr_div]
+ shl min_filter_len_x4d, %3
+ lea dst_endq, [dstq+sizeq*%2]
+
+%if UNIX64
+ mov ecx, [ctxq+ResampleContext.phase_shift]
+ mov edi, [ctxq+ResampleContext.filter_alloc]
+
+ DEFINE_ARGS filter_alloc, dst, src, phase_shift, index, frac, dst_incr_mod, \
+ filter, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+ src_incr, phase_mask, dst_end, filter_bank
+%elif WIN64
+ mov R9d, [ctxq+ResampleContext.filter_alloc]
+ mov ecx, [ctxq+ResampleContext.phase_shift]
+
+ DEFINE_ARGS phase_shift, dst, src, filter_alloc, index, frac, dst_incr_mod, \
+ filter, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+ src_incr, phase_mask, dst_end, filter_bank
+%endif
+
+ neg min_filter_len_x4q
+ sub filter_bankq, min_filter_len_x4q
+ sub srcq, min_filter_len_x4q
+ mov src_stackq, srcq
+%else ; x86-32
+cglobal resample_common_%1, 1, 7, 2, ctx, phase_shift, dst, frac, \
+ index, min_filter_length_x4, filter_bank
+
+ ; push temp variables to stack
+%define ctx_stackq r0mp
+%define src_stackq r2mp
+%define update_context_stackd r4m
+
+ mov dstq, r1mp
+ mov r3, r3mp
+ lea r3, [dstq+r3*%2]
+ PUSH dword [ctxq+ResampleContext.dst_incr_div]
+ PUSH dword [ctxq+ResampleContext.dst_incr_mod]
+ PUSH dword [ctxq+ResampleContext.filter_alloc]
+ PUSH r3
+ PUSH dword [ctxq+ResampleContext.phase_mask]
+ PUSH dword [ctxq+ResampleContext.src_incr]
+ mov min_filter_length_x4d, [ctxq+ResampleContext.filter_length]
+ mov indexd, [ctxq+ResampleContext.index]
+ shl min_filter_length_x4d, %3
+ mov fracd, [ctxq+ResampleContext.frac]
+ neg min_filter_length_x4q
+ mov filter_bankq, [ctxq+ResampleContext.filter_bank]
+ sub r2mp, min_filter_length_x4q
+ sub filter_bankq, min_filter_length_x4q
+ PUSH min_filter_length_x4q
+ PUSH filter_bankq
+ mov phase_shiftd, [ctxq+ResampleContext.phase_shift]
+
+ DEFINE_ARGS src, phase_shift, dst, frac, index, min_filter_count_x4, filter
+
+%define filter_bankq dword [rsp+0x0]
+%define min_filter_length_x4q dword [rsp+0x4]
+%define src_incrd dword [rsp+0x8]
+%define phase_maskd dword [rsp+0xc]
+%define dst_endq dword [rsp+0x10]
+%define filter_allocd dword [rsp+0x14]
+%define dst_incr_modd dword [rsp+0x18]
+%define dst_incr_divd dword [rsp+0x1c]
+
+ mov srcq, r2mp
+%endif
+
+.loop:
+ mov filterd, filter_allocd
+ imul filterd, indexd
+%if ARCH_X86_64
+ mov min_filter_count_x4q, min_filter_len_x4q
+ lea filterq, [filter_bankq+filterq*%2]
+%else ; x86-32
+ mov min_filter_count_x4q, filter_bankq
+ lea filterq, [min_filter_count_x4q+filterq*%2]
+ mov min_filter_count_x4q, min_filter_length_x4q
+%endif
+%ifidn %1, int16
+ movd m0, [pd_0x4000]
+%else ; float/double
+ xorps m0, m0, m0
+%endif
+
+ align 16
+.inner_loop:
+ movu m1, [srcq+min_filter_count_x4q*1]
+%ifidn %1, int16
+ PMADCSWD m0, m1, [filterq+min_filter_count_x4q*1], m0, m1
+%else ; float/double
+%if cpuflag(fma4) || cpuflag(fma3)
+ fmaddp%4 m0, m1, [filterq+min_filter_count_x4q*1], m0
+%else
+ mulp%4 m1, m1, [filterq+min_filter_count_x4q*1]
+ addp%4 m0, m0, m1
+%endif ; cpuflag
+%endif
+ add min_filter_count_x4q, mmsize
+ js .inner_loop
+
+%ifidn %1, int16
+ HADDD m0, m1
+ psrad m0, 15
+ add fracd, dst_incr_modd
+ packssdw m0, m0
+ add indexd, dst_incr_divd
+ movd [dstq], m0
+%else ; float/double
+ ; horizontal sum & store
+%if mmsize == 32
+ vextractf128 xm1, m0, 0x1
+ addps xm0, xm1
+%endif
+ movhlps xm1, xm0
+%ifidn %1, float
+ addps xm0, xm1
+ shufps xm1, xm0, xm0, q0001
+%endif
+ add fracd, dst_incr_modd
+ addp%4 xm0, xm1
+ add indexd, dst_incr_divd
+ movs%4 [dstq], xm0
+%endif
+ cmp fracd, src_incrd
+ jl .skip
+ sub fracd, src_incrd
+ inc indexd
+
+%if UNIX64
+ DEFINE_ARGS filter_alloc, dst, src, phase_shift, index, frac, dst_incr_mod, \
+ index_incr, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+ src_incr, phase_mask, dst_end, filter_bank
+%elif WIN64
+ DEFINE_ARGS phase_shift, dst, src, filter_alloc, index, frac, dst_incr_mod, \
+ index_incr, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+ src_incr, phase_mask, dst_end, filter_bank
+%else ; x86-32
+ DEFINE_ARGS src, phase_shift, dst, frac, index, index_incr
+%endif
+
+.skip:
+ mov index_incrd, indexd
+ add dstq, %2
+ and indexd, phase_maskd
+ sar index_incrd, phase_shiftb
+ lea srcq, [srcq+index_incrq*%2]
+ cmp dstq, dst_endq
+ jne .loop
+
+%if ARCH_X86_64
+ DEFINE_ARGS ctx, dst, src, phase_shift, index, frac
+%else ; x86-32
+ DEFINE_ARGS src, ctx, update_context, frac, index
+%endif
+
+ cmp dword update_context_stackd, 0
+ jz .skip_store
+ ; strictly speaking, the function should always return the consumed
+ ; number of bytes; however, we only use the value if update_context
+ ; is true, so let's just leave it uninitialized otherwise
+ mov ctxq, ctx_stackq
+ movifnidn rax, srcq
+ mov [ctxq+ResampleContext.frac ], fracd
+ sub rax, src_stackq
+ mov [ctxq+ResampleContext.index], indexd
+ shr rax, %3
+
+.skip_store:
+%if ARCH_X86_32
+ ADD rsp, 0x20
+%endif
+ RET
+
+; int resample_linear_$format(ResampleContext *ctx, float *dst,
+; const float *src, int size, int update_ctx)
+%if ARCH_X86_64 ; unix64 and win64
+%if UNIX64
+cglobal resample_linear_%1, 0, 15, 5, ctx, dst, phase_mask, phase_shift, index, frac, \
+ size, dst_incr_mod, min_filter_count_x4, \
+ min_filter_len_x4, dst_incr_div, src_incr, \
+ src, dst_end, filter_bank
+
+ mov srcq, r2mp
+%else ; win64
+cglobal resample_linear_%1, 0, 15, 5, ctx, phase_mask, src, phase_shift, index, frac, \
+ size, dst_incr_mod, min_filter_count_x4, \
+ min_filter_len_x4, dst_incr_div, src_incr, \
+ dst, dst_end, filter_bank
+
+ mov dstq, r1mp
+%endif
+
+ ; use red-zone for variable storage
+%define ctx_stackq [rsp-0x8]
+%define src_stackq [rsp-0x10]
+%define phase_mask_stackd [rsp-0x14]
+%if WIN64
+%define update_context_stackd r4m
+%else ; unix64
+%define update_context_stackd [rsp-0x18]
+%endif
+
+ ; load as many variables in registers as possible; for the rest, store
+ ; on stack so that we have 'ctx' available as one extra register
+ mov sized, r3d
+ mov phase_maskd, [ctxq+ResampleContext.phase_mask]
+%if UNIX64
+ mov update_context_stackd, r4d
+%endif
+ mov indexd, [ctxq+ResampleContext.index]
+ mov fracd, [ctxq+ResampleContext.frac]
+ mov dst_incr_modd, [ctxq+ResampleContext.dst_incr_mod]
+ mov filter_bankq, [ctxq+ResampleContext.filter_bank]
+ mov src_incrd, [ctxq+ResampleContext.src_incr]
+ mov ctx_stackq, ctxq
+ mov phase_mask_stackd, phase_maskd
+ mov min_filter_len_x4d, [ctxq+ResampleContext.filter_length]
+%ifidn %1, int16
+ movd m4, [pd_0x4000]
+%else ; float/double
+ cvtsi2s%4 xm0, src_incrd
+ movs%4 xm4, [%5]
+ divs%4 xm4, xm0
+%endif
+ mov dst_incr_divd, [ctxq+ResampleContext.dst_incr_div]
+ shl min_filter_len_x4d, %3
+ lea dst_endq, [dstq+sizeq*%2]
+
+%if UNIX64
+ mov ecx, [ctxq+ResampleContext.phase_shift]
+ mov edi, [ctxq+ResampleContext.filter_alloc]
+
+ DEFINE_ARGS filter_alloc, dst, filter2, phase_shift, index, frac, filter1, \
+ dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+ dst_incr_div, src_incr, src, dst_end, filter_bank
+%elif WIN64
+ mov R9d, [ctxq+ResampleContext.filter_alloc]
+ mov ecx, [ctxq+ResampleContext.phase_shift]
+
+ DEFINE_ARGS phase_shift, filter2, src, filter_alloc, index, frac, filter1, \
+ dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+ dst_incr_div, src_incr, dst, dst_end, filter_bank
+%endif
+
+ neg min_filter_len_x4q
+ sub filter_bankq, min_filter_len_x4q
+ sub srcq, min_filter_len_x4q
+ mov src_stackq, srcq
+%else ; x86-32
+cglobal resample_linear_%1, 1, 7, 5, ctx, min_filter_length_x4, filter2, \
+ frac, index, dst, filter_bank
+
+ ; push temp variables to stack
+%define ctx_stackq r0mp
+%define src_stackq r2mp
+%define update_context_stackd r4m
+
+ mov dstq, r1mp
+ mov r3, r3mp
+ lea r3, [dstq+r3*%2]
+ PUSH dword [ctxq+ResampleContext.dst_incr_div]
+ PUSH r3
+ mov r3, dword [ctxq+ResampleContext.filter_alloc]
+ PUSH dword [ctxq+ResampleContext.dst_incr_mod]
+ PUSH r3
+ shl r3, %3
+ PUSH r3
+ mov r3, dword [ctxq+ResampleContext.src_incr]
+ PUSH dword [ctxq+ResampleContext.phase_mask]
+ PUSH r3d
+%ifidn %1, int16
+ movd m4, [pd_0x4000]
+%else ; float/double
+ cvtsi2s%4 xm0, r3d
+ movs%4 xm4, [%5]
+ divs%4 xm4, xm0
+%endif
+ mov min_filter_length_x4d, [ctxq+ResampleContext.filter_length]
+ mov indexd, [ctxq+ResampleContext.index]
+ shl min_filter_length_x4d, %3
+ mov fracd, [ctxq+ResampleContext.frac]
+ neg min_filter_length_x4q
+ mov filter_bankq, [ctxq+ResampleContext.filter_bank]
+ sub r2mp, min_filter_length_x4q
+ sub filter_bankq, min_filter_length_x4q
+ PUSH min_filter_length_x4q
+ PUSH filter_bankq
+ PUSH dword [ctxq+ResampleContext.phase_shift]
+
+ DEFINE_ARGS filter1, min_filter_count_x4, filter2, frac, index, dst, src
+
+%define phase_shift_stackd dword [rsp+0x0]
+%define filter_bankq dword [rsp+0x4]
+%define min_filter_length_x4q dword [rsp+0x8]
+%define src_incrd dword [rsp+0xc]
+%define phase_mask_stackd dword [rsp+0x10]
+%define filter_alloc_x4q dword [rsp+0x14]
+%define filter_allocd dword [rsp+0x18]
+%define dst_incr_modd dword [rsp+0x1c]
+%define dst_endq dword [rsp+0x20]
+%define dst_incr_divd dword [rsp+0x24]
+
+ mov srcq, r2mp
+%endif
+
+.loop:
+ mov filter1d, filter_allocd
+ imul filter1d, indexd
+%if ARCH_X86_64
+ mov min_filter_count_x4q, min_filter_len_x4q
+ lea filter1q, [filter_bankq+filter1q*%2]
+ lea filter2q, [filter1q+filter_allocq*%2]
+%else ; x86-32
+ mov min_filter_count_x4q, filter_bankq
+ lea filter1q, [min_filter_count_x4q+filter1q*%2]
+ mov min_filter_count_x4q, min_filter_length_x4q
+ mov filter2q, filter1q
+ add filter2q, filter_alloc_x4q
+%endif
+%ifidn %1, int16
+ mova m0, m4
+ mova m2, m4
+%else ; float/double
+ xorps m0, m0, m0
+ xorps m2, m2, m2
+%endif
+
+ align 16
+.inner_loop:
+ movu m1, [srcq+min_filter_count_x4q*1]
+%ifidn %1, int16
+%if cpuflag(xop)
+ vpmadcswd m2, m1, [filter2q+min_filter_count_x4q*1], m2
+ vpmadcswd m0, m1, [filter1q+min_filter_count_x4q*1], m0
+%else
+ pmaddwd m3, m1, [filter2q+min_filter_count_x4q*1]
+ pmaddwd m1, [filter1q+min_filter_count_x4q*1]
+ paddd m2, m3
+ paddd m0, m1
+%endif ; cpuflag
+%else ; float/double
+%if cpuflag(fma4) || cpuflag(fma3)
+ fmaddp%4 m2, m1, [filter2q+min_filter_count_x4q*1], m2
+ fmaddp%4 m0, m1, [filter1q+min_filter_count_x4q*1], m0
+%else
+ mulp%4 m3, m1, [filter2q+min_filter_count_x4q*1]
+ mulp%4 m1, m1, [filter1q+min_filter_count_x4q*1]
+ addp%4 m2, m2, m3
+ addp%4 m0, m0, m1
+%endif ; cpuflag
+%endif
+ add min_filter_count_x4q, mmsize
+ js .inner_loop
+
+%ifidn %1, int16
+%if mmsize == 16
+%if cpuflag(xop)
+ vphadddq m2, m2
+ vphadddq m0, m0
+%endif
+ pshufd m3, m2, q0032
+ pshufd m1, m0, q0032
+ paddd m2, m3
+ paddd m0, m1
+%endif
+%if notcpuflag(xop)
+ PSHUFLW m3, m2, q0032
+ PSHUFLW m1, m0, q0032
+ paddd m2, m3
+ paddd m0, m1
+%endif
+ psubd m2, m0
+ ; This is probably a really bad idea on atom and other machines with a
+ ; long transfer latency between GPRs and XMMs (atom). However, it does
+ ; make the clip a lot simpler...
+ movd eax, m2
+ add indexd, dst_incr_divd
+ imul fracd
+ idiv src_incrd
+ movd m1, eax
+ add fracd, dst_incr_modd
+ paddd m0, m1
+ psrad m0, 15
+ packssdw m0, m0
+ movd [dstq], m0
+
+ ; note that for imul/idiv, I need to move filter to edx/eax for each:
+ ; - 32bit: eax=r0[filter1], edx=r2[filter2]
+ ; - win64: eax=r6[filter1], edx=r1[todo]
+ ; - unix64: eax=r6[filter1], edx=r2[todo]
+%else ; float/double
+ ; val += (v2 - val) * (FELEML) frac / c->src_incr;
+%if mmsize == 32
+ vextractf128 xm1, m0, 0x1
+ vextractf128 xm3, m2, 0x1
+ addps xm0, xm1
+ addps xm2, xm3
+%endif
+ cvtsi2s%4 xm1, fracd
+ subp%4 xm2, xm0
+ mulp%4 xm1, xm4
+ shufp%4 xm1, xm1, q0000
+%if cpuflag(fma4) || cpuflag(fma3)
+ fmaddp%4 xm0, xm2, xm1, xm0
+%else
+ mulp%4 xm2, xm1
+ addp%4 xm0, xm2
+%endif ; cpuflag
+
+ ; horizontal sum & store
+ movhlps xm1, xm0
+%ifidn %1, float
+ addps xm0, xm1
+ shufps xm1, xm0, xm0, q0001
+%endif
+ add fracd, dst_incr_modd
+ addp%4 xm0, xm1
+ add indexd, dst_incr_divd
+ movs%4 [dstq], xm0
+%endif
+ cmp fracd, src_incrd
+ jl .skip
+ sub fracd, src_incrd
+ inc indexd
+
+%if UNIX64
+ DEFINE_ARGS filter_alloc, dst, filter2, phase_shift, index, frac, index_incr, \
+ dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+ dst_incr_div, src_incr, src, dst_end, filter_bank
+%elif WIN64
+ DEFINE_ARGS phase_shift, filter2, src, filter_alloc, index, frac, index_incr, \
+ dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+ dst_incr_div, src_incr, dst, dst_end, filter_bank
+%else ; x86-32
+ DEFINE_ARGS filter1, phase_shift, index_incr, frac, index, dst, src
+%endif
+
+.skip:
+%if ARCH_X86_32
+ mov phase_shiftd, phase_shift_stackd
+%endif
+ mov index_incrd, indexd
+ add dstq, %2
+ and indexd, phase_mask_stackd
+ sar index_incrd, phase_shiftb
+ lea srcq, [srcq+index_incrq*%2]
+ cmp dstq, dst_endq
+ jne .loop
+
+%if UNIX64
+ DEFINE_ARGS ctx, dst, filter2, phase_shift, index, frac, index_incr, \
+ dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+ dst_incr_div, src_incr, src, dst_end, filter_bank
+%elif WIN64
+ DEFINE_ARGS ctx, filter2, src, phase_shift, index, frac, index_incr, \
+ dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+ dst_incr_div, src_incr, dst, dst_end, filter_bank
+%else ; x86-32
+ DEFINE_ARGS filter1, ctx, update_context, frac, index, dst, src
+%endif
+
+ cmp dword update_context_stackd, 0
+ jz .skip_store
+ ; strictly speaking, the function should always return the consumed
+ ; number of bytes; however, we only use the value if update_context
+ ; is true, so let's just leave it uninitialized otherwise
+ mov ctxq, ctx_stackq
+ movifnidn rax, srcq
+ mov [ctxq+ResampleContext.frac ], fracd
+ sub rax, src_stackq
+ mov [ctxq+ResampleContext.index], indexd
+ shr rax, %3
+
+.skip_store:
+%if ARCH_X86_32
+ ADD rsp, 0x28
+%endif
+ RET
+%endmacro
+
+INIT_XMM sse
+RESAMPLE_FNS float, 4, 2, s, pf_1
+
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+RESAMPLE_FNS float, 4, 2, s, pf_1
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+RESAMPLE_FNS float, 4, 2, s, pf_1
+%endif
+%if HAVE_FMA4_EXTERNAL
+INIT_XMM fma4
+RESAMPLE_FNS float, 4, 2, s, pf_1
+%endif
+
+%if ARCH_X86_32
+INIT_MMX mmxext
+RESAMPLE_FNS int16, 2, 1
+%endif
+
+INIT_XMM sse2
+RESAMPLE_FNS int16, 2, 1
+%if HAVE_XOP_EXTERNAL
+INIT_XMM xop
+RESAMPLE_FNS int16, 2, 1
+%endif
+
+INIT_XMM sse2
+RESAMPLE_FNS double, 8, 3, d, pdbl_1
diff --git a/libswresample/x86/resample_init.c b/libswresample/x86/resample_init.c
new file mode 100644
index 0000000000..93001d65cb
--- /dev/null
+++ b/libswresample/x86/resample_init.c
@@ -0,0 +1,90 @@
+/*
+ * audio resampling
+ * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * audio resampling
+ * @author Michael Niedermayer <michaelni@gmx.at>
+ */
+
+#include "libavutil/x86/cpu.h"
+#include "libswresample/resample.h"
+
+#define RESAMPLE_FUNCS(type, opt) \
+int ff_resample_common_##type##_##opt(ResampleContext *c, void *dst, \
+ const void *src, int sz, int upd); \
+int ff_resample_linear_##type##_##opt(ResampleContext *c, void *dst, \
+ const void *src, int sz, int upd)
+
+RESAMPLE_FUNCS(int16, mmxext);
+RESAMPLE_FUNCS(int16, sse2);
+RESAMPLE_FUNCS(int16, xop);
+RESAMPLE_FUNCS(float, sse);
+RESAMPLE_FUNCS(float, avx);
+RESAMPLE_FUNCS(float, fma3);
+RESAMPLE_FUNCS(float, fma4);
+RESAMPLE_FUNCS(double, sse2);
+
+av_cold void swri_resample_dsp_x86_init(ResampleContext *c)
+{
+ int av_unused mm_flags = av_get_cpu_flags();
+
+ switch(c->format){
+ case AV_SAMPLE_FMT_S16P:
+ if (ARCH_X86_32 && EXTERNAL_MMXEXT(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_int16_mmxext
+ : ff_resample_common_int16_mmxext;
+ }
+ if (EXTERNAL_SSE2(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_int16_sse2
+ : ff_resample_common_int16_sse2;
+ }
+ if (EXTERNAL_XOP(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_int16_xop
+ : ff_resample_common_int16_xop;
+ }
+ break;
+ case AV_SAMPLE_FMT_FLTP:
+ if (EXTERNAL_SSE(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_float_sse
+ : ff_resample_common_float_sse;
+ }
+ if (EXTERNAL_AVX(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_float_avx
+ : ff_resample_common_float_avx;
+ }
+ if (EXTERNAL_FMA3(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_float_fma3
+ : ff_resample_common_float_fma3;
+ }
+ if (EXTERNAL_FMA4(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_float_fma4
+ : ff_resample_common_float_fma4;
+ }
+ break;
+ case AV_SAMPLE_FMT_DBLP:
+ if (EXTERNAL_SSE2(mm_flags)) {
+ c->dsp.resample = c->linear ? ff_resample_linear_double_sse2
+ : ff_resample_common_double_sse2;
+ }
+ break;
+ }
+}
diff --git a/libswresample/x86/w64xmmtest.c b/libswresample/x86/w64xmmtest.c
new file mode 100644
index 0000000000..9cddb4a858
--- /dev/null
+++ b/libswresample/x86/w64xmmtest.c
@@ -0,0 +1,29 @@
+/*
+ * check XMM registers for clobbers on Win64
+ * Copyright (c) 2013 Martin Storsjo
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libswresample/swresample.h"
+#include "libavutil/x86/w64xmmtest.h"
+
+wrap(swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
+ const uint8_t **in , int in_count))
+{
+ testxmmclobbers(swr_convert, s, out, out_count, in, in_count);
+}
diff --git a/libswscale/Makefile b/libswscale/Makefile
index 3e8614da2b..a60b05748d 100644
--- a/libswscale/Makefile
+++ b/libswscale/Makefile
@@ -1,9 +1,12 @@
+include $(SUBDIR)../config.mak
+
NAME = swscale
HEADERS = swscale.h \
version.h \
-OBJS = input.o \
+OBJS = hscale_fast_bilinear.o \
+ input.o \
options.o \
output.o \
rgb2rgb.o \
@@ -12,5 +15,10 @@ OBJS = input.o \
utils.o \
yuv2rgb.o \
+OBJS-$(CONFIG_SHARED) += log2_tab.o
+
+# Windows resource file
+SLIBOBJS-$(HAVE_GNU_WINDRES) += swscaleres.o
+
TESTPROGS = colorspace \
swscale \
diff --git a/libswscale/arm/Makefile b/libswscale/arm/Makefile
new file mode 100644
index 0000000000..8b5a97b54c
--- /dev/null
+++ b/libswscale/arm/Makefile
@@ -0,0 +1,4 @@
+# OBJS += arm/swscale_unscaled.o
+
+# NEON-OBJS += arm/rgb2yuv_neon_32.o
+# NEON-OBJS += arm/rgb2yuv_neon_16.o
diff --git a/libswscale/arm/rgb2yuv_neon_16.S b/libswscale/arm/rgb2yuv_neon_16.S
new file mode 100644
index 0000000000..601bc9a9b7
--- /dev/null
+++ b/libswscale/arm/rgb2yuv_neon_16.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 Xiaolei Yu <dreifachstein@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
+ */
+
+#include "rgb2yuv_neon_common.S"
+
+/* downsampled R16G16B16 x8 */
+alias_qw r16x8, q7
+alias_qw g16x8, q8
+alias_qw b16x8, q9
+
+alias n16x16_l, q11
+alias n16x16_h, q12
+
+alias y16x16_l, q13
+alias y16x16_h, q14
+
+alias_qw y8x16, q15
+
+.macro init src
+ vld3.i32 {q13_l, q14_l, q15_l}, [\src]!
+ vld3.i32 {q13_h[0], q14_h[0], q15_h[0]}, [\src]
+ vrshrn.i32 CO_R, q13, #7
+ vrshrn.i32 CO_G, q14, #7
+ vrshrn.i32 CO_B, q15, #7
+
+ vmov.u8 BIAS_Y, #16
+ vmov.u8 BIAS_U, #128
+.endm
+
+
+.macro compute_y_16x1_step action, s8x16, coeff
+ vmovl.u8 n16x16_l, \s8x16\()_l
+ vmovl.u8 n16x16_h, \s8x16\()_h
+
+ \action y16x16_l, n16x16_l, \coeff
+ \action y16x16_h, n16x16_h, \coeff
+.endm
+
+.macro compute_y_16x1
+ compute_y_16x1_step vmul, r8x16, CO_RY
+ compute_y_16x1_step vmla, g8x16, CO_GY
+ compute_y_16x1_step vmla, b8x16, CO_BY
+
+ vrshrn.i16 y8x16_l, y16x16_l, #8
+ vrshrn.i16 y8x16_h, y16x16_h, #8
+
+ vadd.u8 y8x16, y8x16, BIAS_Y
+.endm
+
+alias c16x8, q15
+alias_qw c8x8x2, q10
+
+
+.macro compute_chroma_8x1 c, C
+ vmul c16x8, r16x8, CO_R\C
+ vmla c16x8, g16x8, CO_G\C
+ vmla c16x8, b16x8, CO_B\C
+
+ vrshrn.i16 \c\()8x8, c16x8, #8
+ vadd.u8 \c\()8x8, \c\()8x8, BIAS_\C
+.endm
+
+ loop_420sp rgbx, nv12, init, kernel_420_16x2, 16
diff --git a/libswscale/arm/rgb2yuv_neon_32.S b/libswscale/arm/rgb2yuv_neon_32.S
new file mode 100644
index 0000000000..f51a5f149f
--- /dev/null
+++ b/libswscale/arm/rgb2yuv_neon_32.S
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 Xiaolei Yu <dreifachstein@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
+ */
+
+#include "rgb2yuv_neon_common.S"
+
+/* downsampled R16G16B16 x8 */
+alias_qw r16x8, q7
+alias_qw g16x8, q8
+alias_qw b16x8, q9
+
+alias n16x16_o, q11
+alias n16x16_ol, q11_l
+alias n16x16_oh, q11_h
+
+alias y32x16_el, q12
+alias y32x16_eh, q13
+alias y32x16_ol, q14
+alias y32x16_oh, q15
+
+alias y16x16_e, q12
+alias y16x16_el, q12_l
+alias y16x16_eh, q12_h
+alias y16x16_o, q13
+alias y16x16_ol, q13_l
+alias y16x16_oh, q13_h
+
+
+alias y8x16, y16x16_e
+
+
+.macro init src
+ // load s32x3x3, narrow to s16x3x3
+ vld3.i32 {q13_l, q14_l, q15_l}, [\src]!
+ vld3.i32 {q13_h[0], q14_h[0], q15_h[0]}, [\src]
+
+ vmovn.i32 CO_R, q13
+ vmovn.i32 CO_G, q14
+ vmovn.i32 CO_B, q15
+
+ vmov.u8 BIAS_Y, #16
+ vmov.u8 BIAS_U, #128
+.endm
+
+
+.macro compute_y_16x1_step action, s8x16, coeff
+ vmov.u8 n16x16_o, #0
+ vtrn.u8 \s8x16, n16x16_o
+
+ \action y32x16_el, \s8x16\()_l, \coeff
+ \action y32x16_eh, \s8x16\()_h, \coeff
+ \action y32x16_ol, n16x16_ol, \coeff
+ \action y32x16_oh, n16x16_oh, \coeff
+.endm
+
+/*
+ * in: r8x16, g8x16, b8x16
+ * out: y8x16
+ * clobber: q11-q15, r8x16, g8x16, b8x16
+ */
+.macro compute_y_16x1
+ compute_y_16x1_step vmull, r8x16, CO_RY
+ compute_y_16x1_step vmlal, g8x16, CO_GY
+ compute_y_16x1_step vmlal, b8x16, CO_BY
+
+ vrshrn.i32 y16x16_el, y32x16_el, #15
+ vrshrn.i32 y16x16_eh, y32x16_eh, #15
+ vrshrn.i32 y16x16_ol, y32x16_ol, #15
+ vrshrn.i32 y16x16_oh, y32x16_oh, #15
+
+ vtrn.8 y16x16_e, y16x16_o
+ vadd.u8 y8x16, y8x16, BIAS_Y
+.endm
+
+alias c32x8_l, q14
+alias c32x8_h, q15
+
+alias_qw c16x8, q13
+alias_qw c8x8x2, q10
+
+.macro compute_chroma_8x1_step action, s16x8, coeff
+ \action c32x8_l, \s16x8\()_l, \coeff
+ \action c32x8_h, \s16x8\()_h, \coeff
+.endm
+
+/*
+ * in: r16x8, g16x8, b16x8
+ * out: c8x8
+ * clobber: q14-q15
+ */
+.macro compute_chroma_8x1 c, C
+ compute_chroma_8x1_step vmull, r16x8, CO_R\C
+ compute_chroma_8x1_step vmlal, g16x8, CO_G\C
+ compute_chroma_8x1_step vmlal, b16x8, CO_B\C
+
+ vrshrn.i32 c16x8_l, c32x8_l, #15
+ vrshrn.i32 c16x8_h, c32x8_h, #15
+ vmovn.i16 \c\()8x8, c16x8
+ vadd.u8 \c\()8x8, \c\()8x8, BIAS_\C
+.endm
+
+
+ loop_420sp rgbx, nv12, init, kernel_420_16x2, 32
diff --git a/libswscale/arm/rgb2yuv_neon_common.S b/libswscale/arm/rgb2yuv_neon_common.S
new file mode 100644
index 0000000000..30bcecd5bb
--- /dev/null
+++ b/libswscale/arm/rgb2yuv_neon_common.S
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2013 Xiaolei Yu <dreifachstein@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
+ */
+
+#include "libavutil/arm/asm.S"
+
+.macro alias name, tgt, set=1
+.if \set != 0
+ \name .req \tgt
+.else
+ .unreq \name
+.endif
+.endm
+
+.altmacro
+
+.macro alias_dw_all qw, dw_l, dw_h
+ alias q\qw\()_l, d\dw_l
+ alias q\qw\()_h, d\dw_h
+ .if \qw < 15
+ alias_dw_all %(\qw + 1), %(\dw_l + 2), %(\dw_h + 2)
+ .endif
+.endm
+
+alias_dw_all 0, 0, 1
+
+.noaltmacro
+
+.macro alias_qw name, qw, set=1
+ alias \name\(), \qw, \set
+ alias \name\()_l, \qw\()_l, \set
+ alias \name\()_h, \qw\()_h, \set
+.endm
+
+.macro prologue
+ push {r4-r12, lr}
+ vpush {q4-q7}
+.endm
+
+.macro epilogue
+ vpop {q4-q7}
+ pop {r4-r12, pc}
+.endm
+
+.macro load_arg reg, ix
+ ldr \reg, [sp, #((10 * 4 + 4 * 16) + (\ix - 4) * 4)]
+.endm
+
+
+/* ()_to_()_neon(const uint8_t *src, uint8_t *y, uint8_t *chroma
+ * int width, int height,
+ * int y_stride, int c_stride, int src_stride,
+ * int32_t coeff_table[9]);
+ */
+.macro alias_loop_420sp set=1
+ alias src, r0, \set
+ alias src0, src, \set
+ alias y, r1, \set
+ alias y0, y, \set
+ alias chroma, r2, \set
+ alias width, r3, \set
+ alias header, width, \set
+
+ alias height, r4, \set
+ alias y_stride, r5, \set
+ alias c_stride, r6, \set
+ alias c_padding, c_stride, \set
+ alias src_stride, r7, \set
+
+ alias y0_end, r8, \set
+
+ alias src_padding,r9, \set
+ alias y_padding, r10, \set
+
+ alias src1, r11, \set
+ alias y1, r12, \set
+
+ alias coeff_table,r12, \set
+.endm
+
+
+.macro loop_420sp s_fmt, d_fmt, init, kernel, precision
+
+function \s_fmt\()_to_\d_fmt\()_neon_\precision, export=1
+ prologue
+
+ alias_loop_420sp
+
+ load_arg height, 4
+ load_arg y_stride, 5
+ load_arg c_stride, 6
+ load_arg src_stride, 7
+ load_arg coeff_table, 8
+
+ \init coeff_table
+
+ sub y_padding, y_stride, width
+ sub c_padding, c_stride, width
+ sub src_padding, src_stride, width, LSL #2
+
+ add y0_end, y0, width
+ and header, width, #15
+
+ add y1, y0, y_stride
+ add src1, src0, src_stride
+
+0:
+ cmp header, #0
+ beq 1f
+
+ \kernel \s_fmt, \d_fmt, src0, src1, y0, y1, chroma, header
+
+1:
+ \kernel \s_fmt, \d_fmt, src0, src1, y0, y1, chroma
+
+ cmp y0, y0_end
+ blt 1b
+2:
+ add y0, y1, y_padding
+ add y0_end, y1, y_stride
+ add chroma, chroma, c_padding
+ add src0, src1, src_padding
+
+ add y1, y0, y_stride
+ add src1, src0, src_stride
+
+ subs height, height, #2
+
+ bgt 0b
+
+ epilogue
+
+ alias_loop_420sp 0
+
+endfunc
+.endm
+
+.macro downsample
+ vpaddl.u8 r16x8, r8x16
+ vpaddl.u8 g16x8, g8x16
+ vpaddl.u8 b16x8, b8x16
+.endm
+
+
+/* acculumate and right shift by 2 */
+.macro downsample_ars2
+ vpadal.u8 r16x8, r8x16
+ vpadal.u8 g16x8, g8x16
+ vpadal.u8 b16x8, b8x16
+
+ vrshr.u16 r16x8, r16x8, #2
+ vrshr.u16 g16x8, g16x8, #2
+ vrshr.u16 b16x8, b16x8, #2
+.endm
+
+.macro store_y8_16x1 dst, count
+.ifc "\count",""
+ vstmia \dst!, {y8x16}
+.else
+ vstmia \dst, {y8x16}
+ add \dst, \dst, \count
+.endif
+.endm
+
+.macro store_chroma_nv12_8x1 dst, count
+.ifc "\count",""
+ vst2.i8 {u8x8, v8x8}, [\dst]!
+.else
+ vst2.i8 {u8x8, v8x8}, [\dst], \count
+.endif
+.endm
+
+.macro store_chroma_nv21_8x1 dst, count
+.ifc "\count",""
+ vst2.i8 {v8x8, u8x8}, [\dst]!
+.else
+ vst2.i8 {v8x8, u8x8}, [\dst], \count
+.endif
+.endm
+
+.macro load_8888_16x1 a, b, c, d, src, count
+.ifc "\count",""
+ vld4.8 {\a\()8x16_l, \b\()8x16_l, \c\()8x16_l, \d\()8x16_l}, [\src]!
+ vld4.8 {\a\()8x16_h, \b\()8x16_h, \c\()8x16_h, \d\()8x16_h}, [\src]!
+.else
+ vld4.8 {\a\()8x16_l, \b\()8x16_l, \c\()8x16_l, \d\()8x16_l}, [\src]!
+ vld4.8 {\a\()8x16_h, \b\()8x16_h, \c\()8x16_h, \d\()8x16_h}, [\src]
+ sub \src, \src, #32
+ add \src, \src, \count, LSL #2
+.endif
+.endm
+
+.macro load_rgbx_16x1 src, count
+ load_8888_16x1 r, g, b, x, \src, \count
+.endm
+
+.macro load_bgrx_16x1 src, count
+ load_8888_16x1 b, g, r, x, \src, \count
+.endm
+
+.macro alias_src_rgbx set=1
+ alias_src_8888 r, g, b, x, \set
+.endm
+
+.macro alias_src_bgrx set=1
+ alias_src_8888 b, g, r, x, \set
+.endm
+
+.macro alias_dst_nv12 set=1
+ alias u8x8, c8x8x2_l, \set
+ alias v8x8, c8x8x2_h, \set
+.endm
+
+.macro alias_dst_nv21 set=1
+ alias v8x8, c8x8x2_l, \set
+ alias u8x8, c8x8x2_h, \set
+.endm
+
+
+// common aliases
+
+alias CO_R d0
+CO_RY .dn d0.s16[0]
+CO_RU .dn d0.s16[1]
+CO_RV .dn d0.s16[2]
+
+alias CO_G d1
+CO_GY .dn d1.s16[0]
+CO_GU .dn d1.s16[1]
+CO_GV .dn d1.s16[2]
+
+alias CO_B d2
+CO_BY .dn d2.s16[0]
+CO_BU .dn d2.s16[1]
+CO_BV .dn d2.s16[2]
+
+alias BIAS_U, d3
+alias BIAS_V, BIAS_U
+
+alias BIAS_Y, q2
+
+
+/* q3-q6 R8G8B8X8 x16 */
+
+.macro alias_src_8888 a, b, c, d, set
+ alias_qw \a\()8x16, q3, \set
+ alias_qw \b\()8x16, q4, \set
+ alias_qw \c\()8x16, q5, \set
+ alias_qw \d\()8x16, q6, \set
+.endm
+
+.macro kernel_420_16x2 rgb_fmt, yuv_fmt, rgb0, rgb1, y0, y1, chroma, count
+ alias_src_\rgb_fmt
+ alias_dst_\yuv_fmt
+
+ load_\rgb_fmt\()_16x1 \rgb0, \count
+
+ downsample
+ compute_y_16x1
+ store_y8_16x1 \y0, \count
+
+
+ load_\rgb_fmt\()_16x1 \rgb1, \count
+ downsample_ars2
+ compute_y_16x1
+ store_y8_16x1 \y1, \count
+
+ compute_chroma_8x1 u, U
+ compute_chroma_8x1 v, V
+
+ store_chroma_\yuv_fmt\()_8x1 \chroma, \count
+
+ alias_dst_\yuv_fmt 0
+ alias_src_\rgb_fmt 0
+.endm
diff --git a/libswscale/arm/swscale_unscaled.c b/libswscale/arm/swscale_unscaled.c
new file mode 100644
index 0000000000..04be7622bc
--- /dev/null
+++ b/libswscale/arm/swscale_unscaled.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 Xiaolei Yu <dreifachstein@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
+ */
+
+#include "config.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/arm/cpu.h"
+
+extern void rgbx_to_nv12_neon_32(const uint8_t *src, uint8_t *y, uint8_t *chroma,
+ int width, int height,
+ int y_stride, int c_stride, int src_stride,
+ int32_t coeff_tbl[9]);
+
+extern void rgbx_to_nv12_neon_16(const uint8_t *src, uint8_t *y, uint8_t *chroma,
+ int width, int height,
+ int y_stride, int c_stride, int src_stride,
+ int32_t coeff_tbl[9]);
+
+static int rgbx_to_nv12_neon_32_wrapper(SwsContext *context, const uint8_t *src[],
+ int srcStride[], int srcSliceY, int srcSliceH,
+ uint8_t *dst[], int dstStride[]) {
+
+ rgbx_to_nv12_neon_32(src[0] + srcSliceY * srcStride[0],
+ dst[0] + srcSliceY * dstStride[0],
+ dst[1] + (srcSliceY / 2) * dstStride[1],
+ context->srcW, srcSliceH,
+ dstStride[0], dstStride[1], srcStride[0],
+ context->input_rgb2yuv_table);
+
+ return 0;
+}
+
+static int rgbx_to_nv12_neon_16_wrapper(SwsContext *context, const uint8_t *src[],
+ int srcStride[], int srcSliceY, int srcSliceH,
+ uint8_t *dst[], int dstStride[]) {
+
+ rgbx_to_nv12_neon_16(src[0] + srcSliceY * srcStride[0],
+ dst[0] + srcSliceY * dstStride[0],
+ dst[1] + (srcSliceY / 2) * dstStride[1],
+ context->srcW, srcSliceH,
+ dstStride[0], dstStride[1], srcStride[0],
+ context->input_rgb2yuv_table);
+
+ return 0;
+}
+
+static void get_unscaled_swscale_neon(SwsContext *c) {
+ int accurate_rnd = c->flags & SWS_ACCURATE_RND;
+ if (c->srcFormat == AV_PIX_FMT_RGBA
+ && c->dstFormat == AV_PIX_FMT_NV12
+ && (c->srcW >= 16)) {
+ c->swscale = accurate_rnd ? rgbx_to_nv12_neon_32_wrapper
+ : rgbx_to_nv12_neon_16_wrapper;
+ }
+}
+
+void ff_get_unscaled_swscale_arm(SwsContext *c)
+{
+ int cpu_flags = av_get_cpu_flags();
+ if (have_neon(cpu_flags))
+ get_unscaled_swscale_neon(c);
+}
diff --git a/libswscale/bayer_template.c b/libswscale/bayer_template.c
new file mode 100644
index 0000000000..1af1b6056e
--- /dev/null
+++ b/libswscale/bayer_template.c
@@ -0,0 +1,236 @@
+/*
+ * Bayer-to-RGB/YV12 template
+ * Copyright (c) 2011-2014 Peter Ross <pross@xvid.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if defined(BAYER_BGGR) || defined(BAYER_GBRG)
+#define BAYER_R 0
+#define BAYER_G 1
+#define BAYER_B 2
+#endif
+#if defined(BAYER_RGGB) || defined(BAYER_GRBG)
+#define BAYER_R 2
+#define BAYER_G 1
+#define BAYER_B 0
+#endif
+
+#if defined(BAYER_8)
+#define BAYER_READ(x) (x)
+#define BAYER_SIZEOF 1
+#define BAYER_SHIFT 0
+#endif
+#if defined(BAYER_16LE)
+#define BAYER_READ(x) AV_RL16(&(x))
+#define BAYER_SIZEOF 2
+#define BAYER_SHIFT 8
+#endif
+#if defined(BAYER_16BE)
+#define BAYER_READ(x) AV_RB16(&(x))
+#define BAYER_SIZEOF 2
+#define BAYER_SHIFT 8
+#endif
+
+#define S(y, x) BAYER_READ(src[(y)*src_stride + BAYER_SIZEOF*(x)])
+#define T(y, x) (unsigned int)S(y, x)
+#define R(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_R]
+#define G(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_G]
+#define B(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_B]
+
+#if defined(BAYER_BGGR) || defined(BAYER_RGGB)
+#define BAYER_TO_RGB24_COPY \
+ R(0, 0) = \
+ R(0, 1) = \
+ R(1, 1) = \
+ R(1, 0) = S(1, 1) >> BAYER_SHIFT; \
+ \
+ G(0, 1) = S(0, 1) >> BAYER_SHIFT; \
+ G(0, 0) = \
+ G(1, 1) = (T(0, 1) + T(1, 0)) >> (1 + BAYER_SHIFT); \
+ G(1, 0) = S(1, 0) >> BAYER_SHIFT; \
+ \
+ B(1, 1) = \
+ B(0, 0) = \
+ B(0, 1) = \
+ B(1, 0) = S(0, 0) >> BAYER_SHIFT;
+#define BAYER_TO_RGB24_INTERPOLATE \
+ R(0, 0) = (T(-1, -1) + T(-1, 1) + T(1, -1) + T(1, 1)) >> (2 + BAYER_SHIFT); \
+ G(0, 0) = (T(-1, 0) + T( 0, -1) + T(0, 1) + T(1, 0)) >> (2 + BAYER_SHIFT); \
+ B(0, 0) = S(0, 0) >> BAYER_SHIFT; \
+ \
+ R(0, 1) = (T(-1, 1) + T(1, 1)) >> (1 + BAYER_SHIFT); \
+ G(0, 1) = S(0, 1) >> BAYER_SHIFT; \
+ B(0, 1) = (T(0, 0) + T(0, 2)) >> (1 + BAYER_SHIFT); \
+ \
+ R(1, 0) = (T(1, -1) + T(1, 1)) >> (1 + BAYER_SHIFT); \
+ G(1, 0) = S(1, 0) >> BAYER_SHIFT; \
+ B(1, 0) = (T(0, 0) + T(2, 0)) >> (1 + BAYER_SHIFT); \
+ \
+ R(1, 1) = S(1, 1) >> BAYER_SHIFT; \
+ G(1, 1) = (T(0, 1) + T(1, 0) + T(1, 2) + T(2, 1)) >> (2 + BAYER_SHIFT); \
+ B(1, 1) = (T(0, 0) + T(0, 2) + T(2, 0) + T(2, 2)) >> (2 + BAYER_SHIFT);
+#else
+#define BAYER_TO_RGB24_COPY \
+ R(0, 0) = \
+ R(0, 1) = \
+ R(1, 1) = \
+ R(1, 0) = S(1, 0) >> BAYER_SHIFT; \
+ \
+ G(0, 0) = S(0, 0) >> BAYER_SHIFT; \
+ G(1, 1) = S(1, 1) >> BAYER_SHIFT; \
+ G(0, 1) = \
+ G(1, 0) = (T(0, 0) + T(1, 1)) >> (1 + BAYER_SHIFT); \
+ \
+ B(1, 1) = \
+ B(0, 0) = \
+ B(0, 1) = \
+ B(1, 0) = S(0, 1) >> BAYER_SHIFT;
+#define BAYER_TO_RGB24_INTERPOLATE \
+ R(0, 0) = (T(-1, 0) + T(1, 0)) >> (1 + BAYER_SHIFT); \
+ G(0, 0) = S(0, 0) >> BAYER_SHIFT; \
+ B(0, 0) = (T(0, -1) + T(0, 1)) >> (1 + BAYER_SHIFT); \
+ \
+ R(0, 1) = (T(-1, 0) + T(-1, 2) + T(1, 0) + T(1, 2)) >> (2 + BAYER_SHIFT); \
+ G(0, 1) = (T(-1, 1) + T(0, 0) + T(0, 2) + T(1, 1)) >> (2 + BAYER_SHIFT); \
+ B(0, 1) = S(0, 1) >> BAYER_SHIFT; \
+ \
+ R(1, 0) = S(1, 0) >> BAYER_SHIFT; \
+ G(1, 0) = (T(0, 0) + T(1, -1) + T(1, 1) + T(2, 0)) >> (2 + BAYER_SHIFT); \
+ B(1, 0) = (T(0, -1) + T(0, 1) + T(2, -1) + T(2, 1)) >> (2 + BAYER_SHIFT); \
+ \
+ R(1, 1) = (T(1, 0) + T(1, 2)) >> (1 + BAYER_SHIFT); \
+ G(1, 1) = S(1, 1) >> BAYER_SHIFT; \
+ B(1, 1) = (T(0, 1) + T(2, 1)) >> (1 + BAYER_SHIFT);
+#endif
+
+/**
+ * invoke ff_rgb24toyv12 for 2x2 pixels
+ */
+#define rgb24toyv12_2x2(src, dstY, dstU, dstV, luma_stride, src_stride, rgb2yuv) \
+ ff_rgb24toyv12(src, dstY, dstV, dstU, 2, 2, luma_stride, 0, src_stride, rgb2yuv)
+
+static void BAYER_RENAME(rgb24_copy)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width)
+{
+ int i;
+ for (i = 0 ; i < width; i+= 2) {
+ BAYER_TO_RGB24_COPY
+ src += 2 * BAYER_SIZEOF;
+ dst += 6;
+ }
+}
+
+static void BAYER_RENAME(rgb24_interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width)
+{
+ int i;
+
+ BAYER_TO_RGB24_COPY
+ src += 2 * BAYER_SIZEOF;
+ dst += 6;
+
+ for (i = 2 ; i < width - 2; i+= 2) {
+ BAYER_TO_RGB24_INTERPOLATE
+ src += 2 * BAYER_SIZEOF;
+ dst += 6;
+ }
+
+ if (width > 2) {
+ BAYER_TO_RGB24_COPY
+ }
+}
+
+static void BAYER_RENAME(yv12_copy)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv)
+{
+ uint8_t dst[12];
+ const int dst_stride = 6;
+ int i;
+ for (i = 0 ; i < width; i+= 2) {
+ BAYER_TO_RGB24_COPY
+ rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+ src += 2 * BAYER_SIZEOF;
+ dstY += 2;
+ dstU++;
+ dstV++;
+ }
+}
+
+static void BAYER_RENAME(yv12_interpolate)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv)
+{
+ uint8_t dst[12];
+ const int dst_stride = 6;
+ int i;
+
+ BAYER_TO_RGB24_COPY
+ rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+ src += 2 * BAYER_SIZEOF;
+ dstY += 2;
+ dstU++;
+ dstV++;
+
+ for (i = 2 ; i < width - 2; i+= 2) {
+ BAYER_TO_RGB24_INTERPOLATE
+ rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+ src += 2 * BAYER_SIZEOF;
+ dstY += 2;
+ dstU++;
+ dstV++;
+ }
+
+ if (width > 2) {
+ BAYER_TO_RGB24_COPY
+ rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+ }
+}
+
+#undef S
+#undef T
+#undef R
+#undef G
+#undef B
+#undef BAYER_TO_RGB24_COPY
+#undef BAYER_TO_RGB24_INTERPOLATE
+
+#undef BAYER_RENAME
+
+#undef BAYER_R
+#undef BAYER_G
+#undef BAYER_B
+#undef BAYER_READ
+#undef BAYER_SIZEOF
+#undef BAYER_SHIFT
+
+#if defined(BAYER_BGGR)
+#undef BAYER_BGGR
+#endif
+#if defined(BAYER_RGGB)
+#undef BAYER_RGGB
+#endif
+#if defined(BAYER_GBRG)
+#undef BAYER_GBRG
+#endif
+#if defined(BAYER_GRBG)
+#undef BAYER_GRBG
+#endif
+#if defined(BAYER_8)
+#undef BAYER_8
+#endif
+#if defined(BAYER_16LE)
+#undef BAYER_16LE
+#endif
+#if defined(BAYER_16BE)
+#undef BAYER_16BE
+#endif
diff --git a/libswscale/colorspace-test.c b/libswscale/colorspace-test.c
index fbf595d4c1..42a915bfe6 100644
--- a/libswscale/colorspace-test.c
+++ b/libswscale/colorspace-test.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -33,7 +33,7 @@
#define FUNC(s, d, n) { s, d, #n, n }
-int main(void)
+int main(int argc, char **argv)
{
int i, funcNum;
uint8_t *srcBuffer = av_malloc(SIZE);
@@ -54,6 +54,7 @@ int main(void)
const char *name;
void (*func)(const uint8_t *src, uint8_t *dst, int src_size);
} func_info[] = {
+ FUNC(2, 2, rgb12to15),
FUNC(2, 2, rgb15to16),
FUNC(2, 3, rgb15to24),
FUNC(2, 4, rgb15to32),
@@ -66,6 +67,7 @@ int main(void)
FUNC(4, 2, rgb32to16),
FUNC(4, 3, rgb32to24),
FUNC(2, 2, rgb16to15),
+ FUNC(2, 2, rgb12tobgr12),
FUNC(2, 2, rgb15tobgr15),
FUNC(2, 2, rgb15tobgr16),
FUNC(2, 3, rgb15tobgr24),
@@ -82,6 +84,12 @@ int main(void)
FUNC(4, 2, rgb32tobgr16),
FUNC(4, 3, rgb32tobgr24),
FUNC(4, 4, shuffle_bytes_2103), /* rgb32tobgr32 */
+ FUNC(6, 6, rgb48tobgr48_nobswap),
+ FUNC(6, 6, rgb48tobgr48_bswap),
+ FUNC(8, 6, rgb64to48_nobswap),
+ FUNC(8, 6, rgb64to48_bswap),
+ FUNC(8, 6, rgb64tobgr48_nobswap),
+ FUNC(8, 6, rgb64tobgr48_bswap),
FUNC(0, 0, NULL)
};
int width;
diff --git a/libswscale/hscale_fast_bilinear.c b/libswscale/hscale_fast_bilinear.c
new file mode 100644
index 0000000000..82d6177bde
--- /dev/null
+++ b/libswscale/hscale_fast_bilinear.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_internal.h"
+
+void ff_hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth,
+ const uint8_t *src, int srcW, int xInc)
+{
+ int i;
+ unsigned int xpos = 0;
+ for (i = 0; i < dstWidth; i++) {
+ register unsigned int xx = xpos >> 16;
+ register unsigned int xalpha = (xpos & 0xFFFF) >> 9;
+ dst[i] = (src[xx] << 7) + (src[xx + 1] - src[xx]) * xalpha;
+ xpos += xInc;
+ }
+ for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--)
+ dst[i] = src[srcW-1]*128;
+}
+
+void ff_hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2,
+ int dstWidth, const uint8_t *src1,
+ const uint8_t *src2, int srcW, int xInc)
+{
+ int i;
+ unsigned int xpos = 0;
+ for (i = 0; i < dstWidth; i++) {
+ register unsigned int xx = xpos >> 16;
+ register unsigned int xalpha = (xpos & 0xFFFF) >> 9;
+ dst1[i] = (src1[xx] * (xalpha ^ 127) + src1[xx + 1] * xalpha);
+ dst2[i] = (src2[xx] * (xalpha ^ 127) + src2[xx + 1] * xalpha);
+ xpos += xInc;
+ }
+ for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) {
+ dst1[i] = src1[srcW-1]*128;
+ dst2[i] = src2[srcW-1]*128;
+ }
+}
diff --git a/libswscale/input.c b/libswscale/input.c
index e806bce661..1f04fc2752 100644
--- a/libswscale/input.c
+++ b/libswscale/input.c
@@ -1,24 +1,23 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
@@ -30,38 +29,117 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
#include "config.h"
#include "rgb2rgb.h"
#include "swscale.h"
#include "swscale_internal.h"
-#define RGB2YUV_SHIFT 15
-#define BY ((int)(0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define BV (-(int)(0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define BU ((int)(0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define GY ((int)(0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define GV (-(int)(0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define GU (-(int)(0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define RY ((int)(0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define RV ((int)(0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define RU (-(int)(0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-
#define input_pixel(pos) (isBE(origin) ? AV_RB16(pos) : AV_RL16(pos))
-#define r ((origin == AV_PIX_FMT_BGR48BE || origin == AV_PIX_FMT_BGR48LE) ? b_r : r_b)
-#define b ((origin == AV_PIX_FMT_BGR48BE || origin == AV_PIX_FMT_BGR48LE) ? r_b : b_r)
+#define r ((origin == AV_PIX_FMT_BGR48BE || origin == AV_PIX_FMT_BGR48LE || origin == AV_PIX_FMT_BGRA64BE || origin == AV_PIX_FMT_BGRA64LE) ? b_r : r_b)
+#define b ((origin == AV_PIX_FMT_BGR48BE || origin == AV_PIX_FMT_BGR48LE || origin == AV_PIX_FMT_BGRA64BE || origin == AV_PIX_FMT_BGRA64LE) ? r_b : b_r)
+
+static av_always_inline void
+rgb64ToY_c_template(uint16_t *dst, const uint16_t *src, int width,
+ enum AVPixelFormat origin, int32_t *rgb2yuv)
+{
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
+ int i;
+ for (i = 0; i < width; i++) {
+ unsigned int r_b = input_pixel(&src[i*4+0]);
+ unsigned int g = input_pixel(&src[i*4+1]);
+ unsigned int b_r = input_pixel(&src[i*4+2]);
+
+ dst[i] = (ry*r + gy*g + by*b + (0x2001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
+ }
+}
+
+static av_always_inline void
+rgb64ToUV_c_template(uint16_t *dstU, uint16_t *dstV,
+ const uint16_t *src1, const uint16_t *src2,
+ int width, enum AVPixelFormat origin, int32_t *rgb2yuv)
+{
+ int i;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ av_assert1(src1==src2);
+ for (i = 0; i < width; i++) {
+ int r_b = input_pixel(&src1[i*4+0]);
+ int g = input_pixel(&src1[i*4+1]);
+ int b_r = input_pixel(&src1[i*4+2]);
+
+ dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
+ dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
+ }
+}
+
+static av_always_inline void
+rgb64ToUV_half_c_template(uint16_t *dstU, uint16_t *dstV,
+ const uint16_t *src1, const uint16_t *src2,
+ int width, enum AVPixelFormat origin, int32_t *rgb2yuv)
+{
+ int i;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ av_assert1(src1==src2);
+ for (i = 0; i < width; i++) {
+ int r_b = (input_pixel(&src1[8 * i + 0]) + input_pixel(&src1[8 * i + 4]) + 1) >> 1;
+ int g = (input_pixel(&src1[8 * i + 1]) + input_pixel(&src1[8 * i + 5]) + 1) >> 1;
+ int b_r = (input_pixel(&src1[8 * i + 2]) + input_pixel(&src1[8 * i + 6]) + 1) >> 1;
+
+ dstU[i]= (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
+ dstV[i]= (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT;
+ }
+}
+
+#define rgb64funcs(pattern, BE_LE, origin) \
+static void pattern ## 64 ## BE_LE ## ToY_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, const uint8_t *unused1,\
+ int width, uint32_t *rgb2yuv) \
+{ \
+ const uint16_t *src = (const uint16_t *) _src; \
+ uint16_t *dst = (uint16_t *) _dst; \
+ rgb64ToY_c_template(dst, src, width, origin, rgb2yuv); \
+} \
+ \
+static void pattern ## 64 ## BE_LE ## ToUV_c(uint8_t *_dstU, uint8_t *_dstV, \
+ const uint8_t *unused0, const uint8_t *_src1, const uint8_t *_src2, \
+ int width, uint32_t *rgb2yuv) \
+{ \
+ const uint16_t *src1 = (const uint16_t *) _src1, \
+ *src2 = (const uint16_t *) _src2; \
+ uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \
+ rgb64ToUV_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv); \
+} \
+ \
+static void pattern ## 64 ## BE_LE ## ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, \
+ const uint8_t *unused0, const uint8_t *_src1, const uint8_t *_src2, \
+ int width, uint32_t *rgb2yuv) \
+{ \
+ const uint16_t *src1 = (const uint16_t *) _src1, \
+ *src2 = (const uint16_t *) _src2; \
+ uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \
+ rgb64ToUV_half_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv); \
+}
+
+rgb64funcs(rgb, LE, AV_PIX_FMT_RGBA64LE)
+rgb64funcs(rgb, BE, AV_PIX_FMT_RGBA64BE)
+rgb64funcs(bgr, LE, AV_PIX_FMT_BGRA64LE)
+rgb64funcs(bgr, BE, AV_PIX_FMT_BGRA64BE)
static av_always_inline void rgb48ToY_c_template(uint16_t *dst,
const uint16_t *src, int width,
- enum AVPixelFormat origin)
+ enum AVPixelFormat origin,
+ int32_t *rgb2yuv)
{
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
int i;
for (i = 0; i < width; i++) {
unsigned int r_b = input_pixel(&src[i * 3 + 0]);
unsigned int g = input_pixel(&src[i * 3 + 1]);
unsigned int b_r = input_pixel(&src[i * 3 + 2]);
- dst[i] = (RY * r + GY * g + BY * b + (0x2001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dst[i] = (ry*r + gy*g + by*b + (0x2001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
}
}
@@ -70,17 +148,20 @@ static av_always_inline void rgb48ToUV_c_template(uint16_t *dstU,
const uint16_t *src1,
const uint16_t *src2,
int width,
- enum AVPixelFormat origin)
+ enum AVPixelFormat origin,
+ int32_t *rgb2yuv)
{
int i;
- assert(src1 == src2);
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ av_assert1(src1 == src2);
for (i = 0; i < width; i++) {
int r_b = input_pixel(&src1[i * 3 + 0]);
int g = input_pixel(&src1[i * 3 + 1]);
int b_r = input_pixel(&src1[i * 3 + 2]);
- dstU[i] = (RU * r + GU * g + BU * b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
- dstV[i] = (RV * r + GV * g + BV * b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstU[i] = (ru*r + gu*g + bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstV[i] = (rv*r + gv*g + bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
}
}
@@ -89,10 +170,13 @@ static av_always_inline void rgb48ToUV_half_c_template(uint16_t *dstU,
const uint16_t *src1,
const uint16_t *src2,
int width,
- enum AVPixelFormat origin)
+ enum AVPixelFormat origin,
+ int32_t *rgb2yuv)
{
int i;
- assert(src1 == src2);
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ av_assert1(src1 == src2);
for (i = 0; i < width; i++) {
int r_b = (input_pixel(&src1[6 * i + 0]) +
input_pixel(&src1[6 * i + 3]) + 1) >> 1;
@@ -101,8 +185,8 @@ static av_always_inline void rgb48ToUV_half_c_template(uint16_t *dstU,
int b_r = (input_pixel(&src1[6 * i + 2]) +
input_pixel(&src1[6 * i + 5]) + 1) >> 1;
- dstU[i] = (RU * r + GU * g + BU * b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
- dstV[i] = (RV * r + GV * g + BV * b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstU[i] = (ru*r + gu*g + bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstV[i] = (rv*r + gv*g + bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
}
}
@@ -113,40 +197,43 @@ static av_always_inline void rgb48ToUV_half_c_template(uint16_t *dstU,
#define rgb48funcs(pattern, BE_LE, origin) \
static void pattern ## 48 ## BE_LE ## ToY_c(uint8_t *_dst, \
const uint8_t *_src, \
+ const uint8_t *unused0, const uint8_t *unused1,\
int width, \
- uint32_t *unused) \
+ uint32_t *rgb2yuv) \
{ \
const uint16_t *src = (const uint16_t *)_src; \
uint16_t *dst = (uint16_t *)_dst; \
- rgb48ToY_c_template(dst, src, width, origin); \
+ rgb48ToY_c_template(dst, src, width, origin, rgb2yuv); \
} \
\
static void pattern ## 48 ## BE_LE ## ToUV_c(uint8_t *_dstU, \
uint8_t *_dstV, \
+ const uint8_t *unused0, \
const uint8_t *_src1, \
const uint8_t *_src2, \
int width, \
- uint32_t *unused) \
+ uint32_t *rgb2yuv) \
{ \
const uint16_t *src1 = (const uint16_t *)_src1, \
*src2 = (const uint16_t *)_src2; \
uint16_t *dstU = (uint16_t *)_dstU, \
*dstV = (uint16_t *)_dstV; \
- rgb48ToUV_c_template(dstU, dstV, src1, src2, width, origin); \
+ rgb48ToUV_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv); \
} \
\
static void pattern ## 48 ## BE_LE ## ToUV_half_c(uint8_t *_dstU, \
uint8_t *_dstV, \
+ const uint8_t *unused0, \
const uint8_t *_src1, \
const uint8_t *_src2, \
int width, \
- uint32_t *unused) \
+ uint32_t *rgb2yuv) \
{ \
const uint16_t *src1 = (const uint16_t *)_src1, \
*src2 = (const uint16_t *)_src2; \
uint16_t *dstU = (uint16_t *)_dstU, \
*dstV = (uint16_t *)_dstV; \
- rgb48ToUV_half_c_template(dstU, dstV, src1, src2, width, origin); \
+ rgb48ToUV_half_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv); \
}
rgb48funcs(rgb, LE, AV_PIX_FMT_RGB48LE)
@@ -162,7 +249,7 @@ rgb48funcs(bgr, BE, AV_PIX_FMT_BGR48BE)
: (isBE(origin) ? AV_RB16(&src[(i) * 2]) \
: AV_RL16(&src[(i) * 2])))
-static av_always_inline void rgb16_32ToY_c_template(uint8_t *dst,
+static av_always_inline void rgb16_32ToY_c_template(int16_t *dst,
const uint8_t *src,
int width,
enum AVPixelFormat origin,
@@ -170,10 +257,11 @@ static av_always_inline void rgb16_32ToY_c_template(uint8_t *dst,
int shb, int shp,
int maskr, int maskg,
int maskb, int rsh,
- int gsh, int bsh, int S)
+ int gsh, int bsh, int S,
+ int32_t *rgb2yuv)
{
- const int ry = RY << rsh, gy = GY << gsh, by = BY << bsh;
- const unsigned rnd = 33u << (S - 1);
+ const int ry = rgb2yuv[RY_IDX]<<rsh, gy = rgb2yuv[GY_IDX]<<gsh, by = rgb2yuv[BY_IDX]<<bsh;
+ const unsigned rnd = (32<<((S)-1)) + (1<<(S-7));
int i;
for (i = 0; i < width; i++) {
@@ -182,12 +270,12 @@ static av_always_inline void rgb16_32ToY_c_template(uint8_t *dst,
int g = (px & maskg) >> shg;
int r = (px & maskr) >> shr;
- dst[i] = (ry * r + gy * g + by * b + rnd) >> S;
+ dst[i] = (ry * r + gy * g + by * b + rnd) >> ((S)-6);
}
}
-static av_always_inline void rgb16_32ToUV_c_template(uint8_t *dstU,
- uint8_t *dstV,
+static av_always_inline void rgb16_32ToUV_c_template(int16_t *dstU,
+ int16_t *dstV,
const uint8_t *src,
int width,
enum AVPixelFormat origin,
@@ -195,11 +283,12 @@ static av_always_inline void rgb16_32ToUV_c_template(uint8_t *dstU,
int shb, int shp,
int maskr, int maskg,
int maskb, int rsh,
- int gsh, int bsh, int S)
+ int gsh, int bsh, int S,
+ int32_t *rgb2yuv)
{
- const int ru = RU << rsh, gu = GU << gsh, bu = BU << bsh,
- rv = RV << rsh, gv = GV << gsh, bv = BV << bsh;
- const unsigned rnd = 257u << (S - 1);
+ const int ru = rgb2yuv[RU_IDX] << rsh, gu = rgb2yuv[GU_IDX] << gsh, bu = rgb2yuv[BU_IDX] << bsh,
+ rv = rgb2yuv[RV_IDX] << rsh, gv = rgb2yuv[GV_IDX] << gsh, bv = rgb2yuv[BV_IDX] << bsh;
+ const unsigned rnd = (256u<<((S)-1)) + (1<<(S-7));
int i;
for (i = 0; i < width; i++) {
@@ -208,13 +297,13 @@ static av_always_inline void rgb16_32ToUV_c_template(uint8_t *dstU,
int g = (px & maskg) >> shg;
int r = (px & maskr) >> shr;
- dstU[i] = (ru * r + gu * g + bu * b + rnd) >> S;
- dstV[i] = (rv * r + gv * g + bv * b + rnd) >> S;
+ dstU[i] = (ru * r + gu * g + bu * b + rnd) >> ((S)-6);
+ dstV[i] = (rv * r + gv * g + bv * b + rnd) >> ((S)-6);
}
}
-static av_always_inline void rgb16_32ToUV_half_c_template(uint8_t *dstU,
- uint8_t *dstV,
+static av_always_inline void rgb16_32ToUV_half_c_template(int16_t *dstU,
+ int16_t *dstV,
const uint8_t *src,
int width,
enum AVPixelFormat origin,
@@ -222,20 +311,21 @@ static av_always_inline void rgb16_32ToUV_half_c_template(uint8_t *dstU,
int shb, int shp,
int maskr, int maskg,
int maskb, int rsh,
- int gsh, int bsh, int S)
+ int gsh, int bsh, int S,
+ int32_t *rgb2yuv)
{
- const int ru = RU << rsh, gu = GU << gsh, bu = BU << bsh,
- rv = RV << rsh, gv = GV << gsh, bv = BV << bsh,
+ const int ru = rgb2yuv[RU_IDX] << rsh, gu = rgb2yuv[GU_IDX] << gsh, bu = rgb2yuv[BU_IDX] << bsh,
+ rv = rgb2yuv[RV_IDX] << rsh, gv = rgb2yuv[GV_IDX] << gsh, bv = rgb2yuv[BV_IDX] << bsh,
maskgx = ~(maskr | maskb);
- const unsigned rnd = 257u << S;
+ const unsigned rnd = (256U<<(S)) + (1<<(S-6));
int i;
maskr |= maskr << 1;
maskb |= maskb << 1;
maskg |= maskg << 1;
for (i = 0; i < width; i++) {
- int px0 = input_pixel(2 * i + 0) >> shp;
- int px1 = input_pixel(2 * i + 1) >> shp;
+ unsigned px0 = input_pixel(2 * i + 0) >> shp;
+ unsigned px1 = input_pixel(2 * i + 1) >> shp;
int b, r, g = (px0 & maskgx) + (px1 & maskgx);
int rb = px0 + px1 - g;
@@ -249,8 +339,8 @@ static av_always_inline void rgb16_32ToUV_half_c_template(uint8_t *dstU,
}
r = (rb & maskr) >> shr;
- dstU[i] = (ru * r + gu * g + bu * b + rnd) >> (S + 1);
- dstV[i] = (rv * r + gv * g + bv * b + rnd) >> (S + 1);
+ dstU[i] = (ru * r + gu * g + bu * b + (unsigned)rnd) >> ((S)-6+1);
+ dstV[i] = (rv * r + gv * g + bv * b + (unsigned)rnd) >> ((S)-6+1);
}
}
@@ -258,31 +348,31 @@ static av_always_inline void rgb16_32ToUV_half_c_template(uint8_t *dstU,
#define rgb16_32_wrapper(fmt, name, shr, shg, shb, shp, maskr, \
maskg, maskb, rsh, gsh, bsh, S) \
-static void name ## ToY_c(uint8_t *dst, const uint8_t *src, \
- int width, uint32_t *unused) \
+static void name ## ToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, \
+ int width, uint32_t *tab) \
{ \
- rgb16_32ToY_c_template(dst, src, width, fmt, shr, shg, shb, shp, \
- maskr, maskg, maskb, rsh, gsh, bsh, S); \
+ rgb16_32ToY_c_template((int16_t*)dst, src, width, fmt, shr, shg, shb, shp, \
+ maskr, maskg, maskb, rsh, gsh, bsh, S, tab); \
} \
\
static void name ## ToUV_c(uint8_t *dstU, uint8_t *dstV, \
- const uint8_t *src, const uint8_t *dummy, \
- int width, uint32_t *unused) \
+ const uint8_t *unused0, const uint8_t *src, const uint8_t *dummy, \
+ int width, uint32_t *tab) \
{ \
- rgb16_32ToUV_c_template(dstU, dstV, src, width, fmt, \
+ rgb16_32ToUV_c_template((int16_t*)dstU, (int16_t*)dstV, src, width, fmt, \
shr, shg, shb, shp, \
- maskr, maskg, maskb, rsh, gsh, bsh, S); \
+ maskr, maskg, maskb, rsh, gsh, bsh, S, tab);\
} \
\
static void name ## ToUV_half_c(uint8_t *dstU, uint8_t *dstV, \
- const uint8_t *src, \
+ const uint8_t *unused0, const uint8_t *src, \
const uint8_t *dummy, \
- int width, uint32_t *unused) \
+ int width, uint32_t *tab) \
{ \
- rgb16_32ToUV_half_c_template(dstU, dstV, src, width, fmt, \
+ rgb16_32ToUV_half_c_template((int16_t*)dstU, (int16_t*)dstV, src, width, fmt, \
shr, shg, shb, shp, \
maskr, maskg, maskb, \
- rsh, gsh, bsh, S); \
+ rsh, gsh, bsh, S, tab); \
}
rgb16_32_wrapper(AV_PIX_FMT_BGR32, bgr32, 16, 0, 0, 0, 0xFF0000, 0xFF00, 0x00FF, 8, 0, 8, RGB2YUV_SHIFT + 8)
@@ -302,71 +392,137 @@ rgb16_32_wrapper(AV_PIX_FMT_RGB565BE, rgb16be, 0, 0, 0, 0, 0xF800, 0x07E0,
rgb16_32_wrapper(AV_PIX_FMT_RGB555BE, rgb15be, 0, 0, 0, 0, 0x7C00, 0x03E0, 0x001F, 0, 5, 10, RGB2YUV_SHIFT + 7)
rgb16_32_wrapper(AV_PIX_FMT_RGB444BE, rgb12be, 0, 0, 0, 0, 0x0F00, 0x00F0, 0x000F, 0, 4, 8, RGB2YUV_SHIFT + 4)
-static void abgrToA_c(uint8_t *dst, const uint8_t *src, int width,
- uint32_t *unused)
+static void gbr24pToUV_half_c(uint8_t *_dstU, uint8_t *_dstV,
+ const uint8_t *gsrc, const uint8_t *bsrc, const uint8_t *rsrc,
+ int width, uint32_t *rgb2yuv)
{
+ uint16_t *dstU = (uint16_t *)_dstU;
+ uint16_t *dstV = (uint16_t *)_dstV;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+
+ int i;
+ for (i = 0; i < width; i++) {
+ unsigned int g = gsrc[2*i] + gsrc[2*i+1];
+ unsigned int b = bsrc[2*i] + bsrc[2*i+1];
+ unsigned int r = rsrc[2*i] + rsrc[2*i+1];
+
+ dstU[i] = (ru*r + gu*g + bu*b + (0x4001<<(RGB2YUV_SHIFT-6))) >> (RGB2YUV_SHIFT-6+1);
+ dstV[i] = (rv*r + gv*g + bv*b + (0x4001<<(RGB2YUV_SHIFT-6))) >> (RGB2YUV_SHIFT-6+1);
+ }
+}
+
+static void rgba64leToA_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1,
+ const uint8_t *unused2, int width, uint32_t *unused)
+{
+ int16_t *dst = (int16_t *)_dst;
+ const uint16_t *src = (const uint16_t *)_src;
int i;
for (i = 0; i < width; i++)
- dst[i] = src[4 * i];
+ dst[i] = AV_RL16(src + 4 * i + 3);
}
-static void rgbaToA_c(uint8_t *dst, const uint8_t *src, int width,
- uint32_t *unused)
+static void rgba64beToA_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1,
+ const uint8_t *unused2, int width, uint32_t *unused)
{
+ int16_t *dst = (int16_t *)_dst;
+ const uint16_t *src = (const uint16_t *)_src;
int i;
for (i = 0; i < width; i++)
- dst[i] = src[4 * i + 3];
+ dst[i] = AV_RB16(src + 4 * i + 3);
+}
+
+static void abgrToA_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, uint32_t *unused)
+{
+ int16_t *dst = (int16_t *)_dst;
+ int i;
+ for (i=0; i<width; i++) {
+ dst[i]= src[4*i]<<6;
+ }
+}
+
+static void rgbaToA_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, uint32_t *unused)
+{
+ int16_t *dst = (int16_t *)_dst;
+ int i;
+ for (i=0; i<width; i++) {
+ dst[i]= src[4*i+3]<<6;
+ }
}
-static void palToY_c(uint8_t *dst, const uint8_t *src, int width, uint32_t *pal)
+static void palToA_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, uint32_t *pal)
{
+ int16_t *dst = (int16_t *)_dst;
+ int i;
+ for (i=0; i<width; i++) {
+ int d= src[i];
+
+ dst[i]= (pal[d] >> 24)<<6;
+ }
+}
+
+static void palToY_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, uint32_t *pal)
+{
+ int16_t *dst = (int16_t *)_dst;
int i;
for (i = 0; i < width; i++) {
int d = src[i];
- dst[i] = pal[d] & 0xFF;
+ dst[i] = (pal[d] & 0xFF)<<6;
}
}
-static void palToUV_c(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src1, const uint8_t *src2,
+static void palToUV_c(uint8_t *_dstU, uint8_t *_dstV,
+ const uint8_t *unused0, const uint8_t *src1, const uint8_t *src2,
int width, uint32_t *pal)
{
+ uint16_t *dstU = (uint16_t *)_dstU;
+ int16_t *dstV = (int16_t *)_dstV;
int i;
- assert(src1 == src2);
+ av_assert1(src1 == src2);
for (i = 0; i < width; i++) {
int p = pal[src1[i]];
- dstU[i] = p >> 8;
- dstV[i] = p >> 16;
+ dstU[i] = (uint8_t)(p>> 8)<<6;
+ dstV[i] = (uint8_t)(p>>16)<<6;
}
}
-static void monowhite2Y_c(uint8_t *dst, const uint8_t *src,
- int width, uint32_t *unused)
+static void monowhite2Y_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, uint32_t *unused)
{
+ int16_t *dst = (int16_t *)_dst;
int i, j;
width = (width + 7) >> 3;
for (i = 0; i < width; i++) {
int d = ~src[i];
for (j = 0; j < 8; j++)
- dst[8 * i + j] = ((d >> (7 - j)) & 1) * 255;
+ dst[8*i+j]= ((d>>(7-j))&1) * 16383;
+ }
+ if(width&7){
+ int d= ~src[i];
+ for (j = 0; j < (width&7); j++)
+ dst[8*i+j]= ((d>>(7-j))&1) * 16383;
}
}
-static void monoblack2Y_c(uint8_t *dst, const uint8_t *src,
- int width, uint32_t *unused)
+static void monoblack2Y_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, uint32_t *unused)
{
+ int16_t *dst = (int16_t *)_dst;
int i, j;
width = (width + 7) >> 3;
for (i = 0; i < width; i++) {
int d = src[i];
for (j = 0; j < 8; j++)
- dst[8 * i + j] = ((d >> (7 - j)) & 1) * 255;
+ dst[8*i+j]= ((d>>(7-j))&1) * 16383;
+ }
+ if(width&7){
+ int d = src[i];
+ for (j = 0; j < (width&7); j++)
+ dst[8*i+j] = ((d>>(7-j))&1) * 16383;
}
}
-static void yuy2ToY_c(uint8_t *dst, const uint8_t *src, int width,
+static void yuy2ToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -374,7 +530,7 @@ static void yuy2ToY_c(uint8_t *dst, const uint8_t *src, int width,
dst[i] = src[2 * i];
}
-static void yuy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
+static void yuy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1,
const uint8_t *src2, int width, uint32_t *unused)
{
int i;
@@ -382,10 +538,10 @@ static void yuy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
dstU[i] = src1[4 * i + 1];
dstV[i] = src1[4 * i + 3];
}
- assert(src1 == src2);
+ av_assert1(src1 == src2);
}
-static void yvy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
+static void yvy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1,
const uint8_t *src2, int width, uint32_t *unused)
{
int i;
@@ -393,10 +549,10 @@ static void yvy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
dstV[i] = src1[4 * i + 1];
dstU[i] = src1[4 * i + 3];
}
- assert(src1 == src2);
+ av_assert1(src1 == src2);
}
-static void bswap16Y_c(uint8_t *_dst, const uint8_t *_src, int width,
+static void bswap16Y_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -406,7 +562,7 @@ static void bswap16Y_c(uint8_t *_dst, const uint8_t *_src, int width,
dst[i] = av_bswap16(src[i]);
}
-static void bswap16UV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *_src1,
+static void bswap16UV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *_src1,
const uint8_t *_src2, int width, uint32_t *unused)
{
int i;
@@ -419,7 +575,7 @@ static void bswap16UV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *_src1,
}
}
-static void read_ya16le_gray_c(uint8_t *dst, const uint8_t *src, int width,
+static void read_ya16le_gray_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -427,7 +583,7 @@ static void read_ya16le_gray_c(uint8_t *dst, const uint8_t *src, int width,
AV_WN16(dst + i * 2, AV_RL16(src + i * 4));
}
-static void read_ya16le_alpha_c(uint8_t *dst, const uint8_t *src, int width,
+static void read_ya16le_alpha_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -435,7 +591,7 @@ static void read_ya16le_alpha_c(uint8_t *dst, const uint8_t *src, int width,
AV_WN16(dst + i * 2, AV_RL16(src + i * 4 + 2));
}
-static void read_ya16be_gray_c(uint8_t *dst, const uint8_t *src, int width,
+static void read_ya16be_gray_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -443,7 +599,7 @@ static void read_ya16be_gray_c(uint8_t *dst, const uint8_t *src, int width,
AV_WN16(dst + i * 2, AV_RB16(src + i * 4));
}
-static void read_ya16be_alpha_c(uint8_t *dst, const uint8_t *src, int width,
+static void read_ya16be_alpha_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -453,7 +609,7 @@ static void read_ya16be_alpha_c(uint8_t *dst, const uint8_t *src, int width,
/* This is almost identical to the previous, end exists only because
* yuy2ToY/UV)(dst, src + 1, ...) would have 100% unaligned accesses. */
-static void uyvyToY_c(uint8_t *dst, const uint8_t *src, int width,
+static void uyvyToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
uint32_t *unused)
{
int i;
@@ -461,7 +617,7 @@ static void uyvyToY_c(uint8_t *dst, const uint8_t *src, int width,
dst[i] = src[2 * i + 1];
}
-static void uyvyToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
+static void uyvyToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1,
const uint8_t *src2, int width, uint32_t *unused)
{
int i;
@@ -469,7 +625,7 @@ static void uyvyToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
dstU[i] = src1[4 * i + 0];
dstV[i] = src1[4 * i + 2];
}
- assert(src1 == src2);
+ av_assert1(src1 == src2);
}
static av_always_inline void nvXXtoUV_c(uint8_t *dst1, uint8_t *dst2,
@@ -483,14 +639,14 @@ static av_always_inline void nvXXtoUV_c(uint8_t *dst1, uint8_t *dst2,
}
static void nv12ToUV_c(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src1, const uint8_t *src2,
+ const uint8_t *unused0, const uint8_t *src1, const uint8_t *src2,
int width, uint32_t *unused)
{
nvXXtoUV_c(dstU, dstV, src1, width);
}
static void nv21ToUV_c(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src1, const uint8_t *src2,
+ const uint8_t *unused0, const uint8_t *src1, const uint8_t *src2,
int width, uint32_t *unused)
{
nvXXtoUV_c(dstV, dstU, src1, width);
@@ -498,225 +654,213 @@ static void nv21ToUV_c(uint8_t *dstU, uint8_t *dstV,
#define input_pixel(pos) (isBE(origin) ? AV_RB16(pos) : AV_RL16(pos))
-static void bgr24ToY_c(uint8_t *dst, const uint8_t *src,
- int width, uint32_t *unused)
+static void bgr24ToY_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2,
+ int width, uint32_t *rgb2yuv)
{
+ int16_t *dst = (int16_t *)_dst;
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
int i;
for (i = 0; i < width; i++) {
int b = src[i * 3 + 0];
int g = src[i * 3 + 1];
int r = src[i * 3 + 2];
- dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+ dst[i] = ((ry*r + gy*g + by*b + (32<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6));
}
}
-static void bgr24ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
- const uint8_t *src2, int width, uint32_t *unused)
+static void bgr24ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1,
+ const uint8_t *src2, int width, uint32_t *rgb2yuv)
{
+ int16_t *dstU = (int16_t *)_dstU;
+ int16_t *dstV = (int16_t *)_dstV;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
int i;
for (i = 0; i < width; i++) {
int b = src1[3 * i + 0];
int g = src1[3 * i + 1];
int r = src1[3 * i + 2];
- dstU[i] = (RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
- dstV[i] = (RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstU[i] = (ru*r + gu*g + bu*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6);
+ dstV[i] = (rv*r + gv*g + bv*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6);
}
- assert(src1 == src2);
+ av_assert1(src1 == src2);
}
-static void bgr24ToUV_half_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
- const uint8_t *src2, int width, uint32_t *unused)
+static void bgr24ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1,
+ const uint8_t *src2, int width, uint32_t *rgb2yuv)
{
+ int16_t *dstU = (int16_t *)_dstU;
+ int16_t *dstV = (int16_t *)_dstV;
int i;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
for (i = 0; i < width; i++) {
int b = src1[6 * i + 0] + src1[6 * i + 3];
int g = src1[6 * i + 1] + src1[6 * i + 4];
int r = src1[6 * i + 2] + src1[6 * i + 5];
- dstU[i] = (RU * r + GU * g + BU * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
- dstV[i] = (RV * r + GV * g + BV * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+ dstU[i] = (ru*r + gu*g + bu*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5);
+ dstV[i] = (rv*r + gv*g + bv*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5);
}
- assert(src1 == src2);
+ av_assert1(src1 == src2);
}
-static void rgb24ToY_c(uint8_t *dst, const uint8_t *src, int width,
- uint32_t *unused)
+static void rgb24ToY_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width,
+ uint32_t *rgb2yuv)
{
+ int16_t *dst = (int16_t *)_dst;
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
int i;
for (i = 0; i < width; i++) {
int r = src[i * 3 + 0];
int g = src[i * 3 + 1];
int b = src[i * 3 + 2];
- dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+ dst[i] = ((ry*r + gy*g + by*b + (32<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6));
}
}
-static void rgb24ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
- const uint8_t *src2, int width, uint32_t *unused)
+static void rgb24ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1,
+ const uint8_t *src2, int width, uint32_t *rgb2yuv)
{
+ int16_t *dstU = (int16_t *)_dstU;
+ int16_t *dstV = (int16_t *)_dstV;
int i;
- assert(src1 == src2);
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ av_assert1(src1 == src2);
for (i = 0; i < width; i++) {
int r = src1[3 * i + 0];
int g = src1[3 * i + 1];
int b = src1[3 * i + 2];
- dstU[i] = (RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
- dstV[i] = (RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstU[i] = (ru*r + gu*g + bu*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6);
+ dstV[i] = (rv*r + gv*g + bv*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6);
}
}
-static void rgb24ToUV_half_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
- const uint8_t *src2, int width, uint32_t *unused)
+static void rgb24ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1,
+ const uint8_t *src2, int width, uint32_t *rgb2yuv)
{
+ int16_t *dstU = (int16_t *)_dstU;
+ int16_t *dstV = (int16_t *)_dstV;
int i;
- assert(src1 == src2);
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ av_assert1(src1 == src2);
for (i = 0; i < width; i++) {
int r = src1[6 * i + 0] + src1[6 * i + 3];
int g = src1[6 * i + 1] + src1[6 * i + 4];
int b = src1[6 * i + 2] + src1[6 * i + 5];
- dstU[i] = (RU * r + GU * g + BU * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
- dstV[i] = (RV * r + GV * g + BV * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+ dstU[i] = (ru*r + gu*g + bu*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5);
+ dstV[i] = (rv*r + gv*g + bv*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5);
}
}
-static void planar_rgb_to_y(uint8_t *dst, const uint8_t *src[4], int width)
+static void planar_rgb_to_y(uint8_t *_dst, const uint8_t *src[4], int width, int32_t *rgb2yuv)
{
+ uint16_t *dst = (uint16_t *)_dst;
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
int i;
for (i = 0; i < width; i++) {
int g = src[0][i];
int b = src[1][i];
int r = src[2][i];
- dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+ dst[i] = (ry*r + gy*g + by*b + (0x801<<(RGB2YUV_SHIFT-7))) >> (RGB2YUV_SHIFT-6);
}
}
-static void planar_rgb_to_a(uint8_t *dst, const uint8_t *src[4], int width)
+static void planar_rgb_to_a(uint8_t *_dst, const uint8_t *src[4], int width, int32_t *unused)
{
+ uint16_t *dst = (uint16_t *)_dst;
int i;
for (i = 0; i < width; i++)
- dst[i] = src[3][i];
+ dst[i] = src[3][i] << 6;
}
-static void planar_rgb_to_uv(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4], int width)
+static void planar_rgb_to_uv(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *src[4], int width, int32_t *rgb2yuv)
{
+ uint16_t *dstU = (uint16_t *)_dstU;
+ uint16_t *dstV = (uint16_t *)_dstV;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
int i;
for (i = 0; i < width; i++) {
int g = src[0][i];
int b = src[1][i];
int r = src[2][i];
- dstU[i] = (RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
- dstV[i] = (RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT;
+ dstU[i] = (ru*r + gu*g + bu*b + (0x4001<<(RGB2YUV_SHIFT-7))) >> (RGB2YUV_SHIFT-6);
+ dstV[i] = (rv*r + gv*g + bv*b + (0x4001<<(RGB2YUV_SHIFT-7))) >> (RGB2YUV_SHIFT-6);
}
}
#define rdpx(src) \
is_be ? AV_RB16(src) : AV_RL16(src)
static av_always_inline void planar_rgb16_to_y(uint8_t *_dst, const uint8_t *_src[4],
- int width, int bpc, int is_be)
+ int width, int bpc, int is_be, int32_t *rgb2yuv)
{
int i;
const uint16_t **src = (const uint16_t **)_src;
uint16_t *dst = (uint16_t *)_dst;
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
+ int shift = bpc < 16 ? bpc : 14;
for (i = 0; i < width; i++) {
int g = rdpx(src[0] + i);
int b = rdpx(src[1] + i);
int r = rdpx(src[2] + i);
- dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT + bpc - 9))) >> RGB2YUV_SHIFT);
+ dst[i] = ((ry*r + gy*g + by*b + (33 << (RGB2YUV_SHIFT + bpc - 9))) >> (RGB2YUV_SHIFT + shift - 14));
}
}
-static void planar_rgb9le_to_y(uint8_t *dst, const uint8_t *src[4], int w)
-{
- planar_rgb16_to_y(dst, src, w, 9, 0);
-}
-
-static void planar_rgb9be_to_y(uint8_t *dst, const uint8_t *src[4], int w)
-{
- planar_rgb16_to_y(dst, src, w, 9, 1);
-}
-
-static void planar_rgb10le_to_y(uint8_t *dst, const uint8_t *src[4], int w)
-{
- planar_rgb16_to_y(dst, src, w, 10, 0);
-}
-
-static void planar_rgb10be_to_y(uint8_t *dst, const uint8_t *src[4], int w)
-{
- planar_rgb16_to_y(dst, src, w, 10, 1);
-}
-
-static void planar_rgb16le_to_y(uint8_t *dst, const uint8_t *src[4], int w)
-{
- planar_rgb16_to_y(dst, src, w, 16, 0);
-}
-
-static void planar_rgb16be_to_y(uint8_t *dst, const uint8_t *src[4], int w)
-{
- planar_rgb16_to_y(dst, src, w, 16, 1);
-}
-
static av_always_inline void planar_rgb16_to_uv(uint8_t *_dstU, uint8_t *_dstV,
const uint8_t *_src[4], int width,
- int bpc, int is_be)
+ int bpc, int is_be, int32_t *rgb2yuv)
{
int i;
const uint16_t **src = (const uint16_t **)_src;
uint16_t *dstU = (uint16_t *)_dstU;
uint16_t *dstV = (uint16_t *)_dstV;
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
+ int shift = bpc < 16 ? bpc : 14;
for (i = 0; i < width; i++) {
int g = rdpx(src[0] + i);
int b = rdpx(src[1] + i);
int r = rdpx(src[2] + i);
- dstU[i] = (RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT + bpc - 9))) >> RGB2YUV_SHIFT;
- dstV[i] = (RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT + bpc - 9))) >> RGB2YUV_SHIFT;
+ dstU[i] = (ru*r + gu*g + bu*b + (257 << (RGB2YUV_SHIFT + bpc - 9))) >> (RGB2YUV_SHIFT + shift - 14);
+ dstV[i] = (rv*r + gv*g + bv*b + (257 << (RGB2YUV_SHIFT + bpc - 9))) >> (RGB2YUV_SHIFT + shift - 14);
}
}
#undef rdpx
-static void planar_rgb9le_to_uv(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src[4], int w)
-{
- planar_rgb16_to_uv(dstU, dstV, src, w, 9, 0);
-}
-
-static void planar_rgb9be_to_uv(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src[4], int w)
-{
- planar_rgb16_to_uv(dstU, dstV, src, w, 9, 1);
-}
-
-static void planar_rgb10le_to_uv(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src[4], int w)
-{
- planar_rgb16_to_uv(dstU, dstV, src, w, 10, 0);
-}
-
-static void planar_rgb10be_to_uv(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src[4], int w)
-{
- planar_rgb16_to_uv(dstU, dstV, src, w, 10, 1);
-}
-
-static void planar_rgb16le_to_uv(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src[4], int w)
-{
- planar_rgb16_to_uv(dstU, dstV, src, w, 16, 0);
-}
-
-static void planar_rgb16be_to_uv(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src[4], int w)
-{
- planar_rgb16_to_uv(dstU, dstV, src, w, 16, 1);
-}
+#define rgb9plus_planar_funcs_endian(nbits, endian_name, endian) \
+static void planar_rgb##nbits##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \
+ int w, int32_t *rgb2yuv) \
+{ \
+ planar_rgb16_to_y(dst, src, w, nbits, endian, rgb2yuv); \
+} \
+static void planar_rgb##nbits##endian_name##_to_uv(uint8_t *dstU, uint8_t *dstV, \
+ const uint8_t *src[4], int w, int32_t *rgb2yuv) \
+{ \
+ planar_rgb16_to_uv(dstU, dstV, src, w, nbits, endian, rgb2yuv); \
+} \
+
+#define rgb9plus_planar_funcs(nbits) \
+ rgb9plus_planar_funcs_endian(nbits, le, 0) \
+ rgb9plus_planar_funcs_endian(nbits, be, 1)
+
+rgb9plus_planar_funcs(9)
+rgb9plus_planar_funcs(10)
+rgb9plus_planar_funcs(12)
+rgb9plus_planar_funcs(14)
+rgb9plus_planar_funcs(16)
av_cold void ff_sws_init_input_funcs(SwsContext *c)
{
@@ -752,6 +896,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_GBRP10LE:
c->readChrPlanar = planar_rgb10le_to_uv;
break;
+ case AV_PIX_FMT_GBRP12LE:
+ c->readChrPlanar = planar_rgb12le_to_uv;
+ break;
+ case AV_PIX_FMT_GBRP14LE:
+ c->readChrPlanar = planar_rgb14le_to_uv;
+ break;
case AV_PIX_FMT_GBRAP16LE:
case AV_PIX_FMT_GBRP16LE:
c->readChrPlanar = planar_rgb16le_to_uv;
@@ -762,6 +912,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_GBRP10BE:
c->readChrPlanar = planar_rgb10be_to_uv;
break;
+ case AV_PIX_FMT_GBRP12BE:
+ c->readChrPlanar = planar_rgb12be_to_uv;
+ break;
+ case AV_PIX_FMT_GBRP14BE:
+ c->readChrPlanar = planar_rgb14be_to_uv;
+ break;
case AV_PIX_FMT_GBRAP16BE:
case AV_PIX_FMT_GBRP16BE:
c->readChrPlanar = planar_rgb16be_to_uv;
@@ -775,16 +931,25 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV422P9LE:
case AV_PIX_FMT_YUV420P9LE:
case AV_PIX_FMT_YUV422P10LE:
+ case AV_PIX_FMT_YUV440P10LE:
case AV_PIX_FMT_YUV444P10LE:
case AV_PIX_FMT_YUV420P10LE:
+ case AV_PIX_FMT_YUV422P12LE:
+ case AV_PIX_FMT_YUV440P12LE:
+ case AV_PIX_FMT_YUV444P12LE:
+ case AV_PIX_FMT_YUV420P12LE:
+ case AV_PIX_FMT_YUV422P14LE:
+ case AV_PIX_FMT_YUV444P14LE:
+ case AV_PIX_FMT_YUV420P14LE:
case AV_PIX_FMT_YUV420P16LE:
case AV_PIX_FMT_YUV422P16LE:
case AV_PIX_FMT_YUV444P16LE:
+
case AV_PIX_FMT_YUVA444P9LE:
case AV_PIX_FMT_YUVA422P9LE:
case AV_PIX_FMT_YUVA420P9LE:
- case AV_PIX_FMT_YUVA422P10LE:
case AV_PIX_FMT_YUVA444P10LE:
+ case AV_PIX_FMT_YUVA422P10LE:
case AV_PIX_FMT_YUVA420P10LE:
case AV_PIX_FMT_YUVA420P16LE:
case AV_PIX_FMT_YUVA422P16LE:
@@ -795,17 +960,26 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV444P9BE:
case AV_PIX_FMT_YUV422P9BE:
case AV_PIX_FMT_YUV420P9BE:
+ case AV_PIX_FMT_YUV440P10BE:
case AV_PIX_FMT_YUV444P10BE:
case AV_PIX_FMT_YUV422P10BE:
case AV_PIX_FMT_YUV420P10BE:
+ case AV_PIX_FMT_YUV440P12BE:
+ case AV_PIX_FMT_YUV444P12BE:
+ case AV_PIX_FMT_YUV422P12BE:
+ case AV_PIX_FMT_YUV420P12BE:
+ case AV_PIX_FMT_YUV444P14BE:
+ case AV_PIX_FMT_YUV422P14BE:
+ case AV_PIX_FMT_YUV420P14BE:
case AV_PIX_FMT_YUV420P16BE:
case AV_PIX_FMT_YUV422P16BE:
case AV_PIX_FMT_YUV444P16BE:
+
case AV_PIX_FMT_YUVA444P9BE:
case AV_PIX_FMT_YUVA422P9BE:
case AV_PIX_FMT_YUVA420P9BE:
- case AV_PIX_FMT_YUVA422P10BE:
case AV_PIX_FMT_YUVA444P10BE:
+ case AV_PIX_FMT_YUVA422P10BE:
case AV_PIX_FMT_YUVA420P10BE:
case AV_PIX_FMT_YUVA420P16BE:
case AV_PIX_FMT_YUVA422P16BE:
@@ -816,6 +990,18 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
}
if (c->chrSrcHSubSample) {
switch (srcFormat) {
+ case AV_PIX_FMT_RGBA64BE:
+ c->chrToYV12 = rgb64BEToUV_half_c;
+ break;
+ case AV_PIX_FMT_RGBA64LE:
+ c->chrToYV12 = rgb64LEToUV_half_c;
+ break;
+ case AV_PIX_FMT_BGRA64BE:
+ c->chrToYV12 = bgr64BEToUV_half_c;
+ break;
+ case AV_PIX_FMT_BGRA64LE:
+ c->chrToYV12 = bgr64LEToUV_half_c;
+ break;
case AV_PIX_FMT_RGB48BE:
c->chrToYV12 = rgb48BEToUV_half_c;
break;
@@ -849,6 +1035,10 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_BGR555BE:
c->chrToYV12 = bgr15beToUV_half_c;
break;
+ case AV_PIX_FMT_GBRAP:
+ case AV_PIX_FMT_GBRP:
+ c->chrToYV12 = gbr24pToUV_half_c;
+ break;
case AV_PIX_FMT_BGR444LE:
c->chrToYV12 = bgr12leToUV_half_c;
break;
@@ -885,6 +1075,18 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
}
} else {
switch (srcFormat) {
+ case AV_PIX_FMT_RGBA64BE:
+ c->chrToYV12 = rgb64BEToUV_c;
+ break;
+ case AV_PIX_FMT_RGBA64LE:
+ c->chrToYV12 = rgb64LEToUV_c;
+ break;
+ case AV_PIX_FMT_BGRA64BE:
+ c->chrToYV12 = bgr64BEToUV_c;
+ break;
+ case AV_PIX_FMT_BGRA64LE:
+ c->chrToYV12 = bgr64LEToUV_c;
+ break;
case AV_PIX_FMT_RGB48BE:
c->chrToYV12 = rgb48BEToUV_c;
break;
@@ -963,6 +1165,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_GBRP10LE:
c->readLumPlanar = planar_rgb10le_to_y;
break;
+ case AV_PIX_FMT_GBRP12LE:
+ c->readLumPlanar = planar_rgb12le_to_y;
+ break;
+ case AV_PIX_FMT_GBRP14LE:
+ c->readLumPlanar = planar_rgb14le_to_y;
+ break;
case AV_PIX_FMT_GBRAP16LE:
case AV_PIX_FMT_GBRP16LE:
c->readLumPlanar = planar_rgb16le_to_y;
@@ -973,6 +1181,12 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_GBRP10BE:
c->readLumPlanar = planar_rgb10be_to_y;
break;
+ case AV_PIX_FMT_GBRP12BE:
+ c->readLumPlanar = planar_rgb12be_to_y;
+ break;
+ case AV_PIX_FMT_GBRP14BE:
+ c->readLumPlanar = planar_rgb14be_to_y;
+ break;
case AV_PIX_FMT_GBRAP16BE:
case AV_PIX_FMT_GBRP16BE:
c->readLumPlanar = planar_rgb16be_to_y;
@@ -987,11 +1201,20 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV422P9LE:
case AV_PIX_FMT_YUV420P9LE:
case AV_PIX_FMT_YUV444P10LE:
+ case AV_PIX_FMT_YUV440P10LE:
case AV_PIX_FMT_YUV422P10LE:
case AV_PIX_FMT_YUV420P10LE:
+ case AV_PIX_FMT_YUV444P12LE:
+ case AV_PIX_FMT_YUV440P12LE:
+ case AV_PIX_FMT_YUV422P12LE:
+ case AV_PIX_FMT_YUV420P12LE:
+ case AV_PIX_FMT_YUV444P14LE:
+ case AV_PIX_FMT_YUV422P14LE:
+ case AV_PIX_FMT_YUV420P14LE:
case AV_PIX_FMT_YUV420P16LE:
case AV_PIX_FMT_YUV422P16LE:
case AV_PIX_FMT_YUV444P16LE:
+
case AV_PIX_FMT_GRAY16LE:
c->lumToYV12 = bswap16Y_c;
break;
@@ -1012,11 +1235,20 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YUV422P9BE:
case AV_PIX_FMT_YUV420P9BE:
case AV_PIX_FMT_YUV444P10BE:
+ case AV_PIX_FMT_YUV440P10BE:
case AV_PIX_FMT_YUV422P10BE:
case AV_PIX_FMT_YUV420P10BE:
+ case AV_PIX_FMT_YUV444P12BE:
+ case AV_PIX_FMT_YUV440P12BE:
+ case AV_PIX_FMT_YUV422P12BE:
+ case AV_PIX_FMT_YUV420P12BE:
+ case AV_PIX_FMT_YUV444P14BE:
+ case AV_PIX_FMT_YUV422P14BE:
+ case AV_PIX_FMT_YUV420P14BE:
case AV_PIX_FMT_YUV420P16BE:
case AV_PIX_FMT_YUV422P16BE:
case AV_PIX_FMT_YUV444P16BE:
+
case AV_PIX_FMT_GRAY16BE:
c->lumToYV12 = bswap16Y_c;
break;
@@ -1035,11 +1267,9 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
#endif
case AV_PIX_FMT_YA16LE:
c->lumToYV12 = read_ya16le_gray_c;
- c->alpToYV12 = read_ya16le_alpha_c;
break;
case AV_PIX_FMT_YA16BE:
c->lumToYV12 = read_ya16be_gray_c;
- c->alpToYV12 = read_ya16be_alpha_c;
break;
case AV_PIX_FMT_YUYV422:
case AV_PIX_FMT_YVYU422:
@@ -1128,9 +1358,28 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_BGR48LE:
c->lumToYV12 = bgr48LEToY_c;
break;
+ case AV_PIX_FMT_RGBA64BE:
+ c->lumToYV12 = rgb64BEToY_c;
+ break;
+ case AV_PIX_FMT_RGBA64LE:
+ c->lumToYV12 = rgb64LEToY_c;
+ break;
+ case AV_PIX_FMT_BGRA64BE:
+ c->lumToYV12 = bgr64BEToY_c;
+ break;
+ case AV_PIX_FMT_BGRA64LE:
+ c->lumToYV12 = bgr64LEToY_c;
}
if (c->alpPixBuf) {
+ if (is16BPS(srcFormat) || isNBPS(srcFormat)) {
+ if (HAVE_BIGENDIAN == !isBE(srcFormat))
+ c->alpToYV12 = bswap16Y_c;
+ }
switch (srcFormat) {
+ case AV_PIX_FMT_BGRA64LE:
+ case AV_PIX_FMT_RGBA64LE: c->alpToYV12 = rgba64leToA_c; break;
+ case AV_PIX_FMT_BGRA64BE:
+ case AV_PIX_FMT_RGBA64BE: c->alpToYV12 = rgba64beToA_c; break;
case AV_PIX_FMT_BGRA:
case AV_PIX_FMT_RGBA:
c->alpToYV12 = rgbaToA_c;
@@ -1142,6 +1391,15 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c)
case AV_PIX_FMT_YA8:
c->alpToYV12 = uyvyToY_c;
break;
+ case AV_PIX_FMT_YA16LE:
+ c->alpToYV12 = read_ya16le_alpha_c;
+ break;
+ case AV_PIX_FMT_YA16BE:
+ c->alpToYV12 = read_ya16be_alpha_c;
+ break;
+ case AV_PIX_FMT_PAL8 :
+ c->alpToYV12 = palToA_c;
+ break;
}
}
}
diff --git a/libswscale/log2_tab.c b/libswscale/log2_tab.c
new file mode 100644
index 0000000000..47a1df03b7
--- /dev/null
+++ b/libswscale/log2_tab.c
@@ -0,0 +1 @@
+#include "libavutil/log2_tab.c"
diff --git a/libswscale/options.c b/libswscale/options.c
index e7765d6ba9..f08267c609 100644
--- a/libswscale/options.c
+++ b/libswscale/options.c
@@ -1,20 +1,20 @@
/*
* Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -34,7 +34,7 @@ static const char *sws_context_to_name(void *ptr)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption swscale_options[] = {
- { "sws_flags", "scaler flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = DEFAULT }, 0, UINT_MAX, VE, "sws_flags" },
+ { "sws_flags", "scaler flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = SWS_BICUBIC }, 0, UINT_MAX, VE, "sws_flags" },
{ "fast_bilinear", "fast bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FAST_BILINEAR }, INT_MIN, INT_MAX, VE, "sws_flags" },
{ "bilinear", "bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BILINEAR }, INT_MIN, INT_MAX, VE, "sws_flags" },
{ "bicubic", "bicubic", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BICUBIC }, INT_MIN, INT_MAX, VE, "sws_flags" },
@@ -51,6 +51,7 @@ static const AVOption swscale_options[] = {
{ "full_chroma_int", "full chroma interpolation", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FULL_CHR_H_INT }, INT_MIN, INT_MAX, VE, "sws_flags" },
{ "full_chroma_inp", "full chroma input", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FULL_CHR_H_INP }, INT_MIN, INT_MAX, VE, "sws_flags" },
{ "bitexact", "", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BITEXACT }, INT_MIN, INT_MAX, VE, "sws_flags" },
+ { "error_diffusion", "error diffusion dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ERROR_DIFFUSION}, INT_MIN, INT_MAX, VE, "sws_flags" },
{ "srcw", "source width", OFFSET(srcW), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, INT_MAX, VE },
{ "srch", "source height", OFFSET(srcH), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, INT_MAX, VE },
@@ -63,10 +64,31 @@ 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 },
+
+ { "sws_dither", "set dithering algorithm", OFFSET(dither), AV_OPT_TYPE_INT, { .i64 = SWS_DITHER_AUTO }, 0, NB_SWS_DITHER, VE, "sws_dither" },
+ { "auto", "leave choice to sws", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_AUTO }, INT_MIN, INT_MAX, VE, "sws_dither" },
+ { "bayer", "bayer dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_BAYER }, INT_MIN, INT_MAX, VE, "sws_dither" },
+ { "ed", "error diffusion", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_ED }, INT_MIN, INT_MAX, VE, "sws_dither" },
+ { "a_dither", "arithmetic addition dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_A_DITHER}, INT_MIN, INT_MAX, VE, "sws_dither" },
+ { "x_dither", "arithmetic xor dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_X_DITHER}, INT_MIN, INT_MAX, VE, "sws_dither" },
+ { "gamma", "gamma correct scaling", OFFSET(gamma_flag), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE, "gamma" },
+ { "true", "enable", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "gamma" },
+ { "false", "disable", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "gamma" },
+
{ NULL }
};
-const AVClass sws_context_class = { "SWScaler", sws_context_to_name, swscale_options };
+const AVClass sws_context_class = {
+ .class_name = "SWScaler",
+ .item_name = sws_context_to_name,
+ .option = swscale_options,
+ .category = AV_CLASS_CATEGORY_SWSCALER,
+ .version = LIBAVUTIL_VERSION_INT,
+};
const AVClass *sws_get_class(void)
{
diff --git a/libswscale/output.c b/libswscale/output.c
index 1670f4a2b9..6048e2bbd7 100644
--- a/libswscale/output.c
+++ b/libswscale/output.c
@@ -1,24 +1,23 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2012 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
@@ -26,6 +25,7 @@
#include "libavutil/attributes.h"
#include "libavutil/avutil.h"
+#include "libavutil/avassert.h"
#include "libavutil/bswap.h"
#include "libavutil/cpu.h"
#include "libavutil/intreadwrite.h"
@@ -36,24 +36,27 @@
#include "swscale.h"
#include "swscale_internal.h"
-DECLARE_ALIGNED(8, static const uint8_t, dither_2x2_4)[2][8]={
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_2x2_4)[][8] = {
{ 1, 3, 1, 3, 1, 3, 1, 3, },
{ 2, 0, 2, 0, 2, 0, 2, 0, },
+{ 1, 3, 1, 3, 1, 3, 1, 3, },
};
-DECLARE_ALIGNED(8, static const uint8_t, dither_2x2_8)[2][8]={
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_2x2_8)[][8] = {
{ 6, 2, 6, 2, 6, 2, 6, 2, },
{ 0, 4, 0, 4, 0, 4, 0, 4, },
+{ 6, 2, 6, 2, 6, 2, 6, 2, },
};
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_4x4_16)[4][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_4x4_16)[][8] = {
{ 8, 4, 11, 7, 8, 4, 11, 7, },
{ 2, 14, 1, 13, 2, 14, 1, 13, },
{ 10, 6, 9, 5, 10, 6, 9, 5, },
{ 0, 12, 3, 15, 0, 12, 3, 15, },
+{ 8, 4, 11, 7, 8, 4, 11, 7, },
};
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_32)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_32)[][8] = {
{ 17, 9, 23, 15, 16, 8, 22, 14, },
{ 5, 29, 3, 27, 4, 28, 2, 26, },
{ 21, 13, 19, 11, 20, 12, 18, 10, },
@@ -62,9 +65,10 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_32)[8][8] = {
{ 4, 28, 2, 26, 5, 29, 3, 27, },
{ 20, 12, 18, 10, 21, 13, 19, 11, },
{ 1, 25, 7, 31, 0, 24, 6, 30, },
+{ 17, 9, 23, 15, 16, 8, 22, 14, },
};
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_73)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_73)[][8] = {
{ 0, 55, 14, 68, 3, 58, 17, 72, },
{ 37, 18, 50, 32, 40, 22, 54, 35, },
{ 9, 64, 5, 59, 13, 67, 8, 63, },
@@ -73,10 +77,11 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_73)[8][8] = {
{ 39, 21, 52, 34, 38, 19, 51, 33, },
{ 11, 66, 7, 62, 10, 65, 6, 60, },
{ 48, 30, 43, 25, 47, 29, 42, 24, },
+{ 0, 55, 14, 68, 3, 58, 17, 72, },
};
#if 1
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = {
{117, 62, 158, 103, 113, 58, 155, 100, },
{ 34, 199, 21, 186, 31, 196, 17, 182, },
{144, 89, 131, 76, 141, 86, 127, 72, },
@@ -85,10 +90,11 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
{ 28, 193, 14, 179, 38, 203, 24, 189, },
{138, 83, 124, 69, 148, 93, 134, 79, },
{ 7, 172, 48, 213, 3, 168, 45, 210, },
+{117, 62, 158, 103, 113, 58, 155, 100, },
};
#elif 1
// tries to correct a gamma of 1.5
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = {
{ 0, 143, 18, 200, 2, 156, 25, 215, },
{ 78, 28, 125, 64, 89, 36, 138, 74, },
{ 10, 180, 3, 161, 16, 195, 8, 175, },
@@ -97,10 +103,11 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
{ 85, 33, 134, 71, 81, 30, 130, 67, },
{ 14, 190, 6, 171, 12, 185, 5, 166, },
{117, 57, 101, 44, 113, 54, 97, 41, },
+{ 0, 143, 18, 200, 2, 156, 25, 215, },
};
#elif 1
// tries to correct a gamma of 2.0
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = {
{ 0, 124, 8, 193, 0, 140, 12, 213, },
{ 55, 14, 104, 42, 66, 19, 119, 52, },
{ 3, 168, 1, 145, 6, 187, 3, 162, },
@@ -109,10 +116,11 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
{ 62, 17, 114, 48, 58, 16, 109, 45, },
{ 5, 181, 2, 157, 4, 175, 1, 151, },
{ 95, 36, 78, 26, 90, 34, 74, 24, },
+{ 0, 124, 8, 193, 0, 140, 12, 213, },
};
#else
// tries to correct a gamma of 2.5
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = {
{ 0, 107, 3, 187, 0, 125, 6, 212, },
{ 39, 7, 86, 28, 49, 11, 102, 36, },
{ 1, 158, 0, 131, 3, 180, 1, 151, },
@@ -121,6 +129,7 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[8][8] = {
{ 45, 9, 96, 33, 42, 8, 91, 30, },
{ 2, 172, 1, 144, 2, 165, 0, 137, },
{ 77, 23, 60, 15, 72, 21, 56, 14, },
+{ 0, 107, 3, 187, 0, 125, 6, 212, },
};
#endif
@@ -136,7 +145,8 @@ yuv2plane1_16_c_template(const int32_t *src, uint16_t *dest, int dstW,
int big_endian, int output_bits)
{
int i;
- int shift = 19 - output_bits;
+ int shift = 3;
+ av_assert0(output_bits == 16);
for (i = 0; i < dstW; i++) {
int val = src[i] + (1 << (shift - 1));
@@ -150,10 +160,11 @@ yuv2planeX_16_c_template(const int16_t *filter, int filterSize,
int big_endian, int output_bits)
{
int i;
- int shift = 15 + 16 - output_bits;
+ int shift = 15;
+ av_assert0(output_bits == 16);
for (i = 0; i < dstW; i++) {
- int val = 1 << (30-output_bits);
+ int val = 1 << (shift - 1);
int j;
/* range of val is [0,0x7FFFFFFF], so 31 bits, but with lanczos/spline
@@ -163,7 +174,7 @@ yuv2planeX_16_c_template(const int16_t *filter, int filterSize,
* reasonable filterSize), and re-add that at the end. */
val -= 0x40000000;
for (j = 0; j < filterSize; j++)
- val += src[j][i] * filter[j];
+ val += src[j][i] * (unsigned)filter[j];
output_pixel(&dest[i], val, 0x8000, int);
}
@@ -200,7 +211,7 @@ yuv2planeX_10_c_template(const int16_t *filter, int filterSize,
int shift = 11 + 16 - output_bits;
for (i = 0; i < dstW; i++) {
- int val = 1 << (26-output_bits);
+ int val = 1 << (shift - 1);
int j;
for (j = 0; j < filterSize; j++)
@@ -232,6 +243,10 @@ yuv2NBPS( 9, BE, 1, 10, int16_t)
yuv2NBPS( 9, LE, 0, 10, int16_t)
yuv2NBPS(10, BE, 1, 10, int16_t)
yuv2NBPS(10, LE, 0, 10, int16_t)
+yuv2NBPS(12, BE, 1, 10, int16_t)
+yuv2NBPS(12, LE, 0, 10, int16_t)
+yuv2NBPS(14, BE, 1, 10, int16_t)
+yuv2NBPS(14, LE, 0, 10, int16_t)
yuv2NBPS(16, BE, 1, 16, int32_t)
yuv2NBPS(16, LE, 0, 16, int32_t)
@@ -317,6 +332,7 @@ yuv2mono_X_c_template(SwsContext *c, const int16_t *lumFilter,
const uint8_t * const d128 = ff_dither_8x8_220[y&7];
int i;
unsigned acc = 0;
+ int err = 0;
for (i = 0; i < dstW; i += 2) {
int j;
@@ -333,12 +349,25 @@ yuv2mono_X_c_template(SwsContext *c, const int16_t *lumFilter,
Y1 = av_clip_uint8(Y1);
Y2 = av_clip_uint8(Y2);
}
- accumulate_bit(acc, Y1 + d128[(i + 0) & 7]);
- accumulate_bit(acc, Y2 + d128[(i + 1) & 7]);
+ if (c->dither == SWS_DITHER_ED) {
+ Y1 += (7*err + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2] + 8 - 256)>>4;
+ c->dither_error[0][i] = err;
+ acc = 2*acc + (Y1 >= 128);
+ Y1 -= 220*(acc&1);
+
+ err = Y2 + ((7*Y1 + 1*c->dither_error[0][i+1] + 5*c->dither_error[0][i+2] + 3*c->dither_error[0][i+3] + 8 - 256)>>4);
+ c->dither_error[0][i+1] = Y1;
+ acc = 2*acc + (err >= 128);
+ err -= 220*(acc&1);
+ } else {
+ accumulate_bit(acc, Y1 + d128[(i + 0) & 7]);
+ accumulate_bit(acc, Y2 + d128[(i + 1) & 7]);
+ }
if ((i & 7) == 6) {
output_pixel(*dest++, acc);
}
}
+ c->dither_error[0][i] = err;
if (i & 6) {
output_pixel(*dest, acc);
@@ -357,6 +386,29 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2],
int yalpha1 = 4096 - yalpha;
int i;
+ if (c->dither == SWS_DITHER_ED) {
+ int err = 0;
+ int acc = 0;
+ for (i = 0; i < dstW; i +=2) {
+ int Y;
+
+ Y = (buf0[i + 0] * yalpha1 + buf1[i + 0] * yalpha) >> 19;
+ Y += (7*err + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2] + 8 - 256)>>4;
+ c->dither_error[0][i] = err;
+ acc = 2*acc + (Y >= 128);
+ Y -= 220*(acc&1);
+
+ err = (buf0[i + 1] * yalpha1 + buf1[i + 1] * yalpha) >> 19;
+ err += (7*Y + 1*c->dither_error[0][i+1] + 5*c->dither_error[0][i+2] + 3*c->dither_error[0][i+3] + 8 - 256)>>4;
+ c->dither_error[0][i+1] = Y;
+ acc = 2*acc + (err >= 128);
+ err -= 220*(acc&1);
+
+ if ((i & 7) == 6)
+ output_pixel(*dest++, acc);
+ }
+ c->dither_error[0][i] = err;
+ } else {
for (i = 0; i < dstW; i += 8) {
int Y, acc = 0;
@@ -379,6 +431,7 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2],
output_pixel(*dest++, acc);
}
+ }
}
static av_always_inline void
@@ -390,20 +443,43 @@ yuv2mono_1_c_template(SwsContext *c, const int16_t *buf0,
const uint8_t * const d128 = ff_dither_8x8_220[y & 7];
int i;
+ if (c->dither == SWS_DITHER_ED) {
+ int err = 0;
+ int acc = 0;
+ for (i = 0; i < dstW; i +=2) {
+ int Y;
+
+ Y = ((buf0[i + 0] + 64) >> 7);
+ Y += (7*err + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2] + 8 - 256)>>4;
+ c->dither_error[0][i] = err;
+ acc = 2*acc + (Y >= 128);
+ Y -= 220*(acc&1);
+
+ err = ((buf0[i + 1] + 64) >> 7);
+ err += (7*Y + 1*c->dither_error[0][i+1] + 5*c->dither_error[0][i+2] + 3*c->dither_error[0][i+3] + 8 - 256)>>4;
+ c->dither_error[0][i+1] = Y;
+ acc = 2*acc + (err >= 128);
+ err -= 220*(acc&1);
+
+ if ((i & 7) == 6)
+ output_pixel(*dest++, acc);
+ }
+ c->dither_error[0][i] = err;
+ } else {
for (i = 0; i < dstW; i += 8) {
int acc = 0;
-
- accumulate_bit(acc, (buf0[i + 0] >> 7) + d128[0]);
- accumulate_bit(acc, (buf0[i + 1] >> 7) + d128[1]);
- accumulate_bit(acc, (buf0[i + 2] >> 7) + d128[2]);
- accumulate_bit(acc, (buf0[i + 3] >> 7) + d128[3]);
- accumulate_bit(acc, (buf0[i + 4] >> 7) + d128[4]);
- accumulate_bit(acc, (buf0[i + 5] >> 7) + d128[5]);
- accumulate_bit(acc, (buf0[i + 6] >> 7) + d128[6]);
- accumulate_bit(acc, (buf0[i + 7] >> 7) + d128[7]);
+ 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]);
+ accumulate_bit(acc, ((buf0[i + 3] + 64) >> 7) + d128[3]);
+ accumulate_bit(acc, ((buf0[i + 4] + 64) >> 7) + d128[4]);
+ accumulate_bit(acc, ((buf0[i + 5] + 64) >> 7) + d128[5]);
+ accumulate_bit(acc, ((buf0[i + 6] + 64) >> 7) + d128[6]);
+ accumulate_bit(acc, ((buf0[i + 7] + 64) >> 7) + d128[7]);
output_pixel(*dest++, acc);
}
+ }
}
#undef output_pixel
@@ -521,10 +597,12 @@ yuv2422_2_c_template(SwsContext *c, const int16_t *buf[2],
int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19;
int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19;
- Y1 = av_clip_uint8(Y1);
- Y2 = av_clip_uint8(Y2);
- U = av_clip_uint8(U);
- V = av_clip_uint8(V);
+ if ((Y1 | Y2 | U | V) & 0x100) {
+ Y1 = av_clip_uint8(Y1);
+ Y2 = av_clip_uint8(Y2);
+ U = av_clip_uint8(U);
+ V = av_clip_uint8(V);
+ }
output_pixels(i * 4, Y1, U, Y2, V);
}
@@ -541,10 +619,17 @@ yuv2422_1_c_template(SwsContext *c, const int16_t *buf0,
if (uvalpha < 2048) {
for (i = 0; i < ((dstW + 1) >> 1); i++) {
- int Y1 = buf0[i * 2] >> 7;
- int Y2 = buf0[i * 2 + 1] >> 7;
- int U = ubuf0[i] >> 7;
- int V = vbuf0[i] >> 7;
+ int Y1 = (buf0[i * 2 ]+64) >> 7;
+ int Y2 = (buf0[i * 2 + 1]+64) >> 7;
+ int U = (ubuf0[i] +64) >> 7;
+ int V = (vbuf0[i] +64) >> 7;
+
+ if ((Y1 | Y2 | U | V) & 0x100) {
+ Y1 = av_clip_uint8(Y1);
+ Y2 = av_clip_uint8(Y2);
+ U = av_clip_uint8(U);
+ V = av_clip_uint8(V);
+ }
Y1 = av_clip_uint8(Y1);
Y2 = av_clip_uint8(Y2);
@@ -556,10 +641,17 @@ yuv2422_1_c_template(SwsContext *c, const int16_t *buf0,
} else {
const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1];
for (i = 0; i < ((dstW + 1) >> 1); i++) {
- int Y1 = buf0[i * 2] >> 7;
- int Y2 = buf0[i * 2 + 1] >> 7;
- int U = (ubuf0[i] + ubuf1[i]) >> 8;
- int V = (vbuf0[i] + vbuf1[i]) >> 8;
+ int Y1 = (buf0[i * 2 ] + 64) >> 7;
+ int Y2 = (buf0[i * 2 + 1] + 64) >> 7;
+ int U = (ubuf0[i] + ubuf1[i]+128) >> 8;
+ int V = (vbuf0[i] + vbuf1[i]+128) >> 8;
+
+ if ((Y1 | Y2 | U | V) & 0x100) {
+ Y1 = av_clip_uint8(Y1);
+ Y2 = av_clip_uint8(Y2);
+ U = av_clip_uint8(U);
+ V = av_clip_uint8(V);
+ }
Y1 = av_clip_uint8(Y1);
Y2 = av_clip_uint8(Y2);
@@ -577,8 +669,8 @@ YUV2PACKEDWRAPPER(yuv2, 422, yuyv422, AV_PIX_FMT_YUYV422)
YUV2PACKEDWRAPPER(yuv2, 422, yvyu422, AV_PIX_FMT_YVYU422)
YUV2PACKEDWRAPPER(yuv2, 422, uyvy422, AV_PIX_FMT_UYVY422)
-#define R_B ((target == AV_PIX_FMT_RGB48LE || target == AV_PIX_FMT_RGB48BE) ? R : B)
-#define B_R ((target == AV_PIX_FMT_RGB48LE || target == AV_PIX_FMT_RGB48BE) ? B : R)
+#define R_B ((target == AV_PIX_FMT_RGB48LE || target == AV_PIX_FMT_RGB48BE || target == AV_PIX_FMT_RGBA64LE || target == AV_PIX_FMT_RGBA64BE) ? R : B)
+#define B_R ((target == AV_PIX_FMT_RGB48LE || target == AV_PIX_FMT_RGB48BE || target == AV_PIX_FMT_RGBA64LE || target == AV_PIX_FMT_RGBA64BE) ? B : R)
#define output_pixel(pos, val) \
if (isBE(target)) { \
AV_WB16(pos, val); \
@@ -587,12 +679,231 @@ YUV2PACKEDWRAPPER(yuv2, 422, uyvy422, AV_PIX_FMT_UYVY422)
}
static av_always_inline void
+yuv2rgba64_X_c_template(SwsContext *c, const int16_t *lumFilter,
+ const int32_t **lumSrc, int lumFilterSize,
+ const int16_t *chrFilter, const int32_t **chrUSrc,
+ const int32_t **chrVSrc, int chrFilterSize,
+ const int32_t **alpSrc, uint16_t *dest, int dstW,
+ int y, enum AVPixelFormat target, int hasAlpha)
+{
+ int i;
+ int A1 = 0xffff<<14, A2 = 0xffff<<14;
+
+ for (i = 0; i < ((dstW + 1) >> 1); i++) {
+ int j;
+ int Y1 = -0x40000000;
+ int Y2 = -0x40000000;
+ int U = -128 << 23; // 19
+ int V = -128 << 23;
+ int R, G, B;
+
+ for (j = 0; j < lumFilterSize; j++) {
+ Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j];
+ Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
+ }
+ for (j = 0; j < chrFilterSize; j++) {;
+ U += chrUSrc[j][i] * (unsigned)chrFilter[j];
+ V += chrVSrc[j][i] * (unsigned)chrFilter[j];
+ }
+
+ if (hasAlpha) {
+ A1 = -0x40000000;
+ A2 = -0x40000000;
+ for (j = 0; j < lumFilterSize; j++) {
+ A1 += alpSrc[j][i * 2] * (unsigned)lumFilter[j];
+ A2 += alpSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
+ }
+ A1 >>= 1;
+ A1 += 0x20002000;
+ A2 >>= 1;
+ A2 += 0x20002000;
+ }
+
+ // 8bit: 12+15=27; 16-bit: 12+19=31
+ Y1 >>= 14; // 10
+ Y1 += 0x10000;
+ Y2 >>= 14;
+ Y2 += 0x10000;
+ U >>= 14;
+ V >>= 14;
+
+ // 8bit: 27 -> 17bit, 16bit: 31 - 14 = 17bit
+ Y1 -= c->yuv2rgb_y_offset;
+ Y2 -= c->yuv2rgb_y_offset;
+ Y1 *= c->yuv2rgb_y_coeff;
+ Y2 *= c->yuv2rgb_y_coeff;
+ Y1 += 1 << 13; // 21
+ Y2 += 1 << 13;
+ // 8bit: 17 + 13bit = 30bit, 16bit: 17 + 13bit = 30bit
+
+ R = V * c->yuv2rgb_v2r_coeff;
+ G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;
+ B = U * c->yuv2rgb_u2b_coeff;
+
+ // 8bit: 30 - 22 = 8bit, 16bit: 30bit - 14 = 16bit
+ output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(R_B + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14);
+ dest += 8;
+ }
+}
+
+static av_always_inline void
+yuv2rgba64_2_c_template(SwsContext *c, const int32_t *buf[2],
+ const int32_t *ubuf[2], const int32_t *vbuf[2],
+ const int32_t *abuf[2], uint16_t *dest, int dstW,
+ int yalpha, int uvalpha, int y,
+ enum AVPixelFormat target, int hasAlpha)
+{
+ const int32_t *buf0 = buf[0], *buf1 = buf[1],
+ *ubuf0 = ubuf[0], *ubuf1 = ubuf[1],
+ *vbuf0 = vbuf[0], *vbuf1 = vbuf[1],
+ *abuf0 = hasAlpha ? abuf[0] : NULL,
+ *abuf1 = hasAlpha ? abuf[1] : NULL;
+ int yalpha1 = 4096 - yalpha;
+ int uvalpha1 = 4096 - uvalpha;
+ int i;
+ int A1 = 0xffff<<14, A2 = 0xffff<<14;
+
+ 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;
+ 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;
+
+ Y1 -= c->yuv2rgb_y_offset;
+ Y2 -= c->yuv2rgb_y_offset;
+ Y1 *= c->yuv2rgb_y_coeff;
+ Y2 *= c->yuv2rgb_y_coeff;
+ Y1 += 1 << 13;
+ Y2 += 1 << 13;
+
+ R = V * c->yuv2rgb_v2r_coeff;
+ G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;
+ B = U * c->yuv2rgb_u2b_coeff;
+
+ if (hasAlpha) {
+ A1 = (abuf0[i * 2 ] * yalpha1 + abuf1[i * 2 ] * yalpha) >> 1;
+ A2 = (abuf0[i * 2 + 1] * yalpha1 + abuf1[i * 2 + 1] * yalpha) >> 1;
+
+ A1 += 1 << 13;
+ A2 += 1 << 13;
+ }
+
+ output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(R_B + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14);
+ dest += 8;
+ }
+}
+
+static av_always_inline void
+yuv2rgba64_1_c_template(SwsContext *c, const int32_t *buf0,
+ const int32_t *ubuf[2], const int32_t *vbuf[2],
+ const int32_t *abuf0, uint16_t *dest, int dstW,
+ int uvalpha, int y, enum AVPixelFormat target, int hasAlpha)
+{
+ const int32_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0];
+ int i;
+ int A1 = 0xffff<<14, A2= 0xffff<<14;
+
+ if (uvalpha < 2048) {
+ for (i = 0; i < ((dstW + 1) >> 1); i++) {
+ int Y1 = (buf0[i * 2] ) >> 2;
+ int Y2 = (buf0[i * 2 + 1]) >> 2;
+ int U = (ubuf0[i] + (-128 << 11)) >> 2;
+ int V = (vbuf0[i] + (-128 << 11)) >> 2;
+ int R, G, B;
+
+ Y1 -= c->yuv2rgb_y_offset;
+ Y2 -= c->yuv2rgb_y_offset;
+ Y1 *= c->yuv2rgb_y_coeff;
+ Y2 *= c->yuv2rgb_y_coeff;
+ Y1 += 1 << 13;
+ Y2 += 1 << 13;
+
+ if (hasAlpha) {
+ A1 = abuf0[i * 2 ] << 11;
+ A2 = abuf0[i * 2 + 1] << 11;
+
+ A1 += 1 << 13;
+ A2 += 1 << 13;
+ }
+
+ R = V * c->yuv2rgb_v2r_coeff;
+ G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;
+ B = U * c->yuv2rgb_u2b_coeff;
+
+ output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(R_B + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14);
+ dest += 8;
+ }
+ } else {
+ const int32_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1];
+ int A1 = 0xffff<<14, A2 = 0xffff<<14;
+ for (i = 0; i < ((dstW + 1) >> 1); i++) {
+ int Y1 = (buf0[i * 2] ) >> 2;
+ int Y2 = (buf0[i * 2 + 1]) >> 2;
+ int U = (ubuf0[i] + ubuf1[i] + (-128 << 12)) >> 3;
+ int V = (vbuf0[i] + vbuf1[i] + (-128 << 12)) >> 3;
+ int R, G, B;
+
+ Y1 -= c->yuv2rgb_y_offset;
+ Y2 -= c->yuv2rgb_y_offset;
+ Y1 *= c->yuv2rgb_y_coeff;
+ Y2 *= c->yuv2rgb_y_coeff;
+ Y1 += 1 << 13;
+ Y2 += 1 << 13;
+
+ if (hasAlpha) {
+ A1 = abuf0[i * 2 ] << 11;
+ A2 = abuf0[i * 2 + 1] << 11;
+
+ A1 += 1 << 13;
+ A2 += 1 << 13;
+ }
+
+ R = V * c->yuv2rgb_v2r_coeff;
+ G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;
+ B = U * c->yuv2rgb_u2b_coeff;
+
+ output_pixel(&dest[0], av_clip_uintp2(R_B + Y1, 30) >> 14);
+ output_pixel(&dest[1], av_clip_uintp2( G + Y1, 30) >> 14);
+ output_pixel(&dest[2], av_clip_uintp2(B_R + Y1, 30) >> 14);
+ output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14);
+ output_pixel(&dest[4], av_clip_uintp2(R_B + Y2, 30) >> 14);
+ output_pixel(&dest[5], av_clip_uintp2( G + Y2, 30) >> 14);
+ output_pixel(&dest[6], av_clip_uintp2(B_R + Y2, 30) >> 14);
+ output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14);
+ dest += 8;
+ }
+ }
+}
+
+static av_always_inline void
yuv2rgb48_X_c_template(SwsContext *c, const int16_t *lumFilter,
const int32_t **lumSrc, int lumFilterSize,
const int16_t *chrFilter, const int32_t **chrUSrc,
const int32_t **chrVSrc, int chrFilterSize,
const int32_t **alpSrc, uint16_t *dest, int dstW,
- int y, enum AVPixelFormat target)
+ int y, enum AVPixelFormat target, int hasAlpha)
{
int i;
@@ -605,12 +916,12 @@ yuv2rgb48_X_c_template(SwsContext *c, const int16_t *lumFilter,
int R, G, B;
for (j = 0; j < lumFilterSize; j++) {
- Y1 += lumSrc[j][i * 2] * lumFilter[j];
- Y2 += lumSrc[j][i * 2 + 1] * lumFilter[j];
+ Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j];
+ Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j];
}
- for (j = 0; j < chrFilterSize; j++) {
- U += chrUSrc[j][i] * chrFilter[j];
- V += chrVSrc[j][i] * chrFilter[j];
+ for (j = 0; j < chrFilterSize; j++) {;
+ U += chrUSrc[j][i] * (unsigned)chrFilter[j];
+ V += chrVSrc[j][i] * (unsigned)chrFilter[j];
}
// 8bit: 12+15=27; 16-bit: 12+19=31
@@ -650,7 +961,7 @@ yuv2rgb48_2_c_template(SwsContext *c, const int32_t *buf[2],
const int32_t *ubuf[2], const int32_t *vbuf[2],
const int32_t *abuf[2], uint16_t *dest, int dstW,
int yalpha, int uvalpha, int y,
- enum AVPixelFormat target)
+ enum AVPixelFormat target, int hasAlpha)
{
const int32_t *buf0 = buf[0], *buf1 = buf[1],
*ubuf0 = ubuf[0], *ubuf1 = ubuf[1],
@@ -691,7 +1002,7 @@ static av_always_inline void
yuv2rgb48_1_c_template(SwsContext *c, const int32_t *buf0,
const int32_t *ubuf[2], const int32_t *vbuf[2],
const int32_t *abuf0, uint16_t *dest, int dstW,
- int uvalpha, int y, enum AVPixelFormat target)
+ int uvalpha, int y, enum AVPixelFormat target, int hasAlpha)
{
const int32_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0];
int i;
@@ -758,7 +1069,7 @@ yuv2rgb48_1_c_template(SwsContext *c, const int32_t *buf0,
#undef r_b
#undef b_r
-#define YUV2PACKED16WRAPPER(name, base, ext, fmt) \
+#define YUV2PACKED16WRAPPER(name, base, ext, fmt, hasAlpha) \
static void name ## ext ## _X_c(SwsContext *c, const int16_t *lumFilter, \
const int16_t **_lumSrc, int lumFilterSize, \
const int16_t *chrFilter, const int16_t **_chrUSrc, \
@@ -773,7 +1084,7 @@ static void name ## ext ## _X_c(SwsContext *c, const int16_t *lumFilter, \
uint16_t *dest = (uint16_t *) _dest; \
name ## base ## _X_c_template(c, lumFilter, lumSrc, lumFilterSize, \
chrFilter, chrUSrc, chrVSrc, chrFilterSize, \
- alpSrc, dest, dstW, y, fmt); \
+ alpSrc, dest, dstW, y, fmt, hasAlpha); \
} \
\
static void name ## ext ## _2_c(SwsContext *c, const int16_t *_buf[2], \
@@ -787,7 +1098,7 @@ static void name ## ext ## _2_c(SwsContext *c, const int16_t *_buf[2], \
**abuf = (const int32_t **) _abuf; \
uint16_t *dest = (uint16_t *) _dest; \
name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \
- dest, dstW, yalpha, uvalpha, y, fmt); \
+ dest, dstW, yalpha, uvalpha, y, fmt, hasAlpha); \
} \
\
static void name ## ext ## _1_c(SwsContext *c, const int16_t *_buf0, \
@@ -801,13 +1112,21 @@ static void name ## ext ## _1_c(SwsContext *c, const int16_t *_buf0, \
*abuf0 = (const int32_t *) _abuf0; \
uint16_t *dest = (uint16_t *) _dest; \
name ## base ## _1_c_template(c, buf0, ubuf, vbuf, abuf0, dest, \
- dstW, uvalpha, y, fmt); \
+ dstW, uvalpha, y, fmt, hasAlpha); \
}
-YUV2PACKED16WRAPPER(yuv2, rgb48, rgb48be, AV_PIX_FMT_RGB48BE)
-YUV2PACKED16WRAPPER(yuv2, rgb48, rgb48le, AV_PIX_FMT_RGB48LE)
-YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48be, AV_PIX_FMT_BGR48BE)
-YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48le, AV_PIX_FMT_BGR48LE)
+YUV2PACKED16WRAPPER(yuv2, rgb48, rgb48be, AV_PIX_FMT_RGB48BE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgb48, rgb48le, AV_PIX_FMT_RGB48LE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48be, AV_PIX_FMT_BGR48BE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48le, AV_PIX_FMT_BGR48LE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgba64, rgba64be, AV_PIX_FMT_RGBA64BE, 1)
+YUV2PACKED16WRAPPER(yuv2, rgba64, rgba64le, AV_PIX_FMT_RGBA64LE, 1)
+YUV2PACKED16WRAPPER(yuv2, rgba64, rgbx64be, AV_PIX_FMT_RGBA64BE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgba64, rgbx64le, AV_PIX_FMT_RGBA64LE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgba64, bgra64be, AV_PIX_FMT_BGRA64BE, 1)
+YUV2PACKED16WRAPPER(yuv2, rgba64, bgra64le, AV_PIX_FMT_BGRA64LE, 1)
+YUV2PACKED16WRAPPER(yuv2, rgba64, bgrx64be, AV_PIX_FMT_BGRA64BE, 0)
+YUV2PACKED16WRAPPER(yuv2, rgba64, bgrx64le, AV_PIX_FMT_BGRA64LE, 0)
/*
* Write out 2 RGB pixels in the target pixel format. This function takes a
@@ -818,7 +1137,7 @@ YUV2PACKED16WRAPPER(yuv2, rgb48, bgr48le, AV_PIX_FMT_BGR48LE)
* correct RGB values into the destination buffer.
*/
static av_always_inline void
-yuv2rgb_write(uint8_t *_dest, int i, unsigned Y1, unsigned Y2,
+yuv2rgb_write(uint8_t *_dest, int i, int Y1, int Y2,
unsigned A1, unsigned A2,
const void *_r, const void *_g, const void *_b, int y,
enum AVPixelFormat target, int hasAlpha)
@@ -839,9 +1158,15 @@ yuv2rgb_write(uint8_t *_dest, int i, unsigned Y1, unsigned Y2,
if (hasAlpha) {
int sh = (target == AV_PIX_FMT_RGB32_1 || target == AV_PIX_FMT_BGR32_1) ? 0 : 24;
+ av_assert2((((r[Y1] + g[Y1] + b[Y1]) >> sh) & 0xFF) == 0);
dest[i * 2 + 0] = r[Y1] + g[Y1] + b[Y1] + (A1 << sh);
dest[i * 2 + 1] = r[Y2] + g[Y2] + b[Y2] + (A2 << sh);
} else {
+#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1
+ int sh = (target == AV_PIX_FMT_RGB32_1 || target == AV_PIX_FMT_BGR32_1) ? 0 : 24;
+
+ av_assert2((((r[Y1] + g[Y1] + b[Y1]) >> sh) & 0xFF) == 0xFF);
+#endif
dest[i * 2 + 0] = r[Y1] + g[Y1] + b[Y1];
dest[i * 2 + 1] = r[Y2] + g[Y2] + b[Y2];
}
@@ -854,6 +1179,7 @@ yuv2rgb_write(uint8_t *_dest, int i, unsigned Y1, unsigned Y2,
#define r_b ((target == AV_PIX_FMT_RGB24) ? r : b)
#define b_r ((target == AV_PIX_FMT_RGB24) ? b : r)
+
dest[i * 6 + 0] = r_b[Y1];
dest[i * 6 + 1] = g[Y1];
dest[i * 6 + 2] = b_r[Y1];
@@ -872,19 +1198,19 @@ yuv2rgb_write(uint8_t *_dest, int i, unsigned Y1, unsigned Y2,
int dr1, dg1, db1, dr2, dg2, db2;
if (target == AV_PIX_FMT_RGB565 || target == AV_PIX_FMT_BGR565) {
- dr1 = dither_2x2_8[ y & 1 ][0];
- dg1 = dither_2x2_4[ y & 1 ][0];
- db1 = dither_2x2_8[(y & 1) ^ 1][0];
- dr2 = dither_2x2_8[ y & 1 ][1];
- dg2 = dither_2x2_4[ y & 1 ][1];
- db2 = dither_2x2_8[(y & 1) ^ 1][1];
+ dr1 = ff_dither_2x2_8[ y & 1 ][0];
+ dg1 = ff_dither_2x2_4[ y & 1 ][0];
+ db1 = ff_dither_2x2_8[(y & 1) ^ 1][0];
+ dr2 = ff_dither_2x2_8[ y & 1 ][1];
+ dg2 = ff_dither_2x2_4[ y & 1 ][1];
+ db2 = ff_dither_2x2_8[(y & 1) ^ 1][1];
} else if (target == AV_PIX_FMT_RGB555 || target == AV_PIX_FMT_BGR555) {
- dr1 = dither_2x2_8[ y & 1 ][0];
- dg1 = dither_2x2_8[ y & 1 ][1];
- db1 = dither_2x2_8[(y & 1) ^ 1][0];
- dr2 = dither_2x2_8[ y & 1 ][1];
- dg2 = dither_2x2_8[ y & 1 ][0];
- db2 = dither_2x2_8[(y & 1) ^ 1][1];
+ dr1 = ff_dither_2x2_8[ y & 1 ][0];
+ dg1 = ff_dither_2x2_8[ y & 1 ][1];
+ db1 = ff_dither_2x2_8[(y & 1) ^ 1][0];
+ dr2 = ff_dither_2x2_8[ y & 1 ][1];
+ dg2 = ff_dither_2x2_8[ y & 1 ][0];
+ db2 = ff_dither_2x2_8[(y & 1) ^ 1][1];
} else {
dr1 = ff_dither_4x4_16[ y & 3 ][0];
dg1 = ff_dither_4x4_16[ y & 3 ][1];
@@ -959,12 +1285,6 @@ yuv2rgb_X_c_template(SwsContext *c, const int16_t *lumFilter,
Y2 >>= 19;
U >>= 19;
V >>= 19;
- if ((Y1 | Y2 | U | V) & 0x100) {
- Y1 = av_clip_uint8(Y1);
- Y2 = av_clip_uint8(Y2);
- U = av_clip_uint8(U);
- V = av_clip_uint8(V);
- }
if (hasAlpha) {
A1 = 1 << 18;
A2 = 1 << 18;
@@ -980,10 +1300,9 @@ yuv2rgb_X_c_template(SwsContext *c, const int16_t *lumFilter,
}
}
- /* FIXME fix tables so that clipping is not needed and then use _NOCLIP*/
- r = c->table_rV[V];
- g = (c->table_gU[U] + c->table_gV[V]);
- b = c->table_bU[U];
+ r = c->table_rV[V + YUVRGB_TABLE_HEADROOM];
+ g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
+ b = c->table_bU[U + YUVRGB_TABLE_HEADROOM];
yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 0,
r, g, b, y, target, hasAlpha);
@@ -1012,16 +1331,9 @@ yuv2rgb_2_c_template(SwsContext *c, const int16_t *buf[2],
int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19;
int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19;
int A1, A2;
- const void *r, *g, *b;
-
- Y1 = av_clip_uint8(Y1);
- Y2 = av_clip_uint8(Y2);
- U = av_clip_uint8(U);
- V = av_clip_uint8(V);
-
- r = c->table_rV[V];
- g = (c->table_gU[U] + c->table_gV[V]);
- b = c->table_bU[U];
+ const void *r = c->table_rV[V + YUVRGB_TABLE_HEADROOM],
+ *g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]),
+ *b = c->table_bU[U + YUVRGB_TABLE_HEADROOM];
if (hasAlpha) {
A1 = (abuf0[i * 2 ] * yalpha1 + abuf1[i * 2 ] * yalpha) >> 19;
@@ -1047,25 +1359,18 @@ yuv2rgb_1_c_template(SwsContext *c, const int16_t *buf0,
if (uvalpha < 2048) {
for (i = 0; i < ((dstW + 1) >> 1); i++) {
- int Y1 = buf0[i * 2] >> 7;
- int Y2 = buf0[i * 2 + 1] >> 7;
- int U = ubuf0[i] >> 7;
- int V = vbuf0[i] >> 7;
+ int Y1 = (buf0[i * 2 ] + 64) >> 7;
+ int Y2 = (buf0[i * 2 + 1] + 64) >> 7;
+ int U = (ubuf0[i] + 64) >> 7;
+ int V = (vbuf0[i] + 64) >> 7;
int A1, A2;
- const void *r, *g, *b;
-
- Y1 = av_clip_uint8(Y1);
- Y2 = av_clip_uint8(Y2);
- U = av_clip_uint8(U);
- V = av_clip_uint8(V);
-
- r = c->table_rV[V];
- g = (c->table_gU[U] + c->table_gV[V]);
- b = c->table_bU[U];
+ const void *r = c->table_rV[V + YUVRGB_TABLE_HEADROOM],
+ *g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]),
+ *b = c->table_bU[U + YUVRGB_TABLE_HEADROOM];
if (hasAlpha) {
- A1 = abuf0[i * 2 ] >> 7;
- A2 = abuf0[i * 2 + 1] >> 7;
+ A1 = abuf0[i * 2 ] * 255 + 16384 >> 15;
+ A2 = abuf0[i * 2 + 1] * 255 + 16384 >> 15;
A1 = av_clip_uint8(A1);
A2 = av_clip_uint8(A2);
}
@@ -1076,25 +1381,18 @@ yuv2rgb_1_c_template(SwsContext *c, const int16_t *buf0,
} else {
const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1];
for (i = 0; i < ((dstW + 1) >> 1); i++) {
- int Y1 = buf0[i * 2] >> 7;
- int Y2 = buf0[i * 2 + 1] >> 7;
- int U = (ubuf0[i] + ubuf1[i]) >> 8;
- int V = (vbuf0[i] + vbuf1[i]) >> 8;
+ int Y1 = (buf0[i * 2 ] + 64) >> 7;
+ int Y2 = (buf0[i * 2 + 1] + 64) >> 7;
+ int U = (ubuf0[i] + ubuf1[i] + 128) >> 8;
+ int V = (vbuf0[i] + vbuf1[i] + 128) >> 8;
int A1, A2;
- const void *r, *g, *b;
-
- Y1 = av_clip_uint8(Y1);
- Y2 = av_clip_uint8(Y2);
- U = av_clip_uint8(U);
- V = av_clip_uint8(V);
-
- r = c->table_rV[V];
- g = (c->table_gU[U] + c->table_gV[V]);
- b = c->table_bU[U];
+ const void *r = c->table_rV[V + YUVRGB_TABLE_HEADROOM],
+ *g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]),
+ *b = c->table_bU[U + YUVRGB_TABLE_HEADROOM];
if (hasAlpha) {
- A1 = abuf0[i * 2 ] >> 7;
- A2 = abuf0[i * 2 + 1] >> 7;
+ A1 = (abuf0[i * 2 ] + 64) >> 7;
+ A2 = (abuf0[i * 2 + 1] + 64) >> 7;
A1 = av_clip_uint8(A1);
A2 = av_clip_uint8(A2);
}
@@ -1117,7 +1415,8 @@ static void name ## ext ## _X_c(SwsContext *c, const int16_t *lumFilter, \
chrFilter, chrUSrc, chrVSrc, chrFilterSize, \
alpSrc, dest, dstW, y, fmt, hasAlpha); \
}
-#define YUV2RGBWRAPPER(name, base, ext, fmt, hasAlpha) \
+
+#define YUV2RGBWRAPPERX2(name, base, ext, fmt, hasAlpha) \
YUV2RGBWRAPPERX(name, base, ext, fmt, hasAlpha) \
static void name ## ext ## _2_c(SwsContext *c, const int16_t *buf[2], \
const int16_t *ubuf[2], const int16_t *vbuf[2], \
@@ -1126,8 +1425,10 @@ static void name ## ext ## _2_c(SwsContext *c, const int16_t *buf[2], \
{ \
name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \
dest, dstW, yalpha, uvalpha, y, fmt, hasAlpha); \
-} \
- \
+}
+
+#define YUV2RGBWRAPPER(name, base, ext, fmt, hasAlpha) \
+YUV2RGBWRAPPERX2(name, base, ext, fmt, hasAlpha) \
static void name ## ext ## _1_c(SwsContext *c, const int16_t *buf0, \
const int16_t *ubuf[2], const int16_t *vbuf[2], \
const int16_t *abuf0, uint8_t *dest, int dstW, \
@@ -1157,6 +1458,145 @@ YUV2RGBWRAPPER(yuv2rgb,, 8, AV_PIX_FMT_RGB8, 0)
YUV2RGBWRAPPER(yuv2rgb,, 4, AV_PIX_FMT_RGB4, 0)
YUV2RGBWRAPPER(yuv2rgb,, 4b, AV_PIX_FMT_RGB4_BYTE, 0)
+static av_always_inline void yuv2rgb_write_full(SwsContext *c,
+ uint8_t *dest, int i, int Y, int A, int U, int V,
+ int y, enum AVPixelFormat target, int hasAlpha, int err[4])
+{
+ int R, G, B;
+ int isrgb8 = target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8;
+
+ Y -= c->yuv2rgb_y_offset;
+ Y *= c->yuv2rgb_y_coeff;
+ Y += 1 << 21;
+ R = Y + V*c->yuv2rgb_v2r_coeff;
+ G = Y + V*c->yuv2rgb_v2g_coeff + U*c->yuv2rgb_u2g_coeff;
+ B = Y + U*c->yuv2rgb_u2b_coeff;
+ if ((R | G | B) & 0xC0000000) {
+ R = av_clip_uintp2(R, 30);
+ G = av_clip_uintp2(G, 30);
+ B = av_clip_uintp2(B, 30);
+ }
+
+ switch(target) {
+ case AV_PIX_FMT_ARGB:
+ dest[0] = hasAlpha ? A : 255;
+ dest[1] = R >> 22;
+ dest[2] = G >> 22;
+ dest[3] = B >> 22;
+ break;
+ case AV_PIX_FMT_RGB24:
+ dest[0] = R >> 22;
+ dest[1] = G >> 22;
+ dest[2] = B >> 22;
+ break;
+ case AV_PIX_FMT_RGBA:
+ dest[0] = R >> 22;
+ dest[1] = G >> 22;
+ dest[2] = B >> 22;
+ dest[3] = hasAlpha ? A : 255;
+ break;
+ case AV_PIX_FMT_ABGR:
+ dest[0] = hasAlpha ? A : 255;
+ dest[1] = B >> 22;
+ dest[2] = G >> 22;
+ dest[3] = R >> 22;
+ break;
+ case AV_PIX_FMT_BGR24:
+ dest[0] = B >> 22;
+ dest[1] = G >> 22;
+ dest[2] = R >> 22;
+ break;
+ case AV_PIX_FMT_BGRA:
+ dest[0] = B >> 22;
+ dest[1] = G >> 22;
+ dest[2] = R >> 22;
+ dest[3] = hasAlpha ? A : 255;
+ break;
+ case AV_PIX_FMT_BGR4_BYTE:
+ case AV_PIX_FMT_RGB4_BYTE:
+ case AV_PIX_FMT_BGR8:
+ case AV_PIX_FMT_RGB8:
+ {
+ int r,g,b;
+
+ switch (c->dither) {
+ default:
+ case SWS_DITHER_AUTO:
+ case SWS_DITHER_ED:
+ R >>= 22;
+ G >>= 22;
+ B >>= 22;
+ R += (7*err[0] + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2])>>4;
+ G += (7*err[1] + 1*c->dither_error[1][i] + 5*c->dither_error[1][i+1] + 3*c->dither_error[1][i+2])>>4;
+ B += (7*err[2] + 1*c->dither_error[2][i] + 5*c->dither_error[2][i+1] + 3*c->dither_error[2][i+2])>>4;
+ c->dither_error[0][i] = err[0];
+ c->dither_error[1][i] = err[1];
+ c->dither_error[2][i] = err[2];
+ r = R >> (isrgb8 ? 5 : 7);
+ g = G >> (isrgb8 ? 5 : 6);
+ b = B >> (isrgb8 ? 6 : 7);
+ r = av_clip(r, 0, isrgb8 ? 7 : 1);
+ g = av_clip(g, 0, isrgb8 ? 7 : 3);
+ b = av_clip(b, 0, isrgb8 ? 3 : 1);
+ err[0] = R - r*(isrgb8 ? 36 : 255);
+ err[1] = G - g*(isrgb8 ? 36 : 85);
+ err[2] = B - b*(isrgb8 ? 85 : 255);
+ break;
+ case SWS_DITHER_A_DITHER:
+ if (isrgb8) {
+ /* see http://pippin.gimp.org/a_dither/ for details/origin */
+#define A_DITHER(u,v) (((((u)+((v)*236))*119)&0xff))
+ r = (((R >> 19) + A_DITHER(i,y) -96)>>8);
+ g = (((G >> 19) + A_DITHER(i + 17,y) - 96)>>8);
+ b = (((B >> 20) + A_DITHER(i + 17*2,y) -96)>>8);
+ r = av_clip_uintp2(r, 3);
+ g = av_clip_uintp2(g, 3);
+ b = av_clip_uintp2(b, 2);
+ } else {
+ r = (((R >> 21) + A_DITHER(i,y)-256)>>8);
+ g = (((G >> 19) + A_DITHER(i + 17,y)-256)>>8);
+ b = (((B >> 21) + A_DITHER(i + 17*2,y)-256)>>8);
+ r = av_clip_uintp2(r, 1);
+ g = av_clip_uintp2(g, 2);
+ b = av_clip_uintp2(b, 1);
+ }
+ break;
+ case SWS_DITHER_X_DITHER:
+ if (isrgb8) {
+ /* see http://pippin.gimp.org/a_dither/ for details/origin */
+#define X_DITHER(u,v) (((((u)^((v)*237))*181)&0x1ff)/2)
+ r = (((R >> 19) + X_DITHER(i,y) - 96)>>8);
+ g = (((G >> 19) + X_DITHER(i + 17,y) - 96)>>8);
+ b = (((B >> 20) + X_DITHER(i + 17*2,y) - 96)>>8);
+ r = av_clip_uintp2(r, 3);
+ g = av_clip_uintp2(g, 3);
+ b = av_clip_uintp2(b, 2);
+ } else {
+ r = (((R >> 21) + X_DITHER(i,y)-256)>>8);
+ g = (((G >> 19) + X_DITHER(i + 17,y)-256)>>8);
+ b = (((B >> 21) + X_DITHER(i + 17*2,y)-256)>>8);
+ r = av_clip_uintp2(r, 1);
+ g = av_clip_uintp2(g, 2);
+ b = av_clip_uintp2(b, 1);
+ }
+
+ break;
+ }
+
+ if(target == AV_PIX_FMT_BGR4_BYTE) {
+ dest[0] = r + 2*g + 8*b;
+ } else if(target == AV_PIX_FMT_RGB4_BYTE) {
+ dest[0] = b + 2*g + 8*r;
+ } else if(target == AV_PIX_FMT_BGR8) {
+ dest[0] = r + 8*g + 64*b;
+ } else if(target == AV_PIX_FMT_RGB8) {
+ dest[0] = b + 4*g + 32*r;
+ } else
+ av_assert2(0);
+ break;}
+ }
+}
+
static av_always_inline void
yuv2rgb_full_X_c_template(SwsContext *c, const int16_t *lumFilter,
const int16_t **lumSrc, int lumFilterSize,
@@ -1167,13 +1607,18 @@ yuv2rgb_full_X_c_template(SwsContext *c, const int16_t *lumFilter,
{
int i;
int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 : 4;
+ int err[4] = {0};
+ int A = 0; //init to silence warning
+
+ if( target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE
+ || target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8)
+ step = 1;
for (i = 0; i < dstW; i++) {
int j;
- int Y = 0;
- int U = -128 << 19;
- int V = -128 << 19;
- int R, G, B, A;
+ int Y = 1<<9;
+ int U = (1<<9)-(128 << 19);
+ int V = (1<<9)-(128 << 19);
for (j = 0; j < lumFilterSize; j++) {
Y += lumSrc[j][i] * lumFilter[j];
@@ -1186,7 +1631,7 @@ yuv2rgb_full_X_c_template(SwsContext *c, const int16_t *lumFilter,
U >>= 10;
V >>= 10;
if (hasAlpha) {
- A = 1 << 21;
+ A = 1 << 18;
for (j = 0; j < lumFilterSize; j++) {
A += alpSrc[j][i] * lumFilter[j];
}
@@ -1194,78 +1639,136 @@ yuv2rgb_full_X_c_template(SwsContext *c, const int16_t *lumFilter,
if (A & 0x100)
A = av_clip_uint8(A);
}
- Y -= c->yuv2rgb_y_offset;
- Y *= c->yuv2rgb_y_coeff;
- Y += 1 << 21;
- R = Y + V*c->yuv2rgb_v2r_coeff;
- G = Y + V*c->yuv2rgb_v2g_coeff + U*c->yuv2rgb_u2g_coeff;
- B = Y + U*c->yuv2rgb_u2b_coeff;
- if ((R | G | B) & 0xC0000000) {
- R = av_clip_uintp2(R, 30);
- G = av_clip_uintp2(G, 30);
- B = av_clip_uintp2(B, 30);
- }
+ yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err);
+ dest += step;
+ }
+ c->dither_error[0][i] = err[0];
+ c->dither_error[1][i] = err[1];
+ c->dither_error[2][i] = err[2];
+}
- switch(target) {
- case AV_PIX_FMT_ARGB:
- dest[0] = hasAlpha ? A : 255;
- dest[1] = R >> 22;
- dest[2] = G >> 22;
- dest[3] = B >> 22;
- break;
- case AV_PIX_FMT_RGB24:
- dest[0] = R >> 22;
- dest[1] = G >> 22;
- dest[2] = B >> 22;
- break;
- case AV_PIX_FMT_RGBA:
- dest[0] = R >> 22;
- dest[1] = G >> 22;
- dest[2] = B >> 22;
- dest[3] = hasAlpha ? A : 255;
- break;
- case AV_PIX_FMT_ABGR:
- dest[0] = hasAlpha ? A : 255;
- dest[1] = B >> 22;
- dest[2] = G >> 22;
- dest[3] = R >> 22;
- dest += 4;
- break;
- case AV_PIX_FMT_BGR24:
- dest[0] = B >> 22;
- dest[1] = G >> 22;
- dest[2] = R >> 22;
- break;
- case AV_PIX_FMT_BGRA:
- dest[0] = B >> 22;
- dest[1] = G >> 22;
- dest[2] = R >> 22;
- dest[3] = hasAlpha ? A : 255;
- break;
+static av_always_inline void
+yuv2rgb_full_2_c_template(SwsContext *c, const int16_t *buf[2],
+ const int16_t *ubuf[2], const int16_t *vbuf[2],
+ const int16_t *abuf[2], uint8_t *dest, int dstW,
+ int yalpha, int uvalpha, int y,
+ enum AVPixelFormat target, int hasAlpha)
+{
+ const int16_t *buf0 = buf[0], *buf1 = buf[1],
+ *ubuf0 = ubuf[0], *ubuf1 = ubuf[1],
+ *vbuf0 = vbuf[0], *vbuf1 = vbuf[1],
+ *abuf0 = hasAlpha ? abuf[0] : NULL,
+ *abuf1 = hasAlpha ? abuf[1] : NULL;
+ int yalpha1 = 4096 - yalpha;
+ int uvalpha1 = 4096 - uvalpha;
+ int i;
+ int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 : 4;
+ int err[4] = {0};
+ int A = 0; // init to silcene warning
+
+ if( target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE
+ || target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8)
+ step = 1;
+
+ for (i = 0; i < dstW; i++) {
+ int Y = ( buf0[i] * yalpha1 + buf1[i] * yalpha ) >> 10; //FIXME rounding
+ int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha-(128 << 19)) >> 10;
+ int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha-(128 << 19)) >> 10;
+
+ if (hasAlpha) {
+ A = (abuf0[i] * yalpha1 + abuf1[i] * yalpha + (1<<18)) >> 19;
+ if (A & 0x100)
+ A = av_clip_uint8(A);
}
+
+ yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err);
dest += step;
}
+ c->dither_error[0][i] = err[0];
+ c->dither_error[1][i] = err[1];
+ c->dither_error[2][i] = err[2];
+}
+
+static av_always_inline void
+yuv2rgb_full_1_c_template(SwsContext *c, const int16_t *buf0,
+ const int16_t *ubuf[2], const int16_t *vbuf[2],
+ const int16_t *abuf0, uint8_t *dest, int dstW,
+ int uvalpha, int y, enum AVPixelFormat target,
+ int hasAlpha)
+{
+ const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0];
+ int i;
+ int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 : 4;
+ int err[4] = {0};
+
+ if( target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE
+ || target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8)
+ step = 1;
+
+ if (uvalpha < 2048) {
+ int A = 0; //init to silence warning
+ for (i = 0; i < dstW; i++) {
+ int Y = buf0[i] << 2;
+ int U = (ubuf0[i] - (128<<7)) * 4;
+ int V = (vbuf0[i] - (128<<7)) * 4;
+
+ if (hasAlpha) {
+ A = (abuf0[i] + 64) >> 7;
+ if (A & 0x100)
+ A = av_clip_uint8(A);
+ }
+
+ yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err);
+ dest += step;
+ }
+ } else {
+ const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1];
+ int A = 0; //init to silence warning
+ for (i = 0; i < dstW; i++) {
+ int Y = buf0[i] << 2;
+ int U = (ubuf0[i] + ubuf1[i] - (128<<8)) << 1;
+ int V = (vbuf0[i] + vbuf1[i] - (128<<8)) << 1;
+
+ if (hasAlpha) {
+ A = (abuf0[i] + 64) >> 7;
+ if (A & 0x100)
+ A = av_clip_uint8(A);
+ }
+
+ yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err);
+ dest += step;
+ }
+ }
+
+ c->dither_error[0][i] = err[0];
+ c->dither_error[1][i] = err[1];
+ c->dither_error[2][i] = err[2];
}
#if CONFIG_SMALL
-YUV2RGBWRAPPERX(yuv2, rgb_full, bgra32_full, AV_PIX_FMT_BGRA, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
-YUV2RGBWRAPPERX(yuv2, rgb_full, abgr32_full, AV_PIX_FMT_ABGR, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
-YUV2RGBWRAPPERX(yuv2, rgb_full, rgba32_full, AV_PIX_FMT_RGBA, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
-YUV2RGBWRAPPERX(yuv2, rgb_full, argb32_full, AV_PIX_FMT_ARGB, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
+YUV2RGBWRAPPER(yuv2, rgb_full, bgra32_full, AV_PIX_FMT_BGRA, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
+YUV2RGBWRAPPER(yuv2, rgb_full, abgr32_full, AV_PIX_FMT_ABGR, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
+YUV2RGBWRAPPER(yuv2, rgb_full, rgba32_full, AV_PIX_FMT_RGBA, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
+YUV2RGBWRAPPER(yuv2, rgb_full, argb32_full, AV_PIX_FMT_ARGB, CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
#else
#if CONFIG_SWSCALE_ALPHA
-YUV2RGBWRAPPERX(yuv2, rgb_full, bgra32_full, AV_PIX_FMT_BGRA, 1)
-YUV2RGBWRAPPERX(yuv2, rgb_full, abgr32_full, AV_PIX_FMT_ABGR, 1)
-YUV2RGBWRAPPERX(yuv2, rgb_full, rgba32_full, AV_PIX_FMT_RGBA, 1)
-YUV2RGBWRAPPERX(yuv2, rgb_full, argb32_full, AV_PIX_FMT_ARGB, 1)
+YUV2RGBWRAPPER(yuv2, rgb_full, bgra32_full, AV_PIX_FMT_BGRA, 1)
+YUV2RGBWRAPPER(yuv2, rgb_full, abgr32_full, AV_PIX_FMT_ABGR, 1)
+YUV2RGBWRAPPER(yuv2, rgb_full, rgba32_full, AV_PIX_FMT_RGBA, 1)
+YUV2RGBWRAPPER(yuv2, rgb_full, argb32_full, AV_PIX_FMT_ARGB, 1)
#endif
-YUV2RGBWRAPPERX(yuv2, rgb_full, bgrx32_full, AV_PIX_FMT_BGRA, 0)
-YUV2RGBWRAPPERX(yuv2, rgb_full, xbgr32_full, AV_PIX_FMT_ABGR, 0)
-YUV2RGBWRAPPERX(yuv2, rgb_full, rgbx32_full, AV_PIX_FMT_RGBA, 0)
-YUV2RGBWRAPPERX(yuv2, rgb_full, xrgb32_full, AV_PIX_FMT_ARGB, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, bgrx32_full, AV_PIX_FMT_BGRA, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, xbgr32_full, AV_PIX_FMT_ABGR, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, rgbx32_full, AV_PIX_FMT_RGBA, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, xrgb32_full, AV_PIX_FMT_ARGB, 0)
#endif
-YUV2RGBWRAPPERX(yuv2, rgb_full, bgr24_full, AV_PIX_FMT_BGR24, 0)
-YUV2RGBWRAPPERX(yuv2, rgb_full, rgb24_full, AV_PIX_FMT_RGB24, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, bgr24_full, AV_PIX_FMT_BGR24, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, rgb24_full, AV_PIX_FMT_RGB24, 0)
+
+YUV2RGBWRAPPER(yuv2, rgb_full, bgr4_byte_full, AV_PIX_FMT_BGR4_BYTE, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, rgb4_byte_full, AV_PIX_FMT_RGB4_BYTE, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, bgr8_full, AV_PIX_FMT_BGR8, 0)
+YUV2RGBWRAPPER(yuv2, rgb_full, rgb8_full, AV_PIX_FMT_RGB8, 0)
static void
yuv2gbrp_full_X_c(SwsContext *c, const int16_t *lumFilter,
@@ -1280,13 +1783,14 @@ yuv2gbrp_full_X_c(SwsContext *c, const int16_t *lumFilter,
int hasAlpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpSrc;
uint16_t **dest16 = (uint16_t**)dest;
int SH = 22 + 7 - desc->comp[0].depth_minus1;
+ int A = 0; // init to silence warning
for (i = 0; i < dstW; i++) {
int j;
int Y = 1 << 9;
int U = (1 << 9) - (128 << 19);
int V = (1 << 9) - (128 << 19);
- int R, G, B, A;
+ int R, G, B;
for (j = 0; j < lumFilterSize; j++)
Y += lumSrc[j][i] * lumFilter[j];
@@ -1369,10 +1873,17 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c,
if (desc->comp[0].depth_minus1 == 8) {
*yuv2planeX = isBE(dstFormat) ? yuv2planeX_9BE_c : yuv2planeX_9LE_c;
*yuv2plane1 = isBE(dstFormat) ? yuv2plane1_9BE_c : yuv2plane1_9LE_c;
- } else {
+ } else if (desc->comp[0].depth_minus1 == 9) {
*yuv2planeX = isBE(dstFormat) ? yuv2planeX_10BE_c : yuv2planeX_10LE_c;
*yuv2plane1 = isBE(dstFormat) ? yuv2plane1_10BE_c : yuv2plane1_10LE_c;
- }
+ } else if (desc->comp[0].depth_minus1 == 11) {
+ *yuv2planeX = isBE(dstFormat) ? yuv2planeX_12BE_c : yuv2planeX_12LE_c;
+ *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_12BE_c : yuv2plane1_12LE_c;
+ } else if (desc->comp[0].depth_minus1 == 13) {
+ *yuv2planeX = isBE(dstFormat) ? yuv2planeX_14BE_c : yuv2planeX_14LE_c;
+ *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_14BE_c : yuv2plane1_14LE_c;
+ } else
+ av_assert0(0);
} else {
*yuv2plane1 = yuv2plane1_8_c;
*yuv2planeX = yuv2planeX_8_c;
@@ -1385,78 +1896,189 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c,
case AV_PIX_FMT_RGBA:
#if CONFIG_SMALL
*yuv2packedX = yuv2rgba32_full_X_c;
+ *yuv2packed2 = yuv2rgba32_full_2_c;
+ *yuv2packed1 = yuv2rgba32_full_1_c;
#else
#if CONFIG_SWSCALE_ALPHA
if (c->alpPixBuf) {
*yuv2packedX = yuv2rgba32_full_X_c;
+ *yuv2packed2 = yuv2rgba32_full_2_c;
+ *yuv2packed1 = yuv2rgba32_full_1_c;
} else
#endif /* CONFIG_SWSCALE_ALPHA */
{
*yuv2packedX = yuv2rgbx32_full_X_c;
+ *yuv2packed2 = yuv2rgbx32_full_2_c;
+ *yuv2packed1 = yuv2rgbx32_full_1_c;
}
#endif /* !CONFIG_SMALL */
break;
case AV_PIX_FMT_ARGB:
#if CONFIG_SMALL
*yuv2packedX = yuv2argb32_full_X_c;
+ *yuv2packed2 = yuv2argb32_full_2_c;
+ *yuv2packed1 = yuv2argb32_full_1_c;
#else
#if CONFIG_SWSCALE_ALPHA
if (c->alpPixBuf) {
*yuv2packedX = yuv2argb32_full_X_c;
+ *yuv2packed2 = yuv2argb32_full_2_c;
+ *yuv2packed1 = yuv2argb32_full_1_c;
} else
#endif /* CONFIG_SWSCALE_ALPHA */
{
*yuv2packedX = yuv2xrgb32_full_X_c;
+ *yuv2packed2 = yuv2xrgb32_full_2_c;
+ *yuv2packed1 = yuv2xrgb32_full_1_c;
}
#endif /* !CONFIG_SMALL */
break;
case AV_PIX_FMT_BGRA:
#if CONFIG_SMALL
*yuv2packedX = yuv2bgra32_full_X_c;
+ *yuv2packed2 = yuv2bgra32_full_2_c;
+ *yuv2packed1 = yuv2bgra32_full_1_c;
#else
#if CONFIG_SWSCALE_ALPHA
if (c->alpPixBuf) {
*yuv2packedX = yuv2bgra32_full_X_c;
+ *yuv2packed2 = yuv2bgra32_full_2_c;
+ *yuv2packed1 = yuv2bgra32_full_1_c;
} else
#endif /* CONFIG_SWSCALE_ALPHA */
{
*yuv2packedX = yuv2bgrx32_full_X_c;
+ *yuv2packed2 = yuv2bgrx32_full_2_c;
+ *yuv2packed1 = yuv2bgrx32_full_1_c;
}
#endif /* !CONFIG_SMALL */
break;
case AV_PIX_FMT_ABGR:
#if CONFIG_SMALL
*yuv2packedX = yuv2abgr32_full_X_c;
+ *yuv2packed2 = yuv2abgr32_full_2_c;
+ *yuv2packed1 = yuv2abgr32_full_1_c;
#else
#if CONFIG_SWSCALE_ALPHA
if (c->alpPixBuf) {
*yuv2packedX = yuv2abgr32_full_X_c;
+ *yuv2packed2 = yuv2abgr32_full_2_c;
+ *yuv2packed1 = yuv2abgr32_full_1_c;
} else
#endif /* CONFIG_SWSCALE_ALPHA */
{
*yuv2packedX = yuv2xbgr32_full_X_c;
+ *yuv2packed2 = yuv2xbgr32_full_2_c;
+ *yuv2packed1 = yuv2xbgr32_full_1_c;
}
#endif /* !CONFIG_SMALL */
break;
case AV_PIX_FMT_RGB24:
*yuv2packedX = yuv2rgb24_full_X_c;
+ *yuv2packed2 = yuv2rgb24_full_2_c;
+ *yuv2packed1 = yuv2rgb24_full_1_c;
break;
case AV_PIX_FMT_BGR24:
*yuv2packedX = yuv2bgr24_full_X_c;
+ *yuv2packed2 = yuv2bgr24_full_2_c;
+ *yuv2packed1 = yuv2bgr24_full_1_c;
+ break;
+ case AV_PIX_FMT_BGR4_BYTE:
+ *yuv2packedX = yuv2bgr4_byte_full_X_c;
+ *yuv2packed2 = yuv2bgr4_byte_full_2_c;
+ *yuv2packed1 = yuv2bgr4_byte_full_1_c;
+ break;
+ case AV_PIX_FMT_RGB4_BYTE:
+ *yuv2packedX = yuv2rgb4_byte_full_X_c;
+ *yuv2packed2 = yuv2rgb4_byte_full_2_c;
+ *yuv2packed1 = yuv2rgb4_byte_full_1_c;
+ break;
+ case AV_PIX_FMT_BGR8:
+ *yuv2packedX = yuv2bgr8_full_X_c;
+ *yuv2packed2 = yuv2bgr8_full_2_c;
+ *yuv2packed1 = yuv2bgr8_full_1_c;
+ break;
+ case AV_PIX_FMT_RGB8:
+ *yuv2packedX = yuv2rgb8_full_X_c;
+ *yuv2packed2 = yuv2rgb8_full_2_c;
+ *yuv2packed1 = yuv2rgb8_full_1_c;
break;
case AV_PIX_FMT_GBRP:
case AV_PIX_FMT_GBRP9BE:
case AV_PIX_FMT_GBRP9LE:
case AV_PIX_FMT_GBRP10BE:
case AV_PIX_FMT_GBRP10LE:
+ case AV_PIX_FMT_GBRP12BE:
+ case AV_PIX_FMT_GBRP12LE:
+ case AV_PIX_FMT_GBRP14BE:
+ case AV_PIX_FMT_GBRP14LE:
case AV_PIX_FMT_GBRP16BE:
case AV_PIX_FMT_GBRP16LE:
case AV_PIX_FMT_GBRAP:
*yuv2anyX = yuv2gbrp_full_X_c;
break;
}
+ if (!*yuv2packedX && !*yuv2anyX)
+ goto YUV_PACKED;
} else {
+ YUV_PACKED:
switch (dstFormat) {
+ case AV_PIX_FMT_RGBA64LE:
+#if CONFIG_SWSCALE_ALPHA
+ if (c->alpPixBuf) {
+ *yuv2packed1 = yuv2rgba64le_1_c;
+ *yuv2packed2 = yuv2rgba64le_2_c;
+ *yuv2packedX = yuv2rgba64le_X_c;
+ } else
+#endif /* CONFIG_SWSCALE_ALPHA */
+ {
+ *yuv2packed1 = yuv2rgbx64le_1_c;
+ *yuv2packed2 = yuv2rgbx64le_2_c;
+ *yuv2packedX = yuv2rgbx64le_X_c;
+ }
+ break;
+ case AV_PIX_FMT_RGBA64BE:
+#if CONFIG_SWSCALE_ALPHA
+ if (c->alpPixBuf) {
+ *yuv2packed1 = yuv2rgba64be_1_c;
+ *yuv2packed2 = yuv2rgba64be_2_c;
+ *yuv2packedX = yuv2rgba64be_X_c;
+ } else
+#endif /* CONFIG_SWSCALE_ALPHA */
+ {
+ *yuv2packed1 = yuv2rgbx64be_1_c;
+ *yuv2packed2 = yuv2rgbx64be_2_c;
+ *yuv2packedX = yuv2rgbx64be_X_c;
+ }
+ break;
+ case AV_PIX_FMT_BGRA64LE:
+#if CONFIG_SWSCALE_ALPHA
+ if (c->alpPixBuf) {
+ *yuv2packed1 = yuv2bgra64le_1_c;
+ *yuv2packed2 = yuv2bgra64le_2_c;
+ *yuv2packedX = yuv2bgra64le_X_c;
+ } else
+#endif /* CONFIG_SWSCALE_ALPHA */
+ {
+ *yuv2packed1 = yuv2bgrx64le_1_c;
+ *yuv2packed2 = yuv2bgrx64le_2_c;
+ *yuv2packedX = yuv2bgrx64le_X_c;
+ }
+ break;
+ case AV_PIX_FMT_BGRA64BE:
+#if CONFIG_SWSCALE_ALPHA
+ if (c->alpPixBuf) {
+ *yuv2packed1 = yuv2bgra64be_1_c;
+ *yuv2packed2 = yuv2bgra64be_2_c;
+ *yuv2packedX = yuv2bgra64be_X_c;
+ } else
+#endif /* CONFIG_SWSCALE_ALPHA */
+ {
+ *yuv2packed1 = yuv2bgrx64be_1_c;
+ *yuv2packed2 = yuv2bgrx64be_2_c;
+ *yuv2packedX = yuv2bgrx64be_X_c;
+ }
+ break;
case AV_PIX_FMT_RGB48LE:
*yuv2packed1 = yuv2rgb48le_1_c;
*yuv2packed2 = yuv2rgb48le_2_c;
diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c
index 7e00488a61..af9fc88ec0 100644
--- a/libswscale/ppc/swscale_altivec.c
+++ b/libswscale/ppc/swscale_altivec.c
@@ -4,20 +4,20 @@
* Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
* based on the equivalent C code in swscale.c
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -29,28 +29,61 @@
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
#include "yuv2rgb_altivec.h"
+#include "libavutil/ppc/util_altivec.h"
#if HAVE_ALTIVEC
#define vzero vec_splat_s32(0)
-#define yuv2planeX_8(d1, d2, l1, src, x, perm, filter) do { \
- vector signed short l2 = vec_ld(((x) << 1) + 16, src); \
- vector signed short ls = vec_perm(l1, l2, perm); \
- vector signed int i1 = vec_mule(filter, ls); \
- vector signed int i2 = vec_mulo(filter, ls); \
- vector signed int vf1 = vec_mergeh(i1, i2); \
- vector signed int vf2 = vec_mergel(i1, i2); \
- d1 = vec_add(d1, vf1); \
- d2 = vec_add(d2, vf2); \
- l1 = l2; \
+#if HAVE_BIGENDIAN
+#define GET_LS(a,b,c,s) {\
+ vector signed short l2 = vec_ld(((b) << 1) + 16, s);\
+ ls = vec_perm(a, l2, c);\
+ a = l2;\
+ }
+#else
+#define GET_LS(a,b,c,s) {\
+ ls = a;\
+ a = vec_vsx_ld(((b) << 1) + 16, s);\
+ }
+#endif
+
+#define yuv2planeX_8(d1, d2, l1, src, x, perm, filter) do {\
+ vector signed short ls;\
+ GET_LS(l1, x, perm, src);\
+ vector signed int i1 = vec_mule(filter, ls);\
+ vector signed int i2 = vec_mulo(filter, ls);\
+ vector signed int vf1, vf2;\
+ vf1 = vec_mergeh(i1, i2);\
+ vf2 = vec_mergel(i1, i2);\
+ d1 = vec_add(d1, vf1);\
+ d2 = vec_add(d2, vf2);\
} while (0)
+#if HAVE_BIGENDIAN
+#define LOAD_FILTER(vf,f) {\
+ vector unsigned char perm0 = vec_lvsl(joffset, f);\
+ vf = vec_ld(joffset, f);\
+ vf = vec_perm(vf, vf, perm0);\
+}
+#define LOAD_L1(ll1,s,p){\
+ p = vec_lvsl(xoffset, s);\
+ ll1 = vec_ld(xoffset, s);\
+}
+#else
+#define LOAD_FILTER(vf,f) {\
+ vf = vec_vsx_ld(joffset, f);\
+}
+#define LOAD_L1(ll1,s,p){\
+ ll1 = vec_vsx_ld(xoffset, s);\
+}
+#endif
+
static void yuv2planeX_16_altivec(const int16_t *filter, int filterSize,
const int16_t **src, uint8_t *dest,
const uint8_t *dither, int offset, int x)
{
register int i, j;
- DECLARE_ALIGNED(16, int, val)[16];
+ LOCAL_ALIGNED(16, int, val, [16]);
vector signed int vo1, vo2, vo3, vo4;
vector unsigned short vs1, vs2;
vector unsigned char vf;
@@ -66,14 +99,13 @@ static void yuv2planeX_16_altivec(const int16_t *filter, int filterSize,
vo4 = vec_ld(48, val);
for (j = 0; j < filterSize; j++) {
- vector signed short l1, vLumFilter = vec_ld(j << 1, filter);
- vector unsigned char perm, perm0 = vec_lvsl(j << 1, filter);
- vLumFilter = vec_perm(vLumFilter, vLumFilter, perm0);
- vLumFilter = vec_splat(vLumFilter, 0); // lumFilter[j] is loaded 8 times in vLumFilter
-
- perm = vec_lvsl(x << 1, src[j]);
- l1 = vec_ld(x << 1, src[j]);
-
+ unsigned int joffset=j<<1;
+ unsigned int xoffset=x<<1;
+ vector unsigned char perm;
+ vector signed short l1,vLumFilter;
+ LOAD_FILTER(vLumFilter,filter);
+ vLumFilter = vec_splat(vLumFilter, 0);
+ LOAD_L1(l1,src[j],perm);
yuv2planeX_8(vo1, vo2, l1, src[j], x, perm, vLumFilter);
yuv2planeX_8(vo3, vo4, l1, src[j], x + 8, perm, vLumFilter);
}
@@ -85,9 +117,10 @@ static void yuv2planeX_16_altivec(const int16_t *filter, int filterSize,
vs1 = vec_packsu(vo1, vo2);
vs2 = vec_packsu(vo3, vo4);
vf = vec_packsu(vs1, vs2);
- vec_st(vf, 0, dest);
+ VEC_ST(vf, 0, dest);
}
+
static inline void yuv2planeX_u(const int16_t *filter, int filterSize,
const int16_t **src, uint8_t *dest, int dstW,
const uint8_t *dither, int offset, int x)
@@ -118,12 +151,64 @@ static void yuv2planeX_altivec(const int16_t *filter, int filterSize,
yuv2planeX_u(filter, filterSize, src, dest, dstW, dither, offset, i);
}
+#if HAVE_BIGENDIAN
+// The 3 above is 2 (filterSize == 4) + 1 (sizeof(short) == 2).
+
+// The neat trick: We only care for half the elements,
+// high or low depending on (i<<3)%16 (it's 0 or 8 here),
+// and we're going to use vec_mule, so we choose
+// carefully how to "unpack" the elements into the even slots.
+#define GET_VF4(a, vf, f) {\
+ vf = vec_ld(a<< 3, f);\
+ if ((a << 3) % 16)\
+ vf = vec_mergel(vf, (vector signed short)vzero);\
+ else\
+ vf = vec_mergeh(vf, (vector signed short)vzero);\
+}
+#define FIRST_LOAD(sv, pos, s, per) {\
+ sv = vec_ld(pos, s);\
+ per = vec_lvsl(pos, s);\
+}
+#define UPDATE_PTR(s0, d0, s1, d1) {\
+ d0 = s0;\
+ d1 = s1;\
+}
+#define LOAD_SRCV(pos, a, s, per, v0, v1, vf) {\
+ v1 = vec_ld(pos + a + 16, s);\
+ vf = vec_perm(v0, v1, per);\
+}
+#define LOAD_SRCV8(pos, a, s, per, v0, v1, vf) {\
+ if ((((uintptr_t)s + pos) % 16) > 8) {\
+ v1 = vec_ld(pos + a + 16, s);\
+ }\
+ vf = vec_perm(v0, src_v1, per);\
+}
+#define GET_VFD(a, b, f, vf0, vf1, per, vf, off) {\
+ vf1 = vec_ld((a * 2 * filterSize) + (b * 2) + 16 + off, f);\
+ vf = vec_perm(vf0, vf1, per);\
+}
+#else /* else of #if HAVE_BIGENDIAN */
+#define GET_VF4(a, vf, f) {\
+ vf = (vector signed short)vec_vsx_ld(a << 3, f);\
+ vf = vec_mergeh(vf, (vector signed short)vzero);\
+}
+#define FIRST_LOAD(sv, pos, s, per) {}
+#define UPDATE_PTR(s0, d0, s1, d1) {}
+#define LOAD_SRCV(pos, a, s, per, v0, v1, vf) {\
+ vf = vec_vsx_ld(pos + a, s);\
+}
+#define LOAD_SRCV8(pos, a, s, per, v0, v1, vf) LOAD_SRCV(pos, a, s, per, v0, v1, vf)
+#define GET_VFD(a, b, f, vf0, vf1, per, vf, off) {\
+ vf = vec_vsx_ld((a * 2 * filterSize) + (b * 2) + off, f);\
+}
+#endif /* end of #if HAVE_BIGENDIAN */
+
static void hScale_altivec_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;
- DECLARE_ALIGNED(16, int, tempo)[4];
+ LOCAL_ALIGNED(16, int, tempo, [4]);
if (filterSize % 4) {
for (i = 0; i < dstW; i++) {
@@ -140,57 +225,32 @@ static void hScale_altivec_real(SwsContext *c, int16_t *dst, int dstW,
for (i = 0; i < dstW; i++) {
register int srcPos = filterPos[i];
- vector unsigned char src_v0 = vec_ld(srcPos, src);
- vector unsigned char src_v1, src_vF;
+ vector unsigned char src_vF = unaligned_load(srcPos, src);
vector signed short src_v, filter_v;
vector signed int val_vEven, val_s;
- if ((((uintptr_t)src + srcPos) % 16) > 12) {
- src_v1 = vec_ld(srcPos + 16, src);
- }
- src_vF = vec_perm(src_v0, src_v1, vec_lvsl(srcPos, src));
-
src_v = // vec_unpackh sign-extends...
- (vector signed short)(vec_mergeh((vector unsigned char)vzero, src_vF));
+ (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);
-
- filter_v = vec_ld(i << 3, filter);
- // The 3 above is 2 (filterSize == 4) + 1 (sizeof(short) == 2).
-
- // The neat trick: We only care for half the elements,
- // high or low depending on (i<<3)%16 (it's 0 or 8 here),
- // and we're going to use vec_mule, so we choose
- // carefully how to "unpack" the elements into the even slots.
- if ((i << 3) % 16)
- filter_v = vec_mergel(filter_v, (vector signed short)vzero);
- else
- filter_v = vec_mergeh(filter_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_v0 = vec_ld(srcPos, src);
- vector unsigned char src_v1, src_vF;
+ vector unsigned char src_vF, src_v0, src_v1;
+ vector unsigned char permS;
vector signed short src_v, filter_v;
vector signed int val_v, val_s;
- if ((((uintptr_t)src + srcPos) % 16) > 8) {
- src_v1 = vec_ld(srcPos + 16, src);
- }
- src_vF = vec_perm(src_v0, src_v1, vec_lvsl(srcPos, src));
-
+ 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));
+ (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF));
filter_v = vec_ld(i << 4, filter);
- // the 4 above is 3 (filterSize == 8) + 1 (sizeof(short) == 2)
-
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);
@@ -202,85 +262,64 @@ static void hScale_altivec_real(SwsContext *c, int16_t *dst, int dstW,
for (i = 0; i < dstW; i++) {
register int srcPos = filterPos[i];
- vector unsigned char src_v0 = vec_ld(srcPos, src);
- vector unsigned char src_v1 = vec_ld(srcPos + 16, src);
- vector unsigned char src_vF = vec_perm(src_v0, src_v1, vec_lvsl(srcPos, src));
-
+ 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)(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)(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);
- // the 5 above are 4 (filterSize == 16) + 1 (sizeof(short) == 2)
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);
+ 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;
+ register int j, offset = i * 2 * filterSize;
register int srcPos = filterPos[i];
vector signed int val_s, val_v = (vector signed int)vzero;
- vector signed short filter_v0R = vec_ld(i * 2 * filterSize, filter);
- vector unsigned char permF = vec_lvsl((i * 2 * filterSize), filter);
-
- vector unsigned char src_v0 = vec_ld(srcPos, src);
- vector unsigned char permS = vec_lvsl(srcPos, src);
+ vector signed short filter_v0R;
+ vector unsigned char permF, src_v0, 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 src_v1 = vec_ld(srcPos + j + 16, src);
- vector unsigned char src_vF = vec_perm(src_v0, src_v1, permS);
-
+ vector unsigned char src_v1, src_vF;
+ vector signed short filter_v1R, filter_v2R, filter_v0, filter_v1;
+ LOAD_SRCV(srcPos, j, src, permS, src_v0, src_v1, src_vF);
vector signed short src_vA = // vec_unpackh sign-extends...
- (vector signed short)(vec_mergeh((vector unsigned char)vzero, src_vF));
+ (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_v1R = vec_ld((i * 2 * filterSize) + (j * 2) + 16, filter);
- vector signed short filter_v2R = vec_ld((i * 2 * filterSize) + (j * 2) + 32, filter);
- vector signed short filter_v0 = vec_perm(filter_v0R, filter_v1R, permF);
- vector signed short filter_v1 = vec_perm(filter_v1R, filter_v2R, permF);
+ (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);
vector signed int val_acc = vec_msums(src_vA, filter_v0, val_v);
val_v = vec_msums(src_vB, filter_v1, val_acc);
-
- filter_v0R = filter_v2R;
- src_v0 = src_v1;
+ 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 src_v0 = vec_ld(srcPos + j, src);
vector unsigned char src_v1, src_vF;
vector signed short src_v, filter_v1R, filter_v;
- if ((((uintptr_t)src + srcPos) % 16) > 8) {
- src_v1 = vec_ld(srcPos + j + 16, src);
- }
- src_vF = vec_perm(src_v0, src_v1, permS);
-
+ 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));
- // loading filter_v0R is useless, it's already done above
- // vector signed short filter_v0R = vec_ld((i * 2 * filterSize) + j, filter);
- filter_v1R = vec_ld((i * 2 * filterSize) + (j * 2) + 16, filter);
- filter_v = vec_perm(filter_v0R, filter_v1R, permF);
-
+ (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);
+ VEC_ST(val_s, 0, tempo);
dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1);
}
}
@@ -295,7 +334,7 @@ av_cold void ff_sws_init_swscale_ppc(SwsContext *c)
if (!(av_get_cpu_flags() & AV_CPU_FLAG_ALTIVEC))
return;
- if (c->srcBpc == 8 && c->dstBpc <= 10) {
+ if (c->srcBpc == 8 && c->dstBpc <= 14) {
c->hyScale = c->hcScale = hScale_altivec_real;
}
if (!is16BPS(dstFormat) && !is9_OR_10BPS(dstFormat) &&
diff --git a/libswscale/ppc/yuv2rgb_altivec.c b/libswscale/ppc/yuv2rgb_altivec.c
index 74b0f18190..25282bf100 100644
--- a/libswscale/ppc/yuv2rgb_altivec.c
+++ b/libswscale/ppc/yuv2rgb_altivec.c
@@ -3,20 +3,20 @@
*
* copyright (C) 2004 Marc Hoffman <marc.hoffman@analog.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -97,6 +97,7 @@
#include "libswscale/swscale_internal.h"
#include "libavutil/attributes.h"
#include "libavutil/cpu.h"
+#include "libavutil/pixdesc.h"
#include "yuv2rgb_altivec.h"
#if HAVE_ALTIVEC
@@ -317,12 +318,7 @@ static int altivec_ ## name(SwsContext *c, const unsigned char **in, \
const ubyte *ui = in[1]; \
const ubyte *vi = in[2]; \
\
- vector unsigned char *oute = \
- (vector unsigned char *) \
- (oplanes[0] + srcSliceY * outstrides[0]); \
- vector unsigned char *outo = \
- (vector unsigned char *) \
- (oplanes[0] + srcSliceY * outstrides[0] + outstrides[0]); \
+ vector unsigned char *oute, *outo; \
\
/* loop moves y{1, 2}i by w */ \
instrides_scl[0] = instrides[0] * 2 - w; \
@@ -332,6 +328,9 @@ static int altivec_ ## name(SwsContext *c, const unsigned char **in, \
instrides_scl[2] = instrides[2] - w / 2; \
\
for (i = 0; i < h / 2; i++) { \
+ oute = (vector unsigned char *)(oplanes[0] + outstrides[0] * \
+ (srcSliceY + i * 2)); \
+ outo = oute + (outstrides[0] >> 4); \
vec_dstst(outo, (0x02000002 | (((w * 3 + 32) / 32) << 16)), 0); \
vec_dstst(oute, (0x02000002 | (((w * 3 + 32) / 32) << 16)), 1); \
\
@@ -429,9 +428,6 @@ static int altivec_ ## name(SwsContext *c, const unsigned char **in, \
vi += 8; \
} \
\
- outo += (outstrides[0]) >> 4; \
- oute += (outstrides[0]) >> 4; \
- \
ui += instrides_scl[1]; \
vi += instrides_scl[2]; \
y1i += instrides_scl[0]; \
@@ -748,7 +744,7 @@ static av_always_inline void yuv2packedX_altivec(SwsContext *c,
if (!printed_error_message) {
av_log(c, AV_LOG_ERROR,
"altivec_yuv2packedX doesn't support %s output\n",
- sws_format_name(c->dstFormat));
+ av_get_pix_fmt_name(c->dstFormat));
printed_error_message = 1;
}
return;
@@ -836,7 +832,7 @@ static av_always_inline void yuv2packedX_altivec(SwsContext *c,
/* Unreachable, I think. */
av_log(c, AV_LOG_ERROR,
"altivec_yuv2packedX doesn't support %s output\n",
- sws_format_name(c->dstFormat));
+ av_get_pix_fmt_name(c->dstFormat));
return;
}
diff --git a/libswscale/ppc/yuv2rgb_altivec.h b/libswscale/ppc/yuv2rgb_altivec.h
index 2c5e7ed876..aa52a4743e 100644
--- a/libswscale/ppc/yuv2rgb_altivec.h
+++ b/libswscale/ppc/yuv2rgb_altivec.h
@@ -4,20 +4,20 @@
* Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
* based on the equivalent C code in swscale.c
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libswscale/ppc/yuv2yuv_altivec.c b/libswscale/ppc/yuv2yuv_altivec.c
index 08545b3c5d..2b1c5dd3b8 100644
--- a/libswscale/ppc/yuv2yuv_altivec.c
+++ b/libswscale/ppc/yuv2yuv_altivec.c
@@ -4,20 +4,20 @@
* Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
* based on the equivalent C code in swscale.c
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libswscale/rgb2rgb.c b/libswscale/rgb2rgb.c
index 3fb3921740..5b1fcf73ca 100644
--- a/libswscale/rgb2rgb.c
+++ b/libswscale/rgb2rgb.c
@@ -6,20 +6,20 @@
* Written by Nick Kurshev.
* palette & YUV & runtime CPU stuff by Michael (michaelni@gmx.at)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -73,10 +73,11 @@ void (*yuy2toyv12)(const uint8_t *src, uint8_t *ydst,
uint8_t *udst, uint8_t *vdst,
int width, int height,
int lumStride, int chromStride, int srcStride);
-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);
+void (*ff_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);
void (*planar2x)(const uint8_t *src, uint8_t *dst, int width, int height,
int srcStride, int dstStride);
void (*interleaveBytes)(const uint8_t *src1, const uint8_t *src2, uint8_t *dst,
@@ -108,7 +109,6 @@ void (*yuyvtoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
const uint8_t *src, int width, int height,
int lumStride, int chromStride, int srcStride);
-#define RGB2YUV_SHIFT 8
#define BY ((int)( 0.098 * (1 << RGB2YUV_SHIFT) + 0.5))
#define BV ((int)(-0.071 * (1 << RGB2YUV_SHIFT) + 0.5))
#define BU ((int)( 0.439 * (1 << RGB2YUV_SHIFT) + 0.5))
@@ -184,13 +184,13 @@ void rgb16tobgr32(const uint8_t *src, uint8_t *dst, int src_size)
register uint16_t bgr = *s++;
#if HAVE_BIGENDIAN
*d++ = 255;
- *d++ = (bgr & 0x1F) << 3;
- *d++ = (bgr & 0x7E0) >> 3;
- *d++ = (bgr & 0xF800) >> 8;
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
+ *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9);
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
#else
- *d++ = (bgr & 0xF800) >> 8;
- *d++ = (bgr & 0x7E0) >> 3;
- *d++ = (bgr & 0x1F) << 3;
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
+ *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9);
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
*d++ = 255;
#endif
}
@@ -223,9 +223,9 @@ void rgb16to24(const uint8_t *src, uint8_t *dst, int src_size)
while (s < end) {
register uint16_t bgr = *s++;
- *d++ = (bgr & 0xF800) >> 8;
- *d++ = (bgr & 0x7E0) >> 3;
- *d++ = (bgr & 0x1F) << 3;
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
+ *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9);
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
}
}
@@ -259,13 +259,13 @@ void rgb15tobgr32(const uint8_t *src, uint8_t *dst, int src_size)
register uint16_t bgr = *s++;
#if HAVE_BIGENDIAN
*d++ = 255;
- *d++ = (bgr & 0x1F) << 3;
- *d++ = (bgr & 0x3E0) >> 2;
- *d++ = (bgr & 0x7C00) >> 7;
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
+ *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7);
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
#else
- *d++ = (bgr & 0x7C00) >> 7;
- *d++ = (bgr & 0x3E0) >> 2;
- *d++ = (bgr & 0x1F) << 3;
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
+ *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7);
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
*d++ = 255;
#endif
}
@@ -279,9 +279,9 @@ void rgb15to24(const uint8_t *src, uint8_t *dst, int src_size)
while (s < end) {
register uint16_t bgr = *s++;
- *d++ = (bgr & 0x7C00) >> 7;
- *d++ = (bgr & 0x3E0) >> 2;
- *d++ = (bgr & 0x1F) << 3;
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
+ *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7);
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
}
}
@@ -318,18 +318,6 @@ void rgb12tobgr12(const uint8_t *src, uint8_t *dst, int src_size)
}
}
-void bgr8torgb8(const uint8_t *src, uint8_t *dst, int src_size)
-{
- int i, num_pixels = src_size;
-
- for (i = 0; i < num_pixels; i++) {
- register uint8_t rgb = src[i];
- unsigned r = (rgb & 0x07);
- unsigned g = (rgb & 0x38) >> 3;
- unsigned b = (rgb & 0xC0) >> 6;
- dst[i] = ((b << 1) & 0x07) | ((g & 0x07) << 3) | ((r & 0x03) << 6);
- }
-}
#define DEFINE_SHUFFLE_BYTES(a, b, c, d) \
void shuffle_bytes_ ## a ## b ## c ## d(const uint8_t *src, \
@@ -349,3 +337,57 @@ DEFINE_SHUFFLE_BYTES(0, 3, 2, 1)
DEFINE_SHUFFLE_BYTES(1, 2, 3, 0)
DEFINE_SHUFFLE_BYTES(3, 0, 1, 2)
DEFINE_SHUFFLE_BYTES(3, 2, 1, 0)
+
+#define DEFINE_RGB48TOBGR48(need_bswap, swap) \
+void rgb48tobgr48_ ## need_bswap(const uint8_t *src, \
+ uint8_t *dst, int src_size) \
+{ \
+ uint16_t *d = (uint16_t *)dst; \
+ uint16_t *s = (uint16_t *)src; \
+ int i, num_pixels = src_size >> 1; \
+ \
+ for (i = 0; i < num_pixels; i += 3) { \
+ d[i ] = swap ? av_bswap16(s[i + 2]) : s[i + 2]; \
+ d[i + 1] = swap ? av_bswap16(s[i + 1]) : s[i + 1]; \
+ d[i + 2] = swap ? av_bswap16(s[i ]) : s[i ]; \
+ } \
+}
+
+DEFINE_RGB48TOBGR48(nobswap, 0)
+DEFINE_RGB48TOBGR48(bswap, 1)
+
+#define DEFINE_RGB64TOBGR48(need_bswap, swap) \
+void rgb64tobgr48_ ## need_bswap(const uint8_t *src, \
+ uint8_t *dst, int src_size) \
+{ \
+ uint16_t *d = (uint16_t *)dst; \
+ uint16_t *s = (uint16_t *)src; \
+ int i, num_pixels = src_size >> 3; \
+ \
+ for (i = 0; i < num_pixels; i++) { \
+ d[3 * i ] = swap ? av_bswap16(s[4 * i + 2]) : s[4 * i + 2]; \
+ d[3 * i + 1] = swap ? av_bswap16(s[4 * i + 1]) : s[4 * i + 1]; \
+ d[3 * i + 2] = swap ? av_bswap16(s[4 * i ]) : s[4 * i ]; \
+ } \
+}
+
+DEFINE_RGB64TOBGR48(nobswap, 0)
+DEFINE_RGB64TOBGR48(bswap, 1)
+
+#define DEFINE_RGB64TO48(need_bswap, swap) \
+void rgb64to48_ ## need_bswap(const uint8_t *src, \
+ uint8_t *dst, int src_size) \
+{ \
+ uint16_t *d = (uint16_t *)dst; \
+ uint16_t *s = (uint16_t *)src; \
+ int i, num_pixels = src_size >> 3; \
+ \
+ for (i = 0; i < num_pixels; i++) { \
+ d[3 * i ] = swap ? av_bswap16(s[4 * i ]) : s[4 * i ]; \
+ d[3 * i + 1] = swap ? av_bswap16(s[4 * i + 1]) : s[4 * i + 1]; \
+ d[3 * i + 2] = swap ? av_bswap16(s[4 * i + 2]) : s[4 * i + 2]; \
+ } \
+}
+
+DEFINE_RGB64TO48(nobswap, 0)
+DEFINE_RGB64TO48(bswap, 1)
diff --git a/libswscale/rgb2rgb.h b/libswscale/rgb2rgb.h
index f47b04ef0d..5df5dea420 100644
--- a/libswscale/rgb2rgb.h
+++ b/libswscale/rgb2rgb.h
@@ -6,20 +6,20 @@
* Written by Nick Kurshev.
* YUV & runtime CPU stuff by Michael (michaelni@gmx.at)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -52,6 +52,12 @@ extern void (*rgb32tobgr15)(const uint8_t *src, uint8_t *dst, int src_size);
extern void (*shuffle_bytes_2103)(const uint8_t *src, uint8_t *dst, int src_size);
+void rgb64tobgr48_nobswap(const uint8_t *src, uint8_t *dst, int src_size);
+void rgb64tobgr48_bswap(const uint8_t *src, uint8_t *dst, int src_size);
+void rgb48tobgr48_nobswap(const uint8_t *src, uint8_t *dst, int src_size);
+void rgb48tobgr48_bswap(const uint8_t *src, uint8_t *dst, int src_size);
+void rgb64to48_nobswap(const uint8_t *src, uint8_t *dst, int src_size);
+void rgb64to48_bswap(const uint8_t *src, uint8_t *dst, int src_size);
void rgb24to32(const uint8_t *src, uint8_t *dst, int src_size);
void rgb32to24(const uint8_t *src, uint8_t *dst, int src_size);
void rgb16tobgr32(const uint8_t *src, uint8_t *dst, int src_size);
@@ -64,16 +70,15 @@ void rgb15tobgr16(const uint8_t *src, uint8_t *dst, int src_size);
void rgb15tobgr15(const uint8_t *src, uint8_t *dst, int src_size);
void rgb12tobgr12(const uint8_t *src, uint8_t *dst, int src_size);
void rgb12to15(const uint8_t *src, uint8_t *dst, int src_size);
-void bgr8torgb8(const uint8_t *src, uint8_t *dst, int src_size);
void shuffle_bytes_0321(const uint8_t *src, uint8_t *dst, int src_size);
void shuffle_bytes_1230(const uint8_t *src, uint8_t *dst, int src_size);
void shuffle_bytes_3012(const uint8_t *src, uint8_t *dst, int src_size);
void shuffle_bytes_3210(const uint8_t *src, uint8_t *dst, int src_size);
-void rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
- uint8_t *vdst, int width, int height, int lumStride,
- int chromStride, int srcStride);
+void ff_rgb24toyv12_c(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);
/**
* Height should be a multiple of 2 and width should be a multiple of 16.
@@ -119,9 +124,10 @@ extern void (*yuv422ptouyvy)(const uint8_t *ysrc, const uint8_t *usrc, const uin
* Chrominance data is only taken from every second line, others are ignored.
* FIXME: Write high quality version.
*/
-extern 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);
+extern void (*ff_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);
extern void (*planar2x)(const uint8_t *src, uint8_t *dst, int width, int height,
int srcStride, int dstStride);
diff --git a/libswscale/rgb2rgb_template.c b/libswscale/rgb2rgb_template.c
index 693c7f2d0e..f9a98a8701 100644
--- a/libswscale/rgb2rgb_template.c
+++ b/libswscale/rgb2rgb_template.c
@@ -7,20 +7,20 @@
* 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -240,27 +240,6 @@ static inline void rgb24to15_c(const uint8_t *src, uint8_t *dst, int src_size)
}
}
-/*
- * I use less accurate approximation here by simply left-shifting the input
- * value and filling the low order bits with zeroes. This method improves PNG
- * compression but this scheme cannot reproduce white exactly, since it does
- * not generate an all-ones maximum value; the net effect is to darken the
- * image slightly.
- *
- * The better method should be "left bit replication":
- *
- * 4 3 2 1 0
- * ---------
- * 1 1 0 1 1
- *
- * 7 6 5 4 3 2 1 0
- * ----------------
- * 1 1 0 1 1 1 1 0
- * |=======| |===|
- * | leftmost bits repeated to fill open bits
- * |
- * original bits
- */
static inline void rgb15tobgr24_c(const uint8_t *src, uint8_t *dst,
int src_size)
{
@@ -270,9 +249,9 @@ static inline void rgb15tobgr24_c(const uint8_t *src, uint8_t *dst,
while (s < end) {
register uint16_t bgr = *s++;
- *d++ = (bgr & 0x1F) << 3;
- *d++ = (bgr & 0x3E0) >> 2;
- *d++ = (bgr & 0x7C00) >> 7;
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
+ *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7);
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
}
}
@@ -285,9 +264,9 @@ static inline void rgb16tobgr24_c(const uint8_t *src, uint8_t *dst,
while (s < end) {
register uint16_t bgr = *s++;
- *d++ = (bgr & 0x1F) << 3;
- *d++ = (bgr & 0x7E0) >> 3;
- *d++ = (bgr & 0xF800) >> 8;
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
+ *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9);
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
}
}
@@ -301,13 +280,13 @@ static inline void rgb15to32_c(const uint8_t *src, uint8_t *dst, int src_size)
register uint16_t bgr = *s++;
#if HAVE_BIGENDIAN
*d++ = 255;
- *d++ = (bgr & 0x7C00) >> 7;
- *d++ = (bgr & 0x3E0) >> 2;
- *d++ = (bgr & 0x1F) << 3;
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
+ *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7);
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
#else
- *d++ = (bgr & 0x1F) << 3;
- *d++ = (bgr & 0x3E0) >> 2;
- *d++ = (bgr & 0x7C00) >> 7;
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
+ *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7);
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
*d++ = 255;
#endif
}
@@ -323,13 +302,13 @@ static inline void rgb16to32_c(const uint8_t *src, uint8_t *dst, int src_size)
register uint16_t bgr = *s++;
#if HAVE_BIGENDIAN
*d++ = 255;
- *d++ = (bgr & 0xF800) >> 8;
- *d++ = (bgr & 0x7E0) >> 3;
- *d++ = (bgr & 0x1F) << 3;
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
+ *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9);
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
#else
- *d++ = (bgr & 0x1F) << 3;
- *d++ = (bgr & 0x7E0) >> 3;
- *d++ = (bgr & 0xF800) >> 8;
+ *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2);
+ *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9);
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
*d++ = 255;
#endif
}
@@ -635,10 +614,13 @@ static inline void uyvytoyv12_c(const uint8_t *src, uint8_t *ydst,
* others are ignored in the C version.
* FIXME: Write HQ version.
*/
-void rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
+void ff_rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
uint8_t *vdst, int width, int height, int lumStride,
- int chromStride, int srcStride)
+ int chromStride, int srcStride, int32_t *rgb2yuv)
{
+ int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX];
+ int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX];
+ int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX];
int y;
const int chromWidth = width >> 1;
@@ -649,9 +631,9 @@ void rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
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;
+ 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;
@@ -661,18 +643,21 @@ void rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
g = src[6 * i + 4];
r = src[6 * i + 5];
- Y = ((RY * r + GY * g + BY * b) >> RGB2YUV_SHIFT) + 16;
+ Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16;
ydst[2 * i + 1] = Y;
}
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 Y = ((RY * r + GY * g + BY * b) >> RGB2YUV_SHIFT) + 16;
+ unsigned int Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16;
ydst[2 * i] = Y;
@@ -680,7 +665,7 @@ void rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
g = src[6 * i + 4];
r = src[6 * i + 5];
- Y = ((RY * r + GY * g + BY * b) >> RGB2YUV_SHIFT) + 16;
+ Y = ((ry * r + gy * g + by * b) >> RGB2YUV_SHIFT) + 16;
ydst[2 * i + 1] = Y;
}
udst += chromStride;
@@ -856,7 +841,7 @@ static void yuyvtoyuv420_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth = -((-width) >> 1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y = 0; y < height; y++) {
extract_even_c(src, ydst, width);
@@ -876,7 +861,7 @@ static void yuyvtoyuv422_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth = -((-width) >> 1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y = 0; y < height; y++) {
extract_even_c(src, ydst, width);
@@ -894,7 +879,7 @@ static void uyvytoyuv420_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth = -((-width) >> 1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y = 0; y < height; y++) {
extract_even_c(src + 1, ydst, width);
@@ -914,7 +899,7 @@ static void uyvytoyuv422_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth = -((-width) >> 1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y = 0; y < height; y++) {
extract_even_c(src + 1, ydst, width);
@@ -953,7 +938,7 @@ static av_cold void rgb2rgb_init_c(void)
yuv422ptouyvy = yuv422ptouyvy_c;
yuy2toyv12 = yuy2toyv12_c;
planar2x = planar2x_c;
- rgb24toyv12 = rgb24toyv12_c;
+ ff_rgb24toyv12 = ff_rgb24toyv12_c;
interleaveBytes = interleaveBytes_c;
deinterleaveBytes = deinterleaveBytes_c;
vu9_to_vu12 = vu9_to_vu12_c;
diff --git a/libswscale/swscale-test.c b/libswscale/swscale-test.c
index 8063519be1..661ff5b7b2 100644
--- a/libswscale/swscale-test.c
+++ b/libswscale/swscale-test.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2003-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -53,7 +53,7 @@
(x) == AV_PIX_FMT_RGB32_1 || \
(x) == AV_PIX_FMT_YUVA420P)
-static uint64_t getSSD(uint8_t *src1, uint8_t *src2, int stride1,
+static uint64_t getSSD(const uint8_t *src1, const uint8_t *src2, int stride1,
int stride2, int w, int h)
{
int x, y;
@@ -92,7 +92,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
static int srcStride[4];
uint8_t *dst[4] = { 0 };
uint8_t *out[4] = { 0 };
- int dstStride[4];
+ int dstStride[4] = {0};
int i;
uint64_t ssdY, ssdU = 0, ssdV = 0, ssdA = 0;
struct SwsContext *dstContext = NULL, *outContext = NULL;
@@ -108,6 +108,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
av_image_fill_linesizes(srcStride, srcFormat, srcW);
for (p = 0; p < 4; p++) {
+ srcStride[p] = FFALIGN(srcStride[p], 16);
if (srcStride[p])
src[p] = av_mallocz(srcStride[p] * srcH + 16);
if (srcStride[p] && !src[p]) {
@@ -125,7 +126,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
res = -1;
goto end;
}
- sws_scale(srcContext, ref, refStride, 0, h, src, srcStride);
+ sws_scale(srcContext, (const uint8_t * const*)ref, refStride, 0, h, src, srcStride);
sws_freeContext(srcContext);
cur_srcFormat = srcFormat;
@@ -141,6 +142,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
* allocated with av_malloc). */
/* An extra 16 bytes is being allocated because some scalers may write
* out of bounds. */
+ dstStride[i] = FFALIGN(dstStride[i], 16);
if (dstStride[i])
dst[i] = av_mallocz(dstStride[i] * dstH + 16);
if (dstStride[i] && !dst[i]) {
@@ -166,7 +168,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
flags);
fflush(stdout);
- sws_scale(dstContext, src, srcStride, 0, srcH, dst, dstStride);
+ sws_scale(dstContext, (const uint8_t * const*)src, srcStride, 0, srcH, dst, dstStride);
for (i = 0; i < 4 && dstStride[i]; i++)
crc = av_crc(av_crc_get_table(AV_CRC_32_IEEE), crc, dst[i],
@@ -179,6 +181,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
ssdA = r->ssdA;
} else {
for (i = 0; i < 4; i++) {
+ refStride[i] = FFALIGN(refStride[i], 16);
if (refStride[i])
out[i] = av_mallocz(refStride[i] * h);
if (refStride[i] && !out[i]) {
@@ -197,7 +200,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h,
res = -1;
goto end;
}
- sws_scale(outContext, dst, dstStride, 0, dstH, out, refStride);
+ sws_scale(outContext, (const uint8_t * const*)dst, dstStride, 0, dstH, out, refStride);
ssdY = getSSD(ref[0], out[0], refStride[0], refStride[0], w, h);
if (hasChroma(srcFormat) && hasChroma(dstFormat)) {
@@ -304,7 +307,7 @@ static int fileTest(uint8_t *ref[4], int refStride[4], int w, int h, FILE *fp,
ret = sscanf(buf,
" %12s %dx%d -> %12s %dx%d flags=%d CRC=%x"
- " SSD=%"PRId64 ", %"PRId64 ", %"PRId64 ", %"PRId64 "\n",
+ " SSD=%"SCNd64 ", %"SCNd64 ", %"SCNd64 ", %"SCNd64 "\n",
srcStr, &srcW, &srcH, dstStr, &dstW, &dstH,
&flags, &r.crc, &r.ssdY, &r.ssdU, &r.ssdV, &r.ssdA);
if (ret != 12) {
@@ -315,7 +318,8 @@ static int fileTest(uint8_t *ref[4], int refStride[4], int w, int h, FILE *fp,
srcFormat = av_get_pix_fmt(srcStr);
dstFormat = av_get_pix_fmt(dstStr);
- if (srcFormat == AV_PIX_FMT_NONE || dstFormat == AV_PIX_FMT_NONE) {
+ if (srcFormat == AV_PIX_FMT_NONE || dstFormat == AV_PIX_FMT_NONE ||
+ srcW > 8192U || srcH > 8192U || dstW > 8192U || dstH > 8192U) {
fprintf(stderr, "malformed input file\n");
return -1;
}
@@ -344,7 +348,7 @@ int main(int argc, char **argv)
enum AVPixelFormat srcFormat = AV_PIX_FMT_NONE;
enum AVPixelFormat dstFormat = AV_PIX_FMT_NONE;
uint8_t *rgb_data = av_malloc(W * H * 4);
- uint8_t *rgb_src[4] = { rgb_data, NULL, NULL, NULL };
+ const uint8_t * const rgb_src[4] = { rgb_data, NULL, NULL, NULL };
int rgb_stride[4] = { 4 * W, 0, 0, 0 };
uint8_t *data = av_malloc(4 * W * H);
uint8_t *src[4] = { data, data + W * H, data + W * H * 2, data + W * H * 3 };
@@ -354,34 +358,20 @@ int main(int argc, char **argv)
AVLFG rand;
int res = -1;
int i;
+ FILE *fp = NULL;
if (!rgb_data || !data)
return -1;
- sws = sws_getContext(W / 12, H / 12, AV_PIX_FMT_RGB32, W, H,
- AV_PIX_FMT_YUVA420P, SWS_BILINEAR, NULL, NULL, NULL);
-
- av_lfg_init(&rand, 1);
-
- for (y = 0; y < H; y++)
- for (x = 0; x < W * 4; x++)
- rgb_data[ x + y * 4 * W] = av_lfg_get(&rand);
- sws_scale(sws, rgb_src, rgb_stride, 0, H, src, stride);
- sws_freeContext(sws);
- av_free(rgb_data);
-
for (i = 1; i < argc; i += 2) {
if (argv[i][0] != '-' || i + 1 == argc)
goto bad_option;
if (!strcmp(argv[i], "-ref")) {
- FILE *fp = fopen(argv[i + 1], "r");
+ fp = fopen(argv[i + 1], "r");
if (!fp) {
fprintf(stderr, "could not open '%s'\n", argv[i + 1]);
goto error;
}
- res = fileTest(src, stride, W, H, fp, srcFormat, dstFormat);
- fclose(fp);
- goto end;
} else if (!strcmp(argv[i], "-src")) {
srcFormat = av_get_pix_fmt(argv[i + 1]);
if (srcFormat == AV_PIX_FMT_NONE) {
@@ -401,9 +391,25 @@ bad_option:
}
}
- selfTest(src, stride, W, H, srcFormat, dstFormat);
-end:
- res = 0;
+ sws = sws_getContext(W / 12, H / 12, AV_PIX_FMT_RGB32, W, H,
+ AV_PIX_FMT_YUVA420P, SWS_BILINEAR, NULL, NULL, NULL);
+
+ av_lfg_init(&rand, 1);
+
+ for (y = 0; y < H; y++)
+ for (x = 0; x < W * 4; x++)
+ rgb_data[ x + y * 4 * W] = av_lfg_get(&rand);
+ sws_scale(sws, rgb_src, rgb_stride, 0, H, src, stride);
+ sws_freeContext(sws);
+ av_free(rgb_data);
+
+ if(fp) {
+ res = fileTest(src, stride, W, H, fp, srcFormat, dstFormat);
+ fclose(fp);
+ } else {
+ selfTest(src, stride, W, H, srcFormat, dstFormat);
+ res = 0;
+ }
error:
av_free(data);
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index f6427bfb55..5312016927 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1,32 +1,33 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
+#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/bswap.h"
#include "libavutil/cpu.h"
+#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
@@ -35,7 +36,7 @@
#include "swscale_internal.h"
#include "swscale.h"
-DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_128)[8][8] = {
+DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_128)[9][8] = {
{ 36, 68, 60, 92, 34, 66, 58, 90, },
{ 100, 4, 124, 28, 98, 2, 122, 26, },
{ 52, 84, 44, 76, 50, 82, 42, 74, },
@@ -44,12 +45,29 @@ DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_128)[8][8] = {
{ 96, 0, 120, 24, 102, 6, 126, 30, },
{ 48, 80, 40, 72, 54, 86, 46, 78, },
{ 112, 16, 104, 8, 118, 22, 110, 14, },
+ { 36, 68, 60, 92, 34, 66, 58, 90, },
};
DECLARE_ALIGNED(8, static const uint8_t, sws_pb_64)[8] = {
64, 64, 64, 64, 64, 64, 64, 64
};
+static void gamma_convert(uint8_t * src[], int width, uint16_t *gamma)
+{
+ int i;
+ uint16_t *src1 = (uint16_t*)src[0];
+
+ for (i = 0; i < width; ++i) {
+ uint16_t r = AV_RL16(src1 + i*4 + 0);
+ uint16_t g = AV_RL16(src1 + i*4 + 1);
+ uint16_t b = AV_RL16(src1 + i*4 + 2);
+
+ AV_WL16(src1 + i*4 + 0, gamma[r]);
+ AV_WL16(src1 + i*4 + 1, gamma[g]);
+ AV_WL16(src1 + i*4 + 2, gamma[b]);
+ }
+}
+
static av_always_inline void fillPlane(uint8_t *plane, int stride, int width,
int height, int y, uint8_t val)
{
@@ -61,28 +79,6 @@ static av_always_inline void fillPlane(uint8_t *plane, int stride, int width,
}
}
-static void fill_plane9or10(uint8_t *plane, int stride, int width,
- int height, int y, uint8_t val,
- const int dst_depth, const int big_endian)
-{
- int i, j;
- uint16_t *dst = (uint16_t *) (plane + stride * y);
-#define FILL8TO9_OR_10(wfunc) \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < width; j++) { \
- wfunc(&dst[j], (val << (dst_depth - 8)) | \
- (val >> (16 - dst_depth))); \
- } \
- dst += stride / 2; \
- }
- if (big_endian) {
- FILL8TO9_OR_10(AV_WB16);
- } else {
- FILL8TO9_OR_10(AV_WL16);
- }
-}
-
-
static void hScale16To19_c(SwsContext *c, int16_t *_dst, int dstW,
const uint8_t *_src, const int16_t *filter,
const int32_t *filterPos, int filterSize)
@@ -94,6 +90,9 @@ static void hScale16To19_c(SwsContext *c, int16_t *_dst, int dstW,
int bits = desc->comp[0].depth_minus1;
int sh = bits - 4;
+ if((isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8) && desc->comp[0].depth_minus1<15)
+ sh= 9;
+
for (i = 0; i < dstW; i++) {
int j;
int srcPos = filterPos[i];
@@ -116,6 +115,9 @@ static void hScale16To15_c(SwsContext *c, int16_t *dst, int dstW,
const uint16_t *src = (const uint16_t *) _src;
int sh = desc->comp[0].depth_minus1;
+ if(sh<15)
+ sh= isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8 ? 13 : desc->comp[0].depth_minus1;
+
for (i = 0; i < dstW; i++) {
int j;
int srcPos = filterPos[i];
@@ -223,8 +225,9 @@ static void lumRangeToJpeg16_c(int16_t *_dst, int width)
{
int i;
int32_t *dst = (int32_t *) _dst;
- for (i = 0; i < width; i++)
- dst[i] = (FFMIN(dst[i], 30189 << 4) * 4769 - (39057361 << 2)) >> 12;
+ for (i = 0; i < width; i++) {
+ dst[i] = ((int)(FFMIN(dst[i], 30189 << 4) * 4769U - (39057361 << 2))) >> 12;
+ }
}
static void lumRangeFromJpeg16_c(int16_t *_dst, int width)
@@ -232,20 +235,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 + (33561947 << 4)) >> 14;
-}
-
-static void hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth,
- const uint8_t *src, int srcW, int xInc)
-{
- int i;
- unsigned int xpos = 0;
- for (i = 0; i < dstWidth; i++) {
- register unsigned int xx = xpos >> 16;
- register unsigned int xalpha = (xpos & 0xFFFF) >> 9;
- dst[i] = (src[xx] << 7) + (src[xx + 1] - src[xx]) * xalpha;
- xpos += xInc;
- }
+ dst[i] = (dst[i]*(14071/4) + (33561947<<4)/4)>>12;
}
// *** horizontal scale Y line to temp buffer
@@ -258,19 +248,19 @@ static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth,
uint8_t *formatConvBuffer,
uint32_t *pal, int isAlpha)
{
- void (*toYV12)(uint8_t *, const uint8_t *, int, uint32_t *) =
+ void (*toYV12)(uint8_t *, const uint8_t *, const uint8_t *, const uint8_t *, int, uint32_t *) =
isAlpha ? c->alpToYV12 : c->lumToYV12;
void (*convertRange)(int16_t *, int) = isAlpha ? NULL : c->lumConvertRange;
const uint8_t *src = src_in[isAlpha ? 3 : 0];
if (toYV12) {
- toYV12(formatConvBuffer, src, srcW, pal);
+ toYV12(formatConvBuffer, src, src_in[1], src_in[2], srcW, pal);
src = formatConvBuffer;
} else if (c->readLumPlanar && !isAlpha) {
- c->readLumPlanar(formatConvBuffer, src_in, srcW);
+ c->readLumPlanar(formatConvBuffer, src_in, srcW, c->input_rgb2yuv_table);
src = formatConvBuffer;
} else if (c->readAlpPlanar && isAlpha) {
- c->readAlpPlanar(formatConvBuffer, src_in, srcW);
+ c->readAlpPlanar(formatConvBuffer, src_in, srcW, NULL);
src = formatConvBuffer;
}
@@ -285,21 +275,6 @@ static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth,
convertRange(dst, dstWidth);
}
-static void hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2,
- int dstWidth, const uint8_t *src1,
- const uint8_t *src2, int srcW, int xInc)
-{
- int i;
- unsigned int xpos = 0;
- for (i = 0; i < dstWidth; i++) {
- register unsigned int xx = xpos >> 16;
- register unsigned int xalpha = (xpos & 0xFFFF) >> 9;
- dst1[i] = (src1[xx] * (xalpha ^ 127) + src1[xx + 1] * xalpha);
- dst2[i] = (src2[xx] * (xalpha ^ 127) + src2[xx + 1] * xalpha);
- xpos += xInc;
- }
-}
-
static av_always_inline void hcscale(SwsContext *c, int16_t *dst1,
int16_t *dst2, int dstWidth,
const uint8_t *src_in[4],
@@ -312,14 +287,14 @@ static av_always_inline void hcscale(SwsContext *c, int16_t *dst1,
const uint8_t *src1 = src_in[1], *src2 = src_in[2];
if (c->chrToYV12) {
uint8_t *buf2 = formatConvBuffer +
- FFALIGN(srcW * FFALIGN(c->srcBpc, 8) >> 3, 16);
- c->chrToYV12(formatConvBuffer, buf2, src1, src2, srcW, pal);
- src1 = formatConvBuffer;
- src2 = buf2;
+ FFALIGN(srcW*2+78, 16);
+ c->chrToYV12(formatConvBuffer, buf2, src_in[0], src1, src2, srcW, pal);
+ src1= formatConvBuffer;
+ src2= buf2;
} else if (c->readChrPlanar) {
uint8_t *buf2 = formatConvBuffer +
- FFALIGN(srcW * FFALIGN(c->srcBpc, 8) >> 3, 16);
- c->readChrPlanar(formatConvBuffer, buf2, src_in, srcW);
+ FFALIGN(srcW*2+78, 16);
+ c->readChrPlanar(formatConvBuffer, buf2, src_in, srcW, c->input_rgb2yuv_table);
src1 = formatConvBuffer;
src2 = buf2;
}
@@ -359,8 +334,6 @@ static int swscale(SwsContext *c, const uint8_t *src[],
int32_t *vChrFilterPos = c->vChrFilterPos;
int32_t *hLumFilterPos = c->hLumFilterPos;
int32_t *hChrFilterPos = c->hChrFilterPos;
- int16_t *vLumFilter = c->vLumFilter;
- int16_t *vChrFilter = c->vChrFilter;
int16_t *hLumFilter = c->hLumFilter;
int16_t *hChrFilter = c->hChrFilter;
int32_t *lumMmxFilter = c->lumMmxFilter;
@@ -384,8 +357,8 @@ static int swscale(SwsContext *c, const uint8_t *src[],
yuv2packed2_fn yuv2packed2 = c->yuv2packed2;
yuv2packedX_fn yuv2packedX = c->yuv2packedX;
yuv2anyX_fn yuv2anyX = c->yuv2anyX;
- const int chrSrcSliceY = srcSliceY >> c->chrSrcVSubSample;
- const int chrSrcSliceH = -((-srcSliceH) >> c->chrSrcVSubSample);
+ const int chrSrcSliceY = srcSliceY >> c->chrSrcVSubSample;
+ const int chrSrcSliceH = FF_CEIL_RSHIFT(srcSliceH, c->chrSrcVSubSample);
int should_dither = is9_OR_10BPS(c->srcFormat) ||
is16BPS(c->srcFormat);
int lastDstY;
@@ -396,6 +369,12 @@ static int swscale(SwsContext *c, const uint8_t *src[],
int chrBufIndex = c->chrBufIndex;
int lastInLumBuf = c->lastInLumBuf;
int lastInChrBuf = c->lastInChrBuf;
+ int perform_gamma = c->is_internal_gamma;
+
+
+ if (!usePal(c->srcFormat)) {
+ pal = c->input_rgb2yuv_table;
+ }
if (isPacked(c->srcFormat)) {
src[0] =
@@ -420,8 +399,8 @@ static int swscale(SwsContext *c, const uint8_t *src[],
DEBUG_BUFFERS("vLumFilterSize: %d vLumBufSize: %d vChrFilterSize: %d vChrBufSize: %d\n",
vLumFilterSize, vLumBufSize, vChrFilterSize, vChrBufSize);
- if (dstStride[0] % 8 != 0 || dstStride[1] % 8 != 0 ||
- dstStride[2] % 8 != 0 || dstStride[3] % 8 != 0) {
+ if (dstStride[0]&15 || dstStride[1]&15 ||
+ dstStride[2]&15 || dstStride[3]&15) {
static int warnedAlready = 0; // FIXME maybe move this into the context
if (flags & SWS_PRINT_INFO && !warnedAlready) {
av_log(c, AV_LOG_WARNING,
@@ -431,6 +410,19 @@ static int swscale(SwsContext *c, const uint8_t *src[],
}
}
+ if ( (uintptr_t)dst[0]&15 || (uintptr_t)dst[1]&15 || (uintptr_t)dst[2]&15
+ || (uintptr_t)src[0]&15 || (uintptr_t)src[1]&15 || (uintptr_t)src[2]&15
+ || dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15
+ || srcStride[0]&15 || srcStride[1]&15 || srcStride[2]&15 || srcStride[3]&15
+ ) {
+ static int warnedAlready=0;
+ int cpu_flags = av_get_cpu_flags();
+ if (HAVE_MMXEXT && (cpu_flags & AV_CPU_FLAG_SSE2) && !warnedAlready){
+ av_log(c, AV_LOG_WARNING, "Warning: data is not aligned! This can lead to a speedloss\n");
+ warnedAlready=1;
+ }
+ }
+
/* Note the user might start scaling the picture in the middle so this
* will not get executed. This is not really intended but works
* currently, so people might do it. */
@@ -455,6 +447,7 @@ static int swscale(SwsContext *c, const uint8_t *src[],
dst[2] + dstStride[2] * chrDstY,
(CONFIG_SWSCALE_ALPHA && alpPixBuf) ? dst[3] + dstStride[3] * dstY : NULL,
};
+ int use_mmx_vfilter= c->use_mmx_vfilter;
// First line needed as input
const int firstLumSrcY = FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]);
@@ -473,8 +466,8 @@ static int swscale(SwsContext *c, const uint8_t *src[],
lastInLumBuf = firstLumSrcY - 1;
if (firstChrSrcY > lastInChrBuf)
lastInChrBuf = firstChrSrcY - 1;
- assert(firstLumSrcY >= lastInLumBuf - vLumBufSize + 1);
- assert(firstChrSrcY >= lastInChrBuf - vChrBufSize + 1);
+ av_assert0(firstLumSrcY >= lastInLumBuf - vLumBufSize + 1);
+ av_assert0(firstChrSrcY >= lastInChrBuf - vChrBufSize + 1);
DEBUG_BUFFERS("dstY: %d\n", dstY);
DEBUG_BUFFERS("\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n",
@@ -484,7 +477,7 @@ static int swscale(SwsContext *c, const uint8_t *src[],
// Do we have enough lines in this slice to output the dstY line
enough_lines = lastLumSrcY2 < srcSliceY + srcSliceH &&
- lastChrSrcY < -((-srcSliceY - srcSliceH) >> c->chrSrcVSubSample);
+ lastChrSrcY < FF_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample);
if (!enough_lines) {
lastLumSrcY = srcSliceY + srcSliceH - 1;
@@ -502,9 +495,13 @@ static int swscale(SwsContext *c, const uint8_t *src[],
src[3] + (lastInLumBuf + 1 - srcSliceY) * srcStride[3],
};
lumBufIndex++;
- assert(lumBufIndex < 2 * vLumBufSize);
- assert(lastInLumBuf + 1 - srcSliceY < srcSliceH);
- assert(lastInLumBuf + 1 - srcSliceY >= 0);
+ av_assert0(lumBufIndex < 2 * vLumBufSize);
+ av_assert0(lastInLumBuf + 1 - srcSliceY < srcSliceH);
+ av_assert0(lastInLumBuf + 1 - srcSliceY >= 0);
+
+ if (perform_gamma)
+ gamma_convert((uint8_t **)src1, srcW, c->inv_gamma);
+
hyscale(c, lumPixBuf[lumBufIndex], dstW, src1, srcW, lumXInc,
hLumFilter, hLumFilterPos, hLumFilterSize,
formatConvBuffer, pal, 0);
@@ -524,9 +521,9 @@ static int swscale(SwsContext *c, const uint8_t *src[],
src[3] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[3],
};
chrBufIndex++;
- assert(chrBufIndex < 2 * vChrBufSize);
- assert(lastInChrBuf + 1 - chrSrcSliceY < (chrSrcSliceH));
- assert(lastInChrBuf + 1 - chrSrcSliceY >= 0);
+ av_assert0(chrBufIndex < 2 * vChrBufSize);
+ av_assert0(lastInChrBuf + 1 - chrSrcSliceY < (chrSrcSliceH));
+ av_assert0(lastInChrBuf + 1 - chrSrcSliceY >= 0);
// FIXME replace parameters through context struct (some at least)
if (c->needs_hcscale)
@@ -547,7 +544,7 @@ static int swscale(SwsContext *c, const uint8_t *src[],
break; // we can't output a dstY line so let's try with the next slice
#if HAVE_MMX_INLINE
- updateMMXDitherTables(c, dstY, lumBufIndex, chrBufIndex,
+ ff_updateMMXDitherTables(c, dstY, lumBufIndex, chrBufIndex,
lastInLumBuf, lastInChrBuf);
#endif
if (should_dither) {
@@ -559,103 +556,81 @@ static int swscale(SwsContext *c, const uint8_t *src[],
* this array's tail */
ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX,
&yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX);
+ use_mmx_vfilter= 0;
}
{
- const int16_t **lumSrcPtr = (const int16_t **)lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize;
- const int16_t **chrUSrcPtr = (const int16_t **)chrUPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
- const int16_t **chrVSrcPtr = (const int16_t **)chrVPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
+ const int16_t **lumSrcPtr = (const int16_t **)(void*) lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize;
+ const int16_t **chrUSrcPtr = (const int16_t **)(void*) chrUPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
+ const int16_t **chrVSrcPtr = (const int16_t **)(void*) chrVPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
const int16_t **alpSrcPtr = (CONFIG_SWSCALE_ALPHA && alpPixBuf) ?
- (const int16_t **)alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL;
-
- if (firstLumSrcY < 0 || firstLumSrcY + vLumFilterSize > c->srcH) {
- const int16_t **tmpY = (const int16_t **)lumPixBuf +
- 2 * vLumBufSize;
- int neg = -firstLumSrcY, i;
- int end = FFMIN(c->srcH - firstLumSrcY, vLumFilterSize);
- for (i = 0; i < neg; i++)
- tmpY[i] = lumSrcPtr[neg];
- for (; i < end; i++)
- tmpY[i] = lumSrcPtr[i];
- for (; i < vLumFilterSize; i++)
- tmpY[i] = tmpY[i - 1];
- lumSrcPtr = tmpY;
-
- if (alpSrcPtr) {
- const int16_t **tmpA = (const int16_t **)alpPixBuf +
- 2 * vLumBufSize;
- for (i = 0; i < neg; i++)
- tmpA[i] = alpSrcPtr[neg];
- for (; i < end; i++)
- tmpA[i] = alpSrcPtr[i];
- for (; i < vLumFilterSize; i++)
- tmpA[i] = tmpA[i - 1];
- alpSrcPtr = tmpA;
- }
- }
- if (firstChrSrcY < 0 ||
- firstChrSrcY + vChrFilterSize > c->chrSrcH) {
- const int16_t **tmpU = (const int16_t **)chrUPixBuf + 2 * vChrBufSize,
- **tmpV = (const int16_t **)chrVPixBuf + 2 * vChrBufSize;
- int neg = -firstChrSrcY, i;
- int end = FFMIN(c->chrSrcH - firstChrSrcY, vChrFilterSize);
- for (i = 0; i < neg; i++) {
- tmpU[i] = chrUSrcPtr[neg];
- tmpV[i] = chrVSrcPtr[neg];
- }
- for (; i < end; i++) {
- tmpU[i] = chrUSrcPtr[i];
- tmpV[i] = chrVSrcPtr[i];
- }
- for (; i < vChrFilterSize; i++) {
- tmpU[i] = tmpU[i - 1];
- tmpV[i] = tmpV[i - 1];
- }
- chrUSrcPtr = tmpU;
- chrVSrcPtr = tmpV;
- }
+ (const int16_t **)(void*) alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL;
+ int16_t *vLumFilter = c->vLumFilter;
+ int16_t *vChrFilter = c->vChrFilter;
if (isPlanarYUV(dstFormat) ||
(isGray(dstFormat) && !isALPHA(dstFormat))) { // YV12 like
const int chrSkipMask = (1 << c->chrDstVSubSample) - 1;
+ vLumFilter += dstY * vLumFilterSize;
+ vChrFilter += chrDstY * vChrFilterSize;
+
+// av_assert0(use_mmx_vfilter != (
+// yuv2planeX == yuv2planeX_10BE_c
+// || yuv2planeX == yuv2planeX_10LE_c
+// || yuv2planeX == yuv2planeX_9BE_c
+// || yuv2planeX == yuv2planeX_9LE_c
+// || yuv2planeX == yuv2planeX_16BE_c
+// || yuv2planeX == yuv2planeX_16LE_c
+// || yuv2planeX == yuv2planeX_8_c) || !ARCH_X86);
+
+ if(use_mmx_vfilter){
+ vLumFilter= (int16_t *)c->lumMmxFilter;
+ vChrFilter= (int16_t *)c->chrMmxFilter;
+ }
+
if (vLumFilterSize == 1) {
yuv2plane1(lumSrcPtr[0], dest[0], dstW, c->lumDither8, 0);
} else {
- yuv2planeX(vLumFilter + dstY * vLumFilterSize,
- vLumFilterSize, lumSrcPtr, dest[0],
+ yuv2planeX(vLumFilter, vLumFilterSize,
+ lumSrcPtr, dest[0],
dstW, c->lumDither8, 0);
}
if (!((dstY & chrSkipMask) || isGray(dstFormat))) {
if (yuv2nv12cX) {
- yuv2nv12cX(c, vChrFilter + chrDstY * vChrFilterSize,
+ yuv2nv12cX(c, vChrFilter,
vChrFilterSize, chrUSrcPtr, chrVSrcPtr,
dest[1], chrDstW);
} else if (vChrFilterSize == 1) {
yuv2plane1(chrUSrcPtr[0], dest[1], chrDstW, c->chrDither8, 0);
yuv2plane1(chrVSrcPtr[0], dest[2], chrDstW, c->chrDither8, 3);
} else {
- yuv2planeX(vChrFilter + chrDstY * vChrFilterSize,
+ yuv2planeX(vChrFilter,
vChrFilterSize, chrUSrcPtr, dest[1],
chrDstW, c->chrDither8, 0);
- yuv2planeX(vChrFilter + chrDstY * vChrFilterSize,
+ yuv2planeX(vChrFilter,
vChrFilterSize, chrVSrcPtr, dest[2],
- chrDstW, c->chrDither8, 3);
+ chrDstW, c->chrDither8, use_mmx_vfilter ? (c->uv_offx2 >> 1) : 3);
}
}
if (CONFIG_SWSCALE_ALPHA && alpPixBuf) {
+ if(use_mmx_vfilter){
+ vLumFilter= (int16_t *)c->alpMmxFilter;
+ }
if (vLumFilterSize == 1) {
yuv2plane1(alpSrcPtr[0], dest[3], dstW,
c->lumDither8, 0);
} else {
- yuv2planeX(vLumFilter + dstY * vLumFilterSize,
+ yuv2planeX(vLumFilter,
vLumFilterSize, alpSrcPtr, dest[3],
dstW, c->lumDither8, 0);
}
}
} else if (yuv2packedX) {
+ av_assert1(lumSrcPtr + vLumFilterSize - 1 < (const int16_t **)lumPixBuf + vLumBufSize * 2);
+ av_assert1(chrUSrcPtr + vChrFilterSize - 1 < (const int16_t **)chrUPixBuf + vChrBufSize * 2);
if (c->yuv2packed1 && vLumFilterSize == 1 &&
vChrFilterSize <= 2) { // unscaled RGB
int chrAlpha = vChrFilterSize == 1 ? 0 : vChrFilter[2 * dstY + 1];
@@ -681,26 +656,26 @@ static int swscale(SwsContext *c, const uint8_t *src[],
alpSrcPtr, dest[0], dstW, dstY);
}
} else {
+ av_assert1(!yuv2packed1 && !yuv2packed2);
yuv2anyX(c, vLumFilter + dstY * vLumFilterSize,
lumSrcPtr, vLumFilterSize,
vChrFilter + dstY * vChrFilterSize,
chrUSrcPtr, chrVSrcPtr, vChrFilterSize,
alpSrcPtr, dest, dstW, dstY);
}
+ if (perform_gamma)
+ gamma_convert(dest, dstW, c->gamma);
}
}
-
if (isPlanar(dstFormat) && isALPHA(dstFormat) && !alpPixBuf) {
int length = dstW;
int height = dstY - lastDstY;
- if (is16BPS(c->dstFormat))
- length *= 2;
- if (is9_OR_10BPS(dstFormat)) {
+ if (is16BPS(dstFormat) || isNBPS(dstFormat)) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat);
- fill_plane9or10(dst[3], dstStride[3], length, height, lastDstY,
- 255, desc->comp[3].depth_minus1 + 1,
- isBE(dstFormat));
+ fillPlane16(dst[3], dstStride[3], length, height, lastDstY,
+ 1, desc->comp[3].depth_minus1,
+ isBE(dstFormat));
} else
fillPlane(dst[3], dstStride[3], length, height, lastDstY, 255);
}
@@ -721,6 +696,31 @@ static int swscale(SwsContext *c, const uint8_t *src[],
return dstY - lastDstY;
}
+av_cold void ff_sws_init_range_convert(SwsContext *c)
+{
+ c->lumConvertRange = NULL;
+ c->chrConvertRange = NULL;
+ if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) {
+ if (c->dstBpc <= 14) {
+ if (c->srcRange) {
+ c->lumConvertRange = lumRangeFromJpeg_c;
+ c->chrConvertRange = chrRangeFromJpeg_c;
+ } else {
+ c->lumConvertRange = lumRangeToJpeg_c;
+ c->chrConvertRange = chrRangeToJpeg_c;
+ }
+ } else {
+ if (c->srcRange) {
+ c->lumConvertRange = lumRangeFromJpeg16_c;
+ c->chrConvertRange = chrRangeFromJpeg16_c;
+ } else {
+ c->lumConvertRange = lumRangeToJpeg16_c;
+ c->chrConvertRange = chrRangeToJpeg16_c;
+ }
+ }
+ }
+}
+
static av_cold void sws_init_swscale(SwsContext *c)
{
enum AVPixelFormat srcFormat = c->srcFormat;
@@ -731,40 +731,23 @@ static av_cold void sws_init_swscale(SwsContext *c)
ff_sws_init_input_funcs(c);
+
if (c->srcBpc == 8) {
- if (c->dstBpc <= 10) {
+ if (c->dstBpc <= 14) {
c->hyScale = c->hcScale = hScale8To15_c;
if (c->flags & SWS_FAST_BILINEAR) {
- c->hyscale_fast = hyscale_fast_c;
- c->hcscale_fast = hcscale_fast_c;
+ c->hyscale_fast = ff_hyscale_fast_c;
+ c->hcscale_fast = ff_hcscale_fast_c;
}
} else {
c->hyScale = c->hcScale = hScale8To19_c;
}
} else {
- c->hyScale = c->hcScale = c->dstBpc > 10 ? hScale16To19_c
+ c->hyScale = c->hcScale = c->dstBpc > 14 ? hScale16To19_c
: hScale16To15_c;
}
- if (c->srcRange != c->dstRange && !isAnyRGB(c->dstFormat)) {
- if (c->dstBpc <= 10) {
- if (c->srcRange) {
- c->lumConvertRange = lumRangeFromJpeg_c;
- c->chrConvertRange = chrRangeFromJpeg_c;
- } else {
- c->lumConvertRange = lumRangeToJpeg_c;
- c->chrConvertRange = chrRangeToJpeg_c;
- }
- } else {
- if (c->srcRange) {
- c->lumConvertRange = lumRangeFromJpeg16_c;
- c->chrConvertRange = chrRangeFromJpeg16_c;
- } else {
- c->lumConvertRange = lumRangeToJpeg16_c;
- c->chrConvertRange = chrRangeToJpeg16_c;
- }
- }
- }
+ ff_sws_init_range_convert(c);
if (!(isGray(srcFormat) || isGray(c->dstFormat) ||
srcFormat == AV_PIX_FMT_MONOBLACK || srcFormat == AV_PIX_FMT_MONOWHITE))
@@ -782,3 +765,388 @@ SwsFunc ff_getSwsFunc(SwsContext *c)
return swscale;
}
+
+static void reset_ptr(const uint8_t *src[], enum AVPixelFormat format)
+{
+ if (!isALPHA(format))
+ src[3] = NULL;
+ if (!isPlanar(format)) {
+ src[3] = src[2] = NULL;
+
+ if (!usePal(format))
+ src[1] = NULL;
+ }
+}
+
+static int check_image_pointers(const uint8_t * const data[4], enum AVPixelFormat pix_fmt,
+ const int linesizes[4])
+{
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ int plane = desc->comp[i].plane;
+ if (!data[plane] || !linesizes[plane])
+ return 0;
+ }
+
+ return 1;
+}
+
+static void xyz12Torgb48(struct SwsContext *c, uint16_t *dst,
+ const uint16_t *src, int stride, int h)
+{
+ int xp,yp;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat);
+
+ for (yp=0; yp<h; yp++) {
+ for (xp=0; xp+2<stride; xp+=3) {
+ int x, y, z, r, g, b;
+
+ if (desc->flags & AV_PIX_FMT_FLAG_BE) {
+ x = AV_RB16(src + xp + 0);
+ y = AV_RB16(src + xp + 1);
+ z = AV_RB16(src + xp + 2);
+ } else {
+ x = AV_RL16(src + xp + 0);
+ y = AV_RL16(src + xp + 1);
+ z = AV_RL16(src + xp + 2);
+ }
+
+ x = c->xyzgamma[x>>4];
+ y = c->xyzgamma[y>>4];
+ z = c->xyzgamma[z>>4];
+
+ // convert from XYZlinear to sRGBlinear
+ r = c->xyz2rgb_matrix[0][0] * x +
+ c->xyz2rgb_matrix[0][1] * y +
+ c->xyz2rgb_matrix[0][2] * z >> 12;
+ g = c->xyz2rgb_matrix[1][0] * x +
+ c->xyz2rgb_matrix[1][1] * y +
+ c->xyz2rgb_matrix[1][2] * z >> 12;
+ b = c->xyz2rgb_matrix[2][0] * x +
+ c->xyz2rgb_matrix[2][1] * y +
+ c->xyz2rgb_matrix[2][2] * z >> 12;
+
+ // limit values to 12-bit depth
+ r = av_clip_uintp2(r, 12);
+ g = av_clip_uintp2(g, 12);
+ b = av_clip_uintp2(b, 12);
+
+ // convert from sRGBlinear to RGB and scale from 12bit to 16bit
+ if (desc->flags & AV_PIX_FMT_FLAG_BE) {
+ AV_WB16(dst + xp + 0, c->rgbgamma[r] << 4);
+ AV_WB16(dst + xp + 1, c->rgbgamma[g] << 4);
+ AV_WB16(dst + xp + 2, c->rgbgamma[b] << 4);
+ } else {
+ AV_WL16(dst + xp + 0, c->rgbgamma[r] << 4);
+ AV_WL16(dst + xp + 1, c->rgbgamma[g] << 4);
+ AV_WL16(dst + xp + 2, c->rgbgamma[b] << 4);
+ }
+ }
+ src += stride;
+ dst += stride;
+ }
+}
+
+static void rgb48Toxyz12(struct SwsContext *c, uint16_t *dst,
+ const uint16_t *src, int stride, int h)
+{
+ int xp,yp;
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->dstFormat);
+
+ for (yp=0; yp<h; yp++) {
+ for (xp=0; xp+2<stride; xp+=3) {
+ int x, y, z, r, g, b;
+
+ if (desc->flags & AV_PIX_FMT_FLAG_BE) {
+ r = AV_RB16(src + xp + 0);
+ g = AV_RB16(src + xp + 1);
+ b = AV_RB16(src + xp + 2);
+ } else {
+ r = AV_RL16(src + xp + 0);
+ g = AV_RL16(src + xp + 1);
+ b = AV_RL16(src + xp + 2);
+ }
+
+ r = c->rgbgammainv[r>>4];
+ g = c->rgbgammainv[g>>4];
+ b = c->rgbgammainv[b>>4];
+
+ // convert from sRGBlinear to XYZlinear
+ x = c->rgb2xyz_matrix[0][0] * r +
+ c->rgb2xyz_matrix[0][1] * g +
+ c->rgb2xyz_matrix[0][2] * b >> 12;
+ y = c->rgb2xyz_matrix[1][0] * r +
+ c->rgb2xyz_matrix[1][1] * g +
+ c->rgb2xyz_matrix[1][2] * b >> 12;
+ z = c->rgb2xyz_matrix[2][0] * r +
+ c->rgb2xyz_matrix[2][1] * g +
+ c->rgb2xyz_matrix[2][2] * b >> 12;
+
+ // limit values to 12-bit depth
+ x = av_clip_uintp2(x, 12);
+ y = av_clip_uintp2(y, 12);
+ z = av_clip_uintp2(z, 12);
+
+ // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit
+ if (desc->flags & AV_PIX_FMT_FLAG_BE) {
+ AV_WB16(dst + xp + 0, c->xyzgammainv[x] << 4);
+ AV_WB16(dst + xp + 1, c->xyzgammainv[y] << 4);
+ AV_WB16(dst + xp + 2, c->xyzgammainv[z] << 4);
+ } else {
+ AV_WL16(dst + xp + 0, c->xyzgammainv[x] << 4);
+ AV_WL16(dst + xp + 1, c->xyzgammainv[y] << 4);
+ AV_WL16(dst + xp + 2, c->xyzgammainv[z] << 4);
+ }
+ }
+ src += stride;
+ dst += stride;
+ }
+}
+
+/**
+ * swscale wrapper, so we don't need to export the SwsContext.
+ * Assumes planar YUV to be in YUV order instead of YVU.
+ */
+int attribute_align_arg sws_scale(struct SwsContext *c,
+ const uint8_t * const srcSlice[],
+ const int srcStride[], int srcSliceY,
+ int srcSliceH, uint8_t *const dst[],
+ const int dstStride[])
+{
+ int i, ret;
+ const uint8_t *src2[4];
+ uint8_t *dst2[4];
+ uint8_t *rgb0_tmp = NULL;
+
+ if (!srcStride || !dstStride || !dst || !srcSlice) {
+ av_log(c, AV_LOG_ERROR, "One of the input parameters to sws_scale() is NULL, please check the calling code\n");
+ return 0;
+ }
+
+ if (c->gamma_flag && c->cascaded_context[0]) {
+
+
+ ret = sws_scale(c->cascaded_context[0],
+ srcSlice, srcStride, srcSliceY, srcSliceH,
+ c->cascaded_tmp, c->cascaded_tmpStride);
+
+ if (ret < 0)
+ return ret;
+
+ if (c->cascaded_context[2])
+ ret = sws_scale(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp, c->cascaded_tmpStride, srcSliceY, srcSliceH, c->cascaded1_tmp, c->cascaded1_tmpStride);
+ else
+ ret = sws_scale(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp, c->cascaded_tmpStride, srcSliceY, srcSliceH, dst, dstStride);
+
+ if (ret < 0)
+ return ret;
+
+ if (c->cascaded_context[2]) {
+ ret = sws_scale(c->cascaded_context[2],
+ (const uint8_t * const *)c->cascaded1_tmp, c->cascaded1_tmpStride, c->cascaded_context[1]->dstY - ret, c->cascaded_context[1]->dstY,
+ dst, dstStride);
+ }
+ return ret;
+ }
+
+ if (c->cascaded_context[0] && srcSliceY == 0 && srcSliceH == c->cascaded_context[0]->srcH) {
+ ret = sws_scale(c->cascaded_context[0],
+ srcSlice, srcStride, srcSliceY, srcSliceH,
+ c->cascaded_tmp, c->cascaded_tmpStride);
+ if (ret < 0)
+ return ret;
+ ret = sws_scale(c->cascaded_context[1],
+ (const uint8_t * const * )c->cascaded_tmp, c->cascaded_tmpStride, 0, c->cascaded_context[0]->dstH,
+ dst, dstStride);
+ return ret;
+ }
+
+ memcpy(src2, srcSlice, sizeof(src2));
+ memcpy(dst2, dst, sizeof(dst2));
+
+ // do not mess up sliceDir if we have a "trailing" 0-size slice
+ if (srcSliceH == 0)
+ return 0;
+
+ if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) {
+ av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
+ return 0;
+ }
+ if (!check_image_pointers((const uint8_t* const*)dst, c->dstFormat, dstStride)) {
+ av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
+ return 0;
+ }
+
+ if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
+ av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
+ return 0;
+ }
+ if (c->sliceDir == 0) {
+ if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
+ }
+
+ if (usePal(c->srcFormat)) {
+ for (i = 0; i < 256; i++) {
+ int r, g, b, y, u, v, a = 0xff;
+ if (c->srcFormat == AV_PIX_FMT_PAL8) {
+ uint32_t p = ((const uint32_t *)(srcSlice[1]))[i];
+ a = (p >> 24) & 0xFF;
+ r = (p >> 16) & 0xFF;
+ g = (p >> 8) & 0xFF;
+ b = p & 0xFF;
+ } else if (c->srcFormat == AV_PIX_FMT_RGB8) {
+ r = ( i >> 5 ) * 36;
+ g = ((i >> 2) & 7) * 36;
+ b = ( i & 3) * 85;
+ } else if (c->srcFormat == AV_PIX_FMT_BGR8) {
+ b = ( i >> 6 ) * 85;
+ g = ((i >> 3) & 7) * 36;
+ r = ( i & 7) * 36;
+ } else if (c->srcFormat == AV_PIX_FMT_RGB4_BYTE) {
+ r = ( i >> 3 ) * 255;
+ g = ((i >> 1) & 3) * 85;
+ b = ( i & 1) * 255;
+ } else if (c->srcFormat == AV_PIX_FMT_GRAY8 || c->srcFormat == AV_PIX_FMT_GRAY8A) {
+ r = g = b = i;
+ } else {
+ av_assert1(c->srcFormat == AV_PIX_FMT_BGR4_BYTE);
+ b = ( i >> 3 ) * 255;
+ g = ((i >> 1) & 3) * 85;
+ r = ( i & 1) * 255;
+ }
+#define RGB2YUV_SHIFT 15
+#define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+#define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
+
+ y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+ u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+ v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+ c->pal_yuv[i]= y + (u<<8) + (v<<16) + ((unsigned)a<<24);
+
+ switch (c->dstFormat) {
+ case AV_PIX_FMT_BGR32:
+#if !HAVE_BIGENDIAN
+ case AV_PIX_FMT_RGB24:
+#endif
+ c->pal_rgb[i]= r + (g<<8) + (b<<16) + ((unsigned)a<<24);
+ break;
+ case AV_PIX_FMT_BGR32_1:
+#if HAVE_BIGENDIAN
+ case AV_PIX_FMT_BGR24:
+#endif
+ c->pal_rgb[i]= a + (r<<8) + (g<<16) + ((unsigned)b<<24);
+ break;
+ case AV_PIX_FMT_RGB32_1:
+#if HAVE_BIGENDIAN
+ case AV_PIX_FMT_RGB24:
+#endif
+ c->pal_rgb[i]= a + (b<<8) + (g<<16) + ((unsigned)r<<24);
+ break;
+ case AV_PIX_FMT_RGB32:
+#if !HAVE_BIGENDIAN
+ case AV_PIX_FMT_BGR24:
+#endif
+ default:
+ c->pal_rgb[i]= b + (g<<8) + (r<<16) + ((unsigned)a<<24);
+ }
+ }
+ }
+
+ if (c->src0Alpha && !c->dst0Alpha && isALPHA(c->dstFormat)) {
+ uint8_t *base;
+ int x,y;
+ rgb0_tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32);
+ if (!rgb0_tmp)
+ return AVERROR(ENOMEM);
+
+ base = srcStride[0] < 0 ? rgb0_tmp - srcStride[0] * (srcSliceH-1) : rgb0_tmp;
+ for (y=0; y<srcSliceH; y++){
+ memcpy(base + srcStride[0]*y, src2[0] + srcStride[0]*y, 4*c->srcW);
+ for (x=c->src0Alpha-1; x<4*c->srcW; x+=4) {
+ base[ srcStride[0]*y + x] = 0xFF;
+ }
+ }
+ src2[0] = base;
+ }
+
+ if (c->srcXYZ && !(c->dstXYZ && c->srcW==c->dstW && c->srcH==c->dstH)) {
+ uint8_t *base;
+ rgb0_tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32);
+ if (!rgb0_tmp)
+ return AVERROR(ENOMEM);
+
+ base = srcStride[0] < 0 ? rgb0_tmp - srcStride[0] * (srcSliceH-1) : rgb0_tmp;
+
+ xyz12Torgb48(c, (uint16_t*)base, (const uint16_t*)src2[0], srcStride[0]/2, srcSliceH);
+ src2[0] = base;
+ }
+
+ if (!srcSliceY && (c->flags & SWS_BITEXACT) && c->dither == SWS_DITHER_ED && c->dither_error[0])
+ for (i = 0; i < 4; i++)
+ memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (c->dstW+2));
+
+
+ // copy strides, so they can safely be modified
+ if (c->sliceDir == 1) {
+ // slices go from top to bottom
+ int srcStride2[4] = { srcStride[0], srcStride[1], srcStride[2],
+ srcStride[3] };
+ int dstStride2[4] = { dstStride[0], dstStride[1], dstStride[2],
+ dstStride[3] };
+
+ reset_ptr(src2, c->srcFormat);
+ reset_ptr((void*)dst2, c->dstFormat);
+
+ /* reset slice direction at end of frame */
+ if (srcSliceY + srcSliceH == c->srcH)
+ c->sliceDir = 0;
+
+ ret = c->swscale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
+ dstStride2);
+ } else {
+ // slices go from bottom to top => we flip the image internally
+ int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2],
+ -srcStride[3] };
+ int dstStride2[4] = { -dstStride[0], -dstStride[1], -dstStride[2],
+ -dstStride[3] };
+
+ src2[0] += (srcSliceH - 1) * srcStride[0];
+ if (!usePal(c->srcFormat))
+ src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1];
+ src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2];
+ src2[3] += (srcSliceH - 1) * srcStride[3];
+ dst2[0] += ( c->dstH - 1) * dstStride[0];
+ dst2[1] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[1];
+ dst2[2] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[2];
+ dst2[3] += ( c->dstH - 1) * dstStride[3];
+
+ reset_ptr(src2, c->srcFormat);
+ reset_ptr((void*)dst2, c->dstFormat);
+
+ /* reset slice direction at end of frame */
+ if (!srcSliceY)
+ c->sliceDir = 0;
+
+ ret = c->swscale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
+ srcSliceH, dst2, dstStride2);
+ }
+
+
+ if (c->dstXYZ && !(c->srcXYZ && c->srcW==c->dstW && c->srcH==c->dstH)) {
+ /* replace on the same data */
+ rgb48Toxyz12(c, (uint16_t*)dst2[0], (const uint16_t*)dst2[0], dstStride[0]/2, ret);
+ }
+
+ av_free(rgb0_tmp);
+ return ret;
+}
+
diff --git a/libswscale/swscale.h b/libswscale/swscale.h
index 8abbac4761..903e1203fd 100644
--- a/libswscale/swscale.h
+++ b/libswscale/swscale.h
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -24,8 +24,7 @@
/**
* @file
* @ingroup libsws
- * @brief
- * external api for the swscale stuff
+ * external API header
*/
#include <stdint.h>
@@ -81,6 +80,7 @@ const char *swscale_license(void);
#define SWS_DIRECT_BGR 0x8000
#define SWS_ACCURATE_RND 0x40000
#define SWS_BITEXACT 0x80000
+#define SWS_ERROR_DIFFUSION 0x800000
#if FF_API_SWS_CPU_CAPS
/**
@@ -225,7 +225,13 @@ int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
uint8_t *const dst[], const int dstStride[]);
/**
- * @param inv_table the yuv2rgb coefficients, normally ff_yuv2rgb_coeffs[x]
+ * @param dstRange flag indicating the while-black range of the output (1=jpeg / 0=mpeg)
+ * @param srcRange flag indicating the while-black range of the input (1=jpeg / 0=mpeg)
+ * @param table the yuv2rgb coefficients describing the output yuv space, normally ff_yuv2rgb_coeffs[x]
+ * @param inv_table the yuv2rgb coefficients describing the input yuv space, normally ff_yuv2rgb_coeffs[x]
+ * @param brightness 16.16 fixed point brightness correction
+ * @param contrast 16.16 fixed point contrast correction
+ * @param saturation 16.16 fixed point saturation correction
* @return -1 if not supported
*/
int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4],
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index fdaaeeb67f..2299aa5c87 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,18 +27,23 @@
#include <altivec.h>
#endif
+#include "version.h"
+
#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/log.h"
#include "libavutil/pixfmt.h"
#include "libavutil/pixdesc.h"
#define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long
-#define FAST_BGR2YV12 // use 7-bit instead of 15-bit coefficients
+#define YUVRGB_TABLE_HEADROOM 256
+
+#define MAX_FILTER_SIZE SWS_MAX_FILTER_SIZE
-#define MAX_FILTER_SIZE 256
+#define DITHER1XBPP
#if HAVE_BIGENDIAN
#define ALT32_CORR (-1)
@@ -56,8 +61,20 @@
# define APCK_SIZE 16
#endif
+#define RETCODE_USE_CASCADE -12345
+
struct SwsContext;
+typedef enum SwsDither {
+ SWS_DITHER_NONE = 0,
+ SWS_DITHER_AUTO,
+ SWS_DITHER_BAYER,
+ SWS_DITHER_ED,
+ SWS_DITHER_A_DITHER,
+ SWS_DITHER_X_DITHER,
+ NB_SWS_DITHER,
+} SwsDither;
+
typedef int (*SwsFunc)(struct SwsContext *context, const uint8_t *src[],
int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[]);
@@ -286,6 +303,22 @@ typedef struct SwsContext {
int sliceDir; ///< Direction that slices are fed to the scaler (1 = top-to-bottom, -1 = bottom-to-top).
double param[2]; ///< Input parameters for scaling algorithms that need them.
+ /* The cascaded_* fields allow spliting a scaler task into multiple
+ * sequential steps, this is for example used to limit the maximum
+ * downscaling factor that needs to be supported in one scaler.
+ */
+ struct SwsContext *cascaded_context[3];
+ int cascaded_tmpStride[4];
+ uint8_t *cascaded_tmp[4];
+ int cascaded1_tmpStride[4];
+ uint8_t *cascaded1_tmp[4];
+
+ double gamma_value;
+ int gamma_flag;
+ int is_internal_gamma;
+ uint16_t *gamma;
+ uint16_t *inv_gamma;
+
uint32_t pal_yuv[256];
uint32_t pal_rgb[256];
@@ -351,10 +384,25 @@ typedef struct SwsContext {
int dstY; ///< Last destination vertical line output from last slice.
int flags; ///< Flags passed by the user to select scaler algorithm, optimizations, subsampling, etc...
void *yuvTable; // pointer to the yuv->rgb table start so it can be freed()
- uint8_t *table_rV[256];
- uint8_t *table_gU[256];
- int table_gV[256];
- uint8_t *table_bU[256];
+ // alignment ensures the offset can be added in a single
+ // instruction on e.g. ARM
+ DECLARE_ALIGNED(16, int, table_gV)[256 + 2*YUVRGB_TABLE_HEADROOM];
+ uint8_t *table_rV[256 + 2*YUVRGB_TABLE_HEADROOM];
+ uint8_t *table_gU[256 + 2*YUVRGB_TABLE_HEADROOM];
+ uint8_t *table_bU[256 + 2*YUVRGB_TABLE_HEADROOM];
+ DECLARE_ALIGNED(16, int32_t, input_rgb2yuv_table)[16+40*4]; // This table can contain both C and SIMD formatted values, the C vales are always at the XY_IDX points
+#define RY_IDX 0
+#define GY_IDX 1
+#define BY_IDX 2
+#define RU_IDX 3
+#define GU_IDX 4
+#define BU_IDX 5
+#define RV_IDX 6
+#define GV_IDX 7
+#define BV_IDX 8
+#define RGB2YUV_SHIFT 15
+
+ int *dither_error[4];
//Colorspace stuff
int contrast, brightness, saturation; // for sws_getColorspaceDetails
@@ -362,6 +410,14 @@ typedef struct SwsContext {
int dstColorspaceTable[4];
int srcRange; ///< 0 = MPG YUV range, 1 = JPG YUV range (source image).
int dstRange; ///< 0 = MPG YUV range, 1 = JPG YUV range (destination image).
+ int src0Alpha;
+ int dst0Alpha;
+ int srcXYZ;
+ int dstXYZ;
+ int src_h_chr_pos;
+ int dst_h_chr_pos;
+ int src_v_chr_pos;
+ int dst_v_chr_pos;
int yuv2rgb_y_offset;
int yuv2rgb_y_coeff;
int yuv2rgb_v2r_coeff;
@@ -381,18 +437,19 @@ typedef struct SwsContext {
#define U_OFFSET "9*8"
#define V_OFFSET "10*8"
#define LUM_MMX_FILTER_OFFSET "11*8"
-#define CHR_MMX_FILTER_OFFSET "11*8+4*4*256"
-#define DSTW_OFFSET "11*8+4*4*256*2" //do not change, it is hardcoded in the ASM
-#define ESP_OFFSET "11*8+4*4*256*2+8"
-#define VROUNDER_OFFSET "11*8+4*4*256*2+16"
-#define U_TEMP "11*8+4*4*256*2+24"
-#define V_TEMP "11*8+4*4*256*2+32"
-#define Y_TEMP "11*8+4*4*256*2+40"
-#define ALP_MMX_FILTER_OFFSET "11*8+4*4*256*2+48"
-#define UV_OFF_PX "11*8+4*4*256*3+48"
-#define UV_OFF_BYTE "11*8+4*4*256*3+56"
-#define DITHER16 "11*8+4*4*256*3+64"
-#define DITHER32 "11*8+4*4*256*3+80"
+#define CHR_MMX_FILTER_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)
+#define DSTW_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2"
+#define ESP_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+8"
+#define VROUNDER_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+16"
+#define U_TEMP "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+24"
+#define V_TEMP "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+32"
+#define Y_TEMP "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+40"
+#define ALP_MMX_FILTER_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+48"
+#define UV_OFF_PX "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+48"
+#define UV_OFF_BYTE "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+56"
+#define DITHER16 "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+64"
+#define DITHER32 "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+80"
+#define DITHER32_INT (11*8+4*4*MAX_FILTER_SIZE*3+80) // value equal to above, used for checking that the struct hasn't been changed by mistake
DECLARE_ALIGNED(8, uint64_t, redDither);
DECLARE_ALIGNED(8, uint64_t, greenDither);
@@ -418,8 +475,8 @@ typedef struct SwsContext {
// alignment of these values is not necessary, but merely here
// to maintain the same offset across x8632 and x86-64. Once we
// use proper offset macros in the asm, they can be removed.
- DECLARE_ALIGNED(8, ptrdiff_t, uv_off_px); ///< offset (in pixels) between u and v planes
- DECLARE_ALIGNED(8, ptrdiff_t, uv_off_byte); ///< offset (in bytes) between u and v planes
+ DECLARE_ALIGNED(8, ptrdiff_t, uv_off); ///< offset (in pixels) between u and v planes
+ DECLARE_ALIGNED(8, ptrdiff_t, uv_offx2); ///< offset (in bytes) between u and v planes
DECLARE_ALIGNED(8, uint16_t, dither16)[8];
DECLARE_ALIGNED(8, uint32_t, dither32)[8];
@@ -436,6 +493,18 @@ typedef struct SwsContext {
vector signed short *vYCoeffsBank, *vCCoeffsBank;
#endif
+ int use_mmx_vfilter;
+
+/* pre defined color-spaces gamma */
+#define XYZ_GAMMA (2.6f)
+#define RGB_GAMMA (2.2f)
+ int16_t *xyzgamma;
+ int16_t *rgbgamma;
+ int16_t *xyzgammainv;
+ int16_t *rgbgammainv;
+ int16_t xyz2rgb_matrix[3][4];
+ int16_t rgb2xyz_matrix[3][4];
+
/* function pointers for swscale() */
yuv2planar1_fn yuv2plane1;
yuv2planarX_fn yuv2planeX;
@@ -446,14 +515,14 @@ typedef struct SwsContext {
yuv2anyX_fn yuv2anyX;
/// Unscaled conversion of luma plane to YV12 for horizontal scaler.
- void (*lumToYV12)(uint8_t *dst, const uint8_t *src,
+ void (*lumToYV12)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, const uint8_t *src3,
int width, uint32_t *pal);
/// Unscaled conversion of alpha plane to YV12 for horizontal scaler.
- void (*alpToYV12)(uint8_t *dst, const uint8_t *src,
+ void (*alpToYV12)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, const uint8_t *src3,
int width, uint32_t *pal);
/// Unscaled conversion of chroma planes to YV12 for horizontal scaler.
void (*chrToYV12)(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src1, const uint8_t *src2,
+ const uint8_t *src1, const uint8_t *src2, const uint8_t *src3,
int width, uint32_t *pal);
/**
@@ -461,10 +530,10 @@ typedef struct SwsContext {
* internally to Y/UV/A.
*/
/** @{ */
- void (*readLumPlanar)(uint8_t *dst, const uint8_t *src[4], int width);
+ void (*readLumPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv);
void (*readChrPlanar)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4],
- int width);
- void (*readAlpPlanar)(uint8_t *dst, const uint8_t *src[4], int width);
+ int width, int32_t *rgb2yuv);
+ void (*readAlpPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv);
/** @} */
/**
@@ -540,6 +609,8 @@ typedef struct SwsContext {
void (*chrConvertRange)(int16_t *dst1, int16_t *dst2, int width);
int needs_hcscale; ///< Set if there are chroma planes to be converted.
+
+ SwsDither dither;
} SwsContext;
//FIXME check init (where 0)
@@ -550,14 +621,14 @@ int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
void ff_yuv2rgb_init_tables_ppc(SwsContext *c, const int inv_table[4],
int brightness, int contrast, int saturation);
-void updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufIndex,
+void ff_updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufIndex,
int lastInLumBuf, int lastInChrBuf);
+av_cold void ff_sws_init_range_convert(SwsContext *c);
+
SwsFunc ff_yuv2rgb_init_x86(SwsContext *c);
SwsFunc ff_yuv2rgb_init_ppc(SwsContext *c);
-const char *sws_format_name(enum AVPixelFormat format);
-
static av_always_inline int is16BPS(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -569,9 +640,11 @@ static av_always_inline int is9_OR_10BPS(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
av_assert0(desc);
- return desc->comp[0].depth_minus1 == 8 || desc->comp[0].depth_minus1 == 9;
+ return desc->comp[0].depth_minus1 >= 8 && desc->comp[0].depth_minus1 <= 13;
}
+#define isNBPS(x) is9_OR_10BPS(x)
+
static av_always_inline int isBE(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -602,8 +675,8 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
#if 0 // FIXME
#define isGray(x) \
- (!(av_pix_fmt_descriptors[x].flags & AV_PIX_FMT_FLAG_PAL) && \
- av_pix_fmt_descriptors[x].nb_components <= 2)
+ (!(av_pix_fmt_desc_get(x)->flags & AV_PIX_FMT_FLAG_PAL) && \
+ av_pix_fmt_desc_get(x)->nb_components <= 2)
#else
#define isGray(x) \
((x) == AV_PIX_FMT_GRAY8 || \
@@ -614,8 +687,9 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
(x) == AV_PIX_FMT_YA16LE)
#endif
-#define isRGBinInt(x) \
- ((x) == AV_PIX_FMT_RGB48BE || \
+#define isRGBinInt(x) \
+ ( \
+ (x) == AV_PIX_FMT_RGB48BE || \
(x) == AV_PIX_FMT_RGB48LE || \
(x) == AV_PIX_FMT_RGB32 || \
(x) == AV_PIX_FMT_RGB32_1 || \
@@ -632,10 +706,11 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
(x) == AV_PIX_FMT_RGBA64BE || \
(x) == AV_PIX_FMT_RGBA64LE || \
(x) == AV_PIX_FMT_MONOBLACK || \
- (x) == AV_PIX_FMT_MONOWHITE)
-
-#define isBGRinInt(x) \
- ((x) == AV_PIX_FMT_BGR48BE || \
+ (x) == AV_PIX_FMT_MONOWHITE \
+ )
+#define isBGRinInt(x) \
+ ( \
+ (x) == AV_PIX_FMT_BGR48BE || \
(x) == AV_PIX_FMT_BGR48LE || \
(x) == AV_PIX_FMT_BGR32 || \
(x) == AV_PIX_FMT_BGR32_1 || \
@@ -652,19 +727,73 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
(x) == AV_PIX_FMT_BGRA64BE || \
(x) == AV_PIX_FMT_BGRA64LE || \
(x) == AV_PIX_FMT_MONOBLACK || \
- (x) == AV_PIX_FMT_MONOWHITE)
-
-#define isAnyRGB(x) \
- (isRGBinInt(x) || \
- isBGRinInt(x))
+ (x) == AV_PIX_FMT_MONOWHITE \
+ )
+
+#define isRGBinBytes(x) ( \
+ (x) == AV_PIX_FMT_RGB48BE \
+ || (x) == AV_PIX_FMT_RGB48LE \
+ || (x) == AV_PIX_FMT_RGBA64BE \
+ || (x) == AV_PIX_FMT_RGBA64LE \
+ || (x) == AV_PIX_FMT_RGBA \
+ || (x) == AV_PIX_FMT_ARGB \
+ || (x) == AV_PIX_FMT_RGB24 \
+ )
+#define isBGRinBytes(x) ( \
+ (x) == AV_PIX_FMT_BGR48BE \
+ || (x) == AV_PIX_FMT_BGR48LE \
+ || (x) == AV_PIX_FMT_BGRA64BE \
+ || (x) == AV_PIX_FMT_BGRA64LE \
+ || (x) == AV_PIX_FMT_BGRA \
+ || (x) == AV_PIX_FMT_ABGR \
+ || (x) == AV_PIX_FMT_BGR24 \
+ )
+
+#define isBayer(x) ( \
+ (x)==AV_PIX_FMT_BAYER_BGGR8 \
+ || (x)==AV_PIX_FMT_BAYER_BGGR16LE \
+ || (x)==AV_PIX_FMT_BAYER_BGGR16BE \
+ || (x)==AV_PIX_FMT_BAYER_RGGB8 \
+ || (x)==AV_PIX_FMT_BAYER_RGGB16LE \
+ || (x)==AV_PIX_FMT_BAYER_RGGB16BE \
+ || (x)==AV_PIX_FMT_BAYER_GBRG8 \
+ || (x)==AV_PIX_FMT_BAYER_GBRG16LE \
+ || (x)==AV_PIX_FMT_BAYER_GBRG16BE \
+ || (x)==AV_PIX_FMT_BAYER_GRBG8 \
+ || (x)==AV_PIX_FMT_BAYER_GRBG16LE \
+ || (x)==AV_PIX_FMT_BAYER_GRBG16BE \
+ )
+
+#define isAnyRGB(x) \
+ ( \
+ isBayer(x) || \
+ isRGBinInt(x) || \
+ isBGRinInt(x) || \
+ isRGB(x) \
+ )
static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
av_assert0(desc);
- return desc->nb_components == 2 || desc->nb_components == 4;
+ if (pix_fmt == AV_PIX_FMT_PAL8)
+ return 1;
+ return desc->flags & AV_PIX_FMT_FLAG_ALPHA;
}
+#if 1
+#define isPacked(x) ( \
+ (x)==AV_PIX_FMT_PAL8 \
+ || (x)==AV_PIX_FMT_YUYV422 \
+ || (x)==AV_PIX_FMT_YVYU422 \
+ || (x)==AV_PIX_FMT_UYVY422 \
+ || (x)==AV_PIX_FMT_YA8 \
+ || (x)==AV_PIX_FMT_YA16LE \
+ || (x)==AV_PIX_FMT_YA16BE \
+ || isRGBinInt(x) \
+ || isBGRinInt(x) \
+ )
+#else
static av_always_inline int isPacked(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -673,6 +802,7 @@ static av_always_inline int isPacked(enum AVPixelFormat pix_fmt)
pix_fmt == AV_PIX_FMT_PAL8);
}
+#endif
static av_always_inline int isPlanar(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
@@ -699,18 +829,19 @@ static av_always_inline int usePal(enum AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
av_assert0(desc);
- return ((desc->flags & AV_PIX_FMT_FLAG_PAL) || (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) ||
- pix_fmt == AV_PIX_FMT_YA8);
+ return (desc->flags & AV_PIX_FMT_FLAG_PAL) || (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL);
}
extern const uint64_t ff_dither4[2];
extern const uint64_t ff_dither8[2];
-extern const uint8_t ff_dither_4x4_16[4][8];
-extern const uint8_t ff_dither_8x8_32[8][8];
-extern const uint8_t ff_dither_8x8_73[8][8];
-extern const uint8_t ff_dither_8x8_128[8][8];
-extern const uint8_t ff_dither_8x8_220[8][8];
+extern const uint8_t ff_dither_2x2_4[3][8];
+extern const uint8_t ff_dither_2x2_8[3][8];
+extern const uint8_t ff_dither_4x4_16[5][8];
+extern const uint8_t ff_dither_8x8_32[9][8];
+extern const uint8_t ff_dither_8x8_73[9][8];
+extern const uint8_t ff_dither_8x8_128[9][8];
+extern const uint8_t ff_dither_8x8_220[9][8];
extern const int32_t ff_yuv2rgb_coeffs[8][4];
@@ -722,6 +853,7 @@ extern const AVClass sws_context_class;
*/
void ff_get_unscaled_swscale(SwsContext *c);
void ff_get_unscaled_swscale_ppc(SwsContext *c);
+void ff_get_unscaled_swscale_arm(SwsContext *c);
/**
* Return function pointer to fastest main scaler path function depending
@@ -741,4 +873,39 @@ void ff_sws_init_output_funcs(SwsContext *c,
void ff_sws_init_swscale_ppc(SwsContext *c);
void ff_sws_init_swscale_x86(SwsContext *c);
+void ff_hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth,
+ const uint8_t *src, int srcW, int xInc);
+void ff_hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2,
+ int dstWidth, const uint8_t *src1,
+ const uint8_t *src2, int srcW, int xInc);
+int ff_init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode,
+ int16_t *filter, int32_t *filterPos,
+ int numSplits);
+void ff_hyscale_fast_mmxext(SwsContext *c, int16_t *dst,
+ int dstWidth, const uint8_t *src,
+ int srcW, int xInc);
+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);
+
+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>>(15-bits) : (1<<bits);
+ 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);
+ }
+ ptr += stride;
+ }
+}
+
#endif /* SWSCALE_SWSCALE_INTERNAL_H */
diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c
index 699aa60701..b426fa188b 100644
--- a/libswscale/swscale_unscaled.c
+++ b/libswscale/swscale_unscaled.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,7 +23,6 @@
#include <math.h>
#include <stdio.h>
#include "config.h"
-#include <assert.h>
#include "swscale.h"
#include "swscale_internal.h"
#include "rgb2rgb.h"
@@ -33,58 +32,101 @@
#include "libavutil/mathematics.h"
#include "libavutil/bswap.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
-DECLARE_ALIGNED(8, static const uint8_t, dither_8x8_1)[8][8] = {
- { 0, 1, 0, 1, 0, 1, 0, 1,},
- { 1, 0, 1, 0, 1, 0, 1, 0,},
- { 0, 1, 0, 1, 0, 1, 0, 1,},
- { 1, 0, 1, 0, 1, 0, 1, 0,},
- { 0, 1, 0, 1, 0, 1, 0, 1,},
- { 1, 0, 1, 0, 1, 0, 1, 0,},
- { 0, 1, 0, 1, 0, 1, 0, 1,},
- { 1, 0, 1, 0, 1, 0, 1, 0,},
-};
-DECLARE_ALIGNED(8, static const uint8_t, dither_8x8_3)[8][8] = {
- { 1, 2, 1, 2, 1, 2, 1, 2,},
- { 3, 0, 3, 0, 3, 0, 3, 0,},
- { 1, 2, 1, 2, 1, 2, 1, 2,},
- { 3, 0, 3, 0, 3, 0, 3, 0,},
- { 1, 2, 1, 2, 1, 2, 1, 2,},
- { 3, 0, 3, 0, 3, 0, 3, 0,},
- { 1, 2, 1, 2, 1, 2, 1, 2,},
- { 3, 0, 3, 0, 3, 0, 3, 0,},
-};
-DECLARE_ALIGNED(8, static const uint8_t, dither_8x8_64)[8][8] = {
- { 18, 34, 30, 46, 17, 33, 29, 45,},
- { 50, 2, 62, 14, 49, 1, 61, 13,},
- { 26, 42, 22, 38, 25, 41, 21, 37,},
- { 58, 10, 54, 6, 57, 9, 53, 5,},
- { 16, 32, 28, 44, 19, 35, 31, 47,},
- { 48, 0, 60, 12, 51, 3, 63, 15,},
- { 24, 40, 20, 36, 27, 43, 23, 39,},
- { 56, 8, 52, 4, 59, 11, 55, 7,},
-};
-DECLARE_ALIGNED(8, static const uint8_t, dither_8x8_256)[8][8] = {
- { 72, 136, 120, 184, 68, 132, 116, 180,},
- { 200, 8, 248, 56, 196, 4, 244, 52,},
- { 104, 168, 88, 152, 100, 164, 84, 148,},
- { 232, 40, 216, 24, 228, 36, 212, 20,},
- { 64, 128, 102, 176, 76, 140, 124, 188,},
- { 192, 0, 240, 48, 204, 12, 252, 60,},
- { 96, 160, 80, 144, 108, 172, 92, 156,},
- { 224, 32, 208, 16, 236, 44, 220, 28,},
+DECLARE_ALIGNED(8, static const uint8_t, dithers)[8][8][8]={
+{
+ { 0, 1, 0, 1, 0, 1, 0, 1,},
+ { 1, 0, 1, 0, 1, 0, 1, 0,},
+ { 0, 1, 0, 1, 0, 1, 0, 1,},
+ { 1, 0, 1, 0, 1, 0, 1, 0,},
+ { 0, 1, 0, 1, 0, 1, 0, 1,},
+ { 1, 0, 1, 0, 1, 0, 1, 0,},
+ { 0, 1, 0, 1, 0, 1, 0, 1,},
+ { 1, 0, 1, 0, 1, 0, 1, 0,},
+},{
+ { 1, 2, 1, 2, 1, 2, 1, 2,},
+ { 3, 0, 3, 0, 3, 0, 3, 0,},
+ { 1, 2, 1, 2, 1, 2, 1, 2,},
+ { 3, 0, 3, 0, 3, 0, 3, 0,},
+ { 1, 2, 1, 2, 1, 2, 1, 2,},
+ { 3, 0, 3, 0, 3, 0, 3, 0,},
+ { 1, 2, 1, 2, 1, 2, 1, 2,},
+ { 3, 0, 3, 0, 3, 0, 3, 0,},
+},{
+ { 2, 4, 3, 5, 2, 4, 3, 5,},
+ { 6, 0, 7, 1, 6, 0, 7, 1,},
+ { 3, 5, 2, 4, 3, 5, 2, 4,},
+ { 7, 1, 6, 0, 7, 1, 6, 0,},
+ { 2, 4, 3, 5, 2, 4, 3, 5,},
+ { 6, 0, 7, 1, 6, 0, 7, 1,},
+ { 3, 5, 2, 4, 3, 5, 2, 4,},
+ { 7, 1, 6, 0, 7, 1, 6, 0,},
+},{
+ { 4, 8, 7, 11, 4, 8, 7, 11,},
+ { 12, 0, 15, 3, 12, 0, 15, 3,},
+ { 6, 10, 5, 9, 6, 10, 5, 9,},
+ { 14, 2, 13, 1, 14, 2, 13, 1,},
+ { 4, 8, 7, 11, 4, 8, 7, 11,},
+ { 12, 0, 15, 3, 12, 0, 15, 3,},
+ { 6, 10, 5, 9, 6, 10, 5, 9,},
+ { 14, 2, 13, 1, 14, 2, 13, 1,},
+},{
+ { 9, 17, 15, 23, 8, 16, 14, 22,},
+ { 25, 1, 31, 7, 24, 0, 30, 6,},
+ { 13, 21, 11, 19, 12, 20, 10, 18,},
+ { 29, 5, 27, 3, 28, 4, 26, 2,},
+ { 8, 16, 14, 22, 9, 17, 15, 23,},
+ { 24, 0, 30, 6, 25, 1, 31, 7,},
+ { 12, 20, 10, 18, 13, 21, 11, 19,},
+ { 28, 4, 26, 2, 29, 5, 27, 3,},
+},{
+ { 18, 34, 30, 46, 17, 33, 29, 45,},
+ { 50, 2, 62, 14, 49, 1, 61, 13,},
+ { 26, 42, 22, 38, 25, 41, 21, 37,},
+ { 58, 10, 54, 6, 57, 9, 53, 5,},
+ { 16, 32, 28, 44, 19, 35, 31, 47,},
+ { 48, 0, 60, 12, 51, 3, 63, 15,},
+ { 24, 40, 20, 36, 27, 43, 23, 39,},
+ { 56, 8, 52, 4, 59, 11, 55, 7,},
+},{
+ { 18, 34, 30, 46, 17, 33, 29, 45,},
+ { 50, 2, 62, 14, 49, 1, 61, 13,},
+ { 26, 42, 22, 38, 25, 41, 21, 37,},
+ { 58, 10, 54, 6, 57, 9, 53, 5,},
+ { 16, 32, 28, 44, 19, 35, 31, 47,},
+ { 48, 0, 60, 12, 51, 3, 63, 15,},
+ { 24, 40, 20, 36, 27, 43, 23, 39,},
+ { 56, 8, 52, 4, 59, 11, 55, 7,},
+},{
+ { 36, 68, 60, 92, 34, 66, 58, 90,},
+ { 100, 4,124, 28, 98, 2,122, 26,},
+ { 52, 84, 44, 76, 50, 82, 42, 74,},
+ { 116, 20,108, 12,114, 18,106, 10,},
+ { 32, 64, 56, 88, 38, 70, 62, 94,},
+ { 96, 0,120, 24,102, 6,126, 30,},
+ { 48, 80, 40, 72, 54, 86, 46, 78,},
+ { 112, 16,104, 8,118, 22,110, 14,},
+}};
+
+static const uint16_t dither_scale[15][16]={
+{ 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,},
+{ 2, 3, 7, 7, 13, 13, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,},
+{ 3, 3, 4, 15, 15, 29, 57, 57, 57, 113, 113, 113, 113, 113, 113, 113,},
+{ 3, 4, 4, 5, 31, 31, 61, 121, 241, 241, 241, 241, 481, 481, 481, 481,},
+{ 3, 4, 5, 5, 6, 63, 63, 125, 249, 497, 993, 993, 993, 993, 993, 1985,},
+{ 3, 5, 6, 6, 6, 7, 127, 127, 253, 505, 1009, 2017, 4033, 4033, 4033, 4033,},
+{ 3, 5, 6, 7, 7, 7, 8, 255, 255, 509, 1017, 2033, 4065, 8129,16257,16257,},
+{ 3, 5, 6, 8, 8, 8, 8, 9, 511, 511, 1021, 2041, 4081, 8161,16321,32641,},
+{ 3, 5, 7, 8, 9, 9, 9, 9, 10, 1023, 1023, 2045, 4089, 8177,16353,32705,},
+{ 3, 5, 7, 8, 10, 10, 10, 10, 10, 11, 2047, 2047, 4093, 8185,16369,32737,},
+{ 3, 5, 7, 8, 10, 11, 11, 11, 11, 11, 12, 4095, 4095, 8189,16377,32753,},
+{ 3, 5, 7, 9, 10, 12, 12, 12, 12, 12, 12, 13, 8191, 8191,16381,32761,},
+{ 3, 5, 7, 9, 10, 12, 13, 13, 13, 13, 13, 13, 14,16383,16383,32765,},
+{ 3, 5, 7, 9, 10, 12, 14, 14, 14, 14, 14, 14, 14, 15,32767,32767,},
+{ 3, 5, 7, 9, 11, 12, 14, 15, 15, 15, 15, 15, 15, 15, 16,65535,},
};
-#define RGB2YUV_SHIFT 15
-#define BY ( (int) (0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define BV (-(int) (0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define BU ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define GY ( (int) (0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define GV (-(int) (0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define GU (-(int) (0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define RY ( (int) (0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define RV ( (int) (0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
-#define RU (-(int) (0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5))
static void fillPlane(uint8_t *plane, int stride, int width, int height, int y,
uint8_t val)
@@ -97,27 +139,6 @@ static void fillPlane(uint8_t *plane, int stride, int width, int height, int y,
}
}
-static void fill_plane9or10(uint8_t *plane, int stride, int width,
- int height, int y, uint8_t val,
- const int dst_depth, const int big_endian)
-{
- int i, j;
- uint16_t *dst = (uint16_t *) (plane + stride * y);
-#define FILL8TO9_OR_10(wfunc) \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < width; j++) { \
- wfunc(&dst[j], (val << (dst_depth - 8)) | \
- (val >> (16 - dst_depth))); \
- } \
- dst += stride / 2; \
- }
- if (big_endian) {
- FILL8TO9_OR_10(AV_WB16);
- } else {
- FILL8TO9_OR_10(AV_WL16);
- }
-}
-
static void copyPlane(const uint8_t *src, int srcStride,
int srcSliceY, int srcSliceH, int width,
uint8_t *dst, int dstStride)
@@ -321,19 +342,23 @@ static int packed_16bpc_bswap(SwsContext *c, const uint8_t *src[],
int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int i, j;
- int srcstr = srcStride[0] >> 1;
- int dststr = dstStride[0] >> 1;
- uint16_t *dstPtr = (uint16_t *) dst[0];
- const uint16_t *srcPtr = (const uint16_t *) src[0];
- int min_stride = FFMIN(srcstr, dststr);
-
- for (i = 0; i < srcSliceH; i++) {
- for (j = 0; j < min_stride; j++) {
- dstPtr[j] = av_bswap16(srcPtr[j]);
+ int i, j, p;
+
+ for (p = 0; p < 4; p++) {
+ int srcstr = srcStride[p] / 2;
+ int dststr = dstStride[p] / 2;
+ uint16_t *dstPtr = (uint16_t *) dst[p];
+ const uint16_t *srcPtr = (const uint16_t *) src[p];
+ int min_stride = FFMIN(FFABS(srcstr), FFABS(dststr));
+ if(!dstPtr || !srcPtr)
+ continue;
+ for (i = 0; i < (srcSliceH >> c->chrDstVSubSample); i++) {
+ for (j = 0; j < min_stride; j++) {
+ dstPtr[j] = av_bswap16(srcPtr[j]);
+ }
+ srcPtr += srcstr;
+ dstPtr += dststr;
}
- srcPtr += srcstr;
- dstPtr += dststr;
}
return srcSliceH;
@@ -373,7 +398,7 @@ static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
if (!conv)
av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
- sws_format_name(srcFormat), sws_format_name(dstFormat));
+ av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
else {
for (i = 0; i < srcSliceH; i++) {
conv(srcPtr, dstPtr, c->srcW, (uint8_t *) c->pal_rgb);
@@ -385,6 +410,371 @@ static int palToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
return srcSliceH;
}
+static void packed16togbra16(const uint8_t *src, int srcStride,
+ uint16_t *dst[], int dstStride[], int srcSliceH,
+ int src_alpha, int swap, int shift, int width)
+{
+ int x, h, i;
+ int dst_alpha = dst[3] != NULL;
+ for (h = 0; h < srcSliceH; h++) {
+ uint16_t *src_line = (uint16_t *)(src + srcStride * h);
+ switch (swap) {
+ case 3:
+ if (src_alpha && dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[3][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ }
+ } else if (dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[3][x] = 0xFFFF;
+ }
+ } else if (src_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ src_line++;
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift);
+ }
+ }
+ break;
+ case 2:
+ if (src_alpha && dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++ >> shift);
+ dst[1][x] = av_bswap16(*src_line++ >> shift);
+ dst[2][x] = av_bswap16(*src_line++ >> shift);
+ dst[3][x] = av_bswap16(*src_line++ >> shift);
+ }
+ } else if (dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++ >> shift);
+ dst[1][x] = av_bswap16(*src_line++ >> shift);
+ dst[2][x] = av_bswap16(*src_line++ >> shift);
+ dst[3][x] = 0xFFFF;
+ }
+ } else if (src_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++ >> shift);
+ dst[1][x] = av_bswap16(*src_line++ >> shift);
+ dst[2][x] = av_bswap16(*src_line++ >> shift);
+ src_line++;
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++ >> shift);
+ dst[1][x] = av_bswap16(*src_line++ >> shift);
+ dst[2][x] = av_bswap16(*src_line++ >> shift);
+ }
+ }
+ break;
+ case 1:
+ if (src_alpha && dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++) >> shift;
+ dst[1][x] = av_bswap16(*src_line++) >> shift;
+ dst[2][x] = av_bswap16(*src_line++) >> shift;
+ dst[3][x] = av_bswap16(*src_line++) >> shift;
+ }
+ } else if (dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++) >> shift;
+ dst[1][x] = av_bswap16(*src_line++) >> shift;
+ dst[2][x] = av_bswap16(*src_line++) >> shift;
+ dst[3][x] = 0xFFFF;
+ }
+ } else if (src_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++) >> shift;
+ dst[1][x] = av_bswap16(*src_line++) >> shift;
+ dst[2][x] = av_bswap16(*src_line++) >> shift;
+ src_line++;
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = av_bswap16(*src_line++) >> shift;
+ dst[1][x] = av_bswap16(*src_line++) >> shift;
+ dst[2][x] = av_bswap16(*src_line++) >> shift;
+ }
+ }
+ break;
+ default:
+ if (src_alpha && dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = *src_line++ >> shift;
+ dst[1][x] = *src_line++ >> shift;
+ dst[2][x] = *src_line++ >> shift;
+ dst[3][x] = *src_line++ >> shift;
+ }
+ } else if (dst_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = *src_line++ >> shift;
+ dst[1][x] = *src_line++ >> shift;
+ dst[2][x] = *src_line++ >> shift;
+ dst[3][x] = 0xFFFF;
+ }
+ } else if (src_alpha) {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = *src_line++ >> shift;
+ dst[1][x] = *src_line++ >> shift;
+ dst[2][x] = *src_line++ >> shift;
+ src_line++;
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ dst[0][x] = *src_line++ >> shift;
+ dst[1][x] = *src_line++ >> shift;
+ dst[2][x] = *src_line++ >> shift;
+ }
+ }
+ }
+ for (i = 0; i < 4; i++)
+ dst[i] += dstStride[i] >> 1;
+ }
+}
+
+static int Rgb16ToPlanarRgb16Wrapper(SwsContext *c, const uint8_t *src[],
+ int srcStride[], int srcSliceY, int srcSliceH,
+ uint8_t *dst[], int dstStride[])
+{
+ uint16_t *dst2013[] = { (uint16_t *)dst[2], (uint16_t *)dst[0], (uint16_t *)dst[1], (uint16_t *)dst[3] };
+ uint16_t *dst1023[] = { (uint16_t *)dst[1], (uint16_t *)dst[0], (uint16_t *)dst[2], (uint16_t *)dst[3] };
+ int stride2013[] = { dstStride[2], dstStride[0], dstStride[1], dstStride[3] };
+ int stride1023[] = { dstStride[1], dstStride[0], dstStride[2], dstStride[3] };
+ const AVPixFmtDescriptor *src_format = av_pix_fmt_desc_get(c->srcFormat);
+ const AVPixFmtDescriptor *dst_format = av_pix_fmt_desc_get(c->dstFormat);
+ int bpc = dst_format->comp[0].depth_minus1 + 1;
+ int alpha = src_format->flags & AV_PIX_FMT_FLAG_ALPHA;
+ int swap = 0;
+ if ( HAVE_BIGENDIAN && !(src_format->flags & AV_PIX_FMT_FLAG_BE) ||
+ !HAVE_BIGENDIAN && src_format->flags & AV_PIX_FMT_FLAG_BE)
+ swap++;
+ if ( HAVE_BIGENDIAN && !(dst_format->flags & AV_PIX_FMT_FLAG_BE) ||
+ !HAVE_BIGENDIAN && dst_format->flags & AV_PIX_FMT_FLAG_BE)
+ swap += 2;
+
+ if ((dst_format->flags & (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)) !=
+ (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB) || bpc < 9) {
+ av_log(c, AV_LOG_ERROR, "unsupported conversion to planar RGB %s -> %s\n",
+ src_format->name, dst_format->name);
+ return srcSliceH;
+ }
+ switch (c->srcFormat) {
+ case AV_PIX_FMT_RGB48LE:
+ case AV_PIX_FMT_RGB48BE:
+ case AV_PIX_FMT_RGBA64LE:
+ case AV_PIX_FMT_RGBA64BE:
+ packed16togbra16(src[0] + srcSliceY * srcStride[0], srcStride[0],
+ dst2013, stride2013, srcSliceH, alpha, swap,
+ 16 - bpc, c->srcW);
+ break;
+ case AV_PIX_FMT_BGR48LE:
+ case AV_PIX_FMT_BGR48BE:
+ case AV_PIX_FMT_BGRA64LE:
+ case AV_PIX_FMT_BGRA64BE:
+ packed16togbra16(src[0] + srcSliceY * srcStride[0], srcStride[0],
+ dst1023, stride1023, srcSliceH, alpha, swap,
+ 16 - bpc, c->srcW);
+ break;
+ default:
+ av_log(c, AV_LOG_ERROR,
+ "unsupported conversion to planar RGB %s -> %s\n",
+ src_format->name, dst_format->name);
+ }
+
+ return srcSliceH;
+}
+
+static void gbr16ptopacked16(const uint16_t *src[], int srcStride[],
+ uint8_t *dst, int dstStride, int srcSliceH,
+ int alpha, int swap, int bpp, int width)
+{
+ int x, h, i;
+ int src_alpha = src[3] != NULL;
+ int scale_high = 16 - bpp, scale_low = (bpp - 8) * 2;
+ for (h = 0; h < srcSliceH; h++) {
+ uint16_t *dest = (uint16_t *)(dst + dstStride * h);
+ uint16_t component;
+
+ switch(swap) {
+ case 3:
+ if (alpha && !src_alpha) {
+ for (x = 0; x < width; x++) {
+ component = av_bswap16(src[0][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[1][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[2][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ *dest++ = 0xffff;
+ }
+ } else if (alpha && src_alpha) {
+ for (x = 0; x < width; x++) {
+ component = av_bswap16(src[0][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[1][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[2][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[3][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ component = av_bswap16(src[0][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[1][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ component = av_bswap16(src[2][x]);
+ *dest++ = av_bswap16(component << scale_high | component >> scale_low);
+ }
+ }
+ break;
+ case 2:
+ if (alpha && !src_alpha) {
+ for (x = 0; x < width; x++) {
+ *dest++ = av_bswap16(src[0][x] << scale_high | src[0][x] >> scale_low);
+ *dest++ = av_bswap16(src[1][x] << scale_high | src[1][x] >> scale_low);
+ *dest++ = av_bswap16(src[2][x] << scale_high | src[2][x] >> scale_low);
+ *dest++ = 0xffff;
+ }
+ } else if (alpha && src_alpha) {
+ for (x = 0; x < width; x++) {
+ *dest++ = av_bswap16(src[0][x] << scale_high | src[0][x] >> scale_low);
+ *dest++ = av_bswap16(src[1][x] << scale_high | src[1][x] >> scale_low);
+ *dest++ = av_bswap16(src[2][x] << scale_high | src[2][x] >> scale_low);
+ *dest++ = av_bswap16(src[3][x] << scale_high | src[3][x] >> scale_low);
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ *dest++ = av_bswap16(src[0][x] << scale_high | src[0][x] >> scale_low);
+ *dest++ = av_bswap16(src[1][x] << scale_high | src[1][x] >> scale_low);
+ *dest++ = av_bswap16(src[2][x] << scale_high | src[2][x] >> scale_low);
+ }
+ }
+ break;
+ case 1:
+ if (alpha && !src_alpha) {
+ for (x = 0; x < width; x++) {
+ *dest++ = av_bswap16(src[0][x]) << scale_high | av_bswap16(src[0][x]) >> scale_low;
+ *dest++ = av_bswap16(src[1][x]) << scale_high | av_bswap16(src[1][x]) >> scale_low;
+ *dest++ = av_bswap16(src[2][x]) << scale_high | av_bswap16(src[2][x]) >> scale_low;
+ *dest++ = 0xffff;
+ }
+ } else if (alpha && src_alpha) {
+ for (x = 0; x < width; x++) {
+ *dest++ = av_bswap16(src[0][x]) << scale_high | av_bswap16(src[0][x]) >> scale_low;
+ *dest++ = av_bswap16(src[1][x]) << scale_high | av_bswap16(src[1][x]) >> scale_low;
+ *dest++ = av_bswap16(src[2][x]) << scale_high | av_bswap16(src[2][x]) >> scale_low;
+ *dest++ = av_bswap16(src[3][x]) << scale_high | av_bswap16(src[3][x]) >> scale_low;
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ *dest++ = av_bswap16(src[0][x]) << scale_high | av_bswap16(src[0][x]) >> scale_low;
+ *dest++ = av_bswap16(src[1][x]) << scale_high | av_bswap16(src[1][x]) >> scale_low;
+ *dest++ = av_bswap16(src[2][x]) << scale_high | av_bswap16(src[2][x]) >> scale_low;
+ }
+ }
+ break;
+ default:
+ if (alpha && !src_alpha) {
+ for (x = 0; x < width; x++) {
+ *dest++ = src[0][x] << scale_high | src[0][x] >> scale_low;
+ *dest++ = src[1][x] << scale_high | src[1][x] >> scale_low;
+ *dest++ = src[2][x] << scale_high | src[2][x] >> scale_low;
+ *dest++ = 0xffff;
+ }
+ } else if (alpha && src_alpha) {
+ for (x = 0; x < width; x++) {
+ *dest++ = src[0][x] << scale_high | src[0][x] >> scale_low;
+ *dest++ = src[1][x] << scale_high | src[1][x] >> scale_low;
+ *dest++ = src[2][x] << scale_high | src[2][x] >> scale_low;
+ *dest++ = src[3][x] << scale_high | src[3][x] >> scale_low;
+ }
+ } else {
+ for (x = 0; x < width; x++) {
+ *dest++ = src[0][x] << scale_high | src[0][x] >> scale_low;
+ *dest++ = src[1][x] << scale_high | src[1][x] >> scale_low;
+ *dest++ = src[2][x] << scale_high | src[2][x] >> scale_low;
+ }
+ }
+ }
+ for (i = 0; i < 3 + src_alpha; i++)
+ src[i] += srcStride[i] >> 1;
+ }
+}
+
+static int planarRgb16ToRgb16Wrapper(SwsContext *c, const uint8_t *src[],
+ int srcStride[], int srcSliceY, int srcSliceH,
+ uint8_t *dst[], int dstStride[])
+{
+ const uint16_t *src102[] = { (uint16_t *)src[1], (uint16_t *)src[0], (uint16_t *)src[2], (uint16_t *)src[3] };
+ const uint16_t *src201[] = { (uint16_t *)src[2], (uint16_t *)src[0], (uint16_t *)src[1], (uint16_t *)src[3] };
+ int stride102[] = { srcStride[1], srcStride[0], srcStride[2], srcStride[3] };
+ int stride201[] = { srcStride[2], srcStride[0], srcStride[1], srcStride[3] };
+ const AVPixFmtDescriptor *src_format = av_pix_fmt_desc_get(c->srcFormat);
+ const AVPixFmtDescriptor *dst_format = av_pix_fmt_desc_get(c->dstFormat);
+ int bits_per_sample = src_format->comp[0].depth_minus1 + 1;
+ int swap = 0;
+ if ( HAVE_BIGENDIAN && !(src_format->flags & AV_PIX_FMT_FLAG_BE) ||
+ !HAVE_BIGENDIAN && src_format->flags & AV_PIX_FMT_FLAG_BE)
+ swap++;
+ if ( HAVE_BIGENDIAN && !(dst_format->flags & AV_PIX_FMT_FLAG_BE) ||
+ !HAVE_BIGENDIAN && dst_format->flags & AV_PIX_FMT_FLAG_BE)
+ swap += 2;
+
+ if ((src_format->flags & (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)) !=
+ (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB) ||
+ bits_per_sample <= 8) {
+ av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n",
+ src_format->name, dst_format->name);
+ return srcSliceH;
+ }
+ switch (c->dstFormat) {
+ case AV_PIX_FMT_BGR48LE:
+ case AV_PIX_FMT_BGR48BE:
+ gbr16ptopacked16(src102, stride102,
+ dst[0] + srcSliceY * dstStride[0], dstStride[0],
+ srcSliceH, 0, swap, bits_per_sample, c->srcW);
+ break;
+ case AV_PIX_FMT_RGB48LE:
+ case AV_PIX_FMT_RGB48BE:
+ gbr16ptopacked16(src201, stride201,
+ dst[0] + srcSliceY * dstStride[0], dstStride[0],
+ srcSliceH, 0, swap, bits_per_sample, c->srcW);
+ break;
+ case AV_PIX_FMT_RGBA64LE:
+ case AV_PIX_FMT_RGBA64BE:
+ gbr16ptopacked16(src201, stride201,
+ dst[0] + srcSliceY * dstStride[0], dstStride[0],
+ srcSliceH, 1, swap, bits_per_sample, c->srcW);
+ break;
+ case AV_PIX_FMT_BGRA64LE:
+ case AV_PIX_FMT_BGRA64BE:
+ gbr16ptopacked16(src102, stride102,
+ dst[0] + srcSliceY * dstStride[0], dstStride[0],
+ srcSliceH, 1, swap, bits_per_sample, c->srcW);
+ break;
+ default:
+ av_log(c, AV_LOG_ERROR,
+ "unsupported planar RGB conversion %s -> %s\n",
+ src_format->name, dst_format->name);
+ }
+
+ return srcSliceH;
+}
+
static void gbr24ptopacked24(const uint8_t *src[], int srcStride[],
uint8_t *dst, int dstStride, int srcSliceH,
int width)
@@ -579,6 +969,160 @@ static int rgbToPlanarRgbWrapper(SwsContext *c, const uint8_t *src[],
return srcSliceH;
}
+#define BAYER_GBRG
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_gbrg8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GBRG
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_gbrg16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GBRG
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_gbrg16be_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GRBG
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_grbg8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GRBG
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_grbg16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GRBG
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_grbg16be_to_##x
+#include "bayer_template.c"
+
+#define BAYER_BGGR
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_bggr8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_BGGR
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_bggr16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_BGGR
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_bggr16be_to_##x
+#include "bayer_template.c"
+
+#define BAYER_RGGB
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_rggb8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_RGGB
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_rggb16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_RGGB
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_rggb16be_to_##x
+#include "bayer_template.c"
+
+static int bayer_to_rgb24_wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
+ int srcSliceH, uint8_t* dst[], int dstStride[])
+{
+ uint8_t *dstPtr= dst[0];
+ const uint8_t *srcPtr= src[0];
+ int i;
+ void (*copy) (const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width);
+ void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width);
+
+ switch(c->srcFormat) {
+#define CASE(pixfmt, prefix) \
+ case pixfmt: copy = bayer_##prefix##_to_rgb24_copy; \
+ interpolate = bayer_##prefix##_to_rgb24_interpolate; \
+ break;
+ CASE(AV_PIX_FMT_BAYER_BGGR8, bggr8)
+ CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le)
+ CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be)
+ CASE(AV_PIX_FMT_BAYER_RGGB8, rggb8)
+ CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le)
+ CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be)
+ CASE(AV_PIX_FMT_BAYER_GBRG8, gbrg8)
+ CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le)
+ CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be)
+ CASE(AV_PIX_FMT_BAYER_GRBG8, grbg8)
+ CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le)
+ CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be)
+#undef CASE
+ default: return 0;
+ }
+
+ copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->srcW);
+ srcPtr += 2 * srcStride[0];
+ dstPtr += 2 * dstStride[0];
+
+ for (i = 2; i < srcSliceH - 2; i += 2) {
+ interpolate(srcPtr, srcStride[0], dstPtr, dstStride[0], c->srcW);
+ srcPtr += 2 * srcStride[0];
+ dstPtr += 2 * dstStride[0];
+ }
+
+ copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->srcW);
+ return srcSliceH;
+}
+
+static int bayer_to_yv12_wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
+ int srcSliceH, uint8_t* dst[], int dstStride[])
+{
+ const uint8_t *srcPtr= src[0];
+ uint8_t *dstY= dst[0];
+ uint8_t *dstU= dst[1];
+ uint8_t *dstV= dst[2];
+ int i;
+ void (*copy) (const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv);
+ void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv);
+
+ switch(c->srcFormat) {
+#define CASE(pixfmt, prefix) \
+ case pixfmt: copy = bayer_##prefix##_to_yv12_copy; \
+ interpolate = bayer_##prefix##_to_yv12_interpolate; \
+ break;
+ CASE(AV_PIX_FMT_BAYER_BGGR8, bggr8)
+ CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le)
+ CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be)
+ CASE(AV_PIX_FMT_BAYER_RGGB8, rggb8)
+ CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le)
+ CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be)
+ CASE(AV_PIX_FMT_BAYER_GBRG8, gbrg8)
+ CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le)
+ CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be)
+ CASE(AV_PIX_FMT_BAYER_GRBG8, grbg8)
+ CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le)
+ CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be)
+#undef CASE
+ default: return 0;
+ }
+
+ copy(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->srcW, c->input_rgb2yuv_table);
+ srcPtr += 2 * srcStride[0];
+ dstY += 2 * dstStride[0];
+ dstU += dstStride[1];
+ dstV += dstStride[1];
+
+ for (i = 2; i < srcSliceH - 2; i += 2) {
+ interpolate(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->srcW, c->input_rgb2yuv_table);
+ srcPtr += 2 * srcStride[0];
+ dstY += 2 * dstStride[0];
+ dstU += dstStride[1];
+ dstV += dstStride[1];
+ }
+
+ copy(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->srcW, c->input_rgb2yuv_table);
+ return srcSliceH;
+}
+
#define isRGBA32(x) ( \
(x) == AV_PIX_FMT_ARGB \
|| (x) == AV_PIX_FMT_RGBA \
@@ -586,6 +1130,20 @@ static int rgbToPlanarRgbWrapper(SwsContext *c, const uint8_t *src[],
|| (x) == AV_PIX_FMT_ABGR \
)
+#define isRGBA64(x) ( \
+ (x) == AV_PIX_FMT_RGBA64LE \
+ || (x) == AV_PIX_FMT_RGBA64BE \
+ || (x) == AV_PIX_FMT_BGRA64LE \
+ || (x) == AV_PIX_FMT_BGRA64BE \
+ )
+
+#define isRGB48(x) ( \
+ (x) == AV_PIX_FMT_RGB48LE \
+ || (x) == AV_PIX_FMT_RGB48BE \
+ || (x) == AV_PIX_FMT_BGR48LE \
+ || (x) == AV_PIX_FMT_BGR48BE \
+ )
+
/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */
typedef void (* rgbConvFn) (const uint8_t *, uint8_t *, int);
static rgbConvFn findRgbConvFn(SwsContext *c)
@@ -595,17 +1153,11 @@ static rgbConvFn findRgbConvFn(SwsContext *c)
const int srcId = c->srcFormatBpp;
const int dstId = c->dstFormatBpp;
rgbConvFn conv = NULL;
- const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(srcFormat);
- const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(dstFormat);
#define IS_NOT_NE(bpp, desc) \
(((bpp + 7) >> 3) == 2 && \
(!(desc->flags & AV_PIX_FMT_FLAG_BE) != !HAVE_BIGENDIAN))
- /* if this is non-native rgb444/555/565, don't handle it here. */
- if (IS_NOT_NE(srcId, desc_src) || IS_NOT_NE(dstId, desc_dst))
- return NULL;
-
#define CONV_IS(src, dst) (srcFormat == AV_PIX_FMT_##src && dstFormat == AV_PIX_FMT_##dst)
if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) {
@@ -621,6 +1173,32 @@ static rgbConvFn findRgbConvFn(SwsContext *c)
|| CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103;
else if (CONV_IS(BGRA, ABGR)
|| CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012;
+ } else if (isRGB48(srcFormat) && isRGB48(dstFormat)) {
+ if (CONV_IS(RGB48LE, BGR48LE)
+ || CONV_IS(BGR48LE, RGB48LE)
+ || CONV_IS(RGB48BE, BGR48BE)
+ || CONV_IS(BGR48BE, RGB48BE)) conv = rgb48tobgr48_nobswap;
+ else if (CONV_IS(RGB48LE, BGR48BE)
+ || CONV_IS(BGR48LE, RGB48BE)
+ || CONV_IS(RGB48BE, BGR48LE)
+ || CONV_IS(BGR48BE, RGB48LE)) conv = rgb48tobgr48_bswap;
+ } else if (isRGBA64(srcFormat) && isRGB48(dstFormat)) {
+ if (CONV_IS(RGBA64LE, BGR48LE)
+ || CONV_IS(BGRA64LE, RGB48LE)
+ || CONV_IS(RGBA64BE, BGR48BE)
+ || CONV_IS(BGRA64BE, RGB48BE)) conv = rgb64tobgr48_nobswap;
+ else if (CONV_IS(RGBA64LE, BGR48BE)
+ || CONV_IS(BGRA64LE, RGB48BE)
+ || CONV_IS(RGBA64BE, BGR48LE)
+ || CONV_IS(BGRA64BE, RGB48LE)) conv = rgb64tobgr48_bswap;
+ else if (CONV_IS(RGBA64LE, RGB48LE)
+ || CONV_IS(BGRA64LE, BGR48LE)
+ || CONV_IS(RGBA64BE, RGB48BE)
+ || CONV_IS(BGRA64BE, BGR48BE)) conv = rgb64to48_nobswap;
+ else if (CONV_IS(RGBA64LE, RGB48BE)
+ || CONV_IS(BGRA64LE, BGR48BE)
+ || CONV_IS(RGBA64BE, RGB48LE)
+ || CONV_IS(BGRA64BE, BGR48LE)) conv = rgb64to48_bswap;
} else
/* BGR -> BGR */
if ((isBGRinInt(srcFormat) && isBGRinInt(dstFormat)) ||
@@ -662,6 +1240,9 @@ static rgbConvFn findRgbConvFn(SwsContext *c)
}
}
+ if ((dstFormat == AV_PIX_FMT_RGB32_1 || dstFormat == AV_PIX_FMT_BGR32_1) && !isRGBA32(srcFormat) && ALT32_CORR<0)
+ return NULL;
+
return conv;
}
@@ -673,34 +1254,52 @@ static int rgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[],
{
const enum AVPixelFormat srcFormat = c->srcFormat;
const enum AVPixelFormat dstFormat = c->dstFormat;
+ const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(c->srcFormat);
+ const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->dstFormat);
const int srcBpp = (c->srcFormatBpp + 7) >> 3;
const int dstBpp = (c->dstFormatBpp + 7) >> 3;
rgbConvFn conv = findRgbConvFn(c);
if (!conv) {
av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n",
- sws_format_name(srcFormat), sws_format_name(dstFormat));
+ av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
} else {
const uint8_t *srcPtr = src[0];
uint8_t *dstPtr = dst[0];
+ int src_bswap = IS_NOT_NE(c->srcFormatBpp, desc_src);
+ int dst_bswap = IS_NOT_NE(c->dstFormatBpp, desc_dst);
+
if ((srcFormat == AV_PIX_FMT_RGB32_1 || srcFormat == AV_PIX_FMT_BGR32_1) &&
!isRGBA32(dstFormat))
srcPtr += ALT32_CORR;
if ((dstFormat == AV_PIX_FMT_RGB32_1 || dstFormat == AV_PIX_FMT_BGR32_1) &&
- !isRGBA32(srcFormat))
+ !isRGBA32(srcFormat)) {
+ int i;
+ av_assert0(ALT32_CORR == 1);
+ for (i = 0; i < srcSliceH; i++)
+ dstPtr[dstStride[0] * (srcSliceY + i)] = 255;
dstPtr += ALT32_CORR;
+ }
if (dstStride[0] * srcBpp == srcStride[0] * dstBpp && srcStride[0] > 0 &&
- !(srcStride[0] % srcBpp))
+ !(srcStride[0] % srcBpp) && !dst_bswap && !src_bswap)
conv(srcPtr, dstPtr + dstStride[0] * srcSliceY,
(srcSliceH - 1) * srcStride[0] + c->srcW * srcBpp);
else {
- int i;
+ int i, j;
dstPtr += dstStride[0] * srcSliceY;
for (i = 0; i < srcSliceH; i++) {
- conv(srcPtr, dstPtr, c->srcW * srcBpp);
+ if(src_bswap) {
+ for(j=0; j<c->srcW; j++)
+ ((uint16_t*)c->formatConvBuffer)[j] = av_bswap16(((uint16_t*)srcPtr)[j]);
+ conv(c->formatConvBuffer, dstPtr, c->srcW * srcBpp);
+ }else
+ conv(srcPtr, dstPtr, c->srcW * srcBpp);
+ if(dst_bswap)
+ for(j=0; j<c->srcW; j++)
+ ((uint16_t*)dstPtr)[j] = av_bswap16(((uint16_t*)dstPtr)[j]);
srcPtr += srcStride[0];
dstPtr += dstStride[0];
}
@@ -713,13 +1312,14 @@ static int bgr24ToYv12Wrapper(SwsContext *c, const uint8_t *src[],
int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- rgb24toyv12(
+ ff_rgb24toyv12(
src[0],
dst[0] + srcSliceY * dstStride[0],
dst[1] + (srcSliceY >> 1) * dstStride[1],
dst[2] + (srcSliceY >> 1) * dstStride[2],
c->srcW, srcSliceH,
- dstStride[0], dstStride[1], srcStride[0]);
+ dstStride[0], dstStride[1], srcStride[0],
+ c->input_rgb2yuv_table);
if (dst[3])
fillPlane(dst[3], dstStride[3], c->srcW, srcSliceH, srcSliceY, 255);
return srcSliceH;
@@ -758,7 +1358,7 @@ static int packedCopyWrapper(SwsContext *c, const uint8_t *src[],
while (length + c->srcW <= FFABS(dstStride[0]) &&
length + c->srcW <= FFABS(srcStride[0]))
length += c->srcW;
- assert(length != 0);
+ av_assert1(length != 0);
for (i = 0; i < srcSliceH; i++) {
memcpy(dstPtr, srcPtr, length);
@@ -769,25 +1369,25 @@ static int packedCopyWrapper(SwsContext *c, const uint8_t *src[],
return srcSliceH;
}
-#define clip9(x) av_clip_uintp2(x, 9)
-#define clip10(x) av_clip_uintp2(x, 10)
-#define DITHER_COPY(dst, dstStride, wfunc, src, srcStride, rfunc, dithers, shift, clip) \
- for (i = 0; i < height; i++) { \
- const uint8_t *dither = dithers[i & 7]; \
- for (j = 0; j < length - 7; j += 8) { \
- wfunc(&dst[j + 0], clip((rfunc(&src[j + 0]) + dither[0]) >> shift)); \
- wfunc(&dst[j + 1], clip((rfunc(&src[j + 1]) + dither[1]) >> shift)); \
- wfunc(&dst[j + 2], clip((rfunc(&src[j + 2]) + dither[2]) >> shift)); \
- wfunc(&dst[j + 3], clip((rfunc(&src[j + 3]) + dither[3]) >> shift)); \
- wfunc(&dst[j + 4], clip((rfunc(&src[j + 4]) + dither[4]) >> shift)); \
- wfunc(&dst[j + 5], clip((rfunc(&src[j + 5]) + dither[5]) >> shift)); \
- wfunc(&dst[j + 6], clip((rfunc(&src[j + 6]) + dither[6]) >> shift)); \
- wfunc(&dst[j + 7], clip((rfunc(&src[j + 7]) + dither[7]) >> shift)); \
- } \
- for (; j < length; j++) \
- wfunc(&dst[j], (rfunc(&src[j]) + dither[j & 7]) >> shift); \
- dst += dstStride; \
- src += srcStride; \
+#define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\
+ uint16_t scale= dither_scale[dst_depth-1][src_depth-1];\
+ int shift= src_depth-dst_depth + dither_scale[src_depth-2][dst_depth-1];\
+ for (i = 0; i < height; i++) {\
+ const uint8_t *dither= dithers[src_depth-9][i&7];\
+ for (j = 0; j < length-7; j+=8){\
+ dst[j+0] = dbswap((bswap(src[j+0]) + dither[0])*scale>>shift);\
+ dst[j+1] = dbswap((bswap(src[j+1]) + dither[1])*scale>>shift);\
+ dst[j+2] = dbswap((bswap(src[j+2]) + dither[2])*scale>>shift);\
+ dst[j+3] = dbswap((bswap(src[j+3]) + dither[3])*scale>>shift);\
+ dst[j+4] = dbswap((bswap(src[j+4]) + dither[4])*scale>>shift);\
+ dst[j+5] = dbswap((bswap(src[j+5]) + dither[5])*scale>>shift);\
+ dst[j+6] = dbswap((bswap(src[j+6]) + dither[6])*scale>>shift);\
+ dst[j+7] = dbswap((bswap(src[j+7]) + dither[7])*scale>>shift);\
+ }\
+ for (; j < length; j++)\
+ dst[j] = dbswap((bswap(src[j]) + dither[j&7])*scale>>shift);\
+ dst += dstStride;\
+ src += srcStride;\
}
static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
@@ -798,9 +1398,9 @@ static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->dstFormat);
int plane, i, j;
for (plane = 0; plane < 4; plane++) {
- int length = (plane == 0 || plane == 3) ? c->srcW : -((-c->srcW ) >> c->chrDstHSubSample);
- int y = (plane == 0 || plane == 3) ? srcSliceY: -((-srcSliceY) >> c->chrDstVSubSample);
- int height = (plane == 0 || plane == 3) ? srcSliceH: -((-srcSliceH) >> c->chrDstVSubSample);
+ int length = (plane == 0 || plane == 3) ? c->srcW : FF_CEIL_RSHIFT(c->srcW, c->chrDstHSubSample);
+ int y = (plane == 0 || plane == 3) ? srcSliceY: FF_CEIL_RSHIFT(srcSliceY, c->chrDstVSubSample);
+ int height = (plane == 0 || plane == 3) ? srcSliceH: FF_CEIL_RSHIFT(srcSliceH, c->chrDstVSubSample);
const uint8_t *srcPtr = src[plane];
uint8_t *dstPtr = dst[plane] + dstStride[plane] * y;
int shiftonly = plane == 1 || plane == 2 || (!c->srcRange && plane == 0);
@@ -810,185 +1410,117 @@ static int planarCopyWrapper(SwsContext *c, const uint8_t *src[],
// ignore palette for GRAY8
if (plane == 1 && !dst[2]) continue;
if (!src[plane] || (plane == 1 && !src[2])) {
- int val = (plane == 3) ? 255 : 128;
- if (is16BPS(c->dstFormat))
- length *= 2;
- if (is9_OR_10BPS(c->dstFormat)) {
- fill_plane9or10(dst[plane], dstStride[plane],
- length, height, y, val,
- desc_dst->comp[plane].depth_minus1 + 1,
- isBE(c->dstFormat));
- } else
+ if (is16BPS(c->dstFormat) || isNBPS(c->dstFormat)) {
+ fillPlane16(dst[plane], dstStride[plane], length, height, y,
+ plane == 3, desc_dst->comp[plane].depth_minus1,
+ isBE(c->dstFormat));
+ } else {
fillPlane(dst[plane], dstStride[plane], length, height, y,
- val);
+ (plane == 3) ? 255 : 128);
+ }
} else {
- if (is9_OR_10BPS(c->srcFormat)) {
+ if(isNBPS(c->srcFormat) || isNBPS(c->dstFormat)
+ || (is16BPS(c->srcFormat) != is16BPS(c->dstFormat))
+ ) {
const int src_depth = desc_src->comp[plane].depth_minus1 + 1;
const int dst_depth = desc_dst->comp[plane].depth_minus1 + 1;
const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
+ uint16_t *dstPtr2 = (uint16_t*)dstPtr;
- if (is16BPS(c->dstFormat)) {
- uint16_t *dstPtr2 = (uint16_t *) dstPtr;
-#define COPY9_OR_10TO16(rfunc, wfunc) \
- if (shiftonly) { \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < length; j++) { \
- int srcpx = rfunc(&srcPtr2[j]); \
- wfunc(&dstPtr2[j], srcpx << (16 - src_depth)); \
- } \
- dstPtr2 += dstStride[plane] / 2; \
- srcPtr2 += srcStride[plane] / 2; \
- } \
- } else { \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < length; j++) { \
- int srcpx = rfunc(&srcPtr2[j]); \
- wfunc(&dstPtr2[j], (srcpx << (16 - src_depth)) | (srcpx >> (2 * src_depth - 16))); \
- } \
- dstPtr2 += dstStride[plane] / 2; \
- srcPtr2 += srcStride[plane] / 2; \
- } \
+ if (dst_depth == 8) {
+ if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
+ DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, , )
+ } else {
+ DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, av_bswap16, )
}
- if (isBE(c->dstFormat)) {
- if (isBE(c->srcFormat)) {
- COPY9_OR_10TO16(AV_RB16, AV_WB16);
- } else {
- COPY9_OR_10TO16(AV_RL16, AV_WB16);
+ } else if (src_depth == 8) {
+ for (i = 0; i < height; i++) {
+ #define COPY816(w)\
+ if (shiftonly) {\
+ for (j = 0; j < length; j++)\
+ w(&dstPtr2[j], srcPtr[j]<<(dst_depth-8));\
+ } else {\
+ for (j = 0; j < length; j++)\
+ w(&dstPtr2[j], (srcPtr[j]<<(dst_depth-8)) |\
+ (srcPtr[j]>>(2*8-dst_depth)));\
}
- } else {
- if (isBE(c->srcFormat)) {
- COPY9_OR_10TO16(AV_RB16, AV_WL16);
+ if(isBE(c->dstFormat)){
+ COPY816(AV_WB16)
} else {
- COPY9_OR_10TO16(AV_RL16, AV_WL16);
+ COPY816(AV_WL16)
}
+ dstPtr2 += dstStride[plane]/2;
+ srcPtr += srcStride[plane];
}
- } else if (is9_OR_10BPS(c->dstFormat)) {
- uint16_t *dstPtr2 = (uint16_t *) dstPtr;
-#define COPY9_OR_10TO9_OR_10(loop) \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < length; j++) { \
- loop; \
- } \
- dstPtr2 += dstStride[plane] / 2; \
- srcPtr2 += srcStride[plane] / 2; \
- }
-#define COPY9_OR_10TO9_OR_10_2(rfunc, wfunc) \
- if (dst_depth > src_depth) { \
- COPY9_OR_10TO9_OR_10(int srcpx = rfunc(&srcPtr2[j]); \
- wfunc(&dstPtr2[j], (srcpx << 1) | (srcpx >> 9))); \
- } else if (dst_depth < src_depth) { \
- DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
- srcPtr2, srcStride[plane] / 2, rfunc, \
- dither_8x8_1, 1, clip9); \
- } else { \
- COPY9_OR_10TO9_OR_10(wfunc(&dstPtr2[j], rfunc(&srcPtr2[j]))); \
- }
- if (isBE(c->dstFormat)) {
- if (isBE(c->srcFormat)) {
- COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WB16);
- } else {
- COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WB16);
+ } else if (src_depth <= dst_depth) {
+ for (i = 0; i < height; i++) {
+ j = 0;
+ if(isBE(c->srcFormat) == HAVE_BIGENDIAN &&
+ isBE(c->dstFormat) == HAVE_BIGENDIAN &&
+ shiftonly) {
+ unsigned shift = dst_depth - src_depth;
+#if HAVE_FAST_64BIT
+#define FAST_COPY_UP(shift) \
+ for (; j < length - 3; j += 4) { \
+ uint64_t v = AV_RN64A(srcPtr2 + j); \
+ AV_WN64A(dstPtr2 + j, v << shift); \
+ }
+#else
+#define FAST_COPY_UP(shift) \
+ for (; j < length - 1; j += 2) { \
+ uint32_t v = AV_RN32A(srcPtr2 + j); \
+ AV_WN32A(dstPtr2 + j, v << shift); \
+ }
+#endif
+ switch (shift)
+ {
+ case 6: FAST_COPY_UP(6); break;
+ case 7: FAST_COPY_UP(7); break;
+ }
}
- } else {
- if (isBE(c->srcFormat)) {
- COPY9_OR_10TO9_OR_10_2(AV_RB16, AV_WL16);
+#define COPY_UP(r,w) \
+ if(shiftonly){\
+ for (; j < length; j++){ \
+ unsigned int v= r(&srcPtr2[j]);\
+ w(&dstPtr2[j], v<<(dst_depth-src_depth));\
+ }\
+ }else{\
+ for (; j < length; j++){ \
+ unsigned int v= r(&srcPtr2[j]);\
+ w(&dstPtr2[j], (v<<(dst_depth-src_depth)) | \
+ (v>>(2*src_depth-dst_depth)));\
+ }\
+ }
+ if(isBE(c->srcFormat)){
+ if(isBE(c->dstFormat)){
+ COPY_UP(AV_RB16, AV_WB16)
+ } else {
+ COPY_UP(AV_RB16, AV_WL16)
+ }
} else {
- COPY9_OR_10TO9_OR_10_2(AV_RL16, AV_WL16);
+ if(isBE(c->dstFormat)){
+ COPY_UP(AV_RL16, AV_WB16)
+ } else {
+ COPY_UP(AV_RL16, AV_WL16)
+ }
}
+ dstPtr2 += dstStride[plane]/2;
+ srcPtr2 += srcStride[plane]/2;
}
} else {
-#define W8(a, b) { *(a) = (b); }
-#define COPY9_OR_10TO8(rfunc) \
- if (src_depth == 9) { \
- DITHER_COPY(dstPtr, dstStride[plane], W8, \
- srcPtr2, srcStride[plane] / 2, rfunc, \
- dither_8x8_1, 1, av_clip_uint8); \
- } else { \
- DITHER_COPY(dstPtr, dstStride[plane], W8, \
- srcPtr2, srcStride[plane] / 2, rfunc, \
- dither_8x8_3, 2, av_clip_uint8); \
- }
- if (isBE(c->srcFormat)) {
- COPY9_OR_10TO8(AV_RB16);
- } else {
- COPY9_OR_10TO8(AV_RL16);
- }
- }
- } else if (is9_OR_10BPS(c->dstFormat)) {
- const int dst_depth = desc_dst->comp[plane].depth_minus1 + 1;
- uint16_t *dstPtr2 = (uint16_t *) dstPtr;
-
- if (is16BPS(c->srcFormat)) {
- const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
-#define COPY16TO9_OR_10(rfunc, wfunc) \
- if (dst_depth == 9) { \
- DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
- srcPtr2, srcStride[plane] / 2, rfunc, \
- ff_dither_8x8_128, 7, clip9); \
- } else { \
- DITHER_COPY(dstPtr2, dstStride[plane] / 2, wfunc, \
- srcPtr2, srcStride[plane] / 2, rfunc, \
- dither_8x8_64, 6, clip10); \
- }
- if (isBE(c->dstFormat)) {
- if (isBE(c->srcFormat)) {
- COPY16TO9_OR_10(AV_RB16, AV_WB16);
+ if(isBE(c->srcFormat) == HAVE_BIGENDIAN){
+ if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
+ DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , )
} else {
- COPY16TO9_OR_10(AV_RL16, AV_WB16);
+ DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , av_bswap16)
}
- } else {
- if (isBE(c->srcFormat)) {
- COPY16TO9_OR_10(AV_RB16, AV_WL16);
+ }else{
+ if(isBE(c->dstFormat) == HAVE_BIGENDIAN){
+ DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, )
} else {
- COPY16TO9_OR_10(AV_RL16, AV_WL16);
+ DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, av_bswap16)
}
}
- } else /* 8bit */ {
-#define COPY8TO9_OR_10(wfunc) \
- if (shiftonly) { \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < length; j++) { \
- const int srcpx = srcPtr[j]; \
- wfunc(&dstPtr2[j], srcpx << (dst_depth - 8)); \
- } \
- dstPtr2 += dstStride[plane] / 2; \
- srcPtr += srcStride[plane]; \
- } \
- } else { \
- for (i = 0; i < height; i++) { \
- for (j = 0; j < length; j++) { \
- const int srcpx = srcPtr[j]; \
- wfunc(&dstPtr2[j], (srcpx << (dst_depth - 8)) | (srcpx >> (16 - dst_depth))); \
- } \
- dstPtr2 += dstStride[plane] / 2; \
- srcPtr += srcStride[plane]; \
- } \
- }
- if (isBE(c->dstFormat)) {
- COPY8TO9_OR_10(AV_WB16);
- } else {
- COPY8TO9_OR_10(AV_WL16);
- }
- }
- } else if (is16BPS(c->srcFormat) && !is16BPS(c->dstFormat)) {
- const uint16_t *srcPtr2 = (const uint16_t *) srcPtr;
-#define COPY16TO8(rfunc) \
- DITHER_COPY(dstPtr, dstStride[plane], W8, \
- srcPtr2, srcStride[plane] / 2, rfunc, \
- dither_8x8_256, 8, av_clip_uint8);
- if (isBE(c->srcFormat)) {
- COPY16TO8(AV_RB16);
- } else {
- COPY16TO8(AV_RL16);
- }
- } else if (!is16BPS(c->srcFormat) && is16BPS(c->dstFormat)) {
- for (i = 0; i < height; i++) {
- for (j = 0; j < length; j++) {
- dstPtr[ j << 1 ] = srcPtr[j];
- dstPtr[(j << 1) + 1] = srcPtr[j];
- }
- srcPtr += srcStride[plane];
- dstPtr += dstStride[plane];
}
} else if (is16BPS(c->srcFormat) && is16BPS(c->dstFormat) &&
isBE(c->srcFormat) != isBE(c->dstFormat)) {
@@ -1050,11 +1582,11 @@ void ff_get_unscaled_swscale(SwsContext *c)
/* yuv2bgr */
if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUV422P ||
srcFormat == AV_PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) &&
- !(flags & SWS_ACCURATE_RND) && !(dstH & 1)) {
+ !(flags & SWS_ACCURATE_RND) && (c->dither == SWS_DITHER_BAYER || c->dither == SWS_DITHER_AUTO) && !(dstH & 1)) {
c->swscale = ff_yuv2rgb_get_func_ptr(c);
}
- if (srcFormat == AV_PIX_FMT_YUV410P &&
+ if (srcFormat == AV_PIX_FMT_YUV410P && !(dstH & 3) &&
(dstFormat == AV_PIX_FMT_YUV420P || dstFormat == AV_PIX_FMT_YUVA420P) &&
!(flags & SWS_BITEXACT)) {
c->swscale = yvu9ToYv12Wrapper;
@@ -1087,34 +1619,91 @@ void ff_get_unscaled_swscale(SwsContext *c)
if (srcFormat == AV_PIX_FMT_GBRP && isPlanar(srcFormat) && isByteRGB(dstFormat))
c->swscale = planarRgbToRgbWrapper;
+ if ((srcFormat == AV_PIX_FMT_RGB48LE || srcFormat == AV_PIX_FMT_RGB48BE ||
+ srcFormat == AV_PIX_FMT_BGR48LE || srcFormat == AV_PIX_FMT_BGR48BE ||
+ srcFormat == AV_PIX_FMT_RGBA64LE || srcFormat == AV_PIX_FMT_RGBA64BE ||
+ srcFormat == AV_PIX_FMT_BGRA64LE || srcFormat == AV_PIX_FMT_BGRA64BE) &&
+ (dstFormat == AV_PIX_FMT_GBRP9LE || dstFormat == AV_PIX_FMT_GBRP9BE ||
+ dstFormat == AV_PIX_FMT_GBRP10LE || dstFormat == AV_PIX_FMT_GBRP10BE ||
+ dstFormat == AV_PIX_FMT_GBRP12LE || dstFormat == AV_PIX_FMT_GBRP12BE ||
+ dstFormat == AV_PIX_FMT_GBRP14LE || dstFormat == AV_PIX_FMT_GBRP14BE ||
+ dstFormat == AV_PIX_FMT_GBRP16LE || dstFormat == AV_PIX_FMT_GBRP16BE ||
+ dstFormat == AV_PIX_FMT_GBRAP16LE || dstFormat == AV_PIX_FMT_GBRAP16BE ))
+ c->swscale = Rgb16ToPlanarRgb16Wrapper;
+
+ if ((srcFormat == AV_PIX_FMT_GBRP9LE || srcFormat == AV_PIX_FMT_GBRP9BE ||
+ srcFormat == AV_PIX_FMT_GBRP16LE || srcFormat == AV_PIX_FMT_GBRP16BE ||
+ srcFormat == AV_PIX_FMT_GBRP10LE || srcFormat == AV_PIX_FMT_GBRP10BE ||
+ srcFormat == AV_PIX_FMT_GBRP12LE || srcFormat == AV_PIX_FMT_GBRP12BE ||
+ srcFormat == AV_PIX_FMT_GBRP14LE || srcFormat == AV_PIX_FMT_GBRP14BE ||
+ srcFormat == AV_PIX_FMT_GBRAP16LE || srcFormat == AV_PIX_FMT_GBRAP16BE) &&
+ (dstFormat == AV_PIX_FMT_RGB48LE || dstFormat == AV_PIX_FMT_RGB48BE ||
+ dstFormat == AV_PIX_FMT_BGR48LE || dstFormat == AV_PIX_FMT_BGR48BE ||
+ dstFormat == AV_PIX_FMT_RGBA64LE || dstFormat == AV_PIX_FMT_RGBA64BE ||
+ dstFormat == AV_PIX_FMT_BGRA64LE || dstFormat == AV_PIX_FMT_BGRA64BE))
+ c->swscale = planarRgb16ToRgb16Wrapper;
+
if (av_pix_fmt_desc_get(srcFormat)->comp[0].depth_minus1 == 7 &&
isPackedRGB(srcFormat) && dstFormat == AV_PIX_FMT_GBRP)
c->swscale = rgbToPlanarRgbWrapper;
+ if (isBayer(srcFormat)) {
+ if (dstFormat == AV_PIX_FMT_RGB24)
+ c->swscale = bayer_to_rgb24_wrapper;
+ else if (dstFormat == AV_PIX_FMT_YUV420P)
+ c->swscale = bayer_to_yv12_wrapper;
+ else if (!isBayer(dstFormat)) {
+ av_log(c, AV_LOG_ERROR, "unsupported bayer conversion\n");
+ av_assert0(0);
+ }
+ }
+
/* bswap 16 bits per pixel/component packed formats */
- if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR444) ||
+ if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_BGGR16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_RGGB16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_GBRG16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_GRBG16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR444) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR48) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGRA64) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR555) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR565) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGRA64) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY16) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YA16) ||
- IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAP16)||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP9) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP10) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP12) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP14) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAP16) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB444) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB48) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGBA64) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB555) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB565) ||
IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGBA64) ||
- IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_XYZ12))
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_XYZ12) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P9) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P10) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P12) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P14) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P9) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P10) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P12) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P14) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P16) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV440P10) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV440P12) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P9) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P10) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P12) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P14) ||
+ IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P16))
c->swscale = packed_16bpc_bswap;
- if ((usePal(srcFormat) && (
- dstFormat == AV_PIX_FMT_RGB32 ||
- dstFormat == AV_PIX_FMT_RGB32_1 ||
- dstFormat == AV_PIX_FMT_RGB24 ||
- dstFormat == AV_PIX_FMT_BGR32 ||
- dstFormat == AV_PIX_FMT_BGR32_1 ||
- dstFormat == AV_PIX_FMT_BGR24)))
+ if (usePal(srcFormat) && isByteRGB(dstFormat))
c->swscale = palToRgbWrapper;
if (srcFormat == AV_PIX_FMT_YUV422P) {
@@ -1145,13 +1734,14 @@ void ff_get_unscaled_swscale(SwsContext *c)
if (srcFormat == AV_PIX_FMT_UYVY422 && dstFormat == AV_PIX_FMT_YUV422P)
c->swscale = uyvyToYuv422Wrapper;
+#define isPlanarGray(x) (isGray(x) && (x) != AV_PIX_FMT_YA8 && (x) != AV_PIX_FMT_YA16LE && (x) != AV_PIX_FMT_YA16BE)
/* simple copy */
if ( srcFormat == dstFormat ||
(srcFormat == AV_PIX_FMT_YUVA420P && dstFormat == AV_PIX_FMT_YUV420P) ||
(srcFormat == AV_PIX_FMT_YUV420P && dstFormat == AV_PIX_FMT_YUVA420P) ||
- (isPlanarYUV(srcFormat) && isGray(dstFormat)) ||
- (isPlanarYUV(dstFormat) && isGray(srcFormat)) ||
- (isGray(dstFormat) && isGray(srcFormat)) ||
+ (isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) ||
+ (isPlanarYUV(dstFormat) && isPlanarGray(srcFormat)) ||
+ (isPlanarGray(dstFormat) && isPlanarGray(srcFormat)) ||
(isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) &&
c->chrDstHSubSample == c->chrSrcHSubSample &&
c->chrDstVSubSample == c->chrSrcVSubSample &&
@@ -1166,177 +1756,8 @@ void ff_get_unscaled_swscale(SwsContext *c)
if (ARCH_PPC)
ff_get_unscaled_swscale_ppc(c);
-}
-
-static void reset_ptr(const uint8_t *src[], enum AVPixelFormat format)
-{
- if (!isALPHA(format))
- src[3] = NULL;
- if (!isPlanar(format)) {
- src[3] = src[2] = NULL;
-
- if (!usePal(format))
- src[1] = NULL;
- }
-}
-
-static int check_image_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt,
- const int linesizes[4])
-{
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
- int i;
-
- for (i = 0; i < 4; i++) {
- int plane = desc->comp[i].plane;
- if (!data[plane] || !linesizes[plane])
- return 0;
- }
-
- return 1;
-}
-
-/**
- * swscale wrapper, so we don't need to export the SwsContext.
- * Assumes planar YUV to be in YUV order instead of YVU.
- */
-int attribute_align_arg sws_scale(struct SwsContext *c,
- const uint8_t * const srcSlice[],
- const int srcStride[], int srcSliceY,
- int srcSliceH, uint8_t *const dst[],
- const int dstStride[])
-{
- int i;
- const uint8_t *src2[4] = { srcSlice[0], srcSlice[1], srcSlice[2], srcSlice[3] };
- uint8_t *dst2[4] = { dst[0], dst[1], dst[2], dst[3] };
-
- // do not mess up sliceDir if we have a "trailing" 0-size slice
- if (srcSliceH == 0)
- return 0;
-
- if (!check_image_pointers(srcSlice, c->srcFormat, srcStride)) {
- av_log(c, AV_LOG_ERROR, "bad src image pointers\n");
- return 0;
- }
- if (!check_image_pointers(dst, c->dstFormat, dstStride)) {
- av_log(c, AV_LOG_ERROR, "bad dst image pointers\n");
- return 0;
- }
-
- if (c->sliceDir == 0 && srcSliceY != 0 && srcSliceY + srcSliceH != c->srcH) {
- av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n");
- return 0;
- }
- if (c->sliceDir == 0) {
- if (srcSliceY == 0) c->sliceDir = 1; else c->sliceDir = -1;
- }
-
- if (usePal(c->srcFormat)) {
- for (i = 0; i < 256; i++) {
- int r, g, b, y, u, v;
- if (c->srcFormat == AV_PIX_FMT_PAL8) {
- uint32_t p = ((const uint32_t *)(srcSlice[1]))[i];
- r = (p >> 16) & 0xFF;
- g = (p >> 8) & 0xFF;
- b = p & 0xFF;
- } else if (c->srcFormat == AV_PIX_FMT_RGB8) {
- r = ( i >> 5 ) * 36;
- g = ((i >> 2) & 7) * 36;
- b = ( i & 3) * 85;
- } else if (c->srcFormat == AV_PIX_FMT_BGR8) {
- b = ( i >> 6 ) * 85;
- g = ((i >> 3) & 7) * 36;
- r = ( i & 7) * 36;
- } else if (c->srcFormat == AV_PIX_FMT_RGB4_BYTE) {
- r = ( i >> 3 ) * 255;
- g = ((i >> 1) & 3) * 85;
- b = ( i & 1) * 255;
- } else if (c->srcFormat == AV_PIX_FMT_GRAY8 ||
- c->srcFormat == AV_PIX_FMT_YA8) {
- r = g = b = i;
- } else {
- assert(c->srcFormat == AV_PIX_FMT_BGR4_BYTE);
- b = ( i >> 3 ) * 255;
- g = ((i >> 1) & 3) * 85;
- r = ( i & 1) * 255;
- }
- y = av_clip_uint8((RY * r + GY * g + BY * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
- u = av_clip_uint8((RU * r + GU * g + BU * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
- v = av_clip_uint8((RV * r + GV * g + BV * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
- c->pal_yuv[i] = y + (u << 8) + (v << 16) + (0xFFU << 24);
-
- switch (c->dstFormat) {
- case AV_PIX_FMT_BGR32:
-#if !HAVE_BIGENDIAN
- case AV_PIX_FMT_RGB24:
-#endif
- c->pal_rgb[i] = r + (g << 8) + (b << 16) + (0xFFU << 24);
- break;
- case AV_PIX_FMT_BGR32_1:
-#if HAVE_BIGENDIAN
- case AV_PIX_FMT_BGR24:
-#endif
- c->pal_rgb[i] = 0xFF + (r << 8) + (g << 16) + ((unsigned)b << 24);
- break;
- case AV_PIX_FMT_RGB32_1:
-#if HAVE_BIGENDIAN
- case AV_PIX_FMT_RGB24:
-#endif
- c->pal_rgb[i] = 0xFF + (b << 8) + (g << 16) + ((unsigned)r << 24);
- break;
- case AV_PIX_FMT_RGB32:
-#if !HAVE_BIGENDIAN
- case AV_PIX_FMT_BGR24:
-#endif
- default:
- c->pal_rgb[i] = b + (g << 8) + (r << 16) + (0xFFU << 24);
- }
- }
- }
-
- // copy strides, so they can safely be modified
- if (c->sliceDir == 1) {
- // slices go from top to bottom
- int srcStride2[4] = { srcStride[0], srcStride[1], srcStride[2],
- srcStride[3] };
- int dstStride2[4] = { dstStride[0], dstStride[1], dstStride[2],
- dstStride[3] };
-
- reset_ptr(src2, c->srcFormat);
- reset_ptr((const uint8_t **) dst2, c->dstFormat);
-
- /* reset slice direction at end of frame */
- if (srcSliceY + srcSliceH == c->srcH)
- c->sliceDir = 0;
-
- return c->swscale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
- dstStride2);
- } else {
- // slices go from bottom to top => we flip the image internally
- int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2],
- -srcStride[3] };
- int dstStride2[4] = { -dstStride[0], -dstStride[1], -dstStride[2],
- -dstStride[3] };
-
- src2[0] += (srcSliceH - 1) * srcStride[0];
- if (!usePal(c->srcFormat))
- src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1];
- src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2];
- src2[3] += (srcSliceH - 1) * srcStride[3];
- dst2[0] += ( c->dstH - 1) * dstStride[0];
- dst2[1] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[1];
- dst2[2] += ((c->dstH >> c->chrDstVSubSample) - 1) * dstStride[2];
- dst2[3] += ( c->dstH - 1) * dstStride[3];
-
- reset_ptr(src2, c->srcFormat);
- reset_ptr((const uint8_t **) dst2, c->dstFormat);
-
- /* reset slice direction at end of frame */
- if (!srcSliceY)
- c->sliceDir = 0;
-
- return c->swscale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
- srcSliceH, dst2, dstStride2);
- }
+// if (ARCH_ARM)
+// ff_get_unscaled_swscale_arm(c);
}
/* Convert the palette to the same packed 32-bit format as the palette */
diff --git a/libswscale/swscaleres.rc b/libswscale/swscaleres.rc
new file mode 100644
index 0000000000..5cb8ee7023
--- /dev/null
+++ b/libswscale/swscaleres.rc
@@ -0,0 +1,55 @@
+/*
+ * Windows resource file for libswscale
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "libswscale/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION LIBSWSCALE_VERSION_MAJOR, LIBSWSCALE_VERSION_MINOR, LIBSWSCALE_VERSION_MICRO, 0
+PRODUCTVERSION LIBSWSCALE_VERSION_MAJOR, LIBSWSCALE_VERSION_MINOR, LIBSWSCALE_VERSION_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "FFmpeg image rescaling library"
+ VALUE "FileVersion", AV_STRINGIFY(LIBSWSCALE_VERSION)
+ VALUE "InternalName", "libswscale"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "swscale" BUILDSUF "-" AV_STRINGIFY(LIBSWSCALE_VERSION_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
diff --git a/libswscale/utils.c b/libswscale/utils.c
index f5b251136a..f9f4ec6cb7 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -1,27 +1,27 @@
/*
* Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * 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"
#define _SVID_SOURCE // needed for MAP_ANONYMOUS
-#include <assert.h>
+#define _DARWIN_C_SOURCE // needed for MAP_ANON
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
@@ -38,9 +38,11 @@
#endif
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/bswap.h"
#include "libavutil/cpu.h"
+#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
@@ -52,24 +54,25 @@
#include "swscale.h"
#include "swscale_internal.h"
+static void handle_formats(SwsContext *c);
+
unsigned swscale_version(void)
{
+ av_assert0(LIBSWSCALE_VERSION_MICRO >= 100);
return LIBSWSCALE_VERSION_INT;
}
const char *swscale_configuration(void)
{
- return LIBAV_CONFIGURATION;
+ return FFMPEG_CONFIGURATION;
}
const char *swscale_license(void)
{
#define LICENSE_PREFIX "libswscale license: "
- return LICENSE_PREFIX LIBAV_LICENSE + sizeof(LICENSE_PREFIX) - 1;
+ return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;
}
-#define RET 0xC3 // near return opcode for x86
-
typedef struct FormatEntry {
uint8_t is_supported_in :1;
uint8_t is_supported_out :1;
@@ -90,6 +93,7 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
[AV_PIX_FMT_MONOBLACK] = { 1, 1 },
[AV_PIX_FMT_PAL8] = { 1, 0 },
[AV_PIX_FMT_YUVJ420P] = { 1, 1 },
+ [AV_PIX_FMT_YUVJ411P] = { 1, 1 },
[AV_PIX_FMT_YUVJ422P] = { 1, 1 },
[AV_PIX_FMT_YUVJ444P] = { 1, 1 },
[AV_PIX_FMT_YVYU422] = { 1, 1 },
@@ -107,10 +111,18 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
[AV_PIX_FMT_RGBA] = { 1, 1 },
[AV_PIX_FMT_ABGR] = { 1, 1 },
[AV_PIX_FMT_BGRA] = { 1, 1 },
+ [AV_PIX_FMT_0RGB] = { 1, 1 },
+ [AV_PIX_FMT_RGB0] = { 1, 1 },
+ [AV_PIX_FMT_0BGR] = { 1, 1 },
+ [AV_PIX_FMT_BGR0] = { 1, 1 },
[AV_PIX_FMT_GRAY16BE] = { 1, 1 },
[AV_PIX_FMT_GRAY16LE] = { 1, 1 },
[AV_PIX_FMT_YUV440P] = { 1, 1 },
[AV_PIX_FMT_YUVJ440P] = { 1, 1 },
+ [AV_PIX_FMT_YUV440P10LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV440P10BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV440P12LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV440P12BE] = { 1, 1 },
[AV_PIX_FMT_YUVA420P] = { 1, 1 },
[AV_PIX_FMT_YUVA422P] = { 1, 1 },
[AV_PIX_FMT_YUVA444P] = { 1, 1 },
@@ -134,8 +146,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
[AV_PIX_FMT_YUVA444P16LE]= { 1, 1 },
[AV_PIX_FMT_RGB48BE] = { 1, 1 },
[AV_PIX_FMT_RGB48LE] = { 1, 1 },
- [AV_PIX_FMT_RGBA64BE] = { 0, 0, 1 },
- [AV_PIX_FMT_RGBA64LE] = { 0, 0, 1 },
+ [AV_PIX_FMT_RGBA64BE] = { 1, 1, 1 },
+ [AV_PIX_FMT_RGBA64LE] = { 1, 1, 1 },
[AV_PIX_FMT_RGB565BE] = { 1, 1 },
[AV_PIX_FMT_RGB565LE] = { 1, 1 },
[AV_PIX_FMT_RGB555BE] = { 1, 1 },
@@ -159,32 +171,60 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
[AV_PIX_FMT_YA16LE] = { 1, 0 },
[AV_PIX_FMT_BGR48BE] = { 1, 1 },
[AV_PIX_FMT_BGR48LE] = { 1, 1 },
- [AV_PIX_FMT_BGRA64BE] = { 0, 0, 1 },
- [AV_PIX_FMT_BGRA64LE] = { 0, 0, 1 },
+ [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 },
+ [AV_PIX_FMT_BGRA64LE] = { 1, 1, 1 },
[AV_PIX_FMT_YUV420P9BE] = { 1, 1 },
[AV_PIX_FMT_YUV420P9LE] = { 1, 1 },
[AV_PIX_FMT_YUV420P10BE] = { 1, 1 },
[AV_PIX_FMT_YUV420P10LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV420P12BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV420P12LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV420P14BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV420P14LE] = { 1, 1 },
[AV_PIX_FMT_YUV422P9BE] = { 1, 1 },
[AV_PIX_FMT_YUV422P9LE] = { 1, 1 },
[AV_PIX_FMT_YUV422P10BE] = { 1, 1 },
[AV_PIX_FMT_YUV422P10LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV422P12BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV422P12LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV422P14BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV422P14LE] = { 1, 1 },
[AV_PIX_FMT_YUV444P9BE] = { 1, 1 },
[AV_PIX_FMT_YUV444P9LE] = { 1, 1 },
[AV_PIX_FMT_YUV444P10BE] = { 1, 1 },
[AV_PIX_FMT_YUV444P10LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV444P12BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV444P12LE] = { 1, 1 },
+ [AV_PIX_FMT_YUV444P14BE] = { 1, 1 },
+ [AV_PIX_FMT_YUV444P14LE] = { 1, 1 },
[AV_PIX_FMT_GBRP] = { 1, 1 },
[AV_PIX_FMT_GBRP9LE] = { 1, 1 },
[AV_PIX_FMT_GBRP9BE] = { 1, 1 },
[AV_PIX_FMT_GBRP10LE] = { 1, 1 },
[AV_PIX_FMT_GBRP10BE] = { 1, 1 },
+ [AV_PIX_FMT_GBRP12LE] = { 1, 1 },
+ [AV_PIX_FMT_GBRP12BE] = { 1, 1 },
+ [AV_PIX_FMT_GBRP14LE] = { 1, 1 },
+ [AV_PIX_FMT_GBRP14BE] = { 1, 1 },
[AV_PIX_FMT_GBRP16LE] = { 1, 0 },
[AV_PIX_FMT_GBRP16BE] = { 1, 0 },
[AV_PIX_FMT_GBRAP] = { 1, 1 },
[AV_PIX_FMT_GBRAP16LE] = { 1, 0 },
[AV_PIX_FMT_GBRAP16BE] = { 1, 0 },
- [AV_PIX_FMT_XYZ12BE] = { 0, 0, 1 },
- [AV_PIX_FMT_XYZ12LE] = { 0, 0, 1 },
+ [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 },
+ [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 },
+ [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 },
+ [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 },
};
int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
@@ -205,15 +245,6 @@ int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt)
format_entries[pix_fmt].is_supported_endianness : 0;
}
-const char *sws_format_name(enum AVPixelFormat format)
-{
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
- if (desc)
- return desc->name;
- else
- return "Unknown format";
-}
-
static double getSplineCoeff(double a, double b, double c, double d,
double dist)
{
@@ -227,12 +258,41 @@ static double getSplineCoeff(double a, double b, double c, double d,
dist - 1.0);
}
+static av_cold int get_local_pos(SwsContext *s, int chr_subsample, int pos, int dir)
+{
+ if (pos == -1 || pos <= -513) {
+ pos = (128 << chr_subsample) - 128;
+ }
+ pos += 128; // relative to ideal left edge
+ return pos >> chr_subsample;
+}
+
+typedef struct {
+ int flag; ///< flag associated to the algorithm
+ const char *description; ///< human-readable description
+ int size_factor; ///< size factor used when initing the filters
+} ScaleAlgorithm;
+
+static const ScaleAlgorithm scale_algorithms[] = {
+ { SWS_AREA, "area averaging", 1 /* downscale only, for upscale it is bilinear */ },
+ { SWS_BICUBIC, "bicubic", 4 },
+ { SWS_BICUBLIN, "luma bicubic / chroma bilinear", -1 },
+ { SWS_BILINEAR, "bilinear", 2 },
+ { SWS_FAST_BILINEAR, "fast bilinear", -1 },
+ { SWS_GAUSS, "Gaussian", 8 /* infinite ;) */ },
+ { SWS_LANCZOS, "Lanczos", -1 /* custom */ },
+ { SWS_POINT, "nearest neighbor / point", -1 },
+ { SWS_SINC, "sinc", 20 /* infinite ;) */ },
+ { SWS_SPLINE, "bicubic spline", 20 /* infinite :)*/ },
+ { SWS_X, "experimental", 8 },
+};
+
static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
int *outFilterSize, int xInc, int srcW,
int dstW, int filterAlign, int one,
int flags, int cpu_flags,
SwsVector *srcFilter, SwsVector *dstFilter,
- double param[2], int is_horizontal)
+ double param[2], int srcPos, int dstPos)
{
int i;
int filterSize;
@@ -240,19 +300,19 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
int minFilterSize;
int64_t *filter = NULL;
int64_t *filter2 = NULL;
- const int64_t fone = 1LL << 54;
+ const int64_t fone = 1LL << (54 - FFMIN(av_log2(srcW/dstW), 8));
int ret = -1;
emms_c(); // FIXME should not be required but IS (even for non-MMX versions)
// NOTE: the +3 is for the MMX(+1) / SSE(+3) scaler which reads over the end
- FF_ALLOC_OR_GOTO(NULL, *filterPos, (dstW + 3) * sizeof(**filterPos), fail);
+ FF_ALLOC_ARRAY_OR_GOTO(NULL, *filterPos, (dstW + 3), sizeof(**filterPos), fail);
- if (FFABS(xInc - 0x10000) < 10) { // unscaled
+ if (FFABS(xInc - 0x10000) < 10 && srcPos == dstPos) { // unscaled
int i;
filterSize = 1;
- FF_ALLOCZ_OR_GOTO(NULL, filter,
- dstW * sizeof(*filter) * filterSize, fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(NULL, filter,
+ dstW, sizeof(*filter) * filterSize, fail);
for (i = 0; i < dstW; i++) {
filter[i * filterSize] = fone;
@@ -260,12 +320,12 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
}
} else if (flags & SWS_POINT) { // lame looking point sampling mode
int i;
- int xDstInSrc;
+ int64_t xDstInSrc;
filterSize = 1;
- FF_ALLOC_OR_GOTO(NULL, filter,
- dstW * sizeof(*filter) * filterSize, fail);
+ FF_ALLOC_ARRAY_OR_GOTO(NULL, filter,
+ dstW, sizeof(*filter) * filterSize, fail);
- xDstInSrc = xInc / 2 - 0x8000;
+ xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7);
for (i = 0; i < dstW; i++) {
int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16;
@@ -276,12 +336,12 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
} else if ((xInc <= (1 << 16) && (flags & SWS_AREA)) ||
(flags & SWS_FAST_BILINEAR)) { // bilinear upscale
int i;
- int xDstInSrc;
+ int64_t xDstInSrc;
filterSize = 2;
- FF_ALLOC_OR_GOTO(NULL, filter,
- dstW * sizeof(*filter) * filterSize, fail);
+ FF_ALLOC_ARRAY_OR_GOTO(NULL, filter,
+ dstW, sizeof(*filter) * filterSize, fail);
- xDstInSrc = xInc / 2 - 0x8000;
+ xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7);
for (i = 0; i < dstW; i++) {
int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16;
int j;
@@ -289,8 +349,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
(*filterPos)[i] = xx;
// bilinear upscale / linear interpolate / area averaging
for (j = 0; j < filterSize; j++) {
- int64_t coeff = fone - FFABS((xx << 16) - xDstInSrc) *
- (fone >> 16);
+ int64_t coeff= fone - FFABS(((int64_t)xx<<16) - xDstInSrc)*(fone>>16);
if (coeff < 0)
coeff = 0;
filter[i * filterSize + j] = coeff;
@@ -300,28 +359,17 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
}
} else {
int64_t xDstInSrc;
- int sizeFactor;
-
- if (flags & SWS_BICUBIC)
- sizeFactor = 4;
- else if (flags & SWS_X)
- sizeFactor = 8;
- else if (flags & SWS_AREA)
- sizeFactor = 1; // downscale only, for upscale it is bilinear
- else if (flags & SWS_GAUSS)
- sizeFactor = 8; // infinite ;)
- else if (flags & SWS_LANCZOS)
- sizeFactor = param[0] != SWS_PARAM_DEFAULT ? ceil(2 * param[0]) : 6;
- else if (flags & SWS_SINC)
- sizeFactor = 20; // infinite ;)
- else if (flags & SWS_SPLINE)
- sizeFactor = 20; // infinite ;)
- else if (flags & SWS_BILINEAR)
- sizeFactor = 2;
- else {
- sizeFactor = 0; // GCC warning killer
- assert(0);
+ int sizeFactor = -1;
+
+ for (i = 0; i < FF_ARRAY_ELEMS(scale_algorithms); i++) {
+ if (flags & scale_algorithms[i].flag && scale_algorithms[i].size_factor > 0) {
+ sizeFactor = scale_algorithms[i].size_factor;
+ break;
+ }
}
+ if (flags & SWS_LANCZOS)
+ sizeFactor = param[0] != SWS_PARAM_DEFAULT ? ceil(2 * param[0]) : 6;
+ av_assert0(sizeFactor > 0);
if (xInc <= 1 << 16)
filterSize = 1 + sizeFactor; // upscale
@@ -331,16 +379,16 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
filterSize = FFMIN(filterSize, srcW - 2);
filterSize = FFMAX(filterSize, 1);
- FF_ALLOC_OR_GOTO(NULL, filter,
- dstW * sizeof(*filter) * filterSize, fail);
+ FF_ALLOC_ARRAY_OR_GOTO(NULL, filter,
+ dstW, sizeof(*filter) * filterSize, fail);
- xDstInSrc = xInc - 0x10000;
+ xDstInSrc = ((dstPos*(int64_t)xInc)>>7) - ((srcPos*0x10000LL)>>7);
for (i = 0; i < dstW; i++) {
int xx = (xDstInSrc - ((int64_t)(filterSize - 2) << 16)) / (1 << 17);
int j;
(*filterPos)[i] = xx;
for (j = 0; j < filterSize; j++) {
- int64_t d = (FFABS(((int64_t)xx << 17) - xDstInSrc)) << 13;
+ int64_t d = (FFABS(((int64_t)xx * (1 << 17)) - xDstInSrc)) << 13;
double floatd;
int64_t coeff;
@@ -368,7 +416,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
(-12 * B - 48 * C) * d +
(8 * B + 24 * C) * (1 << 30);
}
- coeff *= fone >> (30 + 24);
+ coeff /= (1LL<<54)/fone;
}
#if 0
else if (flags & SWS_X) {
@@ -419,8 +467,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
double p = -2.196152422706632;
coeff = getSplineCoeff(1.0, 0.0, p, -p - 1.0, floatd) * fone;
} else {
- coeff = 0.0; // GCC warning killer
- assert(0);
+ av_assert0(0);
}
filter[i * filterSize + j] = coeff;
@@ -433,14 +480,14 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
/* apply src & dst Filter to filter -> filter2
* av_free(filter);
*/
- assert(filterSize > 0);
+ av_assert0(filterSize > 0);
filter2Size = filterSize;
if (srcFilter)
filter2Size += srcFilter->length - 1;
if (dstFilter)
filter2Size += dstFilter->length - 1;
- assert(filter2Size > 0);
- FF_ALLOCZ_OR_GOTO(NULL, filter2, filter2Size * dstW * sizeof(*filter2), fail);
+ av_assert0(filter2Size > 0);
+ FF_ALLOCZ_ARRAY_OR_GOTO(NULL, filter2, dstW, filter2Size * sizeof(*filter2), fail);
for (i = 0; i < dstW; i++) {
int j, k;
@@ -515,19 +562,23 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
filterAlign = 1;
}
- if (INLINE_MMX(cpu_flags)) {
+ if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX) {
// special case for unscaled vertical filtering
if (minFilterSize == 1 && filterAlign == 2)
filterAlign = 1;
}
- assert(minFilterSize > 0);
+ av_assert0(minFilterSize > 0);
filterSize = (minFilterSize + (filterAlign - 1)) & (~(filterAlign - 1));
- assert(filterSize > 0);
- filter = av_malloc(filterSize * dstW * sizeof(*filter));
+ av_assert0(filterSize > 0);
+ filter = av_malloc_array(dstW, filterSize * sizeof(*filter));
+ if (!filter)
+ goto fail;
if (filterSize >= MAX_FILTER_SIZE * 16 /
- ((flags & SWS_ACCURATE_RND) ? APCK_SIZE : 16) || !filter)
+ ((flags & SWS_ACCURATE_RND) ? APCK_SIZE : 16)) {
+ ret = RETCODE_USE_CASCADE;
goto fail;
+ }
*outFilterSize = filterSize;
if (flags & SWS_PRINT_INFO)
@@ -551,36 +602,52 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
// FIXME try to align filterPos if possible
// fix borders
- if (is_horizontal) {
- for (i = 0; i < dstW; i++) {
- int j;
- if ((*filterPos)[i] < 0) {
- // move filter coefficients left to compensate for filterPos
- for (j = 1; j < filterSize; j++) {
- int left = FFMAX(j + (*filterPos)[i], 0);
- filter[i * filterSize + left] += filter[i * filterSize + j];
- filter[i * filterSize + j] = 0;
- }
- (*filterPos)[i] = 0;
+ for (i = 0; i < dstW; i++) {
+ int j;
+ if ((*filterPos)[i] < 0) {
+ // move filter coefficients left to compensate for filterPos
+ for (j = 1; j < filterSize; j++) {
+ int left = FFMAX(j + (*filterPos)[i], 0);
+ filter[i * filterSize + left] += filter[i * filterSize + j];
+ filter[i * filterSize + j] = 0;
}
+ (*filterPos)[i]= 0;
+ }
+
+ if ((*filterPos)[i] + filterSize > srcW) {
+ int shift = (*filterPos)[i] + FFMIN(filterSize - srcW, 0);
+ int64_t acc = 0;
- if ((*filterPos)[i] + filterSize > srcW) {
- int shift = (*filterPos)[i] + filterSize - srcW;
- // move filter coefficients right to compensate for filterPos
- for (j = filterSize - 2; j >= 0; j--) {
- int right = FFMIN(j + shift, filterSize - 1);
- filter[i * filterSize + right] += filter[i * filterSize + j];
- filter[i * filterSize + j] = 0;
+ for (j = filterSize - 1; j >= 0; j--) {
+ if ((*filterPos)[i] + j >= srcW) {
+ acc += filter[i * filterSize + j];
+ filter[i * filterSize + j] = 0;
}
- (*filterPos)[i] = srcW - filterSize;
+ }
+ for (j = filterSize - 1; j >= 0; j--) {
+ if (j < shift) {
+ filter[i * filterSize + j] = 0;
+ } else {
+ filter[i * filterSize + j] = filter[i * filterSize + j - shift];
+ }
+ }
+
+ (*filterPos)[i]-= shift;
+ filter[i * filterSize + srcW - 1 - (*filterPos)[i]] += acc;
+ }
+ av_assert0((*filterPos)[i] >= 0);
+ av_assert0((*filterPos)[i] < srcW);
+ if ((*filterPos)[i] + filterSize > srcW) {
+ for (j = 0; j < filterSize; j++) {
+ av_assert0((*filterPos)[i] + j < srcW || !filter[i * filterSize + j]);
}
}
}
// Note the +1 is for the MMX scaler which reads over the end
/* align at 16 for AltiVec (needed by hScale_altivec_real) */
- FF_ALLOCZ_OR_GOTO(NULL, *outFilter,
- *outFilterSize * (dstW + 3) * sizeof(int16_t), fail);
+ FF_ALLOCZ_ARRAY_OR_GOTO(NULL, *outFilter,
+ (dstW + 3), *outFilterSize * sizeof(int16_t), fail);
/* normalize & store in outFilter */
for (i = 0; i < dstW; i++) {
@@ -592,6 +659,10 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
sum += filter[i * filterSize + j];
}
sum = (sum + one / 2) / one;
+ if (!sum) {
+ av_log(NULL, AV_LOG_WARNING, "SwScaler: zero vector in scaling\n");
+ sum = 1;
+ }
for (j = 0; j < *outFilterSize; j++) {
int64_t v = filter[i * filterSize + j] + error;
int intV = ROUNDED_DIV(v, sum);
@@ -614,211 +685,193 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
ret = 0;
fail:
+ if(ret < 0)
+ av_log(NULL, ret == RETCODE_USE_CASCADE ? AV_LOG_DEBUG : AV_LOG_ERROR, "sws: initFilter failed\n");
av_free(filter);
av_free(filter2);
return ret;
}
-#if HAVE_MMXEXT_INLINE
-static av_cold int init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode,
- int16_t *filter, int32_t *filterPos,
- int numSplits)
+static void fill_rgb2yuv_table(SwsContext *c, const int table[4], int dstRange)
{
- uint8_t *fragmentA;
- x86_reg imm8OfPShufW1A;
- x86_reg imm8OfPShufW2A;
- x86_reg fragmentLengthA;
- uint8_t *fragmentB;
- x86_reg imm8OfPShufW1B;
- x86_reg imm8OfPShufW2B;
- x86_reg fragmentLengthB;
- int fragmentPos;
-
- int xpos, i;
-
- // create an optimized horizontal scaling routine
- /* This scaler is made of runtime-generated MMXEXT code using specially tuned
- * pshufw instructions. For every four output pixels, if four input pixels
- * are enough for the fast bilinear scaling, then a chunk of fragmentB is
- * used. If five input pixels are needed, then a chunk of fragmentA is used.
- */
-
- // code fragment
-
- __asm__ volatile (
- "jmp 9f \n\t"
- // Begin
- "0: \n\t"
- "movq (%%"REG_d", %%"REG_a"), %%mm3 \n\t"
- "movd (%%"REG_c", %%"REG_S"), %%mm0 \n\t"
- "movd 1(%%"REG_c", %%"REG_S"), %%mm1 \n\t"
- "punpcklbw %%mm7, %%mm1 \n\t"
- "punpcklbw %%mm7, %%mm0 \n\t"
- "pshufw $0xFF, %%mm1, %%mm1 \n\t"
- "1: \n\t"
- "pshufw $0xFF, %%mm0, %%mm0 \n\t"
- "2: \n\t"
- "psubw %%mm1, %%mm0 \n\t"
- "movl 8(%%"REG_b", %%"REG_a"), %%esi \n\t"
- "pmullw %%mm3, %%mm0 \n\t"
- "psllw $7, %%mm1 \n\t"
- "paddw %%mm1, %%mm0 \n\t"
-
- "movq %%mm0, (%%"REG_D", %%"REG_a") \n\t"
-
- "add $8, %%"REG_a" \n\t"
- // End
- "9: \n\t"
- // "int $3 \n\t"
- "lea " LOCAL_MANGLE(0b) ", %0 \n\t"
- "lea " LOCAL_MANGLE(1b) ", %1 \n\t"
- "lea " LOCAL_MANGLE(2b) ", %2 \n\t"
- "dec %1 \n\t"
- "dec %2 \n\t"
- "sub %0, %1 \n\t"
- "sub %0, %2 \n\t"
- "lea " LOCAL_MANGLE(9b) ", %3 \n\t"
- "sub %0, %3 \n\t"
-
-
- : "=r" (fragmentA), "=r" (imm8OfPShufW1A), "=r" (imm8OfPShufW2A),
- "=r" (fragmentLengthA)
- );
-
- __asm__ volatile (
- "jmp 9f \n\t"
- // Begin
- "0: \n\t"
- "movq (%%"REG_d", %%"REG_a"), %%mm3 \n\t"
- "movd (%%"REG_c", %%"REG_S"), %%mm0 \n\t"
- "punpcklbw %%mm7, %%mm0 \n\t"
- "pshufw $0xFF, %%mm0, %%mm1 \n\t"
- "1: \n\t"
- "pshufw $0xFF, %%mm0, %%mm0 \n\t"
- "2: \n\t"
- "psubw %%mm1, %%mm0 \n\t"
- "movl 8(%%"REG_b", %%"REG_a"), %%esi \n\t"
- "pmullw %%mm3, %%mm0 \n\t"
- "psllw $7, %%mm1 \n\t"
- "paddw %%mm1, %%mm0 \n\t"
-
- "movq %%mm0, (%%"REG_D", %%"REG_a") \n\t"
-
- "add $8, %%"REG_a" \n\t"
- // End
- "9: \n\t"
- // "int $3 \n\t"
- "lea " LOCAL_MANGLE(0b) ", %0 \n\t"
- "lea " LOCAL_MANGLE(1b) ", %1 \n\t"
- "lea " LOCAL_MANGLE(2b) ", %2 \n\t"
- "dec %1 \n\t"
- "dec %2 \n\t"
- "sub %0, %1 \n\t"
- "sub %0, %2 \n\t"
- "lea " LOCAL_MANGLE(9b) ", %3 \n\t"
- "sub %0, %3 \n\t"
-
-
- : "=r" (fragmentB), "=r" (imm8OfPShufW1B), "=r" (imm8OfPShufW2B),
- "=r" (fragmentLengthB)
- );
-
- xpos = 0; // lumXInc/2 - 0x8000; // difference between pixel centers
- fragmentPos = 0;
-
- for (i = 0; i < dstW / numSplits; i++) {
- int xx = xpos >> 16;
-
- if ((i & 3) == 0) {
- int a = 0;
- int b = ((xpos + xInc) >> 16) - xx;
- int c = ((xpos + xInc * 2) >> 16) - xx;
- int d = ((xpos + xInc * 3) >> 16) - xx;
- int inc = (d + 1 < 4);
- uint8_t *fragment = (d + 1 < 4) ? fragmentB : fragmentA;
- x86_reg imm8OfPShufW1 = (d + 1 < 4) ? imm8OfPShufW1B : imm8OfPShufW1A;
- x86_reg imm8OfPShufW2 = (d + 1 < 4) ? imm8OfPShufW2B : imm8OfPShufW2A;
- x86_reg fragmentLength = (d + 1 < 4) ? fragmentLengthB : fragmentLengthA;
- int maxShift = 3 - (d + inc);
- int shift = 0;
-
- if (filterCode) {
- filter[i] = ((xpos & 0xFFFF) ^ 0xFFFF) >> 9;
- filter[i + 1] = (((xpos + xInc) & 0xFFFF) ^ 0xFFFF) >> 9;
- filter[i + 2] = (((xpos + xInc * 2) & 0xFFFF) ^ 0xFFFF) >> 9;
- filter[i + 3] = (((xpos + xInc * 3) & 0xFFFF) ^ 0xFFFF) >> 9;
- filterPos[i / 2] = xx;
-
- memcpy(filterCode + fragmentPos, fragment, fragmentLength);
-
- filterCode[fragmentPos + imm8OfPShufW1] = (a + inc) |
- ((b + inc) << 2) |
- ((c + inc) << 4) |
- ((d + inc) << 6);
- filterCode[fragmentPos + imm8OfPShufW2] = a | (b << 2) |
- (c << 4) |
- (d << 6);
-
- if (i + 4 - inc >= dstW)
- shift = maxShift; // avoid overread
- else if ((filterPos[i / 2] & 3) <= maxShift)
- shift = filterPos[i / 2] & 3; // align
-
- if (shift && i >= shift) {
- filterCode[fragmentPos + imm8OfPShufW1] += 0x55 * shift;
- filterCode[fragmentPos + imm8OfPShufW2] += 0x55 * shift;
- filterPos[i / 2] -= shift;
- }
- }
-
- fragmentPos += fragmentLength;
-
- if (filterCode)
- filterCode[fragmentPos] = RET;
- }
- xpos += xInc;
+ int64_t W, V, Z, Cy, Cu, Cv;
+ int64_t vr = table[0];
+ int64_t ub = table[1];
+ int64_t ug = -table[2];
+ int64_t vg = -table[3];
+ int64_t ONE = 65536;
+ int64_t cy = ONE;
+ uint8_t *p = (uint8_t*)c->input_rgb2yuv_table;
+ int i;
+ static const int8_t map[] = {
+ BY_IDX, GY_IDX, -1 , BY_IDX, BY_IDX, GY_IDX, -1 , BY_IDX,
+ RY_IDX, -1 , GY_IDX, RY_IDX, RY_IDX, -1 , GY_IDX, RY_IDX,
+ RY_IDX, GY_IDX, -1 , RY_IDX, RY_IDX, GY_IDX, -1 , RY_IDX,
+ BY_IDX, -1 , GY_IDX, BY_IDX, BY_IDX, -1 , GY_IDX, BY_IDX,
+ BU_IDX, GU_IDX, -1 , BU_IDX, BU_IDX, GU_IDX, -1 , BU_IDX,
+ RU_IDX, -1 , GU_IDX, RU_IDX, RU_IDX, -1 , GU_IDX, RU_IDX,
+ RU_IDX, GU_IDX, -1 , RU_IDX, RU_IDX, GU_IDX, -1 , RU_IDX,
+ BU_IDX, -1 , GU_IDX, BU_IDX, BU_IDX, -1 , GU_IDX, BU_IDX,
+ BV_IDX, GV_IDX, -1 , BV_IDX, BV_IDX, GV_IDX, -1 , BV_IDX,
+ RV_IDX, -1 , GV_IDX, RV_IDX, RV_IDX, -1 , GV_IDX, RV_IDX,
+ RV_IDX, GV_IDX, -1 , RV_IDX, RV_IDX, GV_IDX, -1 , RV_IDX,
+ BV_IDX, -1 , GV_IDX, BV_IDX, BV_IDX, -1 , GV_IDX, BV_IDX,
+ RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX,
+ BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX,
+ GY_IDX, -1 , GY_IDX, -1 , GY_IDX, -1 , GY_IDX, -1 ,
+ -1 , GY_IDX, -1 , GY_IDX, -1 , GY_IDX, -1 , GY_IDX,
+ RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX,
+ BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX,
+ GU_IDX, -1 , GU_IDX, -1 , GU_IDX, -1 , GU_IDX, -1 ,
+ -1 , GU_IDX, -1 , GU_IDX, -1 , GU_IDX, -1 , GU_IDX,
+ RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX,
+ BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX,
+ GV_IDX, -1 , GV_IDX, -1 , GV_IDX, -1 , GV_IDX, -1 ,
+ -1 , GV_IDX, -1 , GV_IDX, -1 , GV_IDX, -1 , GV_IDX, //23
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //24
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //25
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //26
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //27
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //28
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //29
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //30
+ -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //31
+ BY_IDX, GY_IDX, RY_IDX, -1 , -1 , -1 , -1 , -1 , //32
+ BU_IDX, GU_IDX, RU_IDX, -1 , -1 , -1 , -1 , -1 , //33
+ BV_IDX, GV_IDX, RV_IDX, -1 , -1 , -1 , -1 , -1 , //34
+ };
+
+ dstRange = 0; //FIXME range = 1 is handled elsewhere
+
+ if (!dstRange) {
+ cy = cy * 255 / 219;
+ } else {
+ vr = vr * 224 / 255;
+ ub = ub * 224 / 255;
+ ug = ug * 224 / 255;
+ vg = vg * 224 / 255;
}
- if (filterCode)
- filterPos[((i / 2) + 1) & (~1)] = xpos >> 16; // needed to jump to the next part
-
- return fragmentPos + 1;
+ W = ROUNDED_DIV(ONE*ONE*ug, ub);
+ V = ROUNDED_DIV(ONE*ONE*vg, vr);
+ Z = ONE*ONE-W-V;
+
+ Cy = ROUNDED_DIV(cy*Z, ONE);
+ Cu = ROUNDED_DIV(ub*Z, ONE);
+ Cv = ROUNDED_DIV(vr*Z, ONE);
+
+ c->input_rgb2yuv_table[RY_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*V , Cy);
+ c->input_rgb2yuv_table[GY_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*ONE*ONE , Cy);
+ c->input_rgb2yuv_table[BY_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*W , Cy);
+
+ c->input_rgb2yuv_table[RU_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*V , Cu);
+ c->input_rgb2yuv_table[GU_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*ONE*ONE , Cu);
+ c->input_rgb2yuv_table[BU_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*(Z+W) , Cu);
+
+ c->input_rgb2yuv_table[RV_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*(V+Z) , Cv);
+ c->input_rgb2yuv_table[GV_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*ONE*ONE , Cv);
+ c->input_rgb2yuv_table[BV_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*W , Cv);
+
+ if(/*!dstRange && */!memcmp(table, ff_yuv2rgb_coeffs[SWS_CS_DEFAULT], sizeof(ff_yuv2rgb_coeffs[SWS_CS_DEFAULT]))) {
+ c->input_rgb2yuv_table[BY_IDX] = ((int)(0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[BV_IDX] = (-(int)(0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[BU_IDX] = ((int)(0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[GY_IDX] = ((int)(0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[GV_IDX] = (-(int)(0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[GU_IDX] = (-(int)(0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[RY_IDX] = ((int)(0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[RV_IDX] = ((int)(0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ c->input_rgb2yuv_table[RU_IDX] = (-(int)(0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5));
+ }
+ for(i=0; i<FF_ARRAY_ELEMS(map); i++)
+ AV_WL16(p + 16*4 + 2*i, map[i] >= 0 ? c->input_rgb2yuv_table[map[i]] : 0);
}
-#endif /* HAVE_MMXEXT_INLINE */
-static void getSubSampleFactors(int *h, int *v, enum AVPixelFormat format)
+static void fill_xyztables(struct SwsContext *c)
{
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
- *h = desc->log2_chroma_w;
- *v = desc->log2_chroma_h;
+ int i;
+ double xyzgamma = XYZ_GAMMA;
+ double rgbgamma = 1.0 / RGB_GAMMA;
+ double xyzgammainv = 1.0 / XYZ_GAMMA;
+ double rgbgammainv = RGB_GAMMA;
+ static const int16_t xyz2rgb_matrix[3][4] = {
+ {13270, -6295, -2041},
+ {-3969, 7682, 170},
+ { 228, -835, 4329} };
+ static const int16_t rgb2xyz_matrix[3][4] = {
+ {1689, 1464, 739},
+ { 871, 2929, 296},
+ { 79, 488, 3891} };
+ static int16_t xyzgamma_tab[4096], rgbgamma_tab[4096], xyzgammainv_tab[4096], rgbgammainv_tab[4096];
+
+ memcpy(c->xyz2rgb_matrix, xyz2rgb_matrix, sizeof(c->xyz2rgb_matrix));
+ memcpy(c->rgb2xyz_matrix, rgb2xyz_matrix, sizeof(c->rgb2xyz_matrix));
+ c->xyzgamma = xyzgamma_tab;
+ c->rgbgamma = rgbgamma_tab;
+ c->xyzgammainv = xyzgammainv_tab;
+ c->rgbgammainv = rgbgammainv_tab;
+
+ if (rgbgamma_tab[4095])
+ return;
+
+ /* set gamma vectors */
+ for (i = 0; i < 4096; i++) {
+ xyzgamma_tab[i] = lrint(pow(i / 4095.0, xyzgamma) * 4095.0);
+ rgbgamma_tab[i] = lrint(pow(i / 4095.0, rgbgamma) * 4095.0);
+ xyzgammainv_tab[i] = lrint(pow(i / 4095.0, xyzgammainv) * 4095.0);
+ rgbgammainv_tab[i] = lrint(pow(i / 4095.0, rgbgammainv) * 4095.0);
+ }
}
int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4],
int srcRange, const int table[4], int dstRange,
int brightness, int contrast, int saturation)
{
- const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->dstFormat);
- const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(c->srcFormat);
- memcpy(c->srcColorspaceTable, inv_table, sizeof(int) * 4);
- memcpy(c->dstColorspaceTable, table, sizeof(int) * 4);
+ const AVPixFmtDescriptor *desc_dst;
+ const AVPixFmtDescriptor *desc_src;
+ int need_reinit = 0;
+ memmove(c->srcColorspaceTable, inv_table, sizeof(int) * 4);
+ memmove(c->dstColorspaceTable, table, sizeof(int) * 4);
+
+ handle_formats(c);
+ desc_dst = av_pix_fmt_desc_get(c->dstFormat);
+ desc_src = av_pix_fmt_desc_get(c->srcFormat);
+
+ if(!isYUV(c->dstFormat) && !isGray(c->dstFormat))
+ dstRange = 0;
+ if(!isYUV(c->srcFormat) && !isGray(c->srcFormat))
+ srcRange = 0;
c->brightness = brightness;
c->contrast = contrast;
c->saturation = saturation;
+ if (c->srcRange != srcRange || c->dstRange != dstRange)
+ need_reinit = 1;
c->srcRange = srcRange;
c->dstRange = dstRange;
- if (isYUV(c->dstFormat) || isGray(c->dstFormat))
+
+ //The srcBpc check is possibly wrong but we seem to lack a definitive reference to test this
+ //and what we have in ticket 2939 looks better with this check
+ if (need_reinit && (c->srcBpc == 8 || !isYUV(c->srcFormat)))
+ ff_sws_init_range_convert(c);
+
+ if ((isYUV(c->dstFormat) || isGray(c->dstFormat)) && (isYUV(c->srcFormat) || isGray(c->srcFormat)))
return -1;
c->dstFormatBpp = av_get_bits_per_pixel(desc_dst);
c->srcFormatBpp = av_get_bits_per_pixel(desc_src);
- ff_yuv2rgb_c_init_tables(c, inv_table, srcRange, brightness,
- contrast, saturation);
- // FIXME factorize
+ if (!isYUV(c->dstFormat) && !isGray(c->dstFormat)) {
+ ff_yuv2rgb_c_init_tables(c, inv_table, srcRange, brightness,
+ contrast, saturation);
+ // FIXME factorize
+
+ if (ARCH_PPC)
+ ff_yuv2rgb_init_tables_ppc(c, inv_table, brightness,
+ contrast, saturation);
+ }
+
+ fill_rgb2yuv_table(c, table, dstRange);
- if (ARCH_PPC)
- ff_yuv2rgb_init_tables_ppc(c, inv_table, brightness,
- contrast, saturation);
return 0;
}
@@ -826,7 +879,7 @@ int sws_getColorspaceDetails(struct SwsContext *c, int **inv_table,
int *srcRange, int **table, int *dstRange,
int *brightness, int *contrast, int *saturation)
{
- if (isYUV(c->dstFormat) || isGray(c->dstFormat))
+ if (!c )
return -1;
*inv_table = c->srcColorspaceTable;
@@ -846,6 +899,9 @@ static int handle_jpeg(enum AVPixelFormat *format)
case AV_PIX_FMT_YUVJ420P:
*format = AV_PIX_FMT_YUV420P;
return 1;
+ case AV_PIX_FMT_YUVJ411P:
+ *format = AV_PIX_FMT_YUV411P;
+ return 1;
case AV_PIX_FMT_YUVJ422P:
*format = AV_PIX_FMT_YUV422P;
return 1;
@@ -855,15 +911,51 @@ static int handle_jpeg(enum AVPixelFormat *format)
case AV_PIX_FMT_YUVJ440P:
*format = AV_PIX_FMT_YUV440P;
return 1;
+ case AV_PIX_FMT_GRAY8:
+ case AV_PIX_FMT_GRAY16LE:
+ case AV_PIX_FMT_GRAY16BE:
+ return 1;
default:
return 0;
}
}
+static int handle_0alpha(enum AVPixelFormat *format)
+{
+ switch (*format) {
+ case AV_PIX_FMT_0BGR : *format = AV_PIX_FMT_ABGR ; return 1;
+ case AV_PIX_FMT_BGR0 : *format = AV_PIX_FMT_BGRA ; return 4;
+ case AV_PIX_FMT_0RGB : *format = AV_PIX_FMT_ARGB ; return 1;
+ case AV_PIX_FMT_RGB0 : *format = AV_PIX_FMT_RGBA ; return 4;
+ default: return 0;
+ }
+}
+
+static int handle_xyz(enum AVPixelFormat *format)
+{
+ switch (*format) {
+ case AV_PIX_FMT_XYZ12BE : *format = AV_PIX_FMT_RGB48BE; return 1;
+ case AV_PIX_FMT_XYZ12LE : *format = AV_PIX_FMT_RGB48LE; return 1;
+ default: return 0;
+ }
+}
+
+static void handle_formats(SwsContext *c)
+{
+ c->src0Alpha |= handle_0alpha(&c->srcFormat);
+ c->dst0Alpha |= handle_0alpha(&c->dstFormat);
+ c->srcXYZ |= handle_xyz(&c->srcFormat);
+ c->dstXYZ |= handle_xyz(&c->dstFormat);
+ if (c->srcXYZ || c->dstXYZ)
+ fill_xyztables(c);
+}
+
SwsContext *sws_alloc_context(void)
{
SwsContext *c = av_mallocz(sizeof(SwsContext));
+ av_assert0(offsetof(SwsContext, redDither) + DITHER32_INT == offsetof(SwsContext, dither32));
+
if (c) {
c->av_class = &sws_context_class;
av_opt_set_defaults(c);
@@ -872,10 +964,24 @@ SwsContext *sws_alloc_context(void)
return c;
}
+static uint16_t * alloc_gamma_tbl(double e)
+{
+ int i = 0;
+ uint16_t * tbl;
+ tbl = (uint16_t*)av_malloc(sizeof(uint16_t) * 1 << 16);
+ if (!tbl)
+ return NULL;
+
+ for (i = 0; i < 65536; ++i) {
+ tbl[i] = pow(i / 65535.0, e) * 65535.0;
+ }
+ return tbl;
+}
+
av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
SwsFilter *dstFilter)
{
- int i;
+ int i, j;
int usesVFilter, usesHFilter;
int unscaled;
SwsFilter dummyFilter = { NULL, NULL, NULL, NULL };
@@ -883,13 +989,14 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
int srcH = c->srcH;
int dstW = c->dstW;
int dstH = c->dstH;
- int dst_stride = FFALIGN(dstW * sizeof(int16_t) + 16, 16);
- int dst_stride_px = dst_stride >> 1;
+ int dst_stride = FFALIGN(dstW * sizeof(int16_t) + 66, 16);
int flags, cpu_flags;
enum AVPixelFormat srcFormat = c->srcFormat;
enum AVPixelFormat dstFormat = c->dstFormat;
- const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(srcFormat);
- const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(dstFormat);
+ const AVPixFmtDescriptor *desc_src;
+ const AVPixFmtDescriptor *desc_dst;
+ int ret = 0;
+ enum AVPixelFormat tmpFmt;
cpu_flags = av_get_cpu_flags();
flags = c->flags;
@@ -899,16 +1006,33 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
unscaled = (srcW == dstW && srcH == dstH);
+ c->srcRange |= handle_jpeg(&c->srcFormat);
+ c->dstRange |= handle_jpeg(&c->dstFormat);
+
+ if(srcFormat!=c->srcFormat || dstFormat!=c->dstFormat)
+ av_log(c, AV_LOG_WARNING, "deprecated pixel format used, make sure you did set range correctly\n");
+
+ if (!c->contrast && !c->saturation && !c->dstFormatBpp)
+ sws_setColorspaceDetails(c, ff_yuv2rgb_coeffs[SWS_CS_DEFAULT], c->srcRange,
+ ff_yuv2rgb_coeffs[SWS_CS_DEFAULT],
+ c->dstRange, 0, 1 << 16, 1 << 16);
+
+ handle_formats(c);
+ srcFormat = c->srcFormat;
+ dstFormat = c->dstFormat;
+ desc_src = av_pix_fmt_desc_get(srcFormat);
+ desc_dst = av_pix_fmt_desc_get(dstFormat);
+
if (!(unscaled && sws_isSupportedEndiannessConversion(srcFormat) &&
av_pix_fmt_swap_endianness(srcFormat) == dstFormat)) {
if (!sws_isSupportedInput(srcFormat)) {
av_log(c, AV_LOG_ERROR, "%s is not supported as input pixel format\n",
- sws_format_name(srcFormat));
+ av_get_pix_fmt_name(srcFormat));
return AVERROR(EINVAL);
}
if (!sws_isSupportedOutput(dstFormat)) {
av_log(c, AV_LOG_ERROR, "%s is not supported as output pixel format\n",
- sws_format_name(dstFormat));
+ av_get_pix_fmt_name(dstFormat));
return AVERROR(EINVAL);
}
}
@@ -928,19 +1052,19 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
/* provide a default scaler if not set by caller */
if (!i) {
if (dstW < srcW && dstH < srcH)
- flags |= SWS_GAUSS;
+ flags |= SWS_BICUBIC;
else if (dstW > srcW && dstH > srcH)
- flags |= SWS_SINC;
+ flags |= SWS_BICUBIC;
else
- flags |= SWS_LANCZOS;
+ flags |= SWS_BICUBIC;
c->flags = flags;
} else if (i & (i - 1)) {
av_log(c, AV_LOG_ERROR,
- "Exactly one scaler algorithm must be chosen\n");
+ "Exactly one scaler algorithm must be chosen, got %X\n", i);
return AVERROR(EINVAL);
}
/* sanity check */
- if (srcW < 4 || srcH < 1 || dstW < 8 || dstH < 1) {
+ if (srcW < 1 || srcH < 1 || dstW < 1 || dstH < 1) {
/* FIXME check if these are enough and try to lower them after
* fixing the relevant parts of the code */
av_log(c, AV_LOG_ERROR, "%dx%d -> %dx%d is invalid scaling dimension\n",
@@ -968,9 +1092,56 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
(dstFilter->lumH && dstFilter->lumH->length > 1) ||
(dstFilter->chrH && dstFilter->chrH->length > 1);
- getSubSampleFactors(&c->chrSrcHSubSample, &c->chrSrcVSubSample, srcFormat);
- getSubSampleFactors(&c->chrDstHSubSample, &c->chrDstVSubSample, dstFormat);
+ av_pix_fmt_get_chroma_sub_sample(srcFormat, &c->chrSrcHSubSample, &c->chrSrcVSubSample);
+ av_pix_fmt_get_chroma_sub_sample(dstFormat, &c->chrDstHSubSample, &c->chrDstVSubSample);
+
+ if (isAnyRGB(dstFormat) && !(flags&SWS_FULL_CHR_H_INT)) {
+ if (dstW&1) {
+ av_log(c, AV_LOG_DEBUG, "Forcing full internal H chroma due to odd output size\n");
+ flags |= SWS_FULL_CHR_H_INT;
+ c->flags = flags;
+ }
+
+ if ( c->chrSrcHSubSample == 0
+ && c->chrSrcVSubSample == 0
+ && c->dither != SWS_DITHER_BAYER //SWS_FULL_CHR_H_INT is currently not supported with SWS_DITHER_BAYER
+ && !(c->flags & SWS_FAST_BILINEAR)
+ ) {
+ av_log(c, AV_LOG_DEBUG, "Forcing full internal H chroma due to input having non subsampled chroma\n");
+ flags |= SWS_FULL_CHR_H_INT;
+ c->flags = flags;
+ }
+ }
+
+ if (c->dither == SWS_DITHER_AUTO) {
+ if (flags & SWS_ERROR_DIFFUSION)
+ c->dither = SWS_DITHER_ED;
+ }
+ if(dstFormat == AV_PIX_FMT_BGR4_BYTE ||
+ dstFormat == AV_PIX_FMT_RGB4_BYTE ||
+ dstFormat == AV_PIX_FMT_BGR8 ||
+ dstFormat == AV_PIX_FMT_RGB8) {
+ if (c->dither == SWS_DITHER_AUTO)
+ c->dither = (flags & SWS_FULL_CHR_H_INT) ? SWS_DITHER_ED : SWS_DITHER_BAYER;
+ if (!(flags & SWS_FULL_CHR_H_INT)) {
+ if (c->dither == SWS_DITHER_ED || c->dither == SWS_DITHER_A_DITHER || c->dither == SWS_DITHER_X_DITHER) {
+ av_log(c, AV_LOG_DEBUG,
+ "Desired dithering only supported in full chroma interpolation for destination format '%s'\n",
+ av_get_pix_fmt_name(dstFormat));
+ flags |= SWS_FULL_CHR_H_INT;
+ c->flags = flags;
+ }
+ }
+ if (flags & SWS_FULL_CHR_H_INT) {
+ if (c->dither == SWS_DITHER_BAYER) {
+ av_log(c, AV_LOG_DEBUG,
+ "Ordered dither is not supported in full chroma interpolation for destination format '%s'\n",
+ av_get_pix_fmt_name(dstFormat));
+ c->dither = SWS_DITHER_ED;
+ }
+ }
+ }
if (isPlanarRGB(dstFormat)) {
if (!(flags & SWS_FULL_CHR_H_INT)) {
av_log(c, AV_LOG_DEBUG,
@@ -991,10 +1162,15 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
dstFormat != AV_PIX_FMT_BGRA &&
dstFormat != AV_PIX_FMT_ABGR &&
dstFormat != AV_PIX_FMT_RGB24 &&
- dstFormat != AV_PIX_FMT_BGR24) {
- av_log(c, AV_LOG_ERROR,
+ dstFormat != AV_PIX_FMT_BGR24 &&
+ dstFormat != AV_PIX_FMT_BGR4_BYTE &&
+ dstFormat != AV_PIX_FMT_RGB4_BYTE &&
+ dstFormat != AV_PIX_FMT_BGR8 &&
+ dstFormat != AV_PIX_FMT_RGB8
+ ) {
+ av_log(c, AV_LOG_WARNING,
"full chroma interpolation for destination format '%s' not yet implemented\n",
- sws_format_name(dstFormat));
+ av_get_pix_fmt_name(dstFormat));
flags &= ~SWS_FULL_CHR_H_INT;
c->flags = flags;
}
@@ -1014,30 +1190,20 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
srcFormat != AV_PIX_FMT_RGB4_BYTE && srcFormat != AV_PIX_FMT_BGR4_BYTE &&
srcFormat != AV_PIX_FMT_GBRP9BE && srcFormat != AV_PIX_FMT_GBRP9LE &&
srcFormat != AV_PIX_FMT_GBRP10BE && srcFormat != AV_PIX_FMT_GBRP10LE &&
+ srcFormat != AV_PIX_FMT_GBRP12BE && srcFormat != AV_PIX_FMT_GBRP12LE &&
+ srcFormat != AV_PIX_FMT_GBRP14BE && srcFormat != AV_PIX_FMT_GBRP14LE &&
srcFormat != AV_PIX_FMT_GBRP16BE && srcFormat != AV_PIX_FMT_GBRP16LE &&
((dstW >> c->chrDstHSubSample) <= (srcW >> 1) ||
(flags & SWS_FAST_BILINEAR)))
c->chrSrcHSubSample = 1;
- // Note the -((-x)>>y) is so that we always round toward +inf.
- c->chrSrcW = -((-srcW) >> c->chrSrcHSubSample);
- c->chrSrcH = -((-srcH) >> c->chrSrcVSubSample);
- c->chrDstW = -((-dstW) >> c->chrDstHSubSample);
- c->chrDstH = -((-dstH) >> c->chrDstVSubSample);
+ // Note the FF_CEIL_RSHIFT is so that we always round toward +inf.
+ c->chrSrcW = FF_CEIL_RSHIFT(srcW, c->chrSrcHSubSample);
+ c->chrSrcH = FF_CEIL_RSHIFT(srcH, c->chrSrcVSubSample);
+ c->chrDstW = FF_CEIL_RSHIFT(dstW, c->chrDstHSubSample);
+ c->chrDstH = FF_CEIL_RSHIFT(dstH, c->chrDstVSubSample);
- /* unscaled special cases */
- if (unscaled && !usesHFilter && !usesVFilter &&
- (c->srcRange == c->dstRange || isAnyRGB(dstFormat))) {
- ff_get_unscaled_swscale(c);
-
- if (c->swscale) {
- if (flags & SWS_PRINT_INFO)
- av_log(c, AV_LOG_INFO,
- "using unscaled %s -> %s special converter\n",
- sws_format_name(srcFormat), sws_format_name(dstFormat));
- return 0;
- }
- }
+ FF_ALLOCZ_OR_GOTO(c, c->formatConvBuffer, FFALIGN(srcW*2+78, 16) * 2, fail);
c->srcBpc = 1 + desc_src->comp[0].depth_minus1;
if (c->srcBpc < 8)
@@ -1045,21 +1211,23 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
c->dstBpc = 1 + desc_dst->comp[0].depth_minus1;
if (c->dstBpc < 8)
c->dstBpc = 8;
+ if (isAnyRGB(srcFormat) || srcFormat == AV_PIX_FMT_PAL8)
+ c->srcBpc = 16;
if (c->dstBpc == 16)
dst_stride <<= 1;
- FF_ALLOC_OR_GOTO(c, c->formatConvBuffer,
- (FFALIGN(srcW, 16) * 2 * FFALIGN(c->srcBpc, 8) >> 3) + 16,
- fail);
- if (INLINE_MMXEXT(cpu_flags) && c->srcBpc == 8 && c->dstBpc <= 10) {
- c->canMMXEXTBeUsed = (dstW >= srcW && (dstW & 31) == 0 &&
- (srcW & 15) == 0) ? 1 : 0;
- if (!c->canMMXEXTBeUsed && dstW >= srcW && (srcW & 15) == 0
+
+ if (INLINE_MMXEXT(cpu_flags) && c->srcBpc == 8 && c->dstBpc <= 14) {
+ c->canMMXEXTBeUsed = dstW >= srcW && (dstW & 31) == 0 &&
+ c->chrDstW >= c->chrSrcW &&
+ (srcW & 15) == 0;
+ if (!c->canMMXEXTBeUsed && dstW >= srcW && c->chrDstW >= c->chrSrcW && (srcW & 15) == 0
+
&& (flags & SWS_FAST_BILINEAR)) {
if (flags & SWS_PRINT_INFO)
av_log(c, AV_LOG_INFO,
"output width is not a multiple of 32 -> no MMXEXT scaler\n");
}
- if (usesHFilter)
+ if (usesHFilter || isNBPS(c->srcFormat) || is16BPS(c->srcFormat) || isAnyRGB(c->srcFormat))
c->canMMXEXTBeUsed = 0;
} else
c->canMMXEXTBeUsed = 0;
@@ -1080,12 +1248,88 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
c->chrXInc += 20;
}
// we don't use the x86 asm scaler if MMX is available
- else if (INLINE_MMX(cpu_flags)) {
+ else if (INLINE_MMX(cpu_flags) && c->dstBpc <= 14) {
c->lumXInc = ((int64_t)(srcW - 2) << 16) / (dstW - 2) - 20;
c->chrXInc = ((int64_t)(c->chrSrcW - 2) << 16) / (c->chrDstW - 2) - 20;
}
}
+ // hardcoded for now
+ c->gamma_value = 2.2;
+ tmpFmt = AV_PIX_FMT_RGBA64LE;
+
+
+ if (!unscaled && c->gamma_flag && (srcFormat != tmpFmt || dstFormat != tmpFmt)) {
+ SwsContext *c2;
+ c->cascaded_context[0] = NULL;
+
+ ret = av_image_alloc(c->cascaded_tmp, c->cascaded_tmpStride,
+ srcW, srcH, tmpFmt, 64);
+ if (ret < 0)
+ return ret;
+
+ c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat,
+ srcW, srcH, tmpFmt,
+ flags, NULL, NULL, c->param);
+ if (!c->cascaded_context[0]) {
+ return -1;
+ }
+
+ c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFmt,
+ dstW, dstH, tmpFmt,
+ flags, srcFilter, dstFilter, c->param);
+
+ if (!c->cascaded_context[1])
+ return -1;
+
+ c2 = c->cascaded_context[1];
+ c2->is_internal_gamma = 1;
+ c2->gamma = alloc_gamma_tbl( c->gamma_value);
+ c2->inv_gamma = alloc_gamma_tbl(1.f/c->gamma_value);
+ if (!c2->gamma || !c2->inv_gamma)
+ return AVERROR(ENOMEM);
+
+ c->cascaded_context[2] = NULL;
+ if (dstFormat != tmpFmt) {
+ ret = av_image_alloc(c->cascaded1_tmp, c->cascaded1_tmpStride,
+ dstW, dstH, tmpFmt, 64);
+ if (ret < 0)
+ return ret;
+
+ c->cascaded_context[2] = sws_getContext(dstW, dstH, tmpFmt,
+ dstW, dstH, dstFormat,
+ flags, NULL, NULL, c->param);
+ if (!c->cascaded_context[2])
+ return -1;
+ }
+ return 0;
+ }
+
+ if (isBayer(srcFormat)) {
+ if (!unscaled ||
+ (dstFormat != AV_PIX_FMT_RGB24 && dstFormat != AV_PIX_FMT_YUV420P)) {
+ enum AVPixelFormat tmpFormat = AV_PIX_FMT_RGB24;
+
+ ret = av_image_alloc(c->cascaded_tmp, c->cascaded_tmpStride,
+ srcW, srcH, tmpFormat, 64);
+ if (ret < 0)
+ return ret;
+
+ c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat,
+ srcW, srcH, tmpFormat,
+ flags, srcFilter, NULL, c->param);
+ if (!c->cascaded_context[0])
+ return -1;
+
+ c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFormat,
+ dstW, dstH, dstFormat,
+ flags, NULL, dstFilter, c->param);
+ if (!c->cascaded_context[1])
+ return -1;
+ return 0;
+ }
+ }
+
#define USE_MMAP (HAVE_MMAP && HAVE_MPROTECT && defined MAP_ANONYMOUS)
/* precalculate horizontal scaler filter coefficients */
@@ -1093,9 +1337,9 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
#if HAVE_MMXEXT_INLINE
// can't downscale !!!
if (c->canMMXEXTBeUsed && (flags & SWS_FAST_BILINEAR)) {
- c->lumMmxextFilterCodeSize = init_hscaler_mmxext(dstW, c->lumXInc, NULL,
+ c->lumMmxextFilterCodeSize = ff_init_hscaler_mmxext(dstW, c->lumXInc, NULL,
NULL, NULL, 8);
- c->chrMmxextFilterCodeSize = init_hscaler_mmxext(c->chrDstW, c->chrXInc,
+ c->chrMmxextFilterCodeSize = ff_init_hscaler_mmxext(c->chrDstW, c->chrXInc,
NULL, NULL, NULL, 4);
#if USE_MMAP
@@ -1121,21 +1365,32 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
c->chrMmxextFilterCode = av_malloc(c->chrMmxextFilterCodeSize);
#endif
+#ifdef MAP_ANONYMOUS
+ if (c->lumMmxextFilterCode == MAP_FAILED || c->chrMmxextFilterCode == MAP_FAILED)
+#else
if (!c->lumMmxextFilterCode || !c->chrMmxextFilterCode)
+#endif
+ {
+ av_log(c, AV_LOG_ERROR, "Failed to allocate MMX2FilterCode\n");
return AVERROR(ENOMEM);
+ }
+
FF_ALLOCZ_OR_GOTO(c, c->hLumFilter, (dstW / 8 + 8) * sizeof(int16_t), fail);
FF_ALLOCZ_OR_GOTO(c, c->hChrFilter, (c->chrDstW / 4 + 8) * sizeof(int16_t), fail);
FF_ALLOCZ_OR_GOTO(c, c->hLumFilterPos, (dstW / 2 / 8 + 8) * sizeof(int32_t), fail);
FF_ALLOCZ_OR_GOTO(c, c->hChrFilterPos, (c->chrDstW / 2 / 4 + 8) * sizeof(int32_t), fail);
- init_hscaler_mmxext(dstW, c->lumXInc, c->lumMmxextFilterCode,
- c->hLumFilter, c->hLumFilterPos, 8);
- init_hscaler_mmxext(c->chrDstW, c->chrXInc, c->chrMmxextFilterCode,
- c->hChrFilter, c->hChrFilterPos, 4);
+ ff_init_hscaler_mmxext( dstW, c->lumXInc, c->lumMmxextFilterCode,
+ c->hLumFilter, (uint32_t*)c->hLumFilterPos, 8);
+ ff_init_hscaler_mmxext(c->chrDstW, c->chrXInc, c->chrMmxextFilterCode,
+ c->hChrFilter, (uint32_t*)c->hChrFilterPos, 4);
#if USE_MMAP
- mprotect(c->lumMmxextFilterCode, c->lumMmxextFilterCodeSize, PROT_EXEC | PROT_READ);
- mprotect(c->chrMmxextFilterCode, c->chrMmxextFilterCodeSize, PROT_EXEC | PROT_READ);
+ if ( mprotect(c->lumMmxextFilterCode, c->lumMmxextFilterCodeSize, PROT_EXEC | PROT_READ) == -1
+ || mprotect(c->chrMmxextFilterCode, c->chrMmxextFilterCodeSize, PROT_EXEC | PROT_READ) == -1) {
+ av_log(c, AV_LOG_ERROR, "mprotect failed, cannot use fast bilinear scaler\n");
+ goto fail;
+ }
#endif
} else
#endif /* HAVE_MMXEXT_INLINE */
@@ -1143,19 +1398,23 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
const int filterAlign = X86_MMX(cpu_flags) ? 4 :
PPC_ALTIVEC(cpu_flags) ? 8 : 1;
- if (initFilter(&c->hLumFilter, &c->hLumFilterPos,
+ if ((ret = initFilter(&c->hLumFilter, &c->hLumFilterPos,
&c->hLumFilterSize, c->lumXInc,
srcW, dstW, filterAlign, 1 << 14,
(flags & SWS_BICUBLIN) ? (flags | SWS_BICUBIC) : flags,
cpu_flags, srcFilter->lumH, dstFilter->lumH,
- c->param, 1) < 0)
+ c->param,
+ get_local_pos(c, 0, 0, 0),
+ get_local_pos(c, 0, 0, 0))) < 0)
goto fail;
- if (initFilter(&c->hChrFilter, &c->hChrFilterPos,
+ if ((ret = initFilter(&c->hChrFilter, &c->hChrFilterPos,
&c->hChrFilterSize, c->chrXInc,
c->chrSrcW, c->chrDstW, filterAlign, 1 << 14,
(flags & SWS_BICUBLIN) ? (flags | SWS_BILINEAR) : flags,
cpu_flags, srcFilter->chrH, dstFilter->chrH,
- c->param, 1) < 0)
+ c->param,
+ get_local_pos(c, c->chrSrcHSubSample, c->src_h_chr_pos, 0),
+ get_local_pos(c, c->chrDstHSubSample, c->dst_h_chr_pos, 0))) < 0)
goto fail;
}
} // initialize horizontal stuff
@@ -1165,18 +1424,23 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
const int filterAlign = X86_MMX(cpu_flags) ? 2 :
PPC_ALTIVEC(cpu_flags) ? 8 : 1;
- if (initFilter(&c->vLumFilter, &c->vLumFilterPos, &c->vLumFilterSize,
+ if ((ret = initFilter(&c->vLumFilter, &c->vLumFilterPos, &c->vLumFilterSize,
c->lumYInc, srcH, dstH, filterAlign, (1 << 12),
(flags & SWS_BICUBLIN) ? (flags | SWS_BICUBIC) : flags,
cpu_flags, srcFilter->lumV, dstFilter->lumV,
- c->param, 0) < 0)
+ c->param,
+ get_local_pos(c, 0, 0, 1),
+ get_local_pos(c, 0, 0, 1))) < 0)
goto fail;
- if (initFilter(&c->vChrFilter, &c->vChrFilterPos, &c->vChrFilterSize,
+ if ((ret = initFilter(&c->vChrFilter, &c->vChrFilterPos, &c->vChrFilterSize,
c->chrYInc, c->chrSrcH, c->chrDstH,
filterAlign, (1 << 12),
(flags & SWS_BICUBLIN) ? (flags | SWS_BILINEAR) : flags,
cpu_flags, srcFilter->chrV, dstFilter->chrV,
- c->param, 0) < 0)
+ c->param,
+ get_local_pos(c, c->chrSrcVSubSample, c->src_v_chr_pos, 1),
+ get_local_pos(c, c->chrDstVSubSample, c->dst_v_chr_pos, 1))) < 0)
+
goto fail;
#if HAVE_ALTIVEC
@@ -1218,6 +1482,9 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
c->vChrFilterPos[chrI];
}
+ for (i = 0; i < 4; i++)
+ FF_ALLOCZ_OR_GOTO(c, c->dither_error[i], (c->dstW+2) * sizeof(int), fail);
+
/* Allocate pixbufs (we use dynamic allocation because otherwise we would
* need to allocate several megabytes to handle all possible cases) */
FF_ALLOC_OR_GOTO(c, c->lumPixBuf, c->vLumBufSize * 3 * sizeof(int16_t *), fail);
@@ -1233,9 +1500,9 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
dst_stride + 16, fail);
c->lumPixBuf[i] = c->lumPixBuf[i + c->vLumBufSize];
}
- // 64 / (c->dstBpc & ~7) is the same as 16 / sizeof(scaling_intermediate)
- c->uv_off_px = dst_stride_px + 64 / (c->dstBpc & ~7);
- c->uv_off_byte = dst_stride + 16;
+ // 64 / c->scalingBpp is the same as 16 / sizeof(scaling_intermediate)
+ c->uv_off = (dst_stride>>1) + 64 / (c->dstBpc &~ 7);
+ c->uv_offx2 = dst_stride + 16;
for (i = 0; i < c->vChrBufSize; i++) {
FF_ALLOC_OR_GOTO(c, c->chrUPixBuf[i + c->vChrBufSize],
dst_stride * 2 + 32, fail);
@@ -1252,38 +1519,30 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
// try to avoid drawing green stuff between the right end and the stride end
for (i = 0; i < c->vChrBufSize; i++)
- memset(c->chrUPixBuf[i], 64, dst_stride * 2 + 1);
+ if(desc_dst->comp[0].depth_minus1 == 15){
+ av_assert0(c->dstBpc > 14);
+ for(j=0; j<dst_stride/2+1; j++)
+ ((int32_t*)(c->chrUPixBuf[i]))[j] = 1<<18;
+ } else
+ for(j=0; j<dst_stride+1; j++)
+ ((int16_t*)(c->chrUPixBuf[i]))[j] = 1<<14;
- assert(c->chrDstH <= dstH);
+ av_assert0(c->chrDstH <= dstH);
if (flags & SWS_PRINT_INFO) {
- if (flags & SWS_FAST_BILINEAR)
- av_log(c, AV_LOG_INFO, "FAST_BILINEAR scaler, ");
- else if (flags & SWS_BILINEAR)
- av_log(c, AV_LOG_INFO, "BILINEAR scaler, ");
- else if (flags & SWS_BICUBIC)
- av_log(c, AV_LOG_INFO, "BICUBIC scaler, ");
- else if (flags & SWS_X)
- av_log(c, AV_LOG_INFO, "Experimental scaler, ");
- else if (flags & SWS_POINT)
- av_log(c, AV_LOG_INFO, "Nearest Neighbor / POINT scaler, ");
- else if (flags & SWS_AREA)
- av_log(c, AV_LOG_INFO, "Area Averaging scaler, ");
- else if (flags & SWS_BICUBLIN)
- av_log(c, AV_LOG_INFO, "luma BICUBIC / chroma BILINEAR scaler, ");
- else if (flags & SWS_GAUSS)
- av_log(c, AV_LOG_INFO, "Gaussian scaler, ");
- else if (flags & SWS_SINC)
- av_log(c, AV_LOG_INFO, "Sinc scaler, ");
- else if (flags & SWS_LANCZOS)
- av_log(c, AV_LOG_INFO, "Lanczos scaler, ");
- else if (flags & SWS_SPLINE)
- av_log(c, AV_LOG_INFO, "Bicubic spline scaler, ");
- else
- av_log(c, AV_LOG_INFO, "ehh flags invalid?! ");
+ const char *scaler = NULL, *cpucaps;
- av_log(c, AV_LOG_INFO, "from %s to %s%s ",
- sws_format_name(srcFormat),
+ for (i = 0; i < FF_ARRAY_ELEMS(scale_algorithms); i++) {
+ if (flags & scale_algorithms[i].flag) {
+ scaler = scale_algorithms[i].description;
+ break;
+ }
+ }
+ if (!scaler)
+ scaler = "ehh flags invalid?!";
+ 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 ||
@@ -1292,18 +1551,20 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
#else
"",
#endif
- sws_format_name(dstFormat));
+ av_get_pix_fmt_name(dstFormat));
if (INLINE_MMXEXT(cpu_flags))
- av_log(c, AV_LOG_INFO, "using MMXEXT\n");
+ cpucaps = "MMXEXT";
else if (INLINE_AMD3DNOW(cpu_flags))
- av_log(c, AV_LOG_INFO, "using 3DNOW\n");
+ cpucaps = "3DNOW";
else if (INLINE_MMX(cpu_flags))
- av_log(c, AV_LOG_INFO, "using MMX\n");
+ cpucaps = "MMX";
else if (PPC_ALTIVEC(cpu_flags))
- av_log(c, AV_LOG_INFO, "using AltiVec\n");
+ cpucaps = "AltiVec";
else
- av_log(c, AV_LOG_INFO, "using C\n");
+ cpucaps = "C";
+
+ av_log(c, AV_LOG_INFO, "using %s\n", cpucaps);
av_log(c, AV_LOG_VERBOSE, "%dx%d -> %dx%d\n", srcW, srcH, dstW, dstH);
av_log(c, AV_LOG_DEBUG,
@@ -1315,9 +1576,49 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
c->chrXInc, c->chrYInc);
}
+ /* unscaled special cases */
+ if (unscaled && !usesHFilter && !usesVFilter &&
+ (c->srcRange == c->dstRange || isAnyRGB(dstFormat))) {
+ ff_get_unscaled_swscale(c);
+
+ if (c->swscale) {
+ if (flags & SWS_PRINT_INFO)
+ av_log(c, AV_LOG_INFO,
+ "using unscaled %s -> %s special converter\n",
+ av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
+ return 0;
+ }
+ }
+
c->swscale = ff_getSwsFunc(c);
return 0;
fail: // FIXME replace things by appropriate error codes
+ if (ret == RETCODE_USE_CASCADE) {
+ int tmpW = sqrt(srcW * (int64_t)dstW);
+ int tmpH = sqrt(srcH * (int64_t)dstH);
+ enum AVPixelFormat tmpFormat = AV_PIX_FMT_YUV420P;
+
+ if (srcW*(int64_t)srcH <= 4LL*dstW*dstH)
+ return AVERROR(EINVAL);
+
+ ret = av_image_alloc(c->cascaded_tmp, c->cascaded_tmpStride,
+ tmpW, tmpH, tmpFormat, 64);
+ if (ret < 0)
+ return ret;
+
+ c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat,
+ tmpW, tmpH, tmpFormat,
+ flags, srcFilter, NULL, c->param);
+ if (!c->cascaded_context[0])
+ return -1;
+
+ c->cascaded_context[1] = sws_getContext(tmpW, tmpH, tmpFormat,
+ dstW, dstH, dstFormat,
+ flags, NULL, dstFilter, c->param);
+ if (!c->cascaded_context[1])
+ return -1;
+ return 0;
+ }
return -1;
}
@@ -1336,8 +1637,6 @@ SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
c->srcH = srcH;
c->dstW = dstW;
c->dstH = dstH;
- c->srcRange = handle_jpeg(&srcFormat);
- c->dstRange = handle_jpeg(&dstFormat);
c->srcFormat = srcFormat;
c->dstFormat = dstFormat;
@@ -1345,9 +1644,6 @@ SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
c->param[0] = param[0];
c->param[1] = param[1];
}
- sws_setColorspaceDetails(c, ff_yuv2rgb_coeffs[SWS_CS_DEFAULT], c->srcRange,
- ff_yuv2rgb_coeffs[SWS_CS_DEFAULT] /* FIXME*/,
- c->dstRange, 0, 1 << 16, 1 << 16);
if (sws_init_context(c, srcFilter, dstFilter) < 0) {
sws_freeContext(c);
@@ -1436,7 +1732,12 @@ fail:
SwsVector *sws_allocVec(int length)
{
- SwsVector *vec = av_malloc(sizeof(SwsVector));
+ SwsVector *vec;
+
+ if(length <= 0 || length > INT_MAX/ sizeof(double))
+ return NULL;
+
+ vec = av_malloc(sizeof(SwsVector));
if (!vec)
return NULL;
vec->length = length;
@@ -1451,7 +1752,12 @@ SwsVector *sws_getGaussianVec(double variance, double quality)
const int length = (int)(variance * quality + 0.5) | 1;
int i;
double middle = (length - 1) * 0.5;
- SwsVector *vec = sws_allocVec(length);
+ SwsVector *vec;
+
+ if(variance < 0 || quality < 0)
+ return NULL;
+
+ vec = sws_allocVec(length);
if (!vec)
return NULL;
@@ -1618,14 +1924,12 @@ void sws_convVec(SwsVector *a, SwsVector *b)
SwsVector *sws_cloneVec(SwsVector *a)
{
- int i;
SwsVector *vec = sws_allocVec(a->length);
if (!vec)
return NULL;
- for (i = 0; i < a->length; i++)
- vec->coeff[i] = a->coeff[i];
+ memcpy(vec->coeff, a->coeff, a->length * sizeof(*a->coeff));
return vec;
}
@@ -1670,14 +1974,10 @@ void sws_freeFilter(SwsFilter *filter)
if (!filter)
return;
- if (filter->lumH)
- sws_freeVec(filter->lumH);
- if (filter->lumV)
- sws_freeVec(filter->lumV);
- if (filter->chrH)
- sws_freeVec(filter->chrH);
- if (filter->chrV)
- sws_freeVec(filter->chrV);
+ sws_freeVec(filter->lumH);
+ sws_freeVec(filter->lumV);
+ sws_freeVec(filter->chrH);
+ sws_freeVec(filter->chrV);
av_free(filter);
}
@@ -1706,6 +2006,9 @@ void sws_freeContext(SwsContext *c)
av_freep(&c->alpPixBuf);
}
+ for (i = 0; i < 4; i++)
+ av_freep(&c->dither_error[i]);
+
av_freep(&c->vLumFilter);
av_freep(&c->vChrFilter);
av_freep(&c->hLumFilter);
@@ -1740,7 +2043,18 @@ void sws_freeContext(SwsContext *c)
#endif /* HAVE_MMX_INLINE */
av_freep(&c->yuvTable);
- av_free(c->formatConvBuffer);
+ av_freep(&c->formatConvBuffer);
+
+ sws_freeContext(c->cascaded_context[0]);
+ sws_freeContext(c->cascaded_context[1]);
+ sws_freeContext(c->cascaded_context[2]);
+ memset(c->cascaded_context, 0, sizeof(c->cascaded_context));
+ av_freep(&c->cascaded_tmp[0]);
+ av_freep(&c->cascaded1_tmp[0]);
+
+ av_freep(&c->gamma);
+ av_freep(&c->inv_gamma);
+
av_free(c);
}
@@ -1755,6 +2069,8 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW,
{
static const double default_param[2] = { SWS_PARAM_DEFAULT,
SWS_PARAM_DEFAULT };
+ int64_t src_h_chr_pos = -513, dst_h_chr_pos = -513,
+ src_v_chr_pos = -513, dst_v_chr_pos = -513;
if (!param)
param = default_param;
@@ -1769,6 +2085,11 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW,
context->flags != flags ||
context->param[0] != param[0] ||
context->param[1] != param[1])) {
+
+ av_opt_get_int(context, "src_h_chr_pos", 0, &src_h_chr_pos);
+ av_opt_get_int(context, "src_v_chr_pos", 0, &src_v_chr_pos);
+ av_opt_get_int(context, "dst_h_chr_pos", 0, &dst_h_chr_pos);
+ av_opt_get_int(context, "dst_v_chr_pos", 0, &dst_v_chr_pos);
sws_freeContext(context);
context = NULL;
}
@@ -1778,19 +2099,19 @@ struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW,
return NULL;
context->srcW = srcW;
context->srcH = srcH;
- context->srcRange = handle_jpeg(&srcFormat);
context->srcFormat = srcFormat;
context->dstW = dstW;
context->dstH = dstH;
- context->dstRange = handle_jpeg(&dstFormat);
context->dstFormat = dstFormat;
context->flags = flags;
context->param[0] = param[0];
context->param[1] = param[1];
- sws_setColorspaceDetails(context, ff_yuv2rgb_coeffs[SWS_CS_DEFAULT],
- context->srcRange,
- ff_yuv2rgb_coeffs[SWS_CS_DEFAULT] /* FIXME*/,
- context->dstRange, 0, 1 << 16, 1 << 16);
+
+ av_opt_set_int(context, "src_h_chr_pos", src_h_chr_pos, 0);
+ av_opt_set_int(context, "src_v_chr_pos", src_v_chr_pos, 0);
+ av_opt_set_int(context, "dst_h_chr_pos", dst_h_chr_pos, 0);
+ av_opt_set_int(context, "dst_v_chr_pos", dst_v_chr_pos, 0);
+
if (sws_init_context(context, srcFilter, dstFilter) < 0) {
sws_freeContext(context);
return NULL;
diff --git a/libswscale/version.h b/libswscale/version.h
index fdde657168..228c5770eb 100644
--- a/libswscale/version.h
+++ b/libswscale/version.h
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,8 +27,8 @@
#include "libavutil/version.h"
#define LIBSWSCALE_VERSION_MAJOR 3
-#define LIBSWSCALE_VERSION_MINOR 0
-#define LIBSWSCALE_VERSION_MICRO 0
+#define LIBSWSCALE_VERSION_MINOR 1
+#define LIBSWSCALE_VERSION_MICRO 101
#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \
LIBSWSCALE_VERSION_MINOR, \
diff --git a/libswscale/x86/Makefile b/libswscale/x86/Makefile
index b94b14abbb..69012077bb 100644
--- a/libswscale/x86/Makefile
+++ b/libswscale/x86/Makefile
@@ -1,7 +1,11 @@
+$(SUBDIR)x86/swscale_mmx.o: CFLAGS += $(NOREDZONE_FLAGS)
+
OBJS += x86/rgb2rgb.o \
x86/swscale.o \
x86/yuv2rgb.o \
+MMX-OBJS += x86/hscale_fast_bilinear_simd.o \
+
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
YASM-OBJS += x86/input.o \
diff --git a/libswscale/x86/hscale_fast_bilinear_simd.c b/libswscale/x86/hscale_fast_bilinear_simd.c
new file mode 100644
index 0000000000..b37b63c3ec
--- /dev/null
+++ b/libswscale/x86/hscale_fast_bilinear_simd.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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_internal.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+
+#define RET 0xC3 // near return opcode for x86
+#define PREFETCH "prefetchnta"
+
+#if HAVE_INLINE_ASM
+av_cold int ff_init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode,
+ int16_t *filter, int32_t *filterPos,
+ int numSplits)
+{
+ uint8_t *fragmentA;
+ x86_reg imm8OfPShufW1A;
+ x86_reg imm8OfPShufW2A;
+ x86_reg fragmentLengthA;
+ uint8_t *fragmentB;
+ x86_reg imm8OfPShufW1B;
+ x86_reg imm8OfPShufW2B;
+ x86_reg fragmentLengthB;
+ int fragmentPos;
+
+ int xpos, i;
+
+ // create an optimized horizontal scaling routine
+ /* This scaler is made of runtime-generated MMXEXT code using specially tuned
+ * pshufw instructions. For every four output pixels, if four input pixels
+ * are enough for the fast bilinear scaling, then a chunk of fragmentB is
+ * used. If five input pixels are needed, then a chunk of fragmentA is used.
+ */
+
+ // code fragment
+
+ __asm__ volatile (
+ "jmp 9f \n\t"
+ // Begin
+ "0: \n\t"
+ "movq (%%"REG_d", %%"REG_a"), %%mm3 \n\t"
+ "movd (%%"REG_c", %%"REG_S"), %%mm0 \n\t"
+ "movd 1(%%"REG_c", %%"REG_S"), %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm1 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+ "pshufw $0xFF, %%mm1, %%mm1 \n\t"
+ "1: \n\t"
+ "pshufw $0xFF, %%mm0, %%mm0 \n\t"
+ "2: \n\t"
+ "psubw %%mm1, %%mm0 \n\t"
+ "movl 8(%%"REG_b", %%"REG_a"), %%esi \n\t"
+ "pmullw %%mm3, %%mm0 \n\t"
+ "psllw $7, %%mm1 \n\t"
+ "paddw %%mm1, %%mm0 \n\t"
+
+ "movq %%mm0, (%%"REG_D", %%"REG_a") \n\t"
+
+ "add $8, %%"REG_a" \n\t"
+ // End
+ "9: \n\t"
+ "lea " LOCAL_MANGLE(0b) ", %0 \n\t"
+ "lea " LOCAL_MANGLE(1b) ", %1 \n\t"
+ "lea " LOCAL_MANGLE(2b) ", %2 \n\t"
+ "dec %1 \n\t"
+ "dec %2 \n\t"
+ "sub %0, %1 \n\t"
+ "sub %0, %2 \n\t"
+ "lea " LOCAL_MANGLE(9b) ", %3 \n\t"
+ "sub %0, %3 \n\t"
+
+
+ : "=r" (fragmentA), "=r" (imm8OfPShufW1A), "=r" (imm8OfPShufW2A),
+ "=r" (fragmentLengthA)
+ );
+
+ __asm__ volatile (
+ "jmp 9f \n\t"
+ // Begin
+ "0: \n\t"
+ "movq (%%"REG_d", %%"REG_a"), %%mm3 \n\t"
+ "movd (%%"REG_c", %%"REG_S"), %%mm0 \n\t"
+ "punpcklbw %%mm7, %%mm0 \n\t"
+ "pshufw $0xFF, %%mm0, %%mm1 \n\t"
+ "1: \n\t"
+ "pshufw $0xFF, %%mm0, %%mm0 \n\t"
+ "2: \n\t"
+ "psubw %%mm1, %%mm0 \n\t"
+ "movl 8(%%"REG_b", %%"REG_a"), %%esi \n\t"
+ "pmullw %%mm3, %%mm0 \n\t"
+ "psllw $7, %%mm1 \n\t"
+ "paddw %%mm1, %%mm0 \n\t"
+
+ "movq %%mm0, (%%"REG_D", %%"REG_a") \n\t"
+
+ "add $8, %%"REG_a" \n\t"
+ // End
+ "9: \n\t"
+ "lea " LOCAL_MANGLE(0b) ", %0 \n\t"
+ "lea " LOCAL_MANGLE(1b) ", %1 \n\t"
+ "lea " LOCAL_MANGLE(2b) ", %2 \n\t"
+ "dec %1 \n\t"
+ "dec %2 \n\t"
+ "sub %0, %1 \n\t"
+ "sub %0, %2 \n\t"
+ "lea " LOCAL_MANGLE(9b) ", %3 \n\t"
+ "sub %0, %3 \n\t"
+
+
+ : "=r" (fragmentB), "=r" (imm8OfPShufW1B), "=r" (imm8OfPShufW2B),
+ "=r" (fragmentLengthB)
+ );
+
+ xpos = 0; // lumXInc/2 - 0x8000; // difference between pixel centers
+ fragmentPos = 0;
+
+ for (i = 0; i < dstW / numSplits; i++) {
+ int xx = xpos >> 16;
+
+ if ((i & 3) == 0) {
+ int a = 0;
+ int b = ((xpos + xInc) >> 16) - xx;
+ int c = ((xpos + xInc * 2) >> 16) - xx;
+ int d = ((xpos + xInc * 3) >> 16) - xx;
+ int inc = (d + 1 < 4);
+ uint8_t *fragment = inc ? fragmentB : fragmentA;
+ x86_reg imm8OfPShufW1 = inc ? imm8OfPShufW1B : imm8OfPShufW1A;
+ x86_reg imm8OfPShufW2 = inc ? imm8OfPShufW2B : imm8OfPShufW2A;
+ x86_reg fragmentLength = inc ? fragmentLengthB : fragmentLengthA;
+ int maxShift = 3 - (d + inc);
+ int shift = 0;
+
+ if (filterCode) {
+ filter[i] = ((xpos & 0xFFFF) ^ 0xFFFF) >> 9;
+ filter[i + 1] = (((xpos + xInc) & 0xFFFF) ^ 0xFFFF) >> 9;
+ filter[i + 2] = (((xpos + xInc * 2) & 0xFFFF) ^ 0xFFFF) >> 9;
+ filter[i + 3] = (((xpos + xInc * 3) & 0xFFFF) ^ 0xFFFF) >> 9;
+ filterPos[i / 2] = xx;
+
+ memcpy(filterCode + fragmentPos, fragment, fragmentLength);
+
+ filterCode[fragmentPos + imm8OfPShufW1] = (a + inc) |
+ ((b + inc) << 2) |
+ ((c + inc) << 4) |
+ ((d + inc) << 6);
+ filterCode[fragmentPos + imm8OfPShufW2] = a | (b << 2) |
+ (c << 4) |
+ (d << 6);
+
+ if (i + 4 - inc >= dstW)
+ shift = maxShift; // avoid overread
+ else if ((filterPos[i / 2] & 3) <= maxShift)
+ shift = filterPos[i / 2] & 3; // align
+
+ if (shift && i >= shift) {
+ filterCode[fragmentPos + imm8OfPShufW1] += 0x55 * shift;
+ filterCode[fragmentPos + imm8OfPShufW2] += 0x55 * shift;
+ filterPos[i / 2] -= shift;
+ }
+ }
+
+ fragmentPos += fragmentLength;
+
+ if (filterCode)
+ filterCode[fragmentPos] = RET;
+ }
+ xpos += xInc;
+ }
+ if (filterCode)
+ filterPos[((i / 2) + 1) & (~1)] = xpos >> 16; // needed to jump to the next part
+
+ return fragmentPos + 1;
+}
+
+void ff_hyscale_fast_mmxext(SwsContext *c, int16_t *dst,
+ int dstWidth, const uint8_t *src,
+ int srcW, int xInc)
+{
+ int32_t *filterPos = c->hLumFilterPos;
+ int16_t *filter = c->hLumFilter;
+ void *mmxextFilterCode = c->lumMmxextFilterCode;
+ int i;
+#if ARCH_X86_64
+ uint64_t retsave;
+#else
+#if defined(PIC)
+ uint64_t ebxsave;
+#endif
+#endif
+
+ __asm__ volatile(
+#if ARCH_X86_64
+ "mov -8(%%rsp), %%"REG_a" \n\t"
+ "mov %%"REG_a", %5 \n\t" // retsave
+#else
+#if defined(PIC)
+ "mov %%"REG_b", %5 \n\t" // ebxsave
+#endif
+#endif
+ "pxor %%mm7, %%mm7 \n\t"
+ "mov %0, %%"REG_c" \n\t"
+ "mov %1, %%"REG_D" \n\t"
+ "mov %2, %%"REG_d" \n\t"
+ "mov %3, %%"REG_b" \n\t"
+ "xor %%"REG_a", %%"REG_a" \n\t" // i
+ PREFETCH" (%%"REG_c") \n\t"
+ PREFETCH" 32(%%"REG_c") \n\t"
+ PREFETCH" 64(%%"REG_c") \n\t"
+
+#if ARCH_X86_64
+#define CALL_MMXEXT_FILTER_CODE \
+ "movl (%%"REG_b"), %%esi \n\t"\
+ "call *%4 \n\t"\
+ "movl (%%"REG_b", %%"REG_a"), %%esi \n\t"\
+ "add %%"REG_S", %%"REG_c" \n\t"\
+ "add %%"REG_a", %%"REG_D" \n\t"\
+ "xor %%"REG_a", %%"REG_a" \n\t"\
+
+#else
+#define CALL_MMXEXT_FILTER_CODE \
+ "movl (%%"REG_b"), %%esi \n\t"\
+ "call *%4 \n\t"\
+ "addl (%%"REG_b", %%"REG_a"), %%"REG_c" \n\t"\
+ "add %%"REG_a", %%"REG_D" \n\t"\
+ "xor %%"REG_a", %%"REG_a" \n\t"\
+
+#endif /* ARCH_X86_64 */
+
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+
+#if ARCH_X86_64
+ "mov %5, %%"REG_a" \n\t"
+ "mov %%"REG_a", -8(%%rsp) \n\t"
+#else
+#if defined(PIC)
+ "mov %5, %%"REG_b" \n\t"
+#endif
+#endif
+ :: "m" (src), "m" (dst), "m" (filter), "m" (filterPos),
+ "m" (mmxextFilterCode)
+#if ARCH_X86_64
+ ,"m"(retsave)
+#else
+#if defined(PIC)
+ ,"m" (ebxsave)
+#endif
+#endif
+ : "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S, "%"REG_D
+#if ARCH_X86_64 || !defined(PIC)
+ ,"%"REG_b
+#endif
+ );
+
+ for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--)
+ dst[i] = src[srcW-1]*128;
+}
+
+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)
+{
+ int32_t *filterPos = c->hChrFilterPos;
+ int16_t *filter = c->hChrFilter;
+ void *mmxextFilterCode = c->chrMmxextFilterCode;
+ int i;
+#if ARCH_X86_64
+ DECLARE_ALIGNED(8, uint64_t, retsave);
+#else
+#if defined(PIC)
+ DECLARE_ALIGNED(8, uint64_t, ebxsave);
+#endif
+#endif
+ __asm__ volatile(
+#if ARCH_X86_64
+ "mov -8(%%rsp), %%"REG_a" \n\t"
+ "mov %%"REG_a", %7 \n\t" // retsave
+#else
+#if defined(PIC)
+ "mov %%"REG_b", %7 \n\t" // ebxsave
+#endif
+#endif
+ "pxor %%mm7, %%mm7 \n\t"
+ "mov %0, %%"REG_c" \n\t"
+ "mov %1, %%"REG_D" \n\t"
+ "mov %2, %%"REG_d" \n\t"
+ "mov %3, %%"REG_b" \n\t"
+ "xor %%"REG_a", %%"REG_a" \n\t" // i
+ PREFETCH" (%%"REG_c") \n\t"
+ PREFETCH" 32(%%"REG_c") \n\t"
+ PREFETCH" 64(%%"REG_c") \n\t"
+
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ "xor %%"REG_a", %%"REG_a" \n\t" // i
+ "mov %5, %%"REG_c" \n\t" // src2
+ "mov %6, %%"REG_D" \n\t" // dst2
+ PREFETCH" (%%"REG_c") \n\t"
+ PREFETCH" 32(%%"REG_c") \n\t"
+ PREFETCH" 64(%%"REG_c") \n\t"
+
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+ CALL_MMXEXT_FILTER_CODE
+
+#if ARCH_X86_64
+ "mov %7, %%"REG_a" \n\t"
+ "mov %%"REG_a", -8(%%rsp) \n\t"
+#else
+#if defined(PIC)
+ "mov %7, %%"REG_b" \n\t"
+#endif
+#endif
+ :: "m" (src1), "m" (dst1), "m" (filter), "m" (filterPos),
+ "m" (mmxextFilterCode), "m" (src2), "m"(dst2)
+#if ARCH_X86_64
+ ,"m"(retsave)
+#else
+#if defined(PIC)
+ ,"m" (ebxsave)
+#endif
+#endif
+ : "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S, "%"REG_D
+#if ARCH_X86_64 || !defined(PIC)
+ ,"%"REG_b
+#endif
+ );
+
+ for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) {
+ dst1[i] = src1[srcW-1]*128;
+ dst2[i] = src2[srcW-1]*128;
+ }
+}
+#endif //HAVE_INLINE_ASM
diff --git a/libswscale/x86/input.asm b/libswscale/x86/input.asm
index 6f5677e1fd..af9afcaa53 100644
--- a/libswscale/x86/input.asm
+++ b/libswscale/x86/input.asm
@@ -4,20 +4,20 @@
;* into YUV planes also.
;* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -35,33 +35,59 @@ SECTION_RODATA
%define GV 0xD0E3
%define BV 0xF6E4
-rgb_Yrnd: times 4 dd 0x84000 ; 16.5 << 15
-rgb_UVrnd: times 4 dd 0x404000 ; 128.5 << 15
-bgr_Ycoeff_12x4: times 2 dw BY, GY, 0, BY
-bgr_Ycoeff_3x56: times 2 dw RY, 0, GY, RY
-rgb_Ycoeff_12x4: times 2 dw RY, GY, 0, RY
-rgb_Ycoeff_3x56: times 2 dw BY, 0, GY, BY
-bgr_Ucoeff_12x4: times 2 dw BU, GU, 0, BU
-bgr_Ucoeff_3x56: times 2 dw RU, 0, GU, RU
-rgb_Ucoeff_12x4: times 2 dw RU, GU, 0, RU
-rgb_Ucoeff_3x56: times 2 dw BU, 0, GU, BU
-bgr_Vcoeff_12x4: times 2 dw BV, GV, 0, BV
-bgr_Vcoeff_3x56: times 2 dw RV, 0, GV, RV
-rgb_Vcoeff_12x4: times 2 dw RV, GV, 0, RV
-rgb_Vcoeff_3x56: times 2 dw BV, 0, GV, BV
-
-rgba_Ycoeff_rb: times 4 dw RY, BY
-rgba_Ycoeff_br: times 4 dw BY, RY
-rgba_Ycoeff_ga: times 4 dw GY, 0
-rgba_Ycoeff_ag: times 4 dw 0, GY
-rgba_Ucoeff_rb: times 4 dw RU, BU
-rgba_Ucoeff_br: times 4 dw BU, RU
-rgba_Ucoeff_ga: times 4 dw GU, 0
-rgba_Ucoeff_ag: times 4 dw 0, GU
-rgba_Vcoeff_rb: times 4 dw RV, BV
-rgba_Vcoeff_br: times 4 dw BV, RV
-rgba_Vcoeff_ga: times 4 dw GV, 0
-rgba_Vcoeff_ag: times 4 dw 0, GV
+rgb_Yrnd: times 4 dd 0x80100 ; 16.5 << 15
+rgb_UVrnd: times 4 dd 0x400100 ; 128.5 << 15
+%define bgr_Ycoeff_12x4 16*4 + 16* 0 + tableq
+%define bgr_Ycoeff_3x56 16*4 + 16* 1 + tableq
+%define rgb_Ycoeff_12x4 16*4 + 16* 2 + tableq
+%define rgb_Ycoeff_3x56 16*4 + 16* 3 + tableq
+%define bgr_Ucoeff_12x4 16*4 + 16* 4 + tableq
+%define bgr_Ucoeff_3x56 16*4 + 16* 5 + tableq
+%define rgb_Ucoeff_12x4 16*4 + 16* 6 + tableq
+%define rgb_Ucoeff_3x56 16*4 + 16* 7 + tableq
+%define bgr_Vcoeff_12x4 16*4 + 16* 8 + tableq
+%define bgr_Vcoeff_3x56 16*4 + 16* 9 + tableq
+%define rgb_Vcoeff_12x4 16*4 + 16*10 + tableq
+%define rgb_Vcoeff_3x56 16*4 + 16*11 + tableq
+
+%define rgba_Ycoeff_rb 16*4 + 16*12 + tableq
+%define rgba_Ycoeff_br 16*4 + 16*13 + tableq
+%define rgba_Ycoeff_ga 16*4 + 16*14 + tableq
+%define rgba_Ycoeff_ag 16*4 + 16*15 + tableq
+%define rgba_Ucoeff_rb 16*4 + 16*16 + tableq
+%define rgba_Ucoeff_br 16*4 + 16*17 + tableq
+%define rgba_Ucoeff_ga 16*4 + 16*18 + tableq
+%define rgba_Ucoeff_ag 16*4 + 16*19 + tableq
+%define rgba_Vcoeff_rb 16*4 + 16*20 + tableq
+%define rgba_Vcoeff_br 16*4 + 16*21 + tableq
+%define rgba_Vcoeff_ga 16*4 + 16*22 + tableq
+%define rgba_Vcoeff_ag 16*4 + 16*23 + tableq
+
+; bgr_Ycoeff_12x4: times 2 dw BY, GY, 0, BY
+; bgr_Ycoeff_3x56: times 2 dw RY, 0, GY, RY
+; rgb_Ycoeff_12x4: times 2 dw RY, GY, 0, RY
+; rgb_Ycoeff_3x56: times 2 dw BY, 0, GY, BY
+; bgr_Ucoeff_12x4: times 2 dw BU, GU, 0, BU
+; bgr_Ucoeff_3x56: times 2 dw RU, 0, GU, RU
+; rgb_Ucoeff_12x4: times 2 dw RU, GU, 0, RU
+; rgb_Ucoeff_3x56: times 2 dw BU, 0, GU, BU
+; bgr_Vcoeff_12x4: times 2 dw BV, GV, 0, BV
+; bgr_Vcoeff_3x56: times 2 dw RV, 0, GV, RV
+; rgb_Vcoeff_12x4: times 2 dw RV, GV, 0, RV
+; rgb_Vcoeff_3x56: times 2 dw BV, 0, GV, BV
+
+; rgba_Ycoeff_rb: times 4 dw RY, BY
+; rgba_Ycoeff_br: times 4 dw BY, RY
+; rgba_Ycoeff_ga: times 4 dw GY, 0
+; rgba_Ycoeff_ag: times 4 dw 0, GY
+; rgba_Ucoeff_rb: times 4 dw RU, BU
+; rgba_Ucoeff_br: times 4 dw BU, RU
+; rgba_Ucoeff_ga: times 4 dw GU, 0
+; rgba_Ucoeff_ag: times 4 dw 0, GU
+; rgba_Vcoeff_rb: times 4 dw RV, BV
+; rgba_Vcoeff_br: times 4 dw BV, RV
+; rgba_Vcoeff_ga: times 4 dw GV, 0
+; 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
@@ -82,7 +108,7 @@ SECTION .text
; %1 = nr. of XMM registers
; %2 = rgb or bgr
%macro RGB24_TO_Y_FN 2-3
-cglobal %2 %+ 24ToY, 3, 3, %1, dst, src, w
+cglobal %2 %+ 24ToY, 6, 6, %1, dst, src, u1, u2, w, table
%if mmsize == 8
mova m5, [%2_Ycoeff_12x4]
mova m6, [%2_Ycoeff_3x56]
@@ -114,6 +140,7 @@ cglobal %2 %+ 24ToY, 3, 3, %1, dst, src, w
%if ARCH_X86_64
movsxd wq, wd
%endif
+ add wq, wq
add dstq, wq
neg wq
%if notcpuflag(ssse3)
@@ -157,12 +184,11 @@ cglobal %2 %+ 24ToY, 3, 3, %1, dst, src, w
paddd m2, m3 ; (dword) { Bx*BY + Gx*GY + Rx*RY }[4-7]
paddd m0, m4 ; += rgb_Yrnd, i.e. (dword) { Y[0-3] }
paddd m2, m4 ; += rgb_Yrnd, i.e. (dword) { Y[4-7] }
- psrad m0, 15
- psrad m2, 15
+ psrad m0, 9
+ psrad m2, 9
packssdw m0, m2 ; (word) { Y[0-7] }
- packuswb m0, m0 ; (byte) { Y[0-7] }
- movh [dstq+wq], m0
- add wq, mmsize / 2
+ mova [dstq+wq], m0
+ add wq, mmsize
jl .loop
REP_RET
%endif ; (ARCH_X86_64 && %0 == 3) || mmsize == 8
@@ -171,7 +197,7 @@ cglobal %2 %+ 24ToY, 3, 3, %1, dst, src, w
; %1 = nr. of XMM registers
; %2 = rgb or bgr
%macro RGB24_TO_UV_FN 2-3
-cglobal %2 %+ 24ToUV, 3, 4, %1, dstU, dstV, src, w
+cglobal %2 %+ 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]
@@ -202,10 +228,11 @@ cglobal %2 %+ 24ToUV, 3, 4, %1, dstU, dstV, src, w
%endif ; x86-32/64
%endif ; cpuflag(ssse3)
%if ARCH_X86_64
- movsxd wq, dword r4m
+ movsxd wq, dword r5m
%else ; x86-32
- mov wq, r4m
+ mov wq, r5m
%endif
+ add wq, wq
add dstUq, wq
add dstVq, wq
neg wq
@@ -263,23 +290,20 @@ cglobal %2 %+ 24ToUV, 3, 4, %1, dstU, dstV, src, w
paddd m2, m6 ; += rgb_UVrnd, i.e. (dword) { V[0-3] }
paddd m1, m6 ; += rgb_UVrnd, i.e. (dword) { U[4-7] }
paddd m4, m6 ; += rgb_UVrnd, i.e. (dword) { V[4-7] }
- psrad m0, 15
- psrad m2, 15
- psrad m1, 15
- psrad m4, 15
+ psrad m0, 9
+ psrad m2, 9
+ psrad m1, 9
+ psrad m4, 9
packssdw m0, m1 ; (word) { U[0-7] }
packssdw m2, m4 ; (word) { V[0-7] }
%if mmsize == 8
- packuswb m0, m0 ; (byte) { U[0-3] }
- packuswb m2, m2 ; (byte) { V[0-3] }
- movh [dstUq+wq], m0
- movh [dstVq+wq], m2
+ mova [dstUq+wq], m0
+ mova [dstVq+wq], m2
%else ; mmsize == 16
- packuswb m0, m2 ; (byte) { U[0-7], V[0-7] }
- movh [dstUq+wq], m0
- movhps [dstVq+wq], m0
+ mova [dstUq+wq], m0
+ mova [dstVq+wq], m2
%endif ; mmsize == 8/16
- add wq, mmsize / 2
+ add wq, mmsize
jl .loop
REP_RET
%endif ; ARCH_X86_64 && %0 == 3
@@ -305,13 +329,15 @@ RGB24_FUNCS 10, 12
INIT_XMM ssse3
RGB24_FUNCS 11, 13
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
RGB24_FUNCS 11, 13
+%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, 3, 3, %1, dst, src, w
+cglobal %2%3%4%5 %+ ToY, 6, 6, %1, dst, src, u1, u2, w, table
mova m5, [rgba_Ycoeff_%2%4]
mova m6, [rgba_Ycoeff_%3%5]
%if %0 == 6
@@ -321,7 +347,9 @@ cglobal %2%3%4%5 %+ ToY, 3, 3, %1, dst, src, w
%if ARCH_X86_64
movsxd wq, wd
%endif
- lea srcq, [srcq+wq*4]
+ add wq, wq
+ sub wq, mmsize - 1
+ lea srcq, [srcq+wq*2]
add dstq, wq
neg wq
mova m4, [rgb_Yrnd]
@@ -329,8 +357,8 @@ cglobal %2%3%4%5 %+ ToY, 3, 3, %1, dst, src, w
psrlw m7, 8 ; (word) { 0x00ff } x4
.loop:
; FIXME check alignment and use mova
- movu m0, [srcq+wq*4+0] ; (byte) { Bx, Gx, Rx, xx }[0-3]
- movu m2, [srcq+wq*4+mmsize] ; (byte) { Bx, Gx, Rx, xx }[4-7]
+ 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]
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]
@@ -340,13 +368,29 @@ cglobal %2%3%4%5 %+ ToY, 3, 3, %1, dst, src, w
paddd m2, m4 ; += rgb_Yrnd
paddd m0, m1 ; (dword) { Y[0-3] }
paddd m2, m3 ; (dword) { Y[4-7] }
- psrad m0, 15
- psrad m2, 15
+ psrad m0, 9
+ psrad m2, 9
packssdw m0, m2 ; (word) { Y[0-7] }
- packuswb m0, m0 ; (byte) { Y[0-7] }
- movh [dstq+wq], m0
- add wq, mmsize / 2
+ mova [dstq+wq], m0
+ add wq, mmsize
jl .loop
+ sub wq, mmsize - 1
+ jz .end
+ add srcq, 2*mmsize - 2
+ add dstq, mmsize - 1
+.loop2:
+ 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]
+ pmaddwd m0, m6 ; (dword) { Gx*GY }[0-3]
+ paddd m0, m4 ; += rgb_Yrnd
+ paddd m0, m1 ; (dword) { Y[0-3] }
+ psrad m0, 9
+ packssdw m0, m0 ; (word) { Y[0-7] }
+ movd [dstq+wq], m0
+ add wq, 2
+ jl .loop2
+.end:
REP_RET
%endif ; %0 == 3
%endmacro
@@ -354,7 +398,7 @@ cglobal %2%3%4%5 %+ ToY, 3, 3, %1, dst, src, w
; %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, 3, 4, %1, dstU, dstV, src, w
+cglobal %2%3%4%5 %+ 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]
@@ -375,21 +419,23 @@ cglobal %2%3%4%5 %+ ToUV, 3, 4, %1, dstU, dstV, src, w
%else ; ARCH_X86_64 && %0 == 6
.body:
%if ARCH_X86_64
- movsxd wq, dword r4m
+ movsxd wq, dword r5m
%else ; x86-32
- mov wq, r4m
+ mov wq, r5m
%endif
+ add wq, wq
+ sub wq, mmsize - 1
add dstUq, wq
add dstVq, wq
- lea srcq, [srcq+wq*4]
+ lea srcq, [srcq+wq*2]
neg wq
pcmpeqb m7, m7
psrlw m7, 8 ; (word) { 0x00ff } x4
mova m6, [rgb_UVrnd]
.loop:
; FIXME check alignment and use mova
- movu m0, [srcq+wq*4+0] ; (byte) { Bx, Gx, Rx, xx }[0-3]
- movu m4, [srcq+wq*4+mmsize] ; (byte) { Bx, Gx, Rx, xx }[4-7]
+ 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]
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]
@@ -405,26 +451,48 @@ cglobal %2%3%4%5 %+ ToUV, 3, 4, %1, dstU, dstV, src, w
pmaddwd m4, coeffU2 ; (dword) { Gx*GU }[4-7]
paddd m3, m6 ; += rgb_UVrnd
paddd m5, m6 ; += rgb_UVrnd
- psrad m0, 15
+ psrad m0, 9
paddd m1, m3 ; (dword) { V[4-7] }
paddd m4, m5 ; (dword) { U[4-7] }
- psrad m2, 15
- psrad m4, 15
- psrad m1, 15
+ psrad m2, 9
+ psrad m4, 9
+ psrad m1, 9
packssdw m0, m4 ; (word) { U[0-7] }
packssdw m2, m1 ; (word) { V[0-7] }
%if mmsize == 8
- packuswb m0, m0 ; (byte) { U[0-7] }
- packuswb m2, m2 ; (byte) { V[0-7] }
- movh [dstUq+wq], m0
- movh [dstVq+wq], m2
+ mova [dstUq+wq], m0
+ mova [dstVq+wq], m2
%else ; mmsize == 16
- packuswb m0, m2 ; (byte) { U[0-7], V[0-7] }
- movh [dstUq+wq], m0
- movhps [dstVq+wq], m0
+ mova [dstUq+wq], m0
+ mova [dstVq+wq], m2
%endif ; mmsize == 8/16
- add wq, mmsize / 2
+ add wq, mmsize
jl .loop
+ sub wq, mmsize - 1
+ jz .end
+ add srcq , 2*mmsize - 2
+ add dstUq, mmsize - 1
+ add dstVq, mmsize - 1
+.loop2:
+ 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]
+ pmaddwd m2, m0, coeffV2 ; (dword) { Gx*GV }[0-3]
+ pmaddwd m1, coeffU1 ; (dword) { Bx*BU + Rx*RU }[0-3]
+ pmaddwd m0, coeffU2 ; (dword) { Gx*GU }[0-3]
+ paddd m3, m6 ; += rgb_UVrnd
+ paddd m1, m6 ; += rgb_UVrnd
+ paddd m2, m3 ; (dword) { V[0-3] }
+ paddd m0, m1 ; (dword) { U[0-3] }
+ psrad m0, 9
+ psrad m2, 9
+ packssdw m0, m0 ; (word) { U[0-7] }
+ packssdw m2, m2 ; (word) { V[0-7] }
+ movd [dstUq+wq], m0
+ movd [dstVq+wq], m2
+ add wq, 2
+ jl .loop2
+.end:
REP_RET
%endif ; ARCH_X86_64 && %0 == 3
%endmacro
@@ -451,8 +519,10 @@ RGB32_FUNCS 0, 0
INIT_XMM sse2
RGB32_FUNCS 8, 12
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
RGB32_FUNCS 8, 12
+%endif
;-----------------------------------------------------------------------------
; YUYV/UYVY/NV12/NV21 packed pixel shuffling.
@@ -489,7 +559,7 @@ RGB32_FUNCS 8, 12
; will be the same (i.e. YUYV+AVX), and thus we don't need to
; split the loop in an aligned and unaligned case
%macro YUYV_TO_Y_FN 2-3
-cglobal %2ToY, 3, 3, %1, dst, src, w
+cglobal %2ToY, 5, 5, %1, dst, unused0, unused1, src, w
%if ARCH_X86_64
movsxd wq, wd
%endif
@@ -559,11 +629,11 @@ cglobal %2ToY, 3, 3, %1, dst, src, w
; will be the same (i.e. UYVY+AVX), and thus we don't need to
; split the loop in an aligned and unaligned case
%macro YUYV_TO_UV_FN 2-3
-cglobal %2ToUV, 3, 4, %1, dstU, dstV, src, w
+cglobal %2ToUV, 4, 5, %1, dstU, dstV, unused, src, w
%if ARCH_X86_64
- movsxd wq, dword r4m
+ movsxd wq, dword r5m
%else ; x86-32
- mov wq, r4m
+ mov wq, r5m
%endif
add dstUq, wq
add dstVq, wq
@@ -593,8 +663,8 @@ cglobal %2ToUV, 3, 4, %1, dstU, dstV, src, w
.loop_%1:
mov%1 m0, [srcq+wq*2] ; (byte) { U0, V0, U1, V1, ... }
mov%1 m1, [srcq+wq*2+mmsize] ; (byte) { U8, V8, U9, V9, ... }
- pand m2, m0, m4 ; (word) { U0, U1, ..., U7 }
- pand m3, m1, m4 ; (word) { U8, U9, ..., U15 }
+ pand m2, m0, m5 ; (word) { U0, U1, ..., U7 }
+ pand m3, m1, m5 ; (word) { U8, U9, ..., U15 }
psrlw m0, 8 ; (word) { V0, V1, ..., V7 }
psrlw m1, 8 ; (word) { V8, V9, ..., V15 }
packuswb m2, m3 ; (byte) { U0, ..., U15 }
@@ -614,11 +684,11 @@ cglobal %2ToUV, 3, 4, %1, dstU, dstV, src, w
; %1 = nr. of XMM registers
; %2 = nv12 or nv21
%macro NVXX_TO_UV_FN 2
-cglobal %2ToUV, 3, 4, %1, dstU, dstV, src, w
+cglobal %2ToUV, 4, 5, %1, dstU, dstV, unused, src, w
%if ARCH_X86_64
- movsxd wq, dword r4m
+ movsxd wq, dword r5m
%else ; x86-32
- mov wq, r4m
+ mov wq, r5m
%endif
add dstUq, wq
add dstVq, wq
@@ -626,8 +696,8 @@ cglobal %2ToUV, 3, 4, %1, dstU, dstV, src, w
test srcq, 15
%endif
lea srcq, [srcq+wq*2]
- pcmpeqb m4, m4 ; (byte) { 0xff } x 16
- psrlw m4, 8 ; (word) { 0x00ff } x 8
+ pcmpeqb m5, m5 ; (byte) { 0xff } x 16
+ psrlw m5, 8 ; (word) { 0x00ff } x 8
%if mmsize == 16
jnz .loop_u_start
neg wq
@@ -659,6 +729,7 @@ YUYV_TO_UV_FN 3, uyvy
NVXX_TO_UV_FN 5, nv12
NVXX_TO_UV_FN 5, nv21
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
; in theory, we could write a yuy2-to-y using vpand (i.e. AVX), but
; that's not faster in practice
@@ -666,3 +737,4 @@ YUYV_TO_UV_FN 3, yuyv
YUYV_TO_UV_FN 3, uyvy, 1
NVXX_TO_UV_FN 5, nv12
NVXX_TO_UV_FN 5, nv21
+%endif
diff --git a/libswscale/x86/output.asm b/libswscale/x86/output.asm
index e1ceded756..9ea4af9535 100644
--- a/libswscale/x86/output.asm
+++ b/libswscale/x86/output.asm
@@ -3,20 +3,20 @@
;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
;* Kieran Kunhya <kieran@kunhya.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -264,10 +264,12 @@ yuv2planeX_fn 9, 7, 5
yuv2planeX_fn 10, 7, 5
yuv2planeX_fn 16, 8, 5
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
yuv2planeX_fn 8, 10, 7
yuv2planeX_fn 9, 7, 5
yuv2planeX_fn 10, 7, 5
+%endif
; %1=outout-bpc, %2=alignment (u/a)
%macro yuv2plane1_mainloop 2
@@ -402,8 +404,10 @@ yuv2plane1_fn 16, 6, 3
INIT_XMM sse4
yuv2plane1_fn 16, 5, 3
+%if HAVE_AVX_EXTERNAL
INIT_XMM avx
yuv2plane1_fn 8, 5, 5
yuv2plane1_fn 9, 5, 3
yuv2plane1_fn 10, 5, 3
yuv2plane1_fn 16, 5, 3
+%endif
diff --git a/libswscale/x86/rgb2rgb.c b/libswscale/x86/rgb2rgb.c
index 9cfe831e3c..b80e869e0c 100644
--- a/libswscale/x86/rgb2rgb.c
+++ b/libswscale/x86/rgb2rgb.c
@@ -6,20 +6,20 @@
* Written by Nick Kurshev.
* palette & YUV & runtime CPU stuff by Michael (michaelni@gmx.at)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -72,8 +72,14 @@ DECLARE_ASM_CONST(8, uint64_t, blue_16mask) = 0x0000001f0000001fULL;
DECLARE_ASM_CONST(8, uint64_t, red_15mask) = 0x00007c0000007c00ULL;
DECLARE_ASM_CONST(8, uint64_t, green_15mask) = 0x000003e0000003e0ULL;
DECLARE_ASM_CONST(8, uint64_t, blue_15mask) = 0x0000001f0000001fULL;
+DECLARE_ASM_CONST(8, uint64_t, mul15_mid) = 0x4200420042004200ULL;
+DECLARE_ASM_CONST(8, uint64_t, mul15_hi) = 0x0210021002100210ULL;
+DECLARE_ASM_CONST(8, uint64_t, mul16_mid) = 0x2080208020802080ULL;
+
+DECLARE_ALIGNED(8, extern const uint64_t, ff_bgr2YOffset);
+DECLARE_ALIGNED(8, extern const uint64_t, ff_w1111);
+DECLARE_ALIGNED(8, extern const uint64_t, ff_bgr2UVOffset);
-#define RGB2YUV_SHIFT 8
#define BY ((int)( 0.098*(1<<RGB2YUV_SHIFT)+0.5))
#define BV ((int)(-0.071*(1<<RGB2YUV_SHIFT)+0.5))
#define BU ((int)( 0.439*(1<<RGB2YUV_SHIFT)+0.5))
@@ -125,6 +131,7 @@ DECLARE_ASM_CONST(8, uint64_t, blue_15mask) = 0x0000001f0000001fULL;
#undef COMPILE_TEMPLATE_AMD3DNOW
#define COMPILE_TEMPLATE_MMXEXT 0
#define COMPILE_TEMPLATE_SSE2 0
+#define COMPILE_TEMPLATE_AVX 0
#define COMPILE_TEMPLATE_AMD3DNOW 1
#define RENAME(a) a ## _3dnow
#include "rgb2rgb_template.c"
diff --git a/libswscale/x86/rgb2rgb_template.c b/libswscale/x86/rgb2rgb_template.c
index 5d34c21711..e71c7ebfe3 100644
--- a/libswscale/x86/rgb2rgb_template.c
+++ b/libswscale/x86/rgb2rgb_template.c
@@ -7,20 +7,20 @@
* 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 Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -131,14 +131,11 @@ static inline void RENAME(rgb24tobgr32)(const uint8_t *src, uint8_t *dst, int sr
"movq %%mm4, %%mm3 \n\t" \
"psllq $48, %%mm2 \n\t" \
"psllq $32, %%mm3 \n\t" \
- "pand "MANGLE(mask24hh)", %%mm2\n\t" \
- "pand "MANGLE(mask24hhh)", %%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" \
- "pand "MANGLE(mask24hhhh)", %%mm5\n\t" \
"por %%mm5, %%mm4 \n\t" \
\
MOVNTQ" %%mm0, (%0) \n\t" \
@@ -168,6 +165,7 @@ static inline void RENAME(rgb32tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"movq %%mm5, %%mm7 \n\t"
STORE_BGR24_MMX
:: "r"(dest), "r"(s)
+ NAMED_CONSTRAINTS_ADD(mask24l,mask24h)
:"memory");
dest += 24;
s += 32;
@@ -717,27 +715,6 @@ static inline void RENAME(rgb24to15)(const uint8_t *src, uint8_t *dst, int src_s
}
}
-/*
- I use less accurate approximation here by simply left-shifting the input
- value and filling the low order bits with zeroes. This method improves PNG
- compression but this scheme cannot reproduce white exactly, since it does
- not generate an all-ones maximum value; the net effect is to darken the
- image slightly.
-
- The better method should be "left bit replication":
-
- 4 3 2 1 0
- ---------
- 1 1 0 1 1
-
- 7 6 5 4 3 2 1 0
- ----------------
- 1 1 0 1 1 1 1 0
- |=======| |===|
- | leftmost bits repeated to fill open bits
- |
- original bits
-*/
static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int src_size)
{
const uint16_t *end;
@@ -756,9 +733,10 @@ static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"pand %2, %%mm0 \n\t"
"pand %3, %%mm1 \n\t"
"pand %4, %%mm2 \n\t"
- "psllq $3, %%mm0 \n\t"
- "psrlq $2, %%mm1 \n\t"
- "psrlq $7, %%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"
@@ -786,9 +764,10 @@ static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"pand %2, %%mm0 \n\t"
"pand %3, %%mm1 \n\t"
"pand %4, %%mm2 \n\t"
- "psllq $3, %%mm0 \n\t"
- "psrlq $2, %%mm1 \n\t"
- "psrlq $7, %%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"
@@ -809,6 +788,7 @@ static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int sr
:"=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(
@@ -825,6 +805,7 @@ static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int sr
STORE_BGR24_MMX
:: "r"(d), "m"(*s)
+ NAMED_CONSTRAINTS_ADD(mask24l,mask24h)
:"memory");
d += 24;
s += 8;
@@ -834,9 +815,9 @@ static inline void RENAME(rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int sr
while (s < end) {
register uint16_t bgr;
bgr = *s++;
- *d++ = (bgr&0x1F)<<3;
- *d++ = (bgr&0x3E0)>>2;
- *d++ = (bgr&0x7C00)>>7;
+ *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+ *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7);
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
}
}
@@ -858,9 +839,11 @@ static inline void RENAME(rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"pand %2, %%mm0 \n\t"
"pand %3, %%mm1 \n\t"
"pand %4, %%mm2 \n\t"
- "psllq $3, %%mm0 \n\t"
- "psrlq $3, %%mm1 \n\t"
- "psrlq $8, %%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"
@@ -888,9 +871,11 @@ static inline void RENAME(rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"pand %2, %%mm0 \n\t"
"pand %3, %%mm1 \n\t"
"pand %4, %%mm2 \n\t"
- "psllq $3, %%mm0 \n\t"
- "psrlq $3, %%mm1 \n\t"
- "psrlq $8, %%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"
@@ -910,6 +895,7 @@ static inline void RENAME(rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"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(
@@ -926,6 +912,7 @@ static inline void RENAME(rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int sr
STORE_BGR24_MMX
:: "r"(d), "m"(*s)
+ NAMED_CONSTRAINTS_ADD(mask24l,mask24h)
:"memory");
d += 24;
s += 8;
@@ -935,9 +922,9 @@ static inline void RENAME(rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int sr
while (s < end) {
register uint16_t bgr;
bgr = *s++;
- *d++ = (bgr&0x1F)<<3;
- *d++ = (bgr&0x7E0)>>3;
- *d++ = (bgr&0xF800)>>8;
+ *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+ *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9);
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
}
}
@@ -980,11 +967,13 @@ static inline void RENAME(rgb15to32)(const uint8_t *src, uint8_t *dst, int src_s
"pand %2, %%mm0 \n\t"
"pand %3, %%mm1 \n\t"
"pand %4, %%mm2 \n\t"
- "psllq $3, %%mm0 \n\t"
- "psrlq $2, %%mm1 \n\t"
- "psrlq $7, %%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)
+ ::"r"(d),"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r) ,"m"(mul15_mid)
+ NAMED_CONSTRAINTS_ADD(mul15_hi)
:"memory");
d += 16;
s += 4;
@@ -994,9 +983,9 @@ static inline void RENAME(rgb15to32)(const uint8_t *src, uint8_t *dst, int src_s
while (s < end) {
register uint16_t bgr;
bgr = *s++;
- *d++ = (bgr&0x1F)<<3;
- *d++ = (bgr&0x3E0)>>2;
- *d++ = (bgr&0x7C00)>>7;
+ *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+ *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7);
+ *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
*d++ = 255;
}
}
@@ -1021,11 +1010,14 @@ static inline void RENAME(rgb16to32)(const uint8_t *src, uint8_t *dst, int src_s
"pand %2, %%mm0 \n\t"
"pand %3, %%mm1 \n\t"
"pand %4, %%mm2 \n\t"
- "psllq $3, %%mm0 \n\t"
- "psrlq $3, %%mm1 \n\t"
- "psrlq $8, %%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)
+ ::"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;
@@ -1035,9 +1027,9 @@ static inline void RENAME(rgb16to32)(const uint8_t *src, uint8_t *dst, int src_s
while (s < end) {
register uint16_t bgr;
bgr = *s++;
- *d++ = (bgr&0x1F)<<3;
- *d++ = (bgr&0x7E0)>>3;
- *d++ = (bgr&0xF800)>>8;
+ *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+ *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9);
+ *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
*d++ = 255;
}
}
@@ -1150,6 +1142,7 @@ static inline void RENAME(rgb24tobgr24)(const uint8_t *src, uint8_t *dst, int sr
"2: \n\t"
: "+a" (mmx_size)
: "r" (src-mmx_size), "r"(dst-mmx_size)
+ NAMED_CONSTRAINTS_ADD(mask24r,mask24g,mask24b)
);
__asm__ volatile(SFENCE:::"memory");
@@ -1485,6 +1478,7 @@ static inline void RENAME(planar2x)(const uint8_t *src, uint8_t *dst, int srcWid
:: "r" (src + mmxSize ), "r" (src + srcStride + mmxSize ),
"r" (dst + mmxSize*2), "r" (dst + dstStride + mmxSize*2),
"g" (-mmxSize)
+ NAMED_CONSTRAINTS_ADD(mmx_ff)
: "%"REG_a
);
@@ -1629,18 +1623,33 @@ static inline void RENAME(uyvytoyv12)(const uint8_t *src, uint8_t *ydst, uint8_t
* others are ignored in the C version.
* FIXME: Write HQ version.
*/
+#if HAVE_7REGS
static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
int width, int height,
- int lumStride, int chromStride, int srcStride)
+ 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) {
int i;
for (i=0; i<2; i++) {
__asm__ volatile(
"mov %2, %%"REG_a" \n\t"
- "movq "MANGLE(ff_bgr2YCoeff)", %%mm6 \n\t"
+ "movq "BGR2Y_IDX"(%3), %%mm6 \n\t"
"movq "MANGLE(ff_w1111)", %%mm5 \n\t"
"pxor %%mm7, %%mm7 \n\t"
"lea (%%"REG_a", %%"REG_a", 2), %%"REG_d" \n\t"
@@ -1659,12 +1668,10 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
"pmaddwd %%mm6, %%mm1 \n\t"
"pmaddwd %%mm6, %%mm2 \n\t"
"pmaddwd %%mm6, %%mm3 \n\t"
-#ifndef FAST_BGR2YV12
"psrad $8, %%mm0 \n\t"
"psrad $8, %%mm1 \n\t"
"psrad $8, %%mm2 \n\t"
"psrad $8, %%mm3 \n\t"
-#endif
"packssdw %%mm1, %%mm0 \n\t"
"packssdw %%mm3, %%mm2 \n\t"
"pmaddwd %%mm5, %%mm0 \n\t"
@@ -1684,12 +1691,10 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
"pmaddwd %%mm6, %%mm1 \n\t"
"pmaddwd %%mm6, %%mm2 \n\t"
"pmaddwd %%mm6, %%mm3 \n\t"
-#ifndef FAST_BGR2YV12
"psrad $8, %%mm4 \n\t"
"psrad $8, %%mm1 \n\t"
"psrad $8, %%mm2 \n\t"
"psrad $8, %%mm3 \n\t"
-#endif
"packssdw %%mm1, %%mm4 \n\t"
"packssdw %%mm3, %%mm2 \n\t"
"pmaddwd %%mm5, %%mm4 \n\t"
@@ -1704,7 +1709,8 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
MOVNTQ" %%mm0, (%1, %%"REG_a") \n\t"
"add $8, %%"REG_a" \n\t"
" js 1b \n\t"
- : : "r" (src+width*3), "r" (ydst+width), "g" ((x86_reg)-width)
+ : : "r" (src+width*3), "r" (ydst+width), "g" ((x86_reg)-width), "r"(rgb2yuv)
+ NAMED_CONSTRAINTS_ADD(ff_w1111,ff_bgr2YOffset)
: "%"REG_a, "%"REG_d
);
ydst += lumStride;
@@ -1714,7 +1720,7 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
__asm__ volatile(
"mov %4, %%"REG_a" \n\t"
"movq "MANGLE(ff_w1111)", %%mm5 \n\t"
- "movq "MANGLE(ff_bgr2UCoeff)", %%mm6 \n\t"
+ "movq "BGR2U_IDX"(%5), %%mm6 \n\t"
"pxor %%mm7, %%mm7 \n\t"
"lea (%%"REG_a", %%"REG_a", 2), %%"REG_d" \n\t"
"add %%"REG_d", %%"REG_d" \n\t"
@@ -1763,19 +1769,17 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
"psrlw $2, %%mm0 \n\t"
"psrlw $2, %%mm2 \n\t"
#endif
- "movq "MANGLE(ff_bgr2VCoeff)", %%mm1 \n\t"
- "movq "MANGLE(ff_bgr2VCoeff)", %%mm3 \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"
-#ifndef FAST_BGR2YV12
"psrad $8, %%mm0 \n\t"
"psrad $8, %%mm1 \n\t"
"psrad $8, %%mm2 \n\t"
"psrad $8, %%mm3 \n\t"
-#endif
"packssdw %%mm2, %%mm0 \n\t"
"packssdw %%mm3, %%mm1 \n\t"
"pmaddwd %%mm5, %%mm0 \n\t"
@@ -1825,19 +1829,17 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
"psrlw $2, %%mm4 \n\t"
"psrlw $2, %%mm2 \n\t"
#endif
- "movq "MANGLE(ff_bgr2VCoeff)", %%mm1 \n\t"
- "movq "MANGLE(ff_bgr2VCoeff)", %%mm3 \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"
-#ifndef FAST_BGR2YV12
"psrad $8, %%mm4 \n\t"
"psrad $8, %%mm1 \n\t"
"psrad $8, %%mm2 \n\t"
"psrad $8, %%mm3 \n\t"
-#endif
"packssdw %%mm2, %%mm4 \n\t"
"packssdw %%mm3, %%mm1 \n\t"
"pmaddwd %%mm5, %%mm4 \n\t"
@@ -1856,7 +1858,8 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
"movd %%mm0, (%3, %%"REG_a") \n\t"
"add $4, %%"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" (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)
: "%"REG_a, "%"REG_d
);
@@ -1869,8 +1872,9 @@ static inline void RENAME(rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_
SFENCE" \n\t"
:::"memory");
- rgb24toyv12_c(src, ydst, udst, vdst, width, height-y, lumStride, chromStride, srcStride);
+ ff_rgb24toyv12_c(src, ydst, udst, vdst, width, height-y, lumStride, chromStride, srcStride, rgb2yuv);
}
+#endif /* HAVE_7REGS */
#endif /* !COMPILE_TEMPLATE_SSE2 */
#if !COMPILE_TEMPLATE_AMD3DNOW && !COMPILE_TEMPLATE_AVX
@@ -1883,6 +1887,7 @@ static void RENAME(interleaveBytes)(const uint8_t *src1, const uint8_t *src2, ui
for (h=0; h < height; h++) {
int w;
+ if (width >= 16)
#if COMPILE_TEMPLATE_SSE2
__asm__(
"xor %%"REG_a", %%"REG_a" \n\t"
@@ -1945,9 +1950,13 @@ static void RENAME(interleaveBytes)(const uint8_t *src1, const uint8_t *src2, ui
}
#endif /* !COMPILE_TEMPLATE_AMD3DNOW && !COMPILE_TEMPLATE_AVX */
+#if !COMPILE_TEMPLATE_AVX || HAVE_AVX_EXTERNAL
#if !COMPILE_TEMPLATE_AMD3DNOW && (ARCH_X86_32 || COMPILE_TEMPLATE_SSE2) && COMPILE_TEMPLATE_MMXEXT == COMPILE_TEMPLATE_SSE2 && HAVE_YASM
void RENAME(ff_nv12ToUV)(uint8_t *dstU, uint8_t *dstV,
- const uint8_t *src, const uint8_t *unused, int w,
+ const uint8_t *unused,
+ const uint8_t *src1,
+ const uint8_t *src2,
+ int w,
uint32_t *unused2);
static void RENAME(deinterleaveBytes)(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
int width, int height, int srcStride,
@@ -1956,7 +1965,7 @@ static void RENAME(deinterleaveBytes)(const uint8_t *src, uint8_t *dst1, uint8_t
int h;
for (h = 0; h < height; h++) {
- RENAME(ff_nv12ToUV)(dst1, dst2, src, NULL, width, NULL);
+ RENAME(ff_nv12ToUV)(dst1, dst2, NULL, src, NULL, width, NULL);
src += srcStride;
dst1 += dst1Stride;
dst2 += dst2Stride;
@@ -1968,6 +1977,7 @@ static void RENAME(deinterleaveBytes)(const uint8_t *src, uint8_t *dst1, uint8_t
);
}
#endif /* !COMPILE_TEMPLATE_AMD3DNOW */
+#endif /* !COMPILE_TEMPLATE_AVX || HAVE_AVX_EXTERNAL */
#if !COMPILE_TEMPLATE_SSE2
#if !COMPILE_TEMPLATE_AMD3DNOW
@@ -2187,6 +2197,44 @@ static void RENAME(extract_even)(const uint8_t *src, uint8_t *dst, x86_reg count
}
}
+static void RENAME(extract_odd)(const uint8_t *src, uint8_t *dst, x86_reg count)
+{
+ src ++;
+ dst += count;
+ src += 2*count;
+ count= - count;
+
+ if(count < -16) {
+ count += 16;
+ __asm__ volatile(
+ "pcmpeqw %%mm7, %%mm7 \n\t"
+ "psrlw $8, %%mm7 \n\t"
+ "1: \n\t"
+ "movq -32(%1, %0, 2), %%mm0 \n\t"
+ "movq -24(%1, %0, 2), %%mm1 \n\t"
+ "movq -16(%1, %0, 2), %%mm2 \n\t"
+ "movq -8(%1, %0, 2), %%mm3 \n\t"
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "packuswb %%mm1, %%mm0 \n\t"
+ "packuswb %%mm3, %%mm2 \n\t"
+ MOVNTQ" %%mm0,-16(%2, %0) \n\t"
+ MOVNTQ" %%mm2,- 8(%2, %0) \n\t"
+ "add $16, %0 \n\t"
+ " js 1b \n\t"
+ : "+r"(count)
+ : "r"(src), "r"(dst)
+ );
+ count -= 16;
+ }
+ while(count<0) {
+ dst[count]= src[2*count];
+ count++;
+ }
+}
+
#if !COMPILE_TEMPLATE_AMD3DNOW
static void RENAME(extract_even2)(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, x86_reg count)
{
@@ -2397,7 +2445,7 @@ static void RENAME(yuyvtoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, co
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth= -((-width)>>1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y=0; y<height; y++) {
RENAME(extract_even)(src, ydst, width);
@@ -2423,7 +2471,7 @@ static void RENAME(yuyvtoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, co
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth= -((-width)>>1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y=0; y<height; y++) {
RENAME(extract_even)(src, ydst, width);
@@ -2447,10 +2495,10 @@ static void RENAME(uyvytoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, co
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth= -((-width)>>1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y=0; y<height; y++) {
- RENAME(extract_even)(src+1, ydst, width);
+ RENAME(extract_odd)(src, ydst, width);
if(y&1) {
RENAME(extract_even2avg)(src-srcStride, src, udst, vdst, chromWidth);
udst+= chromStride;
@@ -2473,10 +2521,10 @@ static void RENAME(uyvytoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, co
int lumStride, int chromStride, int srcStride)
{
int y;
- const int chromWidth= -((-width)>>1);
+ const int chromWidth = FF_CEIL_RSHIFT(width, 1);
for (y=0; y<height; y++) {
- RENAME(extract_even)(src+1, ydst, width);
+ RENAME(extract_odd)(src, ydst, width);
RENAME(extract_even2)(src, udst, vdst, chromWidth);
src += srcStride;
@@ -2529,7 +2577,9 @@ static av_cold void RENAME(rgb2rgb_init)(void)
#if COMPILE_TEMPLATE_MMXEXT || COMPILE_TEMPLATE_AMD3DNOW
planar2x = RENAME(planar2x);
#endif /* COMPILE_TEMPLATE_MMXEXT || COMPILE_TEMPLATE_AMD3DNOW */
- rgb24toyv12 = RENAME(rgb24toyv12);
+#if HAVE_7REGS
+ ff_rgb24toyv12 = RENAME(rgb24toyv12);
+#endif /* HAVE_7REGS */
yuyvtoyuv420 = RENAME(yuyvtoyuv420);
uyvytoyuv420 = RENAME(uyvytoyuv420);
@@ -2538,7 +2588,9 @@ static av_cold void RENAME(rgb2rgb_init)(void)
#if !COMPILE_TEMPLATE_AMD3DNOW && !COMPILE_TEMPLATE_AVX
interleaveBytes = RENAME(interleaveBytes);
#endif /* !COMPILE_TEMPLATE_AMD3DNOW && !COMPILE_TEMPLATE_AVX */
+#if !COMPILE_TEMPLATE_AVX || HAVE_AVX_EXTERNAL
#if !COMPILE_TEMPLATE_AMD3DNOW && (ARCH_X86_32 || COMPILE_TEMPLATE_SSE2) && COMPILE_TEMPLATE_MMXEXT == COMPILE_TEMPLATE_SSE2 && HAVE_YASM
deinterleaveBytes = RENAME(deinterleaveBytes);
#endif
+#endif
}
diff --git a/libswscale/x86/scale.asm b/libswscale/x86/scale.asm
index 440a27b0ba..7af92f7f52 100644
--- a/libswscale/x86/scale.asm
+++ b/libswscale/x86/scale.asm
@@ -2,20 +2,20 @@
;* x86-optimized horizontal line scaling functions
;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
;*
-;* This file is part of Libav.
+;* This file is part of FFmpeg.
;*
-;* Libav is free software; you can redistribute it and/or
+;* FFmpeg is free software; you can redistribute it and/or
;* modify it under the terms of the GNU Lesser General Public
;* License as published by the Free Software Foundation; either
;* version 2.1 of the License, or (at your option) any later version.
;*
-;* Libav is distributed in the hope that it will be useful,
+;* FFmpeg is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;* Lesser General Public License for more details.
;*
;* You should have received a copy of the GNU Lesser General Public
-;* License along with Libav; if not, write to the Free Software
+;* License along with FFmpeg; if not, write to the Free Software
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;******************************************************************************
@@ -407,11 +407,15 @@ SCALE_FUNC %1, %2, X, X8, 7, %3
SCALE_FUNCS 8, 15, %1
SCALE_FUNCS 9, 15, %2
SCALE_FUNCS 10, 15, %2
+SCALE_FUNCS 12, 15, %2
+SCALE_FUNCS 14, 15, %2
SCALE_FUNCS 16, 15, %3
%endif ; !sse4
SCALE_FUNCS 8, 19, %1
SCALE_FUNCS 9, 19, %2
SCALE_FUNCS 10, 19, %2
+SCALE_FUNCS 12, 19, %2
+SCALE_FUNCS 14, 19, %2
SCALE_FUNCS 16, 19, %3
%endmacro
@@ -420,7 +424,7 @@ INIT_MMX mmx
SCALE_FUNCS2 0, 0, 0
%endif
INIT_XMM sse2
-SCALE_FUNCS2 6, 7, 8
+SCALE_FUNCS2 7, 6, 8
INIT_XMM ssse3
SCALE_FUNCS2 6, 6, 8
INIT_XMM sse4
diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c
index f310a7593f..d611b76c73 100644
--- a/libswscale/x86/swscale.c
+++ b/libswscale/x86/swscale.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,6 +23,7 @@
#include "libswscale/swscale.h"
#include "libswscale/swscale_internal.h"
#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/x86/asm.h"
#include "libavutil/x86/cpu.h"
@@ -57,19 +58,11 @@ DECLARE_ALIGNED(8, const uint64_t, ff_M24A) = 0x00FF0000FF0000FFLL;
DECLARE_ALIGNED(8, const uint64_t, ff_M24B) = 0xFF0000FF0000FF00LL;
DECLARE_ALIGNED(8, const uint64_t, ff_M24C) = 0x0000FF0000FF0000LL;
-#ifdef FAST_BGR2YV12
-DECLARE_ALIGNED(8, const uint64_t, ff_bgr2YCoeff) = 0x000000210041000DULL;
-DECLARE_ALIGNED(8, const uint64_t, ff_bgr2UCoeff) = 0x0000FFEEFFDC0038ULL;
-DECLARE_ALIGNED(8, const uint64_t, ff_bgr2VCoeff) = 0x00000038FFD2FFF8ULL;
-#else
-DECLARE_ALIGNED(8, const uint64_t, ff_bgr2YCoeff) = 0x000020E540830C8BULL;
-DECLARE_ALIGNED(8, const uint64_t, ff_bgr2UCoeff) = 0x0000ED0FDAC23831ULL;
-DECLARE_ALIGNED(8, const uint64_t, ff_bgr2VCoeff) = 0x00003831D0E6F6EAULL;
-#endif /* FAST_BGR2YV12 */
DECLARE_ALIGNED(8, const uint64_t, ff_bgr2YOffset) = 0x1010101010101010ULL;
DECLARE_ALIGNED(8, const uint64_t, ff_bgr2UVOffset) = 0x8080808080808080ULL;
DECLARE_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL;
+
//MMX versions
#if HAVE_MMX_INLINE
#undef RENAME
@@ -87,7 +80,7 @@ DECLARE_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL;
#include "swscale_template.c"
#endif
-void updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufIndex,
+void ff_updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufIndex,
int lastInLumBuf, int lastInChrBuf)
{
const int dstH= c->dstH;
@@ -117,9 +110,9 @@ void updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufI
c->greenDither= ff_dither4[dstY&1];
c->redDither= ff_dither8[(dstY+1)&1];
if (dstY < dstH - 2) {
- const int16_t **lumSrcPtr= (const int16_t **) lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize;
- const int16_t **chrUSrcPtr= (const int16_t **) chrUPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
- const int16_t **alpSrcPtr= (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? (const int16_t **) alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL;
+ const int16_t **lumSrcPtr= (const int16_t **)(void*) lumPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize;
+ const int16_t **chrUSrcPtr= (const int16_t **)(void*) chrUPixBuf + chrBufIndex + firstChrSrcY - lastInChrBuf + vChrBufSize;
+ const int16_t **alpSrcPtr= (CONFIG_SWSCALE_ALPHA && alpPixBuf) ? (const int16_t **)(void*) alpPixBuf + lumBufIndex + firstLumSrcY - lastInLumBuf + vLumBufSize : NULL;
int i;
if (firstLumSrcY < 0 || firstLumSrcY + vLumFilterSize > c->srcH) {
@@ -186,7 +179,7 @@ void updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufI
*(const void**)&lumMmxFilter[4*i+0]= lumSrcPtr[i];
lumMmxFilter[4*i+2]=
lumMmxFilter[4*i+3]=
- ((uint16_t)vLumFilter[dstY*vLumFilterSize + i])*0x10001;
+ ((uint16_t)vLumFilter[dstY*vLumFilterSize + i])*0x10001U;
if (CONFIG_SWSCALE_ALPHA && alpPixBuf) {
*(const void**)&alpMmxFilter[4*i+0]= alpSrcPtr[i];
alpMmxFilter[4*i+2]=
@@ -197,12 +190,90 @@ void updateMMXDitherTables(SwsContext *c, int dstY, int lumBufIndex, int chrBufI
*(const void**)&chrMmxFilter[4*i+0]= chrUSrcPtr[i];
chrMmxFilter[4*i+2]=
chrMmxFilter[4*i+3]=
- ((uint16_t)vChrFilter[chrDstY*vChrFilterSize + i])*0x10001;
+ ((uint16_t)vChrFilter[chrDstY*vChrFilterSize + i])*0x10001U;
}
}
}
}
+#if HAVE_MMXEXT
+static void yuv2yuvX_sse3(const int16_t *filter, int filterSize,
+ const int16_t **src, uint8_t *dest, int dstW,
+ const uint8_t *dither, int offset)
+{
+ if(((uintptr_t)dest) & 15){
+ yuv2yuvX_mmxext(filter, filterSize, src, dest, dstW, dither, offset);
+ return;
+ }
+ filterSize--;
+#define MAIN_FUNCTION \
+ "pxor %%xmm0, %%xmm0 \n\t" \
+ "punpcklbw %%xmm0, %%xmm3 \n\t" \
+ "movd %4, %%xmm1 \n\t" \
+ "punpcklwd %%xmm1, %%xmm1 \n\t" \
+ "punpckldq %%xmm1, %%xmm1 \n\t" \
+ "punpcklqdq %%xmm1, %%xmm1 \n\t" \
+ "psllw $3, %%xmm1 \n\t" \
+ "paddw %%xmm1, %%xmm3 \n\t" \
+ "psraw $4, %%xmm3 \n\t" \
+ "movdqa %%xmm3, %%xmm4 \n\t" \
+ "movdqa %%xmm3, %%xmm7 \n\t" \
+ "movl %3, %%ecx \n\t" \
+ "mov %0, %%"REG_d" \n\t"\
+ "mov (%%"REG_d"), %%"REG_S" \n\t"\
+ ".p2align 4 \n\t" /* FIXME Unroll? */\
+ "1: \n\t"\
+ "movddup 8(%%"REG_d"), %%xmm0 \n\t" /* filterCoeff */\
+ "movdqa (%%"REG_S", %%"REG_c", 2), %%xmm2 \n\t" /* srcData */\
+ "movdqa 16(%%"REG_S", %%"REG_c", 2), %%xmm5 \n\t" /* srcData */\
+ "add $16, %%"REG_d" \n\t"\
+ "mov (%%"REG_d"), %%"REG_S" \n\t"\
+ "test %%"REG_S", %%"REG_S" \n\t"\
+ "pmulhw %%xmm0, %%xmm2 \n\t"\
+ "pmulhw %%xmm0, %%xmm5 \n\t"\
+ "paddw %%xmm2, %%xmm3 \n\t"\
+ "paddw %%xmm5, %%xmm4 \n\t"\
+ " jnz 1b \n\t"\
+ "psraw $3, %%xmm3 \n\t"\
+ "psraw $3, %%xmm4 \n\t"\
+ "packuswb %%xmm4, %%xmm3 \n\t"\
+ "movntdq %%xmm3, (%1, %%"REG_c")\n\t"\
+ "add $16, %%"REG_c" \n\t"\
+ "cmp %2, %%"REG_c" \n\t"\
+ "movdqa %%xmm7, %%xmm3 \n\t" \
+ "movdqa %%xmm7, %%xmm4 \n\t" \
+ "mov %0, %%"REG_d" \n\t"\
+ "mov (%%"REG_d"), %%"REG_S" \n\t"\
+ "jb 1b \n\t"
+
+ if (offset) {
+ __asm__ volatile(
+ "movq %5, %%xmm3 \n\t"
+ "movdqa %%xmm3, %%xmm4 \n\t"
+ "psrlq $24, %%xmm3 \n\t"
+ "psllq $40, %%xmm4 \n\t"
+ "por %%xmm4, %%xmm3 \n\t"
+ MAIN_FUNCTION
+ :: "g" (filter),
+ "r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset),
+ "m"(filterSize), "m"(((uint64_t *) dither)[0])
+ : XMM_CLOBBERS("%xmm0" , "%xmm1" , "%xmm2" , "%xmm3" , "%xmm4" , "%xmm5" , "%xmm7" ,)
+ "%"REG_d, "%"REG_S, "%"REG_c
+ );
+ } else {
+ __asm__ volatile(
+ "movq %5, %%xmm3 \n\t"
+ MAIN_FUNCTION
+ :: "g" (filter),
+ "r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset),
+ "m"(filterSize), "m"(((uint64_t *) dither)[0])
+ : XMM_CLOBBERS("%xmm0" , "%xmm1" , "%xmm2" , "%xmm3" , "%xmm4" , "%xmm5" , "%xmm7" ,)
+ "%"REG_d, "%"REG_S, "%"REG_c
+ );
+ }
+}
+#endif
+
#endif /* HAVE_INLINE_ASM */
#define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
@@ -216,10 +287,14 @@ void ff_hscale ## from_bpc ## to ## to_bpc ## _ ## filter_n ## _ ## opt( \
SCALE_FUNC(filter_n, 8, 15, opt); \
SCALE_FUNC(filter_n, 9, 15, opt); \
SCALE_FUNC(filter_n, 10, 15, opt); \
+ SCALE_FUNC(filter_n, 12, 15, opt); \
+ SCALE_FUNC(filter_n, 14, 15, opt); \
SCALE_FUNC(filter_n, 16, 15, opt); \
SCALE_FUNC(filter_n, 8, 19, opt); \
SCALE_FUNC(filter_n, 9, 19, opt); \
SCALE_FUNC(filter_n, 10, 19, opt); \
+ SCALE_FUNC(filter_n, 12, 19, opt); \
+ SCALE_FUNC(filter_n, 14, 19, opt); \
SCALE_FUNC(filter_n, 16, 19, opt)
#define SCALE_FUNCS_MMX(opt) \
@@ -275,11 +350,14 @@ VSCALE_FUNCS(avx, avx);
#define INPUT_Y_FUNC(fmt, opt) \
void ff_ ## fmt ## ToY_ ## opt(uint8_t *dst, const uint8_t *src, \
+ const uint8_t *unused1, const uint8_t *unused2, \
int w, uint32_t *unused)
#define INPUT_UV_FUNC(fmt, opt) \
void ff_ ## fmt ## ToUV_ ## opt(uint8_t *dstU, uint8_t *dstV, \
- const uint8_t *src, const uint8_t *unused1, \
- int w, uint32_t *unused2)
+ const uint8_t *unused0, \
+ const uint8_t *src1, \
+ const uint8_t *src2, \
+ int w, uint32_t *unused)
#define INPUT_FUNC(fmt, opt) \
INPUT_Y_FUNC(fmt, opt); \
INPUT_UV_FUNC(fmt, opt)
@@ -313,20 +391,31 @@ av_cold void ff_sws_init_swscale_x86(SwsContext *c)
#if HAVE_MMXEXT_INLINE
if (INLINE_MMXEXT(cpu_flags))
sws_init_swscale_mmxext(c);
+ if (cpu_flags & AV_CPU_FLAG_SSE3){
+ if(c->use_mmx_vfilter && !(c->flags & SWS_ACCURATE_RND))
+ c->yuv2planeX = yuv2yuvX_sse3;
+ }
#endif
#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt1, opt2) do { \
if (c->srcBpc == 8) { \
- hscalefn = c->dstBpc <= 10 ? ff_hscale8to15_ ## filtersize ## _ ## opt2 : \
+ hscalefn = c->dstBpc <= 14 ? ff_hscale8to15_ ## filtersize ## _ ## opt2 : \
ff_hscale8to19_ ## filtersize ## _ ## opt1; \
} else if (c->srcBpc == 9) { \
- hscalefn = c->dstBpc <= 10 ? ff_hscale9to15_ ## filtersize ## _ ## opt2 : \
+ hscalefn = c->dstBpc <= 14 ? ff_hscale9to15_ ## filtersize ## _ ## opt2 : \
ff_hscale9to19_ ## filtersize ## _ ## opt1; \
} else if (c->srcBpc == 10) { \
- hscalefn = c->dstBpc <= 10 ? ff_hscale10to15_ ## filtersize ## _ ## opt2 : \
+ hscalefn = c->dstBpc <= 14 ? ff_hscale10to15_ ## filtersize ## _ ## opt2 : \
ff_hscale10to19_ ## filtersize ## _ ## opt1; \
- } else /* c->srcBpc == 16 */ { \
- hscalefn = c->dstBpc <= 10 ? ff_hscale16to15_ ## filtersize ## _ ## opt2 : \
+ } else if (c->srcBpc == 12) { \
+ hscalefn = c->dstBpc <= 14 ? ff_hscale12to15_ ## filtersize ## _ ## opt2 : \
+ ff_hscale12to19_ ## filtersize ## _ ## opt1; \
+ } else if (c->srcBpc == 14 || ((c->srcFormat==AV_PIX_FMT_PAL8||isAnyRGB(c->srcFormat)) && av_pix_fmt_desc_get(c->srcFormat)->comp[0].depth_minus1<15)) { \
+ hscalefn = c->dstBpc <= 14 ? ff_hscale14to15_ ## filtersize ## _ ## opt2 : \
+ ff_hscale14to19_ ## filtersize ## _ ## opt1; \
+ } else { /* c->srcBpc == 16 */ \
+ av_assert0(c->srcBpc == 16);\
+ hscalefn = c->dstBpc <= 14 ? ff_hscale16to15_ ## filtersize ## _ ## opt2 : \
ff_hscale16to19_ ## filtersize ## _ ## opt1; \
} \
} while (0)
@@ -341,14 +430,15 @@ switch(c->dstBpc){ \
case 16: do_16_case; break; \
case 10: if (!isBE(c->dstFormat)) vscalefn = ff_yuv2planeX_10_ ## opt; break; \
case 9: if (!isBE(c->dstFormat)) vscalefn = ff_yuv2planeX_9_ ## opt; break; \
- default: if (condition_8bit) vscalefn = ff_yuv2planeX_8_ ## opt; break; \
+ case 8: if ((condition_8bit) && !c->use_mmx_vfilter) vscalefn = ff_yuv2planeX_8_ ## opt; break; \
}
#define ASSIGN_VSCALE_FUNC(vscalefn, opt1, opt2, opt2chk) \
switch(c->dstBpc){ \
case 16: if (!isBE(c->dstFormat)) vscalefn = ff_yuv2plane1_16_ ## opt1; break; \
case 10: if (!isBE(c->dstFormat) && opt2chk) vscalefn = ff_yuv2plane1_10_ ## opt2; break; \
case 9: if (!isBE(c->dstFormat) && opt2chk) vscalefn = ff_yuv2plane1_9_ ## opt2; break; \
- default: vscalefn = ff_yuv2plane1_8_ ## opt1; break; \
+ case 8: vscalefn = ff_yuv2plane1_8_ ## opt1; break; \
+ default: av_assert0(c->dstBpc>8); \
}
#define case_rgb(x, X, opt) \
case AV_PIX_FMT_ ## X: \
diff --git a/libswscale/x86/swscale_template.c b/libswscale/x86/swscale_template.c
index 1e42ec5b12..36a606c5b2 100644
--- a/libswscale/x86/swscale_template.c
+++ b/libswscale/x86/swscale_template.c
@@ -1,20 +1,20 @@
/*
- * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at>
+ * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,21 +25,101 @@
#undef REAL_MOVNTQ
#undef MOVNTQ
+#undef MOVNTQ2
#undef PREFETCH
-#if COMPILE_TEMPLATE_MMXEXT
-#define PREFETCH "prefetchnta"
-#else
-#define PREFETCH " # nop"
-#endif
#if COMPILE_TEMPLATE_MMXEXT
#define REAL_MOVNTQ(a,b) "movntq " #a ", " #b " \n\t"
+#define MOVNTQ2 "movntq "
#else
#define REAL_MOVNTQ(a,b) "movq " #a ", " #b " \n\t"
+#define MOVNTQ2 "movq "
#endif
#define MOVNTQ(a,b) REAL_MOVNTQ(a,b)
+#if !COMPILE_TEMPLATE_MMXEXT
+static av_always_inline void
+dither_8to16(const uint8_t *srcDither, int rot)
+{
+ if (rot) {
+ __asm__ volatile("pxor %%mm0, %%mm0\n\t"
+ "movq (%0), %%mm3\n\t"
+ "movq %%mm3, %%mm4\n\t"
+ "psrlq $24, %%mm3\n\t"
+ "psllq $40, %%mm4\n\t"
+ "por %%mm4, %%mm3\n\t"
+ "movq %%mm3, %%mm4\n\t"
+ "punpcklbw %%mm0, %%mm3\n\t"
+ "punpckhbw %%mm0, %%mm4\n\t"
+ :: "r"(srcDither)
+ );
+ } else {
+ __asm__ volatile("pxor %%mm0, %%mm0\n\t"
+ "movq (%0), %%mm3\n\t"
+ "movq %%mm3, %%mm4\n\t"
+ "punpcklbw %%mm0, %%mm3\n\t"
+ "punpckhbw %%mm0, %%mm4\n\t"
+ :: "r"(srcDither)
+ );
+ }
+}
+#endif
+
+static void RENAME(yuv2yuvX)(const int16_t *filter, int filterSize,
+ const int16_t **src, uint8_t *dest, int dstW,
+ const uint8_t *dither, int offset)
+{
+ dither_8to16(dither, offset);
+ filterSize--;
+ __asm__ volatile(
+ "movd %0, %%mm1\n\t"
+ "punpcklwd %%mm1, %%mm1\n\t"
+ "punpckldq %%mm1, %%mm1\n\t"
+ "psllw $3, %%mm1\n\t"
+ "paddw %%mm1, %%mm3\n\t"
+ "paddw %%mm1, %%mm4\n\t"
+ "psraw $4, %%mm3\n\t"
+ "psraw $4, %%mm4\n\t"
+ ::"m"(filterSize)
+ );
+
+ __asm__ volatile(\
+ "movq %%mm3, %%mm6\n\t"
+ "movq %%mm4, %%mm7\n\t"
+ "movl %3, %%ecx\n\t"
+ "mov %0, %%"REG_d" \n\t"\
+ "mov (%%"REG_d"), %%"REG_S" \n\t"\
+ ".p2align 4 \n\t" /* FIXME Unroll? */\
+ "1: \n\t"\
+ "movq 8(%%"REG_d"), %%mm0 \n\t" /* filterCoeff */\
+ "movq (%%"REG_S", %%"REG_c", 2), %%mm2 \n\t" /* srcData */\
+ "movq 8(%%"REG_S", %%"REG_c", 2), %%mm5 \n\t" /* srcData */\
+ "add $16, %%"REG_d" \n\t"\
+ "mov (%%"REG_d"), %%"REG_S" \n\t"\
+ "test %%"REG_S", %%"REG_S" \n\t"\
+ "pmulhw %%mm0, %%mm2 \n\t"\
+ "pmulhw %%mm0, %%mm5 \n\t"\
+ "paddw %%mm2, %%mm3 \n\t"\
+ "paddw %%mm5, %%mm4 \n\t"\
+ " jnz 1b \n\t"\
+ "psraw $3, %%mm3 \n\t"\
+ "psraw $3, %%mm4 \n\t"\
+ "packuswb %%mm4, %%mm3 \n\t"
+ MOVNTQ2 " %%mm3, (%1, %%"REG_c")\n\t"
+ "add $8, %%"REG_c" \n\t"\
+ "cmp %2, %%"REG_c" \n\t"\
+ "movq %%mm6, %%mm3\n\t"
+ "movq %%mm7, %%mm4\n\t"
+ "mov %0, %%"REG_d" \n\t"\
+ "mov (%%"REG_d"), %%"REG_S" \n\t"\
+ "jb 1b \n\t"\
+ :: "g" (filter),
+ "r" (dest-offset), "g" ((x86_reg)(dstW+offset)), "m" (offset)
+ : "%"REG_d, "%"REG_S, "%"REG_c
+ );
+}
+
#define YSCALEYUV2PACKEDX_UV \
__asm__ volatile(\
"xor %%"REG_a", %%"REG_a" \n\t"\
@@ -92,6 +172,7 @@
:: "r" (&c->redDither), \
"m" (dummy), "m" (dummy), "m" (dummy),\
"r" (dest), "m" (dstW_reg), "m"(uv_off) \
+ NAMED_CONSTRAINTS_ADD(bF8,bFC) \
: "%"REG_a, "%"REG_d, "%"REG_S \
);
@@ -252,7 +333,7 @@
MOVNTQ( q3, 24(dst, index, 4))\
\
"add $8, "#index" \n\t"\
- "cmp "#dstw", "#index" \n\t"\
+ "cmp "dstw", "#index" \n\t"\
" jb 1b \n\t"
#define WRITEBGR32(dst, dstw, index, b, g, r, a, q0, q2, q3, t) REAL_WRITEBGR32(dst, dstw, index, b, g, r, a, q0, q2, q3, t)
@@ -265,7 +346,7 @@ static void RENAME(yuv2rgb32_X_ar)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
if (CONFIG_SWSCALE_ALPHA && c->alpPixBuf) {
YSCALEYUV2PACKEDX_ACCURATE
@@ -278,13 +359,13 @@ static void RENAME(yuv2rgb32_X_ar)(SwsContext *c, const int16_t *lumFilter,
"psraw $3, %%mm1 \n\t"
"psraw $3, %%mm7 \n\t"
"packuswb %%mm7, %%mm1 \n\t"
- WRITEBGR32(%4, %5, %%REGa, %%mm3, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm2, %%mm6)
+ WRITEBGR32(%4, "%5", %%REGa, %%mm3, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm2, %%mm6)
YSCALEYUV2PACKEDX_END
} else {
YSCALEYUV2PACKEDX_ACCURATE
YSCALEYUV2RGBX
"pcmpeqd %%mm7, %%mm7 \n\t"
- WRITEBGR32(%4, %5, %%REGa, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%4, "%5", %%REGa, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
YSCALEYUV2PACKEDX_END
}
}
@@ -298,7 +379,7 @@ static void RENAME(yuv2rgb32_X)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
if (CONFIG_SWSCALE_ALPHA && c->alpPixBuf) {
YSCALEYUV2PACKEDX
@@ -307,13 +388,13 @@ static void RENAME(yuv2rgb32_X)(SwsContext *c, const int16_t *lumFilter,
"psraw $3, %%mm1 \n\t"
"psraw $3, %%mm7 \n\t"
"packuswb %%mm7, %%mm1 \n\t"
- WRITEBGR32(%4, %5, %%REGa, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+ WRITEBGR32(%4, "%5", %%REGa, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
YSCALEYUV2PACKEDX_END
} else {
YSCALEYUV2PACKEDX
YSCALEYUV2RGBX
"pcmpeqd %%mm7, %%mm7 \n\t"
- WRITEBGR32(%4, %5, %%REGa, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%4, "%5", %%REGa, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
YSCALEYUV2PACKEDX_END
}
}
@@ -342,7 +423,7 @@ static void RENAME(yuv2rgb32_X)(SwsContext *c, const int16_t *lumFilter,
MOVNTQ(%%mm1, 8(dst, index, 2))\
\
"add $8, "#index" \n\t"\
- "cmp "#dstw", "#index" \n\t"\
+ "cmp "dstw", "#index" \n\t"\
" jb 1b \n\t"
#define WRITERGB16(dst, dstw, index) REAL_WRITERGB16(dst, dstw, index)
@@ -355,7 +436,7 @@ static void RENAME(yuv2rgb565_X_ar)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX_ACCURATE
YSCALEYUV2RGBX
@@ -366,7 +447,7 @@ static void RENAME(yuv2rgb565_X_ar)(SwsContext *c, const int16_t *lumFilter,
"paddusb "GREEN_DITHER"(%0), %%mm4\n\t"
"paddusb "RED_DITHER"(%0), %%mm5\n\t"
#endif
- WRITERGB16(%4, %5, %%REGa)
+ WRITERGB16(%4, "%5", %%REGa)
YSCALEYUV2PACKEDX_END
}
@@ -379,7 +460,7 @@ static void RENAME(yuv2rgb565_X)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX
YSCALEYUV2RGBX
@@ -390,7 +471,7 @@ static void RENAME(yuv2rgb565_X)(SwsContext *c, const int16_t *lumFilter,
"paddusb "GREEN_DITHER"(%0), %%mm4 \n\t"
"paddusb "RED_DITHER"(%0), %%mm5 \n\t"
#endif
- WRITERGB16(%4, %5, %%REGa)
+ WRITERGB16(%4, "%5", %%REGa)
YSCALEYUV2PACKEDX_END
}
@@ -419,7 +500,7 @@ static void RENAME(yuv2rgb565_X)(SwsContext *c, const int16_t *lumFilter,
MOVNTQ(%%mm1, 8(dst, index, 2))\
\
"add $8, "#index" \n\t"\
- "cmp "#dstw", "#index" \n\t"\
+ "cmp "dstw", "#index" \n\t"\
" jb 1b \n\t"
#define WRITERGB15(dst, dstw, index) REAL_WRITERGB15(dst, dstw, index)
@@ -432,7 +513,7 @@ static void RENAME(yuv2rgb555_X_ar)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX_ACCURATE
YSCALEYUV2RGBX
@@ -443,7 +524,7 @@ static void RENAME(yuv2rgb555_X_ar)(SwsContext *c, const int16_t *lumFilter,
"paddusb "GREEN_DITHER"(%0), %%mm4\n\t"
"paddusb "RED_DITHER"(%0), %%mm5\n\t"
#endif
- WRITERGB15(%4, %5, %%REGa)
+ WRITERGB15(%4, "%5", %%REGa)
YSCALEYUV2PACKEDX_END
}
@@ -456,7 +537,7 @@ static void RENAME(yuv2rgb555_X)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX
YSCALEYUV2RGBX
@@ -467,7 +548,7 @@ static void RENAME(yuv2rgb555_X)(SwsContext *c, const int16_t *lumFilter,
"paddusb "GREEN_DITHER"(%0), %%mm4 \n\t"
"paddusb "RED_DITHER"(%0), %%mm5 \n\t"
#endif
- WRITERGB15(%4, %5, %%REGa)
+ WRITERGB15(%4, "%5", %%REGa)
YSCALEYUV2PACKEDX_END
}
@@ -521,7 +602,7 @@ static void RENAME(yuv2rgb555_X)(SwsContext *c, const int16_t *lumFilter,
"add $24, "#dst" \n\t"\
\
"add $8, "#index" \n\t"\
- "cmp "#dstw", "#index" \n\t"\
+ "cmp "dstw", "#index" \n\t"\
" jb 1b \n\t"
#define WRITEBGR24MMXEXT(dst, dstw, index) \
@@ -569,7 +650,7 @@ static void RENAME(yuv2rgb555_X)(SwsContext *c, const int16_t *lumFilter,
"add $24, "#dst" \n\t"\
\
"add $8, "#index" \n\t"\
- "cmp "#dstw", "#index" \n\t"\
+ "cmp "dstw", "#index" \n\t"\
" jb 1b \n\t"
#if COMPILE_TEMPLATE_MMXEXT
@@ -580,6 +661,7 @@ static void RENAME(yuv2rgb555_X)(SwsContext *c, const int16_t *lumFilter,
#define WRITEBGR24(dst, dstw, index) WRITEBGR24MMX(dst, dstw, index)
#endif
+#if HAVE_6REGS
static void RENAME(yuv2bgr24_X_ar)(SwsContext *c, const int16_t *lumFilter,
const int16_t **lumSrc, int lumFilterSize,
const int16_t *chrFilter, const int16_t **chrUSrc,
@@ -589,17 +671,18 @@ static void RENAME(yuv2bgr24_X_ar)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX_ACCURATE
YSCALEYUV2RGBX
"pxor %%mm7, %%mm7 \n\t"
"lea (%%"REG_a", %%"REG_a", 2), %%"REG_c"\n\t" //FIXME optimize
"add %4, %%"REG_c" \n\t"
- WRITEBGR24(%%REGc, %5, %%REGa)
+ WRITEBGR24(%%REGc, "%5", %%REGa)
:: "r" (&c->redDither),
"m" (dummy), "m" (dummy), "m" (dummy),
"r" (dest), "m" (dstW_reg), "m"(uv_off)
+ NAMED_CONSTRAINTS_ADD(ff_M24A,ff_M24C,ff_M24B)
: "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S
);
}
@@ -613,20 +696,22 @@ static void RENAME(yuv2bgr24_X)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX
YSCALEYUV2RGBX
"pxor %%mm7, %%mm7 \n\t"
"lea (%%"REG_a", %%"REG_a", 2), %%"REG_c" \n\t" //FIXME optimize
"add %4, %%"REG_c" \n\t"
- WRITEBGR24(%%REGc, %5, %%REGa)
+ WRITEBGR24(%%REGc, "%5", %%REGa)
:: "r" (&c->redDither),
"m" (dummy), "m" (dummy), "m" (dummy),
"r" (dest), "m" (dstW_reg), "m"(uv_off)
+ NAMED_CONSTRAINTS_ADD(ff_M24A,ff_M24C,ff_M24B)
: "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S
);
}
+#endif /* HAVE_6REGS */
#define REAL_WRITEYUY2(dst, dstw, index) \
"packuswb %%mm3, %%mm3 \n\t"\
@@ -641,7 +726,7 @@ static void RENAME(yuv2bgr24_X)(SwsContext *c, const int16_t *lumFilter,
MOVNTQ(%%mm7, 8(dst, index, 2))\
\
"add $8, "#index" \n\t"\
- "cmp "#dstw", "#index" \n\t"\
+ "cmp "dstw", "#index" \n\t"\
" jb 1b \n\t"
#define WRITEYUY2(dst, dstw, index) REAL_WRITEYUY2(dst, dstw, index)
@@ -654,7 +739,7 @@ static void RENAME(yuv2yuyv422_X_ar)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX_ACCURATE
/* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
@@ -662,7 +747,7 @@ static void RENAME(yuv2yuyv422_X_ar)(SwsContext *c, const int16_t *lumFilter,
"psraw $3, %%mm4 \n\t"
"psraw $3, %%mm1 \n\t"
"psraw $3, %%mm7 \n\t"
- WRITEYUY2(%4, %5, %%REGa)
+ WRITEYUY2(%4, "%5", %%REGa)
YSCALEYUV2PACKEDX_END
}
@@ -675,7 +760,7 @@ static void RENAME(yuv2yuyv422_X)(SwsContext *c, const int16_t *lumFilter,
{
x86_reg dummy=0;
x86_reg dstW_reg = dstW;
- x86_reg uv_off = c->uv_off_byte;
+ x86_reg uv_off = c->uv_offx2;
YSCALEYUV2PACKEDX
/* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
@@ -683,7 +768,7 @@ static void RENAME(yuv2yuyv422_X)(SwsContext *c, const int16_t *lumFilter,
"psraw $3, %%mm4 \n\t"
"psraw $3, %%mm1 \n\t"
"psraw $3, %%mm7 \n\t"
- WRITEYUY2(%4, %5, %%REGa)
+ WRITEYUY2(%4, "%5", %%REGa)
YSCALEYUV2PACKEDX_END
}
@@ -784,15 +869,15 @@ static void RENAME(yuv2rgb32_2)(SwsContext *c, const int16_t *buf[2],
"psraw $3, %%mm1 \n\t" /* abuf0[eax] - abuf1[eax] >>7*/
"psraw $3, %%mm7 \n\t" /* abuf0[eax] - abuf1[eax] >>7*/
"packuswb %%mm7, %%mm1 \n\t"
- WRITEBGR32(%4, 8280(%5), %%r8, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+ WRITEBGR32(%4, DSTW_OFFSET"(%5)", %%r8, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "r" (dest),
"a" (&c->redDither),
"r" (abuf0), "r" (abuf1)
: "%r8"
);
#else
- *(const uint16_t **)(&c->u_temp)=abuf0;
- *(const uint16_t **)(&c->v_temp)=abuf1;
+ c->u_temp=(intptr_t)abuf0;
+ c->v_temp=(intptr_t)abuf1;
__asm__ volatile(
"mov %%"REG_b", "ESP_OFFSET"(%5) \n\t"
"mov %4, %%"REG_b" \n\t"
@@ -808,7 +893,7 @@ static void RENAME(yuv2rgb32_2)(SwsContext *c, const int16_t *buf[2],
"packuswb %%mm7, %%mm1 \n\t"
"pop %1 \n\t"
"pop %0 \n\t"
- WRITEBGR32(%%REGb, 8280(%5), %%REGBP, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+ WRITEBGR32(%%REGb, DSTW_OFFSET"(%5)", %%REGBP, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -822,7 +907,7 @@ static void RENAME(yuv2rgb32_2)(SwsContext *c, const int16_t *buf[2],
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB(%%REGBP, %5)
"pcmpeqd %%mm7, %%mm7 \n\t"
- WRITEBGR32(%%REGb, 8280(%5), %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%%REGb, DSTW_OFFSET"(%5)", %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -839,18 +924,18 @@ static void RENAME(yuv2bgr24_2)(SwsContext *c, const int16_t *buf[2],
const int16_t *buf0 = buf[0], *buf1 = buf[1],
*ubuf0 = ubuf[0], *ubuf1 = ubuf[1];
- //Note 8280 == DSTW_OFFSET but the preprocessor can't handle that there :(
__asm__ volatile(
"mov %%"REG_b", "ESP_OFFSET"(%5) \n\t"
"mov %4, %%"REG_b" \n\t"
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB(%%REGBP, %5)
"pxor %%mm7, %%mm7 \n\t"
- WRITEBGR24(%%REGb, 8280(%5), %%REGBP)
+ WRITEBGR24(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(ff_M24A,ff_M24C,ff_M24B)
);
}
@@ -862,7 +947,6 @@ static void RENAME(yuv2rgb555_2)(SwsContext *c, const int16_t *buf[2],
const int16_t *buf0 = buf[0], *buf1 = buf[1],
*ubuf0 = ubuf[0], *ubuf1 = ubuf[1];
- //Note 8280 == DSTW_OFFSET but the preprocessor can't handle that there :(
__asm__ volatile(
"mov %%"REG_b", "ESP_OFFSET"(%5) \n\t"
"mov %4, %%"REG_b" \n\t"
@@ -875,11 +959,12 @@ static void RENAME(yuv2rgb555_2)(SwsContext *c, const int16_t *buf[2],
"paddusb "GREEN_DITHER"(%5), %%mm4 \n\t"
"paddusb "RED_DITHER"(%5), %%mm5 \n\t"
#endif
- WRITERGB15(%%REGb, 8280(%5), %%REGBP)
+ WRITERGB15(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(bF8)
);
}
@@ -891,7 +976,6 @@ static void RENAME(yuv2rgb565_2)(SwsContext *c, const int16_t *buf[2],
const int16_t *buf0 = buf[0], *buf1 = buf[1],
*ubuf0 = ubuf[0], *ubuf1 = ubuf[1];
- //Note 8280 == DSTW_OFFSET but the preprocessor can't handle that there :(
__asm__ volatile(
"mov %%"REG_b", "ESP_OFFSET"(%5) \n\t"
"mov %4, %%"REG_b" \n\t"
@@ -904,11 +988,12 @@ static void RENAME(yuv2rgb565_2)(SwsContext *c, const int16_t *buf[2],
"paddusb "GREEN_DITHER"(%5), %%mm4 \n\t"
"paddusb "RED_DITHER"(%5), %%mm5 \n\t"
#endif
- WRITERGB16(%%REGb, 8280(%5), %%REGBP)
+ WRITERGB16(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(bF8,bFC)
);
}
@@ -960,13 +1045,12 @@ static void RENAME(yuv2yuyv422_2)(SwsContext *c, const int16_t *buf[2],
const int16_t *buf0 = buf[0], *buf1 = buf[1],
*ubuf0 = ubuf[0], *ubuf1 = ubuf[1];
- //Note 8280 == DSTW_OFFSET but the preprocessor can't handle that there :(
__asm__ volatile(
"mov %%"REG_b", "ESP_OFFSET"(%5) \n\t"
"mov %4, %%"REG_b" \n\t"
"push %%"REG_BP" \n\t"
YSCALEYUV2PACKED(%%REGBP, %5)
- WRITEYUY2(%%REGb, 8280(%5), %%REGBP)
+ WRITEYUY2(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1109,7 +1193,7 @@ static void RENAME(yuv2rgb32_1)(SwsContext *c, const int16_t *buf0,
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB1(%%REGBP, %5)
YSCALEYUV2RGB1_ALPHA(%%REGBP)
- WRITEBGR32(%%REGb, 8280(%5), %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%%REGb, DSTW_OFFSET"(%5)", %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (abuf0), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1122,7 +1206,7 @@ static void RENAME(yuv2rgb32_1)(SwsContext *c, const int16_t *buf0,
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB1(%%REGBP, %5)
"pcmpeqd %%mm7, %%mm7 \n\t"
- WRITEBGR32(%%REGb, 8280(%5), %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%%REGb, DSTW_OFFSET"(%5)", %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1138,7 +1222,7 @@ static void RENAME(yuv2rgb32_1)(SwsContext *c, const int16_t *buf0,
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB1b(%%REGBP, %5)
YSCALEYUV2RGB1_ALPHA(%%REGBP)
- WRITEBGR32(%%REGb, 8280(%5), %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%%REGb, DSTW_OFFSET"(%5)", %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (abuf0), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1151,7 +1235,7 @@ static void RENAME(yuv2rgb32_1)(SwsContext *c, const int16_t *buf0,
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB1b(%%REGBP, %5)
"pcmpeqd %%mm7, %%mm7 \n\t"
- WRITEBGR32(%%REGb, 8280(%5), %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+ WRITEBGR32(%%REGb, DSTW_OFFSET"(%5)", %%REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1177,11 +1261,12 @@ static void RENAME(yuv2bgr24_1)(SwsContext *c, const int16_t *buf0,
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB1(%%REGBP, %5)
"pxor %%mm7, %%mm7 \n\t"
- WRITEBGR24(%%REGb, 8280(%5), %%REGBP)
+ WRITEBGR24(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(ff_M24A,ff_M24C,ff_M24B)
);
} else {
const int16_t *ubuf1 = ubuf[1];
@@ -1191,11 +1276,12 @@ static void RENAME(yuv2bgr24_1)(SwsContext *c, const int16_t *buf0,
"push %%"REG_BP" \n\t"
YSCALEYUV2RGB1b(%%REGBP, %5)
"pxor %%mm7, %%mm7 \n\t"
- WRITEBGR24(%%REGb, 8280(%5), %%REGBP)
+ WRITEBGR24(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(ff_M24A,ff_M24C,ff_M24B)
);
}
}
@@ -1222,11 +1308,12 @@ static void RENAME(yuv2rgb555_1)(SwsContext *c, const int16_t *buf0,
"paddusb "GREEN_DITHER"(%5), %%mm4 \n\t"
"paddusb "RED_DITHER"(%5), %%mm5 \n\t"
#endif
- WRITERGB15(%%REGb, 8280(%5), %%REGBP)
+ WRITERGB15(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(bF8)
);
} else {
const int16_t *ubuf1 = ubuf[1];
@@ -1242,11 +1329,12 @@ static void RENAME(yuv2rgb555_1)(SwsContext *c, const int16_t *buf0,
"paddusb "GREEN_DITHER"(%5), %%mm4 \n\t"
"paddusb "RED_DITHER"(%5), %%mm5 \n\t"
#endif
- WRITERGB15(%%REGb, 8280(%5), %%REGBP)
+ WRITERGB15(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(bF8)
);
}
}
@@ -1273,11 +1361,12 @@ static void RENAME(yuv2rgb565_1)(SwsContext *c, const int16_t *buf0,
"paddusb "GREEN_DITHER"(%5), %%mm4 \n\t"
"paddusb "RED_DITHER"(%5), %%mm5 \n\t"
#endif
- WRITERGB16(%%REGb, 8280(%5), %%REGBP)
+ WRITERGB16(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(bF8,bFC)
);
} else {
const int16_t *ubuf1 = ubuf[1];
@@ -1293,11 +1382,12 @@ static void RENAME(yuv2rgb565_1)(SwsContext *c, const int16_t *buf0,
"paddusb "GREEN_DITHER"(%5), %%mm4 \n\t"
"paddusb "RED_DITHER"(%5), %%mm5 \n\t"
#endif
- WRITERGB16(%%REGb, 8280(%5), %%REGBP)
+ WRITERGB16(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
"a" (&c->redDither)
+ NAMED_CONSTRAINTS_ADD(bF8,bFC)
);
}
}
@@ -1354,7 +1444,7 @@ static void RENAME(yuv2yuyv422_1)(SwsContext *c, const int16_t *buf0,
"mov %4, %%"REG_b" \n\t"
"push %%"REG_BP" \n\t"
YSCALEYUV2PACKED1(%%REGBP, %5)
- WRITEYUY2(%%REGb, 8280(%5), %%REGBP)
+ WRITEYUY2(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1367,7 +1457,7 @@ static void RENAME(yuv2yuyv422_1)(SwsContext *c, const int16_t *buf0,
"mov %4, %%"REG_b" \n\t"
"push %%"REG_BP" \n\t"
YSCALEYUV2PACKED1b(%%REGBP, %5)
- WRITEYUY2(%%REGb, 8280(%5), %%REGBP)
+ WRITEYUY2(%%REGb, DSTW_OFFSET"(%5)", %%REGBP)
"pop %%"REG_BP" \n\t"
"mov "ESP_OFFSET"(%5), %%"REG_b" \n\t"
:: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
@@ -1375,203 +1465,20 @@ static void RENAME(yuv2yuyv422_1)(SwsContext *c, const int16_t *buf0,
);
}
}
-
-#if COMPILE_TEMPLATE_MMXEXT
-static void RENAME(hyscale_fast)(SwsContext *c, int16_t *dst,
- int dstWidth, const uint8_t *src,
- int srcW, int xInc)
-{
- int32_t *filterPos = c->hLumFilterPos;
- int16_t *filter = c->hLumFilter;
- void *mmxextFilterCode = c->lumMmxextFilterCode;
- int i;
-#if defined(PIC)
- uint64_t ebxsave;
-#endif
-#if ARCH_X86_64
- uint64_t retsave;
-#endif
-
- __asm__ volatile(
-#if defined(PIC)
- "mov %%"REG_b", %5 \n\t"
-#if ARCH_X86_64
- "mov -8(%%rsp), %%"REG_a" \n\t"
- "mov %%"REG_a", %6 \n\t"
-#endif
-#else
-#if ARCH_X86_64
- "mov -8(%%rsp), %%"REG_a" \n\t"
- "mov %%"REG_a", %5 \n\t"
-#endif
-#endif
- "pxor %%mm7, %%mm7 \n\t"
- "mov %0, %%"REG_c" \n\t"
- "mov %1, %%"REG_D" \n\t"
- "mov %2, %%"REG_d" \n\t"
- "mov %3, %%"REG_b" \n\t"
- "xor %%"REG_a", %%"REG_a" \n\t" // i
- PREFETCH" (%%"REG_c") \n\t"
- PREFETCH" 32(%%"REG_c") \n\t"
- PREFETCH" 64(%%"REG_c") \n\t"
-
-#if ARCH_X86_64
-#define CALL_MMXEXT_FILTER_CODE \
- "movl (%%"REG_b"), %%esi \n\t"\
- "call *%4 \n\t"\
- "movl (%%"REG_b", %%"REG_a"), %%esi \n\t"\
- "add %%"REG_S", %%"REG_c" \n\t"\
- "add %%"REG_a", %%"REG_D" \n\t"\
- "xor %%"REG_a", %%"REG_a" \n\t"\
-
-#else
-#define CALL_MMXEXT_FILTER_CODE \
- "movl (%%"REG_b"), %%esi \n\t"\
- "call *%4 \n\t"\
- "addl (%%"REG_b", %%"REG_a"), %%"REG_c" \n\t"\
- "add %%"REG_a", %%"REG_D" \n\t"\
- "xor %%"REG_a", %%"REG_a" \n\t"\
-
-#endif /* ARCH_X86_64 */
-
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
-
-#if defined(PIC)
- "mov %5, %%"REG_b" \n\t"
-#if ARCH_X86_64
- "mov %6, %%"REG_a" \n\t"
- "mov %%"REG_a", -8(%%rsp) \n\t"
-#endif
-#else
-#if ARCH_X86_64
- "mov %5, %%"REG_a" \n\t"
- "mov %%"REG_a", -8(%%rsp) \n\t"
-#endif
-#endif
- :: "m" (src), "m" (dst), "m" (filter), "m" (filterPos),
- "m" (mmxextFilterCode)
-#if defined(PIC)
- ,"m" (ebxsave)
-#endif
-#if ARCH_X86_64
- ,"m"(retsave)
-#endif
- : "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S, "%"REG_D
-#if !defined(PIC)
- ,"%"REG_b
-#endif
- );
-
- for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--)
- dst[i] = src[srcW-1]*128;
-}
-
-static void RENAME(hcscale_fast)(SwsContext *c, int16_t *dst1, int16_t *dst2,
- int dstWidth, const uint8_t *src1,
- const uint8_t *src2, int srcW, int xInc)
-{
- int32_t *filterPos = c->hChrFilterPos;
- int16_t *filter = c->hChrFilter;
- void *mmxextFilterCode = c->chrMmxextFilterCode;
- int i;
-#if defined(PIC)
- DECLARE_ALIGNED(8, uint64_t, ebxsave);
-#endif
-#if ARCH_X86_64
- DECLARE_ALIGNED(8, uint64_t, retsave);
-#endif
-
- __asm__ volatile(
-#if defined(PIC)
- "mov %%"REG_b", %7 \n\t"
-#if ARCH_X86_64
- "mov -8(%%rsp), %%"REG_a" \n\t"
- "mov %%"REG_a", %8 \n\t"
-#endif
-#else
-#if ARCH_X86_64
- "mov -8(%%rsp), %%"REG_a" \n\t"
- "mov %%"REG_a", %7 \n\t"
-#endif
-#endif
- "pxor %%mm7, %%mm7 \n\t"
- "mov %0, %%"REG_c" \n\t"
- "mov %1, %%"REG_D" \n\t"
- "mov %2, %%"REG_d" \n\t"
- "mov %3, %%"REG_b" \n\t"
- "xor %%"REG_a", %%"REG_a" \n\t" // i
- PREFETCH" (%%"REG_c") \n\t"
- PREFETCH" 32(%%"REG_c") \n\t"
- PREFETCH" 64(%%"REG_c") \n\t"
-
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- "xor %%"REG_a", %%"REG_a" \n\t" // i
- "mov %5, %%"REG_c" \n\t" // src
- "mov %6, %%"REG_D" \n\t" // buf2
- PREFETCH" (%%"REG_c") \n\t"
- PREFETCH" 32(%%"REG_c") \n\t"
- PREFETCH" 64(%%"REG_c") \n\t"
-
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
- CALL_MMXEXT_FILTER_CODE
-
-#if defined(PIC)
- "mov %7, %%"REG_b" \n\t"
-#if ARCH_X86_64
- "mov %8, %%"REG_a" \n\t"
- "mov %%"REG_a", -8(%%rsp) \n\t"
-#endif
-#else
-#if ARCH_X86_64
- "mov %7, %%"REG_a" \n\t"
- "mov %%"REG_a", -8(%%rsp) \n\t"
-#endif
-#endif
- :: "m" (src1), "m" (dst1), "m" (filter), "m" (filterPos),
- "m" (mmxextFilterCode), "m" (src2), "m"(dst2)
-#if defined(PIC)
- ,"m" (ebxsave)
-#endif
-#if ARCH_X86_64
- ,"m"(retsave)
-#endif
- : "%"REG_a, "%"REG_c, "%"REG_d, "%"REG_S, "%"REG_D
-#if !defined(PIC)
- ,"%"REG_b
-#endif
- );
-
- for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) {
- dst1[i] = src1[srcW-1]*128;
- dst2[i] = src2[srcW-1]*128;
- }
-}
-#endif /* COMPILE_TEMPLATE_MMXEXT */
-
static av_cold void RENAME(sws_init_swscale)(SwsContext *c)
{
enum AVPixelFormat dstFormat = c->dstFormat;
- if (!is16BPS(dstFormat) && !is9_OR_10BPS(dstFormat) &&
- dstFormat != AV_PIX_FMT_NV12 && dstFormat != AV_PIX_FMT_NV21) {
- if (!(c->flags & SWS_BITEXACT)) {
+ c->use_mmx_vfilter= 0;
+ if (!is16BPS(dstFormat) && !is9_OR_10BPS(dstFormat) && dstFormat != AV_PIX_FMT_NV12
+ && dstFormat != AV_PIX_FMT_NV21 && !(c->flags & SWS_BITEXACT)) {
if (c->flags & SWS_ACCURATE_RND) {
if (!(c->flags & SWS_FULL_CHR_H_INT)) {
switch (c->dstFormat) {
case AV_PIX_FMT_RGB32: c->yuv2packedX = RENAME(yuv2rgb32_X_ar); break;
+#if HAVE_6REGS
case AV_PIX_FMT_BGR24: c->yuv2packedX = RENAME(yuv2bgr24_X_ar); break;
+#endif
case AV_PIX_FMT_RGB555: c->yuv2packedX = RENAME(yuv2rgb555_X_ar); break;
case AV_PIX_FMT_RGB565: c->yuv2packedX = RENAME(yuv2rgb565_X_ar); break;
case AV_PIX_FMT_YUYV422: c->yuv2packedX = RENAME(yuv2yuyv422_X_ar); break;
@@ -1579,10 +1486,14 @@ static av_cold void RENAME(sws_init_swscale)(SwsContext *c)
}
}
} else {
+ c->use_mmx_vfilter= 1;
+ c->yuv2planeX = RENAME(yuv2yuvX );
if (!(c->flags & SWS_FULL_CHR_H_INT)) {
switch (c->dstFormat) {
case AV_PIX_FMT_RGB32: c->yuv2packedX = RENAME(yuv2rgb32_X); break;
+#if HAVE_6REGS
case AV_PIX_FMT_BGR24: c->yuv2packedX = RENAME(yuv2bgr24_X); break;
+#endif
case AV_PIX_FMT_RGB555: c->yuv2packedX = RENAME(yuv2rgb555_X); break;
case AV_PIX_FMT_RGB565: c->yuv2packedX = RENAME(yuv2rgb565_X); break;
case AV_PIX_FMT_YUYV422: c->yuv2packedX = RENAME(yuv2yuyv422_X); break;
@@ -1590,7 +1501,6 @@ static av_cold void RENAME(sws_init_swscale)(SwsContext *c)
}
}
}
- }
if (!(c->flags & SWS_FULL_CHR_H_INT)) {
switch (c->dstFormat) {
case AV_PIX_FMT_RGB32:
@@ -1619,12 +1529,12 @@ static av_cold void RENAME(sws_init_swscale)(SwsContext *c)
}
}
- if (c->srcBpc == 8 && c->dstBpc <= 10) {
+ if (c->srcBpc == 8 && c->dstBpc <= 14) {
// Use the new MMX scaler if the MMXEXT one can't be used (it is faster than the x86 ASM one).
#if COMPILE_TEMPLATE_MMXEXT
if (c->flags & SWS_FAST_BILINEAR && c->canMMXEXTBeUsed) {
- c->hyscale_fast = RENAME(hyscale_fast);
- c->hcscale_fast = RENAME(hcscale_fast);
+ c->hyscale_fast = ff_hyscale_fast_mmxext;
+ c->hcscale_fast = ff_hcscale_fast_mmxext;
} else {
#endif /* COMPILE_TEMPLATE_MMXEXT */
c->hyscale_fast = NULL;
diff --git a/libswscale/x86/w64xmmtest.c b/libswscale/x86/w64xmmtest.c
index dd9a2a4378..88143d9687 100644
--- a/libswscale/x86/w64xmmtest.c
+++ b/libswscale/x86/w64xmmtest.c
@@ -2,20 +2,20 @@
* check XMM registers for clobbers on Win64
* Copyright (c) 2012 Ronald S. Bultje <rsbultje@gmail.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/libswscale/x86/yuv2rgb.c b/libswscale/x86/yuv2rgb.c
index bacc87f6c7..5e2f77c20f 100644
--- a/libswscale/x86/yuv2rgb.c
+++ b/libswscale/x86/yuv2rgb.c
@@ -7,27 +7,26 @@
* 1,4,8bpp support and context / deglobalize stuff
* by Michael Niedermayer (michaelni@gmx.at)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
-#include <assert.h>
#include "config.h"
#include "libswscale/rgb2rgb.h"
@@ -51,34 +50,30 @@ DECLARE_ASM_CONST(8, uint64_t, pb_03) = 0x0303030303030303ULL;
DECLARE_ASM_CONST(8, uint64_t, pb_07) = 0x0707070707070707ULL;
//MMX versions
-#if HAVE_MMX_INLINE
+#if HAVE_MMX_INLINE && HAVE_6REGS
#undef RENAME
#undef COMPILE_TEMPLATE_MMXEXT
#define COMPILE_TEMPLATE_MMXEXT 0
#define RENAME(a) a ## _mmx
#include "yuv2rgb_template.c"
-#endif /* HAVE_MMX_INLINE */
+#endif /* HAVE_MMX_INLINE && HAVE_6REGS */
// MMXEXT versions
-#if HAVE_MMXEXT_INLINE
+#if HAVE_MMXEXT_INLINE && HAVE_6REGS
#undef RENAME
#undef COMPILE_TEMPLATE_MMXEXT
#define COMPILE_TEMPLATE_MMXEXT 1
#define RENAME(a) a ## _mmxext
#include "yuv2rgb_template.c"
-#endif /* HAVE_MMXEXT_INLINE */
+#endif /* HAVE_MMXEXT_INLINE && HAVE_6REGS */
#endif /* HAVE_INLINE_ASM */
av_cold SwsFunc ff_yuv2rgb_init_x86(SwsContext *c)
{
-#if HAVE_MMX_INLINE
+#if HAVE_MMX_INLINE && HAVE_6REGS
int cpu_flags = av_get_cpu_flags();
- if (c->srcFormat != AV_PIX_FMT_YUV420P &&
- c->srcFormat != AV_PIX_FMT_YUVA420P)
- return NULL;
-
#if HAVE_MMXEXT_INLINE
if (INLINE_MMXEXT(cpu_flags)) {
switch (c->dstFormat) {
@@ -118,7 +113,7 @@ av_cold SwsFunc ff_yuv2rgb_init_x86(SwsContext *c)
return yuv420_rgb15_mmx;
}
}
-#endif /* HAVE_MMX_INLINE */
+#endif /* HAVE_MMX_INLINE && HAVE_6REGS */
return NULL;
}
diff --git a/libswscale/x86/yuv2rgb_template.c b/libswscale/x86/yuv2rgb_template.c
index 0b9751623e..acb78f520e 100644
--- a/libswscale/x86/yuv2rgb_template.c
+++ b/libswscale/x86/yuv2rgb_template.c
@@ -4,20 +4,20 @@
* Copyright (C) 2001-2007 Michael Niedermayer
* (c) 2010 Konstantin Shishkov
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -48,17 +48,14 @@
if (h_size * depth > FFABS(dstStride[0])) \
h_size -= 8; \
\
- if (c->srcFormat == AV_PIX_FMT_YUV422P) { \
- srcStride[1] *= 2; \
- srcStride[2] *= 2; \
- } \
+ vshift = c->srcFormat != AV_PIX_FMT_YUV422P; \
\
__asm__ volatile ("pxor %mm4, %mm4\n\t"); \
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 >> 1) * srcStride[1]; \
- const uint8_t *pv = src[2] + (y >> 1) * srcStride[2]; \
+ 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; \
#define YUV2RGB_INITIAL_LOAD \
@@ -142,10 +139,21 @@
"add $4, %0\n\t" \
"js 1b\n\t" \
+#if COMPILE_TEMPLATE_MMXEXT
+#undef RGB_PACK24_B_OPERANDS
+#define RGB_PACK24_B_OPERANDS NAMED_CONSTRAINTS_ARRAY_ADD(mask1101,mask0110,mask0100,mask0010,mask1001)
+#else
+#undef RGB_PACK24_B_OPERANDS
+#define RGB_PACK24_B_OPERANDS
+#endif
+
#define YUV2RGB_OPERANDS \
: "+r" (index), "+r" (image) \
: "r" (pu - index), "r" (pv - index), "r"(&c->redDither), \
"r" (py - 2*index) \
+ NAMED_CONSTRAINTS_ADD(mmx_00ffw,pb_03,pb_07,mmx_redmask,pb_e0) \
+ RGB_PACK24_B_OPERANDS \
+ : "memory" \
); \
} \
@@ -153,6 +161,8 @@
: "+r" (index), "+r" (image) \
: "r" (pu - index), "r" (pv - index), "r"(&c->redDither), \
"r" (py - 2*index), "r" (pa - 2*index) \
+ NAMED_CONSTRAINTS_ADD(mmx_00ffw) \
+ : "memory" \
); \
} \
@@ -193,7 +203,7 @@ static inline int RENAME(yuv420_rgb15)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(2)
@@ -221,7 +231,7 @@ static inline int RENAME(yuv420_rgb16)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(2)
@@ -311,7 +321,7 @@ static inline int RENAME(yuv420_rgb24)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(3)
@@ -329,7 +339,7 @@ static inline int RENAME(yuv420_bgr24)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(3)
@@ -373,7 +383,7 @@ static inline int RENAME(yuv420_rgb32)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(4)
@@ -394,7 +404,7 @@ static inline int RENAME(yuva420_rgb32)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(4)
@@ -416,7 +426,7 @@ static inline int RENAME(yuv420_bgr32)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(4)
@@ -437,7 +447,7 @@ static inline int RENAME(yuva420_bgr32)(SwsContext *c, const uint8_t *src[],
int srcSliceY, int srcSliceH,
uint8_t *dst[], int dstStride[])
{
- int y, h_size;
+ int y, h_size, vshift;
YUV2RGB_LOOP(4)
diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c
index a4f7a1178e..1d682ba57c 100644
--- a/libswscale/yuv2rgb.c
+++ b/libswscale/yuv2rgb.c
@@ -6,27 +6,26 @@
* 1,4,8bpp support and context / deglobalize stuff
* by Michael Niedermayer (michaelni@gmx.at)
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
-#include <assert.h>
#include "libavutil/cpu.h"
#include "libavutil/bswap.h"
@@ -34,6 +33,7 @@
#include "rgb2rgb.h"
#include "swscale.h"
#include "swscale_internal.h"
+#include "libavutil/pixdesc.h"
const int32_t ff_yuv2rgb_coeffs[8][4] = {
{ 117504, 138453, 13954, 34903 }, /* no sequence_display_extension */
@@ -56,9 +56,9 @@ const int *sws_getCoefficients(int colorspace)
#define LOADCHROMA(i) \
U = pu[i]; \
V = pv[i]; \
- r = (void *)c->table_rV[V]; \
- g = (void *)(c->table_gU[U] + c->table_gV[V]); \
- b = (void *)c->table_bU[U];
+ 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]; \
@@ -382,24 +382,65 @@ ENDYUV2RGBLINE(24, 1)
PUTBGR24(dst_2, py_2, 0);
ENDYUV2RGBFUNC()
-// This is exactly the same code as yuv2rgb_c_32 except for the types of
-// r, g, b, dst_1, dst_2
-YUV2RGBFUNC(yuv2rgb_c_16, uint16_t, 0)
+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];
+ 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);
- PUTRGB(dst_1, py_1, 0);
- PUTRGB(dst_2, py_2, 0);
+ PUTRGB16(dst_1, py_1, 0, 0);
+ PUTRGB16(dst_2, py_2, 0, 0 + 8);
LOADCHROMA(1);
- PUTRGB(dst_2, py_2, 1);
- PUTRGB(dst_1, py_1, 1);
+ PUTRGB16(dst_2, py_2, 1, 2 + 8);
+ PUTRGB16(dst_1, py_1, 1, 2);
LOADCHROMA(2);
- PUTRGB(dst_1, py_1, 2);
- PUTRGB(dst_2, py_2, 2);
+ PUTRGB16(dst_1, py_1, 2, 4);
+ PUTRGB16(dst_2, py_2, 2, 4 + 8);
LOADCHROMA(3);
- PUTRGB(dst_2, py_2, 3);
- PUTRGB(dst_1, py_1, 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];
+ 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);
+
+ 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
@@ -463,7 +504,27 @@ YUV2RGBFUNC(yuv2rgb_c_8_ordered_dither, uint8_t, 0)
LOADCHROMA(3);
PUTRGB8(dst_2, py_2, 3, 6 + 8);
PUTRGB8(dst_1, py_1, 3, 6);
-CLOSEYUV2RGBFUNC(8)
+
+ENDYUV2RGBLINE(8, 0)
+ const uint8_t *d32 = ff_dither_8x8_32[y & 7];
+ const uint8_t *d64 = ff_dither_8x8_73[y & 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[y & 7];
+ const uint8_t *d64 = ff_dither_8x8_73[y & 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[y & 7];
@@ -496,7 +557,27 @@ YUV2RGBFUNC(yuv2rgb_c_4_ordered_dither, uint8_t, 0)
LOADCHROMA(3);
PUTRGB4D(dst_2, py_2, 3, 6 + 8);
PUTRGB4D(dst_1, py_1, 3, 6);
-CLOSEYUV2RGBFUNC(4)
+
+ENDYUV2RGBLINE(4, 0)
+ const uint8_t * d64 = ff_dither_8x8_73[y & 7];
+ const uint8_t *d128 = ff_dither_8x8_220[y & 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[y & 7];
+ const uint8_t *d128 = ff_dither_8x8_220[y & 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[y & 7];
@@ -527,12 +608,28 @@ YUV2RGBFUNC(yuv2rgb_c_4b_ordered_dither, uint8_t, 0)
LOADCHROMA(3);
PUTRGB4DB(dst_2, py_2, 3, 6 + 8);
PUTRGB4DB(dst_1, py_1, 3, 6);
-CLOSEYUV2RGBFUNC(8)
+ENDYUV2RGBLINE(8, 0)
+ const uint8_t *d64 = ff_dither_8x8_73[y & 7];
+ const uint8_t *d128 = ff_dither_8x8_220[y & 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[y & 7];
+ const uint8_t *d128 = ff_dither_8x8_220[y & 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)
const uint8_t *d128 = ff_dither_8x8_220[y & 7];
char out_1 = 0, out_2 = 0;
- g = c->table_gU[128] + c->table_gV[128];
+ g = c->table_gU[128 + YUVRGB_TABLE_HEADROOM] + c->table_gV[128 + YUVRGB_TABLE_HEADROOM];
#define PUTRGB1(out, src, i, o) \
Y = src[2 * i]; \
@@ -570,7 +667,7 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c)
av_log(c, AV_LOG_WARNING,
"No accelerated colorspace conversion found from %s to %s.\n",
- sws_format_name(c->srcFormat), sws_format_name(c->dstFormat));
+ av_get_pix_fmt_name(c->srcFormat), av_get_pix_fmt_name(c->dstFormat));
switch (c->dstFormat) {
case AV_PIX_FMT_BGR48BE:
@@ -581,23 +678,21 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c)
return yuv2rgb_c_48;
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_ABGR:
- if (CONFIG_SWSCALE_ALPHA && c->srcFormat == AV_PIX_FMT_YUVA420P)
+ if (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat))
return yuva2argb_c;
case AV_PIX_FMT_RGBA:
case AV_PIX_FMT_BGRA:
- if (CONFIG_SWSCALE_ALPHA && c->srcFormat == AV_PIX_FMT_YUVA420P)
- return yuva2rgba_c;
- else
- return yuv2rgb_c_32;
+ 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_16;
+ return yuv2rgb_c_15_ordered_dither;
case AV_PIX_FMT_RGB444:
case AV_PIX_FMT_BGR444:
return yuv2rgb_c_12_ordered_dither;
@@ -612,36 +707,32 @@ SwsFunc ff_yuv2rgb_get_func_ptr(SwsContext *c)
return yuv2rgb_c_4b_ordered_dither;
case AV_PIX_FMT_MONOBLACK:
return yuv2rgb_c_1_ordered_dither;
- default:
- assert(0);
}
return NULL;
}
-static void fill_table(uint8_t *table[256], const int elemsize,
- const int inc, void *y_tab)
+static void fill_table(uint8_t* table[256 + 2*YUVRGB_TABLE_HEADROOM], const int elemsize,
+ const int64_t inc, void *y_tab)
{
int i;
- int64_t cb = 0;
uint8_t *y_table = y_tab;
y_table -= elemsize * (inc >> 9);
- for (i = 0; i < 256; i++) {
+ for (i = 0; i < 256 + 2*YUVRGB_TABLE_HEADROOM; i++) {
+ int64_t cb = av_clip_uint8(i-YUVRGB_TABLE_HEADROOM)*inc;
table[i] = y_table + elemsize * (cb >> 16);
- cb += inc;
}
}
-static void fill_gv_table(int table[256], const int elemsize, const int inc)
+static void fill_gv_table(int table[256 + 2*YUVRGB_TABLE_HEADROOM], const int elemsize, const int64_t inc)
{
int i;
- int64_t cb = 0;
int off = -(inc >> 9);
- for (i = 0; i < 256; i++) {
+ for (i = 0; i < 256 + 2*YUVRGB_TABLE_HEADROOM; i++) {
+ int64_t cb = av_clip_uint8(i-YUVRGB_TABLE_HEADROOM)*inc;
table[i] = elemsize * (off + (cb >> 16));
- cb += inc;
}
}
@@ -684,7 +775,7 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
uint8_t *y_table;
uint16_t *y_table16;
uint32_t *y_table32;
- int i, base, rbase, gbase, bbase, abase, needAlpha;
+ int i, base, rbase, gbase, bbase, av_uninit(abase), needAlpha;
const int yoffs = fullRange ? 384 : 326;
int64_t crv = inv_table[0];
@@ -729,12 +820,12 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
c->yuv2rgb_u2b_coeff = (int16_t)roundToInt16(cbu << 13);
//scale coefficients by cy
- crv = ((crv << 16) + 0x8000) / cy;
- cbu = ((cbu << 16) + 0x8000) / cy;
- cgu = ((cgu << 16) + 0x8000) / cy;
- cgv = ((cgv << 16) + 0x8000) / cy;
+ crv = ((crv << 16) + 0x8000) / FFMAX(cy, 1);
+ cbu = ((cbu << 16) + 0x8000) / FFMAX(cy, 1);
+ cgu = ((cgu << 16) + 0x8000) / FFMAX(cy, 1);
+ cgv = ((cgv << 16) + 0x8000) / FFMAX(cy, 1);
- av_free(c->yuvTable);
+ av_freep(&c->yuvTable);
#define ALLOC_YUV_TABLE(x) \
c->yuvTable = av_malloc(x); \
@@ -851,6 +942,7 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
fill_gv_table(c->table_gV, 1, cgv);
break;
case 32:
+ case 64:
base = (c->dstFormat == AV_PIX_FMT_RGB32_1 ||
c->dstFormat == AV_PIX_FMT_BGR32_1) ? 8 : 0;
rbase = base + (isRgb ? 16 : 0);
@@ -876,7 +968,6 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4],
fill_gv_table(c->table_gV, 4, cgv);
break;
default:
- c->yuvTable = NULL;
if(!isPlanar(c->dstFormat) || bpp <= 24)
av_log(c, AV_LOG_ERROR, "%ibpp not supported by yuv2rgb\n", bpp);
return -1;
diff --git a/presets/libvpx-1080p.avpreset b/presets/libvpx-1080p.avpreset
deleted file mode 100644
index 5c7da6fb86..0000000000
--- a/presets/libvpx-1080p.avpreset
+++ /dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=16
-deadline=good
-cpu-used=0
-profile=1
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-1080p.ffpreset b/presets/libvpx-1080p.ffpreset
new file mode 100644
index 0000000000..cf25932100
--- /dev/null
+++ b/presets/libvpx-1080p.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=16
+deadline=good
+cpu-used=0
+vprofile=1
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-1080p50_60.avpreset b/presets/libvpx-1080p50_60.avpreset
deleted file mode 100644
index f85d3d6486..0000000000
--- a/presets/libvpx-1080p50_60.avpreset
+++ /dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=25
-deadline=good
-cpu-used=0
-profile=1
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-1080p50_60.ffpreset b/presets/libvpx-1080p50_60.ffpreset
new file mode 100644
index 0000000000..4a88040d34
--- /dev/null
+++ b/presets/libvpx-1080p50_60.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=25
+deadline=good
+cpu-used=0
+vprofile=1
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-360p.avpreset b/presets/libvpx-360p.avpreset
deleted file mode 100644
index 2cb9e380f3..0000000000
--- a/presets/libvpx-360p.avpreset
+++ /dev/null
@@ -1,16 +0,0 @@
-g=120
-lag-in-frames=16
-deadline=good
-cpu-used=0
-profile=0
-qmax=63
-qmin=0
-b=768k
-
-#ignored unless using -pass 2
-maxrate=1.5M
-minrate=40k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-360p.ffpreset b/presets/libvpx-360p.ffpreset
new file mode 100644
index 0000000000..f9729ba2bb
--- /dev/null
+++ b/presets/libvpx-360p.ffpreset
@@ -0,0 +1,18 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=16
+deadline=good
+cpu-used=0
+vprofile=0
+qmax=63
+qmin=0
+b=768k
+
+#ignored unless using -pass 2
+maxrate=1.5M
+minrate=40k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-720p.avpreset b/presets/libvpx-720p.avpreset
deleted file mode 100644
index 3c7e396ad6..0000000000
--- a/presets/libvpx-720p.avpreset
+++ /dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=16
-deadline=good
-cpu-used=0
-profile=0
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-720p.ffpreset b/presets/libvpx-720p.ffpreset
new file mode 100644
index 0000000000..e84cc150cd
--- /dev/null
+++ b/presets/libvpx-720p.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=16
+deadline=good
+cpu-used=0
+vprofile=0
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libvpx-720p50_60.avpreset b/presets/libvpx-720p50_60.avpreset
deleted file mode 100644
index 613930063e..0000000000
--- a/presets/libvpx-720p50_60.avpreset
+++ /dev/null
@@ -1,17 +0,0 @@
-g=120
-lag-in-frames=25
-deadline=good
-cpu-used=0
-profile=0
-qmax=51
-qmin=11
-slices=4
-b=2M
-
-#ignored unless using -pass 2
-maxrate=24M
-minrate=100k
-auto-alt-ref=1
-arnr-maxframes=7
-arnr-strength=5
-arnr-type=centered
diff --git a/presets/libvpx-720p50_60.ffpreset b/presets/libvpx-720p50_60.ffpreset
new file mode 100644
index 0000000000..8fce2bfb5a
--- /dev/null
+++ b/presets/libvpx-720p50_60.ffpreset
@@ -0,0 +1,19 @@
+vcodec=libvpx
+
+g=120
+lag-in-frames=25
+deadline=good
+cpu-used=0
+vprofile=0
+qmax=51
+qmin=11
+slices=4
+b=2M
+
+#ignored unless using -pass 2
+maxrate=24M
+minrate=100k
+auto-alt-ref=1
+arnr-maxframes=7
+arnr-strength=5
+arnr-type=centered
diff --git a/presets/libx264-baseline.avpreset b/presets/libx264-baseline.avpreset
deleted file mode 100644
index 0626e28440..0000000000
--- a/presets/libx264-baseline.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-profile=baseline
diff --git a/presets/libx264-fast.avpreset b/presets/libx264-fast.avpreset
deleted file mode 100644
index a8c526e8b4..0000000000
--- a/presets/libx264-fast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=fast
diff --git a/presets/libx264-fast_firstpass.avpreset b/presets/libx264-fast_firstpass.avpreset
deleted file mode 100644
index d9cf5afe0e..0000000000
--- a/presets/libx264-fast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=fast
-fastfirstpass=1
diff --git a/presets/libx264-faster.avpreset b/presets/libx264-faster.avpreset
deleted file mode 100644
index e311989bbb..0000000000
--- a/presets/libx264-faster.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=faster
diff --git a/presets/libx264-faster_firstpass.avpreset b/presets/libx264-faster_firstpass.avpreset
deleted file mode 100644
index 48a2d443bc..0000000000
--- a/presets/libx264-faster_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=faster
-fastfirstpass=1
diff --git a/presets/libx264-ipod320.avpreset b/presets/libx264-ipod320.avpreset
deleted file mode 100644
index 6323191740..0000000000
--- a/presets/libx264-ipod320.avpreset
+++ /dev/null
@@ -1,4 +0,0 @@
-profile=baseline
-level=13
-maxrate=768000
-bufsize=3000000
diff --git a/presets/libx264-ipod640.avpreset b/presets/libx264-ipod640.avpreset
deleted file mode 100644
index c2c3e1a88e..0000000000
--- a/presets/libx264-ipod640.avpreset
+++ /dev/null
@@ -1,4 +0,0 @@
-profile=baseline
-level=30
-maxrate=10000000
-bufsize=10000000
diff --git a/presets/libx264-lossless_fast.avpreset b/presets/libx264-lossless_fast.avpreset
deleted file mode 100644
index 1658d563aa..0000000000
--- a/presets/libx264-lossless_fast.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=fast
-qp=0
diff --git a/presets/libx264-lossless_max.avpreset b/presets/libx264-lossless_max.avpreset
deleted file mode 100644
index c25ff32d16..0000000000
--- a/presets/libx264-lossless_max.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=placebo
-qp=0
diff --git a/presets/libx264-lossless_medium.avpreset b/presets/libx264-lossless_medium.avpreset
deleted file mode 100644
index f7b1d81f39..0000000000
--- a/presets/libx264-lossless_medium.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=medium
-qp=0
diff --git a/presets/libx264-lossless_slow.avpreset b/presets/libx264-lossless_slow.avpreset
deleted file mode 100644
index a15ff4c426..0000000000
--- a/presets/libx264-lossless_slow.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slow
-qp=0
diff --git a/presets/libx264-lossless_slower.avpreset b/presets/libx264-lossless_slower.avpreset
deleted file mode 100644
index bd71f03291..0000000000
--- a/presets/libx264-lossless_slower.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slower
-qp=0
diff --git a/presets/libx264-lossless_ultrafast.avpreset b/presets/libx264-lossless_ultrafast.avpreset
deleted file mode 100644
index 4d71eb72aa..0000000000
--- a/presets/libx264-lossless_ultrafast.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=ultrafast
-qp=0
diff --git a/presets/libx264-main.avpreset b/presets/libx264-main.avpreset
deleted file mode 100644
index 336c69b3af..0000000000
--- a/presets/libx264-main.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-profile=main
diff --git a/presets/libx264-medium.avpreset b/presets/libx264-medium.avpreset
deleted file mode 100644
index 261d584f95..0000000000
--- a/presets/libx264-medium.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=medium
diff --git a/presets/libx264-medium_firstpass.avpreset b/presets/libx264-medium_firstpass.avpreset
deleted file mode 100644
index 06c8f9f8fb..0000000000
--- a/presets/libx264-medium_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=medium
-fastfirstpass=1
diff --git a/presets/libx264-placebo.avpreset b/presets/libx264-placebo.avpreset
deleted file mode 100644
index 93d721d004..0000000000
--- a/presets/libx264-placebo.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=placebo
diff --git a/presets/libx264-placebo_firstpass.avpreset b/presets/libx264-placebo_firstpass.avpreset
deleted file mode 100644
index c8099e50c7..0000000000
--- a/presets/libx264-placebo_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=placebo
-fastfirstpass=1
diff --git a/presets/libx264-slow.avpreset b/presets/libx264-slow.avpreset
deleted file mode 100644
index 85778ec8ba..0000000000
--- a/presets/libx264-slow.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=slow
diff --git a/presets/libx264-slow_firstpass.avpreset b/presets/libx264-slow_firstpass.avpreset
deleted file mode 100644
index 9998bc95a2..0000000000
--- a/presets/libx264-slow_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slow
-fastfirstpass=1
diff --git a/presets/libx264-slower.avpreset b/presets/libx264-slower.avpreset
deleted file mode 100644
index 87d69893f2..0000000000
--- a/presets/libx264-slower.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=slower
diff --git a/presets/libx264-slower_firstpass.avpreset b/presets/libx264-slower_firstpass.avpreset
deleted file mode 100644
index c798b82872..0000000000
--- a/presets/libx264-slower_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=slower
-fastfirstpass=1
diff --git a/presets/libx264-superfast.avpreset b/presets/libx264-superfast.avpreset
deleted file mode 100644
index 1c117ecf60..0000000000
--- a/presets/libx264-superfast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=superfast
diff --git a/presets/libx264-superfast_firstpass.avpreset b/presets/libx264-superfast_firstpass.avpreset
deleted file mode 100644
index fc70e0970b..0000000000
--- a/presets/libx264-superfast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=superfast
-fastfirstpass=1
diff --git a/presets/libx264-ultrafast.avpreset b/presets/libx264-ultrafast.avpreset
deleted file mode 100644
index 910330188f..0000000000
--- a/presets/libx264-ultrafast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=ultrafast
diff --git a/presets/libx264-ultrafast_firstpass.avpreset b/presets/libx264-ultrafast_firstpass.avpreset
deleted file mode 100644
index e3aaa17a2e..0000000000
--- a/presets/libx264-ultrafast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=ultrafast
-fastfirstpass=1
diff --git a/presets/libx264-veryfast.avpreset b/presets/libx264-veryfast.avpreset
deleted file mode 100644
index fa49629b35..0000000000
--- a/presets/libx264-veryfast.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=veryfast
diff --git a/presets/libx264-veryfast_firstpass.avpreset b/presets/libx264-veryfast_firstpass.avpreset
deleted file mode 100644
index 4909030551..0000000000
--- a/presets/libx264-veryfast_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=veryfast
-fastfirstpass=1
diff --git a/presets/libx264-veryslow.avpreset b/presets/libx264-veryslow.avpreset
deleted file mode 100644
index 7e01c8f5c1..0000000000
--- a/presets/libx264-veryslow.avpreset
+++ /dev/null
@@ -1 +0,0 @@
-preset=veryslow
diff --git a/presets/libx264-veryslow_firstpass.avpreset b/presets/libx264-veryslow_firstpass.avpreset
deleted file mode 100644
index daf5a8f4d5..0000000000
--- a/presets/libx264-veryslow_firstpass.avpreset
+++ /dev/null
@@ -1,2 +0,0 @@
-preset=veryslow
-fastfirstpass=1
diff --git a/tests/Makefile b/tests/Makefile
index ed341010a2..cffa541213 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,7 +1,21 @@
+FFSERVER_REFFILE = $(SRC_PATH)/tests/ffserver.regression.ref
+
THREADS = 1
VREF = tests/vsynth1/00.pgm
AREF = tests/data/asynth1.sw
+FATEW = 34
+FATEH = 34
+
+$(AREF): CMP=
+
+ffservertest: ffserver$(EXESUF) tests/vsynth1/00.pgm tests/data/asynth1.sw
+ @echo
+ @echo "Unfortunately ffserver is broken and therefore its regression"
+ @echo "test fails randomly. Treat the results accordingly."
+ @echo
+ $(SRC_PATH)/tests/ffserver-regression.sh $(FFSERVER_REFFILE) $(SRC_PATH)/tests/ffserver.conf
+
OBJDIRS += tests/data tests/vsynth1 tests/data/filtergraphs
$(VREF): tests/videogen$(HOSTEXESUF) | tests/vsynth1
@@ -19,7 +33,26 @@ tests/data/vsynth1.yuv: tests/videogen$(HOSTEXESUF) | tests/data
tests/data/vsynth2.yuv: tests/rotozoom$(HOSTEXESUF) | tests/data
$(M)$< $(SRC_PATH)/tests/reference.pnm $@
-tests/data/asynth% tests/data/vsynth%.yuv tests/vsynth%/00.pgm: TAG = GEN
+tests/data/vsynth_lena.yuv: tests/rotozoom$(HOSTEXESUF) | tests/data
+ $(M)$< $(SAMPLES)/lena.pnm $@
+
+tests/data/vsynth3.yuv: tests/videogen$(HOSTEXESUF) | tests/data
+ $(M)$< $@ $(FATEW) $(FATEH)
+
+tests/test_copy.ffmeta: TAG = COPY
+tests/test_copy.ffmeta: tests/data
+ $(M)cp -f $(SRC_PATH)/tests/test.ffmeta tests/test_copy.ffmeta
+
+tests/data/ffprobe-test.nut: ffmpeg$(EXESUF) tests/test_copy.ffmeta
+ $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \
+ -f lavfi -i "aevalsrc=sin(400*PI*2*t):d=0.125[out0]; testsrc=d=0.125[out1]; testsrc=s=100x100:d=0.125[out2]" \
+ -f ffmetadata -i $(TARGET_PATH)/tests/test_copy.ffmeta \
+ -flags +bitexact -map 0:0 -map 0:1 -map 0:2 -map_metadata 1 \
+ -map_metadata:s:0 1:s:0 -map_metadata:s:1 1:s:1 \
+ -vcodec rawvideo -acodec pcm_s16le \
+ -y $(TARGET_PATH)/$@ 2>/dev/null
+
+tests/data/%.sw tests/data/asynth% tests/data/vsynth%.yuv tests/vsynth%/00.pgm tests/data/%.nut: TAG = GEN
tests/data/filtergraphs/%: TAG = COPY
tests/data/filtergraphs/%: $(SRC_PATH)/tests/filtergraphs/% | tests/data/filtergraphs
@@ -77,10 +110,15 @@ include $(SRC_PATH)/tests/fate/demux.mak
include $(SRC_PATH)/tests/fate/dfa.mak
include $(SRC_PATH)/tests/fate/dpcm.mak
include $(SRC_PATH)/tests/fate/ea.mak
+include $(SRC_PATH)/tests/fate/exif.mak
+include $(SRC_PATH)/tests/fate/ffmpeg.mak
+include $(SRC_PATH)/tests/fate/ffprobe.mak
include $(SRC_PATH)/tests/fate/filter-audio.mak
include $(SRC_PATH)/tests/fate/filter-video.mak
include $(SRC_PATH)/tests/fate/flac.mak
include $(SRC_PATH)/tests/fate/fft.mak
+include $(SRC_PATH)/tests/fate/gapless.mak
+include $(SRC_PATH)/tests/fate/gif.mak
include $(SRC_PATH)/tests/fate/h264.mak
include $(SRC_PATH)/tests/fate/hevc.mak
include $(SRC_PATH)/tests/fate/image.mak
@@ -90,6 +128,7 @@ include $(SRC_PATH)/tests/fate/libavdevice.mak
include $(SRC_PATH)/tests/fate/libavformat.mak
include $(SRC_PATH)/tests/fate/libavresample.mak
include $(SRC_PATH)/tests/fate/libavutil.mak
+include $(SRC_PATH)/tests/fate/libswresample.mak
include $(SRC_PATH)/tests/fate/lossless-audio.mak
include $(SRC_PATH)/tests/fate/lossless-video.mak
include $(SRC_PATH)/tests/fate/microsoft.mak
@@ -97,6 +136,7 @@ include $(SRC_PATH)/tests/fate/monkeysaudio.mak
include $(SRC_PATH)/tests/fate/mp3.mak
include $(SRC_PATH)/tests/fate/mpc.mak
include $(SRC_PATH)/tests/fate/mpeg4.mak
+include $(SRC_PATH)/tests/fate/mxf.mak
include $(SRC_PATH)/tests/fate/opus.mak
include $(SRC_PATH)/tests/fate/pcm.mak
include $(SRC_PATH)/tests/fate/probe.mak
@@ -105,6 +145,7 @@ include $(SRC_PATH)/tests/fate/qt.mak
include $(SRC_PATH)/tests/fate/qtrle.mak
include $(SRC_PATH)/tests/fate/real.mak
include $(SRC_PATH)/tests/fate/screen.mak
+include $(SRC_PATH)/tests/fate/subtitles.mak
include $(SRC_PATH)/tests/fate/utvideo.mak
include $(SRC_PATH)/tests/fate/video.mak
include $(SRC_PATH)/tests/fate/voice.mak
@@ -115,35 +156,47 @@ include $(SRC_PATH)/tests/fate/wavpack.mak
include $(SRC_PATH)/tests/fate/wma.mak
include $(SRC_PATH)/tests/fate/xvid.mak
-FATE_AVCONV += $(FATE_AVCONV-yes)
-FATE-$(CONFIG_AVCONV) += $(FATE_AVCONV)
+FATE_FFMPEG += $(FATE_FFMPEG-yes) $(FATE_AVCONV) $(FATE_AVCONV-yes)
+FATE-$(CONFIG_FFMPEG) += $(FATE_FFMPEG)
+FATE-$(CONFIG_FFPROBE) += $(FATE_FFPROBE)
FATE_SAMPLES_AVCONV += $(FATE_SAMPLES_AVCONV-yes)
-FATE_SAMPLES-$(CONFIG_AVCONV) += $(FATE_SAMPLES_AVCONV)
-FATE_SAMPLES += $(FATE_SAMPLES-yes)
+FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_FFMPEG-yes)
+FATE_EXTERN-$(CONFIG_FFMPEG) += $(FATE_SAMPLES_AVCONV) $(FATE_SAMPLES_FFMPEG) $(FATE_SAMPLES_FFPROBE)
+FATE_EXTERN += $(FATE_EXTERN-yes)
FATE += $(FATE-yes)
-$(FATE_AVCONV) $(FATE_SAMPLES_AVCONV): avconv$(EXESUF)
+RSYNC_OPTIONS-$(HAVE_RSYNC_CONTIMEOUT) += --contimeout=60
+RSYNC_OPTIONS = -vrltLW --timeout=60 $(RSYNC_OPTIONS-yes)
+
+$(FATE_FFMPEG) $(FATE_SAMPLES_AVCONV) $(FATE_SAMPLES_FFMPEG): ffmpeg$(EXESUF)
+
+$(FATE_FFPROBE) $(FATE_SAMPLES_FFPROBE): ffprobe$(EXESUF)
ifdef SAMPLES
-FATE += $(FATE_SAMPLES)
+FATE += $(FATE_FULL) $(FATE_FULL-yes)
+FATE += $(FATE_EXTERN)
fate-rsync:
- rsync -vaLW rsync://fate-suite.libav.org/fate-suite/ $(SAMPLES)
+ rsync $(RSYNC_OPTIONS) rsync://fate-suite.ffmpeg.org/fate-suite/ $(SAMPLES)
else
+fate::
+ @echo "warning: only a subset of the fate tests will be run because SAMPLES is not specified"
fate-rsync:
@echo "use 'make fate-rsync SAMPLES=/path/to/samples' to sync the fate suite"
-$(FATE_SAMPLES):
+$(FATE_EXTERN):
@echo "$@ requires external samples and SAMPLES not specified"; false
endif
-FATE_UTILS = base64 tiny_psnr
+FATE_UTILS = base64 tiny_psnr tiny_ssim
+
+TOOL = ffmpeg
-fate: $(FATE)
+fate:: $(FATE)
-$(FATE): $(FATE_UTILS:%=tests/%$(HOSTEXESUF))
+$(FATE) $(FATE_TESTS-no): $(FATE_UTILS:%=tests/%$(HOSTEXESUF))
@echo "TEST $(@:fate-%=%)"
- $(Q)$(SRC_PATH)/tests/fate-run.sh $@ "$(SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" '$(CMD)' '$(CMP)' '$(REF)' '$(FUZZ)' '$(THREADS)' '$(THREAD_TYPE)' '$(CPUFLAGS)' '$(CMP_SHIFT)' '$(CMP_TARGET)' '$(SIZE_TOLERANCE)' '$(CMP_UNIT)' '$(GEN)' '$(HWACCEL)'
+ $(Q)$(SRC_PATH)/tests/fate-run.sh $@ "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" '$(CMD)' '$(CMP)' '$(REF)' '$(FUZZ)' '$(THREADS)' '$(THREAD_TYPE)' '$(CPUFLAGS)' '$(CMP_SHIFT)' '$(CMP_TARGET)' '$(SIZE_TOLERANCE)' '$(CMP_UNIT)' '$(GEN)' '$(HWACCEL)'
fate-list:
@printf '%s\n' $(sort $(FATE))
@@ -152,7 +205,7 @@ coverage.info: TAG = LCOV
coverage.info:
$(M)lcov -q -d $(CURDIR) -b $(SRC_PATH) --capture | \
sed "s,$(CURDIR)/\./,$(CURDIR)/," > $@
- $(M)lcov -q --remove $@ "/usr/include*" -o $@
+ $(M)lcov -q --remove $@ "/usr*" -o $@
lcov: TAG = GENHTML
lcov: coverage.info
@@ -166,10 +219,10 @@ lcov-reset:
clean:: testclean
testclean:
- $(RM) -r tests/vsynth1 tests/data
+ $(RM) -r tests/vsynth1 tests/data tools/lavfi-showfiltfmts$(EXESUF)
$(RM) $(CLEANSUFFIXES:%=tests/%)
$(RM) $(TESTTOOLS:%=tests/%$(HOSTEXESUF))
- $(RM) tests/pixfmts.mak
+ $(RM) tests/pixfmts.mak tests/test_copy.ffmeta
-include $(wildcard tests/*.d)
diff --git a/tests/audiogen.c b/tests/audiogen.c
index 7f9caedd4e..8d596b5108 100644
--- a/tests/audiogen.c
+++ b/tests/audiogen.c
@@ -4,20 +4,20 @@
*
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tests/base64.c b/tests/base64.c
index 6462d9aa7a..5035ad96a7 100644
--- a/tests/base64.c
+++ b/tests/base64.c
@@ -1,18 +1,18 @@
/*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tests/copycooker.sh b/tests/copycooker.sh
new file mode 100755
index 0000000000..4b5811dcf6
--- /dev/null
+++ b/tests/copycooker.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+datadir="tests/data"
+
+logfile="$datadir/copy.regression"
+reffile="$1"
+
+list=$(grep -oh ' ./tests/data/.*' tests/ref/{acodec,lavf,vsynth1}/*| sort)
+rm -f $logfile
+for i in $list ; do
+ echo ---------------- >> $logfile
+ echo $i >> $logfile
+ ./ffmpeg_g -flags +bitexact -i $i -acodec copy -vcodec copy -y first.nut
+ ./ffmpeg_g -flags +bitexact -i first.nut -acodec copy -vcodec copy -y second.nut
+ cmp first.nut second.nut >> $logfile
+ md5sum first.nut >> $logfile
+done
+
+if diff -u -w "$reffile" "$logfile" ; then
+ echo
+ echo copy regression test: success
+ exit 0
+else
+ echo
+ echo copy regression test: error
+ exit 1
+fi
diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index 9edfa9aeb6..b88730a47e 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -8,7 +8,7 @@ base=$(dirname $0)
base64=tests/base64
test="${1#fate-}"
-samples=$2
+target_samples=$2
target_exec=$3
target_path=$4
command=$5
@@ -43,7 +43,7 @@ compare(){
}
do_tiny_psnr(){
- psnr=$(tests/tiny_psnr "$1" "$2" $cmp_unit $cmp_shift 0)
+ psnr=$(tests/tiny_psnr "$1" "$2" $cmp_unit $cmp_shift 0) || return 1
val=$(expr "$psnr" : ".*$3: *\([0-9.]*\)")
size1=$(expr "$psnr" : '.*bytes: *\([0-9]*\)')
size2=$(expr "$psnr" : '.*bytes:[ 0-9]*/ *\([0-9]*\)')
@@ -51,6 +51,12 @@ do_tiny_psnr(){
size_cmp=$(compare $size1 $size2 $size_tolerance)
if [ "$val_cmp" != 0 ] || [ "$size_cmp" != 0 ]; then
echo "$psnr"
+ if [ "$val_cmp" != 0 ]; then
+ echo "$3: |$val - $cmp_target| >= $fuzz"
+ fi
+ if [ "$size_cmp" != 0 ]; then
+ echo "size: |$size1 - $size2| >= $size_tolerance"
+ fi
return 1
fi
}
@@ -72,38 +78,53 @@ run(){
$target_exec $target_path/"$@"
}
+runecho(){
+ test "${V:-0}" -gt 0 && echo "$target_exec" $target_path/"$@" >&3
+ $target_exec $target_path/"$@" >&3
+}
+
probefmt(){
- run avprobe -show_format_entry format_name -v 0 "$@"
+ run ffprobe -show_entries format=format_name -print_format default=nw=1:nk=1 -v 0 "$@"
}
-avconv(){
+probeframes(){
+ run ffprobe -show_frames -v 0 "$@"
+}
+
+ffmpeg(){
dec_opts="-hwaccel $hwaccel -threads $threads -thread_type $thread_type"
- avconv_args="-nostats -cpuflags $cpuflags"
+ ffmpeg_args="-nostats -cpuflags $cpuflags"
for arg in $@; do
- [ x${arg} = x-i ] && avconv_args="${avconv_args} ${dec_opts}"
- avconv_args="${avconv_args} ${arg}"
+ [ x${arg} = x-i ] && ffmpeg_args="${ffmpeg_args} ${dec_opts}"
+ ffmpeg_args="${ffmpeg_args} ${arg}"
done
- run avconv ${avconv_args}
+ run ffmpeg ${ffmpeg_args}
}
framecrc(){
- avconv "$@" -f framecrc -
+ ffmpeg "$@" -flags +bitexact -f framecrc -
}
framemd5(){
- avconv "$@" -f framemd5 -
+ ffmpeg "$@" -flags +bitexact -f framemd5 -
}
crc(){
- avconv "$@" -f crc -
+ ffmpeg "$@" -f crc -
}
md5(){
- avconv "$@" md5:
+ ffmpeg "$@" md5:
}
pcm(){
- avconv "$@" -vn -f s16le -
+ ffmpeg "$@" -vn -f s16le -
+}
+
+fmtstdout(){
+ fmt=$1
+ shift 1
+ ffmpeg -flags +bitexact "$@" -f $fmt -
}
enc_dec_pcm(){
@@ -115,8 +136,8 @@ enc_dec_pcm(){
encfile="${outdir}/${test}.${out_fmt}"
cleanfiles=$encfile
encfile=$(target_path ${encfile})
- avconv -i $src_file "$@" -f $out_fmt -y ${encfile} || return
- avconv -f $out_fmt -i ${encfile} -c:a pcm_${pcm_fmt} -f ${dec_fmt} -
+ ffmpeg -i $src_file "$@" -f $out_fmt -y ${encfile} || return
+ ffmpeg -flags +bitexact -i ${encfile} -c:a pcm_${pcm_fmt} -f ${dec_fmt} -
}
FLAGS="-flags +bitexact -sws_flags +accurate_rnd+bitexact -fflags +bitexact"
@@ -137,20 +158,26 @@ enc_dec(){
tsrcfile=$(target_path $srcfile)
tencfile=$(target_path $encfile)
tdecfile=$(target_path $decfile)
- avconv -f $src_fmt $DEC_OPTS -i $tsrcfile $ENC_OPTS $enc_opt $FLAGS \
+ ffmpeg -f $src_fmt $DEC_OPTS -i $tsrcfile $ENC_OPTS $enc_opt $FLAGS \
-f $enc_fmt -y $tencfile || return
do_md5sum $encfile
echo $(wc -c $encfile)
- avconv $DEC_OPTS -i $tencfile $ENC_OPTS $dec_opt $FLAGS \
+ ffmpeg $8 $DEC_OPTS -i $tencfile $ENC_OPTS $dec_opt $FLAGS \
-f $dec_fmt -y $tdecfile || return
do_md5sum $decfile
tests/tiny_psnr $srcfile $decfile $cmp_unit $cmp_shift
}
+lavffatetest(){
+ t="${test#lavf-fate-}"
+ ref=${base}/ref/lavf-fate/$t
+ ${base}/lavf-regression.sh $t lavf-fate tests/vsynth1 "$target_exec" "$target_path" "$threads" "$thread_type" "$cpuflags" "$target_samples"
+}
+
lavftest(){
t="${test#lavf-}"
ref=${base}/ref/lavf/$t
- ${base}/lavf-regression.sh $t lavf tests/vsynth1 "$target_exec" "$target_path" "$threads" "$thread_type" "$cpuflags"
+ ${base}/lavf-regression.sh $t lavf tests/vsynth1 "$target_exec" "$target_path" "$threads" "$thread_type" "$cpuflags" "$target_samples"
}
video_filter(){
@@ -159,36 +186,70 @@ video_filter(){
label=${test#filter-}
raw_src="${target_path}/tests/vsynth1/%02d.pgm"
printf '%-20s' $label
- avconv $DEC_OPTS -f image2 -vcodec pgmyuv -i $raw_src \
+ ffmpeg $DEC_OPTS -f image2 -vcodec pgmyuv -i $raw_src \
$FLAGS $ENC_OPTS -vf "$filters" -vcodec rawvideo -frames:v 5 $* -f nut md5:
}
pixfmts(){
filter=${test#filter-pixfmts-}
+ filter=${filter%_*}
filter_args=$1
+ prefilter_chain=$2
+ nframes=${3:-1}
showfiltfmts="$target_exec $target_path/libavfilter/filtfmts-test"
- exclude_fmts=${outfile}${filter}_exclude_fmts
- out_fmts=${outfile}${filter}_out_fmts
+ scale_exclude_fmts=${outfile}_scale_exclude_fmts
+ scale_in_fmts=${outfile}_scale_in_fmts
+ scale_out_fmts=${outfile}_scale_out_fmts
+ in_fmts=${outfile}_in_fmts
# exclude pixel formats which are not supported as input
- avconv -pix_fmts list 2>/dev/null | awk 'NR > 8 && /^\..\./ { print $2 }' | sort >$exclude_fmts
- $showfiltfmts scale | awk -F '[ \r]' '/^OUTPUT/{ print $3 }' | sort | comm -23 - $exclude_fmts >$out_fmts
+ $showfiltfmts scale | awk -F '[ \r]' '/^INPUT/{ fmt=substr($3, 5); print fmt }' | sort >$scale_in_fmts
+ $showfiltfmts scale | awk -F '[ \r]' '/^OUTPUT/{ fmt=substr($3, 5); print fmt }' | sort >$scale_out_fmts
+ comm -12 $scale_in_fmts $scale_out_fmts >$scale_exclude_fmts
- pix_fmts=$($showfiltfmts $filter | awk -F '[ \r]' '/^INPUT/{ print $3 }' | sort | comm -12 - $out_fmts)
+ $showfiltfmts $filter | awk -F '[ \r]' '/^INPUT/{ fmt=substr($3, 5); print fmt }' | sort >$in_fmts
+ pix_fmts=$(comm -12 $scale_exclude_fmts $in_fmts)
outertest=$test
for pix_fmt in $pix_fmts; do
test=$pix_fmt
- video_filter "format=$pix_fmt,$filter=$filter_args" -pix_fmt $pix_fmt -frames:v 1
+ video_filter "${prefilter_chain}format=$pix_fmt,$filter=$filter_args" -pix_fmt $pix_fmt -frames:v $nframes
done
- rm $exclude_fmts $out_fmts
+ rm $in_fmts $scale_in_fmts $scale_out_fmts $scale_exclude_fmts
test=$outertest
}
+gapless(){
+ sample=$(target_path $1)
+ extra_args=$2
+
+ decfile1="${outdir}/${test}.out-1"
+ decfile2="${outdir}/${test}.out-2"
+ decfile3="${outdir}/${test}.out-3"
+ cleanfiles="$cleanfiles $decfile1 $decfile2 $decfile3"
+
+ # test packet data
+ ffmpeg $extra_args -i "$sample" -flags +bitexact -c:a copy -f framecrc -y $decfile1
+ do_md5sum $decfile1
+ # test decoded (and cut) data
+ ffmpeg $extra_args -i "$sample" -flags +bitexact -f wav md5:
+ # the same as above again, with seeking to the start
+ ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -flags +bitexact -c:a copy -f framecrc -y $decfile2
+ do_md5sum $decfile2
+ ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -flags +bitexact -f wav md5:
+ # test packet data, with seeking to a specific position
+ ffmpeg $extra_args -ss 5 -seek_timestamp 1 -i "$sample" -flags +bitexact -c:a copy -f framecrc -y $decfile3
+ do_md5sum $decfile3
+}
+
mkdir -p "$outdir"
+# Disable globbing: command arguments may contain globbing characters and
+# must be kept verbatim
+set -f
+
exec 3>&2
eval $command >"$outfile" 2>$errfile
err=$?
@@ -201,6 +262,7 @@ fi
if test -e "$ref" || test $cmp = "oneline" ; then
case $cmp in
diff) diff -u -b "$ref" "$outfile" >$cmpfile ;;
+ rawdiff)diff -u "$ref" "$outfile" >$cmpfile ;;
oneoff) oneoff "$ref" "$outfile" >$cmpfile ;;
stddev) stddev "$ref" "$outfile" >$cmpfile ;;
oneline)oneline "$ref" "$outfile" >$cmpfile ;;
@@ -228,5 +290,12 @@ if test $err != 0 && test $gen != "no" ; then
err=$?
fi
-test $err = 0 && rm -f $outfile $errfile $cmpfile $cleanfiles
+if test $err = 0; then
+ rm -f $outfile $errfile $cmpfile $cleanfiles
+elif test $gen = "no"; then
+ echo "Test $test failed. Look at $errfile for details."
+ test "${V:-0}" -gt 0 && cat $errfile
+else
+ echo "Updating reference failed, possibly no output file was generated."
+fi
exit $err
diff --git a/tests/fate-valgrind.supp b/tests/fate-valgrind.supp
new file mode 100644
index 0000000000..db72c54b7f
--- /dev/null
+++ b/tests/fate-valgrind.supp
@@ -0,0 +1,31 @@
+# seems fixed in newer versions
+# http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=577135
+{
+ zlib-inflate
+ Memcheck:Cond
+ fun:inflateReset2
+ fun:inflateInit2_
+}
+# libc overreads on purpose
+# http://sourceware.org/bugzilla/show_bug.cgi?id=12424
+{
+ eval-strtod
+ Memcheck:Addr8
+ fun:__GI___strncasecmp_l
+ fun:____strtod_l_internal
+ fun:av_strtod
+}
+{
+ eval-strtod
+ Memcheck:Value8
+ fun:__GI___strncasecmp_l
+ fun:____strtod_l_internal
+ fun:av_strtod
+}
+{
+ eval-strtod
+ Memcheck:Cond
+ fun:__GI___strncasecmp_l
+ fun:____strtod_l_internal
+ fun:av_strtod
+}
diff --git a/tests/fate.sh b/tests/fate.sh
index f9f8b95810..6ce8c48610 100755
--- a/tests/fate.sh
+++ b/tests/fate.sh
@@ -37,16 +37,18 @@ checkout(){
update()(
cd ${src} || return
case "$repo" in
- git:*) git fetch --force; git reset --hard "origin/$branch" ;;
+ git:*) git fetch --force && git reset --hard "origin/$branch" ;;
esac
)
configure()(
cd ${build} || return
- ${src}/configure \
+ ${shell} ${src}/configure \
--prefix="${inst}" \
--samples="${samples}" \
--enable-gpl \
+ --enable-memory-poisoning \
+ --enable-avresample \
${arch:+--arch=$arch} \
${cpu:+--cpu="$cpu"} \
${toolchain:+--toolchain="$toolchain"} \
@@ -83,7 +85,8 @@ clean(){
report(){
date=$(date -u +%Y%m%d%H%M%S)
echo "fate:1:${date}:${slot}:${version}:$1:$2:${branch}:${comment}" >report
- cat ${build}/config.fate ${build}/tests/data/fate/*.rep >>report
+ cat ${build}/config.fate >>report
+ cat ${build}/tests/data/fate/*.rep >>report || for i in ${build}/tests/data/fate/*.rep ; do cat "$i" >>report ; done
test -n "$fate_recv" && $tar report *.log | gzip | $fate_recv
}
@@ -112,8 +115,8 @@ echo ${version} >version-$slot
rm -rf "${build}" *.log
mkdir -p ${build}
-configure >configure.log 2>&1 || fail $? "error configuring"
-compile >compile.log 2>&1 || fail $? "error compiling"
-fate >test.log 2>&1 || fail $? "error testing"
+configure >configure.log 2>&1 || fail 3 "error configuring"
+compile >compile.log 2>&1 || fail 2 "error compiling"
+fate >test.log 2>&1 || fail 1 "error testing"
report 0 success
clean
diff --git a/tests/fate/aac.mak b/tests/fate/aac.mak
index 63ea06ce53..34823be59e 100644
--- a/tests/fate/aac.mak
+++ b/tests/fate/aac.mak
@@ -85,6 +85,24 @@ FATE_AAC_CT = sbr_bc-ps_i.3gp \
FATE_AAC += $(FATE_AAC_CT:%=fate-aac-ct-%)
+FATE_AAC_ENCODE += fate-aac-aref-encode
+fate-aac-aref-encode: ./tests/data/asynth-44100-2.wav
+fate-aac-aref-encode: CMD = enc_dec_pcm adts wav s16le $(REF) -strict -2 -c:a aac -b:a 512k
+fate-aac-aref-encode: CMP = stddev
+fate-aac-aref-encode: REF = ./tests/data/asynth-44100-2.wav
+fate-aac-aref-encode: CMP_SHIFT = -4096
+fate-aac-aref-encode: CMP_TARGET = 434
+fate-aac-aref-encode: SIZE_TOLERANCE = 2464
+fate-aac-aref-encode: FUZZ = 5
+
+FATE_AAC_ENCODE += fate-aac-ln-encode
+fate-aac-ln-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav -strict -2 -c:a aac -b:a 512k
+fate-aac-ln-encode: CMP = stddev
+fate-aac-ln-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav
+fate-aac-ln-encode: CMP_SHIFT = -4096
+fate-aac-ln-encode: CMP_TARGET = 65
+fate-aac-ln-encode: SIZE_TOLERANCE = 3560
+
FATE_AAC_LATM += fate-aac-latm_000000001180bc60
fate-aac-latm_000000001180bc60: CMD = pcm -i $(TARGET_SAMPLES)/aac/latm_000000001180bc60.mpg
fate-aac-latm_000000001180bc60: REF = $(SAMPLES)/aac/latm_000000001180bc60.s16
@@ -102,7 +120,9 @@ FATE_AAC_ALL = $(FATE_AAC-yes) $(FATE_AAC_LATM-yes)
$(FATE_AAC_ALL): CMP = oneoff
$(FATE_AAC_ALL): FUZZ = 2
-FATE_SAMPLES_AVCONV += $(FATE_AAC_ALL)
+FATE_AAC_ENCODE-$(call ENCMUX, AAC, ADTS) += $(FATE_AAC_ENCODE)
+
+FATE_SAMPLES_FFMPEG += $(FATE_AAC_ALL) $(FATE_AAC_ENCODE-yes)
-fate-aac: $(FATE_AAC_ALL)
+fate-aac: $(FATE_AAC_ALL) $(FATE_AAC_ENCODE)
fate-aac-latm: $(FATE_AAC_LATM-yes)
diff --git a/tests/fate/ac3.mak b/tests/fate/ac3.mak
index 3841240457..f00c3c4eb2 100644
--- a/tests/fate/ac3.mak
+++ b/tests/fate/ac3.mak
@@ -26,6 +26,14 @@ FATE_AC3 += fate-ac3-5.1-downmix-stereo
fate-ac3-5.1-downmix-stereo: CMD = pcm -request_channels 2 -i $(TARGET_SAMPLES)/ac3/monsters_inc_5.1_448_small.ac3
fate-ac3-5.1-downmix-stereo: REF = $(SAMPLES)/ac3/monsters_inc_5.1_448_small_stereo_v2.pcm
+FATE_AC3 += fate-ac3-fixed-2.0
+fate-ac3-fixed-2.0: CMD = pcm -c ac3_fixed -i $(TARGET_SAMPLES)/ac3/monsters_inc_2.0_192_small.ac3
+fate-ac3-fixed-2.0: REF = $(SAMPLES)/ac3/monsters_inc_2.0_192_small_v2.pcm
+
+FATE_AC3 += fate-ac3-fixed-4.0-downmix-mono
+fate-ac3-fixed-4.0-downmix-mono: CMD = pcm -c ac3_fixed -request_channels 1 -i $(TARGET_SAMPLES)/ac3/millers_crossing_4.0.ac3
+fate-ac3-fixed-4.0-downmix-mono: REF = $(SAMPLES)/ac3/millers_crossing_4.0_mono_v2.pcm
+
FATE_EAC3 += fate-eac3-1
fate-eac3-1: CMD = pcm -i $(TARGET_SAMPLES)/eac3/csi_miami_5.1_256_spx_small.eac3
fate-eac3-1: REF = $(SAMPLES)/eac3/csi_miami_5.1_256_spx_small_v2.pcm
@@ -53,6 +61,7 @@ fate-ac3-encode: CMP_SHIFT = -1024
fate-ac3-encode: CMP_TARGET = 404.53
fate-ac3-encode: SIZE_TOLERANCE = 488
+
FATE_EAC3-$(call ENCDEC, EAC3, EAC3) += fate-eac3-encode
fate-eac3-encode: CMD = enc_dec_pcm eac3 wav s16le $(subst $(SAMPLES),$(TARGET_SAMPLES),$(REF)) -c:a eac3 -b:a 128k
fate-eac3-encode: CMP_SHIFT = -1024
@@ -65,7 +74,7 @@ fate-ac3-encode fate-eac3-encode: REF = $(SAMPLES)/audio-reference/luckynight_2c
FATE_AC3-$(call ENCMUX, AC3_FIXED, AC3) += fate-ac3-fixed-encode
fate-ac3-fixed-encode: tests/data/asynth-44100-2.wav
fate-ac3-fixed-encode: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav
-fate-ac3-fixed-encode: CMD = md5 -i $(SRC) -c ac3_fixed -b 128k -f ac3 -flags bitexact
+fate-ac3-fixed-encode: CMD = md5 -i $(SRC) -c ac3_fixed -ab 128k -f ac3 -flags +bitexact
fate-ac3-fixed-encode: CMP = oneline
fate-ac3-fixed-encode: REF = a1d1fc116463b771abf5aef7ed37d7b1
diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak
index 3431754bfe..d693e9e65d 100644
--- a/tests/fate/acodec.mak
+++ b/tests/fate/acodec.mak
@@ -1,6 +1,6 @@
fate-acodec-%: CODEC = $(@:fate-acodec-%=%)
fate-acodec-%: SRC = tests/data/asynth-44100-2.wav
-fate-acodec-%: CMD = enc_dec wav $(SRC) $(FMT) "-b 128k -ar 44100 -c $(CODEC)" wav "-c pcm_s16le" -keep
+fate-acodec-%: CMD = enc_dec wav $(SRC) $(FMT) "-b 128k -c $(CODEC) $(ENCOPTS)" wav "-c pcm_s16le $(DECOPTS)" -keep
fate-acodec-%: CMP_UNIT = 2
fate-acodec-%: REF = $(SRC_PATH)/tests/ref/acodec/$(@:fate-acodec-%=%)
@@ -10,24 +10,38 @@ FATE_ACODEC_PCM-$(call ENCDEC, PCM_S8, MOV) += s8
FATE_ACODEC_PCM-$(call ENCDEC, PCM_U8, WAV) += u8
FATE_ACODEC_PCM-$(call ENCDEC, PCM_S16BE, MOV) += s16be
FATE_ACODEC_PCM-$(call ENCDEC, PCM_S16LE, WAV) += s16le
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_U16BE, NUT) += u16be
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_U16LE, NUT) += u16le
FATE_ACODEC_PCM-$(call ENCDEC, PCM_S24BE, MOV) += s24be
FATE_ACODEC_PCM-$(call ENCDEC, PCM_S24LE, WAV) += s24le
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_U24BE, NUT) += u24be
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_U24LE, NUT) += u24le
FATE_ACODEC_PCM-$(call ENCDEC, PCM_S32BE, MOV) += s32be
FATE_ACODEC_PCM-$(call ENCDEC, PCM_S32LE, WAV) += s32le
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_U32BE, NUT) += u32be
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_U32LE, NUT) += u32le
FATE_ACODEC_PCM-$(call ENCDEC, PCM_F32BE, AU) += f32be
FATE_ACODEC_PCM-$(call ENCDEC, PCM_F32LE, WAV) += f32le
FATE_ACODEC_PCM-$(call ENCDEC, PCM_F64BE, AU) += f64be
FATE_ACODEC_PCM-$(call ENCDEC, PCM_F64LE, WAV) += f64le
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_S8_PLANAR, NUT) += s8_planar
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_S16BE_PLANAR, NUT) += s16be_planar
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_S16LE_PLANAR, NUT) += s16le_planar
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_S24LE_PLANAR, NUT) += s24le_planar
+FATE_ACODEC_PCM-$(call ENCDEC, PCM_S32LE_PLANAR, NUT) += s32le_planar
FATE_ACODEC_PCM := $(FATE_ACODEC_PCM-yes:%=fate-acodec-pcm-%)
FATE_ACODEC += $(FATE_ACODEC_PCM)
fate-acodec-pcm: $(FATE_ACODEC_PCM)
fate-acodec-pcm-%: FMT = wav
+fate-acodec-pcm-%_planar: FMT = nut
fate-acodec-pcm-%: CODEC = pcm_$(@:fate-acodec-pcm-%=%)
fate-acodec-pcm-s8: FMT = mov
fate-acodec-pcm-s%be: FMT = mov
+fate-acodec-pcm-u%be: FMT = nut
+fate-acodec-pcm-u%le: FMT = nut
fate-acodec-pcm-f%be: FMT = au
FATE_ACODEC_ADPCM-$(call ENCDEC, ADPCM_ADX, ADX) += adx
@@ -50,18 +64,98 @@ fate-acodec-adpcm-ms: FMT = wav
fate-acodec-adpcm-swf: FMT = flv
fate-acodec-adpcm-yamaha: FMT = wav
+FATE_ACODEC_ADPCM_TRELLIS-$(call ENCDEC, ADPCM_ADX, ADX) += adx
+FATE_ACODEC_ADPCM_TRELLIS-$(call ENCDEC, ADPCM_IMA_QT, AIFF) += ima_qt
+FATE_ACODEC_ADPCM_TRELLIS-$(call ENCDEC, ADPCM_IMA_WAV, WAV) += ima_wav
+FATE_ACODEC_ADPCM_TRELLIS-$(call ENCDEC, ADPCM_MS, WAV) += ms
+FATE_ACODEC_ADPCM_TRELLIS-$(call ENCDEC, ADPCM_SWF, FLV) += swf
+FATE_ACODEC_ADPCM_TRELLIS-$(call ENCDEC, ADPCM_YAMAHA, WAV) += yamaha
+
+FATE_ACODEC_ADPCM_TRELLIS := $(FATE_ACODEC_ADPCM_TRELLIS-yes:%=fate-acodec-adpcm-%-trellis)
+FATE_ACODEC += $(FATE_ACODEC_ADPCM_TRELLIS)
+fate-acodec-adpcm-trellis: $(FATE_ACODEC_ADPCM_TRELLIS)
+
+fate-acodec-adpcm-%-trellis: CODEC = adpcm_$(@:fate-acodec-adpcm-%-trellis=%)
+fate-acodec-adpcm-%-trellis: ENCOPTS = -trellis 5
+
+fate-acodec-adpcm-adx-trellis: FMT = adx
+fate-acodec-adpcm-ima_qt-trellis: FMT = aiff
+fate-acodec-adpcm-ima_wav-trellis: FMT = wav
+fate-acodec-adpcm-ms-trellis: FMT = wav
+fate-acodec-adpcm-swf-trellis: FMT = flv
+fate-acodec-adpcm-yamaha-trellis: FMT = wav
+
FATE_ACODEC-$(call ENCDEC, MP2, MP2 MP3) += fate-acodec-mp2
fate-acodec-mp2: FMT = mp2
fate-acodec-mp2: CMP_SHIFT = -1924
+fate-acodec-mp2: ENCOPTS = -b:a 128k
+
+FATE_ACODEC-$(call ENCDEC, MP2FIXED MP2 , MP2 MP3) += fate-acodec-mp2fixed
+fate-acodec-mp2fixed: FMT = mp2
+fate-acodec-mp2fixed: CMP_SHIFT = -1924
FATE_ACODEC-$(call ENCDEC, ALAC, MOV) += fate-acodec-alac
fate-acodec-alac: FMT = mov
fate-acodec-alac: CODEC = alac -compression_level 1
-FATE_ACODEC-$(call ENCDEC, FLAC, FLAC) += fate-acodec-flac
+FATE_ACODEC-$(call ENCDEC, DCA, DTS) += fate-acodec-dca
+fate-acodec-dca: tests/data/asynth-44100-2.wav
+fate-acodec-dca: SRC = tests/data/asynth-44100-2.wav
+fate-acodec-dca: CMD = md5 -i $(TARGET_PATH)/$(SRC) -c:a dca -strict -2 -f dts -flags +bitexact
+fate-acodec-dca: CMP = oneline
+fate-acodec-dca: REF = fe28cef432ed88de4ee01b87537fd2bd
+
+FATE_ACODEC-$(call ENCDEC, DCA, WAV) += fate-acodec-dca2
+fate-acodec-dca2: CMD = enc_dec_pcm dts wav s16le $(SRC) -c:a dca -strict -2 -flags +bitexact
+fate-acodec-dca2: REF = $(SRC)
+fate-acodec-dca2: CMP = stddev
+fate-acodec-dca2: CMP_SHIFT = -2048
+fate-acodec-dca2: CMP_TARGET = 527
+fate-acodec-dca2: SIZE_TOLERANCE = 1632
+
+FATE_ACODEC-$(call ENCDEC, FLAC, FLAC) += fate-acodec-flac fate-acodec-flac-exact-rice
fate-acodec-flac: FMT = flac
fate-acodec-flac: CODEC = flac -compression_level 2
+fate-acodec-flac-exact-rice: FMT = flac
+fate-acodec-flac-exact-rice: CODEC = flac -compression_level 2 -exact_rice_parameters 1
+
+FATE_ACODEC-$(call ENCDEC, G723_1, G723_1) += fate-acodec-g723_1
+fate-acodec-g723_1: tests/data/asynth-8000-1.wav
+fate-acodec-g723_1: SRC = tests/data/asynth-8000-1.wav
+fate-acodec-g723_1: FMT = g723_1
+fate-acodec-g723_1: CODEC = g723_1
+fate-acodec-g723_1: ENCOPTS = -b:a 6.3k
+fate-acodec-g723_1: CMP_SHIFT = 8
+
+FATE_ACODEC-$(call ENCDEC, RA_144, WAV) += fate-acodec-ra144
+fate-acodec-ra144: tests/data/asynth-8000-1.wav
+fate-acodec-ra144: SRC = tests/data/asynth-8000-1.wav
+fate-acodec-ra144: CMD = enc_dec_pcm rm wav s16le $(SRC) -c:a real_144
+fate-acodec-ra144: REF = $(SRC)
+fate-acodec-ra144: CMP = stddev
+fate-acodec-ra144: CMP_TARGET = 4777
+fate-acodec-ra144: CMP_SHIFT = -320
+
+FATE_ACODEC-$(call ENCDEC, ROQ_DPCM, ROQ) += fate-acodec-roqaudio
+fate-acodec-roqaudio: FMT = roq
+fate-acodec-roqaudio: CODEC = roq_dpcm
+fate-acodec-roqaudio: ENCOPTS = -ar 22050
+fate-acodec-roqaudio: DECOPTS = -ar 44100
+
+FATE_ACODEC-$(call ENCDEC, S302M, MPEGTS) += fate-acodec-s302m
+fate-acodec-s302m: FMT = mpegts
+fate-acodec-s302m: CODEC = s302m
+fate-acodec-s302m: ENCOPTS = -ar 48000 -strict -2
+fate-acodec-s302m: DECOPTS = -ar 44100
+
+FATE_ACODEC-$(call ENCDEC, WAVPACK, WV) += fate-acodec-wavpack
+fate-acodec-wavpack: FMT = wv
+fate-acodec-wavpack: CODEC = wavpack -compression_level 1
+
+FATE_ACODEC-$(call ENCDEC, TTA, MATROSKA) += fate-acodec-tta
+fate-acodec-tta: FMT = matroska
+
FATE_ACODEC += $(FATE_ACODEC-yes)
$(FATE_ACODEC): tests/data/asynth-44100-2.wav
diff --git a/tests/fate/adpcm.mak b/tests/fate/adpcm.mak
index 7ee62459f0..b64920d4fe 100644
--- a/tests/fate/adpcm.mak
+++ b/tests/fate/adpcm.mak
@@ -1,3 +1,9 @@
+FATE_ADPCM-$(call DEMDEC, FOURXM, ADPCM_4XM) += fate-adpcm-4xm
+fate-adpcm-4xm: CMD = framecrc -i $(TARGET_SAMPLES)/4xm/dracula.4xm -vn -map 0:6
+
+FATE_ADPCM-$(call DEMDEC, AST, ADPCM_AFC) += fate-adpcm-afc
+fate-adpcm-afc: CMD = framecrc -i $(TARGET_SAMPLES)/ast/demo11_02_partial.ast
+
FATE_ADPCM-$(call DEMDEC, WAV, ADPCM_CT) += fate-adpcm-creative
fate-adpcm-creative: CMD = md5 -i $(TARGET_SAMPLES)/creative/intro-partial.wav -f s16le
@@ -10,6 +16,9 @@ fate-adpcm-creative-8-2.6bit: CMD = md5 -i $(TARGET_SAMPLES)/creative/BBC_3BIT.V
FATE_ADPCM-$(call DEMDEC, VOC, ADPCM_SBPRO_4) += fate-adpcm-creative-8-4bit
fate-adpcm-creative-8-4bit: CMD = md5 -i $(TARGET_SAMPLES)/creative/BBC_4BIT.VOC -f s16le
+FATE_ADPCM-$(call DEMDEC, ADP, ADPCM_DTK) += fate-adpcm-dtk
+fate-adpcm-dtk: CMD = framecrc -i $(TARGET_SAMPLES)/adp/shakespr_partial.adp -f s16le
+
FATE_ADPCM-$(call DEMDEC, EA, ADPCM_EA) += fate-adpcm-ea-1
fate-adpcm-ea-1: CMD = framecrc -i $(TARGET_SAMPLES)/ea-wve/networkBackbone-partial.wve -frames:a 26 -vn
@@ -49,6 +58,12 @@ fate-adpcm-ima-ea-sead: CMD = framecrc -i $(TARGET_SAMPLES)/ea-tgv/INTEL_S.TGV -
FATE_ADPCM-$(call DEMDEC, ISS, ADPCM_IMA_ISS) += fate-adpcm-ima-iss
fate-adpcm-ima-iss: CMD = md5 -i $(TARGET_SAMPLES)/funcom-iss/0004010100.iss -f s16le
+FATE_ADPCM-$(call DEMDEC, WAV, ADPCM_IMA_OKI) += fate-adpcm-ima-oki
+fate-adpcm-ima-oki: CMD = md5 -i $(TARGET_SAMPLES)/oki/test.wav -f s16le
+
+FATE_ADPCM-$(call DEMDEC, RSD, ADPCM_IMA_RAD) += fate-adpcm-ima-rad
+fate-adpcm-ima-rad: CMD = md5 -i $(TARGET_SAMPLES)/rsd/hit_run_partial.rsd -f s16le
+
FATE_ADPCM-$(call DEMDEC, SMJPEG, ADPCM_IMA_SMJPEG) += fate-adpcm-ima-smjpeg
fate-adpcm-ima-smjpeg: CMD = framecrc -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -vn
diff --git a/tests/fate/atrac.mak b/tests/fate/atrac.mak
index 94dbe3809b..0a086d8fba 100644
--- a/tests/fate/atrac.mak
+++ b/tests/fate/atrac.mak
@@ -16,11 +16,22 @@ fate-atrac3-3: REF = $(SAMPLES)/atrac3/mc_sich_at3_132_small.pcm
FATE_ATRAC3-$(call DEMDEC, WAV, ATRAC3) += $(FATE_ATRAC3)
-FATE_ATRAC_ALL = $(FATE_ATRAC1-yes) $(FATE_ATRAC3-yes)
+FATE_ATRAC3P += fate-atrac3p-1
+fate-atrac3p-1: CMD = pcm -i $(TARGET_SAMPLES)/atrac3p/at3p_sample1.oma
+fate-atrac3p-1: REF = $(SAMPLES)/atrac3p/at3p_sample1.pcm
+
+FATE_ATRAC3P += fate-atrac3p-2
+fate-atrac3p-2: CMD = pcm -i $(TARGET_SAMPLES)/atrac3p/sonateno14op27-2-cut.aa3
+fate-atrac3p-2: REF = $(SAMPLES)/atrac3p/sonateno14op27-2-cut.pcm
+
+FATE_ATRAC3P-$(call DEMDEC, OMA, ATRAC3P) += $(FATE_ATRAC3P)
+
+FATE_ATRAC_ALL = $(FATE_ATRAC1-yes) $(FATE_ATRAC3-yes) $(FATE_ATRAC3P-yes)
$(FATE_ATRAC_ALL): CMP = oneoff
FATE_SAMPLES_AVCONV += $(FATE_ATRAC_ALL)
-fate-atrac: $(FATE_ATRAC_ALL)
-fate-atrac3: $(FATE_ATRAC3-yes)
+fate-atrac: $(FATE_ATRAC_ALL)
+fate-atrac3: $(FATE_ATRAC3-yes)
+fate-atrac3p: $(FATE_ATRAC3P-yes)
diff --git a/tests/fate/audio.mak b/tests/fate/audio.mak
index bc107c5017..7ab4038ca9 100644
--- a/tests/fate/audio.mak
+++ b/tests/fate/audio.mak
@@ -10,10 +10,10 @@ fate-binkaudio-rdft: FUZZ = 2
$(FATE_BINKAUDIO-yes): CMP = oneoff
-FATE_SAMPLES_AVCONV += $(FATE_BINKAUDIO-yes)
+FATE_SAMPLES_AUDIO += $(FATE_BINKAUDIO-yes)
fate-binkaudio: $(FATE_BINKAUDIO-yes)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, BMV, BMV_AUDIO) += fate-bmv-audio
+FATE_SAMPLES_AUDIO-$(call DEMDEC, BMV, BMV_AUDIO) += fate-bmv-audio
fate-bmv-audio: CMD = framecrc -i $(TARGET_SAMPLES)/bmv/SURFING-partial.BMV -vn
FATE_DCA-$(CONFIG_MPEGTS_DEMUXER) += fate-dca-core
@@ -26,37 +26,56 @@ fate-dca-xll: CMD = pcm -disable_xll 0 -i $(TARGET_SAMPLES)/dts/master_audio_7.1
fate-dca-xll: CMP = oneoff
fate-dca-xll: REF = $(SAMPLES)/dts/master_audio_7.1_24bit.pcm
-FATE_SAMPLES_AVCONV-$(CONFIG_DCA_DECODER) += $(FATE_DCA-yes)
+FATE_SAMPLES_AUDIO-$(CONFIG_DCA_DECODER) += $(FATE_DCA-yes)
fate-dca: $(FATE_DCA-yes)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, DSICIN, DSICINAUDIO) += fate-delphine-cin-audio
+FATE_SAMPLES_AUDIO-$(call DEMDEC, DSICIN, DSICINAUDIO) += fate-delphine-cin-audio
fate-delphine-cin-audio: CMD = framecrc -i $(TARGET_SAMPLES)/delphine-cin/LOGO-partial.CIN -vn
-FATE_SAMPLES_AVCONV-$(call DEMDEC, DSS, DSS_SP) += fate-dss-lp fate-dss-sp
+FATE_SAMPLES_AUDIO-$(call DEMDEC, DSS, DSS_SP) += fate-dss-lp fate-dss-sp
fate-dss-lp: CMD = framecrc -i $(TARGET_SAMPLES)/dss/lp.dss -frames 30
fate-dss-sp: CMD = framecrc -i $(TARGET_SAMPLES)/dss/sp.dss -frames 30
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, IMC) += fate-imc
+FATE_SAMPLES_AUDIO-$(call DEMDEC, DTS, DCA) += fate-dts_es
+fate-dts_es: CMD = pcm -i $(TARGET_SAMPLES)/dts/dts_es.dts
+fate-dts_es: CMP = oneoff
+fate-dts_es: REF = $(SAMPLES)/dts/dts_es.pcm
+
+FATE_SAMPLES_AUDIO-$(call DEMDEC, AVI, IMC) += fate-imc
fate-imc: CMD = pcm -i $(TARGET_SAMPLES)/imc/imc.avi
fate-imc: CMP = oneoff
fate-imc: REF = $(SAMPLES)/imc/imc.pcm
-FATE_SAMPLES_AVCONV-$(call DEMDEC, FLV, NELLYMOSER) += fate-nellymoser
+FATE_SAMPLES_AUDIO-$(call DEMDEC, FLV, NELLYMOSER) += fate-nellymoser
fate-nellymoser: CMD = pcm -i $(TARGET_SAMPLES)/nellymoser/nellymoser.flv
fate-nellymoser: CMP = oneoff
fate-nellymoser: REF = $(SAMPLES)/nellymoser/nellymoser.pcm
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, ON2AVC) += fate-on2avc
+FATE_SAMPLES_AUDIO-$(call ENCMUX, NELLYMOSER, FLV) += fate-nellymoser-aref-encode
+fate-nellymoser-aref-encode: $(AREF) ./tests/data/asynth-16000-1.wav
+fate-nellymoser-aref-encode: CMD = enc_dec_pcm flv wav s16le $(REF) -c:a nellymoser
+fate-nellymoser-aref-encode: CMP = stddev
+fate-nellymoser-aref-encode: REF = ./tests/data/asynth-16000-1.wav
+fate-nellymoser-aref-encode: CMP_SHIFT = -256
+fate-nellymoser-aref-encode: CMP_TARGET = 3863
+fate-nellymoser-aref-encode: SIZE_TOLERANCE = 268
+
+FATE_SAMPLES_AUDIO-$(call DEMDEC, AVI, ON2AVC) += fate-on2avc
fate-on2avc: CMD = framecrc -i $(TARGET_SAMPLES)/vp7/potter-40.vp7 -frames 30 -vn
-FATE_SAMPLES_AVCONV-$(call DEMDEC, PAF, PAF_AUDIO) += fate-paf-audio
+FATE_SAMPLES_AUDIO-$(call DEMDEC, PAF, PAF_AUDIO) += fate-paf-audio
fate-paf-audio: CMD = framecrc -i $(TARGET_SAMPLES)/paf/hod1-partial.paf -vn
-FATE_SAMPLES_AVCONV-$(call DEMDEC, VMD, VMDAUDIO) += fate-sierra-vmd-audio
+FATE_SAMPLES_AUDIO-$(call DEMDEC, VMD, VMDAUDIO) += fate-sierra-vmd-audio
fate-sierra-vmd-audio: CMD = framecrc -i $(TARGET_SAMPLES)/vmd/12.vmd -vn
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SMACKER, SMACKAUD) += fate-smacker-audio
+FATE_SAMPLES_AUDIO-$(call DEMDEC, SMACKER, SMACKAUD) += fate-smacker-audio
fate-smacker-audio: CMD = framecrc -i $(TARGET_SAMPLES)/smacker/wetlogo.smk -vn
-FATE_SAMPLES_AVCONV-$(call DEMDEC, WSVQA, WS_SND1) += fate-ws_snd
+FATE_SAMPLES_AUDIO-$(call DEMDEC, WSVQA, WS_SND1) += fate-ws_snd
fate-ws_snd: CMD = md5 -i $(TARGET_SAMPLES)/vqa/ws_snd.vqa -f s16le
+
+FATE_SAMPLES_AUDIO += $(FATE_SAMPLES_AUDIO-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_AUDIO)
+fate-audio: $(FATE_SAMPLES_AUDIO)
diff --git a/tests/fate/avformat.mak b/tests/fate/avformat.mak
index 458ae7cae9..1d13434d45 100644
--- a/tests/fate/avformat.mak
+++ b/tests/fate/avformat.mak
@@ -1,22 +1,29 @@
FATE_LAVF-$(call ENCDEC, PCM_S16BE, AIFF) += aiff
FATE_LAVF-$(call ENCDEC, PCM_ALAW, PCM_ALAW) += alaw
FATE_LAVF-$(call ENCDEC2, MSMPEG4V3, MP2, ASF) += asf
+FATE_LAVF-$(call ENCDEC, PCM_S16BE_PLANAR, AST) += ast
FATE_LAVF-$(call ENCDEC, PCM_S16BE, AU) += au
FATE_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi
FATE_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp
+FATE_LAVF-$(call ENCDEC, PCM_S16BE, CAF) += caf
FATE_LAVF-$(call ENCDEC, DPX, IMAGE2) += dpx
FATE_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt
+FATE_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm
+FATE_LAVF-$(call ENCDEC, RAWVIDEO, FILMSTRIP) += flm
FATE_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt
FATE_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif
FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf
+FATE_LAVF-$(call ENCDEC, PCM_S16LE, IRCAM) += ircam
FATE_LAVF-$(call ENCDEC, MJPEG, IMAGE2) += jpg
FATE_LAVF-$(call ENCDEC2, MPEG4, MP2, MATROSKA) += mkv
FATE_LAVF-$(call ENCDEC, ADPCM_YAMAHA, MMF) += mmf
-FATE_LAVF-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov
+FATE_LAVF-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov ismv
FATE_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, MPEG1SYSTEM MPEGPS) += mpg
FATE_LAVF-$(call ENCDEC, PCM_MULAW, PCM_MULAW) += mulaw
FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += mxf
FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF_D10 MXF) += mxf_d10
+FATE_LAVF-$(call ENCDEC2, DNXHD, PCM_S16LE, MXF_OPATOM MXF) += mxf_opatom
+FATE_LAVF-$(call ENCDEC2, DNXHD, PCM_S16LE, MXF_OPATOM MXF) += mxf_opatom_audio
FATE_LAVF-$(call ENCDEC2, MPEG4, MP2, NUT) += nut
FATE_LAVF-$(call ENCDEC, FLAC, OGG) += ogg
FATE_LAVF-$(call ENCDEC, PAM, IMAGE2) += pam
@@ -30,6 +37,7 @@ FATE_LAVF-$(call ENCDEC, PPM, IMAGE2PIPE) += ppmpipe
FATE_LAVF-$(call ENCMUX, RV10 AC3_FIXED, RM) += rm
FATE_LAVF-$(call ENCDEC, PCM_U8, RSO) += rso
FATE_LAVF-$(call ENCDEC, SGI, IMAGE2) += sgi
+FATE_LAVF-$(call ENCMUX, MJPEG PCM_S16LE, SMJPEG) += smjpeg
FATE_LAVF-$(call ENCDEC, PCM_S16LE, SOX) += sox
FATE_LAVF-$(call ENCDEC, SUNRAST, IMAGE2) += sunrast
FATE_LAVF-$(call ENCDEC, FLV, SWF) += swf
@@ -39,14 +47,30 @@ FATE_LAVF-$(call ENCDEC2, MPEG2VIDEO, MP2, MPEGTS) += ts
FATE_LAVF-$(call ENCDEC, PCM_U8, VOC) += voc
FATE_LAVF-$(call ENCDEC, PCM_S16LE, VOC) += voc_s16
FATE_LAVF-$(call ENCDEC, PCM_S16LE, WAV) += wav
+FATE_LAVF-$(call ENCDEC, PCM_S16LE, WAV) += wav_peak
+FATE_LAVF-$(call ENCDEC, PCM_S16LE, WAV) += wav_peak_only
+FATE_LAVF-$(call ENCMUX, PCM_S16LE, W64) += w64
+FATE_LAVF-$(call ENCDEC, MP2, WTV) += wtv
+FATE_LAVF-$(call ENCDEC, XBM, IMAGE2) += xbm
FATE_LAVF-$(call ENCDEC, XWD, IMAGE2) += xwd
FATE_LAVF-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg
FATE_LAVF += $(FATE_LAVF-yes:%=fate-lavf-%)
-FATE_LAVF += fate-lavf-pixfmt
+FATE_LAVF_PIXFMT-$(CONFIG_SCALE_FILTER) += fate-lavf-pixfmt
+FATE_LAVF += $(FATE_LAVF_PIXFMT-yes)
$(FATE_LAVF): $(AREF) $(VREF)
$(FATE_LAVF): CMD = lavftest
FATE_AVCONV += $(FATE_LAVF)
fate-lavf: $(FATE_LAVF)
+
+FATE_LAVF_FATE-$(call ALLYES, MATROSKA_DEMUXER OGG_MUXER) += ogg_vp3
+FATE_LAVF_FATE-$(call ALLYES, MOV_DEMUXER LATM_MUXER) += latm
+FATE_LAVF_FATE-$(call ALLYES, MP3_DEMUXER MP3_MUXER) += mp3
+
+FATE_LAVF_FATE += $(FATE_LAVF_FATE-yes:%=fate-lavf-fate-%)
+$(FATE_LAVF_FATE): CMD = lavffatetest
+
+FATE_SAMPLES_FFMPEG += $(FATE_LAVF_FATE)
+fate-lavf-fate: $(FATE_LAVF_FATE)
diff --git a/tests/fate/cover-art.mak b/tests/fate/cover-art.mak
index 54dc0ba777..721c650b78 100644
--- a/tests/fate/cover-art.mak
+++ b/tests/fate/cover-art.mak
@@ -1,35 +1,38 @@
-FATE_COVER_ART += fate-cover-art-ape
+FATE_COVER_ART-$(CONFIG_APE_DEMUXER) += fate-cover-art-ape
fate-cover-art-ape: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/luckynight_cover.ape -an -c:v copy -f rawvideo
fate-cover-art-ape: REF = 45333c983c45af54449dff10af144317
-FATE_COVER_ART += fate-cover-art-flac
+FATE_COVER_ART-$(CONFIG_FLAC_DEMUXER) += fate-cover-art-flac
fate-cover-art-flac: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/cover_art.flac -an -c:v copy -f rawvideo
fate-cover-art-flac: REF = 0de1fc6200596fa32b8f7300a14c0261
-FATE_COVER_ART += fate-cover-art-m4a
+FATE_COVER_ART-$(CONFIG_MOV_DEMUXER) += fate-cover-art-m4a
fate-cover-art-m4a: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/Owner-iTunes_9.0.3.15.m4a -an -c:v copy -f rawvideo
fate-cover-art-m4a: REF = 08ba70a3b594ff6345a93965e96a9d3e
-FATE_COVER_ART += fate-cover-art-ogg
-fate-cover-art-ogg: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/ogg_vorbiscomment_cover.opus -an -c:v copy -f rawvideo
-fate-cover-art-ogg: REF = b796d33363dbfed1868523b5c751b7b1
+FATE_COVER_ART-$(CONFIG_OGG_DEMUXER) += fate-cover-art-ogg
+fate-cover-art-ogg: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/ogg_vorbiscomment_cover.opus -map 0:v -c:v copy -f rawvideo
+fate-cover-art-ogg: REF = 7f117e073620eabb4ed02680cf70af41
-FATE_COVER_ART += fate-cover-art-wma
+FATE_COVER_ART-$(CONFIG_ASF_DEMUXER) += fate-cover-art-wma
fate-cover-art-wma: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/Californication_cover.wma -an -c:v copy -f rawvideo
fate-cover-art-wma: REF = 0808bd0e1b61542a16e1906812dd924b
-FATE_COVER_ART += fate-cover-art-wma-id3
+FATE_COVER_ART-$(CONFIG_ASF_DEMUXER) += fate-cover-art-wma-id3
fate-cover-art-wma-id3: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/wma_with_ID3_APIC_trimmed.wma -an -c:v copy -f rawvideo
fate-cover-art-wma-id3: REF = e6a8dd03687d5178bc13fc7d3316696e
-FATE_COVER_ART += fate-cover-art-wma-metadatalib
+FATE_COVER_ART-$(CONFIG_ASF_DEMUXER) += fate-cover-art-wma-metadatalib
fate-cover-art-wma-metadatalib: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/wma_with_metadata_library_object_tag_trimmed.wma -map 0:v -c:v copy -f rawvideo
fate-cover-art-wma-metadatalib: REF = 32e8bd4fad546f63d881a0256f083aea
-FATE_COVER_ART += fate-cover-art-wv
+FATE_COVER_ART-$(CONFIG_WV_DEMUXER) += fate-cover-art-wv
fate-cover-art-wv: CMD = md5 -i $(TARGET_SAMPLES)/cover_art/luckynight_cover.wv -an -c:v copy -f rawvideo
fate-cover-art-wv: REF = 45333c983c45af54449dff10af144317
+FCA_TEMP-$(call ALLYES, RAWVIDEO_MUXER FILE_PROTOCOL) = $(FATE_COVER_ART-yes)
+FATE_COVER_ART = $(FCA_TEMP-yes)
+
$(FATE_COVER_ART): CMP = oneline
FATE_SAMPLES_AVCONV += $(FATE_COVER_ART)
fate-cover-art: $(FATE_COVER_ART)
diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak
index 2446b90b03..0eccc9b3c7 100644
--- a/tests/fate/demux.mak
+++ b/tests/fate/demux.mak
@@ -1,71 +1,117 @@
-FATE_SAMPLES_AVCONV-$(CONFIG_AAC_DEMUXER) += fate-adts-demux
+FATE_SAMPLES_DEMUX-$(call DEMDEC, AVI, FRAPS) += fate-avio-direct
+fate-avio-direct: CMD = framecrc -avioflags direct -i $(TARGET_SAMPLES)/fraps/fraps-v5-bouncing-balls-partial.avi -avioflags direct
+
+FATE_SAMPLES_DEMUX-$(CONFIG_AAC_DEMUXER) += fate-adts-demux
fate-adts-demux: CMD = crc -i $(TARGET_SAMPLES)/aac/ct_faac-adts.aac -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_AEA_DEMUXER) += fate-aea-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_AEA_DEMUXER) += fate-aea-demux
fate-aea-demux: CMD = crc -i $(TARGET_SAMPLES)/aea/chirp.aea -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_BINK_DEMUXER) += fate-bink-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_AST_DEMUXER) += fate-ast
+fate-ast: CMD = crc -i $(TARGET_SAMPLES)/ast/demo11_02_partial.ast -c copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_BINK_DEMUXER) += fate-bink-demux
fate-bink-demux: CMD = crc -i $(TARGET_SAMPLES)/bink/Snd0a7d9b58.dee -vn -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_CAF_DEMUXER) += fate-caf
+FATE_SAMPLES_DEMUX-$(CONFIG_BRSTM_DEMUXER) += fate-brstm
+fate-brstm: CMD = crc -i $(TARGET_SAMPLES)/brstm/lozswd_partial.brstm -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_CAF_DEMUXER) += fate-caf
fate-caf: CMD = crc -i $(TARGET_SAMPLES)/caf/caf-pcm16.caf -c copy
-FATE_SAMPLES_AVCONV-$(CONFIG_CDXL_DEMUXER) += fate-cdxl-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_CDXL_DEMUXER) += fate-cdxl-demux
fate-cdxl-demux: CMD = framecrc -i $(TARGET_SAMPLES)/cdxl/mirage.cdxl -vcodec copy -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_DAUD_DEMUXER) += fate-d-cinema-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_CINE_DEMUXER) += fate-cine-demux
+fate-cine-demux: CMD = crc -i $(TARGET_SAMPLES)/cine/bayer_gbrg8.cine -c copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_DAUD_DEMUXER) += fate-d-cinema-demux
fate-d-cinema-demux: CMD = framecrc -i $(TARGET_SAMPLES)/d-cinema/THX_Science_FLT_1920-partial.302 -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_IV8_DEMUXER) += fate-iv8-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_GIF_DEMUXER) += fate-gif-demux
+fate-gif-demux: CMD = framecrc -i $(TARGET_SAMPLES)/gif/Newtons_cradle_animation_book_2.gif -vcodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_IV8_DEMUXER) += fate-iv8-demux
fate-iv8-demux: CMD = framecrc -i $(TARGET_SAMPLES)/iv8/zzz-partial.mpg -vcodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_LMLM4_DEMUXER) += fate-lmlm4-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_JV_DEMUXER) += fate-jv-demux
+fate-jv-demux: CMD = framecrc -i $(TARGET_SAMPLES)/jv/intro.jv -vcodec copy -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_LMLM4_DEMUXER) += fate-lmlm4-demux
fate-lmlm4-demux: CMD = framecrc -i $(TARGET_SAMPLES)/lmlm4/LMLM4_CIFat30fps.divx -t 3 -acodec copy -vcodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_XA_DEMUXER) += fate-maxis-xa
+FATE_SAMPLES_DEMUX-$(CONFIG_XA_DEMUXER) += fate-maxis-xa
fate-maxis-xa: CMD = framecrc -i $(TARGET_SAMPLES)/maxis-xa/SC2KBUG.XA -frames:a 30 -c:a copy
-FATE_SAMPLES_AVCONV-$(CONFIG_MTV_DEMUXER) += fate-mtv
+FATE_SAMPLES_DEMUX-$(call DEMDEC, MATROSKA, H264) += fate-mkv
+fate-mkv: CMD = framecrc -i $(TARGET_SAMPLES)/mkv/test7_cut.mkv -c copy
+
+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_MTV_DEMUXER) += fate-mtv
fate-mtv: CMD = framecrc -i $(TARGET_SAMPLES)/mtv/comedian_auto-partial.mtv -c copy
-FATE_SAMPLES_AVCONV-$(CONFIG_MXF_DEMUXER) += fate-mxf-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_MXF_DEMUXER) += fate-mxf-demux
fate-mxf-demux: CMD = framecrc -i $(TARGET_SAMPLES)/mxf/C0023S01.mxf -acodec copy -vcodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_NC_DEMUXER) += fate-nc-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_NC_DEMUXER) += fate-nc-demux
fate-nc-demux: CMD = framecrc -i $(TARGET_SAMPLES)/nc-camera/nc-sample-partial -vcodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_NSV_DEMUXER) += fate-nsv-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_NISTSPHERE_DEMUXER) += fate-nistsphere-demux
+fate-nistsphere-demux: CMD = crc -i $(TARGET_SAMPLES)/nistsphere/nist-ulaw.nist -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_NSV_DEMUXER) += fate-nsv-demux
fate-nsv-demux: CMD = framecrc -i $(TARGET_SAMPLES)/nsv/witchblade-51kbps.nsv -t 6 -vcodec copy -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_OMA_DEMUXER) += fate-oma-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_OGG_DEMUXER) += fate-oggvp8-demux
+fate-oggvp8-demux: CMD = framecrc -i $(TARGET_SAMPLES)/ogg/videotest.ogv -c:v copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_OMA_DEMUXER) += fate-oma-demux
fate-oma-demux: CMD = crc -i $(TARGET_SAMPLES)/oma/01-Untitled-partial.oma -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_STR_DEMUXER) += fate-psx-str-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_PAF_DEMUXER) += fate-paf-demux
+fate-paf-demux: CMD = framecrc -i $(TARGET_SAMPLES)/paf/hod1-partial.paf -vcodec copy -acodec copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_PMP_DEMUXER) += fate-pmp-demux
+fate-pmp-demux: CMD = framecrc -i $(TARGET_SAMPLES)/pmp/demo.pmp -vn -c:a copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_RSD_DEMUXER) += fate-rsd-demux
+fate-rsd-demux: CMD = crc -i $(TARGET_SAMPLES)/rsd/hum01_partial.rsd -c:a copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_REDSPARK_DEMUXER) += fate-redspark-demux
+fate-redspark-demux: CMD = crc -i $(TARGET_SAMPLES)/redspark/jingle04_partial.rsd -c:a copy
+
+FATE_SAMPLES_DEMUX-$(CONFIG_STR_DEMUXER) += fate-psx-str-demux
fate-psx-str-demux: CMD = framecrc -i $(TARGET_SAMPLES)/psx-str/descent-partial.str -c copy
-FATE_SAMPLES_AVCONV-$(CONFIG_PVA_DEMUXER) += fate-pva-demux
-fate-pva-demux: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/pva/PVA_test-partial.pva -t 0.6 -acodec copy -vn
+FATE_SAMPLES_DEMUX-$(CONFIG_PVA_DEMUXER) += fate-pva-demux
+fate-pva-demux: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/pva/PVA_test-partial.pva -t 0.6 -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_QCP_DEMUXER) += fate-qcp-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_QCP_DEMUXER) += fate-qcp-demux
fate-qcp-demux: CMD = crc -i $(TARGET_SAMPLES)/qcp/0036580847.QCP -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_R3D_DEMUXER) += fate-redcode-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_R3D_DEMUXER) += fate-redcode-demux
fate-redcode-demux: CMD = framecrc -i $(TARGET_SAMPLES)/r3d/4MB-sample.r3d -vcodec copy -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_SIFF_DEMUXER) += fate-siff-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_SIFF_DEMUXER) += fate-siff-demux
fate-siff-demux: CMD = framecrc -i $(TARGET_SAMPLES)/SIFF/INTRO_B.VB -c copy
-FATE_SAMPLES_AVCONV-$(CONFIG_SMJPEG_DEMUXER) += fate-smjpeg-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_SMJPEG_DEMUXER) += fate-smjpeg-demux
fate-smjpeg-demux: CMD = framecrc -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -c copy
-FATE_SAMPLES_AVCONV-$(CONFIG_WSAUD_DEMUXER) += fate-westwood-aud
+FATE_SAMPLES_DEMUX-$(CONFIG_WSAUD_DEMUXER) += fate-westwood-aud
fate-westwood-aud: CMD = framecrc -i $(TARGET_SAMPLES)/westwood-aud/excellent.aud -c copy
-FATE_SAMPLES_AVCONV-$(CONFIG_WTV_DEMUXER) += fate-wtv-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_WTV_DEMUXER) += fate-wtv-demux
fate-wtv-demux: CMD = framecrc -i $(TARGET_SAMPLES)/wtv/law-and-order-partial.wtv -vcodec copy -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_XMV_DEMUXER) += fate-xmv-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_XMV_DEMUXER) += fate-xmv-demux
fate-xmv-demux: CMD = framecrc -i $(TARGET_SAMPLES)/xmv/logos1p.fmv -vcodec copy -acodec copy
-FATE_SAMPLES_AVCONV-$(CONFIG_XWMA_DEMUXER) += fate-xwma-demux
+FATE_SAMPLES_DEMUX-$(CONFIG_XWMA_DEMUXER) += fate-xwma-demux
fate-xwma-demux: CMD = crc -i $(TARGET_SAMPLES)/xwma/ergon.xwma -acodec copy
+
+FATE_SAMPLES_DEMUX += $(FATE_SAMPLES_DEMUX-yes)
+FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_DEMUX)
+fate-demux: $(FATE_SAMPLES_DEMUX)
diff --git a/tests/fate/ea.mak b/tests/fate/ea.mak
index 2bffd47b70..9de671ce6b 100644
--- a/tests/fate/ea.mak
+++ b/tests/fate/ea.mak
@@ -1,13 +1,13 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA_CDATA, ADPCM_EA_XAS) += fate-ea-cdata
+FATE_SAMPLES_EA-$(call DEMDEC, EA_CDATA, ADPCM_EA_XAS) += fate-ea-cdata
fate-ea-cdata: CMD = md5 -i $(TARGET_SAMPLES)/ea-cdata/166b084d.46410f77.0009b440.24be960c.cdata -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA, EACMV) += fate-ea-cmv
+FATE_SAMPLES_EA-$(call DEMDEC, EA, EACMV) += fate-ea-cmv
fate-ea-cmv: CMD = framecrc -i $(TARGET_SAMPLES)/ea-cmv/TITLE.CMV -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA, EAMAD) += fate-ea-mad
+FATE_SAMPLES_EA-$(call DEMDEC, EA, EAMAD) += fate-ea-mad
fate-ea-mad: CMD = framecrc -i $(TARGET_SAMPLES)/ea-mad/NFS6LogoE.mad -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA, EATGQ) += fate-ea-tgq
+FATE_SAMPLES_EA-$(call DEMDEC, EA, EATGQ) += fate-ea-tgq
fate-ea-tgq: CMD = framecrc -i $(TARGET_SAMPLES)/ea-tgq/v27.tgq -an
FATE_EA_TGV += fate-ea-tgv-1
@@ -16,8 +16,11 @@ fate-ea-tgv-1: CMD = framecrc -i $(TARGET_SAMPLES)/ea-tgv/INTRO8K-partial.TGV -p
FATE_EA_TGV += fate-ea-tgv-2
fate-ea-tgv-2: CMD = framecrc -i $(TARGET_SAMPLES)/ea-tgv/INTEL_S.TGV -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA, EATGV) += $(FATE_EA_TGV)
+FATE_SAMPLES_EA-$(call DEMDEC, EA, EATGV) += $(FATE_EA_TGV)
fate-ea-tgv: $(FATE_EA_TGV)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA, EATQI) += fate-ea-tqi
+FATE_SAMPLES_EA-$(call DEMDEC, EA, EATQI) += fate-ea-tqi
fate-ea-tqi: CMD = framecrc -i $(TARGET_SAMPLES)/ea-wve/networkBackbone-partial.wve -frames:v 26 -an
+
+FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_EA-yes)
+fate-ea: $(FATE_SAMPLES_EA-yes)
diff --git a/tests/fate/exif.mak b/tests/fate/exif.mak
new file mode 100644
index 0000000000..da5dae8d5e
--- /dev/null
+++ b/tests/fate/exif.mak
@@ -0,0 +1,18 @@
+# test exif metadata in TIFF images
+FATE_SAMPLES_EXIF-$(call DEMDEC, IMAGE2, TIFF) += fate-exif-image-tiff
+fate-exif-image-tiff: CMD = probeframes $(TARGET_SAMPLES)/exif/image_small.tiff
+
+# test exif metadata in JPG images
+FATE_SAMPLES_EXIF-$(call DEMDEC, IMAGE2, MJPEG) += fate-exif-image-jpg
+fate-exif-image-jpg: CMD = probeframes $(TARGET_SAMPLES)/exif/image_small.jpg
+
+# test exif metadata in WebP images
+FATE_SAMPLES_EXIF-$(call DEMDEC, IMAGE2, WEBP) += fate-exif-image-webp
+fate-exif-image-webp: CMD = probeframes $(TARGET_SAMPLES)/exif/image_small.webp
+
+# test exif metadata in MP3 with embedded JPEG images
+FATE_SAMPLES_EXIF-$(call ALLYES, MP3_DEMUXER IMAGE2_DEMUXER MJPEG_DECODER) += fate-exif-image-embedded
+fate-exif-image-embedded: CMD = probeframes $(TARGET_SAMPLES)/exif/embedded_small.mp3
+
+# add all -yes targets to the tested targets
+FATE_SAMPLES_FFPROBE += $(FATE_SAMPLES_EXIF-yes)
diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
new file mode 100644
index 0000000000..6af1081eb7
--- /dev/null
+++ b/tests/fate/ffmpeg.mak
@@ -0,0 +1,48 @@
+FATE_MAPCHAN-$(CONFIG_CHANNELMAP_FILTER) += fate-mapchan-6ch-extract-2
+fate-mapchan-6ch-extract-2: tests/data/asynth-22050-6.wav
+fate-mapchan-6ch-extract-2: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-22050-6.wav -map_channel 0.0.0 -flags +bitexact -f wav md5: -map_channel 0.0.1 -flags +bitexact -f wav md5:
+
+FATE_MAPCHAN-$(CONFIG_CHANNELMAP_FILTER) += fate-mapchan-6ch-extract-2-downmix-mono
+fate-mapchan-6ch-extract-2-downmix-mono: tests/data/asynth-22050-6.wav
+fate-mapchan-6ch-extract-2-downmix-mono: CMD = md5 -i $(TARGET_PATH)/tests/data/asynth-22050-6.wav -map_channel 0.0.1 -map_channel 0.0.0 -ac 1 -flags +bitexact -f wav
+
+FATE_MAPCHAN-$(CONFIG_CHANNELMAP_FILTER) += fate-mapchan-silent-mono
+fate-mapchan-silent-mono: tests/data/asynth-22050-1.wav
+fate-mapchan-silent-mono: CMD = md5 -i $(TARGET_PATH)/tests/data/asynth-22050-1.wav -map_channel -1 -map_channel 0.0.0 -flags +bitexact -f wav
+
+FATE_MAPCHAN = $(FATE_MAPCHAN-yes)
+
+FATE_FFMPEG += $(FATE_MAPCHAN)
+fate-mapchan: $(FATE_MAPCHAN)
+
+FATE_FFMPEG-$(CONFIG_COLOR_FILTER) += fate-ffmpeg-filter_complex
+fate-ffmpeg-filter_complex: CMD = framecrc -filter_complex color=d=1:r=5
+
+FATE_FFMPEG-$(CONFIG_COLOR_FILTER) += fate-ffmpeg-lavfi
+fate-ffmpeg-lavfi: CMD = framecrc -lavfi color=d=1:r=5
+
+FATE_SAMPLES_FFMPEG-$(CONFIG_RAWVIDEO_DEMUXER) += fate-force_key_frames
+fate-force_key_frames: tests/data/vsynth_lena.yuv
+fate-force_key_frames: CMD = enc_dec \
+ "rawvideo -s 352x288 -pix_fmt yuv420p" tests/data/vsynth_lena.yuv \
+ avi "-c mpeg4 -g 240 -qscale 10 -force_key_frames 0.5,0:00:01.5" \
+ framecrc "" "" "-skip_frame nokey"
+
+FATE_SAMPLES_FFMPEG-$(call ALLYES, VOBSUB_DEMUXER DVDSUB_DECODER AVFILTER OVERLAY_FILTER DVDSUB_ENCODER) += fate-sub2video
+fate-sub2video: tests/data/vsynth_lena.yuv
+fate-sub2video: CMD = framecrc \
+ -f rawvideo -r 5 -s 352x288 -pix_fmt yuv420p -i $(TARGET_PATH)/tests/data/vsynth_lena.yuv \
+ -ss 132 -i $(TARGET_SAMPLES)/sub/vobsub.idx \
+ -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:0]scale=720:480[v]\;[v][1:0]overlay[v2]" \
+ -map "[v2]" -c:v rawvideo -map 1:s -c:s dvdsub
+
+FATE_FFMPEG-$(call ALLYES, PCM_S16LE_DEMUXER PCM_S16LE_MUXER PCM_S16LE_DECODER PCM_S16LE_ENCODER) += fate-unknown_layout-pcm
+fate-unknown_layout-pcm: $(AREF)
+fate-unknown_layout-pcm: CMD = md5 \
+ -guess_layout_max 0 -f s16le -ac 1 -ar 44100 -i $(TARGET_PATH)/$(AREF) -f s16le
+
+FATE_FFMPEG-$(call ALLYES, PCM_S16LE_DEMUXER AC3_MUXER PCM_S16LE_DECODER AC3_FIXED_ENCODER) += fate-unknown_layout-ac3
+fate-unknown_layout-ac3: $(AREF)
+fate-unknown_layout-ac3: CMD = md5 \
+ -guess_layout_max 0 -f s16le -ac 1 -ar 44100 -i $(TARGET_PATH)/$(AREF) \
+ -f ac3 -flags +bitexact -c ac3_fixed
diff --git a/tests/fate/ffprobe.mak b/tests/fate/ffprobe.mak
new file mode 100644
index 0000000000..cf20185960
--- /dev/null
+++ b/tests/fate/ffprobe.mak
@@ -0,0 +1,33 @@
+FFPROBE_TEST_FILE=tests/data/ffprobe-test.nut
+FFPROBE_COMMAND=ffprobe$(EXESUF) -show_streams -show_packets -show_format -show_frames -bitexact $(FFPROBE_TEST_FILE)
+
+FATE_FFPROBE += fate-ffprobe_compact
+fate-ffprobe_compact: $(FFPROBE_TEST_FILE)
+fate-ffprobe_compact: CMD = run $(FFPROBE_COMMAND) -of compact
+
+FATE_FFPROBE += fate-ffprobe_csv
+fate-ffprobe_csv: $(FFPROBE_TEST_FILE)
+fate-ffprobe_csv: CMD = run $(FFPROBE_COMMAND) -of csv
+
+FATE_FFPROBE += fate-ffprobe_default
+fate-ffprobe_default: $(FFPROBE_TEST_FILE)
+fate-ffprobe_default: CMD = run $(FFPROBE_COMMAND) -of default
+
+FATE_FFPROBE += fate-ffprobe_flat
+fate-ffprobe_flat: $(FFPROBE_TEST_FILE)
+fate-ffprobe_flat: CMD = run $(FFPROBE_COMMAND) -of flat
+
+FATE_FFPROBE += fate-ffprobe_ini
+fate-ffprobe_ini: $(FFPROBE_TEST_FILE)
+fate-ffprobe_ini: CMD = run $(FFPROBE_COMMAND) -of ini
+
+FATE_FFPROBE += fate-ffprobe_json
+fate-ffprobe_json: $(FFPROBE_TEST_FILE)
+fate-ffprobe_json: CMD = run $(FFPROBE_COMMAND) -of json
+
+FATE_FFPROBE += fate-ffprobe_xml
+fate-ffprobe_xml: $(FFPROBE_TEST_FILE)
+fate-ffprobe_xml: CMD = run $(FFPROBE_COMMAND) -of xml
+
+fate-ffprobe: $(FATE_FFPROBE)
+
diff --git a/tests/fate/fft.mak b/tests/fate/fft.mak
index d2a390404b..9fdca2b3e2 100644
--- a/tests/fate/fft.mak
+++ b/tests/fate/fft.mak
@@ -38,5 +38,22 @@ $(FATE_FFT_FIXED-yes): libavcodec/fft-fixed-test$(EXESUF)
$(FATE_FFT_FIXED-yes): CMD = run libavcodec/fft-fixed-test $(CPUFLAGS:%=-c%) $(ARGS)
$(FATE_FFT_FIXED-yes): REF = /dev/null
-FATE-$(CONFIG_AVCODEC) += $(FATE_FFT-yes) $(FATE_FFT_FIXED-yes)
-fate-fft: $(FATE_FFT-yes) $(FATE_FFT_FIXED-yes)
+define DEF_FFT_FIXED32
+FATE_FFT_FIXED32 += fate-fft-fixed32-$(1) fate-ifft-fixed32-$(1) \
+ fate-mdct-fixed32-$(1) fate-imdct-fixed32-$(1)
+
+fate-fft-fixed32-$(1): ARGS = -n$(1)
+fate-ifft-fixed32-$(1): ARGS = -n$(1) -i
+#fate-mdct-fixed32-$(1): ARGS = -n$(1) -m
+fate-imdct-fixed32-$(1): ARGS = -n$(1) -m -i
+endef
+
+$(foreach N, 4 5 6 7 8 9 10 11 12, $(eval $(call DEF_FFT_FIXED32,$(N))))
+
+fate-fft-fixed32-test: $(FATE_FFT_FIXED32)
+$(FATE_FFT_FIXED32): libavcodec/fft-fixed32-test$(EXESUF)
+$(FATE_FFT_FIXED32): CMD = run libavcodec/fft-fixed32-test $(CPUFLAGS:%=-c%) $(ARGS)
+$(FATE_FFT_FIXED32): REF = /dev/null
+
+FATE-$(call ALLYES, AVCODEC FFT MDCT) += $(FATE_FFT-yes) $(FATE_FFT_FIXED-yes) $(FATE_FFT_FIXED32)
+fate-fft: $(FATE_FFT-yes) $(FATE_FFT_FIXED-yes) $(FATE_FFT_FIXED32)
diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak
index 363ae2e317..210b89eb07 100644
--- a/tests/fate/filter-audio.mak
+++ b/tests/fate/filter-audio.mak
@@ -1,15 +1,20 @@
+FATE_AFILTER-$(call FILTERDEMDECENCMUX, ADELAY, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-adelay
+fate-filter-adelay: tests/data/asynth-44100-2.wav
+fate-filter-adelay: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav
+fate-filter-adelay: CMD = framecrc -i $(SRC) -af adelay=42
+
FATE_AMIX += fate-filter-amix-simple
-fate-filter-amix-simple: CMD = avconv -filter_complex amix -i $(SRC) -ss 3 -i $(SRC1) -f f32le -
+fate-filter-amix-simple: CMD = ffmpeg -filter_complex amix -i $(SRC) -ss 3 -i $(SRC1) -f f32le -
fate-filter-amix-simple: REF = $(SAMPLES)/filter/amix_simple.pcm
FATE_AMIX += fate-filter-amix-first
-fate-filter-amix-first: CMD = avconv -filter_complex amix=duration=first -ss 4 -i $(SRC) -i $(SRC1) -f f32le -
+fate-filter-amix-first: CMD = ffmpeg -filter_complex amix=duration=first -ss 4 -i $(SRC) -i $(SRC1) -f f32le -
fate-filter-amix-first: REF = $(SAMPLES)/filter/amix_first.pcm
FATE_AMIX += fate-filter-amix-transition
fate-filter-amix-transition: tests/data/asynth-44100-2-3.wav
fate-filter-amix-transition: SRC2 = $(TARGET_PATH)/tests/data/asynth-44100-2-3.wav
-fate-filter-amix-transition: CMD = avconv -filter_complex amix=inputs=3:dropout_transition=0.5 -i $(SRC) -ss 2 -i $(SRC1) -ss 4 -i $(SRC2) -f f32le -
+fate-filter-amix-transition: CMD = ffmpeg -filter_complex amix=inputs=3:dropout_transition=0.5 -i $(SRC) -ss 2 -i $(SRC1) -ss 4 -i $(SRC2) -f f32le -
fate-filter-amix-transition: REF = $(SAMPLES)/filter/amix_transition.pcm
FATE_AFILTER-$(call FILTERDEMDECENCMUX, AMIX, WAV, PCM_S16LE, PCM_F32LE, PCM_F32LE) += $(FATE_AMIX)
@@ -23,7 +28,13 @@ FATE_AFILTER-$(call FILTERDEMDECMUX, ASYNCTS, FLV, NELLYMOSER, PCM_S16LE) += fat
fate-filter-asyncts: SRC = $(TARGET_SAMPLES)/nellymoser/nellymoser-discont.flv
fate-filter-asyncts: CMD = pcm -analyzeduration 10000000 -i $(SRC) -af asyncts
fate-filter-asyncts: CMP = oneoff
-fate-filter-asyncts: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm
+fate-filter-asyncts: REF = $(SAMPLES)/nellymoser/nellymoser-discont-async-v3.pcm
+
+FATE_FILTER-$(CONFIG_ARESAMPLE_FILTER) += fate-filter-aresample
+fate-filter-aresample: SRC = $(TARGET_SAMPLES)/nellymoser/nellymoser-discont.flv
+fate-filter-aresample: CMD = pcm -analyzeduration 10000000 -i $(SRC) -af aresample=min_comp=0.001:min_hard_comp=0.1:first_pts=0
+fate-filter-aresample: CMP = oneoff
+fate-filter-aresample: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm
FATE_ATRIM += fate-filter-atrim-duration
fate-filter-atrim-duration: CMD = framecrc -i $(SRC) -af atrim=start=0.1:duration=0.01
@@ -47,7 +58,7 @@ fate-filter-channelmap-one-int: SRC = $(TARGET_PATH)/tests/data/asynth-44100-6.w
fate-filter-channelmap-one-int: tests/data/asynth-44100-6.wav
fate-filter-channelmap-one-int: CMD = md5 -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/channelmap_one_int -f wav -fflags +bitexact
fate-filter-channelmap-one-int: CMP = oneline
-fate-filter-channelmap-one-int: REF = 21f1977c4f9705e2057083f84764e685
+fate-filter-channelmap-one-int: REF = 428b8f9fac6d57147069b97335019ef5
FATE_FILTER_CHANNELMAP += fate-filter-channelmap-one-str
fate-filter-channelmap-one-str: tests/data/filtergraphs/channelmap_one_str
@@ -55,7 +66,7 @@ fate-filter-channelmap-one-str: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.w
fate-filter-channelmap-one-str: tests/data/asynth-44100-2.wav
fate-filter-channelmap-one-str: CMD = md5 -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/channelmap_one_str -f wav -fflags +bitexact
fate-filter-channelmap-one-str: CMP = oneline
-fate-filter-channelmap-one-str: REF = 9fe9bc452282dfd94fd80e9491607a0c
+fate-filter-channelmap-one-str: REF = e788890db6a11c2fb29d7c4229072d49
FATE_AFILTER-$(call FILTERDEMDECENCMUX, CHANNELMAP, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_FILTER_CHANNELMAP)
@@ -72,12 +83,12 @@ fate-filter-join: SRC2 = $(TARGET_PATH)/tests/data/asynth-44100-3.wav
fate-filter-join: tests/data/asynth-44100-2.wav tests/data/asynth-44100-3.wav
fate-filter-join: CMD = md5 -i $(SRC1) -i $(SRC2) -filter_complex join=channel_layout=5 -f s16le
fate-filter-join: CMP = oneline
-fate-filter-join: REF = 409e66fc5ece4ddea4aa16bc47026bb0
+fate-filter-join: REF = 88b0d24a64717ba8635b29e8dac6ecd8
-FATE_AFILTER-$(call FILTERDEMDECENCMUX, VOLUME, WAV, PCM_S16LE, PCM_S16LE, PCM_S16LE) += fate-filter-volume
+FATE_AFILTER-$(call ALLYES, WAV_DEMUXER PCM_S16LE_DECODER PCM_S16LE_ENCODER PCM_S16LE_MUXER APERMS_FILTER VOLUME_FILTER) += fate-filter-volume
fate-filter-volume: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav
fate-filter-volume: tests/data/asynth-44100-2.wav
-fate-filter-volume: CMD = md5 -i $(SRC) -af volume=precision=fixed:volume=0.5 -f s16le
+fate-filter-volume: CMD = md5 -i $(SRC) -af aperms=random,volume=precision=fixed:volume=0.5 -f s16le
fate-filter-volume: CMP = oneline
fate-filter-volume: REF = 4d6ba75ef3e32d305d066b9bc771d6f4
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index 42fb063547..f502c45651 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -1,36 +1,92 @@
-FATE_FILTER-$(call FILTERDEMDEC, DELOGO, RM, RV30) += fate-filter-delogo
-fate-filter-delogo: CMD = framecrc -i $(TARGET_SAMPLES)/real/rv30.rm -vf delogo=show=0:x=290:y=25:w=26:h=16 -an
+FATE_FILTER-$(call ALLYES, PERMS_FILTER DELOGO_FILTER RM_DEMUXER RV30_DECODER) += fate-filter-delogo
+fate-filter-delogo: CMD = framecrc -i $(TARGET_SAMPLES)/real/rv30.rm -vf perms=random,delogo=show=0:x=290:y=25:w=26:h=16 -an
FATE_YADIF += fate-filter-yadif-mode0
-fate-filter-yadif-mode0: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vf yadif=0
+fate-filter-yadif-mode0: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 30 -vf yadif=0
FATE_YADIF += fate-filter-yadif-mode1
-fate-filter-yadif-mode1: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vf yadif=1
+fate-filter-yadif-mode1: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 59 -vf yadif=1
+
+FATE_YADIF += fate-filter-yadif10
+fate-filter-yadif10: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p10le -vframes 30 -vf yadif=0
+
+FATE_YADIF += fate-filter-yadif16
+fate-filter-yadif16: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -flags bitexact -pix_fmt yuv420p16le -vframes 30 -vf yadif=0
FATE_FILTER-$(call FILTERDEMDEC, YADIF, MPEGTS, MPEG2VIDEO) += $(FATE_YADIF)
+FATE_MCDEINT += fate-filter-mcdeint-fast
+fate-filter-mcdeint-fast: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 30 -vf mcdeint=fast
+
+FATE_MCDEINT += fate-filter-mcdeint-medium
+fate-filter-mcdeint-medium: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 30 -vf mcdeint=mode=medium
+
+FATE_FILTER-$(call ALLYES, MCDEINT_FILTER, MPEGTS_DEMUXER, MPEG2VIDEO_DECODER SNOW_ENCODER) += $(FATE_MCDEINT)
+
+FATE_FILTER-$(call ALLYES, CODECVIEW_FILTER RM_DEMUXER RV40_DECODER) += fate-filter-codecview-mvs
+fate-filter-codecview-mvs: CMD = framecrc -flags2 +export_mvs -i $(TARGET_SAMPLES)/real/spygames-2MB.rmvb -vf codecview=mv=pf+bf+bb -vframes 60 -an
+
+FATE_FILTER-$(call ALLYES, SHOWPALETTE_FILTER FLIC_DEMUXER FLIC_DECODER) += fate-filter-showpalette
+fate-filter-showpalette: CMD = framecrc -i $(TARGET_SAMPLES)/fli/fli-engines.fli -vf showpalette=3 -pix_fmt bgra
+
+FATE_FILTER_PALETTEGEN += fate-filter-palettegen-1
+fate-filter-palettegen-1: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -vf palettegen -pix_fmt bgra
+
+FATE_FILTER_PALETTEGEN += fate-filter-palettegen-2
+fate-filter-palettegen-2: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -vf palettegen=max_colors=128:reserve_transparent=0:stats_mode=diff -pix_fmt bgra
+
+fate-filter-palettegen: $(FATE_FILTER_PALETTEGEN)
+FATE_FILTER-$(call ALLYES, PALETTEGEN_FILTER MATROSKA_DEMUXER H264_DECODER) += $(FATE_FILTER_PALETTEGEN)
+
+FATE_FILTER_PALETTEUSE += fate-filter-paletteuse-nodither
+fate-filter-paletteuse-nodither: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -i $(TARGET_SAMPLES)/filter/anim-palette.png -lavfi paletteuse=none -pix_fmt bgra
+
+FATE_FILTER_PALETTEUSE += fate-filter-paletteuse-bayer
+fate-filter-paletteuse-bayer: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -i $(TARGET_SAMPLES)/filter/anim-palette.png -lavfi paletteuse=bayer -pix_fmt bgra
+
+FATE_FILTER_PALETTEUSE += fate-filter-paletteuse-sierra2_4a
+fate-filter-paletteuse-sierra2_4a: CMD = framecrc -i $(TARGET_SAMPLES)/filter/anim.mkv -i $(TARGET_SAMPLES)/filter/anim-palette.png -lavfi paletteuse=sierra2_4a:diff_mode=rectangle -pix_fmt bgra
+
+fate-filter-paletteuse: $(FATE_FILTER_PALETTEUSE)
+FATE_FILTER-$(call ALLYES, PALETTEUSE_FILTER MATROSKA_DEMUXER H264_DECODER IMAGE2_DEMUXER PNG_DECODER) += $(FATE_FILTER_PALETTEUSE)
+
FATE_SAMPLES_AVCONV += $(FATE_FILTER-yes)
+FATE_FILTER-$(call ALLYES, AVDEVICE LIFE_FILTER) += fate-filter-lavd-life
+fate-filter-lavd-life: CMD = framecrc -f lavfi -i life=s=40x40:r=5:seed=42:mold=64:ratio=0.1:death_color=red:life_color=green -t 2
+
+FATE_FILTER-$(call ALLYES, AVDEVICE TESTSRC_FILTER) += fate-filter-lavd-testsrc
+fate-filter-lavd-testsrc: CMD = framecrc -f lavfi -i testsrc=r=7:n=2:d=10
+
+FATE_FILTER-$(call ALLYES, AVDEVICE TESTSRC_FILTER FORMAT_FILTER CONCAT_FILTER SCALE_FILTER) += fate-filter-lavd-scalenorm
+fate-filter-lavd-scalenorm: tests/data/filtergraphs/scalenorm
+fate-filter-lavd-scalenorm: CMD = framecrc -f lavfi -graph_file $(TARGET_PATH)/tests/data/filtergraphs/scalenorm -i dummy
+
FATE_FILTER_VSYNTH-$(CONFIG_BOXBLUR_FILTER) += fate-filter-boxblur
fate-filter-boxblur: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf boxblur=2:1
+FATE_FILTER_VSYNTH-$(call ALLYES, COLORCHANNELMIXER_FILTER FORMAT_FILTER PERMS_FILTER) += fate-filter-colorchannelmixer
+fate-filter-colorchannelmixer: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf format=rgb24,perms=random,colorchannelmixer=.31415927:.4:.31415927:0:.27182818:.8:.27182818:0:.2:.6:.2:0 -flags +bitexact -sws_flags +accurate_rnd+bitexact
+
FATE_FILTER_VSYNTH-$(CONFIG_DRAWBOX_FILTER) += fate-filter-drawbox
-fate-filter-drawbox: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf drawbox=10:20:200:60:red@0.5
+fate-filter-drawbox: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf drawbox=224:24:88:72:red@0.5
FATE_FILTER_VSYNTH-$(CONFIG_FADE_FILTER) += fate-filter-fade
-fate-filter-fade: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf fade=in:0:25,fade=out:25:25
+fate-filter-fade: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf fade=in:5:15,fade=out:30:15
FATE_FILTER_VSYNTH-$(call ALLYES, INTERLACE_FILTER FIELDORDER_FILTER) += fate-filter-fieldorder
fate-filter-fieldorder: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf interlace=tff,fieldorder=bff -sws_flags +accurate_rnd+bitexact
define FATE_FPFILTER_SUITE
-FATE_FILTER_VSYNTH-$(CONFIG_FRAMEPACK_FILTER) += fate-filter-framepack-$(1)
+FATE_FILTER_FRAMEPACK += fate-filter-framepack-$(1)
fate-filter-framepack-$(1): CMD = framecrc -c:v pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -c:v pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -filter_complex framepack=$(1) -frames 15
endef
FPMODES = columns frameseq lines sbs tab
$(foreach MODE,$(FPMODES),$(eval $(call FATE_FPFILTER_SUITE,$(MODE))))
+FATE_FILTER_VSYNTH-$(CONFIG_FRAMEPACK_FILTER) += $(FATE_FILTER_FRAMEPACK)
+fate-filter-framepack: $(FATE_FILTER_FRAMEPACK)
FATE_FILTER_VSYNTH-$(CONFIG_GRADFUN_FILTER) += fate-filter-gradfun
fate-filter-gradfun: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf gradfun
@@ -41,13 +97,41 @@ fate-filter-hqdn3d: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf hqdn3d
FATE_FILTER_VSYNTH-$(CONFIG_INTERLACE_FILTER) += fate-filter-interlace
fate-filter-interlace: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf interlace
-FATE_FILTER_VSYNTH-$(CONFIG_NEGATE_FILTER) += fate-filter-negate
-fate-filter-negate: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf negate
+FATE_FILTER_VSYNTH-$(call ALLYES, NEGATE_FILTER PERMS_FILTER) += fate-filter-negate
+fate-filter-negate: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf perms=random,negate
+
+FATE_FILTER_VSYNTH-$(CONFIG_HISTOGRAM_FILTER) += fate-filter-histogram-levels
+fate-filter-histogram-levels: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf histogram -flags +bitexact -sws_flags +accurate_rnd+bitexact
+
+FATE_FILTER_VSYNTH-$(CONFIG_HISTOGRAM_FILTER) += fate-filter-histogram-waveform
+fate-filter-histogram-waveform: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf format=yuv444p,histogram=mode=waveform -flags +bitexact -sws_flags +accurate_rnd+bitexact
FATE_FILTER_VSYNTH-$(CONFIG_OVERLAY_FILTER) += fate-filter-overlay
fate-filter-overlay: tests/data/filtergraphs/overlay
fate-filter-overlay: CMD = framecrc -c:v pgmyuv -i $(SRC) -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/overlay
+FATE_FILTER_VSYNTH-$(call ALLYES, SPLIT_FILTER SCALE_FILTER PAD_FILTER OVERLAY_FILTER) += fate-filter-overlay_rgb
+fate-filter-overlay_rgb: tests/data/filtergraphs/overlay_rgb
+fate-filter-overlay_rgb: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/overlay_rgb
+
+FATE_FILTER_VSYNTH-$(call ALLYES, SPLIT_FILTER SCALE_FILTER PAD_FILTER OVERLAY_FILTER) += fate-filter-overlay_yuv420
+fate-filter-overlay_yuv420: tests/data/filtergraphs/overlay_yuv420
+fate-filter-overlay_yuv420: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/overlay_yuv420
+
+FATE_FILTER_VSYNTH-$(call ALLYES, SPLIT_FILTER SCALE_FILTER PAD_FILTER OVERLAY_FILTER) += fate-filter-overlay_yuv422
+fate-filter-overlay_yuv422: tests/data/filtergraphs/overlay_yuv422
+fate-filter-overlay_yuv422: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/overlay_yuv422
+
+FATE_FILTER_VSYNTH-$(call ALLYES, SPLIT_FILTER SCALE_FILTER PAD_FILTER OVERLAY_FILTER) += fate-filter-overlay_yuv444
+fate-filter-overlay_yuv444: tests/data/filtergraphs/overlay_yuv444
+fate-filter-overlay_yuv444: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/overlay_yuv444
+
+FATE_FILTER_VSYNTH-$(CONFIG_PHASE_FILTER) += fate-filter-phase
+fate-filter-phase: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf phase
+
+FATE_FILTER_VSYNTH-$(CONFIG_SEPARATEFIELDS_FILTER) += fate-filter-separatefields
+fate-filter-separatefields: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf separatefields
+
FATE_FILTER_VSYNTH-$(CONFIG_SELECT_FILTER) += fate-filter-select-alternate
fate-filter-select-alternate: tests/data/filtergraphs/select-alternate
fate-filter-select-alternate: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_script $(TARGET_PATH)/tests/data/filtergraphs/select-alternate
@@ -64,6 +148,9 @@ fate-filter-shuffleplanes-swapuv: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf shuff
FATE_FILTER_VSYNTH-$(CONFIG_SHUFFLEPLANES_FILTER) += $(FATE_SHUFFLEPLANES)
+FATE_FILTER_VSYNTH-$(CONFIG_TELECINE_FILTER) += fate-filter-telecine
+fate-filter-telecine: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf telecine
+
FATE_FILTER_VSYNTH-$(CONFIG_TRANSPOSE_FILTER) += fate-filter-transpose
fate-filter-transpose: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf transpose
@@ -82,8 +169,44 @@ fate-filter-trim-time: CMD = framecrc -i $(SRC) -vf trim=0:0.09
FATE_FILTER_VSYNTH-$(CONFIG_TRIM_FILTER) += $(FATE_TRIM)
FATE_FILTER_VSYNTH-$(CONFIG_UNSHARP_FILTER) += fate-filter-unsharp
-fate-filter-unsharp: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf unsharp
+fate-filter-unsharp: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf unsharp=11:11:-1.5:11:11:-1.5
+
+FATE_FILTER-$(call ALLYES, SMJPEG_DEMUXER MJPEG_DECODER PERMS_FILTER HQDN3D_FILTER) += fate-filter-hqdn3d-sample
+fate-filter-hqdn3d-sample: tests/data/filtergraphs/hqdn3d
+fate-filter-hqdn3d-sample: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/hqdn3d -an
+
+FATE_FILTER_HQX-$(call ALLYES, IMAGE2_DEMUXER PNG_DECODER HQX_FILTER) = fate-filter-hq2x fate-filter-hq3x fate-filter-hq4x
+FATE_FILTER-yes += $(FATE_FILTER_HQX-yes)
+fate-filter-hq2x: CMD = framecrc -i $(TARGET_SAMPLES)/filter/pixelart%d.png -vf hqx=2 -pix_fmt bgra
+fate-filter-hq3x: CMD = framecrc -i $(TARGET_SAMPLES)/filter/pixelart%d.png -vf hqx=3 -pix_fmt bgra
+fate-filter-hq4x: CMD = framecrc -i $(TARGET_SAMPLES)/filter/pixelart%d.png -vf hqx=4 -pix_fmt bgra
+fate-filter-hqx: $(FATE_FILTER_HQX-yes)
+FATE_FILTER_XBR-$(call ALLYES, IMAGE2_DEMUXER PNG_DECODER XBR_FILTER) = fate-filter-2xbr fate-filter-3xbr fate-filter-4xbr
+FATE_FILTER-yes += $(FATE_FILTER_XBR-yes)
+fate-filter-2xbr: CMD = framecrc -i $(TARGET_SAMPLES)/filter/pixelart%d.png -vf xbr=2 -pix_fmt bgra
+fate-filter-3xbr: CMD = framecrc -i $(TARGET_SAMPLES)/filter/pixelart%d.png -vf xbr=3 -pix_fmt bgra
+fate-filter-4xbr: CMD = framecrc -i $(TARGET_SAMPLES)/filter/pixelart%d.png -vf xbr=4 -pix_fmt bgra
+fate-filter-xbr: $(FATE_FILTER_XBR-yes)
+
+FATE_FILTER-$(call ALLYES, UTVIDEO_DECODER AVI_DEMUXER PERMS_FILTER CURVES_FILTER) += fate-filter-curves
+fate-filter-curves: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgb_median.avi -vf perms=random,curves=vintage
+
+FATE_FILTER-$(call ALLYES, VMD_DEMUXER VMDVIDEO_DECODER FORMAT_FILTER PERMS_FILTER GRADFUN_FILTER) += fate-filter-gradfun-sample
+fate-filter-gradfun-sample: tests/data/filtergraphs/gradfun
+fate-filter-gradfun-sample: CMD = framecrc -i $(TARGET_SAMPLES)/vmd/12.vmd -filter_script $(TARGET_PATH)/tests/data/filtergraphs/gradfun -an -frames:v 20
+
+FATE_FILTER-$(call ALLYES, TESTSRC_FILTER SINE_FILTER CONCAT_FILTER) += fate-filter-concat
+fate-filter-concat: tests/data/filtergraphs/concat
+fate-filter-concat: CMD = framecrc -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/concat
+
+FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER SPLIT_FILTER ALPHAEXTRACT_FILTER ALPHAMERGE_FILTER) += fate-filter-alphaextract_alphamerge_rgb
+fate-filter-alphaextract_alphamerge_rgb: tests/data/filtergraphs/alphamerge_alphaextract_rgb
+fate-filter-alphaextract_alphamerge_rgb: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/alphamerge_alphaextract_rgb
+
+FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER SPLIT_FILTER ALPHAEXTRACT_FILTER ALPHAMERGE_FILTER) += fate-filter-alphaextract_alphamerge_yuv
+fate-filter-alphaextract_alphamerge_yuv: tests/data/filtergraphs/alphamerge_alphaextract_yuv
+fate-filter-alphaextract_alphamerge_yuv: CMD = framecrc -c:v pgmyuv -i $(SRC) -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/alphamerge_alphaextract_yuv
FATE_FILTER_VSYNTH-$(CONFIG_CROP_FILTER) += fate-filter-crop
fate-filter-crop: CMD = video_filter "crop=iw-100:ih-100:100:100"
@@ -109,15 +232,92 @@ fate-filter-scale500: CMD = video_filter "scale=w=500:h=500"
FATE_FILTER_VSYNTH-$(CONFIG_VFLIP_FILTER) += fate-filter-vflip
fate-filter-vflip: CMD = video_filter "vflip"
+FATE_FILTER_VSYNTH-$(CONFIG_COLORMATRIX_FILTER) += fate-filter-colormatrix1
+fate-filter-colormatrix1: CMD = video_filter "colormatrix=bt601:smpte240m,colormatrix=smpte240m:fcc,colormatrix=fcc:bt601,colormatrix=bt601:fcc,colormatrix=fcc:smpte240m,colormatrix=smpte240m:bt709"
+
+FATE_FILTER_VSYNTH-$(CONFIG_COLORMATRIX_FILTER) += fate-filter-colormatrix2
+fate-filter-colormatrix2: CMD = video_filter "colormatrix=bt709:fcc,colormatrix=fcc:bt709,colormatrix=bt709:bt601,colormatrix=bt601:bt709,colormatrix=bt709:smpte240m,colormatrix=smpte240m:bt601"
+
FATE_FILTER_VSYNTH-$(call ALLYES, CROP_FILTER VFLIP_FILTER) += fate-filter-vflip_crop
fate-filter-vflip_crop: CMD = video_filter "vflip,crop=iw-100:ih-100:100:100"
FATE_FILTER_VSYNTH-$(CONFIG_VFLIP_FILTER) += fate-filter-vflip_vflip
fate-filter-vflip_vflip: CMD = video_filter "vflip,vflip"
+FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER PERMS_FILTER EDGEDETECT_FILTER) += fate-filter-edgedetect
+fate-filter-edgedetect: CMD = video_filter "format=gray,perms=random,edgedetect" -vframes 20
+
+FATE_FILTER_VSYNTH-$(call ALLYES, FORMAT_FILTER PERMS_FILTER EDGEDETECT_FILTER) += fate-filter-edgedetect-colormix
+fate-filter-edgedetect-colormix: CMD = video_filter "format=gbrp,perms=random,edgedetect=mode=colormix" -vframes 20
+
+FATE_FILTER_VSYNTH-$(call ALLYES, PERMS_FILTER HUE_FILTER) += fate-filter-hue
+fate-filter-hue: CMD = video_filter "perms=random,hue=s=sin(2*PI*t)+1" -vframes 20
+
+FATE_FILTER_VSYNTH-$(CONFIG_IDET_FILTER) += fate-filter-idet
+fate-filter-idet: CMD = framecrc -flags bitexact -idct simple -i $(SRC) -vf idet -vframes 25 -flags +bitexact
+
+FATE_FILTER_VSYNTH-$(CONFIG_PAD_FILTER) += fate-filter-pad
+fate-filter-pad: CMD = video_filter "pad=iw*1.5:ih*1.5:iw*0.3:ih*0.2"
+
+FATE_FILTER_PP = fate-filter-pp fate-filter-pp1 fate-filter-pp2 fate-filter-pp3 fate-filter-pp4 fate-filter-pp5 fate-filter-pp6
+FATE_FILTER_VSYNTH-$(CONFIG_PP_FILTER) += $(FATE_FILTER_PP)
+$(FATE_FILTER_PP): fate-vsynth1-mpeg4-qprd
+
+fate-filter-pp: CMD = framecrc -flags bitexact -idct simple -i $(TARGET_PATH)/tests/data/fate/vsynth1-mpeg4-qprd.avi -vframes 5 -flags +bitexact -vf "pp=be/hb/vb/tn/l5/al"
+fate-filter-pp1: CMD = video_filter "pp=fq|4/be/hb/vb/tn/l5/al"
+fate-filter-pp2: CMD = video_filter "qp=x+y,pp=be/h1/v1/lb"
+fate-filter-pp3: CMD = video_filter "qp=x+y,pp=be/ha|128|7/va/li"
+fate-filter-pp4: CMD = video_filter "pp=be/ci"
+fate-filter-pp5: CMD = video_filter "pp=md"
+fate-filter-pp6: CMD = video_filter "pp=be/fd"
+
+FATE_FILTER_VSYNTH-$(call ALLYES, QP_FILTER PP_FILTER) += fate-filter-qp
+fate-filter-qp: CMD = video_filter "qp=17,pp=be/hb/vb/tn/l5/al"
+
+FATE_FILTER_VSYNTH-$(CONFIG_SELECT_FILTER) += fate-filter-select
+fate-filter-select: CMD = framecrc -flags bitexact -idct simple -i $(SRC) -vf "select=not(eq(mod(n\,2)\,0)+eq(mod(n\,3)\,0))" -vframes 25 -flags +bitexact
+
+FATE_FILTER_VSYNTH-$(CONFIG_SETDAR_FILTER) += fate-filter-setdar
+fate-filter-setdar: CMD = video_filter "setdar=dar=16/9"
+
+FATE_FILTER_VSYNTH-$(CONFIG_SETSAR_FILTER) += fate-filter-setsar
+fate-filter-setsar: CMD = video_filter "setsar=sar=16/11"
+
+FATE_STEREO3D += fate-filter-stereo3d-al-sbsl
+fate-filter-stereo3d-al-sbsl: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=al:sbsl
+
+FATE_STEREO3D += fate-filter-stereo3d-ar-abl
+fate-filter-stereo3d-ar-abl: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=ar:abl
+
+FATE_STEREO3D += fate-filter-stereo3d-abr-mr
+fate-filter-stereo3d-abr-mr: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=abr:mr
+
+FATE_STEREO3D += fate-filter-stereo3d-abr-ml
+fate-filter-stereo3d-abr-ml: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=abr:ml
+
+FATE_STEREO3D += fate-filter-stereo3d-sbsl-abl
+fate-filter-stereo3d-sbsl-abl: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=sbsl:abl
+
+FATE_STEREO3D += fate-filter-stereo3d-sbsl-abr
+fate-filter-stereo3d-sbsl-abr: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=sbsl:abr
+
+FATE_STEREO3D += fate-filter-stereo3d-sbsl-al
+fate-filter-stereo3d-sbsl-al: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=sbsl:al
+
+FATE_STEREO3D += fate-filter-stereo3d-sbsl-sbsr
+fate-filter-stereo3d-sbsl-sbsr: CMD = framecrc -c:v pgmyuv -i $(SRC) -vframes 5 -flags +bitexact -sws_flags +accurate_rnd+bitexact -vf stereo3d=sbsl:sbsr
+
+FATE_FILTER_VSYNTH-$(CONFIG_STEREO3D_FILTER) += $(FATE_STEREO3D)
+
+FATE_FILTER_VSYNTH-$(CONFIG_THUMBNAIL_FILTER) += fate-filter-thumbnail
+fate-filter-thumbnail: CMD = video_filter "thumbnail=10"
+
+FATE_FILTER_VSYNTH-$(CONFIG_TILE_FILTER) += fate-filter-tile
+fate-filter-tile: CMD = video_filter "tile=3x3:nb_frames=5:padding=7:margin=2"
+
tests/pixfmts.mak: TAG = GEN
-tests/pixfmts.mak: avconv$(EXESUF)
+tests/pixfmts.mak: ffmpeg$(EXESUF)
$(M)printf "PIXFMTS = " > $@
$(Q)$(TARGET_EXEC) $(TARGET_PATH)/$< -pix_fmts list 2> /dev/null | awk 'NR > 8 && /^IO/ { printf $$2 " " }' >> $@
$(Q)printf "\n" >> $@
@@ -139,36 +339,99 @@ fate-filter-pixdesc: $(FATE_FILTER_PIXDESC-yes)
FATE_FILTER_VSYNTH-yes += $(FATE_FILTER_PIXDESC-yes)
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-copy
+FATE_FILTER_PIXFMTS-$(CONFIG_COPY_FILTER) += fate-filter-pixfmts-copy
fate-filter-pixfmts-copy: CMD = pixfmts
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-crop
+FATE_FILTER_PIXFMTS-$(CONFIG_CROP_FILTER) += fate-filter-pixfmts-crop
fate-filter-pixfmts-crop: CMD = pixfmts "100:100:100:100"
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-hflip
+FATE_FILTER_PIXFMTS-$(CONFIG_FIELD_FILTER) += fate-filter-pixfmts-field
+fate-filter-pixfmts-field: CMD = pixfmts "bottom"
+
+FATE_FILTER_PIXFMTS-$(call ALLYES, TELECINE_FILTER FIELDMATCH_FILTER) += fate-filter-pixfmts-fieldmatch
+fate-filter-pixfmts-fieldmatch: CMD = pixfmts "" "telecine," 25
+
+FATE_FILTER_PIXFMTS-$(CONFIG_FIELDORDER_FILTER) += fate-filter-pixfmts-fieldorder
+fate-filter-pixfmts-fieldorder: CMD = pixfmts "tff" "setfield=bff,"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_HFLIP_FILTER) += fate-filter-pixfmts-hflip
fate-filter-pixfmts-hflip: CMD = pixfmts
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-null
+#FATE_FILTER_PIXFMTS-$(CONFIG_HISTEQ_FILTER) += fate-filter-pixfmts-histeq
+#fate-filter-pixfmts-histeq: CMD = pixfmts "antibanding=strong"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_IL_FILTER) += fate-filter-pixfmts-il
+fate-filter-pixfmts-il: CMD = pixfmts "luma_mode=d:chroma_mode=d:alpha_mode=d"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_KERNDEINT_FILTER) += fate-filter-pixfmts-kerndeint
+fate-filter-pixfmts-kerndeint: CMD = pixfmts "" "tinterlace=interleave_top,"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_LUT_FILTER) += fate-filter-pixfmts-lut
+fate-filter-pixfmts-lut: CMD = pixfmts "c0=2*val:c1=2*val:c2=val/2:c3=negval+40"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_NULL_FILTER) += fate-filter-pixfmts-null
fate-filter-pixfmts-null: CMD = pixfmts
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-pad
+FATE_FILTER_PIXFMTS-$(CONFIG_PAD_FILTER) += fate-filter-pixfmts-pad
fate-filter-pixfmts-pad: CMD = pixfmts "500:400:20:20"
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-scale
+FATE_FILTER_PIXFMTS-$(call ALLYES, TELECINE_FILTER PULLUP_FILTER) += fate-filter-pixfmts-pullup
+fate-filter-pixfmts-pullup: CMD = pixfmts "" "telecine," 25
+
+FATE_FILTER_PIXFMTS-$(CONFIG_ROTATE_FILTER) += fate-filter-pixfmts-rotate
+fate-filter-pixfmts-rotate: CMD = pixfmts "2*PI*n/50"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_SCALE_FILTER) += fate-filter-pixfmts-scale
fate-filter-pixfmts-scale: CMD = pixfmts "200:100"
-FATE_FILTER_PIXFMTS += fate-filter-pixfmts-vflip
+FATE_FILTER_PIXFMTS-$(CONFIG_SUPER2XSAI_FILTER) += fate-filter-pixfmts-super2xsai
+fate-filter-pixfmts-super2xsai: CMD = pixfmts
+
+FATE_FILTER_PIXFMTS-$(CONFIG_SWAPUV_FILTER) += fate-filter-pixfmts-swapuv
+fate-filter-pixfmts-swapuv: CMD = pixfmts
+
+FATE_FILTER_PIXFMTS-$(CONFIG_TINTERLACE_FILTER) += fate-filter-pixfmts-tinterlace_merge
+fate-filter-pixfmts-tinterlace_merge: CMD = pixfmts "merge"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_TINTERLACE_FILTER) += fate-filter-pixfmts-tinterlace_pad
+fate-filter-pixfmts-tinterlace_pad: CMD = pixfmts "pad"
+
+FATE_FILTER_PIXFMTS-$(CONFIG_VFLIP_FILTER) += fate-filter-pixfmts-vflip
fate-filter-pixfmts-vflip: CMD = pixfmts
-$(FATE_FILTER_PIXFMTS): libavfilter/filtfmts-test$(EXESUF)
-FATE_FILTER_VSYNTH-$(CONFIG_FORMAT_FILTER) += $(FATE_FILTER_PIXFMTS)
+$(FATE_FILTER_PIXFMTS-yes): libavfilter/filtfmts-test$(EXESUF)
+FATE_FILTER_VSYNTH-$(CONFIG_FORMAT_FILTER) += $(FATE_FILTER_PIXFMTS-yes)
+fate-filter-pixfmts: $(FATE_FILTER_PIXFMTS-yes)
$(FATE_FILTER_VSYNTH-yes): $(VREF)
$(FATE_FILTER_VSYNTH-yes): SRC = $(TARGET_PATH)/tests/vsynth1/%02d.pgm
FATE_AVCONV-$(call DEMDEC, IMAGE2, PGMYUV) += $(FATE_FILTER_VSYNTH-yes)
+#
+# Metadata tests
+#
+FILTER_METADATA_COMMAND = ffprobe$(EXESUF) -of compact=p=0 -show_entries frame=pkt_pts:frame_tags -bitexact -f lavfi
+
+SCENEDETECT_DEPS = FFPROBE LAVFI_INDEV MOVIE_FILTER SELECT_FILTER SCALE_FILTER \
+ AVCODEC AVDEVICE MOV_DEMUXER SVQ3_DECODER ZLIB
+FATE_METADATA_FILTER-$(call ALLYES, $(SCENEDETECT_DEPS)) += fate-filter-metadata-scenedetect
+fate-filter-metadata-scenedetect: SRC = $(TARGET_SAMPLES)/svq3/Vertical400kbit.sorenson3.mov
+fate-filter-metadata-scenedetect: CMD = run $(FILTER_METADATA_COMMAND) "sws_flags=+accurate_rnd+bitexact;movie='$(SRC)',select=gt(scene\,.4)"
+
+SILENCEDETECT_DEPS = FFPROBE AVDEVICE LAVFI_INDEV AMOVIE_FILTER AMR_DEMUXER AMRWB_DECODER SILENCEDETECT_FILTER
+FATE_METADATA_FILTER-$(call ALLYES, $(SILENCEDETECT_DEPS)) += fate-filter-metadata-silencedetect
+fate-filter-metadata-silencedetect: SRC = $(TARGET_SAMPLES)/amrwb/seed-12k65.awb
+fate-filter-metadata-silencedetect: CMD = run $(FILTER_METADATA_COMMAND) "amovie='$(SRC)',silencedetect=d=-20dB"
+
+EBUR128_METADATA_DEPS = FFPROBE AVDEVICE LAVFI_INDEV AMOVIE_FILTER FLAC_DEMUXER FLAC_DECODER EBUR128_FILTER
+FATE_METADATA_FILTER-$(call ALLYES, $(EBUR128_METADATA_DEPS)) += fate-filter-metadata-ebur128
+fate-filter-metadata-ebur128: SRC = $(TARGET_SAMPLES)/filter/seq-3341-7_seq-3342-5-24bit.flac
+fate-filter-metadata-ebur128: CMD = run $(FILTER_METADATA_COMMAND) "amovie='$(SRC)',ebur128=metadata=1"
+
+FATE_SAMPLES_FFPROBE += $(FATE_METADATA_FILTER-yes)
+
fate-vfilter: $(FATE_FILTER-yes) $(FATE_FILTER_VSYNTH-yes)
-fate-filter: fate-afilter fate-vfilter
+fate-filter: fate-afilter fate-vfilter $(FATE_METADATA_FILTER-yes)
diff --git a/tests/fate/flac.mak b/tests/fate/flac.mak
index e28f45f82f..4a13404dcb 100644
--- a/tests/fate/flac.mak
+++ b/tests/fate/flac.mak
@@ -22,5 +22,7 @@ fate-flac-24-%: CMD = enc_dec_pcm flac wav s24le $(subst $(SAMPLES),$(TARGET_SAM
fate-flac-%: CMP = oneoff
fate-flac-%: FUZZ = 0
-FATE_SAMPLES_AVCONV += $(FATE_FLAC)
+FATE_FLAC-$(call ENCMUX, FLAC, FLAC) += $(FATE_FLAC)
+
+FATE_SAMPLES_AVCONV += $(FATE_FLAC-yes)
fate-flac: $(FATE_FLAC)
diff --git a/tests/fate/gapless.mak b/tests/fate/gapless.mak
new file mode 100644
index 0000000000..2fb005f3c1
--- /dev/null
+++ b/tests/fate/gapless.mak
@@ -0,0 +1,7 @@
+FATE_GAPLESS-$(CONFIG_MP3_DEMUXER) += fate-gapless-mp3
+fate-gapless-mp3: CMD = gapless $(TARGET_SAMPLES)/gapless/gapless.mp3
+
+FATE_GAPLESS = $(FATE_GAPLESS-yes)
+
+FATE_SAMPLES_AVCONV += $(FATE_GAPLESS)
+fate-gapless: $(FATE_GAPLESS)
diff --git a/tests/fate/gif.mak b/tests/fate/gif.mak
new file mode 100644
index 0000000000..3dc50b3b5f
--- /dev/null
+++ b/tests/fate/gif.mak
@@ -0,0 +1,27 @@
+FATE_GIF += fate-gif-color
+fate-gif-color: CMD = framecrc -i $(TARGET_SAMPLES)/gif/tc217.gif -pix_fmt bgra
+
+FATE_GIF += fate-gif-disposal-background
+fate-gif-disposal-background: CMD = framecrc -trans_color 0 -i $(TARGET_SAMPLES)/gif/m4nb.gif -pix_fmt bgra
+
+FATE_GIF += fate-gif-disposal-restore
+fate-gif-disposal-restore: CMD = framecrc -i $(TARGET_SAMPLES)/gif/banner2.gif -pix_fmt bgra
+
+FATE_GIF += fate-gif-gray
+fate-gif-gray: CMD = framecrc -i $(TARGET_SAMPLES)/gif/Newtons_cradle_animation_book_2.gif -pix_fmt bgra
+
+fate-gifenc%: fate-gif-color
+fate-gifenc%: PIXFMT = $(word 3, $(subst -, ,$(@)))
+fate-gifenc%: SRC = $(TARGET_SAMPLES)/gif/tc217.gif
+fate-gifenc%: CMD = framecrc -i $(SRC) -c:v gif -pix_fmt $(PIXFMT)
+
+FATE_GIF_ENC_PIXFMT = rgb8 bgr8 rgb4_byte bgr4_byte gray pal8
+FATE_GIF_ENC-$(call ENCDEC, GIF, GIF) = $(FATE_GIF_ENC_PIXFMT:%=fate-gifenc-%)
+
+FATE_GIF += $(FATE_GIF_ENC-yes)
+fate-gifenc: $(FATE_GIF_ENC-yes)
+
+FATE_GIF-$(call DEMDEC, GIF, GIF) += $(FATE_GIF)
+
+FATE_SAMPLES_AVCONV += $(FATE_GIF-yes)
+fate-gif: $(FATE_GIF-yes)
diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak
index 34d03bf2d3..46178cd599 100644
--- a/tests/fate/h264.mak
+++ b/tests/fate/h264.mak
@@ -114,6 +114,10 @@ FATE_H264 = aud_mw_e \
frext-hcafr3_hhi_a \
frext-hcafr4_hhi_a \
frext-hcamff1_hhi_b \
+ frext-hi422fr10_sony_b \
+ frext-hi422fr13_sony_b \
+ frext-hi422fr1_sony_a \
+ frext-hi422fr6_sony_a \
frext-hpca_brcm_c \
frext-hpcadq_brcm_b \
frext-hpcafl_bcrm_c \
@@ -135,6 +139,13 @@ FATE_H264 = aud_mw_e \
frext-pph10i5_panasonic_a \
frext-pph10i6_panasonic_a \
frext-pph10i7_panasonic_a \
+ frext-pph422i1_panasonic_a \
+ frext-pph422i2_panasonic_a \
+ frext-pph422i3_panasonic_a \
+ frext-pph422i4_panasonic_a \
+ frext-pph422i5_panasonic_a \
+ frext-pph422i6_panasonic_a \
+ frext-pph422i7_panasonic_a \
hcbp2_hhi_a \
hcmp1_hhi_a \
ls_sva_d \
@@ -191,179 +202,190 @@ FATE_H264-$(call DEMDEC, MATROSKA, H264) += fate-h264-direct-bff
FATE_SAMPLES_AVCONV += $(FATE_H264-yes)
fate-h264: $(FATE_H264-yes)
-fate-h264-conformance-aud_mw_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/AUD_MW_E.264
-fate-h264-conformance-ba1_ft_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BA1_FT_C.264
-fate-h264-conformance-ba1_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BA1_Sony_D.jsv
-fate-h264-conformance-ba2_sony_f: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BA2_Sony_F.jsv
-fate-h264-conformance-ba3_sva_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BA3_SVA_C.264
-fate-h264-conformance-ba_mw_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BA_MW_D.264
-fate-h264-conformance-bamq1_jvc_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BAMQ1_JVC_C.264
-fate-h264-conformance-bamq2_jvc_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BAMQ2_JVC_C.264
-fate-h264-conformance-banm_mw_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BANM_MW_D.264
-fate-h264-conformance-basqp1_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/BASQP1_Sony_C.jsv
-fate-h264-conformance-caba1_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA1_Sony_D.jsv
-fate-h264-conformance-caba1_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA1_SVA_B.264
-fate-h264-conformance-caba2_sony_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA2_Sony_E.jsv
-fate-h264-conformance-caba2_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA2_SVA_B.264
-fate-h264-conformance-caba3_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA3_Sony_C.jsv
-fate-h264-conformance-caba3_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA3_SVA_B.264
-fate-h264-conformance-caba3_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABA3_TOSHIBA_E.264
-fate-h264-conformance-cabac_mot_fld0_full: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_fld0_full.26l
-fate-h264-conformance-cabac_mot_frm0_full: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_frm0_full.26l
-fate-h264-conformance-cabac_mot_mbaff0_full: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_mbaff0_full.26l
-fate-h264-conformance-cabac_mot_picaff0_full: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_picaff0_full.26l
-fate-h264-conformance-cabaci3_sony_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABACI3_Sony_B.jsv
-fate-h264-conformance-cabast3_sony_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABAST3_Sony_E.jsv
-fate-h264-conformance-cabastbr3_sony_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABASTBR3_Sony_B.jsv
-fate-h264-conformance-cabref3_sand_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CABREF3_Sand_D.264
-fate-h264-conformance-cacqp3_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CACQP3_Sony_D.jsv
-fate-h264-conformance-cafi1_sva_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAFI1_SVA_C.264
-fate-h264-conformance-cama1_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMA1_Sony_C.jsv
-fate-h264-conformance-cama1_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMA1_TOSHIBA_B.264
-fate-h264-conformance-cama1_vtc_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cama1_vtc_c.avc
-fate-h264-conformance-cama2_vtc_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cama2_vtc_b.avc
-fate-h264-conformance-cama3_sand_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMA3_Sand_E.264
-fate-h264-conformance-cama3_vtc_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cama3_vtc_b.avc
-fate-h264-conformance-camaci3_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMACI3_Sony_C.jsv
-fate-h264-conformance-camanl1_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMANL1_TOSHIBA_B.264
-fate-h264-conformance-camanl2_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMANL2_TOSHIBA_B.264
-fate-h264-conformance-camanl3_sand_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMANL3_Sand_E.264
-fate-h264-conformance-camasl3_sony_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMASL3_Sony_B.jsv
-fate-h264-conformance-camp_mot_mbaff_l30: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L30.26l
-fate-h264-conformance-camp_mot_mbaff_l31: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L31.26l
-fate-h264-conformance-canl1_sony_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL1_Sony_E.jsv
-fate-h264-conformance-canl1_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL1_SVA_B.264
-fate-h264-conformance-canl1_toshiba_g: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL1_TOSHIBA_G.264
-fate-h264-conformance-canl2_sony_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL2_Sony_E.jsv
-fate-h264-conformance-canl2_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL2_SVA_B.264
-fate-h264-conformance-canl3_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL3_Sony_C.jsv
-fate-h264-conformance-canl3_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL3_SVA_B.264
-fate-h264-conformance-canl4_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANL4_SVA_B.264
-fate-h264-conformance-canlma2_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANLMA2_Sony_C.jsv
-fate-h264-conformance-canlma3_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CANLMA3_Sony_C.jsv
-fate-h264-conformance-capa1_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAPA1_TOSHIBA_B.264
-fate-h264-conformance-capama3_sand_f: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAPAMA3_Sand_F.264
-fate-h264-conformance-capcm1_sand_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAPCM1_Sand_E.264
-fate-h264-conformance-capcmnl1_sand_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAPCMNL1_Sand_E.264
-fate-h264-conformance-capm3_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAPM3_Sony_D.jsv
-fate-h264-conformance-caqp1_sony_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAQP1_Sony_B.jsv
-fate-h264-conformance-cavlc_mot_fld0_full_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_fld0_full_B.26l
-fate-h264-conformance-cavlc_mot_frm0_full_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_frm0_full_B.26l
-fate-h264-conformance-cavlc_mot_mbaff0_full_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_mbaff0_full_B.26l
-fate-h264-conformance-cavlc_mot_picaff0_full_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_picaff0_full_B.26l
-fate-h264-conformance-cawp1_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAWP1_TOSHIBA_E.264
-fate-h264-conformance-cawp5_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CAWP5_TOSHIBA_E.264
-fate-h264-conformance-ci1_ft_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CI1_FT_B.264
-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-aud_mw_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/AUD_MW_E.264
+fate-h264-conformance-ba1_ft_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BA1_FT_C.264
+fate-h264-conformance-ba1_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BA1_Sony_D.jsv
+fate-h264-conformance-ba2_sony_f: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BA2_Sony_F.jsv
+fate-h264-conformance-ba3_sva_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BA3_SVA_C.264
+fate-h264-conformance-ba_mw_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BA_MW_D.264
+fate-h264-conformance-bamq1_jvc_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BAMQ1_JVC_C.264
+fate-h264-conformance-bamq2_jvc_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BAMQ2_JVC_C.264
+fate-h264-conformance-banm_mw_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BANM_MW_D.264
+fate-h264-conformance-basqp1_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/BASQP1_Sony_C.jsv
+fate-h264-conformance-caba1_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA1_Sony_D.jsv
+fate-h264-conformance-caba1_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA1_SVA_B.264
+fate-h264-conformance-caba2_sony_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA2_Sony_E.jsv
+fate-h264-conformance-caba2_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA2_SVA_B.264
+fate-h264-conformance-caba3_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA3_Sony_C.jsv
+fate-h264-conformance-caba3_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA3_SVA_B.264
+fate-h264-conformance-caba3_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABA3_TOSHIBA_E.264
+fate-h264-conformance-cabac_mot_fld0_full: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_fld0_full.26l
+fate-h264-conformance-cabac_mot_frm0_full: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_frm0_full.26l
+fate-h264-conformance-cabac_mot_mbaff0_full: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_mbaff0_full.26l
+fate-h264-conformance-cabac_mot_picaff0_full: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/camp_mot_picaff0_full.26l
+fate-h264-conformance-cabaci3_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABACI3_Sony_B.jsv
+fate-h264-conformance-cabast3_sony_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABAST3_Sony_E.jsv
+fate-h264-conformance-cabastbr3_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABASTBR3_Sony_B.jsv
+fate-h264-conformance-cabref3_sand_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CABREF3_Sand_D.264
+fate-h264-conformance-cacqp3_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CACQP3_Sony_D.jsv
+fate-h264-conformance-cafi1_sva_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAFI1_SVA_C.264
+fate-h264-conformance-cama1_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMA1_Sony_C.jsv
+fate-h264-conformance-cama1_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMA1_TOSHIBA_B.264
+fate-h264-conformance-cama1_vtc_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cama1_vtc_c.avc
+fate-h264-conformance-cama2_vtc_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cama2_vtc_b.avc
+fate-h264-conformance-cama3_sand_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMA3_Sand_E.264
+fate-h264-conformance-cama3_vtc_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cama3_vtc_b.avc
+fate-h264-conformance-camaci3_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMACI3_Sony_C.jsv
+fate-h264-conformance-camanl1_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMANL1_TOSHIBA_B.264
+fate-h264-conformance-camanl2_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMANL2_TOSHIBA_B.264
+fate-h264-conformance-camanl3_sand_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMANL3_Sand_E.264
+fate-h264-conformance-camasl3_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMASL3_Sony_B.jsv
+fate-h264-conformance-camp_mot_mbaff_l30: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L30.26l
+fate-h264-conformance-camp_mot_mbaff_l31: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAMP_MOT_MBAFF_L31.26l
+fate-h264-conformance-canl1_sony_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL1_Sony_E.jsv
+fate-h264-conformance-canl1_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL1_SVA_B.264
+fate-h264-conformance-canl1_toshiba_g: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL1_TOSHIBA_G.264
+fate-h264-conformance-canl2_sony_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL2_Sony_E.jsv
+fate-h264-conformance-canl2_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL2_SVA_B.264
+fate-h264-conformance-canl3_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL3_Sony_C.jsv
+fate-h264-conformance-canl3_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL3_SVA_B.264
+fate-h264-conformance-canl4_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANL4_SVA_B.264
+fate-h264-conformance-canlma2_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANLMA2_Sony_C.jsv
+fate-h264-conformance-canlma3_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CANLMA3_Sony_C.jsv
+fate-h264-conformance-capa1_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAPA1_TOSHIBA_B.264
+fate-h264-conformance-capama3_sand_f: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAPAMA3_Sand_F.264
+fate-h264-conformance-capcm1_sand_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAPCM1_Sand_E.264
+fate-h264-conformance-capcmnl1_sand_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAPCMNL1_Sand_E.264
+fate-h264-conformance-capm3_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAPM3_Sony_D.jsv
+fate-h264-conformance-caqp1_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAQP1_Sony_B.jsv
+fate-h264-conformance-cavlc_mot_fld0_full_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_fld0_full_B.26l
+fate-h264-conformance-cavlc_mot_frm0_full_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_frm0_full_B.26l
+fate-h264-conformance-cavlc_mot_mbaff0_full_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_mbaff0_full_B.26l
+fate-h264-conformance-cavlc_mot_picaff0_full_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/cvmp_mot_picaff0_full_B.26l
+fate-h264-conformance-cawp1_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAWP1_TOSHIBA_E.264
+fate-h264-conformance-cawp5_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CAWP5_TOSHIBA_E.264
+fate-h264-conformance-ci1_ft_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CI1_FT_B.264
+fate-h264-conformance-ci_mw_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CI_MW_D.264
+fate-h264-conformance-cvbs3_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVBS3_Sony_C.jsv
+fate-h264-conformance-cvcanlma2_sony_c: CMD = framecrc -vsync drop -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-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
-fate-h264-conformance-cvfi2_sva_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVFI2_SVA_C.264
-fate-h264-conformance-cvma1_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMA1_Sony_D.jsv
-fate-h264-conformance-cvma1_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMA1_TOSHIBA_B.264
-fate-h264-conformance-cvmanl1_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMANL1_TOSHIBA_B.264
-fate-h264-conformance-cvmanl2_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMANL2_TOSHIBA_B.264
-fate-h264-conformance-cvmapaqp3_sony_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMAPAQP3_Sony_E.jsv
-fate-h264-conformance-cvmaqp2_sony_g: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMAQP2_Sony_G.jsv
-fate-h264-conformance-cvmaqp3_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMAQP3_Sony_D.jsv
-fate-h264-conformance-cvmp_mot_fld_l30_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMP_MOT_FLD_L30_B.26l
-fate-h264-conformance-cvmp_mot_frm_l31_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVMP_MOT_FRM_L31_B.26l
-fate-h264-conformance-cvnlfi1_sony_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVNLFI1_Sony_C.jsv
-fate-h264-conformance-cvnlfi2_sony_h: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVNLFI2_Sony_H.jsv
-fate-h264-conformance-cvpa1_toshiba_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVPA1_TOSHIBA_B.264
-fate-h264-conformance-cvpcmnl1_sva_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVPCMNL1_SVA_C.264
-fate-h264-conformance-cvpcmnl2_sva_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVPCMNL2_SVA_C.264
-fate-h264-conformance-cvwp1_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVWP1_TOSHIBA_E.264
-fate-h264-conformance-cvwp2_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVWP2_TOSHIBA_E.264
-fate-h264-conformance-cvwp3_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVWP3_TOSHIBA_E.264
-fate-h264-conformance-cvwp5_toshiba_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/CVWP5_TOSHIBA_E.264
-fate-h264-conformance-fi1_sony_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FI1_Sony_E.jsv
-fate-h264-conformance-frext-alphaconformanceg: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/test8b43.264
-fate-h264-conformance-frext-bcrm_freh10: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh10.264 -vsync 0
-fate-h264-conformance-frext-brcm_freh11: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh11.264 -vsync 0
-fate-h264-conformance-frext-brcm_freh3: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh3.264
-fate-h264-conformance-frext-brcm_freh4: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh4.264 -vsync 0
-fate-h264-conformance-frext-brcm_freh5: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh5.264
-fate-h264-conformance-frext-brcm_freh8: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh8.264
-fate-h264-conformance-frext-brcm_freh9: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh9.264
-fate-h264-conformance-frext-freh12_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh12_B.264
-fate-h264-conformance-frext-freh1_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh1_B.264
-fate-h264-conformance-frext-freh2_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh2_B.264
-fate-h264-conformance-frext-freh6: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh6.264 -vsync 0
-fate-h264-conformance-frext-freh7_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh7_B.264 -vsync 0
-fate-h264-conformance-frext-frext01_jvc_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FREXT01_JVC_D.264
-fate-h264-conformance-frext-frext02_jvc_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FREXT02_JVC_C.264
-fate-h264-conformance-frext-frext1_panasonic_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt1_Panasonic.avc
-fate-h264-conformance-frext-frext2_panasonic_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt2_Panasonic.avc -vsync 0
-fate-h264-conformance-frext-frext3_panasonic_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt3_Panasonic.avc
-fate-h264-conformance-frext-frext4_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt4_Panasonic.avc
-fate-h264-conformance-frext-frext_mmco4_sony_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt_MMCO4_Sony_B.264
-fate-h264-conformance-frext-hcaff1_hhi_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFF1_HHI.264
-fate-h264-conformance-frext-hcafr1_hhi_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR1_HHI.264
-fate-h264-conformance-frext-hcafr2_hhi_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR2_HHI.264
-fate-h264-conformance-frext-hcafr3_hhi_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR3_HHI.264
-fate-h264-conformance-frext-hcafr4_hhi_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR4_HHI.264
-fate-h264-conformance-frext-hcamff1_hhi_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAMFF1_HHI.264
-fate-h264-conformance-frext-hpca_brcm_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCA_BRCM_C.264
-fate-h264-conformance-frext-hpcadq_brcm_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCADQ_BRCM_B.264
-fate-h264-conformance-frext-hpcafl_bcrm_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAFL_BRCM_C.264 -vsync 0
-fate-h264-conformance-frext-hpcaflnl_bcrm_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAFLNL_BRCM_C.264 -vsync 0
-fate-h264-conformance-frext-hpcalq_brcm_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCALQ_BRCM_B.264
-fate-h264-conformance-frext-hpcamapalq_bcrm_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAMAPALQ_BRCM_B.264 -vsync 0
-fate-h264-conformance-frext-hpcamolq_brcm_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAMOLQ_BRCM_B.264
-fate-h264-conformance-frext-hpcanl_brcm_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCANL_BRCM_C.264
-fate-h264-conformance-frext-hpcaq2lq_brcm_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAQ2LQ_BRCM_B.264
-fate-h264-conformance-frext-hpcv_brcm_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCV_BRCM_A.264
-fate-h264-conformance-frext-hpcvfl_bcrm_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVFL_BRCM_A.264 -vsync 0
-fate-h264-conformance-frext-hpcvflnl_bcrm_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVFLNL_BRCM_A.264 -vsync 0
-fate-h264-conformance-frext-hpcvmolq_brcm_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVMOLQ_BRCM_B.264
-fate-h264-conformance-frext-hpcvnl_brcm_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVNL_BRCM_A.264
-fate-h264-conformance-frext-pph10i1_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I1_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i2_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I2_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i3_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I3_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i4_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I4_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i5_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I5_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i6_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I6_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-frext-pph10i7_panasonic_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I7_Panasonic_A.264 -pix_fmt yuv420p10le
-fate-h264-conformance-hcbp2_hhi_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/HCBP2_HHI_A.264
-fate-h264-conformance-hcmp1_hhi_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/HCMP1_HHI_A.264
-fate-h264-conformance-ls_sva_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/LS_SVA_D.264
-fate-h264-conformance-midr_mw_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MIDR_MW_D.264
-fate-h264-conformance-mps_mw_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MPS_MW_A.264
-fate-h264-conformance-mr1_bt_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR1_BT_A.h264
-fate-h264-conformance-mr1_mw_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR1_MW_A.264
-fate-h264-conformance-mr2_mw_a: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR2_MW_A.264
-fate-h264-conformance-mr2_tandberg_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR2_TANDBERG_E.264
-fate-h264-conformance-mr3_tandberg_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR3_TANDBERG_B.264
-fate-h264-conformance-mr4_tandberg_c: CMD = framecrc -strict 1 -i $(TARGET_SAMPLES)/h264-conformance/MR4_TANDBERG_C.264
-fate-h264-conformance-mr5_tandberg_c: CMD = framecrc -strict 1 -i $(TARGET_SAMPLES)/h264-conformance/MR5_TANDBERG_C.264
-fate-h264-conformance-mr6_bt_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR6_BT_B.h264
-fate-h264-conformance-mr7_bt_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR7_BT_B.h264
-fate-h264-conformance-mr8_bt_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR8_BT_B.h264
-fate-h264-conformance-mr9_bt_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/MR9_BT_B.h264
-fate-h264-conformance-mv1_brcm_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/src19td.IBP.264
-fate-h264-conformance-nl1_sony_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/NL1_Sony_D.jsv
-fate-h264-conformance-nl2_sony_h: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/NL2_Sony_H.jsv
-fate-h264-conformance-nl3_sva_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/NL3_SVA_E.264
-fate-h264-conformance-nlmq1_jvc_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/NLMQ1_JVC_C.264
-fate-h264-conformance-nlmq2_jvc_c: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/NLMQ2_JVC_C.264
-fate-h264-conformance-nrf_mw_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/NRF_MW_E.264
-fate-h264-conformance-sharp_mp_field_1_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_Field_1_B.jvt
-fate-h264-conformance-sharp_mp_field_2_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_Field_2_B.jvt
-fate-h264-conformance-sharp_mp_field_3_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_Field_3_B.jvt
-fate-h264-conformance-sharp_mp_paff_1r2: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_PAFF_1r2.jvt
-fate-h264-conformance-sharp_mp_paff_2r: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_PAFF_2.jvt
-fate-h264-conformance-sl1_sva_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SL1_SVA_B.264
-fate-h264-conformance-sva_ba1_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_BA1_B.264
-fate-h264-conformance-sva_ba2_d: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_BA2_D.264
-fate-h264-conformance-sva_base_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_Base_B.264
-fate-h264-conformance-sva_cl1_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_CL1_E.264
-fate-h264-conformance-sva_fm1_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_FM1_E.264
-fate-h264-conformance-sva_nl1_b: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_NL1_B.264
-fate-h264-conformance-sva_nl2_e: CMD = framecrc -i $(TARGET_SAMPLES)/h264-conformance/SVA_NL2_E.264
+fate-h264-conformance-cvfi1_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVFI1_Sony_D.jsv
+fate-h264-conformance-cvfi1_sva_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVFI1_SVA_C.264
+fate-h264-conformance-cvfi2_sony_h: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVFI2_Sony_H.jsv
+fate-h264-conformance-cvfi2_sva_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVFI2_SVA_C.264
+fate-h264-conformance-cvma1_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMA1_Sony_D.jsv
+fate-h264-conformance-cvma1_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMA1_TOSHIBA_B.264
+fate-h264-conformance-cvmanl1_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMANL1_TOSHIBA_B.264
+fate-h264-conformance-cvmanl2_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMANL2_TOSHIBA_B.264
+fate-h264-conformance-cvmapaqp3_sony_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMAPAQP3_Sony_E.jsv
+fate-h264-conformance-cvmaqp2_sony_g: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMAQP2_Sony_G.jsv
+fate-h264-conformance-cvmaqp3_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMAQP3_Sony_D.jsv
+fate-h264-conformance-cvmp_mot_fld_l30_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMP_MOT_FLD_L30_B.26l
+fate-h264-conformance-cvmp_mot_frm_l31_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVMP_MOT_FRM_L31_B.26l
+fate-h264-conformance-cvnlfi1_sony_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVNLFI1_Sony_C.jsv
+fate-h264-conformance-cvnlfi2_sony_h: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVNLFI2_Sony_H.jsv
+fate-h264-conformance-cvpa1_toshiba_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVPA1_TOSHIBA_B.264
+fate-h264-conformance-cvpcmnl1_sva_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVPCMNL1_SVA_C.264
+fate-h264-conformance-cvpcmnl2_sva_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVPCMNL2_SVA_C.264
+fate-h264-conformance-cvwp1_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVWP1_TOSHIBA_E.264
+fate-h264-conformance-cvwp2_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVWP2_TOSHIBA_E.264
+fate-h264-conformance-cvwp3_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVWP3_TOSHIBA_E.264
+fate-h264-conformance-cvwp5_toshiba_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/CVWP5_TOSHIBA_E.264
+fate-h264-conformance-fi1_sony_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FI1_Sony_E.jsv
+fate-h264-conformance-frext-alphaconformanceg: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/test8b43.264
+fate-h264-conformance-frext-bcrm_freh10: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh10.264 -vsync drop
+fate-h264-conformance-frext-brcm_freh11: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh11.264 -vsync drop
+fate-h264-conformance-frext-brcm_freh3: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh3.264
+fate-h264-conformance-frext-brcm_freh4: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh4.264 -vsync drop
+fate-h264-conformance-frext-brcm_freh5: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh5.264
+fate-h264-conformance-frext-brcm_freh8: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh8.264
+fate-h264-conformance-frext-brcm_freh9: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh9.264
+fate-h264-conformance-frext-freh12_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh12_B.264
+fate-h264-conformance-frext-freh1_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh1_B.264
+fate-h264-conformance-frext-freh2_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh2_B.264
+fate-h264-conformance-frext-freh6: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/freh6.264 -vsync drop
+fate-h264-conformance-frext-freh7_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Freh7_B.264 -vsync drop
+fate-h264-conformance-frext-frext01_jvc_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FREXT01_JVC_D.264
+fate-h264-conformance-frext-frext02_jvc_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FREXT02_JVC_C.264
+fate-h264-conformance-frext-frext1_panasonic_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt1_Panasonic.avc
+fate-h264-conformance-frext-frext2_panasonic_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt2_Panasonic.avc -vsync 0
+fate-h264-conformance-frext-frext3_panasonic_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt3_Panasonic.avc
+fate-h264-conformance-frext-frext4_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt4_Panasonic.avc
+fate-h264-conformance-frext-frext_mmco4_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/FRExt_MMCO4_Sony_B.264
+fate-h264-conformance-frext-hcaff1_hhi_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFF1_HHI.264
+fate-h264-conformance-frext-hcafr1_hhi_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR1_HHI.264
+fate-h264-conformance-frext-hcafr2_hhi_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR2_HHI.264
+fate-h264-conformance-frext-hcafr3_hhi_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR3_HHI.264
+fate-h264-conformance-frext-hcafr4_hhi_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAFR4_HHI.264
+fate-h264-conformance-frext-hcamff1_hhi_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HCAMFF1_HHI.264
+fate-h264-conformance-frext-hi422fr10_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Hi422FR10_SONY_B.264
+fate-h264-conformance-frext-hi422fr13_sony_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Hi422FR13_SONY_B.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-hi422fr1_sony_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Hi422FR1_SONY_A.jsv
+fate-h264-conformance-frext-hi422fr6_sony_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/Hi422FR6_SONY_A.jsv -pix_fmt yuv422p10le
+fate-h264-conformance-frext-hpca_brcm_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCA_BRCM_C.264
+fate-h264-conformance-frext-hpcadq_brcm_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCADQ_BRCM_B.264
+fate-h264-conformance-frext-hpcafl_bcrm_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAFL_BRCM_C.264 -vsync drop
+fate-h264-conformance-frext-hpcaflnl_bcrm_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAFLNL_BRCM_C.264 -vsync drop
+fate-h264-conformance-frext-hpcalq_brcm_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCALQ_BRCM_B.264
+fate-h264-conformance-frext-hpcamapalq_bcrm_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAMAPALQ_BRCM_B.264 -vsync 0
+fate-h264-conformance-frext-hpcamolq_brcm_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAMOLQ_BRCM_B.264
+fate-h264-conformance-frext-hpcanl_brcm_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCANL_BRCM_C.264
+fate-h264-conformance-frext-hpcaq2lq_brcm_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCAQ2LQ_BRCM_B.264
+fate-h264-conformance-frext-hpcv_brcm_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCV_BRCM_A.264
+fate-h264-conformance-frext-hpcvfl_bcrm_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVFL_BRCM_A.264 -vsync drop
+fate-h264-conformance-frext-hpcvflnl_bcrm_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVFLNL_BRCM_A.264 -vsync drop
+fate-h264-conformance-frext-hpcvmolq_brcm_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVMOLQ_BRCM_B.264
+fate-h264-conformance-frext-hpcvnl_brcm_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/HPCVNL_BRCM_A.264
+fate-h264-conformance-frext-pph10i1_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I1_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i2_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I2_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i3_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I3_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i4_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I4_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i5_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I5_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i6_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I6_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph10i7_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH10I7_Panasonic_A.264 -pix_fmt yuv420p10le
+fate-h264-conformance-frext-pph422i1_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I1_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i2_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I2_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i3_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I3_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i4_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I4_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i5_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I5_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i6_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I6_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-frext-pph422i7_panasonic_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/FRext/PPH422I7_Panasonic_A.264 -pix_fmt yuv422p10le
+fate-h264-conformance-hcbp2_hhi_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/HCBP2_HHI_A.264
+fate-h264-conformance-hcmp1_hhi_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/HCMP1_HHI_A.264
+fate-h264-conformance-ls_sva_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/LS_SVA_D.264
+fate-h264-conformance-midr_mw_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MIDR_MW_D.264
+fate-h264-conformance-mps_mw_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MPS_MW_A.264
+fate-h264-conformance-mr1_bt_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR1_BT_A.h264
+fate-h264-conformance-mr1_mw_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR1_MW_A.264
+fate-h264-conformance-mr2_mw_a: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR2_MW_A.264
+fate-h264-conformance-mr2_tandberg_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR2_TANDBERG_E.264
+fate-h264-conformance-mr3_tandberg_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR3_TANDBERG_B.264
+fate-h264-conformance-mr4_tandberg_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR4_TANDBERG_C.264
+fate-h264-conformance-mr5_tandberg_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR5_TANDBERG_C.264
+fate-h264-conformance-mr6_bt_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR6_BT_B.h264
+fate-h264-conformance-mr7_bt_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR7_BT_B.h264
+fate-h264-conformance-mr8_bt_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR8_BT_B.h264
+fate-h264-conformance-mr9_bt_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/MR9_BT_B.h264
+fate-h264-conformance-mv1_brcm_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/src19td.IBP.264
+fate-h264-conformance-nl1_sony_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/NL1_Sony_D.jsv
+fate-h264-conformance-nl2_sony_h: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/NL2_Sony_H.jsv
+fate-h264-conformance-nl3_sva_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/NL3_SVA_E.264
+fate-h264-conformance-nlmq1_jvc_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/NLMQ1_JVC_C.264
+fate-h264-conformance-nlmq2_jvc_c: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/NLMQ2_JVC_C.264
+fate-h264-conformance-nrf_mw_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/NRF_MW_E.264
+fate-h264-conformance-sharp_mp_field_1_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_Field_1_B.jvt
+fate-h264-conformance-sharp_mp_field_2_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_Field_2_B.jvt
+fate-h264-conformance-sharp_mp_field_3_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_Field_3_B.jvt
+fate-h264-conformance-sharp_mp_paff_1r2: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_PAFF_1r2.jvt
+fate-h264-conformance-sharp_mp_paff_2r: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/Sharp_MP_PAFF_2.jvt
+fate-h264-conformance-sl1_sva_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SL1_SVA_B.264
+fate-h264-conformance-sva_ba1_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_BA1_B.264
+fate-h264-conformance-sva_ba2_d: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_BA2_D.264
+fate-h264-conformance-sva_base_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_Base_B.264
+fate-h264-conformance-sva_cl1_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_CL1_E.264
+fate-h264-conformance-sva_fm1_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_FM1_E.264
+fate-h264-conformance-sva_nl1_b: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_NL1_B.264
+fate-h264-conformance-sva_nl2_e: CMD = framecrc -vsync drop -i $(TARGET_SAMPLES)/h264-conformance/SVA_NL2_E.264
fate-h264-bsf-mp4toannexb: CMD = md5 -i $(TARGET_SAMPLES)/h264/interlaced_crop.mp4 -vcodec copy -bsf h264_mp4toannexb -f h264
fate-h264-crop-to-container: CMD = framemd5 -i $(TARGET_SAMPLES)/h264/crop-to-container-dims-canon.mov
diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak
index fc4ce23bb7..05266cd0fb 100644
--- a/tests/fate/hevc.mak
+++ b/tests/fate/hevc.mak
@@ -1,12 +1,16 @@
HEVC_SAMPLES = \
AMP_A_Samsung_4 \
+ AMP_A_Samsung_6 \
AMP_B_Samsung_4 \
- AMVP_C_Samsung_4 \
+ AMP_B_Samsung_6 \
AMP_D_Hisilicon \
AMP_E_Hisilicon \
AMP_F_Hisilicon_3 \
AMVP_A_MTK_4 \
AMVP_B_MTK_4 \
+ AMVP_C_Samsung_4 \
+ AMVP_C_Samsung_6 \
+ BUMPING_A_ericsson_1 \
CAINIT_A_SHARP_4 \
CAINIT_B_SHARP_4 \
CAINIT_C_SHARP_3 \
@@ -18,26 +22,28 @@ HEVC_SAMPLES = \
CIP_A_Panasonic_3 \
cip_B_NEC_3 \
CIP_C_Panasonic_2 \
+ CONFWIN_A_Sony_1 \
DBLK_A_SONY_3 \
DBLK_B_SONY_3 \
DBLK_C_SONY_3 \
- DBLK_D_VIXS_1 \
DBLK_D_VIXS_2 \
- DBLK_E_VIXS_1 \
DBLK_E_VIXS_2 \
- DBLK_F_VIXS_1 \
DBLK_F_VIXS_2 \
- DBLK_G_VIXS_1 \
DBLK_G_VIXS_2 \
+ DELTAQP_A_BRCM_4 \
DELTAQP_B_SONY_3 \
DELTAQP_C_SONY_3 \
DSLICE_A_HHI_5 \
DSLICE_B_HHI_5 \
DSLICE_C_HHI_5 \
- ENTP_A_LG_2 \
- ENTP_B_LG_2 \
- ENTP_C_LG_3 \
+ ENTP_A_Qualcomm_1 \
+ ENTP_B_Qualcomm_1 \
+ ENTP_C_Qualcomm_1 \
EXT_A_ericsson_4 \
+ FILLER_A_Sony_1 \
+ HRD_A_Fujitsu_2 \
+ HRD_A_Fujitsu_3 \
+ INITQP_A_Sony_1 \
ipcm_A_NEC_3 \
ipcm_B_NEC_3 \
ipcm_C_NEC_3 \
@@ -45,7 +51,7 @@ HEVC_SAMPLES = \
ipcm_E_NEC_2 \
IPRED_A_docomo_2 \
IPRED_B_Nokia_3 \
- IPRED_C_Mitsubishi_2 \
+ IPRED_C_Mitsubishi_3 \
LS_A_Orange_2 \
LS_B_ORANGE_4 \
LTRPSPS_A_Qualcomm_1 \
@@ -62,7 +68,12 @@ HEVC_SAMPLES = \
MVCLIP_A_qualcomm_3 \
MVDL1ZERO_A_docomo_3 \
MVEDGE_A_qualcomm_3 \
+ NoOutPrior_A_Qualcomm_1 \
+ NoOutPrior_B_Qualcomm_1 \
NUT_A_ericsson_5 \
+ OPFLAG_A_Qualcomm_1 \
+ OPFLAG_B_Qualcomm_1 \
+ OPFLAG_C_Qualcomm_1 \
PICSIZE_A_Bossen_1 \
PICSIZE_B_Bossen_1 \
PICSIZE_C_Bossen_1 \
@@ -74,9 +85,9 @@ HEVC_SAMPLES = \
PMERGE_E_TI_3 \
POC_A_Bossen_3 \
PPS_A_qualcomm_7 \
- RAP_A_docomo_4 \
PS_A_VIDYO_3 \
PS_B_VIDYO_3 \
+ RAP_A_docomo_4 \
RAP_B_Bossen_1 \
RPLM_A_qualcomm_4 \
RPLM_B_qualcomm_4 \
@@ -96,7 +107,9 @@ HEVC_SAMPLES = \
SAO_A_MediaTek_4 \
SAO_B_MediaTek_5 \
SAO_C_Samsung_4 \
+ SAO_C_Samsung_5 \
SAO_D_Samsung_4 \
+ SAO_D_Samsung_5 \
SAO_E_Canon_4 \
SAO_F_Canon_3 \
SAO_G_Canon_3 \
@@ -107,8 +120,10 @@ HEVC_SAMPLES = \
SLIST_C_Sony_3 \
SLIST_D_Sony_9 \
SLPPLP_A_VIDYO_1 \
+ SLPPLP_A_VIDYO_2 \
STRUCT_A_Samsung_5 \
STRUCT_B_Samsung_4 \
+ STRUCT_B_Samsung_6 \
TILES_A_Cisco_2 \
TILES_B_Cisco_1 \
TMVP_A_MS_3 \
@@ -117,6 +132,7 @@ HEVC_SAMPLES = \
TSKIP_A_MS_3 \
TUSIZE_A_Samsung_1 \
VPSID_A_VIDYO_1 \
+ VPSID_A_VIDYO_2 \
WP_A_Toshiba_3 \
WP_B_Toshiba_3 \
WPP_A_ericsson_MAIN_2 \
@@ -127,7 +143,7 @@ HEVC_SAMPLES = \
WPP_F_ericsson_MAIN_2 \
HEVC_SAMPLES_10BIT = \
- DBLK_A_MAIN10_VIXS_2 \
+ DBLK_A_MAIN10_VIXS_3 \
WP_A_MAIN10_Toshiba_3 \
WP_MAIN10_B_Toshiba_3 \
WPP_A_ericsson_MAIN10_2 \
@@ -136,26 +152,77 @@ HEVC_SAMPLES_10BIT = \
WPP_D_ericsson_MAIN10_2 \
WPP_E_ericsson_MAIN10_2 \
WPP_F_ericsson_MAIN10_2 \
+ INITQP_B_Sony_1 \
+
+HEVC_SAMPLES_422_10BIT = \
+ ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1 \
+ IPCM_A_RExt_NEC \
+
+HEVC_SAMPLES_422_10BIN = \
+ Main_422_10_A_RExt_Sony_1 \
+ Main_422_10_B_RExt_Sony_1 \
+
+HEVC_SAMPLES_444_8BIT = \
+ QMATRIX_A_RExt_Sony_1 \
+
+HEVC_SAMPLES_444_12BIT = \
+ IPCM_B_RExt_NEC \
+ PERSIST_RPARAM_A_RExt_Sony_1\
+ SAO_A_RExt_MediaTek_1 \
+
+
+# equivalent bitstreams
+# AMP_D_Hisilicon_3 -- AMP_D_Hisilicon
+# AMP_E_Hisilicon_3 -- AMP_E_Hisilicon
+# MVDL1ZERO_A_docomo_4 -- MVDL1ZERO_A_docomo_3
+# RAP_A_docomo_5 -- RAP_A_docomo_4
+# RAP_B_bossen_2 -- RAP_B_bossen_1
+# RPS_A_docomo_5 -- RPS_A_docomo_4
+# RPS_F_docomo_2 -- RPS_F_docomo_1
# do not pass:
-# DELTAQP_A_BRCM_4.bit -- TODO uses CRC instead of MD5
-# HRD_A_Fujitsu_2.bin -- TODO uses hash 2 ("checksum")
-# TSUNEQBD_A_MAIN10_Technicolor_2.bit (segfault)
+# TSUNEQBD_A_MAIN10_Technicolor_2.bit (segfault mix 9-10bits)
+# PERSIST_RPARAM_A_RExt_Sony_1 (rext)
+
define FATE_HEVC_TEST
FATE_HEVC += fate-hevc-conformance-$(1)
-fate-hevc-conformance-$(1): CMD = framecrc -vsync 0 -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit
+fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit
endef
define FATE_HEVC_TEST_10BIT
FATE_HEVC += fate-hevc-conformance-$(1)
-fate-hevc-conformance-$(1): CMD = framecrc -vsync 0 -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv420p10le
+fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv420p10le
+endef
+
+define FATE_HEVC_TEST_422_10BIT
+FATE_HEVC += fate-hevc-conformance-$(1)
+fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv422p10le
+endef
+
+define FATE_HEVC_TEST_422_10BIN
+FATE_HEVC += fate-hevc-conformance-$(1)
+fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bin -pix_fmt yuv422p10le
+endef
+
+define FATE_HEVC_TEST_444_8BIT
+FATE_HEVC += fate-hevc-conformance-$(1)
+fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit
+endef
+
+define FATE_HEVC_TEST_444_12BIT
+FATE_HEVC += fate-hevc-conformance-$(1)
+fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv444p12le
endef
$(foreach N,$(HEVC_SAMPLES),$(eval $(call FATE_HEVC_TEST,$(N))))
$(foreach N,$(HEVC_SAMPLES_10BIT),$(eval $(call FATE_HEVC_TEST_10BIT,$(N))))
+$(foreach N,$(HEVC_SAMPLES_422_10BIT),$(eval $(call FATE_HEVC_TEST_422_10BIT,$(N))))
+$(foreach N,$(HEVC_SAMPLES_422_10BIN),$(eval $(call FATE_HEVC_TEST_422_10BIN,$(N))))
+$(foreach N,$(HEVC_SAMPLES_444_8BIT),$(eval $(call FATE_HEVC_TEST_444_8BIT,$(N))))
+$(foreach N,$(HEVC_SAMPLES_444_12BIT),$(eval $(call FATE_HEVC_TEST_444_12BIT,$(N))))
-fate-hevc-paramchange-yuv420p-yuv420p10: CMD = framecrc -vsync 0 -i $(TARGET_SAMPLES)/hevc/paramchange_yuv420p_yuv420p10.hevc
+fate-hevc-paramchange-yuv420p-yuv420p10: CMD = framecrc -vsync 0 -i $(TARGET_SAMPLES)/hevc/paramchange_yuv420p_yuv420p10.hevc -sws_flags area+accurate_rnd+bitexact
FATE_HEVC += fate-hevc-paramchange-yuv420p-yuv420p10
FATE_HEVC-$(call DEMDEC, HEVC, HEVC) += $(FATE_HEVC)
diff --git a/tests/fate/image.mak b/tests/fate/image.mak
index 807b118aeb..6f5e4cb2c6 100644
--- a/tests/fate/image.mak
+++ b/tests/fate/image.mak
@@ -5,7 +5,7 @@ FATE_ALIASPIX += fate-aliaspix-gray
fate-aliaspix-gray: CMD = framecrc -i $(TARGET_SAMPLES)/aliaspix/firstgray.pix -pix_fmt gray
FATE_ALIASPIX-$(call DEMDEC, IMAGE2, ALIAS_PIX) += $(FATE_ALIASPIX)
-FATE_SAMPLES_AVCONV += $(FATE_ALIASPIX-yes)
+FATE_IMAGE += $(FATE_ALIASPIX-yes)
fate-aliaspix: $(FATE_ALIASPIX-yes)
FATE_BRENDERPIX += fate-brenderpix-24
@@ -24,17 +24,17 @@ FATE_BRENDERPIX += fate-brenderpix-y400a
fate-brenderpix-y400a: CMD = framecrc -c:v brender_pix -i $(TARGET_SAMPLES)/brenderpix/gears.pix
FATE_BRENDERPIX-$(call DEMDEC, IMAGE2, BRENDER_PIX) += $(FATE_BRENDERPIX)
-FATE_SAMPLES_AVCONV += $(FATE_BRENDERPIX-yes)
+FATE_IMAGE += $(FATE_BRENDERPIX-yes)
fate-brenderpix: $(FATE_BRENDERPIX-yes)
-FATE_SAMPLES_AVCONV-$(call PARSERDEMDEC, BMP, IMAGE2PIPE, BMP) += fate-bmpparser
-fate-bmpparser: CMD = framecrc -f image2pipe -i $(TARGET_SAMPLES)/bmp/libav_4x_concat.bmp -pix_fmt rgb24
+FATE_IMAGE-$(call PARSERDEMDEC, BMP, IMAGE2PIPE, BMP) += fate-bmpparser
+fate-bmpparser: CMD = framecrc -f image2pipe -i $(TARGET_SAMPLES)/bmp/numbers.bmp -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, DPX) += fate-dpx
+FATE_IMAGE-$(call DEMDEC, IMAGE2, DPX) += fate-dpx
fate-dpx: CMD = framecrc -i $(TARGET_SAMPLES)/dpx/lighthouse_rgb48.dpx
FATE_SAMPLES_AVCONV-$(call PARSERDEMDEC, DPX, IMAGE2PIPE, DPX) += fate-dpxparser
-fate-dpxparser: CMD = framecrc -f image2pipe -i $(TARGET_SAMPLES)/dpx/libav_4x_concat.dpx -sws_flags +accurate_rnd+bitexact
+fate-dpxparser: CMD = framecrc -f image2pipe -i $(TARGET_SAMPLES)/dpx/lena_4x_concat.dpx -sws_flags +accurate_rnd+bitexact
FATE_EXR += fate-exr-slice-raw
fate-exr-slice-raw: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_slice_raw.exr -pix_fmt rgba64le
@@ -53,56 +53,56 @@ fate-exr-slice-pxr24: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_slice_pxr24.ex
FATE_EXR-$(call DEMDEC, IMAGE2, EXR) += $(FATE_EXR)
-FATE_SAMPLES_AVCONV += $(FATE_EXR-yes)
+FATE_IMAGE += $(FATE_EXR-yes)
fate-exr: $(FATE_EXR-yes)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, QDRAW) += fate-pict
+FATE_IMAGE-$(call DEMDEC, IMAGE2, QDRAW) += fate-pict
fate-pict: CMD = framecrc -i $(TARGET_SAMPLES)/quickdraw/TRU256.PCT -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, PICTOR) += fate-pictor
-fate-pictor: CMD = framecrc -c pictor -i $(TARGET_SAMPLES)/pictor/MFISH.PIC -pix_fmt rgb24
+FATE_IMAGE-$(call DEMDEC, IMAGE2, PICTOR) += fate-pictor
+fate-pictor: CMD = framecrc -i $(TARGET_SAMPLES)/pictor/MFISH.PIC -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call PARSERDEMDEC, PNG, IMAGE2PIPE, PNG) += fate-pngparser
-fate-pngparser: CMD = framecrc -f image2pipe -i $(TARGET_SAMPLES)/png1/libav_4x_concat.png -pix_fmt rgba
+FATE_IMAGE-$(call PARSERDEMDEC, PNG, IMAGE2PIPE, PNG) += fate-pngparser
+fate-pngparser: CMD = framecrc -f image2pipe -i $(TARGET_SAMPLES)/png1/feed_4x_concat.png -pix_fmt rgba
define FATE_IMGSUITE_PNG
FATE_PNG += fate-png-$(1)
-fate-png-$(1): CMD = framecrc -i $(TARGET_SAMPLES)/png1/libav_$(1).png -sws_flags +accurate_rnd+bitexact -pix_fmt rgb24
+fate-png-$(1): CMD = framecrc -i $(TARGET_SAMPLES)/png1/lena-$(1).png -sws_flags +accurate_rnd+bitexact -pix_fmt rgb24
endef
PNG_COLORSPACES = gray8 gray16 rgb24 rgb48 rgba ya8 ya16
$(foreach CLSP,$(PNG_COLORSPACES),$(eval $(call FATE_IMGSUITE_PNG,$(CLSP))))
FATE_PNG-$(call DEMDEC, IMAGE2, PNG) += $(FATE_PNG)
-FATE_SAMPLES_AVCONV += $(FATE_PNG-yes)
+FATE_IMAGE += $(FATE_PNG-yes)
fate-png: $(FATE_PNG-yes)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IMAGE2, PTX) += fate-ptx
+FATE_IMAGE-$(call DEMDEC, IMAGE2, PTX) += fate-ptx
fate-ptx: CMD = framecrc -i $(TARGET_SAMPLES)/ptx/_113kw_pic.ptx -pix_fmt rgb24
FATE_SGI += fate-sgi-gray
-fate-sgi-gray: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/vulap_gray.sgi -pix_fmt gray
+fate-sgi-gray: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/lena_gray.sgi -pix_fmt gray
FATE_SGI += fate-sgi-gray16
-fate-sgi-gray16: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/vulap_gray16.sgi -pix_fmt gray16le
+fate-sgi-gray16: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/lena_gray16.sgi -pix_fmt gray16le
FATE_SGI += fate-sgi-rgb24
-fate-sgi-rgb24: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/vulap_rgb24.sgi -pix_fmt rgb24
+fate-sgi-rgb24: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/lena_rgb24.sgi -pix_fmt rgb24
FATE_SGI += fate-sgi-rgb24-rle
fate-sgi-rgb24-rle: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/uvmap_rgb24_rle.sgi -pix_fmt rgb24
FATE_SGI += fate-sgi-rgb48
-fate-sgi-rgb48: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/vulap_rgb48.sgi -pix_fmt rgb48be
+fate-sgi-rgb48: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/lena_rgb48.sgi -pix_fmt rgb48be
FATE_SGI += fate-sgi-rgb48-rle
fate-sgi-rgb48-rle: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/uvmap_rgb48_rle.sgi -pix_fmt rgb48be
FATE_SGI += fate-sgi-rgba
-fate-sgi-rgba: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/vulap_rgba.sgi -pix_fmt rgba
+fate-sgi-rgba: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/lena_rgba.sgi -pix_fmt rgba
FATE_SGI += fate-sgi-rgba64
-fate-sgi-rgba64: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/vulap_rgba64.sgi -pix_fmt rgba64be
+fate-sgi-rgba64: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/lena_rgba64.sgi -pix_fmt rgba64be
FATE_SGI += fate-sgi-rgba64-rle
fate-sgi-rgba64-rle: CMD = framecrc -i $(TARGET_SAMPLES)/sgi/maya_rgba64_rle.sgi -pix_fmt rgba64be
@@ -135,7 +135,7 @@ fate-sunraster-24bit-rle: CMD = framecrc -i $(TARGET_SAMPLES)/sunraster/lena-24b
FATE_SUNRASTER-$(call DEMDEC, IMAGE2, SUNRAST) += $(FATE_SUNRASTER)
-FATE_SAMPLES_AVCONV += $(FATE_SUNRASTER-yes)
+FATE_IMAGE += $(FATE_SUNRASTER-yes)
fate-sunraster: $(FATE_SUNRASTER-yes)
FATE_TARGA = CBW8 \
@@ -154,7 +154,7 @@ FATE_TARGA := $(FATE_TARGA:%=fate-targa-conformance-%) \
FATE_TARGA-$(call DEMDEC, IMAGE2, TARGA) += $(FATE_TARGA)
-FATE_SAMPLES_AVCONV += $(FATE_TARGA-yes)
+FATE_IMAGE += $(FATE_TARGA-yes)
fate-targa: $(FATE_TARGA-yes)
fate-targa-conformance-CBW8: CMD = framecrc -i $(TARGET_SAMPLES)/targa-conformance/CBW8.TGA
@@ -178,9 +178,12 @@ fate-tiff-fax-g3s: CMD = framecrc -i $(TARGET_SAMPLES)/CCITT_fax/G31DS.TIF
FATE_TIFF-$(call DEMDEC, IMAGE2, TIFF) += $(FATE_TIFF)
-FATE_SAMPLES_AVCONV += $(FATE_TIFF-yes)
+FATE_IMAGE += $(FATE_TIFF-yes)
fate-tiff: $(FATE_TIFF-yes)
+FATE_IMAGE-$(call DEMDEC, IMAGE2, XFACE) += fate-xface
+fate-xface: CMD = framecrc -i $(TARGET_SAMPLES)/xface/lena.xface
+
FATE_XBM += fate-xbm10
fate-xbm10: CMD = framecrc -i $(TARGET_SAMPLES)/xbm/xl.xbm
@@ -188,5 +191,10 @@ FATE_XBM += fate-xbm11
fate-xbm11: CMD = framecrc -i $(TARGET_SAMPLES)/xbm/lbw.xbm
FATE_XBM-$(call DEMDEC, IMAGE2, XBM) += $(FATE_XBM)
-FATE_SAMPLES_AVCONV += $(FATE_XBM-yes)
+FATE_IMAGE += $(FATE_XBM-yes)
fate-xbm: $(FATE_XBM-yes)
+
+FATE_IMAGE += $(FATE_IMAGE-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_IMAGE)
+fate-image: $(FATE_IMAGE)
diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak
index 138a1b2dcf..ae8ef47828 100644
--- a/tests/fate/libavcodec.mak
+++ b/tests/fate/libavcodec.mak
@@ -1,3 +1,8 @@
+FATE_LIBAVCODEC-$(CONFIG_CABAC) += fate-cabac
+fate-cabac: libavcodec/cabac-test$(EXESUF)
+fate-cabac: CMD = run libavcodec/cabac-test
+fate-cabac: REF = /dev/null
+
FATE_LIBAVCODEC-$(CONFIG_GOLOMB) += fate-golomb
fate-golomb: libavcodec/golomb-test$(EXESUF)
fate-golomb: CMD = run libavcodec/golomb-test
@@ -13,11 +18,27 @@ FATE_LIBAVCODEC-$(CONFIG_IIRFILTER) += fate-iirfilter
fate-iirfilter: libavcodec/iirfilter-test$(EXESUF)
fate-iirfilter: CMD = run libavcodec/iirfilter-test
+FATE_LIBAVCODEC-yes += fate-libavcodec-options
+fate-libavcodec-options: libavcodec/options-test$(EXESUF)
+fate-libavcodec-options: CMD = run libavcodec/options-test
+
FATE_LIBAVCODEC-$(CONFIG_RANGECODER) += fate-rangecoder
fate-rangecoder: libavcodec/rangecoder-test$(EXESUF)
fate-rangecoder: CMD = run libavcodec/rangecoder-test
fate-rangecoder: CMP = null
fate-rangecoder: REF = /dev/null
+FATE_LIBAVCODEC-yes += fate-mathops
+fate-mathops: libavcodec/mathops-test$(EXESUF)
+fate-mathops: CMD = run libavcodec/mathops-test
+fate-mathops: CMP = null
+fate-mathops: REF = /dev/null
+
+FATE_LIBAVCODEC-$(call ENCDEC, FLAC, FLAC) += fate-api-flac
+fate-api-flac: libavcodec/api-flac-test$(EXESUF)
+fate-api-flac: CMD = run libavcodec/api-flac-test
+fate-api-flac: CMP = null
+fate-api-flac: REF = /dev/null
+
FATE-$(CONFIG_AVCODEC) += $(FATE_LIBAVCODEC-yes)
fate-libavcodec: $(FATE_LIBAVCODEC-yes)
diff --git a/tests/fate/libavresample.mak b/tests/fate/libavresample.mak
index 4a48c9c042..c854a477ac 100644
--- a/tests/fate/libavresample.mak
+++ b/tests/fate/libavresample.mak
@@ -9,7 +9,7 @@ MIX_CHANNELS = 1 2 3 4 5 6 7 8
define MIX
FATE_LAVR_MIX += fate-lavr-mix-$(3)-$(1)-$(2)
fate-lavr-mix-$(3)-$(1)-$(2): tests/data/asynth-44100-$(1).wav
-fate-lavr-mix-$(3)-$(1)-$(2): CMD = avconv -i $(TARGET_PATH)/tests/data/asynth-44100-$(1).wav -ac $(2) -mix_coeff_type $(3) -internal_sample_fmt $(4) -f s16le -af atrim=end_sample=1024 -
+fate-lavr-mix-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-$(1).wav -ac $(2) -mix_coeff_type $(3) -internal_sample_fmt $(4) -f s16le -af atrim=end_sample=1024 -
fate-lavr-mix-$(3)-$(1)-$(2): CMP = oneoff
fate-lavr-mix-$(3)-$(1)-$(2): REF = $(SAMPLES)/lavr/lavr-mix-$(3)-$(1)-$(2)
endef
@@ -22,19 +22,19 @@ $(call CROSS_TEST,$(MIX_CHANNELS),MIX,flt,fltp)
FATE_LAVR_MIX-$(call FILTERDEMDECENCMUX, CHANNELMAP RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-lavr-mix-output-zero
fate-lavr-mix-output-zero: tests/data/filtergraphs/lavr_mix_output_zero tests/data/asynth-44100-4.wav
fate-lavr-mix-output-zero: CMP = oneoff
-fate-lavr-mix-output-zero: CMD = avconv -i $(TARGET_PATH)/tests/data/asynth-44100-4.wav -filter_script $(TARGET_PATH)/tests/data/filtergraphs/lavr_mix_output_zero -f s16le -
+fate-lavr-mix-output-zero: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-4.wav -filter_script $(TARGET_PATH)/tests/data/filtergraphs/lavr_mix_output_zero -f s16le -
fate-lavr-mix-output-zero: REF = $(SAMPLES)/lavr/lavr-mix-output-zero
FATE_LAVR_MIX-$(call FILTERDEMDECENCMUX, RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_LAVR_MIX)
fate-lavr-mix: $(FATE_LAVR_MIX-yes)
-FATE_LAVR += $(FATE_LAVR_MIX-yes)
+#FATE_LAVR += $(FATE_LAVR_MIX-yes)
SAMPLERATES = 2626 8000 44100 48000 96000
define RESAMPLE
FATE_LAVR_RESAMPLE += fate-lavr-resample-$(3)-$(1)-$(2)
fate-lavr-resample-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav
-fate-lavr-resample-$(3)-$(1)-$(2): CMD = avconv -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -ar $(2) -internal_sample_fmt $(3) -f $(4) -af atrim=end_sample=10240 -
+fate-lavr-resample-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -ar $(2) -internal_sample_fmt $(3) -f $(4) -af atrim=end_sample=10240 -
fate-lavr-resample-$(3)-$(1)-$(2): CMP = oneoff
fate-lavr-resample-$(3)-$(1)-$(2): CMP_UNIT = $(5)
fate-lavr-resample-$(3)-$(1)-$(2): FUZZ = 6
@@ -48,21 +48,21 @@ $(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,dblp,f64le,f64)
FATE_LAVR_RESAMPLE += fate-lavr-resample-linear
fate-lavr-resample-linear: tests/data/asynth-44100-1.wav
-fate-lavr-resample-linear: CMD = avconv -i $(TARGET_PATH)/tests/data/asynth-44100-1.wav -ar 48000 -filter_size 32 -linear_interp 1 -f s16le -af atrim=end_sample=10240 -
+fate-lavr-resample-linear: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-1.wav -ar 48000 -filter_size 32 -linear_interp 1 -f s16le -af atrim=end_sample=10240 -
fate-lavr-resample-linear: CMP = oneoff
fate-lavr-resample-linear: CMP_UNIT = s16
fate-lavr-resample-linear: REF = $(SAMPLES)/lavr/lavr-resample-linear
FATE_LAVR_RESAMPLE += fate-lavr-resample-nearest
fate-lavr-resample-nearest: tests/data/asynth-48000-1.wav
-fate-lavr-resample-nearest: CMD = avconv -i $(TARGET_PATH)/tests/data/asynth-48000-1.wav -ar 44100 -filter_size 0 -phase_shift 0 -f s16le -af atrim=end_sample=10240 -
+fate-lavr-resample-nearest: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-48000-1.wav -ar 44100 -filter_size 0 -phase_shift 0 -f s16le -af atrim=end_sample=10240 -
fate-lavr-resample-nearest: CMP = oneoff
fate-lavr-resample-nearest: CMP_UNIT = s16
fate-lavr-resample-nearest: REF = $(SAMPLES)/lavr/lavr-resample-nearest
FATE_LAVR_RESAMPLE-$(call FILTERDEMDECENCMUX, RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_LAVR_RESAMPLE)
fate-lavr-resample: $(FATE_LAVR_RESAMPLE-yes)
-FATE_LAVR += $(FATE_LAVR_RESAMPLE-yes)
+#FATE_LAVR += $(FATE_LAVR_RESAMPLE-yes)
FATE_SAMPLES_AVCONV += $(FATE_LAVR)
fate-lavr: $(FATE_LAVR)
diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak
index 7f3329b1d5..ff052e060d 100644
--- a/tests/fate/libavutil.mak
+++ b/tests/fate/libavutil.mak
@@ -8,6 +8,16 @@ fate-aes: libavutil/aes-test$(EXESUF)
fate-aes: CMD = run libavutil/aes-test
fate-aes: REF = /dev/null
+FATE_LIBAVUTIL += fate-camellia
+fate-camellia: libavutil/camellia-test$(EXESUF)
+fate-camellia: CMD = run libavutil/camellia-test
+fate-camellia: REF = /dev/null
+
+FATE_LIBAVUTIL += fate-cast5
+fate-cast5: libavutil/cast5-test$(EXESUF)
+fate-cast5: CMD = run libavutil/cast5-test
+fate-cast5: REF = /dev/null
+
FATE_LIBAVUTIL += fate-atomic
fate-atomic: libavutil/atomic-test$(EXESUF)
fate-atomic: CMD = run libavutil/atomic-test
@@ -25,9 +35,13 @@ FATE_LIBAVUTIL += fate-blowfish
fate-blowfish: libavutil/blowfish-test$(EXESUF)
fate-blowfish: CMD = run libavutil/blowfish-test
+FATE_LIBAVUTIL += fate-bprint
+fate-bprint: libavutil/bprint-test$(EXESUF)
+fate-bprint: CMD = run libavutil/bprint-test
+
FATE_LIBAVUTIL += fate-cpu
fate-cpu: libavutil/cpu-test$(EXESUF)
-fate-cpu: CMD = run libavutil/cpu-test $(CPUFLAGS:%=-c%) $(THREADS:%=-t%)
+fate-cpu: CMD = runecho libavutil/cpu-test $(CPUFLAGS:%=-c%) $(THREADS:%=-t%)
fate-cpu: REF = /dev/null
FATE_LIBAVUTIL += fate-crc
@@ -39,6 +53,10 @@ fate-des: libavutil/des-test$(EXESUF)
fate-des: CMD = run libavutil/des-test
fate-des: REF = /dev/null
+FATE_LIBAVUTIL += fate-dict
+fate-dict: libavutil/dict-test$(EXESUF)
+fate-dict: CMD = run libavutil/dict-test
+
FATE_LIBAVUTIL += fate-eval
fate-eval: libavutil/eval-test$(EXESUF)
fate-eval: CMD = run libavutil/eval-test
@@ -49,7 +67,7 @@ fate-fifo: CMD = run libavutil/fifo-test
FATE_LIBAVUTIL += fate-float-dsp
fate-float-dsp: libavutil/float_dsp-test$(EXESUF)
-fate-float-dsp: CMD = run libavutil/float_dsp-test
+fate-float-dsp: CMD = run libavutil/float_dsp-test $(CPUFLAGS:%=-c%)
fate-float-dsp: CMP = null
fate-float-dsp: REF = /dev/null
@@ -61,22 +79,52 @@ FATE_LIBAVUTIL += fate-md5
fate-md5: libavutil/md5-test$(EXESUF)
fate-md5: CMD = run libavutil/md5-test
+FATE_LIBAVUTIL += fate-murmur3
+fate-murmur3: libavutil/murmur3-test$(EXESUF)
+fate-murmur3: CMD = run libavutil/murmur3-test
+
FATE_LIBAVUTIL += fate-parseutils
fate-parseutils: libavutil/parseutils-test$(EXESUF)
fate-parseutils: CMD = run libavutil/parseutils-test
+FATE_LIBAVUTIL-$(CONFIG_PIXELUTILS) += fate-pixelutils
+fate-pixelutils: libavutil/pixelutils-test$(EXESUF)
+fate-pixelutils: CMD = run libavutil/pixelutils-test
+
+FATE_LIBAVUTIL += fate-random_seed
+fate-random_seed: libavutil/random_seed-test$(EXESUF)
+fate-random_seed: CMD = run libavutil/random_seed-test
+
+FATE_LIBAVUTIL += fate-ripemd
+fate-ripemd: libavutil/ripemd-test$(EXESUF)
+fate-ripemd: CMD = run libavutil/ripemd-test
+
FATE_LIBAVUTIL += fate-sha
fate-sha: libavutil/sha-test$(EXESUF)
fate-sha: CMD = run libavutil/sha-test
+FATE_LIBAVUTIL += fate-sha512
+fate-sha512: libavutil/sha512-test$(EXESUF)
+fate-sha512: CMD = run libavutil/sha512-test
+
FATE_LIBAVUTIL += fate-tree
fate-tree: libavutil/tree-test$(EXESUF)
fate-tree: CMD = run libavutil/tree-test
fate-tree: REF = /dev/null
+FATE_LIBAVUTIL += fate-twofish
+fate-twofish: libavutil/twofish-test$(EXESUF)
+fate-twofish: CMD = run libavutil/twofish-test
+fate-twofish: REF = /dev/null
+
FATE_LIBAVUTIL += fate-xtea
fate-xtea: libavutil/xtea-test$(EXESUF)
fate-xtea: CMD = run libavutil/xtea-test
+FATE_LIBAVUTIL += fate-opt
+fate-opt: libavutil/opt-test$(EXESUF)
+fate-opt: CMD = run libavutil/opt-test
+
+FATE_LIBAVUTIL += $(FATE_LIBAVUTIL-yes)
FATE-$(CONFIG_AVUTIL) += $(FATE_LIBAVUTIL)
fate-libavutil: $(FATE_LIBAVUTIL)
diff --git a/tests/fate/libswresample.mak b/tests/fate/libswresample.mak
new file mode 100644
index 0000000000..24b7d665dc
--- /dev/null
+++ b/tests/fate/libswresample.mak
@@ -0,0 +1,401 @@
+CROSS_TEST = $(foreach I,$(1), \
+ $(foreach J,$(1), \
+ $(if $(filter-out $(I),$(J)), \
+ $(eval $(call $(2),$(I),$(J),$(3),$(4),$(5))), \
+ )))
+
+
+SAMPLERATES = 2626 8000 44100 48000 96000
+
+SAMPLERATES_LITE = 8000 44100 48000
+
+SAMPLERATES_NN = 8000 44100
+
+define ARESAMPLE
+FATE_SWR_RESAMPLE += fate-swr-resample-$(3)-$(1)-$(2)
+fate-swr-resample-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav
+fate-swr-resample-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -af atrim=end_sample=10240,aresample=$(2):internal_sample_fmt=$(3),aformat=$(3),aresample=$(1):internal_sample_fmt=$(3) -f wav -acodec pcm_s16le -
+
+fate-swr-resample-$(3)-$(1)-$(2): CMP = stddev
+fate-swr-resample-$(3)-$(1)-$(2): CMP_UNIT = $(5)
+fate-swr-resample-$(3)-$(1)-$(2): FUZZ = 0.1
+fate-swr-resample-$(3)-$(1)-$(2): REF = tests/data/asynth-$(1)-1.wav
+endef
+
+#below list is generated by:
+#you can use this if you need to update it!
+#make -k `make fate-list | grep swr` | egrep 'TEST|stddev' | tr '\n' '@' | sed 's#TEST *\([^@]*\)@stddev: *\([0-9.]*\)[^b@]*bytes: *\([0-9]*\) */ *\([0-9]*\)@#fate-\1: CMP_TARGET = \2@fate-\1: SIZE_TOLERANCE = \3 - \4@@#g' | tr '@' '\n'
+
+fate-swr-resample-dblp-2626-44100: CMP_TARGET = 1393.01
+fate-swr-resample-dblp-2626-44100: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-dblp-2626-48000: CMP_TARGET = 1393.01
+fate-swr-resample-dblp-2626-48000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-dblp-2626-8000: CMP_TARGET = 1393.90
+fate-swr-resample-dblp-2626-8000: SIZE_TOLERANCE = 31512 - 20482
+
+fate-swr-resample-dblp-2626-96000: CMP_TARGET = 1393.01
+fate-swr-resample-dblp-2626-96000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-dblp-44100-2626: CMP_TARGET = 185.84
+fate-swr-resample-dblp-44100-2626: SIZE_TOLERANCE = 529200 - 20490
+
+fate-swr-resample-dblp-44100-48000: CMP_TARGET = 9.70
+fate-swr-resample-dblp-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-dblp-44100-8000: CMP_TARGET = 75.46
+fate-swr-resample-dblp-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample-dblp-44100-96000: CMP_TARGET = 11.47
+fate-swr-resample-dblp-44100-96000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-dblp-48000-2626: CMP_TARGET = 456.55
+fate-swr-resample-dblp-48000-2626: SIZE_TOLERANCE = 576000 - 20510
+
+fate-swr-resample-dblp-48000-44100: CMP_TARGET = 1.16
+fate-swr-resample-dblp-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-dblp-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample-dblp-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample-dblp-48000-96000: CMP_TARGET = 0.47
+fate-swr-resample-dblp-48000-96000: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-dblp-8000-2626: CMP_TARGET = 2506.01
+fate-swr-resample-dblp-8000-2626: SIZE_TOLERANCE = 96000 - 20486
+
+fate-swr-resample-dblp-8000-44100: CMP_TARGET = 15.09
+fate-swr-resample-dblp-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-dblp-8000-48000: CMP_TARGET = 14.68
+fate-swr-resample-dblp-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-dblp-8000-96000: CMP_TARGET = 13.82
+fate-swr-resample-dblp-8000-96000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-dblp-96000-2626: CMP_TARGET = 675.14
+fate-swr-resample-dblp-96000-2626: SIZE_TOLERANCE = 1152000 - 20474
+
+fate-swr-resample-dblp-96000-44100: CMP_TARGET = 1.58
+fate-swr-resample-dblp-96000-44100: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-dblp-96000-48000: CMP_TARGET = 1.04
+fate-swr-resample-dblp-96000-48000: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-dblp-96000-8000: CMP_TARGET = 58.60
+fate-swr-resample-dblp-96000-8000: SIZE_TOLERANCE = 1152000 - 20496
+
+fate-swr-resample-fltp-2626-44100: CMP_TARGET = 1393.01
+fate-swr-resample-fltp-2626-44100: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-fltp-2626-48000: CMP_TARGET = 1393.01
+fate-swr-resample-fltp-2626-48000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-fltp-2626-8000: CMP_TARGET = 1393.90
+fate-swr-resample-fltp-2626-8000: SIZE_TOLERANCE = 31512 - 20482
+
+fate-swr-resample-fltp-2626-96000: CMP_TARGET = 1393.01
+fate-swr-resample-fltp-2626-96000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-fltp-44100-2626: CMP_TARGET = 185.84
+fate-swr-resample-fltp-44100-2626: SIZE_TOLERANCE = 529200 - 20490
+
+fate-swr-resample-fltp-44100-48000: CMP_TARGET = 9.70
+fate-swr-resample-fltp-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-fltp-44100-8000: CMP_TARGET = 75.46
+fate-swr-resample-fltp-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample-fltp-44100-96000: CMP_TARGET = 11.47
+fate-swr-resample-fltp-44100-96000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-fltp-48000-2626: CMP_TARGET = 456.55
+fate-swr-resample-fltp-48000-2626: SIZE_TOLERANCE = 576000 - 20510
+
+fate-swr-resample-fltp-48000-44100: CMP_TARGET = 1.16
+fate-swr-resample-fltp-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-fltp-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample-fltp-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample-fltp-48000-96000: CMP_TARGET = 0.47
+fate-swr-resample-fltp-48000-96000: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-fltp-8000-2626: CMP_TARGET = 2506.01
+fate-swr-resample-fltp-8000-2626: SIZE_TOLERANCE = 96000 - 20486
+
+fate-swr-resample-fltp-8000-44100: CMP_TARGET = 15.09
+fate-swr-resample-fltp-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-fltp-8000-48000: CMP_TARGET = 14.68
+fate-swr-resample-fltp-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-fltp-8000-96000: CMP_TARGET = 13.82
+fate-swr-resample-fltp-8000-96000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-fltp-96000-2626: CMP_TARGET = 675.14
+fate-swr-resample-fltp-96000-2626: SIZE_TOLERANCE = 1152000 - 20474
+
+fate-swr-resample-fltp-96000-44100: CMP_TARGET = 1.58
+fate-swr-resample-fltp-96000-44100: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-fltp-96000-48000: CMP_TARGET = 1.04
+fate-swr-resample-fltp-96000-48000: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-fltp-96000-8000: CMP_TARGET = 58.60
+fate-swr-resample-fltp-96000-8000: SIZE_TOLERANCE = 1152000 - 20496
+
+fate-swr-resample-s16p-2626-44100: CMP_TARGET = 1393.01
+fate-swr-resample-s16p-2626-44100: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-s16p-2626-48000: CMP_TARGET = 1392.99
+fate-swr-resample-s16p-2626-48000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-s16p-2626-8000: CMP_TARGET = 1393.90
+fate-swr-resample-s16p-2626-8000: SIZE_TOLERANCE = 31512 - 20482
+
+fate-swr-resample-s16p-2626-96000: CMP_TARGET = 1393.08
+fate-swr-resample-s16p-2626-96000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-s16p-44100-2626: CMP_TARGET = 185.84
+fate-swr-resample-s16p-44100-2626: SIZE_TOLERANCE = 529200 - 20490
+
+fate-swr-resample-s16p-44100-48000: CMP_TARGET = 9.71
+fate-swr-resample-s16p-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-s16p-44100-8000: CMP_TARGET = 75.46
+fate-swr-resample-s16p-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample-s16p-44100-96000: CMP_TARGET = 11.48
+fate-swr-resample-s16p-44100-96000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-s16p-48000-2626: CMP_TARGET = 456.55
+fate-swr-resample-s16p-48000-2626: SIZE_TOLERANCE = 576000 - 20510
+
+fate-swr-resample-s16p-48000-44100: CMP_TARGET = 1.22
+fate-swr-resample-s16p-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-s16p-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample-s16p-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample-s16p-48000-96000: CMP_TARGET = 0.50
+fate-swr-resample-s16p-48000-96000: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-s16p-8000-2626: CMP_TARGET = 2506.02
+fate-swr-resample-s16p-8000-2626: SIZE_TOLERANCE = 96000 - 20486
+
+fate-swr-resample-s16p-8000-44100: CMP_TARGET = 15.12
+fate-swr-resample-s16p-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-s16p-8000-48000: CMP_TARGET = 14.69
+fate-swr-resample-s16p-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-s16p-8000-96000: CMP_TARGET = 13.83
+fate-swr-resample-s16p-8000-96000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-s16p-96000-2626: CMP_TARGET = 675.14
+fate-swr-resample-s16p-96000-2626: SIZE_TOLERANCE = 1152000 - 20474
+
+fate-swr-resample-s16p-96000-44100: CMP_TARGET = 1.62
+fate-swr-resample-s16p-96000-44100: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-s16p-96000-48000: CMP_TARGET = 1.03
+fate-swr-resample-s16p-96000-48000: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-s16p-96000-8000: CMP_TARGET = 58.60
+fate-swr-resample-s16p-96000-8000: SIZE_TOLERANCE = 1152000 - 20496
+
+fate-swr-resample-s32p-2626-44100: CMP_TARGET = 1393.01
+fate-swr-resample-s32p-2626-44100: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-s32p-2626-48000: CMP_TARGET = 1393.01
+fate-swr-resample-s32p-2626-48000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-s32p-2626-8000: CMP_TARGET = 1393.90
+fate-swr-resample-s32p-2626-8000: SIZE_TOLERANCE = 31512 - 20482
+
+fate-swr-resample-s32p-2626-96000: CMP_TARGET = 1393.01
+fate-swr-resample-s32p-2626-96000: SIZE_TOLERANCE = 31512 - 20480
+
+fate-swr-resample-s32p-44100-2626: CMP_TARGET = 185.84
+fate-swr-resample-s32p-44100-2626: SIZE_TOLERANCE = 529200 - 20490
+
+fate-swr-resample-s32p-44100-48000: CMP_TARGET = 9.70
+fate-swr-resample-s32p-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-s32p-44100-8000: CMP_TARGET = 75.46
+fate-swr-resample-s32p-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample-s32p-44100-96000: CMP_TARGET = 11.47
+fate-swr-resample-s32p-44100-96000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample-s32p-48000-2626: CMP_TARGET = 456.55
+fate-swr-resample-s32p-48000-2626: SIZE_TOLERANCE = 576000 - 20510
+
+fate-swr-resample-s32p-48000-44100: CMP_TARGET = 1.16
+fate-swr-resample-s32p-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-s32p-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample-s32p-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample-s32p-48000-96000: CMP_TARGET = 0.47
+fate-swr-resample-s32p-48000-96000: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample-s32p-8000-2626: CMP_TARGET = 2506.01
+fate-swr-resample-s32p-8000-2626: SIZE_TOLERANCE = 96000 - 20486
+
+fate-swr-resample-s32p-8000-44100: CMP_TARGET = 15.09
+fate-swr-resample-s32p-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-s32p-8000-48000: CMP_TARGET = 14.68
+fate-swr-resample-s32p-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-s32p-8000-96000: CMP_TARGET = 13.82
+fate-swr-resample-s32p-8000-96000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample-s32p-96000-2626: CMP_TARGET = 675.14
+fate-swr-resample-s32p-96000-2626: SIZE_TOLERANCE = 1152000 - 20474
+
+fate-swr-resample-s32p-96000-44100: CMP_TARGET = 1.58
+fate-swr-resample-s32p-96000-44100: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-s32p-96000-48000: CMP_TARGET = 1.04
+fate-swr-resample-s32p-96000-48000: SIZE_TOLERANCE = 1152000 - 20480
+
+fate-swr-resample-s32p-96000-8000: CMP_TARGET = 58.60
+fate-swr-resample-s32p-96000-8000: SIZE_TOLERANCE = 1152000 - 20496
+
+define ARESAMPLE_LIN
+FATE_SWR_RESAMPLE += fate-swr-resample_lin-$(3)-$(1)-$(2)
+fate-swr-resample_lin-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav
+fate-swr-resample_lin-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -af atrim=end_sample=10240,aresample=$(2):linear_interp=1:internal_sample_fmt=$(3),aformat=$(3),aresample=$(1):linear_interp=1:internal_sample_fmt=$(3) -f wav -acodec pcm_s16le -
+
+fate-swr-resample_lin-$(3)-$(1)-$(2): CMP = stddev
+fate-swr-resample_lin-$(3)-$(1)-$(2): CMP_UNIT = $(5)
+fate-swr-resample_lin-$(3)-$(1)-$(2): FUZZ = 0.1
+fate-swr-resample_lin-$(3)-$(1)-$(2): REF = tests/data/asynth-$(1)-1.wav
+endef
+
+fate-swr-resample_lin-s16p-8000-44100: CMP_TARGET = 14.63
+fate-swr-resample_lin-s16p-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_lin-s16p-8000-48000: CMP_TARGET = 14.53
+fate-swr-resample_lin-s16p-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_lin-s16p-44100-8000: CMP_TARGET = 75.45
+fate-swr-resample_lin-s16p-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample_lin-s16p-44100-48000: CMP_TARGET = 9.68
+fate-swr-resample_lin-s16p-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample_lin-s16p-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample_lin-s16p-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample_lin-s16p-48000-44100: CMP_TARGET = 0.68
+fate-swr-resample_lin-s16p-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample_lin-fltp-8000-44100: CMP_TARGET = 14.61
+fate-swr-resample_lin-fltp-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_lin-fltp-8000-48000: CMP_TARGET = 14.50
+fate-swr-resample_lin-fltp-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_lin-fltp-44100-8000: CMP_TARGET = 75.45
+fate-swr-resample_lin-fltp-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample_lin-fltp-44100-48000: CMP_TARGET = 9.67
+fate-swr-resample_lin-fltp-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample_lin-fltp-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample_lin-fltp-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample_lin-fltp-48000-44100: CMP_TARGET = 0.63
+fate-swr-resample_lin-fltp-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+fate-swr-resample_lin-dblp-8000-44100: CMP_TARGET = 14.61
+fate-swr-resample_lin-dblp-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_lin-dblp-8000-48000: CMP_TARGET = 14.50
+fate-swr-resample_lin-dblp-8000-48000: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_lin-dblp-44100-8000: CMP_TARGET = 75.45
+fate-swr-resample_lin-dblp-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample_lin-dblp-44100-48000: CMP_TARGET = 9.67
+fate-swr-resample_lin-dblp-44100-48000: SIZE_TOLERANCE = 529200 - 20482
+
+fate-swr-resample_lin-dblp-48000-8000: CMP_TARGET = 62.41
+fate-swr-resample_lin-dblp-48000-8000: SIZE_TOLERANCE = 576000 - 20484
+
+fate-swr-resample_lin-dblp-48000-44100: CMP_TARGET = 0.63
+fate-swr-resample_lin-dblp-48000-44100: SIZE_TOLERANCE = 576000 - 20480
+
+define ARESAMPLE_NN
+FATE_SWR_RESAMPLE += fate-swr-resample_nn-$(3)-$(1)-$(2)
+fate-swr-resample_nn-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav
+fate-swr-resample_nn-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -af atrim=end_sample=10240,aresample=$(2):filter_size=1:phase_shift=0:internal_sample_fmt=$(3),aformat=$(3),aresample=$(1):internal_sample_fmt=$(3) -f wav -acodec pcm_s16le -
+
+fate-swr-resample_nn-$(3)-$(1)-$(2): CMP = stddev
+fate-swr-resample_nn-$(3)-$(1)-$(2): CMP_UNIT = $(5)
+fate-swr-resample_nn-$(3)-$(1)-$(2): FUZZ = 0.1
+fate-swr-resample_nn-$(3)-$(1)-$(2): REF = tests/data/asynth-$(1)-1.wav
+endef
+
+fate-swr-resample_nn-fltp-44100-8000: CMP_TARGET = 590.98
+fate-swr-resample_nn-fltp-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample_nn-fltp-8000-44100: CMP_TARGET = 3163.32
+fate-swr-resample_nn-fltp-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+fate-swr-resample_nn-s16p-44100-8000: CMP_TARGET = 590.97
+fate-swr-resample_nn-s16p-44100-8000: SIZE_TOLERANCE = 529200 - 20486
+
+fate-swr-resample_nn-s16p-8000-44100: CMP_TARGET = 3163.39
+fate-swr-resample_nn-s16p-8000-44100: SIZE_TOLERANCE = 96000 - 20480
+
+define ARESAMPLE_ASYNC
+FATE_SWR_RESAMPLE += fate-swr-resample_async-$(3)-$(1)-$(2)
+fate-swr-resample_async-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav
+fate-swr-resample_async-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -af atrim=end_sample=10240,asetpts=PTS+random\(0\)*200-100,aresample=$(2):async=50:min_hard_comp=0.100000:first_pts=0:internal_sample_fmt=$(3),aformat=$(3),aresample=$(1):internal_sample_fmt=$(3) -f wav -acodec pcm_s16le -
+
+fate-swr-resample_async-$(3)-$(1)-$(2): CMP = stddev
+fate-swr-resample_async-$(3)-$(1)-$(2): CMP_UNIT = $(5)
+fate-swr-resample_async-$(3)-$(1)-$(2): FUZZ = 0.1
+fate-swr-resample_async-$(3)-$(1)-$(2): REF = tests/data/asynth-$(1)-1.wav
+endef
+
+fate-swr-resample_async-fltp-44100-8000: CMP_TARGET = 4031.60
+fate-swr-resample_async-fltp-44100-8000: SIZE_TOLERANCE = 529200 - 20310
+
+fate-swr-resample_async-fltp-8000-44100: CMP_TARGET = 11185.34
+fate-swr-resample_async-fltp-8000-44100: SIZE_TOLERANCE = 96000 - 20344
+
+fate-swr-resample_async-s16p-44100-8000: CMP_TARGET = 4031.59
+fate-swr-resample_async-s16p-44100-8000: SIZE_TOLERANCE = 529200 - 20310
+
+fate-swr-resample_async-s16p-8000-44100: CMP_TARGET = 11185.65
+fate-swr-resample_async-s16p-8000-44100: SIZE_TOLERANCE = 96000 - 20344
+
+$(call CROSS_TEST,$(SAMPLERATES),ARESAMPLE,s16p,s16le,s16)
+$(call CROSS_TEST,$(SAMPLERATES),ARESAMPLE,s32p,s32le,s16)
+$(call CROSS_TEST,$(SAMPLERATES),ARESAMPLE,fltp,f32le,s16)
+$(call CROSS_TEST,$(SAMPLERATES),ARESAMPLE,dblp,f64le,s16)
+
+$(call CROSS_TEST,$(SAMPLERATES_LITE),ARESAMPLE_LIN,s16p,s16le,s16)
+$(call CROSS_TEST,$(SAMPLERATES_LITE),ARESAMPLE_LIN,fltp,f32le,s16)
+$(call CROSS_TEST,$(SAMPLERATES_LITE),ARESAMPLE_LIN,dblp,f64le,s16)
+
+$(call CROSS_TEST,$(SAMPLERATES_NN),ARESAMPLE_NN,s16p,s16le,s16)
+$(call CROSS_TEST,$(SAMPLERATES_NN),ARESAMPLE_NN,fltp,f32le,s16)
+
+$(call CROSS_TEST,$(SAMPLERATES_NN),ARESAMPLE_ASYNC,s16p,s16le,s16)
+$(call CROSS_TEST,$(SAMPLERATES_NN),ARESAMPLE_ASYNC,fltp,f32le,s16)
+
+
+FATE_SWR_RESAMPLE-$(call FILTERDEMDECENCMUX, ARESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_SWR_RESAMPLE)
+fate-swr-resample: $(FATE_SWR_RESAMPLE-yes)
+FATE_SWR += $(FATE_SWR_RESAMPLE-yes)
+
+FATE_FFMPEG += $(FATE_SWR)
+fate-swr: $(FATE_SWR)
diff --git a/tests/fate/lossless-audio.mak b/tests/fate/lossless-audio.mak
index 751c7210e8..1d278da0e4 100644
--- a/tests/fate/lossless-audio.mak
+++ b/tests/fate/lossless-audio.mak
@@ -1,28 +1,35 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, ALAC) += fate-lossless-alac
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, MOV, ALAC) += fate-lossless-alac
fate-lossless-alac: CMD = md5 -i $(TARGET_SAMPLES)/lossless-audio/inside.m4a -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MLP, MLP) += fate-lossless-meridianaudio
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, MLP, MLP) += fate-lossless-meridianaudio
fate-lossless-meridianaudio: CMD = md5 -i $(TARGET_SAMPLES)/lossless-audio/luckynight-partial.mlp -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RM, RALF) += fate-ralf
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, RM, RALF) += fate-ralf
fate-ralf: CMD = md5 -i $(TARGET_SAMPLES)/lossless-audio/luckynight-partial.rmvb -vn -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SHORTEN, SHORTEN) += fate-lossless-shorten
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, SHORTEN, SHORTEN) += fate-lossless-shorten
fate-lossless-shorten: CMD = md5 -i $(TARGET_SAMPLES)/lossless-audio/luckynight-partial.shn -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TAK, TAK) += fate-lossless-tak
-fate-lossless-tak: CMD = md5 -i $(TARGET_SAMPLES)/lossless-audio/luckynight-partial.tak -f s16le
-fate-lossless-tak: CMP = oneline
-fate-lossless-tak: REF = a28d4e5f2192057f7d4bece870f40bd0
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, TAK, TAK) += fate-lossless-tak
+fate-lossless-tak: CMD = crc -i $(TARGET_SAMPLES)/lossless-audio/luckynight-partial.tak
FATE_TRUEHD = fate-lossless-truehd-5.1 fate-lossless-truehd-5.1-downmix-2.0
fate-lossless-truehd-5.1: CMD = md5 -f truehd -i $(TARGET_SAMPLES)/lossless-audio/truehd_5.1.raw -f s32le
fate-lossless-truehd-5.1-downmix-2.0: CMD = md5 -f truehd -request_channel_layout 2 -i $(TARGET_SAMPLES)/lossless-audio/truehd_5.1.raw -f s32le
fate-lossless-truehd: $(FATE_TRUEHD)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TRUEHD, TRUEHD) += $(FATE_TRUEHD)
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, TRUEHD, TRUEHD) += $(FATE_TRUEHD)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TTA, TTA) += fate-lossless-tta
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, TTA, TTA) += fate-lossless-tta
fate-lossless-tta: CMD = crc -i $(TARGET_SAMPLES)/lossless-audio/inside.tta
-FATE_SAMPLES_AVCONV-$(call DEMDEC, ASF, WMALOSSLESS) += fate-lossless-wma
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, TTA, TTA) += fate-lossless-tta-encrypted
+fate-lossless-tta-encrypted: CMD = crc -password ffmpeg -i $(TARGET_SAMPLES)/lossless-audio/encrypted.tta
+
+FATE_SAMPLES_LOSSLESS_AUDIO-$(call DEMDEC, ASF, WMALOSSLESS) += fate-lossless-wma
fate-lossless-wma: CMD = md5 -i $(TARGET_SAMPLES)/lossless-audio/luckynight-partial.wma -f s16le
+
+FATE_SAMPLES_LOSSLESS_AUDIO += $(FATE_SAMPLES_LOSSLESS_AUDIO-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_LOSSLESS_AUDIO)
+fate-lossless-audio: $(FATE_SAMPLES_LOSSLESS_AUDIO)
+
diff --git a/tests/fate/lossless-video.mak b/tests/fate/lossless-video.mak
index d5b10b3154..514d6fdfea 100644
--- a/tests/fate/lossless-video.mak
+++ b/tests/fate/lossless-video.mak
@@ -7,7 +7,7 @@ fate-canopus-cllc-rgb: CMD = framecrc -i $(TARGET_SAMPLES)/cllc/sample-cllc-rgb.
FATE_CANOPUS_CLLC += fate-canopus-cllc-yuy2-noblock
fate-canopus-cllc-yuy2-noblock: CMD = framecrc -i $(TARGET_SAMPLES)/cllc/sample-cllc-yuy2-noblock.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, CLLC) += $(FATE_CANOPUS_CLLC)
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, CLLC) += $(FATE_CANOPUS_CLLC)
fate-canopus-cllc: $(FATE_CANOPUS_CLLC)
FATE_LAGARITH += fate-lagarith-rgb24
@@ -22,7 +22,10 @@ fate-lagarith-yuy2: CMD = framecrc -i $(TARGET_SAMPLES)/lagarith/lag-yuy2.avi
FATE_LAGARITH += fate-lagarith-yv12
fate-lagarith-yv12: CMD = framecrc -i $(TARGET_SAMPLES)/lagarith/lag-yv12.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, LAGARITH) += $(FATE_LAGARITH)
+FATE_LAGARITH += fate-lagarith-red
+fate-lagarith-red: CMD = framecrc -i $(TARGET_SAMPLES)/lagarith/lagarith-red.avi
+
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, LAGARITH) += $(FATE_LAGARITH)
fate-lagarith: $(FATE_LAGARITH)
FATE_LOCO += fate-loco-rgb
@@ -31,20 +34,25 @@ fate-loco-rgb: CMD = framecrc -i $(TARGET_SAMPLES)/loco/pig-loco-rgb.avi
FATE_LOCO += fate-loco-yuy2
fate-loco-yuy2: CMD = framecrc -i $(TARGET_SAMPLES)/loco/pig-loco-0.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, LOCO) += $(FATE_LOCO)
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, LOCO) += $(FATE_LOCO)
fate-loco: $(FATE_LOCO)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, MSRLE) += fate-msrle-8bit
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, MSRLE) += fate-msrle-8bit
fate-msrle-8bit: CMD = framecrc -i $(TARGET_SAMPLES)/msrle/Search-RLE.avi -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, MSZH) += fate-mszh
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, MSZH) += fate-mszh
fate-mszh: CMD = framecrc -i $(TARGET_SAMPLES)/lcl/mszh-1frame.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, VBLE) += fate-vble
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, VBLE) += fate-vble
fate-vble: CMD = framecrc -i $(TARGET_SAMPLES)/vble/flowers-partial-2MB.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, ZEROCODEC) += fate-zerocodec
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, ZEROCODEC) += fate-zerocodec
fate-zerocodec: CMD = framecrc -i $(TARGET_SAMPLES)/zerocodec/sample-zeco.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, ZLIB) += fate-zlib
+FATE_LOSSLESS_VIDEO-$(call DEMDEC, AVI, ZLIB) += fate-zlib
fate-zlib: CMD = framecrc -i $(TARGET_SAMPLES)/lcl/zlib-1frame.avi
+
+FATE_LOSSLESS_VIDEO += $(FATE_LOSSLESS_VIDEO-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_LOSSLESS_VIDEO)
+fate-lossless-video: $(FATE_LOSSLESS_VIDEO)
diff --git a/tests/fate/microsoft.mak b/tests/fate/microsoft.mak
index 10bbb30e9e..4e8ae51116 100644
--- a/tests/fate/microsoft.mak
+++ b/tests/fate/microsoft.mak
@@ -1,4 +1,4 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, MSMPEG4V1) += fate-msmpeg4v1
+FATE_MICROSOFT-$(call DEMDEC, AVI, MSMPEG4V1) += fate-msmpeg4v1
fate-msmpeg4v1: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/msmpeg4v1/mpg4.avi -an
FATE_MSS2 += fate-mss2-pal
@@ -25,7 +25,7 @@ fate-msvideo1-8bit: CMD = framecrc -i $(TARGET_SAMPLES)/cram/skating.avi -t 1 -p
FATE_MSVIDEO1 += fate-msvideo1-16bit
fate-msvideo1-16bit: CMD = framecrc -i $(TARGET_SAMPLES)/cram/clock-cram16.avi -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, MSVIDEO1) += $(FATE_MSVIDEO1)
+FATE_MICROSOFT-$(call DEMDEC, AVI, MSVIDEO1) += $(FATE_MSVIDEO1)
fate-msvideo1: $(FATE_MSVIDEO1)
FATE_WMV8_DRM += fate-wmv8-drm
@@ -35,7 +35,11 @@ fate-wmv8-drm: CMD = framecrc -cryptokey 137381538c84c068111902a59c5cf6c340247c3
FATE_WMV8_DRM += fate-wmv8-drm-nodec
fate-wmv8-drm-nodec: CMD = framecrc -cryptokey 137381538c84c068111902a59c5cf6c340247c39 -i $(TARGET_SAMPLES)/wmv8/wmv_drm.wmv -acodec copy -vcodec copy
-FATE_SAMPLES_AVCONV-$(call DEMDEC, ASF, WMV3) += $(FATE_WMV8_DRM)
+#FATE_MICROSOFT += fate-wmv8-x8intra
+FATE_TESTS-no += fate-wmv8-x8intra
+fate-wmv8-x8intra: CMD = framecrc -flags +bitexact -idct 19 -i $(TARGET_SAMPLES)/wmv8/wmv8_x8intra.wmv -an
+
+FATE_MICROSOFT-$(call DEMDEC, ASF, WMV3) += $(FATE_WMV8_DRM)
fate-wmv8_drm: $(FATE_WMV8_DRM)
FATE_VC1-$(CONFIG_VC1_DEMUXER) += fate-vc1_sa00040
@@ -59,5 +63,10 @@ fate-vc1_ilaced_twomv: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/vc1/
FATE_VC1-$(CONFIG_MOV_DEMUXER) += fate-vc1-ism
fate-vc1-ism: CMD = framecrc -i $(TARGET_SAMPLES)/isom/vc1-wmapro.ism -an
-FATE_SAMPLES_AVCONV-$(CONFIG_VC1_DECODER) += $(FATE_VC1-yes)
+FATE_MICROSOFT-$(CONFIG_VC1_DECODER) += $(FATE_VC1-yes)
fate-vc1: $(FATE_VC1-yes)
+
+FATE_MICROSOFT += $(FATE_MICROSOFT-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_MICROSOFT)
+fate-microsoft: $(FATE_MICROSOFT)
diff --git a/tests/fate/mp3.mak b/tests/fate/mp3.mak
index fe6a0e12eb..57ee08414b 100644
--- a/tests/fate/mp3.mak
+++ b/tests/fate/mp3.mak
@@ -33,6 +33,10 @@ fate-mp3-float-extra_overread: REF = $(SAMPLES)/mpegaudio/extra_overread.pcm
$(FATE_MP3): CMP = stddev
$(FATE_MP3): FUZZ = 0.07
+ifdef HAVE_NEON
+fate-mp3-float-conf-hecommon: FUZZ = 0.70
+endif
+
FATE_MP3-$(call DEMDEC, MP3, MP3FLOAT) += $(FATE_MP3)
FATE_SAMPLES_AVCONV += $(FATE_MP3-yes)
diff --git a/tests/fate/mpeg4.mak b/tests/fate/mpeg4.mak
index f9b94e6d1c..b24d21afbc 100644
--- a/tests/fate/mpeg4.mak
+++ b/tests/fate/mpeg4.mak
@@ -1,9 +1,12 @@
MPEG4_RESOLUTION_CHANGE = down-down down-up up-down up-up
-fate-mpeg4-resolution-change-%: CMD = framemd5 -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg4/resize_$(@:fate-mpeg4-resolution-change-%=%).h263
+fate-mpeg4-resolution-change-%: CMD = framemd5 -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg4/resize_$(@:fate-mpeg4-resolution-change-%=%).h263 -sws_flags +bitexact
FATE_MPEG4-$(call DEMDEC, H263, H263) := $(addprefix fate-mpeg4-resolution-change-, $(MPEG4_RESOLUTION_CHANGE))
+fate-mpeg4-bsf-unpack-bframes: CMD = md5 -i $(TARGET_SAMPLES)/mpeg4/packed_bframes.avi -flags +bitexact -c:v copy -bsf mpeg4_unpack_bframes -f avi
+FATE_MPEG4-$(call ALLYES, AVI_DEMUXER MPEG4_UNPACK_BFRAMES_BSF AVI_MUXER) += fate-mpeg4-bsf-unpack-bframes
+
FATE_SAMPLES_AVCONV += $(FATE_MPEG4-yes)
fate-mpeg4: $(FATE_MPEG4-yes)
diff --git a/tests/fate/mxf.mak b/tests/fate/mxf.mak
new file mode 100644
index 0000000000..6032c85ccb
--- /dev/null
+++ b/tests/fate/mxf.mak
@@ -0,0 +1,11 @@
+
+FATE_MXF += fate-mxf-missing-index-demux
+fate-mxf-missing-index-demux: CMD = crc -i $(TARGET_SAMPLES)/mxf/opatom_missing_index.mxf -acodec copy
+
+FATE_MXF += fate-mxf-essencegroup-demux
+fate-mxf-essencegroup-demux: CMD = framecrc -i $(TARGET_SAMPLES)/mxf/opatom_essencegroup_alpha_raw.mxf -vcodec copy
+
+FATE_MXF-$(CONFIG_MXF_DEMUXER) += $(FATE_MXF)
+
+FATE_SAMPLES_AVCONV += $(FATE_MXF-yes)
+fate-mxf: $(FATE_MXF-yes)
diff --git a/tests/fate/opus.mak b/tests/fate/opus.mak
index 161a94f472..b13d86c138 100644
--- a/tests/fate/opus.mak
+++ b/tests/fate/opus.mak
@@ -14,8 +14,8 @@ OPUS_SAMPLES = $(addprefix testvector, 08 09 10 12)
define FATE_OPUS_TEST
FATE_OPUS += fate-opus-$(1)
FATE_OPUS$(2) += fate-opus-$(1)
-fate-opus-$(1): CMD = avconv -i $(TARGET_SAMPLES)/opus/$(1).mka -f f32le -
-fate-opus-$(1): REF = $(SAMPLES)/opus/$(1).f32
+fate-opus-$(1): CMD = ffmpeg -i $(TARGET_SAMPLES)/opus/$(1).mka -f s16le -
+fate-opus-$(1): REF = $(SAMPLES)/opus/$(1).dec
endef
$(foreach N,$(OPUS_CELT_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),_CELT)))
@@ -26,8 +26,16 @@ $(foreach N,$(OPUS_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),)))
FATE_OPUS := $(sort $(FATE_OPUS))
$(FATE_OPUS): CMP = stddev
-$(FATE_OPUS): CMP_UNIT = f32
+$(FATE_OPUS): CMP_UNIT = s16
$(FATE_OPUS): FUZZ = 3
+fate-opus-testvector02: CMP_TARGET = 191
+fate-opus-testvector03: CMP_TARGET = 139
+fate-opus-testvector04: CMP_TARGET = 119
+fate-opus-testvector05: CMP_TARGET = 108
+fate-opus-testvector06: CMP_TARGET = 106
+fate-opus-testvector08: CMP_TARGET = 6
+fate-opus-testvector10: CMP_TARGET = 38
+fate-opus-testvector12: CMP_TARGET = 160
$(FATE_OPUS_CELT): CMP = oneoff
$(FATE_OPUS_CELT): FUZZ = 6
diff --git a/tests/fate/pcm.mak b/tests/fate/pcm.mak
index 116b50f10d..9ba4be50d0 100644
--- a/tests/fate/pcm.mak
+++ b/tests/fate/pcm.mak
@@ -1,32 +1,32 @@
-FATE_SAMPLES_PCM += fate-iff-pcm
+FATE_SAMPLES_PCM-$(call DEMDEC, WAV, PCM_U8) += fate-iff-pcm
fate-iff-pcm: CMD = md5 -i $(TARGET_SAMPLES)/iff/Bells -f s16le
-FATE_SAMPLES_PCM += fate-pcm_dvd
+FATE_SAMPLES_PCM-$(call DEMDEC, MPEGPS, PCM_DVD) += fate-pcm_dvd
fate-pcm_dvd: CMD = framecrc -i $(TARGET_SAMPLES)/pcm-dvd/coolitnow-partial.vob -vn
-FATE_SAMPLES_PCM += fate-pcm-planar
+FATE_SAMPLES_PCM-$(call DEMDEC, EA, PCM_S16LE_PLANAR) += fate-pcm-planar
fate-pcm-planar: CMD = framecrc -i $(TARGET_SAMPLES)/ea-mad/xeasport.mad -vn
-FATE_SAMPLES_PCM += fate-pcm_s16be-stereo
+FATE_SAMPLES_PCM-$(call DEMDEC, MOV, PCM_S16BE) += fate-pcm_s16be-stereo
fate-pcm_s16be-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-16-B-twos.mov -f s16le
-FATE_SAMPLES_PCM += fate-pcm_s16le-stereo
+FATE_SAMPLES_PCM-$(call DEMDEC, MOV, PCM_S16LE) += fate-pcm_s16le-stereo
fate-pcm_s16le-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-16-L-sowt.mov -f s16le
-FATE_SAMPLES_PCM += fate-pcm_u8-mono
+FATE_SAMPLES_PCM-$(call DEMDEC, MOV, PCM_U8) += fate-pcm_u8-mono
fate-pcm_u8-mono: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-1-8-raw.mov -f s16le
-FATE_SAMPLES_PCM += fate-pcm_u8-stereo
+FATE_SAMPLES_PCM-$(call DEMDEC, MOV, PCM_U8) += fate-pcm_u8-stereo
fate-pcm_u8-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-8-raw.mov -f s16le
-FATE_SAMPLES_PCM += fate-w64
+FATE_SAMPLES_PCM-$(call DEMDEC, W64, PCM_S16LE) += fate-w64
fate-w64: CMD = crc -i $(TARGET_SAMPLES)/w64/w64-pcm16.w64
-FATE_PCM += fate-dcinema-encode
+FATE_PCM-$(call ENCMUX, PCM_S24DAUD, DAUD) += fate-dcinema-encode
fate-dcinema-encode: tests/data/asynth-96000-6.wav
fate-dcinema-encode: SRC = tests/data/asynth-96000-6.wav
fate-dcinema-encode: CMD = enc_dec_pcm daud md5 s16le $(SRC) -c:a pcm_s24daud
-FATE_AVCONV += $(FATE_PCM)
-FATE_SAMPLES_AVCONV += $(FATE_SAMPLES_PCM)
-fate-pcm: $(FATE_PCM) $(FATE_SAMPLES_PCM)
+FATE_FFMPEG += $(FATE_PCM-yes)
+FATE_SAMPLES_AVCONV += $(FATE_SAMPLES_PCM-yes)
+fate-pcm: $(FATE_PCM-yes) $(FATE_SAMPLES_PCM-yes)
diff --git a/tests/fate/probe.mak b/tests/fate/probe.mak
index 376dfdd6a6..9f9dd4a926 100644
--- a/tests/fate/probe.mak
+++ b/tests/fate/probe.mak
@@ -1,18 +1,20 @@
-FATE_PROBE_FORMAT += fate-probe-format-roundup997
+FATE_PROBE_FORMAT-$(CONFIG_MPEGPS_DEMUXER) += fate-probe-format-roundup997
fate-probe-format-roundup997: REF = mpeg
-FATE_PROBE_FORMAT += fate-probe-format-roundup1383
+FATE_PROBE_FORMAT-$(CONFIG_MP3_DEMUXER) += fate-probe-format-roundup1383
fate-probe-format-roundup1383: REF = mp3
-FATE_PROBE_FORMAT += fate-probe-format-roundup1414
+FATE_PROBE_FORMAT-$(CONFIG_MPEGPS_DEMUXER) += fate-probe-format-roundup1414
fate-probe-format-roundup1414: REF = mpeg
-FATE_PROBE_FORMAT += fate-probe-format-roundup2015
+FATE_PROBE_FORMAT-$(CONFIG_DV_DEMUXER) += fate-probe-format-roundup2015
fate-probe-format-roundup2015: REF = dv
-FATE_SAMPLES-$(CONFIG_AVPROBE) += $(FATE_PROBE_FORMAT)
+FATE_PROBE_FORMAT = $(FATE_PROBE_FORMAT-yes)
+
+FATE_EXTERN-$(CONFIG_FFPROBE) += $(FATE_PROBE_FORMAT)
fate-probe-format: $(FATE_PROBE_FORMAT)
-$(FATE_PROBE_FORMAT): avprobe$(EXESUF)
+$(FATE_PROBE_FORMAT): ffprobe$(EXESUF)
$(FATE_PROBE_FORMAT): CMP = oneline
fate-probe-format-%: CMD = probefmt $(TARGET_SAMPLES)/probe-format/$(@:fate-probe-format-%=%)
diff --git a/tests/fate/prores.mak b/tests/fate/prores.mak
index 8d4b6ac9a7..e88df5fede 100644
--- a/tests/fate/prores.mak
+++ b/tests/fate/prores.mak
@@ -3,12 +3,18 @@ FATE_PRORES = fate-prores-422 \
fate-prores-422_lt \
fate-prores-422_proxy \
fate-prores-alpha \
+ fate-prores-alpha_skip \
+ fate-prores-transparency \
+ fate-prores-transparency_skip \
FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PRORES) += $(FATE_PRORES)
fate-prores: $(FATE_PRORES)
-fate-prores-422: CMD = framecrc -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422.mov -pix_fmt yuv422p10le
-fate-prores-422_hq: CMD = framecrc -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_HQ.mov -pix_fmt yuv422p10le
-fate-prores-422_lt: CMD = framecrc -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_LT.mov -pix_fmt yuv422p10le
-fate-prores-422_proxy: CMD = framecrc -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_Proxy.mov -pix_fmt yuv422p10le
-fate-prores-alpha: CMD = framecrc -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuva444p10le
+fate-prores-422: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422.mov -pix_fmt yuv422p10le
+fate-prores-422_hq: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_HQ.mov -pix_fmt yuv422p10le
+fate-prores-422_lt: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_LT.mov -pix_fmt yuv422p10le
+fate-prores-422_proxy: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_Proxy.mov -pix_fmt yuv422p10le
+fate-prores-alpha: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuva444p10le
+fate-prores-alpha_skip: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuv444p10le
+fate-prores-transparency: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/prores4444_with_transparency.mov -pix_fmt yuva444p10le
+fate-prores-transparency_skip: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/prores/prores4444_with_transparency.mov -pix_fmt yuv444p10le
diff --git a/tests/fate/qt.mak b/tests/fate/qt.mak
index 97537f93ef..670523e151 100644
--- a/tests/fate/qt.mak
+++ b/tests/fate/qt.mak
@@ -1,53 +1,58 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, EIGHTBPS) += fate-8bps
+FATE_QT-$(call DEMDEC, MOV, EIGHTBPS) += fate-8bps
fate-8bps: CMD = framecrc -i $(TARGET_SAMPLES)/8bps/full9iron-partial.mov -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, QDM2) += fate-qdm2
+FATE_QT-$(call DEMDEC, MOV, QDM2) += fate-qdm2
fate-qdm2: CMD = pcm -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-16-B-QDM2.mov
fate-qdm2: CMP = oneoff
fate-qdm2: REF = $(SAMPLES)/qt-surge-suite/surge-2-16-B-QDM2.pcm
fate-qdm2: FUZZ = 2
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PCM_ALAW) += fate-qt-alaw-mono
+FATE_QT-$(call DEMDEC, MOV, PCM_ALAW) += fate-qt-alaw-mono
fate-qt-alaw-mono: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-1-16-B-alaw.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PCM_ALAW) += fate-qt-alaw-stereo
+FATE_QT-$(call DEMDEC, MOV, PCM_ALAW) += fate-qt-alaw-stereo
fate-qt-alaw-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-16-B-alaw.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, ADPCM_IMA_QT) += fate-qt-ima4-mono
+FATE_QT-$(call DEMDEC, MOV, ADPCM_IMA_QT) += fate-qt-ima4-mono
fate-qt-ima4-mono: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-1-16-B-ima4.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, ADPCM_IMA_QT) += fate-qt-ima4-stereo
+FATE_QT-$(call DEMDEC, MOV, ADPCM_IMA_QT) += fate-qt-ima4-stereo
fate-qt-ima4-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-16-B-ima4.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, MACE3) += fate-qt-mac3-mono
+FATE_QT-$(call DEMDEC, MOV, MACE3) += fate-qt-mac3-mono
fate-qt-mac3-mono: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-1-8-MAC3.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, MACE3) += fate-qt-mac3-stereo
+FATE_QT-$(call DEMDEC, MOV, MACE3) += fate-qt-mac3-stereo
fate-qt-mac3-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-8-MAC3.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, MACE6) += fate-qt-mac6-mono
+FATE_QT-$(call DEMDEC, MOV, MACE6) += fate-qt-mac6-mono
fate-qt-mac6-mono: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-1-8-MAC6.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, MACE6) += fate-qt-mac6-stereo
+FATE_QT-$(call DEMDEC, MOV, MACE6) += fate-qt-mac6-stereo
fate-qt-mac6-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-8-MAC6.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PCM_MULAW) += fate-qt-ulaw-mono
+FATE_QT-$(call DEMDEC, MOV, PCM_MULAW) += fate-qt-ulaw-mono
fate-qt-ulaw-mono: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-1-16-B-ulaw.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PCM_MULAW) += fate-qt-ulaw-stereo
+FATE_QT-$(call DEMDEC, MOV, PCM_MULAW) += fate-qt-ulaw-stereo
fate-qt-ulaw-stereo: CMD = md5 -i $(TARGET_SAMPLES)/qt-surge-suite/surge-2-16-B-ulaw.mov -f s16le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, QDRAW) += fate-quickdraw
+FATE_QT-$(call DEMDEC, MOV, QDRAW) += fate-quickdraw
fate-quickdraw: CMD = framecrc -i $(TARGET_SAMPLES)/quickdraw/Airplane.mov -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, RPZA) += fate-rpza
+FATE_QT-$(call DEMDEC, MOV, RPZA) += fate-rpza
fate-rpza: CMD = framecrc -i $(TARGET_SAMPLES)/rpza/rpza2.mov -t 2 -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, SVQ1) += fate-svq1
+FATE_QT-$(call DEMDEC, MOV, SVQ1) += fate-svq1
fate-svq1: CMD = framecrc -i $(TARGET_SAMPLES)/svq1/marymary-shackles.mov -an -t 10
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, SVQ1) += fate-svq1-headerswap
+FATE_QT-$(call DEMDEC, MOV, SVQ1) += fate-svq1-headerswap
fate-svq1-headerswap: CMD = framecrc -i $(TARGET_SAMPLES)/svq1/ct_ending_cut.mov -frames 4
-FATE_SAMPLES_AVCONV-$(call ALLYES, MOV_DEMUXER SVQ3_DECODER ZLIB) += fate-svq3
+FATE_QT-$(call ALLYES, MOV_DEMUXER SVQ3_DECODER ZLIB) += fate-svq3
fate-svq3: CMD = framecrc -i $(TARGET_SAMPLES)/svq3/Vertical400kbit.sorenson3.mov -t 6 -an
+
+FATE_QT += $(FATE_QT-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_QT)
+fate-qt: $(FATE_QT)
diff --git a/tests/fate/real.mak b/tests/fate/real.mak
index f119ce9559..c123e4447f 100644
--- a/tests/fate/real.mak
+++ b/tests/fate/real.mak
@@ -1,7 +1,7 @@
FATE_REALAUDIO-$(call DEMDEC, RM, RA_144) += fate-ra3-144
fate-ra3-144: CMD = framecrc -i $(TARGET_SAMPLES)/realaudio/ra3.ra
-FATE_REALAUDIO-$(call DEMDEC, RM, RA_288) += fate-ra4-288
+#FATE_REALAUDIO-$(call DEMDEC, RM, RA_288) += fate-ra4-288
fate-ra4-288: CMD = pcm -i $(TARGET_SAMPLES)/realaudio/ra4_288.ra
fate-ra4-288: REF = $(SAMPLES)/realaudio/ra4_288.pcm
fate-ra4-288: CMP = oneoff
@@ -24,7 +24,7 @@ FATE_REALMEDIA_VIDEO-$(call DEMDEC, RM, RV30) += fate-rv30
fate-rv30: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/real/rv30.rm -an
FATE_REALMEDIA_VIDEO-$(call DEMDEC, RM, RV40) += fate-rv40
-fate-rv40: CMD = framecrc -i $(TARGET_SAMPLES)/real/spygames-2MB.rmvb -t 10 -an -vsync 0
+fate-rv40: CMD = framecrc -i $(TARGET_SAMPLES)/real/spygames-2MB.rmvb -t 10 -an
FATE_SIPR += fate-sipr-5k0
fate-sipr-5k0: CMD = pcm -i $(TARGET_SAMPLES)/sipr/sipr_5k0.rm
@@ -39,8 +39,9 @@ fate-sipr-8k5: CMD = pcm -i $(TARGET_SAMPLES)/sipr/sipr_8k5.rm
fate-sipr-8k5: REF = $(SAMPLES)/sipr/sipr_8k5.pcm
FATE_SIPR += fate-sipr-16k
-fate-sipr-16k: CMD = pcm -i $(TARGET_SAMPLES)/sipr/sipr_16k.rm
+fate-sipr-16k: CMD = pcm -i $(TARGET_SAMPLES)/sipr/sipr_16k.rm -aframes 3250
fate-sipr-16k: REF = $(SAMPLES)/sipr/sipr_16k.pcm
+fate-sipr-16k: SIZE_TOLERANCE = 40000
$(FATE_SIPR): CMP = oneoff
@@ -53,4 +54,4 @@ fate-realmedia-video: $(FATE_REALMEDIA_VIDEO-yes)
fate-realmedia: fate-realmedia-audio fate-realmedia-video
fate-real: fate-realaudio fate-realmedia
-FATE_SAMPLES_AVCONV += $(FATE_REALAUDIO-yes) $(FATE_REALMEDIA_AUDIO-yes) $(FATE_REALMEDIA_VIDEO-yes)
+FATE_SAMPLES_FFMPEG += $(FATE_REALAUDIO-yes) $(FATE_REALMEDIA_AUDIO-yes) $(FATE_REALMEDIA_VIDEO-yes)
diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak
index f0667aebc5..9142d497db 100644
--- a/tests/fate/screen.mak
+++ b/tests/fate/screen.mak
@@ -1,8 +1,8 @@
# FIXME dropped frames in this test because of coarse timebase
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, CSCD) += fate-cscd
+FATE_SCREEN-$(call DEMDEC, AVI, CSCD) += fate-cscd
fate-cscd: CMD = framecrc -i $(TARGET_SAMPLES)/CSCD/sample_video.avi -an -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, DXTORY) += fate-dxtory
+FATE_SCREEN-$(call DEMDEC, AVI, DXTORY) += fate-dxtory
fate-dxtory: CMD = framecrc -i $(TARGET_SAMPLES)/dxtory/dxtory_mic.avi
FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FIC) += fate-fic-avi
@@ -26,7 +26,7 @@ fate-fraps-v4: CMD = framecrc -i $(TARGET_SAMPLES)/fraps/WoW_2006-11-03_14-58-17
FATE_FRAPS += fate-fraps-v5
fate-fraps-v5: CMD = framecrc -i $(TARGET_SAMPLES)/fraps/fraps-v5-bouncing-balls-partial.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FRAPS) += $(FATE_FRAPS)
+FATE_SCREEN-$(call DEMDEC, AVI, FRAPS) += $(FATE_FRAPS)
fate-fraps: $(FATE_FRAPS)
FATE_SAMPLES_AVCONV-$(call DEMDEC, ASF, TDSC) += fate-tdsc
@@ -38,7 +38,7 @@ fate-tscc-15bit: CMD = framecrc -i $(TARGET_SAMPLES)/tscc/oneminute.avi -t 15 -p
FATE_TSCC += fate-tscc-32bit
fate-tscc-32bit: CMD = framecrc -i $(TARGET_SAMPLES)/tscc/2004-12-17-uebung9-partial.avi -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, TSCC) += $(FATE_TSCC)
+FATE_SCREEN-$(call DEMDEC, AVI, TSCC) += $(FATE_TSCC)
fate-tscc: $(FATE_TSCC)
FATE_TSCC2-$(CONFIG_AVI_DEMUXER) += fate-tscc2-avi
@@ -56,7 +56,7 @@ fate-vmnc-16bit: CMD = framecrc -i $(TARGET_SAMPLES)/VMnc/test.avi -pix_fmt rgb2
FATE_VMNC += fate-vmnc-32bit
fate-vmnc-32bit: CMD = framecrc -i $(TARGET_SAMPLES)/VMnc/VS2k5DebugDemo-01-partial.avi -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, VMNC) += $(FATE_VMNC)
+FATE_SCREEN-$(call DEMDEC, AVI, VMNC) += $(FATE_VMNC)
fate-vmnc: $(FATE_VMNC)
FATE_ZMBV += fate-zmbv-8bit
@@ -71,5 +71,10 @@ fate-zmbv-16bit: CMD = framecrc -i $(TARGET_SAMPLES)/zmbv/zmbv_16bit.avi -pix_fm
FATE_ZMBV += fate-zmbv-32bit
fate-zmbv-32bit: CMD = framecrc -i $(TARGET_SAMPLES)/zmbv/zmbv_32bit.avi -pix_fmt rgb24 -t 25
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, ZMBV) += $(FATE_ZMBV)
+FATE_SCREEN-$(call DEMDEC, AVI, ZMBV) += $(FATE_ZMBV)
fate-zmbv: $(FATE_ZMBV)
+
+FATE_SCREEN += $(FATE_SCREEN-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_SCREEN)
+fate-screen: $(FATE_SCREEN)
diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak
index be06f0f7b4..dfb2e84a1e 100644
--- a/tests/fate/seek.mak
+++ b/tests/fate/seek.mak
@@ -1,10 +1,15 @@
# files from fate-acodec
-FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_IMA_QT, AIFF) += adpcm-ima_qt
-FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_IMA_WAV, WAV) += adpcm-ima_wav
-FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_MS, WAV) += adpcm-ms
-FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_SWF, FLV) += adpcm-swf
-FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_YAMAHA, WAV) += adpcm-yamaha
+FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_IMA_QT, AIFF) += adpcm-ima_qt \
+ adpcm-ima_qt-trellis
+FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_IMA_WAV, WAV) += adpcm-ima_wav \
+ adpcm-ima_wav-trellis
+FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_MS, WAV) += adpcm-ms \
+ adpcm-ms-trellis
+FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_SWF, FLV) += adpcm-swf \
+ adpcm-swf-trellis
+FATE_SEEK_ACODEC-$(call ENCDEC, ADPCM_YAMAHA, WAV) += adpcm-yamaha \
+ adpcm-yamaha-trellis
FATE_SEEK_ACODEC-$(call ENCDEC, ALAC, MOV) += alac
FATE_SEEK_ACODEC-$(call ENCDEC, FLAC, FLAC) += flac
FATE_SEEK_ACODEC-$(call ENCDEC, MP2, MP2 MP3) += mp2
@@ -28,6 +33,11 @@ fate-seek-acodec-adpcm-ima_wav: SRC = fate/acodec-adpcm-ima_wav.wav
fate-seek-acodec-adpcm-ms: SRC = fate/acodec-adpcm-ms.wav
fate-seek-acodec-adpcm-swf: SRC = fate/acodec-adpcm-swf.flv
fate-seek-acodec-adpcm-yamaha: SRC = fate/acodec-adpcm-yamaha.wav
+fate-seek-acodec-adpcm-ima_qt-trellis: SRC = fate/acodec-adpcm-ima_qt-trellis.aiff
+fate-seek-acodec-adpcm-ima_wav-trellis: SRC = fate/acodec-adpcm-ima_wav-trellis.wav
+fate-seek-acodec-adpcm-ms-trellis: SRC = fate/acodec-adpcm-ms-trellis.wav
+fate-seek-acodec-adpcm-swf-trellis: SRC = fate/acodec-adpcm-swf-trellis.flv
+fate-seek-acodec-adpcm-yamaha-trellis: SRC = fate/acodec-adpcm-yamaha-trellis.wav
fate-seek-acodec-alac: SRC = fate/acodec-alac.mov
fate-seek-acodec-flac: SRC = fate/acodec-flac.flac
fate-seek-acodec-mp2: SRC = fate/acodec-mp2.mp2
@@ -48,32 +58,32 @@ fate-seek-acodec-pcm-u8: SRC = fate/acodec-pcm-u8.wav
FATE_SEEK += $(FATE_SEEK_ACODEC-yes:%=fate-seek-acodec-%)
-# files from fate-vsynth2
-
-FATE_SEEK_VSYNTH2-$(call ENCDEC, ASV1, AVI) += asv1
-FATE_SEEK_VSYNTH2-$(call ENCDEC, ASV2, AVI) += asv2
-FATE_SEEK_VSYNTH2-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p
-FATE_SEEK_VSYNTH2-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p-rd
-FATE_SEEK_VSYNTH2-$(call ENCDEC, DNXHD, MOV) += dnxhd-1080i
-FATE_SEEK_VSYNTH2-$(call ENCDEC, DVVIDEO, DV) += dv
-FATE_SEEK_VSYNTH2-$(call ENCDEC, DVVIDEO, DV) += dv-411
-FATE_SEEK_VSYNTH2-$(call ENCDEC, DVVIDEO, DV) += dv-50
-FATE_SEEK_VSYNTH2-$(call ENCDEC, FFV1, AVI) += ffv1
-FATE_SEEK_VSYNTH2-$(call ENCDEC, FLASHSV, FLV) += flashsv
-FATE_SEEK_VSYNTH2-$(call ENCDEC, FLV, FLV) += flv
-FATE_SEEK_VSYNTH2-$(call ENCDEC, H261, AVI) += h261
-FATE_SEEK_VSYNTH2-$(call ENCDEC, H263, AVI) += h263
-FATE_SEEK_VSYNTH2-$(call ENCDEC, H263, AVI) += h263p
-FATE_SEEK_VSYNTH2-$(call ENCDEC, HUFFYUV, AVI) += huffyuv
-FATE_SEEK_VSYNTH2-$(call ENCDEC, JPEGLS, AVI) += jpegls
-FATE_SEEK_VSYNTH2-$(call ENCDEC, LJPEG MJPEG, AVI) += ljpeg
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MJPEG, AVI) += mjpeg
-
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MPEG1VIDEO, MPEG1VIDEO MPEGVIDEO) += \
+# files from fate-vsynth_lena
+
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, ASV1, AVI) += asv1
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, ASV2, AVI) += asv2
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p-rd
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, DNXHD, MOV) += dnxhd-1080i
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, DVVIDEO, DV) += dv
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, DVVIDEO, DV) += dv-411
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, DVVIDEO, DV) += dv-50
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, FFV1, AVI) += ffv1
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, FLASHSV, FLV) += flashsv
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, FLV, FLV) += flv
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, H261, AVI) += h261
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, H263, AVI) += h263
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, H263, AVI) += h263p
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, HUFFYUV, AVI) += huffyuv
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, JPEGLS, AVI) += jpegls
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, LJPEG MJPEG, AVI) += ljpeg
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MJPEG, AVI) += mjpeg
+
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MPEG1VIDEO, MPEG1VIDEO MPEGVIDEO) += \
mpeg1 \
mpeg1b
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MPEG2VIDEO, MPEG2VIDEO MPEGVIDEO) += \
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MPEG2VIDEO, MPEG2VIDEO MPEGVIDEO) += \
mpeg2-422 \
mpeg2-idct-int \
mpeg2-ilace \
@@ -81,66 +91,71 @@ FATE_SEEK_VSYNTH2-$(call ENCDEC, MPEG2VIDEO, MPEG2VIDEO MPEGVIDEO) += \
mpeg2-thread \
mpeg2-thread-ivlc
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MPEG4, MP4 MOV) += mpeg4
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MPEG4, AVI) += $(FATE_MPEG4_AVI)
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MSMPEG4V3, AVI) += msmpeg4
-FATE_SEEK_VSYNTH2-$(call ENCDEC, MSMPEG4V2, AVI) += msmpeg4v2
-FATE_SEEK_VSYNTH2-$(call ENCDEC, RAWVIDEO, AVI) += rgb
-FATE_SEEK_VSYNTH2-$(call ENCDEC, ROQ, ROQ) += roqvideo
-FATE_SEEK_VSYNTH2-$(call ENCDEC, RV10, RM) += rv10
-FATE_SEEK_VSYNTH2-$(call ENCDEC, RV20, RM) += rv20
-FATE_SEEK_VSYNTH2-$(call ENCDEC, SVQ1, MOV) += svq1
-FATE_SEEK_VSYNTH2-$(call ENCDEC, WMV1, AVI) += wmv1
-FATE_SEEK_VSYNTH2-$(call ENCDEC, WMV2, AVI) += wmv2
-FATE_SEEK_VSYNTH2-$(call ENCDEC, RAWVIDEO, AVI) += yuv
-
-fate-seek-vsynth2-asv1: SRC = fate/vsynth2-asv1.avi
-fate-seek-vsynth2-asv2: SRC = fate/vsynth2-asv2.avi
-fate-seek-vsynth2-dnxhd-1080i: SRC = fate/vsynth2-dnxhd-1080i.mov
-fate-seek-vsynth2-dnxhd-720p: SRC = fate/vsynth2-dnxhd-720p.dnxhd
-fate-seek-vsynth2-dnxhd-720p-rd: SRC = fate/vsynth2-dnxhd-720p.dnxhd
-fate-seek-vsynth2-dv: SRC = fate/vsynth2-dv.dv
-fate-seek-vsynth2-dv-411: SRC = fate/vsynth2-dv-411.dv
-fate-seek-vsynth2-dv-50: SRC = fate/vsynth2-dv-50.dv
-fate-seek-vsynth2-ffv1: SRC = fate/vsynth2-ffv1.avi
-fate-seek-vsynth2-flashsv: SRC = fate/vsynth2-flashsv.flv
-fate-seek-vsynth2-flv: SRC = fate/vsynth2-flv.flv
-fate-seek-vsynth2-h261: SRC = fate/vsynth2-h261.avi
-fate-seek-vsynth2-h263: SRC = fate/vsynth2-h263.avi
-fate-seek-vsynth2-h263p: SRC = fate/vsynth2-h263p.avi
-fate-seek-vsynth2-huffyuv: SRC = fate/vsynth2-huffyuv.avi
-fate-seek-vsynth2-jpegls: SRC = fate/vsynth2-jpegls.avi
-fate-seek-vsynth2-ljpeg: SRC = fate/vsynth2-ljpeg.avi
-fate-seek-vsynth2-mjpeg: SRC = fate/vsynth2-mjpeg.avi
-fate-seek-vsynth2-mpeg1: SRC = fate/vsynth2-mpeg1.mpeg1video
-fate-seek-vsynth2-mpeg1b: SRC = fate/vsynth2-mpeg1b.mpeg1video
-fate-seek-vsynth2-mpeg2-422: SRC = fate/vsynth2-mpeg2-422.mpeg2video
-fate-seek-vsynth2-mpeg2-idct-int: SRC = fate/vsynth2-mpeg2-idct-int.mpeg2video
-fate-seek-vsynth2-mpeg2-ilace: SRC = fate/vsynth2-mpeg2-ilace.mpeg2video
-fate-seek-vsynth2-mpeg2-ivlc-qprd: SRC = fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
-fate-seek-vsynth2-mpeg2-thread: SRC = fate/vsynth2-mpeg2-thread.mpeg2video
-fate-seek-vsynth2-mpeg2-thread-ivlc: SRC = fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-fate-seek-vsynth2-mpeg4: SRC = fate/vsynth2-mpeg4.mp4
-fate-seek-vsynth2-mpeg4-adap: SRC = fate/vsynth2-mpeg4-adap.avi
-fate-seek-vsynth2-mpeg4-adv: SRC = fate/vsynth2-mpeg4-adv.avi
-fate-seek-vsynth2-mpeg4-error: SRC = fate/vsynth2-mpeg4-error.avi
-fate-seek-vsynth2-mpeg4-nr: SRC = fate/vsynth2-mpeg4-nr.avi
-fate-seek-vsynth2-mpeg4-qpel: SRC = fate/vsynth2-mpeg4-qpel.avi
-fate-seek-vsynth2-mpeg4-qprd: SRC = fate/vsynth2-mpeg4-qprd.avi
-fate-seek-vsynth2-mpeg4-rc: SRC = fate/vsynth2-mpeg4-rc.avi
-fate-seek-vsynth2-mpeg4-thread: SRC = fate/vsynth2-mpeg4-thread.avi
-fate-seek-vsynth2-msmpeg4: SRC = fate/vsynth2-msmpeg4.avi
-fate-seek-vsynth2-msmpeg4v2: SRC = fate/vsynth2-msmpeg4v2.avi
-fate-seek-vsynth2-rgb: SRC = fate/vsynth2-rgb.avi
-fate-seek-vsynth2-roqvideo: SRC = fate/vsynth2-roqvideo.roq
-fate-seek-vsynth2-rv10: SRC = fate/vsynth2-rv10.rm
-fate-seek-vsynth2-rv20: SRC = fate/vsynth2-rv20.rm
-fate-seek-vsynth2-svq1: SRC = fate/vsynth2-svq1.mov
-fate-seek-vsynth2-wmv1: SRC = fate/vsynth2-wmv1.avi
-fate-seek-vsynth2-wmv2: SRC = fate/vsynth2-wmv2.avi
-fate-seek-vsynth2-yuv: SRC = fate/vsynth2-yuv.avi
-
-FATE_SEEK += $(FATE_SEEK_VSYNTH2-yes:%=fate-seek-vsynth2-%)
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MPEG4, MP4 MOV) += mpeg4
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MPEG4, AVI) += $(FATE_MPEG4_AVI)
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MSMPEG4V3, AVI) += msmpeg4
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, MSMPEG4V2, AVI) += msmpeg4v2
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, RAWVIDEO, AVI) += rgb
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, ROQ, ROQ) += roqvideo
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, RV10, RM) += rv10
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, RV20, RM) += rv20
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, SNOW, AVI) += snow
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, SNOW, AVI) += snow-ll
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, SVQ1, MOV) += svq1
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, WMV1, AVI) += wmv1
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, WMV2, AVI) += wmv2
+FATE_SEEK_VSYNTH_LENA-$(call ENCDEC, RAWVIDEO, AVI) += yuv
+
+fate-seek-vsynth_lena-asv1: SRC = fate/vsynth_lena-asv1.avi
+fate-seek-vsynth_lena-asv2: SRC = fate/vsynth_lena-asv2.avi
+fate-seek-vsynth_lena-dnxhd-1080i: SRC = fate/vsynth_lena-dnxhd-1080i.mov
+fate-seek-vsynth_lena-dnxhd-720p: SRC = fate/vsynth_lena-dnxhd-720p.dnxhd
+fate-seek-vsynth_lena-dnxhd-720p-rd: SRC = fate/vsynth_lena-dnxhd-720p.dnxhd
+fate-seek-vsynth_lena-dv: SRC = fate/vsynth_lena-dv.dv
+fate-seek-vsynth_lena-dv-411: SRC = fate/vsynth_lena-dv-411.dv
+fate-seek-vsynth_lena-dv-50: SRC = fate/vsynth_lena-dv-50.dv
+fate-seek-vsynth_lena-ffv1: SRC = fate/vsynth_lena-ffv1.avi
+fate-seek-vsynth_lena-flashsv: SRC = fate/vsynth_lena-flashsv.flv
+fate-seek-vsynth_lena-flv: SRC = fate/vsynth_lena-flv.flv
+fate-seek-vsynth_lena-h261: SRC = fate/vsynth_lena-h261.avi
+fate-seek-vsynth_lena-h263: SRC = fate/vsynth_lena-h263.avi
+fate-seek-vsynth_lena-h263p: SRC = fate/vsynth_lena-h263p.avi
+fate-seek-vsynth_lena-huffyuv: SRC = fate/vsynth_lena-huffyuv.avi
+fate-seek-vsynth_lena-jpegls: SRC = fate/vsynth_lena-jpegls.avi
+fate-seek-vsynth_lena-ljpeg: SRC = fate/vsynth_lena-ljpeg.avi
+fate-seek-vsynth_lena-mjpeg: SRC = fate/vsynth_lena-mjpeg.avi
+fate-seek-vsynth_lena-mpeg1: SRC = fate/vsynth_lena-mpeg1.mpeg1video
+fate-seek-vsynth_lena-mpeg1b: SRC = fate/vsynth_lena-mpeg1b.mpeg1video
+fate-seek-vsynth_lena-mpeg2-422: SRC = fate/vsynth_lena-mpeg2-422.mpeg2video
+fate-seek-vsynth_lena-mpeg2-idct-int: SRC = fate/vsynth_lena-mpeg2-idct-int.mpeg2video
+fate-seek-vsynth_lena-mpeg2-ilace: SRC = fate/vsynth_lena-mpeg2-ilace.mpeg2video
+fate-seek-vsynth_lena-mpeg2-ivlc-qprd: SRC = fate/vsynth_lena-mpeg2-ivlc-qprd.mpeg2video
+fate-seek-vsynth_lena-mpeg2-thread: SRC = fate/vsynth_lena-mpeg2-thread.mpeg2video
+fate-seek-vsynth_lena-mpeg2-thread-ivlc: SRC = fate/vsynth_lena-mpeg2-thread-ivlc.mpeg2video
+fate-seek-vsynth_lena-mpeg4: SRC = fate/vsynth_lena-mpeg4.mp4
+fate-seek-vsynth_lena-mpeg4-adap: SRC = fate/vsynth_lena-mpeg4-adap.avi
+fate-seek-vsynth_lena-mpeg4-adv: SRC = fate/vsynth_lena-mpeg4-adv.avi
+fate-seek-vsynth_lena-mpeg4-error: SRC = fate/vsynth_lena-mpeg4-error.avi
+fate-seek-vsynth_lena-mpeg4-nr: SRC = fate/vsynth_lena-mpeg4-nr.avi
+fate-seek-vsynth_lena-mpeg4-nsse: SRC = fate/vsynth_lena-mpeg4-nsse.avi
+fate-seek-vsynth_lena-mpeg4-qpel: SRC = fate/vsynth_lena-mpeg4-qpel.avi
+fate-seek-vsynth_lena-mpeg4-qprd: SRC = fate/vsynth_lena-mpeg4-qprd.avi
+fate-seek-vsynth_lena-mpeg4-rc: SRC = fate/vsynth_lena-mpeg4-rc.avi
+fate-seek-vsynth_lena-mpeg4-thread: SRC = fate/vsynth_lena-mpeg4-thread.avi
+fate-seek-vsynth_lena-msmpeg4: SRC = fate/vsynth_lena-msmpeg4.avi
+fate-seek-vsynth_lena-msmpeg4v2: SRC = fate/vsynth_lena-msmpeg4v2.avi
+fate-seek-vsynth_lena-rgb: SRC = fate/vsynth_lena-rgb.avi
+fate-seek-vsynth_lena-roqvideo: SRC = fate/vsynth_lena-roqvideo.roq
+fate-seek-vsynth_lena-rv10: SRC = fate/vsynth_lena-rv10.rm
+fate-seek-vsynth_lena-rv20: SRC = fate/vsynth_lena-rv20.rm
+fate-seek-vsynth_lena-snow: SRC = fate/vsynth_lena-snow.avi
+fate-seek-vsynth_lena-snow-ll: SRC = fate/vsynth_lena-snow-ll.avi
+fate-seek-vsynth_lena-svq1: SRC = fate/vsynth_lena-svq1.mov
+fate-seek-vsynth_lena-wmv1: SRC = fate/vsynth_lena-wmv1.avi
+fate-seek-vsynth_lena-wmv2: SRC = fate/vsynth_lena-wmv2.avi
+fate-seek-vsynth_lena-yuv: SRC = fate/vsynth_lena-yuv.avi
+
+FATE_SAMPLES_SEEK += $(FATE_SEEK_VSYNTH_LENA-yes:%=fate-seek-vsynth_lena-%)
# files from fate-lavf
@@ -151,6 +166,7 @@ FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16BE, AU) += au
FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi
FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp
FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt
+FATE_SEEK_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm
FATE_SEEK_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt
FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif
FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf
@@ -162,6 +178,8 @@ FATE_SEEK_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, MPEG1SYSTEM MPEGPS) += mpg
FATE_SEEK_LAVF-$(call ENCDEC, PCM_MULAW, PCM_MULAW) += mulaw
FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += mxf
FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF_D10 MXF) += mxf_d10
+FATE_SEEK_LAVF-$(call ENCDEC2, DNXHD, PCM_S16LE, MXF_OPATOM MXF) += mxf_opatom
+FATE_SEEK_LAVF-$(call ENCDEC2, DNXHD, PCM_S16LE, MXF_OPATOM MXF) += mxf_opatom_audio
FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, NUT) += nut
FATE_SEEK_LAVF-$(call ENCDEC, FLAC, OGG) += ogg
FATE_SEEK_LAVF-$(call ENCDEC, PBM, IMAGE2PIPE) += pbmpipe
@@ -178,6 +196,7 @@ FATE_SEEK_LAVF-$(call ENCDEC, TIFF, IMAGE2) += tiff
FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, MP2, MPEGTS) += ts
FATE_SEEK_LAVF-$(call ENCDEC, PCM_U8, VOC) += voc
FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16LE, WAV) += wav
+FATE_SEEK_LAVF-$(call ENCDEC, MP2, WTV) += wtv
FATE_SEEK_LAVF-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg
fate-seek-lavf-aiff: SRC = lavf/lavf.aif
@@ -187,6 +206,7 @@ fate-seek-lavf-au: SRC = lavf/lavf.au
fate-seek-lavf-avi: SRC = lavf/lavf.avi
fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp
fate-seek-lavf-dv_fmt: SRC = lavf/lavf.dv
+fate-seek-lavf-ffm: SRC = lavf/lavf.ffm
fate-seek-lavf-flv_fmt: SRC = lavf/lavf.flv
fate-seek-lavf-gif: SRC = lavf/lavf.gif
fate-seek-lavf-gxf: SRC = lavf/lavf.gxf
@@ -198,6 +218,8 @@ fate-seek-lavf-mpg: SRC = lavf/lavf.mpg
fate-seek-lavf-mulaw: SRC = lavf/lavf.ul
fate-seek-lavf-mxf: SRC = lavf/lavf.mxf
fate-seek-lavf-mxf_d10: SRC = lavf/lavf.mxf_d10
+fate-seek-lavf-mxf_opatom: SRC = lavf/lavf.mxf_opatom
+fate-seek-lavf-mxf_opatom_audio: SRC = lavf/lavf.mxf_opatom_audio
fate-seek-lavf-nut: SRC = lavf/lavf.nut
fate-seek-lavf-ogg: SRC = lavf/lavf.ogg
fate-seek-lavf-pbmpipe: SRC = lavf/pbmpipe.pbm
@@ -214,14 +236,23 @@ fate-seek-lavf-tiff: SRC = images/tiff/%02d.tiff
fate-seek-lavf-ts: SRC = lavf/lavf.ts
fate-seek-lavf-voc: SRC = lavf/lavf.voc
fate-seek-lavf-wav: SRC = lavf/lavf.wav
+fate-seek-lavf-wtv: SRC = lavf/lavf.wtv
fate-seek-lavf-yuv4mpeg: SRC = lavf/lavf.y4m
FATE_SEEK += $(FATE_SEEK_LAVF-yes:%=fate-seek-lavf-%)
-$(FATE_SEEK): libavformat/seek-test$(EXESUF)
-$(FATE_SEEK): CMD = run libavformat/seek-test$(EXESUF) $(TARGET_PATH)/tests/data/$(SRC)
-$(FATE_SEEK): fate-seek-%: fate-%
+# extra files
+
+FATE_SEEK_EXTRA-$(CONFIG_MP3_DEMUXER) += fate-seek-extra-mp3
+fate-seek-extra-mp3: CMD = run libavformat/seek-test$(EXESUF) $(TARGET_SAMPLES)/gapless/gapless.mp3 -usetoc 0
+FATE_SEEK_EXTRA += $(FATE_SEEK_EXTRA-yes)
+
+
+$(FATE_SEEK) $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA): libavformat/seek-test$(EXESUF)
+$(FATE_SEEK) $(FATE_SAMPLES_SEEK): CMD = run libavformat/seek-test$(EXESUF) $(TARGET_PATH)/tests/data/$(SRC)
+$(FATE_SEEK) $(FATE_SAMPLES_SEEK): fate-seek-%: fate-%
fate-seek-%: REF = $(SRC_PATH)/tests/ref/seek/$(@:fate-seek-%=%)
FATE_AVCONV += $(FATE_SEEK)
-fate-seek: $(FATE_SEEK)
+FATE_SAMPLES_AVCONV += $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA)
+fate-seek: $(FATE_SEEK) $(FATE_SAMPLES_SEEK) $(FATE_SEEK_EXTRA)
diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak
new file mode 100644
index 0000000000..07d886a0af
--- /dev/null
+++ b/tests/fate/subtitles.mak
@@ -0,0 +1,70 @@
+FATE_SUBTITLES_ASS-$(call ALLYES, AQTITLE_DEMUXER TEXT_DECODER ICONV) += fate-sub-aqtitle
+fate-sub-aqtitle: CMD = fmtstdout ass -sub_charenc windows-1250 -i $(TARGET_SAMPLES)/sub/AQTitle_capability_tester.aqt
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, JACOSUB, JACOSUB) += fate-sub-jacosub
+fate-sub-jacosub: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/JACOsub_capability_tester.jss
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MICRODVD, MICRODVD) += fate-sub-microdvd
+fate-sub-microdvd: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/MicroDVD_capability_tester.sub
+
+FATE_SUBTITLES-$(call ALLYES, MICRODVD_DEMUXER MICRODVD_MUXER) += fate-sub-microdvd-remux
+fate-sub-microdvd-remux: CMD = fmtstdout microdvd -i $(TARGET_SAMPLES)/sub/MicroDVD_capability_tester.sub -c:s copy
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MOV, MOVTEXT) += fate-sub-movtext
+fate-sub-movtext: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/MovText_capability_tester.mp4
+
+FATE_SUBTITLES-$(call ENCDEC, MOVTEXT, MOV) += fate-binsub-movtextenc
+fate-binsub-movtextenc: CMD = md5 -i $(TARGET_SAMPLES)/sub/MovText_capability_tester.mp4 -map 0 -scodec mov_text -f mp4 -flags +bitexact -movflags frag_keyframe+empty_moov
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MPL2, MPL2) += fate-sub-mpl2
+fate-sub-mpl2: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/MPL2_capability_tester.txt
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MPSUB, TEXT) += fate-sub-mpsub
+fate-sub-mpsub: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/MPSub_capability_tester.sub
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, MPSUB, TEXT) += fate-sub-mpsub-frames
+fate-sub-mpsub-frames: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/MPSub_capability_tester_frames.sub
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, PJS, PJS) += fate-sub-pjs
+fate-sub-pjs: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/PJS_capability_tester.pjs
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, REALTEXT, REALTEXT) += fate-sub-realtext
+fate-sub-realtext: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/RealText_capability_tester.rt
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SAMI, SAMI) += fate-sub-sami
+fate-sub-sami: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/SAMI_capability_tester.smi
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SRT, SUBRIP) += fate-sub-srt
+fate-sub-srt: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, STL, STL) += fate-sub-stl
+fate-sub-stl: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/STL_capability_tester.stl
+
+FATE_SUBTITLES-$(call ALLYES, MOV_DEMUXER MOVTEXT_DECODER SUBRIP_ENCODER SRT_MUXER) += fate-sub-subripenc
+fate-sub-subripenc: CMD = fmtstdout srt -i $(TARGET_SAMPLES)/sub/MovText_capability_tester.mp4 -scodec subrip
+
+FATE_SUBTITLES_ASS-$(call ALLYES, SUBVIEWER1_DEMUXER SUBVIEWER1_DECODER ICONV) += fate-sub-subviewer1
+fate-sub-subviewer1: CMD = fmtstdout ass -sub_charenc windows-1250 -i $(TARGET_SAMPLES)/sub/SubViewer1_capability_tester.sub
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, SUBVIEWER, SUBVIEWER) += fate-sub-subviewer
+fate-sub-subviewer: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/SubViewer_capability_tester.sub
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, VPLAYER, VPLAYER) += fate-sub-vplayer
+fate-sub-vplayer: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/VPlayer_capability_tester.txt
+
+FATE_SUBTITLES_ASS-$(call DEMDEC, WEBVTT, WEBVTT) += fate-sub-webvtt
+fate-sub-webvtt: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/WebVTT_capability_tester.vtt
+
+FATE_SUBTITLES-$(call ALLYES, SRT_DEMUXER SUBRIP_DECODER WEBVTT_ENCODER WEBVTT_MUXER) += fate-sub-webvttenc
+fate-sub-webvttenc: CMD = fmtstdout webvtt -i $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt
+
+FATE_SUBTITLES_ASS-$(call ALLYES, MICRODVD_DEMUXER MICRODVD_DECODER ICONV) += fate-sub-charenc
+fate-sub-charenc: CMD = fmtstdout ass -sub_charenc cp1251 -i $(TARGET_SAMPLES)/sub/cp1251-subtitles.sub
+
+FATE_SUBTITLES-$(call ENCMUX, ASS, ASS) += $(FATE_SUBTITLES_ASS-yes)
+FATE_SUBTITLES += $(FATE_SUBTITLES-yes)
+
+fate-sub-%: CMP = rawdiff
+
+FATE_SAMPLES_FFMPEG += $(FATE_SUBTITLES)
+fate-subtitles: $(FATE_SUBTITLES)
diff --git a/tests/fate/utvideo.mak b/tests/fate/utvideo.mak
index e1ef7ecbd6..1e4755e355 100644
--- a/tests/fate/utvideo.mak
+++ b/tests/fate/utvideo.mak
@@ -28,7 +28,7 @@ fate-utvideo_yuv422_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_
FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, UTVIDEO) += $(FATE_UTVIDEO)
fate-utvideo: $(FATE_UTVIDEO)
-fate-utvideoenc%: CMD = framemd5 -f image2 -vcodec pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -vcodec utvideo -slices 1 -f avi -sws_flags +accurate_rnd+bitexact ${OPTS}
+fate-utvideoenc%: CMD = framemd5 -f image2 -vcodec pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -vcodec utvideo -slices 1 -sws_flags +accurate_rnd+bitexact ${OPTS}
FATE_UTVIDEOENC += fate-utvideoenc_rgba_left
fate-utvideoenc_rgba_left: OPTS = -pix_fmt rgba -pred left
diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak
index ed9fa2e78f..1ad5e96f92 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -1,40 +1,56 @@
fate-vsynth1-%: SRC = tests/data/vsynth1.yuv
fate-vsynth2-%: SRC = tests/data/vsynth2.yuv
+fate-vsynth_lena-%: SRC = tests/data/vsynth_lena.yuv
+fate-vsynth3-%: SRC = tests/data/vsynth3.yuv
fate-vsynth%: CODEC = $(word 3, $(subst -, ,$(@)))
fate-vsynth%: FMT = avi
-fate-vsynth%: CMD = enc_dec "rawvideo -s 352x288 -pix_fmt yuv420p" $(SRC) $(FMT) "-c $(CODEC) $(ENCOPTS)" rawvideo "-s 352x288 -pix_fmt yuv420p $(DECOPTS)" -keep
+fate-vsynth%: CMD = enc_dec "rawvideo -s 352x288 -pix_fmt yuv420p $(RAWDECOPTS)" $(SRC) $(FMT) "-c $(CODEC) $(ENCOPTS)" rawvideo "-s 352x288 -pix_fmt yuv420p -vsync 0 $(DECOPTS)" -keep "$(DECINOPTS)"
+fate-vsynth3-%: CMD = enc_dec "rawvideo -s $(FATEW)x$(FATEH) -pix_fmt yuv420p $(RAWDECOPTS)" $(SRC) $(FMT) "-c $(CODEC) $(ENCOPTS)" rawvideo "-s $(FATEW)x$(FATEH) -pix_fmt yuv420p -vsync 0 $(DECOPTS)" -keep "$(DECINOPTS)"
fate-vsynth%: CMP_UNIT = 1
fate-vsynth%: REF = $(SRC_PATH)/tests/ref/vsynth/$(@:fate-%=%)
+FATE_VCODEC-$(call ENCDEC, AMV, AVI) += amv
+fate-vsynth%-amv: ENCOPTS = -strict -1
+
FATE_VCODEC-$(call ENCDEC, ASV1, AVI) += asv1
fate-vsynth%-asv1: ENCOPTS = -qscale 10
FATE_VCODEC-$(call ENCDEC, ASV2, AVI) += asv2
fate-vsynth%-asv2: ENCOPTS = -qscale 10
+FATE_VCODEC-$(call ENCDEC, CINEPAK, MOV) += cinepak
+fate-vsynth%-cinepak: ENCOPTS = -vcodec cinepak -frames 3
+fate-vsynth%-cinepak: FMT = mov
+
FATE_VCODEC-$(call ENCDEC, CLJR, AVI) += cljr
+fate-vsynth%-cljr: ENCOPTS = -strict -1
FATE_VCODEC-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p \
dnxhd-720p-rd \
dnxhd-720p-10bit
fate-vsynth%-dnxhd-720p: ENCOPTS = -s hd720 -b 90M \
- -pix_fmt yuv422p -frames 5
+ -pix_fmt yuv422p -frames 5 -qmax 8
fate-vsynth%-dnxhd-720p: FMT = dnxhd
fate-vsynth%-dnxhd-720p-rd: ENCOPTS = -s hd720 -b 90M -threads 4 -mbd rd \
- -pix_fmt yuv422p -frames 5
+ -pix_fmt yuv422p -frames 5 -qmax 8
fate-vsynth%-dnxhd-720p-rd: FMT = dnxhd
fate-vsynth%-dnxhd-720p-10bit: ENCOPTS = -s hd720 -b 90M \
- -pix_fmt yuv422p10 -frames 5
+ -pix_fmt yuv422p10 -frames 5 -qmax 8
fate-vsynth%-dnxhd-720p-10bit: FMT = dnxhd
-FATE_VCODEC-$(call ENCDEC, DNXHD, MOV) += dnxhd-1080i
+FATE_VCODEC-$(call ENCDEC, DNXHD, MOV) += dnxhd-1080i dnxhd-1080i-colr
fate-vsynth%-dnxhd-1080i: ENCOPTS = -s hd1080 -b 120M -flags +ildct \
- -pix_fmt yuv422p -frames 5
+ -pix_fmt yuv422p -frames 5 -qmax 8
fate-vsynth%-dnxhd-1080i: FMT = mov
+fate-vsynth%-dnxhd-1080i-colr: ENCOPTS = -s hd1080 -b 120M -flags +ildct -movflags write_colr \
+ -pix_fmt yuv422p -frames 5 -qmax 8
+fate-vsynth%-dnxhd-1080i-colr: DECOPTS = -sws_flags area+accurate_rnd+bitexact
+fate-vsynth%-dnxhd-1080i-colr: FMT = mov
+
FATE_VCODEC-$(call ENCDEC, DVVIDEO, DV) += dv dv-411 dv-50
fate-vsynth%-dv: CODEC = dvvideo
fate-vsynth%-dv: ENCOPTS = -dct int -s pal
@@ -52,41 +68,65 @@ fate-vsynth%-dv-50: ENCOPTS = -dct int -s pal -pix_fmt yuv422p \
fate-vsynth%-dv-50: DECOPTS = -sws_flags neighbor
fate-vsynth%-dv-50: FMT = dv
-FATE_VCODEC-$(call ENCDEC, FFV1, AVI) += ffv1
-fate-vsynth%-ffv1: ENCOPTS = -slices 4 -strict -2
+FATE_VCODEC-$(call ENCDEC, FFV1, AVI) += ffv1 ffv1.0
+fate-vsynth%-ffv1: ENCOPTS = -slices 4
+fate-vsynth%-ffv1.0: CODEC = ffv1
-FATE_VCODEC-$(call ENCDEC, FFVHUFF, AVI) += ffvhuff
+FATE_VCODEC-$(call ENCDEC, FFVHUFF, AVI) += ffvhuff ffvhuff444 ffvhuff420p12 ffvhuff422p10left ffvhuff444p16
+fate-vsynth%-ffvhuff444: ENCOPTS = -vcodec ffvhuff -pix_fmt yuv444p
+fate-vsynth%-ffvhuff420p12: ENCOPTS = -vcodec ffvhuff -pix_fmt yuv420p12le
+fate-vsynth%-ffvhuff422p10left: ENCOPTS = -vcodec ffvhuff -pix_fmt yuv422p10le -pred left
+fate-vsynth%-ffvhuff444p16: ENCOPTS = -vcodec ffvhuff -pix_fmt yuv444p16le -pred plane
FATE_VCODEC-$(call ENCDEC, FLASHSV, FLV) += flashsv
fate-vsynth%-flashsv: ENCOPTS = -sws_flags neighbor+full_chroma_int
fate-vsynth%-flashsv: DECOPTS = -sws_flags area
fate-vsynth%-flashsv: FMT = flv
+FATE_VCODEC-$(call ENCDEC, FLASHSV2, FLV) += flashsv2
+fate-vsynth%-flashsv2: ENCOPTS = -sws_flags neighbor+full_chroma_int -strict experimental -compression_level 0
+fate-vsynth%-flashsv2: DECOPTS = -sws_flags area
+fate-vsynth%-flashsv2: FMT = flv
+
FATE_VCODEC-$(call ENCDEC, FLV, FLV) += flv
fate-vsynth%-flv: ENCOPTS = -qscale 10
fate-vsynth%-flv: FMT = flv
-FATE_VCODEC-$(call ENCDEC, H261, AVI) += h261
+FATE_VCODEC-$(call ENCDEC, H261, AVI) += h261 h261-trellis
fate-vsynth%-h261: ENCOPTS = -qscale 11
+fate-vsynth%-h261-trellis: ENCOPTS = -qscale 12 -trellis 1 -mbd rd
FATE_VCODEC-$(call ENCDEC, H263, AVI) += h263 h263-obmc h263p
fate-vsynth%-h263: ENCOPTS = -qscale 10
fate-vsynth%-h263-obmc: ENCOPTS = -qscale 10 -obmc 1
fate-vsynth%-h263p: ENCOPTS = -qscale 2 -flags +aic -umv 1 -aiv 1 -ps 300
-FATE_VCODEC-$(call ENCDEC, HUFFYUV, AVI) += huffyuv
-fate-vsynth%-huffyuv: ENCOPTS = -pix_fmt yuv422p -sws_flags neighbor
-fate-vsynth%-huffyuv: DECOPTS = -strict -2 -sws_flags neighbor
+FATE_VCODEC-$(call ENCDEC, HUFFYUV, AVI) += huffyuv huffyuvbgr24 huffyuvbgra
+fate-vsynth%-huffyuv: ENCOPTS = -vcodec huffyuv -pix_fmt yuv422p -sws_flags neighbor
+fate-vsynth%-huffyuv: DECOPTS = -sws_flags neighbor
+fate-vsynth%-huffyuvbgr24: ENCOPTS = -vcodec huffyuv -pix_fmt bgr24 -sws_flags neighbor
+fate-vsynth%-huffyuvbgr24: DECOPTS = -sws_flags neighbor
+fate-vsynth%-huffyuvbgra: ENCOPTS = -vcodec huffyuv -pix_fmt bgr32 -sws_flags neighbor
+fate-vsynth%-huffyuvbgra: DECOPTS = -sws_flags neighbor
FATE_VCODEC-$(call ENCDEC, JPEGLS, AVI) += jpegls
fate-vsynth%-jpegls: ENCOPTS = -sws_flags neighbor+full_chroma_int
fate-vsynth%-jpegls: DECOPTS = -sws_flags area
+FATE_VCODEC-$(call ENCDEC, JPEG2000, AVI) += jpeg2000 jpeg2000-97
+fate-vsynth%-jpeg2000: ENCOPTS = -qscale 7 -strict experimental -pred 1 -pix_fmt rgb24
+fate-vsynth%-jpeg2000: DECINOPTS = -vcodec jpeg2000
+fate-vsynth%-jpeg2000-97: ENCOPTS = -qscale 7 -strict experimental -pix_fmt rgb24
+fate-vsynth%-jpeg2000-97: DECINOPTS = -vcodec jpeg2000
+
FATE_VCODEC-$(call ENCDEC, LJPEG MJPEG, AVI) += ljpeg
fate-vsynth%-ljpeg: ENCOPTS = -strict -1
-FATE_VCODEC-$(call ENCDEC, MJPEG, AVI) += mjpeg
+FATE_VCODEC-$(call ENCDEC, MJPEG, AVI) += mjpeg mjpeg-422 mjpeg-444 mjpeg-trell
fate-vsynth%-mjpeg: ENCOPTS = -qscale 9 -pix_fmt yuvj420p
+fate-vsynth%-mjpeg-422: ENCOPTS = -qscale 9 -pix_fmt yuvj422p
+fate-vsynth%-mjpeg-444: ENCOPTS = -qscale 9 -pix_fmt yuvj444p
+fate-vsynth%-mjpeg-trell: ENCOPTS = -qscale 9 -pix_fmt yuvj420p -trellis 1
FATE_VCODEC-$(call ENCDEC, MPEG1VIDEO, MPEG1VIDEO MPEGVIDEO) += mpeg1 mpeg1b
fate-vsynth%-mpeg1: FMT = mpeg1video
@@ -142,7 +182,8 @@ FATE_MPEG4_AVI = mpeg4-rc \
mpeg4-qpel \
mpeg4-thread \
mpeg4-error \
- mpeg4-nr
+ mpeg4-nr \
+ mpeg4-nsse
FATE_VCODEC-$(call ENCDEC, MPEG4, MP4 MOV) += $(FATE_MPEG4_MP4)
FATE_VCODEC-$(call ENCDEC, MPEG4, AVI) += $(FATE_MPEG4_AVI)
@@ -164,6 +205,10 @@ fate-vsynth%-mpeg4-error: ENCOPTS = -qscale 7 -flags +mv4+aic \
fate-vsynth%-mpeg4-nr: ENCOPTS = -qscale 8 -flags +mv4 -mbd rd -nr 200
+fate-vsynth%-mpeg4-nsse: ENCOPTS = -qscale 7 -cmp nsse -subcmp nsse \
+ -mbcmp nsse -precmp nsse \
+ -skipcmp nsse
+
fate-vsynth%-mpeg4-qpel: ENCOPTS = -qscale 7 -flags +mv4+qpel -mbd 2 \
-bf 2 -cmp 1 -subcmp 2
@@ -184,13 +229,24 @@ fate-vsynth%-msmpeg4: ENCOPTS = -qscale 10
FATE_VCODEC-$(call ENCDEC, MSMPEG4V2, AVI) += msmpeg4v2
fate-vsynth%-msmpeg4v2: ENCOPTS = -qscale 10
-FATE_VCODEC-$(call ENCDEC, PRORES, MOV) += prores
-fate-vsynth%-prores: ENCOPTS = -profile hq
+FATE_VCODEC-$(call ENCDEC, PNG, AVI) += mpng
+fate-vsynth%-mpng: CODEC = png
+
+FATE_VCODEC-$(call ENCDEC, MSVIDEO1, AVI) += msvideo1
+
+FATE_VCODEC-$(call ENCDEC, PRORES, MOV) += prores prores_ks
fate-vsynth%-prores: FMT = mov
-FATE_VCODEC-$(call ENCDEC, QTRLE, MOV) += qtrle
+fate-vsynth%-prores_ks: ENCOPTS = -profile hq
+fate-vsynth%-prores_ks: FMT = mov
+
+FATE_VCODEC-$(call ENCDEC, QTRLE, MOV) += qtrle qtrlegray
fate-vsynth%-qtrle: FMT = mov
+fate-vsynth%-qtrlegray: CODEC = qtrle
+fate-vsynth%-qtrlegray: ENCOPTS = -pix_fmt gray
+fate-vsynth%-qtrlegray: FMT = mov
+
FATE_VCODEC-$(call ENCDEC, RAWVIDEO, AVI) += rgb
fate-vsynth%-rgb: CODEC = rawvideo
fate-vsynth%-rgb: ENCOPTS = -pix_fmt bgr24
@@ -198,6 +254,7 @@ fate-vsynth%-rgb: ENCOPTS = -pix_fmt bgr24
FATE_VCODEC-$(call ENCDEC, ROQ, ROQ) += roqvideo
fate-vsynth%-roqvideo: CODEC = roqvideo
fate-vsynth%-roqvideo: ENCOPTS = -frames 5
+fate-vsynth%-roqvideo: RAWDECOPTS = -r 30
fate-vsynth%-roqvideo: FMT = roq
FATE_VCODEC-$(call ENCDEC, RV10, RM) += rv10
@@ -208,12 +265,37 @@ FATE_VCODEC-$(call ENCDEC, RV20, RM) += rv20
fate-vsynth%-rv20: ENCOPTS = -qscale 10
fate-vsynth%-rv20: FMT = rm
+FATE_VCODEC-$(call ENCDEC, SNOW, AVI) += snow snow-hpel snow-ll
+fate-vsynth%-snow: ENCOPTS = -qscale 2 -flags +qpel \
+ -me_method iter -dia_size 2 \
+ -cmp 12 -subcmp 12 -s 128x64
+
+fate-vsynth%-snow-hpel: ENCOPTS = -qscale 2 \
+ -me_method iter -dia_size 2 \
+ -cmp 12 -subcmp 12 -s 128x64
+
+fate-vsynth%-snow-ll: ENCOPTS = -qscale .001 -pred 1 \
+ -flags +mv4+qpel
+
FATE_VCODEC-$(call ENCDEC, SVQ1, MOV) += svq1
fate-vsynth%-svq1: ENCOPTS = -qscale 3 -pix_fmt yuv410p
fate-vsynth%-svq1: FMT = mov
+FATE_VCODEC-$(call ENCDEC, R210, AVI) += r210
+
FATE_VCODEC-$(call ENCDEC, V210, AVI) += v210
+FATE_VCODEC-$(call ENCDEC, V308, AVI) += v308
+
+FATE_VCODEC-$(call ENCDEC, V408, AVI) += v408
+fate-vsynth%-v408: ENCOPTS = -sws_flags neighbor+bitexact
+fate-vsynth%-v408: DECOPTS = -sws_flags neighbor+bitexact
+
+FATE_VCODEC-$(call ENCDEC, AVUI, MOV) += avui
+fate-vsynth%-avui: ENCOPTS = -s pal -strict experimental -sws_flags neighbor+bitexact
+fate-vsynth%-avui: DECOPTS = -sws_flags neighbor+bitexact
+fate-vsynth%-avui: FMT = mov
+
FATE_VCODEC-$(call ENCDEC, WMV1, AVI) += wmv1
fate-vsynth%-wmv1: ENCOPTS = -qscale 10
@@ -223,15 +305,42 @@ fate-vsynth%-wmv2: ENCOPTS = -qscale 10
FATE_VCODEC-$(call ENCDEC, RAWVIDEO, AVI) += yuv
fate-vsynth%-yuv: CODEC = rawvideo
+FATE_VCODEC-$(call ENCDEC, XFACE, NUT) += xface
+fate-vsynth%-xface: ENCOPTS = -s 48x48 -sws_flags neighbor+bitexact
+fate-vsynth%-xface: DECOPTS = -sws_flags neighbor+bitexact
+fate-vsynth%-xface: FMT = nut
+
+FATE_VCODEC-$(call ENCDEC, YUV4, AVI) += yuv4
+
+FATE_VCODEC-$(call ENCDEC, Y41P, AVI) += y41p
+
+FATE_VCODEC-$(call ENCDEC, ZLIB, AVI) += zlib
+
FATE_VCODEC += $(FATE_VCODEC-yes)
FATE_VSYNTH1 = $(FATE_VCODEC:%=fate-vsynth1-%)
FATE_VSYNTH2 = $(FATE_VCODEC:%=fate-vsynth2-%)
+FATE_VSYNTH_LENA = $(FATE_VCODEC:%=fate-vsynth_lena-%)
+# Redundant tests because they just resize the input
+RESIZE_OFF = dnxhd-720p dnxhd-720p-rd dnxhd-720p-10bit dnxhd-1080i \
+ dv dv-411 dv-50 avui snow snow-hpel snow-ll
+# Incorrect parameters - usually size or color format restrictions
+INC_PAR_OFF = cinepak h261 h261-trellis h263 h263p h263-obmc msvideo1 \
+ roqvideo rv10 rv20 y41p qtrlegray
+VSYNTH3_OFF = $(RESIZE_OFF) $(INC_PAR_OFF)
+
+FATE_VCODEC3 = $(filter-out $(VSYNTH3_OFF),$(FATE_VCODEC))
+FATE_VSYNTH3 = $(FATE_VCODEC3:%=fate-vsynth3-%)
$(FATE_VSYNTH1): tests/data/vsynth1.yuv
$(FATE_VSYNTH2): tests/data/vsynth2.yuv
+$(FATE_VSYNTH_LENA): tests/data/vsynth_lena.yuv
+$(FATE_VSYNTH3): tests/data/vsynth3.yuv
-FATE_AVCONV += $(FATE_VSYNTH1) $(FATE_VSYNTH2)
+FATE_AVCONV += $(FATE_VSYNTH1) $(FATE_VSYNTH2) $(FATE_VSYNTH3)
+FATE_SAMPLES_AVCONV += $(FATE_VSYNTH_LENA)
fate-vsynth1: $(FATE_VSYNTH1)
fate-vsynth2: $(FATE_VSYNTH2)
-fate-vcodec: fate-vsynth1 fate-vsynth2
+fate-vsynth_lena: $(FATE_VSYNTH_LENA)
+fate-vsynth3: $(FATE_VSYNTH3)
+fate-vcodec: fate-vsynth1 fate-vsynth_lena fate-vsynth2 fate-vsynth3
diff --git a/tests/fate/video.mak b/tests/fate/video.mak
index d43754f07a..d07ff40f2b 100644
--- a/tests/fate/video.mak
+++ b/tests/fate/video.mak
@@ -4,40 +4,46 @@ fate-4xm-1: CMD = framecrc -i $(TARGET_SAMPLES)/4xm/version1.4xm -pix_fmt rgb24
FATE_4XM += fate-4xm-2
fate-4xm-2: CMD = framecrc -i $(TARGET_SAMPLES)/4xm/version2.4xm -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, FOURXM, FOURXM) += $(FATE_4XM)
+FATE_VIDEO-$(call DEMDEC, FOURXM, FOURXM) += $(FATE_4XM)
fate-4xm: $(FATE_4XM)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, AASC) += fate-aasc
+FATE_VIDEO-$(call DEMDEC, AVI, AASC) += fate-aasc
fate-aasc: CMD = framecrc -i $(TARGET_SAMPLES)/aasc/AASC-1.5MB.AVI -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, AIC) += fate-aic-oddsize
+FATE_VIDEO-$(call DEMDEC, MOV, AIC) += fate-aic
+fate-aic: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/aic/small_apple_intermediate_codec.mov -an -vframes 15
+
+FATE_VIDEO-$(call DEMDEC, MOV, AIC) += fate-aic-oddsize
fate-aic-oddsize: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/aic/aic_odd_dimensions.mov
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MM, MMVIDEO) += fate-alg-mm
+FATE_VIDEO-$(call DEMDEC, MM, MMVIDEO) += fate-alg-mm
fate-alg-mm: CMD = framecrc -i $(TARGET_SAMPLES)/alg-mm/ibmlogo.mm -an -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, AMV) += fate-amv
+FATE_VIDEO-$(call DEMDEC, AVI, AMV) += fate-amv
fate-amv: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/amv/MTV_high_res_320x240_sample_Penguin_Joke_MTV_from_WMV.amv -t 10 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TTY, ANSI) += fate-ansi
+FATE_VIDEO-$(call DEMDEC, TTY, ANSI) += fate-ansi
fate-ansi: CMD = framecrc -chars_per_frame 44100 -i $(TARGET_SAMPLES)/ansi/TRE-IOM5.ANS -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RPL, ESCAPE124) += fate-armovie-escape124
+FATE_VIDEO-$(call DEMDEC, TTY, ANSI) += fate-ansi256
+fate-ansi256: CMD = framecrc -chars_per_frame 44100 -i $(TARGET_SAMPLES)/ansi/ansi256.ans -pix_fmt rgb24
+
+FATE_VIDEO-$(call DEMDEC, RPL, ESCAPE124) += fate-armovie-escape124
fate-armovie-escape124: CMD = framecrc -i $(TARGET_SAMPLES)/rpl/ESCAPE.RPL -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RPL, ESCAPE130) += fate-armovie-escape130
+FATE_VIDEO-$(call DEMDEC, RPL, ESCAPE130) += fate-armovie-escape130
fate-armovie-escape130: CMD = framecrc -i $(TARGET_SAMPLES)/rpl/landing.rpl -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, AURA) += fate-auravision-v1
+FATE_VIDEO-$(call DEMDEC, AVI, AURA) += fate-auravision-v1
fate-auravision-v1: CMD = framecrc -i $(TARGET_SAMPLES)/auravision/SOUVIDEO.AVI -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, AURA2) += fate-auravision-v2
+FATE_VIDEO-$(call DEMDEC, AVI, AURA2) += fate-auravision-v2
fate-auravision-v2: CMD = framecrc -i $(TARGET_SAMPLES)/auravision/salma-hayek-in-ugly-betty-partial-avi -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, BETHSOFTVID, BETHSOFTVID) += fate-bethsoft-vid
+FATE_VIDEO-$(call DEMDEC, BETHSOFTVID, BETHSOFTVID) += fate-bethsoft-vid
fate-bethsoft-vid: CMD = framecrc -i $(TARGET_SAMPLES)/bethsoft-vid/ANIM0001.VID -t 5 -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, BFI, BFI) += fate-bfi
+FATE_VIDEO-$(call DEMDEC, BFI, BFI) += fate-bfi
fate-bfi: CMD = framecrc -i $(TARGET_SAMPLES)/bfi/2287.bfi -pix_fmt rgb24
FATE_BINK_VIDEO += fate-bink-video-b
@@ -49,10 +55,9 @@ fate-bink-video-f: CMD = framecrc -i $(TARGET_SAMPLES)/bink/hol2br.bik
FATE_BINK_VIDEO += fate-bink-video-i
fate-bink-video-i: CMD = framecrc -i $(TARGET_SAMPLES)/bink/RazOnBull.bik -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, BINK, BINK) += $(FATE_BINK_VIDEO)
-fate-bink-video: $(FATE_BINK_VIDEO)
+FATE_VIDEO-$(call DEMDEC, BINK, BINK) += $(FATE_BINK_VIDEO)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, BMV, BMV_VIDEO) += fate-bmv-video
+FATE_VIDEO-$(call DEMDEC, BMV, BMV_VIDEO) += fate-bmv-video
fate-bmv-video: CMD = framecrc -i $(TARGET_SAMPLES)/bmv/SURFING-partial.BMV -pix_fmt rgb24 -an
FATE_CANOPUS_HQ_HQA += fate-canopus-hq_hqa-hq
@@ -73,22 +78,22 @@ fate-canopus-hqx422: CMD = framecrc -i $(TARGET_SAMPLES)/canopus/hqx422.avi -pix
FATE_CANOPUS_HQX += fate-canopus-hqx422a
fate-canopus-hqx422a: CMD = framecrc -i $(TARGET_SAMPLES)/canopus/hqx422a.avi -pix_fmt yuv422p16be -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, HQX) += $(FATE_CANOPUS_HQX)
+FATE_VIDEO-$(call DEMDEC, AVI, HQX) += $(FATE_CANOPUS_HQX)
fate-canopus-hqx: $(FATE_CANOPUS_HQX)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MPEGPS, CAVS) += fate-cavs
+FATE_VIDEO-$(call DEMDEC, MPEGPS, CAVS) += fate-cavs
fate-cavs: CMD = framecrc -i $(TARGET_SAMPLES)/cavs/cavs.mpg -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, CDG, CDGRAPHICS) += fate-cdgraphics
+FATE_VIDEO-$(call DEMDEC, CDG, CDGRAPHICS) += fate-cdgraphics
fate-cdgraphics: CMD = framecrc -i $(TARGET_SAMPLES)/cdgraphics/BrotherJohn.cdg -pix_fmt rgb24 -t 1
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, CLJR) += fate-cljr
+FATE_VIDEO-$(call DEMDEC, AVI, CLJR) += fate-cljr
fate-cljr: CMD = framecrc -i $(TARGET_SAMPLES)/cljr/testcljr-partial.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, PNG) += fate-corepng
+FATE_VIDEO-$(call DEMDEC, AVI, PNG) += fate-corepng
fate-corepng: CMD = framecrc -i $(TARGET_SAMPLES)/png1/corepng-partial.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVS, AVS) += fate-creatureshock-avs
+FATE_VIDEO-$(call DEMDEC, AVS, AVS) += fate-creatureshock-avs
fate-creatureshock-avs: CMD = framecrc -i $(TARGET_SAMPLES)/creatureshock-avs/OUTATIME.AVS -pix_fmt rgb24
FATE_CVID-$(CONFIG_MOV_DEMUXER) += fate-cvid-palette
@@ -100,31 +105,34 @@ fate-cvid-partial: CMD = framecrc -i $(TARGET_SAMPLES)/cvid/laracroft-cinepak-pa
FATE_CVID-$(CONFIG_AVI_DEMUXER) += fate-cvid-grayscale
fate-cvid-grayscale: CMD = framecrc -i $(TARGET_SAMPLES)/cvid/pcitva15.avi -an
-FATE_SAMPLES_AVCONV-$(CONFIG_CINEPAK_DECODER) += $(FATE_CVID-yes)
+FATE_VIDEO-$(CONFIG_CINEPAK_DECODER) += $(FATE_CVID-yes)
fate-cvid: $(FATE_CVID-yes)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, C93, C93) += fate-cyberia-c93
+FATE_VIDEO-$(call DEMDEC, C93, C93) += fate-cyberia-c93
fate-cyberia-c93: CMD = framecrc -i $(TARGET_SAMPLES)/cyberia-c93/intro1.c93 -t 3 -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, CYUV) += fate-cyuv
+FATE_VIDEO-$(call DEMDEC, AVI, CYUV) += fate-cyuv
fate-cyuv: CMD = framecrc -i $(TARGET_SAMPLES)/cyuv/cyuv.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, DSICIN, DSICINVIDEO) += fate-delphine-cin-video
+FATE_VIDEO-$(call DEMDEC, DSICIN, DSICINVIDEO) += fate-delphine-cin-video
fate-delphine-cin-video: CMD = framecrc -i $(TARGET_SAMPLES)/delphine-cin/LOGO-partial.CIN -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, ANM, ANM) += fate-deluxepaint-anm
+FATE_VIDEO-$(call DEMDEC, ANM, ANM) += fate-deluxepaint-anm
fate-deluxepaint-anm: CMD = framecrc -i $(TARGET_SAMPLES)/deluxepaint-anm/INTRO1.ANM -pix_fmt rgb24
+FATE_VIDEO-$(call DEMDEC, DIRAC, DIRAC) += fate-dirac
+fate-dirac: CMD = framecrc -i $(TARGET_SAMPLES)/dirac/vts.profile-main.drc
+
FATE_TRUEMOTION1 += fate-truemotion1-15
fate-truemotion1-15: CMD = framecrc -i $(TARGET_SAMPLES)/duck/phant2-940.duk -pix_fmt rgb24 -an
FATE_TRUEMOTION1 += fate-truemotion1-24
fate-truemotion1-24: CMD = framecrc -i $(TARGET_SAMPLES)/duck/sonic3dblast_intro-partial.avi -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, TRUEMOTION1) += $(FATE_TRUEMOTION1)
+FATE_VIDEO-$(call DEMDEC, AVI, TRUEMOTION1) += $(FATE_TRUEMOTION1)
fate-truemotion1: $(FATE_TRUEMOTION1)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, TRUEMOTION2) += fate-truemotion2
+FATE_VIDEO-$(call DEMDEC, AVI, TRUEMOTION2) += fate-truemotion2
fate-truemotion2: CMD = framecrc -i $(TARGET_SAMPLES)/duck/tm20.avi
FATE_DXA += fate-dxa-feeble
@@ -133,14 +141,14 @@ fate-dxa-feeble: CMD = framecrc -i $(TARGET_SAMPLES)/dxa/meetsquid.dxa -t 2 -pix
FATE_DXA += fate-dxa-scummvm
fate-dxa-scummvm: CMD = framecrc -i $(TARGET_SAMPLES)/dxa/scummvm.dxa -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, DXA, DXA) += $(FATE_DXA)
+FATE_VIDEO-$(call DEMDEC, DXA, DXA) += $(FATE_DXA)
fate-dxa: $(FATE_DXA)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SEGAFILM, CINEPAK) += fate-film-cvid
+FATE_VIDEO-$(call DEMDEC, SEGAFILM, CINEPAK) += fate-film-cvid
fate-film-cvid: CMD = framecrc -i $(TARGET_SAMPLES)/film/logo-capcom.cpk -an
FATE_FLIC += fate-flic-af11-palette-change
-fate-flic-af11-palette-change: CMD = framecrc -i $(TARGET_SAMPLES)/fli/fli-engines.fli -t 3.3 -pix_fmt rgb24
+fate-flic-af11-palette-change: CMD = framecrc -i $(TARGET_SAMPLES)/fli/fli-engines.fli -t 3.31 -pix_fmt rgb24
FATE_FLIC += fate-flic-af12
fate-flic-af12: CMD = framecrc -i $(TARGET_SAMPLES)/fli/jj00c2.fli -pix_fmt rgb24
@@ -148,17 +156,17 @@ fate-flic-af12: CMD = framecrc -i $(TARGET_SAMPLES)/fli/jj00c2.fli -pix_fmt rgb2
FATE_FLIC += fate-flic-magiccarpet
fate-flic-magiccarpet: CMD = framecrc -i $(TARGET_SAMPLES)/fli/intel.dat -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, FLIC, FLIC) += $(FATE_FLIC)
+FATE_VIDEO-$(call DEMDEC, FLIC, FLIC) += $(FATE_FLIC)
fate-flic: $(FATE_FLIC)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FRWU) += fate-frwu
+FATE_VIDEO-$(call DEMDEC, AVI, FRWU) += fate-frwu
fate-frwu: CMD = framecrc -i $(TARGET_SAMPLES)/frwu/frwu.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IDCIN, IDCIN) += fate-id-cin-video
+FATE_VIDEO-$(call DEMDEC, IDCIN, IDCIN) += fate-id-cin-video
fate-id-cin-video: CMD = framecrc -i $(TARGET_SAMPLES)/idcin/idlog-2MB.cin -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call ENCDEC, ROQ PGMYUV, ROQ IMAGE2) += fate-idroq-video-encode
-fate-idroq-video-encode: CMD = md5 -f image2 -vcodec pgmyuv -i $(TARGET_SAMPLES)/ffmpeg-synthetic/vsynth1/%02d.pgm -sws_flags +bitexact -vf pad=512:512:80:112 -f roq -t 0.2
+FATE_VIDEO-$(call ENCDEC, ROQ PGMYUV, ROQ IMAGE2) += fate-idroq-video-encode
+fate-idroq-video-encode: CMD = md5 -f image2 -vcodec pgmyuv -i $(TARGET_SAMPLES)/ffmpeg-synthetic/vsynth1/%02d.pgm -r 30 -sws_flags +bitexact -vf pad=512:512:80:112 -f roq -t 0.2
FATE_IFF-$(CONFIG_IFF_BYTERUN1_DECODER) += fate-iff-byterun1
fate-iff-byterun1: CMD = framecrc -i $(TARGET_SAMPLES)/iff/ASH.LBM -pix_fmt rgb24
@@ -169,54 +177,57 @@ fate-iff-fibonacci: CMD = md5 -i $(TARGET_SAMPLES)/iff/dasboot-in-compressed -f
FATE_IFF-$(CONFIG_IFF_ILBM_DECODER) += fate-iff-ilbm
fate-iff-ilbm: CMD = framecrc -i $(TARGET_SAMPLES)/iff/lms-matriks.ilbm -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(CONFIG_IFF_DEMUXER) += $(FATE_IFF-yes)
+FATE_VIDEO-$(CONFIG_IFF_DEMUXER) += $(FATE_IFF-yes)
fate-iff: $(FATE_IFF-yes)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IPMOVIE, INTERPLAY_VIDEO) += fate-interplay-mve-8bit
+FATE_VIDEO-$(call DEMDEC, IPMOVIE, INTERPLAY_VIDEO) += fate-interplay-mve-8bit
fate-interplay-mve-8bit: CMD = framecrc -i $(TARGET_SAMPLES)/interplay-mve/interplay-logo-2MB.mve -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, IPMOVIE, INTERPLAY_VIDEO) += fate-interplay-mve-16bit
+FATE_VIDEO-$(call DEMDEC, IPMOVIE, INTERPLAY_VIDEO) += fate-interplay-mve-16bit
fate-interplay-mve-16bit: CMD = framecrc -i $(TARGET_SAMPLES)/interplay-mve/descent3-level5-16bit-partial.mve -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MXF, JPEG2000) += fate-jpeg2000-dcinema
+FATE_VIDEO-$(call DEMDEC, MXF, JPEG2000) += fate-jpeg2000-dcinema
fate-jpeg2000-dcinema: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/jpeg2000/chiens_dcinema2K.mxf -pix_fmt xyz12le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, JV, JV) += fate-jv
+FATE_VIDEO-$(call DEMDEC, JV, JV) += fate-jv
fate-jv: CMD = framecrc -i $(TARGET_SAMPLES)/jv/intro.jv -an -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, KGV1) += fate-kgv1
+FATE_VIDEO-$(call DEMDEC, AVI, KGV1) += fate-kgv1
fate-kgv1: CMD = framecrc -i $(TARGET_SAMPLES)/kega/kgv1.avi -pix_fmt rgb555le -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, KMVC) += fate-kmvc
+FATE_VIDEO-$(call DEMDEC, AVI, KMVC) += fate-kmvc
fate-kmvc: CMD = framecrc -i $(TARGET_SAMPLES)/KMVC/LOGO1.AVI -an -t 3 -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, EA, MDEC) += fate-mdec
+FATE_VIDEO-$(call DEMDEC, EA, MDEC) += fate-mdec
fate-mdec: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/ea-dct/NFS2Esprit-partial.dct -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, STR, MDEC) += fate-mdec-v3
+FATE_VIDEO-$(call DEMDEC, STR, MDEC) += fate-mdec-v3
fate-mdec-v3: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/psx-str/abc000_cut.str -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MSNWC_TCP, MIMIC) += fate-mimic
+FATE_VIDEO-$(call DEMDEC, MSNWC_TCP, MIMIC) += fate-mimic
fate-mimic: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/mimic/mimic2-womanloveffmpeg.cam
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, MJPEGB) += fate-mjpegb
+FATE_VIDEO-$(call DEMDEC, MOV, MJPEGB) += fate-mjpegb
fate-mjpegb: CMD = framecrc -idct simple -fflags +bitexact -i $(TARGET_SAMPLES)/mjpegb/mjpegb_part.mov -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MVI, MOTIONPIXELS) += fate-motionpixels
+FATE_VIDEO-$(call DEMDEC, MVI, MOTIONPIXELS) += fate-motionpixels
fate-motionpixels: CMD = framecrc -i $(TARGET_SAMPLES)/motion-pixels/INTRO-partial.MVI -an -pix_fmt rgb24 -vframes 111
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MPEGTS, MPEG2VIDEO) += fate-mpeg2-field-enc
+FATE_VIDEO-$(call DEMDEC, MPEGTS, MPEG2VIDEO) += fate-mpeg2-field-enc
fate-mpeg2-field-enc: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/mpeg2/mpeg2_field_encoding.ts -an -vframes 30
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MV, MVC1) += fate-mv-mvc1
+FATE_VIDEO-$(call DEMDEC, MV, MVC1) += fate-mv-mvc1
fate-mv-mvc1: CMD = framecrc -i $(TARGET_SAMPLES)/mv/posture.mv -an -frames 25 -pix_fmt rgb555le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MV, MVC2) += fate-mv-mvc2
+FATE_VIDEO-$(call DEMDEC, MV, MVC2) += fate-mv-mvc2
fate-mv-mvc2: CMD = framecrc -i $(TARGET_SAMPLES)/mv/12345.mv -an -frames 30 -pix_fmt bgra
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MV, SGIRLE) += fate-mv-sgirle
+FATE_VIDEO-$(call DEMDEC, MV, SGIRLE) += fate-mv-sgirle
fate-mv-sgirle: CMD = framecrc -i $(TARGET_SAMPLES)/mv/pet-rle.movie -an
+FATE_VIDEO-$(call DEMDEC, MXG, MXPEG) += fate-mxpeg
+fate-mxpeg: CMD = framecrc -idct simple -flags +bitexact -i $(TARGET_SAMPLES)/mxpeg/m1.mxg -an
+
# FIXME dropped frames in this test because of coarse timebase
FATE_NUV += fate-nuv-rtjpeg
fate-nuv-rtjpeg: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/nuv/Today.nuv -an
@@ -224,49 +235,46 @@ fate-nuv-rtjpeg: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/nuv/Today.nuv
FATE_NUV += fate-nuv-rtjpeg-fh
fate-nuv-rtjpeg-fh: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/nuv/rtjpeg_frameheader.nuv -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, NUV, NUV) += $(FATE_NUV)
+FATE_VIDEO-$(call DEMDEC, NUV, NUV) += $(FATE_NUV)
fate-nuv: $(FATE_NUV)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, PAF, PAF_VIDEO) += fate-paf-video
+FATE_VIDEO-$(call DEMDEC, PAF, PAF_VIDEO) += fate-paf-video
fate-paf-video: CMD = framecrc -i $(TARGET_SAMPLES)/paf/hod1-partial.paf -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, QPEG) += fate-qpeg
+FATE_VIDEO-$(call DEMDEC, AVI, QPEG) += fate-qpeg
fate-qpeg: CMD = framecrc -i $(TARGET_SAMPLES)/qpeg/Clock.avi -an -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, R210) += fate-r210
+FATE_VIDEO-$(call DEMDEC, AVI, R210) += fate-r210
fate-r210: CMD = framecrc -i $(TARGET_SAMPLES)/r210/r210.avi -pix_fmt rgb48le
-FATE_SAMPLES_AVCONV-$(call DEMDEC, RL2, RL2) += fate-rl2
+FATE_VIDEO-$(call DEMDEC, RL2, RL2) += fate-rl2
fate-rl2: CMD = framecrc -i $(TARGET_SAMPLES)/rl2/Z4915300.RL2 -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, ROQ, ROQ) += fate-roqvideo
+FATE_VIDEO-$(call DEMDEC, ROQ, ROQ) += fate-roqvideo
fate-roqvideo: CMD = framecrc -i $(TARGET_SAMPLES)/idroq/idlogo.roq -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SMUSH, SANM) += fate-sanm
+FATE_VIDEO-$(call DEMDEC, SMUSH, SANM) += fate-sanm
fate-sanm: CMD = framecrc -i $(TARGET_SAMPLES)/smush/ronin_part.znm -an -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, VMD, VMDVIDEO) += fate-sierra-vmd-video
+FATE_VIDEO-$(call DEMDEC, VMD, VMDVIDEO) += fate-sierra-vmd-video
fate-sierra-vmd-video: CMD = framecrc -i $(TARGET_SAMPLES)/vmd/12.vmd -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SMACKER, SMACKER) += fate-smacker-video
+FATE_VIDEO-$(call DEMDEC, SMACKER, SMACKER) += fate-smacker-video
fate-smacker-video: CMD = framecrc -i $(TARGET_SAMPLES)/smacker/wetlogo.smk -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, SMC) += fate-smc
+FATE_VIDEO-$(call DEMDEC, MOV, SMC) += fate-smc
fate-smc: CMD = framecrc -i $(TARGET_SAMPLES)/smc/cass_schi.qt -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, SP5X) += fate-sp5x
+FATE_VIDEO-$(call DEMDEC, AVI, SP5X) += fate-sp5x
fate-sp5x: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/sp5x/sp5x_problem.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SRT, SRT) += fate-sub-srt
-fate-sub-srt: CMD = md5 -i $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt -f ass
-
-FATE_SAMPLES_AVCONV-$(call DEMDEC, THP, THP) += fate-thp
+FATE_VIDEO-$(call DEMDEC, THP, THP) += fate-thp
fate-thp: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/thp/pikmin2-opening1-partial.thp -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TIERTEXSEQ, TIERTEXSEQVIDEO) += fate-tiertex-seq
+FATE_VIDEO-$(call DEMDEC, TIERTEXSEQ, TIERTEXSEQVIDEO) += fate-tiertex-seq
fate-tiertex-seq: CMD = framecrc -i $(TARGET_SAMPLES)/tiertex-seq/Gameover.seq -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TMV, TMV) += fate-tmv
+FATE_VIDEO-$(call DEMDEC, TMV, TMV) += fate-tmv
fate-tmv: CMD = framecrc -i $(TARGET_SAMPLES)/tmv/pop-partial.tmv -pix_fmt rgb24
FATE_TXD += fate-txd-16bpp
@@ -275,42 +283,53 @@ fate-txd-16bpp: CMD = framecrc -i $(TARGET_SAMPLES)/txd/misc.txd -pix_fmt bgra -
FATE_TXD += fate-txd-pal8
fate-txd-pal8: CMD = framecrc -i $(TARGET_SAMPLES)/txd/outro.txd -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, TXD, TXD) += $(FATE_TXD)
+FATE_VIDEO-$(call DEMDEC, TXD, TXD) += $(FATE_TXD)
fate-txd: $(FATE_TXD)
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, ULTI) += fate-ulti
+FATE_VIDEO-$(call DEMDEC, AVI, ULTI) += fate-ulti
fate-ulti: CMD = framecrc -i $(TARGET_SAMPLES)/ulti/hit12w.avi -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, V210) += fate-v210
+FATE_VIDEO-$(call DEMDEC, AVI, V210) += fate-v210
fate-v210: CMD = framecrc -i $(TARGET_SAMPLES)/v210/v210_720p-partial.avi -pix_fmt yuv422p16be -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, V410) += fate-v410dec
+FATE_VIDEO-$(call DEMDEC, MOV, V410) += fate-v410dec
fate-v410dec: CMD = framecrc -i $(TARGET_SAMPLES)/v410/lenav410.mov -pix_fmt yuv444p10le
-FATE_SAMPLES_AVCONV-$(call ENCDEC, V410 PGMYUV, AVI IMAGE2) += fate-v410enc
+FATE_VIDEO-$(call ENCDEC, V410 PGMYUV, AVI IMAGE2) += fate-v410enc
fate-v410enc: $(VREF)
fate-v410enc: CMD = md5 -f image2 -vcodec pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -fflags +bitexact -vcodec v410 -f avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, SIFF, VB) += fate-vb
+FATE_VIDEO-$(call DEMDEC, SIFF, VB) += fate-vb
fate-vb: CMD = framecrc -i $(TARGET_SAMPLES)/SIFF/INTRO_B.VB -t 3 -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, VCR1) += fate-vcr1
+FATE_VIDEO-$(call DEMDEC, AVI, VCR1) += fate-vcr1
fate-vcr1: CMD = framecrc -i $(TARGET_SAMPLES)/vcr1/VCR1test.avi -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, XL) += fate-videoxl
+FATE_VIDEO-$(call DEMDEC, AVI, MPEG2VIDEO) += fate-vcr2
+fate-vcr2: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_SAMPLES)/vcr2/VCR2test.avi -an
+
+FATE_VIDEO-$(call DEMDEC, AVI, XL) += fate-videoxl
fate-videoxl: CMD = framecrc -i $(TARGET_SAMPLES)/vixl/pig-vixl.avi
-FATE_SAMPLES_AVCONV-$(call DEMDEC, WSVQA, VQA) += fate-vqa-cc
+FATE_VIDEO-$(call DEMDEC, WSVQA, VQA) += fate-vqa-cc
fate-vqa-cc: CMD = framecrc -i $(TARGET_SAMPLES)/vqa/cc-demo1-partial.vqa -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, WC3, XAN_WC3) += fate-wc3movie-xan
+FATE_VIDEO-$(call DEMDEC, WC3, XAN_WC3) += fate-wc3movie-xan
fate-wc3movie-xan: CMD = framecrc -i $(TARGET_SAMPLES)/wc3movie/SC_32-part.MVE -pix_fmt rgb24
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, WNV1) += fate-wnv1
+FATE_VIDEO-$(call DEMDEC, AVI, WNV1) += fate-wnv1
fate-wnv1: CMD = framecrc -i $(TARGET_SAMPLES)/wnv1/wnv1-codec.avi -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, YOP, YOP) += fate-yop
+FATE_VIDEO-$(call DEMDEC, YOP, YOP) += fate-yop
fate-yop: CMD = framecrc -i $(TARGET_SAMPLES)/yop/test1.yop -pix_fmt rgb24 -an
-FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, XAN_WC4) += fate-xxan-wc4
+FATE_VIDEO-$(call DEMDEC, AVI, XAN_WC4) += fate-xxan-wc4
fate-xxan-wc4: CMD = framecrc -i $(TARGET_SAMPLES)/wc4-xan/wc4trailer-partial.avi -an
+
+FATE_VIDEO-$(call DEMDEC, WAV, SMVJPEG) += fate-smvjpeg
+fate-smvjpeg: CMD = framecrc -idct simple -flags +bitexact -i $(TARGET_SAMPLES)/smv/clock.smv -an
+
+FATE_VIDEO += $(FATE_VIDEO-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_VIDEO)
+fate-video: $(FATE_VIDEO)
diff --git a/tests/fate/voice.mak b/tests/fate/voice.mak
index 975936c3ef..44b5b932a7 100644
--- a/tests/fate/voice.mak
+++ b/tests/fate/voice.mak
@@ -1,12 +1,12 @@
-FATE_G722 += fate-g722dec-1
+FATE_G722-$(call DEMDEC, G722, ADPCM_G722) += fate-g722dec-1
fate-g722dec-1: CMD = framecrc -i $(TARGET_SAMPLES)/g722/conf-adminmenu-162.g722
-FATE_G722 += fate-g722-encode
+FATE_G722-$(call ENCMUX, ADPCM_G722, WAV) += fate-g722-encode
fate-g722-encode: tests/data/asynth-16000-1.wav
fate-g722-encode: SRC = tests/data/asynth-16000-1.wav
fate-g722-encode: CMD = enc_dec_pcm wav md5 s16le $(SRC) -c:a g722
-FATE_SAMPLES_AVCONV += $(FATE_G722)
+FATE_VOICE-yes += $(FATE_G722-yes)
fate-g722: $(FATE_G722)
FATE_G723_1 += fate-g723_1-dec-1
@@ -33,7 +33,8 @@ fate-g723_1-dec-7: CMD = framecrc -postfilter 1 -i $(TARGET_SAMPLES)/g723_1/dtx6
FATE_G723_1 += fate-g723_1-dec-8
fate-g723_1-dec-8: CMD = framecrc -postfilter 1 -i $(TARGET_SAMPLES)/g723_1/dtx63e.tco
-FATE_SAMPLES_AVCONV += $(FATE_G723_1)
+FATE_G723_1-$(call DEMDEC, G723_1, G723_1) += $(FATE_G723_1)
+FATE_SAMPLES_AVCONV += $(FATE_G723_1-yes)
fate-g723_1: $(FATE_G723_1)
FATE_G726 += fate-g726-encode-2bit
@@ -51,24 +52,27 @@ fate-g726-encode-5bit: CMD = enc_dec_pcm wav md5 s16le $(SRC) -c:a g726 -b:a 40k
$(FATE_G726): tests/data/asynth-8000-1.wav
$(FATE_G726): SRC = tests/data/asynth-8000-1.wav
-FATE_SAMPLES_AVCONV += $(FATE_G726)
+FATE_VOICE-$(call ENCMUX, ADPCM_G726, WAV) += $(FATE_G726)
fate-g726: $(FATE_G726)
-FATE_GSM += fate-gsm-ms
+FATE_GSM-$(call DEMDEC, WAV, GSM) += fate-gsm-ms
fate-gsm-ms: CMD = framecrc -i $(TARGET_SAMPLES)/gsm/ciao.wav
-FATE_GSM += fate-gsm-toast
+FATE_GSM-$(call DEMDEC, MOV, GSM) += fate-gsm-toast
fate-gsm-toast: CMD = framecrc -i $(TARGET_SAMPLES)/gsm/sample-gsm-8000.mov -t 10
-FATE_SAMPLES_AVCONV += $(FATE_GSM)
+FATE_VOICE-yes += $(FATE_GSM-yes)
fate-gsm: $(FATE_GSM)
-FATE_SAMPLES_AVCONV += fate-qcelp
+FATE_VOICE-$(call DEMDEC, QCP, QCELP) += fate-qcelp
fate-qcelp: CMD = pcm -i $(TARGET_SAMPLES)/qcp/0036580847.QCP
fate-qcelp: CMP = oneoff
fate-qcelp: REF = $(SAMPLES)/qcp/0036580847.pcm
-FATE_SAMPLES_AVCONV += fate-truespeech
+FATE_VOICE-$(call DEMDEC, WAV, TRUESPEECH) += fate-truespeech
fate-truespeech: CMD = pcm -i $(TARGET_SAMPLES)/truespeech/a6.wav
fate-truespeech: CMP = oneoff
fate-truespeech: REF = $(SAMPLES)/truespeech/a6.pcm
+
+FATE_SAMPLES_FFMPEG += $(FATE_VOICE-yes)
+fate-voice: $(FATE_VOICE-yes)
diff --git a/tests/fate/vpx.mak b/tests/fate/vpx.mak
index b9c7c2032a..c381757eb4 100644
--- a/tests/fate/vpx.mak
+++ b/tests/fate/vpx.mak
@@ -22,9 +22,30 @@ fate-vp61: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/ea-vp6/MovieSkir
FATE_VP6-$(call DEMDEC, FLV, VP6A) += fate-vp6a
fate-vp6a: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/flash-vp6/300x180-Scr-f8-056alpha.flv
+FATE_VP6-$(call DEMDEC, FLV, VP6A) += fate-vp6a-skip_alpha
+fate-vp6a-skip_alpha: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/flash-vp6/300x180-Scr-f8-056alpha.flv
+
FATE_VP6-$(call DEMDEC, FLV, VP6F) += fate-vp6f
fate-vp6f: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/flash-vp6/clip1024.flv
+FATE_VP8-$(call DEMDEC, FLV, VP8) += fate-vp8-alpha
+fate-vp8-alpha: CMD = framecrc -i $(TARGET_SAMPLES)/vp8_alpha/vp8_video_with_alpha.webm -vcodec copy
+
+FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest
+fate-webm-dash-manifest: CMD = run ffmpeg -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video2.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio2.webm -c copy -map 0 -map 1 -map 2 -map 3 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1 id=1,streams=2,3" -
+
+FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest-unaligned-video-streams
+fate-webm-dash-manifest-unaligned-video-streams: CMD = run ffmpeg -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video3.webm -c copy -map 0 -map 1 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1" -
+
+FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest-unaligned-audio-streams
+fate-webm-dash-manifest-unaligned-audio-streams: CMD = run ffmpeg -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio3.webm -c copy -map 0 -map 1 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1" -
+
+FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest-representations
+fate-webm-dash-manifest-representations: CMD = run ffmpeg -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video4.webm -c copy -map 0 -map 1 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1" -
+
+FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest-live
+fate-webm-dash-manifest-live: CMD = run ffmpeg -f webm_dash_manifest -live 1 -i $(TARGET_SAMPLES)/vp8/dash_live_video_360.hdr -f webm_dash_manifest -live 1 -i $(TARGET_SAMPLES)/vp8/dash_live_audio_171.hdr -c copy -map 0 -map 1 -f webm_dash_manifest -live 1 -adaptation_sets "id=0,streams=0 id=1,streams=1" -chunk_start_index 1 -chunk_duration_ms 5000 -time_shift_buffer_depth 7200 -minimum_update_period 60 -debug_mode 1 -
+
FATE_SAMPLES_AVCONV += $(FATE_VP6-yes)
fate-vp6: $(FATE_VP6-yes)
@@ -43,17 +64,17 @@ define FATE_VP8_FULL
$(foreach N,$(VP8_SUITE),$(eval $(call FATE_VP8_SUITE,$(N),$(1),$(2))))
# FIXME this file contains two frames with identical timestamps,
-# so avconv drops one of them
+# so ffmpeg drops one of them
FATE_VP8-$(CONFIG_IVF_DEMUXER) += fate-vp8-sign-bias$(1)
fate-vp8-sign-bias$(1): CMD = framemd5 $(2) -i $(TARGET_SAMPLES)/vp8/sintel-signbias.ivf
fate-vp8-sign-bias$(1): REF = $(SRC_PATH)/tests/ref/fate/vp8-sign-bias
FATE_VP8-$(CONFIG_MATROSKA_DEMUXER) += fate-vp8-size-change$(1)
-fate-vp8-size-change$(1): CMD = framemd5 $(2) -i $(TARGET_SAMPLES)/vp8/frame_size_change.webm -frames:v 30
+fate-vp8-size-change$(1): CMD = framemd5 $(2) -flags +bitexact -i $(TARGET_SAMPLES)/vp8/frame_size_change.webm -frames:v 30 -sws_flags bitexact+bilinear
fate-vp8-size-change$(1): REF = $(SRC_PATH)/tests/ref/fate/vp8-size-change
endef
-$(call FATE_VP8_FULL)
+$(eval $(call FATE_VP8_FULL))
FATE_SAMPLES_AVCONV-$(CONFIG_VP8_DECODER) += $(FATE_VP8-yes)
fate-vp8: $(FATE_VP8-yes)
@@ -64,6 +85,12 @@ fate-vp9$(2)-$(1): CMD = framemd5 $(3) -i $(TARGET_SAMPLES)/vp9-test-vectors/vp9
fate-vp9$(2)-$(1): REF = $(SRC_PATH)/tests/ref/fate/vp9-$(1)
endef
+define FATE_VP9_PROFILE_SUITE
+FATE_VP9-$(CONFIG_MATROSKA_DEMUXER) += fate-vp9p$(2)-$(1)
+fate-vp9p$(2)-$(1): CMD = framemd5 -i $(TARGET_SAMPLES)/vp9-test-vectors/vp9$(2)-2-$(1).webm $(3)
+fate-vp9p$(2)-$(1): REF = $(SRC_PATH)/tests/ref/fate/vp9p$(2)-$(1)
+endef
+
VP9_Q = 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 \
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 \
@@ -71,21 +98,37 @@ VP9_Q = 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \
VP9_SHARP = 1 2 3 4 5 6 7
VP9_SIZE_A = 08 10 16 18 32 34 64 66
VP9_SIZE_B = 196 198 200 202 208 210 224 226
+VP9_CHROMA_SUBSAMPLE = 422 440 444
+VP9_HIGH_BITDEPTH = 10 12
define FATE_VP9_FULL
-$(foreach Q,$(VP9_Q),$(eval $(call FATE_VP9_SUITE,00-quantizer-$(Q),$(1),$(2))))
-$(foreach SHARP,$(VP9_SHARP),$(eval $(call FATE_VP9_SUITE,01-sharpness-$(SHARP),$(1),$(2))))
-$(foreach W,$(VP9_SIZE_A),$(eval $(foreach H,$(VP9_SIZE_A),$(eval $(call FATE_VP9_SUITE,02-size-$(W)x$(H),$(1),$(2))))))
-$(foreach W,$(VP9_SIZE_B),$(eval $(foreach H,$(VP9_SIZE_B),$(eval $(call FATE_VP9_SUITE,03-size-$(W)x$(H),$(1),$(2))))))
-$(eval $(call FATE_VP9_SUITE,03-deltaq,$(1),$(2)))
-$(eval $(call FATE_VP9_SUITE,2pass-akiyo,$(1),$(2)))
-$(eval $(call FATE_VP9_SUITE,parallelmode-akiyo,$(1),$(2)))
-$(eval $(call FATE_VP9_SUITE,segmentation-aq-akiyo,$(1),$(2)))
-$(eval $(call FATE_VP9_SUITE,segmentation-sf-akiyo,$(1),$(2)))
-$(eval $(call FATE_VP9_SUITE,tiling-pedestrian,$(1),$(2)))
+$(foreach Q,$(VP9_Q),$(eval $(call FATE_VP9_SUITE,00-quantizer-$(Q))))
+$(foreach SHARP,$(VP9_SHARP),$(eval $(call FATE_VP9_SUITE,01-sharpness-$(SHARP))))
+$(foreach W,$(VP9_SIZE_A),$(eval $(foreach H,$(VP9_SIZE_A),$(eval $(call FATE_VP9_SUITE,02-size-$(W)x$(H))))))
+$(foreach W,$(VP9_SIZE_B),$(eval $(foreach H,$(VP9_SIZE_B),$(eval $(call FATE_VP9_SUITE,03-size-$(W)x$(H))))))
+$(eval $(call FATE_VP9_SUITE,03-deltaq))
+$(foreach SS,$(VP9_CHROMA_SUBSAMPLE),$(eval $(call FATE_VP9_PROFILE_SUITE,04-yuv$(SS),1,)))
+$(foreach BD,$(VP9_HIGH_BITDEPTH),$(eval $(call FATE_VP9_PROFILE_SUITE,20-$(BD)bit-yuv420,2,-pix_fmt yuv420p$(BD)le)))
+$(foreach BD,$(VP9_HIGH_BITDEPTH),$(eval $(foreach SS,$(VP9_CHROMA_SUBSAMPLE),$(eval $(call FATE_VP9_PROFILE_SUITE,20-$(BD)bit-yuv$(SS),3,-pix_fmt yuv$(SS)p$(BD)le)))))
+$(eval $(call FATE_VP9_SUITE,06-bilinear))
+$(eval $(call FATE_VP9_SUITE,09-lf_deltas))
+$(eval $(call FATE_VP9_SUITE,10-show-existing-frame))
+$(eval $(call FATE_VP9_SUITE,10-show-existing-frame2))
+$(eval $(call FATE_VP9_SUITE,15-segkey_adpq))
+$(eval $(call FATE_VP9_SUITE,16-intra-only))
+$(eval $(call FATE_VP9_SUITE,2pass-akiyo))
+$(eval $(call FATE_VP9_SUITE,parallelmode-akiyo))
+$(eval $(call FATE_VP9_SUITE,segmentation-aq-akiyo))
+$(eval $(call FATE_VP9_SUITE,segmentation-sf-akiyo))
+$(eval $(call FATE_VP9_SUITE,tiling-pedestrian))
+$(eval $(call FATE_VP9_SUITE,trac3849))
+$(eval $(call FATE_VP9_SUITE,trac4359))
endef
$(eval $(call FATE_VP9_FULL))
+FATE_VP9-$(CONFIG_IVF_DEMUXER) += fate-vp9-05-resize
+fate-vp9-05-resize: CMD = framemd5 -i $(TARGET_SAMPLES)/vp9-test-vectors/vp90-2-05-resize.ivf -s 352x288 -sws_flags bitexact+bilinear
+fate-vp9-05-resize: REF = $(SRC_PATH)/tests/ref/fate/vp9-05-resize
FATE_SAMPLES_AVCONV-$(CONFIG_VP9_DECODER) += $(FATE_VP9-yes)
fate-vp9: $(FATE_VP9-yes)
diff --git a/tests/fate/vqf.mak b/tests/fate/vqf.mak
index 355bab0908..ac18ebd585 100644
--- a/tests/fate/vqf.mak
+++ b/tests/fate/vqf.mak
@@ -1,7 +1,12 @@
-FATE_SAMPLES_AVCONV-$(call DEMDEC, VQF, TWINVQ) += fate-twinvq
+FATE_VQF-$(call DEMDEC, VQF, TWINVQ) += fate-twinvq
fate-twinvq: CMD = pcm -i $(TARGET_SAMPLES)/vqf/achterba.vqf
fate-twinvq: CMP = oneoff
fate-twinvq: REF = $(SAMPLES)/vqf/achterba.pcm
-FATE_SAMPLES_AVCONV-$(CONFIG_VQF_DEMUXER) += fate-vqf-demux
-fate-vqf-demux: CMD = md5 -i $(TARGET_SAMPLES)/vqf/achterba.vqf -acodec copy -f framecrc
+FATE_VQF-$(CONFIG_VQF_DEMUXER) += fate-vqf-demux
+fate-vqf-demux: CMD = md5 -i $(TARGET_SAMPLES)/vqf/achterba.vqf -acodec copy -flags bitexact -f framecrc
+
+FATE_VQF += $(FATE_VQF-yes)
+
+FATE_SAMPLES_FFMPEG += $(FATE_VQF)
+fate-vqf: $(FATE_VQF)
diff --git a/tests/fate/wavpack.mak b/tests/fate/wavpack.mak
index 3432cc6e0d..240f5ead94 100644
--- a/tests/fate/wavpack.mak
+++ b/tests/fate/wavpack.mak
@@ -1,102 +1,102 @@
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += $(FATE_WAVPACK)
+
# lossless
-FATE_WAVPACK += fate-wavpack-lossless-8bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossless-8bit
fate-wavpack-lossless-8bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossless/8bit-partial.wv -f s8
-FATE_WAVPACK += fate-wavpack-lossless-12bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossless-12bit
fate-wavpack-lossless-12bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossless/12bit-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-lossless-16bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossless-16bit
fate-wavpack-lossless-16bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossless/16bit-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-lossless-24bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossless-24bit
fate-wavpack-lossless-24bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossless/24bit-partial.wv -f s24le
-FATE_WAVPACK += fate-wavpack-lossless-32bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossless-32bit
fate-wavpack-lossless-32bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossless/32bit_int-partial.wv -f s32le
-FATE_WAVPACK += fate-wavpack-lossless-float
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossless-float
fate-wavpack-lossless-float: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossless/32bit_float-partial.wv -f f32le
# lossy
-FATE_WAVPACK += fate-wavpack-lossy-8bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossy-8bit
fate-wavpack-lossy-8bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossy/4.0_8-bit.wv -f s8
-FATE_WAVPACK += fate-wavpack-lossy-16bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossy-16bit
fate-wavpack-lossy-16bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossy/4.0_16-bit.wv -f s16le
-FATE_WAVPACK += fate-wavpack-lossy-24bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossy-24bit
fate-wavpack-lossy-24bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossy/4.0_24-bit.wv -f s24le
-FATE_WAVPACK += fate-wavpack-lossy-32bit
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossy-32bit
fate-wavpack-lossy-32bit: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossy/4.0_32-bit_int.wv -f s32le
-FATE_WAVPACK += fate-wavpack-lossy-float
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-lossy-float
fate-wavpack-lossy-float: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/lossy/2.0_32-bit_float.wv -f f32le
# channel configurations
-FATE_WAVPACK += fate-wavpack-channels-monofloat
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-channels-monofloat
fate-wavpack-channels-monofloat: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/mono_float-partial.wv -f f32le
-FATE_WAVPACK += fate-wavpack-channels-monoint
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-channels-monoint
fate-wavpack-channels-monoint: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/mono_16bit_int.wv -f s16le
-FATE_WAVPACK += fate-wavpack-channels-4.0
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-channels-4.0
fate-wavpack-channels-4.0: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/edward_4.0_16bit-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-channels-5.1
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-channels-5.1
fate-wavpack-channels-5.1: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/panslab_sample_5.1_16bit-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-channels-6.1
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-channels-6.1
fate-wavpack-channels-6.1: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/eva_2.22_6.1_16bit-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-channels-7.1
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-channels-7.1
fate-wavpack-channels-7.1: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/panslab_sample_7.1_16bit-partial.wv -f s16le
# speed modes
-FATE_WAVPACK += fate-wavpack-speed-default
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-speed-default
fate-wavpack-speed-default: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/speed_modes/default-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-speed-fast
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-speed-fast
fate-wavpack-speed-fast: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/speed_modes/fast-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-speed-high
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-speed-high
fate-wavpack-speed-high: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/speed_modes/high-partial.wv -f s16le
-FATE_WAVPACK += fate-wavpack-speed-vhigh
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-speed-vhigh
fate-wavpack-speed-vhigh: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/speed_modes/vhigh-partial.wv -f s16le
# special cases
-FATE_WAVPACK += fate-wavpack-clipping
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-clipping
fate-wavpack-clipping: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/clipping.wv -f s16le
-FATE_WAVPACK += fate-wavpack-cuesheet
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-cuesheet
fate-wavpack-cuesheet: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/cue_sheet.wv -f s16le
-FATE_WAVPACK += fate-wavpack-falsestereo
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-falsestereo
fate-wavpack-falsestereo: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/false_stereo.wv -f s16le
-FATE_WAVPACK += fate-wavpack-zerolsbs
+FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += fate-wavpack-zerolsbs
fate-wavpack-zerolsbs: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/zero_lsbs.wv -f s16le
-FATE_WAVPACK-$(call DEMDEC, WV, WAVPACK) += $(FATE_WAVPACK)
-
FATE_WAVPACK-$(call DEMDEC, MATROSKA, WAVPACK) += fate-wavpack-matroskamode
fate-wavpack-matroskamode: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/matroska_mode.mka -f s16le
FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-mono
fate-wavpack-matroska_mux-mono: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/mono_16bit_int.wv -c copy -fflags +bitexact -f matroska
fate-wavpack-matroska_mux-mono: CMP = oneline
-fate-wavpack-matroska_mux-mono: REF = 6bd769b3f0e9d7fa6261c3b73a53eb7d
+fate-wavpack-matroska_mux-mono: REF = a2987e2e51e01a35e47e7da13eb47a35
FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-61
fate-wavpack-matroska_mux-61: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/num_channels/eva_2.22_6.1_16bit-partial.wv -c copy -fflags +bitexact -f matroska
fate-wavpack-matroska_mux-61: CMP = oneline
-fate-wavpack-matroska_mux-61: REF = 2d2f1e7f81a8b1983fcffc7f24de8a11
+fate-wavpack-matroska_mux-61: REF = ffba4ddea1ba71f7a5901d9ed1a267be
FATE_SAMPLES_AVCONV += $(FATE_WAVPACK-yes)
fate-wavpack: $(FATE_WAVPACK-yes)
diff --git a/tests/ffserver-regression.sh b/tests/ffserver-regression.sh
new file mode 100755
index 0000000000..11e4a5419e
--- /dev/null
+++ b/tests/ffserver-regression.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "<Stream $_>\nFile $wd/tests/data/$_\n</Stream>\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf
+#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "<Stream $_.asf>\nFile $wd/tests/data/$_\n</Stream>\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf
+
+. $(dirname $0)/md5.sh
+
+FILES=$(sed -n 's/^[^#]*<Stream \(.*\)>.*/\1/p' $2 | grep -v html)
+
+rm -f tests/feed1.ffm
+./ffserver -d -f "$2" 2> /dev/null &
+FFSERVER_PID=$!
+echo "Waiting for feeds to startup..."
+sleep 2
+(
+ cd tests/data || exit $?
+ rm -f ff-* ffserver.regression
+ WGET_OPTIONS="--user-agent=NSPlayer -q --proxy=off -e verbose=off -e server_response=off"
+ for file in $FILES; do
+ if [ $(expr $file : "a-*") != 0 ]; then
+ wget $WGET_OPTIONS -O - http://localhost:9999/$file > ff-$file
+ else
+ wget $WGET_OPTIONS -O - http://localhost:9999/$file?date=19700101T000000Z | dd bs=1 count=20000 > ff-$file 2>/dev/null
+ fi
+ do_md5sum ff-$file >>ffserver.regression
+ done
+)
+kill $FFSERVER_PID
+wait > /dev/null 2>&1
+rm -f tests/feed1.ffm
+if diff -u "$1" tests/data/ffserver.regression; then
+ echo
+ echo Server regression test succeeded.
+ exit 0
+else
+ echo
+ echo Server regression test: Error.
+ exit 1
+fi
diff --git a/tests/ffserver.conf b/tests/ffserver.conf
new file mode 100644
index 0000000000..ae35d7f5da
--- /dev/null
+++ b/tests/ffserver.conf
@@ -0,0 +1,311 @@
+#
+# This is a test configuration file. You can invoke it with
+# ../ffserver -f ffserver.conf
+# when in the tests directory and once the vsynth1 subdirectory
+# has been populated. Then point your browser at http://whatever:9999/teststat.html
+# and you can look at the streams
+#
+
+#
+# Port on which the server is listening. You must select a different
+# port from your standard http web server if it is running on the same
+# computer.
+
+HTTPPort 9999
+RTSPPort 9990
+
+# Address on which the server is bound. Only useful if you have
+# several network interfaces.
+
+HTTPBindAddress 0.0.0.0
+
+# Number of simultaneous requests that can be handled. Since FFServer
+# is very fast, this limit is determined mainly by your Internet
+# connection speed.
+
+MaxClients 1000
+
+MaxBandwidth 100000
+
+# Access Log file (uses standard Apache log file format)
+# '-' is the standard output
+
+CustomLog -
+
+##################################################################
+# Definition of the live feeds. Each live feed contains one video
+# and/or audio sequence coming from an ffmpeg encoder or another
+# ffserver. This sequence may be encoded simultaneously with several
+# codecs at several resolutions.
+
+<Feed feed1.ffm>
+
+# You must use 'ffmpeg' to send a live feed to ffserver. In this
+# example, you can type:
+#
+# ffmpeg http://localhost:8090/feed1.ffm
+
+# ffserver can also do time shifting. It means that it can stream any
+# previously recorded live stream. The request should contain:
+# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify
+# a path where the feed is stored on disk. You also specify the
+# maximum size of the feed (100M bytes here). Default:
+# File=/tmp/feed_name.ffm FileMaxSize=5M
+
+File tests/feed1.ffm
+FileMaxSize 100M
+
+# Fire up ffmpeg pointing at this stream
+
+Launch ./ffmpeg -v 0 -y -f image2 -i tests/vsynth1/%02d.pgm
+
+ACL allow localhost
+</Feed>
+
+##################################################################
+# Now you can define each stream which will be generated from the
+# original audio and video stream. Each format has a filename (here
+# 'test128.mpg'). FFServer will send this stream when answering a
+# request containing this filename.
+
+<Stream test_h.avi>
+Feed feed1.ffm
+Format avi
+#
+BitExact
+DctFastint
+IdctSimple
+VideoFrameRate 10
+VideoSize 352x288
+VideoBitRate 100
+VideoGopSize 30
+NoAudio
+
+PreRoll 10
+StartSendOnKey
+MaxTime 100
+
+</Stream>
+
+<Stream test_l.avi>
+Feed feed1.ffm
+Format avi
+#
+BitExact
+DctFastint
+IdctSimple
+VideoFrameRate 2
+VideoSize 320x240
+VideoBitRate 40
+VideoGopSize 20
+NoAudio
+
+PreRoll 20
+StartSendOnKey
+MaxTime 100
+
+</Stream>
+
+#<Stream test_h.mpg>
+#Feed feed1.ffm
+#
+#VideoFrameRate 10
+#VideoSize 352x288
+#VideoBitRate 100
+#VideoGopSize 30
+#NoAudio
+
+#PreRoll 10
+#StartSendOnKey
+#MaxTime 100
+#
+#</Stream>
+#
+#<Stream test_l.mpg>
+#Feed feed1.ffm
+##
+#VideoFrameRate 2
+#VideoSize 320x240
+#VideoBitRate 40
+#VideoGopSize 20
+#NoAudio
+#
+#PreRoll 20
+#StartSendOnKey
+#MaxTime 100
+#
+#</Stream>
+#
+<Stream test.swf>
+Feed feed1.ffm
+#
+BitExact
+DctFastint
+IdctSimple
+Qscale 10
+VideoFrameRate 10
+VideoSize 352x288
+VideoBitRate 100
+VideoGopSize 30
+NoAudio
+
+PreRoll 10
+StartSendOnKey
+MaxTime 100
+
+</Stream>
+
+<Stream test_h.asf>
+Feed feed1.ffm
+Format asf
+#
+BitExact
+DctFastint
+IdctSimple
+Qscale 10
+VideoFrameRate 10
+VideoSize 320x240
+VideoBitRate 100
+VideoGopSize 30
+NoAudio
+
+PreRoll 10
+StartSendOnKey
+MaxTime 100
+
+AVOptionVideo flags +global_header
+
+Metadata title "Test data stream"
+
+</Stream>
+
+<Stream test_l.asf>
+Feed feed1.ffm
+Format asf
+#
+BitExact
+DctFastint
+IdctSimple
+Qscale 10
+VideoFrameRate 2
+VideoSize 320x240
+VideoBitRate 40
+VideoGopSize 20
+NoAudio
+
+PreRoll 20
+StartSendOnKey
+MaxTime 100
+
+AVOptionVideo flags +global_header
+
+Metadata title "Test data stream"
+
+</Stream>
+
+<Stream test_h.rm>
+
+Feed feed1.ffm
+Format rm
+
+BitExact
+DctFastint
+IdctSimple
+Qscale 10
+VideoBitRate 100
+VideoFrameRate 10
+VideoGopSize 30
+VideoSize 320x240
+NoAudio
+
+PreRoll 10
+StartSendOnKey
+MaxTime 100
+
+</Stream>
+
+<Stream test_l.rm>
+
+Feed feed1.ffm
+Format rm
+
+BitExact
+DctFastint
+IdctSimple
+Qscale 10
+VideoBitRate 40
+VideoFrameRate 2
+VideoGopSize 20
+VideoSize 320x240
+NoAudio
+
+PreRoll 20
+StartSendOnKey
+MaxTime 100
+
+</Stream>
+
+
+<Stream test.jpg>
+
+Feed feed1.ffm
+Format jpeg
+Strict -1
+
+BitExact
+DctFastint
+IdctSimple
+VideoFrameRate 1
+VideoSize 352x288
+NoAudio
+
+PreRoll 2
+
+</Stream>
+
+<Stream test_small.jpg>
+
+Feed feed1.ffm
+Format jpeg
+Strict -1
+
+BitExact
+DctFastint
+IdctSimple
+VideoFrameRate 1
+VideoSize 160x128
+NoAudio
+
+PreRoll 2
+
+</Stream>
+
+<Stream test.mjpg>
+
+Feed feed1.ffm
+Format mpjpeg
+Strict -1
+
+BitExact
+DctFastint
+IdctSimple
+VideoFrameRate 1
+VideoSize 320x240
+NoAudio
+StartSendOnKey
+
+PreRoll 1
+MaxTime 100
+
+</Stream>
+
+
+##################################################################
+# Special stream : server status
+
+<Stream teststat.html>
+
+Format status
+
+</Stream>
+
diff --git a/tests/ffserver.regression.ref b/tests/ffserver.regression.ref
new file mode 100644
index 0000000000..9fc749763b
--- /dev/null
+++ b/tests/ffserver.regression.ref
@@ -0,0 +1,10 @@
+18c4ba0e8e7adb781216e38de61c2e39 ff-test_h.avi
+f84767c7af61f360f4b443c2c73f322f ff-test_l.avi
+d976848a9e4d5d8fc2659e4841cdece5 ff-test.swf
+28fd87d5075b9b011aad57292f271a04 ff-test_h.asf
+a31ccd3aba2551e60b9fb1c156fca2f8 ff-test_l.asf
+3279d3ed0ef2d1347b5eda84db2cf3e6 ff-test_h.rm
+440231fe3cf0849887390b4d67d6894a ff-test_l.rm
+e0dc91430660c619e97b5c82e0f398fc ff-test.jpg
+0d6c98fc8a4f00560fe34e94e26880a9 ff-test_small.jpg
+e2a315d7ac0576279f8b4d917999615a ff-test.mjpg
diff --git a/tests/filtergraphs/alphamerge_alphaextract_rgb b/tests/filtergraphs/alphamerge_alphaextract_rgb
new file mode 100644
index 0000000000..1aa302de39
--- /dev/null
+++ b/tests/filtergraphs/alphamerge_alphaextract_rgb
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+format=bgra, split, alphamerge, split [x][y];
+[y] alphaextract [alpha];
+[x][alpha] alphamerge
diff --git a/tests/filtergraphs/alphamerge_alphaextract_yuv b/tests/filtergraphs/alphamerge_alphaextract_yuv
new file mode 100644
index 0000000000..ef3ea14a44
--- /dev/null
+++ b/tests/filtergraphs/alphamerge_alphaextract_yuv
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+format=yuv420p, split, alphamerge, split [x][y];
+[y] alphaextract [alpha];
+[x][alpha] alphamerge
diff --git a/tests/filtergraphs/concat b/tests/filtergraphs/concat
new file mode 100644
index 0000000000..26bca14c3a
--- /dev/null
+++ b/tests/filtergraphs/concat
@@ -0,0 +1,8 @@
+testsrc=r=5:n=1:d=2 [v1];
+sine=440:b=2:d=1 [a1];
+testsrc=r=5:n=1:d=1 [v2];
+sine=622:b=2:d=2 [a2];
+testsrc=r=5:n=1:d=1 [v3];
+sine=880:b=2:d=1 [a3];
+
+[v1][a1][v2][a2][v3][a3] concat=v=1:a=1:n=3
diff --git a/tests/filtergraphs/gradfun b/tests/filtergraphs/gradfun
new file mode 100644
index 0000000000..d93dcafe22
--- /dev/null
+++ b/tests/filtergraphs/gradfun
@@ -0,0 +1,2 @@
+sws_flags=+accurate_rnd+bitexact;
+format=gray, perms=random, gradfun=10:8:enable='not(between(n,5,10))'
diff --git a/tests/filtergraphs/hqdn3d b/tests/filtergraphs/hqdn3d
new file mode 100644
index 0000000000..75918226a4
--- /dev/null
+++ b/tests/filtergraphs/hqdn3d
@@ -0,0 +1 @@
+perms=random, hqdn3d=enable='not(between(t,5,6))'
diff --git a/tests/filtergraphs/overlay b/tests/filtergraphs/overlay
index d646463bfd..f64827466d 100644
--- a/tests/filtergraphs/overlay
+++ b/tests/filtergraphs/overlay
@@ -1,2 +1,3 @@
+sws_flags=+accurate_rnd+bitexact;
[1:v] scale=50:50 [over];
[0:v][over] overlay=20:20
diff --git a/tests/filtergraphs/overlay_rgb b/tests/filtergraphs/overlay_rgb
new file mode 100644
index 0000000000..b060c0176b
--- /dev/null
+++ b/tests/filtergraphs/overlay_rgb
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=rgb
diff --git a/tests/filtergraphs/overlay_yuv420 b/tests/filtergraphs/overlay_yuv420
new file mode 100644
index 0000000000..9ed1b2a57e
--- /dev/null
+++ b/tests/filtergraphs/overlay_yuv420
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=yuv420
diff --git a/tests/filtergraphs/overlay_yuv422 b/tests/filtergraphs/overlay_yuv422
new file mode 100644
index 0000000000..e5df859381
--- /dev/null
+++ b/tests/filtergraphs/overlay_yuv422
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=yuv422
diff --git a/tests/filtergraphs/overlay_yuv444 b/tests/filtergraphs/overlay_yuv444
new file mode 100644
index 0000000000..bda0fd6860
--- /dev/null
+++ b/tests/filtergraphs/overlay_yuv444
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+split [main][over];
+[over] scale=88:72, pad=96:80:4:4 [overf];
+[main][overf] overlay=240:16:format=yuv444
diff --git a/tests/filtergraphs/scalenorm b/tests/filtergraphs/scalenorm
new file mode 100644
index 0000000000..17b69de186
--- /dev/null
+++ b/tests/filtergraphs/scalenorm
@@ -0,0 +1,4 @@
+sws_flags=+accurate_rnd+bitexact;
+testsrc=s=128x96 : d=1:r=5, format=yuv420p [a];
+testsrc=s=160x120 : d=1:r=5 [b];
+[a][b] concat=unsafe=1, scale=flags=+accurate_rnd+bitexact
diff --git a/tests/lavf-regression.sh b/tests/lavf-regression.sh
index 3c18b2f051..a37f714cd4 100755
--- a/tests/lavf-regression.sh
+++ b/tests/lavf-regression.sh
@@ -11,6 +11,16 @@ set -e
eval do_$test=y
+ENC_OPTS="$ENC_OPTS -metadata title=lavftest"
+
+do_lavf_fate()
+{
+ file=${outfile}lavf.$1
+ input="${target_samples}/$2"
+ do_avconv $file $DEC_OPTS -i "$input" $ENC_OPTS -vcodec copy -acodec copy
+ do_avconv_crc $file $DEC_OPTS -i $target_path/$file $3
+}
+
do_lavf()
{
file=${outfile}lavf.$1
@@ -18,6 +28,16 @@ do_lavf()
do_avconv_crc $file $DEC_OPTS -i $target_path/$file $4
}
+do_lavf_timecode_nodrop() { do_lavf $1 "" "$2 -timecode 02:56:14:13"; }
+do_lavf_timecode_drop() { do_lavf $1 "" "$2 -timecode 02:56:14.13 -r 30000/1001"; }
+
+do_lavf_timecode()
+{
+ do_lavf_timecode_nodrop "$@"
+ do_lavf_timecode_drop "$@"
+ do_lavf $1 "" "$2"
+}
+
do_streamed_images()
{
file=${outfile}${1}pipe.$1
@@ -30,9 +50,9 @@ do_image_formats()
outfile="$datadir/images/$1/"
mkdir -p "$outfile"
file=${outfile}%02d.$1
- run_avconv $DEC_OPTS -f image2 -vcodec pgmyuv -i $raw_src $2 $ENC_OPTS $3 -frames 12 -y -qscale 10 $target_path/$file
+ run_avconv $DEC_OPTS -f image2 -vcodec pgmyuv -i $raw_src $2 $ENC_OPTS -frames 13 -y -qscale 10 $target_path/$file
do_md5sum ${outfile}02.$1
- do_avconv_crc $file $DEC_OPTS $3 -i $target_path/$file
+ do_avconv_crc $file $DEC_OPTS -i $target_path/$file $3
echo $(wc -c ${outfile}02.$1)
}
@@ -44,62 +64,108 @@ do_audio_only()
}
if [ -n "$do_avi" ] ; then
-do_lavf avi "" "-acodec mp2 -ar 44100"
+do_lavf avi "" "-acodec mp2 -ar 44100 -ab 64k -threads 1"
fi
if [ -n "$do_asf" ] ; then
-do_lavf asf "" "-acodec mp2 -ar 44100" "-r 25"
+do_lavf asf "" "-acodec mp2 -ar 44100 -ab 64k" "-r 25"
fi
if [ -n "$do_rm" ] ; then
file=${outfile}lavf.rm
-do_avconv $file $DEC_OPTS -f image2 -vcodec pgmyuv -i $raw_src $DEC_OPTS -ar 44100 -f s16le -i $pcm_src $ENC_OPTS -t 1 -qscale 10 -acodec ac3_fixed -b:a 64k
+do_avconv $file $DEC_OPTS -f image2 -vcodec pgmyuv -i $raw_src $DEC_OPTS -ar 44100 -f s16le -i $pcm_src $ENC_OPTS -t 1 -qscale 10 -acodec ac3_fixed -ab 64k
# broken
#do_avconv_crc $file -i $target_path/$file
fi
if [ -n "$do_mpg" ] ; then
-do_lavf mpg "" "-ar 44100"
+do_lavf_timecode mpg "-ab 64k -ar 44100 -threads 1"
fi
if [ -n "$do_mxf" ] ; then
-do_lavf mxf "-ar 48000" "-bf 2 -timecode_frame_start 264363"
+do_lavf_timecode mxf "-ar 48000 -bf 2 -threads 1"
fi
if [ -n "$do_mxf_d10" ]; then
do_lavf mxf_d10 "-ar 48000 -ac 2" "-r 25 -vf scale=720:576,pad=720:608:0:32 -vcodec mpeg2video -g 0 -flags +ildct+low_delay -dc 10 -non_linear_quant 1 -intra_vlc 1 -qscale 1 -ps 1 -qmin 1 -rc_max_vbv_use 1 -rc_min_vbv_use 1 -pix_fmt yuv422p -minrate 30000k -maxrate 30000k -b 30000k -bufsize 1200000 -top 1 -rc_init_occupancy 1200000 -qmax 12 -f mxf_d10"
fi
+if [ -n "$do_mxf_opatom" ]; then
+do_lavf mxf_opatom "" "-s 1920x1080 -vcodec dnxhd -pix_fmt yuv422p -vb 36M -f mxf_opatom -map 0"
+fi
+
+if [ -n "$do_mxf_opatom_audio" ]; then
+do_lavf mxf_opatom_audio "-ar 48000 -ac 1" "-f mxf_opatom -mxf_audio_edit_rate 25 -map 1"
+fi
+
if [ -n "$do_ts" ] ; then
-do_lavf ts "" "-mpegts_transport_stream_id 42 -ar 44100"
+do_lavf ts "" "-ab 64k -mpegts_transport_stream_id 42 -ar 44100 -threads 1"
fi
if [ -n "$do_swf" ] ; then
do_lavf swf "" "-an"
fi
+if [ -n "$do_ffm" ] ; then
+do_lavf ffm "" "-ar 44100 -threads 1"
+fi
+
+if [ -n "$do_flm" ] ; then
+do_lavf flm "" "-pix_fmt rgba"
+fi
+
if [ -n "$do_flv_fmt" ] ; then
do_lavf flv "" "-an"
fi
if [ -n "$do_mov" ] ; then
-do_lavf mov "" "-acodec pcm_alaw -c:v mpeg4"
+mov_common_opt="-acodec pcm_alaw -vcodec mpeg4 -threads 1"
+do_lavf mov "" "-movflags +rtphint $mov_common_opt"
+do_lavf_timecode mov "-movflags +faststart $mov_common_opt"
+fi
+
+if [ -n "$do_ismv" ] ; then
+do_lavf_timecode ismv "-an -vcodec mpeg4 -threads 1"
fi
if [ -n "$do_dv_fmt" ] ; then
+do_lavf_timecode_nodrop dv "-ar 48000 -r 25 -s pal -ac 2"
+do_lavf_timecode_drop dv "-ar 48000 -pix_fmt yuv411p -s ntsc -ac 2"
do_lavf dv "-ar 48000 -channel_layout stereo" "-r 25 -s pal"
fi
if [ -n "$do_gxf" ] ; then
-do_lavf gxf "-ar 48000" "-r 25 -s pal -ac 1"
+do_lavf_timecode_nodrop gxf "-ar 48000 -r 25 -s pal -ac 1 -threads 1"
+do_lavf_timecode_drop gxf "-ar 48000 -s ntsc -ac 1 -threads 1"
+do_lavf gxf "-ar 48000" "-r 25 -s pal -ac 1 -threads 1"
fi
if [ -n "$do_nut" ] ; then
-do_lavf nut "" "-acodec mp2 -ar 44100"
+do_lavf nut "" "-acodec mp2 -ab 64k -ar 44100 -threads 1"
fi
if [ -n "$do_mkv" ] ; then
-do_lavf mkv "" "-c:a mp2 -c:v mpeg4 -ar 44100"
+do_lavf mkv "" "-acodec mp2 -ab 64k -vcodec mpeg4 \
+ -attach ${raw_src%/*}/00.pgm -metadata:s:t mimetype=image/x-portable-greymap -threads 1"
+do_lavf mkv "" "-acodec mp2 -ab 64k -vcodec mpeg4 -ar 44100 -threads 1"
+fi
+
+if [ -n "$do_mp3" ] ; then
+do_lavf_fate mp3 "mp3-conformance/he_32khz.bit" "-acodec copy"
+fi
+
+if [ -n "$do_latm" ] ; then
+do_lavf_fate latm "aac/al04_44.mp4" "-acodec copy"
+fi
+
+if [ -n "$do_ogg_vp3" ] ; then
+# -idct simple causes different results on different systems
+DEC_OPTS="$DEC_OPTS -idct auto"
+do_lavf_fate ogg "vp3/coeff_level64.mkv"
+fi
+
+if [ -n "$do_wtv" ] ; then
+do_lavf wtv "" "-acodec mp2 -threads 1"
fi
@@ -145,6 +211,12 @@ fi
if [ -n "$do_png" ] ; then
do_image_formats png
+do_image_formats png "-pix_fmt gray16be"
+do_image_formats png "-pix_fmt rgb48be"
+fi
+
+if [ -n "$do_xbm" ] ; then
+do_image_formats xbm
fi
if [ -n "$do_bmp" ] ; then
@@ -164,23 +236,40 @@ do_image_formats sgi
fi
if [ -n "$do_jpg" ] ; then
-do_image_formats jpg "-pix_fmt yuvj420p" "-f image2"
+do_image_formats jpg "-pix_fmt yuvj420p"
fi
if [ -n "$do_pam" ] ; then
do_image_formats pam
+do_image_formats pam "-pix_fmt rgba"
+do_image_formats pam "-pix_fmt gray"
+do_image_formats pam "-pix_fmt gray16be" "-pix_fmt gray16be"
+do_image_formats pam "-pix_fmt rgb48be" "-pix_fmt rgb48be"
+do_image_formats pam "-pix_fmt monob"
fi
if [ -n "$do_pcx" ] ; then
do_image_formats pcx
fi
-if [ -n "$do_xwd" ] ; then
-do_image_formats xwd
-fi
-
if [ -n "$do_dpx" ] ; then
do_image_formats dpx
+do_image_formats dpx "-pix_fmt gbrp10le" "-pix_fmt gbrp10le"
+do_image_formats dpx "-pix_fmt gbrp12le" "-pix_fmt gbrp12le"
+do_image_formats dpx "-pix_fmt rgb48le"
+do_image_formats dpx "-pix_fmt rgb48le -bits_per_raw_sample 10" "-pix_fmt rgb48le"
+do_image_formats dpx "-pix_fmt rgba64le"
+fi
+
+if [ -n "$do_xwd" ] ; then
+do_image_formats xwd
+do_image_formats xwd "-pix_fmt rgba"
+do_image_formats xwd "-pix_fmt rgb565be"
+do_image_formats xwd "-pix_fmt rgb555be"
+do_image_formats xwd "-pix_fmt rgb8"
+do_image_formats xwd "-pix_fmt rgb4_byte"
+do_image_formats xwd "-pix_fmt gray"
+do_image_formats xwd "-pix_fmt monow"
fi
if [ -n "$do_sunrast" ] ; then
@@ -193,6 +282,15 @@ if [ -n "$do_wav" ] ; then
do_audio_only wav
fi
+if [ -n "$do_wav_peak" ] ; then
+do_audio_only peak.wav "" "-write_peak on"
+fi
+
+if [ -n "$do_wav_peak_only" ] ; then
+file=${outfile}lavf.peak_only.wav
+do_avconv $file $DEC_OPTS -ar 44100 -f s16le -i $pcm_src $ENC_OPTS -t 1 -qscale 10 -write_peak only
+fi
+
if [ -n "$do_alaw" ] ; then
do_audio_only al "" "" "-ar 44100"
fi
@@ -214,7 +312,7 @@ do_audio_only aif
fi
if [ -n "$do_voc" ] ; then
-do_audio_only voc
+do_audio_only voc "" "-acodec pcm_u8"
fi
if [ -n "$do_voc_s16" ] ; then
@@ -229,10 +327,30 @@ if [ -n "$do_rso" ] ; then
do_audio_only rso
fi
+if [ -n "$do_smjpeg" ] ; then
+do_lavf smjpeg "" "-f smjpeg"
+fi
+
if [ -n "$do_sox" ] ; then
do_audio_only sox
fi
+if [ -n "$do_caf" ] ; then
+do_audio_only caf
+fi
+
+if [ -n "$do_ast" ] ; then
+do_audio_only ast "-ac 2" "-loopstart 1 -loopend 10"
+fi
+
+if [ -n "$do_ircam" ] ; then
+do_audio_only ircam
+fi
+
+if [ -n "$do_w64" ] ; then
+do_audio_only w64
+fi
+
# pix_fmt conversions
if [ -n "$do_pixfmt" ] ; then
diff --git a/tests/md5.sh b/tests/md5.sh
index 0b382b1a5e..5e2528cc75 100644
--- a/tests/md5.sh
+++ b/tests/md5.sh
@@ -5,7 +5,7 @@ if [ X"$(echo | md5sum -b 2> /dev/null)" != X ]; then
elif [ X"$(echo | command md5 2> /dev/null)" != X ]; then
do_md5sum() { command md5 $1 | sed 's#MD5 (\(.*\)) = \(.*\)#\2 *\1#'; }
elif [ -x /sbin/md5 ]; then
- do_md5sum() { /sbin/md5 -r $1 | sed 's# \**\./# *./#'; }
+ do_md5sum() { /sbin/md5 -r $1 | sed 's/\([0-9a-f]\) [ *]*/\1 */'; }
elif openssl version >/dev/null 2>&1; then
do_md5sum() { openssl md5 $1 | sed 's/MD5(\(.*\))= \(.*\)/\2 *\1/'; }
else
diff --git a/tests/ref/acodec/adpcm-adx b/tests/ref/acodec/adpcm-adx
index 2bc49ab94b..34dd9b6c05 100644
--- a/tests/ref/acodec/adpcm-adx
+++ b/tests/ref/acodec/adpcm-adx
@@ -1,4 +1,4 @@
-0a30509d9296b857e134b762b76dbc31 *tests/data/fate/acodec-adpcm-adx.adx
+d7ec7d52a2f5c91464812d031b07cc1d *tests/data/fate/acodec-adpcm-adx.adx
297720 tests/data/fate/acodec-adpcm-adx.adx
-2dbc601ed5259f4d74dc48ccd8da7eaf *tests/data/fate/acodec-adpcm-adx.out.wav
-stddev: 6989.46 PSNR: 19.44 MAXDIFF:65398 bytes: 1058400/ 1058432
+5b5a436ec9d528d6eb0bebaf667521b0 *tests/data/fate/acodec-adpcm-adx.out.wav
+stddev: 2549.93 PSNR: 28.20 MAXDIFF:57514 bytes: 1058400/ 1058432
diff --git a/tests/ref/acodec/adpcm-adx-trellis b/tests/ref/acodec/adpcm-adx-trellis
new file mode 100644
index 0000000000..d620d4a2f0
--- /dev/null
+++ b/tests/ref/acodec/adpcm-adx-trellis
@@ -0,0 +1,4 @@
+d7ec7d52a2f5c91464812d031b07cc1d *tests/data/fate/acodec-adpcm-adx-trellis.adx
+297720 tests/data/fate/acodec-adpcm-adx-trellis.adx
+5b5a436ec9d528d6eb0bebaf667521b0 *tests/data/fate/acodec-adpcm-adx-trellis.out.wav
+stddev: 2549.93 PSNR: 28.20 MAXDIFF:57514 bytes: 1058400/ 1058432
diff --git a/tests/ref/acodec/adpcm-ima_qt b/tests/ref/acodec/adpcm-ima_qt
index 80015275fc..364dfa1e0e 100644
--- a/tests/ref/acodec/adpcm-ima_qt
+++ b/tests/ref/acodec/adpcm-ima_qt
@@ -1,4 +1,4 @@
-23cbae1182e150ebf28e0abfb9cba127 *tests/data/fate/acodec-adpcm-ima_qt.aiff
+44691f14cf5bbef5005df27c692b93ab *tests/data/fate/acodec-adpcm-ima_qt.aiff
281252 tests/data/fate/acodec-adpcm-ima_qt.aiff
-b0fafd002c38fb70acaddfda1a31ed61 *tests/data/fate/acodec-adpcm-ima_qt.out.wav
+7d2f26ea48731b2399718de0f6c39f0c *tests/data/fate/acodec-adpcm-ima_qt.out.wav
stddev: 904.76 PSNR: 37.20 MAXDIFF:34029 bytes: 1058400/ 1058560
diff --git a/tests/ref/acodec/adpcm-ima_qt-trellis b/tests/ref/acodec/adpcm-ima_qt-trellis
new file mode 100644
index 0000000000..0a09965e1e
--- /dev/null
+++ b/tests/ref/acodec/adpcm-ima_qt-trellis
@@ -0,0 +1,4 @@
+15f895c2e7119714f94333e3214d8426 *tests/data/fate/acodec-adpcm-ima_qt-trellis.aiff
+281252 tests/data/fate/acodec-adpcm-ima_qt-trellis.aiff
+593d68369c87d4e3b7323b1bea3e9315 *tests/data/fate/acodec-adpcm-ima_qt-trellis.out.wav
+stddev: 716.74 PSNR: 39.22 MAXDIFF:29633 bytes: 1058400/ 1058560
diff --git a/tests/ref/acodec/adpcm-ima_wav b/tests/ref/acodec/adpcm-ima_wav
index 6d83fd5f1c..bd3306dfc5 100644
--- a/tests/ref/acodec/adpcm-ima_wav
+++ b/tests/ref/acodec/adpcm-ima_wav
@@ -1,4 +1,4 @@
56b75c3a6dacedcf2ce7b0586aa33594 *tests/data/fate/acodec-adpcm-ima_wav.wav
267324 tests/data/fate/acodec-adpcm-ima_wav.wav
-ddddfa47302da540abf19224202bef57 *tests/data/fate/acodec-adpcm-ima_wav.out.wav
+78a2af1c895792d0c221d127bdd48ece *tests/data/fate/acodec-adpcm-ima_wav.out.wav
stddev: 903.51 PSNR: 37.21 MAXDIFF:34026 bytes: 1058400/ 1061748
diff --git a/tests/ref/acodec/adpcm-ima_wav-trellis b/tests/ref/acodec/adpcm-ima_wav-trellis
new file mode 100644
index 0000000000..10d78c74f2
--- /dev/null
+++ b/tests/ref/acodec/adpcm-ima_wav-trellis
@@ -0,0 +1,4 @@
+f9075c7a3adb2cd114b0bac69afcada6 *tests/data/fate/acodec-adpcm-ima_wav-trellis.wav
+267324 tests/data/fate/acodec-adpcm-ima_wav-trellis.wav
+26a9b280c14737b159c56e60181f1170 *tests/data/fate/acodec-adpcm-ima_wav-trellis.out.wav
+stddev: 710.03 PSNR: 39.30 MAXDIFF:25944 bytes: 1058400/ 1061748
diff --git a/tests/ref/acodec/adpcm-ms b/tests/ref/acodec/adpcm-ms
index eb8515d986..c760b783c2 100644
--- a/tests/ref/acodec/adpcm-ms
+++ b/tests/ref/acodec/adpcm-ms
@@ -1,4 +1,4 @@
a407b87daeef5b25dfb6c5b3f519e9c1 *tests/data/fate/acodec-adpcm-ms.wav
268378 tests/data/fate/acodec-adpcm-ms.wav
-22863fb278c4e0ebe9c34cb15db5dd6b *tests/data/fate/acodec-adpcm-ms.out.wav
+7be370f937c51e8a967e6a3d08d5156a *tests/data/fate/acodec-adpcm-ms.out.wav
stddev: 1050.01 PSNR: 35.91 MAXDIFF:29806 bytes: 1058400/ 1060576
diff --git a/tests/ref/acodec/adpcm-ms-trellis b/tests/ref/acodec/adpcm-ms-trellis
new file mode 100644
index 0000000000..8587e703c6
--- /dev/null
+++ b/tests/ref/acodec/adpcm-ms-trellis
@@ -0,0 +1,4 @@
+7ed05f7a88046aa4cd547ddf71953637 *tests/data/fate/acodec-adpcm-ms-trellis.wav
+268378 tests/data/fate/acodec-adpcm-ms-trellis.wav
+ed9d9cdfd264f2ec6c79127c04dd224e *tests/data/fate/acodec-adpcm-ms-trellis.out.wav
+stddev: 896.03 PSNR: 37.28 MAXDIFF:28029 bytes: 1058400/ 1060576
diff --git a/tests/ref/acodec/adpcm-swf b/tests/ref/acodec/adpcm-swf
index fddb771c8b..2cb9e905ca 100644
--- a/tests/ref/acodec/adpcm-swf
+++ b/tests/ref/acodec/adpcm-swf
@@ -1,4 +1,4 @@
42d4639866ed4d692eaf126228a4fa2a *tests/data/fate/acodec-adpcm-swf.flv
269166 tests/data/fate/acodec-adpcm-swf.flv
-f7df69d3fe708303820f2a9d00140a5b *tests/data/fate/acodec-adpcm-swf.out.wav
+628089745a7059ae4055c2515b6d668b *tests/data/fate/acodec-adpcm-swf.out.wav
stddev: 933.58 PSNR: 36.93 MAXDIFF:51119 bytes: 1058400/ 1064960
diff --git a/tests/ref/acodec/adpcm-swf-trellis b/tests/ref/acodec/adpcm-swf-trellis
new file mode 100644
index 0000000000..a2bb565e1c
--- /dev/null
+++ b/tests/ref/acodec/adpcm-swf-trellis
@@ -0,0 +1,4 @@
+ec8859b3206ea0c45701fbdcf60dbe48 *tests/data/fate/acodec-adpcm-swf-trellis.flv
+269166 tests/data/fate/acodec-adpcm-swf-trellis.flv
+29820ce5b95b3b0a2feafa808cc264a7 *tests/data/fate/acodec-adpcm-swf-trellis.out.wav
+stddev: 747.92 PSNR: 38.85 MAXDIFF:51119 bytes: 1058400/ 1064960
diff --git a/tests/ref/acodec/adpcm-yamaha b/tests/ref/acodec/adpcm-yamaha
index da60f44d58..2741058546 100644
--- a/tests/ref/acodec/adpcm-yamaha
+++ b/tests/ref/acodec/adpcm-yamaha
@@ -1,4 +1,4 @@
e9c14f701d25947317db9367b9dc772d *tests/data/fate/acodec-adpcm-yamaha.wav
265274 tests/data/fate/acodec-adpcm-yamaha.wav
-1488b5974fa040a65f0d407fc0224c6a *tests/data/fate/acodec-adpcm-yamaha.out.wav
+93b95a663ec8799e0c4db18467b21234 *tests/data/fate/acodec-adpcm-yamaha.out.wav
stddev: 1247.60 PSNR: 34.41 MAXDIFF:39895 bytes: 1058400/ 1060864
diff --git a/tests/ref/acodec/adpcm-yamaha-trellis b/tests/ref/acodec/adpcm-yamaha-trellis
new file mode 100644
index 0000000000..a099ec54c5
--- /dev/null
+++ b/tests/ref/acodec/adpcm-yamaha-trellis
@@ -0,0 +1,4 @@
+247a06c3f26c57abd2db1a793174cb66 *tests/data/fate/acodec-adpcm-yamaha-trellis.wav
+265274 tests/data/fate/acodec-adpcm-yamaha-trellis.wav
+a42b5fa74b39a07691b0df80ce67f77e *tests/data/fate/acodec-adpcm-yamaha-trellis.out.wav
+stddev: 928.29 PSNR: 36.98 MAXDIFF:33557 bytes: 1058400/ 1060864
diff --git a/tests/ref/acodec/adpcm_ima_qt b/tests/ref/acodec/adpcm_ima_qt
new file mode 100644
index 0000000000..a50c30a27c
--- /dev/null
+++ b/tests/ref/acodec/adpcm_ima_qt
@@ -0,0 +1,4 @@
+23cbae1182e150ebf28e0abfb9cba127 *./tests/data/acodec/adpcm_qt.aiff
+281252 ./tests/data/acodec/adpcm_qt.aiff
+b0fafd002c38fb70acaddfda1a31ed61 *./tests/data/adpcm_ima_qt.acodec.out.wav
+stddev: 904.76 PSNR: 37.20 MAXDIFF:34029 bytes: 1058560/ 1058400
diff --git a/tests/ref/acodec/alac b/tests/ref/acodec/alac
index dde0e364fa..7d6ebe8c8b 100644
--- a/tests/ref/acodec/alac
+++ b/tests/ref/acodec/alac
@@ -1,4 +1,4 @@
-98cfcf6cf139844ca27d16f1fc64f62c *tests/data/fate/acodec-alac.mov
-389258 tests/data/fate/acodec-alac.mov
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-alac.out.wav
+8d9fb9f5433962e7880b666e6e2e428e *tests/data/fate/acodec-alac.mov
+389018 tests/data/fate/acodec-alac.mov
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-alac.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/flac b/tests/ref/acodec/flac
index 3ef32c26dc..c2e7f2099b 100644
--- a/tests/ref/acodec/flac
+++ b/tests/ref/acodec/flac
@@ -1,4 +1,4 @@
-f582b59cc68adfcb3342dcfd7e020b71 *tests/data/fate/acodec-flac.flac
-361581 tests/data/fate/acodec-flac.flac
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-flac.out.wav
+151eef9097f944726968bec48649f00a *tests/data/fate/acodec-flac.flac
+361582 tests/data/fate/acodec-flac.flac
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-flac.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/flac-exact-rice b/tests/ref/acodec/flac-exact-rice
new file mode 100644
index 0000000000..6f6d27427d
--- /dev/null
+++ b/tests/ref/acodec/flac-exact-rice
@@ -0,0 +1,4 @@
+aab144de213ae684ca008a3e0afe5e28 *tests/data/fate/acodec-flac-exact-rice.flac
+360454 tests/data/fate/acodec-flac-exact-rice.flac
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-flac-exact-rice.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/g723_1 b/tests/ref/acodec/g723_1
new file mode 100644
index 0000000000..e33fe3d207
--- /dev/null
+++ b/tests/ref/acodec/g723_1
@@ -0,0 +1,4 @@
+dec0deb2425e908d232d2471acff04a3 *tests/data/fate/acodec-g723_1.g723_1
+4800 tests/data/fate/acodec-g723_1.g723_1
+c3b9055d1830969c10d08762fae0b787 *tests/data/fate/acodec-g723_1.out.wav
+stddev: 8423.47 PSNR: 17.82 MAXDIFF:53292 bytes: 95992/ 96000
diff --git a/tests/ref/acodec/mp2 b/tests/ref/acodec/mp2
index 42381b4784..57b83ac747 100644
--- a/tests/ref/acodec/mp2
+++ b/tests/ref/acodec/mp2
@@ -1,4 +1,4 @@
f6eb0a205350bbd7fb1028a01c7ae8aa *tests/data/fate/acodec-mp2.mp2
96130 tests/data/fate/acodec-mp2.mp2
-5a669ca7321adc6ab66a3eade4035909 *tests/data/fate/acodec-mp2.out.wav
+74c7b6b15a001add199619fafe4059a1 *tests/data/fate/acodec-mp2.out.wav
stddev: 4384.33 PSNR: 23.49 MAXDIFF:52631 bytes: 1058400/ 1057916
diff --git a/tests/ref/acodec/mp2fixed b/tests/ref/acodec/mp2fixed
new file mode 100644
index 0000000000..bf8cc7f372
--- /dev/null
+++ b/tests/ref/acodec/mp2fixed
@@ -0,0 +1,4 @@
+05445de0f0305df85db4ed0ce94e5f4c *tests/data/fate/acodec-mp2fixed.mp2
+288391 tests/data/fate/acodec-mp2fixed.mp2
+b1b4a13e42db11e9fb1bd2c93692d548 *tests/data/fate/acodec-mp2fixed.out.wav
+stddev: 3653.84 PSNR: 25.07 MAXDIFF:39970 bytes: 1058400/ 1057916
diff --git a/tests/ref/acodec/pcm-alaw b/tests/ref/acodec/pcm-alaw
index 28ce960efe..00555e3341 100644
--- a/tests/ref/acodec/pcm-alaw
+++ b/tests/ref/acodec/pcm-alaw
@@ -1,4 +1,4 @@
a2dd6a934ec6d5ec901a211652e85227 *tests/data/fate/acodec-pcm-alaw.wav
529258 tests/data/fate/acodec-pcm-alaw.wav
-f323f7551ffad91de8613f44dcb198b6 *tests/data/fate/acodec-pcm-alaw.out.wav
+0568b0b9a72e31559e150e7e09d301cd *tests/data/fate/acodec-pcm-alaw.out.wav
stddev: 101.67 PSNR: 56.19 MAXDIFF: 515 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-f32be b/tests/ref/acodec/pcm-f32be
index 5b0f4980d5..b98c0b7a23 100644
--- a/tests/ref/acodec/pcm-f32be
+++ b/tests/ref/acodec/pcm-f32be
@@ -1,4 +1,4 @@
-118ff3dc83c62ce9ce669eef57e55bb2 *tests/data/fate/acodec-pcm-f32be.au
-2116824 tests/data/fate/acodec-pcm-f32be.au
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-f32be.out.wav
+e74eb6b65cb397ce541bac120b00680a *tests/data/fate/acodec-pcm-f32be.au
+2116832 tests/data/fate/acodec-pcm-f32be.au
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-f32be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-f32le b/tests/ref/acodec/pcm-f32le
index 681f0836c8..c0fdd70cd2 100644
--- a/tests/ref/acodec/pcm-f32le
+++ b/tests/ref/acodec/pcm-f32le
@@ -1,4 +1,4 @@
653d82a64b7bd96ac193e105e9f92d4c *tests/data/fate/acodec-pcm-f32le.wav
2116880 tests/data/fate/acodec-pcm-f32le.wav
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-f32le.out.wav
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-f32le.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-f64be b/tests/ref/acodec/pcm-f64be
index dd882d38b8..e0e03079d0 100644
--- a/tests/ref/acodec/pcm-f64be
+++ b/tests/ref/acodec/pcm-f64be
@@ -1,4 +1,4 @@
-8112296b1ed94f72f20d04b1a54850a7 *tests/data/fate/acodec-pcm-f64be.au
-4233624 tests/data/fate/acodec-pcm-f64be.au
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-f64be.out.wav
+8c8ba9d2c68384c5f077306e220f1188 *tests/data/fate/acodec-pcm-f64be.au
+4233632 tests/data/fate/acodec-pcm-f64be.au
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-f64be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-f64le b/tests/ref/acodec/pcm-f64le
index c6cb027220..5c90e7bbbd 100644
--- a/tests/ref/acodec/pcm-f64le
+++ b/tests/ref/acodec/pcm-f64le
@@ -1,4 +1,4 @@
48b4cd378f47a50dc902aa03cc8280ed *tests/data/fate/acodec-pcm-f64le.wav
4233680 tests/data/fate/acodec-pcm-f64le.wav
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-f64le.out.wav
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-f64le.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-mulaw b/tests/ref/acodec/pcm-mulaw
index bd2a1e81b5..f5c117de18 100644
--- a/tests/ref/acodec/pcm-mulaw
+++ b/tests/ref/acodec/pcm-mulaw
@@ -1,4 +1,4 @@
fd10ee54bd298fc29fd6fc70baa71414 *tests/data/fate/acodec-pcm-mulaw.wav
529258 tests/data/fate/acodec-pcm-mulaw.wav
-7ae8c3fc804bd574006fd547fe28980c *tests/data/fate/acodec-pcm-mulaw.out.wav
+1c3eeaa8814ebd4916780dff80ed6dc5 *tests/data/fate/acodec-pcm-mulaw.out.wav
stddev: 103.38 PSNR: 56.04 MAXDIFF: 644 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s16be b/tests/ref/acodec/pcm-s16be
index 61e566471e..a9b4593b54 100644
--- a/tests/ref/acodec/pcm-s16be
+++ b/tests/ref/acodec/pcm-s16be
@@ -1,4 +1,4 @@
-b650d16f5ac191c41d5fa3657cf4c1ac *tests/data/fate/acodec-pcm-s16be.mov
-1060097 tests/data/fate/acodec-pcm-s16be.mov
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s16be.out.wav
+d2515f35266ae6dba525c700bb76d893 *tests/data/fate/acodec-pcm-s16be.mov
+1059069 tests/data/fate/acodec-pcm-s16be.mov
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s16be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s16be_planar b/tests/ref/acodec/pcm-s16be_planar
new file mode 100644
index 0000000000..3d7d7b111f
--- /dev/null
+++ b/tests/ref/acodec/pcm-s16be_planar
@@ -0,0 +1,4 @@
+a2d4da448a83dac7cbe11eea96e679fb *tests/data/fate/acodec-pcm-s16be_planar.nut
+1060722 tests/data/fate/acodec-pcm-s16be_planar.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s16be_planar.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s16le b/tests/ref/acodec/pcm-s16le
index 51366ad0d7..5fa80bd7a2 100644
--- a/tests/ref/acodec/pcm-s16le
+++ b/tests/ref/acodec/pcm-s16le
@@ -1,4 +1,4 @@
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s16le.wav
-1058446 tests/data/fate/acodec-pcm-s16le.wav
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s16le.out.wav
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s16le.wav
+1058444 tests/data/fate/acodec-pcm-s16le.wav
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s16le.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s16le_planar b/tests/ref/acodec/pcm-s16le_planar
new file mode 100644
index 0000000000..c635c727e6
--- /dev/null
+++ b/tests/ref/acodec/pcm-s16le_planar
@@ -0,0 +1,4 @@
+761404c11c5b4b0a8bba0061704f70a4 *tests/data/fate/acodec-pcm-s16le_planar.nut
+1060722 tests/data/fate/acodec-pcm-s16le_planar.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s16le_planar.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s24be b/tests/ref/acodec/pcm-s24be
index f673040896..916aceb01b 100644
--- a/tests/ref/acodec/pcm-s24be
+++ b/tests/ref/acodec/pcm-s24be
@@ -1,4 +1,4 @@
-0bd99d1273fb1fb78055cf97f3efe299 *tests/data/fate/acodec-pcm-s24be.mov
-1589297 tests/data/fate/acodec-pcm-s24be.mov
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s24be.out.wav
+0f4a37a77619124f486f656f03c53d33 *tests/data/fate/acodec-pcm-s24be.mov
+1588323 tests/data/fate/acodec-pcm-s24be.mov
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s24be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s24le b/tests/ref/acodec/pcm-s24le
index a7e77e2fc1..cf5ae1a2ac 100644
--- a/tests/ref/acodec/pcm-s24le
+++ b/tests/ref/acodec/pcm-s24le
@@ -1,4 +1,4 @@
18ea73985dbdf59e23f5aba66145e6fe *tests/data/fate/acodec-pcm-s24le.wav
1587668 tests/data/fate/acodec-pcm-s24le.wav
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s24le.out.wav
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s24le.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s24le_planar b/tests/ref/acodec/pcm-s24le_planar
new file mode 100644
index 0000000000..67393d9632
--- /dev/null
+++ b/tests/ref/acodec/pcm-s24le_planar
@@ -0,0 +1,4 @@
+aa9f8ca95de20b2e83f66dcbb15cc307 *tests/data/fate/acodec-pcm-s24le_planar.nut
+1590251 tests/data/fate/acodec-pcm-s24le_planar.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s24le_planar.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s32be b/tests/ref/acodec/pcm-s32be
index 1b6dec962c..5a48bb2757 100644
--- a/tests/ref/acodec/pcm-s32be
+++ b/tests/ref/acodec/pcm-s32be
@@ -1,4 +1,4 @@
-7ebffb0bd01c02b9953ee5b1e2f47910 *tests/data/fate/acodec-pcm-s32be.mov
-2118497 tests/data/fate/acodec-pcm-s32be.mov
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s32be.out.wav
+d6380bf54ac3e452c190ce302c264bf0 *tests/data/fate/acodec-pcm-s32be.mov
+2117527 tests/data/fate/acodec-pcm-s32be.mov
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s32be.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s32le b/tests/ref/acodec/pcm-s32le
index 1c3e412427..47c736b9c1 100644
--- a/tests/ref/acodec/pcm-s32le
+++ b/tests/ref/acodec/pcm-s32le
@@ -1,4 +1,4 @@
8d8849fa5c5d91b9cb74f5c74e937faf *tests/data/fate/acodec-pcm-s32le.wav
2116868 tests/data/fate/acodec-pcm-s32le.wav
-64151e4bcc2b717aa5a8454d424d6a1f *tests/data/fate/acodec-pcm-s32le.out.wav
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s32le.out.wav
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s32le_planar b/tests/ref/acodec/pcm-s32le_planar
new file mode 100644
index 0000000000..643659f21f
--- /dev/null
+++ b/tests/ref/acodec/pcm-s32le_planar
@@ -0,0 +1,4 @@
+d2a712fe08b1792bc65f255f54bb980e *tests/data/fate/acodec-pcm-s32le_planar.nut
+2120197 tests/data/fate/acodec-pcm-s32le_planar.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s32le_planar.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s8 b/tests/ref/acodec/pcm-s8
index c947729924..14f4c8562b 100644
--- a/tests/ref/acodec/pcm-s8
+++ b/tests/ref/acodec/pcm-s8
@@ -1,4 +1,4 @@
-3b52f563e8e99aa26253eff154980a93 *tests/data/fate/acodec-pcm-s8.mov
-530897 tests/data/fate/acodec-pcm-s8.mov
-651d4eb8d98dfcdda96ae6c43d8f156b *tests/data/fate/acodec-pcm-s8.out.wav
+00a9d90e06e8ecb79e5dd4c6c8460836 *tests/data/fate/acodec-pcm-s8.mov
+529853 tests/data/fate/acodec-pcm-s8.mov
+652edf30f35ad89bf27bcc9d2f9c7b53 *tests/data/fate/acodec-pcm-s8.out.wav
stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-s8_planar b/tests/ref/acodec/pcm-s8_planar
new file mode 100644
index 0000000000..301e71538f
--- /dev/null
+++ b/tests/ref/acodec/pcm-s8_planar
@@ -0,0 +1,4 @@
+c0e10e4a5106137082131807b6674a71 *tests/data/fate/acodec-pcm-s8_planar.nut
+531100 tests/data/fate/acodec-pcm-s8_planar.nut
+652edf30f35ad89bf27bcc9d2f9c7b53 *tests/data/fate/acodec-pcm-s8_planar.out.wav
+stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u16be b/tests/ref/acodec/pcm-u16be
new file mode 100644
index 0000000000..3fd831d162
--- /dev/null
+++ b/tests/ref/acodec/pcm-u16be
@@ -0,0 +1,4 @@
+753d5bfdc38d314fa3b1a2eb34449aea *tests/data/fate/acodec-pcm-u16be.nut
+1060715 tests/data/fate/acodec-pcm-u16be.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-u16be.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u16le b/tests/ref/acodec/pcm-u16le
new file mode 100644
index 0000000000..ea724bbe9c
--- /dev/null
+++ b/tests/ref/acodec/pcm-u16le
@@ -0,0 +1,4 @@
+cee38dc471b6b72d97e44d1667591362 *tests/data/fate/acodec-pcm-u16le.nut
+1060715 tests/data/fate/acodec-pcm-u16le.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-u16le.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u24be b/tests/ref/acodec/pcm-u24be
new file mode 100644
index 0000000000..3c196373a8
--- /dev/null
+++ b/tests/ref/acodec/pcm-u24be
@@ -0,0 +1,4 @@
+84c2b6f7197840e40c5f646efd8a43a4 *tests/data/fate/acodec-pcm-u24be.nut
+1590244 tests/data/fate/acodec-pcm-u24be.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-u24be.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u24le b/tests/ref/acodec/pcm-u24le
new file mode 100644
index 0000000000..b82d6bcb2e
--- /dev/null
+++ b/tests/ref/acodec/pcm-u24le
@@ -0,0 +1,4 @@
+5afea1f1b1d0590dbae2ac2e0092f434 *tests/data/fate/acodec-pcm-u24le.nut
+1590244 tests/data/fate/acodec-pcm-u24le.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-u24le.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u32be b/tests/ref/acodec/pcm-u32be
new file mode 100644
index 0000000000..909a130ac3
--- /dev/null
+++ b/tests/ref/acodec/pcm-u32be
@@ -0,0 +1,4 @@
+529f523fcd04002791fce9cee797783b *tests/data/fate/acodec-pcm-u32be.nut
+2120190 tests/data/fate/acodec-pcm-u32be.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-u32be.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u32le b/tests/ref/acodec/pcm-u32le
new file mode 100644
index 0000000000..16a183f600
--- /dev/null
+++ b/tests/ref/acodec/pcm-u32le
@@ -0,0 +1,4 @@
+87f75abd86f84571bafc656e06b63038 *tests/data/fate/acodec-pcm-u32le.nut
+2120190 tests/data/fate/acodec-pcm-u32le.nut
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-u32le.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/pcm-u8 b/tests/ref/acodec/pcm-u8
index 80e70eab04..c9bf04acd5 100644
--- a/tests/ref/acodec/pcm-u8
+++ b/tests/ref/acodec/pcm-u8
@@ -1,4 +1,4 @@
-70fecbae732f81143a560c7315eda49a *tests/data/fate/acodec-pcm-u8.wav
-529246 tests/data/fate/acodec-pcm-u8.wav
-651d4eb8d98dfcdda96ae6c43d8f156b *tests/data/fate/acodec-pcm-u8.out.wav
+98cadb3502dbdc99e6e077c28b1a036c *tests/data/fate/acodec-pcm-u8.wav
+529244 tests/data/fate/acodec-pcm-u8.wav
+652edf30f35ad89bf27bcc9d2f9c7b53 *tests/data/fate/acodec-pcm-u8.out.wav
stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/roqaudio b/tests/ref/acodec/roqaudio
new file mode 100644
index 0000000000..61cb27a38a
--- /dev/null
+++ b/tests/ref/acodec/roqaudio
@@ -0,0 +1,4 @@
+75859976d7098588aeaebbc5551484a9 *tests/data/fate/acodec-roqaudio.roq
+265992 tests/data/fate/acodec-roqaudio.roq
+73d5aaaab9488e63f1cf6fc324c7a9a2 *tests/data/fate/acodec-roqaudio.out.wav
+stddev: 4481.70 PSNR: 23.30 MAXDIFF:46250 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/s302m b/tests/ref/acodec/s302m
new file mode 100644
index 0000000000..f19eebe7a2
--- /dev/null
+++ b/tests/ref/acodec/s302m
@@ -0,0 +1,4 @@
+2d1494ad78292dca556fd079ec27f28d *tests/data/fate/acodec-s302m.mpegts
+1589164 tests/data/fate/acodec-s302m.mpegts
+f9b6528eee1aea04640ee83400c78689 *tests/data/fate/acodec-s302m.out.wav
+stddev: 986.97 PSNR: 36.44 MAXDIFF:18642 bytes: 1058400/ 1056708
diff --git a/tests/ref/acodec/tta b/tests/ref/acodec/tta
new file mode 100644
index 0000000000..b4b96112f2
--- /dev/null
+++ b/tests/ref/acodec/tta
@@ -0,0 +1,4 @@
+aeeb0f2e75d044dbe2f89b7e70a54c82 *tests/data/fate/acodec-tta.matroska
+331080 tests/data/fate/acodec-tta.matroska
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-tta.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/acodec/wavpack b/tests/ref/acodec/wavpack
new file mode 100644
index 0000000000..02f09ae5ed
--- /dev/null
+++ b/tests/ref/acodec/wavpack
@@ -0,0 +1,4 @@
+000420796cc3e526650ce6f4c6334471 *tests/data/fate/acodec-wavpack.wv
+338166 tests/data/fate/acodec-wavpack.wv
+95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-wavpack.out.wav
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400
diff --git a/tests/ref/fate/4xm-1 b/tests/ref/fate/4xm-1
index d38a47a1ad..37371aac66 100644
--- a/tests/ref/fate/4xm-1
+++ b/tests/ref/fate/4xm-1
@@ -1,16 +1,16 @@
#tb 0: 1/15
-0, 0, 0, 1, 921600, 0xd08f97c7
-0, 1, 1, 1, 921600, 0xc433a85b
-0, 2, 2, 1, 921600, 0x7ffeee42
-0, 3, 3, 1, 921600, 0xc0ad9f52
-0, 4, 4, 1, 921600, 0xb0235112
-0, 5, 5, 1, 921600, 0xcbdd9805
-0, 6, 6, 1, 921600, 0x5468bdb9
-0, 7, 7, 1, 921600, 0x2f0c63fd
-0, 8, 8, 1, 921600, 0xf1de04f0
-0, 9, 9, 1, 921600, 0x95709ce2
-0, 10, 10, 1, 921600, 0x69037c4a
-0, 11, 11, 1, 921600, 0x513f8a98
-0, 12, 12, 1, 921600, 0x55b82fa1
-0, 13, 13, 1, 921600, 0x5c8ace28
-0, 14, 14, 1, 921600, 0xb019770a
+0, 0, 0, 1, 921600, 0xd82e4d57
+0, 1, 1, 1, 921600, 0x83f2349c
+0, 2, 2, 1, 921600, 0x70d87db0
+0, 3, 3, 1, 921600, 0x66d27b93
+0, 4, 4, 1, 921600, 0xb730941c
+0, 5, 5, 1, 921600, 0x15da4934
+0, 6, 6, 1, 921600, 0x1953968a
+0, 7, 7, 1, 921600, 0xf0d730a0
+0, 8, 8, 1, 921600, 0x35a7d30c
+0, 9, 9, 1, 921600, 0x33667f62
+0, 10, 10, 1, 921600, 0xf4707f6b
+0, 11, 11, 1, 921600, 0xaac6c392
+0, 12, 12, 1, 921600, 0x68397d16
+0, 13, 13, 1, 921600, 0xb2aa0450
+0, 14, 14, 1, 921600, 0xba25c62e
diff --git a/tests/ref/fate/4xm-2 b/tests/ref/fate/4xm-2
index 35b0797439..6895d124d9 100644
--- a/tests/ref/fate/4xm-2
+++ b/tests/ref/fate/4xm-2
@@ -1,4 +1,4 @@
-#tb 0: 1/6
+#tb 0: 4/25
0, 0, 0, 1, 80640, 0x00000000
0, 1, 1, 1, 80640, 0x3a942680
0, 2, 2, 1, 80640, 0x3a942680
@@ -6,153 +6,153 @@
0, 4, 4, 1, 80640, 0x3a942680
0, 5, 5, 1, 80640, 0x3a942680
0, 6, 6, 1, 80640, 0x3a942680
-0, 7, 7, 1, 80640, 0x1956ebfc
-0, 8, 8, 1, 80640, 0x61686290
-0, 9, 9, 1, 80640, 0x7e2c2753
-0, 10, 10, 1, 80640, 0x63e5e14f
-0, 11, 11, 1, 80640, 0xa775947a
-0, 12, 12, 1, 80640, 0x4b91b93d
-0, 13, 13, 1, 80640, 0x83345f32
-0, 14, 14, 1, 80640, 0x5d3a3374
-0, 15, 15, 1, 80640, 0x164808c5
-0, 16, 16, 1, 80640, 0xfd0189af
-0, 17, 17, 1, 80640, 0x062f9389
-0, 18, 18, 1, 80640, 0xe4dcaff8
-0, 19, 19, 1, 80640, 0xb2d9ec51
-0, 20, 20, 1, 80640, 0x3b4d5331
-0, 21, 21, 1, 80640, 0xfcbd8da1
-0, 22, 22, 1, 80640, 0xa0732142
-0, 23, 23, 1, 80640, 0x6438df5f
-0, 24, 24, 1, 80640, 0x614302fa
-0, 25, 25, 1, 80640, 0x53edf986
-0, 26, 26, 1, 80640, 0x6dfe13f0
-0, 27, 27, 1, 80640, 0x0b2194c3
-0, 28, 28, 1, 80640, 0xe0436945
-0, 29, 29, 1, 80640, 0x8d8ba77f
-0, 30, 30, 1, 80640, 0x9c723388
-0, 31, 31, 1, 80640, 0x336bd2a2
-0, 32, 32, 1, 80640, 0x5905fd0b
-0, 33, 33, 1, 80640, 0x2ca368bb
-0, 34, 34, 1, 80640, 0x38c1e5ec
-0, 35, 35, 1, 80640, 0xe439a194
-0, 36, 36, 1, 80640, 0xe7a19a64
-0, 37, 37, 1, 80640, 0xbe7f9094
-0, 38, 38, 1, 80640, 0x0b2cbec9
-0, 39, 39, 1, 80640, 0x8050bf7d
-0, 40, 40, 1, 80640, 0x4e9d4e78
-0, 41, 41, 1, 80640, 0xaa7bb85d
-0, 42, 42, 1, 80640, 0x6e42b1a6
-0, 43, 43, 1, 80640, 0x27043fe0
-0, 44, 44, 1, 80640, 0xe04bd5e6
-0, 45, 45, 1, 80640, 0xd60762d6
-0, 46, 46, 1, 80640, 0x2729df8f
-0, 47, 47, 1, 80640, 0x1b62c4f7
-0, 48, 48, 1, 80640, 0xe6b5d2f7
-0, 49, 49, 1, 80640, 0xf5885096
-0, 50, 50, 1, 80640, 0xe7625cf6
-0, 51, 51, 1, 80640, 0xed804de6
-0, 52, 52, 1, 80640, 0x3f92728e
-0, 53, 53, 1, 80640, 0x353e4b0d
-0, 54, 54, 1, 80640, 0x70b0228c
-0, 55, 55, 1, 80640, 0x851bd554
-0, 56, 56, 1, 80640, 0x594f22eb
-0, 57, 57, 1, 80640, 0xa2267c0b
-0, 58, 58, 1, 80640, 0xdc0fbafb
-0, 59, 59, 1, 80640, 0xd596b763
-0, 60, 60, 1, 80640, 0x3b9c4b1b
-0, 61, 61, 1, 80640, 0x218ac4b4
-0, 62, 62, 1, 80640, 0x4af393a4
-0, 63, 63, 1, 80640, 0x66c098c5
-0, 64, 64, 1, 80640, 0x7cc91e86
-0, 65, 65, 1, 80640, 0xba282a2e
-0, 66, 66, 1, 80640, 0x50932be6
-0, 67, 67, 1, 80640, 0x6531386e
-0, 68, 68, 1, 80640, 0x2616235f
-0, 69, 69, 1, 80640, 0x27aad18a
-0, 70, 70, 1, 80640, 0x67491df3
-0, 71, 71, 1, 80640, 0x167028f1
-0, 72, 72, 1, 80640, 0xa4229420
-0, 73, 73, 1, 80640, 0x77eaed07
-0, 74, 74, 1, 80640, 0xbdf7d8e8
-0, 75, 75, 1, 80640, 0xc2ac8545
-0, 76, 76, 1, 80640, 0xf3fe64ec
-0, 77, 77, 1, 80640, 0x66451d43
-0, 78, 78, 1, 80640, 0x1af2f05e
-0, 79, 79, 1, 80640, 0x2a63c2c4
-0, 80, 80, 1, 80640, 0xe4e07a0f
-0, 81, 81, 1, 80640, 0x598e8b11
-0, 82, 82, 1, 80640, 0xb2ebb868
-0, 83, 83, 1, 80640, 0xa4b6bb8a
-0, 84, 84, 1, 80640, 0x5037e910
-0, 85, 85, 1, 80640, 0x0c55f6c0
-0, 86, 86, 1, 80640, 0x3f4704f7
-0, 87, 87, 1, 80640, 0xa6a8e810
-0, 88, 88, 1, 80640, 0xedbfcfb0
-0, 89, 89, 1, 80640, 0xe568caa0
-0, 90, 90, 1, 80640, 0xdf21cc20
-0, 91, 91, 1, 80640, 0xb66cd4a8
-0, 92, 92, 1, 80640, 0xcd26c9c8
-0, 93, 93, 1, 80640, 0x5fe8d598
-0, 94, 94, 1, 80640, 0xed0dc9c8
-0, 95, 95, 1, 80640, 0x8313d288
-0, 96, 96, 1, 80640, 0x9ccdd4a0
-0, 97, 97, 1, 80640, 0x66ffe970
-0, 98, 98, 1, 80640, 0xf68ad1c8
-0, 99, 99, 1, 80640, 0xd570f658
-0, 100, 100, 1, 80640, 0x8c39d998
-0, 101, 101, 1, 80640, 0xe18fe5e0
-0, 102, 102, 1, 80640, 0xbbe7e340
-0, 103, 103, 1, 80640, 0x9a90d470
-0, 104, 104, 1, 80640, 0xd2bbced0
-0, 105, 105, 1, 80640, 0xbbf9dce0
-0, 106, 106, 1, 80640, 0x4ff7c888
-0, 107, 107, 1, 80640, 0xc2e7e1f0
-0, 108, 108, 1, 80640, 0x2104e3b0
-0, 109, 109, 1, 80640, 0xaef5e8f0
-0, 110, 110, 1, 80640, 0xc477e890
-0, 111, 111, 1, 80640, 0xb12df778
-0, 112, 112, 1, 80640, 0xd2115720
-0, 113, 113, 1, 80640, 0x620b6538
-0, 114, 114, 1, 80640, 0x894a8db8
-0, 115, 115, 1, 80640, 0x8da3bcb0
-0, 116, 116, 1, 80640, 0x96be8930
-0, 117, 117, 1, 80640, 0xe69dc1f0
-0, 118, 118, 1, 80640, 0x42b8d4e0
-0, 119, 119, 1, 80640, 0x0a8da4f0
-0, 120, 120, 1, 80640, 0x245fd3d8
-0, 121, 121, 1, 80640, 0x3fd1e858
-0, 122, 122, 1, 80640, 0xe2c299f0
-0, 123, 123, 1, 80640, 0xda1cddd0
-0, 124, 124, 1, 80640, 0xf126e498
-0, 125, 125, 1, 80640, 0xc85ab920
-0, 126, 126, 1, 80640, 0x52f39de8
-0, 127, 127, 1, 80640, 0xd0daac60
-0, 128, 128, 1, 80640, 0xef323347
-0, 129, 129, 1, 80640, 0xcc063317
-0, 130, 130, 1, 80640, 0xb6f53057
-0, 131, 131, 1, 80640, 0x5fe53b07
-0, 132, 132, 1, 80640, 0x63183d7f
-0, 133, 133, 1, 80640, 0x91a44bbf
-0, 134, 134, 1, 80640, 0xa433480f
-0, 135, 135, 1, 80640, 0xe90652ef
-0, 136, 136, 1, 80640, 0xe96e35bf
-0, 137, 137, 1, 80640, 0x84ff2ccf
-0, 138, 138, 1, 80640, 0x930f2b07
-0, 139, 139, 1, 80640, 0x5a1228d7
-0, 140, 140, 1, 80640, 0x29f226ef
-0, 141, 141, 1, 80640, 0xd35136df
-0, 142, 142, 1, 80640, 0x0e2d407f
-0, 143, 143, 1, 80640, 0x34a93267
-0, 144, 144, 1, 80640, 0x7ae82af7
-0, 145, 145, 1, 80640, 0xb20c2477
-0, 146, 146, 1, 80640, 0xa104218f
-0, 147, 147, 1, 80640, 0xcb1121e7
-0, 148, 148, 1, 80640, 0xaca04751
-0, 149, 149, 1, 80640, 0x3a51c704
-0, 150, 150, 1, 80640, 0xfa632e3d
-0, 151, 151, 1, 80640, 0x61c9407c
-0, 152, 152, 1, 80640, 0xe9a08dd9
-0, 153, 153, 1, 80640, 0xebf3c623
+0, 7, 7, 1, 80640, 0xa731901a
+0, 8, 8, 1, 80640, 0x0a1e5b3d
+0, 9, 9, 1, 80640, 0x2c66418f
+0, 10, 10, 1, 80640, 0xaaf8575a
+0, 11, 11, 1, 80640, 0x2d1a60b1
+0, 12, 12, 1, 80640, 0x646d6e66
+0, 13, 13, 1, 80640, 0x090de107
+0, 14, 14, 1, 80640, 0x90991f6c
+0, 15, 15, 1, 80640, 0xda862969
+0, 16, 16, 1, 80640, 0x5434e1ec
+0, 17, 17, 1, 80640, 0x4e981ce7
+0, 18, 18, 1, 80640, 0x97eb4000
+0, 19, 19, 1, 80640, 0xbfb375b0
+0, 20, 20, 1, 80640, 0x1529d95d
+0, 21, 21, 1, 80640, 0x2c0015af
+0, 22, 22, 1, 80640, 0x63779ce1
+0, 23, 23, 1, 80640, 0x3f2b3949
+0, 24, 24, 1, 80640, 0xe3cf3be4
+0, 25, 25, 1, 80640, 0x54451a22
+0, 26, 26, 1, 80640, 0xc2901d91
+0, 27, 27, 1, 80640, 0x312f8b7e
+0, 28, 28, 1, 80640, 0x99734f4e
+0, 29, 29, 1, 80640, 0xe50b8391
+0, 30, 30, 1, 80640, 0x7c6b04e4
+0, 31, 31, 1, 80640, 0x04989996
+0, 32, 32, 1, 80640, 0x30c3c00f
+0, 33, 33, 1, 80640, 0x77172ba4
+0, 34, 34, 1, 80640, 0x1257a596
+0, 35, 35, 1, 80640, 0x657e5fa8
+0, 36, 36, 1, 80640, 0xe66958ef
+0, 37, 37, 1, 80640, 0xbf7f4f0a
+0, 38, 38, 1, 80640, 0x588ac70e
+0, 39, 39, 1, 80640, 0xb1a91c4b
+0, 40, 40, 1, 80640, 0x5b73de24
+0, 41, 41, 1, 80640, 0xa3c15e73
+0, 42, 42, 1, 80640, 0x7326196b
+0, 43, 43, 1, 80640, 0x1aa52b88
+0, 44, 44, 1, 80640, 0x0029f511
+0, 45, 45, 1, 80640, 0x2398433a
+0, 46, 46, 1, 80640, 0xef9ab870
+0, 47, 47, 1, 80640, 0xb1ac9b79
+0, 48, 48, 1, 80640, 0x1cc2ab3b
+0, 49, 49, 1, 80640, 0x41362b53
+0, 50, 50, 1, 80640, 0x81e33811
+0, 51, 51, 1, 80640, 0x621d285a
+0, 52, 52, 1, 80640, 0x84e84c24
+0, 53, 53, 1, 80640, 0xbb8c2939
+0, 54, 54, 1, 80640, 0x6c6905a8
+0, 55, 55, 1, 80640, 0xc60bbaf0
+0, 56, 56, 1, 80640, 0xc80d08c8
+0, 57, 57, 1, 80640, 0xc5646343
+0, 58, 58, 1, 80640, 0x3df7a287
+0, 59, 59, 1, 80640, 0x628e9f78
+0, 60, 60, 1, 80640, 0x58f93044
+0, 61, 61, 1, 80640, 0x8ee3a59f
+0, 62, 62, 1, 80640, 0xaa297416
+0, 63, 63, 1, 80640, 0x7bbd7307
+0, 64, 64, 1, 80640, 0x12dbee42
+0, 65, 65, 1, 80640, 0xaea5fb22
+0, 66, 66, 1, 80640, 0x9405fd0b
+0, 67, 67, 1, 80640, 0x59400b6f
+0, 68, 68, 1, 80640, 0x70beeba0
+0, 69, 69, 1, 80640, 0xdc0681ae
+0, 70, 70, 1, 80640, 0xe4a3c803
+0, 71, 71, 1, 80640, 0x3424c568
+0, 72, 72, 1, 80640, 0xeb72838d
+0, 73, 73, 1, 80640, 0x671fbff3
+0, 74, 74, 1, 80640, 0xa4b849bd
+0, 75, 75, 1, 80640, 0xf4c2be6f
+0, 76, 76, 1, 80640, 0xb91988fd
+0, 77, 77, 1, 80640, 0xd0e5bf3a
+0, 78, 78, 1, 80640, 0x78c2b0bc
+0, 79, 79, 1, 80640, 0xcf2deb74
+0, 80, 80, 1, 80640, 0x84a9081b
+0, 81, 81, 1, 80640, 0x9931e9b1
+0, 82, 82, 1, 80640, 0x1ce6b59d
+0, 83, 83, 1, 80640, 0x24a31152
+0, 84, 84, 1, 80640, 0x206f4677
+0, 85, 85, 1, 80640, 0x507755ab
+0, 86, 86, 1, 80640, 0xc4b5643a
+0, 87, 87, 1, 80640, 0x197445f7
+0, 88, 88, 1, 80640, 0x53232d2a
+0, 89, 89, 1, 80640, 0x33ae27d4
+0, 90, 90, 1, 80640, 0x77bb2925
+0, 91, 91, 1, 80640, 0xb0d53220
+0, 92, 92, 1, 80640, 0xacdb26fc
+0, 93, 93, 1, 80640, 0xa83d32e1
+0, 94, 94, 1, 80640, 0xe2002717
+0, 95, 95, 1, 80640, 0xb1722fed
+0, 96, 96, 1, 80640, 0xa7de3206
+0, 97, 97, 1, 80640, 0x68f94780
+0, 98, 98, 1, 80640, 0x2bcc2f28
+0, 99, 99, 1, 80640, 0xaf9354e5
+0, 100, 100, 1, 80640, 0x45b4375c
+0, 101, 101, 1, 80640, 0x60e043ee
+0, 102, 102, 1, 80640, 0x9ed5411e
+0, 103, 103, 1, 80640, 0xbae131ce
+0, 104, 104, 1, 80640, 0x33be2be6
+0, 105, 105, 1, 80640, 0xdadb3a4c
+0, 106, 106, 1, 80640, 0xe9e72559
+0, 107, 107, 1, 80640, 0x9fe93f8c
+0, 108, 108, 1, 80640, 0xc20b413a
+0, 109, 109, 1, 80640, 0x02c74699
+0, 110, 110, 1, 80640, 0x1b284634
+0, 111, 111, 1, 80640, 0xb7ea559e
+0, 112, 112, 1, 80640, 0x62e3b0e1
+0, 113, 113, 1, 80640, 0x8b6bbf68
+0, 114, 114, 1, 80640, 0x04d2e8d8
+0, 115, 115, 1, 80640, 0xc6961955
+0, 116, 116, 1, 80640, 0xf318e461
+0, 117, 117, 1, 80640, 0x55231e8f
+0, 118, 118, 1, 80640, 0x772f325e
+0, 119, 119, 1, 80640, 0x31480120
+0, 120, 120, 1, 80640, 0x5eda30fe
+0, 121, 121, 1, 80640, 0x5c534632
+0, 122, 122, 1, 80640, 0xaca0f5c9
+0, 123, 123, 1, 80640, 0x9ec83b5a
+0, 124, 124, 1, 80640, 0x65944233
+0, 125, 125, 1, 80640, 0xbf7e15f0
+0, 126, 126, 1, 80640, 0xf985f9b7
+0, 127, 127, 1, 80640, 0x0e7a0887
+0, 128, 128, 1, 80640, 0xee33931b
+0, 129, 129, 1, 80640, 0xea6b92f8
+0, 130, 130, 1, 80640, 0xde559025
+0, 131, 131, 1, 80640, 0x970c9af6
+0, 132, 132, 1, 80640, 0x6a579d8a
+0, 133, 133, 1, 80640, 0x7053ac0c
+0, 134, 134, 1, 80640, 0x6d6ca81b
+0, 135, 135, 1, 80640, 0x6ffdb338
+0, 136, 136, 1, 80640, 0x402f953f
+0, 137, 137, 1, 80640, 0x24358c04
+0, 138, 138, 1, 80640, 0x26298a25
+0, 139, 139, 1, 80640, 0xbc0487e7
+0, 140, 140, 1, 80640, 0xf8c885fd
+0, 141, 141, 1, 80640, 0x98a79695
+0, 142, 142, 1, 80640, 0x846aa04b
+0, 143, 143, 1, 80640, 0x22ba919b
+0, 144, 144, 1, 80640, 0xcba08a11
+0, 145, 145, 1, 80640, 0xfba0836c
+0, 146, 146, 1, 80640, 0xb7ff8059
+0, 147, 147, 1, 80640, 0xb15080bb
+0, 148, 148, 1, 80640, 0x42627aed
+0, 149, 149, 1, 80640, 0xd045d485
+0, 150, 150, 1, 80640, 0xf22e7545
+0, 151, 151, 1, 80640, 0xe24a41fc
+0, 152, 152, 1, 80640, 0x854696ac
+0, 153, 153, 1, 80640, 0x6722f8f2
0, 154, 154, 1, 80640, 0x00000000
0, 155, 155, 1, 80640, 0x0f412500
0, 156, 156, 1, 80640, 0x0f412500
@@ -160,16 +160,16 @@
0, 158, 158, 1, 80640, 0xb6634270
0, 159, 159, 1, 80640, 0x9e43a4a0
0, 160, 160, 1, 80640, 0x136ab60b
-0, 161, 161, 1, 80640, 0x6ce3254e
-0, 162, 162, 1, 80640, 0xf4340d15
-0, 163, 163, 1, 80640, 0x73861114
-0, 164, 164, 1, 80640, 0x36b300d3
-0, 165, 165, 1, 80640, 0x2ddde523
-0, 166, 166, 1, 80640, 0xfdd79c02
-0, 167, 167, 1, 80640, 0xe6cc4fe9
-0, 168, 168, 1, 80640, 0x5b13e2b9
-0, 169, 169, 1, 80640, 0x0d588e70
-0, 170, 170, 1, 80640, 0xc6e4023f
-0, 171, 171, 1, 80640, 0xf54c496f
-0, 172, 172, 1, 80640, 0xa315a5cf
-0, 173, 173, 1, 80640, 0x2d2ac9c7
+0, 161, 161, 1, 80640, 0xe43625dc
+0, 162, 162, 1, 80640, 0xc2eb0f8c
+0, 163, 163, 1, 80640, 0x99af167d
+0, 164, 164, 1, 80640, 0xd9cb0a37
+0, 165, 165, 1, 80640, 0x1f2cf2ce
+0, 166, 166, 1, 80640, 0x00eeae7f
+0, 167, 167, 1, 80640, 0xcc1d666c
+0, 168, 168, 1, 80640, 0x77d6fcc9
+0, 169, 169, 1, 80640, 0x58c8acc6
+0, 170, 170, 1, 80640, 0xd026238d
+0, 171, 171, 1, 80640, 0xfefb6c9b
+0, 172, 172, 1, 80640, 0xa9a5cb36
+0, 173, 173, 1, 80640, 0xc845f000
diff --git a/tests/ref/fate/8bps b/tests/ref/fate/8bps
index 869d38c275..9db94301e0 100644
--- a/tests/ref/fate/8bps
+++ b/tests/ref/fate/8bps
@@ -1,36 +1,36 @@
-#tb 0: 1/125
+#tb 0: 2/25
#tb 1: 1/22050
0, 0, 0, 1, 259200, 0x7e91df07
1, 0, 0, 1024, 2048, 0x3d042426
1, 1024, 1024, 1024, 2048, 0x5bcae456
-0, 10, 10, 1, 259200, 0x7e91df07
+0, 1, 1, 1, 259200, 0x7e91df07
1, 2048, 2048, 1024, 2048, 0xb6043655
1, 3072, 3072, 1024, 2048, 0x6fdaffad
-0, 20, 20, 1, 259200, 0xc468c119
+0, 2, 2, 1, 259200, 0xc468c119
1, 4096, 4096, 1024, 2048, 0xf86700cb
1, 5120, 5120, 1024, 2048, 0x045e46c1
-0, 30, 30, 1, 259200, 0x0e058930
+0, 3, 3, 1, 259200, 0x0e058930
1, 6144, 6144, 1024, 2048, 0x000df0e5
-0, 40, 40, 1, 259200, 0xa0261310
+0, 4, 4, 1, 259200, 0xa0261310
1, 7168, 7168, 1024, 2048, 0x8f5f12fb
1, 8192, 8192, 1024, 2048, 0xd516f6b0
-0, 50, 50, 1, 259200, 0x78ca9aba
+0, 5, 5, 1, 259200, 0x78ca9aba
1, 9216, 9216, 1024, 2048, 0xa1fe2bd3
1, 10240, 10240, 1024, 2048, 0x3647087a
-0, 60, 60, 1, 259200, 0x4971f7b3
+0, 6, 6, 1, 259200, 0x4971f7b3
1, 11264, 11264, 1024, 2048, 0xd2ee584e
1, 12288, 12288, 1024, 2048, 0xf132088c
-0, 70, 70, 1, 259200, 0x7dc2cff7
+0, 7, 7, 1, 259200, 0x7dc2cff7
1, 13312, 13312, 1024, 2048, 0x1efc0eb1
-0, 80, 80, 1, 259200, 0x8cbc53d5
+0, 8, 8, 1, 259200, 0x8cbc53d5
1, 14336, 14336, 1024, 2048, 0xeb73f402
1, 15360, 15360, 1024, 2048, 0x75cb3d20
-0, 90, 90, 1, 259200, 0xcccd77e3
+0, 9, 9, 1, 259200, 0xcccd77e3
1, 16384, 16384, 1024, 2048, 0x85a501b6
1, 17408, 17408, 1024, 2048, 0xa4eb312d
-0, 100, 100, 1, 259200, 0x6b3e0fb3
+0, 10, 10, 1, 259200, 0x6b3e0fb3
1, 18432, 18432, 1024, 2048, 0xf0aaf8c7
-0, 110, 110, 1, 259200, 0x281dd175
+0, 11, 11, 1, 259200, 0x281dd175
1, 19456, 19456, 1024, 2048, 0x65371cda
1, 20480, 20480, 1024, 2048, 0x25512cd6
1, 21504, 21504, 1024, 2048, 0xc81410e3
diff --git a/tests/ref/fate/acodec-aref b/tests/ref/fate/acodec-aref
new file mode 100644
index 0000000000..d70876d9d9
--- /dev/null
+++ b/tests/ref/fate/acodec-aref
@@ -0,0 +1,4 @@
+64151e4bcc2b717aa5a8454d424d6a1f *./tests/data/acodec.ref.wav
+1058446 ./tests/data/acodec.ref.wav
+ce524631c2ad0a40aaab46e3a80a1176 *./tests/data/acodec-16000-1.ref.wav
+192046 ./tests/data/acodec-16000-1.ref.wav
diff --git a/tests/ref/fate/adpcm-4xm b/tests/ref/fate/adpcm-4xm
new file mode 100644
index 0000000000..eb5cfe6978
--- /dev/null
+++ b/tests/ref/fate/adpcm-4xm
@@ -0,0 +1,27 @@
+#tb 0: 1/22050
+0, 0, 0, 1472, 5888, 0x9086e310
+0, 1476, 1476, 1472, 5888, 0xac8491f5
+0, 2952, 2952, 1472, 5888, 0xc9a08b6b
+0, 4428, 4428, 1472, 5888, 0x4cff893b
+0, 5904, 5904, 1464, 5856, 0xfb914624
+0, 7372, 7372, 1472, 5888, 0x1dd9781f
+0, 8848, 8848, 1472, 5888, 0x75937688
+0, 10324, 10324, 1472, 5888, 0x6c93a266
+0, 11800, 11800, 1464, 5856, 0xb14e6783
+0, 13268, 13268, 1472, 5888, 0x4d268759
+0, 14744, 14744, 1472, 5888, 0xce44b8c6
+0, 16220, 16220, 1472, 5888, 0xf99f7347
+0, 17696, 17696, 1464, 5856, 0x35591adc
+0, 19164, 19164, 1472, 5888, 0x67692338
+0, 20640, 20640, 1472, 5888, 0x6465addd
+0, 22116, 22116, 1472, 5888, 0x22c66aaf
+0, 23592, 23592, 1464, 5856, 0x016b78d9
+0, 25060, 25060, 1472, 5888, 0xa9a03855
+0, 26536, 26536, 1472, 5888, 0x1aa0603f
+0, 28012, 28012, 1472, 5888, 0x190a25a1
+0, 29488, 29488, 1464, 5856, 0xc6ad8bc0
+0, 30956, 30956, 1472, 5888, 0x42bb9d6b
+0, 32432, 32432, 1472, 5888, 0x797694d7
+0, 33908, 33908, 1472, 5888, 0xd2d1fa69
+0, 35384, 35384, 1464, 5856, 0x61624e9b
+0, 36852, 36852, 1472, 5888, 0x14bf8ec0
diff --git a/tests/ref/fate/adpcm-afc b/tests/ref/fate/adpcm-afc
new file mode 100644
index 0000000000..d1a1c36caa
--- /dev/null
+++ b/tests/ref/fate/adpcm-afc
@@ -0,0 +1,13 @@
+#tb 0: 1/44100
+0, 0, 0, 17920, 71680, 0x52373bc9
+0, 17920, 17920, 17920, 71680, 0x1f854b27
+0, 35840, 35840, 17920, 71680, 0x3d265a6d
+0, 53760, 53760, 17920, 71680, 0x7e38d624
+0, 71680, 71680, 17920, 71680, 0x003b7616
+0, 89600, 89600, 17920, 71680, 0x9fed7ca7
+0, 107520, 107520, 17920, 71680, 0x22af668c
+0, 125440, 125440, 17920, 71680, 0xefd95c4a
+0, 143360, 143360, 17920, 71680, 0x8b68142e
+0, 161280, 161280, 17920, 71680, 0x0a0614fa
+0, 179200, 179200, 17920, 71680, 0x22ababa3
+0, 197120, 197120, 17920, 71680, 0xda4b1708
diff --git a/tests/ref/fate/adpcm-dtk b/tests/ref/fate/adpcm-dtk
new file mode 100644
index 0000000000..3640e1cb14
--- /dev/null
+++ b/tests/ref/fate/adpcm-dtk
@@ -0,0 +1,33 @@
+#tb 0: 1/48000
+0, 0, 0, 896, 3584, 0xdae789d5
+0, 896, 896, 896, 3584, 0x168ed9b6
+0, 1792, 1792, 896, 3584, 0x8920c8d5
+0, 2688, 2688, 896, 3584, 0xaf0a3245
+0, 3584, 3584, 896, 3584, 0x884ee935
+0, 4480, 4480, 896, 3584, 0xe6a832ad
+0, 5376, 5376, 896, 3584, 0x1fa12ea2
+0, 6272, 6272, 896, 3584, 0xf119198c
+0, 7168, 7168, 896, 3584, 0x0a6dbf72
+0, 8064, 8064, 896, 3584, 0xd3467881
+0, 8960, 8960, 896, 3584, 0x25d504ec
+0, 9856, 9856, 896, 3584, 0x452730c9
+0, 10752, 10752, 896, 3584, 0x42b92ff1
+0, 11648, 11648, 896, 3584, 0x85c67bf3
+0, 12544, 12544, 896, 3584, 0xab4d99e9
+0, 13440, 13440, 896, 3584, 0xe5bfc4da
+0, 14336, 14336, 896, 3584, 0x7a5210e9
+0, 15232, 15232, 896, 3584, 0x5265fcd3
+0, 16128, 16128, 896, 3584, 0x76531427
+0, 17024, 17024, 896, 3584, 0xb2b8d7ab
+0, 17920, 17920, 896, 3584, 0x05a453e8
+0, 18816, 18816, 896, 3584, 0x742c45bb
+0, 19712, 19712, 896, 3584, 0x57aaee3b
+0, 20608, 20608, 896, 3584, 0x997bf703
+0, 21504, 21504, 896, 3584, 0xe2d14b13
+0, 22400, 22400, 896, 3584, 0xdafbdd2f
+0, 23296, 23296, 896, 3584, 0x448cec3a
+0, 24192, 24192, 896, 3584, 0xe6f6fb9c
+0, 25088, 25088, 896, 3584, 0x0310276a
+0, 25984, 25984, 896, 3584, 0x44bf04e9
+0, 26880, 26880, 896, 3584, 0xe2105d33
+0, 27776, 27776, 896, 3584, 0x08b7d5e0
diff --git a/tests/ref/fate/adpcm-ima-amv b/tests/ref/fate/adpcm-ima-amv
index 6c2fa32726..4bd22af9b7 100644
--- a/tests/ref/fate/adpcm-ima-amv
+++ b/tests/ref/fate/adpcm-ima-amv
@@ -3,159 +3,159 @@
0, 1378, 1378, 1378, 2756, 0x8462443f
0, 2756, 2756, 1378, 2756, 0x9f493ba6
0, 4134, 4134, 1378, 2756, 0x634e5f06
-0, 5513, 5513, 1380, 2760, 0x51f35cd4
-0, 6891, 6891, 1378, 2756, 0x011c51e5
-0, 8269, 8269, 1378, 2756, 0x8c2c198c
-0, 9647, 9647, 1378, 2756, 0x2b4a3397
-0, 11025, 11025, 1378, 2756, 0x63794f22
-0, 12403, 12403, 1378, 2756, 0xfc363898
-0, 13781, 13781, 1378, 2756, 0x0da5486e
-0, 15159, 15159, 1378, 2756, 0xbae17a5f
+0, 5512, 5512, 1380, 2760, 0x51f35cd4
+0, 6892, 6892, 1378, 2756, 0x011c51e5
+0, 8270, 8270, 1378, 2756, 0x8c2c198c
+0, 9648, 9648, 1378, 2756, 0x2b4a3397
+0, 11026, 11026, 1378, 2756, 0x63794f22
+0, 12404, 12404, 1378, 2756, 0xfc363898
+0, 13782, 13782, 1378, 2756, 0x0da5486e
+0, 15160, 15160, 1378, 2756, 0xbae17a5f
0, 16538, 16538, 1380, 2760, 0xba266e1b
-0, 17916, 17916, 1378, 2756, 0xdfb61002
-0, 19294, 19294, 1378, 2756, 0x15d029da
-0, 20672, 20672, 1378, 2756, 0x7bc82012
-0, 22050, 22050, 1378, 2756, 0x002e6999
-0, 23428, 23428, 1378, 2756, 0x96346ba6
-0, 24806, 24806, 1378, 2756, 0x3d54543b
-0, 26184, 26184, 1380, 2760, 0x601786e1
-0, 27563, 27563, 1378, 2756, 0xf22a5793
-0, 28941, 28941, 1378, 2756, 0x21f54d49
-0, 30319, 30319, 1378, 2756, 0x0c6d4399
-0, 31697, 31697, 1378, 2756, 0x17282f8e
-0, 33075, 33075, 1378, 2756, 0xeb698f75
-0, 34453, 34453, 1378, 2756, 0x935e1de2
-0, 35831, 35831, 1380, 2760, 0xb6fb4293
-0, 37209, 37209, 1378, 2756, 0x485053dc
-0, 38588, 38588, 1378, 2756, 0x24c35027
-0, 39966, 39966, 1378, 2756, 0x09f323ee
-0, 41344, 41344, 1378, 2756, 0xbc7d58d5
-0, 42722, 42722, 1378, 2756, 0xaefd487c
-0, 44100, 44100, 1378, 2756, 0xaca16cc0
-0, 45478, 45478, 1380, 2760, 0x98a76091
-0, 46856, 46856, 1378, 2756, 0x5d357141
-0, 48234, 48234, 1378, 2756, 0x65ea2657
-0, 49613, 49613, 1378, 2756, 0xb5e1334a
-0, 50991, 50991, 1378, 2756, 0x32cd5d91
-0, 52369, 52369, 1378, 2756, 0xdc23722b
-0, 53747, 53747, 1378, 2756, 0x2ba34684
-0, 55125, 55125, 1378, 2756, 0xf9755ba8
-0, 56503, 56503, 1380, 2760, 0x24221ddb
-0, 57881, 57881, 1378, 2756, 0xef843aa4
-0, 59259, 59259, 1378, 2756, 0x420442fe
-0, 60638, 60638, 1378, 2756, 0x5a0933cb
-0, 62016, 62016, 1378, 2756, 0xef5f6d61
-0, 63394, 63394, 1378, 2756, 0xe57e6dc0
-0, 64772, 64772, 1378, 2756, 0xc0f0495a
-0, 66150, 66150, 1380, 2760, 0x2c3b55df
-0, 67528, 67528, 1378, 2756, 0x39c2586c
-0, 68906, 68906, 1378, 2756, 0x7ffc46e5
-0, 70284, 70284, 1378, 2756, 0xa2766664
-0, 71663, 71663, 1378, 2756, 0xacb50c6c
-0, 73041, 73041, 1378, 2756, 0x7f659084
-0, 74419, 74419, 1378, 2756, 0xc72e6a12
-0, 75797, 75797, 1380, 2760, 0xdb6944df
-0, 77175, 77175, 1378, 2756, 0x954f45c1
-0, 78553, 78553, 1378, 2756, 0xa9484240
-0, 79931, 79931, 1378, 2756, 0x1d595349
-0, 81309, 81309, 1378, 2756, 0xcf2a565e
-0, 82688, 82688, 1378, 2756, 0x391028d5
-0, 84066, 84066, 1378, 2756, 0x348db7ad
-0, 85444, 85444, 1380, 2760, 0xb69b5e3a
-0, 86822, 86822, 1378, 2756, 0xe3635fbe
-0, 88200, 88200, 1378, 2756, 0xdcad3654
-0, 89578, 89578, 1378, 2756, 0x5c17abef
-0, 90956, 90956, 1378, 2756, 0xb3235184
-0, 92334, 92334, 1378, 2756, 0xdabb64a6
-0, 93713, 93713, 1378, 2756, 0xa95dc58d
-0, 95091, 95091, 1380, 2760, 0x8e7ac9eb
-0, 96469, 96469, 1378, 2756, 0x492b658e
-0, 97847, 97847, 1378, 2756, 0x377483ab
-0, 99225, 99225, 1378, 2756, 0x2c250279
-0, 100603, 100603, 1378, 2756, 0x704dbdb3
-0, 101981, 101981, 1378, 2756, 0x800d7da2
-0, 103359, 103359, 1378, 2756, 0x872aa32e
-0, 104738, 104738, 1378, 2756, 0x2d4837fe
-0, 106116, 106116, 1380, 2760, 0xc89ea57e
-0, 107494, 107494, 1378, 2756, 0x6447d7ef
-0, 108872, 108872, 1378, 2756, 0x144f59cc
-0, 110250, 110250, 1378, 2756, 0xc667154e
-0, 111628, 111628, 1378, 2756, 0xf0de66ae
-0, 113006, 113006, 1378, 2756, 0xeabf3c32
-0, 114384, 114384, 1378, 2756, 0xe98e81d1
-0, 115763, 115763, 1380, 2760, 0x56aa5889
-0, 117141, 117141, 1378, 2756, 0x4fd34c0e
-0, 118519, 118519, 1378, 2756, 0x67cf6912
-0, 119897, 119897, 1378, 2756, 0xfa944def
-0, 121275, 121275, 1378, 2756, 0xc12f23b2
-0, 122653, 122653, 1378, 2756, 0x5ea325a2
-0, 124031, 124031, 1378, 2756, 0x2b245824
-0, 125409, 125409, 1380, 2760, 0x90ac533e
-0, 126788, 126788, 1378, 2756, 0xcca34d26
-0, 128166, 128166, 1378, 2756, 0xb5f820d0
-0, 129544, 129544, 1378, 2756, 0x27f24335
-0, 130922, 130922, 1378, 2756, 0x4a9e87b7
-0, 132300, 132300, 1378, 2756, 0xbd076129
-0, 133678, 133678, 1378, 2756, 0x2e0e3f2e
-0, 135056, 135056, 1380, 2760, 0xdf534478
-0, 136434, 136434, 1378, 2756, 0xca000a2e
-0, 137813, 137813, 1378, 2756, 0x87472df3
-0, 139191, 139191, 1378, 2756, 0x16733810
-0, 140569, 140569, 1378, 2756, 0xfa0734b4
-0, 141947, 141947, 1378, 2756, 0x5eff3fc4
-0, 143325, 143325, 1378, 2756, 0xf35346bd
-0, 144703, 144703, 1378, 2756, 0xac6411c5
-0, 146081, 146081, 1380, 2760, 0x478c3c56
-0, 147459, 147459, 1378, 2756, 0xebd30bdd
-0, 148838, 148838, 1378, 2756, 0xaef95a31
-0, 150216, 150216, 1378, 2756, 0x8aad29d1
-0, 151594, 151594, 1378, 2756, 0x626863f0
-0, 152972, 152972, 1378, 2756, 0x68c05707
-0, 154350, 154350, 1378, 2756, 0x437c5e8d
-0, 155728, 155728, 1380, 2760, 0x8eca4bdb
-0, 157106, 157106, 1378, 2756, 0x62bd4162
-0, 158484, 158484, 1378, 2756, 0x9f744aa4
-0, 159863, 159863, 1378, 2756, 0x0f3f6409
-0, 161241, 161241, 1378, 2756, 0x3fee827a
-0, 162619, 162619, 1378, 2756, 0x48a0ac19
-0, 163997, 163997, 1378, 2756, 0x8e4ce0d0
-0, 165375, 165375, 1380, 2760, 0xcda82236
-0, 166753, 166753, 1378, 2756, 0x0e523255
-0, 168131, 168131, 1378, 2756, 0x84103d30
-0, 169509, 169509, 1378, 2756, 0x13941cde
-0, 170888, 170888, 1378, 2756, 0x9fc834c5
-0, 172266, 172266, 1378, 2756, 0xc0217a77
-0, 173644, 173644, 1378, 2756, 0x3f643659
-0, 175022, 175022, 1380, 2760, 0x9dbd6002
-0, 176400, 176400, 1378, 2756, 0x94f046fb
-0, 177778, 177778, 1378, 2756, 0xab01fb12
-0, 179156, 179156, 1378, 2756, 0x04cffe5c
-0, 180534, 180534, 1378, 2756, 0xef661c5e
-0, 181913, 181913, 1378, 2756, 0x094c5fc5
-0, 183291, 183291, 1378, 2756, 0xe0c1486a
-0, 184669, 184669, 1380, 2760, 0x8c3535b7
-0, 186047, 186047, 1378, 2756, 0x594934aa
-0, 187425, 187425, 1378, 2756, 0x74007238
-0, 188803, 188803, 1378, 2756, 0x61f1394d
-0, 190181, 190181, 1378, 2756, 0x72584f07
-0, 191559, 191559, 1378, 2756, 0xced9acf9
-0, 192938, 192938, 1378, 2756, 0x7d2e3ea1
-0, 194316, 194316, 1378, 2756, 0x56c06897
-0, 195694, 195694, 1380, 2760, 0x19983bbf
-0, 197072, 197072, 1378, 2756, 0x4f884f27
-0, 198450, 198450, 1378, 2756, 0x81ab2f63
-0, 199828, 199828, 1378, 2756, 0x448e681d
-0, 201206, 201206, 1378, 2756, 0x0ba9826e
-0, 202584, 202584, 1378, 2756, 0x049f36fa
-0, 203963, 203963, 1378, 2756, 0x096a2b62
-0, 205341, 205341, 1380, 2760, 0x579e2035
-0, 206719, 206719, 1378, 2756, 0xd13e30e1
-0, 208097, 208097, 1378, 2756, 0x30b6412b
-0, 209475, 209475, 1378, 2756, 0xbb1c3268
-0, 210853, 210853, 1378, 2756, 0xbc175b6a
-0, 212231, 212231, 1378, 2756, 0xf8d160e2
-0, 213609, 213609, 1378, 2756, 0xc1048154
-0, 214988, 214988, 1380, 2760, 0xb83548f4
-0, 216366, 216366, 1378, 2756, 0x22647962
-0, 217744, 217744, 1378, 2756, 0x14ca54d3
-0, 219122, 219122, 1378, 2756, 0x58754b3a
+0, 17918, 17918, 1378, 2756, 0xdfb61002
+0, 19296, 19296, 1378, 2756, 0x15d029da
+0, 20674, 20674, 1378, 2756, 0x7bc82012
+0, 22052, 22052, 1378, 2756, 0x002e6999
+0, 23430, 23430, 1378, 2756, 0x96346ba6
+0, 24808, 24808, 1378, 2756, 0x3d54543b
+0, 26186, 26186, 1380, 2760, 0x601786e1
+0, 27566, 27566, 1378, 2756, 0xf22a5793
+0, 28944, 28944, 1378, 2756, 0x21f54d49
+0, 30322, 30322, 1378, 2756, 0x0c6d4399
+0, 31700, 31700, 1378, 2756, 0x17282f8e
+0, 33078, 33078, 1378, 2756, 0xeb698f75
+0, 34456, 34456, 1378, 2756, 0x935e1de2
+0, 35834, 35834, 1380, 2760, 0xb6fb4293
+0, 37214, 37214, 1378, 2756, 0x485053dc
+0, 38592, 38592, 1378, 2756, 0x24c35027
+0, 39970, 39970, 1378, 2756, 0x09f323ee
+0, 41348, 41348, 1378, 2756, 0xbc7d58d5
+0, 42726, 42726, 1378, 2756, 0xaefd487c
+0, 44104, 44104, 1378, 2756, 0xaca16cc0
+0, 45482, 45482, 1380, 2760, 0x98a76091
+0, 46862, 46862, 1378, 2756, 0x5d357141
+0, 48240, 48240, 1378, 2756, 0x65ea2657
+0, 49618, 49618, 1378, 2756, 0xb5e1334a
+0, 50996, 50996, 1378, 2756, 0x32cd5d91
+0, 52374, 52374, 1378, 2756, 0xdc23722b
+0, 53752, 53752, 1378, 2756, 0x2ba34684
+0, 55130, 55130, 1378, 2756, 0xf9755ba8
+0, 56508, 56508, 1380, 2760, 0x24221ddb
+0, 57888, 57888, 1378, 2756, 0xef843aa4
+0, 59266, 59266, 1378, 2756, 0x420442fe
+0, 60644, 60644, 1378, 2756, 0x5a0933cb
+0, 62022, 62022, 1378, 2756, 0xef5f6d61
+0, 63400, 63400, 1378, 2756, 0xe57e6dc0
+0, 64778, 64778, 1378, 2756, 0xc0f0495a
+0, 66156, 66156, 1380, 2760, 0x2c3b55df
+0, 67536, 67536, 1378, 2756, 0x39c2586c
+0, 68914, 68914, 1378, 2756, 0x7ffc46e5
+0, 70292, 70292, 1378, 2756, 0xa2766664
+0, 71670, 71670, 1378, 2756, 0xacb50c6c
+0, 73048, 73048, 1378, 2756, 0x7f659084
+0, 74426, 74426, 1378, 2756, 0xc72e6a12
+0, 75804, 75804, 1380, 2760, 0xdb6944df
+0, 77184, 77184, 1378, 2756, 0x954f45c1
+0, 78562, 78562, 1378, 2756, 0xa9484240
+0, 79940, 79940, 1378, 2756, 0x1d595349
+0, 81318, 81318, 1378, 2756, 0xcf2a565e
+0, 82696, 82696, 1378, 2756, 0x391028d5
+0, 84074, 84074, 1378, 2756, 0x348db7ad
+0, 85452, 85452, 1380, 2760, 0xb69b5e3a
+0, 86832, 86832, 1378, 2756, 0xe3635fbe
+0, 88210, 88210, 1378, 2756, 0xdcad3654
+0, 89588, 89588, 1378, 2756, 0x5c17abef
+0, 90966, 90966, 1378, 2756, 0xb3235184
+0, 92344, 92344, 1378, 2756, 0xdabb64a6
+0, 93722, 93722, 1378, 2756, 0xa95dc58d
+0, 95100, 95100, 1380, 2760, 0x8e7ac9eb
+0, 96480, 96480, 1378, 2756, 0x492b658e
+0, 97858, 97858, 1378, 2756, 0x377483ab
+0, 99236, 99236, 1378, 2756, 0x2c250279
+0, 100614, 100614, 1378, 2756, 0x704dbdb3
+0, 101992, 101992, 1378, 2756, 0x800d7da2
+0, 103370, 103370, 1378, 2756, 0x872aa32e
+0, 104748, 104748, 1378, 2756, 0x2d4837fe
+0, 106126, 106126, 1380, 2760, 0xc89ea57e
+0, 107506, 107506, 1378, 2756, 0x6447d7ef
+0, 108884, 108884, 1378, 2756, 0x144f59cc
+0, 110262, 110262, 1378, 2756, 0xc667154e
+0, 111640, 111640, 1378, 2756, 0xf0de66ae
+0, 113018, 113018, 1378, 2756, 0xeabf3c32
+0, 114396, 114396, 1378, 2756, 0xe98e81d1
+0, 115774, 115774, 1380, 2760, 0x56aa5889
+0, 117154, 117154, 1378, 2756, 0x4fd34c0e
+0, 118532, 118532, 1378, 2756, 0x67cf6912
+0, 119910, 119910, 1378, 2756, 0xfa944def
+0, 121288, 121288, 1378, 2756, 0xc12f23b2
+0, 122666, 122666, 1378, 2756, 0x5ea325a2
+0, 124044, 124044, 1378, 2756, 0x2b245824
+0, 125422, 125422, 1380, 2760, 0x90ac533e
+0, 126802, 126802, 1378, 2756, 0xcca34d26
+0, 128180, 128180, 1378, 2756, 0xb5f820d0
+0, 129558, 129558, 1378, 2756, 0x27f24335
+0, 130936, 130936, 1378, 2756, 0x4a9e87b7
+0, 132314, 132314, 1378, 2756, 0xbd076129
+0, 133692, 133692, 1378, 2756, 0x2e0e3f2e
+0, 135070, 135070, 1380, 2760, 0xdf534478
+0, 136450, 136450, 1378, 2756, 0xca000a2e
+0, 137828, 137828, 1378, 2756, 0x87472df3
+0, 139206, 139206, 1378, 2756, 0x16733810
+0, 140584, 140584, 1378, 2756, 0xfa0734b4
+0, 141962, 141962, 1378, 2756, 0x5eff3fc4
+0, 143340, 143340, 1378, 2756, 0xf35346bd
+0, 144718, 144718, 1378, 2756, 0xac6411c5
+0, 146096, 146096, 1380, 2760, 0x478c3c56
+0, 147476, 147476, 1378, 2756, 0xebd30bdd
+0, 148854, 148854, 1378, 2756, 0xaef95a31
+0, 150232, 150232, 1378, 2756, 0x8aad29d1
+0, 151610, 151610, 1378, 2756, 0x626863f0
+0, 152988, 152988, 1378, 2756, 0x68c05707
+0, 154366, 154366, 1378, 2756, 0x437c5e8d
+0, 155744, 155744, 1380, 2760, 0x8eca4bdb
+0, 157124, 157124, 1378, 2756, 0x62bd4162
+0, 158502, 158502, 1378, 2756, 0x9f744aa4
+0, 159880, 159880, 1378, 2756, 0x0f3f6409
+0, 161258, 161258, 1378, 2756, 0x3fee827a
+0, 162636, 162636, 1378, 2756, 0x48a0ac19
+0, 164014, 164014, 1378, 2756, 0x8e4ce0d0
+0, 165392, 165392, 1380, 2760, 0xcda82236
+0, 166772, 166772, 1378, 2756, 0x0e523255
+0, 168150, 168150, 1378, 2756, 0x84103d30
+0, 169528, 169528, 1378, 2756, 0x13941cde
+0, 170906, 170906, 1378, 2756, 0x9fc834c5
+0, 172284, 172284, 1378, 2756, 0xc0217a77
+0, 173662, 173662, 1378, 2756, 0x3f643659
+0, 175040, 175040, 1380, 2760, 0x9dbd6002
+0, 176420, 176420, 1378, 2756, 0x94f046fb
+0, 177798, 177798, 1378, 2756, 0xab01fb12
+0, 179176, 179176, 1378, 2756, 0x04cffe5c
+0, 180554, 180554, 1378, 2756, 0xef661c5e
+0, 181932, 181932, 1378, 2756, 0x094c5fc5
+0, 183310, 183310, 1378, 2756, 0xe0c1486a
+0, 184688, 184688, 1380, 2760, 0x8c3535b7
+0, 186068, 186068, 1378, 2756, 0x594934aa
+0, 187446, 187446, 1378, 2756, 0x74007238
+0, 188824, 188824, 1378, 2756, 0x61f1394d
+0, 190202, 190202, 1378, 2756, 0x72584f07
+0, 191580, 191580, 1378, 2756, 0xced9acf9
+0, 192958, 192958, 1378, 2756, 0x7d2e3ea1
+0, 194336, 194336, 1378, 2756, 0x56c06897
+0, 195714, 195714, 1380, 2760, 0x19983bbf
+0, 197094, 197094, 1378, 2756, 0x4f884f27
+0, 198472, 198472, 1378, 2756, 0x81ab2f63
+0, 199850, 199850, 1378, 2756, 0x448e681d
+0, 201228, 201228, 1378, 2756, 0x0ba9826e
+0, 202606, 202606, 1378, 2756, 0x049f36fa
+0, 203984, 203984, 1378, 2756, 0x096a2b62
+0, 205362, 205362, 1380, 2760, 0x579e2035
+0, 206742, 206742, 1378, 2756, 0xd13e30e1
+0, 208120, 208120, 1378, 2756, 0x30b6412b
+0, 209498, 209498, 1378, 2756, 0xbb1c3268
+0, 210876, 210876, 1378, 2756, 0xbc175b6a
+0, 212254, 212254, 1378, 2756, 0xf8d160e2
+0, 213632, 213632, 1378, 2756, 0xc1048154
+0, 215010, 215010, 1380, 2760, 0xb83548f4
+0, 216390, 216390, 1378, 2756, 0x22647962
+0, 217768, 217768, 1378, 2756, 0x14ca54d3
+0, 219146, 219146, 1354, 2708, 0x85e82e8d
diff --git a/tests/ref/fate/adpcm-ima-oki b/tests/ref/fate/adpcm-ima-oki
new file mode 100644
index 0000000000..c6f1ee1e63
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-oki
@@ -0,0 +1 @@
+641049800e735b62e975baacc9a011a4
diff --git a/tests/ref/fate/adpcm-ima-rad b/tests/ref/fate/adpcm-ima-rad
new file mode 100644
index 0000000000..c5de1a64e6
--- /dev/null
+++ b/tests/ref/fate/adpcm-ima-rad
@@ -0,0 +1 @@
+495f0ae514c28c6bdcbd40811a17e2a5
diff --git a/tests/ref/fate/adpcm-ima-smjpeg b/tests/ref/fate/adpcm-ima-smjpeg
index 45cb97bfc1..3a746b60d2 100644
--- a/tests/ref/fate/adpcm-ima-smjpeg
+++ b/tests/ref/fate/adpcm-ima-smjpeg
@@ -1,351 +1,351 @@
#tb 0: 1/22050
0, 0, 0, 512, 1024, 0x00000000
-0, 507, 507, 512, 1024, 0x00000000
-0, 1014, 1014, 512, 1024, 0xd89a448e
-0, 1521, 1521, 512, 1024, 0x695b369c
-0, 2029, 2029, 512, 1024, 0xc8ba5707
-0, 2558, 2558, 512, 1024, 0xdf241fc6
-0, 3065, 3065, 512, 1024, 0x61cf4166
-0, 3572, 3572, 512, 1024, 0x97cbc386
-0, 4079, 4079, 512, 1024, 0x44899d04
-0, 4586, 4586, 512, 1024, 0xa7cbaa62
-0, 5116, 5116, 512, 1024, 0xa7aea60c
-0, 5623, 5623, 512, 1024, 0xd7b18a89
-0, 6130, 6130, 512, 1024, 0x268e81f6
-0, 6637, 6637, 512, 1024, 0x9cf83a2f
-0, 7166, 7166, 512, 1024, 0x5559b508
-0, 7673, 7673, 512, 1024, 0xe1b9e71c
-0, 8181, 8181, 512, 1024, 0xdcee733e
-0, 8688, 8688, 512, 1024, 0xe5918f60
-0, 9195, 9195, 512, 1024, 0x29dbd209
-0, 9724, 9724, 512, 1024, 0x9bcbcf16
-0, 10231, 10231, 512, 1024, 0x86f5f458
-0, 10738, 10738, 512, 1024, 0xabcbda86
-0, 11246, 11246, 512, 1024, 0xc51f77b9
-0, 11775, 11775, 512, 1024, 0xf6b3a504
-0, 12282, 12282, 512, 1024, 0x1af3e40e
-0, 12789, 12789, 512, 1024, 0x3866b03b
-0, 13296, 13296, 512, 1024, 0xbc005403
-0, 13803, 13803, 512, 1024, 0xe9dfcc51
-0, 14333, 14333, 512, 1024, 0x83c837cb
-0, 14840, 14840, 512, 1024, 0xfa649580
-0, 15347, 15347, 512, 1024, 0x519452ea
-0, 15854, 15854, 512, 1024, 0xd4978774
-0, 16383, 16383, 512, 1024, 0xe2a3b1cd
-0, 16890, 16890, 512, 1024, 0x9a9472ad
-0, 17397, 17397, 512, 1024, 0xa12d4060
-0, 17905, 17905, 512, 1024, 0x31fb0646
-0, 18412, 18412, 512, 1024, 0xfc44343f
-0, 18941, 18941, 512, 1024, 0x0847751a
-0, 19448, 19448, 512, 1024, 0x227968a2
-0, 19955, 19955, 512, 1024, 0x7cce9f1c
-0, 20462, 20462, 512, 1024, 0xb8356713
-0, 20992, 20992, 512, 1024, 0xb29f6e6f
-0, 21499, 21499, 512, 1024, 0x9e1430ab
-0, 22006, 22006, 512, 1024, 0x26d85423
-0, 22513, 22513, 512, 1024, 0x6496547d
-0, 23020, 23020, 512, 1024, 0x316b1a86
-0, 23549, 23549, 512, 1024, 0x3cd83afc
-0, 24057, 24057, 512, 1024, 0x993ff633
-0, 24564, 24564, 512, 1024, 0x0708d1a2
-0, 25071, 25071, 512, 1024, 0xd7230db9
-0, 25578, 25578, 512, 1024, 0xbb0779ca
-0, 26107, 26107, 512, 1024, 0xc6094e1b
-0, 26614, 26614, 512, 1024, 0x15a8b039
-0, 27122, 27122, 512, 1024, 0xd6dbe88c
-0, 27629, 27629, 512, 1024, 0x7e8d1140
-0, 28158, 28158, 512, 1024, 0xef88e525
-0, 28665, 28665, 512, 1024, 0x44e21149
-0, 29172, 29172, 512, 1024, 0x65b0f5f4
-0, 29679, 29679, 512, 1024, 0xb955f687
-0, 30186, 30186, 512, 1024, 0xc85fba9c
-0, 30716, 30716, 512, 1024, 0xf59655ad
-0, 31223, 31223, 512, 1024, 0x6de80bf1
-0, 31730, 31730, 512, 1024, 0x2dcf6e41
-0, 32237, 32237, 512, 1024, 0xd0ddcf8a
-0, 32766, 32766, 512, 1024, 0x00135c2d
-0, 33273, 33273, 512, 1024, 0x697f8efd
-0, 33781, 33781, 512, 1024, 0x7a9bada5
-0, 34288, 34288, 512, 1024, 0x0d22783c
-0, 34795, 34795, 512, 1024, 0x7726d07d
-0, 35324, 35324, 512, 1024, 0xa2f14f67
-0, 35831, 35831, 512, 1024, 0x7f51060d
-0, 36338, 36338, 512, 1024, 0xc4ec6aea
-0, 36846, 36846, 512, 1024, 0x9bb37ca4
-0, 37375, 37375, 512, 1024, 0x9b085577
-0, 37882, 37882, 512, 1024, 0x8812f8af
-0, 38389, 38389, 512, 1024, 0x788f5221
-0, 38896, 38896, 512, 1024, 0x3a2ce642
-0, 39403, 39403, 512, 1024, 0x72415692
-0, 39933, 39933, 512, 1024, 0xe3dcc105
-0, 40440, 40440, 512, 1024, 0xb26c0599
-0, 40947, 40947, 512, 1024, 0x5c9e55eb
-0, 41454, 41454, 512, 1024, 0x8fe88707
-0, 41983, 41983, 512, 1024, 0xc5d7beb6
-0, 42490, 42490, 512, 1024, 0xe1d3a3b4
-0, 42998, 42998, 512, 1024, 0x012da0c6
-0, 43505, 43505, 512, 1024, 0x8d010922
-0, 44012, 44012, 512, 1024, 0x3366eb0d
-0, 44541, 44541, 512, 1024, 0xc9381a27
-0, 45048, 45048, 512, 1024, 0x0774f685
-0, 45555, 45555, 512, 1024, 0xc5cae0a5
-0, 46062, 46062, 512, 1024, 0xa6f4737c
-0, 46592, 46592, 512, 1024, 0x8fb6d0d1
-0, 47099, 47099, 512, 1024, 0x05f579c2
-0, 47606, 47606, 512, 1024, 0x56905d99
-0, 48113, 48113, 512, 1024, 0x002ee18d
-0, 48620, 48620, 512, 1024, 0xeb37ef51
-0, 49149, 49149, 512, 1024, 0x38025635
-0, 49657, 49657, 512, 1024, 0x4fe643c8
-0, 50164, 50164, 512, 1024, 0x11d66ab1
-0, 50671, 50671, 512, 1024, 0xcc3051e9
-0, 51178, 51178, 512, 1024, 0xcd93e854
-0, 51707, 51707, 512, 1024, 0x38f1196d
-0, 52214, 52214, 512, 1024, 0x657a15fc
-0, 52722, 52722, 512, 1024, 0x669ce2a9
-0, 53229, 53229, 512, 1024, 0x95862dda
-0, 53758, 53758, 512, 1024, 0x1726a7b2
-0, 54265, 54265, 512, 1024, 0xd6ece2a1
-0, 54772, 54772, 512, 1024, 0x33ab9553
-0, 55279, 55279, 512, 1024, 0xd50c73a6
-0, 55787, 55787, 512, 1024, 0xfe25b63a
-0, 56316, 56316, 512, 1024, 0x7e2959e3
-0, 56823, 56823, 512, 1024, 0xa4c07b34
-0, 57330, 57330, 512, 1024, 0xd6d8f15c
-0, 57837, 57837, 512, 1024, 0x1eccddd7
-0, 58366, 58366, 512, 1024, 0x2b69f9cb
-0, 58874, 58874, 512, 1024, 0x667b775f
-0, 59381, 59381, 512, 1024, 0xad3b84e9
-0, 59888, 59888, 512, 1024, 0x4f29fc67
-0, 60395, 60395, 512, 1024, 0x8d611ab7
-0, 60924, 60924, 512, 1024, 0x278966ea
-0, 61431, 61431, 512, 1024, 0xaf33812b
-0, 61938, 61938, 512, 1024, 0xa55f4265
-0, 62446, 62446, 512, 1024, 0x023cb51c
-0, 62975, 62975, 512, 1024, 0x1d1f1005
-0, 63482, 63482, 512, 1024, 0x874cccf7
-0, 63989, 63989, 512, 1024, 0xda705428
-0, 64496, 64496, 512, 1024, 0x48d9b440
-0, 65003, 65003, 512, 1024, 0xa14e0712
-0, 65533, 65533, 512, 1024, 0x7efbad1f
-0, 66040, 66040, 512, 1024, 0xdb82c17f
-0, 66547, 66547, 512, 1024, 0xcbe87613
-0, 67054, 67054, 512, 1024, 0x3a63df1d
-0, 67583, 67583, 512, 1024, 0xd5636bba
-0, 68090, 68090, 512, 1024, 0x9397af23
-0, 68598, 68598, 512, 1024, 0x32a07c98
-0, 69105, 69105, 512, 1024, 0x202ca667
-0, 69612, 69612, 512, 1024, 0xdf969011
-0, 70141, 70141, 512, 1024, 0xc434d238
-0, 70648, 70648, 512, 1024, 0xe9ad7562
-0, 71155, 71155, 512, 1024, 0xb51b6b50
-0, 71663, 71663, 512, 1024, 0xe70aecd3
-0, 72192, 72192, 512, 1024, 0x03c816b2
-0, 72699, 72699, 512, 1024, 0x869fdf25
-0, 73206, 73206, 512, 1024, 0xd40a0a62
-0, 73713, 73713, 512, 1024, 0x5af7dd35
-0, 74220, 74220, 512, 1024, 0x891ffc72
-0, 74750, 74750, 512, 1024, 0x1ff68a08
-0, 75257, 75257, 512, 1024, 0x5a7517a9
-0, 75764, 75764, 512, 1024, 0x0f959f74
-0, 76271, 76271, 512, 1024, 0xe92a12a2
-0, 76778, 76778, 512, 1024, 0x38000e55
-0, 77307, 77307, 512, 1024, 0x39fbdd70
-0, 77814, 77814, 512, 1024, 0xca3d9184
-0, 78322, 78322, 512, 1024, 0x66c8995b
-0, 78829, 78829, 512, 1024, 0xac25acea
-0, 79358, 79358, 512, 1024, 0x3cd1046c
-0, 79865, 79865, 512, 1024, 0x6a1df31c
-0, 80372, 80372, 512, 1024, 0x21ca10a1
-0, 80879, 80879, 512, 1024, 0x1aeccedc
-0, 81387, 81387, 512, 1024, 0xddea1335
-0, 81916, 81916, 512, 1024, 0x19f5ca9f
-0, 82423, 82423, 512, 1024, 0x88e95e43
-0, 82930, 82930, 512, 1024, 0x726284fe
-0, 83437, 83437, 512, 1024, 0x6b85b40e
-0, 83966, 83966, 512, 1024, 0x111fee2a
-0, 84474, 84474, 512, 1024, 0x3656b588
-0, 84981, 84981, 512, 1024, 0xa5a2b552
-0, 85488, 85488, 512, 1024, 0x38fb2467
-0, 85995, 85995, 512, 1024, 0xaa919ccc
-0, 86524, 86524, 512, 1024, 0x15993dbc
-0, 87031, 87031, 512, 1024, 0xbe01a7b9
-0, 87539, 87539, 512, 1024, 0xefe93c09
-0, 88046, 88046, 512, 1024, 0x1bb566e5
-0, 88575, 88575, 512, 1024, 0x15ce6237
-0, 89082, 89082, 512, 1024, 0xa8552e66
-0, 89589, 89589, 512, 1024, 0x9d80187e
-0, 90096, 90096, 512, 1024, 0x5df3fc30
-0, 90603, 90603, 512, 1024, 0x1a312aa5
-0, 91133, 91133, 512, 1024, 0x6bb8e302
-0, 91640, 91640, 512, 1024, 0xbd9684bb
-0, 92147, 92147, 512, 1024, 0x78b0b166
-0, 92654, 92654, 512, 1024, 0xd9af5eae
-0, 93183, 93183, 512, 1024, 0xdb90fe82
-0, 93690, 93690, 512, 1024, 0x327614e9
-0, 94198, 94198, 512, 1024, 0x1f19b7fe
-0, 94705, 94705, 512, 1024, 0x46c53f96
-0, 95212, 95212, 512, 1024, 0x921b2189
-0, 95741, 95741, 512, 1024, 0xa8fbc85a
-0, 96248, 96248, 512, 1024, 0xabfdaaae
-0, 96755, 96755, 512, 1024, 0x6acc7387
-0, 97263, 97263, 512, 1024, 0x0d9c27b5
-0, 97792, 97792, 512, 1024, 0xba4dd809
-0, 98299, 98299, 512, 1024, 0x2a2ad521
-0, 98806, 98806, 512, 1024, 0x892de38a
-0, 99313, 99313, 512, 1024, 0xdc97a2eb
-0, 99820, 99820, 512, 1024, 0x4f614ca4
-0, 100350, 100350, 512, 1024, 0x9c8a77ea
-0, 100857, 100857, 512, 1024, 0x2d30e646
-0, 101364, 101364, 512, 1024, 0x74e800a7
-0, 101871, 101871, 512, 1024, 0x1e01fb02
-0, 102378, 102378, 512, 1024, 0x4ed2c1d8
-0, 102907, 102907, 512, 1024, 0xf2fdbe63
-0, 103415, 103415, 512, 1024, 0x8d6f63a1
-0, 103922, 103922, 512, 1024, 0xded468d9
-0, 104429, 104429, 512, 1024, 0xccad839e
-0, 104958, 104958, 512, 1024, 0xdde7c082
-0, 105465, 105465, 512, 1024, 0x548613c5
-0, 105972, 105972, 512, 1024, 0x383909bd
-0, 106479, 106479, 512, 1024, 0xfd37627b
-0, 106987, 106987, 512, 1024, 0x6d95a481
-0, 107516, 107516, 512, 1024, 0x56aa87fa
-0, 108023, 108023, 512, 1024, 0x7b67258c
-0, 108530, 108530, 512, 1024, 0x7dd99a92
-0, 109037, 109037, 512, 1024, 0x4a66d102
-0, 109566, 109566, 512, 1024, 0x7b3fce51
-0, 110074, 110074, 512, 1024, 0xbbd968aa
-0, 110581, 110581, 512, 1024, 0x8283ec36
-0, 111088, 111088, 512, 1024, 0x3c96493d
-0, 111595, 111595, 512, 1024, 0xfa4f8cf8
-0, 112124, 112124, 512, 1024, 0xe2cf872d
-0, 112631, 112631, 512, 1024, 0x0a9e7aa6
-0, 113139, 113139, 512, 1024, 0x6e7a0550
-0, 113646, 113646, 512, 1024, 0x3acfea2f
-0, 114175, 114175, 512, 1024, 0x7111d0fa
-0, 114682, 114682, 512, 1024, 0xe9a1eca9
-0, 115189, 115189, 512, 1024, 0x24da6c46
-0, 115696, 115696, 512, 1024, 0x117cff37
-0, 116204, 116204, 512, 1024, 0x0f27cab6
-0, 116733, 116733, 512, 1024, 0x69b6b4e6
-0, 117240, 117240, 512, 1024, 0x1e6cc841
-0, 117747, 117747, 512, 1024, 0xb01e2365
-0, 118254, 118254, 512, 1024, 0x14e200d3
-0, 118783, 118783, 512, 1024, 0xd1184c98
-0, 119291, 119291, 512, 1024, 0xef9140e9
-0, 119798, 119798, 512, 1024, 0x4cbb645e
-0, 120305, 120305, 512, 1024, 0xe7fe2f06
-0, 120812, 120812, 512, 1024, 0xf8c45028
-0, 121341, 121341, 512, 1024, 0x561358f4
-0, 121848, 121848, 512, 1024, 0xd0129b77
-0, 122355, 122355, 512, 1024, 0xcc636e88
-0, 122863, 122863, 512, 1024, 0xe9406321
-0, 123392, 123392, 512, 1024, 0x9f16a041
-0, 123899, 123899, 512, 1024, 0x468bf409
-0, 124406, 124406, 512, 1024, 0x3df70f7b
-0, 124913, 124913, 512, 1024, 0xa880b11b
-0, 125420, 125420, 512, 1024, 0x3286c489
-0, 125950, 125950, 512, 1024, 0x39fe9ebc
-0, 126457, 126457, 512, 1024, 0xc533d83b
-0, 126964, 126964, 512, 1024, 0x153b195d
-0, 127471, 127471, 512, 1024, 0xd84786a1
-0, 127978, 127978, 512, 1024, 0xdc295aaa
-0, 128507, 128507, 512, 1024, 0xfb764d8c
-0, 129015, 129015, 512, 1024, 0xeebc9db9
-0, 129522, 129522, 512, 1024, 0x7ba9403e
-0, 130029, 130029, 512, 1024, 0x4e5571ec
-0, 130558, 130558, 512, 1024, 0xd965fad4
-0, 131065, 131065, 512, 1024, 0x87e259f2
-0, 131572, 131572, 512, 1024, 0xae7e533b
-0, 132080, 132080, 512, 1024, 0x313cf4d6
-0, 132587, 132587, 512, 1024, 0xe1844c90
-0, 133116, 133116, 512, 1024, 0xbb057b44
-0, 133623, 133623, 512, 1024, 0xa5099687
-0, 134130, 134130, 512, 1024, 0xbff10707
-0, 134637, 134637, 512, 1024, 0x37c4ffc0
-0, 135167, 135167, 512, 1024, 0xf9fb6caa
-0, 135674, 135674, 512, 1024, 0x3b6a3a1f
-0, 136181, 136181, 512, 1024, 0x83431edb
-0, 136688, 136688, 512, 1024, 0x1eb713cf
-0, 137195, 137195, 512, 1024, 0xd7b07a6d
-0, 137724, 137724, 512, 1024, 0x81ae3391
-0, 138231, 138231, 512, 1024, 0xf150130a
-0, 138739, 138739, 512, 1024, 0x09678eaa
-0, 139246, 139246, 512, 1024, 0xb94e06f1
-0, 139775, 139775, 512, 1024, 0x67b1dbc9
-0, 140282, 140282, 512, 1024, 0xd6edc235
-0, 140789, 140789, 512, 1024, 0x34e4c499
-0, 141296, 141296, 512, 1024, 0xeefd89c0
-0, 141804, 141804, 512, 1024, 0x38afdaf1
-0, 142333, 142333, 512, 1024, 0x29a60d76
-0, 142840, 142840, 512, 1024, 0xe28a4372
-0, 143347, 143347, 512, 1024, 0x7089454d
-0, 143854, 143854, 512, 1024, 0x0c01bb7b
-0, 144383, 144383, 512, 1024, 0xbd776a72
-0, 144891, 144891, 512, 1024, 0x86776fd0
-0, 145398, 145398, 512, 1024, 0xb37c88f7
-0, 145905, 145905, 512, 1024, 0x5f90aaf8
-0, 146412, 146412, 512, 1024, 0x203d4222
-0, 146941, 146941, 512, 1024, 0x382692a6
-0, 147448, 147448, 512, 1024, 0xf37c95fd
-0, 147956, 147956, 512, 1024, 0x6c0b8877
-0, 148463, 148463, 512, 1024, 0x2e54a8b6
-0, 148992, 148992, 512, 1024, 0x7f266488
-0, 149499, 149499, 512, 1024, 0xfbf20f9a
-0, 150006, 150006, 512, 1024, 0xf2985cc0
-0, 150513, 150513, 512, 1024, 0xc7075340
-0, 151020, 151020, 512, 1024, 0xe4585695
-0, 151550, 151550, 512, 1024, 0xbdffa380
-0, 152057, 152057, 512, 1024, 0x2422a8a9
-0, 152564, 152564, 512, 1024, 0x59cbd75f
-0, 153071, 153071, 512, 1024, 0x04ad1a8c
-0, 153578, 153578, 512, 1024, 0x33c09191
-0, 154107, 154107, 512, 1024, 0x55efa6fd
-0, 154615, 154615, 512, 1024, 0xf73d0e5d
-0, 155122, 155122, 512, 1024, 0x6141ebae
-0, 155629, 155629, 512, 1024, 0x7db17a68
-0, 156158, 156158, 512, 1024, 0xa6c690b6
-0, 156665, 156665, 512, 1024, 0xa6fd6725
-0, 157172, 157172, 512, 1024, 0x50a90b9b
-0, 157680, 157680, 512, 1024, 0xef990dc8
-0, 158187, 158187, 512, 1024, 0x75adf6b5
-0, 158716, 158716, 512, 1024, 0x61eac43e
-0, 159223, 159223, 512, 1024, 0x67797a19
-0, 159730, 159730, 512, 1024, 0xf325277a
-0, 160237, 160237, 512, 1024, 0x18bf254a
-0, 160767, 160767, 512, 1024, 0x2ce6bee3
-0, 161274, 161274, 512, 1024, 0x8d320860
-0, 161781, 161781, 512, 1024, 0xc979b6e8
-0, 162288, 162288, 512, 1024, 0xdb644b41
-0, 162795, 162795, 512, 1024, 0xe1b368ba
-0, 163324, 163324, 512, 1024, 0xacc53d15
-0, 163832, 163832, 512, 1024, 0x42ea8c18
-0, 164339, 164339, 512, 1024, 0xe52c99a4
-0, 164846, 164846, 512, 1024, 0xd7db54a6
-0, 165375, 165375, 512, 1024, 0x7f27a7e3
-0, 165882, 165882, 512, 1024, 0xf7ffeaa9
-0, 166389, 166389, 512, 1024, 0x792b6088
-0, 166896, 166896, 512, 1024, 0x61d99724
-0, 167404, 167404, 512, 1024, 0x5213720e
-0, 167933, 167933, 512, 1024, 0xac09dd30
-0, 168440, 168440, 512, 1024, 0x960bf6bb
-0, 168947, 168947, 512, 1024, 0xc90168e1
-0, 169454, 169454, 512, 1024, 0x43b45768
-0, 169983, 169983, 512, 1024, 0x935d60a1
-0, 170491, 170491, 512, 1024, 0x9a342ef2
-0, 170998, 170998, 512, 1024, 0xc894709f
-0, 171505, 171505, 512, 1024, 0x59b43b07
-0, 172012, 172012, 512, 1024, 0x36a1a98d
-0, 172541, 172541, 512, 1024, 0x9e1a121c
-0, 173048, 173048, 512, 1024, 0x02208b78
-0, 173556, 173556, 512, 1024, 0xd1d7b274
-0, 174063, 174063, 512, 1024, 0xdacd5096
-0, 174592, 174592, 512, 1024, 0x51b71ead
-0, 175099, 175099, 512, 1024, 0xd009a7ca
-0, 175606, 175606, 512, 1024, 0xb6d5a938
-0, 176113, 176113, 512, 1024, 0xf3d45e47
-0, 176621, 176621, 512, 1024, 0xea8e04fc
-0, 177150, 177150, 512, 1024, 0x0b928bd8
-0, 177657, 177657, 512, 1024, 0x0f02caec
-0, 178164, 178164, 512, 1024, 0xe2b137a8
-0, 178671, 178671, 512, 1024, 0xd5f94892
+0, 512, 512, 512, 1024, 0x00000000
+0, 1024, 1024, 512, 1024, 0xed2d3f6b
+0, 1533, 1533, 512, 1024, 0x51f6ccb3
+0, 2040, 2040, 512, 1024, 0x58bd75aa
+0, 2552, 2552, 512, 1024, 0xd857a310
+0, 3064, 3064, 512, 1024, 0xc483a5b8
+0, 3576, 3576, 512, 1024, 0x923ecf67
+0, 4088, 4088, 512, 1024, 0xf87dcd53
+0, 4598, 4598, 512, 1024, 0xdc32c002
+0, 5110, 5110, 512, 1024, 0xb760def1
+0, 5622, 5622, 512, 1024, 0x6838d2b2
+0, 6134, 6134, 512, 1024, 0xe45aca1e
+0, 6646, 6646, 512, 1024, 0xde1fb955
+0, 7158, 7158, 512, 1024, 0x9e23b949
+0, 7670, 7670, 512, 1024, 0x840cc000
+0, 8182, 8182, 512, 1024, 0x0a29cbfa
+0, 8694, 8694, 512, 1024, 0x9871d4c4
+0, 9206, 9206, 512, 1024, 0xb35dc9f2
+0, 9718, 9718, 512, 1024, 0xf37fda0a
+0, 10230, 10230, 512, 1024, 0xa640f990
+0, 10742, 10742, 512, 1024, 0x516fe6f5
+0, 11254, 11254, 512, 1024, 0xc78bc6a6
+0, 11766, 11766, 512, 1024, 0x700fd6ee
+0, 12278, 12278, 512, 1024, 0x5383d5ad
+0, 12790, 12790, 512, 1024, 0xbe01d091
+0, 13302, 13302, 512, 1024, 0x72dfcfc7
+0, 13814, 13814, 512, 1024, 0xd8fecea9
+0, 14326, 14326, 512, 1024, 0xa464d79b
+0, 14838, 14838, 512, 1024, 0xf394e2cb
+0, 15350, 15350, 512, 1024, 0xa301ec49
+0, 15862, 15862, 512, 1024, 0x5e09d60f
+0, 16374, 16374, 512, 1024, 0xd13edd6f
+0, 16886, 16886, 512, 1024, 0x7423ef39
+0, 17398, 17398, 512, 1024, 0x96e2f083
+0, 17910, 17910, 512, 1024, 0x5ed7dbee
+0, 18422, 18422, 512, 1024, 0x3874f714
+0, 18934, 18934, 512, 1024, 0xa5e6edab
+0, 19446, 19446, 512, 1024, 0x0a04ee3a
+0, 19958, 19958, 512, 1024, 0xadfee6b9
+0, 20470, 20470, 512, 1024, 0xd0bbe6d2
+0, 20982, 20982, 512, 1024, 0x223eebb7
+0, 21494, 21494, 512, 1024, 0x0473e479
+0, 22006, 22006, 512, 1024, 0xdf15e51e
+0, 22518, 22518, 512, 1024, 0xa954e483
+0, 23030, 23030, 512, 1024, 0x6df3ed03
+0, 23542, 23542, 512, 1024, 0x0860e544
+0, 24054, 24054, 512, 1024, 0xc241e8dc
+0, 24566, 24566, 512, 1024, 0xd0e1d6a4
+0, 25078, 25078, 512, 1024, 0xcb2ff988
+0, 25590, 25590, 512, 1024, 0x51fae08e
+0, 26102, 26102, 512, 1024, 0xae39f2fc
+0, 26614, 26614, 512, 1024, 0xfd74f07c
+0, 27126, 27126, 512, 1024, 0x1936edc1
+0, 27638, 27638, 512, 1024, 0x95f8deae
+0, 28150, 28150, 512, 1024, 0x93bdf605
+0, 28662, 28662, 512, 1024, 0x7a07dd32
+0, 29174, 29174, 512, 1024, 0x6889fdc1
+0, 29686, 29686, 512, 1024, 0x989bf024
+0, 30198, 30198, 512, 1024, 0xc764ce80
+0, 30710, 30710, 512, 1024, 0x0e62d721
+0, 31222, 31222, 512, 1024, 0x59c2fbe3
+0, 31734, 31734, 512, 1024, 0xf14ee29d
+0, 32246, 32246, 512, 1024, 0x02a0f21b
+0, 32758, 32758, 512, 1024, 0xadb3d361
+0, 33270, 33270, 512, 1024, 0xdcb3d1fc
+0, 33782, 33782, 512, 1024, 0x2924f9dc
+0, 34294, 34294, 512, 1024, 0x7507ebec
+0, 34806, 34806, 512, 1024, 0xe009f343
+0, 35318, 35318, 512, 1024, 0x21e9e7ac
+0, 35830, 35830, 512, 1024, 0x845bda9e
+0, 36342, 36342, 512, 1024, 0xb1b3e632
+0, 36854, 36854, 512, 1024, 0x61ccf593
+0, 37366, 37366, 512, 1024, 0x8cdbf603
+0, 37878, 37878, 512, 1024, 0xf8f7e673
+0, 38390, 38390, 512, 1024, 0x55efdd24
+0, 38902, 38902, 512, 1024, 0x4059e8ff
+0, 39414, 39414, 512, 1024, 0xb3afe5be
+0, 39926, 39926, 512, 1024, 0x7236e965
+0, 40438, 40438, 512, 1024, 0xe683db69
+0, 40950, 40950, 512, 1024, 0x29e3d93c
+0, 41462, 41462, 512, 1024, 0x74f2f27f
+0, 41974, 41974, 512, 1024, 0x32cde3ba
+0, 42486, 42486, 512, 1024, 0xe907f171
+0, 42998, 42998, 512, 1024, 0x206ae2a5
+0, 43510, 43510, 512, 1024, 0x6379efa1
+0, 44022, 44022, 512, 1024, 0x0f0fee85
+0, 44534, 44534, 512, 1024, 0x3195e314
+0, 45046, 45046, 512, 1024, 0x4646ead3
+0, 45558, 45558, 512, 1024, 0x5635dcf5
+0, 46070, 46070, 512, 1024, 0xd76fc780
+0, 46582, 46582, 512, 1024, 0x847ff8a5
+0, 47094, 47094, 512, 1024, 0xaca8eda3
+0, 47606, 47606, 512, 1024, 0x9a2de1ea
+0, 48118, 48118, 512, 1024, 0xc92ff23a
+0, 48630, 48630, 512, 1024, 0x0e0ef038
+0, 49142, 49142, 512, 1024, 0xc32cf495
+0, 49654, 49654, 512, 1024, 0x6ab1ec79
+0, 50166, 50166, 512, 1024, 0xe43cd8d6
+0, 50678, 50678, 512, 1024, 0x4ba2deab
+0, 51190, 51190, 512, 1024, 0x6d16ea0e
+0, 51702, 51702, 512, 1024, 0xe5b0ee70
+0, 52214, 52214, 512, 1024, 0xcf6cf074
+0, 52726, 52726, 512, 1024, 0x2206e61d
+0, 53238, 53238, 512, 1024, 0xfbb9e7e7
+0, 53750, 53750, 512, 1024, 0x2bc1e115
+0, 54262, 54262, 512, 1024, 0x4ca6e5c5
+0, 54774, 54774, 512, 1024, 0x061cead0
+0, 55286, 55286, 512, 1024, 0x3dc9f950
+0, 55798, 55798, 512, 1024, 0x9399f10d
+0, 56310, 56310, 512, 1024, 0xa2bff5ae
+0, 56822, 56822, 512, 1024, 0xd21de569
+0, 57334, 57334, 512, 1024, 0x1c45e3be
+0, 57846, 57846, 512, 1024, 0xff5dff1c
+0, 58358, 58358, 512, 1024, 0x992df5d3
+0, 58870, 58870, 512, 1024, 0xafedea2f
+0, 59382, 59382, 512, 1024, 0x6e73d6a8
+0, 59894, 59894, 512, 1024, 0x72dff283
+0, 60406, 60406, 512, 1024, 0x50b5f1a6
+0, 60918, 60918, 512, 1024, 0xffe1decb
+0, 61430, 61430, 512, 1024, 0x8993ecff
+0, 61942, 61942, 512, 1024, 0x954bd63a
+0, 62454, 62454, 512, 1024, 0x4707f577
+0, 62966, 62966, 512, 1024, 0x7a88f81f
+0, 63478, 63478, 512, 1024, 0xc771f537
+0, 63990, 63990, 512, 1024, 0x7aade6af
+0, 64502, 64502, 512, 1024, 0x8af5ede5
+0, 65014, 65014, 512, 1024, 0x7500f3f1
+0, 65526, 65526, 512, 1024, 0xea36f707
+0, 66038, 66038, 512, 1024, 0x1a26e39a
+0, 66550, 66550, 512, 1024, 0xa04cf00d
+0, 67062, 67062, 512, 1024, 0xc362f182
+0, 67574, 67574, 512, 1024, 0x79c8f82c
+0, 68086, 68086, 512, 1024, 0x6480eee1
+0, 68598, 68598, 512, 1024, 0x7152eaa0
+0, 69110, 69110, 512, 1024, 0x5dfee6a9
+0, 69622, 69622, 512, 1024, 0x0afae660
+0, 70134, 70134, 512, 1024, 0xdc98e9fc
+0, 70646, 70646, 512, 1024, 0x10b7da06
+0, 71158, 71158, 512, 1024, 0x0571e585
+0, 71670, 71670, 512, 1024, 0x18ddf45e
+0, 72182, 72182, 512, 1024, 0x2cbef242
+0, 72694, 72694, 512, 1024, 0xf5380845
+0, 73206, 73206, 512, 1024, 0x34fff45e
+0, 73718, 73718, 512, 1024, 0x6f97e490
+0, 74230, 74230, 512, 1024, 0x77d6f0db
+0, 74742, 74742, 512, 1024, 0xa25ce2db
+0, 75254, 75254, 512, 1024, 0x8260e4e9
+0, 75766, 75766, 512, 1024, 0xc3b2f7d2
+0, 76278, 76278, 512, 1024, 0x82a7edae
+0, 76790, 76790, 512, 1024, 0x7d08dd54
+0, 77302, 77302, 512, 1024, 0x9059eda6
+0, 77814, 77814, 512, 1024, 0xbebaec88
+0, 78326, 78326, 512, 1024, 0xd9afd586
+0, 78838, 78838, 512, 1024, 0x0ca3e622
+0, 79350, 79350, 512, 1024, 0x4123e9e6
+0, 79862, 79862, 512, 1024, 0x2ff9f95c
+0, 80374, 80374, 512, 1024, 0x8522e261
+0, 80886, 80886, 512, 1024, 0xe4f8f499
+0, 81398, 81398, 512, 1024, 0x34f3f2bd
+0, 81910, 81910, 512, 1024, 0x82efe863
+0, 82422, 82422, 512, 1024, 0x9966fcea
+0, 82934, 82934, 512, 1024, 0xe94de3fd
+0, 83446, 83446, 512, 1024, 0x1ce0e27b
+0, 83958, 83958, 512, 1024, 0xd718dcde
+0, 84470, 84470, 512, 1024, 0xd503e724
+0, 84982, 84982, 512, 1024, 0x427ee3b2
+0, 85494, 85494, 512, 1024, 0x4512dcc4
+0, 86006, 86006, 512, 1024, 0xcf31e77c
+0, 86518, 86518, 512, 1024, 0xeb41ea81
+0, 87030, 87030, 512, 1024, 0xfa43e67c
+0, 87542, 87542, 512, 1024, 0x8162f3c9
+0, 88054, 88054, 512, 1024, 0x1b55f6b0
+0, 88566, 88566, 512, 1024, 0x3ebeec44
+0, 89078, 89078, 512, 1024, 0x740fe0c4
+0, 89590, 89590, 512, 1024, 0x8fb4e8b2
+0, 90102, 90102, 512, 1024, 0xe49de6a2
+0, 90614, 90614, 512, 1024, 0xd64febdf
+0, 91126, 91126, 512, 1024, 0x0e74ee08
+0, 91638, 91638, 512, 1024, 0x6c0ddf07
+0, 92150, 92150, 512, 1024, 0x7fb8e3c9
+0, 92662, 92662, 512, 1024, 0x52bfe96c
+0, 93174, 93174, 512, 1024, 0xfc22ee64
+0, 93686, 93686, 512, 1024, 0xe20ae718
+0, 94198, 94198, 512, 1024, 0xa94be395
+0, 94710, 94710, 512, 1024, 0xded306d0
+0, 95222, 95222, 512, 1024, 0x31f7c831
+0, 95734, 95734, 512, 1024, 0x0ffde0a8
+0, 96246, 96246, 512, 1024, 0xc692e3e0
+0, 96758, 96758, 512, 1024, 0x1d8ff7c7
+0, 97270, 97270, 512, 1024, 0x038ee172
+0, 97782, 97782, 512, 1024, 0x9a1eef59
+0, 98294, 98294, 512, 1024, 0x158fe750
+0, 98806, 98806, 512, 1024, 0xac15e42c
+0, 99318, 99318, 512, 1024, 0x6323ed44
+0, 99830, 99830, 512, 1024, 0xd10ce4bb
+0, 100342, 100342, 512, 1024, 0xc1cce296
+0, 100854, 100854, 512, 1024, 0x0782f094
+0, 101366, 101366, 512, 1024, 0xd109de36
+0, 101878, 101878, 512, 1024, 0x175600fb
+0, 102390, 102390, 512, 1024, 0x95d5e8d9
+0, 102902, 102902, 512, 1024, 0xebb6eee1
+0, 103414, 103414, 512, 1024, 0x187cfadc
+0, 103926, 103926, 512, 1024, 0xce35fa5c
+0, 104438, 104438, 512, 1024, 0x8327eea2
+0, 104950, 104950, 512, 1024, 0x5543f219
+0, 105462, 105462, 512, 1024, 0xaacbe0dc
+0, 105974, 105974, 512, 1024, 0xa538e9fb
+0, 106486, 106486, 512, 1024, 0x4dcbe655
+0, 106998, 106998, 512, 1024, 0x86b6d93b
+0, 107510, 107510, 512, 1024, 0x1a06f878
+0, 108022, 108022, 512, 1024, 0xd926e8ef
+0, 108534, 108534, 512, 1024, 0xc624db2f
+0, 109046, 109046, 512, 1024, 0x2153e20d
+0, 109558, 109558, 512, 1024, 0x01dce868
+0, 110070, 110070, 512, 1024, 0xfa5fd3cd
+0, 110582, 110582, 512, 1024, 0x2adef2d5
+0, 111094, 111094, 512, 1024, 0x4f48f8e2
+0, 111606, 111606, 512, 1024, 0x613feeee
+0, 112118, 112118, 512, 1024, 0x3780de8a
+0, 112630, 112630, 512, 1024, 0x2093eb65
+0, 113142, 113142, 512, 1024, 0x54baebbb
+0, 113654, 113654, 512, 1024, 0x8686dd7c
+0, 114166, 114166, 512, 1024, 0x7f8ae80c
+0, 114678, 114678, 512, 1024, 0x7aede972
+0, 115190, 115190, 512, 1024, 0x971bebc0
+0, 115702, 115702, 512, 1024, 0x2dd5fd4b
+0, 116214, 116214, 512, 1024, 0xb1b3e4a3
+0, 116726, 116726, 512, 1024, 0x192defc6
+0, 117238, 117238, 512, 1024, 0x5e46ec44
+0, 117750, 117750, 512, 1024, 0xe6d8e05a
+0, 118262, 118262, 512, 1024, 0x7e2fe2b0
+0, 118774, 118774, 512, 1024, 0x9e3bdf80
+0, 119286, 119286, 512, 1024, 0xa98cd85e
+0, 119798, 119798, 512, 1024, 0x6061e0c4
+0, 120310, 120310, 512, 1024, 0x6112f3fc
+0, 120822, 120822, 512, 1024, 0x99bdfb01
+0, 121334, 121334, 512, 1024, 0x3f5df3ca
+0, 121846, 121846, 512, 1024, 0xf5ebeb05
+0, 122358, 122358, 512, 1024, 0x8498e565
+0, 122870, 122870, 512, 1024, 0x0497f0b7
+0, 123382, 123382, 512, 1024, 0x626ae800
+0, 123894, 123894, 512, 1024, 0xfb71eec4
+0, 124406, 124406, 512, 1024, 0xa86ee739
+0, 124918, 124918, 512, 1024, 0x25c0e050
+0, 125430, 125430, 512, 1024, 0x6027e91e
+0, 125942, 125942, 512, 1024, 0x6772df6e
+0, 126454, 126454, 512, 1024, 0xfefff844
+0, 126966, 126966, 512, 1024, 0x547be862
+0, 127478, 127478, 512, 1024, 0xca84e795
+0, 127990, 127990, 512, 1024, 0xd124db3e
+0, 128502, 128502, 512, 1024, 0xcaf3deb5
+0, 129014, 129014, 512, 1024, 0x487ce92d
+0, 129526, 129526, 512, 1024, 0x117feb95
+0, 130038, 130038, 512, 1024, 0x7b63de3d
+0, 130550, 130550, 512, 1024, 0xa529d8e1
+0, 131062, 131062, 512, 1024, 0x56f6da26
+0, 131574, 131574, 512, 1024, 0xffb8d5af
+0, 132086, 132086, 512, 1024, 0xeecbdc04
+0, 132598, 132598, 512, 1024, 0xfc59d2d2
+0, 133110, 133110, 512, 1024, 0xaf7acef7
+0, 133622, 133622, 512, 1024, 0x3f9bf258
+0, 134134, 134134, 512, 1024, 0xcf54e9d6
+0, 134646, 134646, 512, 1024, 0x680cd0aa
+0, 135158, 135158, 512, 1024, 0x3c1bdc1f
+0, 135670, 135670, 512, 1024, 0x8c8ffe22
+0, 136182, 136182, 512, 1024, 0xf415d362
+0, 136694, 136694, 512, 1024, 0x8c8cdaa9
+0, 137206, 137206, 512, 1024, 0x9531e9f1
+0, 137718, 137718, 512, 1024, 0x223ce536
+0, 138230, 138230, 512, 1024, 0xdfbce5f9
+0, 138742, 138742, 512, 1024, 0x20b6ed7d
+0, 139254, 139254, 512, 1024, 0x1a17e109
+0, 139766, 139766, 512, 1024, 0xc672eaea
+0, 140278, 140278, 512, 1024, 0x12a7dc5e
+0, 140790, 140790, 512, 1024, 0x4497f342
+0, 141302, 141302, 512, 1024, 0xdfb5db4b
+0, 141814, 141814, 512, 1024, 0xde48ef6c
+0, 142326, 142326, 512, 1024, 0x1d98e316
+0, 142838, 142838, 512, 1024, 0xbd2ad72f
+0, 143350, 143350, 512, 1024, 0xf1aad776
+0, 143862, 143862, 512, 1024, 0x4db3e3c0
+0, 144374, 144374, 512, 1024, 0x832de0a0
+0, 144886, 144886, 512, 1024, 0xc5f0ef25
+0, 145398, 145398, 512, 1024, 0x419bda6e
+0, 145910, 145910, 512, 1024, 0x5de7f77e
+0, 146422, 146422, 512, 1024, 0x0063ec9a
+0, 146934, 146934, 512, 1024, 0x10c3d470
+0, 147446, 147446, 512, 1024, 0xba66d226
+0, 147958, 147958, 512, 1024, 0xea47ded3
+0, 148470, 148470, 512, 1024, 0x6202d67b
+0, 148982, 148982, 512, 1024, 0x3f80e7cf
+0, 149494, 149494, 512, 1024, 0x4e64eaae
+0, 150006, 150006, 512, 1024, 0x2108e83d
+0, 150518, 150518, 512, 1024, 0x38c3dec1
+0, 151030, 151030, 512, 1024, 0x46d3f77a
+0, 151542, 151542, 512, 1024, 0x4838e787
+0, 152054, 152054, 512, 1024, 0xc71df16d
+0, 152566, 152566, 512, 1024, 0xdbe4ebbd
+0, 153078, 153078, 512, 1024, 0xa156d07b
+0, 153590, 153590, 512, 1024, 0x34eddc80
+0, 154102, 154102, 512, 1024, 0xe840e87c
+0, 154614, 154614, 512, 1024, 0x6accf8f5
+0, 155126, 155126, 512, 1024, 0xa1dbebb9
+0, 155638, 155638, 512, 1024, 0x6d07d98c
+0, 156150, 156150, 512, 1024, 0x94c7e805
+0, 156662, 156662, 512, 1024, 0x5199e586
+0, 157174, 157174, 512, 1024, 0xe797e1aa
+0, 157686, 157686, 512, 1024, 0xff19eda7
+0, 158198, 158198, 512, 1024, 0x9cb9d040
+0, 158710, 158710, 512, 1024, 0xaeedd325
+0, 159222, 159222, 512, 1024, 0xf5ade306
+0, 159734, 159734, 512, 1024, 0x54a5e129
+0, 160246, 160246, 512, 1024, 0x6665ddeb
+0, 160758, 160758, 512, 1024, 0x9d18e033
+0, 161270, 161270, 512, 1024, 0x7f23df74
+0, 161782, 161782, 512, 1024, 0x7c34f158
+0, 162294, 162294, 512, 1024, 0x47f6dae2
+0, 162806, 162806, 512, 1024, 0x5ffdd903
+0, 163318, 163318, 512, 1024, 0x8233d108
+0, 163830, 163830, 512, 1024, 0x45c6e20d
+0, 164342, 164342, 512, 1024, 0xae11fa6e
+0, 164854, 164854, 512, 1024, 0xa30defd2
+0, 165366, 165366, 512, 1024, 0xfc1ecccf
+0, 165878, 165878, 512, 1024, 0x920edc94
+0, 166390, 166390, 512, 1024, 0xd7f3dc58
+0, 166902, 166902, 512, 1024, 0x4972d37d
+0, 167414, 167414, 512, 1024, 0xfefef358
+0, 167926, 167926, 512, 1024, 0x3648e473
+0, 168438, 168438, 512, 1024, 0x58dee6c3
+0, 168950, 168950, 512, 1024, 0x9cc6df27
+0, 169462, 169462, 512, 1024, 0x6adfe99c
+0, 169974, 169974, 512, 1024, 0x6a56e11f
+0, 170486, 170486, 512, 1024, 0x4860edf1
+0, 170998, 170998, 512, 1024, 0x9132f10a
+0, 171510, 171510, 512, 1024, 0x3e09d209
+0, 172022, 172022, 512, 1024, 0x4b6bf4d8
+0, 172534, 172534, 512, 1024, 0x0cd5e838
+0, 173046, 173046, 512, 1024, 0x080be078
+0, 173558, 173558, 512, 1024, 0xfdb0e31c
+0, 174070, 174070, 512, 1024, 0xced5e7bd
+0, 174582, 174582, 512, 1024, 0x65b3e435
+0, 175094, 175094, 512, 1024, 0x5b5bfe2e
+0, 175606, 175606, 512, 1024, 0xa8bde3cb
+0, 176118, 176118, 512, 1024, 0xfd0fdefa
+0, 176630, 176630, 512, 1024, 0xbec4ef95
+0, 177142, 177142, 512, 1024, 0x683ad8dd
+0, 177654, 177654, 512, 1024, 0x8eefeb77
+0, 178166, 178166, 512, 1024, 0x84fc5878
+0, 178678, 178678, 512, 1024, 0x9a0ded60
diff --git a/tests/ref/fate/aic b/tests/ref/fate/aic
new file mode 100644
index 0000000000..90692f1d0f
--- /dev/null
+++ b/tests/ref/fate/aic
@@ -0,0 +1,16 @@
+#tb 0: 100/2997
+0, 0, 0, 1, 2332800, 0xd941b42f
+0, 1, 1, 1, 2332800, 0xd941b42f
+0, 2, 2, 1, 2332800, 0xae0f5983
+0, 3, 3, 1, 2332800, 0x51cfc127
+0, 4, 4, 1, 2332800, 0x24d40447
+0, 5, 5, 1, 2332800, 0x858a9f51
+0, 6, 6, 1, 2332800, 0x533b48e8
+0, 7, 7, 1, 2332800, 0x2fd73267
+0, 8, 8, 1, 2332800, 0x153566c7
+0, 9, 9, 1, 2332800, 0xa1c49c45
+0, 10, 10, 1, 2332800, 0xb966e25a
+0, 11, 11, 1, 2332800, 0xd0ce5985
+0, 12, 12, 1, 2332800, 0x0029a52e
+0, 13, 13, 1, 2332800, 0x893116c5
+0, 14, 14, 1, 2332800, 0x073d2491
diff --git a/tests/ref/fate/aic-oddsize b/tests/ref/fate/aic-oddsize
index ba4a6256a9..9183089971 100644
--- a/tests/ref/fate/aic-oddsize
+++ b/tests/ref/fate/aic-oddsize
@@ -1,58 +1,58 @@
-#tb 0: 1/14587
-0, 0, 0, 0, 174243, 0xa40491e1
-0, 1000, 1000, 0, 174243, 0xa12cbb56
-0, 2000, 2000, 0, 174243, 0xa12cbb56
-0, 3000, 3000, 0, 174243, 0xa12cbb56
-0, 4000, 4000, 0, 174243, 0xa12cbb56
-0, 5000, 5000, 0, 174243, 0xa12cbb56
-0, 6000, 6000, 0, 174243, 0xa12cbb56
-0, 7000, 7000, 0, 174243, 0xa12cbb56
-0, 8000, 8000, 0, 174243, 0xa12cbb56
-0, 9000, 9000, 0, 174243, 0x4e7b7299
-0, 10000, 10000, 0, 174243, 0x31573b99
-0, 11000, 11000, 0, 174243, 0x013397b6
-0, 12000, 12000, 0, 174243, 0xdd988ab8
-0, 13000, 13000, 0, 174243, 0xd6d96b1e
-0, 14000, 14000, 0, 174243, 0xd6d96b1e
-0, 15000, 15000, 0, 174243, 0xd6d96b1e
-0, 16000, 16000, 0, 174243, 0x111627d3
-0, 17000, 17000, 0, 174243, 0x284d9ab7
-0, 18000, 18000, 0, 174243, 0xa348c492
-0, 19000, 19000, 0, 174243, 0xa348c492
-0, 20000, 20000, 0, 174243, 0xa348c492
-0, 21000, 21000, 0, 174243, 0xa348c492
-0, 22000, 22000, 0, 174243, 0x2d22c3b8
-0, 23000, 23000, 0, 174243, 0x2d22c3b8
-0, 24000, 24000, 0, 174243, 0x2d22c3b8
-0, 25000, 25000, 0, 174243, 0x2d22c3b8
-0, 26000, 26000, 0, 174243, 0xa6d7c890
-0, 27000, 27000, 0, 174243, 0x8068bfbb
-0, 28000, 28000, 0, 174243, 0x420ae647
-0, 29000, 29000, 0, 174243, 0xc5467756
-0, 30000, 30000, 0, 174243, 0x238a13dd
-0, 31000, 31000, 0, 174243, 0x5bab75dc
-0, 32000, 32000, 0, 174243, 0x14d7f61f
-0, 33000, 33000, 0, 174243, 0x2e1d334f
-0, 34000, 34000, 0, 174243, 0xeade7dc0
-0, 35000, 35000, 0, 174243, 0xeade7dc0
-0, 36000, 36000, 0, 174243, 0xeade7dc0
-0, 37000, 37000, 0, 174243, 0xeade7dc0
-0, 38000, 38000, 0, 174243, 0x088c7ef9
-0, 39000, 39000, 0, 174243, 0x70a3554e
-0, 40000, 40000, 0, 174243, 0x0753d1d4
-0, 41000, 41000, 0, 174243, 0x8266bd6d
-0, 42000, 42000, 0, 174243, 0x4ce3cda9
-0, 43000, 43000, 0, 174243, 0x4ce3cda9
-0, 44000, 44000, 0, 174243, 0x4ce3cda9
-0, 45000, 45000, 0, 174243, 0x4ce3cda9
-0, 46000, 46000, 0, 174243, 0xe5f7cd98
-0, 47000, 47000, 0, 174243, 0xe5f7cd98
-0, 48000, 48000, 0, 174243, 0xe5f7cd98
-0, 49000, 49000, 0, 174243, 0xe5f7cd98
-0, 50000, 50000, 0, 174243, 0x78c5cdb7
-0, 51000, 51000, 0, 174243, 0x78c5cdb7
-0, 52000, 52000, 0, 174243, 0x78c5cdb7
-0, 53000, 53000, 0, 174243, 0xce7ccd92
-0, 54000, 54000, 0, 174243, 0xce7ccd92
-0, 55000, 55000, 0, 174243, 0xce7ccd92
-0, 56000, 56000, 0, 174243, 0xce7ccd92
+#tb 0: 1000/14587
+0, 0, 0, 1, 174243, 0xa40491e1
+0, 1, 1, 1, 174243, 0xa12cbb56
+0, 2, 2, 1, 174243, 0xa12cbb56
+0, 3, 3, 1, 174243, 0xa12cbb56
+0, 4, 4, 1, 174243, 0xa12cbb56
+0, 5, 5, 1, 174243, 0xa12cbb56
+0, 6, 6, 1, 174243, 0xa12cbb56
+0, 7, 7, 1, 174243, 0xa12cbb56
+0, 8, 8, 1, 174243, 0xa12cbb56
+0, 9, 9, 1, 174243, 0x4e7b7299
+0, 10, 10, 1, 174243, 0x31573b99
+0, 11, 11, 1, 174243, 0x013397b6
+0, 12, 12, 1, 174243, 0xdd988ab8
+0, 13, 13, 1, 174243, 0xd6d96b1e
+0, 14, 14, 1, 174243, 0xd6d96b1e
+0, 15, 15, 1, 174243, 0xd6d96b1e
+0, 16, 16, 1, 174243, 0x111627d3
+0, 17, 17, 1, 174243, 0x284d9ab7
+0, 18, 18, 1, 174243, 0xa348c492
+0, 19, 19, 1, 174243, 0xa348c492
+0, 20, 20, 1, 174243, 0xa348c492
+0, 21, 21, 1, 174243, 0xa348c492
+0, 22, 22, 1, 174243, 0x2d22c3b8
+0, 23, 23, 1, 174243, 0x2d22c3b8
+0, 24, 24, 1, 174243, 0x2d22c3b8
+0, 25, 25, 1, 174243, 0x2d22c3b8
+0, 26, 26, 1, 174243, 0xa6d7c890
+0, 27, 27, 1, 174243, 0x8068bfbb
+0, 28, 28, 1, 174243, 0x420ae647
+0, 29, 29, 1, 174243, 0xc5467756
+0, 30, 30, 1, 174243, 0x238a13dd
+0, 31, 31, 1, 174243, 0x5bab75dc
+0, 32, 32, 1, 174243, 0x14d7f61f
+0, 33, 33, 1, 174243, 0x2e1d334f
+0, 34, 34, 1, 174243, 0xeade7dc0
+0, 35, 35, 1, 174243, 0xeade7dc0
+0, 36, 36, 1, 174243, 0xeade7dc0
+0, 37, 37, 1, 174243, 0xeade7dc0
+0, 38, 38, 1, 174243, 0x088c7ef9
+0, 39, 39, 1, 174243, 0x70a3554e
+0, 40, 40, 1, 174243, 0x0753d1d4
+0, 41, 41, 1, 174243, 0x8266bd6d
+0, 42, 42, 1, 174243, 0x4ce3cda9
+0, 43, 43, 1, 174243, 0x4ce3cda9
+0, 44, 44, 1, 174243, 0x4ce3cda9
+0, 45, 45, 1, 174243, 0x4ce3cda9
+0, 46, 46, 1, 174243, 0xe5f7cd98
+0, 47, 47, 1, 174243, 0xe5f7cd98
+0, 48, 48, 1, 174243, 0xe5f7cd98
+0, 49, 49, 1, 174243, 0xe5f7cd98
+0, 50, 50, 1, 174243, 0x78c5cdb7
+0, 51, 51, 1, 174243, 0x78c5cdb7
+0, 52, 52, 1, 174243, 0x78c5cdb7
+0, 53, 53, 1, 174243, 0xce7ccd92
+0, 54, 54, 1, 174243, 0xce7ccd92
+0, 55, 55, 1, 174243, 0xce7ccd92
+0, 56, 56, 1, 174243, 0xce7ccd92
diff --git a/tests/ref/fate/aliaspix-bgr b/tests/ref/fate/aliaspix-bgr
index 235a5acf69..8671d3ef7b 100644
--- a/tests/ref/fate/aliaspix-bgr
+++ b/tests/ref/fate/aliaspix-bgr
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 36000, 0x9ff1ba55
+0, 0, 0, 1, 47637, 0xcb77368f
diff --git a/tests/ref/fate/aliaspix-gray b/tests/ref/fate/aliaspix-gray
index 74cf6a20bc..0433a36eb6 100644
--- a/tests/ref/fate/aliaspix-gray
+++ b/tests/ref/fate/aliaspix-gray
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 12000, 0x29f8832c
+0, 0, 0, 1, 16119, 0x3d0785f5
diff --git a/tests/ref/fate/ansi256 b/tests/ref/fate/ansi256
new file mode 100644
index 0000000000..94acd45831
--- /dev/null
+++ b/tests/ref/fate/ansi256
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 768000, 0x4dfbb6d0
+0, 1, 1, 1, 768000, 0x22652a22
+0, 2, 2, 1, 768000, 0x6c613e8c
+0, 3, 3, 1, 768000, 0x82471f25
+0, 4, 4, 1, 768000, 0xd8dc5ac6
+0, 5, 5, 1, 768000, 0x1afdc026
+0, 6, 6, 1, 768000, 0x518f3ba1
+0, 7, 7, 1, 768000, 0xa82a8e4b
diff --git a/tests/ref/fate/armovie-escape124 b/tests/ref/fate/armovie-escape124
index c686327c9e..83614c263d 100644
--- a/tests/ref/fate/armovie-escape124
+++ b/tests/ref/fate/armovie-escape124
@@ -1,106 +1,106 @@
#tb 0: 1/25
#tb 1: 1/44100
-0, 0, 0, 1, 230400, 0x5288d70f
+0, 0, 0, 1, 230400, 0xd133e177
1, 0, 0, 44100, 176400, 0xdd61578c
-0, 1, 1, 1, 230400, 0x2d3c1066
-0, 2, 2, 1, 230400, 0x89eb5b4a
-0, 3, 3, 1, 230400, 0x24c2d2e7
-0, 4, 4, 1, 230400, 0x9271cb38
-0, 5, 5, 1, 230400, 0xc74a5009
-0, 6, 6, 1, 230400, 0x61d70705
-0, 7, 7, 1, 230400, 0x6bb2c252
-0, 8, 8, 1, 230400, 0x6b3ac910
-0, 9, 9, 1, 230400, 0x44071f28
-0, 10, 10, 1, 230400, 0x8abd00fe
-0, 11, 11, 1, 230400, 0xcbe3395d
-0, 12, 12, 1, 230400, 0x603e7b7a
-0, 13, 13, 1, 230400, 0x2ca8865b
-0, 14, 14, 1, 230400, 0x11b4c665
-0, 15, 15, 1, 230400, 0x3f19787c
-0, 16, 16, 1, 230400, 0x651d24b6
-0, 17, 17, 1, 230400, 0x325d05af
-0, 18, 18, 1, 230400, 0x4f89d8a8
-0, 19, 19, 1, 230400, 0xb07647f0
-0, 20, 20, 1, 230400, 0x71141237
-0, 21, 21, 1, 230400, 0xa848a2d2
-0, 22, 22, 1, 230400, 0x3fbe4b58
-0, 23, 23, 1, 230400, 0xa1e235a0
-0, 24, 24, 1, 230400, 0x9bcf607a
-0, 25, 25, 1, 230400, 0x3302e9eb
+0, 1, 1, 1, 230400, 0xe3501bb2
+0, 2, 2, 1, 230400, 0x44da84f0
+0, 3, 3, 1, 230400, 0xe0fd17ed
+0, 4, 4, 1, 230400, 0xef4e08c7
+0, 5, 5, 1, 230400, 0xf52f82b5
+0, 6, 6, 1, 230400, 0x05eb186c
+0, 7, 7, 1, 230400, 0x0653f05d
+0, 8, 8, 1, 230400, 0xde1a0735
+0, 9, 9, 1, 230400, 0x6045576e
+0, 10, 10, 1, 230400, 0xac9444c4
+0, 11, 11, 1, 230400, 0x5f7f82fb
+0, 12, 12, 1, 230400, 0xaf4718ce
+0, 13, 13, 1, 230400, 0x117d5787
+0, 14, 14, 1, 230400, 0x319ac1f5
+0, 15, 15, 1, 230400, 0xd05cb30a
+0, 16, 16, 1, 230400, 0x96107c72
+0, 17, 17, 1, 230400, 0x73ff0a30
+0, 18, 18, 1, 230400, 0x865d0f3e
+0, 19, 19, 1, 230400, 0x3384ad55
+0, 20, 20, 1, 230400, 0x6694b2ea
+0, 21, 21, 1, 230400, 0x324f5cb8
+0, 22, 22, 1, 230400, 0x2de7c12f
+0, 23, 23, 1, 230400, 0x57fedb1a
+0, 24, 24, 1, 230400, 0xf46f2abf
+0, 25, 25, 1, 230400, 0xe5fead9b
1, 44100, 44100, 44100, 176400, 0x0b9e6d67
-0, 26, 26, 1, 230400, 0xd731ba90
-0, 27, 27, 1, 230400, 0x821eedcf
-0, 28, 28, 1, 230400, 0xd068a93d
-0, 29, 29, 1, 230400, 0x2811d46e
-0, 30, 30, 1, 230400, 0xd9740446
-0, 31, 31, 1, 230400, 0x1bce0df6
-0, 32, 32, 1, 230400, 0x44bc60ad
-0, 33, 33, 1, 230400, 0xf56f6200
-0, 34, 34, 1, 230400, 0x874a2264
-0, 35, 35, 1, 230400, 0xaa155c0e
-0, 36, 36, 1, 230400, 0x595392d4
-0, 37, 37, 1, 230400, 0x58dc57de
-0, 38, 38, 1, 230400, 0x1c06733e
-0, 39, 39, 1, 230400, 0x6807b1db
-0, 40, 40, 1, 230400, 0x3fedff87
-0, 41, 41, 1, 230400, 0x3e38cc13
-0, 42, 42, 1, 230400, 0x6685ec35
-0, 43, 43, 1, 230400, 0x6c0742fd
-0, 44, 44, 1, 230400, 0x8108f83c
-0, 45, 45, 1, 230400, 0xc0e217c8
-0, 46, 46, 1, 230400, 0xb22ca65d
-0, 47, 47, 1, 230400, 0xd54cec93
-0, 48, 48, 1, 230400, 0xd9d61de3
-0, 49, 49, 1, 230400, 0x7e0f9675
-0, 50, 50, 1, 230400, 0x9869f5b7
+0, 26, 26, 1, 230400, 0x65764edb
+0, 27, 27, 1, 230400, 0xeabdcf53
+0, 28, 28, 1, 230400, 0xaeb659fc
+0, 29, 29, 1, 230400, 0x5ec97eb1
+0, 30, 30, 1, 230400, 0x2482abae
+0, 31, 31, 1, 230400, 0x297fb0c8
+0, 32, 32, 1, 230400, 0x57a52a3d
+0, 33, 33, 1, 230400, 0x44040e98
+0, 34, 34, 1, 230400, 0xa150e542
+0, 35, 35, 1, 230400, 0x0a1e1296
+0, 36, 36, 1, 230400, 0xf1085864
+0, 37, 37, 1, 230400, 0xe7a13b40
+0, 38, 38, 1, 230400, 0x759d384d
+0, 39, 39, 1, 230400, 0x72e08991
+0, 40, 40, 1, 230400, 0x10a4bbc9
+0, 41, 41, 1, 230400, 0xb258ac16
+0, 42, 42, 1, 230400, 0xde06facb
+0, 43, 43, 1, 230400, 0x94284e11
+0, 44, 44, 1, 230400, 0xedf23092
+0, 45, 45, 1, 230400, 0xc2be6319
+0, 46, 46, 1, 230400, 0x103a0b7b
+0, 47, 47, 1, 230400, 0x3415888b
+0, 48, 48, 1, 230400, 0x5ecaac75
+0, 49, 49, 1, 230400, 0xb9ba503e
+0, 50, 50, 1, 230400, 0xb20ccf57
1, 88200, 88200, 44100, 176400, 0x2793fad7
-0, 51, 51, 1, 230400, 0x22f33400
-0, 52, 52, 1, 230400, 0x31b999bd
-0, 53, 53, 1, 230400, 0x36c23878
-0, 54, 54, 1, 230400, 0x06093a30
-0, 55, 55, 1, 230400, 0x213f1718
-0, 56, 56, 1, 230400, 0x83683006
-0, 57, 57, 1, 230400, 0x0bfcec36
-0, 58, 58, 1, 230400, 0x01b77825
-0, 59, 59, 1, 230400, 0x650a5ea2
-0, 60, 60, 1, 230400, 0xd8b2c559
-0, 61, 61, 1, 230400, 0xb012eb10
-0, 62, 62, 1, 230400, 0x135d53a4
-0, 63, 63, 1, 230400, 0x98dd0712
-0, 64, 64, 1, 230400, 0x75240ac0
-0, 65, 65, 1, 230400, 0xa16769d5
-0, 66, 66, 1, 230400, 0x3e08cda3
-0, 67, 67, 1, 230400, 0xcd20d561
-0, 68, 68, 1, 230400, 0x3531577d
-0, 69, 69, 1, 230400, 0x65ff4c82
-0, 70, 70, 1, 230400, 0x8fd4a580
-0, 71, 71, 1, 230400, 0x3cf7af4c
-0, 72, 72, 1, 230400, 0xda7a9202
-0, 73, 73, 1, 230400, 0x4bebc138
-0, 74, 74, 1, 230400, 0x5517e685
-0, 75, 75, 1, 230400, 0x95f6c7a3
+0, 51, 51, 1, 230400, 0x0dba31ed
+0, 52, 52, 1, 230400, 0x91c5e7d4
+0, 53, 53, 1, 230400, 0x09ac954b
+0, 54, 54, 1, 230400, 0xe9c3d563
+0, 55, 55, 1, 230400, 0xf46eef67
+0, 56, 56, 1, 230400, 0x117f4b80
+0, 57, 57, 1, 230400, 0x61714860
+0, 58, 58, 1, 230400, 0x5c7112d0
+0, 59, 59, 1, 230400, 0xd42c51e7
+0, 60, 60, 1, 230400, 0x425f0c99
+0, 61, 61, 1, 230400, 0x4c398834
+0, 62, 62, 1, 230400, 0x237f89c2
+0, 63, 63, 1, 230400, 0xd2e29b05
+0, 64, 64, 1, 230400, 0x204a054b
+0, 65, 65, 1, 230400, 0x25a9faf7
+0, 66, 66, 1, 230400, 0x83f6c1a8
+0, 67, 67, 1, 230400, 0xe48321b9
+0, 68, 68, 1, 230400, 0x714c1005
+0, 69, 69, 1, 230400, 0x36cc58e9
+0, 70, 70, 1, 230400, 0x5e9ffdd9
+0, 71, 71, 1, 230400, 0x582b55dc
+0, 72, 72, 1, 230400, 0x139a7f39
+0, 73, 73, 1, 230400, 0xefb5f998
+0, 74, 74, 1, 230400, 0xeb736da8
+0, 75, 75, 1, 230400, 0x488f9847
1, 132300, 132300, 44100, 176400, 0xe2649a4a
-0, 76, 76, 1, 230400, 0x9849ebf9
-0, 77, 77, 1, 230400, 0xd77e1c7d
-0, 78, 78, 1, 230400, 0x4dc6c923
-0, 79, 79, 1, 230400, 0x7ce817c8
-0, 80, 80, 1, 230400, 0xafb4acde
-0, 81, 81, 1, 230400, 0xd0030b2c
-0, 82, 82, 1, 230400, 0xb3acb77c
-0, 83, 83, 1, 230400, 0x4d32b61c
-0, 84, 84, 1, 230400, 0x2436a915
-0, 85, 85, 1, 230400, 0xa6fd831f
-0, 86, 86, 1, 230400, 0x6c6edfca
-0, 87, 87, 1, 230400, 0x4b30d72e
-0, 88, 88, 1, 230400, 0x59f46a8a
-0, 89, 89, 1, 230400, 0xa2d0435f
-0, 90, 90, 1, 230400, 0x463872c4
-0, 91, 91, 1, 230400, 0x1d7e870a
-0, 92, 92, 1, 230400, 0x74f4e530
-0, 93, 93, 1, 230400, 0xbc61053d
-0, 94, 94, 1, 230400, 0x5fb238dc
-0, 95, 95, 1, 230400, 0x14a29d83
-0, 96, 96, 1, 230400, 0x3fd1d09b
-0, 97, 97, 1, 230400, 0x098afc13
-0, 98, 98, 1, 230400, 0x9bd12a62
-0, 99, 99, 1, 230400, 0x7bf71419
+0, 76, 76, 1, 230400, 0x6ab20741
+0, 77, 77, 1, 230400, 0xa73686f0
+0, 78, 78, 1, 230400, 0x67878643
+0, 79, 79, 1, 230400, 0x83bb241b
+0, 80, 80, 1, 230400, 0xe6b70660
+0, 81, 81, 1, 230400, 0x87f5aca3
+0, 82, 82, 1, 230400, 0x29c79bc3
+0, 83, 83, 1, 230400, 0xcadbd70b
+0, 84, 84, 1, 230400, 0x8cdcfdee
+0, 85, 85, 1, 230400, 0x90aa0442
+0, 86, 86, 1, 230400, 0xa68e87b7
+0, 87, 87, 1, 230400, 0xa2c49e58
+0, 88, 88, 1, 230400, 0x9a9a4c55
+0, 89, 89, 1, 230400, 0x06b53aed
+0, 90, 90, 1, 230400, 0x79e1808a
+0, 91, 91, 1, 230400, 0x3e53a411
+0, 92, 92, 1, 230400, 0xfebc13ca
+0, 93, 93, 1, 230400, 0x1f1f443b
+0, 94, 94, 1, 230400, 0xd0db806a
+0, 95, 95, 1, 230400, 0x6f2aee94
+0, 96, 96, 1, 230400, 0xe8cc23ba
+0, 97, 97, 1, 230400, 0x2edf510b
+0, 98, 98, 1, 230400, 0x87118129
+0, 99, 99, 1, 230400, 0x1dd1709a
diff --git a/tests/ref/fate/ast b/tests/ref/fate/ast
new file mode 100644
index 0000000000..5b89c2b1ef
--- /dev/null
+++ b/tests/ref/fate/ast
@@ -0,0 +1 @@
+CRC=0x87713611
diff --git a/tests/ref/fate/avio-direct b/tests/ref/fate/avio-direct
new file mode 100644
index 0000000000..599683a8a3
--- /dev/null
+++ b/tests/ref/fate/avio-direct
@@ -0,0 +1,59 @@
+#tb 0: 1/30
+0, 0, 0, 1, 145152, 0x8458d4cb
+0, 1, 1, 1, 145152, 0xa694d7c7
+0, 2, 2, 1, 145152, 0x2bd4bfc9
+0, 3, 3, 1, 145152, 0xe53b1616
+0, 4, 4, 1, 145152, 0x6a0a806a
+0, 5, 5, 1, 145152, 0x45f7b8e6
+0, 6, 6, 1, 145152, 0x4e14150e
+0, 7, 7, 1, 145152, 0xe1cd9b6f
+0, 8, 8, 1, 145152, 0x5b5802d7
+0, 9, 9, 1, 145152, 0xb03da5e7
+0, 10, 10, 1, 145152, 0x3436b06e
+0, 11, 11, 1, 145152, 0x4535e638
+0, 12, 12, 1, 145152, 0x72934af1
+0, 13, 13, 1, 145152, 0xb672d459
+0, 14, 14, 1, 145152, 0xab57491b
+0, 15, 15, 1, 145152, 0xdbac3480
+0, 16, 16, 1, 145152, 0x54215962
+0, 17, 17, 1, 145152, 0x451f456e
+0, 18, 18, 1, 145152, 0xa17655d1
+0, 19, 19, 1, 145152, 0xce95422c
+0, 20, 20, 1, 145152, 0xe0ee8e77
+0, 21, 21, 1, 145152, 0xdaabe277
+0, 22, 22, 1, 145152, 0xc21bb665
+0, 23, 23, 1, 145152, 0x1e74270e
+0, 24, 24, 1, 145152, 0xae7bac5f
+0, 25, 25, 1, 145152, 0xf62442ed
+0, 26, 26, 1, 145152, 0x5c8d8984
+0, 27, 27, 1, 145152, 0x97a69fe7
+0, 28, 28, 1, 145152, 0x1f244d19
+0, 29, 29, 1, 145152, 0x2758bc25
+0, 30, 30, 1, 145152, 0xf43ddb89
+0, 31, 31, 1, 145152, 0x086a524e
+0, 32, 32, 1, 145152, 0x8b464d4d
+0, 33, 33, 1, 145152, 0xb77b63d2
+0, 34, 34, 1, 145152, 0xfd842fa8
+0, 35, 35, 1, 145152, 0xa98b6dbe
+0, 36, 36, 1, 145152, 0xdedbab2c
+0, 37, 37, 1, 145152, 0x24e19172
+0, 38, 38, 1, 145152, 0x1ef456f6
+0, 39, 39, 1, 145152, 0xaceabdf0
+0, 40, 40, 1, 145152, 0xb54de3d9
+0, 41, 41, 1, 145152, 0x3af0df9b
+0, 42, 42, 1, 145152, 0xf89fbd9a
+0, 43, 43, 1, 145152, 0xc6a9673c
+0, 44, 44, 1, 145152, 0x6d5a929e
+0, 45, 45, 1, 145152, 0x879e7d9b
+0, 46, 46, 1, 145152, 0x233c14eb
+0, 47, 47, 1, 145152, 0x8246f081
+0, 48, 48, 1, 145152, 0x3366c4bf
+0, 49, 49, 1, 145152, 0x6b0203da
+0, 50, 50, 1, 145152, 0x48a00163
+0, 51, 51, 1, 145152, 0xe956ac2c
+0, 52, 52, 1, 145152, 0xa2511283
+0, 53, 53, 1, 145152, 0x7e03222d
+0, 54, 54, 1, 145152, 0xc31a7a40
+0, 55, 55, 1, 145152, 0x80448031
+0, 56, 56, 1, 145152, 0xe3b1fbf7
+0, 57, 57, 1, 145152, 0xa00395a4
diff --git a/tests/ref/fate/avstring b/tests/ref/fate/avstring
index bc231e8148..1ca9be52ed 100644
--- a/tests/ref/fate/avstring
+++ b/tests/ref/fate/avstring
@@ -25,3 +25,12 @@ Testing av_get_token()
|'foo : \ \ ' : blahblah| -> |foo : \ \ | + |: blahblah|
|'\fo\o:': blahblah| -> |\fo\o:| + |: blahblah|
|\'fo\o\:': foo ' :blahblah| -> |'foo:: foo | + |:blahblah|
+Testing av_append_path_component()
+(null) = (null)
+path = path
+comp = comp
+path/comp = path/comp
+path/comp = path/comp
+path/comp = path/comp
+path/comp = path/comp
+path/path2/comp/comp2 = path/path2/comp/comp2
diff --git a/tests/ref/fate/bethsoft-vid b/tests/ref/fate/bethsoft-vid
index 535888b69e..9f96da1e87 100644
--- a/tests/ref/fate/bethsoft-vid
+++ b/tests/ref/fate/bethsoft-vid
@@ -1,143 +1,143 @@
-#tb 0: 185/11111
+#tb 0: 1/14
#tb 1: 1/11111
0, 0, 0, 1, 192000, 0x00000000
1, 0, 0, 740, 1480, 0x00000000
-0, 4, 4, 1, 192000, 0x01a6cf45
1, 740, 740, 740, 1480, 0x20a92bd4
-0, 8, 8, 1, 192000, 0xd07d57e9
+0, 1, 1, 1, 192000, 0x5a5acf57
1, 1480, 1480, 925, 1850, 0xa9e48a74
-0, 13, 13, 1, 192000, 0x3cb1dff5
+0, 2, 2, 1, 192000, 0xbd055cf1
+0, 3, 3, 1, 192000, 0x28b1eefc
1, 2405, 2405, 740, 1480, 0x23ecd018
-0, 17, 17, 1, 192000, 0xd1aaa8fb
1, 3145, 3145, 740, 1480, 0x206bb915
-0, 21, 21, 1, 192000, 0x75f526cd
+0, 4, 4, 1, 192000, 0x0636bacd
1, 3885, 3885, 925, 1850, 0xb0e10e75
-0, 26, 26, 1, 192000, 0x0f673577
+0, 5, 5, 1, 192000, 0xbfd33cbd
+0, 6, 6, 1, 192000, 0x0bd150ef
1, 4810, 4810, 740, 1480, 0x8d9baedd
-0, 30, 30, 1, 192000, 0x897b6781
1, 5550, 5550, 740, 1480, 0xb802aae1
-0, 34, 34, 1, 192000, 0x81e6b7f7
+0, 7, 7, 1, 192000, 0x780d891e
1, 6290, 6290, 740, 1480, 0xecd7b5cc
-0, 38, 38, 1, 192000, 0x1f45ce61
+0, 8, 8, 1, 192000, 0xacf5e205
1, 7030, 7030, 925, 1850, 0x16861355
-0, 43, 43, 1, 192000, 0x5a0772a6
+0, 9, 9, 1, 192000, 0x37c900dc
+0, 10, 10, 1, 192000, 0x4ee6add7
1, 7955, 7955, 740, 1480, 0xa51690bd
-0, 47, 47, 1, 192000, 0xf78732b3
1, 8695, 8695, 740, 1480, 0xdd0b90d1
-0, 51, 51, 1, 192000, 0x8427f9e5
+0, 11, 11, 1, 192000, 0x1844783a
1, 9435, 9435, 925, 1850, 0x3ce6e333
-0, 56, 56, 1, 192000, 0x40473f11
+0, 12, 12, 1, 192000, 0x7bf84848
+0, 13, 13, 1, 192000, 0x1ec296bc
1, 10360, 10360, 740, 1480, 0xf8ce8ea3
-0, 60, 60, 1, 192000, 0x173ceebe
1, 11100, 11100, 740, 1480, 0xda4597af
-0, 64, 64, 1, 192000, 0x136b9516
+0, 14, 14, 1, 192000, 0xbaeb5292
1, 11840, 11840, 740, 1480, 0x918f7cb3
-0, 68, 68, 1, 192000, 0x138d11ae
+0, 15, 15, 1, 192000, 0xcb18038d
1, 12580, 12580, 925, 1850, 0xca6edb15
-0, 73, 73, 1, 192000, 0x063dbff3
+0, 16, 16, 1, 192000, 0xb3cc8b65
+0, 17, 17, 1, 192000, 0x6f164685
1, 13505, 13505, 740, 1480, 0xba279597
-0, 77, 77, 1, 192000, 0x5280852f
1, 14245, 14245, 740, 1480, 0xc5a38a9e
-0, 81, 81, 1, 192000, 0x99943a8f
+0, 18, 18, 1, 192000, 0x304917c9
1, 14985, 14985, 925, 1850, 0x8147eef5
-0, 86, 86, 1, 192000, 0x0330a728
+0, 19, 19, 1, 192000, 0x8269daa1
+0, 20, 20, 1, 192000, 0x04d3500d
1, 15910, 15910, 740, 1480, 0xce2c7cb5
-0, 90, 90, 1, 192000, 0x5d35467d
1, 16650, 16650, 740, 1480, 0x4282819f
-0, 94, 94, 1, 192000, 0xfd436343
+0, 21, 21, 1, 192000, 0x9788f7a5
1, 17390, 17390, 740, 1480, 0xbdbb8da6
-0, 98, 98, 1, 192000, 0xc323fcfe
+0, 22, 22, 1, 192000, 0x05351c98
1, 18130, 18130, 925, 1850, 0xdbbeea10
-0, 103, 103, 1, 192000, 0x2a1530a0
+0, 23, 23, 1, 192000, 0xcc8bba97
+0, 24, 24, 1, 192000, 0x76caf27b
1, 19055, 19055, 740, 1480, 0xbe6a77c2
-0, 107, 107, 1, 192000, 0xbd43bb60
1, 19795, 19795, 740, 1480, 0xa85c75b2
-0, 111, 111, 1, 192000, 0xa47f5eab
+0, 25, 25, 1, 192000, 0x28648040
1, 20535, 20535, 925, 1850, 0xa45bde21
-0, 116, 116, 1, 192000, 0xff17f5f7
+0, 26, 26, 1, 192000, 0x99ea251f
+0, 27, 27, 1, 192000, 0x20e7bf4d
1, 21460, 21460, 740, 1480, 0x84aa7895
-0, 120, 120, 1, 192000, 0xb4140b55
1, 22200, 22200, 740, 1480, 0x147f7d9f
-0, 124, 124, 1, 192000, 0xb8782cc4
+0, 28, 28, 1, 192000, 0x046ed625
1, 22940, 22940, 740, 1480, 0xc8e77b85
-0, 128, 128, 1, 192000, 0x92975b8b
+0, 29, 29, 1, 192000, 0x1613fb12
1, 23680, 23680, 925, 1850, 0x10d4d81b
-0, 133, 133, 1, 192000, 0xf42a64d6
+0, 30, 30, 1, 192000, 0xd8b52d16
+0, 31, 31, 1, 192000, 0x31443aa9
1, 24605, 24605, 740, 1480, 0xb4ae8bb1
-0, 137, 137, 1, 192000, 0x2cc7077d
1, 25345, 25345, 740, 1480, 0x3ef782a5
-0, 141, 141, 1, 192000, 0x00080cc8
+0, 32, 32, 1, 192000, 0xd426de3d
1, 26085, 26085, 925, 1850, 0xdeebda14
-0, 146, 146, 1, 192000, 0x584b48f3
+0, 33, 33, 1, 192000, 0xb2bce77b
+0, 34, 34, 1, 192000, 0x25a52805
1, 27010, 27010, 740, 1480, 0x4c7e7bbb
-0, 150, 150, 1, 192000, 0xd68f57da
1, 27750, 27750, 740, 1480, 0x0e0e9198
-0, 154, 154, 1, 192000, 0x60158422
+0, 35, 35, 1, 192000, 0x04f03a87
1, 28490, 28490, 740, 1480, 0x5c1f819f
-0, 158, 158, 1, 192000, 0xd7fb89e6
+0, 36, 36, 1, 192000, 0x41d56889
1, 29230, 29230, 925, 1850, 0x0e4cf6ff
-0, 163, 163, 1, 192000, 0x97f1c76a
+0, 37, 37, 1, 192000, 0x3d4d6de9
1, 30155, 30155, 740, 1480, 0x374388a7
-0, 167, 167, 1, 192000, 0x46c4bb9e
+0, 38, 38, 1, 192000, 0xa7a2abfe
1, 30895, 30895, 740, 1480, 0xed729389
-0, 171, 171, 1, 192000, 0xd32f9b66
+0, 39, 39, 1, 192000, 0x663e9fca
1, 31635, 31635, 925, 1850, 0xe0f1e43f
-0, 176, 176, 1, 192000, 0x74f43886
+0, 40, 40, 1, 192000, 0x29a67f86
+0, 41, 41, 1, 192000, 0x51531bb0
1, 32560, 32560, 740, 1480, 0x3b27839a
-0, 180, 180, 1, 192000, 0x3c4e47df
1, 33300, 33300, 740, 1480, 0xe6287e94
-0, 184, 184, 1, 192000, 0xb5ac0a58
+0, 42, 42, 1, 192000, 0xd993277e
1, 34040, 34040, 740, 1480, 0x7e0d84b5
-0, 188, 188, 1, 192000, 0xcc572b31
+0, 43, 43, 1, 192000, 0x4873e583
1, 34780, 34780, 925, 1850, 0xf08bebf7
-0, 193, 193, 1, 192000, 0xb1739d26
+0, 44, 44, 1, 192000, 0x06df053b
1, 35705, 35705, 740, 1480, 0x94cf73a0
-0, 197, 197, 1, 192000, 0x73da5473
+0, 45, 45, 1, 192000, 0x044f7698
1, 36445, 36445, 740, 1480, 0xfef384ae
-0, 201, 201, 1, 192000, 0x5f79f5bc
+0, 46, 46, 1, 192000, 0xc2302a45
1, 37185, 37185, 925, 1850, 0x3b93e0f7
-0, 206, 206, 1, 192000, 0x0affc0a0
+0, 47, 47, 1, 192000, 0xbdfec8ee
+0, 48, 48, 1, 192000, 0x3b739286
1, 38110, 38110, 740, 1480, 0x28d27bae
-0, 210, 210, 1, 192000, 0x2b4d5c1c
1, 38850, 38850, 740, 1480, 0x94d57da5
-0, 214, 214, 1, 192000, 0x309b41bc
+0, 49, 49, 1, 192000, 0x3ca82cd6
1, 39590, 39590, 740, 1480, 0xc9327db5
-0, 218, 218, 1, 192000, 0xd42b6424
+0, 50, 50, 1, 192000, 0x25af10f2
1, 40330, 40330, 925, 1850, 0xe781f604
-0, 223, 223, 1, 192000, 0x4795c948
+0, 51, 51, 1, 192000, 0x09ce32bf
1, 41255, 41255, 740, 1480, 0x752f8c5b
-0, 227, 227, 1, 192000, 0xbc1a3a8b
+0, 52, 52, 1, 192000, 0xdab399c2
1, 41995, 41995, 740, 1480, 0x30068032
-0, 231, 231, 1, 192000, 0x16529c5b
+0, 53, 53, 1, 192000, 0x77400d93
1, 42735, 42735, 925, 1850, 0x7895023e
-0, 236, 236, 1, 192000, 0x6b1b31ba
+0, 54, 54, 1, 192000, 0x5e8e6fe7
+0, 55, 55, 1, 192000, 0x277506c9
1, 43660, 43660, 740, 1480, 0xa1e0a6e1
-0, 240, 240, 1, 192000, 0x569182ce
1, 44400, 44400, 740, 1480, 0x6af4b500
-0, 244, 244, 1, 192000, 0xe6ea9866
+0, 56, 56, 1, 192000, 0xe91b59ac
1, 45140, 45140, 740, 1480, 0xc26ea4c7
-0, 248, 248, 1, 192000, 0x102c6076
+0, 57, 57, 1, 192000, 0xc2aa6e19
1, 45880, 45880, 925, 1850, 0x16a72419
-0, 253, 253, 1, 192000, 0xb29f527a
+0, 58, 58, 1, 192000, 0x12c63645
1, 46805, 46805, 740, 1480, 0x1794aacc
-0, 257, 257, 1, 192000, 0x040b4eee
+0, 59, 59, 1, 192000, 0xa39f27d6
1, 47545, 47545, 740, 1480, 0x2ecad8d0
-0, 261, 261, 1, 192000, 0x92574f4a
+0, 60, 60, 1, 192000, 0x20c32512
1, 48285, 48285, 925, 1850, 0x2e645e07
-0, 266, 266, 1, 192000, 0x1e8acdce
+0, 61, 61, 1, 192000, 0x385a26a0
+0, 62, 62, 1, 192000, 0x2566a70c
1, 49210, 49210, 740, 1480, 0x1c54dfe7
-0, 270, 270, 1, 192000, 0x1becf516
1, 49950, 49950, 740, 1480, 0xbd35feec
-0, 274, 274, 1, 192000, 0xb62e9776
+0, 63, 63, 1, 192000, 0x7105cfb9
1, 50690, 50690, 740, 1480, 0x419403d6
-0, 278, 278, 1, 192000, 0xed37a08e
+0, 64, 64, 1, 192000, 0x725671a2
1, 51430, 51430, 925, 1850, 0x78699d2a
-0, 283, 283, 1, 192000, 0xc0719912
+0, 65, 65, 1, 192000, 0x3ff2782a
1, 52355, 52355, 740, 1480, 0x74ec68e0
-0, 287, 287, 1, 192000, 0x24cf7a7e
+0, 66, 66, 1, 192000, 0xdc0571c3
1, 53095, 53095, 740, 1480, 0x76af64d9
-0, 291, 291, 1, 192000, 0x0307f62f
+0, 67, 67, 1, 192000, 0x4a6a5405
1, 53835, 53835, 925, 1850, 0x5a303d1a
-0, 296, 296, 1, 192000, 0x79b7417b
+0, 68, 68, 1, 192000, 0x3ec3cce1
1, 54760, 54760, 537, 1074, 0x142ce7ba
+0, 69, 69, 1, 192000, 0x159313a8
1, 55297, 55297, 258, 516, 0x98885b26
diff --git a/tests/ref/fate/binsub-movtextenc b/tests/ref/fate/binsub-movtextenc
new file mode 100644
index 0000000000..6efe2c015a
--- /dev/null
+++ b/tests/ref/fate/binsub-movtextenc
@@ -0,0 +1 @@
+ef264064c522389d0cf267c4d6235561
diff --git a/tests/ref/fate/bmpparser b/tests/ref/fate/bmpparser
index e7022b1cab..3cdd9864af 100644
--- a/tests/ref/fate/bmpparser
+++ b/tests/ref/fate/bmpparser
@@ -1,5 +1,5 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0x47c3e3a0
-0, 1, 1, 1, 203280, 0x6494c4db
-0, 2, 2, 1, 203280, 0x042fe3a0
-0, 3, 3, 1, 203280, 0xba9be3a0
+0, 0, 0, 1, 3600, 0xd3a7c583
+0, 1, 1, 1, 3600, 0x4602bbf9
+0, 2, 2, 1, 3600, 0x3a96b8f8
+0, 3, 3, 1, 3600, 0xb343b17f
diff --git a/tests/ref/fate/bprint b/tests/ref/fate/bprint
new file mode 100644
index 0000000000..b33c1ae6e7
--- /dev/null
+++ b/tests/ref/fate/bprint
@@ -0,0 +1,16 @@
+Short text in unlimited buffer: 174/174
+ 1
+ 1 1
+ 1 2 1
+ 1 3 3 1
+ 1 4 6 4 1
+ 1 5 10 10 5 1
+
+Long text in unlimited buffer: 2834/2834
+Long text in limited buffer: 2047/2834
+Short text in automatic buffer: 174/174
+Long text in automatic buffer: 1000/2834
+Long text count only buffer: 0/2834
+Long text count only buffer: 255/2834
+strftime full: 255/10 "2000-12-20"
+strftime truncated: 255/10 "2000-12"
diff --git a/tests/ref/fate/brstm b/tests/ref/fate/brstm
new file mode 100644
index 0000000000..d183b3f46a
--- /dev/null
+++ b/tests/ref/fate/brstm
@@ -0,0 +1 @@
+CRC=0x1feb92a8
diff --git a/tests/ref/fate/cavs b/tests/ref/fate/cavs
index c96468a27b..87cf9ca83c 100644
--- a/tests/ref/fate/cavs
+++ b/tests/ref/fate/cavs
@@ -1,171 +1,172 @@
-#tb 0: 1/90000
-0, 0, 0, 0, 622080, 0x76183b91
-0, 3624, 3624, 0, 622080, 0x2ca5e808
-0, 7248, 7248, 0, 622080, 0xc503eda4
-0, 10872, 10872, 0, 622080, 0xa0dbf06c
-0, 14496, 14496, 0, 622080, 0xf4363cfa
-0, 18120, 18120, 0, 622080, 0xaa7dd9b8
-0, 21744, 21744, 0, 622080, 0x3ab6223b
-0, 25368, 25368, 0, 622080, 0xe402644b
-0, 28992, 28992, 0, 622080, 0xd0da3ade
-0, 32616, 32616, 0, 622080, 0x0aff6151
-0, 36240, 36240, 0, 622080, 0x02aea3d5
-0, 39864, 39864, 0, 622080, 0x5d8eeccd
-0, 43488, 43488, 0, 622080, 0x54384735
-0, 47112, 47112, 0, 622080, 0x890d71c2
-0, 50736, 50736, 0, 622080, 0xc60ae25b
-0, 54360, 54360, 0, 622080, 0xe589e774
-0, 57984, 57984, 0, 622080, 0x03471e74
-0, 61608, 61608, 0, 622080, 0x4e22302c
-0, 65232, 65232, 0, 622080, 0x00333583
-0, 68856, 68856, 0, 622080, 0xd6eae7d9
-0, 72480, 72480, 0, 622080, 0x72fe94f7
-0, 76104, 76104, 0, 622080, 0x3ebbad1e
-0, 79728, 79728, 0, 622080, 0x2fb1de4b
-0, 83352, 83352, 0, 622080, 0x3bfea6d2
-0, 86976, 86976, 0, 622080, 0x0fb551b2
-0, 90600, 90600, 0, 622080, 0xb203284f
-0, 94224, 94224, 0, 622080, 0xb3baac30
-0, 97200, 97200, 0, 622080, 0x15f2c1c7
-0, 100824, 100824, 0, 622080, 0xb2b530ce
-0, 104448, 104448, 0, 622080, 0xbbaaf241
-0, 108072, 108072, 0, 622080, 0x01bc9dfc
-0, 111696, 111696, 0, 622080, 0x8a449a42
-0, 115320, 115320, 0, 622080, 0xdc63d73f
-0, 118944, 118944, 0, 622080, 0xf06bc231
-0, 122568, 122568, 0, 622080, 0x19e04295
-0, 126192, 126192, 0, 622080, 0x1e7d1acd
-0, 129816, 129816, 0, 622080, 0x43878b48
-0, 133440, 133440, 0, 622080, 0xcd94b702
-0, 137064, 137064, 0, 622080, 0xd2706cf1
-0, 140688, 140688, 0, 622080, 0x47d636f3
-0, 144312, 144312, 0, 622080, 0x4a516acc
-0, 147936, 147936, 0, 622080, 0x52b7d89a
-0, 151560, 151560, 0, 622080, 0xc9ba03be
-0, 155184, 155184, 0, 622080, 0x6d17785e
-0, 158808, 158808, 0, 622080, 0x8264871b
-0, 162432, 162432, 0, 622080, 0xd59c84c0
-0, 166056, 166056, 0, 622080, 0x2b86d6cd
-0, 169680, 169680, 0, 622080, 0x9c5a5f51
-0, 173304, 173304, 0, 622080, 0x221f79ca
-0, 176928, 176928, 0, 622080, 0x98edb3ec
-0, 180552, 180552, 0, 622080, 0x9a31262c
-0, 184176, 184176, 0, 622080, 0x18f48378
-0, 187800, 187800, 0, 622080, 0x957c3d9c
-0, 191424, 191424, 0, 622080, 0x9cc6866e
-0, 195048, 195048, 0, 622080, 0x45613726
-0, 198672, 198672, 0, 622080, 0x7a6c5e65
-0, 202296, 202296, 0, 622080, 0x976d7a11
-0, 205200, 205200, 0, 622080, 0x192aea08
-0, 208824, 208824, 0, 622080, 0x8d4fc823
-0, 212448, 212448, 0, 622080, 0x1f9c55d7
-0, 216072, 216072, 0, 622080, 0xd4336d41
-0, 219696, 219696, 0, 622080, 0x7aa650cd
-0, 223320, 223320, 0, 622080, 0x8efaaeb1
-0, 226944, 226944, 0, 622080, 0x3d8c3053
-0, 230568, 230568, 0, 622080, 0x1e2b64b0
-0, 234192, 234192, 0, 622080, 0x0436b1a7
-0, 237816, 237816, 0, 622080, 0xc5120072
-0, 241440, 241440, 0, 622080, 0x0203b245
-0, 245064, 245064, 0, 622080, 0x9815582b
-0, 248688, 248688, 0, 622080, 0x3c60c359
-0, 252312, 252312, 0, 622080, 0x1a26b948
-0, 255936, 255936, 0, 622080, 0x56079812
-0, 259560, 259560, 0, 622080, 0x7b192a55
-0, 263184, 263184, 0, 622080, 0x335632ab
-0, 266808, 266808, 0, 622080, 0xd0c12eb8
-0, 270432, 270432, 0, 622080, 0x93bf46cb
-0, 274056, 274056, 0, 622080, 0xce67ce24
-0, 277680, 277680, 0, 622080, 0xff95bb26
-0, 281304, 281304, 0, 622080, 0x5e750705
-0, 284928, 284928, 0, 622080, 0x45a35725
-0, 288552, 288552, 0, 622080, 0xd8e93c39
-0, 292176, 292176, 0, 622080, 0xa9f8db50
-0, 295800, 295800, 0, 622080, 0xf90a862e
-0, 299424, 299424, 0, 622080, 0x5e5a4216
-0, 303048, 303048, 0, 622080, 0xaaf45ed6
-0, 306672, 306672, 0, 622080, 0x1933cda5
-0, 310296, 310296, 0, 622080, 0x7ff68d91
-0, 313200, 313200, 0, 622080, 0x10038fe9
-0, 316824, 316824, 0, 622080, 0x9b3425a6
-0, 320448, 320448, 0, 622080, 0x8d2a141d
-0, 324072, 324072, 0, 622080, 0x698a333e
-0, 327696, 327696, 0, 622080, 0x334685d1
-0, 331320, 331320, 0, 622080, 0x40317d40
-0, 334944, 334944, 0, 622080, 0xd3c6f519
-0, 338568, 338568, 0, 622080, 0xfc2210c2
-0, 342192, 342192, 0, 622080, 0x3761df34
-0, 345816, 345816, 0, 622080, 0xef25462a
-0, 349440, 349440, 0, 622080, 0x0fd38121
-0, 353064, 353064, 0, 622080, 0x184856a6
-0, 356688, 356688, 0, 622080, 0xc57c9f12
-0, 360312, 360312, 0, 622080, 0x39874291
-0, 363936, 363936, 0, 622080, 0x7c13cec4
-0, 367560, 367560, 0, 622080, 0xc4192a76
-0, 371184, 371184, 0, 622080, 0x2af404e3
-0, 374808, 374808, 0, 622080, 0x1ee18f41
-0, 378432, 378432, 0, 622080, 0xfb4d9ee5
-0, 382056, 382056, 0, 622080, 0x50aae4ff
-0, 385680, 385680, 0, 622080, 0x030f91fe
-0, 389304, 389304, 0, 622080, 0x3a3ee08c
-0, 392928, 392928, 0, 622080, 0x50121423
-0, 396552, 396552, 0, 622080, 0xda39e2d6
-0, 400176, 400176, 0, 622080, 0x9e13ccd6
-0, 403800, 403800, 0, 622080, 0xb72a22a7
-0, 407424, 407424, 0, 622080, 0xb76904d5
-0, 411048, 411048, 0, 622080, 0xcffa04a8
-0, 414672, 414672, 0, 622080, 0x2984bf3f
-0, 418296, 418296, 0, 622080, 0x274b5778
-0, 421200, 421200, 0, 622080, 0xf059413a
-0, 424824, 424824, 0, 622080, 0x969fae57
-0, 428448, 428448, 0, 622080, 0x75c29097
-0, 432072, 432072, 0, 622080, 0x2bf3b07d
-0, 435696, 435696, 0, 622080, 0x9f43271d
-0, 439320, 439320, 0, 622080, 0x67bf23f3
-0, 442944, 442944, 0, 622080, 0xa8edcf33
-0, 446568, 446568, 0, 622080, 0x17a0789e
-0, 450192, 450192, 0, 622080, 0x14b67cc7
-0, 453816, 453816, 0, 622080, 0x779215cd
-0, 457440, 457440, 0, 622080, 0x8b460a21
-0, 461064, 461064, 0, 622080, 0x0502ad7d
-0, 464688, 464688, 0, 622080, 0x6860678f
-0, 468312, 468312, 0, 622080, 0xe180469e
-0, 471936, 471936, 0, 622080, 0x9a992835
-0, 475560, 475560, 0, 622080, 0x2efafa33
-0, 479184, 479184, 0, 622080, 0xe24e59b2
-0, 482808, 482808, 0, 622080, 0xfb774d53
-0, 486432, 486432, 0, 622080, 0x3de4ea81
-0, 490056, 490056, 0, 622080, 0xaf9aa1d6
-0, 493680, 493680, 0, 622080, 0xa0e3722f
-0, 497304, 497304, 0, 622080, 0x81684492
-0, 500928, 500928, 0, 622080, 0xa4e971fb
-0, 504552, 504552, 0, 622080, 0x4a1903c8
-0, 508176, 508176, 0, 622080, 0x26304e4a
-0, 511800, 511800, 0, 622080, 0x867983a4
-0, 515424, 515424, 0, 622080, 0x2e7e4d13
-0, 519048, 519048, 0, 622080, 0x736f4682
-0, 522672, 522672, 0, 622080, 0x426a95fa
-0, 526296, 526296, 0, 622080, 0x2bc8850c
-0, 529200, 529200, 0, 622080, 0x047e77ab
-0, 532824, 532824, 0, 622080, 0x414ab77f
-0, 536448, 536448, 0, 622080, 0x42681090
-0, 540072, 540072, 0, 622080, 0x80744ccb
-0, 543696, 543696, 0, 622080, 0x50e2ecc0
-0, 547320, 547320, 0, 622080, 0x5c9fe70e
-0, 550944, 550944, 0, 622080, 0x016461ee
-0, 554568, 554568, 0, 622080, 0xd42f019a
-0, 558192, 558192, 0, 622080, 0x8171bf41
-0, 561816, 561816, 0, 622080, 0xf4d8ef7e
-0, 565440, 565440, 0, 622080, 0xf2d513c8
-0, 569064, 569064, 0, 622080, 0xb5b07704
-0, 572688, 572688, 0, 622080, 0x2168a07a
-0, 576312, 576312, 0, 622080, 0x840418f9
-0, 579936, 579936, 0, 622080, 0xd36f1b7c
-0, 583560, 583560, 0, 622080, 0x52532604
-0, 587184, 587184, 0, 622080, 0x0856d6eb
-0, 590808, 590808, 0, 622080, 0x21748734
-0, 594432, 594432, 0, 622080, 0xbd315c05
-0, 598056, 598056, 0, 622080, 0x1cea8103
-0, 601680, 601680, 0, 622080, 0x71f6e3cb
-0, 605304, 605304, 0, 622080, 0xb12d7aa7
-0, 608928, 608928, 0, 622080, 0x549b2acb
+#tb 0: 1/25
+0, 0, 0, 1, 622080, 0x2276bc78
+0, 1, 1, 1, 622080, 0xda1f698a
+0, 2, 2, 1, 622080, 0xb9907023
+0, 3, 3, 1, 622080, 0xc1c05e44
+0, 4, 4, 1, 622080, 0x9366d0a7
+0, 5, 5, 1, 622080, 0xbf92812d
+0, 6, 6, 1, 622080, 0xd6b1cb3e
+0, 7, 7, 1, 622080, 0x8be011f6
+0, 8, 8, 1, 622080, 0xfde1f1de
+0, 9, 9, 1, 622080, 0xabad03c3
+0, 10, 10, 1, 622080, 0x74204d0a
+0, 11, 11, 1, 622080, 0x220a9de9
+0, 12, 12, 1, 622080, 0x913be934
+0, 13, 13, 1, 622080, 0xab47295b
+0, 14, 14, 1, 622080, 0x1938afc3
+0, 15, 15, 1, 622080, 0x3a5fbe19
+0, 16, 16, 1, 622080, 0x8c15f517
+0, 17, 17, 1, 622080, 0x78410c15
+0, 18, 18, 1, 622080, 0xe2861423
+0, 19, 19, 1, 622080, 0x1dfac8aa
+0, 20, 20, 1, 622080, 0x07b57615
+0, 21, 21, 1, 622080, 0xe9558e77
+0, 22, 22, 1, 622080, 0x917abfc8
+0, 23, 23, 1, 622080, 0xe13d883b
+0, 24, 24, 1, 622080, 0x8abb3304
+0, 25, 25, 1, 622080, 0xc3f10a22
+0, 26, 26, 1, 622080, 0x0ecf8c84
+0, 27, 27, 1, 622080, 0xc3eba1dd
+0, 28, 28, 1, 622080, 0x147d28fd
+0, 29, 29, 1, 622080, 0xba0be99c
+0, 30, 30, 1, 622080, 0xa6d99d9e
+0, 31, 31, 1, 622080, 0xf173991c
+0, 32, 32, 1, 622080, 0x0779d637
+0, 33, 33, 1, 622080, 0xc1f8c139
+0, 34, 34, 1, 622080, 0x7d3a42fc
+0, 35, 35, 1, 622080, 0xcd621bc9
+0, 36, 36, 1, 622080, 0x03cc8d02
+0, 37, 37, 1, 622080, 0xac39b968
+0, 38, 38, 1, 622080, 0xb7896f8c
+0, 39, 39, 1, 622080, 0x57c4399d
+0, 40, 40, 1, 622080, 0xcdc16dc1
+0, 41, 41, 1, 622080, 0x9621db44
+0, 42, 42, 1, 622080, 0xd59d064c
+0, 43, 43, 1, 622080, 0x17a97e5d
+0, 44, 44, 1, 622080, 0xde7789e8
+0, 45, 45, 1, 622080, 0xf5708808
+0, 46, 46, 1, 622080, 0x5b94d8fd
+0, 47, 47, 1, 622080, 0x98bf5f8f
+0, 48, 48, 1, 622080, 0x92107bf6
+0, 49, 49, 1, 622080, 0x86a1b601
+0, 50, 50, 1, 622080, 0x9d7f28c0
+0, 51, 51, 1, 622080, 0x185a85bb
+0, 52, 52, 1, 622080, 0x10a34015
+0, 53, 53, 1, 622080, 0xea21890e
+0, 54, 54, 1, 622080, 0x9a64399a
+0, 55, 55, 1, 622080, 0x2bb460d2
+0, 56, 56, 1, 622080, 0x73ce7c21
+0, 57, 57, 1, 622080, 0x6289ebca
+0, 58, 58, 1, 622080, 0x63a2c57e
+0, 59, 59, 1, 622080, 0xaf5a5123
+0, 60, 60, 1, 622080, 0xcc3062c7
+0, 61, 61, 1, 622080, 0xac434664
+0, 62, 62, 1, 622080, 0x7d5fa464
+0, 63, 63, 1, 622080, 0xd2c4260a
+0, 64, 64, 1, 622080, 0xe2f95a6c
+0, 65, 65, 1, 622080, 0xe073a85a
+0, 66, 66, 1, 622080, 0x34b9f64b
+0, 67, 67, 1, 622080, 0x861da899
+0, 68, 68, 1, 622080, 0x611d4ed5
+0, 69, 69, 1, 622080, 0x3077b9de
+0, 70, 70, 1, 622080, 0x4dedaf9f
+0, 71, 71, 1, 622080, 0xe48d8e8b
+0, 72, 72, 1, 622080, 0x5db2207a
+0, 73, 73, 1, 622080, 0xf10128ab
+0, 74, 74, 1, 622080, 0xd8fd249e
+0, 75, 75, 1, 622080, 0x8f643cc2
+0, 76, 76, 1, 622080, 0xfe1cc433
+0, 77, 77, 1, 622080, 0x3af0b0f4
+0, 78, 78, 1, 622080, 0x4a75fcc8
+0, 79, 79, 1, 622080, 0x48874d71
+0, 80, 80, 1, 622080, 0x3eb5324f
+0, 81, 81, 1, 622080, 0xd7a7d172
+0, 82, 82, 1, 622080, 0x32a17c2a
+0, 83, 83, 1, 622080, 0xcf1137bb
+0, 84, 84, 1, 622080, 0x622e54a2
+0, 85, 85, 1, 622080, 0x0b73c385
+0, 86, 86, 1, 622080, 0x47f082fb
+0, 87, 87, 1, 622080, 0xe7e68540
+0, 88, 88, 1, 622080, 0x77551fde
+0, 89, 89, 1, 622080, 0xa70b0faf
+0, 90, 90, 1, 622080, 0x05ee3436
+0, 91, 91, 1, 622080, 0x2d2f86a9
+0, 92, 92, 1, 622080, 0x78b07e1f
+0, 93, 93, 1, 622080, 0x9714f5fc
+0, 94, 94, 1, 622080, 0x521d118c
+0, 95, 95, 1, 622080, 0x0102e005
+0, 96, 96, 1, 622080, 0x20b1470c
+0, 97, 97, 1, 622080, 0x828f8212
+0, 98, 98, 1, 622080, 0x6fbb57b5
+0, 99, 99, 1, 622080, 0x3b19a01f
+0, 100, 100, 1, 622080, 0x114d43b2
+0, 101, 101, 1, 622080, 0xeca5cfda
+0, 102, 102, 1, 622080, 0x8ca12ba6
+0, 103, 103, 1, 622080, 0xc11e061b
+0, 104, 104, 1, 622080, 0xca6c905a
+0, 105, 105, 1, 622080, 0x9c2ca00f
+0, 106, 106, 1, 622080, 0x8641e615
+0, 107, 107, 1, 622080, 0x90e1930f
+0, 108, 108, 1, 622080, 0xa2eae188
+0, 109, 109, 1, 622080, 0x9be41511
+0, 110, 110, 1, 622080, 0x4268e3b3
+0, 111, 111, 1, 622080, 0x69d0cdd5
+0, 112, 112, 1, 622080, 0x437223c2
+0, 113, 113, 1, 622080, 0x669205c5
+0, 114, 114, 1, 622080, 0x85f1059b
+0, 115, 115, 1, 622080, 0x1595c0a9
+0, 116, 116, 1, 622080, 0xa7fa58c4
+0, 117, 117, 1, 622080, 0x839c42c2
+0, 118, 118, 1, 622080, 0xfadaa4c1
+0, 119, 119, 1, 622080, 0xdbd08677
+0, 120, 120, 1, 622080, 0xbc529d52
+0, 121, 121, 1, 622080, 0x9c9013f3
+0, 122, 122, 1, 622080, 0x7ea9112f
+0, 123, 123, 1, 622080, 0xbb49bc2c
+0, 124, 124, 1, 622080, 0x18c9656f
+0, 125, 125, 1, 622080, 0x637f698e
+0, 126, 126, 1, 622080, 0x4f66028c
+0, 127, 127, 1, 622080, 0xaf1bf6eb
+0, 128, 128, 1, 622080, 0x22c19a51
+0, 129, 129, 1, 622080, 0x085d547a
+0, 130, 130, 1, 622080, 0x11143435
+0, 131, 131, 1, 622080, 0x3a6d15b9
+0, 132, 132, 1, 622080, 0xd380e7cb
+0, 133, 133, 1, 622080, 0xfd1247d5
+0, 134, 134, 1, 622080, 0xd0de3b55
+0, 135, 135, 1, 622080, 0xa876d813
+0, 136, 136, 1, 622080, 0xdc8d8f66
+0, 137, 137, 1, 622080, 0x3a8e5ffe
+0, 138, 138, 1, 622080, 0x1a8a31da
+0, 139, 139, 1, 622080, 0x7e975fba
+0, 140, 140, 1, 622080, 0x242ef158
+0, 141, 141, 1, 622080, 0xbcad3b81
+0, 142, 142, 1, 622080, 0x5db0701f
+0, 143, 143, 1, 622080, 0x4cbf3ab5
+0, 144, 144, 1, 622080, 0xed603395
+0, 145, 145, 1, 622080, 0xd098834b
+0, 146, 146, 1, 622080, 0x92b972e0
+0, 147, 147, 1, 622080, 0xdd4f64d5
+0, 148, 148, 1, 622080, 0x60b1a37b
+0, 149, 149, 1, 622080, 0xed6efdba
+0, 150, 150, 1, 622080, 0xa30235f6
+0, 151, 151, 1, 622080, 0x3419d5c3
+0, 152, 152, 1, 622080, 0x1adbd052
+0, 153, 153, 1, 622080, 0x88e14b04
+0, 154, 154, 1, 622080, 0xca66eada
+0, 155, 155, 1, 622080, 0xa6daa83c
+0, 156, 156, 1, 622080, 0x7ea4d899
+0, 157, 157, 1, 622080, 0x4929fce5
+0, 158, 158, 1, 622080, 0x3c2d6009
+0, 159, 159, 1, 622080, 0xa40e8949
+0, 160, 160, 1, 622080, 0x624801ea
+0, 161, 161, 1, 622080, 0x7877045d
+0, 162, 162, 1, 622080, 0x8dae0e94
+0, 163, 163, 1, 622080, 0xaed5bfd9
+0, 164, 164, 1, 622080, 0x17ab701c
+0, 165, 165, 1, 622080, 0x564f44e8
+0, 166, 166, 1, 622080, 0x05496a5d
+0, 167, 167, 1, 622080, 0xdcb4cee8
+0, 168, 168, 1, 622080, 0xb41172e5
+0, 169, 169, 1, 622080, 0x56c72478
+0, 170, 170, 1, 622080, 0x84ff3af9
diff --git a/tests/ref/fate/cdgraphics b/tests/ref/fate/cdgraphics
index dccb2b5c36..a7820591c9 100644
--- a/tests/ref/fate/cdgraphics
+++ b/tests/ref/fate/cdgraphics
@@ -35,267 +35,179 @@
0, 33, 33, 1, 194400, 0x9ff8cbb1
0, 34, 34, 1, 194400, 0xd015dba1
0, 35, 35, 1, 194400, 0x6a39f18b
-0, 36, 36, 1, 194400, 0x7b8cf983
-0, 37, 37, 1, 194400, 0x07a20f7c
-0, 38, 38, 1, 194400, 0xa63e2962
-0, 39, 39, 1, 194400, 0x2dd54447
-0, 40, 40, 1, 194400, 0x90735e2d
-0, 41, 41, 1, 194400, 0x90d98506
-0, 42, 42, 1, 194400, 0xe5b08ffb
-0, 43, 43, 1, 194400, 0x7a0d95f5
-0, 44, 44, 1, 194400, 0xff6bacde
-0, 45, 45, 1, 194400, 0xd998c2c8
-0, 46, 46, 1, 194400, 0x3d1ddfab
-0, 47, 47, 1, 194400, 0x817de4a6
-0, 48, 48, 1, 194400, 0xfa3ef694
-0, 49, 49, 1, 194400, 0x0b5bfb8f
-0, 50, 50, 1, 194400, 0x00f62376
-0, 51, 51, 1, 194400, 0x2f6b2d6c
-0, 52, 52, 1, 194400, 0x40cb4752
-0, 53, 53, 1, 194400, 0xd8456435
-0, 54, 54, 1, 194400, 0x459f6a2f
-0, 55, 55, 1, 194400, 0x9b678910
-0, 56, 56, 1, 194400, 0x8791a1f7
-0, 57, 57, 1, 194400, 0xdb4ac5d3
-0, 58, 58, 1, 194400, 0xb223c8d0
-0, 59, 59, 1, 194400, 0x4a9ce7b1
-0, 60, 60, 1, 194400, 0x187eeaae
-0, 61, 61, 1, 194400, 0xc712f8a0
-0, 62, 62, 1, 194400, 0x549c00a7
-0, 63, 63, 1, 194400, 0x4d991295
-0, 64, 64, 1, 194400, 0xc41b2681
-0, 65, 65, 1, 194400, 0xed5a3077
-0, 66, 66, 1, 194400, 0x85ad4463
-0, 67, 67, 1, 194400, 0xb98f4760
-0, 68, 68, 1, 194400, 0x87ef5e49
-0, 69, 69, 1, 194400, 0x830a6146
-0, 70, 70, 1, 194400, 0xe33a792e
-0, 71, 71, 1, 194400, 0x83517a2d
-0, 72, 72, 1, 194400, 0xa97e9314
-0, 73, 73, 1, 194400, 0x39059611
-0, 74, 74, 1, 194400, 0xbf4eb9ed
-0, 75, 75, 1, 194400, 0xe5afc4e2
-0, 76, 76, 1, 194400, 0x35d4cdd9
-0, 77, 77, 1, 194400, 0xb376e1c5
-0, 78, 78, 1, 194400, 0x6128e3c3
-0, 79, 79, 1, 194400, 0x30b7f7af
-0, 80, 80, 1, 194400, 0xf1effaac
-0, 81, 81, 1, 194400, 0x483914a1
-0, 82, 82, 1, 194400, 0xbd48199c
-0, 83, 83, 1, 194400, 0x382f2d88
-0, 84, 84, 1, 194400, 0x5a573085
-0, 85, 85, 1, 194400, 0x89733580
-0, 86, 86, 1, 194400, 0xd1325a5b
-0, 87, 87, 1, 194400, 0x655b6253
-0, 88, 88, 1, 194400, 0x55146352
-0, 89, 89, 1, 194400, 0xda527c39
-0, 90, 90, 1, 194400, 0xb0cd7e37
-0, 91, 91, 1, 194400, 0x25e7991c
-0, 92, 92, 1, 194400, 0x5c22a411
-0, 93, 93, 1, 194400, 0x1e2abdf7
-0, 94, 94, 1, 194400, 0x8308bff5
-0, 95, 95, 1, 194400, 0xfdbfd6de
-0, 96, 96, 1, 194400, 0xd4d4d9db
-0, 97, 97, 1, 194400, 0xa449fbb9
-0, 98, 98, 1, 194400, 0x3dcafdb7
-0, 99, 99, 1, 194400, 0x6f1f01c2
-0, 100, 100, 1, 194400, 0xf54a1da6
-0, 101, 101, 1, 194400, 0x88d11fa4
-0, 102, 102, 1, 194400, 0x59642d96
-0, 103, 103, 1, 194400, 0x8ba44182
-0, 104, 104, 1, 194400, 0x88f56360
-0, 105, 105, 1, 194400, 0xfb246d56
-0, 106, 106, 1, 194400, 0xad128043
-0, 107, 107, 1, 194400, 0x3a4f8a39
-0, 108, 108, 1, 194400, 0x563d9d26
-0, 109, 109, 1, 194400, 0x6ff8a320
-0, 110, 110, 1, 194400, 0xcdb9b70c
-0, 111, 111, 1, 194400, 0x99c2bd06
-0, 112, 112, 1, 194400, 0x4b47cef4
-0, 113, 113, 1, 194400, 0x10b9dce6
-0, 114, 114, 1, 194400, 0xdd39f1d1
-0, 115, 115, 1, 194400, 0xbcf104cd
-0, 116, 116, 1, 194400, 0x85ec17ba
-0, 117, 117, 1, 194400, 0x069219b8
-0, 118, 118, 1, 194400, 0x84dd3899
-0, 119, 119, 1, 194400, 0xacca4190
-0, 120, 120, 1, 194400, 0xcf5b5d74
-0, 121, 121, 1, 194400, 0x4b8c626f
-0, 122, 122, 1, 194400, 0xf0817958
-0, 123, 123, 1, 194400, 0xc0887e53
-0, 124, 124, 1, 194400, 0x42e6854c
-0, 125, 125, 1, 194400, 0x036c9140
-0, 126, 126, 1, 194400, 0x0f21a62b
-0, 127, 127, 1, 194400, 0xcdaeaa27
-0, 128, 128, 1, 194400, 0xe425bc15
-0, 129, 129, 1, 194400, 0x8e18c20f
-0, 130, 130, 1, 194400, 0x767cd5fb
-0, 131, 131, 1, 194400, 0x554ae6ea
-0, 132, 132, 1, 194400, 0xeac1f9d7
-0, 133, 133, 1, 194400, 0x0b32fed2
-0, 134, 134, 1, 194400, 0xe30c19c6
-0, 135, 135, 1, 194400, 0x6a8a23bc
-0, 136, 136, 1, 194400, 0x26bf36a9
-0, 137, 137, 1, 194400, 0x1e4f3fa0
-0, 138, 138, 1, 194400, 0x231f5986
-0, 139, 139, 1, 194400, 0xf557756a
-0, 140, 140, 1, 194400, 0x6bce805f
-0, 141, 141, 1, 194400, 0xcd80924d
-0, 142, 142, 1, 194400, 0x65dc9f40
-0, 143, 143, 1, 194400, 0x2ab7af30
-0, 144, 144, 1, 194400, 0xd43cb728
-0, 145, 145, 1, 194400, 0x05d9c916
-0, 146, 146, 1, 194400, 0x43cad10e
-0, 147, 147, 1, 194400, 0x06b5e0fe
-0, 148, 148, 1, 194400, 0xa142f0ee
-0, 149, 149, 1, 194400, 0xed7f03ea
-0, 150, 150, 1, 194400, 0xf26019d4
-0, 151, 151, 1, 194400, 0x3b7f29c4
-0, 152, 152, 1, 194400, 0x30282ebf
-0, 153, 153, 1, 194400, 0xaeff4aa3
-0, 154, 154, 1, 194400, 0x1d355697
-0, 155, 155, 1, 194400, 0x2ead6f7e
-0, 156, 156, 1, 194400, 0xf1b67776
-0, 157, 157, 1, 194400, 0x93b38b62
-0, 158, 158, 1, 194400, 0x9469905d
-0, 159, 159, 1, 194400, 0x27bf9756
-0, 160, 160, 1, 194400, 0xd016a548
-0, 161, 161, 1, 194400, 0x6889b835
-0, 162, 162, 1, 194400, 0x6a05be2f
-0, 163, 163, 1, 194400, 0xe0a1ce1f
-0, 164, 164, 1, 194400, 0x8fdbd617
-0, 165, 165, 1, 194400, 0xd68fe805
-0, 166, 166, 1, 194400, 0x0d1dfbf1
-0, 167, 167, 1, 194400, 0x0fe70bf0
-0, 168, 168, 1, 194400, 0x0a8f13e8
-0, 169, 169, 1, 194400, 0x0ca42bd0
-0, 170, 170, 1, 194400, 0x6f3838c3
-0, 171, 171, 1, 194400, 0x045448b3
-0, 172, 172, 1, 194400, 0x764349b2
-0, 173, 173, 1, 194400, 0xed1651aa
-0, 174, 174, 1, 194400, 0xbb376398
-0, 175, 175, 1, 194400, 0xd0d5718a
-0, 176, 176, 1, 194400, 0xcd977e7d
-0, 177, 177, 1, 194400, 0x8cb39665
-0, 178, 178, 1, 194400, 0xb935b04b
-0, 179, 179, 1, 194400, 0x0292be3d
-0, 180, 180, 1, 194400, 0x4f21c833
-0, 181, 181, 1, 194400, 0xa5c7d823
-0, 182, 182, 1, 194400, 0xfb8ee01b
-0, 183, 183, 1, 194400, 0xea53ee0d
-0, 184, 184, 1, 194400, 0x803efcfe
-0, 185, 185, 1, 194400, 0x2c0e0aff
-0, 186, 186, 1, 194400, 0x3df318f1
-0, 187, 187, 1, 194400, 0xc4cb26e3
-0, 188, 188, 1, 194400, 0x92a033d6
-0, 189, 189, 1, 194400, 0x1b2048c1
-0, 190, 190, 1, 194400, 0x236858b1
-0, 191, 191, 1, 194400, 0x482f6d9c
-0, 192, 192, 1, 194400, 0x9ee97891
-0, 193, 193, 1, 194400, 0xe0dc8683
-0, 194, 194, 1, 194400, 0x461b9079
-0, 195, 195, 1, 194400, 0xd346a960
-0, 196, 196, 1, 194400, 0xa384b554
-0, 197, 197, 1, 194400, 0x3246cf3a
-0, 198, 198, 1, 194400, 0xa53fe722
-0, 199, 199, 1, 194400, 0xe620fd0c
-0, 200, 200, 1, 194400, 0xd6370414
-0, 201, 201, 1, 194400, 0xf57f1404
-0, 202, 202, 1, 194400, 0x8c6420f7
-0, 203, 203, 1, 194400, 0xd4be3add
-0, 204, 204, 1, 194400, 0xa8dc4ec9
-0, 205, 205, 1, 194400, 0xda1563b4
-0, 206, 206, 1, 194400, 0xd51873a4
-0, 207, 207, 1, 194400, 0x68588196
-0, 208, 208, 1, 194400, 0x40d18e89
-0, 209, 209, 1, 194400, 0x1b75a275
-0, 210, 210, 1, 194400, 0xedd1a572
-0, 211, 211, 1, 194400, 0x55daad6a
-0, 212, 212, 1, 194400, 0xcb93b067
-0, 213, 213, 1, 194400, 0x5888ba5d
-0, 214, 214, 1, 194400, 0x2c11c84f
-0, 215, 215, 1, 194400, 0x0fbae334
-0, 216, 216, 1, 194400, 0x773fed2a
-0, 217, 217, 1, 194400, 0x2f87fc1b
-0, 218, 218, 1, 194400, 0xe8120521
-0, 219, 219, 1, 194400, 0x64ac0f17
-0, 220, 220, 1, 194400, 0xba531c0a
-0, 221, 221, 1, 194400, 0xf49433f2
-0, 222, 222, 1, 194400, 0x79e234f1
-0, 223, 223, 1, 194400, 0x043937ee
-0, 224, 224, 1, 194400, 0x9e6141e4
-0, 225, 225, 1, 194400, 0x34204fd6
-0, 226, 226, 1, 194400, 0xa1dd60c5
-0, 227, 227, 1, 194400, 0x12b36eb7
-0, 228, 228, 1, 194400, 0x68987aab
-0, 229, 229, 1, 194400, 0x3207889d
-0, 230, 230, 1, 194400, 0x3bb59194
-0, 231, 231, 1, 194400, 0x0a119f86
-0, 232, 232, 1, 194400, 0x472bab7a
-0, 233, 233, 1, 194400, 0x7364c85d
-0, 234, 234, 1, 194400, 0xa812d84d
-0, 235, 235, 1, 194400, 0xf384f530
-0, 236, 236, 1, 194400, 0x1546052f
-0, 237, 237, 1, 194400, 0xeb611a1a
-0, 238, 238, 1, 194400, 0xc39d250f
-0, 239, 239, 1, 194400, 0x7bd73301
-0, 240, 240, 1, 194400, 0x10f73cf7
-0, 241, 241, 1, 194400, 0x95dc55de
-0, 242, 242, 1, 194400, 0x392e61d2
-0, 243, 243, 1, 194400, 0x113c7bb8
-0, 244, 244, 1, 194400, 0x17128fa4
-0, 245, 245, 1, 194400, 0xf95e9b98
-0, 246, 246, 1, 194400, 0xdc47aa89
-0, 247, 247, 1, 194400, 0xea5dc073
-0, 248, 248, 1, 194400, 0x8dfadc57
-0, 249, 249, 1, 194400, 0xe5c3e84b
-0, 250, 250, 1, 194400, 0x8952f43f
-0, 251, 251, 1, 194400, 0xec9e0240
-0, 252, 252, 1, 194400, 0x8f460c36
-0, 253, 253, 1, 194400, 0xd43e182a
-0, 254, 254, 1, 194400, 0xb00b2919
-0, 255, 255, 1, 194400, 0xc9f6350d
-0, 256, 256, 1, 194400, 0x87ca44fd
-0, 257, 257, 1, 194400, 0xa6a250f1
-0, 258, 258, 1, 194400, 0x34fa60e1
-0, 259, 259, 1, 194400, 0xe1a372cf
-0, 260, 260, 1, 194400, 0xc80785bc
-0, 261, 261, 1, 194400, 0x43e297aa
-0, 262, 262, 1, 194400, 0x7e8ea49d
-0, 263, 263, 1, 194400, 0xd009b091
-0, 264, 264, 1, 194400, 0x9126bc85
-0, 265, 265, 1, 194400, 0x175ad36e
-0, 266, 266, 1, 194400, 0xf9dae160
-0, 267, 267, 1, 194400, 0x1b98f948
-0, 268, 268, 1, 194400, 0xa6c5133d
-0, 269, 269, 1, 194400, 0xf5d42729
-0, 270, 270, 1, 194400, 0x8cfe311f
-0, 271, 271, 1, 194400, 0x18733e12
-0, 272, 272, 1, 194400, 0x24ac50ff
-0, 273, 273, 1, 194400, 0x0d1c64eb
-0, 274, 274, 1, 194400, 0xde947cd3
-0, 275, 275, 1, 194400, 0x08268dc2
-0, 276, 276, 1, 194400, 0xfec69fb0
-0, 277, 277, 1, 194400, 0xba83aba4
-0, 278, 278, 1, 194400, 0xfbe2bc93
-0, 279, 279, 1, 194400, 0xe22fcc83
-0, 280, 280, 1, 194400, 0x050fcf80
-0, 281, 281, 1, 194400, 0xee1ed778
-0, 282, 282, 1, 194400, 0xb44cda75
-0, 283, 283, 1, 194400, 0xa29fe46b
-0, 284, 284, 1, 194400, 0xa99bf55a
-0, 285, 285, 1, 194400, 0x4f840d51
-0, 286, 286, 1, 194400, 0x58941945
-0, 287, 287, 1, 194400, 0x62cb2638
-0, 288, 288, 1, 194400, 0x22ee312d
-0, 289, 289, 1, 194400, 0xea8f3925
-0, 290, 290, 1, 194400, 0xed294c12
-0, 291, 291, 1, 194400, 0xafa75e00
-0, 292, 292, 1, 194400, 0x19d45ffe
-0, 293, 293, 1, 194400, 0x7fcf61fc
-0, 294, 294, 1, 194400, 0x2c126df0
-0, 295, 295, 1, 194400, 0x331379e4
-0, 296, 296, 1, 194400, 0x99fe8cd1
-0, 297, 297, 1, 194400, 0xa5ec98c5
-0, 298, 298, 1, 194400, 0xac68a6b7
-0, 299, 299, 1, 194400, 0x28e6b2ab
+0, 37, 37, 1, 194400, 0x7b8cf983
+0, 38, 38, 1, 194400, 0x07a20f7c
+0, 40, 40, 1, 194400, 0xa63e2962
+0, 41, 41, 1, 194400, 0x2dd54447
+0, 43, 43, 1, 194400, 0x90735e2d
+0, 44, 44, 1, 194400, 0x90d98506
+0, 46, 46, 1, 194400, 0xe5b08ffb
+0, 47, 47, 1, 194400, 0x7a0d95f5
+0, 49, 49, 1, 194400, 0xff6bacde
+0, 50, 50, 1, 194400, 0xd998c2c8
+0, 52, 52, 1, 194400, 0x3d1ddfab
+0, 53, 53, 1, 194400, 0x817de4a6
+0, 55, 55, 1, 194400, 0xfa3ef694
+0, 56, 56, 1, 194400, 0x0b5bfb8f
+0, 58, 58, 1, 194400, 0x00f62376
+0, 59, 59, 1, 194400, 0x2f6b2d6c
+0, 61, 61, 1, 194400, 0x40cb4752
+0, 62, 62, 1, 194400, 0xd8456435
+0, 64, 64, 1, 194400, 0x459f6a2f
+0, 65, 65, 1, 194400, 0x9b678910
+0, 67, 67, 1, 194400, 0x8791a1f7
+0, 68, 68, 1, 194400, 0xdb4ac5d3
+0, 70, 70, 1, 194400, 0xb223c8d0
+0, 71, 71, 1, 194400, 0x4a9ce7b1
+0, 73, 73, 1, 194400, 0x187eeaae
+0, 74, 74, 1, 194400, 0xc712f8a0
+0, 76, 76, 1, 194400, 0x549c00a7
+0, 77, 77, 1, 194400, 0x4d991295
+0, 79, 79, 1, 194400, 0xc41b2681
+0, 80, 80, 1, 194400, 0xed5a3077
+0, 82, 82, 1, 194400, 0x85ad4463
+0, 83, 83, 1, 194400, 0xb98f4760
+0, 85, 85, 1, 194400, 0x87ef5e49
+0, 86, 86, 1, 194400, 0x830a6146
+0, 88, 88, 1, 194400, 0xe33a792e
+0, 89, 89, 1, 194400, 0x83517a2d
+0, 91, 91, 1, 194400, 0xa97e9314
+0, 92, 92, 1, 194400, 0x39059611
+0, 94, 94, 1, 194400, 0xbf4eb9ed
+0, 95, 95, 1, 194400, 0xe5afc4e2
+0, 97, 97, 1, 194400, 0x35d4cdd9
+0, 98, 98, 1, 194400, 0xb376e1c5
+0, 100, 100, 1, 194400, 0x6128e3c3
+0, 101, 101, 1, 194400, 0x30b7f7af
+0, 103, 103, 1, 194400, 0xf1effaac
+0, 104, 104, 1, 194400, 0x483914a1
+0, 106, 106, 1, 194400, 0xbd48199c
+0, 107, 107, 1, 194400, 0x382f2d88
+0, 109, 109, 1, 194400, 0x5a573085
+0, 110, 110, 1, 194400, 0x89733580
+0, 112, 112, 1, 194400, 0xd1325a5b
+0, 113, 113, 1, 194400, 0x655b6253
+0, 115, 115, 1, 194400, 0x55146352
+0, 116, 116, 1, 194400, 0xda527c39
+0, 118, 118, 1, 194400, 0xb0cd7e37
+0, 119, 119, 1, 194400, 0x25e7991c
+0, 121, 121, 1, 194400, 0x5c22a411
+0, 122, 122, 1, 194400, 0x1e2abdf7
+0, 124, 124, 1, 194400, 0x8308bff5
+0, 125, 125, 1, 194400, 0xfdbfd6de
+0, 127, 127, 1, 194400, 0xd4d4d9db
+0, 128, 128, 1, 194400, 0xa449fbb9
+0, 130, 130, 1, 194400, 0x3dcafdb7
+0, 131, 131, 1, 194400, 0x6f1f01c2
+0, 133, 133, 1, 194400, 0xf54a1da6
+0, 134, 134, 1, 194400, 0x88d11fa4
+0, 136, 136, 1, 194400, 0x59642d96
+0, 137, 137, 1, 194400, 0x8ba44182
+0, 139, 139, 1, 194400, 0x88f56360
+0, 140, 140, 1, 194400, 0xfb246d56
+0, 142, 142, 1, 194400, 0xad128043
+0, 143, 143, 1, 194400, 0x3a4f8a39
+0, 145, 145, 1, 194400, 0x563d9d26
+0, 146, 146, 1, 194400, 0x6ff8a320
+0, 148, 148, 1, 194400, 0xcdb9b70c
+0, 149, 149, 1, 194400, 0x99c2bd06
+0, 151, 151, 1, 194400, 0x4b47cef4
+0, 152, 152, 1, 194400, 0x10b9dce6
+0, 154, 154, 1, 194400, 0xdd39f1d1
+0, 155, 155, 1, 194400, 0xbcf104cd
+0, 157, 157, 1, 194400, 0x85ec17ba
+0, 158, 158, 1, 194400, 0x069219b8
+0, 160, 160, 1, 194400, 0x84dd3899
+0, 161, 161, 1, 194400, 0xacca4190
+0, 163, 163, 1, 194400, 0xcf5b5d74
+0, 164, 164, 1, 194400, 0x4b8c626f
+0, 166, 166, 1, 194400, 0xf0817958
+0, 167, 167, 1, 194400, 0xc0887e53
+0, 169, 169, 1, 194400, 0x42e6854c
+0, 170, 170, 1, 194400, 0x036c9140
+0, 172, 172, 1, 194400, 0x0f21a62b
+0, 173, 173, 1, 194400, 0xcdaeaa27
+0, 175, 175, 1, 194400, 0xe425bc15
+0, 176, 176, 1, 194400, 0x8e18c20f
+0, 178, 178, 1, 194400, 0x767cd5fb
+0, 179, 179, 1, 194400, 0x554ae6ea
+0, 181, 181, 1, 194400, 0xeac1f9d7
+0, 182, 182, 1, 194400, 0x0b32fed2
+0, 184, 184, 1, 194400, 0xe30c19c6
+0, 185, 185, 1, 194400, 0x6a8a23bc
+0, 187, 187, 1, 194400, 0x26bf36a9
+0, 188, 188, 1, 194400, 0x1e4f3fa0
+0, 190, 190, 1, 194400, 0x231f5986
+0, 191, 191, 1, 194400, 0xf557756a
+0, 193, 193, 1, 194400, 0x6bce805f
+0, 194, 194, 1, 194400, 0xcd80924d
+0, 196, 196, 1, 194400, 0x65dc9f40
+0, 197, 197, 1, 194400, 0x2ab7af30
+0, 199, 199, 1, 194400, 0xd43cb728
+0, 200, 200, 1, 194400, 0x05d9c916
+0, 202, 202, 1, 194400, 0x43cad10e
+0, 203, 203, 1, 194400, 0x06b5e0fe
+0, 205, 205, 1, 194400, 0xa142f0ee
+0, 206, 206, 1, 194400, 0xed7f03ea
+0, 208, 208, 1, 194400, 0xf26019d4
+0, 209, 209, 1, 194400, 0x3b7f29c4
+0, 211, 211, 1, 194400, 0x30282ebf
+0, 212, 212, 1, 194400, 0xaeff4aa3
+0, 214, 214, 1, 194400, 0x1d355697
+0, 215, 215, 1, 194400, 0x2ead6f7e
+0, 217, 217, 1, 194400, 0xf1b67776
+0, 218, 218, 1, 194400, 0x93b38b62
+0, 220, 220, 1, 194400, 0x9469905d
+0, 221, 221, 1, 194400, 0x27bf9756
+0, 223, 223, 1, 194400, 0xd016a548
+0, 224, 224, 1, 194400, 0x6889b835
+0, 226, 226, 1, 194400, 0x6a05be2f
+0, 227, 227, 1, 194400, 0xe0a1ce1f
+0, 229, 229, 1, 194400, 0x8fdbd617
+0, 230, 230, 1, 194400, 0xd68fe805
+0, 232, 232, 1, 194400, 0x0d1dfbf1
+0, 233, 233, 1, 194400, 0x0fe70bf0
+0, 235, 235, 1, 194400, 0x0a8f13e8
+0, 236, 236, 1, 194400, 0x0ca42bd0
+0, 238, 238, 1, 194400, 0x6f3838c3
+0, 239, 239, 1, 194400, 0x045448b3
+0, 241, 241, 1, 194400, 0x764349b2
+0, 242, 242, 1, 194400, 0xed1651aa
+0, 244, 244, 1, 194400, 0xbb376398
+0, 245, 245, 1, 194400, 0xd0d5718a
+0, 247, 247, 1, 194400, 0xcd977e7d
+0, 248, 248, 1, 194400, 0x8cb39665
+0, 250, 250, 1, 194400, 0xb935b04b
+0, 251, 251, 1, 194400, 0x0292be3d
+0, 253, 253, 1, 194400, 0x4f21c833
+0, 254, 254, 1, 194400, 0xa5c7d823
+0, 256, 256, 1, 194400, 0xfb8ee01b
+0, 257, 257, 1, 194400, 0xea53ee0d
+0, 259, 259, 1, 194400, 0x803efcfe
+0, 260, 260, 1, 194400, 0x2c0e0aff
+0, 262, 262, 1, 194400, 0x3df318f1
+0, 263, 263, 1, 194400, 0xc4cb26e3
+0, 265, 265, 1, 194400, 0x92a033d6
+0, 266, 266, 1, 194400, 0x1b2048c1
+0, 268, 268, 1, 194400, 0x236858b1
+0, 269, 269, 1, 194400, 0x482f6d9c
+0, 271, 271, 1, 194400, 0x9ee97891
+0, 272, 272, 1, 194400, 0xe0dc8683
+0, 274, 274, 1, 194400, 0x461b9079
+0, 275, 275, 1, 194400, 0xd346a960
+0, 277, 277, 1, 194400, 0xa384b554
+0, 278, 278, 1, 194400, 0x3246cf3a
+0, 280, 280, 1, 194400, 0xa53fe722
+0, 281, 281, 1, 194400, 0xe620fd0c
+0, 283, 283, 1, 194400, 0xd6370414
+0, 284, 284, 1, 194400, 0xf57f1404
+0, 286, 286, 1, 194400, 0x8c6420f7
+0, 287, 287, 1, 194400, 0xd4be3add
+0, 289, 289, 1, 194400, 0xa8dc4ec9
+0, 290, 290, 1, 194400, 0xda1563b4
+0, 292, 292, 1, 194400, 0xd51873a4
+0, 293, 293, 1, 194400, 0x68588196
+0, 295, 295, 1, 194400, 0x40d18e89
+0, 296, 296, 1, 194400, 0x1b75a275
+0, 298, 298, 1, 194400, 0xedd1a572
+0, 299, 299, 1, 194400, 0x55daad6a
diff --git a/tests/ref/fate/cdxl-bitline-ham6 b/tests/ref/fate/cdxl-bitline-ham6
index e4071a9955..9ba7404b71 100644
--- a/tests/ref/fate/cdxl-bitline-ham6
+++ b/tests/ref/fate/cdxl-bitline-ham6
@@ -1,11 +1,11 @@
-#tb 0: 1/11025
-0, 0, 0, 0, 63180, 0xcda82c16
-0, 220, 220, 0, 63180, 0xa6097bf9
-0, 440, 440, 0, 63180, 0x4c2fb091
-0, 660, 660, 0, 63180, 0xc597db00
-0, 880, 880, 0, 63180, 0xfa581ccd
-0, 1100, 1100, 0, 63180, 0x3e51498f
-0, 1320, 1320, 0, 63180, 0xe3495396
-0, 1540, 1540, 0, 63180, 0x425f5f02
-0, 1760, 1760, 0, 63180, 0x6077465f
-0, 1980, 1980, 0, 63180, 0x923ba29c
+#tb 0: 1/50
+0, 0, 0, 1, 63180, 0xcda82c16
+0, 1, 1, 1, 63180, 0xa6097bf9
+0, 2, 2, 1, 63180, 0x4c2fb091
+0, 3, 3, 1, 63180, 0xc597db00
+0, 4, 4, 1, 63180, 0xfa581ccd
+0, 5, 5, 1, 63180, 0x3e51498f
+0, 6, 6, 1, 63180, 0xe3495396
+0, 7, 7, 1, 63180, 0x425f5f02
+0, 8, 8, 1, 63180, 0x6077465f
+0, 9, 9, 1, 63180, 0x923ba29c
diff --git a/tests/ref/fate/cdxl-ham6 b/tests/ref/fate/cdxl-ham6
index 25886b2518..6426d45014 100644
--- a/tests/ref/fate/cdxl-ham6
+++ b/tests/ref/fate/cdxl-ham6
@@ -1,17 +1,17 @@
-#tb 0: 1/11025
-0, 0, 0, 0, 57600, 0x87887a7b
-0, 1092, 1092, 0, 57600, 0x10c301d2
-0, 2184, 2184, 0, 57600, 0xd1a6f910
-0, 3276, 3276, 0, 57600, 0x20242bb9
-0, 4368, 4368, 0, 57600, 0xae33cb7f
-0, 5460, 5460, 0, 57600, 0x501b82c8
-0, 6552, 6552, 0, 57600, 0x84199043
-0, 7644, 7644, 0, 57600, 0x946a6dbb
-0, 8736, 8736, 0, 57600, 0xeacea671
-0, 9828, 9828, 0, 57600, 0x77b8723f
-0, 10920, 10920, 0, 57600, 0x371cdb09
-0, 12012, 12012, 0, 57600, 0xa16ef5ee
-0, 13104, 13104, 0, 57600, 0xcb6abd9e
-0, 14196, 14196, 0, 57600, 0xb73e800f
-0, 15288, 15288, 0, 57600, 0x368bd93e
-0, 16380, 16380, 0, 57600, 0xcde72dc5
+#tb 0: 52/525
+0, 0, 0, 1, 57600, 0x87887a7b
+0, 1, 1, 1, 57600, 0x10c301d2
+0, 2, 2, 1, 57600, 0xd1a6f910
+0, 3, 3, 1, 57600, 0x20242bb9
+0, 4, 4, 1, 57600, 0xae33cb7f
+0, 5, 5, 1, 57600, 0x501b82c8
+0, 6, 6, 1, 57600, 0x84199043
+0, 7, 7, 1, 57600, 0x946a6dbb
+0, 8, 8, 1, 57600, 0xeacea671
+0, 9, 9, 1, 57600, 0x77b8723f
+0, 10, 10, 1, 57600, 0x371cdb09
+0, 11, 11, 1, 57600, 0xa16ef5ee
+0, 12, 12, 1, 57600, 0xcb6abd9e
+0, 13, 13, 1, 57600, 0xb73e800f
+0, 14, 14, 1, 57600, 0x368bd93e
+0, 15, 15, 1, 57600, 0xcde72dc5
diff --git a/tests/ref/fate/cdxl-ham8 b/tests/ref/fate/cdxl-ham8
index 356ad1be19..1eebea37c7 100644
--- a/tests/ref/fate/cdxl-ham8
+++ b/tests/ref/fate/cdxl-ham8
@@ -1,2 +1,2 @@
-#tb 0: 1/11025
-0, 0, 0, 0, 67584, 0xce0cade5
+#tb 0: 12/281
+0, 0, 0, 1, 67584, 0xce0cade5
diff --git a/tests/ref/fate/cdxl-pal8 b/tests/ref/fate/cdxl-pal8
index f5c319af58..b2fb04518e 100644
--- a/tests/ref/fate/cdxl-pal8
+++ b/tests/ref/fate/cdxl-pal8
@@ -1,12 +1,12 @@
-#tb 0: 1/11025
-0, 0, 0, 0, 67584, 0x5eae629b
-0, 220, 220, 0, 67584, 0x32591227
-0, 440, 440, 0, 67584, 0x4e4424c7
-0, 660, 660, 0, 67584, 0x70db0134
-0, 880, 880, 0, 67584, 0x3550ed0b
-0, 1100, 1100, 0, 67584, 0x86fe3eef
-0, 1320, 1320, 0, 67584, 0x3414bb33
-0, 1540, 1540, 0, 67584, 0x667bfb91
-0, 1760, 1760, 0, 67584, 0x6e1a4ccb
-0, 1980, 1980, 0, 67584, 0xf723f9ae
-0, 2200, 2200, 0, 67584, 0x88481d5d
+#tb 0: 1/50
+0, 0, 0, 1, 67584, 0x5eae629b
+0, 1, 1, 1, 67584, 0x32591227
+0, 2, 2, 1, 67584, 0x4e4424c7
+0, 3, 3, 1, 67584, 0x70db0134
+0, 4, 4, 1, 67584, 0x3550ed0b
+0, 5, 5, 1, 67584, 0x86fe3eef
+0, 6, 6, 1, 67584, 0x3414bb33
+0, 7, 7, 1, 67584, 0x667bfb91
+0, 8, 8, 1, 67584, 0x6e1a4ccb
+0, 9, 9, 1, 67584, 0xf723f9ae
+0, 10, 10, 1, 67584, 0x88481d5d
diff --git a/tests/ref/fate/cdxl-pal8-small b/tests/ref/fate/cdxl-pal8-small
index d285e9a190..f7a1a465ab 100644
--- a/tests/ref/fate/cdxl-pal8-small
+++ b/tests/ref/fate/cdxl-pal8-small
@@ -1,47 +1,47 @@
-#tb 0: 1/11025
-0, 0, 0, 0, 30720, 0x0d552cfd
-0, 368, 368, 0, 30720, 0x3cf93291
-0, 736, 736, 0, 30720, 0xe45b2868
-0, 1104, 1104, 0, 30720, 0xb5df289b
-0, 1472, 1472, 0, 30720, 0x2562259e
-0, 1840, 1840, 0, 30720, 0xbf171878
-0, 2208, 2208, 0, 30720, 0x695b1d73
-0, 2576, 2576, 0, 30720, 0x89ef1614
-0, 2944, 2944, 0, 30720, 0xe12a1dd9
-0, 3312, 3312, 0, 30720, 0x49622ffa
-0, 3680, 3680, 0, 30720, 0xd6832703
-0, 4048, 4048, 0, 30720, 0xec1d0cb7
-0, 4416, 4416, 0, 30720, 0x8bee0525
-0, 4784, 4784, 0, 30720, 0x1e0cf0c4
-0, 5152, 5152, 0, 30720, 0xf83fd9db
-0, 5520, 5520, 0, 30720, 0xffb0d6ab
-0, 5888, 5888, 0, 30720, 0xe37fe239
-0, 6256, 6256, 0, 30720, 0x74b0f856
-0, 6624, 6624, 0, 30720, 0x9c88d3e1
-0, 6992, 6992, 0, 30720, 0x714db368
-0, 7360, 7360, 0, 30720, 0x6c8e8860
-0, 7728, 7728, 0, 30720, 0x804968e6
-0, 8096, 8096, 0, 30720, 0x7ac56ae4
-0, 8464, 8464, 0, 30720, 0xffd85cbf
-0, 8832, 8832, 0, 30720, 0x1f8455f9
-0, 9200, 9200, 0, 30720, 0x3ae65296
-0, 9568, 9568, 0, 30720, 0x9e544ecd
-0, 9936, 9936, 0, 30720, 0x35678e5a
-0, 10304, 10304, 0, 30720, 0x04bae866
-0, 10672, 10672, 0, 30720, 0xb126ed94
-0, 11040, 11040, 0, 30720, 0x1720efc5
-0, 11408, 11408, 0, 30720, 0x4c1b01c2
-0, 11776, 11776, 0, 30720, 0xd0a1e866
-0, 12144, 12144, 0, 30720, 0x0d330789
-0, 12512, 12512, 0, 30720, 0xf5ac08bb
-0, 12880, 12880, 0, 30720, 0x9abe0d83
-0, 13248, 13248, 0, 30720, 0xa44c02f4
-0, 13616, 13616, 0, 30720, 0xdc4cc688
-0, 13984, 13984, 0, 30720, 0x22eef3c1
-0, 14352, 14352, 0, 30720, 0xcfbc0d1d
-0, 14720, 14720, 0, 30720, 0x7104ea31
-0, 15088, 15088, 0, 30720, 0x80daecfb
-0, 15456, 15456, 0, 30720, 0xe1bab995
-0, 15824, 15824, 0, 30720, 0x43f4b896
-0, 16192, 16192, 0, 30720, 0xa0d2bf5c
-0, 16560, 16560, 0, 30720, 0x3556a114
+#tb 0: 368/11025
+0, 0, 0, 1, 30720, 0x0d552cfd
+0, 1, 1, 1, 30720, 0x3cf93291
+0, 2, 2, 1, 30720, 0xe45b2868
+0, 3, 3, 1, 30720, 0xb5df289b
+0, 4, 4, 1, 30720, 0x2562259e
+0, 5, 5, 1, 30720, 0xbf171878
+0, 6, 6, 1, 30720, 0x695b1d73
+0, 7, 7, 1, 30720, 0x89ef1614
+0, 8, 8, 1, 30720, 0xe12a1dd9
+0, 9, 9, 1, 30720, 0x49622ffa
+0, 10, 10, 1, 30720, 0xd6832703
+0, 11, 11, 1, 30720, 0xec1d0cb7
+0, 12, 12, 1, 30720, 0x8bee0525
+0, 13, 13, 1, 30720, 0x1e0cf0c4
+0, 14, 14, 1, 30720, 0xf83fd9db
+0, 15, 15, 1, 30720, 0xffb0d6ab
+0, 16, 16, 1, 30720, 0xe37fe239
+0, 17, 17, 1, 30720, 0x74b0f856
+0, 18, 18, 1, 30720, 0x9c88d3e1
+0, 19, 19, 1, 30720, 0x714db368
+0, 20, 20, 1, 30720, 0x6c8e8860
+0, 21, 21, 1, 30720, 0x804968e6
+0, 22, 22, 1, 30720, 0x7ac56ae4
+0, 23, 23, 1, 30720, 0xffd85cbf
+0, 24, 24, 1, 30720, 0x1f8455f9
+0, 25, 25, 1, 30720, 0x3ae65296
+0, 26, 26, 1, 30720, 0x9e544ecd
+0, 27, 27, 1, 30720, 0x35678e5a
+0, 28, 28, 1, 30720, 0x04bae866
+0, 29, 29, 1, 30720, 0xb126ed94
+0, 30, 30, 1, 30720, 0x1720efc5
+0, 31, 31, 1, 30720, 0x4c1b01c2
+0, 32, 32, 1, 30720, 0xd0a1e866
+0, 33, 33, 1, 30720, 0x0d330789
+0, 34, 34, 1, 30720, 0xf5ac08bb
+0, 35, 35, 1, 30720, 0x9abe0d83
+0, 36, 36, 1, 30720, 0xa44c02f4
+0, 37, 37, 1, 30720, 0xdc4cc688
+0, 38, 38, 1, 30720, 0x22eef3c1
+0, 39, 39, 1, 30720, 0xcfbc0d1d
+0, 40, 40, 1, 30720, 0x7104ea31
+0, 41, 41, 1, 30720, 0x80daecfb
+0, 42, 42, 1, 30720, 0xe1bab995
+0, 43, 43, 1, 30720, 0x43f4b896
+0, 44, 44, 1, 30720, 0xa0d2bf5c
+0, 45, 45, 1, 30720, 0x3556a114
diff --git a/tests/ref/fate/cine-demux b/tests/ref/fate/cine-demux
new file mode 100644
index 0000000000..bb7ac70d41
--- /dev/null
+++ b/tests/ref/fate/cine-demux
@@ -0,0 +1 @@
+CRC=0x8555ed33
diff --git a/tests/ref/fate/cljr b/tests/ref/fate/cljr
index f73c8c0b34..584254154a 100644
--- a/tests/ref/fate/cljr
+++ b/tests/ref/fate/cljr
@@ -1,37 +1,37 @@
#tb 0: 3521/100000
-0, 0, 0, 1, 64800, 0x44a1c47c
-0, 1, 1, 1, 64800, 0x649cc3a4
-0, 2, 2, 1, 64800, 0xcab1b88c
-0, 3, 3, 1, 64800, 0xf56cb788
-0, 4, 4, 1, 64800, 0x5336b618
-0, 5, 5, 1, 64800, 0x2704b438
-0, 6, 6, 1, 64800, 0x04c7b8e4
-0, 7, 7, 1, 64800, 0x3185b288
-0, 8, 8, 1, 64800, 0xa537c410
-0, 9, 9, 1, 64800, 0x6495c0f8
-0, 10, 10, 1, 64800, 0x06a1ca14
-0, 11, 11, 1, 64800, 0x69cdd2a0
-0, 12, 12, 1, 64800, 0x4ad2d828
-0, 13, 13, 1, 64800, 0x9604dea4
-0, 14, 14, 1, 64800, 0x1c00e430
-0, 15, 15, 1, 64800, 0x9afeefe0
-0, 16, 16, 1, 64800, 0xc13fdd78
-0, 17, 17, 1, 64800, 0x8438da7c
-0, 18, 18, 1, 64800, 0xa0ead278
-0, 19, 19, 1, 64800, 0xbeced2d8
-0, 20, 20, 1, 64800, 0x85bbd7dc
-0, 21, 21, 1, 64800, 0xbe59ce34
-0, 22, 22, 1, 64800, 0xd76ecccc
-0, 23, 23, 1, 64800, 0xe182b474
-0, 24, 24, 1, 64800, 0x916cc394
-0, 25, 25, 1, 64800, 0x7efebd14
-0, 26, 26, 1, 64800, 0x8d28c9f0
-0, 27, 27, 1, 64800, 0x00a1c960
-0, 28, 28, 1, 64800, 0xc164c400
-0, 29, 29, 1, 64800, 0xfd4dc544
-0, 30, 30, 1, 64800, 0x01bfbe38
-0, 31, 31, 1, 64800, 0xff11b5d0
-0, 32, 32, 1, 64800, 0x4876bb20
-0, 33, 33, 1, 64800, 0x756ecb04
-0, 34, 34, 1, 64800, 0x3b8cd540
-0, 35, 35, 1, 64800, 0x063ed444
+0, 0, 0, 1, 64800, 0x63132a60
+0, 1, 1, 1, 64800, 0xb3c729a3
+0, 2, 2, 1, 64800, 0xa27b1e0e
+0, 3, 3, 1, 64800, 0xb9131d00
+0, 4, 4, 1, 64800, 0xaf9a1bae
+0, 5, 5, 1, 64800, 0x11e319c5
+0, 6, 6, 1, 64800, 0xee6e1e6b
+0, 7, 7, 1, 64800, 0x418417e9
+0, 8, 8, 1, 64800, 0x339d29f4
+0, 9, 9, 1, 64800, 0x198926c4
+0, 10, 10, 1, 64800, 0x439a3044
+0, 11, 11, 1, 64800, 0x0a4e38e1
+0, 12, 12, 1, 64800, 0x6e043e7e
+0, 13, 13, 1, 64800, 0xde434533
+0, 14, 14, 1, 64800, 0xb58a4ad1
+0, 15, 15, 1, 64800, 0xaa105710
+0, 16, 16, 1, 64800, 0x1723440c
+0, 17, 17, 1, 64800, 0x3b064116
+0, 18, 18, 1, 64800, 0x853f38e4
+0, 19, 19, 1, 64800, 0x52f53917
+0, 20, 20, 1, 64800, 0xea363e5a
+0, 21, 21, 1, 64800, 0x4d0a344e
+0, 22, 22, 1, 64800, 0xe49232fc
+0, 23, 23, 1, 64800, 0x747b1a02
+0, 24, 24, 1, 64800, 0xbaa82992
+0, 25, 25, 1, 64800, 0x8e9322db
+0, 26, 26, 1, 64800, 0x029a2fcf
+0, 27, 27, 1, 64800, 0xb9a62f6a
+0, 28, 28, 1, 64800, 0x553329fe
+0, 29, 29, 1, 64800, 0x9a052b5b
+0, 30, 30, 1, 64800, 0xe2ff2404
+0, 31, 31, 1, 64800, 0xaacd1b59
+0, 32, 32, 1, 64800, 0x17d820de
+0, 33, 33, 1, 64800, 0x1c9e312c
+0, 34, 34, 1, 64800, 0x84df3b99
+0, 35, 35, 1, 64800, 0xf7d13aa1
diff --git a/tests/ref/fate/crc b/tests/ref/fate/crc
index 80bb0eae4d..8aa0dd2448 100644
--- a/tests/ref/fate/crc
+++ b/tests/ref/fate/crc
@@ -1,5 +1,6 @@
crc EDB88320 = 3D5CDD04
crc 04C11DB7 = E0BAF5C0
+crc 00864CFB = 326039
crc 0000A001 = BFD8
crc 00008005 = BB1F
crc 00000007 = E3
diff --git a/tests/ref/fate/creatureshock-avs b/tests/ref/fate/creatureshock-avs
index 979baf61bb..4c721d8594 100644
--- a/tests/ref/fate/creatureshock-avs
+++ b/tests/ref/fate/creatureshock-avs
@@ -1,94 +1,94 @@
-#tb 0: 1/90000
+#tb 0: 1/15
#tb 1: 1/22222
-0, 0, 0, 0, 188892, 0xcb5be3dd
+0, 0, 0, 1, 188892, 0x9f47a5ec
1, 0, 0, 8186, 16372, 0xfaaab59d
-0, 6000, 6000, 0, 188892, 0x0f313ebc
-0, 12000, 12000, 0, 188892, 0xc0da25cc
-0, 18000, 18000, 0, 188892, 0xad6e1d44
-0, 24000, 24000, 0, 188892, 0xb1103b40
-0, 30000, 30000, 0, 188892, 0xae033450
+0, 1, 1, 1, 188892, 0xdece0269
+0, 2, 2, 1, 188892, 0xd097e86e
+0, 3, 3, 1, 188892, 0x1cf2de83
+0, 4, 4, 1, 188892, 0xb664fd10
+0, 5, 5, 1, 188892, 0xc654f4c1
1, 8186, 8186, 2014, 4028, 0xc2daed72
-0, 36000, 36000, 0, 188892, 0xb31f03b4
+0, 6, 6, 1, 188892, 0x5adac3ff
1, 10200, 10200, 2743, 5486, 0xf7fd794d
-0, 42000, 42000, 0, 188892, 0xacb2d3f9
-0, 48000, 48000, 0, 188892, 0x7d77ecbd
+0, 7, 7, 1, 188892, 0x5928954e
+0, 8, 8, 1, 188892, 0x5e4cad6c
1, 12943, 12943, 2895, 5790, 0xfd5a369f
-0, 54000, 54000, 0, 188892, 0x7faa2f6c
-0, 60000, 60000, 0, 188892, 0x28f4fdf1
+0, 9, 9, 1, 188892, 0xbbb5f11b
+0, 10, 10, 1, 188892, 0xcb6bbdee
1, 15838, 15838, 534, 1068, 0x0b602cd0
-0, 66000, 66000, 0, 188892, 0x4b53f3b9
+0, 11, 11, 1, 188892, 0xa5b3b316
1, 16372, 16372, 2454, 4908, 0xfe870aad
-0, 72000, 72000, 0, 188892, 0x1f09bb29
+0, 12, 12, 1, 188892, 0x9bf87b5d
1, 18826, 18826, 3031, 6062, 0x8a4d6e0f
-0, 78000, 78000, 0, 188892, 0x3afcc11d
-0, 84000, 84000, 0, 188892, 0x6b918e49
+0, 13, 13, 1, 188892, 0xcc3981be
+0, 14, 14, 1, 188892, 0x2eb44dfa
1, 21857, 21857, 2701, 5402, 0x71fd352f
-0, 90000, 90000, 0, 188892, 0x9630a04d
-0, 96000, 96000, 0, 188892, 0x9381b4c1
+0, 15, 15, 1, 188892, 0x11c861b9
+0, 16, 16, 1, 188892, 0x7c1b767b
1, 24558, 24558, 272, 544, 0xeb766d34
1, 24830, 24830, 2953, 5906, 0x47ac7e08
-0, 102000, 102000, 0, 188892, 0xa7dea7e5
-0, 108000, 108000, 0, 188892, 0xd277c41d
+0, 17, 17, 1, 188892, 0x5078694c
+0, 18, 18, 1, 188892, 0xa24485c2
1, 27783, 27783, 2958, 5916, 0x0d26eb56
-0, 114000, 114000, 0, 188892, 0xafa2a6c9
-0, 120000, 120000, 0, 188892, 0x13a38839
+0, 19, 19, 1, 188892, 0xc8016946
+0, 20, 20, 1, 188892, 0x71e3493b
1, 30741, 30741, 2003, 4006, 0x9941c71a
-0, 126000, 126000, 0, 188892, 0xcd5e5a6d
-0, 132000, 132000, 0, 188892, 0xe7da71e9
+0, 21, 21, 1, 188892, 0xa9771a0d
+0, 22, 22, 1, 188892, 0x98be33fd
1, 32744, 32744, 1050, 2100, 0xc9a2ee36
1, 33794, 33794, 2947, 5894, 0xd2ba4eaa
-0, 138000, 138000, 0, 188892, 0x06928add
-0, 144000, 144000, 0, 188892, 0x4a108eb9
+0, 23, 23, 1, 188892, 0x193e4cda
+0, 24, 24, 1, 188892, 0x3b444fd1
1, 36741, 36741, 3045, 6090, 0xf43e73d0
-0, 150000, 150000, 0, 188892, 0xea2598f5
-0, 156000, 156000, 0, 188892, 0x17ed6839
+0, 25, 25, 1, 188892, 0x8bfe594c
+0, 26, 26, 1, 188892, 0xaab8267b
1, 39786, 39786, 1144, 2288, 0x5a8b7aa0
-0, 162000, 162000, 0, 188892, 0x9de6ab65
+0, 27, 27, 1, 188892, 0x03206c55
1, 40930, 40930, 1925, 3850, 0x7f66eb2c
-0, 168000, 168000, 0, 188892, 0xb4ee326f
+0, 28, 28, 1, 188892, 0x8ed7ea7d
1, 42855, 42855, 2898, 5796, 0xc5cf3ee8
-0, 174000, 174000, 0, 188892, 0x3f85095b
-0, 180000, 180000, 0, 188892, 0xaab7e331
+0, 29, 29, 1, 188892, 0x2a1bc3e1
+0, 30, 30, 1, 188892, 0xa6a12aa7
1, 45753, 45753, 3021, 6042, 0xed80136d
-0, 186000, 186000, 0, 188892, 0xc2a079e1
-0, 192000, 192000, 0, 188892, 0x612080c2
+0, 31, 31, 1, 188892, 0xa96ca4fa
+0, 32, 32, 1, 188892, 0x3e3a6d70
1, 48774, 48774, 342, 684, 0xc42bd137
-0, 198000, 198000, 0, 188892, 0xa7232d47
+0, 33, 33, 1, 188892, 0x47e173dd
1, 49116, 49116, 2718, 5436, 0xb7f8a6fd
-0, 204000, 204000, 0, 188892, 0xc053297d
+0, 34, 34, 1, 188892, 0xfcf183ba
1, 51834, 51834, 3049, 6098, 0xee6354a2
-0, 210000, 210000, 0, 188892, 0x1ecc3bfe
-0, 216000, 216000, 0, 188892, 0xcc4ac803
-0, 222000, 222000, 0, 188892, 0x4b90047b
+0, 35, 35, 1, 188892, 0xf051be46
+0, 36, 36, 1, 188892, 0x8aa6b100
+0, 37, 37, 1, 188892, 0x36c86b01
1, 54883, 54883, 2419, 4838, 0x129e61d0
-0, 228000, 228000, 0, 188892, 0xd863b643
+0, 38, 38, 1, 188892, 0x15ae396e
1, 57302, 57302, 537, 1074, 0x9da90634
-0, 234000, 234000, 0, 188892, 0x93a25fb1
+0, 39, 39, 1, 188892, 0xc876eabf
1, 57839, 57839, 3042, 6084, 0x8ffed952
-0, 240000, 240000, 0, 188892, 0xf969e131
-0, 246000, 246000, 0, 188892, 0x73bd2469
+0, 40, 40, 1, 188892, 0xc5c65fae
+0, 41, 41, 1, 188892, 0x4feec932
1, 60881, 60881, 3019, 6038, 0xa07b4276
-0, 252000, 252000, 0, 188892, 0x265a9ce2
-0, 258000, 258000, 0, 188892, 0xd59ccd39
+0, 42, 42, 1, 188892, 0x21374e88
+0, 43, 43, 1, 188892, 0x52e689f1
1, 63900, 63900, 1588, 3176, 0xebef63c1
-0, 264000, 264000, 0, 188892, 0xe50fc068
+0, 44, 44, 1, 188892, 0x9e2492e8
1, 65488, 65488, 1397, 2794, 0xbe1000db
-0, 270000, 270000, 0, 188892, 0x83113a86
+0, 45, 45, 1, 188892, 0xac841247
1, 66885, 66885, 3010, 6020, 0xd8e34961
-0, 276000, 276000, 0, 188892, 0xa0203504
-0, 282000, 282000, 0, 188892, 0x9e2d518c
+0, 46, 46, 1, 188892, 0x8467aab2
+0, 47, 47, 1, 188892, 0x552b6029
1, 69895, 69895, 3010, 6020, 0xc07cf461
-0, 288000, 288000, 0, 188892, 0x5f610e66
-0, 294000, 294000, 0, 188892, 0x9b77f900
+0, 48, 48, 1, 188892, 0x836eb46e
+0, 49, 49, 1, 188892, 0x93eb9f1b
1, 72905, 72905, 769, 1538, 0xc975ae02
1, 73674, 73674, 2115, 4230, 0x0827111b
-0, 300000, 300000, 0, 188892, 0xaaf279c2
-0, 306000, 306000, 0, 188892, 0x4ac97cc2
+0, 50, 50, 1, 188892, 0xa3661fdd
+0, 51, 51, 1, 188892, 0x433d22dd
1, 75789, 75789, 3042, 6084, 0x2cf0a407
-0, 312000, 312000, 0, 188892, 0xddd91642
-0, 318000, 318000, 0, 188892, 0x4f32dcd1
+0, 52, 52, 1, 188892, 0xd64dbc4e
+0, 53, 53, 1, 188892, 0x4a2aa0e3
1, 78831, 78831, 2914, 5828, 0x12750279
-0, 324000, 324000, 0, 188892, 0xdc126b42
-0, 330000, 330000, 0, 188892, 0x00000000
+0, 54, 54, 1, 188892, 0xd98e4d4b
+0, 55, 55, 1, 188892, 0x00000000
1, 81745, 81745, 115, 230, 0xc9c03f3b
1, 81860, 81860, 384, 768, 0x6137a04d
diff --git a/tests/ref/fate/cvid-grayscale b/tests/ref/fate/cvid-grayscale
index 87ca600add..1b586b3dde 100644
--- a/tests/ref/fate/cvid-grayscale
+++ b/tests/ref/fate/cvid-grayscale
@@ -1,153 +1,153 @@
#tb 0: 99561/500000
-0, 0, 0, 1, 11300, 0x46c78923
-0, 1, 1, 1, 11300, 0x3f2a1175
-0, 2, 2, 1, 11300, 0x722de221
-0, 3, 3, 1, 11300, 0x01746b88
-0, 4, 4, 1, 11300, 0x549587a7
-0, 5, 5, 1, 11300, 0x843ab943
-0, 6, 6, 1, 11300, 0x62fdee48
-0, 7, 7, 1, 11300, 0x74a62867
-0, 8, 8, 1, 11300, 0x35a20e2f
-0, 9, 9, 1, 11300, 0x4e9ef54d
-0, 10, 10, 1, 11300, 0xec7201f5
-0, 11, 11, 1, 11300, 0x363bfe27
-0, 12, 12, 1, 11300, 0x2aaab418
-0, 13, 13, 1, 11300, 0x6a48ab3f
-0, 14, 14, 1, 11300, 0x3fecea34
-0, 15, 15, 1, 11300, 0xa371f55e
-0, 16, 16, 1, 11300, 0xa86b147c
-0, 17, 17, 1, 11300, 0x49e9206e
-0, 18, 18, 1, 11300, 0x6c9a2155
-0, 19, 19, 1, 11300, 0x2c8a4798
-0, 20, 20, 1, 11300, 0x3485676c
-0, 21, 21, 1, 11300, 0xb0b293f2
-0, 22, 22, 1, 11300, 0xe4a9b068
-0, 23, 23, 1, 11300, 0xd68d0556
-0, 24, 24, 1, 11300, 0xc28e5193
-0, 25, 25, 1, 11300, 0xf6948483
-0, 26, 26, 1, 11300, 0xf21fbf57
-0, 27, 27, 1, 11300, 0x8345eb44
-0, 28, 28, 1, 11300, 0x8124f045
-0, 29, 29, 1, 11300, 0x18e31f10
-0, 30, 30, 1, 11300, 0xdb1943fc
-0, 31, 31, 1, 11300, 0x8701699f
-0, 32, 32, 1, 11300, 0xd7b18550
-0, 33, 33, 1, 11300, 0xa56faccc
-0, 34, 34, 1, 11300, 0xf8bcc17c
-0, 35, 35, 1, 11300, 0x446acab9
-0, 36, 36, 1, 11300, 0x755fd295
-0, 37, 37, 1, 11300, 0x92e3d100
-0, 38, 38, 1, 11300, 0x54895bb3
-0, 39, 39, 1, 11300, 0xd18bffda
-0, 40, 40, 1, 11300, 0x480dbe4f
-0, 41, 41, 1, 11300, 0x49ea9dbe
-0, 42, 42, 1, 11300, 0x00d3a003
-0, 43, 43, 1, 11300, 0xda7bbfb2
-0, 44, 44, 1, 11300, 0x9700d9c2
-0, 45, 45, 1, 11300, 0xa0a9e490
-0, 46, 46, 1, 11300, 0x00eb0979
-0, 47, 47, 1, 11300, 0x32b04630
-0, 48, 48, 1, 11300, 0xdfb73e51
-0, 49, 49, 1, 11300, 0x3d8e4f96
-0, 50, 50, 1, 11300, 0x2ca83271
-0, 51, 51, 1, 11300, 0xb5b123c0
-0, 52, 52, 1, 11300, 0x8a570e58
-0, 53, 53, 1, 11300, 0xc6c805bc
-0, 54, 54, 1, 11300, 0x27caf7a5
-0, 55, 55, 1, 11300, 0x5319ecb0
-0, 56, 56, 1, 11300, 0x5471e3fd
-0, 57, 57, 1, 11300, 0x6d68a6f4
-0, 58, 58, 1, 11300, 0x872b7194
-0, 59, 59, 1, 11300, 0x007c36bd
-0, 60, 60, 1, 11300, 0x2714f1b5
-0, 61, 61, 1, 11300, 0x6c8eb50f
-0, 62, 62, 1, 11300, 0xf5d57be8
-0, 63, 63, 1, 11300, 0x981f412b
-0, 64, 64, 1, 11300, 0x1a9804a1
-0, 65, 65, 1, 11300, 0xf0c1d24a
-0, 66, 66, 1, 11300, 0xa70a9d9b
-0, 67, 67, 1, 11300, 0x8c466876
-0, 68, 68, 1, 11300, 0xcf2e32df
-0, 69, 69, 1, 11300, 0xcb8cfebf
-0, 70, 70, 1, 11300, 0xb961ca99
-0, 71, 71, 1, 11300, 0x666d9619
-0, 72, 72, 1, 11300, 0x84bf5b55
-0, 73, 73, 1, 11300, 0xbfa22ccc
-0, 74, 74, 1, 11300, 0xcde41849
-0, 75, 75, 1, 11300, 0x71372dcd
-0, 76, 76, 1, 11300, 0x13402cfd
-0, 77, 77, 1, 11300, 0xdebdd321
-0, 78, 78, 1, 11300, 0xdda66de1
-0, 79, 79, 1, 11300, 0x7f4bb682
-0, 80, 80, 1, 11300, 0xf67fd528
-0, 81, 81, 1, 11300, 0xe739ff8c
-0, 82, 82, 1, 11300, 0x2e131774
-0, 83, 83, 1, 11300, 0xfa942811
-0, 84, 84, 1, 11300, 0x0cd93ac2
-0, 85, 85, 1, 11300, 0xd0445e0e
-0, 86, 86, 1, 11300, 0x3f3497c7
-0, 87, 87, 1, 11300, 0x11b5bd2c
-0, 88, 88, 1, 11300, 0xccd5e62a
-0, 89, 89, 1, 11300, 0xa9d4fcb5
-0, 90, 90, 1, 11300, 0x34aa1a03
-0, 91, 91, 1, 11300, 0x1ce6299e
-0, 92, 92, 1, 11300, 0x661c2745
-0, 93, 93, 1, 11300, 0x27d8a8b3
-0, 94, 94, 1, 11300, 0x9eb07467
-0, 95, 95, 1, 11300, 0x128374d2
-0, 96, 96, 1, 11300, 0x05c36ff5
-0, 97, 97, 1, 11300, 0x8a136bde
-0, 98, 98, 1, 11300, 0x15c47c99
-0, 99, 99, 1, 11300, 0xcc4a93f4
-0, 100, 100, 1, 11300, 0x19529b2b
-0, 101, 101, 1, 11300, 0x9943c076
-0, 102, 102, 1, 11300, 0xf898e583
-0, 103, 103, 1, 11300, 0x40f71f94
-0, 104, 104, 1, 11300, 0x5b604afb
-0, 105, 105, 1, 11300, 0x8c176af4
-0, 106, 106, 1, 11300, 0x0f1a6216
-0, 107, 107, 1, 11300, 0x38bbd13d
-0, 108, 108, 1, 11300, 0x90c8d1fc
-0, 109, 109, 1, 11300, 0x253000d7
-0, 110, 110, 1, 11300, 0xb94b03b1
-0, 111, 111, 1, 11300, 0xbc872268
-0, 112, 112, 1, 11300, 0xe77adb8c
-0, 113, 113, 1, 11300, 0xa38936b7
-0, 114, 114, 1, 11300, 0xd6153632
-0, 115, 115, 1, 11300, 0x1ae633cc
-0, 116, 116, 1, 11300, 0xb90c286e
-0, 117, 117, 1, 11300, 0xbc7e333d
-0, 118, 118, 1, 11300, 0x1b5421f8
-0, 119, 119, 1, 11300, 0xdde6506d
-0, 120, 120, 1, 11300, 0xd3eb757e
-0, 121, 121, 1, 11300, 0x5ad1929c
-0, 122, 122, 1, 11300, 0x4f6aa47d
-0, 123, 123, 1, 11300, 0xab3caf55
-0, 124, 124, 1, 11300, 0x5ff9b39a
-0, 125, 125, 1, 11300, 0x1454e12e
-0, 126, 126, 1, 11300, 0xf18216e8
-0, 127, 127, 1, 11300, 0x62144880
-0, 128, 128, 1, 11300, 0x54284241
-0, 129, 129, 1, 11300, 0x8e8c7228
-0, 130, 130, 1, 11300, 0xb498d06e
-0, 131, 131, 1, 11300, 0x7b1e6be1
-0, 132, 132, 1, 11300, 0x5e5ea1f4
-0, 133, 133, 1, 11300, 0x41eda28e
-0, 134, 134, 1, 11300, 0x7ba6aa92
-0, 135, 135, 1, 11300, 0xa8a8b1c7
-0, 136, 136, 1, 11300, 0x0d30bd08
-0, 137, 137, 1, 11300, 0xc610bf16
-0, 138, 138, 1, 11300, 0xed57c075
-0, 139, 139, 1, 11300, 0xb86dbfea
-0, 140, 140, 1, 11300, 0x0970c03d
-0, 141, 141, 1, 11300, 0x743ac2ac
-0, 142, 142, 1, 11300, 0x0a44c816
-0, 143, 143, 1, 11300, 0xe32acd6b
-0, 144, 144, 1, 11300, 0x209bcdab
-0, 145, 145, 1, 11300, 0x3cd0d105
-0, 146, 146, 1, 11300, 0xc0bcd330
-0, 147, 147, 1, 11300, 0x4785d6dc
-0, 148, 148, 1, 11300, 0xe85f9c90
-0, 149, 149, 1, 11300, 0xd4a72850
-0, 150, 150, 1, 11300, 0x04766e41
-0, 151, 151, 1, 11300, 0x04766e41
+0, 0, 0, 1, 22500, 0x0f8e562e
+0, 1, 1, 1, 22500, 0x507aef06
+0, 2, 2, 1, 22500, 0x059d6137
+0, 3, 3, 1, 22500, 0xfb1bfd4e
+0, 4, 4, 1, 22500, 0xe97a51ba
+0, 5, 5, 1, 22500, 0xfc77e68e
+0, 6, 6, 1, 22500, 0x7f1985ac
+0, 7, 7, 1, 22500, 0xdfb933eb
+0, 8, 8, 1, 22500, 0x6dafe534
+0, 9, 9, 1, 22500, 0xb7b69abb
+0, 10, 10, 1, 22500, 0xc435c086
+0, 11, 11, 1, 22500, 0xf8ddb549
+0, 12, 12, 1, 22500, 0x76c0d70d
+0, 13, 13, 1, 22500, 0x1120bc82
+0, 14, 14, 1, 22500, 0x3f7c7970
+0, 15, 15, 1, 22500, 0xd37c9aee
+0, 16, 16, 1, 22500, 0x7407f81b
+0, 17, 17, 1, 22500, 0xce2f1c00
+0, 18, 18, 1, 22500, 0x70921eb5
+0, 19, 19, 1, 22500, 0x0abc917e
+0, 20, 20, 1, 22500, 0xeff1f0fa
+0, 21, 21, 1, 22500, 0x5e0d769b
+0, 22, 22, 1, 22500, 0xc984cbfd
+0, 23, 23, 1, 22500, 0x73f1caa9
+0, 24, 24, 1, 22500, 0x9108af6f
+0, 25, 25, 1, 22500, 0x4f33484e
+0, 26, 26, 1, 22500, 0x9810f8ca
+0, 27, 27, 1, 22500, 0xa0b97ca0
+0, 28, 28, 1, 22500, 0xd9c28ba3
+0, 29, 29, 1, 22500, 0xc97e17e6
+0, 30, 30, 1, 22500, 0x85cf86aa
+0, 31, 31, 1, 22500, 0xf15ff793
+0, 32, 32, 1, 22500, 0x35c54ab5
+0, 33, 33, 1, 22500, 0xe80ec129
+0, 34, 34, 1, 22500, 0x3d6cff39
+0, 35, 35, 1, 22500, 0x54e41aff
+0, 36, 36, 1, 22500, 0xc1d63293
+0, 37, 37, 1, 22500, 0x362c2dd4
+0, 38, 38, 1, 22500, 0xa1f8cdcf
+0, 39, 39, 1, 22500, 0x5b59ba62
+0, 40, 40, 1, 22500, 0x6d02f5b2
+0, 41, 41, 1, 22500, 0x899293ff
+0, 42, 42, 1, 22500, 0xad0e9ace
+0, 43, 43, 1, 22500, 0x4263f9db
+0, 44, 44, 1, 22500, 0xff1e481a
+0, 45, 45, 1, 22500, 0x70c86884
+0, 46, 46, 1, 22500, 0x203ed712
+0, 47, 47, 1, 22500, 0x2f0e8d46
+0, 48, 48, 1, 22500, 0x215075a9
+0, 49, 49, 1, 22500, 0x9882a978
+0, 50, 50, 1, 22500, 0xc2fd5209
+0, 51, 51, 1, 22500, 0xe1c925f6
+0, 52, 52, 1, 22500, 0x012be5af
+0, 53, 53, 1, 22500, 0xa718cbdb
+0, 54, 54, 1, 22500, 0x2494a1c3
+0, 55, 55, 1, 22500, 0xeb8980e4
+0, 56, 56, 1, 22500, 0x7f2766cb
+0, 57, 57, 1, 22500, 0xdf3cafa1
+0, 58, 58, 1, 22500, 0x9a390f81
+0, 59, 59, 1, 22500, 0xfdad5eed
+0, 60, 60, 1, 22500, 0x94f58ff3
+0, 61, 61, 1, 22500, 0xd7c6d9f2
+0, 62, 62, 1, 22500, 0x48b72e7d
+0, 63, 63, 1, 22500, 0x8a7a7e37
+0, 64, 64, 1, 22500, 0x5413c88a
+0, 65, 65, 1, 22500, 0x3f4531b2
+0, 66, 66, 1, 22500, 0x152d9396
+0, 67, 67, 1, 22500, 0x2ac3f418
+0, 68, 68, 1, 22500, 0x0e1c5353
+0, 69, 69, 1, 22500, 0xe058b711
+0, 70, 70, 1, 22500, 0x262e1a9f
+0, 71, 71, 1, 22500, 0x20057d10
+0, 72, 72, 1, 22500, 0x65c5ccb5
+0, 73, 73, 1, 22500, 0x3e36411a
+0, 74, 74, 1, 22500, 0xd9740391
+0, 75, 75, 1, 22500, 0x53d1441d
+0, 76, 76, 1, 22500, 0x9a3941ad
+0, 77, 77, 1, 22500, 0x61553437
+0, 78, 78, 1, 22500, 0xfe0c0468
+0, 79, 79, 1, 22500, 0xd57bde4b
+0, 80, 80, 1, 22500, 0x4a183a4c
+0, 81, 81, 1, 22500, 0xd618b978
+0, 82, 82, 1, 22500, 0x6b480112
+0, 83, 83, 1, 22500, 0x7a1732e9
+0, 84, 84, 1, 22500, 0x45836afc
+0, 85, 85, 1, 22500, 0x3548d4e0
+0, 86, 86, 1, 22500, 0x476c821a
+0, 87, 87, 1, 22500, 0x6be5f249
+0, 88, 88, 1, 22500, 0xf79b6d52
+0, 89, 89, 1, 22500, 0x2edeb0f3
+0, 90, 90, 1, 22500, 0xbaf808bf
+0, 91, 91, 1, 22500, 0x71013790
+0, 92, 92, 1, 22500, 0xbf4e3085
+0, 93, 93, 1, 22500, 0x15c2b4de
+0, 94, 94, 1, 22500, 0x031d17fa
+0, 95, 95, 1, 22500, 0x3a2c193b
+0, 96, 96, 1, 22500, 0xb0420aa4
+0, 97, 97, 1, 22500, 0xe448fe50
+0, 98, 98, 1, 22500, 0x02173090
+0, 99, 99, 1, 22500, 0x4b2f76a1
+0, 100, 100, 1, 22500, 0xd6458c46
+0, 101, 101, 1, 22500, 0xa698fc27
+0, 102, 102, 1, 22500, 0xaeca6b5d
+0, 103, 103, 1, 22500, 0x4a591972
+0, 104, 104, 1, 22500, 0x19e49ba7
+0, 105, 105, 1, 22500, 0x1d4ffb92
+0, 106, 106, 1, 22500, 0xb1f8e0f8
+0, 107, 107, 1, 22500, 0x32c82e8b
+0, 108, 108, 1, 22500, 0x96e930c8
+0, 109, 109, 1, 22500, 0x0e6ebd2c
+0, 110, 110, 1, 22500, 0x315bc5ba
+0, 111, 111, 1, 22500, 0xb22321ee
+0, 112, 112, 1, 22500, 0xbe464d78
+0, 113, 113, 1, 22500, 0xdb4b5edb
+0, 114, 114, 1, 22500, 0x0ff65d4c
+0, 115, 115, 1, 22500, 0xff68561a
+0, 116, 116, 1, 22500, 0xa0033400
+0, 117, 117, 1, 22500, 0x5414546d
+0, 118, 118, 1, 22500, 0x7e43209e
+0, 119, 119, 1, 22500, 0x0037abfd
+0, 120, 120, 1, 22500, 0x3dd31b3f
+0, 121, 121, 1, 22500, 0xe0777299
+0, 122, 122, 1, 22500, 0x35a2a83c
+0, 123, 123, 1, 22500, 0x5282c8c4
+0, 124, 124, 1, 22500, 0x1ccdd593
+0, 125, 125, 1, 22500, 0x92525e5e
+0, 126, 126, 1, 22500, 0x5fa3ff5f
+0, 127, 127, 1, 22500, 0xd1169436
+0, 128, 128, 1, 22500, 0x07dc8179
+0, 129, 129, 1, 22500, 0x9a83113d
+0, 130, 130, 1, 22500, 0x9c722c1e
+0, 131, 131, 1, 22500, 0xccbcfe59
+0, 132, 132, 1, 22500, 0x8606a0a1
+0, 133, 133, 1, 22500, 0x2210a26f
+0, 134, 134, 1, 22500, 0xfc73ba7b
+0, 135, 135, 1, 22500, 0x731fd01a
+0, 136, 136, 1, 22500, 0x0e21f1dd
+0, 137, 137, 1, 22500, 0xf9c4f807
+0, 138, 138, 1, 22500, 0x2123fc24
+0, 139, 139, 1, 22500, 0xd42cfa83
+0, 140, 140, 1, 22500, 0x5927fb7c
+0, 141, 141, 1, 22500, 0xe32e02d8
+0, 142, 142, 1, 22500, 0xa5c11316
+0, 143, 143, 1, 22500, 0xb9112315
+0, 144, 144, 1, 22500, 0x78f223d5
+0, 145, 145, 1, 22500, 0x93202de3
+0, 146, 146, 1, 22500, 0x7eb03464
+0, 147, 147, 1, 22500, 0x899c3f68
+0, 148, 148, 1, 22500, 0xc2169075
+0, 149, 149, 1, 22500, 0x419f33a6
+0, 150, 150, 1, 22500, 0x3de50588
+0, 151, 151, 1, 22500, 0x3de50588
diff --git a/tests/ref/fate/cvid-palette b/tests/ref/fate/cvid-palette
index 5fcbc5153c..49de1c1a05 100644
--- a/tests/ref/fate/cvid-palette
+++ b/tests/ref/fate/cvid-palette
@@ -1,57 +1,57 @@
-#tb 0: 1/14985
-0, 0, 0, 0, 57600, 0x1f5c89b7
-0, 1000, 1000, 0, 57600, 0xd2055aaf
-0, 2000, 2000, 0, 57600, 0x22336052
-0, 3000, 3000, 0, 57600, 0xf7135e2a
-0, 4000, 4000, 0, 57600, 0xd9de126a
-0, 5000, 5000, 0, 57600, 0xe5a9e1de
-0, 6000, 6000, 0, 57600, 0x253f1702
-0, 7000, 7000, 0, 57600, 0xcb8679c9
-0, 8000, 8000, 0, 57600, 0x96cb5fa8
-0, 9000, 9000, 0, 57600, 0xbe03528a
-0, 10000, 10000, 0, 57600, 0x120a097d
-0, 11000, 11000, 0, 57600, 0xaf562041
-0, 12000, 12000, 0, 57600, 0x15b2d8c9
-0, 13000, 13000, 0, 57600, 0x95f60e58
-0, 14000, 14000, 0, 57600, 0x5ace5a6b
-0, 15000, 15000, 0, 57600, 0x2f80b8e3
-0, 16000, 16000, 0, 57600, 0x5c49c915
-0, 17000, 17000, 0, 57600, 0xb91efe60
-0, 18000, 18000, 0, 57600, 0xa80d29e8
-0, 19000, 19000, 0, 57600, 0x6e72d03a
-0, 20000, 20000, 0, 57600, 0x4f716a9e
-0, 21000, 21000, 0, 57600, 0x3a43b9c9
-0, 22000, 22000, 0, 57600, 0x65002db3
-0, 23000, 23000, 0, 57600, 0x70edc765
-0, 24000, 24000, 0, 57600, 0x9dc54abd
-0, 25000, 25000, 0, 57600, 0xd17bda86
-0, 26000, 26000, 0, 57600, 0xc5d2d458
-0, 27000, 27000, 0, 57600, 0x32313c79
-0, 28000, 28000, 0, 57600, 0x2e537e8d
-0, 29000, 29000, 0, 57600, 0xe77d5d9e
-0, 30000, 30000, 0, 57600, 0x9cc2599a
-0, 31000, 31000, 0, 57600, 0x8a9be76e
-0, 32000, 32000, 0, 57600, 0x47447eef
-0, 33000, 33000, 0, 57600, 0xbf5f84fa
-0, 34000, 34000, 0, 57600, 0xacd49c07
-0, 35000, 35000, 0, 57600, 0xdc628975
-0, 36000, 36000, 0, 57600, 0x97d7964e
-0, 37000, 37000, 0, 57600, 0xd0a19b6b
-0, 38000, 38000, 0, 57600, 0x5ea3d78c
-0, 39000, 39000, 0, 57600, 0x39b59be0
-0, 40000, 40000, 0, 57600, 0x6501a2d2
-0, 41000, 41000, 0, 57600, 0x0ee7e36d
-0, 42000, 42000, 0, 57600, 0x354ddd1d
-0, 43000, 43000, 0, 57600, 0x9b8f22d3
-0, 44000, 44000, 0, 57600, 0x0aadfb8c
-0, 45000, 45000, 0, 57600, 0x322e2785
-0, 46000, 46000, 0, 57600, 0x78a6467e
-0, 47000, 47000, 0, 57600, 0x1757f3b1
-0, 48000, 48000, 0, 57600, 0xe874ceb7
-0, 49000, 49000, 0, 57600, 0xc40f9e4d
-0, 50000, 50000, 0, 57600, 0x89f6a735
-0, 51000, 51000, 0, 57600, 0xe3635393
-0, 52000, 52000, 0, 57600, 0xdae585c7
-0, 53000, 53000, 0, 57600, 0xf99baa60
-0, 54000, 54000, 0, 57600, 0x28a8b1ee
-0, 55000, 55000, 0, 57600, 0xcd5587f8
+#tb 0: 200/2997
+0, 0, 0, 1, 57600, 0x1f5c89b7
+0, 1, 1, 1, 57600, 0xd2055aaf
+0, 2, 2, 1, 57600, 0x22336052
+0, 3, 3, 1, 57600, 0xf7135e2a
+0, 4, 4, 1, 57600, 0xd9de126a
+0, 5, 5, 1, 57600, 0xe5a9e1de
+0, 6, 6, 1, 57600, 0x253f1702
+0, 7, 7, 1, 57600, 0xcb8679c9
+0, 8, 8, 1, 57600, 0x96cb5fa8
+0, 9, 9, 1, 57600, 0xbe03528a
+0, 10, 10, 1, 57600, 0x120a097d
+0, 11, 11, 1, 57600, 0xaf562041
+0, 12, 12, 1, 57600, 0x15b2d8c9
+0, 13, 13, 1, 57600, 0x95f60e58
+0, 14, 14, 1, 57600, 0x5ace5a6b
+0, 15, 15, 1, 57600, 0x2f80b8e3
+0, 16, 16, 1, 57600, 0x5c49c915
+0, 17, 17, 1, 57600, 0xb91efe60
+0, 18, 18, 1, 57600, 0xa80d29e8
+0, 19, 19, 1, 57600, 0x6e72d03a
+0, 20, 20, 1, 57600, 0x4f716a9e
+0, 21, 21, 1, 57600, 0x3a43b9c9
+0, 22, 22, 1, 57600, 0x65002db3
+0, 23, 23, 1, 57600, 0x70edc765
+0, 24, 24, 1, 57600, 0x9dc54abd
+0, 25, 25, 1, 57600, 0xd17bda86
+0, 26, 26, 1, 57600, 0xc5d2d458
+0, 27, 27, 1, 57600, 0x32313c79
+0, 28, 28, 1, 57600, 0x2e537e8d
+0, 29, 29, 1, 57600, 0xe77d5d9e
+0, 30, 30, 1, 57600, 0x9cc2599a
+0, 31, 31, 1, 57600, 0x8a9be76e
+0, 32, 32, 1, 57600, 0x47447eef
+0, 33, 33, 1, 57600, 0xbf5f84fa
+0, 34, 34, 1, 57600, 0xacd49c07
+0, 35, 35, 1, 57600, 0xdc628975
+0, 36, 36, 1, 57600, 0x97d7964e
+0, 37, 37, 1, 57600, 0xd0a19b6b
+0, 38, 38, 1, 57600, 0x5ea3d78c
+0, 39, 39, 1, 57600, 0x39b59be0
+0, 40, 40, 1, 57600, 0x6501a2d2
+0, 41, 41, 1, 57600, 0x0ee7e36d
+0, 42, 42, 1, 57600, 0x354ddd1d
+0, 43, 43, 1, 57600, 0x9b8f22d3
+0, 44, 44, 1, 57600, 0x0aadfb8c
+0, 45, 45, 1, 57600, 0x322e2785
+0, 46, 46, 1, 57600, 0x78a6467e
+0, 47, 47, 1, 57600, 0x1757f3b1
+0, 48, 48, 1, 57600, 0xe874ceb7
+0, 49, 49, 1, 57600, 0xc40f9e4d
+0, 50, 50, 1, 57600, 0x89f6a735
+0, 51, 51, 1, 57600, 0xe3635393
+0, 52, 52, 1, 57600, 0xdae585c7
+0, 53, 53, 1, 57600, 0xf99baa60
+0, 54, 54, 1, 57600, 0x28a8b1ee
+0, 55, 55, 1, 57600, 0xcd5587f8
diff --git a/tests/ref/fate/cvid-partial b/tests/ref/fate/cvid-partial
index 907ef4a5d2..bb368a1eae 100644
--- a/tests/ref/fate/cvid-partial
+++ b/tests/ref/fate/cvid-partial
@@ -1,80 +1,80 @@
#tb 0: 1/12
-0, 0, 0, 1, 112400, 0x829180d8
-0, 1, 1, 1, 112400, 0xdbebac5b
-0, 2, 2, 1, 112400, 0xc5adc0f7
-0, 3, 3, 1, 112400, 0xbe1fc030
-0, 4, 4, 1, 112400, 0xe08ab460
-0, 5, 5, 1, 112400, 0xfde0dbc5
-0, 6, 6, 1, 112400, 0xed9242b0
-0, 7, 7, 1, 112400, 0x1ae3933a
-0, 8, 8, 1, 112400, 0xc82d2f5b
-0, 9, 9, 1, 112400, 0xbae9ddfc
-0, 10, 10, 1, 112400, 0xa350a1f7
-0, 11, 11, 1, 112400, 0x3cf78029
-0, 12, 12, 1, 112400, 0xaa0b82bf
-0, 13, 13, 1, 112400, 0x71aa4794
-0, 14, 14, 1, 112400, 0x2fe57373
-0, 15, 15, 1, 112400, 0x429c6f82
-0, 16, 16, 1, 112400, 0xfb2d917d
-0, 17, 17, 1, 112400, 0xcc84cb9a
-0, 18, 18, 1, 112400, 0xc68f0613
-0, 19, 19, 1, 112400, 0x05f30e6a
-0, 20, 20, 1, 112400, 0x5c5d853d
-0, 21, 21, 1, 112400, 0x01e0aff2
-0, 22, 22, 1, 112400, 0xc3b2cf4a
-0, 23, 23, 1, 112400, 0xc0a3cf19
-0, 24, 24, 1, 112400, 0xc743abda
-0, 25, 25, 1, 112400, 0x54bd17a2
-0, 26, 26, 1, 112400, 0x616ef28d
-0, 27, 27, 1, 112400, 0x04b51f59
-0, 28, 28, 1, 112400, 0x857511a2
-0, 29, 29, 1, 112400, 0x25c62440
-0, 30, 30, 1, 112400, 0x8c78198d
-0, 31, 31, 1, 112400, 0xc046c912
-0, 32, 32, 1, 112400, 0x0d828630
-0, 33, 33, 1, 112400, 0x48999b80
-0, 34, 34, 1, 112400, 0x9a869e77
-0, 35, 35, 1, 112400, 0x16d893df
-0, 36, 36, 1, 112400, 0xf6b86132
-0, 37, 37, 1, 112400, 0xfa564ea4
-0, 38, 38, 1, 112400, 0xdd473f69
-0, 39, 39, 1, 112400, 0xf89625a6
-0, 40, 40, 1, 112400, 0x823a58aa
-0, 41, 41, 1, 112400, 0x25e0fe43
-0, 42, 42, 1, 112400, 0x41034522
-0, 43, 43, 1, 112400, 0xb8da4f00
-0, 44, 44, 1, 112400, 0x9f684fce
-0, 45, 45, 1, 112400, 0xf7188710
-0, 46, 46, 1, 112400, 0x428fbfc6
-0, 47, 47, 1, 112400, 0x535bace0
-0, 48, 48, 1, 112400, 0x23216059
-0, 49, 49, 1, 112400, 0x9b8bbfa6
-0, 50, 50, 1, 112400, 0x932be522
-0, 51, 51, 1, 112400, 0xdbd31409
-0, 52, 52, 1, 112400, 0x0a69bf18
-0, 53, 53, 1, 112400, 0xa15ef128
-0, 54, 54, 1, 112400, 0x49a1fa92
-0, 55, 55, 1, 112400, 0xadeeaf62
-0, 56, 56, 1, 112400, 0xc1ce636e
-0, 57, 57, 1, 112400, 0x5ca544eb
-0, 58, 58, 1, 112400, 0x07230a36
-0, 59, 59, 1, 112400, 0x12ae2b53
-0, 60, 60, 1, 112400, 0x62453ef6
-0, 61, 61, 1, 112400, 0xe0588a98
-0, 62, 62, 1, 112400, 0xacd3927a
-0, 63, 63, 1, 112400, 0x5d3c6b01
-0, 64, 64, 1, 112400, 0xda671808
-0, 65, 65, 1, 112400, 0x61d0b492
-0, 66, 66, 1, 112400, 0x068b1293
-0, 67, 67, 1, 112400, 0x75b99287
-0, 68, 68, 1, 112400, 0xe657e7d6
-0, 69, 69, 1, 112400, 0x17873df6
-0, 70, 70, 1, 112400, 0xa8db5e31
-0, 71, 71, 1, 112400, 0x4f633b8e
-0, 72, 72, 1, 112400, 0x22266252
-0, 73, 73, 1, 112400, 0x308a6282
-0, 74, 74, 1, 112400, 0xfdb356ce
-0, 75, 75, 1, 112400, 0xe4394f1f
-0, 76, 76, 1, 112400, 0x8ca8649f
-0, 77, 77, 1, 112400, 0x804d44eb
-0, 78, 78, 1, 112400, 0x3864488b
+0, 0, 0, 1, 224400, 0xd8f2f310
+0, 1, 1, 1, 224400, 0xe38676c2
+0, 2, 2, 1, 224400, 0x7163b6ad
+0, 3, 3, 1, 224400, 0xa514b0f7
+0, 4, 4, 1, 224400, 0xeed48b96
+0, 5, 5, 1, 224400, 0x5e9f02b2
+0, 6, 6, 1, 224400, 0x70822c53
+0, 7, 7, 1, 224400, 0x93101067
+0, 8, 8, 1, 224400, 0x0710e900
+0, 9, 9, 1, 224400, 0x0e8add6a
+0, 10, 10, 1, 224400, 0x53fb2c5a
+0, 11, 11, 1, 224400, 0xa58cc02f
+0, 12, 12, 1, 224400, 0x0a5cc76b
+0, 13, 13, 1, 224400, 0xfa551631
+0, 14, 14, 1, 224400, 0xde9f99bf
+0, 15, 15, 1, 224400, 0xe66a8690
+0, 16, 16, 1, 224400, 0xd9e6f3d1
+0, 17, 17, 1, 224400, 0xa479a5c6
+0, 18, 18, 1, 224400, 0xdaa3531f
+0, 19, 19, 1, 224400, 0xde3e6843
+0, 20, 20, 1, 224400, 0x181adafd
+0, 21, 21, 1, 224400, 0x784b6429
+0, 22, 22, 1, 224400, 0x91cdc30e
+0, 23, 23, 1, 224400, 0x6e78be49
+0, 24, 24, 1, 224400, 0x7515644c
+0, 25, 25, 1, 224400, 0xcc32a91b
+0, 26, 26, 1, 224400, 0xc63e3831
+0, 27, 27, 1, 224400, 0xfb53b651
+0, 28, 28, 1, 224400, 0x12ec8a01
+0, 29, 29, 1, 224400, 0x136fcb2c
+0, 30, 30, 1, 224400, 0x827fa546
+0, 31, 31, 1, 224400, 0x1773b7f5
+0, 32, 32, 1, 224400, 0x732defc1
+0, 33, 33, 1, 224400, 0x84292372
+0, 34, 34, 1, 224400, 0x20f22365
+0, 35, 35, 1, 224400, 0xb39a0700
+0, 36, 36, 1, 224400, 0xf245706c
+0, 37, 37, 1, 224400, 0xdb702ae7
+0, 38, 38, 1, 224400, 0xadfefe5b
+0, 39, 39, 1, 224400, 0xa667adcb
+0, 40, 40, 1, 224400, 0x4d645191
+0, 41, 41, 1, 224400, 0x33802f58
+0, 42, 42, 1, 224400, 0x24eff4b8
+0, 43, 43, 1, 224400, 0x4dc817a6
+0, 44, 44, 1, 224400, 0x9a891d35
+0, 45, 45, 1, 224400, 0x2d0bb83b
+0, 46, 46, 1, 224400, 0xd13469c1
+0, 47, 47, 1, 224400, 0xd2e6302a
+0, 48, 48, 1, 224400, 0xc7594ee1
+0, 49, 49, 1, 224400, 0xc6da714c
+0, 50, 50, 1, 224400, 0xf675e838
+0, 51, 51, 1, 224400, 0xdc047c76
+0, 52, 52, 1, 224400, 0xe5727de5
+0, 53, 53, 1, 224400, 0x153b0f62
+0, 54, 54, 1, 224400, 0x65922f68
+0, 55, 55, 1, 224400, 0x04e04bfb
+0, 56, 56, 1, 224400, 0x1dde6c88
+0, 57, 57, 1, 224400, 0xed3905f2
+0, 58, 58, 1, 224400, 0x211a5996
+0, 59, 59, 1, 224400, 0xd010baaf
+0, 60, 60, 1, 224400, 0xcbc9f272
+0, 61, 61, 1, 224400, 0x7380d6f0
+0, 62, 62, 1, 224400, 0xfd0bf084
+0, 63, 63, 1, 224400, 0xc4d671d9
+0, 64, 64, 1, 224400, 0x84236aa5
+0, 65, 65, 1, 224400, 0x9c584ede
+0, 66, 66, 1, 224400, 0xdb0c6029
+0, 67, 67, 1, 224400, 0x775ae560
+0, 68, 68, 1, 224400, 0xe3800916
+0, 69, 69, 1, 224400, 0x9313a8e8
+0, 70, 70, 1, 224400, 0x3a5d07cc
+0, 71, 71, 1, 224400, 0x4651a10b
+0, 72, 72, 1, 224400, 0xc2d72183
+0, 73, 73, 1, 224400, 0xcd971625
+0, 74, 74, 1, 224400, 0x9fb0f3c2
+0, 75, 75, 1, 224400, 0x920ee561
+0, 76, 76, 1, 224400, 0x8a2c1bbf
+0, 77, 77, 1, 224400, 0x6150c072
+0, 78, 78, 1, 224400, 0x499dc869
diff --git a/tests/ref/fate/d-cinema-demux b/tests/ref/fate/d-cinema-demux
index f663040c17..2f28e46efe 100644
--- a/tests/ref/fate/d-cinema-demux
+++ b/tests/ref/fate/d-cinema-demux
@@ -2,4 +2,4 @@
0, 0, 0, 1875, 36000, 0xd592781d
0, 1875, 1875, 1875, 36000, 0xd592781d
0, 3750, 3750, 1875, 36000, 0xd592781d
-0, 5625, 5625, 1200, 23056, 0xde81f0d6
+0, 5625, 5625, 1200, 23056, 0xde81f0d6, F=0x3
diff --git a/tests/ref/fate/dfa1 b/tests/ref/fate/dfa1
index 92a7ccecea..7bc5bf1e48 100644
--- a/tests/ref/fate/dfa1
+++ b/tests/ref/fate/dfa1
@@ -1,26 +1,26 @@
#tb 0: 16/125
-0, 0, 0, 1, 921600, 0x2e2b3ca4
-0, 1, 1, 1, 921600, 0x0ff7a368
-0, 2, 2, 1, 921600, 0xf5f0dc50
-0, 3, 3, 1, 921600, 0x56cb0c9d
-0, 4, 4, 1, 921600, 0xb253228f
-0, 5, 5, 1, 921600, 0xefd3419e
-0, 6, 6, 1, 921600, 0x708c0ce7
-0, 7, 7, 1, 921600, 0x0b3a7f6d
-0, 8, 8, 1, 921600, 0x72db4eac
-0, 9, 9, 1, 921600, 0x94328111
-0, 10, 10, 1, 921600, 0x95f7b2f0
-0, 11, 11, 1, 921600, 0xdc3c9655
-0, 12, 12, 1, 921600, 0xfe03dec6
-0, 13, 13, 1, 921600, 0x2551dffb
-0, 14, 14, 1, 921600, 0xe8b37d9e
-0, 15, 15, 1, 921600, 0xad93508b
-0, 16, 16, 1, 921600, 0x5a1c4890
-0, 17, 17, 1, 921600, 0x6f972fb4
-0, 18, 18, 1, 921600, 0xa1d5ff95
-0, 19, 19, 1, 921600, 0x7bc5d07c
-0, 20, 20, 1, 921600, 0xc0311e4e
-0, 21, 21, 1, 921600, 0x5b02cc48
-0, 22, 22, 1, 921600, 0x8db4d5fa
-0, 23, 23, 1, 921600, 0x31aae769
-0, 24, 24, 1, 921600, 0xab62b9a7
+0, 0, 0, 1, 921600, 0xb69faa34
+0, 1, 1, 1, 921600, 0x38680829
+0, 2, 2, 1, 921600, 0xa7263c5a
+0, 3, 3, 1, 921600, 0xa784626a
+0, 4, 4, 1, 921600, 0xb4c47212
+0, 5, 5, 1, 921600, 0xd17285ea
+0, 6, 6, 1, 921600, 0xe9b33902
+0, 7, 7, 1, 921600, 0x215ea693
+0, 8, 8, 1, 921600, 0xe2ab6c7a
+0, 9, 9, 1, 921600, 0xf2867624
+0, 10, 10, 1, 921600, 0x607d78c1
+0, 11, 11, 1, 921600, 0x6e743bb7
+0, 12, 12, 1, 921600, 0x1fbf8f5a
+0, 13, 13, 1, 921600, 0xac6c912e
+0, 14, 14, 1, 921600, 0x556933bc
+0, 15, 15, 1, 921600, 0xda4c242b
+0, 16, 16, 1, 921600, 0xa6b32f83
+0, 17, 17, 1, 921600, 0x1ecc2996
+0, 18, 18, 1, 921600, 0xf1c3fc0f
+0, 19, 19, 1, 921600, 0x3f1db909
+0, 20, 20, 1, 921600, 0x7582fb93
+0, 21, 21, 1, 921600, 0x102ba261
+0, 22, 22, 1, 921600, 0xfbcf9de0
+0, 23, 23, 1, 921600, 0xe9ecb4d9
+0, 24, 24, 1, 921600, 0x7ee36a42
diff --git a/tests/ref/fate/dfa10 b/tests/ref/fate/dfa10
index a140e5c391..a799f03b22 100644
--- a/tests/ref/fate/dfa10
+++ b/tests/ref/fate/dfa10
@@ -1,9 +1,9 @@
#tb 0: 71/1000
-0, 0, 0, 1, 192000, 0xbabcbd55
-0, 1, 1, 1, 192000, 0xf00a5683
-0, 2, 2, 1, 192000, 0xcce90589
-0, 3, 3, 1, 192000, 0x8545631f
-0, 4, 4, 1, 192000, 0xd3ab654c
-0, 5, 5, 1, 192000, 0x5e0dda12
-0, 6, 6, 1, 192000, 0x7e94b053
-0, 7, 7, 1, 192000, 0x8027e68b
+0, 0, 0, 1, 192000, 0x7384f9b2
+0, 1, 1, 1, 192000, 0xd1f61c71
+0, 2, 2, 1, 192000, 0x0c6937d1
+0, 3, 3, 1, 192000, 0x56459a3a
+0, 4, 4, 1, 192000, 0x6d011790
+0, 5, 5, 1, 192000, 0xb5347ce8
+0, 6, 6, 1, 192000, 0xcd422568
+0, 7, 7, 1, 192000, 0xde4fef2d
diff --git a/tests/ref/fate/dfa11 b/tests/ref/fate/dfa11
index 3990d24cfc..30b4b71032 100644
--- a/tests/ref/fate/dfa11
+++ b/tests/ref/fate/dfa11
@@ -1,10 +1,10 @@
#tb 0: 71/1000
-0, 0, 0, 1, 192000, 0x8b8bd8de
-0, 1, 1, 1, 192000, 0xdac26ec2
-0, 2, 2, 1, 192000, 0x0fc01c28
-0, 3, 3, 1, 192000, 0x1251eef7
-0, 4, 4, 1, 192000, 0x89eced0e
-0, 5, 5, 1, 192000, 0x4943d821
-0, 6, 6, 1, 192000, 0x49258ec9
-0, 7, 7, 1, 192000, 0x9afd5881
-0, 8, 8, 1, 192000, 0xb322b901
+0, 0, 0, 1, 192000, 0x4269d703
+0, 1, 1, 1, 192000, 0xdf8667e7
+0, 2, 2, 1, 192000, 0x450026ad
+0, 3, 3, 1, 192000, 0x2528ea52
+0, 4, 4, 1, 192000, 0x83bcd1ec
+0, 5, 5, 1, 192000, 0x88d5ba27
+0, 6, 6, 1, 192000, 0x44424577
+0, 7, 7, 1, 192000, 0xd93f12a3
+0, 8, 8, 1, 192000, 0xcd625f3e
diff --git a/tests/ref/fate/dfa2 b/tests/ref/fate/dfa2
index a050c97d44..cc4b454fa9 100644
--- a/tests/ref/fate/dfa2
+++ b/tests/ref/fate/dfa2
@@ -1,18 +1,18 @@
#tb 0: 71/1000
-0, 0, 0, 1, 921600, 0x713f2da1
-0, 1, 1, 1, 921600, 0x9e772ec9
-0, 2, 2, 1, 921600, 0x9420310f
-0, 3, 3, 1, 921600, 0xd68f294f
-0, 4, 4, 1, 921600, 0xe25a1bcf
-0, 5, 5, 1, 921600, 0x32f903ec
-0, 6, 6, 1, 921600, 0xdb290b1c
-0, 7, 7, 1, 921600, 0x0b0d1b0f
-0, 8, 8, 1, 921600, 0x58430921
-0, 9, 9, 1, 921600, 0xe65dd39e
-0, 10, 10, 1, 921600, 0x146b3068
-0, 11, 11, 1, 921600, 0x6e1e7f78
-0, 12, 12, 1, 921600, 0x0166e01c
-0, 13, 13, 1, 921600, 0x83b86b56
-0, 14, 14, 1, 921600, 0xd52a1697
-0, 15, 15, 1, 921600, 0x5b38adc8
-0, 16, 16, 1, 921600, 0x457f6cea
+0, 0, 0, 1, 921600, 0x8a5d15df
+0, 1, 1, 1, 921600, 0x92c01362
+0, 2, 2, 1, 921600, 0xe1a31643
+0, 3, 3, 1, 921600, 0x37a90fe2
+0, 4, 4, 1, 921600, 0x74410783
+0, 5, 5, 1, 921600, 0xecf4ef1a
+0, 6, 6, 1, 921600, 0x4d7ff3d4
+0, 7, 7, 1, 921600, 0xac820317
+0, 8, 8, 1, 921600, 0xbe5ff56e
+0, 9, 9, 1, 921600, 0x8e59c329
+0, 10, 10, 1, 921600, 0x73bf23f3
+0, 11, 11, 1, 921600, 0xb90c780f
+0, 12, 12, 1, 921600, 0xfbd9dc32
+0, 13, 13, 1, 921600, 0x30586821
+0, 14, 14, 1, 921600, 0x6695195b
+0, 15, 15, 1, 921600, 0xc449aa85
+0, 16, 16, 1, 921600, 0xca6a391c
diff --git a/tests/ref/fate/dfa3 b/tests/ref/fate/dfa3
index 8c91faaa4b..9b170ec69b 100644
--- a/tests/ref/fate/dfa3
+++ b/tests/ref/fate/dfa3
@@ -1,11 +1,11 @@
#tb 0: 1/10
-0, 0, 0, 1, 192000, 0x10380cf0
-0, 1, 1, 1, 192000, 0x1d74af4c
-0, 2, 2, 1, 192000, 0xd665492d
-0, 3, 3, 1, 192000, 0xbf544565
-0, 4, 4, 1, 192000, 0xf8a33b00
-0, 5, 5, 1, 192000, 0x7d08bbad
-0, 6, 6, 1, 192000, 0x10685a90
-0, 7, 7, 1, 192000, 0x0a1a9ef6
-0, 8, 8, 1, 192000, 0x3e967980
-0, 9, 9, 1, 192000, 0x9849f751
+0, 0, 0, 1, 192000, 0x236a1b54
+0, 1, 1, 1, 192000, 0xfb438b68
+0, 2, 2, 1, 192000, 0xde504563
+0, 3, 3, 1, 192000, 0xfaf88e05
+0, 4, 4, 1, 192000, 0xe15de5af
+0, 5, 5, 1, 192000, 0x641fcca4
+0, 6, 6, 1, 192000, 0x74899cb6
+0, 7, 7, 1, 192000, 0x93fdb1b4
+0, 8, 8, 1, 192000, 0x58d83456
+0, 9, 9, 1, 192000, 0x7d3012ac
diff --git a/tests/ref/fate/dfa4 b/tests/ref/fate/dfa4
index 67b5722b2a..0e0dc020a4 100644
--- a/tests/ref/fate/dfa4
+++ b/tests/ref/fate/dfa4
@@ -1,14 +1,15 @@
#tb 0: 71/500
-0, 1, 1, 1, 921600, 0xe6309638
-0, 2, 2, 1, 921600, 0xa99a7665
-0, 3, 3, 1, 921600, 0x172ccfbb
-0, 4, 4, 1, 921600, 0xcf676571
-0, 5, 5, 1, 921600, 0x6a5077f2
-0, 6, 6, 1, 921600, 0x6a5077f2
-0, 7, 7, 1, 921600, 0x6a5077f2
-0, 8, 8, 1, 921600, 0x6a5077f2
-0, 9, 9, 1, 921600, 0x6a5077f2
-0, 10, 10, 1, 921600, 0x6a5077f2
-0, 11, 11, 1, 921600, 0xb83db404
-0, 12, 12, 1, 921600, 0x997ceb90
-0, 13, 13, 1, 921600, 0xd707157c
+0, 0, 0, 1, 921600, 0x00000000
+0, 1, 1, 1, 921600, 0xd9e060e3
+0, 2, 2, 1, 921600, 0x15e28dc7
+0, 3, 3, 1, 921600, 0x78e8bfbc
+0, 4, 4, 1, 921600, 0xe9407075
+0, 5, 5, 1, 921600, 0xab818b8a
+0, 6, 6, 1, 921600, 0xab818b8a
+0, 7, 7, 1, 921600, 0xab818b8a
+0, 8, 8, 1, 921600, 0xab818b8a
+0, 9, 9, 1, 921600, 0xab818b8a
+0, 10, 10, 1, 921600, 0xab818b8a
+0, 11, 11, 1, 921600, 0xad5ad11c
+0, 12, 12, 1, 921600, 0xe6e50f8c
+0, 13, 13, 1, 921600, 0x9f127099
diff --git a/tests/ref/fate/dfa5 b/tests/ref/fate/dfa5
index b9f7727e58..3be3c5269a 100644
--- a/tests/ref/fate/dfa5
+++ b/tests/ref/fate/dfa5
@@ -1,16 +1,16 @@
#tb 0: 1/10
-0, 0, 0, 1, 192000, 0xc0941c10
-0, 1, 1, 1, 192000, 0xe2fe3ae5
-0, 2, 2, 1, 192000, 0x4a352d98
-0, 3, 3, 1, 192000, 0x7b78e0bb
-0, 4, 4, 1, 192000, 0x855c6675
-0, 5, 5, 1, 192000, 0xf443dad6
-0, 6, 6, 1, 192000, 0xe7e2a2e1
-0, 7, 7, 1, 192000, 0xa9009c58
-0, 8, 8, 1, 192000, 0x551855ab
-0, 9, 9, 1, 192000, 0x253908c7
-0, 10, 10, 1, 192000, 0x616213c4
-0, 11, 11, 1, 192000, 0xa381c3b1
-0, 12, 12, 1, 192000, 0xa2d64152
-0, 13, 13, 1, 192000, 0x34ed0f72
-0, 14, 14, 1, 192000, 0x05be63b4
+0, 0, 0, 1, 192000, 0x9754890f
+0, 1, 1, 1, 192000, 0x01668965
+0, 2, 2, 1, 192000, 0xbd1b5e12
+0, 3, 3, 1, 192000, 0x2e97fb9f
+0, 4, 4, 1, 192000, 0xf8b452e2
+0, 5, 5, 1, 192000, 0xc6859449
+0, 6, 6, 1, 192000, 0x910844f7
+0, 7, 7, 1, 192000, 0x99443581
+0, 8, 8, 1, 192000, 0xec52d1e5
+0, 9, 9, 1, 192000, 0x2fc66c35
+0, 10, 10, 1, 192000, 0xd9af7379
+0, 11, 11, 1, 192000, 0x947a26ef
+0, 12, 12, 1, 192000, 0x7b77ab28
+0, 13, 13, 1, 192000, 0x2507637e
+0, 14, 14, 1, 192000, 0x6ce8c0ea
diff --git a/tests/ref/fate/dfa6 b/tests/ref/fate/dfa6
index 92ed259369..535f98b346 100644
--- a/tests/ref/fate/dfa6
+++ b/tests/ref/fate/dfa6
@@ -1,13 +1,13 @@
#tb 0: 71/1000
-0, 0, 0, 1, 192000, 0x69f6a5f6
-0, 1, 1, 1, 192000, 0xc741d0a6
-0, 2, 2, 1, 192000, 0xba31e7a4
-0, 3, 3, 1, 192000, 0x7dc45080
-0, 4, 4, 1, 192000, 0x1c91dad5
-0, 5, 5, 1, 192000, 0x564b69b1
-0, 6, 6, 1, 192000, 0xdd9d9ae8
-0, 7, 7, 1, 192000, 0x605c05e1
-0, 8, 8, 1, 192000, 0xa5341ddb
-0, 9, 9, 1, 192000, 0x1ebff8ba
-0, 10, 10, 1, 192000, 0x240df237
-0, 11, 11, 1, 192000, 0xac641867
+0, 0, 0, 1, 192000, 0xb718dc63
+0, 1, 1, 1, 192000, 0x2efb7b89
+0, 2, 2, 1, 192000, 0x70827047
+0, 3, 3, 1, 192000, 0x61e1fd2f
+0, 4, 4, 1, 192000, 0x06f8bccd
+0, 5, 5, 1, 192000, 0xf0362404
+0, 6, 6, 1, 192000, 0xc00fc1b8
+0, 7, 7, 1, 192000, 0x94265476
+0, 8, 8, 1, 192000, 0x4b50ad23
+0, 9, 9, 1, 192000, 0x4d578b60
+0, 10, 10, 1, 192000, 0xfb14b875
+0, 11, 11, 1, 192000, 0x81682338
diff --git a/tests/ref/fate/dfa7 b/tests/ref/fate/dfa7
index 7dd40f2bc0..28122c5287 100644
--- a/tests/ref/fate/dfa7
+++ b/tests/ref/fate/dfa7
@@ -1,13 +1,13 @@
#tb 0: 71/1000
-0, 0, 0, 1, 7866, 0xa0056fdb
-0, 1, 1, 1, 7866, 0xed906c7a
-0, 2, 2, 1, 7866, 0x1c6e6f7d
-0, 3, 3, 1, 7866, 0xa2c460f7
-0, 4, 4, 1, 7866, 0xcf2166d4
-0, 5, 5, 1, 7866, 0xea545432
-0, 6, 6, 1, 7866, 0x604a5a9e
-0, 7, 7, 1, 7866, 0xbbc95c89
-0, 8, 8, 1, 7866, 0x80b16b5b
-0, 9, 9, 1, 7866, 0x9a1660ae
-0, 10, 10, 1, 7866, 0x6f886b10
-0, 11, 11, 1, 7866, 0xad8b5c99
+0, 0, 0, 1, 7866, 0xab73dae7
+0, 1, 1, 1, 7866, 0x100adec8
+0, 2, 2, 1, 7866, 0x1a20ddfa
+0, 3, 3, 1, 7866, 0xc358cd16
+0, 4, 4, 1, 7866, 0xee0bd20e
+0, 5, 5, 1, 7866, 0xef26bef9
+0, 6, 6, 1, 7866, 0xa9d0c755
+0, 7, 7, 1, 7866, 0x6c11cc7c
+0, 8, 8, 1, 7866, 0x4d6ed988
+0, 9, 9, 1, 7866, 0x9965cf24
+0, 10, 10, 1, 7866, 0x9a12db24
+0, 11, 11, 1, 7866, 0x2e85cfeb
diff --git a/tests/ref/fate/dfa8 b/tests/ref/fate/dfa8
index 39dde05465..866260a10c 100644
--- a/tests/ref/fate/dfa8
+++ b/tests/ref/fate/dfa8
@@ -1,37 +1,37 @@
#tb 0: 71/1000
-0, 0, 0, 1, 134724, 0x2ab217de
-0, 1, 1, 1, 134724, 0xbf240f9a
-0, 2, 2, 1, 134724, 0x020a6010
-0, 3, 3, 1, 134724, 0x9a5f9374
-0, 4, 4, 1, 134724, 0x1e93a7e9
-0, 5, 5, 1, 134724, 0x9e4a4c55
-0, 6, 6, 1, 134724, 0x8f9d1bab
-0, 7, 7, 1, 134724, 0xb26ac45b
-0, 8, 8, 1, 134724, 0xc08706d2
-0, 9, 9, 1, 134724, 0x0806b031
-0, 10, 10, 1, 134724, 0x234dbb33
-0, 11, 11, 1, 134724, 0xe4cbfb2f
-0, 12, 12, 1, 134724, 0xf603f3fd
-0, 13, 13, 1, 134724, 0x205669d1
-0, 14, 14, 1, 134724, 0x7ddbb5e3
-0, 15, 15, 1, 134724, 0x8dfbb45a
-0, 16, 16, 1, 134724, 0x9632f681
-0, 17, 17, 1, 134724, 0x259e462c
-0, 18, 18, 1, 134724, 0x14f2bac1
-0, 19, 19, 1, 134724, 0xac3de7ed
-0, 20, 20, 1, 134724, 0x6b8af396
-0, 21, 21, 1, 134724, 0xd1e4bc1c
-0, 22, 22, 1, 134724, 0x716d1c73
-0, 23, 23, 1, 134724, 0x610956c8
-0, 24, 24, 1, 134724, 0x89ff8e86
-0, 25, 25, 1, 134724, 0xc3ea6b6f
-0, 26, 26, 1, 134724, 0x886688ef
-0, 27, 27, 1, 134724, 0xe60fc8c1
-0, 28, 28, 1, 134724, 0x22bd3131
-0, 29, 29, 1, 134724, 0xb1d74561
-0, 30, 30, 1, 134724, 0x61b069bc
-0, 31, 31, 1, 134724, 0x50b665c1
-0, 32, 32, 1, 134724, 0x027e5144
-0, 33, 33, 1, 134724, 0xfe0c31b4
-0, 34, 34, 1, 134724, 0x1e7a1f2d
-0, 35, 35, 1, 134724, 0x48bff03d
+0, 0, 0, 1, 134724, 0x53784ca9
+0, 1, 1, 1, 134724, 0x14c345b7
+0, 2, 2, 1, 134724, 0xe0d0dd51
+0, 3, 3, 1, 134724, 0xd53b5610
+0, 4, 4, 1, 134724, 0x7cbb8d47
+0, 5, 5, 1, 134724, 0x875d67c4
+0, 6, 6, 1, 134724, 0x9811c085
+0, 7, 7, 1, 134724, 0x25f6d228
+0, 8, 8, 1, 134724, 0x349495a0
+0, 9, 9, 1, 134724, 0xd0d75311
+0, 10, 10, 1, 134724, 0xb49cdfbb
+0, 11, 11, 1, 134724, 0x9fa69518
+0, 12, 12, 1, 134724, 0x28a1f58c
+0, 13, 13, 1, 134724, 0xb8dab657
+0, 14, 14, 1, 134724, 0x8c7e3b3b
+0, 15, 15, 1, 134724, 0x37268acf
+0, 16, 16, 1, 134724, 0xcce8ca02
+0, 17, 17, 1, 134724, 0xe0fd0c28
+0, 18, 18, 1, 134724, 0x5bdac906
+0, 19, 19, 1, 134724, 0xdd850bf0
+0, 20, 20, 1, 134724, 0x2002a228
+0, 21, 21, 1, 134724, 0x633617ea
+0, 22, 22, 1, 134724, 0x2a3ef337
+0, 23, 23, 1, 134724, 0x507886c3
+0, 24, 24, 1, 134724, 0x51c0f07b
+0, 25, 25, 1, 134724, 0x5e73dce1
+0, 26, 26, 1, 134724, 0x26acc6f0
+0, 27, 27, 1, 134724, 0x360c4349
+0, 28, 28, 1, 134724, 0xc7dbabd4
+0, 29, 29, 1, 134724, 0x671bbf66
+0, 30, 30, 1, 134724, 0x4d44df79
+0, 31, 31, 1, 134724, 0x69eade5b
+0, 32, 32, 1, 134724, 0x2b1bca82
+0, 33, 33, 1, 134724, 0x8b16af47
+0, 34, 34, 1, 134724, 0xb59fa1bd
+0, 35, 35, 1, 134724, 0x2ec17c24
diff --git a/tests/ref/fate/dfa9 b/tests/ref/fate/dfa9
index cf24e3e212..99eb3f678d 100644
--- a/tests/ref/fate/dfa9
+++ b/tests/ref/fate/dfa9
@@ -1,7 +1,7 @@
#tb 0: 71/1000
-0, 0, 0, 1, 228150, 0x188c6d9b
-0, 1, 1, 1, 228150, 0x658dbf2f
-0, 2, 2, 1, 228150, 0xc09a4b2e
-0, 3, 3, 1, 228150, 0x8777bc7d
-0, 4, 4, 1, 228150, 0xa388f0ce
-0, 5, 5, 1, 228150, 0x4e06666e
+0, 0, 0, 1, 228150, 0xde68df49
+0, 1, 1, 1, 228150, 0x8e12bcaf
+0, 2, 2, 1, 228150, 0x851b04f7
+0, 3, 3, 1, 228150, 0x7e5e0950
+0, 4, 4, 1, 228150, 0x1d92219f
+0, 5, 5, 1, 228150, 0x93caa693
diff --git a/tests/ref/fate/dict b/tests/ref/fate/dict
new file mode 100644
index 0000000000..837f7b02e5
--- /dev/null
+++ b/tests/ref/fate/dict
@@ -0,0 +1,43 @@
+Testing av_dict_get_string() and av_dict_parse_string()
+
+aaa aaa b,b bbb c=c ccc ddd d,d eee e=e f,f f=f g=g g,g
+aaa=aaa,b\,b=bbb,c\=c=ccc,ddd=d\,d,eee=e\=e,f\,f=f\=f,g\=g=g\,g
+aaa aaa b,b bbb c=c ccc ddd d,d eee e=e f,f f=f g=g g,g
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa=aaa"bbb=bbb"ccc=ccc"\\,\=\'\"=\\,\=\'\"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa=aaa'bbb=bbb'ccc=ccc'\\,\=\'"=\\,\=\'"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa"aaa,bbb"bbb,ccc"ccc,\\\,=\'\""\\\,=\'\"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa'aaa,bbb'bbb,ccc'ccc,\\\,=\'"'\\\,=\'"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa"aaa'bbb"bbb'ccc"ccc'\\,=\'\""\\,=\'\"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+aaa'aaa"bbb'bbb"ccc'ccc"\\,=\'\"'\\,=\'\"
+aaa aaa bbb bbb ccc ccc \,='" \,='"
+
+Testing av_dict_set()
+a a
+b b
+c c
+d d
+e e
+ff ff
+
+Testing av_dict_set_int()
+1 1
+2 2
+3 3
+4 4
+5 5
+12 12
+
+Testing av_dict_set() with existing AVDictionaryEntry.key as key
+new val OK
+new val OK
diff --git a/tests/ref/fate/dirac b/tests/ref/fate/dirac
new file mode 100644
index 0000000000..7781b4e5dd
--- /dev/null
+++ b/tests/ref/fate/dirac
@@ -0,0 +1,3 @@
+#tb 0: 1/30
+0, 0, 0, 1, 115200, 0xf73819e8
+0, 1, 1, 1, 115200, 0x082e3788
diff --git a/tests/ref/fate/dpxparser b/tests/ref/fate/dpxparser
index 025c87d30d..0ecc36cab2 100644
--- a/tests/ref/fate/dpxparser
+++ b/tests/ref/fate/dpxparser
@@ -1,5 +1,5 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0xa7d03ff5
-0, 1, 1, 1, 203280, 0xb908d8d4
-0, 2, 2, 1, 203280, 0xf7900408
-0, 3, 3, 1, 203280, 0xb74ed6a8
+0, 0, 0, 1, 50700, 0xe7153545
+0, 1, 1, 1, 50700, 0x2bc92ece
+0, 2, 2, 1, 50700, 0x83c731bb
+0, 3, 3, 1, 50700, 0x92f52f19
diff --git a/tests/ref/fate/ea-cmv b/tests/ref/fate/ea-cmv
index 18f2b3ae15..8f9049e907 100644
--- a/tests/ref/fate/ea-cmv
+++ b/tests/ref/fate/ea-cmv
@@ -1,195 +1,195 @@
#tb 0: 1/10
-0, 1, 1, 1, 120000, 0x34ac91d2
-0, 2, 2, 1, 120000, 0x17150729
-0, 3, 3, 1, 120000, 0xc3f510bb
-0, 4, 4, 1, 120000, 0xb3b14a3b
-0, 5, 5, 1, 120000, 0x26a7f3d1
-0, 6, 6, 1, 120000, 0xd161af6f
-0, 7, 7, 1, 120000, 0x459fc92d
-0, 8, 8, 1, 120000, 0x05c3fa94
-0, 9, 9, 1, 120000, 0x6630cd8c
-0, 10, 10, 1, 120000, 0x60cd39d4
-0, 11, 11, 1, 120000, 0xc8854d1c
-0, 12, 12, 1, 120000, 0xe55e8e6d
-0, 13, 13, 1, 120000, 0xbeab201f
-0, 14, 14, 1, 120000, 0x70744b0b
-0, 15, 15, 1, 120000, 0x80dea5d0
-0, 16, 16, 1, 120000, 0x769bfa1c
-0, 17, 17, 1, 120000, 0x04e25bbe
-0, 18, 18, 1, 120000, 0x48abc5a5
-0, 19, 19, 1, 120000, 0xda5c4e2a
-0, 20, 20, 1, 120000, 0x8de96d38
-0, 21, 21, 1, 120000, 0xe96418b0
-0, 22, 22, 1, 120000, 0x1c2f272b
-0, 23, 23, 1, 120000, 0x4b755804
-0, 24, 24, 1, 120000, 0xc92f96fd
-0, 25, 25, 1, 120000, 0x69e90ebb
-0, 26, 26, 1, 120000, 0x78d4bd1a
-0, 27, 27, 1, 120000, 0xaf2edf55
-0, 28, 28, 1, 120000, 0x94161c78
-0, 29, 29, 1, 120000, 0x1109094d
-0, 30, 30, 1, 120000, 0xc61b0392
-0, 31, 31, 1, 120000, 0xc157d003
-0, 32, 32, 1, 120000, 0xf2747e7b
-0, 33, 33, 1, 120000, 0xa36299c2
-0, 34, 34, 1, 120000, 0x49bc788c
-0, 35, 35, 1, 120000, 0x3bee336e
-0, 36, 36, 1, 120000, 0xa316b9d1
-0, 37, 37, 1, 120000, 0x5cc32e9c
-0, 38, 38, 1, 120000, 0x9f7eca16
-0, 39, 39, 1, 120000, 0x958e2988
-0, 40, 40, 1, 120000, 0xebcba2f1
-0, 41, 41, 1, 120000, 0x281f1e60
-0, 42, 42, 1, 120000, 0x82256c4d
-0, 43, 43, 1, 120000, 0xddc8be56
-0, 44, 44, 1, 120000, 0x64ff2ed0
-0, 45, 45, 1, 120000, 0x3e63ab02
-0, 46, 46, 1, 120000, 0x43f78b37
-0, 47, 47, 1, 120000, 0xb7cc62d4
-0, 48, 48, 1, 120000, 0x694f1764
-0, 49, 49, 1, 120000, 0x2264c483
-0, 51, 51, 1, 120000, 0xb6680b4a
-0, 52, 52, 1, 120000, 0x2a92626a
-0, 53, 53, 1, 120000, 0x8da02509
-0, 54, 54, 1, 120000, 0xa976c382
-0, 55, 55, 1, 120000, 0x749e822b
-0, 56, 56, 1, 120000, 0xe9e7fc8c
-0, 57, 57, 1, 120000, 0xfdc05a0c
-0, 58, 58, 1, 120000, 0x7d5a856d
-0, 59, 59, 1, 120000, 0xcc344937
-0, 60, 60, 1, 120000, 0x9d90bc67
-0, 61, 61, 1, 120000, 0x3f527712
-0, 62, 62, 1, 120000, 0xf0f57f97
-0, 63, 63, 1, 120000, 0xc29535cd
-0, 64, 64, 1, 120000, 0x9a64598b
-0, 65, 65, 1, 120000, 0x0d1ddf7c
-0, 66, 66, 1, 120000, 0xb580ec24
-0, 67, 67, 1, 120000, 0xf0db5bbc
-0, 68, 68, 1, 120000, 0x6b980b61
-0, 69, 69, 1, 120000, 0xc29f30b5
-0, 70, 70, 1, 120000, 0xaf2c4bcd
-0, 71, 71, 1, 120000, 0x1e725645
-0, 72, 72, 1, 120000, 0x295c4c96
-0, 73, 73, 1, 120000, 0x7ea121a2
-0, 74, 74, 1, 120000, 0xdb9e9cec
-0, 75, 75, 1, 120000, 0x1da47c80
-0, 76, 76, 1, 120000, 0x9d0c1345
-0, 77, 77, 1, 120000, 0x88058527
-0, 78, 78, 1, 120000, 0x46766aed
-0, 79, 79, 1, 120000, 0xba520bd3
-0, 80, 80, 1, 120000, 0x7fb6373c
-0, 81, 81, 1, 120000, 0x05a86f4d
-0, 82, 82, 1, 120000, 0x7fb47cbd
-0, 83, 83, 1, 120000, 0x6814d8ca
-0, 84, 84, 1, 120000, 0x9c13acb8
-0, 85, 85, 1, 120000, 0xad0edbfe
-0, 86, 86, 1, 120000, 0x352fde81
-0, 87, 87, 1, 120000, 0xa654b386
-0, 88, 88, 1, 120000, 0xd3b3dc72
-0, 89, 89, 1, 120000, 0x01572668
-0, 90, 90, 1, 120000, 0x30189e03
-0, 91, 91, 1, 120000, 0x26126d30
-0, 92, 92, 1, 120000, 0x4f376c7d
-0, 93, 93, 1, 120000, 0xd3667bcf
-0, 94, 94, 1, 120000, 0x0b46b3d5
-0, 95, 95, 1, 120000, 0x893415ef
-0, 96, 96, 1, 120000, 0x99a78749
-0, 97, 97, 1, 120000, 0x6da0d8e9
-0, 98, 98, 1, 120000, 0x22d8ceb6
-0, 99, 99, 1, 120000, 0x67ef9be8
-0, 100, 100, 1, 120000, 0xb696fb53
-0, 101, 101, 1, 120000, 0x70339dab
-0, 102, 102, 1, 120000, 0xc1876efa
-0, 103, 103, 1, 120000, 0x80e78c92
-0, 104, 104, 1, 120000, 0x18d2f2ac
-0, 105, 105, 1, 120000, 0x28be9ae4
-0, 106, 106, 1, 120000, 0xc3c2c190
-0, 107, 107, 1, 120000, 0xd6a859d8
-0, 108, 108, 1, 120000, 0x40b9046d
-0, 109, 109, 1, 120000, 0x7f8d5999
-0, 110, 110, 1, 120000, 0x89724027
-0, 111, 111, 1, 120000, 0x4c15c988
-0, 112, 112, 1, 120000, 0x812ebe08
-0, 113, 113, 1, 120000, 0x273ef8e2
-0, 114, 114, 1, 120000, 0xe029de06
-0, 115, 115, 1, 120000, 0x5846127c
-0, 116, 116, 1, 120000, 0x6c5df8e3
-0, 117, 117, 1, 120000, 0x7424919f
-0, 118, 118, 1, 120000, 0xa8313015
-0, 119, 119, 1, 120000, 0x28878ab4
-0, 120, 120, 1, 120000, 0x126d0746
-0, 121, 121, 1, 120000, 0xee3f7138
-0, 122, 122, 1, 120000, 0xd4b2e0a1
-0, 123, 123, 1, 120000, 0x8d60bfff
-0, 124, 124, 1, 120000, 0x701c23d0
-0, 125, 125, 1, 120000, 0x1cbb5654
-0, 126, 126, 1, 120000, 0x0f5853e9
-0, 127, 127, 1, 120000, 0x2a5c3339
-0, 128, 128, 1, 120000, 0x86b00350
-0, 129, 129, 1, 120000, 0xe8cc6931
-0, 130, 130, 1, 120000, 0xf1cad983
-0, 131, 131, 1, 120000, 0xabcd8704
-0, 132, 132, 1, 120000, 0x89592f94
-0, 133, 133, 1, 120000, 0x100486d9
-0, 134, 134, 1, 120000, 0x60ef9e2d
-0, 135, 135, 1, 120000, 0x2485176a
-0, 136, 136, 1, 120000, 0x6b8c360d
-0, 137, 137, 1, 120000, 0xe2e1bf4f
-0, 138, 138, 1, 120000, 0xe17b65c3
-0, 139, 139, 1, 120000, 0x2a42821a
-0, 140, 140, 1, 120000, 0xbe9ddba7
-0, 141, 141, 1, 120000, 0x19f937fe
-0, 142, 142, 1, 120000, 0xb7e0c600
-0, 143, 143, 1, 120000, 0xfbf8c5f6
-0, 144, 144, 1, 120000, 0x93b62f93
-0, 145, 145, 1, 120000, 0xb6ddec93
-0, 146, 146, 1, 120000, 0xa04d031b
-0, 147, 147, 1, 120000, 0x61c986c0
-0, 148, 148, 1, 120000, 0x3516e54a
-0, 149, 149, 1, 120000, 0x3489eb2c
-0, 150, 150, 1, 120000, 0xb75a4827
-0, 151, 151, 1, 120000, 0x76031a80
-0, 152, 152, 1, 120000, 0x867c3969
-0, 153, 153, 1, 120000, 0x9b63a093
-0, 154, 154, 1, 120000, 0xcb253d8a
-0, 155, 155, 1, 120000, 0x354ba3b2
-0, 156, 156, 1, 120000, 0x4d5ead8c
-0, 157, 157, 1, 120000, 0x7b7029ae
-0, 158, 158, 1, 120000, 0x4765ab9d
-0, 159, 159, 1, 120000, 0x747cdee9
-0, 160, 160, 1, 120000, 0x20989b08
-0, 161, 161, 1, 120000, 0x3a957085
-0, 162, 162, 1, 120000, 0xdd49e8ad
-0, 163, 163, 1, 120000, 0x00e89719
-0, 164, 164, 1, 120000, 0x2822aa76
-0, 165, 165, 1, 120000, 0x492388f3
-0, 166, 166, 1, 120000, 0x4dffa6ee
-0, 167, 167, 1, 120000, 0xc382bb83
-0, 168, 168, 1, 120000, 0xb59aaa74
-0, 169, 169, 1, 120000, 0x7c7885d3
-0, 170, 170, 1, 120000, 0xc05ee219
-0, 171, 171, 1, 120000, 0xc3df6b73
-0, 172, 172, 1, 120000, 0x8ae31170
-0, 173, 173, 1, 120000, 0xb979fdce
-0, 174, 174, 1, 120000, 0xb8f9e407
-0, 175, 175, 1, 120000, 0x56675b80
-0, 176, 176, 1, 120000, 0x1aad1ce2
-0, 177, 177, 1, 120000, 0xa050a52b
-0, 178, 178, 1, 120000, 0x49f8c32f
-0, 179, 179, 1, 120000, 0x8e7f4d2c
-0, 180, 180, 1, 120000, 0x5c07f751
-0, 181, 181, 1, 120000, 0x67fa5523
-0, 182, 182, 1, 120000, 0xf38b933a
-0, 183, 183, 1, 120000, 0xb113e202
-0, 184, 184, 1, 120000, 0xb8d99ff4
-0, 185, 185, 1, 120000, 0x15ab6cc6
-0, 186, 186, 1, 120000, 0xd64a51c9
-0, 187, 187, 1, 120000, 0x2088b53c
-0, 188, 188, 1, 120000, 0xdd78d40a
-0, 189, 189, 1, 120000, 0x2fb58848
-0, 190, 190, 1, 120000, 0xf775d36a
-0, 191, 191, 1, 120000, 0xa03987e9
-0, 192, 192, 1, 120000, 0x457322ad
-0, 193, 193, 1, 120000, 0x0f6c3d1c
-0, 194, 194, 1, 120000, 0xbdf2f1a5
-0, 195, 195, 1, 120000, 0x5828ee1d
+0, 0, 0, 1, 120000, 0x34ac91d2
+0, 1, 1, 1, 120000, 0x17150729
+0, 2, 2, 1, 120000, 0xc3f510bb
+0, 3, 3, 1, 120000, 0xb3b14a3b
+0, 4, 4, 1, 120000, 0x26a7f3d1
+0, 5, 5, 1, 120000, 0xd161af6f
+0, 6, 6, 1, 120000, 0x459fc92d
+0, 7, 7, 1, 120000, 0x05c3fa94
+0, 8, 8, 1, 120000, 0x6630cd8c
+0, 9, 9, 1, 120000, 0x60cd39d4
+0, 10, 10, 1, 120000, 0xc8854d1c
+0, 11, 11, 1, 120000, 0xe55e8e6d
+0, 12, 12, 1, 120000, 0xbeab201f
+0, 13, 13, 1, 120000, 0x70744b0b
+0, 14, 14, 1, 120000, 0x80dea5d0
+0, 15, 15, 1, 120000, 0x769bfa1c
+0, 16, 16, 1, 120000, 0x04e25bbe
+0, 17, 17, 1, 120000, 0x48abc5a5
+0, 18, 18, 1, 120000, 0xda5c4e2a
+0, 19, 19, 1, 120000, 0x8de96d38
+0, 20, 20, 1, 120000, 0xe96418b0
+0, 21, 21, 1, 120000, 0x1c2f272b
+0, 22, 22, 1, 120000, 0x4b755804
+0, 23, 23, 1, 120000, 0xc92f96fd
+0, 24, 24, 1, 120000, 0x69e90ebb
+0, 25, 25, 1, 120000, 0x78d4bd1a
+0, 26, 26, 1, 120000, 0xaf2edf55
+0, 27, 27, 1, 120000, 0x94161c78
+0, 28, 28, 1, 120000, 0x1109094d
+0, 29, 29, 1, 120000, 0xc61b0392
+0, 30, 30, 1, 120000, 0xc157d003
+0, 31, 31, 1, 120000, 0xf2747e7b
+0, 32, 32, 1, 120000, 0xa36299c2
+0, 33, 33, 1, 120000, 0x49bc788c
+0, 34, 34, 1, 120000, 0x3bee336e
+0, 35, 35, 1, 120000, 0xa316b9d1
+0, 36, 36, 1, 120000, 0x5cc32e9c
+0, 37, 37, 1, 120000, 0x9f7eca16
+0, 38, 38, 1, 120000, 0x958e2988
+0, 39, 39, 1, 120000, 0xebcba2f1
+0, 40, 40, 1, 120000, 0x281f1e60
+0, 41, 41, 1, 120000, 0x82256c4d
+0, 42, 42, 1, 120000, 0xddc8be56
+0, 43, 43, 1, 120000, 0x64ff2ed0
+0, 44, 44, 1, 120000, 0x3e63ab02
+0, 45, 45, 1, 120000, 0x43f78b37
+0, 46, 46, 1, 120000, 0xb7cc62d4
+0, 47, 47, 1, 120000, 0x694f1764
+0, 48, 48, 1, 120000, 0x2264c483
+0, 49, 49, 1, 120000, 0xb6680b4a
+0, 50, 50, 1, 120000, 0x2a92626a
+0, 51, 51, 1, 120000, 0x8da02509
+0, 52, 52, 1, 120000, 0xa976c382
+0, 53, 53, 1, 120000, 0x749e822b
+0, 54, 54, 1, 120000, 0xe9e7fc8c
+0, 55, 55, 1, 120000, 0xfdc05a0c
+0, 56, 56, 1, 120000, 0x7d5a856d
+0, 57, 57, 1, 120000, 0xcc344937
+0, 58, 58, 1, 120000, 0x9d90bc67
+0, 59, 59, 1, 120000, 0x3f527712
+0, 60, 60, 1, 120000, 0xf0f57f97
+0, 61, 61, 1, 120000, 0xc29535cd
+0, 62, 62, 1, 120000, 0x9a64598b
+0, 63, 63, 1, 120000, 0x0d1ddf7c
+0, 64, 64, 1, 120000, 0xb580ec24
+0, 65, 65, 1, 120000, 0xf0db5bbc
+0, 66, 66, 1, 120000, 0x6b980b61
+0, 67, 67, 1, 120000, 0xc29f30b5
+0, 68, 68, 1, 120000, 0xaf2c4bcd
+0, 69, 69, 1, 120000, 0x1e725645
+0, 70, 70, 1, 120000, 0x295c4c96
+0, 71, 71, 1, 120000, 0x7ea121a2
+0, 72, 72, 1, 120000, 0xdb9e9cec
+0, 73, 73, 1, 120000, 0x1da47c80
+0, 74, 74, 1, 120000, 0x9d0c1345
+0, 75, 75, 1, 120000, 0x88058527
+0, 76, 76, 1, 120000, 0x46766aed
+0, 77, 77, 1, 120000, 0xba520bd3
+0, 78, 78, 1, 120000, 0x7fb6373c
+0, 79, 79, 1, 120000, 0x05a86f4d
+0, 80, 80, 1, 120000, 0x7fb47cbd
+0, 81, 81, 1, 120000, 0x6814d8ca
+0, 82, 82, 1, 120000, 0x9c13acb8
+0, 83, 83, 1, 120000, 0xad0edbfe
+0, 84, 84, 1, 120000, 0x352fde81
+0, 85, 85, 1, 120000, 0xa654b386
+0, 86, 86, 1, 120000, 0xd3b3dc72
+0, 87, 87, 1, 120000, 0x01572668
+0, 88, 88, 1, 120000, 0x30189e03
+0, 89, 89, 1, 120000, 0x26126d30
+0, 90, 90, 1, 120000, 0x4f376c7d
+0, 91, 91, 1, 120000, 0xd3667bcf
+0, 92, 92, 1, 120000, 0x0b46b3d5
+0, 93, 93, 1, 120000, 0x893415ef
+0, 94, 94, 1, 120000, 0x99a78749
+0, 95, 95, 1, 120000, 0x6da0d8e9
+0, 96, 96, 1, 120000, 0x22d8ceb6
+0, 97, 97, 1, 120000, 0x67ef9be8
+0, 98, 98, 1, 120000, 0xb696fb53
+0, 99, 99, 1, 120000, 0x70339dab
+0, 100, 100, 1, 120000, 0xc1876efa
+0, 101, 101, 1, 120000, 0x80e78c92
+0, 102, 102, 1, 120000, 0x18d2f2ac
+0, 103, 103, 1, 120000, 0x28be9ae4
+0, 104, 104, 1, 120000, 0xc3c2c190
+0, 105, 105, 1, 120000, 0xd6a859d8
+0, 106, 106, 1, 120000, 0x40b9046d
+0, 107, 107, 1, 120000, 0x7f8d5999
+0, 108, 108, 1, 120000, 0x89724027
+0, 109, 109, 1, 120000, 0x4c15c988
+0, 110, 110, 1, 120000, 0x812ebe08
+0, 111, 111, 1, 120000, 0x273ef8e2
+0, 112, 112, 1, 120000, 0xe029de06
+0, 113, 113, 1, 120000, 0x5846127c
+0, 114, 114, 1, 120000, 0x6c5df8e3
+0, 115, 115, 1, 120000, 0x7424919f
+0, 116, 116, 1, 120000, 0xa8313015
+0, 117, 117, 1, 120000, 0x28878ab4
+0, 118, 118, 1, 120000, 0x126d0746
+0, 119, 119, 1, 120000, 0xee3f7138
+0, 120, 120, 1, 120000, 0xd4b2e0a1
+0, 121, 121, 1, 120000, 0x8d60bfff
+0, 122, 122, 1, 120000, 0x701c23d0
+0, 123, 123, 1, 120000, 0x1cbb5654
+0, 124, 124, 1, 120000, 0x0f5853e9
+0, 125, 125, 1, 120000, 0x2a5c3339
+0, 126, 126, 1, 120000, 0x86b00350
+0, 127, 127, 1, 120000, 0xe8cc6931
+0, 128, 128, 1, 120000, 0xf1cad983
+0, 129, 129, 1, 120000, 0xabcd8704
+0, 130, 130, 1, 120000, 0x89592f94
+0, 131, 131, 1, 120000, 0x100486d9
+0, 132, 132, 1, 120000, 0x60ef9e2d
+0, 133, 133, 1, 120000, 0x2485176a
+0, 134, 134, 1, 120000, 0x6b8c360d
+0, 135, 135, 1, 120000, 0xe2e1bf4f
+0, 136, 136, 1, 120000, 0xe17b65c3
+0, 137, 137, 1, 120000, 0x2a42821a
+0, 138, 138, 1, 120000, 0xbe9ddba7
+0, 139, 139, 1, 120000, 0x19f937fe
+0, 140, 140, 1, 120000, 0xb7e0c600
+0, 141, 141, 1, 120000, 0xfbf8c5f6
+0, 142, 142, 1, 120000, 0x93b62f93
+0, 143, 143, 1, 120000, 0xb6ddec93
+0, 144, 144, 1, 120000, 0xa04d031b
+0, 145, 145, 1, 120000, 0x61c986c0
+0, 146, 146, 1, 120000, 0x3516e54a
+0, 147, 147, 1, 120000, 0x3489eb2c
+0, 148, 148, 1, 120000, 0xb75a4827
+0, 149, 149, 1, 120000, 0x76031a80
+0, 150, 150, 1, 120000, 0x867c3969
+0, 151, 151, 1, 120000, 0x9b63a093
+0, 152, 152, 1, 120000, 0xcb253d8a
+0, 153, 153, 1, 120000, 0x354ba3b2
+0, 154, 154, 1, 120000, 0x4d5ead8c
+0, 155, 155, 1, 120000, 0x7b7029ae
+0, 156, 156, 1, 120000, 0x4765ab9d
+0, 157, 157, 1, 120000, 0x747cdee9
+0, 158, 158, 1, 120000, 0x20989b08
+0, 159, 159, 1, 120000, 0x3a957085
+0, 160, 160, 1, 120000, 0xdd49e8ad
+0, 161, 161, 1, 120000, 0x00e89719
+0, 162, 162, 1, 120000, 0x2822aa76
+0, 163, 163, 1, 120000, 0x492388f3
+0, 164, 164, 1, 120000, 0x4dffa6ee
+0, 165, 165, 1, 120000, 0xc382bb83
+0, 166, 166, 1, 120000, 0xb59aaa74
+0, 167, 167, 1, 120000, 0x7c7885d3
+0, 168, 168, 1, 120000, 0xc05ee219
+0, 169, 169, 1, 120000, 0xc3df6b73
+0, 170, 170, 1, 120000, 0x8ae31170
+0, 171, 171, 1, 120000, 0xb979fdce
+0, 172, 172, 1, 120000, 0xb8f9e407
+0, 173, 173, 1, 120000, 0x56675b80
+0, 174, 174, 1, 120000, 0x1aad1ce2
+0, 175, 175, 1, 120000, 0xa050a52b
+0, 176, 176, 1, 120000, 0x49f8c32f
+0, 177, 177, 1, 120000, 0x8e7f4d2c
+0, 178, 178, 1, 120000, 0x5c07f751
+0, 179, 179, 1, 120000, 0x67fa5523
+0, 180, 180, 1, 120000, 0xf38b933a
+0, 181, 181, 1, 120000, 0xb113e202
+0, 182, 182, 1, 120000, 0xb8d99ff4
+0, 183, 183, 1, 120000, 0x15ab6cc6
+0, 184, 184, 1, 120000, 0xd64a51c9
+0, 185, 185, 1, 120000, 0x2088b53c
+0, 186, 186, 1, 120000, 0xdd78d40a
+0, 187, 187, 1, 120000, 0x2fb58848
+0, 188, 188, 1, 120000, 0xf775d36a
+0, 189, 189, 1, 120000, 0xa03987e9
+0, 190, 190, 1, 120000, 0x457322ad
+0, 191, 191, 1, 120000, 0x0f6c3d1c
+0, 192, 192, 1, 120000, 0xbdf2f1a5
+0, 193, 193, 1, 120000, 0x5828ee1d
diff --git a/tests/ref/fate/eval b/tests/ref/fate/eval
index b01e5a5718..914b13ccfa 100644
--- a/tests/ref/fate/eval
+++ b/tests/ref/fate/eval
@@ -190,5 +190,92 @@ Evaluating '6.0206dB'
Evaluating '-3.0103dB'
'-3.0103dB' -> 0.707107
+Evaluating 'pow(0,1.23)'
+'pow(0,1.23)' -> 0.000000
+
+Evaluating 'pow(PI,1.23)'
+'pow(PI,1.23)' -> 4.087844
+
+Evaluating 'PI^1.23'
+'PI^1.23' -> 4.087844
+
+Evaluating 'pow(-1,1.23)'
+'pow(-1,1.23)' -> nan
+
+Evaluating 'if(1, 2)'
+'if(1, 2)' -> 2.000000
+
+Evaluating 'if(1, 1, 2)'
+'if(1, 1, 2)' -> 1.000000
+
+Evaluating 'if(0, 1, 2)'
+'if(0, 1, 2)' -> 2.000000
+
+Evaluating 'ifnot(0, 23)'
+'ifnot(0, 23)' -> 23.000000
+
+Evaluating 'ifnot(1, NaN) + if(0, 1)'
+'ifnot(1, NaN) + if(0, 1)' -> 0.000000
+
+Evaluating 'ifnot(1, 1, 2)'
+'ifnot(1, 1, 2)' -> 2.000000
+
+Evaluating 'ifnot(0, 1, 2)'
+'ifnot(0, 1, 2)' -> 1.000000
+
+Evaluating 'taylor(1, 1)'
+'taylor(1, 1)' -> 2.718282
+
+Evaluating 'taylor(eq(mod(ld(1),4),1)-eq(mod(ld(1),4),3), PI/2, 1)'
+'taylor(eq(mod(ld(1),4),1)-eq(mod(ld(1),4),3), PI/2, 1)' -> 1.000000
+
+Evaluating 'root(sin(ld(0))-1, 2)'
+'root(sin(ld(0))-1, 2)' -> 1.570796
+
+Evaluating 'root(sin(ld(0))+6+sin(ld(0)/12)-log(ld(0)), 100)'
+'root(sin(ld(0))+6+sin(ld(0)/12)-log(ld(0)), 100)' -> 60.965601
+
+Evaluating '7000000B*random(0)'
+'7000000B*random(0)' -> 0.003078
+
+Evaluating 'squish(2)'
+'squish(2)' -> 0.000335
+
+Evaluating 'gauss(0.1)'
+'gauss(0.1)' -> 0.396953
+
+Evaluating 'hypot(4,3)'
+'hypot(4,3)' -> 5.000000
+
+Evaluating 'gcd(30,55)*print(min(9,1))'
+'gcd(30,55)*print(min(9,1))' -> 5.000000
+
+Evaluating 'bitor(42, 12)'
+'bitor(42, 12)' -> 46.000000
+
+Evaluating 'bitand(42, 12)'
+'bitand(42, 12)' -> 8.000000
+
+Evaluating 'bitand(NAN, 1)'
+'bitand(NAN, 1)' -> nan
+
+Evaluating 'between(10, -3, 10)'
+'between(10, -3, 10)' -> 1.000000
+
+Evaluating 'between(-4, -2, -1)'
+'between(-4, -2, -1)' -> 0.000000
+
+Evaluating 'between(1,2)'
+'between(1,2)' -> nan
+
+Evaluating 'clip(0, 2, 1)'
+'clip(0, 2, 1)' -> nan
+
+Evaluating 'clip(0/0, 1, 2)'
+'clip(0/0, 1, 2)' -> nan
+
+Evaluating 'clip(0, 0/0, 1)'
+'clip(0, 0/0, 1)' -> nan
+
12.700000 == 12.7
0.931323 == 0.931322575
diff --git a/tests/ref/fate/exif-image-embedded b/tests/ref/fate/exif-image-embedded
new file mode 100644
index 0000000000..d0fad03c60
--- /dev/null
+++ b/tests/ref/fate/exif-image-embedded
@@ -0,0 +1,404 @@
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=N/A
+pkt_pts_time=N/A
+pkt_dts=N/A
+pkt_dts_time=N/A
+best_effort_timestamp=N/A
+best_effort_timestamp_time=N/A
+pkt_duration=N/A
+pkt_duration_time=N/A
+pkt_pos=N/A
+pkt_size=15760
+width=263
+height=263
+pix_fmt=yuvj420p
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+TAG:UserComment=AppleMark
+
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=353600
+pkt_pts_time=0.025057
+pkt_dts=353600
+pkt_dts_time=0.025057
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=15040
+pkt_duration_time=0.001066
+pkt_pos=16292
+pkt_size=417
+sample_fmt=s16p
+nb_samples=47
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=368640
+pkt_pts_time=0.026122
+pkt_dts=368640
+pkt_dts_time=0.026122
+best_effort_timestamp=368640
+best_effort_timestamp_time=0.026122
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=16709
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=737280
+pkt_pts_time=0.052245
+pkt_dts=737280
+pkt_dts_time=0.052245
+best_effort_timestamp=737280
+best_effort_timestamp_time=0.052245
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=17127
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=1105920
+pkt_pts_time=0.078367
+pkt_dts=1105920
+pkt_dts_time=0.078367
+best_effort_timestamp=1105920
+best_effort_timestamp_time=0.078367
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=17545
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=1474560
+pkt_pts_time=0.104490
+pkt_dts=1474560
+pkt_dts_time=0.104490
+best_effort_timestamp=1474560
+best_effort_timestamp_time=0.104490
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=17963
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=1843200
+pkt_pts_time=0.130612
+pkt_dts=1843200
+pkt_dts_time=0.130612
+best_effort_timestamp=1843200
+best_effort_timestamp_time=0.130612
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=18381
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=2211840
+pkt_pts_time=0.156735
+pkt_dts=2211840
+pkt_dts_time=0.156735
+best_effort_timestamp=2211840
+best_effort_timestamp_time=0.156735
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=18799
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=2580480
+pkt_pts_time=0.182857
+pkt_dts=2580480
+pkt_dts_time=0.182857
+best_effort_timestamp=2580480
+best_effort_timestamp_time=0.182857
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=19217
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=2949120
+pkt_pts_time=0.208980
+pkt_dts=2949120
+pkt_dts_time=0.208980
+best_effort_timestamp=2949120
+best_effort_timestamp_time=0.208980
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=19635
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=3317760
+pkt_pts_time=0.235102
+pkt_dts=3317760
+pkt_dts_time=0.235102
+best_effort_timestamp=3317760
+best_effort_timestamp_time=0.235102
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=20053
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=3686400
+pkt_pts_time=0.261224
+pkt_dts=3686400
+pkt_dts_time=0.261224
+best_effort_timestamp=3686400
+best_effort_timestamp_time=0.261224
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=20471
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=4055040
+pkt_pts_time=0.287347
+pkt_dts=4055040
+pkt_dts_time=0.287347
+best_effort_timestamp=4055040
+best_effort_timestamp_time=0.287347
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=20889
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=4423680
+pkt_pts_time=0.313469
+pkt_dts=4423680
+pkt_dts_time=0.313469
+best_effort_timestamp=4423680
+best_effort_timestamp_time=0.313469
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=21307
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=4792320
+pkt_pts_time=0.339592
+pkt_dts=4792320
+pkt_dts_time=0.339592
+best_effort_timestamp=4792320
+best_effort_timestamp_time=0.339592
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=21725
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=5160960
+pkt_pts_time=0.365714
+pkt_dts=5160960
+pkt_dts_time=0.365714
+best_effort_timestamp=5160960
+best_effort_timestamp_time=0.365714
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=22143
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=5529600
+pkt_pts_time=0.391837
+pkt_dts=5529600
+pkt_dts_time=0.391837
+best_effort_timestamp=5529600
+best_effort_timestamp_time=0.391837
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=22561
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=5898240
+pkt_pts_time=0.417959
+pkt_dts=5898240
+pkt_dts_time=0.417959
+best_effort_timestamp=5898240
+best_effort_timestamp_time=0.417959
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=22979
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=6266880
+pkt_pts_time=0.444082
+pkt_dts=6266880
+pkt_dts_time=0.444082
+best_effort_timestamp=6266880
+best_effort_timestamp_time=0.444082
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=23397
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=6635520
+pkt_pts_time=0.470204
+pkt_dts=6635520
+pkt_dts_time=0.470204
+best_effort_timestamp=6635520
+best_effort_timestamp_time=0.470204
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=23815
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=7004160
+pkt_pts_time=0.496327
+pkt_dts=7004160
+pkt_dts_time=0.496327
+best_effort_timestamp=7004160
+best_effort_timestamp_time=0.496327
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=24233
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=7372800
+pkt_pts_time=0.522449
+pkt_dts=7372800
+pkt_dts_time=0.522449
+best_effort_timestamp=7372800
+best_effort_timestamp_time=0.522449
+pkt_duration=368640
+pkt_duration_time=0.026122
+pkt_pos=24651
+pkt_size=418
+sample_fmt=s16p
+nb_samples=1152
+channels=2
+channel_layout=stereo
+[/FRAME]
diff --git a/tests/ref/fate/exif-image-jpg b/tests/ref/fate/exif-image-jpg
new file mode 100644
index 0000000000..7b303cd8a1
--- /dev/null
+++ b/tests/ref/fate/exif-image-jpg
@@ -0,0 +1,226 @@
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=1
+pkt_duration_time=0.040000
+pkt_pos=N/A
+pkt_size=46095
+width=400
+height=225
+pix_fmt=yuvj422p
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+TAG:ImageDescription=
+TAG:Make=Canon
+TAG:Model=Canon PowerShot SX200 IS
+TAG:Orientation= 1
+TAG:XResolution= 180:1
+TAG:YResolution= 180:1
+TAG:ResolutionUnit= 2
+TAG:DateTime=2013:07:18 13:12:03
+TAG:YCbCrPositioning= 2
+TAG:ExposureTime= 1:1250
+TAG:FNumber= 40:10
+TAG:ISOSpeedRatings= 160
+TAG:ExifVersion= 48, 50, 50, 49
+TAG:DateTimeOriginal=2013:07:18 13:12:03
+TAG:DateTimeDigitized=2013:07:18 13:12:03
+TAG:ComponentsConfiguration= 1, 2, 3, 0
+TAG:CompressedBitsPerPixel= 3:1
+TAG:ShutterSpeedValue= 329:32
+TAG:ApertureValue= 128:32
+TAG:ExposureBiasValue= 0:3
+TAG:MaxApertureValue= 113:32
+TAG:MeteringMode= 5
+TAG:Flash= 16
+TAG:FocalLength= 5000:1000
+TAG:MakerNote=
+ 25, 0, 1, 0, 3, 0, 48, 0, 0, 0, 28, 4, 0, 0, 2, 0
+ 3, 0, 4, 0, 0, 0, 124, 4, 0, 0, 3, 0, 3, 0, 4, 0
+ 0, 0, 132, 4, 0, 0, 4, 0, 3, 0, 34, 0, 0, 0, 140, 4
+ 0, 0, 0, 0, 3, 0, 6, 0, 0, 0, 208, 4, 0, 0, 6, 0
+ 2, 0, 28, 0, 0, 0, 220, 4, 0, 0, 7, 0, 2, 0, 22, 0
+ 0, 0, 252, 4, 0, 0, 8, 0, 4, 0, 1, 0, 0, 0, 17, 166
+ 15, 0, 9, 0, 2, 0, 32, 0, 0, 0, 20, 5, 0, 0, 13, 0
+ 4, 0, 167, 0, 0, 0, 52, 5, 0, 0, 16, 0, 4, 0, 1, 0
+ 0, 0, 0, 0, 96, 2, 38, 0, 3, 0, 48, 0, 0, 0, 208, 7
+ 0, 0, 19, 0, 3, 0, 4, 0, 0, 0, 48, 8, 0, 0, 24, 0
+ 1, 0, 0, 1, 0, 0, 56, 8, 0, 0, 25, 0, 3, 0, 1, 0
+ 0, 0, 1, 0, 0, 0, 28, 0, 3, 0, 1, 0, 0, 0, 0, 0
+ 0, 0, 29, 0, 3, 0, 16, 0, 0, 0, 56, 9, 0, 0, 30, 0
+ 4, 0, 1, 0, 0, 0, 0, 4, 0, 1, 31, 0, 3, 0, 69, 0
+ 0, 0, 88, 9, 0, 0, 34, 0, 3, 0, 208, 0, 0, 0, 226, 9
+ 0, 0, 35, 0, 4, 0, 2, 0, 0, 0, 130, 11, 0, 0, 39, 0
+ 3, 0, 5, 0, 0, 0, 138, 11, 0, 0, 40, 0, 1, 0, 16, 0
+ 0, 0, 148, 11, 0, 0, 208, 0, 4, 0, 1, 0, 0, 0, 0, 0
+ 0, 0, 45, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0
+ 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 255, 255
+ 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0
+ 3, 0, 1, 0, 6, 64, 0, 0, 255, 127, 255, 255, 96, 234, 136, 19
+232, 3, 113, 0, 221, 0, 255, 255, 0, 0, 0, 0, 0, 0, 1, 0
+ 0, 0, 1, 0, 0, 0, 160, 15, 160, 15, 0, 0, 0, 0, 255, 255
+ 0, 0, 255, 127, 255, 127, 0, 0, 0, 0, 255, 255, 90, 0, 2, 0
+136, 19, 250, 0, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0
+ 18, 0, 160, 0, 68, 1, 128, 0, 73, 1, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 1, 0, 119, 0, 0, 0, 128, 0, 73, 1, 0, 0, 0, 0
+ 23, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 77
+ 71, 58, 80, 111, 119, 101, 114, 83, 104, 111, 116, 32, 83, 88, 50, 48
+ 48, 32, 73, 83, 32, 74, 80, 69, 71, 0, 0, 0, 0, 0, 70, 105
+114, 109, 119, 97, 114, 101, 32, 86, 101, 114, 115, 105, 111, 110, 32, 49
+ 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 211, 1, 0, 0, 155, 1
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 1
+ 0, 0, 221, 3, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 2, 0, 0, 123, 3
+ 0, 0, 165, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0
+ 0, 0, 66, 0, 0, 0, 10, 0, 0, 0, 17, 0, 0, 0, 70, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0
+ 0, 0, 204, 3, 0, 0, 138, 3, 0, 0, 138, 3, 0, 0, 128, 1
+ 0, 0, 66, 4, 0, 0, 165, 255, 255, 255, 0, 0, 0, 0, 0, 0
+ 0, 0, 138, 3, 0, 0, 138, 3, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 35, 0, 0, 0, 120, 0, 0, 0, 120, 0, 0, 0, 102, 255
+255, 255, 208, 0, 0, 0, 114, 255, 255, 255, 208, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 114, 255, 255, 255, 208, 0, 0, 0, 12, 0
+ 0, 0, 204, 0, 0, 0, 239, 255, 255, 255, 201, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4
+ 0, 0, 0, 5, 0, 0, 8, 0, 0, 0, 239, 255, 255, 255, 201, 0
+ 0, 0, 24, 0, 0, 0, 143, 3, 0, 0, 125, 6, 0, 0, 97, 6
+ 0, 0, 143, 3, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 113, 4, 0, 0, 204, 3
+ 0, 0, 147, 2, 0, 0, 165, 255, 255, 255, 10, 0, 0, 0, 128, 0
+ 0, 0, 251, 1, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 74, 2
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 2, 0, 0, 150, 2
+ 0, 0, 204, 2, 0, 0, 241, 2, 0, 0, 0, 0, 0, 0, 128, 0
+ 0, 0, 0, 0, 0, 0, 8, 162, 255, 255, 70, 2, 0, 0, 69, 2
+ 0, 0, 69, 2, 0, 0, 65, 2, 0, 0, 66, 2, 0, 0, 68, 2
+ 0, 0, 66, 2, 0, 0, 67, 2, 0, 0, 67, 2, 0, 0, 68, 2
+ 0, 0, 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 56, 5, 0, 0, 250, 0, 0, 0, 53, 1, 0, 0, 58, 0
+ 0, 0, 5, 4, 0, 0, 193, 0, 0, 0, 240, 0, 0, 0, 45, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0
+ 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0
+ 0, 0, 6, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0
+ 0, 0, 0, 244, 255, 255, 133, 0, 0, 0, 102, 2, 0, 0, 243, 1
+ 0, 0, 0, 0, 0, 0, 99, 2, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 192, 0, 0, 0, 4, 1, 0, 0, 0, 1, 0, 0, 4, 1
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 13, 0, 0, 0, 237, 157
+ 54, 41, 96, 0, 4, 0, 9, 0, 9, 0, 160, 15, 200, 8, 100, 0
+100, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0
+ 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0
+ 18, 0, 18, 0, 18, 0, 238, 255, 0, 0, 18, 0, 238, 255, 0, 0
+ 18, 0, 238, 255, 0, 0, 18, 0, 238, 255, 238, 255, 238, 255, 0, 0
+ 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 1, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 159, 0, 15, 0, 104, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 1, 0, 0, 0
+ 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 1, 0, 0, 0
+ 4, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 160, 1, 0, 0, 0, 0, 16, 0, 8, 0, 1, 0
+ 1, 0, 128, 2, 224, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 8, 0, 128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0
+255, 255, 0, 0, 0, 0, 239, 154, 237, 228, 191, 235, 20, 171, 30, 6
+ 2, 129, 88, 251, 56, 49, 73, 73, 42, 0, 222, 2, 0, 0
+TAG:UserComment=
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0
+TAG:FlashpixVersion= 48, 49, 48, 48
+TAG:ColorSpace= 1
+TAG:PixelXDimension= 4000
+TAG:PixelYDimension= 2248
+TAG:GPSLatitudeRef=R98
+TAG:GPSLatitude= 48, 49, 48, 48
+TAG:0x1001= 4000
+TAG:0x1002= 2248
+TAG:FocalPlaneXResolution=4000000:244
+TAG:FocalPlaneYResolution=2248000:183
+TAG:FocalPlaneResolutionUnit= 2
+TAG:SensingMethod= 2
+TAG:FileSource= 3
+TAG:CustomRendered= 0
+TAG:ExposureMode= 0
+TAG:WhiteBalance= 0
+TAG:DigitalZoomRatio= 4000:4000
+TAG:SceneCaptureType= 0
+[/FRAME]
diff --git a/tests/ref/fate/exif-image-tiff b/tests/ref/fate/exif-image-tiff
new file mode 100644
index 0000000000..2b10529a08
--- /dev/null
+++ b/tests/ref/fate/exif-image-tiff
@@ -0,0 +1,27 @@
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=1
+pkt_duration_time=0.040000
+pkt_pos=0
+pkt_size=67604
+width=200
+height=112
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=?
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+TAG:document_name=image_small.tiff
+TAG:page_number= 0 / 1
+TAG:software=ImageMagick 6.5.8-0 2010-02-09 Q16 http://www.imagemagick.org
+[/FRAME]
diff --git a/tests/ref/fate/exif-image-webp b/tests/ref/fate/exif-image-webp
new file mode 100644
index 0000000000..88e3c82923
--- /dev/null
+++ b/tests/ref/fate/exif-image-webp
@@ -0,0 +1,226 @@
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=1
+pkt_duration_time=0.040000
+pkt_pos=0
+pkt_size=39276
+width=400
+height=225
+pix_fmt=yuv420p
+sample_aspect_ratio=N/A
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+TAG:ImageDescription=
+TAG:Make=Canon
+TAG:Model=Canon PowerShot SX200 IS
+TAG:Orientation= 1
+TAG:XResolution= 180:1
+TAG:YResolution= 180:1
+TAG:ResolutionUnit= 2
+TAG:DateTime=2013:07:18 13:12:03
+TAG:YCbCrPositioning= 2
+TAG:ExposureTime= 1:1250
+TAG:FNumber= 40:10
+TAG:ISOSpeedRatings= 160
+TAG:ExifVersion= 48, 50, 50, 49
+TAG:DateTimeOriginal=2013:07:18 13:12:03
+TAG:DateTimeDigitized=2013:07:18 13:12:03
+TAG:ComponentsConfiguration= 1, 2, 3, 0
+TAG:CompressedBitsPerPixel= 3:1
+TAG:ShutterSpeedValue= 329:32
+TAG:ApertureValue= 128:32
+TAG:ExposureBiasValue= 0:3
+TAG:MaxApertureValue= 113:32
+TAG:MeteringMode= 5
+TAG:Flash= 16
+TAG:FocalLength= 5000:1000
+TAG:MakerNote=
+ 25, 0, 1, 0, 3, 0, 48, 0, 0, 0, 28, 4, 0, 0, 2, 0
+ 3, 0, 4, 0, 0, 0, 124, 4, 0, 0, 3, 0, 3, 0, 4, 0
+ 0, 0, 132, 4, 0, 0, 4, 0, 3, 0, 34, 0, 0, 0, 140, 4
+ 0, 0, 0, 0, 3, 0, 6, 0, 0, 0, 208, 4, 0, 0, 6, 0
+ 2, 0, 28, 0, 0, 0, 220, 4, 0, 0, 7, 0, 2, 0, 22, 0
+ 0, 0, 252, 4, 0, 0, 8, 0, 4, 0, 1, 0, 0, 0, 17, 166
+ 15, 0, 9, 0, 2, 0, 32, 0, 0, 0, 20, 5, 0, 0, 13, 0
+ 4, 0, 167, 0, 0, 0, 52, 5, 0, 0, 16, 0, 4, 0, 1, 0
+ 0, 0, 0, 0, 96, 2, 38, 0, 3, 0, 48, 0, 0, 0, 208, 7
+ 0, 0, 19, 0, 3, 0, 4, 0, 0, 0, 48, 8, 0, 0, 24, 0
+ 1, 0, 0, 1, 0, 0, 56, 8, 0, 0, 25, 0, 3, 0, 1, 0
+ 0, 0, 1, 0, 0, 0, 28, 0, 3, 0, 1, 0, 0, 0, 0, 0
+ 0, 0, 29, 0, 3, 0, 16, 0, 0, 0, 56, 9, 0, 0, 30, 0
+ 4, 0, 1, 0, 0, 0, 0, 4, 0, 1, 31, 0, 3, 0, 69, 0
+ 0, 0, 88, 9, 0, 0, 34, 0, 3, 0, 208, 0, 0, 0, 226, 9
+ 0, 0, 35, 0, 4, 0, 2, 0, 0, 0, 130, 11, 0, 0, 39, 0
+ 3, 0, 5, 0, 0, 0, 138, 11, 0, 0, 40, 0, 1, 0, 16, 0
+ 0, 0, 148, 11, 0, 0, 208, 0, 4, 0, 1, 0, 0, 0, 0, 0
+ 0, 0, 45, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0
+ 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 255, 255
+ 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0
+ 3, 0, 1, 0, 6, 64, 0, 0, 255, 127, 255, 255, 96, 234, 136, 19
+232, 3, 113, 0, 221, 0, 255, 255, 0, 0, 0, 0, 0, 0, 1, 0
+ 0, 0, 1, 0, 0, 0, 160, 15, 160, 15, 0, 0, 0, 0, 255, 255
+ 0, 0, 255, 127, 255, 127, 0, 0, 0, 0, 255, 255, 90, 0, 2, 0
+136, 19, 250, 0, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0
+ 18, 0, 160, 0, 68, 1, 128, 0, 73, 1, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 1, 0, 119, 0, 0, 0, 128, 0, 73, 1, 0, 0, 0, 0
+ 23, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 77
+ 71, 58, 80, 111, 119, 101, 114, 83, 104, 111, 116, 32, 83, 88, 50, 48
+ 48, 32, 73, 83, 32, 74, 80, 69, 71, 0, 0, 0, 0, 0, 70, 105
+114, 109, 119, 97, 114, 101, 32, 86, 101, 114, 115, 105, 111, 110, 32, 49
+ 46, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 211, 1, 0, 0, 155, 1
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 1
+ 0, 0, 221, 3, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 2, 0, 0, 123, 3
+ 0, 0, 165, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0
+ 0, 0, 66, 0, 0, 0, 10, 0, 0, 0, 17, 0, 0, 0, 70, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0
+ 0, 0, 204, 3, 0, 0, 138, 3, 0, 0, 138, 3, 0, 0, 128, 1
+ 0, 0, 66, 4, 0, 0, 165, 255, 255, 255, 0, 0, 0, 0, 0, 0
+ 0, 0, 138, 3, 0, 0, 138, 3, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 35, 0, 0, 0, 120, 0, 0, 0, 120, 0, 0, 0, 102, 255
+255, 255, 208, 0, 0, 0, 114, 255, 255, 255, 208, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 114, 255, 255, 255, 208, 0, 0, 0, 12, 0
+ 0, 0, 204, 0, 0, 0, 239, 255, 255, 255, 201, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 4
+ 0, 0, 0, 5, 0, 0, 8, 0, 0, 0, 239, 255, 255, 255, 201, 0
+ 0, 0, 24, 0, 0, 0, 143, 3, 0, 0, 125, 6, 0, 0, 97, 6
+ 0, 0, 143, 3, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 1, 0, 0, 0, 91, 1, 0, 0, 113, 4, 0, 0, 204, 3
+ 0, 0, 147, 2, 0, 0, 165, 255, 255, 255, 10, 0, 0, 0, 128, 0
+ 0, 0, 251, 1, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 74, 2
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 2, 0, 0, 150, 2
+ 0, 0, 204, 2, 0, 0, 241, 2, 0, 0, 0, 0, 0, 0, 128, 0
+ 0, 0, 0, 0, 0, 0, 8, 162, 255, 255, 70, 2, 0, 0, 69, 2
+ 0, 0, 69, 2, 0, 0, 65, 2, 0, 0, 66, 2, 0, 0, 68, 2
+ 0, 0, 66, 2, 0, 0, 67, 2, 0, 0, 67, 2, 0, 0, 68, 2
+ 0, 0, 18, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 56, 5, 0, 0, 250, 0, 0, 0, 53, 1, 0, 0, 58, 0
+ 0, 0, 5, 4, 0, 0, 193, 0, 0, 0, 240, 0, 0, 0, 45, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0
+ 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 0
+ 0, 0, 6, 255, 255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 0, 0
+ 0, 0, 0, 244, 255, 255, 133, 0, 0, 0, 102, 2, 0, 0, 243, 1
+ 0, 0, 0, 0, 0, 0, 99, 2, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 192, 0, 0, 0, 4, 1, 0, 0, 0, 1, 0, 0, 4, 1
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 13, 0, 0, 0, 237, 157
+ 54, 41, 96, 0, 4, 0, 9, 0, 9, 0, 160, 15, 200, 8, 100, 0
+100, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0
+ 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0, 18, 0
+ 18, 0, 18, 0, 18, 0, 238, 255, 0, 0, 18, 0, 238, 255, 0, 0
+ 18, 0, 238, 255, 0, 0, 18, 0, 238, 255, 238, 255, 238, 255, 0, 0
+ 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 1, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 159, 0, 15, 0, 104, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 1, 0, 0, 0
+ 2, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 1, 0, 0, 0
+ 4, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 160, 1, 0, 0, 0, 0, 16, 0, 8, 0, 1, 0
+ 1, 0, 128, 2, 224, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 8, 0, 128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0
+255, 255, 0, 0, 0, 0, 239, 154, 237, 228, 191, 235, 20, 171, 30, 6
+ 2, 129, 88, 251, 56, 49, 73, 73, 42, 0, 222, 2, 0, 0
+TAG:UserComment=
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0
+TAG:FlashpixVersion= 48, 49, 48, 48
+TAG:ColorSpace= 1
+TAG:PixelXDimension= 4000
+TAG:PixelYDimension= 2248
+TAG:GPSLatitudeRef=R98
+TAG:GPSLatitude= 48, 49, 48, 48
+TAG:0x1001= 4000
+TAG:0x1002= 2248
+TAG:FocalPlaneXResolution=4000000:244
+TAG:FocalPlaneYResolution=2248000:183
+TAG:FocalPlaneResolutionUnit= 2
+TAG:SensingMethod= 2
+TAG:FileSource= 3
+TAG:CustomRendered= 0
+TAG:ExposureMode= 0
+TAG:WhiteBalance= 0
+TAG:DigitalZoomRatio= 4000:4000
+TAG:SceneCaptureType= 0
+[/FRAME]
diff --git a/tests/ref/fate/ffmpeg-filter_complex b/tests/ref/fate/ffmpeg-filter_complex
new file mode 100644
index 0000000000..54d318db9d
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-filter_complex
@@ -0,0 +1,6 @@
+#tb 0: 1/5
+0, 0, 0, 1, 115200, 0x375ec573
+0, 1, 1, 1, 115200, 0x375ec573
+0, 2, 2, 1, 115200, 0x375ec573
+0, 3, 3, 1, 115200, 0x375ec573
+0, 4, 4, 1, 115200, 0x375ec573
diff --git a/tests/ref/fate/ffmpeg-lavfi b/tests/ref/fate/ffmpeg-lavfi
new file mode 100644
index 0000000000..54d318db9d
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-lavfi
@@ -0,0 +1,6 @@
+#tb 0: 1/5
+0, 0, 0, 1, 115200, 0x375ec573
+0, 1, 1, 1, 115200, 0x375ec573
+0, 2, 2, 1, 115200, 0x375ec573
+0, 3, 3, 1, 115200, 0x375ec573
+0, 4, 4, 1, 115200, 0x375ec573
diff --git a/tests/ref/fate/ffprobe_compact b/tests/ref/fate/ffprobe_compact
new file mode 100644
index 0000000000..fb0b834705
--- /dev/null
+++ b/tests/ref/fate/ffprobe_compact
@@ -0,0 +1,32 @@
+packet|codec_type=audio|stream_index=0|pts=0|pts_time=0.000000|dts=0|dts_time=0.000000|duration=1024|duration_time=0.023220|convergence_duration=N/A|convergence_duration_time=N/A|size=2048|pos=642|flags=K
+frame|media_type=audio|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=0|pkt_dts_time=0.000000|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=642|pkt_size=2048|sample_fmt=s16|nb_samples=1024|channels=1|channel_layout=unknown
+packet|codec_type=video|stream_index=1|pts=0|pts_time=0.000000|dts=0|dts_time=0.000000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=230400|pos=2717|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=0|pkt_dts_time=0.000000|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=2717|pkt_size=230400|width=320|height=240|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+packet|codec_type=video|stream_index=2|pts=0|pts_time=0.000000|dts=0|dts_time=0.000000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=30000|pos=233138|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=0|pkt_dts_time=0.000000|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=233138|pkt_size=30000|width=100|height=100|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+packet|codec_type=audio|stream_index=0|pts=1024|pts_time=0.023220|dts=1024|dts_time=0.023220|duration=1024|duration_time=0.023220|convergence_duration=N/A|convergence_duration_time=N/A|size=2048|pos=263143|flags=K
+frame|media_type=audio|key_frame=1|pkt_pts=1024|pkt_pts_time=0.023220|pkt_dts=1024|pkt_dts_time=0.023220|best_effort_timestamp=1024|best_effort_timestamp_time=0.023220|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=263143|pkt_size=2048|sample_fmt=s16|nb_samples=1024|channels=1|channel_layout=unknown
+packet|codec_type=video|stream_index=1|pts=2048|pts_time=0.040000|dts=2048|dts_time=0.040000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=230400|pos=265221|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=2048|pkt_pts_time=0.040000|pkt_dts=2048|pkt_dts_time=0.040000|best_effort_timestamp=2048|best_effort_timestamp_time=0.040000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=265221|pkt_size=230400|width=320|height=240|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+packet|codec_type=video|stream_index=2|pts=2048|pts_time=0.040000|dts=2048|dts_time=0.040000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=30000|pos=495645|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=2048|pkt_pts_time=0.040000|pkt_dts=2048|pkt_dts_time=0.040000|best_effort_timestamp=2048|best_effort_timestamp_time=0.040000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=495645|pkt_size=30000|width=100|height=100|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+packet|codec_type=audio|stream_index=0|pts=2048|pts_time=0.046440|dts=2048|dts_time=0.046440|duration=1024|duration_time=0.023220|convergence_duration=N/A|convergence_duration_time=N/A|size=2048|pos=525650|flags=K
+frame|media_type=audio|key_frame=1|pkt_pts=2048|pkt_pts_time=0.046440|pkt_dts=2048|pkt_dts_time=0.046440|best_effort_timestamp=2048|best_effort_timestamp_time=0.046440|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=525650|pkt_size=2048|sample_fmt=s16|nb_samples=1024|channels=1|channel_layout=unknown
+packet|codec_type=audio|stream_index=0|pts=3072|pts_time=0.069660|dts=3072|dts_time=0.069660|duration=1024|duration_time=0.023220|convergence_duration=N/A|convergence_duration_time=N/A|size=2048|pos=527721|flags=K
+frame|media_type=audio|key_frame=1|pkt_pts=3072|pkt_pts_time=0.069660|pkt_dts=3072|pkt_dts_time=0.069660|best_effort_timestamp=3072|best_effort_timestamp_time=0.069660|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=527721|pkt_size=2048|sample_fmt=s16|nb_samples=1024|channels=1|channel_layout=unknown
+packet|codec_type=video|stream_index=1|pts=4096|pts_time=0.080000|dts=4096|dts_time=0.080000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=230400|pos=529799|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=4096|pkt_pts_time=0.080000|pkt_dts=4096|pkt_dts_time=0.080000|best_effort_timestamp=4096|best_effort_timestamp_time=0.080000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=529799|pkt_size=230400|width=320|height=240|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+packet|codec_type=video|stream_index=2|pts=4096|pts_time=0.080000|dts=4096|dts_time=0.080000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=30000|pos=760223|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=4096|pkt_pts_time=0.080000|pkt_dts=4096|pkt_dts_time=0.080000|best_effort_timestamp=4096|best_effort_timestamp_time=0.080000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=760223|pkt_size=30000|width=100|height=100|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+packet|codec_type=audio|stream_index=0|pts=4096|pts_time=0.092880|dts=4096|dts_time=0.092880|duration=1024|duration_time=0.023220|convergence_duration=N/A|convergence_duration_time=N/A|size=2048|pos=790228|flags=K
+frame|media_type=audio|key_frame=1|pkt_pts=4096|pkt_pts_time=0.092880|pkt_dts=4096|pkt_dts_time=0.092880|best_effort_timestamp=4096|best_effort_timestamp_time=0.092880|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=790228|pkt_size=2048|sample_fmt=s16|nb_samples=1024|channels=1|channel_layout=unknown
+packet|codec_type=audio|stream_index=0|pts=5120|pts_time=0.116100|dts=5120|dts_time=0.116100|duration=1024|duration_time=0.023220|convergence_duration=N/A|convergence_duration_time=N/A|size=2048|pos=792299|flags=K
+frame|media_type=audio|key_frame=1|pkt_pts=5120|pkt_pts_time=0.116100|pkt_dts=5120|pkt_dts_time=0.116100|best_effort_timestamp=5120|best_effort_timestamp_time=0.116100|pkt_duration=1024|pkt_duration_time=0.023220|pkt_pos=792299|pkt_size=2048|sample_fmt=s16|nb_samples=1024|channels=1|channel_layout=unknown
+packet|codec_type=video|stream_index=1|pts=6144|pts_time=0.120000|dts=6144|dts_time=0.120000|duration=2048|duration_time=0.040000|convergence_duration=N/A|convergence_duration_time=N/A|size=230400|pos=794377|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=6144|pkt_pts_time=0.120000|pkt_dts=6144|pkt_dts_time=0.120000|best_effort_timestamp=6144|best_effort_timestamp_time=0.120000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=794377|pkt_size=230400|width=320|height=240|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+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|convergence_duration=N/A|convergence_duration_time=N/A|size=30000|pos=1024801|flags=K
+frame|media_type=video|key_frame=1|pkt_pts=6144|pkt_pts_time=0.120000|pkt_dts=6144|pkt_dts_time=0.120000|best_effort_timestamp=6144|best_effort_timestamp_time=0.120000|pkt_duration=2048|pkt_duration_time=0.040000|pkt_pos=1024801|pkt_size=30000|width=100|height=100|pix_fmt=rgb24|sample_aspect_ratio=1:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0
+stream|index=0|codec_name=pcm_s16le|profile=unknown|codec_type=audio|codec_time_base=1/44100|codec_tag_string=PSD[16]|codec_tag=0x10445350|sample_fmt=s16|sample_rate=44100|channels=1|channel_layout=unknown|bits_per_sample=16|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|tag:E=mc²|tag:encoder=Lavc pcm_s16le
+stream|index=1|codec_name=rawvideo|profile=unknown|codec_type=video|codec_time_base=1/51200|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=320|height=240|coded_width=320|coded_height=240|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=4:3|pix_fmt=rgb24|level=-99|color_range=N/A|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|timecode=N/A|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|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_time_base=1/51200|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=100|height=100|coded_width=100|coded_height=100|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=1:1|pix_fmt=rgb24|level=-99|color_range=N/A|color_space=unknown|color_transfer=unknown|color_primaries=unknown|chroma_location=unspecified|timecode=N/A|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|tag:encoder=Lavc rawvideo
+format|filename=tests/data/ffprobe-test.nut|nb_streams=3|nb_programs=0|format_name=nut|start_time=0.000000|duration=0.120000|size=1054882|bit_rate=70325466|probe_score=100|tag:title=ffprobe test file|tag:comment='A comment with CSV, XML & JSON special chars': <tag value="x">|tag:comment2=I ♥ ĂœĂ±Ă®Ă§Ă¸d€
diff --git a/tests/ref/fate/ffprobe_csv b/tests/ref/fate/ffprobe_csv
new file mode 100644
index 0000000000..496477fc44
--- /dev/null
+++ b/tests/ref/fate/ffprobe_csv
@@ -0,0 +1,32 @@
+packet,audio,0,0,0.000000,0,0.000000,1024,0.023220,N/A,N/A,2048,642,K
+frame,audio,1,0,0.000000,0,0.000000,0,0.000000,1024,0.023220,642,2048,s16,1024,1,unknown
+packet,video,1,0,0.000000,0,0.000000,2048,0.040000,N/A,N/A,230400,2717,K
+frame,video,1,0,0.000000,0,0.000000,0,0.000000,2048,0.040000,2717,230400,320,240,rgb24,1:1,I,0,0,0,0,0
+packet,video,2,0,0.000000,0,0.000000,2048,0.040000,N/A,N/A,30000,233138,K
+frame,video,1,0,0.000000,0,0.000000,0,0.000000,2048,0.040000,233138,30000,100,100,rgb24,1:1,I,0,0,0,0,0
+packet,audio,0,1024,0.023220,1024,0.023220,1024,0.023220,N/A,N/A,2048,263143,K
+frame,audio,1,1024,0.023220,1024,0.023220,1024,0.023220,1024,0.023220,263143,2048,s16,1024,1,unknown
+packet,video,1,2048,0.040000,2048,0.040000,2048,0.040000,N/A,N/A,230400,265221,K
+frame,video,1,2048,0.040000,2048,0.040000,2048,0.040000,2048,0.040000,265221,230400,320,240,rgb24,1:1,I,0,0,0,0,0
+packet,video,2,2048,0.040000,2048,0.040000,2048,0.040000,N/A,N/A,30000,495645,K
+frame,video,1,2048,0.040000,2048,0.040000,2048,0.040000,2048,0.040000,495645,30000,100,100,rgb24,1:1,I,0,0,0,0,0
+packet,audio,0,2048,0.046440,2048,0.046440,1024,0.023220,N/A,N/A,2048,525650,K
+frame,audio,1,2048,0.046440,2048,0.046440,2048,0.046440,1024,0.023220,525650,2048,s16,1024,1,unknown
+packet,audio,0,3072,0.069660,3072,0.069660,1024,0.023220,N/A,N/A,2048,527721,K
+frame,audio,1,3072,0.069660,3072,0.069660,3072,0.069660,1024,0.023220,527721,2048,s16,1024,1,unknown
+packet,video,1,4096,0.080000,4096,0.080000,2048,0.040000,N/A,N/A,230400,529799,K
+frame,video,1,4096,0.080000,4096,0.080000,4096,0.080000,2048,0.040000,529799,230400,320,240,rgb24,1:1,I,0,0,0,0,0
+packet,video,2,4096,0.080000,4096,0.080000,2048,0.040000,N/A,N/A,30000,760223,K
+frame,video,1,4096,0.080000,4096,0.080000,4096,0.080000,2048,0.040000,760223,30000,100,100,rgb24,1:1,I,0,0,0,0,0
+packet,audio,0,4096,0.092880,4096,0.092880,1024,0.023220,N/A,N/A,2048,790228,K
+frame,audio,1,4096,0.092880,4096,0.092880,4096,0.092880,1024,0.023220,790228,2048,s16,1024,1,unknown
+packet,audio,0,5120,0.116100,5120,0.116100,1024,0.023220,N/A,N/A,2048,792299,K
+frame,audio,1,5120,0.116100,5120,0.116100,5120,0.116100,1024,0.023220,792299,2048,s16,1024,1,unknown
+packet,video,1,6144,0.120000,6144,0.120000,2048,0.040000,N/A,N/A,230400,794377,K
+frame,video,1,6144,0.120000,6144,0.120000,6144,0.120000,2048,0.040000,794377,230400,320,240,rgb24,1:1,I,0,0,0,0,0
+packet,video,2,6144,0.120000,6144,0.120000,2048,0.040000,N/A,N/A,30000,1024801,K
+frame,video,1,6144,0.120000,6144,0.120000,6144,0.120000,2048,0.040000,1024801,30000,100,100,rgb24,1:1,I,0,0,0,0,0
+stream,0,pcm_s16le,unknown,audio,1/44100,PSD[16],0x10445350,s16,44100,1,unknown,16,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,mc²,Lavc pcm_s16le
+stream,1,rawvideo,unknown,video,1/51200,RGB[24],0x18424752,320,240,320,240,0,1:1,4:3,rgb24,-99,N/A,unknown,unknown,unknown,unspecified,N/A,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,foobar,field-and-tags-conflict-attempt,Lavc rawvideo
+stream,2,rawvideo,unknown,video,1/51200,RGB[24],0x18424752,100,100,100,100,0,1:1,1:1,rgb24,-99,N/A,unknown,unknown,unknown,unspecified,N/A,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,Lavc rawvideo
+format,tests/data/ffprobe-test.nut,3,0,nut,0.000000,0.120000,1054882,70325466,100,ffprobe test file,"'A comment with CSV, XML & JSON special chars': <tag value=""x"">",I ♥ ĂœĂ±Ă®Ă§Ă¸d€
diff --git a/tests/ref/fate/ffprobe_default b/tests/ref/fate/ffprobe_default
new file mode 100644
index 0000000000..123208a09d
--- /dev/null
+++ b/tests/ref/fate/ffprobe_default
@@ -0,0 +1,669 @@
+[PACKET]
+codec_type=audio
+stream_index=0
+pts=0
+pts_time=0.000000
+dts=0
+dts_time=0.000000
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=642
+flags=K
+[/PACKET]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=642
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=1
+pts=0
+pts_time=0.000000
+dts=0
+dts_time=0.000000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=2717
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=2717
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=2
+pts=0
+pts_time=0.000000
+dts=0
+dts_time=0.000000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=233138
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=233138
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[PACKET]
+codec_type=audio
+stream_index=0
+pts=1024
+pts_time=0.023220
+dts=1024
+dts_time=0.023220
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=263143
+flags=K
+[/PACKET]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=1024
+pkt_pts_time=0.023220
+pkt_dts=1024
+pkt_dts_time=0.023220
+best_effort_timestamp=1024
+best_effort_timestamp_time=0.023220
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=263143
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=1
+pts=2048
+pts_time=0.040000
+dts=2048
+dts_time=0.040000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=265221
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=2048
+pkt_pts_time=0.040000
+pkt_dts=2048
+pkt_dts_time=0.040000
+best_effort_timestamp=2048
+best_effort_timestamp_time=0.040000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=265221
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=2
+pts=2048
+pts_time=0.040000
+dts=2048
+dts_time=0.040000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=495645
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=2048
+pkt_pts_time=0.040000
+pkt_dts=2048
+pkt_dts_time=0.040000
+best_effort_timestamp=2048
+best_effort_timestamp_time=0.040000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=495645
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[PACKET]
+codec_type=audio
+stream_index=0
+pts=2048
+pts_time=0.046440
+dts=2048
+dts_time=0.046440
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=525650
+flags=K
+[/PACKET]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=2048
+pkt_pts_time=0.046440
+pkt_dts=2048
+pkt_dts_time=0.046440
+best_effort_timestamp=2048
+best_effort_timestamp_time=0.046440
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=525650
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+[/FRAME]
+[PACKET]
+codec_type=audio
+stream_index=0
+pts=3072
+pts_time=0.069660
+dts=3072
+dts_time=0.069660
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=527721
+flags=K
+[/PACKET]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=3072
+pkt_pts_time=0.069660
+pkt_dts=3072
+pkt_dts_time=0.069660
+best_effort_timestamp=3072
+best_effort_timestamp_time=0.069660
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=527721
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=1
+pts=4096
+pts_time=0.080000
+dts=4096
+dts_time=0.080000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=529799
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=4096
+pkt_pts_time=0.080000
+pkt_dts=4096
+pkt_dts_time=0.080000
+best_effort_timestamp=4096
+best_effort_timestamp_time=0.080000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=529799
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=2
+pts=4096
+pts_time=0.080000
+dts=4096
+dts_time=0.080000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=760223
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=4096
+pkt_pts_time=0.080000
+pkt_dts=4096
+pkt_dts_time=0.080000
+best_effort_timestamp=4096
+best_effort_timestamp_time=0.080000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=760223
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[PACKET]
+codec_type=audio
+stream_index=0
+pts=4096
+pts_time=0.092880
+dts=4096
+dts_time=0.092880
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=790228
+flags=K
+[/PACKET]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=4096
+pkt_pts_time=0.092880
+pkt_dts=4096
+pkt_dts_time=0.092880
+best_effort_timestamp=4096
+best_effort_timestamp_time=0.092880
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=790228
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+[/FRAME]
+[PACKET]
+codec_type=audio
+stream_index=0
+pts=5120
+pts_time=0.116100
+dts=5120
+dts_time=0.116100
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=792299
+flags=K
+[/PACKET]
+[FRAME]
+media_type=audio
+key_frame=1
+pkt_pts=5120
+pkt_pts_time=0.116100
+pkt_dts=5120
+pkt_dts_time=0.116100
+best_effort_timestamp=5120
+best_effort_timestamp_time=0.116100
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=792299
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+[/FRAME]
+[PACKET]
+codec_type=video
+stream_index=1
+pts=6144
+pts_time=0.120000
+dts=6144
+dts_time=0.120000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=794377
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=6144
+pkt_pts_time=0.120000
+pkt_dts=6144
+pkt_dts_time=0.120000
+best_effort_timestamp=6144
+best_effort_timestamp_time=0.120000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=794377
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[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
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=1024801
+flags=K
+[/PACKET]
+[FRAME]
+media_type=video
+key_frame=1
+pkt_pts=6144
+pkt_pts_time=0.120000
+pkt_dts=6144
+pkt_dts_time=0.120000
+best_effort_timestamp=6144
+best_effort_timestamp_time=0.120000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=1024801
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+[/FRAME]
+[STREAM]
+index=0
+codec_name=pcm_s16le
+profile=unknown
+codec_type=audio
+codec_time_base=1/44100
+codec_tag_string=PSD[16]
+codec_tag=0x10445350
+sample_fmt=s16
+sample_rate=44100
+channels=1
+channel_layout=unknown
+bits_per_sample=16
+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
+TAG:E=mc²
+TAG:encoder=Lavc pcm_s16le
+[/STREAM]
+[STREAM]
+index=1
+codec_name=rawvideo
+profile=unknown
+codec_type=video
+codec_time_base=1/51200
+codec_tag_string=RGB[24]
+codec_tag=0x18424752
+width=320
+height=240
+coded_width=320
+coded_height=240
+has_b_frames=0
+sample_aspect_ratio=1:1
+display_aspect_ratio=4:3
+pix_fmt=rgb24
+level=-99
+color_range=N/A
+color_space=unknown
+color_transfer=unknown
+color_primaries=unknown
+chroma_location=unspecified
+timecode=N/A
+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
+TAG:title=foobar
+TAG:duration_ts=field-and-tags-conflict-attempt
+TAG:encoder=Lavc rawvideo
+[/STREAM]
+[STREAM]
+index=2
+codec_name=rawvideo
+profile=unknown
+codec_type=video
+codec_time_base=1/51200
+codec_tag_string=RGB[24]
+codec_tag=0x18424752
+width=100
+height=100
+coded_width=100
+coded_height=100
+has_b_frames=0
+sample_aspect_ratio=1:1
+display_aspect_ratio=1:1
+pix_fmt=rgb24
+level=-99
+color_range=N/A
+color_space=unknown
+color_transfer=unknown
+color_primaries=unknown
+chroma_location=unspecified
+timecode=N/A
+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
+TAG:encoder=Lavc rawvideo
+[/STREAM]
+[FORMAT]
+filename=tests/data/ffprobe-test.nut
+nb_streams=3
+nb_programs=0
+format_name=nut
+start_time=0.000000
+duration=0.120000
+size=1054882
+bit_rate=70325466
+probe_score=100
+TAG:title=ffprobe test file
+TAG:comment='A comment with CSV, XML & JSON special chars': <tag value="x">
+TAG:comment2=I ♥ ĂœĂ±Ă®Ă§Ă¸d€
+[/FORMAT]
diff --git a/tests/ref/fate/ffprobe_flat b/tests/ref/fate/ffprobe_flat
new file mode 100644
index 0000000000..5c02a21d66
--- /dev/null
+++ b/tests/ref/fate/ffprobe_flat
@@ -0,0 +1,605 @@
+packets_and_frames.packet.0.codec_type="audio"
+packets_and_frames.packet.0.stream_index=0
+packets_and_frames.packet.0.pts=0
+packets_and_frames.packet.0.pts_time="0.000000"
+packets_and_frames.packet.0.dts=0
+packets_and_frames.packet.0.dts_time="0.000000"
+packets_and_frames.packet.0.duration=1024
+packets_and_frames.packet.0.duration_time="0.023220"
+packets_and_frames.packet.0.convergence_duration="N/A"
+packets_and_frames.packet.0.convergence_duration_time="N/A"
+packets_and_frames.packet.0.size="2048"
+packets_and_frames.packet.0.pos="642"
+packets_and_frames.packet.0.flags="K"
+packets_and_frames.frame.0.media_type="audio"
+packets_and_frames.frame.0.key_frame=1
+packets_and_frames.frame.0.pkt_pts=0
+packets_and_frames.frame.0.pkt_pts_time="0.000000"
+packets_and_frames.frame.0.pkt_dts=0
+packets_and_frames.frame.0.pkt_dts_time="0.000000"
+packets_and_frames.frame.0.best_effort_timestamp=0
+packets_and_frames.frame.0.best_effort_timestamp_time="0.000000"
+packets_and_frames.frame.0.pkt_duration=1024
+packets_and_frames.frame.0.pkt_duration_time="0.023220"
+packets_and_frames.frame.0.pkt_pos="642"
+packets_and_frames.frame.0.pkt_size="2048"
+packets_and_frames.frame.0.sample_fmt="s16"
+packets_and_frames.frame.0.nb_samples=1024
+packets_and_frames.frame.0.channels=1
+packets_and_frames.frame.0.channel_layout="unknown"
+packets_and_frames.packet.1.codec_type="video"
+packets_and_frames.packet.1.stream_index=1
+packets_and_frames.packet.1.pts=0
+packets_and_frames.packet.1.pts_time="0.000000"
+packets_and_frames.packet.1.dts=0
+packets_and_frames.packet.1.dts_time="0.000000"
+packets_and_frames.packet.1.duration=2048
+packets_and_frames.packet.1.duration_time="0.040000"
+packets_and_frames.packet.1.convergence_duration="N/A"
+packets_and_frames.packet.1.convergence_duration_time="N/A"
+packets_and_frames.packet.1.size="230400"
+packets_and_frames.packet.1.pos="2717"
+packets_and_frames.packet.1.flags="K"
+packets_and_frames.frame.1.media_type="video"
+packets_and_frames.frame.1.key_frame=1
+packets_and_frames.frame.1.pkt_pts=0
+packets_and_frames.frame.1.pkt_pts_time="0.000000"
+packets_and_frames.frame.1.pkt_dts=0
+packets_and_frames.frame.1.pkt_dts_time="0.000000"
+packets_and_frames.frame.1.best_effort_timestamp=0
+packets_and_frames.frame.1.best_effort_timestamp_time="0.000000"
+packets_and_frames.frame.1.pkt_duration=2048
+packets_and_frames.frame.1.pkt_duration_time="0.040000"
+packets_and_frames.frame.1.pkt_pos="2717"
+packets_and_frames.frame.1.pkt_size="230400"
+packets_and_frames.frame.1.width=320
+packets_and_frames.frame.1.height=240
+packets_and_frames.frame.1.pix_fmt="rgb24"
+packets_and_frames.frame.1.sample_aspect_ratio="1:1"
+packets_and_frames.frame.1.pict_type="I"
+packets_and_frames.frame.1.coded_picture_number=0
+packets_and_frames.frame.1.display_picture_number=0
+packets_and_frames.frame.1.interlaced_frame=0
+packets_and_frames.frame.1.top_field_first=0
+packets_and_frames.frame.1.repeat_pict=0
+packets_and_frames.packet.2.codec_type="video"
+packets_and_frames.packet.2.stream_index=2
+packets_and_frames.packet.2.pts=0
+packets_and_frames.packet.2.pts_time="0.000000"
+packets_and_frames.packet.2.dts=0
+packets_and_frames.packet.2.dts_time="0.000000"
+packets_and_frames.packet.2.duration=2048
+packets_and_frames.packet.2.duration_time="0.040000"
+packets_and_frames.packet.2.convergence_duration="N/A"
+packets_and_frames.packet.2.convergence_duration_time="N/A"
+packets_and_frames.packet.2.size="30000"
+packets_and_frames.packet.2.pos="233138"
+packets_and_frames.packet.2.flags="K"
+packets_and_frames.frame.2.media_type="video"
+packets_and_frames.frame.2.key_frame=1
+packets_and_frames.frame.2.pkt_pts=0
+packets_and_frames.frame.2.pkt_pts_time="0.000000"
+packets_and_frames.frame.2.pkt_dts=0
+packets_and_frames.frame.2.pkt_dts_time="0.000000"
+packets_and_frames.frame.2.best_effort_timestamp=0
+packets_and_frames.frame.2.best_effort_timestamp_time="0.000000"
+packets_and_frames.frame.2.pkt_duration=2048
+packets_and_frames.frame.2.pkt_duration_time="0.040000"
+packets_and_frames.frame.2.pkt_pos="233138"
+packets_and_frames.frame.2.pkt_size="30000"
+packets_and_frames.frame.2.width=100
+packets_and_frames.frame.2.height=100
+packets_and_frames.frame.2.pix_fmt="rgb24"
+packets_and_frames.frame.2.sample_aspect_ratio="1:1"
+packets_and_frames.frame.2.pict_type="I"
+packets_and_frames.frame.2.coded_picture_number=0
+packets_and_frames.frame.2.display_picture_number=0
+packets_and_frames.frame.2.interlaced_frame=0
+packets_and_frames.frame.2.top_field_first=0
+packets_and_frames.frame.2.repeat_pict=0
+packets_and_frames.packet.3.codec_type="audio"
+packets_and_frames.packet.3.stream_index=0
+packets_and_frames.packet.3.pts=1024
+packets_and_frames.packet.3.pts_time="0.023220"
+packets_and_frames.packet.3.dts=1024
+packets_and_frames.packet.3.dts_time="0.023220"
+packets_and_frames.packet.3.duration=1024
+packets_and_frames.packet.3.duration_time="0.023220"
+packets_and_frames.packet.3.convergence_duration="N/A"
+packets_and_frames.packet.3.convergence_duration_time="N/A"
+packets_and_frames.packet.3.size="2048"
+packets_and_frames.packet.3.pos="263143"
+packets_and_frames.packet.3.flags="K"
+packets_and_frames.frame.3.media_type="audio"
+packets_and_frames.frame.3.key_frame=1
+packets_and_frames.frame.3.pkt_pts=1024
+packets_and_frames.frame.3.pkt_pts_time="0.023220"
+packets_and_frames.frame.3.pkt_dts=1024
+packets_and_frames.frame.3.pkt_dts_time="0.023220"
+packets_and_frames.frame.3.best_effort_timestamp=1024
+packets_and_frames.frame.3.best_effort_timestamp_time="0.023220"
+packets_and_frames.frame.3.pkt_duration=1024
+packets_and_frames.frame.3.pkt_duration_time="0.023220"
+packets_and_frames.frame.3.pkt_pos="263143"
+packets_and_frames.frame.3.pkt_size="2048"
+packets_and_frames.frame.3.sample_fmt="s16"
+packets_and_frames.frame.3.nb_samples=1024
+packets_and_frames.frame.3.channels=1
+packets_and_frames.frame.3.channel_layout="unknown"
+packets_and_frames.packet.4.codec_type="video"
+packets_and_frames.packet.4.stream_index=1
+packets_and_frames.packet.4.pts=2048
+packets_and_frames.packet.4.pts_time="0.040000"
+packets_and_frames.packet.4.dts=2048
+packets_and_frames.packet.4.dts_time="0.040000"
+packets_and_frames.packet.4.duration=2048
+packets_and_frames.packet.4.duration_time="0.040000"
+packets_and_frames.packet.4.convergence_duration="N/A"
+packets_and_frames.packet.4.convergence_duration_time="N/A"
+packets_and_frames.packet.4.size="230400"
+packets_and_frames.packet.4.pos="265221"
+packets_and_frames.packet.4.flags="K"
+packets_and_frames.frame.4.media_type="video"
+packets_and_frames.frame.4.key_frame=1
+packets_and_frames.frame.4.pkt_pts=2048
+packets_and_frames.frame.4.pkt_pts_time="0.040000"
+packets_and_frames.frame.4.pkt_dts=2048
+packets_and_frames.frame.4.pkt_dts_time="0.040000"
+packets_and_frames.frame.4.best_effort_timestamp=2048
+packets_and_frames.frame.4.best_effort_timestamp_time="0.040000"
+packets_and_frames.frame.4.pkt_duration=2048
+packets_and_frames.frame.4.pkt_duration_time="0.040000"
+packets_and_frames.frame.4.pkt_pos="265221"
+packets_and_frames.frame.4.pkt_size="230400"
+packets_and_frames.frame.4.width=320
+packets_and_frames.frame.4.height=240
+packets_and_frames.frame.4.pix_fmt="rgb24"
+packets_and_frames.frame.4.sample_aspect_ratio="1:1"
+packets_and_frames.frame.4.pict_type="I"
+packets_and_frames.frame.4.coded_picture_number=0
+packets_and_frames.frame.4.display_picture_number=0
+packets_and_frames.frame.4.interlaced_frame=0
+packets_and_frames.frame.4.top_field_first=0
+packets_and_frames.frame.4.repeat_pict=0
+packets_and_frames.packet.5.codec_type="video"
+packets_and_frames.packet.5.stream_index=2
+packets_and_frames.packet.5.pts=2048
+packets_and_frames.packet.5.pts_time="0.040000"
+packets_and_frames.packet.5.dts=2048
+packets_and_frames.packet.5.dts_time="0.040000"
+packets_and_frames.packet.5.duration=2048
+packets_and_frames.packet.5.duration_time="0.040000"
+packets_and_frames.packet.5.convergence_duration="N/A"
+packets_and_frames.packet.5.convergence_duration_time="N/A"
+packets_and_frames.packet.5.size="30000"
+packets_and_frames.packet.5.pos="495645"
+packets_and_frames.packet.5.flags="K"
+packets_and_frames.frame.5.media_type="video"
+packets_and_frames.frame.5.key_frame=1
+packets_and_frames.frame.5.pkt_pts=2048
+packets_and_frames.frame.5.pkt_pts_time="0.040000"
+packets_and_frames.frame.5.pkt_dts=2048
+packets_and_frames.frame.5.pkt_dts_time="0.040000"
+packets_and_frames.frame.5.best_effort_timestamp=2048
+packets_and_frames.frame.5.best_effort_timestamp_time="0.040000"
+packets_and_frames.frame.5.pkt_duration=2048
+packets_and_frames.frame.5.pkt_duration_time="0.040000"
+packets_and_frames.frame.5.pkt_pos="495645"
+packets_and_frames.frame.5.pkt_size="30000"
+packets_and_frames.frame.5.width=100
+packets_and_frames.frame.5.height=100
+packets_and_frames.frame.5.pix_fmt="rgb24"
+packets_and_frames.frame.5.sample_aspect_ratio="1:1"
+packets_and_frames.frame.5.pict_type="I"
+packets_and_frames.frame.5.coded_picture_number=0
+packets_and_frames.frame.5.display_picture_number=0
+packets_and_frames.frame.5.interlaced_frame=0
+packets_and_frames.frame.5.top_field_first=0
+packets_and_frames.frame.5.repeat_pict=0
+packets_and_frames.packet.6.codec_type="audio"
+packets_and_frames.packet.6.stream_index=0
+packets_and_frames.packet.6.pts=2048
+packets_and_frames.packet.6.pts_time="0.046440"
+packets_and_frames.packet.6.dts=2048
+packets_and_frames.packet.6.dts_time="0.046440"
+packets_and_frames.packet.6.duration=1024
+packets_and_frames.packet.6.duration_time="0.023220"
+packets_and_frames.packet.6.convergence_duration="N/A"
+packets_and_frames.packet.6.convergence_duration_time="N/A"
+packets_and_frames.packet.6.size="2048"
+packets_and_frames.packet.6.pos="525650"
+packets_and_frames.packet.6.flags="K"
+packets_and_frames.frame.6.media_type="audio"
+packets_and_frames.frame.6.key_frame=1
+packets_and_frames.frame.6.pkt_pts=2048
+packets_and_frames.frame.6.pkt_pts_time="0.046440"
+packets_and_frames.frame.6.pkt_dts=2048
+packets_and_frames.frame.6.pkt_dts_time="0.046440"
+packets_and_frames.frame.6.best_effort_timestamp=2048
+packets_and_frames.frame.6.best_effort_timestamp_time="0.046440"
+packets_and_frames.frame.6.pkt_duration=1024
+packets_and_frames.frame.6.pkt_duration_time="0.023220"
+packets_and_frames.frame.6.pkt_pos="525650"
+packets_and_frames.frame.6.pkt_size="2048"
+packets_and_frames.frame.6.sample_fmt="s16"
+packets_and_frames.frame.6.nb_samples=1024
+packets_and_frames.frame.6.channels=1
+packets_and_frames.frame.6.channel_layout="unknown"
+packets_and_frames.packet.7.codec_type="audio"
+packets_and_frames.packet.7.stream_index=0
+packets_and_frames.packet.7.pts=3072
+packets_and_frames.packet.7.pts_time="0.069660"
+packets_and_frames.packet.7.dts=3072
+packets_and_frames.packet.7.dts_time="0.069660"
+packets_and_frames.packet.7.duration=1024
+packets_and_frames.packet.7.duration_time="0.023220"
+packets_and_frames.packet.7.convergence_duration="N/A"
+packets_and_frames.packet.7.convergence_duration_time="N/A"
+packets_and_frames.packet.7.size="2048"
+packets_and_frames.packet.7.pos="527721"
+packets_and_frames.packet.7.flags="K"
+packets_and_frames.frame.7.media_type="audio"
+packets_and_frames.frame.7.key_frame=1
+packets_and_frames.frame.7.pkt_pts=3072
+packets_and_frames.frame.7.pkt_pts_time="0.069660"
+packets_and_frames.frame.7.pkt_dts=3072
+packets_and_frames.frame.7.pkt_dts_time="0.069660"
+packets_and_frames.frame.7.best_effort_timestamp=3072
+packets_and_frames.frame.7.best_effort_timestamp_time="0.069660"
+packets_and_frames.frame.7.pkt_duration=1024
+packets_and_frames.frame.7.pkt_duration_time="0.023220"
+packets_and_frames.frame.7.pkt_pos="527721"
+packets_and_frames.frame.7.pkt_size="2048"
+packets_and_frames.frame.7.sample_fmt="s16"
+packets_and_frames.frame.7.nb_samples=1024
+packets_and_frames.frame.7.channels=1
+packets_and_frames.frame.7.channel_layout="unknown"
+packets_and_frames.packet.8.codec_type="video"
+packets_and_frames.packet.8.stream_index=1
+packets_and_frames.packet.8.pts=4096
+packets_and_frames.packet.8.pts_time="0.080000"
+packets_and_frames.packet.8.dts=4096
+packets_and_frames.packet.8.dts_time="0.080000"
+packets_and_frames.packet.8.duration=2048
+packets_and_frames.packet.8.duration_time="0.040000"
+packets_and_frames.packet.8.convergence_duration="N/A"
+packets_and_frames.packet.8.convergence_duration_time="N/A"
+packets_and_frames.packet.8.size="230400"
+packets_and_frames.packet.8.pos="529799"
+packets_and_frames.packet.8.flags="K"
+packets_and_frames.frame.8.media_type="video"
+packets_and_frames.frame.8.key_frame=1
+packets_and_frames.frame.8.pkt_pts=4096
+packets_and_frames.frame.8.pkt_pts_time="0.080000"
+packets_and_frames.frame.8.pkt_dts=4096
+packets_and_frames.frame.8.pkt_dts_time="0.080000"
+packets_and_frames.frame.8.best_effort_timestamp=4096
+packets_and_frames.frame.8.best_effort_timestamp_time="0.080000"
+packets_and_frames.frame.8.pkt_duration=2048
+packets_and_frames.frame.8.pkt_duration_time="0.040000"
+packets_and_frames.frame.8.pkt_pos="529799"
+packets_and_frames.frame.8.pkt_size="230400"
+packets_and_frames.frame.8.width=320
+packets_and_frames.frame.8.height=240
+packets_and_frames.frame.8.pix_fmt="rgb24"
+packets_and_frames.frame.8.sample_aspect_ratio="1:1"
+packets_and_frames.frame.8.pict_type="I"
+packets_and_frames.frame.8.coded_picture_number=0
+packets_and_frames.frame.8.display_picture_number=0
+packets_and_frames.frame.8.interlaced_frame=0
+packets_and_frames.frame.8.top_field_first=0
+packets_and_frames.frame.8.repeat_pict=0
+packets_and_frames.packet.9.codec_type="video"
+packets_and_frames.packet.9.stream_index=2
+packets_and_frames.packet.9.pts=4096
+packets_and_frames.packet.9.pts_time="0.080000"
+packets_and_frames.packet.9.dts=4096
+packets_and_frames.packet.9.dts_time="0.080000"
+packets_and_frames.packet.9.duration=2048
+packets_and_frames.packet.9.duration_time="0.040000"
+packets_and_frames.packet.9.convergence_duration="N/A"
+packets_and_frames.packet.9.convergence_duration_time="N/A"
+packets_and_frames.packet.9.size="30000"
+packets_and_frames.packet.9.pos="760223"
+packets_and_frames.packet.9.flags="K"
+packets_and_frames.frame.9.media_type="video"
+packets_and_frames.frame.9.key_frame=1
+packets_and_frames.frame.9.pkt_pts=4096
+packets_and_frames.frame.9.pkt_pts_time="0.080000"
+packets_and_frames.frame.9.pkt_dts=4096
+packets_and_frames.frame.9.pkt_dts_time="0.080000"
+packets_and_frames.frame.9.best_effort_timestamp=4096
+packets_and_frames.frame.9.best_effort_timestamp_time="0.080000"
+packets_and_frames.frame.9.pkt_duration=2048
+packets_and_frames.frame.9.pkt_duration_time="0.040000"
+packets_and_frames.frame.9.pkt_pos="760223"
+packets_and_frames.frame.9.pkt_size="30000"
+packets_and_frames.frame.9.width=100
+packets_and_frames.frame.9.height=100
+packets_and_frames.frame.9.pix_fmt="rgb24"
+packets_and_frames.frame.9.sample_aspect_ratio="1:1"
+packets_and_frames.frame.9.pict_type="I"
+packets_and_frames.frame.9.coded_picture_number=0
+packets_and_frames.frame.9.display_picture_number=0
+packets_and_frames.frame.9.interlaced_frame=0
+packets_and_frames.frame.9.top_field_first=0
+packets_and_frames.frame.9.repeat_pict=0
+packets_and_frames.packet.10.codec_type="audio"
+packets_and_frames.packet.10.stream_index=0
+packets_and_frames.packet.10.pts=4096
+packets_and_frames.packet.10.pts_time="0.092880"
+packets_and_frames.packet.10.dts=4096
+packets_and_frames.packet.10.dts_time="0.092880"
+packets_and_frames.packet.10.duration=1024
+packets_and_frames.packet.10.duration_time="0.023220"
+packets_and_frames.packet.10.convergence_duration="N/A"
+packets_and_frames.packet.10.convergence_duration_time="N/A"
+packets_and_frames.packet.10.size="2048"
+packets_and_frames.packet.10.pos="790228"
+packets_and_frames.packet.10.flags="K"
+packets_and_frames.frame.10.media_type="audio"
+packets_and_frames.frame.10.key_frame=1
+packets_and_frames.frame.10.pkt_pts=4096
+packets_and_frames.frame.10.pkt_pts_time="0.092880"
+packets_and_frames.frame.10.pkt_dts=4096
+packets_and_frames.frame.10.pkt_dts_time="0.092880"
+packets_and_frames.frame.10.best_effort_timestamp=4096
+packets_and_frames.frame.10.best_effort_timestamp_time="0.092880"
+packets_and_frames.frame.10.pkt_duration=1024
+packets_and_frames.frame.10.pkt_duration_time="0.023220"
+packets_and_frames.frame.10.pkt_pos="790228"
+packets_and_frames.frame.10.pkt_size="2048"
+packets_and_frames.frame.10.sample_fmt="s16"
+packets_and_frames.frame.10.nb_samples=1024
+packets_and_frames.frame.10.channels=1
+packets_and_frames.frame.10.channel_layout="unknown"
+packets_and_frames.packet.11.codec_type="audio"
+packets_and_frames.packet.11.stream_index=0
+packets_and_frames.packet.11.pts=5120
+packets_and_frames.packet.11.pts_time="0.116100"
+packets_and_frames.packet.11.dts=5120
+packets_and_frames.packet.11.dts_time="0.116100"
+packets_and_frames.packet.11.duration=1024
+packets_and_frames.packet.11.duration_time="0.023220"
+packets_and_frames.packet.11.convergence_duration="N/A"
+packets_and_frames.packet.11.convergence_duration_time="N/A"
+packets_and_frames.packet.11.size="2048"
+packets_and_frames.packet.11.pos="792299"
+packets_and_frames.packet.11.flags="K"
+packets_and_frames.frame.11.media_type="audio"
+packets_and_frames.frame.11.key_frame=1
+packets_and_frames.frame.11.pkt_pts=5120
+packets_and_frames.frame.11.pkt_pts_time="0.116100"
+packets_and_frames.frame.11.pkt_dts=5120
+packets_and_frames.frame.11.pkt_dts_time="0.116100"
+packets_and_frames.frame.11.best_effort_timestamp=5120
+packets_and_frames.frame.11.best_effort_timestamp_time="0.116100"
+packets_and_frames.frame.11.pkt_duration=1024
+packets_and_frames.frame.11.pkt_duration_time="0.023220"
+packets_and_frames.frame.11.pkt_pos="792299"
+packets_and_frames.frame.11.pkt_size="2048"
+packets_and_frames.frame.11.sample_fmt="s16"
+packets_and_frames.frame.11.nb_samples=1024
+packets_and_frames.frame.11.channels=1
+packets_and_frames.frame.11.channel_layout="unknown"
+packets_and_frames.packet.12.codec_type="video"
+packets_and_frames.packet.12.stream_index=1
+packets_and_frames.packet.12.pts=6144
+packets_and_frames.packet.12.pts_time="0.120000"
+packets_and_frames.packet.12.dts=6144
+packets_and_frames.packet.12.dts_time="0.120000"
+packets_and_frames.packet.12.duration=2048
+packets_and_frames.packet.12.duration_time="0.040000"
+packets_and_frames.packet.12.convergence_duration="N/A"
+packets_and_frames.packet.12.convergence_duration_time="N/A"
+packets_and_frames.packet.12.size="230400"
+packets_and_frames.packet.12.pos="794377"
+packets_and_frames.packet.12.flags="K"
+packets_and_frames.frame.12.media_type="video"
+packets_and_frames.frame.12.key_frame=1
+packets_and_frames.frame.12.pkt_pts=6144
+packets_and_frames.frame.12.pkt_pts_time="0.120000"
+packets_and_frames.frame.12.pkt_dts=6144
+packets_and_frames.frame.12.pkt_dts_time="0.120000"
+packets_and_frames.frame.12.best_effort_timestamp=6144
+packets_and_frames.frame.12.best_effort_timestamp_time="0.120000"
+packets_and_frames.frame.12.pkt_duration=2048
+packets_and_frames.frame.12.pkt_duration_time="0.040000"
+packets_and_frames.frame.12.pkt_pos="794377"
+packets_and_frames.frame.12.pkt_size="230400"
+packets_and_frames.frame.12.width=320
+packets_and_frames.frame.12.height=240
+packets_and_frames.frame.12.pix_fmt="rgb24"
+packets_and_frames.frame.12.sample_aspect_ratio="1:1"
+packets_and_frames.frame.12.pict_type="I"
+packets_and_frames.frame.12.coded_picture_number=0
+packets_and_frames.frame.12.display_picture_number=0
+packets_and_frames.frame.12.interlaced_frame=0
+packets_and_frames.frame.12.top_field_first=0
+packets_and_frames.frame.12.repeat_pict=0
+packets_and_frames.packet.13.codec_type="video"
+packets_and_frames.packet.13.stream_index=2
+packets_and_frames.packet.13.pts=6144
+packets_and_frames.packet.13.pts_time="0.120000"
+packets_and_frames.packet.13.dts=6144
+packets_and_frames.packet.13.dts_time="0.120000"
+packets_and_frames.packet.13.duration=2048
+packets_and_frames.packet.13.duration_time="0.040000"
+packets_and_frames.packet.13.convergence_duration="N/A"
+packets_and_frames.packet.13.convergence_duration_time="N/A"
+packets_and_frames.packet.13.size="30000"
+packets_and_frames.packet.13.pos="1024801"
+packets_and_frames.packet.13.flags="K"
+packets_and_frames.frame.13.media_type="video"
+packets_and_frames.frame.13.key_frame=1
+packets_and_frames.frame.13.pkt_pts=6144
+packets_and_frames.frame.13.pkt_pts_time="0.120000"
+packets_and_frames.frame.13.pkt_dts=6144
+packets_and_frames.frame.13.pkt_dts_time="0.120000"
+packets_and_frames.frame.13.best_effort_timestamp=6144
+packets_and_frames.frame.13.best_effort_timestamp_time="0.120000"
+packets_and_frames.frame.13.pkt_duration=2048
+packets_and_frames.frame.13.pkt_duration_time="0.040000"
+packets_and_frames.frame.13.pkt_pos="1024801"
+packets_and_frames.frame.13.pkt_size="30000"
+packets_and_frames.frame.13.width=100
+packets_and_frames.frame.13.height=100
+packets_and_frames.frame.13.pix_fmt="rgb24"
+packets_and_frames.frame.13.sample_aspect_ratio="1:1"
+packets_and_frames.frame.13.pict_type="I"
+packets_and_frames.frame.13.coded_picture_number=0
+packets_and_frames.frame.13.display_picture_number=0
+packets_and_frames.frame.13.interlaced_frame=0
+packets_and_frames.frame.13.top_field_first=0
+packets_and_frames.frame.13.repeat_pict=0
+streams.stream.0.index=0
+streams.stream.0.codec_name="pcm_s16le"
+streams.stream.0.profile="unknown"
+streams.stream.0.codec_type="audio"
+streams.stream.0.codec_time_base="1/44100"
+streams.stream.0.codec_tag_string="PSD[16]"
+streams.stream.0.codec_tag="0x10445350"
+streams.stream.0.sample_fmt="s16"
+streams.stream.0.sample_rate="44100"
+streams.stream.0.channels=1
+streams.stream.0.channel_layout="unknown"
+streams.stream.0.bits_per_sample=16
+streams.stream.0.id="N/A"
+streams.stream.0.r_frame_rate="0/0"
+streams.stream.0.avg_frame_rate="0/0"
+streams.stream.0.time_base="1/44100"
+streams.stream.0.start_pts=0
+streams.stream.0.start_time="0.000000"
+streams.stream.0.duration_ts="N/A"
+streams.stream.0.duration="N/A"
+streams.stream.0.bit_rate="705600"
+streams.stream.0.max_bit_rate="N/A"
+streams.stream.0.bits_per_raw_sample="N/A"
+streams.stream.0.nb_frames="N/A"
+streams.stream.0.nb_read_frames="6"
+streams.stream.0.nb_read_packets="6"
+streams.stream.0.disposition.default=0
+streams.stream.0.disposition.dub=0
+streams.stream.0.disposition.original=0
+streams.stream.0.disposition.comment=0
+streams.stream.0.disposition.lyrics=0
+streams.stream.0.disposition.karaoke=0
+streams.stream.0.disposition.forced=0
+streams.stream.0.disposition.hearing_impaired=0
+streams.stream.0.disposition.visual_impaired=0
+streams.stream.0.disposition.clean_effects=0
+streams.stream.0.disposition.attached_pic=0
+streams.stream.0.tags.E="mc²"
+streams.stream.0.tags.encoder="Lavc pcm_s16le"
+streams.stream.1.index=1
+streams.stream.1.codec_name="rawvideo"
+streams.stream.1.profile="unknown"
+streams.stream.1.codec_type="video"
+streams.stream.1.codec_time_base="1/51200"
+streams.stream.1.codec_tag_string="RGB[24]"
+streams.stream.1.codec_tag="0x18424752"
+streams.stream.1.width=320
+streams.stream.1.height=240
+streams.stream.1.coded_width=320
+streams.stream.1.coded_height=240
+streams.stream.1.has_b_frames=0
+streams.stream.1.sample_aspect_ratio="1:1"
+streams.stream.1.display_aspect_ratio="4:3"
+streams.stream.1.pix_fmt="rgb24"
+streams.stream.1.level=-99
+streams.stream.1.color_range="N/A"
+streams.stream.1.color_space="unknown"
+streams.stream.1.color_transfer="unknown"
+streams.stream.1.color_primaries="unknown"
+streams.stream.1.chroma_location="unspecified"
+streams.stream.1.timecode="N/A"
+streams.stream.1.refs=1
+streams.stream.1.id="N/A"
+streams.stream.1.r_frame_rate="25/1"
+streams.stream.1.avg_frame_rate="25/1"
+streams.stream.1.time_base="1/51200"
+streams.stream.1.start_pts=0
+streams.stream.1.start_time="0.000000"
+streams.stream.1.duration_ts="N/A"
+streams.stream.1.duration="N/A"
+streams.stream.1.bit_rate="N/A"
+streams.stream.1.max_bit_rate="N/A"
+streams.stream.1.bits_per_raw_sample="N/A"
+streams.stream.1.nb_frames="N/A"
+streams.stream.1.nb_read_frames="4"
+streams.stream.1.nb_read_packets="4"
+streams.stream.1.disposition.default=0
+streams.stream.1.disposition.dub=0
+streams.stream.1.disposition.original=0
+streams.stream.1.disposition.comment=0
+streams.stream.1.disposition.lyrics=0
+streams.stream.1.disposition.karaoke=0
+streams.stream.1.disposition.forced=0
+streams.stream.1.disposition.hearing_impaired=0
+streams.stream.1.disposition.visual_impaired=0
+streams.stream.1.disposition.clean_effects=0
+streams.stream.1.disposition.attached_pic=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"
+streams.stream.2.index=2
+streams.stream.2.codec_name="rawvideo"
+streams.stream.2.profile="unknown"
+streams.stream.2.codec_type="video"
+streams.stream.2.codec_time_base="1/51200"
+streams.stream.2.codec_tag_string="RGB[24]"
+streams.stream.2.codec_tag="0x18424752"
+streams.stream.2.width=100
+streams.stream.2.height=100
+streams.stream.2.coded_width=100
+streams.stream.2.coded_height=100
+streams.stream.2.has_b_frames=0
+streams.stream.2.sample_aspect_ratio="1:1"
+streams.stream.2.display_aspect_ratio="1:1"
+streams.stream.2.pix_fmt="rgb24"
+streams.stream.2.level=-99
+streams.stream.2.color_range="N/A"
+streams.stream.2.color_space="unknown"
+streams.stream.2.color_transfer="unknown"
+streams.stream.2.color_primaries="unknown"
+streams.stream.2.chroma_location="unspecified"
+streams.stream.2.timecode="N/A"
+streams.stream.2.refs=1
+streams.stream.2.id="N/A"
+streams.stream.2.r_frame_rate="25/1"
+streams.stream.2.avg_frame_rate="25/1"
+streams.stream.2.time_base="1/51200"
+streams.stream.2.start_pts=0
+streams.stream.2.start_time="0.000000"
+streams.stream.2.duration_ts="N/A"
+streams.stream.2.duration="N/A"
+streams.stream.2.bit_rate="N/A"
+streams.stream.2.max_bit_rate="N/A"
+streams.stream.2.bits_per_raw_sample="N/A"
+streams.stream.2.nb_frames="N/A"
+streams.stream.2.nb_read_frames="4"
+streams.stream.2.nb_read_packets="4"
+streams.stream.2.disposition.default=0
+streams.stream.2.disposition.dub=0
+streams.stream.2.disposition.original=0
+streams.stream.2.disposition.comment=0
+streams.stream.2.disposition.lyrics=0
+streams.stream.2.disposition.karaoke=0
+streams.stream.2.disposition.forced=0
+streams.stream.2.disposition.hearing_impaired=0
+streams.stream.2.disposition.visual_impaired=0
+streams.stream.2.disposition.clean_effects=0
+streams.stream.2.disposition.attached_pic=0
+streams.stream.2.tags.encoder="Lavc rawvideo"
+format.filename="tests/data/ffprobe-test.nut"
+format.nb_streams=3
+format.nb_programs=0
+format.format_name="nut"
+format.start_time="0.000000"
+format.duration="0.120000"
+format.size="1054882"
+format.bit_rate="70325466"
+format.probe_score=100
+format.tags.title="ffprobe test file"
+format.tags.comment="'A comment with CSV, XML & JSON special chars': <tag value=\"x\">"
+format.tags.comment2="I ♥ ĂœĂ±Ă®Ă§Ă¸d€"
diff --git a/tests/ref/fate/ffprobe_ini b/tests/ref/fate/ffprobe_ini
new file mode 100644
index 0000000000..e30c2fe450
--- /dev/null
+++ b/tests/ref/fate/ffprobe_ini
@@ -0,0 +1,684 @@
+# ffprobe output
+
+[packets_and_frames.packet.0]
+codec_type=audio
+stream_index=0
+pts=0
+pts_time=0.000000
+dts=0
+dts_time=0.000000
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=642
+flags=K
+
+[packets_and_frames.frame.0]
+media_type=audio
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=642
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+
+[packets_and_frames.packet.1]
+codec_type=video
+stream_index=1
+pts=0
+pts_time=0.000000
+dts=0
+dts_time=0.000000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=2717
+flags=K
+
+[packets_and_frames.frame.1]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=2717
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.2]
+codec_type=video
+stream_index=2
+pts=0
+pts_time=0.000000
+dts=0
+dts_time=0.000000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=233138
+flags=K
+
+[packets_and_frames.frame.2]
+media_type=video
+key_frame=1
+pkt_pts=0
+pkt_pts_time=0.000000
+pkt_dts=0
+pkt_dts_time=0.000000
+best_effort_timestamp=0
+best_effort_timestamp_time=0.000000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=233138
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.3]
+codec_type=audio
+stream_index=0
+pts=1024
+pts_time=0.023220
+dts=1024
+dts_time=0.023220
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=263143
+flags=K
+
+[packets_and_frames.frame.3]
+media_type=audio
+key_frame=1
+pkt_pts=1024
+pkt_pts_time=0.023220
+pkt_dts=1024
+pkt_dts_time=0.023220
+best_effort_timestamp=1024
+best_effort_timestamp_time=0.023220
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=263143
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+
+[packets_and_frames.packet.4]
+codec_type=video
+stream_index=1
+pts=2048
+pts_time=0.040000
+dts=2048
+dts_time=0.040000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=265221
+flags=K
+
+[packets_and_frames.frame.4]
+media_type=video
+key_frame=1
+pkt_pts=2048
+pkt_pts_time=0.040000
+pkt_dts=2048
+pkt_dts_time=0.040000
+best_effort_timestamp=2048
+best_effort_timestamp_time=0.040000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=265221
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.5]
+codec_type=video
+stream_index=2
+pts=2048
+pts_time=0.040000
+dts=2048
+dts_time=0.040000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=495645
+flags=K
+
+[packets_and_frames.frame.5]
+media_type=video
+key_frame=1
+pkt_pts=2048
+pkt_pts_time=0.040000
+pkt_dts=2048
+pkt_dts_time=0.040000
+best_effort_timestamp=2048
+best_effort_timestamp_time=0.040000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=495645
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.6]
+codec_type=audio
+stream_index=0
+pts=2048
+pts_time=0.046440
+dts=2048
+dts_time=0.046440
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=525650
+flags=K
+
+[packets_and_frames.frame.6]
+media_type=audio
+key_frame=1
+pkt_pts=2048
+pkt_pts_time=0.046440
+pkt_dts=2048
+pkt_dts_time=0.046440
+best_effort_timestamp=2048
+best_effort_timestamp_time=0.046440
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=525650
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+
+[packets_and_frames.packet.7]
+codec_type=audio
+stream_index=0
+pts=3072
+pts_time=0.069660
+dts=3072
+dts_time=0.069660
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=527721
+flags=K
+
+[packets_and_frames.frame.7]
+media_type=audio
+key_frame=1
+pkt_pts=3072
+pkt_pts_time=0.069660
+pkt_dts=3072
+pkt_dts_time=0.069660
+best_effort_timestamp=3072
+best_effort_timestamp_time=0.069660
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=527721
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+
+[packets_and_frames.packet.8]
+codec_type=video
+stream_index=1
+pts=4096
+pts_time=0.080000
+dts=4096
+dts_time=0.080000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=529799
+flags=K
+
+[packets_and_frames.frame.8]
+media_type=video
+key_frame=1
+pkt_pts=4096
+pkt_pts_time=0.080000
+pkt_dts=4096
+pkt_dts_time=0.080000
+best_effort_timestamp=4096
+best_effort_timestamp_time=0.080000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=529799
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.9]
+codec_type=video
+stream_index=2
+pts=4096
+pts_time=0.080000
+dts=4096
+dts_time=0.080000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=760223
+flags=K
+
+[packets_and_frames.frame.9]
+media_type=video
+key_frame=1
+pkt_pts=4096
+pkt_pts_time=0.080000
+pkt_dts=4096
+pkt_dts_time=0.080000
+best_effort_timestamp=4096
+best_effort_timestamp_time=0.080000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=760223
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.10]
+codec_type=audio
+stream_index=0
+pts=4096
+pts_time=0.092880
+dts=4096
+dts_time=0.092880
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=790228
+flags=K
+
+[packets_and_frames.frame.10]
+media_type=audio
+key_frame=1
+pkt_pts=4096
+pkt_pts_time=0.092880
+pkt_dts=4096
+pkt_dts_time=0.092880
+best_effort_timestamp=4096
+best_effort_timestamp_time=0.092880
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=790228
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+
+[packets_and_frames.packet.11]
+codec_type=audio
+stream_index=0
+pts=5120
+pts_time=0.116100
+dts=5120
+dts_time=0.116100
+duration=1024
+duration_time=0.023220
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=2048
+pos=792299
+flags=K
+
+[packets_and_frames.frame.11]
+media_type=audio
+key_frame=1
+pkt_pts=5120
+pkt_pts_time=0.116100
+pkt_dts=5120
+pkt_dts_time=0.116100
+best_effort_timestamp=5120
+best_effort_timestamp_time=0.116100
+pkt_duration=1024
+pkt_duration_time=0.023220
+pkt_pos=792299
+pkt_size=2048
+sample_fmt=s16
+nb_samples=1024
+channels=1
+channel_layout=unknown
+
+[packets_and_frames.packet.12]
+codec_type=video
+stream_index=1
+pts=6144
+pts_time=0.120000
+dts=6144
+dts_time=0.120000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=230400
+pos=794377
+flags=K
+
+[packets_and_frames.frame.12]
+media_type=video
+key_frame=1
+pkt_pts=6144
+pkt_pts_time=0.120000
+pkt_dts=6144
+pkt_dts_time=0.120000
+best_effort_timestamp=6144
+best_effort_timestamp_time=0.120000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=794377
+pkt_size=230400
+width=320
+height=240
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[packets_and_frames.packet.13]
+codec_type=video
+stream_index=2
+pts=6144
+pts_time=0.120000
+dts=6144
+dts_time=0.120000
+duration=2048
+duration_time=0.040000
+convergence_duration=N/A
+convergence_duration_time=N/A
+size=30000
+pos=1024801
+flags=K
+
+[packets_and_frames.frame.13]
+media_type=video
+key_frame=1
+pkt_pts=6144
+pkt_pts_time=0.120000
+pkt_dts=6144
+pkt_dts_time=0.120000
+best_effort_timestamp=6144
+best_effort_timestamp_time=0.120000
+pkt_duration=2048
+pkt_duration_time=0.040000
+pkt_pos=1024801
+pkt_size=30000
+width=100
+height=100
+pix_fmt=rgb24
+sample_aspect_ratio=1\:1
+pict_type=I
+coded_picture_number=0
+display_picture_number=0
+interlaced_frame=0
+top_field_first=0
+repeat_pict=0
+
+[streams.stream.0]
+index=0
+codec_name=pcm_s16le
+profile=unknown
+codec_type=audio
+codec_time_base=1/44100
+codec_tag_string=PSD[16]
+codec_tag=0x10445350
+sample_fmt=s16
+sample_rate=44100
+channels=1
+channel_layout=unknown
+bits_per_sample=16
+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
+
+[streams.stream.0.disposition]
+default=0
+dub=0
+original=0
+comment=0
+lyrics=0
+karaoke=0
+forced=0
+hearing_impaired=0
+visual_impaired=0
+clean_effects=0
+attached_pic=0
+
+[streams.stream.0.tags]
+E=mc²
+encoder=Lavc pcm_s16le
+
+[streams.stream.1]
+index=1
+codec_name=rawvideo
+profile=unknown
+codec_type=video
+codec_time_base=1/51200
+codec_tag_string=RGB[24]
+codec_tag=0x18424752
+width=320
+height=240
+coded_width=320
+coded_height=240
+has_b_frames=0
+sample_aspect_ratio=1\:1
+display_aspect_ratio=4\:3
+pix_fmt=rgb24
+level=-99
+color_range=N/A
+color_space=unknown
+color_transfer=unknown
+color_primaries=unknown
+chroma_location=unspecified
+timecode=N/A
+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
+
+[streams.stream.1.disposition]
+default=0
+dub=0
+original=0
+comment=0
+lyrics=0
+karaoke=0
+forced=0
+hearing_impaired=0
+visual_impaired=0
+clean_effects=0
+attached_pic=0
+
+[streams.stream.1.tags]
+title=foobar
+duration_ts=field-and-tags-conflict-attempt
+encoder=Lavc rawvideo
+
+[streams.stream.2]
+index=2
+codec_name=rawvideo
+profile=unknown
+codec_type=video
+codec_time_base=1/51200
+codec_tag_string=RGB[24]
+codec_tag=0x18424752
+width=100
+height=100
+coded_width=100
+coded_height=100
+has_b_frames=0
+sample_aspect_ratio=1\:1
+display_aspect_ratio=1\:1
+pix_fmt=rgb24
+level=-99
+color_range=N/A
+color_space=unknown
+color_transfer=unknown
+color_primaries=unknown
+chroma_location=unspecified
+timecode=N/A
+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
+
+[streams.stream.2.disposition]
+default=0
+dub=0
+original=0
+comment=0
+lyrics=0
+karaoke=0
+forced=0
+hearing_impaired=0
+visual_impaired=0
+clean_effects=0
+attached_pic=0
+
+[streams.stream.2.tags]
+encoder=Lavc rawvideo
+
+[format]
+filename=tests/data/ffprobe-test.nut
+nb_streams=3
+nb_programs=0
+format_name=nut
+start_time=0.000000
+duration=0.120000
+size=1054882
+bit_rate=70325466
+probe_score=100
+
+[format.tags]
+title=ffprobe test file
+comment='A comment with CSV, XML & JSON special chars'\: <tag value\="x">
+comment2=I ♥ ĂœĂ±Ă®Ă§Ă¸d€
diff --git a/tests/ref/fate/ffprobe_json b/tests/ref/fate/ffprobe_json
new file mode 100644
index 0000000000..ee2f8e6da9
--- /dev/null
+++ b/tests/ref/fate/ffprobe_json
@@ -0,0 +1,647 @@
+{
+ "packets_and_frames": [
+ {
+ "type": "packet",
+ "codec_type": "audio",
+ "stream_index": 0,
+ "pts": 0,
+ "pts_time": "0.000000",
+ "dts": 0,
+ "dts_time": "0.000000",
+ "duration": 1024,
+ "duration_time": "0.023220",
+ "size": "2048",
+ "pos": "642",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "audio",
+ "key_frame": 1,
+ "pkt_pts": 0,
+ "pkt_pts_time": "0.000000",
+ "pkt_dts": 0,
+ "pkt_dts_time": "0.000000",
+ "best_effort_timestamp": 0,
+ "best_effort_timestamp_time": "0.000000",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "642",
+ "pkt_size": "2048",
+ "sample_fmt": "s16",
+ "nb_samples": 1024,
+ "channels": 1
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 1,
+ "pts": 0,
+ "pts_time": "0.000000",
+ "dts": 0,
+ "dts_time": "0.000000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "230400",
+ "pos": "2717",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 0,
+ "pkt_pts_time": "0.000000",
+ "pkt_dts": 0,
+ "pkt_dts_time": "0.000000",
+ "best_effort_timestamp": 0,
+ "best_effort_timestamp_time": "0.000000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "2717",
+ "pkt_size": "230400",
+ "width": 320,
+ "height": 240,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 2,
+ "pts": 0,
+ "pts_time": "0.000000",
+ "dts": 0,
+ "dts_time": "0.000000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "30000",
+ "pos": "233138",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 0,
+ "pkt_pts_time": "0.000000",
+ "pkt_dts": 0,
+ "pkt_dts_time": "0.000000",
+ "best_effort_timestamp": 0,
+ "best_effort_timestamp_time": "0.000000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "233138",
+ "pkt_size": "30000",
+ "width": 100,
+ "height": 100,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "packet",
+ "codec_type": "audio",
+ "stream_index": 0,
+ "pts": 1024,
+ "pts_time": "0.023220",
+ "dts": 1024,
+ "dts_time": "0.023220",
+ "duration": 1024,
+ "duration_time": "0.023220",
+ "size": "2048",
+ "pos": "263143",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "audio",
+ "key_frame": 1,
+ "pkt_pts": 1024,
+ "pkt_pts_time": "0.023220",
+ "pkt_dts": 1024,
+ "pkt_dts_time": "0.023220",
+ "best_effort_timestamp": 1024,
+ "best_effort_timestamp_time": "0.023220",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "263143",
+ "pkt_size": "2048",
+ "sample_fmt": "s16",
+ "nb_samples": 1024,
+ "channels": 1
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 1,
+ "pts": 2048,
+ "pts_time": "0.040000",
+ "dts": 2048,
+ "dts_time": "0.040000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "230400",
+ "pos": "265221",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 2048,
+ "pkt_pts_time": "0.040000",
+ "pkt_dts": 2048,
+ "pkt_dts_time": "0.040000",
+ "best_effort_timestamp": 2048,
+ "best_effort_timestamp_time": "0.040000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "265221",
+ "pkt_size": "230400",
+ "width": 320,
+ "height": 240,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 2,
+ "pts": 2048,
+ "pts_time": "0.040000",
+ "dts": 2048,
+ "dts_time": "0.040000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "30000",
+ "pos": "495645",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 2048,
+ "pkt_pts_time": "0.040000",
+ "pkt_dts": 2048,
+ "pkt_dts_time": "0.040000",
+ "best_effort_timestamp": 2048,
+ "best_effort_timestamp_time": "0.040000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "495645",
+ "pkt_size": "30000",
+ "width": 100,
+ "height": 100,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "packet",
+ "codec_type": "audio",
+ "stream_index": 0,
+ "pts": 2048,
+ "pts_time": "0.046440",
+ "dts": 2048,
+ "dts_time": "0.046440",
+ "duration": 1024,
+ "duration_time": "0.023220",
+ "size": "2048",
+ "pos": "525650",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "audio",
+ "key_frame": 1,
+ "pkt_pts": 2048,
+ "pkt_pts_time": "0.046440",
+ "pkt_dts": 2048,
+ "pkt_dts_time": "0.046440",
+ "best_effort_timestamp": 2048,
+ "best_effort_timestamp_time": "0.046440",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "525650",
+ "pkt_size": "2048",
+ "sample_fmt": "s16",
+ "nb_samples": 1024,
+ "channels": 1
+ },
+ {
+ "type": "packet",
+ "codec_type": "audio",
+ "stream_index": 0,
+ "pts": 3072,
+ "pts_time": "0.069660",
+ "dts": 3072,
+ "dts_time": "0.069660",
+ "duration": 1024,
+ "duration_time": "0.023220",
+ "size": "2048",
+ "pos": "527721",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "audio",
+ "key_frame": 1,
+ "pkt_pts": 3072,
+ "pkt_pts_time": "0.069660",
+ "pkt_dts": 3072,
+ "pkt_dts_time": "0.069660",
+ "best_effort_timestamp": 3072,
+ "best_effort_timestamp_time": "0.069660",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "527721",
+ "pkt_size": "2048",
+ "sample_fmt": "s16",
+ "nb_samples": 1024,
+ "channels": 1
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 1,
+ "pts": 4096,
+ "pts_time": "0.080000",
+ "dts": 4096,
+ "dts_time": "0.080000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "230400",
+ "pos": "529799",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 4096,
+ "pkt_pts_time": "0.080000",
+ "pkt_dts": 4096,
+ "pkt_dts_time": "0.080000",
+ "best_effort_timestamp": 4096,
+ "best_effort_timestamp_time": "0.080000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "529799",
+ "pkt_size": "230400",
+ "width": 320,
+ "height": 240,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 2,
+ "pts": 4096,
+ "pts_time": "0.080000",
+ "dts": 4096,
+ "dts_time": "0.080000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "30000",
+ "pos": "760223",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 4096,
+ "pkt_pts_time": "0.080000",
+ "pkt_dts": 4096,
+ "pkt_dts_time": "0.080000",
+ "best_effort_timestamp": 4096,
+ "best_effort_timestamp_time": "0.080000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "760223",
+ "pkt_size": "30000",
+ "width": 100,
+ "height": 100,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "packet",
+ "codec_type": "audio",
+ "stream_index": 0,
+ "pts": 4096,
+ "pts_time": "0.092880",
+ "dts": 4096,
+ "dts_time": "0.092880",
+ "duration": 1024,
+ "duration_time": "0.023220",
+ "size": "2048",
+ "pos": "790228",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "audio",
+ "key_frame": 1,
+ "pkt_pts": 4096,
+ "pkt_pts_time": "0.092880",
+ "pkt_dts": 4096,
+ "pkt_dts_time": "0.092880",
+ "best_effort_timestamp": 4096,
+ "best_effort_timestamp_time": "0.092880",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "790228",
+ "pkt_size": "2048",
+ "sample_fmt": "s16",
+ "nb_samples": 1024,
+ "channels": 1
+ },
+ {
+ "type": "packet",
+ "codec_type": "audio",
+ "stream_index": 0,
+ "pts": 5120,
+ "pts_time": "0.116100",
+ "dts": 5120,
+ "dts_time": "0.116100",
+ "duration": 1024,
+ "duration_time": "0.023220",
+ "size": "2048",
+ "pos": "792299",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "audio",
+ "key_frame": 1,
+ "pkt_pts": 5120,
+ "pkt_pts_time": "0.116100",
+ "pkt_dts": 5120,
+ "pkt_dts_time": "0.116100",
+ "best_effort_timestamp": 5120,
+ "best_effort_timestamp_time": "0.116100",
+ "pkt_duration": 1024,
+ "pkt_duration_time": "0.023220",
+ "pkt_pos": "792299",
+ "pkt_size": "2048",
+ "sample_fmt": "s16",
+ "nb_samples": 1024,
+ "channels": 1
+ },
+ {
+ "type": "packet",
+ "codec_type": "video",
+ "stream_index": 1,
+ "pts": 6144,
+ "pts_time": "0.120000",
+ "dts": 6144,
+ "dts_time": "0.120000",
+ "duration": 2048,
+ "duration_time": "0.040000",
+ "size": "230400",
+ "pos": "794377",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 6144,
+ "pkt_pts_time": "0.120000",
+ "pkt_dts": 6144,
+ "pkt_dts_time": "0.120000",
+ "best_effort_timestamp": 6144,
+ "best_effort_timestamp_time": "0.120000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "794377",
+ "pkt_size": "230400",
+ "width": 320,
+ "height": 240,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ },
+ {
+ "type": "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": "1024801",
+ "flags": "K"
+ },
+ {
+ "type": "frame",
+ "media_type": "video",
+ "key_frame": 1,
+ "pkt_pts": 6144,
+ "pkt_pts_time": "0.120000",
+ "pkt_dts": 6144,
+ "pkt_dts_time": "0.120000",
+ "best_effort_timestamp": 6144,
+ "best_effort_timestamp_time": "0.120000",
+ "pkt_duration": 2048,
+ "pkt_duration_time": "0.040000",
+ "pkt_pos": "1024801",
+ "pkt_size": "30000",
+ "width": 100,
+ "height": 100,
+ "pix_fmt": "rgb24",
+ "sample_aspect_ratio": "1:1",
+ "pict_type": "I",
+ "coded_picture_number": 0,
+ "display_picture_number": 0,
+ "interlaced_frame": 0,
+ "top_field_first": 0,
+ "repeat_pict": 0
+ }
+ ],
+ "streams": [
+ {
+ "index": 0,
+ "codec_name": "pcm_s16le",
+ "codec_type": "audio",
+ "codec_time_base": "1/44100",
+ "codec_tag_string": "PSD[16]",
+ "codec_tag": "0x10445350",
+ "sample_fmt": "s16",
+ "sample_rate": "44100",
+ "channels": 1,
+ "bits_per_sample": 16,
+ "r_frame_rate": "0/0",
+ "avg_frame_rate": "0/0",
+ "time_base": "1/44100",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "bit_rate": "705600",
+ "nb_read_frames": "6",
+ "nb_read_packets": "6",
+ "disposition": {
+ "default": 0,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0
+ },
+ "tags": {
+ "E": "mc²",
+ "encoder": "Lavc pcm_s16le"
+ }
+ },
+ {
+ "index": 1,
+ "codec_name": "rawvideo",
+ "codec_type": "video",
+ "codec_time_base": "1/51200",
+ "codec_tag_string": "RGB[24]",
+ "codec_tag": "0x18424752",
+ "width": 320,
+ "height": 240,
+ "coded_width": 320,
+ "coded_height": 240,
+ "has_b_frames": 0,
+ "sample_aspect_ratio": "1:1",
+ "display_aspect_ratio": "4:3",
+ "pix_fmt": "rgb24",
+ "level": -99,
+ "refs": 1,
+ "r_frame_rate": "25/1",
+ "avg_frame_rate": "25/1",
+ "time_base": "1/51200",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "nb_read_frames": "4",
+ "nb_read_packets": "4",
+ "disposition": {
+ "default": 0,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0
+ },
+ "tags": {
+ "title": "foobar",
+ "duration_ts": "field-and-tags-conflict-attempt",
+ "encoder": "Lavc rawvideo"
+ }
+ },
+ {
+ "index": 2,
+ "codec_name": "rawvideo",
+ "codec_type": "video",
+ "codec_time_base": "1/51200",
+ "codec_tag_string": "RGB[24]",
+ "codec_tag": "0x18424752",
+ "width": 100,
+ "height": 100,
+ "coded_width": 100,
+ "coded_height": 100,
+ "has_b_frames": 0,
+ "sample_aspect_ratio": "1:1",
+ "display_aspect_ratio": "1:1",
+ "pix_fmt": "rgb24",
+ "level": -99,
+ "refs": 1,
+ "r_frame_rate": "25/1",
+ "avg_frame_rate": "25/1",
+ "time_base": "1/51200",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "nb_read_frames": "4",
+ "nb_read_packets": "4",
+ "disposition": {
+ "default": 0,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0
+ },
+ "tags": {
+ "encoder": "Lavc rawvideo"
+ }
+ }
+ ],
+ "format": {
+ "filename": "tests/data/ffprobe-test.nut",
+ "nb_streams": 3,
+ "nb_programs": 0,
+ "format_name": "nut",
+ "start_time": "0.000000",
+ "duration": "0.120000",
+ "size": "1054882",
+ "bit_rate": "70325466",
+ "probe_score": 100,
+ "tags": {
+ "title": "ffprobe test file",
+ "comment": "'A comment with CSV, XML & JSON special chars': <tag value=\"x\">",
+ "comment2": "I ♥ ĂœĂ±Ă®Ă§Ă¸d€"
+ }
+ }
+}
diff --git a/tests/ref/fate/ffprobe_xml b/tests/ref/fate/ffprobe_xml
new file mode 100644
index 0000000000..5dad3e7ba1
--- /dev/null
+++ b/tests/ref/fate/ffprobe_xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ffprobe>
+ <packets_and_frames>
+ <packet codec_type="audio" stream_index="0" pts="0" pts_time="0.000000" dts="0" dts_time="0.000000" duration="1024" duration_time="0.023220" size="2048" pos="642" flags="K"/>
+ <frame media_type="audio" key_frame="1" pkt_pts="0" pkt_pts_time="0.000000" pkt_dts="0" pkt_dts_time="0.000000" best_effort_timestamp="0" best_effort_timestamp_time="0.000000" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="642" pkt_size="2048" sample_fmt="s16" nb_samples="1024" channels="1"/>
+ <packet codec_type="video" stream_index="1" pts="0" pts_time="0.000000" dts="0" dts_time="0.000000" duration="2048" duration_time="0.040000" size="230400" pos="2717" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="0" pkt_pts_time="0.000000" pkt_dts="0" pkt_dts_time="0.000000" best_effort_timestamp="0" best_effort_timestamp_time="0.000000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="2717" pkt_size="230400" width="320" height="240" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <packet codec_type="video" stream_index="2" pts="0" pts_time="0.000000" dts="0" dts_time="0.000000" duration="2048" duration_time="0.040000" size="30000" pos="233138" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="0" pkt_pts_time="0.000000" pkt_dts="0" pkt_dts_time="0.000000" best_effort_timestamp="0" best_effort_timestamp_time="0.000000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="233138" pkt_size="30000" width="100" height="100" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <packet codec_type="audio" stream_index="0" pts="1024" pts_time="0.023220" dts="1024" dts_time="0.023220" duration="1024" duration_time="0.023220" size="2048" pos="263143" flags="K"/>
+ <frame media_type="audio" key_frame="1" pkt_pts="1024" pkt_pts_time="0.023220" pkt_dts="1024" pkt_dts_time="0.023220" best_effort_timestamp="1024" best_effort_timestamp_time="0.023220" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="263143" pkt_size="2048" sample_fmt="s16" nb_samples="1024" channels="1"/>
+ <packet codec_type="video" stream_index="1" pts="2048" pts_time="0.040000" dts="2048" dts_time="0.040000" duration="2048" duration_time="0.040000" size="230400" pos="265221" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="2048" pkt_pts_time="0.040000" pkt_dts="2048" pkt_dts_time="0.040000" best_effort_timestamp="2048" best_effort_timestamp_time="0.040000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="265221" pkt_size="230400" width="320" height="240" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <packet codec_type="video" stream_index="2" pts="2048" pts_time="0.040000" dts="2048" dts_time="0.040000" duration="2048" duration_time="0.040000" size="30000" pos="495645" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="2048" pkt_pts_time="0.040000" pkt_dts="2048" pkt_dts_time="0.040000" best_effort_timestamp="2048" best_effort_timestamp_time="0.040000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="495645" pkt_size="30000" width="100" height="100" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <packet codec_type="audio" stream_index="0" pts="2048" pts_time="0.046440" dts="2048" dts_time="0.046440" duration="1024" duration_time="0.023220" size="2048" pos="525650" flags="K"/>
+ <frame media_type="audio" key_frame="1" pkt_pts="2048" pkt_pts_time="0.046440" pkt_dts="2048" pkt_dts_time="0.046440" best_effort_timestamp="2048" best_effort_timestamp_time="0.046440" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="525650" pkt_size="2048" sample_fmt="s16" nb_samples="1024" channels="1"/>
+ <packet codec_type="audio" stream_index="0" pts="3072" pts_time="0.069660" dts="3072" dts_time="0.069660" duration="1024" duration_time="0.023220" size="2048" pos="527721" flags="K"/>
+ <frame media_type="audio" key_frame="1" pkt_pts="3072" pkt_pts_time="0.069660" pkt_dts="3072" pkt_dts_time="0.069660" best_effort_timestamp="3072" best_effort_timestamp_time="0.069660" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="527721" pkt_size="2048" sample_fmt="s16" nb_samples="1024" channels="1"/>
+ <packet codec_type="video" stream_index="1" pts="4096" pts_time="0.080000" dts="4096" dts_time="0.080000" duration="2048" duration_time="0.040000" size="230400" pos="529799" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="4096" pkt_pts_time="0.080000" pkt_dts="4096" pkt_dts_time="0.080000" best_effort_timestamp="4096" best_effort_timestamp_time="0.080000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="529799" pkt_size="230400" width="320" height="240" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <packet codec_type="video" stream_index="2" pts="4096" pts_time="0.080000" dts="4096" dts_time="0.080000" duration="2048" duration_time="0.040000" size="30000" pos="760223" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="4096" pkt_pts_time="0.080000" pkt_dts="4096" pkt_dts_time="0.080000" best_effort_timestamp="4096" best_effort_timestamp_time="0.080000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="760223" pkt_size="30000" width="100" height="100" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <packet codec_type="audio" stream_index="0" pts="4096" pts_time="0.092880" dts="4096" dts_time="0.092880" duration="1024" duration_time="0.023220" size="2048" pos="790228" flags="K"/>
+ <frame media_type="audio" key_frame="1" pkt_pts="4096" pkt_pts_time="0.092880" pkt_dts="4096" pkt_dts_time="0.092880" best_effort_timestamp="4096" best_effort_timestamp_time="0.092880" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="790228" pkt_size="2048" sample_fmt="s16" nb_samples="1024" channels="1"/>
+ <packet codec_type="audio" stream_index="0" pts="5120" pts_time="0.116100" dts="5120" dts_time="0.116100" duration="1024" duration_time="0.023220" size="2048" pos="792299" flags="K"/>
+ <frame media_type="audio" key_frame="1" pkt_pts="5120" pkt_pts_time="0.116100" pkt_dts="5120" pkt_dts_time="0.116100" best_effort_timestamp="5120" best_effort_timestamp_time="0.116100" pkt_duration="1024" pkt_duration_time="0.023220" pkt_pos="792299" pkt_size="2048" sample_fmt="s16" nb_samples="1024" channels="1"/>
+ <packet codec_type="video" stream_index="1" pts="6144" pts_time="0.120000" dts="6144" dts_time="0.120000" duration="2048" duration_time="0.040000" size="230400" pos="794377" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="6144" pkt_pts_time="0.120000" pkt_dts="6144" pkt_dts_time="0.120000" best_effort_timestamp="6144" best_effort_timestamp_time="0.120000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="794377" pkt_size="230400" width="320" height="240" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ <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="1024801" flags="K"/>
+ <frame media_type="video" key_frame="1" pkt_pts="6144" pkt_pts_time="0.120000" pkt_dts="6144" pkt_dts_time="0.120000" best_effort_timestamp="6144" best_effort_timestamp_time="0.120000" pkt_duration="2048" pkt_duration_time="0.040000" pkt_pos="1024801" pkt_size="30000" width="100" height="100" pix_fmt="rgb24" sample_aspect_ratio="1:1" pict_type="I" coded_picture_number="0" display_picture_number="0" interlaced_frame="0" top_field_first="0" repeat_pict="0"/>
+ </packets_and_frames>
+
+ <streams>
+ <stream index="0" codec_name="pcm_s16le" codec_type="audio" codec_time_base="1/44100" codec_tag_string="PSD[16]" codec_tag="0x10445350" sample_fmt="s16" sample_rate="44100" channels="1" bits_per_sample="16" r_frame_rate="0/0" avg_frame_rate="0/0" time_base="1/44100" start_pts="0" start_time="0.000000" bit_rate="705600" nb_read_frames="6" nb_read_packets="6">
+ <disposition default="0" dub="0" original="0" comment="0" lyrics="0" karaoke="0" forced="0" hearing_impaired="0" visual_impaired="0" clean_effects="0" attached_pic="0"/>
+ <tag key="E" value="mc²"/>
+ <tag key="encoder" value="Lavc pcm_s16le"/>
+ </stream>
+ <stream index="1" codec_name="rawvideo" codec_type="video" codec_time_base="1/51200" codec_tag_string="RGB[24]" codec_tag="0x18424752" width="320" height="240" coded_width="320" coded_height="240" has_b_frames="0" sample_aspect_ratio="1:1" display_aspect_ratio="4:3" pix_fmt="rgb24" level="-99" refs="1" r_frame_rate="25/1" avg_frame_rate="25/1" time_base="1/51200" start_pts="0" start_time="0.000000" nb_read_frames="4" nb_read_packets="4">
+ <disposition default="0" dub="0" original="0" comment="0" lyrics="0" karaoke="0" forced="0" hearing_impaired="0" visual_impaired="0" clean_effects="0" attached_pic="0"/>
+ <tag key="title" value="foobar"/>
+ <tag key="duration_ts" value="field-and-tags-conflict-attempt"/>
+ <tag key="encoder" value="Lavc rawvideo"/>
+ </stream>
+ <stream index="2" codec_name="rawvideo" codec_type="video" codec_time_base="1/51200" codec_tag_string="RGB[24]" codec_tag="0x18424752" width="100" height="100" coded_width="100" coded_height="100" has_b_frames="0" sample_aspect_ratio="1:1" display_aspect_ratio="1:1" pix_fmt="rgb24" level="-99" refs="1" r_frame_rate="25/1" avg_frame_rate="25/1" time_base="1/51200" start_pts="0" start_time="0.000000" nb_read_frames="4" nb_read_packets="4">
+ <disposition default="0" dub="0" original="0" comment="0" lyrics="0" karaoke="0" forced="0" hearing_impaired="0" visual_impaired="0" clean_effects="0" attached_pic="0"/>
+ <tag key="encoder" value="Lavc rawvideo"/>
+ </stream>
+ </streams>
+
+ <format filename="tests/data/ffprobe-test.nut" nb_streams="3" nb_programs="0" format_name="nut" start_time="0.000000" duration="0.120000" size="1054882" bit_rate="70325466" probe_score="100">
+ <tag key="title" value="ffprobe test file"/>
+ <tag key="comment" value="&apos;A comment with CSV, XML &amp; JSON special chars&apos;: &lt;tag value=&quot;x&quot;&gt;"/>
+ <tag key="comment2" value="I ♥ ĂœĂ±Ă®Ă§Ă¸d€"/>
+ </format>
+</ffprobe>
diff --git a/tests/ref/fate/film-cvid b/tests/ref/fate/film-cvid
index 12b1f1cdcb..3ca7b5981c 100644
--- a/tests/ref/fate/film-cvid
+++ b/tests/ref/fate/film-cvid
@@ -1,111 +1,111 @@
#tb 0: 1/30
-0, 0, 0, 1, 107520, 0xa6c9fdd2
-0, 2, 2, 1, 107520, 0x61eb28c1
-0, 4, 4, 1, 107520, 0x45e20af7
-0, 6, 6, 1, 107520, 0x366970fc
-0, 8, 8, 1, 107520, 0xa392bcb3
-0, 10, 10, 1, 107520, 0xcf7bac98
-0, 12, 12, 1, 107520, 0x222eba53
-0, 14, 14, 1, 107520, 0x74e255a1
-0, 16, 16, 1, 107520, 0xc19eec6f
-0, 18, 18, 1, 107520, 0xa3880681
-0, 20, 20, 1, 107520, 0x957878db
-0, 22, 22, 1, 107520, 0x18340692
-0, 24, 24, 1, 107520, 0x9970f24d
-0, 26, 26, 1, 107520, 0xf08618aa
-0, 28, 28, 1, 107520, 0xee7324f0
-0, 30, 30, 1, 107520, 0xe15025b3
-0, 32, 32, 1, 107520, 0x8afa312e
-0, 34, 34, 1, 107520, 0x717a7d0f
-0, 36, 36, 1, 107520, 0x355c6e23
-0, 38, 38, 1, 107520, 0x7015a50f
-0, 40, 40, 1, 107520, 0xcdfc1a16
-0, 42, 42, 1, 107520, 0x38d929e7
-0, 44, 44, 1, 107520, 0x52913423
-0, 46, 46, 1, 107520, 0xe2c91c10
-0, 48, 48, 1, 107520, 0x85516e9c
-0, 50, 50, 1, 107520, 0xd1626030
-0, 52, 52, 1, 107520, 0xea7b16de
-0, 54, 54, 1, 107520, 0xa33eaa0d
-0, 56, 56, 1, 107520, 0x8e3be6a6
-0, 58, 58, 1, 107520, 0x14147bd6
-0, 60, 60, 1, 107520, 0x07d54bec
-0, 62, 62, 1, 107520, 0xe287a0a7
-0, 64, 64, 1, 107520, 0xc023a14d
-0, 66, 66, 1, 107520, 0x2437085d
-0, 68, 68, 1, 107520, 0x63823918
-0, 70, 70, 1, 107520, 0xbc17e198
-0, 72, 72, 1, 107520, 0x9d99bc81
-0, 74, 74, 1, 107520, 0x7e4ec71e
-0, 76, 76, 1, 107520, 0x55b98376
-0, 78, 78, 1, 107520, 0x356d8e9e
-0, 80, 80, 1, 107520, 0xf77e8a61
-0, 82, 82, 1, 107520, 0x5ae7c8c7
-0, 84, 84, 1, 107520, 0x8acf9322
-0, 86, 86, 1, 107520, 0x40a9177e
-0, 88, 88, 1, 107520, 0x3e0e4d8d
-0, 90, 90, 1, 107520, 0xd268865b
-0, 92, 92, 1, 107520, 0x89a4efeb
-0, 94, 94, 1, 107520, 0x70ca2478
-0, 96, 96, 1, 107520, 0xcc9ec981
-0, 98, 98, 1, 107520, 0xf0648459
-0, 100, 100, 1, 107520, 0x7e4a4cca
-0, 102, 102, 1, 107520, 0xb315dc65
-0, 104, 104, 1, 107520, 0x2aecc7b4
-0, 106, 106, 1, 107520, 0x81742f51
-0, 108, 108, 1, 107520, 0x3a1d7571
-0, 110, 110, 1, 107520, 0x3a1d7571
-0, 112, 112, 1, 107520, 0x3a1d7571
-0, 114, 114, 1, 107520, 0x3a1d7571
-0, 116, 116, 1, 107520, 0x3a1d7571
-0, 118, 118, 1, 107520, 0x3a1d7571
-0, 120, 120, 1, 107520, 0x3a1d7571
-0, 122, 122, 1, 107520, 0xe974733e
-0, 124, 124, 1, 107520, 0x999c6fbf
-0, 126, 126, 1, 107520, 0x26b56b6e
-0, 128, 128, 1, 107520, 0xc9f9647b
-0, 130, 130, 1, 107520, 0x6d025d00
-0, 132, 132, 1, 107520, 0xf9c056c1
-0, 134, 134, 1, 107520, 0xa5cc4d0b
-0, 136, 136, 1, 107520, 0x1a4c4236
-0, 138, 138, 1, 107520, 0xa9d538b6
-0, 140, 140, 1, 107520, 0x14682d00
-0, 142, 142, 1, 107520, 0x6236204f
-0, 144, 144, 1, 107520, 0x303e14aa
-0, 146, 146, 1, 107520, 0x943b0837
-0, 148, 148, 1, 107520, 0xfce5fd07
-0, 150, 150, 1, 107520, 0xd993f193
-0, 152, 152, 1, 107520, 0x4d48e7b4
-0, 154, 154, 1, 107520, 0x61ccdf83
-0, 156, 156, 1, 107520, 0xfb4fd608
-0, 158, 158, 1, 107520, 0x5efdcdb3
-0, 160, 160, 1, 107520, 0xb03ec886
-0, 162, 162, 1, 107520, 0xf464c343
-0, 164, 164, 1, 107520, 0xf464c343
-0, 166, 166, 1, 107520, 0xf464c343
-0, 168, 168, 1, 107520, 0xf464c343
-0, 170, 170, 1, 107520, 0xf464c343
-0, 172, 172, 1, 107520, 0xf464c343
-0, 174, 174, 1, 107520, 0xf464c343
-0, 176, 176, 1, 107520, 0xf464c343
-0, 178, 178, 1, 107520, 0xf464c343
-0, 180, 180, 1, 107520, 0xf464c343
-0, 182, 182, 1, 107520, 0xf464c343
-0, 184, 184, 1, 107520, 0xf2b2c712
-0, 186, 186, 1, 107520, 0xf2b2c712
-0, 188, 188, 1, 107520, 0xf2b2c712
-0, 190, 190, 1, 107520, 0xf2b2c712
-0, 192, 192, 1, 107520, 0xb95e6bc8
-0, 194, 194, 1, 107520, 0x33feee37
-0, 196, 196, 1, 107520, 0x36ee3cd5
-0, 198, 198, 1, 107520, 0x59096471
-0, 200, 200, 1, 107520, 0x53b470c6
-0, 202, 202, 1, 107520, 0xdb7c64ff
-0, 204, 204, 1, 107520, 0xe5a1596a
-0, 206, 206, 1, 107520, 0x8c8942eb
-0, 208, 208, 1, 107520, 0x5ecc379e
-0, 210, 210, 1, 107520, 0xea09432a
-0, 212, 212, 1, 107520, 0xe01e6b73
-0, 214, 214, 1, 107520, 0x1d13bba8
-0, 216, 216, 1, 107520, 0x3a993a6c
-0, 218, 218, 1, 107520, 0x2ede041a
+0, 0, 0, 1, 215040, 0x067c5362
+0, 2, 2, 1, 215040, 0xd9eacb98
+0, 4, 4, 1, 215040, 0x3c8a4cbd
+0, 6, 6, 1, 215040, 0xbdf996e1
+0, 8, 8, 1, 215040, 0x1b7fa123
+0, 10, 10, 1, 215040, 0x834b4a8d
+0, 12, 12, 1, 215040, 0xf4b1bebe
+0, 14, 14, 1, 215040, 0x088c3802
+0, 16, 16, 1, 215040, 0xf6ddedb9
+0, 18, 18, 1, 215040, 0x2791d538
+0, 20, 20, 1, 215040, 0x81fe4688
+0, 22, 22, 1, 215040, 0xad864fbd
+0, 24, 24, 1, 215040, 0xa637a97a
+0, 26, 26, 1, 215040, 0x2287e378
+0, 28, 28, 1, 215040, 0x13a017d7
+0, 30, 30, 1, 215040, 0x89a4acee
+0, 32, 32, 1, 215040, 0x97888ffc
+0, 34, 34, 1, 215040, 0x7c2c3b58
+0, 36, 36, 1, 215040, 0x2e3ab808
+0, 38, 38, 1, 215040, 0x2d553af2
+0, 40, 40, 1, 215040, 0x929c420e
+0, 42, 42, 1, 215040, 0x4841bd6d
+0, 44, 44, 1, 215040, 0xb350fbcd
+0, 46, 46, 1, 215040, 0x0d70b918
+0, 48, 48, 1, 215040, 0xf98b0f47
+0, 50, 50, 1, 215040, 0x748b8ff2
+0, 52, 52, 1, 215040, 0x62017c38
+0, 54, 54, 1, 215040, 0x46042bb4
+0, 56, 56, 1, 215040, 0xe7a74806
+0, 58, 58, 1, 215040, 0xb4c856e6
+0, 60, 60, 1, 215040, 0xb21a28dd
+0, 62, 62, 1, 215040, 0x2a6e0834
+0, 64, 64, 1, 215040, 0x7044d6ca
+0, 66, 66, 1, 215040, 0x17780335
+0, 68, 68, 1, 215040, 0x94f51e7a
+0, 70, 70, 1, 215040, 0x5beb5f5f
+0, 72, 72, 1, 215040, 0xc7d59527
+0, 74, 74, 1, 215040, 0x40f69049
+0, 76, 76, 1, 215040, 0x1f78740e
+0, 78, 78, 1, 215040, 0x49f7265d
+0, 80, 80, 1, 215040, 0x057ac5c9
+0, 82, 82, 1, 215040, 0x649bd476
+0, 84, 84, 1, 215040, 0x1c75aa43
+0, 86, 86, 1, 215040, 0xc4bd1e29
+0, 88, 88, 1, 215040, 0x5033fa74
+0, 90, 90, 1, 215040, 0xba5c949e
+0, 92, 92, 1, 215040, 0x2fa78a0e
+0, 94, 94, 1, 215040, 0x9d363dce
+0, 96, 96, 1, 215040, 0xd1dc82b0
+0, 98, 98, 1, 215040, 0xd25be322
+0, 100, 100, 1, 215040, 0xf1374ef9
+0, 102, 102, 1, 215040, 0x33467b42
+0, 104, 104, 1, 215040, 0x7ec7dfad
+0, 106, 106, 1, 215040, 0x706ed416
+0, 108, 108, 1, 215040, 0x6576b3eb
+0, 110, 110, 1, 215040, 0x6576b3eb
+0, 112, 112, 1, 215040, 0x6576b3eb
+0, 114, 114, 1, 215040, 0x6576b3eb
+0, 116, 116, 1, 215040, 0x6576b3eb
+0, 118, 118, 1, 215040, 0x6576b3eb
+0, 120, 120, 1, 215040, 0x6576b3eb
+0, 122, 122, 1, 215040, 0x6873993d
+0, 124, 124, 1, 215040, 0x8c2a84d8
+0, 126, 126, 1, 215040, 0xdd456bd5
+0, 128, 128, 1, 215040, 0x50fa4f3d
+0, 130, 130, 1, 215040, 0x00c4369c
+0, 132, 132, 1, 215040, 0xe4c220d2
+0, 134, 134, 1, 215040, 0xe43a033b
+0, 136, 136, 1, 215040, 0x72f6e32c
+0, 138, 138, 1, 215040, 0xb738c69c
+0, 140, 140, 1, 215040, 0x56bda3fe
+0, 142, 142, 1, 215040, 0xaa2f7da3
+0, 144, 144, 1, 215040, 0xf21f5c24
+0, 146, 146, 1, 215040, 0xd33e3579
+0, 148, 148, 1, 215040, 0x6a601495
+0, 150, 150, 1, 215040, 0xdfcff1e0
+0, 152, 152, 1, 215040, 0xa774d327
+0, 154, 154, 1, 215040, 0x8e9db8c9
+0, 156, 156, 1, 215040, 0xb4fd9689
+0, 158, 158, 1, 215040, 0xa80b77ff
+0, 160, 160, 1, 215040, 0x1d9c6568
+0, 162, 162, 1, 215040, 0x388c515a
+0, 164, 164, 1, 215040, 0x388c515a
+0, 166, 166, 1, 215040, 0x388c515a
+0, 168, 168, 1, 215040, 0x388c515a
+0, 170, 170, 1, 215040, 0x388c515a
+0, 172, 172, 1, 215040, 0x388c515a
+0, 174, 174, 1, 215040, 0x388c515a
+0, 176, 176, 1, 215040, 0x388c515a
+0, 178, 178, 1, 215040, 0x388c515a
+0, 180, 180, 1, 215040, 0x388c515a
+0, 182, 182, 1, 215040, 0x388c515a
+0, 184, 184, 1, 215040, 0x3aef5fee
+0, 186, 186, 1, 215040, 0x3aef5fee
+0, 188, 188, 1, 215040, 0x3aef5fee
+0, 190, 190, 1, 215040, 0x3aef5fee
+0, 192, 192, 1, 215040, 0x7f8e4b62
+0, 194, 194, 1, 215040, 0xbf9fcae8
+0, 196, 196, 1, 215040, 0x02f9a66c
+0, 198, 198, 1, 215040, 0x00ef062f
+0, 200, 200, 1, 215040, 0xe83b132c
+0, 202, 202, 1, 215040, 0x2701d21b
+0, 204, 204, 1, 215040, 0xbea79188
+0, 206, 206, 1, 215040, 0x6f6d3109
+0, 208, 208, 1, 215040, 0x4173f1e8
+0, 210, 210, 1, 215040, 0xd7adfce1
+0, 212, 212, 1, 215040, 0xa3825ffd
+0, 214, 214, 1, 215040, 0x41e63fe4
+0, 216, 216, 1, 215040, 0xb525b9c5
+0, 218, 218, 1, 215040, 0x00000000
diff --git a/tests/ref/fate/filter-2xbr b/tests/ref/fate/filter-2xbr
new file mode 100644
index 0000000000..91e1d4c396
--- /dev/null
+++ b/tests/ref/fate/filter-2xbr
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 877072, 0x5142c6cd
+0, 1, 1, 1, 877072, 0xa01a3f47
diff --git a/tests/ref/fate/filter-3xbr b/tests/ref/fate/filter-3xbr
new file mode 100644
index 0000000000..013f6a3ef8
--- /dev/null
+++ b/tests/ref/fate/filter-3xbr
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1973412, 0xd4cf257b
+0, 1, 1, 1, 1973412, 0x63fcd614
diff --git a/tests/ref/fate/filter-4xbr b/tests/ref/fate/filter-4xbr
new file mode 100644
index 0000000000..92b70d9f15
--- /dev/null
+++ b/tests/ref/fate/filter-4xbr
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3508288, 0xc7b1d170
+0, 1, 1, 1, 3508288, 0x3fd0c3fb
diff --git a/tests/ref/fate/filter-adelay b/tests/ref/fate/filter-adelay
new file mode 100644
index 0000000000..ac1c5847f9
--- /dev/null
+++ b/tests/ref/fate/filter-adelay
@@ -0,0 +1,261 @@
+#tb 0: 1/44100
+0, 0, 0, 1024, 4096, 0x9d7bf760
+0, 1024, 1024, 1024, 4096, 0xdf42c46b
+0, 2048, 2048, 1024, 4096, 0x2214fd20
+0, 3072, 3072, 1024, 4096, 0x811bfcf0
+0, 4096, 4096, 1024, 4096, 0x671ee9af
+0, 5120, 5120, 1024, 4096, 0x5e60fb90
+0, 6144, 6144, 1024, 4096, 0x857bfa49
+0, 7168, 7168, 1024, 4096, 0x100e028d
+0, 8192, 8192, 1024, 4096, 0xa351ed1e
+0, 9216, 9216, 1024, 4096, 0xa79cf58c
+0, 10240, 10240, 1024, 4096, 0x63c1f86a
+0, 11264, 11264, 1024, 4096, 0x325a055f
+0, 12288, 12288, 1024, 4096, 0x8457f621
+0, 13312, 13312, 1024, 4096, 0xa158f43e
+0, 14336, 14336, 1024, 4096, 0x69b6ef60
+0, 15360, 15360, 1024, 4096, 0x3bf1fb3c
+0, 16384, 16384, 1024, 4096, 0x942f00cc
+0, 17408, 17408, 1024, 4096, 0x16c2f0ab
+0, 18432, 18432, 1024, 4096, 0x6b9ff3b6
+0, 19456, 19456, 1024, 4096, 0x1616f3e7
+0, 20480, 20480, 1024, 4096, 0x1ec90735
+0, 21504, 21504, 1024, 4096, 0x3fd3f547
+0, 22528, 22528, 1024, 4096, 0x062af68d
+0, 23552, 23552, 1024, 4096, 0x9179ee59
+0, 24576, 24576, 1024, 4096, 0x172d01cb
+0, 25600, 25600, 1024, 4096, 0xd9bff94c
+0, 26624, 26624, 1024, 4096, 0x3db6f86e
+0, 27648, 27648, 1024, 4096, 0x617deb86
+0, 28672, 28672, 1024, 4096, 0x0e06fab5
+0, 29696, 29696, 1024, 4096, 0xf660fc98
+0, 30720, 30720, 1024, 4096, 0x31a30186
+0, 31744, 31744, 1024, 4096, 0x5312f599
+0, 32768, 32768, 1024, 4096, 0x0592f01a
+0, 33792, 33792, 1024, 4096, 0x6e770039
+0, 34816, 34816, 1024, 4096, 0x2214fd20
+0, 35840, 35840, 1024, 4096, 0x811bfcf0
+0, 36864, 36864, 1024, 4096, 0x671ee9af
+0, 37888, 37888, 1024, 4096, 0x5e60fb90
+0, 38912, 38912, 1024, 4096, 0x857bfa49
+0, 39936, 39936, 1024, 4096, 0x100e028d
+0, 40960, 40960, 1024, 4096, 0xa351ed1e
+0, 41984, 41984, 1024, 4096, 0xa79cf58c
+0, 43008, 43008, 1024, 4096, 0x63c1f86a
+0, 44032, 44032, 1024, 4096, 0x96ebeed8
+0, 45056, 45056, 1024, 4096, 0xdfa8cc5b
+0, 46080, 46080, 1024, 4096, 0x50660dab
+0, 47104, 47104, 1024, 4096, 0x58f1f11c
+0, 48128, 48128, 1024, 4096, 0x5a7ceb7d
+0, 49152, 49152, 1024, 4096, 0x27fe02db
+0, 50176, 50176, 1024, 4096, 0x6d83f8ed
+0, 51200, 51200, 1024, 4096, 0x3cc1f309
+0, 52224, 52224, 1024, 4096, 0x2bc5fea4
+0, 53248, 53248, 1024, 4096, 0x0a4ef2ca
+0, 54272, 54272, 1024, 4096, 0xd580ed7f
+0, 55296, 55296, 1024, 4096, 0x67c210b1
+0, 56320, 56320, 1024, 4096, 0x45d1e8a4
+0, 57344, 57344, 1024, 4096, 0xd9a820a6
+0, 58368, 58368, 1024, 4096, 0x27f405da
+0, 59392, 59392, 1024, 4096, 0x863a1b65
+0, 60416, 60416, 1024, 4096, 0xf7770535
+0, 61440, 61440, 1024, 4096, 0x069cee20
+0, 62464, 62464, 1024, 4096, 0x6564f3bb
+0, 63488, 63488, 1024, 4096, 0xd953e9dd
+0, 64512, 64512, 1024, 4096, 0x6a23f296
+0, 65536, 65536, 1024, 4096, 0x8051f8ed
+0, 66560, 66560, 1024, 4096, 0x226af522
+0, 67584, 67584, 1024, 4096, 0x526bf350
+0, 68608, 68608, 1024, 4096, 0x5b8cf6e5
+0, 69632, 69632, 1024, 4096, 0xd155fd1e
+0, 70656, 70656, 1024, 4096, 0x0fd2ed83
+0, 71680, 71680, 1024, 4096, 0x0df7f50c
+0, 72704, 72704, 1024, 4096, 0x96aa05fc
+0, 73728, 73728, 1024, 4096, 0x763ef755
+0, 74752, 74752, 1024, 4096, 0x2022fbb2
+0, 75776, 75776, 1024, 4096, 0x33f0fd78
+0, 76800, 76800, 1024, 4096, 0x91701636
+0, 77824, 77824, 1024, 4096, 0xb43106b7
+0, 78848, 78848, 1024, 4096, 0x3ec312cd
+0, 79872, 79872, 1024, 4096, 0x2f97ecb0
+0, 80896, 80896, 1024, 4096, 0x2872f93d
+0, 81920, 81920, 1024, 4096, 0xb9fc0bb6
+0, 82944, 82944, 1024, 4096, 0xdba41993
+0, 83968, 83968, 1024, 4096, 0x13f42827
+0, 84992, 84992, 1024, 4096, 0x19c0fc72
+0, 86016, 86016, 1024, 4096, 0x0c760320
+0, 87040, 87040, 1024, 4096, 0x739803c6
+0, 88064, 88064, 1024, 4096, 0x8101e8e8
+0, 89088, 89088, 1024, 4096, 0x521ef51e
+0, 90112, 90112, 1024, 4096, 0x5796c18e
+0, 91136, 91136, 1024, 4096, 0xae15b81c
+0, 92160, 92160, 1024, 4096, 0xa14da4f6
+0, 93184, 93184, 1024, 4096, 0x0df4a2c5
+0, 94208, 94208, 1024, 4096, 0xe6d6b7db
+0, 95232, 95232, 1024, 4096, 0x4d83aec1
+0, 96256, 96256, 1024, 4096, 0x1c8dbffb
+0, 97280, 97280, 1024, 4096, 0xff62da79
+0, 98304, 98304, 1024, 4096, 0xf41ca375
+0, 99328, 99328, 1024, 4096, 0x32a6dc8a
+0, 100352, 100352, 1024, 4096, 0x2d77bdfb
+0, 101376, 101376, 1024, 4096, 0x91fec716
+0, 102400, 102400, 1024, 4096, 0x599bdb67
+0, 103424, 103424, 1024, 4096, 0xeeb0c5e7
+0, 104448, 104448, 1024, 4096, 0x1c79cae2
+0, 105472, 105472, 1024, 4096, 0x3b5cbe5e
+0, 106496, 106496, 1024, 4096, 0x1168a813
+0, 107520, 107520, 1024, 4096, 0x13e8b7f7
+0, 108544, 108544, 1024, 4096, 0x9cebb015
+0, 109568, 109568, 1024, 4096, 0xcaf5da54
+0, 110592, 110592, 1024, 4096, 0xc555e4d2
+0, 111616, 111616, 1024, 4096, 0x67c2de67
+0, 112640, 112640, 1024, 4096, 0xd642f9ea
+0, 113664, 113664, 1024, 4096, 0xa4320e7f
+0, 114688, 114688, 1024, 4096, 0xf1b0f37b
+0, 115712, 115712, 1024, 4096, 0x4e33f2f2
+0, 116736, 116736, 1024, 4096, 0x17d5edfd
+0, 117760, 117760, 1024, 4096, 0x9849e28e
+0, 118784, 118784, 1024, 4096, 0x1af9f3a2
+0, 119808, 119808, 1024, 4096, 0x37730916
+0, 120832, 120832, 1024, 4096, 0xe737fd3c
+0, 121856, 121856, 1024, 4096, 0x8a590d88
+0, 122880, 122880, 1024, 4096, 0xe6d401e5
+0, 123904, 123904, 1024, 4096, 0xc8e2ec17
+0, 124928, 124928, 1024, 4096, 0x4019cf7d
+0, 125952, 125952, 1024, 4096, 0x1f93dd9c
+0, 126976, 126976, 1024, 4096, 0x2f9ff3f1
+0, 128000, 128000, 1024, 4096, 0x1530e129
+0, 129024, 129024, 1024, 4096, 0xcd79066a
+0, 130048, 130048, 1024, 4096, 0x6b9cfba7
+0, 131072, 131072, 1024, 4096, 0x43170f0b
+0, 132096, 132096, 1024, 4096, 0xf183fecf
+0, 133120, 133120, 1024, 4096, 0xf1e3f9ca
+0, 134144, 134144, 1024, 4096, 0x7d3fef31
+0, 135168, 135168, 1024, 4096, 0x4ea3f680
+0, 136192, 136192, 1024, 4096, 0x80e8ff67
+0, 137216, 137216, 1024, 4096, 0xba58f3b6
+0, 138240, 138240, 1024, 4096, 0xf18d0602
+0, 139264, 139264, 1024, 4096, 0xf7b2f8dc
+0, 140288, 140288, 1024, 4096, 0x7ab5fdab
+0, 141312, 141312, 1024, 4096, 0x0b04ef46
+0, 142336, 142336, 1024, 4096, 0xb23bf464
+0, 143360, 143360, 1024, 4096, 0xba08edbe
+0, 144384, 144384, 1024, 4096, 0x7e1af596
+0, 145408, 145408, 1024, 4096, 0xf23ff63c
+0, 146432, 146432, 1024, 4096, 0x7a55efca
+0, 147456, 147456, 1024, 4096, 0x427515b0
+0, 148480, 148480, 1024, 4096, 0x653de823
+0, 149504, 149504, 1024, 4096, 0x93a70335
+0, 150528, 150528, 1024, 4096, 0x60eaed4c
+0, 151552, 151552, 1024, 4096, 0xe9f30f02
+0, 152576, 152576, 1024, 4096, 0x1e9ff096
+0, 153600, 153600, 1024, 4096, 0xcc7d00a0
+0, 154624, 154624, 1024, 4096, 0xf994fa05
+0, 155648, 155648, 1024, 4096, 0x4577fc19
+0, 156672, 156672, 1024, 4096, 0xa312ed95
+0, 157696, 157696, 1024, 4096, 0xdbe0df34
+0, 158720, 158720, 1024, 4096, 0x4080f766
+0, 159744, 159744, 1024, 4096, 0x2751ec59
+0, 160768, 160768, 1024, 4096, 0xcd14f684
+0, 161792, 161792, 1024, 4096, 0xd42aeee0
+0, 162816, 162816, 1024, 4096, 0x21d3f3f6
+0, 163840, 163840, 1024, 4096, 0x32a6f850
+0, 164864, 164864, 1024, 4096, 0xc4c01074
+0, 165888, 165888, 1024, 4096, 0x27fef9bd
+0, 166912, 166912, 1024, 4096, 0x8f29fc33
+0, 167936, 167936, 1024, 4096, 0x0e360352
+0, 168960, 168960, 1024, 4096, 0xc992ecaf
+0, 169984, 169984, 1024, 4096, 0x05eff12c
+0, 171008, 171008, 1024, 4096, 0x700def8b
+0, 172032, 172032, 1024, 4096, 0xfbc3ef85
+0, 173056, 173056, 1024, 4096, 0x6908f67c
+0, 174080, 174080, 1024, 4096, 0xf6c305d6
+0, 175104, 175104, 1024, 4096, 0xbfdfe430
+0, 176128, 176128, 1024, 4096, 0xef7902ec
+0, 177152, 177152, 1024, 4096, 0x62adeb88
+0, 178176, 178176, 1024, 4096, 0x1fea0128
+0, 179200, 179200, 1024, 4096, 0xfeb0f860
+0, 180224, 180224, 1024, 4096, 0xa9e7e63b
+0, 181248, 181248, 1024, 4096, 0x62ffe62f
+0, 182272, 182272, 1024, 4096, 0xf743fbed
+0, 183296, 183296, 1024, 4096, 0x3953f3f3
+0, 184320, 184320, 1024, 4096, 0x17a6fc18
+0, 185344, 185344, 1024, 4096, 0x1531dc96
+0, 186368, 186368, 1024, 4096, 0x2560950a
+0, 187392, 187392, 1024, 4096, 0xa87704d0
+0, 188416, 188416, 1024, 4096, 0x89540f7f
+0, 189440, 189440, 1024, 4096, 0xa22ff108
+0, 190464, 190464, 1024, 4096, 0xd3e5fed6
+0, 191488, 191488, 1024, 4096, 0x10eafd99
+0, 192512, 192512, 1024, 4096, 0x7f6beeea
+0, 193536, 193536, 1024, 4096, 0x4fe101f7
+0, 194560, 194560, 1024, 4096, 0x5f94ef98
+0, 195584, 195584, 1024, 4096, 0x9cb4f877
+0, 196608, 196608, 1024, 4096, 0x03960aac
+0, 197632, 197632, 1024, 4096, 0x3fec0ab8
+0, 198656, 198656, 1024, 4096, 0x8225f4e7
+0, 199680, 199680, 1024, 4096, 0x5ffafce4
+0, 200704, 200704, 1024, 4096, 0x15caf2c1
+0, 201728, 201728, 1024, 4096, 0x7d54144f
+0, 202752, 202752, 1024, 4096, 0xa2139295
+0, 203776, 203776, 1024, 4096, 0xf2c1ec16
+0, 204800, 204800, 1024, 4096, 0x0c61e166
+0, 205824, 205824, 1024, 4096, 0xfdb7ffce
+0, 206848, 206848, 1024, 4096, 0xb783f1ff
+0, 207872, 207872, 1024, 4096, 0x8c07f340
+0, 208896, 208896, 1024, 4096, 0x8a03e20d
+0, 209920, 209920, 1024, 4096, 0x389eeeec
+0, 210944, 210944, 1024, 4096, 0x2f6b014c
+0, 211968, 211968, 1024, 4096, 0xfeb0f860
+0, 212992, 212992, 1024, 4096, 0xa9e7e63b
+0, 214016, 214016, 1024, 4096, 0x62ffe62f
+0, 215040, 215040, 1024, 4096, 0xf743fbed
+0, 216064, 216064, 1024, 4096, 0x3953f3f3
+0, 217088, 217088, 1024, 4096, 0x17a6fc18
+0, 218112, 218112, 1024, 4096, 0x1531dc96
+0, 219136, 219136, 1024, 4096, 0x2560950a
+0, 220160, 220160, 1024, 4096, 0xa87704d0
+0, 221184, 221184, 1024, 4096, 0x89540f7f
+0, 222208, 222208, 1024, 4096, 0xa22ff108
+0, 223232, 223232, 1024, 4096, 0xd3e5fed6
+0, 224256, 224256, 1024, 4096, 0x10eafd99
+0, 225280, 225280, 1024, 4096, 0x7f6beeea
+0, 226304, 226304, 1024, 4096, 0x4fe101f7
+0, 227328, 227328, 1024, 4096, 0x5f94ef98
+0, 228352, 228352, 1024, 4096, 0x9cb4f877
+0, 229376, 229376, 1024, 4096, 0x03960aac
+0, 230400, 230400, 1024, 4096, 0x3fec0ab8
+0, 231424, 231424, 1024, 4096, 0x8225f4e7
+0, 232448, 232448, 1024, 4096, 0x5ffafce4
+0, 233472, 233472, 1024, 4096, 0x15caf2c1
+0, 234496, 234496, 1024, 4096, 0x7d54144f
+0, 235520, 235520, 1024, 4096, 0xa2139295
+0, 236544, 236544, 1024, 4096, 0xf2c1ec16
+0, 237568, 237568, 1024, 4096, 0x0c61e166
+0, 238592, 238592, 1024, 4096, 0xfdb7ffce
+0, 239616, 239616, 1024, 4096, 0xb783f1ff
+0, 240640, 240640, 1024, 4096, 0x8c07f340
+0, 241664, 241664, 1024, 4096, 0x8a03e20d
+0, 242688, 242688, 1024, 4096, 0x389eeeec
+0, 243712, 243712, 1024, 4096, 0x2f6b014c
+0, 244736, 244736, 1024, 4096, 0xfeb0f860
+0, 245760, 245760, 1024, 4096, 0xa9e7e63b
+0, 246784, 246784, 1024, 4096, 0x62ffe62f
+0, 247808, 247808, 1024, 4096, 0xf743fbed
+0, 248832, 248832, 1024, 4096, 0x3953f3f3
+0, 249856, 249856, 1024, 4096, 0x17a6fc18
+0, 250880, 250880, 1024, 4096, 0x1531dc96
+0, 251904, 251904, 1024, 4096, 0x2560950a
+0, 252928, 252928, 1024, 4096, 0xa87704d0
+0, 253952, 253952, 1024, 4096, 0x89540f7f
+0, 254976, 254976, 1024, 4096, 0xa22ff108
+0, 256000, 256000, 1024, 4096, 0xd3e5fed6
+0, 257024, 257024, 1024, 4096, 0x10eafd99
+0, 258048, 258048, 1024, 4096, 0x7f6beeea
+0, 259072, 259072, 1024, 4096, 0x4fe101f7
+0, 260096, 260096, 1024, 4096, 0x5f94ef98
+0, 261120, 261120, 1024, 4096, 0x9cb4f877
+0, 262144, 262144, 1024, 4096, 0x03960aac
+0, 263168, 263168, 1024, 4096, 0x3fec0ab8
+0, 264192, 264192, 408, 1632, 0x23933452
+0, 264600, 264600, 1852, 7408, 0x77074171
diff --git a/tests/ref/fate/filter-alphaextract_alphamerge_rgb b/tests/ref/fate/filter-alphaextract_alphamerge_rgb
new file mode 100644
index 0000000000..1b1a48d4c9
--- /dev/null
+++ b/tests/ref/fate/filter-alphaextract_alphamerge_rgb
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0x6d5666c8
+0, 1, 1, 1, 405504, 0x4813ba17
+0, 2, 2, 1, 405504, 0x23880ee1
+0, 3, 3, 1, 405504, 0x3709926b
+0, 4, 4, 1, 405504, 0x1748e102
+0, 5, 5, 1, 405504, 0x12b4472b
+0, 6, 6, 1, 405504, 0x0441fe6b
+0, 7, 7, 1, 405504, 0x4fa8d058
+0, 8, 8, 1, 405504, 0xa0d810fb
+0, 9, 9, 1, 405504, 0xaca3ca02
+0, 10, 10, 1, 405504, 0x0afe65ea
+0, 11, 11, 1, 405504, 0xb81a9bd1
+0, 12, 12, 1, 405504, 0xb85f10eb
+0, 13, 13, 1, 405504, 0x4dc5e992
+0, 14, 14, 1, 405504, 0x6e9f8042
+0, 15, 15, 1, 405504, 0xf8e58f43
+0, 16, 16, 1, 405504, 0xc717635c
+0, 17, 17, 1, 405504, 0x5928548d
+0, 18, 18, 1, 405504, 0x8f2295f9
+0, 19, 19, 1, 405504, 0x5c449294
+0, 20, 20, 1, 405504, 0xe8c5d6ef
+0, 21, 21, 1, 405504, 0x3608a811
+0, 22, 22, 1, 405504, 0xa3788a12
+0, 23, 23, 1, 405504, 0x90ad93a3
+0, 24, 24, 1, 405504, 0x26c603bc
+0, 25, 25, 1, 405504, 0x055d69a8
+0, 26, 26, 1, 405504, 0x834747ea
+0, 27, 27, 1, 405504, 0x16eea5dd
+0, 28, 28, 1, 405504, 0xa2af8e0d
+0, 29, 29, 1, 405504, 0x65d2380f
+0, 30, 30, 1, 405504, 0xf4858c72
+0, 31, 31, 1, 405504, 0x90755bc9
+0, 32, 32, 1, 405504, 0xabfac3b0
+0, 33, 33, 1, 405504, 0x4a76adbd
+0, 34, 34, 1, 405504, 0x633183e9
+0, 35, 35, 1, 405504, 0xcb8ff8fe
+0, 36, 36, 1, 405504, 0x9c96074a
+0, 37, 37, 1, 405504, 0x700ea35c
+0, 38, 38, 1, 405504, 0x31bb483c
+0, 39, 39, 1, 405504, 0x50dd7ca7
+0, 40, 40, 1, 405504, 0x047988a0
+0, 41, 41, 1, 405504, 0xe4d7a9dd
+0, 42, 42, 1, 405504, 0x455d82ab
+0, 43, 43, 1, 405504, 0x8f875343
+0, 44, 44, 1, 405504, 0x8be18c94
+0, 45, 45, 1, 405504, 0x75431a7d
+0, 46, 46, 1, 405504, 0x08122c08
+0, 47, 47, 1, 405504, 0xfca4159a
+0, 48, 48, 1, 405504, 0x90c9afd6
+0, 49, 49, 1, 405504, 0x817e3b6a
diff --git a/tests/ref/fate/filter-alphaextract_alphamerge_yuv b/tests/ref/fate/filter-alphaextract_alphamerge_yuv
new file mode 100644
index 0000000000..37c3486202
--- /dev/null
+++ b/tests/ref/fate/filter-alphaextract_alphamerge_yuv
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 253440, 0x1ada7ac4
+0, 1, 1, 1, 253440, 0x711c1599
+0, 2, 2, 1, 253440, 0x533017ea
+0, 3, 3, 1, 253440, 0x86c6865f
+0, 4, 4, 1, 253440, 0xe5962b75
+0, 5, 5, 1, 253440, 0xe45dae97
+0, 6, 6, 1, 253440, 0x2d6b8047
+0, 7, 7, 1, 253440, 0xdd48b706
+0, 8, 8, 1, 253440, 0xb7a7823a
+0, 9, 9, 1, 253440, 0xa491f11f
+0, 10, 10, 1, 253440, 0x48b9abd5
+0, 11, 11, 1, 253440, 0x7d72078e
+0, 12, 12, 1, 253440, 0xe6901732
+0, 13, 13, 1, 253440, 0x8866ee68
+0, 14, 14, 1, 253440, 0x603e8fbc
+0, 15, 15, 1, 253440, 0x25c5633d
+0, 16, 16, 1, 253440, 0x7ef22b82
+0, 17, 17, 1, 253440, 0xffb25705
+0, 18, 18, 1, 253440, 0x921f9560
+0, 19, 19, 1, 253440, 0xd367c2a4
+0, 20, 20, 1, 253440, 0x6962a02d
+0, 21, 21, 1, 253440, 0x780d2b78
+0, 22, 22, 1, 253440, 0xa7bdf61e
+0, 23, 23, 1, 253440, 0x19797146
+0, 24, 24, 1, 253440, 0x3128c3bd
+0, 25, 25, 1, 253440, 0x2a3df40e
+0, 26, 26, 1, 253440, 0x3eb71582
+0, 27, 27, 1, 253440, 0x57f8c64d
+0, 28, 28, 1, 253440, 0x7e5872b1
+0, 29, 29, 1, 253440, 0x2c092689
+0, 30, 30, 1, 253440, 0xe92f4956
+0, 31, 31, 1, 253440, 0x6b49e20f
+0, 32, 32, 1, 253440, 0x274e4d28
+0, 33, 33, 1, 253440, 0xc1660f8c
+0, 34, 34, 1, 253440, 0xca9e5566
+0, 35, 35, 1, 253440, 0x30fa342a
+0, 36, 36, 1, 253440, 0xcbf915fd
+0, 37, 37, 1, 253440, 0x27fa90f6
+0, 38, 38, 1, 253440, 0x777743aa
+0, 39, 39, 1, 253440, 0xe6104ff6
+0, 40, 40, 1, 253440, 0xed51cb35
+0, 41, 41, 1, 253440, 0x218d192d
+0, 42, 42, 1, 253440, 0x100a5c86
+0, 43, 43, 1, 253440, 0xddcc3023
+0, 44, 44, 1, 253440, 0x788ff77d
+0, 45, 45, 1, 253440, 0x4488fb59
+0, 46, 46, 1, 253440, 0x634ff895
+0, 47, 47, 1, 253440, 0xd68bccb6
+0, 48, 48, 1, 253440, 0x1a9810ff
+0, 49, 49, 1, 253440, 0x05beb75b
diff --git a/tests/ref/fate/filter-codecview-mvs b/tests/ref/fate/filter-codecview-mvs
new file mode 100644
index 0000000000..e2404f3f40
--- /dev/null
+++ b/tests/ref/fate/filter-codecview-mvs
@@ -0,0 +1,61 @@
+#tb 0: 32768/785647
+0, 0, 0, 1, 276480, 0x5f7a0d4f
+0, 1, 1, 1, 276480, 0x5f7a0d4f
+0, 2, 2, 1, 276480, 0x5f7a0d4f
+0, 3, 3, 1, 276480, 0x5f7a0d4f
+0, 4, 4, 1, 276480, 0x5f7a0d4f
+0, 5, 5, 1, 276480, 0x5f7a0d4f
+0, 6, 6, 1, 276480, 0x5f7a0d4f
+0, 7, 7, 1, 276480, 0x5f7a0d4f
+0, 8, 8, 1, 276480, 0x5f7a0d4f
+0, 9, 9, 1, 276480, 0x5f7a0d4f
+0, 10, 10, 1, 276480, 0x5f7a0d4f
+0, 11, 11, 1, 276480, 0x5f7a0d4f
+0, 12, 12, 1, 276480, 0x5f7a0d4f
+0, 13, 13, 1, 276480, 0x5f7a0d4f
+0, 14, 14, 1, 276480, 0x5f7a0d4f
+0, 15, 15, 1, 276480, 0x5f7a0d4f
+0, 16, 16, 1, 276480, 0xc3b80edf
+0, 17, 17, 1, 276480, 0x5f7a0d4f
+0, 18, 18, 1, 276480, 0x5f7a0d4f
+0, 19, 19, 1, 276480, 0x5f7a0d4f
+0, 20, 20, 1, 276480, 0xc3b80edf
+0, 21, 21, 1, 276480, 0x5f7a0d4f
+0, 22, 22, 1, 276480, 0x5f7a0d4f
+0, 23, 23, 1, 276480, 0x5f7a0d4f
+0, 24, 24, 1, 276480, 0xc3b80edf
+0, 25, 25, 1, 276480, 0x5f7a0d4f
+0, 26, 26, 1, 276480, 0x5f7a0d4f
+0, 27, 27, 1, 276480, 0x5f7a0d4f
+0, 28, 28, 1, 276480, 0xc3b80edf
+0, 29, 29, 1, 276480, 0x5f7a0d4f
+0, 30, 30, 1, 276480, 0x5f7a0d4f
+0, 31, 31, 1, 276480, 0x5f7a0d4f
+0, 32, 32, 1, 276480, 0xc3b80edf
+0, 33, 33, 1, 276480, 0x75641594
+0, 34, 34, 1, 276480, 0x32ee3526
+0, 35, 35, 1, 276480, 0xcb53479a
+0, 36, 36, 1, 276480, 0xe1be6e26
+0, 37, 37, 1, 276480, 0x5ce39368
+0, 38, 38, 1, 276480, 0x4ec1e418
+0, 39, 39, 1, 276480, 0x23c418ae
+0, 40, 40, 1, 276480, 0x499c55d6
+0, 41, 41, 1, 276480, 0x166ef020
+0, 42, 42, 1, 276480, 0xaa0614ab
+0, 43, 43, 1, 276480, 0x8bc2fa2b
+0, 44, 44, 1, 276480, 0xc9c873f7
+0, 45, 45, 1, 276480, 0x99838153
+0, 46, 46, 1, 276480, 0x32e5f45b
+0, 47, 47, 1, 276480, 0xe7834514
+0, 48, 48, 1, 276480, 0x454c99c8
+0, 49, 49, 1, 276480, 0xe29bacc8
+0, 50, 50, 1, 276480, 0x6b79c3d3
+0, 51, 51, 1, 276480, 0x284d358e
+0, 52, 52, 1, 276480, 0x17552cd4
+0, 53, 53, 1, 276480, 0x6ceebf3e
+0, 54, 54, 1, 276480, 0x7ac8de3c
+0, 55, 55, 1, 276480, 0x14d6768c
+0, 56, 56, 1, 276480, 0x59891e5f
+0, 57, 57, 1, 276480, 0xed3053ea
+0, 58, 58, 1, 276480, 0x9b0182c3
+0, 59, 59, 1, 276480, 0xf849eb88
diff --git a/tests/ref/fate/filter-colorchannelmixer b/tests/ref/fate/filter-colorchannelmixer
new file mode 100644
index 0000000000..4e9e9d3a94
--- /dev/null
+++ b/tests/ref/fate/filter-colorchannelmixer
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 304128, 0x42900c13
+0, 1, 1, 1, 304128, 0xfb0439bc
+0, 2, 2, 1, 304128, 0x967b9f0d
+0, 3, 3, 1, 304128, 0xc2c92489
+0, 4, 4, 1, 304128, 0x024499b1
+0, 5, 5, 1, 304128, 0x66144785
+0, 6, 6, 1, 304128, 0x0e505bcd
+0, 7, 7, 1, 304128, 0xc8b26ed2
+0, 8, 8, 1, 304128, 0x14b5717b
+0, 9, 9, 1, 304128, 0x2ba3144a
+0, 10, 10, 1, 304128, 0x1185992b
+0, 11, 11, 1, 304128, 0xd55b289a
+0, 12, 12, 1, 304128, 0x59f2f3be
+0, 13, 13, 1, 304128, 0xfe4d6adf
+0, 14, 14, 1, 304128, 0x630806cc
+0, 15, 15, 1, 304128, 0x2deb2f19
+0, 16, 16, 1, 304128, 0xfbffa923
+0, 17, 17, 1, 304128, 0xb7770d46
+0, 18, 18, 1, 304128, 0xda09bd0e
+0, 19, 19, 1, 304128, 0x17a422d2
+0, 20, 20, 1, 304128, 0xbb6172f5
+0, 21, 21, 1, 304128, 0xcf639456
+0, 22, 22, 1, 304128, 0xdb0ae1ac
+0, 23, 23, 1, 304128, 0x850d6a68
+0, 24, 24, 1, 304128, 0xdc8409fb
+0, 25, 25, 1, 304128, 0x26216c51
+0, 26, 26, 1, 304128, 0x1d0004de
+0, 27, 27, 1, 304128, 0xed019a70
+0, 28, 28, 1, 304128, 0xb1abd985
+0, 29, 29, 1, 304128, 0xec1c14b2
+0, 30, 30, 1, 304128, 0x046db068
+0, 31, 31, 1, 304128, 0xa4fb1029
+0, 32, 32, 1, 304128, 0x49e05e61
+0, 33, 33, 1, 304128, 0x7668d6d1
+0, 34, 34, 1, 304128, 0x6dd0ce9d
+0, 35, 35, 1, 304128, 0x87983f5e
+0, 36, 36, 1, 304128, 0xb98278cf
+0, 37, 37, 1, 304128, 0x55186244
+0, 38, 38, 1, 304128, 0x3135e7ea
+0, 39, 39, 1, 304128, 0xdbf59a2c
+0, 40, 40, 1, 304128, 0x944cdc92
+0, 41, 41, 1, 304128, 0x5849dfe8
+0, 42, 42, 1, 304128, 0xaf9075ba
+0, 43, 43, 1, 304128, 0xb4f01118
+0, 44, 44, 1, 304128, 0x4dfb711f
+0, 45, 45, 1, 304128, 0xb558e732
+0, 46, 46, 1, 304128, 0xb23a171e
+0, 47, 47, 1, 304128, 0xb5c68065
+0, 48, 48, 1, 304128, 0xcf1b122e
+0, 49, 49, 1, 304128, 0x1e2d38e5
diff --git a/tests/ref/fate/filter-colormatrix1 b/tests/ref/fate/filter-colormatrix1
new file mode 100644
index 0000000000..0f008e0410
--- /dev/null
+++ b/tests/ref/fate/filter-colormatrix1
@@ -0,0 +1 @@
+colormatrix1 0a0640b2d4ccd4e793f4919d82a89523
diff --git a/tests/ref/fate/filter-colormatrix2 b/tests/ref/fate/filter-colormatrix2
new file mode 100644
index 0000000000..7f3232ec8b
--- /dev/null
+++ b/tests/ref/fate/filter-colormatrix2
@@ -0,0 +1 @@
+colormatrix2 5eb17671c03496ae43723e49832ab17a
diff --git a/tests/ref/fate/filter-concat b/tests/ref/fate/filter-concat
new file mode 100644
index 0000000000..73e41857e0
--- /dev/null
+++ b/tests/ref/fate/filter-concat
@@ -0,0 +1,202 @@
+#tb 0: 1/5
+#tb 1: 1/44100
+0, 0, 0, 1, 230400, 0x88c4d19a
+1, 0, 0, 1024, 2048, 0xb3f10192
+1, 1024, 1024, 1024, 2048, 0xb340fe4e
+1, 2048, 2048, 1024, 2048, 0x0a5f0111
+1, 3072, 3072, 1024, 2048, 0x51be06b8
+1, 4096, 4096, 1024, 2048, 0x71a1ffcb
+1, 5120, 5120, 1024, 2048, 0x7f64f50f
+1, 6144, 6144, 1024, 2048, 0x70a8fa17
+1, 7168, 7168, 1024, 2048, 0x0dad072a
+1, 8192, 8192, 1024, 2048, 0x5e810c51
+0, 1, 1, 1, 230400, 0x0d77c977
+1, 9216, 9216, 1024, 2048, 0xbe5bf462
+1, 10240, 10240, 1024, 2048, 0xbcd9faeb
+1, 11264, 11264, 1024, 2048, 0x0d5bfe9c
+1, 12288, 12288, 1024, 2048, 0x97d80297
+1, 13312, 13312, 1024, 2048, 0xba0f0894
+1, 14336, 14336, 1024, 2048, 0xcc22f291
+1, 15360, 15360, 1024, 2048, 0x11a9fa03
+1, 16384, 16384, 1024, 2048, 0x9a920378
+1, 17408, 17408, 1024, 2048, 0x901b0525
+0, 2, 2, 1, 230400, 0x242629d7
+1, 18432, 18432, 1024, 2048, 0x74b2003f
+1, 19456, 19456, 1024, 2048, 0xa20ef3ed
+1, 20480, 20480, 1024, 2048, 0x44cef9de
+1, 21504, 21504, 1024, 2048, 0x4b2e039b
+1, 22528, 22528, 1024, 2048, 0x198509a1
+1, 23552, 23552, 1024, 2048, 0xcab6f9e5
+1, 24576, 24576, 1024, 2048, 0x67f8f608
+1, 25600, 25600, 1024, 2048, 0x8d7f03fa
+0, 3, 3, 1, 230400, 0x62cdc018
+1, 26624, 26624, 1024, 2048, 0x3e1e0566
+1, 27648, 27648, 1024, 2048, 0x2cfe0308
+1, 28672, 28672, 1024, 2048, 0x1ceaf702
+1, 29696, 29696, 1024, 2048, 0x38a9f3d1
+1, 30720, 30720, 1024, 2048, 0x6c3306b7
+1, 31744, 31744, 1024, 2048, 0x600f0579
+1, 32768, 32768, 1024, 2048, 0x3e5afa28
+1, 33792, 33792, 1024, 2048, 0x053ff47a
+1, 34816, 34816, 1024, 2048, 0x0d28fed9
+0, 4, 4, 1, 230400, 0x248ad058
+1, 35840, 35840, 1024, 2048, 0x279805cc
+1, 36864, 36864, 1024, 2048, 0xb16a0a12
+1, 37888, 37888, 1024, 2048, 0xb45af340
+1, 38912, 38912, 1024, 2048, 0x1834f972
+1, 39936, 39936, 1024, 2048, 0xb5d206ae
+1, 40960, 40960, 1024, 2048, 0xc5760375
+1, 41984, 41984, 1024, 2048, 0x503800ce
+1, 43008, 43008, 1024, 2048, 0xa3bbf4af
+1, 44032, 44032, 68, 136, 0xc8d751c7
+0, 5, 5, 1, 230400, 0x223d134f
+1, 44100, 44100, 9600, 19200, 0x00000000
+0, 6, 6, 1, 230400, 0xbf1c3d34
+1, 53700, 53700, 9600, 19200, 0x00000000
+0, 7, 7, 1, 230400, 0xae0efe96
+1, 63300, 63300, 9600, 19200, 0x00000000
+0, 8, 8, 1, 230400, 0x0cd624d1
+1, 72900, 72900, 9600, 19200, 0x00000000
+0, 9, 9, 1, 230400, 0x6dedf2c0
+1, 82500, 82500, 5700, 11400, 0x00000000
+0, 10, 10, 1, 230400, 0x88c4d19a
+1, 88200, 88200, 1024, 2048, 0x283efb3a
+1, 89224, 89224, 1024, 2048, 0x7692fb8f
+1, 90248, 90248, 1024, 2048, 0xbaaafcc0
+1, 91272, 91272, 1024, 2048, 0xadc8017e
+1, 92296, 92296, 1024, 2048, 0x4f4dffdc
+1, 93320, 93320, 1024, 2048, 0x7ffbff48
+1, 94344, 94344, 1024, 2048, 0x2f990719
+1, 95368, 95368, 1024, 2048, 0xe2caf65c
+1, 96392, 96392, 1024, 2048, 0x825208e4
+0, 11, 11, 1, 230400, 0x0d77c977
+1, 97416, 97416, 1024, 2048, 0xf563f13b
+1, 98440, 98440, 1024, 2048, 0x855d03e9
+1, 99464, 99464, 1024, 2048, 0x0ba9fa4b
+1, 100488, 100488, 1024, 2048, 0x83e1fb92
+1, 101512, 101512, 1024, 2048, 0x1162f965
+1, 102536, 102536, 1024, 2048, 0x0cfef73d
+1, 103560, 103560, 1024, 2048, 0x5688ff75
+1, 104584, 104584, 1024, 2048, 0xf6c0ede9
+1, 105608, 105608, 1024, 2048, 0xfdb20602
+0, 12, 12, 1, 230400, 0x242629d7
+1, 106632, 106632, 1024, 2048, 0x40c5f17b
+1, 107656, 107656, 1024, 2048, 0x559600b1
+1, 108680, 108680, 1024, 2048, 0xccc3f930
+1, 109704, 109704, 1024, 2048, 0xdc800045
+1, 110728, 110728, 1024, 2048, 0xdce4fb3e
+1, 111752, 111752, 1024, 2048, 0x1e5efba9
+1, 112776, 112776, 1024, 2048, 0x8c2e0832
+1, 113800, 113800, 1024, 2048, 0x5c42f66d
+0, 13, 13, 1, 230400, 0x62cdc018
+1, 114824, 114824, 1024, 2048, 0x08e20b1e
+1, 115848, 115848, 1024, 2048, 0x4cf7f903
+1, 116872, 116872, 1024, 2048, 0xe6b90794
+1, 117896, 117896, 1024, 2048, 0x5956f8e6
+1, 118920, 118920, 1024, 2048, 0x6632ff16
+1, 119944, 119944, 1024, 2048, 0x46c8fe11
+1, 120968, 120968, 1024, 2048, 0x7431f732
+1, 121992, 121992, 1024, 2048, 0xa258049f
+1, 123016, 123016, 1024, 2048, 0xdb71f00e
+0, 14, 14, 1, 230400, 0x248ad058
+1, 124040, 124040, 1024, 2048, 0xa89b0359
+1, 125064, 125064, 1024, 2048, 0xe0aff0f2
+1, 126088, 126088, 1024, 2048, 0xc33e0085
+1, 127112, 127112, 1024, 2048, 0x9d09f379
+1, 128136, 128136, 1024, 2048, 0x8c78fd06
+1, 129160, 129160, 1024, 2048, 0x532bfbdd
+1, 130184, 130184, 1024, 2048, 0xfc36f5cd
+1, 131208, 131208, 1024, 2048, 0x2e8f0699
+1, 132232, 132232, 1024, 2048, 0x52382578
+1, 133256, 133256, 1024, 2048, 0x97ed1a28
+1, 134280, 134280, 1024, 2048, 0xabcdf73f
+1, 135304, 135304, 1024, 2048, 0x3a24082c
+1, 136328, 136328, 1024, 2048, 0xbe1cfc3d
+1, 137352, 137352, 1024, 2048, 0xad5800a5
+1, 138376, 138376, 1024, 2048, 0x90b80522
+1, 139400, 139400, 1024, 2048, 0x1fa1f912
+1, 140424, 140424, 1024, 2048, 0x733a0878
+1, 141448, 141448, 1024, 2048, 0x9a3eee47
+1, 142472, 142472, 1024, 2048, 0x5d900759
+1, 143496, 143496, 1024, 2048, 0x1287f540
+1, 144520, 144520, 1024, 2048, 0x941cfe5d
+1, 145544, 145544, 1024, 2048, 0x1587f8a9
+1, 146568, 146568, 1024, 2048, 0xb9e7f888
+1, 147592, 147592, 1024, 2048, 0xe9defbe2
+1, 148616, 148616, 1024, 2048, 0x3a5ef312
+1, 149640, 149640, 1024, 2048, 0xdcbe0544
+1, 150664, 150664, 1024, 2048, 0xbe51ecc5
+1, 151688, 151688, 1024, 2048, 0x21a60721
+1, 152712, 152712, 1024, 2048, 0xf29ff318
+1, 153736, 153736, 1024, 2048, 0xcd4c02ea
+1, 154760, 154760, 1024, 2048, 0xa424faac
+1, 155784, 155784, 1024, 2048, 0xbaedfdab
+1, 156808, 156808, 1024, 2048, 0xcbff047c
+1, 157832, 157832, 1024, 2048, 0x9ac8f96b
+1, 158856, 158856, 1024, 2048, 0x43220bee
+1, 159880, 159880, 1024, 2048, 0x547bf351
+1, 160904, 160904, 1024, 2048, 0x7dd10d6e
+1, 161928, 161928, 1024, 2048, 0x77cbf603
+1, 162952, 162952, 1024, 2048, 0xb6fcff50
+1, 163976, 163976, 1024, 2048, 0x927bfde5
+1, 165000, 165000, 1024, 2048, 0x5bd0fca5
+1, 166024, 166024, 1024, 2048, 0x672cff2a
+1, 167048, 167048, 1024, 2048, 0x3e3ef01c
+1, 168072, 168072, 1024, 2048, 0xe52607af
+1, 169096, 169096, 1024, 2048, 0x66bceaf5
+1, 170120, 170120, 1024, 2048, 0xe065046b
+1, 171144, 171144, 1024, 2048, 0x350bf21f
+1, 172168, 172168, 1024, 2048, 0x60b1fca4
+1, 173192, 173192, 1024, 2048, 0x8b1efa55
+1, 174216, 174216, 1024, 2048, 0xf86ff855
+1, 175240, 175240, 1024, 2048, 0x6934061b
+1, 176264, 176264, 136, 272, 0x4a458a45
+0, 20, 20, 1, 230400, 0x88c4d19a
+1, 176400, 176400, 1024, 2048, 0xdb0cfe95
+1, 177424, 177424, 1024, 2048, 0xcff3fdf1
+1, 178448, 178448, 1024, 2048, 0x070cf585
+1, 179472, 179472, 1024, 2048, 0xe9b8007f
+1, 180496, 180496, 1024, 2048, 0xc51ffd64
+1, 181520, 181520, 1024, 2048, 0xede2fbf9
+1, 182544, 182544, 1024, 2048, 0x51510410
+1, 183568, 183568, 1024, 2048, 0x198af498
+1, 184592, 184592, 1024, 2048, 0xae3603a2
+0, 21, 21, 1, 230400, 0x0d77c977
+1, 185616, 185616, 1024, 2048, 0x6200f7a1
+1, 186640, 186640, 1024, 2048, 0xe6e3fe32
+1, 187664, 187664, 1024, 2048, 0xb2e2fd77
+1, 188688, 188688, 1024, 2048, 0x063dff2f
+1, 189712, 189712, 1024, 2048, 0xa89ffe21
+1, 190736, 190736, 1024, 2048, 0x9e6ffa6d
+1, 191760, 191760, 1024, 2048, 0x028b004e
+1, 192784, 192784, 1024, 2048, 0x57edfa23
+1, 193808, 193808, 1024, 2048, 0x6d8efe1f
+0, 22, 22, 1, 230400, 0x242629d7
+1, 194832, 194832, 1024, 2048, 0x774bfe54
+1, 195856, 195856, 1024, 2048, 0xa931fcfb
+1, 196880, 196880, 1024, 2048, 0x3505004b
+1, 197904, 197904, 1024, 2048, 0x5001f576
+1, 198928, 198928, 1024, 2048, 0x78ea049b
+1, 199952, 199952, 1024, 2048, 0xd45bf733
+1, 200976, 200976, 1024, 2048, 0x6395fead
+1, 202000, 202000, 1024, 2048, 0xc126015e
+0, 23, 23, 1, 230400, 0x62cdc018
+1, 203024, 203024, 1024, 2048, 0xbecff8aa
+1, 204048, 204048, 1024, 2048, 0x0fea06c3
+1, 205072, 205072, 1024, 2048, 0xdea6f351
+1, 206096, 206096, 1024, 2048, 0x35b808f0
+1, 207120, 207120, 1024, 2048, 0x5487ee73
+1, 208144, 208144, 1024, 2048, 0xac69050e
+1, 209168, 209168, 1024, 2048, 0xcc5ffb00
+1, 210192, 210192, 1024, 2048, 0x328c00cb
+1, 211216, 211216, 1024, 2048, 0xa707fd82
+0, 24, 24, 1, 230400, 0x248ad058
+1, 212240, 212240, 1024, 2048, 0xe442f73d
+1, 213264, 213264, 1024, 2048, 0x545c0418
+1, 214288, 214288, 1024, 2048, 0x744ff3f7
+1, 215312, 215312, 1024, 2048, 0x01aa04fd
+1, 216336, 216336, 1024, 2048, 0xa885f7cd
+1, 217360, 217360, 1024, 2048, 0xcfca04f4
+1, 218384, 218384, 1024, 2048, 0x67fdf91b
+1, 219408, 219408, 1024, 2048, 0xce2b001d
+1, 220432, 220432, 68, 136, 0x33e64a0d
diff --git a/tests/ref/fate/filter-crop b/tests/ref/fate/filter-crop
index b226c96b6b..e48461ea6f 100644
--- a/tests/ref/fate/filter-crop
+++ b/tests/ref/fate/filter-crop
@@ -1 +1 @@
-crop f3a9421392a9aa71a974c1b933c8d6ee
+crop 59c225f4cdab05af984dd259f10be762
diff --git a/tests/ref/fate/filter-crop_scale b/tests/ref/fate/filter-crop_scale
index b80a83fa75..9bc7de7ac4 100644
--- a/tests/ref/fate/filter-crop_scale
+++ b/tests/ref/fate/filter-crop_scale
@@ -1 +1 @@
-crop_scale fe197338c0cb626766cb04f7d46fcc44
+crop_scale 728fa480f1b959cddd3f83c92d8719c4
diff --git a/tests/ref/fate/filter-crop_scale_vflip b/tests/ref/fate/filter-crop_scale_vflip
index b1eba7ecf4..36874db953 100644
--- a/tests/ref/fate/filter-crop_scale_vflip
+++ b/tests/ref/fate/filter-crop_scale_vflip
@@ -1 +1 @@
-crop_scale_vflip 1e456de396706899f3dca38ef2b43777
+crop_scale_vflip d6a0bb35b159aa6787add0082088a59f
diff --git a/tests/ref/fate/filter-crop_vflip b/tests/ref/fate/filter-crop_vflip
index 56aa383906..2f6a32019d 100644
--- a/tests/ref/fate/filter-crop_vflip
+++ b/tests/ref/fate/filter-crop_vflip
@@ -1 +1 @@
-crop_vflip 2527b0a2a7b4a6a732fd0e0f07b9bb74
+crop_vflip 0652fe087e7a0cc110c3a876543b8662
diff --git a/tests/ref/fate/filter-curves b/tests/ref/fate/filter-curves
new file mode 100644
index 0000000000..a96f0eea84
--- /dev/null
+++ b/tests/ref/fate/filter-curves
@@ -0,0 +1,6 @@
+#tb 0: 1001/30000
+0, 0, 0, 1, 921600, 0xcf426780
+0, 1, 1, 1, 921600, 0x7642892d
+0, 2, 2, 1, 921600, 0x13c1ab7e
+0, 3, 3, 1, 921600, 0x3eca04bf
+0, 4, 4, 1, 921600, 0x61539162
diff --git a/tests/ref/fate/filter-delogo b/tests/ref/fate/filter-delogo
index 1a1f4970da..80342ee836 100644
--- a/tests/ref/fate/filter-delogo
+++ b/tests/ref/fate/filter-delogo
@@ -1,110 +1,110 @@
-#tb 0: 1/1000
-0, 1, 1, 0, 126720, 0x689de87e
-0, 33, 33, 0, 126720, 0x3db9e91c
-0, 66, 66, 0, 126720, 0x3db9e91c
-0, 100, 100, 0, 126720, 0x3db9e91c
-0, 133, 133, 0, 126720, 0xfa6ae95e
-0, 166, 166, 0, 126720, 0x5bcbf0e6
-0, 200, 200, 0, 126720, 0x94a0f126
-0, 233, 233, 0, 126720, 0x0250f106
-0, 266, 266, 0, 126720, 0xcf6ab4bc
-0, 300, 300, 0, 126720, 0x429eb57c
-0, 333, 333, 0, 126720, 0x3bf0b5bc
-0, 367, 367, 0, 126720, 0xcaedb591
-0, 400, 400, 0, 126720, 0xa492b5ec
-0, 433, 433, 0, 126720, 0x2431b85c
-0, 467, 467, 0, 126720, 0x8283b8dc
-0, 500, 500, 0, 126720, 0xd71bb871
-0, 533, 533, 0, 126720, 0x698eb5cc
-0, 567, 567, 0, 126720, 0x4719aa98
-0, 600, 600, 0, 126720, 0x9ca1962c
-0, 633, 633, 0, 126720, 0x18cda460
-0, 667, 667, 0, 126720, 0xc230b716
-0, 700, 700, 0, 126720, 0x8451a4e2
-0, 734, 734, 0, 126720, 0x59e9a7ea
-0, 767, 767, 0, 126720, 0xc77ca73d
-0, 800, 800, 0, 126720, 0x725fb976
-0, 834, 834, 0, 126720, 0xb30da3b3
-0, 867, 867, 0, 126720, 0x7af2ea86
-0, 900, 900, 0, 126720, 0x40d4b4eb
-0, 934, 934, 0, 126720, 0x49d00307
-0, 967, 967, 0, 126720, 0x0654849c
-0, 1000, 1000, 0, 126720, 0xe46d0107
-0, 1034, 1034, 0, 126720, 0xa483b963
-0, 1067, 1067, 0, 126720, 0xd0e903f0
-0, 1101, 1101, 0, 126720, 0x964ed592
-0, 1134, 1134, 0, 126720, 0x23fbdb3c
-0, 1167, 1167, 0, 126720, 0x59fdace5
-0, 1201, 1201, 0, 126720, 0xb1e37954
-0, 1234, 1234, 0, 126720, 0x8ed9c554
-0, 1267, 1267, 0, 126720, 0xe3c4b39f
-0, 1301, 1301, 0, 126720, 0xfd17e0ce
-0, 1334, 1334, 0, 126720, 0xf26e1dcc
-0, 1368, 1368, 0, 126720, 0x13cc783c
-0, 1401, 1401, 0, 126720, 0x47ad47a1
-0, 1434, 1434, 0, 126720, 0x427c8b0d
-0, 1468, 1468, 0, 126720, 0x59d99901
-0, 1501, 1501, 0, 126720, 0xc40707da
-0, 1534, 1534, 0, 126720, 0xcd060dce
-0, 1568, 1568, 0, 126720, 0xed4024f6
-0, 1601, 1601, 0, 126720, 0x7decd2b4
-0, 1634, 1634, 0, 126720, 0xd1d2e730
-0, 1668, 1668, 0, 126720, 0x77cee457
-0, 1701, 1701, 0, 126720, 0xe78d02c0
-0, 1735, 1735, 0, 126720, 0xad0beb29
-0, 1768, 1768, 0, 126720, 0xc414eea2
-0, 1801, 1801, 0, 126720, 0x6a15f17d
-0, 1835, 1835, 0, 126720, 0x516027f6
-0, 1868, 1868, 0, 126720, 0x4eda9dce
-0, 1901, 1901, 0, 126720, 0x7d9bdba3
-0, 1935, 1935, 0, 126720, 0x7aa3d5c0
-0, 1968, 1968, 0, 126720, 0x7c7a04f9
-0, 2001, 2001, 0, 126720, 0x3e8fb6cc
-0, 2035, 2035, 0, 126720, 0xd5474916
-0, 2068, 2068, 0, 126720, 0xf3f62bab
-0, 2102, 2102, 0, 126720, 0x2f054987
-0, 2135, 2135, 0, 126720, 0x974c2e81
-0, 2168, 2168, 0, 126720, 0xe7e28a97
-0, 2202, 2202, 0, 126720, 0x45e38b41
-0, 2235, 2235, 0, 126720, 0x169c7f19
-0, 2268, 2268, 0, 126720, 0x91d90ee8
-0, 2302, 2302, 0, 126720, 0xdd653e24
-0, 2335, 2335, 0, 126720, 0x0da598c4
-0, 2369, 2369, 0, 126720, 0x687e62cc
-0, 2402, 2402, 0, 126720, 0x7631232d
-0, 2435, 2435, 0, 126720, 0xbd1ea826
-0, 2469, 2469, 0, 126720, 0xb55f7f4b
-0, 2502, 2502, 0, 126720, 0x923f3fc9
-0, 2535, 2535, 0, 126720, 0x15515301
-0, 2569, 2569, 0, 126720, 0x9ee066e5
-0, 2602, 2602, 0, 126720, 0x7c21664b
-0, 2635, 2635, 0, 126720, 0x36849100
-0, 2669, 2669, 0, 126720, 0x08b1f61a
-0, 2702, 2702, 0, 126720, 0x5bfca6e2
-0, 2736, 2736, 0, 126720, 0x929f60e3
-0, 2769, 2769, 0, 126720, 0xa2b55c29
-0, 2802, 2802, 0, 126720, 0x68bd3ff3
-0, 2836, 2836, 0, 126720, 0x30db5b29
-0, 2869, 2869, 0, 126720, 0x00578f9b
-0, 2902, 2902, 0, 126720, 0x18368642
-0, 2936, 2936, 0, 126720, 0xbcb83a80
-0, 2969, 2969, 0, 126720, 0x90f36b72
-0, 3002, 3002, 0, 126720, 0x85e46522
-0, 3036, 3036, 0, 126720, 0x2429660a
-0, 3069, 3069, 0, 126720, 0xf283dfe2
-0, 3103, 3103, 0, 126720, 0x896b27dc
-0, 3136, 3136, 0, 126720, 0x5af4f961
-0, 3169, 3169, 0, 126720, 0x31897085
-0, 3203, 3203, 0, 126720, 0x441ce33e
-0, 3236, 3236, 0, 126720, 0x903f8009
-0, 3269, 3269, 0, 126720, 0xbdf33dba
-0, 3303, 3303, 0, 126720, 0x8a364f36
-0, 3336, 3336, 0, 126720, 0xda5513f6
-0, 3370, 3370, 0, 126720, 0xd60012b3
-0, 3403, 3403, 0, 126720, 0x67bce7be
-0, 3436, 3436, 0, 126720, 0x697e6174
-0, 3470, 3470, 0, 126720, 0xbe3e3e90
-0, 3503, 3503, 0, 126720, 0xf3e4bba6
-0, 3536, 3536, 0, 126720, 0x8124a679
-0, 3570, 3570, 0, 126720, 0x58d1acde
-0, 3603, 3603, 0, 126720, 0xd8a15ba3
+#tb 0: 32768/982057
+0, 0, 0, 1, 126720, 0x77a5ebed
+0, 1, 1, 1, 126720, 0x4cc1ec8b
+0, 2, 2, 1, 126720, 0x4cc1ec8b
+0, 3, 3, 1, 126720, 0x4cc1ec8b
+0, 4, 4, 1, 126720, 0x0981eccd
+0, 5, 5, 1, 126720, 0x04fef463
+0, 6, 6, 1, 126720, 0x3dd3f4a3
+0, 7, 7, 1, 126720, 0xab74f483
+0, 8, 8, 1, 126720, 0x5ed7b7db
+0, 9, 9, 1, 126720, 0xd1fcb89b
+0, 10, 10, 1, 126720, 0xcb4eb8db
+0, 11, 11, 1, 126720, 0xdcc5b8a7
+0, 12, 12, 1, 126720, 0x33ffb90b
+0, 13, 13, 1, 126720, 0xb38fbb7b
+0, 14, 14, 1, 126720, 0x11f0bbfb
+0, 15, 15, 1, 126720, 0xe8f3bb87
+0, 16, 16, 1, 126720, 0xf8ecb8eb
+0, 17, 17, 1, 126720, 0x5db2ae48
+0, 18, 18, 1, 126720, 0x4e7999a6
+0, 19, 19, 1, 126720, 0xdb84a7a6
+0, 20, 20, 1, 126720, 0x9c4fba45
+0, 21, 21, 1, 126720, 0xe635a858
+0, 22, 22, 1, 126720, 0xd4eeab35
+0, 23, 23, 1, 126720, 0xc416aa56
+0, 24, 24, 1, 126720, 0x4c7ebca5
+0, 25, 25, 1, 126720, 0x2887a70e
+0, 26, 26, 1, 126720, 0xc978eaf1
+0, 27, 27, 1, 126720, 0x8a29b563
+0, 28, 28, 1, 126720, 0x275a0352
+0, 29, 29, 1, 126720, 0x446484bb
+0, 30, 30, 1, 126720, 0xdbe00151
+0, 31, 31, 1, 126720, 0x5874b9aa
+0, 32, 32, 1, 126720, 0xdeb30460
+0, 33, 33, 1, 126720, 0xc6d2d62a
+0, 34, 34, 1, 126720, 0x9270dbc7
+0, 35, 35, 1, 126720, 0x30e4ad59
+0, 36, 36, 1, 126720, 0x117479cd
+0, 37, 37, 1, 126720, 0x0567c5d2
+0, 38, 38, 1, 126720, 0x87c8b4a5
+0, 39, 39, 1, 126720, 0xe5c5e0d1
+0, 40, 40, 1, 126720, 0x78d61e3f
+0, 41, 41, 1, 126720, 0xda8d787f
+0, 42, 42, 1, 126720, 0xf32547f7
+0, 43, 43, 1, 126720, 0x70bc8b60
+0, 44, 44, 1, 126720, 0x3ad09927
+0, 45, 45, 1, 126720, 0x5d9607d6
+0, 46, 46, 1, 126720, 0x348a0e02
+0, 47, 47, 1, 126720, 0x7d21255c
+0, 48, 48, 1, 126720, 0x308ed32b
+0, 49, 49, 1, 126720, 0x79fbe734
+0, 50, 50, 1, 126720, 0xdc5de409
+0, 51, 51, 1, 126720, 0x4ee00283
+0, 52, 52, 1, 126720, 0x2697ea2e
+0, 53, 53, 1, 126720, 0x0885edeb
+0, 54, 54, 1, 126720, 0xc041f0d8
+0, 55, 55, 1, 126720, 0xa893272e
+0, 56, 56, 1, 126720, 0x55419d4e
+0, 57, 57, 1, 126720, 0xbc47dbb5
+0, 58, 58, 1, 126720, 0x9666d60b
+0, 59, 59, 1, 126720, 0xac5c054a
+0, 60, 60, 1, 126720, 0x4affb780
+0, 61, 61, 1, 126720, 0x2b7349eb
+0, 62, 62, 1, 126720, 0x75592d02
+0, 63, 63, 1, 126720, 0xdb904a83
+0, 64, 64, 1, 126720, 0xf85e2f93
+0, 65, 65, 1, 126720, 0x632f8be8
+0, 66, 66, 1, 126720, 0x96108ce4
+0, 67, 67, 1, 126720, 0xb68e816b
+0, 68, 68, 1, 126720, 0x89ca112f
+0, 69, 69, 1, 126720, 0x4bed40d3
+0, 70, 70, 1, 126720, 0xe4cb9b12
+0, 71, 71, 1, 126720, 0xa4f164ec
+0, 72, 72, 1, 126720, 0xd1aa2554
+0, 73, 73, 1, 126720, 0x0277aa01
+0, 74, 74, 1, 126720, 0x8ea280fd
+0, 75, 75, 1, 126720, 0xbae64170
+0, 76, 76, 1, 126720, 0xaf9b543b
+0, 77, 77, 1, 126720, 0x1b31680a
+0, 78, 78, 1, 126720, 0x7da4671e
+0, 79, 79, 1, 126720, 0x82b791cb
+0, 80, 80, 1, 126720, 0xd2fff6bb
+0, 81, 81, 1, 126720, 0x2395a793
+0, 82, 82, 1, 126720, 0x66586185
+0, 83, 83, 1, 126720, 0x99c55c63
+0, 84, 84, 1, 126720, 0x7e3f403e
+0, 85, 85, 1, 126720, 0x9eda5b9a
+0, 86, 86, 1, 126720, 0x27469047
+0, 87, 87, 1, 126720, 0xaa5b870e
+0, 88, 88, 1, 126720, 0x70423b2a
+0, 89, 89, 1, 126720, 0x70d86c0a
+0, 90, 90, 1, 126720, 0x4bd065f3
+0, 91, 91, 1, 126720, 0xd71f66bb
+0, 92, 92, 1, 126720, 0x5333e081
+0, 93, 93, 1, 126720, 0xdf0b28d6
+0, 94, 94, 1, 126720, 0x6c48fa53
+0, 95, 95, 1, 126720, 0x9438712d
+0, 96, 96, 1, 126720, 0x9910e3ec
+0, 97, 97, 1, 126720, 0xb0ea80dd
+0, 98, 98, 1, 126720, 0x71983e67
+0, 99, 99, 1, 126720, 0x18924fe6
+0, 100, 100, 1, 126720, 0x9ca014b9
+0, 101, 101, 1, 126720, 0x45f013a0
+0, 102, 102, 1, 126720, 0xf697e8a9
+0, 103, 103, 1, 126720, 0x214a626a
+0, 104, 104, 1, 126720, 0xb2873fb5
+0, 105, 105, 1, 126720, 0xfb47bc52
+0, 106, 106, 1, 126720, 0x63b7a708
+0, 107, 107, 1, 126720, 0x1904ad40
+0, 108, 108, 1, 126720, 0x80015b91
diff --git a/tests/ref/fate/filter-drawbox b/tests/ref/fate/filter-drawbox
index 869b9f32b0..c63d2fc5e5 100644
--- a/tests/ref/fate/filter-drawbox
+++ b/tests/ref/fate/filter-drawbox
@@ -1,51 +1,51 @@
#tb 0: 1/25
-0, 0, 0, 1, 152064, 0x7eee5ca3
-0, 1, 1, 1, 152064, 0x61125759
-0, 2, 2, 1, 152064, 0x2a64f47f
-0, 3, 3, 1, 152064, 0xc1089594
-0, 4, 4, 1, 152064, 0xd9e18830
-0, 5, 5, 1, 152064, 0xeb135e03
-0, 6, 6, 1, 152064, 0x6a5b40d7
-0, 7, 7, 1, 152064, 0x0a356a16
-0, 8, 8, 1, 152064, 0xfc1d7858
-0, 9, 9, 1, 152064, 0xa04bfeb8
-0, 10, 10, 1, 152064, 0x2d952ef0
-0, 11, 11, 1, 152064, 0x7f360233
-0, 12, 12, 1, 152064, 0xdd2bd142
-0, 13, 13, 1, 152064, 0xd231ad4a
-0, 14, 14, 1, 152064, 0x0543400e
-0, 15, 15, 1, 152064, 0x8252be2b
-0, 16, 16, 1, 152064, 0xd9f702be
-0, 17, 17, 1, 152064, 0xed5cf787
-0, 18, 18, 1, 152064, 0xf9472f8e
-0, 19, 19, 1, 152064, 0x89e4a60b
-0, 20, 20, 1, 152064, 0x1f12c1f5
-0, 21, 21, 1, 152064, 0x76eaf390
-0, 22, 22, 1, 152064, 0x60b5eba3
-0, 23, 23, 1, 152064, 0xf09e348c
-0, 24, 24, 1, 152064, 0x1afabf8a
-0, 25, 25, 1, 152064, 0xd16c558e
-0, 26, 26, 1, 152064, 0x78634796
-0, 27, 27, 1, 152064, 0xcd13b1e3
-0, 28, 28, 1, 152064, 0x59c2c6e5
-0, 29, 29, 1, 152064, 0x265e6beb
-0, 30, 30, 1, 152064, 0x82c656af
-0, 31, 31, 1, 152064, 0x919e923c
-0, 32, 32, 1, 152064, 0xc428fc15
-0, 33, 33, 1, 152064, 0x488760cd
-0, 34, 34, 1, 152064, 0x0a080c93
-0, 35, 35, 1, 152064, 0xaab649e6
-0, 36, 36, 1, 152064, 0x9b34edaa
-0, 37, 37, 1, 152064, 0x44e12816
-0, 38, 38, 1, 152064, 0x03777927
-0, 39, 39, 1, 152064, 0x6644573e
-0, 40, 40, 1, 152064, 0x18574df7
-0, 41, 41, 1, 152064, 0x5dce82f6
-0, 42, 42, 1, 152064, 0xb8be9205
-0, 43, 43, 1, 152064, 0xb927eacb
-0, 44, 44, 1, 152064, 0x303ec874
-0, 45, 45, 1, 152064, 0x05eb3c6f
-0, 46, 46, 1, 152064, 0x74a614d6
-0, 47, 47, 1, 152064, 0x6d078969
-0, 48, 48, 1, 152064, 0xe57a7ae0
-0, 49, 49, 1, 152064, 0xd6fca9ec
+0, 0, 0, 1, 152064, 0x9ada9be9
+0, 1, 1, 1, 152064, 0xb0ec7d59
+0, 2, 2, 1, 152064, 0x938816b8
+0, 3, 3, 1, 152064, 0x1d8fac2e
+0, 4, 4, 1, 152064, 0x8ed4bbf6
+0, 5, 5, 1, 152064, 0xc9e585de
+0, 6, 6, 1, 152064, 0xf1e83c0b
+0, 7, 7, 1, 152064, 0xed0e5981
+0, 8, 8, 1, 152064, 0x6fc55e8c
+0, 9, 9, 1, 152064, 0xcf3e2eb5
+0, 10, 10, 1, 152064, 0xe62d4dcf
+0, 11, 11, 1, 152064, 0xd30712cd
+0, 12, 12, 1, 152064, 0xcb99d3e8
+0, 13, 13, 1, 152064, 0x6b9cb3ed
+0, 14, 14, 1, 152064, 0xb96774c1
+0, 15, 15, 1, 152064, 0xfae0f615
+0, 16, 16, 1, 152064, 0xeb211f65
+0, 17, 17, 1, 152064, 0xc9f7ff9f
+0, 18, 18, 1, 152064, 0xe5bc2b7f
+0, 19, 19, 1, 152064, 0x8f82a022
+0, 20, 20, 1, 152064, 0xb8e5bb92
+0, 21, 21, 1, 152064, 0x051aeb1a
+0, 22, 22, 1, 152064, 0x5b3ce556
+0, 23, 23, 1, 152064, 0xda552e9c
+0, 24, 24, 1, 152064, 0x865ebca1
+0, 25, 25, 1, 152064, 0xd77b6d16
+0, 26, 26, 1, 152064, 0xcf7e89d8
+0, 27, 27, 1, 152064, 0xe340d477
+0, 28, 28, 1, 152064, 0x8167c0e4
+0, 29, 29, 1, 152064, 0xa6af7555
+0, 30, 30, 1, 152064, 0x305a6def
+0, 31, 31, 1, 152064, 0xf395b657
+0, 32, 32, 1, 152064, 0x6f6bdfdc
+0, 33, 33, 1, 152064, 0x976c50ff
+0, 34, 34, 1, 152064, 0x89661e9d
+0, 35, 35, 1, 152064, 0x001760a0
+0, 36, 36, 1, 152064, 0x7ac624ba
+0, 37, 37, 1, 152064, 0x40941960
+0, 38, 38, 1, 152064, 0x89917c8a
+0, 39, 39, 1, 152064, 0xcf4667e5
+0, 40, 40, 1, 152064, 0x985f6670
+0, 41, 41, 1, 152064, 0x5368a016
+0, 42, 42, 1, 152064, 0x2f04b620
+0, 43, 43, 1, 152064, 0x637f1129
+0, 44, 44, 1, 152064, 0x4b41f131
+0, 45, 45, 1, 152064, 0x6e786dea
+0, 46, 46, 1, 152064, 0xeafa55b3
+0, 47, 47, 1, 152064, 0xfdf2d102
+0, 48, 48, 1, 152064, 0x127abdfa
+0, 49, 49, 1, 152064, 0x0e4ae6c7
diff --git a/tests/ref/fate/filter-edgedetect b/tests/ref/fate/filter-edgedetect
new file mode 100644
index 0000000000..23c9953e61
--- /dev/null
+++ b/tests/ref/fate/filter-edgedetect
@@ -0,0 +1 @@
+edgedetect 93ceace33f6636bcdbeb037317c65745
diff --git a/tests/ref/fate/filter-edgedetect-colormix b/tests/ref/fate/filter-edgedetect-colormix
new file mode 100644
index 0000000000..e828c6bd19
--- /dev/null
+++ b/tests/ref/fate/filter-edgedetect-colormix
@@ -0,0 +1 @@
+edgedetect-colormix 1b8658252e2f03fbae30e6d63dd24c7c
diff --git a/tests/ref/fate/filter-fade b/tests/ref/fate/filter-fade
index 131b614b0c..9d691ce90d 100644
--- a/tests/ref/fate/filter-fade
+++ b/tests/ref/fate/filter-fade
@@ -1,51 +1,51 @@
#tb 0: 1/25
-0, 0, 0, 1, 152064, 0xeb8105cd
-0, 1, 1, 1, 152064, 0x0bc0a27d
-0, 2, 2, 1, 152064, 0x9dcd3a04
-0, 3, 3, 1, 152064, 0xecd9e8ec
-0, 4, 4, 1, 152064, 0xdcc09bca
-0, 5, 5, 1, 152064, 0xbf1537ad
-0, 6, 6, 1, 152064, 0xf32214db
-0, 7, 7, 1, 152064, 0x9584ce5e
-0, 8, 8, 1, 152064, 0xbaa930e7
-0, 9, 9, 1, 152064, 0xce411a6c
-0, 10, 10, 1, 152064, 0xdbc2c004
-0, 11, 11, 1, 152064, 0x635a55df
-0, 12, 12, 1, 152064, 0x49d5807f
-0, 13, 13, 1, 152064, 0xd18734a6
-0, 14, 14, 1, 152064, 0xf9d3581f
-0, 15, 15, 1, 152064, 0x423dbdf7
-0, 16, 16, 1, 152064, 0x0c52a4a2
-0, 17, 17, 1, 152064, 0xf7a6a90e
-0, 18, 18, 1, 152064, 0x472441c2
-0, 19, 19, 1, 152064, 0x9470c09a
-0, 20, 20, 1, 152064, 0xce7da1a3
-0, 21, 21, 1, 152064, 0xdb01a0c9
-0, 22, 22, 1, 152064, 0x052e74cb
-0, 23, 23, 1, 152064, 0xab0eab85
-0, 24, 24, 1, 152064, 0x069c1d15
+0, 0, 0, 1, 152064, 0xb4e6c735
+0, 1, 1, 1, 152064, 0xb4e6c735
+0, 2, 2, 1, 152064, 0xb4e6c735
+0, 3, 3, 1, 152064, 0xb4e6c735
+0, 4, 4, 1, 152064, 0xb4e6c735
+0, 5, 5, 1, 152064, 0xb4e6c735
+0, 6, 6, 1, 152064, 0x1f3b0657
+0, 7, 7, 1, 152064, 0x6e7547e6
+0, 8, 8, 1, 152064, 0x1197524c
+0, 9, 9, 1, 152064, 0xb4cdb293
+0, 10, 10, 1, 152064, 0xdd7cf1b8
+0, 11, 11, 1, 152064, 0x360b1005
+0, 12, 12, 1, 152064, 0x11a49918
+0, 13, 13, 1, 152064, 0xa10dd4f9
+0, 14, 14, 1, 152064, 0x78da71d7
+0, 15, 15, 1, 152064, 0x105e4cc0
+0, 16, 16, 1, 152064, 0x54bfa1c5
+0, 17, 17, 1, 152064, 0xd666559e
+0, 18, 18, 1, 152064, 0xd93faa1c
+0, 19, 19, 1, 152064, 0xb1af85ed
+0, 20, 20, 1, 152064, 0xfc7bf570
+0, 21, 21, 1, 152064, 0x9dc72412
+0, 22, 22, 1, 152064, 0x445d1d59
+0, 23, 23, 1, 152064, 0x2f2768ef
+0, 24, 24, 1, 152064, 0xce09f9d6
0, 25, 25, 1, 152064, 0x95579936
-0, 26, 26, 1, 152064, 0x292dc6d4
-0, 27, 27, 1, 152064, 0x951d382d
-0, 28, 28, 1, 152064, 0x9ce23e7d
-0, 29, 29, 1, 152064, 0x5ceb17dd
-0, 30, 30, 1, 152064, 0xe0835003
-0, 31, 31, 1, 152064, 0x7b8a03ba
-0, 32, 32, 1, 152064, 0x1531b18c
-0, 33, 33, 1, 152064, 0xa4a2ee9a
-0, 34, 34, 1, 152064, 0xa5b0e442
-0, 35, 35, 1, 152064, 0x47e0554d
-0, 36, 36, 1, 152064, 0x9443792e
-0, 37, 37, 1, 152064, 0x1a3316ce
-0, 38, 38, 1, 152064, 0xbe8088d7
-0, 39, 39, 1, 152064, 0xd3013824
-0, 40, 40, 1, 152064, 0x342f2f5d
-0, 41, 41, 1, 152064, 0x638a816f
-0, 42, 42, 1, 152064, 0x0cf11a0f
-0, 43, 43, 1, 152064, 0xc4d87159
-0, 44, 44, 1, 152064, 0xa5c36b72
-0, 45, 45, 1, 152064, 0x17a9970d
-0, 46, 46, 1, 152064, 0x5479e51c
-0, 47, 47, 1, 152064, 0x2ae4382a
-0, 48, 48, 1, 152064, 0xab7097a6
-0, 49, 49, 1, 152064, 0xbc97d4bb
+0, 26, 26, 1, 152064, 0x43d796b5
+0, 27, 27, 1, 152064, 0xd780d887
+0, 28, 28, 1, 152064, 0x76d2a455
+0, 29, 29, 1, 152064, 0x6dc3650e
+0, 30, 30, 1, 152064, 0x0f9d6aca
+0, 31, 31, 1, 152064, 0xddae8141
+0, 32, 32, 1, 152064, 0x67cb8f24
+0, 33, 33, 1, 152064, 0xc7a72348
+0, 34, 34, 1, 152064, 0x0d7a1144
+0, 35, 35, 1, 152064, 0x39adfb3d
+0, 36, 36, 1, 152064, 0x0ecc70d5
+0, 37, 37, 1, 152064, 0xf3a6805e
+0, 38, 38, 1, 152064, 0xc3bd71ad
+0, 39, 39, 1, 152064, 0xa9be9730
+0, 40, 40, 1, 152064, 0xab9af790
+0, 41, 41, 1, 152064, 0x4c3ccd25
+0, 42, 42, 1, 152064, 0xbc83c58a
+0, 43, 43, 1, 152064, 0x94877df4
+0, 44, 44, 1, 152064, 0xa2360ea6
+0, 45, 45, 1, 152064, 0xb4e6c735
+0, 46, 46, 1, 152064, 0xb4e6c735
+0, 47, 47, 1, 152064, 0xb4e6c735
+0, 48, 48, 1, 152064, 0xb4e6c735
+0, 49, 49, 1, 152064, 0xb4e6c735
diff --git a/tests/ref/fate/filter-gradfun-sample b/tests/ref/fate/filter-gradfun-sample
new file mode 100644
index 0000000000..595f82ad24
--- /dev/null
+++ b/tests/ref/fate/filter-gradfun-sample
@@ -0,0 +1,21 @@
+#tb 0: 1/10
+0, 0, 0, 1, 76800, 0xea62ab65
+0, 1, 1, 1, 76800, 0xbc0d8b58
+0, 2, 2, 1, 76800, 0x682967d0
+0, 3, 3, 1, 76800, 0x2f1d3353
+0, 4, 4, 1, 76800, 0x0f3306c5
+0, 5, 5, 1, 76800, 0x1f026ce0
+0, 6, 6, 1, 76800, 0xefff2a28
+0, 7, 7, 1, 76800, 0xa7daf536
+0, 8, 8, 1, 76800, 0x8b95b1b2
+0, 9, 9, 1, 76800, 0x821b76c2
+0, 10, 10, 1, 76800, 0x48193d3d
+0, 11, 11, 1, 76800, 0x6182634a
+0, 12, 12, 1, 76800, 0x442b2dcc
+0, 13, 13, 1, 76800, 0x83e2ee26
+0, 14, 14, 1, 76800, 0x47d8b74d
+0, 15, 15, 1, 76800, 0x412b7dcd
+0, 16, 16, 1, 76800, 0x65e33b7c
+0, 17, 17, 1, 76800, 0xb04a0915
+0, 18, 18, 1, 76800, 0x5405c876
+0, 19, 19, 1, 76800, 0xce6d98bc
diff --git a/tests/ref/fate/filter-histogram-levels b/tests/ref/fate/filter-histogram-levels
new file mode 100644
index 0000000000..df9f6b2d52
--- /dev/null
+++ b/tests/ref/fate/filter-histogram-levels
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 488448, 0x0d7343b9
+0, 1, 1, 1, 488448, 0x118e3ade
+0, 2, 2, 1, 488448, 0x778f1ba9
+0, 3, 3, 1, 488448, 0x153bf44e
+0, 4, 4, 1, 488448, 0x2d83c1ab
+0, 5, 5, 1, 488448, 0xa3e95f8f
+0, 6, 6, 1, 488448, 0x91aad31b
+0, 7, 7, 1, 488448, 0x90b92c09
+0, 8, 8, 1, 488448, 0x1e4c9f41
+0, 9, 9, 1, 488448, 0xa88c1882
+0, 10, 10, 1, 488448, 0x1aa04274
+0, 11, 11, 1, 488448, 0x49c45de8
+0, 12, 12, 1, 488448, 0xe799c29f
+0, 13, 13, 1, 488448, 0x789e233f
+0, 14, 14, 1, 488448, 0x9f753404
+0, 15, 15, 1, 488448, 0x83050c2c
+0, 16, 16, 1, 488448, 0xddf7ccbf
+0, 17, 17, 1, 488448, 0xe3128531
+0, 18, 18, 1, 488448, 0xcc6596af
+0, 19, 19, 1, 488448, 0x6e19754f
+0, 20, 20, 1, 488448, 0xc3b32c7c
+0, 21, 21, 1, 488448, 0x40b4853f
+0, 22, 22, 1, 488448, 0x6e492674
+0, 23, 23, 1, 488448, 0x7f867236
+0, 24, 24, 1, 488448, 0x22094365
+0, 25, 25, 1, 488448, 0x45f30fc3
+0, 26, 26, 1, 488448, 0xe6cbad09
+0, 27, 27, 1, 488448, 0x0c44836b
+0, 28, 28, 1, 488448, 0xa7f04271
+0, 29, 29, 1, 488448, 0xd222ba88
+0, 30, 30, 1, 488448, 0xc96a9749
+0, 31, 31, 1, 488448, 0x82e25bbd
+0, 32, 32, 1, 488448, 0xf79d1882
+0, 33, 33, 1, 488448, 0x6d7fdd68
+0, 34, 34, 1, 488448, 0xeb5c9b1b
+0, 35, 35, 1, 488448, 0x9014f9f4
+0, 36, 36, 1, 488448, 0x96c6ab5f
+0, 37, 37, 1, 488448, 0x03911af0
+0, 38, 38, 1, 488448, 0xbf9dd8eb
+0, 39, 39, 1, 488448, 0x73509963
+0, 40, 40, 1, 488448, 0xf2ecb068
+0, 41, 41, 1, 488448, 0xec2fb311
+0, 42, 42, 1, 488448, 0xf4c7ba26
+0, 43, 43, 1, 488448, 0x23f56543
+0, 44, 44, 1, 488448, 0x25f8c48c
+0, 45, 45, 1, 488448, 0xf1ccd38b
+0, 46, 46, 1, 488448, 0x10780667
+0, 47, 47, 1, 488448, 0xbeb70431
+0, 48, 48, 1, 488448, 0xbc950678
+0, 49, 49, 1, 488448, 0xfedf5d83
diff --git a/tests/ref/fate/filter-histogram-waveform b/tests/ref/fate/filter-histogram-waveform
new file mode 100644
index 0000000000..da6bbc4fcf
--- /dev/null
+++ b/tests/ref/fate/filter-histogram-waveform
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 663552, 0x8a55d4d9
+0, 1, 1, 1, 663552, 0xf4c4d42d
+0, 2, 2, 1, 663552, 0x291cd441
+0, 3, 3, 1, 663552, 0xce5bd56b
+0, 4, 4, 1, 663552, 0x1dc0d637
+0, 5, 5, 1, 663552, 0x4676d387
+0, 6, 6, 1, 663552, 0x8064d607
+0, 7, 7, 1, 663552, 0x1981d54f
+0, 8, 8, 1, 663552, 0x8fffd4a3
+0, 9, 9, 1, 663552, 0x5041d2f7
+0, 10, 10, 1, 663552, 0x03bbd401
+0, 11, 11, 1, 663552, 0x965bd2f3
+0, 12, 12, 1, 663552, 0x0d39d27d
+0, 13, 13, 1, 663552, 0xad39d1fb
+0, 14, 14, 1, 663552, 0x1809d195
+0, 15, 15, 1, 663552, 0xe083cf2f
+0, 16, 16, 1, 663552, 0x0d6fd3b3
+0, 17, 17, 1, 663552, 0x3a8ed3f3
+0, 18, 18, 1, 663552, 0xbbb5d00d
+0, 19, 19, 1, 663552, 0xe6ead0df
+0, 20, 20, 1, 663552, 0xf5dcd35f
+0, 21, 21, 1, 663552, 0x9cd9d32b
+0, 22, 22, 1, 663552, 0xcb91d1b9
+0, 23, 23, 1, 663552, 0x5640cfd7
+0, 24, 24, 1, 663552, 0x5370d285
+0, 25, 25, 1, 663552, 0xd894d1dd
+0, 26, 26, 1, 663552, 0xace4ce65
+0, 27, 27, 1, 663552, 0x6e15ce17
+0, 28, 28, 1, 663552, 0xd21cce21
+0, 29, 29, 1, 663552, 0xec1ecd83
+0, 30, 30, 1, 663552, 0x9852ce0f
+0, 31, 31, 1, 663552, 0xe488cba3
+0, 32, 32, 1, 663552, 0x2e15cbed
+0, 33, 33, 1, 663552, 0x5e59ca97
+0, 34, 34, 1, 663552, 0x7cefcd7d
+0, 35, 35, 1, 663552, 0xcb99ccfb
+0, 36, 36, 1, 663552, 0xce32cf29
+0, 37, 37, 1, 663552, 0x7fb8ceef
+0, 38, 38, 1, 663552, 0x4014d18f
+0, 39, 39, 1, 663552, 0x224dd381
+0, 40, 40, 1, 663552, 0x5347d125
+0, 41, 41, 1, 663552, 0xec83ce79
+0, 42, 42, 1, 663552, 0x4d24ce8b
+0, 43, 43, 1, 663552, 0xfdc5ccbd
+0, 44, 44, 1, 663552, 0x592cd18b
+0, 45, 45, 1, 663552, 0xff06d43b
+0, 46, 46, 1, 663552, 0x7f69d4ef
+0, 47, 47, 1, 663552, 0x1607d3f1
+0, 48, 48, 1, 663552, 0x33e0d211
+0, 49, 49, 1, 663552, 0xe1b1d2cd
diff --git a/tests/ref/fate/filter-hq2x b/tests/ref/fate/filter-hq2x
new file mode 100644
index 0000000000..dcf2a291cd
--- /dev/null
+++ b/tests/ref/fate/filter-hq2x
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 877072, 0x9369339e
+0, 1, 1, 1, 877072, 0x32d119a1
diff --git a/tests/ref/fate/filter-hq3x b/tests/ref/fate/filter-hq3x
new file mode 100644
index 0000000000..82153881d4
--- /dev/null
+++ b/tests/ref/fate/filter-hq3x
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 1973412, 0xafc227fa
+0, 1, 1, 1, 1973412, 0x93aebf19
diff --git a/tests/ref/fate/filter-hq4x b/tests/ref/fate/filter-hq4x
new file mode 100644
index 0000000000..c1d6fd8fac
--- /dev/null
+++ b/tests/ref/fate/filter-hq4x
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3508288, 0x034ef75e
+0, 1, 1, 1, 3508288, 0x738e9bbb
diff --git a/tests/ref/fate/filter-hqdn3d-sample b/tests/ref/fate/filter-hqdn3d-sample
new file mode 100644
index 0000000000..97718f92fc
--- /dev/null
+++ b/tests/ref/fate/filter-hqdn3d-sample
@@ -0,0 +1,74 @@
+#tb 0: 1/9
+0, 0, 0, 1, 115200, 0x2c810465
+0, 1, 1, 1, 115200, 0x957c0563
+0, 2, 2, 1, 115200, 0x786c6d5b
+0, 3, 3, 1, 115200, 0xd5ef87d3
+0, 4, 4, 1, 115200, 0x3a2158e2
+0, 5, 5, 1, 115200, 0x19d7d048
+0, 6, 6, 1, 115200, 0x16d5e09a
+0, 7, 7, 1, 115200, 0x73cca454
+0, 8, 8, 1, 115200, 0x4d6be3bc
+0, 9, 9, 1, 115200, 0x672aad0f
+0, 10, 10, 1, 115200, 0x1bd103b7
+0, 11, 11, 1, 115200, 0xbc3a9c02
+0, 12, 12, 1, 115200, 0xa19cb68c
+0, 13, 13, 1, 115200, 0x83477b6c
+0, 14, 14, 1, 115200, 0x68b6898e
+0, 15, 15, 1, 115200, 0xebbc5701
+0, 16, 16, 1, 115200, 0x37e873db
+0, 17, 17, 1, 115200, 0xcf9e7ad1
+0, 18, 18, 1, 115200, 0x3fdffd3a
+0, 19, 19, 1, 115200, 0x413da058
+0, 20, 20, 1, 115200, 0xa432b2f6
+0, 21, 21, 1, 115200, 0x9c532b61
+0, 22, 22, 1, 115200, 0x40c03856
+0, 23, 23, 1, 115200, 0xf8310ec7
+0, 24, 24, 1, 115200, 0x89246da7
+0, 25, 25, 1, 115200, 0x501d4dd0
+0, 26, 26, 1, 115200, 0xe5151ebf
+0, 27, 27, 1, 115200, 0xc166e201
+0, 28, 28, 1, 115200, 0xded25b69
+0, 29, 29, 1, 115200, 0xb51ec43f
+0, 30, 30, 1, 115200, 0x9bba20eb
+0, 31, 31, 1, 115200, 0x7a7b9278
+0, 32, 32, 1, 115200, 0xe98475d0
+0, 33, 33, 1, 115200, 0x960dc933
+0, 34, 34, 1, 115200, 0xe93f558b
+0, 35, 35, 1, 115200, 0x37ae3e42
+0, 36, 36, 1, 115200, 0x0ecaf64a
+0, 37, 37, 1, 115200, 0xd5938191
+0, 38, 38, 1, 115200, 0xeb04510a
+0, 39, 39, 1, 115200, 0xf5729201
+0, 40, 40, 1, 115200, 0xb2c04015
+0, 41, 41, 1, 115200, 0xd883143e
+0, 42, 42, 1, 115200, 0x5e04197b
+0, 43, 43, 1, 115200, 0x6b846e24
+0, 44, 44, 1, 115200, 0x026e7a0b
+0, 45, 45, 1, 115200, 0xef23db9d
+0, 46, 46, 1, 115200, 0x9e94265d
+0, 47, 47, 1, 115200, 0x2830098a
+0, 48, 48, 1, 115200, 0xf5d211d6
+0, 49, 49, 1, 115200, 0xb96b22b0
+0, 50, 50, 1, 115200, 0x9acda7c9
+0, 51, 51, 1, 115200, 0xed7b40f6
+0, 52, 52, 1, 115200, 0x8250278f
+0, 53, 53, 1, 115200, 0xa10003e0
+0, 54, 54, 1, 115200, 0xe67b5513
+0, 55, 55, 1, 115200, 0x2c581d60
+0, 56, 56, 1, 115200, 0xd7a506ed
+0, 57, 57, 1, 115200, 0x35e09799
+0, 58, 58, 1, 115200, 0x2d4f5499
+0, 59, 59, 1, 115200, 0x92fdc85b
+0, 60, 60, 1, 115200, 0x33f4888a
+0, 61, 61, 1, 115200, 0x65e04e05
+0, 62, 62, 1, 115200, 0x14766728
+0, 63, 63, 1, 115200, 0x2a432c3f
+0, 64, 64, 1, 115200, 0x136a1362
+0, 65, 65, 1, 115200, 0xfbf4cb01
+0, 66, 66, 1, 115200, 0x7dcaff69
+0, 67, 67, 1, 115200, 0x5afd3b9e
+0, 68, 68, 1, 115200, 0x86fcb122
+0, 69, 69, 1, 115200, 0xc988b519
+0, 70, 70, 1, 115200, 0x48fd3e75
+0, 71, 71, 1, 115200, 0x2728a2d7
+0, 72, 72, 1, 115200, 0xa2ac6418
diff --git a/tests/ref/fate/filter-hue b/tests/ref/fate/filter-hue
new file mode 100644
index 0000000000..2f1ae619dd
--- /dev/null
+++ b/tests/ref/fate/filter-hue
@@ -0,0 +1 @@
+hue 57463dd9bc17156a51b704dd7271c863
diff --git a/tests/ref/fate/filter-idet b/tests/ref/fate/filter-idet
new file mode 100644
index 0000000000..6283039055
--- /dev/null
+++ b/tests/ref/fate/filter-idet
@@ -0,0 +1,26 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0x6e4f89ef
+0, 1, 1, 1, 152064, 0x7f5f6551
+0, 2, 2, 1, 152064, 0xc566f64a
+0, 3, 3, 1, 152064, 0xceb080b0
+0, 4, 4, 1, 152064, 0x473db652
+0, 5, 5, 1, 152064, 0x287da8e6
+0, 6, 6, 1, 152064, 0x68b47c23
+0, 7, 7, 1, 152064, 0xe9028bac
+0, 8, 8, 1, 152064, 0x28ff8026
+0, 9, 9, 1, 152064, 0x2d7c3915
+0, 10, 10, 1, 152064, 0xb45c4760
+0, 11, 11, 1, 152064, 0xb247fcd5
+0, 12, 12, 1, 152064, 0xcc0bad61
+0, 13, 13, 1, 152064, 0xb1d6a223
+0, 14, 14, 1, 152064, 0x75b38ddd
+0, 15, 15, 1, 152064, 0x6e080f05
+0, 16, 16, 1, 152064, 0x93414e18
+0, 17, 17, 1, 152064, 0xa3e038c8
+0, 18, 18, 1, 152064, 0xec506acc
+0, 19, 19, 1, 152064, 0x1a0ddbff
+0, 20, 20, 1, 152064, 0x19b0f570
+0, 21, 21, 1, 152064, 0xc15e2412
+0, 22, 22, 1, 152064, 0x59ac1d59
+0, 23, 23, 1, 152064, 0x813468ef
+0, 24, 24, 1, 152064, 0x4491f9d6
diff --git a/tests/ref/fate/filter-lavd-life b/tests/ref/fate/filter-lavd-life
new file mode 100644
index 0000000000..565f88ab7a
--- /dev/null
+++ b/tests/ref/fate/filter-lavd-life
@@ -0,0 +1,11 @@
+#tb 0: 1/5
+0, 0, 0, 1, 4800, 0xf2a15b15
+0, 1, 1, 1, 4800, 0x78c29dcf
+0, 2, 2, 1, 4800, 0x28509d6e
+0, 3, 3, 1, 4800, 0xb9d0841a
+0, 4, 4, 1, 4800, 0x53ac6a72
+0, 5, 5, 1, 4800, 0x6e6a6587
+0, 6, 6, 1, 4800, 0x6de46287
+0, 7, 7, 1, 4800, 0x7e0d5b95
+0, 8, 8, 1, 4800, 0xf30f5a1b
+0, 9, 9, 1, 4800, 0x84505420
diff --git a/tests/ref/fate/filter-lavd-scalenorm b/tests/ref/fate/filter-lavd-scalenorm
new file mode 100644
index 0000000000..c946b5c3b1
--- /dev/null
+++ b/tests/ref/fate/filter-lavd-scalenorm
@@ -0,0 +1,11 @@
+#tb 0: 1/5
+0, 0, 0, 1, 18432, 0xac484db5
+0, 1, 1, 1, 18432, 0x94734db6
+0, 2, 2, 1, 18432, 0x3fac4db3
+0, 3, 3, 1, 18432, 0x37a94dcd
+0, 4, 4, 1, 18432, 0x2b3e4dbb
+0, 5, 5, 1, 18432, 0xd23a67bf
+0, 6, 6, 1, 18432, 0x898368e1
+0, 7, 7, 1, 18432, 0x79466438
+0, 8, 8, 1, 18432, 0x458c5d95
+0, 9, 9, 1, 18432, 0x9d9a56ee
diff --git a/tests/ref/fate/filter-lavd-testsrc b/tests/ref/fate/filter-lavd-testsrc
new file mode 100644
index 0000000000..0ea5a49531
--- /dev/null
+++ b/tests/ref/fate/filter-lavd-testsrc
@@ -0,0 +1,71 @@
+#tb 0: 1/7
+0, 0, 0, 1, 230400, 0x88c4d19a
+0, 1, 1, 1, 230400, 0xcc930a2e
+0, 2, 2, 1, 230400, 0x8e1b0e23
+0, 3, 3, 1, 230400, 0xff3b5a72
+0, 4, 4, 1, 230400, 0xb0ad3760
+0, 5, 5, 1, 230400, 0x8013eaaf
+0, 6, 6, 1, 230400, 0xa6eaa9c3
+0, 7, 7, 1, 230400, 0xef4695a2
+0, 8, 8, 1, 230400, 0x8f144889
+0, 9, 9, 1, 230400, 0x693779f9
+0, 10, 10, 1, 230400, 0xedaf92f0
+0, 11, 11, 1, 230400, 0x1c39d7c4
+0, 12, 12, 1, 230400, 0xb72589bb
+0, 13, 13, 1, 230400, 0x61c2de4a
+0, 14, 14, 1, 230400, 0xc46085ae
+0, 15, 15, 1, 230400, 0xad059d62
+0, 16, 16, 1, 230400, 0xe82ea157
+0, 17, 17, 1, 230400, 0xa30aeda6
+0, 18, 18, 1, 230400, 0x7f86ca94
+0, 19, 19, 1, 230400, 0x4c4f7df2
+0, 20, 20, 1, 230400, 0x535a3d06
+0, 21, 21, 1, 230400, 0x449262ff
+0, 22, 22, 1, 230400, 0x971c15e6
+0, 23, 23, 1, 230400, 0xda1d4756
+0, 24, 24, 1, 230400, 0x78ad604d
+0, 25, 25, 1, 230400, 0x72d8a521
+0, 26, 26, 1, 230400, 0x8f395718
+0, 27, 27, 1, 230400, 0x6e57aba7
+0, 28, 28, 1, 230400, 0x54ad968f
+0, 29, 29, 1, 230400, 0x59d9ae43
+0, 30, 30, 1, 230400, 0x843fb238
+0, 31, 31, 1, 230400, 0x0f77fe87
+0, 32, 32, 1, 230400, 0x8c8adb75
+0, 33, 33, 1, 230400, 0xdd568ed3
+0, 34, 34, 1, 230400, 0x38bd4de7
+0, 35, 35, 1, 230400, 0x62ad62ff
+0, 36, 36, 1, 230400, 0x1f0215e6
+0, 37, 37, 1, 230400, 0xe8534756
+0, 38, 38, 1, 230400, 0x3d36604d
+0, 39, 39, 1, 230400, 0x0c57a521
+0, 40, 40, 1, 230400, 0x2b555718
+0, 41, 41, 1, 230400, 0x2a3faba7
+0, 42, 42, 1, 230400, 0x4e0a74cd
+0, 43, 43, 1, 230400, 0xa06b8c81
+0, 44, 44, 1, 230400, 0x61f39076
+0, 45, 45, 1, 230400, 0xd313dcc5
+0, 46, 46, 1, 230400, 0x8485b9b3
+0, 47, 47, 1, 230400, 0x53eb6d11
+0, 48, 48, 1, 230400, 0x7ac22c25
+0, 49, 49, 1, 230400, 0xce7b84c1
+0, 50, 50, 1, 230400, 0x6e4937a8
+0, 51, 51, 1, 230400, 0x486c6918
+0, 52, 52, 1, 230400, 0xcce4820f
+0, 53, 53, 1, 230400, 0xfb5fc6e3
+0, 54, 54, 1, 230400, 0x965a78da
+0, 55, 55, 1, 230400, 0x40f7cd69
+0, 56, 56, 1, 230400, 0x68db63ec
+0, 57, 57, 1, 230400, 0x51807ba0
+0, 58, 58, 1, 230400, 0x8ca97f95
+0, 59, 59, 1, 230400, 0x4785cbe4
+0, 60, 60, 1, 230400, 0x2401a8d2
+0, 61, 61, 1, 230400, 0xf0bb5c30
+0, 62, 62, 1, 230400, 0xf7c61b44
+0, 63, 63, 1, 230400, 0x7d7e521e
+0, 64, 64, 1, 230400, 0xd0080505
+0, 65, 65, 1, 230400, 0x13183675
+0, 66, 66, 1, 230400, 0xb1994f6c
+0, 67, 67, 1, 230400, 0xabc49440
+0, 68, 68, 1, 230400, 0xc8254637
+0, 69, 69, 1, 230400, 0xa7439ac6
diff --git a/tests/ref/fate/filter-mcdeint-fast b/tests/ref/fate/filter-mcdeint-fast
new file mode 100644
index 0000000000..000d43bd33
--- /dev/null
+++ b/tests/ref/fate/filter-mcdeint-fast
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 9, 9, 1, 622080, 0xb3b66c5c
+0, 10, 10, 1, 622080, 0xc6568bd7
+0, 11, 11, 1, 622080, 0xa5b543c3
+0, 12, 12, 1, 622080, 0x4095ac51
+0, 13, 13, 1, 622080, 0xccd8c1d9
+0, 14, 14, 1, 622080, 0x84a88f22
+0, 15, 15, 1, 622080, 0x7273c26b
+0, 16, 16, 1, 622080, 0xac188c41
+0, 17, 17, 1, 622080, 0xf32f6fb4
+0, 18, 18, 1, 622080, 0xd696ccce
+0, 19, 19, 1, 622080, 0x9778a418
+0, 20, 20, 1, 622080, 0xf2b5be2e
+0, 21, 21, 1, 622080, 0x653ee12a
+0, 22, 22, 1, 622080, 0xe7fce188
+0, 23, 23, 1, 622080, 0x6e9f1deb
+0, 24, 24, 1, 622080, 0x33090aac
+0, 25, 25, 1, 622080, 0x840a57f1
+0, 26, 26, 1, 622080, 0x635e430a
+0, 27, 27, 1, 622080, 0x52f98809
+0, 28, 28, 1, 622080, 0xc567b6a5
+0, 29, 29, 1, 622080, 0x4134f583
+0, 30, 30, 1, 622080, 0xd02a73bc
+0, 31, 31, 1, 622080, 0x763085d6
+0, 32, 32, 1, 622080, 0x77fdc7a6
+0, 33, 33, 1, 622080, 0x77f71b9f
+0, 34, 34, 1, 622080, 0x71c91244
+0, 35, 35, 1, 622080, 0xc7b86da5
+0, 36, 36, 1, 622080, 0x1edf8890
+0, 37, 37, 1, 622080, 0x03c82bec
+0, 38, 38, 1, 622080, 0x148b6a04
diff --git a/tests/ref/fate/filter-mcdeint-medium b/tests/ref/fate/filter-mcdeint-medium
new file mode 100644
index 0000000000..cfd504f084
--- /dev/null
+++ b/tests/ref/fate/filter-mcdeint-medium
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 9, 9, 1, 622080, 0xb3b66c5c
+0, 10, 10, 1, 622080, 0x26a29152
+0, 11, 11, 1, 622080, 0x787adddc
+0, 12, 12, 1, 622080, 0xcc52df08
+0, 13, 13, 1, 622080, 0x53dad126
+0, 14, 14, 1, 622080, 0xe1448652
+0, 15, 15, 1, 622080, 0x159fd353
+0, 16, 16, 1, 622080, 0xcbe893a0
+0, 17, 17, 1, 622080, 0x43a67c6b
+0, 18, 18, 1, 622080, 0xef30caf9
+0, 19, 19, 1, 622080, 0xa9cea62b
+0, 20, 20, 1, 622080, 0x4c4cada1
+0, 21, 21, 1, 622080, 0x8e91f6de
+0, 22, 22, 1, 622080, 0xb03ef044
+0, 23, 23, 1, 622080, 0x6b54262b
+0, 24, 24, 1, 622080, 0x911e0cea
+0, 25, 25, 1, 622080, 0x8320632c
+0, 26, 26, 1, 622080, 0x2bde42b2
+0, 27, 27, 1, 622080, 0xe9d988c3
+0, 28, 28, 1, 622080, 0xa9f0b1db
+0, 29, 29, 1, 622080, 0xb5bcf186
+0, 30, 30, 1, 622080, 0x469c6717
+0, 31, 31, 1, 622080, 0x2ca883e6
+0, 32, 32, 1, 622080, 0x4f5fba72
+0, 33, 33, 1, 622080, 0xa2e423ca
+0, 34, 34, 1, 622080, 0xc1fb0aaf
+0, 35, 35, 1, 622080, 0x96a879b8
+0, 36, 36, 1, 622080, 0x212e92e6
+0, 37, 37, 1, 622080, 0x9f26378a
+0, 38, 38, 1, 622080, 0xdeaf77ab
diff --git a/tests/ref/fate/filter-metadata-ebur128 b/tests/ref/fate/filter-metadata-ebur128
new file mode 100644
index 0000000000..7a060bdf87
--- /dev/null
+++ b/tests/ref/fate/filter-metadata-ebur128
@@ -0,0 +1,280 @@
+pkt_pts=0|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=4800|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=9600|tag:lavfi.r128.M=-120.691|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-70.000|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=14400|tag:lavfi.r128.M=-21.333|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.340|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=19200|tag:lavfi.r128.M=-21.249|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.295|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=24000|tag:lavfi.r128.M=-21.235|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.276|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=28800|tag:lavfi.r128.M=-21.587|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.353|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=33600|tag:lavfi.r128.M=-21.999|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.475|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=38400|tag:lavfi.r128.M=-22.371|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.613|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=43200|tag:lavfi.r128.M=-23.195|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.807|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=48000|tag:lavfi.r128.M=-23.550|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-21.991|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=52800|tag:lavfi.r128.M=-23.901|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.167|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=57600|tag:lavfi.r128.M=-24.461|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.350|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=62400|tag:lavfi.r128.M=-24.984|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.533|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=67200|tag:lavfi.r128.M=-25.448|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.714|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=72000|tag:lavfi.r128.M=-25.847|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-22.889|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=76800|tag:lavfi.r128.M=-26.187|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.058|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=81600|tag:lavfi.r128.M=-26.229|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.210|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=86400|tag:lavfi.r128.M=-26.132|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.346|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=91200|tag:lavfi.r128.M=-26.164|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.470|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=96000|tag:lavfi.r128.M=-26.282|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.586|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=100800|tag:lavfi.r128.M=-26.371|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.696|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=105600|tag:lavfi.r128.M=-26.421|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.799|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=110400|tag:lavfi.r128.M=-26.362|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.892|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=115200|tag:lavfi.r128.M=-26.278|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-23.977|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=120000|tag:lavfi.r128.M=-26.524|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.061|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=124800|tag:lavfi.r128.M=-26.867|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.148|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=129600|tag:lavfi.r128.M=-27.286|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.239|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=134400|tag:lavfi.r128.M=-27.372|tag:lavfi.r128.S=-120.691|tag:lavfi.r128.I=-24.326|tag:lavfi.r128.LRA=0.000|tag:lavfi.r128.LRA.low=0.000|tag:lavfi.r128.LRA.high=0.000
+pkt_pts=139200|tag:lavfi.r128.M=-27.449|tag:lavfi.r128.S=-24.296|tag:lavfi.r128.I=-24.409|tag:lavfi.r128.LRA=20.000|tag:lavfi.r128.LRA.low=-44.300|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=144000|tag:lavfi.r128.M=-27.083|tag:lavfi.r128.S=-24.455|tag:lavfi.r128.I=-24.481|tag:lavfi.r128.LRA=20.080|tag:lavfi.r128.LRA.low=-44.380|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=148800|tag:lavfi.r128.M=-26.899|tag:lavfi.r128.S=-24.719|tag:lavfi.r128.I=-24.545|tag:lavfi.r128.LRA=20.190|tag:lavfi.r128.LRA.low=-44.490|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=153600|tag:lavfi.r128.M=-26.880|tag:lavfi.r128.S=-24.962|tag:lavfi.r128.I=-24.606|tag:lavfi.r128.LRA=20.310|tag:lavfi.r128.LRA.low=-44.610|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=158400|tag:lavfi.r128.M=-26.886|tag:lavfi.r128.S=-25.214|tag:lavfi.r128.I=-24.664|tag:lavfi.r128.LRA=0.920|tag:lavfi.r128.LRA.low=-25.220|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=163200|tag:lavfi.r128.M=-27.096|tag:lavfi.r128.S=-25.459|tag:lavfi.r128.I=-24.722|tag:lavfi.r128.LRA=1.160|tag:lavfi.r128.LRA.low=-25.460|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=168000|tag:lavfi.r128.M=-26.430|tag:lavfi.r128.S=-25.729|tag:lavfi.r128.I=-24.765|tag:lavfi.r128.LRA=1.430|tag:lavfi.r128.LRA.low=-25.730|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=172800|tag:lavfi.r128.M=-25.736|tag:lavfi.r128.S=-25.816|tag:lavfi.r128.I=-24.791|tag:lavfi.r128.LRA=1.520|tag:lavfi.r128.LRA.low=-25.820|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=177600|tag:lavfi.r128.M=-25.976|tag:lavfi.r128.S=-26.011|tag:lavfi.r128.I=-24.821|tag:lavfi.r128.LRA=1.720|tag:lavfi.r128.LRA.low=-26.020|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=182400|tag:lavfi.r128.M=-26.417|tag:lavfi.r128.S=-26.240|tag:lavfi.r128.I=-24.858|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=187200|tag:lavfi.r128.M=-27.102|tag:lavfi.r128.S=-26.393|tag:lavfi.r128.I=-24.906|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=192000|tag:lavfi.r128.M=-28.221|tag:lavfi.r128.S=-26.511|tag:lavfi.r128.I=-24.968|tag:lavfi.r128.LRA=2.060|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=196800|tag:lavfi.r128.M=-27.900|tag:lavfi.r128.S=-26.618|tag:lavfi.r128.I=-25.023|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=201600|tag:lavfi.r128.M=-27.179|tag:lavfi.r128.S=-26.666|tag:lavfi.r128.I=-25.065|tag:lavfi.r128.LRA=2.210|tag:lavfi.r128.LRA.low=-26.670|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=206400|tag:lavfi.r128.M=-26.274|tag:lavfi.r128.S=-26.604|tag:lavfi.r128.I=-25.091|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=211200|tag:lavfi.r128.M=-25.385|tag:lavfi.r128.S=-26.501|tag:lavfi.r128.I=-25.098|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=216000|tag:lavfi.r128.M=-25.220|tag:lavfi.r128.S=-26.511|tag:lavfi.r128.I=-25.101|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=220800|tag:lavfi.r128.M=-23.888|tag:lavfi.r128.S=-26.237|tag:lavfi.r128.I=-25.069|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=225600|tag:lavfi.r128.M=-24.544|tag:lavfi.r128.S=-26.315|tag:lavfi.r128.I=-25.057|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=230400|tag:lavfi.r128.M=-25.042|tag:lavfi.r128.S=-26.325|tag:lavfi.r128.I=-25.057|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=235200|tag:lavfi.r128.M=-25.146|tag:lavfi.r128.S=-26.349|tag:lavfi.r128.I=-25.059|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=240000|tag:lavfi.r128.M=-27.510|tag:lavfi.r128.S=-26.380|tag:lavfi.r128.I=-25.098|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=244800|tag:lavfi.r128.M=-26.266|tag:lavfi.r128.S=-26.301|tag:lavfi.r128.I=-25.119|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=249600|tag:lavfi.r128.M=-26.455|tag:lavfi.r128.S=-26.329|tag:lavfi.r128.I=-25.142|tag:lavfi.r128.LRA=2.160|tag:lavfi.r128.LRA.low=-26.620|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=254400|tag:lavfi.r128.M=-26.169|tag:lavfi.r128.S=-26.323|tag:lavfi.r128.I=-25.160|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=259200|tag:lavfi.r128.M=-25.834|tag:lavfi.r128.S=-26.317|tag:lavfi.r128.I=-25.172|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=264000|tag:lavfi.r128.M=-26.461|tag:lavfi.r128.S=-26.293|tag:lavfi.r128.I=-25.194|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=268800|tag:lavfi.r128.M=-26.327|tag:lavfi.r128.S=-26.262|tag:lavfi.r128.I=-25.212|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=273600|tag:lavfi.r128.M=-26.559|tag:lavfi.r128.S=-26.239|tag:lavfi.r128.I=-25.233|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=278400|tag:lavfi.r128.M=-26.657|tag:lavfi.r128.S=-26.236|tag:lavfi.r128.I=-25.255|tag:lavfi.r128.LRA=2.150|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=283200|tag:lavfi.r128.M=-26.563|tag:lavfi.r128.S=-26.193|tag:lavfi.r128.I=-25.275|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=288000|tag:lavfi.r128.M=-26.632|tag:lavfi.r128.S=-26.210|tag:lavfi.r128.I=-25.295|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=292800|tag:lavfi.r128.M=-26.750|tag:lavfi.r128.S=-26.222|tag:lavfi.r128.I=-25.316|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=297600|tag:lavfi.r128.M=-26.727|tag:lavfi.r128.S=-26.218|tag:lavfi.r128.I=-25.336|tag:lavfi.r128.LRA=1.890|tag:lavfi.r128.LRA.low=-26.610|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=302400|tag:lavfi.r128.M=-26.945|tag:lavfi.r128.S=-26.200|tag:lavfi.r128.I=-25.358|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=307200|tag:lavfi.r128.M=-26.839|tag:lavfi.r128.S=-26.181|tag:lavfi.r128.I=-25.379|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=312000|tag:lavfi.r128.M=-26.056|tag:lavfi.r128.S=-26.172|tag:lavfi.r128.I=-25.389|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=316800|tag:lavfi.r128.M=-26.589|tag:lavfi.r128.S=-26.335|tag:lavfi.r128.I=-25.405|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=321600|tag:lavfi.r128.M=-27.190|tag:lavfi.r128.S=-26.351|tag:lavfi.r128.I=-25.428|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=326400|tag:lavfi.r128.M=-28.078|tag:lavfi.r128.S=-26.359|tag:lavfi.r128.I=-25.458|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=331200|tag:lavfi.r128.M=-27.878|tag:lavfi.r128.S=-26.250|tag:lavfi.r128.I=-25.486|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=336000|tag:lavfi.r128.M=-26.604|tag:lavfi.r128.S=-26.169|tag:lavfi.r128.I=-25.500|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=340800|tag:lavfi.r128.M=-26.289|tag:lavfi.r128.S=-26.173|tag:lavfi.r128.I=-25.511|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=345600|tag:lavfi.r128.M=-24.672|tag:lavfi.r128.S=-26.000|tag:lavfi.r128.I=-25.498|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=350400|tag:lavfi.r128.M=-25.114|tag:lavfi.r128.S=-26.077|tag:lavfi.r128.I=-25.492|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=355200|tag:lavfi.r128.M=-24.561|tag:lavfi.r128.S=-26.027|tag:lavfi.r128.I=-25.478|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=360000|tag:lavfi.r128.M=-23.558|tag:lavfi.r128.S=-25.849|tag:lavfi.r128.I=-25.445|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=364800|tag:lavfi.r128.M=-24.650|tag:lavfi.r128.S=-26.154|tag:lavfi.r128.I=-25.433|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=369600|tag:lavfi.r128.M=-23.700|tag:lavfi.r128.S=-25.903|tag:lavfi.r128.I=-25.405|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=374400|tag:lavfi.r128.M=-24.144|tag:lavfi.r128.S=-25.863|tag:lavfi.r128.I=-25.386|tag:lavfi.r128.LRA=1.800|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=379200|tag:lavfi.r128.M=-23.935|tag:lavfi.r128.S=-25.635|tag:lavfi.r128.I=-25.364|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=384000|tag:lavfi.r128.M=-22.202|tag:lavfi.r128.S=-25.242|tag:lavfi.r128.I=-25.305|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=388800|tag:lavfi.r128.M=-22.634|tag:lavfi.r128.S=-25.257|tag:lavfi.r128.I=-25.258|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=393600|tag:lavfi.r128.M=-22.480|tag:lavfi.r128.S=-25.165|tag:lavfi.r128.I=-25.210|tag:lavfi.r128.LRA=1.550|tag:lavfi.r128.LRA.low=-26.520|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=398400|tag:lavfi.r128.M=-23.030|tag:lavfi.r128.S=-25.124|tag:lavfi.r128.I=-25.176|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=403200|tag:lavfi.r128.M=-24.357|tag:lavfi.r128.S=-25.042|tag:lavfi.r128.I=-25.165|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=408000|tag:lavfi.r128.M=-24.346|tag:lavfi.r128.S=-24.990|tag:lavfi.r128.I=-25.154|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=412800|tag:lavfi.r128.M=-24.868|tag:lavfi.r128.S=-24.992|tag:lavfi.r128.I=-25.151|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=417600|tag:lavfi.r128.M=-25.190|tag:lavfi.r128.S=-24.972|tag:lavfi.r128.I=-25.151|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=422400|tag:lavfi.r128.M=-26.094|tag:lavfi.r128.S=-24.987|tag:lavfi.r128.I=-25.161|tag:lavfi.r128.LRA=1.540|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.970
+pkt_pts=427200|tag:lavfi.r128.M=-26.093|tag:lavfi.r128.S=-24.944|tag:lavfi.r128.I=-25.171|tag:lavfi.r128.LRA=1.560|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.950
+pkt_pts=432000|tag:lavfi.r128.M=-26.243|tag:lavfi.r128.S=-24.955|tag:lavfi.r128.I=-25.182|tag:lavfi.r128.LRA=1.560|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.950
+pkt_pts=436800|tag:lavfi.r128.M=-25.959|tag:lavfi.r128.S=-24.896|tag:lavfi.r128.I=-25.190|tag:lavfi.r128.LRA=1.610|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.900
+pkt_pts=441600|tag:lavfi.r128.M=-24.870|tag:lavfi.r128.S=-24.785|tag:lavfi.r128.I=-25.186|tag:lavfi.r128.LRA=1.720|tag:lavfi.r128.LRA.low=-26.510|tag:lavfi.r128.LRA.high=-24.790
+pkt_pts=446400|tag:lavfi.r128.M=-24.644|tag:lavfi.r128.S=-24.696|tag:lavfi.r128.I=-25.180|tag:lavfi.r128.LRA=1.680|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.720
+pkt_pts=451200|tag:lavfi.r128.M=-24.141|tag:lavfi.r128.S=-24.643|tag:lavfi.r128.I=-25.167|tag:lavfi.r128.LRA=1.700|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.700
+pkt_pts=456000|tag:lavfi.r128.M=-23.990|tag:lavfi.r128.S=-24.634|tag:lavfi.r128.I=-25.153|tag:lavfi.r128.LRA=1.750|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.650
+pkt_pts=460800|tag:lavfi.r128.M=-24.020|tag:lavfi.r128.S=-24.487|tag:lavfi.r128.I=-25.139|tag:lavfi.r128.LRA=1.760|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.640
+pkt_pts=465600|tag:lavfi.r128.M=-24.627|tag:lavfi.r128.S=-24.442|tag:lavfi.r128.I=-25.133|tag:lavfi.r128.LRA=1.910|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.490
+pkt_pts=470400|tag:lavfi.r128.M=-25.115|tag:lavfi.r128.S=-24.394|tag:lavfi.r128.I=-25.133|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=475200|tag:lavfi.r128.M=-25.672|tag:lavfi.r128.S=-24.456|tag:lavfi.r128.I=-25.138|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=480000|tag:lavfi.r128.M=-26.632|tag:lavfi.r128.S=-24.490|tag:lavfi.r128.I=-25.151|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=484800|tag:lavfi.r128.M=-25.996|tag:lavfi.r128.S=-24.416|tag:lavfi.r128.I=-25.159|tag:lavfi.r128.LRA=1.940|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.460
+pkt_pts=489600|tag:lavfi.r128.M=-24.937|tag:lavfi.r128.S=-24.426|tag:lavfi.r128.I=-25.157|tag:lavfi.r128.LRA=1.950|tag:lavfi.r128.LRA.low=-26.400|tag:lavfi.r128.LRA.high=-24.450
+pkt_pts=494400|tag:lavfi.r128.M=-22.685|tag:lavfi.r128.S=-24.098|tag:lavfi.r128.I=-25.124|tag:lavfi.r128.LRA=1.960|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.430
+pkt_pts=499200|tag:lavfi.r128.M=-21.913|tag:lavfi.r128.S=-24.036|tag:lavfi.r128.I=-25.078|tag:lavfi.r128.LRA=1.970|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.420
+pkt_pts=504000|tag:lavfi.r128.M=-21.524|tag:lavfi.r128.S=-24.013|tag:lavfi.r128.I=-25.025|tag:lavfi.r128.LRA=1.990|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.400
+pkt_pts=508800|tag:lavfi.r128.M=-21.267|tag:lavfi.r128.S=-23.821|tag:lavfi.r128.I=-24.968|tag:lavfi.r128.LRA=2.090|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.300
+pkt_pts=513600|tag:lavfi.r128.M=-22.730|tag:lavfi.r128.S=-23.942|tag:lavfi.r128.I=-24.940|tag:lavfi.r128.LRA=2.290|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.100
+pkt_pts=518400|tag:lavfi.r128.M=-23.373|tag:lavfi.r128.S=-23.927|tag:lavfi.r128.I=-24.923|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=523200|tag:lavfi.r128.M=-24.172|tag:lavfi.r128.S=-24.045|tag:lavfi.r128.I=-24.915|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=528000|tag:lavfi.r128.M=-25.060|tag:lavfi.r128.S=-24.247|tag:lavfi.r128.I=-24.916|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=532800|tag:lavfi.r128.M=-24.555|tag:lavfi.r128.S=-24.232|tag:lavfi.r128.I=-24.913|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=537600|tag:lavfi.r128.M=-25.070|tag:lavfi.r128.S=-24.306|tag:lavfi.r128.I=-24.915|tag:lavfi.r128.LRA=2.350|tag:lavfi.r128.LRA.low=-26.390|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=542400|tag:lavfi.r128.M=-25.104|tag:lavfi.r128.S=-24.332|tag:lavfi.r128.I=-24.916|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=547200|tag:lavfi.r128.M=-25.813|tag:lavfi.r128.S=-24.411|tag:lavfi.r128.I=-24.924|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=552000|tag:lavfi.r128.M=-25.950|tag:lavfi.r128.S=-24.409|tag:lavfi.r128.I=-24.932|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=556800|tag:lavfi.r128.M=-25.759|tag:lavfi.r128.S=-24.402|tag:lavfi.r128.I=-24.938|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=561600|tag:lavfi.r128.M=-25.702|tag:lavfi.r128.S=-24.385|tag:lavfi.r128.I=-24.944|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=566400|tag:lavfi.r128.M=-24.540|tag:lavfi.r128.S=-24.245|tag:lavfi.r128.I=-24.941|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=571200|tag:lavfi.r128.M=-23.455|tag:lavfi.r128.S=-24.093|tag:lavfi.r128.I=-24.926|tag:lavfi.r128.LRA=2.310|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.050
+pkt_pts=576000|tag:lavfi.r128.M=-22.161|tag:lavfi.r128.S=-23.848|tag:lavfi.r128.I=-24.893|tag:lavfi.r128.LRA=2.320|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.040
+pkt_pts=580800|tag:lavfi.r128.M=-21.752|tag:lavfi.r128.S=-23.772|tag:lavfi.r128.I=-24.855|tag:lavfi.r128.LRA=2.340|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-24.020
+pkt_pts=585600|tag:lavfi.r128.M=-21.869|tag:lavfi.r128.S=-23.772|tag:lavfi.r128.I=-24.819|tag:lavfi.r128.LRA=2.410|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.950
+pkt_pts=590400|tag:lavfi.r128.M=-22.553|tag:lavfi.r128.S=-23.788|tag:lavfi.r128.I=-24.795|tag:lavfi.r128.LRA=2.430|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.930
+pkt_pts=595200|tag:lavfi.r128.M=-23.563|tag:lavfi.r128.S=-23.771|tag:lavfi.r128.I=-24.783|tag:lavfi.r128.LRA=2.510|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.850
+pkt_pts=600000|tag:lavfi.r128.M=-23.930|tag:lavfi.r128.S=-23.764|tag:lavfi.r128.I=-24.776|tag:lavfi.r128.LRA=2.530|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.830
+pkt_pts=604800|tag:lavfi.r128.M=-24.599|tag:lavfi.r128.S=-23.841|tag:lavfi.r128.I=-24.774|tag:lavfi.r128.LRA=2.530|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.830
+pkt_pts=609600|tag:lavfi.r128.M=-24.476|tag:lavfi.r128.S=-23.772|tag:lavfi.r128.I=-24.772|tag:lavfi.r128.LRA=2.570|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.790
+pkt_pts=614400|tag:lavfi.r128.M=-24.380|tag:lavfi.r128.S=-23.694|tag:lavfi.r128.I=-24.769|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=619200|tag:lavfi.r128.M=-23.440|tag:lavfi.r128.S=-23.520|tag:lavfi.r128.I=-24.756|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=624000|tag:lavfi.r128.M=-22.290|tag:lavfi.r128.S=-23.347|tag:lavfi.r128.I=-24.731|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=628800|tag:lavfi.r128.M=-21.092|tag:lavfi.r128.S=-23.100|tag:lavfi.r128.I=-24.687|tag:lavfi.r128.LRA=2.580|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.780
+pkt_pts=633600|tag:lavfi.r128.M=-20.607|tag:lavfi.r128.S=-23.007|tag:lavfi.r128.I=-24.635|tag:lavfi.r128.LRA=2.590|tag:lavfi.r128.LRA.low=-26.360|tag:lavfi.r128.LRA.high=-23.770
+pkt_pts=638400|tag:lavfi.r128.M=-20.608|tag:lavfi.r128.S=-23.110|tag:lavfi.r128.I=-24.585|tag:lavfi.r128.LRA=2.650|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.700
+pkt_pts=643200|tag:lavfi.r128.M=-20.622|tag:lavfi.r128.S=-23.077|tag:lavfi.r128.I=-24.536|tag:lavfi.r128.LRA=2.820|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.530
+pkt_pts=648000|tag:lavfi.r128.M=-21.543|tag:lavfi.r128.S=-23.104|tag:lavfi.r128.I=-24.504|tag:lavfi.r128.LRA=3.000|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.350
+pkt_pts=652800|tag:lavfi.r128.M=-22.071|tag:lavfi.r128.S=-23.156|tag:lavfi.r128.I=-24.480|tag:lavfi.r128.LRA=3.190|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.160
+pkt_pts=657600|tag:lavfi.r128.M=-22.327|tag:lavfi.r128.S=-23.049|tag:lavfi.r128.I=-24.459|tag:lavfi.r128.LRA=3.240|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.110
+pkt_pts=662400|tag:lavfi.r128.M=-22.810|tag:lavfi.r128.S=-23.003|tag:lavfi.r128.I=-24.445|tag:lavfi.r128.LRA=3.240|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.110
+pkt_pts=667200|tag:lavfi.r128.M=-22.676|tag:lavfi.r128.S=-22.921|tag:lavfi.r128.I=-24.429|tag:lavfi.r128.LRA=3.240|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.110
+pkt_pts=672000|tag:lavfi.r128.M=-22.942|tag:lavfi.r128.S=-22.927|tag:lavfi.r128.I=-24.416|tag:lavfi.r128.LRA=3.250|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.100
+pkt_pts=676800|tag:lavfi.r128.M=-23.165|tag:lavfi.r128.S=-22.897|tag:lavfi.r128.I=-24.406|tag:lavfi.r128.LRA=3.270|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.080
+pkt_pts=681600|tag:lavfi.r128.M=-23.339|tag:lavfi.r128.S=-22.830|tag:lavfi.r128.I=-24.397|tag:lavfi.r128.LRA=3.300|tag:lavfi.r128.LRA.low=-26.350|tag:lavfi.r128.LRA.high=-23.050
+pkt_pts=686400|tag:lavfi.r128.M=-23.672|tag:lavfi.r128.S=-22.786|tag:lavfi.r128.I=-24.392|tag:lavfi.r128.LRA=3.330|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-23.010
+pkt_pts=691200|tag:lavfi.r128.M=-23.306|tag:lavfi.r128.S=-22.701|tag:lavfi.r128.I=-24.383|tag:lavfi.r128.LRA=3.330|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-23.010
+pkt_pts=696000|tag:lavfi.r128.M=-23.384|tag:lavfi.r128.S=-22.672|tag:lavfi.r128.I=-24.375|tag:lavfi.r128.LRA=3.410|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.930
+pkt_pts=700800|tag:lavfi.r128.M=-23.531|tag:lavfi.r128.S=-22.637|tag:lavfi.r128.I=-24.369|tag:lavfi.r128.LRA=3.410|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.930
+pkt_pts=705600|tag:lavfi.r128.M=-23.311|tag:lavfi.r128.S=-22.574|tag:lavfi.r128.I=-24.361|tag:lavfi.r128.LRA=3.440|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.900
+pkt_pts=710400|tag:lavfi.r128.M=-23.705|tag:lavfi.r128.S=-22.621|tag:lavfi.r128.I=-24.356|tag:lavfi.r128.LRA=3.500|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.840
+pkt_pts=715200|tag:lavfi.r128.M=-24.104|tag:lavfi.r128.S=-22.740|tag:lavfi.r128.I=-24.354|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=720000|tag:lavfi.r128.M=-24.403|tag:lavfi.r128.S=-22.905|tag:lavfi.r128.I=-24.355|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=724800|tag:lavfi.r128.M=-24.337|tag:lavfi.r128.S=-22.900|tag:lavfi.r128.I=-24.354|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=729600|tag:lavfi.r128.M=-23.538|tag:lavfi.r128.S=-22.846|tag:lavfi.r128.I=-24.348|tag:lavfi.r128.LRA=3.550|tag:lavfi.r128.LRA.low=-26.340|tag:lavfi.r128.LRA.high=-22.790
+pkt_pts=734400|tag:lavfi.r128.M=-22.774|tag:lavfi.r128.S=-22.770|tag:lavfi.r128.I=-24.336|tag:lavfi.r128.LRA=3.560|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.770
+pkt_pts=739200|tag:lavfi.r128.M=-21.589|tag:lavfi.r128.S=-22.628|tag:lavfi.r128.I=-24.311|tag:lavfi.r128.LRA=3.590|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.740
+pkt_pts=744000|tag:lavfi.r128.M=-21.003|tag:lavfi.r128.S=-22.482|tag:lavfi.r128.I=-24.279|tag:lavfi.r128.LRA=3.620|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.710
+pkt_pts=748800|tag:lavfi.r128.M=-21.057|tag:lavfi.r128.S=-22.384|tag:lavfi.r128.I=-24.248|tag:lavfi.r128.LRA=3.650|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.680
+pkt_pts=753600|tag:lavfi.r128.M=-20.378|tag:lavfi.r128.S=-22.196|tag:lavfi.r128.I=-24.208|tag:lavfi.r128.LRA=3.690|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.640
+pkt_pts=758400|tag:lavfi.r128.M=-20.735|tag:lavfi.r128.S=-22.147|tag:lavfi.r128.I=-24.174|tag:lavfi.r128.LRA=3.700|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.630
+pkt_pts=763200|tag:lavfi.r128.M=-21.502|tag:lavfi.r128.S=-22.228|tag:lavfi.r128.I=-24.150|tag:lavfi.r128.LRA=3.700|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.630
+pkt_pts=768000|tag:lavfi.r128.M=-21.158|tag:lavfi.r128.S=-22.211|tag:lavfi.r128.I=-24.123|tag:lavfi.r128.LRA=3.700|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.630
+pkt_pts=772800|tag:lavfi.r128.M=-22.252|tag:lavfi.r128.S=-22.375|tag:lavfi.r128.I=-24.109|tag:lavfi.r128.LRA=3.750|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.580
+pkt_pts=777600|tag:lavfi.r128.M=-22.753|tag:lavfi.r128.S=-22.481|tag:lavfi.r128.I=-24.099|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=782400|tag:lavfi.r128.M=-22.726|tag:lavfi.r128.S=-22.565|tag:lavfi.r128.I=-24.089|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=787200|tag:lavfi.r128.M=-23.676|tag:lavfi.r128.S=-22.655|tag:lavfi.r128.I=-24.086|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=792000|tag:lavfi.r128.M=-23.719|tag:lavfi.r128.S=-22.660|tag:lavfi.r128.I=-24.084|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=796800|tag:lavfi.r128.M=-23.765|tag:lavfi.r128.S=-22.692|tag:lavfi.r128.I=-24.082|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=801600|tag:lavfi.r128.M=-22.760|tag:lavfi.r128.S=-22.624|tag:lavfi.r128.I=-24.073|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=806400|tag:lavfi.r128.M=-21.532|tag:lavfi.r128.S=-22.468|tag:lavfi.r128.I=-24.052|tag:lavfi.r128.LRA=3.840|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.490
+pkt_pts=811200|tag:lavfi.r128.M=-21.329|tag:lavfi.r128.S=-22.455|tag:lavfi.r128.I=-24.029|tag:lavfi.r128.LRA=3.860|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.470
+pkt_pts=816000|tag:lavfi.r128.M=-20.701|tag:lavfi.r128.S=-22.338|tag:lavfi.r128.I=-24.000|tag:lavfi.r128.LRA=3.870|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.460
+pkt_pts=820800|tag:lavfi.r128.M=-20.533|tag:lavfi.r128.S=-22.218|tag:lavfi.r128.I=-23.969|tag:lavfi.r128.LRA=3.940|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.390
+pkt_pts=825600|tag:lavfi.r128.M=-21.049|tag:lavfi.r128.S=-22.151|tag:lavfi.r128.I=-23.944|tag:lavfi.r128.LRA=3.950|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.380
+pkt_pts=830400|tag:lavfi.r128.M=-21.066|tag:lavfi.r128.S=-22.110|tag:lavfi.r128.I=-23.920|tag:lavfi.r128.LRA=3.990|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.340
+pkt_pts=835200|tag:lavfi.r128.M=-20.990|tag:lavfi.r128.S=-22.023|tag:lavfi.r128.I=-23.896|tag:lavfi.r128.LRA=4.100|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.230
+pkt_pts=840000|tag:lavfi.r128.M=-21.658|tag:lavfi.r128.S=-22.007|tag:lavfi.r128.I=-23.879|tag:lavfi.r128.LRA=4.110|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.220
+pkt_pts=844800|tag:lavfi.r128.M=-21.649|tag:lavfi.r128.S=-21.928|tag:lavfi.r128.I=-23.863|tag:lavfi.r128.LRA=4.110|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.220
+pkt_pts=849600|tag:lavfi.r128.M=-22.120|tag:lavfi.r128.S=-21.973|tag:lavfi.r128.I=-23.850|tag:lavfi.r128.LRA=4.130|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.200
+pkt_pts=854400|tag:lavfi.r128.M=-23.297|tag:lavfi.r128.S=-21.984|tag:lavfi.r128.I=-23.847|tag:lavfi.r128.LRA=4.170|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.160
+pkt_pts=859200|tag:lavfi.r128.M=-22.936|tag:lavfi.r128.S=-21.898|tag:lavfi.r128.I=-23.841|tag:lavfi.r128.LRA=4.170|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.160
+pkt_pts=864000|tag:lavfi.r128.M=-22.360|tag:lavfi.r128.S=-21.736|tag:lavfi.r128.I=-23.831|tag:lavfi.r128.LRA=4.180|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.150
+pkt_pts=868800|tag:lavfi.r128.M=-20.997|tag:lavfi.r128.S=-21.601|tag:lavfi.r128.I=-23.809|tag:lavfi.r128.LRA=4.220|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.110
+pkt_pts=873600|tag:lavfi.r128.M=-20.852|tag:lavfi.r128.S=-21.651|tag:lavfi.r128.I=-23.786|tag:lavfi.r128.LRA=4.300|tag:lavfi.r128.LRA.low=-26.330|tag:lavfi.r128.LRA.high=-22.030
+pkt_pts=878400|tag:lavfi.r128.M=-21.194|tag:lavfi.r128.S=-21.695|tag:lavfi.r128.I=-23.766|tag:lavfi.r128.LRA=4.310|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-22.010
+pkt_pts=883200|tag:lavfi.r128.M=-22.598|tag:lavfi.r128.S=-21.862|tag:lavfi.r128.I=-23.759|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=888000|tag:lavfi.r128.M=-24.897|tag:lavfi.r128.S=-22.013|tag:lavfi.r128.I=-23.764|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=892800|tag:lavfi.r128.M=-25.212|tag:lavfi.r128.S=-22.080|tag:lavfi.r128.I=-23.771|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=897600|tag:lavfi.r128.M=-24.334|tag:lavfi.r128.S=-22.191|tag:lavfi.r128.I=-23.774|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=902400|tag:lavfi.r128.M=-22.984|tag:lavfi.r128.S=-22.176|tag:lavfi.r128.I=-23.769|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=907200|tag:lavfi.r128.M=-21.388|tag:lavfi.r128.S=-21.996|tag:lavfi.r128.I=-23.753|tag:lavfi.r128.LRA=4.330|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.990
+pkt_pts=912000|tag:lavfi.r128.M=-20.307|tag:lavfi.r128.S=-21.928|tag:lavfi.r128.I=-23.725|tag:lavfi.r128.LRA=4.340|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.980
+pkt_pts=916800|tag:lavfi.r128.M=-20.094|tag:lavfi.r128.S=-21.838|tag:lavfi.r128.I=-23.695|tag:lavfi.r128.LRA=4.390|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.930
+pkt_pts=921600|tag:lavfi.r128.M=-20.032|tag:lavfi.r128.S=-21.756|tag:lavfi.r128.I=-23.665|tag:lavfi.r128.LRA=4.390|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.930
+pkt_pts=926400|tag:lavfi.r128.M=-20.060|tag:lavfi.r128.S=-21.599|tag:lavfi.r128.I=-23.635|tag:lavfi.r128.LRA=4.420|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.900
+pkt_pts=931200|tag:lavfi.r128.M=-20.372|tag:lavfi.r128.S=-21.507|tag:lavfi.r128.I=-23.610|tag:lavfi.r128.LRA=4.450|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.870
+pkt_pts=936000|tag:lavfi.r128.M=-20.643|tag:lavfi.r128.S=-21.468|tag:lavfi.r128.I=-23.588|tag:lavfi.r128.LRA=4.480|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.840
+pkt_pts=940800|tag:lavfi.r128.M=-20.647|tag:lavfi.r128.S=-21.389|tag:lavfi.r128.I=-23.567|tag:lavfi.r128.LRA=4.560|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.760
+pkt_pts=945600|tag:lavfi.r128.M=-21.341|tag:lavfi.r128.S=-21.431|tag:lavfi.r128.I=-23.552|tag:lavfi.r128.LRA=4.580|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.740
+pkt_pts=950400|tag:lavfi.r128.M=-21.704|tag:lavfi.r128.S=-21.530|tag:lavfi.r128.I=-23.540|tag:lavfi.r128.LRA=4.620|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.700
+pkt_pts=955200|tag:lavfi.r128.M=-21.778|tag:lavfi.r128.S=-21.527|tag:lavfi.r128.I=-23.529|tag:lavfi.r128.LRA=4.620|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.700
+pkt_pts=960000|tag:lavfi.r128.M=-22.390|tag:lavfi.r128.S=-21.613|tag:lavfi.r128.I=-23.523|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=964800|tag:lavfi.r128.M=-22.355|tag:lavfi.r128.S=-21.682|tag:lavfi.r128.I=-23.516|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=969600|tag:lavfi.r128.M=-22.697|tag:lavfi.r128.S=-21.739|tag:lavfi.r128.I=-23.512|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.320|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=974400|tag:lavfi.r128.M=-22.814|tag:lavfi.r128.S=-21.745|tag:lavfi.r128.I=-23.508|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=979200|tag:lavfi.r128.M=-22.749|tag:lavfi.r128.S=-21.842|tag:lavfi.r128.I=-23.504|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=984000|tag:lavfi.r128.M=-23.155|tag:lavfi.r128.S=-21.856|tag:lavfi.r128.I=-23.502|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=988800|tag:lavfi.r128.M=-22.927|tag:lavfi.r128.S=-21.893|tag:lavfi.r128.I=-23.499|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=993600|tag:lavfi.r128.M=-22.583|tag:lavfi.r128.S=-21.800|tag:lavfi.r128.I=-23.494|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=998400|tag:lavfi.r128.M=-22.022|tag:lavfi.r128.S=-21.702|tag:lavfi.r128.I=-23.486|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1003200|tag:lavfi.r128.M=-21.852|tag:lavfi.r128.S=-21.729|tag:lavfi.r128.I=-23.476|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1008000|tag:lavfi.r128.M=-21.746|tag:lavfi.r128.S=-21.814|tag:lavfi.r128.I=-23.466|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1012800|tag:lavfi.r128.M=-21.751|tag:lavfi.r128.S=-21.912|tag:lavfi.r128.I=-23.456|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1017600|tag:lavfi.r128.M=-21.891|tag:lavfi.r128.S=-21.855|tag:lavfi.r128.I=-23.447|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.310|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1022400|tag:lavfi.r128.M=-21.392|tag:lavfi.r128.S=-21.759|tag:lavfi.r128.I=-23.435|tag:lavfi.r128.LRA=4.640|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1027200|tag:lavfi.r128.M=-21.375|tag:lavfi.r128.S=-21.660|tag:lavfi.r128.I=-23.422|tag:lavfi.r128.LRA=4.640|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.660
+pkt_pts=1032000|tag:lavfi.r128.M=-21.806|tag:lavfi.r128.S=-21.620|tag:lavfi.r128.I=-23.413|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1036800|tag:lavfi.r128.M=-21.826|tag:lavfi.r128.S=-21.550|tag:lavfi.r128.I=-23.404|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1041600|tag:lavfi.r128.M=-22.447|tag:lavfi.r128.S=-21.588|tag:lavfi.r128.I=-23.399|tag:lavfi.r128.LRA=4.690|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.610
+pkt_pts=1046400|tag:lavfi.r128.M=-22.717|tag:lavfi.r128.S=-21.633|tag:lavfi.r128.I=-23.396|tag:lavfi.r128.LRA=4.690|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.610
+pkt_pts=1051200|tag:lavfi.r128.M=-23.325|tag:lavfi.r128.S=-21.845|tag:lavfi.r128.I=-23.396|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1056000|tag:lavfi.r128.M=-23.105|tag:lavfi.r128.S=-21.933|tag:lavfi.r128.I=-23.394|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1060800|tag:lavfi.r128.M=-23.086|tag:lavfi.r128.S=-22.015|tag:lavfi.r128.I=-23.393|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1065600|tag:lavfi.r128.M=-22.412|tag:lavfi.r128.S=-22.001|tag:lavfi.r128.I=-23.388|tag:lavfi.r128.LRA=4.680|tag:lavfi.r128.LRA.low=-26.300|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1070400|tag:lavfi.r128.M=-20.845|tag:lavfi.r128.S=-21.992|tag:lavfi.r128.I=-23.372|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1075200|tag:lavfi.r128.M=-20.738|tag:lavfi.r128.S=-22.001|tag:lavfi.r128.I=-23.356|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1080000|tag:lavfi.r128.M=-20.165|tag:lavfi.r128.S=-21.924|tag:lavfi.r128.I=-23.335|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1084800|tag:lavfi.r128.M=-19.829|tag:lavfi.r128.S=-21.840|tag:lavfi.r128.I=-23.311|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1089600|tag:lavfi.r128.M=-20.699|tag:lavfi.r128.S=-21.887|tag:lavfi.r128.I=-23.295|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1094400|tag:lavfi.r128.M=-20.677|tag:lavfi.r128.S=-21.838|tag:lavfi.r128.I=-23.279|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1099200|tag:lavfi.r128.M=-20.121|tag:lavfi.r128.S=-21.654|tag:lavfi.r128.I=-23.259|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1104000|tag:lavfi.r128.M=-20.893|tag:lavfi.r128.S=-21.635|tag:lavfi.r128.I=-23.245|tag:lavfi.r128.LRA=4.650|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.620
+pkt_pts=1108800|tag:lavfi.r128.M=-19.603|tag:lavfi.r128.S=-21.450|tag:lavfi.r128.I=-23.220|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.610
+pkt_pts=1113600|tag:lavfi.r128.M=-19.675|tag:lavfi.r128.S=-21.385|tag:lavfi.r128.I=-23.197|tag:lavfi.r128.LRA=4.670|tag:lavfi.r128.LRA.low=-26.270|tag:lavfi.r128.LRA.high=-21.600
+pkt_pts=1118400|tag:lavfi.r128.M=-20.415|tag:lavfi.r128.S=-21.339|tag:lavfi.r128.I=-23.180|tag:lavfi.r128.LRA=4.660|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.590
+pkt_pts=1123200|tag:lavfi.r128.M=-20.446|tag:lavfi.r128.S=-21.333|tag:lavfi.r128.I=-23.164|tag:lavfi.r128.LRA=4.690|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.560
+pkt_pts=1128000|tag:lavfi.r128.M=-21.361|tag:lavfi.r128.S=-21.254|tag:lavfi.r128.I=-23.154|tag:lavfi.r128.LRA=4.720|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.530
+pkt_pts=1132800|tag:lavfi.r128.M=-21.725|tag:lavfi.r128.S=-21.257|tag:lavfi.r128.I=-23.147|tag:lavfi.r128.LRA=4.720|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.530
+pkt_pts=1137600|tag:lavfi.r128.M=-22.311|tag:lavfi.r128.S=-21.311|tag:lavfi.r128.I=-23.143|tag:lavfi.r128.LRA=4.740|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.510
+pkt_pts=1142400|tag:lavfi.r128.M=-21.973|tag:lavfi.r128.S=-21.327|tag:lavfi.r128.I=-23.137|tag:lavfi.r128.LRA=4.780|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.470
+pkt_pts=1147200|tag:lavfi.r128.M=-22.032|tag:lavfi.r128.S=-21.275|tag:lavfi.r128.I=-23.132|tag:lavfi.r128.LRA=4.780|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.470
+pkt_pts=1152000|tag:lavfi.r128.M=-21.631|tag:lavfi.r128.S=-21.243|tag:lavfi.r128.I=-23.125|tag:lavfi.r128.LRA=4.800|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.450
+pkt_pts=1156800|tag:lavfi.r128.M=-20.494|tag:lavfi.r128.S=-21.139|tag:lavfi.r128.I=-23.110|tag:lavfi.r128.LRA=4.810|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.440
+pkt_pts=1161600|tag:lavfi.r128.M=-19.902|tag:lavfi.r128.S=-21.041|tag:lavfi.r128.I=-23.090|tag:lavfi.r128.LRA=4.860|tag:lavfi.r128.LRA.low=-26.250|tag:lavfi.r128.LRA.high=-21.390
+pkt_pts=1166400|tag:lavfi.r128.M=-20.221|tag:lavfi.r128.S=-21.104|tag:lavfi.r128.I=-23.073|tag:lavfi.r128.LRA=4.850|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.390
+pkt_pts=1171200|tag:lavfi.r128.M=-20.245|tag:lavfi.r128.S=-21.080|tag:lavfi.r128.I=-23.057|tag:lavfi.r128.LRA=4.900|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.340
+pkt_pts=1176000|tag:lavfi.r128.M=-21.470|tag:lavfi.r128.S=-21.099|tag:lavfi.r128.I=-23.049|tag:lavfi.r128.LRA=4.900|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.340
+pkt_pts=1180800|tag:lavfi.r128.M=-22.623|tag:lavfi.r128.S=-21.123|tag:lavfi.r128.I=-23.047|tag:lavfi.r128.LRA=4.910|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.330
+pkt_pts=1185600|tag:lavfi.r128.M=-22.312|tag:lavfi.r128.S=-21.090|tag:lavfi.r128.I=-23.044|tag:lavfi.r128.LRA=4.920|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.320
+pkt_pts=1190400|tag:lavfi.r128.M=-22.937|tag:lavfi.r128.S=-21.099|tag:lavfi.r128.I=-23.043|tag:lavfi.r128.LRA=4.960|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.280
+pkt_pts=1195200|tag:lavfi.r128.M=-22.401|tag:lavfi.r128.S=-21.017|tag:lavfi.r128.I=-23.041|tag:lavfi.r128.LRA=4.980|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.260
+pkt_pts=1200000|tag:lavfi.r128.M=-22.004|tag:lavfi.r128.S=-21.018|tag:lavfi.r128.I=-23.036|tag:lavfi.r128.LRA=4.980|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.260
+pkt_pts=1204800|tag:lavfi.r128.M=-22.416|tag:lavfi.r128.S=-21.030|tag:lavfi.r128.I=-23.033|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1209600|tag:lavfi.r128.M=-22.481|tag:lavfi.r128.S=-21.106|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1214400|tag:lavfi.r128.M=-22.841|tag:lavfi.r128.S=-21.245|tag:lavfi.r128.I=-23.030|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1219200|tag:lavfi.r128.M=-23.663|tag:lavfi.r128.S=-21.332|tag:lavfi.r128.I=-23.033|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1224000|tag:lavfi.r128.M=-22.728|tag:lavfi.r128.S=-21.357|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1228800|tag:lavfi.r128.M=-23.016|tag:lavfi.r128.S=-21.530|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1233600|tag:lavfi.r128.M=-22.934|tag:lavfi.r128.S=-21.518|tag:lavfi.r128.I=-23.031|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1238400|tag:lavfi.r128.M=-21.320|tag:lavfi.r128.S=-21.426|tag:lavfi.r128.I=-23.023|tag:lavfi.r128.LRA=5.100|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.140
+pkt_pts=1243200|tag:lavfi.r128.M=-21.282|tag:lavfi.r128.S=-21.541|tag:lavfi.r128.I=-23.015|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1248000|tag:lavfi.r128.M=-20.639|tag:lavfi.r128.S=-21.490|tag:lavfi.r128.I=-23.002|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1252800|tag:lavfi.r128.M=-20.626|tag:lavfi.r128.S=-21.711|tag:lavfi.r128.I=-22.990|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1257600|tag:lavfi.r128.M=-21.333|tag:lavfi.r128.S=-21.710|tag:lavfi.r128.I=-22.982|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1262400|tag:lavfi.r128.M=-21.384|tag:lavfi.r128.S=-21.694|tag:lavfi.r128.I=-22.975|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1267200|tag:lavfi.r128.M=-21.410|tag:lavfi.r128.S=-21.639|tag:lavfi.r128.I=-22.968|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1272000|tag:lavfi.r128.M=-21.461|tag:lavfi.r128.S=-21.725|tag:lavfi.r128.I=-22.961|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1276800|tag:lavfi.r128.M=-21.846|tag:lavfi.r128.S=-21.726|tag:lavfi.r128.I=-22.956|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1281600|tag:lavfi.r128.M=-22.482|tag:lavfi.r128.S=-21.713|tag:lavfi.r128.I=-22.954|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1286400|tag:lavfi.r128.M=-22.681|tag:lavfi.r128.S=-21.720|tag:lavfi.r128.I=-22.953|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1291200|tag:lavfi.r128.M=-22.718|tag:lavfi.r128.S=-21.804|tag:lavfi.r128.I=-22.952|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1296000|tag:lavfi.r128.M=-22.849|tag:lavfi.r128.S=-21.873|tag:lavfi.r128.I=-22.952|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1300800|tag:lavfi.r128.M=-23.041|tag:lavfi.r128.S=-22.068|tag:lavfi.r128.I=-22.952|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1305600|tag:lavfi.r128.M=-23.898|tag:lavfi.r128.S=-22.285|tag:lavfi.r128.I=-22.956|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1310400|tag:lavfi.r128.M=-24.280|tag:lavfi.r128.S=-22.343|tag:lavfi.r128.I=-22.960|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1315200|tag:lavfi.r128.M=-25.072|tag:lavfi.r128.S=-22.479|tag:lavfi.r128.I=-22.966|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1320000|tag:lavfi.r128.M=-25.530|tag:lavfi.r128.S=-22.491|tag:lavfi.r128.I=-22.973|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1324800|tag:lavfi.r128.M=-25.269|tag:lavfi.r128.S=-22.536|tag:lavfi.r128.I=-22.980|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1329600|tag:lavfi.r128.M=-25.127|tag:lavfi.r128.S=-22.630|tag:lavfi.r128.I=-22.986|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1334400|tag:lavfi.r128.M=-24.909|tag:lavfi.r128.S=-22.673|tag:lavfi.r128.I=-22.991|tag:lavfi.r128.LRA=4.990|tag:lavfi.r128.LRA.low=-26.240|tag:lavfi.r128.LRA.high=-21.250
+pkt_pts=1339200
diff --git a/tests/ref/fate/filter-metadata-scenedetect b/tests/ref/fate/filter-metadata-scenedetect
new file mode 100644
index 0000000000..d04054a951
--- /dev/null
+++ b/tests/ref/fate/filter-metadata-scenedetect
@@ -0,0 +1,10 @@
+pkt_pts=1620|tag:lavfi.scene_score=1.000000
+pkt_pts=4140|tag:lavfi.scene_score=0.875036
+pkt_pts=5800|tag:lavfi.scene_score=1.000000
+pkt_pts=6720|tag:lavfi.scene_score=0.461625
+pkt_pts=8160|tag:lavfi.scene_score=1.000000
+pkt_pts=9760|tag:lavfi.scene_score=1.000000
+pkt_pts=14080|tag:lavfi.scene_score=0.838916
+pkt_pts=15700|tag:lavfi.scene_score=1.000000
+pkt_pts=18500|tag:lavfi.scene_score=0.474948
+pkt_pts=21760|tag:lavfi.scene_score=1.000000
diff --git a/tests/ref/fate/filter-metadata-silencedetect b/tests/ref/fate/filter-metadata-silencedetect
new file mode 100644
index 0000000000..4161287e6c
--- /dev/null
+++ b/tests/ref/fate/filter-metadata-silencedetect
@@ -0,0 +1,512 @@
+pkt_pts=0
+pkt_pts=320
+pkt_pts=640
+pkt_pts=960
+pkt_pts=1280
+pkt_pts=1600
+pkt_pts=1920|tag:lavfi.silence_start=0.02
+pkt_pts=2240
+pkt_pts=2560|tag:lavfi.silence_end=0.16|tag:lavfi.silence_duration=0.14
+pkt_pts=2880
+pkt_pts=3200
+pkt_pts=3520
+pkt_pts=3840
+pkt_pts=4160
+pkt_pts=4480
+pkt_pts=4800
+pkt_pts=5120
+pkt_pts=5440
+pkt_pts=5760|tag:lavfi.silence_start=0.26|tag:lavfi.silence_end=0.36|tag:lavfi.silence_duration=0.1
+pkt_pts=6080
+pkt_pts=6400
+pkt_pts=6720
+pkt_pts=7040
+pkt_pts=7360
+pkt_pts=7680
+pkt_pts=8000
+pkt_pts=8320
+pkt_pts=8640
+pkt_pts=8960
+pkt_pts=9280
+pkt_pts=9600
+pkt_pts=9920
+pkt_pts=10240
+pkt_pts=10560
+pkt_pts=10880
+pkt_pts=11200
+pkt_pts=11520
+pkt_pts=11840
+pkt_pts=12160
+pkt_pts=12480
+pkt_pts=12800
+pkt_pts=13120
+pkt_pts=13440
+pkt_pts=13760
+pkt_pts=14080
+pkt_pts=14400
+pkt_pts=14720
+pkt_pts=15040
+pkt_pts=15360
+pkt_pts=15680
+pkt_pts=16000
+pkt_pts=16320
+pkt_pts=16640
+pkt_pts=16960
+pkt_pts=17280
+pkt_pts=17600
+pkt_pts=17920
+pkt_pts=18240
+pkt_pts=18560
+pkt_pts=18880
+pkt_pts=19200
+pkt_pts=19520
+pkt_pts=19840
+pkt_pts=20160
+pkt_pts=20480
+pkt_pts=20800
+pkt_pts=21120
+pkt_pts=21440
+pkt_pts=21760
+pkt_pts=22080|tag:lavfi.silence_start=1.28
+pkt_pts=22400
+pkt_pts=22720
+pkt_pts=23040
+pkt_pts=23360
+pkt_pts=23680
+pkt_pts=24000
+pkt_pts=24320
+pkt_pts=24640
+pkt_pts=24960
+pkt_pts=25280
+pkt_pts=25600
+pkt_pts=25920
+pkt_pts=26240
+pkt_pts=26560
+pkt_pts=26880
+pkt_pts=27200
+pkt_pts=27520
+pkt_pts=27840
+pkt_pts=28160
+pkt_pts=28480
+pkt_pts=28800
+pkt_pts=29120
+pkt_pts=29440
+pkt_pts=29760
+pkt_pts=30080
+pkt_pts=30400
+pkt_pts=30720
+pkt_pts=31040
+pkt_pts=31360
+pkt_pts=31680|tag:lavfi.silence_end=1.98|tag:lavfi.silence_duration=0.7
+pkt_pts=32000
+pkt_pts=32320
+pkt_pts=32640
+pkt_pts=32960
+pkt_pts=33280
+pkt_pts=33600
+pkt_pts=33920
+pkt_pts=34240
+pkt_pts=34560
+pkt_pts=34880
+pkt_pts=35200
+pkt_pts=35520
+pkt_pts=35840
+pkt_pts=36160
+pkt_pts=36480
+pkt_pts=36800
+pkt_pts=37120
+pkt_pts=37440
+pkt_pts=37760
+pkt_pts=38080
+pkt_pts=38400
+pkt_pts=38720
+pkt_pts=39040
+pkt_pts=39360
+pkt_pts=39680
+pkt_pts=40000
+pkt_pts=40320
+pkt_pts=40640
+pkt_pts=40960
+pkt_pts=41280
+pkt_pts=41600
+pkt_pts=41920
+pkt_pts=42240
+pkt_pts=42560
+pkt_pts=42880
+pkt_pts=43200
+pkt_pts=43520
+pkt_pts=43840
+pkt_pts=44160
+pkt_pts=44480
+pkt_pts=44800
+pkt_pts=45120
+pkt_pts=45440
+pkt_pts=45760
+pkt_pts=46080
+pkt_pts=46400
+pkt_pts=46720
+pkt_pts=47040
+pkt_pts=47360
+pkt_pts=47680
+pkt_pts=48000
+pkt_pts=48320
+pkt_pts=48640
+pkt_pts=48960
+pkt_pts=49280
+pkt_pts=49600
+pkt_pts=49920
+pkt_pts=50240
+pkt_pts=50560
+pkt_pts=50880
+pkt_pts=51200
+pkt_pts=51520
+pkt_pts=51840
+pkt_pts=52160
+pkt_pts=52480
+pkt_pts=52800|tag:lavfi.silence_start=3.2
+pkt_pts=53120
+pkt_pts=53440
+pkt_pts=53760
+pkt_pts=54080
+pkt_pts=54400
+pkt_pts=54720
+pkt_pts=55040
+pkt_pts=55360
+pkt_pts=55680
+pkt_pts=56000
+pkt_pts=56320
+pkt_pts=56640
+pkt_pts=56960
+pkt_pts=57280
+pkt_pts=57600
+pkt_pts=57920
+pkt_pts=58240
+pkt_pts=58560
+pkt_pts=58880
+pkt_pts=59200
+pkt_pts=59520
+pkt_pts=59840
+pkt_pts=60160
+pkt_pts=60480
+pkt_pts=60800
+pkt_pts=61120
+pkt_pts=61440
+pkt_pts=61760
+pkt_pts=62080
+pkt_pts=62400|tag:lavfi.silence_end=3.9|tag:lavfi.silence_duration=0.7
+pkt_pts=62720
+pkt_pts=63040
+pkt_pts=63360
+pkt_pts=63680
+pkt_pts=64000
+pkt_pts=64320
+pkt_pts=64640
+pkt_pts=64960
+pkt_pts=65280
+pkt_pts=65600
+pkt_pts=65920
+pkt_pts=66240
+pkt_pts=66560
+pkt_pts=66880
+pkt_pts=67200
+pkt_pts=67520
+pkt_pts=67840
+pkt_pts=68160
+pkt_pts=68480
+pkt_pts=68800
+pkt_pts=69120
+pkt_pts=69440
+pkt_pts=69760
+pkt_pts=70080
+pkt_pts=70400
+pkt_pts=70720
+pkt_pts=71040
+pkt_pts=71360
+pkt_pts=71680
+pkt_pts=72000
+pkt_pts=72320
+pkt_pts=72640
+pkt_pts=72960
+pkt_pts=73280
+pkt_pts=73600
+pkt_pts=73920
+pkt_pts=74240
+pkt_pts=74560
+pkt_pts=74880
+pkt_pts=75200
+pkt_pts=75520
+pkt_pts=75840
+pkt_pts=76160
+pkt_pts=76480
+pkt_pts=76800
+pkt_pts=77120
+pkt_pts=77440
+pkt_pts=77760
+pkt_pts=78080
+pkt_pts=78400
+pkt_pts=78720
+pkt_pts=79040
+pkt_pts=79360
+pkt_pts=79680
+pkt_pts=80000|tag:lavfi.silence_start=4.9
+pkt_pts=80320
+pkt_pts=80640
+pkt_pts=80960
+pkt_pts=81280
+pkt_pts=81600
+pkt_pts=81920
+pkt_pts=82240
+pkt_pts=82560
+pkt_pts=82880
+pkt_pts=83200
+pkt_pts=83520
+pkt_pts=83840
+pkt_pts=84160
+pkt_pts=84480
+pkt_pts=84800
+pkt_pts=85120
+pkt_pts=85440
+pkt_pts=85760
+pkt_pts=86080
+pkt_pts=86400
+pkt_pts=86720
+pkt_pts=87040|tag:lavfi.silence_end=5.44|tag:lavfi.silence_duration=0.54
+pkt_pts=87360
+pkt_pts=87680
+pkt_pts=88000
+pkt_pts=88320
+pkt_pts=88640
+pkt_pts=88960
+pkt_pts=89280
+pkt_pts=89600
+pkt_pts=89920
+pkt_pts=90240
+pkt_pts=90560
+pkt_pts=90880
+pkt_pts=91200
+pkt_pts=91520
+pkt_pts=91840
+pkt_pts=92160
+pkt_pts=92480
+pkt_pts=92800
+pkt_pts=93120
+pkt_pts=93440
+pkt_pts=93760
+pkt_pts=94080
+pkt_pts=94400
+pkt_pts=94720
+pkt_pts=95040
+pkt_pts=95360
+pkt_pts=95680
+pkt_pts=96000
+pkt_pts=96320
+pkt_pts=96640
+pkt_pts=96960
+pkt_pts=97280
+pkt_pts=97600
+pkt_pts=97920
+pkt_pts=98240
+pkt_pts=98560
+pkt_pts=98880
+pkt_pts=99200
+pkt_pts=99520
+pkt_pts=99840
+pkt_pts=100160
+pkt_pts=100480
+pkt_pts=100800
+pkt_pts=101120
+pkt_pts=101440
+pkt_pts=101760
+pkt_pts=102080
+pkt_pts=102400
+pkt_pts=102720
+pkt_pts=103040
+pkt_pts=103360
+pkt_pts=103680
+pkt_pts=104000
+pkt_pts=104320
+pkt_pts=104640|tag:lavfi.silence_start=6.44
+pkt_pts=104960
+pkt_pts=105280
+pkt_pts=105600
+pkt_pts=105920
+pkt_pts=106240
+pkt_pts=106560
+pkt_pts=106880
+pkt_pts=107200
+pkt_pts=107520
+pkt_pts=107840
+pkt_pts=108160
+pkt_pts=108480
+pkt_pts=108800
+pkt_pts=109120
+pkt_pts=109440
+pkt_pts=109760
+pkt_pts=110080
+pkt_pts=110400
+pkt_pts=110720
+pkt_pts=111040
+pkt_pts=111360
+pkt_pts=111680
+pkt_pts=112000
+pkt_pts=112320
+pkt_pts=112640
+pkt_pts=112960
+pkt_pts=113280
+pkt_pts=113600
+pkt_pts=113920
+pkt_pts=114240
+pkt_pts=114560
+pkt_pts=114880
+pkt_pts=115200
+pkt_pts=115520
+pkt_pts=115840
+pkt_pts=116160|tag:lavfi.silence_end=7.26|tag:lavfi.silence_duration=0.82
+pkt_pts=116480
+pkt_pts=116800
+pkt_pts=117120
+pkt_pts=117440
+pkt_pts=117760
+pkt_pts=118080
+pkt_pts=118400
+pkt_pts=118720
+pkt_pts=119040
+pkt_pts=119360
+pkt_pts=119680
+pkt_pts=120000
+pkt_pts=120320
+pkt_pts=120640
+pkt_pts=120960
+pkt_pts=121280
+pkt_pts=121600
+pkt_pts=121920
+pkt_pts=122240
+pkt_pts=122560
+pkt_pts=122880
+pkt_pts=123200
+pkt_pts=123520
+pkt_pts=123840
+pkt_pts=124160
+pkt_pts=124480
+pkt_pts=124800
+pkt_pts=125120
+pkt_pts=125440
+pkt_pts=125760
+pkt_pts=126080
+pkt_pts=126400
+pkt_pts=126720
+pkt_pts=127040
+pkt_pts=127360
+pkt_pts=127680
+pkt_pts=128000
+pkt_pts=128320
+pkt_pts=128640
+pkt_pts=128960
+pkt_pts=129280
+pkt_pts=129600
+pkt_pts=129920
+pkt_pts=130240
+pkt_pts=130560
+pkt_pts=130880
+pkt_pts=131200
+pkt_pts=131520
+pkt_pts=131840
+pkt_pts=132160
+pkt_pts=132480
+pkt_pts=132800
+pkt_pts=133120
+pkt_pts=133440
+pkt_pts=133760
+pkt_pts=134080
+pkt_pts=134400
+pkt_pts=134720
+pkt_pts=135040
+pkt_pts=135360
+pkt_pts=135680
+pkt_pts=136000
+pkt_pts=136320
+pkt_pts=136640
+pkt_pts=136960
+pkt_pts=137280
+pkt_pts=137600|tag:lavfi.silence_start=8.5
+pkt_pts=137920
+pkt_pts=138240
+pkt_pts=138560
+pkt_pts=138880|tag:lavfi.silence_end=8.68|tag:lavfi.silence_duration=0.18
+pkt_pts=139200
+pkt_pts=139520
+pkt_pts=139840
+pkt_pts=140160
+pkt_pts=140480|tag:lavfi.silence_start=8.68
+pkt_pts=140800
+pkt_pts=141120
+pkt_pts=141440
+pkt_pts=141760
+pkt_pts=142080
+pkt_pts=142400
+pkt_pts=142720
+pkt_pts=143040
+pkt_pts=143360
+pkt_pts=143680|tag:lavfi.silence_end=8.98|tag:lavfi.silence_duration=0.3
+pkt_pts=144000
+pkt_pts=144320
+pkt_pts=144640
+pkt_pts=144960
+pkt_pts=145280
+pkt_pts=145600
+pkt_pts=145920
+pkt_pts=146240
+pkt_pts=146560
+pkt_pts=146880
+pkt_pts=147200
+pkt_pts=147520
+pkt_pts=147840
+pkt_pts=148160
+pkt_pts=148480
+pkt_pts=148800
+pkt_pts=149120
+pkt_pts=149440
+pkt_pts=149760
+pkt_pts=150080
+pkt_pts=150400
+pkt_pts=150720
+pkt_pts=151040
+pkt_pts=151360
+pkt_pts=151680
+pkt_pts=152000
+pkt_pts=152320
+pkt_pts=152640
+pkt_pts=152960
+pkt_pts=153280
+pkt_pts=153600
+pkt_pts=153920
+pkt_pts=154240
+pkt_pts=154560
+pkt_pts=154880
+pkt_pts=155200
+pkt_pts=155520
+pkt_pts=155840
+pkt_pts=156160
+pkt_pts=156480
+pkt_pts=156800
+pkt_pts=157120
+pkt_pts=157440
+pkt_pts=157760
+pkt_pts=158080
+pkt_pts=158400
+pkt_pts=158720
+pkt_pts=159040
+pkt_pts=159360
+pkt_pts=159680
+pkt_pts=160000
+pkt_pts=160320
+pkt_pts=160640
+pkt_pts=160960
+pkt_pts=161280
+pkt_pts=161600|tag:lavfi.silence_start=10
+pkt_pts=161920
+pkt_pts=162240
+pkt_pts=162560
+pkt_pts=162880
+pkt_pts=163200
+pkt_pts=163520
diff --git a/tests/ref/fate/filter-null b/tests/ref/fate/filter-null
index 3a1d0c1824..034ee8db20 100644
--- a/tests/ref/fate/filter-null
+++ b/tests/ref/fate/filter-null
@@ -1 +1 @@
-null 7aaf1057c0edf7d5e9700f9c8e510ea9
+null fcb007249fba9371fe84a61c974fcb00
diff --git a/tests/ref/fate/filter-overlay b/tests/ref/fate/filter-overlay
index d988a2e4e1..f0f03d6ec7 100644
--- a/tests/ref/fate/filter-overlay
+++ b/tests/ref/fate/filter-overlay
@@ -1,51 +1,51 @@
#tb 0: 1/25
-0, 0, 0, 1, 152064, 0xf6f773b6
-0, 1, 1, 1, 152064, 0x8e67618e
-0, 2, 2, 1, 152064, 0xc8eff2ef
-0, 3, 3, 1, 152064, 0xcf39936c
-0, 4, 4, 1, 152064, 0xaf18c4d1
-0, 5, 5, 1, 152064, 0x7e69911e
-0, 6, 6, 1, 152064, 0x1b70214f
-0, 7, 7, 1, 152064, 0xc8032176
-0, 8, 8, 1, 152064, 0xefb42ecc
-0, 9, 9, 1, 152064, 0xfb210e4b
-0, 10, 10, 1, 152064, 0x2ee24b11
-0, 11, 11, 1, 152064, 0x0dac02a5
-0, 12, 12, 1, 152064, 0x9a5ce483
-0, 13, 13, 1, 152064, 0x6bb7c758
-0, 14, 14, 1, 152064, 0xcbb545e5
-0, 15, 15, 1, 152064, 0x81c1b339
-0, 16, 16, 1, 152064, 0xfa38d624
-0, 17, 17, 1, 152064, 0x56c5e63e
-0, 18, 18, 1, 152064, 0x419d194d
-0, 19, 19, 1, 152064, 0xed1a92b8
-0, 20, 20, 1, 152064, 0xd2c0aa39
-0, 21, 21, 1, 152064, 0x6214ddd5
-0, 22, 22, 1, 152064, 0xa978e19f
-0, 23, 23, 1, 152064, 0x676422a2
-0, 24, 24, 1, 152064, 0x5213dd62
-0, 25, 25, 1, 152064, 0x13c1a404
-0, 26, 26, 1, 152064, 0xa543a1a2
-0, 27, 27, 1, 152064, 0x8d0d0bed
-0, 28, 28, 1, 152064, 0x000304cf
-0, 29, 29, 1, 152064, 0x7f75b0ab
-0, 30, 30, 1, 152064, 0x68d07ce6
-0, 31, 31, 1, 152064, 0xb88c9852
-0, 32, 32, 1, 152064, 0x4be5ae13
-0, 33, 33, 1, 152064, 0x85b3f7b1
-0, 34, 34, 1, 152064, 0x9facb7d5
-0, 35, 35, 1, 152064, 0x9f11617e
-0, 36, 36, 1, 152064, 0x43393f46
-0, 37, 37, 1, 152064, 0xd45c3b92
-0, 38, 38, 1, 152064, 0x53de7e1b
-0, 39, 39, 1, 152064, 0xd1c685a7
-0, 40, 40, 1, 152064, 0x21e1778f
-0, 41, 41, 1, 152064, 0xe2b1abe1
-0, 42, 42, 1, 152064, 0x8623b5aa
-0, 43, 43, 1, 152064, 0xfc700aa3
-0, 44, 44, 1, 152064, 0x30a2d120
-0, 45, 45, 1, 152064, 0xa35e4d15
-0, 46, 46, 1, 152064, 0xa3fb11c5
-0, 47, 47, 1, 152064, 0x034f8fb7
-0, 48, 48, 1, 152064, 0x921c7d85
-0, 49, 49, 1, 152064, 0x7a94b9bf
+0, 0, 0, 1, 152064, 0x2b1a7a92
+0, 1, 1, 1, 152064, 0x6f28685a
+0, 2, 2, 1, 152064, 0xeac9f99c
+0, 3, 3, 1, 152064, 0x3a059a74
+0, 4, 4, 1, 152064, 0xb53ecbf0
+0, 5, 5, 1, 152064, 0x288c9843
+0, 6, 6, 1, 152064, 0x927a293b
+0, 7, 7, 1, 152064, 0x85f72884
+0, 8, 8, 1, 152064, 0x42c234b9
+0, 9, 9, 1, 152064, 0x36c2152f
+0, 10, 10, 1, 152064, 0x903b529a
+0, 11, 11, 1, 152064, 0x29ce0a02
+0, 12, 12, 1, 152064, 0x3683ebce
+0, 13, 13, 1, 152064, 0xfb88cdab
+0, 14, 14, 1, 152064, 0x3a6a4c7c
+0, 15, 15, 1, 152064, 0x8d81ba4a
+0, 16, 16, 1, 152064, 0x982cdddb
+0, 17, 17, 1, 152064, 0x9554ee2f
+0, 18, 18, 1, 152064, 0x1e61219d
+0, 19, 19, 1, 152064, 0xfcfe9b00
+0, 20, 20, 1, 152064, 0x891fb285
+0, 21, 21, 1, 152064, 0x4401e619
+0, 22, 22, 1, 152064, 0x57beea17
+0, 23, 23, 1, 152064, 0x94102ade
+0, 24, 24, 1, 152064, 0x5240e58d
+0, 25, 25, 1, 152064, 0x3783abba
+0, 26, 26, 1, 152064, 0x2570a936
+0, 27, 27, 1, 152064, 0x53071378
+0, 28, 28, 1, 152064, 0x3cda0c41
+0, 29, 29, 1, 152064, 0x3a8cb83d
+0, 30, 30, 1, 152064, 0x5fc0840b
+0, 31, 31, 1, 152064, 0x32519f3d
+0, 32, 32, 1, 152064, 0xac56b3f7
+0, 33, 33, 1, 152064, 0xe36dfece
+0, 34, 34, 1, 152064, 0xb663bfbd
+0, 35, 35, 1, 152064, 0xafdf691c
+0, 36, 36, 1, 152064, 0x31bd4631
+0, 37, 37, 1, 152064, 0xac7a421a
+0, 38, 38, 1, 152064, 0x05f7856d
+0, 39, 39, 1, 152064, 0xec3a8ccf
+0, 40, 40, 1, 152064, 0x9e7a7efb
+0, 41, 41, 1, 152064, 0x9747b314
+0, 42, 42, 1, 152064, 0x1ba4bcc0
+0, 43, 43, 1, 152064, 0x90e31197
+0, 44, 44, 1, 152064, 0x98f5d7cd
+0, 45, 45, 1, 152064, 0x763053cb
+0, 46, 46, 1, 152064, 0x4fb8183e
+0, 47, 47, 1, 152064, 0xf27596ad
+0, 48, 48, 1, 152064, 0x4c6a843a
+0, 49, 49, 1, 152064, 0x7ff3c070
diff --git a/tests/ref/fate/filter-overlay_rgb b/tests/ref/fate/filter-overlay_rgb
new file mode 100644
index 0000000000..cb94aa52db
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_rgb
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 304128, 0x027e34c6
+0, 1, 1, 1, 304128, 0xc436b3d2
+0, 2, 2, 1, 304128, 0x86b77f58
+0, 3, 3, 1, 304128, 0x94e279e1
+0, 4, 4, 1, 304128, 0x658da060
+0, 5, 5, 1, 304128, 0x2005ffb7
+0, 6, 6, 1, 304128, 0x4730c6b1
+0, 7, 7, 1, 304128, 0x9e29fbca
+0, 8, 8, 1, 304128, 0xfcbe105a
+0, 9, 9, 1, 304128, 0x96b6af91
+0, 10, 10, 1, 304128, 0xe1a4ecd5
+0, 11, 11, 1, 304128, 0x53f42f84
+0, 12, 12, 1, 304128, 0xa5221a14
+0, 13, 13, 1, 304128, 0xaf7d2ab4
+0, 14, 14, 1, 304128, 0x1bc8208f
+0, 15, 15, 1, 304128, 0x5e090d01
+0, 16, 16, 1, 304128, 0xf01de68a
+0, 17, 17, 1, 304128, 0x33ad5467
+0, 18, 18, 1, 304128, 0x3b37d722
+0, 19, 19, 1, 304128, 0x410f0872
+0, 20, 20, 1, 304128, 0xc110db2a
+0, 21, 21, 1, 304128, 0x2023e6e2
+0, 22, 22, 1, 304128, 0xf63fa6fc
+0, 23, 23, 1, 304128, 0x25f10ab0
+0, 24, 24, 1, 304128, 0x0efe0a9b
+0, 25, 25, 1, 304128, 0x5779e963
+0, 26, 26, 1, 304128, 0xa43226da
+0, 27, 27, 1, 304128, 0xc6d4e99d
+0, 28, 28, 1, 304128, 0x39c5e32d
+0, 29, 29, 1, 304128, 0x78dd509b
+0, 30, 30, 1, 304128, 0x496f07af
+0, 31, 31, 1, 304128, 0xb878805c
+0, 32, 32, 1, 304128, 0xc62e4825
+0, 33, 33, 1, 304128, 0x8e7a2787
+0, 34, 34, 1, 304128, 0xebee121d
+0, 35, 35, 1, 304128, 0x12f6fd57
+0, 36, 36, 1, 304128, 0x08b05d8d
+0, 37, 37, 1, 304128, 0x57e02088
+0, 38, 38, 1, 304128, 0x6ff1dd89
+0, 39, 39, 1, 304128, 0xa5b0e20f
+0, 40, 40, 1, 304128, 0x4e9c0cf7
+0, 41, 41, 1, 304128, 0x64c93f20
+0, 42, 42, 1, 304128, 0x4264e490
+0, 43, 43, 1, 304128, 0xd7a3d763
+0, 44, 44, 1, 304128, 0x0fecf186
+0, 45, 45, 1, 304128, 0x3b87dd16
+0, 46, 46, 1, 304128, 0x7f46b1cd
+0, 47, 47, 1, 304128, 0xc635aca4
+0, 48, 48, 1, 304128, 0xfbaebb8d
+0, 49, 49, 1, 304128, 0x73976bb4
diff --git a/tests/ref/fate/filter-overlay_yuv420 b/tests/ref/fate/filter-overlay_yuv420
new file mode 100644
index 0000000000..a1f6787d11
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_yuv420
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0xfbd72a27
+0, 1, 1, 1, 152064, 0x06d10a14
+0, 2, 2, 1, 152064, 0x629e9a71
+0, 3, 3, 1, 152064, 0xd899f14b
+0, 4, 4, 1, 152064, 0x2de2e162
+0, 5, 5, 1, 152064, 0x1987b281
+0, 6, 6, 1, 152064, 0x36b68a47
+0, 7, 7, 1, 152064, 0x8d53cd7e
+0, 8, 8, 1, 152064, 0x3aa8daa1
+0, 9, 9, 1, 152064, 0xf329f3f4
+0, 10, 10, 1, 152064, 0xdff21c52
+0, 11, 11, 1, 152064, 0xe2550bc3
+0, 12, 12, 1, 152064, 0xb1ae65ef
+0, 13, 13, 1, 152064, 0x7401d246
+0, 14, 14, 1, 152064, 0x62c46ff5
+0, 15, 15, 1, 152064, 0xf5fd16df
+0, 16, 16, 1, 152064, 0x0052369e
+0, 17, 17, 1, 152064, 0x2b184fc2
+0, 18, 18, 1, 152064, 0xf244a268
+0, 19, 19, 1, 152064, 0x51210f57
+0, 20, 20, 1, 152064, 0x5f553ffc
+0, 21, 21, 1, 152064, 0x61da8757
+0, 22, 22, 1, 152064, 0x31dfa701
+0, 23, 23, 1, 152064, 0x7af0ccad
+0, 24, 24, 1, 152064, 0xa5766f36
+0, 25, 25, 1, 152064, 0xa1230c4f
+0, 26, 26, 1, 152064, 0x5166dca5
+0, 27, 27, 1, 152064, 0x3eff1d08
+0, 28, 28, 1, 152064, 0x738a44ea
+0, 29, 29, 1, 152064, 0x8ff6550f
+0, 30, 30, 1, 152064, 0x4b5d3a23
+0, 31, 31, 1, 152064, 0x354c4776
+0, 32, 32, 1, 152064, 0x6c02557b
+0, 33, 33, 1, 152064, 0xdc949adc
+0, 34, 34, 1, 152064, 0xfe1e85f1
+0, 35, 35, 1, 152064, 0xed52dbf2
+0, 36, 36, 1, 152064, 0x29bb4cd9
+0, 37, 37, 1, 152064, 0x61cc6102
+0, 38, 38, 1, 152064, 0x833b2351
+0, 39, 39, 1, 152064, 0x58af469f
+0, 40, 40, 1, 152064, 0x3fe6351b
+0, 41, 41, 1, 152064, 0x51987aaf
+0, 42, 42, 1, 152064, 0xb0636ca6
+0, 43, 43, 1, 152064, 0x83ebb949
+0, 44, 44, 1, 152064, 0x81168854
+0, 45, 45, 1, 152064, 0x251ef894
+0, 46, 46, 1, 152064, 0xa40bc6c4
+0, 47, 47, 1, 152064, 0x176a5d4a
+0, 48, 48, 1, 152064, 0x8d04302f
+0, 49, 49, 1, 152064, 0x444f8690
diff --git a/tests/ref/fate/filter-overlay_yuv422 b/tests/ref/fate/filter-overlay_yuv422
new file mode 100644
index 0000000000..982386b4a7
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_yuv422
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 304128, 0x9b9e09b2
+0, 1, 1, 1, 304128, 0x33addb48
+0, 2, 2, 1, 304128, 0xd5b973e9
+0, 3, 3, 1, 304128, 0xcb847cb6
+0, 4, 4, 1, 304128, 0xf64536f0
+0, 5, 5, 1, 304128, 0xda17564a
+0, 6, 6, 1, 304128, 0x85e33692
+0, 7, 7, 1, 304128, 0x081a657f
+0, 8, 8, 1, 304128, 0xf15f69ee
+0, 9, 9, 1, 304128, 0x0a2dd737
+0, 10, 10, 1, 304128, 0x14ae5b1b
+0, 11, 11, 1, 304128, 0x0b654f1e
+0, 12, 12, 1, 304128, 0x35a11962
+0, 13, 13, 1, 304128, 0x010b7514
+0, 14, 14, 1, 304128, 0x5db20c43
+0, 15, 15, 1, 304128, 0xafb6c615
+0, 16, 16, 1, 304128, 0xa671a3ac
+0, 17, 17, 1, 304128, 0x1a0fc75d
+0, 18, 18, 1, 304128, 0xe3a05ff1
+0, 19, 19, 1, 304128, 0x58437c36
+0, 20, 20, 1, 304128, 0x1303f940
+0, 21, 21, 1, 304128, 0xec2f3248
+0, 22, 22, 1, 304128, 0xe9ff7d49
+0, 23, 23, 1, 304128, 0x3972a1ed
+0, 24, 24, 1, 304128, 0xee2311df
+0, 25, 25, 1, 304128, 0x5b62c4d9
+0, 26, 26, 1, 304128, 0x9e1e52e2
+0, 27, 27, 1, 304128, 0x60c56d07
+0, 28, 28, 1, 304128, 0x313a8534
+0, 29, 29, 1, 304128, 0x9f548f56
+0, 30, 30, 1, 304128, 0x8d894ed3
+0, 31, 31, 1, 304128, 0x3ce0500a
+0, 32, 32, 1, 304128, 0xb8dd487a
+0, 33, 33, 1, 304128, 0xdde97863
+0, 34, 34, 1, 304128, 0x8d9d1689
+0, 35, 35, 1, 304128, 0x703634dd
+0, 36, 36, 1, 304128, 0x3e321210
+0, 37, 37, 1, 304128, 0x6b5a1a8c
+0, 38, 38, 1, 304128, 0xffc1015d
+0, 39, 39, 1, 304128, 0x4abc4495
+0, 40, 40, 1, 304128, 0x3c03ada9
+0, 41, 41, 1, 304128, 0x6fa0344a
+0, 42, 42, 1, 304128, 0x36572833
+0, 43, 43, 1, 304128, 0x31646c4d
+0, 44, 44, 1, 304128, 0xa22d18c7
+0, 45, 45, 1, 304128, 0xf3b058f2
+0, 46, 46, 1, 304128, 0x4c6be349
+0, 47, 47, 1, 304128, 0xda98914a
+0, 48, 48, 1, 304128, 0x1a6d2f58
+0, 49, 49, 1, 304128, 0x12684280
diff --git a/tests/ref/fate/filter-overlay_yuv444 b/tests/ref/fate/filter-overlay_yuv444
new file mode 100644
index 0000000000..0b2d9f77f4
--- /dev/null
+++ b/tests/ref/fate/filter-overlay_yuv444
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0xaa82add0
+0, 1, 1, 1, 405504, 0x0e9d65d0
+0, 2, 2, 1, 405504, 0xd8470d82
+0, 3, 3, 1, 405504, 0x11dc7a8a
+0, 4, 4, 1, 405504, 0xc538c776
+0, 5, 5, 1, 405504, 0x653b848e
+0, 6, 6, 1, 405504, 0xa6b773ef
+0, 7, 7, 1, 405504, 0x6cf17c3a
+0, 8, 8, 1, 405504, 0x7f5d6f17
+0, 9, 9, 1, 405504, 0x09167f36
+0, 10, 10, 1, 405504, 0xc650bb68
+0, 11, 11, 1, 405504, 0x25cebcac
+0, 12, 12, 1, 405504, 0xb2eb6342
+0, 13, 13, 1, 405504, 0xe827a01a
+0, 14, 14, 1, 405504, 0xe0bb2aba
+0, 15, 15, 1, 405504, 0xd32e0e45
+0, 16, 16, 1, 405504, 0xd5956738
+0, 17, 17, 1, 405504, 0xb8dd99db
+0, 18, 18, 1, 405504, 0x6d21c1ef
+0, 19, 19, 1, 405504, 0xd8db3a49
+0, 20, 20, 1, 405504, 0x235a53c6
+0, 21, 21, 1, 405504, 0x9db66c64
+0, 22, 22, 1, 405504, 0x71dc0e7a
+0, 23, 23, 1, 405504, 0x05f530f8
+0, 24, 24, 1, 405504, 0x4f053cb1
+0, 25, 25, 1, 405504, 0xdcf51aba
+0, 26, 26, 1, 405504, 0x59031fd1
+0, 27, 27, 1, 405504, 0x8451f2e2
+0, 28, 28, 1, 405504, 0xd393ebfc
+0, 29, 29, 1, 405504, 0x95a9ed6b
+0, 30, 30, 1, 405504, 0xa04b5e71
+0, 31, 31, 1, 405504, 0xf1ee4788
+0, 32, 32, 1, 405504, 0x9f3213ea
+0, 33, 33, 1, 405504, 0x1e021a23
+0, 34, 34, 1, 405504, 0xa1c21b9b
+0, 35, 35, 1, 405504, 0x15a9d0ee
+0, 36, 36, 1, 405504, 0xd99f8291
+0, 37, 37, 1, 405504, 0x3e197839
+0, 38, 38, 1, 405504, 0x851ba77b
+0, 39, 39, 1, 405504, 0xc808270a
+0, 40, 40, 1, 405504, 0x8e38821e
+0, 41, 41, 1, 405504, 0x75858815
+0, 42, 42, 1, 405504, 0x4633861b
+0, 43, 43, 1, 405504, 0xb0bdb8a9
+0, 44, 44, 1, 405504, 0x15681e03
+0, 45, 45, 1, 405504, 0x467cfea8
+0, 46, 46, 1, 405504, 0xd53d02ad
+0, 47, 47, 1, 405504, 0xf4cde081
+0, 48, 48, 1, 405504, 0x3ab111f5
+0, 49, 49, 1, 405504, 0xd1fa9f1d
diff --git a/tests/ref/fate/filter-pad b/tests/ref/fate/filter-pad
new file mode 100644
index 0000000000..1c46b696aa
--- /dev/null
+++ b/tests/ref/fate/filter-pad
@@ -0,0 +1 @@
+pad 8fdc977f88a9884b95cf87836603022e
diff --git a/tests/ref/fate/filter-palettegen-1 b/tests/ref/fate/filter-palettegen-1
new file mode 100644
index 0000000000..98b7159dc4
--- /dev/null
+++ b/tests/ref/fate/filter-palettegen-1
@@ -0,0 +1,2 @@
+#tb 0: 1001/24000
+0, 0, 0, 1, 1024, 0x3395ef5a
diff --git a/tests/ref/fate/filter-palettegen-2 b/tests/ref/fate/filter-palettegen-2
new file mode 100644
index 0000000000..2f58b64ee8
--- /dev/null
+++ b/tests/ref/fate/filter-palettegen-2
@@ -0,0 +1,2 @@
+#tb 0: 1001/24000
+0, 0, 0, 1, 1024, 0x906ff5aa
diff --git a/tests/ref/fate/filter-paletteuse-bayer b/tests/ref/fate/filter-paletteuse-bayer
new file mode 100644
index 0000000000..4b449396c1
--- /dev/null
+++ b/tests/ref/fate/filter-paletteuse-bayer
@@ -0,0 +1,72 @@
+#tb 0: 1001/24000
+0, 0, 0, 1, 230400, 0x7b259d08
+0, 1, 1, 1, 230400, 0xf04095e0
+0, 2, 2, 1, 230400, 0x84d49cd5
+0, 3, 3, 1, 230400, 0xd7a29aaf
+0, 4, 4, 1, 230400, 0x9047947c
+0, 5, 5, 1, 230400, 0xfeb990e7
+0, 6, 6, 1, 230400, 0x51ee9295
+0, 7, 7, 1, 230400, 0x66fd4833
+0, 8, 8, 1, 230400, 0x4c0948f0
+0, 9, 9, 1, 230400, 0x632b4776
+0, 10, 10, 1, 230400, 0x7a3c87e2
+0, 11, 11, 1, 230400, 0x4a9286ba
+0, 12, 12, 1, 230400, 0x54dc8649
+0, 13, 13, 1, 230400, 0x92628944
+0, 14, 14, 1, 230400, 0x80f9899f
+0, 15, 15, 1, 230400, 0x5cd78bd8
+0, 16, 16, 1, 230400, 0x4b4ca390
+0, 17, 17, 1, 230400, 0x82cca153
+0, 18, 18, 1, 230400, 0x65f1a2d0
+0, 19, 19, 1, 230400, 0x7df6ae4c
+0, 20, 20, 1, 230400, 0x909baccc
+0, 21, 21, 1, 230400, 0x1892ac65
+0, 22, 22, 1, 230400, 0x3247bb32
+0, 23, 23, 1, 230400, 0x592fbbe5
+0, 24, 24, 1, 230400, 0x189db9d5
+0, 25, 25, 1, 230400, 0x1a38b8da
+0, 26, 26, 1, 230400, 0xccd6bd07
+0, 27, 27, 1, 230400, 0xd4a2bc53
+0, 28, 28, 1, 230400, 0x9ce3bb4e
+0, 29, 29, 1, 230400, 0x5ffdc4db
+0, 30, 30, 1, 230400, 0xc885c7c9
+0, 31, 31, 1, 230400, 0xe27b9d33
+0, 32, 32, 1, 230400, 0xac03a256
+0, 33, 33, 1, 230400, 0xa2c73929
+0, 34, 34, 1, 230400, 0x33793b73
+0, 35, 35, 1, 230400, 0x1e400add
+0, 36, 36, 1, 230400, 0x98e50c6e
+0, 37, 37, 1, 230400, 0x68ed226d
+0, 38, 38, 1, 230400, 0x569e23cb
+0, 39, 39, 1, 230400, 0x82bf3fc0
+0, 40, 40, 1, 230400, 0x2b202e86
+0, 41, 41, 1, 230400, 0x7acd2dee
+0, 42, 42, 1, 230400, 0xfe872e42
+0, 43, 43, 1, 230400, 0x026c12e5
+0, 44, 44, 1, 230400, 0x81561399
+0, 45, 45, 1, 230400, 0xa08c13b6
+0, 46, 46, 1, 230400, 0x89e712f5
+0, 47, 47, 1, 230400, 0x569011ac
+0, 48, 48, 1, 230400, 0xd4691112
+0, 49, 49, 1, 230400, 0x2e50165a
+0, 50, 50, 1, 230400, 0x0a1215b6
+0, 51, 51, 1, 230400, 0x3c5316e3
+0, 52, 52, 1, 230400, 0x079c1393
+0, 53, 53, 1, 230400, 0x39ca1c48
+0, 54, 54, 1, 230400, 0xe27f199c
+0, 55, 55, 1, 230400, 0x10ab1bab
+0, 56, 56, 1, 230400, 0xeab017c3
+0, 57, 57, 1, 230400, 0x5f701f77
+0, 58, 58, 1, 230400, 0x01371d7d
+0, 59, 59, 1, 230400, 0x22751e99
+0, 60, 60, 1, 230400, 0xaee91a97
+0, 61, 61, 1, 230400, 0x27b41f32
+0, 62, 62, 1, 230400, 0x4ff32bb1
+0, 63, 63, 1, 230400, 0x86e02864
+0, 64, 64, 1, 230400, 0x5eb52b3e
+0, 65, 65, 1, 230400, 0xd9252ba8
+0, 66, 66, 1, 230400, 0x72232d9b
+0, 67, 67, 1, 230400, 0x599a206f
+0, 68, 68, 1, 230400, 0x4d2c1ca5
+0, 69, 69, 1, 230400, 0x9166293b
+0, 70, 70, 1, 230400, 0x00992453
diff --git a/tests/ref/fate/filter-paletteuse-nodither b/tests/ref/fate/filter-paletteuse-nodither
new file mode 100644
index 0000000000..8171ffa171
--- /dev/null
+++ b/tests/ref/fate/filter-paletteuse-nodither
@@ -0,0 +1,72 @@
+#tb 0: 1001/24000
+0, 0, 0, 1, 230400, 0x690560cb
+0, 1, 1, 1, 230400, 0x197a5a54
+0, 2, 2, 1, 230400, 0x665961db
+0, 3, 3, 1, 230400, 0xce0b5fa8
+0, 4, 4, 1, 230400, 0xa40e5cb0
+0, 5, 5, 1, 230400, 0xa5aa58da
+0, 6, 6, 1, 230400, 0x8e0259bb
+0, 7, 7, 1, 230400, 0x476d0dba
+0, 8, 8, 1, 230400, 0xfb1b0e8c
+0, 9, 9, 1, 230400, 0x50f60d3b
+0, 10, 10, 1, 230400, 0x12cd4bab
+0, 11, 11, 1, 230400, 0x4c274b13
+0, 12, 12, 1, 230400, 0xea494b0a
+0, 13, 13, 1, 230400, 0x118c4cc1
+0, 14, 14, 1, 230400, 0xd4224db7
+0, 15, 15, 1, 230400, 0xc3014f88
+0, 16, 16, 1, 230400, 0xe07a6838
+0, 17, 17, 1, 230400, 0x1b97659a
+0, 18, 18, 1, 230400, 0xf104670c
+0, 19, 19, 1, 230400, 0x7b63733d
+0, 20, 20, 1, 230400, 0x2c237200
+0, 21, 21, 1, 230400, 0x775d7248
+0, 22, 22, 1, 230400, 0xcaee7f9e
+0, 23, 23, 1, 230400, 0x4e4680a1
+0, 24, 24, 1, 230400, 0x21fb7e53
+0, 25, 25, 1, 230400, 0xf0297db6
+0, 26, 26, 1, 230400, 0x79a9829d
+0, 27, 27, 1, 230400, 0x8ccb80f7
+0, 28, 28, 1, 230400, 0xf4dd807f
+0, 29, 29, 1, 230400, 0xb6cc8696
+0, 30, 30, 1, 230400, 0x6c8a8917
+0, 31, 31, 1, 230400, 0x9e08615a
+0, 32, 32, 1, 230400, 0xc098685b
+0, 33, 33, 1, 230400, 0x5c09e710
+0, 34, 34, 1, 230400, 0xe4c4e9be
+0, 35, 35, 1, 230400, 0xac59c150
+0, 36, 36, 1, 230400, 0x6045c272
+0, 37, 37, 1, 230400, 0xf71ee6dc
+0, 38, 38, 1, 230400, 0xc82ce6f6
+0, 39, 39, 1, 230400, 0xb7ed039a
+0, 40, 40, 1, 230400, 0xda93f241
+0, 41, 41, 1, 230400, 0x194bf23b
+0, 42, 42, 1, 230400, 0xe7e6f2e2
+0, 43, 43, 1, 230400, 0xe479d834
+0, 44, 44, 1, 230400, 0xefdfd87e
+0, 45, 45, 1, 230400, 0xec66d8c0
+0, 46, 46, 1, 230400, 0x3a6bd81b
+0, 47, 47, 1, 230400, 0xb5d1d700
+0, 48, 48, 1, 230400, 0x3bc69e8b
+0, 49, 49, 1, 230400, 0x723fa455
+0, 50, 50, 1, 230400, 0x7c49a392
+0, 51, 51, 1, 230400, 0x272ea4b7
+0, 52, 52, 1, 230400, 0xebdda081
+0, 53, 53, 1, 230400, 0xfd26ab99
+0, 54, 54, 1, 230400, 0xfa02a891
+0, 55, 55, 1, 230400, 0xda2caa7f
+0, 56, 56, 1, 230400, 0x2360a611
+0, 57, 57, 1, 230400, 0xaa3baefd
+0, 58, 58, 1, 230400, 0x0961ad5c
+0, 59, 59, 1, 230400, 0x48d2ae47
+0, 60, 60, 1, 230400, 0x20eda81b
+0, 61, 61, 1, 230400, 0x8821adbb
+0, 62, 62, 1, 230400, 0x1150b810
+0, 63, 63, 1, 230400, 0x08dab596
+0, 64, 64, 1, 230400, 0x4731b7a5
+0, 65, 65, 1, 230400, 0xf382b87e
+0, 66, 66, 1, 230400, 0xdba7bac2
+0, 67, 67, 1, 230400, 0xf569acf9
+0, 68, 68, 1, 230400, 0x22d8a95d
+0, 69, 69, 1, 230400, 0xed0bb4fb
+0, 70, 70, 1, 230400, 0x2dccb218
diff --git a/tests/ref/fate/filter-paletteuse-sierra2_4a b/tests/ref/fate/filter-paletteuse-sierra2_4a
new file mode 100644
index 0000000000..95d7636097
--- /dev/null
+++ b/tests/ref/fate/filter-paletteuse-sierra2_4a
@@ -0,0 +1,72 @@
+#tb 0: 1001/24000
+0, 0, 0, 1, 230400, 0xa4f85758
+0, 1, 1, 1, 230400, 0xbe83505c
+0, 2, 2, 1, 230400, 0x0a09584e
+0, 3, 3, 1, 230400, 0xd2065629
+0, 4, 4, 1, 230400, 0x11eb5319
+0, 5, 5, 1, 230400, 0x61024f4c
+0, 6, 6, 1, 230400, 0xd5384faa
+0, 7, 7, 1, 230400, 0xdeae0343
+0, 8, 8, 1, 230400, 0xcb640541
+0, 9, 9, 1, 230400, 0xea2602c3
+0, 10, 10, 1, 230400, 0xa7974293
+0, 11, 11, 1, 230400, 0x67cd4287
+0, 12, 12, 1, 230400, 0x83fa437a
+0, 13, 13, 1, 230400, 0x852b42bf
+0, 14, 14, 1, 230400, 0x6d2d434c
+0, 15, 15, 1, 230400, 0x20c44629
+0, 16, 16, 1, 230400, 0xf2a35f57
+0, 17, 17, 1, 230400, 0x232959ec
+0, 18, 18, 1, 230400, 0x1f8e5c48
+0, 19, 19, 1, 230400, 0x88dc69bd
+0, 20, 20, 1, 230400, 0x4b6866f3
+0, 21, 21, 1, 230400, 0xe8f966dc
+0, 22, 22, 1, 230400, 0xe0877466
+0, 23, 23, 1, 230400, 0x8799748c
+0, 24, 24, 1, 230400, 0xcab871bc
+0, 25, 25, 1, 230400, 0x2e0372b4
+0, 26, 26, 1, 230400, 0x15fb77d5
+0, 27, 27, 1, 230400, 0xbadf75fc
+0, 28, 28, 1, 230400, 0xa4977626
+0, 29, 29, 1, 230400, 0x5b987943
+0, 30, 30, 1, 230400, 0x9ed57c09
+0, 31, 31, 1, 230400, 0x565d5105
+0, 32, 32, 1, 230400, 0x901b5a07
+0, 33, 33, 1, 230400, 0x8dc4e9a8
+0, 34, 34, 1, 230400, 0x0b9cee1c
+0, 35, 35, 1, 230400, 0x2bcdbe37
+0, 36, 36, 1, 230400, 0xf3e2bf71
+0, 37, 37, 1, 230400, 0xb718da67
+0, 38, 38, 1, 230400, 0x8f59da64
+0, 39, 39, 1, 230400, 0x8812f9aa
+0, 40, 40, 1, 230400, 0xe0dae6a3
+0, 41, 41, 1, 230400, 0xd2c7e5b7
+0, 42, 42, 1, 230400, 0xea2ae5d2
+0, 43, 43, 1, 230400, 0x2d66ca25
+0, 44, 44, 1, 230400, 0xf0d3cac6
+0, 45, 45, 1, 230400, 0xb9acccac
+0, 46, 46, 1, 230400, 0x8523ca4a
+0, 47, 47, 1, 230400, 0x92b9c9ef
+0, 48, 48, 1, 230400, 0x0a88946e
+0, 49, 49, 1, 230400, 0xe33699b8
+0, 50, 50, 1, 230400, 0x5e7b9917
+0, 51, 51, 1, 230400, 0xdac99998
+0, 52, 52, 1, 230400, 0xb5c995fc
+0, 53, 53, 1, 230400, 0x908b9f50
+0, 54, 54, 1, 230400, 0x60d59ced
+0, 55, 55, 1, 230400, 0x212e9f55
+0, 56, 56, 1, 230400, 0x95e69b2a
+0, 57, 57, 1, 230400, 0x6c38a34a
+0, 58, 58, 1, 230400, 0xeb32a103
+0, 59, 59, 1, 230400, 0x0131a1b7
+0, 60, 60, 1, 230400, 0xd59b9c4e
+0, 61, 61, 1, 230400, 0x2fc0a13f
+0, 62, 62, 1, 230400, 0x7a40adf9
+0, 63, 63, 1, 230400, 0x5cdbab2f
+0, 64, 64, 1, 230400, 0xcdc0ada8
+0, 65, 65, 1, 230400, 0x2f5faf32
+0, 66, 66, 1, 230400, 0xd463b224
+0, 67, 67, 1, 230400, 0xe337a2d5
+0, 68, 68, 1, 230400, 0xe775a0c1
+0, 69, 69, 1, 230400, 0x726aab49
+0, 70, 70, 1, 230400, 0x74dda81e
diff --git a/tests/ref/fate/filter-phase b/tests/ref/fate/filter-phase
new file mode 100644
index 0000000000..e0ec8d65b9
--- /dev/null
+++ b/tests/ref/fate/filter-phase
@@ -0,0 +1,51 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0x05b789ef
+0, 1, 1, 1, 152064, 0x4bb46551
+0, 2, 2, 1, 152064, 0x9dddf64a
+0, 3, 3, 1, 152064, 0x2a8380b0
+0, 4, 4, 1, 152064, 0x4de3b652
+0, 5, 5, 1, 152064, 0xedb5a8e6
+0, 6, 6, 1, 152064, 0xe20f7c23
+0, 7, 7, 1, 152064, 0x5ab58bac
+0, 8, 8, 1, 152064, 0x1f1b8026
+0, 9, 9, 1, 152064, 0x91373915
+0, 10, 10, 1, 152064, 0x02344760
+0, 11, 11, 1, 152064, 0x30f5fcd5
+0, 12, 12, 1, 152064, 0xc711ad61
+0, 13, 13, 1, 152064, 0x24eca223
+0, 14, 14, 1, 152064, 0x52a48ddd
+0, 15, 15, 1, 152064, 0xa91c0f05
+0, 16, 16, 1, 152064, 0x8e364e18
+0, 17, 17, 1, 152064, 0xb15d38c8
+0, 18, 18, 1, 152064, 0xf25f6acc
+0, 19, 19, 1, 152064, 0xf34ddbff
+0, 20, 20, 1, 152064, 0xfc7bf570
+0, 21, 21, 1, 152064, 0x9dc72412
+0, 22, 22, 1, 152064, 0x445d1d59
+0, 23, 23, 1, 152064, 0x2f2768ef
+0, 24, 24, 1, 152064, 0xce09f9d6
+0, 25, 25, 1, 152064, 0x95579936
+0, 26, 26, 1, 152064, 0x43d796b5
+0, 27, 27, 1, 152064, 0xd780d887
+0, 28, 28, 1, 152064, 0x76d2a455
+0, 29, 29, 1, 152064, 0x6dc3650e
+0, 30, 30, 1, 152064, 0x0f9d6aca
+0, 31, 31, 1, 152064, 0xe295c51e
+0, 32, 32, 1, 152064, 0xd766fc8d
+0, 33, 33, 1, 152064, 0xe22f7a30
+0, 34, 34, 1, 152064, 0x7fea4378
+0, 35, 35, 1, 152064, 0xfa8d94fb
+0, 36, 36, 1, 152064, 0x4c9737ab
+0, 37, 37, 1, 152064, 0xa50d01f8
+0, 38, 38, 1, 152064, 0x0b07594c
+0, 39, 39, 1, 152064, 0x88734edd
+0, 40, 40, 1, 152064, 0xd2735925
+0, 41, 41, 1, 152064, 0xd4e49e08
+0, 42, 42, 1, 152064, 0x20cebfa9
+0, 43, 43, 1, 152064, 0x575c20ec
+0, 44, 44, 1, 152064, 0xfd500471
+0, 45, 45, 1, 152064, 0x61b47e73
+0, 46, 46, 1, 152064, 0x09ef53ff
+0, 47, 47, 1, 152064, 0x6e88c5c2
+0, 48, 48, 1, 152064, 0xbb87b483
+0, 49, 49, 1, 152064, 0x4bbad8ea
diff --git a/tests/ref/fate/filter-pixdesc-0bgr b/tests/ref/fate/filter-pixdesc-0bgr
new file mode 100644
index 0000000000..7bbb03dc25
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-0bgr
@@ -0,0 +1 @@
+pixdesc-0bgr 89fa866f5532548a67b6e742b4d49e03
diff --git a/tests/ref/fate/filter-pixdesc-0rgb b/tests/ref/fate/filter-pixdesc-0rgb
new file mode 100644
index 0000000000..e0da275840
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-0rgb
@@ -0,0 +1 @@
+pixdesc-0rgb b181e1d3d4ca1e64d55f434e97c9fdba
diff --git a/tests/ref/fate/filter-pixdesc-abgr b/tests/ref/fate/filter-pixdesc-abgr
index 691bc0751e..194819e431 100644
--- a/tests/ref/fate/filter-pixdesc-abgr
+++ b/tests/ref/fate/filter-pixdesc-abgr
@@ -1 +1 @@
-pixdesc-abgr 0a96433ddadb89d577870419c0c0f122
+pixdesc-abgr ded06f35fe57b74f6cdbba9e356cd02d
diff --git a/tests/ref/fate/filter-pixdesc-argb b/tests/ref/fate/filter-pixdesc-argb
index 27531dc0c6..a21a87a64b 100644
--- a/tests/ref/fate/filter-pixdesc-argb
+++ b/tests/ref/fate/filter-pixdesc-argb
@@ -1 +1 @@
-pixdesc-argb 29a7781fc931a8fe4847bbbd02ca966a
+pixdesc-argb f983e1f44ce61c3c2bfac3cb55d3cdd8
diff --git a/tests/ref/fate/filter-pixdesc-bgr0 b/tests/ref/fate/filter-pixdesc-bgr0
new file mode 100644
index 0000000000..f4a2c1bc14
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-bgr0
@@ -0,0 +1 @@
+pixdesc-bgr0 5bf31ebb28690035b15eb8252c11b630
diff --git a/tests/ref/fate/filter-pixdesc-bgr24 b/tests/ref/fate/filter-pixdesc-bgr24
index 7c530b44e4..c63da5812f 100644
--- a/tests/ref/fate/filter-pixdesc-bgr24
+++ b/tests/ref/fate/filter-pixdesc-bgr24
@@ -1 +1 @@
-pixdesc-bgr24 0c8ccab8bf3055c6299f943e94e90e25
+pixdesc-bgr24 30134c7e6c9298df1d830398edca22b9
diff --git a/tests/ref/fate/filter-pixdesc-bgr444be b/tests/ref/fate/filter-pixdesc-bgr444be
index 6de43e78a0..1c6ce575c4 100644
--- a/tests/ref/fate/filter-pixdesc-bgr444be
+++ b/tests/ref/fate/filter-pixdesc-bgr444be
@@ -1 +1 @@
-pixdesc-bgr444be 4f223284a5797b7665994cea8045bc70
+pixdesc-bgr444be bbe69fdff1c6965674bf5be5d14a342d
diff --git a/tests/ref/fate/filter-pixdesc-bgr444le b/tests/ref/fate/filter-pixdesc-bgr444le
index 0d3a6eda0b..2886eee5bf 100644
--- a/tests/ref/fate/filter-pixdesc-bgr444le
+++ b/tests/ref/fate/filter-pixdesc-bgr444le
@@ -1 +1 @@
-pixdesc-bgr444le fa37199bf217a5a82a628f175b375a86
+pixdesc-bgr444le 497e36f9004a10b46e4bc7253e95ad9f
diff --git a/tests/ref/fate/filter-pixdesc-bgr48be b/tests/ref/fate/filter-pixdesc-bgr48be
index 65b2289077..72e2df7fe0 100644
--- a/tests/ref/fate/filter-pixdesc-bgr48be
+++ b/tests/ref/fate/filter-pixdesc-bgr48be
@@ -1 +1 @@
-pixdesc-bgr48be 728452ef75877706fddabdee386ea6a3
+pixdesc-bgr48be c0ddbd8b786877336e725ec3c150b17e
diff --git a/tests/ref/fate/filter-pixdesc-bgr48le b/tests/ref/fate/filter-pixdesc-bgr48le
index 5906109399..dad2d06474 100644
--- a/tests/ref/fate/filter-pixdesc-bgr48le
+++ b/tests/ref/fate/filter-pixdesc-bgr48le
@@ -1 +1 @@
-pixdesc-bgr48le 82f5689e141989e7368f1057f4411040
+pixdesc-bgr48le 0d7a6d9d46fec1e701f34c2d5e2c6918
diff --git a/tests/ref/fate/filter-pixdesc-bgr4_byte b/tests/ref/fate/filter-pixdesc-bgr4_byte
index 1995bc95de..e71fec2317 100644
--- a/tests/ref/fate/filter-pixdesc-bgr4_byte
+++ b/tests/ref/fate/filter-pixdesc-bgr4_byte
@@ -1 +1 @@
-pixdesc-bgr4_byte dc7a43438728d94f27c495491ea6b5fc
+pixdesc-bgr4_byte 68d51f7d88311efcb4661ffb5ff9582e
diff --git a/tests/ref/fate/filter-pixdesc-bgr555be b/tests/ref/fate/filter-pixdesc-bgr555be
index 6624bc47a8..a0ba70f38d 100644
--- a/tests/ref/fate/filter-pixdesc-bgr555be
+++ b/tests/ref/fate/filter-pixdesc-bgr555be
@@ -1 +1 @@
-pixdesc-bgr555be 5c247603c16194f1206cc120de268628
+pixdesc-bgr555be 2718e3363c3191b14bc2f3f1936cebdb
diff --git a/tests/ref/fate/filter-pixdesc-bgr555le b/tests/ref/fate/filter-pixdesc-bgr555le
index 155cda13c3..dd22eef8b7 100644
--- a/tests/ref/fate/filter-pixdesc-bgr555le
+++ b/tests/ref/fate/filter-pixdesc-bgr555le
@@ -1 +1 @@
-pixdesc-bgr555le 29f6a95f0c11734ab2dfbef9e7633eaf
+pixdesc-bgr555le 35bf7049f067f541ae6dad8a70bc28ed
diff --git a/tests/ref/fate/filter-pixdesc-bgr565be b/tests/ref/fate/filter-pixdesc-bgr565be
index be096b26fa..f050688676 100644
--- a/tests/ref/fate/filter-pixdesc-bgr565be
+++ b/tests/ref/fate/filter-pixdesc-bgr565be
@@ -1 +1 @@
-pixdesc-bgr565be 0225e9ef2a254369e0682832774dd0d5
+pixdesc-bgr565be 104e725cc5237aee0b03b8c537eaacac
diff --git a/tests/ref/fate/filter-pixdesc-bgr565le b/tests/ref/fate/filter-pixdesc-bgr565le
index 720a2221d8..fa35622689 100644
--- a/tests/ref/fate/filter-pixdesc-bgr565le
+++ b/tests/ref/fate/filter-pixdesc-bgr565le
@@ -1 +1 @@
-pixdesc-bgr565le 5216493ff6c65fa86e117a4fc508c45f
+pixdesc-bgr565le 33df7dd9a9d738fb9c8b82dbf23c7caa
diff --git a/tests/ref/fate/filter-pixdesc-bgr8 b/tests/ref/fate/filter-pixdesc-bgr8
index 77ca8c4b06..299665e52a 100644
--- a/tests/ref/fate/filter-pixdesc-bgr8
+++ b/tests/ref/fate/filter-pixdesc-bgr8
@@ -1 +1 @@
-pixdesc-bgr8 cbd7b5fbc9cdc1960b99338d4b7a717f
+pixdesc-bgr8 0abb130e5224af5e2e10149f1680fa2e
diff --git a/tests/ref/fate/filter-pixdesc-bgra b/tests/ref/fate/filter-pixdesc-bgra
index 061d3952b8..abdedbe48c 100644
--- a/tests/ref/fate/filter-pixdesc-bgra
+++ b/tests/ref/fate/filter-pixdesc-bgra
@@ -1 +1 @@
-pixdesc-bgra ed2e65c70afddfb5ecdcbbe84b699125
+pixdesc-bgra 0bb08da9936d2efd20351ab4a88e9b10
diff --git a/tests/ref/fate/filter-pixdesc-bgra64be b/tests/ref/fate/filter-pixdesc-bgra64be
new file mode 100644
index 0000000000..4459e24999
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-bgra64be
@@ -0,0 +1 @@
+pixdesc-bgra64be c524aa7e4c02dbca57035bb548afc1ec
diff --git a/tests/ref/fate/filter-pixdesc-bgra64le b/tests/ref/fate/filter-pixdesc-bgra64le
new file mode 100644
index 0000000000..82f2a5479e
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-bgra64le
@@ -0,0 +1 @@
+pixdesc-bgra64le df3a79d47b9dcf3ed2c252afd80e062c
diff --git a/tests/ref/fate/filter-pixdesc-gbrap b/tests/ref/fate/filter-pixdesc-gbrap
index 7b6cb9e629..6be442b006 100644
--- a/tests/ref/fate/filter-pixdesc-gbrap
+++ b/tests/ref/fate/filter-pixdesc-gbrap
@@ -1 +1 @@
-pixdesc-gbrap 27d9432f970ab0858efecb5a5411cff9
+pixdesc-gbrap a2b9d6261ad24d75d192cbb3af277022
diff --git a/tests/ref/fate/filter-pixdesc-gbrp b/tests/ref/fate/filter-pixdesc-gbrp
index b2eb19ae90..4edfdcb36e 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp
+++ b/tests/ref/fate/filter-pixdesc-gbrp
@@ -1 +1 @@
-pixdesc-gbrp 6590f4971764ad82148440354f1635d3
+pixdesc-gbrp fe5bffda29f9afbf84fbf9cc2a8f45bd
diff --git a/tests/ref/fate/filter-pixdesc-gbrp10be b/tests/ref/fate/filter-pixdesc-gbrp10be
index b2f6ee8d01..9400d6f02d 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp10be
+++ b/tests/ref/fate/filter-pixdesc-gbrp10be
@@ -1 +1 @@
-pixdesc-gbrp10be 7737f88a6ea043a5cd142afe89da3c21
+pixdesc-gbrp10be c4ee3140e42a264568834c29f2c78027
diff --git a/tests/ref/fate/filter-pixdesc-gbrp10le b/tests/ref/fate/filter-pixdesc-gbrp10le
index bc0e2b98cb..5851a47f33 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp10le
+++ b/tests/ref/fate/filter-pixdesc-gbrp10le
@@ -1 +1 @@
-pixdesc-gbrp10le a912e36ddb9380de328ef2555c303302
+pixdesc-gbrp10le 9a0cb9d105d80e6058efbb1127820329
diff --git a/tests/ref/fate/filter-pixdesc-gbrp12be b/tests/ref/fate/filter-pixdesc-gbrp12be
new file mode 100644
index 0000000000..c5cc9426cd
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp12be
@@ -0,0 +1 @@
+pixdesc-gbrp12be e6ce20968d63ece72476d038bb99fb1d
diff --git a/tests/ref/fate/filter-pixdesc-gbrp12le b/tests/ref/fate/filter-pixdesc-gbrp12le
new file mode 100644
index 0000000000..35467308f3
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp12le
@@ -0,0 +1 @@
+pixdesc-gbrp12le df936efd70fb5751e72bd8c0a70a513f
diff --git a/tests/ref/fate/filter-pixdesc-gbrp14be b/tests/ref/fate/filter-pixdesc-gbrp14be
new file mode 100644
index 0000000000..e020129d05
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp14be
@@ -0,0 +1 @@
+pixdesc-gbrp14be b2ba152fcca2f5beef7c972948395a34
diff --git a/tests/ref/fate/filter-pixdesc-gbrp14le b/tests/ref/fate/filter-pixdesc-gbrp14le
new file mode 100644
index 0000000000..2f61310c20
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-gbrp14le
@@ -0,0 +1 @@
+pixdesc-gbrp14le 66a0b4530129ca693aed5099fb2b93f6
diff --git a/tests/ref/fate/filter-pixdesc-gbrp9be b/tests/ref/fate/filter-pixdesc-gbrp9be
index 3386eab6b2..19b0ad6810 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp9be
+++ b/tests/ref/fate/filter-pixdesc-gbrp9be
@@ -1 +1 @@
-pixdesc-gbrp9be 1c448e780b6e82e163e576f0ebb22522
+pixdesc-gbrp9be e3c5235e05fd8cd6ed3e48a4d95e58e0
diff --git a/tests/ref/fate/filter-pixdesc-gbrp9le b/tests/ref/fate/filter-pixdesc-gbrp9le
index 49b03df0b0..f0c2f2e0d1 100644
--- a/tests/ref/fate/filter-pixdesc-gbrp9le
+++ b/tests/ref/fate/filter-pixdesc-gbrp9le
@@ -1 +1 @@
-pixdesc-gbrp9le 77c2331ceb429454ff7999f771685f38
+pixdesc-gbrp9le 8ba96d3fe6e190f53660c225623e653c
diff --git a/tests/ref/fate/filter-pixdesc-gray b/tests/ref/fate/filter-pixdesc-gray
index 20424cd10a..3ba6448074 100644
--- a/tests/ref/fate/filter-pixdesc-gray
+++ b/tests/ref/fate/filter-pixdesc-gray
@@ -1 +1 @@
-pixdesc-gray 6b89bdf31cbbb19580b1edd3c65b2100
+pixdesc-gray 24563fd8a34c2bfa8523da74da025e23
diff --git a/tests/ref/fate/filter-pixdesc-gray16be b/tests/ref/fate/filter-pixdesc-gray16be
index 8ecaf57858..b4d28d38a6 100644
--- a/tests/ref/fate/filter-pixdesc-gray16be
+++ b/tests/ref/fate/filter-pixdesc-gray16be
@@ -1 +1 @@
-pixdesc-gray16be d8acd9d657ad5d916cc6b016fa62044e
+pixdesc-gray16be 99e7e54973b479845932e92581292b03
diff --git a/tests/ref/fate/filter-pixdesc-gray16le b/tests/ref/fate/filter-pixdesc-gray16le
index d99ca6159e..841d3ee1c5 100644
--- a/tests/ref/fate/filter-pixdesc-gray16le
+++ b/tests/ref/fate/filter-pixdesc-gray16le
@@ -1 +1 @@
-pixdesc-gray16le db884b18fd1a09c53f2cf3d6ca30e086
+pixdesc-gray16le 33bd1b950d279a4bb22af325905d3604
diff --git a/tests/ref/fate/filter-pixdesc-monob b/tests/ref/fate/filter-pixdesc-monob
index 9f5df059bf..00df9ef973 100644
--- a/tests/ref/fate/filter-pixdesc-monob
+++ b/tests/ref/fate/filter-pixdesc-monob
@@ -1 +1 @@
-pixdesc-monob 48a6d35857c18e2ed20117dd9ef80fdc
+pixdesc-monob e795648f4f5054ca133437570cf5ba5f
diff --git a/tests/ref/fate/filter-pixdesc-monow b/tests/ref/fate/filter-pixdesc-monow
index 0201f4467a..429c5b410e 100644
--- a/tests/ref/fate/filter-pixdesc-monow
+++ b/tests/ref/fate/filter-pixdesc-monow
@@ -1 +1 @@
-pixdesc-monow de6cd58f5525e692981d8c8678f878c4
+pixdesc-monow e7d8142228a04d9ef3cdc4473ef8a69f
diff --git a/tests/ref/fate/filter-pixdesc-nv12 b/tests/ref/fate/filter-pixdesc-nv12
index 6cc824b6a1..2151cd03a1 100644
--- a/tests/ref/fate/filter-pixdesc-nv12
+++ b/tests/ref/fate/filter-pixdesc-nv12
@@ -1 +1 @@
-pixdesc-nv12 d3a477a5a56d334728720ac268b1ef99
+pixdesc-nv12 7686f473937082abcba7a46f028aaa08
diff --git a/tests/ref/fate/filter-pixdesc-nv21 b/tests/ref/fate/filter-pixdesc-nv21
index 3f8393bc7a..02703836d3 100644
--- a/tests/ref/fate/filter-pixdesc-nv21
+++ b/tests/ref/fate/filter-pixdesc-nv21
@@ -1 +1 @@
-pixdesc-nv21 977c4582b5d4c7cbdda70ccabb16884b
+pixdesc-nv21 61c09258160939049f9807ed589bc90e
diff --git a/tests/ref/fate/filter-pixdesc-rgb0 b/tests/ref/fate/filter-pixdesc-rgb0
new file mode 100644
index 0000000000..dccd9c130f
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-rgb0
@@ -0,0 +1 @@
+pixdesc-rgb0 bd816424fbe4d56b22b5b0f9a238e26e
diff --git a/tests/ref/fate/filter-pixdesc-rgb24 b/tests/ref/fate/filter-pixdesc-rgb24
index 21a720eb9f..67d92d8e18 100644
--- a/tests/ref/fate/filter-pixdesc-rgb24
+++ b/tests/ref/fate/filter-pixdesc-rgb24
@@ -1 +1 @@
-pixdesc-rgb24 f902267656c28501c123e0bde836421b
+pixdesc-rgb24 6fa2d8a2a57d1cb1a30354851e8dfd82
diff --git a/tests/ref/fate/filter-pixdesc-rgb444be b/tests/ref/fate/filter-pixdesc-rgb444be
index a8ff704c8a..63ba2885b7 100644
--- a/tests/ref/fate/filter-pixdesc-rgb444be
+++ b/tests/ref/fate/filter-pixdesc-rgb444be
@@ -1 +1 @@
-pixdesc-rgb444be bc6cb36dbf15cb132ff6d8eee765a95e
+pixdesc-rgb444be cfa4ee284dd89df92eed7f99f19a0218
diff --git a/tests/ref/fate/filter-pixdesc-rgb444le b/tests/ref/fate/filter-pixdesc-rgb444le
index 3b77e74a44..eafe2eb134 100644
--- a/tests/ref/fate/filter-pixdesc-rgb444le
+++ b/tests/ref/fate/filter-pixdesc-rgb444le
@@ -1 +1 @@
-pixdesc-rgb444le a425e8048218b25dad9a81506d891b6f
+pixdesc-rgb444le a40633dce705f439ecfc1a1b75661e17
diff --git a/tests/ref/fate/filter-pixdesc-rgb48be b/tests/ref/fate/filter-pixdesc-rgb48be
index f7ac2ac968..43b4b3c12c 100644
--- a/tests/ref/fate/filter-pixdesc-rgb48be
+++ b/tests/ref/fate/filter-pixdesc-rgb48be
@@ -1 +1 @@
-pixdesc-rgb48be d42c8b9fb2d34df383a5f9c2388b5243
+pixdesc-rgb48be 464a81ce147465017b7edb71f806f434
diff --git a/tests/ref/fate/filter-pixdesc-rgb48le b/tests/ref/fate/filter-pixdesc-rgb48le
index ff3dee918b..614f1648af 100644
--- a/tests/ref/fate/filter-pixdesc-rgb48le
+++ b/tests/ref/fate/filter-pixdesc-rgb48le
@@ -1 +1 @@
-pixdesc-rgb48le ded9e1cb5a4e40de05c0849143658daf
+pixdesc-rgb48le e05c1d73c722b93735ec2d5f8109e1f3
diff --git a/tests/ref/fate/filter-pixdesc-rgb4_byte b/tests/ref/fate/filter-pixdesc-rgb4_byte
index 6763c11a72..99fce381f7 100644
--- a/tests/ref/fate/filter-pixdesc-rgb4_byte
+++ b/tests/ref/fate/filter-pixdesc-rgb4_byte
@@ -1 +1 @@
-pixdesc-rgb4_byte c38cb84e03142ba79b67efa6eb435a40
+pixdesc-rgb4_byte 0d4f7b0112d0e942527f168a651a6f8c
diff --git a/tests/ref/fate/filter-pixdesc-rgb555be b/tests/ref/fate/filter-pixdesc-rgb555be
index 520eeccba4..4cc69d8fde 100644
--- a/tests/ref/fate/filter-pixdesc-rgb555be
+++ b/tests/ref/fate/filter-pixdesc-rgb555be
@@ -1 +1 @@
-pixdesc-rgb555be 0684e7db3ed49f0fc8bb2787b44bbdf6
+pixdesc-rgb555be 6ba7d102e12460af51365ee66e070ad4
diff --git a/tests/ref/fate/filter-pixdesc-rgb555le b/tests/ref/fate/filter-pixdesc-rgb555le
index f178868420..1bd13c0428 100644
--- a/tests/ref/fate/filter-pixdesc-rgb555le
+++ b/tests/ref/fate/filter-pixdesc-rgb555le
@@ -1 +1 @@
-pixdesc-rgb555le 1a890ce4ebe5f59fb53e1bf3275c799b
+pixdesc-rgb555le ab391dde7ec72eb100c6a38aa301ff55
diff --git a/tests/ref/fate/filter-pixdesc-rgb565be b/tests/ref/fate/filter-pixdesc-rgb565be
index c2cf284253..59dbaae46b 100644
--- a/tests/ref/fate/filter-pixdesc-rgb565be
+++ b/tests/ref/fate/filter-pixdesc-rgb565be
@@ -1 +1 @@
-pixdesc-rgb565be c5c1ee14a373afcf4ac3fc32fc9583e1
+pixdesc-rgb565be 8f05c5786c1e5c9bd64cc6dab05139a5
diff --git a/tests/ref/fate/filter-pixdesc-rgb565le b/tests/ref/fate/filter-pixdesc-rgb565le
index 1766eaf56d..418a18b91e 100644
--- a/tests/ref/fate/filter-pixdesc-rgb565le
+++ b/tests/ref/fate/filter-pixdesc-rgb565le
@@ -1 +1 @@
-pixdesc-rgb565le 3d16aef38fc165413d3aa35194151d78
+pixdesc-rgb565le 427bd36cdf8e8786be888368bbfb35be
diff --git a/tests/ref/fate/filter-pixdesc-rgb8 b/tests/ref/fate/filter-pixdesc-rgb8
index 6c798c0693..d9c4c6298a 100644
--- a/tests/ref/fate/filter-pixdesc-rgb8
+++ b/tests/ref/fate/filter-pixdesc-rgb8
@@ -1 +1 @@
-pixdesc-rgb8 cd3dd114110b48758df3410aae6dd7d3
+pixdesc-rgb8 2ce87991241972bea465f41e4d82d27a
diff --git a/tests/ref/fate/filter-pixdesc-rgba b/tests/ref/fate/filter-pixdesc-rgba
index 2ea2c56075..ff98607c0c 100644
--- a/tests/ref/fate/filter-pixdesc-rgba
+++ b/tests/ref/fate/filter-pixdesc-rgba
@@ -1 +1 @@
-pixdesc-rgba 301a8e45ab9d14a06c5cde7bbedef0b8
+pixdesc-rgba f55378fcaad1b471faaa4068be30104c
diff --git a/tests/ref/fate/filter-pixdesc-rgba64be b/tests/ref/fate/filter-pixdesc-rgba64be
new file mode 100644
index 0000000000..0c999db22c
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-rgba64be
@@ -0,0 +1 @@
+pixdesc-rgba64be 8d5aea96a7c90aad9d97b06533ad291c
diff --git a/tests/ref/fate/filter-pixdesc-rgba64le b/tests/ref/fate/filter-pixdesc-rgba64le
new file mode 100644
index 0000000000..6534cc2f94
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-rgba64le
@@ -0,0 +1 @@
+pixdesc-rgba64le 2c757090db978d11718bae97027f3a56
diff --git a/tests/ref/fate/filter-pixdesc-uyvy422 b/tests/ref/fate/filter-pixdesc-uyvy422
index 2d89065c27..52d83b0c53 100644
--- a/tests/ref/fate/filter-pixdesc-uyvy422
+++ b/tests/ref/fate/filter-pixdesc-uyvy422
@@ -1 +1 @@
-pixdesc-uyvy422 a36a7fa35ad4acc647431a51c9beec4d
+pixdesc-uyvy422 45211ac7c751e7a7ce6b703a74ce9e71
diff --git a/tests/ref/fate/filter-pixdesc-xyz12be b/tests/ref/fate/filter-pixdesc-xyz12be
new file mode 100644
index 0000000000..d355f9bcc3
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-xyz12be
@@ -0,0 +1 @@
+pixdesc-xyz12be 4ec824668b9753e26c1bccffca866e27
diff --git a/tests/ref/fate/filter-pixdesc-xyz12le b/tests/ref/fate/filter-pixdesc-xyz12le
new file mode 100644
index 0000000000..1c14fba213
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-xyz12le
@@ -0,0 +1 @@
+pixdesc-xyz12le 88d2563589044a3e28f6cde9a43599f9
diff --git a/tests/ref/fate/filter-pixdesc-yuv410p b/tests/ref/fate/filter-pixdesc-yuv410p
index 7522a3e6a3..f758204472 100644
--- a/tests/ref/fate/filter-pixdesc-yuv410p
+++ b/tests/ref/fate/filter-pixdesc-yuv410p
@@ -1 +1 @@
-pixdesc-yuv410p 21a5303f9ef6819bd7abe4b86dc8cdf2
+pixdesc-yuv410p 87d3cb32a4b5a44b94cd6f61e441d279
diff --git a/tests/ref/fate/filter-pixdesc-yuv411p b/tests/ref/fate/filter-pixdesc-yuv411p
index 3e0e8a2e6d..5cc45c2fb0 100644
--- a/tests/ref/fate/filter-pixdesc-yuv411p
+++ b/tests/ref/fate/filter-pixdesc-yuv411p
@@ -1 +1 @@
-pixdesc-yuv411p c69ecd3af68379064fddc2f75611965e
+pixdesc-yuv411p 0b5beeda04c6f9d091f75ca767b5ffb7
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p b/tests/ref/fate/filter-pixdesc-yuv420p
index ea94f8c518..f0003c0984 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p
+++ b/tests/ref/fate/filter-pixdesc-yuv420p
@@ -1 +1 @@
-pixdesc-yuv420p 7aaf1057c0edf7d5e9700f9c8e510ea9
+pixdesc-yuv420p fcb007249fba9371fe84a61c974fcb00
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p10be b/tests/ref/fate/filter-pixdesc-yuv420p10be
index 34c2dc86b7..058db9e88c 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p10be
+++ b/tests/ref/fate/filter-pixdesc-yuv420p10be
@@ -1 +1 @@
-pixdesc-yuv420p10be 05662068c354779b0c26255efe33c955
+pixdesc-yuv420p10be 51349063819809ca088e76c01041f3e9
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p10le b/tests/ref/fate/filter-pixdesc-yuv420p10le
index bec240b9cf..b5f62f2091 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p10le
+++ b/tests/ref/fate/filter-pixdesc-yuv420p10le
@@ -1 +1 @@
-pixdesc-yuv420p10le 591af435ff8650b48824ec3705a933d5
+pixdesc-yuv420p10le 070fe05fe4df43e117d1e4cff578655d
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p12be b/tests/ref/fate/filter-pixdesc-yuv420p12be
new file mode 100644
index 0000000000..35a908ab88
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p12be
@@ -0,0 +1 @@
+pixdesc-yuv420p12be 0527525aee87d21db82ecc738ab76848
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p12le b/tests/ref/fate/filter-pixdesc-yuv420p12le
new file mode 100644
index 0000000000..9d6410278d
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p12le
@@ -0,0 +1 @@
+pixdesc-yuv420p12le cb513fbc83b63eedf0cafb26914d37be
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p14be b/tests/ref/fate/filter-pixdesc-yuv420p14be
new file mode 100644
index 0000000000..adbf04dbff
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p14be
@@ -0,0 +1 @@
+pixdesc-yuv420p14be ecafa03e42e81d83c8e8711f2133b128
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p14le b/tests/ref/fate/filter-pixdesc-yuv420p14le
new file mode 100644
index 0000000000..ab80278ba6
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv420p14le
@@ -0,0 +1 @@
+pixdesc-yuv420p14le a7ed1889fec8fff122dd2b065a5082ba
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p16be b/tests/ref/fate/filter-pixdesc-yuv420p16be
index 3e9c4f039f..85ea329523 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p16be
+++ b/tests/ref/fate/filter-pixdesc-yuv420p16be
@@ -1 +1 @@
-pixdesc-yuv420p16be df8ed373b77222ee82f12564b5edfa77
+pixdesc-yuv420p16be 9219829ae866614f64889a0b2603240d
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p16le b/tests/ref/fate/filter-pixdesc-yuv420p16le
index c6e51415ed..f10521c2fa 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p16le
+++ b/tests/ref/fate/filter-pixdesc-yuv420p16le
@@ -1 +1 @@
-pixdesc-yuv420p16le 5aa9648f73f09c1a3d1c652f2285762a
+pixdesc-yuv420p16le be0f1d41796ac141f33161349d47b4b5
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p9be b/tests/ref/fate/filter-pixdesc-yuv420p9be
index 00fb78eb69..7c74adcc03 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p9be
+++ b/tests/ref/fate/filter-pixdesc-yuv420p9be
@@ -1 +1 @@
-pixdesc-yuv420p9be 605305ba8581d63f160c7885630514a6
+pixdesc-yuv420p9be 5750914b29640a8e5fe9cda0e5bf0a84
diff --git a/tests/ref/fate/filter-pixdesc-yuv420p9le b/tests/ref/fate/filter-pixdesc-yuv420p9le
index 864456bfc9..2b9c3f9865 100644
--- a/tests/ref/fate/filter-pixdesc-yuv420p9le
+++ b/tests/ref/fate/filter-pixdesc-yuv420p9le
@@ -1 +1 @@
-pixdesc-yuv420p9le 73722053a27e8c5ef8aa407a2452c652
+pixdesc-yuv420p9le 6f9d17cae7cfd2676e8798241e266322
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p b/tests/ref/fate/filter-pixdesc-yuv422p
index b49f995d84..d782585e80 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p
+++ b/tests/ref/fate/filter-pixdesc-yuv422p
@@ -1 +1 @@
-pixdesc-yuv422p 12b097c00dd1e526186d3d7dcba204bc
+pixdesc-yuv422p 81452c764f8da88d823c925d52cce322
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p10be b/tests/ref/fate/filter-pixdesc-yuv422p10be
index 1e8729476c..9e2779b867 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p10be
+++ b/tests/ref/fate/filter-pixdesc-yuv422p10be
@@ -1 +1 @@
-pixdesc-yuv422p10be f53e6d39e40e1ae35cc855716dda8dbc
+pixdesc-yuv422p10be 55c4d6699258c42444265aa8dae7720e
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p10le b/tests/ref/fate/filter-pixdesc-yuv422p10le
index d0d845d092..db31f7f88f 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p10le
+++ b/tests/ref/fate/filter-pixdesc-yuv422p10le
@@ -1 +1 @@
-pixdesc-yuv422p10le deab1e4f7f3907ffd06ec448cf142f3f
+pixdesc-yuv422p10le 8732c020f4401b757caa9e5616f426f2
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p12be b/tests/ref/fate/filter-pixdesc-yuv422p12be
new file mode 100644
index 0000000000..4c94151546
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p12be
@@ -0,0 +1 @@
+pixdesc-yuv422p12be a3119254cc1aa9893478faedf3b49b4f
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p12le b/tests/ref/fate/filter-pixdesc-yuv422p12le
new file mode 100644
index 0000000000..6974e69386
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p12le
@@ -0,0 +1 @@
+pixdesc-yuv422p12le 8d397de88edec1a85b5fbbe7bdce08ac
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p14be b/tests/ref/fate/filter-pixdesc-yuv422p14be
new file mode 100644
index 0000000000..50202f92ba
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p14be
@@ -0,0 +1 @@
+pixdesc-yuv422p14be c9d0750d9b784ca43d279479372f3a3e
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p14le b/tests/ref/fate/filter-pixdesc-yuv422p14le
new file mode 100644
index 0000000000..a2ee82a1db
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv422p14le
@@ -0,0 +1 @@
+pixdesc-yuv422p14le c8233b3c0fee4036ead0ac7a65489f69
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p16be b/tests/ref/fate/filter-pixdesc-yuv422p16be
index e09298c7ed..b09a4711f4 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p16be
+++ b/tests/ref/fate/filter-pixdesc-yuv422p16be
@@ -1 +1 @@
-pixdesc-yuv422p16be fddc6580ccbc42d1d2d4e40f44403c54
+pixdesc-yuv422p16be 1dddb5353eb5b2e99cb54707eb7b80a7
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p16le b/tests/ref/fate/filter-pixdesc-yuv422p16le
index eea2005d6d..c829162f0c 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p16le
+++ b/tests/ref/fate/filter-pixdesc-yuv422p16le
@@ -1 +1 @@
-pixdesc-yuv422p16le 37760ff26bcc46d7cae41be0f7aa7287
+pixdesc-yuv422p16le ba6cdf27c86b2dfdfaa29c394eea76cb
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p9be b/tests/ref/fate/filter-pixdesc-yuv422p9be
index 2b38cf0be3..05816b2a9d 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p9be
+++ b/tests/ref/fate/filter-pixdesc-yuv422p9be
@@ -1 +1 @@
-pixdesc-yuv422p9be d29a3861d4fb85b1f14af82b6c098d10
+pixdesc-yuv422p9be 33d2d5ea6f00f36c7c28ebca9b097348
diff --git a/tests/ref/fate/filter-pixdesc-yuv422p9le b/tests/ref/fate/filter-pixdesc-yuv422p9le
index 154abce700..de4b7785d7 100644
--- a/tests/ref/fate/filter-pixdesc-yuv422p9le
+++ b/tests/ref/fate/filter-pixdesc-yuv422p9le
@@ -1 +1 @@
-pixdesc-yuv422p9le 77d1eb4547c7f1a22977924c154d049c
+pixdesc-yuv422p9le e0a3b15393d266b50c31dabcd3c5697b
diff --git a/tests/ref/fate/filter-pixdesc-yuv440p b/tests/ref/fate/filter-pixdesc-yuv440p
index dd9a59c064..b2ef32399e 100644
--- a/tests/ref/fate/filter-pixdesc-yuv440p
+++ b/tests/ref/fate/filter-pixdesc-yuv440p
@@ -1 +1 @@
-pixdesc-yuv440p 7f3e289e7109a051379313933e6e430f
+pixdesc-yuv440p 155eec1fc346090dab79d25cf1a3902a
diff --git a/tests/ref/fate/filter-pixdesc-yuv440p10be b/tests/ref/fate/filter-pixdesc-yuv440p10be
new file mode 100644
index 0000000000..b3a49414b4
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv440p10be
@@ -0,0 +1 @@
+pixdesc-yuv440p10be 3ad2b1fd9659be2f2f0a1d824c1bdede
diff --git a/tests/ref/fate/filter-pixdesc-yuv440p10le b/tests/ref/fate/filter-pixdesc-yuv440p10le
new file mode 100644
index 0000000000..99924dbfa1
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv440p10le
@@ -0,0 +1 @@
+pixdesc-yuv440p10le 657aa6e83f5bcd91c1feab2c6d2db8e8
diff --git a/tests/ref/fate/filter-pixdesc-yuv440p12be b/tests/ref/fate/filter-pixdesc-yuv440p12be
new file mode 100644
index 0000000000..9c4db9ae7e
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv440p12be
@@ -0,0 +1 @@
+pixdesc-yuv440p12be 3c1ae4bdffe084ad574eff46bd88d556
diff --git a/tests/ref/fate/filter-pixdesc-yuv440p12le b/tests/ref/fate/filter-pixdesc-yuv440p12le
new file mode 100644
index 0000000000..c2b6e53f20
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv440p12le
@@ -0,0 +1 @@
+pixdesc-yuv440p12le ac9101bdea22b00dc24d4975935425bb
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p b/tests/ref/fate/filter-pixdesc-yuv444p
index 2ef114a132..28bb87a075 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p
+++ b/tests/ref/fate/filter-pixdesc-yuv444p
@@ -1 +1 @@
-pixdesc-yuv444p 37edfdeae2a93c91209e806cd9e0ceee
+pixdesc-yuv444p d8401af0780d85b75769571a07fa8538
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p10be b/tests/ref/fate/filter-pixdesc-yuv444p10be
index 05c346ec0e..f6c2c20e55 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p10be
+++ b/tests/ref/fate/filter-pixdesc-yuv444p10be
@@ -1 +1 @@
-pixdesc-yuv444p10be df6bd44006a00116c4b805e0c83a98ba
+pixdesc-yuv444p10be 05f72cb93495d28ad032a54ad5b69cc5
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p10le b/tests/ref/fate/filter-pixdesc-yuv444p10le
index 57c5161b26..e412cd155c 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p10le
+++ b/tests/ref/fate/filter-pixdesc-yuv444p10le
@@ -1 +1 @@
-pixdesc-yuv444p10le 94c579bd8e88f271cd193be222f93694
+pixdesc-yuv444p10le 8f34212f8f9b95c9266cf7cd62eeae3f
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p12be b/tests/ref/fate/filter-pixdesc-yuv444p12be
new file mode 100644
index 0000000000..832b2457ec
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p12be
@@ -0,0 +1 @@
+pixdesc-yuv444p12be 24540e0c367e31a66f3ba40a6b847600
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p12le b/tests/ref/fate/filter-pixdesc-yuv444p12le
new file mode 100644
index 0000000000..f29ad77690
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p12le
@@ -0,0 +1 @@
+pixdesc-yuv444p12le 15d9282fae68c44f17005e5eb15bc7e7
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p14be b/tests/ref/fate/filter-pixdesc-yuv444p14be
new file mode 100644
index 0000000000..e138abd6aa
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p14be
@@ -0,0 +1 @@
+pixdesc-yuv444p14be 682673e893053a3a3d61dacb5212112e
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p14le b/tests/ref/fate/filter-pixdesc-yuv444p14le
new file mode 100644
index 0000000000..0c30509b69
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuv444p14le
@@ -0,0 +1 @@
+pixdesc-yuv444p14le 9e9edf45e52df28d1b74e032815ad17f
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p16be b/tests/ref/fate/filter-pixdesc-yuv444p16be
index c8f19f4442..c79078000b 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p16be
+++ b/tests/ref/fate/filter-pixdesc-yuv444p16be
@@ -1 +1 @@
-pixdesc-yuv444p16be 8172616c2590bfe95fb3115684b3bf06
+pixdesc-yuv444p16be 5cea1d7afdc3d7b47043947eb61de666
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p16le b/tests/ref/fate/filter-pixdesc-yuv444p16le
index f4402bf83f..5b5e1f2e99 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p16le
+++ b/tests/ref/fate/filter-pixdesc-yuv444p16le
@@ -1 +1 @@
-pixdesc-yuv444p16le 0cb500e7313e15513c5510edae51d46c
+pixdesc-yuv444p16le 4fbf077117a0cadf4d277e99ebf254d6
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p9be b/tests/ref/fate/filter-pixdesc-yuv444p9be
index ad8ed8b0e7..d6b0ea94e5 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p9be
+++ b/tests/ref/fate/filter-pixdesc-yuv444p9be
@@ -1 +1 @@
-pixdesc-yuv444p9be 6410ac29a501711ac3d7485adbee0736
+pixdesc-yuv444p9be ec5b450a8c0d4097fc15d5f8e62a045a
diff --git a/tests/ref/fate/filter-pixdesc-yuv444p9le b/tests/ref/fate/filter-pixdesc-yuv444p9le
index dcf05e95bb..f24ca35610 100644
--- a/tests/ref/fate/filter-pixdesc-yuv444p9le
+++ b/tests/ref/fate/filter-pixdesc-yuv444p9le
@@ -1 +1 @@
-pixdesc-yuv444p9le ed579c47f3a0cdb481a886e2b3192c42
+pixdesc-yuv444p9le cca3bc99d4f3d5f3a7c87d95d444731d
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p b/tests/ref/fate/filter-pixdesc-yuva420p
index 49d5485dae..9b60dfb901 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p
+++ b/tests/ref/fate/filter-pixdesc-yuva420p
@@ -1 +1 @@
-pixdesc-yuva420p 43d7123392af51a8716447a7dd69608b
+pixdesc-yuva420p 3f4612e9436065a77a40945a71fdc0b8
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p10be b/tests/ref/fate/filter-pixdesc-yuva420p10be
index 6ed19b1fd0..75526a765f 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p10be
+++ b/tests/ref/fate/filter-pixdesc-yuva420p10be
@@ -1 +1 @@
-pixdesc-yuva420p10beb3d4763eae9de728a4e10ddc89a18cf6
+pixdesc-yuva420p10beeea756629ceb059a9368899ebe8623d7
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p10le b/tests/ref/fate/filter-pixdesc-yuva420p10le
index d4f21a0774..d60dc0ba0d 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p10le
+++ b/tests/ref/fate/filter-pixdesc-yuva420p10le
@@ -1 +1 @@
-pixdesc-yuva420p10leaa8d76f2871dc8f9a20919a2f13688ec
+pixdesc-yuva420p10leca41b24346d7b71baff040d8e05d1c99
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p16be b/tests/ref/fate/filter-pixdesc-yuva420p16be
index 077eab5697..1d5b5c59e1 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p16be
+++ b/tests/ref/fate/filter-pixdesc-yuva420p16be
@@ -1 +1 @@
-pixdesc-yuva420p16beaba97863a5e670a2a6b772cf82940e04
+pixdesc-yuva420p16be62309264f29a79ffe2c7e224a49afb10
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p16le b/tests/ref/fate/filter-pixdesc-yuva420p16le
index 3fb3a2e260..144b7b0630 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p16le
+++ b/tests/ref/fate/filter-pixdesc-yuva420p16le
@@ -1 +1 @@
-pixdesc-yuva420p16leb1680b05ce69447bdc53dec154addc0a
+pixdesc-yuva420p16le8e3f544099b9b92421fae4147bb64892
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p9be b/tests/ref/fate/filter-pixdesc-yuva420p9be
index 1004d313f9..5e1b048b44 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p9be
+++ b/tests/ref/fate/filter-pixdesc-yuva420p9be
@@ -1 +1 @@
-pixdesc-yuva420p9be 3c9ce8191c1510b35fee892ad15d39b9
+pixdesc-yuva420p9be daadd46290d54a592bb1c0e657001e06
diff --git a/tests/ref/fate/filter-pixdesc-yuva420p9le b/tests/ref/fate/filter-pixdesc-yuva420p9le
index 8ed1daff22..8e8fda2a56 100644
--- a/tests/ref/fate/filter-pixdesc-yuva420p9le
+++ b/tests/ref/fate/filter-pixdesc-yuva420p9le
@@ -1 +1 @@
-pixdesc-yuva420p9le 1955fb115953284ea0ecdc0d4b10e0ae
+pixdesc-yuva420p9le e417b7c2a5d18768dd42f44c50a67a47
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p b/tests/ref/fate/filter-pixdesc-yuva422p
index df5a856760..ad0c619432 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p
+++ b/tests/ref/fate/filter-pixdesc-yuva422p
@@ -1 +1 @@
-pixdesc-yuva422p 639ce1131de9b362d18b3dc7f871c1ae
+pixdesc-yuva422p 1faf18b3fef6c3792d8e2f1ac6e7490a
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p10be b/tests/ref/fate/filter-pixdesc-yuva422p10be
index 601e66f2c5..d3ffa81fa6 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p10be
+++ b/tests/ref/fate/filter-pixdesc-yuva422p10be
@@ -1 +1 @@
-pixdesc-yuva422p10bec797caa09ee483d6cc0b06eac7fc606b
+pixdesc-yuva422p10be48269e4c136138ebf989f3829b636136
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p10le b/tests/ref/fate/filter-pixdesc-yuva422p10le
index 9b4b1c39dc..59cd80ce83 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p10le
+++ b/tests/ref/fate/filter-pixdesc-yuva422p10le
@@ -1 +1 @@
-pixdesc-yuva422p10le61a6339e7321972ee6f45428bd55a8f3
+pixdesc-yuva422p10le1e9a7ea03647cb6d8f5a4cb3085124e3
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p16be b/tests/ref/fate/filter-pixdesc-yuva422p16be
index 1c651d1de3..fbcbaf779d 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p16be
+++ b/tests/ref/fate/filter-pixdesc-yuva422p16be
@@ -1 +1 @@
-pixdesc-yuva422p16be01381b27508afbca57241d7431da7ba9
+pixdesc-yuva422p16be3ed898fd49bb4210a1c204a555c63997
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p16le b/tests/ref/fate/filter-pixdesc-yuva422p16le
index 1f1f1d3c17..ebadc1b220 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p16le
+++ b/tests/ref/fate/filter-pixdesc-yuva422p16le
@@ -1 +1 @@
-pixdesc-yuva422p16lef5c8d306a099d594749ddebeb279b259
+pixdesc-yuva422p16led3ca3020575d91f2a9bf27eaf3c9bce6
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p9be b/tests/ref/fate/filter-pixdesc-yuva422p9be
index ff6514cab4..6f2e248040 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p9be
+++ b/tests/ref/fate/filter-pixdesc-yuva422p9be
@@ -1 +1 @@
-pixdesc-yuva422p9be eb35d12008a9dce4ff860951ded90edb
+pixdesc-yuva422p9be a9da61fa1aecb8c8f55eff08a89f8f4d
diff --git a/tests/ref/fate/filter-pixdesc-yuva422p9le b/tests/ref/fate/filter-pixdesc-yuva422p9le
index 22003df83d..7414ca1bea 100644
--- a/tests/ref/fate/filter-pixdesc-yuva422p9le
+++ b/tests/ref/fate/filter-pixdesc-yuva422p9le
@@ -1 +1 @@
-pixdesc-yuva422p9le e97bd27f580cd46ee3feb2ba3c8c057d
+pixdesc-yuva422p9le bd427a5fd70aa2e07aa5869dcd9d7d17
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p b/tests/ref/fate/filter-pixdesc-yuva444p
index 56bc201812..a2b8c01fe6 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p
+++ b/tests/ref/fate/filter-pixdesc-yuva444p
@@ -1 +1 @@
-pixdesc-yuva444p d78d51ee6286394b1f1839dd74d68861
+pixdesc-yuva444p 7ce64f043f8d3658c7c627d2163ad19f
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p10be b/tests/ref/fate/filter-pixdesc-yuva444p10be
index 89df14f6cb..737b49cbe2 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p10be
+++ b/tests/ref/fate/filter-pixdesc-yuva444p10be
@@ -1 +1 @@
-pixdesc-yuva444p10be32f40553f2d8d771561d4f6f8514e1e8
+pixdesc-yuva444p10beadba33abe66edb10474ca6e81a05b5aa
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p10le b/tests/ref/fate/filter-pixdesc-yuva444p10le
index cb4b6634aa..3737a367e0 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p10le
+++ b/tests/ref/fate/filter-pixdesc-yuva444p10le
@@ -1 +1 @@
-pixdesc-yuva444p10le1bb71c784b65cdcb06408a37c2fa2eef
+pixdesc-yuva444p10lea649ca6173037030cae3d21936d3b19d
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p16be b/tests/ref/fate/filter-pixdesc-yuva444p16be
index a9bffff95b..fb26bb2017 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p16be
+++ b/tests/ref/fate/filter-pixdesc-yuva444p16be
@@ -1 +1 @@
-pixdesc-yuva444p16beb52b5efbad264a6a8aa7280234e0c9d6
+pixdesc-yuva444p16bede8077bfb08bc61284b23db5d524563b
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p16le b/tests/ref/fate/filter-pixdesc-yuva444p16le
index 249090cd57..6182e4cabc 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p16le
+++ b/tests/ref/fate/filter-pixdesc-yuva444p16le
@@ -1 +1 @@
-pixdesc-yuva444p16le54d4ab00bb5a0e7228a974d27b59285c
+pixdesc-yuva444p16lecf80d3441689eca8cd5fe007c4091c35
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p9be b/tests/ref/fate/filter-pixdesc-yuva444p9be
index 041a57bcf4..7a6ec9f934 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p9be
+++ b/tests/ref/fate/filter-pixdesc-yuva444p9be
@@ -1 +1 @@
-pixdesc-yuva444p9be 0139f53dd39f1538648c5be2f38fb3ed
+pixdesc-yuva444p9be 0f5d25349e3fd1e0580300b3a36724ac
diff --git a/tests/ref/fate/filter-pixdesc-yuva444p9le b/tests/ref/fate/filter-pixdesc-yuva444p9le
index 71e449036c..579c1f6415 100644
--- a/tests/ref/fate/filter-pixdesc-yuva444p9le
+++ b/tests/ref/fate/filter-pixdesc-yuva444p9le
@@ -1 +1 @@
-pixdesc-yuva444p9le 6f16075ddc120457eef912beb20ed546
+pixdesc-yuva444p9le 46e052f61b8cebd4b016836857f54b39
diff --git a/tests/ref/fate/filter-pixdesc-yuvj411p b/tests/ref/fate/filter-pixdesc-yuvj411p
new file mode 100644
index 0000000000..5dfc0dc4cd
--- /dev/null
+++ b/tests/ref/fate/filter-pixdesc-yuvj411p
@@ -0,0 +1 @@
+pixdesc-yuvj411p cac93399031ad86e8de0796b60b5bb8a
diff --git a/tests/ref/fate/filter-pixdesc-yuvj420p b/tests/ref/fate/filter-pixdesc-yuvj420p
index d31bdfc3d4..ad2f968a1f 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj420p
+++ b/tests/ref/fate/filter-pixdesc-yuvj420p
@@ -1 +1 @@
-pixdesc-yuvj420p 6cb083afe6e0b54ba9753744194ca765
+pixdesc-yuvj420p 5244374882cf07c3cbcde71940caf8e5
diff --git a/tests/ref/fate/filter-pixdesc-yuvj422p b/tests/ref/fate/filter-pixdesc-yuvj422p
index 1480ae5088..5f80d585d6 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj422p
+++ b/tests/ref/fate/filter-pixdesc-yuvj422p
@@ -1 +1 @@
-pixdesc-yuvj422p 6b2dfa7e50dfe279cd73eeaf9b767dc0
+pixdesc-yuvj422p 6c9722aa9e0c1b8f9d953efeb93dc318
diff --git a/tests/ref/fate/filter-pixdesc-yuvj440p b/tests/ref/fate/filter-pixdesc-yuvj440p
index 480017f823..c98669285b 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj440p
+++ b/tests/ref/fate/filter-pixdesc-yuvj440p
@@ -1 +1 @@
-pixdesc-yuvj440p 278317b4ff8b272b22465481d3673a7c
+pixdesc-yuvj440p 34e6e86ca3ec4e6ef62d533aa2290e8f
diff --git a/tests/ref/fate/filter-pixdesc-yuvj444p b/tests/ref/fate/filter-pixdesc-yuvj444p
index 5f6c301466..3e182fa6e2 100644
--- a/tests/ref/fate/filter-pixdesc-yuvj444p
+++ b/tests/ref/fate/filter-pixdesc-yuvj444p
@@ -1 +1 @@
-pixdesc-yuvj444p a56b1f49af0a7a42794d92bea3eca9c9
+pixdesc-yuvj444p f67694103bb42d74742918adf9ea31c5
diff --git a/tests/ref/fate/filter-pixdesc-yuyv422 b/tests/ref/fate/filter-pixdesc-yuyv422
index 434a880e72..334aa2d500 100644
--- a/tests/ref/fate/filter-pixdesc-yuyv422
+++ b/tests/ref/fate/filter-pixdesc-yuyv422
@@ -1 +1 @@
-pixdesc-yuyv422 d154fdb0bd0258f1a0cdeaaaefa21581
+pixdesc-yuyv422 edb8aa7b424e4d810ed500fd1ea0268b
diff --git a/tests/ref/fate/filter-pixdesc-yvyu422 b/tests/ref/fate/filter-pixdesc-yvyu422
index cac9726d5a..f23eb87aae 100644
--- a/tests/ref/fate/filter-pixdesc-yvyu422
+++ b/tests/ref/fate/filter-pixdesc-yvyu422
@@ -1 +1 @@
-pixdesc-yvyu422 24f0a489853ededa47cd7386c116fb3f
+pixdesc-yvyu422 f8ac718bb6a56ccd9ab91c68d01986de
diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy
index 2f6a71e8e1..6281711ac6 100644
--- a/tests/ref/fate/filter-pixfmts-copy
+++ b/tests/ref/fate/filter-pixfmts-copy
@@ -1,91 +1,123 @@
-abgr 1250387304351fea5cc57b232bc0a5e5
-argb ee5a1e2e2d4dbd2cd978d6e3bf8dee70
-bgr24 437ea8de747009d73f41af120f0360ad
-bgr444be 0a9b7c91c6f50c0ed2633aebd19d7326
-bgr444le f032368a3134918e6802922e4cde7baf
-bgr48be bf24403f14d4085f970475dd17a9edcd
-bgr48le 1db5661da851a44dd5b92f8dd5a0ec84
-bgr4_byte 2bf8e7fbf1179ba0543cb42d2d8a5308
-bgr555be b8b23bcfa9a850d46850d59662e6eba8
-bgr555le d72c90906cb4df818abb37fb07a67d01
-bgr565be 0fcba91cb4c55a458271173cb26e649d
-bgr565le 6a0d182c7165103b2613d1805c822f9f
-bgr8 36b9ef72c87da36ac547202d85a5805f
-bgra 56e6e1bfde40aaa27473e01b46345c82
-gbrap 57cb1a02d6f015a4329fe367f3bdfe49
-gbrp d5f73b5d3ba7f6cadbc9b4ecbc161005
-gbrp10be eb19bda60ab7f893198364dff21342d6
-gbrp10le 546146efb36ad2605e9f74ee5e4c2a36
-gbrp9be cbe1bf8ead497a92362a749bd4b0a57e
-gbrp9le f88c68df5d699a4a7f1b0152df9f25fe
-gray 8c941e9bbf6da5336384c57f15a4a454
-gray16be 43bda75c197b0d59a9b87ee941553644
-gray16le a4ea1369ef1efff0e1341a1dc42dbfdf
-monob e13b2cbfb93d3ed6fdc1f256662ea959
-monow 87a594c125f52af67dc1dd51d800ff31
-nv12 a0b3578ec9b28be3d6e66479df8b1995
-nv21 a9318dc58dc14b9931a00ea6cedea849
-rgb24 fc0c7ce1d5d6be1b89d4471542785508
-rgb444be cc479f17c73cd50d65475a1644c5053f
-rgb444le c98bc1811d29a86471357cb2358e5a30
-rgb48be 1e2a176dadf246e376932a20303ca572
-rgb48le 57fd6d93cda99070acc4213b6958fe70
-rgb4_byte e4dcdc9adddcb3958ddd0ea3b0896140
-rgb555be 8fd499c9a6d98414ab2803ae08698651
-rgb555le a9b93f8b61e52eac76aca392dc3ebd81
-rgb565be a8c6c7817f80c8a0cee9918c3748e00c
-rgb565le 510a4ce796d7cb11aba5b25b419cdf3b
-rgb8 2e53d27e93554f874986fbba4f9d6354
-rgba ed87fc4907951608893b421624716f9b
-uyvy422 deb3625b67a8d2a51c17a322ad2021ba
-yuv410p dec949ce1d8a5f7bb1aa7640f97e05eb
-yuv411p fc2f303b20ae610dce86dae4a6671881
-yuv420p a2117c3c5d4533dca311dc94a3d157bc
-yuv420p10be 7756ef359f79d63ef6f983caeaba5c51
-yuv420p10le aa8abcc05010b4b0df7d924fd5887291
-yuv420p16be 7a708532d8ac26d598ac7332e38dd2de
-yuv420p16le 6b868d3b0c44c6b04f39415890d6ee0b
-yuv420p9be 11ffb289661f4f55347d60e99dcef632
-yuv420p9le a0c9608b2be3ca6d4e8cf625714a3833
-yuv422p b082344038849f5fd444ccf2a30e3f4f
-yuv422p10be 43a6293e138d0ecfd3385df3dcf9b713
-yuv422p10le 74da030a4efb5a20986fcead50018f4d
-yuv422p16be f7a0fb9e82805660317d07209e726100
-yuv422p16le 12eeb2f95bb0d655d52e8eed1cfbf771
-yuv422p9be 60daf1a7e61434b244c5a43f4449b617
-yuv422p9le 4c4885c48812f5ac0916a9509ba84345
-yuv440p 12000ce709b38aac3f7b7f59b07847ef
-yuv444p 628c9d1e10c22e0e512b27c0e03b46e6
-yuv444p10be b60d77db54a592ed088ebf7964e2dd5e
-yuv444p10le 1752a238eb27fb7c746e349536f60686
-yuv444p16be 8e1e2f04cb2e97f80fdfecbb2c5679a0
-yuv444p16le 5677b2caa63e0c075eac6937b03cf2a6
-yuv444p9be 5ab55576b180b2966e9ed5a1ea55508a
-yuv444p9le 3d9b69b8d6e17f2d25ce92602688bcc8
-yuva420p 9e9889ad7837b0d0dde023bf931ed639
-yuva420p10be ff20f57da08f79e44e7b603e89b18d74
-yuva420p10le a2dcfa563602232d999a19b7ae272131
-yuva420p16be 63bd8a57eedfc58e8e6319913ee1064c
-yuva420p16le 797dc4ff3a9a3f36cb84ddd808a1c04a
-yuva420p9be d2de221d375fea605a9f81c9e0fd3661
-yuva420p9le 0dd82737677f2b604a0aaa638e65f64a
-yuva422p 375465ec39a82221a4a502e92bf0453f
-yuva422p10be 81144a6638bc34bd9e6790977159a754
-yuva422p10le b30c735f71275004d2d7d78ec647fd5b
-yuva422p16be b7641ec1896f306065073f0348448f19
-yuva422p16le 3ab82ddf757a78f0184c01aa0259fc42
-yuva422p9be dd2a4affd2140d945c88c545cbd15794
-yuva422p9le a7a00cf6c696e8e94ce62576dbb28527
-yuva444p 8031aee1a4a13d679e3fa960b70e27c7
-yuva444p10be 62dc7423df2a90da591e313dea0f72b0
-yuva444p10le e45e36e79e39e1ed300fc93bc20a2232
-yuva444p16be c2321be5e7184b874cf4e16fff959179
-yuva444p16le 107836d19b0735f225eb7d97da98fd49
-yuva444p9be d8ba268bef3cf8d2dbd57a65b49be6db
-yuva444p9le f4589d40b7514e021ec7096003907ef7
-yuvj420p 9ba65711dfe07d3078b5b874b49240fb
-yuvj422p 05873ba9f14597ded3d4a2f6e1cd7e5c
-yuvj440p d76a421f62d692c664cbb2d1727e77d2
-yuvj444p 787e53351113065777bd1061ddb04834
-yuyv422 48d652c76bbdebec0bf7842578b39c53
-yvyu422 b0364ee13bd574d01b23a0809e6ddca9
+0bgr 4060279c35dd8810a2f55a021b836557
+0rgb 527ef3d164c8fd0700493733959689c2
+abgr 023ecf6396d324edb113e4a483b79ba2
+argb f003b555ef429222005d33844cca9325
+bgr0 6fcd67c8e6cec723dab21c70cf53dc16
+bgr24 4cff3814819f02ecf5824edfd768d2b1
+bgr444be 1cd47c1555f947dfcba99192e3429d20
+bgr444le e1832fdc9b118d4440ba03cea6e30428
+bgr48be 51477f029592ddb6b912980fdf2df7f1
+bgr48le b34faf404b33c74cd25f5f912ca3274c
+bgr4_byte 7ca99bc8a1c7c831cb955806ac05cb72
+bgr555be 6d32031ad4f52723023e547058a62c71
+bgr555le 823a3b2f2585e537da5cb76c8ce30cf4
+bgr565be 438b0f18fd754280d5dc2f421c376ffb
+bgr565le acab2b65c0fe5f9618c90f77f70ab3be
+bgr8 898a66734bda0572dfab1edd8239f6a2
+bgra 3934fb81a602dfa7d29420b1a66f0fd8
+bgra64be c8d3217bf58d34f080ac88c0b0012c77
+bgra64le b71d75a928aac14cb768403e6f6a9910
+gbrap ae09c3e9dcbe0d1ef21b2342be369210
+gbrp 5fbc319e30110d19d539f5b274eddb6d
+gbrp10be e71e0dc9c54419297e97a895bf57ab1c
+gbrp10le 11fb697197e79d27eeba4093a207e015
+gbrp12be 2a611bff3b8f63e1d99d0b0f5082eaed
+gbrp12le bd4529ca9bd680d23a16ec65fdfb313b
+gbrp14be b8ccc776dd1e57c39386d3cb5bdbe899
+gbrp14le 74431dd00ddf10d94d1db1496d10e42f
+gbrp9be 6d45b61c48b40c83b43cf2d4ecf4dc32
+gbrp9le bc80da439638c59f1d822037f52739af
+gray 188590b1231afd231ea910815aef2b25
+gray16be 08d997a3faa25a3db9d6be272d282eef
+gray16le df65eb804360795e3e38a2701fa9641a
+monob a6869bab4f6e64fe13dcab13b41775b3
+monow 0404328f1838a6503371478a559ca20d
+nv12 8e24feb2c544dc26a20047a71e4c27aa
+nv21 335d85c9af6110f26ae9e187a82ed2cf
+pal8 d9a58fa1964ba9a3b902797b0b1af0ab
+rgb0 0de71e5a1f97f81fb51397a0435bfa72
+rgb24 f4438057d046e6d98ade4e45294b21be
+rgb444be 115e5259b91f4a416546b09570347633
+rgb444le f3f66689cb4c810563fba7665c526800
+rgb48be 18127d8ec64aa21619ada80b93514906
+rgb48le 60d0ba0e5a429c947aaa736be54aca87
+rgb4_byte 7d68393a3de6f392cf2ed05ffaec6259
+rgb555be f76c8109974636b54bd0cb4c36bb883d
+rgb555le 21daf4d05999ccf3eef7d492e73c4d5b
+rgb565be 85711f35f71340ba23e553a07d246656
+rgb565le e04771e79a8ee8a51e9a325540e6215e
+rgb8 7ac6008c84d622c2fc50581706e17576
+rgba b6e1b441c365e03b5ffdf9b7b68d9a0c
+rgba64be ae2ae04b5efedca3505f47c4dd6ea6ea
+rgba64le b91e1d77f799eb92241a2d2d28437b15
+uyvy422 3bcf3c80047592f2211fae3260b1b65d
+xyz12be a1ef56bf746d71f59669c28e48fc8450
+xyz12le 831ff03c1ba4ef19374686f16a064d8c
+yuv410p 5d4d992a7728431aa4e0700f87fb7fd8
+yuv411p 7e1300e89f5bc07939e2c4a6acbdf267
+yuv420p a014c7eb7a8385d1dd092b7a583f1bff
+yuv420p10be f9b154364efaa1af376fa6d8eeae6955
+yuv420p10le 15c83294ef560d57f25d16ae6e0fc70c
+yuv420p12be 34da9c4e289124122ba36a9d4fb133fa
+yuv420p12le c19a477a07fcf88e37ab37b416d064c0
+yuv420p14be 64779858686946fc0e780baf7c1391b6
+yuv420p14le c1d012a4f9d54fbc8b04fea96d85e903
+yuv420p16be 268b07358d8dc733ee81d0b87990d5af
+yuv420p16le dae8da9edd4255051e3e546ae7ed9bd3
+yuv420p9be e86ecd4112c86637c96f2b5e90341da1
+yuv420p9le 4496bea8504dce651485cc8a7e8403c9
+yuv422p 74f8006b4482db104f1986f49807a0af
+yuv422p10be 7291903c3c0cf4e5456dd9673a619f1d
+yuv422p10le 14cbaa728e888534359b9dddc5430f08
+yuv422p12be e9bc7f2da217fade40feb6960dcd894e
+yuv422p12le 8d8184e4d0f1eb50e1834ac0c4af8c33
+yuv422p14be 2617c569ae9659d8fe6a01f96e2c9657
+yuv422p14le 7d01363cf090306cf93337c474cd8827
+yuv422p16be 86147d8bfb795ab1873c899611e2a361
+yuv422p16le 9df47cb7d6d39b335a547ced2865e72e
+yuv422p9be fdd15494de6cfc8c3f15650ecd3d8046
+yuv422p9le a112fd777494d203d9d8e9623a50e503
+yuv440p 98d0f96fdb3ba415899017adf7d4a4f9
+yuv440p10be d874167042037c1daf9b9a2f74bffad9
+yuv440p10le 3cfbd921369aa8f1e4977efdb7f44c8c
+yuv440p12be dc3e6a40c44d5a5f9fd260b270e9037f
+yuv440p12le 2fff7746ae7c07d407075c0e372baf46
+yuv444p 8f90fb3a757878c545a8bfe5d19a9bab
+yuv444p10be 6683d5cb82c708d5f3a2a89d0311f7a4
+yuv444p10le 6d736fa464ff2de2b07e0a56af8444b7
+yuv444p12be 04320ad158450ee158f84a27c6325702
+yuv444p12le 08a81b2ea9c7c8b447e40ef8f4a46a4a
+yuv444p14be ea3057d469d0c49c24e844256ef7871e
+yuv444p14le 940f5908ccf06e01411f0a7bddb45c6a
+yuv444p16be aee24ab2e9a4656f889399f1b0d98639
+yuv444p16le 781c22317c02b3dd4225709000bdb847
+yuv444p9be c37eb400483012fd97a030431818f328
+yuv444p9le 2136d762328cb9ce168b6261b7874791
+yuva420p b227672e56215e184e702c02a771d7f3
+yuva420p10be f66e7d677625380f7504867fab51305c
+yuva420p10le 01e94ee605714396e69b013c11dda348
+yuva420p16be 76e5e65eae1e7c5681a397a3462f4a9d
+yuva420p16le b1930ab28ffe031c78ca28d3406311c8
+yuva420p9be 48dfa24cf0ea3864f35285074e8fa888
+yuva420p9le 0e9c9803aaaddc9f38e419de587793c2
+yuva422p 8f6bb778647e5dee62f544d646321171
+yuva422p10be 2f7204c93a1e5bfb04538852f99e4074
+yuva422p10le c8082548aca999edde77ef2749b1ff4c
+yuva422p16be 427ad55f7464121bb3ce164641772bc6
+yuva422p16le af6f8df651275de58129e010bb45ffcd
+yuva422p9be 47579cc2cea861ca1461589b80c4720f
+yuva422p9le aaeab2bfe80a29390e8666103ed8bb40
+yuva444p 459fad5abfd16db9bb6a52761dc74cc1
+yuva444p10be fa16bae4fc25429deb944ffa9f5b28a0
+yuva444p10le 92f820d3481b7ebcb48b98a73e7b4c90
+yuva444p16be c80c1899789a6411d0025730efc8f01c
+yuva444p16le 2ed56ea50fafda4d226c9b133755dad8
+yuva444p9be 4903fde22b15d28da90761ac1cfcb1c5
+yuva444p9le 4eeb5988df0740fea720da1e31bbb829
+yuvj411p e003eefa7e2a20f20d33767775417216
+yuvj420p 8f3d8f1b4577d11082d5ab8a901e048d
+yuvj422p 79d480e99e610112f266c833c6cb3d35
+yuvj440p f4b18310c7174868fc92579f87460876
+yuvj444p b161e6d5a941e2a4bb7bc56ef8af623f
+yuyv422 435c92283b538aa3d8fa2a020b0afd49
+yvyu422 8436c2a760291cc979e0dd62ab8cede0
diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop
index c42c620265..1b1a763ee6 100644
--- a/tests/ref/fate/filter-pixfmts-crop
+++ b/tests/ref/fate/filter-pixfmts-crop
@@ -1,42 +1,118 @@
-abgr 5f70a21347bce16111a36fc41a117df8
-argb 35801018bb35dcb0ee31f66f0090b890
-bgr24 f9cc271089a5b560f29d9614f357c720
-bgr48be 8d957f7b11ed446dcea5f76c164f2368
-bgr48le 2a72cdae677d2c190b5beefd7e8a0e53
-bgr4_byte 8612d21fb5c353bdcf3eecb66a0bb0c3
-bgr555be 5c6c82ba788553cab28794c7c4707558
-bgr555le 326db2c29c70aef71b5d408dd6ca8c86
-bgr565be 035910ec94dbca6dae1e81f26852bcc3
-bgr565le 84dec346512486158c7d65299e62e924
-bgr8 e6d8896ccbe02c04d208bae55fc221c4
-bgra cfc8cdc70ed29bc206dbc907495d0869
-gray ccac69ad220529826be3d94d29157e8d
-gray16be a8f761dc9e6dad62d1e4459eec9baf07
-gray16le 8b480306cb5584bc85fb51d1ea97b8f4
-rgb24 b85c0b1e6039a971bdef1d710bf7f8d3
-rgb48be 5ea361c8fbff68868e20385508b63181
-rgb48le 5966526796a37f871fd0831c41ddd3dc
-rgb4_byte 774ca7852d51ae52462b0360112e143f
-rgb555be c4bd32793895432e6c2f1c4e2b6c4e94
-rgb555le a320a2e210e4e9f1352ffa8af2793b27
-rgb565be dc1440a7832c7ff781bbbd62dbadf6b1
-rgb565le 64f2ebebb02c2ac8eab2ed708c297fa4
-rgb8 ebc7118d01e82b77b8aeddb1f83a2872
-rgba 32bdb0cf19af40203515fd83c6cec8c8
-yuv410p 006e5b4735797ff0e7e3c7dd27660a8e
-yuv411p 894e368ed68876e357f095a8b2a7b3a7
-yuv420p d9641cbe8436380d8505ddd695b0a7d2
-yuv420p16be 8b7ad840e9079a19da1bfed79a448847
-yuv420p16le 8827ee2f20ee18bae143b9b38b0f8622
-yuv422p 31277ec25cbb0c43eb57d4f29047a267
-yuv422p16be 49cdcc490b4e87a65eef88feacdb87d2
-yuv422p16le e634bdf11b047f3641fb0de1eb0feb57
-yuv440p f9340d3797c3b3446bc830e4e198d5be
-yuv444p 43bf7b75708d62f0f02fb3f6b8dd3bba
-yuv444p16be 8dc374395cd1f31e52609089c54c9908
-yuv444p16le 285df61fab70499218677c1eed4db448
-yuva420p a8d2c50df5fe5808b7057727699640f3
-yuvj420p cc464c6e15079539b907414b5aaa32e0
-yuvj422p 7ee6bd168e2ae34eabb6ae617f02739e
-yuvj440p 35a50b3b8ca637fbf5ad581fa742ad34
-yuvj444p 5dbd0537a42bedcf941fb27f74b54b69
+0bgr 8a83998de96327cb334538d7a265304e
+0rgb 974833c777e6abe6d84dc59af2ca5625
+abgr 1d21f5b8a20186ac9dd54459c986a2a7
+argb 8b822972049a1e207000763f2564d6e0
+bgr0 38a84849a9198667c348c686802e3b52
+bgr24 1dacd8e04bf0eff163e82250d01a9cc7
+bgr444be e2d2b864dfa528e77684ddc117f2d974
+bgr444le 5f48e6dc70fdbf4ef6d651081f104a2f
+bgr48be 61b6a1a7c6d523b7e594f63790c7f032
+bgr48le 2b158ebcd483e03abea86c32abd21642
+bgr4_byte 441c4d66a344babfbbd3e4767413893b
+bgr555be c5480b08d681d33ae29148054762bcfb
+bgr555le 500a2ed02aa57f7635125e6c983702db
+bgr565be 2d4a32d7e3d994b21c400ad008a5cdf0
+bgr565le 14ed3f499e83ccb0cdbfa0a457557880
+bgr8 142275ecc024d3f7b66c168ac2279ae2
+bgra e66a5f68ba463cbc89fce23a61bb5203
+bgra64be 1ad8dd02714cafec793fb89577ddde47
+bgra64le dd29ec9aba43aa3e8f9f5b9a93ca8831
+gbrap da6be176149efdfecb2a690bc64a644e
+gbrp ec671f573c2105072ab68a1933c58fee
+gbrp10be 2a0f7e8216df19a835f086f5e552dbc8
+gbrp10le a15e4359b58c5d0fef301ee3c2c3b85c
+gbrp12be 520ddafabd9dbb34262f223c0cea9d96
+gbrp12le 295f6d5bf35a941e4db83c01744a3c19
+gbrp14be db73d2beadd837355c4cf08c33a631e4
+gbrp14le 76d4e3c0d2cad5c6cecac7fbc76645a7
+gbrp9be b9c9837b92fa8dc7e32dff986da87cdb
+gbrp9le 04e8e8a2863307d24de78466ecf536cb
+gray 0d70b54b4b888ec4dbd89713620ac1ee
+gray16be 38f599da990224de86e3dc7a543121a9
+gray16le 9ff7c866bd98def4e6c91542c1c45f80
+nv12 92cda427f794374731ec0321ee00caac
+nv21 1bcfc197f4fb95de85ba58182d8d2f69
+pal8 c89abc9660914b2e6c2e6f8c29e86503
+rgb0 736646b70dd9a0be22b8da8041e35035
+rgb24 c5fbbf816bb2000f4d2914e335698ef5
+rgb444be 44a33306889f7fa1a71ec831b860fd0a
+rgb444le 934708063a8ecb93b46f6ab7e828419c
+rgb48be 39ef8f30c85bbb58433df9c085f158a1
+rgb48le c92ee84f0952517a2830aa19166638a0
+rgb4_byte 847730fe0a7dc7fd99dd16599d6b828b
+rgb555be 39bb24bfcf01e379bd1653eb731ed21c
+rgb555le e9f1e9fc4d0ef9fe18f1771b21d02dbc
+rgb565be 974ddb6347a700a75eec014311725aaa
+rgb565le a0a2ce6d0907386f476364f9571ad3df
+rgb8 9b364a8f112ad9459fec47a51cc03b30
+rgba 9488ac85abceaf99a9309eac5a87697e
+rgba64be 89910046972ab3c68e2a348302cc8ca9
+rgba64le fea8ebfc869b52adf353778f29eac7a7
+xyz12be cb4571f9aaa7b59f999ef327276104b7
+xyz12le cd6aae8d26b18bdb4b9d068586276d91
+yuv410p 3bb6c7b64f2c46bc5e8b77198ce4ea58
+yuv411p 693e4afe96998e6dd91734037d75d887
+yuv420p 510d36163e4d3710988c23c2240ca6dc
+yuv420p10be ce9af476d924b463b0f68579f30a6463
+yuv420p10le 65214f2af95e816bbe303fa0649ecc84
+yuv420p12be f86f763eb2ae76d12226009e5f9595d7
+yuv420p12le 3741f6a4ccd368d0e9d00ecdebdde0c9
+yuv420p14be 5544e5fc40e718e608c0bd8c7b1d0812
+yuv420p14le 2c763a71c7c4650b91b405634556e21c
+yuv420p16be c22f72b460beef22b0bf80806c43b25f
+yuv420p16le 564d26a52ed271792e8909f8aa9a3e87
+yuv420p9be 4209e42b8f6cc7c123d6e65afba91528
+yuv420p9le c33dd96a3096bb776e01dc6aec740c4a
+yuv422p 42ea5e9a22df5913b2ec75512162e533
+yuv422p10be 3956017f5023ff5d56b4f814422dd711
+yuv422p10le a5fa7cb6a21bcbb60ae3ba4a9f4e60e0
+yuv422p12be 3a7cdaa7671394aae514d60c529e099d
+yuv422p12le 3369b2b6eed18a450ab0a5581335e375
+yuv422p14be 845c42b333e331a556008ef0a16afc85
+yuv422p14le abcdaccf8d01a9133daca94383d27db7
+yuv422p16be 565299a5d6265c77d00fd1a1d0173834
+yuv422p16le a3fc398dd11644235e260f7e82cc87e6
+yuv422p9be b402f27475dd7739f63510d08deb7001
+yuv422p9le f8603c35fe74a30d13d37e5bdadcf158
+yuv440p 11786b7e8f8f45fdeafe841a258fe5fd
+yuv440p10be 7c47e76d0430f2a1de2a1bfd50221c97
+yuv440p10le 6e501e62a7f84748338cdf19b0186a19
+yuv440p12be ab1c4c998c757b2e26d40575c5a6d0c9
+yuv440p12le 33c5cae9acde262b194efdf78ad44258
+yuv444p 28166fdead6f87f57f4c77156dce0466
+yuv444p10be 2c9b7f39c006b68d6b53791472ade1d5
+yuv444p10le 8427e65a1608ff8c5c88492f4926f6c1
+yuv444p12be 6e1f91ed1c6fc42fbc912d7d3aed0aca
+yuv444p12le 6a674498003ca57c8c2700b7d0ecb290
+yuv444p14be bb07382a868b35875b771b37dd234605
+yuv444p14le f8f6e6124bae7e95d0061b95bd64be66
+yuv444p16be 25b9244db531ccab7095a44b3115032d
+yuv444p16le b537ff9b2ef601b8568ffef2fdc4281b
+yuv444p9be 082a56901b11ed2508c1f0b7b6f25c02
+yuv444p9le 678f94003f4051dfa6b8a7650da136e8
+yuva420p 5fb8147030796ad0ebb4fadac776ca05
+yuva420p10be f2127ce6fe956ee3a3b6c9b308c3bb9f
+yuva420p10le 080798ee8a995734fcb2d7238010e046
+yuva420p16be ee90bc4624631b784dc8c9a68b72fbb0
+yuva420p16le 965dfd8e5f0e22bdd33fb2b7155eca22
+yuva420p9be f4f93012c80c905a5885459aa2d29ef5
+yuva420p9le abff60ecbe6e867949399710953bd1fc
+yuva422p ad564e513a8c08ff0ec99324e204dfbd
+yuva422p10be 61c806e5e02ea4c90ad3156c90957a18
+yuva422p10le 41507ce136674ad458e562d44c67ddca
+yuva422p16be 3437cce47184e4b9a7a681831816e1ea
+yuva422p16le 0d534fcd61fc54fa9d4bbae5bde537ec
+yuva422p9be 588f72cd85285ed71a519525a947dedc
+yuva422p9le d5a5d50f414caa1563700207931f0e0a
+yuva444p 64bd3debe7c2b8cca91bc1d6e2a8d80e
+yuva444p10be 1291045203be7d60b9015fa7e34b5716
+yuva444p10le 75865370fb0c018fb8663958bafcdc51
+yuva444p16be f817caf234aaf5848b2bc9679582ed56
+yuva444p16le b32ad623fc423f897ff31c4073ea2a6f
+yuva444p9be 48498d994c3c9070f31773e39da306dd
+yuva444p9le 431b0ac211a8f81c15f38fb57a73530c
+yuvj411p 241d393eeaa1517f6b4b23034222994b
+yuvj420p 35583968261c636b9c57ff03fd60eb54
+yuvj422p c29a94439e96cd5dab7f65eb6dfc2f5c
+yuvj440p 8899d4ce717e32937d58a76df473ba7a
+yuvj444p 6c0d0ad629baaa96fe4dcb00f0f5d9de
diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field
new file mode 100644
index 0000000000..9ba8e58160
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-field
@@ -0,0 +1,123 @@
+0bgr 8f34406a8e6f293b6468b6941d8944e6
+0rgb e2c35753a2271d1f9455b1809bc0e907
+abgr c0eb95959edf5d40ff8af315e62d0f8a
+argb 6dca4f2987b49b7d63f702d17bace630
+bgr0 1da3fdbac616b3b410d081e39ed7a1f6
+bgr24 573c76d77b1cbe6534ea7c0267dc1b13
+bgr444be 064887b4ca8f49cfb7c776057bc75c74
+bgr444le adbbebc13a6a00db18a91086fe66e99f
+bgr48be 1516f1c0816ea22e1a7590b82b9762c7
+bgr48le bce78fec940d8d22186418e42b5a4caf
+bgr4_byte 59d0a8b0ffd371ed645ef8a22304435d
+bgr555be 26371682da1569a7d979ce26096fc19c
+bgr555le c31595e9ae64fcbd6147ef33b2899b28
+bgr565be 46e14950534befc7e791f65e66449bdd
+bgr565le 7f53bf9a2d3ab2badf50469e8a8e988e
+bgr8 47b2118262ad932cacf731cb66905ffd
+bgra 66d6e0846990fff0f09a07c43c3add71
+bgra64be ec0bdef8663dc9d73818a48419cb4764
+bgra64le 9e2def541e51bc6e77fbffbff7fa146a
+gbrap 5bbed2c5c872748b38db078dbd7535fa
+gbrp 838025a3062f7f31e99196ce66961ad7
+gbrp10be 73cb1311d90dda83a4db617a4700075e
+gbrp10le fcf0b1c6e045116517e26bc6edfa9418
+gbrp12be 6cacba42b26a20e523003666bb9bf31c
+gbrp12le 92bc95b034cad061420af56962c947d2
+gbrp14be 6f76bc354f4578c90613c8cd71cea14e
+gbrp14le c7279cae8a3f1bb4f3e9935339343aca
+gbrp9be 8c71140fc83665db7f7d7fbdd9c552f1
+gbrp9le 1654c79e38dc78fdf106239ed2a7bd4f
+gray 57fd8e6e00f6be8752726005974cce1b
+gray16be e1700e056de9917744a7ff4ab2ca63fd
+gray16le 338de7ac5f7d36d5ad5ac2c8d5bbea68
+monob 599b938a6207de81bd96c902c2511676
+monow 8486b94cd7c498b0effd33cb7e8e63df
+nv12 16f7a46708ef25ebd0b72e47920cc11e
+nv21 7294574037cc7f9373ef5695d8ebe809
+pal8 379b8c80f4422a353ad286f7120f2fb6
+rgb0 ca3fa6e865b91b3511c7f2bf62830059
+rgb24 25ab271e26a5785be169578d99da5dd0
+rgb444be a05fabc91e485ec02461be900cd72ef3
+rgb444le 61825e18081a86c96cc407f5e6105f28
+rgb48be 425b90bfe7d2c944921c3d224eb383f2
+rgb48le 33202a1d6baa93c5a29d88eeb47b5f04
+rgb4_byte d9d8b1fc15960fc0b49edc7dbb1108eb
+rgb555be ed65d5e935d38d7da789adaeb07a72c8
+rgb555le c53ba385311e57e75f6919aceb7eb689
+rgb565be 692136248339f1ac903932d48b8f3311
+rgb565le d0f227a59da3208567485aa79679fe8d
+rgb8 62c3b9e2a171de3d894a8eeb271c85e8
+rgba ee616262ca6d67b7ecfba4b36c602ce3
+rgba64be 23c8c0edaabe3eaec89ce69633fb0048
+rgba64le dfdba4de4a7cac9abf08852666c341d3
+uyvy422 1c49e44ab3f060e85fc4a3a9464f045e
+xyz12be d2fa69ec91d3ed862f2dac3f8e7a3437
+xyz12le 02bccd5e0b6824779a1f848b0ea3e3b5
+yuv410p a85920d6bd26f51306e2ecbe71d1c554
+yuv411p 9106e283d5dbcfba01c611886d58871a
+yuv420p 9ea8ed3c22c31c0354b7face540bb280
+yuv420p10be c6e76d651b991c0814a3047b2b3a517c
+yuv420p10le 3bf226b758c0b53b893729d97e7bc602
+yuv420p12be 8d63ddea0b9a886e859fec778d72a1ef
+yuv420p12le f5b6dd8cd8b62fce64deac95aae916ef
+yuv420p14be dda2c5c09b72b41a19943b3832ddd2d5
+yuv420p14le e79f827393fb9344190bacacffe9978e
+yuv420p16be 62d08d547f857b254c1d31b5c40b20a6
+yuv420p16le 4ddc458e596c44dfe007ca0c8b211e38
+yuv420p9be c4a6faaec240d7d11d25b75afd7a6183
+yuv420p9le 2ed3dfcf2e5db5de7076dd74dee5c433
+yuv422p 9bd12ab1efe6c3fe6d9f639b97b79c7e
+yuv422p10be 6dd930ff81b89b71f6cadf757e0e8b3e
+yuv422p10le 5e314f06833b5016cc5cd76c611f7a48
+yuv422p12be 71c75f56a518f07be9946cbdb38b1d45
+yuv422p12le 1351d615ca6a97f206d04b9c4bb2d130
+yuv422p14be d3d1d29966b9737dc8bbc31c6d215c9e
+yuv422p14le 3ba9d5d2a32dc3e0ec025100621e20f9
+yuv422p16be ed49651e67f96c34649762f4678091de
+yuv422p16le c7a8ad6f7aded288ca2d16c6e5d73026
+yuv422p9be 6d3da72c1c56c330d23f1f232ac6bde6
+yuv422p9le 0b3df4939e52a9c47521b33ca76a8ea8
+yuv440p 5100aaa0d8b30f0eea8825fe9ae20b42
+yuv440p10be 4456a712fbf663d3eb591dfec7c0556d
+yuv440p10le a71cc3c1b47f6600717421bc88ba1c43
+yuv440p12be 735964fdb80852e971ccb4264ce7d822
+yuv440p12le a529385f94a4d46fa339746693975d99
+yuv444p 389eda40a7a3bd5d3b280b448e99f27e
+yuv444p10be 80b1cf057149a1f7dfae1da061e00523
+yuv444p10le cdd8ba90dfc7689e0771dc36a70db433
+yuv444p12be caaa959ed39a74dcec478f23690f5ffc
+yuv444p12le a7965a51a2e45723f650d1313f2aa356
+yuv444p14be 18a46dde1fafcc7bbc6ebb3fd6681e7c
+yuv444p14le 90058811cf9c35a4ddfab367bea40c51
+yuv444p16be 1ff6ee64bcc33be585712e86359430d5
+yuv444p16le 9fc18b0a156d20503e3bac4823277adb
+yuv444p9be 12e6232d0e0c809527f64452341761cc
+yuv444p9le 9af93703a9819f834bcfeeb86eb33fa8
+yuva420p ebd72004be42de4743ca46fd81947b56
+yuva420p10be 5e000937fce49360850bc10d8083f798
+yuva420p10le f16bde9ed6d8bd015d59b2e8e248ab31
+yuva420p16be f29675ea983d3a2a28d648f25d2f79c6
+yuva420p16le b5f41c7abf5b7baf5754a5ade5a6f055
+yuva420p9be dbf1a242d3277c87c07fe7b4db993869
+yuva420p9le 00d48d3b1b0383b92ccdb26543cfb7f8
+yuva422p 801bfb0d4c9e7a524d97bfa11f7995fd
+yuva422p10be a0d743770698deea2be35ceb2bb0eaad
+yuva422p10le 6a0861e5c887f3213dc34d8674611950
+yuva422p16be c870b697714221ef9168b6984294e501
+yuva422p16le fef7d5f29dfec9ee36216b7a610b4b39
+yuva422p9be 83ff1ae035bb587dc59acf4121602dac
+yuva422p9le 75baca2a93a8e76b27ea208858213819
+yuva444p cfbd995b538c34dee9c107ecf875b283
+yuva444p10be de8b80b4c3a12624412530f09de6dd39
+yuva444p10le 04c93877f724a29b47bc8c0a10a3036b
+yuva444p16be b10fd7c1b61ac22bdb285f0d91a390f1
+yuva444p16le cac82ffc36b7052747407663fc5ed510
+yuva444p9be a6f66d08b3370fdd90987a6143b7b91c
+yuva444p9le 8d0f0b0840096127613920984078ce53
+yuvj411p 0c7caab687fbd33cba04702366b6c401
+yuvj420p c9bef7e5c1dba1024be992167806ef07
+yuvj422p ac900a0f9854dc2a0ec2e016ff5487dc
+yuvj440p 6f0d66982a3b96efb341a512314317ca
+yuvj444p d559f8cf2e68b0cd3abadbb2f3642dd7
+yuyv422 449ca8d4b5a28ccaaa342860b24aeb3c
+yvyu422 6b226a0d4fce5478294d3bd4ecfb46a5
diff --git a/tests/ref/fate/filter-pixfmts-fieldmatch b/tests/ref/fate/filter-pixfmts-fieldmatch
new file mode 100644
index 0000000000..44622d060c
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-fieldmatch
@@ -0,0 +1,5 @@
+yuv410p a6c9b4065e8253d8120772f69be0bf04
+yuv411p b913e634ad37ce046240252bed8681fb
+yuv420p d448d95326eadeeb12ea0cc348067958
+yuv422p 11ad22ce00c5e8a30d0472f29fb15434
+yuv444p 9350a3f23cd7d95ec441a49f63f55953
diff --git a/tests/ref/fate/filter-pixfmts-fieldorder b/tests/ref/fate/filter-pixfmts-fieldorder
new file mode 100644
index 0000000000..085b05349a
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-fieldorder
@@ -0,0 +1,92 @@
+0bgr 955efde1695e9f4da276622e462ea9cf
+0rgb 2b0f066cfa0bef378a492875d541de8f
+abgr 832924b5351361db68dbdbb96c60ae55
+argb 80d08e68cb91bc8f2f817516e65f0bd0
+bgr0 d2c676224ea80ac3ce01afde325ea1a0
+bgr24 b7fdbcd10f20e6ea2d40aae0f329f80d
+bgr444be ca5acc0d5315d6d9f4422337c6f20842
+bgr444le 8a82dc31d4305abb60825c54e07c1b09
+bgr48be b1be092ef916a204e002606cf83240fe
+bgr48le 3e64bd2ad45de53a780b2bf546fd5343
+bgr4_byte 319d0fda198978f05e0318863d10bc01
+bgr555be 686b1f3318a44c48e2ea473c42d7d90a
+bgr555le 113908a73bbef613f68706be3352f404
+bgr565be b0aca25c2de20dabce53cc0e6e27b8aa
+bgr565le 2e00c326499c8475ffc6aca5476ad422
+bgr8 cfc405aaf0162b4edfe9b3e047c5624d
+bgra 5967b559257dbb6784f93b9d2bef4edd
+bgra64be 64a4ec15bc35ede2018f650b50c2429b
+bgra64le 5029192d0f32383c9f25f8e7da7cb5a0
+gbrap 8096c8ee9ade98101348c10eb22504cb
+gbrp 506dea2fe492e985a396d1b11ccd8db3
+gbrp10be d5c3b42e39c3f62d917cf2e4e9e073d9
+gbrp10le fa28502ba68c55c55b6bb6f732e813f6
+gbrp12be 36140aa1ed675c148f64d259f914a2a3
+gbrp12le 30f0996103262ea8adb0629a07051df5
+gbrp14be a0b22f06857eb537996f5b0d75557c53
+gbrp14le e317ce07a605643c494f35b6e7229ea3
+gbrp9be 7b4d5e760b72817f4c3d7141b409b0c4
+gbrp9le 9a4523eab86a4e0c897d9a07ae9036b7
+gray d96e0f1c73d3f0b9506d691b5cd36c73
+gray16be 293a36548ce16543494790f8f7f76a05
+gray16le 84f83f5fcbb5d458efb8395a50a3797e
+rgb0 2e3d8c91c7a83d451593dfd06607ff39
+rgb24 b82577f8215d3dc2681be60f1da247af
+rgb444be 1c3afc3a0c53c51139c76504f59bb1f4
+rgb444le afced429728bf94c0617d0c031e356e5
+rgb48be dd9db831fb640b113bd9531f3f19c226
+rgb48le ef45b68fddf5e4d2e2ab3c08920dae64
+rgb4_byte e9804cb4aa572a40ddf3204e9c2c4566
+rgb555be b4ef7a0ad6f45b329a1ece563617c557
+rgb555le bcc3bd31b2df8180341fa0e50b70852b
+rgb565be d9b1e8f52a4044b0019ce56f6bc2242c
+rgb565le eac5262d84669b2af28e9357660dc912
+rgb8 6deae05ccac5c50bd0d9c9fe8e124557
+rgba 1fdf872a087a32cd35b80cc7be399578
+rgba64be 5598f44514d122b9a57c5c92c20bbc61
+rgba64le b34e6e30621ae579519a2d91a96a0acf
+uyvy422 75de70e31c435dde878002d3f22b238a
+xyz12be 15f5cda71de5fef9cec5e75e3833b6bc
+xyz12le 7be6c8781f38c21a6b8f602f62ca31e6
+yuv411p e4a040e0e786c4dae07d9d3f90a54905
+yuv422p 16ce67249c6ce7ef57a433646ad6dfc1
+yuv422p10be 62ae323dcc41aabf8ff6ecc53b119ce8
+yuv422p10le 60b20ad8c01ad7ea774ce1d74d8932ba
+yuv422p12be 7bcb3e28323dbf566512b5b8a1d33380
+yuv422p12le 5877624df10122dd51c173f814bd5414
+yuv422p14be 8bd7bfb0b35d68000ba57af66958ef2d
+yuv422p14le 471c7528e3da240d0a40f33548cbfbab
+yuv422p16be 8c193a8b6064e2379b2fb211cd2e6e37
+yuv422p16le c949614bec06baca5ffca840b164eacc
+yuv422p9be 245551dc31484ff4d31f7e7230efd1ed
+yuv422p9le 8fd07db781631685523e3193f2792874
+yuv444p 1483374f69c4bbaf9252ce255fc84feb
+yuv444p10be 2e5caee508692869141bd9649cc17f64
+yuv444p10le c0ceb41ad4c2ddc454f3fdb9cda2d8ad
+yuv444p12be 8729565c21a9d8f1e7a87d81d0aa4a54
+yuv444p12le d4786cb4b1e79b2af1493e01d685282f
+yuv444p14be 33f1cf5233f57582618390ea337e83c6
+yuv444p14le 7d9fc358232488f671d663d27875f3c1
+yuv444p16be 779ea70979e735d3074fef0466792681
+yuv444p16le aa893d9b1857b68fd1c5fc42236d7816
+yuv444p9be 4e5c3a669f37a6f0587d372a28d3e6e8
+yuv444p9le 621d86abf2ed636d9933ece245033278
+yuva422p c470da57cde22b452deb8874df710dce
+yuva422p10be a2ffa080ae661c1033aa38be28002922
+yuva422p10le a4f5e8006f8ea3f964206605045e0fe0
+yuva422p16be 929ec5d4bcfac13ba8a02f12e3f5fc7f
+yuva422p16le 7155a6036e25719f2e4d2d47212f077d
+yuva422p9be b1af62d553d790e041e80cf89608efe3
+yuva422p9le 65c80faeb0021deb232ee451f77c89e3
+yuva444p 9ac54882677f1fc5553a97ea558e942d
+yuva444p10be 3326267d176a8dfed2c7511b926962e6
+yuva444p10le bfe957d1b5fea3585b3942cbfdd529ad
+yuva444p16be 2f80d411847856e1364659dee8b23485
+yuva444p16le 5796be8d66371b60037fc8053c27e900
+yuva444p9be a83599c0e9fca08f6b7c6e02c2413fcf
+yuva444p9le 390fcd8f72ee407a8c338667944e3f72
+yuvj411p 73fa99cb96d2f7171bff15bc2e43d963
+yuvj422p d5e67ce1db5347cf3416069286359f57
+yuvj444p e915da6b5aa0ee5298771ba0ca187cad
+yuyv422 a923c5bd4889bec92d872237f6a578ec
+yvyu422 d7a8697f1f5e6a2a27b0df17811b2613
diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip
index d39b0ca130..206462a61f 100644
--- a/tests/ref/fate/filter-pixfmts-hflip
+++ b/tests/ref/fate/filter-pixfmts-hflip
@@ -1,42 +1,118 @@
-abgr 7b68405327d7c0862b4e3c1a2e5f8401
-argb f2d838efb97f9daa035681acf0fd7aa3
-bgr24 6428be12c092356cf9a570b43566b406
-bgr48be e776e0de8605c9db81380fddb3aa8a16
-bgr48le eba1836285756b8950981dea2c02be6a
-bgr4_byte 658a71bfc3a2e9271bf60ddda03d138d
-bgr555be 39d9fafcfed4f7c4ebe0a5bdfb202d67
-bgr555le 92f693be95b64dca452221747bab4f70
-bgr565be 3bb3d1918f7a9977ff3998c051159102
-bgr565le bea2b9a14a24acd7a7443fa4cdc45128
-bgr8 c07a695e1a247f753a24c08de1124eaa
-bgra 2a358c075799b6e4ff56c0d4464d7f9e
-gray 60c5640a7a48454c6a18375ab9c99599
-gray16be 64ba7dcd3478833d2fffd3705ef1123e
-gray16le d4f370937b499c9b63c31970f409114c
-rgb24 24b18acc43c119f2de1e727b32b550b1
-rgb48be 23ed645ce6c7e4cedd8045130ae07e15
-rgb48le 6918e306925438c92b8100ff9408eec9
-rgb4_byte 2c6929584add1f600e1c87a61d9450c4
-rgb555be 8b4adf81d9c9b9161891229ad79f8b66
-rgb555le 51684ecc7cf0cb11dd87909e0dfd71ac
-rgb565be d9a4eafb25d103c3dd79c7d6e58e1ce4
-rgb565le 1476f867d8f1f970d51f9dd6cb51307c
-rgb8 b7a090903c6f1d9c9ad6215a8e7b71cc
-rgba cf8ba075a00d44599a8a49caa37d87f7
-yuv410p af26db9a0af59863c6643f21259ecc54
-yuv411p 58f0cf9d30c5604fcfe1209d281a9242
-yuv420p 0e86307c56a749cb6009ee1509d709d0
-yuv420p16be a1e2b231fe1de23fae97cb9d6d5cce2b
-yuv420p16le c5a2ff8d29e25840dfabc441b4cf733f
-yuv422p 52faae832987874d7cd49bdc76b08762
-yuv422p16be 5001f3a4216e895f84b78e8bfda0cb43
-yuv422p16le 90303bb96430e12d6f45b3d2e90a9dd1
-yuv440p 30da73c35a5862e39d7d43bca3dc70ce
-yuv444p 3b472a790d4db3a5c404cfcc16ea44a6
-yuv444p16be 7efc49abd10868e5bfa2bf4bf5ad9ec0
-yuv444p16le 59140c4d599e80ceb75d8ae803c5f538
-yuva420p ee3499a2bc030c68f51aa11887b9fa56
-yuvj420p 75344d0547474b9198ffbae2a54c571b
-yuvj422p 3b479c749d6de189735c95fe6b051c13
-yuvj440p fe56033764fadf849d73ed992a1f9010
-yuvj444p 3068acd925a73222e79a1da31496eb48
+0bgr 823994965cfb2ba4566f878c75eed684
+0rgb ada57572ee2b35f86edac9b911ce8523
+abgr d2da6c3ee72e4a89a7cd011dd08566b2
+argb 36cf791c52c5463bfc52a070de54337e
+bgr0 66e9fda4e658d73bfe4fc9d792542271
+bgr24 db074979bd684ca4547e28681ad3f6ab
+bgr444be 63ad2fe7b4e44b11c5ca03b545a941ca
+bgr444le a742195a606d5c3f1de795b499077f01
+bgr48be e59efaa40ad1652c74a7c83aba43b4f2
+bgr48le 13c4f904e318356c96ffce911226cf83
+bgr4_byte 8de3494b53a459ab0f748a525e87ad4c
+bgr555be 2b491222a2807a112b404f2924ba0c3e
+bgr555le 533feb969289df2bc628d46816d1db89
+bgr565be 3094c0320e068305b35c57b82476370c
+bgr565le d20c95743b957cbecd09272a630f22cb
+bgr8 67fb3fd116f0c0eb36d8ed03bdfbb0a6
+bgra 275f05a382bcbc9bc77c06b79e1d8a71
+bgra64be 1cabeafe9c21a4f7ccd976220f22ee5a
+bgra64le 1b15c01c94cf9af89273da1d1f994cff
+gbrap 28e8d545a8f32a330c9368c927d97b66
+gbrp 0ecfeca171ba3a1a2ff4e92f572b71cf
+gbrp10be 558636cef6abb12748abc01eb976ae53
+gbrp10le d1f7cd56e675f4103c8325f328e8f076
+gbrp12be cbee068250a510eac492019b3789223d
+gbrp12le d8e19a9046f4befd9567ecb6fe44f1c4
+gbrp14be 0646dda397e0ffaa55b2f993db241153
+gbrp14le 5c66f1e622fecf35cc64b8d9956d2a0f
+gbrp9be ca4ca6388207c69c494970fac2cacf7c
+gbrp9le c24110afa41b18beb52a07910e2d576f
+gray 8bd4ece1dbf89b20ee785e0515356e07
+gray16be cf7294d9aa23e1b838692ec01ade587b
+gray16le d91ce41e304419bcf32ac792f01bd64f
+nv12 801e58f1be5fd0b5bc4bf007c604b0b4
+nv21 9f10dfff8963dc327d3395af21f0554f
+pal8 cfe90d91bea5172babd97c3828270ea5
+rgb0 0092452f37d73da20193265ace0b7d57
+rgb24 21571104e6091a689feabb7867e513dd
+rgb444be 38d6d0e9aa15ce95f3fffcde8437632d
+rgb444le 4c5bb6590def780c480abbe6a6349b1a
+rgb48be dc7f3a98c0913a6defa56bf032590ad0
+rgb48le a813a316f8b5d49340f64990f914e2f7
+rgb4_byte f28c594e547d38166c2757338948e874
+rgb555be 316c7c1f785d8ba84dbe3eaa20591158
+rgb555le 07f561fec000bbadf6b732a358c6126a
+rgb565be 593c48d6214cb40f6472ebdf9f6ede1a
+rgb565le ccc896ad1852500b7e72bb858860d747
+rgb8 68a3a575badadd9e4f90226209f11699
+rgba 51961c723ea6707e0a410cd3f21f15d3
+rgba64be c910444019f4cfbf4d995227af55da8d
+rgba64le 0c810d8b3a6bca10321788e1cb145340
+xyz12be 25f90259ff8a226befdaec3dfe82996e
+xyz12le 926c0791d59aaff61b2778e8ada3316d
+yuv410p c49fd0c55c41185b1580aac77211992b
+yuv411p c416371077dce13d31bf1dc706111ae7
+yuv420p eb8d9f02db98e10400781428c43e9438
+yuv420p10be 5cd5c8181248b2dbdc7a8669caca3ed7
+yuv420p10le 95a92ee031fdb8812661c019d925fad0
+yuv420p12be 8fe5d344a1576aba7892e855d2790df9
+yuv420p12le c0897e2b53c1417fcf0cfbdbf9f54163
+yuv420p14be c5758d8062c61248110485243a75b712
+yuv420p14le e283871dec73c853421d3aa098f071a7
+yuv420p16be da4f5b6e537edf9cdea48a60defe520e
+yuv420p16le 4173d444fea2ea27ad03b3f92e982bcd
+yuv420p9be 7dbcd8f9bc1602f0a85dd7ff43e4522c
+yuv420p9le 187355df9ce2d35df085bd900cfc0953
+yuv422p 5aade4d118cd7243800a08d300033748
+yuv422p10be a12d0957b703bd54cd569664b821ca3e
+yuv422p10le 8b6ac98276b10b7e540a5f689e5453fa
+yuv422p12be b5d2142e6ccd9f69dee2c0643b14a741
+yuv422p12le da75ea80662636c698986cdeab334669
+yuv422p14be 027a593f148a96ff9e37a35e55608818
+yuv422p14le 4c1de1ce4f199ab8e94a28bf79ecedb6
+yuv422p16be 3d4b525c8056b740a4afa5b86cd79cd3
+yuv422p16le bb93ea91207d118811e2dfd5a48e223d
+yuv422p9be 33c54fa3595492c10dbb58de2f3ef05c
+yuv422p9le 296f934ce228f436a3733a05bae280ad
+yuv440p 53fb331a853af01bed7f32504a1e5ff0
+yuv440p10be 38108067cdce71f3a8f51eee25e4ff5d
+yuv440p10le a369c78eda4f46d71105c38ddc92b976
+yuv440p12be 2d5e61f399ecb12bfb66fdf20b37b4f0
+yuv440p12le 7aecbe06b7cd8c84d98af8cf3bb971e8
+yuv444p 0bd726440d90438ad357172fe1fac9b3
+yuv444p10be c2e452fbe45f23c70525919154f4b81f
+yuv444p10le 90140d5f930fb2ff750fe18df990d0f3
+yuv444p12be f858a8f0c55192ab69d356b97e0449bb
+yuv444p12le 22f099dbae63e6564f06e1cc32683a4e
+yuv444p14be be4727c283bb3af3327f7b9dc57e51b8
+yuv444p14le 289f4d6a3d60ba654e8280683825ee9a
+yuv444p16be acb6b001d445a628d1d0a2dfbeed078c
+yuv444p16le cce4770e9e2c6d4104562490d6ffbbaa
+yuv444p9be bd3d219c010098c25dcd5ad211fe5ec6
+yuv444p9le 3a68468fbe09c9b963d9f9ee9ce3e439
+yuva420p e910f0f5ed439a17fc3e61b42dec88c2
+yuva420p10be 2c3b83450c3155793a142ecd5d525131
+yuva420p10le c49ac6b0e89564fa8243e0400adc37de
+yuva420p16be 8fbd18fd0d3b755dd311988856843b80
+yuva420p16le cd647fd48bf5398a783f6ba6a6332835
+yuva420p9be 3cd29a8e3da6c6ab7538ecf987fb8123
+yuva420p9le 15e6654f50eddf97f852070d8dd8f009
+yuva422p 902dc911ee175d9b1f2addcc03aab9a3
+yuva422p10be fb927978446e975f7424600495a7acde
+yuva422p10le 1d0b5a5946b824810b1b83a7ce429274
+yuva422p16be 88977e5ddcee9377525c3f251fdeb25e
+yuva422p16le d6a50a91be5fc720ca97fc2f6fbd3bb2
+yuva422p9be 996d8d73648c602c73c51e2d95b6cf9b
+yuva422p9le 2d64684a8844967e9ffe827c04e3c917
+yuva444p 53247be24822d158c0866cd58d2ceeba
+yuva444p10be 9f3c25c3b9d26787d0bf8da2b15c75c6
+yuva444p10le 1721b843b721629da7a0cd76ac665708
+yuva444p16be 635fb2720470e0042a7c9b70bf908a2c
+yuva444p16le 6d5bd13f8bb804bd1158c1af732a24e1
+yuva444p9be 3d3e7491192aa4e396015bf8e3755a24
+yuva444p9le 31727b34bc3d5ce726681e90557d39e4
+yuvj411p 70a0abb56a538376aff33c275584b61e
+yuvj420p 83af439c504d41f986adc17059b7fda8
+yuvj422p daf02a72b26d17d1855b977aa04609fb
+yuvj440p a4af7a9e3cff6cfc1c8924590ae69807
+yuvj444p f5937e0183439411673d2ebf8df62e2b
diff --git a/tests/ref/fate/filter-pixfmts-histeq b/tests/ref/fate/filter-pixfmts-histeq
new file mode 100644
index 0000000000..a250902dae
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-histeq
@@ -0,0 +1,6 @@
+abgr a538e1221c94a12fb4e60b47b5358f67
+argb d0ef008d603d67a6a7d698d2a8f53d6a
+bgr24 9ef3c69a658490c4fbc807272372e73a
+bgra 716e70fdf7413d9a3b83e0365c2b0a99
+rgb24 8423322bbc66bc5050f6b93fdab23433
+rgba a960c9423bbb3925c3511362348b38e2
diff --git a/tests/ref/fate/filter-pixfmts-il b/tests/ref/fate/filter-pixfmts-il
new file mode 100644
index 0000000000..d6f510c2cc
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-il
@@ -0,0 +1,122 @@
+0bgr 501a8320becc400e2a72dc847003d82d
+0rgb 53efe0182723cd1dedfdbf56357c76f5
+abgr 97603869e6248a8e5d8501563a11b114
+argb 9e50e6ef02c83f28e97865a1f46ddfcd
+bgr0 590dcd1297d1dd4541eea217381db604
+bgr24 73afe7b447b083a7c2d682abe8dd451a
+bgr444be 4fa078adc981fd07440a7b657c98c4c1
+bgr444le 404c22249a4222f3c086ef9ef79e090f
+bgr48be 6de326fc52d92c6a31d74378534d2fff
+bgr48le d37e673d846e9ceb06641ba6d480db84
+bgr4_byte f275df6bc1d33eb037b0f609bfa5a7a8
+bgr555be e9007cafaf389f2895cf0e45079ecb90
+bgr555le 9d4d4c0c5e85eca0030e74ed873e9538
+bgr565be bef8c77c32880c9eebe4507ebc3f2a6d
+bgr565le 8190c5275d8b62d997362f999b72be16
+bgr8 ef01593604512621b3d175f8b6c2ec9e
+bgra e6ae08f06f157297296b319a249dddf5
+bgra64be de7c036f20fc54d89690239cc6239678
+bgra64le d1aa975fa03ce226008396b30a653420
+gbrap 2345d4dbd130d7c6d1cedad5954543bb
+gbrp dc06edb62e70024a216c8e303b79b328
+gbrp10be d0d52a2a87d545a5ddc7da6b95e862d7
+gbrp10le 6471cdb95c03b14ebcb86d807fa8035f
+gbrp12be b955ca6256901b1640fefc7c0f1c489e
+gbrp12le 2dd46939b7e2440feac2c373aa48395e
+gbrp14be 93140bf6404b2b3647fbd56518ace212
+gbrp14le 2164009f7f646b039eaa488ade79db4f
+gbrp9be e89c0674c92f103517d43d2a02698b45
+gbrp9le 7e79b4bbb589095c925d65cb7c037d44
+gray 52ae18648161ac43144f5c9cd2127786
+gray16be 92c3b09f371b610cc1b6a9776034f4d0
+gray16le 1db278d23a554e01910cedacc6c02521
+monob ee0012e4df0bf06a09cefb49be68e850
+monow 5e0868812e25cc867cdc78d5252cbb81
+nv12 3c3ba9b1b4c4dfff09c26f71b51dd146
+nv21 ab586d8781246b5a32d8760a61db9797
+rgb0 cfaf68671e43248267d8cd50cae8c13f
+rgb24 88894f608cf33ba310f21996748d77a7
+rgb444be 99d36d814988fb388aacdef575dacfcf
+rgb444le 71b4b1a44e13d1bdb31f81b5f9a75803
+rgb48be 267ac00248129e735a917175b5cf0a82
+rgb48le 15e7d807b7f4ea68ac506dfc2db9146c
+rgb4_byte 9bd11ff523ea914bf0b26f8af7965054
+rgb555be fd0be5e3f5f6fdb250f8368c2eabe943
+rgb555le c85a16162ca83496306ba6c888c1a8b7
+rgb565be 046e381ad0be8277f7020420297a8f6b
+rgb565le 9b79220c3c2f23b60a55c2bdf709ffb8
+rgb8 93f9fa5ecf522abe13ed34f21831fdfe
+rgba 625d8f4bd39c4bdbf61eb5e4713aecc9
+rgba64be db70d33aa6c06f3e0a1c77bd11284261
+rgba64le a8a2daae04374a27219bc1c890204007
+uyvy422 d6ee3ca43356d08c392382b24b22cda5
+xyz12be 7c7d54c55f136cbbc50b18029f3be0b3
+xyz12le 090ba6b1170baf2b1358b43b971d33b0
+yuv410p dea1ab8843465adf5b8240b2d98fd85b
+yuv411p 8bf73777a5ff43c126be274245aceff1
+yuv420p f1f4e7e94a76d5320049464bdeac24ed
+yuv420p10be f7839393b65972595bdcb2485c6bf2a1
+yuv420p10le cb00b1fc299baff8bc31086d8571fed6
+yuv420p12be e5bba4d9f2299e98e69c9347234545c8
+yuv420p12le 7110d2862c1da19e0298029383d31dab
+yuv420p14be 240357c01079020ccc3d9287b5821a1b
+yuv420p14le f7d0f5f5e72455b238897ed87cf67b3c
+yuv420p16be 8195046b708c613b3ca521c95db529ab
+yuv420p16le 0586439ecbd0d2fb8f22f953e6efade8
+yuv420p9be 4e324786af988df5fb82b68000ca886e
+yuv420p9le 1d9329a946bd14e9079c8ef9836bc04e
+yuv422p da122be331a53ec389ab6b2064488beb
+yuv422p10be 956f3c496807e62a288501e183fafad0
+yuv422p10le 43f99eb0d8abd1754572f77e430d4c41
+yuv422p12be 9e8e40a95c4c762274e22026d16a4157
+yuv422p12le 28a5b358a919297c005bc491c91b2b15
+yuv422p14be ccff1e00f5d3adb899f1c266b22c9628
+yuv422p14le f8a3bcbf8c55b1f570c078ff2f436b1f
+yuv422p16be 7f2363ccb6e69241c70411b6d063a2fe
+yuv422p16le 58c0fabd1042b35346ed8b8ed3f90653
+yuv422p9be 57b0eba4fd698fbe30d052b2e37e70c0
+yuv422p9le 280d7e85aa54bf4b0e6098603408c2a9
+yuv440p b4261e15f5dc347b873cf19ccaba8123
+yuv440p10be 9c8e626ca9722f872ef0ecc8e3fca74e
+yuv440p10le 8c28978a0ad4d80c588989505a7f0807
+yuv440p12be 6711f322b74edc424230bc973c6afcd6
+yuv440p12le 6f47a23742f5763f3240982e1892e4dc
+yuv444p bbd70cde098f24097c4cdcd3ad22d9ce
+yuv444p10be b0de51e143a5bd490c424dc836becfa8
+yuv444p10le 4435dca19253b88dc7cd553928467e79
+yuv444p12be 23f0ce3a810138df7849d4f6b5e50211
+yuv444p12le 0394aeef391e2cc09722ee8e7244f1c3
+yuv444p14be c712cf9dbf8571fbd31fa747e58993ec
+yuv444p14le 3a0e361e5998f8590dd8ca8ce896cea1
+yuv444p16be 929c50756bfe8cab7c416f56095fbb82
+yuv444p16le 63c3c3bc5d08f701afa3406f7a22018c
+yuv444p9be 8044a9593b813fa1e23eee6b8bba4737
+yuv444p9le e38d519ea585e2d17107b8ac34648ef7
+yuva420p e72aad3c3cf41445bdc1c9d14b21321f
+yuva420p10be 7cd2e0948f56fb54e8e6856b02561493
+yuva420p10le 5f038e8362ab2f999984a5b7d1536b7d
+yuva420p16be b98c585e4b9a6cdb86147499d8fe8531
+yuva420p16le c58b31509a944e5ec6a0676218e43daa
+yuva420p9be 845bc11e88affc3161ae6265008edc84
+yuva420p9le fbc3300867510900fec84caf718e8601
+yuva422p 6c347a539965cd63cddfeec598858c11
+yuva422p10be d34bf5f06ac5c67e12409aa111b4e21b
+yuva422p10le ecb3cc8d77cee05e54d4de60831be159
+yuva422p16be 47a8d3c98492d31bce0ed0d6f74f5131
+yuva422p16le a950acae1f7ffc47a0951a40e3309b09
+yuva422p9be 0217ba7015245e017ceb0a3eeb39fa56
+yuva422p9le 1bbb5ba2b649bbe47c928012deb4e3ae
+yuva444p c8153b52159fb0f392459b8be406c294
+yuva444p10be b0456e5ecdd87c983573e1016db85178
+yuva444p10le f9b10500666ba220ce42b478a6785dae
+yuva444p16be 97f8cb6ed835c7c5cd2fb112b1e135c7
+yuva444p16le 47170401a8c348d3f05f6530607d066b
+yuva444p9be d5c0170b41221a9607e6ae586880a383
+yuva444p9le 4948983313f46180666dec85ef30130c
+yuvj411p 91e137f54b2cbbb1c1423c36f031d5f2
+yuvj420p 2b6d8e3b527af5de94963d1bdefe20a9
+yuvj422p 4ce16aa04a5e785b29fd9cdf54bc9ca1
+yuvj440p 36a248ec6f1dc67555ee590651388b15
+yuvj444p 279790fe3c83b07f0a09085d36849c30
+yuyv422 09af5b85deecfeaef2e00e00fbc12a49
+yvyu422 62c62a80939c34fb7890c0e7791a0321
diff --git a/tests/ref/fate/filter-pixfmts-kerndeint b/tests/ref/fate/filter-pixfmts-kerndeint
new file mode 100644
index 0000000000..558e9451bf
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-kerndeint
@@ -0,0 +1,10 @@
+0bgr 7de3240bb5ab40dc9b599f7112990439
+0rgb 09f7b9006720a4b1ba4e2927b441022c
+abgr 4242d4bbfd5e5697a9a1cfe478a0ae46
+argb 48ea8cc401499ffbf0ac34bacdd1146d
+bgr0 e50249e05a9790c56033bffde502d1a2
+bgra 04f4d485067338e181c4c64b4df1246a
+rgb0 898e3d3bd40a14824929ad83d69be24e
+rgba 919e516d3a052401eb1c658412d3584a
+yuv420p 636b260f98ba9f98e304ff9f82d63393
+yuyv422 768afc798f77b3311d7b1a33caef902f
diff --git a/tests/ref/fate/filter-pixfmts-lut b/tests/ref/fate/filter-pixfmts-lut
new file mode 100644
index 0000000000..1deac4c6c9
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-lut
@@ -0,0 +1,19 @@
+abgr 0a932e831efd4ec22f68b25278bac402
+argb 4f575be3cd02799389f581df99c4de38
+bgr24 fa43e3b2abfde8d9e60e157a9acc553d
+bgra 4e2e689897ee7a8e42b16234597bab35
+rgb24 a356171207723a580e7d277078072005
+rgba 7bc854c2698b78af3e9159a19c2d9d21
+yuv410p 51b39a0e33f108e652457a26667319ea
+yuv411p 9204c5af92aef4922a05f58c1f6c095e
+yuv420p 7c43bb0cae8dee633375c89295598508
+yuv422p 67df35da0c35e54882492b2365438254
+yuv440p 5e41adcfc27be4369afd217b61b2ffe3
+yuv444p a2b58590aef88db2c1f14a1a3a3b0359
+yuva420p 518a380bf1af60ef2ecf4754eec088e9
+yuva422p 7110ac2e37377b05b6fc5ad967dfabb5
+yuva444p 642f3958f141dece9e99407945e2ef43
+yuvj420p 65bc88887c7f06a6221155ca7f9cfca4
+yuvj422p ff5baffefc8ffe4547653092fd7da200
+yuvj440p ef3f27270e60ac06582e3ac7c2f3e6fa
+yuvj444p 29378d3fd132c760522c51c3378067b8
diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null
index 2f6a71e8e1..6281711ac6 100644
--- a/tests/ref/fate/filter-pixfmts-null
+++ b/tests/ref/fate/filter-pixfmts-null
@@ -1,91 +1,123 @@
-abgr 1250387304351fea5cc57b232bc0a5e5
-argb ee5a1e2e2d4dbd2cd978d6e3bf8dee70
-bgr24 437ea8de747009d73f41af120f0360ad
-bgr444be 0a9b7c91c6f50c0ed2633aebd19d7326
-bgr444le f032368a3134918e6802922e4cde7baf
-bgr48be bf24403f14d4085f970475dd17a9edcd
-bgr48le 1db5661da851a44dd5b92f8dd5a0ec84
-bgr4_byte 2bf8e7fbf1179ba0543cb42d2d8a5308
-bgr555be b8b23bcfa9a850d46850d59662e6eba8
-bgr555le d72c90906cb4df818abb37fb07a67d01
-bgr565be 0fcba91cb4c55a458271173cb26e649d
-bgr565le 6a0d182c7165103b2613d1805c822f9f
-bgr8 36b9ef72c87da36ac547202d85a5805f
-bgra 56e6e1bfde40aaa27473e01b46345c82
-gbrap 57cb1a02d6f015a4329fe367f3bdfe49
-gbrp d5f73b5d3ba7f6cadbc9b4ecbc161005
-gbrp10be eb19bda60ab7f893198364dff21342d6
-gbrp10le 546146efb36ad2605e9f74ee5e4c2a36
-gbrp9be cbe1bf8ead497a92362a749bd4b0a57e
-gbrp9le f88c68df5d699a4a7f1b0152df9f25fe
-gray 8c941e9bbf6da5336384c57f15a4a454
-gray16be 43bda75c197b0d59a9b87ee941553644
-gray16le a4ea1369ef1efff0e1341a1dc42dbfdf
-monob e13b2cbfb93d3ed6fdc1f256662ea959
-monow 87a594c125f52af67dc1dd51d800ff31
-nv12 a0b3578ec9b28be3d6e66479df8b1995
-nv21 a9318dc58dc14b9931a00ea6cedea849
-rgb24 fc0c7ce1d5d6be1b89d4471542785508
-rgb444be cc479f17c73cd50d65475a1644c5053f
-rgb444le c98bc1811d29a86471357cb2358e5a30
-rgb48be 1e2a176dadf246e376932a20303ca572
-rgb48le 57fd6d93cda99070acc4213b6958fe70
-rgb4_byte e4dcdc9adddcb3958ddd0ea3b0896140
-rgb555be 8fd499c9a6d98414ab2803ae08698651
-rgb555le a9b93f8b61e52eac76aca392dc3ebd81
-rgb565be a8c6c7817f80c8a0cee9918c3748e00c
-rgb565le 510a4ce796d7cb11aba5b25b419cdf3b
-rgb8 2e53d27e93554f874986fbba4f9d6354
-rgba ed87fc4907951608893b421624716f9b
-uyvy422 deb3625b67a8d2a51c17a322ad2021ba
-yuv410p dec949ce1d8a5f7bb1aa7640f97e05eb
-yuv411p fc2f303b20ae610dce86dae4a6671881
-yuv420p a2117c3c5d4533dca311dc94a3d157bc
-yuv420p10be 7756ef359f79d63ef6f983caeaba5c51
-yuv420p10le aa8abcc05010b4b0df7d924fd5887291
-yuv420p16be 7a708532d8ac26d598ac7332e38dd2de
-yuv420p16le 6b868d3b0c44c6b04f39415890d6ee0b
-yuv420p9be 11ffb289661f4f55347d60e99dcef632
-yuv420p9le a0c9608b2be3ca6d4e8cf625714a3833
-yuv422p b082344038849f5fd444ccf2a30e3f4f
-yuv422p10be 43a6293e138d0ecfd3385df3dcf9b713
-yuv422p10le 74da030a4efb5a20986fcead50018f4d
-yuv422p16be f7a0fb9e82805660317d07209e726100
-yuv422p16le 12eeb2f95bb0d655d52e8eed1cfbf771
-yuv422p9be 60daf1a7e61434b244c5a43f4449b617
-yuv422p9le 4c4885c48812f5ac0916a9509ba84345
-yuv440p 12000ce709b38aac3f7b7f59b07847ef
-yuv444p 628c9d1e10c22e0e512b27c0e03b46e6
-yuv444p10be b60d77db54a592ed088ebf7964e2dd5e
-yuv444p10le 1752a238eb27fb7c746e349536f60686
-yuv444p16be 8e1e2f04cb2e97f80fdfecbb2c5679a0
-yuv444p16le 5677b2caa63e0c075eac6937b03cf2a6
-yuv444p9be 5ab55576b180b2966e9ed5a1ea55508a
-yuv444p9le 3d9b69b8d6e17f2d25ce92602688bcc8
-yuva420p 9e9889ad7837b0d0dde023bf931ed639
-yuva420p10be ff20f57da08f79e44e7b603e89b18d74
-yuva420p10le a2dcfa563602232d999a19b7ae272131
-yuva420p16be 63bd8a57eedfc58e8e6319913ee1064c
-yuva420p16le 797dc4ff3a9a3f36cb84ddd808a1c04a
-yuva420p9be d2de221d375fea605a9f81c9e0fd3661
-yuva420p9le 0dd82737677f2b604a0aaa638e65f64a
-yuva422p 375465ec39a82221a4a502e92bf0453f
-yuva422p10be 81144a6638bc34bd9e6790977159a754
-yuva422p10le b30c735f71275004d2d7d78ec647fd5b
-yuva422p16be b7641ec1896f306065073f0348448f19
-yuva422p16le 3ab82ddf757a78f0184c01aa0259fc42
-yuva422p9be dd2a4affd2140d945c88c545cbd15794
-yuva422p9le a7a00cf6c696e8e94ce62576dbb28527
-yuva444p 8031aee1a4a13d679e3fa960b70e27c7
-yuva444p10be 62dc7423df2a90da591e313dea0f72b0
-yuva444p10le e45e36e79e39e1ed300fc93bc20a2232
-yuva444p16be c2321be5e7184b874cf4e16fff959179
-yuva444p16le 107836d19b0735f225eb7d97da98fd49
-yuva444p9be d8ba268bef3cf8d2dbd57a65b49be6db
-yuva444p9le f4589d40b7514e021ec7096003907ef7
-yuvj420p 9ba65711dfe07d3078b5b874b49240fb
-yuvj422p 05873ba9f14597ded3d4a2f6e1cd7e5c
-yuvj440p d76a421f62d692c664cbb2d1727e77d2
-yuvj444p 787e53351113065777bd1061ddb04834
-yuyv422 48d652c76bbdebec0bf7842578b39c53
-yvyu422 b0364ee13bd574d01b23a0809e6ddca9
+0bgr 4060279c35dd8810a2f55a021b836557
+0rgb 527ef3d164c8fd0700493733959689c2
+abgr 023ecf6396d324edb113e4a483b79ba2
+argb f003b555ef429222005d33844cca9325
+bgr0 6fcd67c8e6cec723dab21c70cf53dc16
+bgr24 4cff3814819f02ecf5824edfd768d2b1
+bgr444be 1cd47c1555f947dfcba99192e3429d20
+bgr444le e1832fdc9b118d4440ba03cea6e30428
+bgr48be 51477f029592ddb6b912980fdf2df7f1
+bgr48le b34faf404b33c74cd25f5f912ca3274c
+bgr4_byte 7ca99bc8a1c7c831cb955806ac05cb72
+bgr555be 6d32031ad4f52723023e547058a62c71
+bgr555le 823a3b2f2585e537da5cb76c8ce30cf4
+bgr565be 438b0f18fd754280d5dc2f421c376ffb
+bgr565le acab2b65c0fe5f9618c90f77f70ab3be
+bgr8 898a66734bda0572dfab1edd8239f6a2
+bgra 3934fb81a602dfa7d29420b1a66f0fd8
+bgra64be c8d3217bf58d34f080ac88c0b0012c77
+bgra64le b71d75a928aac14cb768403e6f6a9910
+gbrap ae09c3e9dcbe0d1ef21b2342be369210
+gbrp 5fbc319e30110d19d539f5b274eddb6d
+gbrp10be e71e0dc9c54419297e97a895bf57ab1c
+gbrp10le 11fb697197e79d27eeba4093a207e015
+gbrp12be 2a611bff3b8f63e1d99d0b0f5082eaed
+gbrp12le bd4529ca9bd680d23a16ec65fdfb313b
+gbrp14be b8ccc776dd1e57c39386d3cb5bdbe899
+gbrp14le 74431dd00ddf10d94d1db1496d10e42f
+gbrp9be 6d45b61c48b40c83b43cf2d4ecf4dc32
+gbrp9le bc80da439638c59f1d822037f52739af
+gray 188590b1231afd231ea910815aef2b25
+gray16be 08d997a3faa25a3db9d6be272d282eef
+gray16le df65eb804360795e3e38a2701fa9641a
+monob a6869bab4f6e64fe13dcab13b41775b3
+monow 0404328f1838a6503371478a559ca20d
+nv12 8e24feb2c544dc26a20047a71e4c27aa
+nv21 335d85c9af6110f26ae9e187a82ed2cf
+pal8 d9a58fa1964ba9a3b902797b0b1af0ab
+rgb0 0de71e5a1f97f81fb51397a0435bfa72
+rgb24 f4438057d046e6d98ade4e45294b21be
+rgb444be 115e5259b91f4a416546b09570347633
+rgb444le f3f66689cb4c810563fba7665c526800
+rgb48be 18127d8ec64aa21619ada80b93514906
+rgb48le 60d0ba0e5a429c947aaa736be54aca87
+rgb4_byte 7d68393a3de6f392cf2ed05ffaec6259
+rgb555be f76c8109974636b54bd0cb4c36bb883d
+rgb555le 21daf4d05999ccf3eef7d492e73c4d5b
+rgb565be 85711f35f71340ba23e553a07d246656
+rgb565le e04771e79a8ee8a51e9a325540e6215e
+rgb8 7ac6008c84d622c2fc50581706e17576
+rgba b6e1b441c365e03b5ffdf9b7b68d9a0c
+rgba64be ae2ae04b5efedca3505f47c4dd6ea6ea
+rgba64le b91e1d77f799eb92241a2d2d28437b15
+uyvy422 3bcf3c80047592f2211fae3260b1b65d
+xyz12be a1ef56bf746d71f59669c28e48fc8450
+xyz12le 831ff03c1ba4ef19374686f16a064d8c
+yuv410p 5d4d992a7728431aa4e0700f87fb7fd8
+yuv411p 7e1300e89f5bc07939e2c4a6acbdf267
+yuv420p a014c7eb7a8385d1dd092b7a583f1bff
+yuv420p10be f9b154364efaa1af376fa6d8eeae6955
+yuv420p10le 15c83294ef560d57f25d16ae6e0fc70c
+yuv420p12be 34da9c4e289124122ba36a9d4fb133fa
+yuv420p12le c19a477a07fcf88e37ab37b416d064c0
+yuv420p14be 64779858686946fc0e780baf7c1391b6
+yuv420p14le c1d012a4f9d54fbc8b04fea96d85e903
+yuv420p16be 268b07358d8dc733ee81d0b87990d5af
+yuv420p16le dae8da9edd4255051e3e546ae7ed9bd3
+yuv420p9be e86ecd4112c86637c96f2b5e90341da1
+yuv420p9le 4496bea8504dce651485cc8a7e8403c9
+yuv422p 74f8006b4482db104f1986f49807a0af
+yuv422p10be 7291903c3c0cf4e5456dd9673a619f1d
+yuv422p10le 14cbaa728e888534359b9dddc5430f08
+yuv422p12be e9bc7f2da217fade40feb6960dcd894e
+yuv422p12le 8d8184e4d0f1eb50e1834ac0c4af8c33
+yuv422p14be 2617c569ae9659d8fe6a01f96e2c9657
+yuv422p14le 7d01363cf090306cf93337c474cd8827
+yuv422p16be 86147d8bfb795ab1873c899611e2a361
+yuv422p16le 9df47cb7d6d39b335a547ced2865e72e
+yuv422p9be fdd15494de6cfc8c3f15650ecd3d8046
+yuv422p9le a112fd777494d203d9d8e9623a50e503
+yuv440p 98d0f96fdb3ba415899017adf7d4a4f9
+yuv440p10be d874167042037c1daf9b9a2f74bffad9
+yuv440p10le 3cfbd921369aa8f1e4977efdb7f44c8c
+yuv440p12be dc3e6a40c44d5a5f9fd260b270e9037f
+yuv440p12le 2fff7746ae7c07d407075c0e372baf46
+yuv444p 8f90fb3a757878c545a8bfe5d19a9bab
+yuv444p10be 6683d5cb82c708d5f3a2a89d0311f7a4
+yuv444p10le 6d736fa464ff2de2b07e0a56af8444b7
+yuv444p12be 04320ad158450ee158f84a27c6325702
+yuv444p12le 08a81b2ea9c7c8b447e40ef8f4a46a4a
+yuv444p14be ea3057d469d0c49c24e844256ef7871e
+yuv444p14le 940f5908ccf06e01411f0a7bddb45c6a
+yuv444p16be aee24ab2e9a4656f889399f1b0d98639
+yuv444p16le 781c22317c02b3dd4225709000bdb847
+yuv444p9be c37eb400483012fd97a030431818f328
+yuv444p9le 2136d762328cb9ce168b6261b7874791
+yuva420p b227672e56215e184e702c02a771d7f3
+yuva420p10be f66e7d677625380f7504867fab51305c
+yuva420p10le 01e94ee605714396e69b013c11dda348
+yuva420p16be 76e5e65eae1e7c5681a397a3462f4a9d
+yuva420p16le b1930ab28ffe031c78ca28d3406311c8
+yuva420p9be 48dfa24cf0ea3864f35285074e8fa888
+yuva420p9le 0e9c9803aaaddc9f38e419de587793c2
+yuva422p 8f6bb778647e5dee62f544d646321171
+yuva422p10be 2f7204c93a1e5bfb04538852f99e4074
+yuva422p10le c8082548aca999edde77ef2749b1ff4c
+yuva422p16be 427ad55f7464121bb3ce164641772bc6
+yuva422p16le af6f8df651275de58129e010bb45ffcd
+yuva422p9be 47579cc2cea861ca1461589b80c4720f
+yuva422p9le aaeab2bfe80a29390e8666103ed8bb40
+yuva444p 459fad5abfd16db9bb6a52761dc74cc1
+yuva444p10be fa16bae4fc25429deb944ffa9f5b28a0
+yuva444p10le 92f820d3481b7ebcb48b98a73e7b4c90
+yuva444p16be c80c1899789a6411d0025730efc8f01c
+yuva444p16le 2ed56ea50fafda4d226c9b133755dad8
+yuva444p9be 4903fde22b15d28da90761ac1cfcb1c5
+yuva444p9le 4eeb5988df0740fea720da1e31bbb829
+yuvj411p e003eefa7e2a20f20d33767775417216
+yuvj420p 8f3d8f1b4577d11082d5ab8a901e048d
+yuvj422p 79d480e99e610112f266c833c6cb3d35
+yuvj440p f4b18310c7174868fc92579f87460876
+yuvj444p b161e6d5a941e2a4bb7bc56ef8af623f
+yuyv422 435c92283b538aa3d8fa2a020b0afd49
+yvyu422 8436c2a760291cc979e0dd62ab8cede0
diff --git a/tests/ref/fate/filter-pixfmts-pad b/tests/ref/fate/filter-pixfmts-pad
index a3d455abd3..122f1ff749 100644
--- a/tests/ref/fate/filter-pixfmts-pad
+++ b/tests/ref/fate/filter-pixfmts-pad
@@ -1,17 +1,27 @@
-abgr 3dbc32909d43adc2a00f8dc267f4954c
-argb f35a99b4c7334d30d8338b5091ff42bb
-bgr24 b946a53a21bee12c6bacf7c9eee0464e
-bgra c12f833549d02143495031161167130e
-rgb24 203a6870c2e78acdd88594204f48485c
-rgba 3cae5f1cd260be32a588ad9ee00d761b
-yuv410p f62c12181d4367bcd22a114288f8ab63
-yuv411p 7ed82814854efe8b6ecca1dddfcf2f4f
-yuv420p 776d85a7a7f60f87bae5ac01fbefc8e6
-yuv422p 31de52cc5bc44973397e29e40a72f10b
-yuv440p 87666e1ff40ef0d6145d583dc9e0593c
-yuv444p 1b1e0dde6f5d663ddc80cdf69554327c
-yuva420p 4a36d4bb207e898058e72f8aaf2aa86f
-yuvj420p 4d1ec70f1ba1eb04b16113807c78c534
-yuvj422p fcf366fe525a5be6e488542448a10e30
-yuvj440p 2315e0d1bcd2ae6493207149abeaf97f
-yuvj444p 6da403666e2d0110161ccf0737fb35aa
+0bgr 7bc6f5a1c44cdd7506174dccf52c68d7
+0rgb ff12e0f1e576b47a4c962729d5c0b868
+abgr 52738042432893de555e6a3833172806
+argb 2a10108ac524b422b8a2393c064b3eab
+bgr0 32207a2de1b2ac7937e940a8459b97c0
+bgr24 f8b65ad845905c7d0c93ca28dfbb826f
+bgra 929aac15e848038e367c250037575f9f
+gbrap 6712984b4a068ffa534f0cb35b2adc6f
+gbrp 3c94d39256db2409015df913fd330a90
+gray ddc663a0491df3959d9c5795dceaa72e
+rgb0 78d500c8361ab6423a4826a00268c908
+rgb24 17f9e2e0c609009acaf2175c42d4a2a5
+rgba b157c90191463d34fb3ce77b36c96386
+yuv410p cb871dcc1e84a7ef1d21f9237b88cf6e
+yuv411p aec2c1740de9a62db0d41f4dda9121b0
+yuv420p 4398e408fc35436ce4b20468946f58b6
+yuv422p e43d68568d9f782908ba56bf1e09d5d5
+yuv440p a7e34de74c96b0224fe1381ec1db2ba7
+yuv444p 6bfd89286dc36f2789b77d747ed8fa22
+yuva420p 842c27169ecdcf6de79f2b787367b51c
+yuva422p 91dcecc4bfdff1f0db9ef8b9b5b9ac2a
+yuva444p fb60941a57596b277417a3c7c00aa194
+yuvj411p ca967e68759a4956729dd366adc7e7fa
+yuvj420p c00611cd5f1558047d579d8a7d30e381
+yuvj422p b3acdf07147a7598836065836ad8420b
+yuvj440p 3446ba4b1d7fdf536c926cee643c2b35
+yuvj444p 3b0f1a185af048b9e0b202d003fc7e62
diff --git a/tests/ref/fate/filter-pixfmts-pullup b/tests/ref/fate/filter-pixfmts-pullup
new file mode 100644
index 0000000000..c6ddb3489a
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-pullup
@@ -0,0 +1,12 @@
+gray 415c928947f83f9b45c24ad15a094bda
+yuv410p 0f29d0b6394871e1e6cde484b4f351f4
+yuv411p ec059b1992e1acda472b9b2dd3e4506b
+yuv420p dba6303cd02cc39cb0db7b546793d565
+yuv422p d7d3224dd900bb1b96608a28a704360d
+yuv440p d4c5f20701cfceb4bbf7d75cfcc13514
+yuv444p 7e405274037e7f2ab845d7413a71e16d
+yuvj411p dc602e7bd3449d16e17e695815616b1e
+yuvj420p b98ec86eeef2d512aeb2fc4d32ffa656
+yuvj422p f09c3240bb662477b76ce4da34b4feed
+yuvj440p 8d3ab69e2bbbbbd2f9be323c18922533
+yuvj444p 2dc27560eed5d685354796dcccce853c
diff --git a/tests/ref/fate/filter-pixfmts-rotate b/tests/ref/fate/filter-pixfmts-rotate
new file mode 100644
index 0000000000..e7bbb5545a
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-rotate
@@ -0,0 +1,20 @@
+0bgr 4060279c35dd8810a2f55a021b836557
+0rgb 527ef3d164c8fd0700493733959689c2
+abgr 023ecf6396d324edb113e4a483b79ba2
+argb f003b555ef429222005d33844cca9325
+bgr0 6fcd67c8e6cec723dab21c70cf53dc16
+bgr24 4cff3814819f02ecf5824edfd768d2b1
+bgra 3934fb81a602dfa7d29420b1a66f0fd8
+gbrap ae09c3e9dcbe0d1ef21b2342be369210
+gbrp 5fbc319e30110d19d539f5b274eddb6d
+gray 188590b1231afd231ea910815aef2b25
+rgb0 0de71e5a1f97f81fb51397a0435bfa72
+rgb24 f4438057d046e6d98ade4e45294b21be
+rgba b6e1b441c365e03b5ffdf9b7b68d9a0c
+yuv410p 5d4d992a7728431aa4e0700f87fb7fd8
+yuv420p a014c7eb7a8385d1dd092b7a583f1bff
+yuv444p 8f90fb3a757878c545a8bfe5d19a9bab
+yuva420p b227672e56215e184e702c02a771d7f3
+yuva444p 459fad5abfd16db9bb6a52761dc74cc1
+yuvj420p 8f3d8f1b4577d11082d5ab8a901e048d
+yuvj444p b161e6d5a941e2a4bb7bc56ef8af623f
diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale
index fbbc1c9f47..4d1cb7d812 100644
--- a/tests/ref/fate/filter-pixfmts-scale
+++ b/tests/ref/fate/filter-pixfmts-scale
@@ -1,91 +1,123 @@
-abgr d7f91e65b25b81f43e8b4d5076116fb1
-argb 3b1964f62ab059fc8d692c63f1fc450c
-bgr24 dcc565b1ffcdae2f60e9759d4d33f596
-bgr444be ba5750740f17cb862e56628683b64258
-bgr444le 2c872b0b91347a35ca00cad816ff3f89
-bgr48be 650aaa8f7db84bcf5c6f2b3da86ee803
-bgr48le 90b82c85b88296fff879c60f21182ae6
-bgr4_byte 7b4e4dc6ae1cdf9e18d9eba79a5b7d23
-bgr555be 80fb87c21c07bf833926c9675ebbe01d
-bgr555le 4539913198858f1bc3899aad97ad105a
-bgr565be ac67f35b6bc7835d1fbfeee3ef89fd59
-bgr565le 34438643c183ff1748cf7d71453f981c
-bgr8 e731ba3dbec294e1daa7313e08e88034
-bgra 6e1f417ae41636f631de1cfe39ce1778
-gbrap eefdbfd1426765ce5e9790022533db0d
-gbrp 5d14768d2ab6cbf3879966b5d5c6befb
-gbrp10be 4192c246f4a52ec7a37919665190cce9
-gbrp10le 170189b2c2dd46f31165d8fa6cadef0a
-gbrp9be 01c837e1def99abec205b80d21b68bf0
-gbrp9le dd982d59c3d71c3b201f2d9363d8952c
-gray 4c571fb634a75f177b64cee168fbf3a1
-gray16be 9b57ff7d2090b47e4427bee79dba0d9e
-gray16le 17d2c00c6ffe346dfb632d927ebbf30a
-monob e28955319a03f1850c467f8fe65b2a22
-monow 69334639f5298173154b262d9054e384
-nv12 e7638156463b059aa75b1d667c89367e
-nv21 adbed0790db2c85c9e777a84acf0c290
-rgb24 6187e90455674633e7d08451a99f17b1
-rgb444be 4ad70310205575f370fa7a9ebee119a2
-rgb444le db9a9973e41a0d583d9c1b536e7717b3
-rgb48be ae0836178249743c91867ee057baf7d9
-rgb48le 49564ae5cab04678889064b1132b44b8
-rgb4_byte 62269884de14b7defbdc7fb8044203c3
-rgb555be 3a1c13bbae95358f9cc23f4a138d4867
-rgb555le fbd6b3d1847ee6c9ba9033fce72ac18e
-rgb565be fdbb84b9f559b4ba14c1407218c79795
-rgb565le 9cea852347ca6ba09944f577ace89d2b
-rgb8 eeb820691b7fd1cb07a0fa066098f926
-rgba 68a05bdcf4abe3b92353d1e4386c94c9
-uyvy422 1d9946bcceb6d13cf0f0deda322a9868
-yuv410p 2cbf84ef9f283b00aee46883653dab8c
-yuv411p 091777fdfffa2dccbfd75769d1a402c7
-yuv420p 4f0105b3f2008bff284de251fe61ce06
-yuv420p10be caaee5d071cccf50cc51c70f7a233024
-yuv420p10le 06c47286459599c62b25466e2ee3c91d
-yuv420p16be 10ba255f3901b5d47d3ac803fb787bcf
-yuv420p16le 38c42f658cad8546bfc465b72f6312ab
-yuv420p9be 17cd0ca2d12fd972045271e06a14b711
-yuv420p9le 38289963713431c8b4a2e7c08b8564b6
-yuv422p 66f47bfad422275bd07b2881760d09a2
-yuv422p10be 00504b09c67e203fc29cac3ae2aa91db
-yuv422p10le b8b38a8d1f1eec3915b628c873bf756a
-yuv422p16be 2f12b4fb816afcaa77e7359b95f25532
-yuv422p16le 3913bbbd4b0aa8038e8565c7312e25be
-yuv422p9be f86744d026c3a65d54c737a93e80093f
-yuv422p9le ad53382760dcf7cce4317247aa0058f7
-yuv440p 4713a7b7ce80dd06923626d13589c098
-yuv444p fd733672651ad5bbffb046fd67151fee
-yuv444p10be 34b38d54167df70044bdc08518d91009
-yuv444p10le 0812e3371c9589c6621408812f9e7a27
-yuv444p16be e89fe5a4624ed06603580b4a74af9170
-yuv444p16le 6944d11048ff4013c5e60359faf1bd2d
-yuv444p9be 04a950e843d099eb9ade2ddcea494fb3
-yuv444p9le 918015450d5ab87600de64bbb7b33a10
-yuva420p 279eec11fe81f48a6cf2950fe097c51f
-yuva420p10be b9178665f4ff9512b10552f212157a94
-yuva420p10le a627c535ced8514f2e1d1b78e73ca046
-yuva420p16be 2ec22c863c67bcba0295e125d0fa9f3e
-yuva420p16le 98725d82a8cc4cf0d2c8673a4e7a7904
-yuva420p9be 44cd32fba1717fc8cf0e11e23a2b601f
-yuva420p9le bcc9e4b4e78d032e2f7b7ced418ad218
-yuva422p 026c5cdefe5d34892e0bacbd0a59c71e
-yuva422p10be 69926b201407ed64fc84abe878be9778
-yuva422p10le 3a4f9779467d055e85aca502fdec32d0
-yuva422p16be 7cdacc54f1fdcad30a69fffa393280e3
-yuva422p16le ab4a73cd006559cc8a276f37e481a817
-yuva422p9be e517391bb53c4b0f8399a5b3155bbbf9
-yuva422p9le 6b66e4543e1fa4583909cfb03bf842a3
-yuva444p b931c613cf41f29673cecc0d6e8c3ef6
-yuva444p10be 3ae3aca8e9d72905df4db6e48cd1aa28
-yuva444p10le 780a786f9205a40331a6ab4ae1b976f2
-yuva444p16be 48e17ea2342cd07d5c2996610f33e543
-yuva444p16le c42df24e7389fa3ee44b05dfc973a482
-yuva444p9be 26cb299ae97a75a86df04daea1d0999c
-yuva444p9le c3e986b78252b413c08d77bcf9da5ab1
-yuvj420p 72ccdc3bd9a363a3b6f1072060df0518
-yuvj422p 278fd54d0e21a3958c46b7f1e680740f
-yuvj440p 413af44fd797db64eb5e72ff448c9ae9
-yuvj444p 9b59dd2345672db000d8baa4a2bc1e20
-yuyv422 dcf49cd849d061a7dcec8bd72adee30f
-yvyu422 c8ef92b4a717f832ff150ea6e78c7e65
+0bgr 0576e427ba28f19e55a856f528e7c282
+0rgb 80a58af8c639743307207ab4b69ca863
+abgr 63f2eaa8712ea6108985f4a0b83587c9
+argb f0e17c71a40643c33a5bcfb481f6d8f8
+bgr0 243d58ca64f97b2f415b4c63cb79f0e1
+bgr24 18744aaab4b8bce065a7144dc0ccf921
+bgr444be 920760bee08c4fa161bf060e21ebba92
+bgr444le 01be36a28ebca1a11eb4d192986cd4e9
+bgr48be a6fee4ac9f70d0da6a4b3a0e6353ca7f
+bgr48le 9c5d30b3b31ceaf3009fc7f1cf1cf7b6
+bgr4_byte 01efea74088e5e3343c19ee053b95f31
+bgr555be ab353278d103d379e1ec86e5cabb645f
+bgr555le 16ccbf59297e4b9ab25fd8af5a84a95d
+bgr565be 3477e19fc11f95285836f30fdff26c1d
+bgr565le 82a81e7c9d4e0431fa22f4df9694afdc
+bgr8 2c57e76ccf04d51de6acafcf35d6fa70
+bgra d8316272bc3a360ef9dff3ecc84520a3
+bgra64be 688499004461a2ce9debadb36dbcde5b
+bgra64le c80dda435633c301e14d5b46a7edcf8d
+gbrap e97ea4a104467c482173b7eaa57c14e3
+gbrp dc3387f925f972c61aae7eb23cdc19f0
+gbrp10be 3a6d59192b6bb89ab42252b2b4818519
+gbrp10le cc2d60d381b25fe2813540409f2d0af3
+gbrp12be ea1da9b3c48baebcc651084b0884482c
+gbrp12le e02a436dc448793fc8c64c9412726274
+gbrp14be a065297ab4ef2f2f0c503f8f2ae43bd1
+gbrp14le 7b07beaf54e2feac774d3c905cbbf15e
+gbrp9be b7bc652518457356444a840ef6d2bc56
+gbrp9le 0ed709f7828f0be5f828596f0720a82b
+gray 221201cc7cfc4964eacd8b3e426fd276
+gray16be 32891cb0928b1119d8d43a6e1bef0e2b
+gray16le f96cfb5652b090dad52615930f0ce65f
+monob 337d236f59b891b16dd17c5267cf874b
+monow 3cb791057cf735930f97fe67e5125c45
+nv12 b118d24a3653fe66e5d9e079033aef79
+nv21 c74bb1c10dbbdee8a1f682b194486c4d
+pal8 28a5374b56a7d3e37f95ddb8469f14dd
+rgb0 fbd27e98154efb7535826afed41e9bb0
+rgb24 e022e741451e81f2ecce1c7240b93e87
+rgb444be db52b9ecdf98479b693e3f4bd9e77bac
+rgb444le 63288425c05f146cde5c82b85bb126e0
+rgb48be c2e456838a71237cb1398ab5a7c35a6e
+rgb48le 6ef772549307349c599f419313c75b7a
+rgb4_byte 9e540a2e7193ebcbf1c7f85d192a0c4e
+rgb555be cb5407a0d40f3d0120155daeaaa9a222
+rgb555le c15540d1fc887882c35860634009c439
+rgb565be c69fa7d6e458509de65e911d147629a8
+rgb565le a4a6ef89cdc10282b428cb1392f2a353
+rgb8 bcdc033b4ef0979d060dbc8893d4db58
+rgba 85bb5d03cea1c6e8002ced3373904336
+rgba64be 21611863fbbe149416a11e95877824ac
+rgba64le 35c195a441e5f8ca8e7e4ed098ecf0c1
+uyvy422 aeb4ba4f9f003ae21f6d18089198244f
+xyz12be f6350b9a2f5add20d3d67f59c100166f
+xyz12le 982935a6ea6a297fd7be8aee0fda9870
+yuv410p e8f49b5fb9335b62c074f7f8bb0234fc
+yuv411p 5af32557c93beb482e26e7af693104c6
+yuv420p 5d3ac239c3712143560b1dfbd48a7ddd
+yuv420p10be 95256d0cefca26429b2f41aabc9bee04
+yuv420p10le 1aae90a2cff18e516f004dae77ac78f7
+yuv420p12be 25a6da0f8045bc7bdeda544e1cf2387b
+yuv420p12le c6e40a0851e1237281cd6500bef7a1fa
+yuv420p14be b202fde5a53d529ddaa35c9467ff0b61
+yuv420p14le 36cac5d88b0d566cf835e84da6513e5a
+yuv420p16be 6f307c5b1a5941023f9029cb3a616f5c
+yuv420p16le 11f4bfbd4a058b58aa26dc47a86061f7
+yuv420p9be 43a800248882c33825a54a686e89be54
+yuv420p9le d9f9238eed6e704c847e5007f5424fba
+yuv422p 9823e4d6bd1482b0cab3c44dab67f0a7
+yuv422p10be 42b9b936392b4a6a678028ace2cdcd20
+yuv422p10le 4bdc5e9ab3a16409600887335dbb1a66
+yuv422p12be af6ec8146dd7860b510017c22e8d0c80
+yuv422p12le d69676f61d2693cfd163b3ce3f79fb56
+yuv422p14be 2a005a86b80b947c953d11ae170551c7
+yuv422p14le dcbde0634eb70bed62dde097c80a1643
+yuv422p16be a772b46454e415ce454c0999ebb71486
+yuv422p16le b4f64306c671ba4aa2eb23732ee02317
+yuv422p9be 1f991e6c661fe1e5840b05cb37945529
+yuv422p9le 7987ca4dbbf658e8dd87565fe225c333
+yuv440p 483b8427cef7ab9c94d6b3f26d0ab094
+yuv440p10be b93618311430e216a3d6736182fe7c04
+yuv440p10le ca2c882018398d2a126c1ec65e8336d8
+yuv440p12be 373ab37ba2498cb11de24218d686e0f8
+yuv440p12le bb9ffc3033fe32b9ce3233524ed5ab70
+yuv444p 098f01e6790e1e6beff8d604120c2664
+yuv444p10be 024ee33cac7b5b7b225d7acb9dc59da3
+yuv444p10le a085fff2fb81d76753da689aee365b55
+yuv444p12be a181627b93bd9c4c384b83e17d373a7c
+yuv444p12le 97e47326ff0efe89c295fd9ddb0ca854
+yuv444p14be 3eac31f0d4969210640de74914faf86d
+yuv444p14le 2c362c4cf167b7e2d83f4eb0dfaeb2b9
+yuv444p16be a60c674411d64cc4b9fbf17039afffb3
+yuv444p16le 0a490fef1f2631367ee362d20a336efe
+yuv444p9be 3f1eddb729b029669cb3cd441c2517c0
+yuv444p9le 74d9db458b659935d82ebe3cbca920bb
+yuva420p 05a12916f04859bb2c9a6decf624af74
+yuva420p10be df8b3acfa7ac6ad96929aac1aa6c0102
+yuva420p10le a5cc4bfc952ad1bc6f033d136d5a821c
+yuva420p16be 01c74149a6696d0ee71232881622ac3a
+yuva420p16le c78a814ad6a2cbbab4b422724f0c7ba9
+yuva420p9be 57b730421849f8ccfe7913c664396376
+yuva420p9le 1fdfcde9cf7ef1d41002175b5793435f
+yuva422p 3a80cb3e08782033aabfeff1e8969403
+yuva422p10be 94b13db95ceb970ded9773c095ade7d4
+yuva422p10le 544965627ee94964b9cc57750c385b31
+yuva422p16be 95be33f9599958669f3c1cb24e54a5e5
+yuva422p16le ed83cc6e8fb70306d0622962504d1fcf
+yuva422p9be 5ff6aeca90b8392133d7b1addfbd639b
+yuva422p9le 451965b076c628b0eabaa4ef33f98ded
+yuva444p f120326d9d940c9ac5cf5fd160969b82
+yuva444p10be 1838cd61a24fda56a7379c9cd9cb1629
+yuva444p10le c5c2f602caab63c58954f5a80691436a
+yuva444p16be 39ca2e32aa61b210b6c528855d24a16b
+yuva444p16le cd2e0a001d8175f2204b2eb411c6a801
+yuva444p9be 58add24afbf43ff0ff7079cc1948fb56
+yuva444p9le 077c8cec2c374163d7f7eae27e797bdb
+yuvj411p d1076331c75ca66bf62497edbd8384f9
+yuvj420p 10390e6dda9cbb4c61fb88bcbb49fc3c
+yuvj422p 996f6672566a4dcd8d272f48f058d49e
+yuvj440p 3d80c9f67f8ef9b2d8a9ae2d37b464a2
+yuvj444p 9f858b9ca3fe949611147414573a904f
+yuyv422 1704675eff94ad0a03a9a6a3ddf5e0df
+yvyu422 516705a40f43d00e9c41ff47f4f7b802
diff --git a/tests/ref/fate/filter-pixfmts-super2xsai b/tests/ref/fate/filter-pixfmts-super2xsai
new file mode 100644
index 0000000000..3c7e65ab5a
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-super2xsai
@@ -0,0 +1,14 @@
+abgr e21be14b5fe9d7a29740a418c325b17e
+argb 563489534663cb2b32beed2b41370c37
+bgr24 a933eac9bb53c3ce3c33950b229996b5
+bgr555be d6d14ec3ae9ffffed3006a253e9b9a9a
+bgr555le 70b819425f79f823356229b90b41cc84
+bgr565be 4ffcc26e740622ffd3314fe251e97804
+bgr565le 6fb9dc50a81b853800ba65d5ec6b8417
+bgra e9cc6644e2f35103c241094ab4bb8fec
+rgb24 3fd7653f414f350ddb0c0a236ce0c809
+rgb555be 0f34c006142babd10065d90b8c2ce3d6
+rgb555le 53325a20c913826566880eb25d1d2946
+rgb565be 9889faf1a636161f3049b78e92db7d89
+rgb565le 14fe550f449a7539d9f1e99e85cf40f1
+rgba 7041184d35c316e73e849504b64bc4f6
diff --git a/tests/ref/fate/filter-pixfmts-swapuv b/tests/ref/fate/filter-pixfmts-swapuv
new file mode 100644
index 0000000000..ff24773ae3
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-swapuv
@@ -0,0 +1,66 @@
+yuv410p c87be6ce12b2d505935893b733e21ee4
+yuv411p 2a8b6b718d437e0bd15b614ea0723a82
+yuv420p 60976c86cb8b9a7ac3a11ba874134f22
+yuv420p10be 84f6ed35268d552fcca83629ab6aa4dd
+yuv420p10le 559e8f10eab594de72d2b081bf9d480d
+yuv420p12be f4650c64b173a906d33719e49c0cfb9b
+yuv420p12le 26370ea437474d2b53ace1e55ee53faf
+yuv420p14be 970fa43a1470ddedbd874c726a519293
+yuv420p14le 5a18b1d6f439077208556f2d2a80becd
+yuv420p16be 97009aa152a4c6dc383b75c551ffa71c
+yuv420p16le e7201caa7838647aefee41ae9e098110
+yuv420p9be 9a0b5dcfa50706676bf818e7215c3036
+yuv420p9le 850d73c33b3d5c55f4fb984871bf5b0a
+yuv422p 80c6bc82f4bc330df1895c8f998e34bf
+yuv422p10be 0aeb0cd5949ee258355fbe4ff2f84a56
+yuv422p10le 1bfff133885efb1c44dfd9191b6f241a
+yuv422p12be d0b86084ce9330782fa24c4bdb3f6bc1
+yuv422p12le d46f2dd548a3edc0b1e3870ce112b722
+yuv422p14be 91a75ccb62fd1149069c6b7b26fe195d
+yuv422p14le dbec6e0152daedafa161437fc931b1e6
+yuv422p16be c5de1a3fd28f647cb14d293061312f80
+yuv422p16le 56d4e3285312b1a24f299bef44f4dc15
+yuv422p9be 31bdd7e06ccd5272df355acbf213522c
+yuv422p9le 77022abb447608c874816675ba1e6aa1
+yuv440p 563fd94ba1ddde6f3cd34a815ec03165
+yuv440p10be 2aadf346979813cbb336c0a543fe243f
+yuv440p10le 9e34483ca0850e2d701a8a6d8ca9a0f1
+yuv440p12be 287406f4129717ae52d0c443cf42c207
+yuv440p12le ecbf69ad94f2917251f1ee642c82e8ae
+yuv444p 184ae83da74e478595258db9e6af0827
+yuv444p10be 224d0e8ed36e9e72ed171aeba6483523
+yuv444p10le b525bc915f533a2a82b3ce525693bb9b
+yuv444p12be afdf75fe13ae792c4e0fa2cfb9e5bd1e
+yuv444p12le f161ba8f5c036deac7def77ccbda67b7
+yuv444p14be c87e248a2c605515f11afd8f1251db67
+yuv444p14le 3085381c2b70642fc95c6bb153d766a1
+yuv444p16be 3d99c4af5cc1ddc3144a10e0b2b75951
+yuv444p16le 56f7022d0aeb4c4f56c6451e431d5390
+yuv444p9be 7879b676f67cde59ddc7c73f8a505918
+yuv444p9le aa8e674a19322b0d89d7930347428e90
+yuva420p 8afb004ce37ac4d9f881c138b25c414a
+yuva420p10be 7417eee3faa13dd69a2335996fd4ed14
+yuva420p10le db1e7e8bc49adb2180d8dcef665331b7
+yuva420p16be 949443d63e99f714b2dfcb5b79033d5c
+yuva420p16le 22c6b3317ece86f461aec210179571be
+yuva420p9be 1125f7298fc3f69725ad793d16c2da12
+yuva420p9le 7f445bfa33b6875cc65b47cee24c3154
+yuva422p a1bd5c90b7bde1d3657025612a6f231e
+yuva422p10be 05bcc2394cfb0406d37b942423f6dbe7
+yuva422p10le c166994709af82b9cdcebe4a7057348c
+yuva422p16be 9599ed5721f52028c3acfeb7b33ddc87
+yuva422p16le dbb74e0bb2cf732e39e669f60ec6e1cf
+yuva422p9be 39093fec98b02e83b7e20dab3e5e4cf6
+yuva422p9le a0a6dd2e62ea01e8a2268c7d88385252
+yuva444p ff2441de373fbfaed7bc199a7abe5a3e
+yuva444p10be 857043b712213eee329d2fb584d74c3e
+yuva444p10le c3c451b3605af959a5d80146f4170e9d
+yuva444p16be 356d72791dfd91861b21630e315d40cb
+yuva444p16le 176591ce074ba8befc5fb279446ca1be
+yuva444p9be 675f0ed3e6572b05f06d9e44611bdff5
+yuva444p9le bf3ea2bf123a3a1ceedf587682b85cb9
+yuvj411p 361c32e086bd27cf3ded194dc00dc9c5
+yuvj420p 553ac1af571391271d9715e2e8a4a5cc
+yuvj422p 39b613d01cacfcdd9eecf9e0d379a393
+yuvj440p afed4ad98d6accf5811d439f3a687aa1
+yuvj444p 8de64aff4b7b3895d8cedd67cc10722b
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_merge b/tests/ref/fate/filter-pixfmts-tinterlace_merge
new file mode 100644
index 0000000000..e5d3bf0383
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_merge
@@ -0,0 +1,14 @@
+gray fab3a7abc4f076cf926205aeacadbe51
+yuv410p d4506e49eeb64c7ce714c07597e7dd69
+yuv411p 2e8bb385cb4a53a0f3771815020f7213
+yuv420p c967d3d5f3200d1b2417b0f2356f12fc
+yuv422p febaa84ea2e3246af742a7ed37c030f6
+yuv440p 13a934b42df65f11e153314ebb4f311e
+yuv444p 45d4466f5689942a4effb0fd23e44949
+yuva420p dc1173a07c3f993b277ea0c94d513e1f
+yuva422p ca200be80e5bfdb159e1aea57129ed3a
+yuva444p 9f39c35d6899dcb8b9a9b07c339ca365
+yuvj420p 844359293bb6ff81549f3fc0090cc587
+yuvj422p 526af049d43974822baa7b48aa1e1098
+yuvj440p af9285194da8efbc40d93bf8109f9dc5
+yuvj444p 2a3f18b02c17a0c39c6245b8b3639b91
diff --git a/tests/ref/fate/filter-pixfmts-tinterlace_pad b/tests/ref/fate/filter-pixfmts-tinterlace_pad
new file mode 100644
index 0000000000..dcf2168fe1
--- /dev/null
+++ b/tests/ref/fate/filter-pixfmts-tinterlace_pad
@@ -0,0 +1,14 @@
+gray 7ef396fecd8d1c9fe32173e4415ba671
+yuv410p 35bc11d0d32efc9e9a969be7d720f4e6
+yuv411p 17ef3cd22a74f7368b5e02f68779f294
+yuv420p 93d5b6a4c44d67e4d4447e8dd0bf3d33
+yuv422p 3ee40b0b6533b9183764b85c853ec3f9
+yuv440p 1d3c1258a51d09e778cd8368b1a4126f
+yuv444p 1093568ad8f479ec20e738d018dd3f8f
+yuva420p 4588aef20c0010e514550c9391219724
+yuva422p 3426ed1ac9429202d8c29fa62a04d4c3
+yuva444p 1b9fc791c7d774b4ba8c9dc836f78cf5
+yuvj420p 9a872e0c1b3c0b6fe856415696b758bd
+yuvj422p da3c9ef25528a2ee96746ce44e6969f3
+yuvj440p a9a5495c6b0e2bf6e561998ea1c356a7
+yuvj444p 085214844e83ad47b4f33303db0ebee6
diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip
index da13b160f9..ac9f003067 100644
--- a/tests/ref/fate/filter-pixfmts-vflip
+++ b/tests/ref/fate/filter-pixfmts-vflip
@@ -1,91 +1,123 @@
-abgr d8d94531620310ec8a731af8d7fdb0ff
-argb 8bc98feb8e990e4ff411663deb9aa566
-bgr24 0a56e4b125552a0660f85f9e3169323d
-bgr444be a4c570c5a6abb38295141fb6f17670c3
-bgr444le 4ed7bb09f3f4f68a12ff2d8e7c837b5a
-bgr48be 9c5191d6db9c7b1abaa9f01b06f02fd4
-bgr48le 31e97c178ad0c4a18ad6690832dbff31
-bgr4_byte 8edfbb2878970f0d44fbf589664c821f
-bgr555be be4a39677809398b4299c9fbf363290d
-bgr555le 15b938709fffc9348ea50cd46b918541
-bgr565be 3c48959244ef268a37e8b3732023e5aa
-bgr565le 6f98ccb05e608863ef0912b9a6fd960b
-bgr8 1f916a75563e6be42c056e7d973a7356
-bgra dd8eaea69683884ea45bf2fb635ce415
-gbrap 38e04cbd4dc5566586d58ffed0c6b20d
-gbrp 37954476d089b5b74b06891e64ad6b9e
-gbrp10be ec01c15ed248a72c42f84a2a8cfec56f
-gbrp10le be52e72a59d87a43727262bcd90967cd
-gbrp9be 2ae8f0d3b079d6550a2b1d4a7c4a6e4b
-gbrp9le c62df0f386c957cc9cacb3c8014542eb
-gray 684ba667effbbf5983f46a9bea4afaae
-gray16be 112077b2f1c85cbd44907ed271901b28
-gray16le 1d7be18af19f4ff847ff4bc7c610c8cc
-monob 0e4946183903fea3ef246c16385e236c
-monow ba546dd99f6bbc4b7d310961df4d6d98
-nv12 2ca05c89d890eee82e1b37aac179d7d1
-nv21 4b2a85b79266097177314a6e56fd5fb5
-rgb24 fe5e3505a5019379cd0721d80ad62d05
-rgb444be 7adf5b77e454f20a02d2cc9562a21e9b
-rgb444le 3f372c6d95e1299b97ea702adabcea9d
-rgb48be d8520683529747778d0bd0e9a9f9e285
-rgb48le c589d81b9787f1144158a0e7f085987e
-rgb4_byte 2b3fe2b3e5f98124e93422721dd03751
-rgb555be 6b82965f2334ce7f43289bbe40697ca8
-rgb555le cd883c0c198a3e045e351f4857f9846c
-rgb565be bedff6bc255a9ea87f96117fd2348454
-rgb565le 500bcd27d380a51279ba0e4e64f5f1c7
-rgb8 e6121e248cb50b687451a437156924a6
-rgba e2cc3906c90ee87d863cb378bd095e18
-uyvy422 87fa53467c7267175c0336c547d8ce90
-yuv410p a8eb12c5ad15217d81e26c11a477a7c5
-yuv411p a97d81c8a515965209127cfdc718f899
-yuv420p daed3fd5e1980ccc4d4409320f16fbf6
-yuv420p10be f434af8526dcda2988f15a08cdc4bf98
-yuv420p10le 9dcbdb0206713a90fd03b313d99e9ff9
-yuv420p16be b8f1a0e4ef98903e2ef8dbce7bc812e2
-yuv420p16le 3be4223322a9d904caa2ad7d4ccf3c6a
-yuv420p9be 34346f74216be11c38cdaeffaba250cc
-yuv420p9le 8248d1c10aa86ef8e4b212a2d9fca937
-yuv422p 5a58e1fe687b71e28f52aeb11b999e46
-yuv422p10be adaf99408661a1dc3c667cad992c08d7
-yuv422p10le bc071b965f5a1b3c7349b71bd2b4247c
-yuv422p16be 1ec214fba454c456d83de5220c867ede
-yuv422p16le 9f9316d40597c9fb917d921bfbcd8421
-yuv422p9be 98e7cefa912845b488f85508a7be7e04
-yuv422p9le 54937395dce9518b2d58aadae21ff69d
-yuv440p fade395d957e1e3b117ac11c09404964
-yuv444p a3c2a074c3609226bf1a0bc4de5c0e51
-yuv444p10be b02fac8bc5a564a755567a86dc3ceae0
-yuv444p10le 88860297f729c90526b157b6bf1e2fcf
-yuv444p16be 26fbffad3c28aa1a6c47f2be6d146173
-yuv444p16le 3d13dcea82caec9eb563a1d7a2e4b339
-yuv444p9be df39c0778e5b13f306e9928c5b0ddbb2
-yuv444p9le 10fe4d81f58d4630e3a02863bd5071c1
-yuva420p 75d91c2de234468b5c7efd490ce40e0b
-yuva420p10be 718e0f49e010934a1f2b33b691855478
-yuva420p10le 1dac68a355050b96ff8716c168f67746
-yuva420p16be 36128486b2c99d0654e8dee63a47bd5e
-yuva420p16le 277b44d05a5098952c7c1a4cf2c6ff7a
-yuva420p9be 1fa63062315888f0eb8b8777c51a589f
-yuva420p9le 073ebffbc7201649f1c439ecf37f33cc
-yuva422p 7ce9f599a8aecd744fe24f2759623661
-yuva422p10be 980ea8ddfbfc0d52ed197fa506a2435e
-yuva422p10le 9f5c0b3d14679fc92120f556d00e1442
-yuva422p16be 94a4cf6182726a807a0f73b0abbf6e49
-yuva422p16le 5d5d4d216192bfb3e67d19ca61b47ae7
-yuva422p9be 57a62f219df38dc7c8138e3f65c4cf55
-yuva422p9le bdd8b63f2672315441d9a7ad5bc63021
-yuva444p 49c8ed206ed6381c9595e13ae8500296
-yuva444p10be 055adfd383003ec6ed96ae4388feb0ad
-yuva444p10le a56fc4d14528637b91699d413b21d87e
-yuva444p16be d2387f6d3c28dc0c3eb87b9c8e719241
-yuva444p16le 6c971dc2fe9a3044776c1eb0b40d7eb4
-yuva444p9be 6e397f5bb5de593923b317fbf5c8c390
-yuva444p9le ed156af72e6e18e7b0a27a3aa53df181
-yuvj420p db95116f6735bc0d6aa1f34479f74842
-yuvj422p 8d947806799c24f9d5a96688b20b6c6a
-yuvj440p eddaebaa7ab344072364b3507407b9d9
-yuvj444p 779aef4afd317cb44a03ec15011e34f2
-yuyv422 7abd4068b7767b1639f2873c446e09ba
-yvyu422 3b0fa1d775623323dbe4eb935fac37d3
+0bgr e6f5c50fa0330cd5d5e69ffc09bc085a
+0rgb 76b792f8ce8a72925e04294dc2f25b36
+abgr 8b94f489e68802d76f1e2844688a4911
+argb 3fd6af7ef2364d8aa845d45db289a04a
+bgr0 7117438cf000254610f23625265769b5
+bgr24 52b2c21cbc166978a38a646c354b6858
+bgr444be 6c6cb3f5a26d5fd00bd04467bb0bbcca
+bgr444le 860b20346d24510c1b3e44067916bb68
+bgr48be 161d37f2f6ba5de48d17f59050804660
+bgr48le 98f471e833021adad925d7d8d45b7c6f
+bgr4_byte f6296e1a5741531f67f62599ae30bfde
+bgr555be f5e041ea34e4c084c3531b9fe2d01016
+bgr555le 3b5c5281a7e13a1f757dc5d8eeb77d85
+bgr565be a567fb6edb4057d44c33c1bad23b9807
+bgr565le c6f40163bd064760f316a90f4c7885ac
+bgr8 f2e4aabfe9e6039beb1f2b8c43c83e3c
+bgra 0af63cc2ffd61af252df93cc767de358
+bgra64be 31af33833f6d8f2e4a62683288770aa4
+bgra64le 45feb93863055282447d1ff89c5158bf
+gbrap f26944c75b887e99bbf9183a59caa6aa
+gbrp 413b0f6ea51588d4be5f0c76d43d8796
+gbrp10be c5b3dc30600adad66c8cb4edc3cfcd1d
+gbrp10le 5026424d4b352d267b74ccb2419fde7f
+gbrp12be 6c46e5d072b9c61515dd7caad60a127e
+gbrp12le 573b26e385e1ee0ffbc74868301314d6
+gbrp14be 522fc41b398715e08a895bc3c3f55742
+gbrp14le 32561510eb3d9c351b18b35b644b731d
+gbrp9be 6ac7c79a4c089b93912bcf0abb4d418d
+gbrp9le cff296346d93e430cbc0acfbc91482ab
+gray 41811422d5819ed69389357294384c10
+gray16be 29f24ba7cb0fc4fd2ae78963d008f6e6
+gray16le a37e9c4ea76e8eeddc2af8f600ba2c10
+monob f51f07ba50f4398233106f0e81494170
+monow ee414089983b5be0f76b9d962757d900
+nv12 261ebe585ae2aa4e70d39a10c1679294
+nv21 2909feacd27bebb080c8e0fa41795269
+pal8 e81c55915557563b46627b0911764578
+rgb0 56a7ea69541bcd27bef6a5615784722b
+rgb24 195e6dae1c3a488b9d3ceb7560d25d85
+rgb444be d30742559618f871ef5543f602e35d04
+rgb444le 8cae7773ce27d959fd7836832ab392a6
+rgb48be 3c519a3f78405a8f2cc05c4846ab6e71
+rgb48le 09218c1dea3d085d435910478d4c4b7a
+rgb4_byte 0e2b561097230e9c72acc645e6806e20
+rgb555be 730f68605d12eb7cd524b63388f69712
+rgb555le 7fec4673ba9025bf492e88754afb51b2
+rgb565be 1f54ab9892bf28e3081ab55c83c86e24
+rgb565le 13255e04237bb16eb22f29f892590182
+rgb8 7df049b6094f8a5e084d74462f6d6cde
+rgba c1a5908572737f2ae1e5d8218af65f4b
+rgba64be 17e6273323b5779b5f3f775f150c1011
+rgba64le 48f45b10503b7dd140329c3dd0d54c98
+uyvy422 3a237e8376264e0cfa78f8a3fdadec8a
+xyz12be 810644e008deb231850d779aaa27cc7e
+xyz12le 829701db461b43533cf9241e0743bc61
+yuv410p c7adfe96c8e043a6cb9290c39bf8063c
+yuv411p 3fce29db403a25f81be39e01aaf6ff3a
+yuv420p d64fae96fac22aefa8fbcf45a09f37c1
+yuv420p10be 63f545453139f38883cfa1210f7b6ac5
+yuv420p10le 925de8b0bf9519c4b841afab4dd6bb25
+yuv420p12be 619425168c3b8bb9da68e7810bf5eacf
+yuv420p12le 403d7d96939fa538b04f7b7b26ac6868
+yuv420p14be 22d2d9fb5883410807ede4066e735426
+yuv420p14le 5cace6a24a1ff5d2a41a3c909c4bc41f
+yuv420p16be 0a6499a1b22230ad030448d3ac95b5c1
+yuv420p16le 2a5c131b060757aab1fe84200528d404
+yuv420p9be 95a9f53de74785fec62415e42048fa3e
+yuv420p9le 3d0a36e6505c49eeb2c305b4acb41a12
+yuv422p 54f608c9d8bc56979aeaa7863820f5d3
+yuv422p10be fbd6329d2decbe318be4d89dc8ade3a3
+yuv422p10le 7d7bdf4f68d8a7698e92722625c59c53
+yuv422p12be d6ca250820312bab977ce88d2ef65c13
+yuv422p12le 3185b59dddc7ee67251d9829a977130b
+yuv422p14be 3bc3a72c7cf995981bd8eb45f23705b3
+yuv422p14le 5987087bbc03d8cbff4c41bce03451d9
+yuv422p16be 97d95a9cfe8f67fb20a4c983c7fdc215
+yuv422p16le 3b9df52a757a0d1ddb1c9c38f0ed4787
+yuv422p9be 104a3cc49ccbbeff0932df5f1a2c104f
+yuv422p9le d0b803eeb1237ffa8a067fd084c2c385
+yuv440p fa45ee7329b98fc43c0be460d9a0d6a5
+yuv440p10be 54789b4f66d9a79fc182ff268639dbd0
+yuv440p10le d06d7c054522ac02ec04f76dfa431676
+yuv440p12be 7b8c9b6688f44282007ae220d52e5ed6
+yuv440p12le 2a3adb4692391171c506cc0899d27511
+yuv444p 7c8c5d138d732f4ca7d864b9ffef3047
+yuv444p10be faa81f737d465afcacef351818d34772
+yuv444p10le bfc5036e4ab0ab6da1416df4a462db74
+yuv444p12be 6706d8807b9dd14d331a7e9572fd9c5d
+yuv444p12le 9bba33b2c0dd09f653a4c22d201142c5
+yuv444p14be cf181f44988d3ddf4cc32b87ca473251
+yuv444p14le 086322cb9a98eb91825c9bb2ad00eac7
+yuv444p16be ee0721d7fda4a67bc6270a78fa361140
+yuv444p16le 8c4c2511907fd23d9aeefab490a22db7
+yuv444p9be 351f5f4ce50e64f264610b474dcc70fd
+yuv444p9le efd49802d44f337f0098e07945d95329
+yuva420p 3b136bcd7c2ffc3a1849e4814c046954
+yuva420p10be d045faff818dabb9ecebab6d14bf7b10
+yuva420p10le becf56ac1e271c04ccc204c68e8e0b5f
+yuva420p16be eeb7b6b0dba4ca15a1457bf0ff2bc51b
+yuva420p16le aa0a678ad48815d226888a5053a6fe6e
+yuva420p9be bcee2f39913b006fdfaa865246fbc122
+yuva420p9le aec21fa8f1088b7898cd80a30f382224
+yuva422p 39707b0dfdaadeefa20819080365db15
+yuva422p10be 53fbfe6d7eb01e2007003383c5d91850
+yuva422p10le df1f95630ccd7bf05b95b6b3061cbeef
+yuva422p16be 35ad91fa92b04e13d6b557d2f250ade1
+yuva422p16le 8fb93970118fde962f5dbcd156966722
+yuva422p9be 2b16b2dc102ad688a3023f30e3c6f9d9
+yuva422p9le 6a23d290358691a9d8bab49582265764
+yuva444p 442a690385166bed3e785d9262c1c501
+yuva444p10be bb6d52902c30f5cc63ddc3fbe3346bf5
+yuva444p10le 6e43f7c44e070fce492dcb1b038de85e
+yuva444p16be b8801dccf64b3eadc2a5b5db67ae0b0f
+yuva444p16le 8e72ae66754badf5d1eeb094e6bf0ddc
+yuva444p9be bcd845394351ca6d15e947342802957d
+yuva444p9le 7727a93765ed38dfd25e3d6b7a38fa63
+yuvj411p 260f51b360dc00b2222f4cb39fa05e36
+yuvj420p fab4394239b08bdb7638215a42d56eaf
+yuvj422p 0309c2b34aa4d74f58048fe320a02b83
+yuvj440p f5e3a92fa46e57e2c613fc9aaad18e9d
+yuvj444p ca4b3662259ba15a6297a44ef64414b7
+yuyv422 8f02b2332fe9bb782f88627c99f32ee8
+yvyu422 bd8cb985c2e1f9c32dc6b865bdf20637
diff --git a/tests/ref/fate/filter-pp b/tests/ref/fate/filter-pp
new file mode 100644
index 0000000000..c1311beffd
--- /dev/null
+++ b/tests/ref/fate/filter-pp
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 1, 1, 1, 152064, 0x0af8a873
+0, 2, 2, 1, 152064, 0xaeb99897
+0, 3, 3, 1, 152064, 0x8f3712c8
+0, 4, 4, 1, 152064, 0x5bf6a64c
+0, 5, 5, 1, 152064, 0x262de352
diff --git a/tests/ref/fate/filter-pp1 b/tests/ref/fate/filter-pp1
new file mode 100644
index 0000000000..8c6b7ba18e
--- /dev/null
+++ b/tests/ref/fate/filter-pp1
@@ -0,0 +1 @@
+pp1 1a45041dd20a941e36b7729116950107
diff --git a/tests/ref/fate/filter-pp2 b/tests/ref/fate/filter-pp2
new file mode 100644
index 0000000000..ed5e77322a
--- /dev/null
+++ b/tests/ref/fate/filter-pp2
@@ -0,0 +1 @@
+pp2 566d48ad25dfa7a9680de933cbdf66d9
diff --git a/tests/ref/fate/filter-pp3 b/tests/ref/fate/filter-pp3
new file mode 100644
index 0000000000..536bf8e9d2
--- /dev/null
+++ b/tests/ref/fate/filter-pp3
@@ -0,0 +1 @@
+pp3 586fc14a52699540a865c070dd113229
diff --git a/tests/ref/fate/filter-pp4 b/tests/ref/fate/filter-pp4
new file mode 100644
index 0000000000..efa9c8a2f2
--- /dev/null
+++ b/tests/ref/fate/filter-pp4
@@ -0,0 +1 @@
+pp4 8a072806ae6b5c68c5c3c57197641e4a
diff --git a/tests/ref/fate/filter-pp5 b/tests/ref/fate/filter-pp5
new file mode 100644
index 0000000000..682e8481ff
--- /dev/null
+++ b/tests/ref/fate/filter-pp5
@@ -0,0 +1 @@
+pp5 5695b8193095a63b9f397fff8343d1a6
diff --git a/tests/ref/fate/filter-pp6 b/tests/ref/fate/filter-pp6
new file mode 100644
index 0000000000..3280a69004
--- /dev/null
+++ b/tests/ref/fate/filter-pp6
@@ -0,0 +1 @@
+pp6 f823b3330935cd1824d526041b429d9a
diff --git a/tests/ref/fate/filter-qp b/tests/ref/fate/filter-qp
new file mode 100644
index 0000000000..3dd4c95874
--- /dev/null
+++ b/tests/ref/fate/filter-qp
@@ -0,0 +1 @@
+qp 2d4da13e883e073084d547a6b41ba688
diff --git a/tests/ref/fate/filter-scale200 b/tests/ref/fate/filter-scale200
index 609a21cb59..7de4fc5002 100644
--- a/tests/ref/fate/filter-scale200
+++ b/tests/ref/fate/filter-scale200
@@ -1 +1 @@
-scale200 6b5797b13531dbfc4b389f2fd89b24e6
+scale200 e7b8419c7de2912f0585b79e99f174c2
diff --git a/tests/ref/fate/filter-scale500 b/tests/ref/fate/filter-scale500
index bd0836cfc2..2b1b6d2b6b 100644
--- a/tests/ref/fate/filter-scale500
+++ b/tests/ref/fate/filter-scale500
@@ -1 +1 @@
-scale500 9d01a7cb7461c1d2d4d3531bbd7c9b4c
+scale500 e7d6f07710a707e4e5583aee54a8f5ff
diff --git a/tests/ref/fate/filter-select b/tests/ref/fate/filter-select
new file mode 100644
index 0000000000..7c30292387
--- /dev/null
+++ b/tests/ref/fate/filter-select
@@ -0,0 +1,18 @@
+#tb 0: 1/25
+0, 1, 1, 1, 152064, 0x7f5f6551
+0, 5, 5, 1, 152064, 0x287da8e6
+0, 7, 7, 1, 152064, 0xe9028bac
+0, 11, 11, 1, 152064, 0xb247fcd5
+0, 13, 13, 1, 152064, 0xb1d6a223
+0, 17, 17, 1, 152064, 0xa3e038c8
+0, 19, 19, 1, 152064, 0x1a0ddbff
+0, 23, 23, 1, 152064, 0x813468ef
+0, 25, 25, 1, 152064, 0x62719936
+0, 29, 29, 1, 152064, 0x2db5650e
+0, 31, 31, 1, 152064, 0x669fc51e
+0, 35, 35, 1, 152064, 0x0db194fb
+0, 37, 37, 1, 152064, 0xac2101f8
+0, 41, 41, 1, 152064, 0xf0c79e08
+0, 43, 43, 1, 152064, 0x5ad420ec
+0, 47, 47, 1, 152064, 0x60afc5c2
+0, 49, 49, 1, 152064, 0x5b29d8ea
diff --git a/tests/ref/fate/filter-separatefields b/tests/ref/fate/filter-separatefields
new file mode 100644
index 0000000000..46cb4703a1
--- /dev/null
+++ b/tests/ref/fate/filter-separatefields
@@ -0,0 +1,101 @@
+#tb 0: 1/50
+0, 0, 0, 1, 76032, 0x99276ab9
+0, 1, 1, 1, 76032, 0x0b071f36
+0, 2, 2, 1, 76032, 0x8b03b0e8
+0, 3, 3, 1, 76032, 0x3e10b45a
+0, 4, 4, 1, 76032, 0x67a27817
+0, 5, 5, 1, 76032, 0xb3537e33
+0, 6, 6, 1, 76032, 0xc4e78689
+0, 7, 7, 1, 76032, 0x5f11fa18
+0, 8, 8, 1, 76032, 0x7867f720
+0, 9, 9, 1, 76032, 0xb584bf23
+0, 10, 10, 1, 76032, 0x7c4ae6cf
+0, 11, 11, 1, 76032, 0x4b43c208
+0, 12, 12, 1, 76032, 0x974d3882
+0, 13, 13, 1, 76032, 0xfb0543a1
+0, 14, 14, 1, 76032, 0x91da8418
+0, 15, 15, 1, 76032, 0x45260794
+0, 16, 16, 1, 76032, 0xe65397d0
+0, 17, 17, 1, 76032, 0xfa09e847
+0, 18, 18, 1, 76032, 0x3adcfa2c
+0, 19, 19, 1, 76032, 0xa0103eda
+0, 20, 20, 1, 76032, 0xee821b94
+0, 21, 21, 1, 76032, 0xb8cf2bcc
+0, 22, 22, 1, 76032, 0x6e50db83
+0, 23, 23, 1, 76032, 0x2cd12152
+0, 24, 24, 1, 76032, 0x482961d0
+0, 25, 25, 1, 76032, 0x9a304b91
+0, 26, 26, 1, 76032, 0x2591f07b
+0, 27, 27, 1, 76032, 0x1410b199
+0, 28, 28, 1, 76032, 0x1fc9c234
+0, 29, 29, 1, 76032, 0x4a8dcb9a
+0, 30, 30, 1, 76032, 0xda4b81c7
+0, 31, 31, 1, 76032, 0x45ef8d2f
+0, 32, 32, 1, 76032, 0x07fda976
+0, 33, 33, 1, 76032, 0x19cfa493
+0, 34, 34, 1, 76032, 0xdb453b41
+0, 35, 35, 1, 76032, 0xeebefd78
+0, 36, 36, 1, 76032, 0xdb7830bf
+0, 37, 37, 1, 76032, 0x1bc13a0d
+0, 38, 38, 1, 76032, 0xf811e6af
+0, 39, 39, 1, 76032, 0x5bb6f541
+0, 40, 40, 1, 76032, 0xadfc0b2a
+0, 41, 41, 1, 76032, 0x473fea46
+0, 42, 42, 1, 76032, 0xc4541cec
+0, 43, 43, 1, 76032, 0x5e500726
+0, 44, 44, 1, 76032, 0x54df18fa
+0, 45, 45, 1, 76032, 0x6470045f
+0, 46, 46, 1, 76032, 0x01139a0b
+0, 47, 47, 1, 76032, 0x8690ced5
+0, 48, 48, 1, 76032, 0x9796b3f0
+0, 49, 49, 1, 76032, 0x1bee45e6
+0, 50, 50, 1, 76032, 0xacf4c872
+0, 51, 51, 1, 76032, 0x0183d0b5
+0, 52, 52, 1, 76032, 0xeea54bf9
+0, 53, 53, 1, 76032, 0xb42d4abc
+0, 54, 54, 1, 76032, 0x8be07d8b
+0, 55, 55, 1, 76032, 0x9ac75afc
+0, 56, 56, 1, 76032, 0x96bd3717
+0, 57, 57, 1, 76032, 0xbcca6d3e
+0, 58, 58, 1, 76032, 0x3e2edf44
+0, 59, 59, 1, 76032, 0x1b1385bb
+0, 60, 60, 1, 76032, 0xd4c2d759
+0, 61, 61, 1, 76032, 0x67119362
+0, 62, 62, 1, 76032, 0x96327b89
+0, 63, 63, 1, 76032, 0x9b914995
+0, 64, 64, 1, 76032, 0xf1d024b9
+0, 65, 65, 1, 76032, 0xd0e1d7d4
+0, 66, 66, 1, 76032, 0x11e97010
+0, 67, 67, 1, 76032, 0x0ab90a20
+0, 68, 68, 1, 76032, 0xf7ce7e72
+0, 69, 69, 1, 76032, 0x6edec4f7
+0, 70, 70, 1, 76032, 0xbb96a608
+0, 71, 71, 1, 76032, 0x8502eee4
+0, 72, 72, 1, 76032, 0xc27994cb
+0, 73, 73, 1, 76032, 0x6dbba2d1
+0, 74, 74, 1, 76032, 0xe85e04f8
+0, 75, 75, 1, 76032, 0x4bbbfcf1
+0, 76, 76, 1, 76032, 0x8b5a2465
+0, 77, 77, 1, 76032, 0x8a5434e7
+0, 78, 78, 1, 76032, 0xc34578d9
+0, 79, 79, 1, 76032, 0xc2f0d5f5
+0, 80, 80, 1, 76032, 0x90bd2102
+0, 81, 81, 1, 76032, 0xafda3823
+0, 82, 82, 1, 76032, 0x66972a74
+0, 83, 83, 1, 76032, 0xc9d17394
+0, 84, 84, 1, 76032, 0x961cdc22
+0, 85, 85, 1, 76032, 0x6816e378
+0, 86, 86, 1, 76032, 0x4c383925
+0, 87, 87, 1, 76032, 0xf522e7b8
+0, 88, 88, 1, 76032, 0xc1616f33
+0, 89, 89, 1, 76032, 0xad14952f
+0, 90, 90, 1, 76032, 0xe4e11fcd
+0, 91, 91, 1, 76032, 0xca655ea6
+0, 92, 92, 1, 76032, 0x7b18f45f
+0, 93, 93, 1, 76032, 0xb2325f91
+0, 94, 94, 1, 76032, 0xb08d7400
+0, 95, 95, 1, 76032, 0x74ec51c2
+0, 96, 96, 1, 76032, 0xc15a0713
+0, 97, 97, 1, 76032, 0x3838ad70
+0, 98, 98, 1, 76032, 0x74b6bc3f
+0, 99, 99, 1, 76032, 0x29f41cab
diff --git a/tests/ref/fate/filter-setdar b/tests/ref/fate/filter-setdar
new file mode 100644
index 0000000000..14a07f16e4
--- /dev/null
+++ b/tests/ref/fate/filter-setdar
@@ -0,0 +1 @@
+setdar 99036518df5b66d2e64646f3e0c808f2
diff --git a/tests/ref/fate/filter-setpts b/tests/ref/fate/filter-setpts
index 14aa613873..5b1d73446f 100644
--- a/tests/ref/fate/filter-setpts
+++ b/tests/ref/fate/filter-setpts
@@ -1,51 +1,38 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 0x05b789ef
-0, 28, 28, 0, 152064, 0x4bb46551
-0, 57, 57, 0, 152064, 0x9dddf64a
-0, 86, 86, 0, 152064, 0x2a8380b0
-0, 115, 115, 0, 152064, 0x4de3b652
-0, 144, 144, 0, 152064, 0xedb5a8e6
-0, 172, 172, 0, 152064, 0xe20f7c23
-0, 201, 201, 0, 152064, 0x5ab58bac
-0, 229, 229, 0, 152064, 0x1f1b8026
-0, 258, 258, 0, 152064, 0x91373915
-0, 286, 286, 0, 152064, 0x02344760
-0, 314, 314, 0, 152064, 0x30f5fcd5
-0, 343, 343, 0, 152064, 0xc711ad61
-0, 371, 371, 0, 152064, 0x24eca223
-0, 399, 399, 0, 152064, 0x52a48ddd
-0, 427, 427, 0, 152064, 0xa91c0f05
-0, 456, 456, 0, 152064, 0x8e364e18
-0, 484, 484, 0, 152064, 0xb15d38c8
-0, 512, 512, 0, 152064, 0xf25f6acc
-0, 541, 541, 0, 152064, 0xf34ddbff
-0, 570, 570, 0, 152064, 0xfc7bf570
-0, 598, 598, 0, 152064, 0x9dc72412
-0, 627, 627, 0, 152064, 0x445d1d59
-0, 656, 656, 0, 152064, 0x2f2768ef
-0, 685, 685, 0, 152064, 0xce09f9d6
-0, 714, 714, 0, 152064, 0x95579936
-0, 743, 743, 0, 152064, 0x43d796b5
-0, 772, 772, 0, 152064, 0xd780d887
-0, 800, 800, 0, 152064, 0x76d2a455
-0, 829, 829, 0, 152064, 0x6dc3650e
-0, 858, 858, 0, 152064, 0x0f9d6aca
-0, 887, 887, 0, 152064, 0xe295c51e
-0, 915, 915, 0, 152064, 0xd766fc8d
-0, 944, 944, 0, 152064, 0xe22f7a30
-0, 972, 972, 0, 152064, 0x7fea4378
-0, 1000, 1000, 0, 152064, 0xfa8d94fb
-0, 1029, 1029, 0, 152064, 0x4c9737ab
-0, 1057, 1057, 0, 152064, 0xa50d01f8
-0, 1085, 1085, 0, 152064, 0x0b07594c
-0, 1113, 1113, 0, 152064, 0x88734edd
-0, 1142, 1142, 0, 152064, 0xd2735925
-0, 1170, 1170, 0, 152064, 0xd4e49e08
-0, 1198, 1198, 0, 152064, 0x20cebfa9
-0, 1227, 1227, 0, 152064, 0x575c20ec
-0, 1255, 1255, 0, 152064, 0xfd500471
-0, 1284, 1284, 0, 152064, 0x61b47e73
-0, 1313, 1313, 0, 152064, 0x09ef53ff
-0, 1341, 1341, 0, 152064, 0x6e88c5c2
-0, 1370, 1370, 0, 152064, 0xbb87b483
-0, 1399, 1399, 0, 152064, 0x4bbad8ea
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0x05b789ef
+0, 1, 1, 1, 152064, 0x4bb46551
+0, 2, 2, 1, 152064, 0x9dddf64a
+0, 3, 3, 1, 152064, 0x2a8380b0
+0, 4, 4, 1, 152064, 0x4de3b652
+0, 5, 5, 1, 152064, 0xedb5a8e6
+0, 6, 6, 1, 152064, 0x5ab58bac
+0, 7, 7, 1, 152064, 0x1f1b8026
+0, 8, 8, 1, 152064, 0x91373915
+0, 9, 9, 1, 152064, 0x30f5fcd5
+0, 10, 10, 1, 152064, 0xc711ad61
+0, 11, 11, 1, 152064, 0x52a48ddd
+0, 12, 12, 1, 152064, 0xa91c0f05
+0, 13, 13, 1, 152064, 0x8e364e18
+0, 14, 14, 1, 152064, 0xf25f6acc
+0, 15, 15, 1, 152064, 0xf34ddbff
+0, 16, 16, 1, 152064, 0x9dc72412
+0, 17, 17, 1, 152064, 0x445d1d59
+0, 18, 18, 1, 152064, 0x2f2768ef
+0, 19, 19, 1, 152064, 0x95579936
+0, 20, 20, 1, 152064, 0x43d796b5
+0, 21, 21, 1, 152064, 0x76d2a455
+0, 22, 22, 1, 152064, 0x6dc3650e
+0, 23, 23, 1, 152064, 0x0f9d6aca
+0, 24, 24, 1, 152064, 0xd766fc8d
+0, 25, 25, 1, 152064, 0xe22f7a30
+0, 26, 26, 1, 152064, 0xfa8d94fb
+0, 27, 27, 1, 152064, 0x4c9737ab
+0, 28, 28, 1, 152064, 0xa50d01f8
+0, 29, 29, 1, 152064, 0x88734edd
+0, 30, 30, 1, 152064, 0xd2735925
+0, 31, 31, 1, 152064, 0x20cebfa9
+0, 32, 32, 1, 152064, 0x575c20ec
+0, 33, 33, 1, 152064, 0x61b47e73
+0, 34, 34, 1, 152064, 0x09ef53ff
+0, 35, 35, 1, 152064, 0x6e88c5c2
+0, 36, 36, 1, 152064, 0x4bbad8ea
diff --git a/tests/ref/fate/filter-setsar b/tests/ref/fate/filter-setsar
new file mode 100644
index 0000000000..c8199b6edf
--- /dev/null
+++ b/tests/ref/fate/filter-setsar
@@ -0,0 +1 @@
+setsar 99036518df5b66d2e64646f3e0c808f2
diff --git a/tests/ref/fate/filter-showpalette b/tests/ref/fate/filter-showpalette
new file mode 100644
index 0000000000..1a13c2356d
--- /dev/null
+++ b/tests/ref/fate/filter-showpalette
@@ -0,0 +1,316 @@
+#tb 0: 1/35
+0, 0, 0, 1, 9216, 0xc72e034e
+0, 1, 1, 1, 9216, 0xc72e034e
+0, 2, 2, 1, 9216, 0xc72e034e
+0, 3, 3, 1, 9216, 0xc72e034e
+0, 4, 4, 1, 9216, 0xc72e034e
+0, 5, 5, 1, 9216, 0xc72e034e
+0, 6, 6, 1, 9216, 0xc72e034e
+0, 7, 7, 1, 9216, 0xc72e034e
+0, 8, 8, 1, 9216, 0xc72e034e
+0, 9, 9, 1, 9216, 0xc72e034e
+0, 10, 10, 1, 9216, 0xc72e034e
+0, 11, 11, 1, 9216, 0xc72e034e
+0, 12, 12, 1, 9216, 0xc72e034e
+0, 13, 13, 1, 9216, 0xc72e034e
+0, 14, 14, 1, 9216, 0xc72e034e
+0, 15, 15, 1, 9216, 0xc72e034e
+0, 16, 16, 1, 9216, 0xc72e034e
+0, 17, 17, 1, 9216, 0xc72e034e
+0, 18, 18, 1, 9216, 0xc72e034e
+0, 19, 19, 1, 9216, 0xc72e034e
+0, 20, 20, 1, 9216, 0xc72e034e
+0, 21, 21, 1, 9216, 0xc72e034e
+0, 22, 22, 1, 9216, 0xc72e034e
+0, 23, 23, 1, 9216, 0xc72e034e
+0, 24, 24, 1, 9216, 0xc72e034e
+0, 25, 25, 1, 9216, 0xc72e034e
+0, 26, 26, 1, 9216, 0xc72e034e
+0, 27, 27, 1, 9216, 0xc72e034e
+0, 28, 28, 1, 9216, 0xc72e034e
+0, 29, 29, 1, 9216, 0xc72e034e
+0, 30, 30, 1, 9216, 0xc72e034e
+0, 31, 31, 1, 9216, 0xc72e034e
+0, 32, 32, 1, 9216, 0xc72e034e
+0, 33, 33, 1, 9216, 0xc72e034e
+0, 34, 34, 1, 9216, 0xc72e034e
+0, 35, 35, 1, 9216, 0xc72e034e
+0, 36, 36, 1, 9216, 0xc72e034e
+0, 37, 37, 1, 9216, 0xc72e034e
+0, 38, 38, 1, 9216, 0xc72e034e
+0, 39, 39, 1, 9216, 0xc72e034e
+0, 40, 40, 1, 9216, 0xc72e034e
+0, 41, 41, 1, 9216, 0xc72e034e
+0, 42, 42, 1, 9216, 0xc72e034e
+0, 43, 43, 1, 9216, 0xc72e034e
+0, 44, 44, 1, 9216, 0xc72e034e
+0, 45, 45, 1, 9216, 0xc72e034e
+0, 46, 46, 1, 9216, 0xc72e034e
+0, 47, 47, 1, 9216, 0xc72e034e
+0, 48, 48, 1, 9216, 0xc72e034e
+0, 49, 49, 1, 9216, 0xc72e034e
+0, 50, 50, 1, 9216, 0xc72e034e
+0, 51, 51, 1, 9216, 0xc72e034e
+0, 52, 52, 1, 9216, 0xc72e034e
+0, 53, 53, 1, 9216, 0xc72e034e
+0, 54, 54, 1, 9216, 0xc72e034e
+0, 55, 55, 1, 9216, 0xc72e034e
+0, 56, 56, 1, 9216, 0xc72e034e
+0, 57, 57, 1, 9216, 0xc72e034e
+0, 58, 58, 1, 9216, 0xc72e034e
+0, 59, 59, 1, 9216, 0xc72e034e
+0, 60, 60, 1, 9216, 0xc72e034e
+0, 61, 61, 1, 9216, 0xc72e034e
+0, 62, 62, 1, 9216, 0xc72e034e
+0, 63, 63, 1, 9216, 0xc72e034e
+0, 64, 64, 1, 9216, 0xc72e034e
+0, 65, 65, 1, 9216, 0xc72e034e
+0, 66, 66, 1, 9216, 0xc72e034e
+0, 67, 67, 1, 9216, 0xc72e034e
+0, 68, 68, 1, 9216, 0xc72e034e
+0, 69, 69, 1, 9216, 0xc72e034e
+0, 70, 70, 1, 9216, 0xc72e034e
+0, 71, 71, 1, 9216, 0xc72e034e
+0, 72, 72, 1, 9216, 0xc72e034e
+0, 73, 73, 1, 9216, 0xc72e034e
+0, 74, 74, 1, 9216, 0xc72e034e
+0, 75, 75, 1, 9216, 0xc72e034e
+0, 76, 76, 1, 9216, 0xc72e034e
+0, 77, 77, 1, 9216, 0xc72e034e
+0, 78, 78, 1, 9216, 0xc72e034e
+0, 79, 79, 1, 9216, 0xc72e034e
+0, 80, 80, 1, 9216, 0xc72e034e
+0, 81, 81, 1, 9216, 0xc72e034e
+0, 82, 82, 1, 9216, 0xc72e034e
+0, 83, 83, 1, 9216, 0xc72e034e
+0, 84, 84, 1, 9216, 0xc72e034e
+0, 85, 85, 1, 9216, 0xc72e034e
+0, 86, 86, 1, 9216, 0xc72e034e
+0, 87, 87, 1, 9216, 0xc72e034e
+0, 88, 88, 1, 9216, 0xc72e034e
+0, 89, 89, 1, 9216, 0xc72e034e
+0, 90, 90, 1, 9216, 0xf75be32f
+0, 91, 91, 1, 9216, 0xf75be32f
+0, 92, 92, 1, 9216, 0xbb5bc1ae
+0, 93, 93, 1, 9216, 0xbb5bc1ae
+0, 94, 94, 1, 9216, 0x67e4a45c
+0, 95, 95, 1, 9216, 0x67e4a45c
+0, 96, 96, 1, 9216, 0x6a42832c
+0, 97, 97, 1, 9216, 0x6a42832c
+0, 98, 98, 1, 9216, 0x44da649f
+0, 99, 99, 1, 9216, 0x44da649f
+0, 100, 100, 1, 9216, 0x60273f76
+0, 101, 101, 1, 9216, 0x60273f76
+0, 102, 102, 1, 9216, 0x5f0b20aa
+0, 103, 103, 1, 9216, 0x5f0b20aa
+0, 104, 104, 1, 9216, 0xd382ff8f
+0, 105, 105, 1, 9216, 0xd382ff8f
+0, 106, 106, 1, 9216, 0x5a29e2a0
+0, 107, 107, 1, 9216, 0x5a29e2a0
+0, 108, 108, 1, 9216, 0x13ffc143
+0, 109, 109, 1, 9216, 0x93aba0d9
+0, 110, 110, 1, 9216, 0x93aba0d9
+0, 111, 111, 1, 9216, 0x93aba0d9
+0, 112, 112, 1, 9216, 0x93aba0d9
+0, 113, 113, 1, 9216, 0x93aba0d9
+0, 114, 114, 1, 9216, 0x93aba0d9
+0, 115, 115, 1, 9216, 0x93aba0d9
+0, 116, 116, 1, 9216, 0x93aba0d9
+0, 117, 117, 1, 9216, 0x93aba0d9
+0, 118, 118, 1, 9216, 0x93aba0d9
+0, 119, 119, 1, 9216, 0x93aba0d9
+0, 120, 120, 1, 9216, 0x93aba0d9
+0, 121, 121, 1, 9216, 0x93aba0d9
+0, 122, 122, 1, 9216, 0x93aba0d9
+0, 123, 123, 1, 9216, 0x93aba0d9
+0, 124, 124, 1, 9216, 0x93aba0d9
+0, 125, 125, 1, 9216, 0x93aba0d9
+0, 126, 126, 1, 9216, 0x93aba0d9
+0, 127, 127, 1, 9216, 0x93aba0d9
+0, 128, 128, 1, 9216, 0x93aba0d9
+0, 129, 129, 1, 9216, 0x93aba0d9
+0, 130, 130, 1, 9216, 0x93aba0d9
+0, 131, 131, 1, 9216, 0x93aba0d9
+0, 132, 132, 1, 9216, 0x93aba0d9
+0, 133, 133, 1, 9216, 0x93aba0d9
+0, 134, 134, 1, 9216, 0x93aba0d9
+0, 135, 135, 1, 9216, 0x93aba0d9
+0, 136, 136, 1, 9216, 0x93aba0d9
+0, 137, 137, 1, 9216, 0x93aba0d9
+0, 138, 138, 1, 9216, 0x93aba0d9
+0, 139, 139, 1, 9216, 0x93aba0d9
+0, 140, 140, 1, 9216, 0x93aba0d9
+0, 141, 141, 1, 9216, 0x93aba0d9
+0, 142, 142, 1, 9216, 0x93aba0d9
+0, 143, 143, 1, 9216, 0x93aba0d9
+0, 144, 144, 1, 9216, 0x93aba0d9
+0, 145, 145, 1, 9216, 0x93aba0d9
+0, 146, 146, 1, 9216, 0x93aba0d9
+0, 147, 147, 1, 9216, 0x93aba0d9
+0, 148, 148, 1, 9216, 0x93aba0d9
+0, 149, 149, 1, 9216, 0x93aba0d9
+0, 150, 150, 1, 9216, 0x93aba0d9
+0, 151, 151, 1, 9216, 0x93aba0d9
+0, 152, 152, 1, 9216, 0x93aba0d9
+0, 153, 153, 1, 9216, 0x93aba0d9
+0, 154, 154, 1, 9216, 0x93aba0d9
+0, 155, 155, 1, 9216, 0x93aba0d9
+0, 156, 156, 1, 9216, 0x93aba0d9
+0, 157, 157, 1, 9216, 0x93aba0d9
+0, 158, 158, 1, 9216, 0x93aba0d9
+0, 159, 159, 1, 9216, 0x93aba0d9
+0, 160, 160, 1, 9216, 0x93aba0d9
+0, 161, 161, 1, 9216, 0x93aba0d9
+0, 162, 162, 1, 9216, 0x93aba0d9
+0, 163, 163, 1, 9216, 0x93aba0d9
+0, 164, 164, 1, 9216, 0x93aba0d9
+0, 165, 165, 1, 9216, 0x93aba0d9
+0, 166, 166, 1, 9216, 0x93aba0d9
+0, 167, 167, 1, 9216, 0x93aba0d9
+0, 168, 168, 1, 9216, 0x93aba0d9
+0, 169, 169, 1, 9216, 0x93aba0d9
+0, 170, 170, 1, 9216, 0x93aba0d9
+0, 171, 171, 1, 9216, 0x93aba0d9
+0, 172, 172, 1, 9216, 0x93aba0d9
+0, 173, 173, 1, 9216, 0x93aba0d9
+0, 174, 174, 1, 9216, 0x93aba0d9
+0, 175, 175, 1, 9216, 0x93aba0d9
+0, 176, 176, 1, 9216, 0x93aba0d9
+0, 177, 177, 1, 9216, 0x93aba0d9
+0, 178, 178, 1, 9216, 0x93aba0d9
+0, 179, 179, 1, 9216, 0x93aba0d9
+0, 180, 180, 1, 9216, 0x93aba0d9
+0, 181, 181, 1, 9216, 0x93aba0d9
+0, 182, 182, 1, 9216, 0x93aba0d9
+0, 183, 183, 1, 9216, 0x93aba0d9
+0, 184, 184, 1, 9216, 0x93aba0d9
+0, 185, 185, 1, 9216, 0x93aba0d9
+0, 186, 186, 1, 9216, 0x93aba0d9
+0, 187, 187, 1, 9216, 0x93aba0d9
+0, 188, 188, 1, 9216, 0x93aba0d9
+0, 189, 189, 1, 9216, 0x93aba0d9
+0, 190, 190, 1, 9216, 0x93aba0d9
+0, 191, 191, 1, 9216, 0x93aba0d9
+0, 192, 192, 1, 9216, 0x93aba0d9
+0, 193, 193, 1, 9216, 0x93aba0d9
+0, 194, 194, 1, 9216, 0x93aba0d9
+0, 195, 195, 1, 9216, 0x93aba0d9
+0, 196, 196, 1, 9216, 0x93aba0d9
+0, 197, 197, 1, 9216, 0x93aba0d9
+0, 198, 198, 1, 9216, 0x93aba0d9
+0, 199, 199, 1, 9216, 0x93aba0d9
+0, 200, 200, 1, 9216, 0x93aba0d9
+0, 201, 201, 1, 9216, 0x93aba0d9
+0, 202, 202, 1, 9216, 0x93aba0d9
+0, 203, 203, 1, 9216, 0x93aba0d9
+0, 204, 204, 1, 9216, 0x93aba0d9
+0, 205, 205, 1, 9216, 0x93aba0d9
+0, 206, 206, 1, 9216, 0x93aba0d9
+0, 207, 207, 1, 9216, 0x93aba0d9
+0, 208, 208, 1, 9216, 0x93aba0d9
+0, 209, 209, 1, 9216, 0x93aba0d9
+0, 210, 210, 1, 9216, 0xb57cbdda
+0, 211, 211, 1, 9216, 0xfad4d7a8
+0, 212, 212, 1, 9216, 0x4a0bf635
+0, 213, 213, 1, 9216, 0x44880d81
+0, 214, 214, 1, 9216, 0x4de02b90
+0, 215, 215, 1, 9216, 0x2a4f4ac8
+0, 216, 216, 1, 9216, 0x96616376
+0, 217, 217, 1, 9216, 0x65c88629
+0, 218, 218, 1, 9216, 0x3d4a9efb
+0, 219, 219, 1, 9216, 0x85a5bdbe
+0, 220, 220, 1, 9216, 0x653edbd6
+0, 221, 221, 1, 9216, 0x9f28f433
+0, 222, 222, 1, 9216, 0x8f3f13ef
+0, 223, 223, 1, 9216, 0x43e32e56
+0, 224, 224, 1, 9216, 0x780d3969
+0, 225, 225, 1, 9216, 0x780d3969
+0, 226, 226, 1, 9216, 0x780d3969
+0, 227, 227, 1, 9216, 0x780d3969
+0, 228, 228, 1, 9216, 0x780d3969
+0, 229, 229, 1, 9216, 0x780d3969
+0, 230, 230, 1, 9216, 0x780d3969
+0, 231, 231, 1, 9216, 0x780d3969
+0, 232, 232, 1, 9216, 0x780d3969
+0, 233, 233, 1, 9216, 0x780d3969
+0, 234, 234, 1, 9216, 0x780d3969
+0, 235, 235, 1, 9216, 0x780d3969
+0, 236, 236, 1, 9216, 0x780d3969
+0, 237, 237, 1, 9216, 0x780d3969
+0, 238, 238, 1, 9216, 0x780d3969
+0, 239, 239, 1, 9216, 0x780d3969
+0, 240, 240, 1, 9216, 0x780d3969
+0, 241, 241, 1, 9216, 0x780d3969
+0, 242, 242, 1, 9216, 0x780d3969
+0, 243, 243, 1, 9216, 0x780d3969
+0, 244, 244, 1, 9216, 0x780d3969
+0, 245, 245, 1, 9216, 0x780d3969
+0, 246, 246, 1, 9216, 0x780d3969
+0, 247, 247, 1, 9216, 0x780d3969
+0, 248, 248, 1, 9216, 0x780d3969
+0, 249, 249, 1, 9216, 0x780d3969
+0, 250, 250, 1, 9216, 0x780d3969
+0, 251, 251, 1, 9216, 0x780d3969
+0, 252, 252, 1, 9216, 0x780d3969
+0, 253, 253, 1, 9216, 0x780d3969
+0, 254, 254, 1, 9216, 0x780d3969
+0, 255, 255, 1, 9216, 0x780d3969
+0, 256, 256, 1, 9216, 0x780d3969
+0, 257, 257, 1, 9216, 0x780d3969
+0, 258, 258, 1, 9216, 0x780d3969
+0, 259, 259, 1, 9216, 0x780d3969
+0, 260, 260, 1, 9216, 0x780d3969
+0, 261, 261, 1, 9216, 0x780d3969
+0, 262, 262, 1, 9216, 0x780d3969
+0, 263, 263, 1, 9216, 0x780d3969
+0, 264, 264, 1, 9216, 0x780d3969
+0, 265, 265, 1, 9216, 0x780d3969
+0, 266, 266, 1, 9216, 0x780d3969
+0, 267, 267, 1, 9216, 0x780d3969
+0, 268, 268, 1, 9216, 0x780d3969
+0, 269, 269, 1, 9216, 0x780d3969
+0, 270, 270, 1, 9216, 0x780d3969
+0, 271, 271, 1, 9216, 0x780d3969
+0, 272, 272, 1, 9216, 0x780d3969
+0, 273, 273, 1, 9216, 0x780d3969
+0, 274, 274, 1, 9216, 0x780d3969
+0, 275, 275, 1, 9216, 0x780d3969
+0, 276, 276, 1, 9216, 0x780d3969
+0, 277, 277, 1, 9216, 0x780d3969
+0, 278, 278, 1, 9216, 0x780d3969
+0, 279, 279, 1, 9216, 0x780d3969
+0, 280, 280, 1, 9216, 0x780d3969
+0, 281, 281, 1, 9216, 0x780d3969
+0, 282, 282, 1, 9216, 0x780d3969
+0, 283, 283, 1, 9216, 0x780d3969
+0, 284, 284, 1, 9216, 0x780d3969
+0, 285, 285, 1, 9216, 0x780d3969
+0, 286, 286, 1, 9216, 0x780d3969
+0, 287, 287, 1, 9216, 0x780d3969
+0, 288, 288, 1, 9216, 0x780d3969
+0, 289, 289, 1, 9216, 0x780d3969
+0, 290, 290, 1, 9216, 0x780d3969
+0, 291, 291, 1, 9216, 0x780d3969
+0, 292, 292, 1, 9216, 0x780d3969
+0, 293, 293, 1, 9216, 0x780d3969
+0, 294, 294, 1, 9216, 0x780d3969
+0, 295, 295, 1, 9216, 0x780d3969
+0, 296, 296, 1, 9216, 0x780d3969
+0, 297, 297, 1, 9216, 0x780d3969
+0, 298, 298, 1, 9216, 0x780d3969
+0, 299, 299, 1, 9216, 0x780d3969
+0, 300, 300, 1, 9216, 0x780d3969
+0, 301, 301, 1, 9216, 0x780d3969
+0, 302, 302, 1, 9216, 0x780d3969
+0, 303, 303, 1, 9216, 0x780d3969
+0, 304, 304, 1, 9216, 0x780d3969
+0, 305, 305, 1, 9216, 0x780d3969
+0, 306, 306, 1, 9216, 0x780d3969
+0, 307, 307, 1, 9216, 0x780d3969
+0, 308, 308, 1, 9216, 0x780d3969
+0, 309, 309, 1, 9216, 0x780d3969
+0, 310, 310, 1, 9216, 0x780d3969
+0, 311, 311, 1, 9216, 0x780d3969
+0, 312, 312, 1, 9216, 0x780d3969
+0, 313, 313, 1, 9216, 0x780d3969
+0, 314, 314, 1, 9216, 0xc72e034e
diff --git a/tests/ref/fate/filter-stereo3d-abr-ml b/tests/ref/fate/filter-stereo3d-abr-ml
new file mode 100644
index 0000000000..d0597a7fb6
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-abr-ml
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 76032, 0xad4c8a22
+0, 1, 1, 1, 76032, 0x0dfdc6ad
+0, 2, 2, 1, 76032, 0x6341da83
+0, 3, 3, 1, 76032, 0x8dbcb05f
+0, 4, 4, 1, 76032, 0xad87bbee
diff --git a/tests/ref/fate/filter-stereo3d-abr-mr b/tests/ref/fate/filter-stereo3d-abr-mr
new file mode 100644
index 0000000000..44a8091bb9
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-abr-mr
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 76032, 0x5d0effbe
+0, 1, 1, 1, 76032, 0x5bb49e95
+0, 2, 2, 1, 76032, 0xb6301bc7
+0, 3, 3, 1, 76032, 0x7cf1d042
+0, 4, 4, 1, 76032, 0x24fafa55
diff --git a/tests/ref/fate/filter-stereo3d-al-sbsl b/tests/ref/fate/filter-stereo3d-al-sbsl
new file mode 100644
index 0000000000..b19cbb82c9
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-al-sbsl
@@ -0,0 +1,6 @@
+#tb 0: 2/25
+0, 0, 0, 1, 304128, 0xb9c0ef40
+0, 1, 1, 1, 304128, 0xfa0b7709
+0, 2, 2, 1, 304128, 0x14255f47
+0, 3, 3, 1, 304128, 0xa9da07de
+0, 4, 4, 1, 304128, 0x9d64b93b
diff --git a/tests/ref/fate/filter-stereo3d-ar-abl b/tests/ref/fate/filter-stereo3d-ar-abl
new file mode 100644
index 0000000000..0358199f9e
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-ar-abl
@@ -0,0 +1,6 @@
+#tb 0: 2/25
+0, 0, 0, 1, 304128, 0x7babef40
+0, 1, 1, 1, 304128, 0x287d7709
+0, 2, 2, 1, 304128, 0x385f5f47
+0, 3, 3, 1, 304128, 0x503507de
+0, 4, 4, 1, 304128, 0xb97db93b
diff --git a/tests/ref/fate/filter-stereo3d-sbsl-abl b/tests/ref/fate/filter-stereo3d-sbsl-abl
new file mode 100644
index 0000000000..273e520ba7
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-sbsl-abl
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0x2f9389ef
+0, 1, 1, 1, 152064, 0x16c66551
+0, 2, 2, 1, 152064, 0xd779f64a
+0, 3, 3, 1, 152064, 0x7a7c80b0
+0, 4, 4, 1, 152064, 0x0702b652
diff --git a/tests/ref/fate/filter-stereo3d-sbsl-abr b/tests/ref/fate/filter-stereo3d-sbsl-abr
new file mode 100644
index 0000000000..c827e3c456
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-sbsl-abr
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0xd1f489ef
+0, 1, 1, 1, 152064, 0xe4fe6551
+0, 2, 2, 1, 152064, 0xd0d9f64a
+0, 3, 3, 1, 152064, 0xfd3a80b0
+0, 4, 4, 1, 152064, 0x488eb652
diff --git a/tests/ref/fate/filter-stereo3d-sbsl-al b/tests/ref/fate/filter-stereo3d-sbsl-al
new file mode 100644
index 0000000000..5c8a429903
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-sbsl-al
@@ -0,0 +1,6 @@
+#tb 0: 1/50
+0, 0, 0, 1, 76032, 0x3ff06515
+0, 1, 1, 1, 76032, 0x00d824da
+0, 2, 2, 1, 76032, 0x64a33c64
+0, 3, 3, 1, 76032, 0xeef328ed
+0, 4, 4, 1, 76032, 0x4bb209cc
diff --git a/tests/ref/fate/filter-stereo3d-sbsl-sbsr b/tests/ref/fate/filter-stereo3d-sbsl-sbsr
new file mode 100644
index 0000000000..b417ae4f4e
--- /dev/null
+++ b/tests/ref/fate/filter-stereo3d-sbsl-sbsr
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 152064, 0xbe2f89ef
+0, 1, 1, 1, 152064, 0x4c806551
+0, 2, 2, 1, 152064, 0x8165f64a
+0, 3, 3, 1, 152064, 0xadf280b0
+0, 4, 4, 1, 152064, 0x6677b652
diff --git a/tests/ref/fate/filter-telecine b/tests/ref/fate/filter-telecine
new file mode 100644
index 0000000000..b8a13a975f
--- /dev/null
+++ b/tests/ref/fate/filter-telecine
@@ -0,0 +1,63 @@
+#tb 0: 4/125
+0, 0, 0, 1, 152064, 0x05b789ef
+0, 1, 1, 1, 152064, 0x4bb46551
+0, 2, 2, 1, 152064, 0x40692c80
+0, 3, 3, 1, 152064, 0xd7ad04cb
+0, 4, 4, 1, 152064, 0x2a8380b0
+0, 5, 5, 1, 152064, 0x4de3b652
+0, 6, 6, 1, 152064, 0xedb5a8e6
+0, 7, 7, 1, 152064, 0x549dfa8a
+0, 8, 8, 1, 152064, 0x447bc7b9
+0, 9, 9, 1, 152064, 0x5ab58bac
+0, 10, 10, 1, 152064, 0x1f1b8026
+0, 11, 11, 1, 152064, 0x91373915
+0, 12, 12, 1, 152064, 0x90895a6e
+0, 13, 13, 1, 152064, 0x793d075e
+0, 14, 14, 1, 152064, 0x30f5fcd5
+0, 15, 15, 1, 152064, 0xc711ad61
+0, 16, 16, 1, 152064, 0x24eca223
+0, 17, 17, 1, 152064, 0x0a4073dc
+0, 18, 18, 1, 152064, 0x06e34d70
+0, 19, 19, 1, 152064, 0xa91c0f05
+0, 20, 20, 1, 152064, 0x8e364e18
+0, 21, 21, 1, 152064, 0xb15d38c8
+0, 22, 22, 1, 152064, 0x6b2b2e46
+0, 23, 23, 1, 152064, 0xbd2320cb
+0, 24, 24, 1, 152064, 0xf34ddbff
+0, 25, 25, 1, 152064, 0xfc7bf570
+0, 26, 26, 1, 152064, 0x9dc72412
+0, 27, 27, 1, 152064, 0xa1242020
+0, 28, 28, 1, 152064, 0x1f939e6a
+0, 29, 29, 1, 152064, 0x2f2768ef
+0, 30, 30, 1, 152064, 0xce09f9d6
+0, 31, 31, 1, 152064, 0x95579936
+0, 32, 32, 1, 152064, 0x41181cbd
+0, 33, 33, 1, 152064, 0xe9cec847
+0, 34, 34, 1, 152064, 0xd780d887
+0, 35, 35, 1, 152064, 0x76d2a455
+0, 36, 36, 1, 152064, 0x6dc3650e
+0, 37, 37, 1, 152064, 0x8d165d23
+0, 38, 38, 1, 152064, 0x64f10efa
+0, 39, 39, 1, 152064, 0xe295c51e
+0, 40, 40, 1, 152064, 0xd766fc8d
+0, 41, 41, 1, 152064, 0xe22f7a30
+0, 42, 42, 1, 152064, 0xd8c68892
+0, 43, 43, 1, 152064, 0x26516b0e
+0, 44, 44, 1, 152064, 0xfa8d94fb
+0, 45, 45, 1, 152064, 0x4c9737ab
+0, 46, 46, 1, 152064, 0xa50d01f8
+0, 47, 47, 1, 152064, 0x82f12165
+0, 48, 48, 1, 152064, 0x113fadc0
+0, 49, 49, 1, 152064, 0x88734edd
+0, 50, 50, 1, 152064, 0xd2735925
+0, 51, 51, 1, 152064, 0xd4e49e08
+0, 52, 52, 1, 152064, 0x8cd54fc5
+0, 53, 53, 1, 152064, 0xae821cac
+0, 54, 54, 1, 152064, 0x575c20ec
+0, 55, 55, 1, 152064, 0xfd500471
+0, 56, 56, 1, 152064, 0x61b47e73
+0, 57, 57, 1, 152064, 0x213d5314
+0, 58, 58, 1, 152064, 0xb4ddd391
+0, 59, 59, 1, 152064, 0x6e88c5c2
+0, 60, 60, 1, 152064, 0xbb87b483
+0, 61, 61, 1, 152064, 0x4bbad8ea
diff --git a/tests/ref/fate/filter-thumbnail b/tests/ref/fate/filter-thumbnail
new file mode 100644
index 0000000000..36f11f297e
--- /dev/null
+++ b/tests/ref/fate/filter-thumbnail
@@ -0,0 +1 @@
+thumbnail cd429b3d92c33bcc257e8e6a3284dbf7
diff --git a/tests/ref/fate/filter-tile b/tests/ref/fate/filter-tile
new file mode 100644
index 0000000000..03ded41058
--- /dev/null
+++ b/tests/ref/fate/filter-tile
@@ -0,0 +1 @@
+tile 93119209651dc299708c7f31522b991c
diff --git a/tests/ref/fate/filter-unsharp b/tests/ref/fate/filter-unsharp
index 5dcf40fdc4..613163b180 100644
--- a/tests/ref/fate/filter-unsharp
+++ b/tests/ref/fate/filter-unsharp
@@ -1,51 +1,51 @@
#tb 0: 1/25
-0, 0, 0, 1, 152064, 0x19a94798
-0, 1, 1, 1, 152064, 0xc88b24f4
-0, 2, 2, 1, 152064, 0xd027b44b
-0, 3, 3, 1, 152064, 0xa9fb3e54
-0, 4, 4, 1, 152064, 0x2991747d
-0, 5, 5, 1, 152064, 0x1dc267fc
-0, 6, 6, 1, 152064, 0xe9063293
-0, 7, 7, 1, 152064, 0xc23e41a4
-0, 8, 8, 1, 152064, 0xaa433dc5
-0, 9, 9, 1, 152064, 0x22b0f0a3
-0, 10, 10, 1, 152064, 0x796d08d8
-0, 11, 11, 1, 152064, 0xa2babd6b
-0, 12, 12, 1, 152064, 0x531e6a62
-0, 13, 13, 1, 152064, 0xc8fa5b9d
-0, 14, 14, 1, 152064, 0x33e54ae8
-0, 15, 15, 1, 152064, 0x86dfd0b8
-0, 16, 16, 1, 152064, 0x101f1170
-0, 17, 17, 1, 152064, 0x230eef00
-0, 18, 18, 1, 152064, 0xa5ee1c5e
-0, 19, 19, 1, 152064, 0x241893c6
-0, 20, 20, 1, 152064, 0x86a0a883
-0, 21, 21, 1, 152064, 0x12b4d8f7
-0, 22, 22, 1, 152064, 0xb220d497
-0, 23, 23, 1, 152064, 0xbaea200e
-0, 24, 24, 1, 152064, 0x6d96b7f3
-0, 25, 25, 1, 152064, 0xc70d4ebb
-0, 26, 26, 1, 152064, 0x20df50af
-0, 27, 27, 1, 152064, 0xfce89174
-0, 28, 28, 1, 152064, 0x74be5c8e
-0, 29, 29, 1, 152064, 0x51f419a6
-0, 30, 30, 1, 152064, 0x790621e7
-0, 31, 31, 1, 152064, 0x37387da2
-0, 32, 32, 1, 152064, 0x8228baa4
-0, 33, 33, 1, 152064, 0xdd2a42b7
-0, 34, 34, 1, 152064, 0xa28bfc63
-0, 35, 35, 1, 152064, 0xe8284337
-0, 36, 36, 1, 152064, 0xb1dae9fe
-0, 37, 37, 1, 152064, 0x0378c0af
-0, 38, 38, 1, 152064, 0x79c514d4
-0, 39, 39, 1, 152064, 0x043e0347
-0, 40, 40, 1, 152064, 0x4d11131b
-0, 41, 41, 1, 152064, 0xb2a05924
-0, 42, 42, 1, 152064, 0xd0097464
-0, 43, 43, 1, 152064, 0x32dfd8c0
-0, 44, 44, 1, 152064, 0xd9ecbf03
-0, 45, 45, 1, 152064, 0x8dcc403f
-0, 46, 46, 1, 152064, 0x95e81af7
-0, 47, 47, 1, 152064, 0xb8018b25
-0, 48, 48, 1, 152064, 0xeecf7281
-0, 49, 49, 1, 152064, 0x23e49602
+0, 0, 0, 1, 152064, 0x58100735
+0, 1, 1, 1, 152064, 0x2967e43d
+0, 2, 2, 1, 152064, 0x6f0c786d
+0, 3, 3, 1, 152064, 0xaf1fff7c
+0, 4, 4, 1, 152064, 0xee583651
+0, 5, 5, 1, 152064, 0xf50c280f
+0, 6, 6, 1, 152064, 0x3eeff2e9
+0, 7, 7, 1, 152064, 0xb43c0fc7
+0, 8, 8, 1, 152064, 0x55733232
+0, 9, 9, 1, 152064, 0x78b5b9fe
+0, 10, 10, 1, 152064, 0x8b39c410
+0, 11, 11, 1, 152064, 0x1a2b686f
+0, 12, 12, 1, 152064, 0xee622ce9
+0, 13, 13, 1, 152064, 0x9f8a2f4f
+0, 14, 14, 1, 152064, 0xd6210d42
+0, 15, 15, 1, 152064, 0x598a8e88
+0, 16, 16, 1, 152064, 0xeeaccbfa
+0, 17, 17, 1, 152064, 0xe2a3b094
+0, 18, 18, 1, 152064, 0x2becd63d
+0, 19, 19, 1, 152064, 0x2cfd46c6
+0, 20, 20, 1, 152064, 0x781b616e
+0, 21, 21, 1, 152064, 0x90908f49
+0, 22, 22, 1, 152064, 0x136d8950
+0, 23, 23, 1, 152064, 0xe3b8dfa4
+0, 24, 24, 1, 152064, 0x9a857595
+0, 25, 25, 1, 152064, 0x9d5d16f3
+0, 26, 26, 1, 152064, 0xad0815e6
+0, 27, 27, 1, 152064, 0xbd485852
+0, 28, 28, 1, 152064, 0x379023e0
+0, 29, 29, 1, 152064, 0x47c3e49e
+0, 30, 30, 1, 152064, 0x435eead9
+0, 31, 31, 1, 152064, 0x6ef8445d
+0, 32, 32, 1, 152064, 0x13258191
+0, 33, 33, 1, 152064, 0x09adfa4b
+0, 34, 34, 1, 152064, 0xd67e9f1f
+0, 35, 35, 1, 152064, 0x456e1298
+0, 36, 36, 1, 152064, 0x9998b485
+0, 37, 37, 1, 152064, 0xca1f8859
+0, 38, 38, 1, 152064, 0x9d1ad87c
+0, 39, 39, 1, 152064, 0x37a7cfac
+0, 40, 40, 1, 152064, 0xde3ad5a8
+0, 41, 41, 1, 152064, 0xf40c20d3
+0, 42, 42, 1, 152064, 0x35a23e85
+0, 43, 43, 1, 152064, 0xda1fa02a
+0, 44, 44, 1, 152064, 0xe4ae84e9
+0, 45, 45, 1, 152064, 0x113dfdbb
+0, 46, 46, 1, 152064, 0xe50fd571
+0, 47, 47, 1, 152064, 0xd6a043ef
+0, 48, 48, 1, 152064, 0xabfd3940
+0, 49, 49, 1, 152064, 0xdf085a8d
diff --git a/tests/ref/fate/filter-vflip b/tests/ref/fate/filter-vflip
index c0bc8931c3..8850b45e1f 100644
--- a/tests/ref/fate/filter-vflip
+++ b/tests/ref/fate/filter-vflip
@@ -1 +1 @@
-vflip 8f5a94b3d651f24a628ff4465cfea131
+vflip 0de640dff4447bd1b33d23f2b8ad9d4a
diff --git a/tests/ref/fate/filter-vflip_crop b/tests/ref/fate/filter-vflip_crop
index f4e2950fee..9f93ac7a49 100644
--- a/tests/ref/fate/filter-vflip_crop
+++ b/tests/ref/fate/filter-vflip_crop
@@ -1 +1 @@
-vflip_crop eed36832b2e9a3eea0af6311399c015b
+vflip_crop f7d5d9ffd815847c3e2089b920bae406
diff --git a/tests/ref/fate/filter-vflip_vflip b/tests/ref/fate/filter-vflip_vflip
index 5899186869..49d3ec0f3d 100644
--- a/tests/ref/fate/filter-vflip_vflip
+++ b/tests/ref/fate/filter-vflip_vflip
@@ -1 +1 @@
-vflip_vflip 7aaf1057c0edf7d5e9700f9c8e510ea9
+vflip_vflip fcb007249fba9371fe84a61c974fcb00
diff --git a/tests/ref/fate/filter-yadif-mode0 b/tests/ref/fate/filter-yadif-mode0
index d2c14d39b8..4d428903b0 100644
--- a/tests/ref/fate/filter-yadif-mode0
+++ b/tests/ref/fate/filter-yadif-mode0
@@ -1,32 +1,31 @@
-#tb 0: 1/180000
-0, 64800, 64800, 0, 622080, 0x6331caee
-0, 72000, 72000, 0, 622080, 0xa459e690
-0, 79200, 79200, 0, 622080, 0x6429c648
-0, 86400, 86400, 0, 622080, 0xa49891ca
-0, 93600, 93600, 0, 622080, 0x2a887404
-0, 100800, 100800, 0, 622080, 0xe8d49705
-0, 108000, 108000, 0, 622080, 0x1b627835
-0, 115200, 115200, 0, 622080, 0x686858fd
-0, 122400, 122400, 0, 622080, 0x2675174f
-0, 129600, 129600, 0, 622080, 0x78470e7f
-0, 136800, 136800, 0, 622080, 0xffb366ec
-0, 144000, 144000, 0, 622080, 0xd575da72
-0, 151200, 151200, 0, 622080, 0x5fb297f7
-0, 158400, 158400, 0, 622080, 0xbac77ca0
-0, 165600, 165600, 0, 622080, 0x3276ed72
-0, 172800, 172800, 0, 622080, 0x264092b2
-0, 180000, 180000, 0, 622080, 0x20ba1094
-0, 187200, 187200, 0, 622080, 0x76cc3139
-0, 194400, 194400, 0, 622080, 0x469a4902
-0, 201600, 201600, 0, 622080, 0x0ed7b8f5
-0, 208800, 208800, 0, 622080, 0xdc51aeac
-0, 216000, 216000, 0, 622080, 0xee06aa36
-0, 223200, 223200, 0, 622080, 0x7372405f
-0, 230400, 230400, 0, 622080, 0x9e0ee776
-0, 237600, 237600, 0, 622080, 0x39e6d8c9
-0, 244800, 244800, 0, 622080, 0x51d9ac9a
-0, 252000, 252000, 0, 622080, 0x2b63441d
-0, 259200, 259200, 0, 622080, 0x58afbd5e
-0, 266400, 266400, 0, 622080, 0xb972f716
-0, 273600, 273600, 0, 622080, 0x6a6df129
-0, 280800, 280800, 0, 622080, 0x28b1373d
+#tb 0: 1/25
+0, 9, 9, 1, 622080, 0x6331caee
+0, 10, 10, 1, 622080, 0xa459e690
+0, 11, 11, 1, 622080, 0x6429c648
+0, 12, 12, 1, 622080, 0xa49891ca
+0, 13, 13, 1, 622080, 0x2a887404
+0, 14, 14, 1, 622080, 0xe8d49705
+0, 15, 15, 1, 622080, 0x1b627835
+0, 16, 16, 1, 622080, 0x686858fd
+0, 17, 17, 1, 622080, 0x2675174f
+0, 18, 18, 1, 622080, 0x78470e7f
+0, 19, 19, 1, 622080, 0xffb366ec
+0, 20, 20, 1, 622080, 0xd575da72
+0, 21, 21, 1, 622080, 0x5fb297f7
+0, 22, 22, 1, 622080, 0xbac77ca0
+0, 23, 23, 1, 622080, 0x3276ed72
+0, 24, 24, 1, 622080, 0x264092b2
+0, 25, 25, 1, 622080, 0x20ba1094
+0, 26, 26, 1, 622080, 0x76cc3139
+0, 27, 27, 1, 622080, 0x469a4902
+0, 28, 28, 1, 622080, 0x0ed7b8f5
+0, 29, 29, 1, 622080, 0xdc51aeac
+0, 30, 30, 1, 622080, 0xee06aa36
+0, 31, 31, 1, 622080, 0x7372405f
+0, 32, 32, 1, 622080, 0x9e0ee776
+0, 33, 33, 1, 622080, 0x39e6d8c9
+0, 34, 34, 1, 622080, 0x51d9ac9a
+0, 35, 35, 1, 622080, 0x2b63441d
+0, 36, 36, 1, 622080, 0x58afbd5e
+0, 37, 37, 1, 622080, 0xb972f716
+0, 38, 38, 1, 622080, 0x6a6df129
diff --git a/tests/ref/fate/filter-yadif-mode1 b/tests/ref/fate/filter-yadif-mode1
index ca5f290ee9..08cd518570 100644
--- a/tests/ref/fate/filter-yadif-mode1
+++ b/tests/ref/fate/filter-yadif-mode1
@@ -1,63 +1,60 @@
-#tb 0: 1/180000
-0, 64800, 64800, 0, 622080, 0x6331caee
-0, 68400, 68400, 0, 622080, 0x625da883
-0, 72000, 72000, 0, 622080, 0xa459e690
-0, 75600, 75600, 0, 622080, 0xce5d891e
-0, 79200, 79200, 0, 622080, 0x6429c648
-0, 82800, 82800, 0, 622080, 0x608cc0ba
-0, 86400, 86400, 0, 622080, 0xa49891ca
-0, 90000, 90000, 0, 622080, 0x9721987f
-0, 93600, 93600, 0, 622080, 0x2a887404
-0, 97200, 97200, 0, 622080, 0x60d71d47
-0, 100800, 100800, 0, 622080, 0xe8d49705
-0, 104400, 104400, 0, 622080, 0x821e13cb
-0, 108000, 108000, 0, 622080, 0x1b627835
-0, 111600, 111600, 0, 622080, 0x1806c5f4
-0, 115200, 115200, 0, 622080, 0x686858fd
-0, 118800, 118800, 0, 622080, 0xab865773
-0, 122400, 122400, 0, 622080, 0x2675174f
-0, 126000, 126000, 0, 622080, 0x43a61a14
-0, 129600, 129600, 0, 622080, 0x78470e7f
-0, 133200, 133200, 0, 622080, 0xeb877bc6
-0, 136800, 136800, 0, 622080, 0xffb366ec
-0, 140400, 140400, 0, 622080, 0xda0906e7
-0, 144000, 144000, 0, 622080, 0xd575da72
-0, 147600, 147600, 0, 622080, 0x23ae25a4
-0, 151200, 151200, 0, 622080, 0x5fb297f7
-0, 154800, 154800, 0, 622080, 0x99b32978
-0, 158400, 158400, 0, 622080, 0xbac77ca0
-0, 162000, 162000, 0, 622080, 0xc1cdcbf9
-0, 165600, 165600, 0, 622080, 0x3276ed72
-0, 169200, 169200, 0, 622080, 0x4061f5ab
-0, 172800, 172800, 0, 622080, 0x264092b2
-0, 176400, 176400, 0, 622080, 0xa4e2039e
-0, 180000, 180000, 0, 622080, 0x20ba1094
-0, 183600, 183600, 0, 622080, 0x984e906e
-0, 187200, 187200, 0, 622080, 0x76cc3139
-0, 190800, 190800, 0, 622080, 0xf70e2cf6
-0, 194400, 194400, 0, 622080, 0x469a4902
-0, 198000, 198000, 0, 622080, 0x235312e6
-0, 201600, 201600, 0, 622080, 0x0ed7b8f5
-0, 205200, 205200, 0, 622080, 0xd0269cc3
-0, 208800, 208800, 0, 622080, 0xdc51aeac
-0, 212400, 212400, 0, 622080, 0x1aa5f76e
-0, 216000, 216000, 0, 622080, 0xee06aa36
-0, 219600, 219600, 0, 622080, 0xa7103230
-0, 223200, 223200, 0, 622080, 0x7372405f
-0, 226800, 226800, 0, 622080, 0x8d7a44b5
-0, 230400, 230400, 0, 622080, 0x9e0ee776
-0, 234000, 234000, 0, 622080, 0xd41e8560
-0, 237600, 237600, 0, 622080, 0x39e6d8c9
-0, 241200, 241200, 0, 622080, 0x7a23d70c
-0, 244800, 244800, 0, 622080, 0x51d9ac9a
-0, 248400, 248400, 0, 622080, 0x8eacf7f2
-0, 252000, 252000, 0, 622080, 0x2b63441d
-0, 255600, 255600, 0, 622080, 0x9f71b742
-0, 259200, 259200, 0, 622080, 0x58afbd5e
-0, 262800, 262800, 0, 622080, 0x4d645292
-0, 266400, 266400, 0, 622080, 0xb972f716
-0, 270000, 270000, 0, 622080, 0xbb5d01a2
-0, 273600, 273600, 0, 622080, 0x6a6df129
-0, 277200, 277200, 0, 622080, 0x9e45371e
-0, 280800, 280800, 0, 622080, 0x28b1373d
-0, 284400, 284400, 0, 622080, 0xa1cdb1f2
+#tb 0: 1/50
+0, 18, 18, 1, 622080, 0x6331caee
+0, 19, 19, 1, 622080, 0x625da883
+0, 20, 20, 1, 622080, 0xa459e690
+0, 21, 21, 1, 622080, 0xce5d891e
+0, 22, 22, 1, 622080, 0x6429c648
+0, 23, 23, 1, 622080, 0x608cc0ba
+0, 24, 24, 1, 622080, 0xa49891ca
+0, 25, 25, 1, 622080, 0x9721987f
+0, 26, 26, 1, 622080, 0x2a887404
+0, 27, 27, 1, 622080, 0x60d71d47
+0, 28, 28, 1, 622080, 0xe8d49705
+0, 29, 29, 1, 622080, 0x821e13cb
+0, 30, 30, 1, 622080, 0x1b627835
+0, 31, 31, 1, 622080, 0x1806c5f4
+0, 32, 32, 1, 622080, 0x686858fd
+0, 33, 33, 1, 622080, 0xab865773
+0, 34, 34, 1, 622080, 0x2675174f
+0, 35, 35, 1, 622080, 0x43a61a14
+0, 36, 36, 1, 622080, 0x78470e7f
+0, 37, 37, 1, 622080, 0xeb877bc6
+0, 38, 38, 1, 622080, 0xffb366ec
+0, 39, 39, 1, 622080, 0xda0906e7
+0, 40, 40, 1, 622080, 0xd575da72
+0, 41, 41, 1, 622080, 0x23ae25a4
+0, 42, 42, 1, 622080, 0x5fb297f7
+0, 43, 43, 1, 622080, 0x99b32978
+0, 44, 44, 1, 622080, 0xbac77ca0
+0, 45, 45, 1, 622080, 0xc1cdcbf9
+0, 46, 46, 1, 622080, 0x3276ed72
+0, 47, 47, 1, 622080, 0x4061f5ab
+0, 48, 48, 1, 622080, 0x264092b2
+0, 49, 49, 1, 622080, 0xa4e2039e
+0, 50, 50, 1, 622080, 0x20ba1094
+0, 51, 51, 1, 622080, 0x984e906e
+0, 52, 52, 1, 622080, 0x76cc3139
+0, 53, 53, 1, 622080, 0xf70e2cf6
+0, 54, 54, 1, 622080, 0x469a4902
+0, 55, 55, 1, 622080, 0x235312e6
+0, 56, 56, 1, 622080, 0x0ed7b8f5
+0, 57, 57, 1, 622080, 0xd0269cc3
+0, 58, 58, 1, 622080, 0xdc51aeac
+0, 59, 59, 1, 622080, 0x1aa5f76e
+0, 60, 60, 1, 622080, 0xee06aa36
+0, 61, 61, 1, 622080, 0xa7103230
+0, 62, 62, 1, 622080, 0x7372405f
+0, 63, 63, 1, 622080, 0x8d7a44b5
+0, 64, 64, 1, 622080, 0x9e0ee776
+0, 65, 65, 1, 622080, 0xd41e8560
+0, 66, 66, 1, 622080, 0x39e6d8c9
+0, 67, 67, 1, 622080, 0x7a23d70c
+0, 68, 68, 1, 622080, 0x51d9ac9a
+0, 69, 69, 1, 622080, 0x8eacf7f2
+0, 70, 70, 1, 622080, 0x2b63441d
+0, 71, 71, 1, 622080, 0x9f71b742
+0, 72, 72, 1, 622080, 0x58afbd5e
+0, 73, 73, 1, 622080, 0x4d645292
+0, 74, 74, 1, 622080, 0xb972f716
+0, 75, 75, 1, 622080, 0xbb5d01a2
+0, 76, 76, 1, 622080, 0x6a6df129
diff --git a/tests/ref/fate/filter-yadif10 b/tests/ref/fate/filter-yadif10
new file mode 100644
index 0000000000..aa27bfcbb4
--- /dev/null
+++ b/tests/ref/fate/filter-yadif10
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 9, 9, 1, 1244160, 0x5b49e0c0
+0, 10, 10, 1, 1244160, 0x76ba6bab
+0, 11, 11, 1, 1244160, 0x0298cb8d
+0, 12, 12, 1, 1244160, 0x9c81759a
+0, 13, 13, 1, 1244160, 0xa239d1ae
+0, 14, 14, 1, 1244160, 0x3e95ada9
+0, 15, 15, 1, 1244160, 0x8b87e8f8
+0, 16, 16, 1, 1244160, 0x64f89653
+0, 17, 17, 1, 1244160, 0x58e5d12e
+0, 18, 18, 1, 1244160, 0x38b4003a
+0, 19, 19, 1, 1244160, 0xc005c29c
+0, 20, 20, 1, 1244160, 0x10c0c60d
+0, 21, 21, 1, 1244160, 0x1b550998
+0, 22, 22, 1, 1244160, 0x7aacf6ab
+0, 23, 23, 1, 1244160, 0xeb205d98
+0, 24, 24, 1, 1244160, 0x6ad2134c
+0, 25, 25, 1, 1244160, 0x8aea4e56
+0, 26, 26, 1, 1244160, 0x0d910a6b
+0, 27, 27, 1, 1244160, 0x749ae307
+0, 28, 28, 1, 1244160, 0x8ff7af3c
+0, 29, 29, 1, 1244160, 0x9ba51b91
+0, 30, 30, 1, 1244160, 0xad476514
+0, 31, 31, 1, 1244160, 0x674481d6
+0, 32, 32, 1, 1244160, 0x0937e677
+0, 33, 33, 1, 1244160, 0x6c2c53ee
+0, 34, 34, 1, 1244160, 0x524a164e
+0, 35, 35, 1, 1244160, 0x77a405ab
+0, 36, 36, 1, 1244160, 0xaa6b47c4
+0, 37, 37, 1, 1244160, 0x0b5ab556
+0, 38, 38, 1, 1244160, 0xbe1edab9
diff --git a/tests/ref/fate/filter-yadif16 b/tests/ref/fate/filter-yadif16
new file mode 100644
index 0000000000..65427a2357
--- /dev/null
+++ b/tests/ref/fate/filter-yadif16
@@ -0,0 +1,31 @@
+#tb 0: 1/25
+0, 9, 9, 1, 1244160, 0xfb65caee
+0, 10, 10, 1, 1244160, 0x6222e690
+0, 11, 11, 1, 1244160, 0x020ac648
+0, 12, 12, 1, 1244160, 0xb76691ca
+0, 13, 13, 1, 1244160, 0xe0fd7404
+0, 14, 14, 1, 1244160, 0x3ab29705
+0, 15, 15, 1, 1244160, 0xbe807835
+0, 16, 16, 1, 1244160, 0x77d358fd
+0, 17, 17, 1, 1244160, 0x359b174f
+0, 18, 18, 1, 1244160, 0xe20f0e7f
+0, 19, 19, 1, 1244160, 0x988966ec
+0, 20, 20, 1, 1244160, 0xd078da72
+0, 21, 21, 1, 1244160, 0x276d97f7
+0, 22, 22, 1, 1244160, 0xf8ee7ca0
+0, 23, 23, 1, 1244160, 0x776bed72
+0, 24, 24, 1, 1244160, 0xb9bf92b2
+0, 25, 25, 1, 1244160, 0x30e01094
+0, 26, 26, 1, 1244160, 0xbc5f3139
+0, 27, 27, 1, 1244160, 0x44324902
+0, 28, 28, 1, 1244160, 0x64aab8f5
+0, 29, 29, 1, 1244160, 0x0a05aeac
+0, 30, 30, 1, 1244160, 0x31e5aa36
+0, 31, 31, 1, 1244160, 0xa685405f
+0, 32, 32, 1, 1244160, 0x54a6e776
+0, 33, 33, 1, 1244160, 0x9af4d8c9
+0, 34, 34, 1, 1244160, 0xf709ac9a
+0, 35, 35, 1, 1244160, 0x12a9441d
+0, 36, 36, 1, 1244160, 0xf3f1bd5e
+0, 37, 37, 1, 1244160, 0x7bcef716
+0, 38, 38, 1, 1244160, 0xe3a2f129
diff --git a/tests/ref/fate/flic-af11-palette-change b/tests/ref/fate/flic-af11-palette-change
index 61e6c1d8a0..cd702b622c 100644
--- a/tests/ref/fate/flic-af11-palette-change
+++ b/tests/ref/fate/flic-af11-palette-change
@@ -1,117 +1,117 @@
#tb 0: 1/35
-0, 0, 0, 1, 192000, 0x64da83e8
-0, 1, 1, 1, 192000, 0xf59ccccc
-0, 2, 2, 1, 192000, 0xaaa06c5c
-0, 3, 3, 1, 192000, 0xa98f82c0
-0, 4, 4, 1, 192000, 0x164fbbdc
-0, 5, 5, 1, 192000, 0x0b3abc0c
-0, 6, 6, 1, 192000, 0x47661943
-0, 7, 7, 1, 192000, 0x30711074
-0, 8, 8, 1, 192000, 0x67684a84
-0, 9, 9, 1, 192000, 0x1d9afa70
-0, 10, 10, 1, 192000, 0x4fd28e78
-0, 11, 11, 1, 192000, 0x9bc5c8cc
-0, 12, 12, 1, 192000, 0xcf268b6c
-0, 13, 13, 1, 192000, 0xdfe65fd4
-0, 14, 14, 1, 192000, 0x47e75404
-0, 15, 15, 1, 192000, 0xb3b5b448
-0, 16, 16, 1, 192000, 0x826c94b4
-0, 17, 17, 1, 192000, 0x158e95f8
-0, 18, 18, 1, 192000, 0x576f031f
-0, 19, 19, 1, 192000, 0xea3399e8
-0, 20, 20, 1, 192000, 0x76b1e224
-0, 21, 21, 1, 192000, 0x290073db
-0, 22, 22, 1, 192000, 0x83741abf
-0, 23, 23, 1, 192000, 0x50f9c4ec
-0, 24, 24, 1, 192000, 0x6d8fdac0
-0, 25, 25, 1, 192000, 0xe26e2600
-0, 26, 26, 1, 192000, 0xbeb0e11c
-0, 27, 27, 1, 192000, 0x38282fd4
-0, 28, 28, 1, 192000, 0x13d0b790
-0, 29, 29, 1, 192000, 0x0cf8fca9
-0, 30, 30, 1, 192000, 0x64da83e8
-0, 31, 31, 1, 192000, 0xf59ccccc
-0, 32, 32, 1, 192000, 0xaaa06c5c
-0, 33, 33, 1, 192000, 0xa98f82c0
-0, 34, 34, 1, 192000, 0x164fbbdc
-0, 35, 35, 1, 192000, 0x0b3abc0c
-0, 36, 36, 1, 192000, 0x47661943
-0, 37, 37, 1, 192000, 0x30711074
-0, 38, 38, 1, 192000, 0x67684a84
-0, 39, 39, 1, 192000, 0x1d9afa70
-0, 40, 40, 1, 192000, 0x4fd28e78
-0, 41, 41, 1, 192000, 0x9bc5c8cc
-0, 42, 42, 1, 192000, 0xcf268b6c
-0, 43, 43, 1, 192000, 0xdfe65fd4
-0, 44, 44, 1, 192000, 0x47e75404
-0, 45, 45, 1, 192000, 0xb3b5b448
-0, 46, 46, 1, 192000, 0x826c94b4
-0, 47, 47, 1, 192000, 0x158e95f8
-0, 48, 48, 1, 192000, 0x576f031f
-0, 49, 49, 1, 192000, 0xea3399e8
-0, 50, 50, 1, 192000, 0x76b1e224
-0, 51, 51, 1, 192000, 0x290073db
-0, 52, 52, 1, 192000, 0x83741abf
-0, 53, 53, 1, 192000, 0x50f9c4ec
-0, 54, 54, 1, 192000, 0x6d8fdac0
-0, 55, 55, 1, 192000, 0xe26e2600
-0, 56, 56, 1, 192000, 0xbeb0e11c
-0, 57, 57, 1, 192000, 0x38282fd4
-0, 58, 58, 1, 192000, 0x13d0b790
-0, 59, 59, 1, 192000, 0x0cf8fca9
-0, 60, 60, 1, 192000, 0x64da83e8
-0, 61, 61, 1, 192000, 0xf59ccccc
-0, 62, 62, 1, 192000, 0xaaa06c5c
-0, 63, 63, 1, 192000, 0xa98f82c0
-0, 64, 64, 1, 192000, 0x164fbbdc
-0, 65, 65, 1, 192000, 0x0b3abc0c
-0, 66, 66, 1, 192000, 0x47661943
-0, 67, 67, 1, 192000, 0x30711074
-0, 68, 68, 1, 192000, 0x67684a84
-0, 69, 69, 1, 192000, 0x1d9afa70
-0, 70, 70, 1, 192000, 0x4fd28e78
-0, 71, 71, 1, 192000, 0x9bc5c8cc
-0, 72, 72, 1, 192000, 0xcf268b6c
-0, 73, 73, 1, 192000, 0xdfe65fd4
-0, 74, 74, 1, 192000, 0x47e75404
-0, 75, 75, 1, 192000, 0xb3b5b448
-0, 76, 76, 1, 192000, 0x826c94b4
-0, 77, 77, 1, 192000, 0x158e95f8
-0, 78, 78, 1, 192000, 0x576f031f
-0, 79, 79, 1, 192000, 0xea3399e8
-0, 80, 80, 1, 192000, 0x76b1e224
-0, 81, 81, 1, 192000, 0x290073db
-0, 82, 82, 1, 192000, 0x83741abf
-0, 83, 83, 1, 192000, 0x50f9c4ec
-0, 84, 84, 1, 192000, 0x6d8fdac0
-0, 85, 85, 1, 192000, 0xe26e2600
-0, 86, 86, 1, 192000, 0xbeb0e11c
-0, 87, 87, 1, 192000, 0x38282fd4
-0, 88, 88, 1, 192000, 0x13d0b790
-0, 89, 89, 1, 192000, 0x0cf8fca9
-0, 90, 90, 1, 192000, 0xfcb10883
-0, 91, 91, 1, 192000, 0xfcb10883
-0, 92, 92, 1, 192000, 0xd0ba80c4
-0, 93, 93, 1, 192000, 0xd0ba80c4
-0, 94, 94, 1, 192000, 0x690520d9
-0, 95, 95, 1, 192000, 0x690520d9
-0, 96, 96, 1, 192000, 0x5b621c3f
-0, 97, 97, 1, 192000, 0x5b621c3f
-0, 98, 98, 1, 192000, 0x689e231f
-0, 99, 99, 1, 192000, 0x689e231f
-0, 100, 100, 1, 192000, 0x20653ff2
-0, 101, 101, 1, 192000, 0x20653ff2
-0, 102, 102, 1, 192000, 0xc18b3231
-0, 103, 103, 1, 192000, 0xc18b3231
-0, 104, 104, 1, 192000, 0x6d87ec3d
-0, 105, 105, 1, 192000, 0x6d87ec3d
-0, 106, 106, 1, 192000, 0x1c5b53d6
-0, 107, 107, 1, 192000, 0x1c5b53d6
-0, 108, 108, 1, 192000, 0x152fdf12
-0, 109, 109, 1, 192000, 0xde187291
-0, 110, 110, 1, 192000, 0x167617a5
-0, 111, 111, 1, 192000, 0x5067b8de
-0, 112, 112, 1, 192000, 0xd02ae54e
-0, 113, 113, 1, 192000, 0x0d6e9402
-0, 114, 114, 1, 192000, 0xa8e98616
-0, 115, 115, 1, 192000, 0x04762d1a
+0, 0, 0, 1, 192000, 0x508ff8ac
+0, 1, 1, 1, 192000, 0xef0d4274
+0, 2, 2, 1, 192000, 0x0d50e0dd
+0, 3, 3, 1, 192000, 0xf638f782
+0, 4, 4, 1, 192000, 0x40e4314b
+0, 5, 5, 1, 192000, 0x0ce5318f
+0, 6, 6, 1, 192000, 0x14848fa9
+0, 7, 7, 1, 192000, 0x676f83e1
+0, 8, 8, 1, 192000, 0x5b98bea9
+0, 9, 9, 1, 192000, 0xf5cc709d
+0, 10, 10, 1, 192000, 0x719a0373
+0, 11, 11, 1, 192000, 0xba5a3e74
+0, 12, 12, 1, 192000, 0x34e10051
+0, 13, 13, 1, 192000, 0xb66dd42d
+0, 14, 14, 1, 192000, 0xfb58c833
+0, 15, 15, 1, 192000, 0xa28029a4
+0, 16, 16, 1, 192000, 0x28fa09b3
+0, 17, 17, 1, 192000, 0x676f0b08
+0, 18, 18, 1, 192000, 0x7af97965
+0, 19, 19, 1, 192000, 0x436f0f03
+0, 20, 20, 1, 192000, 0xbaca5814
+0, 21, 21, 1, 192000, 0xca97eb51
+0, 22, 22, 1, 192000, 0x1fc89137
+0, 23, 23, 1, 192000, 0x8af63a74
+0, 24, 24, 1, 192000, 0xca015077
+0, 25, 25, 1, 192000, 0x761599ad
+0, 26, 26, 1, 192000, 0x1ca1570c
+0, 27, 27, 1, 192000, 0x1209a3ac
+0, 28, 28, 1, 192000, 0xf7d92d01
+0, 29, 29, 1, 192000, 0x970d6fea
+0, 30, 30, 1, 192000, 0x508ff8ac
+0, 31, 31, 1, 192000, 0xef0d4274
+0, 32, 32, 1, 192000, 0x0d50e0dd
+0, 33, 33, 1, 192000, 0xf638f782
+0, 34, 34, 1, 192000, 0x40e4314b
+0, 35, 35, 1, 192000, 0x0ce5318f
+0, 36, 36, 1, 192000, 0x14848fa9
+0, 37, 37, 1, 192000, 0x676f83e1
+0, 38, 38, 1, 192000, 0x5b98bea9
+0, 39, 39, 1, 192000, 0xf5cc709d
+0, 40, 40, 1, 192000, 0x719a0373
+0, 41, 41, 1, 192000, 0xba5a3e74
+0, 42, 42, 1, 192000, 0x34e10051
+0, 43, 43, 1, 192000, 0xb66dd42d
+0, 44, 44, 1, 192000, 0xfb58c833
+0, 45, 45, 1, 192000, 0xa28029a4
+0, 46, 46, 1, 192000, 0x28fa09b3
+0, 47, 47, 1, 192000, 0x676f0b08
+0, 48, 48, 1, 192000, 0x7af97965
+0, 49, 49, 1, 192000, 0x436f0f03
+0, 50, 50, 1, 192000, 0xbaca5814
+0, 51, 51, 1, 192000, 0xca97eb51
+0, 52, 52, 1, 192000, 0x1fc89137
+0, 53, 53, 1, 192000, 0x8af63a74
+0, 54, 54, 1, 192000, 0xca015077
+0, 55, 55, 1, 192000, 0x761599ad
+0, 56, 56, 1, 192000, 0x1ca1570c
+0, 57, 57, 1, 192000, 0x1209a3ac
+0, 58, 58, 1, 192000, 0xf7d92d01
+0, 59, 59, 1, 192000, 0x970d6fea
+0, 60, 60, 1, 192000, 0x508ff8ac
+0, 61, 61, 1, 192000, 0xef0d4274
+0, 62, 62, 1, 192000, 0x0d50e0dd
+0, 63, 63, 1, 192000, 0xf638f782
+0, 64, 64, 1, 192000, 0x40e4314b
+0, 65, 65, 1, 192000, 0x0ce5318f
+0, 66, 66, 1, 192000, 0x14848fa9
+0, 67, 67, 1, 192000, 0x676f83e1
+0, 68, 68, 1, 192000, 0x5b98bea9
+0, 69, 69, 1, 192000, 0xf5cc709d
+0, 70, 70, 1, 192000, 0x719a0373
+0, 71, 71, 1, 192000, 0xba5a3e74
+0, 72, 72, 1, 192000, 0x34e10051
+0, 73, 73, 1, 192000, 0xb66dd42d
+0, 74, 74, 1, 192000, 0xfb58c833
+0, 75, 75, 1, 192000, 0xa28029a4
+0, 76, 76, 1, 192000, 0x28fa09b3
+0, 77, 77, 1, 192000, 0x676f0b08
+0, 78, 78, 1, 192000, 0x7af97965
+0, 79, 79, 1, 192000, 0x436f0f03
+0, 80, 80, 1, 192000, 0xbaca5814
+0, 81, 81, 1, 192000, 0xca97eb51
+0, 82, 82, 1, 192000, 0x1fc89137
+0, 83, 83, 1, 192000, 0x8af63a74
+0, 84, 84, 1, 192000, 0xca015077
+0, 85, 85, 1, 192000, 0x761599ad
+0, 86, 86, 1, 192000, 0x1ca1570c
+0, 87, 87, 1, 192000, 0x1209a3ac
+0, 88, 88, 1, 192000, 0xf7d92d01
+0, 89, 89, 1, 192000, 0x970d6fea
+0, 90, 90, 1, 192000, 0x1ff28298
+0, 91, 91, 1, 192000, 0x1ff28298
+0, 92, 92, 1, 192000, 0x407d09ca
+0, 93, 93, 1, 192000, 0x407d09ca
+0, 94, 94, 1, 192000, 0xc743a475
+0, 95, 95, 1, 192000, 0xc743a475
+0, 96, 96, 1, 192000, 0x46bf9f7d
+0, 97, 97, 1, 192000, 0x46bf9f7d
+0, 98, 98, 1, 192000, 0x57ecb2c1
+0, 99, 99, 1, 192000, 0x57ecb2c1
+0, 100, 100, 1, 192000, 0x680fd3bf
+0, 101, 101, 1, 192000, 0x680fd3bf
+0, 102, 102, 1, 192000, 0x8772ca19
+0, 103, 103, 1, 192000, 0x8772ca19
+0, 104, 104, 1, 192000, 0x3cc29bbf
+0, 105, 105, 1, 192000, 0x3cc29bbf
+0, 106, 106, 1, 192000, 0xe745fb3c
+0, 107, 107, 1, 192000, 0xe745fb3c
+0, 108, 108, 1, 192000, 0xc5279397
+0, 109, 109, 1, 192000, 0xcc902b35
+0, 110, 110, 1, 192000, 0x50a7cf32
+0, 111, 111, 1, 192000, 0x23fd6f51
+0, 112, 112, 1, 192000, 0x14fe9c4d
+0, 113, 113, 1, 192000, 0x703249f9
+0, 114, 114, 1, 192000, 0x47b73bce
+0, 115, 115, 1, 192000, 0x13bce1c9
diff --git a/tests/ref/fate/flic-magiccarpet b/tests/ref/fate/flic-magiccarpet
index f0faf1dd41..23a93427db 100644
--- a/tests/ref/fate/flic-magiccarpet
+++ b/tests/ref/fate/flic-magiccarpet
@@ -1,43 +1,43 @@
#tb 0: 1/14
0, 0, 0, 1, 192000, 0x00000000
-0, 1, 1, 1, 192000, 0x9c057d9c
-0, 2, 2, 1, 192000, 0xab1aacaf
-0, 3, 3, 1, 192000, 0x49a1dccd
-0, 4, 4, 1, 192000, 0xebb7e245
-0, 5, 5, 1, 192000, 0x6287759e
-0, 6, 6, 1, 192000, 0xbf007410
-0, 7, 7, 1, 192000, 0x6c72b247
-0, 8, 8, 1, 192000, 0x4c26a8c3
-0, 9, 9, 1, 192000, 0x99f06050
-0, 10, 10, 1, 192000, 0x663f2d23
-0, 11, 11, 1, 192000, 0x813c3a1f
-0, 12, 12, 1, 192000, 0x6d6cfbe7
-0, 13, 13, 1, 192000, 0x7b04163a
-0, 14, 14, 1, 192000, 0x6792e679
-0, 15, 15, 1, 192000, 0x939ac626
-0, 16, 16, 1, 192000, 0xc7a139c0
-0, 17, 17, 1, 192000, 0xcac7ef0c
-0, 18, 18, 1, 192000, 0xf4ec59e0
-0, 19, 19, 1, 192000, 0x56060f59
-0, 20, 20, 1, 192000, 0xf45ecb3b
-0, 21, 21, 1, 192000, 0xe7e634ff
-0, 22, 22, 1, 192000, 0x7ac04aa4
-0, 23, 23, 1, 192000, 0x4eaba5a1
-0, 24, 24, 1, 192000, 0x89b84e25
-0, 25, 25, 1, 192000, 0xc368ec1e
-0, 26, 26, 1, 192000, 0xeeafb59e
-0, 27, 27, 1, 192000, 0x0b630619
-0, 28, 28, 1, 192000, 0x59cb8954
-0, 29, 29, 1, 192000, 0x16b2875f
-0, 30, 30, 1, 192000, 0x524e32bd
-0, 31, 31, 1, 192000, 0x96000ba2
-0, 32, 32, 1, 192000, 0x18ec28af
-0, 33, 33, 1, 192000, 0x2609c56c
-0, 34, 34, 1, 192000, 0xff25bb5a
-0, 35, 35, 1, 192000, 0xb19a8819
-0, 36, 36, 1, 192000, 0xa5ff8727
-0, 37, 37, 1, 192000, 0xe83f6289
-0, 38, 38, 1, 192000, 0xc6cb4903
-0, 39, 39, 1, 192000, 0xa4d93eb5
-0, 40, 40, 1, 192000, 0xec84ef6c
+0, 1, 1, 1, 192000, 0x03567eeb
+0, 2, 2, 1, 192000, 0xe73db12c
+0, 3, 3, 1, 192000, 0x7cefe740
+0, 4, 4, 1, 192000, 0xb769f827
+0, 5, 5, 1, 192000, 0x71669dea
+0, 6, 6, 1, 192000, 0xc203b934
+0, 7, 7, 1, 192000, 0x30671ee2
+0, 8, 8, 1, 192000, 0xaea33a1b
+0, 9, 9, 1, 192000, 0x50f220c3
+0, 10, 10, 1, 192000, 0x1ddd090f
+0, 11, 11, 1, 192000, 0x17ac22a4
+0, 12, 12, 1, 192000, 0x19f9f412
+0, 13, 13, 1, 192000, 0xa2df0e55
+0, 14, 14, 1, 192000, 0x5abcd663
+0, 15, 15, 1, 192000, 0x5b09b38d
+0, 16, 16, 1, 192000, 0x894d1f43
+0, 17, 17, 1, 192000, 0xbc95caaf
+0, 18, 18, 1, 192000, 0xeaca27fc
+0, 19, 19, 1, 192000, 0x49c5ccb4
+0, 20, 20, 1, 192000, 0x8b3e78b0
+0, 21, 21, 1, 192000, 0x1645d3ae
+0, 22, 22, 1, 192000, 0x4407da0f
+0, 23, 23, 1, 192000, 0x7d0826ac
+0, 24, 24, 1, 192000, 0xc17ec1b8
+0, 25, 25, 1, 192000, 0x4a82520d
+0, 26, 26, 1, 192000, 0xa89f0e2f
+0, 27, 27, 1, 192000, 0xd58b537a
+0, 28, 28, 1, 192000, 0x7123dafe
+0, 29, 29, 1, 192000, 0x15d1d065
+0, 30, 30, 1, 192000, 0xa86873f6
+0, 31, 31, 1, 192000, 0x32704a91
+0, 32, 32, 1, 192000, 0xbf2b63d7
+0, 33, 33, 1, 192000, 0xb98e0126
+0, 34, 34, 1, 192000, 0x412a03ee
+0, 35, 35, 1, 192000, 0x601ad161
+0, 36, 36, 1, 192000, 0x01ead407
+0, 37, 37, 1, 192000, 0x75a7bbe5
+0, 38, 38, 1, 192000, 0x155ea759
+0, 39, 39, 1, 192000, 0xe3a0a6aa
+0, 40, 40, 1, 192000, 0x2b5a5770
0, 41, 41, 1, 192000, 0x00000000
diff --git a/tests/ref/fate/force_key_frames b/tests/ref/fate/force_key_frames
new file mode 100644
index 0000000000..0a41378f64
--- /dev/null
+++ b/tests/ref/fate/force_key_frames
@@ -0,0 +1,4 @@
+07567b9528b8de523faaf49e4e1e0fc6 *tests/data/fate/force_key_frames.avi
+113312 tests/data/fate/force_key_frames.avi
+8f68ad2e602ecd87a3e0c097ba99d773 *tests/data/fate/force_key_frames.out.framecrc
+stddev:34363.01 PSNR: 5.61 MAXDIFF:56305 bytes: 7603200/ 186
diff --git a/tests/ref/fate/fraps-v2 b/tests/ref/fate/fraps-v2
index 1ebfb7c281..06e0024ced 100644
--- a/tests/ref/fate/fraps-v2
+++ b/tests/ref/fate/fraps-v2
@@ -1,11 +1,3 @@
#tb 0: 1/30
0, 0, 0, 1, 1179648, 0x99f80436
-0, 1, 1, 1, 1179648, 0x99f80436
-0, 2, 2, 1, 1179648, 0x99f80436
-0, 3, 3, 1, 1179648, 0x99f80436
-0, 4, 4, 1, 1179648, 0x99f80436
0, 5, 5, 1, 1179648, 0xe8ae7a30
-0, 6, 6, 1, 1179648, 0xe8ae7a30
-0, 7, 7, 1, 1179648, 0xe8ae7a30
-0, 8, 8, 1, 1179648, 0xe8ae7a30
-0, 9, 9, 1, 1179648, 0xe8ae7a30
diff --git a/tests/ref/fate/fraps-v3 b/tests/ref/fate/fraps-v3
index ac8b701767..139ee7e470 100644
--- a/tests/ref/fate/fraps-v3
+++ b/tests/ref/fate/fraps-v3
@@ -3,8 +3,6 @@
0, 1, 1, 1, 589824, 0xcd740f79
0, 2, 2, 1, 589824, 0x16f8f90e
0, 3, 3, 1, 589824, 0x1aaaceba
-0, 4, 4, 1, 589824, 0x1aaaceba
0, 5, 5, 1, 589824, 0x902e8fe4
0, 6, 6, 1, 589824, 0x019a4443
-0, 7, 7, 1, 589824, 0x019a4443
0, 8, 8, 1, 589824, 0x04eff6c6
diff --git a/tests/ref/fate/g729-0 b/tests/ref/fate/g729-0
new file mode 100644
index 0000000000..36c6634fab
--- /dev/null
+++ b/tests/ref/fate/g729-0
@@ -0,0 +1,1000 @@
+0, 0, 160, 0xbb6d5aa0
+0, 900, 160, 0x91563d8d
+0, 1800, 160, 0x10a7535b
+0, 2700, 160, 0xa4f35594
+0, 3600, 160, 0x7f8e54e0
+0, 4500, 160, 0x85275000
+0, 5400, 160, 0x00734c7b
+0, 6300, 160, 0x8a2d544d
+0, 7200, 160, 0x97dc533c
+0, 8100, 160, 0xa7064ec4
+0, 9000, 160, 0xb7984a3c
+0, 9900, 160, 0x28334db6
+0, 10800, 160, 0x5838521f
+0, 11700, 160, 0x2337502c
+0, 12600, 160, 0x4a1e4599
+0, 13500, 160, 0x0d3858a8
+0, 14400, 160, 0xa0974b46
+0, 15300, 160, 0xc3254b93
+0, 16200, 160, 0x42b75231
+0, 17100, 160, 0x93634662
+0, 18000, 160, 0x11674fa1
+0, 18900, 160, 0xf2da5414
+0, 19800, 160, 0x97754dbc
+0, 20700, 160, 0x40a24d94
+0, 21600, 160, 0x26b34ebf
+0, 22500, 160, 0x7730542f
+0, 23400, 160, 0xb45254aa
+0, 24300, 160, 0xd8d752c3
+0, 25200, 160, 0x655c4a81
+0, 26100, 160, 0xa5da4f35
+0, 27000, 160, 0xd43551a1
+0, 27900, 160, 0x72a74e7d
+0, 28800, 160, 0xdb2150b3
+0, 29700, 160, 0x972852a1
+0, 30600, 160, 0xbae14c07
+0, 31500, 160, 0x23b54d57
+0, 32400, 160, 0x2d9650a5
+0, 33300, 160, 0xaf755107
+0, 34200, 160, 0xdb054f0e
+0, 35100, 160, 0x9f084cc0
+0, 36000, 160, 0x64ca5760
+0, 36900, 160, 0x3ea24be2
+0, 37800, 160, 0x93ea503b
+0, 38700, 160, 0xb6694afa
+0, 39600, 160, 0xf94c52e7
+0, 40500, 160, 0x2b7156b8
+0, 41400, 160, 0xbbdf414c
+0, 42300, 160, 0x10cd4ac8
+0, 43200, 160, 0x39885453
+0, 44100, 160, 0xa1505568
+0, 45000, 160, 0x86124ec1
+0, 45900, 160, 0xe2ab5489
+0, 46800, 160, 0x406254bc
+0, 47700, 160, 0x09044629
+0, 48600, 160, 0xb2ed5702
+0, 49500, 160, 0xd9ee5188
+0, 50400, 160, 0x59f7592a
+0, 51300, 160, 0x8f144c08
+0, 52200, 160, 0x90394e61
+0, 53100, 160, 0x79524df7
+0, 54000, 160, 0x58044674
+0, 54900, 160, 0x73b24d90
+0, 55800, 160, 0x80e257a1
+0, 56700, 160, 0xe8ff4caf
+0, 57600, 160, 0x1db84e3e
+0, 58500, 160, 0xd7db59d9
+0, 59400, 160, 0x43244c15
+0, 60300, 160, 0x1f63558f
+0, 61200, 160, 0xf0d851c6
+0, 62100, 160, 0x76484f3a
+0, 63000, 160, 0x5746551e
+0, 63900, 160, 0x83b54cd7
+0, 64800, 160, 0x97f550a1
+0, 65700, 160, 0x77c45340
+0, 66600, 160, 0xfd7b520a
+0, 67500, 160, 0x989a4e13
+0, 68400, 160, 0x9a8551c0
+0, 69300, 160, 0xa0cb4f93
+0, 70200, 160, 0xc568536f
+0, 71100, 160, 0x6fa74a95
+0, 72000, 160, 0xd550568b
+0, 72900, 160, 0xf88f4de5
+0, 73800, 160, 0x91285517
+0, 74700, 160, 0xdb675270
+0, 75600, 160, 0x606c53f9
+0, 76500, 160, 0x43f64601
+0, 77400, 160, 0x28b94b45
+0, 78300, 160, 0x7f2347f5
+0, 79200, 160, 0x84ba55db
+0, 80100, 160, 0x3ca3477c
+0, 81000, 160, 0x57d158ba
+0, 81900, 160, 0x2c3c506d
+0, 82800, 160, 0x59b34e5f
+0, 83700, 160, 0x014f530a
+0, 84600, 160, 0x877f4f76
+0, 85500, 160, 0x97a65c5f
+0, 86400, 160, 0xf643516d
+0, 87300, 160, 0x6ccc5242
+0, 88200, 160, 0x895450bd
+0, 89100, 160, 0xe246570e
+0, 90000, 160, 0xbb9f4a0c
+0, 90900, 160, 0x60e646fe
+0, 91800, 160, 0x546f515b
+0, 92700, 160, 0xc59254f0
+0, 93600, 160, 0xcad6551f
+0, 94500, 160, 0x14e14fac
+0, 95400, 160, 0x3cf94c52
+0, 96300, 160, 0x99b14f45
+0, 97200, 160, 0xfdb14dc7
+0, 98100, 160, 0x48f359e7
+0, 99000, 160, 0x186153e3
+0, 99900, 160, 0x047d4a78
+0, 100800, 160, 0x992f462b
+0, 101700, 160, 0x4a0e504d
+0, 102600, 160, 0x1f245275
+0, 103500, 160, 0x026959a9
+0, 104400, 160, 0x648846e7
+0, 105300, 160, 0xcac94cb3
+0, 106200, 160, 0x55e551a4
+0, 107100, 160, 0x767a5315
+0, 108000, 160, 0xbfde4d2b
+0, 108900, 160, 0x29bf4613
+0, 109800, 160, 0x8a8d5394
+0, 110700, 160, 0x36f94dae
+0, 111600, 160, 0x4cbf50ba
+0, 112500, 160, 0x9af44d8b
+0, 113400, 160, 0x6e8a519e
+0, 114300, 160, 0x496348b7
+0, 115200, 160, 0x95324eb2
+0, 116100, 160, 0x5bfe5118
+0, 117000, 160, 0xa1ff4c88
+0, 117900, 160, 0x86c2500a
+0, 118800, 160, 0xc53353c5
+0, 119700, 160, 0x062f52ee
+0, 120600, 160, 0x11cf522d
+0, 121500, 160, 0x054f5855
+0, 122400, 160, 0x8c4e44e9
+0, 123300, 160, 0x4d514fda
+0, 124200, 160, 0x5726568e
+0, 125100, 160, 0x281859ad
+0, 126000, 160, 0x3f3344f8
+0, 126900, 160, 0x2cbb3ee5
+0, 127800, 160, 0xa075551c
+0, 128700, 160, 0xafb25528
+0, 129600, 160, 0x9221478a
+0, 130500, 160, 0x6cb15634
+0, 131400, 160, 0xb5cf4523
+0, 132300, 160, 0x8a7a4f2c
+0, 133200, 160, 0x278e553d
+0, 134100, 160, 0x49054ad3
+0, 135000, 160, 0x5d7449bb
+0, 135900, 160, 0x67c346a0
+0, 136800, 160, 0x5d915bf8
+0, 137700, 160, 0x671355b2
+0, 138600, 160, 0xdfa84ee6
+0, 139500, 160, 0x4c3552d0
+0, 140400, 160, 0x63a1483c
+0, 141300, 160, 0x14c151ba
+0, 142200, 160, 0xf7434d78
+0, 143100, 160, 0x1c3652c9
+0, 144000, 160, 0x035b51da
+0, 144900, 160, 0x2bf6496b
+0, 145800, 160, 0x50a14f14
+0, 146700, 160, 0x518948f8
+0, 147600, 160, 0x7e784331
+0, 148500, 160, 0x73384dce
+0, 149400, 160, 0x11015066
+0, 150300, 160, 0xacc5525c
+0, 151200, 160, 0xf75a5431
+0, 152100, 160, 0xa78e4b8a
+0, 153000, 160, 0xd07955b0
+0, 153900, 160, 0x63164a03
+0, 154800, 160, 0x952f519e
+0, 155700, 160, 0xe5764f77
+0, 156600, 160, 0xa9255738
+0, 157500, 160, 0x65d64ce5
+0, 158400, 160, 0x8ab7507c
+0, 159300, 160, 0xf5265251
+0, 160200, 160, 0xa6a84d74
+0, 161100, 160, 0xc2594fee
+0, 162000, 160, 0xdfae5056
+0, 162900, 160, 0xa5a74c11
+0, 163800, 160, 0x5fdf4a21
+0, 164700, 160, 0x11014f8d
+0, 165600, 160, 0x08d0553f
+0, 166500, 160, 0x3036520e
+0, 167400, 160, 0xee3a464e
+0, 168300, 160, 0xbfd94949
+0, 169200, 160, 0x21625176
+0, 170100, 160, 0x6c714e8d
+0, 171000, 160, 0x055a4c05
+0, 171900, 160, 0xc7f35347
+0, 172800, 160, 0x82344b60
+0, 173700, 160, 0x99854ce4
+0, 174600, 160, 0x95504ec3
+0, 175500, 160, 0xe245502a
+0, 176400, 160, 0xb0e14a4c
+0, 177300, 160, 0x09835b86
+0, 178200, 160, 0xe9495220
+0, 179100, 160, 0xce9b514f
+0, 180000, 160, 0xbaf85695
+0, 180900, 160, 0x69aa3f1d
+0, 181800, 160, 0xd6a551b8
+0, 182700, 160, 0x4eb956e6
+0, 183600, 160, 0xdd6d4e58
+0, 184500, 160, 0xba1f4814
+0, 185400, 160, 0x4a604f48
+0, 186300, 160, 0xa8995890
+0, 187200, 160, 0x3a80616b
+0, 188100, 160, 0xfb796013
+0, 189000, 160, 0x8eba5c12
+0, 189900, 160, 0xd37859b9
+0, 190800, 160, 0x19a857c8
+0, 191700, 160, 0xec0e5a16
+0, 192600, 160, 0xd5335159
+0, 193500, 160, 0x560f4de7
+0, 194400, 160, 0x06d354c8
+0, 195300, 160, 0xdade5860
+0, 196200, 160, 0x093a512c
+0, 197100, 160, 0xb37b5098
+0, 198000, 160, 0x3eea537c
+0, 198900, 160, 0xf5c94f06
+0, 199800, 160, 0x552c4bb2
+0, 200700, 160, 0xea9a5a79
+0, 201600, 160, 0xd2645494
+0, 202500, 160, 0x5ba958ea
+0, 203400, 160, 0x54b559cf
+0, 204300, 160, 0x86bf5bba
+0, 205200, 160, 0xb89b6149
+0, 206100, 160, 0x1e825314
+0, 207000, 160, 0xf0d250cc
+0, 207900, 160, 0xc7ad53ba
+0, 208800, 160, 0x320c552f
+0, 209700, 160, 0xc62756f7
+0, 210600, 160, 0xa41351f7
+0, 211500, 160, 0x27ed4e78
+0, 212400, 160, 0x8d6047bc
+0, 213300, 160, 0xa45c48d0
+0, 214200, 160, 0x14da5400
+0, 215100, 160, 0x48514dd2
+0, 216000, 160, 0xec395318
+0, 216900, 160, 0xf3c85e4a
+0, 217800, 160, 0x657a63ed
+0, 218700, 160, 0xcc975c4d
+0, 219600, 160, 0x86125dd4
+0, 220500, 160, 0x6a3f6019
+0, 221400, 160, 0x84c05aeb
+0, 222300, 160, 0xe68561f7
+0, 223200, 160, 0x7ec763ae
+0, 224100, 160, 0x91bd5792
+0, 225000, 160, 0xb9365c8e
+0, 225900, 160, 0x42d7587a
+0, 226800, 160, 0x80a45453
+0, 227700, 160, 0x9ecf50c2
+0, 228600, 160, 0xc8de5173
+0, 229500, 160, 0x776952f7
+0, 230400, 160, 0x45f856c0
+0, 231300, 160, 0x729c4d73
+0, 232200, 160, 0xfd364a18
+0, 233100, 160, 0x709e587d
+0, 234000, 160, 0x288240e5
+0, 234900, 160, 0x16a6493f
+0, 235800, 160, 0x76db596f
+0, 236700, 160, 0x16c24a51
+0, 237600, 160, 0xc55b5a8f
+0, 238500, 160, 0x19024a2e
+0, 239400, 160, 0x16514d1b
+0, 240300, 160, 0x48bb5b82
+0, 241200, 160, 0x5a6e4d80
+0, 242100, 160, 0x6d404b0f
+0, 243000, 160, 0x57bc4e4a
+0, 243900, 160, 0xc10c5381
+0, 244800, 160, 0x34bd51d9
+0, 245700, 160, 0x5dcf52b7
+0, 246600, 160, 0xf61f57a7
+0, 247500, 160, 0x4e204934
+0, 248400, 160, 0xe18b4a3f
+0, 249300, 160, 0xb81256e3
+0, 250200, 160, 0x294047b2
+0, 251100, 160, 0x3ad559df
+0, 252000, 160, 0xd28d4d86
+0, 252900, 160, 0x67b75895
+0, 253800, 160, 0x191357b0
+0, 254700, 160, 0x8016556f
+0, 255600, 160, 0x62475c86
+0, 256500, 160, 0x0c975bc9
+0, 257400, 160, 0x901c5909
+0, 258300, 160, 0x9909567d
+0, 259200, 160, 0xce715b99
+0, 260100, 160, 0xae5062b1
+0, 261000, 160, 0x5bd056d6
+0, 261900, 160, 0xe3d3555a
+0, 262800, 160, 0xc4b1555c
+0, 263700, 160, 0x39c95649
+0, 264600, 160, 0x50145d11
+0, 265500, 160, 0xc0ba5307
+0, 266400, 160, 0x182455a3
+0, 267300, 160, 0x36c24e98
+0, 268200, 160, 0x1b5b52d0
+0, 269100, 160, 0xd38352d1
+0, 270000, 160, 0x6a1d5d2a
+0, 270900, 160, 0x50f05c44
+0, 271800, 160, 0xb2365dc1
+0, 272700, 160, 0x10825934
+0, 273600, 160, 0xcb4c61c2
+0, 274500, 160, 0x578252ab
+0, 275400, 160, 0xed99596c
+0, 276300, 160, 0xdfec6305
+0, 277200, 160, 0x97e2550a
+0, 278100, 160, 0xd60a56e1
+0, 279000, 160, 0xb6c4535e
+0, 279900, 160, 0x4d2e536c
+0, 280800, 160, 0xdef85cc7
+0, 281700, 160, 0xee985a98
+0, 282600, 160, 0x006a4cdb
+0, 283500, 160, 0xd06652ad
+0, 284400, 160, 0xeeee4ed6
+0, 285300, 160, 0xcb8b586d
+0, 286200, 160, 0x2ee4556e
+0, 287100, 160, 0x6d924c01
+0, 288000, 160, 0x7ff257cc
+0, 288900, 160, 0x67df5710
+0, 289800, 160, 0x0f704f29
+0, 290700, 160, 0x19dc53a7
+0, 291600, 160, 0xfbf44bc0
+0, 292500, 160, 0x640b5718
+0, 293400, 160, 0x2bfd4b91
+0, 294300, 160, 0xaae049bf
+0, 295200, 160, 0xca3154f6
+0, 296100, 160, 0x36064f2c
+0, 297000, 160, 0x28404919
+0, 297900, 160, 0x9c944fe3
+0, 298800, 160, 0xb4214c82
+0, 299700, 160, 0x442c514d
+0, 300600, 160, 0x44434ea5
+0, 301500, 160, 0x82a05aae
+0, 302400, 160, 0x4b86510d
+0, 303300, 160, 0x46844eab
+0, 304200, 160, 0xe5455deb
+0, 305100, 160, 0x60826550
+0, 306000, 160, 0x3c5a5448
+0, 306900, 160, 0x2db860c9
+0, 307800, 160, 0x4d845b78
+0, 308700, 160, 0x81dc5e23
+0, 309600, 160, 0x78c95932
+0, 310500, 160, 0xb5be57cd
+0, 311400, 160, 0x6fa45c65
+0, 312300, 160, 0x4e085e2a
+0, 313200, 160, 0x50ee530c
+0, 314100, 160, 0x2bb85587
+0, 315000, 160, 0x6d58614e
+0, 315900, 160, 0xcf4c5d69
+0, 316800, 160, 0x3cbf5ffb
+0, 317700, 160, 0x452157d3
+0, 318600, 160, 0x3cb55cd8
+0, 319500, 160, 0x2bba5735
+0, 320400, 160, 0x36a45670
+0, 321300, 160, 0x23b85b8a
+0, 322200, 160, 0x9a255457
+0, 323100, 160, 0x4e6956f3
+0, 324000, 160, 0xa0714edc
+0, 324900, 160, 0x7dee4a3d
+0, 325800, 160, 0x86404bc9
+0, 326700, 160, 0x358c50cd
+0, 327600, 160, 0x9eda47e8
+0, 328500, 160, 0x3cfe522e
+0, 329400, 160, 0xddb95758
+0, 330300, 160, 0x1a434a83
+0, 331200, 160, 0xa8a450bb
+0, 332100, 160, 0x44e7530e
+0, 333000, 160, 0x59b5555a
+0, 333900, 160, 0x65404db1
+0, 334800, 160, 0xcac15945
+0, 335700, 160, 0x38864f17
+0, 336600, 160, 0x61114f30
+0, 337500, 160, 0x195542d8
+0, 338400, 160, 0xacbb4c69
+0, 339300, 160, 0xd0da4ab9
+0, 340200, 160, 0x563d4eb6
+0, 341100, 160, 0xd0ce503c
+0, 342000, 160, 0x8b684e15
+0, 342900, 160, 0x711541d3
+0, 343800, 160, 0xb28b5b9b
+0, 344700, 160, 0x48b145e4
+0, 345600, 160, 0x908f5606
+0, 346500, 160, 0x22c74f02
+0, 347400, 160, 0x87274716
+0, 348300, 160, 0xaa2351e6
+0, 349200, 160, 0x2df5505a
+0, 350100, 160, 0x7999525c
+0, 351000, 160, 0x728a4b73
+0, 351900, 160, 0xa67447ff
+0, 352800, 160, 0x28884a20
+0, 353700, 160, 0x3ffa5840
+0, 354600, 160, 0xd6265047
+0, 355500, 160, 0x2f1553a8
+0, 356400, 160, 0xac0653ec
+0, 357300, 160, 0x35844368
+0, 358200, 160, 0x6e1553ba
+0, 359100, 160, 0xb62a4c88
+0, 360000, 160, 0x88a04ffc
+0, 360900, 160, 0x947e525e
+0, 361800, 160, 0x3dd24f98
+0, 362700, 160, 0x942e542e
+0, 363600, 160, 0xdb985211
+0, 364500, 160, 0x615a5022
+0, 365400, 160, 0x71c04569
+0, 366300, 160, 0xbbbe4f41
+0, 367200, 160, 0x62074e0b
+0, 368100, 160, 0x2c5d56c7
+0, 369000, 160, 0x34344c18
+0, 369900, 160, 0xc57d4c22
+0, 370800, 160, 0xb273560d
+0, 371700, 160, 0x7e985229
+0, 372600, 160, 0x2dd3542d
+0, 373500, 160, 0x39645000
+0, 374400, 160, 0x1b3f4d9e
+0, 375300, 160, 0x0bbf5ed2
+0, 376200, 160, 0xc81f5608
+0, 377100, 160, 0xe82e569e
+0, 378000, 160, 0x34df537d
+0, 378900, 160, 0x53175837
+0, 379800, 160, 0xbb76517f
+0, 380700, 160, 0xd5a25737
+0, 381600, 160, 0x58eb4f3d
+0, 382500, 160, 0x8f6e51d3
+0, 383400, 160, 0x1fd85602
+0, 384300, 160, 0xef2a4ee7
+0, 385200, 160, 0x0e6e58f4
+0, 386100, 160, 0x80345497
+0, 387000, 160, 0x710150a1
+0, 387900, 160, 0x32fb51db
+0, 388800, 160, 0x7efd564c
+0, 389700, 160, 0xf6604f26
+0, 390600, 160, 0xc0954d7e
+0, 391500, 160, 0x27705072
+0, 392400, 160, 0xd26f5958
+0, 393300, 160, 0x2c2552cd
+0, 394200, 160, 0xd14056b1
+0, 395100, 160, 0x11f356d2
+0, 396000, 160, 0x93b35efd
+0, 396900, 160, 0xa6d65ae7
+0, 397800, 160, 0x95015177
+0, 398700, 160, 0x2e6157e8
+0, 399600, 160, 0xb90c5021
+0, 400500, 160, 0xf39155c9
+0, 401400, 160, 0xd6ad544b
+0, 402300, 160, 0x4b8a5b98
+0, 403200, 160, 0x90a94f2d
+0, 404100, 160, 0x46a04f3f
+0, 405000, 160, 0x542b5cd1
+0, 405900, 160, 0xebaa5710
+0, 406800, 160, 0x504854a0
+0, 407700, 160, 0xbd9d53b5
+0, 408600, 160, 0x91524fed
+0, 409500, 160, 0x9b7a582d
+0, 410400, 160, 0xa4f258cf
+0, 411300, 160, 0x46274dda
+0, 412200, 160, 0xc0335ba9
+0, 413100, 160, 0xe59c5c74
+0, 414000, 160, 0xc2ee5ab0
+0, 414900, 160, 0x3e035996
+0, 415800, 160, 0x63e25521
+0, 416700, 160, 0xc09851af
+0, 417600, 160, 0xb8225715
+0, 418500, 160, 0x74355bfb
+0, 419400, 160, 0xf4c75adf
+0, 420300, 160, 0x2f8b56cd
+0, 421200, 160, 0xb4705795
+0, 422100, 160, 0xb4b25506
+0, 423000, 160, 0xaadb54f8
+0, 423900, 160, 0xe6d158aa
+0, 424800, 160, 0xed64614f
+0, 425700, 160, 0x80195732
+0, 426600, 160, 0xa8995f0e
+0, 427500, 160, 0xdc4a520d
+0, 428400, 160, 0x071a5bae
+0, 429300, 160, 0xce1b5ae9
+0, 430200, 160, 0x85e25804
+0, 431100, 160, 0x435e555f
+0, 432000, 160, 0xe4154ef4
+0, 432900, 160, 0xeff857b4
+0, 433800, 160, 0xc9e25868
+0, 434700, 160, 0x6e6961eb
+0, 435600, 160, 0x361e45e6
+0, 436500, 160, 0xf8a94988
+0, 437400, 160, 0x9de758b3
+0, 438300, 160, 0x2e65533e
+0, 439200, 160, 0x3f89422d
+0, 440100, 160, 0x77fd56a5
+0, 441000, 160, 0x91104845
+0, 441900, 160, 0x2eeb5491
+0, 442800, 160, 0x6a5348c4
+0, 443700, 160, 0xe0954882
+0, 444600, 160, 0x7e915761
+0, 445500, 160, 0x2cb5531f
+0, 446400, 160, 0xe1dc4ecd
+0, 447300, 160, 0xbf6b4e61
+0, 448200, 160, 0x3d6b5746
+0, 449100, 160, 0xe8bd5077
+0, 450000, 160, 0xd38d5921
+0, 450900, 160, 0xfc534e38
+0, 451800, 160, 0xd361475b
+0, 452700, 160, 0x4d5152c7
+0, 453600, 160, 0xb6684d11
+0, 454500, 160, 0xd2e25864
+0, 455400, 160, 0x02ec536a
+0, 456300, 160, 0x27ac550e
+0, 457200, 160, 0xe8d44e2d
+0, 458100, 160, 0x520152c8
+0, 459000, 160, 0xace747ea
+0, 459900, 160, 0x773a4ee3
+0, 460800, 160, 0x7dd1559f
+0, 461700, 160, 0x124453a8
+0, 462600, 160, 0x04154991
+0, 463500, 160, 0x3c794d98
+0, 464400, 160, 0x309f4e47
+0, 465300, 160, 0x98c74a48
+0, 466200, 160, 0xd0c34bcc
+0, 467100, 160, 0xfa304e19
+0, 468000, 160, 0x69505201
+0, 468900, 160, 0x2e714ac7
+0, 469800, 160, 0x076654a3
+0, 470700, 160, 0xc6674e27
+0, 471600, 160, 0x1adf4dd9
+0, 472500, 160, 0x4408507e
+0, 473400, 160, 0xd2654d94
+0, 474300, 160, 0x97a65cc0
+0, 475200, 160, 0xb53251f9
+0, 476100, 160, 0xd498584b
+0, 477000, 160, 0x46a058c8
+0, 477900, 160, 0xa2f85cbd
+0, 478800, 160, 0x43b856fb
+0, 479700, 160, 0xdeb957ba
+0, 480600, 160, 0x3064580a
+0, 481500, 160, 0xe86357a5
+0, 482400, 160, 0x9b974d00
+0, 483300, 160, 0x66ee4ff3
+0, 484200, 160, 0x0b9958f7
+0, 485100, 160, 0xc3754d0a
+0, 486000, 160, 0x42314c33
+0, 486900, 160, 0x4550555f
+0, 487800, 160, 0x0f064e4c
+0, 488700, 160, 0xe569596d
+0, 489600, 160, 0x056c4751
+0, 490500, 160, 0xdc1049fc
+0, 491400, 160, 0x63c54a1e
+0, 492300, 160, 0xb402518e
+0, 493200, 160, 0xaf0d4b19
+0, 494100, 160, 0xa22b4c5b
+0, 495000, 160, 0x28084bbf
+0, 495900, 160, 0x10495224
+0, 496800, 160, 0x4cb94993
+0, 497700, 160, 0x17c15457
+0, 498600, 160, 0xbd834d6d
+0, 499500, 160, 0x6ca25235
+0, 500400, 160, 0x84b74f89
+0, 501300, 160, 0xdeef4e76
+0, 502200, 160, 0x6ab05188
+0, 503100, 160, 0xa91c4646
+0, 504000, 160, 0xad574e7d
+0, 504900, 160, 0xba264d69
+0, 505800, 160, 0xd8734dd0
+0, 506700, 160, 0x69f25581
+0, 507600, 160, 0x3b8e4ae9
+0, 508500, 160, 0xb1124607
+0, 509400, 160, 0xd78e4e4f
+0, 510300, 160, 0x05a1504f
+0, 511200, 160, 0x3e705270
+0, 512100, 160, 0x1e144b3b
+0, 513000, 160, 0xbb0b5416
+0, 513900, 160, 0xc26f5b45
+0, 514800, 160, 0x14224ab9
+0, 515700, 160, 0x2bbd4837
+0, 516600, 160, 0xd2bf4e60
+0, 517500, 160, 0xbeec506c
+0, 518400, 160, 0x2cd34d3a
+0, 519300, 160, 0x85134fc6
+0, 520200, 160, 0xdb9a4ac2
+0, 521100, 160, 0x92715256
+0, 522000, 160, 0xff395098
+0, 522900, 160, 0xa5ec560c
+0, 523800, 160, 0xce95534b
+0, 524700, 160, 0xe36f46f1
+0, 525600, 160, 0x45f74a58
+0, 526500, 160, 0x02d05440
+0, 527400, 160, 0xa005529f
+0, 528300, 160, 0xae0f3f22
+0, 529200, 160, 0x3f984eb0
+0, 530100, 160, 0xc5bd5015
+0, 531000, 160, 0xf4504c53
+0, 531900, 160, 0x7f4044c5
+0, 532800, 160, 0x82dd4bab
+0, 533700, 160, 0x7a0d5122
+0, 534600, 160, 0xd0da5271
+0, 535500, 160, 0x67d14e3e
+0, 536400, 160, 0x54564f42
+0, 537300, 160, 0x77df4e0a
+0, 538200, 160, 0x0c4a4f70
+0, 539100, 160, 0xb2944f40
+0, 540000, 160, 0xe57a52de
+0, 540900, 160, 0x7d994ed1
+0, 541800, 160, 0x9dc35763
+0, 542700, 160, 0x8d0a4da9
+0, 543600, 160, 0x0c6449a4
+0, 544500, 160, 0xc73c503a
+0, 545400, 160, 0x52904cbe
+0, 546300, 160, 0x49824c2e
+0, 547200, 160, 0xb7e14e0b
+0, 548100, 160, 0x9745548e
+0, 549000, 160, 0xdafb4c20
+0, 549900, 160, 0x1aa84d67
+0, 550800, 160, 0x64bc5033
+0, 551700, 160, 0x9e2e5a05
+0, 552600, 160, 0x69144bc5
+0, 553500, 160, 0xce1253fa
+0, 554400, 160, 0x359f4c15
+0, 555300, 160, 0xdba74ed0
+0, 556200, 160, 0xea1453b8
+0, 557100, 160, 0xccdf49d3
+0, 558000, 160, 0xeb324750
+0, 558900, 160, 0x62b14ad4
+0, 559800, 160, 0x446e50c0
+0, 560700, 160, 0x111e5151
+0, 561600, 160, 0x6be84f3a
+0, 562500, 160, 0xf5cf4e42
+0, 563400, 160, 0xcc995459
+0, 564300, 160, 0x0faf5172
+0, 565200, 160, 0x31334f66
+0, 566100, 160, 0x20ba52c0
+0, 567000, 160, 0xc7cc4975
+0, 567900, 160, 0x9e7a51ba
+0, 568800, 160, 0x52884ff1
+0, 569700, 160, 0xc7a84cfd
+0, 570600, 160, 0x5ae64c22
+0, 571500, 160, 0x68125a92
+0, 572400, 160, 0x39ed54f1
+0, 573300, 160, 0xfa0a4ad1
+0, 574200, 160, 0xe8c8590c
+0, 575100, 160, 0x5f555576
+0, 576000, 160, 0xaf7a57a1
+0, 576900, 160, 0x858257e9
+0, 577800, 160, 0x1223523e
+0, 578700, 160, 0x446954a1
+0, 579600, 160, 0xfbe952d9
+0, 580500, 160, 0xd56259ff
+0, 581400, 160, 0xc4fa4f44
+0, 582300, 160, 0x77cc57f6
+0, 583200, 160, 0x53d3573d
+0, 584100, 160, 0x085e4ff9
+0, 585000, 160, 0x7a4e5410
+0, 585900, 160, 0xb4ad5794
+0, 586800, 160, 0x71255738
+0, 587700, 160, 0x36724918
+0, 588600, 160, 0x370e5974
+0, 589500, 160, 0xb709596c
+0, 590400, 160, 0x89b05052
+0, 591300, 160, 0x74e550ce
+0, 592200, 160, 0x6e2c5a49
+0, 593100, 160, 0x4dfa5b50
+0, 594000, 160, 0x80764c70
+0, 594900, 160, 0xc1d14fc6
+0, 595800, 160, 0x53e746b3
+0, 596700, 160, 0x728350c0
+0, 597600, 160, 0x9aa6500e
+0, 598500, 160, 0x60985454
+0, 599400, 160, 0xa0c54b6f
+0, 600300, 160, 0xe3b157ea
+0, 601200, 160, 0xce86573b
+0, 602100, 160, 0x9dad5535
+0, 603000, 160, 0xb3094af9
+0, 603900, 160, 0x2d1456ed
+0, 604800, 160, 0x328248b9
+0, 605700, 160, 0x4ffb4f52
+0, 606600, 160, 0x71fe53de
+0, 607500, 160, 0x0d114e92
+0, 608400, 160, 0x37065510
+0, 609300, 160, 0x426c4c07
+0, 610200, 160, 0x58e3528b
+0, 611100, 160, 0x71674484
+0, 612000, 160, 0x45934ee1
+0, 612900, 160, 0x4e914b31
+0, 613800, 160, 0x525b4ec2
+0, 614700, 160, 0x4393563d
+0, 615600, 160, 0xb10154e9
+0, 616500, 160, 0x23b15a4d
+0, 617400, 160, 0x6d995220
+0, 618300, 160, 0xcd2949fd
+0, 619200, 160, 0x67234f75
+0, 620100, 160, 0x00cc4cdb
+0, 621000, 160, 0x97c35574
+0, 621900, 160, 0xc0855753
+0, 622800, 160, 0xf4e650a5
+0, 623700, 160, 0x95b14bc2
+0, 624600, 160, 0x04d948dc
+0, 625500, 160, 0x284d4d02
+0, 626400, 160, 0xfb0d4cd9
+0, 627300, 160, 0x0e515126
+0, 628200, 160, 0xb4055a86
+0, 629100, 160, 0x0bbe4f68
+0, 630000, 160, 0xf1b848af
+0, 630900, 160, 0x7d154853
+0, 631800, 160, 0x78225418
+0, 632700, 160, 0xfb2f523e
+0, 633600, 160, 0xa6d34ea6
+0, 634500, 160, 0xe4264e30
+0, 635400, 160, 0x113750aa
+0, 636300, 160, 0x4073529b
+0, 637200, 160, 0xd1754dda
+0, 638100, 160, 0x1b495413
+0, 639000, 160, 0x29f94cd8
+0, 639900, 160, 0x49004a53
+0, 640800, 160, 0x1fec4de4
+0, 641700, 160, 0x7d6b4670
+0, 642600, 160, 0x626c4c9f
+0, 643500, 160, 0x79265234
+0, 644400, 160, 0xab765b86
+0, 645300, 160, 0xe9ae4d26
+0, 646200, 160, 0xeee1481f
+0, 647100, 160, 0x289d5287
+0, 648000, 160, 0xb5524e8b
+0, 648900, 160, 0x7e715764
+0, 649800, 160, 0xb1b25091
+0, 650700, 160, 0xf1a946f6
+0, 651600, 160, 0x57dc51bd
+0, 652500, 160, 0x4c0b4f14
+0, 653400, 160, 0xdc1f4930
+0, 654300, 160, 0x79d75057
+0, 655200, 160, 0x22bd52df
+0, 656100, 160, 0x963a5562
+0, 657000, 160, 0x7e475303
+0, 657900, 160, 0x2c065494
+0, 658800, 160, 0xb0514720
+0, 659700, 160, 0xbc734849
+0, 660600, 160, 0xf4924e4d
+0, 661500, 160, 0xe50f44c9
+0, 662400, 160, 0x978c4ce8
+0, 663300, 160, 0x302e51c2
+0, 664200, 160, 0x262b4a60
+0, 665100, 160, 0xf95f4e99
+0, 666000, 160, 0x7465504a
+0, 666900, 160, 0xab0e5108
+0, 667800, 160, 0xbec15395
+0, 668700, 160, 0x4f2c5139
+0, 669600, 160, 0x26444deb
+0, 670500, 160, 0xee4c4b15
+0, 671400, 160, 0x8bc350e1
+0, 672300, 160, 0xd0744a5a
+0, 673200, 160, 0xfee64d9d
+0, 674100, 160, 0x234c50b6
+0, 675000, 160, 0x8592482c
+0, 675900, 160, 0x5e8b5308
+0, 676800, 160, 0x4f9848c7
+0, 677700, 160, 0x939d4faa
+0, 678600, 160, 0x797654f1
+0, 679500, 160, 0x15d24d9b
+0, 680400, 160, 0xa6e54bd2
+0, 681300, 160, 0x755e4c90
+0, 682200, 160, 0xcd334bce
+0, 683100, 160, 0xfc1746e9
+0, 684000, 160, 0x81f04dd5
+0, 684900, 160, 0x44b35080
+0, 685800, 160, 0x91e65217
+0, 686700, 160, 0x492150af
+0, 687600, 160, 0xf73e58ec
+0, 688500, 160, 0xf988538a
+0, 689400, 160, 0x0dee4c10
+0, 690300, 160, 0x2c9f4c23
+0, 691200, 160, 0x8c1e4e08
+0, 692100, 160, 0x25bb5286
+0, 693000, 160, 0xd0ed469b
+0, 693900, 160, 0x71eb50e8
+0, 694800, 160, 0x249f4d26
+0, 695700, 160, 0x9662498f
+0, 696600, 160, 0x49ee55e2
+0, 697500, 160, 0x54d9491b
+0, 698400, 160, 0x4c675649
+0, 699300, 160, 0x0e4b4b34
+0, 700200, 160, 0x776f4995
+0, 701100, 160, 0x722656b2
+0, 702000, 160, 0x081d4b6f
+0, 702900, 160, 0xf70746fe
+0, 703800, 160, 0x08b151da
+0, 704700, 160, 0x6b255328
+0, 705600, 160, 0xeb2b586a
+0, 706500, 160, 0x812b4444
+0, 707400, 160, 0x1e16533f
+0, 708300, 160, 0xc1244760
+0, 709200, 160, 0x67584d87
+0, 710100, 160, 0xde8b5726
+0, 711000, 160, 0xe96d4e3e
+0, 711900, 160, 0x41174c98
+0, 712800, 160, 0x4cdd4cd8
+0, 713700, 160, 0xfb724b64
+0, 714600, 160, 0x78f154df
+0, 715500, 160, 0x97e1476d
+0, 716400, 160, 0x6f034e7f
+0, 717300, 160, 0x93b240df
+0, 718200, 160, 0xc4d040e6
+0, 719100, 160, 0xe47744a4
+0, 720000, 160, 0x87a950ff
+0, 720900, 160, 0x7079491b
+0, 721800, 160, 0x89f0491a
+0, 722700, 160, 0x70b8467e
+0, 723600, 160, 0x20945294
+0, 724500, 160, 0x2d5c4919
+0, 725400, 160, 0x1ed44c78
+0, 726300, 160, 0x93d74a5f
+0, 727200, 160, 0x300e490e
+0, 728100, 160, 0x8249558d
+0, 729000, 160, 0x630a4f57
+0, 729900, 160, 0xdd6e475f
+0, 730800, 160, 0xf50941e5
+0, 731700, 160, 0x1fe44bea
+0, 732600, 160, 0x03be5469
+0, 733500, 160, 0x7ece4f4c
+0, 734400, 160, 0x31f953dd
+0, 735300, 160, 0x22a44b7d
+0, 736200, 160, 0x1f5e5562
+0, 737100, 160, 0x771b5688
+0, 738000, 160, 0x7d1c4d45
+0, 738900, 160, 0x6bc45cd0
+0, 739800, 160, 0x8f714c36
+0, 740700, 160, 0xfb1f4c87
+0, 741600, 160, 0x1f8a4b36
+0, 742500, 160, 0xee5c451a
+0, 743400, 160, 0xd56950ac
+0, 744300, 160, 0x529057f6
+0, 745200, 160, 0x336641fd
+0, 746100, 160, 0xa0dd5a66
+0, 747000, 160, 0x5f4b5248
+0, 747900, 160, 0xb6ef49a3
+0, 748800, 160, 0x07705f19
+0, 749700, 160, 0x3fce4bbb
+0, 750600, 160, 0xda395511
+0, 751500, 160, 0x1ecf5145
+0, 752400, 160, 0x88a547ab
+0, 753300, 160, 0x6c6849be
+0, 754200, 160, 0x979c4e97
+0, 755100, 160, 0x171854b3
+0, 756000, 160, 0x9a715283
+0, 756900, 160, 0x064e50ac
+0, 757800, 160, 0xc2fb4e94
+0, 758700, 160, 0x708146f5
+0, 759600, 160, 0x1ca45198
+0, 760500, 160, 0x332d4869
+0, 761400, 160, 0xc2ff4656
+0, 762300, 160, 0x0747552e
+0, 763200, 160, 0x0c3d4ba8
+0, 764100, 160, 0x72934dab
+0, 765000, 160, 0xbb1e5860
+0, 765900, 160, 0x526d4cea
+0, 766800, 160, 0xa4c445d6
+0, 767700, 160, 0x70cd49ba
+0, 768600, 160, 0x008c53a7
+0, 769500, 160, 0xf7174bca
+0, 770400, 160, 0x0bab4936
+0, 771300, 160, 0x59e5564d
+0, 772200, 160, 0x33045087
+0, 773100, 160, 0xde7454f0
+0, 774000, 160, 0x31184cc3
+0, 774900, 160, 0x37984bb3
+0, 775800, 160, 0xf5e052d4
+0, 776700, 160, 0x23ca4b42
+0, 777600, 160, 0xbe2a572b
+0, 778500, 160, 0x9a91538d
+0, 779400, 160, 0x8a994c40
+0, 780300, 160, 0x5dea51ee
+0, 781200, 160, 0x1b53524c
+0, 782100, 160, 0xd9e75227
+0, 783000, 160, 0x58384c3b
+0, 783900, 160, 0x4a1b53b2
+0, 784800, 160, 0xc2a3458a
+0, 785700, 160, 0x7f68502d
+0, 786600, 160, 0x85475559
+0, 787500, 160, 0xd0d25472
+0, 788400, 160, 0x4c0d4bbf
+0, 789300, 160, 0xcad352df
+0, 790200, 160, 0x17904c97
+0, 791100, 160, 0x4e774b8e
+0, 792000, 160, 0x21905952
+0, 792900, 160, 0xc2d950cd
+0, 793800, 160, 0xfdea55e6
+0, 794700, 160, 0x22ca4e37
+0, 795600, 160, 0x1143562a
+0, 796500, 160, 0xe83c583e
+0, 797400, 160, 0xba544b27
+0, 798300, 160, 0x1e8c50e4
+0, 799200, 160, 0xf7ca4d2a
+0, 800100, 160, 0x67764579
+0, 801000, 160, 0x40d74f42
+0, 801900, 160, 0x88e35360
+0, 802800, 160, 0xda3f4f5b
+0, 803700, 160, 0x19c1522f
+0, 804600, 160, 0x93ce4f78
+0, 805500, 160, 0xf65447ba
+0, 806400, 160, 0xc0bc4e5a
+0, 807300, 160, 0x4915572b
+0, 808200, 160, 0x1651460b
+0, 809100, 160, 0xffe552a5
+0, 810000, 160, 0x5bd351ab
+0, 810900, 160, 0xbbd85034
+0, 811800, 160, 0xb9ff505f
+0, 812700, 160, 0xfc104eaf
+0, 813600, 160, 0xdaa74d6c
+0, 814500, 160, 0x34b04d78
+0, 815400, 160, 0x1e924f70
+0, 816300, 160, 0x0d46512d
+0, 817200, 160, 0x0d115950
+0, 818100, 160, 0x62de55a4
+0, 819000, 160, 0x58d652ab
+0, 819900, 160, 0x1776584e
+0, 820800, 160, 0x60175a2b
+0, 821700, 160, 0x4d714c82
+0, 822600, 160, 0xe13c4ce0
+0, 823500, 160, 0x7cd15464
+0, 824400, 160, 0x6c87571a
+0, 825300, 160, 0x1abe4f07
+0, 826200, 160, 0x039d5661
+0, 827100, 160, 0x0eba5909
+0, 828000, 160, 0xa46e51ec
+0, 828900, 160, 0x9be44eb7
+0, 829800, 160, 0xe0634aad
+0, 830700, 160, 0xcd53530b
+0, 831600, 160, 0x12cd482c
+0, 832500, 160, 0x71884634
+0, 833400, 160, 0xd5845743
+0, 834300, 160, 0xacd1502c
+0, 835200, 160, 0x04795031
+0, 836100, 160, 0xf0df54b9
+0, 837000, 160, 0x43aa5155
+0, 837900, 160, 0x316a4988
+0, 838800, 160, 0xfbc64f8a
+0, 839700, 160, 0xda084e8e
+0, 840600, 160, 0x3cc34ce2
+0, 841500, 160, 0xbfc055d8
+0, 842400, 160, 0x20ef4876
+0, 843300, 160, 0x035a5660
+0, 844200, 160, 0xbc7255be
+0, 845100, 160, 0xba514f44
+0, 846000, 160, 0x868c4c9c
+0, 846900, 160, 0x83494f04
+0, 847800, 160, 0xa452521a
+0, 848700, 160, 0x2ed04f65
+0, 849600, 160, 0x2e3e592d
+0, 850500, 160, 0x82bc4763
+0, 851400, 160, 0x339950db
+0, 852300, 160, 0x5bb64eff
+0, 853200, 160, 0x347c4d85
+0, 854100, 160, 0x25e949a3
+0, 855000, 160, 0xbdf649a8
+0, 855900, 160, 0x498650f3
+0, 856800, 160, 0x2a6f4e60
+0, 857700, 160, 0x661e5697
+0, 858600, 160, 0x5d6150ca
+0, 859500, 160, 0xe7c74b8f
+0, 860400, 160, 0x1ae148da
+0, 861300, 160, 0xaeef485d
+0, 862200, 160, 0x105650c6
+0, 863100, 160, 0xc1c45376
+0, 864000, 160, 0x83c55011
+0, 864900, 160, 0x77025597
+0, 865800, 160, 0x324250b7
+0, 866700, 160, 0x5cdc570f
+0, 867600, 160, 0x292e52a1
+0, 868500, 160, 0x8d7a5090
+0, 869400, 160, 0x32fc54e4
+0, 870300, 160, 0x50984e8b
+0, 871200, 160, 0x07f442a0
+0, 872100, 160, 0xc91c4fc3
+0, 873000, 160, 0x06cf53d7
+0, 873900, 160, 0xa66c5923
+0, 874800, 160, 0xc2015120
+0, 875700, 160, 0xedfa50c4
+0, 876600, 160, 0xe4c85fb5
+0, 877500, 160, 0xcd7b4c65
+0, 878400, 160, 0xb22353c1
+0, 879300, 160, 0x298c5996
+0, 880200, 160, 0xefce51db
+0, 881100, 160, 0x6df74ee3
+0, 882000, 160, 0x7c46496b
+0, 882900, 160, 0x910a48a4
+0, 883800, 160, 0xbf504b1e
+0, 884700, 160, 0x096947e8
+0, 885600, 160, 0x4a07629d
+0, 886500, 160, 0x577b43c1
+0, 887400, 160, 0x939e4d6d
+0, 888300, 160, 0x486e48ac
+0, 889200, 160, 0x50064871
+0, 890100, 160, 0x4a255534
+0, 891000, 160, 0xc80d4618
+0, 891900, 160, 0xf18a4780
+0, 892800, 160, 0x1c274dd4
+0, 893700, 160, 0x2f3e4f7c
+0, 894600, 160, 0x44b24cc2
+0, 895500, 160, 0x89b451f4
+0, 896400, 160, 0x06515b65
+0, 897300, 160, 0xc5b857ce
+0, 898200, 160, 0xa47b47a7
+0, 899100, 160, 0xfb375448
diff --git a/tests/ref/fate/g729-1 b/tests/ref/fate/g729-1
new file mode 100644
index 0000000000..6bf05c5efd
--- /dev/null
+++ b/tests/ref/fate/g729-1
@@ -0,0 +1,1000 @@
+0, 0, 160, 0xf7e550f0
+0, 900, 160, 0x42794ea8
+0, 1800, 160, 0xfe023e42
+0, 2700, 160, 0xc1ae40e3
+0, 3600, 160, 0xee6d4bf1
+0, 4500, 160, 0x107451d7
+0, 5400, 160, 0x40cb4ba4
+0, 6300, 160, 0x90504e5e
+0, 7200, 160, 0xf6f3531d
+0, 8100, 160, 0x48664ea0
+0, 9000, 160, 0xa30458e1
+0, 9900, 160, 0x00b74aa2
+0, 10800, 160, 0x95234e49
+0, 11700, 160, 0x9cf24a94
+0, 12600, 160, 0x4f2952f4
+0, 13500, 160, 0x658353db
+0, 14400, 160, 0x98ef4d79
+0, 15300, 160, 0x765d5472
+0, 16200, 160, 0xc6e25262
+0, 17100, 160, 0x33334993
+0, 18000, 160, 0xfa104dc5
+0, 18900, 160, 0x03ee5530
+0, 19800, 160, 0x52c54e0e
+0, 20700, 160, 0xbd744638
+0, 21600, 160, 0x7775519f
+0, 22500, 160, 0xd22f499e
+0, 23400, 160, 0x26af4eec
+0, 24300, 160, 0x37474ed9
+0, 25200, 160, 0x6b19548d
+0, 26100, 160, 0x4a3449b7
+0, 27000, 160, 0x2bed5231
+0, 27900, 160, 0x556d5349
+0, 28800, 160, 0xbb6c5227
+0, 29700, 160, 0xea354b4d
+0, 30600, 160, 0xf35f4b7d
+0, 31500, 160, 0x9dcb4e9d
+0, 32400, 160, 0xc81f5ac2
+0, 33300, 160, 0xfa054cfd
+0, 34200, 160, 0x0c554e62
+0, 35100, 160, 0x7ffa5250
+0, 36000, 160, 0x7e5148ec
+0, 36900, 160, 0x95bc4d69
+0, 37800, 160, 0xf34a5644
+0, 38700, 160, 0xcaa3493d
+0, 39600, 160, 0xa44745dc
+0, 40500, 160, 0x320355c0
+0, 41400, 160, 0xbd1e5670
+0, 42300, 160, 0xfe3250cd
+0, 43200, 160, 0xce7a574c
+0, 44100, 160, 0x09b04f6e
+0, 45000, 160, 0x035759c8
+0, 45900, 160, 0x713458c7
+0, 46800, 160, 0x9a75494b
+0, 47700, 160, 0x99114fef
+0, 48600, 160, 0x129251f0
+0, 49500, 160, 0x4eb845f2
+0, 50400, 160, 0x5d064da5
+0, 51300, 160, 0x5a8e4a34
+0, 52200, 160, 0x5b784608
+0, 53100, 160, 0x1ca7546a
+0, 54000, 160, 0x327e5cbf
+0, 54900, 160, 0xd7ae4bc3
+0, 55800, 160, 0xba3f55b4
+0, 56700, 160, 0x09fe4ca7
+0, 57600, 160, 0x347248ba
+0, 58500, 160, 0xf0bf52ff
+0, 59400, 160, 0x3500507e
+0, 60300, 160, 0x30e65135
+0, 61200, 160, 0x390a5201
+0, 62100, 160, 0xf0dc5bca
+0, 63000, 160, 0x69b94f64
+0, 63900, 160, 0x6ac04cf6
+0, 64800, 160, 0xbc014cf4
+0, 65700, 160, 0x4b564eca
+0, 66600, 160, 0x33e44e85
+0, 67500, 160, 0xe39e5343
+0, 68400, 160, 0xebf64c80
+0, 69300, 160, 0x5a92562b
+0, 70200, 160, 0xe0075c88
+0, 71100, 160, 0x59bd55e8
+0, 72000, 160, 0xe6ca4ef2
+0, 72900, 160, 0xea9a4df2
+0, 73800, 160, 0xf53c4bf6
+0, 74700, 160, 0x977a4f32
+0, 75600, 160, 0xe5894eb2
+0, 76500, 160, 0x956c4c28
+0, 77400, 160, 0xdff74c3d
+0, 78300, 160, 0xace74db7
+0, 79200, 160, 0x00e74ef5
+0, 80100, 160, 0x6633560a
+0, 81000, 160, 0xd63647c5
+0, 81900, 160, 0xff144eef
+0, 82800, 160, 0xc5fe4d51
+0, 83700, 160, 0x5c244c7c
+0, 84600, 160, 0x95be50f1
+0, 85500, 160, 0x74d84b77
+0, 86400, 160, 0x1e965711
+0, 87300, 160, 0x7ae45ad7
+0, 88200, 160, 0xf9cd5920
+0, 89100, 160, 0xf0064ea9
+0, 90000, 160, 0xec645244
+0, 90900, 160, 0x8330539a
+0, 91800, 160, 0x4a5d5023
+0, 92700, 160, 0x706153d7
+0, 93600, 160, 0xd6e0520f
+0, 94500, 160, 0x0bd9586f
+0, 95400, 160, 0xc1554dec
+0, 96300, 160, 0x89be4bde
+0, 97200, 160, 0x0c2a49c0
+0, 98100, 160, 0xc18d498a
+0, 99000, 160, 0xc36147e1
+0, 99900, 160, 0x99de4d4b
+0, 100800, 160, 0x2b9d542b
+0, 101700, 160, 0x062b52c9
+0, 102600, 160, 0x9dcf542e
+0, 103500, 160, 0x641f58b9
+0, 104400, 160, 0x114c51ff
+0, 105300, 160, 0x78e04b0e
+0, 106200, 160, 0xfec74535
+0, 107100, 160, 0x71d54cd3
+0, 108000, 160, 0xee9e5289
+0, 108900, 160, 0x142354d9
+0, 109800, 160, 0x051e4ddc
+0, 110700, 160, 0x358146b8
+0, 111600, 160, 0x4dec58eb
+0, 112500, 160, 0xd0944f04
+0, 113400, 160, 0xdc025a99
+0, 114300, 160, 0x6b355402
+0, 115200, 160, 0x1c0b5a6d
+0, 116100, 160, 0xa3b34bc8
+0, 117000, 160, 0x92604eb7
+0, 117900, 160, 0x6f2f5465
+0, 118800, 160, 0xcb565361
+0, 119700, 160, 0x8bfb50a3
+0, 120600, 160, 0xf9114e99
+0, 121500, 160, 0x11065580
+0, 122400, 160, 0x903550c8
+0, 123300, 160, 0xe7aa3da8
+0, 124200, 160, 0x13f34e01
+0, 125100, 160, 0x4c3b4c0a
+0, 126000, 160, 0x08e64c60
+0, 126900, 160, 0xffcd6176
+0, 127800, 160, 0x09684f13
+0, 128700, 160, 0xd8a646b5
+0, 129600, 160, 0xc07355f0
+0, 130500, 160, 0xe836515b
+0, 131400, 160, 0x935741a5
+0, 132300, 160, 0x68f85160
+0, 133200, 160, 0x669a4ed0
+0, 134100, 160, 0xce9f4883
+0, 135000, 160, 0xd94c42de
+0, 135900, 160, 0xf1874b54
+0, 136800, 160, 0x42da46ce
+0, 137700, 160, 0xe99a4da5
+0, 138600, 160, 0x94934f16
+0, 139500, 160, 0x8571437f
+0, 140400, 160, 0xe4774dc2
+0, 141300, 160, 0x743f4f89
+0, 142200, 160, 0x3b3e50ba
+0, 143100, 160, 0x439355e9
+0, 144000, 160, 0x3e4d5178
+0, 144900, 160, 0x64595524
+0, 145800, 160, 0x42d14702
+0, 146700, 160, 0x051e4b1d
+0, 147600, 160, 0x5db84cee
+0, 148500, 160, 0x4d875136
+0, 149400, 160, 0x33b75996
+0, 150300, 160, 0xd5094d76
+0, 151200, 160, 0x6a7052b7
+0, 152100, 160, 0x77264c8f
+0, 153000, 160, 0xcf7e4ccf
+0, 153900, 160, 0x5f7c568b
+0, 154800, 160, 0x8886578b
+0, 155700, 160, 0xd33a4e52
+0, 156600, 160, 0xeefe5c23
+0, 157500, 160, 0xa9c94e38
+0, 158400, 160, 0x67845aa0
+0, 159300, 160, 0xbe91498f
+0, 160200, 160, 0x843d46e3
+0, 161100, 160, 0xbd215999
+0, 162000, 160, 0x1a2e5f2c
+0, 162900, 160, 0x6a344a63
+0, 163800, 160, 0xd80d5743
+0, 164700, 160, 0x80964879
+0, 165600, 160, 0xaafb5e35
+0, 166500, 160, 0x3b855ff3
+0, 167400, 160, 0x770b51d0
+0, 168300, 160, 0x623a5312
+0, 169200, 160, 0x0c235b56
+0, 170100, 160, 0xc8c25724
+0, 171000, 160, 0xb44650e2
+0, 171900, 160, 0xab964d47
+0, 172800, 160, 0x7aa35107
+0, 173700, 160, 0xf12d4780
+0, 174600, 160, 0x77e64f92
+0, 175500, 160, 0x34ee4fa0
+0, 176400, 160, 0x6701466b
+0, 177300, 160, 0xa79d4b4c
+0, 178200, 160, 0xbb7f557b
+0, 179100, 160, 0xaeb253c4
+0, 180000, 160, 0xe7255029
+0, 180900, 160, 0xa5f1505c
+0, 181800, 160, 0x4ae54f09
+0, 182700, 160, 0x6a2b4bc9
+0, 183600, 160, 0xf8724ea5
+0, 184500, 160, 0x4ab35317
+0, 185400, 160, 0xc8d350fb
+0, 186300, 160, 0x73a74994
+0, 187200, 160, 0x9cd1596d
+0, 188100, 160, 0x5ba16005
+0, 189000, 160, 0xb17e4fcc
+0, 189900, 160, 0x8ac958cd
+0, 190800, 160, 0x7919557f
+0, 191700, 160, 0x0be35121
+0, 192600, 160, 0xf8f752f2
+0, 193500, 160, 0xae894d40
+0, 194400, 160, 0x03d94c10
+0, 195300, 160, 0xf12c4917
+0, 196200, 160, 0x3c94534e
+0, 197100, 160, 0x111d51c3
+0, 198000, 160, 0x0a285304
+0, 198900, 160, 0xc3ac4ab1
+0, 199800, 160, 0x5576579d
+0, 200700, 160, 0x9cd04f10
+0, 201600, 160, 0x38a04bf9
+0, 202500, 160, 0xbd0d4d6d
+0, 203400, 160, 0x4db24510
+0, 204300, 160, 0x968753de
+0, 205200, 160, 0x1fa35c67
+0, 206100, 160, 0xc9c048bc
+0, 207000, 160, 0x221d629e
+0, 207900, 160, 0xbb864b0e
+0, 208800, 160, 0xe2964bcd
+0, 209700, 160, 0x20ff4b23
+0, 210600, 160, 0x01dc53e7
+0, 211500, 160, 0x522b56aa
+0, 212400, 160, 0x1e6a495a
+0, 213300, 160, 0x0dcf5731
+0, 214200, 160, 0x241f448d
+0, 215100, 160, 0xdafa55b6
+0, 216000, 160, 0x40584e43
+0, 216900, 160, 0xb73850ab
+0, 217800, 160, 0x7cff593a
+0, 218700, 160, 0x2796515a
+0, 219600, 160, 0x872c5454
+0, 220500, 160, 0xa13058e7
+0, 221400, 160, 0xd8a65261
+0, 222300, 160, 0x48a75601
+0, 223200, 160, 0xb1e7584c
+0, 224100, 160, 0x29cd53fa
+0, 225000, 160, 0xba514d84
+0, 225900, 160, 0x747f4f99
+0, 226800, 160, 0x5819526e
+0, 227700, 160, 0x10185413
+0, 228600, 160, 0x4d084cdc
+0, 229500, 160, 0x8313530b
+0, 230400, 160, 0xd26c5583
+0, 231300, 160, 0x76d749f9
+0, 232200, 160, 0x7cf847a5
+0, 233100, 160, 0xa642590c
+0, 234000, 160, 0x7fef56f2
+0, 234900, 160, 0xf6ea49b9
+0, 235800, 160, 0x6c654e89
+0, 236700, 160, 0x164f56e9
+0, 237600, 160, 0x84cf6139
+0, 238500, 160, 0x20c753ef
+0, 239400, 160, 0x3f3a485f
+0, 240300, 160, 0xee0c5f4b
+0, 241200, 160, 0x706b5313
+0, 242100, 160, 0x47da5af3
+0, 243000, 160, 0x05504b25
+0, 243900, 160, 0x584e59d8
+0, 244800, 160, 0xe9cc4e37
+0, 245700, 160, 0xf33b518a
+0, 246600, 160, 0xb9ac58b7
+0, 247500, 160, 0xed5c57f0
+0, 248400, 160, 0x4cf1579d
+0, 249300, 160, 0x96f94792
+0, 250200, 160, 0x7c455836
+0, 251100, 160, 0xad6652ce
+0, 252000, 160, 0x1ba95cab
+0, 252900, 160, 0xd86755bb
+0, 253800, 160, 0x2f9e51b4
+0, 254700, 160, 0x084e5119
+0, 255600, 160, 0x54ad5449
+0, 256500, 160, 0xff7c5b86
+0, 257400, 160, 0x29a94fff
+0, 258300, 160, 0x679c55ff
+0, 259200, 160, 0x9a415b81
+0, 260100, 160, 0x3ea5528a
+0, 261000, 160, 0x54e15d3f
+0, 261900, 160, 0x122b5c28
+0, 262800, 160, 0xdc0f4e7f
+0, 263700, 160, 0xdc304acd
+0, 264600, 160, 0xe55e5407
+0, 265500, 160, 0x8d07485f
+0, 266400, 160, 0xdc0b5333
+0, 267300, 160, 0xfaed4a90
+0, 268200, 160, 0xb0625538
+0, 269100, 160, 0x1ef3526b
+0, 270000, 160, 0xb48c48e9
+0, 270900, 160, 0x8c945190
+0, 271800, 160, 0x7f9a58b3
+0, 272700, 160, 0x55735499
+0, 273600, 160, 0xeba34a71
+0, 274500, 160, 0xbaa94a6d
+0, 275400, 160, 0x15ab484f
+0, 276300, 160, 0xdc675509
+0, 277200, 160, 0xc2e94f0e
+0, 278100, 160, 0xd7f348ac
+0, 279000, 160, 0x14884e8f
+0, 279900, 160, 0x2d274a97
+0, 280800, 160, 0x578c5834
+0, 281700, 160, 0x12074dab
+0, 282600, 160, 0x74c55067
+0, 283500, 160, 0x7c904e0f
+0, 284400, 160, 0x81d45735
+0, 285300, 160, 0x766f4d71
+0, 286200, 160, 0x9c915273
+0, 287100, 160, 0xf37f4d04
+0, 288000, 160, 0x1ac74d66
+0, 288900, 160, 0xf9b253ab
+0, 289800, 160, 0x6e0c5bb2
+0, 290700, 160, 0x603d629e
+0, 291600, 160, 0xbb674faf
+0, 292500, 160, 0x5d8d51c6
+0, 293400, 160, 0xae7350b9
+0, 294300, 160, 0xfde859ec
+0, 295200, 160, 0x900d50a4
+0, 296100, 160, 0x003551b2
+0, 297000, 160, 0xf8ae4c9d
+0, 297900, 160, 0x66ea508f
+0, 298800, 160, 0xd45b4c51
+0, 299700, 160, 0xb64451a3
+0, 300600, 160, 0x6d2a5621
+0, 301500, 160, 0x71db4d36
+0, 302400, 160, 0x06704647
+0, 303300, 160, 0x1f124cf9
+0, 304200, 160, 0x10d14b46
+0, 305100, 160, 0x421b59d8
+0, 306000, 160, 0x84ba4cae
+0, 306900, 160, 0x4fba48e1
+0, 307800, 160, 0xec294a6b
+0, 308700, 160, 0x2f1752a7
+0, 309600, 160, 0x8d665570
+0, 310500, 160, 0x586e537d
+0, 311400, 160, 0x18d54a49
+0, 312300, 160, 0xa895566d
+0, 313200, 160, 0xb9b35255
+0, 314100, 160, 0x2e194e1f
+0, 315000, 160, 0x4810594b
+0, 315900, 160, 0xb82557ee
+0, 316800, 160, 0x35d84d67
+0, 317700, 160, 0x5ee95128
+0, 318600, 160, 0x24f05747
+0, 319500, 160, 0x434d53f6
+0, 320400, 160, 0x3c894f3e
+0, 321300, 160, 0x81c34896
+0, 322200, 160, 0x7540543c
+0, 323100, 160, 0x35bc5504
+0, 324000, 160, 0x546943dc
+0, 324900, 160, 0x084d46e9
+0, 325800, 160, 0x983852ba
+0, 326700, 160, 0xefac4e15
+0, 327600, 160, 0xc9294430
+0, 328500, 160, 0xe9e74de1
+0, 329400, 160, 0x4ca1516a
+0, 330300, 160, 0x44014ceb
+0, 331200, 160, 0x1dbc5ad1
+0, 332100, 160, 0x98be4efd
+0, 333000, 160, 0x2dc75c7a
+0, 333900, 160, 0x46275852
+0, 334800, 160, 0x61c15d30
+0, 335700, 160, 0x1f605adc
+0, 336600, 160, 0xf08659ac
+0, 337500, 160, 0xb7656021
+0, 338400, 160, 0x1f4a5a72
+0, 339300, 160, 0xf8175275
+0, 340200, 160, 0xbbf4564d
+0, 341100, 160, 0x6fdc5a7d
+0, 342000, 160, 0x082f5250
+0, 342900, 160, 0x84cb55b5
+0, 343800, 160, 0x0e1a51ba
+0, 344700, 160, 0xa84e52fc
+0, 345600, 160, 0xcb5a55c9
+0, 346500, 160, 0x9ce6570d
+0, 347400, 160, 0x82b253cc
+0, 348300, 160, 0x34c4594b
+0, 349200, 160, 0xff5c5854
+0, 350100, 160, 0xd5da4ea0
+0, 351000, 160, 0xc86e5553
+0, 351900, 160, 0x7ecb55c6
+0, 352800, 160, 0xb08b5338
+0, 353700, 160, 0xd601573c
+0, 354600, 160, 0x93305092
+0, 355500, 160, 0x352d4912
+0, 356400, 160, 0xddba4d29
+0, 357300, 160, 0xc79c50b7
+0, 358200, 160, 0xe67d4e8e
+0, 359100, 160, 0xdbfd4bbc
+0, 360000, 160, 0xb2f746fb
+0, 360900, 160, 0x835b5539
+0, 361800, 160, 0x612049e9
+0, 362700, 160, 0x91a6503c
+0, 363600, 160, 0x762e4f0e
+0, 364500, 160, 0x2b2153f9
+0, 365400, 160, 0xdcfe5804
+0, 366300, 160, 0x79144cae
+0, 367200, 160, 0xd6394d99
+0, 368100, 160, 0x22395292
+0, 369000, 160, 0x50b04fa0
+0, 369900, 160, 0x846b49a5
+0, 370800, 160, 0x1f554dff
+0, 371700, 160, 0x0aa458dd
+0, 372600, 160, 0x62154dde
+0, 373500, 160, 0xe69847ac
+0, 374400, 160, 0x75855425
+0, 375300, 160, 0x49125665
+0, 376200, 160, 0xa8605945
+0, 377100, 160, 0xc02a5083
+0, 378000, 160, 0x6198537c
+0, 378900, 160, 0x90f25711
+0, 379800, 160, 0x32da51f1
+0, 380700, 160, 0x96c3474d
+0, 381600, 160, 0x82ae4579
+0, 382500, 160, 0xbabf5919
+0, 383400, 160, 0x78095772
+0, 384300, 160, 0x46964abb
+0, 385200, 160, 0x5fcb5ba3
+0, 386100, 160, 0x4a775585
+0, 387000, 160, 0xc41f53af
+0, 387900, 160, 0x457251bc
+0, 388800, 160, 0x8f864fb3
+0, 389700, 160, 0x439d526c
+0, 390600, 160, 0x5cf6503f
+0, 391500, 160, 0x90b7534f
+0, 392400, 160, 0xecc45253
+0, 393300, 160, 0x533b4ee3
+0, 394200, 160, 0x4cc44f27
+0, 395100, 160, 0x6ff35096
+0, 396000, 160, 0x141e4a80
+0, 396900, 160, 0x9e075461
+0, 397800, 160, 0xc4b55791
+0, 398700, 160, 0x40955666
+0, 399600, 160, 0x6255462f
+0, 400500, 160, 0x2cec55d6
+0, 401400, 160, 0xd71652e9
+0, 402300, 160, 0xe65e530c
+0, 403200, 160, 0xeeb9556d
+0, 404100, 160, 0x558f523e
+0, 405000, 160, 0x76e14b00
+0, 405900, 160, 0x3f9f4e9b
+0, 406800, 160, 0x0d7b492a
+0, 407700, 160, 0xdd6e51bd
+0, 408600, 160, 0x5ab353b9
+0, 409500, 160, 0x5b934f33
+0, 410400, 160, 0x36bb57a0
+0, 411300, 160, 0x455d54d3
+0, 412200, 160, 0x7e6853d7
+0, 413100, 160, 0xdcb85ed4
+0, 414000, 160, 0x3a8d5860
+0, 414900, 160, 0x5c90558f
+0, 415800, 160, 0x25504d46
+0, 416700, 160, 0x0fc55413
+0, 417600, 160, 0x98545409
+0, 418500, 160, 0x963b550e
+0, 419400, 160, 0x544a569c
+0, 420300, 160, 0x7ab65f77
+0, 421200, 160, 0x14c257e2
+0, 422100, 160, 0x6cac6262
+0, 423000, 160, 0x2f7f5091
+0, 423900, 160, 0xc2655462
+0, 424800, 160, 0xbb4b4744
+0, 425700, 160, 0x4c5f54db
+0, 426600, 160, 0x9e694ab5
+0, 427500, 160, 0xc2c95173
+0, 428400, 160, 0xf4ae553f
+0, 429300, 160, 0xb4c04ed1
+0, 430200, 160, 0xf3095128
+0, 431100, 160, 0x73b04de1
+0, 432000, 160, 0xff4951c7
+0, 432900, 160, 0x28c156bd
+0, 433800, 160, 0x17b652aa
+0, 434700, 160, 0xb9ce528b
+0, 435600, 160, 0x3cc558be
+0, 436500, 160, 0xdf385905
+0, 437400, 160, 0xe2de4fe2
+0, 438300, 160, 0xc2a6582d
+0, 439200, 160, 0xe5715bc9
+0, 440100, 160, 0x741b6416
+0, 441000, 160, 0xf9b1544f
+0, 441900, 160, 0x012e5f01
+0, 442800, 160, 0x5ab65a49
+0, 443700, 160, 0xfe1e5b1a
+0, 444600, 160, 0x370056ef
+0, 445500, 160, 0xfde45ed4
+0, 446400, 160, 0xa34f6053
+0, 447300, 160, 0x31755604
+0, 448200, 160, 0xc3415bfe
+0, 449100, 160, 0xe5dd5b58
+0, 450000, 160, 0xb6cf5295
+0, 450900, 160, 0x3d81538b
+0, 451800, 160, 0xc00255d2
+0, 452700, 160, 0xb0714f71
+0, 453600, 160, 0x9c9756ac
+0, 454500, 160, 0x4de053a0
+0, 455400, 160, 0x6706500c
+0, 456300, 160, 0x34e4511d
+0, 457200, 160, 0xe4224e3e
+0, 458100, 160, 0xdf695529
+0, 459000, 160, 0xeb1f54e0
+0, 459900, 160, 0x2870550e
+0, 460800, 160, 0x08465464
+0, 461700, 160, 0xe34150e6
+0, 462600, 160, 0xb77556e0
+0, 463500, 160, 0xb23e46ab
+0, 464400, 160, 0x83884a7b
+0, 465300, 160, 0xa0284b16
+0, 466200, 160, 0x87b749e1
+0, 467100, 160, 0x4b276444
+0, 468000, 160, 0x92f95091
+0, 468900, 160, 0x2b1056c2
+0, 469800, 160, 0xd5d5590a
+0, 470700, 160, 0x5a454fac
+0, 471600, 160, 0x0ab05b13
+0, 472500, 160, 0xd98e56ca
+0, 473400, 160, 0x183d5892
+0, 474300, 160, 0x8ba951e4
+0, 475200, 160, 0x487054ff
+0, 476100, 160, 0xc0d05562
+0, 477000, 160, 0x166c590f
+0, 477900, 160, 0x3e254cc0
+0, 478800, 160, 0xd2784ab4
+0, 479700, 160, 0x9f7b4ef6
+0, 480600, 160, 0xdd7653b6
+0, 481500, 160, 0x7ae453b7
+0, 482400, 160, 0xff6c50ec
+0, 483300, 160, 0xfa0d51a9
+0, 484200, 160, 0x29ab583b
+0, 485100, 160, 0x671d5437
+0, 486000, 160, 0x6867569f
+0, 486900, 160, 0xdd775e05
+0, 487800, 160, 0xbafa65ed
+0, 488700, 160, 0xd33f5aea
+0, 489600, 160, 0x851455a8
+0, 490500, 160, 0x044c4d45
+0, 491400, 160, 0xcd7c5d84
+0, 492300, 160, 0xd6565e61
+0, 493200, 160, 0x2f345a92
+0, 494100, 160, 0x50e05530
+0, 495000, 160, 0x787f516a
+0, 495900, 160, 0x75cd5ade
+0, 496800, 160, 0x55b558ad
+0, 497700, 160, 0x55255b01
+0, 498600, 160, 0xfc5b5945
+0, 499500, 160, 0x33914e05
+0, 500400, 160, 0x1f4a5c31
+0, 501300, 160, 0x542f4bf2
+0, 502200, 160, 0xd8b2573f
+0, 503100, 160, 0x127758b0
+0, 504000, 160, 0x18dd5a30
+0, 504900, 160, 0xe8ce61c4
+0, 505800, 160, 0x9a225b47
+0, 506700, 160, 0xd4436314
+0, 507600, 160, 0x2bf06310
+0, 508500, 160, 0x0de35e82
+0, 509400, 160, 0x76cb56f2
+0, 510300, 160, 0x65bc569b
+0, 511200, 160, 0x00a45461
+0, 512100, 160, 0xb5c55019
+0, 513000, 160, 0x5eb04b4d
+0, 513900, 160, 0xf1224c39
+0, 514800, 160, 0x4d135288
+0, 515700, 160, 0x9bc34ba7
+0, 516600, 160, 0xbde3510e
+0, 517500, 160, 0xefaf4fa4
+0, 518400, 160, 0x584950e2
+0, 519300, 160, 0x1e844e27
+0, 520200, 160, 0x38634315
+0, 521100, 160, 0x6b9b4a0b
+0, 522000, 160, 0xd491512a
+0, 522900, 160, 0x8624478c
+0, 523800, 160, 0x67ab45c7
+0, 524700, 160, 0xf78e4c53
+0, 525600, 160, 0xb1654f0d
+0, 526500, 160, 0x17bb4e96
+0, 527400, 160, 0xf3165e7c
+0, 528300, 160, 0xf7914633
+0, 529200, 160, 0x3421530f
+0, 530100, 160, 0x492e572c
+0, 531000, 160, 0xa3185319
+0, 531900, 160, 0x92d054c0
+0, 532800, 160, 0x1cc24ce1
+0, 533700, 160, 0x2ebc519e
+0, 534600, 160, 0x946b53e7
+0, 535500, 160, 0xf85c4fe6
+0, 536400, 160, 0x2974534c
+0, 537300, 160, 0xef7e4a28
+0, 538200, 160, 0x01a74c6e
+0, 539100, 160, 0x2a865674
+0, 540000, 160, 0x70474faf
+0, 540900, 160, 0x2df75014
+0, 541800, 160, 0xf1f3574e
+0, 542700, 160, 0x741b5308
+0, 543600, 160, 0xcb34513e
+0, 544500, 160, 0x7b5e50c7
+0, 545400, 160, 0x0165553b
+0, 546300, 160, 0x04b85450
+0, 547200, 160, 0x795d5873
+0, 548100, 160, 0x508859fb
+0, 549000, 160, 0xca09587d
+0, 549900, 160, 0x86a65ac8
+0, 550800, 160, 0x447353fe
+0, 551700, 160, 0x48ca54a5
+0, 552600, 160, 0x1b3e5f3e
+0, 553500, 160, 0x270a5aa2
+0, 554400, 160, 0x48a45c29
+0, 555300, 160, 0xfbf75a0b
+0, 556200, 160, 0xe65161e5
+0, 557100, 160, 0xf47c6701
+0, 558000, 160, 0xc12058bc
+0, 558900, 160, 0xdb17520c
+0, 559800, 160, 0x860455bd
+0, 560700, 160, 0xa02d56de
+0, 561600, 160, 0xf5574c7d
+0, 562500, 160, 0x500e59b3
+0, 563400, 160, 0xf0b75894
+0, 564300, 160, 0x9d454a04
+0, 565200, 160, 0x0b0554a4
+0, 566100, 160, 0x3fc34d98
+0, 567000, 160, 0x538550b8
+0, 567900, 160, 0xd84e495e
+0, 568800, 160, 0x736c4e17
+0, 569700, 160, 0xa59e5607
+0, 570600, 160, 0xe7485609
+0, 571500, 160, 0x20185a67
+0, 572400, 160, 0x9aa5576f
+0, 573300, 160, 0xed8c5d11
+0, 574200, 160, 0xecef5494
+0, 575100, 160, 0x76f75a5c
+0, 576000, 160, 0xa8fa5322
+0, 576900, 160, 0xd1945734
+0, 577800, 160, 0x817f5c82
+0, 578700, 160, 0x40756063
+0, 579600, 160, 0x524454c7
+0, 580500, 160, 0x5a776106
+0, 581400, 160, 0xd16e5d9d
+0, 582300, 160, 0x8522524c
+0, 583200, 160, 0x4a115bb9
+0, 584100, 160, 0xbf5c5c27
+0, 585000, 160, 0x48905da4
+0, 585900, 160, 0x58735040
+0, 586800, 160, 0x48635631
+0, 587700, 160, 0xf1305eaf
+0, 588600, 160, 0xd34451bd
+0, 589500, 160, 0x1a244fcf
+0, 590400, 160, 0xdb995ca0
+0, 591300, 160, 0xe38e52bb
+0, 592200, 160, 0x00715069
+0, 593100, 160, 0x72a95190
+0, 594000, 160, 0xea7d50b7
+0, 594900, 160, 0xb4094a9c
+0, 595800, 160, 0xd5284d79
+0, 596700, 160, 0x3c4349e5
+0, 597600, 160, 0x65d34e92
+0, 598500, 160, 0x67805756
+0, 599400, 160, 0x1b96502f
+0, 600300, 160, 0x395250ae
+0, 601200, 160, 0x4dc74976
+0, 602100, 160, 0x2666486e
+0, 603000, 160, 0x41924d01
+0, 603900, 160, 0x94a845f5
+0, 604800, 160, 0x1b264cf9
+0, 605700, 160, 0x63ea4aab
+0, 606600, 160, 0x9c0d4a82
+0, 607500, 160, 0x02ba4cf6
+0, 608400, 160, 0x9cd54b87
+0, 609300, 160, 0x24624c5b
+0, 610200, 160, 0x14cf54b1
+0, 611100, 160, 0xce54544b
+0, 612000, 160, 0x459b4fc9
+0, 612900, 160, 0xcc2453f1
+0, 613800, 160, 0xa4ab53bc
+0, 614700, 160, 0x92235013
+0, 615600, 160, 0xbfa257b3
+0, 616500, 160, 0xd32d51f5
+0, 617400, 160, 0x7d5d47e6
+0, 618300, 160, 0xe23d43ed
+0, 619200, 160, 0x51d8514f
+0, 620100, 160, 0x0fa04240
+0, 621000, 160, 0x233c4dce
+0, 621900, 160, 0xcd30466f
+0, 622800, 160, 0x4435546a
+0, 623700, 160, 0x3eb6445b
+0, 624600, 160, 0xcaed4ef9
+0, 625500, 160, 0xf0174da8
+0, 626400, 160, 0x60e756a0
+0, 627300, 160, 0x72ba457d
+0, 628200, 160, 0x84ce4f0f
+0, 629100, 160, 0x660d45ae
+0, 630000, 160, 0xac8446e2
+0, 630900, 160, 0xeeb153b4
+0, 631800, 160, 0x6a634c23
+0, 632700, 160, 0x890f4af8
+0, 633600, 160, 0x1d3743a7
+0, 634500, 160, 0xa37e4ee8
+0, 635400, 160, 0xb9334d56
+0, 636300, 160, 0xc1384bef
+0, 637200, 160, 0x52964f6e
+0, 638100, 160, 0xe36e57e2
+0, 639000, 160, 0x62114a53
+0, 639900, 160, 0xb1f855bb
+0, 640800, 160, 0xf0934da0
+0, 641700, 160, 0xb454494a
+0, 642600, 160, 0xb6e04b15
+0, 643500, 160, 0x933e488e
+0, 644400, 160, 0x762d5ce8
+0, 645300, 160, 0x1c4a4f85
+0, 646200, 160, 0xaaa25313
+0, 647100, 160, 0xd3655979
+0, 648000, 160, 0x8ff149e5
+0, 648900, 160, 0x5d5e51fb
+0, 649800, 160, 0x0a354c51
+0, 650700, 160, 0x79ea52ee
+0, 651600, 160, 0x306e5365
+0, 652500, 160, 0x7e03546a
+0, 653400, 160, 0x71575ddf
+0, 654300, 160, 0x08da523d
+0, 655200, 160, 0x2a2152b2
+0, 656100, 160, 0x50e55447
+0, 657000, 160, 0xf3b55758
+0, 657900, 160, 0xc29d5f12
+0, 658800, 160, 0x0c0b5778
+0, 659700, 160, 0x1b07593a
+0, 660600, 160, 0x946f562d
+0, 661500, 160, 0xcdc85636
+0, 662400, 160, 0x2421589b
+0, 663300, 160, 0x8e3b5451
+0, 664200, 160, 0xd565536a
+0, 665100, 160, 0x8d225557
+0, 666000, 160, 0xa0084e44
+0, 666900, 160, 0x85bd5413
+0, 667800, 160, 0xa4be4c3b
+0, 668700, 160, 0x332957c8
+0, 669600, 160, 0x60505225
+0, 670500, 160, 0x3d154eb3
+0, 671400, 160, 0xd85359f4
+0, 672300, 160, 0xf95b4f6b
+0, 673200, 160, 0x8bea5846
+0, 674100, 160, 0x43835a02
+0, 675000, 160, 0x340b5732
+0, 675900, 160, 0x8b6d5005
+0, 676800, 160, 0xa4995aca
+0, 677700, 160, 0x88d34efc
+0, 678600, 160, 0x078e5003
+0, 679500, 160, 0x09964b19
+0, 680400, 160, 0x2eaf5120
+0, 681300, 160, 0x52514d52
+0, 682200, 160, 0x08f84d4c
+0, 683100, 160, 0x4a9b4cc7
+0, 684000, 160, 0x947f4ca6
+0, 684900, 160, 0x086a4f32
+0, 685800, 160, 0x0e0857a6
+0, 686700, 160, 0x38145bf7
+0, 687600, 160, 0xc6e156bf
+0, 688500, 160, 0xb07853b2
+0, 689400, 160, 0xaeda5172
+0, 690300, 160, 0xc4e54d07
+0, 691200, 160, 0x0b075a61
+0, 692100, 160, 0x09f05c1f
+0, 693000, 160, 0xf5415796
+0, 693900, 160, 0xe3be584e
+0, 694800, 160, 0x6e1656f9
+0, 695700, 160, 0xd6d85599
+0, 696600, 160, 0xd9b4502e
+0, 697500, 160, 0x1186598c
+0, 698400, 160, 0x879c543d
+0, 699300, 160, 0x5b2551a3
+0, 700200, 160, 0xcf50528d
+0, 701100, 160, 0x95d059b2
+0, 702000, 160, 0x34ba5515
+0, 702900, 160, 0x7a014ba8
+0, 703800, 160, 0x27725169
+0, 704700, 160, 0x2fd14ca4
+0, 705600, 160, 0xd5ad542a
+0, 706500, 160, 0xddc24d2e
+0, 707400, 160, 0x8a4b48b4
+0, 708300, 160, 0x915e4a29
+0, 709200, 160, 0xd56d4cae
+0, 710100, 160, 0x59594eea
+0, 711000, 160, 0x87085338
+0, 711900, 160, 0xa5ee538f
+0, 712800, 160, 0xf34e5030
+0, 713700, 160, 0x6bef4da7
+0, 714600, 160, 0x05a14c52
+0, 715500, 160, 0x67bc49ce
+0, 716400, 160, 0xb18f4cff
+0, 717300, 160, 0x5d744e6d
+0, 718200, 160, 0xcb7c5973
+0, 719100, 160, 0x6df056f0
+0, 720000, 160, 0xd62c4e00
+0, 720900, 160, 0xa54d4d1e
+0, 721800, 160, 0xdaa250b0
+0, 722700, 160, 0x350e475f
+0, 723600, 160, 0x0e454bb2
+0, 724500, 160, 0xe37949ca
+0, 725400, 160, 0x551453bf
+0, 726300, 160, 0x35d04c27
+0, 727200, 160, 0x6749469d
+0, 728100, 160, 0x544752e9
+0, 729000, 160, 0xf23b4888
+0, 729900, 160, 0x6f0a5519
+0, 730800, 160, 0x808a58df
+0, 731700, 160, 0x8e674c88
+0, 732600, 160, 0xd3ab51f7
+0, 733500, 160, 0x985d500f
+0, 734400, 160, 0x734e52d8
+0, 735300, 160, 0xb0da5227
+0, 736200, 160, 0xcc7d4a21
+0, 737100, 160, 0xb1354baf
+0, 738000, 160, 0xfc8d4f9a
+0, 738900, 160, 0x6f044d82
+0, 739800, 160, 0x41e7546b
+0, 740700, 160, 0x67014682
+0, 741600, 160, 0x5516575b
+0, 742500, 160, 0x26254693
+0, 743400, 160, 0x81ce4af5
+0, 744300, 160, 0x77f152a0
+0, 745200, 160, 0x995a5096
+0, 746100, 160, 0x6114532e
+0, 747000, 160, 0x4df457f3
+0, 747900, 160, 0xbcd94804
+0, 748800, 160, 0x1e544fd2
+0, 749700, 160, 0xa70b5954
+0, 750600, 160, 0x1c77484c
+0, 751500, 160, 0xb07f4c42
+0, 752400, 160, 0x62074f1f
+0, 753300, 160, 0xf3b656a1
+0, 754200, 160, 0x65734ac0
+0, 755100, 160, 0x2a9752cd
+0, 756000, 160, 0x15ff4ef0
+0, 756900, 160, 0xabd4532c
+0, 757800, 160, 0x8a44503a
+0, 758700, 160, 0xbf4250f3
+0, 759600, 160, 0x17594ac5
+0, 760500, 160, 0x7b5e4b24
+0, 761400, 160, 0x24684cb5
+0, 762300, 160, 0xc4d54b42
+0, 763200, 160, 0xd48f58af
+0, 764100, 160, 0x0374593a
+0, 765000, 160, 0x398a5b0d
+0, 765900, 160, 0xf60855e6
+0, 766800, 160, 0x6fbb5587
+0, 767700, 160, 0x44405c2b
+0, 768600, 160, 0xa6345d70
+0, 769500, 160, 0x464557d5
+0, 770400, 160, 0x0c3153ca
+0, 771300, 160, 0x15ec50c4
+0, 772200, 160, 0xd5e559da
+0, 773100, 160, 0x999757b9
+0, 774000, 160, 0x7a5d5754
+0, 774900, 160, 0xf85b5f18
+0, 775800, 160, 0xa66d5c72
+0, 776700, 160, 0xd8f55981
+0, 777600, 160, 0xe6364f64
+0, 778500, 160, 0x528a5785
+0, 779400, 160, 0xdefe5332
+0, 780300, 160, 0x4bc4532e
+0, 781200, 160, 0x505a4eb3
+0, 782100, 160, 0xa28d589d
+0, 783000, 160, 0x092d511f
+0, 783900, 160, 0x3079591e
+0, 784800, 160, 0x2b1d5339
+0, 785700, 160, 0xf8d849d1
+0, 786600, 160, 0xadb056a6
+0, 787500, 160, 0x2ee74c4f
+0, 788400, 160, 0x35c34c9f
+0, 789300, 160, 0xb6ae53d3
+0, 790200, 160, 0x7258534e
+0, 791100, 160, 0xb76d4b1b
+0, 792000, 160, 0x99a14a0f
+0, 792900, 160, 0x88365944
+0, 793800, 160, 0x97cf4aed
+0, 794700, 160, 0x444b56f6
+0, 795600, 160, 0x1d1f4b01
+0, 796500, 160, 0x3dcd417e
+0, 797400, 160, 0xa4985140
+0, 798300, 160, 0x86f94c4d
+0, 799200, 160, 0xc3635436
+0, 800100, 160, 0x198b432b
+0, 801000, 160, 0xae5253e4
+0, 801900, 160, 0x248c4f1a
+0, 802800, 160, 0x787a45df
+0, 803700, 160, 0x5fd44cad
+0, 804600, 160, 0x68be581c
+0, 805500, 160, 0x5ff5531b
+0, 806400, 160, 0x2bcd4aa1
+0, 807300, 160, 0x0d134a7c
+0, 808200, 160, 0x28af5885
+0, 809100, 160, 0xc09f4d65
+0, 810000, 160, 0x7468552d
+0, 810900, 160, 0x82df49ac
+0, 811800, 160, 0xe3725fdc
+0, 812700, 160, 0x0ec74d11
+0, 813600, 160, 0xfc2a5355
+0, 814500, 160, 0x41df4d4f
+0, 815400, 160, 0x4ebe473d
+0, 816300, 160, 0xd8734bf2
+0, 817200, 160, 0x4acd5056
+0, 818100, 160, 0x47805700
+0, 819000, 160, 0xe4f25135
+0, 819900, 160, 0x9f195649
+0, 820800, 160, 0x8b055f64
+0, 821700, 160, 0xc4b751c8
+0, 822600, 160, 0x95e55ba4
+0, 823500, 160, 0xf0955494
+0, 824400, 160, 0xca1a47b9
+0, 825300, 160, 0x9d025711
+0, 826200, 160, 0xf6cb4a0a
+0, 827100, 160, 0xd8385b4d
+0, 828000, 160, 0x7b2852b6
+0, 828900, 160, 0x90a35643
+0, 829800, 160, 0x63105d0a
+0, 830700, 160, 0x55414083
+0, 831600, 160, 0xc94554a9
+0, 832500, 160, 0xa88f4a36
+0, 833400, 160, 0xda5d52bc
+0, 834300, 160, 0x5b3943da
+0, 835200, 160, 0xd2314755
+0, 836100, 160, 0x743c4cdc
+0, 837000, 160, 0x7c3e4dc2
+0, 837900, 160, 0x12644715
+0, 838800, 160, 0x1050480b
+0, 839700, 160, 0x73645906
+0, 840600, 160, 0x28ef4a9e
+0, 841500, 160, 0xf72440bc
+0, 842400, 160, 0x41964bda
+0, 843300, 160, 0x2afb4d9b
+0, 844200, 160, 0xf74b4c5a
+0, 845100, 160, 0xcf165e2e
+0, 846000, 160, 0x3dbb4d06
+0, 846900, 160, 0xbd9755f9
+0, 847800, 160, 0x3248581d
+0, 848700, 160, 0xc00c559d
+0, 849600, 160, 0xff6c4b0a
+0, 850500, 160, 0x154157e3
+0, 851400, 160, 0xb996499c
+0, 852300, 160, 0xe1a059ba
+0, 853200, 160, 0x98015946
+0, 854100, 160, 0x168b4ceb
+0, 855000, 160, 0x567b4f83
+0, 855900, 160, 0x903e52f8
+0, 856800, 160, 0xc0a252dc
+0, 857700, 160, 0x08cb4b70
+0, 858600, 160, 0x3d9a5be6
+0, 859500, 160, 0x904b4907
+0, 860400, 160, 0x738847b1
+0, 861300, 160, 0x10405c19
+0, 862200, 160, 0x8c134f27
+0, 863100, 160, 0xdfe34d7f
+0, 864000, 160, 0x9d0948a8
+0, 864900, 160, 0x67755611
+0, 865800, 160, 0x46734258
+0, 866700, 160, 0x76f449fa
+0, 867600, 160, 0xfad64d30
+0, 868500, 160, 0x7f4357f4
+0, 869400, 160, 0xd20e5079
+0, 870300, 160, 0xdf7857ec
+0, 871200, 160, 0x46ff4891
+0, 872100, 160, 0x1b724ffc
+0, 873000, 160, 0xdf20545a
+0, 873900, 160, 0xeb5254e0
+0, 874800, 160, 0x794b4a96
+0, 875700, 160, 0x86a15147
+0, 876600, 160, 0x30f75504
+0, 877500, 160, 0x39575354
+0, 878400, 160, 0xb6a35351
+0, 879300, 160, 0x9da34c3a
+0, 880200, 160, 0xcf2d5386
+0, 881100, 160, 0xa7f353f6
+0, 882000, 160, 0xa6e34e95
+0, 882900, 160, 0x98174400
+0, 883800, 160, 0x13685641
+0, 884700, 160, 0x99215154
+0, 885600, 160, 0x5be75237
+0, 886500, 160, 0x4cb64942
+0, 887400, 160, 0x15de4e03
+0, 888300, 160, 0x613a4fd5
+0, 889200, 160, 0xc97c4821
+0, 890100, 160, 0xbf1558f2
+0, 891000, 160, 0x651d4cf4
+0, 891900, 160, 0xbee44a56
+0, 892800, 160, 0x6cbd4c20
+0, 893700, 160, 0xcf45493d
+0, 894600, 160, 0x73e74d2a
+0, 895500, 160, 0x6a3256e4
+0, 896400, 160, 0x89ac4a68
+0, 897300, 160, 0x0d2652aa
+0, 898200, 160, 0x56ce4b78
+0, 899100, 160, 0xb7b24bcb
diff --git a/tests/ref/fate/gapless-mp3 b/tests/ref/fate/gapless-mp3
new file mode 100644
index 0000000000..e6a7a3387b
--- /dev/null
+++ b/tests/ref/fate/gapless-mp3
@@ -0,0 +1,5 @@
+d5c88cf38416329a052a9b0cb140fb4c *tests/data/fate/gapless-mp3.out-1
+c96c3ae7bd3300fd2f4debac222de5b7
+3386bc2009b31b7ef39247918cbb02a5 *tests/data/fate/gapless-mp3.out-2
+c96c3ae7bd3300fd2f4debac222de5b7
+92e37f050ad4fc817730c8af17ee6d1b *tests/data/fate/gapless-mp3.out-3
diff --git a/tests/ref/fate/gif-color b/tests/ref/fate/gif-color
new file mode 100644
index 0000000000..5559186536
--- /dev/null
+++ b/tests/ref/fate/gif-color
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 188356, 0xf0944065
+0, 1, 1, 1, 188356, 0x146ed4c4
+0, 2, 2, 1, 188356, 0x96866a6f
+0, 3, 3, 1, 188356, 0xe15e1f1c
+0, 4, 4, 1, 188356, 0x0662c1d0
+0, 5, 5, 1, 188356, 0x88fa6cc4
+0, 6, 6, 1, 188356, 0x3cce2f71
+0, 7, 7, 1, 188356, 0x1510f9f3
+0, 8, 8, 1, 188356, 0xf27e9fa8
+0, 9, 9, 1, 188356, 0x0f4b64a2
+0, 10, 10, 1, 188356, 0x3d2714a5
+0, 11, 11, 1, 188356, 0x392ce45d
+0, 12, 12, 1, 188356, 0x2eadb79f
+0, 13, 13, 1, 188356, 0x68109314
+0, 14, 14, 1, 188356, 0x4eca71ac
+0, 15, 15, 1, 188356, 0xa9aa5907
+0, 16, 16, 1, 188356, 0x2a5d08c0
+0, 17, 17, 1, 188356, 0x942bba84
+0, 18, 18, 1, 188356, 0xbee38983
+0, 19, 19, 1, 188356, 0xa0d65a5a
+0, 20, 20, 1, 188356, 0x47270bee
+0, 21, 21, 1, 188356, 0xc020dc40
+0, 22, 22, 1, 188356, 0x978dbc8f
+0, 23, 23, 1, 188356, 0x6b1e9f1b
+0, 24, 24, 1, 188356, 0xd8078bf4
+0, 25, 25, 1, 188356, 0x94ca7bd7
+0, 26, 26, 1, 188356, 0xac745e77
+0, 27, 27, 1, 188356, 0x73154f2c
+0, 28, 28, 1, 188356, 0x31200601
+0, 29, 29, 1, 188356, 0x6525dd42
+0, 30, 30, 1, 188356, 0xa29b985a
+0, 31, 31, 1, 188356, 0xe3e074d8
+0, 32, 32, 1, 188356, 0xb87b3222
+0, 33, 33, 1, 188356, 0x5b9a11f2
+0, 34, 34, 1, 188356, 0x25f7f8c9
+0, 35, 35, 1, 188356, 0x0235e93c
+0, 36, 36, 1, 188356, 0x2a42d643
+0, 37, 37, 1, 188356, 0xfb7acddb
+0, 38, 38, 1, 188356, 0xecbbbf5e
+0, 39, 39, 1, 188356, 0xeba4bc9a
+0, 40, 40, 1, 188356, 0x4317b36b
+0, 41, 41, 1, 188356, 0x7316ae1a
+0, 42, 42, 1, 188356, 0xb5ccad05
+0, 43, 43, 1, 188356, 0x38afb0dc
+0, 44, 44, 1, 188356, 0xf11cad55
+0, 45, 45, 1, 188356, 0x3d77b400
+0, 46, 46, 1, 188356, 0xf084b9b9
+0, 47, 47, 1, 188356, 0x02a4c584
+0, 48, 48, 1, 188356, 0x14f4d52e
+0, 49, 49, 1, 188356, 0x55118432
+0, 50, 50, 1, 188356, 0x4ad82e9f
+0, 51, 51, 1, 188356, 0xc6eafc52
+0, 52, 52, 1, 188356, 0xf4bdc575
+0, 53, 53, 1, 188356, 0x8429689e
+0, 54, 54, 1, 188356, 0xaa23019e
+0, 55, 55, 1, 188356, 0xaf52c3a5
+0, 56, 56, 1, 188356, 0x1d387c32
+0, 57, 57, 1, 188356, 0x543d5cd2
+0, 58, 58, 1, 188356, 0x8cdb399c
+0, 59, 59, 1, 188356, 0xcceb292f
+0, 60, 60, 1, 188356, 0xa87115e8
+0, 61, 61, 1, 188356, 0x9665ec8f
+0, 62, 62, 1, 188356, 0xad99baf4
+0, 63, 63, 1, 188356, 0xc6e5a2b5
+0, 64, 64, 1, 188356, 0xe2a48359
+0, 65, 65, 1, 188356, 0x3a270df0
+0, 66, 66, 1, 188356, 0xcc34826b
+0, 67, 67, 1, 188356, 0x15ec2dcc
+0, 68, 68, 1, 188356, 0x8874c5f9
+0, 69, 69, 1, 188356, 0x829966e8
+0, 70, 70, 1, 188356, 0x691f1ebb
+0, 71, 71, 1, 188356, 0x00e3e184
+0, 72, 72, 1, 188356, 0x97739332
+0, 73, 73, 1, 188356, 0x507769aa
+0, 74, 74, 1, 188356, 0xddfb3069
+0, 75, 75, 1, 188356, 0x7296f749
+0, 76, 76, 1, 188356, 0x0555ca32
+0, 77, 77, 1, 188356, 0x4554c683
+0, 78, 78, 1, 188356, 0x2398c10f
+0, 79, 79, 1, 188356, 0x1c5ccfa0
+0, 80, 80, 1, 188356, 0xa580f3c8
+0, 81, 81, 1, 188356, 0x4fadea78
+0, 82, 82, 1, 188356, 0x4a57db38
+0, 83, 83, 1, 188356, 0x9e98df6d
+0, 84, 84, 1, 188356, 0xfeb3dec9
+0, 85, 85, 1, 188356, 0xbf16ef7a
+0, 86, 86, 1, 188356, 0xdc23fc48
+0, 87, 87, 1, 188356, 0x3bf2e401
+0, 88, 88, 1, 188356, 0xc832bcf4
+0, 89, 89, 1, 188356, 0x977db44f
+0, 90, 90, 1, 188356, 0x18d39d96
+0, 91, 91, 1, 188356, 0x9adf60d8
+0, 92, 92, 1, 188356, 0x567b667a
+0, 93, 93, 1, 188356, 0xd4a45e8e
+0, 94, 94, 1, 188356, 0x94a24cc7
+0, 95, 95, 1, 188356, 0x086f0a53
+0, 96, 96, 1, 188356, 0xcbf3ebcb
+0, 97, 97, 1, 188356, 0x1a40a7b9
+0, 98, 98, 1, 188356, 0xe16d8964
+0, 99, 99, 1, 188356, 0x3edd7dfa
+0, 100, 100, 1, 188356, 0xba417fa5
+0, 101, 101, 1, 188356, 0x734a7611
+0, 102, 102, 1, 188356, 0xfa1e7b1e
+0, 103, 103, 1, 188356, 0x1af23355
+0, 104, 104, 1, 188356, 0x28d41390
+0, 105, 105, 1, 188356, 0x2838c58d
+0, 106, 106, 1, 188356, 0x4e2ba2a8
+0, 107, 107, 1, 188356, 0xcedc99ae
+0, 108, 108, 1, 188356, 0xb06ba12d
+0, 109, 109, 1, 188356, 0x38c997b6
+0, 110, 110, 1, 188356, 0x12dba0dc
+0, 111, 111, 1, 188356, 0x5f86496a
+0, 112, 112, 1, 188356, 0x0b74216d
+0, 113, 113, 1, 188356, 0xdbddbada
+0, 114, 114, 1, 188356, 0x7d168af2
+0, 115, 115, 1, 188356, 0x22d4462b
+0, 116, 116, 1, 188356, 0xc248265d
+0, 117, 117, 1, 188356, 0x37a41b0d
+0, 118, 118, 1, 188356, 0x9ebd24f1
+0, 119, 119, 1, 188356, 0xf21f1633
+0, 120, 120, 1, 188356, 0x1db62004
+0, 121, 121, 1, 188356, 0xcc241ac1
+0, 122, 122, 1, 188356, 0x224d2637
+0, 123, 123, 1, 188356, 0x1bd8390c
+0, 124, 124, 1, 188356, 0xd8e64966
+0, 125, 125, 1, 188356, 0x96e66287
+0, 126, 126, 1, 188356, 0xa83c9a32
+0, 127, 127, 1, 188356, 0x3a5faeba
+0, 128, 128, 1, 188356, 0x8200cd87
+0, 129, 129, 1, 188356, 0x6326e591
+0, 130, 130, 1, 188356, 0xb5d70993
+0, 131, 131, 1, 188356, 0x954d5da2
+0, 132, 132, 1, 188356, 0x38b1788b
+0, 133, 133, 1, 188356, 0x4aafa131
+0, 134, 134, 1, 188356, 0xaff2be78
+0, 135, 135, 1, 188356, 0x9bd7eb69
+0, 136, 136, 1, 188356, 0x0d2b17c9
+0, 137, 137, 1, 188356, 0xf5d8a764
+0, 138, 138, 1, 188356, 0xa302dfb2
+0, 139, 139, 1, 188356, 0xe8a32ac1
+0, 140, 140, 1, 188356, 0x50a8470d
+0, 141, 141, 1, 188356, 0x52826061
+0, 142, 142, 1, 188356, 0x26e88798
+0, 143, 143, 1, 188356, 0x1448acb8
+0, 144, 144, 1, 188356, 0xfb380972
+0, 145, 145, 1, 188356, 0x184976e8
+0, 146, 146, 1, 188356, 0xa349a871
+0, 147, 147, 1, 188356, 0x617ed8b1
+0, 148, 148, 1, 188356, 0xb6bc1425
+0, 149, 149, 1, 188356, 0xafe74efd
+0, 150, 150, 1, 188356, 0x0b8b61e5
+0, 151, 151, 1, 188356, 0xc6ad67a7
+0, 152, 152, 1, 188356, 0x4da186fe
+0, 153, 153, 1, 188356, 0xe08f9975
+0, 154, 154, 1, 188356, 0xa43f8ba4
+0, 155, 155, 1, 188356, 0xcad4b6b5
+0, 156, 156, 1, 188356, 0x7e70d51e
+0, 157, 157, 1, 188356, 0x429b0b5b
+0, 158, 158, 1, 188356, 0xea92350d
+0, 159, 159, 1, 188356, 0x9a7440f8
+0, 160, 160, 1, 188356, 0x63a2be6e
+0, 161, 161, 1, 188356, 0x59b64b50
+0, 162, 162, 1, 188356, 0x63c4a10e
+0, 163, 163, 1, 188356, 0x6146e5e0
+0, 164, 164, 1, 188356, 0x603b2ae5
+0, 165, 165, 1, 188356, 0x818bc774
+0, 166, 166, 1, 188356, 0xa5ce278f
+0, 167, 167, 1, 188356, 0x4d85684d
+0, 168, 168, 1, 188356, 0xbbda9cad
+0, 169, 169, 1, 188356, 0xfee2e78e
+0, 170, 170, 1, 188356, 0x681d2635
+0, 171, 171, 1, 188356, 0x05354903
+0, 172, 172, 1, 188356, 0x8eecac99
diff --git a/tests/ref/fate/gif-demux b/tests/ref/fate/gif-demux
new file mode 100644
index 0000000000..547b9ce3d6
--- /dev/null
+++ b/tests/ref/fate/gif-demux
@@ -0,0 +1,37 @@
+#tb 0: 1/100
+0, 0, 0, 5, 74699, 0xef7e91c8
+0, 5, 5, 2, 10079, 0x2892d9e2, F=0x0
+0, 7, 7, 2, 12369, 0xd7d73286, F=0x0
+0, 9, 9, 2, 8868, 0x4bb59b6d, F=0x0
+0, 11, 11, 2, 8249, 0x23d5d174, F=0x0
+0, 13, 13, 2, 8381, 0x10acf0cd, F=0x0
+0, 15, 15, 2, 8579, 0xdfe108b2, F=0x0
+0, 17, 17, 2, 8200, 0x46ec6c55, F=0x0
+0, 19, 19, 2, 7261, 0xaf328999, F=0x0
+0, 21, 21, 4, 7047, 0xab3d2bd0, F=0x0
+0, 25, 25, 2, 6486, 0xa1629769, F=0x0
+0, 27, 27, 2, 7278, 0x4c55b7ce, F=0x0
+0, 29, 29, 2, 7761, 0x54368171, F=0x0
+0, 31, 31, 2, 7794, 0xbde2dbcd, F=0x0
+0, 33, 33, 2, 7935, 0xe6202c65, F=0x0
+0, 35, 35, 2, 8499, 0x1d5ceb7e, F=0x0
+0, 37, 37, 2, 8841, 0xc962be37, F=0x0
+0, 39, 39, 2, 9281, 0x7ec29c31, F=0x0
+0, 41, 41, 5, 9606, 0x3de06d48, F=0x0
+0, 46, 46, 2, 6319, 0xb3e94478, F=0x0
+0, 48, 48, 2, 5521, 0xc8157edc, F=0x0
+0, 50, 50, 2, 5052, 0x23e8ea7c, F=0x0
+0, 52, 52, 2, 4651, 0xa73f25c9, F=0x0
+0, 54, 54, 2, 4477, 0x1ddcc2c3, F=0x0
+0, 56, 56, 2, 4736, 0x6ead0d5e, F=0x0
+0, 58, 58, 2, 4609, 0x8bc7faa3, F=0x0
+0, 60, 60, 2, 4474, 0x3926975e, F=0x0
+0, 62, 62, 4, 4381, 0x28c392d5, F=0x0
+0, 66, 66, 2, 4443, 0x9c33b143, F=0x0
+0, 68, 68, 2, 4540, 0xb1d1c8b9, F=0x0
+0, 70, 70, 2, 4530, 0x773bc617, F=0x0
+0, 72, 72, 2, 4558, 0xa1e8cdf3, F=0x0
+0, 74, 74, 2, 4633, 0x8f64fda7, F=0x0
+0, 76, 76, 2, 4700, 0x45f40805, F=0x0
+0, 78, 78, 2, 5117, 0x4eb4c5fb, F=0x0
+0, 80, 80, 2, 5370, 0xb10c6910, F=0x0
diff --git a/tests/ref/fate/gif-disposal-background b/tests/ref/fate/gif-disposal-background
new file mode 100644
index 0000000000..838745b795
--- /dev/null
+++ b/tests/ref/fate/gif-disposal-background
@@ -0,0 +1,6 @@
+#tb 0: 1/2
+0, 0, 0, 1, 10368, 0x8b200cc8
+0, 1, 1, 1, 10368, 0x4e208e4f
+0, 2, 2, 1, 10368, 0x044dba8b
+0, 3, 3, 1, 10368, 0x1d617e09
+0, 4, 4, 1, 10368, 0xae38a6d2
diff --git a/tests/ref/fate/gif-disposal-restore b/tests/ref/fate/gif-disposal-restore
new file mode 100644
index 0000000000..0ff1715153
--- /dev/null
+++ b/tests/ref/fate/gif-disposal-restore
@@ -0,0 +1,4 @@
+#tb 0: 1/1
+0, 0, 0, 1, 112320, 0xb8afe429
+0, 1, 1, 1, 112320, 0xae588a4b
+0, 3, 3, 1, 112320, 0xccdd27b7
diff --git a/tests/ref/fate/gif-gray b/tests/ref/fate/gif-gray
new file mode 100644
index 0000000000..5a133bd030
--- /dev/null
+++ b/tests/ref/fate/gif-gray
@@ -0,0 +1,37 @@
+#tb 0: 1/100
+0, 0, 0, 1, 691200, 0xef6c0f3d
+0, 5, 5, 1, 691200, 0xc18b32de
+0, 7, 7, 1, 691200, 0x2395a3d7
+0, 9, 9, 1, 691200, 0x81dc3cf2
+0, 11, 11, 1, 691200, 0xabe2390e
+0, 13, 13, 1, 691200, 0xb2955c2a
+0, 15, 15, 1, 691200, 0x868d9ca2
+0, 17, 17, 1, 691200, 0x3016c2b6
+0, 19, 19, 1, 691200, 0x4501cffa
+0, 21, 21, 1, 691200, 0x8661d79e
+0, 25, 25, 1, 691200, 0xbc96d02e
+0, 27, 27, 1, 691200, 0x5f90bf5e
+0, 29, 29, 1, 691200, 0xf18da09a
+0, 31, 31, 1, 691200, 0x540467ce
+0, 33, 33, 1, 691200, 0x60d24012
+0, 35, 35, 1, 691200, 0x24323d36
+0, 37, 37, 1, 691200, 0x9e07c84b
+0, 39, 39, 1, 691200, 0xc18b32de
+0, 41, 41, 1, 691200, 0xef6c0f3d
+0, 46, 46, 1, 691200, 0xc9461045
+0, 48, 48, 1, 691200, 0x23ed4b99
+0, 50, 50, 1, 691200, 0x7e351d69
+0, 52, 52, 1, 691200, 0x0513e0aa
+0, 54, 54, 1, 691200, 0x28a4b6f2
+0, 56, 56, 1, 691200, 0xce10a94e
+0, 58, 58, 1, 691200, 0x63929d4e
+0, 60, 60, 1, 691200, 0xd26c9bb6
+0, 62, 62, 1, 691200, 0xb2a29842
+0, 66, 66, 1, 691200, 0x9fd69a16
+0, 68, 68, 1, 691200, 0x10f99e46
+0, 70, 70, 1, 691200, 0xea95a9fa
+0, 72, 72, 1, 691200, 0x97dbb9d6
+0, 74, 74, 1, 691200, 0xf4e9e2d6
+0, 76, 76, 1, 691200, 0x46b1230d
+0, 78, 78, 1, 691200, 0xb4a54ccd
+0, 80, 80, 1, 691200, 0x40cc103d
diff --git a/tests/ref/fate/gifenc-bgr4_byte b/tests/ref/fate/gifenc-bgr4_byte
new file mode 100644
index 0000000000..c0d39bdecd
--- /dev/null
+++ b/tests/ref/fate/gifenc-bgr4_byte
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 508, 0xa1b80fc0
+0, 1, 1, 1, 213, 0x4f554bd7, S=1, 1024, 0xb6327c81
+0, 2, 2, 1, 131, 0x283b2988, S=1, 1024, 0xae3a7c81
+0, 3, 3, 1, 384, 0xc4fea72a, S=1, 1024, 0xb6327c81
+0, 4, 4, 1, 381, 0x050ba2b8, S=1, 1024, 0x9e4a7c81
+0, 5, 5, 1, 430, 0x00cfb2ae, S=1, 1024, 0x9e4a7c81
+0, 6, 6, 1, 518, 0xc8e5d827, S=1, 1024, 0x9e4a7c81
+0, 7, 7, 1, 535, 0x326ce62a, S=1, 1024, 0x9e4a7c81
+0, 8, 8, 1, 438, 0x34d6b7c0, S=1, 1024, 0xb6327c81
+0, 9, 9, 1, 923, 0x9fb1a37c, S=1, 1024, 0xb6327c81
+0, 10, 10, 1, 694, 0xf20449a5, S=1, 1024, 0xb6327c81
+0, 11, 11, 1, 1194, 0x67cd2ab5, S=1, 1024, 0xb6327c81
+0, 12, 12, 1, 1291, 0x1d23539d, S=1, 1024, 0xb6327c81
+0, 13, 13, 1, 1245, 0x065f32e6, S=1, 1024, 0xb6327c81
+0, 14, 14, 1, 1330, 0x83ec51a4, S=1, 1024, 0xb6327c81
+0, 15, 15, 1, 1276, 0x2acf38dc, S=1, 1024, 0xb6327c81
+0, 16, 16, 1, 1475, 0x4cd197ef, S=1, 1024, 0xb6327c81
+0, 17, 17, 1, 1784, 0xd1e84ae6, S=1, 1024, 0xde0a7c81
+0, 18, 18, 1, 1675, 0x092dfa86, S=1, 1024, 0xde0a7c81
+0, 19, 19, 1, 1509, 0x639aaa00, S=1, 1024, 0xde0a7c81
+0, 20, 20, 1, 1705, 0xfd3719d5, S=1, 1024, 0xde0a7c81
+0, 21, 21, 1, 1745, 0x8a761db4, S=1, 1024, 0xde0a7c81
+0, 22, 22, 1, 1642, 0x18830245, S=1, 1024, 0xde0a7c81
+0, 23, 23, 1, 1718, 0x3c8d1ebe, S=1, 1024, 0xde0a7c81
+0, 24, 24, 1, 1900, 0x2ea879d1, S=1, 1024, 0xde0a7c81
+0, 25, 25, 1, 1807, 0x02b35230, S=1, 1024, 0xde0a7c81
+0, 26, 26, 1, 1915, 0x22d48344, S=1, 1024, 0xde0a7c81
+0, 27, 27, 1, 2100, 0x55fcd063, S=1, 1024, 0xde0a7c81
+0, 28, 28, 1, 2700, 0x7cc5f08b, S=1, 1024, 0xde0a7c81
+0, 29, 29, 1, 2673, 0xb997a80d, S=1, 1024, 0xde0a7c81
+0, 30, 30, 1, 2895, 0xab69484d, S=1, 1024, 0xde0a7c81
+0, 31, 31, 1, 3257, 0xf753cf24, S=1, 1024, 0xde0a7c81
+0, 32, 32, 1, 3179, 0x34f2c13b, S=1, 1024, 0xde0a7c81
+0, 33, 33, 1, 3296, 0x7c06e72f, S=1, 1024, 0xde0a7c81
+0, 34, 34, 1, 3600, 0x4ca67634, S=1, 1024, 0xde0a7c81
+0, 35, 35, 1, 3699, 0xabe89fe3, S=1, 1024, 0xde0a7c81
+0, 36, 36, 1, 3814, 0x1869d3f4, S=1, 1024, 0xde0a7c81
+0, 37, 37, 1, 3627, 0x19bd7da7, S=1, 1024, 0xde0a7c81
+0, 38, 38, 1, 2950, 0x048a6055, S=1, 1024, 0xde0a7c81
+0, 39, 39, 1, 3086, 0x64ec8fc2, S=1, 1024, 0xde0a7c81
+0, 40, 40, 1, 3094, 0x1a388553, S=1, 1024, 0xde0a7c81
+0, 41, 41, 1, 3456, 0x01432c82, S=1, 1024, 0xde0a7c81
+0, 42, 42, 1, 4108, 0xf9505c66, S=1, 1024, 0xde0a7c81
+0, 43, 43, 1, 4217, 0x7f985ba4, S=1, 1024, 0xde0a7c81
+0, 44, 44, 1, 3613, 0xd0684d83, S=1, 1024, 0xde0a7c81
+0, 45, 45, 1, 3910, 0x0070e692, S=1, 1024, 0xde0a7c81
+0, 46, 46, 1, 4461, 0x5cc9e33d, S=1, 1024, 0xde0a7c81
+0, 47, 47, 1, 4593, 0x33a32dd1, S=1, 1024, 0xde0a7c81
+0, 48, 48, 1, 4822, 0x59549883, S=1, 1024, 0xde0a7c81
+0, 49, 49, 1, 5398, 0xb7bac31e, S=1, 1024, 0xde0a7c81
+0, 50, 50, 1, 5266, 0x21c695aa, S=1, 1024, 0xde0a7c81
+0, 51, 51, 1, 5416, 0xf305e3ed, S=1, 1024, 0xde0a7c81
+0, 52, 52, 1, 5519, 0x857d071f, S=1, 1024, 0xde0a7c81
+0, 53, 53, 1, 5701, 0x8f885c9c, S=1, 1024, 0xde0a7c81
+0, 54, 54, 1, 6160, 0x48523e83, S=1, 1024, 0xde0a7c81
+0, 55, 55, 1, 6233, 0x8fd2511e, S=1, 1024, 0xde0a7c81
+0, 56, 56, 1, 5911, 0x92d4c516, S=1, 1024, 0xde0a7c81
+0, 57, 57, 1, 5997, 0xbd7cfa15, S=1, 1024, 0xde0a7c81
+0, 58, 58, 1, 5946, 0x8f5fedff, S=1, 1024, 0xde0a7c81
+0, 59, 59, 1, 6468, 0x45c0cb8c, S=1, 1024, 0xde0a7c81
+0, 60, 60, 1, 6737, 0x4e1e39ac, S=1, 1024, 0xde0a7c81
+0, 61, 61, 1, 6275, 0x1d5e8f4c, S=1, 1024, 0xde0a7c81
+0, 62, 62, 1, 6641, 0x844b3aad, S=1, 1024, 0xde0a7c81
+0, 63, 63, 1, 6378, 0x52568640, S=1, 1024, 0xde0a7c81
+0, 64, 64, 1, 6257, 0xfabc585f, S=1, 1024, 0xde0a7c81
+0, 65, 65, 1, 6908, 0xf261701c, S=1, 1024, 0xde0a7c81
+0, 66, 66, 1, 7230, 0xb4f524ce, S=1, 1024, 0xde0a7c81
+0, 67, 67, 1, 7556, 0x89c1a712, S=1, 1024, 0xde0a7c81
+0, 68, 68, 1, 7413, 0x553970a4, S=1, 1024, 0xde0a7c81
+0, 69, 69, 1, 7476, 0x24d2a761, S=1, 1024, 0xde0a7c81
+0, 70, 70, 1, 7596, 0xf072e431, S=1, 1024, 0xde0a7c81
+0, 71, 71, 1, 7756, 0x131205c0, S=1, 1024, 0xde0a7c81
+0, 72, 72, 1, 8015, 0xf4536a7f, S=1, 1024, 0xde0a7c81
+0, 73, 73, 1, 8128, 0xba80be2b, S=1, 1024, 0xde0a7c81
+0, 74, 74, 1, 8101, 0x44ceb3a2, S=1, 1024, 0xde0a7c81
+0, 75, 75, 1, 7863, 0x55043dfd, S=1, 1024, 0xde0a7c81
+0, 76, 76, 1, 7960, 0x38399182, S=1, 1024, 0xde0a7c81
+0, 77, 77, 1, 8238, 0x1d52ecf3, S=1, 1024, 0xde0a7c81
+0, 78, 78, 1, 8321, 0xd8d24a5c, S=1, 1024, 0xde0a7c81
+0, 79, 79, 1, 8562, 0x4a0cc02b, S=1, 1024, 0xde0a7c81
+0, 80, 80, 1, 8746, 0x2db40da7, S=1, 1024, 0xde0a7c81
+0, 81, 81, 1, 8578, 0x46f9a4c1, S=1, 1024, 0xde0a7c81
+0, 82, 82, 1, 8878, 0xf58d5a19, S=1, 1024, 0xde0a7c81
+0, 83, 83, 1, 9077, 0x78de57f6, S=1, 1024, 0xde0a7c81
+0, 84, 84, 1, 9310, 0x8c10f77a, S=1, 1024, 0xde0a7c81
+0, 85, 85, 1, 9394, 0x741f431e, S=1, 1024, 0xde0a7c81
+0, 86, 86, 1, 9161, 0x6f499587, S=1, 1024, 0xde0a7c81
+0, 87, 87, 1, 9462, 0x628936c3, S=1, 1024, 0xde0a7c81
+0, 88, 88, 1, 9650, 0x4cb4936e, S=1, 1024, 0xde0a7c81
+0, 89, 89, 1, 9701, 0x5e069c40, S=1, 1024, 0xde0a7c81
+0, 90, 90, 1, 9523, 0x66a13c83, S=1, 1024, 0xde0a7c81
+0, 91, 91, 1, 9891, 0x43ea0e93, S=1, 1024, 0xde0a7c81
+0, 92, 92, 1, 10005, 0x96a849e7, S=1, 1024, 0xde0a7c81
+0, 93, 93, 1, 10038, 0x68032d25, S=1, 1024, 0xde0a7c81
+0, 94, 94, 1, 10086, 0xef59458d, S=1, 1024, 0xde0a7c81
+0, 95, 95, 1, 10438, 0x3466fed0, S=1, 1024, 0xde0a7c81
+0, 96, 96, 1, 10583, 0x8bdd5477, S=1, 1024, 0xde0a7c81
+0, 97, 97, 1, 10581, 0x69d27fee, S=1, 1024, 0xde0a7c81
+0, 98, 98, 1, 10807, 0xde62d6e3, S=1, 1024, 0xde0a7c81
+0, 99, 99, 1, 11111, 0x34eb4c13, S=1, 1024, 0xde0a7c81
+0, 100, 100, 1, 11194, 0x584f6b73, S=1, 1024, 0xde0a7c81
+0, 101, 101, 1, 11240, 0xc90ba13f, S=1, 1024, 0xde0a7c81
+0, 102, 102, 1, 11483, 0x59c4f3c5, S=1, 1024, 0xde0a7c81
+0, 103, 103, 1, 11680, 0xc62c5bc1, S=1, 1024, 0xde0a7c81
+0, 104, 104, 1, 11785, 0xc9bab793, S=1, 1024, 0xde0a7c81
+0, 105, 105, 1, 11436, 0xc9c40809, S=1, 1024, 0xde0a7c81
+0, 106, 106, 1, 11928, 0x4b77c9a7, S=1, 1024, 0xde0a7c81
+0, 107, 107, 1, 11932, 0x722abcbe, S=1, 1024, 0xde0a7c81
+0, 108, 108, 1, 12281, 0x0d136f53, S=1, 1024, 0xde0a7c81
+0, 109, 109, 1, 12334, 0x04a47f78, S=1, 1024, 0xde0a7c81
+0, 110, 110, 1, 12452, 0xa02db188, S=1, 1024, 0xde0a7c81
+0, 111, 111, 1, 12695, 0x1a813b2e, S=1, 1024, 0xde0a7c81
+0, 112, 112, 1, 12668, 0x81b24f79, S=1, 1024, 0xde0a7c81
+0, 113, 113, 1, 12957, 0x4da59f8c, S=1, 1024, 0xde0a7c81
+0, 114, 114, 1, 13054, 0x7abedf5a, S=1, 1024, 0xde0a7c81
+0, 115, 115, 1, 13147, 0x138f2bbd, S=1, 1024, 0xde0a7c81
+0, 116, 116, 1, 13171, 0x43c1195f, S=1, 1024, 0xde0a7c81
+0, 117, 117, 1, 13198, 0x2c8d58d4, S=1, 1024, 0xde0a7c81
+0, 118, 118, 1, 13211, 0x12c36193, S=1, 1024, 0xde0a7c81
+0, 119, 119, 1, 13210, 0xfe496107, S=1, 1024, 0xde0a7c81
+0, 120, 120, 1, 13467, 0x4d8ea128, S=1, 1024, 0xde0a7c81
+0, 121, 121, 1, 13665, 0x94caddde, S=1, 1024, 0xde0a7c81
+0, 122, 122, 1, 13692, 0xe38febd9, S=1, 1024, 0xde0a7c81
+0, 123, 123, 1, 13821, 0xee592e62, S=1, 1024, 0xde0a7c81
+0, 124, 124, 1, 13946, 0xceb09235, S=1, 1024, 0xde0a7c81
+0, 125, 125, 1, 14063, 0x7361d2f5, S=1, 1024, 0xde0a7c81
+0, 126, 126, 1, 14124, 0x226bcac1, S=1, 1024, 0xde0a7c81
+0, 127, 127, 1, 14331, 0x0649512b, S=1, 1024, 0xde0a7c81
+0, 128, 128, 1, 14469, 0x0d7da45b, S=1, 1024, 0xde0a7c81
+0, 129, 129, 1, 14536, 0x73cca242, S=1, 1024, 0xde0a7c81
+0, 130, 130, 1, 14608, 0x1f3dd14e, S=1, 1024, 0xde0a7c81
+0, 131, 131, 1, 14898, 0xd13d258e, S=1, 1024, 0xde0a7c81
+0, 132, 132, 1, 14978, 0xfa049fea, S=1, 1024, 0xde0a7c81
+0, 133, 133, 1, 15142, 0x1dfad60c, S=1, 1024, 0xde0a7c81
+0, 134, 134, 1, 15129, 0x5962bae7, S=1, 1024, 0xde0a7c81
+0, 135, 135, 1, 15243, 0x2c2c113b, S=1, 1024, 0xde0a7c81
+0, 136, 136, 1, 15337, 0x3cab623b, S=1, 1024, 0xde0a7c81
+0, 137, 137, 1, 15638, 0xbff3a100, S=1, 1024, 0xde0a7c81
+0, 138, 138, 1, 15912, 0x13bf1fb2, S=1, 1024, 0xde0a7c81
+0, 139, 139, 1, 16041, 0x01134246, S=1, 1024, 0xde0a7c81
+0, 140, 140, 1, 16228, 0xe2f80035, S=1, 1024, 0xde0a7c81
+0, 141, 141, 1, 16262, 0xc8d3ea51, S=1, 1024, 0xde0a7c81
+0, 142, 142, 1, 16371, 0xe7da07f2, S=1, 1024, 0xde0a7c81
+0, 143, 143, 1, 16661, 0x10ada592, S=1, 1024, 0xde0a7c81
+0, 144, 144, 1, 16917, 0xbfb717e5, S=1, 1024, 0xde0a7c81
+0, 145, 145, 1, 17149, 0x4074ca41, S=1, 1024, 0xde0a7c81
+0, 146, 146, 1, 17172, 0xf749b49f, S=1, 1024, 0xde0a7c81
+0, 147, 147, 1, 17315, 0x2abea8a0, S=1, 1024, 0xde0a7c81
+0, 148, 148, 1, 17397, 0x14f71122, S=1, 1024, 0xde0a7c81
+0, 149, 149, 1, 17431, 0xce49f2d3, S=1, 1024, 0xde0a7c81
+0, 150, 150, 1, 17576, 0x7c6552ad, S=1, 1024, 0xde0a7c81
+0, 151, 151, 1, 17764, 0x1d198d60, S=1, 1024, 0xde0a7c81
+0, 152, 152, 1, 17826, 0xe1727f57, S=1, 1024, 0xde0a7c81
+0, 153, 153, 1, 17918, 0xb78d9b9f, S=1, 1024, 0xde0a7c81
+0, 154, 154, 1, 17823, 0xc9fabf19, S=1, 1024, 0xde0a7c81
+0, 155, 155, 1, 18142, 0xeb5b21a9, S=1, 1024, 0xde0a7c81
+0, 156, 156, 1, 18257, 0x7b38822c, S=1, 1024, 0xde0a7c81
+0, 157, 157, 1, 18337, 0xd395c279, S=1, 1024, 0xde0a7c81
+0, 158, 158, 1, 18293, 0x6c3b3766, S=1, 1024, 0xde0a7c81
+0, 159, 159, 1, 18418, 0x2abcbcf8, S=1, 1024, 0xde0a7c81
+0, 160, 160, 1, 18607, 0x79424730, S=1, 1024, 0xde0a7c81
+0, 161, 161, 1, 18916, 0x8707bbc6, S=1, 1024, 0xde0a7c81
+0, 162, 162, 1, 19073, 0xd82c03f6, S=1, 1024, 0xde0a7c81
+0, 163, 163, 1, 19168, 0xb7d6fe27, S=1, 1024, 0xde0a7c81
+0, 164, 164, 1, 19210, 0x79f301eb, S=1, 1024, 0xde0a7c81
+0, 165, 165, 1, 19398, 0x0a5663c6, S=1, 1024, 0xde0a7c81
+0, 166, 166, 1, 19480, 0x4fe09e5b, S=1, 1024, 0xde0a7c81
+0, 167, 167, 1, 19659, 0xab971088, S=1, 1024, 0xde0a7c81
+0, 168, 168, 1, 19672, 0x2e331553, S=1, 1024, 0xde0a7c81
+0, 169, 169, 1, 19936, 0x2eea628a, S=1, 1024, 0xde0a7c81
+0, 170, 170, 1, 19975, 0xd6bb9ab2, S=1, 1024, 0xde0a7c81
+0, 171, 171, 1, 20021, 0xf7e98dc5, S=1, 1024, 0xde0a7c81
+0, 172, 172, 1, 20060, 0x20017807, S=1, 1024, 0xde0a7c81
diff --git a/tests/ref/fate/gifenc-bgr8 b/tests/ref/fate/gifenc-bgr8
new file mode 100644
index 0000000000..f3b7772785
--- /dev/null
+++ b/tests/ref/fate/gifenc-bgr8
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 552, 0x271a2dd3
+0, 1, 1, 1, 297, 0x90168a95, S=1, 1024, 0xf351799f
+0, 2, 2, 1, 438, 0x91efce1b, S=1, 1024, 0xf351799f
+0, 3, 3, 1, 450, 0x7c2dcfad, S=1, 1024, 0xf351799f
+0, 4, 4, 1, 547, 0xc131fd3b, S=1, 1024, 0xf351799f
+0, 5, 5, 1, 614, 0x68182006, S=1, 1024, 0xf351799f
+0, 6, 6, 1, 642, 0x78bb1f5f, S=1, 1024, 0xf351799f
+0, 7, 7, 1, 660, 0x35c033a2, S=1, 1024, 0xf351799f
+0, 8, 8, 1, 821, 0xaf30790b, S=1, 1024, 0xf351799f
+0, 9, 9, 1, 1157, 0x741c2da1, S=1, 1024, 0xf351799f
+0, 10, 10, 1, 179, 0x3a27517c, S=1, 1024, 0xf351799f
+0, 11, 11, 1, 1333, 0x5ee76f3c, S=1, 1024, 0xf351799f
+0, 12, 12, 1, 1638, 0x5f640e86, S=1, 1024, 0xf351799f
+0, 13, 13, 1, 1531, 0xccb8e437, S=1, 1024, 0xf351799f
+0, 14, 14, 1, 1720, 0xc95d45ec, S=1, 1024, 0xf351799f
+0, 15, 15, 1, 1910, 0x56cc831e, S=1, 1024, 0xf351799f
+0, 16, 16, 1, 2124, 0x9cc8e130, S=1, 1024, 0xf351799f
+0, 17, 17, 1, 2248, 0x05a325b1, S=1, 1024, 0xf351799f
+0, 18, 18, 1, 2311, 0xdc633703, S=1, 1024, 0xf351799f
+0, 19, 19, 1, 2408, 0x91c26f3e, S=1, 1024, 0xf351799f
+0, 20, 20, 1, 2601, 0x8cf3c157, S=1, 1024, 0xf351799f
+0, 21, 21, 1, 2687, 0x8f6400e6, S=1, 1024, 0xf351799f
+0, 22, 22, 1, 2784, 0xaa880e55, S=1, 1024, 0xf351799f
+0, 23, 23, 1, 2884, 0x46f546f6, S=1, 1024, 0xf351799f
+0, 24, 24, 1, 2982, 0x807c7ad5, S=1, 1024, 0xf351799f
+0, 25, 25, 1, 3101, 0xbcc89bec, S=1, 1024, 0xf351799f
+0, 26, 26, 1, 3253, 0xd032f3fa, S=1, 1024, 0xf351799f
+0, 27, 27, 1, 3329, 0xe4d42430, S=1, 1024, 0xf351799f
+0, 28, 28, 1, 3572, 0xf8058aa0, S=1, 1024, 0xf351799f
+0, 29, 29, 1, 3807, 0x3d2af9f3, S=1, 1024, 0xf351799f
+0, 30, 30, 1, 2750, 0x814d1c33, S=1, 1024, 0xf351799f
+0, 31, 31, 1, 4031, 0x3b077006, S=1, 1024, 0xf351799f
+0, 32, 32, 1, 3025, 0x86729c1c, S=1, 1024, 0xf351799f
+0, 33, 33, 1, 4295, 0xf71b0b38, S=1, 1024, 0xf351799f
+0, 34, 34, 1, 2044, 0x5adcb93b, S=1, 1024, 0xf351799f
+0, 35, 35, 1, 3212, 0xcf79eeed, S=1, 1024, 0xf351799f
+0, 36, 36, 1, 2292, 0xb4386334, S=1, 1024, 0xf351799f
+0, 37, 37, 1, 3633, 0x0010992f, S=1, 1024, 0xf351799f
+0, 38, 38, 1, 3552, 0x23697490, S=1, 1024, 0xf351799f
+0, 39, 39, 1, 3690, 0x62afdbb8, S=1, 1024, 0xf351799f
+0, 40, 40, 1, 1559, 0x5baef54a, S=1, 1024, 0xf351799f
+0, 41, 41, 1, 954, 0xca75ca79, S=1, 1024, 0xf351799f
+0, 42, 42, 1, 273, 0x3687799b, S=1, 1024, 0xf351799f
+0, 43, 43, 1, 930, 0x29f3b0c4, S=1, 1024, 0xf351799f
+0, 44, 44, 1, 271, 0x305e8094, S=1, 1024, 0xf351799f
+0, 45, 45, 1, 196, 0xf5ab51ee, S=1, 1024, 0xf351799f
+0, 46, 46, 1, 4299, 0x67ec0d55, S=1, 1024, 0xf351799f
+0, 47, 47, 1, 4895, 0xb394406c, S=1, 1024, 0xf351799f
+0, 48, 48, 1, 4928, 0x233919d7, S=1, 1024, 0xf351799f
+0, 49, 49, 1, 4941, 0x58a357da, S=1, 1024, 0xf351799f
+0, 50, 50, 1, 4154, 0x21f2ac33, S=1, 1024, 0xf351799f
+0, 51, 51, 1, 4678, 0xab3cc050, S=1, 1024, 0xf351799f
+0, 52, 52, 1, 4741, 0x1974b581, S=1, 1024, 0xf351799f
+0, 53, 53, 1, 4982, 0x891456d5, S=1, 1024, 0xf351799f
+0, 54, 54, 1, 5179, 0x860fc6a1, S=1, 1024, 0xf351799f
+0, 55, 55, 1, 5046, 0xce9183d3, S=1, 1024, 0xf351799f
+0, 56, 56, 1, 5140, 0xa6d7b9af, S=1, 1024, 0xf351799f
+0, 57, 57, 1, 4301, 0x03b6ef3f, S=1, 1024, 0xf351799f
+0, 58, 58, 1, 5079, 0xa8d59e01, S=1, 1024, 0xf351799f
+0, 59, 59, 1, 5284, 0xea34e3b3, S=1, 1024, 0xf351799f
+0, 60, 60, 1, 5426, 0x556a15cd, S=1, 1024, 0xf351799f
+0, 61, 61, 1, 4645, 0x061e8936, S=1, 1024, 0xf351799f
+0, 62, 62, 1, 5263, 0x7536cf7d, S=1, 1024, 0xf351799f
+0, 63, 63, 1, 5221, 0x9fbac3ca, S=1, 1024, 0xf351799f
+0, 64, 64, 1, 5217, 0x02269bd2, S=1, 1024, 0xf351799f
+0, 65, 65, 1, 5395, 0x120fff66, S=1, 1024, 0xf351799f
+0, 66, 66, 1, 5220, 0x77cedcc5, S=1, 1024, 0xf351799f
+0, 67, 67, 1, 5704, 0xba42dd96, S=1, 1024, 0xf351799f
+0, 68, 68, 1, 5636, 0xcb91a25b, S=1, 1024, 0xf351799f
+0, 69, 69, 1, 5818, 0x8dc0df92, S=1, 1024, 0xf351799f
+0, 70, 70, 1, 5763, 0x51d5d5f0, S=1, 1024, 0xf351799f
+0, 71, 71, 1, 6116, 0x09558b48, S=1, 1024, 0xf351799f
+0, 72, 72, 1, 6069, 0x41926817, S=1, 1024, 0xf351799f
+0, 73, 73, 1, 5796, 0x7fbeda44, S=1, 1024, 0xf351799f
+0, 74, 74, 1, 5999, 0xe07d3770, S=1, 1024, 0xf351799f
+0, 75, 75, 1, 6220, 0x6607b06f, S=1, 1024, 0xf351799f
+0, 76, 76, 1, 6374, 0x7628e533, S=1, 1024, 0xf351799f
+0, 77, 77, 1, 6465, 0xfe956b15, S=1, 1024, 0xf351799f
+0, 78, 78, 1, 7019, 0x6c9a1aef, S=1, 1024, 0xf351799f
+0, 79, 79, 1, 7255, 0x5fa5c1bf, S=1, 1024, 0xf351799f
+0, 80, 80, 1, 8197, 0xf11d6ef2, S=1, 1024, 0xf351799f
+0, 81, 81, 1, 8358, 0x027279e8, S=1, 1024, 0xf351799f
+0, 82, 82, 1, 7708, 0x607f8e8b, S=1, 1024, 0xf351799f
+0, 83, 83, 1, 7412, 0x6bb2105f, S=1, 1024, 0xf351799f
+0, 84, 84, 1, 7541, 0xfdc02154, S=1, 1024, 0xf351799f
+0, 85, 85, 1, 7948, 0x916ecd8b, S=1, 1024, 0xf351799f
+0, 86, 86, 1, 8408, 0x1f97d414, S=1, 1024, 0xf351799f
+0, 87, 87, 1, 8056, 0x9cbf159c, S=1, 1024, 0xf351799f
+0, 88, 88, 1, 7401, 0x2625addb, S=1, 1024, 0xf351799f
+0, 89, 89, 1, 7494, 0x2877eacb, S=1, 1024, 0xf351799f
+0, 90, 90, 1, 7806, 0xe32574a3, S=1, 1024, 0xf351799f
+0, 91, 91, 1, 7768, 0x25ed7ee7, S=1, 1024, 0xf351799f
+0, 92, 92, 1, 7749, 0x6d8e978e, S=1, 1024, 0xf351799f
+0, 93, 93, 1, 8047, 0xec4b150c, S=1, 1024, 0xf351799f
+0, 94, 94, 1, 7618, 0x88cf30d5, S=1, 1024, 0xf351799f
+0, 95, 95, 1, 7979, 0x0eb1cf2a, S=1, 1024, 0xf351799f
+0, 96, 96, 1, 12062, 0xb49d9125, S=1, 1024, 0xf351799f
+0, 97, 97, 1, 12317, 0x2d8fd6e9, S=1, 1024, 0xf351799f
+0, 98, 98, 1, 12217, 0x9b3be549, S=1, 1024, 0xf351799f
+0, 99, 99, 1, 11227, 0x067e9118, S=1, 1024, 0xf351799f
+0, 100, 100, 1, 11108, 0x5e5b0afd, S=1, 1024, 0xf351799f
+0, 101, 101, 1, 11366, 0xb38e8d15, S=1, 1024, 0xf351799f
+0, 102, 102, 1, 11896, 0xeb3e35ca, S=1, 1024, 0xf351799f
+0, 103, 103, 1, 11479, 0xbf7581e9, S=1, 1024, 0xf351799f
+0, 104, 104, 1, 13395, 0x415b38d8, S=1, 1024, 0xf351799f
+0, 105, 105, 1, 12913, 0x61544631, S=1, 1024, 0xf351799f
+0, 106, 106, 1, 13864, 0xd39fe768, S=1, 1024, 0xf351799f
+0, 107, 107, 1, 13551, 0x76c167d1, S=1, 1024, 0xf351799f
+0, 108, 108, 1, 14041, 0x2f206888, S=1, 1024, 0xf351799f
+0, 109, 109, 1, 14144, 0x9ec030d3, S=1, 1024, 0xf351799f
+0, 110, 110, 1, 14277, 0xa84b3a9b, S=1, 1024, 0xf351799f
+0, 111, 111, 1, 14424, 0xf5f1e06e, S=1, 1024, 0xf351799f
+0, 112, 112, 1, 14689, 0xbca0adb5, S=1, 1024, 0xf351799f
+0, 113, 113, 1, 14598, 0xc1d45745, S=1, 1024, 0xf351799f
+0, 114, 114, 1, 15213, 0x8f3080fc, S=1, 1024, 0xf351799f
+0, 115, 115, 1, 15425, 0xb0aa8f59, S=1, 1024, 0xf351799f
+0, 116, 116, 1, 15595, 0x1406e5d5, S=1, 1024, 0xf351799f
+0, 117, 117, 1, 15598, 0x48ec7d08, S=1, 1024, 0xf351799f
+0, 118, 118, 1, 15863, 0x5381db7b, S=1, 1024, 0xf351799f
+0, 119, 119, 1, 15717, 0xb87a1b87, S=1, 1024, 0xf351799f
+0, 120, 120, 1, 16078, 0x5bab2453, S=1, 1024, 0xf351799f
+0, 121, 121, 1, 16225, 0xa1f88113, S=1, 1024, 0xf351799f
+0, 122, 122, 1, 16135, 0x6af2f4e1, S=1, 1024, 0xf351799f
+0, 123, 123, 1, 16661, 0xf02a3343, S=1, 1024, 0xf351799f
+0, 124, 124, 1, 16619, 0xc71935a4, S=1, 1024, 0xf351799f
+0, 125, 125, 1, 16829, 0x29849844, S=1, 1024, 0xf351799f
+0, 126, 126, 1, 16944, 0x3423ae77, S=1, 1024, 0xf351799f
+0, 127, 127, 1, 17119, 0x609b4409, S=1, 1024, 0xf351799f
+0, 128, 128, 1, 17150, 0xf85dfd31, S=1, 1024, 0xf351799f
+0, 129, 129, 1, 17321, 0x38eccb10, S=1, 1024, 0xf351799f
+0, 130, 130, 1, 17395, 0x0ba08b85, S=1, 1024, 0xf351799f
+0, 131, 131, 1, 17666, 0x6fbc0264, S=1, 1024, 0xf351799f
+0, 132, 132, 1, 17730, 0x3dcc64a6, S=1, 1024, 0xf351799f
+0, 133, 133, 1, 17934, 0xb539974b, S=1, 1024, 0xf351799f
+0, 134, 134, 1, 17944, 0x2214ec94, S=1, 1024, 0xf351799f
+0, 135, 135, 1, 18238, 0x70f9ff1d, S=1, 1024, 0xf351799f
+0, 136, 136, 1, 18391, 0x4b149209, S=1, 1024, 0xf351799f
+0, 137, 137, 1, 18543, 0x45a1c02f, S=1, 1024, 0xf351799f
+0, 138, 138, 1, 18939, 0x2789a88c, S=1, 1024, 0xf351799f
+0, 139, 139, 1, 19145, 0x5daafd7a, S=1, 1024, 0xf351799f
+0, 140, 140, 1, 19120, 0x565f80e6, S=1, 1024, 0xf351799f
+0, 141, 141, 1, 19130, 0xff70cc21, S=1, 1024, 0xf351799f
+0, 142, 142, 1, 19494, 0xbfa284db, S=1, 1024, 0xf351799f
+0, 143, 143, 1, 19534, 0x3d40743b, S=1, 1024, 0xf351799f
+0, 144, 144, 1, 19747, 0x33c9b108, S=1, 1024, 0xf351799f
+0, 145, 145, 1, 20114, 0x9d223e36, S=1, 1024, 0xf351799f
+0, 146, 146, 1, 20257, 0xe7bdaf43, S=1, 1024, 0xf351799f
+0, 147, 147, 1, 20370, 0x0c5f1970, S=1, 1024, 0xf351799f
+0, 148, 148, 1, 20292, 0x6986d20e, S=1, 1024, 0xf351799f
+0, 149, 149, 1, 20491, 0xd88e4c08, S=1, 1024, 0xf351799f
+0, 150, 150, 1, 20647, 0x1aefaffc, S=1, 1024, 0xf351799f
+0, 151, 151, 1, 20666, 0x43e4aaaa, S=1, 1024, 0xf351799f
+0, 152, 152, 1, 21007, 0xa7ca3ef0, S=1, 1024, 0xf351799f
+0, 153, 153, 1, 21058, 0x06814351, S=1, 1024, 0xf351799f
+0, 154, 154, 1, 21153, 0x3c852b10, S=1, 1024, 0xf351799f
+0, 155, 155, 1, 21078, 0x8df15855, S=1, 1024, 0xf351799f
+0, 156, 156, 1, 21458, 0xd3a531d6, S=1, 1024, 0xf351799f
+0, 157, 157, 1, 21669, 0x88baca53, S=1, 1024, 0xf351799f
+0, 158, 158, 1, 21581, 0xd692fa1f, S=1, 1024, 0xf351799f
+0, 159, 159, 1, 21654, 0x30fb9061, S=1, 1024, 0xf351799f
+0, 160, 160, 1, 21987, 0xe7646d8b, S=1, 1024, 0xf351799f
+0, 161, 161, 1, 22205, 0x0fc55b6a, S=1, 1024, 0xf351799f
+0, 162, 162, 1, 22475, 0x4bc4c032, S=1, 1024, 0xf351799f
+0, 163, 163, 1, 22490, 0x58ca23f6, S=1, 1024, 0xf351799f
+0, 164, 164, 1, 22460, 0xf9ceb0ac, S=1, 1024, 0xf351799f
+0, 165, 165, 1, 22861, 0xb05f0f84, S=1, 1024, 0xf351799f
+0, 166, 166, 1, 22746, 0x0df23a5c, S=1, 1024, 0xf351799f
+0, 167, 167, 1, 23165, 0xbd7147ad, S=1, 1024, 0xf351799f
+0, 168, 168, 1, 23273, 0x9781a34f, S=1, 1024, 0xf351799f
+0, 169, 169, 1, 23211, 0x69c7606b, S=1, 1024, 0xf351799f
+0, 170, 170, 1, 23648, 0xdafde037, S=1, 1024, 0xf351799f
+0, 171, 171, 1, 23675, 0x2a2147ed, S=1, 1024, 0xf351799f
+0, 172, 172, 1, 23874, 0x12c184b6, S=1, 1024, 0xf351799f
diff --git a/tests/ref/fate/gifenc-gray b/tests/ref/fate/gifenc-gray
new file mode 100644
index 0000000000..c11e132b8b
--- /dev/null
+++ b/tests/ref/fate/gifenc-gray
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 579, 0x0d0e3ab8
+0, 1, 1, 1, 150, 0x178b3a8c, S=1, 1024, 0xc2f67c9f
+0, 2, 2, 1, 155, 0x941743f5, S=1, 1024, 0xc2f67c9f
+0, 3, 3, 1, 144, 0x68c73711, S=1, 1024, 0xc2f67c9f
+0, 4, 4, 1, 152, 0xaf9a3f2e, S=1, 1024, 0xc2f67c9f
+0, 5, 5, 1, 136, 0x68593d85, S=1, 1024, 0xc2f67c9f
+0, 6, 6, 1, 134, 0x0dcb373f, S=1, 1024, 0xc2f67c9f
+0, 7, 7, 1, 129, 0x3baf3279, S=1, 1024, 0xc2f67c9f
+0, 8, 8, 1, 123, 0x9c963148, S=1, 1024, 0xc2f67c9f
+0, 9, 9, 1, 123, 0x5c272d6b, S=1, 1024, 0xc2f67c9f
+0, 10, 10, 1, 150, 0x5f8d41aa, S=1, 1024, 0xc2f67c9f
+0, 11, 11, 1, 134, 0x6f582fee, S=1, 1024, 0xc2f67c9f
+0, 12, 12, 1, 134, 0x85d53038, S=1, 1024, 0xc2f67c9f
+0, 13, 13, 1, 123, 0x6d2a2cb2, S=1, 1024, 0xc2f67c9f
+0, 14, 14, 1, 127, 0x1e78327b, S=1, 1024, 0xc2f67c9f
+0, 15, 15, 1, 119, 0xbafc2c31, S=1, 1024, 0xc2f67c9f
+0, 16, 16, 1, 138, 0x57553638, S=1, 1024, 0xc2f67c9f
+0, 17, 17, 1, 140, 0xf7423adb, S=1, 1024, 0xc2f67c9f
+0, 18, 18, 1, 122, 0x7e592f8b, S=1, 1024, 0xc2f67c9f
+0, 19, 19, 1, 123, 0xaa7d313c, S=1, 1024, 0xc2f67c9f
+0, 20, 20, 1, 140, 0x4fd63b34, S=1, 1024, 0xc2f67c9f
+0, 21, 21, 1, 123, 0x67753163, S=1, 1024, 0xc2f67c9f
+0, 22, 22, 1, 123, 0x02193147, S=1, 1024, 0xc2f67c9f
+0, 23, 23, 1, 124, 0xa85131e9, S=1, 1024, 0xc2f67c9f
+0, 24, 24, 1, 122, 0xef8731e2, S=1, 1024, 0xc2f67c9f
+0, 25, 25, 1, 122, 0x06d432c9, S=1, 1024, 0xc2f67c9f
+0, 26, 26, 1, 123, 0xcc8831cd, S=1, 1024, 0xc2f67c9f
+0, 27, 27, 1, 118, 0xa1d33166, S=1, 1024, 0xc2f67c9f
+0, 28, 28, 1, 159, 0xcc8c454c, S=1, 1024, 0xc2f67c9f
+0, 29, 29, 1, 140, 0x8a0231ad, S=1, 1024, 0xc2f67c9f
+0, 30, 30, 1, 163, 0xe78248d2, S=1, 1024, 0xc2f67c9f
+0, 31, 31, 1, 142, 0x3b293489, S=1, 1024, 0xc2f67c9f
+0, 32, 32, 1, 170, 0x5f504b12, S=1, 1024, 0xc2f67c9f
+0, 33, 33, 1, 146, 0x38a53693, S=1, 1024, 0xc2f67c9f
+0, 34, 34, 1, 132, 0xb18a3499, S=1, 1024, 0xc2f67c9f
+0, 35, 35, 1, 113, 0x55182bda, S=1, 1024, 0xc2f67c9f
+0, 36, 36, 1, 132, 0xaced3333, S=1, 1024, 0xc2f67c9f
+0, 37, 37, 1, 120, 0x9ffe2e4f, S=1, 1024, 0xc2f67c9f
+0, 38, 38, 1, 135, 0x6223351e, S=1, 1024, 0xc2f67c9f
+0, 39, 39, 1, 123, 0x269b3058, S=1, 1024, 0xc2f67c9f
+0, 40, 40, 1, 119, 0x17052def, S=1, 1024, 0xc2f67c9f
+0, 41, 41, 1, 119, 0x36da2ee2, S=1, 1024, 0xc2f67c9f
+0, 42, 42, 1, 120, 0x984e31be, S=1, 1024, 0xc2f67c9f
+0, 43, 43, 1, 114, 0xfd382c9d, S=1, 1024, 0xc2f67c9f
+0, 44, 44, 1, 125, 0x926a36c6, S=1, 1024, 0xc2f67c9f
+0, 45, 45, 1, 117, 0xbceb3183, S=1, 1024, 0xc2f67c9f
+0, 46, 46, 1, 116, 0xf4c72d82, S=1, 1024, 0xc2f67c9f
+0, 47, 47, 1, 124, 0x0c19343c, S=1, 1024, 0xc2f67c9f
+0, 48, 48, 1, 117, 0x1f032eb1, S=1, 1024, 0xc2f67c9f
+0, 49, 49, 1, 135, 0x31a437e6, S=1, 1024, 0xc2f67c9f
+0, 50, 50, 1, 131, 0x4c1735fe, S=1, 1024, 0xc2f67c9f
+0, 51, 51, 1, 122, 0xb7603463, S=1, 1024, 0xc2f67c9f
+0, 52, 52, 1, 122, 0x7f5e34e1, S=1, 1024, 0xc2f67c9f
+0, 53, 53, 1, 124, 0x9562350f, S=1, 1024, 0xc2f67c9f
+0, 54, 54, 1, 126, 0x18b33759, S=1, 1024, 0xc2f67c9f
+0, 55, 55, 1, 117, 0x748f3243, S=1, 1024, 0xc2f67c9f
+0, 56, 56, 1, 109, 0x72832fe7, S=1, 1024, 0xc2f67c9f
+0, 57, 57, 1, 120, 0x748a2e38, S=1, 1024, 0xc2f67c9f
+0, 58, 58, 1, 120, 0x61f82fb2, S=1, 1024, 0xc2f67c9f
+0, 59, 59, 1, 122, 0x2a6b3282, S=1, 1024, 0xc2f67c9f
+0, 60, 60, 1, 116, 0x8b542de6, S=1, 1024, 0xc2f67c9f
+0, 61, 61, 1, 119, 0xf33c318e, S=1, 1024, 0xc2f67c9f
+0, 62, 62, 1, 116, 0xff182f36, S=1, 1024, 0xc2f67c9f
+0, 63, 63, 1, 119, 0xeb9e2fcc, S=1, 1024, 0xc2f67c9f
+0, 64, 64, 1, 118, 0xe82d304e, S=1, 1024, 0xc2f67c9f
+0, 65, 65, 1, 137, 0x98303d30, S=1, 1024, 0xc2f67c9f
+0, 66, 66, 1, 149, 0x01123fff, S=1, 1024, 0xc2f67c9f
+0, 67, 67, 1, 115, 0x4ca92f75, S=1, 1024, 0xc2f67c9f
+0, 68, 68, 1, 131, 0xf4193bc0, S=1, 1024, 0xc2f67c9f
+0, 69, 69, 1, 115, 0xda5e2f30, S=1, 1024, 0xc2f67c9f
+0, 70, 70, 1, 100, 0x9ba32a58, S=1, 1024, 0xc2f67c9f
+0, 71, 71, 1, 109, 0xa47e2c91, S=1, 1024, 0xc2f67c9f
+0, 72, 72, 1, 120, 0x22452fd6, S=1, 1024, 0xc2f67c9f
+0, 73, 73, 1, 116, 0xd3c52c26, S=1, 1024, 0xc2f67c9f
+0, 74, 74, 1, 106, 0x95b42c9f, S=1, 1024, 0xc2f67c9f
+0, 75, 75, 1, 96, 0xfdc12639, S=1, 1024, 0xc2f67c9f
+0, 76, 76, 1, 99, 0x210f251b, S=1, 1024, 0xc2f67c9f
+0, 77, 77, 1, 119, 0x173b341c, S=1, 1024, 0xc2f67c9f
+0, 78, 78, 1, 119, 0x3bca2f29, S=1, 1024, 0xc2f67c9f
+0, 79, 79, 1, 213, 0x9e905d4c, S=1, 1024, 0xc2f67c9f
+0, 80, 80, 1, 209, 0xa0015e94, S=1, 1024, 0xc2f67c9f
+0, 81, 81, 1, 120, 0x36762bd4, S=1, 1024, 0xc2f67c9f
+0, 82, 82, 1, 119, 0x019b2edc, S=1, 1024, 0xc2f67c9f
+0, 83, 83, 1, 124, 0x211d30e7, S=1, 1024, 0xc2f67c9f
+0, 84, 84, 1, 125, 0x538732ff, S=1, 1024, 0xc2f67c9f
+0, 85, 85, 1, 123, 0x2887308a, S=1, 1024, 0xc2f67c9f
+0, 86, 86, 1, 119, 0x7ff930f4, S=1, 1024, 0xc2f67c9f
+0, 87, 87, 1, 119, 0xa50c2e16, S=1, 1024, 0xc2f67c9f
+0, 88, 88, 1, 107, 0x9ed02cea, S=1, 1024, 0xc2f67c9f
+0, 89, 89, 1, 119, 0xc234332a, S=1, 1024, 0xc2f67c9f
+0, 90, 90, 1, 115, 0x38353092, S=1, 1024, 0xc2f67c9f
+0, 91, 91, 1, 162, 0x6cda4644, S=1, 1024, 0xc2f67c9f
+0, 92, 92, 1, 124, 0x2f683081, S=1, 1024, 0xc2f67c9f
+0, 93, 93, 1, 116, 0x72952d04, S=1, 1024, 0xc2f67c9f
+0, 94, 94, 1, 84, 0x1a532301, S=1, 1024, 0xc2f67c9f
+0, 95, 95, 1, 176, 0xfb3c5400, S=1, 1024, 0xc2f67c9f
+0, 96, 96, 1, 137, 0x253132d1, S=1, 1024, 0xc2f67c9f
+0, 97, 97, 1, 179, 0x2b38528b, S=1, 1024, 0xc2f67c9f
+0, 98, 98, 1, 150, 0xbe413cbe, S=1, 1024, 0xc2f67c9f
+0, 99, 99, 1, 140, 0x9e93392a, S=1, 1024, 0xc2f67c9f
+0, 100, 100, 1, 129, 0x577e331e, S=1, 1024, 0xc2f67c9f
+0, 101, 101, 1, 146, 0x16ff3924, S=1, 1024, 0xc2f67c9f
+0, 102, 102, 1, 133, 0x756a3163, S=1, 1024, 0xc2f67c9f
+0, 103, 103, 1, 190, 0x3e865b77, S=1, 1024, 0xc2f67c9f
+0, 104, 104, 1, 159, 0xdf393fc8, S=1, 1024, 0xc2f67c9f
+0, 105, 105, 1, 188, 0x84be5168, S=1, 1024, 0xc2f67c9f
+0, 106, 106, 1, 163, 0x4c0e41f0, S=1, 1024, 0xc2f67c9f
+0, 107, 107, 1, 144, 0x5fda3792, S=1, 1024, 0xc2f67c9f
+0, 108, 108, 1, 136, 0x028c3800, S=1, 1024, 0xc2f67c9f
+0, 109, 109, 1, 150, 0x75d43a8d, S=1, 1024, 0xc2f67c9f
+0, 110, 110, 1, 134, 0x81123999, S=1, 1024, 0xc2f67c9f
+0, 111, 111, 1, 198, 0x0a875baa, S=1, 1024, 0xc2f67c9f
+0, 112, 112, 1, 169, 0xfdd7458c, S=1, 1024, 0xc2f67c9f
+0, 113, 113, 1, 210, 0x9b195be4, S=1, 1024, 0xc2f67c9f
+0, 114, 114, 1, 174, 0x0a424a76, S=1, 1024, 0xc2f67c9f
+0, 115, 115, 1, 137, 0xb1b535fd, S=1, 1024, 0xc2f67c9f
+0, 116, 116, 1, 122, 0x4d3f327b, S=1, 1024, 0xc2f67c9f
+0, 117, 117, 1, 152, 0x5e423b0c, S=1, 1024, 0xc2f67c9f
+0, 118, 118, 1, 137, 0xd13a39f7, S=1, 1024, 0xc2f67c9f
+0, 119, 119, 1, 156, 0x40864321, S=1, 1024, 0xc2f67c9f
+0, 120, 120, 1, 140, 0xbe1e393c, S=1, 1024, 0xc2f67c9f
+0, 121, 121, 1, 179, 0xaf204635, S=1, 1024, 0xc2f67c9f
+0, 122, 122, 1, 116, 0x5ac83123, S=1, 1024, 0xc2f67c9f
+0, 123, 123, 1, 118, 0x22bc2ec5, S=1, 1024, 0xc2f67c9f
+0, 124, 124, 1, 123, 0xc9b5302d, S=1, 1024, 0xc2f67c9f
+0, 125, 125, 1, 125, 0x5cee3077, S=1, 1024, 0xc2f67c9f
+0, 126, 126, 1, 194, 0xccc159ca, S=1, 1024, 0xc2f67c9f
+0, 127, 127, 1, 122, 0x4d243229, S=1, 1024, 0xc2f67c9f
+0, 128, 128, 1, 124, 0x948f330b, S=1, 1024, 0xc2f67c9f
+0, 129, 129, 1, 133, 0xd53c35ca, S=1, 1024, 0xc2f67c9f
+0, 130, 130, 1, 126, 0xc5543710, S=1, 1024, 0xc2f67c9f
+0, 131, 131, 1, 208, 0x6cf15ea2, S=1, 1024, 0xc2f67c9f
+0, 132, 132, 1, 131, 0xa8d33505, S=1, 1024, 0xc2f67c9f
+0, 133, 133, 1, 114, 0x0ae53001, S=1, 1024, 0xc2f67c9f
+0, 134, 134, 1, 129, 0xe9ff37c4, S=1, 1024, 0xc2f67c9f
+0, 135, 135, 1, 120, 0x02623359, S=1, 1024, 0xc2f67c9f
+0, 136, 136, 1, 164, 0x9dc545e5, S=1, 1024, 0xc2f67c9f
+0, 137, 137, 1, 245, 0xc170715a, S=1, 1024, 0xc2f67c9f
+0, 138, 138, 1, 215, 0xc93d5fbe, S=1, 1024, 0xc2f67c9f
+0, 139, 139, 1, 225, 0x14866349, S=1, 1024, 0xc2f67c9f
+0, 140, 140, 1, 123, 0x70cd2b64, S=1, 1024, 0xc2f67c9f
+0, 141, 141, 1, 124, 0xe9002fb5, S=1, 1024, 0xc2f67c9f
+0, 142, 142, 1, 125, 0x106e309b, S=1, 1024, 0xc2f67c9f
+0, 143, 143, 1, 122, 0x050e32b0, S=1, 1024, 0xc2f67c9f
+0, 144, 144, 1, 224, 0xf548614f, S=1, 1024, 0xc2f67c9f
+0, 145, 145, 1, 239, 0x125c6ade, S=1, 1024, 0xc2f67c9f
+0, 146, 146, 1, 127, 0x398734b6, S=1, 1024, 0xc2f67c9f
+0, 147, 147, 1, 126, 0x2ff431e5, S=1, 1024, 0xc2f67c9f
+0, 148, 148, 1, 124, 0x9583313b, S=1, 1024, 0xc2f67c9f
+0, 149, 149, 1, 126, 0xc1fc3692, S=1, 1024, 0xc2f67c9f
+0, 150, 150, 1, 123, 0xd0bf3170, S=1, 1024, 0xc2f67c9f
+0, 151, 151, 1, 117, 0x651f3032, S=1, 1024, 0xc2f67c9f
+0, 152, 152, 1, 119, 0x268a3078, S=1, 1024, 0xc2f67c9f
+0, 153, 153, 1, 117, 0x9e4d3283, S=1, 1024, 0xc2f67c9f
+0, 154, 154, 1, 149, 0x8f1043ba, S=1, 1024, 0xc2f67c9f
+0, 155, 155, 1, 127, 0x352338bc, S=1, 1024, 0xc2f67c9f
+0, 156, 156, 1, 113, 0xf877314e, S=1, 1024, 0xc2f67c9f
+0, 157, 157, 1, 128, 0x88103a62, S=1, 1024, 0xc2f67c9f
+0, 158, 158, 1, 111, 0xbf0630d9, S=1, 1024, 0xc2f67c9f
+0, 159, 159, 1, 146, 0x159c44f7, S=1, 1024, 0xc2f67c9f
+0, 160, 160, 1, 237, 0x4e45662e, S=1, 1024, 0xc2f67c9f
+0, 161, 161, 1, 233, 0x8f9e6354, S=1, 1024, 0xc2f67c9f
+0, 162, 162, 1, 160, 0x9c3f431f, S=1, 1024, 0xc2f67c9f
+0, 163, 163, 1, 125, 0xbd2b33c6, S=1, 1024, 0xc2f67c9f
+0, 164, 164, 1, 131, 0x3ecd3ba5, S=1, 1024, 0xc2f67c9f
+0, 165, 165, 1, 231, 0xdf286db6, S=1, 1024, 0xc2f67c9f
+0, 166, 166, 1, 153, 0xb6da408d, S=1, 1024, 0xc2f67c9f
+0, 167, 167, 1, 126, 0x6741365e, S=1, 1024, 0xc2f67c9f
+0, 168, 168, 1, 113, 0x658f2c90, S=1, 1024, 0xc2f67c9f
+0, 169, 169, 1, 125, 0xc0033320, S=1, 1024, 0xc2f67c9f
+0, 170, 170, 1, 122, 0xe38a2db1, S=1, 1024, 0xc2f67c9f
+0, 171, 171, 1, 145, 0x29d63e83, S=1, 1024, 0xc2f67c9f
+0, 172, 172, 1, 171, 0xc0e44b70, S=1, 1024, 0xc2f67c9f
diff --git a/tests/ref/fate/gifenc-pal8 b/tests/ref/fate/gifenc-pal8
new file mode 100644
index 0000000000..a84efa0a06
--- /dev/null
+++ b/tests/ref/fate/gifenc-pal8
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 552, 0x271a2dd3, S=1, 1024, 0xec907a9e
+0, 1, 1, 1, 297, 0x90168a95, S=1, 1024, 0xf351799f
+0, 2, 2, 1, 438, 0x91efce1b, S=1, 1024, 0xf351799f
+0, 3, 3, 1, 450, 0x7c2dcfad, S=1, 1024, 0xf351799f
+0, 4, 4, 1, 547, 0xc131fd3b, S=1, 1024, 0xf351799f
+0, 5, 5, 1, 614, 0x68182006, S=1, 1024, 0xf351799f
+0, 6, 6, 1, 642, 0x78bb1f5f, S=1, 1024, 0xf351799f
+0, 7, 7, 1, 660, 0x35c033a2, S=1, 1024, 0xf351799f
+0, 8, 8, 1, 821, 0xaf30790b, S=1, 1024, 0xf351799f
+0, 9, 9, 1, 1157, 0x741c2da1, S=1, 1024, 0xf351799f
+0, 10, 10, 1, 179, 0x3a27517c, S=1, 1024, 0xf351799f
+0, 11, 11, 1, 1333, 0x5ee76f3c, S=1, 1024, 0xf351799f
+0, 12, 12, 1, 1638, 0x5f640e86, S=1, 1024, 0xf351799f
+0, 13, 13, 1, 1531, 0xccb8e437, S=1, 1024, 0xf351799f
+0, 14, 14, 1, 1720, 0xc95d45ec, S=1, 1024, 0xf351799f
+0, 15, 15, 1, 1910, 0x56cc831e, S=1, 1024, 0xf351799f
+0, 16, 16, 1, 2124, 0x9cc8e130, S=1, 1024, 0xf351799f
+0, 17, 17, 1, 2248, 0x05a325b1, S=1, 1024, 0xf351799f
+0, 18, 18, 1, 2311, 0xdc633703, S=1, 1024, 0xf351799f
+0, 19, 19, 1, 2408, 0x91c26f3e, S=1, 1024, 0xf351799f
+0, 20, 20, 1, 2601, 0x8cf3c157, S=1, 1024, 0xf351799f
+0, 21, 21, 1, 2687, 0x8f6400e6, S=1, 1024, 0xf351799f
+0, 22, 22, 1, 2784, 0xaa880e55, S=1, 1024, 0xf351799f
+0, 23, 23, 1, 2884, 0x46f546f6, S=1, 1024, 0xf351799f
+0, 24, 24, 1, 2982, 0x807c7ad5, S=1, 1024, 0xf351799f
+0, 25, 25, 1, 3101, 0xbcc89bec, S=1, 1024, 0xf351799f
+0, 26, 26, 1, 3253, 0xd032f3fa, S=1, 1024, 0xf351799f
+0, 27, 27, 1, 3329, 0xe4d42430, S=1, 1024, 0xf351799f
+0, 28, 28, 1, 3572, 0xf8058aa0, S=1, 1024, 0xf351799f
+0, 29, 29, 1, 3807, 0x3d2af9f3, S=1, 1024, 0xf351799f
+0, 30, 30, 1, 2750, 0x814d1c33, S=1, 1024, 0xf351799f
+0, 31, 31, 1, 4031, 0x3b077006, S=1, 1024, 0xf351799f
+0, 32, 32, 1, 3025, 0x86729c1c, S=1, 1024, 0xf351799f
+0, 33, 33, 1, 4295, 0xf71b0b38, S=1, 1024, 0xf351799f
+0, 34, 34, 1, 2044, 0x5adcb93b, S=1, 1024, 0xf351799f
+0, 35, 35, 1, 3212, 0xcf79eeed, S=1, 1024, 0xf351799f
+0, 36, 36, 1, 2292, 0xb4386334, S=1, 1024, 0xf351799f
+0, 37, 37, 1, 3633, 0x0010992f, S=1, 1024, 0xf351799f
+0, 38, 38, 1, 3552, 0x23697490, S=1, 1024, 0xf351799f
+0, 39, 39, 1, 3690, 0x62afdbb8, S=1, 1024, 0xf351799f
+0, 40, 40, 1, 1559, 0x5baef54a, S=1, 1024, 0xf351799f
+0, 41, 41, 1, 954, 0xca75ca79, S=1, 1024, 0xf351799f
+0, 42, 42, 1, 273, 0x3687799b, S=1, 1024, 0xf351799f
+0, 43, 43, 1, 930, 0x29f3b0c4, S=1, 1024, 0xf351799f
+0, 44, 44, 1, 271, 0x305e8094, S=1, 1024, 0xf351799f
+0, 45, 45, 1, 196, 0xf5ab51ee, S=1, 1024, 0xf351799f
+0, 46, 46, 1, 4299, 0x67ec0d55, S=1, 1024, 0xf351799f
+0, 47, 47, 1, 4895, 0xb394406c, S=1, 1024, 0xf351799f
+0, 48, 48, 1, 4928, 0x233919d7, S=1, 1024, 0xf351799f
+0, 49, 49, 1, 4941, 0x58a357da, S=1, 1024, 0xf351799f
+0, 50, 50, 1, 4154, 0x21f2ac33, S=1, 1024, 0xf351799f
+0, 51, 51, 1, 4678, 0xab3cc050, S=1, 1024, 0xf351799f
+0, 52, 52, 1, 4741, 0x1974b581, S=1, 1024, 0xf351799f
+0, 53, 53, 1, 4982, 0x891456d5, S=1, 1024, 0xf351799f
+0, 54, 54, 1, 5179, 0x860fc6a1, S=1, 1024, 0xf351799f
+0, 55, 55, 1, 5046, 0xce9183d3, S=1, 1024, 0xf351799f
+0, 56, 56, 1, 5140, 0xa6d7b9af, S=1, 1024, 0xf351799f
+0, 57, 57, 1, 4301, 0x03b6ef3f, S=1, 1024, 0xf351799f
+0, 58, 58, 1, 5079, 0xa8d59e01, S=1, 1024, 0xf351799f
+0, 59, 59, 1, 5284, 0xea34e3b3, S=1, 1024, 0xf351799f
+0, 60, 60, 1, 5426, 0x556a15cd, S=1, 1024, 0xf351799f
+0, 61, 61, 1, 4645, 0x061e8936, S=1, 1024, 0xf351799f
+0, 62, 62, 1, 5263, 0x7536cf7d, S=1, 1024, 0xf351799f
+0, 63, 63, 1, 5221, 0x9fbac3ca, S=1, 1024, 0xf351799f
+0, 64, 64, 1, 5217, 0x02269bd2, S=1, 1024, 0xf351799f
+0, 65, 65, 1, 5395, 0x120fff66, S=1, 1024, 0xf351799f
+0, 66, 66, 1, 5220, 0x77cedcc5, S=1, 1024, 0xf351799f
+0, 67, 67, 1, 5704, 0xba42dd96, S=1, 1024, 0xf351799f
+0, 68, 68, 1, 5636, 0xcb91a25b, S=1, 1024, 0xf351799f
+0, 69, 69, 1, 5818, 0x8dc0df92, S=1, 1024, 0xf351799f
+0, 70, 70, 1, 5763, 0x51d5d5f0, S=1, 1024, 0xf351799f
+0, 71, 71, 1, 6116, 0x09558b48, S=1, 1024, 0xf351799f
+0, 72, 72, 1, 6069, 0x41926817, S=1, 1024, 0xf351799f
+0, 73, 73, 1, 5796, 0x7fbeda44, S=1, 1024, 0xf351799f
+0, 74, 74, 1, 5999, 0xe07d3770, S=1, 1024, 0xf351799f
+0, 75, 75, 1, 6220, 0x6607b06f, S=1, 1024, 0xf351799f
+0, 76, 76, 1, 6374, 0x7628e533, S=1, 1024, 0xf351799f
+0, 77, 77, 1, 6465, 0xfe956b15, S=1, 1024, 0xf351799f
+0, 78, 78, 1, 7019, 0x6c9a1aef, S=1, 1024, 0xf351799f
+0, 79, 79, 1, 7255, 0x5fa5c1bf, S=1, 1024, 0xf351799f
+0, 80, 80, 1, 8197, 0xf11d6ef2, S=1, 1024, 0xf351799f
+0, 81, 81, 1, 8358, 0x027279e8, S=1, 1024, 0xf351799f
+0, 82, 82, 1, 7708, 0x607f8e8b, S=1, 1024, 0xf351799f
+0, 83, 83, 1, 7412, 0x6bb2105f, S=1, 1024, 0xf351799f
+0, 84, 84, 1, 7541, 0xfdc02154, S=1, 1024, 0xf351799f
+0, 85, 85, 1, 7948, 0x916ecd8b, S=1, 1024, 0xf351799f
+0, 86, 86, 1, 8408, 0x1f97d414, S=1, 1024, 0xf351799f
+0, 87, 87, 1, 8056, 0x9cbf159c, S=1, 1024, 0xf351799f
+0, 88, 88, 1, 7401, 0x2625addb, S=1, 1024, 0xf351799f
+0, 89, 89, 1, 7494, 0x2877eacb, S=1, 1024, 0xf351799f
+0, 90, 90, 1, 7806, 0xe32574a3, S=1, 1024, 0xf351799f
+0, 91, 91, 1, 7768, 0x25ed7ee7, S=1, 1024, 0xf351799f
+0, 92, 92, 1, 7749, 0x6d8e978e, S=1, 1024, 0xf351799f
+0, 93, 93, 1, 8047, 0xec4b150c, S=1, 1024, 0xf351799f
+0, 94, 94, 1, 7618, 0x88cf30d5, S=1, 1024, 0xf351799f
+0, 95, 95, 1, 7979, 0x0eb1cf2a, S=1, 1024, 0xf351799f
+0, 96, 96, 1, 12062, 0xb49d9125, S=1, 1024, 0xf351799f
+0, 97, 97, 1, 12317, 0x2d8fd6e9, S=1, 1024, 0xf351799f
+0, 98, 98, 1, 12217, 0x9b3be549, S=1, 1024, 0xf351799f
+0, 99, 99, 1, 11227, 0x067e9118, S=1, 1024, 0xf351799f
+0, 100, 100, 1, 11108, 0x5e5b0afd, S=1, 1024, 0xf351799f
+0, 101, 101, 1, 11366, 0xb38e8d15, S=1, 1024, 0xf351799f
+0, 102, 102, 1, 11896, 0xeb3e35ca, S=1, 1024, 0xf351799f
+0, 103, 103, 1, 11479, 0xbf7581e9, S=1, 1024, 0xf351799f
+0, 104, 104, 1, 13395, 0x415b38d8, S=1, 1024, 0xf351799f
+0, 105, 105, 1, 12913, 0x61544631, S=1, 1024, 0xf351799f
+0, 106, 106, 1, 13864, 0xd39fe768, S=1, 1024, 0xf351799f
+0, 107, 107, 1, 13551, 0x76c167d1, S=1, 1024, 0xf351799f
+0, 108, 108, 1, 14041, 0x2f206888, S=1, 1024, 0xf351799f
+0, 109, 109, 1, 14144, 0x9ec030d3, S=1, 1024, 0xf351799f
+0, 110, 110, 1, 14277, 0xa84b3a9b, S=1, 1024, 0xf351799f
+0, 111, 111, 1, 14424, 0xf5f1e06e, S=1, 1024, 0xf351799f
+0, 112, 112, 1, 14689, 0xbca0adb5, S=1, 1024, 0xf351799f
+0, 113, 113, 1, 14598, 0xc1d45745, S=1, 1024, 0xf351799f
+0, 114, 114, 1, 15213, 0x8f3080fc, S=1, 1024, 0xf351799f
+0, 115, 115, 1, 15425, 0xb0aa8f59, S=1, 1024, 0xf351799f
+0, 116, 116, 1, 15595, 0x1406e5d5, S=1, 1024, 0xf351799f
+0, 117, 117, 1, 15598, 0x48ec7d08, S=1, 1024, 0xf351799f
+0, 118, 118, 1, 15863, 0x5381db7b, S=1, 1024, 0xf351799f
+0, 119, 119, 1, 15717, 0xb87a1b87, S=1, 1024, 0xf351799f
+0, 120, 120, 1, 16078, 0x5bab2453, S=1, 1024, 0xf351799f
+0, 121, 121, 1, 16225, 0xa1f88113, S=1, 1024, 0xf351799f
+0, 122, 122, 1, 16135, 0x6af2f4e1, S=1, 1024, 0xf351799f
+0, 123, 123, 1, 16661, 0xf02a3343, S=1, 1024, 0xf351799f
+0, 124, 124, 1, 16619, 0xc71935a4, S=1, 1024, 0xf351799f
+0, 125, 125, 1, 16829, 0x29849844, S=1, 1024, 0xf351799f
+0, 126, 126, 1, 16944, 0x3423ae77, S=1, 1024, 0xf351799f
+0, 127, 127, 1, 17119, 0x609b4409, S=1, 1024, 0xf351799f
+0, 128, 128, 1, 17150, 0xf85dfd31, S=1, 1024, 0xf351799f
+0, 129, 129, 1, 17321, 0x38eccb10, S=1, 1024, 0xf351799f
+0, 130, 130, 1, 17395, 0x0ba08b85, S=1, 1024, 0xf351799f
+0, 131, 131, 1, 17666, 0x6fbc0264, S=1, 1024, 0xf351799f
+0, 132, 132, 1, 17730, 0x3dcc64a6, S=1, 1024, 0xf351799f
+0, 133, 133, 1, 17934, 0xb539974b, S=1, 1024, 0xf351799f
+0, 134, 134, 1, 17944, 0x2214ec94, S=1, 1024, 0xf351799f
+0, 135, 135, 1, 18238, 0x70f9ff1d, S=1, 1024, 0xf351799f
+0, 136, 136, 1, 18391, 0x4b149209, S=1, 1024, 0xf351799f
+0, 137, 137, 1, 18543, 0x45a1c02f, S=1, 1024, 0xf351799f
+0, 138, 138, 1, 18939, 0x2789a88c, S=1, 1024, 0xf351799f
+0, 139, 139, 1, 19145, 0x5daafd7a, S=1, 1024, 0xf351799f
+0, 140, 140, 1, 19120, 0x565f80e6, S=1, 1024, 0xf351799f
+0, 141, 141, 1, 19130, 0xff70cc21, S=1, 1024, 0xf351799f
+0, 142, 142, 1, 19494, 0xbfa284db, S=1, 1024, 0xf351799f
+0, 143, 143, 1, 19534, 0x3d40743b, S=1, 1024, 0xf351799f
+0, 144, 144, 1, 19747, 0x33c9b108, S=1, 1024, 0xf351799f
+0, 145, 145, 1, 20114, 0x9d223e36, S=1, 1024, 0xf351799f
+0, 146, 146, 1, 20257, 0xe7bdaf43, S=1, 1024, 0xf351799f
+0, 147, 147, 1, 20370, 0x0c5f1970, S=1, 1024, 0xf351799f
+0, 148, 148, 1, 20292, 0x6986d20e, S=1, 1024, 0xf351799f
+0, 149, 149, 1, 20491, 0xd88e4c08, S=1, 1024, 0xf351799f
+0, 150, 150, 1, 20647, 0x1aefaffc, S=1, 1024, 0xf351799f
+0, 151, 151, 1, 20666, 0x43e4aaaa, S=1, 1024, 0xf351799f
+0, 152, 152, 1, 21007, 0xa7ca3ef0, S=1, 1024, 0xf351799f
+0, 153, 153, 1, 21058, 0x06814351, S=1, 1024, 0xf351799f
+0, 154, 154, 1, 21153, 0x3c852b10, S=1, 1024, 0xf351799f
+0, 155, 155, 1, 21078, 0x8df15855, S=1, 1024, 0xf351799f
+0, 156, 156, 1, 21458, 0xd3a531d6, S=1, 1024, 0xf351799f
+0, 157, 157, 1, 21669, 0x88baca53, S=1, 1024, 0xf351799f
+0, 158, 158, 1, 21581, 0xd692fa1f, S=1, 1024, 0xf351799f
+0, 159, 159, 1, 21654, 0x30fb9061, S=1, 1024, 0xf351799f
+0, 160, 160, 1, 21987, 0xe7646d8b, S=1, 1024, 0xf351799f
+0, 161, 161, 1, 22205, 0x0fc55b6a, S=1, 1024, 0xf351799f
+0, 162, 162, 1, 22475, 0x4bc4c032, S=1, 1024, 0xf351799f
+0, 163, 163, 1, 22490, 0x58ca23f6, S=1, 1024, 0xf351799f
+0, 164, 164, 1, 22460, 0xf9ceb0ac, S=1, 1024, 0xf351799f
+0, 165, 165, 1, 22861, 0xb05f0f84, S=1, 1024, 0xf351799f
+0, 166, 166, 1, 22746, 0x0df23a5c, S=1, 1024, 0xf351799f
+0, 167, 167, 1, 23165, 0xbd7147ad, S=1, 1024, 0xf351799f
+0, 168, 168, 1, 23273, 0x9781a34f, S=1, 1024, 0xf351799f
+0, 169, 169, 1, 23211, 0x69c7606b, S=1, 1024, 0xf351799f
+0, 170, 170, 1, 23648, 0xdafde037, S=1, 1024, 0xf351799f
+0, 171, 171, 1, 23675, 0x2a2147ed, S=1, 1024, 0xf351799f
+0, 172, 172, 1, 23874, 0x12c184b6, S=1, 1024, 0xf351799f
diff --git a/tests/ref/fate/gifenc-rgb4_byte b/tests/ref/fate/gifenc-rgb4_byte
new file mode 100644
index 0000000000..9b00103c65
--- /dev/null
+++ b/tests/ref/fate/gifenc-rgb4_byte
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 508, 0xf04a113b
+0, 1, 1, 1, 213, 0x23c24d3d, S=1, 1024, 0xf7700427
+0, 2, 2, 1, 131, 0x56d22a39, S=1, 1024, 0x03730427
+0, 3, 3, 1, 384, 0xb1d8a4bd, S=1, 1024, 0xf7700427
+0, 4, 4, 1, 381, 0x37a3a2c9, S=1, 1024, 0xf3740427
+0, 5, 5, 1, 430, 0x162bb3d3, S=1, 1024, 0xf3740427
+0, 6, 6, 1, 518, 0x195bd738, S=1, 1024, 0xf3740427
+0, 7, 7, 1, 535, 0x12cde6b7, S=1, 1024, 0xf3740427
+0, 8, 8, 1, 438, 0xa653b946, S=1, 1024, 0x0b6b0427
+0, 9, 9, 1, 923, 0xd2e2a35f, S=1, 1024, 0x0b6b0427
+0, 10, 10, 1, 694, 0xe1cf4a1f, S=1, 1024, 0x0b6b0427
+0, 11, 11, 1, 1194, 0xa6152c8a, S=1, 1024, 0x0b6b0427
+0, 12, 12, 1, 1291, 0x94d25581, S=1, 1024, 0x0b6b0427
+0, 13, 13, 1, 1245, 0x5b483525, S=1, 1024, 0x0b6b0427
+0, 14, 14, 1, 1330, 0xfb5351c8, S=1, 1024, 0x0b6b0427
+0, 15, 15, 1, 1276, 0x6f403914, S=1, 1024, 0x0b6b0427
+0, 16, 16, 1, 1475, 0xbf459755, S=1, 1024, 0x0b6b0427
+0, 17, 17, 1, 1784, 0xe9954aa7, S=1, 1024, 0xecb30526
+0, 18, 18, 1, 1675, 0x219dfaf8, S=1, 1024, 0xecb30526
+0, 19, 19, 1, 1509, 0xd7f5abbe, S=1, 1024, 0xecb30526
+0, 20, 20, 1, 1705, 0x44a01729, S=1, 1024, 0xecb30526
+0, 21, 21, 1, 1745, 0x31ff1f89, S=1, 1024, 0xecb30526
+0, 22, 22, 1, 1642, 0x55420147, S=1, 1024, 0xecb30526
+0, 23, 23, 1, 1718, 0x68ef1cb8, S=1, 1024, 0xecb30526
+0, 24, 24, 1, 1900, 0xd7737a09, S=1, 1024, 0xecb30526
+0, 25, 25, 1, 1807, 0x4f6c5140, S=1, 1024, 0xecb30526
+0, 26, 26, 1, 1915, 0x976d80e6, S=1, 1024, 0xecb30526
+0, 27, 27, 1, 2100, 0x0ae6d1ce, S=1, 1024, 0xecb30526
+0, 28, 28, 1, 2700, 0x7a89f104, S=1, 1024, 0xecb30526
+0, 29, 29, 1, 2673, 0xf6b6a71d, S=1, 1024, 0xecb30526
+0, 30, 30, 1, 2895, 0x9079484b, S=1, 1024, 0xecb30526
+0, 31, 31, 1, 3257, 0x0b0cd125, S=1, 1024, 0xecb30526
+0, 32, 32, 1, 3179, 0x3ee2c161, S=1, 1024, 0xecb30526
+0, 33, 33, 1, 3296, 0x6230e506, S=1, 1024, 0xecb30526
+0, 34, 34, 1, 3600, 0x021775d7, S=1, 1024, 0xecb30526
+0, 35, 35, 1, 3699, 0xfb03a043, S=1, 1024, 0xecb30526
+0, 36, 36, 1, 3814, 0x96a8d57e, S=1, 1024, 0xecb30526
+0, 37, 37, 1, 3627, 0x33a37f8f, S=1, 1024, 0xecb30526
+0, 38, 38, 1, 2950, 0x50806197, S=1, 1024, 0xecb30526
+0, 39, 39, 1, 3086, 0x72068d4c, S=1, 1024, 0xecb30526
+0, 40, 40, 1, 3094, 0x2880861f, S=1, 1024, 0xecb30526
+0, 41, 41, 1, 3456, 0x6d232a96, S=1, 1024, 0xecb30526
+0, 42, 42, 1, 4108, 0x46d75ebb, S=1, 1024, 0xecb30526
+0, 43, 43, 1, 4217, 0x04a258f4, S=1, 1024, 0xecb30526
+0, 44, 44, 1, 3613, 0x667f4ff8, S=1, 1024, 0xecb30526
+0, 45, 45, 1, 3910, 0x8f37e73e, S=1, 1024, 0xecb30526
+0, 46, 46, 1, 4461, 0x5db9e0bf, S=1, 1024, 0xecb30526
+0, 47, 47, 1, 4593, 0x883f2f49, S=1, 1024, 0xecb30526
+0, 48, 48, 1, 4822, 0x03d99b73, S=1, 1024, 0xecb30526
+0, 49, 49, 1, 5398, 0x39f7bff4, S=1, 1024, 0xecb30526
+0, 50, 50, 1, 5266, 0xd5ab9630, S=1, 1024, 0xecb30526
+0, 51, 51, 1, 5416, 0x5876e16f, S=1, 1024, 0xecb30526
+0, 52, 52, 1, 5519, 0x30ed05d8, S=1, 1024, 0xecb30526
+0, 53, 53, 1, 5701, 0x5bae5af7, S=1, 1024, 0xecb30526
+0, 54, 54, 1, 6160, 0x98364177, S=1, 1024, 0xecb30526
+0, 55, 55, 1, 6233, 0x52a05075, S=1, 1024, 0xecb30526
+0, 56, 56, 1, 5911, 0x04bfc46a, S=1, 1024, 0xecb30526
+0, 57, 57, 1, 5997, 0xf1e6f586, S=1, 1024, 0xecb30526
+0, 58, 58, 1, 5946, 0xe6f3f055, S=1, 1024, 0xecb30526
+0, 59, 59, 1, 6468, 0xc8a3cf61, S=1, 1024, 0xecb30526
+0, 60, 60, 1, 6737, 0xc27b3b79, S=1, 1024, 0xecb30526
+0, 61, 61, 1, 6275, 0x84d88e2b, S=1, 1024, 0xecb30526
+0, 62, 62, 1, 6641, 0xb44b3534, S=1, 1024, 0xecb30526
+0, 63, 63, 1, 6378, 0x3965888b, S=1, 1024, 0xecb30526
+0, 64, 64, 1, 6257, 0x12115750, S=1, 1024, 0xecb30526
+0, 65, 65, 1, 6908, 0x57137217, S=1, 1024, 0xecb30526
+0, 66, 66, 1, 7230, 0xbacc24ee, S=1, 1024, 0xecb30526
+0, 67, 67, 1, 7556, 0x1aa2a694, S=1, 1024, 0xecb30526
+0, 68, 68, 1, 7413, 0xbc9e7718, S=1, 1024, 0xecb30526
+0, 69, 69, 1, 7476, 0xb2a1aba0, S=1, 1024, 0xecb30526
+0, 70, 70, 1, 7596, 0x3301e56d, S=1, 1024, 0xecb30526
+0, 71, 71, 1, 7756, 0x8f2504f8, S=1, 1024, 0xecb30526
+0, 72, 72, 1, 8015, 0xd4146c80, S=1, 1024, 0xecb30526
+0, 73, 73, 1, 8128, 0x11b2bf4c, S=1, 1024, 0xecb30526
+0, 74, 74, 1, 8101, 0xc627adbe, S=1, 1024, 0xecb30526
+0, 75, 75, 1, 7863, 0xe99f3f3b, S=1, 1024, 0xecb30526
+0, 76, 76, 1, 7960, 0x4bc091b8, S=1, 1024, 0xecb30526
+0, 77, 77, 1, 8238, 0x1086ea8a, S=1, 1024, 0xecb30526
+0, 78, 78, 1, 8321, 0x3a404791, S=1, 1024, 0xecb30526
+0, 79, 79, 1, 8562, 0xcbdcc01e, S=1, 1024, 0xecb30526
+0, 80, 80, 1, 8746, 0xec190b22, S=1, 1024, 0xecb30526
+0, 81, 81, 1, 8578, 0x12e7a4e8, S=1, 1024, 0xecb30526
+0, 82, 82, 1, 8878, 0x51c05771, S=1, 1024, 0xecb30526
+0, 83, 83, 1, 9077, 0xe12b589b, S=1, 1024, 0xecb30526
+0, 84, 84, 1, 9310, 0xde3bf881, S=1, 1024, 0xecb30526
+0, 85, 85, 1, 9394, 0x1eba46cc, S=1, 1024, 0xecb30526
+0, 86, 86, 1, 9161, 0x7c359911, S=1, 1024, 0xecb30526
+0, 87, 87, 1, 9462, 0xccda3664, S=1, 1024, 0xecb30526
+0, 88, 88, 1, 9650, 0x6e6292fc, S=1, 1024, 0xecb30526
+0, 89, 89, 1, 9701, 0x08909b95, S=1, 1024, 0xecb30526
+0, 90, 90, 1, 9523, 0xe61b38bb, S=1, 1024, 0xecb30526
+0, 91, 91, 1, 9891, 0x96b90b98, S=1, 1024, 0xecb30526
+0, 92, 92, 1, 10005, 0x2db84c80, S=1, 1024, 0xecb30526
+0, 93, 93, 1, 10038, 0x37e52a72, S=1, 1024, 0xecb30526
+0, 94, 94, 1, 10086, 0x135a43e4, S=1, 1024, 0xecb30526
+0, 95, 95, 1, 10438, 0x472c0372, S=1, 1024, 0xecb30526
+0, 96, 96, 1, 10583, 0xcf4c5862, S=1, 1024, 0xecb30526
+0, 97, 97, 1, 10581, 0xce658137, S=1, 1024, 0xecb30526
+0, 98, 98, 1, 10807, 0x3954dad9, S=1, 1024, 0xecb30526
+0, 99, 99, 1, 11111, 0x5f8d504f, S=1, 1024, 0xecb30526
+0, 100, 100, 1, 11194, 0x3c7e6a77, S=1, 1024, 0xecb30526
+0, 101, 101, 1, 11240, 0x5112a0a3, S=1, 1024, 0xecb30526
+0, 102, 102, 1, 11483, 0xaf10f4fa, S=1, 1024, 0xecb30526
+0, 103, 103, 1, 11680, 0x44a25971, S=1, 1024, 0xecb30526
+0, 104, 104, 1, 11785, 0x7350b5db, S=1, 1024, 0xecb30526
+0, 105, 105, 1, 11436, 0xe3170ad5, S=1, 1024, 0xecb30526
+0, 106, 106, 1, 11928, 0x13d8c885, S=1, 1024, 0xecb30526
+0, 107, 107, 1, 11932, 0xecb5bdf7, S=1, 1024, 0xecb30526
+0, 108, 108, 1, 12281, 0x18bb76d5, S=1, 1024, 0xecb30526
+0, 109, 109, 1, 12334, 0x16147fc3, S=1, 1024, 0xecb30526
+0, 110, 110, 1, 12452, 0x61a8b3d7, S=1, 1024, 0xecb30526
+0, 111, 111, 1, 12695, 0x8b703e74, S=1, 1024, 0xecb30526
+0, 112, 112, 1, 12668, 0x19505176, S=1, 1024, 0xecb30526
+0, 113, 113, 1, 12957, 0x3b839f0d, S=1, 1024, 0xecb30526
+0, 114, 114, 1, 13054, 0xb8a5e3db, S=1, 1024, 0xecb30526
+0, 115, 115, 1, 13147, 0xdf5c2e68, S=1, 1024, 0xecb30526
+0, 116, 116, 1, 13171, 0x15961ca2, S=1, 1024, 0xecb30526
+0, 117, 117, 1, 13198, 0xfd855718, S=1, 1024, 0xecb30526
+0, 118, 118, 1, 13211, 0x1a625e31, S=1, 1024, 0xecb30526
+0, 119, 119, 1, 13210, 0x246661c9, S=1, 1024, 0xecb30526
+0, 120, 120, 1, 13467, 0xfcaaa461, S=1, 1024, 0xecb30526
+0, 121, 121, 1, 13665, 0x8100dbf2, S=1, 1024, 0xecb30526
+0, 122, 122, 1, 13692, 0xddd1eab9, S=1, 1024, 0xecb30526
+0, 123, 123, 1, 13821, 0xc70e2af0, S=1, 1024, 0xecb30526
+0, 124, 124, 1, 13946, 0xe15d9134, S=1, 1024, 0xecb30526
+0, 125, 125, 1, 14063, 0xf652d232, S=1, 1024, 0xecb30526
+0, 126, 126, 1, 14124, 0x756ccc81, S=1, 1024, 0xecb30526
+0, 127, 127, 1, 14331, 0x56d64fe8, S=1, 1024, 0xecb30526
+0, 128, 128, 1, 14469, 0x4c3faa7f, S=1, 1024, 0xecb30526
+0, 129, 129, 1, 14536, 0xad02a19b, S=1, 1024, 0xecb30526
+0, 130, 130, 1, 14608, 0x0971d168, S=1, 1024, 0xecb30526
+0, 131, 131, 1, 14898, 0x1a6827b3, S=1, 1024, 0xecb30526
+0, 132, 132, 1, 14978, 0xf9709fef, S=1, 1024, 0xecb30526
+0, 133, 133, 1, 15142, 0x3598da63, S=1, 1024, 0xecb30526
+0, 134, 134, 1, 15129, 0x062fb976, S=1, 1024, 0xecb30526
+0, 135, 135, 1, 15243, 0x0a6a12f9, S=1, 1024, 0xecb30526
+0, 136, 136, 1, 15337, 0x0f9a65d6, S=1, 1024, 0xecb30526
+0, 137, 137, 1, 15638, 0xf7bc9ef5, S=1, 1024, 0xecb30526
+0, 138, 138, 1, 15912, 0x2d5b26bb, S=1, 1024, 0xecb30526
+0, 139, 139, 1, 16041, 0xbfaf4857, S=1, 1024, 0xecb30526
+0, 140, 140, 1, 16228, 0xdac701f0, S=1, 1024, 0xecb30526
+0, 141, 141, 1, 16262, 0xcd0ae5e4, S=1, 1024, 0xecb30526
+0, 142, 142, 1, 16371, 0x9d4f0e73, S=1, 1024, 0xecb30526
+0, 143, 143, 1, 16661, 0xd37ba990, S=1, 1024, 0xecb30526
+0, 144, 144, 1, 16917, 0xd5b01774, S=1, 1024, 0xecb30526
+0, 145, 145, 1, 17149, 0x435ecdd4, S=1, 1024, 0xecb30526
+0, 146, 146, 1, 17172, 0x045fb234, S=1, 1024, 0xecb30526
+0, 147, 147, 1, 17315, 0xc5ddadab, S=1, 1024, 0xecb30526
+0, 148, 148, 1, 17397, 0xff8e15b6, S=1, 1024, 0xecb30526
+0, 149, 149, 1, 17431, 0x6832f8c0, S=1, 1024, 0xecb30526
+0, 150, 150, 1, 17576, 0x5c2a5445, S=1, 1024, 0xecb30526
+0, 151, 151, 1, 17764, 0x609f8c3b, S=1, 1024, 0xecb30526
+0, 152, 152, 1, 17826, 0x538c8532, S=1, 1024, 0xecb30526
+0, 153, 153, 1, 17918, 0x84fc9a95, S=1, 1024, 0xecb30526
+0, 154, 154, 1, 17823, 0x788fbada, S=1, 1024, 0xecb30526
+0, 155, 155, 1, 18142, 0x56881e47, S=1, 1024, 0xecb30526
+0, 156, 156, 1, 18257, 0xa35b86cf, S=1, 1024, 0xecb30526
+0, 157, 157, 1, 18337, 0x82ddbc21, S=1, 1024, 0xecb30526
+0, 158, 158, 1, 18293, 0xf0d838d6, S=1, 1024, 0xecb30526
+0, 159, 159, 1, 18418, 0x7ed8bba6, S=1, 1024, 0xecb30526
+0, 160, 160, 1, 18607, 0xccea47f6, S=1, 1024, 0xecb30526
+0, 161, 161, 1, 18916, 0x880ebd63, S=1, 1024, 0xecb30526
+0, 162, 162, 1, 19073, 0x055f02e3, S=1, 1024, 0xecb30526
+0, 163, 163, 1, 19168, 0xcc2c02d7, S=1, 1024, 0xecb30526
+0, 164, 164, 1, 19210, 0xa538ffc1, S=1, 1024, 0xecb30526
+0, 165, 165, 1, 19398, 0x4777644d, S=1, 1024, 0xecb30526
+0, 166, 166, 1, 19480, 0xcb2aa0fa, S=1, 1024, 0xecb30526
+0, 167, 167, 1, 19659, 0xe3c1122d, S=1, 1024, 0xecb30526
+0, 168, 168, 1, 19672, 0x1d1e193f, S=1, 1024, 0xecb30526
+0, 169, 169, 1, 19936, 0xcd036346, S=1, 1024, 0xecb30526
+0, 170, 170, 1, 19975, 0x96529b21, S=1, 1024, 0xecb30526
+0, 171, 171, 1, 20021, 0xcdaf8bb5, S=1, 1024, 0xecb30526
+0, 172, 172, 1, 20060, 0x1cea7784, S=1, 1024, 0xecb30526
diff --git a/tests/ref/fate/gifenc-rgb8 b/tests/ref/fate/gifenc-rgb8
new file mode 100644
index 0000000000..d1a990d07e
--- /dev/null
+++ b/tests/ref/fate/gifenc-rgb8
@@ -0,0 +1,174 @@
+#tb 0: 1/10
+0, 0, 0, 1, 552, 0x47602c6c
+0, 1, 1, 1, 297, 0x49dd8847, S=1, 1024, 0xcfc8799f
+0, 2, 2, 1, 438, 0x4776d352, S=1, 1024, 0xcfc8799f
+0, 3, 3, 1, 450, 0x2254d187, S=1, 1024, 0xcfc8799f
+0, 4, 4, 1, 547, 0xe16104bc, S=1, 1024, 0xcfc8799f
+0, 5, 5, 1, 614, 0x0fdc2027, S=1, 1024, 0xcfc8799f
+0, 6, 6, 1, 642, 0xa0af1edf, S=1, 1024, 0xcfc8799f
+0, 7, 7, 1, 660, 0xd0763931, S=1, 1024, 0xcfc8799f
+0, 8, 8, 1, 821, 0xc38f7fac, S=1, 1024, 0xcfc8799f
+0, 9, 9, 1, 1157, 0x4c112ecd, S=1, 1024, 0xcfc8799f
+0, 10, 10, 1, 179, 0x0690541c, S=1, 1024, 0xcfc8799f
+0, 11, 11, 1, 1333, 0x216f70a7, S=1, 1024, 0xcfc8799f
+0, 12, 12, 1, 1638, 0x901c093d, S=1, 1024, 0xcfc8799f
+0, 13, 13, 1, 1531, 0xc9bae5ff, S=1, 1024, 0xcfc8799f
+0, 14, 14, 1, 1720, 0xce854743, S=1, 1024, 0xcfc8799f
+0, 15, 15, 1, 1910, 0x2690866d, S=1, 1024, 0xcfc8799f
+0, 16, 16, 1, 2124, 0xa586dad0, S=1, 1024, 0xcfc8799f
+0, 17, 17, 1, 2248, 0x9ddc2a88, S=1, 1024, 0xcfc8799f
+0, 18, 18, 1, 2311, 0xd64235af, S=1, 1024, 0xcfc8799f
+0, 19, 19, 1, 2408, 0xe2a66cc9, S=1, 1024, 0xcfc8799f
+0, 20, 20, 1, 2601, 0xeab6c267, S=1, 1024, 0xcfc8799f
+0, 21, 21, 1, 2687, 0xfe1d0311, S=1, 1024, 0xcfc8799f
+0, 22, 22, 1, 2784, 0xca600dee, S=1, 1024, 0xcfc8799f
+0, 23, 23, 1, 2884, 0xc7134b99, S=1, 1024, 0xcfc8799f
+0, 24, 24, 1, 2982, 0x0b1e7825, S=1, 1024, 0xcfc8799f
+0, 25, 25, 1, 3101, 0x3e029e0e, S=1, 1024, 0xcfc8799f
+0, 26, 26, 1, 3253, 0x846af678, S=1, 1024, 0xcfc8799f
+0, 27, 27, 1, 3329, 0x29a81b71, S=1, 1024, 0xcfc8799f
+0, 28, 28, 1, 3572, 0xa3e08a52, S=1, 1024, 0xcfc8799f
+0, 29, 29, 1, 3807, 0x18e1fed2, S=1, 1024, 0xcfc8799f
+0, 30, 30, 1, 2750, 0xff6e1f9e, S=1, 1024, 0xcfc8799f
+0, 31, 31, 1, 4031, 0x6d4f7329, S=1, 1024, 0xcfc8799f
+0, 32, 32, 1, 3025, 0xb43c9e94, S=1, 1024, 0xcfc8799f
+0, 33, 33, 1, 4295, 0xc1850a80, S=1, 1024, 0xcfc8799f
+0, 34, 34, 1, 2044, 0x0440c072, S=1, 1024, 0xcfc8799f
+0, 35, 35, 1, 3212, 0xe91af08f, S=1, 1024, 0xcfc8799f
+0, 36, 36, 1, 2292, 0x6765633e, S=1, 1024, 0xcfc8799f
+0, 37, 37, 1, 3633, 0xac779aa3, S=1, 1024, 0xcfc8799f
+0, 38, 38, 1, 3552, 0xed2c75b2, S=1, 1024, 0xcfc8799f
+0, 39, 39, 1, 3690, 0x2020dd0d, S=1, 1024, 0xcfc8799f
+0, 40, 40, 1, 1559, 0x596ef330, S=1, 1024, 0xcfc8799f
+0, 41, 41, 1, 954, 0xac12c9c5, S=1, 1024, 0xcfc8799f
+0, 42, 42, 1, 273, 0x138c7831, S=1, 1024, 0xcfc8799f
+0, 43, 43, 1, 930, 0xf1c3ae3f, S=1, 1024, 0xcfc8799f
+0, 44, 44, 1, 271, 0x921a80af, S=1, 1024, 0xcfc8799f
+0, 45, 45, 1, 196, 0xa5de5322, S=1, 1024, 0xcfc8799f
+0, 46, 46, 1, 4299, 0x5bac0d86, S=1, 1024, 0xcfc8799f
+0, 47, 47, 1, 4895, 0xc43639a6, S=1, 1024, 0xcfc8799f
+0, 48, 48, 1, 4928, 0xf17d13e8, S=1, 1024, 0xcfc8799f
+0, 49, 49, 1, 4941, 0x71915520, S=1, 1024, 0xcfc8799f
+0, 50, 50, 1, 4154, 0xc860b8a6, S=1, 1024, 0xcfc8799f
+0, 51, 51, 1, 4678, 0x2651c339, S=1, 1024, 0xcfc8799f
+0, 52, 52, 1, 4741, 0xffd6bb45, S=1, 1024, 0xcfc8799f
+0, 53, 53, 1, 4982, 0x132c5977, S=1, 1024, 0xcfc8799f
+0, 54, 54, 1, 5179, 0x97aac3a1, S=1, 1024, 0xcfc8799f
+0, 55, 55, 1, 5046, 0x836a80cd, S=1, 1024, 0xcfc8799f
+0, 56, 56, 1, 5140, 0xa725c1e7, S=1, 1024, 0xcfc8799f
+0, 57, 57, 1, 4301, 0x0203f239, S=1, 1024, 0xcfc8799f
+0, 58, 58, 1, 5079, 0xb2e7a2de, S=1, 1024, 0xcfc8799f
+0, 59, 59, 1, 5284, 0xb757dfe1, S=1, 1024, 0xcfc8799f
+0, 60, 60, 1, 5426, 0xf9f11e57, S=1, 1024, 0xcfc8799f
+0, 61, 61, 1, 4645, 0xf0f289e1, S=1, 1024, 0xcfc8799f
+0, 62, 62, 1, 5263, 0x8617d7e9, S=1, 1024, 0xcfc8799f
+0, 63, 63, 1, 5221, 0x26e3ca43, S=1, 1024, 0xcfc8799f
+0, 64, 64, 1, 5217, 0x90989cfb, S=1, 1024, 0xcfc8799f
+0, 65, 65, 1, 5395, 0xe29a01cb, S=1, 1024, 0xcfc8799f
+0, 66, 66, 1, 5220, 0xe2dee355, S=1, 1024, 0xcfc8799f
+0, 67, 67, 1, 5704, 0xcfbcd55e, S=1, 1024, 0xcfc8799f
+0, 68, 68, 1, 5636, 0x7fc2a1e5, S=1, 1024, 0xcfc8799f
+0, 69, 69, 1, 5818, 0x6090ebbd, S=1, 1024, 0xcfc8799f
+0, 70, 70, 1, 5763, 0xc110c791, S=1, 1024, 0xcfc8799f
+0, 71, 71, 1, 6116, 0xb4ee8e30, S=1, 1024, 0xcfc8799f
+0, 72, 72, 1, 6069, 0x21b263db, S=1, 1024, 0xcfc8799f
+0, 73, 73, 1, 5796, 0x2514df52, S=1, 1024, 0xcfc8799f
+0, 74, 74, 1, 5999, 0x1c3c3701, S=1, 1024, 0xcfc8799f
+0, 75, 75, 1, 6220, 0x8340b150, S=1, 1024, 0xcfc8799f
+0, 76, 76, 1, 6374, 0x00d8eaa5, S=1, 1024, 0xcfc8799f
+0, 77, 77, 1, 6465, 0x74c4778a, S=1, 1024, 0xcfc8799f
+0, 78, 78, 1, 7019, 0xdb1a28a3, S=1, 1024, 0xcfc8799f
+0, 79, 79, 1, 7255, 0x1e19b76e, S=1, 1024, 0xcfc8799f
+0, 80, 80, 1, 8197, 0x26bc6a79, S=1, 1024, 0xcfc8799f
+0, 81, 81, 1, 8358, 0x118781e0, S=1, 1024, 0xcfc8799f
+0, 82, 82, 1, 7708, 0xfc0c963d, S=1, 1024, 0xcfc8799f
+0, 83, 83, 1, 7412, 0xdcc311ee, S=1, 1024, 0xcfc8799f
+0, 84, 84, 1, 7541, 0x4d2819c1, S=1, 1024, 0xcfc8799f
+0, 85, 85, 1, 7948, 0xf12eca3d, S=1, 1024, 0xcfc8799f
+0, 86, 86, 1, 8408, 0x43add468, S=1, 1024, 0xcfc8799f
+0, 87, 87, 1, 8056, 0x2d162377, S=1, 1024, 0xcfc8799f
+0, 88, 88, 1, 7401, 0x26ebb649, S=1, 1024, 0xcfc8799f
+0, 89, 89, 1, 7494, 0x35fcf9ae, S=1, 1024, 0xcfc8799f
+0, 90, 90, 1, 7806, 0x4238723d, S=1, 1024, 0xcfc8799f
+0, 91, 91, 1, 7768, 0xb01e795a, S=1, 1024, 0xcfc8799f
+0, 92, 92, 1, 7749, 0x6ab39c12, S=1, 1024, 0xcfc8799f
+0, 93, 93, 1, 8047, 0x0e5f24aa, S=1, 1024, 0xcfc8799f
+0, 94, 94, 1, 7618, 0xd787340f, S=1, 1024, 0xcfc8799f
+0, 95, 95, 1, 7979, 0x0824c4df, S=1, 1024, 0xcfc8799f
+0, 96, 96, 1, 12062, 0xc46d9d92, S=1, 1024, 0xcfc8799f
+0, 97, 97, 1, 12317, 0x1314dc0c, S=1, 1024, 0xcfc8799f
+0, 98, 98, 1, 12217, 0x78c2ed30, S=1, 1024, 0xcfc8799f
+0, 99, 99, 1, 11227, 0x2a578eb9, S=1, 1024, 0xcfc8799f
+0, 100, 100, 1, 11108, 0x4eaa068c, S=1, 1024, 0xcfc8799f
+0, 101, 101, 1, 11366, 0x48f8993f, S=1, 1024, 0xcfc8799f
+0, 102, 102, 1, 11896, 0x32414841, S=1, 1024, 0xcfc8799f
+0, 103, 103, 1, 11479, 0xeaa38225, S=1, 1024, 0xcfc8799f
+0, 104, 104, 1, 13395, 0xaa9d4c72, S=1, 1024, 0xcfc8799f
+0, 105, 105, 1, 12913, 0x28854353, S=1, 1024, 0xcfc8799f
+0, 106, 106, 1, 13864, 0x663df630, S=1, 1024, 0xcfc8799f
+0, 107, 107, 1, 13551, 0xf7ba7be7, S=1, 1024, 0xcfc8799f
+0, 108, 108, 1, 14041, 0x2dc071b9, S=1, 1024, 0xcfc8799f
+0, 109, 109, 1, 14144, 0x33a03d1d, S=1, 1024, 0xcfc8799f
+0, 110, 110, 1, 14277, 0x6bda5935, S=1, 1024, 0xcfc8799f
+0, 111, 111, 1, 14424, 0xa696efd8, S=1, 1024, 0xcfc8799f
+0, 112, 112, 1, 14689, 0x8e3ad12c, S=1, 1024, 0xcfc8799f
+0, 113, 113, 1, 14598, 0x544668b4, S=1, 1024, 0xcfc8799f
+0, 114, 114, 1, 15213, 0x60009558, S=1, 1024, 0xcfc8799f
+0, 115, 115, 1, 15425, 0x86e5adf4, S=1, 1024, 0xcfc8799f
+0, 116, 116, 1, 15595, 0x878d09b9, S=1, 1024, 0xcfc8799f
+0, 117, 117, 1, 15598, 0x10daabc4, S=1, 1024, 0xcfc8799f
+0, 118, 118, 1, 15863, 0x2462016c, S=1, 1024, 0xcfc8799f
+0, 119, 119, 1, 15717, 0xe05041c4, S=1, 1024, 0xcfc8799f
+0, 120, 120, 1, 16078, 0x7c8f3a8c, S=1, 1024, 0xcfc8799f
+0, 121, 121, 1, 16225, 0x9771a52e, S=1, 1024, 0xcfc8799f
+0, 122, 122, 1, 16135, 0x2dfc1692, S=1, 1024, 0xcfc8799f
+0, 123, 123, 1, 16661, 0x09c96d7e, S=1, 1024, 0xcfc8799f
+0, 124, 124, 1, 16619, 0xc4735b56, S=1, 1024, 0xcfc8799f
+0, 125, 125, 1, 16829, 0x589dc13f, S=1, 1024, 0xcfc8799f
+0, 126, 126, 1, 16944, 0x997cd18f, S=1, 1024, 0xcfc8799f
+0, 127, 127, 1, 17119, 0x6c396b60, S=1, 1024, 0xcfc8799f
+0, 128, 128, 1, 17150, 0x8e603d31, S=1, 1024, 0xcfc8799f
+0, 129, 129, 1, 17321, 0x0bbcee5a, S=1, 1024, 0xcfc8799f
+0, 130, 130, 1, 17395, 0x99f0c974, S=1, 1024, 0xcfc8799f
+0, 131, 131, 1, 17666, 0x37184223, S=1, 1024, 0xcfc8799f
+0, 132, 132, 1, 17730, 0xa0d385b3, S=1, 1024, 0xcfc8799f
+0, 133, 133, 1, 17934, 0xb22cc97d, S=1, 1024, 0xcfc8799f
+0, 134, 134, 1, 17944, 0x0cd309c6, S=1, 1024, 0xcfc8799f
+0, 135, 135, 1, 18238, 0x6b7e3237, S=1, 1024, 0xcfc8799f
+0, 136, 136, 1, 18391, 0x4df3c48a, S=1, 1024, 0xcfc8799f
+0, 137, 137, 1, 18543, 0x90a2f238, S=1, 1024, 0xcfc8799f
+0, 138, 138, 1, 18939, 0xc57dda5b, S=1, 1024, 0xcfc8799f
+0, 139, 139, 1, 19145, 0x1267294a, S=1, 1024, 0xcfc8799f
+0, 140, 140, 1, 19120, 0xeac6a9c3, S=1, 1024, 0xcfc8799f
+0, 141, 141, 1, 19130, 0x31f3edbc, S=1, 1024, 0xcfc8799f
+0, 142, 142, 1, 19494, 0x3259a2f3, S=1, 1024, 0xcfc8799f
+0, 143, 143, 1, 19534, 0xda22a752, S=1, 1024, 0xcfc8799f
+0, 144, 144, 1, 19747, 0x8805c379, S=1, 1024, 0xcfc8799f
+0, 145, 145, 1, 20114, 0xaaf96864, S=1, 1024, 0xcfc8799f
+0, 146, 146, 1, 20257, 0x7223da26, S=1, 1024, 0xcfc8799f
+0, 147, 147, 1, 20370, 0x08ef382a, S=1, 1024, 0xcfc8799f
+0, 148, 148, 1, 20292, 0x4b47f207, S=1, 1024, 0xcfc8799f
+0, 149, 149, 1, 20491, 0xeedd6d1c, S=1, 1024, 0xcfc8799f
+0, 150, 150, 1, 20647, 0xb0d1dd45, S=1, 1024, 0xcfc8799f
+0, 151, 151, 1, 20666, 0x382cc8a4, S=1, 1024, 0xcfc8799f
+0, 152, 152, 1, 21007, 0x398f4f7d, S=1, 1024, 0xcfc8799f
+0, 153, 153, 1, 21058, 0xd6616a9d, S=1, 1024, 0xcfc8799f
+0, 154, 154, 1, 21153, 0x988749db, S=1, 1024, 0xcfc8799f
+0, 155, 155, 1, 21078, 0x1b328059, S=1, 1024, 0xcfc8799f
+0, 156, 156, 1, 21458, 0x6348529c, S=1, 1024, 0xcfc8799f
+0, 157, 157, 1, 21669, 0xcf63e2de, S=1, 1024, 0xcfc8799f
+0, 158, 158, 1, 21581, 0x1fc021af, S=1, 1024, 0xcfc8799f
+0, 159, 159, 1, 21654, 0x899dab18, S=1, 1024, 0xcfc8799f
+0, 160, 160, 1, 21987, 0x634086fe, S=1, 1024, 0xcfc8799f
+0, 161, 161, 1, 22205, 0x617a7335, S=1, 1024, 0xcfc8799f
+0, 162, 162, 1, 22475, 0x9fa2e01c, S=1, 1024, 0xcfc8799f
+0, 163, 163, 1, 22490, 0x7dc5376c, S=1, 1024, 0xcfc8799f
+0, 164, 164, 1, 22460, 0x33e6bbfe, S=1, 1024, 0xcfc8799f
+0, 165, 165, 1, 22861, 0x18993510, S=1, 1024, 0xcfc8799f
+0, 166, 166, 1, 22746, 0xdff85615, S=1, 1024, 0xcfc8799f
+0, 167, 167, 1, 23165, 0xf0ac66a3, S=1, 1024, 0xcfc8799f
+0, 168, 168, 1, 23273, 0x13869ad9, S=1, 1024, 0xcfc8799f
+0, 169, 169, 1, 23211, 0xd30b6205, S=1, 1024, 0xcfc8799f
+0, 170, 170, 1, 23648, 0xa0cef01b, S=1, 1024, 0xcfc8799f
+0, 171, 171, 1, 23675, 0x760460b9, S=1, 1024, 0xcfc8799f
+0, 172, 172, 1, 23874, 0xacf998c5, S=1, 1024, 0xcfc8799f
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr10_sony_b b/tests/ref/fate/h264-conformance-frext-hi422fr10_sony_b
new file mode 100644
index 0000000000..244e546cd0
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr10_sony_b
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 202752, 0xffa1c502
+0, 1, 1, 1, 202752, 0x51752f3c
+0, 2, 2, 1, 202752, 0xe683991d
+0, 3, 3, 1, 202752, 0xf70200a4
+0, 4, 4, 1, 202752, 0x1a4d63ef
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b b/tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b
new file mode 100644
index 0000000000..016abbce76
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr13_sony_b
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0xe0f40e71
+0, 1, 1, 1, 405504, 0x9bdb5900
+0, 2, 2, 1, 405504, 0x527003ca
+0, 3, 3, 1, 405504, 0x1fbf8ba6
+0, 4, 4, 1, 405504, 0x455e2a4e
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a b/tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a
new file mode 100644
index 0000000000..93a3aa4bde
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr1_sony_a
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 202752, 0xd5a1e49f
+0, 1, 1, 1, 202752, 0x08352d61
+0, 2, 2, 1, 202752, 0x43f78f47
+0, 3, 3, 1, 202752, 0xfb5910f4
+0, 4, 4, 1, 202752, 0xd98e8739
diff --git a/tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a b/tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a
new file mode 100644
index 0000000000..4141eeeda8
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-hi422fr6_sony_a
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 405504, 0x049ab58e
+0, 1, 1, 1, 405504, 0x4f6226cb
+0, 2, 2, 1, 405504, 0xaa5fcb44
+0, 3, 3, 1, 405504, 0xbfc09965
+0, 4, 4, 1, 405504, 0xa30acb90
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a
new file mode 100644
index 0000000000..0957654b9c
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i1_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3686400, 0x1f9b5bee
+0, 1, 1, 1, 3686400, 0x657c3609
+0, 2, 2, 1, 3686400, 0x75753934
+0, 3, 3, 1, 3686400, 0xf434d8e1
+0, 4, 4, 1, 3686400, 0x40679c77
+0, 5, 5, 1, 3686400, 0x5734d8db
+0, 6, 6, 1, 3686400, 0x4a3d8269
+0, 7, 7, 1, 3686400, 0xd20b6cf6
+0, 8, 8, 1, 3686400, 0x31956bca
+0, 9, 9, 1, 3686400, 0xd28d9758
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a
new file mode 100644
index 0000000000..79e69ebacc
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i2_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3686400, 0x8b3ff360
+0, 1, 1, 1, 3686400, 0x422dead1
+0, 2, 2, 1, 3686400, 0xbdd0e431
+0, 3, 3, 1, 3686400, 0x1e3cc216
+0, 4, 4, 1, 3686400, 0x1a80b718
+0, 5, 5, 1, 3686400, 0xc7e3c0a2
+0, 6, 6, 1, 3686400, 0xffc99142
+0, 7, 7, 1, 3686400, 0x8b3bdf1e
+0, 8, 8, 1, 3686400, 0xff1bccfb
+0, 9, 9, 1, 3686400, 0x781fc45b
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a
new file mode 100644
index 0000000000..fc4cc50a40
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i3_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3686400, 0x97c36ae3
+0, 1, 1, 1, 3686400, 0x6a0aa629
+0, 2, 2, 1, 3686400, 0xc658d722
+0, 3, 3, 1, 3686400, 0x713bc774
+0, 4, 4, 1, 3686400, 0x8d0b3afe
+0, 5, 5, 1, 3686400, 0x62bf24cd
+0, 6, 6, 1, 3686400, 0x77e80436
+0, 7, 7, 1, 3686400, 0x4f258e07
+0, 8, 8, 1, 3686400, 0x8426bc53
+0, 9, 9, 1, 3686400, 0xd33b58c8
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a
new file mode 100644
index 0000000000..0aae9fedcb
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i4_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0xf50992f3
+0, 1, 1, 1, 8294400, 0xd34cdf98
+0, 2, 2, 1, 8294400, 0x76bced00
+0, 3, 3, 1, 8294400, 0xf9ffd9b1
+0, 4, 4, 1, 8294400, 0x303231aa
+0, 5, 5, 1, 8294400, 0x0ca57c6a
+0, 6, 6, 1, 8294400, 0xaa056bd5
+0, 7, 7, 1, 8294400, 0x785c9a12
+0, 8, 8, 1, 8294400, 0xe535750e
+0, 9, 9, 1, 8294400, 0x78fd76bb
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a
new file mode 100644
index 0000000000..c74483cbb2
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i5_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0x96d051a1
+0, 1, 1, 1, 8294400, 0xf3c2974e
+0, 2, 2, 1, 8294400, 0xb18f3ed0
+0, 3, 3, 1, 8294400, 0xb5ba9998
+0, 4, 4, 1, 8294400, 0x96327a34
+0, 5, 5, 1, 8294400, 0xe24d7b61
+0, 6, 6, 1, 8294400, 0xc45d5a16
+0, 7, 7, 1, 8294400, 0x13b4a537
+0, 8, 8, 1, 8294400, 0xa81dae90
+0, 9, 9, 1, 8294400, 0x2820bbe9
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a
new file mode 100644
index 0000000000..26d41d4cf7
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i6_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0x1b2f1079
+0, 1, 1, 1, 8294400, 0x6646f91c
+0, 2, 2, 1, 8294400, 0x17dc9f51
+0, 3, 3, 1, 8294400, 0x4aad9b3a
+0, 4, 4, 1, 8294400, 0x8a422d34
+0, 5, 5, 1, 8294400, 0x8fd76d87
+0, 6, 6, 1, 8294400, 0xc7c75f18
+0, 7, 7, 1, 8294400, 0x4a1c2643
+0, 8, 8, 1, 8294400, 0xfe225709
+0, 9, 9, 1, 8294400, 0x032ad2e5
diff --git a/tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a b/tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a
new file mode 100644
index 0000000000..3f9bfed903
--- /dev/null
+++ b/tests/ref/fate/h264-conformance-frext-pph422i7_panasonic_a
@@ -0,0 +1,11 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0xaa37ceea
+0, 1, 1, 1, 8294400, 0xa7546d5c
+0, 2, 2, 1, 8294400, 0xf2abaace
+0, 3, 3, 1, 8294400, 0x36f4d47e
+0, 4, 4, 1, 8294400, 0x1cdf917d
+0, 5, 5, 1, 8294400, 0xa9377ba3
+0, 6, 6, 1, 8294400, 0x21c9db51
+0, 7, 7, 1, 8294400, 0x07d7936e
+0, 8, 8, 1, 8294400, 0x7878ab94
+0, 9, 9, 1, 8294400, 0x77e40921
diff --git a/tests/ref/fate/h264-crop-to-container b/tests/ref/fate/h264-crop-to-container
index 5dfa44157c..4932bdd9d0 100644
--- a/tests/ref/fate/h264-crop-to-container
+++ b/tests/ref/fate/h264-crop-to-container
@@ -1,2 +1,6 @@
-#tb 0: 1/30000
-0, 0, 0, 0, 3110400, 43a312e1eebc7dca1bd23456302a44e3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3110400, 43a312e1eebc7dca1bd23456302a44e3
diff --git a/tests/ref/fate/h264-direct-bff b/tests/ref/fate/h264-direct-bff
index c61fd0ca4e..4d233b5fc8 100644
--- a/tests/ref/fate/h264-direct-bff
+++ b/tests/ref/fate/h264-direct-bff
@@ -1,12 +1,12 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 522720, 0x1ccad503
-0, 33, 33, 0, 522720, 0xd266d6e8
-0, 67, 67, 0, 522720, 0x535473b3
-0, 100, 100, 0, 522720, 0xf8b53c53
-0, 133, 133, 0, 522720, 0x4e4cc04b
-0, 167, 167, 0, 522720, 0x20ea3515
-0, 200, 200, 0, 522720, 0xb9c67e30
-0, 233, 233, 0, 522720, 0x03d2e35a
-0, 267, 267, 0, 522720, 0xae2e7896
-0, 300, 300, 0, 522720, 0x6da37f41
-0, 400, 400, 0, 522720, 0x7caf4954
+#tb 0: 1001/30000
+0, 0, 0, 1, 522720, 0x1ccad503
+0, 1, 1, 1, 522720, 0xd266d6e8
+0, 2, 2, 1, 522720, 0x535473b3
+0, 3, 3, 1, 522720, 0xf8b53c53
+0, 4, 4, 1, 522720, 0x4e4cc04b
+0, 5, 5, 1, 522720, 0x20ea3515
+0, 6, 6, 1, 522720, 0xb9c67e30
+0, 7, 7, 1, 522720, 0x03d2e35a
+0, 8, 8, 1, 522720, 0xae2e7896
+0, 9, 9, 1, 522720, 0x6da37f41
+0, 12, 12, 1, 522720, 0x7caf4954
diff --git a/tests/ref/fate/h264-extreme-plane-pred b/tests/ref/fate/h264-extreme-plane-pred
index db85e99bbb..96c2bf4c08 100644
--- a/tests/ref/fate/h264-extreme-plane-pred
+++ b/tests/ref/fate/h264-extreme-plane-pred
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 152064, 1e857d2dfeea75297e090ffe9e37a249
0, 1, 1, 1, 152064, 29d8336b4e9b77298025074dbad641d1
0, 2, 2, 1, 152064, 3f1a87d2088a7708f4ed06890c8cd018
diff --git a/tests/ref/fate/h264-lossless b/tests/ref/fate/h264-lossless
index 11cc4d0898..44cb13ba24 100644
--- a/tests/ref/fate/h264-lossless
+++ b/tests/ref/fate/h264-lossless
@@ -1,11 +1,11 @@
-#tb 0: 1/25
+#tb 0: 83333/5000000
0, 0, 0, 1, 460800, 0x7731dd2f
-0, 1, 1, 1, 460800, 0x944b8c64
-0, 2, 2, 1, 460800, 0xbe833041
-0, 3, 3, 1, 460800, 0xbe95d96a
-0, 4, 4, 1, 460800, 0xfe7ea5e6
-0, 5, 5, 1, 460800, 0x381743c7
-0, 6, 6, 1, 460800, 0x63fcc2e9
-0, 7, 7, 1, 460800, 0x79574960
-0, 8, 8, 1, 460800, 0xdab9e18a
-0, 9, 9, 1, 460800, 0xd88e8fe8
+0, 2, 2, 1, 460800, 0x944b8c64
+0, 3, 3, 1, 460800, 0xbe833041
+0, 4, 4, 1, 460800, 0xbe95d96a
+0, 5, 5, 1, 460800, 0xfe7ea5e6
+0, 6, 6, 1, 460800, 0x381743c7
+0, 7, 7, 1, 460800, 0x63fcc2e9
+0, 8, 8, 1, 460800, 0x79574960
+0, 9, 9, 1, 460800, 0xdab9e18a
+0, 10, 10, 1, 460800, 0xd88e8fe8
diff --git a/tests/ref/fate/hevc-conformance-ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1 b/tests/ref/fate/hevc-conformance-ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1
new file mode 100644
index 0000000000..f73569f466
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-ADJUST_IPRED_ANGLE_A_RExt_Mitsubishi_1
@@ -0,0 +1,4 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0xa061c78c
+0, 1, 1, 1, 8294400, 0x60250c76
+0, 2, 2, 1, 8294400, 0x48e3fbdb
diff --git a/tests/ref/fate/hevc-conformance-AMP_A_Samsung_6 b/tests/ref/fate/hevc-conformance-AMP_A_Samsung_6
new file mode 100644
index 0000000000..7693050e95
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_A_Samsung_6
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 6144000, 0x6f9dd380
+0, 1, 1, 1, 6144000, 0x3ad765f8
+0, 2, 2, 1, 6144000, 0xe301292d
+0, 3, 3, 1, 6144000, 0x4272c502
+0, 4, 4, 1, 6144000, 0xa07fb65d
+0, 5, 5, 1, 6144000, 0x8ba3bfd9
+0, 6, 6, 1, 6144000, 0x60d043be
+0, 7, 7, 1, 6144000, 0x2569fa6e
+0, 8, 8, 1, 6144000, 0xd645ca25
+0, 9, 9, 1, 6144000, 0xd65a4297
+0, 10, 10, 1, 6144000, 0x3ce13abe
+0, 11, 11, 1, 6144000, 0x2c06229b
+0, 12, 12, 1, 6144000, 0x6efe8de1
+0, 13, 13, 1, 6144000, 0x1500d848
+0, 14, 14, 1, 6144000, 0x453cd614
+0, 15, 15, 1, 6144000, 0x65182daf
+0, 16, 16, 1, 6144000, 0x4cef8519
+0, 17, 17, 1, 6144000, 0x47ff5125
+0, 18, 18, 1, 6144000, 0xa86327d3
+0, 19, 19, 1, 6144000, 0x3e3bd7bb
+0, 20, 20, 1, 6144000, 0x3e591d1a
+0, 21, 21, 1, 6144000, 0x1cb0a751
+0, 22, 22, 1, 6144000, 0x3532e0ae
+0, 23, 23, 1, 6144000, 0xe44fb0fe
+0, 24, 24, 1, 6144000, 0x9b075bc6
+0, 25, 25, 1, 6144000, 0x53352d7d
+0, 26, 26, 1, 6144000, 0x7ded6eac
+0, 27, 27, 1, 6144000, 0xd65b88e8
+0, 28, 28, 1, 6144000, 0xea53ae64
+0, 29, 29, 1, 6144000, 0xf0e21afa
+0, 30, 30, 1, 6144000, 0x43f11a01
+0, 31, 31, 1, 6144000, 0xb3005915
+0, 32, 32, 1, 6144000, 0x3eb450ed
+0, 33, 33, 1, 6144000, 0xdba020e8
+0, 34, 34, 1, 6144000, 0x8f2cbd30
+0, 35, 35, 1, 6144000, 0x9e12e7d6
+0, 36, 36, 1, 6144000, 0x27fd7092
+0, 37, 37, 1, 6144000, 0xf63056cd
+0, 38, 38, 1, 6144000, 0x44bfff47
+0, 39, 39, 1, 6144000, 0x9706c5a8
+0, 40, 40, 1, 6144000, 0xe5fe4658
+0, 41, 41, 1, 6144000, 0x20d5518b
+0, 42, 42, 1, 6144000, 0x25e56fe5
+0, 43, 43, 1, 6144000, 0x8cebd3d1
+0, 44, 44, 1, 6144000, 0x458d2302
+0, 45, 45, 1, 6144000, 0x6fc44942
+0, 46, 46, 1, 6144000, 0xdf8fa6da
+0, 47, 47, 1, 6144000, 0xafb34a56
+0, 48, 48, 1, 6144000, 0x4c5b177e
+0, 49, 49, 1, 6144000, 0x83934d62
+0, 50, 50, 1, 6144000, 0x59028fc3
+0, 51, 51, 1, 6144000, 0xfd9810cf
+0, 52, 52, 1, 6144000, 0x104abf79
+0, 53, 53, 1, 6144000, 0xb9a68e12
+0, 54, 54, 1, 6144000, 0x5ac4bbd8
+0, 55, 55, 1, 6144000, 0x44f4bb5e
+0, 56, 56, 1, 6144000, 0xc48a4f6b
+0, 57, 57, 1, 6144000, 0xecb27957
+0, 58, 58, 1, 6144000, 0xe2ec6e92
+0, 59, 59, 1, 6144000, 0x94697078
diff --git a/tests/ref/fate/hevc-conformance-AMP_B_Samsung_6 b/tests/ref/fate/hevc-conformance-AMP_B_Samsung_6
new file mode 100644
index 0000000000..fd99c827ad
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-AMP_B_Samsung_6
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 6144000, 0x4217e40e
+0, 1, 1, 1, 6144000, 0xafa3a676
+0, 2, 2, 1, 6144000, 0xb8285522
+0, 3, 3, 1, 6144000, 0x07e52fe0
+0, 4, 4, 1, 6144000, 0x04838016
+0, 5, 5, 1, 6144000, 0xd421bd78
+0, 6, 6, 1, 6144000, 0xd49765e1
+0, 7, 7, 1, 6144000, 0xd6623f0c
+0, 8, 8, 1, 6144000, 0x11348e42
+0, 9, 9, 1, 6144000, 0x440a4ba5
+0, 10, 10, 1, 6144000, 0x8c5990fd
+0, 11, 11, 1, 6144000, 0x2284c72a
+0, 12, 12, 1, 6144000, 0x2b16b0c8
+0, 13, 13, 1, 6144000, 0xeadbfbfa
+0, 14, 14, 1, 6144000, 0xf7bf6e0a
+0, 15, 15, 1, 6144000, 0x62fc7321
+0, 16, 16, 1, 6144000, 0xee5707b5
+0, 17, 17, 1, 6144000, 0xc0cafdc7
+0, 18, 18, 1, 6144000, 0x0409333c
+0, 19, 19, 1, 6144000, 0x2ef82c00
+0, 20, 20, 1, 6144000, 0x01d99315
+0, 21, 21, 1, 6144000, 0x2086bdb6
+0, 22, 22, 1, 6144000, 0xdadd95b4
+0, 23, 23, 1, 6144000, 0x97cf72a2
+0, 24, 24, 1, 6144000, 0x1914e283
+0, 25, 25, 1, 6144000, 0x0073f731
+0, 26, 26, 1, 6144000, 0xdcd7a65b
+0, 27, 27, 1, 6144000, 0x43a5a65f
+0, 28, 28, 1, 6144000, 0x89c68568
+0, 29, 29, 1, 6144000, 0xf07517ad
+0, 30, 30, 1, 6144000, 0xa716e9e6
+0, 31, 31, 1, 6144000, 0x004267aa
+0, 32, 32, 1, 6144000, 0x68ec7399
+0, 33, 33, 1, 6144000, 0x558e0339
+0, 34, 34, 1, 6144000, 0xf3a57912
+0, 35, 35, 1, 6144000, 0x708d11e1
+0, 36, 36, 1, 6144000, 0x8c31af81
+0, 37, 37, 1, 6144000, 0xfc0ae2d2
+0, 38, 38, 1, 6144000, 0xdfdf4726
+0, 39, 39, 1, 6144000, 0xe101c925
+0, 40, 40, 1, 6144000, 0xb38ced35
+0, 41, 41, 1, 6144000, 0x4e8848b6
+0, 42, 42, 1, 6144000, 0xb9d526d9
+0, 43, 43, 1, 6144000, 0xb20f931c
+0, 44, 44, 1, 6144000, 0x4143e9f3
+0, 45, 45, 1, 6144000, 0x30fc4669
+0, 46, 46, 1, 6144000, 0x9087bd86
+0, 47, 47, 1, 6144000, 0x34f28088
+0, 48, 48, 1, 6144000, 0x675febc8
+0, 49, 49, 1, 6144000, 0x36ccb881
+0, 50, 50, 1, 6144000, 0xbc0ea02f
+0, 51, 51, 1, 6144000, 0x72619f9e
+0, 52, 52, 1, 6144000, 0x7e115352
+0, 53, 53, 1, 6144000, 0x7ef1e547
+0, 54, 54, 1, 6144000, 0xbac5db79
+0, 55, 55, 1, 6144000, 0xe75bf8e7
+0, 56, 56, 1, 6144000, 0x53992573
+0, 57, 57, 1, 6144000, 0x6b705da6
+0, 58, 58, 1, 6144000, 0x494dbecc
+0, 59, 59, 1, 6144000, 0xfe001b93
diff --git a/tests/ref/fate/hevc-conformance-AMVP_C_Samsung_6 b/tests/ref/fate/hevc-conformance-AMVP_C_Samsung_6
new file mode 100644
index 0000000000..5ed71e2b8c
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-AMVP_C_Samsung_6
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0xd70f52b4
+0, 1, 1, 1, 599040, 0xaf3d1311
+0, 2, 2, 1, 599040, 0xc1b05eef
+0, 3, 3, 1, 599040, 0x74567085
+0, 4, 4, 1, 599040, 0x96fddb91
+0, 5, 5, 1, 599040, 0x17ad9135
+0, 6, 6, 1, 599040, 0xc548a9fb
+0, 7, 7, 1, 599040, 0xb4966a0d
+0, 8, 8, 1, 599040, 0x4faf57f9
+0, 9, 9, 1, 599040, 0x373f02e6
+0, 10, 10, 1, 599040, 0xd140dd00
+0, 11, 11, 1, 599040, 0x306c0cd8
+0, 12, 12, 1, 599040, 0x55cf5e78
+0, 13, 13, 1, 599040, 0xff0be66a
+0, 14, 14, 1, 599040, 0xd9d25dad
+0, 15, 15, 1, 599040, 0x15d9ea2c
+0, 16, 16, 1, 599040, 0x79376390
+0, 17, 17, 1, 599040, 0x24623936
+0, 18, 18, 1, 599040, 0x9219bd14
+0, 19, 19, 1, 599040, 0x527466b1
+0, 20, 20, 1, 599040, 0x7842c98d
+0, 21, 21, 1, 599040, 0x79d7fc77
+0, 22, 22, 1, 599040, 0xef05bfe9
+0, 23, 23, 1, 599040, 0xf8024da4
+0, 24, 24, 1, 599040, 0x511d016e
+0, 25, 25, 1, 599040, 0x81034a76
+0, 26, 26, 1, 599040, 0x08964794
+0, 27, 27, 1, 599040, 0x3a58520d
+0, 28, 28, 1, 599040, 0x11b985e2
+0, 29, 29, 1, 599040, 0x0a74dc70
+0, 30, 30, 1, 599040, 0x84e45bf8
+0, 31, 31, 1, 599040, 0xdfc7b5db
+0, 32, 32, 1, 599040, 0x45b2b466
+0, 33, 33, 1, 599040, 0xeb8a276b
+0, 34, 34, 1, 599040, 0x60901d6b
+0, 35, 35, 1, 599040, 0xa91f4bb5
+0, 36, 36, 1, 599040, 0x075a6805
+0, 37, 37, 1, 599040, 0x125cac7b
+0, 38, 38, 1, 599040, 0x1eaf3e28
+0, 39, 39, 1, 599040, 0xea09afb0
+0, 40, 40, 1, 599040, 0x880f7226
+0, 41, 41, 1, 599040, 0x9c59a833
+0, 42, 42, 1, 599040, 0x6219dc87
+0, 43, 43, 1, 599040, 0x44916437
+0, 44, 44, 1, 599040, 0xb545c563
+0, 45, 45, 1, 599040, 0x988d396e
+0, 46, 46, 1, 599040, 0x6fa11ed6
+0, 47, 47, 1, 599040, 0x7f7e3921
+0, 48, 48, 1, 599040, 0x62eb7f4a
+0, 49, 49, 1, 599040, 0x604c3071
+0, 50, 50, 1, 599040, 0x3d0a3fdd
+0, 51, 51, 1, 599040, 0x38df42ed
+0, 52, 52, 1, 599040, 0x3881190d
+0, 53, 53, 1, 599040, 0x6da811da
+0, 54, 54, 1, 599040, 0x23c61fa1
+0, 55, 55, 1, 599040, 0xfd6f428b
+0, 56, 56, 1, 599040, 0xd03424a8
+0, 57, 57, 1, 599040, 0xaa9b9e2e
+0, 58, 58, 1, 599040, 0x626636b5
+0, 59, 59, 1, 599040, 0x6ce8e513
diff --git a/tests/ref/fate/hevc-conformance-BUMPING_A_ericsson_1 b/tests/ref/fate/hevc-conformance-BUMPING_A_ericsson_1
new file mode 100644
index 0000000000..26387299bd
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-BUMPING_A_ericsson_1
@@ -0,0 +1,50 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x8ce7200b
+0, 1, 1, 1, 149760, 0x73610669
+0, 2, 2, 1, 149760, 0xc01620f4
+0, 3, 3, 1, 149760, 0x847a4297
+0, 4, 4, 1, 149760, 0x8b2db700
+0, 5, 5, 1, 149760, 0x17b1d77c
+0, 6, 6, 1, 149760, 0xc31ee8a5
+0, 7, 7, 1, 149760, 0x19541295
+0, 8, 8, 1, 149760, 0xd050be45
+0, 9, 9, 1, 149760, 0x45cf8e84
+0, 10, 10, 1, 149760, 0x0dd3e4d4
+0, 11, 11, 1, 149760, 0xc8347a7c
+0, 12, 12, 1, 149760, 0x24089674
+0, 13, 13, 1, 149760, 0xdf2c44e4
+0, 14, 14, 1, 149760, 0x83f5100b
+0, 15, 15, 1, 149760, 0x9a060faf
+0, 16, 16, 1, 149760, 0x4cdc6101
+0, 17, 17, 1, 149760, 0xe492ad68
+0, 18, 18, 1, 149760, 0x35b73887
+0, 19, 19, 1, 149760, 0x259f898a
+0, 20, 20, 1, 149760, 0x21df021b
+0, 21, 21, 1, 149760, 0xdddc1cfe
+0, 22, 22, 1, 149760, 0x53841bf5
+0, 23, 23, 1, 149760, 0x16745d74
+0, 24, 24, 1, 149760, 0x66e79e6a
+0, 25, 25, 1, 149760, 0x35f04b5a
+0, 26, 26, 1, 149760, 0x1472eee7
+0, 27, 27, 1, 149760, 0x42d0147c
+0, 28, 28, 1, 149760, 0x57c9bdc2
+0, 29, 29, 1, 149760, 0x20ad4cc7
+0, 30, 30, 1, 149760, 0x1617ef6c
+0, 31, 31, 1, 149760, 0xccdf4da2
+0, 32, 32, 1, 149760, 0xc173b762
+0, 33, 33, 1, 149760, 0xe7390c69
+0, 34, 34, 1, 149760, 0xfd0c97d3
+0, 35, 35, 1, 149760, 0xaeb2d61f
+0, 36, 36, 1, 149760, 0xe7b114d2
+0, 37, 37, 1, 149760, 0x1b771de4
+0, 38, 38, 1, 149760, 0xd3e03840
+0, 39, 39, 1, 149760, 0x702ef44b
+0, 40, 40, 1, 149760, 0xe96f848b
+0, 41, 41, 1, 149760, 0xa0ae24d9
+0, 42, 42, 1, 149760, 0x1b9efdfb
+0, 43, 43, 1, 149760, 0xceac9bc7
+0, 44, 44, 1, 149760, 0x73078700
+0, 45, 45, 1, 149760, 0xa736637e
+0, 46, 46, 1, 149760, 0xbd353c9d
+0, 47, 47, 1, 149760, 0x750a23ba
+0, 48, 48, 1, 149760, 0x4144c56e
diff --git a/tests/ref/fate/hevc-conformance-CONFWIN_A_Sony_1 b/tests/ref/fate/hevc-conformance-CONFWIN_A_Sony_1
new file mode 100644
index 0000000000..3cd7a265e5
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-CONFWIN_A_Sony_1
@@ -0,0 +1,61 @@
+#tb 0: 1001/30000
+0, 0, 0, 1, 145848, 0xad4f07d0
+0, 1, 1, 1, 145848, 0x5825120c
+0, 2, 2, 1, 145848, 0x3eeb0da2
+0, 3, 3, 1, 145848, 0xcb8b552c
+0, 4, 4, 1, 145848, 0x47760242
+0, 5, 5, 1, 145848, 0x300db218
+0, 6, 6, 1, 145848, 0xef413a76
+0, 7, 7, 1, 145848, 0x35ef8c97
+0, 8, 8, 1, 145848, 0x9075e0e4
+0, 9, 9, 1, 145848, 0xedfc1421
+0, 10, 10, 1, 145848, 0x6b11ff04
+0, 11, 11, 1, 145848, 0x07d46c17
+0, 12, 12, 1, 145848, 0xeb65e8f5
+0, 13, 13, 1, 145848, 0xd3ce9d91
+0, 14, 14, 1, 145848, 0x2eec1e60
+0, 15, 15, 1, 145848, 0x31bd643f
+0, 16, 16, 1, 145848, 0xc7279b2d
+0, 17, 17, 1, 145848, 0x1ec6e5d0
+0, 18, 18, 1, 145848, 0x878e7dfb
+0, 19, 19, 1, 145848, 0xe5d06c0f
+0, 20, 20, 1, 145848, 0x67346b38
+0, 21, 21, 1, 145848, 0xe6fb3974
+0, 22, 22, 1, 145848, 0x85ff6677
+0, 23, 23, 1, 145848, 0xbcb7185c
+0, 24, 24, 1, 145848, 0xf83eb2c2
+0, 25, 25, 1, 145848, 0x86f0f302
+0, 26, 26, 1, 145848, 0x427a882b
+0, 27, 27, 1, 145848, 0x6ee5d9ab
+0, 28, 28, 1, 145848, 0x1da83f0e
+0, 29, 29, 1, 145848, 0x6d4c21f0
+0, 30, 30, 1, 145848, 0xccf4df3f
+0, 31, 31, 1, 145848, 0x605cb762
+0, 32, 32, 1, 145848, 0x183e01e4
+0, 33, 33, 1, 145848, 0xdad146e6
+0, 34, 34, 1, 145848, 0x3804955b
+0, 35, 35, 1, 145848, 0x379e8a1c
+0, 36, 36, 1, 145848, 0x73f3246b
+0, 37, 37, 1, 145848, 0x5440b62a
+0, 38, 38, 1, 145848, 0x4919daed
+0, 39, 39, 1, 145848, 0x43f4c06d
+0, 40, 40, 1, 145848, 0x96fd53a8
+0, 41, 41, 1, 145848, 0x41efa7a7
+0, 42, 42, 1, 145848, 0x6bd20430
+0, 43, 43, 1, 145848, 0x25a69a61
+0, 44, 44, 1, 145848, 0xb37a369f
+0, 45, 45, 1, 145848, 0x5f32c40b
+0, 46, 46, 1, 145848, 0x9774371c
+0, 47, 47, 1, 145848, 0x27f28d2d
+0, 48, 48, 1, 145848, 0xd4751a44
+0, 49, 49, 1, 145848, 0x49df5cde
+0, 50, 50, 1, 145848, 0x80829f9f
+0, 51, 51, 1, 145848, 0xc6c3a17d
+0, 52, 52, 1, 145848, 0xdbc0bf65
+0, 53, 53, 1, 145848, 0xd941733a
+0, 54, 54, 1, 145848, 0x1ca612a9
+0, 55, 55, 1, 145848, 0xba52806b
+0, 56, 56, 1, 145848, 0x387f1a1f
+0, 57, 57, 1, 145848, 0x24e405c4
+0, 58, 58, 1, 145848, 0xe35f8d73
+0, 59, 59, 1, 145848, 0x5209a2e4
diff --git a/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_2 b/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_3
index 50be4f1845..50be4f1845 100644
--- a/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_2
+++ b/tests/ref/fate/hevc-conformance-DBLK_A_MAIN10_VIXS_3
diff --git a/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3 b/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3
index 0750bb3209..589cbf39bf 100644
--- a/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3
+++ b/tests/ref/fate/hevc-conformance-DBLK_A_SONY_3
@@ -1,31 +1,31 @@
#tb 0: 1/25
0, 0, 0, 1, 599040, 0x154e6dd9
-0, 2, 2, 1, 599040, 0xcce25693
-0, 3, 3, 1, 599040, 0x3dd84e88
-0, 4, 4, 1, 599040, 0xca197027
-0, 5, 5, 1, 599040, 0xc9af0241
-0, 6, 6, 1, 599040, 0x510470de
-0, 7, 7, 1, 599040, 0xac8c0a7c
-0, 8, 8, 1, 599040, 0x04cbed5e
-0, 9, 9, 1, 599040, 0x514ce2f1
-0, 10, 10, 1, 599040, 0xf37a4eec
-0, 11, 11, 1, 599040, 0xabfd7f2f
-0, 12, 12, 1, 599040, 0x944458a1
-0, 13, 13, 1, 599040, 0xf4f81db2
-0, 14, 14, 1, 599040, 0xdde236fb
-0, 15, 15, 1, 599040, 0x6b0132be
-0, 16, 16, 1, 599040, 0x641683a3
-0, 17, 17, 1, 599040, 0x81d6be90
-0, 18, 18, 1, 599040, 0xf1e04e55
-0, 19, 19, 1, 599040, 0x63c4dc0a
-0, 20, 20, 1, 599040, 0x47170db8
-0, 21, 21, 1, 599040, 0xdc22f27b
-0, 22, 22, 1, 599040, 0xd5b63800
-0, 23, 23, 1, 599040, 0x07b76936
-0, 24, 24, 1, 599040, 0x5215eee2
-0, 25, 25, 1, 599040, 0xb5b2c9b1
-0, 26, 26, 1, 599040, 0x79bee732
-0, 27, 27, 1, 599040, 0x14c1f436
-0, 28, 28, 1, 599040, 0x384f7f05
-0, 29, 29, 1, 599040, 0x44229c42
-0, 30, 30, 1, 599040, 0x5dea88e9
+0, 1, 1, 1, 599040, 0xcce25693
+0, 2, 2, 1, 599040, 0x3dd84e88
+0, 3, 3, 1, 599040, 0xca197027
+0, 4, 4, 1, 599040, 0xc9af0241
+0, 5, 5, 1, 599040, 0x510470de
+0, 6, 6, 1, 599040, 0xac8c0a7c
+0, 7, 7, 1, 599040, 0x04cbed5e
+0, 8, 8, 1, 599040, 0x514ce2f1
+0, 9, 9, 1, 599040, 0xf37a4eec
+0, 10, 10, 1, 599040, 0xabfd7f2f
+0, 11, 11, 1, 599040, 0x944458a1
+0, 12, 12, 1, 599040, 0xf4f81db2
+0, 13, 13, 1, 599040, 0xdde236fb
+0, 14, 14, 1, 599040, 0x6b0132be
+0, 15, 15, 1, 599040, 0x641683a3
+0, 16, 16, 1, 599040, 0x81d6be90
+0, 17, 17, 1, 599040, 0xf1e04e55
+0, 18, 18, 1, 599040, 0x63c4dc0a
+0, 19, 19, 1, 599040, 0x47170db8
+0, 20, 20, 1, 599040, 0xdc22f27b
+0, 21, 21, 1, 599040, 0xd5b63800
+0, 22, 22, 1, 599040, 0x07b76936
+0, 23, 23, 1, 599040, 0x5215eee2
+0, 24, 24, 1, 599040, 0xb5b2c9b1
+0, 25, 25, 1, 599040, 0x79bee732
+0, 26, 26, 1, 599040, 0x14c1f436
+0, 27, 27, 1, 599040, 0x384f7f05
+0, 28, 28, 1, 599040, 0x44229c42
+0, 29, 29, 1, 599040, 0x5dea88e9
diff --git a/tests/ref/fate/hevc-conformance-DBLK_B_SONY_3 b/tests/ref/fate/hevc-conformance-DBLK_B_SONY_3
index 83f9b4a265..077b38e4fb 100644
--- a/tests/ref/fate/hevc-conformance-DBLK_B_SONY_3
+++ b/tests/ref/fate/hevc-conformance-DBLK_B_SONY_3
@@ -1,31 +1,31 @@
#tb 0: 1/25
0, 0, 0, 1, 599040, 0xda0cb5d4
-0, 2, 2, 1, 599040, 0x352bc397
-0, 3, 3, 1, 599040, 0x72bc28fe
-0, 4, 4, 1, 599040, 0x22294f68
-0, 5, 5, 1, 599040, 0x1f6415a7
-0, 6, 6, 1, 599040, 0xa9f6b0d7
-0, 7, 7, 1, 599040, 0x6b7c1f2d
-0, 8, 8, 1, 599040, 0xb93857f5
-0, 9, 9, 1, 599040, 0xb0d752d3
-0, 10, 10, 1, 599040, 0x0622e689
-0, 11, 11, 1, 599040, 0x23d8780a
-0, 12, 12, 1, 599040, 0x4844581b
-0, 13, 13, 1, 599040, 0x791322f9
-0, 14, 14, 1, 599040, 0x82f6cf43
-0, 15, 15, 1, 599040, 0xcace3aba
-0, 16, 16, 1, 599040, 0x68a68427
-0, 17, 17, 1, 599040, 0x23fa500a
-0, 18, 18, 1, 599040, 0x7d78b77d
-0, 19, 19, 1, 599040, 0x8d295032
-0, 20, 20, 1, 599040, 0x16fa266c
-0, 21, 21, 1, 599040, 0x37d8173b
-0, 22, 22, 1, 599040, 0x8a4f90e1
-0, 23, 23, 1, 599040, 0x40f98f6d
-0, 24, 24, 1, 599040, 0xc060b193
-0, 25, 25, 1, 599040, 0xa53c3bc1
-0, 26, 26, 1, 599040, 0x5a9556d6
-0, 27, 27, 1, 599040, 0x37582393
-0, 28, 28, 1, 599040, 0x376acd14
-0, 29, 29, 1, 599040, 0x81ee1e64
-0, 30, 30, 1, 599040, 0xff2a600c
+0, 1, 1, 1, 599040, 0x352bc397
+0, 2, 2, 1, 599040, 0x72bc28fe
+0, 3, 3, 1, 599040, 0x22294f68
+0, 4, 4, 1, 599040, 0x1f6415a7
+0, 5, 5, 1, 599040, 0xa9f6b0d7
+0, 6, 6, 1, 599040, 0x6b7c1f2d
+0, 7, 7, 1, 599040, 0xb93857f5
+0, 8, 8, 1, 599040, 0xb0d752d3
+0, 9, 9, 1, 599040, 0x0622e689
+0, 10, 10, 1, 599040, 0x23d8780a
+0, 11, 11, 1, 599040, 0x4844581b
+0, 12, 12, 1, 599040, 0x791322f9
+0, 13, 13, 1, 599040, 0x82f6cf43
+0, 14, 14, 1, 599040, 0xcace3aba
+0, 15, 15, 1, 599040, 0x68a68427
+0, 16, 16, 1, 599040, 0x23fa500a
+0, 17, 17, 1, 599040, 0x7d78b77d
+0, 18, 18, 1, 599040, 0x8d295032
+0, 19, 19, 1, 599040, 0x16fa266c
+0, 20, 20, 1, 599040, 0x37d8173b
+0, 21, 21, 1, 599040, 0x8a4f90e1
+0, 22, 22, 1, 599040, 0x40f98f6d
+0, 23, 23, 1, 599040, 0xc060b193
+0, 24, 24, 1, 599040, 0xa53c3bc1
+0, 25, 25, 1, 599040, 0x5a9556d6
+0, 26, 26, 1, 599040, 0x37582393
+0, 27, 27, 1, 599040, 0x376acd14
+0, 28, 28, 1, 599040, 0x81ee1e64
+0, 29, 29, 1, 599040, 0xff2a600c
diff --git a/tests/ref/fate/hevc-conformance-DBLK_C_SONY_3 b/tests/ref/fate/hevc-conformance-DBLK_C_SONY_3
index 1087148501..823988dfd7 100644
--- a/tests/ref/fate/hevc-conformance-DBLK_C_SONY_3
+++ b/tests/ref/fate/hevc-conformance-DBLK_C_SONY_3
@@ -1,31 +1,31 @@
#tb 0: 1/25
0, 0, 0, 1, 599040, 0x57369bf4
-0, 2, 2, 1, 599040, 0x319aab9c
-0, 3, 3, 1, 599040, 0xbc1b7698
-0, 4, 4, 1, 599040, 0x05cea248
-0, 5, 5, 1, 599040, 0xdca73743
-0, 6, 6, 1, 599040, 0x5b5a9f70
-0, 7, 7, 1, 599040, 0x16c51b34
-0, 8, 8, 1, 599040, 0x734fe724
-0, 9, 9, 1, 599040, 0x48e4e0ba
-0, 10, 10, 1, 599040, 0xf1423cc1
-0, 11, 11, 1, 599040, 0xb4bb68b1
-0, 12, 12, 1, 599040, 0x54a77ad6
-0, 13, 13, 1, 599040, 0x6e0dfce3
-0, 14, 14, 1, 599040, 0x7ca687e3
-0, 15, 15, 1, 599040, 0xf9ac2443
-0, 16, 16, 1, 599040, 0xe35b8d34
-0, 17, 17, 1, 599040, 0xef4bbe9f
-0, 18, 18, 1, 599040, 0x21eb418e
-0, 19, 19, 1, 599040, 0xae6df30f
-0, 20, 20, 1, 599040, 0x743500af
-0, 21, 21, 1, 599040, 0x7fba1ce1
-0, 22, 22, 1, 599040, 0x45793eae
-0, 23, 23, 1, 599040, 0x1f7e3467
-0, 24, 24, 1, 599040, 0x7400c7c3
-0, 25, 25, 1, 599040, 0xcf79806d
-0, 26, 26, 1, 599040, 0x324ea91d
-0, 27, 27, 1, 599040, 0x9c8cae92
-0, 28, 28, 1, 599040, 0x70bfc368
-0, 29, 29, 1, 599040, 0x46a0f8ff
-0, 30, 30, 1, 599040, 0xd864208a
+0, 1, 1, 1, 599040, 0x319aab9c
+0, 2, 2, 1, 599040, 0xbc1b7698
+0, 3, 3, 1, 599040, 0x05cea248
+0, 4, 4, 1, 599040, 0xdca73743
+0, 5, 5, 1, 599040, 0x5b5a9f70
+0, 6, 6, 1, 599040, 0x16c51b34
+0, 7, 7, 1, 599040, 0x734fe724
+0, 8, 8, 1, 599040, 0x48e4e0ba
+0, 9, 9, 1, 599040, 0xf1423cc1
+0, 10, 10, 1, 599040, 0xb4bb68b1
+0, 11, 11, 1, 599040, 0x54a77ad6
+0, 12, 12, 1, 599040, 0x6e0dfce3
+0, 13, 13, 1, 599040, 0x7ca687e3
+0, 14, 14, 1, 599040, 0xf9ac2443
+0, 15, 15, 1, 599040, 0xe35b8d34
+0, 16, 16, 1, 599040, 0xef4bbe9f
+0, 17, 17, 1, 599040, 0x21eb418e
+0, 18, 18, 1, 599040, 0xae6df30f
+0, 19, 19, 1, 599040, 0x743500af
+0, 20, 20, 1, 599040, 0x7fba1ce1
+0, 21, 21, 1, 599040, 0x45793eae
+0, 22, 22, 1, 599040, 0x1f7e3467
+0, 23, 23, 1, 599040, 0x7400c7c3
+0, 24, 24, 1, 599040, 0xcf79806d
+0, 25, 25, 1, 599040, 0x324ea91d
+0, 26, 26, 1, 599040, 0x9c8cae92
+0, 27, 27, 1, 599040, 0x70bfc368
+0, 28, 28, 1, 599040, 0x46a0f8ff
+0, 29, 29, 1, 599040, 0xd864208a
diff --git a/tests/ref/fate/hevc-conformance-DBLK_D_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_D_VIXS_1
deleted file mode 100644
index 3d9e43b1c0..0000000000
--- a/tests/ref/fate/hevc-conformance-DBLK_D_VIXS_1
+++ /dev/null
@@ -1,9 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 1382400, 0x6ef5c76e
-0, 1, 1, 1, 1382400, 0x975238be
-0, 2, 2, 1, 1382400, 0xe5529a79
-0, 3, 3, 1, 1382400, 0x639641d4
-0, 4, 4, 1, 1382400, 0x566eb1df
-0, 5, 5, 1, 1382400, 0x4fd4b46a
-0, 6, 6, 1, 1382400, 0xfb4a6a0e
-0, 7, 7, 1, 1382400, 0x4485af32
diff --git a/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_1
deleted file mode 100644
index c3ebaf2081..0000000000
--- a/tests/ref/fate/hevc-conformance-DBLK_E_VIXS_1
+++ /dev/null
@@ -1,9 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 1382400, 0x7119bbe5
-0, 1, 1, 1, 1382400, 0xbeda2c83
-0, 2, 2, 1, 1382400, 0x2cbe6669
-0, 3, 3, 1, 1382400, 0x3cee2619
-0, 4, 4, 1, 1382400, 0x93e388e3
-0, 5, 5, 1, 1382400, 0x5e286889
-0, 6, 6, 1, 1382400, 0x4718f29c
-0, 7, 7, 1, 1382400, 0xbedf4dbd
diff --git a/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_1
deleted file mode 100644
index 59f51efaa8..0000000000
--- a/tests/ref/fate/hevc-conformance-DBLK_F_VIXS_1
+++ /dev/null
@@ -1,9 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 1382400, 0xea27f7bd
-0, 1, 1, 1, 1382400, 0xce3d7b4c
-0, 2, 2, 1, 1382400, 0xaea4970e
-0, 3, 3, 1, 1382400, 0xcbc7c89f
-0, 4, 4, 1, 1382400, 0xe5367019
-0, 5, 5, 1, 1382400, 0xb92ca18e
-0, 6, 6, 1, 1382400, 0xde046be1
-0, 7, 7, 1, 1382400, 0x1ae6e393
diff --git a/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_1 b/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_1
deleted file mode 100644
index 4b9793b154..0000000000
--- a/tests/ref/fate/hevc-conformance-DBLK_G_VIXS_1
+++ /dev/null
@@ -1,9 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 1382400, 0xecfdf606
-0, 1, 1, 1, 1382400, 0x7607799b
-0, 2, 2, 1, 1382400, 0x67fb98e4
-0, 3, 3, 1, 1382400, 0xf2dce07f
-0, 4, 4, 1, 1382400, 0x663f991c
-0, 5, 5, 1, 1382400, 0x3877aeb0
-0, 6, 6, 1, 1382400, 0x73409282
-0, 7, 7, 1, 1382400, 0x766c10b1
diff --git a/tests/ref/fate/hevc-conformance-DELTAQP_A_BRCM_4 b/tests/ref/fate/hevc-conformance-DELTAQP_A_BRCM_4
new file mode 100644
index 0000000000..d2ab0f57fa
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-DELTAQP_A_BRCM_4
@@ -0,0 +1,97 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3133440, 0xfbd10331
+0, 1, 1, 1, 3133440, 0x7764ad70
+0, 2, 2, 1, 3133440, 0xaeaf44c1
+0, 3, 3, 1, 3133440, 0x0590073b
+0, 4, 4, 1, 3133440, 0xc4173137
+0, 5, 5, 1, 3133440, 0xd173b667
+0, 6, 6, 1, 3133440, 0xb70253db
+0, 7, 7, 1, 3133440, 0x506ada41
+0, 8, 8, 1, 3133440, 0x7748178b
+0, 9, 9, 1, 3133440, 0xd5450415
+0, 10, 10, 1, 3133440, 0x2d1cf084
+0, 11, 11, 1, 3133440, 0xc89fb208
+0, 12, 12, 1, 3133440, 0x3d065c44
+0, 13, 13, 1, 3133440, 0x15a67a95
+0, 14, 14, 1, 3133440, 0xde1684ca
+0, 15, 15, 1, 3133440, 0xc3e64367
+0, 16, 16, 1, 3133440, 0x5bf1bd00
+0, 17, 17, 1, 3133440, 0x253703c8
+0, 18, 18, 1, 3133440, 0x5c5fb22b
+0, 19, 19, 1, 3133440, 0x5fcd0915
+0, 20, 20, 1, 3133440, 0xb6fe6c0d
+0, 21, 21, 1, 3133440, 0x3673f749
+0, 22, 22, 1, 3133440, 0x42535c71
+0, 23, 23, 1, 3133440, 0x889fd32d
+0, 24, 24, 1, 3133440, 0x259c6c22
+0, 25, 25, 1, 3133440, 0x128844a2
+0, 26, 26, 1, 3133440, 0x34d9ead6
+0, 27, 27, 1, 3133440, 0x0a68658a
+0, 28, 28, 1, 3133440, 0x3aa96f3e
+0, 29, 29, 1, 3133440, 0x20249702
+0, 30, 30, 1, 3133440, 0x6d14a401
+0, 31, 31, 1, 3133440, 0xf6acf9ae
+0, 32, 32, 1, 3133440, 0x0894adfb
+0, 33, 33, 1, 3133440, 0x664178bb
+0, 34, 34, 1, 3133440, 0x6b9305df
+0, 35, 35, 1, 3133440, 0x8afd4ab4
+0, 36, 36, 1, 3133440, 0x1869c2aa
+0, 37, 37, 1, 3133440, 0x004f3a7d
+0, 38, 38, 1, 3133440, 0xadeb9a81
+0, 39, 39, 1, 3133440, 0xbeffc378
+0, 40, 40, 1, 3133440, 0x58c34e3c
+0, 41, 41, 1, 3133440, 0x5b07ad91
+0, 42, 42, 1, 3133440, 0x41bf5cb6
+0, 43, 43, 1, 3133440, 0x65ebea43
+0, 44, 44, 1, 3133440, 0x9c2462ae
+0, 45, 45, 1, 3133440, 0x3cbc1a04
+0, 46, 46, 1, 3133440, 0x0debbeeb
+0, 47, 47, 1, 3133440, 0x954399f6
+0, 48, 48, 1, 3133440, 0x3ba1b057
+0, 49, 49, 1, 3133440, 0x3b5a0cae
+0, 50, 50, 1, 3133440, 0xfdf6c423
+0, 51, 51, 1, 3133440, 0x08097c97
+0, 52, 52, 1, 3133440, 0x13f06984
+0, 53, 53, 1, 3133440, 0x52a3baec
+0, 54, 54, 1, 3133440, 0x7961fb92
+0, 55, 55, 1, 3133440, 0xb6805a96
+0, 56, 56, 1, 3133440, 0xde1c16e9
+0, 57, 57, 1, 3133440, 0x07cb1ffc
+0, 58, 58, 1, 3133440, 0xad1a1f91
+0, 59, 59, 1, 3133440, 0x77bb5968
+0, 60, 60, 1, 3133440, 0x85e8074c
+0, 61, 61, 1, 3133440, 0x1a2919ef
+0, 62, 62, 1, 3133440, 0x81540640
+0, 63, 63, 1, 3133440, 0xd61a3574
+0, 64, 64, 1, 3133440, 0xf875c32c
+0, 65, 65, 1, 3133440, 0x50548308
+0, 66, 66, 1, 3133440, 0xf98ee7e9
+0, 67, 67, 1, 3133440, 0xb7b4cb8e
+0, 68, 68, 1, 3133440, 0x1c22b2b7
+0, 69, 69, 1, 3133440, 0x2ea55366
+0, 70, 70, 1, 3133440, 0x82e76ac5
+0, 71, 71, 1, 3133440, 0x292af798
+0, 72, 72, 1, 3133440, 0x29508415
+0, 73, 73, 1, 3133440, 0x4ef87b17
+0, 74, 74, 1, 3133440, 0xa6eeb679
+0, 75, 75, 1, 3133440, 0xfe69f819
+0, 76, 76, 1, 3133440, 0x95bb6b49
+0, 77, 77, 1, 3133440, 0x5bf3f8ad
+0, 78, 78, 1, 3133440, 0x58113e3a
+0, 79, 79, 1, 3133440, 0xd87b6888
+0, 80, 80, 1, 3133440, 0xb3e7a295
+0, 81, 81, 1, 3133440, 0x3c2c7f97
+0, 82, 82, 1, 3133440, 0xe5f5cc48
+0, 83, 83, 1, 3133440, 0xa222f3e6
+0, 84, 84, 1, 3133440, 0x6ae80e0b
+0, 85, 85, 1, 3133440, 0x2bc02816
+0, 86, 86, 1, 3133440, 0x2a5043cb
+0, 87, 87, 1, 3133440, 0x857089b9
+0, 88, 88, 1, 3133440, 0xf3443ad1
+0, 89, 89, 1, 3133440, 0x7cb10b4c
+0, 90, 90, 1, 3133440, 0x75bb32b9
+0, 91, 91, 1, 3133440, 0x6b720e0f
+0, 92, 92, 1, 3133440, 0x761571be
+0, 93, 93, 1, 3133440, 0x34dc14a1
+0, 94, 94, 1, 3133440, 0xbb94c2d4
+0, 95, 95, 1, 3133440, 0x5300e459
diff --git a/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3 b/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3
index a8427d1d1c..3ba3bb5a3e 100644
--- a/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3
+++ b/tests/ref/fate/hevc-conformance-DELTAQP_B_SONY_3
@@ -1,31 +1,31 @@
#tb 0: 1/25
0, 0, 0, 1, 599040, 0x7ea9597c
-0, 2, 2, 1, 599040, 0x3e7365e4
-0, 3, 3, 1, 599040, 0x4a9149c9
-0, 4, 4, 1, 599040, 0x3b1f6549
-0, 5, 5, 1, 599040, 0x3e35f616
-0, 6, 6, 1, 599040, 0x843c7951
-0, 7, 7, 1, 599040, 0xa2adb299
-0, 8, 8, 1, 599040, 0xb9dda682
-0, 9, 9, 1, 599040, 0x9a5e7355
-0, 10, 10, 1, 599040, 0xc4bafa8c
-0, 11, 11, 1, 599040, 0xc4ec160e
-0, 12, 12, 1, 599040, 0x538421a3
-0, 13, 13, 1, 599040, 0xb294a96e
-0, 14, 14, 1, 599040, 0x9bb217df
-0, 15, 15, 1, 599040, 0xbe70c870
-0, 16, 16, 1, 599040, 0xa4e319a8
-0, 17, 17, 1, 599040, 0x3a4c702d
-0, 18, 18, 1, 599040, 0x9f790906
-0, 19, 19, 1, 599040, 0xbbfdb8d6
-0, 20, 20, 1, 599040, 0x0965c0ed
-0, 21, 21, 1, 599040, 0x6993e1f1
-0, 22, 22, 1, 599040, 0xc1cc1df9
-0, 23, 23, 1, 599040, 0xe570c390
-0, 24, 24, 1, 599040, 0x422f6fd7
-0, 25, 25, 1, 599040, 0x9c89298c
-0, 26, 26, 1, 599040, 0x5ece4193
-0, 27, 27, 1, 599040, 0x142a4f2f
-0, 28, 28, 1, 599040, 0xa5356c63
-0, 29, 29, 1, 599040, 0x8458a378
-0, 30, 30, 1, 599040, 0xc149ed56
+0, 1, 1, 1, 599040, 0x3e7365e4
+0, 2, 2, 1, 599040, 0x4a9149c9
+0, 3, 3, 1, 599040, 0x3b1f6549
+0, 4, 4, 1, 599040, 0x3e35f616
+0, 5, 5, 1, 599040, 0x843c7951
+0, 6, 6, 1, 599040, 0xa2adb299
+0, 7, 7, 1, 599040, 0xb9dda682
+0, 8, 8, 1, 599040, 0x9a5e7355
+0, 9, 9, 1, 599040, 0xc4bafa8c
+0, 10, 10, 1, 599040, 0xc4ec160e
+0, 11, 11, 1, 599040, 0x538421a3
+0, 12, 12, 1, 599040, 0xb294a96e
+0, 13, 13, 1, 599040, 0x9bb217df
+0, 14, 14, 1, 599040, 0xbe70c870
+0, 15, 15, 1, 599040, 0xa4e319a8
+0, 16, 16, 1, 599040, 0x3a4c702d
+0, 17, 17, 1, 599040, 0x9f790906
+0, 18, 18, 1, 599040, 0xbbfdb8d6
+0, 19, 19, 1, 599040, 0x0965c0ed
+0, 20, 20, 1, 599040, 0x6993e1f1
+0, 21, 21, 1, 599040, 0xc1cc1df9
+0, 22, 22, 1, 599040, 0xe570c390
+0, 23, 23, 1, 599040, 0x422f6fd7
+0, 24, 24, 1, 599040, 0x9c89298c
+0, 25, 25, 1, 599040, 0x5ece4193
+0, 26, 26, 1, 599040, 0x142a4f2f
+0, 27, 27, 1, 599040, 0xa5356c63
+0, 28, 28, 1, 599040, 0x8458a378
+0, 29, 29, 1, 599040, 0xc149ed56
diff --git a/tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_3 b/tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_3
index 8037e9c818..d616bac756 100644
--- a/tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_3
+++ b/tests/ref/fate/hevc-conformance-DELTAQP_C_SONY_3
@@ -1,31 +1,31 @@
#tb 0: 1/25
0, 0, 0, 1, 599040, 0xcb2969c5
-0, 2, 2, 1, 599040, 0xd9825d1f
-0, 3, 3, 1, 599040, 0x5ff4245a
-0, 4, 4, 1, 599040, 0xd34e7bcb
-0, 5, 5, 1, 599040, 0x032e1b8b
-0, 6, 6, 1, 599040, 0x5ba1873c
-0, 7, 7, 1, 599040, 0xa0b725ad
-0, 8, 8, 1, 599040, 0x9cade6a6
-0, 9, 9, 1, 599040, 0xe41bee5a
-0, 10, 10, 1, 599040, 0x9de4340f
-0, 11, 11, 1, 599040, 0xb966282a
-0, 12, 12, 1, 599040, 0x52fd5300
-0, 13, 13, 1, 599040, 0x8e6d6753
-0, 14, 14, 1, 599040, 0x2011759b
-0, 15, 15, 1, 599040, 0x5da5b7af
-0, 16, 16, 1, 599040, 0x090e298c
-0, 17, 17, 1, 599040, 0xfd618263
-0, 18, 18, 1, 599040, 0xdaf4ef69
-0, 19, 19, 1, 599040, 0x0349d1a0
-0, 20, 20, 1, 599040, 0x75a35caf
-0, 21, 21, 1, 599040, 0x4544918e
-0, 22, 22, 1, 599040, 0xbca15836
-0, 23, 23, 1, 599040, 0x443bc611
-0, 24, 24, 1, 599040, 0xc380beaf
-0, 25, 25, 1, 599040, 0x01a581ca
-0, 26, 26, 1, 599040, 0x1690835f
-0, 27, 27, 1, 599040, 0x871e9c3b
-0, 28, 28, 1, 599040, 0xf4c20a25
-0, 29, 29, 1, 599040, 0x86d8f2df
-0, 30, 30, 1, 599040, 0x7690bd56
+0, 1, 1, 1, 599040, 0xd9825d1f
+0, 2, 2, 1, 599040, 0x5ff4245a
+0, 3, 3, 1, 599040, 0xd34e7bcb
+0, 4, 4, 1, 599040, 0x032e1b8b
+0, 5, 5, 1, 599040, 0x5ba1873c
+0, 6, 6, 1, 599040, 0xa0b725ad
+0, 7, 7, 1, 599040, 0x9cade6a6
+0, 8, 8, 1, 599040, 0xe41bee5a
+0, 9, 9, 1, 599040, 0x9de4340f
+0, 10, 10, 1, 599040, 0xb966282a
+0, 11, 11, 1, 599040, 0x52fd5300
+0, 12, 12, 1, 599040, 0x8e6d6753
+0, 13, 13, 1, 599040, 0x2011759b
+0, 14, 14, 1, 599040, 0x5da5b7af
+0, 15, 15, 1, 599040, 0x090e298c
+0, 16, 16, 1, 599040, 0xfd618263
+0, 17, 17, 1, 599040, 0xdaf4ef69
+0, 18, 18, 1, 599040, 0x0349d1a0
+0, 19, 19, 1, 599040, 0x75a35caf
+0, 20, 20, 1, 599040, 0x4544918e
+0, 21, 21, 1, 599040, 0xbca15836
+0, 22, 22, 1, 599040, 0x443bc611
+0, 23, 23, 1, 599040, 0xc380beaf
+0, 24, 24, 1, 599040, 0x01a581ca
+0, 25, 25, 1, 599040, 0x1690835f
+0, 26, 26, 1, 599040, 0x871e9c3b
+0, 27, 27, 1, 599040, 0xf4c20a25
+0, 28, 28, 1, 599040, 0x86d8f2df
+0, 29, 29, 1, 599040, 0x7690bd56
diff --git a/tests/ref/fate/hevc-conformance-ENTP_A_LG_2 b/tests/ref/fate/hevc-conformance-ENTP_A_LG_2
deleted file mode 100644
index 5697619a69..0000000000
--- a/tests/ref/fate/hevc-conformance-ENTP_A_LG_2
+++ /dev/null
@@ -1,51 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 599040, 0x866449d5
-0, 1, 1, 1, 599040, 0x6a8919f0
-0, 2, 2, 1, 599040, 0x5bec3742
-0, 3, 3, 1, 599040, 0x0e66f78b
-0, 4, 4, 1, 599040, 0x798e543b
-0, 5, 5, 1, 599040, 0x342467e0
-0, 6, 6, 1, 599040, 0x2cb393e1
-0, 7, 7, 1, 599040, 0x2f326539
-0, 8, 8, 1, 599040, 0x8ac6eb6a
-0, 9, 9, 1, 599040, 0x810a887b
-0, 10, 10, 1, 599040, 0x4feb2d60
-0, 11, 11, 1, 599040, 0xd32165ff
-0, 12, 12, 1, 599040, 0x46e505e1
-0, 13, 13, 1, 599040, 0x2d917014
-0, 14, 14, 1, 599040, 0xb504f112
-0, 15, 15, 1, 599040, 0x0fca37ce
-0, 16, 16, 1, 599040, 0x2d5a269d
-0, 17, 17, 1, 599040, 0x3928ef6d
-0, 18, 18, 1, 599040, 0x94397312
-0, 19, 19, 1, 599040, 0xc1c1257b
-0, 20, 20, 1, 599040, 0x4e23adcc
-0, 21, 21, 1, 599040, 0x3eaef1e0
-0, 22, 22, 1, 599040, 0x5e66fa14
-0, 23, 23, 1, 599040, 0x2adfa0c2
-0, 24, 24, 1, 599040, 0xf888db90
-0, 25, 25, 1, 599040, 0xab3a6418
-0, 26, 26, 1, 599040, 0x7689d0a2
-0, 27, 27, 1, 599040, 0x2f5746bf
-0, 28, 28, 1, 599040, 0xad2cf3da
-0, 29, 29, 1, 599040, 0x32f2854e
-0, 30, 30, 1, 599040, 0xb73cf7db
-0, 31, 31, 1, 599040, 0xbe996991
-0, 32, 32, 1, 599040, 0xe66501c8
-0, 33, 33, 1, 599040, 0x12d1bc13
-0, 34, 34, 1, 599040, 0x06e103d5
-0, 35, 35, 1, 599040, 0x49af0680
-0, 36, 36, 1, 599040, 0xdbf128b0
-0, 37, 37, 1, 599040, 0xa1ac770d
-0, 38, 38, 1, 599040, 0x99156429
-0, 39, 39, 1, 599040, 0x8ce1a9a7
-0, 40, 40, 1, 599040, 0x14067700
-0, 41, 41, 1, 599040, 0xcdedccee
-0, 42, 42, 1, 599040, 0x09c12765
-0, 43, 43, 1, 599040, 0x7979a1be
-0, 44, 44, 1, 599040, 0xbd3148d1
-0, 45, 45, 1, 599040, 0xc83f9aac
-0, 46, 46, 1, 599040, 0x91acbae4
-0, 47, 47, 1, 599040, 0xd230907a
-0, 48, 48, 1, 599040, 0x3f6c31f6
-0, 49, 49, 1, 599040, 0x84496e55
diff --git a/tests/ref/fate/hevc-conformance-ENTP_A_Qualcomm_1 b/tests/ref/fate/hevc-conformance-ENTP_A_Qualcomm_1
new file mode 100644
index 0000000000..4454bfadff
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-ENTP_A_Qualcomm_1
@@ -0,0 +1,25 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x26663e50
+0, 1, 1, 1, 3110400, 0x64ae36c1
+0, 2, 2, 1, 3110400, 0x5c72ac0b
+0, 3, 3, 1, 3110400, 0x13617553
+0, 4, 4, 1, 3110400, 0xee94be8a
+0, 5, 5, 1, 3110400, 0x6324f8da
+0, 6, 6, 1, 3110400, 0xea0dd277
+0, 7, 7, 1, 3110400, 0xdf3e6b85
+0, 8, 8, 1, 3110400, 0xdc754b17
+0, 9, 9, 1, 3110400, 0xbb53a891
+0, 10, 10, 1, 3110400, 0x53c6575a
+0, 11, 11, 1, 3110400, 0xda720794
+0, 12, 12, 1, 3110400, 0x21be3522
+0, 13, 13, 1, 3110400, 0x7fd72aa9
+0, 14, 14, 1, 3110400, 0xeb0d104a
+0, 15, 15, 1, 3110400, 0xd038405a
+0, 16, 16, 1, 3110400, 0xd1f8b9fa
+0, 17, 17, 1, 3110400, 0xc96d2b8c
+0, 18, 18, 1, 3110400, 0x07f77dcd
+0, 19, 19, 1, 3110400, 0x673b444c
+0, 20, 20, 1, 3110400, 0x5a8b4836
+0, 21, 21, 1, 3110400, 0x1ce733d3
+0, 22, 22, 1, 3110400, 0xd919ae60
+0, 23, 23, 1, 3110400, 0x5dcc11c0
diff --git a/tests/ref/fate/hevc-conformance-ENTP_B_LG_2 b/tests/ref/fate/hevc-conformance-ENTP_B_LG_2
deleted file mode 100644
index 0251f3070c..0000000000
--- a/tests/ref/fate/hevc-conformance-ENTP_B_LG_2
+++ /dev/null
@@ -1,51 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 599040, 0x95a24137
-0, 1, 1, 1, 599040, 0x7d7f2b75
-0, 2, 2, 1, 599040, 0xd9fb2120
-0, 3, 3, 1, 599040, 0x14d50590
-0, 4, 4, 1, 599040, 0xe3d1b70e
-0, 5, 5, 1, 599040, 0x57708a86
-0, 6, 6, 1, 599040, 0xae56a720
-0, 7, 7, 1, 599040, 0x74c18679
-0, 8, 8, 1, 599040, 0x6422d2a7
-0, 9, 9, 1, 599040, 0xf587702b
-0, 10, 10, 1, 599040, 0x0f630fe0
-0, 11, 11, 1, 599040, 0x4e3537dd
-0, 12, 12, 1, 599040, 0xa645e9c1
-0, 13, 13, 1, 599040, 0x35ab4155
-0, 14, 14, 1, 599040, 0x4b78ba34
-0, 15, 15, 1, 599040, 0xa9a9e572
-0, 16, 16, 1, 599040, 0x6d57f10f
-0, 17, 17, 1, 599040, 0xffb8e333
-0, 18, 18, 1, 599040, 0x7b2d6319
-0, 19, 19, 1, 599040, 0xcf3319aa
-0, 20, 20, 1, 599040, 0xb0d097ee
-0, 21, 21, 1, 599040, 0xf042f780
-0, 22, 22, 1, 599040, 0xfafafdcb
-0, 23, 23, 1, 599040, 0xc8c1c452
-0, 24, 24, 1, 599040, 0x83c4d488
-0, 25, 25, 1, 599040, 0x81a8fd08
-0, 26, 26, 1, 599040, 0x2cb0c333
-0, 27, 27, 1, 599040, 0xa7bf4e52
-0, 28, 28, 1, 599040, 0x5b7ed8e9
-0, 29, 29, 1, 599040, 0x4ff03464
-0, 30, 30, 1, 599040, 0x54a700c2
-0, 31, 31, 1, 599040, 0x7dbb63aa
-0, 32, 32, 1, 599040, 0xda26288e
-0, 33, 33, 1, 599040, 0x8074da41
-0, 34, 34, 1, 599040, 0xa32b2ab2
-0, 35, 35, 1, 599040, 0x51b457fb
-0, 36, 36, 1, 599040, 0x05e34953
-0, 37, 37, 1, 599040, 0x68c762d6
-0, 38, 38, 1, 599040, 0x11bf469e
-0, 39, 39, 1, 599040, 0xc2fdadaf
-0, 40, 40, 1, 599040, 0x05588da0
-0, 41, 41, 1, 599040, 0x8855f927
-0, 42, 42, 1, 599040, 0x11c85d5a
-0, 43, 43, 1, 599040, 0x7a0aede5
-0, 44, 44, 1, 599040, 0x39dc4f7d
-0, 45, 45, 1, 599040, 0x388f81d6
-0, 46, 46, 1, 599040, 0x2afa830d
-0, 47, 47, 1, 599040, 0xd7f26886
-0, 48, 48, 1, 599040, 0xb8e12aef
-0, 49, 49, 1, 599040, 0x73f7582c
diff --git a/tests/ref/fate/hevc-conformance-ENTP_B_Qualcomm_1 b/tests/ref/fate/hevc-conformance-ENTP_B_Qualcomm_1
new file mode 100644
index 0000000000..547b590119
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-ENTP_B_Qualcomm_1
@@ -0,0 +1,25 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x7d014690
+0, 1, 1, 1, 3110400, 0xe02cd173
+0, 2, 2, 1, 3110400, 0x2f9794c5
+0, 3, 3, 1, 3110400, 0x5df433de
+0, 4, 4, 1, 3110400, 0xae409f1d
+0, 5, 5, 1, 3110400, 0xb4886e82
+0, 6, 6, 1, 3110400, 0x636ee735
+0, 7, 7, 1, 3110400, 0x4d340b3f
+0, 8, 8, 1, 3110400, 0xf11ce983
+0, 9, 9, 1, 3110400, 0x2a1b2094
+0, 10, 10, 1, 3110400, 0x1dee485f
+0, 11, 11, 1, 3110400, 0xac329574
+0, 12, 12, 1, 3110400, 0xa0f11f30
+0, 13, 13, 1, 3110400, 0x99d827d3
+0, 14, 14, 1, 3110400, 0xa0b75c5b
+0, 15, 15, 1, 3110400, 0xf3f169d8
+0, 16, 16, 1, 3110400, 0xde71892b
+0, 17, 17, 1, 3110400, 0xf1129a0e
+0, 18, 18, 1, 3110400, 0x02150e54
+0, 19, 19, 1, 3110400, 0xc79d65a4
+0, 20, 20, 1, 3110400, 0x708fc8fb
+0, 21, 21, 1, 3110400, 0x5431050b
+0, 22, 22, 1, 3110400, 0x237faa60
+0, 23, 23, 1, 3110400, 0xb05ffa7c
diff --git a/tests/ref/fate/hevc-conformance-ENTP_C_LG_3 b/tests/ref/fate/hevc-conformance-ENTP_C_LG_3
deleted file mode 100644
index 3c0946e93f..0000000000
--- a/tests/ref/fate/hevc-conformance-ENTP_C_LG_3
+++ /dev/null
@@ -1,51 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 3110400, 0xaea1c3d6
-0, 1, 1, 1, 3110400, 0x665b4f52
-0, 2, 2, 1, 3110400, 0xc7da58a2
-0, 3, 3, 1, 3110400, 0x1dda6461
-0, 4, 4, 1, 3110400, 0x1d8d6eaf
-0, 5, 5, 1, 3110400, 0x7a29911a
-0, 6, 6, 1, 3110400, 0x0dce92c9
-0, 7, 7, 1, 3110400, 0x79c84570
-0, 8, 8, 1, 3110400, 0x736ef1e7
-0, 9, 9, 1, 3110400, 0x9dd86492
-0, 10, 10, 1, 3110400, 0x0ea31a1b
-0, 11, 11, 1, 3110400, 0x0d84fdc8
-0, 12, 12, 1, 3110400, 0x06ed89a7
-0, 13, 13, 1, 3110400, 0xfaea4fd6
-0, 14, 14, 1, 3110400, 0xe787abe8
-0, 15, 15, 1, 3110400, 0x050b653a
-0, 16, 16, 1, 3110400, 0x35cc1ec1
-0, 17, 17, 1, 3110400, 0x86a43e07
-0, 18, 18, 1, 3110400, 0xa6ab021e
-0, 19, 19, 1, 3110400, 0x491e0efa
-0, 20, 20, 1, 3110400, 0x8f210c38
-0, 21, 21, 1, 3110400, 0x637af0d0
-0, 22, 22, 1, 3110400, 0x47a59197
-0, 23, 23, 1, 3110400, 0x53e04637
-0, 24, 24, 1, 3110400, 0x7b99325e
-0, 25, 25, 1, 3110400, 0x972aa252
-0, 26, 26, 1, 3110400, 0xe76ef917
-0, 27, 27, 1, 3110400, 0x7a25babc
-0, 28, 28, 1, 3110400, 0x3bee3c5c
-0, 29, 29, 1, 3110400, 0xbae82bcb
-0, 30, 30, 1, 3110400, 0x5b65c1e5
-0, 31, 31, 1, 3110400, 0xa546266f
-0, 32, 32, 1, 3110400, 0x5c5b9b8e
-0, 33, 33, 1, 3110400, 0xec29c804
-0, 34, 34, 1, 3110400, 0x384efc7d
-0, 35, 35, 1, 3110400, 0x6c1aaa23
-0, 36, 36, 1, 3110400, 0x55494f9f
-0, 37, 37, 1, 3110400, 0xa9c56fec
-0, 38, 38, 1, 3110400, 0x49c29ef2
-0, 39, 39, 1, 3110400, 0xac24fdd4
-0, 40, 40, 1, 3110400, 0x403d8213
-0, 41, 41, 1, 3110400, 0xf2d8aefe
-0, 42, 42, 1, 3110400, 0x2884f0e1
-0, 43, 43, 1, 3110400, 0x69a0a781
-0, 44, 44, 1, 3110400, 0x3ab6114c
-0, 45, 45, 1, 3110400, 0x1d4425a2
-0, 46, 46, 1, 3110400, 0x59f8970a
-0, 47, 47, 1, 3110400, 0xfe0a05a9
-0, 48, 48, 1, 3110400, 0x50b9be4f
-0, 49, 49, 1, 3110400, 0x3e1b65bd
diff --git a/tests/ref/fate/hevc-conformance-ENTP_C_Qualcomm_1 b/tests/ref/fate/hevc-conformance-ENTP_C_Qualcomm_1
new file mode 100644
index 0000000000..2c21f35d42
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-ENTP_C_Qualcomm_1
@@ -0,0 +1,25 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x4ea3fa57
+0, 1, 1, 1, 3110400, 0xbe33724f
+0, 2, 2, 1, 3110400, 0x9011755e
+0, 3, 3, 1, 3110400, 0x62de338c
+0, 4, 4, 1, 3110400, 0xa49096c5
+0, 5, 5, 1, 3110400, 0xc7af7402
+0, 6, 6, 1, 3110400, 0xd8241f6b
+0, 7, 7, 1, 3110400, 0x82ebc552
+0, 8, 8, 1, 3110400, 0x57c07503
+0, 9, 9, 1, 3110400, 0xc302fc68
+0, 10, 10, 1, 3110400, 0x10183476
+0, 11, 11, 1, 3110400, 0xa953ab4b
+0, 12, 12, 1, 3110400, 0xe1daee4f
+0, 13, 13, 1, 3110400, 0x86828802
+0, 14, 14, 1, 3110400, 0x9bb96175
+0, 15, 15, 1, 3110400, 0xe6c033a0
+0, 16, 16, 1, 3110400, 0x417407dd
+0, 17, 17, 1, 3110400, 0x422ef66c
+0, 18, 18, 1, 3110400, 0x3d216600
+0, 19, 19, 1, 3110400, 0xdfd83135
+0, 20, 20, 1, 3110400, 0x8deff979
+0, 21, 21, 1, 3110400, 0xbce973f4
+0, 22, 22, 1, 3110400, 0x2ae172e2
+0, 23, 23, 1, 3110400, 0x2aa32f21
diff --git a/tests/ref/fate/hevc-conformance-FILLER_A_Sony_1 b/tests/ref/fate/hevc-conformance-FILLER_A_Sony_1
new file mode 100644
index 0000000000..809b4cd4ba
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-FILLER_A_Sony_1
@@ -0,0 +1,61 @@
+#tb 0: 1001/30000
+0, 0, 0, 1, 149760, 0x83261e41
+0, 1, 1, 1, 149760, 0xa8c02e8e
+0, 2, 2, 1, 149760, 0xb89d1fa0
+0, 3, 3, 1, 149760, 0x22f83f2a
+0, 4, 4, 1, 149760, 0x0529e619
+0, 5, 5, 1, 149760, 0x18488682
+0, 6, 6, 1, 149760, 0x91c0fde2
+0, 7, 7, 1, 149760, 0xe07355aa
+0, 8, 8, 1, 149760, 0x6deca92f
+0, 9, 9, 1, 149760, 0xcd16e610
+0, 10, 10, 1, 149760, 0x3fd6cab8
+0, 11, 11, 1, 149760, 0x063e39e4
+0, 12, 12, 1, 149760, 0x8b1fb242
+0, 13, 13, 1, 149760, 0x00ef6987
+0, 14, 14, 1, 149760, 0xdfa7e8ab
+0, 15, 15, 1, 149760, 0x315a23a8
+0, 16, 16, 1, 149760, 0xdd655173
+0, 17, 17, 1, 149760, 0x741b9603
+0, 18, 18, 1, 149760, 0x4a3c29a4
+0, 19, 19, 1, 149760, 0xb14b06f4
+0, 20, 20, 1, 149760, 0x5dd7fa14
+0, 21, 21, 1, 149760, 0x60dac9fe
+0, 22, 22, 1, 149760, 0x231effa8
+0, 23, 23, 1, 149760, 0x6b0cca33
+0, 24, 24, 1, 149760, 0xb1fc6596
+0, 25, 25, 1, 149760, 0x683fa8b5
+0, 26, 26, 1, 149760, 0xa9da45be
+0, 27, 27, 1, 149760, 0x96d69624
+0, 28, 28, 1, 149760, 0xff9e0778
+0, 29, 29, 1, 149760, 0x7410078e
+0, 30, 30, 1, 149760, 0x6418b280
+0, 31, 31, 1, 149760, 0xee66b0dd
+0, 32, 32, 1, 149760, 0xdf4d06fb
+0, 33, 33, 1, 149760, 0xf75c33fd
+0, 34, 34, 1, 149760, 0x73e97017
+0, 35, 35, 1, 149760, 0xcc8c4e15
+0, 36, 36, 1, 149760, 0xa494d7f7
+0, 37, 37, 1, 149760, 0x57564b5f
+0, 38, 38, 1, 149760, 0x84433b5c
+0, 39, 39, 1, 149760, 0x8ec138cf
+0, 40, 40, 1, 149760, 0x72a9e2df
+0, 41, 41, 1, 149760, 0x69ee26c7
+0, 42, 42, 1, 149760, 0x8d85941b
+0, 43, 43, 1, 149760, 0xfa9f41a2
+0, 44, 44, 1, 149760, 0x2ec9d6df
+0, 45, 45, 1, 149760, 0xb9a85b2b
+0, 46, 46, 1, 149760, 0xea10c86d
+0, 47, 47, 1, 149760, 0x2a2d0c1b
+0, 48, 48, 1, 149760, 0xb96395d7
+0, 49, 49, 1, 149760, 0xb9abdbde
+0, 50, 50, 1, 149760, 0x8aff19ae
+0, 51, 51, 1, 149760, 0xa46d1e0b
+0, 52, 52, 1, 149760, 0xb5943391
+0, 53, 53, 1, 149760, 0x49aacf5c
+0, 54, 54, 1, 149760, 0x837b6b38
+0, 55, 55, 1, 149760, 0x1455d41b
+0, 56, 56, 1, 149760, 0xf5b87056
+0, 57, 57, 1, 149760, 0x15ef5ca7
+0, 58, 58, 1, 149760, 0x29edded5
+0, 59, 59, 1, 149760, 0x86f1eb45
diff --git a/tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_2 b/tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_2
new file mode 100644
index 0000000000..d887df2150
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_2
@@ -0,0 +1,97 @@
+#tb 0: 1/50
+0, 0, 0, 1, 149760, 0x49bcac59
+0, 1, 1, 1, 149760, 0x30ffadcd
+0, 2, 2, 1, 149760, 0x85ccc14a
+0, 3, 3, 1, 149760, 0x9e80bab5
+0, 4, 4, 1, 149760, 0xf4d6b065
+0, 5, 5, 1, 149760, 0x3dfea025
+0, 6, 6, 1, 149760, 0x752381f4
+0, 7, 7, 1, 149760, 0x55875176
+0, 8, 8, 1, 149760, 0xaeeceea9
+0, 9, 9, 1, 149760, 0xfa19792b
+0, 10, 10, 1, 149760, 0x1f0cfa3c
+0, 11, 11, 1, 149760, 0xecc09b1a
+0, 12, 12, 1, 149760, 0x816e4e1b
+0, 13, 13, 1, 149760, 0x375cef94
+0, 14, 14, 1, 149760, 0xace1a0ff
+0, 15, 15, 1, 149760, 0x85827658
+0, 16, 16, 1, 149760, 0x8189237e
+0, 17, 17, 1, 149760, 0xec53e171
+0, 18, 18, 1, 149760, 0x0b1bad4a
+0, 19, 19, 1, 149760, 0x9d566fd0
+0, 20, 20, 1, 149760, 0x9b323c87
+0, 21, 21, 1, 149760, 0x2d900cb7
+0, 22, 22, 1, 149760, 0x7062ed06
+0, 23, 23, 1, 149760, 0xe687c687
+0, 24, 24, 1, 149760, 0x4767dd46
+0, 25, 25, 1, 149760, 0xf0d04aae
+0, 26, 26, 1, 149760, 0x1a9d0640
+0, 27, 27, 1, 149760, 0xc831e356
+0, 28, 28, 1, 149760, 0x3b5ee48b
+0, 29, 29, 1, 149760, 0x083f94ec
+0, 30, 30, 1, 149760, 0xfd92050f
+0, 31, 31, 1, 149760, 0x23ce5764
+0, 32, 32, 1, 149760, 0x98167d17
+0, 33, 33, 1, 149760, 0x458a1e97
+0, 34, 34, 1, 149760, 0x913fe090
+0, 35, 35, 1, 149760, 0xdf87fb99
+0, 36, 36, 1, 149760, 0x2c9ffb76
+0, 37, 37, 1, 149760, 0xe52b1f88
+0, 38, 38, 1, 149760, 0xeb6441b3
+0, 39, 39, 1, 149760, 0x229a3428
+0, 40, 40, 1, 149760, 0xab5dc58c
+0, 41, 41, 1, 149760, 0xfdaff77d
+0, 42, 42, 1, 149760, 0x120326dc
+0, 43, 43, 1, 149760, 0x9a9ff8fd
+0, 44, 44, 1, 149760, 0x4e5bb152
+0, 45, 45, 1, 149760, 0x2d16f231
+0, 46, 46, 1, 149760, 0x99a01d57
+0, 47, 47, 1, 149760, 0x3a555c12
+0, 48, 48, 1, 149760, 0x20ad0e79
+0, 49, 49, 1, 149760, 0xc62724f2
+0, 50, 50, 1, 149760, 0x07a81153
+0, 51, 51, 1, 149760, 0x14b9732e
+0, 52, 52, 1, 149760, 0xeefa0be1
+0, 53, 53, 1, 149760, 0x95a82b9e
+0, 54, 54, 1, 149760, 0xa6ecbed4
+0, 55, 55, 1, 149760, 0xaaec0cf6
+0, 56, 56, 1, 149760, 0x087815ca
+0, 57, 57, 1, 149760, 0xff82b221
+0, 58, 58, 1, 149760, 0x709afb9f
+0, 59, 59, 1, 149760, 0xb91e712a
+0, 60, 60, 1, 149760, 0x66dfbaaa
+0, 61, 61, 1, 149760, 0x574501b2
+0, 62, 62, 1, 149760, 0xe1c13daf
+0, 63, 63, 1, 149760, 0xdab85ad6
+0, 64, 64, 1, 149760, 0x57e8a455
+0, 65, 65, 1, 149760, 0xfc95db86
+0, 66, 66, 1, 149760, 0xe298f7ee
+0, 67, 67, 1, 149760, 0x13302040
+0, 68, 68, 1, 149760, 0x69811199
+0, 69, 69, 1, 149760, 0x64f31874
+0, 70, 70, 1, 149760, 0xc1450115
+0, 71, 71, 1, 149760, 0xf0efc355
+0, 72, 72, 1, 149760, 0xeaee572d
+0, 73, 73, 1, 149760, 0xf256fc07
+0, 74, 74, 1, 149760, 0x20d48047
+0, 75, 75, 1, 149760, 0x37a934bf
+0, 76, 76, 1, 149760, 0xd14bcc48
+0, 77, 77, 1, 149760, 0x3de67683
+0, 78, 78, 1, 149760, 0x3b3b2edd
+0, 79, 79, 1, 149760, 0x8cf00f8d
+0, 80, 80, 1, 149760, 0x83d8ddff
+0, 81, 81, 1, 149760, 0xf2f36ae4
+0, 82, 82, 1, 149760, 0xf2549f1a
+0, 83, 83, 1, 149760, 0x6c5a9443
+0, 84, 84, 1, 149760, 0x071e4d64
+0, 85, 85, 1, 149760, 0x0b160074
+0, 86, 86, 1, 149760, 0x0ebdf969
+0, 87, 87, 1, 149760, 0x0331793d
+0, 88, 88, 1, 149760, 0xee7ad61f
+0, 89, 89, 1, 149760, 0xb9ba083f
+0, 90, 90, 1, 149760, 0x8ecf1f9d
+0, 91, 91, 1, 149760, 0x6e861158
+0, 92, 92, 1, 149760, 0x977a203b
+0, 93, 93, 1, 149760, 0xa25d1077
+0, 94, 94, 1, 149760, 0xa4d2fca1
+0, 95, 95, 1, 149760, 0x6093084d
diff --git a/tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_3 b/tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_3
new file mode 100644
index 0000000000..7446ae8ad4
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-HRD_A_Fujitsu_3
@@ -0,0 +1,97 @@
+#tb 0: 1/50
+0, 0, 0, 1, 149760, 0xa329afaa
+0, 1, 1, 1, 149760, 0xb326c405
+0, 2, 2, 1, 149760, 0x7834b936
+0, 3, 3, 1, 149760, 0xb46dbb3e
+0, 4, 4, 1, 149760, 0xcf1ea94c
+0, 5, 5, 1, 149760, 0x4eac94fa
+0, 6, 6, 1, 149760, 0xbfdb808f
+0, 7, 7, 1, 149760, 0x62806469
+0, 8, 8, 1, 149760, 0x74420022
+0, 9, 9, 1, 149760, 0x91e97911
+0, 10, 10, 1, 149760, 0x4903fc4a
+0, 11, 11, 1, 149760, 0x31a09d4e
+0, 12, 12, 1, 149760, 0xeb404776
+0, 13, 13, 1, 149760, 0xadd2ee9e
+0, 14, 14, 1, 149760, 0x23e7a8b7
+0, 15, 15, 1, 149760, 0x76ac5fb9
+0, 16, 16, 1, 149760, 0x32770d4f
+0, 17, 17, 1, 149760, 0x208ddbd0
+0, 18, 18, 1, 149760, 0xf2559760
+0, 19, 19, 1, 149760, 0x3bc65f9e
+0, 20, 20, 1, 149760, 0x9f10263b
+0, 21, 21, 1, 149760, 0x3978edd8
+0, 22, 22, 1, 149760, 0x7afde5b9
+0, 23, 23, 1, 149760, 0xc01699f8
+0, 24, 24, 1, 149760, 0x5056cdeb
+0, 25, 25, 1, 149760, 0xf2275141
+0, 26, 26, 1, 149760, 0xe22efce6
+0, 27, 27, 1, 149760, 0x4331e359
+0, 28, 28, 1, 149760, 0x9a5e031d
+0, 29, 29, 1, 149760, 0x8982a88f
+0, 30, 30, 1, 149760, 0x7e27f127
+0, 31, 31, 1, 149760, 0x1a5a422c
+0, 32, 32, 1, 149760, 0x39328011
+0, 33, 33, 1, 149760, 0x26c335ca
+0, 34, 34, 1, 149760, 0x6429d5e2
+0, 35, 35, 1, 149760, 0x7cf52425
+0, 36, 36, 1, 149760, 0x1762186c
+0, 37, 37, 1, 149760, 0xe0e9370f
+0, 38, 38, 1, 149760, 0x1f0a3f7a
+0, 39, 39, 1, 149760, 0xf19e30be
+0, 40, 40, 1, 149760, 0x14b9a723
+0, 41, 41, 1, 149760, 0x3514f916
+0, 42, 42, 1, 149760, 0x21dd1e9a
+0, 43, 43, 1, 149760, 0x02b2f69c
+0, 44, 44, 1, 149760, 0xec1fa93a
+0, 45, 45, 1, 149760, 0xad45ea1f
+0, 46, 46, 1, 149760, 0x22092591
+0, 47, 47, 1, 149760, 0x733b205b
+0, 48, 48, 1, 149760, 0xcd85ef6a
+0, 49, 49, 1, 149760, 0x5d3afdfb
+0, 50, 50, 1, 149760, 0xc7200b59
+0, 51, 51, 1, 149760, 0xf2c74f38
+0, 52, 52, 1, 149760, 0x8f0b0a60
+0, 53, 53, 1, 149760, 0x875a0fa6
+0, 54, 54, 1, 149760, 0x03ac9cbc
+0, 55, 55, 1, 149760, 0x16830708
+0, 56, 56, 1, 149760, 0xabe709cc
+0, 57, 57, 1, 149760, 0xc5019f66
+0, 58, 58, 1, 149760, 0x6355f5e2
+0, 59, 59, 1, 149760, 0x7770586e
+0, 60, 60, 1, 149760, 0x482aa304
+0, 61, 61, 1, 149760, 0x9b90ef01
+0, 62, 62, 1, 149760, 0x22153180
+0, 63, 63, 1, 149760, 0x23876fda
+0, 64, 64, 1, 149760, 0xfa9d938d
+0, 65, 65, 1, 149760, 0x5731d140
+0, 66, 66, 1, 149760, 0x734ce2c1
+0, 67, 67, 1, 149760, 0x74dafecd
+0, 68, 68, 1, 149760, 0x33b4ff4e
+0, 69, 69, 1, 149760, 0xcd8ef975
+0, 70, 70, 1, 149760, 0xc97cd0ee
+0, 71, 71, 1, 149760, 0x88faa07a
+0, 72, 72, 1, 149760, 0x8c174fe9
+0, 73, 73, 1, 149760, 0x9c60e74e
+0, 74, 74, 1, 149760, 0x7faf7160
+0, 75, 75, 1, 149760, 0x94c70d14
+0, 76, 76, 1, 149760, 0x8e49a6b1
+0, 77, 77, 1, 149760, 0x67255170
+0, 78, 78, 1, 149760, 0xeb1d1a49
+0, 79, 79, 1, 149760, 0x9413051f
+0, 80, 80, 1, 149760, 0x43bce110
+0, 81, 81, 1, 149760, 0x76c821ec
+0, 82, 82, 1, 149760, 0x21487745
+0, 83, 83, 1, 149760, 0xb8776615
+0, 84, 84, 1, 149760, 0x1f2ffc65
+0, 85, 85, 1, 149760, 0x3f1eb53d
+0, 86, 86, 1, 149760, 0x9d15c8e0
+0, 87, 87, 1, 149760, 0x44e77332
+0, 88, 88, 1, 149760, 0x629bb845
+0, 89, 89, 1, 149760, 0x80ea02e8
+0, 90, 90, 1, 149760, 0x405d1653
+0, 91, 91, 1, 149760, 0x0ee8fccd
+0, 92, 92, 1, 149760, 0x4444fe13
+0, 93, 93, 1, 149760, 0x7493f631
+0, 94, 94, 1, 149760, 0xa6c1f737
+0, 95, 95, 1, 149760, 0xb84b055d
diff --git a/tests/ref/fate/hevc-conformance-INITQP_A_Sony_1 b/tests/ref/fate/hevc-conformance-INITQP_A_Sony_1
new file mode 100644
index 0000000000..e99e3897be
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-INITQP_A_Sony_1
@@ -0,0 +1,61 @@
+#tb 0: 1001/30000
+0, 0, 0, 1, 149760, 0x59891e4e
+0, 1, 1, 1, 149760, 0x6c152de8
+0, 2, 2, 1, 149760, 0x6f2c0f37
+0, 3, 3, 1, 149760, 0xdc4142e9
+0, 4, 4, 1, 149760, 0x13a6dfe0
+0, 5, 5, 1, 149760, 0xea2b8197
+0, 6, 6, 1, 149760, 0x228207b8
+0, 7, 7, 1, 149760, 0xe6c33dc5
+0, 8, 8, 1, 149760, 0xa488a0f6
+0, 9, 9, 1, 149760, 0xf618c591
+0, 10, 10, 1, 149760, 0x0c96c7eb
+0, 11, 11, 1, 149760, 0x347b17b8
+0, 12, 12, 1, 149760, 0xa2379e18
+0, 13, 13, 1, 149760, 0x635a7cbd
+0, 14, 14, 1, 149760, 0xa770ed3c
+0, 15, 15, 1, 149760, 0x54271b2b
+0, 16, 16, 1, 149760, 0xc09751d6
+0, 17, 17, 1, 149760, 0xa33997cb
+0, 18, 18, 1, 149760, 0x8f382ef3
+0, 19, 19, 1, 149760, 0x449311d8
+0, 20, 20, 1, 149760, 0x67a2f419
+0, 21, 21, 1, 149760, 0xa025b8a1
+0, 22, 22, 1, 149760, 0xebb7e911
+0, 23, 23, 1, 149760, 0x6decb08e
+0, 24, 24, 1, 149760, 0x20a354ef
+0, 25, 25, 1, 149760, 0x6d609fc5
+0, 26, 26, 1, 149760, 0x73992f9b
+0, 27, 27, 1, 149760, 0x46968752
+0, 28, 28, 1, 149760, 0xd9e9017d
+0, 29, 29, 1, 149760, 0xae321b3c
+0, 30, 30, 1, 149760, 0x0f53a016
+0, 31, 31, 1, 149760, 0x74a5aacd
+0, 32, 32, 1, 149760, 0x893afc39
+0, 33, 33, 1, 149760, 0xbeb13aed
+0, 34, 34, 1, 149760, 0xc8658ed9
+0, 35, 35, 1, 149760, 0xcf7d544e
+0, 36, 36, 1, 149760, 0x782bd063
+0, 37, 37, 1, 149760, 0x32c53ffa
+0, 38, 38, 1, 149760, 0xed3849c2
+0, 39, 39, 1, 149760, 0xda5f336a
+0, 40, 40, 1, 149760, 0x0460dbf7
+0, 41, 41, 1, 149760, 0x782f25e3
+0, 42, 42, 1, 149760, 0x1199900a
+0, 43, 43, 1, 149760, 0xd51e4dfd
+0, 44, 44, 1, 149760, 0xfd32e6d5
+0, 45, 45, 1, 149760, 0x880d5f9b
+0, 46, 46, 1, 149760, 0xe1a7b52d
+0, 47, 47, 1, 149760, 0x97c4228a
+0, 48, 48, 1, 149760, 0x0c539d58
+0, 49, 49, 1, 149760, 0x5edfd99e
+0, 50, 50, 1, 149760, 0x92a40dcc
+0, 51, 51, 1, 149760, 0xa33dff8d
+0, 52, 52, 1, 149760, 0xf9f637ee
+0, 53, 53, 1, 149760, 0x4c02c63d
+0, 54, 54, 1, 149760, 0x94125eda
+0, 55, 55, 1, 149760, 0x0ba6d181
+0, 56, 56, 1, 149760, 0x1c4b7cf1
+0, 57, 57, 1, 149760, 0x3af454c4
+0, 58, 58, 1, 149760, 0x3666e3f4
+0, 59, 59, 1, 149760, 0x1013f2ec
diff --git a/tests/ref/fate/hevc-conformance-INITQP_B_Sony_1 b/tests/ref/fate/hevc-conformance-INITQP_B_Sony_1
new file mode 100644
index 0000000000..e00c29f1cc
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-INITQP_B_Sony_1
@@ -0,0 +1,91 @@
+#tb 0: 1001/30000
+0, 0, 0, 1, 299520, 0x5514958a
+0, 1, 1, 1, 299520, 0x06725ede
+0, 2, 2, 1, 299520, 0xa71d1493
+0, 3, 3, 1, 299520, 0xdd4cde37
+0, 4, 4, 1, 299520, 0x6ea2f981
+0, 5, 5, 1, 299520, 0x34de0d7f
+0, 6, 6, 1, 299520, 0xe3555f62
+0, 7, 7, 1, 299520, 0xa56cf8b5
+0, 8, 8, 1, 299520, 0x74f85f70
+0, 9, 9, 1, 299520, 0x7cc4ff3b
+0, 10, 10, 1, 299520, 0xacaf62f0
+0, 11, 11, 1, 299520, 0x049aa473
+0, 12, 12, 1, 299520, 0x3d202b52
+0, 13, 13, 1, 299520, 0x530920d5
+0, 14, 14, 1, 299520, 0xcf69e5c8
+0, 15, 15, 1, 299520, 0x18ad9a4f
+0, 16, 16, 1, 299520, 0xc8c1bbd9
+0, 17, 17, 1, 299520, 0x6cd37ffc
+0, 18, 18, 1, 299520, 0xc8d64c57
+0, 19, 19, 1, 299520, 0xec4679bf
+0, 20, 20, 1, 299520, 0xc4228355
+0, 21, 21, 1, 299520, 0x908c71b0
+0, 22, 22, 1, 299520, 0x4c4a92eb
+0, 23, 23, 1, 299520, 0x28f7d30d
+0, 24, 24, 1, 299520, 0xed2db3da
+0, 25, 25, 1, 299520, 0xfb22801f
+0, 26, 26, 1, 299520, 0x514de5b9
+0, 27, 27, 1, 299520, 0x7bb8d8f7
+0, 28, 28, 1, 299520, 0x3e43ae30
+0, 29, 29, 1, 299520, 0x45473924
+0, 30, 30, 1, 299520, 0x914a440e
+0, 31, 31, 1, 299520, 0x91e74926
+0, 32, 32, 1, 299520, 0xa8a43ffd
+0, 33, 33, 1, 299520, 0x1df08075
+0, 34, 34, 1, 299520, 0x84611007
+0, 35, 35, 1, 299520, 0x622d7495
+0, 36, 36, 1, 299520, 0xede897b6
+0, 37, 37, 1, 299520, 0xb14f0650
+0, 38, 38, 1, 299520, 0x74f600f9
+0, 39, 39, 1, 299520, 0xf04e2de3
+0, 40, 40, 1, 299520, 0xaeadd6fc
+0, 41, 41, 1, 299520, 0xb5855f8d
+0, 42, 42, 1, 299520, 0xbb6c709f
+0, 43, 43, 1, 299520, 0x486d66e9
+0, 44, 44, 1, 299520, 0x87e7d165
+0, 45, 45, 1, 299520, 0x1f936d47
+0, 46, 46, 1, 299520, 0x2da721a2
+0, 47, 47, 1, 299520, 0x36caf481
+0, 48, 48, 1, 299520, 0x067e3f4d
+0, 49, 49, 1, 299520, 0x1a95c86b
+0, 50, 50, 1, 299520, 0x186c1bde
+0, 51, 51, 1, 299520, 0xd1552b21
+0, 52, 52, 1, 299520, 0x72521786
+0, 53, 53, 1, 299520, 0xe0f0b1b2
+0, 54, 54, 1, 299520, 0xee8c6751
+0, 55, 55, 1, 299520, 0x281817ef
+0, 56, 56, 1, 299520, 0xea98b174
+0, 57, 57, 1, 299520, 0x839575de
+0, 58, 58, 1, 299520, 0xd89b6ff1
+0, 59, 59, 1, 299520, 0xee8432a7
+0, 60, 60, 1, 299520, 0x8f262218
+0, 61, 61, 1, 299520, 0xac918f83
+0, 62, 62, 1, 299520, 0x398c23d7
+0, 63, 63, 1, 299520, 0xdc560109
+0, 64, 64, 1, 299520, 0xb4c3cd8b
+0, 65, 65, 1, 299520, 0x79824026
+0, 66, 66, 1, 299520, 0xd20f5be8
+0, 67, 67, 1, 299520, 0xc93b32a3
+0, 68, 68, 1, 299520, 0xc1363d67
+0, 69, 69, 1, 299520, 0xeb6d2f0a
+0, 70, 70, 1, 299520, 0x29053a08
+0, 71, 71, 1, 299520, 0x8a236752
+0, 72, 72, 1, 299520, 0x5e572146
+0, 73, 73, 1, 299520, 0x4f7ca5cf
+0, 74, 74, 1, 299520, 0x62951193
+0, 75, 75, 1, 299520, 0xf163d1cb
+0, 76, 76, 1, 299520, 0xb995206c
+0, 77, 77, 1, 299520, 0xcf5ebaa3
+0, 78, 78, 1, 299520, 0x22fad89d
+0, 79, 79, 1, 299520, 0xc9c25e12
+0, 80, 80, 1, 299520, 0xd5404f45
+0, 81, 81, 1, 299520, 0x484bd02d
+0, 82, 82, 1, 299520, 0x5790a1c4
+0, 83, 83, 1, 299520, 0xcbec0fed
+0, 84, 84, 1, 299520, 0x36bd1758
+0, 85, 85, 1, 299520, 0x4a133700
+0, 86, 86, 1, 299520, 0x2c582b0a
+0, 87, 87, 1, 299520, 0xadd773e1
+0, 88, 88, 1, 299520, 0xe4bbced3
+0, 89, 89, 1, 299520, 0x463b3ff0
diff --git a/tests/ref/fate/hevc-conformance-IPCM_A_RExt_NEC b/tests/ref/fate/hevc-conformance-IPCM_A_RExt_NEC
new file mode 100644
index 0000000000..d05de74fa2
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-IPCM_A_RExt_NEC
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 399360, 0xbac29a51
diff --git a/tests/ref/fate/hevc-conformance-IPCM_B_RExt_NEC b/tests/ref/fate/hevc-conformance-IPCM_B_RExt_NEC
new file mode 100644
index 0000000000..a01c3b5d65
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-IPCM_B_RExt_NEC
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x1f808406
diff --git a/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_2 b/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_2
deleted file mode 100644
index bff448bb1b..0000000000
--- a/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_2
+++ /dev/null
@@ -1,5 +0,0 @@
-#tb 0: 1/25
-0, 0, 0, 1, 599040, 0x9a8664e6
-0, 1, 1, 1, 599040, 0x72f15982
-0, 2, 2, 1, 599040, 0xc6610a7b
-0, 3, 3, 1, 599040, 0x091d3a93
diff --git a/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_3 b/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_3
new file mode 100644
index 0000000000..72a12e8ebc
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-IPRED_C_Mitsubishi_3
@@ -0,0 +1,5 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x6b61371d
+0, 1, 1, 1, 599040, 0xd38a2e50
+0, 2, 2, 1, 599040, 0xe8eb34bd
+0, 3, 3, 1, 599040, 0xb3ae6401
diff --git a/tests/ref/fate/hevc-conformance-Main_422_10_A_RExt_Sony_1 b/tests/ref/fate/hevc-conformance-Main_422_10_A_RExt_Sony_1
new file mode 100644
index 0000000000..6c43693876
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-Main_422_10_A_RExt_Sony_1
@@ -0,0 +1,25 @@
+#tb 0: 1/25
+0, 0, 0, 1, 8294400, 0xa189c341
+0, 1, 1, 1, 8294400, 0xefe07f3f
+0, 2, 2, 1, 8294400, 0xf11cd41f
+0, 3, 3, 1, 8294400, 0x85897411
+0, 4, 4, 1, 8294400, 0x2db68eca
+0, 5, 5, 1, 8294400, 0xbf826c45
+0, 6, 6, 1, 8294400, 0x9960de92
+0, 7, 7, 1, 8294400, 0xd8125d06
+0, 8, 8, 1, 8294400, 0xb90251df
+0, 9, 9, 1, 8294400, 0x5cc8c099
+0, 10, 10, 1, 8294400, 0xe5b49131
+0, 11, 11, 1, 8294400, 0xa861faac
+0, 12, 12, 1, 8294400, 0x1e125ad2
+0, 13, 13, 1, 8294400, 0xbceba6d9
+0, 14, 14, 1, 8294400, 0x135dab49
+0, 15, 15, 1, 8294400, 0xf09f3164
+0, 16, 16, 1, 8294400, 0xfda414dd
+0, 17, 17, 1, 8294400, 0xbf273db4
+0, 18, 18, 1, 8294400, 0x0dea125e
+0, 19, 19, 1, 8294400, 0xde6dedb0
+0, 20, 20, 1, 8294400, 0x6389ceb6
+0, 21, 21, 1, 8294400, 0x8d69e4b8
+0, 22, 22, 1, 8294400, 0xf74c0457
+0, 23, 23, 1, 8294400, 0x5ecd983e
diff --git a/tests/ref/fate/hevc-conformance-Main_422_10_B_RExt_Sony_1 b/tests/ref/fate/hevc-conformance-Main_422_10_B_RExt_Sony_1
new file mode 100644
index 0000000000..2267a095e6
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-Main_422_10_B_RExt_Sony_1
@@ -0,0 +1,18 @@
+#tb 0: 1/25
+0, 0, 0, 1, 16384000, 0xbf300829
+0, 1, 1, 1, 16384000, 0x7beeab61
+0, 2, 2, 1, 16384000, 0x5e55cd13
+0, 3, 3, 1, 16384000, 0x62a54105
+0, 4, 4, 1, 16384000, 0x2db21797
+0, 5, 5, 1, 16384000, 0x6d9f84c1
+0, 6, 6, 1, 16384000, 0x68fdacfc
+0, 7, 7, 1, 16384000, 0xe2c93c1a
+0, 8, 8, 1, 16384000, 0x7d011df0
+0, 9, 9, 1, 16384000, 0x7524e2d3
+0, 10, 10, 1, 16384000, 0x1d240868
+0, 11, 11, 1, 16384000, 0x14cab858
+0, 12, 12, 1, 16384000, 0x4e2e1130
+0, 13, 13, 1, 16384000, 0x60c75577
+0, 14, 14, 1, 16384000, 0x32dfc64b
+0, 15, 15, 1, 16384000, 0x0725f9ac
+0, 16, 16, 1, 16384000, 0xda0886f1
diff --git a/tests/ref/fate/hevc-conformance-NoOutPrior_A_Qualcomm_1 b/tests/ref/fate/hevc-conformance-NoOutPrior_A_Qualcomm_1
new file mode 100644
index 0000000000..48ca5adb48
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-NoOutPrior_A_Qualcomm_1
@@ -0,0 +1,41 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x91d452d5
+0, 1, 1, 1, 599040, 0x1b482509
+0, 2, 2, 1, 599040, 0xbc51425c
+0, 3, 3, 1, 599040, 0x5777eeee
+0, 4, 4, 1, 599040, 0xe274644d
+0, 5, 5, 1, 599040, 0x867450b5
+0, 6, 6, 1, 599040, 0x58708122
+0, 7, 7, 1, 599040, 0xeef17206
+0, 8, 8, 1, 599040, 0x97f4dc1e
+0, 9, 9, 1, 599040, 0x92c961cc
+0, 10, 10, 1, 599040, 0x1c4ffcb0
+0, 11, 11, 1, 599040, 0xc73e34e6
+0, 12, 12, 1, 599040, 0x1991f1f9
+0, 13, 13, 1, 599040, 0x36e54ba2
+0, 14, 14, 1, 599040, 0x698ce0c6
+0, 15, 15, 1, 599040, 0xc6dd131e
+0, 16, 16, 1, 599040, 0x0a22f4c5
+0, 17, 17, 1, 599040, 0xd6a0c196
+0, 18, 18, 1, 599040, 0x699a3e69
+0, 19, 19, 1, 599040, 0x4227009b
+0, 20, 20, 1, 599040, 0x1bda8be4
+0, 21, 21, 1, 599040, 0xd1d5dcb4
+0, 22, 22, 1, 599040, 0x00a0249f
+0, 23, 23, 1, 599040, 0x7263f7cf
+0, 24, 24, 1, 599040, 0x47054be4
+0, 25, 25, 1, 599040, 0xda083f52
+0, 26, 26, 1, 599040, 0xf2906ab1
+0, 27, 27, 1, 599040, 0x20936797
+0, 28, 28, 1, 599040, 0x644d7c3e
+0, 29, 29, 1, 599040, 0x7c00e8bf
+0, 30, 30, 1, 599040, 0x041f8a48
+0, 31, 31, 1, 599040, 0xcef6e936
+0, 32, 32, 1, 599040, 0x361461e9
+0, 33, 33, 1, 599040, 0xf663ba0a
+0, 34, 34, 1, 599040, 0x4d3371d3
+0, 35, 35, 1, 599040, 0xed6b5c92
+0, 36, 36, 1, 599040, 0xdec67f6e
+0, 37, 37, 1, 599040, 0xbafa50c0
+0, 38, 38, 1, 599040, 0xc9181637
+0, 39, 39, 1, 599040, 0x95834e17
diff --git a/tests/ref/fate/hevc-conformance-NoOutPrior_B_Qualcomm_1 b/tests/ref/fate/hevc-conformance-NoOutPrior_B_Qualcomm_1
new file mode 100644
index 0000000000..872c5c22c5
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-NoOutPrior_B_Qualcomm_1
@@ -0,0 +1,48 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x91d452d5
+0, 1, 1, 1, 599040, 0x1b482509
+0, 2, 2, 1, 599040, 0xbc51425c
+0, 3, 3, 1, 599040, 0x5777eeee
+0, 4, 4, 1, 599040, 0xe274644d
+0, 5, 5, 1, 599040, 0x867450b5
+0, 6, 6, 1, 599040, 0x58708122
+0, 7, 7, 1, 599040, 0xeef17206
+0, 8, 8, 1, 599040, 0x97f4dc1e
+0, 9, 9, 1, 599040, 0x92c961cc
+0, 10, 10, 1, 599040, 0x1c4ffcb0
+0, 11, 11, 1, 599040, 0xc73e34e6
+0, 12, 12, 1, 599040, 0x1991f1f9
+0, 13, 13, 1, 599040, 0x36e54ba2
+0, 14, 14, 1, 599040, 0x698ce0c6
+0, 15, 15, 1, 599040, 0xc6dd131e
+0, 16, 16, 1, 599040, 0x0a22f4c5
+0, 17, 17, 1, 599040, 0xd6a0c196
+0, 18, 18, 1, 599040, 0x699a3e69
+0, 19, 19, 1, 599040, 0x4227009b
+0, 20, 20, 1, 599040, 0x1bda8be4
+0, 21, 21, 1, 599040, 0xd1d5dcb4
+0, 22, 22, 1, 599040, 0x00d87745
+0, 23, 23, 1, 599040, 0x9b689b16
+0, 24, 24, 1, 599040, 0x40ae530a
+0, 25, 25, 1, 599040, 0x8284f649
+0, 26, 26, 1, 599040, 0x37423ae4
+0, 27, 27, 1, 599040, 0xb3f72b02
+0, 28, 28, 1, 599040, 0xc0cc5860
+0, 29, 29, 1, 599040, 0x00a0249f
+0, 30, 30, 1, 599040, 0x7263f7cf
+0, 31, 31, 1, 599040, 0x47054be4
+0, 32, 32, 1, 599040, 0xda083f52
+0, 33, 33, 1, 599040, 0xf2906ab1
+0, 34, 34, 1, 599040, 0x20936797
+0, 35, 35, 1, 599040, 0x644d7c3e
+0, 36, 36, 1, 599040, 0x7c00e8bf
+0, 37, 37, 1, 599040, 0x041f8a48
+0, 38, 38, 1, 599040, 0xcef6e936
+0, 39, 39, 1, 599040, 0x361461e9
+0, 40, 40, 1, 599040, 0xf663ba0a
+0, 41, 41, 1, 599040, 0x4d3371d3
+0, 42, 42, 1, 599040, 0xed6b5c92
+0, 43, 43, 1, 599040, 0xdec67f6e
+0, 44, 44, 1, 599040, 0xbafa50c0
+0, 45, 45, 1, 599040, 0xc9181637
+0, 46, 46, 1, 599040, 0x95834e17
diff --git a/tests/ref/fate/hevc-conformance-OPFLAG_A_Qualcomm_1 b/tests/ref/fate/hevc-conformance-OPFLAG_A_Qualcomm_1
new file mode 100644
index 0000000000..74849ebd5e
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-OPFLAG_A_Qualcomm_1
@@ -0,0 +1,501 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0xcfffa013
+0, 1, 1, 1, 149760, 0x8ae80654
+0, 2, 2, 1, 149760, 0xa79915b8
+0, 3, 3, 1, 149760, 0xcc5d4a1e
+0, 4, 4, 1, 149760, 0x80636df7
+0, 5, 5, 1, 149760, 0x9cf2c175
+0, 6, 6, 1, 149760, 0xb7c9ecc5
+0, 7, 7, 1, 149760, 0xd038133c
+0, 8, 8, 1, 149760, 0x82c62409
+0, 9, 9, 1, 149760, 0xf9ec8f18
+0, 10, 10, 1, 149760, 0x4969ba2d
+0, 11, 11, 1, 149760, 0xc4ece232
+0, 12, 12, 1, 149760, 0xc346cab1
+0, 13, 13, 1, 149760, 0xec83e8fd
+0, 14, 14, 1, 149760, 0x08e6ee21
+0, 15, 15, 1, 149760, 0x816818ac
+0, 16, 16, 1, 149760, 0xc6822627
+0, 17, 17, 1, 149760, 0x2d1d751f
+0, 18, 18, 1, 149760, 0xceb8796d
+0, 19, 19, 1, 149760, 0xa8919e96
+0, 20, 20, 1, 149760, 0x6fce9abe
+0, 21, 21, 1, 149760, 0x66fcbc8b
+0, 22, 22, 1, 149760, 0xfc0acbdb
+0, 23, 23, 1, 149760, 0x4fa7f7c3
+0, 24, 24, 1, 149760, 0xcc1a00a8
+0, 25, 25, 1, 149760, 0xe3b9aab4
+0, 26, 26, 1, 149760, 0xc064a2a9
+0, 27, 27, 1, 149760, 0x7c29bc1e
+0, 28, 28, 1, 149760, 0x54b0a3f2
+0, 29, 29, 1, 149760, 0x4781f75f
+0, 30, 30, 1, 149760, 0x3722ec9b
+0, 31, 31, 1, 149760, 0xb73fffc8
+0, 32, 32, 1, 149760, 0xd4437e12
+0, 33, 33, 1, 149760, 0xeb8bc09f
+0, 34, 34, 1, 149760, 0xe6b0cf24
+0, 35, 35, 1, 149760, 0xffbee400
+0, 36, 36, 1, 149760, 0x71b3d1c2
+0, 37, 37, 1, 149760, 0xeb05fce6
+0, 38, 38, 1, 149760, 0x968a049c
+0, 39, 39, 1, 149760, 0xf0b81987
+0, 40, 40, 1, 149760, 0x8ec12318
+0, 41, 41, 1, 149760, 0xb25f6f73
+0, 42, 42, 1, 149760, 0x4d9972ea
+0, 43, 43, 1, 149760, 0xb1be9ddd
+0, 44, 44, 1, 149760, 0xd8f97724
+0, 45, 45, 1, 149760, 0x88e9a071
+0, 46, 46, 1, 149760, 0xec3a6985
+0, 47, 47, 1, 149760, 0x5eb77758
+0, 48, 48, 1, 149760, 0x7a2d6bc0
+0, 49, 49, 1, 149760, 0x4c108b5a
+0, 50, 50, 1, 149760, 0xd1609676
+0, 51, 51, 1, 149760, 0xf497c5f2
+0, 52, 52, 1, 149760, 0x7d52bf67
+0, 53, 53, 1, 149760, 0xa9aeed34
+0, 54, 54, 1, 149760, 0x8a7a03ad
+0, 55, 55, 1, 149760, 0x7d6f34ba
+0, 56, 56, 1, 149760, 0x3c7a3f33
+0, 57, 57, 1, 149760, 0x220db437
+0, 58, 58, 1, 149760, 0x9098aed1
+0, 59, 59, 1, 149760, 0xba89f864
+0, 60, 60, 1, 149760, 0xc6f0f02a
+0, 61, 61, 1, 149760, 0xda71bdce
+0, 62, 62, 1, 149760, 0x7532698a
+0, 63, 63, 1, 149760, 0x20725283
+0, 64, 64, 1, 149760, 0xd3378be9
+0, 65, 65, 1, 149760, 0x0c449d3b
+0, 66, 66, 1, 149760, 0xcb16554e
+0, 67, 67, 1, 149760, 0x63bf54fd
+0, 68, 68, 1, 149760, 0xc9b8125a
+0, 69, 69, 1, 149760, 0x29391d98
+0, 70, 70, 1, 149760, 0xaba92f83
+0, 71, 71, 1, 149760, 0x278360ab
+0, 72, 72, 1, 149760, 0x72a17719
+0, 73, 73, 1, 149760, 0xc1057998
+0, 74, 74, 1, 149760, 0x3e3fb884
+0, 75, 75, 1, 149760, 0x4cadfcf5
+0, 76, 76, 1, 149760, 0x265ef61a
+0, 77, 77, 1, 149760, 0xc84e8e23
+0, 78, 78, 1, 149760, 0xf23cf3c3
+0, 79, 79, 1, 149760, 0x19280d25
+0, 80, 80, 1, 149760, 0xfc1ed859
+0, 81, 81, 1, 149760, 0x1a4caf70
+0, 82, 82, 1, 149760, 0xcbc3e559
+0, 83, 83, 1, 149760, 0x2284cd25
+0, 84, 84, 1, 149760, 0x4eca841e
+0, 85, 85, 1, 149760, 0xc5b2783b
+0, 86, 86, 1, 149760, 0x5c07bffe
+0, 87, 87, 1, 149760, 0x965b366d
+0, 88, 88, 1, 149760, 0x96a87998
+0, 89, 89, 1, 149760, 0x325fb5a8
+0, 90, 90, 1, 149760, 0xfb50de20
+0, 91, 91, 1, 149760, 0x4551ff6f
+0, 92, 92, 1, 149760, 0x2c313114
+0, 93, 93, 1, 149760, 0x585fbb08
+0, 94, 94, 1, 149760, 0xab620fbc
+0, 95, 95, 1, 149760, 0xac147ed6
+0, 96, 96, 1, 149760, 0x8753dbea
+0, 97, 97, 1, 149760, 0x7bd147a4
+0, 98, 98, 1, 149760, 0x09db40f9
+0, 99, 99, 1, 149760, 0x2c1d3e0e
+0, 100, 100, 1, 149760, 0xb3678490
+0, 101, 101, 1, 149760, 0xaa1ef03a
+0, 102, 102, 1, 149760, 0xaa272a2b
+0, 103, 103, 1, 149760, 0x765022ee
+0, 104, 104, 1, 149760, 0xa77ae265
+0, 105, 105, 1, 149760, 0xd48ce610
+0, 106, 106, 1, 149760, 0xbbe32786
+0, 107, 107, 1, 149760, 0x2ba067dd
+0, 108, 108, 1, 149760, 0x28251c88
+0, 109, 109, 1, 149760, 0xf7073bea
+0, 110, 110, 1, 149760, 0x5ada8c9f
+0, 111, 111, 1, 149760, 0x0ac5f0c3
+0, 112, 112, 1, 149760, 0x5771b681
+0, 113, 113, 1, 149760, 0x63b1aff4
+0, 114, 114, 1, 149760, 0xe52f1c14
+0, 115, 115, 1, 149760, 0x9fc6a873
+0, 116, 116, 1, 149760, 0xaa7fa136
+0, 117, 117, 1, 149760, 0xea0f1bc3
+0, 118, 118, 1, 149760, 0xb960a92a
+0, 119, 119, 1, 149760, 0x8a57440d
+0, 120, 120, 1, 149760, 0x0975231e
+0, 121, 121, 1, 149760, 0x01f4e2ca
+0, 122, 122, 1, 149760, 0x2feba705
+0, 123, 123, 1, 149760, 0xd8c2bb3e
+0, 124, 124, 1, 149760, 0x96d8a2a3
+0, 125, 125, 1, 149760, 0xc32ff8d3
+0, 126, 126, 1, 149760, 0x1f8a8edb
+0, 127, 127, 1, 149760, 0xc6242875
+0, 128, 128, 1, 149760, 0x3d4df3de
+0, 129, 129, 1, 149760, 0x43408010
+0, 130, 130, 1, 149760, 0x2ecd8706
+0, 131, 131, 1, 149760, 0x283c99f9
+0, 132, 132, 1, 149760, 0xa659bde0
+0, 133, 133, 1, 149760, 0x0edc3e70
+0, 134, 134, 1, 149760, 0x9ab3077e
+0, 135, 135, 1, 149760, 0x45a2bf0b
+0, 136, 136, 1, 149760, 0x67aff7d9
+0, 137, 137, 1, 149760, 0x4395fe6f
+0, 138, 138, 1, 149760, 0x84e8ca70
+0, 139, 139, 1, 149760, 0x4089d054
+0, 140, 140, 1, 149760, 0x893bcd2c
+0, 141, 141, 1, 149760, 0x36644083
+0, 142, 142, 1, 149760, 0xa0cf4e7d
+0, 143, 143, 1, 149760, 0x1ee06750
+0, 144, 144, 1, 149760, 0xef952e66
+0, 145, 145, 1, 149760, 0x7bc3936b
+0, 146, 146, 1, 149760, 0x73820f10
+0, 147, 147, 1, 149760, 0xf20e4fa7
+0, 148, 148, 1, 149760, 0xedc2b195
+0, 149, 149, 1, 149760, 0xd5dda892
+0, 150, 150, 1, 149760, 0x065559e4
+0, 151, 151, 1, 149760, 0xd1d1d2f7
+0, 152, 152, 1, 149760, 0x7ea0069e
+0, 153, 153, 1, 149760, 0x7eb18a44
+0, 154, 154, 1, 149760, 0x5165627b
+0, 155, 155, 1, 149760, 0x2bc02a08
+0, 156, 156, 1, 149760, 0x054f4260
+0, 157, 157, 1, 149760, 0x90206d1a
+0, 158, 158, 1, 149760, 0x86a46770
+0, 159, 159, 1, 149760, 0x877956ae
+0, 160, 160, 1, 149760, 0xeaee7801
+0, 161, 161, 1, 149760, 0xf5ae2e9d
+0, 162, 162, 1, 149760, 0x65ef307b
+0, 163, 163, 1, 149760, 0xbcd72d22
+0, 164, 164, 1, 149760, 0x6f5555eb
+0, 165, 165, 1, 149760, 0x5c5f43af
+0, 166, 166, 1, 149760, 0x13c9fa8e
+0, 167, 167, 1, 149760, 0x2236154f
+0, 168, 168, 1, 149760, 0x13fdcefc
+0, 169, 169, 1, 149760, 0x3e95cea3
+0, 170, 170, 1, 149760, 0x11d73074
+0, 171, 171, 1, 149760, 0x66a68f43
+0, 172, 172, 1, 149760, 0x594ce4d2
+0, 173, 173, 1, 149760, 0xbea4a3de
+0, 174, 174, 1, 149760, 0x72258b54
+0, 175, 175, 1, 149760, 0xf7598059
+0, 176, 176, 1, 149760, 0x527b8538
+0, 177, 177, 1, 149760, 0x9150a81a
+0, 178, 178, 1, 149760, 0x9c227fd2
+0, 179, 179, 1, 149760, 0x60347245
+0, 180, 180, 1, 149760, 0x3b9f6f64
+0, 181, 181, 1, 149760, 0xd6f37def
+0, 182, 182, 1, 149760, 0xa06933dd
+0, 183, 183, 1, 149760, 0x19e4ef4d
+0, 184, 184, 1, 149760, 0x1fb958cb
+0, 185, 185, 1, 149760, 0x3c4e3f19
+0, 186, 186, 1, 149760, 0x98ab1123
+0, 187, 187, 1, 149760, 0x0b4cdf66
+0, 188, 188, 1, 149760, 0x75cd51ef
+0, 189, 189, 1, 149760, 0x83e9617d
+0, 190, 190, 1, 149760, 0xb97a175b
+0, 191, 191, 1, 149760, 0x017520de
+0, 192, 192, 1, 149760, 0xa72ecc38
+0, 193, 193, 1, 149760, 0xfb493c45
+0, 194, 194, 1, 149760, 0x6c8e40b4
+0, 195, 195, 1, 149760, 0x4aa6672c
+0, 196, 196, 1, 149760, 0x223f68e5
+0, 197, 197, 1, 149760, 0x6257d660
+0, 198, 198, 1, 149760, 0xade0f8af
+0, 199, 199, 1, 149760, 0x8543652c
+0, 200, 200, 1, 149760, 0x593b7957
+0, 201, 201, 1, 149760, 0x90ce1910
+0, 202, 202, 1, 149760, 0x3d617a3f
+0, 203, 203, 1, 149760, 0x9336fbc0
+0, 204, 204, 1, 149760, 0x26f1387b
+0, 205, 205, 1, 149760, 0x0273a944
+0, 206, 206, 1, 149760, 0x71b9b110
+0, 207, 207, 1, 149760, 0x123fee6d
+0, 208, 208, 1, 149760, 0xc4bde65b
+0, 209, 209, 1, 149760, 0x646e3a45
+0, 210, 210, 1, 149760, 0x987e6024
+0, 211, 211, 1, 149760, 0x0bf6c9d4
+0, 212, 212, 1, 149760, 0x20d6e1cf
+0, 213, 213, 1, 149760, 0x5e0931df
+0, 214, 214, 1, 149760, 0xd96e313c
+0, 215, 215, 1, 149760, 0x04bbfcc5
+0, 216, 216, 1, 149760, 0xa764de56
+0, 217, 217, 1, 149760, 0x1e584d95
+0, 218, 218, 1, 149760, 0x1779f283
+0, 219, 219, 1, 149760, 0xfaefbc07
+0, 220, 220, 1, 149760, 0x2e9b4e2b
+0, 221, 221, 1, 149760, 0xeb6e3a42
+0, 222, 222, 1, 149760, 0xd2cbe3d4
+0, 223, 223, 1, 149760, 0xb9c4cf8c
+0, 224, 224, 1, 149760, 0x167b5401
+0, 225, 225, 1, 149760, 0x37846b87
+0, 226, 226, 1, 149760, 0xd0d66b7c
+0, 227, 227, 1, 149760, 0x4d61970e
+0, 228, 228, 1, 149760, 0x987cbc29
+0, 229, 229, 1, 149760, 0x3fa00111
+0, 230, 230, 1, 149760, 0x42ba262f
+0, 231, 231, 1, 149760, 0x9d40660b
+0, 232, 232, 1, 149760, 0x3b678b28
+0, 233, 233, 1, 149760, 0x3c72d081
+0, 234, 234, 1, 149760, 0xd8ad0056
+0, 235, 235, 1, 149760, 0x86052268
+0, 236, 236, 1, 149760, 0x8ac3f213
+0, 237, 237, 1, 149760, 0xe2cfb6fb
+0, 238, 238, 1, 149760, 0x412b5544
+0, 239, 239, 1, 149760, 0x468d2f6d
+0, 240, 240, 1, 149760, 0x63f5e9d0
+0, 241, 241, 1, 149760, 0x4318f07d
+0, 242, 242, 1, 149760, 0xa0c7b7df
+0, 243, 243, 1, 149760, 0x8ad37f38
+0, 244, 244, 1, 149760, 0xa6101620
+0, 245, 245, 1, 149760, 0x02b3d774
+0, 246, 246, 1, 149760, 0x541a6c86
+0, 247, 247, 1, 149760, 0xe11148f0
+0, 248, 248, 1, 149760, 0x4a920c7e
+0, 249, 249, 1, 149760, 0x878104a9
+0, 250, 250, 1, 149760, 0xbb65dfda
+0, 251, 251, 1, 149760, 0xda02bd47
+0, 252, 252, 1, 149760, 0xe0529fd7
+0, 253, 253, 1, 149760, 0x52619028
+0, 254, 254, 1, 149760, 0x4e9c9f32
+0, 255, 255, 1, 149760, 0x9ae49e70
+0, 256, 256, 1, 149760, 0x851e84de
+0, 257, 257, 1, 149760, 0x1709a3cd
+0, 258, 258, 1, 149760, 0x3dace2eb
+0, 259, 259, 1, 149760, 0x46fe3ebf
+0, 260, 260, 1, 149760, 0xea53610c
+0, 261, 261, 1, 149760, 0x0df3415f
+0, 262, 262, 1, 149760, 0x29c57eec
+0, 263, 263, 1, 149760, 0x1ed3a882
+0, 264, 264, 1, 149760, 0xf3047aed
+0, 265, 265, 1, 149760, 0x7a7d08cd
+0, 266, 266, 1, 149760, 0xc69dd2ad
+0, 267, 267, 1, 149760, 0x94d1c233
+0, 268, 268, 1, 149760, 0x21d7eab9
+0, 269, 269, 1, 149760, 0xd8755fda
+0, 270, 270, 1, 149760, 0xa44fbf4a
+0, 271, 271, 1, 149760, 0x624d42cb
+0, 272, 272, 1, 149760, 0xf462482d
+0, 273, 273, 1, 149760, 0x8dd0641d
+0, 274, 274, 1, 149760, 0x9349bc12
+0, 275, 275, 1, 149760, 0x0488137f
+0, 276, 276, 1, 149760, 0x8088d83e
+0, 277, 277, 1, 149760, 0x051895e4
+0, 278, 278, 1, 149760, 0x0cc16c74
+0, 279, 279, 1, 149760, 0xcdc62942
+0, 280, 280, 1, 149760, 0x6d1392aa
+0, 281, 281, 1, 149760, 0x61e2e1da
+0, 282, 282, 1, 149760, 0x5cb06ae9
+0, 283, 283, 1, 149760, 0x5110b773
+0, 284, 284, 1, 149760, 0x050db1cb
+0, 285, 285, 1, 149760, 0x353dfc85
+0, 286, 286, 1, 149760, 0x96ac57f2
+0, 287, 287, 1, 149760, 0x7e925578
+0, 288, 288, 1, 149760, 0x4eaa64c0
+0, 289, 289, 1, 149760, 0x10b6d8cf
+0, 290, 290, 1, 149760, 0x645317c2
+0, 291, 291, 1, 149760, 0xcf60e8e2
+0, 292, 292, 1, 149760, 0x38dc8503
+0, 293, 293, 1, 149760, 0xf88bd43b
+0, 294, 294, 1, 149760, 0x284b675e
+0, 295, 295, 1, 149760, 0xba9ac819
+0, 296, 296, 1, 149760, 0xd913bba8
+0, 297, 297, 1, 149760, 0x50612c15
+0, 298, 298, 1, 149760, 0x8ec14fb1
+0, 299, 299, 1, 149760, 0x2dd30b7d
+0, 300, 300, 1, 149760, 0x5a3f52cf
+0, 301, 301, 1, 149760, 0x95169561
+0, 302, 302, 1, 149760, 0x6ede7115
+0, 303, 303, 1, 149760, 0x70e435e0
+0, 304, 304, 1, 149760, 0x496df85a
+0, 305, 305, 1, 149760, 0xdd583698
+0, 306, 306, 1, 149760, 0xee46c909
+0, 307, 307, 1, 149760, 0x4b0632ed
+0, 308, 308, 1, 149760, 0x744e4d23
+0, 309, 309, 1, 149760, 0xc72d8111
+0, 310, 310, 1, 149760, 0x6d6c62d4
+0, 311, 311, 1, 149760, 0xbc39103c
+0, 312, 312, 1, 149760, 0x1b0548e5
+0, 313, 313, 1, 149760, 0xac760971
+0, 314, 314, 1, 149760, 0x0bbfeab1
+0, 315, 315, 1, 149760, 0x843ca731
+0, 316, 316, 1, 149760, 0x6a8dd5c9
+0, 317, 317, 1, 149760, 0xd5e19d6e
+0, 318, 318, 1, 149760, 0xde1e9259
+0, 319, 319, 1, 149760, 0xa9c6aecf
+0, 320, 320, 1, 149760, 0x4e3c1463
+0, 321, 321, 1, 149760, 0x20e95cd5
+0, 322, 322, 1, 149760, 0x26b9c119
+0, 323, 323, 1, 149760, 0x0284eab3
+0, 324, 324, 1, 149760, 0x128544f3
+0, 325, 325, 1, 149760, 0x5c33579c
+0, 326, 326, 1, 149760, 0x58e48fc1
+0, 327, 327, 1, 149760, 0x46d20ba5
+0, 328, 328, 1, 149760, 0x232478d4
+0, 329, 329, 1, 149760, 0x4299f014
+0, 330, 330, 1, 149760, 0x68e08339
+0, 331, 331, 1, 149760, 0x01c0ca97
+0, 332, 332, 1, 149760, 0xad7071d6
+0, 333, 333, 1, 149760, 0xa1efff2e
+0, 334, 334, 1, 149760, 0xe788aa06
+0, 335, 335, 1, 149760, 0xa203d648
+0, 336, 336, 1, 149760, 0xdec84349
+0, 337, 337, 1, 149760, 0xb15fc868
+0, 338, 338, 1, 149760, 0x6ca04511
+0, 339, 339, 1, 149760, 0xc4b95d7e
+0, 340, 340, 1, 149760, 0xa3d0d178
+0, 341, 341, 1, 149760, 0xb4835e5f
+0, 342, 342, 1, 149760, 0xcff22407
+0, 343, 343, 1, 149760, 0x8259ad5a
+0, 344, 344, 1, 149760, 0x9cb2f71a
+0, 345, 345, 1, 149760, 0xf2d3cae6
+0, 346, 346, 1, 149760, 0xbdaa58c5
+0, 347, 347, 1, 149760, 0x2c0ec9bd
+0, 348, 348, 1, 149760, 0x63357b56
+0, 349, 349, 1, 149760, 0xc92b5672
+0, 350, 350, 1, 149760, 0xc2deae0d
+0, 351, 351, 1, 149760, 0x111a214d
+0, 352, 352, 1, 149760, 0xbb7a0383
+0, 353, 353, 1, 149760, 0x31b6d2ad
+0, 354, 354, 1, 149760, 0x87f8b103
+0, 355, 355, 1, 149760, 0xd035ede8
+0, 356, 356, 1, 149760, 0xf021cb64
+0, 357, 357, 1, 149760, 0x18a1c19c
+0, 358, 358, 1, 149760, 0xc51980ac
+0, 359, 359, 1, 149760, 0x2394c13e
+0, 360, 360, 1, 149760, 0x2b27c7ee
+0, 361, 361, 1, 149760, 0x40e0670f
+0, 362, 362, 1, 149760, 0xbc0f3989
+0, 363, 363, 1, 149760, 0x391048d6
+0, 364, 364, 1, 149760, 0x1bc0e92c
+0, 365, 365, 1, 149760, 0xa7e278d9
+0, 366, 366, 1, 149760, 0xb4123421
+0, 367, 367, 1, 149760, 0x106bb0e1
+0, 368, 368, 1, 149760, 0x4c2a61d2
+0, 369, 369, 1, 149760, 0x69aaee6e
+0, 370, 370, 1, 149760, 0x925e5432
+0, 371, 371, 1, 149760, 0x06d6d786
+0, 372, 372, 1, 149760, 0xd431fba8
+0, 373, 373, 1, 149760, 0x54092812
+0, 374, 374, 1, 149760, 0xb8e10742
+0, 375, 375, 1, 149760, 0x2ee782d3
+0, 376, 376, 1, 149760, 0x210ff556
+0, 377, 377, 1, 149760, 0xa41cf41e
+0, 378, 378, 1, 149760, 0xbe852e5a
+0, 379, 379, 1, 149760, 0x4a89b5c5
+0, 380, 380, 1, 149760, 0xe44408d1
+0, 381, 381, 1, 149760, 0x503197f3
+0, 382, 382, 1, 149760, 0x686bf74e
+0, 383, 383, 1, 149760, 0xb96fd46b
+0, 384, 384, 1, 149760, 0x9a926a62
+0, 385, 385, 1, 149760, 0x97cf58e9
+0, 386, 386, 1, 149760, 0x0e7840af
+0, 387, 387, 1, 149760, 0x00aa85e9
+0, 388, 388, 1, 149760, 0x24c4fd96
+0, 389, 389, 1, 149760, 0xe520844b
+0, 390, 390, 1, 149760, 0xd4755d80
+0, 391, 391, 1, 149760, 0x9cd4b85c
+0, 392, 392, 1, 149760, 0xd01aa4ad
+0, 393, 393, 1, 149760, 0xa5479aa5
+0, 394, 394, 1, 149760, 0x74c066d4
+0, 395, 395, 1, 149760, 0xe1a35a46
+0, 396, 396, 1, 149760, 0x714aeafb
+0, 397, 397, 1, 149760, 0xb3e0f80e
+0, 398, 398, 1, 149760, 0x99663804
+0, 399, 399, 1, 149760, 0x3a40a623
+0, 400, 400, 1, 149760, 0x91b4d995
+0, 401, 401, 1, 149760, 0x6edd8a1f
+0, 402, 402, 1, 149760, 0x1f763e9a
+0, 403, 403, 1, 149760, 0x932b79d4
+0, 404, 404, 1, 149760, 0x6a1a9755
+0, 405, 405, 1, 149760, 0x403562c8
+0, 406, 406, 1, 149760, 0x6486231b
+0, 407, 407, 1, 149760, 0x3c2bfb98
+0, 408, 408, 1, 149760, 0x198a3cee
+0, 409, 409, 1, 149760, 0x4d2f7817
+0, 410, 410, 1, 149760, 0xd7b189a7
+0, 411, 411, 1, 149760, 0x9ad0ba76
+0, 412, 412, 1, 149760, 0xea8d8859
+0, 413, 413, 1, 149760, 0x30fae052
+0, 414, 414, 1, 149760, 0x55b1763c
+0, 415, 415, 1, 149760, 0x4be39b5b
+0, 416, 416, 1, 149760, 0xec332a7f
+0, 417, 417, 1, 149760, 0x226f7c74
+0, 418, 418, 1, 149760, 0x0a82fa19
+0, 419, 419, 1, 149760, 0x8bb5ca7d
+0, 420, 420, 1, 149760, 0xe59f21e1
+0, 421, 421, 1, 149760, 0x20450c0b
+0, 422, 422, 1, 149760, 0xd9fcc726
+0, 423, 423, 1, 149760, 0xf4e9a639
+0, 424, 424, 1, 149760, 0x932602d1
+0, 425, 425, 1, 149760, 0xcdfdb2c6
+0, 426, 426, 1, 149760, 0xc91929b2
+0, 427, 427, 1, 149760, 0x6b24081c
+0, 428, 428, 1, 149760, 0xa2e00bd5
+0, 429, 429, 1, 149760, 0x7536baea
+0, 430, 430, 1, 149760, 0x5a4279b7
+0, 431, 431, 1, 149760, 0x48741fb4
+0, 432, 432, 1, 149760, 0xe0a71c39
+0, 433, 433, 1, 149760, 0x4422b4cf
+0, 434, 434, 1, 149760, 0x3ddc7752
+0, 435, 435, 1, 149760, 0x209ebb6b
+0, 436, 436, 1, 149760, 0x47cc746f
+0, 437, 437, 1, 149760, 0x159f56a4
+0, 438, 438, 1, 149760, 0x22e39511
+0, 439, 439, 1, 149760, 0x78698fbd
+0, 440, 440, 1, 149760, 0x7bc88f86
+0, 441, 441, 1, 149760, 0x44a423d1
+0, 442, 442, 1, 149760, 0x25fadf02
+0, 443, 443, 1, 149760, 0xd360cfee
+0, 444, 444, 1, 149760, 0xcd6c409f
+0, 445, 445, 1, 149760, 0xd5905aca
+0, 446, 446, 1, 149760, 0x621f3edc
+0, 447, 447, 1, 149760, 0x79bd347e
+0, 448, 448, 1, 149760, 0xdb9d163d
+0, 449, 449, 1, 149760, 0x7282e4d6
+0, 450, 450, 1, 149760, 0x8d6dc686
+0, 451, 451, 1, 149760, 0x35132151
+0, 452, 452, 1, 149760, 0x27a05c87
+0, 453, 453, 1, 149760, 0x8e12df27
+0, 454, 454, 1, 149760, 0xf2fb72cd
+0, 455, 455, 1, 149760, 0xea71796e
+0, 456, 456, 1, 149760, 0xbd2ffeec
+0, 457, 457, 1, 149760, 0xdb849b70
+0, 458, 458, 1, 149760, 0xc8193666
+0, 459, 459, 1, 149760, 0x7dab4b05
+0, 460, 460, 1, 149760, 0x83a94327
+0, 461, 461, 1, 149760, 0x56a2ca36
+0, 462, 462, 1, 149760, 0x7d20c938
+0, 463, 463, 1, 149760, 0xfbbfa0bd
+0, 464, 464, 1, 149760, 0xea020d13
+0, 465, 465, 1, 149760, 0x2ef8c012
+0, 466, 466, 1, 149760, 0x36a10f18
+0, 467, 467, 1, 149760, 0x56e538e3
+0, 468, 468, 1, 149760, 0xf98d9ca8
+0, 469, 469, 1, 149760, 0xeba06818
+0, 470, 470, 1, 149760, 0x7d9c6f79
+0, 471, 471, 1, 149760, 0xd7173a90
+0, 472, 472, 1, 149760, 0xff4ced8d
+0, 473, 473, 1, 149760, 0xe7d92ff8
+0, 474, 474, 1, 149760, 0x4f020382
+0, 475, 475, 1, 149760, 0x4e93292a
+0, 476, 476, 1, 149760, 0x08dc52c7
+0, 477, 477, 1, 149760, 0xbff9557e
+0, 478, 478, 1, 149760, 0x1caa8bc5
+0, 479, 479, 1, 149760, 0x9b7aaf9a
+0, 480, 480, 1, 149760, 0x2cb89025
+0, 481, 481, 1, 149760, 0x18e2a4ad
+0, 482, 482, 1, 149760, 0xf50dce5e
+0, 483, 483, 1, 149760, 0x9f87c44f
+0, 484, 484, 1, 149760, 0xbfdc521d
+0, 485, 485, 1, 149760, 0xa06f5b06
+0, 486, 486, 1, 149760, 0xa169a6fe
+0, 487, 487, 1, 149760, 0xce6280d4
+0, 488, 488, 1, 149760, 0x056c21d6
+0, 489, 489, 1, 149760, 0x70b068df
+0, 490, 490, 1, 149760, 0x1097459b
+0, 491, 491, 1, 149760, 0xef1925f1
+0, 492, 492, 1, 149760, 0x6969b893
+0, 493, 493, 1, 149760, 0x0203fc33
+0, 494, 494, 1, 149760, 0x812e46b9
+0, 495, 495, 1, 149760, 0x7379207f
+0, 496, 496, 1, 149760, 0xff11e733
+0, 497, 497, 1, 149760, 0xc5af45a8
+0, 498, 498, 1, 149760, 0x3ec6b250
+0, 499, 499, 1, 149760, 0xb90ddf3a
diff --git a/tests/ref/fate/hevc-conformance-OPFLAG_B_Qualcomm_1 b/tests/ref/fate/hevc-conformance-OPFLAG_B_Qualcomm_1
new file mode 100644
index 0000000000..55e4be0d73
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-OPFLAG_B_Qualcomm_1
@@ -0,0 +1,99 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x4246702a
+0, 1, 1, 1, 599040, 0x25e02747
+0, 2, 2, 1, 599040, 0x0894b9de
+0, 3, 3, 1, 599040, 0x88ea9524
+0, 4, 4, 1, 599040, 0xaff26463
+0, 5, 5, 1, 599040, 0x5fb75697
+0, 6, 6, 1, 599040, 0xbc2f36a3
+0, 7, 7, 1, 599040, 0xb7823c25
+0, 8, 8, 1, 599040, 0x61cb05cb
+0, 9, 9, 1, 599040, 0x74bfcc5c
+0, 10, 10, 1, 599040, 0x435c4cb3
+0, 11, 11, 1, 599040, 0x34e1a6df
+0, 12, 12, 1, 599040, 0x57760c47
+0, 13, 13, 1, 599040, 0xd8c5092c
+0, 14, 14, 1, 599040, 0x56d4aeed
+0, 15, 15, 1, 599040, 0xda4388c2
+0, 16, 16, 1, 599040, 0x09c82870
+0, 17, 17, 1, 599040, 0x77f63854
+0, 18, 18, 1, 599040, 0xb7ca000b
+0, 19, 19, 1, 599040, 0x6ef162db
+0, 20, 20, 1, 599040, 0x1a274bec
+0, 21, 21, 1, 599040, 0x1a839505
+0, 22, 22, 1, 599040, 0xf78f0c03
+0, 23, 23, 1, 599040, 0x3d395229
+0, 24, 24, 1, 599040, 0x9494b5ac
+0, 25, 25, 1, 599040, 0x42560d96
+0, 26, 26, 1, 599040, 0x135f76d8
+0, 27, 27, 1, 599040, 0x3758c2ab
+0, 28, 28, 1, 599040, 0x100fb1d8
+0, 29, 29, 1, 599040, 0x9273f18e
+0, 30, 30, 1, 599040, 0x41b31734
+0, 31, 31, 1, 599040, 0xb2e140b7
+0, 32, 32, 1, 599040, 0xd35f3451
+0, 33, 33, 1, 599040, 0x6198a3d6
+0, 34, 34, 1, 599040, 0x0253e3fa
+0, 35, 35, 1, 599040, 0x421a1cd1
+0, 36, 36, 1, 599040, 0xd2152e6b
+0, 37, 37, 1, 599040, 0xe4c37cc7
+0, 38, 38, 1, 599040, 0xec3393c3
+0, 39, 39, 1, 599040, 0x1fe16574
+0, 40, 40, 1, 599040, 0xa3a8c14d
+0, 41, 41, 1, 599040, 0x32eb90aa
+0, 42, 42, 1, 599040, 0xebca8310
+0, 43, 43, 1, 599040, 0x7888627f
+0, 44, 44, 1, 599040, 0xe048335c
+0, 45, 45, 1, 599040, 0xe2262b9c
+0, 46, 46, 1, 599040, 0xb8c2b115
+0, 47, 47, 1, 599040, 0x2ff4194b
+0, 48, 48, 1, 599040, 0x3a9b5520
+0, 49, 49, 1, 599040, 0xbd8c0486
+0, 50, 50, 1, 599040, 0xc8b8f29e
+0, 51, 51, 1, 599040, 0xbc12f62c
+0, 52, 52, 1, 599040, 0x04bb6438
+0, 53, 53, 1, 599040, 0x07971646
+0, 54, 54, 1, 599040, 0x0193dabe
+0, 55, 55, 1, 599040, 0x20f41d9e
+0, 56, 56, 1, 599040, 0x04b40718
+0, 57, 57, 1, 599040, 0x75d2c51c
+0, 58, 58, 1, 599040, 0x9b8c2c50
+0, 59, 59, 1, 599040, 0x970e39ea
+0, 60, 60, 1, 599040, 0x7c4264aa
+0, 61, 61, 1, 599040, 0xe939a6fd
+0, 62, 62, 1, 599040, 0xc8b95f8d
+0, 63, 63, 1, 599040, 0x9e2f384a
+0, 64, 64, 1, 599040, 0x7dc74724
+0, 65, 65, 1, 599040, 0x7e93bc5f
+0, 66, 66, 1, 599040, 0x99b2c09d
+0, 67, 67, 1, 599040, 0x284e436f
+0, 68, 68, 1, 599040, 0xaa303eee
+0, 69, 69, 1, 599040, 0x65e54342
+0, 70, 70, 1, 599040, 0x2fe183cd
+0, 71, 71, 1, 599040, 0x5953c191
+0, 72, 72, 1, 599040, 0x0fc9a701
+0, 73, 73, 1, 599040, 0x0eea5327
+0, 74, 74, 1, 599040, 0x118752f1
+0, 75, 75, 1, 599040, 0x778c7711
+0, 76, 76, 1, 599040, 0x6f3ad6a5
+0, 77, 77, 1, 599040, 0xf70fcd3d
+0, 78, 78, 1, 599040, 0x85a366cb
+0, 79, 79, 1, 599040, 0xdda47432
+0, 80, 80, 1, 599040, 0x86379004
+0, 81, 81, 1, 599040, 0xfc539512
+0, 82, 82, 1, 599040, 0x04e70786
+0, 83, 83, 1, 599040, 0x7dddc8f7
+0, 84, 84, 1, 599040, 0xa76a3b6e
+0, 85, 85, 1, 599040, 0x44183060
+0, 86, 86, 1, 599040, 0x6f691c5a
+0, 87, 87, 1, 599040, 0x39d25e12
+0, 88, 88, 1, 599040, 0xfe3aad0d
+0, 89, 89, 1, 599040, 0x57f76928
+0, 90, 90, 1, 599040, 0x4e68eed5
+0, 91, 91, 1, 599040, 0x3a589d50
+0, 92, 92, 1, 599040, 0x92ec69b8
+0, 93, 93, 1, 599040, 0x9f78926e
+0, 94, 94, 1, 599040, 0xa1ca1b1d
+0, 95, 95, 1, 599040, 0x140240eb
+0, 96, 96, 1, 599040, 0x61fa01af
+0, 97, 97, 1, 599040, 0x79f9e3ae
diff --git a/tests/ref/fate/hevc-conformance-OPFLAG_C_Qualcomm_1 b/tests/ref/fate/hevc-conformance-OPFLAG_C_Qualcomm_1
new file mode 100644
index 0000000000..e45005f39a
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-OPFLAG_C_Qualcomm_1
@@ -0,0 +1,97 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x91d452d5
+0, 1, 1, 1, 599040, 0x1b482509
+0, 2, 2, 1, 599040, 0xbc51425c
+0, 3, 3, 1, 599040, 0x5777eeee
+0, 4, 4, 1, 599040, 0xe274644d
+0, 5, 5, 1, 599040, 0x867450b5
+0, 6, 6, 1, 599040, 0x58708122
+0, 7, 7, 1, 599040, 0xeef17206
+0, 8, 8, 1, 599040, 0x97f4dc1e
+0, 9, 9, 1, 599040, 0x92c961cc
+0, 10, 10, 1, 599040, 0x1c4ffcb0
+0, 11, 11, 1, 599040, 0xc73e34e6
+0, 12, 12, 1, 599040, 0x1991f1f9
+0, 13, 13, 1, 599040, 0x36e54ba2
+0, 14, 14, 1, 599040, 0x698ce0c6
+0, 15, 15, 1, 599040, 0xc6dd131e
+0, 16, 16, 1, 599040, 0x0a22f4c5
+0, 17, 17, 1, 599040, 0xd6a0c196
+0, 18, 18, 1, 599040, 0x699a3e69
+0, 19, 19, 1, 599040, 0x4227009b
+0, 20, 20, 1, 599040, 0xd1d5dcb4
+0, 21, 21, 1, 599040, 0x58b2edb3
+0, 22, 22, 1, 599040, 0xd1f795d8
+0, 23, 23, 1, 599040, 0x3331d5e6
+0, 24, 24, 1, 599040, 0x5e5ec2c9
+0, 25, 25, 1, 599040, 0x3b907bf5
+0, 26, 26, 1, 599040, 0xefcbf471
+0, 27, 27, 1, 599040, 0x2769a578
+0, 28, 28, 1, 599040, 0x812ce986
+0, 29, 29, 1, 599040, 0xf07c212c
+0, 30, 30, 1, 599040, 0x00a0249f
+0, 31, 31, 1, 599040, 0x7263f7cf
+0, 32, 32, 1, 599040, 0x47054be4
+0, 33, 33, 1, 599040, 0xda083f52
+0, 34, 34, 1, 599040, 0xf2906ab1
+0, 35, 35, 1, 599040, 0x20936797
+0, 36, 36, 1, 599040, 0x644d7c3e
+0, 37, 37, 1, 599040, 0x7c00e8bf
+0, 38, 38, 1, 599040, 0x041f8a48
+0, 39, 39, 1, 599040, 0xcef6e936
+0, 40, 40, 1, 599040, 0x361461e9
+0, 41, 41, 1, 599040, 0xf663ba0a
+0, 42, 42, 1, 599040, 0x4d3371d3
+0, 43, 43, 1, 599040, 0xed6b5c92
+0, 44, 44, 1, 599040, 0xdec67f6e
+0, 45, 45, 1, 599040, 0xbafa50c0
+0, 46, 46, 1, 599040, 0xc9181637
+0, 47, 47, 1, 599040, 0x29eadcac
+0, 48, 48, 1, 599040, 0xb258430f
+0, 49, 49, 1, 599040, 0x49dc8716
+0, 50, 50, 1, 599040, 0x80b0a3b3
+0, 51, 51, 1, 599040, 0x5d8275a7
+0, 52, 52, 1, 599040, 0xe236242d
+0, 53, 53, 1, 599040, 0x3e14bb43
+0, 54, 54, 1, 599040, 0x20e6e2d7
+0, 55, 55, 1, 599040, 0x19cad4ee
+0, 56, 56, 1, 599040, 0x13fd16f1
+0, 57, 57, 1, 599040, 0x98e56b95
+0, 58, 58, 1, 599040, 0x028e4c6a
+0, 59, 59, 1, 599040, 0x5bd1131d
+0, 60, 60, 1, 599040, 0x0afe3873
+0, 61, 61, 1, 599040, 0xea93e425
+0, 62, 62, 1, 599040, 0xeb301be1
+0, 63, 63, 1, 599040, 0x443ca0a3
+0, 64, 64, 1, 599040, 0xb68b40a1
+0, 65, 65, 1, 599040, 0xf58f75b9
+0, 66, 66, 1, 599040, 0xefa27c52
+0, 67, 67, 1, 599040, 0xac676fa5
+0, 68, 68, 1, 599040, 0x688d1582
+0, 69, 69, 1, 599040, 0x9067a4ef
+0, 70, 70, 1, 599040, 0xdc753d6c
+0, 71, 71, 1, 599040, 0x6f6da304
+0, 72, 72, 1, 599040, 0xa7606f97
+0, 73, 73, 1, 599040, 0xb53c8c18
+0, 74, 74, 1, 599040, 0x3572d550
+0, 75, 75, 1, 599040, 0x123d5423
+0, 76, 76, 1, 599040, 0x89f11e50
+0, 77, 77, 1, 599040, 0x702649cc
+0, 78, 78, 1, 599040, 0x2b4767c4
+0, 79, 79, 1, 599040, 0xf18b9628
+0, 80, 80, 1, 599040, 0x1ef72a6b
+0, 81, 81, 1, 599040, 0x0a8c9641
+0, 82, 82, 1, 599040, 0xf2fa0233
+0, 83, 83, 1, 599040, 0x99385e51
+0, 84, 84, 1, 599040, 0x77b413cf
+0, 85, 85, 1, 599040, 0x6360c9e3
+0, 86, 86, 1, 599040, 0xe216b383
+0, 87, 87, 1, 599040, 0x54df8826
+0, 88, 88, 1, 599040, 0x6691e1ee
+0, 89, 89, 1, 599040, 0x37bebd20
+0, 90, 90, 1, 599040, 0xf05184e4
+0, 91, 91, 1, 599040, 0xbd7fab4f
+0, 92, 92, 1, 599040, 0x70211cdc
+0, 93, 93, 1, 599040, 0x4f4c375b
+0, 94, 94, 1, 599040, 0x2d645b5a
+0, 95, 95, 1, 599040, 0x475d263f
diff --git a/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_1 b/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_1
new file mode 100644
index 0000000000..4e49caac6d
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_1
@@ -0,0 +1,3 @@
+#tb 0: 1/25
+0, 0, 0, 1, 921600, 0x702f0d67
+0, 1, 1, 1, 921600, 0x99822b52
diff --git a/tests/ref/fate/hevc-conformance-POC_A_Bossen_3 b/tests/ref/fate/hevc-conformance-POC_A_Bossen_3
index bcfa7fa3d5..885d0e4da9 100644
--- a/tests/ref/fate/hevc-conformance-POC_A_Bossen_3
+++ b/tests/ref/fate/hevc-conformance-POC_A_Bossen_3
@@ -1,6 +1,6 @@
#tb 0: 1/25
0, 0, 0, 1, 149760, 0xda17acd4
-0, 0, 0, 1, 149760, 0x1691b47f
-0, 1, 1, 1, 149760, 0xeebeac0c
-0, 2, 2, 1, 149760, 0x895c9f62
-0, 3, 3, 1, 149760, 0x9e2077e8
+0, 1, 1, 1, 149760, 0x1691b47f
+0, 2, 2, 1, 149760, 0xeebeac0c
+0, 3, 3, 1, 149760, 0x895c9f62
+0, 4, 4, 1, 149760, 0x9e2077e8
diff --git a/tests/ref/fate/hevc-conformance-QMATRIX_A_RExt_Sony_1 b/tests/ref/fate/hevc-conformance-QMATRIX_A_RExt_Sony_1
new file mode 100644
index 0000000000..63baa95e77
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-QMATRIX_A_RExt_Sony_1
@@ -0,0 +1,21 @@
+#tb 0: 1/25
+0, 0, 0, 1, 2764800, 0xde442361
+0, 1, 1, 1, 2764800, 0x8d482fdf
+0, 2, 2, 1, 2764800, 0x9b431e37
+0, 3, 3, 1, 2764800, 0x8b7d893d
+0, 4, 4, 1, 2764800, 0xa471ac17
+0, 5, 5, 1, 2764800, 0xe990790f
+0, 6, 6, 1, 2764800, 0x8f3f8285
+0, 7, 7, 1, 2764800, 0xeaf9f242
+0, 8, 8, 1, 2764800, 0xfd37f69d
+0, 9, 9, 1, 2764800, 0x31d29f19
+0, 10, 10, 1, 2764800, 0x92f56414
+0, 11, 11, 1, 2764800, 0xb909e334
+0, 12, 12, 1, 2764800, 0x9f2fad13
+0, 13, 13, 1, 2764800, 0xbf9090b2
+0, 14, 14, 1, 2764800, 0xa39c7b78
+0, 15, 15, 1, 2764800, 0x83e77296
+0, 16, 16, 1, 2764800, 0x737a5a9d
+0, 17, 17, 1, 2764800, 0x356c51d6
+0, 18, 18, 1, 2764800, 0xd498468c
+0, 19, 19, 1, 2764800, 0xd25a396d
diff --git a/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1 b/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1
index 4bea99754f..56f5b441aa 100644
--- a/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1
+++ b/tests/ref/fate/hevc-conformance-RAP_B_Bossen_1
@@ -66,19 +66,16 @@
0, 64, 64, 1, 149760, 0x3362678b
0, 65, 65, 1, 149760, 0x6e7fc851
0, 66, 66, 1, 149760, 0x33f96449
-0, 67, 67, 1, 149760, 0xd9d05007
-0, 68, 68, 1, 149760, 0x477f2cf2
-0, 69, 69, 1, 149760, 0xe1f9ccd0
-0, 70, 70, 1, 149760, 0xb3ba8cfb
-0, 71, 71, 1, 149760, 0x64787995
-0, 72, 72, 1, 149760, 0xc10de4c4
-0, 73, 73, 1, 149760, 0x18dd343f
-0, 74, 74, 1, 149760, 0xa1c51358
-0, 75, 75, 1, 149760, 0x91fe6361
-0, 76, 76, 1, 149760, 0xeec85f94
-0, 77, 77, 1, 149760, 0x00a57402
-0, 78, 78, 1, 149760, 0x4e88cc16
-0, 79, 79, 1, 149760, 0xdbd51976
-0, 80, 80, 1, 149760, 0xfebf6b1a
-0, 81, 81, 1, 149760, 0x052546d2
-0, 82, 82, 1, 149760, 0x046cd73b
+0, 67, 67, 1, 149760, 0xb3ba8cfb
+0, 68, 68, 1, 149760, 0x64787995
+0, 69, 69, 1, 149760, 0xc10de4c4
+0, 70, 70, 1, 149760, 0x18dd343f
+0, 71, 71, 1, 149760, 0xa1c51358
+0, 72, 72, 1, 149760, 0x91fe6361
+0, 73, 73, 1, 149760, 0xeec85f94
+0, 74, 74, 1, 149760, 0x00a57402
+0, 75, 75, 1, 149760, 0x4e88cc16
+0, 76, 76, 1, 149760, 0xdbd51976
+0, 77, 77, 1, 149760, 0xfebf6b1a
+0, 78, 78, 1, 149760, 0x052546d2
+0, 79, 79, 1, 149760, 0x046cd73b
diff --git a/tests/ref/fate/hevc-conformance-RPS_D_ericsson_6 b/tests/ref/fate/hevc-conformance-RPS_D_ericsson_6
index 1a58c0d7ff..2851704c52 100644
--- a/tests/ref/fate/hevc-conformance-RPS_D_ericsson_6
+++ b/tests/ref/fate/hevc-conformance-RPS_D_ericsson_6
@@ -1,69 +1,69 @@
#tb 0: 1/25
0, 0, 0, 1, 149760, 0x8ce7200b
-0, 2, 2, 1, 149760, 0x73610669
-0, 3, 3, 1, 149760, 0xc01620f4
-0, 4, 4, 1, 149760, 0x847a4297
-0, 5, 5, 1, 149760, 0xb4d3e870
-0, 6, 6, 1, 149760, 0xc2dd98a6
-0, 7, 7, 1, 149760, 0xefd02009
-0, 8, 8, 1, 149760, 0x3ae86ed0
-0, 9, 9, 1, 149760, 0x92f3cfb6
-0, 10, 10, 1, 149760, 0x0393e437
-0, 11, 11, 1, 149760, 0x6b29ea60
-0, 12, 12, 1, 149760, 0x9cb1216a
-0, 13, 13, 1, 149760, 0x82c2b1c4
-0, 14, 14, 1, 149760, 0x74899241
-0, 15, 15, 1, 149760, 0xa561f720
-0, 16, 16, 1, 149760, 0x339a11f6
-0, 17, 17, 1, 149760, 0x6bd9772b
-0, 18, 18, 1, 149760, 0x0a0c7c7d
-0, 19, 19, 1, 149760, 0x38426f65
-0, 20, 20, 1, 149760, 0x134ee7b3
-0, 21, 21, 1, 149760, 0xe436e35c
-0, 22, 22, 1, 149760, 0x4174d949
-0, 23, 23, 1, 149760, 0x44e60f0d
-0, 24, 24, 1, 149760, 0xbb6fb0a4
-0, 25, 25, 1, 149760, 0x715a653e
-0, 26, 26, 1, 149760, 0xad11b160
-0, 27, 27, 1, 149760, 0xfa6b368e
-0, 28, 28, 1, 149760, 0x60ff970f
-0, 29, 29, 1, 149760, 0x16430649
-0, 30, 30, 1, 149760, 0xa6cc0767
-0, 31, 31, 1, 149760, 0x59b0c566
-0, 32, 32, 1, 149760, 0xc9e3dfa9
-0, 33, 33, 1, 149760, 0x82873917
-0, 34, 34, 1, 149760, 0xc49e5d22
-0, 35, 35, 1, 149760, 0x416890a8
-0, 36, 36, 1, 149760, 0x386e57e8
-0, 37, 37, 1, 149760, 0x1c27e9d7
-0, 38, 38, 1, 149760, 0x85425596
-0, 39, 39, 1, 149760, 0xe6107df8
-0, 40, 40, 1, 149760, 0x056a3977
-0, 41, 41, 1, 149760, 0x753cf7f7
-0, 42, 42, 1, 149760, 0xc4005218
-0, 43, 43, 1, 149760, 0xce7edcf2
-0, 44, 44, 1, 149760, 0x93465fee
-0, 45, 45, 1, 149760, 0xa21b040a
-0, 46, 46, 1, 149760, 0xd82a53d5
-0, 47, 47, 1, 149760, 0x8f8fd3ae
-0, 48, 48, 1, 149760, 0x52420da5
-0, 49, 49, 1, 149760, 0xa899a9be
-0, 50, 50, 1, 149760, 0xcd85e363
-0, 51, 51, 1, 149760, 0x1a9240c4
-0, 52, 52, 1, 149760, 0xf0b11a36
-0, 53, 53, 1, 149760, 0xcf175809
-0, 54, 54, 1, 149760, 0x24afecc2
-0, 55, 55, 1, 149760, 0x874f7176
-0, 56, 56, 1, 149760, 0xb126dff9
-0, 57, 57, 1, 149760, 0x825ba060
-0, 58, 58, 1, 149760, 0x18c55eed
-0, 59, 59, 1, 149760, 0xf09b03f0
-0, 60, 60, 1, 149760, 0xf4dafd64
-0, 61, 61, 1, 149760, 0x08b49190
-0, 62, 62, 1, 149760, 0xcf336dc7
-0, 63, 63, 1, 149760, 0x51c65c08
-0, 64, 64, 1, 149760, 0x6cfe3433
-0, 65, 65, 1, 149760, 0x4b0af196
-0, 66, 66, 1, 149760, 0xffaeb2db
-0, 67, 67, 1, 149760, 0xa990a19f
-0, 68, 68, 1, 149760, 0x7ed944a3
+0, 1, 1, 1, 149760, 0x73610669
+0, 2, 2, 1, 149760, 0xc01620f4
+0, 3, 3, 1, 149760, 0x847a4297
+0, 4, 4, 1, 149760, 0xb4d3e870
+0, 5, 5, 1, 149760, 0xc2dd98a6
+0, 6, 6, 1, 149760, 0xefd02009
+0, 7, 7, 1, 149760, 0x3ae86ed0
+0, 8, 8, 1, 149760, 0x92f3cfb6
+0, 9, 9, 1, 149760, 0x0393e437
+0, 10, 10, 1, 149760, 0x6b29ea60
+0, 11, 11, 1, 149760, 0x9cb1216a
+0, 12, 12, 1, 149760, 0x82c2b1c4
+0, 13, 13, 1, 149760, 0x74899241
+0, 14, 14, 1, 149760, 0xa561f720
+0, 15, 15, 1, 149760, 0x339a11f6
+0, 16, 16, 1, 149760, 0x6bd9772b
+0, 17, 17, 1, 149760, 0x0a0c7c7d
+0, 18, 18, 1, 149760, 0x38426f65
+0, 19, 19, 1, 149760, 0x134ee7b3
+0, 20, 20, 1, 149760, 0xe436e35c
+0, 21, 21, 1, 149760, 0x4174d949
+0, 22, 22, 1, 149760, 0x44e60f0d
+0, 23, 23, 1, 149760, 0xbb6fb0a4
+0, 24, 24, 1, 149760, 0x715a653e
+0, 25, 25, 1, 149760, 0xad11b160
+0, 26, 26, 1, 149760, 0xfa6b368e
+0, 27, 27, 1, 149760, 0x60ff970f
+0, 28, 28, 1, 149760, 0x16430649
+0, 29, 29, 1, 149760, 0xa6cc0767
+0, 30, 30, 1, 149760, 0x59b0c566
+0, 31, 31, 1, 149760, 0xc9e3dfa9
+0, 32, 32, 1, 149760, 0x82873917
+0, 33, 33, 1, 149760, 0xc49e5d22
+0, 34, 34, 1, 149760, 0x416890a8
+0, 35, 35, 1, 149760, 0x386e57e8
+0, 36, 36, 1, 149760, 0x1c27e9d7
+0, 37, 37, 1, 149760, 0x85425596
+0, 38, 38, 1, 149760, 0xe6107df8
+0, 39, 39, 1, 149760, 0x056a3977
+0, 40, 40, 1, 149760, 0x753cf7f7
+0, 41, 41, 1, 149760, 0xc4005218
+0, 42, 42, 1, 149760, 0xce7edcf2
+0, 43, 43, 1, 149760, 0x93465fee
+0, 44, 44, 1, 149760, 0xa21b040a
+0, 45, 45, 1, 149760, 0xd82a53d5
+0, 46, 46, 1, 149760, 0x8f8fd3ae
+0, 47, 47, 1, 149760, 0x52420da5
+0, 48, 48, 1, 149760, 0xa899a9be
+0, 49, 49, 1, 149760, 0xcd85e363
+0, 50, 50, 1, 149760, 0x1a9240c4
+0, 51, 51, 1, 149760, 0xf0b11a36
+0, 52, 52, 1, 149760, 0xcf175809
+0, 53, 53, 1, 149760, 0x24afecc2
+0, 54, 54, 1, 149760, 0x874f7176
+0, 55, 55, 1, 149760, 0xb126dff9
+0, 56, 56, 1, 149760, 0x825ba060
+0, 57, 57, 1, 149760, 0x18c55eed
+0, 58, 58, 1, 149760, 0xf09b03f0
+0, 59, 59, 1, 149760, 0xf4dafd64
+0, 60, 60, 1, 149760, 0x08b49190
+0, 61, 61, 1, 149760, 0xcf336dc7
+0, 62, 62, 1, 149760, 0x51c65c08
+0, 63, 63, 1, 149760, 0x6cfe3433
+0, 64, 64, 1, 149760, 0x4b0af196
+0, 65, 65, 1, 149760, 0xffaeb2db
+0, 66, 66, 1, 149760, 0xa990a19f
+0, 67, 67, 1, 149760, 0x7ed944a3
diff --git a/tests/ref/fate/hevc-conformance-SAO_A_RExt_MediaTek_1 b/tests/ref/fate/hevc-conformance-SAO_A_RExt_MediaTek_1
new file mode 100644
index 0000000000..b6ed2112ae
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_A_RExt_MediaTek_1
@@ -0,0 +1,9 @@
+#tb 0: 1/25
+0, 0, 0, 1, 24576000, 0x5b01ceed
+0, 1, 1, 1, 24576000, 0x043fa798
+0, 2, 2, 1, 24576000, 0x9ec62721
+0, 3, 3, 1, 24576000, 0x5533793b
+0, 4, 4, 1, 24576000, 0x125f859e
+0, 5, 5, 1, 24576000, 0xe3b916b4
+0, 6, 6, 1, 24576000, 0x1fc1a62c
+0, 7, 7, 1, 24576000, 0xe3507948
diff --git a/tests/ref/fate/hevc-conformance-SAO_C_Samsung_5 b/tests/ref/fate/hevc-conformance-SAO_C_Samsung_5
new file mode 100644
index 0000000000..4cb1f78e52
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_C_Samsung_5
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0x6fe6508f
+0, 1, 1, 1, 3110400, 0xa56a3403
+0, 2, 2, 1, 3110400, 0x45db0973
+0, 3, 3, 1, 3110400, 0xb341a760
+0, 4, 4, 1, 3110400, 0x849c086c
diff --git a/tests/ref/fate/hevc-conformance-SAO_D_Samsung_5 b/tests/ref/fate/hevc-conformance-SAO_D_Samsung_5
new file mode 100644
index 0000000000..a1884dd01b
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-SAO_D_Samsung_5
@@ -0,0 +1,6 @@
+#tb 0: 1/25
+0, 0, 0, 1, 3110400, 0xcfb2f251
+0, 1, 1, 1, 3110400, 0xc2621936
+0, 2, 2, 1, 3110400, 0x5cb42788
+0, 3, 3, 1, 3110400, 0x5a3144a5
+0, 4, 4, 1, 3110400, 0x59eca534
diff --git a/tests/ref/fate/hevc-conformance-SLPPLP_A_VIDYO_2 b/tests/ref/fate/hevc-conformance-SLPPLP_A_VIDYO_2
new file mode 100644
index 0000000000..bbb3cfeaa1
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-SLPPLP_A_VIDYO_2
@@ -0,0 +1,34 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x88619f80
+0, 1, 1, 1, 149760, 0x550bdaf0
+0, 2, 2, 1, 149760, 0x99440a14
+0, 3, 3, 1, 149760, 0xcc2c2049
+0, 4, 4, 1, 149760, 0x46927368
+0, 5, 5, 1, 149760, 0x53cdb3fe
+0, 6, 6, 1, 149760, 0x654df025
+0, 7, 7, 1, 149760, 0x024d24bc
+0, 8, 8, 1, 149760, 0x409138c2
+0, 9, 9, 1, 149760, 0xfbb47c48
+0, 10, 10, 1, 149760, 0x18caa19d
+0, 11, 11, 1, 149760, 0x0f88c2e5
+0, 12, 12, 1, 149760, 0x1c16aa2d
+0, 13, 13, 1, 149760, 0x60bfcce8
+0, 14, 14, 1, 149760, 0x1c38e3d3
+0, 15, 15, 1, 149760, 0x0d5b044a
+0, 16, 16, 1, 149760, 0x93d21593
+0, 17, 17, 1, 149760, 0xdf283910
+0, 18, 18, 1, 149760, 0x03324c23
+0, 19, 19, 1, 149760, 0x3b175b7b
+0, 20, 20, 1, 149760, 0xb91b9a7e
+0, 21, 21, 1, 149760, 0x734fbbe7
+0, 22, 22, 1, 149760, 0xfc3fea48
+0, 23, 23, 1, 149760, 0x6609103e
+0, 24, 24, 1, 149760, 0x3f5916fa
+0, 25, 25, 1, 149760, 0x08e43f4d
+0, 26, 26, 1, 149760, 0xc84e5471
+0, 27, 27, 1, 149760, 0xbd4e5c8d
+0, 28, 28, 1, 149760, 0x4a4d3995
+0, 29, 29, 1, 149760, 0x662163c0
+0, 30, 30, 1, 149760, 0xda28671f
+0, 31, 31, 1, 149760, 0x19e1878e
+0, 32, 32, 1, 149760, 0x19807e67
diff --git a/tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_6 b/tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_6
new file mode 100644
index 0000000000..811c79019d
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-STRUCT_B_Samsung_6
@@ -0,0 +1,61 @@
+#tb 0: 1/25
+0, 0, 0, 1, 599040, 0x10e6d882
+0, 1, 1, 1, 599040, 0x10e6d882
+0, 2, 2, 1, 599040, 0x10e6d882
+0, 3, 3, 1, 599040, 0x2fc276f4
+0, 4, 4, 1, 599040, 0x087c24a5
+0, 5, 5, 1, 599040, 0x4355f37b
+0, 6, 6, 1, 599040, 0x4eefa76a
+0, 7, 7, 1, 599040, 0x270f268a
+0, 8, 8, 1, 599040, 0xa9be7d32
+0, 9, 9, 1, 599040, 0xbf75116e
+0, 10, 10, 1, 599040, 0x7d8a4ae2
+0, 11, 11, 1, 599040, 0x53e1c0d8
+0, 12, 12, 1, 599040, 0x076c3784
+0, 13, 13, 1, 599040, 0x49bf1c8d
+0, 14, 14, 1, 599040, 0xe7b537b9
+0, 15, 15, 1, 599040, 0xddc81bcb
+0, 16, 16, 1, 599040, 0x7761c601
+0, 17, 17, 1, 599040, 0xf5993c06
+0, 18, 18, 1, 599040, 0x6e21e3e4
+0, 19, 19, 1, 599040, 0x5964c0b5
+0, 20, 20, 1, 599040, 0xb10e8493
+0, 21, 21, 1, 599040, 0x17b1c730
+0, 22, 22, 1, 599040, 0xa55efe36
+0, 23, 23, 1, 599040, 0x3cb75b6c
+0, 24, 24, 1, 599040, 0xf8ed6b0c
+0, 25, 25, 1, 599040, 0xf1e4bc7d
+0, 26, 26, 1, 599040, 0x23236fd9
+0, 27, 27, 1, 599040, 0x8d8b2892
+0, 28, 28, 1, 599040, 0x3e311573
+0, 29, 29, 1, 599040, 0x81764911
+0, 30, 30, 1, 599040, 0x14d1802e
+0, 31, 31, 1, 599040, 0x0e065246
+0, 32, 32, 1, 599040, 0xc8a607cf
+0, 33, 33, 1, 599040, 0x23b210e7
+0, 34, 34, 1, 599040, 0x2c80da1c
+0, 35, 35, 1, 599040, 0x3e6e896b
+0, 36, 36, 1, 599040, 0x5a4aa035
+0, 37, 37, 1, 599040, 0x1b2d2d20
+0, 38, 38, 1, 599040, 0x12f928fc
+0, 39, 39, 1, 599040, 0x49ae617c
+0, 40, 40, 1, 599040, 0x77fe18a4
+0, 41, 41, 1, 599040, 0x296c1ef7
+0, 42, 42, 1, 599040, 0x72cad62f
+0, 43, 43, 1, 599040, 0xbf82d227
+0, 44, 44, 1, 599040, 0xf2bef8b1
+0, 45, 45, 1, 599040, 0xba67092f
+0, 46, 46, 1, 599040, 0xd5551dab
+0, 47, 47, 1, 599040, 0xf973b042
+0, 48, 48, 1, 599040, 0xdddf947a
+0, 49, 49, 1, 599040, 0x00a3e427
+0, 50, 50, 1, 599040, 0x23d8a74d
+0, 51, 51, 1, 599040, 0x1b84b0a9
+0, 52, 52, 1, 599040, 0x94bfcee9
+0, 53, 53, 1, 599040, 0xf0b6a9cb
+0, 54, 54, 1, 599040, 0x4a950fbe
+0, 55, 55, 1, 599040, 0x925c319c
+0, 56, 56, 1, 599040, 0x76511c5c
+0, 57, 57, 1, 599040, 0x1f59398f
+0, 58, 58, 1, 599040, 0x14af6c11
+0, 59, 59, 1, 599040, 0x20c87118
diff --git a/tests/ref/fate/hevc-conformance-VPSID_A_VIDYO_2 b/tests/ref/fate/hevc-conformance-VPSID_A_VIDYO_2
new file mode 100644
index 0000000000..bbb3cfeaa1
--- /dev/null
+++ b/tests/ref/fate/hevc-conformance-VPSID_A_VIDYO_2
@@ -0,0 +1,34 @@
+#tb 0: 1/25
+0, 0, 0, 1, 149760, 0x88619f80
+0, 1, 1, 1, 149760, 0x550bdaf0
+0, 2, 2, 1, 149760, 0x99440a14
+0, 3, 3, 1, 149760, 0xcc2c2049
+0, 4, 4, 1, 149760, 0x46927368
+0, 5, 5, 1, 149760, 0x53cdb3fe
+0, 6, 6, 1, 149760, 0x654df025
+0, 7, 7, 1, 149760, 0x024d24bc
+0, 8, 8, 1, 149760, 0x409138c2
+0, 9, 9, 1, 149760, 0xfbb47c48
+0, 10, 10, 1, 149760, 0x18caa19d
+0, 11, 11, 1, 149760, 0x0f88c2e5
+0, 12, 12, 1, 149760, 0x1c16aa2d
+0, 13, 13, 1, 149760, 0x60bfcce8
+0, 14, 14, 1, 149760, 0x1c38e3d3
+0, 15, 15, 1, 149760, 0x0d5b044a
+0, 16, 16, 1, 149760, 0x93d21593
+0, 17, 17, 1, 149760, 0xdf283910
+0, 18, 18, 1, 149760, 0x03324c23
+0, 19, 19, 1, 149760, 0x3b175b7b
+0, 20, 20, 1, 149760, 0xb91b9a7e
+0, 21, 21, 1, 149760, 0x734fbbe7
+0, 22, 22, 1, 149760, 0xfc3fea48
+0, 23, 23, 1, 149760, 0x6609103e
+0, 24, 24, 1, 149760, 0x3f5916fa
+0, 25, 25, 1, 149760, 0x08e43f4d
+0, 26, 26, 1, 149760, 0xc84e5471
+0, 27, 27, 1, 149760, 0xbd4e5c8d
+0, 28, 28, 1, 149760, 0x4a4d3995
+0, 29, 29, 1, 149760, 0x662163c0
+0, 30, 30, 1, 149760, 0xda28671f
+0, 31, 31, 1, 149760, 0x19e1878e
+0, 32, 32, 1, 149760, 0x19807e67
diff --git a/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3 b/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3
index f302764711..7dbc72bdbd 100644
--- a/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3
+++ b/tests/ref/fate/hevc-conformance-WP_B_Toshiba_3
@@ -1,257 +1,257 @@
#tb 0: 1/25
0, 0, 0, 1, 149760, 0xd8bf0c39
-0, 4, 4, 1, 149760, 0xad390a29
-0, 5, 5, 1, 149760, 0x0d310906
-0, 5, 5, 1, 149760, 0x03bcb5ac
-0, 6, 6, 1, 149760, 0x6c38226f
-0, 7, 7, 1, 149760, 0xc7d898b6
-0, 8, 8, 1, 149760, 0x1e031118
-0, 9, 9, 1, 149760, 0x7a2437f2
-0, 10, 10, 1, 149760, 0x524d616a
-0, 11, 11, 1, 149760, 0x001ac80e
-0, 12, 12, 1, 149760, 0x6fe323e4
-0, 13, 13, 1, 149760, 0x2a95a125
-0, 14, 14, 1, 149760, 0x212316e4
-0, 15, 15, 1, 149760, 0x7984e2ed
-0, 16, 16, 1, 149760, 0xb0a4a95c
-0, 17, 17, 1, 149760, 0x100566ae
-0, 18, 18, 1, 149760, 0xb21b2344
-0, 19, 19, 1, 149760, 0x0578bca2
-0, 20, 20, 1, 149760, 0xf7523964
-0, 21, 21, 1, 149760, 0x38d2ca9e
-0, 22, 22, 1, 149760, 0x77890564
-0, 23, 23, 1, 149760, 0xbdba85df
-0, 24, 24, 1, 149760, 0x646ae92d
-0, 25, 25, 1, 149760, 0xfcbb58b9
-0, 26, 26, 1, 149760, 0x0122aa96
-0, 27, 27, 1, 149760, 0x60f8e1ee
-0, 28, 28, 1, 149760, 0x3fc2d587
-0, 29, 29, 1, 149760, 0xdb622c12
-0, 30, 30, 1, 149760, 0xa8df64cf
-0, 31, 31, 1, 149760, 0x12f8d6c8
-0, 32, 32, 1, 149760, 0xf6703c4d
-0, 33, 33, 1, 149760, 0x66ef211d
-0, 34, 34, 1, 149760, 0x821b02f6
-0, 35, 35, 1, 149760, 0xc87f48a0
-0, 36, 36, 1, 149760, 0xb816ad51
-0, 37, 37, 1, 149760, 0x238e6fa0
-0, 38, 38, 1, 149760, 0x0fc06010
-0, 39, 39, 1, 149760, 0x749c71dc
-0, 40, 40, 1, 149760, 0x88c69718
-0, 41, 41, 1, 149760, 0x4b29aeb1
-0, 42, 42, 1, 149760, 0xaaefb509
-0, 43, 43, 1, 149760, 0x2975fda6
-0, 44, 44, 1, 149760, 0x613ec356
-0, 45, 45, 1, 149760, 0xf1e46db6
-0, 46, 46, 1, 149760, 0x8c8aec07
-0, 47, 47, 1, 149760, 0xb9a8be75
-0, 48, 48, 1, 149760, 0xfdce756a
-0, 49, 49, 1, 149760, 0x9c76f148
-0, 50, 50, 1, 149760, 0x5d1862dd
-0, 51, 51, 1, 149760, 0x42ae08bf
-0, 52, 52, 1, 149760, 0xc28f9247
-0, 53, 53, 1, 149760, 0x719d321c
-0, 54, 54, 1, 149760, 0x1520a7bc
-0, 55, 55, 1, 149760, 0x4fb98c9a
-0, 56, 56, 1, 149760, 0x88d410a6
-0, 57, 57, 1, 149760, 0x807ac417
-0, 58, 58, 1, 149760, 0x6de5f4ab
-0, 59, 59, 1, 149760, 0x678613c7
-0, 60, 60, 1, 149760, 0xe7d12abf
-0, 61, 61, 1, 149760, 0x23955076
-0, 62, 62, 1, 149760, 0x298d1bce
-0, 63, 63, 1, 149760, 0x18d4605d
-0, 64, 64, 1, 149760, 0x3a606618
-0, 65, 65, 1, 149760, 0x861fcb5a
-0, 66, 66, 1, 149760, 0xc6622a90
-0, 67, 67, 1, 149760, 0x62d4cd48
-0, 68, 68, 1, 149760, 0x991430e6
-0, 69, 69, 1, 149760, 0x6316503c
-0, 70, 70, 1, 149760, 0xdf2d29f2
-0, 71, 71, 1, 149760, 0xeeeb307a
-0, 72, 72, 1, 149760, 0xade9ae1d
-0, 73, 73, 1, 149760, 0x54734581
-0, 74, 74, 1, 149760, 0x5ccd7389
-0, 75, 75, 1, 149760, 0xf0588bf8
-0, 76, 76, 1, 149760, 0xf18e44e5
-0, 77, 77, 1, 149760, 0x4512602b
-0, 78, 78, 1, 149760, 0x9aac8281
-0, 79, 79, 1, 149760, 0x69bdad58
-0, 80, 80, 1, 149760, 0x04ffe580
-0, 81, 81, 1, 149760, 0x28bfe45f
-0, 82, 82, 1, 149760, 0xd7ce93b0
-0, 83, 83, 1, 149760, 0xa880b1d4
-0, 84, 84, 1, 149760, 0xf38298d0
-0, 85, 85, 1, 149760, 0x2ae05958
-0, 86, 86, 1, 149760, 0xa892151b
-0, 87, 87, 1, 149760, 0xed2cef63
-0, 88, 88, 1, 149760, 0x678fc6f5
-0, 89, 89, 1, 149760, 0xfcbaa892
-0, 90, 90, 1, 149760, 0x48cc722b
-0, 91, 91, 1, 149760, 0x32cd8975
-0, 92, 92, 1, 149760, 0x05ad8586
-0, 93, 93, 1, 149760, 0x62a0fb36
-0, 94, 94, 1, 149760, 0x41df8d45
-0, 95, 95, 1, 149760, 0x80bd938d
-0, 96, 96, 1, 149760, 0xafe414b0
-0, 97, 97, 1, 149760, 0x3077d51d
-0, 98, 98, 1, 149760, 0x65148cef
-0, 99, 99, 1, 149760, 0xadb76ef0
-0, 100, 100, 1, 149760, 0x889c3051
-0, 101, 101, 1, 149760, 0xe83b227e
-0, 102, 102, 1, 149760, 0xc373f5e0
-0, 103, 103, 1, 149760, 0x6ffa2a5f
-0, 104, 104, 1, 149760, 0x6eef18f5
-0, 105, 105, 1, 149760, 0x1b1ba6e4
-0, 106, 106, 1, 149760, 0x88e316a4
-0, 107, 107, 1, 149760, 0x4c0697f4
-0, 108, 108, 1, 149760, 0x5eb30515
-0, 109, 109, 1, 149760, 0xeeff8fa3
-0, 110, 110, 1, 149760, 0x653a07a9
-0, 111, 111, 1, 149760, 0x3faf44a8
-0, 112, 112, 1, 149760, 0xe33f740e
-0, 113, 113, 1, 149760, 0x6bea0f49
-0, 114, 114, 1, 149760, 0x4d5aa784
-0, 115, 115, 1, 149760, 0x0c85ea00
-0, 116, 116, 1, 149760, 0xf64fc40b
-0, 117, 117, 1, 149760, 0xf222e3b4
-0, 118, 118, 1, 149760, 0x6b3be6bc
-0, 119, 119, 1, 149760, 0x91447dfb
-0, 120, 120, 1, 149760, 0xfd0dd98c
-0, 121, 121, 1, 149760, 0x468eb01a
-0, 122, 122, 1, 149760, 0x928a720a
-0, 123, 123, 1, 149760, 0x0b3f576b
-0, 124, 124, 1, 149760, 0x430493df
-0, 125, 125, 1, 149760, 0x375d2221
-0, 126, 126, 1, 149760, 0x50d0a88c
-0, 127, 127, 1, 149760, 0x54363ffb
-0, 128, 128, 1, 149760, 0xc243c434
-0, 129, 129, 1, 149760, 0x26fe8f5c
-0, 130, 130, 1, 149760, 0xd936485c
-0, 131, 131, 1, 149760, 0xd936485c
-0, 132, 132, 1, 149760, 0xa0cabe5a
-0, 133, 133, 1, 149760, 0xf0956484
-0, 134, 134, 1, 149760, 0x14cda6ee
-0, 135, 135, 1, 149760, 0x0b7ada70
-0, 136, 136, 1, 149760, 0x113f0ec5
-0, 137, 137, 1, 149760, 0xc1364acc
-0, 138, 138, 1, 149760, 0x0c768a6a
-0, 139, 139, 1, 149760, 0x94fd7a00
-0, 140, 140, 1, 149760, 0x624a5ebb
-0, 141, 141, 1, 149760, 0xdd5008a0
-0, 142, 142, 1, 149760, 0xc380626c
-0, 143, 143, 1, 149760, 0xb0974c02
-0, 144, 144, 1, 149760, 0x68be6c1e
-0, 145, 145, 1, 149760, 0xb8d24677
-0, 146, 146, 1, 149760, 0x1efe195c
-0, 147, 147, 1, 149760, 0x29e9153a
-0, 148, 148, 1, 149760, 0x1b6057b7
-0, 149, 149, 1, 149760, 0x959a4461
-0, 150, 150, 1, 149760, 0x4e3d33a9
-0, 151, 151, 1, 149760, 0x206e7899
-0, 152, 152, 1, 149760, 0xcb7da081
-0, 153, 153, 1, 149760, 0xc650ed7b
-0, 154, 154, 1, 149760, 0x82832d10
-0, 155, 155, 1, 149760, 0xdf9c6218
-0, 156, 156, 1, 149760, 0xcc3489c7
-0, 157, 157, 1, 149760, 0xd284a4a1
-0, 158, 158, 1, 149760, 0x7099451c
-0, 159, 159, 1, 149760, 0xec26fc56
-0, 160, 160, 1, 149760, 0x105a496f
-0, 161, 161, 1, 149760, 0xb8756fe8
-0, 162, 162, 1, 149760, 0xb1a509df
-0, 163, 163, 1, 149760, 0x135f8f7e
-0, 164, 164, 1, 149760, 0x3419098d
-0, 165, 165, 1, 149760, 0xa55dad5f
-0, 166, 166, 1, 149760, 0x326ba794
-0, 167, 167, 1, 149760, 0x5401b03c
-0, 168, 168, 1, 149760, 0x3ace76ee
-0, 169, 169, 1, 149760, 0x140191ac
-0, 170, 170, 1, 149760, 0x3e3ca195
-0, 171, 171, 1, 149760, 0x2a8b3622
-0, 172, 172, 1, 149760, 0x9e33c765
-0, 173, 173, 1, 149760, 0xf7795367
-0, 174, 174, 1, 149760, 0xa7909e25
-0, 175, 175, 1, 149760, 0x44a5a014
-0, 176, 176, 1, 149760, 0x919bb07c
-0, 177, 177, 1, 149760, 0xd353b9a7
-0, 178, 178, 1, 149760, 0x4c3dda24
-0, 179, 179, 1, 149760, 0x1428eafb
-0, 180, 180, 1, 149760, 0x9d9fa613
-0, 181, 181, 1, 149760, 0x661475c6
-0, 182, 182, 1, 149760, 0x5f6f4180
-0, 183, 183, 1, 149760, 0xf50a4b4c
-0, 184, 184, 1, 149760, 0xf6373eb9
-0, 185, 185, 1, 149760, 0x0ab24b74
-0, 186, 186, 1, 149760, 0x6b3d58b0
-0, 187, 187, 1, 149760, 0xc4c8bd05
-0, 188, 188, 1, 149760, 0x0df172c6
-0, 189, 189, 1, 149760, 0x81a85144
-0, 190, 190, 1, 149760, 0x7f926ee5
-0, 191, 191, 1, 149760, 0x3a355d45
-0, 192, 192, 1, 149760, 0x9f645c90
-0, 193, 193, 1, 149760, 0xf42674ea
-0, 194, 194, 1, 149760, 0xa6e943ab
-0, 195, 195, 1, 149760, 0xede16b49
-0, 196, 196, 1, 149760, 0xf80c9957
-0, 197, 197, 1, 149760, 0xa7a44665
-0, 198, 198, 1, 149760, 0x08f17b20
-0, 199, 199, 1, 149760, 0x0319e942
-0, 200, 200, 1, 149760, 0xab69057c
-0, 201, 201, 1, 149760, 0xb98814f4
-0, 202, 202, 1, 149760, 0xa172e6d0
-0, 203, 203, 1, 149760, 0x6cd35cd1
-0, 204, 204, 1, 149760, 0x7352b4b9
-0, 205, 205, 1, 149760, 0x07cbdedd
-0, 206, 206, 1, 149760, 0xbe7aa3c8
-0, 207, 207, 1, 149760, 0xdcbc8993
-0, 208, 208, 1, 149760, 0x0c5dbf95
-0, 209, 209, 1, 149760, 0x107e4f2c
-0, 210, 210, 1, 149760, 0xc650e333
-0, 211, 211, 1, 149760, 0x46abae6f
-0, 212, 212, 1, 149760, 0x0e41309d
-0, 213, 213, 1, 149760, 0x831e19a1
-0, 214, 214, 1, 149760, 0xd1955874
-0, 215, 215, 1, 149760, 0x486c41bb
-0, 216, 216, 1, 149760, 0xba020143
-0, 217, 217, 1, 149760, 0x3ebedef4
-0, 218, 218, 1, 149760, 0xda7bc235
-0, 219, 219, 1, 149760, 0x0abcb13e
-0, 220, 220, 1, 149760, 0xdf5159ac
-0, 221, 221, 1, 149760, 0x4e39d893
-0, 222, 222, 1, 149760, 0x393f382d
-0, 223, 223, 1, 149760, 0x92556867
-0, 224, 224, 1, 149760, 0x2daf47a8
-0, 225, 225, 1, 149760, 0x792a4448
-0, 226, 226, 1, 149760, 0x429e05ad
-0, 227, 227, 1, 149760, 0x89caaa32
-0, 228, 228, 1, 149760, 0xa70ec97b
-0, 229, 229, 1, 149760, 0xce0d24b7
-0, 230, 230, 1, 149760, 0x04be745d
-0, 231, 231, 1, 149760, 0xfb04d3d2
-0, 232, 232, 1, 149760, 0x5b472952
-0, 233, 233, 1, 149760, 0x6cd704b5
-0, 234, 234, 1, 149760, 0x18b0db7e
-0, 235, 235, 1, 149760, 0xdfb24e07
-0, 236, 236, 1, 149760, 0x6d9bae45
-0, 237, 237, 1, 149760, 0xf2eb5756
-0, 238, 238, 1, 149760, 0xdf858203
-0, 239, 239, 1, 149760, 0xdcd4822f
-0, 240, 240, 1, 149760, 0x80ceabaf
-0, 241, 241, 1, 149760, 0x8bd1a92f
-0, 242, 242, 1, 149760, 0x981a61ca
-0, 243, 243, 1, 149760, 0x5fa92603
-0, 244, 244, 1, 149760, 0xbb28f8da
-0, 245, 245, 1, 149760, 0x1710666d
-0, 246, 246, 1, 149760, 0xf928099a
-0, 247, 247, 1, 149760, 0x2e0ae9cb
-0, 248, 248, 1, 149760, 0xcf0e402c
-0, 249, 249, 1, 149760, 0x48e5b987
-0, 250, 250, 1, 149760, 0x7dc42853
-0, 251, 251, 1, 149760, 0x25f4aef0
-0, 252, 252, 1, 149760, 0x5f1d37b3
-0, 253, 253, 1, 149760, 0xb2fabf9f
-0, 254, 254, 1, 149760, 0xe87348ee
-0, 255, 255, 1, 149760, 0xbe9ec00f
-0, 256, 256, 1, 149760, 0xd67d1fb2
-0, 257, 257, 1, 149760, 0x92db1ca8
+0, 1, 1, 1, 149760, 0xad390a29
+0, 2, 2, 1, 149760, 0x0d310906
+0, 3, 3, 1, 149760, 0x03bcb5ac
+0, 4, 4, 1, 149760, 0x6c38226f
+0, 5, 5, 1, 149760, 0xc7d898b6
+0, 6, 6, 1, 149760, 0x1e031118
+0, 7, 7, 1, 149760, 0x7a2437f2
+0, 8, 8, 1, 149760, 0x524d616a
+0, 9, 9, 1, 149760, 0x001ac80e
+0, 10, 10, 1, 149760, 0x6fe323e4
+0, 11, 11, 1, 149760, 0x2a95a125
+0, 12, 12, 1, 149760, 0x212316e4
+0, 13, 13, 1, 149760, 0x7984e2ed
+0, 14, 14, 1, 149760, 0xb0a4a95c
+0, 15, 15, 1, 149760, 0x100566ae
+0, 16, 16, 1, 149760, 0xb21b2344
+0, 17, 17, 1, 149760, 0x0578bca2
+0, 18, 18, 1, 149760, 0xf7523964
+0, 19, 19, 1, 149760, 0x38d2ca9e
+0, 20, 20, 1, 149760, 0x77890564
+0, 21, 21, 1, 149760, 0xbdba85df
+0, 22, 22, 1, 149760, 0x646ae92d
+0, 23, 23, 1, 149760, 0xfcbb58b9
+0, 24, 24, 1, 149760, 0x0122aa96
+0, 25, 25, 1, 149760, 0x60f8e1ee
+0, 26, 26, 1, 149760, 0x3fc2d587
+0, 27, 27, 1, 149760, 0xdb622c12
+0, 28, 28, 1, 149760, 0xa8df64cf
+0, 29, 29, 1, 149760, 0x12f8d6c8
+0, 30, 30, 1, 149760, 0xf6703c4d
+0, 31, 31, 1, 149760, 0x66ef211d
+0, 32, 32, 1, 149760, 0x821b02f6
+0, 33, 33, 1, 149760, 0xc87f48a0
+0, 34, 34, 1, 149760, 0xb816ad51
+0, 35, 35, 1, 149760, 0x238e6fa0
+0, 36, 36, 1, 149760, 0x0fc06010
+0, 37, 37, 1, 149760, 0x749c71dc
+0, 38, 38, 1, 149760, 0x88c69718
+0, 39, 39, 1, 149760, 0x4b29aeb1
+0, 40, 40, 1, 149760, 0xaaefb509
+0, 41, 41, 1, 149760, 0x2975fda6
+0, 42, 42, 1, 149760, 0x613ec356
+0, 43, 43, 1, 149760, 0xf1e46db6
+0, 44, 44, 1, 149760, 0x8c8aec07
+0, 45, 45, 1, 149760, 0xb9a8be75
+0, 46, 46, 1, 149760, 0xfdce756a
+0, 47, 47, 1, 149760, 0x9c76f148
+0, 48, 48, 1, 149760, 0x5d1862dd
+0, 49, 49, 1, 149760, 0x42ae08bf
+0, 50, 50, 1, 149760, 0xc28f9247
+0, 51, 51, 1, 149760, 0x719d321c
+0, 52, 52, 1, 149760, 0x1520a7bc
+0, 53, 53, 1, 149760, 0x4fb98c9a
+0, 54, 54, 1, 149760, 0x88d410a6
+0, 55, 55, 1, 149760, 0x807ac417
+0, 56, 56, 1, 149760, 0x6de5f4ab
+0, 57, 57, 1, 149760, 0x678613c7
+0, 58, 58, 1, 149760, 0xe7d12abf
+0, 59, 59, 1, 149760, 0x23955076
+0, 60, 60, 1, 149760, 0x298d1bce
+0, 61, 61, 1, 149760, 0x18d4605d
+0, 62, 62, 1, 149760, 0x3a606618
+0, 63, 63, 1, 149760, 0x861fcb5a
+0, 64, 64, 1, 149760, 0xc6622a90
+0, 65, 65, 1, 149760, 0x62d4cd48
+0, 66, 66, 1, 149760, 0x991430e6
+0, 67, 67, 1, 149760, 0x6316503c
+0, 68, 68, 1, 149760, 0xdf2d29f2
+0, 69, 69, 1, 149760, 0xeeeb307a
+0, 70, 70, 1, 149760, 0xade9ae1d
+0, 71, 71, 1, 149760, 0x54734581
+0, 72, 72, 1, 149760, 0x5ccd7389
+0, 73, 73, 1, 149760, 0xf0588bf8
+0, 74, 74, 1, 149760, 0xf18e44e5
+0, 75, 75, 1, 149760, 0x4512602b
+0, 76, 76, 1, 149760, 0x9aac8281
+0, 77, 77, 1, 149760, 0x69bdad58
+0, 78, 78, 1, 149760, 0x04ffe580
+0, 79, 79, 1, 149760, 0x28bfe45f
+0, 80, 80, 1, 149760, 0xd7ce93b0
+0, 81, 81, 1, 149760, 0xa880b1d4
+0, 82, 82, 1, 149760, 0xf38298d0
+0, 83, 83, 1, 149760, 0x2ae05958
+0, 84, 84, 1, 149760, 0xa892151b
+0, 85, 85, 1, 149760, 0xed2cef63
+0, 86, 86, 1, 149760, 0x678fc6f5
+0, 87, 87, 1, 149760, 0xfcbaa892
+0, 88, 88, 1, 149760, 0x48cc722b
+0, 89, 89, 1, 149760, 0x32cd8975
+0, 90, 90, 1, 149760, 0x05ad8586
+0, 91, 91, 1, 149760, 0x62a0fb36
+0, 92, 92, 1, 149760, 0x41df8d45
+0, 93, 93, 1, 149760, 0x80bd938d
+0, 94, 94, 1, 149760, 0xafe414b0
+0, 95, 95, 1, 149760, 0x3077d51d
+0, 96, 96, 1, 149760, 0x65148cef
+0, 97, 97, 1, 149760, 0xadb76ef0
+0, 98, 98, 1, 149760, 0x889c3051
+0, 99, 99, 1, 149760, 0xe83b227e
+0, 100, 100, 1, 149760, 0xc373f5e0
+0, 101, 101, 1, 149760, 0x6ffa2a5f
+0, 102, 102, 1, 149760, 0x6eef18f5
+0, 103, 103, 1, 149760, 0x1b1ba6e4
+0, 104, 104, 1, 149760, 0x88e316a4
+0, 105, 105, 1, 149760, 0x4c0697f4
+0, 106, 106, 1, 149760, 0x5eb30515
+0, 107, 107, 1, 149760, 0xeeff8fa3
+0, 108, 108, 1, 149760, 0x653a07a9
+0, 109, 109, 1, 149760, 0x3faf44a8
+0, 110, 110, 1, 149760, 0xe33f740e
+0, 111, 111, 1, 149760, 0x6bea0f49
+0, 112, 112, 1, 149760, 0x4d5aa784
+0, 113, 113, 1, 149760, 0x0c85ea00
+0, 114, 114, 1, 149760, 0xf64fc40b
+0, 115, 115, 1, 149760, 0xf222e3b4
+0, 116, 116, 1, 149760, 0x6b3be6bc
+0, 117, 117, 1, 149760, 0x91447dfb
+0, 118, 118, 1, 149760, 0xfd0dd98c
+0, 119, 119, 1, 149760, 0x468eb01a
+0, 120, 120, 1, 149760, 0x928a720a
+0, 121, 121, 1, 149760, 0x0b3f576b
+0, 122, 122, 1, 149760, 0x430493df
+0, 123, 123, 1, 149760, 0x375d2221
+0, 124, 124, 1, 149760, 0x50d0a88c
+0, 125, 125, 1, 149760, 0x54363ffb
+0, 126, 126, 1, 149760, 0xc243c434
+0, 127, 127, 1, 149760, 0x26fe8f5c
+0, 128, 128, 1, 149760, 0xd936485c
+0, 129, 129, 1, 149760, 0xd936485c
+0, 130, 130, 1, 149760, 0xa0cabe5a
+0, 131, 131, 1, 149760, 0xf0956484
+0, 132, 132, 1, 149760, 0x14cda6ee
+0, 133, 133, 1, 149760, 0x0b7ada70
+0, 134, 134, 1, 149760, 0x113f0ec5
+0, 135, 135, 1, 149760, 0xc1364acc
+0, 136, 136, 1, 149760, 0x0c768a6a
+0, 137, 137, 1, 149760, 0x94fd7a00
+0, 138, 138, 1, 149760, 0x624a5ebb
+0, 139, 139, 1, 149760, 0xdd5008a0
+0, 140, 140, 1, 149760, 0xc380626c
+0, 141, 141, 1, 149760, 0xb0974c02
+0, 142, 142, 1, 149760, 0x68be6c1e
+0, 143, 143, 1, 149760, 0xb8d24677
+0, 144, 144, 1, 149760, 0x1efe195c
+0, 145, 145, 1, 149760, 0x29e9153a
+0, 146, 146, 1, 149760, 0x1b6057b7
+0, 147, 147, 1, 149760, 0x959a4461
+0, 148, 148, 1, 149760, 0x4e3d33a9
+0, 149, 149, 1, 149760, 0x206e7899
+0, 150, 150, 1, 149760, 0xcb7da081
+0, 151, 151, 1, 149760, 0xc650ed7b
+0, 152, 152, 1, 149760, 0x82832d10
+0, 153, 153, 1, 149760, 0xdf9c6218
+0, 154, 154, 1, 149760, 0xcc3489c7
+0, 155, 155, 1, 149760, 0xd284a4a1
+0, 156, 156, 1, 149760, 0x7099451c
+0, 157, 157, 1, 149760, 0xec26fc56
+0, 158, 158, 1, 149760, 0x105a496f
+0, 159, 159, 1, 149760, 0xb8756fe8
+0, 160, 160, 1, 149760, 0xb1a509df
+0, 161, 161, 1, 149760, 0x135f8f7e
+0, 162, 162, 1, 149760, 0x3419098d
+0, 163, 163, 1, 149760, 0xa55dad5f
+0, 164, 164, 1, 149760, 0x326ba794
+0, 165, 165, 1, 149760, 0x5401b03c
+0, 166, 166, 1, 149760, 0x3ace76ee
+0, 167, 167, 1, 149760, 0x140191ac
+0, 168, 168, 1, 149760, 0x3e3ca195
+0, 169, 169, 1, 149760, 0x2a8b3622
+0, 170, 170, 1, 149760, 0x9e33c765
+0, 171, 171, 1, 149760, 0xf7795367
+0, 172, 172, 1, 149760, 0xa7909e25
+0, 173, 173, 1, 149760, 0x44a5a014
+0, 174, 174, 1, 149760, 0x919bb07c
+0, 175, 175, 1, 149760, 0xd353b9a7
+0, 176, 176, 1, 149760, 0x4c3dda24
+0, 177, 177, 1, 149760, 0x1428eafb
+0, 178, 178, 1, 149760, 0x9d9fa613
+0, 179, 179, 1, 149760, 0x661475c6
+0, 180, 180, 1, 149760, 0x5f6f4180
+0, 181, 181, 1, 149760, 0xf50a4b4c
+0, 182, 182, 1, 149760, 0xf6373eb9
+0, 183, 183, 1, 149760, 0x0ab24b74
+0, 184, 184, 1, 149760, 0x6b3d58b0
+0, 185, 185, 1, 149760, 0xc4c8bd05
+0, 186, 186, 1, 149760, 0x0df172c6
+0, 187, 187, 1, 149760, 0x81a85144
+0, 188, 188, 1, 149760, 0x7f926ee5
+0, 189, 189, 1, 149760, 0x3a355d45
+0, 190, 190, 1, 149760, 0x9f645c90
+0, 191, 191, 1, 149760, 0xf42674ea
+0, 192, 192, 1, 149760, 0xa6e943ab
+0, 193, 193, 1, 149760, 0xede16b49
+0, 194, 194, 1, 149760, 0xf80c9957
+0, 195, 195, 1, 149760, 0xa7a44665
+0, 196, 196, 1, 149760, 0x08f17b20
+0, 197, 197, 1, 149760, 0x0319e942
+0, 198, 198, 1, 149760, 0xab69057c
+0, 199, 199, 1, 149760, 0xb98814f4
+0, 200, 200, 1, 149760, 0xa172e6d0
+0, 201, 201, 1, 149760, 0x6cd35cd1
+0, 202, 202, 1, 149760, 0x7352b4b9
+0, 203, 203, 1, 149760, 0x07cbdedd
+0, 204, 204, 1, 149760, 0xbe7aa3c8
+0, 205, 205, 1, 149760, 0xdcbc8993
+0, 206, 206, 1, 149760, 0x0c5dbf95
+0, 207, 207, 1, 149760, 0x107e4f2c
+0, 208, 208, 1, 149760, 0xc650e333
+0, 209, 209, 1, 149760, 0x46abae6f
+0, 210, 210, 1, 149760, 0x0e41309d
+0, 211, 211, 1, 149760, 0x831e19a1
+0, 212, 212, 1, 149760, 0xd1955874
+0, 213, 213, 1, 149760, 0x486c41bb
+0, 214, 214, 1, 149760, 0xba020143
+0, 215, 215, 1, 149760, 0x3ebedef4
+0, 216, 216, 1, 149760, 0xda7bc235
+0, 217, 217, 1, 149760, 0x0abcb13e
+0, 218, 218, 1, 149760, 0xdf5159ac
+0, 219, 219, 1, 149760, 0x4e39d893
+0, 220, 220, 1, 149760, 0x393f382d
+0, 221, 221, 1, 149760, 0x92556867
+0, 222, 222, 1, 149760, 0x2daf47a8
+0, 223, 223, 1, 149760, 0x792a4448
+0, 224, 224, 1, 149760, 0x429e05ad
+0, 225, 225, 1, 149760, 0x89caaa32
+0, 226, 226, 1, 149760, 0xa70ec97b
+0, 227, 227, 1, 149760, 0xce0d24b7
+0, 228, 228, 1, 149760, 0x04be745d
+0, 229, 229, 1, 149760, 0xfb04d3d2
+0, 230, 230, 1, 149760, 0x5b472952
+0, 231, 231, 1, 149760, 0x6cd704b5
+0, 232, 232, 1, 149760, 0x18b0db7e
+0, 233, 233, 1, 149760, 0xdfb24e07
+0, 234, 234, 1, 149760, 0x6d9bae45
+0, 235, 235, 1, 149760, 0xf2eb5756
+0, 236, 236, 1, 149760, 0xdf858203
+0, 237, 237, 1, 149760, 0xdcd4822f
+0, 238, 238, 1, 149760, 0x80ceabaf
+0, 239, 239, 1, 149760, 0x8bd1a92f
+0, 240, 240, 1, 149760, 0x981a61ca
+0, 241, 241, 1, 149760, 0x5fa92603
+0, 242, 242, 1, 149760, 0xbb28f8da
+0, 243, 243, 1, 149760, 0x1710666d
+0, 244, 244, 1, 149760, 0xf928099a
+0, 245, 245, 1, 149760, 0x2e0ae9cb
+0, 246, 246, 1, 149760, 0xcf0e402c
+0, 247, 247, 1, 149760, 0x48e5b987
+0, 248, 248, 1, 149760, 0x7dc42853
+0, 249, 249, 1, 149760, 0x25f4aef0
+0, 250, 250, 1, 149760, 0x5f1d37b3
+0, 251, 251, 1, 149760, 0xb2fabf9f
+0, 252, 252, 1, 149760, 0xe87348ee
+0, 253, 253, 1, 149760, 0xbe9ec00f
+0, 254, 254, 1, 149760, 0xd67d1fb2
+0, 255, 255, 1, 149760, 0x92db1ca8
diff --git a/tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3 b/tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3
index 23f03f8487..332c7df3e4 100644
--- a/tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3
+++ b/tests/ref/fate/hevc-conformance-WP_MAIN10_B_Toshiba_3
@@ -1,257 +1,257 @@
#tb 0: 1/25
0, 0, 0, 1, 299520, 0x6ecba46b
-0, 4, 4, 1, 299520, 0x54e6ef0a
-0, 5, 5, 1, 299520, 0x7a4d46c5
-0, 6, 6, 1, 299520, 0xccd57f4e
-0, 7, 7, 1, 299520, 0xbe0cb48d
-0, 8, 8, 1, 299520, 0x10e7b49f
-0, 9, 9, 1, 299520, 0x81aa72e2
-0, 10, 10, 1, 299520, 0x5bf7b51f
-0, 11, 11, 1, 299520, 0xfcedee4a
-0, 12, 12, 1, 299520, 0x586c99b6
-0, 13, 13, 1, 299520, 0x414ca13c
-0, 14, 14, 1, 299520, 0x3f0162f2
-0, 15, 15, 1, 299520, 0x4d450c05
-0, 16, 16, 1, 299520, 0x0a58bd84
-0, 17, 17, 1, 299520, 0x26e8394d
-0, 18, 18, 1, 299520, 0xfd78121b
-0, 19, 19, 1, 299520, 0x6afeaf44
-0, 20, 20, 1, 299520, 0x3e9a9270
-0, 21, 21, 1, 299520, 0x58b889ca
-0, 22, 22, 1, 299520, 0x0245ba62
-0, 23, 23, 1, 299520, 0xddecc5ab
-0, 24, 24, 1, 299520, 0x32cf3cd9
-0, 25, 25, 1, 299520, 0x5c0a0440
-0, 26, 26, 1, 299520, 0x9d3e2fee
-0, 27, 27, 1, 299520, 0x2894c708
-0, 28, 28, 1, 299520, 0x25be67d5
-0, 29, 29, 1, 299520, 0xe3ece9d6
-0, 30, 30, 1, 299520, 0xcc98e38b
-0, 31, 31, 1, 299520, 0xc448c794
-0, 32, 32, 1, 299520, 0xb4f75575
-0, 33, 33, 1, 299520, 0xac74a437
-0, 34, 34, 1, 299520, 0x09c7f2e2
-0, 35, 35, 1, 299520, 0xbfaed8ab
-0, 36, 36, 1, 299520, 0xb077d700
-0, 37, 37, 1, 299520, 0x6efa0545
-0, 38, 38, 1, 299520, 0xb8c1802d
-0, 39, 39, 1, 299520, 0x794774f8
-0, 40, 40, 1, 299520, 0x1098f4ff
-0, 41, 41, 1, 299520, 0x80ab8bfc
-0, 42, 42, 1, 299520, 0xc324c3bc
-0, 43, 43, 1, 299520, 0x1eee77cd
-0, 44, 44, 1, 299520, 0x7147e72e
-0, 45, 45, 1, 299520, 0x1a34883c
-0, 46, 46, 1, 299520, 0x74e93e31
-0, 47, 47, 1, 299520, 0x89410382
-0, 48, 48, 1, 299520, 0xfcce0ce1
-0, 49, 49, 1, 299520, 0x07bb33c6
-0, 50, 50, 1, 299520, 0xc1ee7318
-0, 51, 51, 1, 299520, 0xd1c4bd2d
-0, 52, 52, 1, 299520, 0xa670cfae
-0, 53, 53, 1, 299520, 0x718de79b
-0, 54, 54, 1, 299520, 0x85e40b78
-0, 55, 55, 1, 299520, 0x15362e72
-0, 56, 56, 1, 299520, 0xc6e523fa
-0, 57, 57, 1, 299520, 0x3e536edd
-0, 58, 58, 1, 299520, 0x9312996e
-0, 59, 59, 1, 299520, 0x9456d53c
-0, 60, 60, 1, 299520, 0x7bc01398
-0, 61, 61, 1, 299520, 0x5a40bcb4
-0, 62, 62, 1, 299520, 0xcfe126ce
-0, 63, 63, 1, 299520, 0xd9e1adf1
-0, 64, 64, 1, 299520, 0x9027b1ae
-0, 65, 65, 1, 299520, 0x4c1372fb
-0, 66, 66, 1, 299520, 0xe475a00b
-0, 67, 67, 1, 299520, 0x945bc646
-0, 68, 68, 1, 299520, 0xc33dbab3
-0, 69, 69, 1, 299520, 0x9e4afb82
-0, 70, 70, 1, 299520, 0x1bffa858
-0, 71, 71, 1, 299520, 0x3bc78ad7
-0, 72, 72, 1, 299520, 0xa096e683
-0, 73, 73, 1, 299520, 0xb889aa23
-0, 74, 74, 1, 299520, 0x8ffad857
-0, 75, 75, 1, 299520, 0x59d3cc7c
-0, 76, 76, 1, 299520, 0x47d1377a
-0, 77, 77, 1, 299520, 0xea73e864
-0, 78, 78, 1, 299520, 0x0994bd5c
-0, 79, 79, 1, 299520, 0xdf779d85
-0, 80, 80, 1, 299520, 0x8238cfa7
-0, 81, 81, 1, 299520, 0x8f2e94cc
-0, 82, 82, 1, 299520, 0x9e0b0df8
-0, 83, 83, 1, 299520, 0x98ac1ce5
-0, 84, 84, 1, 299520, 0xc1c293ed
-0, 85, 85, 1, 299520, 0x1f1dfedb
-0, 86, 86, 1, 299520, 0xe7297d56
-0, 87, 87, 1, 299520, 0xa1390726
-0, 88, 88, 1, 299520, 0xf0e828e8
-0, 89, 89, 1, 299520, 0x108b8291
-0, 90, 90, 1, 299520, 0xd8830efb
-0, 91, 91, 1, 299520, 0xeee3d2f0
-0, 92, 92, 1, 299520, 0xa35d5b29
-0, 93, 93, 1, 299520, 0xa14d0840
-0, 94, 94, 1, 299520, 0xfa894a56
-0, 95, 95, 1, 299520, 0xd50005b5
-0, 96, 96, 1, 299520, 0xba625134
-0, 97, 97, 1, 299520, 0xce7dd782
-0, 98, 98, 1, 299520, 0x9e04e32f
-0, 99, 99, 1, 299520, 0x07e6d466
-0, 100, 100, 1, 299520, 0x4e66e1d4
-0, 101, 101, 1, 299520, 0x80aa6be6
-0, 102, 102, 1, 299520, 0xa4564be8
-0, 103, 103, 1, 299520, 0x7d34e443
-0, 104, 104, 1, 299520, 0xd5a08c86
-0, 105, 105, 1, 299520, 0xa73e63e8
-0, 106, 106, 1, 299520, 0x93937eb2
-0, 107, 107, 1, 299520, 0x0c08ba8f
-0, 108, 108, 1, 299520, 0x1d6b1a8c
-0, 109, 109, 1, 299520, 0x2e0272b4
-0, 110, 110, 1, 299520, 0x47177676
-0, 111, 111, 1, 299520, 0x6af7ffce
-0, 112, 112, 1, 299520, 0x0564a4bc
-0, 113, 113, 1, 299520, 0x7f664100
-0, 114, 114, 1, 299520, 0x6decd6ae
-0, 115, 115, 1, 299520, 0xb2d94adc
-0, 116, 116, 1, 299520, 0x55d33809
-0, 117, 117, 1, 299520, 0x5b126674
-0, 118, 118, 1, 299520, 0xd25d5750
-0, 119, 119, 1, 299520, 0x789a7f89
-0, 120, 120, 1, 299520, 0xdd082ab2
-0, 121, 121, 1, 299520, 0x3e6132ee
-0, 122, 122, 1, 299520, 0xe48209ca
-0, 123, 123, 1, 299520, 0x707d3b24
-0, 124, 124, 1, 299520, 0x8af19539
-0, 125, 125, 1, 299520, 0x0bbb4c38
-0, 126, 126, 1, 299520, 0xaaba4bd6
-0, 127, 127, 1, 299520, 0xa325d79e
-0, 128, 128, 1, 299520, 0x2bd4b64a
-0, 129, 129, 1, 299520, 0xab0c59a7
-0, 130, 130, 1, 299520, 0x260a56fc
-0, 131, 131, 1, 299520, 0xa1a55847
-0, 132, 132, 1, 299520, 0xa1a55847
-0, 133, 133, 1, 299520, 0x01438514
-0, 134, 134, 1, 299520, 0xa511e8bd
-0, 135, 135, 1, 299520, 0x7ebfd5b9
-0, 136, 136, 1, 299520, 0xdf4f1365
-0, 137, 137, 1, 299520, 0x6266911a
-0, 138, 138, 1, 299520, 0xe8eefcab
-0, 139, 139, 1, 299520, 0x7e74ca0d
-0, 140, 140, 1, 299520, 0x4b21d349
-0, 141, 141, 1, 299520, 0xa8b9ef41
-0, 142, 142, 1, 299520, 0x3187ee5b
-0, 143, 143, 1, 299520, 0x3fadb935
-0, 144, 144, 1, 299520, 0x8dca0391
-0, 145, 145, 1, 299520, 0x68215cc6
-0, 146, 146, 1, 299520, 0x7c81f366
-0, 147, 147, 1, 299520, 0x1a976381
-0, 148, 148, 1, 299520, 0x8ac095f4
-0, 149, 149, 1, 299520, 0xf5f8752b
-0, 150, 150, 1, 299520, 0xd8c03c80
-0, 151, 151, 1, 299520, 0x445a2e07
-0, 152, 152, 1, 299520, 0xddb83c6f
-0, 153, 153, 1, 299520, 0xc6dfe76a
-0, 154, 154, 1, 299520, 0x860a120f
-0, 155, 155, 1, 299520, 0x1ec91a95
-0, 156, 156, 1, 299520, 0x0180cc49
-0, 157, 157, 1, 299520, 0x63a115e3
-0, 158, 158, 1, 299520, 0x8848e971
-0, 159, 159, 1, 299520, 0x49246622
-0, 160, 160, 1, 299520, 0x3169db32
-0, 161, 161, 1, 299520, 0xcf01d8a3
-0, 162, 162, 1, 299520, 0x57a1a9c1
-0, 163, 163, 1, 299520, 0x517670eb
-0, 164, 164, 1, 299520, 0x4e2e6b5a
-0, 165, 165, 1, 299520, 0x06240a68
-0, 166, 166, 1, 299520, 0xa0d076a1
-0, 167, 167, 1, 299520, 0xb73c4515
-0, 168, 168, 1, 299520, 0x9f523268
-0, 169, 169, 1, 299520, 0x6fdcc6a2
-0, 170, 170, 1, 299520, 0xf3f5b69f
-0, 171, 171, 1, 299520, 0xce33a286
-0, 172, 172, 1, 299520, 0xce46e834
-0, 173, 173, 1, 299520, 0x14a6fe0d
-0, 174, 174, 1, 299520, 0x39a8145f
-0, 175, 175, 1, 299520, 0x91981d47
-0, 176, 176, 1, 299520, 0x1507d9be
-0, 177, 177, 1, 299520, 0x4525d4a2
-0, 178, 178, 1, 299520, 0x95e058ab
-0, 179, 179, 1, 299520, 0x8de2438a
-0, 180, 180, 1, 299520, 0xf43dc0ff
-0, 181, 181, 1, 299520, 0xaf232f4b
-0, 182, 182, 1, 299520, 0x8adabd81
-0, 183, 183, 1, 299520, 0x1e837b72
-0, 184, 184, 1, 299520, 0xb79f811d
-0, 185, 185, 1, 299520, 0x1532fb05
-0, 186, 186, 1, 299520, 0x2e3f6341
-0, 187, 187, 1, 299520, 0x10c82269
-0, 188, 188, 1, 299520, 0x8c39bd0c
-0, 189, 189, 1, 299520, 0x64fefe7b
-0, 190, 190, 1, 299520, 0x3ef6d5c7
-0, 191, 191, 1, 299520, 0x571c1edc
-0, 192, 192, 1, 299520, 0xe9e1584c
-0, 193, 193, 1, 299520, 0xd150a0db
-0, 194, 194, 1, 299520, 0x5d140f2d
-0, 195, 195, 1, 299520, 0xea00f302
-0, 196, 196, 1, 299520, 0xdd4e0fc4
-0, 197, 197, 1, 299520, 0x51c760fa
-0, 198, 198, 1, 299520, 0x68d5d26e
-0, 199, 199, 1, 299520, 0xde594a02
-0, 200, 200, 1, 299520, 0xac6d361a
-0, 201, 201, 1, 299520, 0xef6506ae
-0, 202, 202, 1, 299520, 0x744737a8
-0, 203, 203, 1, 299520, 0x2bd0834b
-0, 204, 204, 1, 299520, 0x348a8d0f
-0, 205, 205, 1, 299520, 0x93e165c8
-0, 206, 206, 1, 299520, 0x208d305c
-0, 207, 207, 1, 299520, 0xb927ed9a
-0, 208, 208, 1, 299520, 0xd252b13a
-0, 209, 209, 1, 299520, 0x11a59b2d
-0, 210, 210, 1, 299520, 0xc27785d0
-0, 211, 211, 1, 299520, 0x5c654cb5
-0, 212, 212, 1, 299520, 0x3d03a387
-0, 213, 213, 1, 299520, 0xdb0dc19d
-0, 214, 214, 1, 299520, 0x2ef3bbba
-0, 215, 215, 1, 299520, 0x7d36cd79
-0, 216, 216, 1, 299520, 0xa9ceca1e
-0, 217, 217, 1, 299520, 0x33db4d99
-0, 218, 218, 1, 299520, 0x8d28a55e
-0, 219, 219, 1, 299520, 0x554864a6
-0, 220, 220, 1, 299520, 0x6a336557
-0, 221, 221, 1, 299520, 0xd2285832
-0, 222, 222, 1, 299520, 0x9509f5f8
-0, 223, 223, 1, 299520, 0x8e479b03
-0, 224, 224, 1, 299520, 0x9513a8c3
-0, 225, 225, 1, 299520, 0x81080fac
-0, 226, 226, 1, 299520, 0x6c447b69
-0, 227, 227, 1, 299520, 0xbf4c2fbd
-0, 228, 228, 1, 299520, 0x1a77306e
-0, 229, 229, 1, 299520, 0xd485864b
-0, 230, 230, 1, 299520, 0x4e87b787
-0, 231, 231, 1, 299520, 0xe28e7153
-0, 232, 232, 1, 299520, 0x2ab24b9b
-0, 233, 233, 1, 299520, 0xffcb7357
-0, 234, 234, 1, 299520, 0x5e1e2b7e
-0, 235, 235, 1, 299520, 0x58d39e6d
-0, 236, 236, 1, 299520, 0x4a2b836a
-0, 237, 237, 1, 299520, 0xa1728e1e
-0, 238, 238, 1, 299520, 0x33e5bdd4
-0, 239, 239, 1, 299520, 0x3b144d98
-0, 240, 240, 1, 299520, 0xe72c4de2
-0, 241, 241, 1, 299520, 0x031350cb
-0, 242, 242, 1, 299520, 0x146fba58
-0, 243, 243, 1, 299520, 0x1b6679c7
-0, 244, 244, 1, 299520, 0x27e9d545
-0, 245, 245, 1, 299520, 0x5105beeb
-0, 246, 246, 1, 299520, 0x80284fd3
-0, 247, 247, 1, 299520, 0x426a5d65
-0, 248, 248, 1, 299520, 0xdcc33f89
-0, 249, 249, 1, 299520, 0x29e805ec
-0, 250, 250, 1, 299520, 0x89a09ed9
-0, 251, 251, 1, 299520, 0x60ad258c
-0, 252, 252, 1, 299520, 0xb44ee9b1
-0, 253, 253, 1, 299520, 0x184d6a88
-0, 254, 254, 1, 299520, 0xb4c8cefe
-0, 255, 255, 1, 299520, 0x358a0407
-0, 256, 256, 1, 299520, 0xa5cb97eb
-0, 257, 257, 1, 299520, 0x3d6a096e
-0, 258, 258, 1, 299520, 0xcb266e78
+0, 1, 1, 1, 299520, 0x54e6ef0a
+0, 2, 2, 1, 299520, 0x7a4d46c5
+0, 3, 3, 1, 299520, 0xccd57f4e
+0, 4, 4, 1, 299520, 0xbe0cb48d
+0, 5, 5, 1, 299520, 0x10e7b49f
+0, 6, 6, 1, 299520, 0x81aa72e2
+0, 7, 7, 1, 299520, 0x5bf7b51f
+0, 8, 8, 1, 299520, 0xfcedee4a
+0, 9, 9, 1, 299520, 0x586c99b6
+0, 10, 10, 1, 299520, 0x414ca13c
+0, 11, 11, 1, 299520, 0x3f0162f2
+0, 12, 12, 1, 299520, 0x4d450c05
+0, 13, 13, 1, 299520, 0x0a58bd84
+0, 14, 14, 1, 299520, 0x26e8394d
+0, 15, 15, 1, 299520, 0xfd78121b
+0, 16, 16, 1, 299520, 0x6afeaf44
+0, 17, 17, 1, 299520, 0x3e9a9270
+0, 18, 18, 1, 299520, 0x58b889ca
+0, 19, 19, 1, 299520, 0x0245ba62
+0, 20, 20, 1, 299520, 0xddecc5ab
+0, 21, 21, 1, 299520, 0x32cf3cd9
+0, 22, 22, 1, 299520, 0x5c0a0440
+0, 23, 23, 1, 299520, 0x9d3e2fee
+0, 24, 24, 1, 299520, 0x2894c708
+0, 25, 25, 1, 299520, 0x25be67d5
+0, 26, 26, 1, 299520, 0xe3ece9d6
+0, 27, 27, 1, 299520, 0xcc98e38b
+0, 28, 28, 1, 299520, 0xc448c794
+0, 29, 29, 1, 299520, 0xb4f75575
+0, 30, 30, 1, 299520, 0xac74a437
+0, 31, 31, 1, 299520, 0x09c7f2e2
+0, 32, 32, 1, 299520, 0xbfaed8ab
+0, 33, 33, 1, 299520, 0xb077d700
+0, 34, 34, 1, 299520, 0x6efa0545
+0, 35, 35, 1, 299520, 0xb8c1802d
+0, 36, 36, 1, 299520, 0x794774f8
+0, 37, 37, 1, 299520, 0x1098f4ff
+0, 38, 38, 1, 299520, 0x80ab8bfc
+0, 39, 39, 1, 299520, 0xc324c3bc
+0, 40, 40, 1, 299520, 0x1eee77cd
+0, 41, 41, 1, 299520, 0x7147e72e
+0, 42, 42, 1, 299520, 0x1a34883c
+0, 43, 43, 1, 299520, 0x74e93e31
+0, 44, 44, 1, 299520, 0x89410382
+0, 45, 45, 1, 299520, 0xfcce0ce1
+0, 46, 46, 1, 299520, 0x07bb33c6
+0, 47, 47, 1, 299520, 0xc1ee7318
+0, 48, 48, 1, 299520, 0xd1c4bd2d
+0, 49, 49, 1, 299520, 0xa670cfae
+0, 50, 50, 1, 299520, 0x718de79b
+0, 51, 51, 1, 299520, 0x85e40b78
+0, 52, 52, 1, 299520, 0x15362e72
+0, 53, 53, 1, 299520, 0xc6e523fa
+0, 54, 54, 1, 299520, 0x3e536edd
+0, 55, 55, 1, 299520, 0x9312996e
+0, 56, 56, 1, 299520, 0x9456d53c
+0, 57, 57, 1, 299520, 0x7bc01398
+0, 58, 58, 1, 299520, 0x5a40bcb4
+0, 59, 59, 1, 299520, 0xcfe126ce
+0, 60, 60, 1, 299520, 0xd9e1adf1
+0, 61, 61, 1, 299520, 0x9027b1ae
+0, 62, 62, 1, 299520, 0x4c1372fb
+0, 63, 63, 1, 299520, 0xe475a00b
+0, 64, 64, 1, 299520, 0x945bc646
+0, 65, 65, 1, 299520, 0xc33dbab3
+0, 66, 66, 1, 299520, 0x9e4afb82
+0, 67, 67, 1, 299520, 0x1bffa858
+0, 68, 68, 1, 299520, 0x3bc78ad7
+0, 69, 69, 1, 299520, 0xa096e683
+0, 70, 70, 1, 299520, 0xb889aa23
+0, 71, 71, 1, 299520, 0x8ffad857
+0, 72, 72, 1, 299520, 0x59d3cc7c
+0, 73, 73, 1, 299520, 0x47d1377a
+0, 74, 74, 1, 299520, 0xea73e864
+0, 75, 75, 1, 299520, 0x0994bd5c
+0, 76, 76, 1, 299520, 0xdf779d85
+0, 77, 77, 1, 299520, 0x8238cfa7
+0, 78, 78, 1, 299520, 0x8f2e94cc
+0, 79, 79, 1, 299520, 0x9e0b0df8
+0, 80, 80, 1, 299520, 0x98ac1ce5
+0, 81, 81, 1, 299520, 0xc1c293ed
+0, 82, 82, 1, 299520, 0x1f1dfedb
+0, 83, 83, 1, 299520, 0xe7297d56
+0, 84, 84, 1, 299520, 0xa1390726
+0, 85, 85, 1, 299520, 0xf0e828e8
+0, 86, 86, 1, 299520, 0x108b8291
+0, 87, 87, 1, 299520, 0xd8830efb
+0, 88, 88, 1, 299520, 0xeee3d2f0
+0, 89, 89, 1, 299520, 0xa35d5b29
+0, 90, 90, 1, 299520, 0xa14d0840
+0, 91, 91, 1, 299520, 0xfa894a56
+0, 92, 92, 1, 299520, 0xd50005b5
+0, 93, 93, 1, 299520, 0xba625134
+0, 94, 94, 1, 299520, 0xce7dd782
+0, 95, 95, 1, 299520, 0x9e04e32f
+0, 96, 96, 1, 299520, 0x07e6d466
+0, 97, 97, 1, 299520, 0x4e66e1d4
+0, 98, 98, 1, 299520, 0x80aa6be6
+0, 99, 99, 1, 299520, 0xa4564be8
+0, 100, 100, 1, 299520, 0x7d34e443
+0, 101, 101, 1, 299520, 0xd5a08c86
+0, 102, 102, 1, 299520, 0xa73e63e8
+0, 103, 103, 1, 299520, 0x93937eb2
+0, 104, 104, 1, 299520, 0x0c08ba8f
+0, 105, 105, 1, 299520, 0x1d6b1a8c
+0, 106, 106, 1, 299520, 0x2e0272b4
+0, 107, 107, 1, 299520, 0x47177676
+0, 108, 108, 1, 299520, 0x6af7ffce
+0, 109, 109, 1, 299520, 0x0564a4bc
+0, 110, 110, 1, 299520, 0x7f664100
+0, 111, 111, 1, 299520, 0x6decd6ae
+0, 112, 112, 1, 299520, 0xb2d94adc
+0, 113, 113, 1, 299520, 0x55d33809
+0, 114, 114, 1, 299520, 0x5b126674
+0, 115, 115, 1, 299520, 0xd25d5750
+0, 116, 116, 1, 299520, 0x789a7f89
+0, 117, 117, 1, 299520, 0xdd082ab2
+0, 118, 118, 1, 299520, 0x3e6132ee
+0, 119, 119, 1, 299520, 0xe48209ca
+0, 120, 120, 1, 299520, 0x707d3b24
+0, 121, 121, 1, 299520, 0x8af19539
+0, 122, 122, 1, 299520, 0x0bbb4c38
+0, 123, 123, 1, 299520, 0xaaba4bd6
+0, 124, 124, 1, 299520, 0xa325d79e
+0, 125, 125, 1, 299520, 0x2bd4b64a
+0, 126, 126, 1, 299520, 0xab0c59a7
+0, 127, 127, 1, 299520, 0x260a56fc
+0, 128, 128, 1, 299520, 0xa1a55847
+0, 129, 129, 1, 299520, 0xa1a55847
+0, 130, 130, 1, 299520, 0x01438514
+0, 131, 131, 1, 299520, 0xa511e8bd
+0, 132, 132, 1, 299520, 0x7ebfd5b9
+0, 133, 133, 1, 299520, 0xdf4f1365
+0, 134, 134, 1, 299520, 0x6266911a
+0, 135, 135, 1, 299520, 0xe8eefcab
+0, 136, 136, 1, 299520, 0x7e74ca0d
+0, 137, 137, 1, 299520, 0x4b21d349
+0, 138, 138, 1, 299520, 0xa8b9ef41
+0, 139, 139, 1, 299520, 0x3187ee5b
+0, 140, 140, 1, 299520, 0x3fadb935
+0, 141, 141, 1, 299520, 0x8dca0391
+0, 142, 142, 1, 299520, 0x68215cc6
+0, 143, 143, 1, 299520, 0x7c81f366
+0, 144, 144, 1, 299520, 0x1a976381
+0, 145, 145, 1, 299520, 0x8ac095f4
+0, 146, 146, 1, 299520, 0xf5f8752b
+0, 147, 147, 1, 299520, 0xd8c03c80
+0, 148, 148, 1, 299520, 0x445a2e07
+0, 149, 149, 1, 299520, 0xddb83c6f
+0, 150, 150, 1, 299520, 0xc6dfe76a
+0, 151, 151, 1, 299520, 0x860a120f
+0, 152, 152, 1, 299520, 0x1ec91a95
+0, 153, 153, 1, 299520, 0x0180cc49
+0, 154, 154, 1, 299520, 0x63a115e3
+0, 155, 155, 1, 299520, 0x8848e971
+0, 156, 156, 1, 299520, 0x49246622
+0, 157, 157, 1, 299520, 0x3169db32
+0, 158, 158, 1, 299520, 0xcf01d8a3
+0, 159, 159, 1, 299520, 0x57a1a9c1
+0, 160, 160, 1, 299520, 0x517670eb
+0, 161, 161, 1, 299520, 0x4e2e6b5a
+0, 162, 162, 1, 299520, 0x06240a68
+0, 163, 163, 1, 299520, 0xa0d076a1
+0, 164, 164, 1, 299520, 0xb73c4515
+0, 165, 165, 1, 299520, 0x9f523268
+0, 166, 166, 1, 299520, 0x6fdcc6a2
+0, 167, 167, 1, 299520, 0xf3f5b69f
+0, 168, 168, 1, 299520, 0xce33a286
+0, 169, 169, 1, 299520, 0xce46e834
+0, 170, 170, 1, 299520, 0x14a6fe0d
+0, 171, 171, 1, 299520, 0x39a8145f
+0, 172, 172, 1, 299520, 0x91981d47
+0, 173, 173, 1, 299520, 0x1507d9be
+0, 174, 174, 1, 299520, 0x4525d4a2
+0, 175, 175, 1, 299520, 0x95e058ab
+0, 176, 176, 1, 299520, 0x8de2438a
+0, 177, 177, 1, 299520, 0xf43dc0ff
+0, 178, 178, 1, 299520, 0xaf232f4b
+0, 179, 179, 1, 299520, 0x8adabd81
+0, 180, 180, 1, 299520, 0x1e837b72
+0, 181, 181, 1, 299520, 0xb79f811d
+0, 182, 182, 1, 299520, 0x1532fb05
+0, 183, 183, 1, 299520, 0x2e3f6341
+0, 184, 184, 1, 299520, 0x10c82269
+0, 185, 185, 1, 299520, 0x8c39bd0c
+0, 186, 186, 1, 299520, 0x64fefe7b
+0, 187, 187, 1, 299520, 0x3ef6d5c7
+0, 188, 188, 1, 299520, 0x571c1edc
+0, 189, 189, 1, 299520, 0xe9e1584c
+0, 190, 190, 1, 299520, 0xd150a0db
+0, 191, 191, 1, 299520, 0x5d140f2d
+0, 192, 192, 1, 299520, 0xea00f302
+0, 193, 193, 1, 299520, 0xdd4e0fc4
+0, 194, 194, 1, 299520, 0x51c760fa
+0, 195, 195, 1, 299520, 0x68d5d26e
+0, 196, 196, 1, 299520, 0xde594a02
+0, 197, 197, 1, 299520, 0xac6d361a
+0, 198, 198, 1, 299520, 0xef6506ae
+0, 199, 199, 1, 299520, 0x744737a8
+0, 200, 200, 1, 299520, 0x2bd0834b
+0, 201, 201, 1, 299520, 0x348a8d0f
+0, 202, 202, 1, 299520, 0x93e165c8
+0, 203, 203, 1, 299520, 0x208d305c
+0, 204, 204, 1, 299520, 0xb927ed9a
+0, 205, 205, 1, 299520, 0xd252b13a
+0, 206, 206, 1, 299520, 0x11a59b2d
+0, 207, 207, 1, 299520, 0xc27785d0
+0, 208, 208, 1, 299520, 0x5c654cb5
+0, 209, 209, 1, 299520, 0x3d03a387
+0, 210, 210, 1, 299520, 0xdb0dc19d
+0, 211, 211, 1, 299520, 0x2ef3bbba
+0, 212, 212, 1, 299520, 0x7d36cd79
+0, 213, 213, 1, 299520, 0xa9ceca1e
+0, 214, 214, 1, 299520, 0x33db4d99
+0, 215, 215, 1, 299520, 0x8d28a55e
+0, 216, 216, 1, 299520, 0x554864a6
+0, 217, 217, 1, 299520, 0x6a336557
+0, 218, 218, 1, 299520, 0xd2285832
+0, 219, 219, 1, 299520, 0x9509f5f8
+0, 220, 220, 1, 299520, 0x8e479b03
+0, 221, 221, 1, 299520, 0x9513a8c3
+0, 222, 222, 1, 299520, 0x81080fac
+0, 223, 223, 1, 299520, 0x6c447b69
+0, 224, 224, 1, 299520, 0xbf4c2fbd
+0, 225, 225, 1, 299520, 0x1a77306e
+0, 226, 226, 1, 299520, 0xd485864b
+0, 227, 227, 1, 299520, 0x4e87b787
+0, 228, 228, 1, 299520, 0xe28e7153
+0, 229, 229, 1, 299520, 0x2ab24b9b
+0, 230, 230, 1, 299520, 0xffcb7357
+0, 231, 231, 1, 299520, 0x5e1e2b7e
+0, 232, 232, 1, 299520, 0x58d39e6d
+0, 233, 233, 1, 299520, 0x4a2b836a
+0, 234, 234, 1, 299520, 0xa1728e1e
+0, 235, 235, 1, 299520, 0x33e5bdd4
+0, 236, 236, 1, 299520, 0x3b144d98
+0, 237, 237, 1, 299520, 0xe72c4de2
+0, 238, 238, 1, 299520, 0x031350cb
+0, 239, 239, 1, 299520, 0x146fba58
+0, 240, 240, 1, 299520, 0x1b6679c7
+0, 241, 241, 1, 299520, 0x27e9d545
+0, 242, 242, 1, 299520, 0x5105beeb
+0, 243, 243, 1, 299520, 0x80284fd3
+0, 244, 244, 1, 299520, 0x426a5d65
+0, 245, 245, 1, 299520, 0xdcc33f89
+0, 246, 246, 1, 299520, 0x29e805ec
+0, 247, 247, 1, 299520, 0x89a09ed9
+0, 248, 248, 1, 299520, 0x60ad258c
+0, 249, 249, 1, 299520, 0xb44ee9b1
+0, 250, 250, 1, 299520, 0x184d6a88
+0, 251, 251, 1, 299520, 0xb4c8cefe
+0, 252, 252, 1, 299520, 0x358a0407
+0, 253, 253, 1, 299520, 0xa5cb97eb
+0, 254, 254, 1, 299520, 0x3d6a096e
+0, 255, 255, 1, 299520, 0xcb266e78
diff --git a/tests/ref/fate/hevc-paramchange-yuv420p-yuv420p10 b/tests/ref/fate/hevc-paramchange-yuv420p-yuv420p10
index 16a6a3c586..f3cd550a71 100644
--- a/tests/ref/fate/hevc-paramchange-yuv420p-yuv420p10
+++ b/tests/ref/fate/hevc-paramchange-yuv420p-yuv420p10
@@ -9,259 +9,259 @@
0, 7, 7, 1, 13368960, 0x7832ef4e
0, 8, 8, 1, 13368960, 0x328142e9
0, 9, 9, 1, 13368960, 0xbe22f686
-0, 10, 10, 1, 13368960, 0xfdf78a41
-0, 11, 11, 1, 13368960, 0x8ea3a29e
-0, 12, 12, 1, 13368960, 0x10fc932f
-0, 13, 13, 1, 13368960, 0xaea485ff
-0, 14, 14, 1, 13368960, 0xd545d3c9
-0, 15, 15, 1, 13368960, 0x285d23be
-0, 16, 16, 1, 13368960, 0x21453f6a
-0, 17, 17, 1, 13368960, 0xc997240e
-0, 18, 18, 1, 13368960, 0xe4a6a4c9
-0, 19, 19, 1, 13368960, 0x645a04f4
-0, 20, 20, 1, 13368960, 0xf0868e8d
-0, 21, 21, 1, 13368960, 0x53e93a3c
-0, 22, 22, 1, 13368960, 0x9d0bf5c0
-0, 23, 23, 1, 13368960, 0xcff5f416
-0, 24, 24, 1, 13368960, 0xd30bf22e
-0, 25, 25, 1, 13368960, 0x9db94f89
-0, 26, 26, 1, 13368960, 0x32549fde
-0, 27, 27, 1, 13368960, 0xf842679a
-0, 28, 28, 1, 13368960, 0x057b893b
-0, 29, 29, 1, 13368960, 0x10308d96
-0, 30, 30, 1, 13368960, 0x2b92ad92
-0, 31, 31, 1, 13368960, 0xfaef4689
-0, 32, 32, 1, 13368960, 0x0d49ccb3
-0, 33, 33, 1, 13368960, 0x927f9fbf
-0, 34, 34, 1, 13368960, 0x424001ca
-0, 35, 35, 1, 13368960, 0x08651f52
-0, 36, 36, 1, 13368960, 0x95a60717
-0, 37, 37, 1, 13368960, 0x9571a4fc
-0, 38, 38, 1, 13368960, 0x958b479a
-0, 39, 39, 1, 13368960, 0xa93d2034
-0, 40, 40, 1, 13368960, 0x63568237
-0, 41, 41, 1, 13368960, 0x101fcc08
-0, 42, 42, 1, 13368960, 0xb4cd30ae
-0, 43, 43, 1, 13368960, 0x6b16a36e
-0, 44, 44, 1, 13368960, 0x16f462ba
-0, 45, 45, 1, 13368960, 0xfc6f6a4d
-0, 46, 46, 1, 13368960, 0x5801d227
-0, 47, 47, 1, 13368960, 0x4af661ba
-0, 48, 48, 1, 13368960, 0xb3f78825
-0, 49, 49, 1, 13368960, 0xccc5e616
-0, 50, 50, 1, 13368960, 0xf574dd62
-0, 51, 51, 1, 13368960, 0x5f82af98
-0, 52, 52, 1, 13368960, 0xe63f2bcf
-0, 53, 53, 1, 13368960, 0x407d7ee1
-0, 54, 54, 1, 13368960, 0xbdb7eeba
-0, 55, 55, 1, 13368960, 0x37c001c5
-0, 56, 56, 1, 13368960, 0x619414d1
-0, 57, 57, 1, 13368960, 0x82f8cf67
-0, 58, 58, 1, 13368960, 0x464ac4f3
-0, 59, 59, 1, 13368960, 0x78f9991a
-0, 60, 60, 1, 13368960, 0xeeddba5b
-0, 61, 61, 1, 13368960, 0x9426f039
-0, 62, 62, 1, 13368960, 0x2b418600
-0, 63, 63, 1, 13368960, 0xfc41210c
-0, 64, 64, 1, 13368960, 0xa191b118
-0, 65, 65, 1, 13368960, 0x9a3dec6a
-0, 66, 66, 1, 13368960, 0xd8e8b55a
-0, 67, 67, 1, 13368960, 0xb45b815a
-0, 68, 68, 1, 13368960, 0x86a91143
-0, 69, 69, 1, 13368960, 0x2b03221b
-0, 70, 70, 1, 13368960, 0x78aba843
-0, 71, 71, 1, 13368960, 0x6fe9268b
-0, 72, 72, 1, 13368960, 0x4ebe6005
-0, 73, 73, 1, 13368960, 0x5a66f82b
-0, 74, 74, 1, 13368960, 0x8a224cc6
-0, 75, 75, 1, 13368960, 0x8a224cc6
-0, 76, 76, 1, 13368960, 0x5a055a2f
-0, 77, 77, 1, 13368960, 0x5a055a2f
-0, 78, 78, 1, 13368960, 0x984ee1a4
-0, 79, 79, 1, 13368960, 0x0d65da82
-0, 80, 80, 1, 13368960, 0xcd7c4226
-0, 81, 81, 1, 13368960, 0x2896614e
-0, 82, 82, 1, 13368960, 0x997ddce1
-0, 83, 83, 1, 13368960, 0x3018e3d9
-0, 84, 84, 1, 13368960, 0xd01cb3bc
-0, 85, 85, 1, 13368960, 0x2f643612
-0, 86, 86, 1, 13368960, 0x23c2dfb3
-0, 87, 87, 1, 13368960, 0x23c2dfb3
-0, 88, 88, 1, 13368960, 0x57d69dd3
-0, 89, 89, 1, 13368960, 0xd270a0ab
-0, 90, 90, 1, 13368960, 0xa24e5c1e
-0, 91, 91, 1, 13368960, 0xc3c047b2
-0, 92, 92, 1, 13368960, 0x5a5b4eaa
-0, 93, 93, 1, 13368960, 0xd32c7a91
-0, 94, 94, 1, 13368960, 0x87ee6217
-0, 95, 95, 1, 13368960, 0xbe1e8641
-0, 96, 96, 1, 13368960, 0x88225cf9
-0, 97, 97, 1, 13368960, 0x41c1b776
-0, 98, 98, 1, 13368960, 0xc7cde7f4
-0, 99, 99, 1, 13368960, 0x31b8ac12
-0, 100, 100, 1, 13368960, 0x6c12322d
-0, 101, 101, 1, 13368960, 0xa3d4a8e4
-0, 102, 102, 1, 13368960, 0x6d62ade8
-0, 103, 103, 1, 13368960, 0x6d62ade8
-0, 104, 104, 1, 13368960, 0x3ede9b6f
-0, 105, 105, 1, 13368960, 0x56924e2b
-0, 106, 106, 1, 13368960, 0x8c25ee45
-0, 107, 107, 1, 13368960, 0xfc2e5e96
-0, 108, 108, 1, 13368960, 0x5fd3c9ce
-0, 109, 109, 1, 13368960, 0x51e9dd4d
-0, 110, 110, 1, 13368960, 0xd7b90558
-0, 111, 111, 1, 13368960, 0xfe185238
-0, 112, 112, 1, 13368960, 0x1be11174
-0, 113, 113, 1, 13368960, 0x16f9a81b
-0, 114, 114, 1, 13368960, 0x8533b2be
-0, 115, 115, 1, 13368960, 0xd8327426
-0, 116, 116, 1, 13368960, 0x7a6f3d80
-0, 117, 117, 1, 13368960, 0xeb879ea8
-0, 118, 118, 1, 13368960, 0x904da2b8
-0, 119, 119, 1, 13368960, 0xeed21ab9
-0, 120, 120, 1, 13368960, 0x9c5cf568
-0, 121, 121, 1, 13368960, 0x0bbe1a28
-0, 122, 122, 1, 13368960, 0xf2604543
-0, 123, 123, 1, 13368960, 0xf3d43846
-0, 124, 124, 1, 13368960, 0x9f768657
-0, 125, 125, 1, 13368960, 0x74b0d261
-0, 126, 126, 1, 13368960, 0x0f08ec8e
-0, 127, 127, 1, 13368960, 0xb77f9cb8
-0, 128, 128, 1, 13368960, 0x696c5bfa
-0, 129, 129, 1, 13368960, 0x4e99ddf6
-0, 130, 130, 1, 13368960, 0x229ecd66
-0, 131, 131, 1, 13368960, 0xd2b322d4
-0, 132, 132, 1, 13368960, 0x83d42180
-0, 133, 133, 1, 13368960, 0xb40d2508
-0, 134, 134, 1, 13368960, 0x35e92fa5
-0, 135, 135, 1, 13368960, 0x5aa2bec9
-0, 136, 136, 1, 13368960, 0x92be5044
-0, 137, 137, 1, 13368960, 0x6ae3f3a2
-0, 138, 138, 1, 13368960, 0xc76e7b05
-0, 139, 139, 1, 13368960, 0xc76e7b05
-0, 140, 140, 1, 13368960, 0xf04961fe
-0, 141, 141, 1, 13368960, 0x44ce69d1
-0, 142, 142, 1, 13368960, 0xf659fb8f
-0, 143, 143, 1, 13368960, 0x365ae456
-0, 144, 144, 1, 13368960, 0xa6dceffc
-0, 145, 145, 1, 13368960, 0x2dd12c22
-0, 146, 146, 1, 13368960, 0xb896e3f3
-0, 147, 147, 1, 13368960, 0xd6615b15
-0, 148, 148, 1, 13368960, 0xc375996b
-0, 149, 149, 1, 13368960, 0x89a06cbf
-0, 150, 150, 1, 13368960, 0x20d54f8b
-0, 151, 151, 1, 13368960, 0x955f4329
-0, 152, 152, 1, 13368960, 0x9c7e3906
-0, 153, 153, 1, 13368960, 0x449a63ea
-0, 154, 154, 1, 13368960, 0x62431d75
-0, 155, 155, 1, 13368960, 0xac52d9f3
-0, 156, 156, 1, 13368960, 0x57bef208
-0, 157, 157, 1, 13368960, 0x32f604d5
-0, 158, 158, 1, 13368960, 0x55b679c9
-0, 159, 159, 1, 13368960, 0x2003c55d
-0, 160, 160, 1, 13368960, 0x0e8d0111
-0, 161, 161, 1, 13368960, 0x4876f64d
-0, 162, 162, 1, 13368960, 0x44514a09
-0, 163, 163, 1, 13368960, 0x7ce81efd
-0, 164, 164, 1, 13368960, 0x2af740ab
-0, 165, 165, 1, 13368960, 0xbc52dca2
-0, 166, 166, 1, 13368960, 0x9ba679e2
-0, 167, 167, 1, 13368960, 0x4e9195e1
-0, 168, 168, 1, 13368960, 0x5078ae80
-0, 169, 169, 1, 13368960, 0xab823be0
-0, 170, 170, 1, 13368960, 0xc45a011e
-0, 171, 171, 1, 13368960, 0xb0a0beaf
-0, 172, 172, 1, 13368960, 0x0f1169a6
-0, 173, 173, 1, 13368960, 0x56d53564
-0, 174, 174, 1, 13368960, 0x93874837
-0, 175, 175, 1, 13368960, 0x2e4c3acf
-0, 176, 176, 1, 13368960, 0xf51f5beb
-0, 177, 177, 1, 13368960, 0x5ffffae0
-0, 178, 178, 1, 13368960, 0x3b1a3df9
-0, 179, 179, 1, 13368960, 0xfecd52e1
-0, 180, 180, 1, 13368960, 0xc84ec5c6
-0, 181, 181, 1, 13368960, 0xd033a6b4
-0, 182, 182, 1, 13368960, 0x18230ce6
-0, 183, 183, 1, 13368960, 0xa240d858
-0, 184, 184, 1, 13368960, 0x058d32ec
-0, 185, 185, 1, 13368960, 0x46e81bad
-0, 186, 186, 1, 13368960, 0x78a89b7d
-0, 187, 187, 1, 13368960, 0xf9a0b94e
-0, 188, 188, 1, 13368960, 0x34fdd579
-0, 189, 189, 1, 13368960, 0xd58f5aa2
-0, 190, 190, 1, 13368960, 0x4d957a13
-0, 191, 191, 1, 13368960, 0x0b233f2c
-0, 192, 192, 1, 13368960, 0xcc5471d5
-0, 193, 193, 1, 13368960, 0xcc5471d5
-0, 194, 194, 1, 13368960, 0xddccf2ea
-0, 195, 195, 1, 13368960, 0xddccf2ea
-0, 196, 196, 1, 13368960, 0x38290ed9
-0, 197, 197, 1, 13368960, 0x095f6f3a
-0, 198, 198, 1, 13368960, 0xe4c70f9f
-0, 199, 199, 1, 13368960, 0x695cd27d
-0, 200, 200, 1, 13368960, 0x98a15fcb
-0, 201, 201, 1, 13368960, 0x22a37600
-0, 202, 202, 1, 13368960, 0xa7bc5ddf
-0, 203, 203, 1, 13368960, 0x63778def
-0, 204, 204, 1, 13368960, 0xa7bc5ddf
-0, 205, 205, 1, 13368960, 0xcce44a22
-0, 206, 206, 1, 13368960, 0xe9e1e769
-0, 207, 207, 1, 13368960, 0x05c652e7
-0, 208, 208, 1, 13368960, 0xc075c9b0
-0, 209, 209, 1, 13368960, 0x6d674c85
-0, 210, 210, 1, 13368960, 0x57938439
-0, 211, 211, 1, 13368960, 0x28296abd
-0, 212, 212, 1, 13368960, 0xc29bd537
-0, 213, 213, 1, 13368960, 0xbb01f326
-0, 214, 214, 1, 13368960, 0x68f9366d
-0, 215, 215, 1, 13368960, 0x3b8f6d9a
-0, 216, 216, 1, 13368960, 0x26db944e
-0, 217, 217, 1, 13368960, 0x2f975635
-0, 218, 218, 1, 13368960, 0x4f8d15a2
-0, 219, 219, 1, 13368960, 0x3b773121
-0, 220, 220, 1, 13368960, 0x0e502331
-0, 221, 221, 1, 13368960, 0xffe3a0e9
-0, 222, 222, 1, 13368960, 0x443fa9fb
-0, 223, 223, 1, 13368960, 0xdc592fd0
-0, 224, 224, 1, 13368960, 0x88f537a3
-0, 225, 225, 1, 13368960, 0x99216d73
-0, 226, 226, 1, 13368960, 0x4809af2c
-0, 227, 227, 1, 13368960, 0x2dd56e6a
-0, 228, 228, 1, 13368960, 0x674cc602
-0, 229, 229, 1, 13368960, 0x08685038
-0, 230, 230, 1, 13368960, 0x4b4219f3
-0, 231, 231, 1, 13368960, 0xb850e27c
-0, 232, 232, 1, 13368960, 0xe3aca387
-0, 233, 233, 1, 13368960, 0x11c50e02
-0, 234, 234, 1, 13368960, 0xa14f9a7f
-0, 235, 235, 1, 13368960, 0x2407abdd
-0, 236, 236, 1, 13368960, 0xbe8cc86b
-0, 237, 237, 1, 13368960, 0x53f539b4
-0, 238, 238, 1, 13368960, 0x0d4c359c
-0, 239, 239, 1, 13368960, 0x3ed14dad
-0, 240, 240, 1, 13368960, 0xf4676505
-0, 241, 241, 1, 13368960, 0x6dade6bf
-0, 242, 242, 1, 13368960, 0x4390f1fa
-0, 243, 243, 1, 13368960, 0xd4ffd518
-0, 244, 244, 1, 13368960, 0x933b9c20
-0, 245, 245, 1, 13368960, 0xe586663a
-0, 246, 246, 1, 13368960, 0x4b3f1e0f
-0, 247, 247, 1, 13368960, 0xe99668e1
-0, 248, 248, 1, 13368960, 0x4967157b
-0, 249, 249, 1, 13368960, 0x443314db
-0, 250, 250, 1, 13368960, 0x83023744
-0, 251, 251, 1, 13368960, 0x35e8b4da
-0, 252, 252, 1, 13368960, 0xc2eeb60d
-0, 253, 253, 1, 13368960, 0x2df97afe
-0, 254, 254, 1, 13368960, 0x4f9eeab8
-0, 255, 255, 1, 13368960, 0x5cfa523d
-0, 256, 256, 1, 13368960, 0x4badc6b8
-0, 257, 257, 1, 13368960, 0xaa801786
-0, 258, 258, 1, 13368960, 0xca282526
-0, 259, 259, 1, 13368960, 0x3a93f0cc
-0, 260, 260, 1, 13368960, 0x290e550c
-0, 261, 261, 1, 13368960, 0x29a015d8
-0, 262, 262, 1, 13368960, 0x4e2f73d6
-0, 263, 263, 1, 13368960, 0xfa87495c
-0, 264, 264, 1, 13368960, 0xaca638a5
-0, 265, 265, 1, 13368960, 0xef22830f
+0, 10, 10, 1, 13368960, 0x9c4bc207
+0, 11, 11, 1, 13368960, 0x3c5ed3a8
+0, 12, 12, 1, 13368960, 0x2bbad24b
+0, 13, 13, 1, 13368960, 0x1673c4d9
+0, 14, 14, 1, 13368960, 0x2091113f
+0, 15, 15, 1, 13368960, 0xcf6d4fbc
+0, 16, 16, 1, 13368960, 0xd6568883
+0, 17, 17, 1, 13368960, 0xb28f6a46
+0, 18, 18, 1, 13368960, 0x2194e8aa
+0, 19, 19, 1, 13368960, 0xcf9c48ce
+0, 20, 20, 1, 13368960, 0xfc38b71e
+0, 21, 21, 1, 13368960, 0x95497860
+0, 22, 22, 1, 13368960, 0x18d43b46
+0, 23, 23, 1, 13368960, 0xb9e03612
+0, 24, 24, 1, 13368960, 0x0df619fa
+0, 25, 25, 1, 13368960, 0x941c823f
+0, 26, 26, 1, 13368960, 0x4df9ed34
+0, 27, 27, 1, 13368960, 0x6f09aec5
+0, 28, 28, 1, 13368960, 0x03dfcbb1
+0, 29, 29, 1, 13368960, 0x4a64c338
+0, 30, 30, 1, 13368960, 0xd33cf17a
+0, 31, 31, 1, 13368960, 0xc1a38b1b
+0, 32, 32, 1, 13368960, 0x38571158
+0, 33, 33, 1, 13368960, 0x1979e549
+0, 34, 34, 1, 13368960, 0x0c1f42e6
+0, 35, 35, 1, 13368960, 0x589267c1
+0, 36, 36, 1, 13368960, 0x77643e84
+0, 37, 37, 1, 13368960, 0x0b91e89c
+0, 38, 38, 1, 13368960, 0x5a627dc6
+0, 39, 39, 1, 13368960, 0xb1576053
+0, 40, 40, 1, 13368960, 0x9adbc4a1
+0, 41, 41, 1, 13368960, 0x4f6b0f4f
+0, 42, 42, 1, 13368960, 0x70bb7560
+0, 43, 43, 1, 13368960, 0x8c5de89e
+0, 44, 44, 1, 13368960, 0x3268ad70
+0, 45, 45, 1, 13368960, 0xef3caed4
+0, 46, 46, 1, 13368960, 0x71f817b9
+0, 47, 47, 1, 13368960, 0x645da999
+0, 48, 48, 1, 13368960, 0x928ecfad
+0, 49, 49, 1, 13368960, 0xb0d92ec8
+0, 50, 50, 1, 13368960, 0x165927df
+0, 51, 51, 1, 13368960, 0x08fffeed
+0, 52, 52, 1, 13368960, 0xae5b6e67
+0, 53, 53, 1, 13368960, 0x9865c501
+0, 54, 54, 1, 13368960, 0x7ffe38dd
+0, 55, 55, 1, 13368960, 0x27494a3d
+0, 56, 56, 1, 13368960, 0x4bd65d63
+0, 57, 57, 1, 13368960, 0x740c1991
+0, 58, 58, 1, 13368960, 0xc4dd13a5
+0, 59, 59, 1, 13368960, 0xda00e57e
+0, 60, 60, 1, 13368960, 0x49dd07ed
+0, 61, 61, 1, 13368960, 0x0abd3d38
+0, 62, 62, 1, 13368960, 0x5e4dd6c1
+0, 63, 63, 1, 13368960, 0x8003709b
+0, 64, 64, 1, 13368960, 0xc6890279
+0, 65, 65, 1, 13368960, 0x19873cc1
+0, 66, 66, 1, 13368960, 0x4b200ba0
+0, 67, 67, 1, 13368960, 0x4a1cd324
+0, 68, 68, 1, 13368960, 0x0c3067bd
+0, 69, 69, 1, 13368960, 0x8aaa7653
+0, 70, 70, 1, 13368960, 0xf80e0b5b
+0, 71, 71, 1, 13368960, 0x8b3994a7
+0, 72, 72, 1, 13368960, 0x9283add5
+0, 73, 73, 1, 13368960, 0x84c65370
+0, 74, 74, 1, 13368960, 0x861eb66f
+0, 75, 75, 1, 13368960, 0x861eb66f
+0, 76, 76, 1, 13368960, 0xb345c45f
+0, 77, 77, 1, 13368960, 0xb345c45f
+0, 78, 78, 1, 13368960, 0x610a4127
+0, 79, 79, 1, 13368960, 0x80243f40
+0, 80, 80, 1, 13368960, 0xf4759cb7
+0, 81, 81, 1, 13368960, 0x6590bcb9
+0, 82, 82, 1, 13368960, 0xccda37ba
+0, 83, 83, 1, 13368960, 0x63753eb2
+0, 84, 84, 1, 13368960, 0x6c9f0d49
+0, 85, 85, 1, 13368960, 0x65c8760b
+0, 86, 86, 1, 13368960, 0xf67331ae
+0, 87, 87, 1, 13368960, 0xf67331ae
+0, 88, 88, 1, 13368960, 0x04e4f2cf
+0, 89, 89, 1, 13368960, 0xce3bf739
+0, 90, 90, 1, 13368960, 0x37dfaf28
+0, 91, 91, 1, 13368960, 0x66439ac4
+0, 92, 92, 1, 13368960, 0xfccfa1bc
+0, 93, 93, 1, 13368960, 0x5bdfc263
+0, 94, 94, 1, 13368960, 0x65c4c237
+0, 95, 95, 1, 13368960, 0x17aad32b
+0, 96, 96, 1, 13368960, 0xa8dba25c
+0, 97, 97, 1, 13368960, 0x26c6fc9d
+0, 98, 98, 1, 13368960, 0x7e8b4357
+0, 99, 99, 1, 13368960, 0x1bb60730
+0, 100, 100, 1, 13368960, 0x7fa37b25
+0, 101, 101, 1, 13368960, 0xacc7fcf2
+0, 102, 102, 1, 13368960, 0x06a9f637
+0, 103, 103, 1, 13368960, 0x06a9f637
+0, 104, 104, 1, 13368960, 0xd875e692
+0, 105, 105, 1, 13368960, 0x6e4b9e1d
+0, 106, 106, 1, 13368960, 0x58cb3e45
+0, 107, 107, 1, 13368960, 0x9c5daea2
+0, 108, 108, 1, 13368960, 0x78d01454
+0, 109, 109, 1, 13368960, 0xd2122531
+0, 110, 110, 1, 13368960, 0xaf115288
+0, 111, 111, 1, 13368960, 0x17b09d6e
+0, 112, 112, 1, 13368960, 0xc7335c78
+0, 113, 113, 1, 13368960, 0x028bf70c
+0, 114, 114, 1, 13368960, 0x84c9f7ef
+0, 115, 115, 1, 13368960, 0x7151bb7d
+0, 116, 116, 1, 13368960, 0xe5a88164
+0, 117, 117, 1, 13368960, 0xd5e4e381
+0, 118, 118, 1, 13368960, 0xdb3be595
+0, 119, 119, 1, 13368960, 0x068a5b66
+0, 120, 120, 1, 13368960, 0x0eab39c8
+0, 121, 121, 1, 13368960, 0x0dc56563
+0, 122, 122, 1, 13368960, 0xbbf98dd0
+0, 123, 123, 1, 13368960, 0x5a487c5c
+0, 124, 124, 1, 13368960, 0xd33dc8a8
+0, 125, 125, 1, 13368960, 0x8527158b
+0, 126, 126, 1, 13368960, 0x20f2321a
+0, 127, 127, 1, 13368960, 0x2609d883
+0, 128, 128, 1, 13368960, 0x69b89df1
+0, 129, 129, 1, 13368960, 0x74d5246b
+0, 130, 130, 1, 13368960, 0x873e0eeb
+0, 131, 131, 1, 13368960, 0x90405f59
+0, 132, 132, 1, 13368960, 0x93125fd2
+0, 133, 133, 1, 13368960, 0xcbe963c1
+0, 134, 134, 1, 13368960, 0xe79c6347
+0, 135, 135, 1, 13368960, 0x6ffbf0fb
+0, 136, 136, 1, 13368960, 0x3ed97d05
+0, 137, 137, 1, 13368960, 0x724221bc
+0, 138, 138, 1, 13368960, 0x5c1baa66
+0, 139, 139, 1, 13368960, 0x5c1baa66
+0, 140, 140, 1, 13368960, 0xbd3690df
+0, 141, 141, 1, 13368960, 0x52a5947d
+0, 142, 142, 1, 13368960, 0xd73732c8
+0, 143, 143, 1, 13368960, 0x4356196a
+0, 144, 144, 1, 13368960, 0xef7e1e3f
+0, 145, 145, 1, 13368960, 0xa3d76323
+0, 146, 146, 1, 13368960, 0x01751d58
+0, 147, 147, 1, 13368960, 0xd0ef9115
+0, 148, 148, 1, 13368960, 0x2e09d119
+0, 149, 149, 1, 13368960, 0x09d7a785
+0, 150, 150, 1, 13368960, 0xb93189a9
+0, 151, 151, 1, 13368960, 0xd8277b99
+0, 152, 152, 1, 13368960, 0xf3b8766a
+0, 153, 153, 1, 13368960, 0x782e9fa1
+0, 154, 154, 1, 13368960, 0x36d4601e
+0, 155, 155, 1, 13368960, 0x86f70f8c
+0, 156, 156, 1, 13368960, 0xcc7f2c1d
+0, 157, 157, 1, 13368960, 0xe83641fc
+0, 158, 158, 1, 13368960, 0x1d81af8a
+0, 159, 159, 1, 13368960, 0x83c2fe6c
+0, 160, 160, 1, 13368960, 0x3e324390
+0, 161, 161, 1, 13368960, 0xd00235b3
+0, 162, 162, 1, 13368960, 0xd1e8873a
+0, 163, 163, 1, 13368960, 0x7d8f603a
+0, 164, 164, 1, 13368960, 0x76107866
+0, 165, 165, 1, 13368960, 0x79f71d19
+0, 166, 166, 1, 13368960, 0x5ae7b71d
+0, 167, 167, 1, 13368960, 0xeb0acd6e
+0, 168, 168, 1, 13368960, 0x3400e989
+0, 169, 169, 1, 13368960, 0xaa5f7ae6
+0, 170, 170, 1, 13368960, 0xfc294222
+0, 171, 171, 1, 13368960, 0xc95000e2
+0, 172, 172, 1, 13368960, 0x8525afaf
+0, 173, 173, 1, 13368960, 0x02e87e93
+0, 174, 174, 1, 13368960, 0x84de93e2
+0, 175, 175, 1, 13368960, 0xc96984ed
+0, 176, 176, 1, 13368960, 0xf2bba506
+0, 177, 177, 1, 13368960, 0x580a43bd
+0, 178, 178, 1, 13368960, 0xa0768ffe
+0, 179, 179, 1, 13368960, 0x6438a4e6
+0, 180, 180, 1, 13368960, 0x93be17fb
+0, 181, 181, 1, 13368960, 0x3ae701f8
+0, 182, 182, 1, 13368960, 0xdd915885
+0, 183, 183, 1, 13368960, 0x72fd266b
+0, 184, 184, 1, 13368960, 0xb4278a8e
+0, 185, 185, 1, 13368960, 0x3c48692b
+0, 186, 186, 1, 13368960, 0x44dced17
+0, 187, 187, 1, 13368960, 0x75091091
+0, 188, 188, 1, 13368960, 0x5c3e2aeb
+0, 189, 189, 1, 13368960, 0xb867b21b
+0, 190, 190, 1, 13368960, 0x4c54d3df
+0, 191, 191, 1, 13368960, 0x513a925d
+0, 192, 192, 1, 13368960, 0x1413cd87
+0, 193, 193, 1, 13368960, 0x1413cd87
+0, 194, 194, 1, 13368960, 0x3d18513f
+0, 195, 195, 1, 13368960, 0x3d18513f
+0, 196, 196, 1, 13368960, 0x97666d1f
+0, 197, 197, 1, 13368960, 0xc650d2fb
+0, 198, 198, 1, 13368960, 0x506d7298
+0, 199, 199, 1, 13368960, 0x727835f3
+0, 200, 200, 1, 13368960, 0xbd01cccf
+0, 201, 201, 1, 13368960, 0x9903d82f
+0, 202, 202, 1, 13368960, 0x365cccf3
+0, 203, 203, 1, 13368960, 0x6fe5fa0e
+0, 204, 204, 1, 13368960, 0x365cccf3
+0, 205, 205, 1, 13368960, 0x6f3bbbe8
+0, 206, 206, 1, 13368960, 0x15e1563c
+0, 207, 207, 1, 13368960, 0x92b7c586
+0, 208, 208, 1, 13368960, 0x06303a2b
+0, 209, 209, 1, 13368960, 0x6821a67f
+0, 210, 210, 1, 13368960, 0x53dcf376
+0, 211, 211, 1, 13368960, 0x853cca77
+0, 212, 212, 1, 13368960, 0x4990374c
+0, 213, 213, 1, 13368960, 0x96a45ba2
+0, 214, 214, 1, 13368960, 0x33119f81
+0, 215, 215, 1, 13368960, 0x98bcd5cd
+0, 216, 216, 1, 13368960, 0xfe96fda5
+0, 217, 217, 1, 13368960, 0xf299be0f
+0, 218, 218, 1, 13368960, 0xa986733f
+0, 219, 219, 1, 13368960, 0xe95f90f7
+0, 220, 220, 1, 13368960, 0xbc388307
+0, 221, 221, 1, 13368960, 0x9f85ff25
+0, 222, 222, 1, 13368960, 0xec8200e0
+0, 223, 223, 1, 13368960, 0x508b9054
+0, 224, 224, 1, 13368960, 0x96a4975f
+0, 225, 225, 1, 13368960, 0xe583cf82
+0, 226, 226, 1, 13368960, 0xdb930543
+0, 227, 227, 1, 13368960, 0x4359caa5
+0, 228, 228, 1, 13368960, 0x6eb2243b
+0, 229, 229, 1, 13368960, 0xb0b2afd0
+0, 230, 230, 1, 13368960, 0x6b546e73
+0, 231, 231, 1, 13368960, 0x9e3d3798
+0, 232, 232, 1, 13368960, 0xb5c6fd40
+0, 233, 233, 1, 13368960, 0x61ca65a9
+0, 234, 234, 1, 13368960, 0x01c5eb8d
+0, 235, 235, 1, 13368960, 0x02b9f965
+0, 236, 236, 1, 13368960, 0xf8250f5f
+0, 237, 237, 1, 13368960, 0x29ca8680
+0, 238, 238, 1, 13368960, 0x22788402
+0, 239, 239, 1, 13368960, 0xa48697c6
+0, 240, 240, 1, 13368960, 0x20edbbbf
+0, 241, 241, 1, 13368960, 0x83202f92
+0, 242, 242, 1, 13368960, 0x39753c63
+0, 243, 243, 1, 13368960, 0xe53b2010
+0, 244, 244, 1, 13368960, 0x8f4de71d
+0, 245, 245, 1, 13368960, 0x6258a840
+0, 246, 246, 1, 13368960, 0xe6bb63fa
+0, 247, 247, 1, 13368960, 0xe402b0fa
+0, 248, 248, 1, 13368960, 0x2fb45d78
+0, 249, 249, 1, 13368960, 0xf1615865
+0, 250, 250, 1, 13368960, 0xf7b27d57
+0, 251, 251, 1, 13368960, 0x8acff7a0
+0, 252, 252, 1, 13368960, 0x9a07f770
+0, 253, 253, 1, 13368960, 0xd78ebcec
+0, 254, 254, 1, 13368960, 0x9ab52d9c
+0, 255, 255, 1, 13368960, 0xd27494dd
+0, 256, 256, 1, 13368960, 0xc8e60814
+0, 257, 257, 1, 13368960, 0xa1225c85
+0, 258, 258, 1, 13368960, 0x94386aec
+0, 259, 259, 1, 13368960, 0x98352e63
+0, 260, 260, 1, 13368960, 0x1e469945
+0, 261, 261, 1, 13368960, 0xf646569c
+0, 262, 262, 1, 13368960, 0x9831b297
+0, 263, 263, 1, 13368960, 0x37e38119
+0, 264, 264, 1, 13368960, 0xebe37433
+0, 265, 265, 1, 13368960, 0xa1b5c8e1
diff --git a/tests/ref/fate/hmac b/tests/ref/fate/hmac
index 7d2a437c69..27b95ba36d 100644
--- a/tests/ref/fate/hmac
+++ b/tests/ref/fate/hmac
@@ -1,6 +1,30 @@
9294727a3638bb1c13f48ef8158bfc9d
750c783e6ab0b503eaa86e310a5db738
56be34521d144c88dbb8c733f0e8b3f6
-467cb2560355d7fa3ab2d6b939e6e47c
-5a6ffd741d3e23b12f78b1baee9e609a
-8b4b9d11c9e186c58f2a53b08ddfa436
+6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
+6f630fad67cda0ee1fb1f562db3aa53e
+b617318655057264e28bc0b6fb378c8ef146be00
+effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
+125d7342b9ac11cd91a39af48aa17b4f63f175d3
+aa4ae5e15272d00e95705637ce8a3b55ed402112
+e8e99d0f45237d786d6bbaa7965c7808bbff1a91
+896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22
+a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44
+7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea
+95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e
+3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1
+b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
+5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
+773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe
+60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54
+9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2
+afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6
+af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649
+88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27
+4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952
+6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e
+87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854
+164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737
+fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb
+80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598
+e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58
diff --git a/tests/ref/fate/idroq-video-encode b/tests/ref/fate/idroq-video-encode
index badb06d11d..bdb6fedf56 100644
--- a/tests/ref/fate/idroq-video-encode
+++ b/tests/ref/fate/idroq-video-encode
@@ -1 +1 @@
-2ac89fa0e5600152667bcbc661f06cfe
+e9ff61023826fce304350ff6e7c63b2f
diff --git a/tests/ref/fate/indeo3 b/tests/ref/fate/indeo3
index e294f70bb8..0f5564928f 100644
--- a/tests/ref/fate/indeo3
+++ b/tests/ref/fate/indeo3
@@ -1,41 +1,41 @@
-#tb 0: 1/600
+#tb 0: 1/10
0, 0, 0, 1, 21600, 0x845098fc
-0, 60, 60, 1, 21600, 0xc28e8bf0
-0, 120, 120, 1, 21600, 0x2f418fb4
-0, 180, 180, 1, 21600, 0x051d7a0e
-0, 240, 240, 1, 21600, 0x1b36aa7c
-0, 300, 300, 1, 21600, 0xb9e2ad38
-0, 360, 360, 1, 21600, 0x8dc99b60
-0, 420, 420, 1, 21600, 0xa3fa789a
-0, 480, 480, 1, 21600, 0x1fdbade2
-0, 540, 540, 1, 21600, 0x4f4ac164
-0, 600, 600, 1, 21600, 0x0ea5cb50
-0, 660, 660, 1, 21600, 0xfb659528
-0, 720, 720, 1, 21600, 0xac5790f8
-0, 780, 780, 1, 21600, 0x9762beb4
-0, 840, 840, 1, 21600, 0x29b0da0a
-0, 900, 900, 1, 21600, 0x6d88b0da
-0, 960, 960, 1, 21600, 0x687b8efa
-0, 1020, 1020, 1, 21600, 0xcd726220
-0, 1080, 1080, 1, 21600, 0xa1766598
-0, 1140, 1140, 1, 21600, 0xff4b8074
-0, 1200, 1200, 1, 21600, 0x845098fc
-0, 1260, 1260, 1, 21600, 0xdb259e08
-0, 1320, 1320, 1, 21600, 0xb6bda5a0
-0, 1380, 1380, 1, 21600, 0xbb998962
-0, 1440, 1440, 1, 21600, 0x28aa7b7c
-0, 1500, 1500, 1, 21600, 0x1ad1a15c
-0, 1560, 1560, 1, 21600, 0xb535a128
-0, 1620, 1620, 1, 21600, 0x4dbf968a
-0, 1680, 1680, 1, 21600, 0xfe90a8d6
-0, 1740, 1740, 1, 21600, 0xf63fabf0
-0, 1800, 1800, 1, 21600, 0xd6fabe58
-0, 1860, 1860, 1, 21600, 0x172eb09c
-0, 1920, 1920, 1, 21600, 0x44f8a8fe
-0, 1980, 1980, 1, 21600, 0x29429a06
-0, 2040, 2040, 1, 21600, 0xb12f8cc4
-0, 2100, 2100, 1, 21600, 0xd0c78cb4
-0, 2160, 2160, 1, 21600, 0x97e17e0c
-0, 2220, 2220, 1, 21600, 0xf8ac6700
-0, 2280, 2280, 1, 21600, 0xf9c17c94
-0, 2340, 2340, 1, 21600, 0xb10e8c54
+0, 1, 1, 1, 21600, 0xc28e8bf0
+0, 2, 2, 1, 21600, 0x2f418fb4
+0, 3, 3, 1, 21600, 0x051d7a0e
+0, 4, 4, 1, 21600, 0x1b36aa7c
+0, 5, 5, 1, 21600, 0xb9e2ad38
+0, 6, 6, 1, 21600, 0x8dc99b60
+0, 7, 7, 1, 21600, 0xa3fa789a
+0, 8, 8, 1, 21600, 0x1fdbade2
+0, 9, 9, 1, 21600, 0x4f4ac164
+0, 10, 10, 1, 21600, 0x0ea5cb50
+0, 11, 11, 1, 21600, 0xfb659528
+0, 12, 12, 1, 21600, 0xac5790f8
+0, 13, 13, 1, 21600, 0x9762beb4
+0, 14, 14, 1, 21600, 0x29b0da0a
+0, 15, 15, 1, 21600, 0x6d88b0da
+0, 16, 16, 1, 21600, 0x687b8efa
+0, 17, 17, 1, 21600, 0xcd726220
+0, 18, 18, 1, 21600, 0xa1766598
+0, 19, 19, 1, 21600, 0xff4b8074
+0, 20, 20, 1, 21600, 0x845098fc
+0, 21, 21, 1, 21600, 0xdb259e08
+0, 22, 22, 1, 21600, 0xb6bda5a0
+0, 23, 23, 1, 21600, 0xbb998962
+0, 24, 24, 1, 21600, 0x28aa7b7c
+0, 25, 25, 1, 21600, 0x1ad1a15c
+0, 26, 26, 1, 21600, 0xb535a128
+0, 27, 27, 1, 21600, 0x4dbf968a
+0, 28, 28, 1, 21600, 0xfe90a8d6
+0, 29, 29, 1, 21600, 0xf63fabf0
+0, 30, 30, 1, 21600, 0xd6fabe58
+0, 31, 31, 1, 21600, 0x172eb09c
+0, 32, 32, 1, 21600, 0x44f8a8fe
+0, 33, 33, 1, 21600, 0x29429a06
+0, 34, 34, 1, 21600, 0xb12f8cc4
+0, 35, 35, 1, 21600, 0xd0c78cb4
+0, 36, 36, 1, 21600, 0x97e17e0c
+0, 37, 37, 1, 21600, 0xf8ac6700
+0, 38, 38, 1, 21600, 0xf9c17c94
+0, 39, 39, 1, 21600, 0xb10e8c54
diff --git a/tests/ref/fate/indeo5 b/tests/ref/fate/indeo5
index 3f0adfb4ee..7b9123862d 100644
--- a/tests/ref/fate/indeo5
+++ b/tests/ref/fate/indeo5
@@ -1,6 +1,5 @@
#tb 0: 1/15
0, 0, 0, 1, 48600, 0x72d4193b
-0, 1, 1, 1, 48600, 0x72d4193b
0, 2, 2, 1, 48600, 0x36abd6f3
0, 3, 3, 1, 48600, 0x99e582f7
0, 4, 4, 1, 48600, 0xa4cb6fb7
diff --git a/tests/ref/fate/interplay-mve-16bit b/tests/ref/fate/interplay-mve-16bit
index 2469aaac59..b20e998857 100644
--- a/tests/ref/fate/interplay-mve-16bit
+++ b/tests/ref/fate/interplay-mve-16bit
@@ -1,51 +1,51 @@
-#tb 0: 1/1000000
-0, 0, 0, 0, 614400, 0x00000000
-0, 33360, 33360, 0, 614400, 0x00000000
-0, 66720, 66720, 0, 614400, 0xa17ea4ec
-0, 100080, 100080, 0, 614400, 0x4fd207fb
-0, 133440, 133440, 0, 614400, 0xd7a510fb
-0, 166800, 166800, 0, 614400, 0xe901e2f4
-0, 200160, 200160, 0, 614400, 0x4ac5d3c4
-0, 233520, 233520, 0, 614400, 0x32e3e99c
-0, 266880, 266880, 0, 614400, 0x7a2ff20c
-0, 300240, 300240, 0, 614400, 0x59941193
-0, 333600, 333600, 0, 614400, 0x92773a2b
-0, 366960, 366960, 0, 614400, 0x4cd14313
-0, 400320, 400320, 0, 614400, 0x2a093fa3
-0, 433680, 433680, 0, 614400, 0xf68b8463
-0, 467040, 467040, 0, 614400, 0xa9e1969b
-0, 500400, 500400, 0, 614400, 0x461996bb
-0, 533760, 533760, 0, 614400, 0xae58d053
-0, 567120, 567120, 0, 614400, 0x7693015a
-0, 600480, 600480, 0, 614400, 0x0b3507fa
-0, 633840, 633840, 0, 614400, 0xff5c2492
-0, 667200, 667200, 0, 614400, 0x636e3e32
-0, 700560, 700560, 0, 614400, 0x1acd6d0a
-0, 733920, 733920, 0, 614400, 0x67039232
-0, 767280, 767280, 0, 614400, 0x8ab9c75a
-0, 800640, 800640, 0, 614400, 0xe824bbe2
-0, 834000, 834000, 0, 614400, 0x5133e9ea
-0, 867360, 867360, 0, 614400, 0xcecf1249
-0, 900720, 900720, 0, 614400, 0xe6d928c1
-0, 934080, 934080, 0, 614400, 0x8da46ff1
-0, 967440, 967440, 0, 614400, 0x1c778319
-0, 1000800, 1000800, 0, 614400, 0x35a19451
-0, 1034160, 1034160, 0, 614400, 0x5145d1b9
-0, 1067520, 1067520, 0, 614400, 0x146ee231
-0, 1100880, 1100880, 0, 614400, 0xd9b33380
-0, 1134240, 1134240, 0, 614400, 0x8b112ef8
-0, 1167600, 1167600, 0, 614400, 0xb9e79ab0
-0, 1200960, 1200960, 0, 614400, 0x62d3a498
-0, 1234320, 1234320, 0, 614400, 0xaeaaaa58
-0, 1267680, 1267680, 0, 614400, 0x8922c440
-0, 1301040, 1301040, 0, 614400, 0xd62ef758
-0, 1334400, 1334400, 0, 614400, 0x2a53149f
-0, 1367760, 1367760, 0, 614400, 0x13da47df
-0, 1401120, 1401120, 0, 614400, 0x27c05c3f
-0, 1434480, 1434480, 0, 614400, 0x41ff7ca7
-0, 1467840, 1467840, 0, 614400, 0x6b0e8a07
-0, 1501200, 1501200, 0, 614400, 0xa200ad9f
-0, 1534560, 1534560, 0, 614400, 0x9da7cc77
-0, 1567920, 1567920, 0, 614400, 0x2f5703be
-0, 1601280, 1601280, 0, 614400, 0x91c720f6
-0, 1634640, 1634640, 0, 614400, 0x927a882e
+#tb 0: 417/12500
+0, 0, 0, 1, 614400, 0x00000000
+0, 1, 1, 1, 614400, 0x00000000
+0, 2, 2, 1, 614400, 0x3c4ce011
+0, 3, 3, 1, 614400, 0x16e83922
+0, 4, 4, 1, 614400, 0x657a3d4d
+0, 5, 5, 1, 614400, 0x933a08b0
+0, 6, 6, 1, 614400, 0xfcd5f76e
+0, 7, 7, 1, 614400, 0xd0990cf8
+0, 8, 8, 1, 614400, 0x02131686
+0, 9, 9, 1, 614400, 0x4cf53656
+0, 10, 10, 1, 614400, 0x7d1960c0
+0, 11, 11, 1, 614400, 0x5d9f696f
+0, 12, 12, 1, 614400, 0x54e06663
+0, 13, 13, 1, 614400, 0x4c1eade1
+0, 14, 14, 1, 614400, 0x4bd3bfff
+0, 15, 15, 1, 614400, 0xab86c041
+0, 16, 16, 1, 614400, 0xbb2bfbf4
+0, 17, 17, 1, 614400, 0x43822e15
+0, 18, 18, 1, 614400, 0x835e352c
+0, 19, 19, 1, 614400, 0x72cc538f
+0, 20, 20, 1, 614400, 0x20bb6e30
+0, 21, 21, 1, 614400, 0xfb079f52
+0, 22, 22, 1, 614400, 0x759bc4d6
+0, 23, 23, 1, 614400, 0xd116fc3b
+0, 24, 24, 1, 614400, 0x5c06efd2
+0, 25, 25, 1, 614400, 0x61641ecd
+0, 26, 26, 1, 614400, 0x6c8d48a0
+0, 27, 27, 1, 614400, 0x64725eed
+0, 28, 28, 1, 614400, 0x88f9a8ca
+0, 29, 29, 1, 614400, 0xcf1cbcd9
+0, 30, 30, 1, 614400, 0x75a3ce24
+0, 31, 31, 1, 614400, 0x3bf80ce7
+0, 32, 32, 1, 614400, 0xd4011d7c
+0, 33, 33, 1, 614400, 0xd569716b
+0, 34, 34, 1, 614400, 0xfd626b6b
+0, 35, 35, 1, 614400, 0xc856dbaf
+0, 36, 36, 1, 614400, 0x0e56e68e
+0, 37, 37, 1, 614400, 0x5b29ecc9
+0, 38, 38, 1, 614400, 0xe83c0804
+0, 39, 39, 1, 614400, 0xebdd3d61
+0, 40, 40, 1, 614400, 0x7f4c5b56
+0, 41, 41, 1, 614400, 0xb4019155
+0, 42, 42, 1, 614400, 0xffdda515
+0, 43, 43, 1, 614400, 0x5271c695
+0, 44, 44, 1, 614400, 0x8526d3c1
+0, 45, 45, 1, 614400, 0x5accf7a6
+0, 46, 46, 1, 614400, 0x959017aa
+0, 47, 47, 1, 614400, 0x22f450f6
+0, 48, 48, 1, 614400, 0x2e3d6f37
+0, 49, 49, 1, 614400, 0x0db9d89f
diff --git a/tests/ref/fate/interplay-mve-8bit b/tests/ref/fate/interplay-mve-8bit
index abd86eb46d..b37bd6e376 100644
--- a/tests/ref/fate/interplay-mve-8bit
+++ b/tests/ref/fate/interplay-mve-8bit
@@ -1,111 +1,111 @@
-#tb 0: 1/1000000
-0, 0, 0, 0, 414720, 0xa5cd50ca
-0, 66728, 66728, 0, 414720, 0x3facd321
-0, 133456, 133456, 0, 414720, 0x849e6d4b
-0, 200184, 200184, 0, 414720, 0xe649363f
-0, 266912, 266912, 0, 414720, 0x5bbd7b14
-0, 333640, 333640, 0, 414720, 0xe246ab51
-0, 400368, 400368, 0, 414720, 0x5721b22e
-0, 467096, 467096, 0, 414720, 0xe391e107
-0, 533824, 533824, 0, 414720, 0x04d851ff
-0, 600552, 600552, 0, 414720, 0x8d80d580
-0, 667280, 667280, 0, 414720, 0x5a24b0bc
-0, 734008, 734008, 0, 414720, 0x06cd6960
-0, 800736, 800736, 0, 414720, 0xf5ca48b4
-0, 867464, 867464, 0, 414720, 0x24700f94
-0, 934192, 934192, 0, 414720, 0xb0bfe451
-0, 1000920, 1000920, 0, 414720, 0x00e9f3d1
-0, 1067648, 1067648, 0, 414720, 0x0efbffd1
-0, 1134376, 1134376, 0, 414720, 0x2ecdfc8d
-0, 1201104, 1201104, 0, 414720, 0x94b531fc
-0, 1267832, 1267832, 0, 414720, 0x2c2579f8
-0, 1334560, 1334560, 0, 414720, 0x6c7ecfb8
-0, 1401288, 1401288, 0, 414720, 0x08982527
-0, 1468016, 1468016, 0, 414720, 0x5c0161b3
-0, 1534744, 1534744, 0, 414720, 0x453ce413
-0, 1601472, 1601472, 0, 414720, 0x634e36b2
-0, 1668200, 1668200, 0, 414720, 0x401a683a
-0, 1734928, 1734928, 0, 414720, 0x3c5f442e
-0, 1801656, 1801656, 0, 414720, 0x075ef787
-0, 1868384, 1868384, 0, 414720, 0x8501a04f
-0, 1935112, 1935112, 0, 414720, 0x3620093b
-0, 2001840, 2001840, 0, 414720, 0xa42d9480
-0, 2068568, 2068568, 0, 414720, 0x09b150b4
-0, 2135296, 2135296, 0, 414720, 0xcad407f0
-0, 2202024, 2202024, 0, 414720, 0x69e5eecd
-0, 2268752, 2268752, 0, 414720, 0xb92ad2d9
-0, 2335480, 2335480, 0, 414720, 0xc78eaf29
-0, 2402208, 2402208, 0, 414720, 0x47c3fa91
-0, 2468936, 2468936, 0, 414720, 0x8847b7b8
-0, 2535664, 2535664, 0, 414720, 0x864cab2f
-0, 2602392, 2602392, 0, 414720, 0x78d653e2
-0, 2669120, 2669120, 0, 414720, 0xda15cbd2
-0, 2735848, 2735848, 0, 414720, 0xdf9ce28a
-0, 2802576, 2802576, 0, 414720, 0xe88c49ca
-0, 2869304, 2869304, 0, 414720, 0xd6bcbc07
-0, 2936032, 2936032, 0, 414720, 0xf0b4a7bf
-0, 3002760, 3002760, 0, 414720, 0x74f9bfbf
-0, 3069488, 3069488, 0, 414720, 0x904ce103
-0, 3136216, 3136216, 0, 414720, 0xca877e4a
-0, 3202944, 3202944, 0, 414720, 0x588effd6
-0, 3269672, 3269672, 0, 414720, 0x6dff8b71
-0, 3336400, 3336400, 0, 414720, 0xbeaae788
-0, 3403128, 3403128, 0, 414720, 0x1a4d1242
-0, 3469856, 3469856, 0, 414720, 0x4ae98ea0
-0, 3536584, 3536584, 0, 414720, 0x41ed6d22
-0, 3603312, 3603312, 0, 414720, 0x486e70aa
-0, 3670040, 3670040, 0, 414720, 0xfddc103e
-0, 3736768, 3736768, 0, 414720, 0x8620f03e
-0, 3803496, 3803496, 0, 414720, 0x0e4ec273
-0, 3870224, 3870224, 0, 414720, 0xb2298b3e
-0, 3936952, 3936952, 0, 414720, 0xb4f50176
-0, 4003680, 4003680, 0, 414720, 0xb9c7a495
-0, 4070408, 4070408, 0, 414720, 0xed270702
-0, 4137136, 4137136, 0, 414720, 0x98b72586
-0, 4203864, 4203864, 0, 414720, 0xd8977cb1
-0, 4270592, 4270592, 0, 414720, 0xff3d3851
-0, 4337320, 4337320, 0, 414720, 0x7e4f0424
-0, 4404048, 4404048, 0, 414720, 0xa9e75006
-0, 4470776, 4470776, 0, 414720, 0x8f98cba9
-0, 4537504, 4537504, 0, 414720, 0x25ecd620
-0, 4604232, 4604232, 0, 414720, 0x78cf5c58
-0, 4670960, 4670960, 0, 414720, 0x3fb4b81a
-0, 4737688, 4737688, 0, 414720, 0xd7b655fa
-0, 4804416, 4804416, 0, 414720, 0xd9158db3
-0, 4871144, 4871144, 0, 414720, 0x2e651852
-0, 4937872, 4937872, 0, 414720, 0x9f9adb64
-0, 5004600, 5004600, 0, 414720, 0xe9d16e81
-0, 5071328, 5071328, 0, 414720, 0xbe73daf5
-0, 5138056, 5138056, 0, 414720, 0x3d164329
-0, 5204784, 5204784, 0, 414720, 0x1d5a9bc8
-0, 5271512, 5271512, 0, 414720, 0x8e8debbe
-0, 5338240, 5338240, 0, 414720, 0x4e7a2bf0
-0, 5404968, 5404968, 0, 414720, 0x4a13804d
-0, 5471696, 5471696, 0, 414720, 0x5dd188d8
-0, 5538424, 5538424, 0, 414720, 0xbe7f4963
-0, 5605152, 5605152, 0, 414720, 0xcff3b767
-0, 5671880, 5671880, 0, 414720, 0xbbd3afa0
-0, 5738608, 5738608, 0, 414720, 0xaf9dec62
-0, 5805336, 5805336, 0, 414720, 0xc74816a1
-0, 5872064, 5872064, 0, 414720, 0x51488bfc
-0, 5938792, 5938792, 0, 414720, 0x68c10a2c
-0, 6005520, 6005520, 0, 414720, 0x10179c4e
-0, 6072248, 6072248, 0, 414720, 0x18d559b7
-0, 6138976, 6138976, 0, 414720, 0x8257aa55
-0, 6205704, 6205704, 0, 414720, 0x9ea24501
-0, 6272432, 6272432, 0, 414720, 0x238605cc
-0, 6339160, 6339160, 0, 414720, 0xb552deaa
-0, 6405888, 6405888, 0, 414720, 0x07c3348d
-0, 6472616, 6472616, 0, 414720, 0x82f4f9b0
-0, 6539344, 6539344, 0, 414720, 0xf5d76bc5
-0, 6606072, 6606072, 0, 414720, 0x34b3a1e6
-0, 6672800, 6672800, 0, 414720, 0xda25e11b
-0, 6739528, 6739528, 0, 414720, 0x2b19936b
-0, 6806256, 6806256, 0, 414720, 0xe91f9f73
-0, 6872984, 6872984, 0, 414720, 0x48d09aab
-0, 6939712, 6939712, 0, 414720, 0xac42bf83
-0, 7006440, 7006440, 0, 414720, 0x2d8ca14e
-0, 7073168, 7073168, 0, 414720, 0xe65462fd
-0, 7139896, 7139896, 0, 414720, 0xe5bfc929
-0, 7206624, 7206624, 0, 414720, 0x66784c58
-0, 7273352, 7273352, 0, 414720, 0x70dbeca8
+#tb 0: 8341/125000
+0, 0, 0, 1, 414720, 0x2580d574
+0, 1, 1, 1, 414720, 0x97f55cd3
+0, 2, 2, 1, 414720, 0x9408fb63
+0, 3, 3, 1, 414720, 0x7e53c155
+0, 4, 4, 1, 414720, 0xd8570262
+0, 5, 5, 1, 414720, 0x9dc72ed5
+0, 6, 6, 1, 414720, 0xf7d33211
+0, 7, 7, 1, 414720, 0x95935e3b
+0, 8, 8, 1, 414720, 0x62b1cdc5
+0, 9, 9, 1, 414720, 0x971f500a
+0, 10, 10, 1, 414720, 0x05f82b6c
+0, 11, 11, 1, 414720, 0x7713e3cb
+0, 12, 12, 1, 414720, 0x3170c2f0
+0, 13, 13, 1, 414720, 0x8d818956
+0, 14, 14, 1, 414720, 0x16775d71
+0, 15, 15, 1, 414720, 0x63016ce1
+0, 16, 16, 1, 414720, 0x2f94792c
+0, 17, 17, 1, 414720, 0x37f67725
+0, 18, 18, 1, 414720, 0xeb95adb1
+0, 19, 19, 1, 414720, 0xbf32f6df
+0, 20, 20, 1, 414720, 0x242f4d09
+0, 21, 21, 1, 414720, 0x28a2a3b9
+0, 22, 22, 1, 414720, 0x895de0a6
+0, 23, 23, 1, 414720, 0xd3b46447
+0, 24, 24, 1, 414720, 0x3bbfb7d1
+0, 25, 25, 1, 414720, 0x0a5ee9ad
+0, 26, 26, 1, 414720, 0xaabac502
+0, 27, 27, 1, 414720, 0x0951779d
+0, 28, 28, 1, 414720, 0x150e2073
+0, 29, 29, 1, 414720, 0xb86d87ae
+0, 30, 30, 1, 414720, 0x135411da
+0, 31, 31, 1, 414720, 0x9c8fcda5
+0, 32, 32, 1, 414720, 0xb7ba838e
+0, 33, 33, 1, 414720, 0x7ef869e1
+0, 34, 34, 1, 414720, 0xf9764d47
+0, 35, 35, 1, 414720, 0xe6c72872
+0, 36, 36, 1, 414720, 0xb95b73b8
+0, 37, 37, 1, 414720, 0xa19e3221
+0, 38, 38, 1, 414720, 0xc0be27cd
+0, 39, 39, 1, 414720, 0xe97cd1a9
+0, 40, 40, 1, 414720, 0xb6524a34
+0, 41, 41, 1, 414720, 0x61a1607b
+0, 42, 42, 1, 414720, 0x1dd9c606
+0, 43, 43, 1, 414720, 0xe2e736fa
+0, 44, 44, 1, 414720, 0x25b922d9
+0, 45, 45, 1, 414720, 0xbc023b36
+0, 46, 46, 1, 414720, 0x39bb5cdf
+0, 47, 47, 1, 414720, 0xf83bfc4f
+0, 48, 48, 1, 414720, 0x3eae7f36
+0, 49, 49, 1, 414720, 0x8cf80c32
+0, 50, 50, 1, 414720, 0xbc576c03
+0, 51, 51, 1, 414720, 0x28b79ab1
+0, 52, 52, 1, 414720, 0x15da1138
+0, 53, 53, 1, 414720, 0x345ff676
+0, 54, 54, 1, 414720, 0x0108f909
+0, 55, 55, 1, 414720, 0x57459616
+0, 56, 56, 1, 414720, 0x2f497782
+0, 57, 57, 1, 414720, 0xb72b4f79
+0, 58, 58, 1, 414720, 0x2bfd1967
+0, 59, 59, 1, 414720, 0x974a99cd
+0, 60, 60, 1, 414720, 0x5f5f4129
+0, 61, 61, 1, 414720, 0x51ad9df4
+0, 62, 62, 1, 414720, 0xd6e5c16c
+0, 63, 63, 1, 414720, 0xd8751bda
+0, 64, 64, 1, 414720, 0x216ed6f3
+0, 65, 65, 1, 414720, 0x63a0a67d
+0, 66, 66, 1, 414720, 0xe4f4eb0f
+0, 67, 67, 1, 414720, 0xa1665ef8
+0, 68, 68, 1, 414720, 0xc3116dfd
+0, 69, 69, 1, 414720, 0x3213fd70
+0, 70, 70, 1, 414720, 0x2af76048
+0, 71, 71, 1, 414720, 0x3570085d
+0, 72, 72, 1, 414720, 0x2a7c3c39
+0, 73, 73, 1, 414720, 0xd8a6ba7e
+0, 74, 74, 1, 414720, 0x48107b4d
+0, 75, 75, 1, 414720, 0x653a0936
+0, 76, 76, 1, 414720, 0xf68c77ab
+0, 77, 77, 1, 414720, 0xa5ecde84
+0, 78, 78, 1, 414720, 0xaec33ca1
+0, 79, 79, 1, 414720, 0x26e68740
+0, 80, 80, 1, 414720, 0xac09bfa5
+0, 81, 81, 1, 414720, 0xed5111b2
+0, 82, 82, 1, 414720, 0x38041c98
+0, 83, 83, 1, 414720, 0x76fbde1d
+0, 84, 84, 1, 414720, 0x3ae64b7d
+0, 85, 85, 1, 414720, 0xb05f4da2
+0, 86, 86, 1, 414720, 0x65769088
+0, 87, 87, 1, 414720, 0xbc45ba59
+0, 88, 88, 1, 414720, 0x8c893436
+0, 89, 89, 1, 414720, 0x1d5ebe7f
+0, 90, 90, 1, 414720, 0xa9cd5a53
+0, 91, 91, 1, 414720, 0xc69e1fb0
+0, 92, 92, 1, 414720, 0xb28a77ec
+0, 93, 93, 1, 414720, 0x834f1219
+0, 94, 94, 1, 414720, 0xba34c848
+0, 95, 95, 1, 414720, 0x80e590c1
+0, 96, 96, 1, 414720, 0x7146dc31
+0, 97, 97, 1, 414720, 0x05929a5f
+0, 98, 98, 1, 414720, 0x721708c5
+0, 99, 99, 1, 414720, 0x4aa83cbe
+0, 100, 100, 1, 414720, 0x221d799f
+0, 101, 101, 1, 414720, 0xe9e72bec
+0, 102, 102, 1, 414720, 0xb6a3385d
+0, 103, 103, 1, 414720, 0x795a3362
+0, 104, 104, 1, 414720, 0x770b58d9
+0, 105, 105, 1, 414720, 0xb5563ce4
+0, 106, 106, 1, 414720, 0x0c1a00cc
+0, 107, 107, 1, 414720, 0xcbd467fd
+0, 108, 108, 1, 414720, 0x3bccec29
+0, 109, 109, 1, 414720, 0x92d78db7
diff --git a/tests/ref/fate/iv8-demux b/tests/ref/fate/iv8-demux
index 56a54a11db..02b6314b4d 100644
--- a/tests/ref/fate/iv8-demux
+++ b/tests/ref/fate/iv8-demux
@@ -1,3 +1,4 @@
+#extradata 0: 19, 0x1f2604b9
#tb 0: 1/90000
0, 0, 0, 0, 20883, 0x347191e2
0, 0, 3600, 0, 20882, 0xe1573905
@@ -19,8 +20,8 @@
0, 57600, 61200, 0, 20874, 0xed0b91ec
0, 61200, 64799, 0, 20877, 0xe1623e01
0, 64799, 68399, 0, 20933, 0x19906564
-0, 68399, 72000, 3600, 20891, 0x3d064fd3
-0, 72000, 75600, 3600, 20834, 0xcb774dbc
-0, 75600, 79200, 3600, 20870, 0xbc536589
-0, 79200, 82800, 3600, 21421, 0xc99a68e4
-0, 82800, 86400, 3600, 12869, 0x5684e304
+0, 68399, 72000, 0, 20891, 0x3d064fd3
+0, 72000, 75600, 0, 20834, 0xcb774dbc
+0, 75600, 79200, 0, 20870, 0xbc536589
+0, 79200, 82800, 0, 21421, 0xc99a68e4
+0, 82800, 86400, 0, 12869, 0x5684e304
diff --git a/tests/ref/fate/jv b/tests/ref/fate/jv
index 0d5102d13d..b0a6008d93 100644
--- a/tests/ref/fate/jv
+++ b/tests/ref/fate/jv
@@ -1,9 +1,8 @@
#tb 0: 2/25
0, 0, 0, 1, 192000, 0x00000000
-0, 2, 2, 1, 192000, 0x95ece4ea
-0, 3, 3, 1, 192000, 0x9abaf682
-0, 4, 4, 1, 192000, 0x9a93fed6
-0, 5, 5, 1, 192000, 0x112dfade
-0, 6, 6, 1, 192000, 0xb8f3e986
-0, 7, 7, 1, 192000, 0x21daea8e
-0, 8, 8, 1, 192000, 0x5dc1032d
+0, 2, 2, 1, 192000, 0x331b1c12
+0, 3, 3, 1, 192000, 0xc2fa2d89
+0, 4, 4, 1, 192000, 0x9b3035ac
+0, 5, 5, 1, 192000, 0xb8e331eb
+0, 6, 6, 1, 192000, 0xd35b2053
+0, 7, 7, 1, 192000, 0x01062188
diff --git a/tests/ref/fate/jv-demux b/tests/ref/fate/jv-demux
new file mode 100644
index 0000000000..51638df1a8
--- /dev/null
+++ b/tests/ref/fate/jv-demux
@@ -0,0 +1,20 @@
+#tb 0: 2/25
+#tb 1: 1/22050
+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
+1, 131072, 131072, 1764, 1764, 0x30be734d
+1, 132836, 132836, 1764, 1764, 0xa4c873a7
+1, 134600, 134600, 1764, 1764, 0xd5f17443
+1, 136364, 136364, 1764, 1764, 0xd31c7230
+1, 138128, 138128, 1764, 1764, 0x181d730f
+1, 139892, 139892, 1764, 1764, 0x76f47538
+1, 141656, 141656, 1764, 1764, 0x6c51715d
+1, 143420, 143420, 1764, 1764, 0x689374f5
diff --git a/tests/ref/fate/kgv1 b/tests/ref/fate/kgv1
index 6f35893f83..4f475bb632 100644
--- a/tests/ref/fate/kgv1
+++ b/tests/ref/fate/kgv1
@@ -294,15 +294,15 @@
0, 292, 292, 1, 153600, 0x1348310e
0, 293, 293, 1, 153600, 0xb5489dad
0, 294, 294, 1, 153600, 0xa1eb1408
-0, 295, 295, 1, 153600, 0x15e1832c
+0, 295, 295, 1, 153600, 0x15e0832b
0, 296, 296, 1, 153600, 0xb789cba5
0, 297, 297, 1, 153600, 0x3ee86e4f
0, 298, 298, 1, 153600, 0x06ea3883
0, 299, 299, 1, 153600, 0xcedd02b7
-0, 300, 300, 1, 153600, 0xbce6ce58
-0, 301, 301, 1, 153600, 0xaadf9a00
+0, 300, 300, 1, 153600, 0xbcd6ce50
+0, 301, 301, 1, 153600, 0xaacf99f8
0, 302, 302, 1, 153600, 0x98c865a0
-0, 303, 303, 1, 153600, 0x4c8432e0
+0, 303, 303, 1, 153600, 0x4c6432d0
0, 304, 304, 1, 153600, 0x00000000
0, 305, 305, 1, 153600, 0x00000000
0, 306, 306, 1, 153600, 0x00000000
diff --git a/tests/ref/fate/lagarith-red b/tests/ref/fate/lagarith-red
new file mode 100644
index 0000000000..b5fb96b4f6
--- /dev/null
+++ b/tests/ref/fate/lagarith-red
@@ -0,0 +1,26 @@
+#tb 0: 1/25
+0, 0, 0, 1, 230400, 0x67dfe576
+0, 1, 1, 1, 230400, 0x67dfe576
+0, 2, 2, 1, 230400, 0x67dfe576
+0, 3, 3, 1, 230400, 0x67dfe576
+0, 4, 4, 1, 230400, 0x67dfe576
+0, 5, 5, 1, 230400, 0x67dfe576
+0, 6, 6, 1, 230400, 0x67dfe576
+0, 7, 7, 1, 230400, 0x67dfe576
+0, 8, 8, 1, 230400, 0x67dfe576
+0, 9, 9, 1, 230400, 0x67dfe576
+0, 10, 10, 1, 230400, 0x67dfe576
+0, 11, 11, 1, 230400, 0x67dfe576
+0, 12, 12, 1, 230400, 0x67dfe576
+0, 13, 13, 1, 230400, 0x67dfe576
+0, 14, 14, 1, 230400, 0x67dfe576
+0, 15, 15, 1, 230400, 0x67dfe576
+0, 16, 16, 1, 230400, 0x67dfe576
+0, 17, 17, 1, 230400, 0x67dfe576
+0, 18, 18, 1, 230400, 0x67dfe576
+0, 19, 19, 1, 230400, 0x67dfe576
+0, 20, 20, 1, 230400, 0x67dfe576
+0, 21, 21, 1, 230400, 0x67dfe576
+0, 22, 22, 1, 230400, 0x67dfe576
+0, 23, 23, 1, 230400, 0x67dfe576
+0, 24, 24, 1, 230400, 0x67dfe576
diff --git a/tests/ref/fate/libavcodec-options b/tests/ref/fate/libavcodec-options
new file mode 100644
index 0000000000..ecdcac5cac
--- /dev/null
+++ b/tests/ref/fate/libavcodec-options
@@ -0,0 +1,161 @@
+testing avcodec_copy_context()
+dummy_v1_codec -> dummy_v1_codec
+closed:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+opened:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v1_codec -> dummy_v2_codec
+closed:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+opened:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+dummy_v1_codec -> dummy_v3_codec
+closed:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v3_codec: 128x128 prv: set
+opened:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v3_codec: 128x128 prv: set
+dummy_v1_codec -> dummy_v4_codec
+closed:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v4_codec: 128x128 prv: null
+opened:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v4_codec: 128x128 prv: null
+dummy_v1_codec -> NULL
+closed:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+NULL : 128x128 prv: null
+opened:
+dummy_v1_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+NULL : 128x128 prv: null
+dummy_v2_codec -> dummy_v1_codec
+closed:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+opened:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+dummy_v2_codec -> dummy_v2_codec
+closed:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+opened:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v2_codec -> dummy_v3_codec
+closed:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v3_codec: 128x128 prv: set
+opened:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v3_codec: 128x128 prv: set
+dummy_v2_codec -> dummy_v4_codec
+closed:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v4_codec: 128x128 prv: null
+opened:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+dummy_v4_codec: 128x128 prv: null
+dummy_v2_codec -> NULL
+closed:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+NULL : 128x128 prv: null
+opened:
+dummy_v2_codec: 128x128 prv: set opts: 1500100900 i'm src default value
+NULL : 128x128 prv: null
+dummy_v3_codec -> dummy_v1_codec
+closed:
+dummy_v3_codec: 128x128 prv: set
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+opened:
+dummy_v3_codec: 128x128 prv: set
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+dummy_v3_codec -> dummy_v2_codec
+closed:
+dummy_v3_codec: 128x128 prv: set
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+opened:
+dummy_v3_codec: 128x128 prv: set
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+dummy_v3_codec -> dummy_v3_codec
+closed:
+dummy_v3_codec: 128x128 prv: set
+dummy_v3_codec: 128x128 prv: set
+opened:
+dummy_v3_codec: 128x128 prv: set
+dummy_v3_codec: 128x128 prv: set
+dummy_v3_codec -> dummy_v4_codec
+closed:
+dummy_v3_codec: 128x128 prv: set
+dummy_v4_codec: 128x128 prv: null
+opened:
+dummy_v3_codec: 128x128 prv: set
+dummy_v4_codec: 128x128 prv: null
+dummy_v3_codec -> NULL
+closed:
+dummy_v3_codec: 128x128 prv: set
+NULL : 128x128 prv: null
+opened:
+dummy_v3_codec: 128x128 prv: set
+NULL : 128x128 prv: null
+dummy_v4_codec -> dummy_v1_codec
+closed:
+dummy_v4_codec: 128x128 prv: null
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+opened:
+dummy_v4_codec: 128x128 prv: null
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+dummy_v4_codec -> dummy_v2_codec
+closed:
+dummy_v4_codec: 128x128 prv: null
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+opened:
+dummy_v4_codec: 128x128 prv: null
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+dummy_v4_codec -> dummy_v3_codec
+closed:
+dummy_v4_codec: 128x128 prv: null
+dummy_v3_codec: 128x128 prv: set
+opened:
+dummy_v4_codec: 128x128 prv: null
+dummy_v3_codec: 128x128 prv: set
+dummy_v4_codec -> dummy_v4_codec
+closed:
+dummy_v4_codec: 128x128 prv: null
+dummy_v4_codec: 128x128 prv: null
+opened:
+dummy_v4_codec: 128x128 prv: null
+dummy_v4_codec: 128x128 prv: null
+dummy_v4_codec -> NULL
+closed:
+dummy_v4_codec: 128x128 prv: null
+NULL : 128x128 prv: null
+opened:
+dummy_v4_codec: 128x128 prv: null
+NULL : 128x128 prv: null
+NULL -> dummy_v1_codec
+closed:
+NULL : 128x128 prv: null
+dummy_v1_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+NULL -> dummy_v2_codec
+closed:
+NULL : 128x128 prv: null
+dummy_v2_codec: 128x128 prv: set opts: 667 i'm dest value before copy
+NULL -> dummy_v3_codec
+closed:
+NULL : 128x128 prv: null
+dummy_v3_codec: 128x128 prv: set
+NULL -> dummy_v4_codec
+closed:
+NULL : 128x128 prv: null
+dummy_v4_codec: 128x128 prv: null
+NULL -> NULL
+closed:
+NULL : 128x128 prv: null
+NULL : 128x128 prv: null
diff --git a/tests/ref/fate/lmlm4-demux b/tests/ref/fate/lmlm4-demux
index 0546135a46..95df3e6126 100644
--- a/tests/ref/fate/lmlm4-demux
+++ b/tests/ref/fate/lmlm4-demux
@@ -1,217 +1,218 @@
+#extradata 0: 28, 0x2f140538
#tb 0: 1001/30000
#tb 1: 1/90000
0, 0, -9223372036854775808, 1, 5951, 0xe9118e0d
1, 0, 0, 2160, 768, 0xaebcbebb
1, 2160, 2160, 2160, 768, 0xaebcbebb
-0, 1, -9223372036854775808, 1, 1672, 0x4b80d4ca
+0, 1, -9223372036854775808, 1, 1672, 0x4b80d4ca, F=0x0
1, 4320, 4320, 2160, 768, 0xaebcbebb
-0, 2, -9223372036854775808, 1, 1604, 0x99e1b0a7
+0, 2, -9223372036854775808, 1, 1604, 0x99e1b0a7, F=0x0
1, 6480, 6480, 2160, 768, 0x866fe37a
1, 8640, 8640, 2160, 768, 0x05d76890
-0, 3, -9223372036854775808, 1, 1204, 0x9559038a
+0, 3, -9223372036854775808, 1, 1204, 0x9559038a, F=0x0
1, 10800, 10800, 2160, 768, 0x858f5511
-0, 4, -9223372036854775808, 1, 1482, 0x60056564
+0, 4, -9223372036854775808, 1, 1482, 0x60056564, F=0x0
1, 12960, 12960, 2160, 768, 0x97cb65ef
-0, 5, -9223372036854775808, 1, 1105, 0xf508cef4
+0, 5, -9223372036854775808, 1, 1105, 0xf508cef4, F=0x0
1, 15120, 15120, 2160, 768, 0xe269742c
1, 17280, 17280, 2160, 768, 0xa6015f8d
-0, 6, -9223372036854775808, 1, 1193, 0xc8e0fd36
+0, 6, -9223372036854775808, 1, 1193, 0xc8e0fd36, F=0x0
1, 19440, 19440, 2160, 768, 0x759163e0
-0, 7, -9223372036854775808, 1, 1247, 0x8dd202e5
+0, 7, -9223372036854775808, 1, 1247, 0x8dd202e5, F=0x0
1, 21600, 21600, 2160, 768, 0xb1e16082
1, 23760, 23760, 2160, 768, 0x1b616429
-0, 8, -9223372036854775808, 1, 1367, 0xf59435e5
+0, 8, -9223372036854775808, 1, 1367, 0xf59435e5, F=0x0
1, 25920, 25920, 2160, 768, 0x7e4364f7
-0, 9, -9223372036854775808, 1, 1406, 0x68ba4a7e
+0, 9, -9223372036854775808, 1, 1406, 0x68ba4a7e, F=0x0
1, 28080, 28080, 2160, 768, 0x59bd64f7
-0, 10, -9223372036854775808, 1, 1262, 0x82c04123
+0, 10, -9223372036854775808, 1, 1262, 0x82c04123, F=0x0
1, 30240, 30240, 2160, 768, 0xc3116fc6
1, 32400, 32400, 2160, 768, 0x6a1c6b56
-0, 11, -9223372036854775808, 1, 1381, 0x02335cf9
+0, 11, -9223372036854775808, 1, 1381, 0x02335cf9, F=0x0
1, 34560, 34560, 2160, 768, 0x285a64cf
-0, 12, -9223372036854775808, 1, 1450, 0x7be46fd1
+0, 12, -9223372036854775808, 1, 1450, 0x7be46fd1, F=0x0
1, 36720, 36720, 2160, 768, 0x79b16d65
1, 38880, 38880, 2160, 768, 0x09b47635
-0, 13, -9223372036854775808, 1, 1362, 0x75cc381a
+0, 13, -9223372036854775808, 1, 1362, 0x75cc381a, F=0x0
1, 41040, 41040, 2160, 768, 0x81597446
-0, 14, -9223372036854775808, 1, 1409, 0x9ed74f3f
+0, 14, -9223372036854775808, 1, 1409, 0x9ed74f3f, F=0x0
1, 43200, 43200, 2160, 768, 0xfeb66eee
-0, 15, -9223372036854775808, 1, 1253, 0x82400ae1
+0, 15, -9223372036854775808, 1, 1253, 0x82400ae1, F=0x0
1, 45360, 45360, 2160, 768, 0x78557618
1, 47520, 47520, 2160, 768, 0x3af170bf
0, 16, -9223372036854775808, 1, 5499, 0xed286805
1, 49680, 49680, 2160, 768, 0xefbd6399
-0, 17, -9223372036854775808, 1, 1403, 0x483c4cbc
+0, 17, -9223372036854775808, 1, 1403, 0x483c4cbc, F=0x0
1, 51840, 51840, 2160, 768, 0xc98e7492
1, 54000, 54000, 2160, 768, 0x010d7149
-0, 18, -9223372036854775808, 1, 1632, 0xa9ebcd6c
+0, 18, -9223372036854775808, 1, 1632, 0xa9ebcd6c, F=0x0
1, 56160, 56160, 2160, 768, 0xce838b07
-0, 19, -9223372036854775808, 1, 1207, 0xc8580724
+0, 19, -9223372036854775808, 1, 1207, 0xc8580724, F=0x0
1, 58320, 58320, 2160, 768, 0xed18726c
-0, 20, -9223372036854775808, 1, 1289, 0x61fb2fd2
+0, 20, -9223372036854775808, 1, 1289, 0x61fb2fd2, F=0x0
1, 60480, 60480, 2160, 768, 0x017e6712
1, 62640, 62640, 2160, 768, 0x7f9268e9
-0, 21, -9223372036854775808, 1, 1230, 0xf348f53c
+0, 21, -9223372036854775808, 1, 1230, 0xf348f53c, F=0x0
1, 64800, 64800, 2160, 768, 0xf6f258fc
-0, 22, -9223372036854775808, 1, 1579, 0xa260b1ac
+0, 22, -9223372036854775808, 1, 1579, 0xa260b1ac, F=0x0
1, 66960, 66960, 2160, 768, 0x9a1a6f31
-0, 23, -9223372036854775808, 1, 949, 0x91849002
+0, 23, -9223372036854775808, 1, 949, 0x91849002, F=0x0
1, 69120, 69120, 2160, 768, 0x14b47b23
1, 71280, 71280, 2160, 768, 0x9bdc6a50
-0, 24, -9223372036854775808, 1, 786, 0x3e33576f
+0, 24, -9223372036854775808, 1, 786, 0x3e33576f, F=0x0
1, 73440, 73440, 2160, 768, 0x0fc46dab
-0, 25, -9223372036854775808, 1, 894, 0x9ac36a61
+0, 25, -9223372036854775808, 1, 894, 0x9ac36a61, F=0x0
1, 75600, 75600, 2160, 768, 0x6c387372
1, 77760, 77760, 2160, 768, 0x581e71cd
-0, 26, -9223372036854775808, 1, 1186, 0x6bfc116e
+0, 26, -9223372036854775808, 1, 1186, 0x6bfc116e, F=0x0
1, 79920, 79920, 2160, 768, 0x00cb785f
-0, 27, -9223372036854775808, 1, 1187, 0xcfc512ae
+0, 27, -9223372036854775808, 1, 1187, 0xcfc512ae, F=0x0
1, 82080, 82080, 2160, 768, 0x1dda7032
-0, 28, -9223372036854775808, 1, 1527, 0x5c2c965a
+0, 28, -9223372036854775808, 1, 1527, 0x5c2c965a, F=0x0
1, 84240, 84240, 2160, 768, 0xf57c7103
1, 86400, 86400, 2160, 768, 0x2d927183
-0, 29, -9223372036854775808, 1, 1536, 0x5ba7ac29
+0, 29, -9223372036854775808, 1, 1536, 0x5ba7ac29, F=0x0
1, 88560, 88560, 2160, 768, 0xdae86cdf
-0, 30, -9223372036854775808, 1, 1095, 0xce06eb96
+0, 30, -9223372036854775808, 1, 1095, 0xce06eb96, F=0x0
1, 90720, 90720, 2160, 768, 0x2a2f6c3c
1, 92880, 92880, 2160, 768, 0x44696eba
-0, 31, -9223372036854775808, 1, 1402, 0x642f6b0d
+0, 31, -9223372036854775808, 1, 1402, 0x642f6b0d, F=0x0
1, 95040, 95040, 2160, 768, 0xf67c71c4
0, 32, -9223372036854775808, 1, 5551, 0xf01a9c08
1, 97200, 97200, 2160, 768, 0xc1ce7237
-0, 33, -9223372036854775808, 1, 1211, 0x350206f7
+0, 33, -9223372036854775808, 1, 1211, 0x350206f7, F=0x0
1, 99360, 99360, 2160, 768, 0xd9c36ef5
1, 101520, 101520, 2160, 768, 0x63b06b03
-0, 34, -9223372036854775808, 1, 887, 0x08767619
+0, 34, -9223372036854775808, 1, 887, 0x08767619, F=0x0
1, 103680, 103680, 2160, 768, 0x8de97ebe
-0, 35, -9223372036854775808, 1, 1042, 0xcc81a9ed
+0, 35, -9223372036854775808, 1, 1042, 0xcc81a9ed, F=0x0
1, 105840, 105840, 2160, 768, 0xbf117c32
1, 108000, 108000, 2160, 768, 0x82897497
-0, 36, -9223372036854775808, 1, 1247, 0x6f320614
+0, 36, -9223372036854775808, 1, 1247, 0x6f320614, F=0x0
1, 110160, 110160, 2160, 768, 0x7a347abb
-0, 37, -9223372036854775808, 1, 1459, 0xd28975b5
+0, 37, -9223372036854775808, 1, 1459, 0xd28975b5, F=0x0
1, 112320, 112320, 2160, 768, 0xc99b691e
-0, 38, -9223372036854775808, 1, 1116, 0x1ab1e9db
+0, 38, -9223372036854775808, 1, 1116, 0x1ab1e9db, F=0x0
1, 114480, 114480, 2160, 768, 0xf4fc6e74
1, 116640, 116640, 2160, 768, 0x511d6ec4
-0, 39, -9223372036854775808, 1, 1110, 0x6411f66a
+0, 39, -9223372036854775808, 1, 1110, 0x6411f66a, F=0x0
1, 118800, 118800, 2160, 768, 0xb8c06b5f
-0, 40, -9223372036854775808, 1, 1282, 0xd468375d
+0, 40, -9223372036854775808, 1, 1282, 0xd468375d, F=0x0
1, 120960, 120960, 2160, 768, 0xf1776aed
1, 123120, 123120, 2160, 768, 0xe6fe7fb4
-0, 41, -9223372036854775808, 1, 1077, 0x1273c6e3
+0, 41, -9223372036854775808, 1, 1077, 0x1273c6e3, F=0x0
1, 125280, 125280, 2160, 768, 0x36907aff
-0, 42, -9223372036854775808, 1, 1043, 0x12dbd3ae
+0, 42, -9223372036854775808, 1, 1043, 0x12dbd3ae, F=0x0
1, 127440, 127440, 2160, 768, 0xddf666bb
-0, 43, -9223372036854775808, 1, 1087, 0x3e70d37a
+0, 43, -9223372036854775808, 1, 1087, 0x3e70d37a, F=0x0
1, 129600, 129600, 2160, 768, 0x8e896ebc
1, 131760, 131760, 2160, 768, 0x0aa47dfa
-0, 44, -9223372036854775808, 1, 992, 0x0651a71c
+0, 44, -9223372036854775808, 1, 992, 0x0651a71c, F=0x0
1, 133920, 133920, 2160, 768, 0xc1736811
-0, 45, -9223372036854775808, 1, 1012, 0x6a069f8c
+0, 45, -9223372036854775808, 1, 1012, 0x6a069f8c, F=0x0
1, 136080, 136080, 2160, 768, 0xb3e87009
-0, 46, -9223372036854775808, 1, 1320, 0x92803d69
+0, 46, -9223372036854775808, 1, 1320, 0x92803d69, F=0x0
1, 138240, 138240, 2160, 768, 0xf23e6c00
1, 140400, 140400, 2160, 768, 0x993a71d2
-0, 47, -9223372036854775808, 1, 1080, 0xe0ffbe95
+0, 47, -9223372036854775808, 1, 1080, 0xe0ffbe95, F=0x0
1, 142560, 142560, 2160, 768, 0xa53466dd
0, 48, -9223372036854775808, 1, 5639, 0x658ca26b
1, 144720, 144720, 2160, 768, 0xb43a74b0
1, 146880, 146880, 2160, 768, 0x348f615c
-0, 49, -9223372036854775808, 1, 1385, 0xbcb96241
+0, 49, -9223372036854775808, 1, 1385, 0xbcb96241, F=0x0
1, 149040, 149040, 2160, 768, 0x298f6e1b
-0, 50, -9223372036854775808, 1, 1142, 0x8c6df318
+0, 50, -9223372036854775808, 1, 1142, 0x8c6df318, F=0x0
1, 151200, 151200, 2160, 768, 0x5db469c8
-0, 51, -9223372036854775808, 1, 1175, 0xcac1faef
+0, 51, -9223372036854775808, 1, 1175, 0xcac1faef, F=0x0
1, 153360, 153360, 2160, 768, 0x08f16c2c
1, 155520, 155520, 2160, 768, 0x4a0474cb
-0, 52, -9223372036854775808, 1, 1091, 0xa937e32a
+0, 52, -9223372036854775808, 1, 1091, 0xa937e32a, F=0x0
1, 157680, 157680, 2160, 768, 0x077c760b
-0, 53, -9223372036854775808, 1, 1174, 0xfa50040d
+0, 53, -9223372036854775808, 1, 1174, 0xfa50040d, F=0x0
1, 159840, 159840, 2160, 768, 0xa5777c2e
1, 162000, 162000, 2160, 768, 0x0d157ea6
-0, 54, -9223372036854775808, 1, 1293, 0x0c8d2740
+0, 54, -9223372036854775808, 1, 1293, 0x0c8d2740, F=0x0
1, 164160, 164160, 2160, 768, 0x9bc26f86
-0, 55, -9223372036854775808, 1, 1262, 0x502c0c35
+0, 55, -9223372036854775808, 1, 1262, 0x502c0c35, F=0x0
1, 166320, 166320, 2160, 768, 0x1a72742d
-0, 56, -9223372036854775808, 1, 1038, 0x5e98c0cd
+0, 56, -9223372036854775808, 1, 1038, 0x5e98c0cd, F=0x0
1, 168480, 168480, 2160, 768, 0xa5bb6bbb
1, 170640, 170640, 2160, 768, 0x48496c4c
-0, 57, -9223372036854775808, 1, 1362, 0x256e43cf
+0, 57, -9223372036854775808, 1, 1362, 0x256e43cf, F=0x0
1, 172800, 172800, 2160, 768, 0x800d78f0
-0, 58, -9223372036854775808, 1, 1200, 0x29e6f055
+0, 58, -9223372036854775808, 1, 1200, 0x29e6f055, F=0x0
1, 174960, 174960, 2160, 768, 0x40db840c
1, 177120, 177120, 2160, 768, 0xadc96a6b
-0, 59, -9223372036854775808, 1, 1495, 0x88e9b973
+0, 59, -9223372036854775808, 1, 1495, 0x88e9b973, F=0x0
1, 179280, 179280, 2160, 768, 0xff986b03
-0, 60, -9223372036854775808, 1, 1386, 0x849297d2
+0, 60, -9223372036854775808, 1, 1386, 0x849297d2, F=0x0
1, 181440, 181440, 2160, 768, 0x152473d6
-0, 61, -9223372036854775808, 1, 1572, 0x63b7dc79
+0, 61, -9223372036854775808, 1, 1572, 0x63b7dc79, F=0x0
1, 183600, 183600, 2160, 768, 0x01567323
1, 185760, 185760, 2160, 768, 0xe5f26fe5
-0, 62, -9223372036854775808, 1, 1190, 0x32ccf4cb
+0, 62, -9223372036854775808, 1, 1190, 0x32ccf4cb, F=0x0
1, 187920, 187920, 2160, 768, 0xa8fd72cd
-0, 63, -9223372036854775808, 1, 1395, 0xa6ec4ae9
+0, 63, -9223372036854775808, 1, 1395, 0xa6ec4ae9, F=0x0
1, 190080, 190080, 2160, 768, 0x8857655b
0, 64, -9223372036854775808, 1, 5692, 0x81aed6f3
1, 192240, 192240, 2160, 768, 0x84017b13
1, 194400, 194400, 2160, 768, 0xe6a968b3
-0, 65, -9223372036854775808, 1, 1335, 0xe98a5497
+0, 65, -9223372036854775808, 1, 1335, 0xe98a5497, F=0x0
1, 196560, 196560, 2160, 768, 0xb03a7566
-0, 66, -9223372036854775808, 1, 1361, 0x8ae15ab5
+0, 66, -9223372036854775808, 1, 1361, 0x8ae15ab5, F=0x0
1, 198720, 198720, 2160, 768, 0x8bea5f62
1, 200880, 200880, 2160, 768, 0xac7570b0
-0, 67, -9223372036854775808, 1, 1525, 0xed2bc1e8
+0, 67, -9223372036854775808, 1, 1525, 0xed2bc1e8, F=0x0
1, 203040, 203040, 2160, 768, 0x11306fac
-0, 68, -9223372036854775808, 1, 1570, 0xba70d74b
+0, 68, -9223372036854775808, 1, 1570, 0xba70d74b, F=0x0
1, 205200, 205200, 2160, 768, 0xf2af5b28
-0, 69, -9223372036854775808, 1, 1349, 0xd97a687d
+0, 69, -9223372036854775808, 1, 1349, 0xd97a687d, F=0x0
1, 207360, 207360, 2160, 768, 0x3069681f
1, 209520, 209520, 2160, 768, 0x7ff07033
-0, 70, -9223372036854775808, 1, 1270, 0xca8c3ca8
+0, 70, -9223372036854775808, 1, 1270, 0xca8c3ca8, F=0x0
1, 211680, 211680, 2160, 768, 0xd74973f2
-0, 71, -9223372036854775808, 1, 1016, 0x32d0c81a
+0, 71, -9223372036854775808, 1, 1016, 0x32d0c81a, F=0x0
1, 213840, 213840, 2160, 768, 0xb3627304
1, 216000, 216000, 2160, 768, 0x11ff7589
-0, 72, -9223372036854775808, 1, 983, 0x536faa97
+0, 72, -9223372036854775808, 1, 983, 0x536faa97, F=0x0
1, 218160, 218160, 2160, 768, 0x4a156c63
-0, 73, -9223372036854775808, 1, 1111, 0x44ade015
+0, 73, -9223372036854775808, 1, 1111, 0x44ade015, F=0x0
1, 220320, 220320, 2160, 768, 0xcb036127
-0, 74, -9223372036854775808, 1, 1314, 0xce7c477d
+0, 74, -9223372036854775808, 1, 1314, 0xce7c477d, F=0x0
1, 222480, 222480, 2160, 768, 0x0b796bb9
1, 224640, 224640, 2160, 768, 0x1d516c35
-0, 75, -9223372036854775808, 1, 1005, 0x0196b491
+0, 75, -9223372036854775808, 1, 1005, 0x0196b491, F=0x0
1, 226800, 226800, 2160, 768, 0xa9146da1
-0, 76, -9223372036854775808, 1, 1162, 0xb8f6ebe6
+0, 76, -9223372036854775808, 1, 1162, 0xb8f6ebe6, F=0x0
1, 228960, 228960, 2160, 768, 0x6d176392
1, 231120, 231120, 2160, 768, 0x6f966269
-0, 77, -9223372036854775808, 1, 1440, 0xfca67c72
+0, 77, -9223372036854775808, 1, 1440, 0xfca67c72, F=0x0
1, 233280, 233280, 2160, 768, 0x7ee17724
-0, 78, -9223372036854775808, 1, 1437, 0x491181b1
+0, 78, -9223372036854775808, 1, 1437, 0x491181b1, F=0x0
1, 235440, 235440, 2160, 768, 0x3f07614a
-0, 79, -9223372036854775808, 1, 1261, 0xf0cd1898
+0, 79, -9223372036854775808, 1, 1261, 0xf0cd1898, F=0x0
1, 237600, 237600, 2160, 768, 0x49d56945
1, 239760, 239760, 2160, 768, 0x68eb660a
0, 80, -9223372036854775808, 1, 5638, 0x3a25a9f2
1, 241920, 241920, 2160, 768, 0xe7c96677
-0, 81, -9223372036854775808, 1, 1091, 0x67d9c693
+0, 81, -9223372036854775808, 1, 1091, 0x67d9c693, F=0x0
1, 244080, 244080, 2160, 768, 0x7dc07a35
1, 246240, 246240, 2160, 768, 0x1e9c6397
-0, 82, -9223372036854775808, 1, 875, 0x52147bb1
+0, 82, -9223372036854775808, 1, 875, 0x52147bb1, F=0x0
1, 248400, 248400, 2160, 768, 0x93ef5de4
-0, 83, -9223372036854775808, 1, 1188, 0x8522000f
+0, 83, -9223372036854775808, 1, 1188, 0x8522000f, F=0x0
1, 250560, 250560, 2160, 768, 0x34af6803
-0, 84, -9223372036854775808, 1, 1360, 0x89b82e7b
+0, 84, -9223372036854775808, 1, 1360, 0x89b82e7b, F=0x0
1, 252720, 252720, 2160, 768, 0x77e068be
1, 254880, 254880, 2160, 768, 0x65e274de
-0, 85, -9223372036854775808, 1, 1378, 0xe8644914
+0, 85, -9223372036854775808, 1, 1378, 0xe8644914, F=0x0
1, 257040, 257040, 2160, 768, 0xb7ad6a8a
-0, 86, -9223372036854775808, 1, 1194, 0x89fef83d
+0, 86, -9223372036854775808, 1, 1194, 0x89fef83d, F=0x0
1, 259200, 259200, 2160, 768, 0x84b3635f
-0, 87, -9223372036854775808, 1, 1422, 0x99daa18b
+0, 87, -9223372036854775808, 1, 1422, 0x99daa18b, F=0x0
1, 261360, 261360, 2160, 768, 0x066b78f2
1, 263520, 263520, 2160, 768, 0xda137428
-0, 88, -9223372036854775808, 1, 1049, 0x72a9cec1
+0, 88, -9223372036854775808, 1, 1049, 0x72a9cec1, F=0x0
1, 265680, 265680, 2160, 768, 0xfd6c7597
-0, 89, -9223372036854775808, 1, 1327, 0x7d15307c
+0, 89, -9223372036854775808, 1, 1327, 0x7d15307c, F=0x0
1, 267840, 267840, 2160, 768, 0x8d766d40
diff --git a/tests/ref/fate/lossless-tak b/tests/ref/fate/lossless-tak
new file mode 100644
index 0000000000..9e9ba47652
--- /dev/null
+++ b/tests/ref/fate/lossless-tak
@@ -0,0 +1 @@
+CRC=0x4ec0971f
diff --git a/tests/ref/fate/lossless-tta-encrypted b/tests/ref/fate/lossless-tta-encrypted
new file mode 100644
index 0000000000..39aec95e88
--- /dev/null
+++ b/tests/ref/fate/lossless-tta-encrypted
@@ -0,0 +1 @@
+CRC=0x4563745f
diff --git a/tests/ref/fate/mapchan-6ch-extract-2 b/tests/ref/fate/mapchan-6ch-extract-2
new file mode 100644
index 0000000000..435cbec17c
--- /dev/null
+++ b/tests/ref/fate/mapchan-6ch-extract-2
@@ -0,0 +1,2 @@
+955514d4a026a4a48695866d2ec904d0
+498a49e692ee2e3c454863654275c4bb
diff --git a/tests/ref/fate/mapchan-6ch-extract-2-downmix-mono b/tests/ref/fate/mapchan-6ch-extract-2-downmix-mono
new file mode 100644
index 0000000000..a47c85cd6b
--- /dev/null
+++ b/tests/ref/fate/mapchan-6ch-extract-2-downmix-mono
@@ -0,0 +1 @@
+2727e5418eb5b8f89954f140d9f3a19a
diff --git a/tests/ref/fate/mapchan-silent-mono b/tests/ref/fate/mapchan-silent-mono
new file mode 100644
index 0000000000..f720c318f4
--- /dev/null
+++ b/tests/ref/fate/mapchan-silent-mono
@@ -0,0 +1 @@
+16dc73c037897dff9b1d3e3d8561dc73
diff --git a/tests/ref/fate/mjpegb b/tests/ref/fate/mjpegb
index e4887f4af9..ef8a00b23e 100644
--- a/tests/ref/fate/mjpegb
+++ b/tests/ref/fate/mjpegb
@@ -1,11 +1,11 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 38400, 0x45311080
-0, 100, 100, 0, 38400, 0x9474f731
-0, 200, 200, 0, 38400, 0x429ebb12
-0, 300, 300, 0, 38400, 0x472c199a
-0, 400, 400, 0, 38400, 0xefd49dae
-0, 500, 500, 0, 38400, 0x78627fa9
-0, 600, 600, 0, 38400, 0x2a8d9148
-0, 700, 700, 0, 38400, 0x21cc6738
-0, 800, 800, 0, 38400, 0x0bc4703f
-0, 900, 900, 0, 38400, 0x1ddcc035
+#tb 0: 1/12
+0, 0, 0, 1, 38400, 0x45311080
+0, 1, 1, 1, 38400, 0x9474f731
+0, 2, 2, 1, 38400, 0x429ebb12
+0, 3, 3, 1, 38400, 0x472c199a
+0, 4, 4, 1, 38400, 0xefd49dae
+0, 5, 5, 1, 38400, 0x78627fa9
+0, 6, 6, 1, 38400, 0x2a8d9148
+0, 7, 7, 1, 38400, 0x21cc6738
+0, 8, 8, 1, 38400, 0x0bc4703f
+0, 9, 9, 1, 38400, 0x1ddcc035
diff --git a/tests/ref/fate/mkv b/tests/ref/fate/mkv
new file mode 100644
index 0000000000..aea378a881
--- /dev/null
+++ b/tests/ref/fate/mkv
@@ -0,0 +1,219 @@
+#extradata 0: 35, 0xc3b20b70
+#extradata 1: 2, 0x00b200a1
+#tb 0: 1/1000
+#tb 1: 1/1000
+0, -42, 0, 41, 63501, 0x139d4c99
+0, 0, 84, 41, 5368, 0xd964b678, F=0x0
+1, 8, 8, 21, 528, 0x3c990ddf
+1, 29, 29, 21, 510, 0xc16e0719
+0, 42, 42, 41, 1840, 0x097b6726, F=0x0
+1, 50, 50, 21, 500, 0x6248f603
+1, 71, 71, 22, 491, 0xe767f705
+0, 84, 167, 41, 7168, 0xaa5913ed, F=0x0
+1, 93, 93, 21, 506, 0x4340f3f3
+1, 114, 114, 21, 492, 0xf11c0210
+0, 125, 125, 41, 2129, 0x6ab0db3e, F=0x0
+1, 135, 135, 21, 502, 0x314b007e
+1, 156, 156, 22, 507, 0x76de0162
+0, 167, 250, 41, 7230, 0x3fd63940, F=0x0
+1, 179, 179, 21, 501, 0x0538fa45
+1, 200, 200, 21, 521, 0xc89f06d2
+0, 209, 209, 41, 2114, 0xfceafb26, F=0x0
+1, 221, 221, 21, 646, 0x8d8d3599
+1, 242, 242, 22, 661, 0x222242de
+0, 250, 334, 41, 63420, 0x5ca6250f, F=0x0
+1, 264, 264, 21, 609, 0xc0dc255c
+1, 285, 285, 21, 619, 0x9ac52dd1
+0, 292, 292, 41, 16751, 0xf293ab46, F=0x0
+0, 292, 417, 41, 22029, 0x3696462b, F=0x0
+1, 306, 306, 21, 574, 0xf6410d4d
+1, 327, 327, 22, 565, 0xfd561191
+1, 350, 350, 21, 713, 0x48425147
+1, 371, 371, 21, 537, 0x09bbf515
+0, 375, 375, 41, 5044, 0xa0344ae6, F=0x0
+1, 392, 392, 21, 486, 0x7946e28c
+1, 413, 413, 22, 499, 0xa770f22a
+0, 417, 500, 41, 25289, 0x46f9a219, F=0x0
+1, 435, 435, 21, 506, 0x355ef81d
+1, 456, 456, 21, 474, 0x6d24e2c5
+0, 459, 459, 41, 12871, 0x23e570c4, F=0x0
+1, 477, 477, 21, 494, 0x7d77e90f
+1, 498, 498, 22, 524, 0x6c82fdd2
+0, 500, 584, 41, 29580, 0xd051ad0c, F=0x0
+1, 520, 520, 21, 482, 0xe625f255
+1, 541, 541, 21, 533, 0xed00fd16
+0, 542, 542, 41, 9221, 0xfa1bdf6c, F=0x0
+1, 562, 562, 21, 524, 0x65cdf879
+1, 583, 583, 22, 533, 0xee26f570
+0, 584, 667, 41, 22238, 0x4e0daf3e, F=0x0
+1, 605, 605, 21, 621, 0xed9f23cc
+0, 625, 625, 41, 7627, 0xc566337e, F=0x0
+1, 626, 626, 21, 400, 0xe4fdb43a
+1, 647, 647, 21, 428, 0xd7eacd61
+0, 667, 750, 41, 23124, 0x3bad1f16, F=0x0
+1, 668, 668, 22, 442, 0xef1fda0b
+1, 691, 691, 21, 450, 0x1c58e44b
+0, 709, 709, 41, 7093, 0x3ab77cce, F=0x0
+1, 712, 712, 21, 487, 0x0e5feab7
+1, 733, 733, 21, 465, 0x984adca9
+0, 750, 834, 41, 23210, 0xa7851bbf, F=0x0
+1, 754, 754, 22, 479, 0x0960e535
+1, 776, 776, 21, 489, 0x2f3ffc02
+0, 792, 792, 41, 16045, 0x33039eb5, F=0x0
+1, 797, 797, 21, 505, 0x541aff95
+1, 818, 818, 21, 485, 0xb7a5e7f8
+0, 834, 917, 41, 24859, 0x317ea0f2, F=0x0
+1, 839, 839, 22, 537, 0xb0dd1072
+1, 862, 862, 21, 485, 0x6e9eee58
+0, 875, 875, 41, 7589, 0x02a8e5d5, F=0x0
+1, 883, 883, 21, 480, 0x0a6fec0b
+1, 904, 904, 21, 496, 0x6ff8ee65
+0, 917, 959, 41, 19208, 0xdfb1a109, F=0x0
+1, 925, 925, 21, 505, 0x75a308b8
+1, 946, 946, 21, 512, 0x9628f3da
+0, 959, 2000, 41, 60241, 0x43fcc627
+1, 967, 967, 22, 506, 0xefc901cf
+1, 990, 990, 21, 487, 0x1fd3edc8
+1, 1011, 1011, 21, 485, 0x8ccde513
+1, 1993, 1993, 21, 459, 0x725ede33
+0, 2000, 2084, 41, 23528, 0xc1dd888a, F=0x0
+1, 2014, 2014, 21, 481, 0x2cd7e611
+1, 2035, 2035, 21, 473, 0x14f2d777
+0, 2042, 2042, 41, 9206, 0x8f8cb89b, F=0x0
+1, 2056, 2056, 21, 543, 0x0f6dfccf
+1, 2077, 2077, 22, 489, 0x8049f5df
+0, 2084, 2167, 41, 34864, 0x3a343fe0, F=0x0
+1, 2099, 2099, 21, 480, 0xaa82edfc
+1, 2120, 2120, 21, 505, 0xea87f3e9
+0, 2125, 2125, 41, 12516, 0x885c8e4d, F=0x0
+1, 2141, 2141, 21, 474, 0x0760e6a1
+1, 2162, 2162, 22, 547, 0xcde40a72
+0, 2167, 2250, 41, 21215, 0x4428040b, F=0x0
+1, 2184, 2184, 21, 606, 0x4e401ec6
+1, 2205, 2205, 21, 611, 0xd13e18b6
+0, 2209, 2209, 41, 11811, 0xfe46f6c7, F=0x0
+1, 2226, 2226, 21, 492, 0xe2a3ea95
+1, 2247, 2247, 22, 582, 0x15fe1df5
+0, 2250, 2334, 41, 18643, 0xdcd87177, F=0x0
+1, 2269, 2269, 21, 455, 0x3753cfd3
+1, 2290, 2290, 21, 467, 0x9342cfed
+0, 2292, 2292, 41, 4578, 0x0bacbdaf, F=0x0
+1, 2311, 2311, 21, 422, 0x080ec43e
+1, 2332, 2332, 22, 466, 0xefb8e9aa
+0, 2334, 2417, 41, 25403, 0x49348e8b, F=0x0
+1, 2355, 2355, 21, 482, 0x2455e264
+0, 2375, 2375, 41, 7254, 0xe5c672b9, F=0x0
+1, 2376, 2376, 21, 471, 0xb370df1e
+1, 2397, 2397, 21, 461, 0x01addfe6
+0, 2417, 2500, 41, 25215, 0x1149c259, F=0x0
+1, 2418, 2418, 22, 566, 0x93760a5d
+1, 2440, 2440, 21, 618, 0x4e8e2f95
+0, 2459, 2459, 41, 14257, 0x38956a4d, F=0x0
+1, 2461, 2461, 21, 612, 0xc79128bc
+1, 2482, 2482, 21, 594, 0x169d1975
+0, 2500, 2584, 41, 36619, 0xca6497c5, F=0x0
+1, 2503, 2503, 22, 488, 0xb218e907
+1, 2526, 2526, 21, 437, 0xb180c83f
+0, 2542, 2542, 41, 13152, 0x4ea52247, F=0x0
+1, 2547, 2547, 21, 432, 0x85f8cf2b
+1, 2568, 2568, 21, 469, 0x65d0e38e
+0, 2584, 2667, 41, 31751, 0xb0140e79, F=0x0
+1, 2589, 2589, 22, 473, 0xb4dee328
+1, 2611, 2611, 21, 462, 0xd95cd547
+0, 2625, 2625, 41, 13619, 0x97308292, F=0x0
+1, 2632, 2632, 21, 470, 0x3638f48d
+1, 2653, 2653, 21, 558, 0x93c3121b
+0, 2667, 2750, 41, 32851, 0x014d2abc, F=0x0
+1, 2674, 2674, 22, 486, 0x5983ed52
+1, 2696, 2696, 21, 507, 0x572af3c3
+0, 2709, 2709, 41, 16915, 0x3597bc67, F=0x0
+1, 2717, 2717, 21, 480, 0xe3b3e16c
+1, 2738, 2738, 21, 492, 0x9443f00e
+0, 2750, 2834, 41, 35380, 0x728cd77a, F=0x0
+1, 2759, 2759, 22, 480, 0x7845ea30
+1, 2781, 2781, 21, 480, 0x7d01e1a2
+0, 2792, 2792, 41, 12780, 0x84c38c29, F=0x0
+1, 2802, 2802, 21, 505, 0x17d6f18b
+1, 2823, 2823, 21, 506, 0xca09ee14
+0, 2834, 2917, 41, 26049, 0x3788982a, F=0x0
+1, 2844, 2844, 22, 479, 0x0383f05a
+1, 2867, 2867, 21, 499, 0xa3b5e804
+0, 2875, 2875, 41, 11796, 0x0cbff503, F=0x0
+1, 2888, 2888, 21, 494, 0x0970e72e
+1, 2909, 2909, 21, 484, 0x6f34da96
+0, 2917, 2959, 41, 16638, 0x097c9345, F=0x0
+1, 2930, 2930, 21, 492, 0x5282e9aa
+1, 2951, 2951, 21, 487, 0x6f19e15e
+0, 2959, 3000, 41, 64129, 0xc13b91ac
+1, 2972, 2972, 22, 500, 0x17aef81a
+1, 2995, 2995, 21, 510, 0xa323f6e6
+0, 3000, 3084, 41, 19338, 0xfe901382, F=0x0
+1, 3016, 3016, 21, 492, 0x49d7e74f
+1, 3038, 3038, 21, 483, 0xa78deadb
+0, 3042, 3042, 41, 4643, 0x5a05768b, F=0x0
+1, 3059, 3059, 21, 639, 0xf2c237e9
+1, 3080, 3080, 21, 661, 0xcd604711
+0, 3084, 3167, 41, 25932, 0x395e1d01, F=0x0
+1, 3101, 3101, 22, 647, 0xb8ee3acf
+1, 3123, 3123, 21, 575, 0x3303118e
+0, 3125, 3125, 41, 5301, 0x2aacb15c, F=0x0
+1, 3144, 3144, 21, 506, 0x2063eef7
+1, 3165, 3165, 21, 518, 0x7661f08e
+0, 3167, 3250, 41, 24089, 0x5cf78354, F=0x0
+1, 3186, 3186, 22, 534, 0x2858f90e
+1, 3208, 3208, 21, 520, 0xd596f460
+0, 3209, 3209, 41, 5837, 0x1c16cfad, F=0x0
+1, 3229, 3229, 21, 496, 0xc2a6efed
+0, 3250, 3334, 41, 26754, 0x4cf1ad04, F=0x0
+1, 3250, 3250, 21, 470, 0xcff5e778
+1, 3271, 3271, 22, 476, 0xcb63e48a
+0, 3292, 3292, 41, 11067, 0x8b0b776f, F=0x0
+1, 3293, 3293, 21, 516, 0xaea8f74b
+1, 3314, 3314, 21, 503, 0x5998f00d
+0, 3334, 3417, 41, 28780, 0xc610f024, F=0x0
+1, 3335, 3335, 21, 488, 0xd818dd28
+1, 3356, 3356, 22, 495, 0x2662f5b5
+0, 3375, 3375, 41, 14863, 0xd58ed8f0, F=0x0
+1, 3379, 3379, 21, 499, 0x6884ec30
+1, 3400, 3400, 21, 496, 0x556bdc0e
+0, 3417, 3500, 41, 24790, 0x71e32bae, F=0x0
+1, 3421, 3421, 21, 524, 0xa756f115
+1, 3442, 3442, 22, 505, 0xd332f37b
+0, 3459, 3459, 41, 9123, 0x6c72b7a3, F=0x0
+1, 3464, 3464, 21, 494, 0xa380e41e
+1, 3485, 3485, 21, 513, 0xf26bf0a9
+0, 3500, 3584, 41, 24706, 0x9bdd9247, F=0x0
+1, 3506, 3506, 21, 515, 0x28fffe2a
+1, 3527, 3527, 22, 506, 0xc5a2f83c
+0, 3542, 3542, 41, 8105, 0x85b8ff64, F=0x0
+1, 3550, 3550, 21, 510, 0xa10bf9c7
+1, 3571, 3571, 21, 507, 0x93d1e650
+0, 3584, 3667, 41, 25402, 0xe4622ee0, F=0x0
+1, 3592, 3592, 21, 506, 0x1a36f285
+1, 3613, 3613, 22, 522, 0xd7a1f5e4
+0, 3625, 3625, 41, 9693, 0x910910bc, F=0x0
+1, 3635, 3635, 21, 511, 0x2e79fa62
+1, 3656, 3656, 21, 516, 0xfda2ef86
+0, 3667, 3750, 41, 31403, 0xff9934ee, F=0x0
+1, 3677, 3677, 21, 497, 0xd65cf156
+1, 3698, 3698, 22, 480, 0xde3be560
+0, 3709, 3709, 41, 13936, 0x9b6aec9e, F=0x0
+1, 3720, 3720, 21, 514, 0x7d8cf49f
+1, 3741, 3741, 21, 667, 0x7a483dec
+0, 3750, 3834, 41, 28639, 0x620b80de, F=0x0
+1, 3762, 3762, 21, 640, 0x7cd92998
+1, 3783, 3783, 22, 504, 0xe3bbf106
+0, 3792, 3792, 41, 18769, 0xf51353c4, F=0x0
+1, 3805, 3805, 21, 498, 0xe8c6f489
+1, 3826, 3826, 21, 489, 0x620df125
+0, 3834, 3917, 41, 30240, 0x48151fb3, F=0x0
+1, 3847, 3847, 21, 505, 0x7d73e570
+1, 3868, 3868, 22, 496, 0xc211f6c6
+0, 3875, 3875, 41, 13391, 0x4f3f112d, F=0x0
+1, 3891, 3891, 21, 483, 0x126fe774
+1, 3912, 3912, 21, 479, 0xac88db91
+0, 3917, 3959, 41, 19896, 0x0e667f6e, F=0x0
+1, 3933, 3933, 21, 480, 0x545df57b
+1, 3954, 3954, 21, 473, 0x9a37e7ef
+1, 3975, 3975, 22, 472, 0x4c8ee70d
+1, 3998, 3998, 21, 508, 0x5c6bf8f3
diff --git a/tests/ref/fate/mlv-demux b/tests/ref/fate/mlv-demux
new file mode 100644
index 0000000000..8c59012805
--- /dev/null
+++ b/tests/ref/fate/mlv-demux
@@ -0,0 +1 @@
+CRC=0x937f8af3
diff --git a/tests/ref/fate/motionpixels b/tests/ref/fate/motionpixels
index 97d8edfb43..c875275b89 100644
--- a/tests/ref/fate/motionpixels
+++ b/tests/ref/fate/motionpixels
@@ -1,112 +1,112 @@
#tb 0: 66667/1000000
0, 0, 0, 1, 230400, 0xee05b509
-0, 1, 1, 1, 230400, 0x71048964
-0, 2, 2, 1, 230400, 0x2ebe4ba1
-0, 3, 3, 1, 230400, 0xeedc45a6
-0, 4, 4, 1, 230400, 0x218e8656
-0, 5, 5, 1, 230400, 0x5792b17e
-0, 6, 6, 1, 230400, 0x51b0a062
-0, 7, 7, 1, 230400, 0x5dc4fd9c
-0, 8, 8, 1, 230400, 0x9b0261b1
-0, 9, 9, 1, 230400, 0x35086ffc
-0, 10, 10, 1, 230400, 0xcf9352ff
-0, 11, 11, 1, 230400, 0x0b5139a1
-0, 12, 12, 1, 230400, 0x22e8a31e
-0, 13, 13, 1, 230400, 0x82f61a81
-0, 14, 14, 1, 230400, 0xc5741ab5
-0, 15, 15, 1, 230400, 0xb5e7b2ff
-0, 16, 16, 1, 230400, 0x583289ca
-0, 17, 17, 1, 230400, 0xee52afbb
-0, 18, 18, 1, 230400, 0xfdb4dc1a
-0, 19, 19, 1, 230400, 0xf5ce99c0
-0, 20, 20, 1, 230400, 0xae222255
-0, 21, 21, 1, 230400, 0xc4f4439d
-0, 22, 22, 1, 230400, 0x1758f224
-0, 23, 23, 1, 230400, 0x5f517926
-0, 24, 24, 1, 230400, 0x73a8bed8
-0, 25, 25, 1, 230400, 0x7ef8410c
-0, 26, 26, 1, 230400, 0xfcb693c7
-0, 27, 27, 1, 230400, 0x5292832e
-0, 28, 28, 1, 230400, 0x591261d7
-0, 29, 29, 1, 230400, 0x28cca691
-0, 30, 30, 1, 230400, 0x22cf40ef
-0, 31, 31, 1, 230400, 0x517b10f9
-0, 32, 32, 1, 230400, 0x8197e939
-0, 33, 33, 1, 230400, 0x9654ffdb
-0, 34, 34, 1, 230400, 0x803f10dd
-0, 35, 35, 1, 230400, 0xff9f67af
-0, 36, 36, 1, 230400, 0x4847244c
-0, 37, 37, 1, 230400, 0xff31638f
-0, 38, 38, 1, 230400, 0x9692def5
-0, 39, 39, 1, 230400, 0x67f0a5fb
-0, 40, 40, 1, 230400, 0xce192074
-0, 41, 41, 1, 230400, 0x33d6c4a5
-0, 42, 42, 1, 230400, 0xaf7b5a03
-0, 43, 43, 1, 230400, 0xd956b0c0
-0, 44, 44, 1, 230400, 0x58ff1a65
-0, 45, 45, 1, 230400, 0x044758a1
-0, 46, 46, 1, 230400, 0xe8045b65
-0, 47, 47, 1, 230400, 0xf504c5fb
-0, 48, 48, 1, 230400, 0x17a9a2b0
-0, 49, 49, 1, 230400, 0xf68bab8c
-0, 50, 50, 1, 230400, 0xd06dd0cb
-0, 51, 51, 1, 230400, 0xc47d2673
-0, 52, 52, 1, 230400, 0x2112f291
-0, 53, 53, 1, 230400, 0x4c07c83c
-0, 54, 54, 1, 230400, 0x22ca0113
-0, 55, 55, 1, 230400, 0x25b0c8b1
-0, 56, 56, 1, 230400, 0xb6afc645
-0, 57, 57, 1, 230400, 0x663b1c09
-0, 58, 58, 1, 230400, 0x9006ef1f
-0, 59, 59, 1, 230400, 0x54f81b11
-0, 60, 60, 1, 230400, 0x456b79f2
-0, 61, 61, 1, 230400, 0xb08f24d0
-0, 62, 62, 1, 230400, 0x652ad875
-0, 63, 63, 1, 230400, 0xc6ecd67f
-0, 64, 64, 1, 230400, 0x78dad721
-0, 65, 65, 1, 230400, 0x1d2a4f71
-0, 66, 66, 1, 230400, 0xc71721d1
-0, 67, 67, 1, 230400, 0x64e3a7df
-0, 68, 68, 1, 230400, 0x3bb18e71
-0, 69, 69, 1, 230400, 0xb571d58c
-0, 70, 70, 1, 230400, 0xdae6ed5c
-0, 71, 71, 1, 230400, 0xdd91504b
-0, 72, 72, 1, 230400, 0xd5a807a5
-0, 73, 73, 1, 230400, 0x39a67b03
-0, 74, 74, 1, 230400, 0xe245c8ac
-0, 75, 75, 1, 230400, 0x5b0d7858
-0, 76, 76, 1, 230400, 0x501b8097
-0, 77, 77, 1, 230400, 0xf7b10d48
-0, 78, 78, 1, 230400, 0x769db0bd
-0, 79, 79, 1, 230400, 0x600f1086
-0, 80, 80, 1, 230400, 0x874f5565
-0, 81, 81, 1, 230400, 0x14322f73
-0, 82, 82, 1, 230400, 0x0eaa36a5
-0, 83, 83, 1, 230400, 0x97178d13
-0, 84, 84, 1, 230400, 0xd4c7a0d1
-0, 85, 85, 1, 230400, 0x1d424ec8
-0, 86, 86, 1, 230400, 0x695ad8d9
-0, 87, 87, 1, 230400, 0xe7cc3ecf
-0, 88, 88, 1, 230400, 0xfd25fd8c
-0, 89, 89, 1, 230400, 0xef4bc203
-0, 90, 90, 1, 230400, 0x2a113bec
-0, 91, 91, 1, 230400, 0x6e7ad403
-0, 92, 92, 1, 230400, 0xc6714d2b
-0, 93, 93, 1, 230400, 0x77df8ba6
-0, 94, 94, 1, 230400, 0xcd283106
-0, 95, 95, 1, 230400, 0xcb95676f
-0, 96, 96, 1, 230400, 0xb0b70393
-0, 97, 97, 1, 230400, 0x4c40bd63
-0, 98, 98, 1, 230400, 0x557e8ccf
-0, 99, 99, 1, 230400, 0x9d5934b2
-0, 100, 100, 1, 230400, 0x43c1793f
-0, 101, 101, 1, 230400, 0x0232361e
-0, 102, 102, 1, 230400, 0x92ed91e4
-0, 103, 103, 1, 230400, 0x99769789
-0, 104, 104, 1, 230400, 0xd49c2c5b
-0, 105, 105, 1, 230400, 0x66b03495
-0, 106, 106, 1, 230400, 0xb88a4658
-0, 107, 107, 1, 230400, 0x9c21e4c2
-0, 108, 108, 1, 230400, 0xb343f372
-0, 109, 109, 1, 230400, 0xf7f1e588
-0, 110, 110, 1, 230400, 0x9682bdb2
+0, 1, 1, 1, 230400, 0x23b28b24
+0, 2, 2, 1, 230400, 0x4a4d6007
+0, 3, 3, 1, 230400, 0xe5550693
+0, 4, 4, 1, 230400, 0xad4905a3
+0, 5, 5, 1, 230400, 0xc83b9030
+0, 6, 6, 1, 230400, 0xbc73a26a
+0, 7, 7, 1, 230400, 0x7065ff8a
+0, 8, 8, 1, 230400, 0x65bc7675
+0, 9, 9, 1, 230400, 0xc245737f
+0, 10, 10, 1, 230400, 0x77e6c1ed
+0, 11, 11, 1, 230400, 0x6761d73a
+0, 12, 12, 1, 230400, 0x6207b8f8
+0, 13, 13, 1, 230400, 0xa3691862
+0, 14, 14, 1, 230400, 0x83fbfc24
+0, 15, 15, 1, 230400, 0xe1c34ef0
+0, 16, 16, 1, 230400, 0xd7b50e8e
+0, 17, 17, 1, 230400, 0x5b5e2f29
+0, 18, 18, 1, 230400, 0xca7825e5
+0, 19, 19, 1, 230400, 0xb4c7b4a9
+0, 20, 20, 1, 230400, 0xc35513b5
+0, 21, 21, 1, 230400, 0x36117834
+0, 22, 22, 1, 230400, 0x8af035d7
+0, 23, 23, 1, 230400, 0x25c50a2e
+0, 24, 24, 1, 230400, 0x52f54107
+0, 25, 25, 1, 230400, 0xaddca5f9
+0, 26, 26, 1, 230400, 0x3b1fe64c
+0, 27, 27, 1, 230400, 0xcd52de15
+0, 28, 28, 1, 230400, 0xfaa4f7fa
+0, 29, 29, 1, 230400, 0xce5b3221
+0, 30, 30, 1, 230400, 0xb2c3d9ba
+0, 31, 31, 1, 230400, 0xf6ec95e9
+0, 32, 32, 1, 230400, 0xfa7ebd18
+0, 33, 33, 1, 230400, 0xb6e50465
+0, 34, 34, 1, 230400, 0xd48ceee9
+0, 35, 35, 1, 230400, 0x333605cf
+0, 36, 36, 1, 230400, 0xe7ccf362
+0, 37, 37, 1, 230400, 0x39f07b83
+0, 38, 38, 1, 230400, 0xd6450b2e
+0, 39, 39, 1, 230400, 0x2029ec12
+0, 40, 40, 1, 230400, 0x15d7762e
+0, 41, 41, 1, 230400, 0x0d69506d
+0, 42, 42, 1, 230400, 0xcf2ef066
+0, 43, 43, 1, 230400, 0x2c145df0
+0, 44, 44, 1, 230400, 0x153d7fe7
+0, 45, 45, 1, 230400, 0x98846aea
+0, 46, 46, 1, 230400, 0xc0347d4e
+0, 47, 47, 1, 230400, 0xda7a58a8
+0, 48, 48, 1, 230400, 0x5724c05e
+0, 49, 49, 1, 230400, 0x9805237b
+0, 50, 50, 1, 230400, 0x2f5f0d70
+0, 51, 51, 1, 230400, 0xb1271014
+0, 52, 52, 1, 230400, 0x6cb29d9c
+0, 53, 53, 1, 230400, 0x4f91fdb4
+0, 54, 54, 1, 230400, 0x274b3f30
+0, 55, 55, 1, 230400, 0xdfc508e8
+0, 56, 56, 1, 230400, 0x16e974ef
+0, 57, 57, 1, 230400, 0x98fae336
+0, 58, 58, 1, 230400, 0xbf265f84
+0, 59, 59, 1, 230400, 0x75cf323b
+0, 60, 60, 1, 230400, 0xdb3481f7
+0, 61, 61, 1, 230400, 0xb8453df5
+0, 62, 62, 1, 230400, 0xd4598deb
+0, 63, 63, 1, 230400, 0x4dc19cf6
+0, 64, 64, 1, 230400, 0xa8d1b340
+0, 65, 65, 1, 230400, 0x1f98aa27
+0, 66, 66, 1, 230400, 0x505c0687
+0, 67, 67, 1, 230400, 0x86179997
+0, 68, 68, 1, 230400, 0x7e28cc7d
+0, 69, 69, 1, 230400, 0x0a81c0bc
+0, 70, 70, 1, 230400, 0x71cc0c9a
+0, 71, 71, 1, 230400, 0x8c01340f
+0, 72, 72, 1, 230400, 0x4afea48a
+0, 73, 73, 1, 230400, 0x7dc88c26
+0, 74, 74, 1, 230400, 0x4155fbbb
+0, 75, 75, 1, 230400, 0xb1ec2d6b
+0, 76, 76, 1, 230400, 0x6986ee65
+0, 77, 77, 1, 230400, 0x8ff9a311
+0, 78, 78, 1, 230400, 0x36c21c52
+0, 79, 79, 1, 230400, 0xdb0fad2e
+0, 80, 80, 1, 230400, 0xc7a83c34
+0, 81, 81, 1, 230400, 0x8bd97389
+0, 82, 82, 1, 230400, 0x6dd8f0d6
+0, 83, 83, 1, 230400, 0x228e2076
+0, 84, 84, 1, 230400, 0x22544f03
+0, 85, 85, 1, 230400, 0x938084ef
+0, 86, 86, 1, 230400, 0xb002cd81
+0, 87, 87, 1, 230400, 0xe58d3339
+0, 88, 88, 1, 230400, 0x02470a69
+0, 89, 89, 1, 230400, 0xa5c51328
+0, 90, 90, 1, 230400, 0x1a6e37ec
+0, 91, 91, 1, 230400, 0x8f40563c
+0, 92, 92, 1, 230400, 0x30f9095f
+0, 93, 93, 1, 230400, 0x6227f0e8
+0, 94, 94, 1, 230400, 0xdca3596d
+0, 95, 95, 1, 230400, 0x30938988
+0, 96, 96, 1, 230400, 0x28bdc666
+0, 97, 97, 1, 230400, 0x6c534265
+0, 98, 98, 1, 230400, 0x6ea56d2d
+0, 99, 99, 1, 230400, 0x125f3808
+0, 100, 100, 1, 230400, 0x92a41d2f
+0, 101, 101, 1, 230400, 0xf1cf2410
+0, 102, 102, 1, 230400, 0x1bea1204
+0, 103, 103, 1, 230400, 0x817e60f9
+0, 104, 104, 1, 230400, 0x9f6c720e
+0, 105, 105, 1, 230400, 0xf1a43a2f
+0, 106, 106, 1, 230400, 0x5e5e0b7f
+0, 107, 107, 1, 230400, 0x7f526bcf
+0, 108, 108, 1, 230400, 0x63a846ed
+0, 109, 109, 1, 230400, 0x94400af9
+0, 110, 110, 1, 230400, 0x51f4241e
diff --git a/tests/ref/fate/mpeg2-field-enc b/tests/ref/fate/mpeg2-field-enc
index e302536f88..bf8a01a7cc 100644
--- a/tests/ref/fate/mpeg2-field-enc
+++ b/tests/ref/fate/mpeg2-field-enc
@@ -1,31 +1,31 @@
-#tb 0: 1/90000
-0, 32400, 32400, 0, 622080, 0xb3b66c5c
-0, 36000, 36000, 0, 622080, 0x088ec02b
-0, 39600, 39600, 0, 622080, 0x7a36db21
-0, 43200, 43200, 0, 622080, 0x541b286f
-0, 46800, 46800, 0, 622080, 0xb6c3e590
-0, 50400, 50400, 0, 622080, 0x39dbed51
-0, 54000, 54000, 0, 622080, 0x973dc728
-0, 57600, 57600, 0, 622080, 0xd7a4f804
-0, 61200, 61200, 0, 622080, 0xa2484762
-0, 64800, 64800, 0, 622080, 0x0cd268d1
-0, 68400, 68400, 0, 622080, 0x72eb663d
-0, 72000, 72000, 0, 622080, 0x8fdbac59
-0, 75600, 75600, 0, 622080, 0xa6f4feb9
-0, 79200, 79200, 0, 622080, 0xadb828c6
-0, 82800, 82800, 0, 622080, 0xea630a63
-0, 86400, 86400, 0, 622080, 0xa901d925
-0, 90000, 90000, 0, 622080, 0xac5e7087
-0, 93600, 93600, 0, 622080, 0x10274a2b
-0, 97200, 97200, 0, 622080, 0x143d541c
-0, 100800, 100800, 0, 622080, 0xee94c93a
-0, 104400, 104400, 0, 622080, 0xca030208
-0, 108000, 108000, 0, 622080, 0x26f30ead
-0, 111600, 111600, 0, 622080, 0xfc22f32c
-0, 115200, 115200, 0, 622080, 0x940a5ff8
-0, 118800, 118800, 0, 622080, 0x2164f805
-0, 122400, 122400, 0, 622080, 0xa76f5aba
-0, 126000, 126000, 0, 622080, 0x8c311471
-0, 129600, 129600, 0, 622080, 0xa45e1d95
-0, 133200, 133200, 0, 622080, 0x6cc61d6c
-0, 136800, 136800, 0, 622080, 0x6983b417
+#tb 0: 1/25
+0, 9, 9, 1, 622080, 0xb3b66c5c
+0, 10, 10, 1, 622080, 0x088ec02b
+0, 11, 11, 1, 622080, 0x7a36db21
+0, 12, 12, 1, 622080, 0x541b286f
+0, 13, 13, 1, 622080, 0xb6c3e590
+0, 14, 14, 1, 622080, 0x39dbed51
+0, 15, 15, 1, 622080, 0x973dc728
+0, 16, 16, 1, 622080, 0xd7a4f804
+0, 17, 17, 1, 622080, 0xa2484762
+0, 18, 18, 1, 622080, 0x0cd268d1
+0, 19, 19, 1, 622080, 0x72eb663d
+0, 20, 20, 1, 622080, 0x8fdbac59
+0, 21, 21, 1, 622080, 0xa6f4feb9
+0, 22, 22, 1, 622080, 0xadb828c6
+0, 23, 23, 1, 622080, 0xea630a63
+0, 24, 24, 1, 622080, 0xa901d925
+0, 25, 25, 1, 622080, 0xac5e7087
+0, 26, 26, 1, 622080, 0x10274a2b
+0, 27, 27, 1, 622080, 0x143d541c
+0, 28, 28, 1, 622080, 0xee94c93a
+0, 29, 29, 1, 622080, 0xca030208
+0, 30, 30, 1, 622080, 0x26f30ead
+0, 31, 31, 1, 622080, 0xfc22f32c
+0, 32, 32, 1, 622080, 0x940a5ff8
+0, 33, 33, 1, 622080, 0x2164f805
+0, 34, 34, 1, 622080, 0xa76f5aba
+0, 35, 35, 1, 622080, 0x8c311471
+0, 36, 36, 1, 622080, 0xa45e1d95
+0, 37, 37, 1, 622080, 0x6cc61d6c
+0, 38, 38, 1, 622080, 0x6983b417
diff --git a/tests/ref/fate/mpeg4-bsf-unpack-bframes b/tests/ref/fate/mpeg4-bsf-unpack-bframes
new file mode 100644
index 0000000000..21e58f6051
--- /dev/null
+++ b/tests/ref/fate/mpeg4-bsf-unpack-bframes
@@ -0,0 +1 @@
+5db6b7b766c7a9fd5f42292d7467a36d
diff --git a/tests/ref/fate/mpeg4-resolution-change-down-down b/tests/ref/fate/mpeg4-resolution-change-down-down
index 137575ac64..02fcda502f 100644
--- a/tests/ref/fate/mpeg4-resolution-change-down-down
+++ b/tests/ref/fate/mpeg4-resolution-change-down-down
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 460800, d65fcc79c7eb9ebd9d88dca3ebb15bf4
0, 1, 1, 1, 460800, 6c86b8c7e8eae3d63b21342f233fb44e
0, 2, 2, 1, 460800, 7fea65fd8ee4d3fcec722f721d05ef45
diff --git a/tests/ref/fate/mpeg4-resolution-change-down-up b/tests/ref/fate/mpeg4-resolution-change-down-up
index 31332c31fd..37e56d8e9e 100644
--- a/tests/ref/fate/mpeg4-resolution-change-down-up
+++ b/tests/ref/fate/mpeg4-resolution-change-down-up
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 460800, d65fcc79c7eb9ebd9d88dca3ebb15bf4
0, 1, 1, 1, 460800, 6c86b8c7e8eae3d63b21342f233fb44e
0, 2, 2, 1, 460800, 7fea65fd8ee4d3fcec722f721d05ef45
diff --git a/tests/ref/fate/mpeg4-resolution-change-up-down b/tests/ref/fate/mpeg4-resolution-change-up-down
index 81911f7592..36110c3ec7 100644
--- a/tests/ref/fate/mpeg4-resolution-change-up-down
+++ b/tests/ref/fate/mpeg4-resolution-change-up-down
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 180000, 9fc6302026cf2a2dd310646b83c5dfa1
0, 1, 1, 1, 180000, b1b2646c8df579ddf8676bc2488411a5
0, 2, 2, 1, 180000, 5aca8cdf4914a96577cffbbc18508043
diff --git a/tests/ref/fate/mpeg4-resolution-change-up-up b/tests/ref/fate/mpeg4-resolution-change-up-up
index 9aac9c8900..8d1bbcd240 100644
--- a/tests/ref/fate/mpeg4-resolution-change-up-up
+++ b/tests/ref/fate/mpeg4-resolution-change-up-up
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 152064, 7f952fd8bd40c32197afc21e2fa66404
0, 1, 1, 1, 152064, 5b2cc25b04d9a9d33bcf5fe480505d68
0, 2, 2, 1, 152064, 56d6bb0022f68fbccae81ef054a88c9a
diff --git a/tests/ref/fate/mss2-wmv b/tests/ref/fate/mss2-wmv
index d539c714bf..c54cff62b4 100644
--- a/tests/ref/fate/mss2-wmv
+++ b/tests/ref/fate/mss2-wmv
@@ -1,101 +1,101 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 230400, 0x00000000
-0, 233, 233, 0, 230400, 0xaf950008
-0, 299, 299, 0, 230400, 0x8d2a0010
-0, 366, 366, 0, 230400, 0xd75e0018
-0, 433, 433, 0, 230400, 0x00000000
-0, 499, 499, 0, 230400, 0x517f0008
-0, 566, 566, 0, 230400, 0xcf5a0010
-0, 633, 633, 0, 230400, 0x00000000
-0, 699, 699, 0, 230400, 0x40ef0018
-0, 766, 766, 0, 230400, 0xdc850008
-0, 833, 833, 0, 230400, 0x00000000
-0, 899, 899, 0, 230400, 0x09a40008
-0, 966, 966, 0, 230400, 0x00000000
-0, 1033, 1033, 0, 230400, 0x8b950008
-0, 1099, 1099, 0, 230400, 0xae260038
-0, 1166, 1166, 0, 230400, 0x6d850008
-0, 1233, 1233, 0, 230400, 0x00000000
-0, 1566, 1566, 0, 230400, 0x8b950008
-0, 1633, 1633, 0, 230400, 0x75450018
-0, 1699, 1699, 0, 230400, 0xb0dd0010
-0, 1766, 1766, 0, 230400, 0xecdd0018
-0, 1833, 1833, 0, 230400, 0x68e3f7f7
-0, 1899, 1899, 0, 230400, 0x9cfdcea6
-0, 1966, 1966, 0, 230400, 0x735ababf
-0, 2033, 2033, 0, 230400, 0xa1c604ea
-0, 2099, 2099, 0, 230400, 0x18a2f97a
-0, 2166, 2166, 0, 230400, 0xf9e82961
-0, 2233, 2233, 0, 230400, 0x57a8e9e8
-0, 2299, 2299, 0, 230400, 0xdef6fd66
-0, 2366, 2366, 0, 230400, 0xc7d923a9
-0, 2433, 2433, 0, 230400, 0x08bb41ee
-0, 2499, 2499, 0, 230400, 0x43ccbd29
-0, 2566, 2566, 0, 230400, 0x46666ee3
-0, 2633, 2633, 0, 230400, 0xbfd2ef29
-0, 2699, 2699, 0, 230400, 0x6504545f
-0, 2766, 2766, 0, 230400, 0x8fb86901
-0, 2833, 2833, 0, 230400, 0xc95f0917
-0, 2899, 2899, 0, 230400, 0x21f6a54b
-0, 2966, 2966, 0, 230400, 0xf808106b
-0, 3033, 3033, 0, 230400, 0x34150020
-0, 3099, 3099, 0, 230400, 0x50fdfe89
-0, 3166, 3166, 0, 230400, 0x920b7708
-0, 3233, 3233, 0, 230400, 0xed64fcc4
-0, 3299, 3299, 0, 230400, 0x6291a170
-0, 3366, 3366, 0, 230400, 0x20524643
-0, 3433, 3433, 0, 230400, 0x92aafecd
-0, 3499, 3499, 0, 230400, 0xf00ee14d
-0, 3566, 3566, 0, 230400, 0xfa3113ea
-0, 3633, 3633, 0, 230400, 0x99c06df1
-0, 3699, 3699, 0, 230400, 0x625c6918
-0, 3766, 3766, 0, 230400, 0xb277b25e
-0, 3833, 3833, 0, 230400, 0x2e913006
-0, 3899, 3899, 0, 230400, 0x3f6f1d99
-0, 3966, 3966, 0, 230400, 0x100ab60f
-0, 4033, 4033, 0, 230400, 0x9b73d0bf
-0, 4099, 4099, 0, 230400, 0xda0df2ce
-0, 4166, 4166, 0, 230400, 0x67f7ca24
-0, 4233, 4233, 0, 230400, 0xbde9b3d0
-0, 4299, 4299, 0, 230400, 0x92e14d07
-0, 4366, 4366, 0, 230400, 0x9426c3d9
-0, 4433, 4433, 0, 230400, 0x6104be70
-0, 4499, 4499, 0, 230400, 0xc4d1078a
-0, 4566, 4566, 0, 230400, 0x89426a42
-0, 4633, 4633, 0, 230400, 0x5271324a
-0, 4699, 4699, 0, 230400, 0x1cb1c735
-0, 4766, 4766, 0, 230400, 0x4249b8c6
-0, 4833, 4833, 0, 230400, 0x4b88cad3
-0, 4899, 4899, 0, 230400, 0x76af545d
-0, 4966, 4966, 0, 230400, 0xfe47e3c4
-0, 5033, 5033, 0, 230400, 0xa2e0e721
-0, 5099, 5099, 0, 230400, 0xde974a42
-0, 5166, 5166, 0, 230400, 0xe86a376b
-0, 5233, 5233, 0, 230400, 0xd52318fd
-0, 5299, 5299, 0, 230400, 0x0bbb1526
-0, 5366, 5366, 0, 230400, 0xa22c5e5e
-0, 5433, 5433, 0, 230400, 0x4532c5d2
-0, 5499, 5499, 0, 230400, 0x88b560ec
-0, 5566, 5566, 0, 230400, 0xcee9d9c9
-0, 5633, 5633, 0, 230400, 0x0429358f
-0, 5699, 5699, 0, 230400, 0xf18a9b98
-0, 5766, 5766, 0, 230400, 0x63f7a12c
-0, 5833, 5833, 0, 230400, 0x98635515
-0, 5899, 5899, 0, 230400, 0x36affebc
-0, 5966, 5966, 0, 230400, 0xd8c19629
-0, 6033, 6033, 0, 230400, 0x9ef5344d
-0, 6099, 6099, 0, 230400, 0x545668dc
-0, 6166, 6166, 0, 230400, 0x50e65e74
-0, 6233, 6233, 0, 230400, 0xe3258be3
-0, 6299, 6299, 0, 230400, 0xeb479e1b
-0, 6366, 6366, 0, 230400, 0x91894243
-0, 6433, 6433, 0, 230400, 0x3c5660fc
-0, 6499, 6499, 0, 230400, 0xf0c35673
-0, 6566, 6566, 0, 230400, 0x552832e8
-0, 6633, 6633, 0, 230400, 0x1970f2b1
-0, 6699, 6699, 0, 230400, 0x812d4c91
-0, 6766, 6766, 0, 230400, 0xa3fbd4ef
-0, 6833, 6833, 0, 230400, 0x486f9649
-0, 6899, 6899, 0, 230400, 0x850f315a
-0, 6966, 6966, 0, 230400, 0xc18ec66b
-0, 7033, 7033, 0, 230400, 0xc9ef266e
+#tb 0: 1/15
+0, 0, 0, 1, 230400, 0x00000000
+0, 3, 3, 1, 230400, 0xaf950008
+0, 4, 4, 1, 230400, 0x8d2a0010
+0, 5, 5, 1, 230400, 0xd75e0018
+0, 6, 6, 1, 230400, 0x00000000
+0, 7, 7, 1, 230400, 0x517f0008
+0, 8, 8, 1, 230400, 0xcf5a0010
+0, 9, 9, 1, 230400, 0x00000000
+0, 10, 10, 1, 230400, 0x40ef0018
+0, 11, 11, 1, 230400, 0xdc850008
+0, 12, 12, 1, 230400, 0x00000000
+0, 13, 13, 1, 230400, 0x09a40008
+0, 14, 14, 1, 230400, 0x00000000
+0, 15, 15, 1, 230400, 0x8b950008
+0, 16, 16, 1, 230400, 0xae260038
+0, 17, 17, 1, 230400, 0x6d850008
+0, 18, 18, 1, 230400, 0x00000000
+0, 23, 23, 1, 230400, 0x8b950008
+0, 24, 24, 1, 230400, 0x75450018
+0, 25, 25, 1, 230400, 0xb0dd0010
+0, 26, 26, 1, 230400, 0xecdd0018
+0, 27, 27, 1, 230400, 0x68e3f7f7
+0, 28, 28, 1, 230400, 0x9cfdcea6
+0, 29, 29, 1, 230400, 0x735ababf
+0, 30, 30, 1, 230400, 0xa1c604ea
+0, 31, 31, 1, 230400, 0x18a2f97a
+0, 32, 32, 1, 230400, 0xf9e82961
+0, 33, 33, 1, 230400, 0x57a8e9e8
+0, 34, 34, 1, 230400, 0xdef6fd66
+0, 35, 35, 1, 230400, 0xc7d923a9
+0, 36, 36, 1, 230400, 0x08bb41ee
+0, 37, 37, 1, 230400, 0x43ccbd29
+0, 38, 38, 1, 230400, 0x46666ee3
+0, 39, 39, 1, 230400, 0xbfd2ef29
+0, 40, 40, 1, 230400, 0x6504545f
+0, 41, 41, 1, 230400, 0x8fb86901
+0, 42, 42, 1, 230400, 0xc95f0917
+0, 43, 43, 1, 230400, 0x21f6a54b
+0, 44, 44, 1, 230400, 0xf808106b
+0, 45, 45, 1, 230400, 0x34150020
+0, 46, 46, 1, 230400, 0x50fdfe89
+0, 47, 47, 1, 230400, 0x920b7708
+0, 48, 48, 1, 230400, 0xed64fcc4
+0, 49, 49, 1, 230400, 0x6291a170
+0, 50, 50, 1, 230400, 0x20524643
+0, 51, 51, 1, 230400, 0x92aafecd
+0, 52, 52, 1, 230400, 0xf00ee14d
+0, 53, 53, 1, 230400, 0xfa3113ea
+0, 54, 54, 1, 230400, 0x99c06df1
+0, 55, 55, 1, 230400, 0x625c6918
+0, 56, 56, 1, 230400, 0xb277b25e
+0, 57, 57, 1, 230400, 0x2e913006
+0, 58, 58, 1, 230400, 0x3f6f1d99
+0, 59, 59, 1, 230400, 0x100ab60f
+0, 60, 60, 1, 230400, 0x9b73d0bf
+0, 61, 61, 1, 230400, 0xda0df2ce
+0, 62, 62, 1, 230400, 0x67f7ca24
+0, 63, 63, 1, 230400, 0xbde9b3d0
+0, 64, 64, 1, 230400, 0x92e14d07
+0, 65, 65, 1, 230400, 0x9426c3d9
+0, 66, 66, 1, 230400, 0x6104be70
+0, 67, 67, 1, 230400, 0xc4d1078a
+0, 68, 68, 1, 230400, 0x89426a42
+0, 69, 69, 1, 230400, 0x5271324a
+0, 70, 70, 1, 230400, 0x1cb1c735
+0, 71, 71, 1, 230400, 0x4249b8c6
+0, 72, 72, 1, 230400, 0x4b88cad3
+0, 73, 73, 1, 230400, 0x76af545d
+0, 74, 74, 1, 230400, 0xfe47e3c4
+0, 75, 75, 1, 230400, 0xa2e0e721
+0, 76, 76, 1, 230400, 0xde974a42
+0, 77, 77, 1, 230400, 0x87bf38ba
+0, 78, 78, 1, 230400, 0xd52318fd
+0, 79, 79, 1, 230400, 0x0bbb1526
+0, 80, 80, 1, 230400, 0xa22c5e5e
+0, 81, 81, 1, 230400, 0x4532c5d2
+0, 82, 82, 1, 230400, 0x88b560ec
+0, 83, 83, 1, 230400, 0xcee9d9c9
+0, 84, 84, 1, 230400, 0x0429358f
+0, 85, 85, 1, 230400, 0xf18a9b98
+0, 86, 86, 1, 230400, 0x63f7a12c
+0, 87, 87, 1, 230400, 0x98635515
+0, 88, 88, 1, 230400, 0x36affebc
+0, 89, 89, 1, 230400, 0xd8c19629
+0, 90, 90, 1, 230400, 0x9ef5344d
+0, 91, 91, 1, 230400, 0x545668dc
+0, 92, 92, 1, 230400, 0x50e65e74
+0, 93, 93, 1, 230400, 0xe3258be3
+0, 94, 94, 1, 230400, 0xeb479e1b
+0, 95, 95, 1, 230400, 0x91894243
+0, 96, 96, 1, 230400, 0x3c5660fc
+0, 97, 97, 1, 230400, 0xf0c35673
+0, 98, 98, 1, 230400, 0x552832e8
+0, 99, 99, 1, 230400, 0x1970f2b1
+0, 100, 100, 1, 230400, 0x812d4c91
+0, 101, 101, 1, 230400, 0xa3fbd4ef
+0, 102, 102, 1, 230400, 0x486f9649
+0, 103, 103, 1, 230400, 0x850f315a
+0, 104, 104, 1, 230400, 0xc18ec66b
+0, 105, 105, 1, 230400, 0xc9ef266e
diff --git a/tests/ref/fate/msvideo1-16bit b/tests/ref/fate/msvideo1-16bit
index fffdea294a..f5c0e64748 100644
--- a/tests/ref/fate/msvideo1-16bit
+++ b/tests/ref/fate/msvideo1-16bit
@@ -1,31 +1,31 @@
#tb 0: 33369/500000
-0, 0, 0, 1, 65712, 0x917e0076
-0, 1, 1, 1, 65712, 0xfe76fd1f
-0, 2, 2, 1, 65712, 0xd85820ee
-0, 3, 3, 1, 65712, 0x1b410f6e
-0, 4, 4, 1, 65712, 0x53c50436
-0, 5, 5, 1, 65712, 0xa191044d
-0, 6, 6, 1, 65712, 0xcf02ff1f
-0, 7, 7, 1, 65712, 0xc2abf85f
-0, 8, 8, 1, 65712, 0xe273087e
-0, 9, 9, 1, 65712, 0x087d0936
-0, 10, 10, 1, 65712, 0x4e4f2e96
-0, 11, 11, 1, 65712, 0x91b51896
-0, 12, 12, 1, 65712, 0x2798450e
-0, 13, 13, 1, 65712, 0x9fea1d06
-0, 14, 14, 1, 65712, 0xc64a2506
-0, 15, 15, 1, 65712, 0x0551fe07
-0, 16, 16, 1, 65712, 0xc64a042e
-0, 17, 17, 1, 65712, 0xf3680dc6
-0, 18, 18, 1, 65712, 0x2ea5356e
-0, 19, 19, 1, 65712, 0x0315ed3f
-0, 20, 20, 1, 65712, 0xc1d1f917
-0, 21, 21, 1, 65712, 0xc0f6e607
-0, 22, 22, 1, 65712, 0x5b0a092e
-0, 23, 23, 1, 65712, 0x1551f16f
-0, 24, 24, 1, 65712, 0x8440ee87
-0, 25, 25, 1, 65712, 0xf7581ae6
-0, 26, 26, 1, 65712, 0xee67037e
-0, 27, 27, 1, 65712, 0x4a212ca6
-0, 28, 28, 1, 65712, 0x693e0aa6
-0, 29, 29, 1, 65712, 0x13e31116
+0, 0, 0, 1, 65712, 0x03ff25b8
+0, 1, 1, 1, 65712, 0xfca02276
+0, 2, 2, 1, 65712, 0xd23646e4
+0, 3, 3, 1, 65712, 0x9ea43556
+0, 4, 4, 1, 65712, 0x47412948
+0, 5, 5, 1, 65712, 0x667230c9
+0, 6, 6, 1, 65712, 0x8224247a
+0, 7, 7, 1, 65712, 0x9c0f1d71
+0, 8, 8, 1, 65712, 0x4fbb2e11
+0, 9, 9, 1, 65712, 0x0e4a2e34
+0, 10, 10, 1, 65712, 0xd58954c8
+0, 11, 11, 1, 65712, 0x131d3e2c
+0, 12, 12, 1, 65712, 0x3b686bc7
+0, 13, 13, 1, 65712, 0xbea342a7
+0, 14, 14, 1, 65712, 0xbdff4ac7
+0, 15, 15, 1, 65712, 0x215e22ab
+0, 16, 16, 1, 65712, 0xa9f0295f
+0, 17, 17, 1, 65712, 0x46fb32f3
+0, 18, 18, 1, 65712, 0xd8be5bee
+0, 19, 19, 1, 65712, 0x526411b6
+0, 20, 20, 1, 65712, 0x53951e21
+0, 21, 21, 1, 65712, 0x54a70ab3
+0, 22, 22, 1, 65712, 0xcc872e7a
+0, 23, 23, 1, 65712, 0x06b2164c
+0, 24, 24, 1, 65712, 0x1ae5135f
+0, 25, 25, 1, 65712, 0x8d8a40b4
+0, 26, 26, 1, 65712, 0x3d732893
+0, 27, 27, 1, 65712, 0x239a52a8
+0, 28, 28, 1, 65712, 0xf6bd2fc9
+0, 29, 29, 1, 65712, 0x40b336c4
diff --git a/tests/ref/fate/mtv b/tests/ref/fate/mtv
index 4f8f6165b7..9e898ff0b8 100644
--- a/tests/ref/fate/mtv
+++ b/tests/ref/fate/mtv
@@ -1,3 +1,4 @@
+#extradata 0: 9, 0x116c033a
#tb 0: 1/16
#tb 1: 1/44100
0, 0, 0, 1, 12288, 0xc2258ebc
@@ -133,6 +134,6 @@
1, 104832, 104832, 1152, 418, 0xa105cdcc
1, 105984, 105984, 1152, 418, 0x1477ba58
1, 107136, 107136, 1152, 418, 0x8d0dcdb2
-0, 39, 39, 1, 3584, 0x0354c435
+0, 39, 39, 1, 3584, 0x0354c435, F=0x3
1, 108288, 108288, 1152, 418, 0x0d7cbef4
1, 109440, 109440, 1152, 294, 0x5e2b87c4
diff --git a/tests/ref/fate/murmur3 b/tests/ref/fate/murmur3
new file mode 100644
index 0000000000..cd5c0e8655
--- /dev/null
+++ b/tests/ref/fate/murmur3
@@ -0,0 +1 @@
+result: 0x63f3de036384ba69 0x7192878ce684ed2d
diff --git a/tests/ref/fate/mxf-demux b/tests/ref/fate/mxf-demux
index 426afae965..3d9a2dc49d 100644
--- a/tests/ref/fate/mxf-demux
+++ b/tests/ref/fate/mxf-demux
@@ -1,99 +1,100 @@
+#extradata 0: 18, 0x0b150244
#tb 0: 1/25
#tb 1: 1/8000
0, 0, -9223372036854775808, 1, 8468, 0xc0855553
1, 0, 0, 16000, 32000, 0x479155e6
-0, 1, -9223372036854775808, 1, 3814, 0xa10783b4
-0, 2, -9223372036854775808, 1, 3747, 0xb7bf6973
-0, 3, -9223372036854775808, 1, 3705, 0x5462a600
-0, 4, -9223372036854775808, 1, 3704, 0x1e564943
-0, 5, -9223372036854775808, 1, 3760, 0x10464b9a
-0, 6, -9223372036854775808, 1, 3799, 0xd41d6dcf
-0, 7, -9223372036854775808, 1, 3832, 0x5cf6999e
-0, 8, -9223372036854775808, 1, 3778, 0xe5fc7b9e
-0, 9, -9223372036854775808, 1, 38193, 0xd34e5dd4
+0, 1, -9223372036854775808, 1, 3814, 0xa10783b4, F=0x0
+0, 2, -9223372036854775808, 1, 3747, 0xb7bf6973, F=0x0
+0, 3, -9223372036854775808, 1, 3705, 0x5462a600, F=0x0
+0, 4, -9223372036854775808, 1, 3704, 0x1e564943, F=0x0
+0, 5, -9223372036854775808, 1, 3760, 0x10464b9a, F=0x0
+0, 6, -9223372036854775808, 1, 3799, 0xd41d6dcf, F=0x0
+0, 7, -9223372036854775808, 1, 3832, 0x5cf6999e, F=0x0
+0, 8, -9223372036854775808, 1, 3778, 0xe5fc7b9e, F=0x0
+0, 9, -9223372036854775808, 1, 38193, 0xd34e5dd4, F=0x0
0, 10, -9223372036854775808, 1, 8520, 0x2a203e68
-0, 11, -9223372036854775808, 1, 3832, 0xe4c4b2fe
-0, 12, -9223372036854775808, 1, 3787, 0x0cf95fee
-0, 13, -9223372036854775808, 1, 3766, 0x9e019d14
-0, 14, -9223372036854775808, 1, 3785, 0x0ea9ae75
-0, 15, -9223372036854775808, 1, 3703, 0x11d349ff
-0, 16, -9223372036854775808, 1, 3731, 0x5cf358ef
-0, 17, -9223372036854775808, 1, 3785, 0x01c8962f
-0, 18, -9223372036854775808, 1, 3741, 0xb2c47d53
-0, 19, -9223372036854775808, 1, 38150, 0x08fa1f55
+0, 11, -9223372036854775808, 1, 3832, 0xe4c4b2fe, F=0x0
+0, 12, -9223372036854775808, 1, 3787, 0x0cf95fee, F=0x0
+0, 13, -9223372036854775808, 1, 3766, 0x9e019d14, F=0x0
+0, 14, -9223372036854775808, 1, 3785, 0x0ea9ae75, F=0x0
+0, 15, -9223372036854775808, 1, 3703, 0x11d349ff, F=0x0
+0, 16, -9223372036854775808, 1, 3731, 0x5cf358ef, F=0x0
+0, 17, -9223372036854775808, 1, 3785, 0x01c8962f, F=0x0
+0, 18, -9223372036854775808, 1, 3741, 0xb2c47d53, F=0x0
+0, 19, -9223372036854775808, 1, 38150, 0x08fa1f55, F=0x0
0, 20, -9223372036854775808, 1, 8487, 0x0c234b9a
-0, 21, -9223372036854775808, 1, 3791, 0x831192ef
-0, 22, -9223372036854775808, 1, 3612, 0x598944fb
-0, 23, -9223372036854775808, 1, 3710, 0xccbb711a
-0, 24, -9223372036854775808, 1, 3864, 0x4385966e
-0, 25, -9223372036854775808, 1, 3919, 0x24e2abc3
-0, 26, -9223372036854775808, 1, 3777, 0x210c6219
-0, 27, -9223372036854775808, 1, 3811, 0x23bf68c2
-0, 28, -9223372036854775808, 1, 3802, 0x52688862
-0, 29, -9223372036854775808, 1, 38027, 0x3d5aa8b9
+0, 21, -9223372036854775808, 1, 3791, 0x831192ef, F=0x0
+0, 22, -9223372036854775808, 1, 3612, 0x598944fb, F=0x0
+0, 23, -9223372036854775808, 1, 3710, 0xccbb711a, F=0x0
+0, 24, -9223372036854775808, 1, 3864, 0x4385966e, F=0x0
+0, 25, -9223372036854775808, 1, 3919, 0x24e2abc3, F=0x0
+0, 26, -9223372036854775808, 1, 3777, 0x210c6219, F=0x0
+0, 27, -9223372036854775808, 1, 3811, 0x23bf68c2, F=0x0
+0, 28, -9223372036854775808, 1, 3802, 0x52688862, F=0x0
+0, 29, -9223372036854775808, 1, 38027, 0x3d5aa8b9, F=0x0
0, 30, -9223372036854775808, 1, 8333, 0x617de950
-0, 31, -9223372036854775808, 1, 3831, 0x13fad8fc
-0, 32, -9223372036854775808, 1, 3719, 0xbc317470
-0, 33, -9223372036854775808, 1, 3761, 0xeac460b6
-0, 34, -9223372036854775808, 1, 3637, 0x27d64b32
-0, 35, -9223372036854775808, 1, 3666, 0xf0f700a5
-0, 36, -9223372036854775808, 1, 3788, 0x1c4662a8
-0, 37, -9223372036854775808, 1, 3960, 0xef6b9e99
-0, 38, -9223372036854775808, 1, 3793, 0x3a6ca832
-0, 39, -9223372036854775808, 1, 38312, 0xce1317cc
+0, 31, -9223372036854775808, 1, 3831, 0x13fad8fc, F=0x0
+0, 32, -9223372036854775808, 1, 3719, 0xbc317470, F=0x0
+0, 33, -9223372036854775808, 1, 3761, 0xeac460b6, F=0x0
+0, 34, -9223372036854775808, 1, 3637, 0x27d64b32, F=0x0
+0, 35, -9223372036854775808, 1, 3666, 0xf0f700a5, F=0x0
+0, 36, -9223372036854775808, 1, 3788, 0x1c4662a8, F=0x0
+0, 37, -9223372036854775808, 1, 3960, 0xef6b9e99, F=0x0
+0, 38, -9223372036854775808, 1, 3793, 0x3a6ca832, F=0x0
+0, 39, -9223372036854775808, 1, 38312, 0xce1317cc, F=0x0
0, 40, -9223372036854775808, 1, 8548, 0x4ca944d4
-0, 41, -9223372036854775808, 1, 3866, 0x4e85bf0f
-0, 42, -9223372036854775808, 1, 3644, 0x030338e5
-0, 43, -9223372036854775808, 1, 3634, 0xa95f4512
-0, 44, -9223372036854775808, 1, 3925, 0x7583ba86
-0, 45, -9223372036854775808, 1, 3675, 0x979f423f
-0, 46, -9223372036854775808, 1, 3703, 0x11375f7a
-0, 47, -9223372036854775808, 1, 3705, 0xb7de5d16
-0, 48, -9223372036854775808, 1, 3688, 0x1db45852
-0, 49, -9223372036854775808, 1, 38412, 0x2ee26a63
+0, 41, -9223372036854775808, 1, 3866, 0x4e85bf0f, F=0x0
+0, 42, -9223372036854775808, 1, 3644, 0x030338e5, F=0x0
+0, 43, -9223372036854775808, 1, 3634, 0xa95f4512, F=0x0
+0, 44, -9223372036854775808, 1, 3925, 0x7583ba86, F=0x0
+0, 45, -9223372036854775808, 1, 3675, 0x979f423f, F=0x0
+0, 46, -9223372036854775808, 1, 3703, 0x11375f7a, F=0x0
+0, 47, -9223372036854775808, 1, 3705, 0xb7de5d16, F=0x0
+0, 48, -9223372036854775808, 1, 3688, 0x1db45852, F=0x0
+0, 49, -9223372036854775808, 1, 38412, 0x2ee26a63, F=0x0
0, 50, -9223372036854775808, 1, 8385, 0x0bc20a27
1, 16000, 16000, 16000, 32000, 0x8f7e5009
-0, 51, -9223372036854775808, 1, 3733, 0xa3e2a9a0
-0, 52, -9223372036854775808, 1, 3773, 0x27769caa
-0, 53, -9223372036854775808, 1, 3670, 0xc8335e98
-0, 54, -9223372036854775808, 1, 3596, 0xd6512fb0
-0, 55, -9223372036854775808, 1, 3579, 0xa621fbc2
-0, 56, -9223372036854775808, 1, 3641, 0x2f4f46ca
-0, 57, -9223372036854775808, 1, 3686, 0x0a92385a
-0, 58, -9223372036854775808, 1, 3672, 0xe65137b9
-0, 59, -9223372036854775808, 1, 39065, 0xc723bf8b
+0, 51, -9223372036854775808, 1, 3733, 0xa3e2a9a0, F=0x0
+0, 52, -9223372036854775808, 1, 3773, 0x27769caa, F=0x0
+0, 53, -9223372036854775808, 1, 3670, 0xc8335e98, F=0x0
+0, 54, -9223372036854775808, 1, 3596, 0xd6512fb0, F=0x0
+0, 55, -9223372036854775808, 1, 3579, 0xa621fbc2, F=0x0
+0, 56, -9223372036854775808, 1, 3641, 0x2f4f46ca, F=0x0
+0, 57, -9223372036854775808, 1, 3686, 0x0a92385a, F=0x0
+0, 58, -9223372036854775808, 1, 3672, 0xe65137b9, F=0x0
+0, 59, -9223372036854775808, 1, 39065, 0xc723bf8b, F=0x0
0, 60, -9223372036854775808, 1, 8611, 0x5d177f40
-0, 61, -9223372036854775808, 1, 3758, 0x33d59966
-0, 62, -9223372036854775808, 1, 3674, 0x54f37902
-0, 63, -9223372036854775808, 1, 3615, 0xa0f045fa
-0, 64, -9223372036854775808, 1, 3719, 0x41cf93ff
-0, 65, -9223372036854775808, 1, 3757, 0x3a1b7e8f
-0, 66, -9223372036854775808, 1, 3762, 0xe7f9714d
-0, 67, -9223372036854775808, 1, 3738, 0x8121805b
-0, 68, -9223372036854775808, 1, 3733, 0x13e262db
-0, 69, -9223372036854775808, 1, 38433, 0x3d58c500
+0, 61, -9223372036854775808, 1, 3758, 0x33d59966, F=0x0
+0, 62, -9223372036854775808, 1, 3674, 0x54f37902, F=0x0
+0, 63, -9223372036854775808, 1, 3615, 0xa0f045fa, F=0x0
+0, 64, -9223372036854775808, 1, 3719, 0x41cf93ff, F=0x0
+0, 65, -9223372036854775808, 1, 3757, 0x3a1b7e8f, F=0x0
+0, 66, -9223372036854775808, 1, 3762, 0xe7f9714d, F=0x0
+0, 67, -9223372036854775808, 1, 3738, 0x8121805b, F=0x0
+0, 68, -9223372036854775808, 1, 3733, 0x13e262db, F=0x0
+0, 69, -9223372036854775808, 1, 38433, 0x3d58c500, F=0x0
0, 70, -9223372036854775808, 1, 8410, 0xa4f7fd2e
-0, 71, -9223372036854775808, 1, 3711, 0x0e112d3c
-0, 72, -9223372036854775808, 1, 3692, 0xb46574b2
-0, 73, -9223372036854775808, 1, 3563, 0xad43343d
-0, 74, -9223372036854775808, 1, 3613, 0x5cd85c4f
-0, 75, -9223372036854775808, 1, 3653, 0xe15a2853
-0, 76, -9223372036854775808, 1, 3684, 0x9ddd58cb
-0, 77, -9223372036854775808, 1, 3256, 0xd7f89f2e
-0, 78, -9223372036854775808, 1, 3698, 0x2b82624a
-0, 79, -9223372036854775808, 1, 39520, 0xd3f2b7c5
+0, 71, -9223372036854775808, 1, 3711, 0x0e112d3c, F=0x0
+0, 72, -9223372036854775808, 1, 3692, 0xb46574b2, F=0x0
+0, 73, -9223372036854775808, 1, 3563, 0xad43343d, F=0x0
+0, 74, -9223372036854775808, 1, 3613, 0x5cd85c4f, F=0x0
+0, 75, -9223372036854775808, 1, 3653, 0xe15a2853, F=0x0
+0, 76, -9223372036854775808, 1, 3684, 0x9ddd58cb, F=0x0
+0, 77, -9223372036854775808, 1, 3256, 0xd7f89f2e, F=0x0
+0, 78, -9223372036854775808, 1, 3698, 0x2b82624a, F=0x0
+0, 79, -9223372036854775808, 1, 39520, 0xd3f2b7c5, F=0x0
0, 80, -9223372036854775808, 1, 8493, 0x163559be
-0, 81, -9223372036854775808, 1, 3719, 0x6fa0916f
-0, 82, -9223372036854775808, 1, 3655, 0xa9233de1
-0, 83, -9223372036854775808, 1, 3684, 0xa6125737
-0, 84, -9223372036854775808, 1, 3688, 0xa9da6686
-0, 85, -9223372036854775808, 1, 3685, 0x674d634e
-0, 86, -9223372036854775808, 1, 3677, 0x7a85535d
-0, 87, -9223372036854775808, 1, 3666, 0xce3600a2
-0, 88, -9223372036854775808, 1, 3837, 0x3a7090e1
-0, 89, -9223372036854775808, 1, 38696, 0x12c59cd2
+0, 81, -9223372036854775808, 1, 3719, 0x6fa0916f, F=0x0
+0, 82, -9223372036854775808, 1, 3655, 0xa9233de1, F=0x0
+0, 83, -9223372036854775808, 1, 3684, 0xa6125737, F=0x0
+0, 84, -9223372036854775808, 1, 3688, 0xa9da6686, F=0x0
+0, 85, -9223372036854775808, 1, 3685, 0x674d634e, F=0x0
+0, 86, -9223372036854775808, 1, 3677, 0x7a85535d, F=0x0
+0, 87, -9223372036854775808, 1, 3666, 0xce3600a2, F=0x0
+0, 88, -9223372036854775808, 1, 3837, 0x3a7090e1, F=0x0
+0, 89, -9223372036854775808, 1, 38696, 0x12c59cd2, F=0x0
0, 90, -9223372036854775808, 1, 8022, 0xd343433f
-0, 91, -9223372036854775808, 1, 5157, 0x440c14e5
-0, 92, -9223372036854775808, 1, 5003, 0xf8e1daff
-0, 93, -9223372036854775808, 1, 4954, 0x89866344
-0, 94, -9223372036854775808, 1, 53664, 0xeb0c4c42
+0, 91, -9223372036854775808, 1, 5157, 0x440c14e5, F=0x0
+0, 92, -9223372036854775808, 1, 5003, 0xf8e1daff, F=0x0
+0, 93, -9223372036854775808, 1, 4954, 0x89866344, F=0x0
+0, 94, -9223372036854775808, 1, 53664, 0xeb0c4c42, F=0x0
diff --git a/tests/ref/fate/mxf-essencegroup-demux b/tests/ref/fate/mxf-essencegroup-demux
new file mode 100644
index 0000000000..8420db97c8
--- /dev/null
+++ b/tests/ref/fate/mxf-essencegroup-demux
@@ -0,0 +1,2 @@
+#tb 0: 1001/24000
+0, 0, 0, 1, 2080768, 0xe99233d9
diff --git a/tests/ref/fate/mxf-missing-index-demux b/tests/ref/fate/mxf-missing-index-demux
new file mode 100644
index 0000000000..8f03fc1e26
--- /dev/null
+++ b/tests/ref/fate/mxf-missing-index-demux
@@ -0,0 +1 @@
+CRC=0x48508eed
diff --git a/tests/ref/fate/mxpeg b/tests/ref/fate/mxpeg
new file mode 100644
index 0000000000..90af90f0c6
--- /dev/null
+++ b/tests/ref/fate/mxpeg
@@ -0,0 +1,31 @@
+#tb 0: 4/63
+0, 0, 0, 1, 1843200, 0x868a4e64
+0, 4, 4, 1, 1843200, 0x8dda4373
+0, 6, 6, 1, 1843200, 0xfcde3afc
+0, 8, 8, 1, 1843200, 0xeb4048a7
+0, 12, 12, 1, 1843200, 0xe2aa5718
+0, 14, 14, 1, 1843200, 0x86c35765
+0, 16, 16, 1, 1843200, 0x05c66542
+0, 18, 18, 1, 1843200, 0x020967f8
+0, 22, 22, 1, 1843200, 0x57757510
+0, 24, 24, 1, 1843200, 0xb91c61be
+0, 26, 26, 1, 1843200, 0x702381e9
+0, 30, 30, 1, 1843200, 0xe28c6851
+0, 32, 32, 1, 1843200, 0x7f806daa
+0, 34, 34, 1, 1843200, 0xc0758a39
+0, 38, 38, 1, 1843200, 0x3af87be2
+0, 40, 40, 1, 1843200, 0x1d1876eb
+0, 42, 42, 1, 1843200, 0x720e81dd
+0, 44, 44, 1, 1843200, 0xd85b7556
+0, 48, 48, 1, 1843200, 0xb9968314
+0, 50, 50, 1, 1843200, 0x946b9d34
+0, 52, 52, 1, 1843200, 0xd2d87d03
+0, 54, 54, 1, 1843200, 0xdd1b8056
+0, 58, 58, 1, 1843200, 0x436b7937
+0, 60, 60, 1, 1843200, 0xe87a6e42
+0, 62, 62, 1, 1843200, 0x57475c09
+0, 64, 64, 1, 1843200, 0xc3b45a77
+0, 68, 68, 1, 1843200, 0x0308494c
+0, 70, 70, 1, 1843200, 0x1ed02c80
+0, 72, 72, 1, 1843200, 0x48602e92
+0, 74, 74, 1, 1843200, 0xcf332caa
diff --git a/tests/ref/fate/nc-demux b/tests/ref/fate/nc-demux
index 1d00f8e24c..98318ac874 100644
--- a/tests/ref/fate/nc-demux
+++ b/tests/ref/fate/nc-demux
@@ -1,92 +1,93 @@
+#extradata 0: 19, 0x1afd0446
#tb 0: 1/100
0, 0, -9223372036854775808, 1, 19787, 0x75e463f3
-0, 1, -9223372036854775808, 1, 11913, 0x0f429c34
-0, 2, -9223372036854775808, 1, 14225, 0xbd3c704c
-0, 3, -9223372036854775808, 1, 10357, 0xbf232393
-0, 4, -9223372036854775808, 1, 9595, 0xf565d39e
-0, 5, -9223372036854775808, 1, 9262, 0x2afd6ce0
-0, 6, -9223372036854775808, 1, 12214, 0x6ae81d9b
-0, 7, -9223372036854775808, 1, 13920, 0x31b5b307
-0, 8, -9223372036854775808, 1, 10164, 0x141eca4e
-0, 9, -9223372036854775808, 1, 9516, 0xd5f2c42b
-0, 10, -9223372036854775808, 1, 10006, 0x80850a76
-0, 11, -9223372036854775808, 1, 11791, 0x10bc2dcd
-0, 12, -9223372036854775808, 1, 13756, 0xda1fee08
-0, 13, -9223372036854775808, 1, 10452, 0xbb3d62b0
-0, 14, -9223372036854775808, 1, 9171, 0x64ae10f6
-0, 15, -9223372036854775808, 1, 8816, 0x31ad8fcb
-0, 16, -9223372036854775808, 1, 13168, 0xea1085ac
-0, 17, -9223372036854775808, 1, 12797, 0x25143d22
-0, 18, -9223372036854775808, 1, 11324, 0x3a54b38e
-0, 19, -9223372036854775808, 1, 9173, 0x8b2bf552
-0, 20, -9223372036854775808, 1, 9247, 0x2e87226b
-0, 21, -9223372036854775808, 1, 14140, 0x1063786c
-0, 22, -9223372036854775808, 1, 14437, 0xde123a17
-0, 23, -9223372036854775808, 1, 11938, 0x3f1168f4
-0, 24, -9223372036854775808, 1, 11966, 0xdd6786ec
-0, 25, -9223372036854775808, 1, 13213, 0x8ab27c58
-0, 26, -9223372036854775808, 1, 11843, 0x90415d8b
-0, 27, -9223372036854775808, 1, 13345, 0x3c0e1793
-0, 28, -9223372036854775808, 1, 9977, 0x74fc7f4b
-0, 29, -9223372036854775808, 1, 9158, 0x0b5426a5
-0, 30, -9223372036854775808, 1, 12715, 0x0035d569
+0, 1, -9223372036854775808, 1, 11913, 0x0f429c34, F=0x0
+0, 2, -9223372036854775808, 1, 14225, 0xbd3c704c, F=0x0
+0, 3, -9223372036854775808, 1, 10357, 0xbf232393, F=0x0
+0, 4, -9223372036854775808, 1, 9595, 0xf565d39e, F=0x0
+0, 5, -9223372036854775808, 1, 9262, 0x2afd6ce0, F=0x0
+0, 6, -9223372036854775808, 1, 12214, 0x6ae81d9b, F=0x0
+0, 7, -9223372036854775808, 1, 13920, 0x31b5b307, F=0x0
+0, 8, -9223372036854775808, 1, 10164, 0x141eca4e, F=0x0
+0, 9, -9223372036854775808, 1, 9516, 0xd5f2c42b, F=0x0
+0, 10, -9223372036854775808, 1, 10006, 0x80850a76, F=0x0
+0, 11, -9223372036854775808, 1, 11791, 0x10bc2dcd, F=0x0
+0, 12, -9223372036854775808, 1, 13756, 0xda1fee08, F=0x0
+0, 13, -9223372036854775808, 1, 10452, 0xbb3d62b0, F=0x0
+0, 14, -9223372036854775808, 1, 9171, 0x64ae10f6, F=0x0
+0, 15, -9223372036854775808, 1, 8816, 0x31ad8fcb, F=0x0
+0, 16, -9223372036854775808, 1, 13168, 0xea1085ac, F=0x0
+0, 17, -9223372036854775808, 1, 12797, 0x25143d22, F=0x0
+0, 18, -9223372036854775808, 1, 11324, 0x3a54b38e, F=0x0
+0, 19, -9223372036854775808, 1, 9173, 0x8b2bf552, F=0x0
+0, 20, -9223372036854775808, 1, 9247, 0x2e87226b, F=0x0
+0, 21, -9223372036854775808, 1, 14140, 0x1063786c, F=0x0
+0, 22, -9223372036854775808, 1, 14437, 0xde123a17, F=0x0
+0, 23, -9223372036854775808, 1, 11938, 0x3f1168f4, F=0x0
+0, 24, -9223372036854775808, 1, 11966, 0xdd6786ec, F=0x0
+0, 25, -9223372036854775808, 1, 13213, 0x8ab27c58, F=0x0
+0, 26, -9223372036854775808, 1, 11843, 0x90415d8b, F=0x0
+0, 27, -9223372036854775808, 1, 13345, 0x3c0e1793, F=0x0
+0, 28, -9223372036854775808, 1, 9977, 0x74fc7f4b, F=0x0
+0, 29, -9223372036854775808, 1, 9158, 0x0b5426a5, F=0x0
+0, 30, -9223372036854775808, 1, 12715, 0x0035d569, F=0x0
0, 31, -9223372036854775808, 1, 19944, 0xe2887ba8
-0, 32, -9223372036854775808, 1, 12762, 0xb0f17939
-0, 33, -9223372036854775808, 1, 10260, 0x182b27aa
-0, 34, -9223372036854775808, 1, 7405, 0x227fe9bf
-0, 35, -9223372036854775808, 1, 13317, 0x1a678c62
-0, 36, -9223372036854775808, 1, 11304, 0x3277af6d
-0, 37, -9223372036854775808, 1, 13291, 0xe267616a
-0, 38, -9223372036854775808, 1, 8975, 0xe7eeacea
-0, 39, -9223372036854775808, 1, 8473, 0x8bb1cbff
-0, 40, -9223372036854775808, 1, 13878, 0xfd3d55bb
-0, 41, -9223372036854775808, 1, 11278, 0x61c7c55e
-0, 42, -9223372036854775808, 1, 13785, 0x2acbf88f
-0, 43, -9223372036854775808, 1, 9521, 0x99e2d065
-0, 44, -9223372036854775808, 1, 9340, 0xe5c96510
-0, 45, -9223372036854775808, 1, 12777, 0x4c3c7844
-0, 46, -9223372036854775808, 1, 10685, 0x39e0f42e
-0, 47, -9223372036854775808, 1, 14237, 0x9398d07f
-0, 48, -9223372036854775808, 1, 9021, 0x3343c7ec
-0, 49, -9223372036854775808, 1, 9327, 0xad489e86
-0, 50, -9223372036854775808, 1, 13507, 0xb1344f1c
-0, 51, -9223372036854775808, 1, 10199, 0x9a8868bf
-0, 52, -9223372036854775808, 1, 14535, 0xddb13f41
-0, 53, -9223372036854775808, 1, 8773, 0x3d8b6a79
-0, 54, -9223372036854775808, 1, 16084, 0x5d915de4
-0, 55, -9223372036854775808, 1, 9156, 0x5cb08a6a
-0, 56, -9223372036854775808, 1, 15027, 0xc23b1dc8
-0, 57, -9223372036854775808, 1, 8240, 0xd6d3526c
-0, 58, -9223372036854775808, 1, 8720, 0x439c43bf
-0, 59, -9223372036854775808, 1, 13684, 0x18fc82f0
-0, 60, -9223372036854775808, 1, 8829, 0xa3ebeb30
-0, 61, -9223372036854775808, 1, 14650, 0x99e8678c
+0, 32, -9223372036854775808, 1, 12762, 0xb0f17939, F=0x0
+0, 33, -9223372036854775808, 1, 10260, 0x182b27aa, F=0x0
+0, 34, -9223372036854775808, 1, 7405, 0x227fe9bf, F=0x0
+0, 35, -9223372036854775808, 1, 13317, 0x1a678c62, F=0x0
+0, 36, -9223372036854775808, 1, 11304, 0x3277af6d, F=0x0
+0, 37, -9223372036854775808, 1, 13291, 0xe267616a, F=0x0
+0, 38, -9223372036854775808, 1, 8975, 0xe7eeacea, F=0x0
+0, 39, -9223372036854775808, 1, 8473, 0x8bb1cbff, F=0x0
+0, 40, -9223372036854775808, 1, 13878, 0xfd3d55bb, F=0x0
+0, 41, -9223372036854775808, 1, 11278, 0x61c7c55e, F=0x0
+0, 42, -9223372036854775808, 1, 13785, 0x2acbf88f, F=0x0
+0, 43, -9223372036854775808, 1, 9521, 0x99e2d065, F=0x0
+0, 44, -9223372036854775808, 1, 9340, 0xe5c96510, F=0x0
+0, 45, -9223372036854775808, 1, 12777, 0x4c3c7844, F=0x0
+0, 46, -9223372036854775808, 1, 10685, 0x39e0f42e, F=0x0
+0, 47, -9223372036854775808, 1, 14237, 0x9398d07f, F=0x0
+0, 48, -9223372036854775808, 1, 9021, 0x3343c7ec, F=0x0
+0, 49, -9223372036854775808, 1, 9327, 0xad489e86, F=0x0
+0, 50, -9223372036854775808, 1, 13507, 0xb1344f1c, F=0x0
+0, 51, -9223372036854775808, 1, 10199, 0x9a8868bf, F=0x0
+0, 52, -9223372036854775808, 1, 14535, 0xddb13f41, F=0x0
+0, 53, -9223372036854775808, 1, 8773, 0x3d8b6a79, F=0x0
+0, 54, -9223372036854775808, 1, 16084, 0x5d915de4, F=0x0
+0, 55, -9223372036854775808, 1, 9156, 0x5cb08a6a, F=0x0
+0, 56, -9223372036854775808, 1, 15027, 0xc23b1dc8, F=0x0
+0, 57, -9223372036854775808, 1, 8240, 0xd6d3526c, F=0x0
+0, 58, -9223372036854775808, 1, 8720, 0x439c43bf, F=0x0
+0, 59, -9223372036854775808, 1, 13684, 0x18fc82f0, F=0x0
+0, 60, -9223372036854775808, 1, 8829, 0xa3ebeb30, F=0x0
+0, 61, -9223372036854775808, 1, 14650, 0x99e8678c, F=0x0
0, 62, -9223372036854775808, 1, 19626, 0x80a7ee5c
-0, 63, -9223372036854775808, 1, 7762, 0x7c209a12
-0, 64, -9223372036854775808, 1, 13636, 0xc89c1aa3
-0, 65, -9223372036854775808, 1, 8337, 0x749bf76a
-0, 66, -9223372036854775808, 1, 15098, 0xc98bc6dc
-0, 67, -9223372036854775808, 1, 9070, 0xcd4cf7f1
-0, 68, -9223372036854775808, 1, 8269, 0x90e95d54
-0, 69, -9223372036854775808, 1, 12672, 0x034888d0
-0, 70, -9223372036854775808, 1, 7519, 0x6c089672
-0, 71, -9223372036854775808, 1, 14439, 0x5d2478b9
-0, 72, -9223372036854775808, 1, 6928, 0x98fbaa67
-0, 73, -9223372036854775808, 1, 8735, 0x07643f1e
-0, 74, -9223372036854775808, 1, 13522, 0x55034cdb
-0, 75, -9223372036854775808, 1, 7807, 0xf5983103
-0, 76, -9223372036854775808, 1, 14484, 0xfc9cf260
-0, 77, -9223372036854775808, 1, 7193, 0x170a0fa1
-0, 78, -9223372036854775808, 1, 9444, 0x6f9be36f
-0, 79, -9223372036854775808, 1, 12598, 0x69b7609d
-0, 80, -9223372036854775808, 1, 7650, 0x1abaec9e
-0, 81, -9223372036854775808, 1, 15162, 0x2a87f723
-0, 82, -9223372036854775808, 1, 7752, 0xcca248aa
-0, 83, -9223372036854775808, 1, 9085, 0x1ca7d7e5
-0, 84, -9223372036854775808, 1, 13187, 0xababcc64
-0, 85, -9223372036854775808, 1, 7968, 0x64a28f46
-0, 86, -9223372036854775808, 1, 15474, 0xf34c587c
-0, 87, -9223372036854775808, 1, 8615, 0x61301034
-0, 88, -9223372036854775808, 1, 14129, 0x42c88bea
-0, 89, -9223372036854775808, 1, 7223, 0x675d7500
-0, 90, -9223372036854775808, 1, 3072, 0x4cb6254c
+0, 63, -9223372036854775808, 1, 7762, 0x7c209a12, F=0x0
+0, 64, -9223372036854775808, 1, 13636, 0xc89c1aa3, F=0x0
+0, 65, -9223372036854775808, 1, 8337, 0x749bf76a, F=0x0
+0, 66, -9223372036854775808, 1, 15098, 0xc98bc6dc, F=0x0
+0, 67, -9223372036854775808, 1, 9070, 0xcd4cf7f1, F=0x0
+0, 68, -9223372036854775808, 1, 8269, 0x90e95d54, F=0x0
+0, 69, -9223372036854775808, 1, 12672, 0x034888d0, F=0x0
+0, 70, -9223372036854775808, 1, 7519, 0x6c089672, F=0x0
+0, 71, -9223372036854775808, 1, 14439, 0x5d2478b9, F=0x0
+0, 72, -9223372036854775808, 1, 6928, 0x98fbaa67, F=0x0
+0, 73, -9223372036854775808, 1, 8735, 0x07643f1e, F=0x0
+0, 74, -9223372036854775808, 1, 13522, 0x55034cdb, F=0x0
+0, 75, -9223372036854775808, 1, 7807, 0xf5983103, F=0x0
+0, 76, -9223372036854775808, 1, 14484, 0xfc9cf260, F=0x0
+0, 77, -9223372036854775808, 1, 7193, 0x170a0fa1, F=0x0
+0, 78, -9223372036854775808, 1, 9444, 0x6f9be36f, F=0x0
+0, 79, -9223372036854775808, 1, 12598, 0x69b7609d, F=0x0
+0, 80, -9223372036854775808, 1, 7650, 0x1abaec9e, F=0x0
+0, 81, -9223372036854775808, 1, 15162, 0x2a87f723, F=0x0
+0, 82, -9223372036854775808, 1, 7752, 0xcca248aa, F=0x0
+0, 83, -9223372036854775808, 1, 9085, 0x1ca7d7e5, F=0x0
+0, 84, -9223372036854775808, 1, 13187, 0xababcc64, F=0x0
+0, 85, -9223372036854775808, 1, 7968, 0x64a28f46, F=0x0
+0, 86, -9223372036854775808, 1, 15474, 0xf34c587c, F=0x0
+0, 87, -9223372036854775808, 1, 8615, 0x61301034, F=0x0
+0, 88, -9223372036854775808, 1, 14129, 0x42c88bea, F=0x0
+0, 89, -9223372036854775808, 1, 7223, 0x675d7500, F=0x0
+0, 90, -9223372036854775808, 1, 3072, 0x4cb6254c, F=0x0
diff --git a/tests/ref/fate/nistsphere-demux b/tests/ref/fate/nistsphere-demux
new file mode 100644
index 0000000000..bb4874f842
--- /dev/null
+++ b/tests/ref/fate/nistsphere-demux
@@ -0,0 +1 @@
+CRC=0xc4faddaf
diff --git a/tests/ref/fate/nsv-demux b/tests/ref/fate/nsv-demux
index 0f094465db..0ad08b1a84 100644
--- a/tests/ref/fate/nsv-demux
+++ b/tests/ref/fate/nsv-demux
@@ -1,173 +1,173 @@
#tb 0: 1001/15000
#tb 1: 1/30000000
0, 0, 0, 1, 12, 0x1396035f
-0, 1, 1, 1, 24, 0x8ab80ac7
-0, 2, 2, 1, 208, 0x1de1603e
+0, 1, 1, 1, 24, 0x8ab80ac7, F=0x0
+0, 2, 2, 1, 208, 0x1de1603e, F=0x0
1, 4173848, 4173848, 1567346, 104, 0x8ae85dc9
1, 5741194, 5741194, 1567346, 105, 0xb7033847
-0, 3, 3, 1, 364, 0xffb4b341
+0, 3, 3, 1, 364, 0xffb4b341, F=0x0
1, 7308540, 7308540, 1567346, 104, 0x5f853482
-0, 4, 4, 1, 456, 0x7a4deaeb
+0, 4, 4, 1, 456, 0x7a4deaeb, F=0x0
1, 8875886, 8875886, 1567346, 105, 0xfcb731fd
-0, 5, 5, 1, 432, 0xf4ddd813
+0, 5, 5, 1, 432, 0xf4ddd813, F=0x0
1, 10443232, 10443232, 1567346, 104, 0x4f8232bb
1, 12010578, 12010578, 1567346, 105, 0x2f543039
-0, 6, 6, 1, 572, 0xc84c21ff
+0, 6, 6, 1, 572, 0xc84c21ff, F=0x0
1, 13577924, 13577924, 1567346, 104, 0xe4cc34a1
-0, 7, 7, 1, 500, 0x0e6bf9f4
+0, 7, 7, 1, 500, 0x0e6bf9f4, F=0x0
1, 15145270, 15145270, 1567346, 105, 0xea663711
-0, 8, 8, 1, 508, 0x2d6efe2a
+0, 8, 8, 1, 508, 0x2d6efe2a, F=0x0
1, 16712616, 16712616, 1567346, 104, 0x3c583098
-0, 9, 9, 1, 436, 0x7d07d3c5
+0, 9, 9, 1, 436, 0x7d07d3c5, F=0x0
1, 18279962, 18279962, 1567346, 105, 0xbe6c33ff
1, 19847308, 19847308, 1567346, 104, 0x56de2d7a
-0, 10, 10, 1, 620, 0xa9313342
+0, 10, 10, 1, 620, 0xa9313342, F=0x0
1, 21414654, 21414654, 1567346, 105, 0x4e80385d
0, 11, 11, 1, 1384, 0x9b97c579
1, 22982000, 22982000, 1567346, 104, 0x34eb340d
-0, 12, 12, 1, 760, 0xd1aa8183
+0, 12, 12, 1, 760, 0xd1aa8183, F=0x0
1, 24549346, 24549346, 1567346, 105, 0x87e82f74
-0, 13, 13, 1, 836, 0x261da980
+0, 13, 13, 1, 836, 0x261da980, F=0x0
1, 26116692, 26116692, 1567346, 104, 0xa546377d
1, 27684038, 27684038, 1567346, 105, 0x92bd349d
-0, 14, 14, 1, 860, 0x52f0afa0
+0, 14, 14, 1, 860, 0x52f0afa0, F=0x0
1, 29251384, 29251384, 1567346, 104, 0xdba53f3d
-0, 15, 15, 1, 696, 0x63845855
+0, 15, 15, 1, 696, 0x63845855, F=0x0
1, 30818730, 30818730, 1567346, 105, 0xd3c3384e
-0, 16, 16, 1, 460, 0x2916e7be
+0, 16, 16, 1, 460, 0x2916e7be, F=0x0
1, 32386076, 32386076, 1567346, 104, 0xdf7d30ce
1, 33953422, 33953422, 1567346, 105, 0xae20344e
-0, 17, 17, 1, 328, 0xab8caaca
+0, 17, 17, 1, 328, 0xab8caaca, F=0x0
1, 35520768, 35520768, 1567346, 104, 0xe4cc33b7
-0, 18, 18, 1, 396, 0xc775bc8e
+0, 18, 18, 1, 396, 0xc775bc8e, F=0x0
1, 37088114, 37088114, 1567346, 105, 0xda993806
-0, 19, 19, 1, 344, 0x114ea25a
+0, 19, 19, 1, 344, 0x114ea25a, F=0x0
1, 38655460, 38655460, 1567346, 104, 0xd6d12edd
1, 40222806, 40222806, 1567346, 105, 0x6b9c2ed5
1, 41790152, 41790152, 1567346, 104, 0xce6c3b04
-0, 21, 21, 1, 532, 0xd5650f54
+0, 21, 21, 1, 532, 0xd5650f54, F=0x0
1, 43357498, 43357498, 1567346, 105, 0x31db399e
1, 44924844, 44924844, 1567346, 104, 0xd50b347a
-0, 23, 23, 1, 476, 0x77f1f3a7
+0, 23, 23, 1, 476, 0x77f1f3a7, F=0x0
1, 46492190, 46492190, 1567346, 105, 0xe87734d6
1, 48059536, 48059536, 1567346, 104, 0x21873412
0, 25, 25, 1, 976, 0x2f7cf7ae
1, 50140000, 50140000, 1567346, 105, 0x29c03514
1, 51707346, 51707346, 1567346, 104, 0x91a5347a
1, 53274692, 53274692, 1567346, 105, 0xdbbf3696
-0, 27, 27, 1, 104, 0x8fbf2f65
+0, 27, 27, 1, 104, 0x8fbf2f65, F=0x0
1, 54842038, 54842038, 1567346, 104, 0x3b463afc
1, 56409384, 56409384, 1567346, 105, 0xddf53845
1, 57976730, 57976730, 1567346, 104, 0x94c23d1a
-0, 29, 29, 1, 652, 0xa9244ac0
+0, 29, 29, 1, 652, 0xa9244ac0, F=0x0
1, 59544076, 59544076, 1567346, 105, 0xc0fd36c4
1, 61111422, 61111422, 1567346, 104, 0x36d535e0
-0, 31, 31, 1, 152, 0x97804cc1
+0, 31, 31, 1, 152, 0x97804cc1, F=0x0
1, 62678768, 62678768, 1567346, 105, 0xe81a35da
1, 64246114, 64246114, 1567346, 104, 0x2b4e3699
1, 65813460, 65813460, 1567346, 105, 0x3978392c
-0, 33, 33, 1, 156, 0xca434d31
+0, 33, 33, 1, 156, 0xca434d31, F=0x0
1, 67380806, 67380806, 1567346, 104, 0xca903459
-0, 34, 34, 1, 196, 0x1ff16161
+0, 34, 34, 1, 196, 0x1ff16161, F=0x0
1, 68948152, 68948152, 1567346, 105, 0xedc4374a
-0, 35, 35, 1, 176, 0x9b455230
+0, 35, 35, 1, 176, 0x9b455230, F=0x0
1, 70515498, 70515498, 1567346, 104, 0x0b3938d2
-0, 36, 36, 1, 156, 0xbbbf4bf3
+0, 36, 36, 1, 156, 0xbbbf4bf3, F=0x0
1, 72082844, 72082844, 1567346, 105, 0xb2653246
1, 73650190, 73650190, 1567346, 104, 0x76333479
-0, 37, 37, 1, 220, 0x77a97152
+0, 37, 37, 1, 220, 0x77a97152, F=0x0
1, 75217536, 75217536, 1567346, 105, 0x779138c4
-0, 38, 38, 1, 204, 0x667d5ecf
+0, 38, 38, 1, 204, 0x667d5ecf, F=0x0
1, 76784882, 76784882, 1567346, 104, 0xfe142f55
-0, 39, 39, 1, 232, 0x3a266ccd
+0, 39, 39, 1, 232, 0x3a266ccd, F=0x0
1, 78352228, 78352228, 1567346, 105, 0x39aa3410
1, 79919574, 79919574, 1567346, 104, 0x520f330d
-0, 40, 40, 1, 308, 0x844a95b7
+0, 40, 40, 1, 308, 0x844a95b7, F=0x0
1, 81486920, 81486920, 1567346, 104, 0x1aad37b0
-0, 41, 41, 1, 384, 0x71d2c695
+0, 41, 41, 1, 384, 0x71d2c695, F=0x0
1, 83054266, 83054266, 1567346, 105, 0x164038eb
1, 84621612, 84621612, 1567346, 104, 0x21d434bd
-0, 43, 43, 1, 520, 0x4f9d012a
+0, 43, 43, 1, 520, 0x4f9d012a, F=0x0
1, 86188958, 86188958, 1567346, 105, 0x9c1236d4
1, 87756304, 87756304, 1567346, 104, 0x6aa933c3
1, 89323650, 89323650, 1567346, 105, 0xec5c371e
-0, 45, 45, 1, 648, 0xabd13b29
+0, 45, 45, 1, 648, 0xabd13b29, F=0x0
1, 90890996, 90890996, 1567346, 104, 0xedb33251
1, 92458342, 92458342, 1567346, 105, 0x4f953476
1, 94025688, 94025688, 1567346, 104, 0x7da13400
-0, 47, 47, 1, 604, 0x006b328f
+0, 47, 47, 1, 604, 0x006b328f, F=0x0
1, 95593034, 95593034, 1567346, 105, 0x57a83aaa
1, 97160380, 97160380, 1567346, 104, 0x8b822f2f
-0, 49, 49, 1, 492, 0xa150fac1
+0, 49, 49, 1, 492, 0xa150fac1, F=0x0
1, 98727726, 98727726, 1567346, 105, 0x3b31341a
1, 100295072, 100295072, 1567346, 104, 0x74a4316d
1, 101862418, 101862418, 1567346, 105, 0x05013469
-0, 51, 51, 1, 456, 0xd3e9e52c
+0, 51, 51, 1, 456, 0xd3e9e52c, F=0x0
1, 103429764, 103429764, 1567346, 104, 0xcc8932cb
1, 104997110, 104997110, 1567346, 105, 0xd9233422
-0, 53, 53, 1, 340, 0x7229a1b7
+0, 53, 53, 1, 340, 0x7229a1b7, F=0x0
1, 106564456, 106564456, 1567346, 104, 0x5c603350
1, 108131802, 108131802, 1567346, 105, 0x76e631bc
1, 109699148, 109699148, 1567346, 104, 0x657e3b35
-0, 55, 55, 1, 280, 0x48948b60
+0, 55, 55, 1, 280, 0x48948b60, F=0x0
1, 111266494, 111266494, 1567346, 105, 0x9d283226
1, 112833840, 112833840, 1567346, 104, 0x574936ef
-0, 57, 57, 1, 304, 0x3ae68dcf
+0, 57, 57, 1, 304, 0x3ae68dcf, F=0x0
1, 114401186, 114401186, 1567346, 105, 0x1b923555
1, 115968532, 115968532, 1567346, 104, 0x2a9f3583
1, 117535878, 117535878, 1567346, 105, 0xb8cd306f
-0, 59, 59, 1, 324, 0x005da2ab
+0, 59, 59, 1, 324, 0x005da2ab, F=0x0
1, 119103224, 119103224, 1567346, 104, 0xa21d3475
1, 120670570, 120670570, 1567346, 105, 0x651539ea
-0, 61, 61, 1, 348, 0x3230a873
+0, 61, 61, 1, 348, 0x3230a873, F=0x0
1, 122237916, 122237916, 1567346, 104, 0x7b7235b8
1, 123805262, 123805262, 1567346, 105, 0x2bbb337a
1, 125372608, 125372608, 1567346, 104, 0x26c332eb
-0, 63, 63, 1, 336, 0x8655ad2d
+0, 63, 63, 1, 336, 0x8655ad2d, F=0x0
1, 126939954, 126939954, 1567346, 105, 0x990838d8
1, 128507300, 128507300, 1567346, 104, 0x4dc63ad4
1, 130074646, 130074646, 1567346, 105, 0xfb8e3418
-0, 65, 65, 1, 380, 0x742ebc44
+0, 65, 65, 1, 380, 0x742ebc44, F=0x0
1, 131641992, 131641992, 1567346, 104, 0x1882388e
1, 133209338, 133209338, 1567346, 105, 0xe6b534cc
-0, 67, 67, 1, 340, 0xfc1aa74e
+0, 67, 67, 1, 340, 0xfc1aa74e, F=0x0
1, 134776684, 134776684, 1567346, 104, 0x60fe35d0
1, 136344030, 136344030, 1567346, 105, 0x5164354a
1, 137911376, 137911376, 1567346, 104, 0x92ee3115
-0, 69, 69, 1, 332, 0x3cfba56c
+0, 69, 69, 1, 332, 0x3cfba56c, F=0x0
1, 139478722, 139478722, 1567346, 105, 0x9b32327e
1, 141046068, 141046068, 1567346, 104, 0x9b9e394a
-0, 71, 71, 1, 332, 0xc024ad4c
+0, 71, 71, 1, 332, 0xc024ad4c, F=0x0
1, 142613414, 142613414, 1567346, 105, 0xce3c337f
1, 144180760, 144180760, 1567346, 104, 0x7a4e33c5
0, 73, 73, 1, 3432, 0xcdfcd1c9
1, 146956000, 146956000, 1567346, 105, 0x0e3d34eb
1, 148523346, 148523346, 1567346, 104, 0xd23e338e
1, 150090692, 150090692, 1567346, 105, 0x4abf340c
-0, 75, 75, 1, 792, 0xe7df949f
+0, 75, 75, 1, 792, 0xe7df949f, F=0x0
1, 151658038, 151658038, 1567346, 104, 0xe7522e15
1, 153225384, 153225384, 1567346, 105, 0x995037ba
-0, 77, 77, 1, 912, 0xbc61d549
+0, 77, 77, 1, 912, 0xbc61d549, F=0x0
1, 154792730, 154792730, 1567346, 104, 0x5ef12e9b
1, 156360076, 156360076, 1567346, 105, 0x5c3b3166
1, 157927422, 157927422, 1567346, 104, 0xfc38314b
-0, 79, 79, 1, 956, 0x809bdff0
+0, 79, 79, 1, 956, 0x809bdff0, F=0x0
1, 159494768, 159494768, 1567346, 104, 0x5e3636e4
1, 161062114, 161062114, 1567346, 105, 0xae7b3345
-0, 81, 81, 1, 652, 0x88d3484f
+0, 81, 81, 1, 652, 0x88d3484f, F=0x0
1, 162629460, 162629460, 1567346, 104, 0x635c317a
1, 164196806, 164196806, 1567346, 105, 0xa90c361a
1, 165764152, 165764152, 1567346, 104, 0x8f563594
0, 83, 83, 1, 1284, 0xecc37164
1, 167156000, 167156000, 1567346, 105, 0x028e3985
1, 168723346, 168723346, 1567346, 104, 0x4fd135f6
-0, 85, 85, 1, 428, 0x4794e174
+0, 85, 85, 1, 428, 0x4794e174, F=0x0
1, 170290692, 170290692, 1567346, 105, 0xaaf539ac
1, 171858038, 171858038, 1567346, 104, 0x668b3265
1, 173425384, 173425384, 1567346, 105, 0x74ad3b4b
-0, 87, 87, 1, 460, 0x7253d94a
+0, 87, 87, 1, 460, 0x7253d94a, F=0x0
1, 174992730, 174992730, 1567346, 104, 0xbde5332f
1, 176560076, 176560076, 1567346, 105, 0xdc3631e7
1, 178127422, 178127422, 1567346, 104, 0x3e363a1e
-0, 89, 89, 1, 24, 0x664206ba
+0, 89, 89, 1, 24, 0x664206ba, F=0x0
1, 179694768, 179694768, 1567346, 105, 0x48b63926
diff --git a/tests/ref/fate/nuv-rtjpeg b/tests/ref/fate/nuv-rtjpeg
index a5c9c4a6f3..96ead33cbd 100644
--- a/tests/ref/fate/nuv-rtjpeg
+++ b/tests/ref/fate/nuv-rtjpeg
@@ -1,9 +1,9 @@
-#tb 0: 1/1000
-0, 118, 118, 0, 460800, 0x54aedafe
-0, 152, 152, 0, 460800, 0xb7aa8b56
-0, 177, 177, 0, 460800, 0x283ea3b5
-0, 202, 202, 0, 460800, 0x283ea3b5
-0, 235, 235, 0, 460800, 0x10e577de
-0, 269, 269, 0, 460800, 0x4e091ee2
-0, 302, 302, 0, 460800, 0x2ea88828
-0, 335, 335, 0, 460800, 0x4b7f4df0
+#tb 0: 100/2997
+0, 4, 4, 1, 460800, 0x54aedafe
+0, 5, 5, 1, 460800, 0xb7aa8b56
+0, 6, 6, 1, 460800, 0x283ea3b5
+0, 7, 7, 1, 460800, 0x283ea3b5
+0, 8, 8, 1, 460800, 0x10e577de
+0, 9, 9, 1, 460800, 0x4e091ee2
+0, 10, 10, 1, 460800, 0x2ea88828
+0, 11, 11, 1, 460800, 0x4b7f4df0
diff --git a/tests/ref/fate/nuv-rtjpeg-fh b/tests/ref/fate/nuv-rtjpeg-fh
index 71e6bf9713..b2e04cb015 100644
--- a/tests/ref/fate/nuv-rtjpeg-fh
+++ b/tests/ref/fate/nuv-rtjpeg-fh
@@ -1,51 +1,51 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 221184, 0xdaf54f83
-0, 40, 40, 0, 221184, 0xeea3e3b4
-0, 60, 60, 0, 221184, 0x5f1a8525
-0, 80, 80, 0, 221184, 0x950bb170
-0, 100, 100, 0, 221184, 0x6262e94c
-0, 120, 120, 0, 221184, 0x28752197
-0, 140, 140, 0, 221184, 0x0c2811e7
-0, 160, 160, 0, 221184, 0xb2c1a729
-0, 200, 200, 0, 221184, 0x998d6144
-0, 220, 220, 0, 221184, 0xf5d52311
-0, 240, 240, 0, 221184, 0xea9dd6bf
-0, 260, 260, 0, 221184, 0x0e2ed854
-0, 280, 280, 0, 221184, 0xe295ba58
-0, 300, 300, 0, 221184, 0x8aedbb69
-0, 320, 320, 0, 221184, 0x253c9aaa
-0, 340, 340, 0, 221184, 0x5eaf9fb1
-0, 360, 360, 0, 221184, 0xcdb5a0cb
-0, 380, 380, 0, 221184, 0xcdb5a0cb
-0, 400, 400, 0, 221184, 0x23f89994
-0, 420, 420, 0, 221184, 0x23f89994
-0, 440, 440, 0, 221184, 0x10dc98d6
-0, 460, 460, 0, 221184, 0x799b9d98
-0, 480, 480, 0, 221184, 0xb226996c
-0, 500, 500, 0, 221184, 0x0ac59a42
-0, 520, 520, 0, 221184, 0x87c2a654
-0, 540, 540, 0, 221184, 0xf4c1a711
-0, 560, 560, 0, 221184, 0xf60fa72e
-0, 580, 580, 0, 221184, 0xc8f8b6fc
-0, 600, 600, 0, 221184, 0xd709b813
-0, 620, 620, 0, 221184, 0x5fdfb76b
-0, 640, 640, 0, 221184, 0x5798b0aa
-0, 660, 660, 0, 221184, 0xf572b1c3
-0, 680, 680, 0, 221184, 0x14b0afdf
-0, 700, 700, 0, 221184, 0x0a66b5b8
-0, 720, 720, 0, 221184, 0xe316c620
-0, 740, 740, 0, 221184, 0xbc76c5c2
-0, 760, 760, 0, 221184, 0x77c7c5e5
-0, 780, 780, 0, 221184, 0xfc7ac63e
-0, 800, 800, 0, 221184, 0x05a29ffe
-0, 820, 820, 0, 221184, 0x9bffbf6c
-0, 840, 840, 0, 221184, 0x3c55be40
-0, 860, 860, 0, 221184, 0x6f46c14e
-0, 880, 880, 0, 221184, 0x9cf4ae70
-0, 900, 900, 0, 221184, 0xf205b2f8
-0, 920, 920, 0, 221184, 0x7180aff8
-0, 940, 940, 0, 221184, 0x125eaffe
-0, 960, 960, 0, 221184, 0x6970a32d
-0, 980, 980, 0, 221184, 0xaea79f62
-0, 1000, 1000, 0, 221184, 0x48d2a093
-0, 1020, 1020, 0, 221184, 0x10a59eb5
+#tb 0: 1/50
+0, 80, 80, 1, 221184, 0xdaf54f83
+0, 82, 82, 1, 221184, 0xeea3e3b4
+0, 83, 83, 1, 221184, 0x5f1a8525
+0, 84, 84, 1, 221184, 0x950bb170
+0, 85, 85, 1, 221184, 0x6262e94c
+0, 86, 86, 1, 221184, 0x28752197
+0, 87, 87, 1, 221184, 0x0c2811e7
+0, 88, 88, 1, 221184, 0xb2c1a729
+0, 90, 90, 1, 221184, 0x998d6144
+0, 91, 91, 1, 221184, 0xf5d52311
+0, 92, 92, 1, 221184, 0xea9dd6bf
+0, 93, 93, 1, 221184, 0x0e2ed854
+0, 94, 94, 1, 221184, 0xe295ba58
+0, 95, 95, 1, 221184, 0x8aedbb69
+0, 96, 96, 1, 221184, 0x253c9aaa
+0, 97, 97, 1, 221184, 0x5eaf9fb1
+0, 98, 98, 1, 221184, 0xcdb5a0cb
+0, 99, 99, 1, 221184, 0xcdb5a0cb
+0, 100, 100, 1, 221184, 0x23f89994
+0, 101, 101, 1, 221184, 0x23f89994
+0, 102, 102, 1, 221184, 0x10dc98d6
+0, 103, 103, 1, 221184, 0x799b9d98
+0, 104, 104, 1, 221184, 0xb226996c
+0, 105, 105, 1, 221184, 0x0ac59a42
+0, 106, 106, 1, 221184, 0x87c2a654
+0, 107, 107, 1, 221184, 0xf4c1a711
+0, 108, 108, 1, 221184, 0xf60fa72e
+0, 109, 109, 1, 221184, 0xc8f8b6fc
+0, 110, 110, 1, 221184, 0xd709b813
+0, 111, 111, 1, 221184, 0x5fdfb76b
+0, 112, 112, 1, 221184, 0x5798b0aa
+0, 113, 113, 1, 221184, 0xf572b1c3
+0, 114, 114, 1, 221184, 0x14b0afdf
+0, 115, 115, 1, 221184, 0x0a66b5b8
+0, 116, 116, 1, 221184, 0xe316c620
+0, 117, 117, 1, 221184, 0xbc76c5c2
+0, 118, 118, 1, 221184, 0x77c7c5e5
+0, 119, 119, 1, 221184, 0xfc7ac63e
+0, 120, 120, 1, 221184, 0x05a29ffe
+0, 121, 121, 1, 221184, 0x9bffbf6c
+0, 122, 122, 1, 221184, 0x3c55be40
+0, 123, 123, 1, 221184, 0x6f46c14e
+0, 124, 124, 1, 221184, 0x9cf4ae70
+0, 125, 125, 1, 221184, 0xf205b2f8
+0, 126, 126, 1, 221184, 0x7180aff8
+0, 127, 127, 1, 221184, 0x125eaffe
+0, 128, 128, 1, 221184, 0x6970a32d
+0, 129, 129, 1, 221184, 0xaea79f62
+0, 130, 130, 1, 221184, 0x48d2a093
+0, 131, 131, 1, 221184, 0x10a59eb5
diff --git a/tests/ref/fate/oggvp8-demux b/tests/ref/fate/oggvp8-demux
new file mode 100644
index 0000000000..96beb8c96f
--- /dev/null
+++ b/tests/ref/fate/oggvp8-demux
@@ -0,0 +1,71 @@
+#tb 0: 1/30
+0, 0, 0, 1, 5014, 0x4798fa33
+0, 1, 1, 1, 822, 0x596486c5, F=0x0
+0, 2, 2, 1, 840, 0xf06490ba, F=0x0
+0, 3, 3, 1, 853, 0x1db19d31, F=0x0
+0, 4, 4, 1, 885, 0x5a1aa91f, F=0x0
+0, 5, 5, 1, 902, 0xaabdb1ce, F=0x0
+0, 6, 6, 1, 854, 0x6eb1954e, F=0x0
+0, 7, 7, 1, 3086, 0xe4c12b4a, F=0x0
+0, 8, 8, 1, 732, 0x3c0868bc, F=0x0
+0, 9, 9, 1, 719, 0xa0995781, F=0x0
+0, 10, 10, 1, 749, 0xce2c6ce9, F=0x0
+0, 11, 11, 1, 869, 0x9080b554, F=0x0
+0, 12, 12, 1, 967, 0x8cd5e57a, F=0x0
+0, 13, 13, 1, 1581, 0xd0cc21d8, F=0x0
+0, 14, 14, 1, 934, 0x94facbdc, F=0x0
+0, 15, 15, 1, 841, 0xb00aa233, F=0x0
+0, 16, 16, 1, 820, 0xe93da769, F=0x0
+0, 17, 17, 1, 818, 0xa2ff91cb, F=0x0
+0, 18, 18, 1, 3113, 0x8e74377b, F=0x0
+0, 19, 19, 1, 733, 0xc88e7918, F=0x0
+0, 20, 20, 1, 745, 0x41116e83, F=0x0
+0, 21, 21, 1, 764, 0xc89a7652, F=0x0
+0, 22, 22, 1, 730, 0xe9586ef3, F=0x0
+0, 23, 23, 1, 736, 0x89437b6a, F=0x0
+0, 24, 24, 1, 1268, 0x0e985dc0, F=0x0
+0, 25, 25, 1, 805, 0x8f78897f, F=0x0
+0, 26, 26, 1, 769, 0xe5417a9b, F=0x0
+0, 27, 27, 1, 739, 0x5c0f72ea, F=0x0
+0, 28, 28, 1, 730, 0x0f556cb5, F=0x0
+0, 29, 29, 1, 3057, 0x8fb3e57c, F=0x0
+0, 30, 30, 1, 763, 0xc69479da, F=0x0
+0, 31, 31, 1, 745, 0x757b7265, F=0x0
+0, 32, 32, 1, 712, 0x20a75fc2, F=0x0
+0, 33, 33, 1, 723, 0x44016897, F=0x0
+0, 34, 34, 1, 716, 0x18f96229, F=0x0
+0, 35, 35, 1, 1132, 0xe1542e3e, F=0x0
+0, 36, 36, 1, 774, 0x0027865b, F=0x0
+0, 37, 37, 1, 770, 0x1bd67c7e, F=0x0
+0, 38, 38, 1, 755, 0xdb54746a, F=0x0
+0, 39, 39, 1, 726, 0x010973bd, F=0x0
+0, 40, 40, 1, 3078, 0x9971fe7a, F=0x0
+0, 41, 41, 1, 749, 0xcd7873de, F=0x0
+0, 42, 42, 1, 722, 0x05c86a36, F=0x0
+0, 43, 43, 1, 726, 0x4a356dd8, F=0x0
+0, 44, 44, 1, 710, 0x62176453, F=0x0
+0, 45, 45, 1, 707, 0xfb8b5c7c, F=0x0
+0, 46, 46, 1, 1143, 0x771832ff, F=0x0
+0, 47, 47, 1, 780, 0x3fb488a0, F=0x0
+0, 48, 48, 1, 720, 0xbbf27127, F=0x0
+0, 49, 49, 1, 740, 0xc6276dcb, F=0x0
+0, 50, 50, 1, 781, 0xa45586f4, F=0x0
+0, 51, 51, 1, 3122, 0x9e87222e, F=0x0
+0, 52, 52, 1, 748, 0xe5827d61, F=0x0
+0, 53, 53, 1, 740, 0x7b436f4c, F=0x0
+0, 54, 54, 1, 748, 0xa7b972fe, F=0x0
+0, 55, 55, 1, 731, 0x2a0a67d1, F=0x0
+0, 56, 56, 1, 733, 0x8c956ae1, F=0x0
+0, 57, 57, 1, 1132, 0x60f41eaa, F=0x0
+0, 58, 58, 1, 755, 0x72a276b8, F=0x0
+0, 59, 59, 1, 765, 0x4da18195, F=0x0
+0, 60, 60, 1, 715, 0x33b35877, F=0x0
+0, 61, 61, 1, 769, 0x16b6867e, F=0x0
+0, 62, 62, 1, 3219, 0x465f474f, F=0x0
+0, 63, 63, 1, 732, 0xb2f56da4, F=0x0
+0, 64, 64, 1, 808, 0xeca18ba7, F=0x0
+0, 65, 65, 1, 772, 0x7c978926, F=0x0
+0, 66, 66, 1, 791, 0x0c238441, F=0x0
+0, 67, 67, 1, 778, 0x55e0844e, F=0x0
+0, 68, 68, 1, 1443, 0x9cbed37b, F=0x0
+0, 69, 69, 1, 862, 0xbdcaa8b9, F=0x0
diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt
new file mode 100644
index 0000000000..3aa7423efd
--- /dev/null
+++ b/tests/ref/fate/opt
@@ -0,0 +1,364 @@
+Testing default values
+num=0
+toggle=1
+string=default
+escape=\=,
+flags=1
+rational=1/1
+video_rate=25/1
+width=200 height=300
+pix_fmt=0bgr
+sample_fmt=s16
+duration=1000
+color=255 192 203 255
+channel_layout=311=311
+binary=62 69 6e 0
+binary_size=4
+num64=1
+flt=0.333333
+dbl=0.333333
+TestContext AVOptions:
+ -num <int> E....... set num (from 0 to 100) (default 0)
+ -toggle <int> E....... set toggle (from 0 to 1) (default 1)
+ -rational <rational> E....... set rational (from 0 to 10) (default 1/1)
+ -string <string> E....... set string (default "default")
+ -escape <string> E....... set escape str (default "\=,")
+ -flags <flags> E....... set flags (default 1)
+ cool E....... set cool flag
+ lame E....... set lame flag
+ mu E....... set mu flag
+ -size <image_size> E....... set size (default "200x300")
+ -pix_fmt <pix_fmt> E....... set pixfmt (default 0bgr)
+ -sample_fmt <sample_fmt> E....... set samplefmt (default s16)
+ -video_rate <video_rate> E....... set videorate (default "25")
+ -duration <duration> E....... set duration (default 1000)
+ -color <color> E....... set color (default "pink")
+ -cl <channel_layout> E....... set channel layout (default 0x137)
+ -bin <binary> E....... set binary value
+ -bin1 <binary> E....... set binary value
+ -bin2 <binary> E....... set binary value
+ -num64 <int64> E....... set num 64bit (from 0 to 100) (default 1)
+ -flt <float> E....... set float (from 0 to 100) (default 0.333333)
+ -dbl <double> E....... set double (from 0 to 100) (default 0.333333)
+
+Testing av_opt_is_set_to_default()
+name: num default:1 error:
+name: toggle default:0 error:
+name: rational default:0 error:
+name: string default:0 error:
+name: escape default:0 error:
+name: flags default:0 error:
+name: cool default:1 error:Option not found
+name: lame default:1 error:Option not found
+name: mu default:1 error:Option not found
+name: size default:0 error:
+name: pix_fmt default:0 error:
+name:sample_fmt default:0 error:
+name:video_rate default:0 error:
+name: duration default:0 error:
+name: color default:0 error:
+name: cl default:0 error:
+name: bin default:0 error:
+name: bin1 default:1 error:
+name: bin2 default:1 error:
+name: num64 default:0 error:
+name: flt default:0 error:
+name: dbl default:0 error:
+name: num default:1 error:
+name: toggle default:1 error:
+name: rational default:1 error:
+name: string default:1 error:
+name: escape default:1 error:
+name: flags default:1 error:
+name: cool default:1 error:Option not found
+name: lame default:1 error:Option not found
+name: mu default:1 error:Option not found
+name: size default:1 error:
+name: pix_fmt default:1 error:
+name:sample_fmt default:1 error:
+name:video_rate default:1 error:
+name: duration default:1 error:
+name: color default:1 error:
+name: cl default:1 error:
+name: bin default:1 error:
+name: bin1 default:1 error:
+name: bin2 default:1 error:
+name: num64 default:1 error:
+name: flt default:1 error:
+name: dbl default:1 error:
+
+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:00:00.001000,color=0xffc0cbff,cl=0x137,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333
+Setting entry with key 'num' to value '0'
+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'
+Setting entry with key 'escape' to value '\=,'
+Setting entry with key 'flags' to value '0x00000001'
+Setting entry with key 'size' to value '200x300'
+Setting entry with key 'pix_fmt' to value '0bgr'
+Setting entry with key 'sample_fmt' to value 's16'
+Setting entry with key 'video_rate' to value '25/1'
+Setting entry with key 'duration' to value '0:00:00.001000'
+Setting entry with key 'color' to value '0xffc0cbff'
+Setting entry with key 'cl' to value '0x137'
+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 'flt' to value '0.333333'
+Setting entry with key 'dbl' to value '0.333333'
+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:00:00.001000,color=0xffc0cbff,cl=0x137,bin=62696E00,bin1=,bin2=,num64=1,flt=0.333333,dbl=0.333333
+
+Testing av_set_options_string()
+Setting options string ''
+OK ''
+Setting options string ':'
+Missing key or no key/value separator found after key ':'
+Error ':'
+Setting options string '='
+Missing key or no key/value separator found after key ''
+Error '='
+Setting options string 'foo=:'
+Setting entry with key 'foo' to value ''
+Key 'foo' not found.
+Error 'foo=:'
+Setting options string ':=foo'
+Setting entry with key ':' to value 'foo'
+Key ':' not found.
+Error ':=foo'
+Setting options string '=foo'
+Missing key or no key/value separator found after key ''
+Error '=foo'
+Setting options string 'foo='
+Setting entry with key 'foo' to value ''
+Key 'foo' not found.
+Error 'foo='
+Setting options string 'foo'
+Missing key or no key/value separator found after key 'foo'
+Error 'foo'
+Setting options string 'foo=val'
+Setting entry with key 'foo' to value 'val'
+Key 'foo' not found.
+Error 'foo=val'
+Setting options string 'foo==val'
+Setting entry with key 'foo' to value '=val'
+Key 'foo' not found.
+Error 'foo==val'
+Setting options string 'toggle=:'
+Setting entry with key 'toggle' to value ''
+Undefined constant or missing '(' in ''
+Unable to parse option value ""
+Error 'toggle=:'
+Setting options string 'string=:'
+Setting entry with key 'string' to value ''
+OK 'string=:'
+Setting options string 'toggle=1 : foo'
+Setting entry with key 'toggle' to value '1'
+Missing key or no key/value separator found after key 'foo'
+Error 'toggle=1 : foo'
+Setting options string 'toggle=100'
+Setting entry with key 'toggle' to value '100'
+Value 100.000000 for parameter 'toggle' out of range [0 - 1]
+Error 'toggle=100'
+Setting options string 'toggle==1'
+Setting entry with key 'toggle' to value '=1'
+Undefined constant or missing '(' in '=1'
+Unable to parse option value "=1"
+Error 'toggle==1'
+Setting options string 'flags=+mu-lame : num=42: toggle=0'
+Setting entry with key 'flags' to value '+mu-lame'
+Setting entry with key 'num' to value '42'
+Setting entry with key 'toggle' to value '0'
+OK 'flags=+mu-lame : num=42: toggle=0'
+Setting options string 'num=42 : string=blahblah'
+Setting entry with key 'num' to value '42'
+Setting entry with key 'string' to value 'blahblah'
+OK 'num=42 : string=blahblah'
+Setting options string 'rational=0 : rational=1/2 : rational=1/-1'
+Setting entry with key 'rational' to value '0'
+Setting entry with key 'rational' to value '1/2'
+Setting entry with key 'rational' to value '1/-1'
+Value -1.000000 for parameter 'rational' out of range [0 - 10]
+Value -1.000000 for parameter 'rational' out of range [0 - 10]
+Error 'rational=0 : rational=1/2 : rational=1/-1'
+Setting options string 'rational=-1/0'
+Error 'rational=-1/0'
+Setting options string 'size=1024x768'
+Setting entry with key 'size' to value '1024x768'
+OK 'size=1024x768'
+Setting options string 'size=pal'
+Setting entry with key 'size' to value 'pal'
+OK 'size=pal'
+Setting options string 'size=bogus'
+Setting entry with key 'size' to value 'bogus'
+Unable to parse option value "bogus" as image size
+Error 'size=bogus'
+Setting options string 'pix_fmt=yuv420p'
+Setting entry with key 'pix_fmt' to value 'yuv420p'
+OK 'pix_fmt=yuv420p'
+Setting options string 'pix_fmt=2'
+Setting entry with key 'pix_fmt' to value '2'
+OK 'pix_fmt=2'
+Setting options string 'pix_fmt=bogus'
+Setting entry with key 'pix_fmt' to value 'bogus'
+Unable to parse option value "bogus" as pixel format
+Error 'pix_fmt=bogus'
+Setting options string 'sample_fmt=s16'
+Setting entry with key 'sample_fmt' to value 's16'
+OK 'sample_fmt=s16'
+Setting options string 'sample_fmt=2'
+Setting entry with key 'sample_fmt' to value '2'
+OK 'sample_fmt=2'
+Setting options string 'sample_fmt=bogus'
+Setting entry with key 'sample_fmt' to value 'bogus'
+Unable to parse option value "bogus" as sample format
+Error 'sample_fmt=bogus'
+Setting options string 'video_rate=pal'
+Setting entry with key 'video_rate' to value 'pal'
+OK 'video_rate=pal'
+Setting options string 'video_rate=25'
+Setting entry with key 'video_rate' to value '25'
+OK 'video_rate=25'
+Setting options string 'video_rate=30000/1001'
+Setting entry with key 'video_rate' to value '30000/1001'
+OK 'video_rate=30000/1001'
+Setting options string 'video_rate=30/1.001'
+Setting entry with key 'video_rate' to value '30/1.001'
+OK 'video_rate=30/1.001'
+Setting options string 'video_rate=bogus'
+Setting entry with key 'video_rate' to value 'bogus'
+Undefined constant or missing '(' in 'bogus'
+Unable to parse option value "bogus" as video rate
+Error 'video_rate=bogus'
+Setting options string 'duration=bogus'
+Setting entry with key 'duration' to value 'bogus'
+Unable to parse option value "bogus" as duration
+Error 'duration=bogus'
+Setting options string 'duration=123.45'
+Setting entry with key 'duration' to value '123.45'
+OK 'duration=123.45'
+Setting options string 'duration=1\:23\:45.67'
+Setting entry with key 'duration' to value '1:23:45.67'
+OK 'duration=1\:23\:45.67'
+Setting options string 'color=blue'
+Setting entry with key 'color' to value 'blue'
+OK 'color=blue'
+Setting options string 'color=0x223300'
+Setting entry with key 'color' to value '0x223300'
+OK 'color=0x223300'
+Setting options string 'color=0x42FF07AA'
+Setting entry with key 'color' to value '0x42FF07AA'
+OK 'color=0x42FF07AA'
+Setting options string 'cl=stereo+downmix'
+Setting entry with key 'cl' to value 'stereo+downmix'
+OK 'cl=stereo+downmix'
+Setting options string 'cl=foo'
+Setting entry with key 'cl' to value 'foo'
+Unable to parse option value "foo" as channel layout
+Error 'cl=foo'
+Setting options string 'bin=boguss'
+Setting entry with key 'bin' to value 'boguss'
+Error 'bin=boguss'
+Setting options string 'bin=111'
+Setting entry with key 'bin' to value '111'
+Error 'bin=111'
+Setting options string 'bin=ffff'
+Setting entry with key 'bin' to value 'ffff'
+OK 'bin=ffff'
+Setting options string 'num64=bogus'
+Setting entry with key 'num64' to value 'bogus'
+Undefined constant or missing '(' in 'bogus'
+Unable to parse option value "bogus"
+Error 'num64=bogus'
+Setting options string 'num64=44'
+Setting entry with key 'num64' to value '44'
+OK 'num64=44'
+Setting options string 'num64=44.4'
+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'
+Setting options string 'flt=bogus'
+Setting entry with key 'flt' to value 'bogus'
+Undefined constant or missing '(' in 'bogus'
+Unable to parse option value "bogus"
+Error 'flt=bogus'
+Setting options string 'flt=2'
+Setting entry with key 'flt' to value '2'
+OK 'flt=2'
+Setting options string 'flt=2.2'
+Setting entry with key 'flt' to value '2.2'
+OK 'flt=2.2'
+Setting options string 'flt=-1'
+Setting entry with key 'flt' to value '-1'
+Value -1.000000 for parameter 'flt' out of range [0 - 100]
+Error 'flt=-1'
+Setting options string 'flt=101'
+Setting entry with key 'flt' to value '101'
+Value 101.000000 for parameter 'flt' out of range [0 - 100]
+Error 'flt=101'
+Setting options string 'dbl=bogus'
+Setting entry with key 'dbl' to value 'bogus'
+Undefined constant or missing '(' in 'bogus'
+Unable to parse option value "bogus"
+Error 'dbl=bogus'
+Setting options string 'dbl=2'
+Setting entry with key 'dbl' to value '2'
+OK 'dbl=2'
+Setting options string 'dbl=2.2'
+Setting entry with key 'dbl' to value '2.2'
+OK 'dbl=2.2'
+Setting options string 'dbl=-1'
+Setting entry with key 'dbl' to value '-1'
+Value -1.000000 for parameter 'dbl' out of range [0 - 100]
+Error 'dbl=-1'
+Setting options string 'dbl=101'
+Setting entry with key 'dbl' to value '101'
+Value 101.000000 for parameter 'dbl' out of range [0 - 100]
+Error 'dbl=101'
+
+Testing av_opt_set_from_string()
+Setting options string ''
+OK ''
+Setting options string '5'
+Setting 'num' to value '5'
+OK '5'
+Setting options string '5:hello'
+Setting 'num' to value '5'
+Setting 'string' to value 'hello'
+OK '5:hello'
+Setting options string '5:hello:size=pal'
+Setting 'num' to value '5'
+Setting 'string' to value 'hello'
+Setting 'size' to value 'pal'
+OK '5:hello:size=pal'
+Setting options string '5:size=pal:hello'
+Setting 'num' to value '5'
+Setting 'size' to value 'pal'
+No option name near 'hello'
+Error '5:size=pal:hello'
+Setting options string ':'
+Setting 'num' to value ''
+Undefined constant or missing '(' in ''
+Unable to parse option value ""
+Error ':'
+Setting options string '='
+Setting '' to value ''
+Option '' not found
+Error '='
+Setting options string ' 5 : hello : size = pal '
+Setting 'num' to value '5'
+Setting 'string' to value 'hello'
+Setting 'size' to value 'pal'
+OK ' 5 : hello : size = pal '
+Setting options string 'a_very_long_option_name_that_will_need_to_be_ellipsized_around_here=42'
+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'
diff --git a/tests/ref/fate/paf-demux b/tests/ref/fate/paf-demux
new file mode 100644
index 0000000000..857fb5457a
--- /dev/null
+++ b/tests/ref/fate/paf-demux
@@ -0,0 +1,160 @@
+#tb 0: 1/10
+#tb 1: 1/22050
+0, 0, 0, 1, 262144, 0x7f9a3c6a
+1, 0, 0, 57330, 131072, 0x255a6ac2
+0, 1, 1, 1, 260600, 0x0329e6f4, F=0x0
+0, 2, 2, 1, 259724, 0x2db0ad5e, F=0x0
+0, 3, 3, 1, 258616, 0xe666009d, F=0x0
+0, 4, 4, 1, 257364, 0xba42458c, F=0x0
+0, 5, 5, 1, 255964, 0xf7e04c83, F=0x0
+0, 6, 6, 1, 254192, 0xa04b49ff, F=0x0
+0, 7, 7, 1, 252232, 0x65d4ab4c, F=0x0
+0, 8, 8, 1, 249960, 0x8f0b3854, F=0x0
+0, 9, 9, 1, 247396, 0x16d70776, F=0x0
+0, 10, 10, 1, 244452, 0x8b0648f3, F=0x0
+0, 11, 11, 1, 240972, 0x07e3ef41, F=0x0
+0, 12, 12, 1, 237288, 0x197a1964, F=0x0
+0, 13, 13, 1, 233344, 0xd6c51f01, F=0x0
+0, 14, 14, 1, 229196, 0x48581a65, F=0x0
+0, 15, 15, 1, 224688, 0x710e1fdb, F=0x0
+0, 16, 16, 1, 219248, 0xcd96719d, F=0x0
+0, 17, 17, 1, 212712, 0x4de31fd8, F=0x0
+0, 18, 18, 1, 205864, 0x21a0a106, F=0x0
+0, 19, 19, 1, 199148, 0xd1d77c92, F=0x0
+0, 20, 20, 1, 192072, 0x620627a6, F=0x0
+0, 21, 21, 1, 184928, 0x81548454, F=0x0
+0, 22, 22, 1, 178296, 0x7bb40918, F=0x0
+0, 23, 23, 1, 171944, 0xa7b714bb, F=0x0
+0, 24, 24, 1, 165584, 0xa6246dba, F=0x0
+0, 25, 25, 1, 159468, 0x7bc54abb, F=0x0
+0, 26, 26, 1, 153524, 0xd2774028, F=0x0
+1, 57330, 57330, 57330, 131072, 0xcc38a5e5
+0, 27, 27, 1, 147568, 0xd94b2368, F=0x0
+0, 28, 28, 1, 141536, 0xb512eae6, F=0x0
+0, 29, 29, 1, 135368, 0x9b6ea2b3, F=0x0
+0, 30, 30, 1, 128296, 0x7c26d136, F=0x0
+0, 31, 31, 1, 120932, 0xccb8b273, F=0x0
+0, 32, 32, 1, 113432, 0x9f2bb997, F=0x0
+0, 33, 33, 1, 105724, 0x735519f6, F=0x0
+0, 34, 34, 1, 98428, 0xa2933dbb, F=0x0
+0, 35, 35, 1, 91136, 0xbe852457, F=0x0
+0, 36, 36, 1, 83844, 0xc471106a, F=0x0
+0, 37, 37, 1, 76648, 0x3f6e1c92, F=0x0
+0, 38, 38, 1, 69624, 0x00f86b27, F=0x0
+0, 39, 39, 1, 62436, 0xf360ccf0, F=0x0
+0, 40, 40, 1, 55268, 0x0373c2a3, F=0x0
+0, 41, 41, 1, 48220, 0xd5a5e0c1, F=0x0
+0, 42, 42, 1, 48216, 0x1da7e0ad, F=0x0
+0, 43, 43, 1, 48212, 0xa984e098, F=0x0
+0, 44, 44, 1, 48208, 0x7962e082, F=0x0
+0, 45, 45, 1, 48204, 0xc245e06e, F=0x0
+0, 46, 46, 1, 48200, 0x4f2de059, F=0x0
+0, 47, 47, 1, 48196, 0x2013e043, F=0x0
+0, 48, 48, 1, 48192, 0x34ffe02c, F=0x0
+0, 49, 49, 1, 48188, 0x7f22e018, F=0x0
+0, 50, 50, 1, 48184, 0x0d5ae003, F=0x0
+0, 51, 51, 1, 48180, 0xdf91dfed, F=0x0
+0, 52, 52, 1, 48176, 0xf5eddfd6, F=0x0
+1, 114660, 114660, 57330, 131072, 0x4d9c2c7e
+0, 53, 53, 1, 48172, 0x415fdfc2, F=0x0
+0, 54, 54, 1, 48168, 0xd0d8dfad, F=0x0
+0, 55, 55, 1, 48164, 0xa47edf97, F=0x0
+0, 56, 56, 1, 48160, 0xbc4adf80, F=0x0
+0, 57, 57, 1, 48156, 0x08fcdf6c, F=0x0
+0, 58, 58, 1, 48152, 0x99c5df57, F=0x0
+0, 59, 59, 1, 41116, 0x8c22a4c1, F=0x0
+0, 60, 60, 1, 34124, 0x33c9e476, F=0x0
+0, 61, 61, 1, 27272, 0x8069fb08, F=0x0
+0, 62, 62, 1, 20636, 0xa413e37e, F=0x0
+0, 63, 63, 1, 14072, 0x428a2075, F=0x0
+0, 64, 64, 1, 7712, 0x7c6b914f, F=0x0
+0, 65, 65, 1, 262144, 0x687484cb, F=0x0
+0, 66, 66, 1, 256292, 0x0dec8b5a, F=0x0
+0, 67, 67, 1, 250612, 0xd127f411, F=0x0
+0, 68, 68, 1, 245404, 0x4e760ddf, F=0x0
+0, 69, 69, 1, 241956, 0x0412f83d, F=0x0
+0, 70, 70, 1, 241184, 0x0de227e2, F=0x0
+0, 71, 71, 1, 241180, 0xebe9eafb, F=0x0
+0, 72, 72, 1, 241176, 0xf0c8eae5, F=0x0
+0, 73, 73, 1, 241172, 0x47bbeace, F=0x0
+0, 74, 74, 1, 241168, 0xfb8aeab9, F=0x0
+0, 75, 75, 1, 241164, 0x0180eaa3, F=0x0
+0, 76, 76, 1, 241160, 0x5978ea8c, F=0x0
+0, 77, 77, 1, 241156, 0xbc86ea78, F=0x0
+0, 78, 78, 1, 241152, 0x71b4ea63, F=0x0
+1, 171990, 171990, 57330, 131072, 0x1b512fb8
+0, 79, 79, 1, 241148, 0x78fbea4d, F=0x0
+0, 80, 80, 1, 241144, 0xd263ea36
+0, 81, 81, 1, 237912, 0xcb5839a6, F=0x0
+0, 82, 82, 1, 229296, 0x350f07b6, F=0x0
+0, 83, 83, 1, 214256, 0x3c954096, F=0x0
+0, 84, 84, 1, 198068, 0x1470ae1f, F=0x0
+0, 85, 85, 1, 180664, 0xa80de8b6, F=0x0
+0, 86, 86, 1, 164672, 0x11ecf816, F=0x0
+0, 87, 87, 1, 148996, 0x6346aa49, F=0x0
+0, 88, 88, 1, 134804, 0x8fe4699a, F=0x0
+0, 89, 89, 1, 124488, 0x63b82fa0, F=0x0
+0, 90, 90, 1, 116892, 0xac785c29, F=0x0
+0, 91, 91, 1, 109528, 0xc24da959, F=0x0
+0, 92, 92, 1, 102688, 0xba25eb56, F=0x0
+0, 93, 93, 1, 95192, 0x999820b3, F=0x0
+0, 94, 94, 1, 89980, 0xa81aee1a, F=0x0
+0, 95, 95, 1, 84696, 0xb274dad5, F=0x0
+0, 96, 96, 1, 79152, 0xd7936f6e, F=0x0
+0, 97, 97, 1, 74232, 0x1abdf78a, F=0x0
+0, 98, 98, 1, 69112, 0x212918e8, F=0x0
+0, 99, 99, 1, 63484, 0x45e36b2f, F=0x0
+0, 100, 100, 1, 58616, 0xef171a5a, F=0x0
+0, 101, 101, 1, 53396, 0xd16be9a0, F=0x0
+0, 102, 102, 1, 47388, 0xc602914b, F=0x0
+0, 103, 103, 1, 42276, 0x6b86b9dd, F=0x0
+0, 104, 104, 1, 36932, 0xea0d85cb, F=0x0
+1, 229320, 229320, 57330, 131072, 0x4e478505
+0, 105, 105, 1, 30408, 0xc7df6cba, F=0x0
+0, 106, 106, 1, 24468, 0x80007205, F=0x0
+0, 107, 107, 1, 18572, 0xb4aa84d2, F=0x0
+0, 108, 108, 1, 12632, 0x12c2efb8, F=0x0
+0, 109, 109, 1, 6604, 0x75002817, F=0x0
+0, 110, 110, 1, 262144, 0xf9544f5b, F=0x0
+0, 111, 111, 1, 255448, 0x9242877e, F=0x0
+0, 112, 112, 1, 248532, 0xef495999, F=0x0
+0, 113, 113, 1, 238032, 0xac29500b, F=0x0
+0, 114, 114, 1, 225424, 0x73035f24, F=0x0
+0, 115, 115, 1, 215860, 0xed94de14, F=0x0
+0, 116, 116, 1, 205996, 0x4d417b16, F=0x0
+0, 117, 117, 1, 191904, 0xc195d49f, F=0x0
+0, 118, 118, 1, 182596, 0x32a14954, F=0x0
+0, 119, 119, 1, 174988, 0xdc83fa02, F=0x0
+0, 120, 120, 1, 168008, 0x5e1d7302, F=0x0
+0, 121, 121, 1, 161032, 0xf503efb4, F=0x0
+0, 122, 122, 1, 154044, 0x1df06a7c, F=0x0
+0, 123, 123, 1, 147056, 0x4c22ec13, F=0x0
+0, 124, 124, 1, 140060, 0xede97385, F=0x0
+0, 125, 125, 1, 133064, 0x50eefee6, F=0x0
+0, 126, 126, 1, 126060, 0xc6478fb8, F=0x0
+0, 127, 127, 1, 119056, 0xf45a2080, F=0x0
+0, 128, 128, 1, 112044, 0x1d49b4ae, F=0x0
+0, 129, 129, 1, 105028, 0xd35649dd, F=0x0
+0, 130, 130, 1, 98012, 0x03ede949, F=0x0
+1, 286650, 286650, 57330, 131072, 0xb29e283e
+0, 131, 131, 1, 91000, 0x57128fb0, F=0x0
+0, 132, 132, 1, 84000, 0xf7ff39c0, F=0x0
+0, 133, 133, 1, 77004, 0xda18e580, F=0x0
+0, 134, 134, 1, 70004, 0x8eff8af4, F=0x0
+0, 135, 135, 1, 62992, 0x665831fd, F=0x0
+0, 136, 136, 1, 55976, 0x130ada75, F=0x0
+0, 137, 137, 1, 48956, 0x4cf47b2f, F=0x0
+0, 138, 138, 1, 41936, 0x7a8e2006, F=0x0
+0, 139, 139, 1, 34920, 0x9527ca2b, F=0x0
+0, 140, 140, 1, 27912, 0x4c8078df, F=0x0
+0, 141, 141, 1, 20884, 0x1e152e1f, F=0x0
+0, 142, 142, 1, 13848, 0xd358d51b, F=0x0
+0, 143, 143, 1, 262144, 0x38f14810, F=0x0
+0, 144, 144, 1, 255104, 0x579bf26b, F=0x0
+0, 145, 145, 1, 255100, 0x6488a2d4, F=0x0
+0, 146, 146, 1, 248096, 0xbe966730, F=0x0
+0, 147, 147, 1, 241144, 0xd8e3abf6, F=0x0
+0, 148, 148, 1, 234268, 0xde2bb38e, F=0x0
+0, 149, 149, 1, 227440, 0xb78f1aed, F=0x0
+0, 150, 150, 1, 220692, 0x86026588, F=0x0
+0, 151, 151, 1, 214000, 0x0fdbc796, F=0x0
diff --git a/tests/ref/fate/parseutils b/tests/ref/fate/parseutils
index 01f6e08034..1482452857 100644
--- a/tests/ref/fate/parseutils
+++ b/tests/ref/fate/parseutils
@@ -9,10 +9,10 @@ Testing av_parse_video_rate()
' 123 / 321' -> 41/107 OK
'foo/foo' -> 0/0 ERROR
'foo/1' -> 0/0 ERROR
-'1/foo' -> 0/0 ERROR
+'1/foo' -> 1/0 ERROR
'0/0' -> 0/0 ERROR
'/0' -> 0/0 ERROR
-'1/' -> 0/0 ERROR
+'1/' -> 1/0 ERROR
'1' -> 1/1 OK
'0' -> 0/1 ERROR
'-123/123' -> -1/1 ERROR
@@ -21,25 +21,62 @@ Testing av_parse_video_rate()
'.23' -> 23/100 OK
'-.23' -> -23/100 ERROR
'-0.234' -> -117/500 ERROR
-'-0.0000001' -> 0/1 ERROR
+'-0.0000001' -> -1/10000000 ERROR
' 21332.2324 ' -> 917286/43 OK
' -21332.2324 ' -> -917286/43 ERROR
Testing av_parse_color()
+bikeshed -> R(80) G(64) B(140) A(59)
+RaNdOm -> R(185) G(88) B(148) A(94)
+foo -> error
red -> R(255) G(0) B(0) A(255)
+Red -> error
RED -> R(255) G(0) B(0) A(255)
Violet -> R(238) G(130) B(238) A(255)
Yellow -> R(255) G(255) B(0) A(255)
Red -> R(255) G(0) B(0) A(255)
0x000000 -> R(0) G(0) B(0) A(255)
+0x0000000 -> error
0xff000000 -> R(255) G(0) B(0) A(0)
0x3e34ff -> R(62) G(52) B(255) A(255)
0x3e34ffaa -> R(62) G(52) B(255) A(170)
+0xffXXee -> error
+0xfoobar -> error
+0xffffeeeeeeee -> error
#ff0000 -> R(255) G(0) B(0) A(255)
+#ffXX00 -> error
ff0000 -> R(255) G(0) B(0) A(255)
+ffXX00 -> error
+red@foo -> error
+random@10 -> error
0xff0000@1.0 -> R(255) G(0) B(0) A(255)
+red@ -> error
+red@0xfff -> error
red@0xf -> R(255) G(0) B(0) A(15)
+red@2 -> error
red@0.1 -> R(255) G(0) B(0) A(25)
+red@-1 -> error
red@0.5 -> R(255) G(0) B(0) A(127)
red@1.0 -> R(255) G(0) B(0) A(255)
+red@256 -> error
+red@10foo -> error
+red@-1.0 -> error
red@-0.0 -> R(255) G(0) B(0) A(0)
+
+Testing av_small_strptime()
+fmt:'%Y-%m-%d' spec:'2012-12-21' -> 2012-12-21 00:00:00
+fmt:'%Y - %m - %d' spec:'2012-12-21' -> 2012-12-21 00:00:00
+fmt:'%Y-%m-%d %H:%M:%S' spec:'2012-12-21 20:12:21' -> 2012-12-21 20:12:21
+fmt:' %Y - %m - %d %H : %M : %S' spec:' 2012 - 12 - 21 20 : 12 : 21' -> 2012-12-21 20:12:21
+
+Testing av_parse_time()
+(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)
+now -> 1331972053.000000 = 2012-03-17T08:14:13Z
+12:35:46 -> 1331984146.000000 = 2012-03-17T11:35:46Z
+2000-12-20 0:02:47.5z -> 977270567.500000 = 2000-12-20T00:02:47Z
+2000-12-20T010247.6 -> 977270567.600000 = 2000-12-20T00:02:47Z
+2:34:56.79 -> +9296790000
+-1:23:45.67 -> -5025670000
+42.1729 -> +42172900
+-1729.42 -> -1729420000
+12:34 -> +754000000
diff --git a/tests/ref/fate/pictor b/tests/ref/fate/pictor
index 3dc4344758..c89b6087bb 100644
--- a/tests/ref/fate/pictor
+++ b/tests/ref/fate/pictor
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 192816, 0xf97e2ba1
+0, 0, 0, 1, 192816, 0x29b9c158
diff --git a/tests/ref/fate/pixelutils b/tests/ref/fate/pixelutils
new file mode 100644
index 0000000000..493497fb88
--- /dev/null
+++ b/tests/ref/fate/pixelutils
@@ -0,0 +1,48 @@
+[OK] [UU] SAD [random] 2x2=409 ref=409
+[OK] [UU] SAD [random] 4x4=1370 ref=1370
+[OK] [UU] SAD [random] 8x8=5178 ref=5178
+[OK] [UU] SAD [random] 16x16=20946 ref=20946
+[OK] [AU] SAD [random] 2x2=320 ref=320
+[OK] [AU] SAD [random] 4x4=1522 ref=1522
+[OK] [AU] SAD [random] 8x8=5821 ref=5821
+[OK] [AU] SAD [random] 16x16=21951 ref=21951
+[OK] [AA] SAD [random] 2x2=276 ref=276
+[OK] [AA] SAD [random] 4x4=1521 ref=1521
+[OK] [AA] SAD [random] 8x8=5130 ref=5130
+[OK] [AA] SAD [random] 16x16=20775 ref=20775
+[OK] [UU] SAD [max] 2x2=1020 ref=1020
+[OK] [UU] SAD [max] 4x4=4080 ref=4080
+[OK] [UU] SAD [max] 8x8=16320 ref=16320
+[OK] [UU] SAD [max] 16x16=65280 ref=65280
+[OK] [AU] SAD [max] 2x2=1020 ref=1020
+[OK] [AU] SAD [max] 4x4=4080 ref=4080
+[OK] [AU] SAD [max] 8x8=16320 ref=16320
+[OK] [AU] SAD [max] 16x16=65280 ref=65280
+[OK] [AA] SAD [max] 2x2=1020 ref=1020
+[OK] [AA] SAD [max] 4x4=4080 ref=4080
+[OK] [AA] SAD [max] 8x8=16320 ref=16320
+[OK] [AA] SAD [max] 16x16=65280 ref=65280
+[OK] [UU] SAD [min] 2x2=0 ref=0
+[OK] [UU] SAD [min] 4x4=0 ref=0
+[OK] [UU] SAD [min] 8x8=0 ref=0
+[OK] [UU] SAD [min] 16x16=0 ref=0
+[OK] [AU] SAD [min] 2x2=0 ref=0
+[OK] [AU] SAD [min] 4x4=0 ref=0
+[OK] [AU] SAD [min] 8x8=0 ref=0
+[OK] [AU] SAD [min] 16x16=0 ref=0
+[OK] [AA] SAD [min] 2x2=0 ref=0
+[OK] [AA] SAD [min] 4x4=0 ref=0
+[OK] [AA] SAD [min] 8x8=0 ref=0
+[OK] [AA] SAD [min] 16x16=0 ref=0
+[OK] [UU] SAD [small] 2x2=400 ref=400
+[OK] [AU] SAD [small] 2x2=384 ref=384
+[OK] [AA] SAD [small] 2x2=409 ref=409
+[OK] [UU] SAD [small] 4x4=1144 ref=1144
+[OK] [AU] SAD [small] 4x4=1156 ref=1156
+[OK] [AA] SAD [small] 4x4=1086 ref=1086
+[OK] [UU] SAD [small] 8x8=6510 ref=6510
+[OK] [AU] SAD [small] 8x8=5755 ref=5755
+[OK] [AA] SAD [small] 8x8=6156 ref=6156
+[OK] [UU] SAD [small] 16x16=19490 ref=19490
+[OK] [AU] SAD [small] 16x16=21037 ref=21037
+[OK] [AA] SAD [small] 16x16=22986 ref=22986
diff --git a/tests/ref/fate/pmp-demux b/tests/ref/fate/pmp-demux
new file mode 100644
index 0000000000..b481db7354
--- /dev/null
+++ b/tests/ref/fate/pmp-demux
@@ -0,0 +1,106 @@
+#tb 0: 1/44100
+0, 0, 0, 1152, 417, 0xcb873fba
+0, 1152, 1152, 1152, 104, 0x6d521c5a
+0, 2304, 2304, 1152, 104, 0xb3af1d64
+0, 3456, 3456, 1152, 104, 0xc0f71d86
+0, 4608, 4608, 1152, 104, 0xce3f1da8
+0, 5760, 5760, 1152, 104, 0xdb871dca
+0, 6912, 6912, 1152, 104, 0xe8cf1dec
+0, 8064, 8064, 1152, 104, 0xf6171e0e
+0, 9216, 9216, 1152, 104, 0x036e1e30
+0, 10368, 10368, 1152, 104, 0x3b921ec1
+0, 11520, 11520, 1152, 104, 0x3b921ec1
+0, 12672, 12672, 1152, 104, 0x3b921ec1
+0, 13824, 13824, 1152, 104, 0x3b921ec1
+0, 14976, 14976, 1152, 104, 0x3b921ec1
+0, 16128, 16128, 1152, 104, 0x3b921ec1
+0, 17280, 17280, 1152, 104, 0x3b921ec1
+0, 18432, 18432, 1152, 104, 0x3b921ec1
+0, 19584, 19584, 1152, 104, 0x3b921ec1
+0, 20736, 20736, 1152, 104, 0x3b921ec1
+0, 21888, 21888, 1152, 104, 0x3b921ec1
+0, 23040, 23040, 1152, 104, 0x3b921ec1
+0, 24192, 24192, 1152, 104, 0x3b921ec1
+0, 25344, 25344, 1152, 104, 0x3b921ec1
+0, 26496, 26496, 1152, 104, 0x3b921ec1
+0, 27648, 27648, 1152, 104, 0x3b921ec1
+0, 28800, 28800, 1152, 104, 0x3b921ec1
+0, 29952, 29952, 1152, 104, 0x3b921ec1
+0, 31104, 31104, 1152, 104, 0x3b921ec1
+0, 32256, 32256, 1152, 104, 0x3b921ec1
+0, 33408, 33408, 1152, 104, 0x3b921ec1
+0, 34560, 34560, 1152, 104, 0x3b921ec1
+0, 35712, 35712, 1152, 104, 0x3b921ec1
+0, 36864, 36864, 1152, 104, 0x3b921ec1
+0, 38016, 38016, 1152, 104, 0x3b921ec1
+0, 39168, 39168, 1152, 104, 0x3b921ec1
+0, 40320, 40320, 1152, 104, 0x3b921ec1
+0, 41472, 41472, 1152, 104, 0x3b921ec1
+0, 42624, 42624, 1152, 104, 0x3b921ec1
+0, 43776, 43776, 1152, 104, 0x3b921ec1
+0, 44928, 44928, 1152, 104, 0x3b921ec1
+0, 46080, 46080, 1152, 104, 0x3b921ec1
+0, 47232, 47232, 1152, 104, 0x3b921ec1
+0, 48384, 48384, 1152, 104, 0x3b921ec1
+0, 49536, 49536, 1152, 104, 0x3b921ec1
+0, 50688, 50688, 1152, 104, 0x3b921ec1
+0, 51840, 51840, 1152, 104, 0x3b921ec1
+0, 52992, 52992, 1152, 104, 0x3b921ec1
+0, 54144, 54144, 1152, 104, 0x3b921ec1
+0, 55296, 55296, 1152, 104, 0x3b921ec1
+0, 56448, 56448, 1152, 104, 0x3b921ec1
+0, 57600, 57600, 1152, 104, 0x3b921ec1
+0, 58752, 58752, 1152, 104, 0x3b921ec1
+0, 59904, 59904, 1152, 104, 0x3b921ec1
+0, 61056, 61056, 1152, 104, 0x3b921ec1
+0, 62208, 62208, 1152, 104, 0x3b921ec1
+0, 63360, 63360, 1152, 104, 0x3b921ec1
+0, 64512, 64512, 1152, 104, 0x3b921ec1
+0, 65664, 65664, 1152, 104, 0x3b921ec1
+0, 66816, 66816, 1152, 104, 0x3b921ec1
+0, 67968, 67968, 1152, 104, 0x3b921ec1
+0, 69120, 69120, 1152, 104, 0x3b921ec1
+0, 70272, 70272, 1152, 104, 0x3b921ec1
+0, 71424, 71424, 1152, 104, 0x3b921ec1
+0, 72576, 72576, 1152, 104, 0x3b921ec1
+0, 73728, 73728, 1152, 104, 0x3b921ec1
+0, 74880, 74880, 1152, 104, 0x3b921ec1
+0, 76032, 76032, 1152, 104, 0x3b921ec1
+0, 77184, 77184, 1152, 104, 0x3b921ec1
+0, 78336, 78336, 1152, 104, 0x3b921ec1
+0, 79488, 79488, 1152, 104, 0x3b921ec1
+0, 80640, 80640, 1152, 104, 0x3b921ec1
+0, 81792, 81792, 1152, 104, 0x3b921ec1
+0, 82944, 82944, 1152, 104, 0x3b921ec1
+0, 84096, 84096, 1152, 104, 0x3b921ec1
+0, 85248, 85248, 1152, 104, 0x3b921ec1
+0, 86400, 86400, 1152, 104, 0x3b921ec1
+0, 87552, 87552, 1152, 104, 0xf0211aa6
+0, 88704, 88704, 1152, 104, 0xd34224a5
+0, 89856, 89856, 1152, 104, 0x7b78282c
+0, 91008, 91008, 1152, 104, 0x06e32789
+0, 92160, 92160, 1152, 104, 0x1c502696
+0, 93312, 93312, 1152, 104, 0xd7392a5e
+0, 94464, 94464, 1152, 104, 0xbc1b288e
+0, 95616, 95616, 1152, 104, 0xbbd8261f
+0, 96768, 96768, 1152, 104, 0xebbb2f1c
+0, 97920, 97920, 1152, 104, 0xf55b31cc
+0, 99072, 99072, 1152, 104, 0xbdb930e0
+0, 100224, 100224, 1152, 104, 0x36b72db9
+0, 101376, 101376, 1152, 156, 0xbef24bc7
+0, 102528, 102528, 1152, 261, 0xefec7b06
+0, 103680, 103680, 1152, 208, 0xadcd5f92
+0, 104832, 104832, 1152, 261, 0x7ea9792e
+0, 105984, 105984, 1152, 182, 0xf7ad5524
+0, 107136, 107136, 1152, 208, 0x8f325a0c
+0, 108288, 108288, 1152, 208, 0xe6795cde
+0, 109440, 109440, 1152, 208, 0xd4bc5e11
+0, 110592, 110592, 1152, 208, 0x6762553b
+0, 111744, 111744, 1152, 156, 0x47cc39cc
+0, 112896, 112896, 1152, 130, 0xcdcd2e7b
+0, 114048, 114048, 1152, 261, 0x3864753a
+0, 115200, 115200, 1152, 156, 0xc5d24270
+0, 116352, 116352, 1152, 156, 0x3b664195
+0, 117504, 117504, 1152, 130, 0xa928320e
+0, 118656, 118656, 1152, 156, 0x58e03f10
+0, 119808, 119808, 1152, 261, 0xf0707a4c
diff --git a/tests/ref/fate/png-gray16 b/tests/ref/fate/png-gray16
index 7bd73d84d0..66fc601850 100644
--- a/tests/ref/fate/png-gray16
+++ b/tests/ref/fate/png-gray16
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0x56c92114
+0, 0, 0, 1, 49152, 0xc71b77cd
diff --git a/tests/ref/fate/png-gray8 b/tests/ref/fate/png-gray8
index 5b3096826b..9d30db6516 100644
--- a/tests/ref/fate/png-gray8
+++ b/tests/ref/fate/png-gray8
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0xe5df9033
+0, 0, 0, 1, 49152, 0x55121b03
diff --git a/tests/ref/fate/png-rgb24 b/tests/ref/fate/png-rgb24
index ed819cef61..c383836853 100644
--- a/tests/ref/fate/png-rgb24
+++ b/tests/ref/fate/png-rgb24
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0x57fff840
+0, 0, 0, 1, 49152, 0xe0013dee
diff --git a/tests/ref/fate/png-rgb48 b/tests/ref/fate/png-rgb48
index 8bd0445663..b1159f1867 100644
--- a/tests/ref/fate/png-rgb48
+++ b/tests/ref/fate/png-rgb48
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0x764801bb
+0, 0, 0, 1, 49152, 0xcf0e902a
diff --git a/tests/ref/fate/png-rgba b/tests/ref/fate/png-rgba
index eb473ced21..f20fe0c693 100644
--- a/tests/ref/fate/png-rgba
+++ b/tests/ref/fate/png-rgba
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0xb30c9da7
+0, 0, 0, 1, 49152, 0x5017bc21
diff --git a/tests/ref/fate/png-ya16 b/tests/ref/fate/png-ya16
index b932700295..dffdaf7038 100644
--- a/tests/ref/fate/png-ya16
+++ b/tests/ref/fate/png-ya16
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0xf1b83aeb
+0, 0, 0, 1, 49152, 0x0801ce78
diff --git a/tests/ref/fate/png-ya8 b/tests/ref/fate/png-ya8
index 9ce98f698d..1318af80c6 100644
--- a/tests/ref/fate/png-ya8
+++ b/tests/ref/fate/png-ya8
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 203280, 0xe77c008e
+0, 0, 0, 1, 49152, 0x5a1481f8
diff --git a/tests/ref/fate/pngparser b/tests/ref/fate/pngparser
index b481dcd392..93005cff83 100644
--- a/tests/ref/fate/pngparser
+++ b/tests/ref/fate/pngparser
@@ -1,5 +1,5 @@
#tb 0: 1/25
-0, 0, 0, 1, 271040, 0xffe62f5f
-0, 1, 1, 1, 271040, 0xcf502f5f
-0, 2, 2, 1, 271040, 0x72612f5f
-0, 3, 3, 1, 271040, 0x41cb2f5f
+0, 0, 0, 1, 1600, 0x01a481a9
+0, 1, 1, 1, 1600, 0x01a481a9
+0, 2, 2, 1, 1600, 0x01a481a9
+0, 3, 3, 1, 1600, 0x01a481a9
diff --git a/tests/ref/fate/prores-422 b/tests/ref/fate/prores-422
index 379739fa08..f4025112b0 100644
--- a/tests/ref/fate/prores-422
+++ b/tests/ref/fate/prores-422
@@ -1,3 +1,3 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 8294400, 0xe8e9d448
-0, 100, 100, 0, 8294400, 0xe8e9d448
+#tb 0: 100/2997
+0, 0, 0, 1, 8294400, 0x57127dd9
+0, 1, 1, 1, 8294400, 0x57127dd9
diff --git a/tests/ref/fate/prores-422_hq b/tests/ref/fate/prores-422_hq
index dc93c33122..61a5014a2d 100644
--- a/tests/ref/fate/prores-422_hq
+++ b/tests/ref/fate/prores-422_hq
@@ -1,3 +1,3 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 8294400, 0x817063b0
-0, 100, 100, 0, 8294400, 0x817063b0
+#tb 0: 100/2997
+0, 0, 0, 1, 8294400, 0x978851f4
+0, 1, 1, 1, 8294400, 0x978851f4
diff --git a/tests/ref/fate/prores-422_lt b/tests/ref/fate/prores-422_lt
index 1c508409d3..3113c8a522 100644
--- a/tests/ref/fate/prores-422_lt
+++ b/tests/ref/fate/prores-422_lt
@@ -1,3 +1,3 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 8294400, 0xcd4ccde1
-0, 100, 100, 0, 8294400, 0xcd4ccde1
+#tb 0: 100/2997
+0, 0, 0, 1, 8294400, 0x4ca110c7
+0, 1, 1, 1, 8294400, 0x4ca110c7
diff --git a/tests/ref/fate/prores-422_proxy b/tests/ref/fate/prores-422_proxy
index 3763b001fa..5562dce7c6 100644
--- a/tests/ref/fate/prores-422_proxy
+++ b/tests/ref/fate/prores-422_proxy
@@ -1,3 +1,3 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 8294400, 0x51d29320
-0, 100, 100, 0, 8294400, 0x51d29320
+#tb 0: 100/2997
+0, 0, 0, 1, 8294400, 0x007ba770
+0, 1, 1, 1, 8294400, 0x007ba770
diff --git a/tests/ref/fate/prores-alpha b/tests/ref/fate/prores-alpha
index 97be6cf236..d64cfd55a6 100644
--- a/tests/ref/fate/prores-alpha
+++ b/tests/ref/fate/prores-alpha
@@ -1,3 +1,3 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 16588800, 0x8dcdb600
-0, 100, 100, 0, 16588800, 0x8dcdb600
+#tb 0: 100/2997
+0, 0, 0, 1, 16588800, 0x8e4dac48
+0, 1, 1, 1, 16588800, 0x8e4dac48
diff --git a/tests/ref/fate/prores-alpha_skip b/tests/ref/fate/prores-alpha_skip
new file mode 100644
index 0000000000..559ec2be17
--- /dev/null
+++ b/tests/ref/fate/prores-alpha_skip
@@ -0,0 +1,3 @@
+#tb 0: 100/2997
+0, 0, 0, 1, 12441600, 0xf11685dd
+0, 1, 1, 1, 12441600, 0xf11685dd
diff --git a/tests/ref/fate/prores-transparency b/tests/ref/fate/prores-transparency
new file mode 100644
index 0000000000..745e966e58
--- /dev/null
+++ b/tests/ref/fate/prores-transparency
@@ -0,0 +1,5 @@
+#tb 0: 1/25
+#tb 1: 1/48000
+0, 0, 0, 1, 16588800, 0x7163b01a
+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
new file mode 100644
index 0000000000..5fd8d0b25a
--- /dev/null
+++ b/tests/ref/fate/prores-transparency_skip
@@ -0,0 +1,5 @@
+#tb 0: 1/25
+#tb 1: 1/48000
+0, 0, 0, 1, 12441600, 0x627d1548
+1, 0, 0, 1024, 4096, 0x00000000
+1, 1024, 1024, 896, 3584, 0x00000000
diff --git a/tests/ref/fate/ptx b/tests/ref/fate/ptx
index fad2a500fe..7edbbddc4c 100644
--- a/tests/ref/fate/ptx
+++ b/tests/ref/fate/ptx
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 393216, 0xda280efc
+0, 0, 0, 1, 393216, 0x30479950
diff --git a/tests/ref/fate/pva-demux b/tests/ref/fate/pva-demux
index 69b1d4015f..67d4844e13 100644
--- a/tests/ref/fate/pva-demux
+++ b/tests/ref/fate/pva-demux
@@ -1,26 +1,27 @@
-#tb 0: 1/90000
-0, 0, 0, 2160, 384, 0x071abcc8
-0, 2160, 2160, 2160, 384, 0x31c9aee0
-0, 4320, 4320, 2160, 384, 0xa50eaa94
-0, 6480, 6480, 2160, 384, 0x9e86ba0e
-0, 8640, 8640, 2160, 384, 0x2321b800
-0, 10800, 10800, 2160, 384, 0x2347afa8
-0, 12960, 12960, 2160, 384, 0x0831b8d3
-0, 15120, 15120, 2160, 384, 0xd5acafa1
-0, 17280, 17280, 2160, 384, 0xc975b9d2
-0, 19440, 19440, 2160, 384, 0x2e10b02a
-0, 21600, 21600, 2160, 384, 0x501eadd0
-0, 23760, 23760, 2160, 384, 0x153fc171
-0, 25920, 25920, 2160, 384, 0xc5f0b3c2
-0, 28080, 28080, 2160, 384, 0xf731b200
-0, 30240, 30240, 2160, 384, 0x2e16b713
-0, 32400, 32400, 2160, 384, 0x61f6bba9
-0, 34560, 34560, 2160, 384, 0x1b9eb0ff
-0, 36720, 36720, 2160, 384, 0x2ab4b7bd
-0, 38880, 38880, 2160, 384, 0xd66eb45c
-0, 41040, 41040, 2160, 384, 0x145ab426
-0, 43200, 43200, 2160, 384, 0x297cb370
-0, 45360, 45360, 2160, 384, 0x287bb6b7
-0, 47520, 47520, 2160, 384, 0xfddbb7df
-0, 49680, 49680, 2160, 384, 0xbbb2af0c
-0, 51840, 51840, 2160, 384, 0x8f03b5fc
+#tb 0: 1/25
+#tb 1: 1/90000
+1, 0, 0, 2160, 384, 0x071abcc8
+1, 2160, 2160, 2160, 384, 0x31c9aee0
+1, 4320, 4320, 2160, 384, 0xa50eaa94
+1, 6480, 6480, 2160, 384, 0x9e86ba0e
+1, 8640, 8640, 2160, 384, 0x2321b800
+1, 10800, 10800, 2160, 384, 0x2347afa8
+1, 12960, 12960, 2160, 384, 0x0831b8d3
+1, 15120, 15120, 2160, 384, 0xd5acafa1
+1, 17280, 17280, 2160, 384, 0xc975b9d2
+1, 19440, 19440, 2160, 384, 0x2e10b02a
+1, 21600, 21600, 2160, 384, 0x501eadd0
+1, 23760, 23760, 2160, 384, 0x153fc171
+1, 25920, 25920, 2160, 384, 0xc5f0b3c2
+1, 28080, 28080, 2160, 384, 0xf731b200
+1, 30240, 30240, 2160, 384, 0x2e16b713
+1, 32400, 32400, 2160, 384, 0x61f6bba9
+1, 34560, 34560, 2160, 384, 0x1b9eb0ff
+1, 36720, 36720, 2160, 384, 0x2ab4b7bd
+1, 38880, 38880, 2160, 384, 0xd66eb45c
+1, 41040, 41040, 2160, 384, 0x145ab426
+1, 43200, 43200, 2160, 384, 0x297cb370
+1, 45360, 45360, 2160, 384, 0x287bb6b7
+1, 47520, 47520, 2160, 384, 0xfddbb7df
+1, 49680, 49680, 2160, 384, 0xbbb2af0c
+1, 51840, 51840, 2160, 384, 0x8f03b5fc
diff --git a/tests/ref/fate/qtrle-16bit b/tests/ref/fate/qtrle-16bit
index d0d71b57c2..2021f2a6e8 100644
--- a/tests/ref/fate/qtrle-16bit
+++ b/tests/ref/fate/qtrle-16bit
@@ -1,84 +1,84 @@
-#tb 0: 1/600
-0, 0, 0, 1, 57600, 0xe6b0a48c
-0, 40, 40, 1, 57600, 0xe064d51c
-0, 80, 80, 1, 57600, 0xbfce6b33
-0, 120, 120, 1, 57600, 0x371bab02
-0, 160, 160, 1, 57600, 0x0d2d7456
-0, 200, 200, 1, 57600, 0x9184eecb
-0, 240, 240, 1, 57600, 0xb482e8db
-0, 280, 280, 1, 57600, 0x0f4cd4be
-0, 320, 320, 1, 57600, 0xe276cccb
-0, 360, 360, 1, 57600, 0x04c21c62
-0, 400, 400, 1, 57600, 0x848960a2
-0, 440, 440, 1, 57600, 0xc4c8cf03
-0, 480, 480, 1, 57600, 0xb4094866
-0, 520, 520, 1, 57600, 0xf22da043
-0, 560, 560, 1, 57600, 0x6517b67b
-0, 600, 600, 1, 57600, 0x23e39ccb
-0, 640, 640, 1, 57600, 0x41525ca3
-0, 680, 680, 1, 57600, 0xc3edc5f3
-0, 720, 720, 1, 57600, 0x8ce81c7e
-0, 760, 760, 1, 57600, 0x56829443
-0, 800, 800, 1, 57600, 0x511ce287
-0, 840, 840, 1, 57600, 0x8f029a5b
-0, 880, 880, 1, 57600, 0x2b47cf43
-0, 920, 920, 1, 57600, 0x8e7ecf4b
-0, 960, 960, 1, 57600, 0xd620317e
-0, 1000, 1000, 1, 57600, 0x5987646e
-0, 1040, 1040, 1, 57600, 0xcfedb7df
-0, 1080, 1080, 1, 57600, 0x33746e7b
-0, 1120, 1120, 1, 57600, 0x1d318573
-0, 1160, 1160, 1, 57600, 0xc851848b
-0, 1200, 1200, 1, 57600, 0x939db1d7
-0, 1240, 1240, 1, 57600, 0x1719aed3
-0, 1280, 1280, 1, 57600, 0x1ba3e18c
-0, 1320, 1320, 1, 57600, 0x04f355fb
-0, 1360, 1360, 1, 57600, 0x6fafd5f4
-0, 1400, 1400, 1, 57600, 0x434f800b
-0, 1440, 1440, 1, 57600, 0xed42179b
-0, 1480, 1480, 1, 57600, 0x3b33118b
-0, 1520, 1520, 1, 57600, 0xf81880cb
-0, 1560, 1560, 1, 57600, 0xd2c58e1b
-0, 1600, 1600, 1, 57600, 0xd96f50eb
-0, 1640, 1640, 1, 57600, 0x64ef63fb
-0, 1680, 1680, 1, 57600, 0x7b14b6fc
-0, 1720, 1720, 1, 57600, 0xeb1c9054
-0, 1760, 1760, 1, 57600, 0x3b30c97c
-0, 1800, 1800, 1, 57600, 0xc93e9484
-0, 1840, 1840, 1, 57600, 0xe012c0cc
-0, 1880, 1880, 1, 57600, 0x48e2dda4
-0, 1920, 1920, 1, 57600, 0x13eb55fb
-0, 1960, 1960, 1, 57600, 0xa5edbedc
-0, 2000, 2000, 1, 57600, 0x0123a484
-0, 2040, 2040, 1, 57600, 0xc624a7ac
-0, 2080, 2080, 1, 57600, 0xd83cf45c
-0, 2120, 2120, 1, 57600, 0x8f9bf4b4
-0, 2160, 2160, 1, 57600, 0x2d494b8c
-0, 2200, 2200, 1, 57600, 0xb246f07c
-0, 2240, 2240, 1, 57600, 0x5750e67c
-0, 2280, 2280, 1, 57600, 0x6643e9ac
-0, 2320, 2320, 1, 57600, 0x8d3b86b3
-0, 2360, 2360, 1, 57600, 0x4bb0546b
-0, 2400, 2400, 1, 57600, 0xfe439333
-0, 2440, 2440, 1, 57600, 0x0cc76233
-0, 2480, 2480, 1, 57600, 0xb6fe40ae
-0, 2520, 2520, 1, 57600, 0xf79fe0d7
-0, 2560, 2560, 1, 57600, 0xdc90dcbb
-0, 2600, 2600, 1, 57600, 0x371e7c2b
-0, 2640, 2640, 1, 57600, 0x7c4590bb
-0, 2680, 2680, 1, 57600, 0x66f5454b
-0, 2720, 2720, 1, 57600, 0x1678ae5b
-0, 2760, 2760, 1, 57600, 0x1ee8fdec
-0, 2800, 2800, 1, 57600, 0x98d2a083
-0, 2840, 2840, 1, 57600, 0x86d29e5b
-0, 2880, 2880, 1, 57600, 0x23d2bc83
-0, 2920, 2920, 1, 57600, 0x3fc729f2
-0, 2960, 2960, 1, 57600, 0x821d61da
-0, 3000, 3000, 1, 57600, 0xdd549e0e
-0, 3040, 3040, 1, 57600, 0x641234e2
-0, 3080, 3080, 1, 57600, 0x9a282112
-0, 3120, 3120, 1, 57600, 0x6587e2fb
-0, 3160, 3160, 1, 57600, 0x043d0cb2
-0, 3200, 3200, 1, 57600, 0x90328707
-0, 3240, 3240, 1, 57600, 0x5744d313
-0, 3280, 3280, 1, 57600, 0x6e1b95cb
+#tb 0: 1/15
+0, 0, 0, 1, 57600, 0xcf2d39fc
+0, 1, 1, 1, 57600, 0xfc9f6bed
+0, 2, 2, 1, 57600, 0x3f5805bb
+0, 3, 3, 1, 57600, 0xcb34504e
+0, 4, 4, 1, 57600, 0x66b6f6e9
+0, 5, 5, 1, 57600, 0x18698e4d
+0, 6, 6, 1, 57600, 0x233288d7
+0, 7, 7, 1, 57600, 0x6b195ac5
+0, 8, 8, 1, 57600, 0x3b466b45
+0, 9, 9, 1, 57600, 0x9e3dbd75
+0, 10, 10, 1, 57600, 0x90ee04b7
+0, 11, 11, 1, 57600, 0x81096dda
+0, 12, 12, 1, 57600, 0xef24ca50
+0, 13, 13, 1, 57600, 0xea7a3da8
+0, 14, 14, 1, 57600, 0xc3f054c2
+0, 15, 15, 1, 57600, 0x34af39ec
+0, 16, 16, 1, 57600, 0xfc31f846
+0, 17, 17, 1, 57600, 0xa4606399
+0, 18, 18, 1, 57600, 0x4b8a9c88
+0, 19, 19, 1, 57600, 0x87db3195
+0, 20, 20, 1, 57600, 0x443b618d
+0, 21, 21, 1, 57600, 0x601e380e
+0, 22, 22, 1, 57600, 0x405c6e6f
+0, 23, 23, 1, 57600, 0xe6b66f29
+0, 24, 24, 1, 57600, 0xb8e4b2d1
+0, 25, 25, 1, 57600, 0x9fc8e7da
+0, 26, 26, 1, 57600, 0x3bdb363b
+0, 27, 27, 1, 57600, 0xacac0b6a
+0, 28, 28, 1, 57600, 0xff3022fb
+0, 29, 29, 1, 57600, 0x1e5721f3
+0, 30, 30, 1, 57600, 0x511a3071
+0, 31, 31, 1, 57600, 0xff6d4dc0
+0, 32, 32, 1, 57600, 0x5df97a35
+0, 33, 33, 1, 57600, 0x3877f1b1
+0, 34, 34, 1, 57600, 0xa9096dd2
+0, 35, 35, 1, 57600, 0xd36e1ccc
+0, 36, 36, 1, 57600, 0xdc94b124
+0, 37, 37, 1, 57600, 0x873fab49
+0, 38, 38, 1, 57600, 0x7f081dca
+0, 39, 39, 1, 57600, 0x7df52bc3
+0, 40, 40, 1, 57600, 0xf41feb99
+0, 41, 41, 1, 57600, 0xcf59ffeb
+0, 42, 42, 1, 57600, 0x0dd94dfe
+0, 43, 43, 1, 57600, 0xfbc52500
+0, 44, 44, 1, 57600, 0xc300606e
+0, 45, 45, 1, 57600, 0x01e529b4
+0, 46, 46, 1, 57600, 0x359a57b0
+0, 47, 47, 1, 57600, 0xcfee7511
+0, 48, 48, 1, 57600, 0x2189f139
+0, 49, 49, 1, 57600, 0xcc535558
+0, 50, 50, 1, 57600, 0xeed13a76
+0, 51, 51, 1, 57600, 0xfb5c3ddd
+0, 52, 52, 1, 57600, 0x36a98c53
+0, 53, 53, 1, 57600, 0xf4c38c4b
+0, 54, 54, 1, 57600, 0x53d5df15
+0, 55, 55, 1, 57600, 0x336d890c
+0, 56, 56, 1, 57600, 0x19967f1c
+0, 57, 57, 1, 57600, 0xa36b8224
+0, 58, 58, 1, 57600, 0xf6ec2490
+0, 59, 59, 1, 57600, 0x6ffff0d1
+0, 60, 60, 1, 57600, 0xfcb73114
+0, 61, 61, 1, 57600, 0x5f5fff35
+0, 62, 62, 1, 57600, 0xf113c4a0
+0, 63, 63, 1, 57600, 0x64ca6175
+0, 64, 64, 1, 57600, 0x3f6f7d15
+0, 65, 65, 1, 57600, 0x18b619df
+0, 66, 66, 1, 57600, 0xe6872ed7
+0, 67, 67, 1, 57600, 0x3641e174
+0, 68, 68, 1, 57600, 0x4c144d8c
+0, 69, 69, 1, 57600, 0x82529776
+0, 70, 70, 1, 57600, 0xd96f3ead
+0, 71, 71, 1, 57600, 0xce183c4e
+0, 72, 72, 1, 57600, 0xaa475b24
+0, 73, 73, 1, 57600, 0xf7c5cbf3
+0, 74, 74, 1, 57600, 0x798e0548
+0, 75, 75, 1, 57600, 0x1233241a
+0, 76, 76, 1, 57600, 0x1424d758
+0, 77, 77, 1, 57600, 0xa446c264
+0, 78, 78, 1, 57600, 0x66e082ae
+0, 79, 79, 1, 57600, 0xb58cacc8
+0, 80, 80, 1, 57600, 0x3d86431c
+0, 81, 81, 1, 57600, 0x601b724e
+0, 82, 82, 1, 57600, 0xbe9a32c8
diff --git a/tests/ref/fate/qtrle-1bit b/tests/ref/fate/qtrle-1bit
index a424e47765..f191169236 100644
--- a/tests/ref/fate/qtrle-1bit
+++ b/tests/ref/fate/qtrle-1bit
@@ -1,39 +1,39 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 9600, 0xc5921aa2
-0, 100, 100, 0, 9600, 0x9032fc52
-0, 200, 200, 0, 9600, 0x7db0038e
-0, 300, 300, 0, 9600, 0x95b73c41
-0, 400, 400, 0, 9600, 0x531e4189
-0, 500, 500, 0, 9600, 0xb73390ec
-0, 600, 600, 0, 9600, 0x958e8221
-0, 700, 700, 0, 9600, 0xd393f8a6
-0, 800, 800, 0, 9600, 0xa085da1c
-0, 900, 900, 0, 9600, 0x57ace74f
-0, 1000, 1000, 0, 9600, 0x5d11a308
-0, 1100, 1100, 0, 9600, 0x13e133b7
-0, 1200, 1200, 0, 9600, 0x494edb86
-0, 1300, 1300, 0, 9600, 0x43a448ea
-0, 1400, 1400, 0, 9600, 0x3562d35b
-0, 1500, 1500, 0, 9600, 0x0bc655d2
-0, 1600, 1600, 0, 9600, 0xbece73a1
-0, 1700, 1700, 0, 9600, 0x82e7cfa1
-0, 1800, 1800, 0, 9600, 0xda29fd8f
-0, 1900, 1900, 0, 9600, 0x70fb700b
-0, 2000, 2000, 0, 9600, 0xaf57a6b0
-0, 2100, 2100, 0, 9600, 0x0a5ed9b9
-0, 2200, 2200, 0, 9600, 0xf7c62c38
-0, 2300, 2300, 0, 9600, 0x0aa2ccfd
-0, 2400, 2400, 0, 9600, 0xc9adabae
-0, 2500, 2500, 0, 9600, 0x67ff0aba
-0, 2600, 2600, 0, 9600, 0xea79a465
-0, 2700, 2700, 0, 9600, 0x8928c626
-0, 2800, 2800, 0, 9600, 0x8dab4111
-0, 2900, 2900, 0, 9600, 0x81ef63f9
-0, 3000, 3000, 0, 9600, 0xf977bc5e
-0, 3100, 3100, 0, 9600, 0x9e6a3f4a
-0, 3200, 3200, 0, 9600, 0x77c92865
-0, 3300, 3300, 0, 9600, 0x3915170d
-0, 3400, 3400, 0, 9600, 0xbe19b995
-0, 3500, 3500, 0, 9600, 0x3e8a3077
-0, 3600, 3600, 0, 9600, 0x1331342e
-0, 3700, 3700, 0, 9600, 0x4d692175
+#tb 0: 1/12
+0, 0, 0, 1, 9600, 0xc5921aa2
+0, 1, 1, 1, 9600, 0x9032fc52
+0, 2, 2, 1, 9600, 0x7db0038e
+0, 3, 3, 1, 9600, 0x95b73c41
+0, 4, 4, 1, 9600, 0x531e4189
+0, 5, 5, 1, 9600, 0xb73390ec
+0, 6, 6, 1, 9600, 0x958e8221
+0, 7, 7, 1, 9600, 0xd393f8a6
+0, 8, 8, 1, 9600, 0xa085da1c
+0, 9, 9, 1, 9600, 0x57ace74f
+0, 10, 10, 1, 9600, 0x5d11a308
+0, 11, 11, 1, 9600, 0x13e133b7
+0, 12, 12, 1, 9600, 0x494edb86
+0, 13, 13, 1, 9600, 0x43a448ea
+0, 14, 14, 1, 9600, 0x3562d35b
+0, 15, 15, 1, 9600, 0x0bc655d2
+0, 16, 16, 1, 9600, 0xbece73a1
+0, 17, 17, 1, 9600, 0x82e7cfa1
+0, 18, 18, 1, 9600, 0xda29fd8f
+0, 19, 19, 1, 9600, 0x70fb700b
+0, 20, 20, 1, 9600, 0xaf57a6b0
+0, 21, 21, 1, 9600, 0x0a5ed9b9
+0, 22, 22, 1, 9600, 0xf7c62c38
+0, 23, 23, 1, 9600, 0x0aa2ccfd
+0, 24, 24, 1, 9600, 0xc9adabae
+0, 25, 25, 1, 9600, 0x67ff0aba
+0, 26, 26, 1, 9600, 0xea79a465
+0, 27, 27, 1, 9600, 0x8928c626
+0, 28, 28, 1, 9600, 0x8dab4111
+0, 29, 29, 1, 9600, 0x81ef63f9
+0, 30, 30, 1, 9600, 0xf977bc5e
+0, 31, 31, 1, 9600, 0x9e6a3f4a
+0, 32, 32, 1, 9600, 0x77c92865
+0, 33, 33, 1, 9600, 0x3915170d
+0, 34, 34, 1, 9600, 0xbe19b995
+0, 35, 35, 1, 9600, 0x3e8a3077
+0, 36, 36, 1, 9600, 0x1331342e
+0, 37, 37, 1, 9600, 0x4d692175
diff --git a/tests/ref/fate/qtrle-24bit b/tests/ref/fate/qtrle-24bit
index 7a162b820e..a21b0996f4 100644
--- a/tests/ref/fate/qtrle-24bit
+++ b/tests/ref/fate/qtrle-24bit
@@ -1,35 +1,35 @@
-#tb 0: 1/600
+#tb 0: 1/10
0, 0, 0, 1, 57600, 0x3718ad00
-0, 60, 60, 1, 57600, 0x54861558
-0, 120, 120, 1, 57600, 0xea1d6233
-0, 180, 180, 1, 57600, 0xf669a2fd
-0, 240, 240, 1, 57600, 0xc9f76f31
-0, 300, 300, 1, 57600, 0xe23c6d7b
-0, 360, 360, 1, 57600, 0xbc9d6167
-0, 420, 420, 1, 57600, 0x0ca63477
-0, 480, 480, 1, 57600, 0xc0850d22
-0, 540, 540, 1, 57600, 0x735d10b2
-0, 600, 600, 1, 57600, 0x561f3c4a
-0, 660, 660, 1, 57600, 0x84db9cf1
-0, 720, 720, 1, 57600, 0x9fb841f4
-0, 780, 780, 1, 57600, 0xeaf262ab
-0, 840, 840, 1, 57600, 0x264886b4
-0, 900, 900, 1, 57600, 0x5edc5518
-0, 960, 960, 1, 57600, 0xd3e60c72
-0, 1020, 1020, 1, 57600, 0x9cabaed7
-0, 1080, 1080, 1, 57600, 0x616716cf
-0, 1140, 1140, 1, 57600, 0xa43f61aa
-0, 1200, 1200, 1, 57600, 0xdba3a0bd
-0, 1260, 1260, 1, 57600, 0xa7dd6dfa
-0, 1320, 1320, 1, 57600, 0xc3fa6c84
-0, 1380, 1380, 1, 57600, 0xb1275fb8
-0, 1440, 1440, 1, 57600, 0x2e39331f
-0, 1500, 1500, 1, 57600, 0x5b9e0bca
-0, 1560, 1560, 1, 57600, 0x0e760f5a
-0, 1620, 1620, 1, 57600, 0xc56c3e69
-0, 1680, 1680, 1, 57600, 0x51da9fb8
-0, 1740, 1740, 1, 57600, 0xe3a1432b
-0, 1800, 1800, 1, 57600, 0xe1b360a3
-0, 1860, 1860, 1, 57600, 0x30b383cd
-0, 1920, 1920, 1, 57600, 0x950c5439
-0, 1980, 1980, 1, 57600, 0x8f9d0ca2
+0, 1, 1, 1, 57600, 0x54861558
+0, 2, 2, 1, 57600, 0xea1d6233
+0, 3, 3, 1, 57600, 0xf669a2fd
+0, 4, 4, 1, 57600, 0xc9f76f31
+0, 5, 5, 1, 57600, 0xe23c6d7b
+0, 6, 6, 1, 57600, 0xbc9d6167
+0, 7, 7, 1, 57600, 0x0ca63477
+0, 8, 8, 1, 57600, 0xc0850d22
+0, 9, 9, 1, 57600, 0x735d10b2
+0, 10, 10, 1, 57600, 0x561f3c4a
+0, 11, 11, 1, 57600, 0x84db9cf1
+0, 12, 12, 1, 57600, 0x9fb841f4
+0, 13, 13, 1, 57600, 0xeaf262ab
+0, 14, 14, 1, 57600, 0x264886b4
+0, 15, 15, 1, 57600, 0x5edc5518
+0, 16, 16, 1, 57600, 0xd3e60c72
+0, 17, 17, 1, 57600, 0x9cabaed7
+0, 18, 18, 1, 57600, 0x616716cf
+0, 19, 19, 1, 57600, 0xa43f61aa
+0, 20, 20, 1, 57600, 0xdba3a0bd
+0, 21, 21, 1, 57600, 0xa7dd6dfa
+0, 22, 22, 1, 57600, 0xc3fa6c84
+0, 23, 23, 1, 57600, 0xb1275fb8
+0, 24, 24, 1, 57600, 0x2e39331f
+0, 25, 25, 1, 57600, 0x5b9e0bca
+0, 26, 26, 1, 57600, 0x0e760f5a
+0, 27, 27, 1, 57600, 0xc56c3e69
+0, 28, 28, 1, 57600, 0x51da9fb8
+0, 29, 29, 1, 57600, 0xe3a1432b
+0, 30, 30, 1, 57600, 0xe1b360a3
+0, 31, 31, 1, 57600, 0x30b383cd
+0, 32, 32, 1, 57600, 0x950c5439
+0, 33, 33, 1, 57600, 0x8f9d0ca2
diff --git a/tests/ref/fate/qtrle-2bit b/tests/ref/fate/qtrle-2bit
index 5866db5955..95c0f7c391 100644
--- a/tests/ref/fate/qtrle-2bit
+++ b/tests/ref/fate/qtrle-2bit
@@ -1,39 +1,39 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 230400, 0xb1ee55dc
-0, 100, 100, 0, 230400, 0x97c580bf
-0, 200, 200, 0, 230400, 0xd4bd57e8
-0, 300, 300, 0, 230400, 0x412b79aa
-0, 400, 400, 0, 230400, 0x928a44d1
-0, 500, 500, 0, 230400, 0x6bbdc0e4
-0, 600, 600, 0, 230400, 0x382e960f
-0, 700, 700, 0, 230400, 0x62c863ea
-0, 800, 800, 0, 230400, 0xbfccd3ce
-0, 900, 900, 0, 230400, 0x1987cdd4
-0, 1000, 1000, 0, 230400, 0x40279727
-0, 1100, 1100, 0, 230400, 0x9d4f6746
-0, 1200, 1200, 0, 230400, 0x7b8a77ec
-0, 1300, 1300, 0, 230400, 0x2ce7a781
-0, 1400, 1400, 0, 230400, 0xb749815e
-0, 1500, 1500, 0, 230400, 0x61c88610
-0, 1600, 1600, 0, 230400, 0x8449114d
-0, 1700, 1700, 0, 230400, 0x5f73e666
-0, 1800, 1800, 0, 230400, 0xbde53ce6
-0, 1900, 1900, 0, 230400, 0x8c7406fd
-0, 2000, 2000, 0, 230400, 0xf9e9a3ef
-0, 2100, 2100, 0, 230400, 0x7e0a3077
-0, 2200, 2200, 0, 230400, 0xd9245c5f
-0, 2300, 2300, 0, 230400, 0x6d077ea2
-0, 2400, 2400, 0, 230400, 0xf622bb2a
-0, 2500, 2500, 0, 230400, 0x35292dc8
-0, 2600, 2600, 0, 230400, 0xc0cea946
-0, 2700, 2700, 0, 230400, 0x98b27b60
-0, 2800, 2800, 0, 230400, 0x668ef6bd
-0, 2900, 2900, 0, 230400, 0x6c07a31c
-0, 3000, 3000, 0, 230400, 0x0b4a6ae1
-0, 3100, 3100, 0, 230400, 0x945b9878
-0, 3200, 3200, 0, 230400, 0xab28031c
-0, 3300, 3300, 0, 230400, 0x977252b0
-0, 3400, 3400, 0, 230400, 0x6c3d9706
-0, 3500, 3500, 0, 230400, 0xe053bc2a
-0, 3600, 3600, 0, 230400, 0x4cf2fc7c
-0, 3700, 3700, 0, 230400, 0x610beda7
+#tb 0: 1/12
+0, 0, 0, 1, 230400, 0xb1ee55dc
+0, 1, 1, 1, 230400, 0x97c580bf
+0, 2, 2, 1, 230400, 0xd4bd57e8
+0, 3, 3, 1, 230400, 0x412b79aa
+0, 4, 4, 1, 230400, 0x928a44d1
+0, 5, 5, 1, 230400, 0x6bbdc0e4
+0, 6, 6, 1, 230400, 0x382e960f
+0, 7, 7, 1, 230400, 0x62c863ea
+0, 8, 8, 1, 230400, 0xbfccd3ce
+0, 9, 9, 1, 230400, 0x1987cdd4
+0, 10, 10, 1, 230400, 0x40279727
+0, 11, 11, 1, 230400, 0x9d4f6746
+0, 12, 12, 1, 230400, 0x7b8a77ec
+0, 13, 13, 1, 230400, 0x2ce7a781
+0, 14, 14, 1, 230400, 0xb749815e
+0, 15, 15, 1, 230400, 0x61c88610
+0, 16, 16, 1, 230400, 0x8449114d
+0, 17, 17, 1, 230400, 0x5f73e666
+0, 18, 18, 1, 230400, 0xbde53ce6
+0, 19, 19, 1, 230400, 0x8c7406fd
+0, 20, 20, 1, 230400, 0xf9e9a3ef
+0, 21, 21, 1, 230400, 0x7e0a3077
+0, 22, 22, 1, 230400, 0xd9245c5f
+0, 23, 23, 1, 230400, 0x6d077ea2
+0, 24, 24, 1, 230400, 0xf622bb2a
+0, 25, 25, 1, 230400, 0x35292dc8
+0, 26, 26, 1, 230400, 0xc0cea946
+0, 27, 27, 1, 230400, 0x98b27b60
+0, 28, 28, 1, 230400, 0x668ef6bd
+0, 29, 29, 1, 230400, 0x6c07a31c
+0, 30, 30, 1, 230400, 0x0b4a6ae1
+0, 31, 31, 1, 230400, 0x945b9878
+0, 32, 32, 1, 230400, 0xab28031c
+0, 33, 33, 1, 230400, 0x977252b0
+0, 34, 34, 1, 230400, 0x6c3d9706
+0, 35, 35, 1, 230400, 0xe053bc2a
+0, 36, 36, 1, 230400, 0x4cf2fc7c
+0, 37, 37, 1, 230400, 0x610beda7
diff --git a/tests/ref/fate/qtrle-32bit b/tests/ref/fate/qtrle-32bit
index bbdd464593..ed6dc03a26 100644
--- a/tests/ref/fate/qtrle-32bit
+++ b/tests/ref/fate/qtrle-32bit
@@ -1,27 +1,27 @@
-#tb 0: 1/2997
-0, 0, 0, 0, 1036800, 0x2a90d062
-0, 100, 100, 0, 1036800, 0x6565aded
-0, 200, 200, 0, 1036800, 0xf0b587d2
-0, 300, 300, 0, 1036800, 0xf0b4e53f
-0, 400, 400, 0, 1036800, 0x5ba4b96a
-0, 500, 500, 0, 1036800, 0x501df9c1
-0, 600, 600, 0, 1036800, 0xcf45b940
-0, 700, 700, 0, 1036800, 0xa454df07
-0, 800, 800, 0, 1036800, 0xc504d152
-0, 900, 900, 0, 1036800, 0xd90ecac7
-0, 1000, 1000, 0, 1036800, 0xe30368df
-0, 1100, 1100, 0, 1036800, 0x0ca35522
-0, 1200, 1200, 0, 1036800, 0xe76b8d43
-0, 1300, 1300, 0, 1036800, 0x7c85a447
-0, 1400, 1400, 0, 1036800, 0x3e2d1b5f
-0, 1500, 1500, 0, 1036800, 0x230fa5a6
-0, 1600, 1600, 0, 1036800, 0x4fad025e
-0, 1700, 1700, 0, 1036800, 0x7d3366ae
-0, 1800, 1800, 0, 1036800, 0xa83720f7
-0, 1900, 1900, 0, 1036800, 0x5dbd13b1
-0, 2000, 2000, 0, 1036800, 0xd0ebd56d
-0, 2100, 2100, 0, 1036800, 0x4d7c67f3
-0, 2200, 2200, 0, 1036800, 0x226baa3f
-0, 2300, 2300, 0, 1036800, 0xc0e93acf
-0, 2400, 2400, 0, 1036800, 0x5a466c17
-0, 2500, 2500, 0, 1036800, 0xfdb7d2ea
+#tb 0: 100/2997
+0, 0, 0, 1, 1036800, 0x2a90d062
+0, 1, 1, 1, 1036800, 0x6565aded
+0, 2, 2, 1, 1036800, 0xf0b587d2
+0, 3, 3, 1, 1036800, 0xf0b4e53f
+0, 4, 4, 1, 1036800, 0x5ba4b96a
+0, 5, 5, 1, 1036800, 0x501df9c1
+0, 6, 6, 1, 1036800, 0xcf45b940
+0, 7, 7, 1, 1036800, 0xa454df07
+0, 8, 8, 1, 1036800, 0xc504d152
+0, 9, 9, 1, 1036800, 0xd90ecac7
+0, 10, 10, 1, 1036800, 0xe30368df
+0, 11, 11, 1, 1036800, 0x0ca35522
+0, 12, 12, 1, 1036800, 0xe76b8d43
+0, 13, 13, 1, 1036800, 0x7c85a447
+0, 14, 14, 1, 1036800, 0x3e2d1b5f
+0, 15, 15, 1, 1036800, 0x230fa5a6
+0, 16, 16, 1, 1036800, 0x4fad025e
+0, 17, 17, 1, 1036800, 0x7d3366ae
+0, 18, 18, 1, 1036800, 0xa83720f7
+0, 19, 19, 1, 1036800, 0x5dbd13b1
+0, 20, 20, 1, 1036800, 0xd0ebd56d
+0, 21, 21, 1, 1036800, 0x4d7c67f3
+0, 22, 22, 1, 1036800, 0x226baa3f
+0, 23, 23, 1, 1036800, 0xc0e93acf
+0, 24, 24, 1, 1036800, 0x5a466c17
+0, 25, 25, 1, 1036800, 0xfdb7d2ea
diff --git a/tests/ref/fate/qtrle-4bit b/tests/ref/fate/qtrle-4bit
index cc09e78475..74eb4ab078 100644
--- a/tests/ref/fate/qtrle-4bit
+++ b/tests/ref/fate/qtrle-4bit
@@ -1,39 +1,39 @@
-#tb 0: 1/1200
-0, 0, 0, 0, 230400, 0x0655b3d9
-0, 100, 100, 0, 230400, 0x9c626fd3
-0, 200, 200, 0, 230400, 0x5bc95868
-0, 300, 300, 0, 230400, 0x55a38387
-0, 400, 400, 0, 230400, 0xd3495b60
-0, 500, 500, 0, 230400, 0xecdb2d15
-0, 600, 600, 0, 230400, 0x7f9b373e
-0, 700, 700, 0, 230400, 0x51caac22
-0, 800, 800, 0, 230400, 0x0f2ac153
-0, 900, 900, 0, 230400, 0xe5a6f9e7
-0, 1000, 1000, 0, 230400, 0xfc2b2250
-0, 1100, 1100, 0, 230400, 0x24e2da1b
-0, 1200, 1200, 0, 230400, 0x2723d7dd
-0, 1300, 1300, 0, 230400, 0x024a4989
-0, 1400, 1400, 0, 230400, 0xdbafb92d
-0, 1500, 1500, 0, 230400, 0x6b9b5056
-0, 1600, 1600, 0, 230400, 0x010cabb4
-0, 1700, 1700, 0, 230400, 0xf75bc1c0
-0, 1800, 1800, 0, 230400, 0x6c7fd744
-0, 1900, 1900, 0, 230400, 0xabe4371a
-0, 2000, 2000, 0, 230400, 0xe41fb781
-0, 2100, 2100, 0, 230400, 0x42c5649e
-0, 2200, 2200, 0, 230400, 0xf5511deb
-0, 2300, 2300, 0, 230400, 0xebf5ab32
-0, 2400, 2400, 0, 230400, 0x44398194
-0, 2500, 2500, 0, 230400, 0xfd63510c
-0, 2600, 2600, 0, 230400, 0xa013975e
-0, 2700, 2700, 0, 230400, 0xe0aa028d
-0, 2800, 2800, 0, 230400, 0x349f6f3b
-0, 2900, 2900, 0, 230400, 0x2446032c
-0, 3000, 3000, 0, 230400, 0x648f122c
-0, 3100, 3100, 0, 230400, 0xbda221fd
-0, 3200, 3200, 0, 230400, 0xf0f97642
-0, 3300, 3300, 0, 230400, 0x6a1737de
-0, 3400, 3400, 0, 230400, 0x808a8179
-0, 3500, 3500, 0, 230400, 0x121641cf
-0, 3600, 3600, 0, 230400, 0x275d11ea
-0, 3700, 3700, 0, 230400, 0x92adf2cf
+#tb 0: 1/12
+0, 0, 0, 1, 230400, 0x0655b3d9
+0, 1, 1, 1, 230400, 0x9c626fd3
+0, 2, 2, 1, 230400, 0x5bc95868
+0, 3, 3, 1, 230400, 0x55a38387
+0, 4, 4, 1, 230400, 0xd3495b60
+0, 5, 5, 1, 230400, 0xecdb2d15
+0, 6, 6, 1, 230400, 0x7f9b373e
+0, 7, 7, 1, 230400, 0x51caac22
+0, 8, 8, 1, 230400, 0x0f2ac153
+0, 9, 9, 1, 230400, 0xe5a6f9e7
+0, 10, 10, 1, 230400, 0xfc2b2250
+0, 11, 11, 1, 230400, 0x24e2da1b
+0, 12, 12, 1, 230400, 0x2723d7dd
+0, 13, 13, 1, 230400, 0x024a4989
+0, 14, 14, 1, 230400, 0xdbafb92d
+0, 15, 15, 1, 230400, 0x6b9b5056
+0, 16, 16, 1, 230400, 0x010cabb4
+0, 17, 17, 1, 230400, 0xf75bc1c0
+0, 18, 18, 1, 230400, 0x6c7fd744
+0, 19, 19, 1, 230400, 0xabe4371a
+0, 20, 20, 1, 230400, 0xe41fb781
+0, 21, 21, 1, 230400, 0x42c5649e
+0, 22, 22, 1, 230400, 0xf5511deb
+0, 23, 23, 1, 230400, 0xebf5ab32
+0, 24, 24, 1, 230400, 0x44398194
+0, 25, 25, 1, 230400, 0xfd63510c
+0, 26, 26, 1, 230400, 0xa013975e
+0, 27, 27, 1, 230400, 0xe0aa028d
+0, 28, 28, 1, 230400, 0x349f6f3b
+0, 29, 29, 1, 230400, 0x2446032c
+0, 30, 30, 1, 230400, 0x648f122c
+0, 31, 31, 1, 230400, 0xbda221fd
+0, 32, 32, 1, 230400, 0xf0f97642
+0, 33, 33, 1, 230400, 0x6a1737de
+0, 34, 34, 1, 230400, 0x808a8179
+0, 35, 35, 1, 230400, 0x121641cf
+0, 36, 36, 1, 230400, 0x275d11ea
+0, 37, 37, 1, 230400, 0x92adf2cf
diff --git a/tests/ref/fate/qtrle-8bit b/tests/ref/fate/qtrle-8bit
index bef2358e94..5b30fbbf5c 100644
--- a/tests/ref/fate/qtrle-8bit
+++ b/tests/ref/fate/qtrle-8bit
@@ -1,168 +1,168 @@
-#tb 0: 1/600
+#tb 0: 1/15
0, 0, 0, 1, 921600, 0x1492e3ed
-0, 40, 40, 1, 921600, 0x1492e3ed
-0, 80, 80, 1, 921600, 0x1492e3ed
-0, 120, 120, 1, 921600, 0x23ef4fc7
-0, 160, 160, 1, 921600, 0x23ef4fc7
-0, 200, 200, 1, 921600, 0xe406d4be
-0, 240, 240, 1, 921600, 0xe406d4be
-0, 280, 280, 1, 921600, 0xe406d4be
-0, 320, 320, 1, 921600, 0x62b8b5a1
-0, 360, 360, 1, 921600, 0x62b8b5a1
-0, 400, 400, 1, 921600, 0x7d8ba674
-0, 440, 440, 1, 921600, 0x7d8ba674
-0, 480, 480, 1, 921600, 0x7d8ba674
-0, 520, 520, 1, 921600, 0xfe666be7
-0, 560, 560, 1, 921600, 0xfe666be7
-0, 600, 600, 1, 921600, 0x721baec0
-0, 640, 640, 1, 921600, 0x721baec0
-0, 680, 680, 1, 921600, 0x721baec0
-0, 720, 720, 1, 921600, 0xc237180a
-0, 760, 760, 1, 921600, 0xc237180a
-0, 800, 800, 1, 921600, 0xf03a7482
-0, 840, 840, 1, 921600, 0xf03a7482
-0, 880, 880, 1, 921600, 0xf03a7482
-0, 920, 920, 1, 921600, 0x5612a391
-0, 960, 960, 1, 921600, 0x5612a391
-0, 1000, 1000, 1, 921600, 0x9dbcc46a
-0, 1040, 1040, 1, 921600, 0x9dbcc46a
-0, 1080, 1080, 1, 921600, 0x9dbcc46a
-0, 1120, 1120, 1, 921600, 0xa128a5d5
-0, 1160, 1160, 1, 921600, 0xa128a5d5
-0, 1200, 1200, 1, 921600, 0x63e0025c
-0, 1240, 1240, 1, 921600, 0x63e0025c
-0, 1280, 1280, 1, 921600, 0x63e0025c
-0, 1320, 1320, 1, 921600, 0x262359ed
-0, 1360, 1360, 1, 921600, 0x262359ed
-0, 1400, 1400, 1, 921600, 0x343688e8
-0, 1440, 1440, 1, 921600, 0x343688e8
-0, 1480, 1480, 1, 921600, 0x343688e8
-0, 1520, 1520, 1, 921600, 0x343688e8
-0, 1560, 1560, 1, 921600, 0x343688e8
-0, 1600, 1600, 1, 921600, 0x343688e8
-0, 1640, 1640, 1, 921600, 0x343688e8
-0, 1680, 1680, 1, 921600, 0x343688e8
-0, 1720, 1720, 1, 921600, 0x343688e8
-0, 1760, 1760, 1, 921600, 0x343688e8
-0, 1800, 1800, 1, 921600, 0xe4b29d57
-0, 1840, 1840, 1, 921600, 0xe4b29d57
-0, 1880, 1880, 1, 921600, 0xe4b29d57
-0, 1920, 1920, 1, 921600, 0x198e8a4a
-0, 1960, 1960, 1, 921600, 0x198e8a4a
-0, 2000, 2000, 1, 921600, 0x0cad8dc9
-0, 2040, 2040, 1, 921600, 0x0cad8dc9
-0, 2080, 2080, 1, 921600, 0x0cad8dc9
-0, 2120, 2120, 1, 921600, 0x1f74cf3d
-0, 2160, 2160, 1, 921600, 0x1f74cf3d
-0, 2200, 2200, 1, 921600, 0xec5b5449
-0, 2240, 2240, 1, 921600, 0xec5b5449
-0, 2280, 2280, 1, 921600, 0xec5b5449
-0, 2320, 2320, 1, 921600, 0x39829711
-0, 2360, 2360, 1, 921600, 0x39829711
-0, 2400, 2400, 1, 921600, 0x6de5b9c6
-0, 2440, 2440, 1, 921600, 0x6de5b9c6
-0, 2480, 2480, 1, 921600, 0x6de5b9c6
-0, 2520, 2520, 1, 921600, 0x47b0e9d4
-0, 2560, 2560, 1, 921600, 0x47b0e9d4
-0, 2600, 2600, 1, 921600, 0x756452b8
-0, 2640, 2640, 1, 921600, 0x756452b8
-0, 2680, 2680, 1, 921600, 0x756452b8
-0, 2720, 2720, 1, 921600, 0x6fce3478
-0, 2760, 2760, 1, 921600, 0x6fce3478
-0, 2800, 2800, 1, 921600, 0x372397cd
-0, 2840, 2840, 1, 921600, 0x372397cd
-0, 2880, 2880, 1, 921600, 0x372397cd
-0, 2920, 2920, 1, 921600, 0xe3999ba1
-0, 2960, 2960, 1, 921600, 0xe3999ba1
-0, 3000, 3000, 1, 921600, 0x6ba26b43
-0, 3040, 3040, 1, 921600, 0x6ba26b43
-0, 3080, 3080, 1, 921600, 0x6ba26b43
-0, 3120, 3120, 1, 921600, 0x4e9ee49e
-0, 3160, 3160, 1, 921600, 0x4e9ee49e
-0, 3200, 3200, 1, 921600, 0xdb5fd6e7
-0, 3240, 3240, 1, 921600, 0xdb5fd6e7
-0, 3280, 3280, 1, 921600, 0xdb5fd6e7
-0, 3320, 3320, 1, 921600, 0x8f2254a5
-0, 3360, 3360, 1, 921600, 0x8f2254a5
-0, 3400, 3400, 1, 921600, 0x8f2254a5
-0, 3440, 3440, 1, 921600, 0x8f2254a5
-0, 3480, 3480, 1, 921600, 0x8f2254a5
-0, 3520, 3520, 1, 921600, 0x8f2254a5
-0, 3560, 3560, 1, 921600, 0x8f2254a5
-0, 3600, 3600, 1, 921600, 0x8f2254a5
-0, 3640, 3640, 1, 921600, 0x8f2254a5
-0, 3680, 3680, 1, 921600, 0x8f2254a5
-0, 3720, 3720, 1, 921600, 0x57e95c32
-0, 3760, 3760, 1, 921600, 0x57e95c32
-0, 3800, 3800, 1, 921600, 0x41627a9b
-0, 3840, 3840, 1, 921600, 0x41627a9b
-0, 3880, 3880, 1, 921600, 0x41627a9b
-0, 3920, 3920, 1, 921600, 0x7412dcee
-0, 3960, 3960, 1, 921600, 0x7412dcee
-0, 4000, 4000, 1, 921600, 0xaebe10ed
-0, 4040, 4040, 1, 921600, 0xaebe10ed
-0, 4080, 4080, 1, 921600, 0xaebe10ed
-0, 4120, 4120, 1, 921600, 0x411a91f6
-0, 4160, 4160, 1, 921600, 0x411a91f6
-0, 4200, 4200, 1, 921600, 0xb059df3f
-0, 4240, 4240, 1, 921600, 0xb059df3f
-0, 4280, 4280, 1, 921600, 0xb059df3f
-0, 4320, 4320, 1, 921600, 0x4d6f5a77
-0, 4360, 4360, 1, 921600, 0x4d6f5a77
-0, 4400, 4400, 1, 921600, 0xbbf06df4
-0, 4440, 4440, 1, 921600, 0xbbf06df4
-0, 4480, 4480, 1, 921600, 0xbbf06df4
-0, 4520, 4520, 1, 921600, 0xe27f7bf6
-0, 4560, 4560, 1, 921600, 0xe27f7bf6
-0, 4600, 4600, 1, 921600, 0xd7e8360e
-0, 4640, 4640, 1, 921600, 0xd7e8360e
-0, 4680, 4680, 1, 921600, 0xd7e8360e
-0, 4720, 4720, 1, 921600, 0x1dd4c344
-0, 4760, 4760, 1, 921600, 0x1dd4c344
-0, 4800, 4800, 1, 921600, 0x7995a7ce
-0, 4840, 4840, 1, 921600, 0x7995a7ce
-0, 4880, 4880, 1, 921600, 0x7995a7ce
-0, 4920, 4920, 1, 921600, 0x2ef3c566
-0, 4960, 4960, 1, 921600, 0x2ef3c566
-0, 5000, 5000, 1, 921600, 0xf296736e
-0, 5040, 5040, 1, 921600, 0xf296736e
-0, 5080, 5080, 1, 921600, 0xf296736e
-0, 5120, 5120, 1, 921600, 0xf296736e
-0, 5160, 5160, 1, 921600, 0xf296736e
-0, 5200, 5200, 1, 921600, 0xf296736e
-0, 5240, 5240, 1, 921600, 0xf296736e
-0, 5280, 5280, 1, 921600, 0xf296736e
-0, 5320, 5320, 1, 921600, 0xf296736e
-0, 5360, 5360, 1, 921600, 0xf296736e
-0, 5400, 5400, 1, 921600, 0x1a488311
-0, 5440, 5440, 1, 921600, 0x1a488311
-0, 5480, 5480, 1, 921600, 0x1a488311
-0, 5520, 5520, 1, 921600, 0x9e28011b
-0, 5560, 5560, 1, 921600, 0x9e28011b
-0, 5600, 5600, 1, 921600, 0x84d1ea80
-0, 5640, 5640, 1, 921600, 0x84d1ea80
-0, 5680, 5680, 1, 921600, 0x84d1ea80
-0, 5720, 5720, 1, 921600, 0x9ed41052
-0, 5760, 5760, 1, 921600, 0x9ed41052
-0, 5800, 5800, 1, 921600, 0xd4db7206
-0, 5840, 5840, 1, 921600, 0xd4db7206
-0, 5880, 5880, 1, 921600, 0xd4db7206
-0, 5920, 5920, 1, 921600, 0x55f695a9
-0, 5960, 5960, 1, 921600, 0x55f695a9
-0, 6000, 6000, 1, 921600, 0x9d8c667f
-0, 6040, 6040, 1, 921600, 0x9d8c667f
-0, 6080, 6080, 1, 921600, 0x9d8c667f
-0, 6120, 6120, 1, 921600, 0x9b6037ec
-0, 6160, 6160, 1, 921600, 0x9b6037ec
-0, 6200, 6200, 1, 921600, 0x57c5e835
-0, 6240, 6240, 1, 921600, 0x57c5e835
-0, 6280, 6280, 1, 921600, 0x57c5e835
-0, 6320, 6320, 1, 921600, 0x476dad89
-0, 6360, 6360, 1, 921600, 0x476dad89
-0, 6400, 6400, 1, 921600, 0xcfd6ad2b
-0, 6440, 6440, 1, 921600, 0xcfd6ad2b
-0, 6480, 6480, 1, 921600, 0xcfd6ad2b
-0, 6520, 6520, 1, 921600, 0x3b372379
-0, 6560, 6560, 1, 921600, 0x3b372379
-0, 6600, 6600, 1, 921600, 0x36f245f5
-0, 6620, 6620, 1, 921600, 0x36f245f5
+0, 1, 1, 1, 921600, 0x1492e3ed
+0, 2, 2, 1, 921600, 0x1492e3ed
+0, 3, 3, 1, 921600, 0x23ef4fc7
+0, 4, 4, 1, 921600, 0x23ef4fc7
+0, 5, 5, 1, 921600, 0xe406d4be
+0, 6, 6, 1, 921600, 0xe406d4be
+0, 7, 7, 1, 921600, 0xe406d4be
+0, 8, 8, 1, 921600, 0x62b8b5a1
+0, 9, 9, 1, 921600, 0x62b8b5a1
+0, 10, 10, 1, 921600, 0x7d8ba674
+0, 11, 11, 1, 921600, 0x7d8ba674
+0, 12, 12, 1, 921600, 0x7d8ba674
+0, 13, 13, 1, 921600, 0xfe666be7
+0, 14, 14, 1, 921600, 0xfe666be7
+0, 15, 15, 1, 921600, 0x721baec0
+0, 16, 16, 1, 921600, 0x721baec0
+0, 17, 17, 1, 921600, 0x721baec0
+0, 18, 18, 1, 921600, 0xc237180a
+0, 19, 19, 1, 921600, 0xc237180a
+0, 20, 20, 1, 921600, 0xf03a7482
+0, 21, 21, 1, 921600, 0xf03a7482
+0, 22, 22, 1, 921600, 0xf03a7482
+0, 23, 23, 1, 921600, 0x5612a391
+0, 24, 24, 1, 921600, 0x5612a391
+0, 25, 25, 1, 921600, 0x9dbcc46a
+0, 26, 26, 1, 921600, 0x9dbcc46a
+0, 27, 27, 1, 921600, 0x9dbcc46a
+0, 28, 28, 1, 921600, 0xa128a5d5
+0, 29, 29, 1, 921600, 0xa128a5d5
+0, 30, 30, 1, 921600, 0x63e0025c
+0, 31, 31, 1, 921600, 0x63e0025c
+0, 32, 32, 1, 921600, 0x63e0025c
+0, 33, 33, 1, 921600, 0x262359ed
+0, 34, 34, 1, 921600, 0x262359ed
+0, 35, 35, 1, 921600, 0x343688e8
+0, 36, 36, 1, 921600, 0x343688e8
+0, 37, 37, 1, 921600, 0x343688e8
+0, 38, 38, 1, 921600, 0x343688e8
+0, 39, 39, 1, 921600, 0x343688e8
+0, 40, 40, 1, 921600, 0x343688e8
+0, 41, 41, 1, 921600, 0x343688e8
+0, 42, 42, 1, 921600, 0x343688e8
+0, 43, 43, 1, 921600, 0x343688e8
+0, 44, 44, 1, 921600, 0x343688e8
+0, 45, 45, 1, 921600, 0xe4b29d57
+0, 46, 46, 1, 921600, 0xe4b29d57
+0, 47, 47, 1, 921600, 0xe4b29d57
+0, 48, 48, 1, 921600, 0x198e8a4a
+0, 49, 49, 1, 921600, 0x198e8a4a
+0, 50, 50, 1, 921600, 0x0cad8dc9
+0, 51, 51, 1, 921600, 0x0cad8dc9
+0, 52, 52, 1, 921600, 0x0cad8dc9
+0, 53, 53, 1, 921600, 0x1f74cf3d
+0, 54, 54, 1, 921600, 0x1f74cf3d
+0, 55, 55, 1, 921600, 0xec5b5449
+0, 56, 56, 1, 921600, 0xec5b5449
+0, 57, 57, 1, 921600, 0xec5b5449
+0, 58, 58, 1, 921600, 0x39829711
+0, 59, 59, 1, 921600, 0x39829711
+0, 60, 60, 1, 921600, 0x6de5b9c6
+0, 61, 61, 1, 921600, 0x6de5b9c6
+0, 62, 62, 1, 921600, 0x6de5b9c6
+0, 63, 63, 1, 921600, 0x47b0e9d4
+0, 64, 64, 1, 921600, 0x47b0e9d4
+0, 65, 65, 1, 921600, 0x756452b8
+0, 66, 66, 1, 921600, 0x756452b8
+0, 67, 67, 1, 921600, 0x756452b8
+0, 68, 68, 1, 921600, 0x6fce3478
+0, 69, 69, 1, 921600, 0x6fce3478
+0, 70, 70, 1, 921600, 0x372397cd
+0, 71, 71, 1, 921600, 0x372397cd
+0, 72, 72, 1, 921600, 0x372397cd
+0, 73, 73, 1, 921600, 0xe3999ba1
+0, 74, 74, 1, 921600, 0xe3999ba1
+0, 75, 75, 1, 921600, 0x6ba26b43
+0, 76, 76, 1, 921600, 0x6ba26b43
+0, 77, 77, 1, 921600, 0x6ba26b43
+0, 78, 78, 1, 921600, 0x4e9ee49e
+0, 79, 79, 1, 921600, 0x4e9ee49e
+0, 80, 80, 1, 921600, 0xdb5fd6e7
+0, 81, 81, 1, 921600, 0xdb5fd6e7
+0, 82, 82, 1, 921600, 0xdb5fd6e7
+0, 83, 83, 1, 921600, 0x8f2254a5
+0, 84, 84, 1, 921600, 0x8f2254a5
+0, 85, 85, 1, 921600, 0x8f2254a5
+0, 86, 86, 1, 921600, 0x8f2254a5
+0, 87, 87, 1, 921600, 0x8f2254a5
+0, 88, 88, 1, 921600, 0x8f2254a5
+0, 89, 89, 1, 921600, 0x8f2254a5
+0, 90, 90, 1, 921600, 0x8f2254a5
+0, 91, 91, 1, 921600, 0x8f2254a5
+0, 92, 92, 1, 921600, 0x8f2254a5
+0, 93, 93, 1, 921600, 0x57e95c32
+0, 94, 94, 1, 921600, 0x57e95c32
+0, 95, 95, 1, 921600, 0x41627a9b
+0, 96, 96, 1, 921600, 0x41627a9b
+0, 97, 97, 1, 921600, 0x41627a9b
+0, 98, 98, 1, 921600, 0x7412dcee
+0, 99, 99, 1, 921600, 0x7412dcee
+0, 100, 100, 1, 921600, 0xaebe10ed
+0, 101, 101, 1, 921600, 0xaebe10ed
+0, 102, 102, 1, 921600, 0xaebe10ed
+0, 103, 103, 1, 921600, 0x411a91f6
+0, 104, 104, 1, 921600, 0x411a91f6
+0, 105, 105, 1, 921600, 0xb059df3f
+0, 106, 106, 1, 921600, 0xb059df3f
+0, 107, 107, 1, 921600, 0xb059df3f
+0, 108, 108, 1, 921600, 0x4d6f5a77
+0, 109, 109, 1, 921600, 0x4d6f5a77
+0, 110, 110, 1, 921600, 0xbbf06df4
+0, 111, 111, 1, 921600, 0xbbf06df4
+0, 112, 112, 1, 921600, 0xbbf06df4
+0, 113, 113, 1, 921600, 0xe27f7bf6
+0, 114, 114, 1, 921600, 0xe27f7bf6
+0, 115, 115, 1, 921600, 0xd7e8360e
+0, 116, 116, 1, 921600, 0xd7e8360e
+0, 117, 117, 1, 921600, 0xd7e8360e
+0, 118, 118, 1, 921600, 0x1dd4c344
+0, 119, 119, 1, 921600, 0x1dd4c344
+0, 120, 120, 1, 921600, 0x7995a7ce
+0, 121, 121, 1, 921600, 0x7995a7ce
+0, 122, 122, 1, 921600, 0x7995a7ce
+0, 123, 123, 1, 921600, 0x2ef3c566
+0, 124, 124, 1, 921600, 0x2ef3c566
+0, 125, 125, 1, 921600, 0xf296736e
+0, 126, 126, 1, 921600, 0xf296736e
+0, 127, 127, 1, 921600, 0xf296736e
+0, 128, 128, 1, 921600, 0xf296736e
+0, 129, 129, 1, 921600, 0xf296736e
+0, 130, 130, 1, 921600, 0xf296736e
+0, 131, 131, 1, 921600, 0xf296736e
+0, 132, 132, 1, 921600, 0xf296736e
+0, 133, 133, 1, 921600, 0xf296736e
+0, 134, 134, 1, 921600, 0xf296736e
+0, 135, 135, 1, 921600, 0x1a488311
+0, 136, 136, 1, 921600, 0x1a488311
+0, 137, 137, 1, 921600, 0x1a488311
+0, 138, 138, 1, 921600, 0x9e28011b
+0, 139, 139, 1, 921600, 0x9e28011b
+0, 140, 140, 1, 921600, 0x84d1ea80
+0, 141, 141, 1, 921600, 0x84d1ea80
+0, 142, 142, 1, 921600, 0x84d1ea80
+0, 143, 143, 1, 921600, 0x9ed41052
+0, 144, 144, 1, 921600, 0x9ed41052
+0, 145, 145, 1, 921600, 0xd4db7206
+0, 146, 146, 1, 921600, 0xd4db7206
+0, 147, 147, 1, 921600, 0xd4db7206
+0, 148, 148, 1, 921600, 0x55f695a9
+0, 149, 149, 1, 921600, 0x55f695a9
+0, 150, 150, 1, 921600, 0x9d8c667f
+0, 151, 151, 1, 921600, 0x9d8c667f
+0, 152, 152, 1, 921600, 0x9d8c667f
+0, 153, 153, 1, 921600, 0x9b6037ec
+0, 154, 154, 1, 921600, 0x9b6037ec
+0, 155, 155, 1, 921600, 0x57c5e835
+0, 156, 156, 1, 921600, 0x57c5e835
+0, 157, 157, 1, 921600, 0x57c5e835
+0, 158, 158, 1, 921600, 0x476dad89
+0, 159, 159, 1, 921600, 0x476dad89
+0, 160, 160, 1, 921600, 0xcfd6ad2b
+0, 161, 161, 1, 921600, 0xcfd6ad2b
+0, 162, 162, 1, 921600, 0xcfd6ad2b
+0, 163, 163, 1, 921600, 0x3b372379
+0, 164, 164, 1, 921600, 0x3b372379
+0, 165, 165, 1, 921600, 0x36f245f5
+0, 166, 166, 1, 921600, 0x36f245f5
diff --git a/tests/ref/fate/quickdraw b/tests/ref/fate/quickdraw
index 9a55ad5084..eccb477fb7 100644
--- a/tests/ref/fate/quickdraw
+++ b/tests/ref/fate/quickdraw
@@ -1,3 +1,3 @@
-#tb 0: 1/600
+#tb 0: 1/15
0, 0, 0, 1, 921600, 0xc0e68764
-0, 80, 80, 1, 921600, 0x01a16629
+0, 2, 2, 1, 921600, 0x01a16629
diff --git a/tests/ref/fate/random_seed b/tests/ref/fate/random_seed
new file mode 100644
index 0000000000..2b5b3afe72
--- /dev/null
+++ b/tests/ref/fate/random_seed
@@ -0,0 +1 @@
+seeds OK
diff --git a/tests/ref/fate/redcode-demux b/tests/ref/fate/redcode-demux
index 34a2924b94..a7e28380e8 100644
--- a/tests/ref/fate/redcode-demux
+++ b/tests/ref/fate/redcode-demux
@@ -4,4 +4,4 @@
1, 0, 0, 18140, 14816, 0xd185e8c7
0, 10010, 10010, 10010, 1626092, 0x070bd882
1, 18140, 18140, 40920, 32736, 0x791b737a
-0, 20020, 20020, 10010, 893932, 0x8c7cd0a6
+0, 20020, 20020, 10010, 893932, 0x8c7cd0a6, F=0x3
diff --git a/tests/ref/fate/redspark-demux b/tests/ref/fate/redspark-demux
new file mode 100644
index 0000000000..fadfe933ed
--- /dev/null
+++ b/tests/ref/fate/redspark-demux
@@ -0,0 +1 @@
+CRC=0xc0fd1aa2
diff --git a/tests/ref/fate/ripemd b/tests/ref/fate/ripemd
new file mode 100644
index 0000000000..947412de42
--- /dev/null
+++ b/tests/ref/fate/ripemd
@@ -0,0 +1,28 @@
+Testing RIPEMD-128
+C14A12199C66E4BA84636B0F69144C77
+A1AA0689D0FAFA2DDC22E88B49133A06
+4A7F5723F954EBA1216C9D8F6320431F
+c14a1219 9c66e4ba 84636b0f 69144c77
+a1aa0689 d0fafa2d dc22e88b 49133a06
+4a7f5723 f954eba1 216c9d8f 6320431f
+Testing RIPEMD-160
+8EB208F7E05D987A9B044A8E98C6B087F15A0BFC
+12A053384A9C0C88E405A06C27DCF49ADA62EB2B
+52783243C1697BDBE16D37F97F68F08325DC1528
+8eb208f7 e05d987a 9b044a8e 98c6b087 f15a0bfc
+12a05338 4a9c0c88 e405a06c 27dcf49a da62eb2b
+52783243 c1697bdb e16d37f9 7f68f083 25dc1528
+Testing RIPEMD-256
+AFBD6E228B9D8CBBCEF5CA2D03E6DBA10AC0BC7DCBE4680E1E42D2E975459B65
+3843045583AAC6C8C8D9128573E7A9809AFB2A0F34CCC36EA9E72F16F6368E3F
+AC953744E10E31514C150D4D8D7B677342E33399788296E43AE4850CE4F97978
+afbd6e22 8b9d8cbb cef5ca2d 03e6dba1 0ac0bc7d cbe4680e 1e42d2e9 75459b65
+38430455 83aac6c8 c8d91285 73e7a980 9afb2a0f 34ccc36e a9e72f16 f6368e3f
+ac953744 e10e3151 4c150d4d 8d7b6773 42e33399 788296e4 3ae4850c e4f97978
+Testing RIPEMD-320
+DE4C01B3054F8930A79D09AE738E92301E5A17085BEFFDC1B8D116713E74F82FA942D64CDBC4682D
+D034A7950CF722021BA4B84DF769A5DE2060E259DF4C9BB4A4268C0E935BBC7470A969C9D072A1AC
+BDEE37F4371E20646B8B0D862DDA16292AE36F40965E8C8509E63D1DBDDECC503E2B63EB9245BB66
+de4c01b3 054f8930 a79d09ae 738e9230 1e5a1708 5beffdc1 b8d11671 3e74f82f a942d64c dbc4682d
+d034a795 0cf72202 1ba4b84d f769a5de 2060e259 df4c9bb4 a4268c0e 935bbc74 70a969c9 d072a1ac
+bdee37f4 371e2064 6b8b0d86 2dda1629 2ae36f40 965e8c85 09e63d1d bddecc50 3e2b63eb 9245bb66
diff --git a/tests/ref/fate/rpza b/tests/ref/fate/rpza
index a1c5333069..a9ae3bbadb 100644
--- a/tests/ref/fate/rpza
+++ b/tests/ref/fate/rpza
@@ -1,31 +1,31 @@
-#tb 0: 1/600
-0, 0, 0, 1, 230400, 0x4aec80a3
-0, 40, 40, 1, 230400, 0xb6c41452
-0, 80, 80, 1, 230400, 0xa6c27f12
-0, 120, 120, 1, 230400, 0x309bd2d2
-0, 160, 160, 1, 230400, 0x597a7341
-0, 200, 200, 1, 230400, 0x597a7341
-0, 240, 240, 1, 230400, 0xd6d6c569
-0, 280, 280, 1, 230400, 0x31413d89
-0, 320, 320, 1, 230400, 0x464e42e9
-0, 360, 360, 1, 230400, 0x502d7c71
-0, 400, 400, 1, 230400, 0x502d7c71
-0, 440, 440, 1, 230400, 0xc96f23d1
-0, 480, 480, 1, 230400, 0xc96f23d1
-0, 520, 520, 1, 230400, 0x5bfd2bc7
-0, 560, 560, 1, 230400, 0x821640a7
-0, 600, 600, 1, 230400, 0x8f001967
-0, 640, 640, 1, 230400, 0x406ba109
-0, 680, 680, 1, 230400, 0x85d99b50
-0, 720, 720, 1, 230400, 0x2fdb4018
-0, 760, 760, 1, 230400, 0xfa127259
-0, 800, 800, 1, 230400, 0xe6427b9b
-0, 840, 840, 1, 230400, 0xe6427b9b
-0, 880, 880, 1, 230400, 0x3a279000
-0, 920, 920, 1, 230400, 0x710755ee
-0, 960, 960, 1, 230400, 0x76549d35
-0, 1000, 1000, 1, 230400, 0xf4d0132c
-0, 1040, 1040, 1, 230400, 0xf4d0132c
-0, 1080, 1080, 1, 230400, 0x19d7ec14
-0, 1120, 1120, 1, 230400, 0x19d7ec14
-0, 1160, 1160, 1, 230400, 0x5f24b7e1
+#tb 0: 1/15
+0, 0, 0, 1, 230400, 0x26a4728c
+0, 1, 1, 1, 230400, 0xa5ff0a21
+0, 2, 2, 1, 230400, 0x479d767d
+0, 3, 3, 1, 230400, 0xc619cd01
+0, 4, 4, 1, 230400, 0x1d377157
+0, 5, 5, 1, 230400, 0x1d377157
+0, 6, 6, 1, 230400, 0x0941c629
+0, 7, 7, 1, 230400, 0xe64b3a93
+0, 8, 8, 1, 230400, 0x28493fd7
+0, 9, 9, 1, 230400, 0x18c77af2
+0, 10, 10, 1, 230400, 0x18c77af2
+0, 11, 11, 1, 230400, 0x5a542008
+0, 12, 12, 1, 230400, 0x5a542008
+0, 13, 13, 1, 230400, 0x3b1a34fd
+0, 14, 14, 1, 230400, 0x77d34944
+0, 15, 15, 1, 230400, 0x50ac218c
+0, 16, 16, 1, 230400, 0xcb999f16
+0, 17, 17, 1, 230400, 0xe1ce9f19
+0, 18, 18, 1, 230400, 0xb10b4264
+0, 19, 19, 1, 230400, 0x61207031
+0, 20, 20, 1, 230400, 0x81626d5b
+0, 21, 21, 1, 230400, 0x81626d5b
+0, 22, 22, 1, 230400, 0x1cb59751
+0, 23, 23, 1, 230400, 0x316e6962
+0, 24, 24, 1, 230400, 0x4c01b829
+0, 25, 25, 1, 230400, 0x276e32bc
+0, 26, 26, 1, 230400, 0x276e32bc
+0, 27, 27, 1, 230400, 0xe251117a
+0, 28, 28, 1, 230400, 0xe251117a
+0, 29, 29, 1, 230400, 0x41b7f098
diff --git a/tests/ref/fate/rsd-demux b/tests/ref/fate/rsd-demux
new file mode 100644
index 0000000000..3aa2573f78
--- /dev/null
+++ b/tests/ref/fate/rsd-demux
@@ -0,0 +1 @@
+CRC=0x7b7807d8
diff --git a/tests/ref/fate/rv30 b/tests/ref/fate/rv30
index 89a9d8c978..70db647985 100644
--- a/tests/ref/fate/rv30
+++ b/tests/ref/fate/rv30
@@ -1,110 +1,110 @@
-#tb 0: 1/1000
-0, 1, 1, 0, 126720, 0xcefaec47
-0, 33, 33, 0, 126720, 0xa416ece5
-0, 66, 66, 0, 126720, 0xa416ece5
-0, 100, 100, 0, 126720, 0xa416ece5
-0, 133, 133, 0, 126720, 0x60d6ed27
-0, 166, 166, 0, 126720, 0x259af497
-0, 200, 200, 0, 126720, 0x5e6ff4d7
-0, 233, 233, 0, 126720, 0xcc10f4b7
-0, 266, 266, 0, 126720, 0x763ab817
-0, 300, 300, 0, 126720, 0xe95fb8d7
-0, 333, 333, 0, 126720, 0xe2b1b917
-0, 367, 367, 0, 126720, 0x11abb8f7
-0, 400, 400, 0, 126720, 0x4b62b947
-0, 433, 433, 0, 126720, 0xcaf2bbb7
-0, 467, 467, 0, 126720, 0x2953bc37
-0, 500, 500, 0, 126720, 0x1dd9bbd7
-0, 533, 533, 0, 126720, 0x105eb927
-0, 567, 567, 0, 126720, 0x7fa3ae27
-0, 600, 600, 0, 126720, 0x722e99f7
-0, 633, 633, 0, 126720, 0x5ac9a827
-0, 667, 667, 0, 126720, 0x07beba77
-0, 700, 700, 0, 126720, 0x29d6a887
-0, 734, 734, 0, 126720, 0xa5caab87
-0, 767, 767, 0, 126720, 0x9ca7aac7
-0, 800, 800, 0, 126720, 0xb7debcd7
-0, 834, 834, 0, 126720, 0xd115a757
-0, 867, 867, 0, 126720, 0x6ddaef32
-0, 900, 900, 0, 126720, 0xde1bb900
-0, 934, 934, 0, 126720, 0xac6c071b
-0, 967, 967, 0, 126720, 0x4a9f897c
-0, 1000, 1000, 0, 126720, 0xd8fa050f
-0, 1034, 1034, 0, 126720, 0x5d06be59
-0, 1067, 1067, 0, 126720, 0xdc3e0837
-0, 1101, 1101, 0, 126720, 0xcac6da2b
-0, 1134, 1134, 0, 126720, 0x6672dfc9
-0, 1167, 1167, 0, 126720, 0x7491b176
-0, 1201, 1201, 0, 126720, 0xa9477df0
-0, 1234, 1234, 0, 126720, 0xe976c34f
-0, 1267, 1267, 0, 126720, 0xdb7ab0e2
-0, 1301, 1301, 0, 126720, 0x1b42db35
-0, 1334, 1334, 0, 126720, 0xc6e10f9f
-0, 1368, 1368, 0, 126720, 0x169d61b6
-0, 1401, 1401, 0, 126720, 0xc7623119
-0, 1434, 1434, 0, 126720, 0x5b9b7543
-0, 1468, 1468, 0, 126720, 0x68c27aca
-0, 1501, 1501, 0, 126720, 0xa0e4e1c9
-0, 1534, 1534, 0, 126720, 0xbbdae87e
-0, 1568, 1568, 0, 126720, 0xe67e00a1
-0, 1601, 1601, 0, 126720, 0x648ea605
-0, 1634, 1634, 0, 126720, 0x5becb718
-0, 1668, 1668, 0, 126720, 0xb79ab1da
-0, 1701, 1701, 0, 126720, 0x0d52d1dc
-0, 1735, 1735, 0, 126720, 0x1277b853
-0, 1768, 1768, 0, 126720, 0xc57cbc83
-0, 1801, 1801, 0, 126720, 0x2126bdc3
-0, 1835, 1835, 0, 126720, 0x4c1ef41f
-0, 1868, 1868, 0, 126720, 0x185f6a2c
-0, 1901, 1901, 0, 126720, 0xb2b5a7d3
-0, 1935, 1935, 0, 126720, 0x32d7a26d
-0, 1968, 1968, 0, 126720, 0x0bffd118
-0, 2001, 2001, 0, 126720, 0x2eed823a
-0, 2035, 2035, 0, 126720, 0xc4c0147c
-0, 2068, 2068, 0, 126720, 0x1f8bf8ac
-0, 2102, 2102, 0, 126720, 0xfcb715e8
-0, 2135, 2135, 0, 126720, 0xc3e9fa9c
-0, 2168, 2168, 0, 126720, 0x9ad8572c
-0, 2202, 2202, 0, 126720, 0x2800596d
-0, 2235, 2235, 0, 126720, 0x3caa5094
-0, 2268, 2268, 0, 126720, 0x6162e000
-0, 2302, 2302, 0, 126720, 0x18200f2c
-0, 2335, 2335, 0, 126720, 0x649e699f
-0, 2369, 2369, 0, 126720, 0x5f513367
-0, 2402, 2402, 0, 126720, 0x71fbf4a8
-0, 2435, 2435, 0, 126720, 0x5bff7b97
-0, 2469, 2469, 0, 126720, 0xbad453d4
-0, 2502, 2502, 0, 126720, 0x56e6161d
-0, 2535, 2535, 0, 126720, 0x524f2980
-0, 2569, 2569, 0, 126720, 0x0589405a
-0, 2602, 2602, 0, 126720, 0x5c264043
-0, 2635, 2635, 0, 126720, 0x2394696f
-0, 2669, 2669, 0, 126720, 0x1aa0cd15
-0, 2702, 2702, 0, 126720, 0xd6ec7840
-0, 2736, 2736, 0, 126720, 0xde5531f0
-0, 2769, 2769, 0, 126720, 0x03a42c3a
-0, 2802, 2802, 0, 126720, 0xbdee0efb
-0, 2836, 2836, 0, 126720, 0xa6012736
-0, 2869, 2869, 0, 126720, 0x448f5ae6
-0, 2902, 2902, 0, 126720, 0x8a2550c3
-0, 2936, 2936, 0, 126720, 0x143104e7
-0, 2969, 2969, 0, 126720, 0x75db363d
-0, 3002, 3002, 0, 126720, 0x906d2f9d
-0, 3036, 3036, 0, 126720, 0xfc7b30ab
-0, 3069, 3069, 0, 126720, 0xd3edaa62
-0, 3103, 3103, 0, 126720, 0x6267f3fc
-0, 3136, 3136, 0, 126720, 0x87b6c67f
-0, 3169, 3169, 0, 126720, 0x84da3b79
-0, 3203, 3203, 0, 126720, 0x72fbae15
-0, 3236, 3236, 0, 126720, 0xb8474a80
-0, 3269, 3269, 0, 126720, 0xbeae088b
-0, 3303, 3303, 0, 126720, 0x538b1a14
-0, 3336, 3336, 0, 126720, 0x07bbddcd
-0, 3370, 3370, 0, 126720, 0x807ddf8f
-0, 3403, 3403, 0, 126720, 0x325bb46d
-0, 3436, 3436, 0, 126720, 0xd80c2f2a
-0, 3470, 3470, 0, 126720, 0xfc1b0dec
-0, 3503, 3503, 0, 126720, 0x46068ebc
-0, 3536, 3536, 0, 126720, 0xcd987941
-0, 3570, 3570, 0, 126720, 0x52f37f2e
-0, 3603, 3603, 0, 126720, 0xc96931a2
+#tb 0: 32768/982057
+0, 0, 0, 1, 126720, 0xcefaec47
+0, 1, 1, 1, 126720, 0xa416ece5
+0, 2, 2, 1, 126720, 0xa416ece5
+0, 3, 3, 1, 126720, 0xa416ece5
+0, 4, 4, 1, 126720, 0x60d6ed27
+0, 5, 5, 1, 126720, 0x259af497
+0, 6, 6, 1, 126720, 0x5e6ff4d7
+0, 7, 7, 1, 126720, 0xcc10f4b7
+0, 8, 8, 1, 126720, 0x763ab817
+0, 9, 9, 1, 126720, 0xe95fb8d7
+0, 10, 10, 1, 126720, 0xe2b1b917
+0, 11, 11, 1, 126720, 0x11abb8f7
+0, 12, 12, 1, 126720, 0x4b62b947
+0, 13, 13, 1, 126720, 0xcaf2bbb7
+0, 14, 14, 1, 126720, 0x2953bc37
+0, 15, 15, 1, 126720, 0x1dd9bbd7
+0, 16, 16, 1, 126720, 0x105eb927
+0, 17, 17, 1, 126720, 0x7fa3ae27
+0, 18, 18, 1, 126720, 0x722e99f7
+0, 19, 19, 1, 126720, 0x5ac9a827
+0, 20, 20, 1, 126720, 0x07beba77
+0, 21, 21, 1, 126720, 0x29d6a887
+0, 22, 22, 1, 126720, 0xa5caab87
+0, 23, 23, 1, 126720, 0x9ca7aac7
+0, 24, 24, 1, 126720, 0xb7debcd7
+0, 25, 25, 1, 126720, 0xd115a757
+0, 26, 26, 1, 126720, 0x6ddaef32
+0, 27, 27, 1, 126720, 0xde1bb900
+0, 28, 28, 1, 126720, 0xac6c071b
+0, 29, 29, 1, 126720, 0x4a9f897c
+0, 30, 30, 1, 126720, 0xd8fa050f
+0, 31, 31, 1, 126720, 0x5d06be59
+0, 32, 32, 1, 126720, 0xdc3e0837
+0, 33, 33, 1, 126720, 0xcac6da2b
+0, 34, 34, 1, 126720, 0x6672dfc9
+0, 35, 35, 1, 126720, 0x7491b176
+0, 36, 36, 1, 126720, 0xa9477df0
+0, 37, 37, 1, 126720, 0xe976c34f
+0, 38, 38, 1, 126720, 0xdb7ab0e2
+0, 39, 39, 1, 126720, 0x1b42db35
+0, 40, 40, 1, 126720, 0xc6e10f9f
+0, 41, 41, 1, 126720, 0x169d61b6
+0, 42, 42, 1, 126720, 0xc7623119
+0, 43, 43, 1, 126720, 0x5b9b7543
+0, 44, 44, 1, 126720, 0x68c27aca
+0, 45, 45, 1, 126720, 0xa0e4e1c9
+0, 46, 46, 1, 126720, 0xbbdae87e
+0, 47, 47, 1, 126720, 0xe67e00a1
+0, 48, 48, 1, 126720, 0x648ea605
+0, 49, 49, 1, 126720, 0x5becb718
+0, 50, 50, 1, 126720, 0xb79ab1da
+0, 51, 51, 1, 126720, 0x0d52d1dc
+0, 52, 52, 1, 126720, 0x1277b853
+0, 53, 53, 1, 126720, 0xc57cbc83
+0, 54, 54, 1, 126720, 0x2126bdc3
+0, 55, 55, 1, 126720, 0x4c1ef41f
+0, 56, 56, 1, 126720, 0x185f6a2c
+0, 57, 57, 1, 126720, 0xb2b5a7d3
+0, 58, 58, 1, 126720, 0x32d7a26d
+0, 59, 59, 1, 126720, 0x0bffd118
+0, 60, 60, 1, 126720, 0x2eed823a
+0, 61, 61, 1, 126720, 0xc4c0147c
+0, 62, 62, 1, 126720, 0x1f8bf8ac
+0, 63, 63, 1, 126720, 0xfcb715e8
+0, 64, 64, 1, 126720, 0xc3e9fa9c
+0, 65, 65, 1, 126720, 0x9ad8572c
+0, 66, 66, 1, 126720, 0x2800596d
+0, 67, 67, 1, 126720, 0x3caa5094
+0, 68, 68, 1, 126720, 0x6162e000
+0, 69, 69, 1, 126720, 0x18200f2c
+0, 70, 70, 1, 126720, 0x649e699f
+0, 71, 71, 1, 126720, 0x5f513367
+0, 72, 72, 1, 126720, 0x71fbf4a8
+0, 73, 73, 1, 126720, 0x5bff7b97
+0, 74, 74, 1, 126720, 0xbad453d4
+0, 75, 75, 1, 126720, 0x56e6161d
+0, 76, 76, 1, 126720, 0x524f2980
+0, 77, 77, 1, 126720, 0x0589405a
+0, 78, 78, 1, 126720, 0x5c264043
+0, 79, 79, 1, 126720, 0x2394696f
+0, 80, 80, 1, 126720, 0x1aa0cd15
+0, 81, 81, 1, 126720, 0xd6ec7840
+0, 82, 82, 1, 126720, 0xde5531f0
+0, 83, 83, 1, 126720, 0x03a42c3a
+0, 84, 84, 1, 126720, 0xbdee0efb
+0, 85, 85, 1, 126720, 0xa6012736
+0, 86, 86, 1, 126720, 0x448f5ae6
+0, 87, 87, 1, 126720, 0x8a2550c3
+0, 88, 88, 1, 126720, 0x143104e7
+0, 89, 89, 1, 126720, 0x75db363d
+0, 90, 90, 1, 126720, 0x906d2f9d
+0, 91, 91, 1, 126720, 0xfc7b30ab
+0, 92, 92, 1, 126720, 0xd3edaa62
+0, 93, 93, 1, 126720, 0x6267f3fc
+0, 94, 94, 1, 126720, 0x87b6c67f
+0, 95, 95, 1, 126720, 0x84da3b79
+0, 96, 96, 1, 126720, 0x72fbae15
+0, 97, 97, 1, 126720, 0xb8474a80
+0, 98, 98, 1, 126720, 0xbeae088b
+0, 99, 99, 1, 126720, 0x538b1a14
+0, 100, 100, 1, 126720, 0x07bbddcd
+0, 101, 101, 1, 126720, 0x807ddf8f
+0, 102, 102, 1, 126720, 0x325bb46d
+0, 103, 103, 1, 126720, 0xd80c2f2a
+0, 104, 104, 1, 126720, 0xfc1b0dec
+0, 105, 105, 1, 126720, 0x46068ebc
+0, 106, 106, 1, 126720, 0xcd987941
+0, 107, 107, 1, 126720, 0x52f37f2e
+0, 108, 108, 1, 126720, 0xc96931a2
diff --git a/tests/ref/fate/rv40 b/tests/ref/fate/rv40
index d5cb265a00..6159859cad 100644
--- a/tests/ref/fate/rv40
+++ b/tests/ref/fate/rv40
@@ -1,240 +1,241 @@
-#tb 0: 1/1000
-0, -41, -41, 0, 276480, 0x5f7a0d4f
-0, 42, 42, 0, 276480, 0x5f7a0d4f
-0, 83, 83, 0, 276480, 0x5f7a0d4f
-0, 125, 125, 0, 276480, 0x5f7a0d4f
-0, 167, 167, 0, 276480, 0x5f7a0d4f
-0, 209, 209, 0, 276480, 0x5f7a0d4f
-0, 250, 250, 0, 276480, 0x5f7a0d4f
-0, 292, 292, 0, 276480, 0x5f7a0d4f
-0, 334, 334, 0, 276480, 0x5f7a0d4f
-0, 375, 375, 0, 276480, 0x5f7a0d4f
-0, 417, 417, 0, 276480, 0x5f7a0d4f
-0, 459, 459, 0, 276480, 0x5f7a0d4f
-0, 501, 501, 0, 276480, 0x5f7a0d4f
-0, 542, 542, 0, 276480, 0x5f7a0d4f
-0, 584, 584, 0, 276480, 0x5f7a0d4f
-0, 626, 626, 0, 276480, 0x5f7a0d4f
-0, 667, 667, 0, 276480, 0x5f7a0d4f
-0, 709, 709, 0, 276480, 0x5f7a0d4f
-0, 751, 751, 0, 276480, 0x5f7a0d4f
-0, 792, 792, 0, 276480, 0x5f7a0d4f
-0, 834, 834, 0, 276480, 0x5f7a0d4f
-0, 876, 876, 0, 276480, 0x5f7a0d4f
-0, 918, 918, 0, 276480, 0x5f7a0d4f
-0, 959, 959, 0, 276480, 0x5f7a0d4f
-0, 1001, 1001, 0, 276480, 0x5f7a0d4f
-0, 1043, 1043, 0, 276480, 0x5f7a0d4f
-0, 1084, 1084, 0, 276480, 0x5f7a0d4f
-0, 1126, 1126, 0, 276480, 0x5f7a0d4f
-0, 1168, 1168, 0, 276480, 0x5f7a0d4f
-0, 1210, 1210, 0, 276480, 0x5f7a0d4f
-0, 1251, 1251, 0, 276480, 0x5f7a0d4f
-0, 1293, 1293, 0, 276480, 0x5f7a0d4f
-0, 1335, 1335, 0, 276480, 0x5f7a0d4f
-0, 1376, 1376, 0, 276480, 0x75641594
-0, 1418, 1418, 0, 276480, 0x32ee3526
-0, 1460, 1460, 0, 276480, 0xcb53479a
-0, 1502, 1502, 0, 276480, 0x7ca9658e
-0, 1543, 1543, 0, 276480, 0x5ce39368
-0, 1585, 1585, 0, 276480, 0x4ec1e418
-0, 1627, 1627, 0, 276480, 0xb3790499
-0, 1668, 1668, 0, 276480, 0xa9f1506f
-0, 1710, 1710, 0, 276480, 0x85cbc3b5
-0, 1752, 1752, 0, 276480, 0x377c7b46
-0, 1793, 1793, 0, 276480, 0x1a61d8db
-0, 1835, 1835, 0, 276480, 0xe1de7f0a
-0, 1877, 1877, 0, 276480, 0x756a4a2e
-0, 1919, 1919, 0, 276480, 0xcb379547
-0, 1960, 1960, 0, 276480, 0xbae14484
-0, 2002, 2002, 0, 276480, 0x8e12331c
-0, 2044, 2044, 0, 276480, 0x99c085be
-0, 2085, 2085, 0, 276480, 0xe479ffed
-0, 2127, 2127, 0, 276480, 0x99c82949
-0, 2169, 2169, 0, 276480, 0xac7672dd
-0, 2211, 2211, 0, 276480, 0x1e4fae19
-0, 2252, 2252, 0, 276480, 0x776412ef
-0, 2294, 2294, 0, 276480, 0x7d9b579f
-0, 2336, 2336, 0, 276480, 0x1cd1ab29
-0, 2377, 2377, 0, 276480, 0x58ce0f38
-0, 2419, 2419, 0, 276480, 0x5ab69b27
-0, 2461, 2461, 0, 276480, 0x0afad610
-0, 2503, 2503, 0, 276480, 0x9eca3f11
-0, 2544, 2544, 0, 276480, 0xc3db9706
-0, 2586, 2586, 0, 276480, 0xc9c57884
-0, 2628, 2628, 0, 276480, 0xd9fbb2cf
-0, 2669, 2669, 0, 276480, 0xdc07f3c9
-0, 2711, 2711, 0, 276480, 0x000b5269
-0, 2753, 2753, 0, 276480, 0x27ff7a5d
-0, 2794, 2794, 0, 276480, 0xd92e2017
-0, 2836, 2836, 0, 276480, 0x18d4b27d
-0, 2878, 2878, 0, 276480, 0x70647530
-0, 2920, 2920, 0, 276480, 0x97612c4b
-0, 2961, 2961, 0, 276480, 0xc9d4ac78
-0, 3003, 3003, 0, 276480, 0x4ec4d57f
-0, 3045, 3045, 0, 276480, 0xdf4e04d7
-0, 3086, 3086, 0, 276480, 0xbd98f57c
-0, 3128, 3128, 0, 276480, 0x7247ea3e
-0, 3170, 3170, 0, 276480, 0xa5d670ec
-0, 3212, 3212, 0, 276480, 0x5163b29b
-0, 3253, 3253, 0, 276480, 0x99170e64
-0, 3295, 3295, 0, 276480, 0x37f4c0b0
-0, 3337, 3337, 0, 276480, 0x7a4f2561
-0, 3378, 3378, 0, 276480, 0x8a4e991f
-0, 3420, 3420, 0, 276480, 0x6a45425f
-0, 3462, 3462, 0, 276480, 0x1f0e2bb6
-0, 3504, 3504, 0, 276480, 0xd75482c6
-0, 3545, 3545, 0, 276480, 0x7bf6b1ef
-0, 3587, 3587, 0, 276480, 0x6de1e34b
-0, 3629, 3629, 0, 276480, 0x4526c89b
-0, 3670, 3670, 0, 276480, 0xf964e18e
-0, 3712, 3712, 0, 276480, 0xdcaaa99a
-0, 3754, 3754, 0, 276480, 0xd1e98808
-0, 3795, 3795, 0, 276480, 0x556b2365
-0, 3837, 3837, 0, 276480, 0x0cf65540
-0, 3879, 3879, 0, 276480, 0x6e2d524e
-0, 3921, 3921, 0, 276480, 0x22c50a3d
-0, 3962, 3962, 0, 276480, 0x293f19af
-0, 4004, 4004, 0, 276480, 0xf4b1c461
-0, 4046, 4046, 0, 276480, 0x62b76407
-0, 4087, 4087, 0, 276480, 0x51e9b3eb
-0, 4129, 4129, 0, 276480, 0x7b910bc7
-0, 4171, 4171, 0, 276480, 0x6dd14ca6
-0, 4213, 4213, 0, 276480, 0x441f7afd
-0, 4254, 4254, 0, 276480, 0xfb01efc6
-0, 4296, 4296, 0, 276480, 0x4f73ccea
-0, 4338, 4338, 0, 276480, 0x5ac8e06f
-0, 4379, 4379, 0, 276480, 0x294bb441
-0, 4421, 4421, 0, 276480, 0xe04ac45e
-0, 4463, 4463, 0, 276480, 0xa7a38d41
-0, 4505, 4505, 0, 276480, 0xf688a3ed
-0, 4546, 4546, 0, 276480, 0x58f275ea
-0, 4588, 4588, 0, 276480, 0xf0b3b71b
-0, 4630, 4630, 0, 276480, 0x3ce773bf
-0, 4671, 4671, 0, 276480, 0x01840548
-0, 4713, 4713, 0, 276480, 0x674e34e4
-0, 4755, 4755, 0, 276480, 0x41dda2d9
-0, 4796, 4796, 0, 276480, 0xc5b60838
-0, 4838, 4838, 0, 276480, 0x9b209f41
-0, 4880, 4880, 0, 276480, 0xf46ba7fb
-0, 4922, 4922, 0, 276480, 0x28b54815
-0, 4963, 4963, 0, 276480, 0xb605a933
-0, 5005, 5005, 0, 276480, 0x34484aff
-0, 5047, 5047, 0, 276480, 0xaf2b5d89
-0, 5088, 5088, 0, 276480, 0x8facba58
-0, 5130, 5130, 0, 276480, 0xbbe3e99f
-0, 5172, 5172, 0, 276480, 0x02162c7c
-0, 5214, 5214, 0, 276480, 0x28a63236
-0, 5255, 5255, 0, 276480, 0x1ad43fd7
-0, 5297, 5297, 0, 276480, 0xe37883e5
-0, 5339, 5339, 0, 276480, 0x2b8a89c5
-0, 5380, 5380, 0, 276480, 0x71507bd2
-0, 5422, 5422, 0, 276480, 0x35626022
-0, 5464, 5464, 0, 276480, 0x461fc3e7
-0, 5506, 5506, 0, 276480, 0xce5af1ec
-0, 5547, 5547, 0, 276480, 0x7c1139b3
-0, 5589, 5589, 0, 276480, 0x7fd73a99
-0, 5631, 5631, 0, 276480, 0x4ae4c3a6
-0, 5672, 5672, 0, 276480, 0xcb60725a
-0, 5714, 5714, 0, 276480, 0xb52e1aa2
-0, 5756, 5756, 0, 276480, 0xd6f82cae
-0, 5797, 5797, 0, 276480, 0x6310e665
-0, 5839, 5839, 0, 276480, 0xfa88a483
-0, 5881, 5881, 0, 276480, 0xf88f75d4
-0, 5923, 5923, 0, 276480, 0x04a8e3ee
-0, 5964, 5964, 0, 276480, 0x54766a12
-0, 6006, 6006, 0, 276480, 0x0b41f0d7
-0, 6048, 6048, 0, 276480, 0xa29f5b01
-0, 6089, 6089, 0, 276480, 0x754ceaf5
-0, 6131, 6131, 0, 276480, 0x150c0423
-0, 6173, 6173, 0, 276480, 0xde084059
-0, 6215, 6215, 0, 276480, 0x5a38b4af
-0, 6256, 6256, 0, 276480, 0xfcebc261
-0, 6298, 6298, 0, 276480, 0x0eb9770d
-0, 6340, 6340, 0, 276480, 0x046394ae
-0, 6381, 6381, 0, 276480, 0x3d3ca985
-0, 6423, 6423, 0, 276480, 0x94a03c75
-0, 6465, 6465, 0, 276480, 0x800eea2d
-0, 6507, 6507, 0, 276480, 0x6a841f41
-0, 6548, 6548, 0, 276480, 0x2f98911c
-0, 6590, 6590, 0, 276480, 0x923b9937
-0, 6632, 6632, 0, 276480, 0xe82f8e0f
-0, 6673, 6673, 0, 276480, 0xee82d657
-0, 6715, 6715, 0, 276480, 0xefab7ffd
-0, 6757, 6757, 0, 276480, 0x6b9fbc80
-0, 6798, 6798, 0, 276480, 0x4a1ada47
-0, 6840, 6840, 0, 276480, 0x6d4b49d7
-0, 6882, 6882, 0, 276480, 0xe4bdbd1e
-0, 6924, 6924, 0, 276480, 0x225a56c0
-0, 6965, 6965, 0, 276480, 0xd4adadad
-0, 7007, 7007, 0, 276480, 0xff4e1a8c
-0, 7049, 7049, 0, 276480, 0xf58b1b7c
-0, 7090, 7090, 0, 276480, 0xbaffcdcc
-0, 7132, 7132, 0, 276480, 0x374f88f0
-0, 7174, 7174, 0, 276480, 0x3d861ae6
-0, 7216, 7216, 0, 276480, 0xeb6eb88f
-0, 7257, 7257, 0, 276480, 0xdb753d35
-0, 7299, 7299, 0, 276480, 0x9aa543af
-0, 7341, 7341, 0, 276480, 0xb24c8016
-0, 7382, 7382, 0, 276480, 0xea80a82e
-0, 7424, 7424, 0, 276480, 0x2aae902a
-0, 7466, 7466, 0, 276480, 0x5bba3cfb
-0, 7508, 7508, 0, 276480, 0x5c6e97a9
-0, 7549, 7549, 0, 276480, 0x9b9ee961
-0, 7591, 7591, 0, 276480, 0xaa12b6fd
-0, 7633, 7633, 0, 276480, 0xe9d2439f
-0, 7674, 7674, 0, 276480, 0xbf09053c
-0, 7716, 7716, 0, 276480, 0x50c31e73
-0, 7758, 7758, 0, 276480, 0xdd9fb89f
-0, 7799, 7799, 0, 276480, 0x3e4e5aec
-0, 7841, 7841, 0, 276480, 0x0b752d28
-0, 7883, 7883, 0, 276480, 0xaf82399a
-0, 7925, 7925, 0, 276480, 0x7ce5f23c
-0, 7966, 7966, 0, 276480, 0xad135d0f
-0, 8008, 8008, 0, 276480, 0x55dadd30
-0, 8050, 8050, 0, 276480, 0x5aaa7519
-0, 8091, 8091, 0, 276480, 0xe45a5599
-0, 8133, 8133, 0, 276480, 0xc8e89913
-0, 8175, 8175, 0, 276480, 0x2f447fd3
-0, 8217, 8217, 0, 276480, 0x704411fb
-0, 8258, 8258, 0, 276480, 0x9d7430a1
-0, 8300, 8300, 0, 276480, 0x24dd5fd3
-0, 8342, 8342, 0, 276480, 0x51cb657c
-0, 8383, 8383, 0, 276480, 0x2c230702
-0, 8425, 8425, 0, 276480, 0x4a4f76cd
-0, 8467, 8467, 0, 276480, 0xdcd71e88
-0, 8509, 8509, 0, 276480, 0x87160f99
-0, 8550, 8550, 0, 276480, 0x27f54854
-0, 8592, 8592, 0, 276480, 0x694d76e3
-0, 8634, 8634, 0, 276480, 0xcbe93c19
-0, 8675, 8675, 0, 276480, 0x50742e1b
-0, 8717, 8717, 0, 276480, 0x525463e2
-0, 8759, 8759, 0, 276480, 0x819898f9
-0, 8800, 8800, 0, 276480, 0x08fac755
-0, 8842, 8842, 0, 276480, 0x35c46927
-0, 8884, 8884, 0, 276480, 0xeeed00fc
-0, 8926, 8926, 0, 276480, 0xb6f99ee3
-0, 8967, 8967, 0, 276480, 0xd87f4c73
-0, 9009, 9009, 0, 276480, 0xde97d9fd
-0, 9051, 9051, 0, 276480, 0xefc83107
-0, 9092, 9092, 0, 276480, 0xbb22e024
-0, 9134, 9134, 0, 276480, 0x53a7cfcb
-0, 9176, 9176, 0, 276480, 0xbe1fbb19
-0, 9218, 9218, 0, 276480, 0x300f922a
-0, 9259, 9259, 0, 276480, 0x826fc3bd
-0, 9301, 9301, 0, 276480, 0x679aa57a
-0, 9343, 9343, 0, 276480, 0x5497097b
-0, 9384, 9384, 0, 276480, 0x679a53f8
-0, 9426, 9426, 0, 276480, 0x976c9e93
-0, 9468, 9468, 0, 276480, 0xe80f87f2
-0, 9510, 9510, 0, 276480, 0xdc2d7c6c
-0, 9551, 9551, 0, 276480, 0xb194656e
-0, 9593, 9593, 0, 276480, 0xf002c5ca
-0, 9635, 9635, 0, 276480, 0x43fc1c64
-0, 9676, 9676, 0, 276480, 0xf62d8581
-0, 9718, 9718, 0, 276480, 0xb243dda5
-0, 9760, 9760, 0, 276480, 0x1700efbb
-0, 9801, 9801, 0, 276480, 0x9ebe6ba2
-0, 9843, 9843, 0, 276480, 0x8f316c66
-0, 9885, 9885, 0, 276480, 0x6348ecf5
-0, 9927, 9927, 0, 276480, 0x34b5b78a
+#tb 0: 32768/785647
+0, 0, 0, 1, 276480, 0x5f7a0d4f
+0, 1, 1, 1, 276480, 0x5f7a0d4f
+0, 2, 2, 1, 276480, 0x5f7a0d4f
+0, 3, 3, 1, 276480, 0x5f7a0d4f
+0, 4, 4, 1, 276480, 0x5f7a0d4f
+0, 5, 5, 1, 276480, 0x5f7a0d4f
+0, 6, 6, 1, 276480, 0x5f7a0d4f
+0, 7, 7, 1, 276480, 0x5f7a0d4f
+0, 8, 8, 1, 276480, 0x5f7a0d4f
+0, 9, 9, 1, 276480, 0x5f7a0d4f
+0, 10, 10, 1, 276480, 0x5f7a0d4f
+0, 11, 11, 1, 276480, 0x5f7a0d4f
+0, 12, 12, 1, 276480, 0x5f7a0d4f
+0, 13, 13, 1, 276480, 0x5f7a0d4f
+0, 14, 14, 1, 276480, 0x5f7a0d4f
+0, 15, 15, 1, 276480, 0x5f7a0d4f
+0, 16, 16, 1, 276480, 0x5f7a0d4f
+0, 17, 17, 1, 276480, 0x5f7a0d4f
+0, 18, 18, 1, 276480, 0x5f7a0d4f
+0, 19, 19, 1, 276480, 0x5f7a0d4f
+0, 20, 20, 1, 276480, 0x5f7a0d4f
+0, 21, 21, 1, 276480, 0x5f7a0d4f
+0, 22, 22, 1, 276480, 0x5f7a0d4f
+0, 23, 23, 1, 276480, 0x5f7a0d4f
+0, 24, 24, 1, 276480, 0x5f7a0d4f
+0, 25, 25, 1, 276480, 0x5f7a0d4f
+0, 26, 26, 1, 276480, 0x5f7a0d4f
+0, 27, 27, 1, 276480, 0x5f7a0d4f
+0, 28, 28, 1, 276480, 0x5f7a0d4f
+0, 29, 29, 1, 276480, 0x5f7a0d4f
+0, 30, 30, 1, 276480, 0x5f7a0d4f
+0, 31, 31, 1, 276480, 0x5f7a0d4f
+0, 32, 32, 1, 276480, 0x5f7a0d4f
+0, 33, 33, 1, 276480, 0x75641594
+0, 34, 34, 1, 276480, 0x32ee3526
+0, 35, 35, 1, 276480, 0xcb53479a
+0, 36, 36, 1, 276480, 0x7ca9658e
+0, 37, 37, 1, 276480, 0x5ce39368
+0, 38, 38, 1, 276480, 0x4ec1e418
+0, 39, 39, 1, 276480, 0xb3790499
+0, 40, 40, 1, 276480, 0xa9f1506f
+0, 41, 41, 1, 276480, 0x85cbc3b5
+0, 42, 42, 1, 276480, 0x377c7b46
+0, 43, 43, 1, 276480, 0x1a61d8db
+0, 44, 44, 1, 276480, 0xe1de7f0a
+0, 45, 45, 1, 276480, 0x756a4a2e
+0, 46, 46, 1, 276480, 0xcb379547
+0, 47, 47, 1, 276480, 0xbae14484
+0, 48, 48, 1, 276480, 0x8e12331c
+0, 49, 49, 1, 276480, 0x99c085be
+0, 50, 50, 1, 276480, 0xe479ffed
+0, 51, 51, 1, 276480, 0x99c82949
+0, 52, 52, 1, 276480, 0xac7672dd
+0, 53, 53, 1, 276480, 0x1e4fae19
+0, 54, 54, 1, 276480, 0x776412ef
+0, 55, 55, 1, 276480, 0x7d9b579f
+0, 56, 56, 1, 276480, 0x1cd1ab29
+0, 57, 57, 1, 276480, 0x58ce0f38
+0, 58, 58, 1, 276480, 0x5ab69b27
+0, 59, 59, 1, 276480, 0x0afad610
+0, 60, 60, 1, 276480, 0x9eca3f11
+0, 61, 61, 1, 276480, 0xc3db9706
+0, 62, 62, 1, 276480, 0xc9c57884
+0, 63, 63, 1, 276480, 0xd9fbb2cf
+0, 64, 64, 1, 276480, 0xdc07f3c9
+0, 65, 65, 1, 276480, 0x000b5269
+0, 66, 66, 1, 276480, 0x27ff7a5d
+0, 67, 67, 1, 276480, 0xd92e2017
+0, 68, 68, 1, 276480, 0x18d4b27d
+0, 69, 69, 1, 276480, 0x70647530
+0, 70, 70, 1, 276480, 0x97612c4b
+0, 71, 71, 1, 276480, 0xc9d4ac78
+0, 72, 72, 1, 276480, 0x4ec4d57f
+0, 73, 73, 1, 276480, 0xdf4e04d7
+0, 74, 74, 1, 276480, 0xbd98f57c
+0, 75, 75, 1, 276480, 0x7247ea3e
+0, 76, 76, 1, 276480, 0xa5d670ec
+0, 77, 77, 1, 276480, 0x5163b29b
+0, 78, 78, 1, 276480, 0x99170e64
+0, 79, 79, 1, 276480, 0x37f4c0b0
+0, 80, 80, 1, 276480, 0x7a4f2561
+0, 81, 81, 1, 276480, 0x8a4e991f
+0, 82, 82, 1, 276480, 0x6a45425f
+0, 83, 83, 1, 276480, 0x1f0e2bb6
+0, 84, 84, 1, 276480, 0xd75482c6
+0, 85, 85, 1, 276480, 0x7bf6b1ef
+0, 86, 86, 1, 276480, 0x6de1e34b
+0, 87, 87, 1, 276480, 0x4526c89b
+0, 88, 88, 1, 276480, 0xf964e18e
+0, 89, 89, 1, 276480, 0xdcaaa99a
+0, 90, 90, 1, 276480, 0xd1e98808
+0, 91, 91, 1, 276480, 0x556b2365
+0, 92, 92, 1, 276480, 0x0cf65540
+0, 93, 93, 1, 276480, 0x6e2d524e
+0, 94, 94, 1, 276480, 0x22c50a3d
+0, 95, 95, 1, 276480, 0x293f19af
+0, 96, 96, 1, 276480, 0xf4b1c461
+0, 97, 97, 1, 276480, 0x62b76407
+0, 98, 98, 1, 276480, 0x51e9b3eb
+0, 99, 99, 1, 276480, 0x7b910bc7
+0, 100, 100, 1, 276480, 0x6dd14ca6
+0, 101, 101, 1, 276480, 0x441f7afd
+0, 102, 102, 1, 276480, 0xfb01efc6
+0, 103, 103, 1, 276480, 0x4f73ccea
+0, 104, 104, 1, 276480, 0x5ac8e06f
+0, 105, 105, 1, 276480, 0x294bb441
+0, 106, 106, 1, 276480, 0xe04ac45e
+0, 107, 107, 1, 276480, 0xa7a38d41
+0, 108, 108, 1, 276480, 0xf688a3ed
+0, 109, 109, 1, 276480, 0x58f275ea
+0, 110, 110, 1, 276480, 0xf0b3b71b
+0, 111, 111, 1, 276480, 0x3ce773bf
+0, 112, 112, 1, 276480, 0x01840548
+0, 113, 113, 1, 276480, 0x674e34e4
+0, 114, 114, 1, 276480, 0x41dda2d9
+0, 115, 115, 1, 276480, 0xc5b60838
+0, 116, 116, 1, 276480, 0x9b209f41
+0, 117, 117, 1, 276480, 0xf46ba7fb
+0, 118, 118, 1, 276480, 0x28b54815
+0, 119, 119, 1, 276480, 0xb605a933
+0, 120, 120, 1, 276480, 0x34484aff
+0, 121, 121, 1, 276480, 0xaf2b5d89
+0, 122, 122, 1, 276480, 0x8facba58
+0, 123, 123, 1, 276480, 0xbbe3e99f
+0, 124, 124, 1, 276480, 0x02162c7c
+0, 125, 125, 1, 276480, 0x28a63236
+0, 126, 126, 1, 276480, 0x1ad43fd7
+0, 127, 127, 1, 276480, 0xe37883e5
+0, 128, 128, 1, 276480, 0x2b8a89c5
+0, 129, 129, 1, 276480, 0x71507bd2
+0, 130, 130, 1, 276480, 0x35626022
+0, 131, 131, 1, 276480, 0x461fc3e7
+0, 132, 132, 1, 276480, 0xce5af1ec
+0, 133, 133, 1, 276480, 0x7c1139b3
+0, 134, 134, 1, 276480, 0x7fd73a99
+0, 135, 135, 1, 276480, 0x4ae4c3a6
+0, 136, 136, 1, 276480, 0xcb60725a
+0, 137, 137, 1, 276480, 0xb52e1aa2
+0, 138, 138, 1, 276480, 0xd6f82cae
+0, 139, 139, 1, 276480, 0x6310e665
+0, 140, 140, 1, 276480, 0xfa88a483
+0, 141, 141, 1, 276480, 0xf88f75d4
+0, 142, 142, 1, 276480, 0x04a8e3ee
+0, 143, 143, 1, 276480, 0x54766a12
+0, 144, 144, 1, 276480, 0x0b41f0d7
+0, 145, 145, 1, 276480, 0xa29f5b01
+0, 146, 146, 1, 276480, 0x754ceaf5
+0, 147, 147, 1, 276480, 0x150c0423
+0, 148, 148, 1, 276480, 0xde084059
+0, 149, 149, 1, 276480, 0x5a38b4af
+0, 150, 150, 1, 276480, 0xfcebc261
+0, 151, 151, 1, 276480, 0x0eb9770d
+0, 152, 152, 1, 276480, 0x046394ae
+0, 153, 153, 1, 276480, 0x3d3ca985
+0, 154, 154, 1, 276480, 0x94a03c75
+0, 155, 155, 1, 276480, 0x800eea2d
+0, 156, 156, 1, 276480, 0x6a841f41
+0, 157, 157, 1, 276480, 0x2f98911c
+0, 158, 158, 1, 276480, 0x923b9937
+0, 159, 159, 1, 276480, 0xe82f8e0f
+0, 160, 160, 1, 276480, 0xee82d657
+0, 161, 161, 1, 276480, 0xefab7ffd
+0, 162, 162, 1, 276480, 0x6b9fbc80
+0, 163, 163, 1, 276480, 0x4a1ada47
+0, 164, 164, 1, 276480, 0x6d4b49d7
+0, 165, 165, 1, 276480, 0xe4bdbd1e
+0, 166, 166, 1, 276480, 0x225a56c0
+0, 167, 167, 1, 276480, 0xd4adadad
+0, 168, 168, 1, 276480, 0xff4e1a8c
+0, 169, 169, 1, 276480, 0xf58b1b7c
+0, 170, 170, 1, 276480, 0xbaffcdcc
+0, 171, 171, 1, 276480, 0x374f88f0
+0, 172, 172, 1, 276480, 0x3d861ae6
+0, 173, 173, 1, 276480, 0xeb6eb88f
+0, 174, 174, 1, 276480, 0xdb753d35
+0, 175, 175, 1, 276480, 0x9aa543af
+0, 176, 176, 1, 276480, 0xb24c8016
+0, 177, 177, 1, 276480, 0xea80a82e
+0, 178, 178, 1, 276480, 0x2aae902a
+0, 179, 179, 1, 276480, 0x5bba3cfb
+0, 180, 180, 1, 276480, 0x5c6e97a9
+0, 181, 181, 1, 276480, 0x9b9ee961
+0, 182, 182, 1, 276480, 0xaa12b6fd
+0, 183, 183, 1, 276480, 0xe9d2439f
+0, 184, 184, 1, 276480, 0xbf09053c
+0, 185, 185, 1, 276480, 0x50c31e73
+0, 186, 186, 1, 276480, 0xdd9fb89f
+0, 187, 187, 1, 276480, 0x3e4e5aec
+0, 188, 188, 1, 276480, 0x0b752d28
+0, 189, 189, 1, 276480, 0xaf82399a
+0, 190, 190, 1, 276480, 0x7ce5f23c
+0, 191, 191, 1, 276480, 0xad135d0f
+0, 192, 192, 1, 276480, 0x55dadd30
+0, 193, 193, 1, 276480, 0x5aaa7519
+0, 194, 194, 1, 276480, 0xe45a5599
+0, 195, 195, 1, 276480, 0xc8e89913
+0, 196, 196, 1, 276480, 0x2f447fd3
+0, 197, 197, 1, 276480, 0x704411fb
+0, 198, 198, 1, 276480, 0x9d7430a1
+0, 199, 199, 1, 276480, 0x24dd5fd3
+0, 200, 200, 1, 276480, 0x51cb657c
+0, 201, 201, 1, 276480, 0x2c230702
+0, 202, 202, 1, 276480, 0x4a4f76cd
+0, 203, 203, 1, 276480, 0xdcd71e88
+0, 204, 204, 1, 276480, 0x87160f99
+0, 205, 205, 1, 276480, 0x27f54854
+0, 206, 206, 1, 276480, 0x694d76e3
+0, 207, 207, 1, 276480, 0xcbe93c19
+0, 208, 208, 1, 276480, 0x50742e1b
+0, 209, 209, 1, 276480, 0x525463e2
+0, 210, 210, 1, 276480, 0x819898f9
+0, 211, 211, 1, 276480, 0x08fac755
+0, 212, 212, 1, 276480, 0x35c46927
+0, 213, 213, 1, 276480, 0xeeed00fc
+0, 214, 214, 1, 276480, 0xb6f99ee3
+0, 215, 215, 1, 276480, 0xd87f4c73
+0, 216, 216, 1, 276480, 0xde97d9fd
+0, 217, 217, 1, 276480, 0xefc83107
+0, 218, 218, 1, 276480, 0xbb22e024
+0, 219, 219, 1, 276480, 0x53a7cfcb
+0, 220, 220, 1, 276480, 0xbe1fbb19
+0, 221, 221, 1, 276480, 0x300f922a
+0, 222, 222, 1, 276480, 0x826fc3bd
+0, 223, 223, 1, 276480, 0x679aa57a
+0, 224, 224, 1, 276480, 0x5497097b
+0, 225, 225, 1, 276480, 0x679a53f8
+0, 226, 226, 1, 276480, 0x976c9e93
+0, 227, 227, 1, 276480, 0xe80f87f2
+0, 228, 228, 1, 276480, 0xdc2d7c6c
+0, 229, 229, 1, 276480, 0xb194656e
+0, 230, 230, 1, 276480, 0xf002c5ca
+0, 231, 231, 1, 276480, 0x43fc1c64
+0, 232, 232, 1, 276480, 0xf62d8581
+0, 233, 233, 1, 276480, 0xb243dda5
+0, 234, 234, 1, 276480, 0x1700efbb
+0, 235, 235, 1, 276480, 0x9ebe6ba2
+0, 236, 236, 1, 276480, 0x8f316c66
+0, 237, 237, 1, 276480, 0x6348ecf5
+0, 238, 238, 1, 276480, 0x34b5b78a
+0, 239, 239, 1, 276480, 0xcbf66922
diff --git a/tests/ref/fate/sanm b/tests/ref/fate/sanm
index 078d1c280f..a882118b1b 100644
--- a/tests/ref/fate/sanm
+++ b/tests/ref/fate/sanm
@@ -9,8 +9,8 @@
0, 7, 7, 1, 921600, 0x00000000
0, 8, 8, 1, 921600, 0x00000000
0, 9, 9, 1, 921600, 0x00000000
-0, 10, 10, 1, 921600, 0x0870b171
-0, 11, 11, 1, 921600, 0xad557f05
-0, 12, 12, 1, 921600, 0xb06498e0
-0, 13, 13, 1, 921600, 0x156eaccf
-0, 14, 14, 1, 921600, 0x3d48e8e8
+0, 10, 10, 1, 921600, 0x0aa05443
+0, 11, 11, 1, 921600, 0x81d2a7fe
+0, 12, 12, 1, 921600, 0x769f303b
+0, 13, 13, 1, 921600, 0xcd68d0cd
+0, 14, 14, 1, 921600, 0x4cb4894a
diff --git a/tests/ref/fate/sgi-gray b/tests/ref/fate/sgi-gray
index b0e060699c..4d4d3494fa 100644
--- a/tests/ref/fate/sgi-gray
+++ b/tests/ref/fate/sgi-gray
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 131072, 0xb0702a94
+0, 0, 0, 1, 65536, 0xe36c12e1
diff --git a/tests/ref/fate/sgi-gray16 b/tests/ref/fate/sgi-gray16
index 3218edc1b2..f56e53eb37 100644
--- a/tests/ref/fate/sgi-gray16
+++ b/tests/ref/fate/sgi-gray16
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 262144, 0xecdaf084
+0, 0, 0, 1, 131072, 0x6855d247
diff --git a/tests/ref/fate/sgi-rgb24 b/tests/ref/fate/sgi-rgb24
index 30aca1cead..7a6e85537f 100644
--- a/tests/ref/fate/sgi-rgb24
+++ b/tests/ref/fate/sgi-rgb24
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 393216, 0xa9b28fd9
+0, 0, 0, 1, 196608, 0x5b24c51a
diff --git a/tests/ref/fate/sgi-rgb48 b/tests/ref/fate/sgi-rgb48
index 8f3ca50b10..b0521b7fc5 100644
--- a/tests/ref/fate/sgi-rgb48
+++ b/tests/ref/fate/sgi-rgb48
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 786432, 0xee4aa667
+0, 0, 0, 1, 393216, 0xf6b0d73a
diff --git a/tests/ref/fate/sgi-rgba b/tests/ref/fate/sgi-rgba
index 058f5f99c3..9b3d4cb793 100644
--- a/tests/ref/fate/sgi-rgba
+++ b/tests/ref/fate/sgi-rgba
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 524288, 0x4ee5adbb
+0, 0, 0, 1, 262144, 0x7b38d40b
diff --git a/tests/ref/fate/sgi-rgba64 b/tests/ref/fate/sgi-rgba64
index f4e939ec73..94e35afd34 100644
--- a/tests/ref/fate/sgi-rgba64
+++ b/tests/ref/fate/sgi-rgba64
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 1048576, 0xc657e22b
+0, 0, 0, 1, 524288, 0xce70f51c
diff --git a/tests/ref/fate/sha512 b/tests/ref/fate/sha512
new file mode 100644
index 0000000000..6009115350
--- /dev/null
+++ b/tests/ref/fate/sha512
@@ -0,0 +1,28 @@
+Testing SHA-512/224
+4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA
+23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9
+37AB331D76F0D36DE422BD0EDEB22A28ACCD487B7A8453AE965DD287
+4634270f 707b6a54 daae7530 460842e2 0e37ed26 5ceee9a4 3e8924aa
+23fec5bb 94d60b23 30819264 0b0c4533 35d66473 4fe40e72 68674af9
+37ab331d 76f0d36d e422bd0e deb22a28 accd487b 7a8453ae 965dd287
+Testing SHA-512/256
+53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23
+3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A
+9A59A052930187A97038CAE692F30708AA6491923EF5194394DC68D56C74FB21
+53048e26 81941ef9 9b2e29b7 6b4c7dab e4c2d0c6 34fc6d46 e0e2f131 07e7af23
+3928e184 fb8690f8 40da3988 121d31be 65cb9d3e f83ee614 6feac861 e19b563a
+9a59a052 930187a9 7038cae6 92f30708 aa649192 3ef51943 94dc68d5 6c74fb21
+Testing SHA-384
+CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7
+09330C33F71147E83D192FC782CD1B4753111B173B3B05D22FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039
+9D0E1809716474CB086E834E310A4A1CED149E9C00F248527972CEC5704C2A5B07B8B3DC38ECC4EBAE97DDD87F3D8985
+cb00753f 45a35e8b b5a03d69 9ac65007 272c32ab 0eded163 1a8b605a 43ff5bed 8086072b a1e7cc23 58baeca1 34c825a7
+09330c33 f71147e8 3d192fc7 82cd1b47 53111b17 3b3b05d2 2fa08086 e3b0f712 fcc7c71a 557e2db9 66c3e9fa 91746039
+9d0e1809 716474cb 086e834e 310a4a1c ed149e9c 00f24852 7972cec5 704c2a5b 07b8b3dc 38ecc4eb ae97ddd8 7f3d8985
+Testing SHA-512
+DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F
+8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909
+E718483D0CE769644E2E42C7BC15B4638E1F98B13B2044285632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31BEB009C5C2C49AA2E4EADB217AD8CC09B
+ddaf35a1 93617aba cc417349 ae204131 12e6fa4e 89a97ea2 0a9eeee6 4b55d39a 2192992a 274fc1a8 36ba3c23 a3feebbd 454d4423 643ce80e 2a9ac94f a54ca49f
+8e959b75 dae313da 8cf4f728 14fc143f 8f7779c6 eb9f7fa1 7299aead b6889018 501d289e 4900f7e4 331b99de c4b5433a c7d329ee b6dd2654 5e96e55b 874be909
+e718483d 0ce76964 4e2e42c7 bc15b463 8e1f98b1 3b204428 5632a803 afa973eb de0ff244 877ea60a 4cb0432c e577c31b eb009c5c 2c49aa2e 4eadb217 ad8cc09b
diff --git a/tests/ref/fate/sierra-vmd-video b/tests/ref/fate/sierra-vmd-video
index 5b9dde1b32..668faeea56 100644
--- a/tests/ref/fate/sierra-vmd-video
+++ b/tests/ref/fate/sierra-vmd-video
@@ -1,118 +1,118 @@
#tb 0: 1/10
-0, 0, 0, 1, 230400, 0x0224ab01
-0, 1, 1, 1, 230400, 0x449e4d81
-0, 2, 2, 1, 230400, 0x3e15e07a
-0, 3, 3, 1, 230400, 0xdabe4172
-0, 4, 4, 1, 230400, 0x0947b7db
-0, 5, 5, 1, 230400, 0x934e243b
-0, 6, 6, 1, 230400, 0x6b5c5b6c
-0, 7, 7, 1, 230400, 0x4bf7bbb5
-0, 8, 8, 1, 230400, 0x423eec8e
-0, 9, 9, 1, 230400, 0x63663b5e
-0, 10, 10, 1, 230400, 0x9c258a67
-0, 11, 11, 1, 230400, 0x1c92b6e0
-0, 12, 12, 1, 230400, 0xdd0a0e28
-0, 13, 13, 1, 230400, 0x51d64af1
-0, 14, 14, 1, 230400, 0x5776ac12
-0, 15, 15, 1, 230400, 0x49070132
-0, 16, 16, 1, 230400, 0xa59635ab
-0, 17, 17, 1, 230400, 0xb1f99504
-0, 18, 18, 1, 230400, 0x61fac725
-0, 19, 19, 1, 230400, 0xc32c28d5
-0, 20, 20, 1, 230400, 0x2b7a91d6
-0, 21, 21, 1, 230400, 0x917be717
-0, 22, 22, 1, 230400, 0xd3c5a2ff
-0, 23, 23, 1, 230400, 0x0678a707
-0, 24, 24, 1, 230400, 0x122504e6
-0, 25, 25, 1, 230400, 0x76aebdae
-0, 26, 26, 1, 230400, 0x81357545
-0, 27, 27, 1, 230400, 0x38baeebd
-0, 28, 28, 1, 230400, 0x1c5c44d4
-0, 29, 29, 1, 230400, 0x60e189cc
-0, 30, 30, 1, 230400, 0xb1f4381c
-0, 31, 31, 1, 230400, 0xb5048fed
-0, 32, 32, 1, 230400, 0xc947c30e
-0, 33, 33, 1, 230400, 0xe8e31c07
-0, 34, 34, 1, 230400, 0x6d49dd02
-0, 35, 35, 1, 230400, 0x293e15d3
-0, 36, 36, 1, 230400, 0x354d792e
-0, 37, 37, 1, 230400, 0x35468780
-0, 38, 38, 1, 230400, 0x365d3991
-0, 39, 39, 1, 230400, 0xc9debef2
-0, 40, 40, 1, 230400, 0x4c4634c2
-0, 41, 41, 1, 230400, 0x347c2dca
-0, 42, 42, 1, 230400, 0x1efa0aaa
-0, 43, 43, 1, 230400, 0xa79a0b5a
-0, 44, 44, 1, 230400, 0xfdb2dcdb
-0, 45, 45, 1, 230400, 0x42dbea33
-0, 46, 46, 1, 230400, 0x2a207e43
-0, 47, 47, 1, 230400, 0x86573783
-0, 48, 48, 1, 230400, 0xc3968473
-0, 49, 49, 1, 230400, 0x8f62a7b4
-0, 50, 50, 1, 230400, 0x5a2e3073
-0, 51, 51, 1, 230400, 0xd24f5e2c
-0, 52, 52, 1, 230400, 0x1df3c67d
-0, 53, 53, 1, 230400, 0xe4fd884d
-0, 57, 57, 1, 230400, 0x9a228555
-0, 58, 58, 1, 230400, 0x9eba8ed5
-0, 59, 59, 1, 230400, 0x3d808a3d
-0, 60, 60, 1, 230400, 0xf57e866d
-0, 61, 61, 1, 230400, 0x85f594f5
-0, 62, 62, 1, 230400, 0xb09f99dd
-0, 63, 63, 1, 230400, 0x2b368475
-0, 64, 64, 1, 230400, 0xa2417afd
-0, 65, 65, 1, 230400, 0x590b709d
-0, 66, 66, 1, 230400, 0x5d617705
-0, 67, 67, 1, 230400, 0xabf981ad
-0, 68, 68, 1, 230400, 0x5a8590cd
-0, 69, 69, 1, 230400, 0x1bff853d
-0, 70, 70, 1, 230400, 0x71d08055
-0, 71, 71, 1, 230400, 0x2ebd817d
-0, 72, 72, 1, 230400, 0x6e838255
-0, 73, 73, 1, 230400, 0x043984cd
-0, 74, 74, 1, 230400, 0x7ff18495
-0, 75, 75, 1, 230400, 0xa43b8385
-0, 76, 76, 1, 230400, 0x72b5825d
-0, 77, 77, 1, 230400, 0x3a178085
-0, 78, 78, 1, 230400, 0x67748245
-0, 79, 79, 1, 230400, 0xeddf81d5
-0, 80, 80, 1, 230400, 0x8b088665
-0, 81, 81, 1, 230400, 0x6c408e15
-0, 82, 82, 1, 230400, 0x81f196dd
-0, 83, 83, 1, 230400, 0xab9f953d
-0, 84, 84, 1, 230400, 0xa5f69795
-0, 85, 85, 1, 230400, 0xa772950d
-0, 86, 86, 1, 230400, 0x6a5596d5
-0, 87, 87, 1, 230400, 0x1355958d
-0, 88, 88, 1, 230400, 0x4134981d
-0, 89, 89, 1, 230400, 0x8b929515
-0, 90, 90, 1, 230400, 0x482f95c5
-0, 91, 91, 1, 230400, 0x7a9795d5
-0, 92, 92, 1, 230400, 0x21c29abd
-0, 93, 93, 1, 230400, 0x9ae6a475
-0, 94, 94, 1, 230400, 0x3734aee5
-0, 95, 95, 1, 230400, 0xa0a1b365
-0, 96, 96, 1, 230400, 0x2dcab1c5
-0, 97, 97, 1, 230400, 0x9c8b6c44
-0, 98, 98, 1, 230400, 0x5da75feb
-0, 99, 99, 1, 230400, 0x4d02f8e3
-0, 100, 100, 1, 230400, 0x66824f3a
-0, 101, 101, 1, 230400, 0x0c9257e2
-0, 102, 102, 1, 230400, 0xb2927092
-0, 103, 103, 1, 230400, 0xb5dc6e9a
-0, 104, 104, 1, 230400, 0x6e567bc6
-0, 105, 105, 1, 230400, 0xbf9e0f7a
-0, 106, 106, 1, 230400, 0xb16f684a
-0, 107, 107, 1, 230400, 0xf9e55e81
-0, 108, 108, 1, 230400, 0xd8d0bcba
-0, 109, 109, 1, 230400, 0x44720ac0
-0, 110, 110, 1, 230400, 0x7d4c2058
-0, 113, 113, 1, 230400, 0xb0973eb9
-0, 114, 114, 1, 230400, 0x405a13ce
-0, 115, 115, 1, 230400, 0x6422f00a
-0, 116, 116, 1, 230400, 0x924b6c1e
-0, 145, 145, 1, 230400, 0xcf7809c0
-0, 146, 146, 1, 230400, 0x883a3863
-0, 147, 147, 1, 230400, 0x6adc9e03
-0, 148, 148, 1, 230400, 0x4f5ab7a8
-0, 214, 214, 1, 230400, 0xdc0aab94
+0, 0, 0, 1, 230400, 0x54b4bfe2
+0, 1, 1, 1, 230400, 0x9e1460e3
+0, 2, 2, 1, 230400, 0x8136f21c
+0, 3, 3, 1, 230400, 0xadfc5089
+0, 4, 4, 1, 230400, 0x76f2c4bc
+0, 5, 5, 1, 230400, 0x73862ec8
+0, 6, 6, 1, 230400, 0xba2562e3
+0, 7, 7, 1, 230400, 0xf908c0b6
+0, 8, 8, 1, 230400, 0x3596ee56
+0, 9, 9, 1, 230400, 0x97cc3a1e
+0, 10, 10, 1, 230400, 0xe2c585f9
+0, 11, 11, 1, 230400, 0x1732aedb
+0, 12, 12, 1, 230400, 0xa6d20354
+0, 13, 13, 1, 230400, 0x0e1e3d11
+0, 14, 14, 1, 230400, 0xe4f09bbd
+0, 15, 15, 1, 230400, 0x5c15ee1a
+0, 16, 16, 1, 230400, 0x33f51f69
+0, 17, 17, 1, 230400, 0xb6067c26
+0, 18, 18, 1, 230400, 0x985faab2
+0, 19, 19, 1, 230400, 0x3f0a09ae
+0, 20, 20, 1, 230400, 0x4052702f
+0, 21, 21, 1, 230400, 0xcd7fc29c
+0, 22, 22, 1, 230400, 0x73c97d9f
+0, 23, 23, 1, 230400, 0xf0fb8235
+0, 24, 24, 1, 230400, 0x7651e231
+0, 25, 25, 1, 230400, 0x3e749ecf
+0, 26, 26, 1, 230400, 0x20515985
+0, 27, 27, 1, 230400, 0xd086d4b0
+0, 28, 28, 1, 230400, 0x343c2c77
+0, 29, 29, 1, 230400, 0xb9a47309
+0, 30, 30, 1, 230400, 0x39de2037
+0, 31, 31, 1, 230400, 0x9fc2745a
+0, 32, 32, 1, 230400, 0x0868a2f3
+0, 33, 33, 1, 230400, 0xfe53f34d
+0, 34, 34, 1, 230400, 0xf2abaa57
+0, 35, 35, 1, 230400, 0x2dafdc4b
+0, 36, 36, 1, 230400, 0xf7d6353a
+0, 37, 37, 1, 230400, 0x8aa63c0a
+0, 38, 38, 1, 230400, 0xd1afe885
+0, 39, 39, 1, 230400, 0x64626c50
+0, 40, 40, 1, 230400, 0x2654dfca
+0, 41, 41, 1, 230400, 0x6183d8c7
+0, 42, 42, 1, 230400, 0xededb578
+0, 43, 43, 1, 230400, 0xadeeb629
+0, 44, 44, 1, 230400, 0x0009873a
+0, 45, 45, 1, 230400, 0xe2ec94eb
+0, 46, 46, 1, 230400, 0x62132788
+0, 47, 47, 1, 230400, 0x8cc5e014
+0, 48, 48, 1, 230400, 0x2ded2ecd
+0, 49, 49, 1, 230400, 0x81204eec
+0, 50, 50, 1, 230400, 0x4f9fda58
+0, 51, 51, 1, 230400, 0x9d7f073b
+0, 52, 52, 1, 230400, 0x607a6ee6
+0, 53, 53, 1, 230400, 0xed1c305c
+0, 57, 57, 1, 230400, 0x52b52d62
+0, 58, 58, 1, 230400, 0x4ae0370a
+0, 59, 59, 1, 230400, 0xe437326a
+0, 60, 60, 1, 230400, 0xefb82e8c
+0, 61, 61, 1, 230400, 0xa0f13d4b
+0, 62, 62, 1, 230400, 0x473a424a
+0, 63, 63, 1, 230400, 0x205a2c84
+0, 64, 64, 1, 230400, 0xe83022e5
+0, 65, 65, 1, 230400, 0x5db21854
+0, 66, 66, 1, 230400, 0x11991ed7
+0, 67, 67, 1, 230400, 0x649429b1
+0, 68, 68, 1, 230400, 0x840a3912
+0, 69, 69, 1, 230400, 0x8bb72d49
+0, 70, 70, 1, 230400, 0xedfc2850
+0, 71, 71, 1, 230400, 0x1b9b2977
+0, 72, 72, 1, 230400, 0x63912a4f
+0, 73, 73, 1, 230400, 0x971c2ccc
+0, 74, 74, 1, 230400, 0x1f022c98
+0, 75, 75, 1, 230400, 0x5dc42b8c
+0, 76, 76, 1, 230400, 0x25172a53
+0, 77, 77, 1, 230400, 0x31fd287f
+0, 78, 78, 1, 230400, 0x95182a44
+0, 79, 79, 1, 230400, 0xbf7d29ea
+0, 80, 80, 1, 230400, 0xdeb82e84
+0, 81, 81, 1, 230400, 0xc3ad3659
+0, 82, 82, 1, 230400, 0xfef23f36
+0, 83, 83, 1, 230400, 0xf4a23d8c
+0, 84, 84, 1, 230400, 0x90713fef
+0, 85, 85, 1, 230400, 0x5fad3d58
+0, 86, 86, 1, 230400, 0x69283f2e
+0, 87, 87, 1, 230400, 0x8f3d3dde
+0, 88, 88, 1, 230400, 0x3129407a
+0, 89, 89, 1, 230400, 0x266e3d64
+0, 90, 90, 1, 230400, 0xc41b3e19
+0, 91, 91, 1, 230400, 0x64203e29
+0, 92, 92, 1, 230400, 0x3f7e4328
+0, 93, 93, 1, 230400, 0xacef4d0e
+0, 94, 94, 1, 230400, 0xf0ca57a7
+0, 95, 95, 1, 230400, 0x87c75c41
+0, 96, 96, 1, 230400, 0x9db75a9c
+0, 97, 97, 1, 230400, 0x4152164c
+0, 98, 98, 1, 230400, 0x8a330ac8
+0, 99, 99, 1, 230400, 0x5113a45d
+0, 100, 100, 1, 230400, 0x60effb12
+0, 101, 101, 1, 230400, 0x01dc03c5
+0, 102, 102, 1, 230400, 0x7ae81caf
+0, 103, 103, 1, 230400, 0x35c31ab0
+0, 104, 104, 1, 230400, 0xd59e171e
+0, 105, 105, 1, 230400, 0x35c3989e
+0, 106, 106, 1, 230400, 0xf93656a5
+0, 107, 107, 1, 230400, 0x0962745c
+0, 108, 108, 1, 230400, 0x6a90cdb2
+0, 109, 109, 1, 230400, 0x4bc2216d
+0, 110, 110, 1, 230400, 0x7a6d3744
+0, 113, 113, 1, 230400, 0xf16a5742
+0, 114, 114, 1, 230400, 0x1495ce79
+0, 115, 115, 1, 230400, 0x3b4397b0
+0, 116, 116, 1, 230400, 0x33ed8506
+0, 145, 145, 1, 230400, 0xf953256d
+0, 146, 146, 1, 230400, 0xd7faaef9
+0, 147, 147, 1, 230400, 0xb37e6161
+0, 148, 148, 1, 230400, 0x526b6797
+0, 214, 214, 1, 230400, 0x8ec35bc5
diff --git a/tests/ref/fate/smc b/tests/ref/fate/smc
index cdfc3d5594..1635b37e55 100644
--- a/tests/ref/fate/smc
+++ b/tests/ref/fate/smc
@@ -1,121 +1,121 @@
-#tb 0: 1/30
+#tb 0: 1/10
0, 0, 0, 1, 230400, 0xf814fc90
-0, 3, 3, 1, 230400, 0xe1b13137
-0, 6, 6, 1, 230400, 0xa7f4d408
-0, 9, 9, 1, 230400, 0x4b86e1d5
-0, 12, 12, 1, 230400, 0xc663af5a
-0, 15, 15, 1, 230400, 0x943b5757
-0, 18, 18, 1, 230400, 0x0d7ee496
-0, 21, 21, 1, 230400, 0x78792de4
-0, 24, 24, 1, 230400, 0xd102fb8d
-0, 27, 27, 1, 230400, 0xf9006139
-0, 30, 30, 1, 230400, 0x216bd87d
-0, 33, 33, 1, 230400, 0x1e4c902c
-0, 36, 36, 1, 230400, 0x5aaa7742
-0, 39, 39, 1, 230400, 0x48699d93
-0, 42, 42, 1, 230400, 0xd1e22a5c
-0, 45, 45, 1, 230400, 0x18929315
-0, 48, 48, 1, 230400, 0x680dd4d3
-0, 51, 51, 1, 230400, 0x4cdbcbcb
-0, 54, 54, 1, 230400, 0x6f810d98
-0, 57, 57, 1, 230400, 0xb4f68204
-0, 60, 60, 1, 230400, 0xbd3bb19e
-0, 63, 63, 1, 230400, 0xab27b424
-0, 66, 66, 1, 230400, 0xe5dd675d
-0, 69, 69, 1, 230400, 0x811e45a1
-0, 72, 72, 1, 230400, 0x951011f7
-0, 75, 75, 1, 230400, 0x2f1e2b99
-0, 78, 78, 1, 230400, 0x6657c0d6
-0, 81, 81, 1, 230400, 0xfd29177d
-0, 84, 84, 1, 230400, 0x4b4c01d7
-0, 87, 87, 1, 230400, 0x9af286aa
-0, 90, 90, 1, 230400, 0xc4e9b193
-0, 93, 93, 1, 230400, 0x05dc28ec
-0, 96, 96, 1, 230400, 0x68352119
-0, 99, 99, 1, 230400, 0x0b87e79c
-0, 102, 102, 1, 230400, 0x8358b180
-0, 105, 105, 1, 230400, 0x8debbc9d
-0, 108, 108, 1, 230400, 0x961c58ce
-0, 111, 111, 1, 230400, 0xd8a809c8
-0, 114, 114, 1, 230400, 0x5351789d
-0, 117, 117, 1, 230400, 0xa7ca598c
-0, 120, 120, 1, 230400, 0xc5ce1812
-0, 123, 123, 1, 230400, 0x74496550
-0, 126, 126, 1, 230400, 0x326e366e
-0, 129, 129, 1, 230400, 0x27ae9a92
-0, 132, 132, 1, 230400, 0xadbc8794
-0, 135, 135, 1, 230400, 0x7f3587d8
-0, 138, 138, 1, 230400, 0xf0400ca6
-0, 141, 141, 1, 230400, 0x59a5138e
-0, 144, 144, 1, 230400, 0x456d62a5
-0, 147, 147, 1, 230400, 0xf1a5e5f1
-0, 150, 150, 1, 230400, 0x75c712e4
-0, 153, 153, 1, 230400, 0xd160780a
-0, 156, 156, 1, 230400, 0xc6c23cf0
-0, 159, 159, 1, 230400, 0x0339a2ac
-0, 162, 162, 1, 230400, 0x0e27a2e2
-0, 165, 165, 1, 230400, 0x84976300
-0, 168, 168, 1, 230400, 0xb368f3c4
-0, 171, 171, 1, 230400, 0xa5231fb8
-0, 174, 174, 1, 230400, 0x17c036d4
-0, 177, 177, 1, 230400, 0xfc81a2c0
-0, 180, 180, 1, 230400, 0x99faa403
-0, 183, 183, 1, 230400, 0xff59efd3
-0, 186, 186, 1, 230400, 0xcece1d23
-0, 189, 189, 1, 230400, 0x56c785d9
-0, 192, 192, 1, 230400, 0xe5a9f222
-0, 195, 195, 1, 230400, 0xb80946f8
-0, 198, 198, 1, 230400, 0xf6b642c6
-0, 201, 201, 1, 230400, 0x69573aed
-0, 204, 204, 1, 230400, 0xfb69a1fd
-0, 207, 207, 1, 230400, 0x100b47f4
-0, 210, 210, 1, 230400, 0x6edf9543
-0, 213, 213, 1, 230400, 0x11fdf43c
-0, 216, 216, 1, 230400, 0xd143bf2a
-0, 219, 219, 1, 230400, 0x7ca747c4
-0, 222, 222, 1, 230400, 0xd984bd73
-0, 225, 225, 1, 230400, 0xc5477e8d
-0, 228, 228, 1, 230400, 0xf7d58300
-0, 231, 231, 1, 230400, 0x7a1b9463
-0, 234, 234, 1, 230400, 0x47a29342
-0, 237, 237, 1, 230400, 0xdf437f9d
-0, 240, 240, 1, 230400, 0xf836ef5d
-0, 243, 243, 1, 230400, 0xc98937af
-0, 246, 246, 1, 230400, 0x9258695b
-0, 249, 249, 1, 230400, 0xd4fe179c
-0, 252, 252, 1, 230400, 0x35d524d3
-0, 255, 255, 1, 230400, 0xd9ce5484
-0, 258, 258, 1, 230400, 0xdef776ed
-0, 261, 261, 1, 230400, 0x154c4057
-0, 264, 264, 1, 230400, 0xf5c764f1
-0, 267, 267, 1, 230400, 0x41979b13
-0, 270, 270, 1, 230400, 0xae4e83db
-0, 273, 273, 1, 230400, 0x09fc0f83
-0, 276, 276, 1, 230400, 0x60267fdf
-0, 279, 279, 1, 230400, 0xeaafc525
-0, 282, 282, 1, 230400, 0x80cc35e5
-0, 285, 285, 1, 230400, 0xd82c6164
-0, 288, 288, 1, 230400, 0xd68b8111
-0, 291, 291, 1, 230400, 0x96f874a3
-0, 294, 294, 1, 230400, 0x7fc861c4
-0, 297, 297, 1, 230400, 0xb911f310
-0, 300, 300, 1, 230400, 0x35bbf5aa
-0, 303, 303, 1, 230400, 0xa922b683
-0, 306, 306, 1, 230400, 0xbf6ae353
-0, 309, 309, 1, 230400, 0x6bd3984c
-0, 312, 312, 1, 230400, 0xe51768c0
-0, 315, 315, 1, 230400, 0xee691624
-0, 318, 318, 1, 230400, 0xd546fed7
-0, 321, 321, 1, 230400, 0x98d375e6
-0, 324, 324, 1, 230400, 0x3b9ca990
-0, 327, 327, 1, 230400, 0x27128ad1
-0, 330, 330, 1, 230400, 0x2788e38c
-0, 333, 333, 1, 230400, 0xb0cf3381
-0, 336, 336, 1, 230400, 0x4fc86d39
-0, 339, 339, 1, 230400, 0xf5632fff
-0, 342, 342, 1, 230400, 0x7fa1e6c2
-0, 345, 345, 1, 230400, 0xffeef044
-0, 348, 348, 1, 230400, 0x932af385
-0, 351, 351, 1, 230400, 0x76738428
-0, 354, 354, 1, 230400, 0xf6771ba2
-0, 357, 357, 1, 230400, 0x17e2ff27
+0, 1, 1, 1, 230400, 0xe1b13137
+0, 2, 2, 1, 230400, 0xa7f4d408
+0, 3, 3, 1, 230400, 0x4b86e1d5
+0, 4, 4, 1, 230400, 0xc663af5a
+0, 5, 5, 1, 230400, 0x943b5757
+0, 6, 6, 1, 230400, 0x0d7ee496
+0, 7, 7, 1, 230400, 0x78792de4
+0, 8, 8, 1, 230400, 0xd102fb8d
+0, 9, 9, 1, 230400, 0xf9006139
+0, 10, 10, 1, 230400, 0x216bd87d
+0, 11, 11, 1, 230400, 0x1e4c902c
+0, 12, 12, 1, 230400, 0x5aaa7742
+0, 13, 13, 1, 230400, 0x48699d93
+0, 14, 14, 1, 230400, 0xd1e22a5c
+0, 15, 15, 1, 230400, 0x18929315
+0, 16, 16, 1, 230400, 0x680dd4d3
+0, 17, 17, 1, 230400, 0x4cdbcbcb
+0, 18, 18, 1, 230400, 0x6f810d98
+0, 19, 19, 1, 230400, 0xb4f68204
+0, 20, 20, 1, 230400, 0xbd3bb19e
+0, 21, 21, 1, 230400, 0xab27b424
+0, 22, 22, 1, 230400, 0xe5dd675d
+0, 23, 23, 1, 230400, 0x811e45a1
+0, 24, 24, 1, 230400, 0x951011f7
+0, 25, 25, 1, 230400, 0x2f1e2b99
+0, 26, 26, 1, 230400, 0x6657c0d6
+0, 27, 27, 1, 230400, 0xfd29177d
+0, 28, 28, 1, 230400, 0x4b4c01d7
+0, 29, 29, 1, 230400, 0x9af286aa
+0, 30, 30, 1, 230400, 0xc4e9b193
+0, 31, 31, 1, 230400, 0x05dc28ec
+0, 32, 32, 1, 230400, 0x68352119
+0, 33, 33, 1, 230400, 0x0b87e79c
+0, 34, 34, 1, 230400, 0x8358b180
+0, 35, 35, 1, 230400, 0x8debbc9d
+0, 36, 36, 1, 230400, 0x961c58ce
+0, 37, 37, 1, 230400, 0xd8a809c8
+0, 38, 38, 1, 230400, 0x5351789d
+0, 39, 39, 1, 230400, 0xa7ca598c
+0, 40, 40, 1, 230400, 0xc5ce1812
+0, 41, 41, 1, 230400, 0x74496550
+0, 42, 42, 1, 230400, 0x326e366e
+0, 43, 43, 1, 230400, 0x27ae9a92
+0, 44, 44, 1, 230400, 0xadbc8794
+0, 45, 45, 1, 230400, 0x7f3587d8
+0, 46, 46, 1, 230400, 0xf0400ca6
+0, 47, 47, 1, 230400, 0x59a5138e
+0, 48, 48, 1, 230400, 0x456d62a5
+0, 49, 49, 1, 230400, 0xf1a5e5f1
+0, 50, 50, 1, 230400, 0x75c712e4
+0, 51, 51, 1, 230400, 0xd160780a
+0, 52, 52, 1, 230400, 0xc6c23cf0
+0, 53, 53, 1, 230400, 0x0339a2ac
+0, 54, 54, 1, 230400, 0x0e27a2e2
+0, 55, 55, 1, 230400, 0x84976300
+0, 56, 56, 1, 230400, 0xb368f3c4
+0, 57, 57, 1, 230400, 0xa5231fb8
+0, 58, 58, 1, 230400, 0x17c036d4
+0, 59, 59, 1, 230400, 0xfc81a2c0
+0, 60, 60, 1, 230400, 0x99faa403
+0, 61, 61, 1, 230400, 0xff59efd3
+0, 62, 62, 1, 230400, 0xcece1d23
+0, 63, 63, 1, 230400, 0x56c785d9
+0, 64, 64, 1, 230400, 0xe5a9f222
+0, 65, 65, 1, 230400, 0xb80946f8
+0, 66, 66, 1, 230400, 0xf6b642c6
+0, 67, 67, 1, 230400, 0x69573aed
+0, 68, 68, 1, 230400, 0xfb69a1fd
+0, 69, 69, 1, 230400, 0x100b47f4
+0, 70, 70, 1, 230400, 0x6edf9543
+0, 71, 71, 1, 230400, 0x11fdf43c
+0, 72, 72, 1, 230400, 0xd143bf2a
+0, 73, 73, 1, 230400, 0x7ca747c4
+0, 74, 74, 1, 230400, 0xd984bd73
+0, 75, 75, 1, 230400, 0xc5477e8d
+0, 76, 76, 1, 230400, 0xf7d58300
+0, 77, 77, 1, 230400, 0x7a1b9463
+0, 78, 78, 1, 230400, 0x47a29342
+0, 79, 79, 1, 230400, 0xdf437f9d
+0, 80, 80, 1, 230400, 0xf836ef5d
+0, 81, 81, 1, 230400, 0xc98937af
+0, 82, 82, 1, 230400, 0x9258695b
+0, 83, 83, 1, 230400, 0xd4fe179c
+0, 84, 84, 1, 230400, 0x35d524d3
+0, 85, 85, 1, 230400, 0xd9ce5484
+0, 86, 86, 1, 230400, 0xdef776ed
+0, 87, 87, 1, 230400, 0x154c4057
+0, 88, 88, 1, 230400, 0xf5c764f1
+0, 89, 89, 1, 230400, 0x41979b13
+0, 90, 90, 1, 230400, 0xae4e83db
+0, 91, 91, 1, 230400, 0x09fc0f83
+0, 92, 92, 1, 230400, 0x60267fdf
+0, 93, 93, 1, 230400, 0xeaafc525
+0, 94, 94, 1, 230400, 0x80cc35e5
+0, 95, 95, 1, 230400, 0xd82c6164
+0, 96, 96, 1, 230400, 0xd68b8111
+0, 97, 97, 1, 230400, 0x96f874a3
+0, 98, 98, 1, 230400, 0x7fc861c4
+0, 99, 99, 1, 230400, 0xb911f310
+0, 100, 100, 1, 230400, 0x35bbf5aa
+0, 101, 101, 1, 230400, 0xa922b683
+0, 102, 102, 1, 230400, 0xbf6ae353
+0, 103, 103, 1, 230400, 0x6bd3984c
+0, 104, 104, 1, 230400, 0xe51768c0
+0, 105, 105, 1, 230400, 0xee691624
+0, 106, 106, 1, 230400, 0xd546fed7
+0, 107, 107, 1, 230400, 0x98d375e6
+0, 108, 108, 1, 230400, 0x3b9ca990
+0, 109, 109, 1, 230400, 0x27128ad1
+0, 110, 110, 1, 230400, 0x2788e38c
+0, 111, 111, 1, 230400, 0xb0cf3381
+0, 112, 112, 1, 230400, 0x4fc86d39
+0, 113, 113, 1, 230400, 0xf5632fff
+0, 114, 114, 1, 230400, 0x7fa1e6c2
+0, 115, 115, 1, 230400, 0xffeef044
+0, 116, 116, 1, 230400, 0x932af385
+0, 117, 117, 1, 230400, 0x76738428
+0, 118, 118, 1, 230400, 0xf6771ba2
+0, 119, 119, 1, 230400, 0x17e2ff27
diff --git a/tests/ref/fate/smjpeg b/tests/ref/fate/smjpeg
new file mode 100644
index 0000000000..7aac52febc
--- /dev/null
+++ b/tests/ref/fate/smjpeg
@@ -0,0 +1,425 @@
+#tb 0: 1/1000
+#tb 1: 1/22050
+0, 0, 0, 0, 734, 0x5a042c2c
+1, 0, 0, 512, 1024, 0x00000000
+1, 507, 507, 512, 1024, 0x00000000
+1, 1014, 1014, 512, 1024, 0xd89a448e
+1, 1521, 1521, 512, 1024, 0x695b369c
+1, 2029, 2029, 512, 1024, 0xc8ba5707
+0, 111, 111, 0, 763, 0xb5893f2f
+1, 2558, 2558, 512, 1024, 0xdf241fc6
+1, 3065, 3065, 512, 1024, 0x61cf4166
+1, 3572, 3572, 512, 1024, 0x97cbc386
+1, 4079, 4079, 512, 1024, 0x44899d04
+1, 4586, 4586, 512, 1024, 0xa7cbaa62
+0, 222, 222, 0, 3023, 0x0f3907d3
+1, 5116, 5116, 512, 1024, 0xa7aea60c
+1, 5623, 5623, 512, 1024, 0xd7b18a89
+1, 6130, 6130, 512, 1024, 0x268e81f6
+1, 6637, 6637, 512, 1024, 0x9cf83a2f
+1, 7166, 7166, 512, 1024, 0x5559b508
+0, 333, 333, 0, 4800, 0x22e6e18a
+1, 7673, 7673, 512, 1024, 0xe1b9e71c
+1, 8181, 8181, 512, 1024, 0xdcee733e
+1, 8688, 8688, 512, 1024, 0xe5918f60
+1, 9195, 9195, 512, 1024, 0x29dbd209
+1, 9724, 9724, 512, 1024, 0x9bcbcf16
+0, 444, 444, 0, 6417, 0x427adde5
+1, 10231, 10231, 512, 1024, 0x86f5f458
+1, 10738, 10738, 512, 1024, 0xabcbda86
+1, 11246, 11246, 512, 1024, 0xc51f77b9
+1, 11775, 11775, 512, 1024, 0xf6b3a504
+0, 555, 555, 0, 6776, 0x7a74c6ad
+1, 12282, 12282, 512, 1024, 0x1af3e40e
+1, 12789, 12789, 512, 1024, 0x3866b03b
+1, 13296, 13296, 512, 1024, 0xbc005403
+1, 13803, 13803, 512, 1024, 0xe9dfcc51
+1, 14333, 14333, 512, 1024, 0x83c837cb
+0, 666, 666, 0, 6808, 0x1f6eb7c3
+1, 14840, 14840, 512, 1024, 0xfa649580
+1, 15347, 15347, 512, 1024, 0x519452ea
+1, 15854, 15854, 512, 1024, 0xd4978774
+1, 16383, 16383, 512, 1024, 0xe2a3b1cd
+1, 16890, 16890, 512, 1024, 0x9a9472ad
+0, 777, 777, 0, 6726, 0x452087e6
+1, 17397, 17397, 512, 1024, 0xa12d4060
+1, 17905, 17905, 512, 1024, 0x31fb0646
+1, 18412, 18412, 512, 1024, 0xfc44343f
+1, 18941, 18941, 512, 1024, 0x0847751a
+1, 19448, 19448, 512, 1024, 0x227968a2
+0, 888, 888, 0, 6829, 0xee82b109
+1, 19955, 19955, 512, 1024, 0x7cce9f1c
+1, 20462, 20462, 512, 1024, 0xb8356713
+1, 20992, 20992, 512, 1024, 0xb29f6e6f
+1, 21499, 21499, 512, 1024, 0x9e1430ab
+1, 22006, 22006, 512, 1024, 0x26d85423
+0, 999, 999, 0, 7055, 0xf41f1108
+1, 22513, 22513, 512, 1024, 0x6496547d
+1, 23020, 23020, 512, 1024, 0x316b1a86
+1, 23549, 23549, 512, 1024, 0x3cd83afc
+1, 24057, 24057, 512, 1024, 0x993ff633
+0, 1111, 1111, 0, 6977, 0xf8fe1ede
+1, 24564, 24564, 512, 1024, 0x0708d1a2
+1, 25071, 25071, 512, 1024, 0xd7230db9
+1, 25578, 25578, 512, 1024, 0xbb0779ca
+1, 26107, 26107, 512, 1024, 0xc6094e1b
+1, 26614, 26614, 512, 1024, 0x15a8b039
+0, 1222, 1222, 0, 6942, 0x9ad105c6
+1, 27122, 27122, 512, 1024, 0xd6dbe88c
+1, 27629, 27629, 512, 1024, 0x7e8d1140
+1, 28158, 28158, 512, 1024, 0xef88e525
+1, 28665, 28665, 512, 1024, 0x44e21149
+1, 29172, 29172, 512, 1024, 0x65b0f5f4
+0, 1333, 1333, 0, 6926, 0xe239dad6
+1, 29679, 29679, 512, 1024, 0xb955f687
+1, 30186, 30186, 512, 1024, 0xc85fba9c
+1, 30716, 30716, 512, 1024, 0xf59655ad
+1, 31223, 31223, 512, 1024, 0x6de80bf1
+1, 31730, 31730, 512, 1024, 0x2dcf6e41
+0, 1444, 1444, 0, 6966, 0x81dcfab1
+1, 32237, 32237, 512, 1024, 0xd0ddcf8a
+1, 32766, 32766, 512, 1024, 0x00135c2d
+1, 33273, 33273, 512, 1024, 0x697f8efd
+1, 33781, 33781, 512, 1024, 0x7a9bada5
+0, 1555, 1555, 0, 6896, 0x31e6cc02
+1, 34288, 34288, 512, 1024, 0x0d22783c
+1, 34795, 34795, 512, 1024, 0x7726d07d
+1, 35324, 35324, 512, 1024, 0xa2f14f67
+1, 35831, 35831, 512, 1024, 0x7f51060d
+1, 36338, 36338, 512, 1024, 0xc4ec6aea
+0, 1666, 1666, 0, 6889, 0x1cc1006e
+1, 36846, 36846, 512, 1024, 0x9bb37ca4
+1, 37375, 37375, 512, 1024, 0x9b085577
+1, 37882, 37882, 512, 1024, 0x8812f8af
+1, 38389, 38389, 512, 1024, 0x788f5221
+1, 38896, 38896, 512, 1024, 0x3a2ce642
+0, 1777, 1777, 0, 6933, 0xc303f87f
+1, 39403, 39403, 512, 1024, 0x72415692
+1, 39933, 39933, 512, 1024, 0xe3dcc105
+1, 40440, 40440, 512, 1024, 0xb26c0599
+1, 40947, 40947, 512, 1024, 0x5c9e55eb
+1, 41454, 41454, 512, 1024, 0x8fe88707
+0, 1888, 1888, 0, 7034, 0xb4970a20
+1, 41983, 41983, 512, 1024, 0xc5d7beb6
+1, 42490, 42490, 512, 1024, 0xe1d3a3b4
+1, 42998, 42998, 512, 1024, 0x012da0c6
+1, 43505, 43505, 512, 1024, 0x8d010922
+1, 44012, 44012, 512, 1024, 0x3366eb0d
+0, 1999, 1999, 0, 6961, 0xf064095d
+1, 44541, 44541, 512, 1024, 0xc9381a27
+1, 45048, 45048, 512, 1024, 0x0774f685
+1, 45555, 45555, 512, 1024, 0xc5cae0a5
+1, 46062, 46062, 512, 1024, 0xa6f4737c
+0, 2111, 2111, 0, 7089, 0x5ba350f9
+1, 46592, 46592, 512, 1024, 0x8fb6d0d1
+1, 47099, 47099, 512, 1024, 0x05f579c2
+1, 47606, 47606, 512, 1024, 0x56905d99
+1, 48113, 48113, 512, 1024, 0x002ee18d
+1, 48620, 48620, 512, 1024, 0xeb37ef51
+0, 2222, 2222, 0, 7078, 0xa83f3e88
+1, 49149, 49149, 512, 1024, 0x38025635
+1, 49657, 49657, 512, 1024, 0x4fe643c8
+1, 50164, 50164, 512, 1024, 0x11d66ab1
+1, 50671, 50671, 512, 1024, 0xcc3051e9
+1, 51178, 51178, 512, 1024, 0xcd93e854
+0, 2333, 2333, 0, 7147, 0xcda66cfc
+1, 51707, 51707, 512, 1024, 0x38f1196d
+1, 52214, 52214, 512, 1024, 0x657a15fc
+1, 52722, 52722, 512, 1024, 0x669ce2a9
+1, 53229, 53229, 512, 1024, 0x95862dda
+1, 53758, 53758, 512, 1024, 0x1726a7b2
+0, 2444, 2444, 0, 7173, 0xb7455859
+1, 54265, 54265, 512, 1024, 0xd6ece2a1
+1, 54772, 54772, 512, 1024, 0x33ab9553
+1, 55279, 55279, 512, 1024, 0xd50c73a6
+1, 55787, 55787, 512, 1024, 0xfe25b63a
+1, 56316, 56316, 512, 1024, 0x7e2959e3
+0, 2555, 2555, 0, 7213, 0x97b89994
+1, 56823, 56823, 512, 1024, 0xa4c07b34
+1, 57330, 57330, 512, 1024, 0xd6d8f15c
+1, 57837, 57837, 512, 1024, 0x1eccddd7
+1, 58366, 58366, 512, 1024, 0x2b69f9cb
+0, 2666, 2666, 0, 7170, 0xca8b2948
+1, 58874, 58874, 512, 1024, 0x667b775f
+1, 59381, 59381, 512, 1024, 0xad3b84e9
+1, 59888, 59888, 512, 1024, 0x4f29fc67
+1, 60395, 60395, 512, 1024, 0x8d611ab7
+1, 60924, 60924, 512, 1024, 0x278966ea
+0, 2777, 2777, 0, 7174, 0xc7cc6bbb
+1, 61431, 61431, 512, 1024, 0xaf33812b
+1, 61938, 61938, 512, 1024, 0xa55f4265
+1, 62446, 62446, 512, 1024, 0x023cb51c
+1, 62975, 62975, 512, 1024, 0x1d1f1005
+1, 63482, 63482, 512, 1024, 0x874cccf7
+0, 2888, 2888, 0, 7235, 0xc2e68d2b
+1, 63989, 63989, 512, 1024, 0xda705428
+1, 64496, 64496, 512, 1024, 0x48d9b440
+1, 65003, 65003, 512, 1024, 0xa14e0712
+1, 65533, 65533, 512, 1024, 0x7efbad1f
+1, 66040, 66040, 512, 1024, 0xdb82c17f
+0, 3000, 3000, 0, 7261, 0x8204a423
+1, 66547, 66547, 512, 1024, 0xcbe87613
+1, 67054, 67054, 512, 1024, 0x3a63df1d
+1, 67583, 67583, 512, 1024, 0xd5636bba
+1, 68090, 68090, 512, 1024, 0x9397af23
+0, 3111, 3111, 0, 7353, 0xacc7e7c0
+1, 68598, 68598, 512, 1024, 0x32a07c98
+1, 69105, 69105, 512, 1024, 0x202ca667
+1, 69612, 69612, 512, 1024, 0xdf969011
+1, 70141, 70141, 512, 1024, 0xc434d238
+1, 70648, 70648, 512, 1024, 0xe9ad7562
+0, 3222, 3222, 0, 7065, 0x45035c5c
+1, 71155, 71155, 512, 1024, 0xb51b6b50
+1, 71663, 71663, 512, 1024, 0xe70aecd3
+1, 72192, 72192, 512, 1024, 0x03c816b2
+1, 72699, 72699, 512, 1024, 0x869fdf25
+1, 73206, 73206, 512, 1024, 0xd40a0a62
+0, 3333, 3333, 0, 7269, 0x72edbb76
+1, 73713, 73713, 512, 1024, 0x5af7dd35
+1, 74220, 74220, 512, 1024, 0x891ffc72
+1, 74750, 74750, 512, 1024, 0x1ff68a08
+1, 75257, 75257, 512, 1024, 0x5a7517a9
+1, 75764, 75764, 512, 1024, 0x0f959f74
+0, 3444, 3444, 0, 7220, 0xb926772f
+1, 76271, 76271, 512, 1024, 0xe92a12a2
+1, 76778, 76778, 512, 1024, 0x38000e55
+1, 77307, 77307, 512, 1024, 0x39fbdd70
+1, 77814, 77814, 512, 1024, 0xca3d9184
+1, 78322, 78322, 512, 1024, 0x66c8995b
+0, 3555, 3555, 0, 7326, 0x0a66c632
+1, 78829, 78829, 512, 1024, 0xac25acea
+1, 79358, 79358, 512, 1024, 0x3cd1046c
+1, 79865, 79865, 512, 1024, 0x6a1df31c
+1, 80372, 80372, 512, 1024, 0x21ca10a1
+0, 3666, 3666, 0, 7225, 0xe39076ab
+1, 80879, 80879, 512, 1024, 0x1aeccedc
+1, 81387, 81387, 512, 1024, 0xddea1335
+1, 81916, 81916, 512, 1024, 0x19f5ca9f
+1, 82423, 82423, 512, 1024, 0x88e95e43
+1, 82930, 82930, 512, 1024, 0x726284fe
+0, 3777, 3777, 0, 7265, 0xe0209036
+1, 83437, 83437, 512, 1024, 0x6b85b40e
+1, 83966, 83966, 512, 1024, 0x111fee2a
+1, 84474, 84474, 512, 1024, 0x3656b588
+1, 84981, 84981, 512, 1024, 0xa5a2b552
+1, 85488, 85488, 512, 1024, 0x38fb2467
+0, 3888, 3888, 0, 7337, 0x7a5dc093
+1, 85995, 85995, 512, 1024, 0xaa919ccc
+1, 86524, 86524, 512, 1024, 0x15993dbc
+1, 87031, 87031, 512, 1024, 0xbe01a7b9
+1, 87539, 87539, 512, 1024, 0xefe93c09
+1, 88046, 88046, 512, 1024, 0x1bb566e5
+0, 4000, 4000, 0, 7246, 0x519a7a3c
+1, 88575, 88575, 512, 1024, 0x15ce6237
+1, 89082, 89082, 512, 1024, 0xa8552e66
+1, 89589, 89589, 512, 1024, 0x9d80187e
+1, 90096, 90096, 512, 1024, 0x5df3fc30
+1, 90603, 90603, 512, 1024, 0x1a312aa5
+0, 4111, 4111, 0, 7266, 0x352c8078
+1, 91133, 91133, 512, 1024, 0x6bb8e302
+1, 91640, 91640, 512, 1024, 0xbd9684bb
+1, 92147, 92147, 512, 1024, 0x78b0b166
+1, 92654, 92654, 512, 1024, 0xd9af5eae
+0, 4222, 4222, 0, 7323, 0xcaf69d7c
+1, 93183, 93183, 512, 1024, 0xdb90fe82
+1, 93690, 93690, 512, 1024, 0x327614e9
+1, 94198, 94198, 512, 1024, 0x1f19b7fe
+1, 94705, 94705, 512, 1024, 0x46c53f96
+1, 95212, 95212, 512, 1024, 0x921b2189
+0, 4333, 4333, 0, 7309, 0x98c1e6f7
+1, 95741, 95741, 512, 1024, 0xa8fbc85a
+1, 96248, 96248, 512, 1024, 0xabfdaaae
+1, 96755, 96755, 512, 1024, 0x6acc7387
+1, 97263, 97263, 512, 1024, 0x0d9c27b5
+1, 97792, 97792, 512, 1024, 0xba4dd809
+0, 4444, 4444, 0, 7121, 0x913d5bd6
+1, 98299, 98299, 512, 1024, 0x2a2ad521
+1, 98806, 98806, 512, 1024, 0x892de38a
+1, 99313, 99313, 512, 1024, 0xdc97a2eb
+1, 99820, 99820, 512, 1024, 0x4f614ca4
+1, 100350, 100350, 512, 1024, 0x9c8a77ea
+0, 4555, 4555, 111, 7088, 0x56302362
+1, 100857, 100857, 512, 1024, 0x2d30e646
+1, 101364, 101364, 512, 1024, 0x74e800a7
+1, 101871, 101871, 512, 1024, 0x1e01fb02
+1, 102378, 102378, 512, 1024, 0x4ed2c1d8
+0, 4666, 4666, 111, 7104, 0xc0d14f78
+1, 102907, 102907, 512, 1024, 0xf2fdbe63
+1, 103415, 103415, 512, 1024, 0x8d6f63a1
+1, 103922, 103922, 512, 1024, 0xded468d9
+1, 104429, 104429, 512, 1024, 0xccad839e
+1, 104958, 104958, 512, 1024, 0xdde7c082
+0, 4777, 4777, 111, 7169, 0xd03c825b
+1, 105465, 105465, 512, 1024, 0x548613c5
+1, 105972, 105972, 512, 1024, 0x383909bd
+1, 106479, 106479, 512, 1024, 0xfd37627b
+1, 106987, 106987, 512, 1024, 0x6d95a481
+1, 107516, 107516, 512, 1024, 0x56aa87fa
+0, 4888, 4888, 111, 7038, 0x1ecc201d
+1, 108023, 108023, 512, 1024, 0x7b67258c
+1, 108530, 108530, 512, 1024, 0x7dd99a92
+1, 109037, 109037, 512, 1024, 0x4a66d102
+1, 109566, 109566, 512, 1024, 0x7b3fce51
+1, 110074, 110074, 512, 1024, 0xbbd968aa
+0, 5000, 5000, 111, 7015, 0x83c94454
+1, 110581, 110581, 512, 1024, 0x8283ec36
+1, 111088, 111088, 512, 1024, 0x3c96493d
+1, 111595, 111595, 512, 1024, 0xfa4f8cf8
+1, 112124, 112124, 512, 1024, 0xe2cf872d
+1, 112631, 112631, 512, 1024, 0x0a9e7aa6
+0, 5111, 5111, 111, 6983, 0x9e51f54d
+1, 113139, 113139, 512, 1024, 0x6e7a0550
+1, 113646, 113646, 512, 1024, 0x3acfea2f
+1, 114175, 114175, 512, 1024, 0x7111d0fa
+1, 114682, 114682, 512, 1024, 0xe9a1eca9
+0, 5222, 5222, 111, 7088, 0x70d33de1
+1, 115189, 115189, 512, 1024, 0x24da6c46
+1, 115696, 115696, 512, 1024, 0x117cff37
+1, 116204, 116204, 512, 1024, 0x0f27cab6
+1, 116733, 116733, 512, 1024, 0x69b6b4e6
+1, 117240, 117240, 512, 1024, 0x1e6cc841
+0, 5333, 5333, 111, 7096, 0x4d0f81b5
+1, 117747, 117747, 512, 1024, 0xb01e2365
+1, 118254, 118254, 512, 1024, 0x14e200d3
+1, 118783, 118783, 512, 1024, 0xd1184c98
+1, 119291, 119291, 512, 1024, 0xef9140e9
+1, 119798, 119798, 512, 1024, 0x4cbb645e
+0, 5444, 5444, 111, 7106, 0xd1a83ddc
+1, 120305, 120305, 512, 1024, 0xe7fe2f06
+1, 120812, 120812, 512, 1024, 0xf8c45028
+1, 121341, 121341, 512, 1024, 0x561358f4
+1, 121848, 121848, 512, 1024, 0xd0129b77
+1, 122355, 122355, 512, 1024, 0xcc636e88
+0, 5555, 5555, 111, 7219, 0x20f47fe4
+1, 122863, 122863, 512, 1024, 0xe9406321
+1, 123392, 123392, 512, 1024, 0x9f16a041
+1, 123899, 123899, 512, 1024, 0x468bf409
+1, 124406, 124406, 512, 1024, 0x3df70f7b
+1, 124913, 124913, 512, 1024, 0xa880b11b
+0, 5666, 5666, 111, 7184, 0x45dc6a0e
+1, 125420, 125420, 512, 1024, 0x3286c489
+1, 125950, 125950, 512, 1024, 0x39fe9ebc
+1, 126457, 126457, 512, 1024, 0xc533d83b
+1, 126964, 126964, 512, 1024, 0x153b195d
+0, 5777, 5777, 111, 7222, 0x488c6499
+1, 127471, 127471, 512, 1024, 0xd84786a1
+1, 127978, 127978, 512, 1024, 0xdc295aaa
+1, 128507, 128507, 512, 1024, 0xfb764d8c
+1, 129015, 129015, 512, 1024, 0xeebc9db9
+1, 129522, 129522, 512, 1024, 0x7ba9403e
+0, 5888, 5888, 111, 7254, 0xbd097ba7
+1, 130029, 130029, 512, 1024, 0x4e5571ec
+1, 130558, 130558, 512, 1024, 0xd965fad4
+1, 131065, 131065, 512, 1024, 0x87e259f2
+1, 131572, 131572, 512, 1024, 0xae7e533b
+1, 132080, 132080, 512, 1024, 0x313cf4d6
+0, 6000, 6000, 111, 7189, 0x46e06d43
+1, 132587, 132587, 512, 1024, 0xe1844c90
+1, 133116, 133116, 512, 1024, 0xbb057b44
+1, 133623, 133623, 512, 1024, 0xa5099687
+1, 134130, 134130, 512, 1024, 0xbff10707
+1, 134637, 134637, 512, 1024, 0x37c4ffc0
+0, 6111, 6111, 111, 7283, 0x19dd7319
+1, 135167, 135167, 512, 1024, 0xf9fb6caa
+1, 135674, 135674, 512, 1024, 0x3b6a3a1f
+1, 136181, 136181, 512, 1024, 0x83431edb
+1, 136688, 136688, 512, 1024, 0x1eb713cf
+1, 137195, 137195, 512, 1024, 0xd7b07a6d
+0, 6222, 6222, 111, 7161, 0x23171d02
+1, 137724, 137724, 512, 1024, 0x81ae3391
+1, 138231, 138231, 512, 1024, 0xf150130a
+1, 138739, 138739, 512, 1024, 0x09678eaa
+1, 139246, 139246, 512, 1024, 0xb94e06f1
+0, 6333, 6333, 111, 6976, 0xcc610c26
+1, 139775, 139775, 512, 1024, 0x67b1dbc9
+1, 140282, 140282, 512, 1024, 0xd6edc235
+1, 140789, 140789, 512, 1024, 0x34e4c499
+1, 141296, 141296, 512, 1024, 0xeefd89c0
+1, 141804, 141804, 512, 1024, 0x38afdaf1
+0, 6444, 6444, 111, 7056, 0x6cd917b0
+1, 142333, 142333, 512, 1024, 0x29a60d76
+1, 142840, 142840, 512, 1024, 0xe28a4372
+1, 143347, 143347, 512, 1024, 0x7089454d
+1, 143854, 143854, 512, 1024, 0x0c01bb7b
+1, 144383, 144383, 512, 1024, 0xbd776a72
+0, 6555, 6555, 111, 6736, 0x02b78951
+1, 144891, 144891, 512, 1024, 0x86776fd0
+1, 145398, 145398, 512, 1024, 0xb37c88f7
+1, 145905, 145905, 512, 1024, 0x5f90aaf8
+1, 146412, 146412, 512, 1024, 0x203d4222
+1, 146941, 146941, 512, 1024, 0x382692a6
+0, 6666, 6666, 111, 6540, 0x767e0854
+1, 147448, 147448, 512, 1024, 0xf37c95fd
+1, 147956, 147956, 512, 1024, 0x6c0b8877
+1, 148463, 148463, 512, 1024, 0x2e54a8b6
+1, 148992, 148992, 512, 1024, 0x7f266488
+0, 6777, 6777, 111, 6170, 0xc84962fb
+1, 149499, 149499, 512, 1024, 0xfbf20f9a
+1, 150006, 150006, 512, 1024, 0xf2985cc0
+1, 150513, 150513, 512, 1024, 0xc7075340
+1, 151020, 151020, 512, 1024, 0xe4585695
+1, 151550, 151550, 512, 1024, 0xbdffa380
+0, 6888, 6888, 111, 6169, 0x27e06c03
+1, 152057, 152057, 512, 1024, 0x2422a8a9
+1, 152564, 152564, 512, 1024, 0x59cbd75f
+1, 153071, 153071, 512, 1024, 0x04ad1a8c
+1, 153578, 153578, 512, 1024, 0x33c09191
+1, 154107, 154107, 512, 1024, 0x55efa6fd
+0, 7000, 7000, 111, 5864, 0xd14db83f
+1, 154615, 154615, 512, 1024, 0xf73d0e5d
+1, 155122, 155122, 512, 1024, 0x6141ebae
+1, 155629, 155629, 512, 1024, 0x7db17a68
+1, 156158, 156158, 512, 1024, 0xa6c690b6
+1, 156665, 156665, 512, 1024, 0xa6fd6725
+0, 7111, 7111, 111, 5375, 0x4a21055d
+1, 157172, 157172, 512, 1024, 0x50a90b9b
+1, 157680, 157680, 512, 1024, 0xef990dc8
+1, 158187, 158187, 512, 1024, 0x75adf6b5
+1, 158716, 158716, 512, 1024, 0x61eac43e
+1, 159223, 159223, 512, 1024, 0x67797a19
+0, 7222, 7222, 111, 5206, 0x95ead3cb
+1, 159730, 159730, 512, 1024, 0xf325277a
+1, 160237, 160237, 512, 1024, 0x18bf254a
+1, 160767, 160767, 512, 1024, 0x2ce6bee3
+1, 161274, 161274, 512, 1024, 0x8d320860
+0, 7333, 7333, 111, 5220, 0xcfdcc37e
+1, 161781, 161781, 512, 1024, 0xc979b6e8
+1, 162288, 162288, 512, 1024, 0xdb644b41
+1, 162795, 162795, 512, 1024, 0xe1b368ba
+1, 163324, 163324, 512, 1024, 0xacc53d15
+1, 163832, 163832, 512, 1024, 0x42ea8c18
+0, 7444, 7444, 111, 4946, 0x2d864a77
+1, 164339, 164339, 512, 1024, 0xe52c99a4
+1, 164846, 164846, 512, 1024, 0xd7db54a6
+1, 165375, 165375, 512, 1024, 0x7f27a7e3
+1, 165882, 165882, 512, 1024, 0xf7ffeaa9
+1, 166389, 166389, 512, 1024, 0x792b6088
+0, 7555, 7555, 111, 4390, 0x2ab9f462
+1, 166896, 166896, 512, 1024, 0x61d99724
+1, 167404, 167404, 512, 1024, 0x5213720e
+1, 167933, 167933, 512, 1024, 0xac09dd30
+1, 168440, 168440, 512, 1024, 0x960bf6bb
+1, 168947, 168947, 512, 1024, 0xc90168e1
+0, 7666, 7666, 111, 4051, 0x1d09592e
+1, 169454, 169454, 512, 1024, 0x43b45768
+1, 169983, 169983, 512, 1024, 0x935d60a1
+1, 170491, 170491, 512, 1024, 0x9a342ef2
+1, 170998, 170998, 512, 1024, 0xc894709f
+0, 7777, 7777, 111, 3680, 0x39bd6a12
+1, 171505, 171505, 512, 1024, 0x59b43b07
+1, 172012, 172012, 512, 1024, 0x36a1a98d
+1, 172541, 172541, 512, 1024, 0x9e1a121c
+1, 173048, 173048, 512, 1024, 0x02208b78
+1, 173556, 173556, 512, 1024, 0xd1d7b274
+0, 7888, 7888, 111, 2910, 0x6337ece9
+1, 174063, 174063, 512, 1024, 0xdacd5096
+1, 174592, 174592, 512, 1024, 0x51b71ead
+1, 175099, 175099, 512, 1024, 0xd009a7ca
+1, 175606, 175606, 512, 1024, 0xb6d5a938
+1, 176113, 176113, 512, 1024, 0xf3d45e47
+0, 8000, 8000, 111, 2153, 0xf4e3bc17
+1, 176621, 176621, 512, 1024, 0xea8e04fc
+1, 177150, 177150, 512, 1024, 0x0b928bd8
+1, 177657, 177657, 512, 1024, 0x0f02caec
+1, 178164, 178164, 512, 1024, 0xe2b137a8
+1, 178671, 178671, 512, 1024, 0xd5f94892
diff --git a/tests/ref/fate/smjpeg-demux b/tests/ref/fate/smjpeg-demux
index 4fcd6149d4..637f28c663 100644
--- a/tests/ref/fate/smjpeg-demux
+++ b/tests/ref/fate/smjpeg-demux
@@ -232,7 +232,7 @@
1, 4388, 4388, 23, 260, 0x06ad6a93
1, 4411, 4411, 23, 260, 0xdd1b6c91
1, 4435, 4435, 23, 260, 0x05b94d27
-0, 4444, 4444, 111, 7121, 0x913d5bd6
+0, 4444, 4444, 0, 7121, 0x913d5bd6
1, 4458, 4458, 23, 260, 0x12cc5062
1, 4481, 4481, 23, 260, 0x44526d0f
1, 4504, 4504, 23, 260, 0xf2ac6d95
diff --git a/tests/ref/fate/smvjpeg b/tests/ref/fate/smvjpeg
new file mode 100644
index 0000000000..1a012cd942
--- /dev/null
+++ b/tests/ref/fate/smvjpeg
@@ -0,0 +1,13 @@
+#tb 0: 1/1
+0, 0, 0, 1, 30720, 0x3a821807
+0, 1, 1, 1, 30720, 0x95168e5d
+0, 2, 2, 1, 30720, 0xd4d98e45
+0, 3, 3, 1, 30720, 0xe340a7ea
+0, 4, 4, 1, 30720, 0xb832a22d
+0, 5, 5, 1, 30720, 0x1f3eb488
+0, 6, 6, 1, 30720, 0x6429ce43
+0, 7, 7, 1, 30720, 0x3a3da232
+0, 8, 8, 1, 30720, 0x5c02aeff
+0, 9, 9, 1, 30720, 0x4c7b1c9a
+0, 10, 10, 1, 30720, 0x6f7a8313
+0, 11, 11, 1, 30720, 0xaa32fd72
diff --git a/tests/ref/fate/sub-aqtitle b/tests/ref/fate/sub-aqtitle
new file mode 100644
index 0000000000..87253c9a2d
--- /dev/null
+++ b/tests/ref/fate/sub-aqtitle
@@ -0,0 +1,45 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:03:29.92,0:03:31.28,Default,,0,0,0,,Dougu?
+Dialogue: 0,0:03:33.36,0:03:35.76,Default,,0,0,0,,Zlato, jseÅ¡ v poÅ™Ă¡dku?
+Dialogue: 0,0:03:37.72,0:03:39.12,Default,,0,0,0,,Měl jsi sny.
+Dialogue: 0,0:03:41.44,0:03:43.32,Default,,0,0,0,,Byly o Marsu?
+Dialogue: 0,0:03:48.92,0:03:50.52,Default,,0,0,0,,Je to lepÅ¡Ă­?
+Dialogue: 0,0:03:53.12,0:03:54.72,Default,,0,0,0,,Chudinko moje.
+Dialogue: 0,0:03:55.76,0:03:58.08,Default,,0,0,0,,ZaÄĂ­nĂ¡ to bĂ½t\Nposedlost.
+Dialogue: 0,0:04:05.92,0:04:07.16,Default,,0,0,0,,Byla tam i ona?
+Dialogue: 0,0:04:09.12,0:04:10.48,Default,,0,0,0,,Kdo?
+Dialogue: 0,0:04:12.44,0:04:15.16,Default,,0,0,0,,Ta, o kterĂ© jsi mi vyprĂ¡vÄ›l.\NTa bruneta.
+Dialogue: 0,0:04:16.32,0:04:17.52,Default,,0,0,0,,Lori.
+Dialogue: 0,0:04:20.32,0:04:23.16,Default,,0,0,0,,Nemůžu uvěřit\Nže Å¾Ă¡rlĂ­Å¡ na sen.
+Dialogue: 0,0:04:23.84,0:04:26.60,Default,,0,0,0,,- Kdo je ona?\N- Nikdo.
+Dialogue: 0,0:04:26.60,0:04:28.80,Default,,0,0,0,,"Nikdo"? Jak se jmenuje?
+Dialogue: 0,0:04:28.80,0:04:30.24,Default,,0,0,0,,NevĂ­m.
+Dialogue: 0,0:04:31.52,0:04:33.20,Default,,0,0,0,,- Pověz!\N- Nevím!
+Dialogue: 0,0:04:33.20,0:04:35.48,Default,,0,0,0,,RadÅ¡i bys mi to mÄ›l Å™Ă­ct!
+Dialogue: 0,0:04:35.48,0:04:39.16,Default,,0,0,0,,To nenĂ­ legrace Dougu.\NZdĂ¡ se ti o nĂ­ každou noc.
+Dialogue: 0,0:04:39.16,0:04:41.84,Default,,0,0,0,,Ale vždy se rĂ¡no probudĂ­m.
+Dialogue: 0,0:04:41.84,0:04:43.28,Default,,0,0,0,,Nech mÄ› bĂ½t!
+Dialogue: 0,0:04:45.72,0:04:47.76,Default,,0,0,0,,No tak, zlato.
+Dialogue: 0,0:04:47.76,0:04:50.72,Default,,0,0,0,,Ty vĂ­Å¡, že jsi dĂ­vkou\NmĂ½ch snů.
+Dialogue: 0,0:04:50.72,0:04:52.40,Default,,0,0,0,,MyslĂ­Å¡ to vĂ¡Å¾nÄ›?
+Dialogue: 0,0:04:53.48,0:04:55.32,Default,,0,0,0,,To vĂ­Å¡ že ano.
+Dialogue: 0,0:05:04.40,0:05:07.20,Default,,0,0,0,,DĂ¡m ti nÄ›co\No Äem budeÅ¡ snĂ­t.
+Dialogue: 0,0:05:16.76,0:05:16.92,Default,,0,0,0,,PremiĂ©r se Ăºtoku ubrĂ¡nil\Na Å™ekl, že zbranÄ› založenĂ© na vesmĂ­rnĂ½ch...
+Dialogue: 0,0:05:16.92,0:05:20.36,Default,,0,0,0,,PremiĂ©r se Ăºtoku ubrĂ¡nil\Na Å™ekl, že zbranÄ› založenĂ© na vesmĂ­rnĂ½ch...
+Dialogue: 0,0:05:20.36,0:05:24.36,Default,,0,0,0,,jsou naÅ¡e jedinĂ¡ obrana proti\NpoÄetnĂ­ pÅ™evaze z jižnĂ­ho bloku.
+Dialogue: 0,0:05:24.36,0:05:26.76,Default,,0,0,0,,A dalÅ¡Ă­ nĂ¡silĂ­ na Marsu...
+Dialogue: 0,0:05:26.76,1:44:16.00,Default,,0,0,0,,[...]
+Dialogue: 0,1:44:16.00,1:44:17.60,Default,,0,0,0,,Co se děje?
+Dialogue: 0,1:44:17.60,1:44:21.28,Default,,0,0,0,,Měl jsem jenom hroznou představu.\NCo když tohle je jenom sen?
+Dialogue: 0,1:44:22.76,1:44:25.68,Default,,0,0,0,,Tak mi dej ryhcle pusu\Nnež se probudĂ­Å¡.
diff --git a/tests/ref/fate/sub-charenc b/tests/ref/fate/sub-charenc
new file mode 100644
index 0000000000..ed5cdbe5c7
--- /dev/null
+++ b/tests/ref/fate/sub-charenc
@@ -0,0 +1,62 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:32.95,0:00:38.25,Default,,0,0,0,,ĐĐĐ›Đ£ĐœĐ‘Đ˜Đ ĐŸĐ˜ĐĐ§ĐªĐ Đ¡ - ĐĐ—Đ˜Đ¯\NĐ¡ĐĐĐ˜ ĐŸĐ˜ĐĐ§ĐªĐ Đ¡ и Đ•.Đ•. Co.\NĐ¿Ñ€ĐµĐ´ÑÑ‚Đ°Đ²ÑÑ‚
+Dialogue: 0,0:00:52.76,0:00:58.60,Default,,0,0,0,,Đ¢ Đ˜ Đ“ Đª Đ  Đ˜ Đ” Đ  Đ Đ Đ Đ
+Dialogue: 0,0:01:22.17,0:01:24.05,Default,,0,0,0,,Đ£Ñ‡Đ¸Ñ‚ĐµĐ»ÑÑ‚ Ли е Ñ‚ÑƒĐº.
+Dialogue: 0,0:01:45.48,0:01:47.32,Default,,0,0,0,,Đ¨Ñƒ Đ›Đ¸ĐµĐ½!
+Dialogue: 0,0:01:54.53,0:01:57.24,Default,,0,0,0,,Ли ĐœÑƒ Đ‘Đ°Đ¹ е Ñ‚ÑƒĐº.
+Dialogue: 0,0:02:05.83,0:02:09.00,Default,,0,0,0,,- ĐĐ°Đº Đ²ÑÑ€Đ²ÑÑ‚ Đ½ĐµÑ‰Đ°Ñ‚Đ°?\N- Đ”Đ¾Đ±Ñ€Đµ. ĐœĐ¾Đ»Ñ, Đ²Đ»ĐµĐ·Ñ‚Đµ!
+Dialogue: 0,0:02:23.48,0:02:26.52,Default,,0,0,0,,ĐœÑƒ Đ‘Đ°Đ¹...\NĐœĐ¸Đ½Đ° Đ¼Đ½Đ¾Đ³Đ¾ Đ²Ñ€ĐµĐ¼Đµ.
+Dialogue: 0,0:02:26.73,0:02:28.11,Default,,0,0,0,,Đ¢Đ°ĐºĐ° е.
+Dialogue: 0,0:02:28.57,0:02:31.41,Default,,0,0,0,,- ĐĐ°Đº Đ²ÑÑ€Đ²Đ¸ Đ±Đ¸Đ·Đ½ĐµÑÑÑ‚?\N- Đ”Đ¾Đ±Ñ€Đµ.
+Dialogue: 0,0:02:31.61,0:02:33.90,Default,,0,0,0,,- Đ Ñ‚Đ¸ ĐºĐ°Đº Ñи?\N- Đ”Đ¾Đ±Ñ€Đµ.
+Dialogue: 0,0:02:40.16,0:02:42.79,Default,,0,0,0,,ĐœĐ¾Đ½Đ°Ñ…ÑÑ‚ Đ”Đ·ĐµĐ½Đ³ ĐºĐ°Đ·Đ°,\NÑ‡Đµ Ñи Đ² Đ¿Đ»Đ°Đ½Đ¸Đ½Đ°Ñ‚Đ° Đ£Đ´Đ°Đ½.
+Dialogue: 0,0:02:43.04,0:02:46.54,Default,,0,0,0,,ĐĐ°Đ·Đ°, Ñ‡Đµ Đ¿Ñ€Đ°ĐºÑ‚Đ¸ĐºÑƒĐ²Đ°Ñˆ\NĐ´ÑĐ»Đ±Đ¾ĐºĐ° Đ¼ĐµĐ´Đ¸Ñ‚Đ°Ñ†Đ¸Ñ.
+Dialogue: 0,0:02:48.84,0:02:50.68,Default,,0,0,0,,Đ¡Đ¸Đ³ÑƒÑ€Đ½Đ¾ Đ² Đ¿Đ»Đ°Đ½Đ¸Đ½Đ°Ñ‚Đ°\Nе Đ¼Đ½Đ¾Đ³Đ¾ ÑĐ¿Đ¾ĐºĐ¾Đ¹Đ½Đ¾.
+Dialogue: 0,0:02:51.25,0:02:53.46,Default,,0,0,0,,Đ—Đ°Đ²Đ¸Đ¶Đ´Đ°Đ¼ Ñ‚Đ¸.
+Dialogue: 0,0:02:53.67,0:02:58.34,Default,,0,0,0,,Đ˜Đ¼Đ°Đ¼ Ñ‚Đ¾Đ»ĐºĐ¾Đ²Đ° Đ¼Đ½Đ¾Đ³Đ¾ Ñ€Đ°Đ±Đ¾Ñ‚Đ°,\NĐ¿Đ¾Ñ‡Ñ‚Đ¸ Đ½Đµ Đ¼Đ¸ Đ¾ÑÑ‚Đ°Đ²Đ°\NĐ²Ñ€ĐµĐ¼Đµ Đ·Đ° Đ¿Đ¾Ñ‡Đ¸Đ²ĐºĐ°.
+Dialogue: 0,0:03:00.26,0:03:03.89,Default,,0,0,0,,ĐÑÑ‚Đ°Đ²Đ¸Ñ… Đ¾Đ±ÑƒÑ‡ĐµĐ½Đ¸ĐµÑ‚Đ¾ Ñ€Đ°Đ½Đ¾.
+Dialogue: 0,0:03:05.69,0:03:11.28,Default,,0,0,0,,Đ—Đ°Ñ‰Đ¾? Đ¢Đ¸ Ñи Đ±Đ¾ĐµÑ† Đ½Đ° Đ£Đ´Đ°Đ½.\NĐĐ±ÑƒÑ‡ĐµĐ½Đ¸ĐµÑ‚Đ¾ е Đ²ÑĐ¸Ñ‡ĐºĐ¾.
+Dialogue: 0,0:03:11.90,0:03:14.86,Default,,0,0,0,,ĐŸĐ¾ Đ²Ñ€ĐµĐ¼Đµ Đ½Đ° Đ¼ĐµĐ´Đ¸Ñ‚Đ°Ñ†Đ¸Ñ…
+Dialogue: 0,0:03:15.07,0:03:18.49,Default,,0,0,0,,ÑÑ‚Đ¸Đ³Đ½Đ°Ñ… Đ´Đ¾ Đ¼ÑÑÑ‚Đ¾,\NĐºÑĐ´ĐµÑ‚Đ¾ Đ¸Đ¼Đ°ÑˆĐµ Đ´ÑĐ»Đ±Đ¾ĐºĐ° Ñ‚Đ¸ÑˆĐ¸Đ½Đ°...
+Dialogue: 0,0:03:19.87,0:03:22.79,Default,,0,0,0,,бÑÑ… Đ¾Đ±Đ³Ñ€Đ°Đ´ĐµĐ½ Đ¾Ñ‚ ÑĐ²ĐµÑ‚Đ»Đ¸Đ½Đ°...
+Dialogue: 0,0:03:23.41,0:03:28.08,Default,,0,0,0,,Đ²Ñ€ĐµĐ¼ĐµÑ‚Đ¾ и Đ¿Ñ€Đ¾ÑÑ‚Ñ€Đ°Đ½ÑÑ‚Đ²Đ¾Ñ‚Đ¾ Đ¸Đ·Ñ‡ĐµĐ·Đ½Đ°Ñ…Đ°.
+Dialogue: 0,0:03:28.71,0:03:34.09,Default,,0,0,0,,Đ”Đ¾ÑÑ‚Đ¸Đ³Đ½Đ°Ñ… Đ´Đ¾ ÑÑÑÑ‚Đ¾ÑĐ½Đ¸Đµ, Đ·Đ° ĐºĐ¾ĐµÑ‚Đ¾\NÑƒÑ‡Đ¸Ñ‚ĐµĐ»ÑÑ‚ Đ½Đµ Đ¼Đ¸ Đ±ĐµÑˆĐµ ĐºĐ°Đ·Đ²Đ°Đ».
+Dialogue: 0,0:03:37.05,0:03:39.14,Default,,0,0,0,,ĐŸĐ¾ÑÑ‚Đ¸Đ³Đ½Đ°Đ» Ñи Đ¿Ñ€Đ¾ÑĐ²ĐµÑ‚Đ»ĐµĐ½Đ¸Đµ?
+Dialogue: 0,0:03:39.34,0:03:41.22,Default,,0,0,0,,Đе.
+Dialogue: 0,0:03:41.72,0:03:45.81,Default,,0,0,0,,Đе Đ¿Đ¾Ñ‡ÑƒĐ²ÑÑ‚Đ²Đ°Ñ… Đ±Đ»Đ°Đ¶ĐµĐ½ÑÑ‚Đ²Đ¾Ñ‚Đ¾\NĐ½Đ° Đ¿Ñ€Đ¾ÑĐ²ĐµÑ‚Đ»ĐµĐ½Đ¸ĐµÑ‚Đ¾.
+Dialogue: 0,0:03:46.02,0:03:52.86,Default,,0,0,0,,Đ’Đ¼ĐµÑÑ‚Đ¾ Ñ‚Đ¾Đ²Đ°... Đ¼Đµ Đ¾Đ±Đ³ÑÑ€Đ½Đ°\NĐ±ĐµĐ·ĐºÑ€Đ°Đ¹Đ½Đ° Đ¼ÑĐºĐ°.
+Dialogue: 0,0:03:53.40,0:03:56.57,Default,,0,0,0,,Đе Đ¼Đ¾Đ¶Đ°Ñ… Đ´Đ° издÑÑ€Đ¶Đ°.
+Dialogue: 0,0:03:57.49,0:03:59.74,Default,,0,0,0,,ĐŸÑ€ĐµĐºÑÑĐ½Đ°Ñ… Đ¼ĐµĐ´Đ¸Ñ‚Đ°Ñ†Đ¸ÑÑ‚Đ° Ñи.
+Dialogue: 0,0:03:59.95,0:04:02.24,Default,,0,0,0,,Đе Đ¼Đ¾Đ¶Đ°Ñ… Đ´Đ° Đ¿Ñ€Đ¾Đ´Ñлжа.
+Dialogue: 0,0:04:03.20,0:04:07.79,Default,,0,0,0,,ĐĐµÑ‰Đ¾...\NĐ¼Đµ Đ´ÑÑ€Đ¿Đ°ÑˆĐµ Đ½Đ°Đ·Đ°Đ´.
+Dialogue: 0,0:04:09.62,0:04:10.91,Default,,0,0,0,,ĐĐ°ĐºĐ²Đ¾ Đ±ĐµÑˆĐµ?
+Dialogue: 0,0:04:15.46,0:04:18.00,Default,,0,0,0,,ĐĐµÑ‰Đ¾, Đ¾Ñ‚ ĐºĐ¾ĐµÑ‚Đ¾ Đ½Đµ\NĐ¼Đ¾Đ³Đ° Đ´Đ° Ñе Đ¾ÑĐ²Đ¾Đ±Đ¾Đ´Ñ.
+Dialogue: 0,0:04:23.39,0:04:24.68,Default,,0,0,0,,Đ¡ĐºĐ¾Ñ€Đ¾ ли Ñ‰Đµ Ñ‚Ñ€ÑĐ³Đ²Đ°Ñˆ?
+Dialogue: 0,0:04:26.77,0:04:30.27,Default,,0,0,0,,ĐŸĐ¾Đ´Đ³Đ¾Ñ‚Đ²ÑĐ¼Đµ Đ¾Ñ…Ñ€Đ°Đ½Đ°\NĐ·Đ° ĐµĐ´Đ½Đ° Đ´Đ¾ÑÑ‚Đ°Đ²ĐºĐ°...
+Dialogue: 0,0:04:30.48,0:04:31.94,Default,,0,0,0,,Đ·Đ° ĐŸĐµĐºĐ¸Đ½.
+Dialogue: 0,0:04:32.56,0:04:34.10,Default,,0,0,0,,ĐœĐ¾Đ³Đ° ли Đ´Đ° Ñ‚Đµ Đ¿Đ¾Đ¼Đ¾Đ»Ñ...
+Dialogue: 0,0:04:35.07,0:04:38.82,Default,,0,0,0,,Đ´Đ° Đ·Đ°Đ½ĐµÑĐµÑˆ Đ½ĐµÑ‰Đ¾ Đ½Đ° Đ³Đ¾ÑĐ¿Đ¾Đ´Đ¸Đ½ Đ¢Đµ.
+Dialogue: 0,0:04:44.28,0:04:48.12,Default,,0,0,0,,Đ—ĐµĐ»ĐµĐ½Đ¸ÑÑ‚ Đ¼ĐµÑ‡ Đ½Đ° Đ¡ÑĐ´Đ±Đ°Ñ‚Đ°!?\NĐ”Đ°Đ²Đ°Ñˆ Đ³Đ¾ Đ½Đ° Đ³Đ¾ÑĐ¿Đ¾Đ´Đ¸Đ½ Đ¢Đµ!?
+Dialogue: 0,0:04:48.37,0:04:52.67,Default,,0,0,0,,Да. Đ¢Đ¾Đ¹ Đ²Đ¸Đ½Đ°Đ³Đ¸ е бил\NĐ½Đ°ÑˆĐ¸ÑÑ‚ Đ½Đ°Đ¹-Đ³Đ¾Đ»ÑĐ¼ Đ¿Đ¾ĐºÑ€Đ¾Đ²Đ¸Ñ‚ĐµĐ».
+Dialogue: 0,0:04:52.88,0:04:56.55,Default,,0,0,0,,Đе Ñ€Đ°Đ·Đ±Đ¸Ñ€Đ°Đ¼.\NĐĐ°Đº Đ¼Đ¾Đ¶ĐµÑˆ Đ´Đ° Ñе Ñ€Đ°Đ·Đ´ĐµĐ»Đ¸Ñˆ Ñ Đ½ĐµĐ³Đ¾?
+Dialogue: 0,0:04:56.76,0:04:59.93,Default,,0,0,0,,Đ¢Đ¾Đ¹ Đ²Đ¸Đ½Đ°Đ³Đ¸ е бил Ñ Ñ‚ĐµĐ±.
+Dialogue: 0,0:05:01.18,0:05:05.52,Default,,0,0,0,,Đ¢Đ²ÑÑ€Đ´Đµ Đ¼Đ½Đ¾Đ³Đ¾ Ñ…Đ¾Ñ€Đ° ÑĐ°\NĐ·Đ°Đ³Đ¸Đ½Đ°Đ»Đ¸ Đ¾Ñ‚ Ñ‚Đ¾Đ²Đ° Đ¾ÑÑ‚Ñ€Đ¸Đµ.
+Dialogue: 0,0:05:09.68,0:05:14.52,Default,,0,0,0,,ЧиÑÑ‚Đ¾ е ĐµĐ´Đ¸Đ½ÑÑ‚Đ²ĐµĐ½Đ¾ Đ·Đ°Ñ‰Đ¾Ñ‚Đ¾\NĐºÑ€ÑĐ²Ñ‚Đ° Ñе Đ¾Ñ‚Đ¼Đ¸Đ²Đ° леÑĐ½Đ¾.
+Dialogue: 0,0:05:15.40,0:05:20.61,Default,,0,0,0,,Đ¢Đ¸ Đ³Đ¾ Đ¸Đ·Đ¿Đ¾Đ»Đ·Đ²Đ°Ñˆ ÑĐ¿Ñ€Đ°Đ²ĐµĐ´Đ»Đ¸Đ²Đ¾.\NĐ”Đ¾ÑÑ‚Đ¾ĐµĐ½ Ñи Đ·Đ° Đ½ĐµĐ³Đ¾.
+Dialogue: 0,0:05:23.66,0:05:27.37,Default,,0,0,0,,Đ”Đ¾Đ¹Đ´Đµ Đ²Ñ€ĐµĐ¼Đµ\NĐ´Đ° Đ³Đ¾ Đ¾ÑÑ‚Đ°Đ²Ñ.
+Dialogue: 0,0:05:27.58,0:05:31.21,Default,,0,0,0,,Đ•, ĐºĐ°ĐºĐ²Đ¾ Ñ‰Đµ Đ¿Ñ€Đ°Đ²Đ¸Ñˆ\NĐ¾Ñ‚ ÑĐµĐ³Đ° Đ½Đ°Ñ‚Đ°Ñ‚ÑĐº?
+Dialogue: 0,0:05:34.71,0:05:37.50,Default,,0,0,0,,Ела Ñ Đ¼ĐµĐ½ Đ² ĐŸĐµĐºĐ¸Đ½.
+Dialogue: 0,0:05:37.71,0:05:41.42,Default,,0,0,0,,Đ›Đ¸Ñ‡Đ½Đ¾ Ñ‰Đµ Đ´Đ°Đ´ĐµÑˆ Đ¼ĐµÑ‡Đ°\NĐ½Đ° Đ³Đ¾ÑĐ¿Đ¾Đ´Đ¸Đ½ Đ¢Đµ.
+Dialogue: 0,0:05:41.68,0:05:44.89,Default,,0,0,0,,Ще бÑде ĐºĐ°ĐºÑ‚Đ¾ Đ¿Ñ€ĐµĐ´Đ¸.
+Dialogue: 0,0:05:47.01,0:05:51.68,Default,,0,0,0,,ĐŸÑÑ€Đ²Đ¾ Ñ‚Ñ€ÑĐ±Đ²Đ° Đ´Đ° Đ¾Ñ‚Đ¸Đ´Đ°\NĐ½Đ° Đ³Ñ€Đ¾Đ±Đ° Đ½Đ° ÑƒÑ‡Đ¸Ñ‚ĐµĐ»Ñ Ñи.
diff --git a/tests/ref/fate/sub-jacosub b/tests/ref/fate/sub-jacosub
new file mode 100644
index 0000000000..a30fe4a196
--- /dev/null
+++ b/tests/ref/fate/sub-jacosub
@@ -0,0 +1,23 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.12,0:00:04.36,Default,,0,0,0,,{\an5}JACOsub\N\NThis script demonstrates some of the capabilities of JACOsub.
+Dialogue: 0,0:00:04.12,0:00:14.86,Default,,0,0,0,,{\an8}Text may be positioned at the top,
+Dialogue: 0,0:00:05.12,0:00:17.46,Default,,0,0,0,,{\an5}middle,
+Dialogue: 0,0:00:06.12,0:00:20.06,Default,,0,0,0,,{\an2}or bottom of the screen.
+Dialogue: 0,0:00:08.12,0:00:27.36,Default,,0,0,0,,{\an5}{this is a comment} (And, you just saw, {another comment} timing ranges for different lines of text.
+Dialogue: 0,0:00:11.12,0:00:35.86,Default,,0,0,0,,{\an1}Within margin constraints\Nthat you set, text may be\Nleft justified,
+Dialogue: 0,0:00:13.62,0:00:42.11,Default,,0,0,0,,{\an2}{the JC is redundant - it's the default}center\Njustified,
+Dialogue: 0,0:00:14.87,0:00:45.86,Default,,0,0,0,,{\an3}and also\Nright justified.
+Dialogue: 0,0:00:22.42,0:01:12.76,Default,,0,0,0,,Text may appear in different styles\N(Normal, {\b1}Bold{\r}, {\i1}Italic{\r})
+Dialogue: 0,0:01:16.12,0:03:53.36,Default,,0,0,0,,{\an5}\N\NAt that time, you may press any key to return to the Editor.
+Dialogue: 0,0:01:16.12,0:03:53.36,Default,,0,0,0,,OK, this script will be finished when the screen goes blank.
diff --git a/tests/ref/fate/sub-microdvd b/tests/ref/fate/sub-microdvd
new file mode 100644
index 0000000000..d2170bc2a4
--- /dev/null
+++ b/tests/ref/fate/sub-microdvd
@@ -0,0 +1,22 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Comic Sans MS,30,&H123456,&H123456,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:40.00,0:00:52.00,Default,,0,0,0,,{\c&H345678&}foo{\c}\N{\c&HABCDEF&}bar{\c}\Nbla
+Dialogue: 0,0:00:52.00,0:00:56.00,Default,,0,0,0,,{\u1}{\s1}{\i1}{\b1}italic bold underline strike{\s0}{\u0}\Nitalic bold no-underline no-strike
+Dialogue: 0,0:00:56.00,0:01:00.00,Default,,0,0,0,,back to
+Dialogue: 0,0:01:00.00,0:01:04.00,Default,,0,0,0,,the future
+Dialogue: 0,0:01:20.00,0:01:24.92,Default,,0,0,0,,{\pos(10,20)}Some more crazy stuff
+Dialogue: 0,0:02:14.00,0:02:15.60,Default,,0,0,0,,this subtitle...
+Dialogue: 0,0:02:15.60,0:02:40.00,Default,,0,0,0,,...continues up to...
+Dialogue: 0,0:02:40.00,0:03:00.00,Default,,0,0,0,,this one.
+Dialogue: 0,0:03:04.00,0:03:12.00,Default,,0,0,0,,and now...
+Dialogue: 0,0:03:12.00,9:59:59.99,Default,,0,0,0,,...to the end of the presentation
diff --git a/tests/ref/fate/sub-microdvd-remux b/tests/ref/fate/sub-microdvd-remux
new file mode 100644
index 0000000000..a71da99031
--- /dev/null
+++ b/tests/ref/fate/sub-microdvd-remux
Binary files differ
diff --git a/tests/ref/fate/sub-movtext b/tests/ref/fate/sub-movtext
new file mode 100644
index 0000000000..6a90e967d3
--- /dev/null
+++ b/tests/ref/fate/sub-movtext
@@ -0,0 +1,15 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.97,0:00:02.54,Default,,0,0,0,,- Test 1.\N- Test 2.
+Dialogue: 0,0:00:03.05,0:00:04.74,Default,,0,0,0,,Test 3.
+Dialogue: 0,0:00:05.85,0:00:08.14,Default,,0,0,0,,- Test 4.\N- Test 5.
diff --git a/tests/ref/fate/sub-mpl2 b/tests/ref/fate/sub-mpl2
new file mode 100644
index 0000000000..72fc0fccd7
--- /dev/null
+++ b/tests/ref/fate/sub-mpl2
@@ -0,0 +1,16 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.00,0:00:01.20,Default,,0,0,0,,Foo\Nbar\Nbla
+Dialogue: 0,0:00:04.10,0:00:05.30,Default,,0,0,0,,{\i1}italic{\r}\N{\b1}bold{\r}\N{\b1}{\i1}italicbold
+Dialogue: 0,0:00:05.30,0:00:07.20,Default,,0,0,0,,{\u1}underline{\r}\Nnormal
+Dialogue: 0,0:00:08.40,0:00:12.80,Default,,0,0,0,,hello
diff --git a/tests/ref/fate/sub-mpsub b/tests/ref/fate/sub-mpsub
new file mode 100644
index 0000000000..890ceb08a2
--- /dev/null
+++ b/tests/ref/fate/sub-mpsub
@@ -0,0 +1,33 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:15.00,0:00:18.00,Default,,0,0,0,,A long, long time ago...
+Dialogue: 0,0:00:18.00,0:00:21.00,Default,,0,0,0,,in a galaxy far away...
+Dialogue: 0,0:00:21.00,0:00:24.00,Default,,0,0,0,,Naboo was under an attack.
+Dialogue: 0,0:00:25.00,0:00:27.50,Default,,0,0,0,,And I thought me and\NQui-Gon Jinn could
+Dialogue: 0,0:00:27.50,0:00:30.00,Default,,0,0,0,,talk the Federation into
+Dialogue: 0,0:00:30.00,0:00:34.00,Default,,0,0,0,,...maybe cutting them a\Nlittle slack.
+Dialogue: 0,0:00:36.00,0:00:39.00,Default,,0,0,0,,But their response, it\Ndidn't thrill us,
+Dialogue: 0,0:00:39.00,0:00:42.00,Default,,0,0,0,,They locked the doors,\Nand tried to kill us.
+Dialogue: 0,0:00:42.00,0:00:44.50,Default,,0,0,0,,We escaped from that gas,
+Dialogue: 0,0:00:44.50,0:00:48.00,Default,,0,0,0,,then met Jar-jar and\NBoss-Nass.
+Dialogue: 0,0:00:49.00,0:00:55.00,Default,,0,0,0,,We took a bongo from the\Nscene and we went to\NTheed to see the Queen.
+Dialogue: 0,0:00:55.00,0:01:00.00,Default,,0,0,0,,We all wound' up on\NTatooine.
+Dialogue: 0,0:01:00.00,0:01:06.00,Default,,0,0,0,,That's where, we've found\Nthis boy.
+Dialogue: 0,0:01:06.00,0:01:10.00,Default,,0,0,0,,Oh my, my this here\NAnakin guy,
+Dialogue: 0,0:01:10.00,0:01:15.00,Default,,0,0,0,,maybe Vader someday\Nlater now he's just\Na small fry.
+Dialogue: 0,0:01:15.00,0:01:19.00,Default,,0,0,0,,And he left his home and\Nkissed his mommy goodbye,
+Dialogue: 0,0:01:19.00,0:01:24.00,Default,,0,0,0,,singing "Soon I'm gonna be\Na Jedi!"
+Dialogue: 0,0:01:30.00,0:01:36.00,Default,,0,0,0,,Did you know this junkyard\Nslave isn't even old enough\Nto shave,
+Dialogue: 0,0:01:36.00,0:01:39.00,Default,,0,0,0,,but he can use the Force,\Nthey say.
+Dialogue: 0,0:01:40.00,0:01:46.00,Default,,0,0,0,,Ahh, do you see him hitting\Non the queen though he's\Njust nine and she's fourteen
+Dialogue: 0,0:01:46.00,0:01:52.00,Default,,0,0,0,,yeah, he's probably gonna\Nmarry her, someday!
diff --git a/tests/ref/fate/sub-mpsub-frames b/tests/ref/fate/sub-mpsub-frames
new file mode 100644
index 0000000000..64528ec70e
--- /dev/null
+++ b/tests/ref/fate/sub-mpsub-frames
@@ -0,0 +1,14 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:01.00,0:00:02.48,Default,,0,0,0,,Start at 1sec,\Nlast 1.5 seconds
+Dialogue: 0,0:00:02.52,0:00:11.52,Default,,0,0,0,,One frame later,\Nduring 9 seconds
diff --git a/tests/ref/fate/sub-pjs b/tests/ref/fate/sub-pjs
new file mode 100644
index 0000000000..799c62b2a3
--- /dev/null
+++ b/tests/ref/fate/sub-pjs
@@ -0,0 +1,15 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:04:04.70,0:04:11.30,Default,,0,0,0,,You should come to the Drama Club, too.
+Dialogue: 0,0:04:11.30,0:04:19.40,Default,,0,0,0,,Yeah. The Drama Club is worried\Nthat you haven't been coming.
+Dialogue: 0,0:04:20.30,0:04:27.50,Default,,0,0,0,,I see. Sorry, I'll drop by next time.
diff --git a/tests/ref/fate/sub-realtext b/tests/ref/fate/sub-realtext
new file mode 100644
index 0000000000..cd9aa5a294
--- /dev/null
+++ b/tests/ref/fate/sub-realtext
@@ -0,0 +1,17 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,,Mary had a little lamb, \N
+Dialogue: 0,0:00:03.00,0:00:18.00,Default,,0,0,0,,little lamb, \N
+Dialogue: 0,0:00:06.99,0:00:21.99,Default,,0,0,0,,little lamb, \N
+Dialogue: 0,0:00:09.00,0:00:23.00,Default,,0,0,0,,Mary had a little lamb \N
+Dialogue: 0,0:00:12.34,0:00:27.34,Default,,0,0,0,,whose fleece was white as snow.
diff --git a/tests/ref/fate/sub-sami b/tests/ref/fate/sub-sami
new file mode 100644
index 0000000000..caa85a268f
--- /dev/null
+++ b/tests/ref/fate/sub-sami
@@ -0,0 +1,21 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.00,0:00:00.01,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\N
+Dialogue: 0,0:00:00.01,0:00:08.80,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\NLet the word go forth, from this time and place to friend and foe alike that the torch
+Dialogue: 0,0:00:08.80,0:00:19.50,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\Nhas been passed to a new generation of Americans, born in this century, tempered by war,
+Dialogue: 0,0:00:19.50,0:00:28.00,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\Ndisciplined by a hard and bitter peace, proud of our ancient heritage, and unwilling to witness
+Dialogue: 0,0:00:28.00,0:00:38.00,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\Nor permit the slow undoing of those human rights to which this nation has always
+Dialogue: 0,0:00:38.00,0:00:46.00,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\Nbeen committed and to which we are committed today at home and around the world.
+Dialogue: 0,0:00:46.00,0:01:01.00,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\NLet every nation know, whether it wishes us well or ill, that we shall pay any price, bear any burden,
+Dialogue: 0,0:01:01.00,0:01:13.00,Default,,0,0,0,,{\i1}Pres. John F. Kennedy {\i0}\Nmeet any hardship, support any friend, oppose any foe, to ensure the survival and success of liberty.
+Dialogue: 0,0:01:13.00,9:59:59.99,Default,,0,0,0,,{\i1}End of: {\i0}\NPresident John F. Kennedy Speech
diff --git a/tests/ref/fate/sub-srt b/tests/ref/fate/sub-srt
index 5a1466437e..40b20cde90 100644
--- a/tests/ref/fate/sub-srt
+++ b/tests/ref/fate/sub-srt
@@ -1 +1,49 @@
-03b2a3f7e7e83624c8e4d1b5569df758
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.00,0:00:00.00,Default,,0,0,0,,Don't show this text it may be used to insert hidden data
+Dialogue: 0,0:00:01.50,0:00:04.50,Default,,0,0,0,,SubRip subtitles capability tester 1.3o by ale5000\N{\b1}{\i1}Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others{\i0}{\b0}\N{\c&HFF0000&}This text should be blue{\c}\N{\c&HFF&}This text should be red{\c}\N{\c&H0&}This text should be black{\c}\N{\fnWebdings}If you see this with the normal font, the player don't (fully) support font face{\fn}
+Dialogue: 0,0:00:04.50,0:00:04.50,Default,,0,0,0,,Hidden
+Dialogue: 0,0:00:04.50,0:00:07.50,Default,,0,0,0,,{\fs8}This text should be small{\fs}\NThis text should be normal\N{\fs35}This text should be big{\fs}
+Dialogue: 0,0:00:07.50,0:00:11.50,Default,,0,0,0,,This should be an E with an accent: Ăˆ\N日本èª\N{\fs30}{\b1}{\i1}{\u1}This text should be bold, italics and underline{\u0}{\i0}{\b0}{\fs}\N{\fs9}{\c&HFF00&}This text should be small and green{\c}{\fs}\N{\fs9}{\c&HFF&}This text should be small and red{\c}{\fs}\N{\fs24}{\c&H2A2AA5&}This text should be big and brown{\c}{\fs}
+Dialogue: 0,0:00:11.50,0:00:14.50,Default,,0,0,0,,{\b1}This line should be bold{\b0}\N{\i1}This line should be italics{\i0}\N{\u1}This line should be underline{\u0}\N{\s1}This line should be strikethrough{\s0}\N{\u1}Both lines\Nshould be underline{\u0}
+Dialogue: 0,0:00:14.50,0:00:17.50,Default,,0,0,0,,>\NIt would be a good thing to\Nhide invalid html tags that are closed and show the text in them\N<invalid_tag_unclosed>but show un-closed invalid html tags\NShow not opened tags</invalid_tag_not_opened>\N<
+Dialogue: 0,0:00:17.50,0:00:20.50,Default,,0,0,0,,and also\Nhide invalid html tags with parameters that are closed and show the text in them\N<invalid_tag_uc par=5>but show un-closed invalid html tags\N{\u1}This text should be showed underlined without problems also: 2<3,5>1,4<6{\u0}\NThis shouldn't be underlined
+Dialogue: 0,0:00:20.50,0:00:21.50,Default,,0,0,0,,This text should be in the normal position...
+Dialogue: 0,0:00:21.50,0:00:22.50,Default,,0,0,0,,{\an5}{\pos(0,45)}This text should NOT be in the normal position
+Dialogue: 0,0:00:22.50,0:00:24.50,Default,,0,0,0,,Implementation is the same of the ASS tag\N{\an8}This text should be at the\Ntop and horizontally centered
+Dialogue: 0,0:00:22.50,0:00:24.50,Default,,0,0,0,,{\an5}This text should be at the\Nmiddle and horizontally centered
+Dialogue: 0,0:00:22.50,0:00:24.50,Default,,0,0,0,,{\an2}This text should be at the\Nbottom and horizontally centered
+Dialogue: 0,0:00:24.50,0:00:26.50,Default,,0,0,0,,This text should be at the\Ntop and horizontally at the left{\an7}
+Dialogue: 0,0:00:24.50,0:00:26.50,Default,,0,0,0,,{\an4}This text should be at the\Nmiddle and horizontally at the left\N(The second position must be ignored)
+Dialogue: 0,0:00:24.50,0:00:26.50,Default,,0,0,0,,{\an1}This text should be at the\Nbottom and horizontally at the left
+Dialogue: 0,0:00:26.50,0:00:28.50,Default,,0,0,0,,{\an9}This text should be at the\Ntop and horizontally at the right
+Dialogue: 0,0:00:26.50,0:00:28.50,Default,,0,0,0,,{\an6}This text should be at the\Nmiddle and horizontally at the right
+Dialogue: 0,0:00:26.50,0:00:28.50,Default,,0,0,0,,{\an3}This text should be at the\Nbottom and horizontally at the right
+Dialogue: 0,0:00:28.50,0:00:31.50,Default,,0,0,0,,{\fs6}{\c&HFF00&}This could be the {\fs35}m{\c&H0&}o{\c&HFF00&}st{\fs6} difficult thing to implement{\c}{\fs}
+Dialogue: 0,0:00:31.50,0:00:50.50,Default,,0,0,0,,First text
+Dialogue: 0,0:00:33.50,0:00:35.50,Default,,0,0,0,,Second, it shouldn't overlap first
+Dialogue: 0,0:00:35.50,0:00:37.50,Default,,0,0,0,,Third, it should replace second
+Dialogue: 0,0:00:36.50,0:00:50.50,Default,,0,0,0,,Fourth, it shouldn't overlap first and third
+Dialogue: 0,0:00:40.50,0:00:45.50,Default,,0,0,0,,Fifth, it should replace third
+Dialogue: 0,0:00:45.50,0:00:50.50,Default,,0,0,0,,Sixth, it shouldn't be\Nshowed overlapped
+Dialogue: 0,0:00:50.50,0:00:52.50,Default,,0,0,0,,TEXT 1 (bottom)
+Dialogue: 0,0:00:50.50,0:00:52.50,Default,,0,0,0,,text 2
+Dialogue: 0,0:00:52.50,0:00:54.50,Default,,0,0,0,,Hide these tags:\Nalso hide these tags:\Nbut show this: {normal text}
+Dialogue: 0,0:00:54.50,0:01:00.50,Default,,0,0,0,,{\an8}\N\ N is a forced line break\N\ h is a hard space\NNormal spaces at the start and at the end of the line are trimmed while hard spaces are not trimmed.\NThe\hline\hwill\hnever\hbreak\hautomatically\hright\hbefore\hor\hafter\ha\hhard\hspace.\h:-D
+Dialogue: 0,0:00:54.50,0:00:56.50,Default,,0,0,0,,{\an1}\N\h\h\h\h\hA (05 hard spaces followed by a letter)\NA (Normal spaces followed by a letter)\NA (No hard spaces followed by a letter)
+Dialogue: 0,0:00:56.50,0:00:58.50,Default,,0,0,0,,\h\h\h\h\hA (05 hard spaces followed by a letter)\NA (Normal spaces followed by a letter)\NA (No hard spaces followed by a letter)\NShow this: \TEST and this: \-)
+Dialogue: 0,0:00:58.50,0:01:00.50,Default,,0,0,0,,{\an3}\NA letter followed by 05 hard spaces: A\h\h\h\h\h\NA letter followed by normal spaces: A\NA letter followed by no hard spaces: A\N05 hard spaces between letters: A\h\h\h\h\hA\N5 normal spaces between letters: A A\N\N^--Forced line break
+Dialogue: 0,0:01:00.50,0:01:02.50,Default,,0,0,0,,{\s1}Both line should be strikethrough,\Nyes.{\s0}\NCorrectly closed tags\Nshould be hidden.
+Dialogue: 0,0:01:02.50,0:01:04.50,Default,,0,0,0,,It shouldn't be strikethrough,\Nnot opened tag showed as text.</s>\NNot opened tag showed as text.</xxxxx>
+Dialogue: 0,0:01:04.50,0:01:06.50,Default,,0,0,0,,{\s1}Three lines should be strikethrough,\Nyes.\N<yyyy>Not closed tags showed as text
+Dialogue: 0,0:01:06.50,0:01:08.50,Default,,0,0,0,,{\s1}Both line should be strikethrough but\Nthe wrong closing tag should be showed</b>
diff --git a/tests/ref/fate/sub-stl b/tests/ref/fate/sub-stl
new file mode 100644
index 0000000000..cde33cd7cd
--- /dev/null
+++ b/tests/ref/fate/sub-stl
@@ -0,0 +1,29 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:31.02,0:00:33.00,Default,,0,0,0,,Hello, my name is Axel Kornmesser.
+Dialogue: 0,0:00:45.02,0:00:49.13,Default,,0,0,0,,It is always a pleasure to work with ESA astronomers.
+Dialogue: 0,0:00:49.13,0:00:52.03,Default,,0,0,0,,The "Eyes on The Skies" documentary
+Dialogue: 0,0:00:52.03,0:00:55.09,Default,,0,0,0,,was our second collaboration
+Dialogue: 0,0:00:55.09,0:00:58.07,Default,,0,0,0,,after a great \Nexperience in 2005,
+Dialogue: 0,0:00:58.07,0:00:59.20,Default,,0,0,0,,when \Nwe did the story about the
+Dialogue: 0,0:00:59.20,0:01:04.01,Default,,0,0,0,,Hubble Telescope "15 Years of Discovery".
+Dialogue: 0,0:01:04.16,0:01:07.04,Default,,0,0,0,,It was a lot of fun again.
+Dialogue: 0,0:01:15.04,0:01:18.16,Default,,0,0,0,,We usually \N don't get the final film \Nbefore we start composing
+Dialogue: 0,0:01:18.21,0:01:22.02,Default,,0,0,0,,We had a script and many details about the story,
+Dialogue: 0,0:01:22.10,0:01:26.08,Default,,0,0,0,,and so we worked\N in parallel \Nin the movie production
+Dialogue: 0,0:01:27.04,0:01:30.17,Default,,0,0,0,,The largest part of \N the soundtrack \Nwas done without seeing a movie
+Dialogue: 0,0:01:30.17,0:01:36.06,Default,,0,0,0,,It was no problem, but very inspiring \Nand a free working process.
+Dialogue: 0,0:02:08.13,0:02:10.23,Default,,0,0,0,,Galileo's theme is one of my favourites.
+Dialogue: 0,0:02:10.23,0:02:14.10,Default,,0,0,0,,We did a lot of different versions \Nabout the central theme.
+Dialogue: 0,0:02:14.10,0:02:18.02,Default,,0,0,0,,For the 17th century \N we used a nice harpsichord
+Dialogue: 0,0:02:19.05,0:02:22.09,Default,,0,0,0,,and so we landed directly into Galileo's time.
diff --git a/tests/ref/fate/sub-subripenc b/tests/ref/fate/sub-subripenc
new file mode 100644
index 0000000000..1f1e031643
--- /dev/null
+++ b/tests/ref/fate/sub-subripenc
@@ -0,0 +1,14 @@
+1
+00:00:00,970 --> 00:00:02,540
+- Test 1.
+- Test 2.
+
+2
+00:00:03,050 --> 00:00:04,740
+Test 3.
+
+3
+00:00:05,850 --> 00:00:08,140
+- Test 4.
+- Test 5.
+
diff --git a/tests/ref/fate/sub-subviewer b/tests/ref/fate/sub-subviewer
new file mode 100644
index 0000000000..19944f6416
--- /dev/null
+++ b/tests/ref/fate/sub-subviewer
@@ -0,0 +1,15 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:01:00.10,0:02:00.20,Default,,0,0,0,,Hello.\NWorld!
+Dialogue: 0,0:02:00.30,0:03:00.40,Default,,0,0,0,,\Nfoo\Nbar\Nbla\Nmixed with br
+Dialogue: 0,0:03:04.12,0:03:10.20,Default,,0,0,0,,Another event.
diff --git a/tests/ref/fate/sub-subviewer1 b/tests/ref/fate/sub-subviewer1
new file mode 100644
index 0000000000..a75406b857
--- /dev/null
+++ b/tests/ref/fate/sub-subviewer1
@@ -0,0 +1,22 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:03:45.00,0:03:48.00,Default,,0,0,0,,- ToIerĂ¡biIis?\N- Azt jeIenti: tűrhetÅ‘.
+Dialogue: 0,0:03:48.00,0:03:51.00,Default,,0,0,0,,Tudom, mit jeIent. Megnézhetem?
+Dialogue: 0,0:03:52.00,0:03:54.00,Default,,0,0,0,,TiszteIt bĂ­rĂ³nÅ‘.
+Dialogue: 0,0:03:57.00,0:04:00.00,Default,,0,0,0,,KĂ©pzeIje magĂ¡t\Na környĂ©kbeIi gyermekek heIyĂ©be.
+Dialogue: 0,0:04:01.00,0:04:05.00,Default,,0,0,0,,Naphosszat monoton, döngöIÅ‘ zaj\Nszaggatja a dobhĂ¡rtyĂ¡jukat.
+Dialogue: 0,0:04:05.00,0:04:10.00,Default,,0,0,0,,Ahogy egyre föIĂ©bĂ¼k tornyosuI,\NrĂ¡juk veti sötĂ©t Ă¡rnyĂ©kĂ¡t.
+Dialogue: 0,0:04:10.00,0:04:15.00,Default,,0,0,0,,Ez a feIhÅ‘karcoIĂ³, az emberi\NmohĂ³sĂ¡g Ăºjabb emIĂ©kműve.
+Dialogue: 0,1:50:38.00,1:50:41.00,Default,,0,0,0,,kĂ©szen Ă¡IIok.
+Dialogue: 0,1:51:00.00,1:51:03.00,Default,,0,0,0,,Joe ... Miguel keres.
+Dialogue: 0,2:00:18.00,9:59:59.99,Default,,0,0,0,,Magyar szöveg: Nikowvitz OszkĂ¡r
diff --git a/tests/ref/fate/sub-vplayer b/tests/ref/fate/sub-vplayer
new file mode 100644
index 0000000000..6e804f6c22
--- /dev/null
+++ b/tests/ref/fate/sub-vplayer
@@ -0,0 +1,15 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:00.12,0:00:23.51,Default,,0,0,0,,Hello
+Dialogue: 0,0:00:23.51,0:01:02.05,Default,,0,0,0,,World
+Dialogue: 0,0:01:02.05,9:59:59.99,Default,,0,0,0,,!\Nnewline
diff --git a/tests/ref/fate/sub-webvtt b/tests/ref/fate/sub-webvtt
new file mode 100644
index 0000000000..8c63a90279
--- /dev/null
+++ b/tests/ref/fate/sub-webvtt
@@ -0,0 +1,27 @@
+[Script Info]
+; Script generated by FFmpeg/Lavc
+ScriptType: v4.00+
+PlayResX: 384
+PlayResY: 288
+
+[V4+ Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
+Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,0
+
+[Events]
+Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: 0,0:00:11.00,0:00:13.00,Default,,0,0,0,,We are in New York City\NRandom line added
+Dialogue: 0,0:00:13.00,0:00:16.00,Default,,0,0,0,,We're actually at the Lucern Hotel, just down the street
+Dialogue: 0,0:00:16.00,0:00:18.00,Default,,0,0,0,,from the American Museum of Natural History
+Dialogue: 0,0:00:18.00,0:00:20.00,Default,,0,0,0,,And with me is Neil deGrasse Tyson
+Dialogue: 0,0:00:20.00,0:00:22.00,Default,,0,0,0,,Astrophysicist, Director of the Hayden Planetarium
+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: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.
+Dialogue: 0,0:00:50.00,0:00:51.13,Default,,0,0,0,,This event and the following\None have CLRF
+Dialogue: 0,0:59:00.12,1:23:45.68,Default,,0,0,0,,Obiwan Kenobi
diff --git a/tests/ref/fate/sub-webvttenc b/tests/ref/fate/sub-webvttenc
new file mode 100644
index 0000000000..dbeadb0c2c
--- /dev/null
+++ b/tests/ref/fate/sub-webvttenc
@@ -0,0 +1,177 @@
+WEBVTT
+
+00:00.000 --> 00:00.000
+Don't show this text it may be used to insert hidden data
+
+00:01.500 --> 00:04.500
+SubRip subtitles capability tester 1.3o by ale5000
+<b><i>Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others</i></b>
+This text should be blue
+This text should be red
+This text should be black
+If you see this with the normal font, the player don't (fully) support font face
+
+00:04.500 --> 00:04.500
+Hidden
+
+00:04.501 --> 00:07.501
+This text should be small
+This text should be normal
+This text should be big
+
+00:07.501 --> 00:11.501
+This should be an E with an accent: Ăˆ
+日本èª
+<b><i><u>This text should be bold, italics and underline</u></i></b>
+This text should be small and green
+This text should be small and red
+This text should be big and brown
+
+00:11.501 --> 00:14.501
+<b>This line should be bold</b>
+<i>This line should be italics</i>
+<u>This line should be underline</u>
+This line should be strikethrough
+<u>Both lines
+should be underline</u>
+
+00:14.501 --> 00:17.501
+>
+It would be a good thing to
+hide invalid html tags that are closed and show the text in them
+<invalid_tag_unclosed>but show un-closed invalid html tags
+Show not opened tags</invalid_tag_not_opened>
+<
+
+00:17.501 --> 00:20.501
+and also
+hide invalid html tags with parameters that are closed and show the text in them
+<invalid_tag_uc par=5>but show un-closed invalid html tags
+<u>This text should be showed underlined without problems also: 2<3,5>1,4<6</u>
+This shouldn't be underlined
+
+00:20.501 --> 00:21.501
+This text should be in the normal position...
+
+00:21.501 --> 00:22.501
+This text should NOT be in the normal position
+
+00:22.501 --> 00:24.501
+Implementation is the same of the ASS tag
+This text should be at the
+top and horizontally centered
+
+00:22.501 --> 00:24.501
+This text should be at the
+middle and horizontally centered
+
+00:22.501 --> 00:24.501
+This text should be at the
+bottom and horizontally centered
+
+00:24.501 --> 00:26.501
+This text should be at the
+top and horizontally at the left
+
+00:24.501 --> 00:26.501
+This text should be at the
+middle and horizontally at the left
+(The second position must be ignored)
+
+00:24.501 --> 00:26.501
+This text should be at the
+bottom and horizontally at the left
+
+00:26.501 --> 00:28.501
+This text should be at the
+top and horizontally at the right
+
+00:26.501 --> 00:28.501
+This text should be at the
+middle and horizontally at the right
+
+00:26.501 --> 00:28.501
+This text should be at the
+bottom and horizontally at the right
+
+00:28.501 --> 00:31.501
+This could be the most difficult thing to implement
+
+00:31.501 --> 00:50.501
+First text
+
+00:33.500 --> 00:35.500
+Second, it shouldn't overlap first
+
+00:35.501 --> 00:37.501
+Third, it should replace second
+
+00:36.501 --> 00:50.501
+Fourth, it shouldn't overlap first and third
+
+00:40.501 --> 00:45.501
+Fifth, it should replace third
+
+00:45.501 --> 00:50.501
+Sixth, it shouldn't be
+showed overlapped
+
+00:50.501 --> 00:52.501
+TEXT 1 (bottom)
+
+00:50.501 --> 00:52.501
+text 2
+
+00:52.501 --> 00:54.501
+Hide these tags:
+also hide these tags:
+but show this: {normal text}
+
+00:54.501 --> 01:00.501
+
+\ N is a forced line break
+\ h is a hard space
+Normal spaces at the start and at the end of the line are trimmed while hard spaces are not trimmed.
+The\hline\hwill\hnever\hbreak\hautomatically\hright\hbefore\hor\hafter\ha\hhard\hspace.\h:-D
+
+00:54.501 --> 00:56.501
+
+\h\h\h\h\hA (05 hard spaces followed by a letter)
+A (Normal spaces followed by a letter)
+A (No hard spaces followed by a letter)
+
+00:56.501 --> 00:58.501
+\h\h\h\h\hA (05 hard spaces followed by a letter)
+A (Normal spaces followed by a letter)
+A (No hard spaces followed by a letter)
+Show this: \TEST and this: \-)
+
+00:58.501 --> 01:00.501
+
+A letter followed by 05 hard spaces: A\h\h\h\h\h
+A letter followed by normal spaces: A
+A letter followed by no hard spaces: A
+05 hard spaces between letters: A\h\h\h\h\hA
+5 normal spaces between letters: A A
+
+^--Forced line break
+
+01:00.501 --> 01:02.501
+Both line should be strikethrough,
+yes.
+Correctly closed tags
+should be hidden.
+
+01:02.501 --> 01:04.501
+It shouldn't be strikethrough,
+not opened tag showed as text.</s>
+Not opened tag showed as text.</xxxxx>
+
+01:04.501 --> 01:06.501
+Three lines should be strikethrough,
+yes.
+<yyyy>Not closed tags showed as text
+
+01:06.501 --> 01:08.501
+Both line should be strikethrough but
+the wrong closing tag should be showed</b>
diff --git a/tests/ref/fate/sub2video b/tests/ref/fate/sub2video
new file mode 100644
index 0000000000..5c2c46a6fc
--- /dev/null
+++ b/tests/ref/fate/sub2video
@@ -0,0 +1,97 @@
+#extradata 1: 150, 0x7c99258b
+#tb 0: 1/5
+#tb 1: 1/1000
+0, 0, 0, 1, 518400, 0x83c27b82
+0, 1, 1, 1, 518400, 0x4051c7f9
+0, 2, 2, 1, 518400, 0xfb00e17e
+1, 499, 499, 4960, 1015, 0x19e092d2, F=0x0
+0, 3, 3, 1, 518400, 0x192abb74
+0, 4, 4, 1, 518400, 0x4669a88b
+0, 5, 5, 1, 518400, 0xaababe00
+0, 6, 6, 1, 518400, 0x98a211a5
+0, 7, 7, 1, 518400, 0x440e7547
+0, 8, 8, 1, 518400, 0xca5bb496
+0, 9, 9, 1, 518400, 0xf86e0b0a
+0, 10, 10, 1, 518400, 0xb80fa020
+0, 11, 11, 1, 518400, 0x41c2a54b
+0, 12, 12, 1, 518400, 0x51baf353
+0, 13, 13, 1, 518400, 0x967ea7f3
+0, 14, 14, 1, 518400, 0x819e7f89
+0, 15, 15, 1, 518400, 0x192233e1
+0, 16, 16, 1, 518400, 0xc80a0eb3
+0, 17, 17, 1, 518400, 0x08260a23
+0, 18, 18, 1, 518400, 0xc92e2caf
+0, 19, 19, 1, 518400, 0x3fe36eea
+0, 20, 20, 1, 518400, 0x0891e8d5
+0, 21, 21, 1, 518400, 0x84655095
+0, 22, 22, 1, 518400, 0x9c7fa014
+0, 23, 23, 1, 518400, 0x9c43b656
+0, 24, 24, 1, 518400, 0x2cf46221
+0, 25, 25, 1, 518400, 0x7322e11c
+0, 26, 26, 1, 518400, 0x45af1a84
+0, 27, 27, 1, 518400, 0x7b781071
+0, 28, 28, 1, 518400, 0x4f7c706c
+0, 29, 29, 1, 518400, 0xb227603b
+0, 30, 30, 1, 518400, 0x7b4b89c2
+0, 31, 31, 1, 518400, 0x456da21e
+0, 32, 32, 1, 518400, 0xb691979f
+0, 33, 33, 1, 518400, 0x0dfaa66d
+0, 34, 34, 1, 518400, 0x191a6f23
+0, 35, 35, 1, 518400, 0xa03b2605
+0, 36, 36, 1, 518400, 0xb36aff87
+0, 37, 37, 1, 518400, 0xf5f0bc4a
+0, 38, 38, 1, 518400, 0x863d701a
+0, 39, 39, 1, 518400, 0xd11b4dce
+0, 40, 40, 1, 518400, 0x969236bd
+0, 41, 41, 1, 518400, 0xb60a485c
+0, 42, 42, 1, 518400, 0xe9796621
+0, 43, 43, 1, 518400, 0x3e8fc04b
+0, 44, 44, 1, 518400, 0xac9944e3
+0, 45, 45, 1, 518400, 0x01452b4d
+0, 46, 46, 1, 518400, 0xb384f6d2
+0, 47, 47, 1, 518400, 0xde69683f
+0, 48, 48, 1, 518400, 0x7df08fba
+0, 49, 49, 1, 518400, 0xbab197ea
+0, 50, 50, 1, 518400, 0x902285d9
+1, 15355, 15355, 4733, 2094, 0x3c171425, F=0x0
+1, 48797, 48797, 2560, 2480, 0x7c0edf21, F=0x0
+1, 51433, 51433, 2366, 3059, 0xc95b8a05, F=0x0
+1, 53910, 53910, 2696, 2095, 0x61bb15ed, F=0x0
+1, 56663, 56663, 1262, 1013, 0xc9ae89b7, F=0x0
+1, 58014, 58014, 1661, 969, 0xe01878f0, F=0x0
+1, 67724, 67724, 1365, 844, 0xe7db4fc1, F=0x0
+1, 69175, 69175, 1558, 802, 0xf48531ba, F=0x0
+1, 70819, 70819, 1865, 1709, 0xb4d5a1bd, F=0x0
+1, 72762, 72762, 1968, 2438, 0x99d7bc82, F=0x0
+1, 74806, 74806, 1831, 2116, 0x96514097, F=0x0
+1, 76716, 76716, 1262, 1822, 0xefccc72e, F=0x0
+1, 78051, 78051, 1524, 987, 0x7b927a27, F=0x0
+1, 79644, 79644, 2662, 2956, 0x190778f7, F=0x0
+1, 82380, 82380, 2764, 3094, 0xc021b7d3, F=0x0
+1, 85225, 85225, 2366, 2585, 0x74d0048f, F=0x0
+1, 87652, 87652, 1831, 634, 0x8832fda1, F=0x0
+1, 91531, 91531, 2332, 2080, 0x97a1146f, F=0x0
+1, 95510, 95510, 3299, 2964, 0x8b8f6684, F=0x0
+1, 98872, 98872, 2161, 1875, 0x9002ef71, F=0x0
+1, 101124, 101124, 4096, 3872, 0x20c6ed9c, F=0x0
+1, 105303, 105303, 2730, 3094, 0xf203a663, F=0x0
+1, 108106, 108106, 2059, 2404, 0x41a7b429, F=0x0
+1, 141556, 141556, 1661, 1088, 0xde20aa20, F=0x0
+1, 163445, 163445, 1331, 339, 0x8bd186ef, F=0x0
+1, 168049, 168049, 1900, 1312, 0x0bf20e8d, F=0x0
+1, 170035, 170035, 1524, 1279, 0xb6c2dafe, F=0x0
+1, 172203, 172203, 1695, 1826, 0x9a1ac769, F=0x0
+1, 173947, 173947, 1934, 1474, 0xa9b03cdc, F=0x0
+1, 175957, 175957, 1763, 1019, 0x20409355, F=0x0
+1, 189295, 189295, 1968, 1596, 0x408c726e, F=0x0
+1, 191356, 191356, 1228, 1517, 0xae8c5c2b, F=0x0
+1, 192640, 192640, 1763, 2506, 0xa458d6d4, F=0x0
+1, 195193, 195193, 1092, 1074, 0x397ba9a8, F=0x0
+1, 196361, 196361, 1524, 1715, 0x695ca41e, F=0x0
+1, 197946, 197946, 1160, 789, 0xc63a189e, F=0x0
+1, 199230, 199230, 1627, 1846, 0xeea8c599, F=0x0
+1, 200924, 200924, 1763, 922, 0xd4a87222, F=0x0
+1, 210600, 210600, 1831, 665, 0x55580135, F=0x0
+1, 214771, 214771, 1558, 1216, 0x50d1f6c5, F=0x0
+1, 225640, 225640, 2127, 2133, 0x670c11a5, F=0x0
+1, 227834, 227834, 1262, 1264, 0xc1d9fc57, F=0x0
diff --git a/tests/ref/fate/svq1 b/tests/ref/fate/svq1
index 3b26d1ffa5..3bcf715a61 100644
--- a/tests/ref/fate/svq1
+++ b/tests/ref/fate/svq1
@@ -1,151 +1,151 @@
-#tb 0: 1/600
+#tb 0: 1/15
0, 0, 0, 1, 21600, 0x7f9389e3
-0, 40, 40, 1, 21600, 0xcebb8896
-0, 80, 80, 1, 21600, 0xef51860a
-0, 120, 120, 1, 21600, 0x88d97e7d
-0, 160, 160, 1, 21600, 0xc7757c88
-0, 200, 200, 1, 21600, 0x2f537ade
-0, 240, 240, 1, 21600, 0xd50a7eff
-0, 280, 280, 1, 21600, 0xdcfb7fc6
-0, 320, 320, 1, 21600, 0x0d608299
-0, 360, 360, 1, 21600, 0x97ca81b4
-0, 400, 400, 1, 21600, 0x791f80e7
-0, 440, 440, 1, 21600, 0x96ae7d33
-0, 480, 480, 1, 21600, 0x4d7474a8
-0, 520, 520, 1, 21600, 0x2ae76f37
-0, 560, 560, 1, 21600, 0x7da76265
-0, 600, 600, 1, 21600, 0x93ae3eb6
-0, 640, 640, 1, 21600, 0xebfd3868
-0, 680, 680, 1, 21600, 0x54f82ffa
-0, 720, 720, 1, 21600, 0x8d5b2ad0
-0, 760, 760, 1, 21600, 0xe67128e6
-0, 800, 800, 1, 21600, 0xb7bf613e
-0, 840, 840, 1, 21600, 0xefd0f51b
-0, 880, 880, 1, 21600, 0x31b7da59
-0, 920, 920, 1, 21600, 0x7a84a8f7
-0, 960, 960, 1, 21600, 0x0351ad27
-0, 1000, 1000, 1, 21600, 0xed6f434d
-0, 1040, 1040, 1, 21600, 0x0e771127
-0, 1080, 1080, 1, 21600, 0x37bf0b95
-0, 1120, 1120, 1, 21600, 0x30e10a77
-0, 1160, 1160, 1, 21600, 0x1a48288a
-0, 1200, 1200, 1, 21600, 0xf43c6770
-0, 1240, 1240, 1, 21600, 0x3c43ae68
-0, 1280, 1280, 1, 21600, 0x04dc0949
-0, 1320, 1320, 1, 21600, 0x7920758d
-0, 1360, 1360, 1, 21600, 0x6c12bab5
-0, 1400, 1400, 1, 21600, 0x1ac23706
-0, 1440, 1440, 1, 21600, 0x7a95cb5f
-0, 1480, 1480, 1, 21600, 0xf1bfbb46
-0, 1520, 1520, 1, 21600, 0x773d1d0c
-0, 1560, 1560, 1, 21600, 0x2e7bea65
-0, 1600, 1600, 1, 21600, 0xdb1a086f
-0, 1640, 1640, 1, 21600, 0x5b36b78d
-0, 1680, 1680, 1, 21600, 0x7b533ca6
-0, 1720, 1720, 1, 21600, 0x65d75105
-0, 1760, 1760, 1, 21600, 0xfe6f6207
-0, 1800, 1800, 1, 21600, 0x44c4ce57
-0, 1840, 1840, 1, 21600, 0x220f3dae
-0, 1880, 1880, 1, 21600, 0xb4d20ffb
-0, 1920, 1920, 1, 21600, 0x8907ad72
-0, 1960, 1960, 1, 21600, 0xc6418998
-0, 2000, 2000, 1, 21600, 0x395b6670
-0, 2040, 2040, 1, 21600, 0x83495b88
-0, 2080, 2080, 1, 21600, 0x8920d683
-0, 2120, 2120, 1, 21600, 0xd7fc64ea
-0, 2160, 2160, 1, 21600, 0x21a3b222
-0, 2200, 2200, 1, 21600, 0xc11f2dbd
-0, 2240, 2240, 1, 21600, 0xd1d5495d
-0, 2280, 2280, 1, 21600, 0x70f2de20
-0, 2320, 2320, 1, 21600, 0x10adc9a9
-0, 2360, 2360, 1, 21600, 0xf713c0ec
-0, 2400, 2400, 1, 21600, 0xa346b3fe
-0, 2440, 2440, 1, 21600, 0x7945c29b
-0, 2480, 2480, 1, 21600, 0xb07ceb91
-0, 2520, 2520, 1, 21600, 0xe1eaf9ef
-0, 2560, 2560, 1, 21600, 0x6fa915c7
-0, 2600, 2600, 1, 21600, 0x61952055
-0, 2640, 2640, 1, 21600, 0x4bca2382
-0, 2680, 2680, 1, 21600, 0x36161fe2
-0, 2720, 2720, 1, 21600, 0xf93a28f7
-0, 2760, 2760, 1, 21600, 0xa02a3d47
-0, 2800, 2800, 1, 21600, 0x925b3609
-0, 2840, 2840, 1, 21600, 0x5b6941db
-0, 2880, 2880, 1, 21600, 0x33154a91
-0, 2920, 2920, 1, 21600, 0xb1d75c50
-0, 2960, 2960, 1, 21600, 0x1cb369bd
-0, 3000, 3000, 1, 21600, 0x3be4eff2
-0, 3040, 3040, 1, 21600, 0xbb89c301
-0, 3080, 3080, 1, 21600, 0xc7630d85
-0, 3120, 3120, 1, 21600, 0xf7441c67
-0, 3160, 3160, 1, 21600, 0xc23611ef
-0, 3200, 3200, 1, 21600, 0x840efb21
-0, 3240, 3240, 1, 21600, 0x7d470a0f
-0, 3280, 3280, 1, 21600, 0xfe093210
-0, 3320, 3320, 1, 21600, 0x0f3ea098
-0, 3360, 3360, 1, 21600, 0xcd72286f
-0, 3400, 3400, 1, 21600, 0x826f8030
-0, 3440, 3440, 1, 21600, 0xcda3ace8
-0, 3480, 3480, 1, 21600, 0x39cb4cd0
-0, 3520, 3520, 1, 21600, 0xa86a60ac
-0, 3560, 3560, 1, 21600, 0xcd32ed8e
-0, 3600, 3600, 1, 21600, 0x769b285d
-0, 3640, 3640, 1, 21600, 0x10234cd0
-0, 3680, 3680, 1, 21600, 0x951036b8
-0, 3720, 3720, 1, 21600, 0xaef248fa
-0, 3760, 3760, 1, 21600, 0x74e36e84
-0, 3800, 3800, 1, 21600, 0x3908531b
-0, 3840, 3840, 1, 21600, 0x342f2a9d
-0, 3880, 3880, 1, 21600, 0x291d58f3
-0, 3920, 3920, 1, 21600, 0xcf24b1e5
-0, 3960, 3960, 1, 21600, 0x3e7c7959
-0, 4000, 4000, 1, 21600, 0x6517e573
-0, 4040, 4040, 1, 21600, 0x304cc6db
-0, 4080, 4080, 1, 21600, 0x272895e4
-0, 4120, 4120, 1, 21600, 0x52325837
-0, 4160, 4160, 1, 21600, 0xd01344bd
-0, 4200, 4200, 1, 21600, 0xd25a370b
-0, 4240, 4240, 1, 21600, 0x274e0ae9
-0, 4280, 4280, 1, 21600, 0x6f66138f
-0, 4320, 4320, 1, 21600, 0xd35a0f60
-0, 4360, 4360, 1, 21600, 0xe0610863
-0, 4400, 4400, 1, 21600, 0x920b05fb
-0, 4440, 4440, 1, 21600, 0x5befe39d
-0, 4480, 4480, 1, 21600, 0xd167bd58
-0, 4520, 4520, 1, 21600, 0x653ac504
-0, 4560, 4560, 1, 21600, 0x8372c6d7
-0, 4600, 4600, 1, 21600, 0x0302c276
-0, 4640, 4640, 1, 21600, 0xa176b694
-0, 4680, 4680, 1, 21600, 0x4c2e935a
-0, 4720, 4720, 1, 21600, 0xf7ea844e
-0, 4760, 4760, 1, 21600, 0x76d6c07b
-0, 4800, 4800, 1, 21600, 0x0a14d610
-0, 4840, 4840, 1, 21600, 0x0ec9f3f3
-0, 4880, 4880, 1, 21600, 0xdc90f6ea
-0, 4920, 4920, 1, 21600, 0xc841f9ef
-0, 4960, 4960, 1, 21600, 0x7ab5f9b9
-0, 5000, 5000, 1, 21600, 0xda40f3c2
-0, 5040, 5040, 1, 21600, 0x0040fb72
-0, 5080, 5080, 1, 21600, 0x705b0786
-0, 5120, 5120, 1, 21600, 0x26d5198d
-0, 5160, 5160, 1, 21600, 0x6f5153ad
-0, 5200, 5200, 1, 21600, 0x9f26624b
-0, 5240, 5240, 1, 21600, 0x0d3ea7af
-0, 5280, 5280, 1, 21600, 0xb957ca79
-0, 5320, 5320, 1, 21600, 0x03a60612
-0, 5360, 5360, 1, 21600, 0x3ddc4ff1
-0, 5400, 5400, 1, 21600, 0x8fe5697f
-0, 5440, 5440, 1, 21600, 0x3d199b09
-0, 5480, 5480, 1, 21600, 0x97e2b504
-0, 5520, 5520, 1, 21600, 0x7563f784
-0, 5560, 5560, 1, 21600, 0x9a473879
-0, 5600, 5600, 1, 21600, 0x2e2054e5
-0, 5640, 5640, 1, 21600, 0x06b3658b
-0, 5680, 5680, 1, 21600, 0xa37ee249
-0, 5720, 5720, 1, 21600, 0xa527efa1
-0, 5760, 5760, 1, 21600, 0x12791532
-0, 5800, 5800, 1, 21600, 0xc5350145
-0, 5840, 5840, 1, 21600, 0xcd44f1ac
-0, 5880, 5880, 1, 21600, 0xe610edfb
-0, 5920, 5920, 1, 21600, 0x5642f672
-0, 5960, 5960, 1, 21600, 0xf2bc3e5b
+0, 1, 1, 1, 21600, 0xcebb8896
+0, 2, 2, 1, 21600, 0xef51860a
+0, 3, 3, 1, 21600, 0x88d97e7d
+0, 4, 4, 1, 21600, 0xc7757c88
+0, 5, 5, 1, 21600, 0x2f537ade
+0, 6, 6, 1, 21600, 0xd50a7eff
+0, 7, 7, 1, 21600, 0xdcfb7fc6
+0, 8, 8, 1, 21600, 0x0d608299
+0, 9, 9, 1, 21600, 0x97ca81b4
+0, 10, 10, 1, 21600, 0x791f80e7
+0, 11, 11, 1, 21600, 0x96ae7d33
+0, 12, 12, 1, 21600, 0x4d7474a8
+0, 13, 13, 1, 21600, 0x2ae76f37
+0, 14, 14, 1, 21600, 0x7da76265
+0, 15, 15, 1, 21600, 0x93ae3eb6
+0, 16, 16, 1, 21600, 0xebfd3868
+0, 17, 17, 1, 21600, 0x54f82ffa
+0, 18, 18, 1, 21600, 0x8d5b2ad0
+0, 19, 19, 1, 21600, 0xe67128e6
+0, 20, 20, 1, 21600, 0xb7bf613e
+0, 21, 21, 1, 21600, 0xefd0f51b
+0, 22, 22, 1, 21600, 0x31b7da59
+0, 23, 23, 1, 21600, 0x7a84a8f7
+0, 24, 24, 1, 21600, 0x0351ad27
+0, 25, 25, 1, 21600, 0xed6f434d
+0, 26, 26, 1, 21600, 0x0e771127
+0, 27, 27, 1, 21600, 0x37bf0b95
+0, 28, 28, 1, 21600, 0x30e10a77
+0, 29, 29, 1, 21600, 0x1a48288a
+0, 30, 30, 1, 21600, 0xf43c6770
+0, 31, 31, 1, 21600, 0x3c43ae68
+0, 32, 32, 1, 21600, 0x04dc0949
+0, 33, 33, 1, 21600, 0x7920758d
+0, 34, 34, 1, 21600, 0x6c12bab5
+0, 35, 35, 1, 21600, 0x1ac23706
+0, 36, 36, 1, 21600, 0x7a95cb5f
+0, 37, 37, 1, 21600, 0xf1bfbb46
+0, 38, 38, 1, 21600, 0x773d1d0c
+0, 39, 39, 1, 21600, 0x2e7bea65
+0, 40, 40, 1, 21600, 0xdb1a086f
+0, 41, 41, 1, 21600, 0x5b36b78d
+0, 42, 42, 1, 21600, 0x7b533ca6
+0, 43, 43, 1, 21600, 0x65d75105
+0, 44, 44, 1, 21600, 0xfe6f6207
+0, 45, 45, 1, 21600, 0x44c4ce57
+0, 46, 46, 1, 21600, 0x220f3dae
+0, 47, 47, 1, 21600, 0xb4d20ffb
+0, 48, 48, 1, 21600, 0x8907ad72
+0, 49, 49, 1, 21600, 0xc6418998
+0, 50, 50, 1, 21600, 0x395b6670
+0, 51, 51, 1, 21600, 0x83495b88
+0, 52, 52, 1, 21600, 0x8920d683
+0, 53, 53, 1, 21600, 0xd7fc64ea
+0, 54, 54, 1, 21600, 0x21a3b222
+0, 55, 55, 1, 21600, 0xc11f2dbd
+0, 56, 56, 1, 21600, 0xd1d5495d
+0, 57, 57, 1, 21600, 0x70f2de20
+0, 58, 58, 1, 21600, 0x10adc9a9
+0, 59, 59, 1, 21600, 0xf713c0ec
+0, 60, 60, 1, 21600, 0xa346b3fe
+0, 61, 61, 1, 21600, 0x7945c29b
+0, 62, 62, 1, 21600, 0xb07ceb91
+0, 63, 63, 1, 21600, 0xe1eaf9ef
+0, 64, 64, 1, 21600, 0x6fa915c7
+0, 65, 65, 1, 21600, 0x61952055
+0, 66, 66, 1, 21600, 0x4bca2382
+0, 67, 67, 1, 21600, 0x36161fe2
+0, 68, 68, 1, 21600, 0xf93a28f7
+0, 69, 69, 1, 21600, 0xa02a3d47
+0, 70, 70, 1, 21600, 0x925b3609
+0, 71, 71, 1, 21600, 0x5b6941db
+0, 72, 72, 1, 21600, 0x33154a91
+0, 73, 73, 1, 21600, 0xb1d75c50
+0, 74, 74, 1, 21600, 0x1cb369bd
+0, 75, 75, 1, 21600, 0x3be4eff2
+0, 76, 76, 1, 21600, 0xbb89c301
+0, 77, 77, 1, 21600, 0xc7630d85
+0, 78, 78, 1, 21600, 0xf7441c67
+0, 79, 79, 1, 21600, 0xc23611ef
+0, 80, 80, 1, 21600, 0x840efb21
+0, 81, 81, 1, 21600, 0x7d470a0f
+0, 82, 82, 1, 21600, 0xfe093210
+0, 83, 83, 1, 21600, 0x0f3ea098
+0, 84, 84, 1, 21600, 0xcd72286f
+0, 85, 85, 1, 21600, 0x826f8030
+0, 86, 86, 1, 21600, 0xcda3ace8
+0, 87, 87, 1, 21600, 0x39cb4cd0
+0, 88, 88, 1, 21600, 0xa86a60ac
+0, 89, 89, 1, 21600, 0xcd32ed8e
+0, 90, 90, 1, 21600, 0x769b285d
+0, 91, 91, 1, 21600, 0x10234cd0
+0, 92, 92, 1, 21600, 0x951036b8
+0, 93, 93, 1, 21600, 0xaef248fa
+0, 94, 94, 1, 21600, 0x74e36e84
+0, 95, 95, 1, 21600, 0x3908531b
+0, 96, 96, 1, 21600, 0x342f2a9d
+0, 97, 97, 1, 21600, 0x291d58f3
+0, 98, 98, 1, 21600, 0xcf24b1e5
+0, 99, 99, 1, 21600, 0x3e7c7959
+0, 100, 100, 1, 21600, 0x6517e573
+0, 101, 101, 1, 21600, 0x304cc6db
+0, 102, 102, 1, 21600, 0x272895e4
+0, 103, 103, 1, 21600, 0x52325837
+0, 104, 104, 1, 21600, 0xd01344bd
+0, 105, 105, 1, 21600, 0xd25a370b
+0, 106, 106, 1, 21600, 0x274e0ae9
+0, 107, 107, 1, 21600, 0x6f66138f
+0, 108, 108, 1, 21600, 0xd35a0f60
+0, 109, 109, 1, 21600, 0xe0610863
+0, 110, 110, 1, 21600, 0x920b05fb
+0, 111, 111, 1, 21600, 0x5befe39d
+0, 112, 112, 1, 21600, 0xd167bd58
+0, 113, 113, 1, 21600, 0x653ac504
+0, 114, 114, 1, 21600, 0x8372c6d7
+0, 115, 115, 1, 21600, 0x0302c276
+0, 116, 116, 1, 21600, 0xa176b694
+0, 117, 117, 1, 21600, 0x4c2e935a
+0, 118, 118, 1, 21600, 0xf7ea844e
+0, 119, 119, 1, 21600, 0x76d6c07b
+0, 120, 120, 1, 21600, 0x0a14d610
+0, 121, 121, 1, 21600, 0x0ec9f3f3
+0, 122, 122, 1, 21600, 0xdc90f6ea
+0, 123, 123, 1, 21600, 0xc841f9ef
+0, 124, 124, 1, 21600, 0x7ab5f9b9
+0, 125, 125, 1, 21600, 0xda40f3c2
+0, 126, 126, 1, 21600, 0x0040fb72
+0, 127, 127, 1, 21600, 0x705b0786
+0, 128, 128, 1, 21600, 0x26d5198d
+0, 129, 129, 1, 21600, 0x6f5153ad
+0, 130, 130, 1, 21600, 0x9f26624b
+0, 131, 131, 1, 21600, 0x0d3ea7af
+0, 132, 132, 1, 21600, 0xb957ca79
+0, 133, 133, 1, 21600, 0x03a60612
+0, 134, 134, 1, 21600, 0x3ddc4ff1
+0, 135, 135, 1, 21600, 0x8fe5697f
+0, 136, 136, 1, 21600, 0x3d199b09
+0, 137, 137, 1, 21600, 0x97e2b504
+0, 138, 138, 1, 21600, 0x7563f784
+0, 139, 139, 1, 21600, 0x9a473879
+0, 140, 140, 1, 21600, 0x2e2054e5
+0, 141, 141, 1, 21600, 0x06b3658b
+0, 142, 142, 1, 21600, 0xa37ee249
+0, 143, 143, 1, 21600, 0xa527efa1
+0, 144, 144, 1, 21600, 0x12791532
+0, 145, 145, 1, 21600, 0xc5350145
+0, 146, 146, 1, 21600, 0xcd44f1ac
+0, 147, 147, 1, 21600, 0xe610edfb
+0, 148, 148, 1, 21600, 0x5642f672
+0, 149, 149, 1, 21600, 0xf2bc3e5b
diff --git a/tests/ref/fate/svq1-headerswap b/tests/ref/fate/svq1-headerswap
index f5ffe4d652..d9f9597354 100644
--- a/tests/ref/fate/svq1-headerswap
+++ b/tests/ref/fate/svq1-headerswap
@@ -1,5 +1,5 @@
-#tb 0: 1/600
+#tb 0: 1/10
0, 0, 0, 1, 58814, 0x5caad04b
-0, 60, 60, 1, 58814, 0x98d8ceb8
-0, 120, 120, 1, 58814, 0x8925cdb0
-0, 180, 180, 1, 58814, 0x6ffc02c3
+0, 1, 1, 1, 58814, 0x98d8ceb8
+0, 2, 2, 1, 58814, 0x8925cdb0
+0, 3, 3, 1, 58814, 0x6ffc02c3
diff --git a/tests/ref/fate/svq3 b/tests/ref/fate/svq3
index 141300ac17..073d10b366 100644
--- a/tests/ref/fate/svq3
+++ b/tests/ref/fate/svq3
@@ -1,181 +1,181 @@
-#tb 0: 1/600
+#tb 0: 1/30
0, 0, 0, 1, 115200, 0x2c810465
-0, 20, 20, 1, 115200, 0x010b5765
-0, 40, 40, 1, 115200, 0x2be11a4e
-0, 60, 60, 1, 115200, 0x99445d06
-0, 80, 80, 1, 115200, 0x6b54d83c
-0, 100, 100, 1, 115200, 0x3832b76a
-0, 120, 120, 1, 115200, 0x3832b76a
-0, 140, 140, 1, 115200, 0xe18385db
-0, 160, 160, 1, 115200, 0x847d4bf0
-0, 180, 180, 1, 115200, 0x0d650f50
-0, 200, 200, 1, 115200, 0x4b85c44c
-0, 220, 220, 1, 115200, 0xce1927a6
-0, 240, 240, 1, 115200, 0x89353747
-0, 260, 260, 1, 115200, 0x58da43f2
-0, 280, 280, 1, 115200, 0xee9a4eef
-0, 300, 300, 1, 115200, 0xce9453d9
-0, 320, 320, 1, 115200, 0x804a5eb0
-0, 340, 340, 1, 115200, 0xb3d46605
-0, 360, 360, 1, 115200, 0x45b5668e
-0, 380, 380, 1, 115200, 0xdd0d4c5a
-0, 400, 400, 1, 115200, 0x99101301
-0, 420, 420, 1, 115200, 0xf0c3f272
-0, 440, 440, 1, 115200, 0xea21f8b1
-0, 460, 460, 1, 115200, 0xd8e7fbb1
-0, 480, 480, 1, 115200, 0x89d90aa1
-0, 500, 500, 1, 115200, 0x882e19da
-0, 520, 520, 1, 115200, 0xfc0f2709
-0, 540, 540, 1, 115200, 0x9b732f3f
-0, 560, 560, 1, 115200, 0xec453cda
-0, 580, 580, 1, 115200, 0xa77e4989
-0, 600, 600, 1, 115200, 0xad935834
-0, 620, 620, 1, 115200, 0x3a5a6177
-0, 640, 640, 1, 115200, 0xd3c07999
-0, 660, 660, 1, 115200, 0xfad388dd
-0, 680, 680, 1, 115200, 0xaf6e9520
-0, 700, 700, 1, 115200, 0xdb64a4b3
-0, 720, 720, 1, 115200, 0xc6f9b49e
-0, 740, 740, 1, 115200, 0x4446c315
-0, 760, 760, 1, 115200, 0x660bd01c
-0, 780, 780, 1, 115200, 0x963fdd7d
-0, 800, 800, 1, 115200, 0x8733e7b3
-0, 820, 820, 1, 115200, 0x41aaf1d5
-0, 840, 840, 1, 115200, 0xa803fd81
-0, 860, 860, 1, 115200, 0xe2b4077f
-0, 880, 880, 1, 115200, 0xfe6707cb
-0, 900, 900, 1, 115200, 0x027c122d
-0, 920, 920, 1, 115200, 0xbcb81ea8
-0, 940, 940, 1, 115200, 0xd2ac2405
-0, 960, 960, 1, 115200, 0x3d893006
-0, 980, 980, 1, 115200, 0xbdcc3ba8
-0, 1000, 1000, 1, 115200, 0x83ed4c6b
-0, 1020, 1020, 1, 115200, 0x69ee5e7c
-0, 1040, 1040, 1, 115200, 0xfe317411
-0, 1060, 1060, 1, 115200, 0x849e84e6
-0, 1080, 1080, 1, 115200, 0x040f945f
-0, 1100, 1100, 1, 115200, 0x6481ac89
-0, 1120, 1120, 1, 115200, 0x8a48be9e
-0, 1140, 1140, 1, 115200, 0xb162ce94
-0, 1160, 1160, 1, 115200, 0x178dd69a
-0, 1180, 1180, 1, 115200, 0x64fdecaa
-0, 1200, 1200, 1, 115200, 0x4b51297e
-0, 1220, 1220, 1, 115200, 0x3d39a1ae
-0, 1240, 1240, 1, 115200, 0x900fd939
-0, 1260, 1260, 1, 115200, 0x7704fb19
-0, 1280, 1280, 1, 115200, 0xa426137e
-0, 1300, 1300, 1, 115200, 0x9a112706
-0, 1320, 1320, 1, 115200, 0x294931f7
-0, 1340, 1340, 1, 115200, 0x0d0e4372
-0, 1360, 1360, 1, 115200, 0x33bd50e4
-0, 1380, 1380, 1, 115200, 0x9c86e3e2
-0, 1400, 1400, 1, 115200, 0x714af5d5
-0, 1420, 1420, 1, 115200, 0xc5f9fcd0
-0, 1440, 1440, 1, 115200, 0x184602bb
-0, 1460, 1460, 1, 115200, 0x6958e9e6
-0, 1480, 1480, 1, 115200, 0x5a214952
-0, 1500, 1500, 1, 115200, 0x706cca0e
-0, 1520, 1520, 1, 115200, 0x67689363
-0, 1540, 1540, 1, 115200, 0x459f410c
-0, 1560, 1560, 1, 115200, 0xa8f4c365
-0, 1580, 1580, 1, 115200, 0xf1fc50c5
-0, 1600, 1600, 1, 115200, 0xc22af545
-0, 1620, 1620, 1, 115200, 0xd39802a2
-0, 1640, 1640, 1, 115200, 0xb76c04b6
-0, 1660, 1660, 1, 115200, 0x7a548db4
-0, 1680, 1680, 1, 115200, 0x79e56765
-0, 1700, 1700, 1, 115200, 0x3f273a17
-0, 1720, 1720, 1, 115200, 0xe04366db
-0, 1740, 1740, 1, 115200, 0x8e10939b
-0, 1760, 1760, 1, 115200, 0x49220ea2
-0, 1780, 1780, 1, 115200, 0x35361889
-0, 1800, 1800, 1, 115200, 0x9b20bdfa
-0, 1820, 1820, 1, 115200, 0x5d472eaf
-0, 1840, 1840, 1, 115200, 0xeda43081
-0, 1860, 1860, 1, 115200, 0x59bae8b4
-0, 1880, 1880, 1, 115200, 0xf126d6a4
-0, 1900, 1900, 1, 115200, 0x18106464
-0, 1920, 1920, 1, 115200, 0x85530c73
-0, 1940, 1940, 1, 115200, 0xcef32c78
-0, 1960, 1960, 1, 115200, 0xfd6233a0
-0, 1980, 1980, 1, 115200, 0xae9d6fc3
-0, 2000, 2000, 1, 115200, 0x3d0cce10
-0, 2020, 2020, 1, 115200, 0xfce5f124
-0, 2040, 2040, 1, 115200, 0x90b10802
-0, 2060, 2060, 1, 115200, 0xeea44201
-0, 2080, 2080, 1, 115200, 0x1cefb56d
-0, 2100, 2100, 1, 115200, 0xd6daa0b1
-0, 2120, 2120, 1, 115200, 0xd700cef4
-0, 2140, 2140, 1, 115200, 0x36dbf58f
-0, 2160, 2160, 1, 115200, 0xdb20d060
-0, 2180, 2180, 1, 115200, 0x5ca61fd5
-0, 2200, 2200, 1, 115200, 0x4f271361
-0, 2220, 2220, 1, 115200, 0xcaf03743
-0, 2240, 2240, 1, 115200, 0x520f351a
-0, 2260, 2260, 1, 115200, 0x40bc7b89
-0, 2280, 2280, 1, 115200, 0xd0af0b08
-0, 2300, 2300, 1, 115200, 0x6a45290c
-0, 2320, 2320, 1, 115200, 0x57210c14
-0, 2340, 2340, 1, 115200, 0xc1e233f9
-0, 2360, 2360, 1, 115200, 0x96fdfc54
-0, 2380, 2380, 1, 115200, 0x43a8359c
-0, 2400, 2400, 1, 115200, 0xd493bfde
-0, 2420, 2420, 1, 115200, 0xd5339d13
-0, 2440, 2440, 1, 115200, 0x7542baa0
-0, 2460, 2460, 1, 115200, 0x268d2cb9
-0, 2480, 2480, 1, 115200, 0xaf3888bb
-0, 2500, 2500, 1, 115200, 0xb82f520a
-0, 2520, 2520, 1, 115200, 0x0feb2981
-0, 2540, 2540, 1, 115200, 0x45314b58
-0, 2560, 2560, 1, 115200, 0xb26a193a
-0, 2580, 2580, 1, 115200, 0xdfdffc38
-0, 2600, 2600, 1, 115200, 0xec6a55f5
-0, 2620, 2620, 1, 115200, 0xf6e35716
-0, 2640, 2640, 1, 115200, 0x5ce8544e
-0, 2660, 2660, 1, 115200, 0x3e38ddce
-0, 2680, 2680, 1, 115200, 0x964a2006
-0, 2700, 2700, 1, 115200, 0xaba138d6
-0, 2720, 2720, 1, 115200, 0x2f46949c
-0, 2740, 2740, 1, 115200, 0xbdbdb587
-0, 2760, 2760, 1, 115200, 0x1bf11e1d
-0, 2780, 2780, 1, 115200, 0x2632f558
-0, 2800, 2800, 1, 115200, 0x0e58078b
-0, 2820, 2820, 1, 115200, 0x2ab2f9be
-0, 2840, 2840, 1, 115200, 0x9205f1d8
-0, 2860, 2860, 1, 115200, 0x6a4bd949
-0, 2880, 2880, 1, 115200, 0xedc1552f
-0, 2900, 2900, 1, 115200, 0x0a60974d
-0, 2920, 2920, 1, 115200, 0xe1a1400e
-0, 2940, 2940, 1, 115200, 0x45f06952
-0, 2960, 2960, 1, 115200, 0xc5163125
-0, 2980, 2980, 1, 115200, 0x151da156
-0, 3000, 3000, 1, 115200, 0x3f34b048
-0, 3020, 3020, 1, 115200, 0xcf7c1e5d
-0, 3040, 3040, 1, 115200, 0xed9c4e1c
-0, 3060, 3060, 1, 115200, 0x47e06453
-0, 3080, 3080, 1, 115200, 0xc8ce6f19
-0, 3100, 3100, 1, 115200, 0xac619619
-0, 3120, 3120, 1, 115200, 0x64711e2d
-0, 3140, 3140, 1, 115200, 0x1f502b52
-0, 3160, 3160, 1, 115200, 0x39592c9d
-0, 3180, 3180, 1, 115200, 0x7dffb901
-0, 3200, 3200, 1, 115200, 0xc75fa3ce
-0, 3220, 3220, 1, 115200, 0x625bc977
-0, 3240, 3240, 1, 115200, 0x15c7fda3
-0, 3260, 3260, 1, 115200, 0x6e5d35b5
-0, 3280, 3280, 1, 115200, 0xf847cf88
-0, 3300, 3300, 1, 115200, 0xc10867fe
-0, 3320, 3320, 1, 115200, 0xae07fbfc
-0, 3340, 3340, 1, 115200, 0xc1571542
-0, 3360, 3360, 1, 115200, 0x4c7d5602
-0, 3380, 3380, 1, 115200, 0xbe7045aa
-0, 3400, 3400, 1, 115200, 0xc8b4835b
-0, 3420, 3420, 1, 115200, 0xf9b7d427
-0, 3440, 3440, 1, 115200, 0x7fa7c112
-0, 3460, 3460, 1, 115200, 0xe0105feb
-0, 3480, 3480, 1, 115200, 0x70784740
-0, 3500, 3500, 1, 115200, 0xa6801ef5
-0, 3520, 3520, 1, 115200, 0x9cf35921
-0, 3540, 3540, 1, 115200, 0x4d956630
-0, 3560, 3560, 1, 115200, 0x717a25c1
-0, 3580, 3580, 1, 115200, 0x8f5e39de
+0, 1, 1, 1, 115200, 0x010b5765
+0, 2, 2, 1, 115200, 0x2be11a4e
+0, 3, 3, 1, 115200, 0x99445d06
+0, 4, 4, 1, 115200, 0x6b54d83c
+0, 5, 5, 1, 115200, 0x3832b76a
+0, 6, 6, 1, 115200, 0x3832b76a
+0, 7, 7, 1, 115200, 0xe18385db
+0, 8, 8, 1, 115200, 0x847d4bf0
+0, 9, 9, 1, 115200, 0x0d650f50
+0, 10, 10, 1, 115200, 0x4b85c44c
+0, 11, 11, 1, 115200, 0xce1927a6
+0, 12, 12, 1, 115200, 0x89353747
+0, 13, 13, 1, 115200, 0x58da43f2
+0, 14, 14, 1, 115200, 0xee9a4eef
+0, 15, 15, 1, 115200, 0xce9453d9
+0, 16, 16, 1, 115200, 0x804a5eb0
+0, 17, 17, 1, 115200, 0xb3d46605
+0, 18, 18, 1, 115200, 0x45b5668e
+0, 19, 19, 1, 115200, 0xdd0d4c5a
+0, 20, 20, 1, 115200, 0x99101301
+0, 21, 21, 1, 115200, 0xf0c3f272
+0, 22, 22, 1, 115200, 0xea21f8b1
+0, 23, 23, 1, 115200, 0xd8e7fbb1
+0, 24, 24, 1, 115200, 0x89d90aa1
+0, 25, 25, 1, 115200, 0x882e19da
+0, 26, 26, 1, 115200, 0xfc0f2709
+0, 27, 27, 1, 115200, 0x9b732f3f
+0, 28, 28, 1, 115200, 0xec453cda
+0, 29, 29, 1, 115200, 0xa77e4989
+0, 30, 30, 1, 115200, 0xad935834
+0, 31, 31, 1, 115200, 0x3a5a6177
+0, 32, 32, 1, 115200, 0xd3c07999
+0, 33, 33, 1, 115200, 0xfad388dd
+0, 34, 34, 1, 115200, 0xaf6e9520
+0, 35, 35, 1, 115200, 0xdb64a4b3
+0, 36, 36, 1, 115200, 0xc6f9b49e
+0, 37, 37, 1, 115200, 0x4446c315
+0, 38, 38, 1, 115200, 0x660bd01c
+0, 39, 39, 1, 115200, 0x963fdd7d
+0, 40, 40, 1, 115200, 0x8733e7b3
+0, 41, 41, 1, 115200, 0x41aaf1d5
+0, 42, 42, 1, 115200, 0xa803fd81
+0, 43, 43, 1, 115200, 0xe2b4077f
+0, 44, 44, 1, 115200, 0xfe6707cb
+0, 45, 45, 1, 115200, 0x027c122d
+0, 46, 46, 1, 115200, 0xbcb81ea8
+0, 47, 47, 1, 115200, 0xd2ac2405
+0, 48, 48, 1, 115200, 0x3d893006
+0, 49, 49, 1, 115200, 0xbdcc3ba8
+0, 50, 50, 1, 115200, 0x83ed4c6b
+0, 51, 51, 1, 115200, 0x69ee5e7c
+0, 52, 52, 1, 115200, 0xfe317411
+0, 53, 53, 1, 115200, 0x849e84e6
+0, 54, 54, 1, 115200, 0x040f945f
+0, 55, 55, 1, 115200, 0x6481ac89
+0, 56, 56, 1, 115200, 0x8a48be9e
+0, 57, 57, 1, 115200, 0xb162ce94
+0, 58, 58, 1, 115200, 0x178dd69a
+0, 59, 59, 1, 115200, 0x64fdecaa
+0, 60, 60, 1, 115200, 0x4b51297e
+0, 61, 61, 1, 115200, 0x3d39a1ae
+0, 62, 62, 1, 115200, 0x900fd939
+0, 63, 63, 1, 115200, 0x7704fb19
+0, 64, 64, 1, 115200, 0xa426137e
+0, 65, 65, 1, 115200, 0x9a112706
+0, 66, 66, 1, 115200, 0x294931f7
+0, 67, 67, 1, 115200, 0x0d0e4372
+0, 68, 68, 1, 115200, 0x33bd50e4
+0, 69, 69, 1, 115200, 0x9c86e3e2
+0, 70, 70, 1, 115200, 0x714af5d5
+0, 71, 71, 1, 115200, 0xc5f9fcd0
+0, 72, 72, 1, 115200, 0x184602bb
+0, 73, 73, 1, 115200, 0x6958e9e6
+0, 74, 74, 1, 115200, 0x5a214952
+0, 75, 75, 1, 115200, 0x706cca0e
+0, 76, 76, 1, 115200, 0x67689363
+0, 77, 77, 1, 115200, 0x459f410c
+0, 78, 78, 1, 115200, 0xa8f4c365
+0, 79, 79, 1, 115200, 0xf1fc50c5
+0, 80, 80, 1, 115200, 0xc22af545
+0, 81, 81, 1, 115200, 0xd39802a2
+0, 82, 82, 1, 115200, 0xb76c04b6
+0, 83, 83, 1, 115200, 0x7a548db4
+0, 84, 84, 1, 115200, 0x79e56765
+0, 85, 85, 1, 115200, 0x3f273a17
+0, 86, 86, 1, 115200, 0xe04366db
+0, 87, 87, 1, 115200, 0x8e10939b
+0, 88, 88, 1, 115200, 0x49220ea2
+0, 89, 89, 1, 115200, 0x35361889
+0, 90, 90, 1, 115200, 0x9b20bdfa
+0, 91, 91, 1, 115200, 0x5d472eaf
+0, 92, 92, 1, 115200, 0xeda43081
+0, 93, 93, 1, 115200, 0x59bae8b4
+0, 94, 94, 1, 115200, 0xf126d6a4
+0, 95, 95, 1, 115200, 0x18106464
+0, 96, 96, 1, 115200, 0x85530c73
+0, 97, 97, 1, 115200, 0xcef32c78
+0, 98, 98, 1, 115200, 0xfd6233a0
+0, 99, 99, 1, 115200, 0xae9d6fc3
+0, 100, 100, 1, 115200, 0x3d0cce10
+0, 101, 101, 1, 115200, 0xfce5f124
+0, 102, 102, 1, 115200, 0x90b10802
+0, 103, 103, 1, 115200, 0xeea44201
+0, 104, 104, 1, 115200, 0x1cefb56d
+0, 105, 105, 1, 115200, 0xd6daa0b1
+0, 106, 106, 1, 115200, 0xd700cef4
+0, 107, 107, 1, 115200, 0x36dbf58f
+0, 108, 108, 1, 115200, 0xdb20d060
+0, 109, 109, 1, 115200, 0x5ca61fd5
+0, 110, 110, 1, 115200, 0x4f271361
+0, 111, 111, 1, 115200, 0xcaf03743
+0, 112, 112, 1, 115200, 0x520f351a
+0, 113, 113, 1, 115200, 0x40bc7b89
+0, 114, 114, 1, 115200, 0xd0af0b08
+0, 115, 115, 1, 115200, 0x6a45290c
+0, 116, 116, 1, 115200, 0x57210c14
+0, 117, 117, 1, 115200, 0xc1e233f9
+0, 118, 118, 1, 115200, 0x96fdfc54
+0, 119, 119, 1, 115200, 0x43a8359c
+0, 120, 120, 1, 115200, 0xd493bfde
+0, 121, 121, 1, 115200, 0xd5339d13
+0, 122, 122, 1, 115200, 0x7542baa0
+0, 123, 123, 1, 115200, 0x268d2cb9
+0, 124, 124, 1, 115200, 0xaf3888bb
+0, 125, 125, 1, 115200, 0xb82f520a
+0, 126, 126, 1, 115200, 0x0feb2981
+0, 127, 127, 1, 115200, 0x45314b58
+0, 128, 128, 1, 115200, 0xb26a193a
+0, 129, 129, 1, 115200, 0xdfdffc38
+0, 130, 130, 1, 115200, 0xec6a55f5
+0, 131, 131, 1, 115200, 0xf6e35716
+0, 132, 132, 1, 115200, 0x5ce8544e
+0, 133, 133, 1, 115200, 0x3e38ddce
+0, 134, 134, 1, 115200, 0x964a2006
+0, 135, 135, 1, 115200, 0xaba138d6
+0, 136, 136, 1, 115200, 0x2f46949c
+0, 137, 137, 1, 115200, 0xbdbdb587
+0, 138, 138, 1, 115200, 0x1bf11e1d
+0, 139, 139, 1, 115200, 0x2632f558
+0, 140, 140, 1, 115200, 0x0e58078b
+0, 141, 141, 1, 115200, 0x2ab2f9be
+0, 142, 142, 1, 115200, 0x9205f1d8
+0, 143, 143, 1, 115200, 0x6a4bd949
+0, 144, 144, 1, 115200, 0xedc1552f
+0, 145, 145, 1, 115200, 0x0a60974d
+0, 146, 146, 1, 115200, 0xe1a1400e
+0, 147, 147, 1, 115200, 0x45f06952
+0, 148, 148, 1, 115200, 0xc5163125
+0, 149, 149, 1, 115200, 0x151da156
+0, 150, 150, 1, 115200, 0x3f34b048
+0, 151, 151, 1, 115200, 0xcf7c1e5d
+0, 152, 152, 1, 115200, 0xed9c4e1c
+0, 153, 153, 1, 115200, 0x47e06453
+0, 154, 154, 1, 115200, 0xc8ce6f19
+0, 155, 155, 1, 115200, 0xac619619
+0, 156, 156, 1, 115200, 0x64711e2d
+0, 157, 157, 1, 115200, 0x1f502b52
+0, 158, 158, 1, 115200, 0x39592c9d
+0, 159, 159, 1, 115200, 0x7dffb901
+0, 160, 160, 1, 115200, 0xc75fa3ce
+0, 161, 161, 1, 115200, 0x625bc977
+0, 162, 162, 1, 115200, 0x15c7fda3
+0, 163, 163, 1, 115200, 0x6e5d35b5
+0, 164, 164, 1, 115200, 0xf847cf88
+0, 165, 165, 1, 115200, 0xc10867fe
+0, 166, 166, 1, 115200, 0xae07fbfc
+0, 167, 167, 1, 115200, 0xc1571542
+0, 168, 168, 1, 115200, 0x4c7d5602
+0, 169, 169, 1, 115200, 0xbe7045aa
+0, 170, 170, 1, 115200, 0xc8b4835b
+0, 171, 171, 1, 115200, 0xf9b7d427
+0, 172, 172, 1, 115200, 0x7fa7c112
+0, 173, 173, 1, 115200, 0xe0105feb
+0, 174, 174, 1, 115200, 0x70784740
+0, 175, 175, 1, 115200, 0xa6801ef5
+0, 176, 176, 1, 115200, 0x9cf35921
+0, 177, 177, 1, 115200, 0x4d956630
+0, 178, 178, 1, 115200, 0x717a25c1
+0, 179, 179, 1, 115200, 0x8f5e39de
diff --git a/tests/ref/fate/tdsc b/tests/ref/fate/tdsc
index 945933fdcd..d6925e9a99 100644
--- a/tests/ref/fate/tdsc
+++ b/tests/ref/fate/tdsc
@@ -1,42 +1,42 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3888000, 0x9c498657
-0, 233, 233, 0, 3888000, 0x72a2ae22
-0, 266, 266, 0, 3888000, 0x72a2ae22
-0, 333, 333, 0, 3888000, 0x72a2ae22
-0, 533, 533, 0, 3888000, 0x72a2ae22
-0, 566, 566, 0, 3888000, 0x72a2ae22
-0, 666, 666, 0, 3888000, 0x550e417b
-0, 966, 966, 0, 3888000, 0x550e417b
-0, 999, 999, 0, 3888000, 0x550e417b
-0, 1033, 1033, 0, 3888000, 0x550e417b
-0, 1066, 1066, 0, 3888000, 0x550e417b
-0, 1133, 1133, 0, 3888000, 0x550e417b
-0, 1166, 1166, 0, 3888000, 0x38dcde13
-0, 1566, 1566, 0, 3888000, 0x2b7c0edd
-0, 1599, 1599, 0, 3888000, 0xaaaf3c7b
-0, 1633, 1633, 0, 3888000, 0x26d1710f
-0, 1666, 1666, 0, 3888000, 0xa6609f3f
-0, 1699, 1699, 0, 3888000, 0xaa41c6f3
-0, 1733, 1733, 0, 3888000, 0xc0ffd4d5
-0, 1766, 1766, 0, 3888000, 0x44d4f383
-0, 1833, 1833, 0, 3888000, 0x517047eb
-0, 1866, 1866, 0, 3888000, 0x1d5a4d5b
-0, 1899, 1899, 0, 3888000, 0x7d2da2f6
-0, 1933, 1933, 0, 3888000, 0x27f7a2f6
-0, 1966, 1966, 0, 3888000, 0x9de49edb
-0, 1999, 1999, 0, 3888000, 0x5ccb9f38
-0, 2033, 2033, 0, 3888000, 0x88069fb2
-0, 2066, 2066, 0, 3888000, 0x1d059fd3
-0, 2099, 2099, 0, 3888000, 0xe16d9fd3
-0, 2133, 2133, 0, 3888000, 0xb6a69fd3
-0, 2166, 2166, 0, 3888000, 0xb6a69fd3
-0, 2199, 2199, 0, 3888000, 0x61709fd3
-0, 2233, 2233, 0, 3888000, 0xb6f59fd3
-0, 2266, 2266, 0, 3888000, 0x5c7b9fd3
-0, 2299, 2299, 0, 3888000, 0x57869fd3
-0, 2333, 2333, 0, 3888000, 0x9d3f9fd3
-0, 2433, 2433, 0, 3888000, 0x5e6082a5
-0, 2466, 2466, 0, 3888000, 0x5e6082a5
-0, 2499, 2499, 0, 3888000, 0x5e6082a5
-0, 2533, 2533, 0, 3888000, 0x48ce82f3
-0, 2566, 2566, 0, 3888000, 0x4c5ebeaf
+#tb 0: 1/30
+0, 0, 0, 1, 3888000, 0x9c498657
+0, 7, 7, 1, 3888000, 0x72a2ae22
+0, 8, 8, 1, 3888000, 0x72a2ae22
+0, 10, 10, 1, 3888000, 0x72a2ae22
+0, 16, 16, 1, 3888000, 0x72a2ae22
+0, 17, 17, 1, 3888000, 0x72a2ae22
+0, 20, 20, 1, 3888000, 0x550e417b
+0, 29, 29, 1, 3888000, 0x550e417b
+0, 30, 30, 1, 3888000, 0x550e417b
+0, 31, 31, 1, 3888000, 0x550e417b
+0, 32, 32, 1, 3888000, 0x550e417b
+0, 34, 34, 1, 3888000, 0x550e417b
+0, 35, 35, 1, 3888000, 0x38dcde13
+0, 47, 47, 1, 3888000, 0x2b7c0edd
+0, 48, 48, 1, 3888000, 0xaaaf3c7b
+0, 49, 49, 1, 3888000, 0x26d1710f
+0, 50, 50, 1, 3888000, 0xa6609f3f
+0, 51, 51, 1, 3888000, 0xaa41c6f3
+0, 52, 52, 1, 3888000, 0xc0ffd4d5
+0, 53, 53, 1, 3888000, 0x44d4f383
+0, 55, 55, 1, 3888000, 0x517047eb
+0, 56, 56, 1, 3888000, 0x1d5a4d5b
+0, 57, 57, 1, 3888000, 0x7d2da2f6
+0, 58, 58, 1, 3888000, 0x27f7a2f6
+0, 59, 59, 1, 3888000, 0x9de49edb
+0, 60, 60, 1, 3888000, 0x5ccb9f38
+0, 61, 61, 1, 3888000, 0x88069fb2
+0, 62, 62, 1, 3888000, 0x1d059fd3
+0, 63, 63, 1, 3888000, 0xe16d9fd3
+0, 64, 64, 1, 3888000, 0xb6a69fd3
+0, 65, 65, 1, 3888000, 0xb6a69fd3
+0, 66, 66, 1, 3888000, 0x61709fd3
+0, 67, 67, 1, 3888000, 0xb6f59fd3
+0, 68, 68, 1, 3888000, 0x5c7b9fd3
+0, 69, 69, 1, 3888000, 0x57869fd3
+0, 70, 70, 1, 3888000, 0x9d3f9fd3
+0, 73, 73, 1, 3888000, 0x5e6082a5
+0, 74, 74, 1, 3888000, 0x5e6082a5
+0, 75, 75, 1, 3888000, 0x5e6082a5
+0, 76, 76, 1, 3888000, 0x48ce82f3
+0, 77, 77, 1, 3888000, 0x4c5ebeaf
diff --git a/tests/ref/fate/theora-coeff-level64 b/tests/ref/fate/theora-coeff-level64
index d6abb62f70..4bfafaf5ef 100644
--- a/tests/ref/fate/theora-coeff-level64
+++ b/tests/ref/fate/theora-coeff-level64
@@ -1,9 +1,9 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 4617600, 0x4ba6df50
-0, 66, 66, 0, 4617600, 0x419fdeaf
-0, 132, 132, 0, 4617600, 0xeb2edced
-0, 198, 198, 0, 4617600, 0xa2bb3a1a
-0, 264, 264, 0, 4617600, 0x411cfb36
-0, 330, 330, 0, 4617600, 0xb2dc22ed
-0, 396, 396, 0, 4617600, 0x236d23b5
-0, 462, 462, 0, 4617600, 0x7fef275e
+#tb 0: 1/15
+0, 0, 0, 1, 4617600, 0x4ba6df50
+0, 1, 1, 1, 4617600, 0x419fdeaf
+0, 2, 2, 1, 4617600, 0xeb2edced
+0, 3, 3, 1, 4617600, 0xa2bb3a1a
+0, 4, 4, 1, 4617600, 0x411cfb36
+0, 5, 5, 1, 4617600, 0xb2dc22ed
+0, 6, 6, 1, 4617600, 0x236d23b5
+0, 7, 7, 1, 4617600, 0x7fef275e
diff --git a/tests/ref/fate/timefilter b/tests/ref/fate/timefilter
index 57c1209042..2fa88c9b3b 100644
--- a/tests/ref/fate/timefilter
+++ b/tests/ref/fate/timefilter
@@ -1,6 +1,6 @@
- [0.800000 0.000800 0.000000] [1.021025 0.998922 0.000000] [1.021025 0.998922 0.000000] [1.021025 0.998922 0.000000]
- [0.001003 0.000000 0.004341] [0.041562 0.000996 0.045245] [0.081175 0.002874 0.074431] [0.118380 0.006568 0.108913]
- [0.001003 0.000000 0.039073] [0.013619 0.000455 0.224390] [0.041562 0.000996 0.407205] [0.068719 0.002305 0.600848]
- [0.001003 0.000000 0.212729] [0.022518 0.000060 0.941262] [0.015889 0.000507 1.391585] [0.041562 0.000996 2.217003]
- [0.001003 0.000000 0.976818] [0.014412 0.000021 2.712350] [0.013691 0.000370 4.648765] [0.018915 0.000542 6.709646]
- [0.001003 0.000000 4.172097] [0.010677 0.000007 7.809261] [0.018915 0.000032 14.578784] [0.013619 0.000387 20.628496]
+ [80000.000000 0.800000 0.000000] [80000.000000 0.800000 0.000000] [80000.000000 0.800000 0.000000] [80000.000000 0.800000 0.000000]
+ [ 1688.672234 0.000000 0.018551] [ 21.026792 0.000401 0.068856] [ 1.162481 0.008576 0.121287] [ 0.803356 0.016078 0.153518]
+ [ 1218.378235 0.000000 0.167011] [ 12.908626 0.000281 0.296858] [ 21.026792 0.000401 0.619608] [ 2.064064 0.004760 1.020336]
+ [ 1218.378235 0.000000 0.909282] [ 10.047626 0.000191 0.873495] [ 14.909464 0.000297 1.935407] [ 21.026792 0.000401 3.373312]
+ [ 177.634056 0.000002 4.988477] [ 5.363801 0.000176 2.102302] [ 12.879355 0.000195 5.029066] [ 15.615799 0.000298 9.292377]
+ [ 43.713191 0.000007 63.605530] [ 1.345385 0.000213 13.918138] [ 6.800629 0.000142 13.284614] [ 14.909464 0.000142 21.761697]
diff --git a/tests/ref/fate/truemotion1-15 b/tests/ref/fate/truemotion1-15
index 6b5281decf..af4a3205d8 100644
--- a/tests/ref/fate/truemotion1-15
+++ b/tests/ref/fate/truemotion1-15
@@ -1,106 +1,106 @@
#tb 0: 1/15
-0, 0, 0, 1, 161280, 0x7041748d
-0, 1, 1, 1, 161280, 0x3cc4dfb5
-0, 2, 2, 1, 161280, 0xca3af22d
-0, 3, 3, 1, 161280, 0x23ad1d85
-0, 4, 4, 1, 161280, 0x9c9cf364
-0, 5, 5, 1, 161280, 0x1551d6a8
-0, 6, 6, 1, 161280, 0xc39f6b95
-0, 7, 7, 1, 161280, 0x3b036dcc
-0, 8, 8, 1, 161280, 0xa6fac1db
-0, 9, 9, 1, 161280, 0x67656b62
-0, 10, 10, 1, 161280, 0xb41f47d1
-0, 11, 11, 1, 161280, 0xc207249e
-0, 12, 12, 1, 161280, 0xbee8f843
-0, 13, 13, 1, 161280, 0x092acf46
-0, 14, 14, 1, 161280, 0x8d9e2680
-0, 15, 15, 1, 161280, 0x8becc20c
-0, 16, 16, 1, 161280, 0x655e444e
-0, 17, 17, 1, 161280, 0x5c112da0
-0, 18, 18, 1, 161280, 0x232fa9eb
-0, 19, 19, 1, 161280, 0x9721745d
-0, 20, 20, 1, 161280, 0x92f1d880
-0, 21, 21, 1, 161280, 0x16233978
-0, 22, 22, 1, 161280, 0x19a27e69
-0, 23, 23, 1, 161280, 0x7b6ad73a
-0, 24, 24, 1, 161280, 0xa7a674aa
-0, 25, 25, 1, 161280, 0x4e434abb
-0, 26, 26, 1, 161280, 0xb96eea14
-0, 27, 27, 1, 161280, 0x1350188c
-0, 28, 28, 1, 161280, 0x79c6f305
-0, 29, 29, 1, 161280, 0xa9c7782d
-0, 30, 30, 1, 161280, 0x40a4f456
-0, 31, 31, 1, 161280, 0xaf291ed6
-0, 32, 32, 1, 161280, 0xab29b4e1
-0, 33, 33, 1, 161280, 0xbfcd2712
-0, 34, 34, 1, 161280, 0xff22a0d7
-0, 35, 35, 1, 161280, 0xb0ae88a9
-0, 36, 36, 1, 161280, 0x811d1259
-0, 37, 37, 1, 161280, 0x593c39a1
-0, 38, 38, 1, 161280, 0x5a5a97f8
-0, 39, 39, 1, 161280, 0xa5639ecf
-0, 40, 40, 1, 161280, 0x543920c6
-0, 41, 41, 1, 161280, 0xb41689ee
-0, 42, 42, 1, 161280, 0xc0ad83de
-0, 43, 43, 1, 161280, 0x9e9e7456
-0, 44, 44, 1, 161280, 0x777ccbfe
-0, 45, 45, 1, 161280, 0x9c2df916
-0, 46, 46, 1, 161280, 0xe0c13b35
-0, 47, 47, 1, 161280, 0x39bfa5a5
-0, 48, 48, 1, 161280, 0x35dfb264
-0, 49, 49, 1, 161280, 0x43018613
-0, 50, 50, 1, 161280, 0x43584b8a
-0, 51, 51, 1, 161280, 0xa5cd230a
-0, 52, 52, 1, 161280, 0x6fe2cfb3
-0, 53, 53, 1, 161280, 0x88a7c0db
-0, 54, 54, 1, 161280, 0x476f1cd2
-0, 55, 55, 1, 161280, 0x96401d49
-0, 56, 56, 1, 161280, 0x7d932919
-0, 57, 57, 1, 161280, 0x06465481
-0, 58, 58, 1, 161280, 0x39631520
-0, 59, 59, 1, 161280, 0xc3fff780
-0, 60, 60, 1, 161280, 0xa81faf28
-0, 61, 61, 1, 161280, 0x7a311f4f
-0, 62, 62, 1, 161280, 0x52f9b931
-0, 63, 63, 1, 161280, 0x938cf016
-0, 64, 64, 1, 161280, 0xf8f6e19c
-0, 65, 65, 1, 161280, 0xca90561b
-0, 66, 66, 1, 161280, 0x8594d06b
-0, 67, 67, 1, 161280, 0xea32bf3b
-0, 68, 68, 1, 161280, 0x4646111a
-0, 69, 69, 1, 161280, 0xee891162
-0, 70, 70, 1, 161280, 0xcfc32082
-0, 71, 71, 1, 161280, 0x863c281a
-0, 72, 72, 1, 161280, 0x01b591aa
-0, 73, 73, 1, 161280, 0x211fbc62
-0, 74, 74, 1, 161280, 0xae2bafe2
-0, 75, 75, 1, 161280, 0xcfe46dca
-0, 76, 76, 1, 161280, 0xcf8fe8a3
-0, 77, 77, 1, 161280, 0x3f8474eb
-0, 78, 78, 1, 161280, 0x06da345a
-0, 79, 79, 1, 161280, 0xbd4d3280
-0, 80, 80, 1, 161280, 0xb5e70fea
-0, 81, 81, 1, 161280, 0x0c99c804
-0, 82, 82, 1, 161280, 0x19841ed4
-0, 83, 83, 1, 161280, 0xf81dea50
-0, 84, 84, 1, 161280, 0x7777d81c
-0, 85, 85, 1, 161280, 0x0497cfd8
-0, 86, 86, 1, 161280, 0x50b6eb64
-0, 87, 87, 1, 161280, 0x5071fc07
-0, 88, 88, 1, 161280, 0xbb7527fb
-0, 89, 89, 1, 161280, 0x13054f1f
-0, 90, 90, 1, 161280, 0x4b78fb27
-0, 91, 91, 1, 161280, 0xf504968f
-0, 92, 92, 1, 161280, 0x555b10b7
-0, 93, 93, 1, 161280, 0xcc0dde40
-0, 94, 94, 1, 161280, 0xcc0dde40
-0, 95, 95, 1, 161280, 0x367f60c8
-0, 96, 96, 1, 161280, 0x367f60c8
-0, 97, 97, 1, 161280, 0x367f60c8
-0, 98, 98, 1, 161280, 0x367f60c8
-0, 99, 99, 1, 161280, 0x367f60c8
-0, 100, 100, 1, 161280, 0x367f60c8
-0, 101, 101, 1, 161280, 0x367f60c8
-0, 102, 102, 1, 161280, 0x367f60c8
-0, 103, 103, 1, 161280, 0x367f60c8
-0, 104, 104, 1, 161280, 0x367f60c8
+0, 0, 0, 1, 161280, 0x677c9fb3
+0, 1, 1, 1, 161280, 0xaa280e0a
+0, 2, 2, 1, 161280, 0x8a4d2225
+0, 3, 3, 1, 161280, 0xf10f46a8
+0, 4, 4, 1, 161280, 0x98d9eab6
+0, 5, 5, 1, 161280, 0xa543ae1e
+0, 6, 6, 1, 161280, 0x79d717ae
+0, 7, 7, 1, 161280, 0x1a87e2cb
+0, 8, 8, 1, 161280, 0xe5c000ac
+0, 9, 9, 1, 161280, 0xa5827077
+0, 10, 10, 1, 161280, 0xfd0615ee
+0, 11, 11, 1, 161280, 0xc6fdc861
+0, 12, 12, 1, 161280, 0xaa007c7e
+0, 13, 13, 1, 161280, 0xf15e3a96
+0, 14, 14, 1, 161280, 0xce827ae1
+0, 15, 15, 1, 161280, 0xf379fc13
+0, 16, 16, 1, 161280, 0x89686a0c
+0, 17, 17, 1, 161280, 0x7e8342bd
+0, 18, 18, 1, 161280, 0x640dab86
+0, 19, 19, 1, 161280, 0xc6a86456
+0, 20, 20, 1, 161280, 0xe360b538
+0, 21, 21, 1, 161280, 0xbcc21064
+0, 22, 22, 1, 161280, 0x95bc4e63
+0, 23, 23, 1, 161280, 0x390fa1bd
+0, 24, 24, 1, 161280, 0xa35b3bb9
+0, 25, 25, 1, 161280, 0x730b0779
+0, 26, 26, 1, 161280, 0xf3c3a3eb
+0, 27, 27, 1, 161280, 0x676ecbaa
+0, 28, 28, 1, 161280, 0x06c4a4e5
+0, 29, 29, 1, 161280, 0x177d26d9
+0, 30, 30, 1, 161280, 0xdaf69ebe
+0, 31, 31, 1, 161280, 0xabadc296
+0, 32, 32, 1, 161280, 0xec144665
+0, 33, 33, 1, 161280, 0x6785aa48
+0, 34, 34, 1, 161280, 0x2a0cfcaf
+0, 35, 35, 1, 161280, 0x9288d513
+0, 36, 36, 1, 161280, 0x1d295ad0
+0, 37, 37, 1, 161280, 0xb9fd8406
+0, 38, 38, 1, 161280, 0x98bced49
+0, 39, 39, 1, 161280, 0x42e6fbae
+0, 40, 40, 1, 161280, 0xfd218209
+0, 41, 41, 1, 161280, 0x21c2ef31
+0, 42, 42, 1, 161280, 0xce4be932
+0, 43, 43, 1, 161280, 0xd5c0d5fc
+0, 44, 44, 1, 161280, 0xf8d13076
+0, 45, 45, 1, 161280, 0xdbf86007
+0, 46, 46, 1, 161280, 0x9475a651
+0, 47, 47, 1, 161280, 0x41bf1542
+0, 48, 48, 1, 161280, 0x6945297f
+0, 49, 49, 1, 161280, 0x2282025e
+0, 50, 50, 1, 161280, 0x55aace0c
+0, 51, 51, 1, 161280, 0xc78aa51c
+0, 52, 52, 1, 161280, 0xb4b84e6c
+0, 53, 53, 1, 161280, 0x3bbb3e44
+0, 54, 54, 1, 161280, 0x4dd89d80
+0, 55, 55, 1, 161280, 0xa446a5c5
+0, 56, 56, 1, 161280, 0x8f56b1d6
+0, 57, 57, 1, 161280, 0xa170df87
+0, 58, 58, 1, 161280, 0x4740a4df
+0, 59, 59, 1, 161280, 0x86608ee7
+0, 60, 60, 1, 161280, 0x629b4543
+0, 61, 61, 1, 161280, 0x697fb952
+0, 62, 62, 1, 161280, 0x98e84a51
+0, 63, 63, 1, 161280, 0x97949a90
+0, 64, 64, 1, 161280, 0x6a8c9b96
+0, 65, 65, 1, 161280, 0xafa714ab
+0, 66, 66, 1, 161280, 0x0cf39314
+0, 67, 67, 1, 161280, 0x9ccc8171
+0, 68, 68, 1, 161280, 0x8232d5a8
+0, 69, 69, 1, 161280, 0x250dd5cb
+0, 70, 70, 1, 161280, 0xf764e43a
+0, 71, 71, 1, 161280, 0x2f4bec00
+0, 72, 72, 1, 161280, 0x76f1598b
+0, 73, 73, 1, 161280, 0xa91b84da
+0, 74, 74, 1, 161280, 0x011a77fb
+0, 75, 75, 1, 161280, 0xdbf5341c
+0, 76, 76, 1, 161280, 0x40d5abfa
+0, 77, 77, 1, 161280, 0x9fb8360c
+0, 78, 78, 1, 161280, 0xabc5fba8
+0, 79, 79, 1, 161280, 0x98090909
+0, 80, 80, 1, 161280, 0x9a3613bd
+0, 81, 81, 1, 161280, 0x9071024f
+0, 82, 82, 1, 161280, 0x4df39487
+0, 83, 83, 1, 161280, 0x17658524
+0, 84, 84, 1, 161280, 0xbcd794df
+0, 85, 85, 1, 161280, 0x2a14ae05
+0, 86, 86, 1, 161280, 0x664feab2
+0, 87, 87, 1, 161280, 0xf6b721f4
+0, 88, 88, 1, 161280, 0xfec565f3
+0, 89, 89, 1, 161280, 0xd39aabee
+0, 90, 90, 1, 161280, 0x1f3d5de7
+0, 91, 91, 1, 161280, 0xaf97f50c
+0, 92, 92, 1, 161280, 0xe34b6b6a
+0, 93, 93, 1, 161280, 0x4117371e
+0, 94, 94, 1, 161280, 0x4117371e
+0, 95, 95, 1, 161280, 0xe555b55e
+0, 96, 96, 1, 161280, 0xe555b55e
+0, 97, 97, 1, 161280, 0xe555b55e
+0, 98, 98, 1, 161280, 0xe555b55e
+0, 99, 99, 1, 161280, 0xe555b55e
+0, 100, 100, 1, 161280, 0xe555b55e
+0, 101, 101, 1, 161280, 0xe555b55e
+0, 102, 102, 1, 161280, 0xe555b55e
+0, 103, 103, 1, 161280, 0xe555b55e
+0, 104, 104, 1, 161280, 0xe555b55e
diff --git a/tests/ref/fate/tscc-15bit b/tests/ref/fate/tscc-15bit
index 372b165850..a2871efd4d 100644
--- a/tests/ref/fate/tscc-15bit
+++ b/tests/ref/fate/tscc-15bit
@@ -1,242 +1,242 @@
#tb 0: 1/15
#tb 1: 1/11025
-0, 0, 0, 1, 657600, 0xaf456809
+0, 0, 0, 1, 657600, 0x50b3a0c2
1, 0, 0, 11025, 22050, 0x1740aaec
-0, 1, 1, 1, 657600, 0xaf456809
-0, 2, 2, 1, 657600, 0xaf456809
-0, 3, 3, 1, 657600, 0x2dbe6889
-0, 4, 4, 1, 657600, 0x2dbe6889
-0, 5, 5, 1, 657600, 0x2dbe6889
-0, 6, 6, 1, 657600, 0x2dbe6889
-0, 7, 7, 1, 657600, 0x2dbe6889
-0, 8, 8, 1, 657600, 0x2dbe6889
-0, 9, 9, 1, 657600, 0x2dbe6889
-0, 10, 10, 1, 657600, 0x2dbe6889
-0, 11, 11, 1, 657600, 0x2dbe6889
-0, 12, 12, 1, 657600, 0x2dbe6889
-0, 13, 13, 1, 657600, 0x2dbe6889
-0, 14, 14, 1, 657600, 0x2dbe6889
-0, 15, 15, 1, 657600, 0x2dbe6889
+0, 1, 1, 1, 657600, 0x50b3a0c2
+0, 2, 2, 1, 657600, 0x50b3a0c2
+0, 3, 3, 1, 657600, 0x661aa145
+0, 4, 4, 1, 657600, 0x661aa145
+0, 5, 5, 1, 657600, 0x661aa145
+0, 6, 6, 1, 657600, 0x661aa145
+0, 7, 7, 1, 657600, 0x661aa145
+0, 8, 8, 1, 657600, 0x661aa145
+0, 9, 9, 1, 657600, 0x661aa145
+0, 10, 10, 1, 657600, 0x661aa145
+0, 11, 11, 1, 657600, 0x661aa145
+0, 12, 12, 1, 657600, 0x661aa145
+0, 13, 13, 1, 657600, 0x661aa145
+0, 14, 14, 1, 657600, 0x661aa145
+0, 15, 15, 1, 657600, 0x661aa145
1, 11025, 11025, 11025, 22050, 0x75ed6086
-0, 16, 16, 1, 657600, 0x2dbe6889
-0, 17, 17, 1, 657600, 0x2dbe6889
-0, 18, 18, 1, 657600, 0x2dbe6889
-0, 19, 19, 1, 657600, 0x2dbe6889
-0, 20, 20, 1, 657600, 0x2dbe6889
-0, 21, 21, 1, 657600, 0x92796e59
-0, 22, 22, 1, 657600, 0x92796e59
-0, 23, 23, 1, 657600, 0x92796e59
-0, 24, 24, 1, 657600, 0x64cb6889
-0, 25, 25, 1, 657600, 0x64cb6889
-0, 26, 26, 1, 657600, 0x64cb6889
-0, 27, 27, 1, 657600, 0x64cb6889
-0, 28, 28, 1, 657600, 0x64cb6889
-0, 29, 29, 1, 657600, 0x64cb6889
-0, 30, 30, 1, 657600, 0x42036b71
+0, 16, 16, 1, 657600, 0x661aa145
+0, 17, 17, 1, 657600, 0x661aa145
+0, 18, 18, 1, 657600, 0x661aa145
+0, 19, 19, 1, 657600, 0x661aa145
+0, 20, 20, 1, 657600, 0x661aa145
+0, 21, 21, 1, 657600, 0x3c29a73f
+0, 22, 22, 1, 657600, 0x3c29a73f
+0, 23, 23, 1, 657600, 0x3c29a73f
+0, 24, 24, 1, 657600, 0xee2ca145
+0, 25, 25, 1, 657600, 0xee2ca145
+0, 26, 26, 1, 657600, 0xee2ca145
+0, 27, 27, 1, 657600, 0xee2ca145
+0, 28, 28, 1, 657600, 0xee2ca145
+0, 29, 29, 1, 657600, 0xee2ca145
+0, 30, 30, 1, 657600, 0xeb6fa442
1, 22050, 22050, 11025, 22050, 0xca52a4e9
-0, 31, 31, 1, 657600, 0x42036b71
-0, 32, 32, 1, 657600, 0x42036b71
-0, 33, 33, 1, 657600, 0xc40a6889
-0, 34, 34, 1, 657600, 0xc40a6889
-0, 35, 35, 1, 657600, 0xc40a6889
-0, 36, 36, 1, 657600, 0xaa6f7429
-0, 37, 37, 1, 657600, 0xaa6f7429
-0, 38, 38, 1, 657600, 0xaa6f7429
-0, 39, 39, 1, 657600, 0x854172d9
-0, 40, 40, 1, 657600, 0x854172d9
-0, 41, 41, 1, 657600, 0x854172d9
-0, 42, 42, 1, 657600, 0x22d10de0
-0, 43, 43, 1, 657600, 0xa75f0d60
-0, 44, 44, 1, 657600, 0x7a440be0
-0, 45, 45, 1, 657600, 0x40095d50
+0, 31, 31, 1, 657600, 0xeb6fa442
+0, 32, 32, 1, 657600, 0xeb6fa442
+0, 33, 33, 1, 657600, 0xb235a145
+0, 34, 34, 1, 657600, 0xb235a145
+0, 35, 35, 1, 657600, 0xb235a145
+0, 36, 36, 1, 657600, 0x39f7ad39
+0, 37, 37, 1, 657600, 0x39f7ad39
+0, 38, 38, 1, 657600, 0x39f7ad39
+0, 39, 39, 1, 657600, 0xb851abda
+0, 40, 40, 1, 657600, 0xb851abda
+0, 41, 41, 1, 657600, 0xb851abda
+0, 42, 42, 1, 657600, 0xf6574b22
+0, 43, 43, 1, 657600, 0x1a154a9f
+0, 44, 44, 1, 657600, 0x3de64916
+0, 45, 45, 1, 657600, 0xca3d9cd5
1, 33075, 33075, 11025, 22050, 0xb306d419
-0, 46, 46, 1, 657600, 0x40095d50
-0, 47, 47, 1, 657600, 0x64766320
-0, 48, 48, 1, 657600, 0x64766320
-0, 49, 49, 1, 657600, 0x64766320
-0, 50, 50, 1, 657600, 0x64766320
-0, 51, 51, 1, 657600, 0x64766320
-0, 52, 52, 1, 657600, 0x64766320
-0, 53, 53, 1, 657600, 0x64766320
-0, 54, 54, 1, 657600, 0x64766320
-0, 55, 55, 1, 657600, 0x64766320
-0, 56, 56, 1, 657600, 0x64766320
-0, 57, 57, 1, 657600, 0xf51adc49
-0, 58, 58, 1, 657600, 0xf51adc49
-0, 59, 59, 1, 657600, 0xf51adc49
-0, 60, 60, 1, 657600, 0xdd47af59
+0, 46, 46, 1, 657600, 0xca3d9cd5
+0, 47, 47, 1, 657600, 0x4779a2cf
+0, 48, 48, 1, 657600, 0x4779a2cf
+0, 49, 49, 1, 657600, 0x4779a2cf
+0, 50, 50, 1, 657600, 0x4779a2cf
+0, 51, 51, 1, 657600, 0x4779a2cf
+0, 52, 52, 1, 657600, 0x4779a2cf
+0, 53, 53, 1, 657600, 0x4779a2cf
+0, 54, 54, 1, 657600, 0x4779a2cf
+0, 55, 55, 1, 657600, 0x4779a2cf
+0, 56, 56, 1, 657600, 0x4779a2cf
+0, 57, 57, 1, 657600, 0x29af1818
+0, 58, 58, 1, 657600, 0x29af1818
+0, 59, 59, 1, 657600, 0x29af1818
+0, 60, 60, 1, 657600, 0x77ace9c5
1, 44100, 44100, 11025, 22050, 0x8cbb9625
-0, 61, 61, 1, 657600, 0xdd47af59
-0, 62, 62, 1, 657600, 0xffa8acf1
-0, 63, 63, 1, 657600, 0x5994b059
-0, 64, 64, 1, 657600, 0x5994b059
-0, 65, 65, 1, 657600, 0x5994b059
-0, 66, 66, 1, 657600, 0x03ffae71
-0, 67, 67, 1, 657600, 0x03ffae71
-0, 68, 68, 1, 657600, 0x03ffae71
-0, 69, 69, 1, 657600, 0xe33ab89e
-0, 70, 70, 1, 657600, 0xe33ab89e
-0, 71, 71, 1, 657600, 0xe33ab89e
-0, 72, 72, 1, 657600, 0xbe37b549
-0, 73, 73, 1, 657600, 0xbe37b549
-0, 74, 74, 1, 657600, 0x1d395bf9
-0, 75, 75, 1, 657600, 0x1d395bf9
+0, 61, 61, 1, 657600, 0x77ace9c5
+0, 62, 62, 1, 657600, 0x61b8e74b
+0, 63, 63, 1, 657600, 0x8c6deace
+0, 64, 64, 1, 657600, 0x8c6deace
+0, 65, 65, 1, 657600, 0x8c6deace
+0, 66, 66, 1, 657600, 0xbe1fe8d7
+0, 67, 67, 1, 657600, 0xbe1fe8d7
+0, 68, 68, 1, 657600, 0xbe1fe8d7
+0, 69, 69, 1, 657600, 0x633209db
+0, 70, 70, 1, 657600, 0x633209db
+0, 71, 71, 1, 657600, 0x633209db
+0, 72, 72, 1, 657600, 0x3148adb5
+0, 73, 73, 1, 657600, 0x3148adb5
+0, 74, 74, 1, 657600, 0x3b5f5216
+0, 75, 75, 1, 657600, 0x3b5f5216
1, 55125, 55125, 11025, 22050, 0x34a11f66
-0, 76, 76, 1, 657600, 0x1d395bf9
-0, 77, 77, 1, 657600, 0x1d395bf9
-0, 78, 78, 1, 657600, 0x2ec36f37
-0, 79, 79, 1, 657600, 0x2ec36f37
-0, 80, 80, 1, 657600, 0xb04a6eb7
-0, 81, 81, 1, 657600, 0x66610458
-0, 82, 82, 1, 657600, 0x66610458
-0, 83, 83, 1, 657600, 0xaf8901f0
-0, 84, 84, 1, 657600, 0x3ae41c48
-0, 85, 85, 1, 657600, 0x5b870b70
-0, 86, 86, 1, 657600, 0x11490c60
-0, 87, 87, 1, 657600, 0x70064801
-0, 88, 88, 1, 657600, 0x80d54519
-0, 89, 89, 1, 657600, 0xe8c942b1
-0, 90, 90, 1, 657600, 0x830d8c24
+0, 76, 76, 1, 657600, 0x3b5f5216
+0, 77, 77, 1, 657600, 0x3b5f5216
+0, 78, 78, 1, 657600, 0x5e51fb89
+0, 79, 79, 1, 657600, 0x5e51fb89
+0, 80, 80, 1, 657600, 0x48eafb06
+0, 81, 81, 1, 657600, 0x9f7a8653
+0, 82, 82, 1, 657600, 0x9f7a8653
+0, 83, 83, 1, 657600, 0x29fc83d9
+0, 84, 84, 1, 657600, 0xe7689f10
+0, 85, 85, 1, 657600, 0x9f788dba
+0, 86, 86, 1, 657600, 0x0e808eb2
+0, 87, 87, 1, 657600, 0x3ec53d79
+0, 88, 88, 1, 657600, 0x67ca3a7c
+0, 89, 89, 1, 657600, 0xf7583802
+0, 90, 90, 1, 657600, 0x239e2fc6
1, 66150, 66150, 11025, 22050, 0x1ae81230
-0, 91, 91, 1, 657600, 0x830d8c24
-0, 92, 92, 1, 657600, 0x830d8c24
-0, 93, 93, 1, 657600, 0xf3c4707c
-0, 94, 94, 1, 657600, 0x6ace707c
-0, 95, 95, 1, 657600, 0x6ace707c
-0, 96, 96, 1, 657600, 0x6ace707c
-0, 97, 97, 1, 657600, 0x6ace707c
-0, 98, 98, 1, 657600, 0x6ace707c
-0, 99, 99, 1, 657600, 0x5f461aae
-0, 100, 100, 1, 657600, 0x5f461aae
-0, 101, 101, 1, 657600, 0x221ceecf
-0, 102, 102, 1, 657600, 0x221ceecf
-0, 103, 103, 1, 657600, 0x221ceecf
-0, 104, 104, 1, 657600, 0x221ceecf
-0, 105, 105, 1, 657600, 0x221ceecf
+0, 91, 91, 1, 657600, 0x239e2fc6
+0, 92, 92, 1, 657600, 0x239e2fc6
+0, 93, 93, 1, 657600, 0x001c134c
+0, 94, 94, 1, 657600, 0x5c85134c
+0, 95, 95, 1, 657600, 0x5c85134c
+0, 96, 96, 1, 657600, 0x5c85134c
+0, 97, 97, 1, 657600, 0x5c85134c
+0, 98, 98, 1, 657600, 0x5c85134c
+0, 99, 99, 1, 657600, 0x5fef8bea
+0, 100, 100, 1, 657600, 0x5fef8bea
+0, 101, 101, 1, 657600, 0x23135efa
+0, 102, 102, 1, 657600, 0x23135efa
+0, 103, 103, 1, 657600, 0x23135efa
+0, 104, 104, 1, 657600, 0x23135efa
+0, 105, 105, 1, 657600, 0x23135efa
1, 77175, 77175, 11025, 22050, 0x1217eeba
-0, 106, 106, 1, 657600, 0x221ceecf
-0, 107, 107, 1, 657600, 0x221ceecf
-0, 108, 108, 1, 657600, 0x3bf6f39f
-0, 109, 109, 1, 657600, 0x3bf6f39f
-0, 110, 110, 1, 657600, 0x3bf6f39f
-0, 111, 111, 1, 657600, 0xc2caeecf
-0, 112, 112, 1, 657600, 0xc2caeecf
-0, 113, 113, 1, 657600, 0xc2caeecf
-0, 114, 114, 1, 657600, 0xc316d63e
-0, 115, 115, 1, 657600, 0xc316d63e
-0, 116, 116, 1, 657600, 0xc316d63e
-0, 117, 117, 1, 657600, 0x41f6218d
-0, 118, 118, 1, 657600, 0x41f6218d
-0, 119, 119, 1, 657600, 0x41f6218d
-0, 120, 120, 1, 657600, 0xff43ec36
+0, 106, 106, 1, 657600, 0x23135efa
+0, 107, 107, 1, 657600, 0x23135efa
+0, 108, 108, 1, 657600, 0x50cf63ee
+0, 109, 109, 1, 657600, 0x50cf63ee
+0, 110, 110, 1, 657600, 0x50cf63ee
+0, 111, 111, 1, 657600, 0x2f5c5efa
+0, 112, 112, 1, 657600, 0x2f5c5efa
+0, 113, 113, 1, 657600, 0x2f5c5efa
+0, 114, 114, 1, 657600, 0x9980d3c1
+0, 115, 115, 1, 657600, 0x9980d3c1
+0, 116, 116, 1, 657600, 0x9980d3c1
+0, 117, 117, 1, 657600, 0x23f02141
+0, 118, 118, 1, 657600, 0x23f02141
+0, 119, 119, 1, 657600, 0x23f02141
+0, 120, 120, 1, 657600, 0x3d31ea57
1, 88200, 88200, 11025, 22050, 0x50e70baa
-0, 121, 121, 1, 657600, 0x0b10eb16
-0, 122, 122, 1, 657600, 0x0b10eb16
-0, 123, 123, 1, 657600, 0xbdf41aa5
-0, 124, 124, 1, 657600, 0xbdf41aa5
-0, 125, 125, 1, 657600, 0xbdf41aa5
-0, 126, 126, 1, 657600, 0xd502ca06
-0, 127, 127, 1, 657600, 0xd502ca06
-0, 128, 128, 1, 657600, 0xd502ca06
-0, 129, 129, 1, 657600, 0x8446f89e
-0, 130, 130, 1, 657600, 0x8446f89e
-0, 131, 131, 1, 657600, 0x8446f89e
-0, 132, 132, 1, 657600, 0x3d4ccf06
-0, 133, 133, 1, 657600, 0x0897d1de
-0, 134, 134, 1, 657600, 0x0897d1de
-0, 135, 135, 1, 657600, 0x3e27e01e
+0, 121, 121, 1, 657600, 0x1e9be92f
+0, 122, 122, 1, 657600, 0x1e9be92f
+0, 123, 123, 1, 657600, 0x05091a2e
+0, 124, 124, 1, 657600, 0x05091a2e
+0, 125, 125, 1, 657600, 0x05091a2e
+0, 126, 126, 1, 657600, 0xd214c71a
+0, 127, 127, 1, 657600, 0xd214c71a
+0, 128, 128, 1, 657600, 0xd214c71a
+0, 129, 129, 1, 657600, 0x3b07f720
+0, 130, 130, 1, 657600, 0x3b07f720
+0, 131, 131, 1, 657600, 0x3b07f720
+0, 132, 132, 1, 657600, 0x02becc42
+0, 133, 133, 1, 657600, 0x3d8fcf2e
+0, 134, 134, 1, 657600, 0x3d8fcf2e
+0, 135, 135, 1, 657600, 0xec51ddd7
1, 99225, 99225, 11025, 22050, 0xb19e89c0
-0, 136, 136, 1, 657600, 0x3e27e01e
-0, 137, 137, 1, 657600, 0x3e27e01e
-0, 138, 138, 1, 657600, 0x3e27e01e
-0, 139, 139, 1, 657600, 0x3e27e01e
-0, 140, 140, 1, 657600, 0x3e27e01e
-0, 141, 141, 1, 657600, 0xe51078a8
-0, 142, 142, 1, 657600, 0xe51078a8
-0, 143, 143, 1, 657600, 0xe9967a40
-0, 144, 144, 1, 657600, 0xe9967a40
-0, 145, 145, 1, 657600, 0xe9967a40
-0, 146, 146, 1, 657600, 0xe9967a40
-0, 147, 147, 1, 657600, 0xe9967a40
-0, 148, 148, 1, 657600, 0xe9967a40
-0, 149, 149, 1, 657600, 0xe9967a40
-0, 150, 150, 1, 657600, 0x726cb6b8
+0, 136, 136, 1, 657600, 0xec51ddd7
+0, 137, 137, 1, 657600, 0xec51ddd7
+0, 138, 138, 1, 657600, 0xec51ddd7
+0, 139, 139, 1, 657600, 0xec51ddd7
+0, 140, 140, 1, 657600, 0xec51ddd7
+0, 141, 141, 1, 657600, 0x40a3b905
+0, 142, 142, 1, 657600, 0x40a3b905
+0, 143, 143, 1, 657600, 0xbfc5baa9
+0, 144, 144, 1, 657600, 0xbfc5baa9
+0, 145, 145, 1, 657600, 0xbfc5baa9
+0, 146, 146, 1, 657600, 0xbfc5baa9
+0, 147, 147, 1, 657600, 0xbfc5baa9
+0, 148, 148, 1, 657600, 0xbfc5baa9
+0, 149, 149, 1, 657600, 0xbfc5baa9
+0, 150, 150, 1, 657600, 0x54a2f8dd
1, 110250, 110250, 11025, 22050, 0x78526696
-0, 151, 151, 1, 657600, 0x2960b6e8
-0, 152, 152, 1, 657600, 0x2960b6e8
-0, 153, 153, 1, 657600, 0x1637d6c8
-0, 154, 154, 1, 657600, 0x6f2fd9b0
-0, 155, 155, 1, 657600, 0x27a7d6c8
-0, 156, 156, 1, 657600, 0xe855d6c8
-0, 157, 157, 1, 657600, 0xe855d6c8
-0, 158, 158, 1, 657600, 0xe855d6c8
-0, 159, 159, 1, 657600, 0x1a8ad6c8
-0, 160, 160, 1, 657600, 0x9c11d648
-0, 161, 161, 1, 657600, 0x6136d648
-0, 162, 162, 1, 657600, 0xdfa0d6c8
-0, 163, 163, 1, 657600, 0xdfa0d6c8
-0, 164, 164, 1, 657600, 0xdfa0d6c8
-0, 165, 165, 1, 657600, 0xdfa0d6c8
+0, 151, 151, 1, 657600, 0x0b96f90d
+0, 152, 152, 1, 657600, 0x0b96f90d
+0, 153, 153, 1, 657600, 0xa18119e9
+0, 154, 154, 1, 657600, 0x70a11ce6
+0, 155, 155, 1, 657600, 0xb36f19e9
+0, 156, 156, 1, 657600, 0xeb2219e9
+0, 157, 157, 1, 657600, 0xeb2219e9
+0, 158, 158, 1, 657600, 0xeb2219e9
+0, 159, 159, 1, 657600, 0xb98f19e9
+0, 160, 160, 1, 657600, 0xa4281966
+0, 161, 161, 1, 657600, 0xf0e61966
+0, 162, 162, 1, 657600, 0x065c19e9
+0, 163, 163, 1, 657600, 0x065c19e9
+0, 164, 164, 1, 657600, 0x065c19e9
+0, 165, 165, 1, 657600, 0x065c19e9
1, 121275, 121275, 11025, 22050, 0x48e3bb21
-0, 166, 166, 1, 657600, 0xdfa0d6c8
-0, 167, 167, 1, 657600, 0xdfa0d6c8
-0, 168, 168, 1, 657600, 0xdfa0d6c8
-0, 169, 169, 1, 657600, 0xdfa0d6c8
-0, 170, 170, 1, 657600, 0xdfa0d6c8
-0, 171, 171, 1, 657600, 0x125cd9b0
-0, 172, 172, 1, 657600, 0x125cd9b0
-0, 173, 173, 1, 657600, 0x8a7ed6c8
-0, 174, 174, 1, 657600, 0x09a6d9b0
-0, 175, 175, 1, 657600, 0x09a6d9b0
-0, 176, 176, 1, 657600, 0x09a6d9b0
-0, 177, 177, 1, 657600, 0x85e87a68
-0, 178, 178, 1, 657600, 0x85e87a68
-0, 179, 179, 1, 657600, 0x85e87a68
-0, 180, 180, 1, 657600, 0xb0a141a8
+0, 166, 166, 1, 657600, 0x065c19e9
+0, 167, 167, 1, 657600, 0x065c19e9
+0, 168, 168, 1, 657600, 0x065c19e9
+0, 169, 169, 1, 657600, 0x065c19e9
+0, 170, 170, 1, 657600, 0x065c19e9
+0, 171, 171, 1, 657600, 0x2f1d1ce6
+0, 172, 172, 1, 657600, 0x2f1d1ce6
+0, 173, 173, 1, 657600, 0x181719e9
+0, 174, 174, 1, 657600, 0x938d1ce6
+0, 175, 175, 1, 657600, 0x938d1ce6
+0, 176, 176, 1, 657600, 0x938d1ce6
+0, 177, 177, 1, 657600, 0xf0acbabf
+0, 178, 178, 1, 657600, 0xf0acbabf
+0, 179, 179, 1, 657600, 0xf0acbabf
+0, 180, 180, 1, 657600, 0x0f47804f
1, 132300, 132300, 11025, 22050, 0xbc32204a
-0, 181, 181, 1, 657600, 0xb0a141a8
-0, 182, 182, 1, 657600, 0xf3333bd8
-0, 183, 183, 1, 657600, 0xea090688
-0, 184, 184, 1, 657600, 0xa017fe41
-0, 185, 185, 1, 657600, 0xa017fe41
-0, 186, 186, 1, 657600, 0x32e93bd8
-0, 187, 187, 1, 657600, 0x7fe640c0
-0, 188, 188, 1, 657600, 0x7fe640c0
-0, 189, 189, 1, 657600, 0xcd8995b2
-0, 190, 190, 1, 657600, 0x84278a92
-0, 191, 191, 1, 657600, 0x84278a92
-0, 192, 192, 1, 657600, 0xf1d2874a
-0, 193, 193, 1, 657600, 0xf1d2874a
-0, 194, 194, 1, 657600, 0xf1d2874a
-0, 195, 195, 1, 657600, 0xa58d6742
+0, 181, 181, 1, 657600, 0x0f47804f
+0, 182, 182, 1, 657600, 0x5e0c7a55
+0, 183, 183, 1, 657600, 0x0c8f4374
+0, 184, 184, 1, 657600, 0x709a3b00
+0, 185, 185, 1, 657600, 0x709a3b00
+0, 186, 186, 1, 657600, 0xf57b7a0f
+0, 187, 187, 1, 657600, 0x99427f1b
+0, 188, 188, 1, 657600, 0x99427f1b
+0, 189, 189, 1, 657600, 0xcb3608e7
+0, 190, 190, 1, 657600, 0x0992fd64
+0, 191, 191, 1, 657600, 0x0992fd64
+0, 192, 192, 1, 657600, 0x7a95fa02
+0, 193, 193, 1, 657600, 0x7a95fa02
+0, 194, 194, 1, 657600, 0x7a95fa02
+0, 195, 195, 1, 657600, 0xb97dd910
1, 143325, 143325, 11025, 22050, 0xdf6f1e46
-0, 196, 196, 1, 657600, 0xa58d6742
-0, 197, 197, 1, 657600, 0xa58d6742
-0, 198, 198, 1, 657600, 0xb0cd11bb
-0, 199, 199, 1, 657600, 0xb0cd11bb
-0, 200, 200, 1, 657600, 0xc55610bb
-0, 201, 201, 1, 657600, 0x4ee1168b
-0, 202, 202, 1, 657600, 0x61c513a3
-0, 203, 203, 1, 657600, 0xd26410bb
-0, 204, 204, 1, 657600, 0xe7c410bb
-0, 205, 205, 1, 657600, 0x444a0dd3
-0, 206, 206, 1, 657600, 0x444a0dd3
-0, 207, 207, 1, 657600, 0x97ac10bb
-0, 208, 208, 1, 657600, 0x97ac10bb
-0, 209, 209, 1, 657600, 0xe8b30dd3
-0, 210, 210, 1, 657600, 0x3d0c10bb
+0, 196, 196, 1, 657600, 0xb97dd910
+0, 197, 197, 1, 657600, 0xb97dd910
+0, 198, 198, 1, 657600, 0x3be07a66
+0, 199, 199, 1, 657600, 0x3be07a66
+0, 200, 200, 1, 657600, 0x1ae77960
+0, 201, 201, 1, 657600, 0x62177f5a
+0, 202, 202, 1, 657600, 0xf57c7c5d
+0, 203, 203, 1, 657600, 0x600e7960
+0, 204, 204, 1, 657600, 0xe15d7960
+0, 205, 205, 1, 657600, 0x79427663
+0, 206, 206, 1, 657600, 0x79427663
+0, 207, 207, 1, 657600, 0xa7c77960
+0, 208, 208, 1, 657600, 0xa7c77960
+0, 209, 209, 1, 657600, 0x75f67663
+0, 210, 210, 1, 657600, 0x3a157960
1, 154350, 154350, 11025, 22050, 0x4c91da9d
-0, 211, 211, 1, 657600, 0x8d2b0dd3
-0, 212, 212, 1, 657600, 0x8d2b0dd3
-0, 213, 213, 1, 657600, 0xa5760dd3
-0, 214, 214, 1, 657600, 0xa5760dd3
-0, 215, 215, 1, 657600, 0xa5760dd3
-0, 216, 216, 1, 657600, 0x31a30dd3
-0, 217, 217, 1, 657600, 0x31a30dd3
-0, 218, 218, 1, 657600, 0x31a30dd3
-0, 219, 219, 1, 657600, 0x31a30dd3
-0, 220, 220, 1, 657600, 0x31a30dd3
-0, 221, 221, 1, 657600, 0x31a30dd3
-0, 222, 222, 1, 657600, 0x31a30dd3
-0, 223, 223, 1, 657600, 0x31a30dd3
-0, 224, 224, 1, 657600, 0x31a30dd3
+0, 211, 211, 1, 657600, 0x72aa7663
+0, 212, 212, 1, 657600, 0x72aa7663
+0, 213, 213, 1, 657600, 0x1b277663
+0, 214, 214, 1, 657600, 0x1b277663
+0, 215, 215, 1, 657600, 0x1b277663
+0, 216, 216, 1, 657600, 0x6f5e7663
+0, 217, 217, 1, 657600, 0x6f5e7663
+0, 218, 218, 1, 657600, 0x6f5e7663
+0, 219, 219, 1, 657600, 0x6f5e7663
+0, 220, 220, 1, 657600, 0x6f5e7663
+0, 221, 221, 1, 657600, 0x6f5e7663
+0, 222, 222, 1, 657600, 0x6f5e7663
+0, 223, 223, 1, 657600, 0x6f5e7663
+0, 224, 224, 1, 657600, 0x6f5e7663
diff --git a/tests/ref/fate/unknown_layout-ac3 b/tests/ref/fate/unknown_layout-ac3
new file mode 100644
index 0000000000..d332efcec4
--- /dev/null
+++ b/tests/ref/fate/unknown_layout-ac3
@@ -0,0 +1 @@
+bbb7550d6d93973c10f4ee13c87cf799
diff --git a/tests/ref/fate/unknown_layout-pcm b/tests/ref/fate/unknown_layout-pcm
new file mode 100644
index 0000000000..73c6a2dbab
--- /dev/null
+++ b/tests/ref/fate/unknown_layout-pcm
@@ -0,0 +1 @@
+4dada0795adf50f7a0e60861658f86ea
diff --git a/tests/ref/fate/utvideoenc_rgb_left b/tests/ref/fate/utvideoenc_rgb_left
index 99d1182f73..f6adabe9d9 100644
--- a/tests/ref/fate/utvideoenc_rgb_left
+++ b/tests/ref/fate/utvideoenc_rgb_left
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 182328, cd084b244939d7e0008d8e5ab3429dc1
0, 1, 1, 1, 182336, c9c40672750f372134185901147fb776
0, 2, 2, 1, 182956, c728911ca73225f2dc7453533c9be95e
@@ -40,7 +44,7 @@
0, 38, 38, 1, 179776, 01d407ed0b86eeb2c3ee3c24dd452d8d
0, 39, 39, 1, 180100, 062e4af150100d7accf86a907a4b99b5
0, 40, 40, 1, 180228, 23c617b76ef8f274bd089016fb8516c7
-0, 41, 41, 1, 180592, 55f538ae5e44b60209138b7536d5c199
+0, 41, 41, 1, 180592, 5cd3d93597325196079dc019556f6933
0, 42, 42, 1, 181188, d39d52f5b690661434b1abd8717b3e30
0, 43, 43, 1, 181300, 9e202444287234bafd103fab83b1a974
0, 44, 44, 1, 180812, 602165271de71594132cce98af56a7b2
diff --git a/tests/ref/fate/utvideoenc_rgb_median b/tests/ref/fate/utvideoenc_rgb_median
index 5983ddf4b3..3d4c22bd34 100644
--- a/tests/ref/fate/utvideoenc_rgb_median
+++ b/tests/ref/fate/utvideoenc_rgb_median
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 182160, abcf4f477f74b696faca2fcff1f62aa9
0, 1, 1, 1, 182104, 7cbcf339fa40c24522067295b39d637f
0, 2, 2, 1, 183108, dfc2c418f4379a89654c16b34ff19446
diff --git a/tests/ref/fate/utvideoenc_rgb_none b/tests/ref/fate/utvideoenc_rgb_none
index d6c69625fa..839766bf4d 100644
--- a/tests/ref/fate/utvideoenc_rgb_none
+++ b/tests/ref/fate/utvideoenc_rgb_none
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 301052, 8645cb98470205cceea3c2026223b69f
-0, 1, 1, 1, 301068, 9123c3c31ac0bc0832bb07e8c6d5b372
-0, 2, 2, 1, 300840, 394aa034eba2b306efa8171efc5fb960
-0, 3, 3, 1, 300904, 1abc4512d268bb7bb4b9f467aa19e5a8
-0, 4, 4, 1, 300912, e117d6f8d2bbd89bdce86cd5c4cf6206
-0, 5, 5, 1, 300936, d6a6c100e6dfd0e4dcdaa67ec59a757a
-0, 6, 6, 1, 300944, 3a0bf05461965bf2e538f5ed1067e784
-0, 7, 7, 1, 301044, 66e2fef970e8d997bb52f28eed9ad6fe
-0, 8, 8, 1, 301076, 6ae8f26125255c46be8c6da07d21ba35
-0, 9, 9, 1, 301044, 024d41f9d3b217b58ad6ba2a8f3b680d
-0, 10, 10, 1, 300944, 5dc0387f32b68e365c467f9dcc62b923
-0, 11, 11, 1, 300912, 47db16c6118feb2143fe0d1ec909bb51
-0, 12, 12, 1, 301044, 7161af85d2c85529b83548a701c6f5b7
-0, 13, 13, 1, 300964, 2dd90b4edcfc8d2b84168f42c7a47785
-0, 14, 14, 1, 300868, 76b296949227e7b22f204bec90dd02af
-0, 15, 15, 1, 300880, 44f9c830be2c9efdda335bf774f3b6c6
-0, 16, 16, 1, 301020, 70c1883ae4ff2ae8b0d5a608a75c839c
-0, 17, 17, 1, 301072, bac10cb932595594e4e8146831bbe00b
-0, 18, 18, 1, 301192, 46c2aa31dc33baa4d37f71f9873cbe6f
-0, 19, 19, 1, 301224, 396c406acf79cbe79c064ccbe7a3b648
-0, 20, 20, 1, 301180, 8d5d2071ddc79335f6785a921851905e
-0, 21, 21, 1, 301180, 9767bc30cadd23f0625e665e9b70ac31
-0, 22, 22, 1, 301116, fba702e0ab727d9446a7796790a10545
-0, 23, 23, 1, 301060, 9a08113dd947874b57d4cc85d56343ca
-0, 24, 24, 1, 301128, a58b1ebeb28fac3c88f64c8ba15f0591
-0, 25, 25, 1, 301144, e071b28b961f8d9c5da9b1ff41c24c2a
-0, 26, 26, 1, 301088, d19bed9054db25a718724d746d22c800
-0, 27, 27, 1, 301232, 70b2832bb0eb5f8a74e0bee411f66a46
-0, 28, 28, 1, 301152, 470bd72096d3ef6b5490b03cfdea438d
-0, 29, 29, 1, 301224, f3c285eb28a3c5b820276d3a68976df4
-0, 30, 30, 1, 301224, a432bfc1e022f189a70cbc963d716596
-0, 31, 31, 1, 301160, fbde0ac1bb6e5dbd870c1c6d8f03190c
-0, 32, 32, 1, 301120, 61f251db3d73483206609718063cfbb9
-0, 33, 33, 1, 301096, 6c1908eac263c8c3368683ced8078da4
-0, 34, 34, 1, 301000, 4b8df4fa83c085ea36369dbdd37f58bd
-0, 35, 35, 1, 301152, e2ceb9ff6b72b815e4b511a85dc0ae38
-0, 36, 36, 1, 301232, 27cc508ff5081f9c901c4eabd62e5835
-0, 37, 37, 1, 301228, bdb62b975b1cfe4ba8be08be1e8b1a5e
-0, 38, 38, 1, 301296, 13fc07f3935b70e98922233cf81bc7a4
-0, 39, 39, 1, 301296, 5fe19496257987b809e56e3c11192c43
-0, 40, 40, 1, 301308, a86115cd10e74c795739e8e325403ac6
-0, 41, 41, 1, 301268, 6c1f7bbf077ff58486f256e2ce9d01e6
-0, 42, 42, 1, 301344, 3fda739956dfa07a15cc5bd7e054568d
-0, 43, 43, 1, 301308, 54584061bcce46feb19aafa37922f923
-0, 44, 44, 1, 301292, 092e08d230dcfe4abd1460ef26c31421
-0, 45, 45, 1, 301344, 39ca46f9f38434aee15660263921f392
-0, 46, 46, 1, 301432, f7b76bebcfc614537c20bd6b20096d78
-0, 47, 47, 1, 301440, 86c97147d03bf7aee71073127c7fad32
-0, 48, 48, 1, 301460, 3fdbe5ae0b7e6b7ec0bc5668ba50a491
-0, 49, 49, 1, 301444, 8ef2e62af67f91e886b8f25456b38869
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 301024, 44de62472f485410819707c44b53f276
+0, 1, 1, 1, 301036, ff3c28c23b15834a84c57b304610924f
+0, 2, 2, 1, 300812, 72f02a697464f5fdd54ae2e054c131d1
+0, 3, 3, 1, 300876, 8879becf8b3d5001b196f45b7817ef6b
+0, 4, 4, 1, 300880, 2edeed55c4d84dea1fc9386553d7503f
+0, 5, 5, 1, 300904, f799f26eae30e1796bd62f9cdbcb2b17
+0, 6, 6, 1, 300908, bc606ee3ab284d3567a3fbd476d674f0
+0, 7, 7, 1, 301012, 404f55be9ec860a1ab3d15711965c9ba
+0, 8, 8, 1, 301048, 112394db28656101b4e8ba3621b437ae
+0, 9, 9, 1, 301008, 8945bb7668b4a529844e68e1f6b6522b
+0, 10, 10, 1, 300908, a9097c5f0bd7ddea711a25aa74696f70
+0, 11, 11, 1, 300876, 579de317d166295088530c78f403611d
+0, 12, 12, 1, 301012, d97e3627c494012d6167a30ec8192360
+0, 13, 13, 1, 300928, fd20066b7f31363751328aefedfae04c
+0, 14, 14, 1, 300836, d9bdd5606f4426b503f19a674e8058a3
+0, 15, 15, 1, 300848, 6c8f2cbd75646592876f8138a017c1ce
+0, 16, 16, 1, 300988, 54e19940011b3bfed809a0edc12c3dd7
+0, 17, 17, 1, 301040, b1d5f39215f305953a846fb01dbc2f24
+0, 18, 18, 1, 301164, 9dde74f0ee3626eeea41c538fd80e1fb
+0, 19, 19, 1, 301196, fdf22d2c35c7ab72416a268bf6612650
+0, 20, 20, 1, 301148, 275261bc1c1dec0bf712dcf05213def2
+0, 21, 21, 1, 301144, 66ccea6fce9d6d7016dafb3b349fa163
+0, 22, 22, 1, 301080, d6dc6ce0708dfdf74e936271a98c19e9
+0, 23, 23, 1, 301028, 48e610b9d798e0642825919fab233524
+0, 24, 24, 1, 301100, aed8f8f0a9d96ab9906ea8175e18c9ff
+0, 25, 25, 1, 301116, fe9e1eccb9ccc92b4041228ea2c56c8e
+0, 26, 26, 1, 301052, 3ec2f76b41fd8a6eafaa6bb14b94c153
+0, 27, 27, 1, 301200, 60d608bbe0ca285a7d8a1a4822a84c4d
+0, 28, 28, 1, 301120, 6d2cec50ee32e76eb6dff76a4976d221
+0, 29, 29, 1, 301188, 8faa69fd62e0646e4eb85c1601827364
+0, 30, 30, 1, 301192, eb1fa109c5e9b89f29be7cf363649acd
+0, 31, 31, 1, 301128, 32ba1797f5dee6643712688621984326
+0, 32, 32, 1, 301088, a1bfa70314c40f60a0823beef74e233e
+0, 33, 33, 1, 301064, b18d84efa0091199dd9167bbdb36b873
+0, 34, 34, 1, 300964, a2ae8d3dd655403bcfdace40aaa1d78b
+0, 35, 35, 1, 301124, 8ece60df0f0ef4f3d887eac16c23cad6
+0, 36, 36, 1, 301200, 13eb4b5ec7471837aadce38848e48cb2
+0, 37, 37, 1, 301196, b5fdef211755134f8e7998793a0ab0c0
+0, 38, 38, 1, 301260, 2f7e2046bae9e664e74bc56a3596743c
+0, 39, 39, 1, 301264, 2cfc013c9e66a5dd0229c6551febd658
+0, 40, 40, 1, 301272, 47e8ff02a8f054c66687e2b613e46cf5
+0, 41, 41, 1, 301236, f4d766155eeeb7b03687a3141840bf32
+0, 42, 42, 1, 301312, 8fe134aefc02b6910dc2054447fd9c37
+0, 43, 43, 1, 301272, 9ec57db275fca2b596734c48a50c28bc
+0, 44, 44, 1, 301256, 17bae207d8d6f5b2b500885e3058185f
+0, 45, 45, 1, 301308, 9f8e91f3fbbdd0ca17b2ad0ffe888d5a
+0, 46, 46, 1, 301400, 8184e55eb5432516547df512175c15fc
+0, 47, 47, 1, 301408, dd0c0aa1426427549e9cbb22ef82f930
+0, 48, 48, 1, 301424, c65025dc3fa21fad98118ab0386b910e
+0, 49, 49, 1, 301408, 2982b49e94aa25b8ef30f81769650f15
diff --git a/tests/ref/fate/utvideoenc_rgba_left b/tests/ref/fate/utvideoenc_rgba_left
index 757febe833..83e3cb48b7 100644
--- a/tests/ref/fate/utvideoenc_rgba_left
+++ b/tests/ref/fate/utvideoenc_rgba_left
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 195264, 5869dee2126d98ecc1fab1e69720906a
-0, 1, 1, 1, 195272, 1bd08dcde1061b0d9273bdc6dd901382
-0, 2, 2, 1, 195892, 2b3fc3632bcd1cc44f777fb97a56f79b
-0, 3, 3, 1, 195320, 792870fc50a4145ad561b1004a8b6451
-0, 4, 4, 1, 194640, c3d4031c46d6dc64e632e2d38b48fc96
-0, 5, 5, 1, 195072, 27e4b09e7f8446a8dd8dd7dcbc578e2b
-0, 6, 6, 1, 194488, e44441beb8d3e358112e2776a0116ea9
-0, 7, 7, 1, 195228, 0519afd694512aea2c839fe0456e518c
-0, 8, 8, 1, 194360, 7296944c86296fb256188975db6e5620
-0, 9, 9, 1, 195252, 40b53999a36ce413256c7a81c3aa0c44
-0, 10, 10, 1, 195000, 925fe520c460f94ae7a05cf0e6cf8dd8
-0, 11, 11, 1, 195532, af417aac106af9b4e8c04cf1a84d3bd8
-0, 12, 12, 1, 193836, 0eadf04f475a93ebef3979d32c13ee92
-0, 13, 13, 1, 194856, 5814ff44b233d68e4c991703c0fa6f44
-0, 14, 14, 1, 195760, e9a66bbeadeab4ed3f34296346eafc27
-0, 15, 15, 1, 195388, 17d33cd676c8b464d1b97ce0f0234716
-0, 16, 16, 1, 195248, 1054b945cd6e11e70d8b348e540e4dd5
-0, 17, 17, 1, 194792, f0a6ceee9014f6cf8a999f344897ad3e
-0, 18, 18, 1, 194044, 4fbf2b9fd8b7e8233f65b5bf61e326c0
-0, 19, 19, 1, 194324, eb90b72edafab7bbe5e9ff561313927c
-0, 20, 20, 1, 193872, 6ebc973b9f66e1ebdb3029f1aadd9a24
-0, 21, 21, 1, 193836, cde713fba6bede0361779c45f7a6d80b
-0, 22, 22, 1, 194872, 64225b7d92c8371ed0335d7693902f60
-0, 23, 23, 1, 195240, b11e0b10b4e713caffec706d952edb7b
-0, 24, 24, 1, 195516, 932244aee01b068f1bfb5132f092675b
-0, 25, 25, 1, 195508, 2745faafa2ec34dcf2cec2f5f791f49b
-0, 26, 26, 1, 195292, 6ff67783eabad9c72b146d510ffa0b7e
-0, 27, 27, 1, 194468, cc5aa248fe507ac3fbb839b9388856bc
-0, 28, 28, 1, 192516, 13063bb195380953743ab24a73ff6ddd
-0, 29, 29, 1, 192464, a391b0d795b2f565cc3e351975fb528d
-0, 30, 30, 1, 193696, 4239c695d1b9eaa44c2d037a9c39da20
-0, 31, 31, 1, 194500, 5857b4c4cc86a9a0f38d833c236e396c
-0, 32, 32, 1, 194364, ad0eeec7622c76bd996deac7e99390e5
-0, 33, 33, 1, 195916, b98da9283eef85f6dffe308774161441
-0, 34, 34, 1, 195560, 32f924fc40bb777c951481b623a8f46b
-0, 35, 35, 1, 195288, 96a7bb386420902fbb98b8267d4496ca
-0, 36, 36, 1, 194272, 98b88d6092708ffff416417d8f628477
-0, 37, 37, 1, 194464, 3c8295490b77415c2e4ebb7ce9b8cc53
-0, 38, 38, 1, 192712, 17798a13ba5f82939d98dfd619a68e18
-0, 39, 39, 1, 193036, b92ab54b363c1bd29042feeb3b9f5631
-0, 40, 40, 1, 193164, a971b68bb49148afdf510be5f5793933
-0, 41, 41, 1, 193528, 6fbf07d240e0073e57d295bdd0d32465
-0, 42, 42, 1, 194124, 4b1ddea464b8e40da48418e77b4fdf7a
-0, 43, 43, 1, 194236, d46914a9e2bdda30bf84b3282924bb3d
-0, 44, 44, 1, 193748, 3d4587081c6d73366d85e5df42c87810
-0, 45, 45, 1, 191752, 996274b3852ac6af30db8f9e242895e0
-0, 46, 46, 1, 191132, 5a1e47e4d1cc9e18e94041b4357a5de4
-0, 47, 47, 1, 191708, e3048c5ba2b9a494791cad3cbf843780
-0, 48, 48, 1, 191588, dbc63170a9b7be348497162c42a1b9f1
-0, 49, 49, 1, 191448, db923a15f424e69bbf8c8af2a2f7e157
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 195260, a8fdb226460f210542e7aca6c12b0874
+0, 1, 1, 1, 195268, 45f098764ccba85dc641b7e401461c0a
+0, 2, 2, 1, 195888, e922261672c7de46a302abad3a3fe450
+0, 3, 3, 1, 195316, f8febd5af0fed000fab2943cc649975f
+0, 4, 4, 1, 194636, d90985ad8afd2f969afa842510085852
+0, 5, 5, 1, 195068, 909adb44bd049186a959f2803e641520
+0, 6, 6, 1, 194484, 547772233e653daccc6610fcb6369da7
+0, 7, 7, 1, 195224, aa82b75f6230b2e948abdfe36bce1150
+0, 8, 8, 1, 194356, d67fb1208532137252701ddcbf7bfc2e
+0, 9, 9, 1, 195248, 7b08698d2a911fba5231c0fef0ded4c2
+0, 10, 10, 1, 194996, 570e7d9caec52975dec1c2a5dbf7cdef
+0, 11, 11, 1, 195528, 7309c0531b942902c691781f2a6da1a1
+0, 12, 12, 1, 193832, 40954ceb87370cac3db5c8c2d7c001d1
+0, 13, 13, 1, 194852, 538382c377f0c6e9070ec0b8c5fb3e39
+0, 14, 14, 1, 195756, d002a80346f3460380abb794f2d56a62
+0, 15, 15, 1, 195384, 1a4f58b3c710f2fedaf746c281556b4c
+0, 16, 16, 1, 195244, 218832dab1251e1dc852e6839a48b3fc
+0, 17, 17, 1, 194788, a035acf428bd9565a4c3fec25dfc6f4f
+0, 18, 18, 1, 194040, 6dbfeb949bdeeb055a4f7ebf78af9a85
+0, 19, 19, 1, 194320, 8b4aa3f6f05aa684d9e4adfa4cdce814
+0, 20, 20, 1, 193868, 98cd8b150784f6695f8dea163cecf286
+0, 21, 21, 1, 193832, 27a8db33014c4bc6a8da356c4b1a3e4f
+0, 22, 22, 1, 194868, f1e1460dca9127197c0a40e659924616
+0, 23, 23, 1, 195236, a012f8548e92243334edcd7c8f57aa52
+0, 24, 24, 1, 195512, bf3d4e968d126231baa6618d3344ef81
+0, 25, 25, 1, 195504, adf4b49d8721f1b323fa518f2f0d4750
+0, 26, 26, 1, 195288, aa16dd087a73a9cadc5abfc0a46ccdd4
+0, 27, 27, 1, 194464, 2e3f07244999cbe949495b57adcabe69
+0, 28, 28, 1, 192512, 2d6ce0d29a929e0208e1578e95c9d388
+0, 29, 29, 1, 192460, 081d18cd138eead0cd4b25f54a7c7540
+0, 30, 30, 1, 193692, 546b6ad28b612c2f601c7d87b265ba95
+0, 31, 31, 1, 194496, b2b2ae3b1d67e332295456e6c7bdd381
+0, 32, 32, 1, 194360, 0837b122d85abc4d704d40629266c58d
+0, 33, 33, 1, 195912, b7a4bbe436d63394cee70d40e8a8a4cf
+0, 34, 34, 1, 195556, 1b9a3eb6cda9bbd44bbdd0dc26a74252
+0, 35, 35, 1, 195284, f28d780d43fa6979379dd21fcb12e906
+0, 36, 36, 1, 194268, 5508989dad06fa05ee4054e759cdfd4b
+0, 37, 37, 1, 194460, cb65a0e97c03b2fbe69caa6ac1660070
+0, 38, 38, 1, 192708, 4125ee86cf4b8ca6d891c176662e584f
+0, 39, 39, 1, 193032, 096ee24b3e35049480e28171693fbd85
+0, 40, 40, 1, 193160, c01aef63b8bc792d08355ce6d68affee
+0, 41, 41, 1, 193524, 57af47b7bfe132cf58eab2807996b3fe
+0, 42, 42, 1, 194120, 9a4e2d72f4526815b253b3acce2dd49c
+0, 43, 43, 1, 194232, e575508ffbd2a53871e817cd8947e2d2
+0, 44, 44, 1, 193744, 95d8eefbfbf5a7354ecbf35835243e44
+0, 45, 45, 1, 191748, de2eedebb28491e59700300635af1f90
+0, 46, 46, 1, 191128, 652670f6881419be5068f2de6ac2d91e
+0, 47, 47, 1, 191704, 070f46dc278230528aa6b40256a6d891
+0, 48, 48, 1, 191584, e4b76fcf344e125729c339e360a14b15
+0, 49, 49, 1, 191444, 6a33b374a8b48549094a24543d81d999
diff --git a/tests/ref/fate/utvideoenc_rgba_median b/tests/ref/fate/utvideoenc_rgba_median
index 1198a337cb..1588b6d286 100644
--- a/tests/ref/fate/utvideoenc_rgba_median
+++ b/tests/ref/fate/utvideoenc_rgba_median
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 195096, 29ad3287ab4d7f4d46968c6d38ba049b
-0, 1, 1, 1, 195040, 2c7b4f5f0aee96dca6dc30ce01b3c74d
-0, 2, 2, 1, 196044, 7ffc6ab3c4a2eee436ef6a59c72ffb04
-0, 3, 3, 1, 195256, f4453470d77c246cbb30d00c13512359
-0, 4, 4, 1, 194856, b84c4d56bf28033db539e4e0cad3d342
-0, 5, 5, 1, 195360, d2d3371b96f679f9b7c62d98b5d54af9
-0, 6, 6, 1, 195184, 8e3782bc12b24023a5899eb4806ffed6
-0, 7, 7, 1, 194812, 4fcf24a0660606304c58c93db2baf7de
-0, 8, 8, 1, 195040, 6ab57a9dcb4c99df7848a0971335a6b4
-0, 9, 9, 1, 195476, 66a3d66c3dc2f5b0847266a21927fa77
-0, 10, 10, 1, 195056, 530b251a8497af21bc56cd73af5c7ddf
-0, 11, 11, 1, 195072, 2904d24eca3db9734ed78dc8d557a334
-0, 12, 12, 1, 194232, 97566b596b113bf94a12ee1c02058a95
-0, 13, 13, 1, 195072, dceefd5df6efc5fefc8cfa1543b1a20e
-0, 14, 14, 1, 195348, d5b75f298fa6d474435333467b3497ae
-0, 15, 15, 1, 195668, 519f63be313f311cbb3fb48970a19f15
-0, 16, 16, 1, 194880, ab2da22767f540f8adea7e43dd6c1d0c
-0, 17, 17, 1, 195168, 667b85c19dd2d8ae105594f1294297b9
-0, 18, 18, 1, 194448, 575bc4b46f6158e76e503e8028902aaa
-0, 19, 19, 1, 194360, 851acbaf04c464689c8e2c4af3b9ed14
-0, 20, 20, 1, 193700, 1a477e0d665dcd088da6edeef77f21b1
-0, 21, 21, 1, 194008, b0d752c2201235e51ba0bbb59046fa60
-0, 22, 22, 1, 194096, 099df2b23c41ee54a6bd11aa6c92c390
-0, 23, 23, 1, 195092, e4d4dc89b8afba245355cec57ddcae40
-0, 24, 24, 1, 195196, 070c27e0499cf0210d729242ebc1a24e
-0, 25, 25, 1, 194912, 0fb78b7892035ecbec6ee9be6a13831c
-0, 26, 26, 1, 194768, 3ff6a05e68d6e33eeea22232e71bdf9a
-0, 27, 27, 1, 194360, 3828288e90a780d0c338ba5ab046aaa5
-0, 28, 28, 1, 193568, 60afb0ae9e6cbc9d8e4081764de7b4e6
-0, 29, 29, 1, 193560, 6b22fcfce4bff96b2afcb891f4fa9cf3
-0, 30, 30, 1, 193960, cae9eddb4464627fdc4413c3b5159575
-0, 31, 31, 1, 194780, 9e3d730fb835d3acaf92b7be368ea89e
-0, 32, 32, 1, 194648, 1ac7f5ae1b392ee8630266317a1818df
-0, 33, 33, 1, 194944, 374142509500017bbc29e157569bca2f
-0, 34, 34, 1, 194736, 0072a43b8de988683340c81e5bd4dba6
-0, 35, 35, 1, 194776, d5add7706f49a6a2f8d6bf3ed0ce3410
-0, 36, 36, 1, 194784, 7a1d38bc73fd293afef5fbcf9d34decd
-0, 37, 37, 1, 194912, 695e2d4c5d613245d591ae58100323bd
-0, 38, 38, 1, 194152, d4c9adb4f6340bc5f10b5b13f71d07bd
-0, 39, 39, 1, 194172, 0c7419c5c550e784e01a8c9927ecf59a
-0, 40, 40, 1, 193608, 4abff529172476d76c2956179041b2e4
-0, 41, 41, 1, 194260, dfa07971b01032b6a653d0d6715ffa8c
-0, 42, 42, 1, 193916, 6ffe1e68c74d51ea0cba0ede10b0f6f0
-0, 43, 43, 1, 194140, 46e18d23810193dd352fcc49b7c5ef6e
-0, 44, 44, 1, 193656, 4339d3e8b9dbeb376a1e19c4b86824f3
-0, 45, 45, 1, 192964, ff4680c71688f9944cd494105d2ab0b5
-0, 46, 46, 1, 192640, 62ce4b6d3311c34c73c6af1399fedfdc
-0, 47, 47, 1, 192584, f71b06a232a1a62a45ddac80c6f75090
-0, 48, 48, 1, 192360, 6642b9838eb32ed81d4d10a46ab9f954
-0, 49, 49, 1, 191916, d3ed1686383cfa7130ecc17c1ab52432
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 195092, d32d5a3dc88b9aef0826b565ee5dfbc6
+0, 1, 1, 1, 195036, ea13e3522d1f3aeddd47117c91eccc55
+0, 2, 2, 1, 196040, 21c2c9abe791bed2a9bf02e539caa787
+0, 3, 3, 1, 195252, 58d5e081127f246f711f5b8ee1c760ff
+0, 4, 4, 1, 194852, 8ceb3824ec628a73e1c08e498f369484
+0, 5, 5, 1, 195356, 30ea64094f29d670e2ff8f43b50578d6
+0, 6, 6, 1, 195180, 08b406b9f3063a54681d7195fb53e953
+0, 7, 7, 1, 194808, e28c43ef3aef174f0f9b9d7a702ca747
+0, 8, 8, 1, 195036, 66247b40b0def9373bf6fdda9ef832f7
+0, 9, 9, 1, 195472, efa8a624d6b0fa69e0c1c746baed0b33
+0, 10, 10, 1, 195052, fdfc784aed661cb76bc5b3ef1863bd89
+0, 11, 11, 1, 195068, 040ad503d18a36d4f1cdaec64998138a
+0, 12, 12, 1, 194228, 1cd168427d022825a801b232cb23ca12
+0, 13, 13, 1, 195068, e4082f833d3bf75af24e1bb5f06d94fe
+0, 14, 14, 1, 195344, 19638340e93d4f1f7099deda34d28e3f
+0, 15, 15, 1, 195664, 001a801c5c5ceb197576c0f7b793850d
+0, 16, 16, 1, 194876, 9550b3cf6133997bf7557483f346b036
+0, 17, 17, 1, 195164, eb7220caf48ab2605ec971ca1297a7ae
+0, 18, 18, 1, 194444, a2ac812e6307a92ecd09d4282367a9d4
+0, 19, 19, 1, 194356, ee4d250226ab2a34cef0e3ed8920f7b2
+0, 20, 20, 1, 193696, 4bff0fc871969d17ad1f7391bbd543b2
+0, 21, 21, 1, 194004, 080e2a91fe768fd1725a8400bc6a1331
+0, 22, 22, 1, 194092, 5b9d65275695372e1f6b9c0a23f1ffa0
+0, 23, 23, 1, 195088, a4060bf595c877476a5952b335526d57
+0, 24, 24, 1, 195192, 17b55735834f291ecae399c317007d2c
+0, 25, 25, 1, 194908, fc78d797bd5740f4fec8f3d34bc2ff1b
+0, 26, 26, 1, 194764, d229a9e4d1c782504cad617d2b00802b
+0, 27, 27, 1, 194356, f987a587cb9fdcd04e36d9382c4d9139
+0, 28, 28, 1, 193564, bdfa512e3a0a46aabf289c22dbaee0b9
+0, 29, 29, 1, 193556, 341708f3181ba4b37114d6dbffc65e63
+0, 30, 30, 1, 193956, f97693469ae6f49c3995794d00430c4a
+0, 31, 31, 1, 194776, 970c96fe0f733683ce4f2b478af21b88
+0, 32, 32, 1, 194644, 8a96248e2821040e4d0d6d32d0a4f1a9
+0, 33, 33, 1, 194940, 70a462d8de0da8b5718bf8fb8034fa38
+0, 34, 34, 1, 194732, 2fb3437abbc0a85b6c46e1b1edd922c9
+0, 35, 35, 1, 194772, 0a0f54e266438e1a840247e1af2fb1f1
+0, 36, 36, 1, 194780, c4d516a459523b1c150d8aad1d5e3a6d
+0, 37, 37, 1, 194908, e09db67196513400dd55397a525b73c2
+0, 38, 38, 1, 194148, f3cc9fc8597f8806fbc2a0c13af5b9ba
+0, 39, 39, 1, 194168, 2bb82f80c239984fe7c1091ab6afb332
+0, 40, 40, 1, 193604, 6fd128240c540a0655e8f27ff6a50ee9
+0, 41, 41, 1, 194256, 9b49275154b4538abdebbddffe010105
+0, 42, 42, 1, 193912, 6acff798f9cca91347e36ee1ea86183c
+0, 43, 43, 1, 194136, f24ca78d9b813ab8bfc720bad2682e7b
+0, 44, 44, 1, 193652, d7d927faf59a3b82bd1cce418c13c430
+0, 45, 45, 1, 192960, 8a813fce1d21dd4ad474d06d890a3de5
+0, 46, 46, 1, 192636, 6bbe157ec4f799cfd47a69c5a5cbb0fc
+0, 47, 47, 1, 192580, 1c17bf08a3928533a0036bda1fb08ecb
+0, 48, 48, 1, 192356, a5b34ac48c82e79ff827f72dddbfc6b0
+0, 49, 49, 1, 191912, afceb467ddffd9697c9566c43f2576f9
diff --git a/tests/ref/fate/utvideoenc_rgba_none b/tests/ref/fate/utvideoenc_rgba_none
index 555409fbc9..b8e0b4109f 100644
--- a/tests/ref/fate/utvideoenc_rgba_none
+++ b/tests/ref/fate/utvideoenc_rgba_none
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 301312, 6912d70f7c20db0b5079a99443ffe65c
-0, 1, 1, 1, 301328, 53f1b7d3c2f87ecfe9c9d305771421c5
-0, 2, 2, 1, 301100, 7040f2b50dc10b2565fa899ba007983d
-0, 3, 3, 1, 301164, 2bfe87a43842b21b083c166a5fcae979
-0, 4, 4, 1, 301172, e6535559b9cafb81d0f5312e6982228f
-0, 5, 5, 1, 301196, 899d3b7f4daca28b8d08fd80b9732332
-0, 6, 6, 1, 301204, 9ba8d921eb9345b9b90e5ec690cedbc6
-0, 7, 7, 1, 301304, 89d5758e5a4966d28fa3e6811822c9e6
-0, 8, 8, 1, 301336, b3f805d45e2cba1f3273fdc30e3d3d9c
-0, 9, 9, 1, 301304, 83c9ce5fdf5b20b29fc787ae20c5aa8f
-0, 10, 10, 1, 301204, 2cb730d551309ac307b69fb1e0f0bcbb
-0, 11, 11, 1, 301172, dc5d09bbd04e7b0a20521e67dbbad5f2
-0, 12, 12, 1, 301304, 9e08281b8be73b732b2793f7ffcf3bd4
-0, 13, 13, 1, 301224, 430fa7e9cc87e9292811601473bb03f9
-0, 14, 14, 1, 301128, 32eab97914c2f165e270e42e3c348ea0
-0, 15, 15, 1, 301140, c38233a19e22cc41957cd5a2e13bbca0
-0, 16, 16, 1, 301280, b87e1697217b744404d7998ec3dfac80
-0, 17, 17, 1, 301332, 231912bca1a1d4b54bc7ad392ca437c5
-0, 18, 18, 1, 301452, 30ce746afa3750735872fc9f2680e5b0
-0, 19, 19, 1, 301484, 9a56d219bcfb153190d17c8d89a0c5e3
-0, 20, 20, 1, 301440, c864010df06930259e712f7029a428b4
-0, 21, 21, 1, 301440, 1a4b6bf6557c65d5f088829602440819
-0, 22, 22, 1, 301376, f0ce8402bf00fcde4399da2f4088cd9f
-0, 23, 23, 1, 301320, 27d296bfd2df72c2fcf790098d2129cd
-0, 24, 24, 1, 301388, 0e78fec341c4d137959491e53ab23d92
-0, 25, 25, 1, 301404, 1ec3ca66bd6005cb754c00e346cdd895
-0, 26, 26, 1, 301348, b78ad47e42cfa510ab92d3ffc99371cf
-0, 27, 27, 1, 301492, 558f35abf593bf29a82e6353c75052d2
-0, 28, 28, 1, 301412, f44dae5d90ac9907b8847db0966e8d0b
-0, 29, 29, 1, 301484, 40d87d4e7c51bc2b3dede754c25e1b7e
-0, 30, 30, 1, 301484, 15dda8edd88e97f3db294bce9397e681
-0, 31, 31, 1, 301420, ff1dd12c16b295c83098a6b0135bd951
-0, 32, 32, 1, 301380, a290b1944381632a50fbb680f3f1af9e
-0, 33, 33, 1, 301356, 73d66b8546ac0698975af841dcea7a4c
-0, 34, 34, 1, 301260, 408ab0a50a74e7aaf196a202fd781892
-0, 35, 35, 1, 301412, bde264649818ed761d74281bf92a871e
-0, 36, 36, 1, 301492, c3612f4a8a748ffd6b43ccf24b2db821
-0, 37, 37, 1, 301488, 068ec12d90d1236e367caaf87f14da03
-0, 38, 38, 1, 301556, 000ee987cce47ab701e743d21a6607e6
-0, 39, 39, 1, 301556, 41277aa578fe7367c138a70b532bdf59
-0, 40, 40, 1, 301568, ebf086337aedfac24afc5c17715424d2
-0, 41, 41, 1, 301528, d8f0c31897748dfc761033f237f31f7f
-0, 42, 42, 1, 301604, 50b67f1d579eb8e7c5e0bdc438bf0ee2
-0, 43, 43, 1, 301568, 8297516127bb32a4326d6a859b2d8407
-0, 44, 44, 1, 301552, 1f9e1272e7249467631c4b9bd88bddcf
-0, 45, 45, 1, 301604, d835d90e9fc37583978c053bab5a96ed
-0, 46, 46, 1, 301692, fcb67990a58d25bff135fcc970714c4a
-0, 47, 47, 1, 301700, a4b0a26ed1626a4e46effa7987a32034
-0, 48, 48, 1, 301720, 44d53eab1be166c9bcc4b7b8bc3f80c9
-0, 49, 49, 1, 301704, 34314d5b44ea555b7d52958dec489fde
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 301284, 55e84c6e1f41e48f47dcefb63e3c1efd
+0, 1, 1, 1, 301296, 12dab23dfd2c2d5b48bed2292b876688
+0, 2, 2, 1, 301072, cc2e2889403dcc5d8e36868f07918b9d
+0, 3, 3, 1, 301136, 9813d60e613a3a14e639f9af0a5b1fe7
+0, 4, 4, 1, 301140, 58554bb6749e8bbd9476335ac1cb0076
+0, 5, 5, 1, 301164, 37a249286019761a4a3e498e977f9da1
+0, 6, 6, 1, 301168, f3aa11b419ec6f683ad906e7f7a36342
+0, 7, 7, 1, 301272, f489654640f0e42225815ea9c9681201
+0, 8, 8, 1, 301308, f10eb3c1d0324b59bd25c8bc6556aca0
+0, 9, 9, 1, 301268, 2163aa992afef5210d677953d81adb17
+0, 10, 10, 1, 301168, 684d19d14212615ebffa1748a9c552ed
+0, 11, 11, 1, 301136, a5c47c30d12dbc679ce932a5988b32e5
+0, 12, 12, 1, 301272, 3a51dc37d7e5ecb4a8db948eade2e0fa
+0, 13, 13, 1, 301188, f9f9ed41c233e791e6cd75a34e52edf8
+0, 14, 14, 1, 301096, 63bbfbee6f0fa6745e143dfae40ce7ff
+0, 15, 15, 1, 301108, 1fb3340dd1804d27fb40aea6b073e9ce
+0, 16, 16, 1, 301248, 476d27f29da8e74db696ff38e81743fc
+0, 17, 17, 1, 301300, 84a7f5804a856b7ef640838320634568
+0, 18, 18, 1, 301424, f34006fb55745aac29e265e0362434bf
+0, 19, 19, 1, 301456, d9207e54e261d184ddd02f3706e63103
+0, 20, 20, 1, 301408, 89b5a6804bad85025a6a3d23dc539426
+0, 21, 21, 1, 301404, 5987d22d6e3bf18cd2ebea98a1915f57
+0, 22, 22, 1, 301340, 43ff13bb237a7899ecb04fa7d27e94ab
+0, 23, 23, 1, 301288, 01b3e148ed6b8a0d05ee628fb21fa4a5
+0, 24, 24, 1, 301360, aa7704007e3c437cfcad4fb83a69594a
+0, 25, 25, 1, 301376, 4dea983f0b4a012ba6875aa857d02e91
+0, 26, 26, 1, 301312, e263f1cb0fb19b50751e9a214a4c9d81
+0, 27, 27, 1, 301460, 85ad441664c99c591d6dc427910faa19
+0, 28, 28, 1, 301380, 86ffe8273011763d800dbf6c89942a70
+0, 29, 29, 1, 301448, 500862ea62e1982325d653d4853dcbcd
+0, 30, 30, 1, 301452, 91c4390a805e02d1924bd75946bc0b63
+0, 31, 31, 1, 301388, 4eb3040d65948355c4506ee8e8e041ca
+0, 32, 32, 1, 301348, ece814a764470f1d80973743a7adaa4b
+0, 33, 33, 1, 301324, 2ae0b9af5380c8f98087b90c646af813
+0, 34, 34, 1, 301224, d6a3ba0b543534bd7de9dd82107c468c
+0, 35, 35, 1, 301384, 4f4919c1b2502c6e03ddaa83f4c03f15
+0, 36, 36, 1, 301460, b45189bc89e6583f4426c390622fa1fc
+0, 37, 37, 1, 301456, db0c5e2bc705c825e554c2da54314746
+0, 38, 38, 1, 301520, 8d01037b2dcbba39d4746758fd53323c
+0, 39, 39, 1, 301524, 0a78af44bf49520ae8830060e6011898
+0, 40, 40, 1, 301532, da9032ac97b76ec10f94d74ee878cf41
+0, 41, 41, 1, 301496, 9a22b2a9a3ad897406fc7c3137d41a3b
+0, 42, 42, 1, 301572, a14a80ab416cf4a9a1ec24bfc72602a1
+0, 43, 43, 1, 301532, 71ea5a240540a2e08ced8ad78c1a0676
+0, 44, 44, 1, 301516, fffe101d036ed5afee9b6f86267c2a0c
+0, 45, 45, 1, 301568, 58ea3a6edaee760d98eadb072fb30796
+0, 46, 46, 1, 301660, 9886e77f5df35d8bd164d598d0f87514
+0, 47, 47, 1, 301668, 1f326eb789974fc853e1db57115ef58b
+0, 48, 48, 1, 301684, 08b2eb620b9a7be1bded4744cd4c88db
+0, 49, 49, 1, 301668, bfcce1ce5f7c30230aae9a2d67fc8a70
diff --git a/tests/ref/fate/utvideoenc_yuv420_left b/tests/ref/fate/utvideoenc_yuv420_left
index cec5a28ddc..ae79effe55 100644
--- a/tests/ref/fate/utvideoenc_yuv420_left
+++ b/tests/ref/fate/utvideoenc_yuv420_left
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 59796, a7136363bc4b9ac663178e5c7f24bae7
-0, 1, 1, 1, 60012, d296cf24776234599e22526598de838c
-0, 2, 2, 1, 61040, e889f81df51b75acf8131de97f9da4e3
-0, 3, 3, 1, 59656, a63c343139b1117260cf6f790ba87968
-0, 4, 4, 1, 58592, e2170222ac38ddc0703f5b537b4beb79
-0, 5, 5, 1, 60248, 0ea350ecf7d8a440b06a60550b5dfa4c
-0, 6, 6, 1, 60480, 792694fa65994c407fd76d06fdbbdc34
-0, 7, 7, 1, 59888, eaef81fd1fa459feb9a3b15817c861a4
-0, 8, 8, 1, 60080, 610a75f3c275ffef75006fb862642993
-0, 9, 9, 1, 60320, 1e1cc244d2ea6b259d06384d1a95cc89
-0, 10, 10, 1, 60300, ddbb7eb36b73cd4f1dc28ded5217952e
-0, 11, 11, 1, 60288, 13f14eed47e1c4fec9f99b47316f82b6
-0, 12, 12, 1, 59172, c7c205489a3b389290f2c56e66bf8ddb
-0, 13, 13, 1, 59664, 81eead1a1fe199e4b66e9bc2f04ac892
-0, 14, 14, 1, 61004, d02e17515451d4259d7179741d208b28
-0, 15, 15, 1, 61088, 4f1c9877caf59dc5ebf5646fe98b3ef5
-0, 16, 16, 1, 60072, 5c4c41d25e9aa0da07da89475275513b
-0, 17, 17, 1, 59876, aeeb1f7a68a23f9fd0503831bfeb2ed1
-0, 18, 18, 1, 59396, 154d2a0717aeb78e47e20bbc9d4aa69a
-0, 19, 19, 1, 59076, 3fdcb2330689aed91d92d515a9eb015a
-0, 20, 20, 1, 58740, 71a054852adaf0da188550fd77ae2069
-0, 21, 21, 1, 58584, 403746356fd559e9bace9bb37557e58e
-0, 22, 22, 1, 58952, 1a3d80d21e00ca5ce8c378da373c65d8
-0, 23, 23, 1, 59696, f66ace9c237d6ee91a4c23a957fde2a1
-0, 24, 24, 1, 60664, 69e6f45d9adf351650648b3fd6fc41b8
-0, 25, 25, 1, 59748, ed9e5524584eb0438f88e12af331009e
-0, 26, 26, 1, 59088, 4325aa8c838b5793364c6ab6ed904d84
-0, 27, 27, 1, 58752, 46a17359055b7ac3285c845af9701c74
-0, 28, 28, 1, 56928, a1fb544e10ee9806c80b5b80d85ef813
-0, 29, 29, 1, 56960, e17a9082644d542b3d589346d3421c51
-0, 30, 30, 1, 58140, f5ae6688db909252b67c3fbe62d783ff
-0, 31, 31, 1, 58980, 71a7053ff0857fa0651e2b8c5626598c
-0, 32, 32, 1, 59548, 60b3d97b4f3893b791894968b7586e99
-0, 33, 33, 1, 61248, ceb9cccd0327ae4c52d8a2cf009d15f7
-0, 34, 34, 1, 60032, ea2ce622422c4efa41069707b231fd52
-0, 35, 35, 1, 59252, b891818e1aba1e29c23fecbf405b03c0
-0, 36, 36, 1, 58568, 0aec4492ddb9608bf217f8b828378680
-0, 37, 37, 1, 58744, 0f218bdc62102270393e7973caa251aa
-0, 38, 38, 1, 58280, 89c93e37590d56c7c32f4955e59b7c54
-0, 39, 39, 1, 58236, 9575ac5076c1c347069b48aa8cb6381f
-0, 40, 40, 1, 57308, e4ede1a1ab344b39399b231fec0cf420
-0, 41, 41, 1, 58964, 9f9c800eddf1fbb093c7ae1320f2ec19
-0, 42, 42, 1, 58800, 9729551ff14d80a3b647bb9688e38cd1
-0, 43, 43, 1, 58716, f0d81b0b287bbe1decd18eac2873166b
-0, 44, 44, 1, 58136, e6aa11b60f8be9cd3d3e9d5c22b326ff
-0, 45, 45, 1, 56772, c3dd97f5d29511103b80edfcf39d2fe3
-0, 46, 46, 1, 55904, ae67aee10ae3b04ac2dc19158bb9c69f
-0, 47, 47, 1, 56344, f3c9c3dd5238c1f29f9204e1efeb6235
-0, 48, 48, 1, 56396, 93b8a198ac7c7118da0b581a50633df9
-0, 49, 49, 1, 55480, b2907ad8da8252dd6403b72eeb49b141
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59796, dedd9623ead257b98e079c6d0479e5a9
+0, 1, 1, 1, 60012, 73ae403590ffc5962ff86b8dcb44ca50
+0, 2, 2, 1, 61040, 0c6baa05c0b1e458fceefc7b833edd71
+0, 3, 3, 1, 59656, 4d8d13a50efc73f6e6962bb234cc9b89
+0, 4, 4, 1, 58592, f9fd7cc56b1874bbe1a554f6150826ed
+0, 5, 5, 1, 60248, aa4d8d7f3f5eaead893adce9a7745e1c
+0, 6, 6, 1, 60480, 1c972785fefeb3ef6c5899abc75605cc
+0, 7, 7, 1, 59888, 6ab8c8eacedbd28b4341ae642f94cd83
+0, 8, 8, 1, 60080, 76f3eb46afdb2ebf83bf6aadc7277ddb
+0, 9, 9, 1, 60320, 01932335ef686a759b591ea450a7a802
+0, 10, 10, 1, 60300, 7a1bc0880154dfae83d5c4832d2a0ef4
+0, 11, 11, 1, 60288, 532314d7b508eae13ccb54c021c555eb
+0, 12, 12, 1, 59172, 3c307e8f17b27c489f91b609806eeea6
+0, 13, 13, 1, 59664, 070dd129e15219ac626e66279c6e7cdf
+0, 14, 14, 1, 61004, e6d8023b1c501fabb43e19d1b27e332e
+0, 15, 15, 1, 61088, beffd64b5410a5780481945057259830
+0, 16, 16, 1, 60072, df2ac66ec962c106d241a9e860bbf845
+0, 17, 17, 1, 59876, b4cd630af2b10995be0f46f6c2cb372c
+0, 18, 18, 1, 59396, a07393cd44eab3b4c6b2985931d104d7
+0, 19, 19, 1, 59072, 763f7702088fe148009a13b34e8dc0ba
+0, 20, 20, 1, 58740, 4b3c67d62bda1e1d41ae8b2a08ffc6ed
+0, 21, 21, 1, 58584, 7e696d1e2709d4abbf3777cfb891557b
+0, 22, 22, 1, 58952, 748cf0ce599b8f6b79e94fd38bd6f471
+0, 23, 23, 1, 59696, 369d7dd5403834a99af295ba7f7aec15
+0, 24, 24, 1, 60664, a95fc9270a66c79d1777ff6f970fe7cd
+0, 25, 25, 1, 59748, a4ae4093c9778f8f817977c1fe210e47
+0, 26, 26, 1, 59088, 5afd7ec014f73740095d7b442bce839e
+0, 27, 27, 1, 58752, 415bbfa919f86a4d5d39230749099db9
+0, 28, 28, 1, 56928, b6efa0547ff592c28c141f78e28fac1d
+0, 29, 29, 1, 56960, 9d78613a7511878970cd829809f82a77
+0, 30, 30, 1, 58140, fc65008ad890d0ac6b4d31dd87fcb1ba
+0, 31, 31, 1, 58980, 51ca202c4696073bbcc59885d6c91a2d
+0, 32, 32, 1, 59548, 283da1b559f8a1080df5525266c64963
+0, 33, 33, 1, 61248, 2f8a9fe1e7cac20ed716d2408af5faf2
+0, 34, 34, 1, 60032, 16c1b04dfa06e5896deb412536f82868
+0, 35, 35, 1, 59252, b12c42d343355035e3a80f67eeac29ba
+0, 36, 36, 1, 58568, 6958b7ddd22709356136a761bd1e947a
+0, 37, 37, 1, 58744, 544f50bf7a513425e0bde91bbb0c1b9f
+0, 38, 38, 1, 58280, af0f7e218dedcf8b3a61363cb8b66b80
+0, 39, 39, 1, 58236, 85954d2a24834cff1706f64e2937b84f
+0, 40, 40, 1, 57308, 9454333132d25fa15363fed1eadb9c35
+0, 41, 41, 1, 58964, 534643a08971e5bc1ba11a268dcdb0d0
+0, 42, 42, 1, 58800, fd5bc8c4c63f54dc0a062bbb81f464a4
+0, 43, 43, 1, 58716, 5e7a23faa930e4f447100a6cfb38181c
+0, 44, 44, 1, 58136, 5238fd231b1afdf11760e49341ff57cc
+0, 45, 45, 1, 56772, e82b61e4e6cc3088a482372b2f7af61f
+0, 46, 46, 1, 55904, 41e9834f48eafd70fe1d2361e9c84da0
+0, 47, 47, 1, 56344, 8c31cf8d3d938ec44a99de38cc4eaeea
+0, 48, 48, 1, 56396, ebe832913656dbd08f41b90a30360f5b
+0, 49, 49, 1, 55480, 65956930a7aacdaab5c65324fce90392
diff --git a/tests/ref/fate/utvideoenc_yuv420_median b/tests/ref/fate/utvideoenc_yuv420_median
index ddd074b876..21e15b53ba 100644
--- a/tests/ref/fate/utvideoenc_yuv420_median
+++ b/tests/ref/fate/utvideoenc_yuv420_median
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 62876, c21650baa099fb2dfd35d4f8ddce16d1
-0, 1, 1, 1, 62832, 034a1996d13c15ee0bf482ddc398aac9
-0, 2, 2, 1, 64076, 1f39fd5fc926195b90a3374682a80eac
-0, 3, 3, 1, 62724, 4007f9193b9e3b19e991497bb73679ab
-0, 4, 4, 1, 61664, 3e86c3a2cd07807433ed7f46ede959ec
-0, 5, 5, 1, 63296, 4e7d334f3713ecc07fca77c945c758b7
-0, 6, 6, 1, 63528, 15b8f92a1d84e77521c539a9a02379ac
-0, 7, 7, 1, 62784, 07ead8344bde0c0a060c3313f39cf92e
-0, 8, 8, 1, 63176, 0a8d9329d7f66008a0d41c6ba4749b09
-0, 9, 9, 1, 63492, eefa6ba63516dd2ff9fb0a4e81169977
-0, 10, 10, 1, 63328, 991fd8fcb392774d11b1766cc1dbe0d7
-0, 11, 11, 1, 63328, e2745a89e96a7f0c641fa25a6ed2da83
-0, 12, 12, 1, 62384, 2dd300b64a32ae2d6fb65e88128e5147
-0, 13, 13, 1, 62944, 076331793373fe43cd213ae56fc19e0f
-0, 14, 14, 1, 63932, 37b6b50e7219ba0e593e4ce1de02a864
-0, 15, 15, 1, 64020, ed66d034f605621266054a54714feec9
-0, 16, 16, 1, 62940, fb6a921a8551db3d33b0a24e7e9a3ced
-0, 17, 17, 1, 63052, abac96a9e0128efd4362ec28e66464d2
-0, 18, 18, 1, 62408, 0351d4c9579779dbb398f68f0e4e02e4
-0, 19, 19, 1, 62148, b4f7ed147a1326cf5adae50af6db56ca
-0, 20, 20, 1, 61692, 48a9cdf3d4600768feca7616614dc46d
-0, 21, 21, 1, 61704, d8e6c2daa6ae50caf7d5ee9324812389
-0, 22, 22, 1, 61964, 3983f0bf566d206cde013982722d4453
-0, 23, 23, 1, 62812, b12b44c4df634f608380e2bfb26b717d
-0, 24, 24, 1, 63480, 30ad52da50e0d4f1fc811d24a01e777b
-0, 25, 25, 1, 62708, 2827bd4dec0fa603eaf92bae8c4deb72
-0, 26, 26, 1, 62252, fd7c3a5bcaf83701dd7f2da225f3ce69
-0, 27, 27, 1, 61752, ea9740f3a5f52baaa923e245f649f7c7
-0, 28, 28, 1, 60248, cf4a142fc28437cca11ad1d127a2948f
-0, 29, 29, 1, 60232, 6cd0b708ec41cd10357f8944ae8288bd
-0, 30, 30, 1, 61240, c4a44f902a295f3a6e85276087adcbc0
-0, 31, 31, 1, 62228, a36d5eafa03b784f35303b131ac5d3a0
-0, 32, 32, 1, 62636, e09ca8f58690f991e1ce3986c2864924
-0, 33, 33, 1, 63840, 830de5062cb9c8be8844118c7db4bcef
-0, 34, 34, 1, 62996, e008d4add85b595840a2773d01465147
-0, 35, 35, 1, 62480, 04a38e7c231697aa97e5a401d4329105
-0, 36, 36, 1, 61744, 4cb276703869f45a6ab798e53e615fc0
-0, 37, 37, 1, 62012, dfca9b52389b01d750a4b94d10a8e2e0
-0, 38, 38, 1, 61748, bf2ec90514c268440313fecf68e2f41f
-0, 39, 39, 1, 61688, 99f1c565dc76bde773ccb91b8dbb3860
-0, 40, 40, 1, 60528, 7b66ad4e019964ead8ed1a9eadad9721
-0, 41, 41, 1, 62248, 795e2a8351ac78bc482e341be3af98bb
-0, 42, 42, 1, 61832, d7fc01097c5ec0247d20727aec2adab6
-0, 43, 43, 1, 61688, 4492ffefcaed530fce3221f4bb61ef80
-0, 44, 44, 1, 61216, d9a91c3007686b7166f297bc1dddb9a9
-0, 45, 45, 1, 60192, 7c808c46b376c49fa3d5bd5ba97fce1c
-0, 46, 46, 1, 59388, 6d2a2a72d14ff5c800295de6b2e23465
-0, 47, 47, 1, 59620, 5c1aa124bb6ffb9cd33a6430bf07ea9f
-0, 48, 48, 1, 59584, efc1012cca50e509856e406622d760fe
-0, 49, 49, 1, 58800, fa8563a0bc6022f8f5c5fc70ce0d46f3
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 62876, 5e2a5276e10b86511fb8101733bc4795
+0, 1, 1, 1, 62832, fb1e0a7b2bdbcbada9892e3db7be7821
+0, 2, 2, 1, 64076, e0d2af56a9c80e3e8096cf246260f3ca
+0, 3, 3, 1, 62724, bceca3c261206308030e2d7ad45e7599
+0, 4, 4, 1, 61664, ca8c005ba88cf1c97d49fe25f4830383
+0, 5, 5, 1, 63296, 7967f2592369b10bcd3ecac43413daeb
+0, 6, 6, 1, 63528, 5374d62636243ba8f3fd1d7f31b632a8
+0, 7, 7, 1, 62784, 8c6b4791881433bfa65732ecb5b16866
+0, 8, 8, 1, 63176, 5b63d41ddcb0ab291a0d435d5f581ee8
+0, 9, 9, 1, 63492, e0b3ecdb25bda555ab9b9dfd98179653
+0, 10, 10, 1, 63328, 3dd8397b620d84ca3e7a78f9c8d350d3
+0, 11, 11, 1, 63328, 1af5a1dddff26660e0d7a32e24bd9276
+0, 12, 12, 1, 62384, 1ff3c26a6bac33d80b63c0f8595201ea
+0, 13, 13, 1, 62944, 9c02a60be982847673da55180ef2c18d
+0, 14, 14, 1, 63932, ad7a22cf139c6e4ab8c5e53d9db3e68e
+0, 15, 15, 1, 64020, 53c8612a310d938be1080de4eebb18ba
+0, 16, 16, 1, 62940, bb481e1e906a4fdfdafa1cc15ebcbb5c
+0, 17, 17, 1, 63052, 0d97caa8514b4344c0ad8115e10b48c1
+0, 18, 18, 1, 62404, 0b05bb86b7bb1deaa3a1f0105adb823a
+0, 19, 19, 1, 62148, e70896d0e240f44275ca7d34e4de1b90
+0, 20, 20, 1, 61692, 5811d0049807b3e30bb165c106f121f6
+0, 21, 21, 1, 61704, 7b0714038c38fbaba0f30077e1fff859
+0, 22, 22, 1, 61964, 01e0aa600de8039bcfa29f4855861f72
+0, 23, 23, 1, 62812, a9374a4f24248363aa1011d48f352bea
+0, 24, 24, 1, 63480, 9837389866f467888b58d869c6c629c3
+0, 25, 25, 1, 62708, e463497b45db8c805fe8ef6903b1ce9c
+0, 26, 26, 1, 62252, 4a386a10f454c4a16314ce824348ccfc
+0, 27, 27, 1, 61752, ec17bfb853b0347ed5851adec930ac88
+0, 28, 28, 1, 60248, 2dce5d2345acaebe8d2ffe68248db51b
+0, 29, 29, 1, 60232, 69e26cd6734e29179a152271d31ec4d9
+0, 30, 30, 1, 61240, 4eb9641a3a7f96a1db6291ec1208b243
+0, 31, 31, 1, 62228, 6ea9280e5c470a1843e2af7b086270b0
+0, 32, 32, 1, 62636, cab91136cea5c672b970dbc9e1491ea1
+0, 33, 33, 1, 63840, 25dd643075412e90e16fd6732a7cb218
+0, 34, 34, 1, 62996, 173c292ebe568e845835e63ae98064f7
+0, 35, 35, 1, 62476, 4bdc99c66bcd82238d84f478b2be6d6d
+0, 36, 36, 1, 61744, fb3161857f91255e2fa3efff1fadfd4e
+0, 37, 37, 1, 62012, a7f45644fba6f9d3088800a18a78fe93
+0, 38, 38, 1, 61748, 3c606f8fc6f7535651f1203a0d390a1d
+0, 39, 39, 1, 61688, 636f94c06a5af282026aa82010362fd6
+0, 40, 40, 1, 60528, 157ff55e69660cb272c94ef1bf56f510
+0, 41, 41, 1, 62248, 1001e1aa4249cdc55bfc1f7daea931ad
+0, 42, 42, 1, 61832, 9435239c2ebe6bfee404c002c1f1a683
+0, 43, 43, 1, 61688, 6bdc7de71e539f50ddc7961e7e56e822
+0, 44, 44, 1, 61216, adf9cb20324a6ea37840aa96cc57f67f
+0, 45, 45, 1, 60192, 4d170c4d05a84440c9dbf60902902d70
+0, 46, 46, 1, 59388, f292adfcec971be4dd87e68da7edc662
+0, 47, 47, 1, 59620, ad02e16282fc53a395a3b61c077f56ca
+0, 48, 48, 1, 59584, e9cad9e33a2d9508ab4feabfc9545738
+0, 49, 49, 1, 58800, 83eed6619d5fa154a30128761561ff90
diff --git a/tests/ref/fate/utvideoenc_yuv420_none b/tests/ref/fate/utvideoenc_yuv420_none
index 555eee2ea1..7f9b58d967 100644
--- a/tests/ref/fate/utvideoenc_yuv420_none
+++ b/tests/ref/fate/utvideoenc_yuv420_none
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 144508, 83af3948090ebb44a0091815e4edc61e
-0, 1, 1, 1, 144496, 950742e357ee489fcda4f783b8df3b4c
-0, 2, 2, 1, 144376, 4b818cf0a50e9338fea26101073e445e
-0, 3, 3, 1, 144420, 0335c3b97dca65e9118a12e3cceb1e24
-0, 4, 4, 1, 144588, a9f7e6cb2d9129d97342c4eb67349aa8
-0, 5, 5, 1, 144444, b956115c6bab18a01594103bcb2ba9e0
-0, 6, 6, 1, 144408, 81761b3135ab3f4d5efd6f2790b6b70f
-0, 7, 7, 1, 144408, 566c53ee4126e31b78f6572292f97f55
-0, 8, 8, 1, 144320, 0c24c346a65cb945f8d804817f67f42e
-0, 9, 9, 1, 144316, 7920264636a6933c776b41567181f2d9
-0, 10, 10, 1, 144248, c1c1b10356f27fca35e03fdc67dd1638
-0, 11, 11, 1, 144168, 5a590c4f603aaddd01d4efbf5571426e
-0, 12, 12, 1, 144452, 10459aa8f48f7e8e0ebc03f15f795acd
-0, 13, 13, 1, 144312, 436658612212e706c4ed9f4bdcf45f38
-0, 14, 14, 1, 144252, 7a5612c485c501669e27039c435ac5d3
-0, 15, 15, 1, 144232, 81018c3b49d376d69af71a4ee2c910a9
-0, 16, 16, 1, 144312, 4280abfc59ee6cfddbf45474a42c5cd5
-0, 17, 17, 1, 144348, 0a48ba8ad15f7431830feeb2ac0f2118
-0, 18, 18, 1, 144356, 6c8f0a396195a840a225aca3ada427ff
-0, 19, 19, 1, 144360, 4a0a959d9c3ebb293d94ef37b4f7f19e
-0, 20, 20, 1, 144380, e61b564126a2d8255a7457b70af74514
-0, 21, 21, 1, 144416, fe434ae640e63fb774d6e7c864d02e49
-0, 22, 22, 1, 144344, 9e106257c640b66ca31919668c4da334
-0, 23, 23, 1, 144376, c0cdd6b2aa1bf4d89c82b602f09fa2e0
-0, 24, 24, 1, 144376, 8be60289a2a4c22355b3bd43f2f85fe4
-0, 25, 25, 1, 144320, 124127b8fcacfa5c5e0ee7f0324da7a0
-0, 26, 26, 1, 144408, a5639aedbdbfff34f36dda8872992cde
-0, 27, 27, 1, 144516, fbe3cf39fd764e6a3d05c63be35a4d58
-0, 28, 28, 1, 144676, 6ee82422712e11740d7b003eab69d5bd
-0, 29, 29, 1, 144648, e5f446835709b1baaca14af3aa6fbbb7
-0, 30, 30, 1, 144496, 3b23fb07c528ad824e9c8f10143ae06a
-0, 31, 31, 1, 144496, 4e4dddd0c72f9d3a555b8d32ae82c10e
-0, 32, 32, 1, 144372, 1dfe88fbe0c1193bb04a06840dfab155
-0, 33, 33, 1, 144168, e03b3d67fcbbde71c6985955feebabfe
-0, 34, 34, 1, 144180, 5d5a24b49cff98cbb85f69b547b43e87
-0, 35, 35, 1, 144348, bb9172de1a4c7a00fe80bb673484781b
-0, 36, 36, 1, 144544, 7824a6c4bb8b919306904be6f67f2736
-0, 37, 37, 1, 144516, 456c3884817909b4cca38f8138c079d4
-0, 38, 38, 1, 144532, 0e63cf833a33a9fac9e5969342817fc2
-0, 39, 39, 1, 144452, 9c0155cdd0a5ae42b79475ab47ba87f7
-0, 40, 40, 1, 144532, eefee218d181e74a80a1d2ec27932e91
-0, 41, 41, 1, 144348, fbd4fd20565350dd927005af590912ff
-0, 42, 42, 1, 144332, eac5c49230fb807c81e8a0c9e9721697
-0, 43, 43, 1, 144428, 9ee3fe8be6c4477b0d8ff1d91049634e
-0, 44, 44, 1, 144480, b58fb19549e4497e82491a26d67c1567
-0, 45, 45, 1, 144596, 1c8059bf14f4df3da9db6b89f87a52b9
-0, 46, 46, 1, 144592, db8a5750beb049ea835895d23e924cab
-0, 47, 47, 1, 144512, 58c69889edb9bdab219d698f6a44d2cf
-0, 48, 48, 1, 144468, 3da8e5ae1f1ff9da72abd3d2ac87a7b9
-0, 49, 49, 1, 144500, 4f80ccdb6f9549190ed72407dd7af2c1
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 144508, 808a5bf7f8647095ed629c18bcd78c8e
+0, 1, 1, 1, 144496, 88d91b5aebecb8e3553dc5d25c11f663
+0, 2, 2, 1, 144376, 979d1dcc8eb2ead071545e4098453ab5
+0, 3, 3, 1, 144420, ce1cca3a2399408b1fd3dc28f2f908ff
+0, 4, 4, 1, 144588, f028271d61bc3f7f29eb670b2dc2227d
+0, 5, 5, 1, 144444, 4caecb43ab4f98af4bc2d8fc5737165e
+0, 6, 6, 1, 144408, 78313642af9937e83d4206cf69423f88
+0, 7, 7, 1, 144408, 02afd3b87e1f4a88236c23613d0bb138
+0, 8, 8, 1, 144316, 677dc12dbff90c9f25bc5b1bcfae0220
+0, 9, 9, 1, 144316, 6dd8385746a3a982dfa7683f7b206d86
+0, 10, 10, 1, 144248, 0611dfc4b3ced7c52b5d014d114e3052
+0, 11, 11, 1, 144168, 7d6d56be15d67c0ef736909080bf6d20
+0, 12, 12, 1, 144452, 3a30b5305b301cd1cedffc44867659a7
+0, 13, 13, 1, 144312, b4f1329701c8284f8907e82e73dc225f
+0, 14, 14, 1, 144252, ab4ee9e419d38dca74a22475ffed6b4f
+0, 15, 15, 1, 144232, f486e7e950c8e45b881755fbee9ca967
+0, 16, 16, 1, 144312, aa8aa1826a1da8087567c13914fb1f79
+0, 17, 17, 1, 144348, 9c9ce3c86308dcda388645c0ab3b3f37
+0, 18, 18, 1, 144356, d33fd7c7f23e851a17fd0f0f768db726
+0, 19, 19, 1, 144360, a63e8e41686800d60566b19a9f2783fc
+0, 20, 20, 1, 144376, c9b694f8df1cb44b42aa902392a18a87
+0, 21, 21, 1, 144416, 5624b1dc448e6e6bee47432df8c2703d
+0, 22, 22, 1, 144340, 079128a1838e8fcb718cf4280560e40f
+0, 23, 23, 1, 144376, bb67943fd9d91d6a8af9e4b2da2ef52b
+0, 24, 24, 1, 144376, b91459d03569354faca2237ffbbdf0a5
+0, 25, 25, 1, 144320, 7a8863d8786eee1b82c7469d79d03156
+0, 26, 26, 1, 144408, 13873c8e8a66d12609864bc2a4127ddb
+0, 27, 27, 1, 144516, 09f74425c309920aca58488e8bf9845f
+0, 28, 28, 1, 144676, 12441f9a3d8215793b6b38c6e647d10d
+0, 29, 29, 1, 144648, 6895219f14106bbc780c654fb9835abc
+0, 30, 30, 1, 144488, 0738dc5c283869272bf28bd6a3107808
+0, 31, 31, 1, 144492, 375f99622b54462ef886e66f96998ef3
+0, 32, 32, 1, 144372, effb150140b4d84a3ab6a277992b9da3
+0, 33, 33, 1, 144168, 09677824ee8b6fff8391d6d8fef49459
+0, 34, 34, 1, 144180, ae4b4a60e2fe35f308201a3ace709f2e
+0, 35, 35, 1, 144348, 3f8c8eacfbaee2560059c687a037af7a
+0, 36, 36, 1, 144544, df5dc52fb501151cf8d0bd997f6b3e17
+0, 37, 37, 1, 144516, a9fdb6284f9b3b6d3cb59ad58897cd82
+0, 38, 38, 1, 144528, b4e82d29344b4ef0d34bf37e36f08cdf
+0, 39, 39, 1, 144452, 88516ddef80594babbda3801710bf89b
+0, 40, 40, 1, 144532, d9937a226562e3e02d6a6b134f04043a
+0, 41, 41, 1, 144348, d8c09a3ce3ff01b1620205d54cf28d39
+0, 42, 42, 1, 144332, 5d79f1d677fe98e21b15821f8b3b5754
+0, 43, 43, 1, 144428, c9717bd43d9ddb4cee7946e725fd54e4
+0, 44, 44, 1, 144476, 18db82ef876bc80d777f801107c45c18
+0, 45, 45, 1, 144596, c62c01892d002dbb75a2020b9d0a1137
+0, 46, 46, 1, 144592, 9faf6283b8753002005c5a04ae345d5b
+0, 47, 47, 1, 144512, 8c25deaf7a77b0991861a5c62b4fe5d1
+0, 48, 48, 1, 144468, dcaaa1058c59946691d087c9941ac956
+0, 49, 49, 1, 144500, b36206851f8613bf9cae5296d85eb1c1
diff --git a/tests/ref/fate/utvideoenc_yuv422_left b/tests/ref/fate/utvideoenc_yuv422_left
index d9afc2cdab..9da47a4b7f 100644
--- a/tests/ref/fate/utvideoenc_yuv422_left
+++ b/tests/ref/fate/utvideoenc_yuv422_left
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 91788, e14e576f1f9abd095f13ceca627adb59
-0, 1, 1, 1, 92140, 4b7db11c2d35fa91ff1b6f65c184e3fa
-0, 2, 2, 1, 93268, 6ef5cb83a4db2afbf14467cbc4b6c4f7
-0, 3, 3, 1, 91612, f08ae129a2867a08770bdb61381bf366
-0, 4, 4, 1, 90456, ed3edabe09b9f6cfbf452a08dafa556d
-0, 5, 5, 1, 92180, a0760e91b3af27a7c1bb0264f128ca50
-0, 6, 6, 1, 92200, 2fda4c87dfa34206173e852b67841406
-0, 7, 7, 1, 91872, 944e7c88c7ebeae9e1efac859ea4fe7d
-0, 8, 8, 1, 91952, 34112ec99382b80c397d26cef93573c7
-0, 9, 9, 1, 92312, 63698686348ccd80cc920e9e73a195aa
-0, 10, 10, 1, 92308, 6a675d6678b7b78fac6375d44f325d06
-0, 11, 11, 1, 92272, bc1401e0acd3864ad30711ca4b61578d
-0, 12, 12, 1, 90920, cd7ecda23a4f312abe71bd3fc28af3e7
-0, 13, 13, 1, 91612, 91ebce52e2594296349476f3bf6a6408
-0, 14, 14, 1, 93112, 34be111d02130ed7389c0c62768041de
-0, 15, 15, 1, 93140, e1b440cad63dbf8ff034f424cd1194cc
-0, 16, 16, 1, 92080, 94181fde8563af0b6810f778f6b1d92b
-0, 17, 17, 1, 91816, ed0997f9b341fc3ab6a8c5d9a4067bd2
-0, 18, 18, 1, 91204, d833b0c3b3dfe60b079b746c4c3aed7f
-0, 19, 19, 1, 90880, 0d4702abb70d7cbc8843a96e3a74117a
-0, 20, 20, 1, 90408, 409860b79fe10ffbffd581c19445fa91
-0, 21, 21, 1, 90280, 5360fa4f1afd8c2c55cf33675a928a14
-0, 22, 22, 1, 90808, fe2ca67d315fb1d8806ee04470d06378
-0, 23, 23, 1, 91584, 84168a6fe20ee00ddd9f54ce8f1e1810
-0, 24, 24, 1, 92684, 6fb3d7193d3bb5400c449717358827e0
-0, 25, 25, 1, 91580, acd2aa86dbae6e133183e5bf2ca389a3
-0, 26, 26, 1, 90928, cc0df9c8e00df5985e39ae486eb59eff
-0, 27, 27, 1, 90536, 8f9d294190c03435f3cee266cca2a31a
-0, 28, 28, 1, 88364, ae9564ad4eb3c1fc03e4befb4b1e719e
-0, 29, 29, 1, 88404, 745a16947203cd7017900b137fca70eb
-0, 30, 30, 1, 89844, 1b7e75be9edb25ffe91c54e270eb8f46
-0, 31, 31, 1, 90752, 9ff03fa3b28f2c84a4da41779e0a2aa4
-0, 32, 32, 1, 91320, 409ed4c3eced8793760505cf8095f51a
-0, 33, 33, 1, 93204, 70865d89c930919474500befe0e2ec3f
-0, 34, 34, 1, 92036, 7388d12a6954b9870749ab6a5f05815f
-0, 35, 35, 1, 91144, b47bfdaec4c00177a9258a03e864400f
-0, 36, 36, 1, 90368, 418df89a063f66cfbb1f806d68aca6a2
-0, 37, 37, 1, 90628, 3f90314ab7311ad0f4bd4808d62a1e80
-0, 38, 38, 1, 89836, 414f90d0efc65b993f6e1fc8f2c1d860
-0, 39, 39, 1, 89792, a07cf9fc580ffee5d61c241dce116ae6
-0, 40, 40, 1, 88896, 3d583229da6b7455b6876843b3b747c7
-0, 41, 41, 1, 90572, cbef36619e7c8e62fc21a735c7701514
-0, 42, 42, 1, 90544, 144816eaeaf0412fca6bf40e6f3e6d3f
-0, 43, 43, 1, 90416, 76f0d9dd1f4fd00b68223dd7c6024b2e
-0, 44, 44, 1, 89788, ce0b66e45ed3c50124680f84614c5ac0
-0, 45, 45, 1, 88120, 5d59770b187109e2e6824f5cb42b9b73
-0, 46, 46, 1, 87164, bb52ce20f4a21ef82a2cc3316ba69e1c
-0, 47, 47, 1, 87632, 87f44c3ecebd09b2ffa94d8ace01f3f3
-0, 48, 48, 1, 87700, cbaed2ac667bdc9aa17ffc68ebaea790
-0, 49, 49, 1, 86624, 21797bc69a89976f9b4b552603a63267
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 91788, 2b29ead6a04f08e49c25cd89fe0c0e46
+0, 1, 1, 1, 92140, 011a3c92a1a6659b26db7de3c74cda41
+0, 2, 2, 1, 93268, 69ffde2375949c0124e3f6b46a8bdf1f
+0, 3, 3, 1, 91612, a34b1bbbc245a315906085aab9dca284
+0, 4, 4, 1, 90456, 7a1034d99c06d9163116e05dc88de0b8
+0, 5, 5, 1, 92180, cfe398abada0424f7ceab29426d27711
+0, 6, 6, 1, 92200, 1335b1706618dc85d64c3d47a2bf9eab
+0, 7, 7, 1, 91872, c37958d720e011c337bf87543e635791
+0, 8, 8, 1, 91952, abdb95aa1c20d4724ec442d876b3ef82
+0, 9, 9, 1, 92312, b346e210e76f3ac350c9026d0421c1a6
+0, 10, 10, 1, 92308, 9b36f5e0085b3e4ef50e6a00aa8e9dd3
+0, 11, 11, 1, 92272, 4880487b34e836fa975fc0c857cae271
+0, 12, 12, 1, 90920, 924850fe3b48417160854234a60ee452
+0, 13, 13, 1, 91612, 34e4e1b6114bd2eef0ac26b4c3a0be5d
+0, 14, 14, 1, 93112, 34e98cc2bc42b0cdd12f3b5a8a062a14
+0, 15, 15, 1, 93140, a6163289cc8450b55f82f13a8a372259
+0, 16, 16, 1, 92080, 143e999836a6ebc144c707dd77ce3d6b
+0, 17, 17, 1, 91816, 0fcb2542dd7e281b098f2a4a76220286
+0, 18, 18, 1, 91204, fb9f7126d5c37bf48ae3cb7702fd27c5
+0, 19, 19, 1, 90880, d618dad8a7c6c03091a8d72f05ff06a8
+0, 20, 20, 1, 90408, e9de31ec047f7ea8aa2b781c1b8ac0cf
+0, 21, 21, 1, 90280, 742f6b57e5014c85bf4ce63c3973ceb5
+0, 22, 22, 1, 90808, 0bde9c976e491dbca37762af1569f05f
+0, 23, 23, 1, 91584, f69c98911e98cf1b35fee8c7a17784d6
+0, 24, 24, 1, 92684, 813535f3fddf27ed41475a4a16153407
+0, 25, 25, 1, 91580, 99e840b30697c491a42381278b74060f
+0, 26, 26, 1, 90928, 1bb430db061f5ea70f97b0808f6fd0c6
+0, 27, 27, 1, 90532, 8669ea68164d3f9f6e234c24ed4ba6dd
+0, 28, 28, 1, 88364, 65c5175d6c6bab9f205ae9b8d52931e8
+0, 29, 29, 1, 88404, cb375b083b2d415d11111b7d0b65d499
+0, 30, 30, 1, 89844, 6b29caf5d67711e4a68f9dc852c89607
+0, 31, 31, 1, 90752, d1d424a5f93970e1bca8e6cc558359bc
+0, 32, 32, 1, 91320, 726a9a5fb90b88961f7392028c83cff3
+0, 33, 33, 1, 93204, 0ed7b1760d190df0c84f62f7ee3050c9
+0, 34, 34, 1, 92036, ff3ad470d5195aa00e364f180961b852
+0, 35, 35, 1, 91144, 8a7050fa18088c6dbbf148d7ae047a86
+0, 36, 36, 1, 90368, 0c0252b21de41b75141085a05cdfd462
+0, 37, 37, 1, 90628, 143d503a9e2ca9f5e95ba12e2237a88a
+0, 38, 38, 1, 89836, 93fe7527a5681c819c6052b87bca8bb9
+0, 39, 39, 1, 89792, 6c353b6ef1cc14ebdbb2de24faabcfcb
+0, 40, 40, 1, 88896, ed7e33a68674399293203e4fef8db0f6
+0, 41, 41, 1, 90572, d70967dd3d556559773980a776836423
+0, 42, 42, 1, 90544, ee7727dd0f3833728b3c557e9775f1ef
+0, 43, 43, 1, 90416, 0e4b028286b5b1f7fb902821dd015951
+0, 44, 44, 1, 89788, a4e5d8715ae485f875b80ebcb150692e
+0, 45, 45, 1, 88120, 9dce5bc1420f0e67abed693f75023d43
+0, 46, 46, 1, 87164, 89374077f87c8d3639743e17f8583307
+0, 47, 47, 1, 87632, 6ebcb11b9c0263aa82ca4797acd078ff
+0, 48, 48, 1, 87696, 9941fc859d6b9e4c057c2a4b40faff98
+0, 49, 49, 1, 86624, a2a157ab69d82eda4f8ab502de62ca55
diff --git a/tests/ref/fate/utvideoenc_yuv422_median b/tests/ref/fate/utvideoenc_yuv422_median
index e1c8fcdfe8..8241aae26d 100644
--- a/tests/ref/fate/utvideoenc_yuv422_median
+++ b/tests/ref/fate/utvideoenc_yuv422_median
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 89732, 698174b0d0d68e98774363ca7926f6e1
-0, 1, 1, 1, 89652, f0789b7c32ef44207dfc5a454bb5ccee
-0, 2, 2, 1, 90868, 6df1dcb1957efca736e88adfbad8557b
-0, 3, 3, 1, 89520, 9cee942e7f03a97cd2cdf8cea429fb31
-0, 4, 4, 1, 88508, 798f4e8c00f4d949882cdc3f89be0bf6
-0, 5, 5, 1, 90140, 70fc5f4f240b0ca30332b0f37632d1cb
-0, 6, 6, 1, 90176, 1c2747fc56d5eb70ff8f4f361cb70610
-0, 7, 7, 1, 89392, bd8764124753f784d5984cd829c8ca90
-0, 8, 8, 1, 89848, 1dc30ed23a8634f6b2661ac8583fe8cc
-0, 9, 9, 1, 90356, 0910ae7c3a6924031453f458009354fa
-0, 10, 10, 1, 89984, 61da06bf1ed667b54ee749c69ab031eb
-0, 11, 11, 1, 90012, 11d05491f86014f19b34cab3111a95d2
-0, 12, 12, 1, 89072, 4598f16727472daa1710c39b4840efdc
-0, 13, 13, 1, 89776, ed6c0da32acf621e9f79b76a3afaa280
-0, 14, 14, 1, 90680, 05f3a9232bc14ca8721ef04243177a20
-0, 15, 15, 1, 90852, e4deff113ea503656efecb227f6b702a
-0, 16, 16, 1, 89844, 5ee70abd6f1d2e5c55117b28840327e6
-0, 17, 17, 1, 89852, 6721997ae0563009adbdeed31f437ce4
-0, 18, 18, 1, 89144, 8a40f0af74afb4ff05e6242a41c7789f
-0, 19, 19, 1, 88880, 8824c3526629a30fbf9a53abc448844c
-0, 20, 20, 1, 88344, 18a656127a16bb50113bb2e98b11a26d
-0, 21, 21, 1, 88464, 19a3b9510e6347a7782f695b48736991
-0, 22, 22, 1, 88588, e3d22d15b4812c26214db546ce17c7dd
-0, 23, 23, 1, 89720, afe800faa0188dff0899cd83af6301d6
-0, 24, 24, 1, 90216, a9d9ece70c978c595e1d724a0f644f56
-0, 25, 25, 1, 89456, 9bf3e8f87f072d55095acc9351a09f45
-0, 26, 26, 1, 88992, 40d1b1858f1ba0bebd9eb9f5263cda9d
-0, 27, 27, 1, 88632, 1df39644ac99bccab4c6bd72498284c4
-0, 28, 28, 1, 87048, 9983cd95307c1bab653170ba2aecdc55
-0, 29, 29, 1, 87120, 006b48403af94a0bc5121900b48af9c1
-0, 30, 30, 1, 88044, 652d17c8805de56cd83824d99888822e
-0, 31, 31, 1, 89016, 652a971973d088b5098a06b216137151
-0, 32, 32, 1, 89324, 2775a087358ead0281ce188f4006050d
-0, 33, 33, 1, 90328, 564e119bdf5f3c780c0613990ca487db
-0, 34, 34, 1, 89684, 1f5fb4ec22234aee771791b71881b630
-0, 35, 35, 1, 89216, dde7a003cfe5b47f9be407f28dcdfb3f
-0, 36, 36, 1, 88644, 1fed2d2f72ec9488181a06606aaf4e12
-0, 37, 37, 1, 89000, 8f916bee0ad8efe8d3572e4af4bf4b8e
-0, 38, 38, 1, 88628, d802fb5634d3acd72a96bd99c22dd566
-0, 39, 39, 1, 88448, a4d438df349f1f2ff1620fb965d08513
-0, 40, 40, 1, 87332, 18a8527dcfc5c1fa8ae7aa8a83781d2d
-0, 41, 41, 1, 88856, 63179f19a5d60d3ea9fa14c00ca5c493
-0, 42, 42, 1, 88556, 92b568c24ed53e823b54fa6c064d16ac
-0, 43, 43, 1, 88380, c204b982e3ab7fc1aa6b1b132c4ae462
-0, 44, 44, 1, 87888, 45f1cd55d454a0b611b047b6e5172b30
-0, 45, 45, 1, 86876, c668ac58b31feb51902b78fdfcdc1064
-0, 46, 46, 1, 86272, 24a94950de7065cb236e52502c9c8e67
-0, 47, 47, 1, 86388, 51dad738cd8896616694a4fb52b47fbd
-0, 48, 48, 1, 86188, dc6709cd2722eb8dd927f405c6a30915
-0, 49, 49, 1, 85244, 68f40045a250ab0799a7325aa16ec80c
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 89732, c8dbbbed6c59cff00c7cead39cadd7d4
+0, 1, 1, 1, 89652, f1c995c2bcb13f9de97fd8c5da2637a1
+0, 2, 2, 1, 90868, e126298a564eec5e60518fca891bfd43
+0, 3, 3, 1, 89520, 8694da46ab5672f890d57c741d69d830
+0, 4, 4, 1, 88508, 0e0ae55ba0bcdf6618b7cffae7242d71
+0, 5, 5, 1, 90140, ef59eccdbf3b699a2eb857c6da044fa7
+0, 6, 6, 1, 90176, 95509ddb5a5169900714eaa2aac59703
+0, 7, 7, 1, 89392, 25782fbbf8552e7682cded46b418096b
+0, 8, 8, 1, 89848, 46cbfe84ab2c46f045d23fd798dc64b2
+0, 9, 9, 1, 90356, 41cdc2e6dec30172ecccf1aca7b7ab0e
+0, 10, 10, 1, 89984, 469be246c63ba4743d9c5ea91c4b849a
+0, 11, 11, 1, 90012, 100bc595e92ca6d73525b2e20eaa7d25
+0, 12, 12, 1, 89072, a355e131c150b82d3620fe54ab53b423
+0, 13, 13, 1, 89776, 67e7c8a187157c1827a2e529865ab941
+0, 14, 14, 1, 90676, 7fa956927033cab7c0ae9a0a86d57b59
+0, 15, 15, 1, 90852, d507b175068e9d6c729530b436824436
+0, 16, 16, 1, 89844, ae6b71fe15285387229734fdaaad86d0
+0, 17, 17, 1, 89852, 6ced7f1bc56299e5c7b5169a1e62f4e6
+0, 18, 18, 1, 89144, 09a950b254eb5e7ac061e30a14ef98e8
+0, 19, 19, 1, 88880, acf28ad860b52fb502d22c063689a9d8
+0, 20, 20, 1, 88344, 682436aa7aeffa2cd5daa6adf037eb88
+0, 21, 21, 1, 88464, bbbefa2630e4e5165c9db638ceb730b8
+0, 22, 22, 1, 88588, 71d0e9178794e0ebf414bdd1c532d4fd
+0, 23, 23, 1, 89720, f39171093709c90dae1ecc56e1a0d52b
+0, 24, 24, 1, 90216, d8a7e85456ed58b86f42120269a62a46
+0, 25, 25, 1, 89456, e6d8b4f4b7c1903d66caea47cde9188a
+0, 26, 26, 1, 88992, 226f69483ab481fd48fa2121fa925fc9
+0, 27, 27, 1, 88632, 2ef0ae5d9b35440a540dce11098be40b
+0, 28, 28, 1, 87048, 5ed9c2db56db5ab3b5695ff282fbbd00
+0, 29, 29, 1, 87120, afe541aa18fd0fbeb7d623c2e03f7313
+0, 30, 30, 1, 88044, 4783145cbcbac507631d89b4c1b9f657
+0, 31, 31, 1, 89016, b8d2e919eecced0e4e13bab212fe5eaa
+0, 32, 32, 1, 89324, 1be1c9ee208834cb150e7dc114b3c3f5
+0, 33, 33, 1, 90328, 9ecb6f9511b869becfc3ae1cac0532c4
+0, 34, 34, 1, 89684, dc56a959ece1d3ea923be523ae4b5f03
+0, 35, 35, 1, 89216, bb1b89d23284a73faaae092e02c35318
+0, 36, 36, 1, 88644, 5a01fba266207f286dd000502144374c
+0, 37, 37, 1, 89000, e30493ff019668eaccae12c420a250ea
+0, 38, 38, 1, 88628, 0217f6f365739f8c7f1738d369afb2e5
+0, 39, 39, 1, 88448, 9d064836b1b232620da1d470fa314d56
+0, 40, 40, 1, 87332, 9179648b65b4757cd23d732ef96e8685
+0, 41, 41, 1, 88856, 96e0779b5fb5708a73519cc5f8a685b3
+0, 42, 42, 1, 88556, 5586e5b8149eefe271d7d2c4688a57e0
+0, 43, 43, 1, 88380, c8a1962e2c4fc33b303e3e09c87ee1fb
+0, 44, 44, 1, 87888, 70f38ebefceec78ec00fc2d190efc633
+0, 45, 45, 1, 86876, f8e0beb98988c19930c2cdd90ecfe867
+0, 46, 46, 1, 86272, fcb7343e281b2d42c81f9b5c4c1e786e
+0, 47, 47, 1, 86388, cfa6fce827ac3604ea2124d7332e2226
+0, 48, 48, 1, 86188, 5455b984533d774b8e7f04eea4e4eeaa
+0, 49, 49, 1, 85244, 9e4691d5a8be8270d48ef15292aaf0f7
diff --git a/tests/ref/fate/utvideoenc_yuv422_none b/tests/ref/fate/utvideoenc_yuv422_none
index ca771770e7..bb97e219a3 100644
--- a/tests/ref/fate/utvideoenc_yuv422_none
+++ b/tests/ref/fate/utvideoenc_yuv422_none
@@ -1,51 +1,55 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 0, 0, 1, 191800, 0e1d199f87997ba47e98596b6087d7d4
-0, 1, 1, 1, 191820, b35714d0635214095ac06d35da00ed32
-0, 2, 2, 1, 191668, 8336829e44f5b90034e5da33dcd27f1f
-0, 3, 3, 1, 191696, ebff701893f27b026fe6fec4a1cbd90b
-0, 4, 4, 1, 191976, c2729ecde4337a51192da71b0ef36e7d
-0, 5, 5, 1, 191760, e2ef2db5ef30019d5fd24cd32c696318
-0, 6, 6, 1, 191708, 638eb1c1b68bc9f4cc315ebdd3bd86f5
-0, 7, 7, 1, 191688, aca858d2cce189eb60012a33ea74d10b
-0, 8, 8, 1, 191576, aa933dea9aac9b61fea004747e3b8e6a
-0, 9, 9, 1, 191544, 6c410ec9e2492d464d439a58e6e338c3
-0, 10, 10, 1, 191472, 7c7661ff35671b3912b2b216bc6df478
-0, 11, 11, 1, 191280, 73c1ff53a0cd5c65eb2ae75a45efbf72
-0, 12, 12, 1, 191700, 201b0b4834878513e6e13bd9f5977a28
-0, 13, 13, 1, 191424, 0affff549b2da09c7852c5e8dbd1c84a
-0, 14, 14, 1, 191420, e0e80adf520953c4bc4033efc77b9092
-0, 15, 15, 1, 191408, 4fa22efbf2101b7f6bfffae227ce1d23
-0, 16, 16, 1, 191500, fef8df893234b38be36803d5f5656e16
-0, 17, 17, 1, 191580, 3585b500a77344fd87f8f18e3816f1a8
-0, 18, 18, 1, 191608, 419189483180612b72491dab5864c6e7
-0, 19, 19, 1, 191616, 197fa32c8a164eeea73defb7422657d1
-0, 20, 20, 1, 191596, a660a6c630f7e55c3ca2f9a37d599223
-0, 21, 21, 1, 191660, d98445b0387c3d54034f8defe1d03ea6
-0, 22, 22, 1, 191540, ef4522aa762b82d1c715805a779c7c1e
-0, 23, 23, 1, 191576, 32d109d2040c69b3944471b0bd399a65
-0, 24, 24, 1, 191636, 58e2f3a01de4175ba7f915e2d065ba36
-0, 25, 25, 1, 191524, 0989a64e78613cfc26124e195cfc0cde
-0, 26, 26, 1, 191640, b9e252a5c4583736a8ba248d15c429aa
-0, 27, 27, 1, 191800, 1541cccc66cb63d3e1ef675a16a1258e
-0, 28, 28, 1, 192028, 5dada6bf987738caebca210067d13c39
-0, 29, 29, 1, 191964, 8d55bb4a1464ac74364d4b1e416d4a0c
-0, 30, 30, 1, 191736, 88c279b9f3e96485f85dbca09177fe26
-0, 31, 31, 1, 191788, aa75795116428edb57dea8b54527e13b
-0, 32, 32, 1, 191636, aa45e4ec1fcc038ea2e48046e5047417
-0, 33, 33, 1, 191400, 7b2861b3ca8bfcdca010d859c0595e03
-0, 34, 34, 1, 191332, 956acfcc00661d9a9ba7575e8c1a011b
-0, 35, 35, 1, 191548, 3b5b7c3b9a6a5ebe10f178077a5fea4d
-0, 36, 36, 1, 191852, 835219e1689946f3e26457ffce197181
-0, 37, 37, 1, 191828, f67a1e4640472287baf194c02f24dc29
-0, 38, 38, 1, 191812, 978f44d430859044350ea20913ae4194
-0, 39, 39, 1, 191700, 92e21c9ded61f69f793c649eece071c4
-0, 40, 40, 1, 191812, 0a460bc35daad68e8042917f26dac542
-0, 41, 41, 1, 191548, 7c7a65b9257f9b4439002c5c414c401c
-0, 42, 42, 1, 191544, b03d903c46536dc336461827fd4d34db
-0, 43, 43, 1, 191700, 75b391d84b120e63ec229fcb48808d19
-0, 44, 44, 1, 191780, c953dcd42a8aa19eb4d4be0149894bbe
-0, 45, 45, 1, 191952, 64be44b2e21f8301f4234e32a10cb1c9
-0, 46, 46, 1, 191916, a6c805f651f3f57a84681b1aab6fe3ef
-0, 47, 47, 1, 191784, 9cc8db3cb63a026645f634aabc89c37b
-0, 48, 48, 1, 191716, e2f0c7543b3484a726411eac4e9a79cd
-0, 49, 49, 1, 191728, 50277180199917d1259e0cad42f52d4c
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 191800, 4a5653458a4206bcbc584d5e6beb61f2
+0, 1, 1, 1, 191820, 2f77ced17c186b507864ea482016c913
+0, 2, 2, 1, 191668, 2dd719b7228e3b38e1e86a0304a599f1
+0, 3, 3, 1, 191696, 4fe7ef1586ef85f3ceb579426ff4077f
+0, 4, 4, 1, 191972, 9b9718c63d0b6f6bc293036bcf7a884d
+0, 5, 5, 1, 191760, 24fbe86d07c66d4f791533219a6bbca5
+0, 6, 6, 1, 191708, 32f4e266cc3e22e8b5ad354f4685ca9f
+0, 7, 7, 1, 191688, 9614c1881c3c2807ac492b1c3d689559
+0, 8, 8, 1, 191568, a4e53b02fdbc66c47e099cb3506a5f27
+0, 9, 9, 1, 191544, c3f2fcb7a299163e72faa93522405def
+0, 10, 10, 1, 191468, 598cb568c2e4b651f04511eea480b8f0
+0, 11, 11, 1, 191280, 7ac77492856c214f6266da9eea4cc766
+0, 12, 12, 1, 191700, 5b261fda1cdafc11596fca42e902e8a9
+0, 13, 13, 1, 191424, c31421daddb684ec01a0b8953a340891
+0, 14, 14, 1, 191416, 742171e3f053ffb7f27dd14e9a408e33
+0, 15, 15, 1, 191408, 06efc3afdf3c97c6c6e6f76eeea217b7
+0, 16, 16, 1, 191500, ee9d95219dc34981f1e3a9feee21a12a
+0, 17, 17, 1, 191580, 9fd14328b5f304cab54405b2e7b6dd74
+0, 18, 18, 1, 191608, 84374f2e0540d97f4f5a5282397d1fd4
+0, 19, 19, 1, 191616, 6f8d0b3143d78d87209815e4f14e8fde
+0, 20, 20, 1, 191596, 4533cb5577bbee750eee21966f3e6b87
+0, 21, 21, 1, 191660, c9cbe09e11e7bb47565d54ec25e407e1
+0, 22, 22, 1, 191536, 3a9168133d91c67219052869bb4a1aa9
+0, 23, 23, 1, 191576, 0df4b9398953fe710b949cc3912927a1
+0, 24, 24, 1, 191636, 5ee06edd617272e33b59da14e9e472b5
+0, 25, 25, 1, 191524, 3e09b926cf3dbed003746d0fc4bb9eb1
+0, 26, 26, 1, 191640, e4f9408633b8cb13578de8caca4afd77
+0, 27, 27, 1, 191800, 7c57ae6d60df4676c132de16ebf1ec24
+0, 28, 28, 1, 192028, 36fd55e15ee357478bdd3085adc5d1f9
+0, 29, 29, 1, 191964, 82a4fd877d4dba1266fc28d9a74e5cf3
+0, 30, 30, 1, 191732, 3d905c393537ccdbdc2bb83cfc9ac1f3
+0, 31, 31, 1, 191788, 92e647f7728fe892c3f97d866aa9e6e7
+0, 32, 32, 1, 191636, d26af69ceee2e7433e04da1eee6a4043
+0, 33, 33, 1, 191400, 9e5d147eea116586d13cec38e59d0e90
+0, 34, 34, 1, 191332, 93419f91d6d4d274344a0f184f03210a
+0, 35, 35, 1, 191548, 61c4c7a96c86ccb5189daa63b3219340
+0, 36, 36, 1, 191852, 62fd435d20d032686bf9bad5ac5252b8
+0, 37, 37, 1, 191828, 2487f780f709f38c38a19b1d0e255575
+0, 38, 38, 1, 191808, 5bd0d224585427f2fa6fca1392ea6273
+0, 39, 39, 1, 191700, deaed17ec6cbc863313b7698114d54fd
+0, 40, 40, 1, 191812, 296dce78545cf89745c13f117347949b
+0, 41, 41, 1, 191548, 0273c1819d7af2f49b1b86b238414702
+0, 42, 42, 1, 191544, e9e29ab1e3f9fd5bff18748f38a3a79d
+0, 43, 43, 1, 191700, c211fa96ed541d7d53bc975577bd7bbc
+0, 44, 44, 1, 191780, cfcd29e8a289aa0f2d4026189bb0b966
+0, 45, 45, 1, 191952, 0c1f04a3877565eb8bd76b652626a27f
+0, 46, 46, 1, 191916, 1e49ee7ea02c2df7e0b6187fcc6cbdbe
+0, 47, 47, 1, 191784, 5fa516e0bb264c767e49169cf7accd23
+0, 48, 48, 1, 191716, 3a7abe462356b1020f3c8d496bcbbbdc
+0, 49, 49, 1, 191728, cf5fb801291c77b04d9937e4b828f772
diff --git a/tests/ref/fate/v410enc b/tests/ref/fate/v410enc
index ab219bbed1..b2c728e9b2 100644
--- a/tests/ref/fate/v410enc
+++ b/tests/ref/fate/v410enc
@@ -1 +1 @@
-e5c0b1f17d2a64a416dcf9bf7a38d9d9
+f7cf1b743c18f74d047ce8d6ea05d3d9
diff --git a/tests/ref/fate/vc1-ism b/tests/ref/fate/vc1-ism
index a60cb8ac33..7d3b0abb9b 100644
--- a/tests/ref/fate/vc1-ism
+++ b/tests/ref/fate/vc1-ism
@@ -1,63 +1,121 @@
-#tb 0: 1/10000000
-0, 4, 4, 0, 37440, 0xd1bc5235
-0, 1256670, 1256670, 0, 37440, 0x158e6167
-0, 2086670, 2086670, 0, 37440, 0x427158c5
-0, 2916670, 2916670, 0, 37440, 0x99304eea
-0, 3756670, 3756670, 0, 37440, 0xabeb6c35
-0, 4586670, 4586670, 0, 37440, 0xaa79b504
-0, 5416670, 5416670, 0, 37440, 0x7e36ecca
-0, 6256670, 6256670, 0, 37440, 0xf1b4138f
-0, 7086670, 7086670, 0, 37440, 0x5eff21da
-0, 7916670, 7916670, 0, 37440, 0x62e5963e
-0, 8756670, 8756670, 0, 37440, 0x27b4bb6c
-0, 9586670, 9586670, 0, 37440, 0x04260104
-0, 10416670, 10416670, 0, 37440, 0xdf4e2474
-0, 11256670, 11256670, 0, 37440, 0x8780e34c
-0, 12086670, 12086670, 0, 37440, 0x630a7583
-0, 12916670, 12916670, 0, 37440, 0x984b8f0e
-0, 13756670, 13756670, 0, 37440, 0x70f376f2
-0, 14586670, 14586670, 0, 37440, 0xde772d79
-0, 15416670, 15416670, 0, 37440, 0x3dc2bd9f
-0, 16256670, 16256670, 0, 37440, 0x02025d73
-0, 17086670, 17086670, 0, 37440, 0xd6554f62
-0, 17916670, 17916670, 0, 37440, 0x80643560
-0, 18756670, 18756670, 0, 37440, 0x9ce51e0b
-0, 19586670, 19586670, 0, 37440, 0x145fc900
-0, 20416670, 20416670, 0, 37440, 0x0a87552a
-0, 21256670, 21256670, 0, 37440, 0x1c07c825
-0, 22086670, 22086670, 0, 37440, 0xb1a32605
-0, 22916670, 22916670, 0, 37440, 0xff5e6696
-0, 23756670, 23756670, 0, 37440, 0x6c9e9e68
-0, 24586670, 24586670, 0, 37440, 0xf237bd6c
-0, 25416670, 25416670, 0, 37440, 0xc7ccc918
-0, 26256670, 26256670, 0, 37440, 0xacb3c881
-0, 27086670, 27086670, 0, 37440, 0x19d5be85
-0, 27506670, 27506670, 0, 37440, 0xdae7a7aa
-0, 27916670, 27916670, 0, 37440, 0x6b0f9f69
-0, 28756670, 28756670, 0, 37440, 0x353e8201
-0, 29586670, 29586670, 0, 37440, 0x66c8d7e0
-0, 30416670, 30416670, 0, 37440, 0x71431b9b
-0, 31256670, 31256670, 0, 37440, 0x95a146bb
-0, 32086670, 32086670, 0, 37440, 0xa3bdd43c
-0, 32916670, 32916670, 0, 37440, 0xa95423ea
-0, 33756670, 33756670, 0, 37440, 0x6cf82844
-0, 34586670, 34586670, 0, 37440, 0x1f7db118
-0, 35416670, 35416670, 0, 37440, 0x321c1c40
-0, 36256670, 36256670, 0, 37440, 0xa1471f4b
-0, 37086670, 37086670, 0, 37440, 0x24c07107
-0, 37916670, 37916670, 0, 37440, 0xd0ca6495
-0, 38756670, 38756670, 0, 37440, 0xb5ec3c38
-0, 39586670, 39586670, 0, 37440, 0x68170812
-0, 40416670, 40416670, 0, 37440, 0xd688706c
-0, 41256670, 41256670, 0, 37440, 0x28bd0fbf
-0, 42086670, 42086670, 0, 37440, 0x30559121
-0, 42916670, 42916670, 0, 37440, 0x4b427672
-0, 43756670, 43756670, 0, 37440, 0x38a70b06
-0, 44586670, 44586670, 0, 37440, 0x6efe8ea6
-0, 45416670, 45416670, 0, 37440, 0xf4060050
-0, 46256670, 46256670, 0, 37440, 0x5fa21382
-0, 47086670, 47086670, 0, 37440, 0xf7130133
-0, 47916670, 47916670, 0, 37440, 0x1dbae1be
-0, 48756670, 48756670, 0, 37440, 0xbdcd41a3
-0, 49586670, 49586670, 0, 37440, 0xc0036222
-0, 50006670, 50006670, 0, 37440, 0x68141016
+#tb 0: 1/24
+0, 0, 0, 1, 37440, 0xd1bc5235
+0, 2, 2, 1, 37440, 0x158e6167
+0, 3, 3, 1, 37440, 0x0faa4481
+0, 4, 4, 1, 37440, 0x427158c5
+0, 5, 5, 1, 37440, 0x4eb53ac6
+0, 6, 6, 1, 37440, 0x99304eea
+0, 7, 7, 1, 37440, 0xcc554a6f
+0, 8, 8, 1, 37440, 0xabeb6c35
+0, 9, 9, 1, 37440, 0xddfc7e18
+0, 10, 10, 1, 37440, 0xaa79b504
+0, 11, 11, 1, 37440, 0x5cb1c839
+0, 12, 12, 1, 37440, 0x7e36ecca
+0, 13, 13, 1, 37440, 0xf486f425
+0, 14, 14, 1, 37440, 0xf1b4138f
+0, 15, 15, 1, 37440, 0x966f1a49
+0, 16, 16, 1, 37440, 0x5eff21da
+0, 17, 17, 1, 37440, 0x333f39b1
+0, 18, 18, 1, 37440, 0x62e5963e
+0, 19, 19, 1, 37440, 0x26930671
+0, 20, 20, 1, 37440, 0x27b4bb6c
+0, 21, 21, 1, 37440, 0xdbd07766
+0, 22, 22, 1, 37440, 0x04260104
+0, 23, 23, 1, 37440, 0x9b1e078b
+0, 24, 24, 1, 37440, 0xdf4e2474
+0, 25, 25, 1, 37440, 0x57d44986
+0, 26, 26, 1, 37440, 0x8780e34c
+0, 27, 27, 1, 37440, 0xf80c8bc0
+0, 28, 28, 1, 37440, 0x630a7583
+0, 29, 29, 1, 37440, 0x235ae089
+0, 30, 30, 1, 37440, 0x984b8f0e
+0, 31, 31, 1, 37440, 0x865cf592
+0, 32, 32, 1, 37440, 0x70f376f2
+0, 33, 33, 1, 37440, 0x8b30c035
+0, 34, 34, 1, 37440, 0xde772d79
+0, 35, 35, 1, 37440, 0x8e076be5
+0, 36, 36, 1, 37440, 0x3dc2bd9f
+0, 37, 37, 1, 37440, 0xb782eb67
+0, 38, 38, 1, 37440, 0x02025d73
+0, 39, 39, 1, 37440, 0x86bbbce8
+0, 40, 40, 1, 37440, 0xd6554f62
+0, 41, 41, 1, 37440, 0xb831b917
+0, 42, 42, 1, 37440, 0x80643560
+0, 43, 43, 1, 37440, 0x4ecf9afd
+0, 44, 44, 1, 37440, 0x9ce51e0b
+0, 45, 45, 1, 37440, 0x179466cd
+0, 46, 46, 1, 37440, 0x145fc900
+0, 47, 47, 1, 37440, 0xb1b50402
+0, 48, 48, 1, 37440, 0x0a87552a
+0, 49, 49, 1, 37440, 0x8f53821d
+0, 50, 50, 1, 37440, 0x1c07c825
+0, 51, 51, 1, 37440, 0x49dde82f
+0, 52, 52, 1, 37440, 0xb1a32605
+0, 53, 53, 1, 37440, 0x410f3cd5
+0, 54, 54, 1, 37440, 0xff5e6696
+0, 55, 55, 1, 37440, 0x96f678c9
+0, 56, 56, 1, 37440, 0x6c9e9e68
+0, 57, 57, 1, 37440, 0x79a2a655
+0, 58, 58, 1, 37440, 0xf237bd6c
+0, 59, 59, 1, 37440, 0x4051b611
+0, 60, 60, 1, 37440, 0xc7ccc918
+0, 61, 61, 1, 37440, 0xbd02c122
+0, 62, 62, 1, 37440, 0xacb3c881
+0, 63, 63, 1, 37440, 0x2abdb940
+0, 64, 64, 1, 37440, 0x19d5be85
+0, 65, 65, 1, 37440, 0xfa5fb1ba
+0, 66, 66, 1, 37440, 0xdae7a7aa
+0, 67, 67, 1, 37440, 0x6b0f9f69
+0, 68, 68, 1, 37440, 0x353e8201
+0, 69, 69, 1, 37440, 0xa21443aa
+0, 70, 70, 1, 37440, 0x66c8d7e0
+0, 71, 71, 1, 37440, 0xc332068e
+0, 72, 72, 1, 37440, 0x71431b9b
+0, 73, 73, 1, 37440, 0x392f15cb
+0, 74, 74, 1, 37440, 0x95a146bb
+0, 75, 75, 1, 37440, 0x7c51740a
+0, 76, 76, 1, 37440, 0xa3bdd43c
+0, 77, 77, 1, 37440, 0xa079f965
+0, 78, 78, 1, 37440, 0xa95423ea
+0, 79, 79, 1, 37440, 0xd1bd2c67
+0, 80, 80, 1, 37440, 0x6cf82844
+0, 81, 81, 1, 37440, 0xd401e128
+0, 82, 82, 1, 37440, 0x1f7db118
+0, 83, 83, 1, 37440, 0x2e0a65a9
+0, 84, 84, 1, 37440, 0x321c1c40
+0, 85, 85, 1, 37440, 0x95b2a127
+0, 86, 86, 1, 37440, 0xa1471f4b
+0, 87, 87, 1, 37440, 0x29d148c0
+0, 88, 88, 1, 37440, 0x24c07107
+0, 89, 89, 1, 37440, 0x0ead678d
+0, 90, 90, 1, 37440, 0xd0ca6495
+0, 91, 91, 1, 37440, 0x08f935ef
+0, 92, 92, 1, 37440, 0xb5ec3c38
+0, 93, 93, 1, 37440, 0xce371628
+0, 94, 94, 1, 37440, 0x68170812
+0, 95, 95, 1, 37440, 0xe222699e
+0, 96, 96, 1, 37440, 0xd688706c
+0, 97, 97, 1, 37440, 0x81a033f9
+0, 98, 98, 1, 37440, 0x28bd0fbf
+0, 99, 99, 1, 37440, 0xe36db7b2
+0, 100, 100, 1, 37440, 0x30559121
+0, 101, 101, 1, 37440, 0xbf2b5fc8
+0, 102, 102, 1, 37440, 0x4b427672
+0, 103, 103, 1, 37440, 0x0544b0b4
+0, 104, 104, 1, 37440, 0x38a70b06
+0, 105, 105, 1, 37440, 0x4ed62607
+0, 106, 106, 1, 37440, 0x6efe8ea6
+0, 107, 107, 1, 37440, 0x81197e11
+0, 108, 108, 1, 37440, 0xf4060050
+0, 109, 109, 1, 37440, 0xaf205f13
+0, 110, 110, 1, 37440, 0x5fa21382
+0, 111, 111, 1, 37440, 0x8627ad05
+0, 112, 112, 1, 37440, 0xf7130133
+0, 113, 113, 1, 37440, 0x76dea7ba
+0, 114, 114, 1, 37440, 0x1dbae1be
+0, 115, 115, 1, 37440, 0x74a933f7
+0, 116, 116, 1, 37440, 0xbdcd41a3
+0, 117, 117, 1, 37440, 0xf0fe8c1c
+0, 118, 118, 1, 37440, 0xc0036222
+0, 119, 119, 1, 37440, 0x3058385c
+0, 120, 120, 1, 37440, 0x68141016
diff --git a/tests/ref/fate/vc1_ilaced_twomv b/tests/ref/fate/vc1_ilaced_twomv
index dca5fa9990..1b4d55f14c 100644
--- a/tests/ref/fate/vc1_ilaced_twomv
+++ b/tests/ref/fate/vc1_ilaced_twomv
@@ -1,14 +1,14 @@
-#tb 0: 1/25
+#tb 0: 1001/30000
0, 0, 0, 1, 3110400, 0x764f8856
0, 2, 2, 1, 3110400, 0x3b615b79
0, 3, 3, 1, 3110400, 0x4fbb6f84
0, 4, 4, 1, 3110400, 0xc1ca8532
-0, 5, 5, 1, 3110400, 0x53efd0f9
-0, 6, 6, 1, 3110400, 0xa9605bc9
-0, 7, 7, 1, 3110400, 0xbaa9aede
-0, 8, 8, 1, 3110400, 0x602fbcd5
-0, 9, 9, 1, 3110400, 0x93d204b5
-0, 10, 10, 1, 3110400, 0x7b047286
-0, 11, 11, 1, 3110400, 0xa7cb2f84
-0, 12, 12, 1, 3110400, 0xfba20dd1
-0, 13, 13, 1, 3110400, 0x24c32a55
+0, 5, 5, 1, 3110400, 0xb6e7d363
+0, 6, 6, 1, 3110400, 0x1beb5c34
+0, 7, 7, 1, 3110400, 0xcb8cb061
+0, 8, 8, 1, 3110400, 0x13ddbd61
+0, 9, 9, 1, 3110400, 0xde8f052f
+0, 10, 10, 1, 3110400, 0x4d4072db
+0, 11, 11, 1, 3110400, 0x4e5d29e3
+0, 12, 12, 1, 3110400, 0x75300531
+0, 13, 13, 1, 3110400, 0x1114285a
diff --git a/tests/ref/fate/vcr2 b/tests/ref/fate/vcr2
new file mode 100644
index 0000000000..f7e1540b33
--- /dev/null
+++ b/tests/ref/fate/vcr2
@@ -0,0 +1,158 @@
+#tb 0: 1001/15000
+0, 0, 0, 1, 38016, 0x50e93e0d
+0, 1, 1, 1, 38016, 0x6ac8627d
+0, 2, 2, 1, 38016, 0x6f38661e
+0, 3, 3, 1, 38016, 0x18bb3e23
+0, 4, 4, 1, 38016, 0x2029f4da
+0, 5, 5, 1, 38016, 0xa981eeb9
+0, 6, 6, 1, 38016, 0x65c636ef
+0, 7, 7, 1, 38016, 0x8218f178
+0, 8, 8, 1, 38016, 0xc3986e18
+0, 9, 9, 1, 38016, 0xac871f50
+0, 10, 10, 1, 38016, 0xe83ed617
+0, 11, 11, 1, 38016, 0xe87c4132
+0, 12, 12, 1, 38016, 0x9e03c321
+0, 13, 13, 1, 38016, 0x81f06a6e
+0, 14, 14, 1, 38016, 0x4ce15039
+0, 15, 15, 1, 38016, 0x398dfbdd
+0, 16, 16, 1, 38016, 0x3049218c
+0, 17, 17, 1, 38016, 0x6d90bb3f
+0, 18, 18, 1, 38016, 0x5b61ae57
+0, 19, 19, 1, 38016, 0xaf17011d
+0, 20, 20, 1, 38016, 0xb6c13da6
+0, 21, 21, 1, 38016, 0xb58135cf
+0, 22, 22, 1, 38016, 0x051c33ce
+0, 23, 23, 1, 38016, 0xda950393
+0, 24, 24, 1, 38016, 0x76f7ea61
+0, 25, 25, 1, 38016, 0xcba6f5c8
+0, 26, 26, 1, 38016, 0x2ac20405
+0, 27, 27, 1, 38016, 0x6c790a1b
+0, 28, 28, 1, 38016, 0x8525413b
+0, 29, 29, 1, 38016, 0xef2e46a5
+0, 30, 30, 1, 38016, 0x32c16c28
+0, 31, 31, 1, 38016, 0x9fb0755f
+0, 32, 32, 1, 38016, 0xdfd7a1e2
+0, 33, 33, 1, 38016, 0xa91eb2d0
+0, 34, 34, 1, 38016, 0xb7bed869
+0, 35, 35, 1, 38016, 0x0263da70
+0, 36, 36, 1, 38016, 0x1403cf83
+0, 37, 37, 1, 38016, 0xb766f81a
+0, 38, 38, 1, 38016, 0x85abd4e0
+0, 39, 39, 1, 38016, 0xfc30c171
+0, 40, 40, 1, 38016, 0xb53bb9e5
+0, 41, 41, 1, 38016, 0xe93ca93c
+0, 42, 42, 1, 38016, 0xfa9db507
+0, 43, 43, 1, 38016, 0xd4da8492
+0, 44, 44, 1, 38016, 0x951cb041
+0, 45, 45, 1, 38016, 0x64fb9a09
+0, 46, 46, 1, 38016, 0x8f89b841
+0, 47, 47, 1, 38016, 0x9ee4b6df
+0, 48, 48, 1, 38016, 0xd733ae27
+0, 49, 49, 1, 38016, 0x2a1ab87d
+0, 50, 50, 1, 38016, 0x4853bf88
+0, 51, 51, 1, 38016, 0x701da865
+0, 52, 52, 1, 38016, 0x074d8248
+0, 53, 53, 1, 38016, 0xa1b4b019
+0, 54, 54, 1, 38016, 0x33f798c7
+0, 55, 55, 1, 38016, 0x5091bd66
+0, 56, 56, 1, 38016, 0x9dc0bf08
+0, 57, 57, 1, 38016, 0x83cff4c3
+0, 58, 58, 1, 38016, 0xce551295
+0, 59, 59, 1, 38016, 0x3c334a45
+0, 60, 60, 1, 38016, 0xd6e669ae
+0, 61, 61, 1, 38016, 0x08817cb0
+0, 62, 62, 1, 38016, 0x3d399508
+0, 63, 63, 1, 38016, 0xaf49a306
+0, 64, 64, 1, 38016, 0x6b77e02c
+0, 65, 65, 1, 38016, 0x34a6cc72
+0, 66, 66, 1, 38016, 0x0303e6bb
+0, 67, 67, 1, 38016, 0x3995eee2
+0, 68, 68, 1, 38016, 0x8eefd136
+0, 69, 69, 1, 38016, 0xd69ad171
+0, 70, 70, 1, 38016, 0xed98bff6
+0, 71, 71, 1, 38016, 0x606ba5ef
+0, 72, 72, 1, 38016, 0xbce4afaa
+0, 73, 73, 1, 38016, 0xa5baac40
+0, 74, 74, 1, 38016, 0x7a15929f
+0, 75, 75, 1, 38016, 0x0374cdec
+0, 76, 76, 1, 38016, 0xf482e941
+0, 77, 77, 1, 38016, 0xced1c9e3
+0, 78, 78, 1, 38016, 0x638fd91f
+0, 79, 79, 1, 38016, 0xced5d802
+0, 80, 80, 1, 38016, 0x330adeeb
+0, 81, 81, 1, 38016, 0x7a70f93e
+0, 82, 82, 1, 38016, 0x25c0dac1
+0, 83, 83, 1, 38016, 0x6f9401cf
+0, 84, 84, 1, 38016, 0x01632a5b
+0, 85, 85, 1, 38016, 0x6eedd857
+0, 86, 86, 1, 38016, 0xcfad1017
+0, 87, 87, 1, 38016, 0x38071e53
+0, 88, 88, 1, 38016, 0xc7c3013f
+0, 89, 89, 1, 38016, 0x1f41fe19
+0, 90, 90, 1, 38016, 0x9662e170
+0, 91, 91, 1, 38016, 0xec19ecfc
+0, 92, 92, 1, 38016, 0xab419765
+0, 93, 93, 1, 38016, 0xe784d98b
+0, 94, 94, 1, 38016, 0x93c1a4bf
+0, 95, 95, 1, 38016, 0xf2e4c9b4
+0, 96, 96, 1, 38016, 0x7cb6c1ff
+0, 97, 97, 1, 38016, 0x6fb36837
+0, 98, 98, 1, 38016, 0x6fb64665
+0, 99, 99, 1, 38016, 0xf24eaba9
+0, 100, 100, 1, 38016, 0x3866d28b
+0, 101, 101, 1, 38016, 0x807e829c
+0, 102, 102, 1, 38016, 0xf25fcbbb
+0, 103, 103, 1, 38016, 0xc28ba68f
+0, 104, 104, 1, 38016, 0x65ef8def
+0, 105, 105, 1, 38016, 0xc4646ee4
+0, 106, 106, 1, 38016, 0x3cb76962
+0, 107, 107, 1, 38016, 0xe5500136
+0, 108, 108, 1, 38016, 0xb086aa05
+0, 109, 109, 1, 38016, 0xde9fd4c3
+0, 110, 110, 1, 38016, 0xcae0d11b
+0, 111, 111, 1, 38016, 0x6cd3ee1a
+0, 112, 112, 1, 38016, 0x38981b85
+0, 113, 113, 1, 38016, 0xbe742f68
+0, 114, 114, 1, 38016, 0x29c41fc7
+0, 115, 115, 1, 38016, 0x43612eaf
+0, 116, 116, 1, 38016, 0x199dba2f
+0, 117, 117, 1, 38016, 0xb434f64d
+0, 118, 118, 1, 38016, 0x36f2fd8c
+0, 119, 119, 1, 38016, 0xc1075321
+0, 120, 120, 1, 38016, 0x7eabeab8
+0, 121, 121, 1, 38016, 0x7fcd5127
+0, 122, 122, 1, 38016, 0x37ddb544
+0, 123, 123, 1, 38016, 0x5dee2700
+0, 124, 124, 1, 38016, 0x46deb355
+0, 125, 125, 1, 38016, 0xb2496a7c
+0, 126, 126, 1, 38016, 0xfaf3b134
+0, 127, 127, 1, 38016, 0x42e9dbe1
+0, 128, 128, 1, 38016, 0x699fc6e0
+0, 129, 129, 1, 38016, 0x43ba68ae
+0, 130, 130, 1, 38016, 0xffd21579
+0, 131, 131, 1, 38016, 0xdd979741
+0, 132, 132, 1, 38016, 0x789c89aa
+0, 133, 133, 1, 38016, 0x40be024e
+0, 134, 134, 1, 38016, 0xa60c291d
+0, 135, 135, 1, 38016, 0xa8d253e9
+0, 136, 136, 1, 38016, 0x16d7f60e
+0, 137, 137, 1, 38016, 0xf1d21a57
+0, 138, 138, 1, 38016, 0x5e80e3bd
+0, 139, 139, 1, 38016, 0xceec0529
+0, 140, 140, 1, 38016, 0x1ff9c462
+0, 141, 141, 1, 38016, 0x51c168d2
+0, 142, 142, 1, 38016, 0xf61f2059
+0, 143, 143, 1, 38016, 0xb22fa794
+0, 144, 144, 1, 38016, 0xb81ec7d5
+0, 145, 145, 1, 38016, 0x7555d1df
+0, 146, 146, 1, 38016, 0x860d9de3
+0, 147, 147, 1, 38016, 0x9b19a66f
+0, 148, 148, 1, 38016, 0xec52d405
+0, 149, 149, 1, 38016, 0x2da4d05b
+0, 150, 150, 1, 38016, 0xf15bf060
+0, 151, 151, 1, 38016, 0xfabcc24a
+0, 152, 152, 1, 38016, 0xc159f63a
+0, 153, 153, 1, 38016, 0x0b97fcc1
+0, 154, 154, 1, 38016, 0xe0c063a2
+0, 155, 155, 1, 38016, 0x7bda9bec
+0, 156, 156, 1, 38016, 0xbe99a923
diff --git a/tests/ref/fate/vmnc-16bit b/tests/ref/fate/vmnc-16bit
index 2a1848eccb..064b7fa9de 100644
--- a/tests/ref/fate/vmnc-16bit
+++ b/tests/ref/fate/vmnc-16bit
@@ -1,193 +1,193 @@
#tb 0: 1/5
-0, 0, 0, 1, 864000, 0x9b1cee65
-0, 1, 1, 1, 864000, 0x82950e3f
-0, 2, 2, 1, 864000, 0x335f9678
-0, 3, 3, 1, 864000, 0x6b86b7e7
-0, 4, 4, 1, 864000, 0x25618cf2
-0, 5, 5, 1, 864000, 0xed2196c9
-0, 6, 6, 1, 864000, 0xbeaa31ba
-0, 7, 7, 1, 864000, 0x14e6c8ab
-0, 8, 8, 1, 864000, 0x17e5c196
-0, 9, 9, 1, 864000, 0x4aa15110
-0, 10, 10, 1, 864000, 0x4aa15110
-0, 11, 11, 1, 864000, 0x4aa15110
-0, 12, 12, 1, 864000, 0x3c2d3809
-0, 13, 13, 1, 864000, 0xd075f4d0
-0, 14, 14, 1, 864000, 0x0c3f2833
-0, 15, 15, 1, 864000, 0xe7471872
-0, 16, 16, 1, 864000, 0x4300b71d
-0, 17, 17, 1, 864000, 0x6b5844ec
-0, 18, 18, 1, 864000, 0xb3ebc395
-0, 19, 19, 1, 864000, 0x39aa8a7d
-0, 20, 20, 1, 864000, 0x52a3d93d
-0, 21, 21, 1, 864000, 0x73adbdac
-0, 22, 22, 1, 864000, 0xa9fd6cdc
-0, 23, 23, 1, 864000, 0x4a085344
-0, 24, 24, 1, 864000, 0xc21b943c
-0, 25, 25, 1, 864000, 0xfaef6ed4
-0, 26, 26, 1, 864000, 0xa3e9163c
-0, 27, 27, 1, 864000, 0x917e2be4
-0, 28, 28, 1, 864000, 0x2d89d534
-0, 29, 29, 1, 864000, 0x6fe5a9e4
-0, 30, 30, 1, 864000, 0x71af29ec
-0, 31, 31, 1, 864000, 0x8f33f6ad
-0, 32, 32, 1, 864000, 0xe7d46a24
-0, 33, 33, 1, 864000, 0xb631e044
-0, 34, 34, 1, 864000, 0x77db01cb
-0, 35, 35, 1, 864000, 0x9861b6ec
-0, 36, 36, 1, 864000, 0x973bd263
-0, 37, 37, 1, 864000, 0xdd4c175b
-0, 38, 38, 1, 864000, 0xdc28469b
-0, 39, 39, 1, 864000, 0x67393ebb
-0, 40, 40, 1, 864000, 0x01a06813
-0, 41, 41, 1, 864000, 0x63e88f73
-0, 42, 42, 1, 864000, 0x3ffbdd73
-0, 43, 43, 1, 864000, 0xd25f790b
-0, 44, 44, 1, 864000, 0x14e3c5d3
-0, 45, 45, 1, 864000, 0x0d3d1202
-0, 46, 46, 1, 864000, 0x69decf03
-0, 47, 47, 1, 864000, 0x1b20ab93
-0, 48, 48, 1, 864000, 0xee2f8d4a
-0, 49, 49, 1, 864000, 0xaac44c52
-0, 50, 50, 1, 864000, 0x3f874a5a
-0, 51, 51, 1, 864000, 0x239b2d7a
-0, 52, 52, 1, 864000, 0xb85db552
-0, 53, 53, 1, 864000, 0xb12962a2
-0, 54, 54, 1, 864000, 0xb8270fd9
-0, 55, 55, 1, 864000, 0x14930601
-0, 56, 56, 1, 864000, 0x827a15c1
-0, 57, 57, 1, 864000, 0xe31011d1
-0, 58, 58, 1, 864000, 0xcd2154c1
-0, 59, 59, 1, 864000, 0xad02dbd9
-0, 60, 60, 1, 864000, 0x40c17d58
-0, 61, 61, 1, 864000, 0x8219e3b9
-0, 62, 62, 1, 864000, 0x2d348340
-0, 63, 63, 1, 864000, 0x6b61dfc9
-0, 64, 64, 1, 864000, 0xc8d95be1
-0, 65, 65, 1, 864000, 0x70ba0918
-0, 66, 66, 1, 864000, 0xdc728131
-0, 67, 67, 1, 864000, 0x9b054a10
-0, 68, 68, 1, 864000, 0x3983f751
-0, 69, 69, 1, 864000, 0x325fe1a9
-0, 70, 70, 1, 864000, 0x7a41eac0
-0, 71, 71, 1, 864000, 0x324372a8
-0, 72, 72, 1, 864000, 0xc014ea18
-0, 73, 73, 1, 864000, 0x1a506a1f
-0, 74, 74, 1, 864000, 0x47b59557
-0, 75, 75, 1, 864000, 0x5f2e194f
-0, 76, 76, 1, 864000, 0x9f6abb68
-0, 77, 77, 1, 864000, 0x831d2b97
-0, 78, 78, 1, 864000, 0x0635af7f
-0, 79, 79, 1, 864000, 0xe54a5626
-0, 80, 80, 1, 864000, 0x704dca4f
-0, 81, 81, 1, 864000, 0x47de6676
-0, 82, 82, 1, 864000, 0x609705fd
-0, 83, 83, 1, 864000, 0x8d92e086
-0, 84, 84, 1, 864000, 0xdb7dab5e
-0, 85, 85, 1, 864000, 0xe6ccb686
-0, 86, 86, 1, 864000, 0x0d137f66
-0, 87, 87, 1, 864000, 0xd200035d
-0, 88, 88, 1, 864000, 0x7dcb959d
-0, 89, 89, 1, 864000, 0xee849f75
-0, 90, 90, 1, 864000, 0x89d14acd
-0, 91, 91, 1, 864000, 0x3738029d
-0, 92, 92, 1, 864000, 0x6f4c4395
-0, 93, 93, 1, 864000, 0x06334395
-0, 94, 94, 1, 864000, 0x238b7c94
-0, 95, 95, 1, 864000, 0xfa5d1e14
-0, 96, 96, 1, 864000, 0x50b10e54
-0, 97, 97, 1, 864000, 0x9ed3b6e4
-0, 98, 98, 1, 864000, 0x68da9374
-0, 99, 99, 1, 864000, 0xb32a137c
-0, 100, 100, 1, 864000, 0x577d5084
-0, 101, 101, 1, 864000, 0xd262176b
-0, 102, 102, 1, 864000, 0xf58b44b3
-0, 103, 103, 1, 864000, 0xd0828edc
-0, 104, 104, 1, 864000, 0xc91a7544
-0, 105, 105, 1, 864000, 0x18ae7f1c
-0, 106, 106, 1, 864000, 0x82623643
-0, 107, 107, 1, 864000, 0x9cf82cfb
-0, 108, 108, 1, 864000, 0x93ad116b
-0, 109, 109, 1, 864000, 0xa669044b
-0, 110, 110, 1, 864000, 0x8adf88c3
-0, 111, 111, 1, 864000, 0xb83fb413
-0, 112, 112, 1, 864000, 0xb9e291f3
-0, 113, 113, 1, 864000, 0x5833dcc3
-0, 114, 114, 1, 864000, 0x4ab825aa
-0, 115, 115, 1, 864000, 0xb52c3b53
-0, 116, 116, 1, 864000, 0x0cb0dd53
-0, 117, 117, 1, 864000, 0x98b8dd52
-0, 118, 118, 1, 864000, 0x989230ba
-0, 119, 119, 1, 864000, 0xaed4c073
-0, 120, 120, 1, 864000, 0x76a7c83a
-0, 121, 121, 1, 864000, 0x02711eea
-0, 122, 122, 1, 864000, 0x8de65fe2
-0, 123, 123, 1, 864000, 0xc1163689
-0, 124, 124, 1, 864000, 0xc04f8b31
-0, 125, 125, 1, 864000, 0x69218d2a
-0, 126, 126, 1, 864000, 0x7e3abe62
-0, 127, 127, 1, 864000, 0x00ebe27a
-0, 128, 128, 1, 864000, 0x34803f11
-0, 129, 129, 1, 864000, 0x85591cd9
-0, 130, 130, 1, 864000, 0x8422fb51
-0, 131, 131, 1, 864000, 0x67c759e1
-0, 132, 132, 1, 864000, 0x4ac36af1
-0, 133, 133, 1, 864000, 0xdf00fca2
-0, 134, 134, 1, 864000, 0x74c633d1
-0, 135, 135, 1, 864000, 0x00251c31
-0, 136, 136, 1, 864000, 0x6d12a499
-0, 137, 137, 1, 864000, 0x1b6492e1
-0, 138, 138, 1, 864000, 0xdfc9a2a1
-0, 139, 139, 1, 864000, 0x33dcac79
-0, 140, 140, 1, 864000, 0x2305a499
-0, 141, 141, 1, 864000, 0xe1f3ae71
-0, 142, 142, 1, 864000, 0xc0cc92e1
-0, 143, 143, 1, 864000, 0x53d3b261
-0, 144, 144, 1, 864000, 0xf953aa81
-0, 145, 145, 1, 864000, 0x4108da69
-0, 146, 146, 1, 864000, 0xd6acf9e9
-0, 147, 147, 1, 864000, 0xb97ed900
-0, 148, 148, 1, 864000, 0x1d8b7a80
-0, 149, 149, 1, 864000, 0xd5406cb8
-0, 150, 150, 1, 864000, 0x5aa34948
-0, 151, 151, 1, 864000, 0x328eee01
-0, 152, 152, 1, 864000, 0xac92e621
-0, 153, 153, 1, 864000, 0x4fa1f5e1
-0, 154, 154, 1, 864000, 0xf7c4e8a8
-0, 155, 155, 1, 864000, 0xc358bd58
-0, 156, 156, 1, 864000, 0x29ec4b27
-0, 157, 157, 1, 864000, 0xf7219c88
-0, 158, 158, 1, 864000, 0xe77ff130
-0, 159, 159, 1, 864000, 0x73683417
-0, 160, 160, 1, 864000, 0x08b6be77
-0, 161, 161, 1, 864000, 0x3a7eea6f
-0, 162, 162, 1, 864000, 0xb319cce7
-0, 163, 163, 1, 864000, 0x9607b13e
-0, 164, 164, 1, 864000, 0x30543f0d
-0, 165, 165, 1, 864000, 0x56915a9e
-0, 166, 166, 1, 864000, 0x79f158a6
-0, 167, 167, 1, 864000, 0x498b8bd6
-0, 168, 168, 1, 864000, 0xe9ad7046
-0, 169, 169, 1, 864000, 0xe9ad7046
-0, 170, 170, 1, 864000, 0x10317e0e
-0, 171, 171, 1, 864000, 0x10317e0e
-0, 172, 172, 1, 864000, 0x10317e0e
-0, 173, 173, 1, 864000, 0x99ec7046
-0, 174, 174, 1, 864000, 0x924d46ee
-0, 175, 175, 1, 864000, 0x98bf333e
-0, 176, 176, 1, 864000, 0xb2625c96
-0, 177, 177, 1, 864000, 0xb46b3926
-0, 178, 178, 1, 864000, 0xeb4e5c96
-0, 179, 179, 1, 864000, 0x87154ece
-0, 180, 180, 1, 864000, 0x9e4c666e
-0, 181, 181, 1, 864000, 0x65b53d16
-0, 182, 182, 1, 864000, 0x99e85e8e
-0, 183, 183, 1, 864000, 0x650ba17e
-0, 184, 184, 1, 864000, 0x1ecb000e
-0, 185, 185, 1, 864000, 0xb942327d
-0, 186, 186, 1, 864000, 0x1bf20925
-0, 187, 187, 1, 864000, 0x61dba6a5
-0, 188, 188, 1, 864000, 0x5de16d8d
-0, 189, 189, 1, 864000, 0x4eb1f75d
-0, 190, 190, 1, 864000, 0x4eb1f75d
-0, 191, 191, 1, 864000, 0xd0750144
+0, 0, 0, 1, 864000, 0xd6929ea7
+0, 1, 1, 1, 864000, 0x9d5283fa
+0, 2, 2, 1, 864000, 0xcec52d42
+0, 3, 3, 1, 864000, 0x34d5943e
+0, 4, 4, 1, 864000, 0x5bd0b2a8
+0, 5, 5, 1, 864000, 0x41f1c468
+0, 6, 6, 1, 864000, 0x16aa54b9
+0, 7, 7, 1, 864000, 0xdb92e88a
+0, 8, 8, 1, 864000, 0x0ae5d695
+0, 9, 9, 1, 864000, 0x2c338d33
+0, 10, 10, 1, 864000, 0x2c338d33
+0, 11, 11, 1, 864000, 0x2c338d33
+0, 12, 12, 1, 864000, 0xd9c1152f
+0, 13, 13, 1, 864000, 0x9833bf29
+0, 14, 14, 1, 864000, 0xbedbe1bc
+0, 15, 15, 1, 864000, 0xd137d921
+0, 16, 16, 1, 864000, 0xcb0f967a
+0, 17, 17, 1, 864000, 0x931a2881
+0, 18, 18, 1, 864000, 0xeb8ca351
+0, 19, 19, 1, 864000, 0xe2f66886
+0, 20, 20, 1, 864000, 0xb81fb99e
+0, 21, 21, 1, 864000, 0x2048a4d9
+0, 22, 22, 1, 864000, 0x145b514f
+0, 23, 23, 1, 864000, 0xcb6236f4
+0, 24, 24, 1, 864000, 0x6d2d79db
+0, 25, 25, 1, 864000, 0xadca5356
+0, 26, 26, 1, 864000, 0x5d51f80c
+0, 27, 27, 1, 864000, 0x9e240e68
+0, 28, 28, 1, 864000, 0xcafcbcc2
+0, 29, 29, 1, 864000, 0x76f99028
+0, 30, 30, 1, 864000, 0xd7450c61
+0, 31, 31, 1, 864000, 0x1431d79c
+0, 32, 32, 1, 864000, 0x081a4e30
+0, 33, 33, 1, 864000, 0x0437c7d4
+0, 34, 34, 1, 864000, 0xb4bbea4b
+0, 35, 35, 1, 864000, 0x0a149d41
+0, 36, 36, 1, 864000, 0xf7dbc0d5
+0, 37, 37, 1, 864000, 0x6933003c
+0, 38, 38, 1, 864000, 0x18ce30e4
+0, 39, 39, 1, 864000, 0x8c8728c8
+0, 40, 40, 1, 864000, 0x37b6535b
+0, 41, 41, 1, 864000, 0xcdab7be7
+0, 42, 42, 1, 864000, 0xe1e1cbe7
+0, 43, 43, 1, 864000, 0x1d476482
+0, 44, 44, 1, 864000, 0x0ae0b393
+0, 45, 45, 1, 864000, 0x49140206
+0, 46, 46, 1, 864000, 0xe9f9bd09
+0, 47, 47, 1, 864000, 0x89a7988b
+0, 48, 48, 1, 864000, 0x24f780a7
+0, 49, 49, 1, 864000, 0x88a53dc0
+0, 50, 50, 1, 864000, 0x27ed3bb9
+0, 51, 51, 1, 864000, 0xc8151dfd
+0, 52, 52, 1, 864000, 0xfcb8a9e0
+0, 53, 53, 1, 864000, 0xd6d554ba
+0, 54, 54, 1, 864000, 0xbc6e06c6
+0, 55, 55, 1, 864000, 0x6334fc94
+0, 56, 56, 1, 864000, 0x7a7e0cdb
+0, 57, 57, 1, 864000, 0xf96008cd
+0, 58, 58, 1, 864000, 0xffbc4dbb
+0, 59, 59, 1, 864000, 0x1071d886
+0, 60, 60, 1, 864000, 0x6b967ed3
+0, 61, 61, 1, 864000, 0xd370e0a2
+0, 62, 62, 1, 864000, 0x4cca84e8
+0, 63, 63, 1, 864000, 0xd46bdc94
+0, 64, 64, 1, 864000, 0x102a54bf
+0, 65, 65, 1, 864000, 0xe39406cb
+0, 66, 66, 1, 864000, 0x9bb07ad9
+0, 67, 67, 1, 864000, 0xd3b749b2
+0, 68, 68, 1, 864000, 0x59faf47d
+0, 69, 69, 1, 864000, 0xba38de30
+0, 70, 70, 1, 864000, 0x7084eed8
+0, 71, 71, 1, 864000, 0xa966732d
+0, 72, 72, 1, 864000, 0xb9f1ee2b
+0, 73, 73, 1, 864000, 0x09267201
+0, 74, 74, 1, 864000, 0xc6b09e30
+0, 75, 75, 1, 864000, 0x080d1e77
+0, 76, 76, 1, 864000, 0xe28bbdc5
+0, 77, 77, 1, 864000, 0x230a30f8
+0, 78, 78, 1, 864000, 0x4d0bb8cd
+0, 79, 79, 1, 864000, 0x96096417
+0, 80, 80, 1, 864000, 0x7467d417
+0, 81, 81, 1, 864000, 0xbcc07491
+0, 82, 82, 1, 864000, 0x794718d7
+0, 83, 83, 1, 864000, 0xf23ff243
+0, 84, 84, 1, 864000, 0x9961bb86
+0, 85, 85, 1, 864000, 0x7be4c703
+0, 86, 86, 1, 864000, 0x727f8e3f
+0, 87, 87, 1, 864000, 0xda421623
+0, 88, 88, 1, 864000, 0xca69ac6b
+0, 89, 89, 1, 864000, 0x67aeb68e
+0, 90, 90, 1, 864000, 0x3b665f61
+0, 91, 91, 1, 864000, 0x3716150b
+0, 92, 92, 1, 864000, 0x2dcd57f2
+0, 93, 93, 1, 864000, 0x800257f2
+0, 94, 94, 1, 864000, 0x10de99ef
+0, 95, 95, 1, 864000, 0x3438389f
+0, 96, 96, 1, 864000, 0x42682867
+0, 97, 97, 1, 864000, 0x9d64d5a9
+0, 98, 98, 1, 864000, 0x9e2eb12b
+0, 99, 99, 1, 864000, 0xb9f42d64
+0, 100, 100, 1, 864000, 0xd6f36c3d
+0, 101, 101, 1, 864000, 0xfeaa390f
+0, 102, 102, 1, 864000, 0x3fe067b0
+0, 103, 103, 1, 864000, 0x45ebac70
+0, 104, 104, 1, 864000, 0xabfb9215
+0, 105, 105, 1, 864000, 0x20f79c38
+0, 106, 106, 1, 864000, 0x326858d2
+0, 107, 107, 1, 864000, 0x67154ef1
+0, 108, 108, 1, 864000, 0x2b3d328f
+0, 109, 109, 1, 864000, 0x8190250b
+0, 110, 110, 1, 864000, 0x31dead22
+0, 111, 111, 1, 864000, 0xa9b8d9bc
+0, 112, 112, 1, 864000, 0x330db698
+0, 113, 113, 1, 864000, 0x0ff803b1
+0, 114, 114, 1, 864000, 0xb7614eb4
+0, 115, 115, 1, 864000, 0x12c75d64
+0, 116, 116, 1, 864000, 0x622c03f3
+0, 117, 117, 1, 864000, 0x0ace0b90
+0, 118, 118, 1, 864000, 0x2c2b59c6
+0, 119, 119, 1, 864000, 0xadbbe628
+0, 120, 120, 1, 864000, 0x1371f576
+0, 121, 121, 1, 864000, 0x066a471c
+0, 122, 122, 1, 864000, 0x0e6f8a03
+0, 123, 123, 1, 864000, 0x4325670d
+0, 124, 124, 1, 864000, 0x2e8abe3a
+0, 125, 125, 1, 864000, 0x0ea8b8a4
+0, 126, 126, 1, 864000, 0x65e4eb53
+0, 127, 127, 1, 864000, 0xa03d108d
+0, 128, 128, 1, 864000, 0xd3d56fd6
+0, 129, 129, 1, 864000, 0x1b8e4c47
+0, 130, 130, 1, 864000, 0x5bd0316d
+0, 131, 131, 1, 864000, 0x49478b20
+0, 132, 132, 1, 864000, 0x3dae9cb2
+0, 133, 133, 1, 864000, 0x671e2b2a
+0, 134, 134, 1, 864000, 0x521763ee
+0, 135, 135, 1, 864000, 0x73dc4b9a
+0, 136, 136, 1, 864000, 0x3c95d7bf
+0, 137, 137, 1, 864000, 0x3abdc580
+0, 138, 138, 1, 864000, 0xae24d5b8
+0, 139, 139, 1, 864000, 0xe630dfdb
+0, 140, 140, 1, 864000, 0x229ad7bf
+0, 141, 141, 1, 864000, 0x3372e1e2
+0, 142, 142, 1, 864000, 0xa821c580
+0, 143, 143, 1, 864000, 0x7c78e5f0
+0, 144, 144, 1, 864000, 0x3324ddd4
+0, 145, 145, 1, 864000, 0x98580f38
+0, 146, 146, 1, 864000, 0x14072fa8
+0, 147, 147, 1, 864000, 0xdbb21510
+0, 148, 148, 1, 864000, 0x6a55b3b1
+0, 149, 149, 1, 864000, 0x7b5ba580
+0, 150, 150, 1, 864000, 0x2f5e8102
+0, 151, 151, 1, 864000, 0x691e2313
+0, 152, 152, 1, 864000, 0x423b1af7
+0, 153, 153, 1, 864000, 0x02842b2f
+0, 154, 154, 1, 864000, 0x8a4e24dd
+0, 155, 155, 1, 864000, 0xbbebf834
+0, 156, 156, 1, 864000, 0x0ba68a3b
+0, 157, 157, 1, 864000, 0x6390d66a
+0, 158, 158, 1, 864000, 0x6ee32da6
+0, 159, 159, 1, 864000, 0xace87229
+0, 160, 160, 1, 864000, 0xb2a10064
+0, 161, 161, 1, 864000, 0x9cc42dab
+0, 162, 162, 1, 864000, 0x32eb0f42
+0, 163, 163, 1, 864000, 0x6cb1fa03
+0, 164, 164, 1, 864000, 0xddd28c0a
+0, 165, 165, 1, 864000, 0xae5ca0cf
+0, 166, 166, 1, 864000, 0x4cb99ec8
+0, 167, 167, 1, 864000, 0xdad7d37e
+0, 168, 168, 1, 864000, 0x7090b71c
+0, 169, 169, 1, 864000, 0x7090b71c
+0, 170, 170, 1, 864000, 0x96a4c54d
+0, 171, 171, 1, 864000, 0x96a4c54d
+0, 172, 172, 1, 864000, 0x96a4c54d
+0, 173, 173, 1, 864000, 0xc47eb71c
+0, 174, 174, 1, 864000, 0xcd678c89
+0, 175, 175, 1, 864000, 0xb89e7843
+0, 176, 176, 1, 864000, 0x7f3aa2d6
+0, 177, 177, 1, 864000, 0xffc57e58
+0, 178, 178, 1, 864000, 0x091fa2d6
+0, 179, 179, 1, 864000, 0x3bc994a5
+0, 180, 180, 1, 864000, 0x73afacf9
+0, 181, 181, 1, 864000, 0x628b8266
+0, 182, 182, 1, 864000, 0xe2f2a4dd
+0, 183, 183, 1, 864000, 0x7118e9cb
+0, 184, 184, 1, 864000, 0x65b1438d
+0, 185, 185, 1, 864000, 0x51657ec8
+0, 186, 186, 1, 864000, 0x41a75435
+0, 187, 187, 1, 864000, 0xe387f665
+0, 188, 188, 1, 864000, 0x2baabb9a
+0, 189, 189, 1, 864000, 0xd2d74993
+0, 190, 190, 1, 864000, 0xd2d74993
+0, 191, 191, 1, 864000, 0xa7bf53b6
diff --git a/tests/ref/fate/vp60 b/tests/ref/fate/vp60
index 5e4b62c60f..c1da72ba17 100644
--- a/tests/ref/fate/vp60
+++ b/tests/ref/fate/vp60
@@ -6,8 +6,8 @@
0, 4, 4, 1, 55296, 0x17720594
0, 5, 5, 1, 55296, 0x49440805
0, 6, 6, 1, 55296, 0x5b2e0d32
-0, 7, 7, 1, 55296, 0x207891c1
-0, 8, 8, 1, 55296, 0x502da4cd
+0, 7, 7, 1, 55296, 0x5cf691c3
+0, 8, 8, 1, 55296, 0x61a5a4c8
0, 9, 9, 1, 55296, 0x75a22a75
0, 10, 10, 1, 55296, 0xd55099af
0, 11, 11, 1, 55296, 0x48778bb6
@@ -16,85 +16,85 @@
0, 14, 14, 1, 55296, 0xc83d9b90
0, 15, 15, 1, 55296, 0x567877b8
0, 16, 16, 1, 55296, 0x334c7f6e
-0, 17, 17, 1, 55296, 0x8717945c
-0, 18, 18, 1, 55296, 0xe432831e
-0, 19, 19, 1, 55296, 0x032e8d2d
+0, 17, 17, 1, 55296, 0x9317945c
+0, 18, 18, 1, 55296, 0xf032831e
+0, 19, 19, 1, 55296, 0x7b6c8d2c
0, 20, 20, 1, 55296, 0x37109fd6
0, 21, 21, 1, 55296, 0xe9b0b61b
0, 22, 22, 1, 55296, 0x7385dae8
-0, 23, 23, 1, 55296, 0x74b8a9f5
-0, 24, 24, 1, 55296, 0xbce2e218
-0, 25, 25, 1, 55296, 0x0ab6c623
-0, 26, 26, 1, 55296, 0x2234d6d6
-0, 27, 27, 1, 55296, 0xd18be4d6
-0, 28, 28, 1, 55296, 0x5247ecc9
-0, 29, 29, 1, 55296, 0xc89f10ca
-0, 30, 30, 1, 55296, 0x16181f87
-0, 31, 31, 1, 55296, 0x893bfa85
-0, 32, 32, 1, 55296, 0x1fd9f1c0
-0, 33, 33, 1, 55296, 0xa2e8e6a9
-0, 34, 34, 1, 55296, 0x1b42dfd5
-0, 35, 35, 1, 55296, 0x0fa9f509
-0, 36, 36, 1, 55296, 0x4449c216
-0, 37, 37, 1, 55296, 0xb66baa36
-0, 38, 38, 1, 55296, 0x38c19f3b
-0, 39, 39, 1, 55296, 0xcdce83a0
+0, 23, 23, 1, 55296, 0x74a8a9f5
+0, 24, 24, 1, 55296, 0xbcd2e218
+0, 25, 25, 1, 55296, 0x0aa6c623
+0, 26, 26, 1, 55296, 0x2224d6d6
+0, 27, 27, 1, 55296, 0x8c8ee4d9
+0, 28, 28, 1, 55296, 0x0d4ceccc
+0, 29, 29, 1, 55296, 0x623f10c7
+0, 30, 30, 1, 55296, 0x13a61f8f
+0, 31, 31, 1, 55296, 0x5343fa8d
+0, 32, 32, 1, 55296, 0x21fef1b5
+0, 33, 33, 1, 55296, 0x380de6b4
+0, 34, 34, 1, 55296, 0x04bedfd3
+0, 35, 35, 1, 55296, 0x428cf510
+0, 36, 36, 1, 55296, 0xbca8c214
+0, 37, 37, 1, 55296, 0x947faa34
+0, 38, 38, 1, 55296, 0x70769f45
+0, 39, 39, 1, 55296, 0xcb9483ad
0, 40, 40, 1, 55296, 0xac4ea82b
-0, 41, 41, 1, 55296, 0xb77a6979
-0, 42, 42, 1, 55296, 0xc8834ec2
-0, 43, 43, 1, 55296, 0x181d3f0f
-0, 44, 44, 1, 55296, 0x2ae04252
-0, 45, 45, 1, 55296, 0x07633c18
-0, 46, 46, 1, 55296, 0xdc6a3340
-0, 47, 47, 1, 55296, 0xa456ebb1
-0, 48, 48, 1, 55296, 0xbf7de5e2
-0, 49, 49, 1, 55296, 0x54a1c39b
-0, 50, 50, 1, 55296, 0x08fc9423
-0, 51, 51, 1, 55296, 0x926f968a
-0, 52, 52, 1, 55296, 0x5c908481
-0, 53, 53, 1, 55296, 0x6b257f16
-0, 54, 54, 1, 55296, 0xbaf8658a
-0, 55, 55, 1, 55296, 0x61c957b1
-0, 56, 56, 1, 55296, 0xa6d181ff
-0, 57, 57, 1, 55296, 0xef476e69
-0, 58, 58, 1, 55296, 0x74f72f9a
-0, 59, 59, 1, 55296, 0x3a9328e9
-0, 60, 60, 1, 55296, 0xbe962874
-0, 61, 61, 1, 55296, 0x5f8b58cc
-0, 62, 62, 1, 55296, 0x1e066d22
-0, 63, 63, 1, 55296, 0x9ef72b34
-0, 64, 64, 1, 55296, 0x525c2bb1
-0, 65, 65, 1, 55296, 0x8e5a20a3
-0, 66, 66, 1, 55296, 0x1c6723d0
-0, 67, 67, 1, 55296, 0x2b1023c8
-0, 68, 68, 1, 55296, 0x8f682691
-0, 69, 69, 1, 55296, 0x3a0624f5
+0, 41, 41, 1, 55296, 0xa3816977
+0, 42, 42, 1, 55296, 0xcfd54ec4
+0, 43, 43, 1, 55296, 0x97743f0e
+0, 44, 44, 1, 55296, 0x4cb4424d
+0, 45, 45, 1, 55296, 0x0b503c11
+0, 46, 46, 1, 55296, 0x879f333a
+0, 47, 47, 1, 55296, 0x6ff9eb8f
+0, 48, 48, 1, 55296, 0x7cd6e5af
+0, 49, 49, 1, 55296, 0x44e2c36f
+0, 50, 50, 1, 55296, 0x4e8993fb
+0, 51, 51, 1, 55296, 0xf0bb9664
+0, 52, 52, 1, 55296, 0xde608458
+0, 53, 53, 1, 55296, 0xb3017f01
+0, 54, 54, 1, 55296, 0x2e096579
+0, 55, 55, 1, 55296, 0xd7295790
+0, 56, 56, 1, 55296, 0xc40b81cb
+0, 57, 57, 1, 55296, 0x53a86e41
+0, 58, 58, 1, 55296, 0x74142f89
+0, 59, 59, 1, 55296, 0x2a1428ce
+0, 60, 60, 1, 55296, 0x5d0c2852
+0, 61, 61, 1, 55296, 0x162058a4
+0, 62, 62, 1, 55296, 0x4e8c6ce8
+0, 63, 63, 1, 55296, 0x1d382af2
+0, 64, 64, 1, 55296, 0x35dd2b75
+0, 65, 65, 1, 55296, 0x1e4c205f
+0, 66, 66, 1, 55296, 0x74a22383
+0, 67, 67, 1, 55296, 0x6ddb237d
+0, 68, 68, 1, 55296, 0xd290263b
+0, 69, 69, 1, 55296, 0xc778249f
0, 70, 70, 1, 55296, 0xbc1046fb
-0, 71, 71, 1, 55296, 0x2859470e
-0, 72, 72, 1, 55296, 0x61d45a12
-0, 73, 73, 1, 55296, 0xa68853b6
-0, 74, 74, 1, 55296, 0x36543ce4
-0, 75, 75, 1, 55296, 0x95b953d4
-0, 76, 76, 1, 55296, 0x804b3c53
-0, 77, 77, 1, 55296, 0x743960f6
-0, 78, 78, 1, 55296, 0x23916b9c
-0, 79, 79, 1, 55296, 0x8f5a59e3
-0, 80, 80, 1, 55296, 0xf1285f83
-0, 81, 81, 1, 55296, 0xde75640f
-0, 82, 82, 1, 55296, 0xde146188
-0, 83, 83, 1, 55296, 0xb5315cc9
+0, 71, 71, 1, 55296, 0xf44d470f
+0, 72, 72, 1, 55296, 0x28d85a11
+0, 73, 73, 1, 55296, 0xa68953b6
+0, 74, 74, 1, 55296, 0x02593ce5
+0, 75, 75, 1, 55296, 0x61be53d5
+0, 76, 76, 1, 55296, 0x4c503c54
+0, 77, 77, 1, 55296, 0x3d3e60f7
+0, 78, 78, 1, 55296, 0xec876b9d
+0, 79, 79, 1, 55296, 0x5b5f59e4
+0, 80, 80, 1, 55296, 0xbd2d5f84
+0, 81, 81, 1, 55296, 0xaa7a6410
+0, 82, 82, 1, 55296, 0xaa196189
+0, 83, 83, 1, 55296, 0x81365cca
0, 84, 84, 1, 55296, 0xa85f6861
-0, 85, 85, 1, 55296, 0x4fda562f
-0, 86, 86, 1, 55296, 0xa0185863
-0, 87, 87, 1, 55296, 0xe4dc5a5f
-0, 88, 88, 1, 55296, 0x8a2aabb6
-0, 89, 89, 1, 55296, 0x3ba89b4f
-0, 90, 90, 1, 55296, 0x82b07c21
-0, 91, 91, 1, 55296, 0xb7998478
-0, 92, 92, 1, 55296, 0xceca8046
-0, 93, 93, 1, 55296, 0xe652b325
-0, 94, 94, 1, 55296, 0xc26bb607
-0, 95, 95, 1, 55296, 0x40c99200
+0, 85, 85, 1, 55296, 0xcb46562e
+0, 86, 86, 1, 55296, 0x1b935862
+0, 87, 87, 1, 55296, 0x80a45a60
+0, 88, 88, 1, 55296, 0x8e8aabba
+0, 89, 89, 1, 55296, 0x38939b53
+0, 90, 90, 1, 55296, 0x4f397c22
+0, 91, 91, 1, 55296, 0x7d0d8476
+0, 92, 92, 1, 55296, 0x943e8044
+0, 93, 93, 1, 55296, 0xabc6b323
+0, 94, 94, 1, 55296, 0x87dfb605
+0, 95, 95, 1, 55296, 0x5ca89202
0, 96, 96, 1, 55296, 0x61bc9b27
0, 97, 97, 1, 55296, 0x1e4baa30
0, 98, 98, 1, 55296, 0xd8a7adb0
@@ -110,25 +110,25 @@
0, 108, 108, 1, 55296, 0xe208d626
0, 109, 109, 1, 55296, 0x28cc0616
0, 110, 110, 1, 55296, 0xc545179e
-0, 111, 111, 1, 55296, 0xdf9205af
-0, 112, 112, 1, 55296, 0x31d6ed99
-0, 113, 113, 1, 55296, 0x866bf86e
-0, 114, 114, 1, 55296, 0x0490fbd1
-0, 115, 115, 1, 55296, 0xe1102987
-0, 116, 116, 1, 55296, 0x7f860c29
-0, 117, 117, 1, 55296, 0xc3a91f7a
-0, 118, 118, 1, 55296, 0x69641a52
-0, 119, 119, 1, 55296, 0x05b12204
-0, 120, 120, 1, 55296, 0x715b6206
-0, 121, 121, 1, 55296, 0xdcf55139
-0, 122, 122, 1, 55296, 0x1369f746
+0, 111, 111, 1, 55296, 0xd38e05af
+0, 112, 112, 1, 55296, 0x25d6ed99
+0, 113, 113, 1, 55296, 0x7a6bf86e
+0, 114, 114, 1, 55296, 0xbb3bfbcd
+0, 115, 115, 1, 55296, 0x33de2984
+0, 116, 116, 1, 55296, 0xd5b10c27
+0, 117, 117, 1, 55296, 0x19e31f78
+0, 118, 118, 1, 55296, 0xf62f1a4f
+0, 119, 119, 1, 55296, 0x3f792203
+0, 120, 120, 1, 55296, 0xe4ed6202
+0, 121, 121, 1, 55296, 0xee265136
+0, 122, 122, 1, 55296, 0x408af73c
0, 123, 123, 1, 55296, 0xc1533ef5
-0, 124, 124, 1, 55296, 0xc00ff85f
-0, 125, 125, 1, 55296, 0x4f5f70dc
-0, 126, 126, 1, 55296, 0x85720ccc
-0, 127, 127, 1, 55296, 0xfdff0780
-0, 128, 128, 1, 55296, 0x57ef04ff
-0, 129, 129, 1, 55296, 0xbf94041f
-0, 130, 130, 1, 55296, 0x4cee0392
-0, 131, 131, 1, 55296, 0x80160314
-0, 132, 132, 1, 55296, 0x396802af
+0, 124, 124, 1, 55296, 0xf671f85d
+0, 125, 125, 1, 55296, 0xae2670e0
+0, 126, 126, 1, 55296, 0xe4390cd0
+0, 127, 127, 1, 55296, 0x5cd50784
+0, 128, 128, 1, 55296, 0x05880500
+0, 129, 129, 1, 55296, 0x6d2d0420
+0, 130, 130, 1, 55296, 0xfa780393
+0, 131, 131, 1, 55296, 0x2daf0315
+0, 132, 132, 1, 55296, 0x982f02b3
diff --git a/tests/ref/fate/vp6a b/tests/ref/fate/vp6a
index 6ce8486284..1f2ddd9859 100644
--- a/tests/ref/fate/vp6a
+++ b/tests/ref/fate/vp6a
@@ -1,94 +1,94 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 135000, 0x9dceed6d
-0, 249, 249, 0, 135000, 0xcb87787f
-0, 499, 499, 0, 135000, 0xdb4361ce
-0, 749, 749, 0, 135000, 0xb8fd81c2
-0, 1000, 1000, 0, 135000, 0xbf86a7af
-0, 1249, 1249, 0, 135000, 0x2e7787e3
-0, 1499, 1499, 0, 135000, 0x6cec6ebd
-0, 1749, 1749, 0, 135000, 0xa4d08c07
-0, 2000, 2000, 0, 135000, 0x1be48faf
-0, 2249, 2249, 0, 135000, 0xf3cd8ede
-0, 2499, 2499, 0, 135000, 0x33ec8a49
-0, 2749, 2749, 0, 135000, 0x11e887ec
-0, 3000, 3000, 0, 135000, 0x3e215c25
-0, 3249, 3249, 0, 135000, 0x1a2cb3f8
-0, 3499, 3499, 0, 135000, 0x7fb0e48a
-0, 3749, 3749, 0, 135000, 0x749f3738
-0, 4000, 4000, 0, 135000, 0x686e78e9
-0, 4249, 4249, 0, 135000, 0x29515bc7
-0, 4499, 4499, 0, 135000, 0x987126bd
-0, 4749, 4749, 0, 135000, 0xdf77bb13
-0, 5000, 5000, 0, 135000, 0x5fb1468a
-0, 5249, 5249, 0, 135000, 0x06ea50ea
-0, 5499, 5499, 0, 135000, 0x7bd9c715
-0, 5749, 5749, 0, 135000, 0xdd6e6831
-0, 6000, 6000, 0, 135000, 0x0ee3760f
-0, 6249, 6249, 0, 135000, 0xc7984dc8
-0, 6499, 6499, 0, 135000, 0x7e385bff
-0, 6749, 6749, 0, 135000, 0xae155ab9
-0, 7000, 7000, 0, 135000, 0xc05ee8f7
-0, 7249, 7249, 0, 135000, 0x93de3392
-0, 7499, 7499, 0, 135000, 0xfe45b38b
-0, 7749, 7749, 0, 135000, 0xeb5ed72c
-0, 8000, 8000, 0, 135000, 0x0794cb57
-0, 8249, 8249, 0, 135000, 0x2578c6e5
-0, 8499, 8499, 0, 135000, 0x78486707
-0, 8749, 8749, 0, 135000, 0x41e1f0e6
-0, 9000, 9000, 0, 135000, 0x4508eb76
-0, 9249, 9249, 0, 135000, 0xd8c087f3
-0, 9499, 9499, 0, 135000, 0x1a8db89a
-0, 9749, 9749, 0, 135000, 0x6dbd90c6
-0, 10000, 10000, 0, 135000, 0x0845e400
-0, 10249, 10249, 0, 135000, 0xe8b02fc2
-0, 10499, 10499, 0, 135000, 0x8007d813
-0, 10749, 10749, 0, 135000, 0xdfb04e69
-0, 11000, 11000, 0, 135000, 0x5746cf71
-0, 11249, 11249, 0, 135000, 0xe510299f
-0, 11499, 11499, 0, 135000, 0xeea0c829
-0, 11749, 11749, 0, 135000, 0x7c0578ab
-0, 12000, 12000, 0, 135000, 0xb1569ce9
-0, 12249, 12249, 0, 135000, 0x6c233986
-0, 12499, 12499, 0, 135000, 0x95b77f3d
-0, 12749, 12749, 0, 135000, 0xfc368d80
-0, 13000, 13000, 0, 135000, 0x5c73b064
-0, 13249, 13249, 0, 135000, 0x2206da8d
-0, 13499, 13499, 0, 135000, 0x62bb599e
-0, 13749, 13749, 0, 135000, 0x15a68991
-0, 14000, 14000, 0, 135000, 0x5f5eb810
-0, 14249, 14249, 0, 135000, 0x85a9634a
-0, 14499, 14499, 0, 135000, 0xf24b5c1a
-0, 14749, 14749, 0, 135000, 0x38034850
-0, 15000, 15000, 0, 135000, 0x48fd3599
-0, 15249, 15249, 0, 135000, 0xb9d62408
-0, 15499, 15499, 0, 135000, 0xaf202a21
-0, 15749, 15749, 0, 135000, 0x341aa582
-0, 16000, 16000, 0, 135000, 0x90cdc9bb
-0, 16249, 16249, 0, 135000, 0x0b52f319
-0, 16499, 16499, 0, 135000, 0xce61aa5e
-0, 16749, 16749, 0, 135000, 0x988acb45
-0, 17000, 17000, 0, 135000, 0xcd353664
-0, 17249, 17249, 0, 135000, 0xa80c8ce9
-0, 17499, 17499, 0, 135000, 0x15dce784
-0, 17749, 17749, 0, 135000, 0x16bd4519
-0, 18000, 18000, 0, 135000, 0x571712f3
-0, 18249, 18249, 0, 135000, 0x6b109f1e
-0, 18499, 18499, 0, 135000, 0x8e4c19aa
-0, 18749, 18749, 0, 135000, 0x4132bd4c
-0, 19000, 19000, 0, 135000, 0x5babafe2
-0, 19249, 19249, 0, 135000, 0xddef6313
-0, 19499, 19499, 0, 135000, 0x76d6b48b
-0, 19749, 19749, 0, 135000, 0x929e7702
-0, 20000, 20000, 0, 135000, 0x33f5e4a1
-0, 20249, 20249, 0, 135000, 0xdb7041bf
-0, 20499, 20499, 0, 135000, 0xbc761e04
-0, 20749, 20749, 0, 135000, 0x0b2a81e6
-0, 21000, 21000, 0, 135000, 0xf6fd20ea
-0, 21249, 21249, 0, 135000, 0x1894a26c
-0, 21499, 21499, 0, 135000, 0xb25e216f
-0, 21749, 21749, 0, 135000, 0x83bb02ee
-0, 22000, 22000, 0, 135000, 0x6952a3c3
-0, 22249, 22249, 0, 135000, 0x372184d6
-0, 22499, 22499, 0, 135000, 0x2ac47afe
-0, 22749, 22749, 0, 135000, 0x14c33a35
-0, 23000, 23000, 0, 135000, 0xdc08470e
+#tb 0: 1/4
+0, 0, 0, 1, 135000, 0x9dceed6d
+0, 1, 1, 1, 135000, 0x47e5778d
+0, 2, 2, 1, 135000, 0x5de36599
+0, 3, 3, 1, 135000, 0x540d8079
+0, 4, 4, 1, 135000, 0xba9ea534
+0, 5, 5, 1, 135000, 0xa75088f8
+0, 6, 6, 1, 135000, 0x7d867559
+0, 7, 7, 1, 135000, 0xcc678fee
+0, 8, 8, 1, 135000, 0x79c590b9
+0, 9, 9, 1, 135000, 0x87789918
+0, 10, 10, 1, 135000, 0xaa939213
+0, 11, 11, 1, 135000, 0x3912916d
+0, 12, 12, 1, 135000, 0x41305d0b
+0, 13, 13, 1, 135000, 0x2686b5dd
+0, 14, 14, 1, 135000, 0xa69ae422
+0, 15, 15, 1, 135000, 0x998a3478
+0, 16, 16, 1, 135000, 0x5842768d
+0, 17, 17, 1, 135000, 0xf6a85b16
+0, 18, 18, 1, 135000, 0x7a5b2708
+0, 19, 19, 1, 135000, 0x8b2abb63
+0, 20, 20, 1, 135000, 0x7dc8468b
+0, 21, 21, 1, 135000, 0x04d85001
+0, 22, 22, 1, 135000, 0x83e3c647
+0, 23, 23, 1, 135000, 0xcddd687e
+0, 24, 24, 1, 135000, 0x818e785e
+0, 25, 25, 1, 135000, 0x3a915080
+0, 26, 26, 1, 135000, 0x953d603d
+0, 27, 27, 1, 135000, 0x79005ebf
+0, 28, 28, 1, 135000, 0x80afec75
+0, 29, 29, 1, 135000, 0xfc8e376b
+0, 30, 30, 1, 135000, 0xf957b7ef
+0, 31, 31, 1, 135000, 0xe878da44
+0, 32, 32, 1, 135000, 0xe68ecca3
+0, 33, 33, 1, 135000, 0x1a2cc7d3
+0, 34, 34, 1, 135000, 0x4f346a69
+0, 35, 35, 1, 135000, 0x7a0cf4ac
+0, 36, 36, 1, 135000, 0x6d4eee7a
+0, 37, 37, 1, 135000, 0xf0688cbd
+0, 38, 38, 1, 135000, 0xca4abbbc
+0, 39, 39, 1, 135000, 0x87669519
+0, 40, 40, 1, 135000, 0xd090e9d7
+0, 41, 41, 1, 135000, 0xd7f536c1
+0, 42, 42, 1, 135000, 0x353ede54
+0, 43, 43, 1, 135000, 0xbc8f5358
+0, 44, 44, 1, 135000, 0xb52cd59a
+0, 45, 45, 1, 135000, 0x0b882eba
+0, 46, 46, 1, 135000, 0xc544cd54
+0, 47, 47, 1, 135000, 0x31ca7e73
+0, 48, 48, 1, 135000, 0xb1569ce9
+0, 49, 49, 1, 135000, 0x8bf4394f
+0, 50, 50, 1, 135000, 0xf413812a
+0, 51, 51, 1, 135000, 0xf2fa90ab
+0, 52, 52, 1, 135000, 0xdcd8b265
+0, 53, 53, 1, 135000, 0xa89cdba1
+0, 54, 54, 1, 135000, 0x212b59a5
+0, 55, 55, 1, 135000, 0x10c589c3
+0, 56, 56, 1, 135000, 0x432ab5b4
+0, 57, 57, 1, 135000, 0x85a9634a
+0, 58, 58, 1, 135000, 0x10db5b87
+0, 59, 59, 1, 135000, 0x583145d9
+0, 60, 60, 1, 135000, 0x7d3a33bd
+0, 61, 61, 1, 135000, 0xcf592423
+0, 62, 62, 1, 135000, 0xb59728e5
+0, 63, 63, 1, 135000, 0x1eeca660
+0, 64, 64, 1, 135000, 0xff7bcc34
+0, 65, 65, 1, 135000, 0x0ef8f271
+0, 66, 66, 1, 135000, 0x8c9ca8ee
+0, 67, 67, 1, 135000, 0x8a7ece34
+0, 68, 68, 1, 135000, 0x7d4c3b5d
+0, 69, 69, 1, 135000, 0x99118f21
+0, 70, 70, 1, 135000, 0xd97fe7e2
+0, 71, 71, 1, 135000, 0xf93842f1
+0, 72, 72, 1, 135000, 0x35c912e8
+0, 73, 73, 1, 135000, 0x14e59e97
+0, 74, 74, 1, 135000, 0x8e4c19aa
+0, 75, 75, 1, 135000, 0x4adfbc53
+0, 76, 76, 1, 135000, 0x0613adde
+0, 77, 77, 1, 135000, 0x8db264ab
+0, 78, 78, 1, 135000, 0x3948b619
+0, 79, 79, 1, 135000, 0x843d7c02
+0, 80, 80, 1, 135000, 0x534fea34
+0, 81, 81, 1, 135000, 0xdb7041bf
+0, 82, 82, 1, 135000, 0xd0ce1cce
+0, 83, 83, 1, 135000, 0x3c008335
+0, 84, 84, 1, 135000, 0xb699208f
+0, 85, 85, 1, 135000, 0xe07da3ca
+0, 86, 86, 1, 135000, 0x26331f41
+0, 87, 87, 1, 135000, 0x4e19fe83
+0, 88, 88, 1, 135000, 0xaa9a9e45
+0, 89, 89, 1, 135000, 0x336b7ed0
+0, 90, 90, 1, 135000, 0xc9bf7611
+0, 91, 91, 1, 135000, 0x14c33a35
+0, 92, 92, 1, 135000, 0xdc08470e
diff --git a/tests/ref/fate/vp6a-skip_alpha b/tests/ref/fate/vp6a-skip_alpha
new file mode 100644
index 0000000000..91a099c58b
--- /dev/null
+++ b/tests/ref/fate/vp6a-skip_alpha
@@ -0,0 +1,94 @@
+#tb 0: 1/4
+0, 0, 0, 1, 81000, 0xcb92962d
+0, 1, 1, 1, 81000, 0xae381904
+0, 2, 2, 1, 81000, 0x1fcc0c75
+0, 3, 3, 1, 81000, 0x023f0c21
+0, 4, 4, 1, 81000, 0xad691402
+0, 5, 5, 1, 81000, 0x42390be0
+0, 6, 6, 1, 81000, 0xc1c10a4e
+0, 7, 7, 1, 81000, 0x9c0315ac
+0, 8, 8, 1, 81000, 0xc2a315a7
+0, 9, 9, 1, 81000, 0x3a631392
+0, 10, 10, 1, 81000, 0x11591414
+0, 11, 11, 1, 81000, 0x1a551125
+0, 12, 12, 1, 81000, 0x2e1efa4f
+0, 13, 13, 1, 81000, 0x4aa3f016
+0, 14, 14, 1, 81000, 0x74c029d8
+0, 15, 15, 1, 81000, 0xdee9a98b
+0, 16, 16, 1, 81000, 0xdf3502d5
+0, 17, 17, 1, 81000, 0x4653536b
+0, 18, 18, 1, 81000, 0x7f658c75
+0, 19, 19, 1, 81000, 0xab18ff13
+0, 20, 20, 1, 81000, 0xac2b8f3b
+0, 21, 21, 1, 81000, 0xd61ff094
+0, 22, 22, 1, 81000, 0x425bfc2b
+0, 23, 23, 1, 81000, 0x6be7ecd3
+0, 24, 24, 1, 81000, 0x0b0ee65b
+0, 25, 25, 1, 81000, 0x3c6f146b
+0, 26, 26, 1, 81000, 0x27c4e9c8
+0, 27, 27, 1, 81000, 0x174022c4
+0, 28, 28, 1, 81000, 0x3320fe81
+0, 29, 29, 1, 81000, 0x7a3c342e
+0, 30, 30, 1, 81000, 0x448b4346
+0, 31, 31, 1, 81000, 0xd285b23d
+0, 32, 32, 1, 81000, 0x852ed590
+0, 33, 33, 1, 81000, 0xc9d3df17
+0, 34, 34, 1, 81000, 0x4d23727b
+0, 35, 35, 1, 81000, 0x1fae66cd
+0, 36, 36, 1, 81000, 0x384d54ab
+0, 37, 37, 1, 81000, 0x2fee6ba3
+0, 38, 38, 1, 81000, 0xd7ad6f59
+0, 39, 39, 1, 81000, 0xaf5e3e76
+0, 40, 40, 1, 81000, 0x10fceda4
+0, 41, 41, 1, 81000, 0xb26df92b
+0, 42, 42, 1, 81000, 0xd6676e08
+0, 43, 43, 1, 81000, 0xff6b1b95
+0, 44, 44, 1, 81000, 0x6196d598
+0, 45, 45, 1, 81000, 0x833ebf1b
+0, 46, 46, 1, 81000, 0x7b085af1
+0, 47, 47, 1, 81000, 0xe8f583b4
+0, 48, 48, 1, 81000, 0x3426d5e4
+0, 49, 49, 1, 81000, 0x214069ed
+0, 50, 50, 1, 81000, 0x7dbdfd3f
+0, 51, 51, 1, 81000, 0xf19b3f45
+0, 52, 52, 1, 81000, 0x0f05c7e2
+0, 53, 53, 1, 81000, 0xba94e323
+0, 54, 54, 1, 81000, 0x0de7b0c2
+0, 55, 55, 1, 81000, 0xfcf93c55
+0, 56, 56, 1, 81000, 0x8a8dbd55
+0, 57, 57, 1, 81000, 0xddf22b97
+0, 58, 58, 1, 81000, 0x49a830ff
+0, 59, 59, 1, 81000, 0x82ab2a4b
+0, 60, 60, 1, 81000, 0xd23420e5
+0, 61, 61, 1, 81000, 0x7c1017d1
+0, 62, 62, 1, 81000, 0x9aa61b38
+0, 63, 63, 1, 81000, 0x2a724a18
+0, 64, 64, 1, 81000, 0xc18055f2
+0, 65, 65, 1, 81000, 0xecba3855
+0, 66, 66, 1, 81000, 0x0eed6b0f
+0, 67, 67, 1, 81000, 0x4be73816
+0, 68, 68, 1, 81000, 0xa681214e
+0, 69, 69, 1, 81000, 0x4958f83d
+0, 70, 70, 1, 81000, 0xca0f0d61
+0, 71, 71, 1, 81000, 0x3c453de1
+0, 72, 72, 1, 81000, 0xff60360a
+0, 73, 73, 1, 81000, 0xdcef0949
+0, 74, 74, 1, 81000, 0xe5e3732d
+0, 75, 75, 1, 81000, 0x39747fd4
+0, 76, 76, 1, 81000, 0x6bec70e6
+0, 77, 77, 1, 81000, 0x7026a8c0
+0, 78, 78, 1, 81000, 0x92de5b61
+0, 79, 79, 1, 81000, 0x3f00507f
+0, 80, 80, 1, 81000, 0x5620c377
+0, 81, 81, 1, 81000, 0x39f5ed38
+0, 82, 82, 1, 81000, 0x6ee35d67
+0, 83, 83, 1, 81000, 0x4f99a409
+0, 84, 84, 1, 81000, 0x0a05b6ea
+0, 85, 85, 1, 81000, 0xd6c442d9
+0, 86, 86, 1, 81000, 0x0bb3d2f0
+0, 87, 87, 1, 81000, 0x6891c5b1
+0, 88, 88, 1, 81000, 0xf16ba9be
+0, 89, 89, 1, 81000, 0xba53528e
+0, 90, 90, 1, 81000, 0xc847de49
+0, 91, 91, 1, 81000, 0xc5b2e2b0
+0, 92, 92, 1, 81000, 0xb0b497ff
diff --git a/tests/ref/fate/vp6f b/tests/ref/fate/vp6f
index 87950425b0..edb555dc63 100644
--- a/tests/ref/fate/vp6f
+++ b/tests/ref/fate/vp6f
@@ -1,175 +1,175 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 13440, 0x7cb0a22f
-0, 100, 100, 0, 13440, 0xdfcea6ba
-0, 200, 200, 0, 13440, 0x59b2a5da
-0, 300, 300, 0, 13440, 0x12f1b2d8
-0, 400, 400, 0, 13440, 0x280fb9f6
-0, 500, 500, 0, 13440, 0x7bace8b3
-0, 600, 600, 0, 13440, 0x4ec91480
-0, 700, 700, 0, 13440, 0xa8010450
-0, 800, 800, 0, 13440, 0x61d8fc46
-0, 900, 900, 0, 13440, 0x242bb24e
-0, 1000, 1000, 0, 13440, 0x88397a36
-0, 1100, 1100, 0, 13440, 0x10e15726
-0, 1200, 1200, 0, 13440, 0x3018438c
-0, 1300, 1300, 0, 13440, 0xbbb94c21
-0, 1400, 1400, 0, 13440, 0xfc3e5e2b
-0, 1500, 1500, 0, 13440, 0xeaa69354
-0, 1600, 1600, 0, 13440, 0x96f1cc01
-0, 1700, 1700, 0, 13440, 0x333fdaff
-0, 1800, 1800, 0, 13440, 0xb5230ed2
-0, 1900, 1900, 0, 13440, 0x59383446
-0, 2000, 2000, 0, 13440, 0x954939e6
-0, 2100, 2100, 0, 13440, 0x53813d2f
-0, 2200, 2200, 0, 13440, 0x3ca53600
-0, 2300, 2300, 0, 13440, 0x7b30227a
-0, 2400, 2400, 0, 13440, 0x5145bbfe
-0, 2500, 2500, 0, 13440, 0xa0979632
-0, 2600, 2600, 0, 13440, 0x08026e21
-0, 2700, 2700, 0, 13440, 0x3f456d1e
-0, 2800, 2800, 0, 13440, 0x7d036b62
-0, 2900, 2900, 0, 13440, 0x508085fb
-0, 3000, 3000, 0, 13440, 0x251dc193
-0, 3100, 3100, 0, 13440, 0xf3121c9b
-0, 3200, 3200, 0, 13440, 0xf5da772e
-0, 3300, 3300, 0, 13440, 0x8179ccf7
-0, 3400, 3400, 0, 13440, 0xd57ceeb3
-0, 3500, 3500, 0, 13440, 0xc8f2169c
-0, 3600, 3600, 0, 13440, 0xbf8296c3
-0, 3700, 3700, 0, 13440, 0xee1927d0
-0, 3800, 3800, 0, 13440, 0xdd84e8d1
-0, 3900, 3900, 0, 13440, 0x7be57be2
-0, 4000, 4000, 0, 13440, 0xae353f91
-0, 4100, 4100, 0, 13440, 0x3ae927f2
-0, 4200, 4200, 0, 13440, 0x417227c6
-0, 4300, 4300, 0, 13440, 0x32572bea
-0, 4400, 4400, 0, 13440, 0x8b9e4839
-0, 4500, 4500, 0, 13440, 0xad669441
-0, 4600, 4600, 0, 13440, 0xc9de99a6
-0, 4700, 4700, 0, 13440, 0xb3ffb88b
-0, 4800, 4800, 0, 13440, 0xb321b8a0
-0, 4900, 4900, 0, 13440, 0x2efdbf53
-0, 5000, 5000, 0, 13440, 0x9b7aa566
-0, 5100, 5100, 0, 13440, 0x563c8d60
-0, 5200, 5200, 0, 13440, 0xe3848ee8
-0, 5300, 5300, 0, 13440, 0xa84b8f1d
-0, 5400, 5400, 0, 13440, 0x52da9f9f
-0, 5500, 5500, 0, 13440, 0x2ed56d97
-0, 5600, 5600, 0, 13440, 0x4e8534c2
-0, 5700, 5700, 0, 13440, 0x318900a6
-0, 5800, 5800, 0, 13440, 0xda96de39
-0, 5900, 5900, 0, 13440, 0xaae7ac0b
-0, 6000, 6000, 0, 13440, 0x7533ad99
-0, 6100, 6100, 0, 13440, 0x4e70c2c9
-0, 6200, 6200, 0, 13440, 0x9ce5e3fa
-0, 6300, 6300, 0, 13440, 0xc788fbbc
-0, 6400, 6400, 0, 13440, 0xd36604a9
-0, 6500, 6500, 0, 13440, 0x246221a4
-0, 6600, 6600, 0, 13440, 0x290c5c2b
-0, 6700, 6700, 0, 13440, 0xde6c68ec
-0, 6800, 6800, 0, 13440, 0x56248dbf
-0, 6900, 6900, 0, 13440, 0x5b898cbd
-0, 7000, 7000, 0, 13440, 0x090574b9
-0, 7100, 7100, 0, 13440, 0x8df2814a
-0, 7200, 7200, 0, 13440, 0xd4a6b285
-0, 7300, 7300, 0, 13440, 0xa016e921
-0, 7400, 7400, 0, 13440, 0x7f93fdc1
-0, 7500, 7500, 0, 13440, 0xfd0dee6f
-0, 7600, 7600, 0, 13440, 0xef04ce0e
-0, 7700, 7700, 0, 13440, 0x7560bee3
-0, 7800, 7800, 0, 13440, 0x5a8cdc85
-0, 7900, 7900, 0, 13440, 0x4788f7bc
-0, 8000, 8000, 0, 13440, 0xc001e34d
-0, 8100, 8100, 0, 13440, 0xc687eb74
-0, 8200, 8200, 0, 13440, 0xbf20feba
-0, 8300, 8300, 0, 13440, 0xd32647a8
-0, 8400, 8400, 0, 13440, 0xe69a955a
-0, 8500, 8500, 0, 13440, 0x1b56951f
-0, 8600, 8600, 0, 13440, 0xd1977378
-0, 8700, 8700, 0, 13440, 0x1620357d
-0, 8800, 8800, 0, 13440, 0x2596116f
-0, 8900, 8900, 0, 13440, 0x7473feca
-0, 9000, 9000, 0, 13440, 0x7f92bb47
-0, 9100, 9100, 0, 13440, 0x6866a683
-0, 9200, 9200, 0, 13440, 0xe9b08d7e
-0, 9300, 9300, 0, 13440, 0xa3fd7546
-0, 9400, 9400, 0, 13440, 0xa4416522
-0, 9500, 9500, 0, 13440, 0xd8f5572e
-0, 9600, 9600, 0, 13440, 0xf5746dbd
-0, 9700, 9700, 0, 13440, 0x256a87c6
-0, 9800, 9800, 0, 13440, 0x722aa2c8
-0, 9900, 9900, 0, 13440, 0xb26de5f5
-0, 10000, 10000, 0, 13440, 0x117f0841
-0, 10100, 10100, 0, 13440, 0xda2d192c
-0, 10200, 10200, 0, 13440, 0xb022442d
-0, 10300, 10300, 0, 13440, 0xbc4044f2
-0, 10400, 10400, 0, 13440, 0x68b330da
-0, 10500, 10500, 0, 13440, 0xc07228cf
-0, 10600, 10600, 0, 13440, 0xaa3f3d44
-0, 10700, 10700, 0, 13440, 0x25867aad
-0, 10800, 10800, 0, 13440, 0xa3ecb432
-0, 10900, 10900, 0, 13440, 0x93ccdcbb
-0, 11000, 11000, 0, 13440, 0x8302fa4f
-0, 11100, 11100, 0, 13440, 0x2f960f33
-0, 11200, 11200, 0, 13440, 0x15d41d14
-0, 11300, 11300, 0, 13440, 0x636529d0
-0, 11400, 11400, 0, 13440, 0x11035be5
-0, 11500, 11500, 0, 13440, 0x9b6e9167
-0, 11600, 11600, 0, 13440, 0x7b01adc7
-0, 11700, 11700, 0, 13440, 0xa237e05d
-0, 11800, 11800, 0, 13440, 0xd2f4f134
-0, 11900, 11900, 0, 13440, 0x2052d368
-0, 12000, 12000, 0, 13440, 0x08f7ae0d
-0, 12100, 12100, 0, 13440, 0xa89185bc
-0, 12200, 12200, 0, 13440, 0xfa628236
-0, 12300, 12300, 0, 13440, 0xdf79848b
-0, 12400, 12400, 0, 13440, 0xd19a906f
-0, 12500, 12500, 0, 13440, 0x219f9324
-0, 12600, 12600, 0, 13440, 0x46509b6d
-0, 12700, 12700, 0, 13440, 0xc5d9a568
-0, 12800, 12800, 0, 13440, 0xb21aaaa8
-0, 12900, 12900, 0, 13440, 0x925a97ed
-0, 13000, 13000, 0, 13440, 0xc5e3557f
-0, 13100, 13100, 0, 13440, 0x7c57155a
-0, 13200, 13200, 0, 13440, 0x6b26d005
-0, 13300, 13300, 0, 13440, 0xfdc7b369
-0, 13400, 13400, 0, 13440, 0x99919fc2
-0, 13500, 13500, 0, 13440, 0xcfe889e4
-0, 13600, 13600, 0, 13440, 0xd1196856
-0, 13700, 13700, 0, 13440, 0xec8348c6
-0, 13800, 13800, 0, 13440, 0x5ede0d9a
-0, 13900, 13900, 0, 13440, 0x198ef66e
-0, 14000, 14000, 0, 13440, 0x62fcefdf
-0, 14100, 14100, 0, 13440, 0x7791f415
-0, 14200, 14200, 0, 13440, 0xfbdb0029
-0, 14300, 14300, 0, 13440, 0xdab12b01
-0, 14400, 14400, 0, 13440, 0x646b2d5f
-0, 14500, 14500, 0, 13440, 0x5410f52e
-0, 14600, 14600, 0, 13440, 0x7186eef8
-0, 14700, 14700, 0, 13440, 0xca251ef6
-0, 14800, 14800, 0, 13440, 0x757c3b43
-0, 14900, 14900, 0, 13440, 0x59ff4982
-0, 15000, 15000, 0, 13440, 0xbe8ff084
-0, 15100, 15100, 0, 13440, 0xc85a9e38
-0, 15200, 15200, 0, 13440, 0x541b9a19
-0, 15300, 15300, 0, 13440, 0x274893c9
-0, 15400, 15400, 0, 13440, 0x7634b5d2
-0, 15500, 15500, 0, 13440, 0x1bd8e10c
-0, 15600, 15600, 0, 13440, 0xa661dfb1
-0, 15700, 15700, 0, 13440, 0x9d01bf92
-0, 15800, 15800, 0, 13440, 0xcb1eb220
-0, 15900, 15900, 0, 13440, 0x0ce27d25
-0, 16000, 16000, 0, 13440, 0x523b594f
-0, 16100, 16100, 0, 13440, 0xf0a04c4f
-0, 16200, 16200, 0, 13440, 0x0f0ffc3d
-0, 16300, 16300, 0, 13440, 0xb0d8b778
-0, 16400, 16400, 0, 13440, 0x5137a642
-0, 16500, 16500, 0, 13440, 0xd213a552
-0, 16600, 16600, 0, 13440, 0xc2fbc9b1
-0, 16700, 16700, 0, 13440, 0xfc2ee379
-0, 16800, 16800, 0, 13440, 0xfb80f737
-0, 16900, 16900, 0, 13440, 0xd6cb2447
-0, 17000, 17000, 0, 13440, 0x124b606d
-0, 17100, 17100, 0, 13440, 0xf788a066
-0, 17200, 17200, 0, 13440, 0xa16eed6e
-0, 17300, 17300, 0, 13440, 0x73ff0f82
+#tb 0: 1/10
+0, 0, 0, 1, 13440, 0x7cb0a22f
+0, 1, 1, 1, 13440, 0xdfcea6ba
+0, 2, 2, 1, 13440, 0x59b2a5da
+0, 3, 3, 1, 13440, 0x12f1b2d8
+0, 4, 4, 1, 13440, 0x280fb9f6
+0, 5, 5, 1, 13440, 0x7bace8b3
+0, 6, 6, 1, 13440, 0x4ec91480
+0, 7, 7, 1, 13440, 0xa8010450
+0, 8, 8, 1, 13440, 0x61d8fc46
+0, 9, 9, 1, 13440, 0x242bb24e
+0, 10, 10, 1, 13440, 0x88397a36
+0, 11, 11, 1, 13440, 0x10e15726
+0, 12, 12, 1, 13440, 0x3018438c
+0, 13, 13, 1, 13440, 0xbbb94c21
+0, 14, 14, 1, 13440, 0xfc3e5e2b
+0, 15, 15, 1, 13440, 0xeaa69354
+0, 16, 16, 1, 13440, 0x96f1cc01
+0, 17, 17, 1, 13440, 0x333fdaff
+0, 18, 18, 1, 13440, 0xb5230ed2
+0, 19, 19, 1, 13440, 0x59383446
+0, 20, 20, 1, 13440, 0x954939e6
+0, 21, 21, 1, 13440, 0x53813d2f
+0, 22, 22, 1, 13440, 0x3ca53600
+0, 23, 23, 1, 13440, 0x7b30227a
+0, 24, 24, 1, 13440, 0x5145bbfe
+0, 25, 25, 1, 13440, 0xa0979632
+0, 26, 26, 1, 13440, 0x08026e21
+0, 27, 27, 1, 13440, 0x3f456d1e
+0, 28, 28, 1, 13440, 0x7d036b62
+0, 29, 29, 1, 13440, 0x508085fb
+0, 30, 30, 1, 13440, 0x251dc193
+0, 31, 31, 1, 13440, 0xf3121c9b
+0, 32, 32, 1, 13440, 0xf5da772e
+0, 33, 33, 1, 13440, 0x8179ccf7
+0, 34, 34, 1, 13440, 0xd57ceeb3
+0, 35, 35, 1, 13440, 0xc8f2169c
+0, 36, 36, 1, 13440, 0xbf8296c3
+0, 37, 37, 1, 13440, 0xee1927d0
+0, 38, 38, 1, 13440, 0xdd84e8d1
+0, 39, 39, 1, 13440, 0x7be57be2
+0, 40, 40, 1, 13440, 0xae353f91
+0, 41, 41, 1, 13440, 0x3ae927f2
+0, 42, 42, 1, 13440, 0x417227c6
+0, 43, 43, 1, 13440, 0x32572bea
+0, 44, 44, 1, 13440, 0x8b9e4839
+0, 45, 45, 1, 13440, 0xad669441
+0, 46, 46, 1, 13440, 0xc9de99a6
+0, 47, 47, 1, 13440, 0xb3ffb88b
+0, 48, 48, 1, 13440, 0xb321b8a0
+0, 49, 49, 1, 13440, 0x2efdbf53
+0, 50, 50, 1, 13440, 0x9b7aa566
+0, 51, 51, 1, 13440, 0x563c8d60
+0, 52, 52, 1, 13440, 0xe3848ee8
+0, 53, 53, 1, 13440, 0xa84b8f1d
+0, 54, 54, 1, 13440, 0x52da9f9f
+0, 55, 55, 1, 13440, 0x2ed56d97
+0, 56, 56, 1, 13440, 0x4e8534c2
+0, 57, 57, 1, 13440, 0x318900a6
+0, 58, 58, 1, 13440, 0xda96de39
+0, 59, 59, 1, 13440, 0xaae7ac0b
+0, 60, 60, 1, 13440, 0x7533ad99
+0, 61, 61, 1, 13440, 0x4e70c2c9
+0, 62, 62, 1, 13440, 0x9ce5e3fa
+0, 63, 63, 1, 13440, 0xc788fbbc
+0, 64, 64, 1, 13440, 0xd36604a9
+0, 65, 65, 1, 13440, 0x246221a4
+0, 66, 66, 1, 13440, 0x290c5c2b
+0, 67, 67, 1, 13440, 0xde6c68ec
+0, 68, 68, 1, 13440, 0x56248dbf
+0, 69, 69, 1, 13440, 0x5b898cbd
+0, 70, 70, 1, 13440, 0x090574b9
+0, 71, 71, 1, 13440, 0x8df2814a
+0, 72, 72, 1, 13440, 0xd4a6b285
+0, 73, 73, 1, 13440, 0xa016e921
+0, 74, 74, 1, 13440, 0x7f93fdc1
+0, 75, 75, 1, 13440, 0xfd0dee6f
+0, 76, 76, 1, 13440, 0xef04ce0e
+0, 77, 77, 1, 13440, 0x7560bee3
+0, 78, 78, 1, 13440, 0x5a8cdc85
+0, 79, 79, 1, 13440, 0x4788f7bc
+0, 80, 80, 1, 13440, 0xc001e34d
+0, 81, 81, 1, 13440, 0xc687eb74
+0, 82, 82, 1, 13440, 0xbf20feba
+0, 83, 83, 1, 13440, 0xd32647a8
+0, 84, 84, 1, 13440, 0xe69a955a
+0, 85, 85, 1, 13440, 0x1b56951f
+0, 86, 86, 1, 13440, 0xd1977378
+0, 87, 87, 1, 13440, 0x1620357d
+0, 88, 88, 1, 13440, 0x2596116f
+0, 89, 89, 1, 13440, 0x7473feca
+0, 90, 90, 1, 13440, 0x7f92bb47
+0, 91, 91, 1, 13440, 0x6866a683
+0, 92, 92, 1, 13440, 0xe9b08d7e
+0, 93, 93, 1, 13440, 0xa3fd7546
+0, 94, 94, 1, 13440, 0xa4416522
+0, 95, 95, 1, 13440, 0xd8f5572e
+0, 96, 96, 1, 13440, 0xf5746dbd
+0, 97, 97, 1, 13440, 0x256a87c6
+0, 98, 98, 1, 13440, 0x722aa2c8
+0, 99, 99, 1, 13440, 0xb26de5f5
+0, 100, 100, 1, 13440, 0x117f0841
+0, 101, 101, 1, 13440, 0xda2d192c
+0, 102, 102, 1, 13440, 0xb022442d
+0, 103, 103, 1, 13440, 0xbc4044f2
+0, 104, 104, 1, 13440, 0x68b330da
+0, 105, 105, 1, 13440, 0xc07228cf
+0, 106, 106, 1, 13440, 0xaa3f3d44
+0, 107, 107, 1, 13440, 0x25867aad
+0, 108, 108, 1, 13440, 0xa3ecb432
+0, 109, 109, 1, 13440, 0x93ccdcbb
+0, 110, 110, 1, 13440, 0x8302fa4f
+0, 111, 111, 1, 13440, 0x2f960f33
+0, 112, 112, 1, 13440, 0x15d41d14
+0, 113, 113, 1, 13440, 0x636529d0
+0, 114, 114, 1, 13440, 0x11035be5
+0, 115, 115, 1, 13440, 0x9b6e9167
+0, 116, 116, 1, 13440, 0x7b01adc7
+0, 117, 117, 1, 13440, 0xa237e05d
+0, 118, 118, 1, 13440, 0xd2f4f134
+0, 119, 119, 1, 13440, 0x2052d368
+0, 120, 120, 1, 13440, 0x08f7ae0d
+0, 121, 121, 1, 13440, 0xa89185bc
+0, 122, 122, 1, 13440, 0xfa628236
+0, 123, 123, 1, 13440, 0xdf79848b
+0, 124, 124, 1, 13440, 0xd19a906f
+0, 125, 125, 1, 13440, 0x219f9324
+0, 126, 126, 1, 13440, 0x46509b6d
+0, 127, 127, 1, 13440, 0xc5d9a568
+0, 128, 128, 1, 13440, 0xb21aaaa8
+0, 129, 129, 1, 13440, 0x925a97ed
+0, 130, 130, 1, 13440, 0xc5e3557f
+0, 131, 131, 1, 13440, 0x7c57155a
+0, 132, 132, 1, 13440, 0x6b26d005
+0, 133, 133, 1, 13440, 0xfdc7b369
+0, 134, 134, 1, 13440, 0x99919fc2
+0, 135, 135, 1, 13440, 0xcfe889e4
+0, 136, 136, 1, 13440, 0xd1196856
+0, 137, 137, 1, 13440, 0xec8348c6
+0, 138, 138, 1, 13440, 0x5ede0d9a
+0, 139, 139, 1, 13440, 0x198ef66e
+0, 140, 140, 1, 13440, 0x62fcefdf
+0, 141, 141, 1, 13440, 0x7791f415
+0, 142, 142, 1, 13440, 0xfbdb0029
+0, 143, 143, 1, 13440, 0xdab12b01
+0, 144, 144, 1, 13440, 0x646b2d5f
+0, 145, 145, 1, 13440, 0x5410f52e
+0, 146, 146, 1, 13440, 0x7186eef8
+0, 147, 147, 1, 13440, 0xca251ef6
+0, 148, 148, 1, 13440, 0x757c3b43
+0, 149, 149, 1, 13440, 0x59ff4982
+0, 150, 150, 1, 13440, 0xbe8ff084
+0, 151, 151, 1, 13440, 0xc85a9e38
+0, 152, 152, 1, 13440, 0x541b9a19
+0, 153, 153, 1, 13440, 0x274893c9
+0, 154, 154, 1, 13440, 0x7634b5d2
+0, 155, 155, 1, 13440, 0x1bd8e10c
+0, 156, 156, 1, 13440, 0xa661dfb1
+0, 157, 157, 1, 13440, 0x9d01bf92
+0, 158, 158, 1, 13440, 0xcb1eb220
+0, 159, 159, 1, 13440, 0x0ce27d25
+0, 160, 160, 1, 13440, 0x523b594f
+0, 161, 161, 1, 13440, 0xf0a04c4f
+0, 162, 162, 1, 13440, 0x0f0ffc3d
+0, 163, 163, 1, 13440, 0xb0d8b778
+0, 164, 164, 1, 13440, 0x5137a642
+0, 165, 165, 1, 13440, 0xd213a552
+0, 166, 166, 1, 13440, 0xc2fbc9b1
+0, 167, 167, 1, 13440, 0xfc2ee379
+0, 168, 168, 1, 13440, 0xfb80f737
+0, 169, 169, 1, 13440, 0xd6cb2447
+0, 170, 170, 1, 13440, 0x124b606d
+0, 171, 171, 1, 13440, 0xf788a066
+0, 172, 172, 1, 13440, 0xa16eed6e
+0, 173, 173, 1, 13440, 0x73ff0f82
diff --git a/tests/ref/fate/vp8-alpha b/tests/ref/fate/vp8-alpha
new file mode 100644
index 0000000000..5b10725da5
--- /dev/null
+++ b/tests/ref/fate/vp8-alpha
@@ -0,0 +1,121 @@
+#tb 0: 1/1000
+0, 0, 0, 33, 2108, 0x59b92a34, S=2, 1900, 0x8fb3adc5, 8, 0x00000000
+0, 32, 32, 33, 142, 0x2f2a3fed, F=0x0, S=1, 160, 0xa13346af
+0, 65, 65, 33, 157, 0x17804767, F=0x0, S=1, 209, 0x64115f15
+0, 99, 99, 33, 206, 0x537262ca, F=0x0, S=1, 317, 0x44a09dd0
+0, 132, 132, 33, 259, 0x73ff74b6, F=0x0, S=1, 384, 0x2ee2c588
+0, 165, 165, 33, 320, 0x0fcf8ce4, F=0x0, S=1, 415, 0xff68c953
+0, 199, 199, 33, 377, 0x8fffb5f5, F=0x0, S=1, 475, 0x4166f3eb
+0, 232, 232, 33, 407, 0xe476c19e, F=0x0, S=1, 193, 0x3ff75489
+0, 265, 265, 33, 539, 0x90202334, F=0x0, S=1, 681, 0x776656b0
+0, 299, 299, 33, 560, 0xc6e2168d, F=0x0, S=1, 585, 0xddc81b8a
+0, 332, 332, 33, 597, 0x201a32a7, F=0x0, S=1, 574, 0x8baa1d65
+0, 365, 365, 33, 770, 0xab2b8891, F=0x0, S=1, 666, 0xcd8e51eb
+0, 399, 399, 33, 708, 0xc2386711, F=0x0, S=1, 706, 0x046b6444
+0, 432, 432, 33, 905, 0x7211c52d, F=0x0, S=1, 814, 0x5e288def
+0, 465, 465, 33, 770, 0xda4f8574, F=0x0, S=1, 829, 0xa0e8a949
+0, 499, 499, 33, 955, 0xf9a1d77a, F=0x0, S=1, 857, 0x9b63b955
+0, 532, 532, 33, 970, 0xff4de39a, F=0x0, S=1, 153, 0x3b00416c
+0, 565, 565, 33, 978, 0x12bcf81f, F=0x0, S=1, 1181, 0xce175555
+0, 599, 599, 33, 1233, 0x2903744a, F=0x0, S=1, 860, 0x737eb566
+0, 632, 632, 33, 1118, 0x7f274f50, F=0x0, S=1, 933, 0xb669c6b6
+0, 665, 665, 33, 941, 0x6bffd4b1, F=0x0, S=1, 1058, 0x07581cee
+0, 699, 699, 33, 1598, 0xc007219f, F=0x0, S=1, 939, 0x2c0bdc45
+0, 732, 732, 33, 1218, 0x25d962b6, F=0x0, S=1, 1090, 0x96482341
+0, 765, 765, 33, 1200, 0x86b85be3, F=0x0, S=1, 189, 0x3f085309
+0, 799, 799, 33, 1329, 0x298a848a, F=0x0, S=1, 1426, 0x6ea3df12
+0, 832, 832, 33, 1500, 0xe437edec, F=0x0, S=1, 1244, 0x32836b8d
+0, 865, 865, 33, 1288, 0xc4447dd5, F=0x0, S=1, 1289, 0x06a57b0f
+0, 899, 899, 33, 1281, 0xb5bf7e9f, F=0x0, S=1, 1227, 0xd96d5697
+0, 932, 932, 33, 1372, 0x09be9014, F=0x0, S=1, 1556, 0x2630fbff
+0, 965, 965, 33, 1238, 0x42ce6316, F=0x0, S=1, 1287, 0x1d3084f6
+0, 999, 999, 33, 1655, 0xb94b45c2, F=0x0, S=1, 1494, 0x34dbd1a4
+0, 1032, 1032, 33, 1164, 0xf6b93ad0, F=0x0, S=1, 1337, 0xba6d9673
+0, 1065, 1065, 33, 1084, 0x58c50fb5, F=0x0, S=1, 1384, 0x3fabb82b
+0, 1099, 1099, 33, 1151, 0x0b3f3359, F=0x0, S=1, 1353, 0x08e2a1d7
+0, 1132, 1132, 33, 1277, 0xa3ae77e1, F=0x0, S=1, 1409, 0xf65cb9f7
+0, 1165, 1165, 33, 782, 0xdcf671ff, F=0x0, S=1, 1408, 0x01e2ac53
+0, 1199, 1199, 33, 926, 0xe913c286, F=0x0, S=1, 1320, 0x32e38e42
+0, 1232, 1232, 33, 970, 0x3d86e5ae, F=0x0, S=1, 1608, 0x40b52618
+0, 1265, 1265, 33, 1353, 0xe4f197b2, F=0x0, S=1, 1272, 0xf1d272a5
+0, 1299, 1299, 33, 685, 0x629b4ce4, F=0x0, S=1, 1257, 0x14845de9
+0, 1332, 1332, 33, 743, 0x6f1172a3, F=0x0, S=1, 1260, 0xa6c66fda
+0, 1365, 1365, 33, 789, 0x94fc84cd, F=0x0, S=1, 1009, 0x7daaf2b0
+0, 1399, 1399, 33, 1460, 0x668adb82, F=0x0, S=1, 944, 0x44b6ccf5
+0, 1432, 1432, 33, 766, 0x49c884ef, F=0x0, S=1, 996, 0x8646e6dd
+0, 1465, 1465, 33, 1037, 0x24831498, F=0x0, S=1, 983, 0x14a9e7a6
+0, 1499, 1499, 33, 943, 0x1f53d180, F=0x0, S=1, 1107, 0x02f72acb
+0, 1532, 1532, 33, 1152, 0xbf6a35ae, F=0x0, S=1, 1026, 0xd57afda0
+0, 1565, 1565, 33, 730, 0x42806abf, F=0x0, S=1, 1029, 0xfb0402d5
+0, 1599, 1599, 33, 975, 0xa5ffec57, F=0x0, S=1, 1081, 0xe2890cea
+0, 1632, 1632, 33, 970, 0xbe8ee224, F=0x0, S=1, 1151, 0x7b0d3b20
+0, 1665, 1665, 33, 1012, 0x20c6f0d8, F=0x0, S=1, 979, 0xc25cd69c
+0, 1699, 1699, 33, 874, 0x1a2fb4da, F=0x0, S=1, 943, 0xdb2dc9f8
+0, 1732, 1732, 33, 869, 0xab0caf3d, F=0x0, S=1, 934, 0x48b9bfcc
+0, 1765, 1765, 33, 863, 0xd8caa2e5, F=0x0, S=1, 874, 0x0b34b026
+0, 1799, 1799, 33, 1246, 0x47866cdc, F=0x0, S=1, 818, 0x0c908eeb
+0, 1832, 1832, 33, 742, 0xa6296ac1, F=0x0, S=1, 921, 0x97b6b053
+0, 1865, 1865, 33, 828, 0x0b568d7a, F=0x0, S=1, 969, 0x3314dbfa
+0, 1899, 1899, 33, 825, 0x6d329394, F=0x0, S=1, 982, 0x5f66e68c
+0, 1932, 1932, 33, 836, 0x8ace8dfb, F=0x0, S=1, 929, 0x9ffdc2fd
+0, 1965, 1965, 33, 1774, 0xd4686726, F=0x0, S=1, 909, 0x11a9c07a
+0, 1999, 1999, 33, 1803, 0x08c879ce, F=0x0, S=1, 1525, 0x1e11f02f
+0, 2032, 2032, 33, 518, 0x7c32fc72, F=0x0, S=1, 785, 0xfc1f792a
+0, 2065, 2065, 33, 790, 0x3dac8aa0, F=0x0, S=1, 876, 0x0918c88d
+0, 2099, 2099, 33, 927, 0x4feccb24, F=0x0, S=1, 1059, 0xbcaa05c7
+0, 2132, 2132, 33, 835, 0x29d39266, F=0x0, S=1, 980, 0x4913e409
+0, 2165, 2165, 33, 951, 0xc1dddd12, F=0x0, S=1, 1041, 0x0541047e
+0, 2199, 2199, 33, 876, 0x2f6eb89d, F=0x0, S=1, 949, 0x2d56c53b
+0, 2232, 2232, 33, 959, 0xf0dedabd, F=0x0, S=1, 1022, 0x8d33f5fa
+0, 2265, 2265, 33, 860, 0x9274ab39, F=0x0, S=1, 1061, 0x289c0132
+0, 2299, 2299, 33, 863, 0x7058ba30, F=0x0, S=1, 940, 0x1f32d4a3
+0, 2332, 2332, 33, 1021, 0xcabdf84f, F=0x0, S=1, 887, 0xda8ab95e
+0, 2365, 2365, 33, 897, 0x9867c8e8, F=0x0, S=1, 840, 0xd93eaaf5
+0, 2399, 2399, 33, 897, 0x6a16b5db, F=0x0, S=1, 977, 0x7b77dc9b
+0, 2432, 2432, 33, 953, 0xe9b4cf1f, F=0x0, S=1, 921, 0x75a8ca45
+0, 2465, 2465, 33, 847, 0x0335ad37, F=0x0, S=1, 1000, 0x2691f3bd
+0, 2499, 2499, 33, 902, 0x3360b315, F=0x0, S=1, 1008, 0xd5e1deb6
+0, 2532, 2532, 33, 881, 0xf5309d59, F=0x0, S=1, 1113, 0xdbef3065
+0, 2565, 2565, 33, 974, 0x7c2de3ce, F=0x0, S=1, 1086, 0x365626bb
+0, 2599, 2599, 33, 974, 0xf42bd9f5, F=0x0, S=1, 1039, 0xa7e9060d
+0, 2632, 2632, 33, 1029, 0x7c33f4d0, F=0x0, S=1, 1041, 0xf4affa59
+0, 2665, 2665, 33, 881, 0x9021a565, F=0x0, S=1, 1039, 0xc1e00521
+0, 2699, 2699, 33, 1157, 0xe1c136f7, F=0x0, S=1, 917, 0x357ac7d3
+0, 2732, 2732, 33, 649, 0xdffb3cb7, F=0x0, S=1, 976, 0xa386e05e
+0, 2765, 2765, 33, 758, 0xb67875f3, F=0x0, S=1, 1041, 0xae4e0a63
+0, 2799, 2799, 33, 1105, 0x8ffb1a26, F=0x0, S=1, 962, 0x211ddc5e
+0, 2832, 2832, 33, 866, 0xa60eb2d9, F=0x0, S=1, 929, 0xe9e4c84b
+0, 2865, 2865, 33, 912, 0xcd34bf9b, F=0x0, S=1, 946, 0xfce9d359
+0, 2899, 2899, 33, 868, 0x5651a343, F=0x0, S=1, 809, 0x624a8ef9
+0, 2932, 2932, 33, 997, 0xfa66eaeb, F=0x0, S=1, 992, 0xc913e5e2
+0, 2965, 2965, 33, 1111, 0x3f272497, F=0x0, S=1, 1007, 0xf78ee6a7
+0, 2999, 2999, 33, 842, 0xe442999f, F=0x0, S=1, 972, 0x25a0d25c
+0, 3032, 3032, 33, 1030, 0x6f97ffad, F=0x0, S=1, 993, 0x4059fd6b
+0, 3065, 3065, 33, 1176, 0x66e64926, F=0x0, S=1, 951, 0x2762cdf1
+0, 3099, 3099, 33, 803, 0xfd1699cb, F=0x0, S=1, 959, 0x5cf9d56c
+0, 3132, 3132, 33, 972, 0x1cdff00e, F=0x0, S=1, 1023, 0xeaf20900
+0, 3165, 3165, 33, 907, 0x17f8acca, F=0x0, S=1, 1054, 0xeb010c4d
+0, 3199, 3199, 33, 915, 0x3569b545, F=0x0, S=1, 987, 0x73b2e159
+0, 3232, 3232, 33, 1021, 0x14c5076a, F=0x0, S=1, 1007, 0x6c4bf7f0
+0, 3265, 3265, 33, 837, 0xbf86b0ef, F=0x0, S=1, 963, 0xf472d31a
+0, 3299, 3299, 33, 885, 0x1caac123, F=0x0, S=1, 1052, 0x2b7bfd20
+0, 3332, 3332, 33, 1355, 0x299e8d3c, F=0x0, S=1, 858, 0x2bbca3f0
+0, 3365, 3365, 33, 784, 0xb0bd7e9d, F=0x0, S=1, 969, 0xc865dc00
+0, 3399, 3399, 33, 991, 0xbc7ddda9, F=0x0, S=1, 1028, 0x801b00a6
+0, 3432, 3432, 33, 986, 0xb356f6b1, F=0x0, S=1, 1056, 0x8b840add
+0, 3465, 3465, 33, 978, 0x94a3e87e, F=0x0, S=1, 1018, 0xe766fa52
+0, 3499, 3499, 33, 976, 0x55ddd14a, F=0x0, S=1, 992, 0x58a9ddfe
+0, 3532, 3532, 33, 1241, 0x1ec867f7, F=0x0, S=1, 966, 0xa329e84f
+0, 3565, 3565, 33, 975, 0xecf5dbb3, F=0x0, S=1, 899, 0xa7539f4d
+0, 3599, 3599, 33, 1129, 0xb7243037, F=0x0, S=1, 1057, 0xbd0d10bd
+0, 3632, 3632, 33, 913, 0xe5f1d03d, F=0x0, S=1, 1092, 0xeb9621f8
+0, 3665, 3665, 33, 943, 0x87d0ed78, F=0x0, S=1, 1057, 0x079c1054
+0, 3699, 3699, 33, 917, 0x536cc3fd, F=0x0, S=1, 946, 0xd2b9d0e2
+0, 3732, 3732, 33, 892, 0x4dffb1e2, F=0x0, S=1, 930, 0x70c9cc40
+0, 3765, 3765, 33, 957, 0x1a98e71c, F=0x0, S=1, 719, 0x6fec614a
+0, 3799, 3799, 33, 893, 0xf405b2c3, F=0x0, S=1, 821, 0x63529cab
+0, 3832, 3832, 33, 978, 0xa0a8d5f6, F=0x0, S=1, 745, 0x3c616219
+0, 3865, 3865, 33, 887, 0xfa7cb65d, F=0x0, S=1, 768, 0xb8f07885
+0, 3899, 3899, 33, 867, 0xd808ade7, F=0x0, S=1, 783, 0xf82b6b9a
+0, 3932, 3932, 33, 1068, 0x6f8b135a, F=0x0, S=1, 807, 0x52028d50
+0, 3965, 3965, 33, 2010, 0x536fe0b6, F=0x0, S=1, 1512, 0x690aeb55
diff --git a/tests/ref/fate/vp8-sign-bias b/tests/ref/fate/vp8-sign-bias
index 77b69ed421..b503de84ef 100644
--- a/tests/ref/fate/vp8-sign-bias
+++ b/tests/ref/fate/vp8-sign-bias
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/24
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 614880, 12ce23b288485be3ddbc1db28c21517f
0, 2, 2, 1, 614880, ce352e1079535ea058c0e9ad50f7cdb8
0, 3, 3, 1, 614880, 9f6bf2739a027dfd12c81586cf75d3a3
@@ -6,4 +10,5 @@
0, 5, 5, 1, 614880, 52f47f1e0348f3297d9f233fb5405e8b
0, 6, 6, 1, 614880, cd51d2c200bfd66e8e1b0fd6b404570f
0, 7, 7, 1, 614880, cf535cf0a53e903cd98a9a944b72da6d
-0, 8, 8, 1, 614880, ff373c0c8a4a319c84e72b1c3d76b399
+0, 8, 8, 1, 614880, 1b270fd2b56daa7892102c2885d23201
+0, 9, 9, 1, 614880, ff373c0c8a4a319c84e72b1c3d76b399
diff --git a/tests/ref/fate/vp8-size-change b/tests/ref/fate/vp8-size-change
index d87c563b7d..f581c999fb 100644
--- a/tests/ref/fate/vp8-size-change
+++ b/tests/ref/fate/vp8-size-change
@@ -1,31 +1,35 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3110400, 649f0f2e3e09e6938161bb07bede5282
-0, 33, 33, 0, 3110400, f24f632d50eafef73fa89391ca98c375
-0, 67, 67, 0, 3110400, 57b6d2ed51bfaf6588f39eb73e7922b8
-0, 100, 100, 0, 3110400, 463e0988ce28eb1c30669c06113deb4c
-0, 133, 133, 0, 3110400, 3c4ac119f998a0ccd7d3a6361f4d10a0
-0, 167, 167, 0, 3110400, 0f11c5cc9c1ac9055e21e417e1259c69
-0, 200, 200, 0, 3110400, 08c6e70f101c61013f2969b6a370d3f9
-0, 233, 233, 0, 3110400, ea8cb37017d8a9d20bf443b730fd8365
-0, 267, 267, 0, 3110400, 3f614203f054c89151680f4b1b0c6c4c
-0, 300, 300, 0, 3110400, 90488ee40d06c0f05eee8348dde57325
-0, 333, 333, 0, 3110400, f48117b74ac7455e69fd14e9b68ce95d
-0, 367, 367, 0, 3110400, 37ee06b6267b5ec25fd642525cf4469a
-0, 400, 400, 0, 3110400, cd5e0988e7c084f29bda4a18cb38c1e8
-0, 433, 433, 0, 3110400, 1fe943b01f00b8bc0cb5722010cef03c
-0, 467, 467, 0, 3110400, 40d8e8150326c7eb061d3f6cfd307d97
-0, 500, 500, 0, 3110400, 49812cbf928858cb56331c8c8aaaf556
-0, 533, 533, 0, 3110400, 3df607c752273ebcac21123e2c4c010c
-0, 567, 567, 0, 3110400, 020a0ae162c8326f83f8f4d8bf1627d2
-0, 600, 600, 0, 3110400, 459ac9f9488a6a2f4e378703a6b2a45a
-0, 633, 633, 0, 3110400, b1baf9a56f7667e4b8f4e3007b9ebe0f
-0, 667, 667, 0, 3110400, eea61a72a05c380450a96b575ba25f65
-0, 700, 700, 0, 3110400, e013a9f233824631d8c6e3f93106eebe
-0, 733, 733, 0, 3110400, 6c64147ebdee4b36728c6978b290ffb5
-0, 767, 767, 0, 3110400, c37956235667345d92fdfc7c62496e84
-0, 800, 800, 0, 3110400, 0ac58c28575b804d9e63395653c3aef2
-0, 833, 833, 0, 3110400, 641f2a78e338c733ef159bd36ec7966f
-0, 867, 867, 0, 3110400, 9402d455fa5bd556b85f479c42c3a4d2
-0, 900, 900, 0, 3110400, ca86e16b05db0c79b028d709c19e1f13
-0, 933, 933, 0, 3110400, 9167d622809df07eef9bcb3cb09de0f0
-0, 967, 967, 0, 3110400, e1d52ae2a2eb6aabb9bdc7e7ed05253e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3110400, 7dde8cd136ab4b04a95d9856b941697e
+0, 1, 1, 1, 3110400, aa885f78cb6374b5bfcc66a4fc57026f
+0, 2, 2, 1, 3110400, b69b7b56f549a3f9b0a603940bac85ed
+0, 3, 3, 1, 3110400, 20e2e0f0c89c58828b6a3b10d9e175e5
+0, 4, 4, 1, 3110400, 483997936e7d6bb849e64d50426ec689
+0, 5, 5, 1, 3110400, c85ef97a853ff594e2bfdf0a0a581dcc
+0, 6, 6, 1, 3110400, c5e7b9ff4c25391793446da788cb83a9
+0, 7, 7, 1, 3110400, 63f93e89d24162e2f6328edbc6716b33
+0, 8, 8, 1, 3110400, 0e346ab4831ce8c69001153c72b7b827
+0, 9, 9, 1, 3110400, c526c21511d8bec2659d3d43d93734f2
+0, 10, 10, 1, 3110400, e95d01d5f9fb81a98bd34305c7ab30f8
+0, 11, 11, 1, 3110400, 177e75e7516e8746d31b43ea9d39e6b1
+0, 12, 12, 1, 3110400, 489d2bc0da93f118dc9a2697275697a7
+0, 13, 13, 1, 3110400, a2dc00d627350ff1ab302bcbad5ca5ac
+0, 14, 14, 1, 3110400, 20ce143831b0189f763ee5bee9c51188
+0, 15, 15, 1, 3110400, 7822fd908bd81b521c23fa4a639caf9e
+0, 16, 16, 1, 3110400, dabc4febbe09734126ac6f5a5180ba8c
+0, 17, 17, 1, 3110400, ef88f0d6667feefac1471b065208e1c8
+0, 18, 18, 1, 3110400, 7c7fc665a6fd9e19af9358bbdc162a51
+0, 19, 19, 1, 3110400, f2bcf32f734f99506bdd0a0376badf82
+0, 20, 20, 1, 3110400, 06809c2d277fd3b3918ebb4b65c27661
+0, 21, 21, 1, 3110400, e403e9e86fa5d519f65c565b3add84b5
+0, 22, 22, 1, 3110400, d2b876730e12245cacb578307794349a
+0, 23, 23, 1, 3110400, dfdfd8cb626a96138f6a2c1953dcf5ec
+0, 24, 24, 1, 3110400, 0ac58c28575b804d9e63395653c3aef2
+0, 25, 25, 1, 3110400, 641f2a78e338c733ef159bd36ec7966f
+0, 26, 26, 1, 3110400, 9402d455fa5bd556b85f479c42c3a4d2
+0, 27, 27, 1, 3110400, 0044d42b4048bc93112aa59789dbdc2d
+0, 28, 28, 1, 3110400, 5d9e5c5ba35f6f452e5f31ccff9e819c
+0, 29, 29, 1, 3110400, 307a55a94739b4cfdf41f7da7e5c0135
diff --git a/tests/ref/fate/vp8-test-vector-001 b/tests/ref/fate/vp8-test-vector-001
index 64accc488c..ef38aa88cd 100644
--- a/tests/ref/fate/vp8-test-vector-001
+++ b/tests/ref/fate/vp8-test-vector-001
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 83c78b5db579710f61f9354d5c51e8c8
0, 1, 1, 1, 38016, 8d089d226f52d6cdaffdb3fcc080b75b
0, 2, 2, 1, 38016, acaae81ca812145e85e0be83bdf54226
diff --git a/tests/ref/fate/vp8-test-vector-002 b/tests/ref/fate/vp8-test-vector-002
index d42674ad0a..55149b0c0a 100644
--- a/tests/ref/fate/vp8-test-vector-002
+++ b/tests/ref/fate/vp8-test-vector-002
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/24
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 872e9922f37f0e92c767d33e0a15b8e0
0, 1, 1, 1, 38016, ea5ad6c6ee4355018fc0ba83b5172836
0, 2, 2, 1, 38016, fe744612b2167c9ba6e1dc81c031e16a
diff --git a/tests/ref/fate/vp8-test-vector-003 b/tests/ref/fate/vp8-test-vector-003
index 504766fd52..ffe3896fd4 100644
--- a/tests/ref/fate/vp8-test-vector-003
+++ b/tests/ref/fate/vp8-test-vector-003
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/24
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 96e6ce168b5ef377053e86ab5484e7f9
0, 1, 1, 1, 38016, 10fd750292d8522ab7ee577043604789
0, 2, 2, 1, 38016, e040995173dc5c85abbbe38f6823ff9a
diff --git a/tests/ref/fate/vp8-test-vector-004 b/tests/ref/fate/vp8-test-vector-004
index f402372b88..f7f5313b2d 100644
--- a/tests/ref/fate/vp8-test-vector-004
+++ b/tests/ref/fate/vp8-test-vector-004
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 83c78b5db579710f61f9354d5c51e8c8
0, 1, 1, 1, 38016, d173eb8a8211a05672b43206609c9034
0, 2, 2, 1, 38016, 204e3e91613d647d30244c00fa2b9563
diff --git a/tests/ref/fate/vp8-test-vector-005 b/tests/ref/fate/vp8-test-vector-005
index 3569deea68..3368c7074f 100644
--- a/tests/ref/fate/vp8-test-vector-005
+++ b/tests/ref/fate/vp8-test-vector-005
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/24
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, e7a4be434df4bb524ba56a03cba901f4
0, 1, 1, 1, 38016, d903ade6d49e51485627c044fbb2190c
0, 2, 2, 1, 38016, af07ee39629b852870104cb9a9dde9e3
diff --git a/tests/ref/fate/vp8-test-vector-006 b/tests/ref/fate/vp8-test-vector-006
index 38b92c4a7f..28c249cf96 100644
--- a/tests/ref/fate/vp8-test-vector-006
+++ b/tests/ref/fate/vp8-test-vector-006
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/24
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 37697, 9ca5df27b0158aca2a38dff946f58c41
0, 1, 1, 1, 37697, 627129a99538ec1ac51be910ca92ebc4
0, 2, 2, 1, 37697, 6c2df1f21af317aa5bb68b161ca96c70
diff --git a/tests/ref/fate/vp8-test-vector-007 b/tests/ref/fate/vp8-test-vector-007
index 8d9b912fc9..a0cb441c9c 100644
--- a/tests/ref/fate/vp8-test-vector-007
+++ b/tests/ref/fate/vp8-test-vector-007
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 98bd0af6928c144888a9c320270e9f0e
0, 1, 1, 1, 38016, 9ff7cff703d58481acd233451388377c
0, 2, 2, 1, 38016, e4cd8815527846cc782ea61ef5a46e49
diff --git a/tests/ref/fate/vp8-test-vector-008 b/tests/ref/fate/vp8-test-vector-008
index 9be8d73a24..0503c4e71e 100644
--- a/tests/ref/fate/vp8-test-vector-008
+++ b/tests/ref/fate/vp8-test-vector-008
@@ -1,3 +1,7 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/23
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 1907424, 7146d3a72b6cb8e43ee5280ef8d661fe
0, 1, 1, 1, 1907424, 5a537e9710158efb5ad2683a1d3b4c72
diff --git a/tests/ref/fate/vp8-test-vector-009 b/tests/ref/fate/vp8-test-vector-009
index fae204db99..f41f014588 100644
--- a/tests/ref/fate/vp8-test-vector-009
+++ b/tests/ref/fate/vp8-test-vector-009
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/24
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, b3a3121c796a60c88988fef5240a07fe
0, 1, 1, 1, 38016, f25147764829cf837e00b8fd6383e2c4
0, 2, 2, 1, 38016, 1b1552291a89c97d5deea145ab0ac0cd
diff --git a/tests/ref/fate/vp8-test-vector-010 b/tests/ref/fate/vp8-test-vector-010
index b250ad92d1..2feeb63413 100644
--- a/tests/ref/fate/vp8-test-vector-010
+++ b/tests/ref/fate/vp8-test-vector-010
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 115200, 3441ec1a9b9d325c9aeda44e3b68377d
0, 1, 1, 1, 115200, bff86a84fd673394f45c09d19a1ee0ac
0, 2, 2, 1, 115200, 8cd920f0de408e8cd883f9241680ff80
diff --git a/tests/ref/fate/vp8-test-vector-011 b/tests/ref/fate/vp8-test-vector-011
index d591ec7eee..adf7235eaa 100644
--- a/tests/ref/fate/vp8-test-vector-011
+++ b/tests/ref/fate/vp8-test-vector-011
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 83c78b5db579710f61f9354d5c51e8c8
0, 1, 1, 1, 38016, 9b755a63c7c5352660a265f6e24991e1
0, 2, 2, 1, 38016, a591f0b04447d6d6dd9bb990502594aa
diff --git a/tests/ref/fate/vp8-test-vector-012 b/tests/ref/fate/vp8-test-vector-012
index 4d5adcbf1b..3de64b6d6f 100644
--- a/tests/ref/fate/vp8-test-vector-012
+++ b/tests/ref/fate/vp8-test-vector-012
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, cc3069a59b6f4319761af2b39923a6e5
0, 1, 1, 1, 38016, c0bc935941d994c6af6a864f02a90a62
0, 2, 2, 1, 38016, 5b6073ce4a03967aa87e56dfa27e32c2
diff --git a/tests/ref/fate/vp8-test-vector-013 b/tests/ref/fate/vp8-test-vector-013
index de7c0b3cbc..e31e6e64d2 100644
--- a/tests/ref/fate/vp8-test-vector-013
+++ b/tests/ref/fate/vp8-test-vector-013
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, ad137b9eae93daed28fe31fd5165b4d0
0, 1, 1, 1, 38016, 7cd527f647680c0eb305050d27fb8092
0, 2, 2, 1, 38016, f306e07a2e86c82a8cc1333be3812326
diff --git a/tests/ref/fate/vp8-test-vector-014 b/tests/ref/fate/vp8-test-vector-014
index 4341e59097..689e24bd2b 100644
--- a/tests/ref/fate/vp8-test-vector-014
+++ b/tests/ref/fate/vp8-test-vector-014
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 37697, 7a0356dc950e79744d79c98e391ebee9
0, 1, 1, 1, 37697, 96e221e75c290dd847b8e55865073366
0, 2, 2, 1, 37697, 67638290841837c90f180a01094f9191
diff --git a/tests/ref/fate/vp8-test-vector-015 b/tests/ref/fate/vp8-test-vector-015
index b32f2337d7..766c931029 100644
--- a/tests/ref/fate/vp8-test-vector-015
+++ b/tests/ref/fate/vp8-test-vector-015
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 115200, 6b4c7cc0c6a7218362e43cffef6618c9
0, 1, 1, 1, 115200, e132a7b1bb4fb15b1019092aedc0e599
0, 2, 2, 1, 115200, b36975db60f24088d95385ff7e8b7b8a
diff --git a/tests/ref/fate/vp8-test-vector-016 b/tests/ref/fate/vp8-test-vector-016
index 291e7fe2cd..4da7ff3a84 100644
--- a/tests/ref/fate/vp8-test-vector-016
+++ b/tests/ref/fate/vp8-test-vector-016
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 905a823da31f71f9c25ebb8dfc9ddd3c
0, 1, 1, 1, 38016, 9a1b97859b2f774954dbf96f45a22a0a
0, 2, 2, 1, 38016, f0f5651b32577549dc2e6e3050125229
diff --git a/tests/ref/fate/vp8-test-vector-017 b/tests/ref/fate/vp8-test-vector-017
index a8ccda8ee9..0d3fbea2af 100644
--- a/tests/ref/fate/vp8-test-vector-017
+++ b/tests/ref/fate/vp8-test-vector-017
@@ -1,4 +1,8 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 1, 38016, 905a823da31f71f9c25ebb8dfc9ddd3c
0, 1, 1, 1, 38016, f0f411dd067bff05d5d9c64e3f52a4b1
0, 2, 2, 1, 38016, c8696f8fa56b4adf18f3db0c384d968f
diff --git a/tests/ref/fate/vp9-00-quantizer-00 b/tests/ref/fate/vp9-00-quantizer-00
index a6e701e4a3..e2afb9c82c 100644
--- a/tests/ref/fate/vp9-00-quantizer-00
+++ b/tests/ref/fate/vp9-00-quantizer-00
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, c3fbb7abbdb5bd4ed4a7e34768c17df1
-0, 33, 33, 0, 152064, 08203c2595bdb2d58ead6f921345d699
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, c3fbb7abbdb5bd4ed4a7e34768c17df1
+0, 1, 1, 1, 152064, 08203c2595bdb2d58ead6f921345d699
diff --git a/tests/ref/fate/vp9-00-quantizer-01 b/tests/ref/fate/vp9-00-quantizer-01
index 0d22d2bf07..4d9b081869 100644
--- a/tests/ref/fate/vp9-00-quantizer-01
+++ b/tests/ref/fate/vp9-00-quantizer-01
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, f041b870cf9236d5f22e2b08a77d5958
-0, 33, 33, 0, 152064, cbdb7526986ae15592891488c9afc84c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, f041b870cf9236d5f22e2b08a77d5958
+0, 1, 1, 1, 152064, cbdb7526986ae15592891488c9afc84c
diff --git a/tests/ref/fate/vp9-00-quantizer-02 b/tests/ref/fate/vp9-00-quantizer-02
index 023caf8f3a..09e62995da 100644
--- a/tests/ref/fate/vp9-00-quantizer-02
+++ b/tests/ref/fate/vp9-00-quantizer-02
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 98048cfdb4af5059f4085c5acc94ef8f
-0, 33, 33, 0, 152064, 8160183e1eed1d0af4427be216b8b9f7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 98048cfdb4af5059f4085c5acc94ef8f
+0, 1, 1, 1, 152064, 8160183e1eed1d0af4427be216b8b9f7
diff --git a/tests/ref/fate/vp9-00-quantizer-03 b/tests/ref/fate/vp9-00-quantizer-03
index 5abb9eecb5..0c22157b47 100644
--- a/tests/ref/fate/vp9-00-quantizer-03
+++ b/tests/ref/fate/vp9-00-quantizer-03
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 15c548208f5eda243a151a42f4d64855
-0, 33, 33, 0, 152064, e96d463dc8e9b27b1c2ec40f77eee6ef
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 15c548208f5eda243a151a42f4d64855
+0, 1, 1, 1, 152064, e96d463dc8e9b27b1c2ec40f77eee6ef
diff --git a/tests/ref/fate/vp9-00-quantizer-04 b/tests/ref/fate/vp9-00-quantizer-04
index 1be91be870..730a012826 100644
--- a/tests/ref/fate/vp9-00-quantizer-04
+++ b/tests/ref/fate/vp9-00-quantizer-04
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 928c64a0747ac57ab50c1520d694fea7
-0, 33, 33, 0, 152064, a6f6daa293231e95ef30ed168f582c84
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 928c64a0747ac57ab50c1520d694fea7
+0, 1, 1, 1, 152064, a6f6daa293231e95ef30ed168f582c84
diff --git a/tests/ref/fate/vp9-00-quantizer-05 b/tests/ref/fate/vp9-00-quantizer-05
index 9e359b39b8..0f2dd7ad33 100644
--- a/tests/ref/fate/vp9-00-quantizer-05
+++ b/tests/ref/fate/vp9-00-quantizer-05
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 082460718b7d7046c8fb23184b7f71ca
-0, 33, 33, 0, 152064, 4a41aad51c40a92df72333e13f47d3fe
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 082460718b7d7046c8fb23184b7f71ca
+0, 1, 1, 1, 152064, 4a41aad51c40a92df72333e13f47d3fe
diff --git a/tests/ref/fate/vp9-00-quantizer-06 b/tests/ref/fate/vp9-00-quantizer-06
index e9843114eb..c6c128285e 100644
--- a/tests/ref/fate/vp9-00-quantizer-06
+++ b/tests/ref/fate/vp9-00-quantizer-06
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, cfca1bed96ff62a69b2d841fda01c6b9
-0, 33, 33, 0, 152064, 9b4d61f1b998745c108f8eb67925e03d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, cfca1bed96ff62a69b2d841fda01c6b9
+0, 1, 1, 1, 152064, 9b4d61f1b998745c108f8eb67925e03d
diff --git a/tests/ref/fate/vp9-00-quantizer-07 b/tests/ref/fate/vp9-00-quantizer-07
index b1e6b542a6..cdc6ec5a42 100644
--- a/tests/ref/fate/vp9-00-quantizer-07
+++ b/tests/ref/fate/vp9-00-quantizer-07
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 6f5122064bead9d9882bec2698a6ed9c
-0, 33, 33, 0, 152064, 50dae67d2f57a76eece210dee8b6df9e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 6f5122064bead9d9882bec2698a6ed9c
+0, 1, 1, 1, 152064, 50dae67d2f57a76eece210dee8b6df9e
diff --git a/tests/ref/fate/vp9-00-quantizer-08 b/tests/ref/fate/vp9-00-quantizer-08
index 6bb9687b11..f405cef92b 100644
--- a/tests/ref/fate/vp9-00-quantizer-08
+++ b/tests/ref/fate/vp9-00-quantizer-08
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, eb3d6985fcda5d93dd62d53354e8a093
-0, 33, 33, 0, 152064, 5b1f5b7780b4cafe1f75e56a0b526643
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, eb3d6985fcda5d93dd62d53354e8a093
+0, 1, 1, 1, 152064, 5b1f5b7780b4cafe1f75e56a0b526643
diff --git a/tests/ref/fate/vp9-00-quantizer-09 b/tests/ref/fate/vp9-00-quantizer-09
index 32055ca00b..bc5e86add8 100644
--- a/tests/ref/fate/vp9-00-quantizer-09
+++ b/tests/ref/fate/vp9-00-quantizer-09
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, d7ccaf28c59875fe91983def5490d2b1
-0, 33, 33, 0, 152064, bd98fe9492054826748de840b4495309
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, d7ccaf28c59875fe91983def5490d2b1
+0, 1, 1, 1, 152064, bd98fe9492054826748de840b4495309
diff --git a/tests/ref/fate/vp9-00-quantizer-10 b/tests/ref/fate/vp9-00-quantizer-10
index 9f738a3389..93e46a93a2 100644
--- a/tests/ref/fate/vp9-00-quantizer-10
+++ b/tests/ref/fate/vp9-00-quantizer-10
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 20dda6231f9801c9c237c6d09d9939b6
-0, 33, 33, 0, 152064, 23c91e93807fb9a4ed5bd5bdd449d99f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 20dda6231f9801c9c237c6d09d9939b6
+0, 1, 1, 1, 152064, 23c91e93807fb9a4ed5bd5bdd449d99f
diff --git a/tests/ref/fate/vp9-00-quantizer-11 b/tests/ref/fate/vp9-00-quantizer-11
index 3449ea9a5e..0924f548c8 100644
--- a/tests/ref/fate/vp9-00-quantizer-11
+++ b/tests/ref/fate/vp9-00-quantizer-11
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 960833315ebcdee97f46c4d98d0f3fef
-0, 33, 33, 0, 152064, eec40507d17b64b7895a61cb87b2096a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 960833315ebcdee97f46c4d98d0f3fef
+0, 1, 1, 1, 152064, eec40507d17b64b7895a61cb87b2096a
diff --git a/tests/ref/fate/vp9-00-quantizer-12 b/tests/ref/fate/vp9-00-quantizer-12
index 1494fd9562..9213e9df81 100644
--- a/tests/ref/fate/vp9-00-quantizer-12
+++ b/tests/ref/fate/vp9-00-quantizer-12
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 6533224d3b6ba1ec0dd973bbe56c6349
-0, 33, 33, 0, 152064, 12ceadc6d28327a24a75f8c40b6084d1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 6533224d3b6ba1ec0dd973bbe56c6349
+0, 1, 1, 1, 152064, 12ceadc6d28327a24a75f8c40b6084d1
diff --git a/tests/ref/fate/vp9-00-quantizer-13 b/tests/ref/fate/vp9-00-quantizer-13
index 1a75e63f5f..80d1a6ca4b 100644
--- a/tests/ref/fate/vp9-00-quantizer-13
+++ b/tests/ref/fate/vp9-00-quantizer-13
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 7268de6756014f79a56dcf010c52a97f
-0, 33, 33, 0, 152064, 9e39e9b0e2295b8460dfa05f44762771
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 7268de6756014f79a56dcf010c52a97f
+0, 1, 1, 1, 152064, 9e39e9b0e2295b8460dfa05f44762771
diff --git a/tests/ref/fate/vp9-00-quantizer-14 b/tests/ref/fate/vp9-00-quantizer-14
index b614bd7759..e7ab21df7c 100644
--- a/tests/ref/fate/vp9-00-quantizer-14
+++ b/tests/ref/fate/vp9-00-quantizer-14
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 57e9e333c641fa952f7485b788df225a
-0, 33, 33, 0, 152064, 551f0cea83dcdf4540c3983736757874
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 57e9e333c641fa952f7485b788df225a
+0, 1, 1, 1, 152064, 551f0cea83dcdf4540c3983736757874
diff --git a/tests/ref/fate/vp9-00-quantizer-15 b/tests/ref/fate/vp9-00-quantizer-15
index e092a9a140..842ab6ed57 100644
--- a/tests/ref/fate/vp9-00-quantizer-15
+++ b/tests/ref/fate/vp9-00-quantizer-15
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 17a0a2842856b9e89aede237648d5dda
-0, 33, 33, 0, 152064, c9fcade888a38621bebe3d4b41664245
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 17a0a2842856b9e89aede237648d5dda
+0, 1, 1, 1, 152064, c9fcade888a38621bebe3d4b41664245
diff --git a/tests/ref/fate/vp9-00-quantizer-16 b/tests/ref/fate/vp9-00-quantizer-16
index 159debc6be..7478558416 100644
--- a/tests/ref/fate/vp9-00-quantizer-16
+++ b/tests/ref/fate/vp9-00-quantizer-16
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 6cc2089e9a3d352fe10b59ccd935c677
-0, 33, 33, 0, 152064, d165bf7b9cb901e121a65038758d8613
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 6cc2089e9a3d352fe10b59ccd935c677
+0, 1, 1, 1, 152064, d165bf7b9cb901e121a65038758d8613
diff --git a/tests/ref/fate/vp9-00-quantizer-17 b/tests/ref/fate/vp9-00-quantizer-17
index bc89173560..3a5b1c1aa4 100644
--- a/tests/ref/fate/vp9-00-quantizer-17
+++ b/tests/ref/fate/vp9-00-quantizer-17
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, bc80511c83162c09661f155cd29f6dd8
-0, 33, 33, 0, 152064, a62f1cbdb3f86d2fb4c880cfd917def5
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, bc80511c83162c09661f155cd29f6dd8
+0, 1, 1, 1, 152064, a62f1cbdb3f86d2fb4c880cfd917def5
diff --git a/tests/ref/fate/vp9-00-quantizer-18 b/tests/ref/fate/vp9-00-quantizer-18
index a05d563fb2..baf3bc3e2a 100644
--- a/tests/ref/fate/vp9-00-quantizer-18
+++ b/tests/ref/fate/vp9-00-quantizer-18
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, b2d350f6faa41cb50c2e8a9907d0f4a5
-0, 33, 33, 0, 152064, 39b4380d16bc8e093dd4dba475175fb3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, b2d350f6faa41cb50c2e8a9907d0f4a5
+0, 1, 1, 1, 152064, 39b4380d16bc8e093dd4dba475175fb3
diff --git a/tests/ref/fate/vp9-00-quantizer-19 b/tests/ref/fate/vp9-00-quantizer-19
index 43c1c5543f..2ba95e1fe6 100644
--- a/tests/ref/fate/vp9-00-quantizer-19
+++ b/tests/ref/fate/vp9-00-quantizer-19
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 441e09be3c15fcb240afd74bb7a10a72
-0, 33, 33, 0, 152064, 32ae5dac876ca5d5ae6ab7c74f4dc25d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 441e09be3c15fcb240afd74bb7a10a72
+0, 1, 1, 1, 152064, 32ae5dac876ca5d5ae6ab7c74f4dc25d
diff --git a/tests/ref/fate/vp9-00-quantizer-20 b/tests/ref/fate/vp9-00-quantizer-20
index 95e5216454..81196881ed 100644
--- a/tests/ref/fate/vp9-00-quantizer-20
+++ b/tests/ref/fate/vp9-00-quantizer-20
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 7786eb9944dba0553e129133523a98c1
-0, 33, 33, 0, 152064, 206d888f8453427f10a40aa8bf5f6df0
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 7786eb9944dba0553e129133523a98c1
+0, 1, 1, 1, 152064, 206d888f8453427f10a40aa8bf5f6df0
diff --git a/tests/ref/fate/vp9-00-quantizer-21 b/tests/ref/fate/vp9-00-quantizer-21
index 4ddd9fb7a9..0e949928c8 100644
--- a/tests/ref/fate/vp9-00-quantizer-21
+++ b/tests/ref/fate/vp9-00-quantizer-21
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, aab95e195be71feca050a839d7b3154d
-0, 33, 33, 0, 152064, 02a05d699bbbdc477e34bb0dad9f0391
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, aab95e195be71feca050a839d7b3154d
+0, 1, 1, 1, 152064, 02a05d699bbbdc477e34bb0dad9f0391
diff --git a/tests/ref/fate/vp9-00-quantizer-22 b/tests/ref/fate/vp9-00-quantizer-22
index bb9d945764..90533aad8c 100644
--- a/tests/ref/fate/vp9-00-quantizer-22
+++ b/tests/ref/fate/vp9-00-quantizer-22
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 41f853c3ee2d4611b645cc643d82e287
-0, 33, 33, 0, 152064, 1c240c653110ff8609ca0f0287a6496d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 41f853c3ee2d4611b645cc643d82e287
+0, 1, 1, 1, 152064, 1c240c653110ff8609ca0f0287a6496d
diff --git a/tests/ref/fate/vp9-00-quantizer-23 b/tests/ref/fate/vp9-00-quantizer-23
index 968dfc1df2..d16d1981a7 100644
--- a/tests/ref/fate/vp9-00-quantizer-23
+++ b/tests/ref/fate/vp9-00-quantizer-23
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, bc5b07369df50c8f97ce1a377fe513cf
-0, 33, 33, 0, 152064, ce62ddb4f3e305d0f8587ae8bb44cc79
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, bc5b07369df50c8f97ce1a377fe513cf
+0, 1, 1, 1, 152064, ce62ddb4f3e305d0f8587ae8bb44cc79
diff --git a/tests/ref/fate/vp9-00-quantizer-24 b/tests/ref/fate/vp9-00-quantizer-24
index 8f087c57bd..eccdfd6aa8 100644
--- a/tests/ref/fate/vp9-00-quantizer-24
+++ b/tests/ref/fate/vp9-00-quantizer-24
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 982d54041221c977b6f0e37a9236cc76
-0, 33, 33, 0, 152064, 57631e7f13f645c834e2944ebfd6d40e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 982d54041221c977b6f0e37a9236cc76
+0, 1, 1, 1, 152064, 57631e7f13f645c834e2944ebfd6d40e
diff --git a/tests/ref/fate/vp9-00-quantizer-25 b/tests/ref/fate/vp9-00-quantizer-25
index a14840b219..70a76b39b3 100644
--- a/tests/ref/fate/vp9-00-quantizer-25
+++ b/tests/ref/fate/vp9-00-quantizer-25
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, b0fb55f3f2f56b3d27038e83c10123ce
-0, 33, 33, 0, 152064, 9fcac3becdcc2d30d778a55eca4c2018
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, b0fb55f3f2f56b3d27038e83c10123ce
+0, 1, 1, 1, 152064, 9fcac3becdcc2d30d778a55eca4c2018
diff --git a/tests/ref/fate/vp9-00-quantizer-26 b/tests/ref/fate/vp9-00-quantizer-26
index 0ccb7494ec..d9308dc1d5 100644
--- a/tests/ref/fate/vp9-00-quantizer-26
+++ b/tests/ref/fate/vp9-00-quantizer-26
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 4f645e0f354da77b9e2f2a6753c361da
-0, 33, 33, 0, 152064, b7542998ec298273ca662bc9b658d10e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 4f645e0f354da77b9e2f2a6753c361da
+0, 1, 1, 1, 152064, b7542998ec298273ca662bc9b658d10e
diff --git a/tests/ref/fate/vp9-00-quantizer-27 b/tests/ref/fate/vp9-00-quantizer-27
index f8c5df7aa9..d2efd69d3a 100644
--- a/tests/ref/fate/vp9-00-quantizer-27
+++ b/tests/ref/fate/vp9-00-quantizer-27
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 6edc96a3747cad43828397045764206e
-0, 33, 33, 0, 152064, 5fbc65d20fdca1abd69079851ce676d3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 6edc96a3747cad43828397045764206e
+0, 1, 1, 1, 152064, 5fbc65d20fdca1abd69079851ce676d3
diff --git a/tests/ref/fate/vp9-00-quantizer-28 b/tests/ref/fate/vp9-00-quantizer-28
index 588ef1c8a1..85919fc881 100644
--- a/tests/ref/fate/vp9-00-quantizer-28
+++ b/tests/ref/fate/vp9-00-quantizer-28
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 5db3e910e70da38bb91d01d73acc33dd
-0, 33, 33, 0, 152064, b920ee7f7e61b7fdf9f44b1f738d0292
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 5db3e910e70da38bb91d01d73acc33dd
+0, 1, 1, 1, 152064, b920ee7f7e61b7fdf9f44b1f738d0292
diff --git a/tests/ref/fate/vp9-00-quantizer-29 b/tests/ref/fate/vp9-00-quantizer-29
index 583cfa06c0..cc6eae780d 100644
--- a/tests/ref/fate/vp9-00-quantizer-29
+++ b/tests/ref/fate/vp9-00-quantizer-29
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 3cb3e310be5305077efa6216f6f10654
-0, 33, 33, 0, 152064, 692d3e098af5978fe1a898ebc1a66a7a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 3cb3e310be5305077efa6216f6f10654
+0, 1, 1, 1, 152064, 692d3e098af5978fe1a898ebc1a66a7a
diff --git a/tests/ref/fate/vp9-00-quantizer-30 b/tests/ref/fate/vp9-00-quantizer-30
index 45b2c69df4..4f26b58216 100644
--- a/tests/ref/fate/vp9-00-quantizer-30
+++ b/tests/ref/fate/vp9-00-quantizer-30
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, e3b3cea66ea38c5dfba1aa73bb4c611d
-0, 33, 33, 0, 152064, 42bb3e54b19c3f4c4f7ee3a6ba012e19
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, e3b3cea66ea38c5dfba1aa73bb4c611d
+0, 1, 1, 1, 152064, 42bb3e54b19c3f4c4f7ee3a6ba012e19
diff --git a/tests/ref/fate/vp9-00-quantizer-31 b/tests/ref/fate/vp9-00-quantizer-31
index 22c5749f99..4c9bf962ce 100644
--- a/tests/ref/fate/vp9-00-quantizer-31
+++ b/tests/ref/fate/vp9-00-quantizer-31
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 2523e9ecfd3781eafcd7da192dc105e9
-0, 33, 33, 0, 152064, 6d5feea012b9a1f51fc643633e728764
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 2523e9ecfd3781eafcd7da192dc105e9
+0, 1, 1, 1, 152064, 6d5feea012b9a1f51fc643633e728764
diff --git a/tests/ref/fate/vp9-00-quantizer-32 b/tests/ref/fate/vp9-00-quantizer-32
index 8103d9622e..ef49c4e056 100644
--- a/tests/ref/fate/vp9-00-quantizer-32
+++ b/tests/ref/fate/vp9-00-quantizer-32
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 0a0305eba36500ebf6cc6cc0f01f5a3b
-0, 33, 33, 0, 152064, 2c76bcd6763467f9057a726fbcf50ab1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 0a0305eba36500ebf6cc6cc0f01f5a3b
+0, 1, 1, 1, 152064, 2c76bcd6763467f9057a726fbcf50ab1
diff --git a/tests/ref/fate/vp9-00-quantizer-33 b/tests/ref/fate/vp9-00-quantizer-33
index ab7c061b98..374c44e1bf 100644
--- a/tests/ref/fate/vp9-00-quantizer-33
+++ b/tests/ref/fate/vp9-00-quantizer-33
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, c68433e0e94047c220be9b629334f744
-0, 33, 33, 0, 152064, fcfa4dff7a39bc9c5e315849ecbb46ea
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, c68433e0e94047c220be9b629334f744
+0, 1, 1, 1, 152064, fcfa4dff7a39bc9c5e315849ecbb46ea
diff --git a/tests/ref/fate/vp9-00-quantizer-34 b/tests/ref/fate/vp9-00-quantizer-34
index d5719ec096..aa9c833e30 100644
--- a/tests/ref/fate/vp9-00-quantizer-34
+++ b/tests/ref/fate/vp9-00-quantizer-34
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, ad9dc2f912c137b014a33e2792c88a25
-0, 33, 33, 0, 152064, 11221ee4ea5c776f43af68756682cd5a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, ad9dc2f912c137b014a33e2792c88a25
+0, 1, 1, 1, 152064, 11221ee4ea5c776f43af68756682cd5a
diff --git a/tests/ref/fate/vp9-00-quantizer-35 b/tests/ref/fate/vp9-00-quantizer-35
index 623d62c795..820725ba61 100644
--- a/tests/ref/fate/vp9-00-quantizer-35
+++ b/tests/ref/fate/vp9-00-quantizer-35
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 75031f898cccf303a64ab46b1f815389
-0, 33, 33, 0, 152064, a4fc864e7fbc470dfcab6207e0eea152
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 75031f898cccf303a64ab46b1f815389
+0, 1, 1, 1, 152064, a4fc864e7fbc470dfcab6207e0eea152
diff --git a/tests/ref/fate/vp9-00-quantizer-36 b/tests/ref/fate/vp9-00-quantizer-36
index e6cde4569c..4a39a13ff0 100644
--- a/tests/ref/fate/vp9-00-quantizer-36
+++ b/tests/ref/fate/vp9-00-quantizer-36
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, c7824af009fde6cafdd8d39fae6bb6cf
-0, 33, 33, 0, 152064, 516a82d5fc4dfa3daf713ed2ec36041b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, c7824af009fde6cafdd8d39fae6bb6cf
+0, 1, 1, 1, 152064, 516a82d5fc4dfa3daf713ed2ec36041b
diff --git a/tests/ref/fate/vp9-00-quantizer-37 b/tests/ref/fate/vp9-00-quantizer-37
index b4c01349b3..96e526f100 100644
--- a/tests/ref/fate/vp9-00-quantizer-37
+++ b/tests/ref/fate/vp9-00-quantizer-37
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, fb23e0bc64728a492a33d985032f21b8
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, fb23e0bc64728a492a33d985032f21b8
diff --git a/tests/ref/fate/vp9-00-quantizer-38 b/tests/ref/fate/vp9-00-quantizer-38
index 89e45f9c6d..9f61d330e3 100644
--- a/tests/ref/fate/vp9-00-quantizer-38
+++ b/tests/ref/fate/vp9-00-quantizer-38
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 8347bfb891317e89ef66781d6c28e24f
-0, 33, 33, 0, 152064, a5722f824d32deac042513a1a7dcdcd0
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 8347bfb891317e89ef66781d6c28e24f
+0, 1, 1, 1, 152064, a5722f824d32deac042513a1a7dcdcd0
diff --git a/tests/ref/fate/vp9-00-quantizer-39 b/tests/ref/fate/vp9-00-quantizer-39
index ed5add1b26..396a1a34f4 100644
--- a/tests/ref/fate/vp9-00-quantizer-39
+++ b/tests/ref/fate/vp9-00-quantizer-39
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 018968f97fac3bdff146cf22c1da5ef0
-0, 33, 33, 0, 152064, ca8b09b01e5132183395e238f1c7901e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 018968f97fac3bdff146cf22c1da5ef0
+0, 1, 1, 1, 152064, ca8b09b01e5132183395e238f1c7901e
diff --git a/tests/ref/fate/vp9-00-quantizer-40 b/tests/ref/fate/vp9-00-quantizer-40
index 8ac2b914c3..dc77394c12 100644
--- a/tests/ref/fate/vp9-00-quantizer-40
+++ b/tests/ref/fate/vp9-00-quantizer-40
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 792660f6589ad5340be4bd0554435866
-0, 33, 33, 0, 152064, 68c84c8a15d679e0a73678b93215c62c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 792660f6589ad5340be4bd0554435866
+0, 1, 1, 1, 152064, 68c84c8a15d679e0a73678b93215c62c
diff --git a/tests/ref/fate/vp9-00-quantizer-41 b/tests/ref/fate/vp9-00-quantizer-41
index ccd735db6c..667549cef6 100644
--- a/tests/ref/fate/vp9-00-quantizer-41
+++ b/tests/ref/fate/vp9-00-quantizer-41
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a456bdfc6c1c07b4cb3a3848843743b9
-0, 33, 33, 0, 152064, fe41a12b8cb6bc5667ba2179e076f3b0
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a456bdfc6c1c07b4cb3a3848843743b9
+0, 1, 1, 1, 152064, fe41a12b8cb6bc5667ba2179e076f3b0
diff --git a/tests/ref/fate/vp9-00-quantizer-42 b/tests/ref/fate/vp9-00-quantizer-42
index 3955ebfcdf..c7fbfbc247 100644
--- a/tests/ref/fate/vp9-00-quantizer-42
+++ b/tests/ref/fate/vp9-00-quantizer-42
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, f016dd8431694d989700fb1ba71a5b2d
-0, 33, 33, 0, 152064, e89c3c5b935157b40f2fb0ab92415828
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, f016dd8431694d989700fb1ba71a5b2d
+0, 1, 1, 1, 152064, e89c3c5b935157b40f2fb0ab92415828
diff --git a/tests/ref/fate/vp9-00-quantizer-43 b/tests/ref/fate/vp9-00-quantizer-43
index e458266113..090ce6f3ea 100644
--- a/tests/ref/fate/vp9-00-quantizer-43
+++ b/tests/ref/fate/vp9-00-quantizer-43
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 7b8ab82625f3006bac89d4fb5197e71c
-0, 33, 33, 0, 152064, 18bd3716045563dfba2c72b640b3274b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 7b8ab82625f3006bac89d4fb5197e71c
+0, 1, 1, 1, 152064, 18bd3716045563dfba2c72b640b3274b
diff --git a/tests/ref/fate/vp9-00-quantizer-44 b/tests/ref/fate/vp9-00-quantizer-44
index 178c224183..130b5fa341 100644
--- a/tests/ref/fate/vp9-00-quantizer-44
+++ b/tests/ref/fate/vp9-00-quantizer-44
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 66fde04d8320c750e56406feefd29979
-0, 33, 33, 0, 152064, f9d01d8fc1722ec345e624e14b404215
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 66fde04d8320c750e56406feefd29979
+0, 1, 1, 1, 152064, f9d01d8fc1722ec345e624e14b404215
diff --git a/tests/ref/fate/vp9-00-quantizer-45 b/tests/ref/fate/vp9-00-quantizer-45
index 4ab45e2043..5cb710590d 100644
--- a/tests/ref/fate/vp9-00-quantizer-45
+++ b/tests/ref/fate/vp9-00-quantizer-45
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, cc97597b015896d73f3e60e7ae44c4da
-0, 33, 33, 0, 152064, fea98bc508f92135641ab99762444b14
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, cc97597b015896d73f3e60e7ae44c4da
+0, 1, 1, 1, 152064, fea98bc508f92135641ab99762444b14
diff --git a/tests/ref/fate/vp9-00-quantizer-46 b/tests/ref/fate/vp9-00-quantizer-46
index df6c212627..cb51f72112 100644
--- a/tests/ref/fate/vp9-00-quantizer-46
+++ b/tests/ref/fate/vp9-00-quantizer-46
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 79ed95c741178bb3c0954f1f6f8e21a3
-0, 33, 33, 0, 152064, f02a06a5e2b5b7619c9a52c5bea0564d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 79ed95c741178bb3c0954f1f6f8e21a3
+0, 1, 1, 1, 152064, f02a06a5e2b5b7619c9a52c5bea0564d
diff --git a/tests/ref/fate/vp9-00-quantizer-47 b/tests/ref/fate/vp9-00-quantizer-47
index 7e6476e5c0..0bf90b4491 100644
--- a/tests/ref/fate/vp9-00-quantizer-47
+++ b/tests/ref/fate/vp9-00-quantizer-47
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 9b98e948b8c2a822f21bd8419e6f4410
-0, 33, 33, 0, 152064, 491382d68c16c2a3c6f1746598bc4a97
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 9b98e948b8c2a822f21bd8419e6f4410
+0, 1, 1, 1, 152064, 491382d68c16c2a3c6f1746598bc4a97
diff --git a/tests/ref/fate/vp9-00-quantizer-48 b/tests/ref/fate/vp9-00-quantizer-48
index 22a3ce2bd4..2604a533bb 100644
--- a/tests/ref/fate/vp9-00-quantizer-48
+++ b/tests/ref/fate/vp9-00-quantizer-48
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, f0f095b0edae7262f44d7ed7ef84ded4
-0, 33, 33, 0, 152064, 0e833889ccac81d60251007d1baf6500
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, f0f095b0edae7262f44d7ed7ef84ded4
+0, 1, 1, 1, 152064, 0e833889ccac81d60251007d1baf6500
diff --git a/tests/ref/fate/vp9-00-quantizer-49 b/tests/ref/fate/vp9-00-quantizer-49
index 34f74a6761..3403d1df1b 100644
--- a/tests/ref/fate/vp9-00-quantizer-49
+++ b/tests/ref/fate/vp9-00-quantizer-49
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 6c1b7b7827617fb9b8417aca2cfdbcaa
-0, 33, 33, 0, 152064, 4c1fc8a89297fdcf79f0faabd42b8684
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 6c1b7b7827617fb9b8417aca2cfdbcaa
+0, 1, 1, 1, 152064, 4c1fc8a89297fdcf79f0faabd42b8684
diff --git a/tests/ref/fate/vp9-00-quantizer-50 b/tests/ref/fate/vp9-00-quantizer-50
index e9d40affd3..f2cdc8ecc5 100644
--- a/tests/ref/fate/vp9-00-quantizer-50
+++ b/tests/ref/fate/vp9-00-quantizer-50
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, ca6142db68463487bc28c888ab38476c
-0, 33, 33, 0, 152064, 02a71153ec70f569524c3d814cb62f86
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, ca6142db68463487bc28c888ab38476c
+0, 1, 1, 1, 152064, 02a71153ec70f569524c3d814cb62f86
diff --git a/tests/ref/fate/vp9-00-quantizer-51 b/tests/ref/fate/vp9-00-quantizer-51
index 3a86326bee..87ab57e6c4 100644
--- a/tests/ref/fate/vp9-00-quantizer-51
+++ b/tests/ref/fate/vp9-00-quantizer-51
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, eece2627df1ddf0872256eb92352e179
-0, 33, 33, 0, 152064, 0ee9f221246ad747250e4b5e8ba586e2
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, eece2627df1ddf0872256eb92352e179
+0, 1, 1, 1, 152064, 0ee9f221246ad747250e4b5e8ba586e2
diff --git a/tests/ref/fate/vp9-00-quantizer-52 b/tests/ref/fate/vp9-00-quantizer-52
index 6d976d83bc..f3a14d13cc 100644
--- a/tests/ref/fate/vp9-00-quantizer-52
+++ b/tests/ref/fate/vp9-00-quantizer-52
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 7290039d974c4e50db9d69f9864bcdbe
-0, 33, 33, 0, 152064, 264765de9d02503038a4da54133b9f85
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 7290039d974c4e50db9d69f9864bcdbe
+0, 1, 1, 1, 152064, 264765de9d02503038a4da54133b9f85
diff --git a/tests/ref/fate/vp9-00-quantizer-53 b/tests/ref/fate/vp9-00-quantizer-53
index 5f2ab99263..784925db35 100644
--- a/tests/ref/fate/vp9-00-quantizer-53
+++ b/tests/ref/fate/vp9-00-quantizer-53
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 917af24da66f143a56a01eb2c2254285
-0, 33, 33, 0, 152064, 45a05d3bc644420519619e4115662a70
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 917af24da66f143a56a01eb2c2254285
+0, 1, 1, 1, 152064, 45a05d3bc644420519619e4115662a70
diff --git a/tests/ref/fate/vp9-00-quantizer-54 b/tests/ref/fate/vp9-00-quantizer-54
index 38c2496ab5..daa6f5d563 100644
--- a/tests/ref/fate/vp9-00-quantizer-54
+++ b/tests/ref/fate/vp9-00-quantizer-54
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 6fea2820bb10a9dec9add4d2452b01f5
-0, 33, 33, 0, 152064, 74675169a4bfc2ff5463c4db5d85a79f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 6fea2820bb10a9dec9add4d2452b01f5
+0, 1, 1, 1, 152064, 74675169a4bfc2ff5463c4db5d85a79f
diff --git a/tests/ref/fate/vp9-00-quantizer-55 b/tests/ref/fate/vp9-00-quantizer-55
index c50fdd4902..0a48cf9100 100644
--- a/tests/ref/fate/vp9-00-quantizer-55
+++ b/tests/ref/fate/vp9-00-quantizer-55
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 11e5d196f6537fb7d85988d90195e556
-0, 33, 33, 0, 152064, 8536106795f7c93c5a43a11493527469
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 11e5d196f6537fb7d85988d90195e556
+0, 1, 1, 1, 152064, 8536106795f7c93c5a43a11493527469
diff --git a/tests/ref/fate/vp9-00-quantizer-56 b/tests/ref/fate/vp9-00-quantizer-56
index 80bff693ad..f1f6069896 100644
--- a/tests/ref/fate/vp9-00-quantizer-56
+++ b/tests/ref/fate/vp9-00-quantizer-56
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 40839b7a3a40ec10f96b8a75224f646d
-0, 33, 33, 0, 152064, 11408dd73e8c45ddaab99f5c9650102b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 40839b7a3a40ec10f96b8a75224f646d
+0, 1, 1, 1, 152064, 11408dd73e8c45ddaab99f5c9650102b
diff --git a/tests/ref/fate/vp9-00-quantizer-57 b/tests/ref/fate/vp9-00-quantizer-57
index 38783aa8e4..499b57eada 100644
--- a/tests/ref/fate/vp9-00-quantizer-57
+++ b/tests/ref/fate/vp9-00-quantizer-57
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, d0e9fa03dd48da4592ebaadb4e3794e0
-0, 33, 33, 0, 152064, 5172e29b1e04cd543833d6a68aab297c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, d0e9fa03dd48da4592ebaadb4e3794e0
+0, 1, 1, 1, 152064, 5172e29b1e04cd543833d6a68aab297c
diff --git a/tests/ref/fate/vp9-00-quantizer-58 b/tests/ref/fate/vp9-00-quantizer-58
index 80ead0f3e8..2a10350790 100644
--- a/tests/ref/fate/vp9-00-quantizer-58
+++ b/tests/ref/fate/vp9-00-quantizer-58
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, bef4a27d460e7697e038fe6f1c8bd597
-0, 33, 33, 0, 152064, 124674686cafc5f2ff5bc7ea412b8f3b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, bef4a27d460e7697e038fe6f1c8bd597
+0, 1, 1, 1, 152064, 124674686cafc5f2ff5bc7ea412b8f3b
diff --git a/tests/ref/fate/vp9-00-quantizer-59 b/tests/ref/fate/vp9-00-quantizer-59
index dbc6a5d28b..8ae9bd30d4 100644
--- a/tests/ref/fate/vp9-00-quantizer-59
+++ b/tests/ref/fate/vp9-00-quantizer-59
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, ae9d99e9d16ef20073300559566844ae
-0, 33, 33, 0, 152064, da9405e5a6bfe4ed18d927ba2004008e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, ae9d99e9d16ef20073300559566844ae
+0, 1, 1, 1, 152064, da9405e5a6bfe4ed18d927ba2004008e
diff --git a/tests/ref/fate/vp9-00-quantizer-60 b/tests/ref/fate/vp9-00-quantizer-60
index c71532ed70..a4094623ad 100644
--- a/tests/ref/fate/vp9-00-quantizer-60
+++ b/tests/ref/fate/vp9-00-quantizer-60
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 9e66bb8e1b5e206ea4afe4bf2d335ac5
-0, 33, 33, 0, 152064, 092b74c905c12c1e87e90f5a79857736
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 9e66bb8e1b5e206ea4afe4bf2d335ac5
+0, 1, 1, 1, 152064, 092b74c905c12c1e87e90f5a79857736
diff --git a/tests/ref/fate/vp9-00-quantizer-61 b/tests/ref/fate/vp9-00-quantizer-61
index b453341345..92aa67f049 100644
--- a/tests/ref/fate/vp9-00-quantizer-61
+++ b/tests/ref/fate/vp9-00-quantizer-61
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, d062dc6be246c8042744018765ef50a8
-0, 33, 33, 0, 152064, 45fd9cbacb6a91060a7e49a58a85869d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, d062dc6be246c8042744018765ef50a8
+0, 1, 1, 1, 152064, 45fd9cbacb6a91060a7e49a58a85869d
diff --git a/tests/ref/fate/vp9-00-quantizer-62 b/tests/ref/fate/vp9-00-quantizer-62
index 1efa26f7bd..d17d3d65af 100644
--- a/tests/ref/fate/vp9-00-quantizer-62
+++ b/tests/ref/fate/vp9-00-quantizer-62
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 62f7e42fe653e81c5a65a25389e045b5
-0, 33, 33, 0, 152064, cb0cdd0b25689e0a43328550011d960d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 62f7e42fe653e81c5a65a25389e045b5
+0, 1, 1, 1, 152064, cb0cdd0b25689e0a43328550011d960d
diff --git a/tests/ref/fate/vp9-00-quantizer-63 b/tests/ref/fate/vp9-00-quantizer-63
index f47388440c..d7765beb42 100644
--- a/tests/ref/fate/vp9-00-quantizer-63
+++ b/tests/ref/fate/vp9-00-quantizer-63
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 8467643dceff827e04acd82eeff1d1b0
-0, 33, 33, 0, 152064, c786f49d66f4dfd685dea9605821a19f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 8467643dceff827e04acd82eeff1d1b0
+0, 1, 1, 1, 152064, c786f49d66f4dfd685dea9605821a19f
diff --git a/tests/ref/fate/vp9-01-sharpness-1 b/tests/ref/fate/vp9-01-sharpness-1
index 406bd61fc7..02e6e16603 100644
--- a/tests/ref/fate/vp9-01-sharpness-1
+++ b/tests/ref/fate/vp9-01-sharpness-1
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, aa20a75be3a316193496706c9f760d08
-0, 66, 66, 0, 152064, 95567be97a64d3c9efe45f2524116a2e
-0, 100, 100, 0, 152064, 219e86cd6b3cca312856eead21776b1c
-0, 133, 133, 0, 152064, 4a67fd359ca362398e97c15eb018a2bb
-0, 166, 166, 0, 152064, 9916d4e359274d690827f0eb22547423
-0, 200, 200, 0, 152064, a07785b52561150c48f1a8eff89d5d75
-0, 233, 233, 0, 152064, a3382a92982953dfa20018e5ac975b51
-0, 266, 266, 0, 152064, 911836989ca7b148438aa3ec7fc7e303
-0, 300, 300, 0, 152064, 5627b981e3fc9e4401d35d3a5ab25917
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, aa20a75be3a316193496706c9f760d08
+0, 2, 2, 1, 152064, 95567be97a64d3c9efe45f2524116a2e
+0, 3, 3, 1, 152064, 219e86cd6b3cca312856eead21776b1c
+0, 4, 4, 1, 152064, 4a67fd359ca362398e97c15eb018a2bb
+0, 5, 5, 1, 152064, 9916d4e359274d690827f0eb22547423
+0, 6, 6, 1, 152064, a07785b52561150c48f1a8eff89d5d75
+0, 7, 7, 1, 152064, a3382a92982953dfa20018e5ac975b51
+0, 8, 8, 1, 152064, 911836989ca7b148438aa3ec7fc7e303
+0, 9, 9, 1, 152064, 5627b981e3fc9e4401d35d3a5ab25917
diff --git a/tests/ref/fate/vp9-01-sharpness-2 b/tests/ref/fate/vp9-01-sharpness-2
index 78d7e9177f..51238c1966 100644
--- a/tests/ref/fate/vp9-01-sharpness-2
+++ b/tests/ref/fate/vp9-01-sharpness-2
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, cd94572239817ae7c9b07de739c3272b
-0, 66, 66, 0, 152064, 383cf752d457e122b5ff49d08960208e
-0, 100, 100, 0, 152064, 1c0a6ec9cd3ce29b8b004e7526f1b07e
-0, 133, 133, 0, 152064, 91c42a8a108d67947cabfc2a5a80df66
-0, 166, 166, 0, 152064, 08c57fc1f3fec0305883315a66c714d1
-0, 200, 200, 0, 152064, 70cb8d8dc83eac82f2d3c4b0376bb1aa
-0, 233, 233, 0, 152064, ffd62a9ef829ec81f0f74f740488a41f
-0, 266, 266, 0, 152064, bab0aa23b5854e2a70926046e4618710
-0, 300, 300, 0, 152064, fec456f38f2a43661e786a8d5f67ed15
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, cd94572239817ae7c9b07de739c3272b
+0, 2, 2, 1, 152064, 383cf752d457e122b5ff49d08960208e
+0, 3, 3, 1, 152064, 1c0a6ec9cd3ce29b8b004e7526f1b07e
+0, 4, 4, 1, 152064, 91c42a8a108d67947cabfc2a5a80df66
+0, 5, 5, 1, 152064, 08c57fc1f3fec0305883315a66c714d1
+0, 6, 6, 1, 152064, 70cb8d8dc83eac82f2d3c4b0376bb1aa
+0, 7, 7, 1, 152064, ffd62a9ef829ec81f0f74f740488a41f
+0, 8, 8, 1, 152064, bab0aa23b5854e2a70926046e4618710
+0, 9, 9, 1, 152064, fec456f38f2a43661e786a8d5f67ed15
diff --git a/tests/ref/fate/vp9-01-sharpness-3 b/tests/ref/fate/vp9-01-sharpness-3
index 541c7e9755..e1af6f6206 100644
--- a/tests/ref/fate/vp9-01-sharpness-3
+++ b/tests/ref/fate/vp9-01-sharpness-3
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, 0d487a146393a0b8b84b4be1b371b507
-0, 66, 66, 0, 152064, 68372e191eba620a431cfff226026ac3
-0, 100, 100, 0, 152064, de7fd274460e36b983fe93acc208d72f
-0, 133, 133, 0, 152064, afbd36c61bab65b98ff9acf08e215721
-0, 166, 166, 0, 152064, e1e9fc2ab4e7a187a8d8d84aae48d6b9
-0, 200, 200, 0, 152064, 11d95de6a9cc5e00511e99534779faac
-0, 233, 233, 0, 152064, cd2f5539fdfc2d8eefe6b6da28c13398
-0, 266, 266, 0, 152064, a8b3aeed41da7aeb8d5b962ee4a4af93
-0, 300, 300, 0, 152064, 4283670bd1c1c506ef18d3dafca22035
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, 0d487a146393a0b8b84b4be1b371b507
+0, 2, 2, 1, 152064, 68372e191eba620a431cfff226026ac3
+0, 3, 3, 1, 152064, de7fd274460e36b983fe93acc208d72f
+0, 4, 4, 1, 152064, afbd36c61bab65b98ff9acf08e215721
+0, 5, 5, 1, 152064, e1e9fc2ab4e7a187a8d8d84aae48d6b9
+0, 6, 6, 1, 152064, 11d95de6a9cc5e00511e99534779faac
+0, 7, 7, 1, 152064, cd2f5539fdfc2d8eefe6b6da28c13398
+0, 8, 8, 1, 152064, a8b3aeed41da7aeb8d5b962ee4a4af93
+0, 9, 9, 1, 152064, 4283670bd1c1c506ef18d3dafca22035
diff --git a/tests/ref/fate/vp9-01-sharpness-4 b/tests/ref/fate/vp9-01-sharpness-4
index df41b70565..977095ff5d 100644
--- a/tests/ref/fate/vp9-01-sharpness-4
+++ b/tests/ref/fate/vp9-01-sharpness-4
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, 8bad76c55b5149169d64ce6512521de6
-0, 66, 66, 0, 152064, c1d986e1f9bf46382e598ba289b9bd7c
-0, 100, 100, 0, 152064, 86c097ac6069c786023d3561dae68bac
-0, 133, 133, 0, 152064, 8c238a2831b8c7c49736b6de6ff76ed8
-0, 166, 166, 0, 152064, cb5a038ed0a74a317ee72dae93a7ee3e
-0, 200, 200, 0, 152064, f8fe330a257e3e4e4c39c1c12820a654
-0, 233, 233, 0, 152064, a73e2fcdcbb9334c0c123f8276a2c881
-0, 266, 266, 0, 152064, 24fccece8ee639e4d0e00e4060e1db0c
-0, 300, 300, 0, 152064, 46d6e9aad69a39c718c5fd1e41e86e6e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, 8bad76c55b5149169d64ce6512521de6
+0, 2, 2, 1, 152064, c1d986e1f9bf46382e598ba289b9bd7c
+0, 3, 3, 1, 152064, 86c097ac6069c786023d3561dae68bac
+0, 4, 4, 1, 152064, 8c238a2831b8c7c49736b6de6ff76ed8
+0, 5, 5, 1, 152064, cb5a038ed0a74a317ee72dae93a7ee3e
+0, 6, 6, 1, 152064, f8fe330a257e3e4e4c39c1c12820a654
+0, 7, 7, 1, 152064, a73e2fcdcbb9334c0c123f8276a2c881
+0, 8, 8, 1, 152064, 24fccece8ee639e4d0e00e4060e1db0c
+0, 9, 9, 1, 152064, 46d6e9aad69a39c718c5fd1e41e86e6e
diff --git a/tests/ref/fate/vp9-01-sharpness-5 b/tests/ref/fate/vp9-01-sharpness-5
index b183d6bea0..c0cf715863 100644
--- a/tests/ref/fate/vp9-01-sharpness-5
+++ b/tests/ref/fate/vp9-01-sharpness-5
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, f1ce0a5d57a46c9ff1331804b7b03fdb
-0, 66, 66, 0, 152064, 0364a085b06bee6b980189cf5378eda9
-0, 100, 100, 0, 152064, 4b5358698d734b0ae210909a913d4c1e
-0, 133, 133, 0, 152064, dc22565aaceee77b15fd8ab3c84bd5e0
-0, 166, 166, 0, 152064, 5f6340b656536292b46ba9a647aeb6e4
-0, 200, 200, 0, 152064, b7d4bce9a04b2a6caa45801be15e331e
-0, 233, 233, 0, 152064, 534c851cfe59ffc047815ece98d8cede
-0, 266, 266, 0, 152064, 786b0e1564d5c71aabfc2dd528cff4e7
-0, 300, 300, 0, 152064, cac0366209cf471bb7cc3e64966cbbd4
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, f1ce0a5d57a46c9ff1331804b7b03fdb
+0, 2, 2, 1, 152064, 0364a085b06bee6b980189cf5378eda9
+0, 3, 3, 1, 152064, 4b5358698d734b0ae210909a913d4c1e
+0, 4, 4, 1, 152064, dc22565aaceee77b15fd8ab3c84bd5e0
+0, 5, 5, 1, 152064, 5f6340b656536292b46ba9a647aeb6e4
+0, 6, 6, 1, 152064, b7d4bce9a04b2a6caa45801be15e331e
+0, 7, 7, 1, 152064, 534c851cfe59ffc047815ece98d8cede
+0, 8, 8, 1, 152064, 786b0e1564d5c71aabfc2dd528cff4e7
+0, 9, 9, 1, 152064, cac0366209cf471bb7cc3e64966cbbd4
diff --git a/tests/ref/fate/vp9-01-sharpness-6 b/tests/ref/fate/vp9-01-sharpness-6
index e0189a2744..2e52d32c5e 100644
--- a/tests/ref/fate/vp9-01-sharpness-6
+++ b/tests/ref/fate/vp9-01-sharpness-6
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, 45d9ca07ed04210b1ebc743169bc8ec4
-0, 66, 66, 0, 152064, 5b646cc309a711f1d8814f925002d8c4
-0, 100, 100, 0, 152064, 34db8db727fa1ded0a55cc7cf85be249
-0, 133, 133, 0, 152064, 54173d08afe6369b16a9c0c9cc6ce04d
-0, 166, 166, 0, 152064, 76275b0a478cdb3c1fb527ebbce023c3
-0, 200, 200, 0, 152064, e7643cdf0c42f2af700d8730bfc1a453
-0, 233, 233, 0, 152064, 6e53097e56f680cb658d63100e7736f7
-0, 266, 266, 0, 152064, 1a407c3c8ea1d5245ae68c5ce7de70e1
-0, 300, 300, 0, 152064, 6cbca24912cadf09b20be74f14e359c9
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, 45d9ca07ed04210b1ebc743169bc8ec4
+0, 2, 2, 1, 152064, 5b646cc309a711f1d8814f925002d8c4
+0, 3, 3, 1, 152064, 34db8db727fa1ded0a55cc7cf85be249
+0, 4, 4, 1, 152064, 54173d08afe6369b16a9c0c9cc6ce04d
+0, 5, 5, 1, 152064, 76275b0a478cdb3c1fb527ebbce023c3
+0, 6, 6, 1, 152064, e7643cdf0c42f2af700d8730bfc1a453
+0, 7, 7, 1, 152064, 6e53097e56f680cb658d63100e7736f7
+0, 8, 8, 1, 152064, 1a407c3c8ea1d5245ae68c5ce7de70e1
+0, 9, 9, 1, 152064, 6cbca24912cadf09b20be74f14e359c9
diff --git a/tests/ref/fate/vp9-01-sharpness-7 b/tests/ref/fate/vp9-01-sharpness-7
index 3fad7dc2b5..b2b5fda830 100644
--- a/tests/ref/fate/vp9-01-sharpness-7
+++ b/tests/ref/fate/vp9-01-sharpness-7
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, a2e5c820fd9733e18f9349fb658ca281
-0, 33, 33, 0, 152064, f719d0be18d16a448b4e7da3e2d9bf28
-0, 66, 66, 0, 152064, 83ee8ebc0ca796782a2376a76f2ffc26
-0, 100, 100, 0, 152064, 7cf5afdbc229e1af50a5377cfc23d831
-0, 133, 133, 0, 152064, 44244e896e0362f6376ba5afa563ba8b
-0, 166, 166, 0, 152064, df5f518d44eb6cb91b2df5a30d27ef82
-0, 200, 200, 0, 152064, 43cc3f151b8337aca7ee659c8abeb783
-0, 233, 233, 0, 152064, 4e89573470d9b97464e10806fc81aa8b
-0, 266, 266, 0, 152064, 62e0ba70f07ece8d85372f0a42e83a9a
-0, 300, 300, 0, 152064, 45ac2928acb11326f6c4a21401f3609c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, a2e5c820fd9733e18f9349fb658ca281
+0, 1, 1, 1, 152064, f719d0be18d16a448b4e7da3e2d9bf28
+0, 2, 2, 1, 152064, 83ee8ebc0ca796782a2376a76f2ffc26
+0, 3, 3, 1, 152064, 7cf5afdbc229e1af50a5377cfc23d831
+0, 4, 4, 1, 152064, 44244e896e0362f6376ba5afa563ba8b
+0, 5, 5, 1, 152064, df5f518d44eb6cb91b2df5a30d27ef82
+0, 6, 6, 1, 152064, 43cc3f151b8337aca7ee659c8abeb783
+0, 7, 7, 1, 152064, 4e89573470d9b97464e10806fc81aa8b
+0, 8, 8, 1, 152064, 62e0ba70f07ece8d85372f0a42e83a9a
+0, 9, 9, 1, 152064, 45ac2928acb11326f6c4a21401f3609c
diff --git a/tests/ref/fate/vp9-02-size-08x08 b/tests/ref/fate/vp9-02-size-08x08
index 51a27b35e2..403a131c23 100644
--- a/tests/ref/fate/vp9-02-size-08x08
+++ b/tests/ref/fate/vp9-02-size-08x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 96, 52def242c36123e5a8f5f53d6a971399
-0, 33, 33, 0, 96, 79c93360fbd47179400414bbfee0901c
-0, 66, 66, 0, 96, c3b1947c79537baa7838905276276a91
-0, 100, 100, 0, 96, 20f35e501bdee0bc63e87b9240265c25
-0, 133, 133, 0, 96, 5e8f1c464bafd54833c51860906b5368
-0, 166, 166, 0, 96, f57b592600dfc99e634a083278af769a
-0, 200, 200, 0, 96, 7b02191f85590cbad3f148c7b92d6436
-0, 233, 233, 0, 96, b0a1c9870447a1744f64cd4087ef55ee
-0, 266, 266, 0, 96, c82712b1ba7a95efb67cbdde0ad708b6
-0, 300, 300, 0, 96, 89f4539f8d7a7b45a91fd2f46335988e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 96, 52def242c36123e5a8f5f53d6a971399
+0, 1, 1, 1, 96, 79c93360fbd47179400414bbfee0901c
+0, 2, 2, 1, 96, c3b1947c79537baa7838905276276a91
+0, 3, 3, 1, 96, 20f35e501bdee0bc63e87b9240265c25
+0, 4, 4, 1, 96, 5e8f1c464bafd54833c51860906b5368
+0, 5, 5, 1, 96, f57b592600dfc99e634a083278af769a
+0, 6, 6, 1, 96, 7b02191f85590cbad3f148c7b92d6436
+0, 7, 7, 1, 96, b0a1c9870447a1744f64cd4087ef55ee
+0, 8, 8, 1, 96, c82712b1ba7a95efb67cbdde0ad708b6
+0, 9, 9, 1, 96, 89f4539f8d7a7b45a91fd2f46335988e
diff --git a/tests/ref/fate/vp9-02-size-08x10 b/tests/ref/fate/vp9-02-size-08x10
index 3829cfbb61..01d8818dc4 100644
--- a/tests/ref/fate/vp9-02-size-08x10
+++ b/tests/ref/fate/vp9-02-size-08x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 120, ea3e0f807304b0eb2d3e329b0124f75c
-0, 33, 33, 0, 120, 8d13cf682d63e7eb13094f55d67fc458
-0, 66, 66, 0, 120, e729cc6c3684c94a8f6118c618efc3ea
-0, 100, 100, 0, 120, ac43a0ace8e4112e877c2491ecc14fb5
-0, 133, 133, 0, 120, 53695f90b88d8e8cb838f0faec3238d3
-0, 166, 166, 0, 120, 40afd1c4dfd4a2e3b31631c46d252bcc
-0, 200, 200, 0, 120, 2b656f76f2e84d2f82d9bda2b5be94d3
-0, 233, 233, 0, 120, b22f004d678d047bc401be5e040cf883
-0, 266, 266, 0, 120, 57c840319abfb9c31013fbde54de3fb0
-0, 300, 300, 0, 120, 0f3dfc156216d7cfb6fd1d8c77dadab9
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 120, ea3e0f807304b0eb2d3e329b0124f75c
+0, 1, 1, 1, 120, 8d13cf682d63e7eb13094f55d67fc458
+0, 2, 2, 1, 120, e729cc6c3684c94a8f6118c618efc3ea
+0, 3, 3, 1, 120, ac43a0ace8e4112e877c2491ecc14fb5
+0, 4, 4, 1, 120, 53695f90b88d8e8cb838f0faec3238d3
+0, 5, 5, 1, 120, 40afd1c4dfd4a2e3b31631c46d252bcc
+0, 6, 6, 1, 120, 2b656f76f2e84d2f82d9bda2b5be94d3
+0, 7, 7, 1, 120, b22f004d678d047bc401be5e040cf883
+0, 8, 8, 1, 120, 57c840319abfb9c31013fbde54de3fb0
+0, 9, 9, 1, 120, 0f3dfc156216d7cfb6fd1d8c77dadab9
diff --git a/tests/ref/fate/vp9-02-size-08x16 b/tests/ref/fate/vp9-02-size-08x16
index c2e0a68ebb..d72aafc839 100644
--- a/tests/ref/fate/vp9-02-size-08x16
+++ b/tests/ref/fate/vp9-02-size-08x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 192, 0553e56a9d89aea496421885aab491f5
-0, 33, 33, 0, 192, b2a14cf676f7ebf3c50450050f76ad16
-0, 66, 66, 0, 192, a308d981e09b50571fb0c8ebdcefe505
-0, 100, 100, 0, 192, d592ec625a0ac0373e82610c3eed9864
-0, 133, 133, 0, 192, acd19642455e643023b4fb882c3891ba
-0, 166, 166, 0, 192, 5af5390fd8c29b795e0ddf83f3f34284
-0, 200, 200, 0, 192, 473505aa2a76231725cf2107d6c9dbef
-0, 233, 233, 0, 192, 84860db6887e320f2d64f80cf0032e57
-0, 266, 266, 0, 192, 408e9cf60e99ae99d204ff08f3196d1a
-0, 300, 300, 0, 192, d8af96b79258f9382e911ed38340bdf5
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 192, 0553e56a9d89aea496421885aab491f5
+0, 1, 1, 1, 192, b2a14cf676f7ebf3c50450050f76ad16
+0, 2, 2, 1, 192, a308d981e09b50571fb0c8ebdcefe505
+0, 3, 3, 1, 192, d592ec625a0ac0373e82610c3eed9864
+0, 4, 4, 1, 192, acd19642455e643023b4fb882c3891ba
+0, 5, 5, 1, 192, 5af5390fd8c29b795e0ddf83f3f34284
+0, 6, 6, 1, 192, 473505aa2a76231725cf2107d6c9dbef
+0, 7, 7, 1, 192, 84860db6887e320f2d64f80cf0032e57
+0, 8, 8, 1, 192, 408e9cf60e99ae99d204ff08f3196d1a
+0, 9, 9, 1, 192, d8af96b79258f9382e911ed38340bdf5
diff --git a/tests/ref/fate/vp9-02-size-08x18 b/tests/ref/fate/vp9-02-size-08x18
index 8b7470d5b2..8615d7b24b 100644
--- a/tests/ref/fate/vp9-02-size-08x18
+++ b/tests/ref/fate/vp9-02-size-08x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 216, 4c41f93b1b280b37bc77d7047435eaa4
-0, 33, 33, 0, 216, c9c80fdba2ebc2b8c3490ae35e34f84f
-0, 66, 66, 0, 216, 089d86acb3263fa5ef4f591a7f44556d
-0, 100, 100, 0, 216, 938fca6d93b83484144f5054e4838a41
-0, 133, 133, 0, 216, e0592e2ac9f5e09525ce0d3904cadf47
-0, 166, 166, 0, 216, ea43ff5d1330986e60c08567262ea764
-0, 200, 200, 0, 216, 08b40fe109ee90188f1cba9bbb1b376e
-0, 233, 233, 0, 216, b067068a2a7e36d5c5b5b405a1e73a18
-0, 266, 266, 0, 216, 9cf2d350296288803434b7451bd2be85
-0, 300, 300, 0, 216, 3c785e21dc228d6396738fbfcb470289
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 216, 4c41f93b1b280b37bc77d7047435eaa4
+0, 1, 1, 1, 216, c9c80fdba2ebc2b8c3490ae35e34f84f
+0, 2, 2, 1, 216, 089d86acb3263fa5ef4f591a7f44556d
+0, 3, 3, 1, 216, 938fca6d93b83484144f5054e4838a41
+0, 4, 4, 1, 216, e0592e2ac9f5e09525ce0d3904cadf47
+0, 5, 5, 1, 216, ea43ff5d1330986e60c08567262ea764
+0, 6, 6, 1, 216, 08b40fe109ee90188f1cba9bbb1b376e
+0, 7, 7, 1, 216, b067068a2a7e36d5c5b5b405a1e73a18
+0, 8, 8, 1, 216, 9cf2d350296288803434b7451bd2be85
+0, 9, 9, 1, 216, 3c785e21dc228d6396738fbfcb470289
diff --git a/tests/ref/fate/vp9-02-size-08x32 b/tests/ref/fate/vp9-02-size-08x32
index 7d3841f408..55ab620f5c 100644
--- a/tests/ref/fate/vp9-02-size-08x32
+++ b/tests/ref/fate/vp9-02-size-08x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 384, f92a7777fd69aa2f2914d9a41c4828ba
-0, 33, 33, 0, 384, 62e1cc73487d2249a88a60e35a22d9c7
-0, 66, 66, 0, 384, aa2619b605cb65eda15fdd99d5775550
-0, 100, 100, 0, 384, e6f0a491c543b835d0cefe5ca62c3dbe
-0, 133, 133, 0, 384, 361be1a06913c398f09494ca1b2d288f
-0, 166, 166, 0, 384, 0497bf849a973357c0ccb8d43f5bd8b4
-0, 200, 200, 0, 384, 5ac6ac523147c409dd00820622161dd7
-0, 233, 233, 0, 384, 7d07245574a46c524360f09be29a5f19
-0, 266, 266, 0, 384, fcfa7fbcaf42f81e4e34a4ee5a029ca1
-0, 300, 300, 0, 384, 336e3fe4f15d3d6c82d82b1855dcfeb4
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 384, f92a7777fd69aa2f2914d9a41c4828ba
+0, 1, 1, 1, 384, 62e1cc73487d2249a88a60e35a22d9c7
+0, 2, 2, 1, 384, aa2619b605cb65eda15fdd99d5775550
+0, 3, 3, 1, 384, e6f0a491c543b835d0cefe5ca62c3dbe
+0, 4, 4, 1, 384, 361be1a06913c398f09494ca1b2d288f
+0, 5, 5, 1, 384, 0497bf849a973357c0ccb8d43f5bd8b4
+0, 6, 6, 1, 384, 5ac6ac523147c409dd00820622161dd7
+0, 7, 7, 1, 384, 7d07245574a46c524360f09be29a5f19
+0, 8, 8, 1, 384, fcfa7fbcaf42f81e4e34a4ee5a029ca1
+0, 9, 9, 1, 384, 336e3fe4f15d3d6c82d82b1855dcfeb4
diff --git a/tests/ref/fate/vp9-02-size-08x34 b/tests/ref/fate/vp9-02-size-08x34
index affba3788b..bdcedbf971 100644
--- a/tests/ref/fate/vp9-02-size-08x34
+++ b/tests/ref/fate/vp9-02-size-08x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 408, f3f2cd8f157466ff23dace85d77367ce
-0, 33, 33, 0, 408, 639d9b70a14062e95559c12d2b597f91
-0, 66, 66, 0, 408, b2ee07a6656af583f19593229fa11848
-0, 100, 100, 0, 408, 74e3b5ab4c798a0afe745694e871bbd5
-0, 133, 133, 0, 408, 35f1c30d0f8678f319a392a6c53b5989
-0, 166, 166, 0, 408, 07e2b4c0b92a394bfb11124fe80476f0
-0, 200, 200, 0, 408, 7864bd20dfc5280e5f027d67ea22bf30
-0, 233, 233, 0, 408, 10a2925a7b91dfa9b82de76069388fd4
-0, 266, 266, 0, 408, 79cc7f7a149e8d6e04e065f75e63733c
-0, 300, 300, 0, 408, 6453d10d97532d9bb03f7c06cba9fca0
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 408, f3f2cd8f157466ff23dace85d77367ce
+0, 1, 1, 1, 408, 639d9b70a14062e95559c12d2b597f91
+0, 2, 2, 1, 408, b2ee07a6656af583f19593229fa11848
+0, 3, 3, 1, 408, 74e3b5ab4c798a0afe745694e871bbd5
+0, 4, 4, 1, 408, 35f1c30d0f8678f319a392a6c53b5989
+0, 5, 5, 1, 408, 07e2b4c0b92a394bfb11124fe80476f0
+0, 6, 6, 1, 408, 7864bd20dfc5280e5f027d67ea22bf30
+0, 7, 7, 1, 408, 10a2925a7b91dfa9b82de76069388fd4
+0, 8, 8, 1, 408, 79cc7f7a149e8d6e04e065f75e63733c
+0, 9, 9, 1, 408, 6453d10d97532d9bb03f7c06cba9fca0
diff --git a/tests/ref/fate/vp9-02-size-08x64 b/tests/ref/fate/vp9-02-size-08x64
index 506f39fa1b..3226dfa0a8 100644
--- a/tests/ref/fate/vp9-02-size-08x64
+++ b/tests/ref/fate/vp9-02-size-08x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 768, 764bd02b781a38c621a109c12f3d9393
-0, 33, 33, 0, 768, 79496bd2b9212026af816b3b7a0587d5
-0, 66, 66, 0, 768, 2a3afd47ba3d075033fd94d5c3746c45
-0, 100, 100, 0, 768, fca00cad8d37a6646337baebadd0ca31
-0, 133, 133, 0, 768, aca376fb3f8a5ef670ecc2430037262a
-0, 166, 166, 0, 768, 7e6c8d96d1e24855c3e380f1bf2ce02c
-0, 200, 200, 0, 768, 09e051241972969d439f27f324d78490
-0, 233, 233, 0, 768, 2566b2a425caaba41305bf04ff10ea01
-0, 266, 266, 0, 768, db3995bedee42ada1b4ee63c339daf1b
-0, 300, 300, 0, 768, b00b8f1bf4fd907f0487738f5b5442c6
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 768, 764bd02b781a38c621a109c12f3d9393
+0, 1, 1, 1, 768, 79496bd2b9212026af816b3b7a0587d5
+0, 2, 2, 1, 768, 2a3afd47ba3d075033fd94d5c3746c45
+0, 3, 3, 1, 768, fca00cad8d37a6646337baebadd0ca31
+0, 4, 4, 1, 768, aca376fb3f8a5ef670ecc2430037262a
+0, 5, 5, 1, 768, 7e6c8d96d1e24855c3e380f1bf2ce02c
+0, 6, 6, 1, 768, 09e051241972969d439f27f324d78490
+0, 7, 7, 1, 768, 2566b2a425caaba41305bf04ff10ea01
+0, 8, 8, 1, 768, db3995bedee42ada1b4ee63c339daf1b
+0, 9, 9, 1, 768, b00b8f1bf4fd907f0487738f5b5442c6
diff --git a/tests/ref/fate/vp9-02-size-08x66 b/tests/ref/fate/vp9-02-size-08x66
index 6ef07a075c..7aaa369d77 100644
--- a/tests/ref/fate/vp9-02-size-08x66
+++ b/tests/ref/fate/vp9-02-size-08x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 792, df20e8df89449fe50bb610e95a449a95
-0, 33, 33, 0, 792, 18f1a66d463274d1b0489f3a50e86857
-0, 66, 66, 0, 792, b0cc102875a94c9a92e53826617adbe9
-0, 100, 100, 0, 792, dfece7c17b4b149283ef51bdc1bd440e
-0, 133, 133, 0, 792, 6e346884f67be259fcabe493109cb63c
-0, 166, 166, 0, 792, 6d282127311eb2d958377490d7cb77f0
-0, 200, 200, 0, 792, 637ac8b14ca5ddbaf7b8910406c3cd08
-0, 233, 233, 0, 792, e7980f3fcb36969da0d218c4389fa9e8
-0, 266, 266, 0, 792, 730a1c95b9fb165f6e1a2f33a0d25de0
-0, 300, 300, 0, 792, 7bd8424d0783b1c8ad617e17408371bb
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 792, df20e8df89449fe50bb610e95a449a95
+0, 1, 1, 1, 792, 18f1a66d463274d1b0489f3a50e86857
+0, 2, 2, 1, 792, b0cc102875a94c9a92e53826617adbe9
+0, 3, 3, 1, 792, dfece7c17b4b149283ef51bdc1bd440e
+0, 4, 4, 1, 792, 6e346884f67be259fcabe493109cb63c
+0, 5, 5, 1, 792, 6d282127311eb2d958377490d7cb77f0
+0, 6, 6, 1, 792, 637ac8b14ca5ddbaf7b8910406c3cd08
+0, 7, 7, 1, 792, e7980f3fcb36969da0d218c4389fa9e8
+0, 8, 8, 1, 792, 730a1c95b9fb165f6e1a2f33a0d25de0
+0, 9, 9, 1, 792, 7bd8424d0783b1c8ad617e17408371bb
diff --git a/tests/ref/fate/vp9-02-size-10x08 b/tests/ref/fate/vp9-02-size-10x08
index f9ea55bd42..5708cd3515 100644
--- a/tests/ref/fate/vp9-02-size-10x08
+++ b/tests/ref/fate/vp9-02-size-10x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 120, e1e66a88615da98523ef887f1463fc42
-0, 33, 33, 0, 120, 549842fa98c8faf572882d38b0aae390
-0, 66, 66, 0, 120, 17ee85785517705fdc78c6122a4b2548
-0, 100, 100, 0, 120, 1143391d419dac30a6c11f366157c974
-0, 133, 133, 0, 120, b62d2a962c4c36809ef75a610106715c
-0, 166, 166, 0, 120, e6f143ca33fbc0e776bb149950cdedff
-0, 200, 200, 0, 120, 01716a1077ec66df00474fd4510d2789
-0, 233, 233, 0, 120, 8cb5b6a865fa2cbb15f0d7736fda88a6
-0, 266, 266, 0, 120, 0fb9fd883e895a540fe1704dddbbab04
-0, 300, 300, 0, 120, 150a3b99aa24ef102c92f87c8adb4386
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 120, e1e66a88615da98523ef887f1463fc42
+0, 1, 1, 1, 120, 549842fa98c8faf572882d38b0aae390
+0, 2, 2, 1, 120, 17ee85785517705fdc78c6122a4b2548
+0, 3, 3, 1, 120, 1143391d419dac30a6c11f366157c974
+0, 4, 4, 1, 120, b62d2a962c4c36809ef75a610106715c
+0, 5, 5, 1, 120, e6f143ca33fbc0e776bb149950cdedff
+0, 6, 6, 1, 120, 01716a1077ec66df00474fd4510d2789
+0, 7, 7, 1, 120, 8cb5b6a865fa2cbb15f0d7736fda88a6
+0, 8, 8, 1, 120, 0fb9fd883e895a540fe1704dddbbab04
+0, 9, 9, 1, 120, 150a3b99aa24ef102c92f87c8adb4386
diff --git a/tests/ref/fate/vp9-02-size-10x10 b/tests/ref/fate/vp9-02-size-10x10
index cff03c2b3b..a60e36bf5b 100644
--- a/tests/ref/fate/vp9-02-size-10x10
+++ b/tests/ref/fate/vp9-02-size-10x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 150, 083d638f2e147295d817bb14fff5e4f4
-0, 33, 33, 0, 150, 6dbdc445b6fd6bb99f2025cc2a40977e
-0, 66, 66, 0, 150, 41714089383b181d64fbfa7de5904608
-0, 100, 100, 0, 150, 11fdb8465e1599f7a9227706646d2cba
-0, 133, 133, 0, 150, 907876b3342a10040db0851a936af4e3
-0, 166, 166, 0, 150, e7b18d47d06b25de205d873d3d941640
-0, 200, 200, 0, 150, 523ce7413c8da7f6a657a9b661f36c44
-0, 233, 233, 0, 150, 23caff863af875c66c903662a3e1e6a1
-0, 266, 266, 0, 150, ed4cc5557203e5b7a119112ee9ceb00b
-0, 300, 300, 0, 150, 4bb78a996be3188888d1c60e11a08e1b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 150, 083d638f2e147295d817bb14fff5e4f4
+0, 1, 1, 1, 150, 6dbdc445b6fd6bb99f2025cc2a40977e
+0, 2, 2, 1, 150, 41714089383b181d64fbfa7de5904608
+0, 3, 3, 1, 150, 11fdb8465e1599f7a9227706646d2cba
+0, 4, 4, 1, 150, 907876b3342a10040db0851a936af4e3
+0, 5, 5, 1, 150, e7b18d47d06b25de205d873d3d941640
+0, 6, 6, 1, 150, 523ce7413c8da7f6a657a9b661f36c44
+0, 7, 7, 1, 150, 23caff863af875c66c903662a3e1e6a1
+0, 8, 8, 1, 150, ed4cc5557203e5b7a119112ee9ceb00b
+0, 9, 9, 1, 150, 4bb78a996be3188888d1c60e11a08e1b
diff --git a/tests/ref/fate/vp9-02-size-10x16 b/tests/ref/fate/vp9-02-size-10x16
index 9f9f5fe4cb..659d491ab7 100644
--- a/tests/ref/fate/vp9-02-size-10x16
+++ b/tests/ref/fate/vp9-02-size-10x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 240, fab07d6209d2413e0a434e1aaaa12154
-0, 33, 33, 0, 240, f9ffffdb96f98527ba2e553d1265edbb
-0, 66, 66, 0, 240, 56a992264cf7da2b23dd97435e9d0365
-0, 100, 100, 0, 240, b1db980423d8004bd45a789b02b92a65
-0, 133, 133, 0, 240, b29496aedc7026566367b634f55ebb28
-0, 166, 166, 0, 240, 2bc9def672da4a2fc17cbd669e2b8081
-0, 200, 200, 0, 240, 8c54721514cdf577a52a8668b9135f13
-0, 233, 233, 0, 240, 2efab81d5e039d82b3bc7b0303b022c4
-0, 266, 266, 0, 240, bd0f42b91b5d126fd0baec765b1096ad
-0, 300, 300, 0, 240, c6bfea2735a629167bc6a7a7c76eb7f3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 240, fab07d6209d2413e0a434e1aaaa12154
+0, 1, 1, 1, 240, f9ffffdb96f98527ba2e553d1265edbb
+0, 2, 2, 1, 240, 56a992264cf7da2b23dd97435e9d0365
+0, 3, 3, 1, 240, b1db980423d8004bd45a789b02b92a65
+0, 4, 4, 1, 240, b29496aedc7026566367b634f55ebb28
+0, 5, 5, 1, 240, 2bc9def672da4a2fc17cbd669e2b8081
+0, 6, 6, 1, 240, 8c54721514cdf577a52a8668b9135f13
+0, 7, 7, 1, 240, 2efab81d5e039d82b3bc7b0303b022c4
+0, 8, 8, 1, 240, bd0f42b91b5d126fd0baec765b1096ad
+0, 9, 9, 1, 240, c6bfea2735a629167bc6a7a7c76eb7f3
diff --git a/tests/ref/fate/vp9-02-size-10x18 b/tests/ref/fate/vp9-02-size-10x18
index 3f1e9f1cb0..d4069c9be4 100644
--- a/tests/ref/fate/vp9-02-size-10x18
+++ b/tests/ref/fate/vp9-02-size-10x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 270, 0e9182e214aae732d94d007e5fe44888
-0, 33, 33, 0, 270, 2630e2674b5611d68218fddac08815e2
-0, 66, 66, 0, 270, d5cdd7d6a3de17939f60bb60ef6877da
-0, 100, 100, 0, 270, 29d1961096061029e78963fa82581eca
-0, 133, 133, 0, 270, 5c2629f8aa59757f6b4aafa9f6cbcba1
-0, 166, 166, 0, 270, 1f1a8b61e4fbd6222ddf42e9d0a07032
-0, 200, 200, 0, 270, cfb9771190ac2d0129907102d6abb63f
-0, 233, 233, 0, 270, cd98dd856ba573a26a943cbe53221f26
-0, 266, 266, 0, 270, ca13c161f067c4a4ce22bd58a2aca55b
-0, 300, 300, 0, 270, de4bd1a474a76a35b796a5fc45b4f893
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 270, 0e9182e214aae732d94d007e5fe44888
+0, 1, 1, 1, 270, 2630e2674b5611d68218fddac08815e2
+0, 2, 2, 1, 270, d5cdd7d6a3de17939f60bb60ef6877da
+0, 3, 3, 1, 270, 29d1961096061029e78963fa82581eca
+0, 4, 4, 1, 270, 5c2629f8aa59757f6b4aafa9f6cbcba1
+0, 5, 5, 1, 270, 1f1a8b61e4fbd6222ddf42e9d0a07032
+0, 6, 6, 1, 270, cfb9771190ac2d0129907102d6abb63f
+0, 7, 7, 1, 270, cd98dd856ba573a26a943cbe53221f26
+0, 8, 8, 1, 270, ca13c161f067c4a4ce22bd58a2aca55b
+0, 9, 9, 1, 270, de4bd1a474a76a35b796a5fc45b4f893
diff --git a/tests/ref/fate/vp9-02-size-10x32 b/tests/ref/fate/vp9-02-size-10x32
index 5ca7bee024..f5ec31cd89 100644
--- a/tests/ref/fate/vp9-02-size-10x32
+++ b/tests/ref/fate/vp9-02-size-10x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 480, 622e6407a051ea08706394d03330ffbf
-0, 33, 33, 0, 480, 1841a0daf7c3ef7be94e01fdb1d3968a
-0, 66, 66, 0, 480, 37790e6cb2415f7add0ac5d3ab354755
-0, 100, 100, 0, 480, 91485880e17c292096a7335566d3648f
-0, 133, 133, 0, 480, eb6f74983d5fd13d6bd90afbce8836e1
-0, 166, 166, 0, 480, 0069ab5ff7f0d4d601f7d0f9b7a08338
-0, 200, 200, 0, 480, dbf04254765f7497070387e8c34895c6
-0, 233, 233, 0, 480, 410a9b2d9855b2c29618070994adae96
-0, 266, 266, 0, 480, 7e7f34effd90209f29f1b9ae01488b3b
-0, 300, 300, 0, 480, 471530f74082c01c9b0f1fcf3d240d77
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 480, 622e6407a051ea08706394d03330ffbf
+0, 1, 1, 1, 480, 1841a0daf7c3ef7be94e01fdb1d3968a
+0, 2, 2, 1, 480, 37790e6cb2415f7add0ac5d3ab354755
+0, 3, 3, 1, 480, 91485880e17c292096a7335566d3648f
+0, 4, 4, 1, 480, eb6f74983d5fd13d6bd90afbce8836e1
+0, 5, 5, 1, 480, 0069ab5ff7f0d4d601f7d0f9b7a08338
+0, 6, 6, 1, 480, dbf04254765f7497070387e8c34895c6
+0, 7, 7, 1, 480, 410a9b2d9855b2c29618070994adae96
+0, 8, 8, 1, 480, 7e7f34effd90209f29f1b9ae01488b3b
+0, 9, 9, 1, 480, 471530f74082c01c9b0f1fcf3d240d77
diff --git a/tests/ref/fate/vp9-02-size-10x34 b/tests/ref/fate/vp9-02-size-10x34
index e61e65da74..950b04e652 100644
--- a/tests/ref/fate/vp9-02-size-10x34
+++ b/tests/ref/fate/vp9-02-size-10x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 510, bfeeaf51f972fd0dfe9ee757083cbb54
-0, 33, 33, 0, 510, 10cd4ed6d762004846412d9cd0caa407
-0, 66, 66, 0, 510, 04cca4008d656ed180de88dd2ddb4f21
-0, 100, 100, 0, 510, ec777e377836895748c06849fa35ed2d
-0, 133, 133, 0, 510, b55633d0f9239dff3e45a4abce4a35a7
-0, 166, 166, 0, 510, 063c3ab4b4c599942c3a8a5b7bfe5029
-0, 200, 200, 0, 510, 07b920169d32b5fc51d5b9ae16fef5bf
-0, 233, 233, 0, 510, 8d49e727db9d3072b5ab7bab2133d9be
-0, 266, 266, 0, 510, 17441437203447e946a57d2f96966332
-0, 300, 300, 0, 510, 5d3f14af0e5cd81d0c7d2059f13efa5a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 510, bfeeaf51f972fd0dfe9ee757083cbb54
+0, 1, 1, 1, 510, 10cd4ed6d762004846412d9cd0caa407
+0, 2, 2, 1, 510, 04cca4008d656ed180de88dd2ddb4f21
+0, 3, 3, 1, 510, ec777e377836895748c06849fa35ed2d
+0, 4, 4, 1, 510, b55633d0f9239dff3e45a4abce4a35a7
+0, 5, 5, 1, 510, 063c3ab4b4c599942c3a8a5b7bfe5029
+0, 6, 6, 1, 510, 07b920169d32b5fc51d5b9ae16fef5bf
+0, 7, 7, 1, 510, 8d49e727db9d3072b5ab7bab2133d9be
+0, 8, 8, 1, 510, 17441437203447e946a57d2f96966332
+0, 9, 9, 1, 510, 5d3f14af0e5cd81d0c7d2059f13efa5a
diff --git a/tests/ref/fate/vp9-02-size-10x64 b/tests/ref/fate/vp9-02-size-10x64
index 9a9401f7ac..04a5e7e2fe 100644
--- a/tests/ref/fate/vp9-02-size-10x64
+++ b/tests/ref/fate/vp9-02-size-10x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 960, 835254d0eecb17bed1f2b0f3a1638165
-0, 33, 33, 0, 960, c0c95ce9890eab339a0e0f8b26cb095c
-0, 66, 66, 0, 960, f0337d645ade07cb716952b0d19352e8
-0, 100, 100, 0, 960, 7e3deb21cb3f0ead90c8af94464cde14
-0, 133, 133, 0, 960, c6b1ca6cfce358c411c0637c581157c8
-0, 166, 166, 0, 960, 10fce3f11f1ce90286ff4d74fe44fcfd
-0, 200, 200, 0, 960, ee0565a1f121bc905a35550619127a50
-0, 233, 233, 0, 960, 0624b601d379616eb792c94be60b6c91
-0, 266, 266, 0, 960, a1bb79cdf347548f1103f580f2b6930f
-0, 300, 300, 0, 960, 40e96e16c7e065aa7932e5aa57f32398
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 960, 835254d0eecb17bed1f2b0f3a1638165
+0, 1, 1, 1, 960, c0c95ce9890eab339a0e0f8b26cb095c
+0, 2, 2, 1, 960, f0337d645ade07cb716952b0d19352e8
+0, 3, 3, 1, 960, 7e3deb21cb3f0ead90c8af94464cde14
+0, 4, 4, 1, 960, c6b1ca6cfce358c411c0637c581157c8
+0, 5, 5, 1, 960, 10fce3f11f1ce90286ff4d74fe44fcfd
+0, 6, 6, 1, 960, ee0565a1f121bc905a35550619127a50
+0, 7, 7, 1, 960, 0624b601d379616eb792c94be60b6c91
+0, 8, 8, 1, 960, a1bb79cdf347548f1103f580f2b6930f
+0, 9, 9, 1, 960, 40e96e16c7e065aa7932e5aa57f32398
diff --git a/tests/ref/fate/vp9-02-size-10x66 b/tests/ref/fate/vp9-02-size-10x66
index ef9fa1b8a6..f26965ac76 100644
--- a/tests/ref/fate/vp9-02-size-10x66
+++ b/tests/ref/fate/vp9-02-size-10x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 990, 1bd8b2d3bf679c4b925780bf82e12fae
-0, 33, 33, 0, 990, a0254b4cd4928fe1080cd6f8828288a9
-0, 66, 66, 0, 990, e416e99644cca481dc2806708d716ecb
-0, 100, 100, 0, 990, b1ed3203ffc77ed814f1cda7bfe721d2
-0, 133, 133, 0, 990, 0ff7b9d84765f7b0b0650775ba72b334
-0, 166, 166, 0, 990, 8b6cd91e035bad19b46b132bd411231d
-0, 200, 200, 0, 990, c714759a9a64402043ad00e5677c954c
-0, 233, 233, 0, 990, 8e4738010b724ce66bcd0a5d5afcfbc1
-0, 266, 266, 0, 990, 998a7aab8ed94f4b69bed39fb487f8d5
-0, 300, 300, 0, 990, 9964683a15a65c032631a4f608e6009b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 990, 1bd8b2d3bf679c4b925780bf82e12fae
+0, 1, 1, 1, 990, a0254b4cd4928fe1080cd6f8828288a9
+0, 2, 2, 1, 990, e416e99644cca481dc2806708d716ecb
+0, 3, 3, 1, 990, b1ed3203ffc77ed814f1cda7bfe721d2
+0, 4, 4, 1, 990, 0ff7b9d84765f7b0b0650775ba72b334
+0, 5, 5, 1, 990, 8b6cd91e035bad19b46b132bd411231d
+0, 6, 6, 1, 990, c714759a9a64402043ad00e5677c954c
+0, 7, 7, 1, 990, 8e4738010b724ce66bcd0a5d5afcfbc1
+0, 8, 8, 1, 990, 998a7aab8ed94f4b69bed39fb487f8d5
+0, 9, 9, 1, 990, 9964683a15a65c032631a4f608e6009b
diff --git a/tests/ref/fate/vp9-02-size-16x08 b/tests/ref/fate/vp9-02-size-16x08
index aac95a3c9a..84e9b17189 100644
--- a/tests/ref/fate/vp9-02-size-16x08
+++ b/tests/ref/fate/vp9-02-size-16x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 192, 68dccd167f9aa18df0840ebb8715eb68
-0, 33, 33, 0, 192, 65c90bb99fdbee7abf21031d34cb18dc
-0, 66, 66, 0, 192, 9ef1feb2dcbd4d73f3ee84e9e1cd2668
-0, 100, 100, 0, 192, b6281f7c88e9aa132d3902046f8cde5a
-0, 133, 133, 0, 192, 4b439b716a294bddf9f56a229705907b
-0, 166, 166, 0, 192, d42c0a6f0d24522c90bc2233bc1df2c7
-0, 200, 200, 0, 192, 74b763a5a12c4c4a581efb1818a92970
-0, 233, 233, 0, 192, 0c3a0916ddfda5abdd3ac382f036e71f
-0, 266, 266, 0, 192, 26ff590e8ae726f70e8b36f5eaee7a19
-0, 300, 300, 0, 192, 30fa5810995d7132387ea585c4a1cc3a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 192, 68dccd167f9aa18df0840ebb8715eb68
+0, 1, 1, 1, 192, 65c90bb99fdbee7abf21031d34cb18dc
+0, 2, 2, 1, 192, 9ef1feb2dcbd4d73f3ee84e9e1cd2668
+0, 3, 3, 1, 192, b6281f7c88e9aa132d3902046f8cde5a
+0, 4, 4, 1, 192, 4b439b716a294bddf9f56a229705907b
+0, 5, 5, 1, 192, d42c0a6f0d24522c90bc2233bc1df2c7
+0, 6, 6, 1, 192, 74b763a5a12c4c4a581efb1818a92970
+0, 7, 7, 1, 192, 0c3a0916ddfda5abdd3ac382f036e71f
+0, 8, 8, 1, 192, 26ff590e8ae726f70e8b36f5eaee7a19
+0, 9, 9, 1, 192, 30fa5810995d7132387ea585c4a1cc3a
diff --git a/tests/ref/fate/vp9-02-size-16x10 b/tests/ref/fate/vp9-02-size-16x10
index bea7010216..8490e4e09e 100644
--- a/tests/ref/fate/vp9-02-size-16x10
+++ b/tests/ref/fate/vp9-02-size-16x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 240, fb3cad61d7d9eb511758dbf87dd8abe1
-0, 33, 33, 0, 240, 4fbc1aa5559c8db2930803893bd6ba75
-0, 66, 66, 0, 240, 2d8e2ee04dcc6097ca9e3f27070cdcc8
-0, 100, 100, 0, 240, 05d419f1322855ba3620665b68ce9910
-0, 133, 133, 0, 240, b004f8d88cb2c94f4e9a13cfa5bd480a
-0, 166, 166, 0, 240, 9d9dec90e2213c0411939131aa9adf7f
-0, 200, 200, 0, 240, a00874356ff1b1e9da1a400424661f8d
-0, 233, 233, 0, 240, fda587eb6323cd98c773f05905ac1794
-0, 266, 266, 0, 240, 781c63d221a04d8130806c799d16753a
-0, 300, 300, 0, 240, f346e311829f3789dc5a94da48ada5f4
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 240, fb3cad61d7d9eb511758dbf87dd8abe1
+0, 1, 1, 1, 240, 4fbc1aa5559c8db2930803893bd6ba75
+0, 2, 2, 1, 240, 2d8e2ee04dcc6097ca9e3f27070cdcc8
+0, 3, 3, 1, 240, 05d419f1322855ba3620665b68ce9910
+0, 4, 4, 1, 240, b004f8d88cb2c94f4e9a13cfa5bd480a
+0, 5, 5, 1, 240, 9d9dec90e2213c0411939131aa9adf7f
+0, 6, 6, 1, 240, a00874356ff1b1e9da1a400424661f8d
+0, 7, 7, 1, 240, fda587eb6323cd98c773f05905ac1794
+0, 8, 8, 1, 240, 781c63d221a04d8130806c799d16753a
+0, 9, 9, 1, 240, f346e311829f3789dc5a94da48ada5f4
diff --git a/tests/ref/fate/vp9-02-size-16x16 b/tests/ref/fate/vp9-02-size-16x16
index b013952c65..fb6f0c8cdd 100644
--- a/tests/ref/fate/vp9-02-size-16x16
+++ b/tests/ref/fate/vp9-02-size-16x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 384, b5c9daafa548e54a8e33e9881fda33f4
-0, 33, 33, 0, 384, 1193acd7ea4b7aac968e35ef83c64378
-0, 66, 66, 0, 384, cd0e42c0b5a8b3be6f0e1d224062bf99
-0, 100, 100, 0, 384, ed79c71d17f68f86cbfa75ea2bfe97f3
-0, 133, 133, 0, 384, 1502a859c7e07b31faad5b80e3e27cf7
-0, 166, 166, 0, 384, df3f093da914ea947db93c3baa188ecb
-0, 200, 200, 0, 384, 480f86eb183b99277c1b38fdaafe2970
-0, 233, 233, 0, 384, 023e0114282e04963f0f52e00e65ac61
-0, 266, 266, 0, 384, e67f29cf0acc7f9b553458e1e5c59ebf
-0, 300, 300, 0, 384, a779a14ba718f0c1df8a7edc9467d12e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 384, b5c9daafa548e54a8e33e9881fda33f4
+0, 1, 1, 1, 384, 1193acd7ea4b7aac968e35ef83c64378
+0, 2, 2, 1, 384, cd0e42c0b5a8b3be6f0e1d224062bf99
+0, 3, 3, 1, 384, ed79c71d17f68f86cbfa75ea2bfe97f3
+0, 4, 4, 1, 384, 1502a859c7e07b31faad5b80e3e27cf7
+0, 5, 5, 1, 384, df3f093da914ea947db93c3baa188ecb
+0, 6, 6, 1, 384, 480f86eb183b99277c1b38fdaafe2970
+0, 7, 7, 1, 384, 023e0114282e04963f0f52e00e65ac61
+0, 8, 8, 1, 384, e67f29cf0acc7f9b553458e1e5c59ebf
+0, 9, 9, 1, 384, a779a14ba718f0c1df8a7edc9467d12e
diff --git a/tests/ref/fate/vp9-02-size-16x18 b/tests/ref/fate/vp9-02-size-16x18
index 1795bd9aa5..fadce55939 100644
--- a/tests/ref/fate/vp9-02-size-16x18
+++ b/tests/ref/fate/vp9-02-size-16x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 432, 5156b11cd9995d0c1638c9b0d2b0786c
-0, 33, 33, 0, 432, ef78557f93fb3ea770c7d49ab60edf21
-0, 66, 66, 0, 432, f31fb9bb14566e4538a45ac7bf398b2a
-0, 100, 100, 0, 432, 97633875537f76ade183e975fa91b0fb
-0, 133, 133, 0, 432, 602cf54f9af852175173c21abd63796f
-0, 166, 166, 0, 432, 0b3741a6842cb65d6d21eda891882033
-0, 200, 200, 0, 432, 44240a27a6b6d36c9661d499fb965f87
-0, 233, 233, 0, 432, 9050f263f9a4767f9323ec8aa42cf7e6
-0, 266, 266, 0, 432, 57fa3a8494375f588a95376bc0c3cb28
-0, 300, 300, 0, 432, 084595f2a65aa10e7d3845044a0e7213
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 432, 5156b11cd9995d0c1638c9b0d2b0786c
+0, 1, 1, 1, 432, ef78557f93fb3ea770c7d49ab60edf21
+0, 2, 2, 1, 432, f31fb9bb14566e4538a45ac7bf398b2a
+0, 3, 3, 1, 432, 97633875537f76ade183e975fa91b0fb
+0, 4, 4, 1, 432, 602cf54f9af852175173c21abd63796f
+0, 5, 5, 1, 432, 0b3741a6842cb65d6d21eda891882033
+0, 6, 6, 1, 432, 44240a27a6b6d36c9661d499fb965f87
+0, 7, 7, 1, 432, 9050f263f9a4767f9323ec8aa42cf7e6
+0, 8, 8, 1, 432, 57fa3a8494375f588a95376bc0c3cb28
+0, 9, 9, 1, 432, 084595f2a65aa10e7d3845044a0e7213
diff --git a/tests/ref/fate/vp9-02-size-16x32 b/tests/ref/fate/vp9-02-size-16x32
index 663a456250..02a26762ab 100644
--- a/tests/ref/fate/vp9-02-size-16x32
+++ b/tests/ref/fate/vp9-02-size-16x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 768, c73d611490a5ddec6c690589deaf5e86
-0, 33, 33, 0, 768, 5d8eaeb222aa64abda59ce7b09b2f6d9
-0, 66, 66, 0, 768, 34321856b8dd5bbb9b63db04d3532289
-0, 100, 100, 0, 768, 947337d2fec8a09242f60e31e99f4065
-0, 133, 133, 0, 768, bb7d92f6fc055f0cf0e97bd2be56cc9e
-0, 166, 166, 0, 768, 5d343c82bcdd0e9d08581043cddfd0ca
-0, 200, 200, 0, 768, 612ded93207712e4916d584cc4a7b87c
-0, 233, 233, 0, 768, 6ba5e0d19893e1b96f5ca86e0bfd7e18
-0, 266, 266, 0, 768, 336572e1dcb110b1eb87bea81e0752f4
-0, 300, 300, 0, 768, 705f73d0a39afce59ea571e68bfe25df
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 768, c73d611490a5ddec6c690589deaf5e86
+0, 1, 1, 1, 768, 5d8eaeb222aa64abda59ce7b09b2f6d9
+0, 2, 2, 1, 768, 34321856b8dd5bbb9b63db04d3532289
+0, 3, 3, 1, 768, 947337d2fec8a09242f60e31e99f4065
+0, 4, 4, 1, 768, bb7d92f6fc055f0cf0e97bd2be56cc9e
+0, 5, 5, 1, 768, 5d343c82bcdd0e9d08581043cddfd0ca
+0, 6, 6, 1, 768, 612ded93207712e4916d584cc4a7b87c
+0, 7, 7, 1, 768, 6ba5e0d19893e1b96f5ca86e0bfd7e18
+0, 8, 8, 1, 768, 336572e1dcb110b1eb87bea81e0752f4
+0, 9, 9, 1, 768, 705f73d0a39afce59ea571e68bfe25df
diff --git a/tests/ref/fate/vp9-02-size-16x34 b/tests/ref/fate/vp9-02-size-16x34
index 54d9aaa73a..97e527fc7f 100644
--- a/tests/ref/fate/vp9-02-size-16x34
+++ b/tests/ref/fate/vp9-02-size-16x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 816, b8bf711d9a1ce49180ed56407c8a4b0a
-0, 33, 33, 0, 816, 0457929b06ce46aec63d66bd38586e3f
-0, 66, 66, 0, 816, 3b5f417ee5a936797a6f0d138b8ed73b
-0, 100, 100, 0, 816, 5d1a42aeecfd5c8513cb2df94c206c8b
-0, 133, 133, 0, 816, a0ab2dddbc810a1667d779f6ed69d010
-0, 166, 166, 0, 816, b150cd7c4ec83e6f9d948e99d7465350
-0, 200, 200, 0, 816, ea39622ad21312bd8bcecdaf09aa18fb
-0, 233, 233, 0, 816, 467a42e1226a01c8ba244f312f588bab
-0, 266, 266, 0, 816, f2311e15228ffc7fd377b89c203d0fbf
-0, 300, 300, 0, 816, 5df58b3ac0a7856796a46f27be7dcf4c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 816, b8bf711d9a1ce49180ed56407c8a4b0a
+0, 1, 1, 1, 816, 0457929b06ce46aec63d66bd38586e3f
+0, 2, 2, 1, 816, 3b5f417ee5a936797a6f0d138b8ed73b
+0, 3, 3, 1, 816, 5d1a42aeecfd5c8513cb2df94c206c8b
+0, 4, 4, 1, 816, a0ab2dddbc810a1667d779f6ed69d010
+0, 5, 5, 1, 816, b150cd7c4ec83e6f9d948e99d7465350
+0, 6, 6, 1, 816, ea39622ad21312bd8bcecdaf09aa18fb
+0, 7, 7, 1, 816, 467a42e1226a01c8ba244f312f588bab
+0, 8, 8, 1, 816, f2311e15228ffc7fd377b89c203d0fbf
+0, 9, 9, 1, 816, 5df58b3ac0a7856796a46f27be7dcf4c
diff --git a/tests/ref/fate/vp9-02-size-16x64 b/tests/ref/fate/vp9-02-size-16x64
index 0e19d9a1f3..63dbf24e1f 100644
--- a/tests/ref/fate/vp9-02-size-16x64
+++ b/tests/ref/fate/vp9-02-size-16x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1536, 925fdc485f3baa1ed145ae391519d7fd
-0, 33, 33, 0, 1536, d37af656da2d7a727c8451773495d5ed
-0, 66, 66, 0, 1536, 8a0f207a99e46f3d3b2aaa3f1b061981
-0, 100, 100, 0, 1536, a3914c7b739d3af2641fd6aae35428ef
-0, 133, 133, 0, 1536, 0ba3b49970d7b029f2dfa991fdfc6e61
-0, 166, 166, 0, 1536, 55838d1d787dc5a4fa4da2994f04587f
-0, 200, 200, 0, 1536, c089f7ba2b2983df2a4dc2e07798af31
-0, 233, 233, 0, 1536, c23dcb3b109543a61ccfa404a726caae
-0, 266, 266, 0, 1536, 01aaf09960f5ca599ca32768f017d0c9
-0, 300, 300, 0, 1536, 79fe955692ecba8bbb00b20a42ca8104
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1536, 925fdc485f3baa1ed145ae391519d7fd
+0, 1, 1, 1, 1536, d37af656da2d7a727c8451773495d5ed
+0, 2, 2, 1, 1536, 8a0f207a99e46f3d3b2aaa3f1b061981
+0, 3, 3, 1, 1536, a3914c7b739d3af2641fd6aae35428ef
+0, 4, 4, 1, 1536, 0ba3b49970d7b029f2dfa991fdfc6e61
+0, 5, 5, 1, 1536, 55838d1d787dc5a4fa4da2994f04587f
+0, 6, 6, 1, 1536, c089f7ba2b2983df2a4dc2e07798af31
+0, 7, 7, 1, 1536, c23dcb3b109543a61ccfa404a726caae
+0, 8, 8, 1, 1536, 01aaf09960f5ca599ca32768f017d0c9
+0, 9, 9, 1, 1536, 79fe955692ecba8bbb00b20a42ca8104
diff --git a/tests/ref/fate/vp9-02-size-16x66 b/tests/ref/fate/vp9-02-size-16x66
index 2d75fc8719..f7d01022ec 100644
--- a/tests/ref/fate/vp9-02-size-16x66
+++ b/tests/ref/fate/vp9-02-size-16x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1584, c7b0d91f362dff0a581434af6e902d43
-0, 33, 33, 0, 1584, d8b016ef59c6bc193b29d1c714f342c1
-0, 66, 66, 0, 1584, c520bd8d4b81aafc7687befff66c7396
-0, 100, 100, 0, 1584, 92e81bbd3af675c9cdb1cb00d03dabe1
-0, 133, 133, 0, 1584, a271db3defe5daa6d9e0a73a580f4f88
-0, 166, 166, 0, 1584, 4077e857321e241bb98dfd89c0aca46f
-0, 200, 200, 0, 1584, 0466e1453a94baf876e9f64b60235300
-0, 233, 233, 0, 1584, 9d2cb9c7b180d44841e0e4d8a595d912
-0, 266, 266, 0, 1584, 500f443eeb0ecef47c34d1e91f0df6ce
-0, 300, 300, 0, 1584, 83354487982915c33b1c6243d80adaeb
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1584, c7b0d91f362dff0a581434af6e902d43
+0, 1, 1, 1, 1584, d8b016ef59c6bc193b29d1c714f342c1
+0, 2, 2, 1, 1584, c520bd8d4b81aafc7687befff66c7396
+0, 3, 3, 1, 1584, 92e81bbd3af675c9cdb1cb00d03dabe1
+0, 4, 4, 1, 1584, a271db3defe5daa6d9e0a73a580f4f88
+0, 5, 5, 1, 1584, 4077e857321e241bb98dfd89c0aca46f
+0, 6, 6, 1, 1584, 0466e1453a94baf876e9f64b60235300
+0, 7, 7, 1, 1584, 9d2cb9c7b180d44841e0e4d8a595d912
+0, 8, 8, 1, 1584, 500f443eeb0ecef47c34d1e91f0df6ce
+0, 9, 9, 1, 1584, 83354487982915c33b1c6243d80adaeb
diff --git a/tests/ref/fate/vp9-02-size-18x08 b/tests/ref/fate/vp9-02-size-18x08
index 49129ce92f..08aabcc889 100644
--- a/tests/ref/fate/vp9-02-size-18x08
+++ b/tests/ref/fate/vp9-02-size-18x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 216, 3219af4ef540636b0f67a989e9966059
-0, 33, 33, 0, 216, 1a3655c2cfd2ee332bc89da5b3faf778
-0, 66, 66, 0, 216, d638d5b361a6d81440e26993ed86c97d
-0, 100, 100, 0, 216, d9bc2e7cffd66db4ba9dcbce99448d4d
-0, 133, 133, 0, 216, 399f962e0a0573915bc4da4a9f1effcf
-0, 166, 166, 0, 216, 69d917e19b903e4f07f848e9e557bbe7
-0, 200, 200, 0, 216, d6311488a58acf6eb0cc45bc4fe3c2da
-0, 233, 233, 0, 216, 0ce360a84d5755307f98d65c83f190e1
-0, 266, 266, 0, 216, 2554828e6dbf94424ccac30fb153872e
-0, 300, 300, 0, 216, 598a55f9735e85b8d45105dd6be7f97b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 216, 3219af4ef540636b0f67a989e9966059
+0, 1, 1, 1, 216, 1a3655c2cfd2ee332bc89da5b3faf778
+0, 2, 2, 1, 216, d638d5b361a6d81440e26993ed86c97d
+0, 3, 3, 1, 216, d9bc2e7cffd66db4ba9dcbce99448d4d
+0, 4, 4, 1, 216, 399f962e0a0573915bc4da4a9f1effcf
+0, 5, 5, 1, 216, 69d917e19b903e4f07f848e9e557bbe7
+0, 6, 6, 1, 216, d6311488a58acf6eb0cc45bc4fe3c2da
+0, 7, 7, 1, 216, 0ce360a84d5755307f98d65c83f190e1
+0, 8, 8, 1, 216, 2554828e6dbf94424ccac30fb153872e
+0, 9, 9, 1, 216, 598a55f9735e85b8d45105dd6be7f97b
diff --git a/tests/ref/fate/vp9-02-size-18x10 b/tests/ref/fate/vp9-02-size-18x10
index 3fcf5ca5db..9323a14819 100644
--- a/tests/ref/fate/vp9-02-size-18x10
+++ b/tests/ref/fate/vp9-02-size-18x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 270, bf574489e9360b6475aa012c747e7924
-0, 33, 33, 0, 270, 851100301c2937312a6fd32f5aab5a09
-0, 66, 66, 0, 270, 0f7c1209e44ea7cd4df12d82f9224684
-0, 100, 100, 0, 270, 28d121f9c40de5280435bfdeaec0c072
-0, 133, 133, 0, 270, bb00898d03ce4dff5f7bee719dd3f5b5
-0, 166, 166, 0, 270, a098cc66bc25b81f84b0e930b0915cdb
-0, 200, 200, 0, 270, 81e25f19bfcbfce17bd7138eedae04ee
-0, 233, 233, 0, 270, 69c36c5ce555a461f16a1733450f7258
-0, 266, 266, 0, 270, c95236d9e7c624bb664310bd9ef47fb4
-0, 300, 300, 0, 270, 7ab0942e686939951037314e9402d2c1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 270, bf574489e9360b6475aa012c747e7924
+0, 1, 1, 1, 270, 851100301c2937312a6fd32f5aab5a09
+0, 2, 2, 1, 270, 0f7c1209e44ea7cd4df12d82f9224684
+0, 3, 3, 1, 270, 28d121f9c40de5280435bfdeaec0c072
+0, 4, 4, 1, 270, bb00898d03ce4dff5f7bee719dd3f5b5
+0, 5, 5, 1, 270, a098cc66bc25b81f84b0e930b0915cdb
+0, 6, 6, 1, 270, 81e25f19bfcbfce17bd7138eedae04ee
+0, 7, 7, 1, 270, 69c36c5ce555a461f16a1733450f7258
+0, 8, 8, 1, 270, c95236d9e7c624bb664310bd9ef47fb4
+0, 9, 9, 1, 270, 7ab0942e686939951037314e9402d2c1
diff --git a/tests/ref/fate/vp9-02-size-18x16 b/tests/ref/fate/vp9-02-size-18x16
index 6b2a43a433..a3a91b923b 100644
--- a/tests/ref/fate/vp9-02-size-18x16
+++ b/tests/ref/fate/vp9-02-size-18x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 432, 9535aaa2ea26fbdc16e7fe9cba3fc9b4
-0, 33, 33, 0, 432, 7f6e7ca33c0b27ff052dc2ab6721e37d
-0, 66, 66, 0, 432, d37e3f169457a9c7f2a197353e39d3d6
-0, 100, 100, 0, 432, f26d7d81dd81d051680ea2485e812705
-0, 133, 133, 0, 432, 704b01955ced6d101b9e9315d3327f28
-0, 166, 166, 0, 432, 30d46d6a0f6be383dede451cacf465f4
-0, 200, 200, 0, 432, 83c7ed04f0af61ec665041967cbce05d
-0, 233, 233, 0, 432, 152daf37dd37607886c50dd4c7796357
-0, 266, 266, 0, 432, 609d807351ba74b1c432e3d0516add91
-0, 300, 300, 0, 432, 67953f0c735984232cb6782217cdcdf6
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 432, 9535aaa2ea26fbdc16e7fe9cba3fc9b4
+0, 1, 1, 1, 432, 7f6e7ca33c0b27ff052dc2ab6721e37d
+0, 2, 2, 1, 432, d37e3f169457a9c7f2a197353e39d3d6
+0, 3, 3, 1, 432, f26d7d81dd81d051680ea2485e812705
+0, 4, 4, 1, 432, 704b01955ced6d101b9e9315d3327f28
+0, 5, 5, 1, 432, 30d46d6a0f6be383dede451cacf465f4
+0, 6, 6, 1, 432, 83c7ed04f0af61ec665041967cbce05d
+0, 7, 7, 1, 432, 152daf37dd37607886c50dd4c7796357
+0, 8, 8, 1, 432, 609d807351ba74b1c432e3d0516add91
+0, 9, 9, 1, 432, 67953f0c735984232cb6782217cdcdf6
diff --git a/tests/ref/fate/vp9-02-size-18x18 b/tests/ref/fate/vp9-02-size-18x18
index d7103ae911..b90faf3298 100644
--- a/tests/ref/fate/vp9-02-size-18x18
+++ b/tests/ref/fate/vp9-02-size-18x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 486, 83790b0e7004d8d89b7134ee1a88d885
-0, 33, 33, 0, 486, 0baf0bf556ae56d2f4b04567e6ac7ed9
-0, 66, 66, 0, 486, c648854a4d49f7e407a2450cf4ba292a
-0, 100, 100, 0, 486, 510c3aca23339841ffc72ed5c75d184e
-0, 133, 133, 0, 486, 1c1f3116ec4d4ee1ad790652e49233ad
-0, 166, 166, 0, 486, f94891f4e16fd32d638a2c696f5922e6
-0, 200, 200, 0, 486, e164814c22e38cbe45312dfd48d987fc
-0, 233, 233, 0, 486, f582515fcc6c4308ad931d2f6cf371a0
-0, 266, 266, 0, 486, 0a446974bd227ee34a1621a2b7852abb
-0, 300, 300, 0, 486, beca28bdae8d1fe20036b3646f3109cd
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 486, 83790b0e7004d8d89b7134ee1a88d885
+0, 1, 1, 1, 486, 0baf0bf556ae56d2f4b04567e6ac7ed9
+0, 2, 2, 1, 486, c648854a4d49f7e407a2450cf4ba292a
+0, 3, 3, 1, 486, 510c3aca23339841ffc72ed5c75d184e
+0, 4, 4, 1, 486, 1c1f3116ec4d4ee1ad790652e49233ad
+0, 5, 5, 1, 486, f94891f4e16fd32d638a2c696f5922e6
+0, 6, 6, 1, 486, e164814c22e38cbe45312dfd48d987fc
+0, 7, 7, 1, 486, f582515fcc6c4308ad931d2f6cf371a0
+0, 8, 8, 1, 486, 0a446974bd227ee34a1621a2b7852abb
+0, 9, 9, 1, 486, beca28bdae8d1fe20036b3646f3109cd
diff --git a/tests/ref/fate/vp9-02-size-18x32 b/tests/ref/fate/vp9-02-size-18x32
index 450facc6df..b7bd74b845 100644
--- a/tests/ref/fate/vp9-02-size-18x32
+++ b/tests/ref/fate/vp9-02-size-18x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 864, 62eabc8819ded6ddba2c3a5029497cf0
-0, 33, 33, 0, 864, b760182fddf8bc05f149e80bbcb2c281
-0, 66, 66, 0, 864, 0c44be0472ebd2653ce9fb174c6180ab
-0, 100, 100, 0, 864, bbb033c3bfeeb6f59cb43013597b9d92
-0, 133, 133, 0, 864, a769975cdbc6529525f7cac8a0d9299a
-0, 166, 166, 0, 864, 15b02059bbced62f19c0626efea1ecb9
-0, 200, 200, 0, 864, 47f4b50322ed31649bdcfffb05c70fa2
-0, 233, 233, 0, 864, 8649cdd0a958047839f5b6e7bbf6f288
-0, 266, 266, 0, 864, 2c766e3fd3882a9a5aff52ffe9d1d341
-0, 300, 300, 0, 864, 184a62b7332a1c24acbf03f670fb7ac1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 864, 62eabc8819ded6ddba2c3a5029497cf0
+0, 1, 1, 1, 864, b760182fddf8bc05f149e80bbcb2c281
+0, 2, 2, 1, 864, 0c44be0472ebd2653ce9fb174c6180ab
+0, 3, 3, 1, 864, bbb033c3bfeeb6f59cb43013597b9d92
+0, 4, 4, 1, 864, a769975cdbc6529525f7cac8a0d9299a
+0, 5, 5, 1, 864, 15b02059bbced62f19c0626efea1ecb9
+0, 6, 6, 1, 864, 47f4b50322ed31649bdcfffb05c70fa2
+0, 7, 7, 1, 864, 8649cdd0a958047839f5b6e7bbf6f288
+0, 8, 8, 1, 864, 2c766e3fd3882a9a5aff52ffe9d1d341
+0, 9, 9, 1, 864, 184a62b7332a1c24acbf03f670fb7ac1
diff --git a/tests/ref/fate/vp9-02-size-18x34 b/tests/ref/fate/vp9-02-size-18x34
index ef6042abe1..0f46da7aa8 100644
--- a/tests/ref/fate/vp9-02-size-18x34
+++ b/tests/ref/fate/vp9-02-size-18x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 918, 612cc424eaae924cb25c7732c422f752
-0, 33, 33, 0, 918, 010e8c2a814862529fcf8d7771ba2d7f
-0, 66, 66, 0, 918, 7d791b7a5916738998f77586339d5840
-0, 100, 100, 0, 918, aeada5f59f3dda9ab3e898f305428cb2
-0, 133, 133, 0, 918, 06af894d38a1f0d3665c0081f5397ddf
-0, 166, 166, 0, 918, 24bf31323c568e652550e9d35de9c96c
-0, 200, 200, 0, 918, a9681ec47d3e6a19321b9ea47221dc3f
-0, 233, 233, 0, 918, 73ae7268df79c4012952bd3e8011e894
-0, 266, 266, 0, 918, 67aa4145398ca17036959251cb4ce17b
-0, 300, 300, 0, 918, de247b80114c722da849f5aa23adbb38
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 918, 612cc424eaae924cb25c7732c422f752
+0, 1, 1, 1, 918, 010e8c2a814862529fcf8d7771ba2d7f
+0, 2, 2, 1, 918, 7d791b7a5916738998f77586339d5840
+0, 3, 3, 1, 918, aeada5f59f3dda9ab3e898f305428cb2
+0, 4, 4, 1, 918, 06af894d38a1f0d3665c0081f5397ddf
+0, 5, 5, 1, 918, 24bf31323c568e652550e9d35de9c96c
+0, 6, 6, 1, 918, a9681ec47d3e6a19321b9ea47221dc3f
+0, 7, 7, 1, 918, 73ae7268df79c4012952bd3e8011e894
+0, 8, 8, 1, 918, 67aa4145398ca17036959251cb4ce17b
+0, 9, 9, 1, 918, de247b80114c722da849f5aa23adbb38
diff --git a/tests/ref/fate/vp9-02-size-18x64 b/tests/ref/fate/vp9-02-size-18x64
index 038b21bcfe..172422c884 100644
--- a/tests/ref/fate/vp9-02-size-18x64
+++ b/tests/ref/fate/vp9-02-size-18x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1728, 72c74de547d9ed1b17bc962dbd5e0bb1
-0, 33, 33, 0, 1728, 462849f9e2204738e9f08b40e682a6ae
-0, 66, 66, 0, 1728, f0ee17692fd816747b11d5737b511cda
-0, 100, 100, 0, 1728, 0234d23406660ede76dd22b35a708390
-0, 133, 133, 0, 1728, 6544fdb9dc225d155820d3c7dfc909eb
-0, 166, 166, 0, 1728, 1c073544794389596177512fb4dcffce
-0, 200, 200, 0, 1728, 864709daac7b091d33afa2210c145084
-0, 233, 233, 0, 1728, b049c4ac941743613ede9a41b16acde5
-0, 266, 266, 0, 1728, ad0c4adb0efec03729a79f42eec66267
-0, 300, 300, 0, 1728, 146057d941f5a47eb8b2c9eefeaf3100
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1728, 72c74de547d9ed1b17bc962dbd5e0bb1
+0, 1, 1, 1, 1728, 462849f9e2204738e9f08b40e682a6ae
+0, 2, 2, 1, 1728, f0ee17692fd816747b11d5737b511cda
+0, 3, 3, 1, 1728, 0234d23406660ede76dd22b35a708390
+0, 4, 4, 1, 1728, 6544fdb9dc225d155820d3c7dfc909eb
+0, 5, 5, 1, 1728, 1c073544794389596177512fb4dcffce
+0, 6, 6, 1, 1728, 864709daac7b091d33afa2210c145084
+0, 7, 7, 1, 1728, b049c4ac941743613ede9a41b16acde5
+0, 8, 8, 1, 1728, ad0c4adb0efec03729a79f42eec66267
+0, 9, 9, 1, 1728, 146057d941f5a47eb8b2c9eefeaf3100
diff --git a/tests/ref/fate/vp9-02-size-18x66 b/tests/ref/fate/vp9-02-size-18x66
index 6d3021b233..c400956d7b 100644
--- a/tests/ref/fate/vp9-02-size-18x66
+++ b/tests/ref/fate/vp9-02-size-18x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1782, c3fc4a1593b9cc2f3752106af8539386
-0, 33, 33, 0, 1782, 7f2ffe6bc1750f6749bb5ad12cbaf34b
-0, 66, 66, 0, 1782, 2539b10a981d59ef54efd77cd7276aaa
-0, 100, 100, 0, 1782, 0bff22b4dfb7485fbedd6ff5b99673d1
-0, 133, 133, 0, 1782, 6a2b38f4abee785260a61bc60f16e7fa
-0, 166, 166, 0, 1782, 2fbb69b5519b51548bf1ee425ff79c55
-0, 200, 200, 0, 1782, dbd267028be2256111b2411b91fcc117
-0, 233, 233, 0, 1782, 12b2f1003633c9e19cae3d0fda06102d
-0, 266, 266, 0, 1782, d419a756c492867523af5185fd57d989
-0, 300, 300, 0, 1782, 8a7d36760bf5db32baef349b97316b47
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1782, c3fc4a1593b9cc2f3752106af8539386
+0, 1, 1, 1, 1782, 7f2ffe6bc1750f6749bb5ad12cbaf34b
+0, 2, 2, 1, 1782, 2539b10a981d59ef54efd77cd7276aaa
+0, 3, 3, 1, 1782, 0bff22b4dfb7485fbedd6ff5b99673d1
+0, 4, 4, 1, 1782, 6a2b38f4abee785260a61bc60f16e7fa
+0, 5, 5, 1, 1782, 2fbb69b5519b51548bf1ee425ff79c55
+0, 6, 6, 1, 1782, dbd267028be2256111b2411b91fcc117
+0, 7, 7, 1, 1782, 12b2f1003633c9e19cae3d0fda06102d
+0, 8, 8, 1, 1782, d419a756c492867523af5185fd57d989
+0, 9, 9, 1, 1782, 8a7d36760bf5db32baef349b97316b47
diff --git a/tests/ref/fate/vp9-02-size-32x08 b/tests/ref/fate/vp9-02-size-32x08
index ae376d3c49..2df5adcf06 100644
--- a/tests/ref/fate/vp9-02-size-32x08
+++ b/tests/ref/fate/vp9-02-size-32x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 384, c7b30cde5664387b0f7a80d9b01e4fe2
-0, 33, 33, 0, 384, 2228a2a4e54ab5145525e5803c314dcd
-0, 66, 66, 0, 384, 8c048469eba24f3163c36b7461b3b42a
-0, 100, 100, 0, 384, f6b8e8e701dea09dcf1158e9a52921c6
-0, 133, 133, 0, 384, b3a5fde0daf2eef8fc08521f88f79692
-0, 166, 166, 0, 384, 653ae11cc1380ae7f39b2e007f896d81
-0, 200, 200, 0, 384, 6e66fe002a7dff95e13cc9d3d13d9686
-0, 233, 233, 0, 384, 13308c917a1e22c2f702afc32b8a23c2
-0, 266, 266, 0, 384, 4fee1e63f9452dc3f81c1d634bd7f41d
-0, 300, 300, 0, 384, 666b43ead5c7c99ae5b7637da5aa4d62
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 384, c7b30cde5664387b0f7a80d9b01e4fe2
+0, 1, 1, 1, 384, 2228a2a4e54ab5145525e5803c314dcd
+0, 2, 2, 1, 384, 8c048469eba24f3163c36b7461b3b42a
+0, 3, 3, 1, 384, f6b8e8e701dea09dcf1158e9a52921c6
+0, 4, 4, 1, 384, b3a5fde0daf2eef8fc08521f88f79692
+0, 5, 5, 1, 384, 653ae11cc1380ae7f39b2e007f896d81
+0, 6, 6, 1, 384, 6e66fe002a7dff95e13cc9d3d13d9686
+0, 7, 7, 1, 384, 13308c917a1e22c2f702afc32b8a23c2
+0, 8, 8, 1, 384, 4fee1e63f9452dc3f81c1d634bd7f41d
+0, 9, 9, 1, 384, 666b43ead5c7c99ae5b7637da5aa4d62
diff --git a/tests/ref/fate/vp9-02-size-32x10 b/tests/ref/fate/vp9-02-size-32x10
index bc816e934e..f5f45fb20d 100644
--- a/tests/ref/fate/vp9-02-size-32x10
+++ b/tests/ref/fate/vp9-02-size-32x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 480, 7c5b5df373ebfd31d210ff910e02213b
-0, 33, 33, 0, 480, c5b0a5e3eceb792b15818324a43aa2a8
-0, 66, 66, 0, 480, 1d9c0eafd4638dfe4fe308174fde2faf
-0, 100, 100, 0, 480, 47301d12055944b35008028761cf5e7b
-0, 133, 133, 0, 480, 9586ac1087423dcd3b0ff96d43ae475e
-0, 166, 166, 0, 480, 26bfe1afea96c7ef2084fffd1fa99a33
-0, 200, 200, 0, 480, 0995c8a1935266159a7ef3f95d7f4697
-0, 233, 233, 0, 480, 8cfcc0ea67507ab7f3551d8ac50f93a5
-0, 266, 266, 0, 480, 658cf3cb887b055d9de7d50db4eb78a9
-0, 300, 300, 0, 480, 856bd5189688f7ccfe9995752bc0f1f6
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 480, 7c5b5df373ebfd31d210ff910e02213b
+0, 1, 1, 1, 480, c5b0a5e3eceb792b15818324a43aa2a8
+0, 2, 2, 1, 480, 1d9c0eafd4638dfe4fe308174fde2faf
+0, 3, 3, 1, 480, 47301d12055944b35008028761cf5e7b
+0, 4, 4, 1, 480, 9586ac1087423dcd3b0ff96d43ae475e
+0, 5, 5, 1, 480, 26bfe1afea96c7ef2084fffd1fa99a33
+0, 6, 6, 1, 480, 0995c8a1935266159a7ef3f95d7f4697
+0, 7, 7, 1, 480, 8cfcc0ea67507ab7f3551d8ac50f93a5
+0, 8, 8, 1, 480, 658cf3cb887b055d9de7d50db4eb78a9
+0, 9, 9, 1, 480, 856bd5189688f7ccfe9995752bc0f1f6
diff --git a/tests/ref/fate/vp9-02-size-32x16 b/tests/ref/fate/vp9-02-size-32x16
index ebb465e4d9..4aac211548 100644
--- a/tests/ref/fate/vp9-02-size-32x16
+++ b/tests/ref/fate/vp9-02-size-32x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 768, 7c2818db2632e5c5beee17e7105d9209
-0, 33, 33, 0, 768, cead72bd22995e98b54a91c7b4a20975
-0, 66, 66, 0, 768, eb6baee5d65d778052c88ba5db2f9174
-0, 100, 100, 0, 768, 1f5f38e89e985e9e4172446de05e91fd
-0, 133, 133, 0, 768, 57b57ffcb03627942fc5868324a10feb
-0, 166, 166, 0, 768, 4b4066a452d8e9cd687cd611f5d9cb88
-0, 200, 200, 0, 768, 113e5069b2a4d2c2e802b72649eb435d
-0, 233, 233, 0, 768, e176bb233f76f9fd4c55d62d53487b60
-0, 266, 266, 0, 768, f2ff3def712a846ea7b678bd9078e32b
-0, 300, 300, 0, 768, 21007ed1c727c5ccc5955188a2cec276
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 768, 7c2818db2632e5c5beee17e7105d9209
+0, 1, 1, 1, 768, cead72bd22995e98b54a91c7b4a20975
+0, 2, 2, 1, 768, eb6baee5d65d778052c88ba5db2f9174
+0, 3, 3, 1, 768, 1f5f38e89e985e9e4172446de05e91fd
+0, 4, 4, 1, 768, 57b57ffcb03627942fc5868324a10feb
+0, 5, 5, 1, 768, 4b4066a452d8e9cd687cd611f5d9cb88
+0, 6, 6, 1, 768, 113e5069b2a4d2c2e802b72649eb435d
+0, 7, 7, 1, 768, e176bb233f76f9fd4c55d62d53487b60
+0, 8, 8, 1, 768, f2ff3def712a846ea7b678bd9078e32b
+0, 9, 9, 1, 768, 21007ed1c727c5ccc5955188a2cec276
diff --git a/tests/ref/fate/vp9-02-size-32x18 b/tests/ref/fate/vp9-02-size-32x18
index 6afccbbbdd..2b302191fc 100644
--- a/tests/ref/fate/vp9-02-size-32x18
+++ b/tests/ref/fate/vp9-02-size-32x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 864, 9da5409d344e7b8380688569e54803a5
-0, 33, 33, 0, 864, 9b51e14e2e624ee2b430e9eaf1a48798
-0, 66, 66, 0, 864, b8811779f363b9a595e3a92737771ea9
-0, 100, 100, 0, 864, e5a0c335e5e713a3e77fff0b65127fb9
-0, 133, 133, 0, 864, 1bffa3283b463a356794c8f7a73f8c54
-0, 166, 166, 0, 864, 97c13270621a583eb9e13c05f9d792f0
-0, 200, 200, 0, 864, a6f81a4dde1ffc352ebe9d8ab8782f35
-0, 233, 233, 0, 864, 91a955a86ce9378ff3442794ce0934c6
-0, 266, 266, 0, 864, 2e4f8938e9c88b328a258a0b99366ea6
-0, 300, 300, 0, 864, adbbbc192cf36e1fc7c308824765d482
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 864, 9da5409d344e7b8380688569e54803a5
+0, 1, 1, 1, 864, 9b51e14e2e624ee2b430e9eaf1a48798
+0, 2, 2, 1, 864, b8811779f363b9a595e3a92737771ea9
+0, 3, 3, 1, 864, e5a0c335e5e713a3e77fff0b65127fb9
+0, 4, 4, 1, 864, 1bffa3283b463a356794c8f7a73f8c54
+0, 5, 5, 1, 864, 97c13270621a583eb9e13c05f9d792f0
+0, 6, 6, 1, 864, a6f81a4dde1ffc352ebe9d8ab8782f35
+0, 7, 7, 1, 864, 91a955a86ce9378ff3442794ce0934c6
+0, 8, 8, 1, 864, 2e4f8938e9c88b328a258a0b99366ea6
+0, 9, 9, 1, 864, adbbbc192cf36e1fc7c308824765d482
diff --git a/tests/ref/fate/vp9-02-size-32x32 b/tests/ref/fate/vp9-02-size-32x32
index fb3fb878b5..e9de2ed48c 100644
--- a/tests/ref/fate/vp9-02-size-32x32
+++ b/tests/ref/fate/vp9-02-size-32x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1536, 117915db1856cee26f05a609c8c8de2e
-0, 33, 33, 0, 1536, 943771a98b26b174e88ed1f4e872e504
-0, 66, 66, 0, 1536, 3e0d2585e1f1cb540998d107aca5c395
-0, 100, 100, 0, 1536, e64a9e1e0232983a69ab48453025b23d
-0, 133, 133, 0, 1536, 2c6ef6637fb7b9425f7d7ea28cd84087
-0, 166, 166, 0, 1536, 419a5a31a43955d408c13ee8a5ddce9c
-0, 200, 200, 0, 1536, 2ab13e1c236553d42d59498ca350b190
-0, 233, 233, 0, 1536, b8068beb037f3232d4da38fe33a8a885
-0, 266, 266, 0, 1536, 160df68b9e3f75e9b1f8ed7cce327bc2
-0, 300, 300, 0, 1536, 1ccafa8c7babdce0983aeb20d298b0ee
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1536, 117915db1856cee26f05a609c8c8de2e
+0, 1, 1, 1, 1536, 943771a98b26b174e88ed1f4e872e504
+0, 2, 2, 1, 1536, 3e0d2585e1f1cb540998d107aca5c395
+0, 3, 3, 1, 1536, e64a9e1e0232983a69ab48453025b23d
+0, 4, 4, 1, 1536, 2c6ef6637fb7b9425f7d7ea28cd84087
+0, 5, 5, 1, 1536, 419a5a31a43955d408c13ee8a5ddce9c
+0, 6, 6, 1, 1536, 2ab13e1c236553d42d59498ca350b190
+0, 7, 7, 1, 1536, b8068beb037f3232d4da38fe33a8a885
+0, 8, 8, 1, 1536, 160df68b9e3f75e9b1f8ed7cce327bc2
+0, 9, 9, 1, 1536, 1ccafa8c7babdce0983aeb20d298b0ee
diff --git a/tests/ref/fate/vp9-02-size-32x34 b/tests/ref/fate/vp9-02-size-32x34
index 4e000a503c..e1e00fdb8f 100644
--- a/tests/ref/fate/vp9-02-size-32x34
+++ b/tests/ref/fate/vp9-02-size-32x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1632, 770582911fd0095ebbeae384e87665ac
-0, 33, 33, 0, 1632, f99d7e3131f04413cba2f9de6818976d
-0, 66, 66, 0, 1632, 3bfbb8c9c48f24cd596973a6deb33a3f
-0, 100, 100, 0, 1632, 0b8166afdd357f20c76f77d228bb7171
-0, 133, 133, 0, 1632, 3a3d7f2a03e19a82250d6ca0238f9791
-0, 166, 166, 0, 1632, 9b558f9b8744b016059f69f3fca90d2c
-0, 200, 200, 0, 1632, c857736342f1145d919cb77732120006
-0, 233, 233, 0, 1632, 11dc5dda4c883a3146db060dd50343d0
-0, 266, 266, 0, 1632, 7526a62ae87de174be86eac7bb36c7f3
-0, 300, 300, 0, 1632, 9ef38f47cfc461710ff0dd75690473c0
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1632, 770582911fd0095ebbeae384e87665ac
+0, 1, 1, 1, 1632, f99d7e3131f04413cba2f9de6818976d
+0, 2, 2, 1, 1632, 3bfbb8c9c48f24cd596973a6deb33a3f
+0, 3, 3, 1, 1632, 0b8166afdd357f20c76f77d228bb7171
+0, 4, 4, 1, 1632, 3a3d7f2a03e19a82250d6ca0238f9791
+0, 5, 5, 1, 1632, 9b558f9b8744b016059f69f3fca90d2c
+0, 6, 6, 1, 1632, c857736342f1145d919cb77732120006
+0, 7, 7, 1, 1632, 11dc5dda4c883a3146db060dd50343d0
+0, 8, 8, 1, 1632, 7526a62ae87de174be86eac7bb36c7f3
+0, 9, 9, 1, 1632, 9ef38f47cfc461710ff0dd75690473c0
diff --git a/tests/ref/fate/vp9-02-size-32x64 b/tests/ref/fate/vp9-02-size-32x64
index d2b9c992fe..c39c88d15e 100644
--- a/tests/ref/fate/vp9-02-size-32x64
+++ b/tests/ref/fate/vp9-02-size-32x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3072, caa8471a8b381d53c3e8fc627946a871
-0, 33, 33, 0, 3072, 2cba86ea14c0f28e242625b08f5e9b88
-0, 66, 66, 0, 3072, cea0440ff6569fc82c3030e0340fb649
-0, 100, 100, 0, 3072, c18ef37f1356ade96a2f40af954b31c8
-0, 133, 133, 0, 3072, 21e6e549378bcff47913ef292e74dc37
-0, 166, 166, 0, 3072, a9d3d483f74a5afe5d80725ce696fd20
-0, 200, 200, 0, 3072, a436e2586b0963747deaf5e450e2b230
-0, 233, 233, 0, 3072, 9daaadf265df56974cb0950843d9fd8c
-0, 266, 266, 0, 3072, e0b84714bad2519e62b7d16705fb09d5
-0, 300, 300, 0, 3072, 8cdfce574edbe548da7f6cd9a7076b9e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3072, caa8471a8b381d53c3e8fc627946a871
+0, 1, 1, 1, 3072, 2cba86ea14c0f28e242625b08f5e9b88
+0, 2, 2, 1, 3072, cea0440ff6569fc82c3030e0340fb649
+0, 3, 3, 1, 3072, c18ef37f1356ade96a2f40af954b31c8
+0, 4, 4, 1, 3072, 21e6e549378bcff47913ef292e74dc37
+0, 5, 5, 1, 3072, a9d3d483f74a5afe5d80725ce696fd20
+0, 6, 6, 1, 3072, a436e2586b0963747deaf5e450e2b230
+0, 7, 7, 1, 3072, 9daaadf265df56974cb0950843d9fd8c
+0, 8, 8, 1, 3072, e0b84714bad2519e62b7d16705fb09d5
+0, 9, 9, 1, 3072, 8cdfce574edbe548da7f6cd9a7076b9e
diff --git a/tests/ref/fate/vp9-02-size-32x66 b/tests/ref/fate/vp9-02-size-32x66
index 65c87da48d..d036df1de5 100644
--- a/tests/ref/fate/vp9-02-size-32x66
+++ b/tests/ref/fate/vp9-02-size-32x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3168, 920ea4b8a00d41489d122d641d6e4fe5
-0, 33, 33, 0, 3168, 8bfc8d452a79f2978b8e973b77cbf8a8
-0, 66, 66, 0, 3168, 09f3f0d31d3377a844fa5385d9b36b9f
-0, 100, 100, 0, 3168, df43fae763da9360c8062bb92ee091a8
-0, 133, 133, 0, 3168, 445d8c675bb865d1814fcfa6b8a9afd3
-0, 166, 166, 0, 3168, dc7d43db86aac6636724de8790eda555
-0, 200, 200, 0, 3168, d3a9fc272424449ffc5b7e69f8f9948b
-0, 233, 233, 0, 3168, 11ef33b9bccca54b3703bf24ab55e2d6
-0, 266, 266, 0, 3168, ce31b8bf9b00b427ca956abb800d8034
-0, 300, 300, 0, 3168, e707f824d6e95d482bf3a0b4d52ea069
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3168, 920ea4b8a00d41489d122d641d6e4fe5
+0, 1, 1, 1, 3168, 8bfc8d452a79f2978b8e973b77cbf8a8
+0, 2, 2, 1, 3168, 09f3f0d31d3377a844fa5385d9b36b9f
+0, 3, 3, 1, 3168, df43fae763da9360c8062bb92ee091a8
+0, 4, 4, 1, 3168, 445d8c675bb865d1814fcfa6b8a9afd3
+0, 5, 5, 1, 3168, dc7d43db86aac6636724de8790eda555
+0, 6, 6, 1, 3168, d3a9fc272424449ffc5b7e69f8f9948b
+0, 7, 7, 1, 3168, 11ef33b9bccca54b3703bf24ab55e2d6
+0, 8, 8, 1, 3168, ce31b8bf9b00b427ca956abb800d8034
+0, 9, 9, 1, 3168, e707f824d6e95d482bf3a0b4d52ea069
diff --git a/tests/ref/fate/vp9-02-size-34x08 b/tests/ref/fate/vp9-02-size-34x08
index d6ccbbb4b5..586918631c 100644
--- a/tests/ref/fate/vp9-02-size-34x08
+++ b/tests/ref/fate/vp9-02-size-34x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 408, c14f2ba5b4582c9d3a488976814691b3
-0, 33, 33, 0, 408, 4387a4dce19007b7efb810b5a4069749
-0, 66, 66, 0, 408, ecfe868d28f4861a5612edfd57447a02
-0, 100, 100, 0, 408, 5cba54f568534d29169ac31c8fa505e0
-0, 133, 133, 0, 408, fe9aab7b3378b9fc3e373ee626b887db
-0, 166, 166, 0, 408, fce72dfc7f9c0cb50ff73761b4d82c1f
-0, 200, 200, 0, 408, d4d98f42b1377e0f0ffaa66aa81d40c3
-0, 233, 233, 0, 408, 65c027646dc95a749ce2d7ad0a6beccc
-0, 266, 266, 0, 408, 317b283a0d907270f671272771022e69
-0, 300, 300, 0, 408, d3e2c008584608502f3e24c5c5f64028
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 408, c14f2ba5b4582c9d3a488976814691b3
+0, 1, 1, 1, 408, 4387a4dce19007b7efb810b5a4069749
+0, 2, 2, 1, 408, ecfe868d28f4861a5612edfd57447a02
+0, 3, 3, 1, 408, 5cba54f568534d29169ac31c8fa505e0
+0, 4, 4, 1, 408, fe9aab7b3378b9fc3e373ee626b887db
+0, 5, 5, 1, 408, fce72dfc7f9c0cb50ff73761b4d82c1f
+0, 6, 6, 1, 408, d4d98f42b1377e0f0ffaa66aa81d40c3
+0, 7, 7, 1, 408, 65c027646dc95a749ce2d7ad0a6beccc
+0, 8, 8, 1, 408, 317b283a0d907270f671272771022e69
+0, 9, 9, 1, 408, d3e2c008584608502f3e24c5c5f64028
diff --git a/tests/ref/fate/vp9-02-size-34x10 b/tests/ref/fate/vp9-02-size-34x10
index adcb22e1c4..a2ce10e9cb 100644
--- a/tests/ref/fate/vp9-02-size-34x10
+++ b/tests/ref/fate/vp9-02-size-34x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 510, fd7212b519783cf4831ce4bff91f2312
-0, 33, 33, 0, 510, 9768722ee939d80a6716865fdebca33d
-0, 66, 66, 0, 510, 328ee0f774eeafde00dcc4b9a8f4e9af
-0, 100, 100, 0, 510, f882fa6015fcb042094eadab5fa952cf
-0, 133, 133, 0, 510, 4331a3dabeae27d2bf3590eb96ce914a
-0, 166, 166, 0, 510, 0e15106bd8e90377f6ed8b464d17159c
-0, 200, 200, 0, 510, 8f062653ac2b83f7e541393e838d0e0f
-0, 233, 233, 0, 510, eeb98c1728c1a74510f8bfaf10fc0002
-0, 266, 266, 0, 510, 30bb058a67d6a5ee3693b21cbca5349a
-0, 300, 300, 0, 510, 7ce4b79983b3abc37b141a3bea56e0b7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 510, fd7212b519783cf4831ce4bff91f2312
+0, 1, 1, 1, 510, 9768722ee939d80a6716865fdebca33d
+0, 2, 2, 1, 510, 328ee0f774eeafde00dcc4b9a8f4e9af
+0, 3, 3, 1, 510, f882fa6015fcb042094eadab5fa952cf
+0, 4, 4, 1, 510, 4331a3dabeae27d2bf3590eb96ce914a
+0, 5, 5, 1, 510, 0e15106bd8e90377f6ed8b464d17159c
+0, 6, 6, 1, 510, 8f062653ac2b83f7e541393e838d0e0f
+0, 7, 7, 1, 510, eeb98c1728c1a74510f8bfaf10fc0002
+0, 8, 8, 1, 510, 30bb058a67d6a5ee3693b21cbca5349a
+0, 9, 9, 1, 510, 7ce4b79983b3abc37b141a3bea56e0b7
diff --git a/tests/ref/fate/vp9-02-size-34x16 b/tests/ref/fate/vp9-02-size-34x16
index db88976ed9..0c8dc673d7 100644
--- a/tests/ref/fate/vp9-02-size-34x16
+++ b/tests/ref/fate/vp9-02-size-34x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 816, e443c43101be00470c6a61c1a2995b5a
-0, 33, 33, 0, 816, 1e79b1b46ec704d360b5fb725913b0f1
-0, 66, 66, 0, 816, 6d5e77cafab6bc43498980c515d299d3
-0, 100, 100, 0, 816, 91c3bba5fd2aa29ee54c8f3783cfe5a2
-0, 133, 133, 0, 816, 9548d07c2a6204694d34e973e8339077
-0, 166, 166, 0, 816, 6819a34c7e3c13bee3ea2b18e12e92fd
-0, 200, 200, 0, 816, f75920457f01f65bf30ba1ec41076d4e
-0, 233, 233, 0, 816, 3a04f6cc0c348c21464b173ac6005043
-0, 266, 266, 0, 816, 93a3336374e8cc4dfb2c0b4716ab60ec
-0, 300, 300, 0, 816, 148af188b8a2ee93de406a01c2af180d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 816, e443c43101be00470c6a61c1a2995b5a
+0, 1, 1, 1, 816, 1e79b1b46ec704d360b5fb725913b0f1
+0, 2, 2, 1, 816, 6d5e77cafab6bc43498980c515d299d3
+0, 3, 3, 1, 816, 91c3bba5fd2aa29ee54c8f3783cfe5a2
+0, 4, 4, 1, 816, 9548d07c2a6204694d34e973e8339077
+0, 5, 5, 1, 816, 6819a34c7e3c13bee3ea2b18e12e92fd
+0, 6, 6, 1, 816, f75920457f01f65bf30ba1ec41076d4e
+0, 7, 7, 1, 816, 3a04f6cc0c348c21464b173ac6005043
+0, 8, 8, 1, 816, 93a3336374e8cc4dfb2c0b4716ab60ec
+0, 9, 9, 1, 816, 148af188b8a2ee93de406a01c2af180d
diff --git a/tests/ref/fate/vp9-02-size-34x18 b/tests/ref/fate/vp9-02-size-34x18
index d877088849..8c92b2de15 100644
--- a/tests/ref/fate/vp9-02-size-34x18
+++ b/tests/ref/fate/vp9-02-size-34x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 918, ab7eabb355e5163e7451945018fadebd
-0, 33, 33, 0, 918, b9a77cc0c769535808996a6de7b374ff
-0, 66, 66, 0, 918, bd773f11d89091b3c9ebc22d8291dd49
-0, 100, 100, 0, 918, 278c215d6c188752818f07f4d317c0e0
-0, 133, 133, 0, 918, b59856932c675c1ba587644c23cdb002
-0, 166, 166, 0, 918, 2bcaef04f89326a56025269a68742043
-0, 200, 200, 0, 918, 5abb4a1b96b4bc003cd19a146347c54e
-0, 233, 233, 0, 918, 26e36058f451ff80d498ac1c0343489f
-0, 266, 266, 0, 918, 57ac43fcc6f1a2c863188aca68d52524
-0, 300, 300, 0, 918, 282467118b5b7a986ccd28d16dab3ea7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 918, ab7eabb355e5163e7451945018fadebd
+0, 1, 1, 1, 918, b9a77cc0c769535808996a6de7b374ff
+0, 2, 2, 1, 918, bd773f11d89091b3c9ebc22d8291dd49
+0, 3, 3, 1, 918, 278c215d6c188752818f07f4d317c0e0
+0, 4, 4, 1, 918, b59856932c675c1ba587644c23cdb002
+0, 5, 5, 1, 918, 2bcaef04f89326a56025269a68742043
+0, 6, 6, 1, 918, 5abb4a1b96b4bc003cd19a146347c54e
+0, 7, 7, 1, 918, 26e36058f451ff80d498ac1c0343489f
+0, 8, 8, 1, 918, 57ac43fcc6f1a2c863188aca68d52524
+0, 9, 9, 1, 918, 282467118b5b7a986ccd28d16dab3ea7
diff --git a/tests/ref/fate/vp9-02-size-34x32 b/tests/ref/fate/vp9-02-size-34x32
index ce29241349..a9f804ef2e 100644
--- a/tests/ref/fate/vp9-02-size-34x32
+++ b/tests/ref/fate/vp9-02-size-34x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1632, 7e334867e27046fabf0f39365311c38c
-0, 33, 33, 0, 1632, d2a49216ecedea62f546e54c1552f163
-0, 66, 66, 0, 1632, f66e10d1779533e5b6e2b98369134833
-0, 100, 100, 0, 1632, 0054b8d4393df58eee87784862a29901
-0, 133, 133, 0, 1632, b9cdf3ebea0d1e3f1e0c42db2e11a3c2
-0, 166, 166, 0, 1632, c08a728d955a559457c82e44c3296148
-0, 200, 200, 0, 1632, d05f4c4a8b0e606525c3d388d26a9351
-0, 233, 233, 0, 1632, 78fc2544da88a1a21d6626b0f7bbcf8c
-0, 266, 266, 0, 1632, 90832c4fed05390377551359bb9a91f7
-0, 300, 300, 0, 1632, 5290a0e77081863398f36c7ae192710b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1632, 7e334867e27046fabf0f39365311c38c
+0, 1, 1, 1, 1632, d2a49216ecedea62f546e54c1552f163
+0, 2, 2, 1, 1632, f66e10d1779533e5b6e2b98369134833
+0, 3, 3, 1, 1632, 0054b8d4393df58eee87784862a29901
+0, 4, 4, 1, 1632, b9cdf3ebea0d1e3f1e0c42db2e11a3c2
+0, 5, 5, 1, 1632, c08a728d955a559457c82e44c3296148
+0, 6, 6, 1, 1632, d05f4c4a8b0e606525c3d388d26a9351
+0, 7, 7, 1, 1632, 78fc2544da88a1a21d6626b0f7bbcf8c
+0, 8, 8, 1, 1632, 90832c4fed05390377551359bb9a91f7
+0, 9, 9, 1, 1632, 5290a0e77081863398f36c7ae192710b
diff --git a/tests/ref/fate/vp9-02-size-34x34 b/tests/ref/fate/vp9-02-size-34x34
index fc5b90c4cc..4bed149904 100644
--- a/tests/ref/fate/vp9-02-size-34x34
+++ b/tests/ref/fate/vp9-02-size-34x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1734, 1bb98ba89abf6b86f47a851f8126e1ff
-0, 33, 33, 0, 1734, b960cc795c179afe7eec360c57fddd7f
-0, 66, 66, 0, 1734, a93cd094a80c542ecb7b6ac7720c5eff
-0, 100, 100, 0, 1734, f1cd34e4f0bf9b1238769f028708b742
-0, 133, 133, 0, 1734, f01437ad14450d2136a8fc971f180eb7
-0, 166, 166, 0, 1734, 8778230f1182c2227bf1e253bd85df4c
-0, 200, 200, 0, 1734, 1d1d5cf6c5cc9e73a1fa5b882e441d74
-0, 233, 233, 0, 1734, 2f7a1867487c56c252e35225f71adb55
-0, 266, 266, 0, 1734, 1d1aea21f70ceed596f22ec32d8712ee
-0, 300, 300, 0, 1734, 260e66df92f32bc853f4cd4ede692ea4
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1734, 1bb98ba89abf6b86f47a851f8126e1ff
+0, 1, 1, 1, 1734, b960cc795c179afe7eec360c57fddd7f
+0, 2, 2, 1, 1734, a93cd094a80c542ecb7b6ac7720c5eff
+0, 3, 3, 1, 1734, f1cd34e4f0bf9b1238769f028708b742
+0, 4, 4, 1, 1734, f01437ad14450d2136a8fc971f180eb7
+0, 5, 5, 1, 1734, 8778230f1182c2227bf1e253bd85df4c
+0, 6, 6, 1, 1734, 1d1d5cf6c5cc9e73a1fa5b882e441d74
+0, 7, 7, 1, 1734, 2f7a1867487c56c252e35225f71adb55
+0, 8, 8, 1, 1734, 1d1aea21f70ceed596f22ec32d8712ee
+0, 9, 9, 1, 1734, 260e66df92f32bc853f4cd4ede692ea4
diff --git a/tests/ref/fate/vp9-02-size-34x64 b/tests/ref/fate/vp9-02-size-34x64
index e31ad98c77..ac61f27f9e 100644
--- a/tests/ref/fate/vp9-02-size-34x64
+++ b/tests/ref/fate/vp9-02-size-34x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3264, 3856635223f578e1e7f7e7250a53cb8d
-0, 33, 33, 0, 3264, ee8d7c3a0ea165420d7e733b9e59219a
-0, 66, 66, 0, 3264, 3d33f06bac22131f04e3411fc216dc02
-0, 100, 100, 0, 3264, 7aea667775077de32250dac25fd24bb3
-0, 133, 133, 0, 3264, 43fb534551f153c5e9e60240df0bf3b4
-0, 166, 166, 0, 3264, d42b721aa2242d4258d97f840fdcc901
-0, 200, 200, 0, 3264, e876200d720cbe6e36e0ffb775c5ad6c
-0, 233, 233, 0, 3264, 453078449d8701270564086e58a1d69e
-0, 266, 266, 0, 3264, 22cb799a817d45a7591489e6faa31cb9
-0, 300, 300, 0, 3264, 628dc3f03bf5dd5cae135ad1e4b9ebf7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3264, 3856635223f578e1e7f7e7250a53cb8d
+0, 1, 1, 1, 3264, ee8d7c3a0ea165420d7e733b9e59219a
+0, 2, 2, 1, 3264, 3d33f06bac22131f04e3411fc216dc02
+0, 3, 3, 1, 3264, 7aea667775077de32250dac25fd24bb3
+0, 4, 4, 1, 3264, 43fb534551f153c5e9e60240df0bf3b4
+0, 5, 5, 1, 3264, d42b721aa2242d4258d97f840fdcc901
+0, 6, 6, 1, 3264, e876200d720cbe6e36e0ffb775c5ad6c
+0, 7, 7, 1, 3264, 453078449d8701270564086e58a1d69e
+0, 8, 8, 1, 3264, 22cb799a817d45a7591489e6faa31cb9
+0, 9, 9, 1, 3264, 628dc3f03bf5dd5cae135ad1e4b9ebf7
diff --git a/tests/ref/fate/vp9-02-size-34x66 b/tests/ref/fate/vp9-02-size-34x66
index 2182c29aeb..2bc9eb610e 100644
--- a/tests/ref/fate/vp9-02-size-34x66
+++ b/tests/ref/fate/vp9-02-size-34x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3366, bf4e568217906ee4b58dc4707bee8ef6
-0, 33, 33, 0, 3366, f823f8c7b6e47ba43215f3becd35208e
-0, 66, 66, 0, 3366, 1d986d65b502e77764428e21e77503a6
-0, 100, 100, 0, 3366, 73520382bc54d6aee165402518dd7b5d
-0, 133, 133, 0, 3366, c84e943758f2d7e37126172728838640
-0, 166, 166, 0, 3366, 1d4b298da98e4b66b31ad6874f726aa6
-0, 200, 200, 0, 3366, e67748eeb3c818deb8b51d321cd16a9c
-0, 233, 233, 0, 3366, 4d1514c63e669261beef9e35b04c241e
-0, 266, 266, 0, 3366, 57705e2131e2129efbc68b74a1e0459c
-0, 300, 300, 0, 3366, 681acf1b384856d6e544d8e7a79fc628
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3366, bf4e568217906ee4b58dc4707bee8ef6
+0, 1, 1, 1, 3366, f823f8c7b6e47ba43215f3becd35208e
+0, 2, 2, 1, 3366, 1d986d65b502e77764428e21e77503a6
+0, 3, 3, 1, 3366, 73520382bc54d6aee165402518dd7b5d
+0, 4, 4, 1, 3366, c84e943758f2d7e37126172728838640
+0, 5, 5, 1, 3366, 1d4b298da98e4b66b31ad6874f726aa6
+0, 6, 6, 1, 3366, e67748eeb3c818deb8b51d321cd16a9c
+0, 7, 7, 1, 3366, 4d1514c63e669261beef9e35b04c241e
+0, 8, 8, 1, 3366, 57705e2131e2129efbc68b74a1e0459c
+0, 9, 9, 1, 3366, 681acf1b384856d6e544d8e7a79fc628
diff --git a/tests/ref/fate/vp9-02-size-64x08 b/tests/ref/fate/vp9-02-size-64x08
index b15296add0..e1e01eeae2 100644
--- a/tests/ref/fate/vp9-02-size-64x08
+++ b/tests/ref/fate/vp9-02-size-64x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 768, d801797c94039b0a166d46e151ec912c
-0, 33, 33, 0, 768, 161ec22caa3689b214d9ab993424584b
-0, 66, 66, 0, 768, 499b589ecf1873e388c256ce948eabb9
-0, 100, 100, 0, 768, 22bc77650e3df70e3e36f2a1b8d8aa71
-0, 133, 133, 0, 768, 750e40530257a68211596a60de18bffa
-0, 166, 166, 0, 768, 4f812a92157e7186642656b59bc28a3d
-0, 200, 200, 0, 768, a3f141cec127a2c2e16740b8dd4ce56a
-0, 233, 233, 0, 768, a5ba9959bf65ab6e254e5b359a3d59b5
-0, 266, 266, 0, 768, baa72b8a57277d9e9ad4b92aab04f5d1
-0, 300, 300, 0, 768, 4cb9aebb6c9d5bd164461726de201549
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 768, d801797c94039b0a166d46e151ec912c
+0, 1, 1, 1, 768, 161ec22caa3689b214d9ab993424584b
+0, 2, 2, 1, 768, 499b589ecf1873e388c256ce948eabb9
+0, 3, 3, 1, 768, 22bc77650e3df70e3e36f2a1b8d8aa71
+0, 4, 4, 1, 768, 750e40530257a68211596a60de18bffa
+0, 5, 5, 1, 768, 4f812a92157e7186642656b59bc28a3d
+0, 6, 6, 1, 768, a3f141cec127a2c2e16740b8dd4ce56a
+0, 7, 7, 1, 768, a5ba9959bf65ab6e254e5b359a3d59b5
+0, 8, 8, 1, 768, baa72b8a57277d9e9ad4b92aab04f5d1
+0, 9, 9, 1, 768, 4cb9aebb6c9d5bd164461726de201549
diff --git a/tests/ref/fate/vp9-02-size-64x10 b/tests/ref/fate/vp9-02-size-64x10
index e499cc9da8..046e7ee686 100644
--- a/tests/ref/fate/vp9-02-size-64x10
+++ b/tests/ref/fate/vp9-02-size-64x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 960, 97eb5fd0599d482662eb0a1def5c5ef2
-0, 33, 33, 0, 960, dfdc1b61b478dcca8d411021486aa2ec
-0, 66, 66, 0, 960, 2cf560f068bdcb9e345951739091808e
-0, 100, 100, 0, 960, 33cacb04c0797fc7bd774251e04b7fb9
-0, 133, 133, 0, 960, 7fca126c0542c0dcdcf769b156bd85f5
-0, 166, 166, 0, 960, 8a46c5a48cb5bd34be8e647c127f8d61
-0, 200, 200, 0, 960, 1ddf07562c0b7dc68ed61b8e1a09fcf0
-0, 233, 233, 0, 960, d75911d5eb7fc75ffc3ee40344fc7ed2
-0, 266, 266, 0, 960, 498329c8a01d950286af11e1fcf3ac07
-0, 300, 300, 0, 960, 7a6ec019df5f3e419d389699094f87c3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 960, 97eb5fd0599d482662eb0a1def5c5ef2
+0, 1, 1, 1, 960, dfdc1b61b478dcca8d411021486aa2ec
+0, 2, 2, 1, 960, 2cf560f068bdcb9e345951739091808e
+0, 3, 3, 1, 960, 33cacb04c0797fc7bd774251e04b7fb9
+0, 4, 4, 1, 960, 7fca126c0542c0dcdcf769b156bd85f5
+0, 5, 5, 1, 960, 8a46c5a48cb5bd34be8e647c127f8d61
+0, 6, 6, 1, 960, 1ddf07562c0b7dc68ed61b8e1a09fcf0
+0, 7, 7, 1, 960, d75911d5eb7fc75ffc3ee40344fc7ed2
+0, 8, 8, 1, 960, 498329c8a01d950286af11e1fcf3ac07
+0, 9, 9, 1, 960, 7a6ec019df5f3e419d389699094f87c3
diff --git a/tests/ref/fate/vp9-02-size-64x16 b/tests/ref/fate/vp9-02-size-64x16
index 4810a6e6dd..16cb5dd30d 100644
--- a/tests/ref/fate/vp9-02-size-64x16
+++ b/tests/ref/fate/vp9-02-size-64x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1536, a43068a364cc42619e62406dcf17ddfc
-0, 33, 33, 0, 1536, 94691f93299bbf5b6ba3022b02b3e069
-0, 66, 66, 0, 1536, 3c8fc275490b4daf63ef6d8f9b7f81f6
-0, 100, 100, 0, 1536, 96c06031f0fcad49dfed256c5c737d07
-0, 133, 133, 0, 1536, f722d3a51790b55d070d57d3b9a53d0d
-0, 166, 166, 0, 1536, a753b3dfe13f5778f9f054e73e512ef1
-0, 200, 200, 0, 1536, fa12cbe6cbc38fa8a38ecbcf1af8833c
-0, 233, 233, 0, 1536, cb42303391ef6f76f77d14d2600cce12
-0, 266, 266, 0, 1536, e0c18bb1d4dcc8168b5fdd7c7963987e
-0, 300, 300, 0, 1536, 581b5291cb60e50326c0dfa6a2d09d8a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1536, a43068a364cc42619e62406dcf17ddfc
+0, 1, 1, 1, 1536, 94691f93299bbf5b6ba3022b02b3e069
+0, 2, 2, 1, 1536, 3c8fc275490b4daf63ef6d8f9b7f81f6
+0, 3, 3, 1, 1536, 96c06031f0fcad49dfed256c5c737d07
+0, 4, 4, 1, 1536, f722d3a51790b55d070d57d3b9a53d0d
+0, 5, 5, 1, 1536, a753b3dfe13f5778f9f054e73e512ef1
+0, 6, 6, 1, 1536, fa12cbe6cbc38fa8a38ecbcf1af8833c
+0, 7, 7, 1, 1536, cb42303391ef6f76f77d14d2600cce12
+0, 8, 8, 1, 1536, e0c18bb1d4dcc8168b5fdd7c7963987e
+0, 9, 9, 1, 1536, 581b5291cb60e50326c0dfa6a2d09d8a
diff --git a/tests/ref/fate/vp9-02-size-64x18 b/tests/ref/fate/vp9-02-size-64x18
index 1f8fdf3438..427acca3fa 100644
--- a/tests/ref/fate/vp9-02-size-64x18
+++ b/tests/ref/fate/vp9-02-size-64x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1728, adf7e84a351847683f6a8dd177019e29
-0, 33, 33, 0, 1728, 8227cf283a27277fbab3d7826e340337
-0, 66, 66, 0, 1728, a5551b16db948e395537310d12128e76
-0, 100, 100, 0, 1728, 4b57ed07dbc15de9ab6143656b2a7e8e
-0, 133, 133, 0, 1728, a15489495f0acc41f446e9689e4142d6
-0, 166, 166, 0, 1728, b0a0d5d3ff756e8ae19797455432755c
-0, 200, 200, 0, 1728, 094a440243d36edcdd3e9d0d070de011
-0, 233, 233, 0, 1728, a780bd61e1abbfbb28581784531608bd
-0, 266, 266, 0, 1728, 55886a8c7aad65683aa9366a38382512
-0, 300, 300, 0, 1728, 5ae5b24383f66720a62ed1001664051f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1728, adf7e84a351847683f6a8dd177019e29
+0, 1, 1, 1, 1728, 8227cf283a27277fbab3d7826e340337
+0, 2, 2, 1, 1728, a5551b16db948e395537310d12128e76
+0, 3, 3, 1, 1728, 4b57ed07dbc15de9ab6143656b2a7e8e
+0, 4, 4, 1, 1728, a15489495f0acc41f446e9689e4142d6
+0, 5, 5, 1, 1728, b0a0d5d3ff756e8ae19797455432755c
+0, 6, 6, 1, 1728, 094a440243d36edcdd3e9d0d070de011
+0, 7, 7, 1, 1728, a780bd61e1abbfbb28581784531608bd
+0, 8, 8, 1, 1728, 55886a8c7aad65683aa9366a38382512
+0, 9, 9, 1, 1728, 5ae5b24383f66720a62ed1001664051f
diff --git a/tests/ref/fate/vp9-02-size-64x32 b/tests/ref/fate/vp9-02-size-64x32
index ed1c9a52b5..a0f033ea67 100644
--- a/tests/ref/fate/vp9-02-size-64x32
+++ b/tests/ref/fate/vp9-02-size-64x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3072, 931ab6a2482c3e84bc7ef8dfbc251307
-0, 33, 33, 0, 3072, 3552a9d8470a64ed627a6dbb799b7811
-0, 66, 66, 0, 3072, cae1863fc606a0e3df3e708b7eefdf99
-0, 100, 100, 0, 3072, 4b825a07e235c4708b12a726da8e4cdf
-0, 133, 133, 0, 3072, 0dac578ef616a13be2b9db3c0d775524
-0, 166, 166, 0, 3072, bfd47cbab8285f301777351c8bc5553c
-0, 200, 200, 0, 3072, f29f9a0cfeaaae3bdeb26933bc7c17dc
-0, 233, 233, 0, 3072, c7f3a4d24dcf72ef195a402eff77d8f6
-0, 266, 266, 0, 3072, 88ede6207441a7953cf893032c353663
-0, 300, 300, 0, 3072, 258f4e86541813e3edb1fe5332ff4ab1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3072, 931ab6a2482c3e84bc7ef8dfbc251307
+0, 1, 1, 1, 3072, 3552a9d8470a64ed627a6dbb799b7811
+0, 2, 2, 1, 3072, cae1863fc606a0e3df3e708b7eefdf99
+0, 3, 3, 1, 3072, 4b825a07e235c4708b12a726da8e4cdf
+0, 4, 4, 1, 3072, 0dac578ef616a13be2b9db3c0d775524
+0, 5, 5, 1, 3072, bfd47cbab8285f301777351c8bc5553c
+0, 6, 6, 1, 3072, f29f9a0cfeaaae3bdeb26933bc7c17dc
+0, 7, 7, 1, 3072, c7f3a4d24dcf72ef195a402eff77d8f6
+0, 8, 8, 1, 3072, 88ede6207441a7953cf893032c353663
+0, 9, 9, 1, 3072, 258f4e86541813e3edb1fe5332ff4ab1
diff --git a/tests/ref/fate/vp9-02-size-64x34 b/tests/ref/fate/vp9-02-size-64x34
index c90f7e3e39..a8522729db 100644
--- a/tests/ref/fate/vp9-02-size-64x34
+++ b/tests/ref/fate/vp9-02-size-64x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3264, 68d00958a78e6252dd75d632806e2022
-0, 33, 33, 0, 3264, f7b6266e74200a669eecd241db787ee2
-0, 66, 66, 0, 3264, c8b88d43aee037857310edeb74bc66f4
-0, 100, 100, 0, 3264, c6d9a52baf3ca962574bff1364fcb8dc
-0, 133, 133, 0, 3264, b384fbf3ceef0affa69f5e81681edc6e
-0, 166, 166, 0, 3264, cd473f0c8d1cde98153402123a3ee7cf
-0, 200, 200, 0, 3264, c0f320a23c3e39719a3b3590fe3c2ab5
-0, 233, 233, 0, 3264, 751207d15a791728c1022f711a25cd68
-0, 266, 266, 0, 3264, 7396df89a0d88044cf7527420d193636
-0, 300, 300, 0, 3264, b772dd247838b0c3ed12713447894323
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3264, 68d00958a78e6252dd75d632806e2022
+0, 1, 1, 1, 3264, f7b6266e74200a669eecd241db787ee2
+0, 2, 2, 1, 3264, c8b88d43aee037857310edeb74bc66f4
+0, 3, 3, 1, 3264, c6d9a52baf3ca962574bff1364fcb8dc
+0, 4, 4, 1, 3264, b384fbf3ceef0affa69f5e81681edc6e
+0, 5, 5, 1, 3264, cd473f0c8d1cde98153402123a3ee7cf
+0, 6, 6, 1, 3264, c0f320a23c3e39719a3b3590fe3c2ab5
+0, 7, 7, 1, 3264, 751207d15a791728c1022f711a25cd68
+0, 8, 8, 1, 3264, 7396df89a0d88044cf7527420d193636
+0, 9, 9, 1, 3264, b772dd247838b0c3ed12713447894323
diff --git a/tests/ref/fate/vp9-02-size-64x64 b/tests/ref/fate/vp9-02-size-64x64
index 743732bd00..418febe51f 100644
--- a/tests/ref/fate/vp9-02-size-64x64
+++ b/tests/ref/fate/vp9-02-size-64x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 6144, 35f17db9076fa20368fddfa01543c746
-0, 33, 33, 0, 6144, 61cd775dfc177262da9a91d3912e6718
-0, 66, 66, 0, 6144, 8b8cf175f91425d703332b22b46c1c0e
-0, 100, 100, 0, 6144, 6041afbdd81e228f8f16384d3f9e988e
-0, 133, 133, 0, 6144, d30bd08897b50f518920014c7fa55df9
-0, 166, 166, 0, 6144, fb67222a183876b502f93e48bb779b70
-0, 200, 200, 0, 6144, 60830425ca1dcf3df4ee9c6cd75f066a
-0, 233, 233, 0, 6144, 3e178df858f7fcaa2552a1c5c719b5cc
-0, 266, 266, 0, 6144, 66718eb0c3981beb7c1119df8a2cd27e
-0, 300, 300, 0, 6144, 7c1912448c7756f7451888050760d73d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 6144, 35f17db9076fa20368fddfa01543c746
+0, 1, 1, 1, 6144, 61cd775dfc177262da9a91d3912e6718
+0, 2, 2, 1, 6144, 8b8cf175f91425d703332b22b46c1c0e
+0, 3, 3, 1, 6144, 6041afbdd81e228f8f16384d3f9e988e
+0, 4, 4, 1, 6144, d30bd08897b50f518920014c7fa55df9
+0, 5, 5, 1, 6144, fb67222a183876b502f93e48bb779b70
+0, 6, 6, 1, 6144, 60830425ca1dcf3df4ee9c6cd75f066a
+0, 7, 7, 1, 6144, 3e178df858f7fcaa2552a1c5c719b5cc
+0, 8, 8, 1, 6144, 66718eb0c3981beb7c1119df8a2cd27e
+0, 9, 9, 1, 6144, 7c1912448c7756f7451888050760d73d
diff --git a/tests/ref/fate/vp9-02-size-64x66 b/tests/ref/fate/vp9-02-size-64x66
index 7f2a052e0e..d358bd6219 100644
--- a/tests/ref/fate/vp9-02-size-64x66
+++ b/tests/ref/fate/vp9-02-size-64x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 6336, 88587de65acfc85ff56daac8ef5d12e6
-0, 33, 33, 0, 6336, be41f6c788b929b5b6b27c5674f40abd
-0, 66, 66, 0, 6336, 04ab3f88ca062a6911405fd84c7e9de4
-0, 100, 100, 0, 6336, 231436e0a68d19d3882f285d38aca3fb
-0, 133, 133, 0, 6336, 1a067e147a6740bb4ce57c4184437eea
-0, 166, 166, 0, 6336, be0c47e06c7e9439570473adf4713f5f
-0, 200, 200, 0, 6336, a213b0611247eafab0711748c25e88a0
-0, 233, 233, 0, 6336, b1df495aa3afb74399f91c74b527b93c
-0, 266, 266, 0, 6336, 46319f21069541e1ee1652621b957860
-0, 300, 300, 0, 6336, 313517a5721b2b14683e7eefc83e51b1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 6336, 88587de65acfc85ff56daac8ef5d12e6
+0, 1, 1, 1, 6336, be41f6c788b929b5b6b27c5674f40abd
+0, 2, 2, 1, 6336, 04ab3f88ca062a6911405fd84c7e9de4
+0, 3, 3, 1, 6336, 231436e0a68d19d3882f285d38aca3fb
+0, 4, 4, 1, 6336, 1a067e147a6740bb4ce57c4184437eea
+0, 5, 5, 1, 6336, be0c47e06c7e9439570473adf4713f5f
+0, 6, 6, 1, 6336, a213b0611247eafab0711748c25e88a0
+0, 7, 7, 1, 6336, b1df495aa3afb74399f91c74b527b93c
+0, 8, 8, 1, 6336, 46319f21069541e1ee1652621b957860
+0, 9, 9, 1, 6336, 313517a5721b2b14683e7eefc83e51b1
diff --git a/tests/ref/fate/vp9-02-size-66x08 b/tests/ref/fate/vp9-02-size-66x08
index 76ec31e60c..426f91b7e8 100644
--- a/tests/ref/fate/vp9-02-size-66x08
+++ b/tests/ref/fate/vp9-02-size-66x08
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 792, 3b16847e60786706fc339abc452746ff
-0, 33, 33, 0, 792, 365a5951cb127d6df183fe5d5000f493
-0, 66, 66, 0, 792, 6d4bceb815ca7717c4a3f86a6670703a
-0, 100, 100, 0, 792, 5a0a03d4788934285448c85788ae8d71
-0, 133, 133, 0, 792, 8712f9a82d07447e7a0d0a37ddc3858d
-0, 166, 166, 0, 792, cff32e6c183c16962207a86d7c6cf0a0
-0, 200, 200, 0, 792, dc933d90f87110651d7efb39854d3d46
-0, 233, 233, 0, 792, d1299562a022521f0c3cb30668f83b6d
-0, 266, 266, 0, 792, 5054254ca125d7c7e6df4001397170cd
-0, 300, 300, 0, 792, a6bd7c7c0b02afa8d25f911ec847c61a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 792, 3b16847e60786706fc339abc452746ff
+0, 1, 1, 1, 792, 365a5951cb127d6df183fe5d5000f493
+0, 2, 2, 1, 792, 6d4bceb815ca7717c4a3f86a6670703a
+0, 3, 3, 1, 792, 5a0a03d4788934285448c85788ae8d71
+0, 4, 4, 1, 792, 8712f9a82d07447e7a0d0a37ddc3858d
+0, 5, 5, 1, 792, cff32e6c183c16962207a86d7c6cf0a0
+0, 6, 6, 1, 792, dc933d90f87110651d7efb39854d3d46
+0, 7, 7, 1, 792, d1299562a022521f0c3cb30668f83b6d
+0, 8, 8, 1, 792, 5054254ca125d7c7e6df4001397170cd
+0, 9, 9, 1, 792, a6bd7c7c0b02afa8d25f911ec847c61a
diff --git a/tests/ref/fate/vp9-02-size-66x10 b/tests/ref/fate/vp9-02-size-66x10
index 63c775bf29..8e0133a90f 100644
--- a/tests/ref/fate/vp9-02-size-66x10
+++ b/tests/ref/fate/vp9-02-size-66x10
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 990, 7cbd8c6b2fb35c0c3063cb7a379944c9
-0, 33, 33, 0, 990, 14062e74b98bed1ca982f408bc14326c
-0, 66, 66, 0, 990, f6d6868d849aa74b27df1c5f40c7096e
-0, 100, 100, 0, 990, 719c8d7e3769466ee8e3dca3f4747a0e
-0, 133, 133, 0, 990, a72e1a7a4c82ec09ea77f87b0e6f25aa
-0, 166, 166, 0, 990, a5163d142b429afa155cc2f1401a0b8a
-0, 200, 200, 0, 990, 27762d813dd1f80d6aaed5f197124fa5
-0, 233, 233, 0, 990, 02e94454660f3528abbde8f50e94288f
-0, 266, 266, 0, 990, 1d57dcfa57a55d96f14cfe471aac2e0b
-0, 300, 300, 0, 990, 7804477923c0cd067bd09ebca3529775
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 990, 7cbd8c6b2fb35c0c3063cb7a379944c9
+0, 1, 1, 1, 990, 14062e74b98bed1ca982f408bc14326c
+0, 2, 2, 1, 990, f6d6868d849aa74b27df1c5f40c7096e
+0, 3, 3, 1, 990, 719c8d7e3769466ee8e3dca3f4747a0e
+0, 4, 4, 1, 990, a72e1a7a4c82ec09ea77f87b0e6f25aa
+0, 5, 5, 1, 990, a5163d142b429afa155cc2f1401a0b8a
+0, 6, 6, 1, 990, 27762d813dd1f80d6aaed5f197124fa5
+0, 7, 7, 1, 990, 02e94454660f3528abbde8f50e94288f
+0, 8, 8, 1, 990, 1d57dcfa57a55d96f14cfe471aac2e0b
+0, 9, 9, 1, 990, 7804477923c0cd067bd09ebca3529775
diff --git a/tests/ref/fate/vp9-02-size-66x16 b/tests/ref/fate/vp9-02-size-66x16
index 97d67c855b..4bdc1bae57 100644
--- a/tests/ref/fate/vp9-02-size-66x16
+++ b/tests/ref/fate/vp9-02-size-66x16
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1584, fa2f292d273c37dc2804a70d1cae1e9d
-0, 33, 33, 0, 1584, ba75d90652c021bc7ca061352e6e94ce
-0, 66, 66, 0, 1584, e65d9a205bd17d100e50c7b6a7ea772d
-0, 100, 100, 0, 1584, 46f9e9ff891576b9462f21d48b7b9e2b
-0, 133, 133, 0, 1584, d23cedacf3a37cf6b2774e0b18b6b9d7
-0, 166, 166, 0, 1584, 84329f7716a6db5a7e64a68a1155bfc6
-0, 200, 200, 0, 1584, ad62286b0e13f4e54df4445cdd4fd4e3
-0, 233, 233, 0, 1584, 4511529eb24b21eb63e280070f888642
-0, 266, 266, 0, 1584, 4e1c122df1785e0e9134c43c85082e05
-0, 300, 300, 0, 1584, ac3a3747a00be3f9f58155648fcf9b24
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1584, fa2f292d273c37dc2804a70d1cae1e9d
+0, 1, 1, 1, 1584, ba75d90652c021bc7ca061352e6e94ce
+0, 2, 2, 1, 1584, e65d9a205bd17d100e50c7b6a7ea772d
+0, 3, 3, 1, 1584, 46f9e9ff891576b9462f21d48b7b9e2b
+0, 4, 4, 1, 1584, d23cedacf3a37cf6b2774e0b18b6b9d7
+0, 5, 5, 1, 1584, 84329f7716a6db5a7e64a68a1155bfc6
+0, 6, 6, 1, 1584, ad62286b0e13f4e54df4445cdd4fd4e3
+0, 7, 7, 1, 1584, 4511529eb24b21eb63e280070f888642
+0, 8, 8, 1, 1584, 4e1c122df1785e0e9134c43c85082e05
+0, 9, 9, 1, 1584, ac3a3747a00be3f9f58155648fcf9b24
diff --git a/tests/ref/fate/vp9-02-size-66x18 b/tests/ref/fate/vp9-02-size-66x18
index 03928deef4..3b395dd213 100644
--- a/tests/ref/fate/vp9-02-size-66x18
+++ b/tests/ref/fate/vp9-02-size-66x18
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 1782, fda5ad9bf70a51b3a41bdcabf2cce32a
-0, 33, 33, 0, 1782, 91916fb20ad542a7a3ad276e6505f9b0
-0, 66, 66, 0, 1782, e18e5d11aec483c76afd68f7e64415a4
-0, 100, 100, 0, 1782, c13da01c2b6c09101bda7af93ad5fd07
-0, 133, 133, 0, 1782, ed8d2568b2ad9c7bd980cba0d3b95cff
-0, 166, 166, 0, 1782, e6f3cf312b69d37579e77f2e52cc936b
-0, 200, 200, 0, 1782, e509f3682e9c4bcdb0889e044b1979b7
-0, 233, 233, 0, 1782, acc3945e557cd7a9642f08a656444976
-0, 266, 266, 0, 1782, 44ddd03aa8f03ba393f12fc6a1b3fc17
-0, 300, 300, 0, 1782, fdd3e68132c742d9f0cf0ea6fff2a074
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1782, fda5ad9bf70a51b3a41bdcabf2cce32a
+0, 1, 1, 1, 1782, 91916fb20ad542a7a3ad276e6505f9b0
+0, 2, 2, 1, 1782, e18e5d11aec483c76afd68f7e64415a4
+0, 3, 3, 1, 1782, c13da01c2b6c09101bda7af93ad5fd07
+0, 4, 4, 1, 1782, ed8d2568b2ad9c7bd980cba0d3b95cff
+0, 5, 5, 1, 1782, e6f3cf312b69d37579e77f2e52cc936b
+0, 6, 6, 1, 1782, e509f3682e9c4bcdb0889e044b1979b7
+0, 7, 7, 1, 1782, acc3945e557cd7a9642f08a656444976
+0, 8, 8, 1, 1782, 44ddd03aa8f03ba393f12fc6a1b3fc17
+0, 9, 9, 1, 1782, fdd3e68132c742d9f0cf0ea6fff2a074
diff --git a/tests/ref/fate/vp9-02-size-66x32 b/tests/ref/fate/vp9-02-size-66x32
index 0901a7bdfe..14b9cb0ffa 100644
--- a/tests/ref/fate/vp9-02-size-66x32
+++ b/tests/ref/fate/vp9-02-size-66x32
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3168, 013cd22aea6bfeccc8ec809abd52be5c
-0, 33, 33, 0, 3168, 0980adfb0ef879b3c960797272f025ad
-0, 66, 66, 0, 3168, d1411ffa0429befb8c71d3ab45acee92
-0, 100, 100, 0, 3168, 6c6f825379eaf21709a45be77def7a63
-0, 133, 133, 0, 3168, bab632ef00a080739a41c692f2b21c3a
-0, 166, 166, 0, 3168, fc0f6045aca252f2e904730227b8f337
-0, 200, 200, 0, 3168, c8dbea209329463bfd9238a11b8d5b17
-0, 233, 233, 0, 3168, 457247bf4186ed8459e0a1564f0e68f2
-0, 266, 266, 0, 3168, baa55e20bd7c73960b080d8a0c8db4d5
-0, 300, 300, 0, 3168, dc8933e8edc98cd0cfca44ae22997c62
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3168, 013cd22aea6bfeccc8ec809abd52be5c
+0, 1, 1, 1, 3168, 0980adfb0ef879b3c960797272f025ad
+0, 2, 2, 1, 3168, d1411ffa0429befb8c71d3ab45acee92
+0, 3, 3, 1, 3168, 6c6f825379eaf21709a45be77def7a63
+0, 4, 4, 1, 3168, bab632ef00a080739a41c692f2b21c3a
+0, 5, 5, 1, 3168, fc0f6045aca252f2e904730227b8f337
+0, 6, 6, 1, 3168, c8dbea209329463bfd9238a11b8d5b17
+0, 7, 7, 1, 3168, 457247bf4186ed8459e0a1564f0e68f2
+0, 8, 8, 1, 3168, baa55e20bd7c73960b080d8a0c8db4d5
+0, 9, 9, 1, 3168, dc8933e8edc98cd0cfca44ae22997c62
diff --git a/tests/ref/fate/vp9-02-size-66x34 b/tests/ref/fate/vp9-02-size-66x34
index a999573009..79bc91cdd4 100644
--- a/tests/ref/fate/vp9-02-size-66x34
+++ b/tests/ref/fate/vp9-02-size-66x34
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 3366, 6821eb3fcd1d10db32eff70468dcf9c1
-0, 33, 33, 0, 3366, ed0094d347d9f250d46b4903cbc14801
-0, 66, 66, 0, 3366, fd018555dc9a62b8074d46e7c0fd0b40
-0, 100, 100, 0, 3366, 05d5baf9f2e62bbeeb3809a099e84147
-0, 133, 133, 0, 3366, 7a150c265214269c08e05fe4f296122d
-0, 166, 166, 0, 3366, 9a7ae61d4bb125ee4c4ccce9cc1c3664
-0, 200, 200, 0, 3366, 5a88fd6d96dcbc4255e98dfe19ff96b8
-0, 233, 233, 0, 3366, 4192c273a46b2b196c871ead0e61ec71
-0, 266, 266, 0, 3366, e79ebfc47e755f5db221f392c3216278
-0, 300, 300, 0, 3366, b995c5f483a2e553baf4f66d1a47fc57
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 3366, 6821eb3fcd1d10db32eff70468dcf9c1
+0, 1, 1, 1, 3366, ed0094d347d9f250d46b4903cbc14801
+0, 2, 2, 1, 3366, fd018555dc9a62b8074d46e7c0fd0b40
+0, 3, 3, 1, 3366, 05d5baf9f2e62bbeeb3809a099e84147
+0, 4, 4, 1, 3366, 7a150c265214269c08e05fe4f296122d
+0, 5, 5, 1, 3366, 9a7ae61d4bb125ee4c4ccce9cc1c3664
+0, 6, 6, 1, 3366, 5a88fd6d96dcbc4255e98dfe19ff96b8
+0, 7, 7, 1, 3366, 4192c273a46b2b196c871ead0e61ec71
+0, 8, 8, 1, 3366, e79ebfc47e755f5db221f392c3216278
+0, 9, 9, 1, 3366, b995c5f483a2e553baf4f66d1a47fc57
diff --git a/tests/ref/fate/vp9-02-size-66x64 b/tests/ref/fate/vp9-02-size-66x64
index 3a3d6c8c70..a89e10f9ed 100644
--- a/tests/ref/fate/vp9-02-size-66x64
+++ b/tests/ref/fate/vp9-02-size-66x64
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 6336, 929086fbb3e117bd53110b64c1ee915b
-0, 33, 33, 0, 6336, 9ed45f5e40dd2393434e14a0c0160c63
-0, 66, 66, 0, 6336, 5cdade692b1baf23e61896da18e3e44f
-0, 100, 100, 0, 6336, 11a2ebac61a3f826ec41c8031899e55c
-0, 133, 133, 0, 6336, 621a1e0142b94d14db9c2121553a11fb
-0, 166, 166, 0, 6336, 029a29590f7255f1bc9ff9b7a000ca25
-0, 200, 200, 0, 6336, 5fde42becf6bf054d04e2a0fa1b2d55e
-0, 233, 233, 0, 6336, 5b8ba552cef1931e1412fb4f3420748b
-0, 266, 266, 0, 6336, d41cd7d418f6ec1db802a01a90cfee1e
-0, 300, 300, 0, 6336, cea99c93a84a82edff8c6069d131453f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 6336, 929086fbb3e117bd53110b64c1ee915b
+0, 1, 1, 1, 6336, 9ed45f5e40dd2393434e14a0c0160c63
+0, 2, 2, 1, 6336, 5cdade692b1baf23e61896da18e3e44f
+0, 3, 3, 1, 6336, 11a2ebac61a3f826ec41c8031899e55c
+0, 4, 4, 1, 6336, 621a1e0142b94d14db9c2121553a11fb
+0, 5, 5, 1, 6336, 029a29590f7255f1bc9ff9b7a000ca25
+0, 6, 6, 1, 6336, 5fde42becf6bf054d04e2a0fa1b2d55e
+0, 7, 7, 1, 6336, 5b8ba552cef1931e1412fb4f3420748b
+0, 8, 8, 1, 6336, d41cd7d418f6ec1db802a01a90cfee1e
+0, 9, 9, 1, 6336, cea99c93a84a82edff8c6069d131453f
diff --git a/tests/ref/fate/vp9-02-size-66x66 b/tests/ref/fate/vp9-02-size-66x66
index 5c4e1aca72..73aa4e7bc1 100644
--- a/tests/ref/fate/vp9-02-size-66x66
+++ b/tests/ref/fate/vp9-02-size-66x66
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 6534, 69f9028d52f95d2e7f986c57b19fc018
-0, 33, 33, 0, 6534, 068e611f62b3f6222f6b1699748c8fbf
-0, 66, 66, 0, 6534, 3d3fec78ff2274241a7958f17a773a19
-0, 100, 100, 0, 6534, 93d71ef1a2d00c7e70e76ccc1859143d
-0, 133, 133, 0, 6534, 5a35a640d52bc0930825b963b0b9e830
-0, 166, 166, 0, 6534, 782223239e6b1ca1bedbd25d9652a07c
-0, 200, 200, 0, 6534, a4b5e8a319cbc9a12d3e36127c7f0fbb
-0, 233, 233, 0, 6534, a3e2d9a78fa42b3c817aadfd31fd2d16
-0, 266, 266, 0, 6534, e9fc6b83535735f46006f3e4b376755f
-0, 300, 300, 0, 6534, 80223f600dfe86021bd0e83fecdc4b2b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 6534, 69f9028d52f95d2e7f986c57b19fc018
+0, 1, 1, 1, 6534, 068e611f62b3f6222f6b1699748c8fbf
+0, 2, 2, 1, 6534, 3d3fec78ff2274241a7958f17a773a19
+0, 3, 3, 1, 6534, 93d71ef1a2d00c7e70e76ccc1859143d
+0, 4, 4, 1, 6534, 5a35a640d52bc0930825b963b0b9e830
+0, 5, 5, 1, 6534, 782223239e6b1ca1bedbd25d9652a07c
+0, 6, 6, 1, 6534, a4b5e8a319cbc9a12d3e36127c7f0fbb
+0, 7, 7, 1, 6534, a3e2d9a78fa42b3c817aadfd31fd2d16
+0, 8, 8, 1, 6534, e9fc6b83535735f46006f3e4b376755f
+0, 9, 9, 1, 6534, 80223f600dfe86021bd0e83fecdc4b2b
diff --git a/tests/ref/fate/vp9-03-deltaq b/tests/ref/fate/vp9-03-deltaq
index c8ed23fd47..293abad2a7 100644
--- a/tests/ref/fate/vp9-03-deltaq
+++ b/tests/ref/fate/vp9-03-deltaq
@@ -1,3 +1,7 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 126720, 2f90d606edc511c8c960530dd915cb98
-0, 33, 33, 0, 126720, 7fd451a057d6341b2b0d116f59e41a13
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 126720, 2f90d606edc511c8c960530dd915cb98
+0, 1, 1, 1, 126720, 7fd451a057d6341b2b0d116f59e41a13
diff --git a/tests/ref/fate/vp9-03-size-196x196 b/tests/ref/fate/vp9-03-size-196x196
index 39efcba832..1c4156b31f 100644
--- a/tests/ref/fate/vp9-03-size-196x196
+++ b/tests/ref/fate/vp9-03-size-196x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 57624, 14cc1c34b8106e35238d4650a9123852
-0, 33, 33, 0, 57624, 66e0bb9136ea24e30b781a4610b428a1
-0, 66, 66, 0, 57624, 8e36679c20a3a3e974fdacf7a9343817
-0, 100, 100, 0, 57624, 2669fd03ce7ce01f4fc9db23e06fffdb
-0, 133, 133, 0, 57624, 46ced29eb6edf2136c8ee19e9a87380f
-0, 166, 166, 0, 57624, 4e4138b65a30bc56cd18663a1799f98f
-0, 200, 200, 0, 57624, 580b0431b5f808c67e50ed34e62f39ad
-0, 233, 233, 0, 57624, 1339bbe256d8499ab17d6a550f7dac70
-0, 266, 266, 0, 57624, 89b9dac29a4c4136249c40a3763dc114
-0, 300, 300, 0, 57624, a735d341d7df9dcd0b6e51a82b813f61
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 57624, 14cc1c34b8106e35238d4650a9123852
+0, 1, 1, 1, 57624, 66e0bb9136ea24e30b781a4610b428a1
+0, 2, 2, 1, 57624, 8e36679c20a3a3e974fdacf7a9343817
+0, 3, 3, 1, 57624, 2669fd03ce7ce01f4fc9db23e06fffdb
+0, 4, 4, 1, 57624, 46ced29eb6edf2136c8ee19e9a87380f
+0, 5, 5, 1, 57624, 4e4138b65a30bc56cd18663a1799f98f
+0, 6, 6, 1, 57624, 580b0431b5f808c67e50ed34e62f39ad
+0, 7, 7, 1, 57624, 1339bbe256d8499ab17d6a550f7dac70
+0, 8, 8, 1, 57624, 89b9dac29a4c4136249c40a3763dc114
+0, 9, 9, 1, 57624, a735d341d7df9dcd0b6e51a82b813f61
diff --git a/tests/ref/fate/vp9-03-size-196x198 b/tests/ref/fate/vp9-03-size-196x198
index b328ab442f..294c7de628 100644
--- a/tests/ref/fate/vp9-03-size-196x198
+++ b/tests/ref/fate/vp9-03-size-196x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 58212, d2bd2dfaf2ac22b3f2499844f228d89a
-0, 33, 33, 0, 58212, e066448baeb39da04b22d4d2ebd27b0a
-0, 66, 66, 0, 58212, aace53c0ecca2596c51dd5e70da7abc4
-0, 100, 100, 0, 58212, 077256d024ab101918d10ae61142f203
-0, 133, 133, 0, 58212, e2bfdad36b0365d41dc6813a371111ee
-0, 166, 166, 0, 58212, 17495af68b0a2c075899849382f3b046
-0, 200, 200, 0, 58212, 7853db163344798e5c37672adaac92d8
-0, 233, 233, 0, 58212, 7b2ee2e1ca709c58457c7d818e47c95c
-0, 266, 266, 0, 58212, f7eb3ce10561628f932861358a30b414
-0, 300, 300, 0, 58212, 3182374f5aa539fd0faa44ed4a7492e5
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 58212, d2bd2dfaf2ac22b3f2499844f228d89a
+0, 1, 1, 1, 58212, e066448baeb39da04b22d4d2ebd27b0a
+0, 2, 2, 1, 58212, aace53c0ecca2596c51dd5e70da7abc4
+0, 3, 3, 1, 58212, 077256d024ab101918d10ae61142f203
+0, 4, 4, 1, 58212, e2bfdad36b0365d41dc6813a371111ee
+0, 5, 5, 1, 58212, 17495af68b0a2c075899849382f3b046
+0, 6, 6, 1, 58212, 7853db163344798e5c37672adaac92d8
+0, 7, 7, 1, 58212, 7b2ee2e1ca709c58457c7d818e47c95c
+0, 8, 8, 1, 58212, f7eb3ce10561628f932861358a30b414
+0, 9, 9, 1, 58212, 3182374f5aa539fd0faa44ed4a7492e5
diff --git a/tests/ref/fate/vp9-03-size-196x200 b/tests/ref/fate/vp9-03-size-196x200
index 0aed80257b..d0882e50fc 100644
--- a/tests/ref/fate/vp9-03-size-196x200
+++ b/tests/ref/fate/vp9-03-size-196x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 58800, b2f2ac3e3833ae1b4dd075fe00210373
-0, 33, 33, 0, 58800, c0cce05e56a07111fe62553fa3a87074
-0, 66, 66, 0, 58800, 626aab3de03242073e03504e166b4697
-0, 100, 100, 0, 58800, 574d2c810f0bbfac57f1f06c2b97445c
-0, 133, 133, 0, 58800, 7d5bc5860bd1422d08396fe080452099
-0, 166, 166, 0, 58800, 5d47bbfb0f5cdecfe8415ca2caddc206
-0, 200, 200, 0, 58800, fbef6a0fa51029d0475975945ccf4b36
-0, 233, 233, 0, 58800, c9179c153bcb2a8e9d17ed04e5e2c39c
-0, 266, 266, 0, 58800, 107d796592cf2140d4d492beadba2d68
-0, 300, 300, 0, 58800, eee46f9ee67fc1121bffb63aeb7c768f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 58800, b2f2ac3e3833ae1b4dd075fe00210373
+0, 1, 1, 1, 58800, c0cce05e56a07111fe62553fa3a87074
+0, 2, 2, 1, 58800, 626aab3de03242073e03504e166b4697
+0, 3, 3, 1, 58800, 574d2c810f0bbfac57f1f06c2b97445c
+0, 4, 4, 1, 58800, 7d5bc5860bd1422d08396fe080452099
+0, 5, 5, 1, 58800, 5d47bbfb0f5cdecfe8415ca2caddc206
+0, 6, 6, 1, 58800, fbef6a0fa51029d0475975945ccf4b36
+0, 7, 7, 1, 58800, c9179c153bcb2a8e9d17ed04e5e2c39c
+0, 8, 8, 1, 58800, 107d796592cf2140d4d492beadba2d68
+0, 9, 9, 1, 58800, eee46f9ee67fc1121bffb63aeb7c768f
diff --git a/tests/ref/fate/vp9-03-size-196x202 b/tests/ref/fate/vp9-03-size-196x202
index 9f8c3f2518..20f46ea570 100644
--- a/tests/ref/fate/vp9-03-size-196x202
+++ b/tests/ref/fate/vp9-03-size-196x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 59388, 7109d2ef160828ece26337f36fcfc092
-0, 33, 33, 0, 59388, bdaa6612f81a956d9b20d55a04df8346
-0, 66, 66, 0, 59388, 15eb75495d2713a64415b990b058d5ca
-0, 100, 100, 0, 59388, b997c84553475ba84e8ba3d7ee19ae4e
-0, 133, 133, 0, 59388, 63a8badd691bcf643cf676d029ce8a6c
-0, 166, 166, 0, 59388, b8ca23d9b3418c4c36040a215b2b7917
-0, 200, 200, 0, 59388, 1be0da18386c35e4a5e5d5d32d9a4468
-0, 233, 233, 0, 59388, e75a03fa70fe7e6b3a8d8ce7dc8305f1
-0, 266, 266, 0, 59388, cbd2b60df9209025c8e890771a05321d
-0, 300, 300, 0, 59388, c655d6fcc3333917b66358a9ac2b1357
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59388, 7109d2ef160828ece26337f36fcfc092
+0, 1, 1, 1, 59388, bdaa6612f81a956d9b20d55a04df8346
+0, 2, 2, 1, 59388, 15eb75495d2713a64415b990b058d5ca
+0, 3, 3, 1, 59388, b997c84553475ba84e8ba3d7ee19ae4e
+0, 4, 4, 1, 59388, 63a8badd691bcf643cf676d029ce8a6c
+0, 5, 5, 1, 59388, b8ca23d9b3418c4c36040a215b2b7917
+0, 6, 6, 1, 59388, 1be0da18386c35e4a5e5d5d32d9a4468
+0, 7, 7, 1, 59388, e75a03fa70fe7e6b3a8d8ce7dc8305f1
+0, 8, 8, 1, 59388, cbd2b60df9209025c8e890771a05321d
+0, 9, 9, 1, 59388, c655d6fcc3333917b66358a9ac2b1357
diff --git a/tests/ref/fate/vp9-03-size-196x208 b/tests/ref/fate/vp9-03-size-196x208
index 2e6880239f..b1ffd8fbce 100644
--- a/tests/ref/fate/vp9-03-size-196x208
+++ b/tests/ref/fate/vp9-03-size-196x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61152, efa2a2a76a0fe709a78e491346cfcf29
-0, 33, 33, 0, 61152, 97de85e21b408878853fa870104707d7
-0, 66, 66, 0, 61152, 419bd1157e156d3059190d6b561c57dd
-0, 100, 100, 0, 61152, fbb6e01c524fc7c8007c6cfe2c64f467
-0, 133, 133, 0, 61152, 7453994c2e9901fa23f295ec0b556f9c
-0, 166, 166, 0, 61152, ba39dc984789fa2c4b833cd88013cc97
-0, 200, 200, 0, 61152, cea5061cac1be18d5f9a9301a5460491
-0, 233, 233, 0, 61152, 1c583018c425b1a91949e0c3eb0a4152
-0, 266, 266, 0, 61152, b48be02280ac6f97731af69bcf18de25
-0, 300, 300, 0, 61152, 6f8ab465214d8374c9ff77b939da333e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61152, efa2a2a76a0fe709a78e491346cfcf29
+0, 1, 1, 1, 61152, 97de85e21b408878853fa870104707d7
+0, 2, 2, 1, 61152, 419bd1157e156d3059190d6b561c57dd
+0, 3, 3, 1, 61152, fbb6e01c524fc7c8007c6cfe2c64f467
+0, 4, 4, 1, 61152, 7453994c2e9901fa23f295ec0b556f9c
+0, 5, 5, 1, 61152, ba39dc984789fa2c4b833cd88013cc97
+0, 6, 6, 1, 61152, cea5061cac1be18d5f9a9301a5460491
+0, 7, 7, 1, 61152, 1c583018c425b1a91949e0c3eb0a4152
+0, 8, 8, 1, 61152, b48be02280ac6f97731af69bcf18de25
+0, 9, 9, 1, 61152, 6f8ab465214d8374c9ff77b939da333e
diff --git a/tests/ref/fate/vp9-03-size-196x210 b/tests/ref/fate/vp9-03-size-196x210
index 7d24b47abd..72488741a6 100644
--- a/tests/ref/fate/vp9-03-size-196x210
+++ b/tests/ref/fate/vp9-03-size-196x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61740, fccc18714a9ed3840bd6e9c6ca4858e5
-0, 33, 33, 0, 61740, a8f6eb43cf6ed670eb180c5051de06f7
-0, 66, 66, 0, 61740, 6a9baf9eae6e799deaefd6e801f7ace3
-0, 100, 100, 0, 61740, 3bb44c8a45aab088c9887c11bc6a4acf
-0, 133, 133, 0, 61740, 0907a7e926be9e54bbb087251b4715d9
-0, 166, 166, 0, 61740, 10fef2876c20eb3f9570c0c23e5acc69
-0, 200, 200, 0, 61740, ffe5d2b6d874af0f878075c97940ccfb
-0, 233, 233, 0, 61740, d10fae10144ff88075048827203f7e9c
-0, 266, 266, 0, 61740, bdf35736ac625f2178902c1f24d513c0
-0, 300, 300, 0, 61740, 30882bf2c21785be6234b637c4b16b28
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61740, fccc18714a9ed3840bd6e9c6ca4858e5
+0, 1, 1, 1, 61740, a8f6eb43cf6ed670eb180c5051de06f7
+0, 2, 2, 1, 61740, 6a9baf9eae6e799deaefd6e801f7ace3
+0, 3, 3, 1, 61740, 3bb44c8a45aab088c9887c11bc6a4acf
+0, 4, 4, 1, 61740, 0907a7e926be9e54bbb087251b4715d9
+0, 5, 5, 1, 61740, 10fef2876c20eb3f9570c0c23e5acc69
+0, 6, 6, 1, 61740, ffe5d2b6d874af0f878075c97940ccfb
+0, 7, 7, 1, 61740, d10fae10144ff88075048827203f7e9c
+0, 8, 8, 1, 61740, bdf35736ac625f2178902c1f24d513c0
+0, 9, 9, 1, 61740, 30882bf2c21785be6234b637c4b16b28
diff --git a/tests/ref/fate/vp9-03-size-196x224 b/tests/ref/fate/vp9-03-size-196x224
index 152de0d149..fb49188fb6 100644
--- a/tests/ref/fate/vp9-03-size-196x224
+++ b/tests/ref/fate/vp9-03-size-196x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 65856, 13263674ea5aa619250dfd139bda872f
-0, 33, 33, 0, 65856, 39f5cbd8917f2b3a1df8cf2b786266de
-0, 66, 66, 0, 65856, f9aade31f9e3065f3d5b8645ef099ac6
-0, 100, 100, 0, 65856, 124f9664380f092e692b5e881f5a8fcc
-0, 133, 133, 0, 65856, e8e040e417830f5e911537828ace21b7
-0, 166, 166, 0, 65856, 84ce09882b9c184a787e8022e6d8c8de
-0, 200, 200, 0, 65856, b1397fd91814e4fdc4f75c89161ced26
-0, 233, 233, 0, 65856, d64f39d64d248f0223ed359e092d46cb
-0, 266, 266, 0, 65856, e04ee663dcc52eebd74255671c6f4ec9
-0, 300, 300, 0, 65856, 955303cb73bf072c693f37d9778ca2b6
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 65856, 13263674ea5aa619250dfd139bda872f
+0, 1, 1, 1, 65856, 39f5cbd8917f2b3a1df8cf2b786266de
+0, 2, 2, 1, 65856, f9aade31f9e3065f3d5b8645ef099ac6
+0, 3, 3, 1, 65856, 124f9664380f092e692b5e881f5a8fcc
+0, 4, 4, 1, 65856, e8e040e417830f5e911537828ace21b7
+0, 5, 5, 1, 65856, 84ce09882b9c184a787e8022e6d8c8de
+0, 6, 6, 1, 65856, b1397fd91814e4fdc4f75c89161ced26
+0, 7, 7, 1, 65856, d64f39d64d248f0223ed359e092d46cb
+0, 8, 8, 1, 65856, e04ee663dcc52eebd74255671c6f4ec9
+0, 9, 9, 1, 65856, 955303cb73bf072c693f37d9778ca2b6
diff --git a/tests/ref/fate/vp9-03-size-196x226 b/tests/ref/fate/vp9-03-size-196x226
index 974ab53737..0ef318aa58 100644
--- a/tests/ref/fate/vp9-03-size-196x226
+++ b/tests/ref/fate/vp9-03-size-196x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 66444, 5cb240f10761f59687612ed589759800
-0, 33, 33, 0, 66444, 9d8d5b57336ddfa5c9c5100a0302197d
-0, 66, 66, 0, 66444, 9db74997d23b16f527c63e88795331dc
-0, 100, 100, 0, 66444, 52758cd901533e790334d464bee516da
-0, 133, 133, 0, 66444, 40e671b9b85d07b13acba85eb64bbbaa
-0, 166, 166, 0, 66444, 8524b2cd2c9bb3e41c6167f8269e75d2
-0, 200, 200, 0, 66444, ff194ad6fa180fde86cc05a99c0580ec
-0, 233, 233, 0, 66444, 22ab303cb37745a73c227cd7d1c70003
-0, 266, 266, 0, 66444, 01986c58e82e0b5194418f5b75a8599c
-0, 300, 300, 0, 66444, eedfc9c14cbf3fa10402dbed52103848
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 66444, 5cb240f10761f59687612ed589759800
+0, 1, 1, 1, 66444, 9d8d5b57336ddfa5c9c5100a0302197d
+0, 2, 2, 1, 66444, 9db74997d23b16f527c63e88795331dc
+0, 3, 3, 1, 66444, 52758cd901533e790334d464bee516da
+0, 4, 4, 1, 66444, 40e671b9b85d07b13acba85eb64bbbaa
+0, 5, 5, 1, 66444, 8524b2cd2c9bb3e41c6167f8269e75d2
+0, 6, 6, 1, 66444, ff194ad6fa180fde86cc05a99c0580ec
+0, 7, 7, 1, 66444, 22ab303cb37745a73c227cd7d1c70003
+0, 8, 8, 1, 66444, 01986c58e82e0b5194418f5b75a8599c
+0, 9, 9, 1, 66444, eedfc9c14cbf3fa10402dbed52103848
diff --git a/tests/ref/fate/vp9-03-size-198x196 b/tests/ref/fate/vp9-03-size-198x196
index 595299ecab..2d02a4922f 100644
--- a/tests/ref/fate/vp9-03-size-198x196
+++ b/tests/ref/fate/vp9-03-size-198x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 58212, c980866a6f17d4107ce128ee112d74cf
-0, 33, 33, 0, 58212, d4d5d2a10e73f1d09919355dc4d63d48
-0, 66, 66, 0, 58212, 82c76ed020acb68ff9d8bd81899aa6f8
-0, 100, 100, 0, 58212, 8330705fa354fb5838af56dcf9cc0980
-0, 133, 133, 0, 58212, e47b63d839a592e6372d18249bf5bc0c
-0, 166, 166, 0, 58212, b6095b6f752a50e96cab52e7c3fd52f3
-0, 200, 200, 0, 58212, fc4786f48b6ee31043d94f79c5c8a54f
-0, 233, 233, 0, 58212, 7d3d06c96496bd5ab44fe5489877771d
-0, 266, 266, 0, 58212, 5b96de089a9faa2dc01697fe9dd97f7f
-0, 300, 300, 0, 58212, d7361203b4c264067dcb7bf6912e8df2
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 58212, c980866a6f17d4107ce128ee112d74cf
+0, 1, 1, 1, 58212, d4d5d2a10e73f1d09919355dc4d63d48
+0, 2, 2, 1, 58212, 82c76ed020acb68ff9d8bd81899aa6f8
+0, 3, 3, 1, 58212, 8330705fa354fb5838af56dcf9cc0980
+0, 4, 4, 1, 58212, e47b63d839a592e6372d18249bf5bc0c
+0, 5, 5, 1, 58212, b6095b6f752a50e96cab52e7c3fd52f3
+0, 6, 6, 1, 58212, fc4786f48b6ee31043d94f79c5c8a54f
+0, 7, 7, 1, 58212, 7d3d06c96496bd5ab44fe5489877771d
+0, 8, 8, 1, 58212, 5b96de089a9faa2dc01697fe9dd97f7f
+0, 9, 9, 1, 58212, d7361203b4c264067dcb7bf6912e8df2
diff --git a/tests/ref/fate/vp9-03-size-198x198 b/tests/ref/fate/vp9-03-size-198x198
index 890dd9c75e..f458f53cd9 100644
--- a/tests/ref/fate/vp9-03-size-198x198
+++ b/tests/ref/fate/vp9-03-size-198x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 58806, ee0760611da9938e72f551d219671c76
-0, 33, 33, 0, 58806, c512cb8a864c25318254438c7170f373
-0, 66, 66, 0, 58806, aaea10aeb7dfd1f9f6dc77adccfcd56f
-0, 100, 100, 0, 58806, fb4e68ce202d9c6ecbddc6fe50b1cd7b
-0, 133, 133, 0, 58806, 57a803d02f0d71ec4c3c17a112574525
-0, 166, 166, 0, 58806, 526d0beaf7ef721c3a6ae8bf3505fd78
-0, 200, 200, 0, 58806, 972ab31f81dbb79c2273bcfc98569e8b
-0, 233, 233, 0, 58806, e1f05d62691bd1a9494d57449417415c
-0, 266, 266, 0, 58806, bc39a559b25e5a1ac698e0101bd6bf29
-0, 300, 300, 0, 58806, 04caed04ac21c76af873e21899860fb2
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 58806, ee0760611da9938e72f551d219671c76
+0, 1, 1, 1, 58806, c512cb8a864c25318254438c7170f373
+0, 2, 2, 1, 58806, aaea10aeb7dfd1f9f6dc77adccfcd56f
+0, 3, 3, 1, 58806, fb4e68ce202d9c6ecbddc6fe50b1cd7b
+0, 4, 4, 1, 58806, 57a803d02f0d71ec4c3c17a112574525
+0, 5, 5, 1, 58806, 526d0beaf7ef721c3a6ae8bf3505fd78
+0, 6, 6, 1, 58806, 972ab31f81dbb79c2273bcfc98569e8b
+0, 7, 7, 1, 58806, e1f05d62691bd1a9494d57449417415c
+0, 8, 8, 1, 58806, bc39a559b25e5a1ac698e0101bd6bf29
+0, 9, 9, 1, 58806, 04caed04ac21c76af873e21899860fb2
diff --git a/tests/ref/fate/vp9-03-size-198x200 b/tests/ref/fate/vp9-03-size-198x200
index 2535ceb2a0..176b9d9a38 100644
--- a/tests/ref/fate/vp9-03-size-198x200
+++ b/tests/ref/fate/vp9-03-size-198x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 59400, fb0e8171b0f91d9b2ceb5430db27a67b
-0, 33, 33, 0, 59400, 73f121e6aa0e6290cfd06ac9b033c772
-0, 66, 66, 0, 59400, 4113897efc44f49f5169a579bee03596
-0, 100, 100, 0, 59400, aec1d4cf1a15e12b689980cfe136d5d6
-0, 133, 133, 0, 59400, 1322af65f647254330120e67ddae38bd
-0, 166, 166, 0, 59400, 5d28c1684451812c9db41433e6286d85
-0, 200, 200, 0, 59400, 33843fc49d1d8655520c2f42332222ca
-0, 233, 233, 0, 59400, 92a8125d8c75eaf6159d5f431c5c71bf
-0, 266, 266, 0, 59400, 5bc96553842f65a3e37f012b72b580f5
-0, 300, 300, 0, 59400, de5eb6299ee5034dc3b01cdc94bf810a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59400, fb0e8171b0f91d9b2ceb5430db27a67b
+0, 1, 1, 1, 59400, 73f121e6aa0e6290cfd06ac9b033c772
+0, 2, 2, 1, 59400, 4113897efc44f49f5169a579bee03596
+0, 3, 3, 1, 59400, aec1d4cf1a15e12b689980cfe136d5d6
+0, 4, 4, 1, 59400, 1322af65f647254330120e67ddae38bd
+0, 5, 5, 1, 59400, 5d28c1684451812c9db41433e6286d85
+0, 6, 6, 1, 59400, 33843fc49d1d8655520c2f42332222ca
+0, 7, 7, 1, 59400, 92a8125d8c75eaf6159d5f431c5c71bf
+0, 8, 8, 1, 59400, 5bc96553842f65a3e37f012b72b580f5
+0, 9, 9, 1, 59400, de5eb6299ee5034dc3b01cdc94bf810a
diff --git a/tests/ref/fate/vp9-03-size-198x202 b/tests/ref/fate/vp9-03-size-198x202
index ba4d425718..371a874d2c 100644
--- a/tests/ref/fate/vp9-03-size-198x202
+++ b/tests/ref/fate/vp9-03-size-198x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 59994, f5e1cf4cc56742fadddf42189a3f65e3
-0, 33, 33, 0, 59994, f3e8ca2c8deb29a6b5bfe415b39c901e
-0, 66, 66, 0, 59994, 89c513049e41e145bca46a7f7119567c
-0, 100, 100, 0, 59994, 419089035739e84f1aa14ccdf34edcb1
-0, 133, 133, 0, 59994, 4962c98c23b16b9257869a8ad5138731
-0, 166, 166, 0, 59994, fde9e858ec895c36c2d8071e69f68db6
-0, 200, 200, 0, 59994, 42e1271915f31a00be3627fa866ce3ee
-0, 233, 233, 0, 59994, c15f794933f913861a6d0041ff2fccdb
-0, 266, 266, 0, 59994, 35dab245ba952dc6fddc1a9668c30b28
-0, 300, 300, 0, 59994, 30bb4ef77cdde9cf5aea0f1287183b23
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59994, f5e1cf4cc56742fadddf42189a3f65e3
+0, 1, 1, 1, 59994, f3e8ca2c8deb29a6b5bfe415b39c901e
+0, 2, 2, 1, 59994, 89c513049e41e145bca46a7f7119567c
+0, 3, 3, 1, 59994, 419089035739e84f1aa14ccdf34edcb1
+0, 4, 4, 1, 59994, 4962c98c23b16b9257869a8ad5138731
+0, 5, 5, 1, 59994, fde9e858ec895c36c2d8071e69f68db6
+0, 6, 6, 1, 59994, 42e1271915f31a00be3627fa866ce3ee
+0, 7, 7, 1, 59994, c15f794933f913861a6d0041ff2fccdb
+0, 8, 8, 1, 59994, 35dab245ba952dc6fddc1a9668c30b28
+0, 9, 9, 1, 59994, 30bb4ef77cdde9cf5aea0f1287183b23
diff --git a/tests/ref/fate/vp9-03-size-198x208 b/tests/ref/fate/vp9-03-size-198x208
index 49fea910cb..95b2e0606a 100644
--- a/tests/ref/fate/vp9-03-size-198x208
+++ b/tests/ref/fate/vp9-03-size-198x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61776, d45b561f81cbfcca8a1dddbc2bf8ca31
-0, 33, 33, 0, 61776, 3664f63b2e59e380622caadb7a05545e
-0, 66, 66, 0, 61776, 0662fa199512320704efecc10af1aaa4
-0, 100, 100, 0, 61776, d8dc00882e73be89d0585663892cbcff
-0, 133, 133, 0, 61776, ff64b8d50b7c5b484a06dab09a26147c
-0, 166, 166, 0, 61776, 1771b6a55112eb7ea10885d1390339cc
-0, 200, 200, 0, 61776, 0d5944e8a13e3c2faffb562bbe2671a8
-0, 233, 233, 0, 61776, 744bed3a88407b75a8ff27a1b0cec64e
-0, 266, 266, 0, 61776, 3887415f2ab10d2a265c4a413e7060b9
-0, 300, 300, 0, 61776, 7dd683019b19b464bc0436f41e0b7c87
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61776, d45b561f81cbfcca8a1dddbc2bf8ca31
+0, 1, 1, 1, 61776, 3664f63b2e59e380622caadb7a05545e
+0, 2, 2, 1, 61776, 0662fa199512320704efecc10af1aaa4
+0, 3, 3, 1, 61776, d8dc00882e73be89d0585663892cbcff
+0, 4, 4, 1, 61776, ff64b8d50b7c5b484a06dab09a26147c
+0, 5, 5, 1, 61776, 1771b6a55112eb7ea10885d1390339cc
+0, 6, 6, 1, 61776, 0d5944e8a13e3c2faffb562bbe2671a8
+0, 7, 7, 1, 61776, 744bed3a88407b75a8ff27a1b0cec64e
+0, 8, 8, 1, 61776, 3887415f2ab10d2a265c4a413e7060b9
+0, 9, 9, 1, 61776, 7dd683019b19b464bc0436f41e0b7c87
diff --git a/tests/ref/fate/vp9-03-size-198x210 b/tests/ref/fate/vp9-03-size-198x210
index 899fd50bd2..1e2790afea 100644
--- a/tests/ref/fate/vp9-03-size-198x210
+++ b/tests/ref/fate/vp9-03-size-198x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 62370, 8525a27170982c059d5904c1af3b43fb
-0, 33, 33, 0, 62370, c4eb329733913360384d3917a58f6f36
-0, 66, 66, 0, 62370, ec118b87c9cba0e4bd89fd43567cca4e
-0, 100, 100, 0, 62370, 7e57c6caba7924823977e2c9bc11f7fa
-0, 133, 133, 0, 62370, f77ffb7228a5eda848acc40ff636ecad
-0, 166, 166, 0, 62370, c5dddafbe3badcbbcaaebe97076e0394
-0, 200, 200, 0, 62370, 34d69ae2e5b4c4fbcc51627237c9abc5
-0, 233, 233, 0, 62370, d9c63fa8b18d6c54e5fa31db866c06cc
-0, 266, 266, 0, 62370, 7ab392764a399328bf35977539e3148a
-0, 300, 300, 0, 62370, 7fbb7bae3ec775298aaa49a286dfb9d1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 62370, 8525a27170982c059d5904c1af3b43fb
+0, 1, 1, 1, 62370, c4eb329733913360384d3917a58f6f36
+0, 2, 2, 1, 62370, ec118b87c9cba0e4bd89fd43567cca4e
+0, 3, 3, 1, 62370, 7e57c6caba7924823977e2c9bc11f7fa
+0, 4, 4, 1, 62370, f77ffb7228a5eda848acc40ff636ecad
+0, 5, 5, 1, 62370, c5dddafbe3badcbbcaaebe97076e0394
+0, 6, 6, 1, 62370, 34d69ae2e5b4c4fbcc51627237c9abc5
+0, 7, 7, 1, 62370, d9c63fa8b18d6c54e5fa31db866c06cc
+0, 8, 8, 1, 62370, 7ab392764a399328bf35977539e3148a
+0, 9, 9, 1, 62370, 7fbb7bae3ec775298aaa49a286dfb9d1
diff --git a/tests/ref/fate/vp9-03-size-198x224 b/tests/ref/fate/vp9-03-size-198x224
index b972f6af03..7cccf9b0e3 100644
--- a/tests/ref/fate/vp9-03-size-198x224
+++ b/tests/ref/fate/vp9-03-size-198x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 66528, 5f69230bfd8bb485bd85552b18339fc0
-0, 33, 33, 0, 66528, f5c365774fc1d0bffd5025ce2e931aaf
-0, 66, 66, 0, 66528, 2898234103c3624e6470ae82c916e000
-0, 100, 100, 0, 66528, d82a7fa705180b68a8ee8cb7de0cdd2d
-0, 133, 133, 0, 66528, 144a162d418deae62883a2cc4c341b4c
-0, 166, 166, 0, 66528, b3419a48385e42ca15717289ff2daa1c
-0, 200, 200, 0, 66528, d6306b5737f88f989bf2e6a1084a94fe
-0, 233, 233, 0, 66528, 5669761d7417b52b3cf81d44a13e3fb7
-0, 266, 266, 0, 66528, 3f730b8658d7a6657d1af38c75357512
-0, 300, 300, 0, 66528, 27df68d515148f732325bf821037d59f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 66528, 5f69230bfd8bb485bd85552b18339fc0
+0, 1, 1, 1, 66528, f5c365774fc1d0bffd5025ce2e931aaf
+0, 2, 2, 1, 66528, 2898234103c3624e6470ae82c916e000
+0, 3, 3, 1, 66528, d82a7fa705180b68a8ee8cb7de0cdd2d
+0, 4, 4, 1, 66528, 144a162d418deae62883a2cc4c341b4c
+0, 5, 5, 1, 66528, b3419a48385e42ca15717289ff2daa1c
+0, 6, 6, 1, 66528, d6306b5737f88f989bf2e6a1084a94fe
+0, 7, 7, 1, 66528, 5669761d7417b52b3cf81d44a13e3fb7
+0, 8, 8, 1, 66528, 3f730b8658d7a6657d1af38c75357512
+0, 9, 9, 1, 66528, 27df68d515148f732325bf821037d59f
diff --git a/tests/ref/fate/vp9-03-size-198x226 b/tests/ref/fate/vp9-03-size-198x226
index 4f622cd0bf..81136e6437 100644
--- a/tests/ref/fate/vp9-03-size-198x226
+++ b/tests/ref/fate/vp9-03-size-198x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67122, 412c33a8fd71c99e68e6701b050b107c
-0, 33, 33, 0, 67122, 8e69483ff8a094096dd550b30be20dde
-0, 66, 66, 0, 67122, b8df87ab3d2613be31a3743e34d7e794
-0, 100, 100, 0, 67122, ec4b08a4014950f1fe04e83f8a790af0
-0, 133, 133, 0, 67122, 030da2b60627d879730108826ce6632c
-0, 166, 166, 0, 67122, 03aab0c9b4d75bc0b47fa5237e9efe3d
-0, 200, 200, 0, 67122, fd01e369df258f340eb8e486c07ae136
-0, 233, 233, 0, 67122, 1c301f0e60c96008fd7b6e8de1ebaa29
-0, 266, 266, 0, 67122, 912723f43b2b36366c3e6ab122d31801
-0, 300, 300, 0, 67122, b2774a66f7aa0fb7dd7e64b0d67818cd
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67122, 412c33a8fd71c99e68e6701b050b107c
+0, 1, 1, 1, 67122, 8e69483ff8a094096dd550b30be20dde
+0, 2, 2, 1, 67122, b8df87ab3d2613be31a3743e34d7e794
+0, 3, 3, 1, 67122, ec4b08a4014950f1fe04e83f8a790af0
+0, 4, 4, 1, 67122, 030da2b60627d879730108826ce6632c
+0, 5, 5, 1, 67122, 03aab0c9b4d75bc0b47fa5237e9efe3d
+0, 6, 6, 1, 67122, fd01e369df258f340eb8e486c07ae136
+0, 7, 7, 1, 67122, 1c301f0e60c96008fd7b6e8de1ebaa29
+0, 8, 8, 1, 67122, 912723f43b2b36366c3e6ab122d31801
+0, 9, 9, 1, 67122, b2774a66f7aa0fb7dd7e64b0d67818cd
diff --git a/tests/ref/fate/vp9-03-size-200x196 b/tests/ref/fate/vp9-03-size-200x196
index b0b7ee2a92..670d115af7 100644
--- a/tests/ref/fate/vp9-03-size-200x196
+++ b/tests/ref/fate/vp9-03-size-200x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 58800, 651a0627c6cdaee8b46e1f8c4121a368
-0, 33, 33, 0, 58800, 3e63075148df16f69c933cf6c63e078c
-0, 66, 66, 0, 58800, edf18e52b7d52af2bb7594ed358542d8
-0, 100, 100, 0, 58800, 30284124756d00d10f4f8428206ceab8
-0, 133, 133, 0, 58800, 6f6ecde53cd0ea5298f4529d396460c6
-0, 166, 166, 0, 58800, 0431d389278957fbef3e72f69f3ce008
-0, 200, 200, 0, 58800, a047c60c4c60d2ea1f79c86dc98cdf8e
-0, 233, 233, 0, 58800, dceda8bf128a8cdcadfa6c5db49cde51
-0, 266, 266, 0, 58800, d8a6283637f5abda17e0bf150eac2983
-0, 300, 300, 0, 58800, 33dca31ef26fdd0daf9971c8de685d01
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 58800, 651a0627c6cdaee8b46e1f8c4121a368
+0, 1, 1, 1, 58800, 3e63075148df16f69c933cf6c63e078c
+0, 2, 2, 1, 58800, edf18e52b7d52af2bb7594ed358542d8
+0, 3, 3, 1, 58800, 30284124756d00d10f4f8428206ceab8
+0, 4, 4, 1, 58800, 6f6ecde53cd0ea5298f4529d396460c6
+0, 5, 5, 1, 58800, 0431d389278957fbef3e72f69f3ce008
+0, 6, 6, 1, 58800, a047c60c4c60d2ea1f79c86dc98cdf8e
+0, 7, 7, 1, 58800, dceda8bf128a8cdcadfa6c5db49cde51
+0, 8, 8, 1, 58800, d8a6283637f5abda17e0bf150eac2983
+0, 9, 9, 1, 58800, 33dca31ef26fdd0daf9971c8de685d01
diff --git a/tests/ref/fate/vp9-03-size-200x198 b/tests/ref/fate/vp9-03-size-200x198
index f7c7c3fe89..fd375066c8 100644
--- a/tests/ref/fate/vp9-03-size-200x198
+++ b/tests/ref/fate/vp9-03-size-200x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 59400, d4b3578d800c747bcabaa484a140ffb0
-0, 33, 33, 0, 59400, a40f6f8c384c5dc3d5546d960bb6d9e5
-0, 66, 66, 0, 59400, e270ae8754d9906dd88b1c7d05280801
-0, 100, 100, 0, 59400, bde7fde5012840c5e188f3b29f4f0003
-0, 133, 133, 0, 59400, 8f8510c1130615b64fb8469af66ff678
-0, 166, 166, 0, 59400, 79b9d4e0c64f82a6e9540394222a593d
-0, 200, 200, 0, 59400, 34852ac9ca5c6bfa51736296784343c7
-0, 233, 233, 0, 59400, b055218509dbed644113642f8f0ac8a8
-0, 266, 266, 0, 59400, 1628866b436f1c4b892474025226e545
-0, 300, 300, 0, 59400, 3fdec760c04e30c90e74afb38dbf757c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59400, d4b3578d800c747bcabaa484a140ffb0
+0, 1, 1, 1, 59400, a40f6f8c384c5dc3d5546d960bb6d9e5
+0, 2, 2, 1, 59400, e270ae8754d9906dd88b1c7d05280801
+0, 3, 3, 1, 59400, bde7fde5012840c5e188f3b29f4f0003
+0, 4, 4, 1, 59400, 8f8510c1130615b64fb8469af66ff678
+0, 5, 5, 1, 59400, 79b9d4e0c64f82a6e9540394222a593d
+0, 6, 6, 1, 59400, 34852ac9ca5c6bfa51736296784343c7
+0, 7, 7, 1, 59400, b055218509dbed644113642f8f0ac8a8
+0, 8, 8, 1, 59400, 1628866b436f1c4b892474025226e545
+0, 9, 9, 1, 59400, 3fdec760c04e30c90e74afb38dbf757c
diff --git a/tests/ref/fate/vp9-03-size-200x200 b/tests/ref/fate/vp9-03-size-200x200
index 6f453701b3..d5806a1f6d 100644
--- a/tests/ref/fate/vp9-03-size-200x200
+++ b/tests/ref/fate/vp9-03-size-200x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 60000, b339f4e563afadb25f43b8c05b12dc03
-0, 33, 33, 0, 60000, 3bd5280e7fb42400085b0b1dbba1905e
-0, 66, 66, 0, 60000, acf1c84cabff763fe2073d2c1f183bfc
-0, 100, 100, 0, 60000, eaa4983b6baf907efb11d137644569d2
-0, 133, 133, 0, 60000, 8a1871c8dc38a19dfd4ac571ad7f39be
-0, 166, 166, 0, 60000, 0be539bd51f5f364828dd0abc70360be
-0, 200, 200, 0, 60000, df60622d2c9f294f61d738be9e3bd16c
-0, 233, 233, 0, 60000, 22b3f1d51ddf92c7d2add305ba0ef405
-0, 266, 266, 0, 60000, 01ba29be721e64a5a50526de0797c7d3
-0, 300, 300, 0, 60000, 7b7aa7fa0e58202b3104671375762587
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 60000, b339f4e563afadb25f43b8c05b12dc03
+0, 1, 1, 1, 60000, 3bd5280e7fb42400085b0b1dbba1905e
+0, 2, 2, 1, 60000, acf1c84cabff763fe2073d2c1f183bfc
+0, 3, 3, 1, 60000, eaa4983b6baf907efb11d137644569d2
+0, 4, 4, 1, 60000, 8a1871c8dc38a19dfd4ac571ad7f39be
+0, 5, 5, 1, 60000, 0be539bd51f5f364828dd0abc70360be
+0, 6, 6, 1, 60000, df60622d2c9f294f61d738be9e3bd16c
+0, 7, 7, 1, 60000, 22b3f1d51ddf92c7d2add305ba0ef405
+0, 8, 8, 1, 60000, 01ba29be721e64a5a50526de0797c7d3
+0, 9, 9, 1, 60000, 7b7aa7fa0e58202b3104671375762587
diff --git a/tests/ref/fate/vp9-03-size-200x202 b/tests/ref/fate/vp9-03-size-200x202
index 3657e80e19..3f6ee8bfa5 100644
--- a/tests/ref/fate/vp9-03-size-200x202
+++ b/tests/ref/fate/vp9-03-size-200x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 60600, c4a13df44e66f06961dd72fc990439e9
-0, 33, 33, 0, 60600, 81c73b8d3806ad96af8f422914a253f8
-0, 66, 66, 0, 60600, 05f77526125e802be9cb306e375ded6e
-0, 100, 100, 0, 60600, ab2e224840ff89abec2c675a23a73094
-0, 133, 133, 0, 60600, c30f58f88819eb57102678b169e15188
-0, 166, 166, 0, 60600, 33e5e2799eb4a9c548c8372fd6769db9
-0, 200, 200, 0, 60600, fa53c1c7e60bd1d00335af542ec69ed7
-0, 233, 233, 0, 60600, 534cafe658af10a314d6d084e55b3620
-0, 266, 266, 0, 60600, 502529e4fbecc8b890abf665fa21f53c
-0, 300, 300, 0, 60600, bf1f73c6e77370bc51a770c8ae87bd12
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 60600, c4a13df44e66f06961dd72fc990439e9
+0, 1, 1, 1, 60600, 81c73b8d3806ad96af8f422914a253f8
+0, 2, 2, 1, 60600, 05f77526125e802be9cb306e375ded6e
+0, 3, 3, 1, 60600, ab2e224840ff89abec2c675a23a73094
+0, 4, 4, 1, 60600, c30f58f88819eb57102678b169e15188
+0, 5, 5, 1, 60600, 33e5e2799eb4a9c548c8372fd6769db9
+0, 6, 6, 1, 60600, fa53c1c7e60bd1d00335af542ec69ed7
+0, 7, 7, 1, 60600, 534cafe658af10a314d6d084e55b3620
+0, 8, 8, 1, 60600, 502529e4fbecc8b890abf665fa21f53c
+0, 9, 9, 1, 60600, bf1f73c6e77370bc51a770c8ae87bd12
diff --git a/tests/ref/fate/vp9-03-size-200x208 b/tests/ref/fate/vp9-03-size-200x208
index cd47b57d24..ea1cb0cff7 100644
--- a/tests/ref/fate/vp9-03-size-200x208
+++ b/tests/ref/fate/vp9-03-size-200x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 62400, 702748bec18c500dd41d93ae74b11d56
-0, 33, 33, 0, 62400, 4fb542190dab2fd673724d47451ff6ee
-0, 66, 66, 0, 62400, dbb4d27d52797dab67e39d32092c9d44
-0, 100, 100, 0, 62400, e4a0ed1572207b7ba433896bba711148
-0, 133, 133, 0, 62400, 28ec32bc165f4f9d455efec8a7aa8737
-0, 166, 166, 0, 62400, a95910575a6423abffb28ca38c384b34
-0, 200, 200, 0, 62400, 791f1c558c5467725f4614a75a8a687e
-0, 233, 233, 0, 62400, cfd3e12f84f7a811966721e890228313
-0, 266, 266, 0, 62400, 824c5fdf938551c28ac1c996645ae52f
-0, 300, 300, 0, 62400, 7465917fdd0206e393968232a0ec5193
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 62400, 702748bec18c500dd41d93ae74b11d56
+0, 1, 1, 1, 62400, 4fb542190dab2fd673724d47451ff6ee
+0, 2, 2, 1, 62400, dbb4d27d52797dab67e39d32092c9d44
+0, 3, 3, 1, 62400, e4a0ed1572207b7ba433896bba711148
+0, 4, 4, 1, 62400, 28ec32bc165f4f9d455efec8a7aa8737
+0, 5, 5, 1, 62400, a95910575a6423abffb28ca38c384b34
+0, 6, 6, 1, 62400, 791f1c558c5467725f4614a75a8a687e
+0, 7, 7, 1, 62400, cfd3e12f84f7a811966721e890228313
+0, 8, 8, 1, 62400, 824c5fdf938551c28ac1c996645ae52f
+0, 9, 9, 1, 62400, 7465917fdd0206e393968232a0ec5193
diff --git a/tests/ref/fate/vp9-03-size-200x210 b/tests/ref/fate/vp9-03-size-200x210
index 91eaa80f82..7c459d2d70 100644
--- a/tests/ref/fate/vp9-03-size-200x210
+++ b/tests/ref/fate/vp9-03-size-200x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 63000, 31ef44bd12ae702f306c55eba10d2ba7
-0, 33, 33, 0, 63000, 83e9d913f5aa058d79a81047ca45e4a2
-0, 66, 66, 0, 63000, b5e21313b859f1e2c67aaac5fefc9f68
-0, 100, 100, 0, 63000, 959d63c1b219c3479af673a9a8b8d82c
-0, 133, 133, 0, 63000, ffcfaf42b69c7cd92f6e3c21987ff7df
-0, 166, 166, 0, 63000, e9667d3ee4d8179da44de4fbffcb7df2
-0, 200, 200, 0, 63000, 5e2c841bcf4ec6f3a05020d36986fe5b
-0, 233, 233, 0, 63000, 19fe287c30bd4c90b00a9631409568c0
-0, 266, 266, 0, 63000, 58a8843e50b19860a0a91e1e1bb63bfd
-0, 300, 300, 0, 63000, 0ebd31e18597a567f96645acbb2500cf
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 63000, 31ef44bd12ae702f306c55eba10d2ba7
+0, 1, 1, 1, 63000, 83e9d913f5aa058d79a81047ca45e4a2
+0, 2, 2, 1, 63000, b5e21313b859f1e2c67aaac5fefc9f68
+0, 3, 3, 1, 63000, 959d63c1b219c3479af673a9a8b8d82c
+0, 4, 4, 1, 63000, ffcfaf42b69c7cd92f6e3c21987ff7df
+0, 5, 5, 1, 63000, e9667d3ee4d8179da44de4fbffcb7df2
+0, 6, 6, 1, 63000, 5e2c841bcf4ec6f3a05020d36986fe5b
+0, 7, 7, 1, 63000, 19fe287c30bd4c90b00a9631409568c0
+0, 8, 8, 1, 63000, 58a8843e50b19860a0a91e1e1bb63bfd
+0, 9, 9, 1, 63000, 0ebd31e18597a567f96645acbb2500cf
diff --git a/tests/ref/fate/vp9-03-size-200x224 b/tests/ref/fate/vp9-03-size-200x224
index 14f52f60b1..19a786cc71 100644
--- a/tests/ref/fate/vp9-03-size-200x224
+++ b/tests/ref/fate/vp9-03-size-200x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67200, 315d69847bf752a84231a368278eb0b6
-0, 33, 33, 0, 67200, d245738f8627fc345ab38a547bc7d352
-0, 66, 66, 0, 67200, 982681cdca448919c2eead94435772ad
-0, 100, 100, 0, 67200, 7b67b2d96476e17cd407bbccb19fd070
-0, 133, 133, 0, 67200, c38dde73ca097049d1fc689e18a49b5d
-0, 166, 166, 0, 67200, 525f323b81d780c669a03655bb0d0b56
-0, 200, 200, 0, 67200, 5dbeb96f65e383771c1c877ec559044a
-0, 233, 233, 0, 67200, 7d96e976265ef0f9faf173376caaa9e9
-0, 266, 266, 0, 67200, 6047c805a724701b80a133486aae0e65
-0, 300, 300, 0, 67200, eb8895dd994076a52aa3a0c1758ccbb7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67200, 315d69847bf752a84231a368278eb0b6
+0, 1, 1, 1, 67200, d245738f8627fc345ab38a547bc7d352
+0, 2, 2, 1, 67200, 982681cdca448919c2eead94435772ad
+0, 3, 3, 1, 67200, 7b67b2d96476e17cd407bbccb19fd070
+0, 4, 4, 1, 67200, c38dde73ca097049d1fc689e18a49b5d
+0, 5, 5, 1, 67200, 525f323b81d780c669a03655bb0d0b56
+0, 6, 6, 1, 67200, 5dbeb96f65e383771c1c877ec559044a
+0, 7, 7, 1, 67200, 7d96e976265ef0f9faf173376caaa9e9
+0, 8, 8, 1, 67200, 6047c805a724701b80a133486aae0e65
+0, 9, 9, 1, 67200, eb8895dd994076a52aa3a0c1758ccbb7
diff --git a/tests/ref/fate/vp9-03-size-200x226 b/tests/ref/fate/vp9-03-size-200x226
index 97e600c3b7..dd7967dc94 100644
--- a/tests/ref/fate/vp9-03-size-200x226
+++ b/tests/ref/fate/vp9-03-size-200x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67800, e45b6b9dce4a8509b7d26bc3cfdf7c86
-0, 33, 33, 0, 67800, ddb9d5033ecfa2d6e9a5505dce374bda
-0, 66, 66, 0, 67800, 52c495d3137143e0bce9382fe5506057
-0, 100, 100, 0, 67800, d09f3d6ad084f2966196acd48246f951
-0, 133, 133, 0, 67800, 1556d006d0119a3172b98a500b27f8d0
-0, 166, 166, 0, 67800, 904f86cfbcc3fa683d3d7744a286cd88
-0, 200, 200, 0, 67800, b35907456b8ccab0ae8efc8405b04c89
-0, 233, 233, 0, 67800, b7f2648fe0f873f7e9ea4a6d913e45ec
-0, 266, 266, 0, 67800, 2da76544bc7e295486c335e17047e12e
-0, 300, 300, 0, 67800, 10fd6424caf837d37564ef15f1c6f93d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67800, e45b6b9dce4a8509b7d26bc3cfdf7c86
+0, 1, 1, 1, 67800, ddb9d5033ecfa2d6e9a5505dce374bda
+0, 2, 2, 1, 67800, 52c495d3137143e0bce9382fe5506057
+0, 3, 3, 1, 67800, d09f3d6ad084f2966196acd48246f951
+0, 4, 4, 1, 67800, 1556d006d0119a3172b98a500b27f8d0
+0, 5, 5, 1, 67800, 904f86cfbcc3fa683d3d7744a286cd88
+0, 6, 6, 1, 67800, b35907456b8ccab0ae8efc8405b04c89
+0, 7, 7, 1, 67800, b7f2648fe0f873f7e9ea4a6d913e45ec
+0, 8, 8, 1, 67800, 2da76544bc7e295486c335e17047e12e
+0, 9, 9, 1, 67800, 10fd6424caf837d37564ef15f1c6f93d
diff --git a/tests/ref/fate/vp9-03-size-202x196 b/tests/ref/fate/vp9-03-size-202x196
index c224ef0c71..1af7c58b7c 100644
--- a/tests/ref/fate/vp9-03-size-202x196
+++ b/tests/ref/fate/vp9-03-size-202x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 59388, 1261466179df96099e598e46c50fa7c1
-0, 33, 33, 0, 59388, cc0fe373cd0399cf0c95edf92d9ab01f
-0, 66, 66, 0, 59388, 7a2dc0afd06ecfcf54321fb759f57601
-0, 100, 100, 0, 59388, db9c138503d27f87449f870ab07cab03
-0, 133, 133, 0, 59388, ddea2e5e2659e97132a537566d5ed989
-0, 166, 166, 0, 59388, c31e90b5eee032526c4e0603332fd160
-0, 200, 200, 0, 59388, 7e5b40f03b905d9ee749d3097a484ea0
-0, 233, 233, 0, 59388, 93e9f7defa94ff03c041448ae1e55cea
-0, 266, 266, 0, 59388, aef8e03f0146699faa16ec28dea49dbe
-0, 300, 300, 0, 59388, a651d949b4c8f0e455c6592dc98385f7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59388, 1261466179df96099e598e46c50fa7c1
+0, 1, 1, 1, 59388, cc0fe373cd0399cf0c95edf92d9ab01f
+0, 2, 2, 1, 59388, 7a2dc0afd06ecfcf54321fb759f57601
+0, 3, 3, 1, 59388, db9c138503d27f87449f870ab07cab03
+0, 4, 4, 1, 59388, ddea2e5e2659e97132a537566d5ed989
+0, 5, 5, 1, 59388, c31e90b5eee032526c4e0603332fd160
+0, 6, 6, 1, 59388, 7e5b40f03b905d9ee749d3097a484ea0
+0, 7, 7, 1, 59388, 93e9f7defa94ff03c041448ae1e55cea
+0, 8, 8, 1, 59388, aef8e03f0146699faa16ec28dea49dbe
+0, 9, 9, 1, 59388, a651d949b4c8f0e455c6592dc98385f7
diff --git a/tests/ref/fate/vp9-03-size-202x198 b/tests/ref/fate/vp9-03-size-202x198
index 96a3a1f497..d51ee967d9 100644
--- a/tests/ref/fate/vp9-03-size-202x198
+++ b/tests/ref/fate/vp9-03-size-202x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 59994, 181edc4ebeeff7f0527b93b84d5d8efb
-0, 33, 33, 0, 59994, 132c71b634fb67eed51fcdef1775b6b2
-0, 66, 66, 0, 59994, fd41144770765fc893adc5843ebe32e4
-0, 100, 100, 0, 59994, 77dcbaea101142940b6a78a271842829
-0, 133, 133, 0, 59994, 01737c38c1ac711a9744256788211177
-0, 166, 166, 0, 59994, 31cd0b5f621daac309c6f249f4c26cd8
-0, 200, 200, 0, 59994, e06d34e570dc46904fdb9eeb55811464
-0, 233, 233, 0, 59994, 71bf55030373bde1eaeb52d1e97bfa4a
-0, 266, 266, 0, 59994, e96063ff02e8a23a666222b59391de9c
-0, 300, 300, 0, 59994, 5aa0079168ab5069e8a3064f9e2a6d8b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 59994, 181edc4ebeeff7f0527b93b84d5d8efb
+0, 1, 1, 1, 59994, 132c71b634fb67eed51fcdef1775b6b2
+0, 2, 2, 1, 59994, fd41144770765fc893adc5843ebe32e4
+0, 3, 3, 1, 59994, 77dcbaea101142940b6a78a271842829
+0, 4, 4, 1, 59994, 01737c38c1ac711a9744256788211177
+0, 5, 5, 1, 59994, 31cd0b5f621daac309c6f249f4c26cd8
+0, 6, 6, 1, 59994, e06d34e570dc46904fdb9eeb55811464
+0, 7, 7, 1, 59994, 71bf55030373bde1eaeb52d1e97bfa4a
+0, 8, 8, 1, 59994, e96063ff02e8a23a666222b59391de9c
+0, 9, 9, 1, 59994, 5aa0079168ab5069e8a3064f9e2a6d8b
diff --git a/tests/ref/fate/vp9-03-size-202x200 b/tests/ref/fate/vp9-03-size-202x200
index a8d42a767b..f75e192200 100644
--- a/tests/ref/fate/vp9-03-size-202x200
+++ b/tests/ref/fate/vp9-03-size-202x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 60600, 20c41d4a1271183dbbc7a44e6b90ea80
-0, 33, 33, 0, 60600, bd8c1fba8d8742f4d98b7d5097c8c828
-0, 66, 66, 0, 60600, 55cbe06a925009c1b1f9b609b60b4c1d
-0, 100, 100, 0, 60600, 78e80c7cf1f142e2dda1bc269b5b3e00
-0, 133, 133, 0, 60600, 42ee8157a4c8af6670b81e9324b251e9
-0, 166, 166, 0, 60600, 022bdf5a2e1ea5f98503cd25b383ae53
-0, 200, 200, 0, 60600, c2073865386a991da01966878ce1ce6d
-0, 233, 233, 0, 60600, 6a5b95cd4eff0836b9180a25f663d36a
-0, 266, 266, 0, 60600, 5e5498c357340d4755dc98eb0669f103
-0, 300, 300, 0, 60600, 0907d5e4020111b1ecfe707df71bcd8a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 60600, 20c41d4a1271183dbbc7a44e6b90ea80
+0, 1, 1, 1, 60600, bd8c1fba8d8742f4d98b7d5097c8c828
+0, 2, 2, 1, 60600, 55cbe06a925009c1b1f9b609b60b4c1d
+0, 3, 3, 1, 60600, 78e80c7cf1f142e2dda1bc269b5b3e00
+0, 4, 4, 1, 60600, 42ee8157a4c8af6670b81e9324b251e9
+0, 5, 5, 1, 60600, 022bdf5a2e1ea5f98503cd25b383ae53
+0, 6, 6, 1, 60600, c2073865386a991da01966878ce1ce6d
+0, 7, 7, 1, 60600, 6a5b95cd4eff0836b9180a25f663d36a
+0, 8, 8, 1, 60600, 5e5498c357340d4755dc98eb0669f103
+0, 9, 9, 1, 60600, 0907d5e4020111b1ecfe707df71bcd8a
diff --git a/tests/ref/fate/vp9-03-size-202x202 b/tests/ref/fate/vp9-03-size-202x202
index 9867cc7cb5..af7cb9a6ac 100644
--- a/tests/ref/fate/vp9-03-size-202x202
+++ b/tests/ref/fate/vp9-03-size-202x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61206, 610cef52d35e9c641f2b8c10489c3d12
-0, 33, 33, 0, 61206, 1f84062e607d4798b0544739fe0da99c
-0, 66, 66, 0, 61206, ea379947b5c52ea3989dfc3f47c729d9
-0, 100, 100, 0, 61206, 1d06b72f06178cbb6bb5d188d22bff43
-0, 133, 133, 0, 61206, 25bd41bd7607f88a01aa0cdc336c9975
-0, 166, 166, 0, 61206, 86836a95a7a9fb1eefb20f7c5a15a9ab
-0, 200, 200, 0, 61206, d8eb3fecce1b646b9877cd4fcca9f9bf
-0, 233, 233, 0, 61206, a057e0b29e4ac9717452cc478c418c12
-0, 266, 266, 0, 61206, 9a3bab91b4f0fff174536b1609c9632c
-0, 300, 300, 0, 61206, d1cd93975f746b6cae490aae31f89e7e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61206, 610cef52d35e9c641f2b8c10489c3d12
+0, 1, 1, 1, 61206, 1f84062e607d4798b0544739fe0da99c
+0, 2, 2, 1, 61206, ea379947b5c52ea3989dfc3f47c729d9
+0, 3, 3, 1, 61206, 1d06b72f06178cbb6bb5d188d22bff43
+0, 4, 4, 1, 61206, 25bd41bd7607f88a01aa0cdc336c9975
+0, 5, 5, 1, 61206, 86836a95a7a9fb1eefb20f7c5a15a9ab
+0, 6, 6, 1, 61206, d8eb3fecce1b646b9877cd4fcca9f9bf
+0, 7, 7, 1, 61206, a057e0b29e4ac9717452cc478c418c12
+0, 8, 8, 1, 61206, 9a3bab91b4f0fff174536b1609c9632c
+0, 9, 9, 1, 61206, d1cd93975f746b6cae490aae31f89e7e
diff --git a/tests/ref/fate/vp9-03-size-202x208 b/tests/ref/fate/vp9-03-size-202x208
index a2a98f69c9..cc85d27053 100644
--- a/tests/ref/fate/vp9-03-size-202x208
+++ b/tests/ref/fate/vp9-03-size-202x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 63024, d2128e290be81bb0700ebe19e3faed4f
-0, 33, 33, 0, 63024, dccaecb7e4ddb7e4224221a659af2a43
-0, 66, 66, 0, 63024, be8e0966aaf3a9fe9164f63695dc3b62
-0, 100, 100, 0, 63024, da944fadc3a239c2254678cadb4cf7fa
-0, 133, 133, 0, 63024, 3c270f3c02fcbd192b7f896f3f9ee6d9
-0, 166, 166, 0, 63024, 0b3ccda0a87c37e40104ae2f1060e8e9
-0, 200, 200, 0, 63024, 254253aba91758f302e7177e614596be
-0, 233, 233, 0, 63024, b1501a4e372a5249e74aab77e57a28f1
-0, 266, 266, 0, 63024, c4497fea1cefed5cf2b2908620153d26
-0, 300, 300, 0, 63024, 5ba20dfa2400b15b5394f315c5c3707d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 63024, d2128e290be81bb0700ebe19e3faed4f
+0, 1, 1, 1, 63024, dccaecb7e4ddb7e4224221a659af2a43
+0, 2, 2, 1, 63024, be8e0966aaf3a9fe9164f63695dc3b62
+0, 3, 3, 1, 63024, da944fadc3a239c2254678cadb4cf7fa
+0, 4, 4, 1, 63024, 3c270f3c02fcbd192b7f896f3f9ee6d9
+0, 5, 5, 1, 63024, 0b3ccda0a87c37e40104ae2f1060e8e9
+0, 6, 6, 1, 63024, 254253aba91758f302e7177e614596be
+0, 7, 7, 1, 63024, b1501a4e372a5249e74aab77e57a28f1
+0, 8, 8, 1, 63024, c4497fea1cefed5cf2b2908620153d26
+0, 9, 9, 1, 63024, 5ba20dfa2400b15b5394f315c5c3707d
diff --git a/tests/ref/fate/vp9-03-size-202x210 b/tests/ref/fate/vp9-03-size-202x210
index b9fb7c2a3d..d51fcc616c 100644
--- a/tests/ref/fate/vp9-03-size-202x210
+++ b/tests/ref/fate/vp9-03-size-202x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 63630, e4663a28cabbfdd3815efda2d38debcc
-0, 33, 33, 0, 63630, 3cc7dbec64e9f697f40d740a72c09fc7
-0, 66, 66, 0, 63630, f108981e0ce9c6c501b9ac61d0f1ba44
-0, 100, 100, 0, 63630, 63191c7aceb8ac6b030cc1a4b3cda18c
-0, 133, 133, 0, 63630, b0a527ae3aafe94d13573199c6f4944f
-0, 166, 166, 0, 63630, 1be14b213ebf1d653468b8c16bae03fb
-0, 200, 200, 0, 63630, 44e5a8333a043cd93b9d1cc78e5f188f
-0, 233, 233, 0, 63630, bfd7619f990f20e23b47d0738a6a8449
-0, 266, 266, 0, 63630, 800405f45ca5198014ef8d8521b044fa
-0, 300, 300, 0, 63630, dca4eda872349708f54486433efc8225
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 63630, e4663a28cabbfdd3815efda2d38debcc
+0, 1, 1, 1, 63630, 3cc7dbec64e9f697f40d740a72c09fc7
+0, 2, 2, 1, 63630, f108981e0ce9c6c501b9ac61d0f1ba44
+0, 3, 3, 1, 63630, 63191c7aceb8ac6b030cc1a4b3cda18c
+0, 4, 4, 1, 63630, b0a527ae3aafe94d13573199c6f4944f
+0, 5, 5, 1, 63630, 1be14b213ebf1d653468b8c16bae03fb
+0, 6, 6, 1, 63630, 44e5a8333a043cd93b9d1cc78e5f188f
+0, 7, 7, 1, 63630, bfd7619f990f20e23b47d0738a6a8449
+0, 8, 8, 1, 63630, 800405f45ca5198014ef8d8521b044fa
+0, 9, 9, 1, 63630, dca4eda872349708f54486433efc8225
diff --git a/tests/ref/fate/vp9-03-size-202x224 b/tests/ref/fate/vp9-03-size-202x224
index 9a6b9da06b..0a36bd3372 100644
--- a/tests/ref/fate/vp9-03-size-202x224
+++ b/tests/ref/fate/vp9-03-size-202x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67872, 1d318f05310f6d40646f23c62c7eafe4
-0, 33, 33, 0, 67872, 42870bd73e1a0c5d84b986db3d24f0f0
-0, 66, 66, 0, 67872, afaac676150286143c6fec7992a81467
-0, 100, 100, 0, 67872, 128f84400c272628e802c2369b6bf548
-0, 133, 133, 0, 67872, 9adc24d69f12349d8b17c84f5c111767
-0, 166, 166, 0, 67872, b33d2f7a1955248652701f2ade8ab55d
-0, 200, 200, 0, 67872, b8acc23721097fce6c8835f5fcfaa6ee
-0, 233, 233, 0, 67872, b63bf9a08e4dc5879bbd91efaec95960
-0, 266, 266, 0, 67872, 96e8fe29935266f6bd486b99f917eabc
-0, 300, 300, 0, 67872, 54be14f8dde6857867cd4581f8557044
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67872, 1d318f05310f6d40646f23c62c7eafe4
+0, 1, 1, 1, 67872, 42870bd73e1a0c5d84b986db3d24f0f0
+0, 2, 2, 1, 67872, afaac676150286143c6fec7992a81467
+0, 3, 3, 1, 67872, 128f84400c272628e802c2369b6bf548
+0, 4, 4, 1, 67872, 9adc24d69f12349d8b17c84f5c111767
+0, 5, 5, 1, 67872, b33d2f7a1955248652701f2ade8ab55d
+0, 6, 6, 1, 67872, b8acc23721097fce6c8835f5fcfaa6ee
+0, 7, 7, 1, 67872, b63bf9a08e4dc5879bbd91efaec95960
+0, 8, 8, 1, 67872, 96e8fe29935266f6bd486b99f917eabc
+0, 9, 9, 1, 67872, 54be14f8dde6857867cd4581f8557044
diff --git a/tests/ref/fate/vp9-03-size-202x226 b/tests/ref/fate/vp9-03-size-202x226
index 38d2e605ed..6bc31f9be1 100644
--- a/tests/ref/fate/vp9-03-size-202x226
+++ b/tests/ref/fate/vp9-03-size-202x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 68478, 5aa0f439c58c6335cd86d4238a8c4b68
-0, 33, 33, 0, 68478, 3616cc306ec05f89d9b0db63200e4abf
-0, 66, 66, 0, 68478, 424e98f8ec0ebf2a326a917ee0159bbe
-0, 100, 100, 0, 68478, ed5710e412f056fa8c1a277d86dd45d7
-0, 133, 133, 0, 68478, 760b850feab485f0bda6cde9943102bc
-0, 166, 166, 0, 68478, f4bd90ca72aa707f9b68e6192ac230fd
-0, 200, 200, 0, 68478, 58e4aad0bc2a9f3fc279df10208bd6f6
-0, 233, 233, 0, 68478, b42f84723dd167d5c544d539275ad537
-0, 266, 266, 0, 68478, 5f54feca21331646e68797380260932a
-0, 300, 300, 0, 68478, 8e787dd318024aff25af8b4d85040f3c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 68478, 5aa0f439c58c6335cd86d4238a8c4b68
+0, 1, 1, 1, 68478, 3616cc306ec05f89d9b0db63200e4abf
+0, 2, 2, 1, 68478, 424e98f8ec0ebf2a326a917ee0159bbe
+0, 3, 3, 1, 68478, ed5710e412f056fa8c1a277d86dd45d7
+0, 4, 4, 1, 68478, 760b850feab485f0bda6cde9943102bc
+0, 5, 5, 1, 68478, f4bd90ca72aa707f9b68e6192ac230fd
+0, 6, 6, 1, 68478, 58e4aad0bc2a9f3fc279df10208bd6f6
+0, 7, 7, 1, 68478, b42f84723dd167d5c544d539275ad537
+0, 8, 8, 1, 68478, 5f54feca21331646e68797380260932a
+0, 9, 9, 1, 68478, 8e787dd318024aff25af8b4d85040f3c
diff --git a/tests/ref/fate/vp9-03-size-208x196 b/tests/ref/fate/vp9-03-size-208x196
index a541f14382..b06557f25c 100644
--- a/tests/ref/fate/vp9-03-size-208x196
+++ b/tests/ref/fate/vp9-03-size-208x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61152, 6195975181969789e101a83a555d13f7
-0, 33, 33, 0, 61152, 2aca5e3307d68a5e969564a943b8e723
-0, 66, 66, 0, 61152, aee4b00472ee0b6b7a13e31069181db4
-0, 100, 100, 0, 61152, 7808595b650a7c14d8a4800db7c014e0
-0, 133, 133, 0, 61152, 746eb763b176286aa875ae06b81118c4
-0, 166, 166, 0, 61152, 0e8a78ec061319e27d49ca25e333e017
-0, 200, 200, 0, 61152, ac4432db2bb0971d5f70a7dda1210c19
-0, 233, 233, 0, 61152, 78870f4bd767f8ab65d369a5b322735d
-0, 266, 266, 0, 61152, eee9ddd91209348a64259db6a4a3f80c
-0, 300, 300, 0, 61152, c48d21e36a9c0d0d1c64db3f776b3002
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61152, 6195975181969789e101a83a555d13f7
+0, 1, 1, 1, 61152, 2aca5e3307d68a5e969564a943b8e723
+0, 2, 2, 1, 61152, aee4b00472ee0b6b7a13e31069181db4
+0, 3, 3, 1, 61152, 7808595b650a7c14d8a4800db7c014e0
+0, 4, 4, 1, 61152, 746eb763b176286aa875ae06b81118c4
+0, 5, 5, 1, 61152, 0e8a78ec061319e27d49ca25e333e017
+0, 6, 6, 1, 61152, ac4432db2bb0971d5f70a7dda1210c19
+0, 7, 7, 1, 61152, 78870f4bd767f8ab65d369a5b322735d
+0, 8, 8, 1, 61152, eee9ddd91209348a64259db6a4a3f80c
+0, 9, 9, 1, 61152, c48d21e36a9c0d0d1c64db3f776b3002
diff --git a/tests/ref/fate/vp9-03-size-208x198 b/tests/ref/fate/vp9-03-size-208x198
index 223668723f..84da7dda6c 100644
--- a/tests/ref/fate/vp9-03-size-208x198
+++ b/tests/ref/fate/vp9-03-size-208x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61776, 1f1fa3cdf865d8c75183f4ba6203b675
-0, 33, 33, 0, 61776, ead33ead8fea5bd5d831a79f4c75a590
-0, 66, 66, 0, 61776, 9a406b4464989fd4bb7cbcb1b18aeaa7
-0, 100, 100, 0, 61776, fab3d228e7032f2cdc440dbfcb17c4c1
-0, 133, 133, 0, 61776, f2f3f8b8d9ece21c359c89245157c613
-0, 166, 166, 0, 61776, 321f5a8ecb2cec1780013fe72c237bde
-0, 200, 200, 0, 61776, 6f025b1f4ef61d261f05ca149a9470e6
-0, 233, 233, 0, 61776, 85abcc8d8e6b5f286ed6aa6c588cf416
-0, 266, 266, 0, 61776, b28d710dd44389f774aa02edd6327d5c
-0, 300, 300, 0, 61776, 79374bef9819eecafa7396d70c80be7f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61776, 1f1fa3cdf865d8c75183f4ba6203b675
+0, 1, 1, 1, 61776, ead33ead8fea5bd5d831a79f4c75a590
+0, 2, 2, 1, 61776, 9a406b4464989fd4bb7cbcb1b18aeaa7
+0, 3, 3, 1, 61776, fab3d228e7032f2cdc440dbfcb17c4c1
+0, 4, 4, 1, 61776, f2f3f8b8d9ece21c359c89245157c613
+0, 5, 5, 1, 61776, 321f5a8ecb2cec1780013fe72c237bde
+0, 6, 6, 1, 61776, 6f025b1f4ef61d261f05ca149a9470e6
+0, 7, 7, 1, 61776, 85abcc8d8e6b5f286ed6aa6c588cf416
+0, 8, 8, 1, 61776, b28d710dd44389f774aa02edd6327d5c
+0, 9, 9, 1, 61776, 79374bef9819eecafa7396d70c80be7f
diff --git a/tests/ref/fate/vp9-03-size-208x200 b/tests/ref/fate/vp9-03-size-208x200
index 5f924a3dcf..0943abf6f4 100644
--- a/tests/ref/fate/vp9-03-size-208x200
+++ b/tests/ref/fate/vp9-03-size-208x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 62400, ff2dda3ddbe8b461d960baba0ad132bf
-0, 33, 33, 0, 62400, d6935ac8f2250316f498e8f01afa04fd
-0, 66, 66, 0, 62400, 57173ebaef7b21698c62fa959cb40ead
-0, 100, 100, 0, 62400, f354c76d7cf45e9f3adfdde0f6b3b5c9
-0, 133, 133, 0, 62400, fbc968ecd214b01509a76996e45dd09a
-0, 166, 166, 0, 62400, 9c314b51a80f2a081adf9b9cc26f5f8a
-0, 200, 200, 0, 62400, f22883a6a5b74ffa4bb16f22d496b5a5
-0, 233, 233, 0, 62400, eb4fa914fc5658d43e32c48a0c39bab3
-0, 266, 266, 0, 62400, d763c0c2f44b68e1e3fe9e165334eb0b
-0, 300, 300, 0, 62400, 344e1075a48cd61e79b0550809b4c91f
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 62400, ff2dda3ddbe8b461d960baba0ad132bf
+0, 1, 1, 1, 62400, d6935ac8f2250316f498e8f01afa04fd
+0, 2, 2, 1, 62400, 57173ebaef7b21698c62fa959cb40ead
+0, 3, 3, 1, 62400, f354c76d7cf45e9f3adfdde0f6b3b5c9
+0, 4, 4, 1, 62400, fbc968ecd214b01509a76996e45dd09a
+0, 5, 5, 1, 62400, 9c314b51a80f2a081adf9b9cc26f5f8a
+0, 6, 6, 1, 62400, f22883a6a5b74ffa4bb16f22d496b5a5
+0, 7, 7, 1, 62400, eb4fa914fc5658d43e32c48a0c39bab3
+0, 8, 8, 1, 62400, d763c0c2f44b68e1e3fe9e165334eb0b
+0, 9, 9, 1, 62400, 344e1075a48cd61e79b0550809b4c91f
diff --git a/tests/ref/fate/vp9-03-size-208x202 b/tests/ref/fate/vp9-03-size-208x202
index b5373d5cf0..b181224938 100644
--- a/tests/ref/fate/vp9-03-size-208x202
+++ b/tests/ref/fate/vp9-03-size-208x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 63024, e5164f87feadf4b65257f578affc3e04
-0, 33, 33, 0, 63024, 6aee5a3b6c3a096dfc1594762b2b248f
-0, 66, 66, 0, 63024, cb1c9dce6fdf7372e0eb2397251f0ade
-0, 100, 100, 0, 63024, 4fe5f24c08690c966b6a14ac3422510b
-0, 133, 133, 0, 63024, b22a273814523251b365f3278d8a3a9c
-0, 166, 166, 0, 63024, 190d9dff373023a25427fc859545ea24
-0, 200, 200, 0, 63024, a6307f38718ed686cb195e3833ab27ab
-0, 233, 233, 0, 63024, 79630bec5a91d69aca42a910413c2800
-0, 266, 266, 0, 63024, 2231cec9c03714b8671e5e1456b148c9
-0, 300, 300, 0, 63024, 278458f6734a24f2eb9bc877a6e9d7df
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 63024, e5164f87feadf4b65257f578affc3e04
+0, 1, 1, 1, 63024, 6aee5a3b6c3a096dfc1594762b2b248f
+0, 2, 2, 1, 63024, cb1c9dce6fdf7372e0eb2397251f0ade
+0, 3, 3, 1, 63024, 4fe5f24c08690c966b6a14ac3422510b
+0, 4, 4, 1, 63024, b22a273814523251b365f3278d8a3a9c
+0, 5, 5, 1, 63024, 190d9dff373023a25427fc859545ea24
+0, 6, 6, 1, 63024, a6307f38718ed686cb195e3833ab27ab
+0, 7, 7, 1, 63024, 79630bec5a91d69aca42a910413c2800
+0, 8, 8, 1, 63024, 2231cec9c03714b8671e5e1456b148c9
+0, 9, 9, 1, 63024, 278458f6734a24f2eb9bc877a6e9d7df
diff --git a/tests/ref/fate/vp9-03-size-208x208 b/tests/ref/fate/vp9-03-size-208x208
index aa5bc3c961..7bcbfdc390 100644
--- a/tests/ref/fate/vp9-03-size-208x208
+++ b/tests/ref/fate/vp9-03-size-208x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 64896, 6bff7c1f4c5ef8412ebf669852c70de6
-0, 33, 33, 0, 64896, fdfd7a2308de9509a41fed2880a8f0f5
-0, 66, 66, 0, 64896, d8b464811e9c3b8a6db9cc277ac88c59
-0, 100, 100, 0, 64896, b8fa29e79be3126dd74310d6dd09c747
-0, 133, 133, 0, 64896, dad29803fed686887a0873eb78a469c6
-0, 166, 166, 0, 64896, 684de29bbf800f52aea4af9850bcc5b3
-0, 200, 200, 0, 64896, 06862dbce7571b4487766b179a596e1d
-0, 233, 233, 0, 64896, 99582a966bc7070112e214ce7912e485
-0, 266, 266, 0, 64896, a61158581a5719cb0cf13fb3301cb8c4
-0, 300, 300, 0, 64896, 9c2295332f34fee3a249262c8ba843bc
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 64896, 6bff7c1f4c5ef8412ebf669852c70de6
+0, 1, 1, 1, 64896, fdfd7a2308de9509a41fed2880a8f0f5
+0, 2, 2, 1, 64896, d8b464811e9c3b8a6db9cc277ac88c59
+0, 3, 3, 1, 64896, b8fa29e79be3126dd74310d6dd09c747
+0, 4, 4, 1, 64896, dad29803fed686887a0873eb78a469c6
+0, 5, 5, 1, 64896, 684de29bbf800f52aea4af9850bcc5b3
+0, 6, 6, 1, 64896, 06862dbce7571b4487766b179a596e1d
+0, 7, 7, 1, 64896, 99582a966bc7070112e214ce7912e485
+0, 8, 8, 1, 64896, a61158581a5719cb0cf13fb3301cb8c4
+0, 9, 9, 1, 64896, 9c2295332f34fee3a249262c8ba843bc
diff --git a/tests/ref/fate/vp9-03-size-208x210 b/tests/ref/fate/vp9-03-size-208x210
index 0477efa13c..7dbccf69fc 100644
--- a/tests/ref/fate/vp9-03-size-208x210
+++ b/tests/ref/fate/vp9-03-size-208x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 65520, b15c7e98ddd137237b062cb51667522f
-0, 33, 33, 0, 65520, 00c594c68b19ef39a79a38e86853dc64
-0, 66, 66, 0, 65520, e6742abe3d2c178af4298e121391c299
-0, 100, 100, 0, 65520, efe5387b38c32f1c25c0fc9836921074
-0, 133, 133, 0, 65520, e0e696f4c18af09a74e052903db1468c
-0, 166, 166, 0, 65520, f1960270c6704ca47caed63161716025
-0, 200, 200, 0, 65520, a1542d7749cfa447481acd7835db838a
-0, 233, 233, 0, 65520, a91fb10a17d1d056667860cc43c81dae
-0, 266, 266, 0, 65520, b673bfbb722522b4e7b5e9c5b85cc31f
-0, 300, 300, 0, 65520, 8b4bb57d3cf609cbf9564a96a6ca6ade
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 65520, b15c7e98ddd137237b062cb51667522f
+0, 1, 1, 1, 65520, 00c594c68b19ef39a79a38e86853dc64
+0, 2, 2, 1, 65520, e6742abe3d2c178af4298e121391c299
+0, 3, 3, 1, 65520, efe5387b38c32f1c25c0fc9836921074
+0, 4, 4, 1, 65520, e0e696f4c18af09a74e052903db1468c
+0, 5, 5, 1, 65520, f1960270c6704ca47caed63161716025
+0, 6, 6, 1, 65520, a1542d7749cfa447481acd7835db838a
+0, 7, 7, 1, 65520, a91fb10a17d1d056667860cc43c81dae
+0, 8, 8, 1, 65520, b673bfbb722522b4e7b5e9c5b85cc31f
+0, 9, 9, 1, 65520, 8b4bb57d3cf609cbf9564a96a6ca6ade
diff --git a/tests/ref/fate/vp9-03-size-208x224 b/tests/ref/fate/vp9-03-size-208x224
index 18ed456564..70d64ea0d7 100644
--- a/tests/ref/fate/vp9-03-size-208x224
+++ b/tests/ref/fate/vp9-03-size-208x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 69888, 479d07bb96905ad7d5f0ec3ee12b41ba
-0, 33, 33, 0, 69888, 4b6555aaed8e5a45879773f1bf87962e
-0, 66, 66, 0, 69888, c5f42cb796dd7b6622957016ca6b502f
-0, 100, 100, 0, 69888, f06c954483560866fbff10bae7ba0785
-0, 133, 133, 0, 69888, af83aff39999852310395fe241ccb49b
-0, 166, 166, 0, 69888, 108377d6f30ceba6f2377330af2da38f
-0, 200, 200, 0, 69888, e81e6e0b37a7b92368ede9cab124567c
-0, 233, 233, 0, 69888, 59dbe51caaed8e6e825c78c5901fb22c
-0, 266, 266, 0, 69888, 24686123ea14c8d1a9b447733df0aaab
-0, 300, 300, 0, 69888, ce2035c49237c8076f8dac0d3f61848e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 69888, 479d07bb96905ad7d5f0ec3ee12b41ba
+0, 1, 1, 1, 69888, 4b6555aaed8e5a45879773f1bf87962e
+0, 2, 2, 1, 69888, c5f42cb796dd7b6622957016ca6b502f
+0, 3, 3, 1, 69888, f06c954483560866fbff10bae7ba0785
+0, 4, 4, 1, 69888, af83aff39999852310395fe241ccb49b
+0, 5, 5, 1, 69888, 108377d6f30ceba6f2377330af2da38f
+0, 6, 6, 1, 69888, e81e6e0b37a7b92368ede9cab124567c
+0, 7, 7, 1, 69888, 59dbe51caaed8e6e825c78c5901fb22c
+0, 8, 8, 1, 69888, 24686123ea14c8d1a9b447733df0aaab
+0, 9, 9, 1, 69888, ce2035c49237c8076f8dac0d3f61848e
diff --git a/tests/ref/fate/vp9-03-size-208x226 b/tests/ref/fate/vp9-03-size-208x226
index a7a19813ae..7d9020cbe4 100644
--- a/tests/ref/fate/vp9-03-size-208x226
+++ b/tests/ref/fate/vp9-03-size-208x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 70512, 33aa4af6153570518c59960a0c959053
-0, 33, 33, 0, 70512, 024fa27dee80ad199528052aaa8d42c7
-0, 66, 66, 0, 70512, b949ef118c7e7e62a8b88e2308219ef9
-0, 100, 100, 0, 70512, 3061ee13696ced5e10a646fdd5ca6c34
-0, 133, 133, 0, 70512, c4984bd53dcb7b9e2570f2965d077b2f
-0, 166, 166, 0, 70512, d564c35c5caadcfd9f80377fa414af72
-0, 200, 200, 0, 70512, 9b7d7b10ee2f3eb7a9ffddcebff45b97
-0, 233, 233, 0, 70512, a0ede7085b04cbb3519d56b2e4347d14
-0, 266, 266, 0, 70512, 63d7af745f9e6a34b618db28fe878ffd
-0, 300, 300, 0, 70512, 85077809087e7bdfb9215bfcd1f1bbc0
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 70512, 33aa4af6153570518c59960a0c959053
+0, 1, 1, 1, 70512, 024fa27dee80ad199528052aaa8d42c7
+0, 2, 2, 1, 70512, b949ef118c7e7e62a8b88e2308219ef9
+0, 3, 3, 1, 70512, 3061ee13696ced5e10a646fdd5ca6c34
+0, 4, 4, 1, 70512, c4984bd53dcb7b9e2570f2965d077b2f
+0, 5, 5, 1, 70512, d564c35c5caadcfd9f80377fa414af72
+0, 6, 6, 1, 70512, 9b7d7b10ee2f3eb7a9ffddcebff45b97
+0, 7, 7, 1, 70512, a0ede7085b04cbb3519d56b2e4347d14
+0, 8, 8, 1, 70512, 63d7af745f9e6a34b618db28fe878ffd
+0, 9, 9, 1, 70512, 85077809087e7bdfb9215bfcd1f1bbc0
diff --git a/tests/ref/fate/vp9-03-size-210x196 b/tests/ref/fate/vp9-03-size-210x196
index 0db3b0021f..a6813b48a1 100644
--- a/tests/ref/fate/vp9-03-size-210x196
+++ b/tests/ref/fate/vp9-03-size-210x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 61740, 5c69f80da667bfd20394995e93e4cd2b
-0, 33, 33, 0, 61740, 13363cd8e52ca8c1053db1c84c111bc9
-0, 66, 66, 0, 61740, 108976afdf99f59276d6f89879e3bdc3
-0, 100, 100, 0, 61740, 770ce25985e6b479d52a9185876cfe83
-0, 133, 133, 0, 61740, eba7cbb3c91989aa4c13487ed01675b5
-0, 166, 166, 0, 61740, f391c30a47c33a250dd20cb12f0a6e01
-0, 200, 200, 0, 61740, c38e12de302177d19dd744a3ea227e90
-0, 233, 233, 0, 61740, 8c9370439a0b7289919c6ee68e00570f
-0, 266, 266, 0, 61740, ac3748c4b99c4f1aba7430ae12c19cfd
-0, 300, 300, 0, 61740, e5228dc84f7933ccc9306907d737ad3c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 61740, 5c69f80da667bfd20394995e93e4cd2b
+0, 1, 1, 1, 61740, 13363cd8e52ca8c1053db1c84c111bc9
+0, 2, 2, 1, 61740, 108976afdf99f59276d6f89879e3bdc3
+0, 3, 3, 1, 61740, 770ce25985e6b479d52a9185876cfe83
+0, 4, 4, 1, 61740, eba7cbb3c91989aa4c13487ed01675b5
+0, 5, 5, 1, 61740, f391c30a47c33a250dd20cb12f0a6e01
+0, 6, 6, 1, 61740, c38e12de302177d19dd744a3ea227e90
+0, 7, 7, 1, 61740, 8c9370439a0b7289919c6ee68e00570f
+0, 8, 8, 1, 61740, ac3748c4b99c4f1aba7430ae12c19cfd
+0, 9, 9, 1, 61740, e5228dc84f7933ccc9306907d737ad3c
diff --git a/tests/ref/fate/vp9-03-size-210x198 b/tests/ref/fate/vp9-03-size-210x198
index 3949dbd9a0..c14d20cf99 100644
--- a/tests/ref/fate/vp9-03-size-210x198
+++ b/tests/ref/fate/vp9-03-size-210x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 62370, d83ee2413e701ae405a2b74863d4c5a9
-0, 33, 33, 0, 62370, f2ebc0f7dc171e0e5d2911c7ee2df5e1
-0, 66, 66, 0, 62370, e189ef4d8add227352a0d6ee62748ee7
-0, 100, 100, 0, 62370, 6dcb1dca1a0e2ba85034aba9f021427e
-0, 133, 133, 0, 62370, e98c633ba8912f6d65374055ec9af543
-0, 166, 166, 0, 62370, 82111cb7d5addce16d9bcba9e0a99503
-0, 200, 200, 0, 62370, bbbc73002f794ab0261fe384b2524226
-0, 233, 233, 0, 62370, 0bcdc427df47123959f7de9c44fe291e
-0, 266, 266, 0, 62370, 505776b3d82e38612393d60b6aa55c1d
-0, 300, 300, 0, 62370, feb93758242b847f3d53bb4c97b0ad9c
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 62370, d83ee2413e701ae405a2b74863d4c5a9
+0, 1, 1, 1, 62370, f2ebc0f7dc171e0e5d2911c7ee2df5e1
+0, 2, 2, 1, 62370, e189ef4d8add227352a0d6ee62748ee7
+0, 3, 3, 1, 62370, 6dcb1dca1a0e2ba85034aba9f021427e
+0, 4, 4, 1, 62370, e98c633ba8912f6d65374055ec9af543
+0, 5, 5, 1, 62370, 82111cb7d5addce16d9bcba9e0a99503
+0, 6, 6, 1, 62370, bbbc73002f794ab0261fe384b2524226
+0, 7, 7, 1, 62370, 0bcdc427df47123959f7de9c44fe291e
+0, 8, 8, 1, 62370, 505776b3d82e38612393d60b6aa55c1d
+0, 9, 9, 1, 62370, feb93758242b847f3d53bb4c97b0ad9c
diff --git a/tests/ref/fate/vp9-03-size-210x200 b/tests/ref/fate/vp9-03-size-210x200
index 9c4245c0a1..873525b4be 100644
--- a/tests/ref/fate/vp9-03-size-210x200
+++ b/tests/ref/fate/vp9-03-size-210x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 63000, 2465560246c1ee24d937cb9cbc1422f1
-0, 33, 33, 0, 63000, 8926b628dcdf2182516822c7d0d778ec
-0, 66, 66, 0, 63000, 9bd14d3ebc7fe81c4223116de1b9c2ec
-0, 100, 100, 0, 63000, 2d029d8461c20236066c0786950540fb
-0, 133, 133, 0, 63000, 39412b6e62de43bd40c58d4e2e38daf8
-0, 166, 166, 0, 63000, 3ea211c24f606b29582147bf872994dd
-0, 200, 200, 0, 63000, 261c37f88bf7f40549642578d9464aeb
-0, 233, 233, 0, 63000, 98551d44de1e23165e05975babb72446
-0, 266, 266, 0, 63000, 1d85ad052dd27e7e6bfea5d2babf5176
-0, 300, 300, 0, 63000, ad18b6a3698a3674c2488f927810eb0d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 63000, 2465560246c1ee24d937cb9cbc1422f1
+0, 1, 1, 1, 63000, 8926b628dcdf2182516822c7d0d778ec
+0, 2, 2, 1, 63000, 9bd14d3ebc7fe81c4223116de1b9c2ec
+0, 3, 3, 1, 63000, 2d029d8461c20236066c0786950540fb
+0, 4, 4, 1, 63000, 39412b6e62de43bd40c58d4e2e38daf8
+0, 5, 5, 1, 63000, 3ea211c24f606b29582147bf872994dd
+0, 6, 6, 1, 63000, 261c37f88bf7f40549642578d9464aeb
+0, 7, 7, 1, 63000, 98551d44de1e23165e05975babb72446
+0, 8, 8, 1, 63000, 1d85ad052dd27e7e6bfea5d2babf5176
+0, 9, 9, 1, 63000, ad18b6a3698a3674c2488f927810eb0d
diff --git a/tests/ref/fate/vp9-03-size-210x202 b/tests/ref/fate/vp9-03-size-210x202
index 253bb1dfbe..91e229e233 100644
--- a/tests/ref/fate/vp9-03-size-210x202
+++ b/tests/ref/fate/vp9-03-size-210x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 63630, 5d01848aee2b324f2e356627f9c39532
-0, 33, 33, 0, 63630, b671fe34bc0e5a682baff929d26ea627
-0, 66, 66, 0, 63630, e9a40f87ca5aaa5af9772e286feb9063
-0, 100, 100, 0, 63630, 4730f60d4c856e8ad877c0d8b1729ec4
-0, 133, 133, 0, 63630, 317fc01349e0984c23d15f97a3a0f442
-0, 166, 166, 0, 63630, aea89116ffe48340d1752d1ad5195529
-0, 200, 200, 0, 63630, 14694ba65b6308e5f5571486b62ca1cc
-0, 233, 233, 0, 63630, 53c6102d877c9a30eaa20ddc45207ea0
-0, 266, 266, 0, 63630, 7d1e898b1bead878224e8ff15d624bd9
-0, 300, 300, 0, 63630, 37b684bfae5dbd33e8dbb8332b94ce8a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 63630, 5d01848aee2b324f2e356627f9c39532
+0, 1, 1, 1, 63630, b671fe34bc0e5a682baff929d26ea627
+0, 2, 2, 1, 63630, e9a40f87ca5aaa5af9772e286feb9063
+0, 3, 3, 1, 63630, 4730f60d4c856e8ad877c0d8b1729ec4
+0, 4, 4, 1, 63630, 317fc01349e0984c23d15f97a3a0f442
+0, 5, 5, 1, 63630, aea89116ffe48340d1752d1ad5195529
+0, 6, 6, 1, 63630, 14694ba65b6308e5f5571486b62ca1cc
+0, 7, 7, 1, 63630, 53c6102d877c9a30eaa20ddc45207ea0
+0, 8, 8, 1, 63630, 7d1e898b1bead878224e8ff15d624bd9
+0, 9, 9, 1, 63630, 37b684bfae5dbd33e8dbb8332b94ce8a
diff --git a/tests/ref/fate/vp9-03-size-210x208 b/tests/ref/fate/vp9-03-size-210x208
index 39752a9a71..a77ac5f33b 100644
--- a/tests/ref/fate/vp9-03-size-210x208
+++ b/tests/ref/fate/vp9-03-size-210x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 65520, 1156d318c00d299cf5bdc7e485966dab
-0, 33, 33, 0, 65520, a8094f8f1e7e04e54251bee8c4c800ce
-0, 66, 66, 0, 65520, e2a07d99ffe1cfe6b9fce36e93677fe1
-0, 100, 100, 0, 65520, 63d179b00816dbad75b778d2c23955c6
-0, 133, 133, 0, 65520, 407de5fb2dfdd52e6173905b09ff22f2
-0, 166, 166, 0, 65520, 36900199c56310e651723de4e3ad2f2c
-0, 200, 200, 0, 65520, 908db56e975b5db07af17fdc51b12be8
-0, 233, 233, 0, 65520, 400e32490b1262009a481cc331a00e44
-0, 266, 266, 0, 65520, dc43b786cba033cc92b9921d12f7b3d7
-0, 300, 300, 0, 65520, e8c94c5965c729f5d1ef3ba4509c97c8
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 65520, 1156d318c00d299cf5bdc7e485966dab
+0, 1, 1, 1, 65520, a8094f8f1e7e04e54251bee8c4c800ce
+0, 2, 2, 1, 65520, e2a07d99ffe1cfe6b9fce36e93677fe1
+0, 3, 3, 1, 65520, 63d179b00816dbad75b778d2c23955c6
+0, 4, 4, 1, 65520, 407de5fb2dfdd52e6173905b09ff22f2
+0, 5, 5, 1, 65520, 36900199c56310e651723de4e3ad2f2c
+0, 6, 6, 1, 65520, 908db56e975b5db07af17fdc51b12be8
+0, 7, 7, 1, 65520, 400e32490b1262009a481cc331a00e44
+0, 8, 8, 1, 65520, dc43b786cba033cc92b9921d12f7b3d7
+0, 9, 9, 1, 65520, e8c94c5965c729f5d1ef3ba4509c97c8
diff --git a/tests/ref/fate/vp9-03-size-210x210 b/tests/ref/fate/vp9-03-size-210x210
index efbc81c233..fa9f1580c3 100644
--- a/tests/ref/fate/vp9-03-size-210x210
+++ b/tests/ref/fate/vp9-03-size-210x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 66150, b65725c68978bdaaafdf735dfbafa9e3
-0, 33, 33, 0, 66150, 35be2f16bd5dedc9d3f7a016f0d71701
-0, 66, 66, 0, 66150, 8c2873a97b51510d7449869e24a348f5
-0, 100, 100, 0, 66150, 724a30e8ae539e797db8889dc08aec5e
-0, 133, 133, 0, 66150, e3ae1246a63ea22afd026bfb859fe165
-0, 166, 166, 0, 66150, 7e1fa363cf3f44c7a3019f29c14a6da4
-0, 200, 200, 0, 66150, c6f26619ab5687a2a698c8766b79f2eb
-0, 233, 233, 0, 66150, be5b8c50a772afe95d72bf3cc7c4fd2f
-0, 266, 266, 0, 66150, 9eab1417ac249ce31c79750143d52084
-0, 300, 300, 0, 66150, 9d2455048dbc3cdc2343a818c5a2bcb1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 66150, b65725c68978bdaaafdf735dfbafa9e3
+0, 1, 1, 1, 66150, 35be2f16bd5dedc9d3f7a016f0d71701
+0, 2, 2, 1, 66150, 8c2873a97b51510d7449869e24a348f5
+0, 3, 3, 1, 66150, 724a30e8ae539e797db8889dc08aec5e
+0, 4, 4, 1, 66150, e3ae1246a63ea22afd026bfb859fe165
+0, 5, 5, 1, 66150, 7e1fa363cf3f44c7a3019f29c14a6da4
+0, 6, 6, 1, 66150, c6f26619ab5687a2a698c8766b79f2eb
+0, 7, 7, 1, 66150, be5b8c50a772afe95d72bf3cc7c4fd2f
+0, 8, 8, 1, 66150, 9eab1417ac249ce31c79750143d52084
+0, 9, 9, 1, 66150, 9d2455048dbc3cdc2343a818c5a2bcb1
diff --git a/tests/ref/fate/vp9-03-size-210x224 b/tests/ref/fate/vp9-03-size-210x224
index cfa37581a8..1e1d22554b 100644
--- a/tests/ref/fate/vp9-03-size-210x224
+++ b/tests/ref/fate/vp9-03-size-210x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 70560, bb903b926c4b34ae336e21d65ad8fd25
-0, 33, 33, 0, 70560, c4c0bc3b112487e994d22176817ace3c
-0, 66, 66, 0, 70560, 24e699f7a92ab1b0fe12e0b747470b5b
-0, 100, 100, 0, 70560, 200f403694d3acfda63f52e8373f1420
-0, 133, 133, 0, 70560, 6df417a8ec1810562301c89724b739d1
-0, 166, 166, 0, 70560, 55757b633d8fe669fc0f507dab4fa9f7
-0, 200, 200, 0, 70560, 45bc82bee02cb45422be3ac1019896d0
-0, 233, 233, 0, 70560, 4aaf5d07d2796910767d5084556c9cf9
-0, 266, 266, 0, 70560, f100fa26da47250b98d95a18915f521d
-0, 300, 300, 0, 70560, f5a8def53b4638b6ce7c8588d595d0ad
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 70560, bb903b926c4b34ae336e21d65ad8fd25
+0, 1, 1, 1, 70560, c4c0bc3b112487e994d22176817ace3c
+0, 2, 2, 1, 70560, 24e699f7a92ab1b0fe12e0b747470b5b
+0, 3, 3, 1, 70560, 200f403694d3acfda63f52e8373f1420
+0, 4, 4, 1, 70560, 6df417a8ec1810562301c89724b739d1
+0, 5, 5, 1, 70560, 55757b633d8fe669fc0f507dab4fa9f7
+0, 6, 6, 1, 70560, 45bc82bee02cb45422be3ac1019896d0
+0, 7, 7, 1, 70560, 4aaf5d07d2796910767d5084556c9cf9
+0, 8, 8, 1, 70560, f100fa26da47250b98d95a18915f521d
+0, 9, 9, 1, 70560, f5a8def53b4638b6ce7c8588d595d0ad
diff --git a/tests/ref/fate/vp9-03-size-210x226 b/tests/ref/fate/vp9-03-size-210x226
index 046f7335bb..5563363e89 100644
--- a/tests/ref/fate/vp9-03-size-210x226
+++ b/tests/ref/fate/vp9-03-size-210x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 71190, 03707b2f5c392933f7336f380423a0a1
-0, 33, 33, 0, 71190, b388553c79573555a3b660f5e36d4e36
-0, 66, 66, 0, 71190, a1a7fd8ba7fb0fe7733cdf5440c7c1f3
-0, 100, 100, 0, 71190, 9daff7ef71dd54951f0b75a902065259
-0, 133, 133, 0, 71190, 60218a4b8bc0a5b0b40fa560a40fb4c0
-0, 166, 166, 0, 71190, 21229bfed833468fafc27ce93db1450c
-0, 200, 200, 0, 71190, 7aa290c6e503315d7aa3517258d5f63a
-0, 233, 233, 0, 71190, 63fd08ae2e859ff3d874ab2c2ce41a42
-0, 266, 266, 0, 71190, 725b371247fae28ef4b912368738df64
-0, 300, 300, 0, 71190, 7cf2d8d9e464307311b499ff0c3ea05e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 71190, 03707b2f5c392933f7336f380423a0a1
+0, 1, 1, 1, 71190, b388553c79573555a3b660f5e36d4e36
+0, 2, 2, 1, 71190, a1a7fd8ba7fb0fe7733cdf5440c7c1f3
+0, 3, 3, 1, 71190, 9daff7ef71dd54951f0b75a902065259
+0, 4, 4, 1, 71190, 60218a4b8bc0a5b0b40fa560a40fb4c0
+0, 5, 5, 1, 71190, 21229bfed833468fafc27ce93db1450c
+0, 6, 6, 1, 71190, 7aa290c6e503315d7aa3517258d5f63a
+0, 7, 7, 1, 71190, 63fd08ae2e859ff3d874ab2c2ce41a42
+0, 8, 8, 1, 71190, 725b371247fae28ef4b912368738df64
+0, 9, 9, 1, 71190, 7cf2d8d9e464307311b499ff0c3ea05e
diff --git a/tests/ref/fate/vp9-03-size-224x196 b/tests/ref/fate/vp9-03-size-224x196
index b94c04d311..1275e9e3e6 100644
--- a/tests/ref/fate/vp9-03-size-224x196
+++ b/tests/ref/fate/vp9-03-size-224x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 65856, 3ffc096f1b42b4d319d4a9efbefc7625
-0, 33, 33, 0, 65856, 78b3655d5cad30fa6b2c2d8fd29463de
-0, 66, 66, 0, 65856, ab197553d9599b2a03aff62d1d694848
-0, 100, 100, 0, 65856, be368d1f3d3fcc710565b5433940f0df
-0, 133, 133, 0, 65856, 374c5db60ea9c110b871bb45be0efff1
-0, 166, 166, 0, 65856, ec50085400d626de5833bc0a94d9941f
-0, 200, 200, 0, 65856, d4ae69937e2a8d9bf2023d4215749635
-0, 233, 233, 0, 65856, 9b0b81eb6d62b8014e0639932fe35bc0
-0, 266, 266, 0, 65856, cd02d0cc268e6b6df0b2dbd3f3b137e6
-0, 300, 300, 0, 65856, 5322ba1085c114f93534e1761a0d8aa1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 65856, 3ffc096f1b42b4d319d4a9efbefc7625
+0, 1, 1, 1, 65856, 78b3655d5cad30fa6b2c2d8fd29463de
+0, 2, 2, 1, 65856, ab197553d9599b2a03aff62d1d694848
+0, 3, 3, 1, 65856, be368d1f3d3fcc710565b5433940f0df
+0, 4, 4, 1, 65856, 374c5db60ea9c110b871bb45be0efff1
+0, 5, 5, 1, 65856, ec50085400d626de5833bc0a94d9941f
+0, 6, 6, 1, 65856, d4ae69937e2a8d9bf2023d4215749635
+0, 7, 7, 1, 65856, 9b0b81eb6d62b8014e0639932fe35bc0
+0, 8, 8, 1, 65856, cd02d0cc268e6b6df0b2dbd3f3b137e6
+0, 9, 9, 1, 65856, 5322ba1085c114f93534e1761a0d8aa1
diff --git a/tests/ref/fate/vp9-03-size-224x198 b/tests/ref/fate/vp9-03-size-224x198
index dfcc091dae..39e082539c 100644
--- a/tests/ref/fate/vp9-03-size-224x198
+++ b/tests/ref/fate/vp9-03-size-224x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 66528, cf35dffc80946e87bb9d3e18aab9d320
-0, 33, 33, 0, 66528, a76ac92f05e9b097f8ac5882e1ffe656
-0, 66, 66, 0, 66528, faa1e8a11c9df3e9c9a9dafbebea6d04
-0, 100, 100, 0, 66528, 905a28289c8ac793b335096ca7f84e1d
-0, 133, 133, 0, 66528, cb480fa6977baf98a74bddf213ecba82
-0, 166, 166, 0, 66528, 35224d3708e3ba1dafcc58b803d5ea77
-0, 200, 200, 0, 66528, d166d764e87854bca47ab7a2bc8b1f9b
-0, 233, 233, 0, 66528, 562f1e06ae36abba5f1fb53e3d6cd7e8
-0, 266, 266, 0, 66528, 1599cebef060f6464aeef15aacbde446
-0, 300, 300, 0, 66528, 3316ebca2864a9dc04db86069efb1dd1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 66528, cf35dffc80946e87bb9d3e18aab9d320
+0, 1, 1, 1, 66528, a76ac92f05e9b097f8ac5882e1ffe656
+0, 2, 2, 1, 66528, faa1e8a11c9df3e9c9a9dafbebea6d04
+0, 3, 3, 1, 66528, 905a28289c8ac793b335096ca7f84e1d
+0, 4, 4, 1, 66528, cb480fa6977baf98a74bddf213ecba82
+0, 5, 5, 1, 66528, 35224d3708e3ba1dafcc58b803d5ea77
+0, 6, 6, 1, 66528, d166d764e87854bca47ab7a2bc8b1f9b
+0, 7, 7, 1, 66528, 562f1e06ae36abba5f1fb53e3d6cd7e8
+0, 8, 8, 1, 66528, 1599cebef060f6464aeef15aacbde446
+0, 9, 9, 1, 66528, 3316ebca2864a9dc04db86069efb1dd1
diff --git a/tests/ref/fate/vp9-03-size-224x200 b/tests/ref/fate/vp9-03-size-224x200
index f7cf72cf69..8fbc5b174c 100644
--- a/tests/ref/fate/vp9-03-size-224x200
+++ b/tests/ref/fate/vp9-03-size-224x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67200, 0819e6d715c9b4d94f05f63a7ca86199
-0, 33, 33, 0, 67200, 9b9a4b01ed4c8a93687e45245b3092a3
-0, 66, 66, 0, 67200, 3a076f5b8dba60552e84a391ee04d1c7
-0, 100, 100, 0, 67200, 7aafc561f5b96e9d286bd8deb5687774
-0, 133, 133, 0, 67200, daa43a89ab6b2761eedaa183e33a3465
-0, 166, 166, 0, 67200, c14874409872357b11b65f35a283e058
-0, 200, 200, 0, 67200, 37d2ef52a9c694b2596d58ed9ca0d90b
-0, 233, 233, 0, 67200, c97bc860c006896d80f52ccc0759f472
-0, 266, 266, 0, 67200, 5f8618114a723a017e39a1af695996f3
-0, 300, 300, 0, 67200, ee8234fc5ccd41d05eb87e1510f9795e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67200, 0819e6d715c9b4d94f05f63a7ca86199
+0, 1, 1, 1, 67200, 9b9a4b01ed4c8a93687e45245b3092a3
+0, 2, 2, 1, 67200, 3a076f5b8dba60552e84a391ee04d1c7
+0, 3, 3, 1, 67200, 7aafc561f5b96e9d286bd8deb5687774
+0, 4, 4, 1, 67200, daa43a89ab6b2761eedaa183e33a3465
+0, 5, 5, 1, 67200, c14874409872357b11b65f35a283e058
+0, 6, 6, 1, 67200, 37d2ef52a9c694b2596d58ed9ca0d90b
+0, 7, 7, 1, 67200, c97bc860c006896d80f52ccc0759f472
+0, 8, 8, 1, 67200, 5f8618114a723a017e39a1af695996f3
+0, 9, 9, 1, 67200, ee8234fc5ccd41d05eb87e1510f9795e
diff --git a/tests/ref/fate/vp9-03-size-224x202 b/tests/ref/fate/vp9-03-size-224x202
index e9573443fe..3e212ac60d 100644
--- a/tests/ref/fate/vp9-03-size-224x202
+++ b/tests/ref/fate/vp9-03-size-224x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67872, e1e3b4af5910383ff6f66b6ab1a29544
-0, 33, 33, 0, 67872, 8668ef92b72f35728ebb456665d48b95
-0, 66, 66, 0, 67872, dffc7c28f86f07bf28451292990e9594
-0, 100, 100, 0, 67872, aebfb446fa6d48db36dbd9b5cd147f1e
-0, 133, 133, 0, 67872, e3c6cb8c5bb3a26928493bfc297ab827
-0, 166, 166, 0, 67872, 68dabae76c1d27ab0e1079d99cb6d413
-0, 200, 200, 0, 67872, d1f7745eef748688f3871d00a7e67ef8
-0, 233, 233, 0, 67872, 36738851cc2af83fd250dea4cd63941b
-0, 266, 266, 0, 67872, 16c0315c43427e7e6719806a89551703
-0, 300, 300, 0, 67872, c4d589c0ea4cdfc1dd6dff72084c61fd
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67872, e1e3b4af5910383ff6f66b6ab1a29544
+0, 1, 1, 1, 67872, 8668ef92b72f35728ebb456665d48b95
+0, 2, 2, 1, 67872, dffc7c28f86f07bf28451292990e9594
+0, 3, 3, 1, 67872, aebfb446fa6d48db36dbd9b5cd147f1e
+0, 4, 4, 1, 67872, e3c6cb8c5bb3a26928493bfc297ab827
+0, 5, 5, 1, 67872, 68dabae76c1d27ab0e1079d99cb6d413
+0, 6, 6, 1, 67872, d1f7745eef748688f3871d00a7e67ef8
+0, 7, 7, 1, 67872, 36738851cc2af83fd250dea4cd63941b
+0, 8, 8, 1, 67872, 16c0315c43427e7e6719806a89551703
+0, 9, 9, 1, 67872, c4d589c0ea4cdfc1dd6dff72084c61fd
diff --git a/tests/ref/fate/vp9-03-size-224x208 b/tests/ref/fate/vp9-03-size-224x208
index b2efc6552a..a925e1a1e5 100644
--- a/tests/ref/fate/vp9-03-size-224x208
+++ b/tests/ref/fate/vp9-03-size-224x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 69888, 85f08afadfd1204d4131b9ee9c8cc10b
-0, 33, 33, 0, 69888, f893de5432a082b3dffcf7499827f548
-0, 66, 66, 0, 69888, cb81e0d7b657bc5a4a9cf8ad75a76a77
-0, 100, 100, 0, 69888, 8a40842123965731c15fc23fb6366d1d
-0, 133, 133, 0, 69888, 09c6d92af14a3fcfb12705cd5da57f2a
-0, 166, 166, 0, 69888, 6bede4dc8770df534b599021b0425309
-0, 200, 200, 0, 69888, 334b0b0448e9e4e6a0cddcd2e3a0af3f
-0, 233, 233, 0, 69888, 09f491f0f3870ef96cff0384cd7183d1
-0, 266, 266, 0, 69888, c9e5f81186ac947a77b051c8f0e76eac
-0, 300, 300, 0, 69888, 917565c3327bff78b53a78ea739472ff
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 69888, 85f08afadfd1204d4131b9ee9c8cc10b
+0, 1, 1, 1, 69888, f893de5432a082b3dffcf7499827f548
+0, 2, 2, 1, 69888, cb81e0d7b657bc5a4a9cf8ad75a76a77
+0, 3, 3, 1, 69888, 8a40842123965731c15fc23fb6366d1d
+0, 4, 4, 1, 69888, 09c6d92af14a3fcfb12705cd5da57f2a
+0, 5, 5, 1, 69888, 6bede4dc8770df534b599021b0425309
+0, 6, 6, 1, 69888, 334b0b0448e9e4e6a0cddcd2e3a0af3f
+0, 7, 7, 1, 69888, 09f491f0f3870ef96cff0384cd7183d1
+0, 8, 8, 1, 69888, c9e5f81186ac947a77b051c8f0e76eac
+0, 9, 9, 1, 69888, 917565c3327bff78b53a78ea739472ff
diff --git a/tests/ref/fate/vp9-03-size-224x210 b/tests/ref/fate/vp9-03-size-224x210
index 0996abd2f0..3c5945910d 100644
--- a/tests/ref/fate/vp9-03-size-224x210
+++ b/tests/ref/fate/vp9-03-size-224x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 70560, 427421e5fd2087c6ff7b87a27982332f
-0, 33, 33, 0, 70560, b68311fd44e189e4174ac357d5415068
-0, 66, 66, 0, 70560, 2c822ff45be7a1ea412d21ff82c7bc1d
-0, 100, 100, 0, 70560, 34659186d93516eae1dd4d9a391d1c3f
-0, 133, 133, 0, 70560, 1990dd822abc3a10f511589db5aa50f4
-0, 166, 166, 0, 70560, 4a4dc076172c79d9fde3e17b47109835
-0, 200, 200, 0, 70560, 51874c79850120537fa5c405721d0107
-0, 233, 233, 0, 70560, 15d7897a128de9be90be17f1679012c9
-0, 266, 266, 0, 70560, a8d9480accf8585e94161a5f7c371cef
-0, 300, 300, 0, 70560, 8a9d3f09561b895b423ae9428f620b9b
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 70560, 427421e5fd2087c6ff7b87a27982332f
+0, 1, 1, 1, 70560, b68311fd44e189e4174ac357d5415068
+0, 2, 2, 1, 70560, 2c822ff45be7a1ea412d21ff82c7bc1d
+0, 3, 3, 1, 70560, 34659186d93516eae1dd4d9a391d1c3f
+0, 4, 4, 1, 70560, 1990dd822abc3a10f511589db5aa50f4
+0, 5, 5, 1, 70560, 4a4dc076172c79d9fde3e17b47109835
+0, 6, 6, 1, 70560, 51874c79850120537fa5c405721d0107
+0, 7, 7, 1, 70560, 15d7897a128de9be90be17f1679012c9
+0, 8, 8, 1, 70560, a8d9480accf8585e94161a5f7c371cef
+0, 9, 9, 1, 70560, 8a9d3f09561b895b423ae9428f620b9b
diff --git a/tests/ref/fate/vp9-03-size-224x224 b/tests/ref/fate/vp9-03-size-224x224
index fba94fc39c..610578b669 100644
--- a/tests/ref/fate/vp9-03-size-224x224
+++ b/tests/ref/fate/vp9-03-size-224x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 75264, bedd5d2725ffff06a50e23841bc2dfb8
-0, 33, 33, 0, 75264, 8c363f68b0b30f507563516aa99e23ac
-0, 66, 66, 0, 75264, 9cb7d51ca4439614dc3f5980507a4d32
-0, 100, 100, 0, 75264, b393a18de28ab6b8d1c6afd67a7794e0
-0, 133, 133, 0, 75264, 81f69ee1e3d89cb78cac192c352f7741
-0, 166, 166, 0, 75264, aabb51f029a9a02e71524cf3500931e9
-0, 200, 200, 0, 75264, 6581aec620c508d2b42ccceaa2c6044d
-0, 233, 233, 0, 75264, 993cde759158c30dcf0f0a9fdcdfb0d8
-0, 266, 266, 0, 75264, 85985ae8d35514d601800a06c8226625
-0, 300, 300, 0, 75264, 0eba1d7c193e473586e4a5c87d0e0d21
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 75264, bedd5d2725ffff06a50e23841bc2dfb8
+0, 1, 1, 1, 75264, 8c363f68b0b30f507563516aa99e23ac
+0, 2, 2, 1, 75264, 9cb7d51ca4439614dc3f5980507a4d32
+0, 3, 3, 1, 75264, b393a18de28ab6b8d1c6afd67a7794e0
+0, 4, 4, 1, 75264, 81f69ee1e3d89cb78cac192c352f7741
+0, 5, 5, 1, 75264, aabb51f029a9a02e71524cf3500931e9
+0, 6, 6, 1, 75264, 6581aec620c508d2b42ccceaa2c6044d
+0, 7, 7, 1, 75264, 993cde759158c30dcf0f0a9fdcdfb0d8
+0, 8, 8, 1, 75264, 85985ae8d35514d601800a06c8226625
+0, 9, 9, 1, 75264, 0eba1d7c193e473586e4a5c87d0e0d21
diff --git a/tests/ref/fate/vp9-03-size-224x226 b/tests/ref/fate/vp9-03-size-224x226
index 2bf12257c4..874e595b78 100644
--- a/tests/ref/fate/vp9-03-size-224x226
+++ b/tests/ref/fate/vp9-03-size-224x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 75936, dca556e648a576b3973fbe4b34d0328c
-0, 33, 33, 0, 75936, 34a49e4aba4aca5c76ab0f751341c32b
-0, 66, 66, 0, 75936, 4b7cc6d500b273efe7e30fc3a3946f74
-0, 100, 100, 0, 75936, 1960f0f1edf9196c96b0de742a3cd53c
-0, 133, 133, 0, 75936, 3cb7d90178636911c5d53a5f8e75599c
-0, 166, 166, 0, 75936, 84b56c60c2282f85102048cc2cf40b88
-0, 200, 200, 0, 75936, 3ca34d2978307ec0fca05130d81bcc26
-0, 233, 233, 0, 75936, c15560be737e02ea9d1deeca0af9bb77
-0, 266, 266, 0, 75936, 391439789a6aa7bb02d7e699795a9559
-0, 300, 300, 0, 75936, 9f681e91cbcbe9920f21236b8ff093c7
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 75936, dca556e648a576b3973fbe4b34d0328c
+0, 1, 1, 1, 75936, 34a49e4aba4aca5c76ab0f751341c32b
+0, 2, 2, 1, 75936, 4b7cc6d500b273efe7e30fc3a3946f74
+0, 3, 3, 1, 75936, 1960f0f1edf9196c96b0de742a3cd53c
+0, 4, 4, 1, 75936, 3cb7d90178636911c5d53a5f8e75599c
+0, 5, 5, 1, 75936, 84b56c60c2282f85102048cc2cf40b88
+0, 6, 6, 1, 75936, 3ca34d2978307ec0fca05130d81bcc26
+0, 7, 7, 1, 75936, c15560be737e02ea9d1deeca0af9bb77
+0, 8, 8, 1, 75936, 391439789a6aa7bb02d7e699795a9559
+0, 9, 9, 1, 75936, 9f681e91cbcbe9920f21236b8ff093c7
diff --git a/tests/ref/fate/vp9-03-size-226x196 b/tests/ref/fate/vp9-03-size-226x196
index 9cb72d315a..43d55b9802 100644
--- a/tests/ref/fate/vp9-03-size-226x196
+++ b/tests/ref/fate/vp9-03-size-226x196
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 66444, 4757a31842453f806de2f2256329547e
-0, 33, 33, 0, 66444, fe5fb955a4143091c5bfae7c4a4afe0f
-0, 66, 66, 0, 66444, 93766c5a03d71f99afb7705add7b63f0
-0, 100, 100, 0, 66444, 30c91162aa6fb0ed3e47325146bb6d8a
-0, 133, 133, 0, 66444, 501fe67785b970b1b62c2ae0b36b19ad
-0, 166, 166, 0, 66444, 836be5e778e3d20e75c4fcd71f765b3d
-0, 200, 200, 0, 66444, 21a9fd5e78212fe71719e173844bc6e6
-0, 233, 233, 0, 66444, 81b3919208e345d93dde62740b47dd93
-0, 266, 266, 0, 66444, df010555a929ba88a2f25c6267e3786e
-0, 300, 300, 0, 66444, d2cff8282e5e7a5bbd879c73df0670c3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 66444, 4757a31842453f806de2f2256329547e
+0, 1, 1, 1, 66444, fe5fb955a4143091c5bfae7c4a4afe0f
+0, 2, 2, 1, 66444, 93766c5a03d71f99afb7705add7b63f0
+0, 3, 3, 1, 66444, 30c91162aa6fb0ed3e47325146bb6d8a
+0, 4, 4, 1, 66444, 501fe67785b970b1b62c2ae0b36b19ad
+0, 5, 5, 1, 66444, 836be5e778e3d20e75c4fcd71f765b3d
+0, 6, 6, 1, 66444, 21a9fd5e78212fe71719e173844bc6e6
+0, 7, 7, 1, 66444, 81b3919208e345d93dde62740b47dd93
+0, 8, 8, 1, 66444, df010555a929ba88a2f25c6267e3786e
+0, 9, 9, 1, 66444, d2cff8282e5e7a5bbd879c73df0670c3
diff --git a/tests/ref/fate/vp9-03-size-226x198 b/tests/ref/fate/vp9-03-size-226x198
index f70b3308ed..fe2c4770fb 100644
--- a/tests/ref/fate/vp9-03-size-226x198
+++ b/tests/ref/fate/vp9-03-size-226x198
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67122, b97087eb8c53cf56dc44576912654fb2
-0, 33, 33, 0, 67122, 219bb68a59dc166806a5b5689a943b66
-0, 66, 66, 0, 67122, 67b2ec19dd3b74d828b51912c25249d6
-0, 100, 100, 0, 67122, 73dd9625538e10a0f94d31ac9fe3db23
-0, 133, 133, 0, 67122, 51e68f201130da18beb0cb27adcf6fa9
-0, 166, 166, 0, 67122, 455d9753b3c0ac5ad7d9da022f69acd0
-0, 200, 200, 0, 67122, 60a8905a63db4cdd2560583fb6415030
-0, 233, 233, 0, 67122, 48c156f4b2c9f936487b43713a4573fd
-0, 266, 266, 0, 67122, a5c8f4190cb34b3ecd42ca8e09bf1646
-0, 300, 300, 0, 67122, 233a5d5187137e047993532fc2e725d3
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67122, b97087eb8c53cf56dc44576912654fb2
+0, 1, 1, 1, 67122, 219bb68a59dc166806a5b5689a943b66
+0, 2, 2, 1, 67122, 67b2ec19dd3b74d828b51912c25249d6
+0, 3, 3, 1, 67122, 73dd9625538e10a0f94d31ac9fe3db23
+0, 4, 4, 1, 67122, 51e68f201130da18beb0cb27adcf6fa9
+0, 5, 5, 1, 67122, 455d9753b3c0ac5ad7d9da022f69acd0
+0, 6, 6, 1, 67122, 60a8905a63db4cdd2560583fb6415030
+0, 7, 7, 1, 67122, 48c156f4b2c9f936487b43713a4573fd
+0, 8, 8, 1, 67122, a5c8f4190cb34b3ecd42ca8e09bf1646
+0, 9, 9, 1, 67122, 233a5d5187137e047993532fc2e725d3
diff --git a/tests/ref/fate/vp9-03-size-226x200 b/tests/ref/fate/vp9-03-size-226x200
index 62cea7f2dc..b16c531956 100644
--- a/tests/ref/fate/vp9-03-size-226x200
+++ b/tests/ref/fate/vp9-03-size-226x200
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 67800, 0ae27db338f73f37eaed806b1c789593
-0, 33, 33, 0, 67800, 3f69273752f43699a3bc7b22a88cc3aa
-0, 66, 66, 0, 67800, ce0dfafb59910241d2b1a2275a2c2143
-0, 100, 100, 0, 67800, 8d20f404e25766c819ee728858bcbc76
-0, 133, 133, 0, 67800, 67bc5604c5b0f6c3484b605c1f93c83a
-0, 166, 166, 0, 67800, 1c82def3a06430d205cce0db7b5714de
-0, 200, 200, 0, 67800, 654d7a676e3b8b64541ed8cdefbd7286
-0, 233, 233, 0, 67800, 6c80c78c7b652c5b3b117a0960e89951
-0, 266, 266, 0, 67800, ae73e3c69ec6747c5234d58c5e1e36eb
-0, 300, 300, 0, 67800, e40d716efd8caf2d4004d299fb914328
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 67800, 0ae27db338f73f37eaed806b1c789593
+0, 1, 1, 1, 67800, 3f69273752f43699a3bc7b22a88cc3aa
+0, 2, 2, 1, 67800, ce0dfafb59910241d2b1a2275a2c2143
+0, 3, 3, 1, 67800, 8d20f404e25766c819ee728858bcbc76
+0, 4, 4, 1, 67800, 67bc5604c5b0f6c3484b605c1f93c83a
+0, 5, 5, 1, 67800, 1c82def3a06430d205cce0db7b5714de
+0, 6, 6, 1, 67800, 654d7a676e3b8b64541ed8cdefbd7286
+0, 7, 7, 1, 67800, 6c80c78c7b652c5b3b117a0960e89951
+0, 8, 8, 1, 67800, ae73e3c69ec6747c5234d58c5e1e36eb
+0, 9, 9, 1, 67800, e40d716efd8caf2d4004d299fb914328
diff --git a/tests/ref/fate/vp9-03-size-226x202 b/tests/ref/fate/vp9-03-size-226x202
index d13634aa45..818038d9f0 100644
--- a/tests/ref/fate/vp9-03-size-226x202
+++ b/tests/ref/fate/vp9-03-size-226x202
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 68478, 0cd2876640e71de3a6df7839bd6f0b51
-0, 33, 33, 0, 68478, f887db6839c0cddd1ea9ae6bfd2cc16d
-0, 66, 66, 0, 68478, ff2a890cf4c4973bf181ba8424c2eadc
-0, 100, 100, 0, 68478, f69f2e4f3036a21deb43a0bf4b95771f
-0, 133, 133, 0, 68478, 93f511739c19f1a3b356dda39d945c93
-0, 166, 166, 0, 68478, 7f79633c93765b504fef0324bd10fdba
-0, 200, 200, 0, 68478, d6c53d3937c9a40b227b4486452e0b33
-0, 233, 233, 0, 68478, 4e26625e8997ad6fe08ae68fbdfdbfd7
-0, 266, 266, 0, 68478, 3bf4c8ac0279351bf904cf57b0fc13c1
-0, 300, 300, 0, 68478, 12d64d856025185fa9e610dfa62b05af
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 68478, 0cd2876640e71de3a6df7839bd6f0b51
+0, 1, 1, 1, 68478, f887db6839c0cddd1ea9ae6bfd2cc16d
+0, 2, 2, 1, 68478, ff2a890cf4c4973bf181ba8424c2eadc
+0, 3, 3, 1, 68478, f69f2e4f3036a21deb43a0bf4b95771f
+0, 4, 4, 1, 68478, 93f511739c19f1a3b356dda39d945c93
+0, 5, 5, 1, 68478, 7f79633c93765b504fef0324bd10fdba
+0, 6, 6, 1, 68478, d6c53d3937c9a40b227b4486452e0b33
+0, 7, 7, 1, 68478, 4e26625e8997ad6fe08ae68fbdfdbfd7
+0, 8, 8, 1, 68478, 3bf4c8ac0279351bf904cf57b0fc13c1
+0, 9, 9, 1, 68478, 12d64d856025185fa9e610dfa62b05af
diff --git a/tests/ref/fate/vp9-03-size-226x208 b/tests/ref/fate/vp9-03-size-226x208
index 9e88108b78..cda6f99963 100644
--- a/tests/ref/fate/vp9-03-size-226x208
+++ b/tests/ref/fate/vp9-03-size-226x208
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 70512, 6006cac6628cf9e7cea58aec07471b06
-0, 33, 33, 0, 70512, f7e994921248b6933920c984880ec96c
-0, 66, 66, 0, 70512, c0aeeb9d2009538d8d5e837f45e1542d
-0, 100, 100, 0, 70512, 7dacf9d00e85bd52045eb47bae5225b3
-0, 133, 133, 0, 70512, 024fd008a099ae954e38a3f0a8ebb6c9
-0, 166, 166, 0, 70512, fb6c368a1b3578ab59aa30e0b5cc4853
-0, 200, 200, 0, 70512, 07815251f7020b627c365a7a7be694c7
-0, 233, 233, 0, 70512, db8b8f48f3693867d2bd8208cf4f929a
-0, 266, 266, 0, 70512, 88b42d943c0978d832333a8a3f7b6bbc
-0, 300, 300, 0, 70512, 7aa760190f9328ba4f6fa87d1d9e8d3e
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 70512, 6006cac6628cf9e7cea58aec07471b06
+0, 1, 1, 1, 70512, f7e994921248b6933920c984880ec96c
+0, 2, 2, 1, 70512, c0aeeb9d2009538d8d5e837f45e1542d
+0, 3, 3, 1, 70512, 7dacf9d00e85bd52045eb47bae5225b3
+0, 4, 4, 1, 70512, 024fd008a099ae954e38a3f0a8ebb6c9
+0, 5, 5, 1, 70512, fb6c368a1b3578ab59aa30e0b5cc4853
+0, 6, 6, 1, 70512, 07815251f7020b627c365a7a7be694c7
+0, 7, 7, 1, 70512, db8b8f48f3693867d2bd8208cf4f929a
+0, 8, 8, 1, 70512, 88b42d943c0978d832333a8a3f7b6bbc
+0, 9, 9, 1, 70512, 7aa760190f9328ba4f6fa87d1d9e8d3e
diff --git a/tests/ref/fate/vp9-03-size-226x210 b/tests/ref/fate/vp9-03-size-226x210
index 0ff9dfc20d..fa83e1de0d 100644
--- a/tests/ref/fate/vp9-03-size-226x210
+++ b/tests/ref/fate/vp9-03-size-226x210
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 71190, a6c1b7686202f5cc64335f92be595309
-0, 33, 33, 0, 71190, 3e573d4c693a39c5d6cd46b8873e99bb
-0, 66, 66, 0, 71190, d2388f6f641c8ddec98f11493f1a1390
-0, 100, 100, 0, 71190, 16473e33532ebc8de2f02077c406346b
-0, 133, 133, 0, 71190, 6c75d1c01276838fce40837e373f49db
-0, 166, 166, 0, 71190, b718e7445e2b08dde78fa7f30be01346
-0, 200, 200, 0, 71190, 2f556ed5afd60b1bbae76984ce073107
-0, 233, 233, 0, 71190, 4e5d59daed044c39a14c35f18cb4fb7a
-0, 266, 266, 0, 71190, c14901a9906ffcd0eb1efc068ce32941
-0, 300, 300, 0, 71190, 3d73b7f87bcd16c1ec565b5cc8d0fe93
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 71190, a6c1b7686202f5cc64335f92be595309
+0, 1, 1, 1, 71190, 3e573d4c693a39c5d6cd46b8873e99bb
+0, 2, 2, 1, 71190, d2388f6f641c8ddec98f11493f1a1390
+0, 3, 3, 1, 71190, 16473e33532ebc8de2f02077c406346b
+0, 4, 4, 1, 71190, 6c75d1c01276838fce40837e373f49db
+0, 5, 5, 1, 71190, b718e7445e2b08dde78fa7f30be01346
+0, 6, 6, 1, 71190, 2f556ed5afd60b1bbae76984ce073107
+0, 7, 7, 1, 71190, 4e5d59daed044c39a14c35f18cb4fb7a
+0, 8, 8, 1, 71190, c14901a9906ffcd0eb1efc068ce32941
+0, 9, 9, 1, 71190, 3d73b7f87bcd16c1ec565b5cc8d0fe93
diff --git a/tests/ref/fate/vp9-03-size-226x224 b/tests/ref/fate/vp9-03-size-226x224
index 37b39a865b..50d81cb7ab 100644
--- a/tests/ref/fate/vp9-03-size-226x224
+++ b/tests/ref/fate/vp9-03-size-226x224
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 75936, 80fb3a643384386beadc0991f171669d
-0, 33, 33, 0, 75936, 65a4a51163f49a75f8eeecd94cb2ba47
-0, 66, 66, 0, 75936, d5b2aac9889d2991b83fd4360ada0258
-0, 100, 100, 0, 75936, 7958ff5535358567ea7df351d78256a7
-0, 133, 133, 0, 75936, 7e7413b9a61967d0ade07b81944e9a15
-0, 166, 166, 0, 75936, 40a008016adbf9673adbbc4c0edb4454
-0, 200, 200, 0, 75936, fef7b5e2809ef79917ab394a067ef4be
-0, 233, 233, 0, 75936, 91ee2360faf46a25b95927c55eea603f
-0, 266, 266, 0, 75936, a47f14a80a529f79f97accbe23188046
-0, 300, 300, 0, 75936, 3613bcd41ff13006fbba3bd0087c44f4
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 75936, 80fb3a643384386beadc0991f171669d
+0, 1, 1, 1, 75936, 65a4a51163f49a75f8eeecd94cb2ba47
+0, 2, 2, 1, 75936, d5b2aac9889d2991b83fd4360ada0258
+0, 3, 3, 1, 75936, 7958ff5535358567ea7df351d78256a7
+0, 4, 4, 1, 75936, 7e7413b9a61967d0ade07b81944e9a15
+0, 5, 5, 1, 75936, 40a008016adbf9673adbbc4c0edb4454
+0, 6, 6, 1, 75936, fef7b5e2809ef79917ab394a067ef4be
+0, 7, 7, 1, 75936, 91ee2360faf46a25b95927c55eea603f
+0, 8, 8, 1, 75936, a47f14a80a529f79f97accbe23188046
+0, 9, 9, 1, 75936, 3613bcd41ff13006fbba3bd0087c44f4
diff --git a/tests/ref/fate/vp9-03-size-226x226 b/tests/ref/fate/vp9-03-size-226x226
index 01c05dca3f..88b3c43b77 100644
--- a/tests/ref/fate/vp9-03-size-226x226
+++ b/tests/ref/fate/vp9-03-size-226x226
@@ -1,11 +1,15 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 76614, f2370fc802dafdf5082beffc1907a9c6
-0, 33, 33, 0, 76614, aad6de7b986234a1d621935b272501c9
-0, 66, 66, 0, 76614, 8a6d3784e22e3b4f735e78916fbc3821
-0, 100, 100, 0, 76614, 0c4afce19c43fdf3bb1b972810cc9126
-0, 133, 133, 0, 76614, 814a68dd76a3135221131988910f51ba
-0, 166, 166, 0, 76614, b2379c4b28dca10e67ac58631f9731c0
-0, 200, 200, 0, 76614, b16fd651884340a428cea3fe0ac18ba6
-0, 233, 233, 0, 76614, cb65cd4c421cfd6a19fb123ec27abbe6
-0, 266, 266, 0, 76614, 7f1d2686b9808de8ecc723b18136d57d
-0, 300, 300, 0, 76614, da7fd4bff4b6db0221c42492876c5c4d
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 76614, f2370fc802dafdf5082beffc1907a9c6
+0, 1, 1, 1, 76614, aad6de7b986234a1d621935b272501c9
+0, 2, 2, 1, 76614, 8a6d3784e22e3b4f735e78916fbc3821
+0, 3, 3, 1, 76614, 0c4afce19c43fdf3bb1b972810cc9126
+0, 4, 4, 1, 76614, 814a68dd76a3135221131988910f51ba
+0, 5, 5, 1, 76614, b2379c4b28dca10e67ac58631f9731c0
+0, 6, 6, 1, 76614, b16fd651884340a428cea3fe0ac18ba6
+0, 7, 7, 1, 76614, cb65cd4c421cfd6a19fb123ec27abbe6
+0, 8, 8, 1, 76614, 7f1d2686b9808de8ecc723b18136d57d
+0, 9, 9, 1, 76614, da7fd4bff4b6db0221c42492876c5c4d
diff --git a/tests/ref/fate/vp9-05-resize b/tests/ref/fate/vp9-05-resize
new file mode 100644
index 0000000000..4a3cd09084
--- /dev/null
+++ b/tests/ref/fate/vp9-05-resize
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 539e9964364c1db09ad18f2e01713799
+0, 1, 1, 1, 152064, fb76e673ba2a5342bfed8a1523e0a425
+0, 2, 2, 1, 152064, b0e6881ac6c1e0d839f80f292cb1afd4
+0, 3, 3, 1, 152064, f69a4d7f784e1619e45ffd65e3f103b9
+0, 4, 4, 1, 152064, a9cefc3088de0b403c7cc1ffd117479a
+0, 5, 5, 1, 152064, 6a053249fe6fdc52ed00a21668fe330f
+0, 6, 6, 1, 152064, 2c6f7b8c72a0103cd1fa37270f6d9962
+0, 7, 7, 1, 152064, 9f837ba58bf07d1e1a8b6a30a9a588e8
+0, 8, 8, 1, 152064, 81ecfd1810b25395af999e557ed4b938
+0, 9, 9, 1, 152064, cee53e71d6347333fd76d421ece1740f
diff --git a/tests/ref/fate/vp9-06-bilinear b/tests/ref/fate/vp9-06-bilinear
new file mode 100644
index 0000000000..b175195cba
--- /dev/null
+++ b/tests/ref/fate/vp9-06-bilinear
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 818a5af531c921ae58dfedc75234f3c5
+0, 1, 1, 1, 152064, f863f8c68b5c87c721d345c5a894336d
+0, 2, 2, 1, 152064, 3f1213e44db416530bc0717f0a795b5d
+0, 3, 3, 1, 152064, 4b99c16a62c3d6687c78236fa13e1f41
+0, 4, 4, 1, 152064, 80f23a3f04215dd7542128e7c53d68d0
+0, 5, 5, 1, 152064, b40b7aa34a77fe773d82d75b5bdd9c13
+0, 6, 6, 1, 152064, dd4af6263d20bbaf9afedb6695c1ba67
+0, 7, 7, 1, 152064, 1f2ccf88f15c10e3c27b2368dacc3727
+0, 8, 8, 1, 152064, 232b027c4e9b598f50d078bb7b7a165e
+0, 9, 9, 1, 152064, 2b44367332aa0fe42362d61f18e7f8dd
diff --git a/tests/ref/fate/vp9-09-lf_deltas b/tests/ref/fate/vp9-09-lf_deltas
new file mode 100644
index 0000000000..733a70ca9f
--- /dev/null
+++ b/tests/ref/fate/vp9-09-lf_deltas
@@ -0,0 +1,35 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 126720, a83c7f4602f595fd09e97f8c8a7277ec
+0, 1, 1, 1, 126720, 53e1a3fd44932883a8dd112bbb0e359f
+0, 2, 2, 1, 126720, 4bb16d168f9f0a7702c31a68bb8ff36c
+0, 3, 3, 1, 126720, 1b2df157913aba96553aaf8d51491bf3
+0, 4, 4, 1, 126720, 9d041532e42fca7a4062cd3e9b75413b
+0, 5, 5, 1, 126720, 0dbac5ca06e13714d10e99042aefe375
+0, 6, 6, 1, 126720, bb83a507a65d2a640b08f42a77bb37f6
+0, 7, 7, 1, 126720, 176f992d37c7daa36135cddb49398de3
+0, 8, 8, 1, 126720, c41834f72b3281cf6aaa66fd7416e6c3
+0, 9, 9, 1, 126720, 790d4e6b1609dec782ff978e2003d318
+0, 10, 10, 1, 126720, 449622f741f7577c1d721f2e9eb25091
+0, 11, 11, 1, 126720, 8ef8543f7895c87ab04491b0150628e5
+0, 12, 12, 1, 126720, 88ef626aca4b2bcb8c58a69db20a7b02
+0, 13, 13, 1, 126720, 4b2f7adc2e1872ecdd9ffa7d1f1df4a6
+0, 14, 14, 1, 126720, 7b162660225022ef31e39c34fee3418e
+0, 15, 15, 1, 126720, 2b439a4b846edcc69cdf6075de5ac8fb
+0, 16, 16, 1, 126720, ba2eb1ba0ed9abf701a53a94c9c626fc
+0, 17, 17, 1, 126720, 9fbec5d5334fd5e917feee756b652d93
+0, 18, 18, 1, 126720, 93b5eb99ea54abc5fa90c5674499e27e
+0, 19, 19, 1, 126720, 04a98408e9b0aed28932ef1dfdcfdb6c
+0, 20, 20, 1, 126720, 9856ba976bed30bc790a3f28e926b092
+0, 21, 21, 1, 126720, 2b0f450e9724cfc57b846148ff876e51
+0, 22, 22, 1, 126720, 163757f3529369b9789ea606387b831d
+0, 23, 23, 1, 126720, de5ed2aff936c54f3378d0dcc2575d13
+0, 24, 24, 1, 126720, 1f642826b8a6fb111c7c6130481dab89
+0, 25, 25, 1, 126720, b8e3a77c7d3c5c56f67aa7409fb5404c
+0, 26, 26, 1, 126720, eb06cb4f471e42d7fc06929a442cca8b
+0, 27, 27, 1, 126720, 53471649a5080b306d2c04a4f7673bdf
+0, 28, 28, 1, 126720, 70996be0cc5d2bd97025015dd50caa99
+0, 29, 29, 1, 126720, ff3280a8562fdf6697c4a7cb9c1bf0a0
diff --git a/tests/ref/fate/vp9-10-show-existing-frame b/tests/ref/fate/vp9-10-show-existing-frame
new file mode 100644
index 0000000000..266f44e5b7
--- /dev/null
+++ b/tests/ref/fate/vp9-10-show-existing-frame
@@ -0,0 +1,14 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 18981342ec178e082519451062c3a67f
+0, 1, 1, 1, 152064, 04ab9dbeac49ec31be58f6e671698e05
+0, 6, 6, 1, 152064, a41f00034923e56ba51a0b598acc2e3a
+0, 7, 7, 1, 152064, 63fa55ae9535ccdf06d44cce8065dda6
+0, 9, 9, 1, 152064, 0e4b08e14d919edee2bbff2ecd47de57
+0, 10, 10, 1, 152064, 0e4b08e14d919edee2bbff2ecd47de57
+0, 13, 13, 1, 152064, 9e932915c67a789f6877e6d3f76d3649
+0, 14, 14, 1, 152064, 12f2e975c217e7ffcf334524e8acec35
+0, 15, 15, 1, 152064, 9e932915c67a789f6877e6d3f76d3649
diff --git a/tests/ref/fate/vp9-10-show-existing-frame2 b/tests/ref/fate/vp9-10-show-existing-frame2
new file mode 100644
index 0000000000..cdd4369e82
--- /dev/null
+++ b/tests/ref/fate/vp9-10-show-existing-frame2
@@ -0,0 +1,20 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 382b12c33cd86b38758706b8ebca8a85
+0, 1, 1, 1, 152064, 799544370b35c91711a5b49a28cf86a8
+0, 2, 2, 1, 152064, 7218eb4b6d1c7aea4f96ee47ad675e8e
+0, 3, 3, 1, 152064, 627466200370e6ad60ea570d31be66e3
+0, 4, 4, 1, 152064, 7dc65a2af108379f2b9265a9a1ea7cf8
+0, 5, 5, 1, 152064, c979e2f084760775a567f60f79f28198
+0, 6, 6, 1, 152064, fe668a6417aa0543e4ed4d1c67c5cbcb
+0, 7, 7, 1, 152064, bf9901e39815fa93cce0ed5b02b2ef2d
+0, 8, 8, 1, 152064, 627466200370e6ad60ea570d31be66e3
+0, 9, 9, 1, 152064, 7dc65a2af108379f2b9265a9a1ea7cf8
+0, 10, 10, 1, 152064, c979e2f084760775a567f60f79f28198
+0, 11, 11, 1, 152064, fe668a6417aa0543e4ed4d1c67c5cbcb
+0, 13, 13, 1, 152064, 627466200370e6ad60ea570d31be66e3
+0, 14, 14, 1, 152064, 7dc65a2af108379f2b9265a9a1ea7cf8
+0, 15, 15, 1, 152064, c979e2f084760775a567f60f79f28198
diff --git a/tests/ref/fate/vp9-15-segkey_adpq b/tests/ref/fate/vp9-15-segkey_adpq
new file mode 100644
index 0000000000..f12db8b2eb
--- /dev/null
+++ b/tests/ref/fate/vp9-15-segkey_adpq
@@ -0,0 +1,155 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 613440, d4f0e4b606ddb40b482aecb24cf3bc63
+0, 1, 1, 1, 613440, 692ec092bc5928fa6430d056e883759a
+0, 2, 2, 1, 613440, dad790df33430899fed98886a24b37e5
+0, 3, 3, 1, 613440, 7e66e793ac9462a40dd5b963fb62e667
+0, 4, 4, 1, 613440, 0d795c6e20f42f09aca0ddb9dffaa6e8
+0, 5, 5, 1, 613440, 0ef3739c4ab2c51f0ab8e290eadad77e
+0, 6, 6, 1, 613440, 04a15f765960263c1b4a5a8822e17322
+0, 7, 7, 1, 613440, 116d518830c958bf46759fd79bc74198
+0, 8, 8, 1, 613440, 58ea67addab05825cc2e5f2ab99fca4b
+0, 9, 9, 1, 613440, 590f6e5deea6dde21dc1098fa2017c2f
+0, 10, 10, 1, 613440, 895479957b0882ccce4159782dee8deb
+0, 11, 11, 1, 613440, cc8e05afdfb6f9c7042fd6f9e9d49140
+0, 12, 12, 1, 613440, 3e47c556a63af90f1ca4609f97f25d2c
+0, 13, 13, 1, 613440, e5ca5dce8cbd39412db2fe219d6d2594
+0, 14, 14, 1, 613440, c62b456e12230660d26eb7226f257d0c
+0, 15, 15, 1, 613440, e184c961b373de465d3242f32f7cf3ed
+0, 16, 16, 1, 613440, 7466b91858f740fc28965a63effe05d6
+0, 17, 17, 1, 613440, c8f06a3b1e471c4e7a9efd71a30dfe3b
+0, 18, 18, 1, 613440, d4fb95148963b2eaff0211ddc5117c13
+0, 19, 19, 1, 613440, c646526b40277289520d47ed8ca3b644
+0, 20, 20, 1, 613440, e441ae686fa444e4e3584543611043ba
+0, 21, 21, 1, 613440, 68d707ef6909bfbc02dcbd9e392a04f6
+0, 22, 22, 1, 613440, 1ff285d17a26622b61bd2651754602b1
+0, 23, 23, 1, 613440, c272192987e44e54e5335e6416bd15a5
+0, 24, 24, 1, 613440, 8f6f02572181eb4855dcd4c957e57d2e
+0, 25, 25, 1, 613440, baf03eb567fd092eeb6f08ff5e098350
+0, 26, 26, 1, 613440, 479c78bd3da0892b8d4e32c99ec4739f
+0, 27, 27, 1, 613440, d39a52f6e30ef10462bdef1006809e88
+0, 28, 28, 1, 613440, d58395369806221efe9ba88513319d8a
+0, 29, 29, 1, 613440, 459e77e83c510ee1d79bf069752d44e5
+0, 30, 30, 1, 613440, 438027c8eacb9c795f8267a151ef5a4e
+0, 31, 31, 1, 613440, ea6b73fb0d4b23ebbdaeb0267135d083
+0, 32, 32, 1, 613440, 48160c624d4d5050a4c8abcbe0edf4b2
+0, 33, 33, 1, 613440, 6fc6d5b4751cf137fc0204c0026f2503
+0, 34, 34, 1, 613440, 5ea20f6483fc5cde854313ed8288c7ca
+0, 35, 35, 1, 613440, dafa41fa3468f684ca5538593cd1a0de
+0, 36, 36, 1, 613440, b73d3336c83a27874e24b691c34c3421
+0, 37, 37, 1, 613440, d0b0488a5871a49442746ac8ea1343bc
+0, 38, 38, 1, 613440, df6fe9cb354624b69908730f24f51b88
+0, 39, 39, 1, 613440, a388b159a024ace9437976206e62473c
+0, 40, 40, 1, 613440, 9007423410201a70b6997477ed9040f6
+0, 41, 41, 1, 613440, 7f7425cc018ad391e06b867f51d69513
+0, 42, 42, 1, 613440, 2ef51a3a15c627f803eee7f351cdfa4e
+0, 43, 43, 1, 613440, 260cded2461ab87181d650c58a8a0656
+0, 44, 44, 1, 613440, fdd7a93b5f25ec2b74d93736fa7bb475
+0, 45, 45, 1, 613440, 810bb95ef0221b50ef12c7d0a4740fec
+0, 46, 46, 1, 613440, f7eb4d63c16aebfeba4804c4e9c2c134
+0, 47, 47, 1, 613440, a1ae94b85bced552e2c4f15ab5c5096d
+0, 48, 48, 1, 613440, 4b7b9e460b4a4ceab5deb5c6876cea05
+0, 49, 49, 1, 613440, 514472399dc39fcc4e833e166b81ea8e
+0, 50, 50, 1, 613440, dca73ca76936d0a7eeb71c20955ea3a3
+0, 51, 51, 1, 613440, 927b185567b515a6bd102e1199ee1836
+0, 52, 52, 1, 613440, 63e1fffd59b77c53811d75a116fbac60
+0, 53, 53, 1, 613440, 5ca302497e81d564cfd455e2b606b262
+0, 54, 54, 1, 613440, 6e317d469ee664bc511a8286650f0b79
+0, 55, 55, 1, 613440, d93e1909f3bdda983e0b3c73a8c51754
+0, 56, 56, 1, 613440, 836072cb1c4dc3dc32c935ba4ac3f716
+0, 57, 57, 1, 613440, 014e61666ba819260a25f09ae97768a8
+0, 58, 58, 1, 613440, 997fa6283e48ff017ce04041b9022fb9
+0, 59, 59, 1, 613440, b2c35749c6b848601193c2eff7f0bdf1
+0, 60, 60, 1, 613440, 813e9f562ef53589afbfe7d73002c136
+0, 61, 61, 1, 613440, be876a05cfc72fe6138e1c24b6e94c3f
+0, 62, 62, 1, 613440, 2a33b99f67fe5579ddbd62bac085ae8a
+0, 63, 63, 1, 613440, 8d374a1886861cfd9ca6f16a0aff1b6c
+0, 64, 64, 1, 613440, eff4e17b08c67a1663c8f1cc614bd94a
+0, 65, 65, 1, 613440, 39e4d97460cf02ecfbc666e0413d7db1
+0, 66, 66, 1, 613440, 732f41606146dfb0c6a8cf130df969a8
+0, 67, 67, 1, 613440, 9b724b808bc26f21aaa32653185b2cf3
+0, 68, 68, 1, 613440, e18598cb7ac70cdb5dea29b35ae5accb
+0, 69, 69, 1, 613440, afbcad9f7bad0b58a5bccdb8977a60fb
+0, 70, 70, 1, 613440, 6ec24c40cd8a0cf2e15339ce4f60c232
+0, 71, 71, 1, 613440, 76616dbe8207235f6890360566f9e8df
+0, 72, 72, 1, 613440, 49a5c751ed430e9bc41c3a3334295025
+0, 73, 73, 1, 613440, f657e47dbbcc2a04e9e7b71ecd8451ff
+0, 74, 74, 1, 613440, 8e85f3d26b26f26ccd804061d2f37bbb
+0, 75, 75, 1, 613440, 5a9dd5c0390491cd21163da01dc21f4d
+0, 76, 76, 1, 613440, 3cf88ad2d2d7ecf1223afa5d1b849317
+0, 77, 77, 1, 613440, 27385b23461b5f1c137c2f29354595ed
+0, 78, 78, 1, 613440, e6eacbe2890389c586f2936a75ab3509
+0, 79, 79, 1, 613440, 19a48ffafdcdb6fb1d6b9808daed2f86
+0, 80, 80, 1, 613440, f8c9419d4944fb214e06a2c30a560d93
+0, 81, 81, 1, 613440, 3f3d3dd54e5aa6bd59af1be86ec9be3d
+0, 82, 82, 1, 613440, 28be5316ed79dc47b6a142cef0c16ab7
+0, 83, 83, 1, 613440, 6fbed684bfe8dfd354210293d7eb4d0b
+0, 84, 84, 1, 613440, e60cd76f68c95f8b484d0b6424eea4cc
+0, 85, 85, 1, 613440, e05a0cf382f49039faddaffeff2cec16
+0, 86, 86, 1, 613440, 42ea736ebbfe50f1ebd460d71781e5d6
+0, 87, 87, 1, 613440, 80f78066700b6752bbc1a41390ddb482
+0, 88, 88, 1, 613440, 14671354929fcf10677b2ed2db3c8cb4
+0, 89, 89, 1, 613440, 96a7d68407f1a2c96bd3cafe0c696bf5
+0, 90, 90, 1, 613440, 2f2adb990cfa42229db987a668b19d38
+0, 91, 91, 1, 613440, a8233951004e1bb0d0937435a517fad2
+0, 92, 92, 1, 613440, 6163e872c38adfde7b0c8891cbb2c969
+0, 93, 93, 1, 613440, 990165e0905fb80ccc29d2de062d4f9b
+0, 94, 94, 1, 613440, e6f3224c4c60098ee93fca870f8636b2
+0, 95, 95, 1, 613440, 8c561667345f932618f8b3aaa43ffde0
+0, 96, 96, 1, 613440, 1acb3999bacd483d1153beb43ee09772
+0, 97, 97, 1, 613440, 2a075c7bc49190df83b8285ee6e124d3
+0, 98, 98, 1, 613440, 890a134a3c77d9b64d83fe6d2def02de
+0, 99, 99, 1, 613440, d0b41422b89f03ffcbde7c85889ad2c2
+0, 100, 100, 1, 613440, fdc4f855d70ef16ec9baeb05c3a73f44
+0, 101, 101, 1, 613440, ed9f847a3b4280cfe306018825c76508
+0, 102, 102, 1, 613440, 5deb2536bba158c722bc0d909f45e611
+0, 103, 103, 1, 613440, fc7880ca8680e03fb1978adce8066027
+0, 104, 104, 1, 613440, 6e1c351c6b102e9185f688a02190b87f
+0, 105, 105, 1, 613440, 1f6169bf490ed1b4c391383f770fec02
+0, 106, 106, 1, 613440, 80ac3b673b1504fb1e88d883a91a539c
+0, 107, 107, 1, 613440, d2e7654f961ff3767c1e9e8558c2f20d
+0, 108, 108, 1, 613440, 365368d813eb10c5adc53e47afeb414d
+0, 109, 109, 1, 613440, 5f74f55478377dd31da91cf195332480
+0, 110, 110, 1, 613440, 827b7b3853ea3b1855583b59ed7b09c2
+0, 111, 111, 1, 613440, 2017c1a57a271308172bd84d3887d063
+0, 112, 112, 1, 613440, d65b95c71db9972dc051bec7df19f85f
+0, 113, 113, 1, 613440, 7243da9072729ffa75209a6699e77ac3
+0, 114, 114, 1, 613440, 112da8d27907ab6a66b030e9c8864e46
+0, 115, 115, 1, 613440, e2837b6409de4bc6e71ff9eca8eab391
+0, 116, 116, 1, 613440, 567eba2ddb91a02665ac96fa10703f00
+0, 117, 117, 1, 613440, 474a99d56fce0e7e96ac3585b905956f
+0, 118, 118, 1, 613440, 3087edb09f1ef2e63130b7c03e696028
+0, 119, 119, 1, 613440, 574f7328da31760ecf237617aebd7784
+0, 120, 120, 1, 613440, c3a7669bb496bec766a74a800275ff6c
+0, 121, 121, 1, 613440, c0d87245a92e7140e6b729c26fe97a95
+0, 122, 122, 1, 613440, 467e33e84435fe64cb14653600ec5163
+0, 123, 123, 1, 613440, 1c7a5b2472c00e9dc63f679b51ead6a9
+0, 124, 124, 1, 613440, 8fb7197463cdae6c45437a73dcb4a3d8
+0, 125, 125, 1, 613440, f352fee36f51536175b05b5ff5a3187a
+0, 126, 126, 1, 613440, ac1ed4392a38268a2495508245032d74
+0, 127, 127, 1, 613440, b8179a306c4fbc6f207d15acaae92dfb
+0, 128, 128, 1, 613440, 7f263b0fd68652d83b75d24cc11c89e8
+0, 129, 129, 1, 613440, 39e33d02a01247cefe19d8bf9fbdecae
+0, 130, 130, 1, 613440, 49a4e89c9fcc66f7e6e679aee4af0852
+0, 131, 131, 1, 613440, 0af52a32e6d74694a0a1f12aa78293fe
+0, 132, 132, 1, 613440, fedde75a5c093ea12f0ed328da7350c9
+0, 133, 133, 1, 613440, 2ab788cf689fdbe8fbc74dde165605ad
+0, 134, 134, 1, 613440, 682c2316cbd2e8a5e54edd1e9309a6c7
+0, 135, 135, 1, 613440, f155e8fa47625f18dffea813a7070c71
+0, 136, 136, 1, 613440, 2611eb2b2da8f6995ac2159012ec540a
+0, 137, 137, 1, 613440, a1130a4ddf7dbd592e23001c4b98b3fc
+0, 138, 138, 1, 613440, 84eef6f47bff223c6a0916c0688d2f7c
+0, 139, 139, 1, 613440, ccfab0b84c7fc59d850ac5cb8d36da41
+0, 140, 140, 1, 613440, 6866845dfb320ecd9c22444ca7e52c8b
+0, 141, 141, 1, 613440, 3068ceb83ee4d047df3880c64754efd7
+0, 142, 142, 1, 613440, 7f9a74e20cfe10972961e7f21529f7f4
+0, 143, 143, 1, 613440, 29156833963ec7f218d38fca7df132bf
+0, 144, 144, 1, 613440, f8feb4c2ae1ce371fc8b4a83d7dc34e0
+0, 145, 145, 1, 613440, 0e5fe8965da239c17b02f0c902feeaec
+0, 146, 146, 1, 613440, e8d37eb1b8c2576658ebc58a7cc6c0d4
+0, 147, 147, 1, 613440, 0a89fd2784112bbd54eb559a8272ab1e
+0, 148, 148, 1, 613440, 342bc99cdd618272d12d045698b9cb20
+0, 149, 149, 1, 613440, a489a32bb43559b8a1989b13660e3cf6
diff --git a/tests/ref/fate/vp9-16-intra-only b/tests/ref/fate/vp9-16-intra-only
new file mode 100644
index 0000000000..5bbfaea80e
--- /dev/null
+++ b/tests/ref/fate/vp9-16-intra-only
@@ -0,0 +1,10 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 12/359
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, d57529601178948afa4818c3c8938884
+0, 1, 1, 1, 152064, d47e00250c45733d64af067a417bcd06
+0, 2, 2, 1, 152064, 984e41cd8350808ac6129746b2377818
+0, 4, 4, 1, 152064, 76ba63001170b8992fc72be5c4ace731
+0, 5, 5, 1, 152064, c4e7f96a8fd58d901b1d881926ddae09
diff --git a/tests/ref/fate/vp9-2pass-akiyo b/tests/ref/fate/vp9-2pass-akiyo
index 5061a76410..2f32092100 100644
--- a/tests/ref/fate/vp9-2pass-akiyo
+++ b/tests/ref/fate/vp9-2pass-akiyo
@@ -1,51 +1,55 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, 043ce065a309514e1e8ebdcbb3c2458b
-0, 33, 33, 0, 152064, 8579c9cffd95b11db86158e518b2e34a
-0, 66, 66, 0, 152064, ebbba105e499604f5e69b8aa48fe86f4
-0, 100, 100, 0, 152064, b08526fab7e106021f9fb9b1e2d4b725
-0, 133, 133, 0, 152064, 92afa561d06f41ccc6d2e2bcc3ab2ee4
-0, 166, 166, 0, 152064, 50de8ec2db66c783289a3982dd1c4f97
-0, 200, 200, 0, 152064, c2ab55d114b8822adef06ccb093b5ac7
-0, 233, 233, 0, 152064, e3ee4edbe8a1f0b5486bbd8a52e7cbcb
-0, 266, 266, 0, 152064, fc33fd50566cd64e5b13911ee06c6e24
-0, 300, 300, 0, 152064, 05297e847f983a19fe2ba5e05932a110
-0, 333, 333, 0, 152064, d21db9adb27be89ab3b7f75d89175e24
-0, 367, 367, 0, 152064, 29bb87bdebd078f8dd953a70def6c4dc
-0, 400, 400, 0, 152064, c57f7bc772f6143a22edaf926f92de5f
-0, 433, 433, 0, 152064, 39f2fc755d4bc2cc5ec077035382be22
-0, 467, 467, 0, 152064, 000ec9c75374f6d74a5e61189e6fd782
-0, 500, 500, 0, 152064, 3027187c9bdb2a755d14513b7e597bb1
-0, 533, 533, 0, 152064, 2b3129659df2b3aa10b9398c50301e00
-0, 567, 567, 0, 152064, e23bcacf1cafca9a7959508b33e63907
-0, 600, 600, 0, 152064, fe0382dd155284998a0d7eb7effb5adf
-0, 633, 633, 0, 152064, e0a487860dd0df3d865971b483fab3e9
-0, 667, 667, 0, 152064, 7ca757c55b0ea4779cdfa3a535f8f234
-0, 700, 700, 0, 152064, 1a276d27f4ce0e2720e25dbed2e524ae
-0, 734, 734, 0, 152064, dd39bc322c8bdce196a9c2129bcb5d6e
-0, 767, 767, 0, 152064, 63e295427977d645462e0fb3277ccb53
-0, 800, 800, 0, 152064, e9a35655c71da22fb0c7865e0bbc91b8
-0, 834, 834, 0, 152064, 5903bcbccabb3366382b37bf08119dde
-0, 867, 867, 0, 152064, 3b6ce09353b07b193914a71ca2334d8c
-0, 900, 900, 0, 152064, cb3731eb5dbe338125c0a7d6b4bf2868
-0, 934, 934, 0, 152064, 0837c62b54912ed06f7f755894ad3f6b
-0, 967, 967, 0, 152064, 7f215dc14d8e280fc18ad3fb3122fa58
-0, 1001, 1001, 0, 152064, 6dafaf5adc45fead74f0153e3764b17d
-0, 1034, 1034, 0, 152064, e19c8274ee6377dbf005f6516a81c413
-0, 1067, 1067, 0, 152064, 358cbf29bd136d2f9dcb60ab82a2e9e5
-0, 1101, 1101, 0, 152064, 2276d4670ff35c3a76c27c3a5810eea3
-0, 1134, 1134, 0, 152064, 636dd3390d4011c377915d7d3acc9ee1
-0, 1167, 1167, 0, 152064, 5e7a1ed17d80168567d61987425f4e60
-0, 1201, 1201, 0, 152064, c10a4830c5f268888789fccd16c0cc0e
-0, 1234, 1234, 0, 152064, 298ef49418d730a031ff23311031c969
-0, 1267, 1267, 0, 152064, 4dd2249e13cda0f99fa46786d345c96a
-0, 1301, 1301, 0, 152064, 24232dbc6e35a069c60422c4c23dfa51
-0, 1334, 1334, 0, 152064, ae8751c5ac168d6aa4499fe69f018ae2
-0, 1368, 1368, 0, 152064, 6a3a7e60a569e7415f2c3a1453e4dc38
-0, 1401, 1401, 0, 152064, 5475af1c118d1b7cc0a357bc434241a8
-0, 1434, 1434, 0, 152064, c6b5ab39e630e66e8f09698fd1dfa160
-0, 1468, 1468, 0, 152064, f1c0310adf115456167e3fa790e43dde
-0, 1501, 1501, 0, 152064, 3028296307b47d10156fc9657693edc3
-0, 1534, 1534, 0, 152064, 0903dabcb8ac707b423b222ac5bb4898
-0, 1568, 1568, 0, 152064, 713cf71b994e2c85ed577062814c5732
-0, 1601, 1601, 0, 152064, 674f56b9cccf5c9d1f88f68c3996a671
-0, 1634, 1634, 0, 152064, f63732c2ff823960d8b62d866dfb5e6a
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, 043ce065a309514e1e8ebdcbb3c2458b
+0, 1, 1, 1, 152064, 8579c9cffd95b11db86158e518b2e34a
+0, 2, 2, 1, 152064, ebbba105e499604f5e69b8aa48fe86f4
+0, 3, 3, 1, 152064, b08526fab7e106021f9fb9b1e2d4b725
+0, 4, 4, 1, 152064, 92afa561d06f41ccc6d2e2bcc3ab2ee4
+0, 5, 5, 1, 152064, 50de8ec2db66c783289a3982dd1c4f97
+0, 6, 6, 1, 152064, c2ab55d114b8822adef06ccb093b5ac7
+0, 7, 7, 1, 152064, e3ee4edbe8a1f0b5486bbd8a52e7cbcb
+0, 8, 8, 1, 152064, fc33fd50566cd64e5b13911ee06c6e24
+0, 9, 9, 1, 152064, 05297e847f983a19fe2ba5e05932a110
+0, 10, 10, 1, 152064, d21db9adb27be89ab3b7f75d89175e24
+0, 11, 11, 1, 152064, 29bb87bdebd078f8dd953a70def6c4dc
+0, 12, 12, 1, 152064, c57f7bc772f6143a22edaf926f92de5f
+0, 13, 13, 1, 152064, 39f2fc755d4bc2cc5ec077035382be22
+0, 14, 14, 1, 152064, 000ec9c75374f6d74a5e61189e6fd782
+0, 15, 15, 1, 152064, 3027187c9bdb2a755d14513b7e597bb1
+0, 16, 16, 1, 152064, 2b3129659df2b3aa10b9398c50301e00
+0, 17, 17, 1, 152064, e23bcacf1cafca9a7959508b33e63907
+0, 18, 18, 1, 152064, fe0382dd155284998a0d7eb7effb5adf
+0, 19, 19, 1, 152064, e0a487860dd0df3d865971b483fab3e9
+0, 20, 20, 1, 152064, 7ca757c55b0ea4779cdfa3a535f8f234
+0, 21, 21, 1, 152064, 1a276d27f4ce0e2720e25dbed2e524ae
+0, 22, 22, 1, 152064, dd39bc322c8bdce196a9c2129bcb5d6e
+0, 23, 23, 1, 152064, 63e295427977d645462e0fb3277ccb53
+0, 24, 24, 1, 152064, e9a35655c71da22fb0c7865e0bbc91b8
+0, 25, 25, 1, 152064, 5903bcbccabb3366382b37bf08119dde
+0, 26, 26, 1, 152064, 3b6ce09353b07b193914a71ca2334d8c
+0, 27, 27, 1, 152064, cb3731eb5dbe338125c0a7d6b4bf2868
+0, 28, 28, 1, 152064, 0837c62b54912ed06f7f755894ad3f6b
+0, 29, 29, 1, 152064, 7f215dc14d8e280fc18ad3fb3122fa58
+0, 30, 30, 1, 152064, 6dafaf5adc45fead74f0153e3764b17d
+0, 31, 31, 1, 152064, e19c8274ee6377dbf005f6516a81c413
+0, 32, 32, 1, 152064, 358cbf29bd136d2f9dcb60ab82a2e9e5
+0, 33, 33, 1, 152064, 2276d4670ff35c3a76c27c3a5810eea3
+0, 34, 34, 1, 152064, 636dd3390d4011c377915d7d3acc9ee1
+0, 35, 35, 1, 152064, 5e7a1ed17d80168567d61987425f4e60
+0, 36, 36, 1, 152064, c10a4830c5f268888789fccd16c0cc0e
+0, 37, 37, 1, 152064, 298ef49418d730a031ff23311031c969
+0, 38, 38, 1, 152064, 4dd2249e13cda0f99fa46786d345c96a
+0, 39, 39, 1, 152064, 24232dbc6e35a069c60422c4c23dfa51
+0, 40, 40, 1, 152064, ae8751c5ac168d6aa4499fe69f018ae2
+0, 41, 41, 1, 152064, 6a3a7e60a569e7415f2c3a1453e4dc38
+0, 42, 42, 1, 152064, 5475af1c118d1b7cc0a357bc434241a8
+0, 43, 43, 1, 152064, c6b5ab39e630e66e8f09698fd1dfa160
+0, 44, 44, 1, 152064, f1c0310adf115456167e3fa790e43dde
+0, 45, 45, 1, 152064, 3028296307b47d10156fc9657693edc3
+0, 46, 46, 1, 152064, 0903dabcb8ac707b423b222ac5bb4898
+0, 47, 47, 1, 152064, 713cf71b994e2c85ed577062814c5732
+0, 48, 48, 1, 152064, 674f56b9cccf5c9d1f88f68c3996a671
+0, 49, 49, 1, 152064, f63732c2ff823960d8b62d866dfb5e6a
diff --git a/tests/ref/fate/vp9-parallelmode-akiyo b/tests/ref/fate/vp9-parallelmode-akiyo
index 097880751f..9668c54c7c 100644
--- a/tests/ref/fate/vp9-parallelmode-akiyo
+++ b/tests/ref/fate/vp9-parallelmode-akiyo
@@ -1,26 +1,30 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, f5bc602db15c69545307e56990f9f9f7
-0, 33, 33, 0, 152064, b56428b6f97669938c8b9b05458fca70
-0, 66, 66, 0, 152064, b56428b6f97669938c8b9b05458fca70
-0, 100, 100, 0, 152064, 3098d2eb9129beddb6975e3ae332a4ab
-0, 133, 133, 0, 152064, 6719f3a6c22f05dc53dd3906e4154bd7
-0, 166, 166, 0, 152064, 8cd9a12761e35f67c278949cd3aee88f
-0, 200, 200, 0, 152064, 8cd9a12761e35f67c278949cd3aee88f
-0, 233, 233, 0, 152064, 0160dec415234d39f148e91f72d264ab
-0, 266, 266, 0, 152064, 9f90d96d67d9e9b3716abe2a3faa854e
-0, 300, 300, 0, 152064, 1edb312f9d0be7835b964a3ffa014759
-0, 333, 333, 0, 152064, 7614fd674609afccacd355aa2f714c75
-0, 367, 367, 0, 152064, cb46868706dd246878bebf354aff66f4
-0, 400, 400, 0, 152064, da36fe96cb4956036f890bb2f6d05b98
-0, 433, 433, 0, 152064, af0a178c68b719b369c8fa8537d38e65
-0, 467, 467, 0, 152064, ff03dbc436376fc60ac240cd6c4fc518
-0, 500, 500, 0, 152064, b0bf25e139556bd9067616db7e4f47b5
-0, 533, 533, 0, 152064, e70d5480c1f82fc877bbe1a8093f807a
-0, 567, 567, 0, 152064, 622fb43e6ff63834f0f680a68b49f6e6
-0, 600, 600, 0, 152064, c331ebba15f2290f174533dbffb3c27b
-0, 633, 633, 0, 152064, 15cb153425c55f7065fb36606c48972e
-0, 667, 667, 0, 152064, b95c7699639c51b08b3615ef7fa7046c
-0, 700, 700, 0, 152064, b4774148c71c9c184bda5a18294e459c
-0, 734, 734, 0, 152064, 795b7ce4c5e0dc343bd8f80ad6c1a454
-0, 767, 767, 0, 152064, 19163601b7b6138e2940cf28f6df6c7f
-0, 800, 800, 0, 152064, b9b388e0892c52df0680a30bfa954506
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, f5bc602db15c69545307e56990f9f9f7
+0, 1, 1, 1, 152064, b56428b6f97669938c8b9b05458fca70
+0, 2, 2, 1, 152064, b56428b6f97669938c8b9b05458fca70
+0, 3, 3, 1, 152064, 3098d2eb9129beddb6975e3ae332a4ab
+0, 4, 4, 1, 152064, 6719f3a6c22f05dc53dd3906e4154bd7
+0, 5, 5, 1, 152064, 8cd9a12761e35f67c278949cd3aee88f
+0, 6, 6, 1, 152064, 8cd9a12761e35f67c278949cd3aee88f
+0, 7, 7, 1, 152064, 0160dec415234d39f148e91f72d264ab
+0, 8, 8, 1, 152064, 9f90d96d67d9e9b3716abe2a3faa854e
+0, 9, 9, 1, 152064, 1edb312f9d0be7835b964a3ffa014759
+0, 10, 10, 1, 152064, 7614fd674609afccacd355aa2f714c75
+0, 11, 11, 1, 152064, cb46868706dd246878bebf354aff66f4
+0, 12, 12, 1, 152064, da36fe96cb4956036f890bb2f6d05b98
+0, 13, 13, 1, 152064, af0a178c68b719b369c8fa8537d38e65
+0, 14, 14, 1, 152064, ff03dbc436376fc60ac240cd6c4fc518
+0, 15, 15, 1, 152064, b0bf25e139556bd9067616db7e4f47b5
+0, 16, 16, 1, 152064, e70d5480c1f82fc877bbe1a8093f807a
+0, 17, 17, 1, 152064, 622fb43e6ff63834f0f680a68b49f6e6
+0, 18, 18, 1, 152064, c331ebba15f2290f174533dbffb3c27b
+0, 19, 19, 1, 152064, 15cb153425c55f7065fb36606c48972e
+0, 20, 20, 1, 152064, b95c7699639c51b08b3615ef7fa7046c
+0, 21, 21, 1, 152064, b4774148c71c9c184bda5a18294e459c
+0, 22, 22, 1, 152064, 795b7ce4c5e0dc343bd8f80ad6c1a454
+0, 23, 23, 1, 152064, 19163601b7b6138e2940cf28f6df6c7f
+0, 24, 24, 1, 152064, b9b388e0892c52df0680a30bfa954506
diff --git a/tests/ref/fate/vp9-segmentation-aq-akiyo b/tests/ref/fate/vp9-segmentation-aq-akiyo
index 2be837a9ed..5c931b6fa6 100644
--- a/tests/ref/fate/vp9-segmentation-aq-akiyo
+++ b/tests/ref/fate/vp9-segmentation-aq-akiyo
@@ -1,26 +1,30 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, b208eac12f0ae74a812bc9e314bdfac7
-0, 33, 33, 0, 152064, ebb2259451c3acf3ad6379d1f4092efb
-0, 66, 66, 0, 152064, 33de46060afd14aa359b7bd0d9ff1be8
-0, 100, 100, 0, 152064, 33de46060afd14aa359b7bd0d9ff1be8
-0, 133, 133, 0, 152064, 5d087d8df10fd406d59172710ea0341a
-0, 166, 166, 0, 152064, 3570ed7fb90ac9b5335b97adf0539e94
-0, 200, 200, 0, 152064, 68a8c56b889a3befc75c9ec4293c7fda
-0, 233, 233, 0, 152064, f871f7c0456f644cfb0ec896132a097f
-0, 266, 266, 0, 152064, 14e939bfeb2b878e0782a7ce68ecd214
-0, 300, 300, 0, 152064, bd3e97881ebece0f876d46d067c6a7ff
-0, 333, 333, 0, 152064, a20529c091ef3e68a901c574371224b3
-0, 367, 367, 0, 152064, 5253f16c8b0329d33d38d275124487fb
-0, 400, 400, 0, 152064, c9c2f7d8835e620709a53ff8adfe72bf
-0, 433, 433, 0, 152064, dc8f1df0d7ab8e4f9daf2ccfd96de855
-0, 467, 467, 0, 152064, d09d43208d4de7f81d54f48cff310b6f
-0, 500, 500, 0, 152064, 0dcf7212075c1f15219690ad6ffe2940
-0, 533, 533, 0, 152064, 3b52e3eb4f972318c6912dd29a95dcf3
-0, 567, 567, 0, 152064, aa1414343067749fbd743ace93553492
-0, 600, 600, 0, 152064, 6951cb7a78e0a03f9a3f6264084de6dc
-0, 633, 633, 0, 152064, 5324f2f03c4d5fe35446561af654e9ec
-0, 667, 667, 0, 152064, dff11b046a02ca34c6b1aecc857632ec
-0, 700, 700, 0, 152064, 971182c013c1524d4864fd946b8c1550
-0, 734, 734, 0, 152064, 3306f1dcd5760ba92dd9cec8bfc21b08
-0, 767, 767, 0, 152064, f1f7b13c33332fece576b4d175f91832
-0, 800, 800, 0, 152064, 9e66573fbfe847149eb32e8a9c242c18
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, b208eac12f0ae74a812bc9e314bdfac7
+0, 1, 1, 1, 152064, ebb2259451c3acf3ad6379d1f4092efb
+0, 2, 2, 1, 152064, 33de46060afd14aa359b7bd0d9ff1be8
+0, 3, 3, 1, 152064, 33de46060afd14aa359b7bd0d9ff1be8
+0, 4, 4, 1, 152064, 5d087d8df10fd406d59172710ea0341a
+0, 5, 5, 1, 152064, 3570ed7fb90ac9b5335b97adf0539e94
+0, 6, 6, 1, 152064, 68a8c56b889a3befc75c9ec4293c7fda
+0, 7, 7, 1, 152064, f871f7c0456f644cfb0ec896132a097f
+0, 8, 8, 1, 152064, 14e939bfeb2b878e0782a7ce68ecd214
+0, 9, 9, 1, 152064, bd3e97881ebece0f876d46d067c6a7ff
+0, 10, 10, 1, 152064, a20529c091ef3e68a901c574371224b3
+0, 11, 11, 1, 152064, 5253f16c8b0329d33d38d275124487fb
+0, 12, 12, 1, 152064, c9c2f7d8835e620709a53ff8adfe72bf
+0, 13, 13, 1, 152064, dc8f1df0d7ab8e4f9daf2ccfd96de855
+0, 14, 14, 1, 152064, d09d43208d4de7f81d54f48cff310b6f
+0, 15, 15, 1, 152064, 0dcf7212075c1f15219690ad6ffe2940
+0, 16, 16, 1, 152064, 3b52e3eb4f972318c6912dd29a95dcf3
+0, 17, 17, 1, 152064, aa1414343067749fbd743ace93553492
+0, 18, 18, 1, 152064, 6951cb7a78e0a03f9a3f6264084de6dc
+0, 19, 19, 1, 152064, 5324f2f03c4d5fe35446561af654e9ec
+0, 20, 20, 1, 152064, dff11b046a02ca34c6b1aecc857632ec
+0, 21, 21, 1, 152064, 971182c013c1524d4864fd946b8c1550
+0, 22, 22, 1, 152064, 3306f1dcd5760ba92dd9cec8bfc21b08
+0, 23, 23, 1, 152064, f1f7b13c33332fece576b4d175f91832
+0, 24, 24, 1, 152064, 9e66573fbfe847149eb32e8a9c242c18
diff --git a/tests/ref/fate/vp9-segmentation-sf-akiyo b/tests/ref/fate/vp9-segmentation-sf-akiyo
index bfef222a42..0fdb3f2620 100644
--- a/tests/ref/fate/vp9-segmentation-sf-akiyo
+++ b/tests/ref/fate/vp9-segmentation-sf-akiyo
@@ -1,26 +1,30 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 152064, f4e04a0f92fab3a52d858bb222807ac0
-0, 33, 33, 0, 152064, 493cb96b8202a1518c6c9bdb848540e4
-0, 66, 66, 0, 152064, 60b5b63f832cff119a43de82102758f4
-0, 100, 100, 0, 152064, 0d9bd42e279d480603f9c670f0a8ffe3
-0, 133, 133, 0, 152064, 25ca563f233688f32f40fec985a116a2
-0, 166, 166, 0, 152064, dd14b43d538708a91de41606703dbe1c
-0, 200, 200, 0, 152064, 01bb23cb43960ff185a97ea79936d3b4
-0, 233, 233, 0, 152064, 85045c4310ee80cd12979bdea4f3f86e
-0, 266, 266, 0, 152064, c8e015ea13359a05483de349313a6686
-0, 300, 300, 0, 152064, 8dbb0406bf6fe19c30a9c9253fcdfe7f
-0, 333, 333, 0, 152064, 84881463643069036d03e8120a5f15e9
-0, 367, 367, 0, 152064, 9abcd3f2f86ff31f8d357389b330df59
-0, 400, 400, 0, 152064, 19ada6395c4e656578d2ceeaba291bb2
-0, 433, 433, 0, 152064, fc29773a6f32eed2bfa44143f8f505b1
-0, 467, 467, 0, 152064, 5e56bd91f5e3d1457c124b5702bdc3b6
-0, 500, 500, 0, 152064, 5b920d73e301adb6c45699a209f09a33
-0, 533, 533, 0, 152064, 4d06ec294270638c6abdd1c2303b34fc
-0, 567, 567, 0, 152064, dc99797067851f74708d7e6ff54367d8
-0, 600, 600, 0, 152064, 5df68b49124219592b043916affb1311
-0, 633, 633, 0, 152064, cfb52d101fad76acb1bb0d48c513bffd
-0, 667, 667, 0, 152064, 206dbd55680b8a83d8bafe33c54c3e36
-0, 700, 700, 0, 152064, 171f2e26771db631788065eecf6c44d9
-0, 734, 734, 0, 152064, b10809dcf9ecfdb4f86a6f3236ac273e
-0, 767, 767, 0, 152064, b354107bdea9bd011b09d9f4a32d4e89
-0, 800, 800, 0, 152064, 0c18be13dc6fbf79a613f2b24bb301c1
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1001/30000
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 152064, f4e04a0f92fab3a52d858bb222807ac0
+0, 1, 1, 1, 152064, 493cb96b8202a1518c6c9bdb848540e4
+0, 2, 2, 1, 152064, 60b5b63f832cff119a43de82102758f4
+0, 3, 3, 1, 152064, 0d9bd42e279d480603f9c670f0a8ffe3
+0, 4, 4, 1, 152064, 25ca563f233688f32f40fec985a116a2
+0, 5, 5, 1, 152064, dd14b43d538708a91de41606703dbe1c
+0, 6, 6, 1, 152064, 01bb23cb43960ff185a97ea79936d3b4
+0, 7, 7, 1, 152064, 85045c4310ee80cd12979bdea4f3f86e
+0, 8, 8, 1, 152064, c8e015ea13359a05483de349313a6686
+0, 9, 9, 1, 152064, 8dbb0406bf6fe19c30a9c9253fcdfe7f
+0, 10, 10, 1, 152064, 84881463643069036d03e8120a5f15e9
+0, 11, 11, 1, 152064, 9abcd3f2f86ff31f8d357389b330df59
+0, 12, 12, 1, 152064, 19ada6395c4e656578d2ceeaba291bb2
+0, 13, 13, 1, 152064, fc29773a6f32eed2bfa44143f8f505b1
+0, 14, 14, 1, 152064, 5e56bd91f5e3d1457c124b5702bdc3b6
+0, 15, 15, 1, 152064, 5b920d73e301adb6c45699a209f09a33
+0, 16, 16, 1, 152064, 4d06ec294270638c6abdd1c2303b34fc
+0, 17, 17, 1, 152064, dc99797067851f74708d7e6ff54367d8
+0, 18, 18, 1, 152064, 5df68b49124219592b043916affb1311
+0, 19, 19, 1, 152064, cfb52d101fad76acb1bb0d48c513bffd
+0, 20, 20, 1, 152064, 206dbd55680b8a83d8bafe33c54c3e36
+0, 21, 21, 1, 152064, 171f2e26771db631788065eecf6c44d9
+0, 22, 22, 1, 152064, b10809dcf9ecfdb4f86a6f3236ac273e
+0, 23, 23, 1, 152064, b354107bdea9bd011b09d9f4a32d4e89
+0, 24, 24, 1, 152064, 0c18be13dc6fbf79a613f2b24bb301c1
diff --git a/tests/ref/fate/vp9-tiling-pedestrian b/tests/ref/fate/vp9-tiling-pedestrian
index 23c760e0a7..2915323e41 100644
--- a/tests/ref/fate/vp9-tiling-pedestrian
+++ b/tests/ref/fate/vp9-tiling-pedestrian
@@ -1,3 +1,7 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/1000
+#stream#, dts, pts, duration, size, hash
0, 0, 0, 0, 3110400, 1e6c2e768a5107e57e6d626f0511193a
0, 40, 40, 0, 3110400, 972d3e2b5ee2e3b0907218a243e4cb7d
diff --git a/tests/ref/fate/vp9-trac3849 b/tests/ref/fate/vp9-trac3849
new file mode 100644
index 0000000000..4d129b3be5
--- /dev/null
+++ b/tests/ref/fate/vp9-trac3849
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/30
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 345600, c2ee30cb4529fcbd61938af1887e2b45
+0, 1, 1, 1, 345600, 946e9bfee03777a07c122df038087d92
+0, 2, 2, 1, 345600, 5dd1916a4bad6e94393f6a50a37c823d
+0, 3, 3, 1, 345600, 2f2760d8dcecc1854fd665892382c3af
+0, 4, 4, 1, 345600, 70418b01ae59e2885457b62b7f416bac
+0, 5, 5, 1, 345600, bda937bb934a6eba193daadccdaa418d
+0, 6, 6, 1, 345600, 8348bbb7c260dec6baa135c8f16348a9
+0, 7, 7, 1, 345600, d45bf60db5f25e774d32975eca01f9c7
+0, 8, 8, 1, 345600, 980e73d96767b2097adf26e0ea31d50e
+0, 9, 9, 1, 345600, 66fda810a9a35f1ce57d6f2351b73c13
diff --git a/tests/ref/fate/vp9-trac4359 b/tests/ref/fate/vp9-trac4359
new file mode 100644
index 0000000000..cd271a79ed
--- /dev/null
+++ b/tests/ref/fate/vp9-trac4359
@@ -0,0 +1,9 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 1382400, 2929e5318edee6cd6b24ede0c1015137
+0, 1, 1, 1, 1382400, ca0d83b04297da33a1aa17129a9fe9c9
+0, 2, 2, 1, 1382400, dfdb277e615307e501f416669a208ff4
+0, 3, 3, 1, 1382400, 9c17c58ea4fc5ff1c3398acbf5cc6c69
diff --git a/tests/ref/fate/vp9p1-04-yuv422 b/tests/ref/fate/vp9p1-04-yuv422
new file mode 100644
index 0000000000..59abfb002c
--- /dev/null
+++ b/tests/ref/fate/vp9p1-04-yuv422
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 28800, b81b8a8444ac6ce4a4807c37e0a44c8b
+0, 1, 1, 1, 28800, 344458b82d35ea9944dc841643fc25c2
+0, 2, 2, 1, 28800, 376a4bb3944f052191963740b980eb26
+0, 3, 3, 1, 28800, 2fecb02c842bd7d588415904f2d3a82d
+0, 4, 4, 1, 28800, 0fda2f1dabba5c179599190f179b9782
+0, 5, 5, 1, 28800, a88ac885ee59e3a3a01fa483cdd40274
+0, 6, 6, 1, 28800, e76b488ffa70a05457fc046e7b999c56
+0, 7, 7, 1, 28800, 74ae5e52162f5bbc95258d44a2dd647c
+0, 8, 8, 1, 28800, 0c017e2b12e5192c8d598941d9c93306
+0, 9, 9, 1, 28800, ca3941ee43b7033cb48f8498af127d53
diff --git a/tests/ref/fate/vp9p1-04-yuv440 b/tests/ref/fate/vp9p1-04-yuv440
new file mode 100644
index 0000000000..0c28f36535
--- /dev/null
+++ b/tests/ref/fate/vp9p1-04-yuv440
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 28800, 61157ad4fb02a254de8f34ae7b8915dc
+0, 1, 1, 1, 28800, 9431337382bf90d40aa417e297ac05da
+0, 2, 2, 1, 28800, 56b739049cc9e97a1d82018bba3db0ee
+0, 3, 3, 1, 28800, 75138a9b6bb905b2f79a1ebb959ddfea
+0, 4, 4, 1, 28800, 141b2fc9625fad86577838d84a276ef8
+0, 5, 5, 1, 28800, b364668c44a237d4e532e086a55401a9
+0, 6, 6, 1, 28800, a4ca6014d5194e4c921a4cb4289eb315
+0, 7, 7, 1, 28800, cfcacb3d5086d3861f4712a3c87a6b6c
+0, 8, 8, 1, 28800, 228d3fd3d849d021f3690cc538edb0a3
+0, 9, 9, 1, 28800, 97ecf281eb1130723d70e3c8803fa814
diff --git a/tests/ref/fate/vp9p1-04-yuv444 b/tests/ref/fate/vp9p1-04-yuv444
new file mode 100644
index 0000000000..e9559c6c6e
--- /dev/null
+++ b/tests/ref/fate/vp9p1-04-yuv444
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/25
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 304128, 859df7b3661783e337a16ee79f3c20bc
+0, 1, 1, 1, 304128, 3b3ccf344cd5a478c4c1fa422497183d
+0, 2, 2, 1, 304128, 3be1f565823cb88013a14a93a3cf9480
+0, 3, 3, 1, 304128, 6e188a963deaf46c2d6e741b03c4240c
+0, 4, 4, 1, 304128, 82ead184ae478ac821b1b4b72f28c9cd
+0, 5, 5, 1, 304128, 59bb43badc76b39a228b1ad96b6339ca
+0, 6, 6, 1, 304128, 2eaee790fc188e2251b92dd4ea90c42a
+0, 7, 7, 1, 304128, 2a95f8727589e710dc1b95400916b72e
+0, 8, 8, 1, 304128, b7032f73544a7108fcdcaca2832ecc32
+0, 9, 9, 1, 304128, b7778c35b30bcc400b25ed0e5b7913e1
diff --git a/tests/ref/fate/vp9p2-20-10bit-yuv420 b/tests/ref/fate/vp9p2-20-10bit-yuv420
new file mode 100644
index 0000000000..297a178bec
--- /dev/null
+++ b/tests/ref/fate/vp9p2-20-10bit-yuv420
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 43200, c3964ed9065de7f839b8d878444c6140
+0, 1, 1, 1, 43200, 87595f7f53d6e84af9708dba72422cc4
+0, 2, 2, 1, 43200, 5cadbce099363a71040919e6f1cec496
+0, 3, 3, 1, 43200, 0e3cab2b26b936de245a94b4128a368f
+0, 4, 4, 1, 43200, 07bde452ca50655717a85cd9fdb3f7ce
+0, 5, 5, 1, 43200, 00bee090fe849fee5fd4eb169c62c897
+0, 6, 6, 1, 43200, 4564a423df89d7e9dea1226873ce9a51
+0, 7, 7, 1, 43200, 7580af6956360112191380a677f5e625
+0, 8, 8, 1, 43200, c9d05c5aadf8a372acfc2c93094d003e
+0, 9, 9, 1, 43200, 6c08ea732cda06cf9a12f2e1a089d401
diff --git a/tests/ref/fate/vp9p2-20-12bit-yuv420 b/tests/ref/fate/vp9p2-20-12bit-yuv420
new file mode 100644
index 0000000000..1ba0094146
--- /dev/null
+++ b/tests/ref/fate/vp9p2-20-12bit-yuv420
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 43200, 8403bd5a381737e1c2d737047f6a5a0b
+0, 1, 1, 1, 43200, 3c0bf7eecc3131e3598f6810d6b70539
+0, 2, 2, 1, 43200, ff020bf894bb88d74426f02a75081695
+0, 3, 3, 1, 43200, 097d81cb29f1caaf4446f3a3de4842d9
+0, 4, 4, 1, 43200, e923a7e7e0349846ba27bd2e6ebdf4df
+0, 5, 5, 1, 43200, 28c6016e6687c7eecbe4057a4dbfe372
+0, 6, 6, 1, 43200, 15ae05537ea7152b535d112871b5ef84
+0, 7, 7, 1, 43200, cb50d043a10a0e9b52eed0e8b3aabc7b
+0, 8, 8, 1, 43200, f97dfbce56e36a42538ef000ce0e937e
+0, 9, 9, 1, 43200, aae42063df910ed31c09eba5f73a195c
diff --git a/tests/ref/fate/vp9p3-20-10bit-yuv422 b/tests/ref/fate/vp9p3-20-10bit-yuv422
new file mode 100644
index 0000000000..5aaf0568cd
--- /dev/null
+++ b/tests/ref/fate/vp9p3-20-10bit-yuv422
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 57600, 18fed3eff623f0308561e5db0bc28691
+0, 1, 1, 1, 57600, 3f22b2269cd53738e955c4b27ff6abce
+0, 2, 2, 1, 57600, d1a44bae5cf45c68c5ca86f9e1ffd6a0
+0, 3, 3, 1, 57600, 6592a5b6f1a8a18930bf27195a836efc
+0, 4, 4, 1, 57600, f1dc8ba72916630aa8ff07f214bd1baf
+0, 5, 5, 1, 57600, 195db6438c313e870ecfe9db3e3cbe83
+0, 6, 6, 1, 57600, ad1cca6689026c31c2350594b669b7e7
+0, 7, 7, 1, 57600, 6cb437a604a714ea746b429cdd68c47f
+0, 8, 8, 1, 57600, cda524f9de8774cc161224c3b81033f5
+0, 9, 9, 1, 57600, a2ae05ae998b4158a32b96e01ed02241
diff --git a/tests/ref/fate/vp9p3-20-10bit-yuv440 b/tests/ref/fate/vp9p3-20-10bit-yuv440
new file mode 100644
index 0000000000..cd3f383cd1
--- /dev/null
+++ b/tests/ref/fate/vp9p3-20-10bit-yuv440
@@ -0,0 +1,25 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 57600, 504a347654ef41e568c484ab017f5387
+0, 1, 1, 1, 57600, 6110f151a39144da5616227d44b81c21
+0, 2, 2, 1, 57600, a856b5e0675c59fb9329d087580c6c5b
+0, 3, 3, 1, 57600, d951b271bf38e7c9b9d215f7a87a079c
+0, 4, 4, 1, 57600, a9e6feb4142a111c74d46cdbac08f2e6
+0, 5, 5, 1, 57600, 4802b599651e7aa35cd52d0dfbfaa4d3
+0, 6, 6, 1, 57600, 1244f3b9da3341057566915e708c7afb
+0, 7, 7, 1, 57600, 212a02d7ee8d56b6f2a4fd7ee6eb3c93
+0, 8, 8, 1, 57600, 1872091be977628ff5435f9186f64a29
+0, 9, 9, 1, 57600, d5255599c33859ee96474a20929dc4bb
+0, 10, 10, 1, 57600, 16d0056501cd1bfc630f6f99672504a0
+0, 11, 11, 1, 57600, 7dcca62c4dc5d508f38376533648bce6
+0, 12, 12, 1, 57600, 1e1617813af32cbf7be3df11d275339e
+0, 13, 13, 1, 57600, 88b036fde717f72485b24e346f55f9dc
+0, 14, 14, 1, 57600, e689287b89b116ec71670ee479e15717
+0, 15, 15, 1, 57600, 211aa3727dcde2d9dfe15d6cebda69e4
+0, 16, 16, 1, 57600, 3037677f680cbdcac242da94717da3ff
+0, 17, 17, 1, 57600, 0138ea9fd279a939df385ea0c97700ca
+0, 18, 18, 1, 57600, 9da47cb99085c352f9e9a07639a9b3cb
+0, 19, 19, 1, 57600, d369f4c840ccb61ce3aaffc77b5f230e
diff --git a/tests/ref/fate/vp9p3-20-10bit-yuv444 b/tests/ref/fate/vp9p3-20-10bit-yuv444
new file mode 100644
index 0000000000..ca218b84a4
--- /dev/null
+++ b/tests/ref/fate/vp9p3-20-10bit-yuv444
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 86400, 06a4c4550dc31f75f842a4e65fc32398
+0, 1, 1, 1, 86400, f7feda15d5c2babc1f6438c72d4900e4
+0, 2, 2, 1, 86400, 5aa9924c0a17c2209b72ba7ec9af6fdd
+0, 3, 3, 1, 86400, 01597451aab5498ba89a7f632cd7d0cf
+0, 4, 4, 1, 86400, 9a42ae17c2744c305895acd911066575
+0, 5, 5, 1, 86400, 17c1d9cda113a3ce2fc7387e2adaa89b
+0, 6, 6, 1, 86400, 6c6e303d282d8e043329eb6b29600cb4
+0, 7, 7, 1, 86400, 97b7d47711222a91dd7ac121df01f922
+0, 8, 8, 1, 86400, 69f305bc0a4a92422b5ebe05a3ac8b38
+0, 9, 9, 1, 86400, a559c738c428c2f895e94a31957eec6b
diff --git a/tests/ref/fate/vp9p3-20-12bit-yuv422 b/tests/ref/fate/vp9p3-20-12bit-yuv422
new file mode 100644
index 0000000000..1a8a83b4fd
--- /dev/null
+++ b/tests/ref/fate/vp9p3-20-12bit-yuv422
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 57600, 442a6d932a163907303f1e08056b33b3
+0, 1, 1, 1, 57600, 80b21954eb522f0140e2226a03062839
+0, 2, 2, 1, 57600, 991251ca3f55879e3ed90d5816bf5056
+0, 3, 3, 1, 57600, 33f1a1aa1a48fda4ef7dccf302c4e7bf
+0, 4, 4, 1, 57600, e9faf81b0664be622040910f29e3d522
+0, 5, 5, 1, 57600, fa9aba755df9f52aa551d942bba5e26f
+0, 6, 6, 1, 57600, ef58938b38ced2fecb8afdb9a6d8024b
+0, 7, 7, 1, 57600, ce43338326c024eb187abaeaa64a44b1
+0, 8, 8, 1, 57600, d487dab8c8b9f690f13569f3d1875a6d
+0, 9, 9, 1, 57600, b4ab8672067ffce5df2daa9a2c2496d2
diff --git a/tests/ref/fate/vp9p3-20-12bit-yuv440 b/tests/ref/fate/vp9p3-20-12bit-yuv440
new file mode 100644
index 0000000000..f6e4cf196e
--- /dev/null
+++ b/tests/ref/fate/vp9p3-20-12bit-yuv440
@@ -0,0 +1,25 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 57600, 9c03fb4aa813522d9a44b3b309b85d19
+0, 1, 1, 1, 57600, 73081beafa17bc23a170172e311c0f54
+0, 2, 2, 1, 57600, 36a1eb7aec96b81d54119e26a5056f48
+0, 3, 3, 1, 57600, 228ca739c96ceb5c63f593790e487a49
+0, 4, 4, 1, 57600, 289e08c01574d23562ce8162b0ec553b
+0, 5, 5, 1, 57600, 76ca62fa4b80bef534e3cb4e37d9f178
+0, 6, 6, 1, 57600, 0d9d5c09c4a453b8b7e04d2904924e15
+0, 7, 7, 1, 57600, b659b38305c3afbbc84f5aab4c373592
+0, 8, 8, 1, 57600, 3f5c87c678c2dc6ffc45ec875920e620
+0, 9, 9, 1, 57600, d758cb908aee57e05af8dd7132ce0973
+0, 10, 10, 1, 57600, 5539bdf8f2cfc09580bd9371c3655989
+0, 11, 11, 1, 57600, 0446cf34d7f1a081e7eef6050cbcb7d8
+0, 12, 12, 1, 57600, 2a29f74bd76f8c2187a0f61ff6935744
+0, 13, 13, 1, 57600, fb4b0e71884069537e3e3e62fbe83877
+0, 14, 14, 1, 57600, 57e19855e60825333fbbd9fdbad54ca0
+0, 15, 15, 1, 57600, 2f111ed5be32c4cbff83efd5530893db
+0, 16, 16, 1, 57600, 87afd9a47e6ee7a71cee99157dd89815
+0, 17, 17, 1, 57600, 72992f2a91f9d91dca5c638d6a2f748c
+0, 18, 18, 1, 57600, ad92cad72adfe2ad43c3be5e3b74439f
+0, 19, 19, 1, 57600, d70f736810724ab968307daf4da1120c
diff --git a/tests/ref/fate/vp9p3-20-12bit-yuv444 b/tests/ref/fate/vp9p3-20-12bit-yuv444
new file mode 100644
index 0000000000..2e5322150d
--- /dev/null
+++ b/tests/ref/fate/vp9p3-20-12bit-yuv444
@@ -0,0 +1,15 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
+#tb 0: 1/50
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 86400, d9500a2c9e0b6b44935de019c3583194
+0, 1, 1, 1, 86400, 58edf3e69b332a2b62ca78a8dc99ea68
+0, 2, 2, 1, 86400, ca8894e8496bf0eec64655972323feb2
+0, 3, 3, 1, 86400, 3473bbb77d10631525a6e7240f6f0c68
+0, 4, 4, 1, 86400, 1bc71b016a90d6a79882bd6b8af0cb23
+0, 5, 5, 1, 86400, ebfbb540587c20586d9ff33adee41f24
+0, 6, 6, 1, 86400, e8bd27ebb53f979232abbb9d18b15085
+0, 7, 7, 1, 86400, 820f65d50b3c48ec600924c0bba90c40
+0, 8, 8, 1, 86400, d8d8588550bc9820eb3289c5684dd7a9
+0, 9, 9, 1, 86400, d8bd25842191e47ac1b342655e7015e6
diff --git a/tests/ref/fate/vqa-cc b/tests/ref/fate/vqa-cc
index d3c5e6a8e1..8950f9428e 100644
--- a/tests/ref/fate/vqa-cc
+++ b/tests/ref/fate/vqa-cc
@@ -3,37 +3,37 @@
0, 1, 1, 1, 192000, 0x00000000
0, 2, 2, 1, 192000, 0x00000000
0, 3, 3, 1, 192000, 0x00000000
-0, 4, 4, 1, 192000, 0xcd900ccc
-0, 5, 5, 1, 192000, 0xfd496438
-0, 6, 6, 1, 192000, 0x965f0bf3
-0, 7, 7, 1, 192000, 0x378fca5f
-0, 8, 8, 1, 192000, 0x5ccd8966
-0, 9, 9, 1, 192000, 0x859676f9
-0, 10, 10, 1, 192000, 0x820bfb1c
-0, 11, 11, 1, 192000, 0x7570cc05
-0, 12, 12, 1, 192000, 0xf38bdb06
-0, 13, 13, 1, 192000, 0x9b0cbb44
-0, 14, 14, 1, 192000, 0x0ed70665
-0, 15, 15, 1, 192000, 0xd16de7fc
-0, 16, 16, 1, 192000, 0x97afb484
-0, 17, 17, 1, 192000, 0x012893f3
-0, 18, 18, 1, 192000, 0x742a4b43
-0, 19, 19, 1, 192000, 0x309dcd75
-0, 20, 20, 1, 192000, 0xed7814ac
-0, 21, 21, 1, 192000, 0xdb7de3d7
-0, 22, 22, 1, 192000, 0xe18679a3
-0, 23, 23, 1, 192000, 0xb1f213f4
-0, 24, 24, 1, 192000, 0x33c99b5c
-0, 25, 25, 1, 192000, 0xf66c0c91
-0, 26, 26, 1, 192000, 0x929cdc73
-0, 27, 27, 1, 192000, 0xa723fc3b
-0, 28, 28, 1, 192000, 0xe6395ccc
-0, 29, 29, 1, 192000, 0x147fbf74
-0, 30, 30, 1, 192000, 0x3ec62d28
-0, 31, 31, 1, 192000, 0x22104ffb
-0, 32, 32, 1, 192000, 0x91f25f58
-0, 33, 33, 1, 192000, 0xc91b0e4e
-0, 34, 34, 1, 192000, 0x4683df56
-0, 35, 35, 1, 192000, 0x8ef8932a
-0, 36, 36, 1, 192000, 0xce6c0ec0
-0, 37, 37, 1, 192000, 0xcc10e2a0
+0, 4, 4, 1, 192000, 0x9ee00ccf
+0, 5, 5, 1, 192000, 0x67256507
+0, 6, 6, 1, 192000, 0x74c70e87
+0, 7, 7, 1, 192000, 0x8ecdce9a
+0, 8, 8, 1, 192000, 0xc40f8efd
+0, 9, 9, 1, 192000, 0xb8107dfb
+0, 10, 10, 1, 192000, 0xb4e504eb
+0, 11, 11, 1, 192000, 0x0c7fdb95
+0, 12, 12, 1, 192000, 0x58c9f045
+0, 13, 13, 1, 192000, 0xcba9d0e9
+0, 14, 14, 1, 192000, 0x392a20f6
+0, 15, 15, 1, 192000, 0xc37905cc
+0, 16, 16, 1, 192000, 0xe278cf95
+0, 17, 17, 1, 192000, 0x3d03b01d
+0, 18, 18, 1, 192000, 0x16a26f28
+0, 19, 19, 1, 192000, 0xdd17f51c
+0, 20, 20, 1, 192000, 0x19703b85
+0, 21, 21, 1, 192000, 0xe51f0e70
+0, 22, 22, 1, 192000, 0x6f94ad2a
+0, 23, 23, 1, 192000, 0x71e449f1
+0, 24, 24, 1, 192000, 0x1dcacc52
+0, 25, 25, 1, 192000, 0x49c23f58
+0, 26, 26, 1, 192000, 0x4ce61551
+0, 27, 27, 1, 192000, 0xe54832d5
+0, 28, 28, 1, 192000, 0xbae28a59
+0, 29, 29, 1, 192000, 0xe8a4efbe
+0, 30, 30, 1, 192000, 0xe9e96883
+0, 31, 31, 1, 192000, 0xa5468c49
+0, 32, 32, 1, 192000, 0x7ec6936a
+0, 33, 33, 1, 192000, 0x46e53ee4
+0, 34, 34, 1, 192000, 0x937b168a
+0, 35, 35, 1, 192000, 0xed76cec4
+0, 36, 36, 1, 192000, 0x4b9f454d
+0, 37, 37, 1, 192000, 0xb58c1566
diff --git a/tests/ref/fate/vqf-demux b/tests/ref/fate/vqf-demux
index 3acae60f5a..3c1dd35955 100644
--- a/tests/ref/fate/vqf-demux
+++ b/tests/ref/fate/vqf-demux
@@ -1 +1 @@
-d72fb75fb22f4bcc94a1dc7af5356ec1
+084a9bf92d4096c8156d1fce50dac8b8
diff --git a/tests/ref/fate/webm-dash-manifest b/tests/ref/fate/webm-dash-manifest
new file mode 100644
index 0000000000..f5fc9121da
--- /dev/null
+++ b/tests/ref/fate/webm-dash-manifest
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT32.501S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+<Period id="0" start="PT0S" duration="PT32.501S" >
+<AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" width="640" height="360" bitstreamSwitching="true" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
+<Representation id="0" bandwidth="302355">
+<BaseURL>dash_video1.webm</BaseURL>
+<SegmentBase
+ indexRange="1115974-1116097">
+<Initialization
+ range="0-441" />
+</SegmentBase>
+</Representation>
+<Representation id="1" bandwidth="302355">
+<BaseURL>dash_video2.webm</BaseURL>
+<SegmentBase
+ indexRange="1115782-1115879">
+<Initialization
+ range="0-249" />
+</SegmentBase>
+</Representation>
+</AdaptationSet>
+<AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="44100" bitstreamSwitching="true" subsegmentAlignment="false" subsegmentStartsWithSAP="1">
+<Representation id="2" bandwidth="82867">
+<BaseURL>dash_audio1.webm</BaseURL>
+<SegmentBase
+ indexRange="335488-335612">
+<Initialization
+ range="0-4103" />
+</SegmentBase>
+</Representation>
+<Representation id="3" bandwidth="82814">
+<BaseURL>dash_audio2.webm</BaseURL>
+<SegmentBase
+ indexRange="335312-335425">
+<Initialization
+ range="0-3927" />
+</SegmentBase>
+</Representation>
+</AdaptationSet>
+</Period>
+</MPD>
diff --git a/tests/ref/fate/webm-dash-manifest-live b/tests/ref/fate/webm-dash-manifest-live
new file mode 100644
index 0000000000..6df7f87cca
--- /dev/null
+++ b/tests/ref/fate/webm-dash-manifest-live
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="dynamic"
+ minBufferTime="PT1S"
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
+ availabilityStartTime=""
+ timeShiftBufferDepth="PT7200S"
+ minimumUpdatePeriod="PT60S">
+<Period id="0" start="PT0S" >
+<AdaptationSet id="0" mimeType="video/webm" codecs="vp9" bitstreamSwitching="true" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
+<ContentComponent id="1" type="video"/>
+<SegmentTemplate timescale="1000" duration="5000" media="dash_live_video_$RepresentationID$_$Number$.chk" startNumber="1" initialization="dash_live_video_$RepresentationID$.hdr"/>
+<Representation id="360" bandwidth="1000000" width="640" height="360" codecs="vp9" mimeType="video/webm" startsWithSAP="1"></Representation>
+</AdaptationSet>
+<AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" bitstreamSwitching="true" subsegmentAlignment="true" subsegmentStartsWithSAP="1">
+<ContentComponent id="1" type="audio"/>
+<SegmentTemplate timescale="1000" duration="5000" media="dash_live_audio_$RepresentationID$_$Number$.chk" startNumber="1" initialization="dash_live_audio_$RepresentationID$.hdr"/>
+<Representation id="171" bandwidth="128000" audioSamplingRate="32000" codecs="vorbis" mimeType="audio/webm" startsWithSAP="1"></Representation>
+</AdaptationSet>
+</Period>
+</MPD>
diff --git a/tests/ref/fate/webm-dash-manifest-representations b/tests/ref/fate/webm-dash-manifest-representations
new file mode 100644
index 0000000000..8556ecebee
--- /dev/null
+++ b/tests/ref/fate/webm-dash-manifest-representations
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT32.48S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+<Period id="0" start="PT0S" duration="PT32.48S" >
+<AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" bitstreamSwitching="true" subsegmentAlignment="false" subsegmentStartsWithSAP="1">
+<Representation id="0" bandwidth="302355" width="640" height="360">
+<BaseURL>dash_video1.webm</BaseURL>
+<SegmentBase
+ indexRange="1115974-1116097">
+<Initialization
+ range="0-441" />
+</SegmentBase>
+</Representation>
+<Representation id="1" bandwidth="243938" width="320" height="240">
+<BaseURL>dash_video4.webm</BaseURL>
+<SegmentBase
+ indexRange="871124-871645">
+<Initialization
+ range="0-437" />
+</SegmentBase>
+</Representation>
+</AdaptationSet>
+</Period>
+</MPD>
diff --git a/tests/ref/fate/webm-dash-manifest-unaligned-audio-streams b/tests/ref/fate/webm-dash-manifest-unaligned-audio-streams
new file mode 100644
index 0000000000..6e9de211fb
--- /dev/null
+++ b/tests/ref/fate/webm-dash-manifest-unaligned-audio-streams
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT32.501S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+<Period id="0" start="PT0S" duration="PT32.501S" >
+<AdaptationSet id="0" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="44100" bitstreamSwitching="false" subsegmentAlignment="false" subsegmentStartsWithSAP="1">
+<Representation id="0" bandwidth="82867">
+<BaseURL>dash_audio1.webm</BaseURL>
+<SegmentBase
+ indexRange="335488-335612">
+<Initialization
+ range="0-4103" />
+</SegmentBase>
+</Representation>
+<Representation id="1" bandwidth="83502">
+<BaseURL>dash_audio3.webm</BaseURL>
+<SegmentBase
+ indexRange="335312-335425">
+<Initialization
+ range="0-3927" />
+</SegmentBase>
+</Representation>
+</AdaptationSet>
+</Period>
+</MPD>
diff --git a/tests/ref/fate/webm-dash-manifest-unaligned-video-streams b/tests/ref/fate/webm-dash-manifest-unaligned-video-streams
new file mode 100644
index 0000000000..ce205638b6
--- /dev/null
+++ b/tests/ref/fate/webm-dash-manifest-unaligned-video-streams
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT32.48S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+<Period id="0" start="PT0S" duration="PT32.48S" >
+<AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" width="640" height="360" bitstreamSwitching="true" subsegmentAlignment="false" subsegmentStartsWithSAP="0">
+<Representation id="0" bandwidth="302355">
+<BaseURL>dash_video1.webm</BaseURL>
+<SegmentBase
+ indexRange="1115974-1116097">
+<Initialization
+ range="0-441" />
+</SegmentBase>
+</Representation>
+<Representation id="1" bandwidth="321574">
+<BaseURL>dash_video3.webm</BaseURL>
+<SegmentBase
+ indexRange="1116070-1116455">
+<Initialization
+ range="0-249" />
+</SegmentBase>
+</Representation>
+</AdaptationSet>
+</Period>
+</MPD>
diff --git a/tests/ref/fate/wmv8-drm b/tests/ref/fate/wmv8-drm
index 7f4b523642..12d8fbb9aa 100644
--- a/tests/ref/fate/wmv8-drm
+++ b/tests/ref/fate/wmv8-drm
@@ -1,130 +1,130 @@
-#tb 0: 1/1000
-0, 0, 0, 0, 84480, 0x7760a00b
-0, 1208, 1208, 0, 84480, 0xfe39a1db
-0, 1250, 1250, 0, 84480, 0xd71961b4
-0, 1291, 1291, 0, 84480, 0xc80dedba
-0, 1333, 1333, 0, 84480, 0x34d8b538
-0, 1375, 1375, 0, 84480, 0x1a86b8e5
-0, 1416, 1416, 0, 84480, 0xabf7c25d
-0, 1458, 1458, 0, 84480, 0x912600ee
-0, 1500, 1500, 0, 84480, 0x7ee7c70b
-0, 1541, 1541, 0, 84480, 0x09c5b0d1
-0, 1583, 1583, 0, 84480, 0x6dbe6c0c
-0, 1625, 1625, 0, 84480, 0x0fe0a120
-0, 1666, 1666, 0, 84480, 0x2352d3a2
-0, 1708, 1708, 0, 84480, 0xb22ce92e
-0, 1750, 1750, 0, 84480, 0x31db0099
-0, 1791, 1791, 0, 84480, 0xad2dd73a
-0, 1833, 1833, 0, 84480, 0xb9af8e20
-0, 1875, 1875, 0, 84480, 0x7b956549
-0, 1916, 1916, 0, 84480, 0x3f774b87
-0, 1958, 1958, 0, 84480, 0x824a23a3
-0, 2000, 2000, 0, 84480, 0x4469a8d8
-0, 2041, 2041, 0, 84480, 0xc80c7a0a
-0, 2083, 2083, 0, 84480, 0xcf958549
-0, 2125, 2125, 0, 84480, 0x449746e3
-0, 2166, 2166, 0, 84480, 0xbac66a82
-0, 2208, 2208, 0, 84480, 0x99e85855
-0, 2250, 2250, 0, 84480, 0xa4a17d17
-0, 2291, 2291, 0, 84480, 0xe29c7587
-0, 2333, 2333, 0, 84480, 0x551de592
-0, 2375, 2375, 0, 84480, 0xe0877bce
-0, 2416, 2416, 0, 84480, 0x9660eb35
-0, 2458, 2458, 0, 84480, 0x0a34b644
-0, 2500, 2500, 0, 84480, 0x352919f0
-0, 2541, 2541, 0, 84480, 0xef56ce27
-0, 2583, 2583, 0, 84480, 0x030fe862
-0, 2625, 2625, 0, 84480, 0x2eba33e2
-0, 2666, 2666, 0, 84480, 0x242de401
-0, 2708, 2708, 0, 84480, 0xbadd61ca
-0, 2750, 2750, 0, 84480, 0x2060465b
-0, 2791, 2791, 0, 84480, 0x256e6965
-0, 2833, 2833, 0, 84480, 0x243b7084
-0, 2875, 2875, 0, 84480, 0x8b3c0b47
-0, 2916, 2916, 0, 84480, 0xc174a9af
-0, 2958, 2958, 0, 84480, 0xb6d48686
-0, 3000, 3000, 0, 84480, 0xa3dd1871
-0, 3041, 3041, 0, 84480, 0x04cdcaf7
-0, 3083, 3083, 0, 84480, 0x55f89c94
-0, 3125, 3125, 0, 84480, 0xda657032
-0, 3166, 3166, 0, 84480, 0x38ba7698
-0, 3208, 3208, 0, 84480, 0x4d03a7f2
-0, 3250, 3250, 0, 84480, 0x115d9035
-0, 3291, 3291, 0, 84480, 0x24c6acc6
-0, 3333, 3333, 0, 84480, 0xdd2bbcae
-0, 3375, 3375, 0, 84480, 0xb4fee0b9
-0, 3416, 3416, 0, 84480, 0xc51c14e0
-0, 3458, 3458, 0, 84480, 0xfb7737de
-0, 3500, 3500, 0, 84480, 0x38675fb0
-0, 3541, 3541, 0, 84480, 0x4752c710
-0, 3583, 3583, 0, 84480, 0xfeb7491b
-0, 3625, 3625, 0, 84480, 0xaa248122
-0, 3666, 3666, 0, 84480, 0x9a4af87c
-0, 3708, 3708, 0, 84480, 0xedcf09df
-0, 3750, 3750, 0, 84480, 0x563a05df
-0, 3791, 3791, 0, 84480, 0x0dde1e03
-0, 3833, 3833, 0, 84480, 0xd8f0ff65
-0, 3875, 3875, 0, 84480, 0xbeb9ae1a
-0, 3916, 3916, 0, 84480, 0x416d1468
-0, 3958, 3958, 0, 84480, 0x66c87d4c
-0, 4000, 4000, 0, 84480, 0xa67c0774
-0, 4041, 4041, 0, 84480, 0xd8f8aec1
-0, 4083, 4083, 0, 84480, 0xadfa502b
-0, 4125, 4125, 0, 84480, 0x50bf20e4
-0, 4166, 4166, 0, 84480, 0xbcb3d8cc
-0, 4208, 4208, 0, 84480, 0xa54677d7
-0, 4250, 4250, 0, 84480, 0x3566042d
-0, 4291, 4291, 0, 84480, 0x4c9eed57
-0, 4333, 4333, 0, 84480, 0xc3b90e58
-0, 4375, 4375, 0, 84480, 0x3c042bfa
-0, 4416, 4416, 0, 84480, 0x19f8e890
-0, 4458, 4458, 0, 84480, 0xd3dacfb9
-0, 4500, 4500, 0, 84480, 0x2365fc6f
-0, 4541, 4541, 0, 84480, 0xa2c19d00
-0, 4583, 4583, 0, 84480, 0xce94336f
-0, 4625, 4625, 0, 84480, 0xfa9bcf14
-0, 4916, 4916, 0, 84480, 0x24d6a243
-0, 4958, 4958, 0, 84480, 0xae1c8854
-0, 5000, 5000, 0, 84480, 0xbb8968bf
-0, 5041, 5041, 0, 84480, 0x6f923623
-0, 5083, 5083, 0, 84480, 0x22e98029
-0, 5125, 5125, 0, 84480, 0x8ac33af3
-0, 5166, 5166, 0, 84480, 0x05947b6e
-0, 5208, 5208, 0, 84480, 0xfc35661a
-0, 5250, 5250, 0, 84480, 0x0e6b6e47
-0, 5291, 5291, 0, 84480, 0x82c764bb
-0, 5333, 5333, 0, 84480, 0x57a36833
-0, 5375, 5375, 0, 84480, 0xc8dd690a
-0, 5416, 5416, 0, 84480, 0x02c47232
-0, 5458, 5458, 0, 84480, 0x6645715d
-0, 5500, 5500, 0, 84480, 0xc64860f7
-0, 5541, 5541, 0, 84480, 0x4f5614b3
-0, 5583, 5583, 0, 84480, 0xa70842ca
-0, 5625, 5625, 0, 84480, 0x379d8458
-0, 5666, 5666, 0, 84480, 0xa14701cf
-0, 5708, 5708, 0, 84480, 0xad1aa2b2
-0, 5750, 5750, 0, 84480, 0xee28f320
-0, 5791, 5791, 0, 84480, 0x505801e9
-0, 5833, 5833, 0, 84480, 0x7947233b
-0, 5875, 5875, 0, 84480, 0x3ce72a9d
-0, 5916, 5916, 0, 84480, 0xa6834e64
-0, 5958, 5958, 0, 84480, 0xfebf4d70
-0, 6000, 6000, 0, 84480, 0x4a0775e2
-0, 6041, 6041, 0, 84480, 0x9d7e945b
-0, 6083, 6083, 0, 84480, 0xaa9eadd9
-0, 6125, 6125, 0, 84480, 0xaa85c9b1
-0, 6166, 6166, 0, 84480, 0xa005edaf
-0, 6208, 6208, 0, 84480, 0x7fc4e5cc
-0, 6250, 6250, 0, 84480, 0xb0f6e8d1
-0, 6291, 6291, 0, 84480, 0x9ef9f330
-0, 6333, 6333, 0, 84480, 0xbe14ff1f
-0, 6375, 6375, 0, 84480, 0xd494048c
-0, 6416, 6416, 0, 84480, 0x046166a7
-0, 6458, 6458, 0, 84480, 0x052a09b2
-0, 6500, 6500, 0, 84480, 0x71fff4ab
-0, 6541, 6541, 0, 84480, 0xb9684e41
-0, 6583, 6583, 0, 84480, 0x1ddce068
-0, 6625, 6625, 0, 84480, 0xb9de300e
-0, 6666, 6666, 0, 84480, 0x13962590
-0, 6708, 6708, 0, 84480, 0xde79482f
-0, 6750, 6750, 0, 84480, 0x7d1ca064
+#tb 0: 1/24
+0, 0, 0, 1, 84480, 0x7760a00b
+0, 29, 29, 1, 84480, 0xfe39a1db
+0, 30, 30, 1, 84480, 0xd71961b4
+0, 31, 31, 1, 84480, 0xc80dedba
+0, 32, 32, 1, 84480, 0x34d8b538
+0, 33, 33, 1, 84480, 0x1a86b8e5
+0, 34, 34, 1, 84480, 0xabf7c25d
+0, 35, 35, 1, 84480, 0x912600ee
+0, 36, 36, 1, 84480, 0x7ee7c70b
+0, 37, 37, 1, 84480, 0x09c5b0d1
+0, 38, 38, 1, 84480, 0x6dbe6c0c
+0, 39, 39, 1, 84480, 0x0fe0a120
+0, 40, 40, 1, 84480, 0x2352d3a2
+0, 41, 41, 1, 84480, 0xb22ce92e
+0, 42, 42, 1, 84480, 0x31db0099
+0, 43, 43, 1, 84480, 0xad2dd73a
+0, 44, 44, 1, 84480, 0xb9af8e20
+0, 45, 45, 1, 84480, 0x7b956549
+0, 46, 46, 1, 84480, 0x3f774b87
+0, 47, 47, 1, 84480, 0x824a23a3
+0, 48, 48, 1, 84480, 0x4469a8d8
+0, 49, 49, 1, 84480, 0xc80c7a0a
+0, 50, 50, 1, 84480, 0xcf958549
+0, 51, 51, 1, 84480, 0x449746e3
+0, 52, 52, 1, 84480, 0xbac66a82
+0, 53, 53, 1, 84480, 0x99e85855
+0, 54, 54, 1, 84480, 0xa4a17d17
+0, 55, 55, 1, 84480, 0xe29c7587
+0, 56, 56, 1, 84480, 0x551de592
+0, 57, 57, 1, 84480, 0xe0877bce
+0, 58, 58, 1, 84480, 0x9660eb35
+0, 59, 59, 1, 84480, 0x0a34b644
+0, 60, 60, 1, 84480, 0x352919f0
+0, 61, 61, 1, 84480, 0xef56ce27
+0, 62, 62, 1, 84480, 0x030fe862
+0, 63, 63, 1, 84480, 0x2eba33e2
+0, 64, 64, 1, 84480, 0x242de401
+0, 65, 65, 1, 84480, 0xbadd61ca
+0, 66, 66, 1, 84480, 0x2060465b
+0, 67, 67, 1, 84480, 0x256e6965
+0, 68, 68, 1, 84480, 0x243b7084
+0, 69, 69, 1, 84480, 0x8b3c0b47
+0, 70, 70, 1, 84480, 0xc174a9af
+0, 71, 71, 1, 84480, 0xb6d48686
+0, 72, 72, 1, 84480, 0xa3dd1871
+0, 73, 73, 1, 84480, 0x04cdcaf7
+0, 74, 74, 1, 84480, 0x55f89c94
+0, 75, 75, 1, 84480, 0xda657032
+0, 76, 76, 1, 84480, 0x38ba7698
+0, 77, 77, 1, 84480, 0x4d03a7f2
+0, 78, 78, 1, 84480, 0x115d9035
+0, 79, 79, 1, 84480, 0x24c6acc6
+0, 80, 80, 1, 84480, 0xdd2bbcae
+0, 81, 81, 1, 84480, 0xb4fee0b9
+0, 82, 82, 1, 84480, 0xc51c14e0
+0, 83, 83, 1, 84480, 0xfb7737de
+0, 84, 84, 1, 84480, 0x38675fb0
+0, 85, 85, 1, 84480, 0x4752c710
+0, 86, 86, 1, 84480, 0xfeb7491b
+0, 87, 87, 1, 84480, 0xaa248122
+0, 88, 88, 1, 84480, 0x9a4af87c
+0, 89, 89, 1, 84480, 0xedcf09df
+0, 90, 90, 1, 84480, 0x563a05df
+0, 91, 91, 1, 84480, 0x0dde1e03
+0, 92, 92, 1, 84480, 0xd8f0ff65
+0, 93, 93, 1, 84480, 0xbeb9ae1a
+0, 94, 94, 1, 84480, 0x416d1468
+0, 95, 95, 1, 84480, 0x66c87d4c
+0, 96, 96, 1, 84480, 0xa67c0774
+0, 97, 97, 1, 84480, 0xd8f8aec1
+0, 98, 98, 1, 84480, 0xadfa502b
+0, 99, 99, 1, 84480, 0x50bf20e4
+0, 100, 100, 1, 84480, 0xbcb3d8cc
+0, 101, 101, 1, 84480, 0xa54677d7
+0, 102, 102, 1, 84480, 0x3566042d
+0, 103, 103, 1, 84480, 0x4c9eed57
+0, 104, 104, 1, 84480, 0xc3b90e58
+0, 105, 105, 1, 84480, 0x3c042bfa
+0, 106, 106, 1, 84480, 0x19f8e890
+0, 107, 107, 1, 84480, 0xd3dacfb9
+0, 108, 108, 1, 84480, 0x2365fc6f
+0, 109, 109, 1, 84480, 0xa2c19d00
+0, 110, 110, 1, 84480, 0xce94336f
+0, 111, 111, 1, 84480, 0xfa9bcf14
+0, 118, 118, 1, 84480, 0x24d6a243
+0, 119, 119, 1, 84480, 0xae1c8854
+0, 120, 120, 1, 84480, 0xbb8968bf
+0, 121, 121, 1, 84480, 0x6f923623
+0, 122, 122, 1, 84480, 0x22e98029
+0, 123, 123, 1, 84480, 0x8ac33af3
+0, 124, 124, 1, 84480, 0x05947b6e
+0, 125, 125, 1, 84480, 0xfc35661a
+0, 126, 126, 1, 84480, 0x0e6b6e47
+0, 127, 127, 1, 84480, 0x82c764bb
+0, 128, 128, 1, 84480, 0x57a36833
+0, 129, 129, 1, 84480, 0xc8dd690a
+0, 130, 130, 1, 84480, 0x02c47232
+0, 131, 131, 1, 84480, 0x6645715d
+0, 132, 132, 1, 84480, 0xc64860f7
+0, 133, 133, 1, 84480, 0x4f5614b3
+0, 134, 134, 1, 84480, 0xa70842ca
+0, 135, 135, 1, 84480, 0x379d8458
+0, 136, 136, 1, 84480, 0xa14701cf
+0, 137, 137, 1, 84480, 0xad1aa2b2
+0, 138, 138, 1, 84480, 0xee28f320
+0, 139, 139, 1, 84480, 0x505801e9
+0, 140, 140, 1, 84480, 0x7947233b
+0, 141, 141, 1, 84480, 0x3ce72a9d
+0, 142, 142, 1, 84480, 0xa6834e64
+0, 143, 143, 1, 84480, 0xfebf4d70
+0, 144, 144, 1, 84480, 0x4a0775e2
+0, 145, 145, 1, 84480, 0x9d7e945b
+0, 146, 146, 1, 84480, 0xaa9eadd9
+0, 147, 147, 1, 84480, 0xaa85c9b1
+0, 148, 148, 1, 84480, 0xa005edaf
+0, 149, 149, 1, 84480, 0x7fc4e5cc
+0, 150, 150, 1, 84480, 0xb0f6e8d1
+0, 151, 151, 1, 84480, 0x9ef9f330
+0, 152, 152, 1, 84480, 0xbe14ff1f
+0, 153, 153, 1, 84480, 0xd494048c
+0, 154, 154, 1, 84480, 0x046166a7
+0, 155, 155, 1, 84480, 0x052a09b2
+0, 156, 156, 1, 84480, 0x71fff4ab
+0, 157, 157, 1, 84480, 0xb9684e41
+0, 158, 158, 1, 84480, 0x1ddce068
+0, 159, 159, 1, 84480, 0xb9de300e
+0, 160, 160, 1, 84480, 0x13962590
+0, 161, 161, 1, 84480, 0xde79482f
+0, 162, 162, 1, 84480, 0x7d1ca064
diff --git a/tests/ref/fate/wmv8-drm-nodec b/tests/ref/fate/wmv8-drm-nodec
index d6bf15eb6b..279c8b66ae 100644
--- a/tests/ref/fate/wmv8-drm-nodec
+++ b/tests/ref/fate/wmv8-drm-nodec
@@ -1,3 +1,5 @@
+#extradata 0: 4, 0x021800a2
+#extradata 1: 46, 0x63d9043a
#tb 0: 1/1000
#tb 1: 1/1000
0, 0, 0, 0, 282, 0x000d949a
@@ -5,148 +7,148 @@
1, 435, 435, 0, 1088, 0x8dfa1368
1, 740, 740, 0, 1088, 0xc0d211be
1, 1023, 1023, 0, 1088, 0x8238113a
-0, 1208, 1208, 0, 137, 0x903c415e
-0, 1250, 1250, 0, 942, 0xd5b7d2aa
-0, 1291, 1291, 0, 841, 0xaffd8ce6
+0, 1208, 1208, 0, 137, 0x903c415e, F=0x0
+0, 1250, 1250, 0, 942, 0xd5b7d2aa, F=0x0
+0, 1291, 1291, 0, 841, 0xaffd8ce6, F=0x0
1, 1306, 1306, 0, 1088, 0x9f8924b7
-0, 1333, 1333, 0, 1164, 0x4ed84836
-0, 1375, 1375, 0, 1492, 0x37f3e8aa
-0, 1416, 1416, 0, 1663, 0xc091392d
-0, 1458, 1458, 0, 1443, 0x6162c718
-0, 1500, 1500, 0, 1721, 0x7bdb3dd0
-0, 1541, 1541, 0, 1410, 0xde689881
-0, 1583, 1583, 0, 1258, 0xb5b86920
+0, 1333, 1333, 0, 1164, 0x4ed84836, F=0x0
+0, 1375, 1375, 0, 1492, 0x37f3e8aa, F=0x0
+0, 1416, 1416, 0, 1663, 0xc091392d, F=0x0
+0, 1458, 1458, 0, 1443, 0x6162c718, F=0x0
+0, 1500, 1500, 0, 1721, 0x7bdb3dd0, F=0x0
+0, 1541, 1541, 0, 1410, 0xde689881, F=0x0
+0, 1583, 1583, 0, 1258, 0xb5b86920, F=0x0
1, 1589, 1589, 0, 1088, 0x767f317a
-0, 1625, 1625, 0, 2050, 0x99b6d7c7
-0, 1666, 1666, 0, 1242, 0x9ba35009
-0, 1708, 1708, 0, 1630, 0x17f10192
-0, 1750, 1750, 0, 1747, 0xbbee59d7
-0, 1791, 1791, 0, 1565, 0xb09b00d9
-0, 1833, 1833, 0, 1573, 0xd2e62201
+0, 1625, 1625, 0, 2050, 0x99b6d7c7, F=0x0
+0, 1666, 1666, 0, 1242, 0x9ba35009, F=0x0
+0, 1708, 1708, 0, 1630, 0x17f10192, F=0x0
+0, 1750, 1750, 0, 1747, 0xbbee59d7, F=0x0
+0, 1791, 1791, 0, 1565, 0xb09b00d9, F=0x0
+0, 1833, 1833, 0, 1573, 0xd2e62201, F=0x0
1, 1872, 1872, 0, 1088, 0x57000d38
-0, 1875, 1875, 0, 1353, 0x2305a24d
-0, 1916, 1916, 0, 1425, 0xf41bbb46
-0, 1958, 1958, 0, 1355, 0xfc08a762
-0, 2000, 2000, 0, 1363, 0x98cda71d
-0, 2041, 2041, 0, 1547, 0x8742f11f
-0, 2083, 2083, 0, 1967, 0x43d61723
-0, 2125, 2125, 0, 1378, 0xde22c753
-0, 2166, 2166, 0, 961, 0x2418a4da
+0, 1875, 1875, 0, 1353, 0x2305a24d, F=0x0
+0, 1916, 1916, 0, 1425, 0xf41bbb46, F=0x0
+0, 1958, 1958, 0, 1355, 0xfc08a762, F=0x0
+0, 2000, 2000, 0, 1363, 0x98cda71d, F=0x0
+0, 2041, 2041, 0, 1547, 0x8742f11f, F=0x0
+0, 2083, 2083, 0, 1967, 0x43d61723, F=0x0
+0, 2125, 2125, 0, 1378, 0xde22c753, F=0x0
+0, 2166, 2166, 0, 961, 0x2418a4da, F=0x0
1, 2198, 2198, 0, 1088, 0xad977261
-0, 2208, 2208, 0, 968, 0x0d04ba51
-0, 2250, 2250, 0, 1140, 0x737f3543
-0, 2291, 2291, 0, 1119, 0x3c050388
-0, 2333, 2333, 0, 1078, 0xeac8d981
-0, 2375, 2375, 0, 1113, 0xebfa0314
-0, 2416, 2416, 0, 1229, 0x95dc3cb5
-0, 2458, 2458, 0, 1311, 0x8a6f5bda
-0, 2500, 2500, 0, 1270, 0x2e66540a
-0, 2541, 2541, 0, 1408, 0x5f489779
-0, 2583, 2583, 0, 1359, 0x8bd085f5
-0, 2625, 2625, 0, 1428, 0xef9ba480
-0, 2666, 2666, 0, 1179, 0x5bb221a8
-0, 2708, 2708, 0, 1108, 0x9a6019a8
-0, 2750, 2750, 0, 1205, 0xccba4d22
-0, 2791, 2791, 0, 1306, 0xde708c19
-0, 2833, 2833, 41, 1724, 0xa70b521e
-0, 2875, 2875, 41, 1336, 0xdf3974b9
-0, 2916, 2916, 41, 1259, 0x1f6b4307
-0, 2958, 2958, 41, 1194, 0x635f5a43
-0, 3000, 3000, 41, 1183, 0x1dd47115
-0, 3041, 3041, 41, 1126, 0x5bac3cc8
-0, 3083, 3083, 41, 1360, 0x1fe2d981
-0, 3125, 3125, 41, 1261, 0x34288acb
-0, 3166, 3166, 41, 1250, 0x26bd72b3
-0, 3208, 3208, 41, 1147, 0x02e81ba0
-0, 3250, 3250, 41, 1368, 0xb8146962
-0, 3291, 3291, 41, 1377, 0xf7b6ce65
-0, 3333, 3333, 41, 1396, 0x88467dee
-0, 3375, 3375, 41, 1408, 0x5585c25c
-0, 3416, 3416, 41, 1551, 0x42002c8d
-0, 3458, 3458, 41, 1524, 0xbcb609e3
+0, 2208, 2208, 0, 968, 0x0d04ba51, F=0x0
+0, 2250, 2250, 0, 1140, 0x737f3543, F=0x0
+0, 2291, 2291, 0, 1119, 0x3c050388, F=0x0
+0, 2333, 2333, 0, 1078, 0xeac8d981, F=0x0
+0, 2375, 2375, 0, 1113, 0xebfa0314, F=0x0
+0, 2416, 2416, 0, 1229, 0x95dc3cb5, F=0x0
+0, 2458, 2458, 0, 1311, 0x8a6f5bda, F=0x0
+0, 2500, 2500, 0, 1270, 0x2e66540a, F=0x0
+0, 2541, 2541, 0, 1408, 0x5f489779, F=0x0
+0, 2583, 2583, 0, 1359, 0x8bd085f5, F=0x0
+0, 2625, 2625, 0, 1428, 0xef9ba480, F=0x0
+0, 2666, 2666, 0, 1179, 0x5bb221a8, F=0x0
+0, 2708, 2708, 0, 1108, 0x9a6019a8, F=0x0
+0, 2750, 2750, 0, 1205, 0xccba4d22, F=0x0
+0, 2791, 2791, 0, 1306, 0xde708c19, F=0x0
+0, 2833, 2833, 0, 1724, 0xa70b521e, F=0x0
+0, 2875, 2875, 41, 1336, 0xdf3974b9, F=0x0
+0, 2916, 2916, 41, 1259, 0x1f6b4307, F=0x0
+0, 2958, 2958, 41, 1194, 0x635f5a43, F=0x0
+0, 3000, 3000, 41, 1183, 0x1dd47115, F=0x0
+0, 3041, 3041, 41, 1126, 0x5bac3cc8, F=0x0
+0, 3083, 3083, 41, 1360, 0x1fe2d981, F=0x0
+0, 3125, 3125, 41, 1261, 0x34288acb, F=0x0
+0, 3166, 3166, 41, 1250, 0x26bd72b3, F=0x0
+0, 3208, 3208, 41, 1147, 0x02e81ba0, F=0x0
+0, 3250, 3250, 41, 1368, 0xb8146962, F=0x0
+0, 3291, 3291, 41, 1377, 0xf7b6ce65, F=0x0
+0, 3333, 3333, 41, 1396, 0x88467dee, F=0x0
+0, 3375, 3375, 41, 1408, 0x5585c25c, F=0x0
+0, 3416, 3416, 41, 1551, 0x42002c8d, F=0x0
+0, 3458, 3458, 41, 1524, 0xbcb609e3, F=0x0
1, 3482, 3482, 0, 1088, 0xdce57471
-0, 3500, 3500, 41, 1554, 0x3d740564
-0, 3541, 3541, 41, 1467, 0xc349f2d7
-0, 3583, 3583, 41, 1066, 0xb7401462
-0, 3625, 3625, 41, 1502, 0x3ee602ed
-0, 3666, 3666, 41, 1148, 0xba463637
-0, 3708, 3708, 41, 1351, 0x5e85ae79
-0, 3750, 3750, 41, 1187, 0xed8d6055
-0, 3791, 3791, 41, 1200, 0x64185be6
-0, 3833, 3833, 41, 1175, 0x12ad3c1e
-0, 3875, 3875, 41, 1179, 0x7e034570
-0, 3916, 3916, 41, 1136, 0x5c633c51
+0, 3500, 3500, 41, 1554, 0x3d740564, F=0x0
+0, 3541, 3541, 41, 1467, 0xc349f2d7, F=0x0
+0, 3583, 3583, 41, 1066, 0xb7401462, F=0x0
+0, 3625, 3625, 41, 1502, 0x3ee602ed, F=0x0
+0, 3666, 3666, 41, 1148, 0xba463637, F=0x0
+0, 3708, 3708, 41, 1351, 0x5e85ae79, F=0x0
+0, 3750, 3750, 41, 1187, 0xed8d6055, F=0x0
+0, 3791, 3791, 41, 1200, 0x64185be6, F=0x0
+0, 3833, 3833, 41, 1175, 0x12ad3c1e, F=0x0
+0, 3875, 3875, 41, 1179, 0x7e034570, F=0x0
+0, 3916, 3916, 41, 1136, 0x5c633c51, F=0x0
1, 3918, 3918, 0, 1088, 0xf3887977
-0, 3958, 3958, 41, 1064, 0x5eb51d89
-0, 4000, 4000, 41, 953, 0xe148bbdd
-0, 4041, 4041, 41, 989, 0x901ec306
-0, 4083, 4083, 41, 1030, 0x680de26f
-0, 4125, 4125, 41, 1078, 0x86e0ee43
-0, 4166, 4166, 41, 1232, 0x98546a86
-0, 4208, 4208, 41, 1164, 0x93305074
-0, 4250, 4250, 41, 1348, 0x27cfa91b
-0, 4291, 4291, 41, 1417, 0x2312d70e
-0, 4333, 4333, 41, 1285, 0x46ca4cca
+0, 3958, 3958, 41, 1064, 0x5eb51d89, F=0x0
+0, 4000, 4000, 41, 953, 0xe148bbdd, F=0x0
+0, 4041, 4041, 41, 989, 0x901ec306, F=0x0
+0, 4083, 4083, 41, 1030, 0x680de26f, F=0x0
+0, 4125, 4125, 41, 1078, 0x86e0ee43, F=0x0
+0, 4166, 4166, 41, 1232, 0x98546a86, F=0x0
+0, 4208, 4208, 41, 1164, 0x93305074, F=0x0
+0, 4250, 4250, 41, 1348, 0x27cfa91b, F=0x0
+0, 4291, 4291, 41, 1417, 0x2312d70e, F=0x0
+0, 4333, 4333, 41, 1285, 0x46ca4cca, F=0x0
1, 4353, 4353, 0, 1088, 0x1d6c8ed2
-0, 4375, 4375, 41, 1037, 0xcf09dd3d
-0, 4416, 4416, 41, 1005, 0xe780cf1f
-0, 4458, 4458, 41, 890, 0x8b1d8c1b
-0, 4500, 4500, 41, 1023, 0xd1dbd506
-0, 4541, 4541, 41, 803, 0x935e775e
-0, 4583, 4583, 41, 1035, 0x6a220483
-0, 4625, 4625, 41, 466, 0xd88bb237
+0, 4375, 4375, 41, 1037, 0xcf09dd3d, F=0x0
+0, 4416, 4416, 41, 1005, 0xe780cf1f, F=0x0
+0, 4458, 4458, 41, 890, 0x8b1d8c1b, F=0x0
+0, 4500, 4500, 41, 1023, 0xd1dbd506, F=0x0
+0, 4541, 4541, 41, 803, 0x935e775e, F=0x0
+0, 4583, 4583, 41, 1035, 0x6a220483, F=0x0
+0, 4625, 4625, 41, 466, 0xd88bb237, F=0x0
1, 4789, 4789, 0, 1088, 0x09115bae
-0, 4916, 4916, 41, 945, 0x8f2eb1ec
+0, 4916, 4916, 41, 945, 0x8f2eb1ec, F=0x0
0, 4958, 4958, 41, 1190, 0x4c451c1b
-0, 5000, 5000, 41, 1811, 0x727c52cb
-0, 5041, 5041, 41, 1552, 0x73f82bff
-0, 5083, 5083, 41, 1544, 0xa7241ece
-0, 5125, 5125, 41, 1707, 0x3d1a6464
-0, 5166, 5166, 41, 1103, 0x06b22710
-0, 5208, 5208, 41, 1122, 0x656725b8
+0, 5000, 5000, 41, 1811, 0x727c52cb, F=0x0
+0, 5041, 5041, 41, 1552, 0x73f82bff, F=0x0
+0, 5083, 5083, 41, 1544, 0xa7241ece, F=0x0
+0, 5125, 5125, 41, 1707, 0x3d1a6464, F=0x0
+0, 5166, 5166, 41, 1103, 0x06b22710, F=0x0
+0, 5208, 5208, 41, 1122, 0x656725b8, F=0x0
1, 5224, 5224, 0, 1088, 0x0c8b9372
-0, 5250, 5250, 41, 1150, 0xf9674678
-0, 5291, 5291, 41, 1438, 0x03fac426
-0, 5333, 5333, 41, 1623, 0x7adb1321
-0, 5375, 5375, 41, 1677, 0x0b9a3e62
-0, 5416, 5416, 41, 1124, 0x769c0ea2
-0, 5458, 5458, 41, 1221, 0xd942409f
-0, 5500, 5500, 41, 1698, 0xd7ca3fe3
-0, 5541, 5541, 41, 1262, 0xb994692f
-0, 5583, 5583, 41, 2097, 0xf4eb663f
-0, 5625, 5625, 41, 1251, 0xfd4f633a
+0, 5250, 5250, 41, 1150, 0xf9674678, F=0x0
+0, 5291, 5291, 41, 1438, 0x03fac426, F=0x0
+0, 5333, 5333, 41, 1623, 0x7adb1321, F=0x0
+0, 5375, 5375, 41, 1677, 0x0b9a3e62, F=0x0
+0, 5416, 5416, 41, 1124, 0x769c0ea2, F=0x0
+0, 5458, 5458, 41, 1221, 0xd942409f, F=0x0
+0, 5500, 5500, 41, 1698, 0xd7ca3fe3, F=0x0
+0, 5541, 5541, 41, 1262, 0xb994692f, F=0x0
+0, 5583, 5583, 41, 2097, 0xf4eb663f, F=0x0
+0, 5625, 5625, 41, 1251, 0xfd4f633a, F=0x0
1, 5659, 5659, 0, 1088, 0x75a82540
-0, 5666, 5666, 41, 1633, 0xb7e1290e
-0, 5708, 5708, 41, 1739, 0xecd18c38
-0, 5750, 5750, 41, 1132, 0xc83e1828
-0, 5791, 5791, 41, 825, 0xdd02867c
-0, 5833, 5833, 41, 903, 0x349ba205
-0, 5875, 5875, 41, 1013, 0x1366ec2a
-0, 5916, 5916, 41, 1340, 0xeaa2a231
-0, 5958, 5958, 41, 1102, 0x82de2889
-0, 6000, 6000, 41, 1834, 0x59b99b92
+0, 5666, 5666, 41, 1633, 0xb7e1290e, F=0x0
+0, 5708, 5708, 41, 1739, 0xecd18c38, F=0x0
+0, 5750, 5750, 41, 1132, 0xc83e1828, F=0x0
+0, 5791, 5791, 41, 825, 0xdd02867c, F=0x0
+0, 5833, 5833, 41, 903, 0x349ba205, F=0x0
+0, 5875, 5875, 41, 1013, 0x1366ec2a, F=0x0
+0, 5916, 5916, 41, 1340, 0xeaa2a231, F=0x0
+0, 5958, 5958, 41, 1102, 0x82de2889, F=0x0
+0, 6000, 6000, 41, 1834, 0x59b99b92, F=0x0
1, 6008, 6008, 0, 1088, 0x690312b0
-0, 6041, 6041, 41, 1332, 0x0610813a
-0, 6083, 6083, 41, 1275, 0x5b0d7be7
-0, 6125, 6125, 41, 1376, 0xd915b0fe
-0, 6166, 6166, 41, 1417, 0x8606b34a
-0, 6208, 6208, 41, 1360, 0x3bcd93d3
-0, 6250, 6250, 41, 1330, 0xd0439c93
-0, 6291, 6291, 41, 1562, 0xb2560a09
+0, 6041, 6041, 41, 1332, 0x0610813a, F=0x0
+0, 6083, 6083, 41, 1275, 0x5b0d7be7, F=0x0
+0, 6125, 6125, 41, 1376, 0xd915b0fe, F=0x0
+0, 6166, 6166, 41, 1417, 0x8606b34a, F=0x0
+0, 6208, 6208, 41, 1360, 0x3bcd93d3, F=0x0
+0, 6250, 6250, 41, 1330, 0xd0439c93, F=0x0
+0, 6291, 6291, 41, 1562, 0xb2560a09, F=0x0
1, 6312, 6312, 0, 1088, 0x76d50ff3
-0, 6333, 6333, 41, 1376, 0x4f9eb447
-0, 6375, 6375, 41, 1405, 0x85d3b084
-0, 6416, 6416, 41, 1344, 0xcdbda2ae
-0, 6458, 6458, 41, 1313, 0xe3067b35
-0, 6500, 6500, 41, 1459, 0xf9d2c56f
-0, 6541, 6541, 41, 1275, 0xf5536d81
-0, 6583, 6583, 41, 1209, 0x3b5b4ea5
+0, 6333, 6333, 41, 1376, 0x4f9eb447, F=0x0
+0, 6375, 6375, 41, 1405, 0x85d3b084, F=0x0
+0, 6416, 6416, 41, 1344, 0xcdbda2ae, F=0x0
+0, 6458, 6458, 41, 1313, 0xe3067b35, F=0x0
+0, 6500, 6500, 41, 1459, 0xf9d2c56f, F=0x0
+0, 6541, 6541, 41, 1275, 0xf5536d81, F=0x0
+0, 6583, 6583, 41, 1209, 0x3b5b4ea5, F=0x0
1, 6595, 6595, 0, 1088, 0x8766276f
-0, 6625, 6625, 41, 1352, 0x7b199d28
-0, 6666, 6666, 41, 1349, 0x02adaaf3
-0, 6708, 6708, 41, 1464, 0x20d7cfd2
-0, 6750, 6750, 41, 1377, 0x78e0b1f4
-0, 6791, 6791, 41, 289, 0x1f2e9246
+0, 6625, 6625, 41, 1352, 0x7b199d28, F=0x0
+0, 6666, 6666, 41, 1349, 0x02adaaf3, F=0x0
+0, 6708, 6708, 41, 1464, 0x20d7cfd2, F=0x0
+0, 6750, 6750, 41, 1377, 0x78e0b1f4, F=0x0
+0, 6791, 6791, 41, 289, 0x1f2e9246, F=0x0
1, 6878, 6878, 0, 1088, 0x678f20fd
1, 7161, 7161, 0, 1088, 0x718afa20
1, 7444, 7444, 0, 1088, 0x758f0939
diff --git a/tests/ref/fate/wmv8-x8intra b/tests/ref/fate/wmv8-x8intra
new file mode 100644
index 0000000000..1f75ce2bc6
--- /dev/null
+++ b/tests/ref/fate/wmv8-x8intra
@@ -0,0 +1,474 @@
+#tb 0: 1/15
+0, 0, 0, 1, 115200, 0x03fbd838
+0, 3, 3, 1, 115200, 0x8911d86f
+0, 4, 4, 1, 115200, 0x7c5dd82e
+0, 5, 5, 1, 115200, 0x7c5ed82e
+0, 30, 30, 1, 115200, 0xd323d838
+0, 31, 31, 1, 115200, 0x6e7479ab
+0, 32, 32, 1, 115200, 0x14674bf6
+0, 33, 33, 1, 115200, 0x074c2e3d
+0, 34, 34, 1, 115200, 0x9b3025ef
+0, 35, 35, 1, 115200, 0x76882dae
+0, 36, 36, 1, 115200, 0xedf3421b
+0, 37, 37, 1, 115200, 0xb5378486
+0, 38, 38, 1, 115200, 0xc4a53420
+0, 39, 39, 1, 115200, 0x559cb60f
+0, 40, 40, 1, 115200, 0xcc034ddd
+0, 41, 41, 1, 115200, 0xb77b7779
+0, 42, 42, 1, 115200, 0x0ad9c3e6
+0, 43, 43, 1, 115200, 0x4e673027
+0, 44, 44, 1, 115200, 0x54717979
+0, 45, 45, 1, 115200, 0xf9e557c9
+0, 46, 46, 1, 115200, 0xefad6344
+0, 47, 47, 1, 115200, 0x07497ba3
+0, 48, 48, 1, 115200, 0xabef71d3
+0, 49, 49, 1, 115200, 0x5b8f5802
+0, 50, 50, 1, 115200, 0x8b920b76
+0, 51, 51, 1, 115200, 0xb93f0f04
+0, 52, 52, 1, 115200, 0xa31b18c0
+0, 53, 53, 1, 115200, 0x9116235b
+0, 54, 54, 1, 115200, 0xe54b1d0b
+0, 55, 55, 1, 115200, 0x35e7252a
+0, 56, 56, 1, 115200, 0x2cae31d5
+0, 57, 57, 1, 115200, 0x28493c57
+0, 58, 58, 1, 115200, 0xd8a445b5
+0, 59, 59, 1, 115200, 0xbf854c55
+0, 60, 60, 1, 115200, 0x3761555c
+0, 61, 61, 1, 115200, 0x07a35c8a
+0, 62, 62, 1, 115200, 0x848c6eb0
+0, 63, 63, 1, 115200, 0x8d7c77d1
+0, 64, 64, 1, 115200, 0x903980b7
+0, 65, 65, 1, 115200, 0xbd30898c
+0, 66, 66, 1, 115200, 0x31f78d25
+0, 67, 67, 1, 115200, 0x308aa19d
+0, 68, 68, 1, 115200, 0xf185948c
+0, 69, 69, 1, 115200, 0x8aeea0b9
+0, 70, 70, 1, 115200, 0x06669545
+0, 71, 71, 1, 115200, 0x4d3e84d7
+0, 72, 72, 1, 115200, 0x80007e9c
+0, 73, 73, 1, 115200, 0x7cad6ea5
+0, 74, 74, 1, 115200, 0xd5d747f6
+0, 75, 75, 1, 115200, 0xeddb43bf
+0, 76, 76, 1, 115200, 0x2d3c30b5
+0, 77, 77, 1, 115200, 0x7b465872
+0, 78, 78, 1, 115200, 0xd144b461
+0, 79, 79, 1, 115200, 0x36b0053e
+0, 80, 80, 1, 115200, 0xdf90ec64
+0, 81, 81, 1, 115200, 0xb59cecc6
+0, 82, 82, 1, 115200, 0x0469ed52
+0, 83, 83, 1, 115200, 0x2d7cf7cb
+0, 84, 84, 1, 115200, 0x8376bf2c
+0, 85, 85, 1, 115200, 0xd79dbd1e
+0, 86, 86, 1, 115200, 0xbc79996d
+0, 87, 87, 1, 115200, 0x524d0a62
+0, 88, 88, 1, 115200, 0x07798f44
+0, 89, 89, 1, 115200, 0xd8b85d49
+0, 90, 90, 1, 115200, 0x54126d07
+0, 91, 91, 1, 115200, 0x0346f350
+0, 92, 92, 1, 115200, 0x0feada4f
+0, 93, 93, 1, 115200, 0x74243c65
+0, 94, 94, 1, 115200, 0xbce280c8
+0, 95, 95, 1, 115200, 0xe9bc40c7
+0, 96, 96, 1, 115200, 0x72ecea21
+0, 97, 97, 1, 115200, 0xb4c32a43
+0, 98, 98, 1, 115200, 0x428a6276
+0, 99, 99, 1, 115200, 0xf67f9364
+0, 100, 100, 1, 115200, 0xf25e8858
+0, 101, 101, 1, 115200, 0x9739b909
+0, 102, 102, 1, 115200, 0x8a1b8f38
+0, 103, 103, 1, 115200, 0xe4a2cff1
+0, 104, 104, 1, 115200, 0xa800b83f
+0, 105, 105, 1, 115200, 0xa88e00d0
+0, 106, 106, 1, 115200, 0x5786082e
+0, 107, 107, 1, 115200, 0xc7205eeb
+0, 108, 108, 1, 115200, 0x9ad02d6b
+0, 109, 109, 1, 115200, 0x5314185d
+0, 110, 110, 1, 115200, 0x015b6351
+0, 111, 111, 1, 115200, 0x51a5c2e1
+0, 112, 112, 1, 115200, 0xc232ec26
+0, 113, 113, 1, 115200, 0x35b30ffc
+0, 114, 114, 1, 115200, 0x2b947acd
+0, 115, 115, 1, 115200, 0xcf1a7971
+0, 116, 116, 1, 115200, 0x70055748
+0, 117, 117, 1, 115200, 0x774b61e6
+0, 118, 118, 1, 115200, 0x74da78a7
+0, 119, 119, 1, 115200, 0x13b5523c
+0, 120, 120, 1, 115200, 0xe27050a0
+0, 121, 121, 1, 115200, 0x073156b0
+0, 122, 122, 1, 115200, 0x9a3662d4
+0, 123, 123, 1, 115200, 0x8c90139c
+0, 124, 124, 1, 115200, 0x45cdeb08
+0, 125, 125, 1, 115200, 0x046ff217
+0, 126, 126, 1, 115200, 0xa6b0a863
+0, 127, 127, 1, 115200, 0xa9c2427a
+0, 128, 128, 1, 115200, 0x7d478df1
+0, 129, 129, 1, 115200, 0x9f426504
+0, 130, 130, 1, 115200, 0x89723d89
+0, 131, 131, 1, 115200, 0x851dd023
+0, 132, 132, 1, 115200, 0xe6ed007d
+0, 133, 133, 1, 115200, 0xfe5cb08d
+0, 134, 134, 1, 115200, 0xc96e52bd
+0, 135, 135, 1, 115200, 0x15c5ffe8
+0, 136, 136, 1, 115200, 0x54540656
+0, 137, 137, 1, 115200, 0xa5e8dbec
+0, 138, 138, 1, 115200, 0x35edde29
+0, 139, 139, 1, 115200, 0xbbb6cb36
+0, 140, 140, 1, 115200, 0x59c5ed50
+0, 141, 141, 1, 115200, 0x7e8a497a
+0, 142, 142, 1, 115200, 0x16586d33
+0, 143, 143, 1, 115200, 0x19dfd6e6
+0, 144, 144, 1, 115200, 0x7ea8574a
+0, 145, 145, 1, 115200, 0x58567b44
+0, 146, 146, 1, 115200, 0x0d2d049e
+0, 147, 147, 1, 115200, 0x7c2d7b00
+0, 148, 148, 1, 115200, 0x92debda6
+0, 149, 149, 1, 115200, 0x1e4cfcc1
+0, 150, 150, 1, 115200, 0xf58b742e
+0, 151, 151, 1, 115200, 0xc2089e8b
+0, 152, 152, 1, 115200, 0x1b4f01e8
+0, 153, 153, 1, 115200, 0x113b1e76
+0, 154, 154, 1, 115200, 0x0f154b48
+0, 155, 155, 1, 115200, 0xf82f5795
+0, 156, 156, 1, 115200, 0xa9f68f5c
+0, 157, 157, 1, 115200, 0xd37992fa
+0, 158, 158, 1, 115200, 0x5e08b0ad
+0, 159, 159, 1, 115200, 0xacf77f50
+0, 160, 160, 1, 115200, 0x4a37945b
+0, 161, 161, 1, 115200, 0x9d2670b7
+0, 162, 162, 1, 115200, 0x7f7e5d76
+0, 163, 163, 1, 115200, 0x357d3ec3
+0, 164, 164, 1, 115200, 0xe4622287
+0, 165, 165, 1, 115200, 0x95260aa6
+0, 166, 166, 1, 115200, 0xff87049a
+0, 167, 167, 1, 115200, 0x5b91c76b
+0, 168, 168, 1, 115200, 0xe5fca44c
+0, 169, 169, 1, 115200, 0xccc46ee1
+0, 170, 170, 1, 115200, 0x0aec53e8
+0, 171, 171, 1, 115200, 0x7509537f
+0, 172, 172, 1, 115200, 0xd6516a81
+0, 173, 173, 1, 115200, 0xbc14562b
+0, 174, 174, 1, 115200, 0xe3f9619e
+0, 175, 175, 1, 115200, 0x2cbe35ef
+0, 176, 176, 1, 115200, 0xd78a40b9
+0, 177, 177, 1, 115200, 0x2cfa08cd
+0, 178, 178, 1, 115200, 0x3ece09fe
+0, 179, 179, 1, 115200, 0xc445d43a
+0, 180, 180, 1, 115200, 0xe1cbacdd
+0, 181, 181, 1, 115200, 0x7a03b421
+0, 182, 182, 1, 115200, 0x7c80ab27
+0, 183, 183, 1, 115200, 0xececae60
+0, 184, 184, 1, 115200, 0xef00c6b3
+0, 185, 185, 1, 115200, 0xcdc9e78d
+0, 186, 186, 1, 115200, 0xa5170dd1
+0, 187, 187, 1, 115200, 0xfe561e1f
+0, 188, 188, 1, 115200, 0xc5d056f9
+0, 189, 189, 1, 115200, 0xf0267284
+0, 190, 190, 1, 115200, 0xcdc4a09a
+0, 191, 191, 1, 115200, 0xa8c8af40
+0, 192, 192, 1, 115200, 0x0c0cc987
+0, 193, 193, 1, 115200, 0x13a0cc64
+0, 194, 194, 1, 115200, 0x0ff3e6fe
+0, 195, 195, 1, 115200, 0x7fbfe852
+0, 196, 196, 1, 115200, 0x62ea0273
+0, 197, 197, 1, 115200, 0x8d021330
+0, 198, 198, 1, 115200, 0x7ac6321a
+0, 199, 199, 1, 115200, 0xefc92de8
+0, 200, 200, 1, 115200, 0x4be95c24
+0, 201, 201, 1, 115200, 0xf62c79b0
+0, 202, 202, 1, 115200, 0x1d9f85c6
+0, 203, 203, 1, 115200, 0x13b6ad8f
+0, 204, 204, 1, 115200, 0x3d96e451
+0, 205, 205, 1, 115200, 0x0891f3c4
+0, 206, 206, 1, 115200, 0xc728f8cd
+0, 207, 207, 1, 115200, 0x9481ee74
+0, 208, 208, 1, 115200, 0xaf95fcf9
+0, 209, 209, 1, 115200, 0x856fe48d
+0, 210, 210, 1, 115200, 0x5b9c03da
+0, 211, 211, 1, 115200, 0x98f80228
+0, 212, 212, 1, 115200, 0xa4e52148
+0, 213, 213, 1, 115200, 0x65bc4b91
+0, 214, 214, 1, 115200, 0x0c166312
+0, 215, 215, 1, 115200, 0x4657a356
+0, 216, 216, 1, 115200, 0xf17e0003
+0, 217, 217, 1, 115200, 0x95a81738
+0, 218, 218, 1, 115200, 0xb02d6bd9
+0, 219, 219, 1, 115200, 0x2594e89d
+0, 220, 220, 1, 115200, 0x5c4a1349
+0, 221, 221, 1, 115200, 0xbc9d5875
+0, 222, 222, 1, 115200, 0xd935b307
+0, 223, 223, 1, 115200, 0x2114cb84
+0, 224, 224, 1, 115200, 0xbe58130c
+0, 225, 225, 1, 115200, 0x7a3d2b2b
+0, 226, 226, 1, 115200, 0xe5753e6b
+0, 227, 227, 1, 115200, 0xc84042cc
+0, 228, 228, 1, 115200, 0x98ef4c58
+0, 229, 229, 1, 115200, 0x2cb83bff
+0, 230, 230, 1, 115200, 0x4e58433a
+0, 231, 231, 1, 115200, 0x7ec26734
+0, 232, 232, 1, 115200, 0x49168d07
+0, 233, 233, 1, 115200, 0xfc9e82f2
+0, 234, 234, 1, 115200, 0x49976c26
+0, 235, 235, 1, 115200, 0xa12466ff
+0, 236, 236, 1, 115200, 0x98ae6499
+0, 237, 237, 1, 115200, 0xc8575e78
+0, 238, 238, 1, 115200, 0xc6596cd2
+0, 239, 239, 1, 115200, 0x83d9a068
+0, 240, 240, 1, 115200, 0xe819b560
+0, 241, 241, 1, 115200, 0xb07ac3c3
+0, 242, 242, 1, 115200, 0x3d79ef5b
+0, 243, 243, 1, 115200, 0xbc6800e0
+0, 244, 244, 1, 115200, 0xc78c15f8
+0, 245, 245, 1, 115200, 0xcb91360b
+0, 246, 246, 1, 115200, 0x6c657143
+0, 247, 247, 1, 115200, 0x636391d1
+0, 248, 248, 1, 115200, 0xb519e49d
+0, 249, 249, 1, 115200, 0xb65d00c5
+0, 250, 250, 1, 115200, 0x14672ba8
+0, 251, 251, 1, 115200, 0xb65d389f
+0, 252, 252, 1, 115200, 0xe88e991b
+0, 253, 253, 1, 115200, 0x6a7bad4e
+0, 254, 254, 1, 115200, 0xd305eca1
+0, 255, 255, 1, 115200, 0x8cdbe729
+0, 256, 256, 1, 115200, 0x0d1bfd9a
+0, 257, 257, 1, 115200, 0xef740a06
+0, 258, 258, 1, 115200, 0x1cd423df
+0, 259, 259, 1, 115200, 0xf78616ba
+0, 260, 260, 1, 115200, 0xcc0b2b81
+0, 261, 261, 1, 115200, 0x434e4ae9
+0, 262, 262, 1, 115200, 0xf2d461ec
+0, 263, 263, 1, 115200, 0xc75f6a15
+0, 264, 264, 1, 115200, 0x71038c87
+0, 265, 265, 1, 115200, 0x7a55ab55
+0, 266, 266, 1, 115200, 0xeef2e1de
+0, 267, 267, 1, 115200, 0xd2600c3d
+0, 268, 268, 1, 115200, 0xdd872452
+0, 269, 269, 1, 115200, 0xd1361fcd
+0, 270, 270, 1, 115200, 0xda4f0d12
+0, 271, 271, 1, 115200, 0xba061920
+0, 272, 272, 1, 115200, 0x4b2ef9ed
+0, 273, 273, 1, 115200, 0x11dfab08
+0, 274, 274, 1, 115200, 0x7a603fc2
+0, 275, 275, 1, 115200, 0x61690ad9
+0, 276, 276, 1, 115200, 0x481ac8b9
+0, 277, 277, 1, 115200, 0xea35570d
+0, 278, 278, 1, 115200, 0xdd306f19
+0, 279, 279, 1, 115200, 0x3f975f1b
+0, 280, 280, 1, 115200, 0x2386cd1f
+0, 281, 281, 1, 115200, 0x1b77f573
+0, 282, 282, 1, 115200, 0x8ce213de
+0, 283, 283, 1, 115200, 0x5f7407c6
+0, 284, 284, 1, 115200, 0x01b3ee00
+0, 285, 285, 1, 115200, 0x92759715
+0, 286, 286, 1, 115200, 0x4a208e1e
+0, 287, 287, 1, 115200, 0x6e1b80a5
+0, 288, 288, 1, 115200, 0x298c7621
+0, 289, 289, 1, 115200, 0x0e255da8
+0, 290, 290, 1, 115200, 0xabd661ca
+0, 291, 291, 1, 115200, 0x6f045226
+0, 292, 292, 1, 115200, 0x396a5e4c
+0, 293, 293, 1, 115200, 0x4bd53915
+0, 294, 294, 1, 115200, 0xaf9631b3
+0, 295, 295, 1, 115200, 0xb2602290
+0, 296, 296, 1, 115200, 0xb1272f1b
+0, 297, 297, 1, 115200, 0xe8d23699
+0, 298, 298, 1, 115200, 0xd6e2558d
+0, 299, 299, 1, 115200, 0xf1270106
+0, 300, 300, 1, 115200, 0x6ab1fc4f
+0, 301, 301, 1, 115200, 0x4a9b5c6f
+0, 302, 302, 1, 115200, 0x14177b61
+0, 303, 303, 1, 115200, 0x8f7f7971
+0, 304, 304, 1, 115200, 0x165973cd
+0, 305, 305, 1, 115200, 0x341c4ba5
+0, 306, 306, 1, 115200, 0x08df3902
+0, 307, 307, 1, 115200, 0x4c1e386a
+0, 308, 308, 1, 115200, 0x1b1c387c
+0, 309, 309, 1, 115200, 0xe42fdb83
+0, 310, 310, 1, 115200, 0x5bb2ad2e
+0, 311, 311, 1, 115200, 0x31924902
+0, 312, 312, 1, 115200, 0x5a290e9a
+0, 313, 313, 1, 115200, 0x15d6ea45
+0, 314, 314, 1, 115200, 0xb5adc34d
+0, 315, 315, 1, 115200, 0xb210a956
+0, 316, 316, 1, 115200, 0x79478dac
+0, 317, 317, 1, 115200, 0x626a3fa9
+0, 318, 318, 1, 115200, 0x6b0e370d
+0, 319, 319, 1, 115200, 0x1f1113ec
+0, 320, 320, 1, 115200, 0x362efa10
+0, 321, 321, 1, 115200, 0xca8de637
+0, 322, 322, 1, 115200, 0x432e1f19
+0, 323, 323, 1, 115200, 0xa2c93031
+0, 324, 324, 1, 115200, 0x63294fcc
+0, 325, 325, 1, 115200, 0x1c1d5928
+0, 326, 326, 1, 115200, 0xe5fb45ea
+0, 327, 327, 1, 115200, 0x0712cc77
+0, 328, 328, 1, 115200, 0xaef1c94b
+0, 329, 329, 1, 115200, 0x30c8a84e
+0, 330, 330, 1, 115200, 0xd6896b75
+0, 331, 331, 1, 115200, 0x7f8839cb
+0, 332, 332, 1, 115200, 0xcd69d7d4
+0, 333, 333, 1, 115200, 0xa6f3cdaa
+0, 334, 334, 1, 115200, 0xccbdc609
+0, 335, 335, 1, 115200, 0x2d3f77d7
+0, 336, 336, 1, 115200, 0x18f8582d
+0, 337, 337, 1, 115200, 0xe88717bb
+0, 338, 338, 1, 115200, 0xb42fd44b
+0, 339, 339, 1, 115200, 0x7edaa5b7
+0, 340, 340, 1, 115200, 0xef399a7b
+0, 341, 341, 1, 115200, 0x11d75f35
+0, 342, 342, 1, 115200, 0xc0717b78
+0, 343, 343, 1, 115200, 0x9aebc04d
+0, 344, 344, 1, 115200, 0x44c705fc
+0, 345, 345, 1, 115200, 0xd322add3
+0, 346, 346, 1, 115200, 0x0f5f0b79
+0, 347, 347, 1, 115200, 0x54a15070
+0, 348, 348, 1, 115200, 0xd11553df
+0, 349, 349, 1, 115200, 0x6f3ed910
+0, 350, 350, 1, 115200, 0x6d3a3c17
+0, 351, 351, 1, 115200, 0x434ebc13
+0, 352, 352, 1, 115200, 0xcf07ecb2
+0, 353, 353, 1, 115200, 0x1c94497e
+0, 354, 354, 1, 115200, 0x83c13cbc
+0, 355, 355, 1, 115200, 0x4a8ba4f5
+0, 356, 356, 1, 115200, 0x922a393f
+0, 357, 357, 1, 115200, 0x44024959
+0, 358, 358, 1, 115200, 0x23f18ebd
+0, 359, 359, 1, 115200, 0x2cdf1146
+0, 360, 360, 1, 115200, 0x8a7d402c
+0, 361, 361, 1, 115200, 0x42d67bb3
+0, 362, 362, 1, 115200, 0x7045ff2c
+0, 363, 363, 1, 115200, 0xb67a4f15
+0, 364, 364, 1, 115200, 0x7481f311
+0, 365, 365, 1, 115200, 0xe394ff8d
+0, 366, 366, 1, 115200, 0x2ca16f23
+0, 367, 367, 1, 115200, 0xd53238e1
+0, 368, 368, 1, 115200, 0xe28a80c9
+0, 369, 369, 1, 115200, 0x043ccd51
+0, 370, 370, 1, 115200, 0x2e950d80
+0, 371, 371, 1, 115200, 0xf7394c6e
+0, 372, 372, 1, 115200, 0xae46d2c8
+0, 373, 373, 1, 115200, 0x4b54df85
+0, 374, 374, 1, 115200, 0x636f4ca5
+0, 375, 375, 1, 115200, 0x2c687754
+0, 376, 376, 1, 115200, 0x0ddea0f9
+0, 377, 377, 1, 115200, 0x82b08dfd
+0, 378, 378, 1, 115200, 0x5db58c25
+0, 379, 379, 1, 115200, 0x9b975eaa
+0, 380, 380, 1, 115200, 0x2cbe4bf1
+0, 381, 381, 1, 115200, 0xc8873bd7
+0, 382, 382, 1, 115200, 0x9aa357f2
+0, 383, 383, 1, 115200, 0x526e5392
+0, 384, 384, 1, 115200, 0x30aa5d18
+0, 385, 385, 1, 115200, 0x1fe738b4
+0, 386, 386, 1, 115200, 0x9cec04ad
+0, 387, 387, 1, 115200, 0x3ddd922d
+0, 388, 388, 1, 115200, 0xc6578bbb
+0, 389, 389, 1, 115200, 0x413c35ae
+0, 390, 390, 1, 115200, 0x90095ab3
+0, 391, 391, 1, 115200, 0x8ae84371
+0, 392, 392, 1, 115200, 0x1c935404
+0, 393, 393, 1, 115200, 0x213f37e8
+0, 394, 394, 1, 115200, 0x19ab39e6
+0, 395, 395, 1, 115200, 0x795bf82f
+0, 396, 396, 1, 115200, 0xe238fccf
+0, 397, 397, 1, 115200, 0xe2c0d69e
+0, 398, 398, 1, 115200, 0xa1e9d34c
+0, 399, 399, 1, 115200, 0xedf3d303
+0, 400, 400, 1, 115200, 0x40fac156
+0, 401, 401, 1, 115200, 0x1bc59ddb
+0, 402, 402, 1, 115200, 0x4295a2ab
+0, 403, 403, 1, 115200, 0xc337809d
+0, 404, 404, 1, 115200, 0x4a329996
+0, 405, 405, 1, 115200, 0xb4fa76b4
+0, 406, 406, 1, 115200, 0xb49b7d18
+0, 407, 407, 1, 115200, 0xfab67262
+0, 408, 408, 1, 115200, 0x31919404
+0, 409, 409, 1, 115200, 0x983d896c
+0, 410, 410, 1, 115200, 0x8594939e
+0, 411, 411, 1, 115200, 0x9fb8932a
+0, 412, 412, 1, 115200, 0xb9f3af07
+0, 413, 413, 1, 115200, 0x5904c5b4
+0, 414, 414, 1, 115200, 0xf6e095d6
+0, 415, 415, 1, 115200, 0xd168bd86
+0, 416, 416, 1, 115200, 0x39151a63
+0, 417, 417, 1, 115200, 0x9e426f6d
+0, 418, 418, 1, 115200, 0x0c6d7d1d
+0, 419, 419, 1, 115200, 0x65f787ca
+0, 420, 420, 1, 115200, 0xf42288c6
+0, 421, 421, 1, 115200, 0x565b8d91
+0, 422, 422, 1, 115200, 0xd72e882f
+0, 423, 423, 1, 115200, 0x8def886c
+0, 424, 424, 1, 115200, 0x1d5e7800
+0, 425, 425, 1, 115200, 0x628276f7
+0, 426, 426, 1, 115200, 0x00e27d0f
+0, 427, 427, 1, 115200, 0x52df7737
+0, 428, 428, 1, 115200, 0xf98f6303
+0, 429, 429, 1, 115200, 0x9a2d2d65
+0, 430, 430, 1, 115200, 0xd8cb25f5
+0, 431, 431, 1, 115200, 0x68071ce1
+0, 432, 432, 1, 115200, 0x4c6218c9
+0, 433, 433, 1, 115200, 0xaf0a11a3
+0, 434, 434, 1, 115200, 0xfa0a0fb9
+0, 435, 435, 1, 115200, 0xc61414fb
+0, 436, 436, 1, 115200, 0x3a8b0e94
+0, 437, 437, 1, 115200, 0x1eab0e92
+0, 438, 438, 1, 115200, 0xc726028c
+0, 439, 439, 1, 115200, 0x2da2f5de
+0, 440, 440, 1, 115200, 0x7672e92f
+0, 441, 441, 1, 115200, 0x7edae686
+0, 442, 442, 1, 115200, 0x9a6ce3c6
+0, 443, 443, 1, 115200, 0x9f69e74c
+0, 444, 444, 1, 115200, 0x73fbf502
+0, 445, 445, 1, 115200, 0xff81f5b8
+0, 446, 446, 1, 115200, 0x2b8bf7de
+0, 447, 447, 1, 115200, 0xcd00f380
+0, 448, 448, 1, 115200, 0x4cedfe7c
+0, 449, 449, 1, 115200, 0xcd30fbb4
+0, 450, 450, 1, 115200, 0x4b7df228
+0, 451, 451, 1, 115200, 0xedc7e5df
+0, 452, 452, 1, 115200, 0x687ae0f5
+0, 453, 453, 1, 115200, 0x8127e2b9
+0, 454, 454, 1, 115200, 0xe31ae11c
+0, 455, 455, 1, 115200, 0xece5e5c5
+0, 456, 456, 1, 115200, 0x4f1bdfe4
+0, 457, 457, 1, 115200, 0x65c5dfe3
+0, 458, 458, 1, 115200, 0xfc89d51f
+0, 459, 459, 1, 115200, 0xedd1c6bc
+0, 460, 460, 1, 115200, 0x2913d073
+0, 461, 461, 1, 115200, 0xf196fbbe
+0, 462, 462, 1, 115200, 0xc0be13e1
+0, 463, 463, 1, 115200, 0x55b21f01
+0, 464, 464, 1, 115200, 0xb16b2364
+0, 465, 465, 1, 115200, 0x4a8632db
+0, 466, 466, 1, 115200, 0x44c94426
+0, 467, 467, 1, 115200, 0xe5470b01
+0, 468, 468, 1, 115200, 0xd895d5d0
+0, 469, 469, 1, 115200, 0xe98715c2
+0, 470, 470, 1, 115200, 0x2688599b
+0, 471, 471, 1, 115200, 0x8e4889aa
+0, 472, 472, 1, 115200, 0x658bcd8d
+0, 473, 473, 1, 115200, 0xf0090c06
+0, 474, 474, 1, 115200, 0xefd9bd28
+0, 475, 475, 1, 115200, 0x45009bb4
+0, 476, 476, 1, 115200, 0x7ebd1655
+0, 477, 477, 1, 115200, 0x64ff7898
+0, 478, 478, 1, 115200, 0x4a9384f1
+0, 479, 479, 1, 115200, 0xd80f0701
+0, 480, 480, 1, 115200, 0x2f855116
+0, 481, 481, 1, 115200, 0x0c1313cb
+0, 482, 482, 1, 115200, 0xf4df4d19
+0, 483, 483, 1, 115200, 0xde6218fb
+0, 484, 484, 1, 115200, 0xce26e6b4
+0, 485, 485, 1, 115200, 0x848af931
+0, 486, 486, 1, 115200, 0x86770a97
+0, 487, 487, 1, 115200, 0x8f35c3c0
+0, 488, 488, 1, 115200, 0xb26dc220
+0, 489, 489, 1, 115200, 0x3d5bbfce
+0, 490, 490, 1, 115200, 0xa1f9bee6
+0, 491, 491, 1, 115200, 0xa87dcd24
+0, 492, 492, 1, 115200, 0x9374cb71
+0, 493, 493, 1, 115200, 0x0c7ccbd0
+0, 494, 494, 1, 115200, 0x9a16cc49
+0, 495, 495, 1, 115200, 0x4df0c28b
+0, 496, 496, 1, 115200, 0xb5b8b866
+0, 497, 497, 1, 115200, 0xafcc1019
+0, 510, 510, 1, 115200, 0x623b0ff3
diff --git a/tests/ref/fate/wtv-demux b/tests/ref/fate/wtv-demux
index bdd6c20b42..904d78b068 100644
--- a/tests/ref/fate/wtv-demux
+++ b/tests/ref/fate/wtv-demux
@@ -1,3 +1,5 @@
+#extradata 0: 86, 0xc7ca09e5
+#extradata 1: 22, 0x12dc010c
#tb 0: 1/10000000
#tb 1: 1/10000000
1, -2, -2, 240000, 576, 0x9b6e1638
@@ -33,109 +35,109 @@
1, 7199998, 7199998, 240000, 576, 0xeb4b0d93
1, 7439998, 7439998, 240000, 576, 0xde1322f5
1, 7679998, 7679998, 240000, 576, 0xc3131f35
-0, 7886331, 9486442, 400000, 41980, 0xd4920915
1, 7919998, 7919998, 240000, 576, 0x708f1381
1, 8159998, 8159998, 240000, 576, 0x1f00137e
+0, 8286442, 9486442, 400000, 41980, 0xd4920915
1, 8399998, 8399998, 240000, 576, 0x05131eb0
1, 8639998, 8639998, 240000, 576, 0x78151c22
-0, 8686442, 8686442, 400000, 7228, 0x1b141fa3
+0, 8686442, 8686442, 400000, 7228, 0x1b141fa3, F=0x0
1, 8879998, 8879998, 240000, 576, 0x31771239
-0, 9086331, 9086331, 400000, 7492, 0x1a47f3e4
+0, 9086331, 9086331, 400000, 7492, 0x1a47f3e4, F=0x0
1, 9119998, 9119998, 240000, 576, 0x3ce4097c
1, 9359998, 9359998, 240000, 576, 0x180e15f4
-0, 9486442, 10686331, 400000, 25068, 0xcb70a744
+0, 9486442, 10686331, 400000, 25068, 0xcb70a744, F=0x0
1, 9599998, 9599998, 240000, 576, 0x30db0604
1, 9839998, 9839998, 240000, 576, 0x9b290284
-0, 9886442, 9886442, 400000, 7212, 0x0ab9f558
+0, 9886442, 9886442, 400000, 7212, 0x0ab9f558, F=0x0
1, 10079998, 10079998, 240000, 576, 0xcf340753
-0, 10286442, 10286442, 400000, 7612, 0xa93054f0
+0, 10286442, 10286442, 400000, 7612, 0xa93054f0, F=0x0
1, 10319998, 10319998, 240000, 576, 0xdaa41457
1, 10559998, 10559998, 240000, 576, 0x34d310a2
-0, 10686331, 11886331, 400000, 22868, 0xa77db64a
+0, 10686331, 11886331, 400000, 22868, 0xa77db64a, F=0x0
1, 10799998, 10799998, 240000, 576, 0x58b31010
1, 11039998, 11039998, 240000, 576, 0x19610f54
-0, 11086442, 11086442, 400000, 6260, 0x6cf76411
+0, 11086442, 11086442, 400000, 6260, 0x6cf76411, F=0x0
1, 11279998, 11279998, 240000, 576, 0x17762352
-0, 11486331, 11486331, 400000, 6156, 0xe168394b
+0, 11486331, 11486331, 400000, 6156, 0xe168394b, F=0x0
1, 11519998, 11519998, 240000, 576, 0x1fea1448
1, 11759998, 11759998, 240000, 576, 0x55840a01
-0, 11886331, 13086442, 449438, 23364, 0x53164f1e
+0, 11886331, 13086442, 400000, 23364, 0x53164f1e, F=0x0
1, 11999998, 11999998, 240000, 576, 0x6c9c24ce
1, 12239998, 12239998, 240000, 576, 0x955f1e97
-0, 12286442, 12286442, 449438, 6708, 0x89877269
+0, 12286442, 12286442, 400000, 6708, 0x89877269, F=0x0
1, 12479998, 12479998, 240000, 576, 0x2827134f
-0, 12686442, 12686442, 449438, 6908, 0x8d62a249
+0, 12686442, 12686442, 400000, 6908, 0x8d62a249, F=0x0
1, 12719998, 12719998, 240000, 576, 0x34a01c29
1, 12959998, 12959998, 240000, 576, 0x7d351e52
-0, 13086442, 14286442, 449438, 38156, 0xec41f682
+0, 13086442, 14286442, 400000, 38156, 0xec41f682
1, 13199998, 13199998, 240000, 576, 0x00c91d9e
1, 13439998, 13439998, 240000, 576, 0x57ea1a97
-0, 13486331, 13486331, 449438, 5764, 0xcc04534b
+0, 13486331, 13486331, 400000, 5764, 0xcc04534b, F=0x0
1, 13679998, 13679998, 240000, 576, 0xef3a1c74
-0, 13886331, 13886331, 449438, 5388, 0xb8a1c3c5
+0, 13886331, 13886331, 400000, 5388, 0xb8a1c3c5, F=0x0
1, 13919998, 13919998, 240000, 576, 0x11fc217d
1, 14159998, 14159998, 240000, 576, 0x59ce20e5
-0, 14286442, 15486331, 449438, 16764, 0x59460d96
+0, 14286442, 15486331, 400000, 16764, 0x59460d96, F=0x0
1, 14399998, 14399998, 240000, 576, 0xaafc1dbf
1, 14639998, 14639998, 240000, 576, 0xdd941609
-0, 14686331, 14686331, 449438, 5548, 0x5c91e93d
+0, 14686331, 14686331, 400000, 5548, 0x5c91e93d, F=0x0
1, 14879998, 14879998, 240000, 576, 0x900420b0
-0, 15086331, 15086331, 449438, 5652, 0x5e321aed
+0, 15086331, 15086331, 400000, 5652, 0x5e321aed, F=0x0
1, 15119998, 15119998, 240000, 576, 0x5f4f1aa1
1, 15359998, 15359998, 240000, 576, 0x7d7e18de
-0, 15486331, 16686331, 449438, 15564, 0xefdf5080
+0, 15486331, 16686331, 400000, 15564, 0xefdf5080, F=0x0
1, 15599998, 15599998, 240000, 576, 0x986c0d9d
1, 15839998, 15839998, 240000, 576, 0xcb4c21c0
-0, 15886331, 15886331, 449438, 6492, 0xd1d5c5f8
+0, 15886331, 15886331, 400000, 6492, 0xd1d5c5f8, F=0x0
1, 16079998, 16079998, 240000, 576, 0xbcfb1e8b
-0, 16286331, 16286331, 449438, 5604, 0xf9472b44
+0, 16286331, 16286331, 400000, 5604, 0xf9472b44, F=0x0
1, 16319998, 16319998, 240000, 576, 0xcb541b4c
1, 16559998, 16559998, 240000, 576, 0x980426e9
-0, 16686331, 17886331, 449438, 17924, 0x45815b7b
+0, 16686331, 17886331, 400000, 17924, 0x45815b7b, F=0x0
1, 16799998, 16799998, 240000, 576, 0x09d00aa0
1, 17039998, 17039998, 240000, 576, 0xad591374
-0, 17086442, 17086442, 449438, 5020, 0x3cc5e554
+0, 17086442, 17086442, 400000, 5020, 0x3cc5e554, F=0x0
1, 17279998, 17279998, 240000, 576, 0x97bf1461
-0, 17486442, 17486442, 449438, 5276, 0xa0554c12
+0, 17486442, 17486442, 400000, 5276, 0xa0554c12, F=0x0
1, 17519998, 17519998, 240000, 576, 0xdc871cc4
1, 17759998, 17759998, 240000, 576, 0x56781896
-0, 17886331, 19086442, 449438, 31460, 0x5765eb5f
+0, 17886331, 19086442, 400000, 31460, 0x5765eb5f
1, 17999998, 17999998, 240000, 576, 0xc77714e3
1, 18239998, 18239998, 240000, 576, 0x280e18d4
-0, 18286331, 18286331, 449438, 4972, 0x91adbab7
+0, 18286331, 18286331, 400000, 4972, 0x91adbab7, F=0x0
1, 18479998, 18479998, 240000, 576, 0xbc0d2302
-0, 18686442, 18686442, 449438, 5580, 0xfea707cb
+0, 18686442, 18686442, 400000, 5580, 0xfea707cb, F=0x0
1, 18719998, 18719998, 240000, 576, 0x79191384
1, 18959998, 18959998, 240000, 576, 0x65481c97
-0, 19086442, 20286331, 449438, 17412, 0x0afe4d27
+0, 19086442, 20286331, 400000, 17412, 0x0afe4d27, F=0x0
1, 19199998, 19199998, 240000, 576, 0xc94d227d
1, 19439998, 19439998, 240000, 576, 0xa68a1f14
-0, 19486442, 19486442, 449438, 5236, 0x03f55309
+0, 19486442, 19486442, 400000, 5236, 0x03f55309, F=0x0
1, 19679998, 19679998, 240000, 576, 0x6af11a5c
-0, 19886331, 19886331, 449438, 4924, 0x558e753c
+0, 19886331, 19886331, 400000, 4924, 0x558e753c, F=0x0
1, 19919998, 19919998, 240000, 576, 0x4d1019ef
1, 20159998, 20159998, 240000, 576, 0x3b1b17b5
-0, 20286331, 21486331, 449438, 15396, 0xf145d121
+0, 20286331, 21486331, 400000, 15396, 0xf145d121, F=0x0
1, 20399998, 20399998, 240000, 576, 0xcdd8159f
1, 20639998, 20639998, 240000, 576, 0x97cd1d06
-0, 20686331, 20686331, 449438, 4708, 0x43066a92
+0, 20686331, 20686331, 400000, 4708, 0x43066a92, F=0x0
1, 20879998, 20879998, 240000, 576, 0x5d1b1123
-0, 21086442, 21086442, 449438, 4332, 0x9e22bcba
+0, 21086442, 21086442, 400000, 4332, 0x9e22bcba, F=0x0
1, 21119998, 21119998, 240000, 576, 0x888d0cb0
1, 21359998, 21359998, 240000, 576, 0x556e1dad
-0, 21486331, 22686442, 449438, 12876, 0x46ff9ef4
+0, 21486331, 22686442, 400000, 12876, 0x46ff9ef4, F=0x0
1, 21599998, 21599998, 240000, 576, 0xf7af0bce
1, 21839998, 21839998, 240000, 576, 0xb5da160a
-0, 21886442, 21886442, 449438, 5940, 0x27cba62e
+0, 21886442, 21886442, 400000, 5940, 0x27cba62e, F=0x0
1, 22079998, 22079998, 240000, 576, 0x4a8d0e98
-0, 22286442, 22286442, 449438, 6124, 0x6bab0a6d
+0, 22286442, 22286442, 400000, 6124, 0x6bab0a6d, F=0x0
1, 22319998, 22319998, 240000, 576, 0x183b1c7e
1, 22559998, 22559998, 240000, 576, 0xc47120e6
-0, 22686442, 23886442, 449438, 36428, 0x942f9648
+0, 22686442, 23886442, 400000, 36428, 0x942f9648
1, 22799998, 22799998, 240000, 576, 0xb1f31346
-0, 23086331, 23086331, 449438, 6660, 0x545a0db7
-0, 23486331, 23486331, 449438, 6780, 0x2d1d4189
-0, 23886442, 25086331, 449438, 16460, 0x7c3b3ca4
-0, 24286442, 24286442, 449438, 6724, 0x8538cc6f
-0, 24686442, 24686442, 449438, 7068, 0x69574fd0
-0, 25086331, 26286331, 449438, 19552, 0xf230e854
+0, 23086331, 23086331, 400000, 6660, 0x545a0db7, F=0x0
+0, 23486331, 23486331, 400000, 6780, 0x2d1d4189, F=0x0
+0, 23886442, 25086331, 400000, 16460, 0x7c3b3ca4, F=0x0
+0, 24286442, 24286442, 400000, 6724, 0x8538cc6f, F=0x0
+0, 24686442, 24686442, 400000, 7068, 0x69574fd0, F=0x0
+0, 25086331, 26286331, 400000, 19552, 0xf230e854, F=0x0
diff --git a/tests/ref/fate/xbm11 b/tests/ref/fate/xbm11
index 778e8ab702..77192b3e64 100644
--- a/tests/ref/fate/xbm11
+++ b/tests/ref/fate/xbm11
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 1500, 0x8b73635a
+0, 0, 0, 1, 4750, 0xc85f0b6d
diff --git a/tests/ref/fate/xface b/tests/ref/fate/xface
new file mode 100644
index 0000000000..7f1f1e6445
--- /dev/null
+++ b/tests/ref/fate/xface
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0, 0, 0, 1, 288, 0x87ddaef8
diff --git a/tests/ref/fate/xmv-demux b/tests/ref/fate/xmv-demux
index 20c6ac1c4f..d13270a6fc 100644
--- a/tests/ref/fate/xmv-demux
+++ b/tests/ref/fate/xmv-demux
@@ -1,3 +1,4 @@
+#extradata 0: 4, 0x015a00ad
#tb 0: 1/1000
#tb 1: 16/11025
0, 0, 0, 0, 1508, 0xefceba48
@@ -7,32 +8,32 @@
1, 249, 249, 83, 5976, 0x4ea056f4
1, 332, 332, 83, 5976, 0xda772d8d
1, 415, 415, 83, 5976, 0xafacf7c9
-0, 640, 640, 0, 108, 0x06713c96
-0, 680, 680, 0, 952, 0xd306df7e
-0, 720, 720, 0, 2312, 0xaf316585
+0, 640, 640, 0, 108, 0x06713c96, F=0x0
+0, 680, 680, 0, 952, 0xd306df7e, F=0x0
+0, 720, 720, 0, 2312, 0xaf316585, F=0x0
1, 498, 498, 83, 5976, 0xdeb003f4
-0, 760, 760, 0, 3872, 0xfc1c527c
-0, 800, 800, 0, 20, 0xaffc0edd
-0, 840, 840, 0, 6600, 0xe1b66c7f
+0, 760, 760, 0, 3872, 0xfc1c527c, F=0x0
+0, 800, 800, 0, 20, 0xaffc0edd, F=0x0
+0, 840, 840, 0, 6600, 0xe1b66c7f, F=0x0
1, 581, 581, 28, 2016, 0xa7380d36
-0, 880, 880, 0, 6868, 0xd5b3f631
+0, 880, 880, 0, 6868, 0xd5b3f631, F=0x0
1, 609, 609, 28, 2016, 0xbc090bac
-0, 920, 920, 0, 8420, 0xf70ee33b
+0, 920, 920, 0, 8420, 0xf70ee33b, F=0x0
1, 637, 637, 28, 2016, 0x6f8c164c
-0, 960, 960, 0, 13144, 0x9a54ef39
+0, 960, 960, 0, 13144, 0x9a54ef39, F=0x0
1, 665, 665, 28, 2016, 0x13b80e28
-0, 1000, 1000, 0, 6340, 0xe55bf555
+0, 1000, 1000, 0, 6340, 0xe55bf555, F=0x0
1, 693, 693, 28, 2016, 0xd40ff863
-0, 1040, 1040, 0, 3736, 0x0b23f89f
+0, 1040, 1040, 0, 3736, 0x0b23f89f, F=0x0
1, 721, 721, 28, 2016, 0x4d530ed7
-0, 1080, 1080, 0, 2624, 0x79e2e451
+0, 1080, 1080, 0, 2624, 0x79e2e451, F=0x0
1, 749, 749, 30, 2160, 0x0fbc37eb
-0, 1120, 1120, 0, 1860, 0x63886f11
+0, 1120, 1120, 0, 1860, 0x63886f11, F=0x0
1, 779, 779, 192, 13824, 0x82fb2602
-0, 1160, 1160, 0, 1244, 0x74594601
-0, 1200, 1200, 0, 564, 0xf4561dfb
-0, 1240, 1240, 0, 80, 0xbf8e2e30
-0, 1280, 1280, 0, 20, 0xa0990c29
+0, 1160, 1160, 0, 1244, 0x74594601, F=0x0
+0, 1200, 1200, 0, 564, 0xf4561dfb, F=0x0
+0, 1240, 1240, 0, 80, 0xbf8e2e30, F=0x0
+0, 1280, 1280, 0, 20, 0xa0990c29, F=0x0
1, 971, 971, 192, 13824, 0x08771caf
1, 1163, 1163, 192, 13824, 0xdf7d4a65
1, 1355, 1355, 193, 13896, 0x24bf3f47
@@ -40,35 +41,35 @@
1, 1598, 1598, 50, 3600, 0x8c666fd6
1, 1648, 1648, 50, 3600, 0x305c6ca1
1, 1698, 1698, 50, 3600, 0x48b04e1e
-0, 2480, 2480, 0, 104, 0x12413980
-0, 2520, 2520, 0, 796, 0x2e698ed3
+0, 2480, 2480, 0, 104, 0x12413980, F=0x0
+0, 2520, 2520, 0, 796, 0x2e698ed3, F=0x0
1, 1748, 1748, 50, 3600, 0x8c915935
-0, 2560, 2560, 0, 1808, 0x8b3e6e5e
-0, 2600, 2600, 0, 4712, 0xdbd51737
+0, 2560, 2560, 0, 1808, 0x8b3e6e5e, F=0x0
+0, 2600, 2600, 0, 4712, 0xdbd51737, F=0x0
1, 1798, 1798, 50, 3600, 0xa8f45e01
-0, 2640, 2640, 0, 5548, 0xee9c831c
-0, 2680, 2680, 0, 6152, 0x9c18ccc1
+0, 2640, 2640, 0, 5548, 0xee9c831c, F=0x0
+0, 2680, 2680, 0, 6152, 0x9c18ccc1, F=0x0
1, 1848, 1848, 53, 3816, 0xc64cc5ed
-0, 2720, 2720, 0, 6452, 0x7860462a
+0, 2720, 2720, 0, 6452, 0x7860462a, F=0x0
1, 1901, 1901, 27, 1944, 0x0ac2e3f1
-0, 2760, 2760, 0, 6676, 0xe1b1c9e4
+0, 2760, 2760, 0, 6676, 0xe1b1c9e4, F=0x0
1, 1928, 1928, 27, 1944, 0x2197dccd
-0, 2800, 2800, 0, 10904, 0x0bded7b7
+0, 2800, 2800, 0, 10904, 0x0bded7b7, F=0x0
1, 1955, 1955, 27, 1944, 0x0c02e77f
-0, 2840, 2840, 0, 12844, 0xe6d16cff
+0, 2840, 2840, 0, 12844, 0xe6d16cff, F=0x0
1, 1982, 1982, 27, 1944, 0x675ee06a
-0, 2880, 2880, 0, 10920, 0xe114c46b
+0, 2880, 2880, 0, 10920, 0xe114c46b, F=0x0
1, 2009, 2009, 30, 2160, 0x0d803a8b
-0, 2920, 2920, 0, 5952, 0xb7464634
+0, 2920, 2920, 0, 5952, 0xb7464634, F=0x0
1, 2039, 2039, 93, 6696, 0xa7a0dfea
-0, 2960, 2960, 0, 4732, 0x2fa2e36d
-0, 3000, 3000, 0, 2592, 0xf54ddd57
-0, 3040, 3040, 0, 1516, 0x4a1cd4d5
-0, 3080, 3080, 0, 864, 0x49889afc
+0, 2960, 2960, 0, 4732, 0x2fa2e36d, F=0x0
+0, 3000, 3000, 0, 2592, 0xf54ddd57, F=0x0
+0, 3040, 3040, 0, 1516, 0x4a1cd4d5, F=0x0
+0, 3080, 3080, 0, 864, 0x49889afc, F=0x0
1, 2132, 2132, 93, 6696, 0x59aa3145
-0, 3120, 3120, 0, 468, 0x3932e6a4
-0, 3160, 3160, 0, 116, 0x2b8341e6
-0, 3200, 3200, 0, 16, 0x6a3109cf
+0, 3120, 3120, 0, 468, 0x3932e6a4, F=0x0
+0, 3160, 3160, 0, 116, 0x2b8341e6, F=0x0
+0, 3200, 3200, 0, 16, 0x6a3109cf, F=0x0
1, 2225, 2225, 93, 6696, 0x69be4d78
1, 2318, 2318, 93, 6696, 0x64064c67
1, 2411, 2411, 93, 6696, 0xc8536f98
@@ -80,104 +81,104 @@
1, 2937, 2937, 123, 8856, 0x19e18797
1, 3060, 3060, 123, 8856, 0x0a0c7fbd
1, 3183, 3183, 124, 8928, 0x4a9b2d42
-0, 4640, 4640, 0, 100, 0x45023894
-0, 4680, 4680, 0, 948, 0xa65ed345
-0, 4720, 4720, 108, 2808, 0xd7285746
-0, 4760, 4760, 108, 5372, 0x05794175
+0, 4640, 4640, 0, 100, 0x45023894, F=0x0
+0, 4680, 4680, 0, 948, 0xa65ed345, F=0x0
+0, 4720, 4720, 0, 2808, 0xd7285746, F=0x0
+0, 4760, 4760, 40, 5372, 0x05794175, F=0x0
1, 3307, 3307, 21, 1512, 0xed8b3f4b
-0, 4800, 4800, 108, 11596, 0x8636eca7
+0, 4800, 4800, 40, 11596, 0x8636eca7, F=0x0
1, 3328, 3328, 21, 1512, 0xa27d3891
-0, 4840, 4840, 108, 11524, 0xe1f39be3
+0, 4840, 4840, 40, 11524, 0xe1f39be3, F=0x0
1, 3349, 3349, 21, 1512, 0xb0f13eb6
-0, 4880, 4880, 108, 23392, 0xab053f05
+0, 4880, 4880, 40, 23392, 0xab053f05, F=0x0
1, 3370, 3370, 23, 1656, 0xe5a98324
-0, 4920, 4920, 108, 4560, 0x03197d07
+0, 4920, 4920, 40, 4560, 0x03197d07, F=0x0
1, 3393, 3393, 31, 2232, 0x15445433
-0, 4960, 4960, 108, 4440, 0x1cc361a2
+0, 4960, 4960, 40, 4440, 0x1cc361a2, F=0x0
1, 3424, 3424, 31, 2232, 0x5cb348a9
-0, 5000, 5000, 108, 23688, 0x16030634
+0, 5000, 5000, 40, 23688, 0x16030634, F=0x0
1, 3455, 3455, 31, 2232, 0xf10347da
-0, 5040, 5040, 108, 16132, 0xf0eca799
+0, 5040, 5040, 40, 16132, 0xf0eca799, F=0x0
1, 3486, 3486, 34, 2448, 0x3e16a175
-0, 5080, 5080, 108, 29896, 0x0c0988ea
+0, 5080, 5080, 40, 29896, 0x0c0988ea, F=0x0
1, 3520, 3520, 35, 2520, 0x17e3ca2b
-0, 5120, 5120, 108, 19956, 0x0093aa0b
+0, 5120, 5120, 40, 19956, 0x0093aa0b, F=0x0
1, 3555, 3555, 27, 1944, 0x35c2de84
-0, 5160, 5160, 108, 16392, 0x8829a9ca
+0, 5160, 5160, 40, 16392, 0x8829a9ca, F=0x0
1, 3582, 3582, 27, 1944, 0x55b4db40
-0, 5200, 5200, 108, 16772, 0x9a4a546d
+0, 5200, 5200, 40, 16772, 0x9a4a546d, F=0x0
1, 3609, 3609, 29, 2088, 0xdaae14b2
-0, 5240, 5240, 108, 8920, 0xcd8ca203
+0, 5240, 5240, 40, 8920, 0xcd8ca203, F=0x0
1, 3638, 3638, 27, 1944, 0x92ccd37f
-0, 5280, 5280, 108, 9632, 0x53c1d37b
+0, 5280, 5280, 40, 9632, 0x53c1d37b, F=0x0
1, 3665, 3665, 27, 1944, 0x70efede1
-0, 5320, 5320, 108, 8976, 0xfe4da2cc
+0, 5320, 5320, 40, 8976, 0xfe4da2cc, F=0x0
1, 3692, 3692, 27, 1944, 0x7601d304
-0, 5360, 5360, 108, 6680, 0x35348fe0
+0, 5360, 5360, 40, 6680, 0x35348fe0, F=0x0
1, 3719, 3719, 27, 1944, 0x3922ebc2
-0, 5400, 5400, 108, 9228, 0xcbf62b0c
+0, 5400, 5400, 40, 9228, 0xcbf62b0c, F=0x0
1, 3746, 3746, 30, 2160, 0xde462f2e
-0, 5440, 5440, 108, 5108, 0xd1d88511
+0, 5440, 5440, 40, 5108, 0xd1d88511, F=0x0
1, 3776, 3776, 26, 1872, 0x467ac1d2
-0, 5480, 5480, 108, 10016, 0xaff4b2b2
+0, 5480, 5480, 40, 10016, 0xaff4b2b2, F=0x0
1, 3802, 3802, 26, 1872, 0xa1e4cd43
-0, 5520, 5520, 108, 7468, 0x23e81ab8
+0, 5520, 5520, 40, 7468, 0x23e81ab8, F=0x0
1, 3828, 3828, 26, 1872, 0x1dceccc6
-0, 5560, 5560, 108, 4172, 0x253cd05b
+0, 5560, 5560, 40, 4172, 0x253cd05b, F=0x0
1, 3854, 3854, 26, 1872, 0x2bbad2a5
-0, 5600, 5600, 108, 8188, 0x7ede743f
+0, 5600, 5600, 40, 8188, 0x7ede743f, F=0x0
1, 3880, 3880, 26, 1872, 0xc603d44d
-0, 5640, 5640, 108, 2884, 0x2dec55a3
+0, 5640, 5640, 40, 2884, 0x2dec55a3, F=0x0
1, 3906, 3906, 26, 1872, 0x1b4cc261
-0, 5680, 5680, 108, 3900, 0xd0666a18
+0, 5680, 5680, 40, 3900, 0xd0666a18, F=0x0
1, 3932, 3932, 26, 1872, 0x10edd6cf
-0, 5720, 5720, 108, 2996, 0x9cc99b8c
+0, 5720, 5720, 40, 2996, 0x9cc99b8c, F=0x0
1, 3958, 3958, 33, 2376, 0xecdb9d61
-0, 5760, 5760, 108, 2156, 0xae612776
+0, 5760, 5760, 40, 2156, 0xae612776, F=0x0
1, 3991, 3991, 36, 2592, 0x5559eced
-0, 5800, 5800, 108, 3988, 0x0d2c9992
-0, 5840, 5840, 108, 1512, 0x6281fc00
+0, 5800, 5800, 40, 3988, 0x0d2c9992, F=0x0
+0, 5840, 5840, 40, 1512, 0x6281fc00, F=0x0
1, 4027, 4027, 36, 2592, 0x8848dfc7
-0, 5880, 5880, 108, 6544, 0xb75c2562
+0, 5880, 5880, 40, 6544, 0xb75c2562, F=0x0
1, 4063, 4063, 36, 2592, 0x4ca2d7da
-0, 5920, 5920, 108, 4108, 0xfb21efc9
+0, 5920, 5920, 40, 4108, 0xfb21efc9, F=0x0
1, 4099, 4099, 36, 2592, 0x285fd7e6
-0, 5960, 5960, 108, 1096, 0x85922a37
-0, 6000, 6000, 108, 9740, 0xe57d7647
+0, 5960, 5960, 40, 1096, 0x85922a37, F=0x0
+0, 6000, 6000, 40, 9740, 0xe57d7647, F=0x0
1, 4135, 4135, 36, 2592, 0x2717e404
-0, 6040, 6040, 108, 416, 0x61c2ea02
+0, 6040, 6040, 40, 416, 0x61c2ea02, F=0x0
1, 4171, 4171, 36, 2592, 0xf106111a
-0, 6080, 6080, 108, 336, 0x1dc5ac1c
+0, 6080, 6080, 40, 336, 0x1dc5ac1c, F=0x0
1, 4207, 4207, 36, 2592, 0xd7d01119
-0, 6120, 6120, 108, 204, 0x16f57017
+0, 6120, 6120, 40, 204, 0x16f57017, F=0x0
1, 4243, 4243, 36, 2592, 0x550cfeda
-0, 6160, 6160, 108, 112, 0x78374234
-0, 6200, 6200, 108, 40, 0x6cb21985
+0, 6160, 6160, 40, 112, 0x78374234, F=0x0
+0, 6200, 6200, 40, 40, 0x6cb21985, F=0x0
1, 4279, 4279, 36, 2592, 0x47ad00c4
1, 4315, 4315, 36, 2592, 0x39bbf306
1, 4351, 4351, 45, 3240, 0x69addfce
1, 4396, 4396, 297, 21384, 0x254f63e0
1, 4693, 4693, 298, 21456, 0x2f7a9859
-0, 6840, 6840, 108, 14420, 0x53324ca4
-0, 6880, 6880, 108, 40, 0x10971420
+0, 6840, 6840, 40, 14420, 0x53324ca4, F=0x0
+0, 6880, 6880, 40, 40, 0x10971420, F=0x0
1, 4991, 4991, 521, 37512, 0x6e962928
1, 5512, 5512, 38, 2736, 0x1dc91c69
-0, 8000, 8000, 108, 24904, 0x15574f7e
+0, 8000, 8000, 40, 24904, 0x15574f7e
1, 5550, 5550, 38, 2736, 0x023434fd
1, 5588, 5588, 38, 2736, 0x906f1541
-0, 8160, 8160, 108, 1908, 0xccb2dd3c
+0, 8160, 8160, 40, 1908, 0xccb2dd3c, F=0x0
1, 5626, 5626, 38, 2736, 0x85a31102
-0, 8200, 8200, 108, 4676, 0xbfa42b7e
+0, 8200, 8200, 40, 4676, 0xbfa42b7e, F=0x0
1, 5664, 5664, 42, 3024, 0x9296a5f3
-0, 8240, 8240, 108, 3600, 0x87c9dc58
-0, 8280, 8280, 108, 8184, 0x504a8e65
+0, 8240, 8240, 40, 3600, 0x87c9dc58, F=0x0
+0, 8280, 8280, 40, 8184, 0x504a8e65, F=0x0
1, 5706, 5706, 27, 1944, 0x7bf4dedc
-0, 8320, 8320, 108, 9636, 0x2efb3006
+0, 8320, 8320, 40, 9636, 0x2efb3006, F=0x0
1, 5733, 5733, 27, 1944, 0x4196c404
1, 5760, 5760, 27, 1944, 0xcda97c7a
-0, 8360, 8360, 108, 9580, 0x0fb6f4e8
+0, 8360, 8360, 40, 9580, 0x0fb6f4e8, F=0x0
1, 5787, 5787, 27, 1944, 0x5f4922b2
-0, 8400, 8400, 108, 7840, 0xe996f564
+0, 8400, 8400, 40, 7840, 0xe996f564, F=0x0
1, 5814, 5814, 29, 2088, 0x37dfc157
-0, 8440, 8440, 108, 4208, 0xe9c2fba2
-0, 8480, 8480, 108, 556, 0x3f1e077c
+0, 8440, 8440, 40, 4208, 0xe9c2fba2, F=0x0
+0, 8480, 8480, 40, 556, 0x3f1e077c, F=0x0
diff --git a/tests/ref/fate/xvid-custom-matrix b/tests/ref/fate/xvid-custom-matrix
index 03613890b9..c00a24bbc1 100644
--- a/tests/ref/fate/xvid-custom-matrix
+++ b/tests/ref/fate/xvid-custom-matrix
@@ -1,21 +1,25 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 1, 1, 1, 622080, 870e846b6b001d3e34fa87df96297e28
-0, 2, 2, 1, 622080, de1a3dd9fcc32086ecdffd4591a8defa
-0, 3, 3, 1, 622080, 59f5f16d4224e98e09f22818cc9227e0
-0, 4, 4, 1, 622080, 9744609bcf95107bdbe6a9e21dc22b9d
-0, 5, 5, 1, 622080, 6dc50ad4b5821cc20f418f2eb273a45c
-0, 6, 6, 1, 622080, 57012fc77d853c17591319cc528ebd93
-0, 7, 7, 1, 622080, fd0068955ce1583f21bb888ad3b6952a
-0, 8, 8, 1, 622080, 58b7bcb056fac5d34ec4197fe10723a7
-0, 9, 9, 1, 622080, 064311346d0ea2753f01f18f13188c27
-0, 10, 10, 1, 622080, 21995e49367aee152a11992f48317bbe
-0, 11, 11, 1, 622080, 288c2cd0ac0a3b74d23da6ba30111d55
-0, 12, 12, 1, 622080, 88db7bf240fd6ee5ef89c34522de76e8
-0, 13, 13, 1, 622080, 8e2d38686bbf768e812005decc37cb90
-0, 14, 14, 1, 622080, 3a7d3c036ecaa669d26660937a8b723e
-0, 15, 15, 1, 622080, 6c8b8e847c544125213c9f49d9607d98
-0, 16, 16, 1, 622080, 16b56117f1b327862f78421116dfe52e
-0, 17, 17, 1, 622080, a7ce423456a59bdb4d5921aff1a27691
-0, 18, 18, 1, 622080, 881c9561c9ab66a7659145173f8e8cda
-0, 19, 19, 1, 622080, 7413961f9accd1d32e116592a6448e9b
-0, 20, 20, 1, 622080, c66409494fd1714e6236596f476cece6
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 622080, 870e846b6b001d3e34fa87df96297e28
+0, 1, 1, 1, 622080, de1a3dd9fcc32086ecdffd4591a8defa
+0, 2, 2, 1, 622080, 59f5f16d4224e98e09f22818cc9227e0
+0, 3, 3, 1, 622080, 9744609bcf95107bdbe6a9e21dc22b9d
+0, 4, 4, 1, 622080, 6dc50ad4b5821cc20f418f2eb273a45c
+0, 5, 5, 1, 622080, 57012fc77d853c17591319cc528ebd93
+0, 6, 6, 1, 622080, fd0068955ce1583f21bb888ad3b6952a
+0, 7, 7, 1, 622080, 58b7bcb056fac5d34ec4197fe10723a7
+0, 8, 8, 1, 622080, 064311346d0ea2753f01f18f13188c27
+0, 9, 9, 1, 622080, 21995e49367aee152a11992f48317bbe
+0, 10, 10, 1, 622080, 288c2cd0ac0a3b74d23da6ba30111d55
+0, 11, 11, 1, 622080, 88db7bf240fd6ee5ef89c34522de76e8
+0, 12, 12, 1, 622080, 8e2d38686bbf768e812005decc37cb90
+0, 13, 13, 1, 622080, 3a7d3c036ecaa669d26660937a8b723e
+0, 14, 14, 1, 622080, 6c8b8e847c544125213c9f49d9607d98
+0, 15, 15, 1, 622080, 16b56117f1b327862f78421116dfe52e
+0, 16, 16, 1, 622080, a7ce423456a59bdb4d5921aff1a27691
+0, 17, 17, 1, 622080, 881c9561c9ab66a7659145173f8e8cda
+0, 18, 18, 1, 622080, 7413961f9accd1d32e116592a6448e9b
+0, 21, 21, 1, 622080, c66409494fd1714e6236596f476cece6
diff --git a/tests/ref/fate/xvid-idct b/tests/ref/fate/xvid-idct
index c3cafa3934..2fc93ee684 100644
--- a/tests/ref/fate/xvid-idct
+++ b/tests/ref/fate/xvid-idct
@@ -1,21 +1,25 @@
+#format: frame checksums
+#version: 1
+#hash: MD5
#tb 0: 1/25
-0, 1, 1, 1, 622080, 8fe318df973b5d7669e6d28ebf03b229
-0, 2, 2, 1, 622080, 3568d92074e0298a2027f990004fe1a6
-0, 3, 3, 1, 622080, 4781afb6ba38318738e26a98ace4061b
-0, 4, 4, 1, 622080, bd29a005b8392005ef30211f185ca049
-0, 5, 5, 1, 622080, fc50b441ee9256883edba5a584000d66
-0, 6, 6, 1, 622080, 5fce9fb7e66c9d0773ff9c7482cb8307
-0, 7, 7, 1, 622080, 2e0ad7b1ba39e60cdd7a65ed1ed57c30
-0, 8, 8, 1, 622080, b91cfdb91751dabd6691d3c34221b636
-0, 9, 9, 1, 622080, f65507bc00043e8fe345c542f0861a64
-0, 10, 10, 1, 622080, 2e4ee4ea4ec761c2298acced17f63f35
-0, 11, 11, 1, 622080, e7945bd07296205d1549c8edf843af48
-0, 12, 12, 1, 622080, 52fed0ec02c57a138de7dc0e0c804de8
-0, 13, 13, 1, 622080, 3ee2848d0d70795e14765127111a677c
-0, 14, 14, 1, 622080, 42cb0929406b10b95817ffaa2da47335
-0, 15, 15, 1, 622080, 523986866b6cf729e130ea43feacb0a2
-0, 16, 16, 1, 622080, 5d1e4becddf728e93bbcb428de1f02ae
-0, 17, 17, 1, 622080, 0a1453df21e4547447ec8f27a0d4d5ec
-0, 18, 18, 1, 622080, d3495686e769df299b1732326fa3f17e
-0, 19, 19, 1, 622080, 602e9020397b1e82b58b1ff6b9733d21
-0, 20, 20, 1, 622080, 759bd3f739a3b99309efa5c1a697e34d
+#stream#, dts, pts, duration, size, hash
+0, 0, 0, 1, 622080, 8fe318df973b5d7669e6d28ebf03b229
+0, 1, 1, 1, 622080, 3568d92074e0298a2027f990004fe1a6
+0, 2, 2, 1, 622080, 4781afb6ba38318738e26a98ace4061b
+0, 3, 3, 1, 622080, bd29a005b8392005ef30211f185ca049
+0, 4, 4, 1, 622080, fc50b441ee9256883edba5a584000d66
+0, 5, 5, 1, 622080, 5fce9fb7e66c9d0773ff9c7482cb8307
+0, 6, 6, 1, 622080, 2e0ad7b1ba39e60cdd7a65ed1ed57c30
+0, 7, 7, 1, 622080, b91cfdb91751dabd6691d3c34221b636
+0, 8, 8, 1, 622080, f65507bc00043e8fe345c542f0861a64
+0, 9, 9, 1, 622080, 2e4ee4ea4ec761c2298acced17f63f35
+0, 10, 10, 1, 622080, e7945bd07296205d1549c8edf843af48
+0, 11, 11, 1, 622080, 52fed0ec02c57a138de7dc0e0c804de8
+0, 12, 12, 1, 622080, 3ee2848d0d70795e14765127111a677c
+0, 13, 13, 1, 622080, 42cb0929406b10b95817ffaa2da47335
+0, 14, 14, 1, 622080, 523986866b6cf729e130ea43feacb0a2
+0, 15, 15, 1, 622080, 5d1e4becddf728e93bbcb428de1f02ae
+0, 16, 16, 1, 622080, 0a1453df21e4547447ec8f27a0d4d5ec
+0, 17, 17, 1, 622080, d3495686e769df299b1732326fa3f17e
+0, 18, 18, 1, 622080, 602e9020397b1e82b58b1ff6b9733d21
+0, 21, 21, 1, 622080, 759bd3f739a3b99309efa5c1a697e34d
diff --git a/tests/ref/fate/yop b/tests/ref/fate/yop
index 1a5666069e..1920281a40 100644
--- a/tests/ref/fate/yop
+++ b/tests/ref/fate/yop
@@ -1,7 +1,7 @@
#tb 0: 1/12
-0, 0, 0, 1, 302760, 0x78939253
-0, 1, 1, 1, 302760, 0x534f5253
-0, 2, 2, 1, 302760, 0x25eaa782
-0, 3, 3, 1, 302760, 0x60861c3d
-0, 4, 4, 1, 302760, 0x43552521
-0, 5, 5, 1, 302760, 0x45abca02
+0, 0, 0, 1, 302760, 0xf24dfa37
+0, 1, 1, 1, 302760, 0xcedcbb6c
+0, 2, 2, 1, 302760, 0xc87716a2
+0, 3, 3, 1, 302760, 0x7e378e5a
+0, 4, 4, 1, 302760, 0xd4a19734
+0, 5, 5, 1, 302760, 0x26e93266
diff --git a/tests/ref/fate/zmbv-15bit b/tests/ref/fate/zmbv-15bit
index f054a9d781..384bb650b7 100644
--- a/tests/ref/fate/zmbv-15bit
+++ b/tests/ref/fate/zmbv-15bit
@@ -1,160 +1,160 @@
#tb 0: 250000/1585341
-0, 0, 0, 1, 192000, 0xe1d317d6
-0, 1, 1, 1, 192000, 0xe100109d
-0, 2, 2, 1, 192000, 0xecc69c65
-0, 3, 3, 1, 192000, 0x68f06324
-0, 4, 4, 1, 192000, 0x68f06324
-0, 5, 5, 1, 192000, 0x68f06324
-0, 6, 6, 1, 192000, 0x68f06324
-0, 7, 7, 1, 192000, 0x68f06324
-0, 8, 8, 1, 192000, 0x68f06324
-0, 9, 9, 1, 192000, 0x68f06324
-0, 10, 10, 1, 192000, 0x68f06324
-0, 11, 11, 1, 192000, 0x68f06324
-0, 12, 12, 1, 192000, 0x68f06324
-0, 13, 13, 1, 192000, 0x68f06324
-0, 14, 14, 1, 192000, 0x68f06324
-0, 15, 15, 1, 192000, 0x68f06324
-0, 16, 16, 1, 192000, 0x68f06324
-0, 17, 17, 1, 192000, 0x4c03d2e3
-0, 18, 18, 1, 192000, 0x4c03d2e3
-0, 19, 19, 1, 192000, 0x4c03d2e3
-0, 20, 20, 1, 192000, 0x4c03d2e3
-0, 21, 21, 1, 192000, 0xb562cf68
-0, 22, 22, 1, 192000, 0xb562cf68
-0, 23, 23, 1, 192000, 0xb562cf68
-0, 24, 24, 1, 192000, 0xb562cf68
-0, 25, 25, 1, 192000, 0xb562cf68
-0, 26, 26, 1, 192000, 0x0e5e03c7
-0, 27, 27, 1, 192000, 0x0e5e03c7
-0, 28, 28, 1, 192000, 0x0e5e03c7
-0, 29, 29, 1, 192000, 0x0e5e03c7
-0, 30, 30, 1, 192000, 0xeb2e0f67
-0, 31, 31, 1, 192000, 0xeb2e0f67
-0, 32, 32, 1, 192000, 0xeb2e0f67
-0, 33, 33, 1, 192000, 0xeb2e0f67
-0, 34, 34, 1, 192000, 0xeb2e0f67
-0, 35, 35, 1, 192000, 0xdce603c7
-0, 36, 36, 1, 192000, 0xdce603c7
-0, 37, 37, 1, 192000, 0xdce603c7
-0, 38, 38, 1, 192000, 0xdce603c7
-0, 39, 39, 1, 192000, 0xa8e7db08
-0, 40, 40, 1, 192000, 0xa8e7db08
-0, 41, 41, 1, 192000, 0xa8e7db08
-0, 42, 42, 1, 192000, 0xa8e7db08
-0, 43, 43, 1, 192000, 0xa8e7db08
-0, 44, 44, 1, 192000, 0x322a1b07
-0, 45, 45, 1, 192000, 0x322a1b07
-0, 46, 46, 1, 192000, 0x322a1b07
-0, 47, 47, 1, 192000, 0x322a1b07
-0, 48, 48, 1, 192000, 0x743206af
-0, 49, 49, 1, 192000, 0x743206af
-0, 50, 50, 1, 192000, 0x743206af
-0, 51, 51, 1, 192000, 0x743206af
-0, 52, 52, 1, 192000, 0x743206af
-0, 53, 53, 1, 192000, 0x50195ddf
-0, 54, 54, 1, 192000, 0x50195ddf
-0, 55, 55, 1, 192000, 0x50195ddf
-0, 56, 56, 1, 192000, 0x50195ddf
-0, 57, 57, 1, 192000, 0xd31620d7
-0, 58, 58, 1, 192000, 0xd31620d7
-0, 59, 59, 1, 192000, 0xd31620d7
-0, 60, 60, 1, 192000, 0xd31620d7
-0, 61, 61, 1, 192000, 0xd31620d7
-0, 62, 62, 1, 192000, 0x3af023bf
-0, 63, 63, 1, 192000, 0x3af023bf
-0, 64, 64, 1, 192000, 0x3af023bf
-0, 65, 65, 1, 192000, 0x3af023bf
-0, 66, 66, 1, 192000, 0x561a124f
-0, 67, 67, 1, 192000, 0x561a124f
-0, 68, 68, 1, 192000, 0x561a124f
-0, 69, 69, 1, 192000, 0x561a124f
-0, 70, 70, 1, 192000, 0x561a124f
-0, 71, 71, 1, 192000, 0x99210c7f
-0, 72, 72, 1, 192000, 0x99210c7f
-0, 73, 73, 1, 192000, 0x99210c7f
-0, 74, 74, 1, 192000, 0x99210c7f
-0, 75, 75, 1, 192000, 0xc77b03c7
-0, 76, 76, 1, 192000, 0xc77b03c7
-0, 77, 77, 1, 192000, 0xc77b03c7
-0, 78, 78, 1, 192000, 0xc77b03c7
-0, 79, 79, 1, 192000, 0xc77b03c7
-0, 80, 80, 1, 192000, 0x83ea7550
-0, 81, 81, 1, 192000, 0xec285270
-0, 82, 82, 1, 192000, 0x0e075558
-0, 83, 83, 1, 192000, 0x880c2108
-0, 84, 84, 1, 192000, 0x40c523f0
-0, 85, 85, 1, 192000, 0x01378f78
-0, 86, 86, 1, 192000, 0x42045558
-0, 87, 87, 1, 192000, 0xde8f3278
-0, 88, 88, 1, 192000, 0xa58c0110
-0, 89, 89, 1, 192000, 0x335ea9d1
-0, 90, 90, 1, 192000, 0x7e94bb41
-0, 91, 91, 1, 192000, 0x9cc5d569
-0, 92, 92, 1, 192000, 0xe942e109
-0, 93, 93, 1, 192000, 0x4cb83848
-0, 94, 94, 1, 192000, 0x6986fe19
-0, 95, 95, 1, 192000, 0xbb8c23f0
-0, 96, 96, 1, 192000, 0x296766c8
-0, 97, 97, 1, 192000, 0xb4230cb0
-0, 98, 98, 1, 192000, 0x2c2f1850
-0, 99, 99, 1, 192000, 0x93c70110
-0, 100, 100, 1, 192000, 0xb830a9d1
-0, 101, 101, 1, 192000, 0xbed48fa9
-0, 102, 102, 1, 192000, 0xc087bb41
-0, 103, 103, 1, 192000, 0x792de6d9
-0, 104, 104, 1, 192000, 0x1edaf849
-0, 105, 105, 1, 192000, 0x6564bb41
-0, 106, 106, 1, 192000, 0x9153d569
-0, 107, 107, 1, 192000, 0xe73ff561
-0, 108, 108, 1, 192000, 0xfa3be3f1
-0, 109, 109, 1, 192000, 0x8008fe19
-0, 110, 110, 1, 192000, 0xd2561b38
-0, 111, 111, 1, 192000, 0xae3c26d8
-0, 112, 112, 1, 192000, 0xb0114f88
-0, 113, 113, 1, 192000, 0x117e1e20
-0, 114, 114, 1, 192000, 0x482d1280
-0, 115, 115, 1, 192000, 0x425106e0
-0, 116, 116, 1, 192000, 0x0e6b0cb0
-0, 117, 117, 1, 192000, 0x95dc2ca8
-0, 118, 118, 1, 192000, 0x52097b20
-0, 119, 119, 1, 192000, 0x41a84f88
-0, 120, 120, 1, 192000, 0xb78d7268
-0, 121, 121, 1, 192000, 0x2cd366c8
-0, 122, 122, 1, 192000, 0xbf39e109
-0, 123, 123, 1, 192000, 0xecbaeca9
-0, 124, 124, 1, 192000, 0x3254eca9
-0, 125, 125, 1, 192000, 0x3fc903f8
-0, 126, 126, 1, 192000, 0x0bbc5e10
-0, 127, 127, 1, 192000, 0xe9103560
-0, 128, 128, 1, 192000, 0xbd5d2f90
-0, 129, 129, 1, 192000, 0x7ace2ca8
-0, 130, 130, 1, 192000, 0x7354c6e1
-0, 131, 131, 1, 192000, 0x72e0d569
-0, 132, 132, 1, 192000, 0xa4ade3f1
-0, 133, 133, 1, 192000, 0xf2f8cf99
-0, 134, 134, 1, 192000, 0x2b7ee6d9
-0, 135, 135, 1, 192000, 0x548d1b38
-0, 136, 136, 1, 192000, 0xa1551b38
-0, 137, 137, 1, 192000, 0xfb3e3560
-0, 138, 138, 1, 192000, 0x3aaaccb1
-0, 139, 139, 1, 192000, 0xa85ee109
-0, 140, 140, 1, 192000, 0xc1bff849
-0, 141, 141, 1, 192000, 0xa62bef91
-0, 142, 142, 1, 192000, 0xddf40cb0
-0, 143, 143, 1, 192000, 0x15bb3e18
-0, 144, 144, 1, 192000, 0x92fd5558
-0, 145, 145, 1, 192000, 0x2d365270
-0, 146, 146, 1, 192000, 0xb5f343e8
-0, 147, 147, 1, 192000, 0x93042108
-0, 148, 148, 1, 192000, 0x96d59830
-0, 149, 149, 1, 192000, 0x1f69ddf0
-0, 150, 150, 1, 192000, 0x8eb0124f
-0, 151, 151, 1, 192000, 0xae727dd7
-0, 152, 152, 1, 192000, 0xb8a63aff
-0, 153, 153, 1, 192000, 0xfae83de7
-0, 154, 154, 1, 192000, 0x2f034987
-0, 155, 155, 1, 192000, 0xa99e1537
-0, 156, 156, 1, 192000, 0x0ad70c7f
-0, 157, 157, 1, 192000, 0x74b3e990
-0, 158, 158, 1, 192000, 0x1bf0d250
+0, 0, 0, 1, 192000, 0x8f9020f2
+0, 1, 1, 1, 192000, 0xbfba7f63
+0, 2, 2, 1, 192000, 0x96b48d11
+0, 3, 3, 1, 192000, 0xf91727d5
+0, 4, 4, 1, 192000, 0xf91727d5
+0, 5, 5, 1, 192000, 0xf91727d5
+0, 6, 6, 1, 192000, 0xf91727d5
+0, 7, 7, 1, 192000, 0xf91727d5
+0, 8, 8, 1, 192000, 0xf91727d5
+0, 9, 9, 1, 192000, 0xf91727d5
+0, 10, 10, 1, 192000, 0xf91727d5
+0, 11, 11, 1, 192000, 0xf91727d5
+0, 12, 12, 1, 192000, 0xf91727d5
+0, 13, 13, 1, 192000, 0xf91727d5
+0, 14, 14, 1, 192000, 0xf91727d5
+0, 15, 15, 1, 192000, 0xf91727d5
+0, 16, 16, 1, 192000, 0xf91727d5
+0, 17, 17, 1, 192000, 0x61c4e431
+0, 18, 18, 1, 192000, 0x61c4e431
+0, 19, 19, 1, 192000, 0x61c4e431
+0, 20, 20, 1, 192000, 0x61c4e431
+0, 21, 21, 1, 192000, 0x1fb3f649
+0, 22, 22, 1, 192000, 0x1fb3f649
+0, 23, 23, 1, 192000, 0x1fb3f649
+0, 24, 24, 1, 192000, 0x1fb3f649
+0, 25, 25, 1, 192000, 0x1fb3f649
+0, 26, 26, 1, 192000, 0x14f72c22
+0, 27, 27, 1, 192000, 0x14f72c22
+0, 28, 28, 1, 192000, 0x14f72c22
+0, 29, 29, 1, 192000, 0x14f72c22
+0, 30, 30, 1, 192000, 0x8cae3816
+0, 31, 31, 1, 192000, 0x8cae3816
+0, 32, 32, 1, 192000, 0x8cae3816
+0, 33, 33, 1, 192000, 0x8cae3816
+0, 34, 34, 1, 192000, 0x8cae3816
+0, 35, 35, 1, 192000, 0x2b6f2c22
+0, 36, 36, 1, 192000, 0x2b6f2c22
+0, 37, 37, 1, 192000, 0x2b6f2c22
+0, 38, 38, 1, 192000, 0x2b6f2c22
+0, 39, 39, 1, 192000, 0xc568024c
+0, 40, 40, 1, 192000, 0xc568024c
+0, 41, 41, 1, 192000, 0xc568024c
+0, 42, 42, 1, 192000, 0xc568024c
+0, 43, 43, 1, 192000, 0xc568024c
+0, 44, 44, 1, 192000, 0xa93b440a
+0, 45, 45, 1, 192000, 0xa93b440a
+0, 46, 46, 1, 192000, 0xa93b440a
+0, 47, 47, 1, 192000, 0xa93b440a
+0, 48, 48, 1, 192000, 0x798a2f1f
+0, 49, 49, 1, 192000, 0x798a2f1f
+0, 50, 50, 1, 192000, 0x798a2f1f
+0, 51, 51, 1, 192000, 0x798a2f1f
+0, 52, 52, 1, 192000, 0x798a2f1f
+0, 53, 53, 1, 192000, 0xf04288c5
+0, 54, 54, 1, 192000, 0xf04288c5
+0, 55, 55, 1, 192000, 0xf04288c5
+0, 56, 56, 1, 192000, 0xf04288c5
+0, 57, 57, 1, 192000, 0x4aa04a04
+0, 58, 58, 1, 192000, 0x4aa04a04
+0, 59, 59, 1, 192000, 0x4aa04a04
+0, 60, 60, 1, 192000, 0x4aa04a04
+0, 61, 61, 1, 192000, 0x4aa04a04
+0, 62, 62, 1, 192000, 0xb0304d01
+0, 63, 63, 1, 192000, 0xb0304d01
+0, 64, 64, 1, 192000, 0xb0304d01
+0, 65, 65, 1, 192000, 0xb0304d01
+0, 66, 66, 1, 192000, 0xef353b13
+0, 67, 67, 1, 192000, 0xef353b13
+0, 68, 68, 1, 192000, 0xef353b13
+0, 69, 69, 1, 192000, 0xef353b13
+0, 70, 70, 1, 192000, 0xef353b13
+0, 71, 71, 1, 192000, 0xbf823519
+0, 72, 72, 1, 192000, 0xbf823519
+0, 73, 73, 1, 192000, 0xbf823519
+0, 74, 74, 1, 192000, 0xbf823519
+0, 75, 75, 1, 192000, 0xd0352c22
+0, 76, 76, 1, 192000, 0xd0352c22
+0, 77, 77, 1, 192000, 0xd0352c22
+0, 78, 78, 1, 192000, 0xd0352c22
+0, 79, 79, 1, 192000, 0xd0352c22
+0, 80, 80, 1, 192000, 0x817299a6
+0, 81, 81, 1, 192000, 0xfb1475ca
+0, 82, 82, 1, 192000, 0xfcd278c7
+0, 83, 83, 1, 192000, 0xa08742fd
+0, 84, 84, 1, 192000, 0x47c245fa
+0, 85, 85, 1, 192000, 0xf7e7b48b
+0, 86, 86, 1, 192000, 0xf56378c7
+0, 87, 87, 1, 192000, 0x80bc54eb
+0, 88, 88, 1, 192000, 0xae59221e
+0, 89, 89, 1, 192000, 0x7d0fc869
+0, 90, 90, 1, 192000, 0x8e89da57
+0, 91, 91, 1, 192000, 0xf0a9f53c
+0, 92, 92, 1, 192000, 0x658d013f
+0, 93, 93, 1, 192000, 0x90ef5ae5
+0, 94, 94, 1, 192000, 0x93b81f21
+0, 95, 95, 1, 192000, 0x61e545fa
+0, 96, 96, 1, 192000, 0xc6688ab5
+0, 97, 97, 1, 192000, 0x72032e12
+0, 98, 98, 1, 192000, 0xf28c3a06
+0, 99, 99, 1, 192000, 0xf1bc221e
+0, 100, 100, 1, 192000, 0x941bc869
+0, 101, 101, 1, 192000, 0xe95ead84
+0, 102, 102, 1, 192000, 0x61dbda57
+0, 103, 103, 1, 192000, 0x79800739
+0, 104, 104, 1, 192000, 0x00c31927
+0, 105, 105, 1, 192000, 0x74a3da57
+0, 106, 106, 1, 192000, 0xb98cf53c
+0, 107, 107, 1, 192000, 0xd3f9162a
+0, 108, 108, 1, 192000, 0x888c043c
+0, 109, 109, 1, 192000, 0x100f1f21
+0, 110, 110, 1, 192000, 0x41993d03
+0, 111, 111, 1, 192000, 0x01a548f7
+0, 112, 112, 1, 192000, 0xbe5372cd
+0, 113, 113, 1, 192000, 0x0fec4000
+0, 114, 114, 1, 192000, 0x80e9340c
+0, 115, 115, 1, 192000, 0xea582818
+0, 116, 116, 1, 192000, 0x5c3a2e12
+0, 117, 117, 1, 192000, 0x5c2b4ef1
+0, 118, 118, 1, 192000, 0xf2409fa0
+0, 119, 119, 1, 192000, 0x4bc472cd
+0, 120, 120, 1, 192000, 0x3dcb96a9
+0, 121, 121, 1, 192000, 0xff978ab5
+0, 122, 122, 1, 192000, 0xff72013f
+0, 123, 123, 1, 192000, 0x2f530d33
+0, 124, 124, 1, 192000, 0xa3350d33
+0, 125, 125, 1, 192000, 0x6be6251b
+0, 126, 126, 1, 192000, 0x07f081be
+0, 127, 127, 1, 192000, 0xb5d957e8
+0, 128, 128, 1, 192000, 0x43c551ee
+0, 129, 129, 1, 192000, 0x19224ef1
+0, 130, 130, 1, 192000, 0x0720e64b
+0, 131, 131, 1, 192000, 0x3c53f53c
+0, 132, 132, 1, 192000, 0x8534043c
+0, 133, 133, 1, 192000, 0xb7c7ef42
+0, 134, 134, 1, 192000, 0x9e3e0739
+0, 135, 135, 1, 192000, 0x95e43d03
+0, 136, 136, 1, 192000, 0x92473d03
+0, 137, 137, 1, 192000, 0x636757e8
+0, 138, 138, 1, 192000, 0xba3aec45
+0, 139, 139, 1, 192000, 0xfd9e013f
+0, 140, 140, 1, 192000, 0x108c1927
+0, 141, 141, 1, 192000, 0x29db1030
+0, 142, 142, 1, 192000, 0xe0172e12
+0, 143, 143, 1, 192000, 0x744260df
+0, 144, 144, 1, 192000, 0xc59478c7
+0, 145, 145, 1, 192000, 0xa84475ca
+0, 146, 146, 1, 192000, 0x9d2866d9
+0, 147, 147, 1, 192000, 0xc49342fd
+0, 148, 148, 1, 192000, 0x13e5bd82
+0, 149, 149, 1, 192000, 0x10d10549
+0, 150, 150, 1, 192000, 0xf5ca3b13
+0, 151, 151, 1, 192000, 0x8c27a9a4
+0, 152, 152, 1, 192000, 0xcc4f64e9
+0, 153, 153, 1, 192000, 0x020c67e6
+0, 154, 154, 1, 192000, 0xaf4773da
+0, 155, 155, 1, 192000, 0x62093e10
+0, 156, 156, 1, 192000, 0x96783519
+0, 157, 157, 1, 192000, 0x8b9a113d
+0, 158, 158, 1, 192000, 0x9050f946
diff --git a/tests/ref/fate/zmbv-16bit b/tests/ref/fate/zmbv-16bit
index b0c3df5513..cb390148f1 100644
--- a/tests/ref/fate/zmbv-16bit
+++ b/tests/ref/fate/zmbv-16bit
@@ -1,123 +1,123 @@
#tb 0: 250000/1585341
-0, 0, 0, 1, 192000, 0x11e62dbe
-0, 1, 1, 1, 192000, 0x31698b8f
-0, 2, 2, 1, 192000, 0x31698b8f
-0, 3, 3, 1, 192000, 0x31698b8f
-0, 4, 4, 1, 192000, 0x31698b8f
-0, 5, 5, 1, 192000, 0x31698b8f
-0, 6, 6, 1, 192000, 0x31698b8f
-0, 7, 7, 1, 192000, 0x31698b8f
-0, 8, 8, 1, 192000, 0x31698b8f
-0, 9, 9, 1, 192000, 0x31698b8f
-0, 10, 10, 1, 192000, 0x31698b8f
-0, 11, 11, 1, 192000, 0x31698b8f
-0, 12, 12, 1, 192000, 0x31698b8f
-0, 13, 13, 1, 192000, 0x4ca609ea
-0, 14, 14, 1, 192000, 0x4ca609ea
-0, 15, 15, 1, 192000, 0x4ca609ea
-0, 16, 16, 1, 192000, 0x4ca609ea
-0, 17, 17, 1, 192000, 0x33dd0a8b
-0, 18, 18, 1, 192000, 0x33dd0a8b
-0, 19, 19, 1, 192000, 0x33dd0a8b
-0, 20, 20, 1, 192000, 0x33dd0a8b
-0, 21, 21, 1, 192000, 0x33dd0a8b
-0, 22, 22, 1, 192000, 0x08e2420f
-0, 23, 23, 1, 192000, 0x08e2420f
-0, 24, 24, 1, 192000, 0x08e2420f
-0, 25, 25, 1, 192000, 0x08e2420f
-0, 26, 26, 1, 192000, 0x7b7b50ab
-0, 27, 27, 1, 192000, 0x7b7b50ab
-0, 28, 28, 1, 192000, 0x7b7b50ab
-0, 29, 29, 1, 192000, 0x7b7b50ab
-0, 30, 30, 1, 192000, 0x7b7b50ab
-0, 31, 31, 1, 192000, 0x128744fb
-0, 32, 32, 1, 192000, 0x128744fb
-0, 33, 33, 1, 192000, 0x128744fb
-0, 34, 34, 1, 192000, 0x128744fb
-0, 35, 35, 1, 192000, 0x8643163b
-0, 36, 36, 1, 192000, 0x8643163b
-0, 37, 37, 1, 192000, 0x8643163b
-0, 38, 38, 1, 192000, 0x8643163b
-0, 39, 39, 1, 192000, 0x8643163b
-0, 40, 40, 1, 192000, 0x4f7c596f
-0, 41, 41, 1, 192000, 0x4f7c596f
-0, 42, 42, 1, 192000, 0x4f7c596f
-0, 43, 43, 1, 192000, 0x4f7c596f
-0, 44, 44, 1, 192000, 0xa275420f
-0, 45, 45, 1, 192000, 0xa275420f
-0, 46, 46, 1, 192000, 0xa275420f
-0, 47, 47, 1, 192000, 0xa275420f
-0, 48, 48, 1, 192000, 0xa275420f
-0, 49, 49, 1, 192000, 0x2e4796cb
-0, 50, 50, 1, 192000, 0x2e4796cb
-0, 51, 51, 1, 192000, 0x2e4796cb
-0, 52, 52, 1, 192000, 0x2e4796cb
-0, 53, 53, 1, 192000, 0xebd45683
-0, 54, 54, 1, 192000, 0xebd45683
-0, 55, 55, 1, 192000, 0xebd45683
-0, 56, 56, 1, 192000, 0xebd45683
-0, 57, 57, 1, 192000, 0xebd45683
-0, 58, 58, 1, 192000, 0x0bf6596f
-0, 59, 59, 1, 192000, 0x0bf6596f
-0, 60, 60, 1, 192000, 0x0bf6596f
-0, 61, 61, 1, 192000, 0x0bf6596f
-0, 62, 62, 1, 192000, 0xb7af47e7
-0, 63, 63, 1, 192000, 0xb7af47e7
-0, 64, 64, 1, 192000, 0xb7af47e7
-0, 65, 65, 1, 192000, 0xb7af47e7
-0, 66, 66, 1, 192000, 0xb7af47e7
-0, 67, 67, 1, 192000, 0x8bc344fb
-0, 68, 68, 1, 192000, 0x8bc344fb
-0, 69, 69, 1, 192000, 0x8bc344fb
-0, 70, 70, 1, 192000, 0x8bc344fb
-0, 71, 71, 1, 192000, 0x8bc344fb
-0, 72, 72, 1, 192000, 0x02a23f23
-0, 73, 73, 1, 192000, 0x02a23f23
-0, 74, 74, 1, 192000, 0x02a23f23
-0, 75, 75, 1, 192000, 0x02a23f23
-0, 76, 76, 1, 192000, 0x17be3087
-0, 77, 77, 1, 192000, 0x52c7b2d4
-0, 78, 78, 1, 192000, 0xa05e9888
-0, 79, 79, 1, 192000, 0x4d6a6cb4
-0, 80, 80, 1, 192000, 0x3e2189ec
-0, 81, 81, 1, 192000, 0xfbe3ca34
-0, 82, 82, 1, 192000, 0xa9cd8fc4
-0, 83, 83, 1, 192000, 0x986e6cb4
-0, 84, 84, 1, 192000, 0x42373b08
-0, 85, 85, 1, 192000, 0xab96e351
-0, 86, 86, 1, 192000, 0x28ccf4d9
-0, 87, 87, 1, 192000, 0xc19e0f34
-0, 88, 88, 1, 192000, 0xd8da1ae4
-0, 89, 89, 1, 192000, 0xd015728c
-0, 90, 90, 1, 192000, 0x550623a8
-0, 91, 91, 1, 192000, 0x3c5c5268
-0, 92, 92, 1, 192000, 0x3eae8128
-0, 93, 93, 1, 192000, 0x3c51381c
-0, 94, 94, 1, 192000, 0x745046b8
-0, 95, 95, 1, 192000, 0xa8bd43cc
-0, 96, 96, 1, 192000, 0xde8fe351
-0, 97, 97, 1, 192000, 0x3d5cc905
-0, 98, 98, 1, 192000, 0xcf8df4d9
-0, 99, 99, 1, 192000, 0x698b20bc
-0, 100, 100, 1, 192000, 0x159d3244
-0, 101, 101, 1, 192000, 0xba1af4d9
-0, 102, 102, 1, 192000, 0x033a0f34
-0, 103, 103, 1, 192000, 0x72612f58
-0, 104, 104, 1, 192000, 0x11e11dd0
-0, 105, 105, 1, 192000, 0x4fc04f7c
-0, 106, 106, 1, 192000, 0x37779888
-0, 107, 107, 1, 192000, 0xabfc5e18
-0, 108, 108, 1, 192000, 0x0ad97e3c
-0, 109, 109, 1, 192000, 0xddf492b0
-0, 110, 110, 1, 192000, 0x198b23a8
-0, 111, 111, 1, 192000, 0x6b491220
-0, 112, 112, 1, 192000, 0x632417f8
-0, 113, 113, 1, 192000, 0x0dc5381c
-0, 114, 114, 1, 192000, 0x6d548700
-0, 115, 115, 1, 192000, 0xae0c5b2c
-0, 116, 116, 1, 192000, 0x23427e3c
-0, 117, 117, 1, 192000, 0x5def728c
-0, 118, 118, 1, 192000, 0xec831ae4
+0, 0, 0, 1, 192000, 0xe869dc94
+0, 1, 1, 1, 192000, 0x742932f2
+0, 2, 2, 1, 192000, 0x742932f2
+0, 3, 3, 1, 192000, 0x742932f2
+0, 4, 4, 1, 192000, 0x742932f2
+0, 5, 5, 1, 192000, 0x742932f2
+0, 6, 6, 1, 192000, 0x742932f2
+0, 7, 7, 1, 192000, 0x742932f2
+0, 8, 8, 1, 192000, 0x742932f2
+0, 9, 9, 1, 192000, 0x742932f2
+0, 10, 10, 1, 192000, 0x742932f2
+0, 11, 11, 1, 192000, 0x742932f2
+0, 12, 12, 1, 192000, 0x742932f2
+0, 13, 13, 1, 192000, 0xb718e72e
+0, 14, 14, 1, 192000, 0xb718e72e
+0, 15, 15, 1, 192000, 0xb718e72e
+0, 16, 16, 1, 192000, 0xb718e72e
+0, 17, 17, 1, 192000, 0x7507f946
+0, 18, 18, 1, 192000, 0x7507f946
+0, 19, 19, 1, 192000, 0x7507f946
+0, 20, 20, 1, 192000, 0x7507f946
+0, 21, 21, 1, 192000, 0x7507f946
+0, 22, 22, 1, 192000, 0xe620321c
+0, 23, 23, 1, 192000, 0xe620321c
+0, 24, 24, 1, 192000, 0xe620321c
+0, 25, 25, 1, 192000, 0xe620321c
+0, 26, 26, 1, 192000, 0x9b5f410d
+0, 27, 27, 1, 192000, 0x9b5f410d
+0, 28, 28, 1, 192000, 0x9b5f410d
+0, 29, 29, 1, 192000, 0x9b5f410d
+0, 30, 30, 1, 192000, 0x9b5f410d
+0, 31, 31, 1, 192000, 0xea2c3519
+0, 32, 32, 1, 192000, 0xea2c3519
+0, 33, 33, 1, 192000, 0xea2c3519
+0, 34, 34, 1, 192000, 0xea2c3519
+0, 35, 35, 1, 192000, 0x1acb0549
+0, 36, 36, 1, 192000, 0x1acb0549
+0, 37, 37, 1, 192000, 0x1acb0549
+0, 38, 38, 1, 192000, 0x1acb0549
+0, 39, 39, 1, 192000, 0x1acb0549
+0, 40, 40, 1, 192000, 0x3a064a04
+0, 41, 41, 1, 192000, 0x3a064a04
+0, 42, 42, 1, 192000, 0x3a064a04
+0, 43, 43, 1, 192000, 0x3a064a04
+0, 44, 44, 1, 192000, 0xcede321c
+0, 45, 45, 1, 192000, 0xcede321c
+0, 46, 46, 1, 192000, 0xcede321c
+0, 47, 47, 1, 192000, 0xcede321c
+0, 48, 48, 1, 192000, 0xcede321c
+0, 49, 49, 1, 192000, 0xef4988c5
+0, 50, 50, 1, 192000, 0xef4988c5
+0, 51, 51, 1, 192000, 0xef4988c5
+0, 52, 52, 1, 192000, 0xef4988c5
+0, 53, 53, 1, 192000, 0x1fc84707
+0, 54, 54, 1, 192000, 0x1fc84707
+0, 55, 55, 1, 192000, 0x1fc84707
+0, 56, 56, 1, 192000, 0x1fc84707
+0, 57, 57, 1, 192000, 0x1fc84707
+0, 58, 58, 1, 192000, 0xbabd4a04
+0, 59, 59, 1, 192000, 0xbabd4a04
+0, 60, 60, 1, 192000, 0xbabd4a04
+0, 61, 61, 1, 192000, 0xbabd4a04
+0, 62, 62, 1, 192000, 0x649b3816
+0, 63, 63, 1, 192000, 0x649b3816
+0, 64, 64, 1, 192000, 0x649b3816
+0, 65, 65, 1, 192000, 0x649b3816
+0, 66, 66, 1, 192000, 0x649b3816
+0, 67, 67, 1, 192000, 0x206b3519
+0, 68, 68, 1, 192000, 0x206b3519
+0, 69, 69, 1, 192000, 0x206b3519
+0, 70, 70, 1, 192000, 0x206b3519
+0, 71, 71, 1, 192000, 0x206b3519
+0, 72, 72, 1, 192000, 0x25982f1f
+0, 73, 73, 1, 192000, 0x25982f1f
+0, 74, 74, 1, 192000, 0x25982f1f
+0, 75, 75, 1, 192000, 0x25982f1f
+0, 76, 76, 1, 192000, 0xde0e202e
+0, 77, 77, 1, 192000, 0xced09fa0
+0, 78, 78, 1, 192000, 0x3b4f84bb
+0, 79, 79, 1, 192000, 0xa09c57e8
+0, 80, 80, 1, 192000, 0xf3dd75ca
+0, 81, 81, 1, 192000, 0x4d4ab788
+0, 82, 82, 1, 192000, 0x4ac67bc4
+0, 83, 83, 1, 192000, 0xd61057e8
+0, 84, 84, 1, 192000, 0x03bc251b
+0, 85, 85, 1, 192000, 0xd263cb66
+0, 86, 86, 1, 192000, 0xe3dddd54
+0, 87, 87, 1, 192000, 0x460cf839
+0, 88, 88, 1, 192000, 0xbae1043c
+0, 89, 89, 1, 192000, 0xe6435de2
+0, 90, 90, 1, 192000, 0x340e0d33
+0, 91, 91, 1, 192000, 0x9acd3d03
+0, 92, 92, 1, 192000, 0x1d346cd3
+0, 93, 93, 1, 192000, 0xdabe221e
+0, 94, 94, 1, 192000, 0xeb4b310f
+0, 95, 95, 1, 192000, 0xec8f2e12
+0, 96, 96, 1, 192000, 0xe96fcb66
+0, 97, 97, 1, 192000, 0x3ec1b081
+0, 98, 98, 1, 192000, 0xb72fdd54
+0, 99, 99, 1, 192000, 0xced40a36
+0, 100, 100, 1, 192000, 0x56171c24
+0, 101, 101, 1, 192000, 0xc9f7dd54
+0, 102, 102, 1, 192000, 0x0eeff839
+0, 103, 103, 1, 192000, 0x295c1927
+0, 104, 104, 1, 192000, 0xdde00739
+0, 105, 105, 1, 192000, 0x51903a06
+0, 106, 106, 1, 192000, 0xe16a84bb
+0, 107, 107, 1, 192000, 0xf5b248f7
+0, 108, 108, 1, 192000, 0x054769d6
+0, 109, 109, 1, 192000, 0x9d327ec1
+0, 110, 110, 1, 192000, 0x94470d33
+0, 111, 111, 1, 192000, 0x9671fb36
+0, 112, 112, 1, 192000, 0x0853013f
+0, 113, 113, 1, 192000, 0x0844221e
+0, 114, 114, 1, 192000, 0x9e5972cd
+0, 115, 115, 1, 192000, 0xf7ce45fa
+0, 116, 116, 1, 192000, 0xe9d569d6
+0, 117, 117, 1, 192000, 0xabb05de2
+0, 118, 118, 1, 192000, 0x54d5043c
0, 119, 119, 1, 192000, 0x00000000
0, 120, 120, 1, 192000, 0x00000000
0, 121, 121, 1, 192000, 0x00000000
diff --git a/tests/ref/lavf-fate/latm b/tests/ref/lavf-fate/latm
new file mode 100644
index 0000000000..8c4f5412aa
--- /dev/null
+++ b/tests/ref/lavf-fate/latm
@@ -0,0 +1,3 @@
+eb13788e71c9b5bc7d62ceb748312bbb *./tests/data/lavf-fate/lavf.latm
+67876 ./tests/data/lavf-fate/lavf.latm
+./tests/data/lavf-fate/lavf.latm CRC=0xcf94c59d
diff --git a/tests/ref/lavf-fate/mp3 b/tests/ref/lavf-fate/mp3
new file mode 100644
index 0000000000..b5595387a6
--- /dev/null
+++ b/tests/ref/lavf-fate/mp3
@@ -0,0 +1,3 @@
+f231c5316357fd747573cbcb02f889c5 *./tests/data/lavf-fate/lavf.mp3
+96016 ./tests/data/lavf-fate/lavf.mp3
+./tests/data/lavf-fate/lavf.mp3 CRC=0x6c9850fe
diff --git a/tests/ref/lavf-fate/ogg_vp3 b/tests/ref/lavf-fate/ogg_vp3
new file mode 100644
index 0000000000..9e9cc7ea6b
--- /dev/null
+++ b/tests/ref/lavf-fate/ogg_vp3
@@ -0,0 +1,3 @@
+4bd51dac3194fa88ae33767c25b4b1e6 *./tests/data/lavf-fate/lavf.ogg
+417621 ./tests/data/lavf-fate/lavf.ogg
+./tests/data/lavf-fate/lavf.ogg CRC=0x037e3e79
diff --git a/tests/ref/lavf/aiff b/tests/ref/lavf/aiff
index c713d02909..c504c18c4a 100644
--- a/tests/ref/lavf/aiff
+++ b/tests/ref/lavf/aiff
@@ -1,3 +1,3 @@
-9d9e55431800bf6aea46a7d67509da4e *./tests/data/lavf/lavf.aif
-88254 ./tests/data/lavf/lavf.aif
+2c129d88acef834e32869145fe792b9c *./tests/data/lavf/lavf.aif
+88270 ./tests/data/lavf/lavf.aif
./tests/data/lavf/lavf.aif CRC=0x3a1da17e
diff --git a/tests/ref/lavf/asf b/tests/ref/lavf/asf
index 2178435a52..400278cd94 100644
--- a/tests/ref/lavf/asf
+++ b/tests/ref/lavf/asf
@@ -1,3 +1,3 @@
-33e857a06b2b5dedce0bf76c9973944c *./tests/data/lavf/lavf.asf
-333379 ./tests/data/lavf/lavf.asf
+1a8716a0358b8123c02557dfdf6c259b *./tests/data/lavf/lavf.asf
+333585 ./tests/data/lavf/lavf.asf
./tests/data/lavf/lavf.asf CRC=0xf6340a10
diff --git a/tests/ref/lavf/ast b/tests/ref/lavf/ast
new file mode 100644
index 0000000000..513c612e76
--- /dev/null
+++ b/tests/ref/lavf/ast
@@ -0,0 +1,3 @@
+07f5d23aa8bade984034f7005bd72947 *./tests/data/lavf/lavf.ast
+177872 ./tests/data/lavf/lavf.ast
+./tests/data/lavf/lavf.ast CRC=0xe61e3bd0
diff --git a/tests/ref/lavf/au b/tests/ref/lavf/au
index 71cfdcb552..ede4926a4c 100644
--- a/tests/ref/lavf/au
+++ b/tests/ref/lavf/au
@@ -1,3 +1,3 @@
-b9396e3775ea009094e751e7128d614e *./tests/data/lavf/lavf.au
-88224 ./tests/data/lavf/lavf.au
+aa5ec1f82ac07c653ffc527b0f0dc10d *./tests/data/lavf/lavf.au
+88232 ./tests/data/lavf/lavf.au
./tests/data/lavf/lavf.au CRC=0x3a1da17e
diff --git a/tests/ref/lavf/avi b/tests/ref/lavf/avi
index 08ae04206d..8b14370748 100644
--- a/tests/ref/lavf/avi
+++ b/tests/ref/lavf/avi
@@ -1,3 +1,3 @@
-e2e7b7ceaf038b259558f41df203ded9 *./tests/data/lavf/lavf.avi
-330786 ./tests/data/lavf/lavf.avi
-./tests/data/lavf/lavf.avi CRC=0x4c963cda
+07a29d329e7f07a4fd682145c3771995 *./tests/data/lavf/lavf.avi
+330814 ./tests/data/lavf/lavf.avi
+./tests/data/lavf/lavf.avi CRC=0xec6c3c68
diff --git a/tests/ref/lavf/bmp b/tests/ref/lavf/bmp
index b79ee4d47c..8958855eee 100644
--- a/tests/ref/lavf/bmp
+++ b/tests/ref/lavf/bmp
@@ -1,3 +1,3 @@
71f4d64a6b3c71f43a4eff526f84841c *./tests/data/images/bmp/02.bmp
-./tests/data/images/bmp/%02d.bmp CRC=0x3447369b
+./tests/data/images/bmp/%02d.bmp CRC=0xe6c71946
304182 ./tests/data/images/bmp/02.bmp
diff --git a/tests/ref/lavf/caf b/tests/ref/lavf/caf
new file mode 100644
index 0000000000..7b2a67d1c0
--- /dev/null
+++ b/tests/ref/lavf/caf
@@ -0,0 +1,3 @@
+c3c38cba600722c87c0e75bd0688b7fc *./tests/data/lavf/lavf.caf
+88323 ./tests/data/lavf/lavf.caf
+./tests/data/lavf/lavf.caf CRC=0x3a1da17e
diff --git a/tests/ref/lavf/dpx b/tests/ref/lavf/dpx
index 42c0a335fb..591ef1b4c4 100644
--- a/tests/ref/lavf/dpx
+++ b/tests/ref/lavf/dpx
@@ -1,3 +1,18 @@
-d2f0b4e854fda2d3b3bee84cef80593c *./tests/data/images/dpx/02.dpx
-./tests/data/images/dpx/%02d.dpx CRC=0x28c7369b
+4c8880d5835ffb5fe37c1ed8c8d404de *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0x6da01946
305792 ./tests/data/images/dpx/02.dpx
+16d65ceaa127806dc7ede9391fe80872 *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0x22dcc7a8
+407168 ./tests/data/images/dpx/02.dpx
+02b4fd859d944075905e84e9f389bf23 *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0x964b87ba
+609920 ./tests/data/images/dpx/02.dpx
+075963c3c08978b6a20555ba09161434 *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0xe5b9c023
+609920 ./tests/data/images/dpx/02.dpx
+b9f22728f8ff393bf30cf6cbd624fa95 *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0xf38d5830
+407168 ./tests/data/images/dpx/02.dpx
+545603630f30dec2768c8ae8d12eb8ea *./tests/data/images/dpx/02.dpx
+./tests/data/images/dpx/%02d.dpx CRC=0xe72ce131
+812672 ./tests/data/images/dpx/02.dpx
diff --git a/tests/ref/lavf/dv_fmt b/tests/ref/lavf/dv_fmt
index c2b7335001..b152c84ca8 100644
--- a/tests/ref/lavf/dv_fmt
+++ b/tests/ref/lavf/dv_fmt
@@ -1,3 +1,9 @@
-eb51fbb48af28584ea5515f9f2400fcd *./tests/data/lavf/lavf.dv
+11be3e5caa2892236b3475c3f7807b76 *./tests/data/lavf/lavf.dv
3600000 ./tests/data/lavf/lavf.dv
-./tests/data/lavf/lavf.dv CRC=0x0e868a82
+./tests/data/lavf/lavf.dv CRC=0x0b2cd3ec
+e9949bc767924e1e7d28856029fee024 *./tests/data/lavf/lavf.dv
+3480000 ./tests/data/lavf/lavf.dv
+./tests/data/lavf/lavf.dv CRC=0xfab17c4a
+87d3b20f656235671383a7eaa2f66330 *./tests/data/lavf/lavf.dv
+3600000 ./tests/data/lavf/lavf.dv
+./tests/data/lavf/lavf.dv CRC=0xf3e6873c
diff --git a/tests/ref/lavf/ffm b/tests/ref/lavf/ffm
new file mode 100644
index 0000000000..5de2f39b60
--- /dev/null
+++ b/tests/ref/lavf/ffm
@@ -0,0 +1,3 @@
+d5d4e5e3eec336ae6680dde035870564 *./tests/data/lavf/lavf.ffm
+376832 ./tests/data/lavf/lavf.ffm
+./tests/data/lavf/lavf.ffm CRC=0x000e23ae
diff --git a/tests/ref/lavf/flm b/tests/ref/lavf/flm
new file mode 100644
index 0000000000..59aac922ae
--- /dev/null
+++ b/tests/ref/lavf/flm
@@ -0,0 +1,3 @@
+ef4783171ebbc38855331c9ead978322 *./tests/data/lavf/lavf.flm
+10137636 ./tests/data/lavf/lavf.flm
+./tests/data/lavf/lavf.flm CRC=0xcdf15757
diff --git a/tests/ref/lavf/flv_fmt b/tests/ref/lavf/flv_fmt
index 019204d16a..f014bec708 100644
--- a/tests/ref/lavf/flv_fmt
+++ b/tests/ref/lavf/flv_fmt
@@ -1,3 +1,3 @@
-822735e9d25b3eb22529f444a71840c3 *./tests/data/lavf/lavf.flv
-329521 ./tests/data/lavf/lavf.flv
-./tests/data/lavf/lavf.flv CRC=0x881785d1
+0d229f87b3aad778074ace499359d137 *./tests/data/lavf/lavf.flv
+329554 ./tests/data/lavf/lavf.flv
+./tests/data/lavf/lavf.flv CRC=0x4eac88c5
diff --git a/tests/ref/lavf/gif b/tests/ref/lavf/gif
index 4a4ebfb9dc..d2e2f11e9d 100644
--- a/tests/ref/lavf/gif
+++ b/tests/ref/lavf/gif
@@ -1,3 +1,3 @@
-e6089fd4ef3b9df44090ab3650bdd810 *./tests/data/lavf/lavf.gif
-2906401 ./tests/data/lavf/lavf.gif
-./tests/data/lavf/lavf.gif CRC=0xe5605ff6
+e35f5ea283bbcb249818e0078ec72664 *./tests/data/lavf/lavf.gif
+2011766 ./tests/data/lavf/lavf.gif
+./tests/data/lavf/lavf.gif CRC=0x2429faff
diff --git a/tests/ref/lavf/gxf b/tests/ref/lavf/gxf
index 8dfd63d646..d356f20811 100644
--- a/tests/ref/lavf/gxf
+++ b/tests/ref/lavf/gxf
@@ -1,3 +1,9 @@
-a1cf0a335ad64ec526bb69bbca0656c2 *./tests/data/lavf/lavf.gxf
-796428 ./tests/data/lavf/lavf.gxf
-./tests/data/lavf/lavf.gxf CRC=0xd04c769f
+7993da95d8bfe04832e27892c163e562 *./tests/data/lavf/lavf.gxf
+795876 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0xda7cebbc
+9e873074b5c3ef1d80d233a38e7de156 *./tests/data/lavf/lavf.gxf
+794656 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0x7f0c9089
+0638c4d073ac224608baaba16732b68f *./tests/data/lavf/lavf.gxf
+795876 ./tests/data/lavf/lavf.gxf
+./tests/data/lavf/lavf.gxf CRC=0x5ade0285
diff --git a/tests/ref/lavf/ircam b/tests/ref/lavf/ircam
new file mode 100644
index 0000000000..47e07098e5
--- /dev/null
+++ b/tests/ref/lavf/ircam
@@ -0,0 +1,3 @@
+45d9a4667030e95d1d8fb6ab012f1aa0 *./tests/data/lavf/lavf.ircam
+89224 ./tests/data/lavf/lavf.ircam
+./tests/data/lavf/lavf.ircam CRC=0x3a1da17e
diff --git a/tests/ref/lavf/ismv b/tests/ref/lavf/ismv
new file mode 100644
index 0000000000..f29b5ff3ef
--- /dev/null
+++ b/tests/ref/lavf/ismv
@@ -0,0 +1,9 @@
+a9ccbb4cd1436d222ef4425567b4e03d *./tests/data/lavf/lavf.ismv
+312542 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0x9d9a638a
+440d85f9fd5b9f63c2676638782b5c15 *./tests/data/lavf/lavf.ismv
+321448 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0xe8130120
+a9ccbb4cd1436d222ef4425567b4e03d *./tests/data/lavf/lavf.ismv
+312542 ./tests/data/lavf/lavf.ismv
+./tests/data/lavf/lavf.ismv CRC=0x9d9a638a
diff --git a/tests/ref/lavf/jpg b/tests/ref/lavf/jpg
index 584a97a285..1309d742c8 100644
--- a/tests/ref/lavf/jpg
+++ b/tests/ref/lavf/jpg
@@ -1,3 +1,3 @@
131878fee153a086d740543fbf2ab359 *./tests/data/images/jpg/02.jpg
-./tests/data/images/jpg/%02d.jpg CRC=0x9d770966
+./tests/data/images/jpg/%02d.jpg CRC=0xe3509f33
28406 ./tests/data/images/jpg/02.jpg
diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv
index a871ea9fd9..edbfe60a00 100644
--- a/tests/ref/lavf/mkv
+++ b/tests/ref/lavf/mkv
@@ -1,3 +1,6 @@
-268fb8f9278b0df2f87a6a9455f3cd56 *./tests/data/lavf/lavf.mkv
-320380 ./tests/data/lavf/lavf.mkv
-./tests/data/lavf/lavf.mkv CRC=0x36193cda
+bab98f5a04a9f7991fb960041c996478 *./tests/data/lavf/lavf.mkv
+472668 ./tests/data/lavf/lavf.mkv
+./tests/data/lavf/lavf.mkv CRC=0xec6c3c68
+c93950920d4ee57eb3ff5ba0cf0c8b19 *./tests/data/lavf/lavf.mkv
+320412 ./tests/data/lavf/lavf.mkv
+./tests/data/lavf/lavf.mkv CRC=0xec6c3c68
diff --git a/tests/ref/lavf/mmf b/tests/ref/lavf/mmf
index 947abc746b..fae95cadd5 100644
--- a/tests/ref/lavf/mmf
+++ b/tests/ref/lavf/mmf
@@ -1,3 +1,3 @@
-1a3bbf19a41668c1e928bcafce88ff3e *./tests/data/lavf/lavf.mmf
-22617 ./tests/data/lavf/lavf.mmf
+643fadf7482f6d937ed75ec4f508e4f1 *./tests/data/lavf/lavf.mmf
+22611 ./tests/data/lavf/lavf.mmf
./tests/data/lavf/lavf.mmf CRC=0x8dea1388
diff --git a/tests/ref/lavf/mov b/tests/ref/lavf/mov
index f34a006fb4..72d962aad5 100644
--- a/tests/ref/lavf/mov
+++ b/tests/ref/lavf/mov
@@ -1,3 +1,12 @@
-e46f42ed71a589ac356e9cfad4e1e56a *./tests/data/lavf/lavf.mov
-356797 ./tests/data/lavf/lavf.mov
-./tests/data/lavf/lavf.mov CRC=0xe3f4950d
+a10d50f2679df92264e1fc21cb8be630 *./tests/data/lavf/lavf.mov
+366449 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xbb2b949b
+6258f70f974e3c802e01d02ac33c7bbd *./tests/data/lavf/lavf.mov
+357539 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xbb2b949b
+ba3b8b49e420510a0d417400dbedfc2d *./tests/data/lavf/lavf.mov
+366621 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xa9793231
+fd0e4de8e7f6d0c8c0681d7020f00f50 *./tests/data/lavf/lavf.mov
+356921 ./tests/data/lavf/lavf.mov
+./tests/data/lavf/lavf.mov CRC=0xbb2b949b
diff --git a/tests/ref/lavf/mpg b/tests/ref/lavf/mpg
index e4c8ae0c17..7aab14f84b 100644
--- a/tests/ref/lavf/mpg
+++ b/tests/ref/lavf/mpg
@@ -1,3 +1,9 @@
-7df31ba8a5909e3c88b1d1a3f93c4ec2 *./tests/data/lavf/lavf.mpg
+01bbdea588da51ab4a9d1d26f3443c96 *./tests/data/lavf/lavf.mpg
372736 ./tests/data/lavf/lavf.mpg
-./tests/data/lavf/lavf.mpg CRC=0xdd24439e
+./tests/data/lavf/lavf.mpg CRC=0x000e23ae
+87b447b78a7d1141b9d41bb3aa50434d *./tests/data/lavf/lavf.mpg
+389120 ./tests/data/lavf/lavf.mpg
+./tests/data/lavf/lavf.mpg CRC=0x60ba4ab9
+284f41c914df75c12de01e223d65f87f *./tests/data/lavf/lavf.mpg
+372736 ./tests/data/lavf/lavf.mpg
+./tests/data/lavf/lavf.mpg CRC=0x000e23ae
diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf
index 09e3c36bbc..4885bee753 100644
--- a/tests/ref/lavf/mxf
+++ b/tests/ref/lavf/mxf
@@ -1,3 +1,9 @@
-051b982c1b5799eb107339735a090c70 *./tests/data/lavf/lavf.mxf
+bda6be285b4f275b6d8a74e1c5c5aec9 *./tests/data/lavf/lavf.mxf
525881 ./tests/data/lavf/lavf.mxf
-./tests/data/lavf/lavf.mxf CRC=0x773f059a
+./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1
+a93989cd8e80e9edcce60a2f01eb068b *./tests/data/lavf/lavf.mxf
+561209 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0x11a6178e
+c0b9255defc9f0494084e2b286f222b9 *./tests/data/lavf/lavf.mxf
+525881 ./tests/data/lavf/lavf.mxf
+./tests/data/lavf/lavf.mxf CRC=0xdbfff6f1
diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10
index 5864e8e5ce..9324465448 100644
--- a/tests/ref/lavf/mxf_d10
+++ b/tests/ref/lavf/mxf_d10
@@ -1,3 +1,3 @@
-8cf467a910c84dd05db24848becba42e *./tests/data/lavf/lavf.mxf_d10
+bb8f8e2661e1c81fe4e1ce7900b54200 *./tests/data/lavf/lavf.mxf_d10
5330989 ./tests/data/lavf/lavf.mxf_d10
-./tests/data/lavf/lavf.mxf_d10 CRC=0x4474d480
+./tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488
diff --git a/tests/ref/lavf/mxf_opatom b/tests/ref/lavf/mxf_opatom
new file mode 100644
index 0000000000..9c9ab15b56
--- /dev/null
+++ b/tests/ref/lavf/mxf_opatom
@@ -0,0 +1,3 @@
+2c1a3b94af9e7c606532b1b636902b3a *./tests/data/lavf/lavf.mxf_opatom
+4717113 ./tests/data/lavf/lavf.mxf_opatom
+./tests/data/lavf/lavf.mxf_opatom CRC=0xbdd696b9
diff --git a/tests/ref/lavf/mxf_opatom_audio b/tests/ref/lavf/mxf_opatom_audio
new file mode 100644
index 0000000000..2f79246fed
--- /dev/null
+++ b/tests/ref/lavf/mxf_opatom_audio
@@ -0,0 +1,3 @@
+d571768dd4e32b56917fb76abdb40570 *./tests/data/lavf/lavf.mxf_opatom_audio
+102457 ./tests/data/lavf/lavf.mxf_opatom_audio
+./tests/data/lavf/lavf.mxf_opatom_audio CRC=0xd155c6ff
diff --git a/tests/ref/lavf/nut b/tests/ref/lavf/nut
index bdbe8232ef..1c3d7107da 100644
--- a/tests/ref/lavf/nut
+++ b/tests/ref/lavf/nut
@@ -1,3 +1,3 @@
-d685d5af89cfddb2660f03b1dee3f9a2 *./tests/data/lavf/lavf.nut
-319711 ./tests/data/lavf/lavf.nut
-./tests/data/lavf/lavf.nut CRC=0x4c963cda
+424e8037d7b6f3d3c09cf76bf06a63cb *./tests/data/lavf/lavf.nut
+319958 ./tests/data/lavf/lavf.nut
+./tests/data/lavf/lavf.nut CRC=0xec6c3c68
diff --git a/tests/ref/lavf/ogg b/tests/ref/lavf/ogg
index ea827acd4c..a08fb5ed82 100644
--- a/tests/ref/lavf/ogg
+++ b/tests/ref/lavf/ogg
@@ -1,3 +1,3 @@
-8ca901bc8d24b80ebe79e387e454d1e9 *./tests/data/lavf/lavf.ogg
-13476 ./tests/data/lavf/lavf.ogg
+81b9366cacb23644c2803585dced9996 *./tests/data/lavf/lavf.ogg
+13516 ./tests/data/lavf/lavf.ogg
./tests/data/lavf/lavf.ogg CRC=0x3a1da17e
diff --git a/tests/ref/lavf/pam b/tests/ref/lavf/pam
index 636a419a47..abb29743d0 100644
--- a/tests/ref/lavf/pam
+++ b/tests/ref/lavf/pam
@@ -1,3 +1,18 @@
0dce5565222cf0f8b309467f279aecd2 *./tests/data/images/pam/02.pam
-./tests/data/images/pam/%02d.pam CRC=0x28c7369b
+./tests/data/images/pam/%02d.pam CRC=0x6da01946
304191 ./tests/data/images/pam/02.pam
+2ed31ca8d8de560afb3e0fd7a873cde5 *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0xf07d29cd
+405573 ./tests/data/images/pam/02.pam
+35cb9e42b2d3181be494f8693af1ddea *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0x0ff205be
+101445 ./tests/data/images/pam/02.pam
+740eb42157af9e9eed46b70ba6a6cf4d *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0x893f10ef
+202823 ./tests/data/images/pam/02.pam
+032538f0313b4f240b44a5bef115f5bf *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0x5984c023
+608321 ./tests/data/images/pam/02.pam
+e8bd9f1830e6a9db201386e96580f869 *./tests/data/images/pam/02.pam
+./tests/data/images/pam/%02d.pam CRC=0x65707c37
+101447 ./tests/data/images/pam/02.pam
diff --git a/tests/ref/lavf/pcx b/tests/ref/lavf/pcx
index e60ea782bc..6568b6028c 100644
--- a/tests/ref/lavf/pcx
+++ b/tests/ref/lavf/pcx
@@ -1,3 +1,3 @@
-2df1d747fba23d03b6ff9c91b8b465c9 *./tests/data/images/pcx/02.pcx
-./tests/data/images/pcx/%02d.pcx CRC=0x28c7369b
+c4faf65ecc812ec8412cc26140c13bd5 *./tests/data/images/pcx/02.pcx
+./tests/data/images/pcx/%02d.pcx CRC=0x6da01946
364147 ./tests/data/images/pcx/02.pcx
diff --git a/tests/ref/lavf/pgm b/tests/ref/lavf/pgm
index 419fdaa46f..816579fa86 100644
--- a/tests/ref/lavf/pgm
+++ b/tests/ref/lavf/pgm
@@ -1,3 +1,3 @@
-388f5c51a678ca6a52cc006095c12f08 *./tests/data/images/pgm/02.pgm
-./tests/data/images/pgm/%02d.pgm CRC=0xa6866b82
+cc777c5fc4d116d4c5a996eac8d3133e *./tests/data/images/pgm/02.pgm
+./tests/data/images/pgm/%02d.pgm CRC=0x0ff205be
101391 ./tests/data/images/pgm/02.pgm
diff --git a/tests/ref/lavf/pgmpipe b/tests/ref/lavf/pgmpipe
index 28ad60ea59..da6f9a6d3a 100644
--- a/tests/ref/lavf/pgmpipe
+++ b/tests/ref/lavf/pgmpipe
@@ -1,3 +1,3 @@
-04e66c8e9e064c8310bd657ee559bd70 *./tests/data/lavf/pgmpipe.pgm
+c34e37ea49237c2d1ea81a5944328e59 *./tests/data/lavf/pgmpipe.pgm
2534775 ./tests/data/lavf/pgmpipe.pgm
-./tests/data/lavf/pgmpipe.pgm CRC=0xadf48ba9
+./tests/data/lavf/pgmpipe.pgm CRC=0x7aa0122f
diff --git a/tests/ref/lavf/pixfmt b/tests/ref/lavf/pixfmt
index 186dde5ed3..88030875de 100644
--- a/tests/ref/lavf/pixfmt
+++ b/tests/ref/lavf/pixfmt
@@ -16,21 +16,21 @@ e176bd14185788110e055f945de7f95f *./tests/data/pixfmt/yuvj420p.yuv
304128 ./tests/data/pixfmt/yuvj422p.yuv
c10442da177c9f1d12be3c53be6fa12c *./tests/data/pixfmt/yuvj444p.yuv
304128 ./tests/data/pixfmt/yuvj444p.yuv
-c6e0f9b5817f484b175c1ec4ffb4e9c9 *./tests/data/pixfmt/rgb24.yuv
+6bb61113e7b70eb09dbcec356122a0e2 *./tests/data/pixfmt/rgb24.yuv
304128 ./tests/data/pixfmt/rgb24.yuv
-c6e0f9b5817f484b175c1ec4ffb4e9c9 *./tests/data/pixfmt/bgr24.yuv
+6bb61113e7b70eb09dbcec356122a0e2 *./tests/data/pixfmt/bgr24.yuv
304128 ./tests/data/pixfmt/bgr24.yuv
-c6e0f9b5817f484b175c1ec4ffb4e9c9 *./tests/data/pixfmt/rgb32.yuv
+6bb61113e7b70eb09dbcec356122a0e2 *./tests/data/pixfmt/rgb32.yuv
304128 ./tests/data/pixfmt/rgb32.yuv
-66d39d464bd89ded2a124897f0a75ade *./tests/data/pixfmt/rgb565.yuv
+efa7c0337cc00c796c6df615223716f1 *./tests/data/pixfmt/rgb565.yuv
304128 ./tests/data/pixfmt/rgb565.yuv
-c894c3bd8d2631ed1964500b90a0c350 *./tests/data/pixfmt/rgb555.yuv
+0df2a477af1415a1b8fbf2a3e552bc39 *./tests/data/pixfmt/rgb555.yuv
304128 ./tests/data/pixfmt/rgb555.yuv
-6be306b0cce5f8e6c271ea17fef9745b *./tests/data/pixfmt/gray.yuv
+1e080c12bd9755c41ecb8e19b756f406 *./tests/data/pixfmt/gray.yuv
304128 ./tests/data/pixfmt/gray.yuv
-31398104d2349dd48328a6862bc6711f *./tests/data/pixfmt/monow.yuv
+6c719671e39f1bcf67b47eab98fa529b *./tests/data/pixfmt/monow.yuv
304128 ./tests/data/pixfmt/monow.yuv
-31398104d2349dd48328a6862bc6711f *./tests/data/pixfmt/monob.yuv
+6c719671e39f1bcf67b47eab98fa529b *./tests/data/pixfmt/monob.yuv
304128 ./tests/data/pixfmt/monob.yuv
00b85790df5740bab95e2559d81603a7 *./tests/data/pixfmt/yuv440p.yuv
304128 ./tests/data/pixfmt/yuv440p.yuv
diff --git a/tests/ref/lavf/png b/tests/ref/lavf/png
index f216e7e904..9cf677b21b 100644
--- a/tests/ref/lavf/png
+++ b/tests/ref/lavf/png
@@ -1,3 +1,9 @@
-c162094e51dc1a3203de43e496086dfd *./tests/data/images/png/02.png
-./tests/data/images/png/%02d.png CRC=0x28c7369b
-248612 ./tests/data/images/png/02.png
+2af72da4468e61a37c220b25cb28618a *./tests/data/images/png/02.png
+./tests/data/images/png/%02d.png CRC=0x6da01946
+248633 ./tests/data/images/png/02.png
+6cf54c13aa407b77547cf6dfe23ecba3 *./tests/data/images/png/02.png
+./tests/data/images/png/%02d.png CRC=0x893f10ef
+47365 ./tests/data/images/png/02.png
+b4e38244c97debe3f528e7d1adb283ef *./tests/data/images/png/02.png
+./tests/data/images/png/%02d.png CRC=0x5984c023
+511900 ./tests/data/images/png/02.png
diff --git a/tests/ref/lavf/ppm b/tests/ref/lavf/ppm
index 33275e2d36..97093aaac5 100644
--- a/tests/ref/lavf/ppm
+++ b/tests/ref/lavf/ppm
@@ -1,3 +1,3 @@
16d5dadf0b362fc8ba3cb676c5dde985 *./tests/data/images/ppm/02.ppm
-./tests/data/images/ppm/%02d.ppm CRC=0x28c7369b
+./tests/data/images/ppm/%02d.ppm CRC=0x6da01946
304143 ./tests/data/images/ppm/02.ppm
diff --git a/tests/ref/lavf/rm b/tests/ref/lavf/rm
index 993310d4e3..62e0a31739 100644
--- a/tests/ref/lavf/rm
+++ b/tests/ref/lavf/rm
@@ -1,2 +1,2 @@
-9eeb3b91c0a45f519fd7f2efea882cf4 *./tests/data/lavf/lavf.rm
-346414 ./tests/data/lavf/lavf.rm
+e30681d05d6f3d24108d3614600bf116 *./tests/data/lavf/lavf.rm
+346424 ./tests/data/lavf/lavf.rm
diff --git a/tests/ref/lavf/sgi b/tests/ref/lavf/sgi
index b0cd303735..a43c1f4287 100644
--- a/tests/ref/lavf/sgi
+++ b/tests/ref/lavf/sgi
@@ -1,3 +1,3 @@
7054acafd275e51cec28d4518e213081 *./tests/data/images/sgi/02.sgi
-./tests/data/images/sgi/%02d.sgi CRC=0x28c7369b
+./tests/data/images/sgi/%02d.sgi CRC=0x6da01946
308151 ./tests/data/images/sgi/02.sgi
diff --git a/tests/ref/lavf/smjpeg b/tests/ref/lavf/smjpeg
new file mode 100644
index 0000000000..a2eeb97578
--- /dev/null
+++ b/tests/ref/lavf/smjpeg
@@ -0,0 +1,3 @@
+a95982a2d390f4dcdc72a41d8920abb9 *./tests/data/lavf/lavf.smjpeg
+789551 ./tests/data/lavf/lavf.smjpeg
+./tests/data/lavf/lavf.smjpeg CRC=0x54bf6147
diff --git a/tests/ref/lavf/sunrast b/tests/ref/lavf/sunrast
index 097235b75c..4db0505140 100644
--- a/tests/ref/lavf/sunrast
+++ b/tests/ref/lavf/sunrast
@@ -1,3 +1,3 @@
07518bcb0841bc677ce6aea8464ea240 *./tests/data/images/sun/02.sun
-./tests/data/images/sun/%02d.sun CRC=0x3447369b
+./tests/data/images/sun/%02d.sun CRC=0xe6c71946
304123 ./tests/data/images/sun/02.sun
diff --git a/tests/ref/lavf/swf b/tests/ref/lavf/swf
index 1e07793e1e..7ce0fa46cb 100644
--- a/tests/ref/lavf/swf
+++ b/tests/ref/lavf/swf
@@ -1,3 +1,3 @@
-62c5aeb636fc82cf6ba6277d36e42cb5 *./tests/data/lavf/lavf.swf
-329479 ./tests/data/lavf/lavf.swf
-./tests/data/lavf/lavf.swf CRC=0x881785d1
+11e9e9bf99a0ae6a0ba5434b745eae21 *./tests/data/lavf/lavf.swf
+329474 ./tests/data/lavf/lavf.swf
+./tests/data/lavf/lavf.swf CRC=0x4eac88c5
diff --git a/tests/ref/lavf/tga b/tests/ref/lavf/tga
index ce6b6466bb..7efaf97828 100644
--- a/tests/ref/lavf/tga
+++ b/tests/ref/lavf/tga
@@ -1,3 +1,3 @@
c0305c53e6d79d4ed9f35f04f671246c *./tests/data/images/tga/02.tga
-./tests/data/images/tga/%02d.tga CRC=0x3447369b
+./tests/data/images/tga/%02d.tga CRC=0xe6c71946
304172 ./tests/data/images/tga/02.tga
diff --git a/tests/ref/lavf/tiff b/tests/ref/lavf/tiff
index b636bd9c8b..4b0b985f76 100644
--- a/tests/ref/lavf/tiff
+++ b/tests/ref/lavf/tiff
@@ -1,3 +1,3 @@
b3299346a8959553a437e486d8f3bf76 *./tests/data/images/tiff/02.tiff
-./tests/data/images/tiff/%02d.tiff CRC=0x28c7369b
+./tests/data/images/tiff/%02d.tiff CRC=0x6da01946
307131 ./tests/data/images/tiff/02.tiff
diff --git a/tests/ref/lavf/ts b/tests/ref/lavf/ts
index 8512d264e4..1381f09f19 100644
--- a/tests/ref/lavf/ts
+++ b/tests/ref/lavf/ts
@@ -1,3 +1,3 @@
-3713c852d6ee217ae6a901619df71111 *./tests/data/lavf/lavf.ts
-406456 ./tests/data/lavf/lavf.ts
-./tests/data/lavf/lavf.ts CRC=0xb4ca6cdc
+cca6bca512605bbde20b7aa5cccf4850 *./tests/data/lavf/lavf.ts
+407020 ./tests/data/lavf/lavf.ts
+./tests/data/lavf/lavf.ts CRC=0x71287e25
diff --git a/tests/ref/lavf/voc b/tests/ref/lavf/voc
index 3131960237..ded8af7227 100644
--- a/tests/ref/lavf/voc
+++ b/tests/ref/lavf/voc
@@ -1,3 +1,3 @@
-ae01db5200e569371d4c27316575344c *./tests/data/lavf/lavf.voc
+bb5ad96a5e1b35683d50bf18115db821 *./tests/data/lavf/lavf.voc
44305 ./tests/data/lavf/lavf.voc
./tests/data/lavf/lavf.voc CRC=0x298fd284
diff --git a/tests/ref/lavf/voc_s16 b/tests/ref/lavf/voc_s16
index deb7999485..d026090aff 100644
--- a/tests/ref/lavf/voc_s16
+++ b/tests/ref/lavf/voc_s16
@@ -1,3 +1,3 @@
-e55a9c632cfeab90bcfb9ff29a71728c *./tests/data/lavf/lavf.s16.voc
-176613 ./tests/data/lavf/lavf.s16.voc
+db9fa22ff71992bd8b6cc80047223c92 *./tests/data/lavf/lavf.s16.voc
+176615 ./tests/data/lavf/lavf.s16.voc
./tests/data/lavf/lavf.s16.voc CRC=0xe61e3bd0
diff --git a/tests/ref/lavf/w64 b/tests/ref/lavf/w64
new file mode 100644
index 0000000000..26c68688e5
--- /dev/null
+++ b/tests/ref/lavf/w64
@@ -0,0 +1,3 @@
+82c75c9cb61924fda68d9602ea69c445 *./tests/data/lavf/lavf.w64
+88304 ./tests/data/lavf/lavf.w64
+./tests/data/lavf/lavf.w64 CRC=0x3a1da17e
diff --git a/tests/ref/lavf/wav b/tests/ref/lavf/wav
index fa8a859cd0..da3bfc24ed 100644
--- a/tests/ref/lavf/wav
+++ b/tests/ref/lavf/wav
@@ -1,3 +1,3 @@
-41410d9bbe0603740d1c17050746f475 *./tests/data/lavf/lavf.wav
-88246 ./tests/data/lavf/lavf.wav
+fc958a32b4fca7b1c40cbdaef2d1416e *./tests/data/lavf/lavf.wav
+88274 ./tests/data/lavf/lavf.wav
./tests/data/lavf/lavf.wav CRC=0x3a1da17e
diff --git a/tests/ref/lavf/wav_peak b/tests/ref/lavf/wav_peak
new file mode 100644
index 0000000000..aa7e5fc49e
--- /dev/null
+++ b/tests/ref/lavf/wav_peak
@@ -0,0 +1,3 @@
+35148d1f6e66b0080893851d917ecbf4 *./tests/data/lavf/lavf.peak.wav
+89094 ./tests/data/lavf/lavf.peak.wav
+./tests/data/lavf/lavf.peak.wav CRC=0x3a1da17e
diff --git a/tests/ref/lavf/wav_peak_only b/tests/ref/lavf/wav_peak_only
new file mode 100644
index 0000000000..dccd0e72ff
--- /dev/null
+++ b/tests/ref/lavf/wav_peak_only
@@ -0,0 +1,2 @@
+b609a363e6d490710ed52231a8d09d3c *./tests/data/lavf/lavf.peak_only.wav
+832 ./tests/data/lavf/lavf.peak_only.wav
diff --git a/tests/ref/lavf/wtv b/tests/ref/lavf/wtv
new file mode 100644
index 0000000000..b0ae7d1dbb
--- /dev/null
+++ b/tests/ref/lavf/wtv
@@ -0,0 +1,3 @@
+b74b14ee41830aed90380bf6252dcfdb *./tests/data/lavf/lavf.wtv
+413696 ./tests/data/lavf/lavf.wtv
+./tests/data/lavf/lavf.wtv CRC=0x71287e25
diff --git a/tests/ref/lavf/xbm b/tests/ref/lavf/xbm
new file mode 100644
index 0000000000..4cc4be6eea
--- /dev/null
+++ b/tests/ref/lavf/xbm
@@ -0,0 +1,3 @@
+99c20fff5d17b698b4a25282aebc3c51 *./tests/data/images/xbm/02.xbm
+./tests/data/images/xbm/%02d.xbm CRC=0x0f5aa5cb
+76411 ./tests/data/images/xbm/02.xbm
diff --git a/tests/ref/lavf/xwd b/tests/ref/lavf/xwd
index 3fd20c8f6c..5e593b5d83 100644
--- a/tests/ref/lavf/xwd
+++ b/tests/ref/lavf/xwd
@@ -1,3 +1,24 @@
50baa5560b7d1aa3188b19c1162bf7dc *./tests/data/images/xwd/02.xwd
-./tests/data/images/xwd/%02d.xwd CRC=0x28c7369b
+./tests/data/images/xwd/%02d.xwd CRC=0x6da01946
304239 ./tests/data/images/xwd/02.xwd
+1cdb43599c956dc8563f1e09fac5df00 *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0xf07d29cd
+405615 ./tests/data/images/xwd/02.xwd
+c0866e9e710fce735423594a93bee604 *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0x53209216
+202863 ./tests/data/images/xwd/02.xwd
+1300938325d5ac12caa09a43bd58f37c *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0x14555d6e
+202863 ./tests/data/images/xwd/02.xwd
+c6f3cb7c45f7238474a89d2ad61a1caf *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0xfaafb59b
+104559 ./tests/data/images/xwd/02.xwd
+fe1af954966a40c2cd35fc27094ff823 *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0xd69c3a09
+104559 ./tests/data/images/xwd/02.xwd
+85e9b8b814a1dea71d143aac2e487037 *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0x0ff205be
+101487 ./tests/data/images/xwd/02.xwd
+2131b4c41fe35178b0c7d121223af549 *./tests/data/images/xwd/02.xwd
+./tests/data/images/xwd/%02d.xwd CRC=0x0f5aa5cb
+12783 ./tests/data/images/xwd/02.xwd
diff --git a/tests/ref/seek/acodec-adpcm-ima_qt-trellis b/tests/ref/seek/acodec-adpcm-ima_qt-trellis
new file mode 100644
index 0000000000..bdaf1f0f0c
--- /dev/null
+++ b/tests/ref/seek/acodec-adpcm-ima_qt-trellis
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.893878 pts: 1.893878 pos: 88812 size: 68
+ret: 0 st: 0 flags:0 ts: 0.788345
+ret: 0 st: 0 flags:1 dts: 0.789478 pts: 0.789478 pos: 37064 size: 68
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 2.577438 pts: 2.577438 pos: 120840 size: 68
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.470113 pts: 1.470113 pos: 68956 size: 68
+ret: 0 st: 0 flags:0 ts: 0.365011
+ret: 0 st: 0 flags:1 dts: 0.365714 pts: 0.365714 pos: 17208 size: 68
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 2.153673 pts: 2.153673 pos: 100984 size: 68
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.046349 pts: 1.046349 pos: 49100 size: 68
+ret: 0 st: 0 flags:0 ts:-0.058322
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st: 0 flags:1 ts: 2.835828
+ret: 0 st: 0 flags:1 dts: 2.835760 pts: 2.835760 pos: 132944 size: 68
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.731338 pts: 1.731338 pos: 81196 size: 68
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.624036 pts: 0.624036 pos: 29312 size: 68
+ret: 0 st: 0 flags:0 ts:-0.481655
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st: 0 flags:1 ts: 2.412494
+ret: 0 st: 0 flags:1 dts: 2.411995 pts: 2.411995 pos: 113088 size: 68
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.307574 pts: 1.307574 pos: 61340 size: 68
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200272 pts: 0.200272 pos: 9456 size: 68
+ret: 0 st: 0 flags:0 ts:-0.904989
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st: 0 flags:1 ts: 1.989184
+ret: 0 st: 0 flags:1 dts: 1.988209 pts: 1.988209 pos: 93232 size: 68
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.883810 pts: 0.883810 pos: 41484 size: 68
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
+ret: 0 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 2.671769 pts: 2.671769 pos: 125260 size: 68
+ret: 0 st: 0 flags:1 ts: 1.565850
+ret: 0 st: 0 flags:1 dts: 1.564444 pts: 1.564444 pos: 73376 size: 68
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.460045 pts: 0.460045 pos: 21628 size: 68
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 72 size: 68
diff --git a/tests/ref/seek/acodec-adpcm-ima_wav-trellis b/tests/ref/seek/acodec-adpcm-ima_wav-trellis
new file mode 100644
index 0000000000..b6517c5438
--- /dev/null
+++ b/tests/ref/seek/acodec-adpcm-ima_wav-trellis
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.856009 pts: 1.856009 pos: 29756 size: 4096
+ret: 0 st: 0 flags:0 ts: 0.788345
+ret: 0 st: 0 flags:1 dts: 0.831995 pts: 0.831995 pos: 13372 size: 4096
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 2.623991 pts: 2.623991 pos: 42044 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.408005 pts: 1.408005 pos: 22588 size: 4096
+ret: 0 st: 0 flags:0 ts: 0.365011
+ret: 0 st: 0 flags:1 dts: 0.383991 pts: 0.383991 pos: 6204 size: 4096
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 2.176009 pts: 2.176009 pos: 34876 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.023991 pts: 1.023991 pos: 16444 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.058322
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.835828
+ret: 0 st: 0 flags:1 dts: 2.816009 pts: 2.816009 pos: 45116 size: 4096
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.791995 pts: 1.791995 pos: 28732 size: 4096
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.576009 pts: 0.576009 pos: 9276 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.481655
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.412494
+ret: 0 st: 0 flags:1 dts: 2.368005 pts: 2.368005 pos: 37948 size: 4096
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.343991 pts: 1.343991 pos: 21564 size: 4096
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.191995 pts: 0.191995 pos: 3132 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.904989
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.989184
+ret: 0 st: 0 flags:1 dts: 1.983991 pts: 1.983991 pos: 31804 size: 4096
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.896009 pts: 0.896009 pos: 14396 size: 4096
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
+ret: 0 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 2.688005 pts: 2.688005 pos: 43068 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.565850
+ret: 0 st: 0 flags:1 dts: 1.536009 pts: 1.536009 pos: 24636 size: 4096
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.511995 pts: 0.511995 pos: 8252 size: 4096
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 60 size: 4096
diff --git a/tests/ref/seek/acodec-adpcm-ms-trellis b/tests/ref/seek/acodec-adpcm-ms-trellis
new file mode 100644
index 0000000000..579be7f416
--- /dev/null
+++ b/tests/ref/seek/acodec-adpcm-ms-trellis
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.856009 pts: 1.856009 pos: 29786 size: 4096
+ret: 0 st: 0 flags:0 ts: 0.788345
+ret: 0 st: 0 flags:1 dts: 0.831995 pts: 0.831995 pos: 13402 size: 4096
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 2.623991 pts: 2.623991 pos: 42074 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.408005 pts: 1.408005 pos: 22618 size: 4096
+ret: 0 st: 0 flags:0 ts: 0.365011
+ret: 0 st: 0 flags:1 dts: 0.383991 pts: 0.383991 pos: 6234 size: 4096
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 2.176009 pts: 2.176009 pos: 34906 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.023991 pts: 1.023991 pos: 16474 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.058322
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.835828
+ret: 0 st: 0 flags:1 dts: 2.816009 pts: 2.816009 pos: 45146 size: 4096
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.791995 pts: 1.791995 pos: 28762 size: 4096
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.576009 pts: 0.576009 pos: 9306 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.481655
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.412494
+ret: 0 st: 0 flags:1 dts: 2.368005 pts: 2.368005 pos: 37978 size: 4096
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.343991 pts: 1.343991 pos: 21594 size: 4096
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.191995 pts: 0.191995 pos: 3162 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.904989
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.989184
+ret: 0 st: 0 flags:1 dts: 1.983991 pts: 1.983991 pos: 31834 size: 4096
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.896009 pts: 0.896009 pos: 14426 size: 4096
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
+ret: 0 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 2.688005 pts: 2.688005 pos: 43098 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.565850
+ret: 0 st: 0 flags:1 dts: 1.536009 pts: 1.536009 pos: 24666 size: 4096
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.511995 pts: 0.511995 pos: 8282 size: 4096
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 90 size: 4096
diff --git a/tests/ref/seek/acodec-adpcm-swf-trellis b/tests/ref/seek/acodec-adpcm-swf-trellis
new file mode 100644
index 0000000000..2f9091325a
--- /dev/null
+++ b/tests/ref/seek/acodec-adpcm-swf-trellis
@@ -0,0 +1,49 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 208 size: 2053
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 208 size: 2053
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.858000 pts: 1.858000 pos: 82968 size: 2053
+ret: 0 st: 0 flags:0 ts: 0.788000
+ret: 0 st: 0 flags:1 dts: 0.789000 pts: 0.789000 pos: 35381 size: 2053
+ret:-1 st: 0 flags:1 ts:-0.317000
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 2.601000 pts: 2.601000 pos: 116072 size: 2053
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 64347 size: 2053
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.372000 pts: 0.372000 pos: 16760 size: 2053
+ret:-1 st: 0 flags:1 ts:-0.741000
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 2.183000 pts: 2.183000 pos: 97451 size: 2053
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.022000 pts: 1.022000 pos: 45726 size: 2053
+ret: 0 st: 0 flags:0 ts:-0.058000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 208 size: 2053
+ret: 0 st: 0 flags:1 ts: 2.836000
+ret: 0 st: 0 flags:1 dts: 2.833000 pts: 2.833000 pos: 126417 size: 2053
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.765000 pts: 1.765000 pos: 78830 size: 2053
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.604000 pts: 0.604000 pos: 27105 size: 2053
+ret: 0 st: 0 flags:0 ts:-0.482000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 208 size: 2053
+ret: 0 st: 0 flags:1 ts: 2.413000
+ret: 0 st: 0 flags:1 dts: 2.368000 pts: 2.368000 pos: 105727 size: 2053
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.347000 pts: 1.347000 pos: 60209 size: 2053
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.186000 pts: 0.186000 pos: 8484 size: 2053
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 208 size: 2053
+ret: 0 st: 0 flags:1 ts: 1.989000
+ret: 0 st: 0 flags:1 dts: 1.950000 pts: 1.950000 pos: 87106 size: 2053
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.929000 pts: 0.929000 pos: 41588 size: 2053
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:0 ts: 2.672000
+ret: 0 st: 0 flags:1 dts: 2.694000 pts: 2.694000 pos: 120210 size: 2053
+ret: 0 st: 0 flags:1 ts: 1.566000
+ret: 0 st: 0 flags:1 dts: 1.533000 pts: 1.533000 pos: 68485 size: 2053
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.464000 pts: 0.464000 pos: 20898 size: 2053
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/acodec-adpcm-yamaha-trellis b/tests/ref/seek/acodec-adpcm-yamaha-trellis
new file mode 100644
index 0000000000..5cbfaed73e
--- /dev/null
+++ b/tests/ref/seek/acodec-adpcm-yamaha-trellis
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.856009 pts: 1.856009 pos: 29754 size: 4096
+ret: 0 st: 0 flags:0 ts: 0.788345
+ret: 0 st: 0 flags:1 dts: 0.831995 pts: 0.831995 pos: 13370 size: 4096
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 2.623991 pts: 2.623991 pos: 42042 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.408005 pts: 1.408005 pos: 22586 size: 4096
+ret: 0 st: 0 flags:0 ts: 0.365011
+ret: 0 st: 0 flags:1 dts: 0.383991 pts: 0.383991 pos: 6202 size: 4096
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 2.176009 pts: 2.176009 pos: 34874 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.023991 pts: 1.023991 pos: 16442 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.058322
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.835828
+ret: 0 st: 0 flags:1 dts: 2.816009 pts: 2.816009 pos: 45114 size: 4096
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.791995 pts: 1.791995 pos: 28730 size: 4096
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.576009 pts: 0.576009 pos: 9274 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.481655
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.412494
+ret: 0 st: 0 flags:1 dts: 2.368005 pts: 2.368005 pos: 37946 size: 4096
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.343991 pts: 1.343991 pos: 21562 size: 4096
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.191995 pts: 0.191995 pos: 3130 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.904989
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.989184
+ret: 0 st: 0 flags:1 dts: 1.983991 pts: 1.983991 pos: 31802 size: 4096
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.896009 pts: 0.896009 pos: 14394 size: 4096
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
+ret: 0 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 2.688005 pts: 2.688005 pos: 43066 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.565850
+ret: 0 st: 0 flags:1 dts: 1.536009 pts: 1.536009 pos: 24634 size: 4096
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.511995 pts: 0.511995 pos: 8250 size: 4096
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 58 size: 4096
diff --git a/tests/ref/seek/acodec-flac b/tests/ref/seek/acodec-flac
index 15ab0d2ee3..f6add9abd2 100644
--- a/tests/ref/seek/acodec-flac
+++ b/tests/ref/seek/acodec-flac
@@ -1,49 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8255 size: 614
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8255 size: 614
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880816 pts: 1.880816 pos: 86741 size: 2191
+ret: 0 st: 0 flags:1 dts: 1.880816 pts: 1.880816 pos: 86742 size: 2191
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.809796 pts: 0.809796 pos: 27365 size: 615
-ret:-1 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.809796 pts: 0.809796 pos: 27366 size: 615
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 2.586122 pts: 2.586122 pos: 145605 size: 2384
+ret: 0 st: 0 flags:1 dts: 2.586122 pts: 2.586122 pos: 145606 size: 2384
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.462857 pts: 1.462857 pos: 53387 size: 1851
+ret: 0 st: 0 flags:1 dts: 1.462857 pts: 1.462857 pos: 53388 size: 1851
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365714 pts: 0.365714 pos: 16889 size: 614
-ret:-1 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.365714 pts: 0.365714 pos: 16890 size: 614
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 2.168163 pts: 2.168163 pos: 110530 size: 2143
+ret: 0 st: 0 flags:1 dts: 2.168163 pts: 2.168163 pos: 110531 size: 2143
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.044898 pts: 1.044898 pos: 32879 size: 579
+ret: 0 st: 0 flags:1 dts: 1.044898 pts: 1.044898 pos: 32880 size: 579
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8255 size: 614
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st: 0 flags:1 ts: 2.835828
-ret: 0 st: 0 flags:1 dts: 2.821224 pts: 2.821224 pos: 167111 size: 2391
+ret: 0 st: 0 flags:1 dts: 2.821224 pts: 2.821224 pos: 167112 size: 2391
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.750204 pts: 1.750204 pos: 75787 size: 2191
+ret: 0 st: 0 flags:1 dts: 1.750204 pts: 1.750204 pos: 75788 size: 2191
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.600816 pts: 0.600816 pos: 22445 size: 616
+ret: 0 st: 0 flags:1 dts: 0.600816 pts: 0.600816 pos: 22446 size: 616
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8255 size: 614
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st: 0 flags:1 ts: 2.412494
-ret: 0 st: 0 flags:1 dts: 2.403265 pts: 2.403265 pos: 129792 size: 2138
+ret: 0 st: 0 flags:1 dts: 2.403265 pts: 2.403265 pos: 129793 size: 2138
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.332245 pts: 1.332245 pos: 44811 size: 1609
+ret: 0 st: 0 flags:1 dts: 1.332245 pts: 1.332245 pos: 44812 size: 1609
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.182857 pts: 0.182857 pos: 12571 size: 628
+ret: 0 st: 0 flags:1 dts: 0.182857 pts: 0.182857 pos: 12572 size: 628
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8255 size: 614
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st: 0 flags:1 ts: 1.989184
-ret: 0 st: 0 flags:1 dts: 1.985306 pts: 1.985306 pos: 95507 size: 2169
+ret: 0 st: 0 flags:1 dts: 1.985306 pts: 1.985306 pos: 95508 size: 2169
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.888163 pts: 0.888163 pos: 29210 size: 620
-ret:-1 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.888163 pts: 0.888163 pos: 29211 size: 620
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
ret: 0 st: 0 flags:0 ts: 2.671678
-ret: 0 st: 0 flags:1 dts: 2.690612 pts: 2.690612 pos: 155153 size: 2394
+ret: 0 st: 0 flags:1 dts: 2.690612 pts: 2.690612 pos: 155154 size: 2394
ret: 0 st: 0 flags:1 ts: 1.565850
-ret: 0 st: 0 flags:1 dts: 1.541224 pts: 1.541224 pos: 59081 size: 1974
+ret: 0 st: 0 flags:1 dts: 1.541224 pts: 1.541224 pos: 59082 size: 1974
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.470204 pts: 0.470204 pos: 19352 size: 608
-ret:-1 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.470204 pts: 0.470204 pos: 19353 size: 608
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 8256 size: 614
diff --git a/tests/ref/seek/acodec-pcm-f32be b/tests/ref/seek/acodec-pcm-f32be
index 886356a1a2..b838262b58 100644
--- a/tests/ref/seek/acodec-pcm-f32be
+++ b/tests/ref/seek/acodec-pcm-f32be
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos: 668288 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos: 668296 size: 8192
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 278152 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 278160 size: 8192
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos: 909072 size: 8192
+ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos: 909080 size: 8192
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 518936 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 518944 size: 8192
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 128800 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 128808 size: 8192
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos: 759720 size: 8192
+ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos: 759728 size: 8192
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 369584 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 369592 size: 8192
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st: 0 flags:1 ts: 2.835828
-ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos:1000504 size: 8192
+ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos:1000512 size: 8192
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos: 610368 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos: 610376 size: 8192
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 220232 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 220240 size: 8192
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st: 0 flags:1 ts: 2.412494
-ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos: 851152 size: 8192
+ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos: 851160 size: 8192
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 461016 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 461024 size: 8192
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 70880 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 70888 size: 8192
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st: 0 flags:1 ts: 1.989184
-ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos: 701808 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos: 701816 size: 8192
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 311664 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 311672 size: 8192
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
ret: 0 st: 0 flags:0 ts: 2.671678
-ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos: 942592 size: 8192
+ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos: 942600 size: 8192
ret: 0 st: 0 flags:1 ts: 1.565850
-ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 552456 size: 8192
+ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 552464 size: 8192
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 162312 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 162320 size: 8192
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 8192
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 8192
diff --git a/tests/ref/seek/acodec-pcm-f64be b/tests/ref/seek/acodec-pcm-f64be
index 9be3b4ec16..82223517d5 100644
--- a/tests/ref/seek/acodec-pcm-f64be
+++ b/tests/ref/seek/acodec-pcm-f64be
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos:1336552 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos:1336560 size: 16384
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 556280 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 556288 size: 16384
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos:1818120 size: 16384
+ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos:1818128 size: 16384
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos:1037848 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos:1037856 size: 16384
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 257576 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 257584 size: 16384
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos:1519416 size: 16384
+ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos:1519424 size: 16384
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 739144 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 739152 size: 16384
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st: 0 flags:1 ts: 2.835828
-ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos:2000984 size: 16384
+ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos:2000992 size: 16384
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos:1220712 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos:1220720 size: 16384
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 440440 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 440448 size: 16384
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st: 0 flags:1 ts: 2.412494
-ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos:1702280 size: 16384
+ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos:1702288 size: 16384
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 922008 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 922016 size: 16384
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 141736 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 141744 size: 16384
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st: 0 flags:1 ts: 1.989184
-ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos:1403592 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos:1403600 size: 16384
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 623304 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 623312 size: 16384
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
ret: 0 st: 0 flags:0 ts: 2.671678
-ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos:1885160 size: 16384
+ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos:1885168 size: 16384
ret: 0 st: 0 flags:1 ts: 1.565850
-ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos:1104888 size: 16384
+ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos:1104896 size: 16384
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 324600 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 324608 size: 16384
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 16384
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 16384
diff --git a/tests/ref/seek/acodec-pcm-s16le b/tests/ref/seek/acodec-pcm-s16le
index 4f1ffc5acd..41acc98d8d 100644
--- a/tests/ref/seek/acodec-pcm-s16le
+++ b/tests/ref/seek/acodec-pcm-s16le
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos: 334178 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos: 334176 size: 4096
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 139110 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 139108 size: 4096
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos: 454570 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos: 454568 size: 4096
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 259502 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 259500 size: 4096
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 64434 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 64432 size: 4096
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos: 379894 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos: 379892 size: 4096
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 184826 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 184824 size: 4096
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:1 ts: 2.835828
-ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos: 500286 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos: 500284 size: 4096
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos: 305218 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos: 305216 size: 4096
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 110150 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 110148 size: 4096
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:1 ts: 2.412494
-ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos: 425610 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos: 425608 size: 4096
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 230542 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 230540 size: 4096
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 35474 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 35472 size: 4096
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:1 ts: 1.989184
-ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos: 350938 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos: 350936 size: 4096
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 155866 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 155864 size: 4096
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:0 ts: 2.671678
-ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos: 471330 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos: 471328 size: 4096
ret: 0 st: 0 flags:1 ts: 1.565850
-ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 276262 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 276260 size: 4096
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 81190 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 81188 size: 4096
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
diff --git a/tests/ref/seek/acodec-pcm-u8 b/tests/ref/seek/acodec-pcm-u8
index 8348916432..afa33519d7 100644
--- a/tests/ref/seek/acodec-pcm-u8
+++ b/tests/ref/seek/acodec-pcm-u8
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos: 167112 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.894172 pts: 1.894172 pos: 167110 size: 4096
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69578 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69576 size: 4096
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos: 227308 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.576667 pts: 2.576667 pos: 227306 size: 4096
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 129774 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 129772 size: 4096
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32240 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32238 size: 4096
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos: 189970 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.153333 pts: 2.153333 pos: 189968 size: 4096
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 92436 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.047506 pts: 1.047506 pos: 92434 size: 4096
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:1 ts: 2.835828
-ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos: 250166 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.835828 pts: 2.835828 pos: 250164 size: 4096
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos: 152632 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.730000 pts: 1.730000 pos: 152630 size: 4096
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55098 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55096 size: 4096
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:1 ts: 2.412494
-ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos: 212828 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.412494 pts: 2.412494 pos: 212826 size: 4096
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 115294 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 115292 size: 4096
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17760 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17758 size: 4096
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:1 ts: 1.989184
-ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos: 175492 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.989184 pts: 1.989184 pos: 175490 size: 4096
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77956 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77954 size: 4096
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
ret: 0 st: 0 flags:0 ts: 2.671678
-ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos: 235688 size: 4096
+ret: 0 st: 0 flags:1 dts: 2.671678 pts: 2.671678 pos: 235686 size: 4096
ret: 0 st: 0 flags:1 ts: 1.565850
-ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 138154 size: 4096
+ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 138152 size: 4096
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40618 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40616 size: 4096
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 4096
diff --git a/tests/ref/seek/extra-mp3 b/tests/ref/seek/extra-mp3
new file mode 100644
index 0000000000..981ac02ca8
--- /dev/null
+++ b/tests/ref/seek/extra-mp3
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880816 pts: 1.880816 pos: 31544 size: 418
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.809796 pts: 0.809796 pos: 14407 size: 418
+ret: 0 st: 0 flags:1 ts:-0.317499
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 2.586122 pts: 2.586122 pos: 42828 size: 418
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.462857 pts: 1.462857 pos: 24856 size: 418
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.365714 pts: 0.365714 pos: 7302 size: 418
+ret: 0 st: 0 flags:1 ts:-0.740831
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 2.168163 pts: 2.168163 pos: 36141 size: 418
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.044898 pts: 1.044898 pos: 18169 size: 418
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 2.821224 pts: 2.821224 pos: 46590 size: 418
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.750204 pts: 1.750204 pos: 29454 size: 418
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.600816 pts: 0.600816 pos: 11064 size: 418
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 2.403265 pts: 2.403265 pos: 39903 size: 418
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.332245 pts: 1.332245 pos: 22766 size: 418
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.182857 pts: 0.182857 pos: 4376 size: 418
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.985306 pts: 1.985306 pos: 33215 size: 418
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.888163 pts: 0.888163 pos: 15661 size: 418
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
+ret: 0 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 dts: 2.690612 pts: 2.690612 pos: 44500 size: 418
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.567347 pts: 1.567347 pos: 26528 size: 418
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.470204 pts: 0.470204 pos: 8974 size: 418
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1451 size: 440
diff --git a/tests/ref/seek/lavf-aiff b/tests/ref/seek/lavf-aiff
index 784b1448ae..eb9ada0b79 100644
--- a/tests/ref/seek/lavf-aiff
+++ b/tests/ref/seek/lavf-aiff
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st:-1 flags:1 ts: 1.894167
ret:-EOF
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69586 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69602 size: 4096
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st:-1 flags:0 ts: 2.576668
ret:-EOF
ret: 0 st:-1 flags:1 ts: 1.470835
ret:-EOF
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32248 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32264 size: 4096
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st:-1 flags:0 ts: 2.153336
ret:-EOF
ret: 0 st:-1 flags:1 ts: 1.047503
ret:-EOF
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st: 0 flags:1 ts: 2.835828
ret:-EOF
ret: 0 st:-1 flags:0 ts: 1.730004
ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55106 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55122 size: 4096
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st: 0 flags:1 ts: 2.412494
ret:-EOF
ret: 0 st:-1 flags:0 ts: 1.306672
ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17768 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17784 size: 4096
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st: 0 flags:1 ts: 1.989184
ret:-EOF
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77964 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77980 size: 4096
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
ret: 0 st: 0 flags:0 ts: 2.671678
ret:-EOF
ret: 0 st: 0 flags:1 ts: 1.565850
ret:-EOF
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40626 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40642 size: 4096
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 54 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 70 size: 4096
diff --git a/tests/ref/seek/lavf-asf b/tests/ref/seek/lavf-asf
index 2eade2711b..b64bec3ac3 100644
--- a/tests/ref/seek/lavf-asf
+++ b/tests/ref/seek/lavf-asf
@@ -1,53 +1,53 @@
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147779 size: 209
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147893 size: 209
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147893 size: 209
ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st: 1 flags:0 ts: 2.577000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330179 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330293 size: 209
ret: 0 st: 1 flags:1 ts: 1.471000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330179 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330293 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147779 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147893 size: 209
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st: 0 flags:0 ts: 2.153000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301493 size: 209
ret: 0 st: 0 flags:1 ts: 1.048000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301493 size: 209
ret: 0 st: 1 flags:0 ts:-0.058000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st: 1 flags:1 ts: 2.836000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330179 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330293 size: 209
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301493 size: 209
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147779 size: 209
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301493 size: 209
ret: 0 st: 1 flags:0 ts: 1.307000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330179 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330293 size: 209
ret: 0 st: 1 flags:1 ts: 0.201000
-ret: 0 st: 1 flags:1 dts: 0.183000 pts: 0.183000 pos: 70979 size: 209
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301493 size: 209
ret: 0 st: 0 flags:0 ts: 0.883000
-ret: 0 st: 1 flags:1 dts: 0.941000 pts: 0.941000 pos: 301379 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147893 size: 209
ret: 0 st: 0 flags:1 ts:-0.222000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
ret: 0 st: 1 flags:0 ts: 2.672000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330179 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330293 size: 209
ret: 0 st: 1 flags:1 ts: 1.566000
-ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330179 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 330293 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147779 size: 209
+ret: 0 st: 1 flags:1 dts: 0.470000 pts: 0.470000 pos: 147893 size: 209
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 579 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 693 size: 208
diff --git a/tests/ref/seek/lavf-au b/tests/ref/seek/lavf-au
index a2c57eb786..d5a70b220b 100644
--- a/tests/ref/seek/lavf-au
+++ b/tests/ref/seek/lavf-au
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st:-1 flags:1 ts: 1.894167
ret:-EOF
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69556 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69564 size: 2048
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st:-1 flags:0 ts: 2.576668
ret:-EOF
ret: 0 st:-1 flags:1 ts: 1.470835
ret:-EOF
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32218 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32226 size: 2048
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st:-1 flags:0 ts: 2.153336
ret:-EOF
ret: 0 st:-1 flags:1 ts: 1.047503
ret:-EOF
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st: 0 flags:1 ts: 2.835828
ret:-EOF
ret: 0 st:-1 flags:0 ts: 1.730004
ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55076 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55084 size: 2048
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st: 0 flags:1 ts: 2.412494
ret:-EOF
ret: 0 st:-1 flags:0 ts: 1.306672
ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17738 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17746 size: 2048
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st: 0 flags:1 ts: 1.989184
ret:-EOF
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77934 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77942 size: 2048
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
ret: 0 st: 0 flags:0 ts: 2.671678
ret:-EOF
ret: 0 st: 0 flags:1 ts: 1.565850
ret:-EOF
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40596 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40604 size: 2048
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 24 size: 2048
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 2048
diff --git a/tests/ref/seek/lavf-avi b/tests/ref/seek/lavf-avi
index 0cabe127ff..4f308d69fe 100644
--- a/tests/ref/seek/lavf-avi
+++ b/tests/ref/seek/lavf-avi
@@ -1,44 +1,44 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9896 size: 27867
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9934 size: 27867
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9896 size: 27867
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9934 size: 27867
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301454 size: 27864
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301454 size: 27864
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret:-1 st: 0 flags:1 ts:-0.320000
ret:-1 st: 1 flags:0 ts: 2.586122
ret: 0 st: 1 flags:1 ts: 1.462857
-ret: 0 st: 1 flags:1 dts: 0.992653 pts: 0.992653 pos: 329544 size: 209
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 156154 size: 27955
+ret: 0 st: 1 flags:1 dts: 0.470204 pts: 0.470204 pos: 155964 size: 209
ret:-1 st:-1 flags:1 ts:-0.740831
ret:-1 st: 0 flags:0 ts: 2.160000
ret: 0 st: 0 flags:1 ts: 1.040000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301454 size: 27864
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret: 0 st: 1 flags:0 ts:-0.052245
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 37772 size: 208
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9934 size: 27867
ret: 0 st: 1 flags:1 ts: 2.847347
-ret: 0 st: 1 flags:1 dts: 0.992653 pts: 0.992653 pos: 329544 size: 209
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret:-1 st:-1 flags:0 ts: 1.730004
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 156154 size: 27955
+ret: 0 st: 1 flags:1 dts: 0.470204 pts: 0.470204 pos: 155964 size: 209
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9896 size: 27867
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9934 size: 27867
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301454 size: 27864
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret:-1 st: 1 flags:0 ts: 1.306122
ret: 0 st: 1 flags:1 ts: 0.208980
-ret: 0 st: 1 flags:1 dts: 0.208980 pts: 0.208980 pos: 92788 size: 209
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9934 size: 27867
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9896 size: 27867
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 9934 size: 27867
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301454 size: 27864
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret: 0 st: 0 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301454 size: 27864
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret:-1 st: 0 flags:1 ts:-0.240000
ret:-1 st: 1 flags:0 ts: 2.664490
ret: 0 st: 1 flags:1 ts: 1.567347
-ret: 0 st: 1 flags:1 dts: 0.992653 pts: 0.992653 pos: 329544 size: 209
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 301482 size: 27864
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 156154 size: 27955
+ret: 0 st: 1 flags:1 dts: 0.470204 pts: 0.470204 pos: 155964 size: 209
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-bmp b/tests/ref/seek/lavf-bmp
index d60729b24c..0f0b152fb8 100644
--- a/tests/ref/seek/lavf-bmp
+++ b/tests/ref/seek/lavf-bmp
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:304182
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:304182
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:304182
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-dv_fmt b/tests/ref/seek/lavf-dv_fmt
index 3c49749a6b..0000ff5abe 100644
--- a/tests/ref/seek/lavf-dv_fmt
+++ b/tests/ref/seek/lavf-dv_fmt
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2880000 size:144000
ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st: 1 flags:0 ts: 2.576667
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 1 flags:1 ts: 1.470833
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1296000 size:144000
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st: 0 flags:0 ts: 2.160000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 0 flags:1 ts: 1.040000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 1 flags:0 ts:-0.058333
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st: 1 flags:1 ts: 2.835833
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2304000 size:144000
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 1 flags:0 ts: 1.306667
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 1 flags:1 ts: 0.200833
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 0 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3168000 size:144000
ret: 0 st: 0 flags:1 ts:-0.240000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
ret: 0 st: 1 flags:0 ts: 2.671667
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st: 1 flags:1 ts: 1.565833
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1728000 size:144000
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
diff --git a/tests/ref/seek/lavf-ffm b/tests/ref/seek/lavf-ffm
new file mode 100644
index 0000000000..eceed1a2c2
--- /dev/null
+++ b/tests/ref/seek/lavf-ffm
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 1 flags:1 dts: 0.825011 pts: 0.825011 pos: 327680 size: 209
+ret: 0 st: 0 flags:1 ts:-0.317499
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st: 1 flags:0 ts: 2.576668
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 1 flags:1 ts: 1.470835
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st:-1 flags:0 ts: 0.365002
+ret: 0 st: 1 flags:1 dts: 0.380930 pts: 0.380930 pos: 163840 size: 209
+ret: 0 st:-1 flags:1 ts:-0.740831
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st: 0 flags:0 ts: 2.153336
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 0 flags:1 ts: 1.047503
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 1 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st: 1 flags:1 ts: 2.835837
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 1 flags:1 dts: 0.642154 pts: 0.642154 pos: 274432 size: 209
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 1 flags:0 ts: 1.306672
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 1 flags:1 ts: 0.200839
+ret: 0 st: 1 flags:1 dts: 0.224195 pts: 0.224195 pos: 114688 size: 209
+ret: 0 st:-1 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st:-1 flags:1 ts: 1.989173
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 0 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:0 dts: 0.880000 pts: 0.920000 pos: 339968 size: 12307
+ret: 0 st: 0 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
+ret: 0 st: 1 flags:0 ts: 2.671674
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st: 1 flags:1 ts: 1.565841
+ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 1 flags:1 dts: 0.485420 pts: 0.485420 pos: 221184 size: 209
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663
diff --git a/tests/ref/seek/lavf-flv_fmt b/tests/ref/seek/lavf-flv_fmt
index 77a106608a..c12da84b50 100644
--- a/tests/ref/seek/lavf-flv_fmt
+++ b/tests/ref/seek/lavf-flv_fmt
@@ -1,44 +1,44 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 31074
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 217 size: 31074
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 31074
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 217 size: 31074
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret:-1 st: 0 flags:1 ts:-0.317000
ret:-1 st:-1 flags:0 ts: 2.576668
ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret: 0 st: 0 flags:0 ts: 0.365000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149421 size: 31125
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149456 size: 31125
ret:-1 st: 0 flags:1 ts:-0.741000
ret:-1 st:-1 flags:0 ts: 2.153336
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret: 0 st: 0 flags:0 ts:-0.058000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 31074
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 217 size: 31074
ret: 0 st: 0 flags:1 ts: 2.836000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret:-1 st:-1 flags:0 ts: 1.730004
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149421 size: 31125
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149456 size: 31125
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 31074
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 217 size: 31074
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret:-1 st:-1 flags:0 ts: 1.306672
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 31074
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 217 size: 31074
ret: 0 st: 0 flags:0 ts:-0.905000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 31074
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 217 size: 31074
ret: 0 st: 0 flags:1 ts: 1.989000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret:-1 st:-1 flags:1 ts:-0.222493
ret:-1 st: 0 flags:0 ts: 2.672000
ret: 0 st: 0 flags:1 ts: 1.566000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298383 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298416 size: 31134
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149421 size: 31125
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149456 size: 31125
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-gif b/tests/ref/seek/lavf-gif
index 883f18761e..9ce8308767 100644
--- a/tests/ref/seek/lavf-gif
+++ b/tests/ref/seek/lavf-gif
@@ -1,27 +1,40 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:2906401
-ret:-EINVAL st:-1 flags:0 ts:-1.000000
-ret:-EINVAL st:-1 flags:1 ts: 1.894167
-ret:-EINVAL st: 0 flags:0 ts: 0.800000
-ret:-EINVAL st: 0 flags:1 ts:-0.320000
-ret:-EINVAL st:-1 flags:0 ts: 2.576668
-ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
-ret:-EINVAL st: 0 flags:1 ts:-0.760000
-ret:-EINVAL st:-1 flags:0 ts: 2.153336
-ret:-EINVAL st:-1 flags:1 ts: 1.047503
-ret:-EINVAL st: 0 flags:0 ts:-0.040000
-ret:-EINVAL st: 0 flags:1 ts: 2.840000
-ret:-EINVAL st:-1 flags:0 ts: 1.730004
-ret:-EINVAL st:-1 flags:1 ts: 0.624171
-ret:-EINVAL st: 0 flags:0 ts:-0.480000
-ret:-EINVAL st: 0 flags:1 ts: 2.400000
-ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
-ret:-EINVAL st: 0 flags:0 ts:-0.920000
-ret:-EINVAL st: 0 flags:1 ts: 2.000000
-ret:-EINVAL st:-1 flags:0 ts: 0.883340
-ret:-EINVAL st:-1 flags:1 ts:-0.222493
-ret:-EINVAL st: 0 flags:0 ts: 2.680000
-ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
-ret:-EINVAL st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret:-1 st: 0 flags:0 ts: 0.790000
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret:-1 st: 0 flags:0 ts: 0.370000
+ret:-1 st: 0 flags:1 ts:-0.740000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st: 0 flags:0 ts:-0.060000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st: 0 flags:1 ts: 2.410000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st: 0 flags:0 ts:-0.900000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret: 0 st: 0 flags:1 ts: 1.990000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.670000
+ret: 0 st: 0 flags:1 ts: 1.570000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 81501
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-gxf b/tests/ref/seek/lavf-gxf
index c8f11c84d8..716246268b 100644
--- a/tests/ref/seek/lavf-gxf
+++ b/tests/ref/seek/lavf-gxf
@@ -2,52 +2,52 @@ ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st:-1 flags:0 ts:-1.000000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 0 flags:0 ts: 0.780000
-ret: 0 st: 0 flags:0 dts: 0.800000 pts: NOPTS pos: 653352 size: 22148
+ret: 0 st: 0 flags:0 dts: 0.800000 pts: NOPTS pos: 653420 size: 22124
ret: 0 st: 0 flags:1 ts:-0.320000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st: 1 flags:0 ts: 2.580000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 1 flags:1 ts: 1.480000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 2 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:0 dts: 0.360000 pts: NOPTS pos: 302688 size: 25108
+ret: 0 st: 0 flags:0 dts: 0.360000 pts: NOPTS pos: 302672 size: 25116
ret: 0 st: 2 flags:1 ts:-0.740000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 0 flags:0 ts:-0.060000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 1 flags:0 ts: 1.740000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 1 flags:1 ts: 0.620000
-ret: 0 st: 0 flags:0 dts: 0.640000 pts: NOPTS pos: 497180 size: 21596
+ret: 0 st: 0 flags:0 dts: 0.640000 pts: NOPTS pos: 497196 size: 21612
ret: 0 st: 2 flags:0 ts:-0.480000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st: 2 flags:1 ts: 2.420000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:0 dts: 0.200000 pts: NOPTS pos: 209516 size: 22968
+ret: 0 st: 0 flags:0 dts: 0.200000 pts: NOPTS pos: 209504 size: 22964
ret: 0 st: 0 flags:0 ts:-0.900000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st: 0 flags:1 ts: 1.980000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 1 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:0 dts: 0.880000 pts: NOPTS pos: 696068 size: 22484
+ret: 0 st: 0 flags:0 dts: 0.880000 pts: NOPTS pos: 696160 size: 21820
ret: 0 st: 1 flags:1 ts:-0.220000
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
ret: 0 st: 2 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st: 2 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741664 size: 54748
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 741124 size: 54736
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 370672 size: 54640
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 370700 size: 54628
ret: 0 st:-1 flags:1 ts:-0.645825
ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 5024 size: 65536
diff --git a/tests/ref/seek/lavf-jpg b/tests/ref/seek/lavf-jpg
index 88964cad05..4f3a14ca84 100644
--- a/tests/ref/seek/lavf-jpg
+++ b/tests/ref/seek/lavf-jpg
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size: 27771
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size: 28197
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size: 27950
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-mkv b/tests/ref/seek/lavf-mkv
index fd4fcf10d1..11275d6e4c 100644
--- a/tests/ref/seek/lavf-mkv
+++ b/tests/ref/seek/lavf-mkv
@@ -1,53 +1,48 @@
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 661 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292268 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292268 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834
ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
-ret: 0 st: 1 flags:0 ts: 2.577000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
+ret:-1 st: 1 flags:0 ts: 2.577000
ret: 0 st: 1 flags:1 ts: 1.471000
-ret: 0 st: 1 flags:1 dts: 0.982000 pts: 0.982000 pos: 320109 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320132 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146821 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146844 size: 27925
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
-ret: 0 st: 0 flags:0 ts: 2.153000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
+ret:-1 st: 0 flags:0 ts: 2.153000
ret: 0 st: 0 flags:1 ts: 1.048000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292268 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834
ret: 0 st: 1 flags:0 ts:-0.058000
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 661 size: 208
ret: 0 st: 1 flags:1 ts: 2.836000
-ret: 0 st: 1 flags:1 dts: 0.982000 pts: 0.982000 pos: 320109 size: 209
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret:-EOF
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320132 size: 209
+ret:-1 st:-1 flags:0 ts: 1.730004
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146821 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146844 size: 27925
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292268 size: 27834
-ret: 0 st: 1 flags:0 ts: 1.307000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834
+ret:-1 st: 1 flags:0 ts: 1.307000
ret: 0 st: 1 flags:1 ts: 0.201000
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 661 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292268 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834
ret: 0 st: 0 flags:0 ts: 0.883000
-ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292268 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292291 size: 27834
ret: 0 st: 0 flags:1 ts:-0.222000
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
-ret: 0 st: 1 flags:0 ts: 2.672000
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
+ret:-1 st: 1 flags:0 ts: 2.672000
ret: 0 st: 1 flags:1 ts: 1.566000
-ret: 0 st: 1 flags:1 dts: 0.982000 pts: 0.982000 pos: 320109 size: 209
+ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320132 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146821 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146844 size: 27925
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 1 flags:1 dts:-0.011000 pts:-0.011000 pos: 630 size: 208
+ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 877 size: 27837
diff --git a/tests/ref/seek/lavf-mmf b/tests/ref/seek/lavf-mmf
index 196d2632a0..0bc98fa9e3 100644
--- a/tests/ref/seek/lavf-mmf
+++ b/tests/ref/seek/lavf-mmf
@@ -1,27 +1,44 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size: 4096
-ret:-1 st:-1 flags:0 ts:-1.000000
-ret:-1 st:-1 flags:1 ts: 1.894167
-ret:-1 st: 0 flags:0 ts: 0.788345
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 83 size: 4096
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 83 size: 4096
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
+ret: 0 st: 0 flags:0 ts: 0.788345
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
ret:-1 st: 0 flags:1 ts:-0.317506
ret:-1 st:-1 flags:0 ts: 2.576668
-ret:-1 st:-1 flags:1 ts: 1.470835
-ret:-1 st: 0 flags:0 ts: 0.365011
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
+ret: 0 st: 0 flags:0 ts: 0.365011
+ret: 0 st: 0 flags:1 dts: 0.371519 pts: 0.371519 pos: 8275 size: 4096
ret:-1 st: 0 flags:1 ts:-0.740839
ret:-1 st:-1 flags:0 ts: 2.153336
-ret:-1 st:-1 flags:1 ts: 1.047503
-ret:-1 st: 0 flags:0 ts:-0.058322
-ret:-1 st: 0 flags:1 ts: 2.835828
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
+ret: 0 st: 0 flags:0 ts:-0.058322
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 83 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.835828
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
ret:-1 st:-1 flags:0 ts: 1.730004
-ret:-1 st:-1 flags:1 ts: 0.624171
-ret:-1 st: 0 flags:0 ts:-0.481655
-ret:-1 st: 0 flags:1 ts: 2.412494
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.557279 pts: 0.557279 pos: 12371 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.481655
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 83 size: 4096
+ret: 0 st: 0 flags:1 ts: 2.412494
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
ret:-1 st:-1 flags:0 ts: 1.306672
-ret:-1 st:-1 flags:1 ts: 0.200839
-ret:-1 st: 0 flags:0 ts:-0.904989
-ret:-1 st: 0 flags:1 ts: 1.989184
-ret:-1 st:-1 flags:0 ts: 0.883340
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.185760 pts: 0.185760 pos: 4179 size: 4096
+ret: 0 st: 0 flags:0 ts:-0.904989
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 83 size: 4096
+ret: 0 st: 0 flags:1 ts: 1.989184
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
ret:-1 st:-1 flags:1 ts:-0.222493
ret:-1 st: 0 flags:0 ts: 2.671678
-ret:-1 st: 0 flags:1 ts: 1.565850
-ret:-1 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 ts: 1.565850
+ret: 0 st: 0 flags:1 dts: 0.928798 pts: 0.928798 pos: 20563 size: 2048
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.557279 pts: 0.557279 pos: 12371 size: 4096
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-mov b/tests/ref/seek/lavf-mov
index 0091915e19..27ea7c7730 100644
--- a/tests/ref/seek/lavf-mov
+++ b/tests/ref/seek/lavf-mov
@@ -1,48 +1,48 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 325248 size: 1024
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326272 size: 27834
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 326971 size: 1024
+ret: 0 st: 0 flags:0 ts: 0.788359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327995 size: 27834
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret:-1 st: 1 flags:0 ts: 2.576667
ret: 0 st: 1 flags:1 ts: 1.470839
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326272 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327995 size: 27834
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 163526 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 165249 size: 27925
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
-ret:-1 st: 0 flags:0 ts: 2.160000
-ret: 0 st: 0 flags:1 ts: 1.040000
-ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 325248 size: 1024
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
+ret:-1 st: 0 flags:0 ts: 2.153359
+ret: 0 st: 0 flags:1 ts: 1.047500
+ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 326971 size: 1024
ret: 0 st: 1 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret: 0 st: 1 flags:1 ts: 2.835828
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326272 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327995 size: 27834
ret:-1 st:-1 flags:0 ts: 1.730004
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 1 flags:1 dts: 0.464399 pts: 0.464399 pos: 162502 size: 1024
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 325248 size: 1024
+ret: 0 st: 1 flags:1 dts: 0.464399 pts: 0.464399 pos: 164225 size: 1024
+ret: 0 st: 0 flags:0 ts:-0.481641
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 326971 size: 1024
ret:-1 st: 1 flags:0 ts: 1.306667
ret: 0 st: 1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 325248 size: 1024
-ret: 0 st: 0 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326272 size: 27834
-ret: 0 st: 0 flags:1 ts:-0.240000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 1 flags:1 dts: 0.952018 pts: 0.952018 pos: 326971 size: 1024
+ret: 0 st: 0 flags:0 ts: 0.883359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327995 size: 27834
+ret: 0 st: 0 flags:1 ts:-0.222500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
ret:-1 st: 1 flags:0 ts: 2.671678
ret: 0 st: 1 flags:1 ts: 1.565850
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326272 size: 27834
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 327995 size: 27834
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 163526 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 165249 size: 27925
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 1767 size: 27837
diff --git a/tests/ref/seek/lavf-mpg b/tests/ref/seek/lavf-mpg
index 6e27064684..e804b84739 100644
--- a/tests/ref/seek/lavf-mpg
+++ b/tests/ref/seek/lavf-mpg
@@ -1,53 +1,53 @@
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:0 dts: 1.880000 pts: 1.920000 pos: 315392 size: 12800
+ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 size: 314
ret: 0 st: 0 flags:0 ts: 0.788333
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 0 flags:0 dts: 0.820000 pts: 0.860000 pos: 118784 size: 14717
ret: 0 st: 0 flags:1 ts:-0.317500
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st: 1 flags:0 ts: 2.576667
-ret: 0 st: 1 flags:1 dts: 1.812767 pts: 1.812767 pos: 368652 size: 379
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size: 379
ret: 0 st: 1 flags:1 ts: 1.470833
-ret: 0 st: 1 flags:1 dts: 1.290322 pts: 1.290322 pos: 145408 size: 261
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size: 379
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st: 0 flags:0 ts: 2.153333
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 2.000000 pos: 339968 size: 681
+ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 size: 314
ret: 0 st: 0 flags:1 ts: 1.047500
-ret: 0 st: 0 flags:0 dts: 1.040000 pts: 1.080000 pos: 26624 size: 16303
+ret: 0 st: 0 flags:0 dts: 1.020000 pts: 1.060000 pos: 196608 size: 17639
ret: 0 st: 1 flags:0 ts:-0.058333
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st: 1 flags:1 ts: 2.835833
-ret: 0 st: 1 flags:1 dts: 1.812767 pts: 1.812767 pos: 368652 size: 379
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size: 379
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:0 dts: 1.760000 pts: 1.800000 pos: 280588 size: 13050
+ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 size: 314
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 0 flags:0 dts: 0.620000 pts: 0.660000 pos: 55296 size: 14239
ret: 0 st: 0 flags:0 ts:-0.481667
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st: 0 flags:1 ts: 2.412500
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 2.000000 pos: 339968 size: 681
+ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 size: 314
ret: 0 st: 1 flags:0 ts: 1.306667
-ret: 0 st: 1 flags:1 dts: 1.551544 pts: 1.551544 pos: 342028 size: 314
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size: 379
ret: 0 st: 1 flags:1 ts: 0.200844
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 2.000000 pos: 339968 size: 681
+ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 size: 314
ret: 0 st: 0 flags:0 ts: 0.883344
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 0 flags:0 dts: 0.900000 pts: 0.940000 pos: 147456 size: 12755
ret: 0 st: 0 flags:1 ts:-0.222489
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st: 1 flags:0 ts: 2.671678
-ret: 0 st: 1 flags:1 dts: 1.812767 pts: 1.812767 pos: 368652 size: 379
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size: 379
ret: 0 st: 1 flags:1 ts: 1.565844
-ret: 0 st: 1 flags:1 dts: 1.551544 pts: 1.551544 pos: 342028 size: 314
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size: 379
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 1 flags:1 dts: 1.029089 pts: 1.029089 pos: 2048 size: 208
+ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 2048 size: 208
diff --git a/tests/ref/seek/lavf-mxf b/tests/ref/seek/lavf-mxf
index c65e868350..f1aaa197d6 100644
--- a/tests/ref/seek/lavf-mxf
+++ b/tests/ref/seek/lavf-mxf
@@ -1,48 +1,48 @@
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret:-1 st: 1 flags:0 ts: 2.576667
ret: 0 st: 1 flags:1 ts: 1.470833
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24799
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24786
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret:-1 st: 0 flags:0 ts: 2.160000
ret: 0 st: 0 flags:1 ts: 1.040000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st: 1 flags:0 ts:-0.058333
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret: 0 st: 1 flags:1 ts: 2.835833
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret:-1 st:-1 flags:0 ts: 1.730004
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24799
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211968 size: 24786
ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret:-1 st: 1 flags:0 ts: 1.306667
ret: 0 st: 1 flags:1 ts: 0.200833
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st: 0 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st: 0 flags:1 ts:-0.240000
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
ret:-1 st: 1 flags:0 ts: 2.671667
ret: 0 st: 1 flags:1 ts: 1.565833
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24724
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460800 size: 24711
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24813
+ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6656 size: 24801
diff --git a/tests/ref/seek/lavf-mxf_opatom b/tests/ref/seek/lavf-mxf_opatom
new file mode 100644
index 0000000000..ca17ba78f9
--- /dev/null
+++ b/tests/ref/seek/lavf-mxf_opatom
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3773465 size:188416
+ret: 0 st: 0 flags:1 ts:-0.320000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1700889 size:188416
+ret: 0 st: 0 flags:1 ts:-0.760000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:3019801 size:188416
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 947225 size:188416
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4150297 size:188416
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
+ret: 0 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2266137 size:188416
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416
diff --git a/tests/ref/seek/lavf-mxf_opatom_audio b/tests/ref/seek/lavf-mxf_opatom_audio
new file mode 100644
index 0000000000..12d4644dc2
--- /dev/null
+++ b/tests/ref/seek/lavf-mxf_opatom_audio
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st: 0 flags:0 ts: 0.788333
+ret: 0 st: 0 flags:1 dts: 0.788333 pts: 0.788333 pos: 80825 size: 3840
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.365000 pts: 0.365000 pos: 40185 size: 3840
+ret: 0 st: 0 flags:1 ts:-0.740833
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st: 0 flags:0 ts:-0.058333
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st: 0 flags:1 ts: 2.835833
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.624167 pts: 0.624167 pos: 65065 size: 3840
+ret: 0 st: 0 flags:0 ts:-0.481667
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200833 pts: 0.200833 pos: 24425 size: 3840
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st: 0 flags:1 ts: 1.989167
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 89945 size: 3840
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
+ret: 0 st: 0 flags:0 ts: 2.671667
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st: 0 flags:1 ts: 1.565833
+ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101143 size: 2
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 49305 size: 3840
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size: 3840
diff --git a/tests/ref/seek/lavf-nut b/tests/ref/seek/lavf-nut
index 46f1ea2cc9..b2da52629b 100644
--- a/tests/ref/seek/lavf-nut
+++ b/tests/ref/seek/lavf-nut
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 395 size: 208
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
-ret: 0 st: 1 flags:0 ts: 2.586122
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 1 flags:1 ts: 1.462857
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 0 flags:0 ts: 0.788340
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
+ret: 0 st: 1 flags:0 ts: 2.576667
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271315 size: 209
+ret: 0 st: 1 flags:1 ts: 1.470839
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271315 size: 209
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
-ret: 0 st: 0 flags:0 ts: 2.160000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 0 flags:1 ts: 1.040000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 1 flags:0 ts:-0.052245
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
-ret: 0 st: 1 flags:1 ts: 2.847347
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
+ret: 0 st: 0 flags:0 ts: 2.153340
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 0 flags:1 ts: 1.047500
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 1 flags:0 ts:-0.058322
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 395 size: 208
+ret: 0 st: 1 flags:1 ts: 2.835828
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271315 size: 209
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 1 flags:0 ts: 1.306122
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 1 flags:1 ts: 0.208980
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 0 flags:0 ts:-0.481660
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 1 flags:0 ts: 1.306667
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271315 size: 209
+ret: 0 st: 1 flags:1 ts: 0.200839
+ret: 0 st: 1 flags:1 dts: 0.182857 pts: 0.182857 pos: 71957 size: 209
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 0 flags:0 ts: 0.880000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 0 flags:1 ts:-0.240000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
-ret: 0 st: 1 flags:0 ts: 2.664490
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
-ret: 0 st: 1 flags:1 ts: 1.567347
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 0 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
+ret: 0 st: 0 flags:1 ts:-0.222500
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
+ret: 0 st: 1 flags:0 ts: 2.671678
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271315 size: 209
+ret: 0 st: 1 flags:1 ts: 1.565850
+ret: 0 st: 1 flags:1 dts: 0.862041 pts: 0.862041 pos: 271315 size: 209
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146353 size: 27925
+ret: 0 st: 0 flags:1 dts: 0.490918 pts: 0.490918 pos: 146490 size: 27925
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 295 size: 27837
+ret: 0 st: 0 flags:1 dts: 0.010918 pts: 0.010918 pos: 623 size: 27837
diff --git a/tests/ref/seek/lavf-ogg b/tests/ref/seek/lavf-ogg
index 109ae3226d..caf4879075 100644
--- a/tests/ref/seek/lavf-ogg
+++ b/tests/ref/seek/lavf-ogg
@@ -1,44 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 124 size: 1364
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 124 size: 1364
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:1 ts: 1.894167
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:0 ts: 0.788345
-ret:-EOF
-ret:-1 st: 0 flags:1 ts:-0.317506
-ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st: 0 flags:1 ts:-0.317506
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:1 ts: 1.470835
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:0 ts: 0.365011
-ret:-EOF
-ret:-1 st: 0 flags:1 ts:-0.740839
-ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st: 0 flags:1 ts:-0.740839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:1 ts: 1.047503
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 124 size: 1364
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:1 ts: 2.835828
-ret:-EOF
-ret:-1 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:1 ts: 0.624171
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 124 size: 1364
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:1 ts: 2.412494
-ret:-EOF
-ret:-1 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:1 ts: 0.200839
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 124 size: 1364
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:1 ts: 1.989184
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:0 ts: 0.883340
-ret:-EOF
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st: 0 flags:0 ts: 2.671678
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st: 0 flags:1 ts: 1.565850
-ret:-EOF
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
ret: 0 st:-1 flags:0 ts: 0.460008
-ret:-EOF
-ret:-1 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 164 size: 1364
diff --git a/tests/ref/seek/lavf-pbmpipe b/tests/ref/seek/lavf-pbmpipe
index 2858934786..25bb68f996 100644
--- a/tests/ref/seek/lavf-pbmpipe
+++ b/tests/ref/seek/lavf-pbmpipe
@@ -1,27 +1,27 @@
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:317075
-ret:-EINVAL st:-1 flags:0 ts:-1.000000
-ret:-EINVAL st:-1 flags:1 ts: 1.894167
-ret:-EINVAL st: 0 flags:0 ts: 0.800000
-ret:-EINVAL st: 0 flags:1 ts:-0.320000
-ret:-EINVAL st:-1 flags:0 ts: 2.576668
-ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
-ret:-EINVAL st: 0 flags:1 ts:-0.760000
-ret:-EINVAL st:-1 flags:0 ts: 2.153336
-ret:-EINVAL st:-1 flags:1 ts: 1.047503
-ret:-EINVAL st: 0 flags:0 ts:-0.040000
-ret:-EINVAL st: 0 flags:1 ts: 2.840000
-ret:-EINVAL st:-1 flags:0 ts: 1.730004
-ret:-EINVAL st:-1 flags:1 ts: 0.624171
-ret:-EINVAL st: 0 flags:0 ts:-0.480000
-ret:-EINVAL st: 0 flags:1 ts: 2.400000
-ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
-ret:-EINVAL st: 0 flags:0 ts:-0.920000
-ret:-EINVAL st: 0 flags:1 ts: 2.000000
-ret:-EINVAL st:-1 flags:0 ts: 0.883340
-ret:-EINVAL st:-1 flags:1 ts:-0.222493
-ret:-EINVAL st: 0 flags:0 ts: 2.680000
-ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
-ret:-EINVAL st:-1 flags:1 ts:-0.645825
+ret:-1 st:-1 flags:0 ts:-1.000000
+ret:-1 st:-1 flags:1 ts: 1.894167
+ret:-1 st: 0 flags:0 ts: 0.800000
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret:-1 st:-1 flags:1 ts: 1.470835
+ret:-1 st: 0 flags:0 ts: 0.360000
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret:-1 st:-1 flags:1 ts: 1.047503
+ret:-1 st: 0 flags:0 ts:-0.040000
+ret:-1 st: 0 flags:1 ts: 2.840000
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret:-1 st:-1 flags:1 ts: 0.624171
+ret:-1 st: 0 flags:0 ts:-0.480000
+ret:-1 st: 0 flags:1 ts: 2.400000
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret:-1 st:-1 flags:1 ts: 0.200839
+ret:-1 st: 0 flags:0 ts:-0.920000
+ret:-1 st: 0 flags:1 ts: 2.000000
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret:-1 st: 0 flags:1 ts: 1.560000
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-pcx b/tests/ref/seek/lavf-pcx
index 418674f7a2..ba21627e86 100644
--- a/tests/ref/seek/lavf-pcx
+++ b/tests/ref/seek/lavf-pcx
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:363107
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:364760
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:362983
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-pgm b/tests/ref/seek/lavf-pgm
index 2836367b04..ceac0085bc 100644
--- a/tests/ref/seek/lavf-pgm
+++ b/tests/ref/seek/lavf-pgm
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:101391
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:101391
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:101391
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-pgmpipe b/tests/ref/seek/lavf-pgmpipe
index 8ba51807d8..57b4e4acc2 100644
--- a/tests/ref/seek/lavf-pgmpipe
+++ b/tests/ref/seek/lavf-pgmpipe
@@ -1,27 +1,27 @@
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:2534775
-ret:-EINVAL st:-1 flags:0 ts:-1.000000
-ret:-EINVAL st:-1 flags:1 ts: 1.894167
-ret:-EINVAL st: 0 flags:0 ts: 0.800000
-ret:-EINVAL st: 0 flags:1 ts:-0.320000
-ret:-EINVAL st:-1 flags:0 ts: 2.576668
-ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
-ret:-EINVAL st: 0 flags:1 ts:-0.760000
-ret:-EINVAL st:-1 flags:0 ts: 2.153336
-ret:-EINVAL st:-1 flags:1 ts: 1.047503
-ret:-EINVAL st: 0 flags:0 ts:-0.040000
-ret:-EINVAL st: 0 flags:1 ts: 2.840000
-ret:-EINVAL st:-1 flags:0 ts: 1.730004
-ret:-EINVAL st:-1 flags:1 ts: 0.624171
-ret:-EINVAL st: 0 flags:0 ts:-0.480000
-ret:-EINVAL st: 0 flags:1 ts: 2.400000
-ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
-ret:-EINVAL st: 0 flags:0 ts:-0.920000
-ret:-EINVAL st: 0 flags:1 ts: 2.000000
-ret:-EINVAL st:-1 flags:0 ts: 0.883340
-ret:-EINVAL st:-1 flags:1 ts:-0.222493
-ret:-EINVAL st: 0 flags:0 ts: 2.680000
-ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
-ret:-EINVAL st:-1 flags:1 ts:-0.645825
+ret:-1 st:-1 flags:0 ts:-1.000000
+ret:-1 st:-1 flags:1 ts: 1.894167
+ret:-1 st: 0 flags:0 ts: 0.800000
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret:-1 st:-1 flags:1 ts: 1.470835
+ret:-1 st: 0 flags:0 ts: 0.360000
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret:-1 st:-1 flags:1 ts: 1.047503
+ret:-1 st: 0 flags:0 ts:-0.040000
+ret:-1 st: 0 flags:1 ts: 2.840000
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret:-1 st:-1 flags:1 ts: 0.624171
+ret:-1 st: 0 flags:0 ts:-0.480000
+ret:-1 st: 0 flags:1 ts: 2.400000
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret:-1 st:-1 flags:1 ts: 0.200839
+ret:-1 st: 0 flags:0 ts:-0.920000
+ret:-1 st: 0 flags:1 ts: 2.000000
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret:-1 st: 0 flags:1 ts: 1.560000
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-ppm b/tests/ref/seek/lavf-ppm
index 6376b5ec4a..6d53ce06e6 100644
--- a/tests/ref/seek/lavf-ppm
+++ b/tests/ref/seek/lavf-ppm
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:304143
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:304143
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:304143
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-ppmpipe b/tests/ref/seek/lavf-ppmpipe
index 46c535af75..7087494ca5 100644
--- a/tests/ref/seek/lavf-ppmpipe
+++ b/tests/ref/seek/lavf-ppmpipe
@@ -1,27 +1,27 @@
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:7603575
-ret:-EINVAL st:-1 flags:0 ts:-1.000000
-ret:-EINVAL st:-1 flags:1 ts: 1.894167
-ret:-EINVAL st: 0 flags:0 ts: 0.800000
-ret:-EINVAL st: 0 flags:1 ts:-0.320000
-ret:-EINVAL st:-1 flags:0 ts: 2.576668
-ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
-ret:-EINVAL st: 0 flags:1 ts:-0.760000
-ret:-EINVAL st:-1 flags:0 ts: 2.153336
-ret:-EINVAL st:-1 flags:1 ts: 1.047503
-ret:-EINVAL st: 0 flags:0 ts:-0.040000
-ret:-EINVAL st: 0 flags:1 ts: 2.840000
-ret:-EINVAL st:-1 flags:0 ts: 1.730004
-ret:-EINVAL st:-1 flags:1 ts: 0.624171
-ret:-EINVAL st: 0 flags:0 ts:-0.480000
-ret:-EINVAL st: 0 flags:1 ts: 2.400000
-ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
-ret:-EINVAL st: 0 flags:0 ts:-0.920000
-ret:-EINVAL st: 0 flags:1 ts: 2.000000
-ret:-EINVAL st:-1 flags:0 ts: 0.883340
-ret:-EINVAL st:-1 flags:1 ts:-0.222493
-ret:-EINVAL st: 0 flags:0 ts: 2.680000
-ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
-ret:-EINVAL st:-1 flags:1 ts:-0.645825
+ret:-1 st:-1 flags:0 ts:-1.000000
+ret:-1 st:-1 flags:1 ts: 1.894167
+ret:-1 st: 0 flags:0 ts: 0.800000
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret:-1 st:-1 flags:1 ts: 1.470835
+ret:-1 st: 0 flags:0 ts: 0.360000
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret:-1 st:-1 flags:1 ts: 1.047503
+ret:-1 st: 0 flags:0 ts:-0.040000
+ret:-1 st: 0 flags:1 ts: 2.840000
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret:-1 st:-1 flags:1 ts: 0.624171
+ret:-1 st: 0 flags:0 ts:-0.480000
+ret:-1 st: 0 flags:1 ts: 2.400000
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret:-1 st:-1 flags:1 ts: 0.200839
+ret:-1 st: 0 flags:0 ts:-0.920000
+ret:-1 st: 0 flags:1 ts: 2.000000
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret:-1 st: 0 flags:1 ts: 1.560000
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-rm b/tests/ref/seek/lavf-rm
index adce9e0895..4b1917300e 100644
--- a/tests/ref/seek/lavf-rm
+++ b/tests/ref/seek/lavf-rm
@@ -1,53 +1,53 @@
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 387 size: 278
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 395 size: 278
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
ret: 0 st: 1 flags:0 ts: 2.577000
-ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346128 size: 278
+ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278
ret: 0 st: 1 flags:1 ts: 1.471000
-ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346128 size: 278
+ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 158515 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 158523 size: 31134
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
ret: 0 st: 0 flags:0 ts: 2.153000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 0 flags:1 ts: 1.048000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 1 flags:0 ts:-0.058000
-ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 387 size: 278
+ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 395 size: 278
ret: 0 st: 1 flags:1 ts: 2.836000
-ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346128 size: 278
+ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 158515 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 158523 size: 31134
ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 1 flags:0 ts: 1.307000
-ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346128 size: 278
+ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278
ret: 0 st: 1 flags:1 ts: 0.201000
-ret: 0 st: 1 flags:1 dts: 0.174000 pts: 0.174000 pos: 78969 size: 278
+ret: 0 st: 1 flags:1 dts: 0.174000 pts: 0.174000 pos: 78977 size: 278
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 0 flags:0 ts: 0.883000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314982 size: 31143
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143
ret: 0 st: 0 flags:1 ts:-0.222000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
ret: 0 st: 1 flags:0 ts: 2.672000
-ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346128 size: 278
+ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278
ret: 0 st: 1 flags:1 ts: 1.566000
-ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346128 size: 278
+ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 158515 size: 31134
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 158523 size: 31134
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 688 size: 31082
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082
diff --git a/tests/ref/seek/lavf-sgi b/tests/ref/seek/lavf-sgi
index b2f605ad94..b07132a669 100644
--- a/tests/ref/seek/lavf-sgi
+++ b/tests/ref/seek/lavf-sgi
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:308572
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:308294
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:307773
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-tga b/tests/ref/seek/lavf-tga
index 8f9075364f..ee7552a15d 100644
--- a/tests/ref/seek/lavf-tga
+++ b/tests/ref/seek/lavf-tga
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:304172
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:304172
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:304172
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-tiff b/tests/ref/seek/lavf-tiff
index 1b49f2f2e7..0d9fb04484 100644
--- a/tests/ref/seek/lavf-tiff
+++ b/tests/ref/seek/lavf-tiff
@@ -5,7 +5,8 @@ ret:-EINVAL st: 0 flags:0 ts: 0.800000
ret:-EINVAL st: 0 flags:1 ts:-0.320000
ret:-EINVAL st:-1 flags:0 ts: 2.576668
ret:-EINVAL st:-1 flags:1 ts: 1.470835
-ret:-EINVAL st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:307150
ret:-EINVAL st: 0 flags:1 ts:-0.760000
ret:-EINVAL st:-1 flags:0 ts: 2.153336
ret:-EINVAL st:-1 flags:1 ts: 1.047503
@@ -16,12 +17,14 @@ ret:-EINVAL st:-1 flags:1 ts: 0.624171
ret:-EINVAL st: 0 flags:0 ts:-0.480000
ret:-EINVAL st: 0 flags:1 ts: 2.400000
ret:-EINVAL st:-1 flags:0 ts: 1.306672
-ret:-EINVAL st:-1 flags:1 ts: 0.200839
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:307140
ret:-EINVAL st: 0 flags:0 ts:-0.920000
ret:-EINVAL st: 0 flags:1 ts: 2.000000
ret:-EINVAL st:-1 flags:0 ts: 0.883340
ret:-EINVAL st:-1 flags:1 ts:-0.222493
ret:-EINVAL st: 0 flags:0 ts: 2.680000
ret:-EINVAL st: 0 flags:1 ts: 1.560000
-ret:-EINVAL st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:307140
ret:-EINVAL st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-ts b/tests/ref/seek/lavf-ts
index b31fab052c..e57651ef9c 100644
--- a/tests/ref/seek/lavf-ts
+++ b/tests/ref/seek/lavf-ts
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:0 dts: 1.480000 pts: 1.520000 pos: 44932 size: 14502
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.920000 pos: 189692 size: 24786
ret: 0 st: 0 flags:0 ts: 0.788333
-ret: 0 st: 0 flags:0 dts: 1.560000 pts: 1.600000 pos: 74260 size: 13388
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 0 flags:1 ts:-0.317500
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 1 flags:0 ts: 2.576667
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 404576 size: 209
ret: 0 st: 1 flags:1 ts: 1.470833
-ret: 0 st: 0 flags:0 dts: 2.120000 pts: 2.160000 pos: 294032 size: 13839
+ret: 0 st: 1 flags:1 dts: 1.429089 pts: 1.429089 pos: 159988 size: 208
ret: 0 st:-1 flags:0 ts: 0.365002
-ret: 0 st: 0 flags:0 dts: 1.480000 pts: 1.520000 pos: 44932 size: 14502
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st:-1 flags:1 ts:-0.740831
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 0 flags:0 ts: 2.153333
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 1 flags:1 dts: 1.794811 pts: 1.794811 pos: 322608 size: 209
ret: 0 st: 0 flags:1 ts: 1.047500
-ret: 0 st: 0 flags:0 dts: 1.720000 pts: 1.760000 pos: 130096 size: 14133
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 1 flags:0 ts:-0.058333
-ret: 0 st: 0 flags:0 dts: 1.480000 pts: 1.520000 pos: 44932 size: 14502
+ret: 0 st: 1 flags:1 dts: 1.429089 pts: 1.429089 pos: 159988 size: 208
ret: 0 st: 1 flags:1 ts: 2.835833
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 404576 size: 209
ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 1 flags:1 dts: 1.429089 pts: 1.429089 pos: 159988 size: 208
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 0 flags:0 ts:-0.481667
-ret: 0 st: 0 flags:0 dts: 1.480000 pts: 1.520000 pos: 44932 size: 14502
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 0 flags:1 ts: 2.412500
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 404576 size: 209
ret: 0 st: 1 flags:0 ts: 1.306667
-ret: 0 st: 0 flags:0 dts: 2.040000 pts: 2.080000 pos: 265644 size: 12390
+ret: 0 st: 1 flags:1 dts: 1.429089 pts: 1.429089 pos: 159988 size: 208
ret: 0 st: 1 flags:1 ts: 0.200844
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 1 flags:1 dts: 1.429089 pts: 1.429089 pos: 159988 size: 208
ret: 0 st:-1 flags:0 ts:-0.904994
-ret: 0 st: 0 flags:0 dts: 1.480000 pts: 1.520000 pos: 44932 size: 14502
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st:-1 flags:1 ts: 1.989173
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 0 flags:0 dts: 1.960000 pts: 2.000000 pos: 235000 size: 15019
ret: 0 st: 0 flags:0 ts: 0.883344
-ret: 0 st: 0 flags:0 dts: 1.640000 pts: 1.680000 pos: 102836 size: 12781
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 0 flags:1 ts:-0.222489
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st: 1 flags:0 ts: 2.671678
-ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 403636 size: 209
+ret: 0 st: 1 flags:1 dts: 2.160522 pts: 2.160522 pos: 404576 size: 209
ret: 0 st: 1 flags:1 ts: 1.565844
-ret: 0 st: 0 flags:0 dts: 2.200000 pts: 2.240000 pos: 325240 size: 12679
+ret: 0 st: 1 flags:1 dts: 1.429089 pts: 1.429089 pos: 159988 size: 208
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:0 dts: 1.480000 pts: 1.520000 pos: 44932 size: 14502
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24813
+ret: 0 st: 0 flags:1 dts: 1.400000 pts: 1.440000 pos: 564 size: 24801
diff --git a/tests/ref/seek/lavf-voc b/tests/ref/seek/lavf-voc
index 387aef6cb8..483c782e78 100644
--- a/tests/ref/seek/lavf-voc
+++ b/tests/ref/seek/lavf-voc
@@ -1,27 +1,44 @@
ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 1024
-ret:-1 st:-1 flags:0 ts:-1.000000
-ret:-1 st:-1 flags:1 ts: 1.894167
-ret:-1 st: 0 flags:0 ts: 0.788335
-ret:-1 st: 0 flags:1 ts:-0.317508
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 1024
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret:-EOF
+ret: 0 st: 0 flags:0 ts: 0.788330
+ret: 0 st: 0 flags:1 dts: 0.800773 pts: 0.800773 pos: 33956 size: 1024
+ret:-1 st: 0 flags:1 ts:-0.317494
ret:-1 st:-1 flags:0 ts: 2.576668
-ret:-1 st:-1 flags:1 ts: 1.470835
-ret:-1 st: 0 flags:0 ts: 0.365006
-ret:-1 st: 0 flags:1 ts:-0.740837
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret:-EOF
+ret: 0 st: 0 flags:0 ts: 0.365012
+ret: 0 st: 0 flags:1 dts: 0.376834 pts: 0.376834 pos: 15452 size: 1024
+ret:-1 st: 0 flags:1 ts:-0.740834
ret:-1 st:-1 flags:0 ts: 2.153336
-ret:-1 st:-1 flags:1 ts: 1.047503
-ret:-1 st: 0 flags:0 ts:-0.058323
-ret:-1 st: 0 flags:1 ts: 2.835834
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret:-EOF
+ret: 0 st: 0 flags:0 ts:-0.058328
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 1024
+ret: 0 st: 0 flags:1 ts: 2.835848
+ret:-EOF
ret:-1 st:-1 flags:0 ts: 1.730004
-ret:-1 st:-1 flags:1 ts: 0.624171
-ret:-1 st: 0 flags:0 ts:-0.481652
-ret:-1 st: 0 flags:1 ts: 2.412505
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.612356 pts: 0.612356 pos: 25732 size: 1024
+ret: 0 st: 0 flags:0 ts:-0.481669
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 1024
+ret: 0 st: 0 flags:1 ts: 2.412507
+ret:-EOF
ret:-1 st:-1 flags:0 ts: 1.306672
-ret:-1 st:-1 flags:1 ts: 0.200839
-ret:-1 st: 0 flags:0 ts:-0.905003
-ret:-1 st: 0 flags:1 ts: 1.989176
-ret:-1 st:-1 flags:0 ts: 0.883340
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.188417 pts: 0.188417 pos: 7228 size: 1024
+ret: 0 st: 0 flags:0 ts:-0.904986
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 32 size: 1024
+ret: 0 st: 0 flags:1 ts: 1.989167
+ret:-EOF
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.894981 pts: 0.894981 pos: 38068 size: 1024
ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.671668
-ret:-1 st: 0 flags:1 ts: 1.565847
-ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st: 0 flags:0 ts: 2.671673
+ret: 0 st: 0 flags:1 ts: 1.565849
+ret:-EOF
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.471043 pts: 0.471043 pos: 19564 size: 1024
ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/lavf-wav b/tests/ref/seek/lavf-wav
index 1a9cfc54c7..ed2f8d62de 100644
--- a/tests/ref/seek/lavf-wav
+++ b/tests/ref/seek/lavf-wav
@@ -1,53 +1,53 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st:-1 flags:1 ts: 1.894167
ret:-EOF
ret: 0 st: 0 flags:0 ts: 0.788345
-ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69578 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 69606 size: 4096
ret: 0 st: 0 flags:1 ts:-0.317506
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st:-1 flags:0 ts: 2.576668
ret:-EOF
ret: 0 st:-1 flags:1 ts: 1.470835
ret:-EOF
ret: 0 st: 0 flags:0 ts: 0.365011
-ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32240 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.365011 pts: 0.365011 pos: 32268 size: 4096
ret: 0 st: 0 flags:1 ts:-0.740839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st:-1 flags:0 ts: 2.153336
ret:-EOF
ret: 0 st:-1 flags:1 ts: 1.047503
ret:-EOF
ret: 0 st: 0 flags:0 ts:-0.058322
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st: 0 flags:1 ts: 2.835828
ret:-EOF
ret: 0 st:-1 flags:0 ts: 1.730004
ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55098 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 55126 size: 4096
ret: 0 st: 0 flags:0 ts:-0.481655
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st: 0 flags:1 ts: 2.412494
ret:-EOF
ret: 0 st:-1 flags:0 ts: 1.306672
ret:-EOF
ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17760 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.200839 pts: 0.200839 pos: 17788 size: 4096
ret: 0 st: 0 flags:0 ts:-0.904989
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st: 0 flags:1 ts: 1.989184
ret:-EOF
ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77956 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 77984 size: 4096
ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
ret: 0 st: 0 flags:0 ts: 2.671678
ret:-EOF
ret: 0 st: 0 flags:1 ts: 1.565850
ret:-EOF
ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40618 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 40646 size: 4096
ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 46 size: 4096
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 74 size: 4096
diff --git a/tests/ref/seek/lavf-wtv b/tests/ref/seek/lavf-wtv
new file mode 100644
index 0000000000..355ab98d85
--- /dev/null
+++ b/tests/ref/seek/lavf-wtv
@@ -0,0 +1,48 @@
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret: 0 st: 0 flags:1 ts:-0.317499
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret:-1 st: 1 flags:0 ts: 2.576668
+ret: 0 st: 1 flags:1 ts: 1.470835
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret: 0 st:-1 flags:0 ts: 0.365002
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st:-1 flags:1 ts:-0.740831
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret:-1 st: 0 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 ts: 1.047503
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st: 1 flags:0 ts:-0.058330
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st: 1 flags:1 ts: 2.835837
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret:-1 st: 1 flags:0 ts: 1.306672
+ret: 0 st: 1 flags:1 ts: 0.200839
+ret: 0 st: 1 flags:1 dts: 0.211950 pts: 0.211950 pos: 99280 size: 209
+ret: 0 st:-1 flags:0 ts:-0.904994
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st:-1 flags:1 ts: 1.989173
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret: 0 st: 0 flags:0 ts: 0.883340
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret: 0 st: 0 flags:1 ts:-0.222493
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret:-1 st: 1 flags:0 ts: 2.671674
+ret: 0 st: 1 flags:1 ts: 1.565841
+ret: 0 st: 1 flags:1 dts: 0.734399 pts: 0.734399 pos: 294672 size: 209
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 1 flags:1 dts: 0.029093 pts: 0.029093 pos: 26272 size: 208
diff --git a/tests/ref/seek/vsynth2-asv1 b/tests/ref/seek/vsynth2-asv1
deleted file mode 100644
index b3cca3b0c7..0000000000
--- a/tests/ref/seek/vsynth2-asv1
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 17484
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 17484
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 939696 size: 22704
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 364636 size: 19476
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 717284 size: 21768
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 160544 size: 17672
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 484496 size: 20396
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 17484
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 985140 size: 22640
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 849824 size: 22364
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 288188 size: 18920
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 17484
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 985140 size: 22640
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 631032 size: 21416
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 90952 size: 17244
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 17484
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 985140 size: 22640
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 403836 size: 20024
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 761056 size: 22012
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 214224 size: 18228
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-asv2 b/tests/ref/seek/vsynth2-asv2
deleted file mode 100644
index 906c2358e4..0000000000
--- a/tests/ref/seek/vsynth2-asv2
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 16584
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 16584
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 891064 size: 21664
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 343044 size: 18440
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 678500 size: 20848
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 151024 size: 16584
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 456544 size: 19448
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 16584
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 934400 size: 21624
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 805248 size: 21364
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 271044 size: 17784
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 16584
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 934400 size: 21624
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 596008 size: 20456
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 85924 size: 16152
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 16584
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 934400 size: 21624
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 380220 size: 18948
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 720420 size: 21060
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 201408 size: 17128
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-dnxhd-1080i b/tests/ref/seek/vsynth2-dnxhd-1080i
deleted file mode 100644
index 6c41d67986..0000000000
--- a/tests/ref/seek/vsynth2-dnxhd-1080i
+++ /dev/null
@@ -1,44 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret:-1 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret:-1 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 ts:-0.760000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret:-1 st:-1 flags:0 ts: 1.730004
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret:-1 st:-1 flags:0 ts: 1.306672
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret:-1 st:-1 flags:0 ts: 0.883340
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
-ret:-1 st:-1 flags:0 ts: 0.460008
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
diff --git a/tests/ref/seek/vsynth2-dnxhd-720p b/tests/ref/seek/vsynth2-dnxhd-720p
deleted file mode 100644
index b6398b60d7..0000000000
--- a/tests/ref/seek/vsynth2-dnxhd-720p
+++ /dev/null
@@ -1,40 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st: 0 flags:0 ts: 0.800000
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st: 0 flags:0 ts: 0.360000
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 1.730004
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 1.306672
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 0.883340
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 0.460008
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-dnxhd-720p-rd b/tests/ref/seek/vsynth2-dnxhd-720p-rd
deleted file mode 100644
index b6398b60d7..0000000000
--- a/tests/ref/seek/vsynth2-dnxhd-720p-rd
+++ /dev/null
@@ -1,40 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st: 0 flags:0 ts: 0.800000
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st: 0 flags:0 ts: 0.360000
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 1.730004
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 1.306672
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 0.883340
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
-ret:-1 st:-1 flags:0 ts: 0.460008
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-dv b/tests/ref/seek/vsynth2-dv
deleted file mode 100644
index baaeefb2cf..0000000000
--- a/tests/ref/seek/vsynth2-dv
+++ /dev/null
@@ -1,53 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts:-0.760000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
diff --git a/tests/ref/seek/vsynth2-dv-411 b/tests/ref/seek/vsynth2-dv-411
deleted file mode 100644
index baaeefb2cf..0000000000
--- a/tests/ref/seek/vsynth2-dv-411
+++ /dev/null
@@ -1,53 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts:-0.760000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
-ret: 0 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:144000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: -1 size:144000
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:144000
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:144000
diff --git a/tests/ref/seek/vsynth2-dv-50 b/tests/ref/seek/vsynth2-dv-50
deleted file mode 100644
index 1f07e5b71f..0000000000
--- a/tests/ref/seek/vsynth2-dv-50
+++ /dev/null
@@ -1,53 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: -1 size:288000
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: -1 size:288000
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: -1 size:288000
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: -1 size:288000
-ret: 0 st: 0 flags:1 ts:-0.760000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: -1 size:288000
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: -1 size:288000
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: -1 size:288000
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
-ret: 0 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: -1 size:288000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: -1 size:288000
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: -1 size:288000
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: -1 size:288000
diff --git a/tests/ref/seek/vsynth2-ffv1 b/tests/ref/seek/vsynth2-ffv1
deleted file mode 100644
index 153becbae1..0000000000
--- a/tests/ref/seek/vsynth2-ffv1
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71768
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71768
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2589296 size: 81788
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1666112 size: 77204
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2589296 size: 81788
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 808352 size: 70696
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1666112 size: 77204
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71768
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3550788 size: 83738
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3550788 size: 83738
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 808352 size: 70696
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71768
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3550788 size: 83738
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2589296 size: 81788
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71768
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5688 size: 71768
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3550788 size: 83738
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1666112 size: 77204
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2589296 size: 81788
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 808352 size: 70696
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-flashsv b/tests/ref/seek/vsynth2-flashsv
deleted file mode 100644
index 82acde81d6..0000000000
--- a/tests/ref/seek/vsynth2-flashsv
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size:219405
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size:219405
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:10902646 size:244577
-ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4458610 size:230521
-ret:-1 st: 0 flags:1 ts:-0.317000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:8234830 size:240794
-ret: 0 st: 0 flags:0 ts: 0.365000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: 0.400000 pos:2201083 size:221959
-ret:-1 st: 0 flags:1 ts:-0.741000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:5853907 size:235507
-ret: 0 st: 0 flags:0 ts:-0.058000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size:219405
-ret: 0 st: 0 flags:1 ts: 2.836000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:11391906 size:244616
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.760000 pts: 1.760000 pos:10170977 size:243403
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.600000 pts: 0.600000 pos:3319311 size:226082
-ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size:219405
-ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:11391906 size:244616
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:7515896 size:239079
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1098674 size:220236
-ret: 0 st: 0 flags:0 ts:-0.905000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size:219405
-ret: 0 st: 0 flags:1 ts: 1.989000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:11391906 size:244616
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.920000 pts: 0.920000 pos:5152576 size:233102
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.672000
-ret: 0 st: 0 flags:1 ts: 1.566000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:8958199 size:241837
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2645880 size:223865
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-flv b/tests/ref/seek/vsynth2-flv
deleted file mode 100644
index ba2efdd1c9..0000000000
--- a/tests/ref/seek/vsynth2-flv
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 12771
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 12771
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108745 size: 16158
-ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 67792 size: 14392
-ret:-1 st: 0 flags:1 ts:-0.317000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108745 size: 16158
-ret: 0 st: 0 flags:0 ts: 0.365000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 32529 size: 12708
-ret:-1 st: 0 flags:1 ts:-0.741000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 67792 size: 14392
-ret: 0 st: 0 flags:0 ts:-0.058000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 12771
-ret: 0 st: 0 flags:1 ts: 2.836000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 155318 size: 17185
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 155318 size: 17185
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 32529 size: 12708
-ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 12771
-ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 155318 size: 17185
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108745 size: 16158
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 12771
-ret: 0 st: 0 flags:0 ts:-0.905000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 179 size: 12771
-ret: 0 st: 0 flags:1 ts: 1.989000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 155318 size: 17185
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 67792 size: 14392
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.672000
-ret: 0 st: 0 flags:1 ts: 1.566000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108745 size: 16158
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 32529 size: 12708
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-h261 b/tests/ref/seek/vsynth2-h261
deleted file mode 100644
index 4aa0c43cc9..0000000000
--- a/tests/ref/seek/vsynth2-h261
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11732
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11732
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 168350 size: 14793
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 106950 size: 13195
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 168350 size: 14793
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 55568 size: 11639
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 106950 size: 13195
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11732
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 237672 size: 15734
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 237672 size: 15734
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 55568 size: 11639
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11732
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 237672 size: 15734
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 168350 size: 14793
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11732
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11732
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 237672 size: 15734
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 106950 size: 13195
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 168350 size: 14793
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 55568 size: 11639
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-h263 b/tests/ref/seek/vsynth2-h263
deleted file mode 100644
index 3e0c9245dd..0000000000
--- a/tests/ref/seek/vsynth2-h263
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12772
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12772
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 139428 size: 16159
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 88646 size: 14393
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 139428 size: 16159
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 45784 size: 12709
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 88646 size: 14393
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12772
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 195658 size: 17186
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 195658 size: 17186
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 45784 size: 12709
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12772
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 195658 size: 17186
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 139428 size: 16159
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12772
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 12772
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 195658 size: 17186
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 88646 size: 14393
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 139428 size: 16159
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 45784 size: 12709
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-h263p b/tests/ref/seek/vsynth2-h263p
deleted file mode 100644
index 673f412d49..0000000000
--- a/tests/ref/seek/vsynth2-h263p
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 43985
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 43985
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 733908 size: 56338
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 448856 size: 50481
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 733908 size: 56338
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 210394 size: 43217
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 448856 size: 50481
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 43985
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:1051592 size: 59232
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:1051592 size: 59232
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 210394 size: 43217
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 43985
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:1051592 size: 59232
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 733908 size: 56338
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 43985
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 43985
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:1051592 size: 59232
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 448856 size: 50481
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 733908 size: 56338
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 210394 size: 43217
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-huffyuv b/tests/ref/seek/vsynth2-huffyuv
deleted file mode 100644
index a3e176b9ca..0000000000
--- a/tests/ref/seek/vsynth2-huffyuv
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:120468
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:120468
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:6010684 size:136724
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2445132 size:126464
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:4658492 size:133884
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1085808 size:121284
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3211900 size:129428
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:120468
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:6284380 size:137136
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:5466432 size:135664
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1944388 size:124456
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:120468
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:6284380 size:137136
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:4126904 size:132312
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 604036 size:120044
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5724 size:120468
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:6284380 size:137136
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2698592 size:127564
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:4926660 size:134484
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1451012 size:122720
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-jpegls b/tests/ref/seek/vsynth2-jpegls
deleted file mode 100644
index 1b27a3654a..0000000000
--- a/tests/ref/seek/vsynth2-jpegls
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:154766
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:154766
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:7767024 size:181048
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3057326 size:163405
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:5971676 size:177984
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1334822 size:150568
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:4056260 size:170347
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:154766
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:8129364 size:181472
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:7045426 size:180307
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2414840 size:159022
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:154766
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:8129364 size:181472
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:5265990 size:175400
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 742066 size:147109
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:154766
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:8129364 size:181472
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3385508 size:165810
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:6328220 size:178473
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1789916 size:154383
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-ljpeg b/tests/ref/seek/vsynth2-ljpeg
deleted file mode 100644
index 47f64c6dda..0000000000
--- a/tests/ref/seek/vsynth2-ljpeg
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 86580
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 86580
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:4406068 size:102731
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:1761620 size: 92236
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:3394414 size: 99800
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 778564 size: 87118
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:2323284 size: 95279
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 86580
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4611786 size:103108
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:3997920 size:101607
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1397770 size: 90251
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 86580
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4611786 size:103108
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:2999316 size: 98183
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 433426 size: 85897
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 86580
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4611786 size:103108
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:1946636 size: 93348
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:3594390 size:100410
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1041206 size: 88501
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mjpeg b/tests/ref/seek/vsynth2-mjpeg
deleted file mode 100644
index 6072ddfb97..0000000000
--- a/tests/ref/seek/vsynth2-mjpeg
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14531
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14531
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 771990 size: 19172
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 294112 size: 15816
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 584836 size: 18250
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 130062 size: 14140
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 391598 size: 16843
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14531
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 810344 size: 19135
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 696224 size: 18821
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 232462 size: 15159
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14531
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 810344 size: 19135
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 512664 size: 17924
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 74366 size: 13812
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14531
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 810344 size: 19135
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 325950 size: 16219
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 621546 size: 18498
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 173092 size: 14609
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg1 b/tests/ref/seek/vsynth2-mpeg1
deleted file mode 100644
index 52eef058ae..0000000000
--- a/tests/ref/seek/vsynth2-mpeg1
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 11963
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11963
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 168537 size: 15165
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 103348 size: 13767
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 168537 size: 15165
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 48976 size: 12270
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 103348 size: 13767
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11963
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 240894 size: 16003
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 240894 size: 16003
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 48976 size: 12270
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11963
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 240894 size: 16003
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 168537 size: 15165
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11963
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11963
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 240894 size: 16003
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 103348 size: 13767
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 168537 size: 15165
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 48976 size: 12270
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg1b b/tests/ref/seek/vsynth2-mpeg1b
deleted file mode 100644
index 6e3af809f3..0000000000
--- a/tests/ref/seek/vsynth2-mpeg1b
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 14617
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 14617
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 255467 size: 19667
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 101700 size: 16809
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 172617 size: 18608
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: NOPTS pos: 43550 size: 14859
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 101700 size: 16809
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 14617
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 255467 size: 19667
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 255467 size: 19667
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: NOPTS pos: 43550 size: 14859
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 14617
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 255467 size: 19667
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 172617 size: 18608
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 14617
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 14617
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 255467 size: 19667
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 172617 size: 18608
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 172617 size: 18608
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 101700 size: 16809
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-422 b/tests/ref/seek/vsynth2-mpeg2-422
deleted file mode 100644
index d2a79baa06..0000000000
--- a/tests/ref/seek/vsynth2-mpeg2-422
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 19047
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 19047
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 349153 size: 20638
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 231235 size: 21776
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 291308 size: 22619
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 128388 size: 34098
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 231235 size: 21776
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 19047
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 349153 size: 20638
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 349153 size: 20638
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 128388 size: 34098
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 19047
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 349153 size: 20638
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 291308 size: 22619
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 19047
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 19047
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 349153 size: 20638
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 231235 size: 21776
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 291308 size: 22619
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 231235 size: 21776
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-idct-int b/tests/ref/seek/vsynth2-mpeg2-idct-int
deleted file mode 100644
index 0b369e2498..0000000000
--- a/tests/ref/seek/vsynth2-mpeg2-idct-int
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12092
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12092
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 172048 size: 15287
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 105687 size: 13892
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 172048 size: 15287
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 50238 size: 12392
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 105687 size: 13892
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12092
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 245946 size: 16133
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 245946 size: 16133
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 50238 size: 12392
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12092
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 245946 size: 16133
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 172048 size: 15287
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12092
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12092
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 245946 size: 16133
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 105687 size: 13892
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 172048 size: 15287
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 50238 size: 12392
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-ilace b/tests/ref/seek/vsynth2-mpeg2-ilace
deleted file mode 100644
index 590d10d3a9..0000000000
--- a/tests/ref/seek/vsynth2-mpeg2-ilace
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 177672 size: 15343
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 109003 size: 13947
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 177672 size: 15343
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 51717 size: 12445
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 109003 size: 13947
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 253343 size: 16183
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 253343 size: 16183
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 51717 size: 12445
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 253343 size: 16183
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 177672 size: 15343
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 253343 size: 16183
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 109003 size: 13947
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 177672 size: 15343
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 51717 size: 12445
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd b/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
deleted file mode 100644
index 9b6174f2db..0000000000
--- a/tests/ref/seek/vsynth2-mpeg2-ivlc-qprd
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17896
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17896
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 253840 size: 12176
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 192257 size: 13312
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 223884 size: 13628
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 119729 size: 33112
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 192257 size: 13312
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17896
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 253840 size: 12176
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 253840 size: 12176
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 119729 size: 33112
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17896
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 253840 size: 12176
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 223884 size: 13628
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17896
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17896
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 253840 size: 12176
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 192257 size: 13312
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 223884 size: 13628
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 192257 size: 13312
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-thread b/tests/ref/seek/vsynth2-mpeg2-thread
deleted file mode 100644
index 644513bf8c..0000000000
--- a/tests/ref/seek/vsynth2-mpeg2-thread
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 201811 size: 16183
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 83616 size: 13947
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 138764 size: 15343
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 37634 size: 12445
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 83616 size: 13947
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 201811 size: 16183
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 201811 size: 16183
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 37634 size: 12445
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 201811 size: 16183
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 138764 size: 15343
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 12146
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 201811 size: 16183
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 83616 size: 13947
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 138764 size: 15343
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 83616 size: 13947
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg2-thread-ivlc b/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
deleted file mode 100644
index a799f0a782..0000000000
--- a/tests/ref/seek/vsynth2-mpeg2-thread-ivlc
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11855
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11855
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 199749 size: 15473
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 82883 size: 13398
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 137402 size: 14693
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 37332 size: 12068
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 82883 size: 13398
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11855
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 199749 size: 15473
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 199749 size: 15473
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 37332 size: 12068
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11855
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 199749 size: 15473
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 137402 size: 14693
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11855
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11855
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 199749 size: 15473
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 82883 size: 13398
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 137402 size: 14693
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 82883 size: 13398
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4 b/tests/ref/seek/vsynth2-mpeg4
deleted file mode 100644
index 36ba46c06c..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4
+++ /dev/null
@@ -1,50 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98347 size: 14396
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 60954 size: 12631
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98347 size: 14396
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29166 size: 10862
-ret: 0 st: 0 flags:1 ts:-0.760000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 60954 size: 12631
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 141019 size: 15358
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 141019 size: 15358
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29166 size: 10862
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 141019 size: 15358
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98347 size: 14396
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 141019 size: 15358
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 60954 size: 12631
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98347 size: 14396
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29166 size: 10862
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 10965
diff --git a/tests/ref/seek/vsynth2-mpeg4-adap b/tests/ref/seek/vsynth2-mpeg4-adap
deleted file mode 100644
index 152d020ff3..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-adap
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6951
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6951
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 189122 size: 18125
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 114966 size: 16429
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 151228 size: 18225
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 73890 size: 20238
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 114966 size: 16429
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6951
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 189122 size: 18125
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 189122 size: 18125
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 73890 size: 20238
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6951
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 189122 size: 18125
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 151228 size: 18225
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6951
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 6951
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 189122 size: 18125
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 114966 size: 16429
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 151228 size: 18225
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 114966 size: 16429
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-adv b/tests/ref/seek/vsynth2-mpeg4-adv
deleted file mode 100644
index 06d88ae796..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-adv
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10951
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10951
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 118586 size: 14495
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 75418 size: 12802
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 118586 size: 14495
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38714 size: 11015
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 75418 size: 12802
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10951
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 168206 size: 15537
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 168206 size: 15537
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38714 size: 11015
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10951
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 168206 size: 15537
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 118586 size: 14495
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10951
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10951
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 168206 size: 15537
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 75418 size: 12802
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 118586 size: 14495
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38714 size: 11015
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-error b/tests/ref/seek/vsynth2-mpeg4-error
deleted file mode 100644
index 45550476b1..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-error
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14897
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14897
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 158910 size: 19939
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 100670 size: 17313
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 158910 size: 19939
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 50630 size: 14739
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 100670 size: 17313
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14897
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 226622 size: 19001
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 226622 size: 19001
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 50630 size: 14739
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14897
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 226622 size: 19001
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 158910 size: 19939
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14897
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 14897
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 226622 size: 19001
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 100670 size: 17313
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 158910 size: 19939
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 50630 size: 14739
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-nr b/tests/ref/seek/vsynth2-mpeg4-nr
deleted file mode 100644
index e0abfe8544..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-nr
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 13402
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 13402
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 130650 size: 16609
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83222 size: 14678
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 130650 size: 16609
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42834 size: 12656
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83222 size: 14678
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 13402
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 184792 size: 17684
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 184792 size: 17684
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42834 size: 12656
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 13402
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 184792 size: 17684
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 130650 size: 16609
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 13402
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 13402
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 184792 size: 17684
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83222 size: 14678
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 130650 size: 16609
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42834 size: 12656
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-qpel b/tests/ref/seek/vsynth2-mpeg4-qpel
deleted file mode 100644
index 6f23d126ab..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-qpel
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15135
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15135
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 180366 size: 21181
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 79512 size: 17332
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 126396 size: 19941
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 39736 size: 14805
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 79512 size: 17332
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15135
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 180366 size: 21181
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 180366 size: 21181
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 39736 size: 14805
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15135
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 180366 size: 21181
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 126396 size: 19941
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15135
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 15135
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 180366 size: 21181
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 79512 size: 17332
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 126396 size: 19941
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 79512 size: 17332
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-qprd b/tests/ref/seek/vsynth2-mpeg4-qprd
deleted file mode 100644
index 675e993a9b..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-qprd
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 16904
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 16904
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228068 size: 15339
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 169864 size: 14172
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 198340 size: 15560
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 111330 size: 29024
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 169864 size: 14172
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 16904
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228068 size: 15339
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228068 size: 15339
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 111330 size: 29024
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 16904
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228068 size: 15339
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 198340 size: 15560
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 16904
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 16904
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228068 size: 15339
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 169864 size: 14172
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 198340 size: 15560
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 169864 size: 14172
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-rc b/tests/ref/seek/vsynth2-mpeg4-rc
deleted file mode 100644
index 21aca4c8ae..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-rc
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 20139
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 20139
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 236670 size: 14086
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 185808 size: 12662
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 210456 size: 14427
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 114894 size: 39545
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 185808 size: 12662
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 20139
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 236670 size: 14086
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 236670 size: 14086
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 114894 size: 39545
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 20139
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 236670 size: 14086
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 210456 size: 14427
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 20139
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 20139
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 236670 size: 14086
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 185808 size: 12662
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 210456 size: 14427
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 185808 size: 12662
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-mpeg4-thread b/tests/ref/seek/vsynth2-mpeg4-thread
deleted file mode 100644
index 2b0f0d310c..0000000000
--- a/tests/ref/seek/vsynth2-mpeg4-thread
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 18099
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 18099
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 247612 size: 15696
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 186128 size: 14685
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 215778 size: 16807
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 117134 size: 37486
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 186128 size: 14685
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 18099
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 247612 size: 15696
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 247612 size: 15696
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 117134 size: 37486
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 18099
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 247612 size: 15696
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 215778 size: 16807
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 18099
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5648 size: 18099
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 247612 size: 15696
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 186128 size: 14685
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 215778 size: 16807
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 186128 size: 14685
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-msmpeg4 b/tests/ref/seek/vsynth2-msmpeg4
deleted file mode 100644
index c2a708166a..0000000000
--- a/tests/ref/seek/vsynth2-msmpeg4
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10925
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10925
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 107648 size: 14494
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 68772 size: 12670
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 107648 size: 14494
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35828 size: 10859
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 68772 size: 12670
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10925
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 152100 size: 15457
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 152100 size: 15457
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35828 size: 10859
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10925
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 152100 size: 15457
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 107648 size: 14494
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10925
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 10925
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 152100 size: 15457
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 68772 size: 12670
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 107648 size: 14494
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35828 size: 10859
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-msmpeg4v2 b/tests/ref/seek/vsynth2-msmpeg4v2
deleted file mode 100644
index bf992fdc3a..0000000000
--- a/tests/ref/seek/vsynth2-msmpeg4v2
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11321
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11321
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108682 size: 14845
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69622 size: 13068
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108682 size: 14845
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36266 size: 11274
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69622 size: 13068
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11321
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153222 size: 15792
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153222 size: 15792
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36266 size: 11274
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11321
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153222 size: 15792
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108682 size: 14845
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11321
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11321
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153222 size: 15792
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69622 size: 13068
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108682 size: 14845
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36266 size: 11274
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-rgb b/tests/ref/seek/vsynth2-rgb
deleted file mode 100644
index 91f7260bfb..0000000000
--- a/tests/ref/seek/vsynth2-rgb
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:304128
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:304128
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:14300040 size:304128
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:6088368 size:304128
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:11258680 size:304128
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:2742872 size:304128
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:7913184 size:304128
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:304128
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14908312 size:304128
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:13083496 size:304128
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:4871824 size:304128
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:304128
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14908312 size:304128
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:10042136 size:304128
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1526328 size:304128
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:304128
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14908312 size:304128
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:6696640 size:304128
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:11866952 size:304128
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:3655280 size:304128
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-roqvideo b/tests/ref/seek/vsynth2-roqvideo
deleted file mode 100644
index 6ed78b54ed..0000000000
--- a/tests/ref/seek/vsynth2-roqvideo
+++ /dev/null
@@ -1,27 +0,0 @@
-ret: 0 st: 0 flags:0 dts: 0.000000 pts: 0.000000 pos: 24 size: 25810
-ret:-1 st:-1 flags:0 ts:-1.000000
-ret:-1 st:-1 flags:1 ts: 1.894167
-ret:-1 st: 0 flags:0 ts: 0.800000
-ret:-1 st: 0 flags:1 ts:-0.333333
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret:-1 st:-1 flags:1 ts: 1.470835
-ret:-1 st: 0 flags:0 ts: 0.366667
-ret:-1 st: 0 flags:1 ts:-0.733333
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret:-1 st:-1 flags:1 ts: 1.047503
-ret:-1 st: 0 flags:0 ts:-0.066667
-ret:-1 st: 0 flags:1 ts: 2.833333
-ret:-1 st:-1 flags:0 ts: 1.730004
-ret:-1 st:-1 flags:1 ts: 0.624171
-ret:-1 st: 0 flags:0 ts:-0.466667
-ret:-1 st: 0 flags:1 ts: 2.400000
-ret:-1 st:-1 flags:0 ts: 1.306672
-ret:-1 st:-1 flags:1 ts: 0.200839
-ret:-1 st: 0 flags:0 ts:-0.900000
-ret:-1 st: 0 flags:1 ts: 2.000000
-ret:-1 st:-1 flags:0 ts: 0.883340
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.666667
-ret:-1 st: 0 flags:1 ts: 1.566667
-ret:-1 st:-1 flags:0 ts: 0.460008
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-rv10 b/tests/ref/seek/vsynth2-rv10
deleted file mode 100644
index e31a7f9f10..0000000000
--- a/tests/ref/seek/vsynth2-rv10
+++ /dev/null
@@ -1,52 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret:-1 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83441 size: 14400
-ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134324 size: 16167
-ret: 0 st: 0 flags:0 ts: 0.365000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 40479 size: 12716
-ret: 0 st: 0 flags:1 ts:-0.741000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83441 size: 14400
-ret: 0 st: 0 flags:0 ts:-0.058000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st: 0 flags:1 ts: 2.836000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 40479 size: 12716
-ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134324 size: 16167
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st: 0 flags:0 ts:-0.905000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st: 0 flags:1 ts: 1.989000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83441 size: 14400
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
-ret: 0 st: 0 flags:0 ts: 2.672000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 190667 size: 17194
-ret: 0 st: 0 flags:1 ts: 1.566000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134324 size: 16167
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 40479 size: 12716
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 12779
diff --git a/tests/ref/seek/vsynth2-rv20 b/tests/ref/seek/vsynth2-rv20
deleted file mode 100644
index 0a69c7165e..0000000000
--- a/tests/ref/seek/vsynth2-rv20
+++ /dev/null
@@ -1,53 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134767 size: 14896
-ret: 0 st: 0 flags:0 ts: 0.788000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83421 size: 13120
-ret: 0 st: 0 flags:1 ts:-0.317000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st:-1 flags:0 ts: 2.576668
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134767 size: 14896
-ret: 0 st: 0 flags:0 ts: 0.365000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 40479 size: 11414
-ret: 0 st: 0 flags:1 ts:-0.741000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st:-1 flags:0 ts: 2.153336
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83421 size: 13120
-ret: 0 st: 0 flags:0 ts:-0.058000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st: 0 flags:1 ts: 2.836000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 40479 size: 11414
-ret: 0 st: 0 flags:0 ts:-0.482000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st: 0 flags:1 ts: 2.413000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134767 size: 14896
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st: 0 flags:0 ts:-0.905000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st: 0 flags:1 ts: 1.989000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 83421 size: 13120
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
-ret: 0 st: 0 flags:0 ts: 2.672000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 191423 size: 15859
-ret: 0 st: 0 flags:1 ts: 1.566000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 134767 size: 14896
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 40479 size: 11414
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 11720
diff --git a/tests/ref/seek/vsynth2-svq1 b/tests/ref/seek/vsynth2-svq1
deleted file mode 100644
index 5b90ec8049..0000000000
--- a/tests/ref/seek/vsynth2-svq1
+++ /dev/null
@@ -1,50 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 630104 size: 31344
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 392428 size: 28568
-ret: 0 st: 0 flags:1 ts:-0.320000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 630104 size: 31344
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 185116 size: 25544
-ret: 0 st: 0 flags:1 ts:-0.760000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 392428 size: 28568
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 886184 size: 32128
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 886184 size: 32128
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 185116 size: 25544
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 886184 size: 32128
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 630104 size: 31344
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 886184 size: 32128
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 392428 size: 28568
-ret: 0 st:-1 flags:1 ts:-0.222493
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 630104 size: 31344
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 185116 size: 25544
-ret: 0 st:-1 flags:1 ts:-0.645825
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 25188
diff --git a/tests/ref/seek/vsynth2-wmv1 b/tests/ref/seek/vsynth2-wmv1
deleted file mode 100644
index 47b79b80ee..0000000000
--- a/tests/ref/seek/vsynth2-wmv1
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11126
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11126
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108444 size: 14988
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69132 size: 13137
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108444 size: 14988
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35874 size: 11167
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69132 size: 13137
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11126
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153546 size: 15956
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153546 size: 15956
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35874 size: 11167
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11126
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153546 size: 15956
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108444 size: 14988
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11126
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size: 11126
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 153546 size: 15956
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69132 size: 13137
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 108444 size: 14988
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35874 size: 11167
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-wmv2 b/tests/ref/seek/vsynth2-wmv2
deleted file mode 100644
index 3ba67649e1..0000000000
--- a/tests/ref/seek/vsynth2-wmv2
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11264
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11264
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 109154 size: 15153
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69348 size: 13297
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 109154 size: 15153
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35954 size: 11342
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69348 size: 13297
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11264
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 154736 size: 16130
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 154736 size: 16130
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35954 size: 11342
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11264
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 154736 size: 16130
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 109154 size: 15153
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11264
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11264
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 154736 size: 16130
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 69348 size: 13297
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 109154 size: 15153
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35954 size: 11342
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth2-yuv b/tests/ref/seek/vsynth2-yuv
deleted file mode 100644
index d440761cf7..0000000000
--- a/tests/ref/seek/vsynth2-yuv
+++ /dev/null
@@ -1,46 +0,0 @@
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:152064
-ret: 0 st:-1 flags:0 ts:-1.000000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:152064
-ret: 0 st:-1 flags:1 ts: 1.894167
-ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:7153032 size:152064
-ret: 0 st: 0 flags:0 ts: 0.800000
-ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3047088 size:152064
-ret:-1 st: 0 flags:1 ts:-0.320000
-ret:-1 st:-1 flags:0 ts: 2.576668
-ret: 0 st:-1 flags:1 ts: 1.470835
-ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:5632312 size:152064
-ret: 0 st: 0 flags:0 ts: 0.360000
-ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1374296 size:152064
-ret:-1 st: 0 flags:1 ts:-0.760000
-ret:-1 st:-1 flags:0 ts: 2.153336
-ret: 0 st:-1 flags:1 ts: 1.047503
-ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3959520 size:152064
-ret: 0 st: 0 flags:0 ts:-0.040000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:152064
-ret: 0 st: 0 flags:1 ts: 2.840000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7457176 size:152064
-ret: 0 st:-1 flags:0 ts: 1.730004
-ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:6544744 size:152064
-ret: 0 st:-1 flags:1 ts: 0.624171
-ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2438800 size:152064
-ret: 0 st: 0 flags:0 ts:-0.480000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:152064
-ret: 0 st: 0 flags:1 ts: 2.400000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7457176 size:152064
-ret: 0 st:-1 flags:0 ts: 1.306672
-ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:5024024 size:152064
-ret: 0 st:-1 flags:1 ts: 0.200839
-ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 766008 size:152064
-ret: 0 st: 0 flags:0 ts:-0.920000
-ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5648 size:152064
-ret: 0 st: 0 flags:1 ts: 2.000000
-ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7457176 size:152064
-ret: 0 st:-1 flags:0 ts: 0.883340
-ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3351232 size:152064
-ret:-1 st:-1 flags:1 ts:-0.222493
-ret:-1 st: 0 flags:0 ts: 2.680000
-ret: 0 st: 0 flags:1 ts: 1.560000
-ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:5936456 size:152064
-ret: 0 st:-1 flags:0 ts: 0.460008
-ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1830512 size:152064
-ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-asv1 b/tests/ref/seek/vsynth_lena-asv1
new file mode 100644
index 0000000000..0957d84000
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-asv1
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12152
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12152
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 643348 size: 15064
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 255236 size: 13312
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 493588 size: 14796
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 114856 size: 12356
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 336184 size: 13824
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12152
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 673508 size: 15104
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 583316 size: 14956
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 202876 size: 12944
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12152
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 673508 size: 15104
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 435132 size: 14488
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 65868 size: 12144
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12152
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 673508 size: 15104
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 281888 size: 13412
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 523328 size: 14972
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 152060 size: 12540
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-asv2 b/tests/ref/seek/vsynth_lena-asv2
new file mode 100644
index 0000000000..1a3c93f5d3
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-asv2
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12072
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12072
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 630032 size: 14892
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 248840 size: 13024
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 482704 size: 14532
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 111604 size: 12016
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 328256 size: 13532
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12072
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 659852 size: 14928
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 570788 size: 14712
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 197540 size: 12724
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12072
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 659852 size: 14928
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 425320 size: 14116
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 64108 size: 11780
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5660 size: 12072
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 659852 size: 14928
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 274968 size: 13176
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 511948 size: 14668
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 147824 size: 12240
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-dnxhd-1080i b/tests/ref/seek/vsynth_lena-dnxhd-1080i
new file mode 100644
index 0000000000..a5f0ce916c
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-dnxhd-1080i
@@ -0,0 +1,44 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret:-1 st: 0 flags:0 ts: 0.788359
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret:-1 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 ts:-0.740859
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret: 0 st: 0 flags:0 ts:-0.058359
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret: 0 st: 0 flags:1 ts: 2.835859
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret: 0 st: 0 flags:0 ts:-0.481641
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret: 0 st: 0 flags:1 ts: 1.989141
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
+ret:-1 st: 0 flags:0 ts: 2.671641
+ret: 0 st: 0 flags:1 ts: 1.565859
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:2424868 size:606208
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size:606208
diff --git a/tests/ref/seek/vsynth_lena-dnxhd-720p b/tests/ref/seek/vsynth_lena-dnxhd-720p
new file mode 100644
index 0000000000..b57f07dd71
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-dnxhd-720p
@@ -0,0 +1,40 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st: 0 flags:0 ts: 0.788334
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st: 0 flags:0 ts: 0.365002
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-dnxhd-720p-rd b/tests/ref/seek/vsynth_lena-dnxhd-720p-rd
new file mode 100644
index 0000000000..b57f07dd71
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-dnxhd-720p-rd
@@ -0,0 +1,40 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st: 0 flags:0 ts: 0.788334
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st: 0 flags:0 ts: 0.365002
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:458752
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos:1835008 size:458752
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-dv b/tests/ref/seek/vsynth_lena-dv
new file mode 100644
index 0000000000..d318794157
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-dv
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:6768000 size:144000
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2880000 size:144000
+ret: 0 st: 0 flags:1 ts:-0.320000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:5328000 size:144000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1296000 size:144000
+ret: 0 st: 0 flags:1 ts:-0.760000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3744000 size:144000
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:6192000 size:144000
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2304000 size:144000
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:4752000 size:144000
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 720000 size:144000
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3168000 size:144000
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:5616000 size:144000
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1728000 size:144000
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
diff --git a/tests/ref/seek/vsynth_lena-dv-411 b/tests/ref/seek/vsynth_lena-dv-411
new file mode 100644
index 0000000000..d318794157
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-dv-411
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:6768000 size:144000
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2880000 size:144000
+ret: 0 st: 0 flags:1 ts:-0.320000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:5328000 size:144000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1296000 size:144000
+ret: 0 st: 0 flags:1 ts:-0.760000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3744000 size:144000
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:6192000 size:144000
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2304000 size:144000
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:4752000 size:144000
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 720000 size:144000
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3168000 size:144000
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
+ret: 0 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7056000 size:144000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:5616000 size:144000
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1728000 size:144000
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000
diff --git a/tests/ref/seek/vsynth_lena-dv-50 b/tests/ref/seek/vsynth_lena-dv-50
new file mode 100644
index 0000000000..fae6d1b225
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-dv-50
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:13536000 size:288000
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:5760000 size:288000
+ret: 0 st: 0 flags:1 ts:-0.320000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14112000 size:288000
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:10656000 size:288000
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:2592000 size:288000
+ret: 0 st: 0 flags:1 ts:-0.760000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14112000 size:288000
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:7488000 size:288000
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14112000 size:288000
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:12384000 size:288000
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:4608000 size:288000
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14112000 size:288000
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:9504000 size:288000
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1440000 size:288000
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14112000 size:288000
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:6336000 size:288000
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
+ret: 0 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14112000 size:288000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:11232000 size:288000
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:3456000 size:288000
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:288000
diff --git a/tests/ref/seek/vsynth_lena-ffv1 b/tests/ref/seek/vsynth_lena-ffv1
new file mode 100644
index 0000000000..57583686d4
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-ffv1
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5694 size: 71707
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5694 size: 71707
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499442 size: 75965
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1631574 size: 72710
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499442 size: 75965
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801638 size: 69485
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1631574 size: 72710
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5694 size: 71707
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393894 size: 77489
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393894 size: 77489
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801638 size: 69485
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5694 size: 71707
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393894 size: 77489
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499442 size: 75965
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5694 size: 71707
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5694 size: 71707
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:3393894 size: 77489
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1631574 size: 72710
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:2499442 size: 75965
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 801638 size: 69485
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-flashsv b/tests/ref/seek/vsynth_lena-flashsv
new file mode 100644
index 0000000000..8bfb2fc6df
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-flashsv
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size:240757
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size:240757
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:11605762 size:254053
+ret: 0 st: 0 flags:0 ts: 0.788000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4820517 size:245503
+ret:-1 st: 0 flags:1 ts:-0.317000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:8811911 size:253041
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: 0.400000 pos:2387452 size:241101
+ret:-1 st: 0 flags:1 ts:-0.741000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:6302834 size:248927
+ret: 0 st: 0 flags:0 ts:-0.058000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size:240757
+ret: 0 st: 0 flags:1 ts: 2.836000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:12114712 size:254237
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.760000 pts: 1.760000 pos:10843576 size:253913
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.600000 pts: 0.600000 pos:3598805 size:243372
+ret: 0 st: 0 flags:0 ts:-0.482000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size:240757
+ret: 0 st: 0 flags:1 ts: 2.413000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:12114712 size:254237
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:8053716 size:252195
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1187821 size:238567
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size:240757
+ret: 0 st: 0 flags:1 ts: 1.989000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:12114712 size:254237
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.920000 pts: 0.920000 pos:5559238 size:247341
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.672000
+ret: 0 st: 0 flags:1 ts: 1.566000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:9572247 size:254219
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2870253 size:242377
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-flv b/tests/ref/seek/vsynth_lena-flv
new file mode 100644
index 0000000000..d4aecda5bc
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-flv
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83240 size: 12295
+ret: 0 st: 0 flags:0 ts: 0.788000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 52585 size: 11127
+ret:-1 st: 0 flags:1 ts:-0.317000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83240 size: 12295
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 25960 size: 10089
+ret:-1 st: 0 flags:1 ts:-0.741000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 52585 size: 11127
+ret: 0 st: 0 flags:0 ts:-0.058000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
+ret: 0 st: 0 flags:1 ts: 2.836000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117177 size: 12730
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117177 size: 12730
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 25960 size: 10089
+ret: 0 st: 0 flags:0 ts:-0.482000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
+ret: 0 st: 0 flags:1 ts: 2.413000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117177 size: 12730
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83240 size: 12295
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 199 size: 10380
+ret: 0 st: 0 flags:1 ts: 1.989000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 117177 size: 12730
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 52585 size: 11127
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.672000
+ret: 0 st: 0 flags:1 ts: 1.566000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83240 size: 12295
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 25960 size: 10089
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-h261 b/tests/ref/seek/vsynth_lena-h261
new file mode 100644
index 0000000000..dabf6a3014
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-h261
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9645
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9645
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126498 size: 11377
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82056 size: 10322
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126498 size: 11377
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44668 size: 9404
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82056 size: 10322
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9645
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175860 size: 11707
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175860 size: 11707
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44668 size: 9404
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9645
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175860 size: 11707
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126498 size: 11377
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9645
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9645
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 175860 size: 11707
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 82056 size: 10322
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 126498 size: 11377
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 44668 size: 9404
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-h263 b/tests/ref/seek/vsynth_lena-h263
new file mode 100644
index 0000000000..5e50ca3b2a
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-h263
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10381
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10381
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 103706 size: 12296
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 66796 size: 11128
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 103706 size: 12296
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36442 size: 10090
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 66796 size: 11128
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10381
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144556 size: 12731
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144556 size: 12731
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36442 size: 10090
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10381
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144556 size: 12731
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 103706 size: 12296
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10381
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10381
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 144556 size: 12731
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 66796 size: 11128
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 103706 size: 12296
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 36442 size: 10090
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-h263p b/tests/ref/seek/vsynth_lena-h263p
new file mode 100644
index 0000000000..c87a90672d
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-h263p
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 36208
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 36208
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569922 size: 45151
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355972 size: 40907
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569922 size: 45151
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171046 size: 36514
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355972 size: 40907
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 36208
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804362 size: 46411
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804362 size: 46411
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171046 size: 36514
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 36208
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804362 size: 46411
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569922 size: 45151
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 36208
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 36208
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 804362 size: 46411
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 355972 size: 40907
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 569922 size: 45151
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 171046 size: 36514
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-huffyuv b/tests/ref/seek/vsynth_lena-huffyuv
new file mode 100644
index 0000000000..79e29a0eea
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-huffyuv
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5758 size:123508
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5758 size:123508
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:5745002 size:121152
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2437998 size:122516
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:4523458 size:122784
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1093874 size:121320
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3173594 size:122784
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5758 size:123508
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:5987034 size:120672
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:5258654 size:121992
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1947354 size:122568
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5758 size:123508
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:5987034 size:120672
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:4032698 size:122544
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 609910 size:120724
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5758 size:123508
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:5987034 size:120672
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2683066 size:122588
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:4768982 size:122556
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1458410 size:121888
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-jpegls b/tests/ref/seek/vsynth_lena-jpegls
new file mode 100644
index 0000000000..c773313ad5
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-jpegls
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:164074
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:164074
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:7804122 size:176295
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3172784 size:164643
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:6052978 size:174097
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1402348 size:157283
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:4170252 size:168401
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:164074
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:8157020 size:176793
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:7101758 size:175326
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2519264 size:162522
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:164074
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:8157020 size:176793
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:5360822 size:172183
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 779838 size:154579
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:164074
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:8157020 size:176793
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3502832 size:166017
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:6401456 size:174815
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1876420 size:159659
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-ljpeg b/tests/ref/seek/vsynth_lena-ljpeg
new file mode 100644
index 0000000000..bb58fd91fc
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-ljpeg
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 96000
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 96000
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:4478628 size: 94801
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:1900944 size: 95396
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:3525176 size: 95655
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 854326 size: 94566
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:2473780 size: 95580
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 96000
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4668124 size: 94526
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:4098378 size: 95284
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:1519186 size: 95341
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 96000
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4668124 size: 94526
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:3142842 size: 95518
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 476884 size: 94192
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 96000
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:4668124 size: 94526
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:2091790 size: 95459
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:3716442 size: 95546
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1138412 size: 94963
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mjpeg b/tests/ref/seek/vsynth_lena-mjpeg
new file mode 100644
index 0000000000..08cbd88eb9
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mjpeg
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 12096
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 12096
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos: 627818 size: 14806
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos: 247502 size: 12959
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos: 480740 size: 14519
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos: 111000 size: 11924
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos: 326684 size: 13491
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 12096
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657472 size: 14897
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos: 568610 size: 14751
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos: 196424 size: 12720
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 12096
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657472 size: 14897
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos: 423474 size: 14114
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 63866 size: 11715
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 12096
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos: 657472 size: 14897
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos: 273516 size: 13122
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos: 509896 size: 14594
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 146954 size: 12173
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg1 b/tests/ref/seek/vsynth_lena-mpeg1
new file mode 100644
index 0000000000..0ec751a8b4
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg1
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 9779
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9779
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 124255 size: 11796
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 76706 size: 10792
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 124255 size: 11796
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 37721 size: 9873
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 76706 size: 10792
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9779
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177099 size: 12057
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177099 size: 12057
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 37721 size: 9873
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9779
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177099 size: 12057
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 124255 size: 11796
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9779
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9779
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 177099 size: 12057
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 76706 size: 10792
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 124255 size: 11796
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 37721 size: 9873
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg1b b/tests/ref/seek/vsynth_lena-mpeg1b
new file mode 100644
index 0000000000..e079e343f8
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg1b
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 11817
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11817
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194424 size: 14837
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 80757 size: 13267
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 133899 size: 14470
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 80757 size: 13267
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 80757 size: 13267
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11817
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194424 size: 14837
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194424 size: 14837
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: NOPTS pos: 34797 size: 12009
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11817
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194424 size: 14837
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 133899 size: 14470
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11817
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 11817
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.800000 pts: NOPTS pos: 194424 size: 14837
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 133899 size: 14470
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: NOPTS pos: 133899 size: 14470
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.840000 pts: NOPTS pos: 80757 size: 13267
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg2-422 b/tests/ref/seek/vsynth_lena-mpeg2-422
new file mode 100644
index 0000000000..06d8f7ac3a
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg2-422
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325397 size: 19967
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 200747 size: 22575
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 265466 size: 21329
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 104454 size: 28984
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 200747 size: 22575
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325397 size: 19967
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325397 size: 19967
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 104454 size: 28984
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325397 size: 19967
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 265466 size: 21329
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 17497
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 325397 size: 19967
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 265466 size: 21329
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 265466 size: 21329
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 200747 size: 22575
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg2-idct-int b/tests/ref/seek/vsynth_lena-mpeg2-idct-int
new file mode 100644
index 0000000000..b096f6fe7c
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg2-idct-int
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127925 size: 11918
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 79103 size: 10909
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127925 size: 11918
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 38992 size: 9985
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 79103 size: 10909
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 38992 size: 9985
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127925 size: 11918
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9911
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 182138 size: 12183
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 79103 size: 10909
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 127925 size: 11918
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 38992 size: 9985
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg2-ilace b/tests/ref/seek/vsynth_lena-mpeg2-ilace
new file mode 100644
index 0000000000..d2a7838484
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg2-ilace
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132603 size: 11970
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 82152 size: 10965
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132603 size: 11970
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 40546 size: 10045
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 82152 size: 10965
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188425 size: 12232
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188425 size: 12232
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 40546 size: 10045
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188425 size: 12232
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132603 size: 11970
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: NOPTS pos: 188425 size: 12232
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: NOPTS pos: 82152 size: 10965
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: NOPTS pos: 132603 size: 11970
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: NOPTS pos: 40546 size: 10045
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg2-ivlc-qprd b/tests/ref/seek/vsynth_lena-mpeg2-ivlc-qprd
new file mode 100644
index 0000000000..330dc16a47
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg2-ivlc-qprd
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 164167 size: 13921
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196681 size: 13159
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 98748 size: 29165
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 164167 size: 13921
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 98748 size: 29165
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196681 size: 13159
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 16239
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 227500 size: 12725
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196681 size: 13159
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 196681 size: 13159
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 164167 size: 13921
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg2-thread b/tests/ref/seek/vsynth_lena-mpeg2-thread
new file mode 100644
index 0000000000..8e16f43a9a
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg2-thread
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158232 size: 12232
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67783 size: 10965
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110336 size: 11970
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30747 size: 10045
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67783 size: 10965
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158232 size: 12232
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158232 size: 12232
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30747 size: 10045
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158232 size: 12232
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110336 size: 11970
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9961
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 158232 size: 12232
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110336 size: 11970
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110336 size: 11970
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67783 size: 10965
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg2-thread-ivlc b/tests/ref/seek/vsynth_lena-mpeg2-thread-ivlc
new file mode 100644
index 0000000000..49ec819f76
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg2-thread-ivlc
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157685 size: 11930
+ret: 0 st: 0 flags:0 ts: 0.788334
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67716 size: 10791
+ret:-1 st: 0 flags:1 ts:-0.317499
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110086 size: 11697
+ret: 0 st: 0 flags:0 ts: 0.365002
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30744 size: 9980
+ret:-1 st: 0 flags:1 ts:-0.740831
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67716 size: 10791
+ret: 0 st: 0 flags:0 ts:-0.058330
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
+ret: 0 st: 0 flags:1 ts: 2.835837
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157685 size: 11930
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157685 size: 11930
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 30744 size: 9980
+ret: 0 st: 0 flags:0 ts:-0.481662
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
+ret: 0 st: 0 flags:1 ts: 2.412505
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157685 size: 11930
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110086 size: 11697
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
+ret: 0 st: 0 flags:0 ts:-0.904994
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 0 size: 9954
+ret: 0 st: 0 flags:1 ts: 1.989173
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 157685 size: 11930
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110086 size: 11697
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.671674
+ret: 0 st: 0 flags:1 ts: 1.565841
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 110086 size: 11697
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 67716 size: 10791
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4 b/tests/ref/seek/vsynth_lena-mpeg4
new file mode 100644
index 0000000000..b1c8a19db8
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4
@@ -0,0 +1,50 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 75140 size: 10776
+ret: 0 st: 0 flags:0 ts: 0.788359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 47228 size: 9634
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 75140 size: 10776
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 23271 size: 8524
+ret: 0 st: 0 flags:1 ts:-0.740859
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 47228 size: 9634
+ret: 0 st: 0 flags:0 ts:-0.058359
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret: 0 st: 0 flags:1 ts: 2.835859
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106181 size: 11182
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106181 size: 11182
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 23271 size: 8524
+ret: 0 st: 0 flags:0 ts:-0.481641
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106181 size: 11182
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 75140 size: 10776
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret: 0 st: 0 flags:1 ts: 1.989141
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 106181 size: 11182
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 47228 size: 9634
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
+ret:-1 st: 0 flags:0 ts: 2.671641
+ret: 0 st: 0 flags:1 ts: 1.565859
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 75140 size: 10776
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 23271 size: 8524
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 44 size: 8719
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-adap b/tests/ref/seek/vsynth_lena-mpeg4-adap
new file mode 100644
index 0000000000..0611ee4511
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-adap
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 6855
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 6855
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174446 size: 16883
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98220 size: 17063
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135582 size: 17525
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 59446 size: 17261
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98220 size: 17063
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 6855
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174446 size: 16883
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174446 size: 16883
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 59446 size: 17261
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 6855
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174446 size: 16883
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135582 size: 17525
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 6855
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 6855
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 174446 size: 16883
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98220 size: 17063
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 135582 size: 17525
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 98220 size: 17063
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-adv b/tests/ref/seek/vsynth_lena-mpeg4-adv
new file mode 100644
index 0000000000..9a51eaeaea
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-adv
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8653
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8653
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 91722 size: 11013
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 59496 size: 9815
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 91722 size: 11013
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 31936 size: 8753
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 59496 size: 9815
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8653
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 127616 size: 11279
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 127616 size: 11279
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 31936 size: 8753
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8653
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 127616 size: 11279
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 91722 size: 11013
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8653
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8653
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 127616 size: 11279
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 59496 size: 9815
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 91722 size: 11013
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 31936 size: 8753
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-error b/tests/ref/seek/vsynth_lena-mpeg4-error
new file mode 100644
index 0000000000..9608a7b34c
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-error
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9729
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9729
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113186 size: 15063
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 73146 size: 10235
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113186 size: 15063
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38232 size: 10303
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 73146 size: 10235
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9729
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163068 size: 13980
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163068 size: 13980
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38232 size: 10303
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9729
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163068 size: 13980
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113186 size: 15063
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9729
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9729
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 163068 size: 13980
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 73146 size: 10235
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 113186 size: 15063
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 38232 size: 10303
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-nr b/tests/ref/seek/vsynth_lena-mpeg4-nr
new file mode 100644
index 0000000000..6de31b7f08
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-nr
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10673
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10673
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100656 size: 12464
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65492 size: 11180
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100656 size: 12464
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35314 size: 9987
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65492 size: 11180
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10673
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139376 size: 12911
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139376 size: 12911
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35314 size: 9987
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10673
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139376 size: 12911
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100656 size: 12464
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10673
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 10673
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139376 size: 12911
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 65492 size: 11180
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 100656 size: 12464
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 35314 size: 9987
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-nsse b/tests/ref/seek/vsynth_lena-mpeg4-nsse
new file mode 100644
index 0000000000..e73ce6033c
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-nsse
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11937
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11937
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 127876 size: 15054
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 81656 size: 13376
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 127876 size: 15054
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42642 size: 11805
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 81656 size: 13376
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11937
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179516 size: 15553
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179516 size: 15553
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42642 size: 11805
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11937
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179516 size: 15553
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 127876 size: 15054
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11937
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 11937
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 179516 size: 15553
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 81656 size: 13376
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 127876 size: 15054
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 42642 size: 11805
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-qpel b/tests/ref/seek/vsynth_lena-mpeg4-qpel
new file mode 100644
index 0000000000..cf5da07680
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-qpel
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 11938
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 11938
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141530 size: 15554
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64114 size: 13377
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100340 size: 15055
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 32840 size: 11806
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64114 size: 13377
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 11938
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141530 size: 15554
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141530 size: 15554
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 32840 size: 11806
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 11938
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141530 size: 15554
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100340 size: 15055
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 11938
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 11938
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 141530 size: 15554
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64114 size: 13377
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 100340 size: 15055
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 64114 size: 13377
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-qprd b/tests/ref/seek/vsynth_lena-mpeg4-qprd
new file mode 100644
index 0000000000..b92e3d225d
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-qprd
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14873
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14873
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211034 size: 14638
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150658 size: 14502
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180782 size: 14371
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 93028 size: 29366
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150658 size: 14502
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14873
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211034 size: 14638
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211034 size: 14638
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 93028 size: 29366
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14873
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211034 size: 14638
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180782 size: 14371
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14873
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14873
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 211034 size: 14638
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150658 size: 14502
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180782 size: 14371
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 150658 size: 14502
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-rc b/tests/ref/seek/vsynth_lena-mpeg4-rc
new file mode 100644
index 0000000000..e1994af948
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-rc
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 15766
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 15766
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207954 size: 13826
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153788 size: 13377
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180950 size: 13326
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 94578 size: 32807
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153788 size: 13377
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 15766
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207954 size: 13826
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207954 size: 13826
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 94578 size: 32807
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 15766
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207954 size: 13826
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180950 size: 13326
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 15766
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 15766
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 207954 size: 13826
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153788 size: 13377
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 180950 size: 13326
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 153788 size: 13377
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-mpeg4-thread b/tests/ref/seek/vsynth_lena-mpeg4-thread
new file mode 100644
index 0000000000..287b96d566
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-mpeg4-thread
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14874
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14874
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228190 size: 16323
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162160 size: 16462
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195334 size: 16153
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 97836 size: 33332
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162160 size: 16462
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14874
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228190 size: 16323
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228190 size: 16323
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.400000 pts: NOPTS pos: 97836 size: 33332
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14874
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228190 size: 16323
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195334 size: 16153
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14874
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: NOPTS pos: 5652 size: 14874
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.840000 pts: NOPTS pos: 228190 size: 16323
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162160 size: 16462
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.360000 pts: NOPTS pos: 195334 size: 16153
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: NOPTS pos: 162160 size: 16462
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-msmpeg4 b/tests/ref/seek/vsynth_lena-msmpeg4
new file mode 100644
index 0000000000..0bb9f75056
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-msmpeg4
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8637
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8637
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 82512 size: 10783
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 53850 size: 9624
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 82512 size: 10783
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29392 size: 8502
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 53850 size: 9624
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8637
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114260 size: 11180
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114260 size: 11180
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29392 size: 8502
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8637
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114260 size: 11180
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 82512 size: 10783
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8637
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8637
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 114260 size: 11180
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 53850 size: 9624
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 82512 size: 10783
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29392 size: 8502
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-msmpeg4v2 b/tests/ref/seek/vsynth_lena-msmpeg4v2
new file mode 100644
index 0000000000..27ed0ed5a7
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-msmpeg4v2
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9003
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9003
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83874 size: 11165
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54782 size: 10010
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83874 size: 11165
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29774 size: 8869
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54782 size: 10010
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9003
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116116 size: 11578
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116116 size: 11578
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29774 size: 8869
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9003
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116116 size: 11578
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83874 size: 11165
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9003
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 9003
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116116 size: 11578
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54782 size: 10010
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83874 size: 11165
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29774 size: 8869
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-rgb b/tests/ref/seek/vsynth_lena-rgb
new file mode 100644
index 0000000000..8173ca988a
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-rgb
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:304128
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:304128
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:14300044 size:304128
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:6088372 size:304128
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:11258684 size:304128
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:2742876 size:304128
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:7913188 size:304128
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:304128
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14908316 size:304128
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:13083500 size:304128
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:4871828 size:304128
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:304128
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14908316 size:304128
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:10042140 size:304128
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1526332 size:304128
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:304128
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:14908316 size:304128
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:6696644 size:304128
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:11866956 size:304128
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:3655284 size:304128
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-roqvideo b/tests/ref/seek/vsynth_lena-roqvideo
new file mode 100644
index 0000000000..50a0a335c7
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-roqvideo
@@ -0,0 +1,27 @@
+ret: 0 st: 0 flags:0 dts: 0.000000 pts: 0.000000 pos: 24 size: 26814
+ret:-1 st:-1 flags:0 ts:-1.000000
+ret:-1 st:-1 flags:1 ts: 1.894167
+ret:-1 st: 0 flags:0 ts: 0.800000
+ret:-1 st: 0 flags:1 ts:-0.333333
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret:-1 st:-1 flags:1 ts: 1.470835
+ret:-1 st: 0 flags:0 ts: 0.366667
+ret:-1 st: 0 flags:1 ts:-0.733333
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret:-1 st:-1 flags:1 ts: 1.047503
+ret:-1 st: 0 flags:0 ts:-0.066667
+ret:-1 st: 0 flags:1 ts: 2.833333
+ret:-1 st:-1 flags:0 ts: 1.730004
+ret:-1 st:-1 flags:1 ts: 0.624171
+ret:-1 st: 0 flags:0 ts:-0.466667
+ret:-1 st: 0 flags:1 ts: 2.400000
+ret:-1 st:-1 flags:0 ts: 1.306672
+ret:-1 st:-1 flags:1 ts: 0.200839
+ret:-1 st: 0 flags:0 ts:-0.900000
+ret:-1 st: 0 flags:1 ts: 2.000000
+ret:-1 st:-1 flags:0 ts: 0.883340
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.666667
+ret:-1 st: 0 flags:1 ts: 1.566667
+ret:-1 st:-1 flags:0 ts: 0.460008
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-rv10 b/tests/ref/seek/vsynth_lena-rv10
new file mode 100644
index 0000000000..818040def9
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-rv10
@@ -0,0 +1,52 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret:-1 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:0 ts: 0.788000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 61592 size: 11135
+ret: 0 st: 0 flags:1 ts:-0.317000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98608 size: 12303
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 31132 size: 10097
+ret: 0 st: 0 flags:1 ts:-0.741000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 61592 size: 11135
+ret: 0 st: 0 flags:0 ts:-0.058000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st: 0 flags:1 ts: 2.836000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 31132 size: 10097
+ret: 0 st: 0 flags:0 ts:-0.482000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st: 0 flags:1 ts: 2.413000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98608 size: 12303
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st: 0 flags:1 ts: 1.989000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 61592 size: 11135
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
+ret: 0 st: 0 flags:0 ts: 2.672000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139566 size: 12738
+ret: 0 st: 0 flags:1 ts: 1.566000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98608 size: 12303
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 31132 size: 10097
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 10388
diff --git a/tests/ref/seek/vsynth_lena-rv20 b/tests/ref/seek/vsynth_lena-rv20
new file mode 100644
index 0000000000..7f1ad39243
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-rv20
@@ -0,0 +1,53 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98158 size: 11344
+ret: 0 st: 0 flags:0 ts: 0.788000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 61133 size: 10166
+ret: 0 st: 0 flags:1 ts:-0.317000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st:-1 flags:0 ts: 2.576668
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98158 size: 11344
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 30753 size: 9101
+ret: 0 st: 0 flags:1 ts:-0.741000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st:-1 flags:0 ts: 2.153336
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 61133 size: 10166
+ret: 0 st: 0 flags:0 ts:-0.058000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st: 0 flags:1 ts: 2.836000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 30753 size: 9101
+ret: 0 st: 0 flags:0 ts:-0.482000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st: 0 flags:1 ts: 2.413000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98158 size: 11344
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st: 0 flags:1 ts: 1.989000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 61133 size: 10166
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
+ret: 0 st: 0 flags:0 ts: 2.672000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 139147 size: 11803
+ret: 0 st: 0 flags:1 ts: 1.566000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 98158 size: 11344
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 30753 size: 9101
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 239 size: 9361
diff --git a/tests/ref/seek/vsynth_lena-snow b/tests/ref/seek/vsynth_lena-snow
new file mode 100644
index 0000000000..33d6c27463
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-snow
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 3035
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 3035
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39806 size: 3640
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27442 size: 3494
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39806 size: 3640
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16134 size: 3244
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27442 size: 3494
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52608 size: 3582
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52608 size: 3582
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16134 size: 3244
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52608 size: 3582
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39806 size: 3640
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 3035
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 3035
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 52608 size: 3582
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 27442 size: 3494
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 39806 size: 3640
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 16134 size: 3244
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-snow-ll b/tests/ref/seek/vsynth_lena-snow-ll
new file mode 100644
index 0000000000..039db705d3
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-snow-ll
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 72476
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 72476
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902792 size: 78837
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239094 size: 74994
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902792 size: 78837
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605632 size: 71059
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239094 size: 74994
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585618 size: 79731
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585618 size: 79731
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605632 size: 71059
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585618 size: 79731
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902792 size: 78837
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 72476
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 72476
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos:2585618 size: 79731
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:1239094 size: 74994
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos:1902792 size: 78837
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 605632 size: 71059
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-svq1 b/tests/ref/seek/vsynth_lena-svq1
new file mode 100644
index 0000000000..33fe33e916
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-svq1
@@ -0,0 +1,50 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
+ret: 0 st: 0 flags:0 ts: 0.788359
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326556 size: 23552
+ret: 0 st: 0 flags:1 ts:-0.317500
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
+ret: 0 st: 0 flags:0 ts: 0.365000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 157040 size: 21896
+ret: 0 st: 0 flags:1 ts:-0.740859
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326556 size: 23552
+ret: 0 st: 0 flags:0 ts:-0.058359
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret: 0 st: 0 flags:1 ts: 2.835859
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 157040 size: 21896
+ret: 0 st: 0 flags:0 ts:-0.481641
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret: 0 st: 0 flags:1 ts: 2.412500
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret: 0 st: 0 flags:0 ts:-0.905000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret: 0 st: 0 flags:1 ts: 1.989141
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 722804 size: 25888
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 326556 size: 23552
+ret: 0 st:-1 flags:1 ts:-0.222493
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
+ret:-1 st: 0 flags:0 ts: 2.671641
+ret: 0 st: 0 flags:1 ts: 1.565859
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 517568 size: 25636
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 157040 size: 21896
+ret: 0 st:-1 flags:1 ts:-0.645825
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 36 size: 22300
diff --git a/tests/ref/seek/vsynth_lena-wmv1 b/tests/ref/seek/vsynth_lena-wmv1
new file mode 100644
index 0000000000..125e6cd3c4
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-wmv1
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8990
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8990
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83746 size: 11099
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54762 size: 9931
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83746 size: 11099
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29798 size: 8796
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54762 size: 9931
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8990
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115810 size: 11486
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115810 size: 11486
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29798 size: 8796
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8990
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115810 size: 11486
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83746 size: 11099
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8990
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size: 8990
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 115810 size: 11486
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54762 size: 9931
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83746 size: 11099
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29798 size: 8796
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-wmv2 b/tests/ref/seek/vsynth_lena-wmv2
new file mode 100644
index 0000000000..ffa576208b
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-wmv2
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 8917
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 8917
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83768 size: 11169
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54538 size: 9989
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83768 size: 11169
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29592 size: 8839
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54538 size: 9989
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 8917
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116070 size: 11554
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116070 size: 11554
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29592 size: 8839
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 8917
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116070 size: 11554
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83768 size: 11169
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 8917
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5656 size: 8917
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.920000 pts: 1.920000 pos: 116070 size: 11554
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 54538 size: 9989
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.440000 pts: 1.440000 pos: 83768 size: 11169
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 29592 size: 8839
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/seek/vsynth_lena-yuv b/tests/ref/seek/vsynth_lena-yuv
new file mode 100644
index 0000000000..f899d7f518
--- /dev/null
+++ b/tests/ref/seek/vsynth_lena-yuv
@@ -0,0 +1,46 @@
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:152064
+ret: 0 st:-1 flags:0 ts:-1.000000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:152064
+ret: 0 st:-1 flags:1 ts: 1.894167
+ret: 0 st: 0 flags:1 dts: 1.880000 pts: 1.880000 pos:7153036 size:152064
+ret: 0 st: 0 flags:0 ts: 0.800000
+ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3047092 size:152064
+ret:-1 st: 0 flags:1 ts:-0.320000
+ret:-1 st:-1 flags:0 ts: 2.576668
+ret: 0 st:-1 flags:1 ts: 1.470835
+ret: 0 st: 0 flags:1 dts: 1.480000 pts: 1.480000 pos:5632316 size:152064
+ret: 0 st: 0 flags:0 ts: 0.360000
+ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1374300 size:152064
+ret:-1 st: 0 flags:1 ts:-0.760000
+ret:-1 st:-1 flags:0 ts: 2.153336
+ret: 0 st:-1 flags:1 ts: 1.047503
+ret: 0 st: 0 flags:1 dts: 1.040000 pts: 1.040000 pos:3959524 size:152064
+ret: 0 st: 0 flags:0 ts:-0.040000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:152064
+ret: 0 st: 0 flags:1 ts: 2.840000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7457180 size:152064
+ret: 0 st:-1 flags:0 ts: 1.730004
+ret: 0 st: 0 flags:1 dts: 1.720000 pts: 1.720000 pos:6544748 size:152064
+ret: 0 st:-1 flags:1 ts: 0.624171
+ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2438804 size:152064
+ret: 0 st: 0 flags:0 ts:-0.480000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:152064
+ret: 0 st: 0 flags:1 ts: 2.400000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7457180 size:152064
+ret: 0 st:-1 flags:0 ts: 1.306672
+ret: 0 st: 0 flags:1 dts: 1.320000 pts: 1.320000 pos:5024028 size:152064
+ret: 0 st:-1 flags:1 ts: 0.200839
+ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 766012 size:152064
+ret: 0 st: 0 flags:0 ts:-0.920000
+ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5652 size:152064
+ret: 0 st: 0 flags:1 ts: 2.000000
+ret: 0 st: 0 flags:1 dts: 1.960000 pts: 1.960000 pos:7457180 size:152064
+ret: 0 st:-1 flags:0 ts: 0.883340
+ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3351236 size:152064
+ret:-1 st:-1 flags:1 ts:-0.222493
+ret:-1 st: 0 flags:0 ts: 2.680000
+ret: 0 st: 0 flags:1 ts: 1.560000
+ret: 0 st: 0 flags:1 dts: 1.560000 pts: 1.560000 pos:5936460 size:152064
+ret: 0 st:-1 flags:0 ts: 0.460008
+ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1830516 size:152064
+ret:-1 st:-1 flags:1 ts:-0.645825
diff --git a/tests/ref/vsynth/vsynth1-amv b/tests/ref/vsynth/vsynth1-amv
new file mode 100644
index 0000000000..e4652c5c90
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-amv
@@ -0,0 +1,4 @@
+9e155fcedb3b853876e9ea4233971803 *tests/data/fate/vsynth1-amv.avi
+1365500 tests/data/fate/vsynth1-amv.avi
+e38681b9527b6d2531942f8a176a0265 *tests/data/fate/vsynth1-amv.out.rawvideo
+stddev: 10.07 PSNR: 28.06 MAXDIFF: 98 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-asv1 b/tests/ref/vsynth/vsynth1-asv1
index e640f1c145..99ce220f89 100644
--- a/tests/ref/vsynth/vsynth1-asv1
+++ b/tests/ref/vsynth/vsynth1-asv1
@@ -1,4 +1,4 @@
-41b011551d23ddadaab1083cb2106d9f *tests/data/fate/vsynth1-asv1.avi
-1489644 tests/data/fate/vsynth1-asv1.avi
-2dfc5dfc2c1cbbc2543257cd3d2df6af *tests/data/fate/vsynth1-asv1.out.rawvideo
-stddev: 20.00 PSNR: 22.11 MAXDIFF: 158 bytes: 7603200/ 7603200
+8f1ab10246da351b6be88dd74319f76e *tests/data/fate/vsynth1-asv1.avi
+1298620 tests/data/fate/vsynth1-asv1.avi
+a4f95c58e8b9258da52b9d09153b1078 *tests/data/fate/vsynth1-asv1.out.rawvideo
+stddev: 11.89 PSNR: 26.62 MAXDIFF: 132 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-asv2 b/tests/ref/vsynth/vsynth1-asv2
index 6282ad4acf..2932147dd3 100644
--- a/tests/ref/vsynth/vsynth1-asv2
+++ b/tests/ref/vsynth/vsynth1-asv2
@@ -1,4 +1,4 @@
-a0773690d0e772ff832adea1e8c16773 *tests/data/fate/vsynth1-asv2.avi
-1456044 tests/data/fate/vsynth1-asv2.avi
-d451be09793cd0f35b6d91fc36e2571a *tests/data/fate/vsynth1-asv2.out.rawvideo
-stddev: 18.82 PSNR: 22.63 MAXDIFF: 131 bytes: 7603200/ 7603200
+ea142aefed8e72a2e39cdef350c315ed *tests/data/fate/vsynth1-asv2.avi
+1434412 tests/data/fate/vsynth1-asv2.avi
+cb1f5560005800e889bfbb36cdc9fc40 *tests/data/fate/vsynth1-asv2.out.rawvideo
+stddev: 8.36 PSNR: 29.68 MAXDIFF: 58 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-avui b/tests/ref/vsynth/vsynth1-avui
new file mode 100644
index 0000000000..1f080532b5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-avui
@@ -0,0 +1,4 @@
+25ef49e1aee0b20d4feee89b8dc093b4 *tests/data/fate/vsynth1-avui.mov
+42625037 tests/data/fate/vsynth1-avui.mov
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-avui.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-cinepak b/tests/ref/vsynth/vsynth1-cinepak
new file mode 100644
index 0000000000..f1dfcd81db
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-cinepak
@@ -0,0 +1,4 @@
+546c7c1069f9e418aa787f469b693b94 *tests/data/fate/vsynth1-cinepak.mov
+99465 tests/data/fate/vsynth1-cinepak.mov
+bee091c200262be3427a233a2812388c *tests/data/fate/vsynth1-cinepak.out.rawvideo
+stddev: 8.46 PSNR: 29.58 MAXDIFF: 105 bytes: 7603200/ 456192
diff --git a/tests/ref/vsynth/vsynth1-cljr b/tests/ref/vsynth/vsynth1-cljr
index cdd6ca2308..4260d9eff8 100644
--- a/tests/ref/vsynth/vsynth1-cljr
+++ b/tests/ref/vsynth/vsynth1-cljr
@@ -1,4 +1,4 @@
-41fc45d5e8bca3cf2be35457b188cdb3 *tests/data/fate/vsynth1-cljr.avi
-5075648 tests/data/fate/vsynth1-cljr.avi
-72e01607bae16527bc6389cf6db00b5f *tests/data/fate/vsynth1-cljr.out.rawvideo
-stddev: 6.95 PSNR: 31.28 MAXDIFF: 86 bytes: 7603200/ 7603200
+085c6c83b0ef1ff6b3abd598f296e01e *tests/data/fate/vsynth1-cljr.avi
+5075652 tests/data/fate/vsynth1-cljr.avi
+7bd979b8b397f7bac22a0102c7889452 *tests/data/fate/vsynth1-cljr.out.rawvideo
+stddev: 6.74 PSNR: 31.55 MAXDIFF: 84 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i b/tests/ref/vsynth/vsynth1-dnxhd-1080i
index 8d396e819f..28d55b6b9d 100644
--- a/tests/ref/vsynth/vsynth1-dnxhd-1080i
+++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i
@@ -1,4 +1,4 @@
-9e55c9ec332cc6ee002da67de34ca6d1 *tests/data/fate/vsynth1-dnxhd-1080i.mov
-3031875 tests/data/fate/vsynth1-dnxhd-1080i.mov
-34076f61254997c8157eafed1c916472 *tests/data/fate/vsynth1-dnxhd-1080i.out.rawvideo
+a0234e0a8516d958f423b119aa9e35c4 *tests/data/fate/vsynth1-dnxhd-1080i.mov
+3031911 tests/data/fate/vsynth1-dnxhd-1080i.mov
+a09132c6db44f415e831dcaa630a351b *tests/data/fate/vsynth1-dnxhd-1080i.out.rawvideo
stddev: 6.29 PSNR: 32.15 MAXDIFF: 64 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr
new file mode 100644
index 0000000000..16d895353c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+5fccdb16c0f14dea1b6b603bac90b97e *tests/data/fate/vsynth1-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth1-dnxhd-1080i-colr.mov
+5835dff88cb84e83bbe70b5ed5edd5ab *tests/data/fate/vsynth1-dnxhd-1080i-colr.out.rawvideo
+stddev: 5.79 PSNR: 32.87 MAXDIFF: 56 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth1-dnxhd-720p b/tests/ref/vsynth/vsynth1-dnxhd-720p
index 94c28ed2fc..fd77e86360 100644
--- a/tests/ref/vsynth/vsynth1-dnxhd-720p
+++ b/tests/ref/vsynth/vsynth1-dnxhd-720p
@@ -1,4 +1,4 @@
-81f5be451dc18cf8a1d333c7885de60b *tests/data/fate/vsynth1-dnxhd-720p.dnxhd
+af03d57b8320568027162132643f7814 *tests/data/fate/vsynth1-dnxhd-720p.dnxhd
2293760 tests/data/fate/vsynth1-dnxhd-720p.dnxhd
-94b21e5e68ccf9471eff74afd0ebe319 *tests/data/fate/vsynth1-dnxhd-720p.out.rawvideo
-stddev: 6.32 PSNR: 32.11 MAXDIFF: 183 bytes: 7603200/ 760320
+f074f1b5ed394871b3c73184ad55b895 *tests/data/fate/vsynth1-dnxhd-720p.out.rawvideo
+stddev: 6.26 PSNR: 32.19 MAXDIFF: 65 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth1-dnxhd-720p-10bit b/tests/ref/vsynth/vsynth1-dnxhd-720p-10bit
index a667b9d144..8a8f639d5b 100644
--- a/tests/ref/vsynth/vsynth1-dnxhd-720p-10bit
+++ b/tests/ref/vsynth/vsynth1-dnxhd-720p-10bit
@@ -1,4 +1,4 @@
-b5e24a055af02edec8674333260214fd *tests/data/fate/vsynth1-dnxhd-720p-10bit.dnxhd
+f8c4b7aa165a80df2485d526161290a3 *tests/data/fate/vsynth1-dnxhd-720p-10bit.dnxhd
2293760 tests/data/fate/vsynth1-dnxhd-720p-10bit.dnxhd
-4466ff3d73d01bbe75ea25001d379b63 *tests/data/fate/vsynth1-dnxhd-720p-10bit.out.rawvideo
+ec26a6cbf53e38ffb9d5c51cbfbf4f7c *tests/data/fate/vsynth1-dnxhd-720p-10bit.out.rawvideo
stddev: 6.27 PSNR: 32.18 MAXDIFF: 64 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth1-dnxhd-720p-rd b/tests/ref/vsynth/vsynth1-dnxhd-720p-rd
index 1de576a870..0422776943 100644
--- a/tests/ref/vsynth/vsynth1-dnxhd-720p-rd
+++ b/tests/ref/vsynth/vsynth1-dnxhd-720p-rd
@@ -1,4 +1,4 @@
-1dc6e95925c4f3a230848ec17c02abed *tests/data/fate/vsynth1-dnxhd-720p-rd.dnxhd
+276e5175376051218b0e3eb36f9e9a63 *tests/data/fate/vsynth1-dnxhd-720p-rd.dnxhd
2293760 tests/data/fate/vsynth1-dnxhd-720p-rd.dnxhd
-02972d2aec120ec1577ec9053d68ae0f *tests/data/fate/vsynth1-dnxhd-720p-rd.out.rawvideo
+28662df973b289798bf6069fbbee8071 *tests/data/fate/vsynth1-dnxhd-720p-rd.out.rawvideo
stddev: 6.26 PSNR: 32.19 MAXDIFF: 65 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth1-dnxhd_1080i b/tests/ref/vsynth/vsynth1-dnxhd_1080i
new file mode 100644
index 0000000000..f8f6df09bf
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-dnxhd_1080i
@@ -0,0 +1,4 @@
+027c985483caab9397592bf27477dce1 *./tests/data/vsynth1/dnxhd-1080i.mov
+3031911 ./tests/data/vsynth1/dnxhd-1080i.mov
+0c651e840f860592f0d5b66030d9fa32 *./tests/data/dnxhd_1080i.vsynth1.out.yuv
+stddev: 6.29 PSNR: 32.15 MAXDIFF: 64 bytes: 760320/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-dv b/tests/ref/vsynth/vsynth1-dv
index f5a37adb95..6237b078c5 100644
--- a/tests/ref/vsynth/vsynth1-dv
+++ b/tests/ref/vsynth/vsynth1-dv
@@ -1,4 +1,4 @@
-27ade3031b17214cf81c19cbf70f37d7 *tests/data/fate/vsynth1-dv.dv
+4d572f758b55a1756adf9f54132f3b9e *tests/data/fate/vsynth1-dv.dv
7200000 tests/data/fate/vsynth1-dv.dv
-02ac7cdeab91d4d5621e7ce96dddc498 *tests/data/fate/vsynth1-dv.out.rawvideo
+1cda5a62c3a2f17cc7d5b4cddccf2524 *tests/data/fate/vsynth1-dv.out.rawvideo
stddev: 6.90 PSNR: 31.34 MAXDIFF: 76 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-dv-411 b/tests/ref/vsynth/vsynth1-dv-411
index a1f07da3fc..48e01a1403 100644
--- a/tests/ref/vsynth/vsynth1-dv-411
+++ b/tests/ref/vsynth/vsynth1-dv-411
@@ -1,4 +1,4 @@
-bd67f2431db160d4bb6dcd791cea6efd *tests/data/fate/vsynth1-dv-411.dv
+f179899efba432c6f01149c36c709092 *tests/data/fate/vsynth1-dv-411.dv
7200000 tests/data/fate/vsynth1-dv-411.dv
-53946d51762b7826773e681fb02f377b *tests/data/fate/vsynth1-dv-411.out.rawvideo
-stddev: 9.45 PSNR: 28.62 MAXDIFF: 84 bytes: 7603200/ 7603200
+48904744fabbbc3421a762f615ef6456 *tests/data/fate/vsynth1-dv-411.out.rawvideo
+stddev: 9.44 PSNR: 28.62 MAXDIFF: 84 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-dv-50 b/tests/ref/vsynth/vsynth1-dv-50
index 18ee398864..d5da88d78c 100644
--- a/tests/ref/vsynth/vsynth1-dv-50
+++ b/tests/ref/vsynth/vsynth1-dv-50
@@ -1,4 +1,4 @@
-26dba84f0ea895b914ef5b333d8394ac *tests/data/fate/vsynth1-dv-50.dv
+a193c5f92bf6e74c604e759d5f4f0f94 *tests/data/fate/vsynth1-dv-50.dv
14400000 tests/data/fate/vsynth1-dv-50.dv
-a2ff093e93ffed10f730fa21df02fc50 *tests/data/fate/vsynth1-dv-50.out.rawvideo
+41c4df5f2d876fcd5245643b9ded6711 *tests/data/fate/vsynth1-dv-50.out.rawvideo
stddev: 1.72 PSNR: 43.38 MAXDIFF: 29 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-dv_411 b/tests/ref/vsynth/vsynth1-dv_411
new file mode 100644
index 0000000000..c45b593c02
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-dv_411
@@ -0,0 +1,4 @@
+f179899efba432c6f01149c36c709092 *./tests/data/vsynth1/dv411.dv
+7200000 ./tests/data/vsynth1/dv411.dv
+b6640a3a572353f51284acb746eb00c4 *./tests/data/dv_411.vsynth1.out.yuv
+stddev: 30.76 PSNR: 18.37 MAXDIFF: 205 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffv1 b/tests/ref/vsynth/vsynth1-ffv1
index a162a77abc..001f10aae5 100644
--- a/tests/ref/vsynth/vsynth1-ffv1
+++ b/tests/ref/vsynth/vsynth1-ffv1
@@ -1,4 +1,4 @@
-d236e8441d7e04e24d882bb97faccd36 *tests/data/fate/vsynth1-ffv1.avi
-2689718 tests/data/fate/vsynth1-ffv1.avi
+26b1296a0ef80a3b5c8b63cc57c52bc2 *tests/data/fate/vsynth1-ffv1.avi
+2691268 tests/data/fate/vsynth1-ffv1.avi
c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffv1.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffv1.0 b/tests/ref/vsynth/vsynth1-ffv1.0
new file mode 100644
index 0000000000..09053031ba
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1.0
@@ -0,0 +1,4 @@
+36011c9a2b288fb04bf6c520371646d4 *tests/data/fate/vsynth1-ffv1.0.avi
+2655368 tests/data/fate/vsynth1-ffv1.0.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffv1.0.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffvhuff b/tests/ref/vsynth/vsynth1-ffvhuff
index cf86f570fe..c982fb9437 100644
--- a/tests/ref/vsynth/vsynth1-ffvhuff
+++ b/tests/ref/vsynth/vsynth1-ffvhuff
@@ -1,4 +1,4 @@
-2279cfd5efce9dc3435b814f1f95dcbc *tests/data/fate/vsynth1-ffvhuff.avi
-5987196 tests/data/fate/vsynth1-ffvhuff.avi
+be797b3c97bea941c5df720b44b779d4 *tests/data/fate/vsynth1-ffvhuff.avi
+6809214 tests/data/fate/vsynth1-ffvhuff.avi
c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffvhuff.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffvhuff420p12 b/tests/ref/vsynth/vsynth1-ffvhuff420p12
new file mode 100644
index 0000000000..0d80bd6d68
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff420p12
@@ -0,0 +1,4 @@
+866485c954242232878e40f0389790dd *tests/data/fate/vsynth1-ffvhuff420p12.avi
+14205356 tests/data/fate/vsynth1-ffvhuff420p12.avi
+b48f32c140712e8c7bf81cfdd66ae312 *tests/data/fate/vsynth1-ffvhuff420p12.out.rawvideo
+stddev: 0.68 PSNR: 51.47 MAXDIFF: 1 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffvhuff422p10left b/tests/ref/vsynth/vsynth1-ffvhuff422p10left
new file mode 100644
index 0000000000..25c2ded4a3
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff422p10left
@@ -0,0 +1,4 @@
+d29edc22816fd865d3075ad6c1eaaffa *tests/data/fate/vsynth1-ffvhuff422p10left.avi
+13860684 tests/data/fate/vsynth1-ffvhuff422p10left.avi
+c31e6caada921ffa3daad3432ef3b754 *tests/data/fate/vsynth1-ffvhuff422p10left.out.rawvideo
+stddev: 1.85 PSNR: 42.78 MAXDIFF: 29 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffvhuff444 b/tests/ref/vsynth/vsynth1-ffvhuff444
new file mode 100644
index 0000000000..978a0af9f0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff444
@@ -0,0 +1,4 @@
+b013f0933ef27f7e23a62a13226e0510 *tests/data/fate/vsynth1-ffvhuff444.avi
+11712342 tests/data/fate/vsynth1-ffvhuff444.avi
+10fb42f1abf40a289c3edafc0390482c *tests/data/fate/vsynth1-ffvhuff444.out.rawvideo
+stddev: 2.67 PSNR: 39.60 MAXDIFF: 43 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ffvhuff444p16 b/tests/ref/vsynth/vsynth1-ffvhuff444p16
new file mode 100644
index 0000000000..f3a6d7d21c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffvhuff444p16
@@ -0,0 +1,4 @@
+2f780c186d2549aa257511a951918617 *tests/data/fate/vsynth1-ffvhuff444p16.avi
+24706276 tests/data/fate/vsynth1-ffvhuff444p16.avi
+ee8379fa217dfd023de3aa6974a14d1e *tests/data/fate/vsynth1-ffvhuff444p16.out.rawvideo
+stddev: 2.66 PSNR: 39.62 MAXDIFF: 44 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-flashsv b/tests/ref/vsynth/vsynth1-flashsv
index a4f22ce0a4..8b2783032b 100644
--- a/tests/ref/vsynth/vsynth1-flashsv
+++ b/tests/ref/vsynth/vsynth1-flashsv
@@ -1,4 +1,4 @@
-6675942f5cd6978f16eff5305578de27 *tests/data/fate/vsynth1-flashsv.flv
-14681905 tests/data/fate/vsynth1-flashsv.flv
-947cb24ec45a453348ae6fe3fa278071 *tests/data/fate/vsynth1-flashsv.out.rawvideo
-stddev: 2.85 PSNR: 39.03 MAXDIFF: 49 bytes: 7603200/ 7603200
+97894502b4cb57aca1105b6333f72dae *tests/data/fate/vsynth1-flashsv.flv
+14681925 tests/data/fate/vsynth1-flashsv.flv
+791e1fb999deb2e4156e2286d48c4ed1 *tests/data/fate/vsynth1-flashsv.out.rawvideo
+stddev: 2.84 PSNR: 39.04 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-flashsv2 b/tests/ref/vsynth/vsynth1-flashsv2
new file mode 100644
index 0000000000..a01ccbee53
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-flashsv2
@@ -0,0 +1,4 @@
+adbbdd25c1ed2f87ea589d2314307cdf *tests/data/fate/vsynth1-flashsv2.flv
+9368395 tests/data/fate/vsynth1-flashsv2.flv
+efa88d09115a2e947eff00ee435ba3f3 *tests/data/fate/vsynth1-flashsv2.out.rawvideo
+stddev: 3.47 PSNR: 37.31 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-flv b/tests/ref/vsynth/vsynth1-flv
index a92658b13d..3a21e6a680 100644
--- a/tests/ref/vsynth/vsynth1-flv
+++ b/tests/ref/vsynth/vsynth1-flv
@@ -1,4 +1,4 @@
-202e8b9715f278497eb13476fc9abdac *tests/data/fate/vsynth1-flv.flv
-636249 tests/data/fate/vsynth1-flv.flv
-5ab46d8dd01dbb1d63df2a84858a4b05 *tests/data/fate/vsynth1-flv.out.rawvideo
+7f6ece1acc4163e33a982dd77dfad58a *tests/data/fate/vsynth1-flv.flv
+636264 tests/data/fate/vsynth1-flv.flv
+00ffbd9dac9233e53f4a4a19589a0efe *tests/data/fate/vsynth1-flv.out.rawvideo
stddev: 8.02 PSNR: 30.04 MAXDIFF: 105 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-h261 b/tests/ref/vsynth/vsynth1-h261
index b350e6f358..4ba2a44ad0 100644
--- a/tests/ref/vsynth/vsynth1-h261
+++ b/tests/ref/vsynth/vsynth1-h261
@@ -1,4 +1,4 @@
-d3397557ad8a02d28cb5feeb0b51e5c8 *tests/data/fate/vsynth1-h261.avi
-707576 tests/data/fate/vsynth1-h261.avi
-716e83cb51afb1246bfaa80967df48ea *tests/data/fate/vsynth1-h261.out.rawvideo
+be41f18a8c3120b730270a9ec45545aa *tests/data/fate/vsynth1-h261.avi
+707550 tests/data/fate/vsynth1-h261.avi
+85fde92037c2ccecc02e2d6c21a169b0 *tests/data/fate/vsynth1-h261.out.rawvideo
stddev: 9.11 PSNR: 28.93 MAXDIFF: 113 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-h261-trellis b/tests/ref/vsynth/vsynth1-h261-trellis
new file mode 100644
index 0000000000..bf74a24685
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-h261-trellis
@@ -0,0 +1,4 @@
+707aac692b7478d2312a87b09228e437 *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
diff --git a/tests/ref/vsynth/vsynth1-h263 b/tests/ref/vsynth/vsynth1-h263
index d5916fa21d..53885bf2e8 100644
--- a/tests/ref/vsynth/vsynth1-h263
+++ b/tests/ref/vsynth/vsynth1-h263
@@ -1,4 +1,4 @@
-130ae384b6f12fd7d18979aa5371523a *tests/data/fate/vsynth1-h263.avi
-659674 tests/data/fate/vsynth1-h263.avi
-1a1ba9a3a63ec1a1a9585fded0a7c954 *tests/data/fate/vsynth1-h263.out.rawvideo
+0d94f4a01b959b21de8d351b092d3fd8 *tests/data/fate/vsynth1-h263.avi
+659678 tests/data/fate/vsynth1-h263.avi
+aef88517578fa7f53fe5159c4b6754ef *tests/data/fate/vsynth1-h263.out.rawvideo
stddev: 8.03 PSNR: 30.03 MAXDIFF: 103 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-h263-obmc b/tests/ref/vsynth/vsynth1-h263-obmc
index ca3d4bf9df..b7a267a8cb 100644
--- a/tests/ref/vsynth/vsynth1-h263-obmc
+++ b/tests/ref/vsynth/vsynth1-h263-obmc
@@ -1,4 +1,4 @@
-4e7faa9203abf55a492802d30a8d80ea *tests/data/fate/vsynth1-h263-obmc.avi
-657354 tests/data/fate/vsynth1-h263-obmc.avi
-eba1d733a0c4b71322a78f718f312599 *tests/data/fate/vsynth1-h263-obmc.out.rawvideo
+7dec64380f375e5118b66f3baaaa1e24 *tests/data/fate/vsynth1-h263-obmc.avi
+657320 tests/data/fate/vsynth1-h263-obmc.avi
+844f7ee27fa122e199fe20987b41a15c *tests/data/fate/vsynth1-h263-obmc.out.rawvideo
stddev: 8.16 PSNR: 29.89 MAXDIFF: 113 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-h263p b/tests/ref/vsynth/vsynth1-h263p
index 9e1765fb4b..ac3a660f1e 100644
--- a/tests/ref/vsynth/vsynth1-h263p
+++ b/tests/ref/vsynth/vsynth1-h263p
@@ -1,4 +1,4 @@
-b34c1a52bb504e702485d8d268dd1068 *tests/data/fate/vsynth1-h263p.avi
-2328336 tests/data/fate/vsynth1-h263p.avi
-9554cda00c3487ab3ffda2c3ea22fa2f *tests/data/fate/vsynth1-h263p.out.rawvideo
+7fbb9a42f7047643fa4e1d533bc61f57 *tests/data/fate/vsynth1-h263p.avi
+2328366 tests/data/fate/vsynth1-h263p.avi
+911330cb57c99c440234392be1588081 *tests/data/fate/vsynth1-h263p.out.rawvideo
stddev: 2.06 PSNR: 41.83 MAXDIFF: 20 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-huffyuv b/tests/ref/vsynth/vsynth1-huffyuv
index 246da192b4..6bf79442e4 100644
--- a/tests/ref/vsynth/vsynth1-huffyuv
+++ b/tests/ref/vsynth/vsynth1-huffyuv
@@ -1,4 +1,4 @@
-cd93849c8e9846490d8f950f1b2319d5 *tests/data/fate/vsynth1-huffyuv.avi
-7933788 tests/data/fate/vsynth1-huffyuv.avi
+9a89f73cb2e305c15dda99c99c39b9d1 *tests/data/fate/vsynth1-huffyuv.avi
+8876474 tests/data/fate/vsynth1-huffyuv.avi
c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-huffyuv.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-huffyuvbgr24 b/tests/ref/vsynth/vsynth1-huffyuvbgr24
new file mode 100644
index 0000000000..e4e7723cc0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-huffyuvbgr24
@@ -0,0 +1,4 @@
+54032b56a1727c1ad940d8c66d65169e *tests/data/fate/vsynth1-huffyuvbgr24.avi
+13196990 tests/data/fate/vsynth1-huffyuvbgr24.avi
+49c03ab1b73b7cd3cabc3c77a9479c9e *tests/data/fate/vsynth1-huffyuvbgr24.out.rawvideo
+stddev: 3.16 PSNR: 38.12 MAXDIFF: 50 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-huffyuvbgra b/tests/ref/vsynth/vsynth1-huffyuvbgra
new file mode 100644
index 0000000000..f4ea59b8ff
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-huffyuvbgra
@@ -0,0 +1,4 @@
+98e1f0bd1734cfb0eb0b442259a7de32 *tests/data/fate/vsynth1-huffyuvbgra.avi
+14464170 tests/data/fate/vsynth1-huffyuvbgra.avi
+49c03ab1b73b7cd3cabc3c77a9479c9e *tests/data/fate/vsynth1-huffyuvbgra.out.rawvideo
+stddev: 3.16 PSNR: 38.12 MAXDIFF: 50 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-jpeg2000 b/tests/ref/vsynth/vsynth1-jpeg2000
new file mode 100644
index 0000000000..d169cf668a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-jpeg2000
@@ -0,0 +1,4 @@
+ed9c45dc090a03c2eb9c35cf76e4d914 *tests/data/fate/vsynth1-jpeg2000.avi
+2306906 tests/data/fate/vsynth1-jpeg2000.avi
+1774b621bd92a53a24712cb77e9f0b28 *tests/data/fate/vsynth1-jpeg2000.out.rawvideo
+stddev: 5.37 PSNR: 33.52 MAXDIFF: 63 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-jpeg2000-97 b/tests/ref/vsynth/vsynth1-jpeg2000-97
new file mode 100644
index 0000000000..a8e9bf8d93
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-jpeg2000-97
@@ -0,0 +1,4 @@
+dfb35e733795195c6519ecc37e953931 *tests/data/fate/vsynth1-jpeg2000-97.avi
+2243136 tests/data/fate/vsynth1-jpeg2000-97.avi
+e1a095b40d7f6440f6c46f2995c4759c *tests/data/fate/vsynth1-jpeg2000-97.out.rawvideo
+stddev: 6.23 PSNR: 32.23 MAXDIFF: 75 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-jpegls b/tests/ref/vsynth/vsynth1-jpegls
index b54bd5d1f7..87372494e5 100644
--- a/tests/ref/vsynth/vsynth1-jpegls
+++ b/tests/ref/vsynth/vsynth1-jpegls
@@ -1,4 +1,4 @@
-f8acf917e24ea6c9200f2cdf99744ca9 *tests/data/fate/vsynth1-jpegls.avi
-9089800 tests/data/fate/vsynth1-jpegls.avi
-947cb24ec45a453348ae6fe3fa278071 *tests/data/fate/vsynth1-jpegls.out.rawvideo
-stddev: 2.85 PSNR: 39.03 MAXDIFF: 49 bytes: 7603200/ 7603200
+29cea344136c89ef4e9da29888f7bf34 *tests/data/fate/vsynth1-jpegls.avi
+9089804 tests/data/fate/vsynth1-jpegls.avi
+791e1fb999deb2e4156e2286d48c4ed1 *tests/data/fate/vsynth1-jpegls.out.rawvideo
+stddev: 2.84 PSNR: 39.04 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-ljpeg b/tests/ref/vsynth/vsynth1-ljpeg
index 702de39a8b..4e38aee3d0 100644
--- a/tests/ref/vsynth/vsynth1-ljpeg
+++ b/tests/ref/vsynth/vsynth1-ljpeg
@@ -1,4 +1,4 @@
-aed2be6710c0dddacfa410dff7ce7e79 *tests/data/fate/vsynth1-ljpeg.avi
-6312924 tests/data/fate/vsynth1-ljpeg.avi
+a9c92718692c7eb3fdce5041a6a21eb6 *tests/data/fate/vsynth1-ljpeg.avi
+6309482 tests/data/fate/vsynth1-ljpeg.avi
c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ljpeg.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mjpeg b/tests/ref/vsynth/vsynth1-mjpeg
index 3c6fb4b796..11de0207f6 100644
--- a/tests/ref/vsynth/vsynth1-mjpeg
+++ b/tests/ref/vsynth/vsynth1-mjpeg
@@ -1,4 +1,4 @@
-b3ff9a5a9699ceddfee9abbf1b06bb00 *tests/data/fate/vsynth1-mjpeg.avi
-1516128 tests/data/fate/vsynth1-mjpeg.avi
-c6ae81b5b896e4d05ff584311aebdb18 *tests/data/fate/vsynth1-mjpeg.out.rawvideo
+9ff18b19d12bb9bb2ed434a79f212888 *tests/data/fate/vsynth1-mjpeg.avi
+1515906 tests/data/fate/vsynth1-mjpeg.avi
+9a3b8169c251d19044f7087a95458c55 *tests/data/fate/vsynth1-mjpeg.out.rawvideo
stddev: 7.87 PSNR: 30.21 MAXDIFF: 63 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mjpeg-422 b/tests/ref/vsynth/vsynth1-mjpeg-422
new file mode 100644
index 0000000000..bd760a1c8d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-422
@@ -0,0 +1,4 @@
+3b19da06ffe23cb804bca7a9a86eb3d5 *tests/data/fate/vsynth1-mjpeg-422.avi
+1756304 tests/data/fate/vsynth1-mjpeg-422.avi
+c35eea486c6d72050f4848eab64032b5 *tests/data/fate/vsynth1-mjpeg-422.out.rawvideo
+stddev: 7.45 PSNR: 30.69 MAXDIFF: 63 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mjpeg-444 b/tests/ref/vsynth/vsynth1-mjpeg-444
new file mode 100644
index 0000000000..42a9be3278
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-444
@@ -0,0 +1,4 @@
+9591b754ca151f3802738840fa5c26c0 *tests/data/fate/vsynth1-mjpeg-444.avi
+1989784 tests/data/fate/vsynth1-mjpeg-444.avi
+313a4a76af13d5879ea4910107b7ea74 *tests/data/fate/vsynth1-mjpeg-444.out.rawvideo
+stddev: 7.37 PSNR: 30.77 MAXDIFF: 63 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mjpeg-trell b/tests/ref/vsynth/vsynth1-mjpeg-trell
new file mode 100644
index 0000000000..b97efcbf74
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mjpeg-trell
@@ -0,0 +1,4 @@
+03d14b3db6232f46c0d931477801a7a6 *tests/data/fate/vsynth1-mjpeg-trell.avi
+1454308 tests/data/fate/vsynth1-mjpeg-trell.avi
+218d4dc8086fdef15d5382e6ba97df0b *tests/data/fate/vsynth1-mjpeg-trell.out.rawvideo
+stddev: 7.71 PSNR: 30.39 MAXDIFF: 62 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg1 b/tests/ref/vsynth/vsynth1-mpeg1
index 5f3d703d68..902b201eb5 100644
--- a/tests/ref/vsynth/vsynth1-mpeg1
+++ b/tests/ref/vsynth/vsynth1-mpeg1
@@ -1,4 +1,4 @@
-1428744c6d5835f27506e69be4f837f4 *tests/data/fate/vsynth1-mpeg1.mpeg1video
-712006 tests/data/fate/vsynth1-mpeg1.mpeg1video
-58f0c332bf689117b57fa629a2bc0d2b *tests/data/fate/vsynth1-mpeg1.out.rawvideo
-stddev: 7.62 PSNR: 30.48 MAXDIFF: 84 bytes: 7603200/ 7603200
+746ae4adb7d1921800b9cc30257d7231 *tests/data/fate/vsynth1-mpeg1.mpeg1video
+711835 tests/data/fate/vsynth1-mpeg1.mpeg1video
+c126c7dd12e7161df192d253e3100475 *tests/data/fate/vsynth1-mpeg1.out.rawvideo
+stddev: 7.63 PSNR: 30.48 MAXDIFF: 84 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg1b b/tests/ref/vsynth/vsynth1-mpeg1b
index ddd9bef6c2..6d7afa4915 100644
--- a/tests/ref/vsynth/vsynth1-mpeg1b
+++ b/tests/ref/vsynth/vsynth1-mpeg1b
@@ -1,4 +1,4 @@
-777639666b449ab0a7ef260511e40532 *tests/data/fate/vsynth1-mpeg1b.mpeg1video
-1030337 tests/data/fate/vsynth1-mpeg1b.mpeg1video
-91a7fce732b34748e7bf753ebabe2483 *tests/data/fate/vsynth1-mpeg1b.out.rawvideo
+f99bb6797faddeb48863a49a244793fc *tests/data/fate/vsynth1-mpeg1b.mpeg1video
+1031387 tests/data/fate/vsynth1-mpeg1b.mpeg1video
+22289cbbeb1e40c5fd68dcc73a07d8f5 *tests/data/fate/vsynth1-mpeg1b.out.rawvideo
stddev: 6.30 PSNR: 32.13 MAXDIFF: 75 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2 b/tests/ref/vsynth/vsynth1-mpeg2
index d0baa0ac81..0f06f380cf 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2
+++ b/tests/ref/vsynth/vsynth1-mpeg2
@@ -1,4 +1,4 @@
-50c344f0e0e3c65001a68b2c899a283f *tests/data/fate/vsynth1-mpeg2.mpeg2video
-728104 tests/data/fate/vsynth1-mpeg2.mpeg2video
-b41ca49c1a02e66ce64d262e2cdaec15 *tests/data/fate/vsynth1-mpeg2.out.rawvideo
+89d9481c12d2342e256b322d317e81c4 *tests/data/fate/vsynth1-mpeg2.mpeg2video
+728400 tests/data/fate/vsynth1-mpeg2.mpeg2video
+66c2a14725ba0a6f1535b9a62768977b *tests/data/fate/vsynth1-mpeg2.out.rawvideo
stddev: 7.65 PSNR: 30.45 MAXDIFF: 84 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2-422 b/tests/ref/vsynth/vsynth1-mpeg2-422
index 1209e8879f..e936ba463e 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-422
+++ b/tests/ref/vsynth/vsynth1-mpeg2-422
@@ -1,4 +1,4 @@
-c2124749526d2d4d41398d52557fad1b *tests/data/fate/vsynth1-mpeg2-422.mpeg2video
-728260 tests/data/fate/vsynth1-mpeg2-422.mpeg2video
-eb7fe83ce09af2d79ec16577c9d44e3c *tests/data/fate/vsynth1-mpeg2-422.out.rawvideo
-stddev: 10.29 PSNR: 27.88 MAXDIFF: 168 bytes: 7603200/ 7603200
+6e135a1a27235a320311a932147846b4 *tests/data/fate/vsynth1-mpeg2-422.mpeg2video
+730780 tests/data/fate/vsynth1-mpeg2-422.mpeg2video
+0273cd8463d1fc115378748239951560 *tests/data/fate/vsynth1-mpeg2-422.out.rawvideo
+stddev: 10.27 PSNR: 27.90 MAXDIFF: 162 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2-idct-int b/tests/ref/vsynth/vsynth1-mpeg2-idct-int
index cc789bbc28..89356d060b 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-idct-int
+++ b/tests/ref/vsynth/vsynth1-mpeg2-idct-int
@@ -1,4 +1,4 @@
-d0cc23c61c4afcfdf0fea53b31c6df38 *tests/data/fate/vsynth1-mpeg2-idct-int.mpeg2video
-725728 tests/data/fate/vsynth1-mpeg2-idct-int.mpeg2video
+b63161625d83d39c9114c7018cac5e9b *tests/data/fate/vsynth1-mpeg2-idct-int.mpeg2video
+725668 tests/data/fate/vsynth1-mpeg2-idct-int.mpeg2video
8130f71a467315c9e7bd1a25a01dbb23 *tests/data/fate/vsynth1-mpeg2-idct-int.out.rawvideo
stddev: 7.65 PSNR: 30.45 MAXDIFF: 80 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2-ilace b/tests/ref/vsynth/vsynth1-mpeg2-ilace
index 81e43c5c92..b9144b67a2 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-ilace
+++ b/tests/ref/vsynth/vsynth1-mpeg2-ilace
@@ -1,4 +1,4 @@
-c8e27cddb2da4d76816c258b6e3d1fab *tests/data/fate/vsynth1-mpeg2-ilace.mpeg2video
-737533 tests/data/fate/vsynth1-mpeg2-ilace.mpeg2video
-97615390fdd69abfcbc7e02df863a7d2 *tests/data/fate/vsynth1-mpeg2-ilace.out.rawvideo
+a92e79aa97a2d6b3b48b6cd9ceee1701 *tests/data/fate/vsynth1-mpeg2-ilace.mpeg2video
+738127 tests/data/fate/vsynth1-mpeg2-ilace.mpeg2video
+d0f2fab8d3a3fb8bc67aca068447d2db *tests/data/fate/vsynth1-mpeg2-ilace.out.rawvideo
stddev: 7.67 PSNR: 30.43 MAXDIFF: 84 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd b/tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd
index 647525dbb1..392f9bb7f9 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd
+++ b/tests/ref/vsynth/vsynth1-mpeg2-ivlc-qprd
@@ -1,4 +1,4 @@
-ba08be2c6209f6b88be97e6fe74911db *tests/data/fate/vsynth1-mpeg2-ivlc-qprd.mpeg2video
-783612 tests/data/fate/vsynth1-mpeg2-ivlc-qprd.mpeg2video
-98eb9da15f880978e7f2ee1e7ce476ef *tests/data/fate/vsynth1-mpeg2-ivlc-qprd.out.rawvideo
-stddev: 10.07 PSNR: 28.06 MAXDIFF: 165 bytes: 7603200/ 7603200
+2e5882eeaaae088750d9854c93bbf68e *tests/data/fate/vsynth1-mpeg2-ivlc-qprd.mpeg2video
+783518 tests/data/fate/vsynth1-mpeg2-ivlc-qprd.mpeg2video
+0876d78f40971c5a8eb2367cbd27c5a6 *tests/data/fate/vsynth1-mpeg2-ivlc-qprd.out.rawvideo
+stddev: 10.07 PSNR: 28.07 MAXDIFF: 165 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2-thread b/tests/ref/vsynth/vsynth1-mpeg2-thread
index 1a479bcd90..5f750b914e 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-thread
+++ b/tests/ref/vsynth/vsynth1-mpeg2-thread
@@ -1,4 +1,4 @@
-c17bee51286e13b0c95a504391632087 *tests/data/fate/vsynth1-mpeg2-thread.mpeg2video
-801373 tests/data/fate/vsynth1-mpeg2-thread.mpeg2video
-d1658911ca83f5616c1d32abc40750de *tests/data/fate/vsynth1-mpeg2-thread.out.rawvideo
+b4026056b8b903c37f6adfe2cd2d1894 *tests/data/fate/vsynth1-mpeg2-thread.mpeg2video
+801214 tests/data/fate/vsynth1-mpeg2-thread.mpeg2video
+d433c9b07b40b0d6c4fd5426699efb7f *tests/data/fate/vsynth1-mpeg2-thread.out.rawvideo
stddev: 7.63 PSNR: 30.48 MAXDIFF: 110 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc b/tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc
index b211c94a9e..618125c541 100644
--- a/tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc
+++ b/tests/ref/vsynth/vsynth1-mpeg2-thread-ivlc
@@ -1,4 +1,4 @@
-9f3991d18d5dc5240ca61b158ce76521 *tests/data/fate/vsynth1-mpeg2-thread-ivlc.mpeg2video
-791833 tests/data/fate/vsynth1-mpeg2-thread-ivlc.mpeg2video
-d1658911ca83f5616c1d32abc40750de *tests/data/fate/vsynth1-mpeg2-thread-ivlc.out.rawvideo
+08310d12ac77af11a0ac564552322e08 *tests/data/fate/vsynth1-mpeg2-thread-ivlc.mpeg2video
+791673 tests/data/fate/vsynth1-mpeg2-thread-ivlc.mpeg2video
+d433c9b07b40b0d6c4fd5426699efb7f *tests/data/fate/vsynth1-mpeg2-thread-ivlc.out.rawvideo
stddev: 7.63 PSNR: 30.48 MAXDIFF: 110 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4 b/tests/ref/vsynth/vsynth1-mpeg4
index 38a7294a1a..4e9b4bd03a 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4
+++ b/tests/ref/vsynth/vsynth1-mpeg4
@@ -1,4 +1,4 @@
-dc927acd770e19a97456ecbd4d786938 *tests/data/fate/vsynth1-mpeg4.mp4
-540180 tests/data/fate/vsynth1-mpeg4.mp4
-8828a375448dc5c2215163ba70656f89 *tests/data/fate/vsynth1-mpeg4.out.rawvideo
+b4e8871c504a22c8c874c7e845b73da7 *tests/data/fate/vsynth1-mpeg4.mp4
+540085 tests/data/fate/vsynth1-mpeg4.mp4
+f80ec173d37f2f91add031e95579a220 *tests/data/fate/vsynth1-mpeg4.out.rawvideo
stddev: 7.97 PSNR: 30.10 MAXDIFF: 105 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-adap b/tests/ref/vsynth/vsynth1-mpeg4-adap
index 840eb475f6..e6bd6a59bd 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-adap
+++ b/tests/ref/vsynth/vsynth1-mpeg4-adap
@@ -1,4 +1,4 @@
-eb70136b050f0b216febe57e7766b6a8 *tests/data/fate/vsynth1-mpeg4-adap.avi
-403444 tests/data/fate/vsynth1-mpeg4-adap.avi
-fa2049396479b5f170aa764fed5b2a31 *tests/data/fate/vsynth1-mpeg4-adap.out.rawvideo
+f120f0bf976bb510c5b5305fe7d8159a *tests/data/fate/vsynth1-mpeg4-adap.avi
+403436 tests/data/fate/vsynth1-mpeg4-adap.avi
+fad0b9dc08fe4a95b297af1a7411c1e9 *tests/data/fate/vsynth1-mpeg4-adap.out.rawvideo
stddev: 14.05 PSNR: 25.17 MAXDIFF: 184 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-adv b/tests/ref/vsynth/vsynth1-mpeg4-adv
index 8ca1f2f1e8..f45077912e 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-adv
+++ b/tests/ref/vsynth/vsynth1-mpeg4-adv
@@ -1,4 +1,4 @@
-c67ccefff2a038c1a149eceef8b08d1e *tests/data/fate/vsynth1-mpeg4-adv.avi
-589704 tests/data/fate/vsynth1-mpeg4-adv.avi
-f8b226876b1b2c0b98fd6928fd9adbd8 *tests/data/fate/vsynth1-mpeg4-adv.out.rawvideo
+0700d773f269babdaea4c6c71a3d7876 *tests/data/fate/vsynth1-mpeg4-adv.avi
+589708 tests/data/fate/vsynth1-mpeg4-adv.avi
+b651bd94456005a1990fb64c28306262 *tests/data/fate/vsynth1-mpeg4-adv.out.rawvideo
stddev: 6.98 PSNR: 31.25 MAXDIFF: 84 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-error b/tests/ref/vsynth/vsynth1-mpeg4-error
index 918091173d..b3b8d66e49 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-error
+++ b/tests/ref/vsynth/vsynth1-mpeg4-error
@@ -1,4 +1,4 @@
-63fdc6877c299fe94a061e276ca77bad *tests/data/fate/vsynth1-mpeg4-error.avi
-756824 tests/data/fate/vsynth1-mpeg4-error.avi
-79e94ba32b37759397362cbcb479d4d3 *tests/data/fate/vsynth1-mpeg4-error.out.rawvideo
-stddev: 18.36 PSNR: 22.85 MAXDIFF: 243 bytes: 7603200/ 7603200
+d23ad508e15bf6af8de8799c59acd6dc *tests/data/fate/vsynth1-mpeg4-error.avi
+752350 tests/data/fate/vsynth1-mpeg4-error.avi
+5853c8c789f260ae4dcbf37a17d04b66 *tests/data/fate/vsynth1-mpeg4-error.out.rawvideo
+stddev: 17.33 PSNR: 23.35 MAXDIFF: 229 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-nr b/tests/ref/vsynth/vsynth1-mpeg4-nr
index 28f8c6a9cd..94b5b4fa2f 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-nr
+++ b/tests/ref/vsynth/vsynth1-mpeg4-nr
@@ -1,4 +1,4 @@
-d9eabca19ca600f18539b35a94663603 *tests/data/fate/vsynth1-mpeg4-nr.avi
-675626 tests/data/fate/vsynth1-mpeg4-nr.avi
-d2b89d5958fb7331f6c9e5b7ecaaa5b6 *tests/data/fate/vsynth1-mpeg4-nr.out.rawvideo
-stddev: 6.99 PSNR: 31.23 MAXDIFF: 86 bytes: 7603200/ 7603200
+793b77835fe8073bba19a22e9039d6e1 *tests/data/fate/vsynth1-mpeg4-nr.avi
+675456 tests/data/fate/vsynth1-mpeg4-nr.avi
+5fee518cde41e5567f800fbe14210fb8 *tests/data/fate/vsynth1-mpeg4-nr.out.rawvideo
+stddev: 6.99 PSNR: 31.24 MAXDIFF: 86 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-nsse b/tests/ref/vsynth/vsynth1-mpeg4-nsse
new file mode 100644
index 0000000000..48cc851518
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mpeg4-nsse
@@ -0,0 +1,4 @@
+1c2eac81a7768afe8dba1df85e977aec *tests/data/fate/vsynth1-mpeg4-nsse.avi
+886846 tests/data/fate/vsynth1-mpeg4-nsse.avi
+a987cb2e49284ea83174e3a2c6527173 *tests/data/fate/vsynth1-mpeg4-nsse.out.rawvideo
+stddev: 6.00 PSNR: 32.57 MAXDIFF: 73 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-qpel b/tests/ref/vsynth/vsynth1-mpeg4-qpel
index 1ff1dceafb..f845542a42 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-qpel
+++ b/tests/ref/vsynth/vsynth1-mpeg4-qpel
@@ -1,4 +1,4 @@
-c02be5680307d8f97a2f442d27f48f3c *tests/data/fate/vsynth1-mpeg4-qpel.avi
-860666 tests/data/fate/vsynth1-mpeg4-qpel.avi
-756928496245ecc701f79eebeec8e5e6 *tests/data/fate/vsynth1-mpeg4-qpel.out.rawvideo
-stddev: 5.63 PSNR: 33.12 MAXDIFF: 70 bytes: 7603200/ 7603200
+cb55178feaf790db7bca758708f989dd *tests/data/fate/vsynth1-mpeg4-qpel.avi
+858684 tests/data/fate/vsynth1-mpeg4-qpel.avi
+5089090df7169eb482532df5471d7f5f *tests/data/fate/vsynth1-mpeg4-qpel.out.rawvideo
+stddev: 5.63 PSNR: 33.11 MAXDIFF: 70 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-qprd b/tests/ref/vsynth/vsynth1-mpeg4-qprd
index 0b2892dfc8..d5c75ab92c 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-qprd
+++ b/tests/ref/vsynth/vsynth1-mpeg4-qprd
@@ -1,4 +1,4 @@
-5a95ba2c240fcb28963fe90fba4ce52b *tests/data/fate/vsynth1-mpeg4-qprd.avi
-710932 tests/data/fate/vsynth1-mpeg4-qprd.avi
-e65f4c7f343fe2bad1cac44b7da5f7c4 *tests/data/fate/vsynth1-mpeg4-qprd.out.rawvideo
+14612d85cd7f77de7b5e6345240535ba *tests/data/fate/vsynth1-mpeg4-qprd.avi
+710676 tests/data/fate/vsynth1-mpeg4-qprd.avi
+693231ac7e6fbf8758415f9f2509408d *tests/data/fate/vsynth1-mpeg4-qprd.out.rawvideo
stddev: 9.79 PSNR: 28.31 MAXDIFF: 176 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-rc b/tests/ref/vsynth/vsynth1-mpeg4-rc
index 0c2abf3e71..5b1d7ff1e3 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-rc
+++ b/tests/ref/vsynth/vsynth1-mpeg4-rc
@@ -1,4 +1,4 @@
-49ac6ed095ea2dccf53737e6beab7ad7 *tests/data/fate/vsynth1-mpeg4-rc.avi
-830148 tests/data/fate/vsynth1-mpeg4-rc.avi
-4d95e340db9bc57a559162c039f3784e *tests/data/fate/vsynth1-mpeg4-rc.out.rawvideo
+91c127f2acc04f51e0e62bcf0752e064 *tests/data/fate/vsynth1-mpeg4-rc.avi
+830498 tests/data/fate/vsynth1-mpeg4-rc.avi
+9dcd9d022ae14fe1e4a53aa4865464c6 *tests/data/fate/vsynth1-mpeg4-rc.out.rawvideo
stddev: 10.24 PSNR: 27.92 MAXDIFF: 196 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpeg4-thread b/tests/ref/vsynth/vsynth1-mpeg4-thread
index b0bf7d88fe..6b69fb4c12 100644
--- a/tests/ref/vsynth/vsynth1-mpeg4-thread
+++ b/tests/ref/vsynth/vsynth1-mpeg4-thread
@@ -1,4 +1,4 @@
-c081bc20f1eb048626ea783d8b08a531 *tests/data/fate/vsynth1-mpeg4-thread.avi
-774748 tests/data/fate/vsynth1-mpeg4-thread.avi
-64b96cddf5301990e118978b3a3bcd0d *tests/data/fate/vsynth1-mpeg4-thread.out.rawvideo
+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
stddev: 10.13 PSNR: 28.02 MAXDIFF: 183 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-mpng b/tests/ref/vsynth/vsynth1-mpng
new file mode 100644
index 0000000000..9b394d7629
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-mpng
@@ -0,0 +1,4 @@
+6a27410a07ed1c5556e15b7a7c6a586d *tests/data/fate/vsynth1-mpng.avi
+12158280 tests/data/fate/vsynth1-mpng.avi
+93695a27c24a61105076ca7b1f010bbd *tests/data/fate/vsynth1-mpng.out.rawvideo
+stddev: 3.42 PSNR: 37.44 MAXDIFF: 48 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-msmpeg4 b/tests/ref/vsynth/vsynth1-msmpeg4
index cd1b6db036..7ff497415f 100644
--- a/tests/ref/vsynth/vsynth1-msmpeg4
+++ b/tests/ref/vsynth/vsynth1-msmpeg4
@@ -1,4 +1,4 @@
-c1d04df31764c0ca281dc6fe023287fb *tests/data/fate/vsynth1-msmpeg4.avi
+3957ca57ac97f651c828ab00d8f0e088 *tests/data/fate/vsynth1-msmpeg4.avi
624706 tests/data/fate/vsynth1-msmpeg4.avi
-5ca72c39e3fc5df8e62f223c869589f5 *tests/data/fate/vsynth1-msmpeg4.out.rawvideo
+4529fee96b8073e02974f5355e5f6c4e *tests/data/fate/vsynth1-msmpeg4.out.rawvideo
stddev: 7.98 PSNR: 30.09 MAXDIFF: 104 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-msmpeg4v2 b/tests/ref/vsynth/vsynth1-msmpeg4v2
index fb9862c0e0..514ca99d3e 100644
--- a/tests/ref/vsynth/vsynth1-msmpeg4v2
+++ b/tests/ref/vsynth/vsynth1-msmpeg4v2
@@ -1,4 +1,4 @@
-48c76c638b43ee53bde9c58185b25e80 *tests/data/fate/vsynth1-msmpeg4v2.avi
-623776 tests/data/fate/vsynth1-msmpeg4v2.avi
-c6ff1041a0ef62c2a2e5ef519e5e94c4 *tests/data/fate/vsynth1-msmpeg4v2.out.rawvideo
+d13c6aaf0d3842d3e50cc96574572f6f *tests/data/fate/vsynth1-msmpeg4v2.avi
+623770 tests/data/fate/vsynth1-msmpeg4v2.avi
+0476d9aafc4358654f411fa9648f9560 *tests/data/fate/vsynth1-msmpeg4v2.out.rawvideo
stddev: 7.97 PSNR: 30.10 MAXDIFF: 105 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-msvideo1 b/tests/ref/vsynth/vsynth1-msvideo1
new file mode 100644
index 0000000000..e7435a97ad
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-msvideo1
@@ -0,0 +1,4 @@
+41c8ec9813bb32831c4cf279677e631b *tests/data/fate/vsynth1-msvideo1.avi
+2051896 tests/data/fate/vsynth1-msvideo1.avi
+f4605ac6df556a3ca7053c49aaac04d8 *tests/data/fate/vsynth1-msvideo1.out.rawvideo
+stddev: 11.89 PSNR: 26.62 MAXDIFF: 159 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-prores b/tests/ref/vsynth/vsynth1-prores
index 12aa7582c8..14de8b9cf3 100644
--- a/tests/ref/vsynth/vsynth1-prores
+++ b/tests/ref/vsynth/vsynth1-prores
@@ -1,4 +1,4 @@
-7dfcca40f50ff1d72541bc095c904784 *tests/data/fate/vsynth1-prores.mov
-3859037 tests/data/fate/vsynth1-prores.mov
-0a4153637d0cc0a88a8bcbf04cfaf8c6 *tests/data/fate/vsynth1-prores.out.rawvideo
-stddev: 3.17 PSNR: 38.09 MAXDIFF: 39 bytes: 7603200/ 7603200
+7ca7d2f9f5d8ac2ead691b1b6a70d409 *tests/data/fate/vsynth1-prores.mov
+5022821 tests/data/fate/vsynth1-prores.mov
+fb4a9e025d12afc0dbbca8d82831858f *tests/data/fate/vsynth1-prores.out.rawvideo
+stddev: 2.47 PSNR: 40.27 MAXDIFF: 31 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-prores_ks b/tests/ref/vsynth/vsynth1-prores_ks
new file mode 100644
index 0000000000..6e5ed172b2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-prores_ks
@@ -0,0 +1,4 @@
+fe41a284da97ea5ec8866ca9a55b84da *tests/data/fate/vsynth1-prores_ks.mov
+3858911 tests/data/fate/vsynth1-prores_ks.mov
+100eb002413fe7a632d440dfbdf7e3ff *tests/data/fate/vsynth1-prores_ks.out.rawvideo
+stddev: 3.17 PSNR: 38.09 MAXDIFF: 39 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-qtrle b/tests/ref/vsynth/vsynth1-qtrle
index 4ddd1d8a2a..4b920815ce 100644
--- a/tests/ref/vsynth/vsynth1-qtrle
+++ b/tests/ref/vsynth/vsynth1-qtrle
@@ -1,4 +1,4 @@
-24650c5b226d054c57be7c06c9220058 *tests/data/fate/vsynth1-qtrle.mov
-15263232 tests/data/fate/vsynth1-qtrle.mov
-243325fb2cae1a9245efd49aff936327 *tests/data/fate/vsynth1-qtrle.out.rawvideo
-stddev: 3.42 PSNR: 37.43 MAXDIFF: 48 bytes: 7603200/ 7603200
+35d8a1446d886fadcdffae192bed7e4e *tests/data/fate/vsynth1-qtrle.mov
+15263158 tests/data/fate/vsynth1-qtrle.mov
+93695a27c24a61105076ca7b1f010bbd *tests/data/fate/vsynth1-qtrle.out.rawvideo
+stddev: 3.42 PSNR: 37.44 MAXDIFF: 48 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-qtrlegray b/tests/ref/vsynth/vsynth1-qtrlegray
new file mode 100644
index 0000000000..c3d571d92b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-qtrlegray
@@ -0,0 +1,4 @@
+651b745a37a06ddd52adfe8e0a45b115 *tests/data/fate/vsynth1-qtrlegray.mov
+5113293 tests/data/fate/vsynth1-qtrlegray.mov
+cb20af0e5a65aad7cf47002fcb52288e *tests/data/fate/vsynth1-qtrlegray.out.rawvideo
+stddev: 25.34 PSNR: 20.05 MAXDIFF: 122 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-r210 b/tests/ref/vsynth/vsynth1-r210
new file mode 100644
index 0000000000..e25b1de6d2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-r210
@@ -0,0 +1,4 @@
+fd2bb8b3d3e47f5ea7769443324ee0ae *tests/data/fate/vsynth1-r210.avi
+22125252 tests/data/fate/vsynth1-r210.avi
+ecaafa9eec11b5e1453a63ed6d194eed *tests/data/fate/vsynth1-r210.out.rawvideo
+stddev: 3.23 PSNR: 37.94 MAXDIFF: 48 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-rgb b/tests/ref/vsynth/vsynth1-rgb
index f72b737adb..0a3947c7eb 100644
--- a/tests/ref/vsynth/vsynth1-rgb
+++ b/tests/ref/vsynth/vsynth1-rgb
@@ -1,4 +1,4 @@
-d78bcd5828862c3342388ec8a2c34fef *tests/data/fate/vsynth1-rgb.avi
-15213248 tests/data/fate/vsynth1-rgb.avi
-243325fb2cae1a9245efd49aff936327 *tests/data/fate/vsynth1-rgb.out.rawvideo
-stddev: 3.42 PSNR: 37.43 MAXDIFF: 48 bytes: 7603200/ 7603200
+c8a4b8648436e73ced7fe32f6f65a1b3 *tests/data/fate/vsynth1-rgb.avi
+15213252 tests/data/fate/vsynth1-rgb.avi
+93695a27c24a61105076ca7b1f010bbd *tests/data/fate/vsynth1-rgb.out.rawvideo
+stddev: 3.42 PSNR: 37.44 MAXDIFF: 48 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-roqvideo b/tests/ref/vsynth/vsynth1-roqvideo
index 5adba69490..2cca94224b 100644
--- a/tests/ref/vsynth/vsynth1-roqvideo
+++ b/tests/ref/vsynth/vsynth1-roqvideo
@@ -1,4 +1,4 @@
-cf8b7b0e539bab3169c234ca63d71dd8 *tests/data/fate/vsynth1-roqvideo.roq
-101671 tests/data/fate/vsynth1-roqvideo.roq
-0ad983c291b1ed373645c5b12a108c61 *tests/data/fate/vsynth1-roqvideo.out.rawvideo
-stddev: 7.74 PSNR: 30.35 MAXDIFF: 89 bytes: 7603200/ 760320
+8037e62b2707a246e787bb1723b752b9 *tests/data/fate/vsynth1-roqvideo.roq
+102571 tests/data/fate/vsynth1-roqvideo.roq
+9e3bb47e5e9708392d7eba8f944b6920 *tests/data/fate/vsynth1-roqvideo.out.rawvideo
+stddev: 7.75 PSNR: 30.34 MAXDIFF: 88 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth1-rv10 b/tests/ref/vsynth/vsynth1-rv10
index 234015f46d..d414bd68d1 100644
--- a/tests/ref/vsynth/vsynth1-rv10
+++ b/tests/ref/vsynth/vsynth1-rv10
@@ -1,4 +1,4 @@
-4d7e82de72a83905cf84b8abc3e70b8f *tests/data/fate/vsynth1-rv10.rm
-653905 tests/data/fate/vsynth1-rv10.rm
-1a1ba9a3a63ec1a1a9585fded0a7c954 *tests/data/fate/vsynth1-rv10.out.rawvideo
+5ef46004d474669d19ad06133a1cf137 *tests/data/fate/vsynth1-rv10.rm
+653907 tests/data/fate/vsynth1-rv10.rm
+aef88517578fa7f53fe5159c4b6754ef *tests/data/fate/vsynth1-rv10.out.rawvideo
stddev: 8.03 PSNR: 30.03 MAXDIFF: 103 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-rv20 b/tests/ref/vsynth/vsynth1-rv20
index abcc4a1f7a..5b3310a51a 100644
--- a/tests/ref/vsynth/vsynth1-rv20
+++ b/tests/ref/vsynth/vsynth1-rv20
@@ -1,4 +1,4 @@
-81868601e602eee5b6d80f5ece4aaa98 *tests/data/fate/vsynth1-rv20.rm
-646016 tests/data/fate/vsynth1-rv20.rm
-b45fdb0201b06f7649f44050e262c54c *tests/data/fate/vsynth1-rv20.out.rawvideo
+0f04eec24aaa8ea06eafc58082c2e2ef *tests/data/fate/vsynth1-rv20.rm
+646019 tests/data/fate/vsynth1-rv20.rm
+3f55bcfb3c672d74f0fa64aa90aa0395 *tests/data/fate/vsynth1-rv20.out.rawvideo
stddev: 8.26 PSNR: 29.79 MAXDIFF: 103 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-snow b/tests/ref/vsynth/vsynth1-snow
new file mode 100644
index 0000000000..f20abd2ee4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-snow
@@ -0,0 +1,4 @@
+67c10f8d52fcd1103caa675a1408bf6e *tests/data/fate/vsynth1-snow.avi
+136088 tests/data/fate/vsynth1-snow.avi
+bfc0bcc4bc7b956933aa58acc587018d *tests/data/fate/vsynth1-snow.out.rawvideo
+stddev: 22.77 PSNR: 20.98 MAXDIFF: 175 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-snow-hpel b/tests/ref/vsynth/vsynth1-snow-hpel
new file mode 100644
index 0000000000..39780ad8a2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-snow-hpel
@@ -0,0 +1,4 @@
+e62ae25d5040d04622a965bcb27fdb1e *tests/data/fate/vsynth1-snow-hpel.avi
+138446 tests/data/fate/vsynth1-snow-hpel.avi
+57c914cd150f8fc260b5989ce3e5884c *tests/data/fate/vsynth1-snow-hpel.out.rawvideo
+stddev: 22.74 PSNR: 20.99 MAXDIFF: 172 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-snow-ll b/tests/ref/vsynth/vsynth1-snow-ll
new file mode 100644
index 0000000000..ca5007fefb
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-snow-ll
@@ -0,0 +1,4 @@
+47690bd6f32d8f5ce11b9f6e7f090be2 *tests/data/fate/vsynth1-snow-ll.avi
+3419972 tests/data/fate/vsynth1-snow-ll.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-snow-ll.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-svq1 b/tests/ref/vsynth/vsynth1-svq1
index f610fdc1ce..9c1b6ff7ac 100644
--- a/tests/ref/vsynth/vsynth1-svq1
+++ b/tests/ref/vsynth/vsynth1-svq1
@@ -1,4 +1,4 @@
-3c90c6c0c4db7993660cee642de05bb4 *tests/data/fate/vsynth1-svq1.mov
-1334367 tests/data/fate/vsynth1-svq1.mov
+a3206831d34197a2d236d82dd0248646 *tests/data/fate/vsynth1-svq1.mov
+1334233 tests/data/fate/vsynth1-svq1.mov
9cc35c54b2c77d36bd7e308b393c1f81 *tests/data/fate/vsynth1-svq1.out.rawvideo
stddev: 9.58 PSNR: 28.50 MAXDIFF: 210 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-v210 b/tests/ref/vsynth/vsynth1-v210
index e2f4588c54..388e8b6688 100644
--- a/tests/ref/vsynth/vsynth1-v210
+++ b/tests/ref/vsynth/vsynth1-v210
@@ -1,4 +1,4 @@
-a38de84bfef53ed69204480c979dd6c4 *tests/data/fate/vsynth1-v210.avi
-14752448 tests/data/fate/vsynth1-v210.avi
+0712d60b3a00cf2d5a7e39aa21e2547a *tests/data/fate/vsynth1-v210.avi
+14752452 tests/data/fate/vsynth1-v210.avi
2ba7f4ca302f3c4147860b9dfb12b6e4 *tests/data/fate/vsynth1-v210.out.rawvideo
stddev: 1.84 PSNR: 42.81 MAXDIFF: 29 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-v308 b/tests/ref/vsynth/vsynth1-v308
new file mode 100644
index 0000000000..9eb2911006
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-v308
@@ -0,0 +1,4 @@
+58ea26d3060f9d47cf95056ed9361c90 *tests/data/fate/vsynth1-v308.avi
+15213252 tests/data/fate/vsynth1-v308.avi
+10fb42f1abf40a289c3edafc0390482c *tests/data/fate/vsynth1-v308.out.rawvideo
+stddev: 2.67 PSNR: 39.60 MAXDIFF: 43 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-v408 b/tests/ref/vsynth/vsynth1-v408
new file mode 100644
index 0000000000..bf16cbd489
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-v408
@@ -0,0 +1,4 @@
+4ac68e91ac25bc422abb3febe86a4acd *tests/data/fate/vsynth1-v408.avi
+20282052 tests/data/fate/vsynth1-v408.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-v408.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-wmv1 b/tests/ref/vsynth/vsynth1-wmv1
index 78bd0f03ea..8603ba2fa0 100644
--- a/tests/ref/vsynth/vsynth1-wmv1
+++ b/tests/ref/vsynth/vsynth1-wmv1
@@ -1,4 +1,4 @@
-5f896b2c7d6a0906f5252a5088fbc64a *tests/data/fate/vsynth1-wmv1.avi
-626896 tests/data/fate/vsynth1-wmv1.avi
-5182edba5b5e0354b39ce4f3604b62da *tests/data/fate/vsynth1-wmv1.out.rawvideo
+871a92dc2fe36ca94211830160f9f406 *tests/data/fate/vsynth1-wmv1.avi
+626874 tests/data/fate/vsynth1-wmv1.avi
+3354066ebdd8cd8098394be2384744e7 *tests/data/fate/vsynth1-wmv1.out.rawvideo
stddev: 7.97 PSNR: 30.09 MAXDIFF: 110 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-wmv2 b/tests/ref/vsynth/vsynth1-wmv2
index 6a3cd3be78..4039d86b24 100644
--- a/tests/ref/vsynth/vsynth1-wmv2
+++ b/tests/ref/vsynth/vsynth1-wmv2
@@ -1,4 +1,4 @@
-3c8a93fa645574f5b11eb51cf0efd227 *tests/data/fate/vsynth1-wmv2.avi
-659162 tests/data/fate/vsynth1-wmv2.avi
-2d61f24836d54766e8d370f243d83dcd *tests/data/fate/vsynth1-wmv2.out.rawvideo
+be5c5985d7f4d5b7797aeb0c825bf4f8 *tests/data/fate/vsynth1-wmv2.avi
+659142 tests/data/fate/vsynth1-wmv2.avi
+8a6061ef825e79d887705db656d51247 *tests/data/fate/vsynth1-wmv2.out.rawvideo
stddev: 7.97 PSNR: 30.09 MAXDIFF: 105 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-xface b/tests/ref/vsynth/vsynth1-xface
new file mode 100644
index 0000000000..3b916c669a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-xface
@@ -0,0 +1,4 @@
+487c3e53249f7b9f16e04257295998de *tests/data/fate/vsynth1-xface.nut
+19746 tests/data/fate/vsynth1-xface.nut
+42d8261bb538b8789840ac085f7fc4d2 *tests/data/fate/vsynth1-xface.out.rawvideo
+stddev: 103.88 PSNR: 7.80 MAXDIFF: 254 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-y41p b/tests/ref/vsynth/vsynth1-y41p
new file mode 100644
index 0000000000..cb4c001f09
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-y41p
@@ -0,0 +1,4 @@
+862ffddd90c82163d2505031e5bbcd9a *tests/data/fate/vsynth1-y41p.avi
+7610052 tests/data/fate/vsynth1-y41p.avi
+3aef1d83732a3f9835ee2523a11c95c1 *tests/data/fate/vsynth1-y41p.out.rawvideo
+stddev: 5.98 PSNR: 32.59 MAXDIFF: 87 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-yuv b/tests/ref/vsynth/vsynth1-yuv
index 3db5ab0891..8498d68e6a 100644
--- a/tests/ref/vsynth/vsynth1-yuv
+++ b/tests/ref/vsynth/vsynth1-yuv
@@ -1,4 +1,4 @@
-a9c708ba20f5c562fb1c89f6aa841c8c *tests/data/fate/vsynth1-yuv.avi
-7610048 tests/data/fate/vsynth1-yuv.avi
+2b930d809c19e8d50eb4c92474085c27 *tests/data/fate/vsynth1-yuv.avi
+7610052 tests/data/fate/vsynth1-yuv.avi
c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-yuv.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-yuv4 b/tests/ref/vsynth/vsynth1-yuv4
new file mode 100644
index 0000000000..22ba3b0c9d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-yuv4
@@ -0,0 +1,4 @@
+71d07cf8dd5631f8669294aa86db363e *tests/data/fate/vsynth1-yuv4.avi
+7610052 tests/data/fate/vsynth1-yuv4.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-yuv4.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-zlib b/tests/ref/vsynth/vsynth1-zlib
new file mode 100644
index 0000000000..419c6a6b3a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-zlib
@@ -0,0 +1,4 @@
+fd44e7bf6322f4be46f4f0dada728849 *tests/data/fate/vsynth1-zlib.avi
+12108636 tests/data/fate/vsynth1-zlib.avi
+93695a27c24a61105076ca7b1f010bbd *tests/data/fate/vsynth1-zlib.out.rawvideo
+stddev: 3.42 PSNR: 37.44 MAXDIFF: 48 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth1-zmbv b/tests/ref/vsynth/vsynth1-zmbv
new file mode 100644
index 0000000000..c608c4bb36
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-zmbv
@@ -0,0 +1,4 @@
+09bae55394f86ddb9e5c3254b174f865 *tests/data/fate/vsynth1-zmbv.avi
+2285442 tests/data/fate/vsynth1-zmbv.avi
+4ad1ca9de7c65eab68a619c54fffaec8 *tests/data/fate/vsynth1-zmbv.out.rawvideo
+stddev: 8.61 PSNR: 29.43 MAXDIFF: 64 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-amv b/tests/ref/vsynth/vsynth2-amv
new file mode 100644
index 0000000000..088b5ce143
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-amv
@@ -0,0 +1,4 @@
+a77c55410820d0e0883c76f557774bcf *tests/data/fate/vsynth2-amv.avi
+912552 tests/data/fate/vsynth2-amv.avi
+5b7fe07a366b176e35d2564ecf95ebe9 *tests/data/fate/vsynth2-amv.out.rawvideo
+stddev: 4.91 PSNR: 34.31 MAXDIFF: 71 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-asv1 b/tests/ref/vsynth/vsynth2-asv1
index de8892fcc1..a466ec0927 100644
--- a/tests/ref/vsynth/vsynth2-asv1
+++ b/tests/ref/vsynth/vsynth2-asv1
@@ -1,4 +1,4 @@
-50f5bba0ab3f7ebe687619368b20d29a *tests/data/fate/vsynth2-asv1.avi
-1008588 tests/data/fate/vsynth2-asv1.avi
-bd8e5390a51f062d3ec9545fc93e7ca2 *tests/data/fate/vsynth2-asv1.out.rawvideo
-stddev: 12.39 PSNR: 26.26 MAXDIFF: 110 bytes: 7603200/ 7603200
+375a52cafcd2b2d7bd2fc2841e945bf8 *tests/data/fate/vsynth2-asv1.avi
+836556 tests/data/fate/vsynth2-asv1.avi
+da15fb1affc65904161dc37eff4cdc7a *tests/data/fate/vsynth2-asv1.out.rawvideo
+stddev: 5.78 PSNR: 32.88 MAXDIFF: 75 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-asv2 b/tests/ref/vsynth/vsynth2-asv2
index b7a8f1345d..d4bb4c82d0 100644
--- a/tests/ref/vsynth/vsynth2-asv2
+++ b/tests/ref/vsynth/vsynth2-asv2
@@ -1,4 +1,4 @@
-fc746339bb82e299d14049ea8c7e9a4e *tests/data/fate/vsynth2-asv2.avi
-956832 tests/data/fate/vsynth2-asv2.avi
-4b3fe82b31221ac2b0f292760017668f *tests/data/fate/vsynth2-asv2.out.rawvideo
-stddev: 12.19 PSNR: 26.41 MAXDIFF: 111 bytes: 7603200/ 7603200
+ad6e4a2adf55b04ba42bea1db19d360f *tests/data/fate/vsynth2-asv2.avi
+822232 tests/data/fate/vsynth2-asv2.avi
+15329433bcccfb9ca874d949423cef47 *tests/data/fate/vsynth2-asv2.out.rawvideo
+stddev: 5.13 PSNR: 33.92 MAXDIFF: 50 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-avui b/tests/ref/vsynth/vsynth2-avui
new file mode 100644
index 0000000000..2423916f4d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-avui
@@ -0,0 +1,4 @@
+8f6ab410bb6b5dc4599e12968dbd0366 *tests/data/fate/vsynth2-avui.mov
+42625037 tests/data/fate/vsynth2-avui.mov
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-avui.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-cinepak b/tests/ref/vsynth/vsynth2-cinepak
new file mode 100644
index 0000000000..18eb1d59a8
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-cinepak
@@ -0,0 +1,4 @@
+cc0879f1993cdd6231e2c3b9c2c015a0 *tests/data/fate/vsynth2-cinepak.mov
+88400 tests/data/fate/vsynth2-cinepak.mov
+12c480911ebb89762dc49af003b176c7 *tests/data/fate/vsynth2-cinepak.out.rawvideo
+stddev: 5.07 PSNR: 34.02 MAXDIFF: 59 bytes: 7603200/ 456192
diff --git a/tests/ref/vsynth/vsynth2-cljr b/tests/ref/vsynth/vsynth2-cljr
index b372fa43d7..e3d02c9bb4 100644
--- a/tests/ref/vsynth/vsynth2-cljr
+++ b/tests/ref/vsynth/vsynth2-cljr
@@ -1,4 +1,4 @@
-624a1bcef30a52b39f616d73ded8bb30 *tests/data/fate/vsynth2-cljr.avi
-5075648 tests/data/fate/vsynth2-cljr.avi
-273b2f8fb471602a683049f91f7c4cbb *tests/data/fate/vsynth2-cljr.out.rawvideo
-stddev: 3.69 PSNR: 36.79 MAXDIFF: 36 bytes: 7603200/ 7603200
+4ccffc9ea4a5e260b9867b03d127f85c *tests/data/fate/vsynth2-cljr.avi
+5075652 tests/data/fate/vsynth2-cljr.avi
+14e64b6e6c1d7fdefbb111920911f301 *tests/data/fate/vsynth2-cljr.out.rawvideo
+stddev: 3.34 PSNR: 37.65 MAXDIFF: 37 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i b/tests/ref/vsynth/vsynth2-dnxhd-1080i
index 4a4424b6ab..c3a5073df3 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-1080i
+++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i
@@ -1,4 +1,4 @@
-1bc9fe8d89bae57ed54ae4d5b5262209 *tests/data/fate/vsynth2-dnxhd-1080i.mov
-3031875 tests/data/fate/vsynth2-dnxhd-1080i.mov
-da7f9fbf6034c3a99a1467e77dd62f6b *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo
+2b75889122f8d918e1b068d128b618ca *tests/data/fate/vsynth2-dnxhd-1080i.mov
+3031911 tests/data/fate/vsynth2-dnxhd-1080i.mov
+099001db73036eeb9545c463cf90f0ba *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo
stddev: 1.53 PSNR: 44.43 MAXDIFF: 31 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr
new file mode 100644
index 0000000000..ba5e6a1b76
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+f9827e9867b0ea4f7585d8e362a58413 *tests/data/fate/vsynth2-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth2-dnxhd-1080i-colr.mov
+e4cf5528c993b5e7d57a9d0a4d2cd0c6 *tests/data/fate/vsynth2-dnxhd-1080i-colr.out.rawvideo
+stddev: 1.58 PSNR: 44.15 MAXDIFF: 33 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-720p b/tests/ref/vsynth/vsynth2-dnxhd-720p
index a6e3ae0c33..f40da38346 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-720p
+++ b/tests/ref/vsynth/vsynth2-dnxhd-720p
@@ -1,4 +1,4 @@
-71c7491a41545882b36f07ee98021b4b *tests/data/fate/vsynth2-dnxhd-720p.dnxhd
+3bb2d4fe12b49eae830918d68bde0675 *tests/data/fate/vsynth2-dnxhd-720p.dnxhd
2293760 tests/data/fate/vsynth2-dnxhd-720p.dnxhd
-adef978dc9c9e4f10dc7c30418af62af *tests/data/fate/vsynth2-dnxhd-720p.out.rawvideo
-stddev: 6.69 PSNR: 31.62 MAXDIFF: 171 bytes: 7603200/ 760320
+903e5a7f2b84c0cd362a0f3a69549989 *tests/data/fate/vsynth2-dnxhd-720p.out.rawvideo
+stddev: 1.53 PSNR: 44.41 MAXDIFF: 31 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit b/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit
index 749d5f0d28..c57bf7debe 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit
+++ b/tests/ref/vsynth/vsynth2-dnxhd-720p-10bit
@@ -1,4 +1,4 @@
-4798978f178cdb91203cda27e76ce75e *tests/data/fate/vsynth2-dnxhd-720p-10bit.dnxhd
+e49cb87f69acc809aee55d64990c84a9 *tests/data/fate/vsynth2-dnxhd-720p-10bit.dnxhd
2293760 tests/data/fate/vsynth2-dnxhd-720p-10bit.dnxhd
-7ce1b7e73432498b530c6aa970566757 *tests/data/fate/vsynth2-dnxhd-720p-10bit.out.rawvideo
-stddev: 1.56 PSNR: 44.24 MAXDIFF: 31 bytes: 7603200/ 760320
+3eb47758e42db9fc704e1254b7abbeb0 *tests/data/fate/vsynth2-dnxhd-720p-10bit.out.rawvideo
+stddev: 1.56 PSNR: 44.25 MAXDIFF: 31 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dnxhd-720p-rd b/tests/ref/vsynth/vsynth2-dnxhd-720p-rd
index d9500e33cd..3d975570d1 100644
--- a/tests/ref/vsynth/vsynth2-dnxhd-720p-rd
+++ b/tests/ref/vsynth/vsynth2-dnxhd-720p-rd
@@ -1,4 +1,4 @@
-819a7714098e098981bf08253ef2e490 *tests/data/fate/vsynth2-dnxhd-720p-rd.dnxhd
+b723c7412a4c93f500b917ad721f6d21 *tests/data/fate/vsynth2-dnxhd-720p-rd.dnxhd
2293760 tests/data/fate/vsynth2-dnxhd-720p-rd.dnxhd
-a05c35b99e5e74a9c8b3a9c66da01775 *tests/data/fate/vsynth2-dnxhd-720p-rd.out.rawvideo
-stddev: 1.53 PSNR: 44.39 MAXDIFF: 31 bytes: 7603200/ 760320
+f7d437ea7024700cfd61c40197f44852 *tests/data/fate/vsynth2-dnxhd-720p-rd.out.rawvideo
+stddev: 1.53 PSNR: 44.40 MAXDIFF: 31 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-dv b/tests/ref/vsynth/vsynth2-dv
index fd1f3c6778..bb0602a70f 100644
--- a/tests/ref/vsynth/vsynth2-dv
+++ b/tests/ref/vsynth/vsynth2-dv
@@ -1,4 +1,4 @@
-dbea9acebf1bd2e3a827ab37777ff4bf *tests/data/fate/vsynth2-dv.dv
+9002a5769a7744a4b8d24b01787abc3b *tests/data/fate/vsynth2-dv.dv
7200000 tests/data/fate/vsynth2-dv.dv
-be0a13c96af0065541aa7b3f6a1d688f *tests/data/fate/vsynth2-dv.out.rawvideo
-stddev: 1.99 PSNR: 42.11 MAXDIFF: 38 bytes: 7603200/ 7603200
+22a62dc9108c4a8b1a3c708e5d383748 *tests/data/fate/vsynth2-dv.out.rawvideo
+stddev: 1.99 PSNR: 42.12 MAXDIFF: 38 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dv-411 b/tests/ref/vsynth/vsynth2-dv-411
index 608ee665eb..bdda6367bc 100644
--- a/tests/ref/vsynth/vsynth2-dv-411
+++ b/tests/ref/vsynth/vsynth2-dv-411
@@ -1,4 +1,4 @@
-1bf5ee0be63310b567fe01235c6b81d7 *tests/data/fate/vsynth2-dv-411.dv
+701dac8c1d3fe69957eab7ba8d5ecb25 *tests/data/fate/vsynth2-dv-411.dv
7200000 tests/data/fate/vsynth2-dv-411.dv
-653619342dbecd1e1314fa1eed0488fa *tests/data/fate/vsynth2-dv-411.out.rawvideo
+bf821931bb81f4e92dc38f86d8187300 *tests/data/fate/vsynth2-dv-411.out.rawvideo
stddev: 3.48 PSNR: 37.28 MAXDIFF: 56 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-dv-50 b/tests/ref/vsynth/vsynth2-dv-50
index 0ba19befc4..c21c525df4 100644
--- a/tests/ref/vsynth/vsynth2-dv-50
+++ b/tests/ref/vsynth/vsynth2-dv-50
@@ -1,4 +1,4 @@
-ef9ec02d39b706ce491c027567ffb41a *tests/data/fate/vsynth2-dv-50.dv
+9b9ebdf35911dad62203dfdf1f56754e *tests/data/fate/vsynth2-dv-50.dv
14400000 tests/data/fate/vsynth2-dv-50.dv
-8ba68c2a400fd4974a8489dcecd3d82c *tests/data/fate/vsynth2-dv-50.out.rawvideo
-stddev: 0.88 PSNR: 49.21 MAXDIFF: 17 bytes: 7603200/ 7603200
+b4d324b2095bc919ad16891891d40b36 *tests/data/fate/vsynth2-dv-50.out.rawvideo
+stddev: 0.88 PSNR: 49.20 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1 b/tests/ref/vsynth/vsynth2-ffv1
index 4dc2169443..b38bb38d21 100644
--- a/tests/ref/vsynth/vsynth2-ffv1
+++ b/tests/ref/vsynth/vsynth2-ffv1
@@ -1,4 +1,4 @@
-4af788aeb692573717fe205f3ba20a33 *tests/data/fate/vsynth2-ffv1.avi
-3716494 tests/data/fate/vsynth2-ffv1.avi
+6d7b6352f49e21153bb891df411e60ec *tests/data/fate/vsynth2-ffv1.avi
+3718026 tests/data/fate/vsynth2-ffv1.avi
36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffv1.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1.0 b/tests/ref/vsynth/vsynth2-ffv1.0
new file mode 100644
index 0000000000..117fe2734f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1.0
@@ -0,0 +1,4 @@
+9647e906f0739ed84303bd03d1cb8105 *tests/data/fate/vsynth2-ffv1.0.avi
+3692542 tests/data/fate/vsynth2-ffv1.0.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffv1.0.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff b/tests/ref/vsynth/vsynth2-ffvhuff
index 40c29bbb76..4a791804e4 100644
--- a/tests/ref/vsynth/vsynth2-ffvhuff
+++ b/tests/ref/vsynth/vsynth2-ffvhuff
@@ -1,4 +1,4 @@
-9884966783a0d092b45462ea586df2f8 *tests/data/fate/vsynth2-ffvhuff.avi
-4951180 tests/data/fate/vsynth2-ffvhuff.avi
+bf05520f43523ffde8952c23f36cc6a9 *tests/data/fate/vsynth2-ffvhuff.avi
+4865622 tests/data/fate/vsynth2-ffvhuff.avi
36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffvhuff.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff420p12 b/tests/ref/vsynth/vsynth2-ffvhuff420p12
new file mode 100644
index 0000000000..82c467ac3e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff420p12
@@ -0,0 +1,4 @@
+3ab9567895bf1ec31a82aadf16a5da0e *tests/data/fate/vsynth2-ffvhuff420p12.avi
+10562808 tests/data/fate/vsynth2-ffvhuff420p12.avi
+542327cb5ca7708085513ffc3d7c693c *tests/data/fate/vsynth2-ffvhuff420p12.out.rawvideo
+stddev: 0.72 PSNR: 50.87 MAXDIFF: 1 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff422p10left b/tests/ref/vsynth/vsynth2-ffvhuff422p10left
new file mode 100644
index 0000000000..a4284cf36e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff422p10left
@@ -0,0 +1,4 @@
+d13c20fb63b70b81dd6100be47a3f07c *tests/data/fate/vsynth2-ffvhuff422p10left.avi
+9870628 tests/data/fate/vsynth2-ffvhuff422p10left.avi
+8bb1c449e1a2a94fd0d98841c04246bb *tests/data/fate/vsynth2-ffvhuff422p10left.out.rawvideo
+stddev: 0.39 PSNR: 56.17 MAXDIFF: 9 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff444 b/tests/ref/vsynth/vsynth2-ffvhuff444
new file mode 100644
index 0000000000..7c7242eba1
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff444
@@ -0,0 +1,4 @@
+770909cb12fc8a1b2ce020e5f9b421d4 *tests/data/fate/vsynth2-ffvhuff444.avi
+7635774 tests/data/fate/vsynth2-ffvhuff444.avi
+8394327c14ef0b6fbaae3b69fcc5572a *tests/data/fate/vsynth2-ffvhuff444.out.rawvideo
+stddev: 0.50 PSNR: 54.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ffvhuff444p16 b/tests/ref/vsynth/vsynth2-ffvhuff444p16
new file mode 100644
index 0000000000..ebc3840ef7
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffvhuff444p16
@@ -0,0 +1,4 @@
+63ad1a32444c67d7092735fd74a7193d *tests/data/fate/vsynth2-ffvhuff444p16.avi
+26612924 tests/data/fate/vsynth2-ffvhuff444p16.avi
+410af07de7ae21936aaeae03fc90cbc9 *tests/data/fate/vsynth2-ffvhuff444p16.out.rawvideo
+stddev: 0.53 PSNR: 53.63 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-flashsv b/tests/ref/vsynth/vsynth2-flashsv
index de7446bb5e..9bda896687 100644
--- a/tests/ref/vsynth/vsynth2-flashsv
+++ b/tests/ref/vsynth/vsynth2-flashsv
@@ -1,4 +1,4 @@
-52701f9112732b42aa425129265ef499 *tests/data/fate/vsynth2-flashsv.flv
-11636526 tests/data/fate/vsynth2-flashsv.flv
-eed2322f11b95fc7abe5356306f00d97 *tests/data/fate/vsynth2-flashsv.out.rawvideo
-stddev: 1.21 PSNR: 46.42 MAXDIFF: 20 bytes: 7603200/ 7603200
+f4b45770dd93b43b4077532e8ef90bfc *tests/data/fate/vsynth2-flashsv.flv
+11636546 tests/data/fate/vsynth2-flashsv.flv
+7f0fc12c02e68faddc153e69ddd6841c *tests/data/fate/vsynth2-flashsv.out.rawvideo
+stddev: 1.20 PSNR: 46.52 MAXDIFF: 20 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-flashsv2 b/tests/ref/vsynth/vsynth2-flashsv2
new file mode 100644
index 0000000000..f68095483e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-flashsv2
@@ -0,0 +1,4 @@
+22bdec26851a2003c9f37dd1828284da *tests/data/fate/vsynth2-flashsv2.flv
+8660168 tests/data/fate/vsynth2-flashsv2.flv
+c1b3691276c2982ea55c34c130b2fdb1 *tests/data/fate/vsynth2-flashsv2.out.rawvideo
+stddev: 2.87 PSNR: 38.97 MAXDIFF: 28 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-flv b/tests/ref/vsynth/vsynth2-flv
index 818b1110b9..9b2651c8b7 100644
--- a/tests/ref/vsynth/vsynth2-flv
+++ b/tests/ref/vsynth/vsynth2-flv
@@ -1,4 +1,4 @@
-1be21ea941eb8b5ef5ecde9cac40ada0 *tests/data/fate/vsynth2-flv.flv
-174657 tests/data/fate/vsynth2-flv.flv
-c6e9b6c165558d052541309e48b5f551 *tests/data/fate/vsynth2-flv.out.rawvideo
+9c5da517eec395fd98318a4a86578f03 *tests/data/fate/vsynth2-flv.flv
+174673 tests/data/fate/vsynth2-flv.flv
+b49557d32c0a4a230a1201b270cfadc3 *tests/data/fate/vsynth2-flv.out.rawvideo
stddev: 6.02 PSNR: 32.53 MAXDIFF: 83 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h261 b/tests/ref/vsynth/vsynth2-h261
index 2c3d99b3ae..999ac36aa6 100644
--- a/tests/ref/vsynth/vsynth2-h261
+++ b/tests/ref/vsynth/vsynth2-h261
@@ -1,4 +1,4 @@
-b5187bd5be8b422ff220f297de90fbcb *tests/data/fate/vsynth2-h261.avi
-257928 tests/data/fate/vsynth2-h261.avi
-1a9bb0d52bd24cb62162c5e3c2aed317 *tests/data/fate/vsynth2-h261.out.rawvideo
+6334083b8899cdd8b56f80f8e1345213 *tests/data/fate/vsynth2-h261.avi
+257938 tests/data/fate/vsynth2-h261.avi
+8962b6ea3153a828e5a4df68e1d5da44 *tests/data/fate/vsynth2-h261.out.rawvideo
stddev: 7.21 PSNR: 30.97 MAXDIFF: 96 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h261-trellis b/tests/ref/vsynth/vsynth2-h261-trellis
new file mode 100644
index 0000000000..7f53e303fa
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-h261-trellis
@@ -0,0 +1,4 @@
+f5105d846793cd12f1fedffd917a240d *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
diff --git a/tests/ref/vsynth/vsynth2-h263 b/tests/ref/vsynth/vsynth2-h263
index ce63aab7e7..057021bdd6 100644
--- a/tests/ref/vsynth/vsynth2-h263
+++ b/tests/ref/vsynth/vsynth2-h263
@@ -1,4 +1,4 @@
-350cf3bdc9b0ddbac5648d3343f6311f *tests/data/fate/vsynth2-h263.avi
-216468 tests/data/fate/vsynth2-h263.avi
-4d9c35b109b48f49a62d2a9208e3f0e7 *tests/data/fate/vsynth2-h263.out.rawvideo
+8f765ba6afa2a0a1e33d7bf9d168ae2f *tests/data/fate/vsynth2-h263.avi
+216474 tests/data/fate/vsynth2-h263.avi
+d77291a0611eeec0667bbc3aba7190b8 *tests/data/fate/vsynth2-h263.out.rawvideo
stddev: 6.12 PSNR: 32.39 MAXDIFF: 83 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h263-obmc b/tests/ref/vsynth/vsynth2-h263-obmc
index 40ab3f5f68..2cef7f551b 100644
--- a/tests/ref/vsynth/vsynth2-h263-obmc
+++ b/tests/ref/vsynth/vsynth2-h263-obmc
@@ -1,4 +1,4 @@
-c42dc221b17353b814c72202eb2d9e54 *tests/data/fate/vsynth2-h263-obmc.avi
-208520 tests/data/fate/vsynth2-h263-obmc.avi
-cec8aa66f5ee1c8569f40b572c1ea100 *tests/data/fate/vsynth2-h263-obmc.out.rawvideo
+2d8a58b295e03f94e6a41468b2d3909e *tests/data/fate/vsynth2-h263-obmc.avi
+208522 tests/data/fate/vsynth2-h263-obmc.avi
+4a939ef99fc759293f2e609bfcacd2a4 *tests/data/fate/vsynth2-h263-obmc.out.rawvideo
stddev: 6.10 PSNR: 32.41 MAXDIFF: 90 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-h263p b/tests/ref/vsynth/vsynth2-h263p
index 5a72e729d1..487d282dd2 100644
--- a/tests/ref/vsynth/vsynth2-h263p
+++ b/tests/ref/vsynth/vsynth2-h263p
@@ -1,4 +1,4 @@
-a0527f9eab97e5e6543a5feb901283d0 *tests/data/fate/vsynth2-h263p.avi
-1134962 tests/data/fate/vsynth2-h263p.avi
+f18d6a61cb0b581b0c4835f4055f0905 *tests/data/fate/vsynth2-h263p.avi
+1134966 tests/data/fate/vsynth2-h263p.avi
66e8c0bd40918f970e62b6cdd7df79a5 *tests/data/fate/vsynth2-h263p.out.rawvideo
stddev: 2.01 PSNR: 42.04 MAXDIFF: 21 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-huffyuv b/tests/ref/vsynth/vsynth2-huffyuv
index 0d4f1f92e0..a10d430815 100644
--- a/tests/ref/vsynth/vsynth2-huffyuv
+++ b/tests/ref/vsynth/vsynth2-huffyuv
@@ -1,4 +1,4 @@
-37c68caa7a0bd66a7511e6439c1ada49 *tests/data/fate/vsynth2-huffyuv.avi
-6422324 tests/data/fate/vsynth2-huffyuv.avi
+0f56e00a2850c0156de419d979782f29 *tests/data/fate/vsynth2-huffyuv.avi
+6159098 tests/data/fate/vsynth2-huffyuv.avi
36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-huffyuv.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-huffyuvbgr24 b/tests/ref/vsynth/vsynth2-huffyuvbgr24
new file mode 100644
index 0000000000..4263e0f72b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-huffyuvbgr24
@@ -0,0 +1,4 @@
+f7a321d9dc6b2cdef377067eae413954 *tests/data/fate/vsynth2-huffyuvbgr24.avi
+8809210 tests/data/fate/vsynth2-huffyuvbgr24.avi
+835a86f8dff88917c3e5f2776954c5b7 *tests/data/fate/vsynth2-huffyuvbgr24.out.rawvideo
+stddev: 1.57 PSNR: 44.18 MAXDIFF: 20 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-huffyuvbgra b/tests/ref/vsynth/vsynth2-huffyuvbgra
new file mode 100644
index 0000000000..1451f6b018
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-huffyuvbgra
@@ -0,0 +1,4 @@
+7f591295660b0a4dd93cc436e51d1a87 *tests/data/fate/vsynth2-huffyuvbgra.avi
+10076390 tests/data/fate/vsynth2-huffyuvbgra.avi
+835a86f8dff88917c3e5f2776954c5b7 *tests/data/fate/vsynth2-huffyuvbgra.out.rawvideo
+stddev: 1.57 PSNR: 44.18 MAXDIFF: 20 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-jpeg2000 b/tests/ref/vsynth/vsynth2-jpeg2000
new file mode 100644
index 0000000000..04c5a2a472
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-jpeg2000
@@ -0,0 +1,4 @@
+b918de21dec4310f87af3788ed458462 *tests/data/fate/vsynth2-jpeg2000.avi
+1513144 tests/data/fate/vsynth2-jpeg2000.avi
+1d33de510f21eaad6c3cecfcf29798ba *tests/data/fate/vsynth2-jpeg2000.out.rawvideo
+stddev: 4.99 PSNR: 34.17 MAXDIFF: 70 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-jpeg2000-97 b/tests/ref/vsynth/vsynth2-jpeg2000-97
new file mode 100644
index 0000000000..21ab8ad5d0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-jpeg2000-97
@@ -0,0 +1,4 @@
+f8880f48a46ad43623d00de15ecba2cd *tests/data/fate/vsynth2-jpeg2000-97.avi
+1467472 tests/data/fate/vsynth2-jpeg2000-97.avi
+e523db4385f586d73aa0ee2688a75d2e *tests/data/fate/vsynth2-jpeg2000-97.out.rawvideo
+stddev: 5.44 PSNR: 33.41 MAXDIFF: 57 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-jpegls b/tests/ref/vsynth/vsynth2-jpegls
index fba01fe610..02cdf09c65 100644
--- a/tests/ref/vsynth/vsynth2-jpegls
+++ b/tests/ref/vsynth/vsynth2-jpegls
@@ -1,4 +1,4 @@
-d5901351df4887fd45c6e5da9bdaffcf *tests/data/fate/vsynth2-jpegls.avi
-8311644 tests/data/fate/vsynth2-jpegls.avi
-eed2322f11b95fc7abe5356306f00d97 *tests/data/fate/vsynth2-jpegls.out.rawvideo
-stddev: 1.21 PSNR: 46.42 MAXDIFF: 20 bytes: 7603200/ 7603200
+b26c90f2661ccfe8a68b6cde71e9ccf0 *tests/data/fate/vsynth2-jpegls.avi
+8311648 tests/data/fate/vsynth2-jpegls.avi
+7f0fc12c02e68faddc153e69ddd6841c *tests/data/fate/vsynth2-jpegls.out.rawvideo
+stddev: 1.20 PSNR: 46.52 MAXDIFF: 20 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-ljpeg b/tests/ref/vsynth/vsynth2-ljpeg
index fe78d715e8..776cfcfef1 100644
--- a/tests/ref/vsynth/vsynth2-ljpeg
+++ b/tests/ref/vsynth/vsynth2-ljpeg
@@ -1,4 +1,4 @@
-5198a8578e3a4a82a622eaf91ac13548 *tests/data/fate/vsynth2-ljpeg.avi
-4715702 tests/data/fate/vsynth2-ljpeg.avi
+ae8b43d92240077d7a80b6d543a63d0c *tests/data/fate/vsynth2-ljpeg.avi
+4712248 tests/data/fate/vsynth2-ljpeg.avi
36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ljpeg.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mjpeg b/tests/ref/vsynth/vsynth2-mjpeg
index 4fc585893d..98b257ef01 100644
--- a/tests/ref/vsynth/vsynth2-mjpeg
+++ b/tests/ref/vsynth/vsynth2-mjpeg
@@ -1,4 +1,4 @@
-972d25dee3c6fe965304fa34e2f75f8a *tests/data/fate/vsynth2-mjpeg.avi
-830288 tests/data/fate/vsynth2-mjpeg.avi
-5f979b021284f8b2868f558f6cc593fe *tests/data/fate/vsynth2-mjpeg.out.rawvideo
+c76100bdc3f4c8e2580bb263accda9ec *tests/data/fate/vsynth2-mjpeg.avi
+830154 tests/data/fate/vsynth2-mjpeg.avi
+2b8c59c59e33d6ca7c85d31c5eeab7be *tests/data/fate/vsynth2-mjpeg.out.rawvideo
stddev: 4.87 PSNR: 34.37 MAXDIFF: 55 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mjpeg-422 b/tests/ref/vsynth/vsynth2-mjpeg-422
new file mode 100644
index 0000000000..ddedda68fe
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-422
@@ -0,0 +1,4 @@
+1c8dd65c901ce48ef82d73b80e38c735 *tests/data/fate/vsynth2-mjpeg-422.avi
+920364 tests/data/fate/vsynth2-mjpeg-422.avi
+4a1b18eeb8b0f3dccc2c0e6a9f8c876d *tests/data/fate/vsynth2-mjpeg-422.out.rawvideo
+stddev: 4.69 PSNR: 34.69 MAXDIFF: 55 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mjpeg-444 b/tests/ref/vsynth/vsynth2-mjpeg-444
new file mode 100644
index 0000000000..428fedcc80
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-444
@@ -0,0 +1,4 @@
+0ac6d33ef31d07eecf65955eabf241f7 *tests/data/fate/vsynth2-mjpeg-444.avi
+1060070 tests/data/fate/vsynth2-mjpeg-444.avi
+6417f5a4be03ca7854f0a1be429a286e *tests/data/fate/vsynth2-mjpeg-444.out.rawvideo
+stddev: 4.57 PSNR: 34.93 MAXDIFF: 55 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mjpeg-trell b/tests/ref/vsynth/vsynth2-mjpeg-trell
new file mode 100644
index 0000000000..ce6d917c18
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mjpeg-trell
@@ -0,0 +1,4 @@
+4fdbd2327ed16fc4448eb421def22b5e *tests/data/fate/vsynth2-mjpeg-trell.avi
+765628 tests/data/fate/vsynth2-mjpeg-trell.avi
+ce145393bece26d49076b26cf1a2e52e *tests/data/fate/vsynth2-mjpeg-trell.out.rawvideo
+stddev: 5.03 PSNR: 34.09 MAXDIFF: 67 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg1 b/tests/ref/vsynth/vsynth2-mpeg1
index eebc514546..83c18c1c7c 100644
--- a/tests/ref/vsynth/vsynth2-mpeg1
+++ b/tests/ref/vsynth/vsynth2-mpeg1
@@ -1,4 +1,4 @@
-9daec4f4e4b6fb8960c3509c84eae0c7 *tests/data/fate/vsynth2-mpeg1.mpeg1video
-262171 tests/data/fate/vsynth2-mpeg1.mpeg1video
-33916bea6d2bc5db93aaf38ee706ba46 *tests/data/fate/vsynth2-mpeg1.out.rawvideo
+2e5441dfaf41f9afc1934c9f475afa5d *tests/data/fate/vsynth2-mpeg1.mpeg1video
+262153 tests/data/fate/vsynth2-mpeg1.mpeg1video
+5fd6c2afc4f880cdf65637bfd8d94d9d *tests/data/fate/vsynth2-mpeg1.out.rawvideo
stddev: 5.54 PSNR: 33.26 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg1b b/tests/ref/vsynth/vsynth2-mpeg1b
index 4aab85ecce..5c3f9bc53b 100644
--- a/tests/ref/vsynth/vsynth2-mpeg1b
+++ b/tests/ref/vsynth/vsynth2-mpeg1b
@@ -1,4 +1,4 @@
-30d6d3f9b7b4234e74d3ed22c012ab31 *tests/data/fate/vsynth2-mpeg1b.mpeg1video
-298135 tests/data/fate/vsynth2-mpeg1b.mpeg1video
-bbac65e2e1fd7e14d83f50072e188852 *tests/data/fate/vsynth2-mpeg1b.out.rawvideo
+1496c950cd3d3b61b08b5888c5ae42a1 *tests/data/fate/vsynth2-mpeg1b.mpeg1video
+298132 tests/data/fate/vsynth2-mpeg1b.mpeg1video
+e300711fe39a914c66793b806360b754 *tests/data/fate/vsynth2-mpeg1b.out.rawvideo
stddev: 4.60 PSNR: 34.87 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2 b/tests/ref/vsynth/vsynth2-mpeg2
index 7f441cb1f7..869948adeb 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2
+++ b/tests/ref/vsynth/vsynth2-mpeg2
@@ -1,4 +1,4 @@
-48d5feed5d7866457216577a75b60d59 *tests/data/fate/vsynth2-mpeg2.mpeg2video
-268229 tests/data/fate/vsynth2-mpeg2.mpeg2video
-5887392ff0a05babc480e9f29a1797a3 *tests/data/fate/vsynth2-mpeg2.out.rawvideo
+38afa638d9ac0b9c7ccebb8073412920 *tests/data/fate/vsynth2-mpeg2.mpeg2video
+268153 tests/data/fate/vsynth2-mpeg2.mpeg2video
+bbddc9948fadfcc79487b391417ba8ed *tests/data/fate/vsynth2-mpeg2.out.rawvideo
stddev: 5.55 PSNR: 33.23 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-422 b/tests/ref/vsynth/vsynth2-mpeg2-422
index ea30134fe8..ec7244f9f9 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-422
+++ b/tests/ref/vsynth/vsynth2-mpeg2-422
@@ -1,4 +1,4 @@
-392cd150d65892060374ef0ca98b53c3 *tests/data/fate/vsynth2-mpeg2-422.mpeg2video
-379371 tests/data/fate/vsynth2-mpeg2-422.mpeg2video
-fa9fda9c92a455b39ae7e516b7de6919 *tests/data/fate/vsynth2-mpeg2-422.out.rawvideo
-stddev: 4.16 PSNR: 35.73 MAXDIFF: 70 bytes: 7603200/ 7603200
+b2fa9b73c3547191ecc01b8163abd4e5 *tests/data/fate/vsynth2-mpeg2-422.mpeg2video
+379164 tests/data/fate/vsynth2-mpeg2-422.mpeg2video
+704f6a96f93c2409219bd48b74169041 *tests/data/fate/vsynth2-mpeg2-422.out.rawvideo
+stddev: 4.17 PSNR: 35.73 MAXDIFF: 70 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-idct-int b/tests/ref/vsynth/vsynth2-mpeg2-idct-int
index fe1ed8d3b0..3cbfde939c 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-idct-int
+++ b/tests/ref/vsynth/vsynth2-mpeg2-idct-int
@@ -1,4 +1,4 @@
-4fa4ce9e167fb1816522126d36acfd3c *tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
-267430 tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
+67a99a21e2b88e22b64d8e3d1b5572e8 *tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
+267370 tests/data/fate/vsynth2-mpeg2-idct-int.mpeg2video
b750f48d58f157da94613fe92012e7a5 *tests/data/fate/vsynth2-mpeg2-idct-int.out.rawvideo
stddev: 5.56 PSNR: 33.22 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-ilace b/tests/ref/vsynth/vsynth2-mpeg2-ilace
index 565caf3d02..ba9c0f0caf 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-ilace
+++ b/tests/ref/vsynth/vsynth2-mpeg2-ilace
@@ -1,4 +1,4 @@
-be3bd3d5393320419e82afaaea6c6fb6 *tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
-275014 tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
-fe069b1be5c6aa5808c0840008485912 *tests/data/fate/vsynth2-mpeg2-ilace.out.rawvideo
+b7d52a6496d439f61e8199bfa53e8af8 *tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
+274976 tests/data/fate/vsynth2-mpeg2-ilace.mpeg2video
+7c5b9f6986686e1c3accbc16efd02408 *tests/data/fate/vsynth2-mpeg2-ilace.out.rawvideo
stddev: 5.57 PSNR: 33.20 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd b/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd
index 58feb93943..16de39edfc 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd
+++ b/tests/ref/vsynth/vsynth2-mpeg2-ivlc-qprd
@@ -1,4 +1,4 @@
-5e938746a4b50f496db6faa10cbe98d6 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
-269774 tests/data/fate/vsynth2-mpeg2-ivlc-qprd.mpeg2video
-91316e6e990ee20b4a8de33f9e6adc56 *tests/data/fate/vsynth2-mpeg2-ivlc-qprd.out.rawvideo
+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
stddev: 5.54 PSNR: 33.25 MAXDIFF: 94 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-thread b/tests/ref/vsynth/vsynth2-mpeg2-thread
index 9c44e9f2cd..ee9092f821 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-thread
+++ b/tests/ref/vsynth/vsynth2-mpeg2-thread
@@ -1,4 +1,4 @@
-722c04a6a442e0ae716e879dff4b6639 *tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
-230678 tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
-f35531461e7b31bfba66802954329f2e *tests/data/fate/vsynth2-mpeg2-thread.out.rawvideo
+a451384397f9b64a48fbb52e70be85ec *tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
+230624 tests/data/fate/vsynth2-mpeg2-thread.mpeg2video
+6d666990137b894baf28aadc306f7c2b *tests/data/fate/vsynth2-mpeg2-thread.out.rawvideo
stddev: 5.31 PSNR: 33.62 MAXDIFF: 73 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc b/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
index 6e6763ee18..4ef6211748 100644
--- a/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
+++ b/tests/ref/vsynth/vsynth2-mpeg2-thread-ivlc
@@ -1,4 +1,4 @@
-32abf166f7a6fdb8e4b46795a60761cc *tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-227906 tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
-f35531461e7b31bfba66802954329f2e *tests/data/fate/vsynth2-mpeg2-thread-ivlc.out.rawvideo
+ec4005f89785d14fbb3da14e9e3b18f5 *tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
+227850 tests/data/fate/vsynth2-mpeg2-thread-ivlc.mpeg2video
+6d666990137b894baf28aadc306f7c2b *tests/data/fate/vsynth2-mpeg2-thread-ivlc.out.rawvideo
stddev: 5.31 PSNR: 33.62 MAXDIFF: 73 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4 b/tests/ref/vsynth/vsynth2-mpeg4
index 1aa75a8cb0..85899ff88e 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4
+++ b/tests/ref/vsynth/vsynth2-mpeg4
@@ -1,4 +1,4 @@
-f60260ca447624a19ad8307abad7a431 *tests/data/fate/vsynth2-mpeg4.mp4
-159432 tests/data/fate/vsynth2-mpeg4.mp4
-871fda3853f4766669ad875923920bd5 *tests/data/fate/vsynth2-mpeg4.out.rawvideo
+adbd883d1701beabd04522d003dafab6 *tests/data/fate/vsynth2-mpeg4.mp4
+159310 tests/data/fate/vsynth2-mpeg4.mp4
+2645405bc5350acc85ad72f3352f5135 *tests/data/fate/vsynth2-mpeg4.out.rawvideo
stddev: 6.02 PSNR: 32.53 MAXDIFF: 89 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-adap b/tests/ref/vsynth/vsynth2-mpeg4-adap
index 4cfbf4936f..a3223f6363 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-adap
+++ b/tests/ref/vsynth/vsynth2-mpeg4-adap
@@ -1,4 +1,4 @@
-00b903b1de8c943b344d493312cea9e7 *tests/data/fate/vsynth2-mpeg4-adap.avi
-214026 tests/data/fate/vsynth2-mpeg4-adap.avi
-a004e972aebc9baf8c84965226115526 *tests/data/fate/vsynth2-mpeg4-adap.out.rawvideo
-stddev: 4.87 PSNR: 34.37 MAXDIFF: 86 bytes: 7603200/ 7603200
+4bff98da2342836476da817428594403 *tests/data/fate/vsynth2-mpeg4-adap.avi
+213508 tests/data/fate/vsynth2-mpeg4-adap.avi
+0c709f2b81f4593eaa29490332c2cb39 *tests/data/fate/vsynth2-mpeg4-adap.out.rawvideo
+stddev: 4.87 PSNR: 34.36 MAXDIFF: 86 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-adv b/tests/ref/vsynth/vsynth2-mpeg4-adv
index 4ae4a84eb7..6132b58618 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-adv
+++ b/tests/ref/vsynth/vsynth2-mpeg4-adv
@@ -1,4 +1,4 @@
-e18d6c882c22ac06bffffeb8ef0c1899 *tests/data/fate/vsynth2-mpeg4-adv.avi
-187242 tests/data/fate/vsynth2-mpeg4-adv.avi
+b2021365c46e52a93492e2a8697762e5 *tests/data/fate/vsynth2-mpeg4-adv.avi
+187246 tests/data/fate/vsynth2-mpeg4-adv.avi
505bdffb9b051dc2123d07a4ae183faf *tests/data/fate/vsynth2-mpeg4-adv.out.rawvideo
stddev: 5.51 PSNR: 33.30 MAXDIFF: 80 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-error b/tests/ref/vsynth/vsynth2-mpeg4-error
index fd908aa293..e1adba478b 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-error
+++ b/tests/ref/vsynth/vsynth2-mpeg4-error
@@ -1,4 +1,4 @@
-054264098fa7da0a04d154a7e76ae0e5 *tests/data/fate/vsynth2-mpeg4-error.avi
-248248 tests/data/fate/vsynth2-mpeg4-error.avi
-d341895eb9a76a2236f0eac8b4e331c3 *tests/data/fate/vsynth2-mpeg4-error.out.rawvideo
-stddev: 6.52 PSNR: 31.83 MAXDIFF: 209 bytes: 7603200/ 7603200
+0bee773ac15fd1edd56e1dd28704292f *tests/data/fate/vsynth2-mpeg4-error.avi
+236060 tests/data/fate/vsynth2-mpeg4-error.avi
+f67a99fe41cd22a2a6713965eebb990e *tests/data/fate/vsynth2-mpeg4-error.out.rawvideo
+stddev: 15.66 PSNR: 24.23 MAXDIFF: 236 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-nr b/tests/ref/vsynth/vsynth2-mpeg4-nr
index 63e6c43760..debf3bad06 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-nr
+++ b/tests/ref/vsynth/vsynth2-mpeg4-nr
@@ -1,4 +1,4 @@
-cf978cf6801e09440877c04cd09bee3b *tests/data/fate/vsynth2-mpeg4-nr.avi
-205964 tests/data/fate/vsynth2-mpeg4-nr.avi
-2968ea4618c7fe646fb3e142cea0b8ee *tests/data/fate/vsynth2-mpeg4-nr.out.rawvideo
+83bb3f4618f8d6259d48a51bc65b3cbc *tests/data/fate/vsynth2-mpeg4-nr.avi
+206038 tests/data/fate/vsynth2-mpeg4-nr.avi
+b1b0edaec04620b5f9149dce5171939c *tests/data/fate/vsynth2-mpeg4-nr.out.rawvideo
stddev: 5.32 PSNR: 33.61 MAXDIFF: 78 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-nsse b/tests/ref/vsynth/vsynth2-mpeg4-nsse
new file mode 100644
index 0000000000..cae57160a2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mpeg4-nsse
@@ -0,0 +1,4 @@
+4fdc2aaa4761f245590a3c78c85f0ae2 *tests/data/fate/vsynth2-mpeg4-nsse.avi
+266100 tests/data/fate/vsynth2-mpeg4-nsse.avi
+9123b1641394250a6edd389d02f249e8 *tests/data/fate/vsynth2-mpeg4-nsse.out.rawvideo
+stddev: 4.83 PSNR: 34.45 MAXDIFF: 59 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-qpel b/tests/ref/vsynth/vsynth2-mpeg4-qpel
index 18860d5153..495b9f057d 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-qpel
+++ b/tests/ref/vsynth/vsynth2-mpeg4-qpel
@@ -1,4 +1,4 @@
-41eaa93241ac0eeda43326d063191c05 *tests/data/fate/vsynth2-mpeg4-qpel.avi
-209952 tests/data/fate/vsynth2-mpeg4-qpel.avi
-597bcb0df5f17cbbac0c1e9fcfeadc0b *tests/data/fate/vsynth2-mpeg4-qpel.out.rawvideo
+d05dbd6c6b8a57953aea3caa6cab57b0 *tests/data/fate/vsynth2-mpeg4-qpel.avi
+209870 tests/data/fate/vsynth2-mpeg4-qpel.avi
+5313cb1ef8c520de548389d541842c51 *tests/data/fate/vsynth2-mpeg4-qpel.out.rawvideo
stddev: 4.42 PSNR: 35.22 MAXDIFF: 56 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-qprd b/tests/ref/vsynth/vsynth2-mpeg4-qprd
index 6971ca4303..0a8786b89a 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-qprd
+++ b/tests/ref/vsynth/vsynth2-mpeg4-qprd
@@ -1,4 +1,4 @@
-a8b93de39254468708ebf2744ff8239e *tests/data/fate/vsynth2-mpeg4-qprd.avi
-248702 tests/data/fate/vsynth2-mpeg4-qprd.avi
+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
stddev: 4.85 PSNR: 34.40 MAXDIFF: 85 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-rc b/tests/ref/vsynth/vsynth2-mpeg4-rc
index 7ead7f624e..ec7d7ba031 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-rc
+++ b/tests/ref/vsynth/vsynth2-mpeg4-rc
@@ -1,4 +1,4 @@
-0e2fdca5f87e09c33c638aadd11cadfd *tests/data/fate/vsynth2-mpeg4-rc.avi
-254748 tests/data/fate/vsynth2-mpeg4-rc.avi
-4cf9c72a43a42af3eedef8483a33abef *tests/data/fate/vsynth2-mpeg4-rc.out.rawvideo
+0cf3a444622becc5d56e9034b226cfe2 *tests/data/fate/vsynth2-mpeg4-rc.avi
+254738 tests/data/fate/vsynth2-mpeg4-rc.avi
+53ef615a87c8ae49c379242385315f61 *tests/data/fate/vsynth2-mpeg4-rc.out.rawvideo
stddev: 5.57 PSNR: 33.20 MAXDIFF: 116 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpeg4-thread b/tests/ref/vsynth/vsynth2-mpeg4-thread
index 902d2a858b..49c0ce0241 100644
--- a/tests/ref/vsynth/vsynth2-mpeg4-thread
+++ b/tests/ref/vsynth/vsynth2-mpeg4-thread
@@ -1,4 +1,4 @@
-8dfa6ee464e24417797af572398befdb *tests/data/fate/vsynth2-mpeg4-thread.avi
-268392 tests/data/fate/vsynth2-mpeg4-thread.avi
-75042fdb02de159446ab599cb7fe6bb9 *tests/data/fate/vsynth2-mpeg4-thread.out.rawvideo
+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
stddev: 4.89 PSNR: 34.34 MAXDIFF: 86 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-mpng b/tests/ref/vsynth/vsynth2-mpng
new file mode 100644
index 0000000000..e49714a3b0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-mpng
@@ -0,0 +1,4 @@
+481e2d148f411bb61783aa688ec22943 *tests/data/fate/vsynth2-mpng.avi
+11816978 tests/data/fate/vsynth2-mpng.avi
+32fae3e665407bb4317b3f90fedb903c *tests/data/fate/vsynth2-mpng.out.rawvideo
+stddev: 1.54 PSNR: 44.37 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-msmpeg4 b/tests/ref/vsynth/vsynth2-msmpeg4
index 162e420ecc..375f21c085 100644
--- a/tests/ref/vsynth/vsynth2-msmpeg4
+++ b/tests/ref/vsynth/vsynth2-msmpeg4
@@ -1,4 +1,4 @@
-5c1986c0a11537a6fe8d42c56bd0794e *tests/data/fate/vsynth2-msmpeg4.avi
-170436 tests/data/fate/vsynth2-msmpeg4.avi
-ce58683e7a261aedd4958de6cdbcffd9 *tests/data/fate/vsynth2-msmpeg4.out.rawvideo
+3f4e6d746b71f367ce5964fd1e421c91 *tests/data/fate/vsynth2-msmpeg4.avi
+170440 tests/data/fate/vsynth2-msmpeg4.avi
+81135454c184b78040c49a2aadca6394 *tests/data/fate/vsynth2-msmpeg4.out.rawvideo
stddev: 6.02 PSNR: 32.53 MAXDIFF: 89 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-msmpeg4v2 b/tests/ref/vsynth/vsynth2-msmpeg4v2
index aee7782f6b..3af9f1ddd3 100644
--- a/tests/ref/vsynth/vsynth2-msmpeg4v2
+++ b/tests/ref/vsynth/vsynth2-msmpeg4v2
@@ -1,4 +1,4 @@
-84a9d7579bbaac6b48b5c319d22a8f55 *tests/data/fate/vsynth2-msmpeg4v2.avi
+67358757350de1b3ba39ab074e92b5a7 *tests/data/fate/vsynth2-msmpeg4v2.avi
171910 tests/data/fate/vsynth2-msmpeg4v2.avi
-0213600e1a77c1f28708233cb5a790ac *tests/data/fate/vsynth2-msmpeg4v2.out.rawvideo
+c4ca06487e0fdfdfccdccdb671acab42 *tests/data/fate/vsynth2-msmpeg4v2.out.rawvideo
stddev: 6.02 PSNR: 32.53 MAXDIFF: 83 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-msvideo1 b/tests/ref/vsynth/vsynth2-msvideo1
new file mode 100644
index 0000000000..0d13c90dfc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-msvideo1
@@ -0,0 +1,4 @@
+92708a8eb94d1dc80ae3508c4f712e54 *tests/data/fate/vsynth2-msvideo1.avi
+1301740 tests/data/fate/vsynth2-msvideo1.avi
+9b6e5905b00c64ed936293f85abbd6cf *tests/data/fate/vsynth2-msvideo1.out.rawvideo
+stddev: 9.04 PSNR: 29.01 MAXDIFF: 169 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-prores b/tests/ref/vsynth/vsynth2-prores
index 248b7ce643..a1b4bb748f 100644
--- a/tests/ref/vsynth/vsynth2-prores
+++ b/tests/ref/vsynth/vsynth2-prores
@@ -1,4 +1,4 @@
-b7e8f1fc9cba6db205a89b16ca7ae1da *tests/data/fate/vsynth2-prores.mov
-3868288 tests/data/fate/vsynth2-prores.mov
-549787c514c9172f1f698e9282f009f2 *tests/data/fate/vsynth2-prores.out.rawvideo
-stddev: 1.17 PSNR: 46.72 MAXDIFF: 14 bytes: 7603200/ 7603200
+aa57fd1221b7eefaf1f34f9d57d6a7cb *tests/data/fate/vsynth2-prores.mov
+3265056 tests/data/fate/vsynth2-prores.mov
+537b0ff66d7c8c3c12faa89d042e6a49 *tests/data/fate/vsynth2-prores.out.rawvideo
+stddev: 1.38 PSNR: 45.29 MAXDIFF: 12 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-prores_ks b/tests/ref/vsynth/vsynth2-prores_ks
new file mode 100644
index 0000000000..b42e7b38cf
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-prores_ks
@@ -0,0 +1,4 @@
+00c75fc738859e41c48cbe36ad60c2e2 *tests/data/fate/vsynth2-prores_ks.mov
+3868162 tests/data/fate/vsynth2-prores_ks.mov
+fe7ad707205c6100e9a3956d4e1c300e *tests/data/fate/vsynth2-prores_ks.out.rawvideo
+stddev: 1.17 PSNR: 46.72 MAXDIFF: 14 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-qtrle b/tests/ref/vsynth/vsynth2-qtrle
index b55bc5bb2a..4adf913d18 100644
--- a/tests/ref/vsynth/vsynth2-qtrle
+++ b/tests/ref/vsynth/vsynth2-qtrle
@@ -1,4 +1,4 @@
-3ad59e9e4586a67328d0642dea77782e *tests/data/fate/vsynth2-qtrle.mov
-14036000 tests/data/fate/vsynth2-qtrle.mov
-abbfc86dbfdac158525addbf48cbb15f *tests/data/fate/vsynth2-qtrle.out.rawvideo
-stddev: 1.54 PSNR: 44.34 MAXDIFF: 17 bytes: 7603200/ 7603200
+b44d1cd0bb4c1e7c57d668bd9c1d319a *tests/data/fate/vsynth2-qtrle.mov
+14035926 tests/data/fate/vsynth2-qtrle.mov
+32fae3e665407bb4317b3f90fedb903c *tests/data/fate/vsynth2-qtrle.out.rawvideo
+stddev: 1.54 PSNR: 44.37 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-qtrlegray b/tests/ref/vsynth/vsynth2-qtrlegray
new file mode 100644
index 0000000000..824e64b283
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-qtrlegray
@@ -0,0 +1,4 @@
+4910471607743da624ef7339637a33e2 *tests/data/fate/vsynth2-qtrlegray.mov
+4988372 tests/data/fate/vsynth2-qtrlegray.mov
+510a92a21b552c51fcafab8188982f4d *tests/data/fate/vsynth2-qtrlegray.out.rawvideo
+stddev: 16.31 PSNR: 23.88 MAXDIFF: 89 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-r210 b/tests/ref/vsynth/vsynth2-r210
new file mode 100644
index 0000000000..3e19ef840d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-r210
@@ -0,0 +1,4 @@
+50e82830a941457a3cade01394e34dd0 *tests/data/fate/vsynth2-r210.avi
+22125252 tests/data/fate/vsynth2-r210.avi
+2ade5f6167d7a4a1589e168ddbbc35d0 *tests/data/fate/vsynth2-r210.out.rawvideo
+stddev: 1.17 PSNR: 46.71 MAXDIFF: 15 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-rgb b/tests/ref/vsynth/vsynth2-rgb
index b50d064a75..93fe634b9e 100644
--- a/tests/ref/vsynth/vsynth2-rgb
+++ b/tests/ref/vsynth/vsynth2-rgb
@@ -1,4 +1,4 @@
-f218f8f0e6bdaf486b8a20ebf8363944 *tests/data/fate/vsynth2-rgb.avi
-15213248 tests/data/fate/vsynth2-rgb.avi
-abbfc86dbfdac158525addbf48cbb15f *tests/data/fate/vsynth2-rgb.out.rawvideo
-stddev: 1.54 PSNR: 44.34 MAXDIFF: 17 bytes: 7603200/ 7603200
+707159e45a20b22d383e71d3e5960753 *tests/data/fate/vsynth2-rgb.avi
+15213252 tests/data/fate/vsynth2-rgb.avi
+32fae3e665407bb4317b3f90fedb903c *tests/data/fate/vsynth2-rgb.out.rawvideo
+stddev: 1.54 PSNR: 44.37 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-roqvideo b/tests/ref/vsynth/vsynth2-roqvideo
index 3343765e55..32a90fd8a7 100644
--- a/tests/ref/vsynth/vsynth2-roqvideo
+++ b/tests/ref/vsynth/vsynth2-roqvideo
@@ -1,4 +1,4 @@
-217bc0f8cc28558f88a6c8e1aba56ebd *tests/data/fate/vsynth2-roqvideo.roq
-91575 tests/data/fate/vsynth2-roqvideo.roq
-64385eb8f2c5a15a44f23c914b7d007f *tests/data/fate/vsynth2-roqvideo.out.rawvideo
-stddev: 4.82 PSNR: 34.45 MAXDIFF: 71 bytes: 7603200/ 760320
+f6caa394394e07b16c73fa2bb4807a88 *tests/data/fate/vsynth2-roqvideo.roq
+92517 tests/data/fate/vsynth2-roqvideo.roq
+a80f3f01b06b062ae416bee6a65917e9 *tests/data/fate/vsynth2-roqvideo.out.rawvideo
+stddev: 4.87 PSNR: 34.37 MAXDIFF: 73 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth2-rv10 b/tests/ref/vsynth/vsynth2-rv10
index e1fd75d811..ca5ae17f08 100644
--- a/tests/ref/vsynth/vsynth2-rv10
+++ b/tests/ref/vsynth/vsynth2-rv10
@@ -1,4 +1,4 @@
-3b46a4ecefe76e021bb81cc8cbd09fdc *tests/data/fate/vsynth2-rv10.rm
-210685 tests/data/fate/vsynth2-rv10.rm
-4d9c35b109b48f49a62d2a9208e3f0e7 *tests/data/fate/vsynth2-rv10.out.rawvideo
+45a1e6800af36b7e2d42cadd2b6d1447 *tests/data/fate/vsynth2-rv10.rm
+210679 tests/data/fate/vsynth2-rv10.rm
+d77291a0611eeec0667bbc3aba7190b8 *tests/data/fate/vsynth2-rv10.out.rawvideo
stddev: 6.12 PSNR: 32.39 MAXDIFF: 83 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-rv20 b/tests/ref/vsynth/vsynth2-rv20
index 38c0c8b633..921236e136 100644
--- a/tests/ref/vsynth/vsynth2-rv20
+++ b/tests/ref/vsynth/vsynth2-rv20
@@ -1,4 +1,4 @@
-1bfdb1840495e6c2876ddab73d1c98b6 *tests/data/fate/vsynth2-rv20.rm
-210666 tests/data/fate/vsynth2-rv20.rm
-d32edd26c6a04dceb75b19cf837b9d95 *tests/data/fate/vsynth2-rv20.out.rawvideo
+17ea9a2979ce2a39a390643af5112fa6 *tests/data/fate/vsynth2-rv20.rm
+210658 tests/data/fate/vsynth2-rv20.rm
+3aa8e0c1d5dcf3f07960ac0a2d439b48 *tests/data/fate/vsynth2-rv20.out.rawvideo
stddev: 6.19 PSNR: 32.28 MAXDIFF: 81 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-snow b/tests/ref/vsynth/vsynth2-snow
new file mode 100644
index 0000000000..e9607bb7d0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-snow
@@ -0,0 +1,4 @@
+0a41e73ddd2f54936490655b46dad4a3 *tests/data/fate/vsynth2-snow.avi
+72868 tests/data/fate/vsynth2-snow.avi
+34a75f5cf8a71159f1a572d9cedcfef9 *tests/data/fate/vsynth2-snow.out.rawvideo
+stddev: 13.73 PSNR: 25.37 MAXDIFF: 162 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-snow-hpel b/tests/ref/vsynth/vsynth2-snow-hpel
new file mode 100644
index 0000000000..66839fd6f6
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-snow-hpel
@@ -0,0 +1,4 @@
+9bc409e4794ee50691a26c9c836d31a7 *tests/data/fate/vsynth2-snow-hpel.avi
+79728 tests/data/fate/vsynth2-snow-hpel.avi
+2cc64d8171175a1532fd7d3ed3011fbf *tests/data/fate/vsynth2-snow-hpel.out.rawvideo
+stddev: 13.70 PSNR: 25.39 MAXDIFF: 162 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-snow-ll b/tests/ref/vsynth/vsynth2-snow-ll
new file mode 100644
index 0000000000..54b7d431c8
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-snow-ll
@@ -0,0 +1,4 @@
+4934defc7c2d3f3b6b74a8d3d877cd96 *tests/data/fate/vsynth2-snow-ll.avi
+2829418 tests/data/fate/vsynth2-snow-ll.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-snow-ll.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-svq1 b/tests/ref/vsynth/vsynth2-svq1
index 9d8dcead95..9c7db7f035 100644
--- a/tests/ref/vsynth/vsynth2-svq1
+++ b/tests/ref/vsynth/vsynth2-svq1
@@ -1,4 +1,4 @@
-9118e474af8b119c6c44e828a8dfaa8d *tests/data/fate/vsynth2-svq1.mov
-940439 tests/data/fate/vsynth2-svq1.mov
+c767386f0f6f36b554d278592bc6e9a4 *tests/data/fate/vsynth2-svq1.mov
+940289 tests/data/fate/vsynth2-svq1.mov
a8cd3b833cd7f570ddbf1e6b3eb125b6 *tests/data/fate/vsynth2-svq1.out.rawvideo
stddev: 3.71 PSNR: 36.72 MAXDIFF: 210 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-v210 b/tests/ref/vsynth/vsynth2-v210
index 245e2822a9..cc72bb2220 100644
--- a/tests/ref/vsynth/vsynth2-v210
+++ b/tests/ref/vsynth/vsynth2-v210
@@ -1,4 +1,4 @@
-3aae4d5b25a4d91e4812a297c6a9ef8a *tests/data/fate/vsynth2-v210.avi
-14752448 tests/data/fate/vsynth2-v210.avi
+211a901d7e6327cc7a48a80250acf4f8 *tests/data/fate/vsynth2-v210.avi
+14752452 tests/data/fate/vsynth2-v210.avi
99e367a50da75c2c187230889bee8e2e *tests/data/fate/vsynth2-v210.out.rawvideo
stddev: 0.40 PSNR: 56.06 MAXDIFF: 9 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-v308 b/tests/ref/vsynth/vsynth2-v308
new file mode 100644
index 0000000000..f1fee2d7d4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-v308
@@ -0,0 +1,4 @@
+a07c9e12508dec90a414a4a6119c5ae4 *tests/data/fate/vsynth2-v308.avi
+15213252 tests/data/fate/vsynth2-v308.avi
+8394327c14ef0b6fbaae3b69fcc5572a *tests/data/fate/vsynth2-v308.out.rawvideo
+stddev: 0.50 PSNR: 54.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-v408 b/tests/ref/vsynth/vsynth2-v408
new file mode 100644
index 0000000000..808135ff2d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-v408
@@ -0,0 +1,4 @@
+01612752a44782cd99bf6399875d313c *tests/data/fate/vsynth2-v408.avi
+20282052 tests/data/fate/vsynth2-v408.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-v408.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-wmv1 b/tests/ref/vsynth/vsynth2-wmv1
index 1e20493c62..5d65d61592 100644
--- a/tests/ref/vsynth/vsynth2-wmv1
+++ b/tests/ref/vsynth/vsynth2-wmv1
@@ -1,4 +1,4 @@
-54e3a0432da62f1a11543a1df4aa05eb *tests/data/fate/vsynth2-wmv1.avi
-172394 tests/data/fate/vsynth2-wmv1.avi
-73fbdc771422e590afe213d1242943a2 *tests/data/fate/vsynth2-wmv1.out.rawvideo
+1e041a3ffcdbc4ebfe5e4b43c3d177e2 *tests/data/fate/vsynth2-wmv1.avi
+172404 tests/data/fate/vsynth2-wmv1.avi
+da619b78881243205024fca4c525d8cc *tests/data/fate/vsynth2-wmv1.out.rawvideo
stddev: 6.01 PSNR: 32.54 MAXDIFF: 88 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-wmv2 b/tests/ref/vsynth/vsynth2-wmv2
index 6cc0642465..9608f7a533 100644
--- a/tests/ref/vsynth/vsynth2-wmv2
+++ b/tests/ref/vsynth/vsynth2-wmv2
@@ -1,4 +1,4 @@
-2e22f5024860163d1e11a125b283f261 *tests/data/fate/vsynth2-wmv2.avi
-173824 tests/data/fate/vsynth2-wmv2.avi
-65c4485e592d7fc48b55ba3b6051ddff *tests/data/fate/vsynth2-wmv2.out.rawvideo
+a999f38b25de2ff43438802e40c1ce70 *tests/data/fate/vsynth2-wmv2.avi
+173822 tests/data/fate/vsynth2-wmv2.avi
+cfcdca2c4b183c5502cd6ec69e573127 *tests/data/fate/vsynth2-wmv2.out.rawvideo
stddev: 6.02 PSNR: 32.54 MAXDIFF: 88 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-xface b/tests/ref/vsynth/vsynth2-xface
new file mode 100644
index 0000000000..4544269675
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-xface
@@ -0,0 +1,4 @@
+dc0ff0ba9588dbec10580941529b77a2 *tests/data/fate/vsynth2-xface.nut
+16866 tests/data/fate/vsynth2-xface.nut
+71a54876bc79746cc8c36f3f02aea4ef *tests/data/fate/vsynth2-xface.out.rawvideo
+stddev: 86.58 PSNR: 9.38 MAXDIFF: 250 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-y41p b/tests/ref/vsynth/vsynth2-y41p
new file mode 100644
index 0000000000..e40a0f3359
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-y41p
@@ -0,0 +1,4 @@
+34425303a27433cfa2cf077258c21c68 *tests/data/fate/vsynth2-y41p.avi
+7610052 tests/data/fate/vsynth2-y41p.avi
+7c760febffcf1c2e43e494f38b010af1 *tests/data/fate/vsynth2-y41p.out.rawvideo
+stddev: 1.32 PSNR: 45.72 MAXDIFF: 34 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-yuv b/tests/ref/vsynth/vsynth2-yuv
index 335660a78f..08c9593c8e 100644
--- a/tests/ref/vsynth/vsynth2-yuv
+++ b/tests/ref/vsynth/vsynth2-yuv
@@ -1,4 +1,4 @@
-57fa20652deda0945e57251bf261399a *tests/data/fate/vsynth2-yuv.avi
-7610048 tests/data/fate/vsynth2-yuv.avi
+3d7ecff63ce4863a3d299ff82d910d78 *tests/data/fate/vsynth2-yuv.avi
+7610052 tests/data/fate/vsynth2-yuv.avi
36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-yuv.out.rawvideo
stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-yuv4 b/tests/ref/vsynth/vsynth2-yuv4
new file mode 100644
index 0000000000..557a71a3a3
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-yuv4
@@ -0,0 +1,4 @@
+a62377e0d0a7eba811aada12434959f0 *tests/data/fate/vsynth2-yuv4.avi
+7610052 tests/data/fate/vsynth2-yuv4.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-yuv4.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth2-zlib b/tests/ref/vsynth/vsynth2-zlib
new file mode 100644
index 0000000000..9dfb0d679e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-zlib
@@ -0,0 +1,4 @@
+8d2783483b354e7836cfc45a7241c4eb *tests/data/fate/vsynth2-zlib.avi
+11760520 tests/data/fate/vsynth2-zlib.avi
+32fae3e665407bb4317b3f90fedb903c *tests/data/fate/vsynth2-zlib.out.rawvideo
+stddev: 1.54 PSNR: 44.37 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth3-amv b/tests/ref/vsynth/vsynth3-amv
new file mode 100644
index 0000000000..d2859c7c23
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-amv
@@ -0,0 +1,4 @@
+be6f013af371ab9d350e4998e86d2ea4 *tests/data/fate/vsynth3-amv.avi
+33932 tests/data/fate/vsynth3-amv.avi
+f916c620790a9cf2674391610985ae27 *tests/data/fate/vsynth3-amv.out.rawvideo
+stddev: 11.58 PSNR: 26.85 MAXDIFF: 89 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-asv1 b/tests/ref/vsynth/vsynth3-asv1
new file mode 100644
index 0000000000..0abbf787ec
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-asv1
@@ -0,0 +1,4 @@
+81eeea0d0e6219b2f381cf2100e9a12f *tests/data/fate/vsynth3-asv1.avi
+34704 tests/data/fate/vsynth3-asv1.avi
+3c8636e22a96267451684f42d7a6f608 *tests/data/fate/vsynth3-asv1.out.rawvideo
+stddev: 13.16 PSNR: 25.74 MAXDIFF: 112 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-asv2 b/tests/ref/vsynth/vsynth3-asv2
new file mode 100644
index 0000000000..90b8a47f34
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-asv2
@@ -0,0 +1,4 @@
+8402fb1112fb8119c019154a472b5cd0 *tests/data/fate/vsynth3-asv2.avi
+36208 tests/data/fate/vsynth3-asv2.avi
+5469c0735b7c9279e5e8e3439fc6acab *tests/data/fate/vsynth3-asv2.out.rawvideo
+stddev: 9.07 PSNR: 28.97 MAXDIFF: 51 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-cljr b/tests/ref/vsynth/vsynth3-cljr
new file mode 100644
index 0000000000..53a2e3878e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-cljr
@@ -0,0 +1,4 @@
+34c26d901c5ccfcd10fd63a1494ae23a *tests/data/fate/vsynth3-cljr.avi
+68052 tests/data/fate/vsynth3-cljr.avi
+ac4c80dda332b6311beb1e8f723c13ca *tests/data/fate/vsynth3-cljr.out.rawvideo
+stddev: 7.51 PSNR: 30.61 MAXDIFF: 84 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr
new file mode 100644
index 0000000000..7cc2298189
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+ee7a70832f37793b62642f770d988bdb *tests/data/fate/vsynth3-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth3-dnxhd-1080i-colr.mov
+7dd6b261e439cda21df4f01b45336b41 *tests/data/fate/vsynth3-dnxhd-1080i-colr.out.rawvideo
+stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670
diff --git a/tests/ref/vsynth/vsynth3-ffv1 b/tests/ref/vsynth/vsynth3-ffv1
new file mode 100644
index 0000000000..8ffdd3f48f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1
@@ -0,0 +1,4 @@
+f969ca8542c8384c27233f362b661f8a *tests/data/fate/vsynth3-ffv1.avi
+62194 tests/data/fate/vsynth3-ffv1.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffv1.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ffv1.0 b/tests/ref/vsynth/vsynth3-ffv1.0
new file mode 100644
index 0000000000..7abc1f09a7
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1.0
@@ -0,0 +1,4 @@
+91ddf7723476e2b084253ffca69f382e *tests/data/fate/vsynth3-ffv1.0.avi
+52256 tests/data/fate/vsynth3-ffv1.0.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffv1.0.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ffvhuff b/tests/ref/vsynth/vsynth3-ffvhuff
new file mode 100644
index 0000000000..b2772b0552
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff
@@ -0,0 +1,4 @@
+9f355bfe2abe63b06e325a078151f784 *tests/data/fate/vsynth3-ffvhuff.avi
+90210 tests/data/fate/vsynth3-ffvhuff.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffvhuff.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ffvhuff420p12 b/tests/ref/vsynth/vsynth3-ffvhuff420p12
new file mode 100644
index 0000000000..72d412d644
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff420p12
@@ -0,0 +1,4 @@
+e5a178d75afeda6df1d4eb6f7cdfa3a0 *tests/data/fate/vsynth3-ffvhuff420p12.avi
+175260 tests/data/fate/vsynth3-ffvhuff420p12.avi
+ee95a44ccd612b5057860b43fe9775d6 *tests/data/fate/vsynth3-ffvhuff420p12.out.rawvideo
+stddev: 0.69 PSNR: 51.35 MAXDIFF: 1 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ffvhuff422p10left b/tests/ref/vsynth/vsynth3-ffvhuff422p10left
new file mode 100644
index 0000000000..d395829bf0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff422p10left
@@ -0,0 +1,4 @@
+37e15f58570aeeafc86972524756136a *tests/data/fate/vsynth3-ffvhuff422p10left.avi
+173552 tests/data/fate/vsynth3-ffvhuff422p10left.avi
+0cf7cf68724fa5146b1667e4fa08b0e1 *tests/data/fate/vsynth3-ffvhuff422p10left.out.rawvideo
+stddev: 2.12 PSNR: 41.58 MAXDIFF: 26 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ffvhuff444 b/tests/ref/vsynth/vsynth3-ffvhuff444
new file mode 100644
index 0000000000..37e20e130f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff444
@@ -0,0 +1,4 @@
+dc07c964dad37768d1a021afe7c3612e *tests/data/fate/vsynth3-ffvhuff444.avi
+151366 tests/data/fate/vsynth3-ffvhuff444.avi
+02a85ec07377df6b483281038f8882ee *tests/data/fate/vsynth3-ffvhuff444.out.rawvideo
+stddev: 3.06 PSNR: 38.40 MAXDIFF: 40 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ffvhuff444p16 b/tests/ref/vsynth/vsynth3-ffvhuff444p16
new file mode 100644
index 0000000000..0f4bc77242
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffvhuff444p16
@@ -0,0 +1,4 @@
+93571f2ddceadebd534c6d76fe93fc93 *tests/data/fate/vsynth3-ffvhuff444p16.avi
+320088 tests/data/fate/vsynth3-ffvhuff444p16.avi
+e5933e1e6dbacddb78e6d90cd5ed2b5d *tests/data/fate/vsynth3-ffvhuff444p16.out.rawvideo
+stddev: 3.06 PSNR: 38.40 MAXDIFF: 40 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-flashsv b/tests/ref/vsynth/vsynth3-flashsv
new file mode 100644
index 0000000000..38a34bd71d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-flashsv
@@ -0,0 +1,4 @@
+832fe60169f4d91339458c60a5292924 *tests/data/fate/vsynth3-flashsv.flv
+171419 tests/data/fate/vsynth3-flashsv.flv
+faa660b0ecaaab1bf9b5d7284019aa01 *tests/data/fate/vsynth3-flashsv.out.rawvideo
+stddev: 2.97 PSNR: 38.67 MAXDIFF: 49 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-flashsv2 b/tests/ref/vsynth/vsynth3-flashsv2
new file mode 100644
index 0000000000..31d0d3f2be
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-flashsv2
@@ -0,0 +1,4 @@
+ba57c9555329e60250905def79fe6257 *tests/data/fate/vsynth3-flashsv2.flv
+107956 tests/data/fate/vsynth3-flashsv2.flv
+fb6b5134561d86fc05ccce9323553b80 *tests/data/fate/vsynth3-flashsv2.out.rawvideo
+stddev: 3.62 PSNR: 36.95 MAXDIFF: 49 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-flv b/tests/ref/vsynth/vsynth3-flv
new file mode 100644
index 0000000000..7abe2b54c4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-flv
@@ -0,0 +1,4 @@
+c36dbc8109d1ceed68bd5590084eb375 *tests/data/fate/vsynth3-flv.flv
+28496 tests/data/fate/vsynth3-flv.flv
+b82944d78d1ee68a36d01933c9602520 *tests/data/fate/vsynth3-flv.out.rawvideo
+stddev: 9.71 PSNR: 28.38 MAXDIFF: 86 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-huffyuv b/tests/ref/vsynth/vsynth3-huffyuv
new file mode 100644
index 0000000000..2d79e56f00
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-huffyuv
@@ -0,0 +1,4 @@
+4468635f2c221d7744cc6f87ff9e9b48 *tests/data/fate/vsynth3-huffyuv.avi
+116350 tests/data/fate/vsynth3-huffyuv.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-huffyuv.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-huffyuvbgr24 b/tests/ref/vsynth/vsynth3-huffyuvbgr24
new file mode 100644
index 0000000000..91cd51e879
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-huffyuvbgr24
@@ -0,0 +1,4 @@
+758d6b72a396743c096b003f41f54023 *tests/data/fate/vsynth3-huffyuvbgr24.avi
+165158 tests/data/fate/vsynth3-huffyuvbgr24.avi
+5d031d2e891b13593b8cd79e63d083b4 *tests/data/fate/vsynth3-huffyuvbgr24.out.rawvideo
+stddev: 3.23 PSNR: 37.92 MAXDIFF: 50 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-huffyuvbgra b/tests/ref/vsynth/vsynth3-huffyuvbgra
new file mode 100644
index 0000000000..c155f74574
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-huffyuvbgra
@@ -0,0 +1,4 @@
+79a2b229d1c105b4b20de226f254f4b2 *tests/data/fate/vsynth3-huffyuvbgra.avi
+179602 tests/data/fate/vsynth3-huffyuvbgra.avi
+5d031d2e891b13593b8cd79e63d083b4 *tests/data/fate/vsynth3-huffyuvbgra.out.rawvideo
+stddev: 3.23 PSNR: 37.92 MAXDIFF: 50 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-jpeg2000 b/tests/ref/vsynth/vsynth3-jpeg2000
new file mode 100644
index 0000000000..d4015d25ee
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-jpeg2000
@@ -0,0 +1,4 @@
+7ea4e3901817f06a3de59ee70836f5d9 *tests/data/fate/vsynth3-jpeg2000.avi
+63772 tests/data/fate/vsynth3-jpeg2000.avi
+11b954cc1b0091399fa4342a6bb432b2 *tests/data/fate/vsynth3-jpeg2000.out.rawvideo
+stddev: 5.50 PSNR: 33.31 MAXDIFF: 48 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-jpeg2000-97 b/tests/ref/vsynth/vsynth3-jpeg2000-97
new file mode 100644
index 0000000000..d1695ded2f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-jpeg2000-97
@@ -0,0 +1,4 @@
+3e2f1e7d009d05e2bb9e8c3b10fab134 *tests/data/fate/vsynth3-jpeg2000-97.avi
+65364 tests/data/fate/vsynth3-jpeg2000-97.avi
+f9dad7a31175e400ca35de60aec826fd *tests/data/fate/vsynth3-jpeg2000-97.out.rawvideo
+stddev: 6.27 PSNR: 32.17 MAXDIFF: 52 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-jpegls b/tests/ref/vsynth/vsynth3-jpegls
new file mode 100644
index 0000000000..da005eccba
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-jpegls
@@ -0,0 +1,4 @@
+7651480a59692e77e346f9cc4d2fdb96 *tests/data/fate/vsynth3-jpegls.avi
+133168 tests/data/fate/vsynth3-jpegls.avi
+faa660b0ecaaab1bf9b5d7284019aa01 *tests/data/fate/vsynth3-jpegls.out.rawvideo
+stddev: 2.97 PSNR: 38.67 MAXDIFF: 49 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-ljpeg b/tests/ref/vsynth/vsynth3-ljpeg
new file mode 100644
index 0000000000..b104c6a343
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ljpeg
@@ -0,0 +1,4 @@
+d3cd7906eecc70b882b7cae300d08646 *tests/data/fate/vsynth3-ljpeg.avi
+105844 tests/data/fate/vsynth3-ljpeg.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ljpeg.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mjpeg b/tests/ref/vsynth/vsynth3-mjpeg
new file mode 100644
index 0000000000..c69338fbc0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg
@@ -0,0 +1,4 @@
+7d7a2fa8559a3652db52b7a70267d1a3 *tests/data/fate/vsynth3-mjpeg.avi
+64808 tests/data/fate/vsynth3-mjpeg.avi
+c4fe7a2669afbd96c640748693fc4e30 *tests/data/fate/vsynth3-mjpeg.out.rawvideo
+stddev: 8.60 PSNR: 29.43 MAXDIFF: 58 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mjpeg-422 b/tests/ref/vsynth/vsynth3-mjpeg-422
new file mode 100644
index 0000000000..b50e4792ed
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg-422
@@ -0,0 +1,4 @@
+34c57632d23c4322d2e508368e7c8e36 *tests/data/fate/vsynth3-mjpeg-422.avi
+69462 tests/data/fate/vsynth3-mjpeg-422.avi
+a332893cb0603f2f505fe5d3bf105519 *tests/data/fate/vsynth3-mjpeg-422.out.rawvideo
+stddev: 8.23 PSNR: 29.82 MAXDIFF: 58 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mjpeg-444 b/tests/ref/vsynth/vsynth3-mjpeg-444
new file mode 100644
index 0000000000..d701f667cc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg-444
@@ -0,0 +1,4 @@
+0900258953e90ab97a95ccaccb7b0d8a *tests/data/fate/vsynth3-mjpeg-444.avi
+70588 tests/data/fate/vsynth3-mjpeg-444.avi
+79a901f2ed85d82cf1c674fab3d3ef72 *tests/data/fate/vsynth3-mjpeg-444.out.rawvideo
+stddev: 8.21 PSNR: 29.84 MAXDIFF: 58 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mjpeg-trell b/tests/ref/vsynth/vsynth3-mjpeg-trell
new file mode 100644
index 0000000000..9178d02475
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mjpeg-trell
@@ -0,0 +1,4 @@
+6f815acb8fce5458561aa902703e6189 *tests/data/fate/vsynth3-mjpeg-trell.avi
+63994 tests/data/fate/vsynth3-mjpeg-trell.avi
+4fed1e12c80df7b67df292b153c3cf16 *tests/data/fate/vsynth3-mjpeg-trell.out.rawvideo
+stddev: 8.27 PSNR: 29.77 MAXDIFF: 61 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg1 b/tests/ref/vsynth/vsynth3-mpeg1
new file mode 100644
index 0000000000..7a3b484d6f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg1
@@ -0,0 +1,4 @@
+972ddac6afa89f1344d02b25542fc469 *tests/data/fate/vsynth3-mpeg1.mpeg1video
+28028 tests/data/fate/vsynth3-mpeg1.mpeg1video
+bffc40252da80b55302666b0046468c2 *tests/data/fate/vsynth3-mpeg1.out.rawvideo
+stddev: 9.10 PSNR: 28.94 MAXDIFF: 63 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg1b b/tests/ref/vsynth/vsynth3-mpeg1b
new file mode 100644
index 0000000000..adfa418875
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg1b
@@ -0,0 +1,4 @@
+a2e36336e35f9466c883ade059c6485e *tests/data/fate/vsynth3-mpeg1b.mpeg1video
+38251 tests/data/fate/vsynth3-mpeg1b.mpeg1video
+c44023d27be27deb7f3793321655ca75 *tests/data/fate/vsynth3-mpeg1b.out.rawvideo
+stddev: 7.00 PSNR: 31.22 MAXDIFF: 56 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2 b/tests/ref/vsynth/vsynth3-mpeg2
new file mode 100644
index 0000000000..d2e5b9fffc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2
@@ -0,0 +1,4 @@
+d95da92e3e77e32e3766ed9a95241f98 *tests/data/fate/vsynth3-mpeg2.mpeg2video
+29567 tests/data/fate/vsynth3-mpeg2.mpeg2video
+1df6a406c3959c6de7651b4e4fd98a36 *tests/data/fate/vsynth3-mpeg2.out.rawvideo
+stddev: 9.12 PSNR: 28.93 MAXDIFF: 63 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2-422 b/tests/ref/vsynth/vsynth3-mpeg2-422
new file mode 100644
index 0000000000..2247f286e6
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2-422
@@ -0,0 +1,4 @@
+4d108b861715f1fa010fd70baea91793 *tests/data/fate/vsynth3-mpeg2-422.mpeg2video
+68612 tests/data/fate/vsynth3-mpeg2-422.mpeg2video
+73b16e906d07b6bbccf4b00d4a25302c *tests/data/fate/vsynth3-mpeg2-422.out.rawvideo
+stddev: 4.02 PSNR: 36.05 MAXDIFF: 46 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2-idct-int b/tests/ref/vsynth/vsynth3-mpeg2-idct-int
new file mode 100644
index 0000000000..3b2f714654
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2-idct-int
@@ -0,0 +1,4 @@
+e79b543bed136bca385b2a870d532870 *tests/data/fate/vsynth3-mpeg2-idct-int.mpeg2video
+29614 tests/data/fate/vsynth3-mpeg2-idct-int.mpeg2video
+aebaf03348e2e114d9f487101f61fe3d *tests/data/fate/vsynth3-mpeg2-idct-int.out.rawvideo
+stddev: 9.10 PSNR: 28.94 MAXDIFF: 65 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2-ilace b/tests/ref/vsynth/vsynth3-mpeg2-ilace
new file mode 100644
index 0000000000..fe2720ef57
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2-ilace
@@ -0,0 +1,4 @@
+c13776ac25a9a9553847abddabd41915 *tests/data/fate/vsynth3-mpeg2-ilace.mpeg2video
+35773 tests/data/fate/vsynth3-mpeg2-ilace.mpeg2video
+78861ce7b0d433205e45960e1fadd911 *tests/data/fate/vsynth3-mpeg2-ilace.out.rawvideo
+stddev: 9.10 PSNR: 28.95 MAXDIFF: 62 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2-ivlc-qprd b/tests/ref/vsynth/vsynth3-mpeg2-ivlc-qprd
new file mode 100644
index 0000000000..d732912b8b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2-ivlc-qprd
@@ -0,0 +1,4 @@
+15a7db418ab54b6827d0bf53999de58f *tests/data/fate/vsynth3-mpeg2-ivlc-qprd.mpeg2video
+59765 tests/data/fate/vsynth3-mpeg2-ivlc-qprd.mpeg2video
+92048d455345edebc2b21a5ff102c3e4 *tests/data/fate/vsynth3-mpeg2-ivlc-qprd.out.rawvideo
+stddev: 2.66 PSNR: 39.61 MAXDIFF: 22 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2-thread b/tests/ref/vsynth/vsynth3-mpeg2-thread
new file mode 100644
index 0000000000..faf10716a2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2-thread
@@ -0,0 +1,4 @@
+adceaea1136d072c629d8be517f8d96d *tests/data/fate/vsynth3-mpeg2-thread.mpeg2video
+40356 tests/data/fate/vsynth3-mpeg2-thread.mpeg2video
+917f425ebc14d29783d184d90f493e86 *tests/data/fate/vsynth3-mpeg2-thread.out.rawvideo
+stddev: 8.93 PSNR: 29.11 MAXDIFF: 64 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg2-thread-ivlc b/tests/ref/vsynth/vsynth3-mpeg2-thread-ivlc
new file mode 100644
index 0000000000..8ac72f1fae
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg2-thread-ivlc
@@ -0,0 +1,4 @@
+221231dae1cd87b8c51a8f4772be6632 *tests/data/fate/vsynth3-mpeg2-thread-ivlc.mpeg2video
+40091 tests/data/fate/vsynth3-mpeg2-thread-ivlc.mpeg2video
+917f425ebc14d29783d184d90f493e86 *tests/data/fate/vsynth3-mpeg2-thread-ivlc.out.rawvideo
+stddev: 8.93 PSNR: 29.11 MAXDIFF: 64 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4 b/tests/ref/vsynth/vsynth3-mpeg4
new file mode 100644
index 0000000000..02cf68d55d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4
@@ -0,0 +1,4 @@
+ddcff996543900496f0b374a2d5cae74 *tests/data/fate/vsynth3-mpeg4.mp4
+26017 tests/data/fate/vsynth3-mpeg4.mp4
+fc0d8c1e58d254031e6207dfcae8f867 *tests/data/fate/vsynth3-mpeg4.out.rawvideo
+stddev: 9.66 PSNR: 28.43 MAXDIFF: 79 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-adap b/tests/ref/vsynth/vsynth3-mpeg4-adap
new file mode 100644
index 0000000000..0942f83015
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-adap
@@ -0,0 +1,4 @@
+c16e5c2436ca9953517eadba562768e9 *tests/data/fate/vsynth3-mpeg4-adap.avi
+43706 tests/data/fate/vsynth3-mpeg4-adap.avi
+b42b614e19e7c4859fca1af6d4e36eae *tests/data/fate/vsynth3-mpeg4-adap.out.rawvideo
+stddev: 5.48 PSNR: 33.34 MAXDIFF: 53 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-adv b/tests/ref/vsynth/vsynth3-mpeg4-adv
new file mode 100644
index 0000000000..7a9ecb6a80
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-adv
@@ -0,0 +1,4 @@
+140ecea2eb7d85cbe647adb666f09aa5 *tests/data/fate/vsynth3-mpeg4-adv.avi
+32296 tests/data/fate/vsynth3-mpeg4-adv.avi
+9f80b96af57556d53ce44008bd687f55 *tests/data/fate/vsynth3-mpeg4-adv.out.rawvideo
+stddev: 7.60 PSNR: 30.51 MAXDIFF: 63 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-error b/tests/ref/vsynth/vsynth3-mpeg4-error
new file mode 100644
index 0000000000..c33dad9f52
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-error
@@ -0,0 +1,4 @@
+7f1fb64c5a37be6e5606f92adb84f273 *tests/data/fate/vsynth3-mpeg4-error.avi
+38212 tests/data/fate/vsynth3-mpeg4-error.avi
+f9fd24e26f4ffb5ed597b9bbf0ea731b *tests/data/fate/vsynth3-mpeg4-error.out.rawvideo
+stddev: 6.06 PSNR: 32.47 MAXDIFF: 54 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-nr b/tests/ref/vsynth/vsynth3-mpeg4-nr
new file mode 100644
index 0000000000..590e1332d5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-nr
@@ -0,0 +1,4 @@
+62790bdb7c2bb4da94dba992ea967fc8 *tests/data/fate/vsynth3-mpeg4-nr.avi
+36500 tests/data/fate/vsynth3-mpeg4-nr.avi
+d0ad9918a12019dd2eacfb804d1f7e78 *tests/data/fate/vsynth3-mpeg4-nr.out.rawvideo
+stddev: 8.27 PSNR: 29.78 MAXDIFF: 70 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-nsse b/tests/ref/vsynth/vsynth3-mpeg4-nsse
new file mode 100644
index 0000000000..6ad377cd17
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-nsse
@@ -0,0 +1,4 @@
+88b1aa2dcea6a45c527487ba8f441feb *tests/data/fate/vsynth3-mpeg4-nsse.avi
+41980 tests/data/fate/vsynth3-mpeg4-nsse.avi
+69d86dec0d73e00608e03855a79dbdc0 *tests/data/fate/vsynth3-mpeg4-nsse.out.rawvideo
+stddev: 6.70 PSNR: 31.60 MAXDIFF: 68 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-qpel b/tests/ref/vsynth/vsynth3-mpeg4-qpel
new file mode 100644
index 0000000000..2d9158676b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-qpel
@@ -0,0 +1,4 @@
+8e60ed0013bfc28f48ed4d826fd26a6a *tests/data/fate/vsynth3-mpeg4-qpel.avi
+42622 tests/data/fate/vsynth3-mpeg4-qpel.avi
+50af37a5ae05f0af34bd56dcef997c8d *tests/data/fate/vsynth3-mpeg4-qpel.out.rawvideo
+stddev: 6.59 PSNR: 31.75 MAXDIFF: 54 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-qprd b/tests/ref/vsynth/vsynth3-mpeg4-qprd
new file mode 100644
index 0000000000..db6e58d245
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-qprd
@@ -0,0 +1,4 @@
+e3b49e22e8acbd21f34a2909bb35075e *tests/data/fate/vsynth3-mpeg4-qprd.avi
+61830 tests/data/fate/vsynth3-mpeg4-qprd.avi
+c59f2bead1c81b23fabc0a740048b110 *tests/data/fate/vsynth3-mpeg4-qprd.out.rawvideo
+stddev: 2.68 PSNR: 39.55 MAXDIFF: 27 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-rc b/tests/ref/vsynth/vsynth3-mpeg4-rc
new file mode 100644
index 0000000000..fae06773d4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-rc
@@ -0,0 +1,4 @@
+5b51e8f91fecd621cd3aa5d687659fbc *tests/data/fate/vsynth3-mpeg4-rc.avi
+81092 tests/data/fate/vsynth3-mpeg4-rc.avi
+07ba5baf141a24561f7dba43645a3400 *tests/data/fate/vsynth3-mpeg4-rc.out.rawvideo
+stddev: 2.62 PSNR: 39.74 MAXDIFF: 23 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpeg4-thread b/tests/ref/vsynth/vsynth3-mpeg4-thread
new file mode 100644
index 0000000000..d61803152a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpeg4-thread
@@ -0,0 +1,4 @@
+b071631783ee76df554161fc3966f567 *tests/data/fate/vsynth3-mpeg4-thread.avi
+74582 tests/data/fate/vsynth3-mpeg4-thread.avi
+7eb4d38b01c71064406ce6705c471439 *tests/data/fate/vsynth3-mpeg4-thread.out.rawvideo
+stddev: 1.99 PSNR: 42.12 MAXDIFF: 18 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-mpng b/tests/ref/vsynth/vsynth3-mpng
new file mode 100644
index 0000000000..e708a60d98
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-mpng
@@ -0,0 +1,4 @@
+3f64b66a1f46e31d45dd7f5514422ed0 *tests/data/fate/vsynth3-mpng.avi
+179804 tests/data/fate/vsynth3-mpng.avi
+693aff10c094f8bd31693f74cf79d2b2 *tests/data/fate/vsynth3-mpng.out.rawvideo
+stddev: 3.67 PSNR: 36.82 MAXDIFF: 43 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-msmpeg4 b/tests/ref/vsynth/vsynth3-msmpeg4
new file mode 100644
index 0000000000..a73cb2cdbb
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-msmpeg4
@@ -0,0 +1,4 @@
+31c27687a8bda16ef9cafc9b43f1a016 *tests/data/fate/vsynth3-msmpeg4.avi
+32444 tests/data/fate/vsynth3-msmpeg4.avi
+216b15fb02691b662d0f0112507d5583 *tests/data/fate/vsynth3-msmpeg4.out.rawvideo
+stddev: 9.63 PSNR: 28.45 MAXDIFF: 104 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-msmpeg4v2 b/tests/ref/vsynth/vsynth3-msmpeg4v2
new file mode 100644
index 0000000000..81854f1346
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-msmpeg4v2
@@ -0,0 +1,4 @@
+206b95674f0d7d77b894c17bf81b6b2d *tests/data/fate/vsynth3-msmpeg4v2.avi
+32630 tests/data/fate/vsynth3-msmpeg4v2.avi
+575bfa06fd3f3944faf92205fabf5f22 *tests/data/fate/vsynth3-msmpeg4v2.out.rawvideo
+stddev: 9.66 PSNR: 28.43 MAXDIFF: 86 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-prores b/tests/ref/vsynth/vsynth3-prores
new file mode 100644
index 0000000000..f63a7a736f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-prores
@@ -0,0 +1,4 @@
+b060c59be88b4b089ece5ee8dc4f1c58 *tests/data/fate/vsynth3-prores.mov
+105367 tests/data/fate/vsynth3-prores.mov
+fff5e7ad21d78501c8fa4749bf4bf289 *tests/data/fate/vsynth3-prores.out.rawvideo
+stddev: 2.80 PSNR: 39.17 MAXDIFF: 27 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-prores_ks b/tests/ref/vsynth/vsynth3-prores_ks
new file mode 100644
index 0000000000..99cfc1397e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-prores_ks
@@ -0,0 +1,4 @@
+7ceff8c9cffca766f8a167ba73dad0e2 *tests/data/fate/vsynth3-prores_ks.mov
+95053 tests/data/fate/vsynth3-prores_ks.mov
+9ab6d3e3cc7749796cd9fa984c60d890 *tests/data/fate/vsynth3-prores_ks.out.rawvideo
+stddev: 4.09 PSNR: 35.88 MAXDIFF: 35 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-qtrle b/tests/ref/vsynth/vsynth3-qtrle
new file mode 100644
index 0000000000..6f93232789
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-qtrle
@@ -0,0 +1,4 @@
+33ec7d4f0a18fcf6da3bdacb494e2035 *tests/data/fate/vsynth3-qtrle.mov
+179656 tests/data/fate/vsynth3-qtrle.mov
+693aff10c094f8bd31693f74cf79d2b2 *tests/data/fate/vsynth3-qtrle.out.rawvideo
+stddev: 3.67 PSNR: 36.82 MAXDIFF: 43 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-r210 b/tests/ref/vsynth/vsynth3-r210
new file mode 100644
index 0000000000..cdbdb283bc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-r210
@@ -0,0 +1,4 @@
+40b93804d521e2b7c82a3060dec81221 *tests/data/fate/vsynth3-r210.avi
+442052 tests/data/fate/vsynth3-r210.avi
+e1d882babc8754f7418aa91ce48f7ab0 *tests/data/fate/vsynth3-r210.out.rawvideo
+stddev: 3.48 PSNR: 37.28 MAXDIFF: 42 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-rgb b/tests/ref/vsynth/vsynth3-rgb
new file mode 100644
index 0000000000..c0a856396f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-rgb
@@ -0,0 +1,4 @@
+a2cb86007b8945e2d1399b56585b983a *tests/data/fate/vsynth3-rgb.avi
+180252 tests/data/fate/vsynth3-rgb.avi
+693aff10c094f8bd31693f74cf79d2b2 *tests/data/fate/vsynth3-rgb.out.rawvideo
+stddev: 3.67 PSNR: 36.82 MAXDIFF: 43 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-svq1 b/tests/ref/vsynth/vsynth3-svq1
new file mode 100644
index 0000000000..b51fa03e83
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-svq1
@@ -0,0 +1,4 @@
+1eaf318269afd7426406d73397c39a48 *tests/data/fate/vsynth3-svq1.mov
+40773 tests/data/fate/vsynth3-svq1.mov
+a1e5334cf67649bf8c7d95dc4d1bf148 *tests/data/fate/vsynth3-svq1.out.rawvideo
+stddev: 14.49 PSNR: 24.91 MAXDIFF: 183 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-v210 b/tests/ref/vsynth/vsynth3-v210
new file mode 100644
index 0000000000..658f90c31e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-v210
@@ -0,0 +1,4 @@
+df0ae6cafc1aedbf17176eb44a732e4d *tests/data/fate/vsynth3-v210.avi
+224452 tests/data/fate/vsynth3-v210.avi
+198ffb24c06927d8aaac5e59d81a0934 *tests/data/fate/vsynth3-v210.out.rawvideo
+stddev: 2.11 PSNR: 41.61 MAXDIFF: 27 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-v308 b/tests/ref/vsynth/vsynth3-v308
new file mode 100644
index 0000000000..347d4755dc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-v308
@@ -0,0 +1,4 @@
+073e24cc00a27436e97e0b242d4fd077 *tests/data/fate/vsynth3-v308.avi
+180252 tests/data/fate/vsynth3-v308.avi
+02a85ec07377df6b483281038f8882ee *tests/data/fate/vsynth3-v308.out.rawvideo
+stddev: 3.06 PSNR: 38.40 MAXDIFF: 40 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-v408 b/tests/ref/vsynth/vsynth3-v408
new file mode 100644
index 0000000000..2da09e1825
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-v408
@@ -0,0 +1,4 @@
+e74a1abf73b9df90f5103d901b37185f *tests/data/fate/vsynth3-v408.avi
+238052 tests/data/fate/vsynth3-v408.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-v408.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-wmv1 b/tests/ref/vsynth/vsynth3-wmv1
new file mode 100644
index 0000000000..4344acd55a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-wmv1
@@ -0,0 +1,4 @@
+de255d5f4838784e18af6ff86cf97e0b *tests/data/fate/vsynth3-wmv1.avi
+32658 tests/data/fate/vsynth3-wmv1.avi
+4dafe3c433c7f48c6c9e56d59ca0f7c3 *tests/data/fate/vsynth3-wmv1.out.rawvideo
+stddev: 9.65 PSNR: 28.44 MAXDIFF: 91 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-wmv2 b/tests/ref/vsynth/vsynth3-wmv2
new file mode 100644
index 0000000000..2276e7ec43
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-wmv2
@@ -0,0 +1,4 @@
+d9c2a235b43d1704bb41c73f285d86a8 *tests/data/fate/vsynth3-wmv2.avi
+33980 tests/data/fate/vsynth3-wmv2.avi
+691e00ebbb56c061f74ade70088102e7 *tests/data/fate/vsynth3-wmv2.out.rawvideo
+stddev: 9.60 PSNR: 28.48 MAXDIFF: 81 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-xface b/tests/ref/vsynth/vsynth3-xface
new file mode 100644
index 0000000000..f98a5c5e50
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-xface
@@ -0,0 +1,4 @@
+f399a6b312d0a2d873b8a3bc761c5eba *tests/data/fate/vsynth3-xface.nut
+15696 tests/data/fate/vsynth3-xface.nut
+eafdc027c9c36f96e71e91a5682a0d2e *tests/data/fate/vsynth3-xface.out.rawvideo
+stddev: 97.22 PSNR: 8.37 MAXDIFF: 236 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-yuv b/tests/ref/vsynth/vsynth3-yuv
new file mode 100644
index 0000000000..aa2cf2fad2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-yuv
@@ -0,0 +1,4 @@
+080401647f4b08df4fb44a253c914cc0 *tests/data/fate/vsynth3-yuv.avi
+93552 tests/data/fate/vsynth3-yuv.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-yuv.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-yuv4 b/tests/ref/vsynth/vsynth3-yuv4
new file mode 100644
index 0000000000..7c7b54e3b5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-yuv4
@@ -0,0 +1,4 @@
+88bcfebb7710fc17137459c104d7de4e *tests/data/fate/vsynth3-yuv4.avi
+93552 tests/data/fate/vsynth3-yuv4.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-yuv4.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth3-zlib b/tests/ref/vsynth/vsynth3-zlib
new file mode 100644
index 0000000000..55d65f30e0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-zlib
@@ -0,0 +1,4 @@
+d3705acfc90b16968d0d4a3ac56b049c *tests/data/fate/vsynth3-zlib.avi
+174882 tests/data/fate/vsynth3-zlib.avi
+693aff10c094f8bd31693f74cf79d2b2 *tests/data/fate/vsynth3-zlib.out.rawvideo
+stddev: 3.67 PSNR: 36.82 MAXDIFF: 43 bytes: 86700/ 86700
diff --git a/tests/ref/vsynth/vsynth_lena-amv b/tests/ref/vsynth/vsynth_lena-amv
new file mode 100644
index 0000000000..e4bf72574c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-amv
@@ -0,0 +1,4 @@
+49552a6ac39f27568fab1a4644aa5ddd *tests/data/fate/vsynth_lena-amv.avi
+761980 tests/data/fate/vsynth_lena-amv.avi
+f256ad9feefb499c6569d06d868eb496 *tests/data/fate/vsynth_lena-amv.out.rawvideo
+stddev: 4.30 PSNR: 35.46 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-asv1 b/tests/ref/vsynth/vsynth_lena-asv1
new file mode 100644
index 0000000000..d64bf49c79
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-asv1
@@ -0,0 +1,4 @@
+fc74737b0ea7de84609e1207d0ee9d93 *tests/data/fate/vsynth_lena-asv1.avi
+689420 tests/data/fate/vsynth_lena-asv1.avi
+a7cdefad200f48ab308c746461a8792e *tests/data/fate/vsynth_lena-asv1.out.rawvideo
+stddev: 5.07 PSNR: 34.03 MAXDIFF: 70 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-asv2 b/tests/ref/vsynth/vsynth_lena-asv2
new file mode 100644
index 0000000000..bebb5ac7b0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-asv2
@@ -0,0 +1,4 @@
+36b7ff52186fd87027f57f880eb67fd7 *tests/data/fate/vsynth_lena-asv2.avi
+675588 tests/data/fate/vsynth_lena-asv2.avi
+5990db66c7ac0bbe2f98ec2770c1bf3b *tests/data/fate/vsynth_lena-asv2.out.rawvideo
+stddev: 4.57 PSNR: 34.93 MAXDIFF: 47 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-avui b/tests/ref/vsynth/vsynth_lena-avui
new file mode 100644
index 0000000000..c2fced8e6c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-avui
@@ -0,0 +1,4 @@
+26805e15d9e732cd24aea91ae564d5c3 *tests/data/fate/vsynth_lena-avui.mov
+42625037 tests/data/fate/vsynth_lena-avui.mov
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-avui.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-cinepak b/tests/ref/vsynth/vsynth_lena-cinepak
new file mode 100644
index 0000000000..39b1d68268
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-cinepak
@@ -0,0 +1,4 @@
+e3837018f84929f07019ae2eccd303e2 *tests/data/fate/vsynth_lena-cinepak.mov
+88900 tests/data/fate/vsynth_lena-cinepak.mov
+f54ffa70f335ac7b701d7ae34462e001 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo
+stddev: 4.09 PSNR: 35.88 MAXDIFF: 46 bytes: 7603200/ 456192
diff --git a/tests/ref/vsynth/vsynth_lena-cljr b/tests/ref/vsynth/vsynth_lena-cljr
new file mode 100644
index 0000000000..6ee6150298
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-cljr
@@ -0,0 +1,4 @@
+e3579621c868e464da096a41af0674e4 *tests/data/fate/vsynth_lena-cljr.avi
+5075652 tests/data/fate/vsynth_lena-cljr.avi
+965c4a134144b30b24d6d138b03ddb8c *tests/data/fate/vsynth_lena-cljr.out.rawvideo
+stddev: 3.29 PSNR: 37.76 MAXDIFF: 23 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i
new file mode 100644
index 0000000000..3693d5797b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i
@@ -0,0 +1,4 @@
+f7412afbcb4454692f7492f6710189e3 *tests/data/fate/vsynth_lena-dnxhd-1080i.mov
+3031911 tests/data/fate/vsynth_lena-dnxhd-1080i.mov
+744ba46da5d4c19a28562ea31061d170 *tests/data/fate/vsynth_lena-dnxhd-1080i.out.rawvideo
+stddev: 1.31 PSNR: 45.77 MAXDIFF: 23 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr
new file mode 100644
index 0000000000..1889786ea7
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr
@@ -0,0 +1,4 @@
+5ba3ddb58b10e5f0069cb4f82d594695 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov
+3031929 tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov
+864c3d5f49d9edf66ce8f82a2a6725f6 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.out.rawvideo
+stddev: 1.36 PSNR: 45.45 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-720p b/tests/ref/vsynth/vsynth_lena-dnxhd-720p
new file mode 100644
index 0000000000..686be54808
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd-720p
@@ -0,0 +1,4 @@
+4ca9473a8d106bdfe36e9bf7c516b648 *tests/data/fate/vsynth_lena-dnxhd-720p.dnxhd
+2293760 tests/data/fate/vsynth_lena-dnxhd-720p.dnxhd
+d44c4b08cda8a8042ae345124fdfffcc *tests/data/fate/vsynth_lena-dnxhd-720p.out.rawvideo
+stddev: 1.32 PSNR: 45.68 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-720p-10bit b/tests/ref/vsynth/vsynth_lena-dnxhd-720p-10bit
new file mode 100644
index 0000000000..794e9c1985
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd-720p-10bit
@@ -0,0 +1,4 @@
+e96fc4a7d994b9369c50da32fd325822 *tests/data/fate/vsynth_lena-dnxhd-720p-10bit.dnxhd
+2293760 tests/data/fate/vsynth_lena-dnxhd-720p-10bit.dnxhd
+0449440eb3e8416840a27deb1a8f80b0 *tests/data/fate/vsynth_lena-dnxhd-720p-10bit.out.rawvideo
+stddev: 1.35 PSNR: 45.47 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-720p-rd b/tests/ref/vsynth/vsynth_lena-dnxhd-720p-rd
new file mode 100644
index 0000000000..453f68f018
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd-720p-rd
@@ -0,0 +1,4 @@
+b305b03708e905717b42fc0b304367d4 *tests/data/fate/vsynth_lena-dnxhd-720p-rd.dnxhd
+2293760 tests/data/fate/vsynth_lena-dnxhd-720p-rd.dnxhd
+13de1c5ed025abb5120450e134aa623d *tests/data/fate/vsynth_lena-dnxhd-720p-rd.out.rawvideo
+stddev: 1.32 PSNR: 45.66 MAXDIFF: 22 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd_1080i b/tests/ref/vsynth/vsynth_lena-dnxhd_1080i
new file mode 100644
index 0000000000..125c7a8e16
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dnxhd_1080i
@@ -0,0 +1,4 @@
+204e80f2e406ada90fca596ab2810b3e *./tests/data/vsynth_lena/dnxhd-1080i.mov
+3031911 ./tests/data/vsynth_lena/dnxhd-1080i.mov
+3c559af629ae0a8fb1a9a0e4b4da7733 *./tests/data/dnxhd_1080i.vsynth_lena.out.yuv
+stddev: 1.31 PSNR: 45.77 MAXDIFF: 23 bytes: 760320/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-dv b/tests/ref/vsynth/vsynth_lena-dv
new file mode 100644
index 0000000000..ad0549f6e6
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dv
@@ -0,0 +1,4 @@
+85b8d55b0b68bb3fc2e90babb580f9b7 *tests/data/fate/vsynth_lena-dv.dv
+7200000 tests/data/fate/vsynth_lena-dv.dv
+7dac420637360b031ccae7c5a69c5e0c *tests/data/fate/vsynth_lena-dv.out.rawvideo
+stddev: 1.70 PSNR: 43.47 MAXDIFF: 33 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-dv-411 b/tests/ref/vsynth/vsynth_lena-dv-411
new file mode 100644
index 0000000000..736a35da56
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dv-411
@@ -0,0 +1,4 @@
+e428508f400327aeb96969c08fb9e1b5 *tests/data/fate/vsynth_lena-dv-411.dv
+7200000 tests/data/fate/vsynth_lena-dv-411.dv
+713ed907fde448c603d6e9aee5efedd1 *tests/data/fate/vsynth_lena-dv-411.out.rawvideo
+stddev: 2.89 PSNR: 38.91 MAXDIFF: 45 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-dv-50 b/tests/ref/vsynth/vsynth_lena-dv-50
new file mode 100644
index 0000000000..adee628b67
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dv-50
@@ -0,0 +1,4 @@
+0032a07167199e6f49e07fa7ed4d5f62 *tests/data/fate/vsynth_lena-dv-50.dv
+14400000 tests/data/fate/vsynth_lena-dv-50.dv
+56c77e537291536b242857d1056de30c *tests/data/fate/vsynth_lena-dv-50.out.rawvideo
+stddev: 0.82 PSNR: 49.82 MAXDIFF: 12 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-dv_411 b/tests/ref/vsynth/vsynth_lena-dv_411
new file mode 100644
index 0000000000..1ca2bc03d9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-dv_411
@@ -0,0 +1,4 @@
+e428508f400327aeb96969c08fb9e1b5 *./tests/data/vsynth_lena/dv411.dv
+7200000 ./tests/data/vsynth_lena/dv411.dv
+7f9fa421028aabb11eaf4c6513a5a843 *./tests/data/dv_411.vsynth_lena.out.yuv
+stddev: 10.09 PSNR: 28.05 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffv1 b/tests/ref/vsynth/vsynth_lena-ffv1
new file mode 100644
index 0000000000..4060d8e25d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffv1
@@ -0,0 +1,4 @@
+ed72c22374718589ffacd7ea15424687 *tests/data/fate/vsynth_lena-ffv1.avi
+3547792 tests/data/fate/vsynth_lena-ffv1.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffv1.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffv1.0 b/tests/ref/vsynth/vsynth_lena-ffv1.0
new file mode 100644
index 0000000000..58b1061c91
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffv1.0
@@ -0,0 +1,4 @@
+ad518c7014bdd6a72514a79a9102f64f *tests/data/fate/vsynth_lena-ffv1.0.avi
+3525796 tests/data/fate/vsynth_lena-ffv1.0.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffv1.0.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff b/tests/ref/vsynth/vsynth_lena-ffvhuff
new file mode 100644
index 0000000000..88711a52bf
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffvhuff
@@ -0,0 +1,4 @@
+c8bcad0cd3babf63ce96525f6c11ae6e *tests/data/fate/vsynth_lena-ffvhuff.avi
+4845026 tests/data/fate/vsynth_lena-ffvhuff.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffvhuff.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 b/tests/ref/vsynth/vsynth_lena-ffvhuff420p12
new file mode 100644
index 0000000000..e8ea4bcc85
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffvhuff420p12
@@ -0,0 +1,4 @@
+b2f3d04ca30c113b79877bb5518dd6ea *tests/data/fate/vsynth_lena-ffvhuff420p12.avi
+10925580 tests/data/fate/vsynth_lena-ffvhuff420p12.avi
+08b3c6c70eba608bae926608ff253f2a *tests/data/fate/vsynth_lena-ffvhuff420p12.out.rawvideo
+stddev: 0.68 PSNR: 51.38 MAXDIFF: 1 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff422p10left b/tests/ref/vsynth/vsynth_lena-ffvhuff422p10left
new file mode 100644
index 0000000000..d650427e1f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffvhuff422p10left
@@ -0,0 +1,4 @@
+f6eae87090fcccc682f84a794784b4dd *tests/data/fate/vsynth_lena-ffvhuff422p10left.avi
+10041836 tests/data/fate/vsynth_lena-ffvhuff422p10left.avi
+a627fb50c8276200fd71383977d87ca3 *tests/data/fate/vsynth_lena-ffvhuff422p10left.out.rawvideo
+stddev: 0.34 PSNR: 57.43 MAXDIFF: 6 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff444 b/tests/ref/vsynth/vsynth_lena-ffvhuff444
new file mode 100644
index 0000000000..366498d186
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffvhuff444
@@ -0,0 +1,4 @@
+1afdc5e87de165520f2b7e0fab18b241 *tests/data/fate/vsynth_lena-ffvhuff444.avi
+7530718 tests/data/fate/vsynth_lena-ffvhuff444.avi
+d43cb310c130c69214332d74f6ee5f9a *tests/data/fate/vsynth_lena-ffvhuff444.out.rawvideo
+stddev: 0.41 PSNR: 55.80 MAXDIFF: 7 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff444p16 b/tests/ref/vsynth/vsynth_lena-ffvhuff444p16
new file mode 100644
index 0000000000..3161b41976
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffvhuff444p16
@@ -0,0 +1,4 @@
+94e2c25a08522071ca4d2314ddb2a4a1 *tests/data/fate/vsynth_lena-ffvhuff444p16.avi
+26360720 tests/data/fate/vsynth_lena-ffvhuff444p16.avi
+05ccd9a38f9726030b3099c0c99d3a13 *tests/data/fate/vsynth_lena-ffvhuff444p16.out.rawvideo
+stddev: 0.45 PSNR: 55.06 MAXDIFF: 7 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-flashsv b/tests/ref/vsynth/vsynth_lena-flashsv
new file mode 100644
index 0000000000..52046cdf2e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-flashsv
@@ -0,0 +1,4 @@
+0667077971e0cb63b5f49c580006e90e *tests/data/fate/vsynth_lena-flashsv.flv
+12368953 tests/data/fate/vsynth_lena-flashsv.flv
+3a984506f1ebfc9fb73b6814cab201cc *tests/data/fate/vsynth_lena-flashsv.out.rawvideo
+stddev: 0.66 PSNR: 51.73 MAXDIFF: 14 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-flashsv2 b/tests/ref/vsynth/vsynth_lena-flashsv2
new file mode 100644
index 0000000000..6186a1acc1
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-flashsv2
@@ -0,0 +1,4 @@
+01e0aa4da9ccc8e12fd03df63625eea4 *tests/data/fate/vsynth_lena-flashsv2.flv
+9291162 tests/data/fate/vsynth_lena-flashsv2.flv
+8f63e24049ba1789a7f8353c695a3d99 *tests/data/fate/vsynth_lena-flashsv2.out.rawvideo
+stddev: 2.39 PSNR: 40.55 MAXDIFF: 21 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-flv b/tests/ref/vsynth/vsynth_lena-flv
new file mode 100644
index 0000000000..e9f5e6b9f9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-flv
@@ -0,0 +1,4 @@
+dee04bdab18c2eed81373faec89fd5a7 *tests/data/fate/vsynth_lena-flv.flv
+131380 tests/data/fate/vsynth_lena-flv.flv
+184034553ceb801bb1d1521d2d998a67 *tests/data/fate/vsynth_lena-flv.out.rawvideo
+stddev: 5.33 PSNR: 33.59 MAXDIFF: 79 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-h261 b/tests/ref/vsynth/vsynth_lena-h261
new file mode 100644
index 0000000000..c4ea318f2f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-h261
@@ -0,0 +1,4 @@
+a8a6fe710cf8591d1ce5fd18f478e217 *tests/data/fate/vsynth_lena-h261.avi
+191064 tests/data/fate/vsynth_lena-h261.avi
+08f65e9aeeeaf189548c2bb417d5114f *tests/data/fate/vsynth_lena-h261.out.rawvideo
+stddev: 6.37 PSNR: 32.03 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-h261-trellis b/tests/ref/vsynth/vsynth_lena-h261-trellis
new file mode 100644
index 0000000000..128f224274
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-h261-trellis
@@ -0,0 +1,4 @@
+43fca6298b5366199104942e8a901d52 *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
diff --git a/tests/ref/vsynth/vsynth_lena-h263 b/tests/ref/vsynth/vsynth_lena-h263
new file mode 100644
index 0000000000..862231b7de
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-h263
@@ -0,0 +1,4 @@
+005cba8a5e8f10adc8973fd3c66ea236 *tests/data/fate/vsynth_lena-h263.avi
+160106 tests/data/fate/vsynth_lena-h263.avi
+b7d733ebedbaa04f49bf7493a907e223 *tests/data/fate/vsynth_lena-h263.out.rawvideo
+stddev: 5.43 PSNR: 33.42 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-h263-obmc b/tests/ref/vsynth/vsynth_lena-h263-obmc
new file mode 100644
index 0000000000..5b963107f6
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-h263-obmc
@@ -0,0 +1,4 @@
+3c6946f808412ac320be9e0c36051ea2 *tests/data/fate/vsynth_lena-h263-obmc.avi
+154730 tests/data/fate/vsynth_lena-h263-obmc.avi
+588d992d9d8096da8bdc5027268da914 *tests/data/fate/vsynth_lena-h263-obmc.out.rawvideo
+stddev: 5.39 PSNR: 33.49 MAXDIFF: 82 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-h263p b/tests/ref/vsynth/vsynth_lena-h263p
new file mode 100644
index 0000000000..3aa8223a8d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-h263p
@@ -0,0 +1,4 @@
+de3a8bca32aba3bd5138cbb40fe0099e *tests/data/fate/vsynth_lena-h263p.avi
+868002 tests/data/fate/vsynth_lena-h263p.avi
+dca18571c05c13dd691d7b0b232e43fc *tests/data/fate/vsynth_lena-h263p.out.rawvideo
+stddev: 1.91 PSNR: 42.50 MAXDIFF: 19 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-huffyuv b/tests/ref/vsynth/vsynth_lena-huffyuv
new file mode 100644
index 0000000000..25dac4591d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-huffyuv
@@ -0,0 +1,4 @@
+e0027fb7a9ab8ac964bba02186b4a829 *tests/data/fate/vsynth_lena-huffyuv.avi
+6108514 tests/data/fate/vsynth_lena-huffyuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-huffyuv.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-huffyuvbgr24 b/tests/ref/vsynth/vsynth_lena-huffyuvbgr24
new file mode 100644
index 0000000000..6bb71fcf41
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-huffyuvbgr24
@@ -0,0 +1,4 @@
+baa4da184fd977f1d6040d63644cbd55 *tests/data/fate/vsynth_lena-huffyuvbgr24.avi
+8872414 tests/data/fate/vsynth_lena-huffyuvbgr24.avi
+0a8b7ddfec03622e37c869c5b552f9fc *tests/data/fate/vsynth_lena-huffyuvbgr24.out.rawvideo
+stddev: 1.24 PSNR: 46.26 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-huffyuvbgra b/tests/ref/vsynth/vsynth_lena-huffyuvbgra
new file mode 100644
index 0000000000..509275da32
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-huffyuvbgra
@@ -0,0 +1,4 @@
+bf52b827c5fabea0949ce4776d3d66c8 *tests/data/fate/vsynth_lena-huffyuvbgra.avi
+10139602 tests/data/fate/vsynth_lena-huffyuvbgra.avi
+0a8b7ddfec03622e37c869c5b552f9fc *tests/data/fate/vsynth_lena-huffyuvbgra.out.rawvideo
+stddev: 1.24 PSNR: 46.26 MAXDIFF: 17 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-jpeg2000 b/tests/ref/vsynth/vsynth_lena-jpeg2000
new file mode 100644
index 0000000000..d4d8cf35b5
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-jpeg2000
@@ -0,0 +1,4 @@
+9283c83bc8dc830bd48ad66f71ae42e8 *tests/data/fate/vsynth_lena-jpeg2000.avi
+1151148 tests/data/fate/vsynth_lena-jpeg2000.avi
+e7d79c9e11d0fe97f03e38be66c34e4f *tests/data/fate/vsynth_lena-jpeg2000.out.rawvideo
+stddev: 4.41 PSNR: 35.23 MAXDIFF: 63 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-jpeg2000-97 b/tests/ref/vsynth/vsynth_lena-jpeg2000-97
new file mode 100644
index 0000000000..5945ac7dce
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-jpeg2000-97
@@ -0,0 +1,4 @@
+ba27504dcabe43d6608798c9cadc5cca *tests/data/fate/vsynth_lena-jpeg2000-97.avi
+1118956 tests/data/fate/vsynth_lena-jpeg2000-97.avi
+8ac8b9ee81fa73c873668e9f6b78764d *tests/data/fate/vsynth_lena-jpeg2000-97.out.rawvideo
+stddev: 4.95 PSNR: 34.23 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-jpegls b/tests/ref/vsynth/vsynth_lena-jpegls
new file mode 100644
index 0000000000..72a619bc2b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-jpegls
@@ -0,0 +1,4 @@
+517b3a8d84f1ec5d502ddb9ed0bb8580 *tests/data/fate/vsynth_lena-jpegls.avi
+8334622 tests/data/fate/vsynth_lena-jpegls.avi
+3a984506f1ebfc9fb73b6814cab201cc *tests/data/fate/vsynth_lena-jpegls.out.rawvideo
+stddev: 0.66 PSNR: 51.73 MAXDIFF: 14 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ljpeg b/tests/ref/vsynth/vsynth_lena-ljpeg
new file mode 100644
index 0000000000..81f9cdbbf6
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ljpeg
@@ -0,0 +1,4 @@
+dc136b224f01c757a887d5672d5edfd2 *tests/data/fate/vsynth_lena-ljpeg.avi
+4763458 tests/data/fate/vsynth_lena-ljpeg.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ljpeg.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mjpeg b/tests/ref/vsynth/vsynth_lena-mjpeg
new file mode 100644
index 0000000000..1487641831
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mjpeg
@@ -0,0 +1,4 @@
+40c5ba1b15006799773617f888c2808b *tests/data/fate/vsynth_lena-mjpeg.avi
+673178 tests/data/fate/vsynth_lena-mjpeg.avi
+9d4bd90e9abfa18192383b4adc23c8d4 *tests/data/fate/vsynth_lena-mjpeg.out.rawvideo
+stddev: 4.32 PSNR: 35.40 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mjpeg-422 b/tests/ref/vsynth/vsynth_lena-mjpeg-422
new file mode 100644
index 0000000000..23dd1a257d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mjpeg-422
@@ -0,0 +1,4 @@
+4a1f72cf4c8e562f4e805f0c7912515b *tests/data/fate/vsynth_lena-mjpeg-422.avi
+746534 tests/data/fate/vsynth_lena-mjpeg-422.avi
+451ac80989c4e14445cf951fd7f83b6d *tests/data/fate/vsynth_lena-mjpeg-422.out.rawvideo
+stddev: 4.18 PSNR: 35.70 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mjpeg-444 b/tests/ref/vsynth/vsynth_lena-mjpeg-444
new file mode 100644
index 0000000000..1dc103c199
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mjpeg-444
@@ -0,0 +1,4 @@
+969ac14cbc77d5475f4871cefe3cc6b0 *tests/data/fate/vsynth_lena-mjpeg-444.avi
+851446 tests/data/fate/vsynth_lena-mjpeg-444.avi
+34edcb9c87ff7aac456a4fb07f43504b *tests/data/fate/vsynth_lena-mjpeg-444.out.rawvideo
+stddev: 4.05 PSNR: 35.96 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mjpeg-trell b/tests/ref/vsynth/vsynth_lena-mjpeg-trell
new file mode 100644
index 0000000000..d37d5a2714
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mjpeg-trell
@@ -0,0 +1,4 @@
+61c12b5e0f95c352c1ff2f3b95d88274 *tests/data/fate/vsynth_lena-mjpeg-trell.avi
+613612 tests/data/fate/vsynth_lena-mjpeg-trell.avi
+ee4999fcc0913e01e69fe689b4229cbe *tests/data/fate/vsynth_lena-mjpeg-trell.out.rawvideo
+stddev: 4.51 PSNR: 35.03 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg1 b/tests/ref/vsynth/vsynth_lena-mpeg1
new file mode 100644
index 0000000000..58539e5e39
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg1
@@ -0,0 +1,4 @@
+a77a8eb6e2ad32a5b20b41abda16f4c1 *tests/data/fate/vsynth_lena-mpeg1.mpeg1video
+192794 tests/data/fate/vsynth_lena-mpeg1.mpeg1video
+b3584042c60385e0fb988b8ec5b36409 *tests/data/fate/vsynth_lena-mpeg1.out.rawvideo
+stddev: 4.95 PSNR: 34.22 MAXDIFF: 57 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg1b b/tests/ref/vsynth/vsynth_lena-mpeg1b
new file mode 100644
index 0000000000..23fe024974
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg1b
@@ -0,0 +1,4 @@
+333395b113b8045bac4e3fd90839ca6a *tests/data/fate/vsynth_lena-mpeg1b.mpeg1video
+225201 tests/data/fate/vsynth_lena-mpeg1b.mpeg1video
+f17fb3eef4ed3d03eeaaee45b217f7a5 *tests/data/fate/vsynth_lena-mpeg1b.out.rawvideo
+stddev: 4.10 PSNR: 35.86 MAXDIFF: 59 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2 b/tests/ref/vsynth/vsynth_lena-mpeg2
new file mode 100644
index 0000000000..699a47b652
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2
@@ -0,0 +1,4 @@
+6071414a26d41ae9c4cc5477d8ca19eb *tests/data/fate/vsynth_lena-mpeg2.mpeg2video
+198673 tests/data/fate/vsynth_lena-mpeg2.mpeg2video
+9efe4846a75d9b7387d1e3bb1e5db29a *tests/data/fate/vsynth_lena-mpeg2.out.rawvideo
+stddev: 4.96 PSNR: 34.20 MAXDIFF: 59 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2-422 b/tests/ref/vsynth/vsynth_lena-mpeg2-422
new file mode 100644
index 0000000000..5f11d4e7cd
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2-422
@@ -0,0 +1,4 @@
+521ec92c0b8672011a43dd13db98c400 *tests/data/fate/vsynth_lena-mpeg2-422.mpeg2video
+356431 tests/data/fate/vsynth_lena-mpeg2-422.mpeg2video
+51ca353620f85db8b5b1c56f1a275add *tests/data/fate/vsynth_lena-mpeg2-422.out.rawvideo
+stddev: 3.15 PSNR: 38.14 MAXDIFF: 49 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2-idct-int b/tests/ref/vsynth/vsynth_lena-mpeg2-idct-int
new file mode 100644
index 0000000000..35269dca14
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2-idct-int
@@ -0,0 +1,4 @@
+505371e1b10f5af01b63b3f57606b26e *tests/data/fate/vsynth_lena-mpeg2-idct-int.mpeg2video
+198041 tests/data/fate/vsynth_lena-mpeg2-idct-int.mpeg2video
+92794e70e4a19a494f10efe353d9895d *tests/data/fate/vsynth_lena-mpeg2-idct-int.out.rawvideo
+stddev: 4.97 PSNR: 34.19 MAXDIFF: 58 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2-ilace b/tests/ref/vsynth/vsynth_lena-mpeg2-ilace
new file mode 100644
index 0000000000..400be575bc
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2-ilace
@@ -0,0 +1,4 @@
+dbc7dd0272f3711f50722f4753e3bfb0 *tests/data/fate/vsynth_lena-mpeg2-ilace.mpeg2video
+204576 tests/data/fate/vsynth_lena-mpeg2-ilace.mpeg2video
+d69be0d4ba1cb9c1fef9fb0d94a912ba *tests/data/fate/vsynth_lena-mpeg2-ilace.out.rawvideo
+stddev: 4.98 PSNR: 34.18 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2-ivlc-qprd b/tests/ref/vsynth/vsynth_lena-mpeg2-ivlc-qprd
new file mode 100644
index 0000000000..2112cd2fde
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2-ivlc-qprd
@@ -0,0 +1,4 @@
+5731a196498d4e8097c0ebe57e383ef6 *tests/data/fate/vsynth_lena-mpeg2-ivlc-qprd.mpeg2video
+244694 tests/data/fate/vsynth_lena-mpeg2-ivlc-qprd.mpeg2video
+b26e21599dee48a174bdbc40b2817e55 *tests/data/fate/vsynth_lena-mpeg2-ivlc-qprd.out.rawvideo
+stddev: 4.15 PSNR: 35.76 MAXDIFF: 74 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2-thread b/tests/ref/vsynth/vsynth_lena-mpeg2-thread
new file mode 100644
index 0000000000..01b60a3c1c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2-thread
@@ -0,0 +1,4 @@
+9e734d384b4234d075203dffffa5174c *tests/data/fate/vsynth_lena-mpeg2-thread.mpeg2video
+179656 tests/data/fate/vsynth_lena-mpeg2-thread.mpeg2video
+f8f084b7f51fbe4f82d57b8aeec17edf *tests/data/fate/vsynth_lena-mpeg2-thread.out.rawvideo
+stddev: 4.72 PSNR: 34.65 MAXDIFF: 72 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg2-thread-ivlc b/tests/ref/vsynth/vsynth_lena-mpeg2-thread-ivlc
new file mode 100644
index 0000000000..2d0d42fd3f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg2-thread-ivlc
@@ -0,0 +1,4 @@
+39ae4e15e3da14218ebf250180badd92 *tests/data/fate/vsynth_lena-mpeg2-thread-ivlc.mpeg2video
+178807 tests/data/fate/vsynth_lena-mpeg2-thread-ivlc.mpeg2video
+f8f084b7f51fbe4f82d57b8aeec17edf *tests/data/fate/vsynth_lena-mpeg2-thread-ivlc.out.rawvideo
+stddev: 4.72 PSNR: 34.65 MAXDIFF: 72 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4 b/tests/ref/vsynth/vsynth_lena-mpeg4
new file mode 100644
index 0000000000..8d8cccef40
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4
@@ -0,0 +1,4 @@
+4a029747434d24d128b078a5e6aa1e88 *tests/data/fate/vsynth_lena-mpeg4.mp4
+119722 tests/data/fate/vsynth_lena-mpeg4.mp4
+9a1e085d9e488c5ead0c940c9612a37a *tests/data/fate/vsynth_lena-mpeg4.out.rawvideo
+stddev: 5.34 PSNR: 33.57 MAXDIFF: 83 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-adap b/tests/ref/vsynth/vsynth_lena-mpeg4-adap
new file mode 100644
index 0000000000..10af80b397
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-adap
@@ -0,0 +1,4 @@
+c6108621b1202d32dac68b1944c5b8c2 *tests/data/fate/vsynth_lena-mpeg4-adap.avi
+198500 tests/data/fate/vsynth_lena-mpeg4-adap.avi
+87b6dbe98d276137fceaae2fa672eced *tests/data/fate/vsynth_lena-mpeg4-adap.out.rawvideo
+stddev: 3.75 PSNR: 36.65 MAXDIFF: 71 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-adv b/tests/ref/vsynth/vsynth_lena-mpeg4-adv
new file mode 100644
index 0000000000..c725264553
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-adv
@@ -0,0 +1,4 @@
+68117f01abe704a4ce6a664efffcfb40 *tests/data/fate/vsynth_lena-mpeg4-adv.avi
+141538 tests/data/fate/vsynth_lena-mpeg4-adv.avi
+3f3a21e9db85a9c0f7022f557a5374c1 *tests/data/fate/vsynth_lena-mpeg4-adv.out.rawvideo
+stddev: 4.94 PSNR: 34.25 MAXDIFF: 69 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-error b/tests/ref/vsynth/vsynth_lena-mpeg4-error
new file mode 100644
index 0000000000..b5ebd5e010
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-error
@@ -0,0 +1,4 @@
+0126f46feb09b49144136be09ce6d26b *tests/data/fate/vsynth_lena-mpeg4-error.avi
+180368 tests/data/fate/vsynth_lena-mpeg4-error.avi
+4537ba5320f1ae0971cc6e329c366776 *tests/data/fate/vsynth_lena-mpeg4-error.out.rawvideo
+stddev: 7.65 PSNR: 30.45 MAXDIFF: 158 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-nr b/tests/ref/vsynth/vsynth_lena-mpeg4-nr
new file mode 100644
index 0000000000..e6b5dc4d18
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-nr
@@ -0,0 +1,4 @@
+c1cf10bd999899bce94be0efd15c3605 *tests/data/fate/vsynth_lena-mpeg4-nr.avi
+154998 tests/data/fate/vsynth_lena-mpeg4-nr.avi
+d89cd5d0b1707f48fa9c4747c66d2d56 *tests/data/fate/vsynth_lena-mpeg4-nr.out.rawvideo
+stddev: 4.73 PSNR: 34.63 MAXDIFF: 64 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-nsse b/tests/ref/vsynth/vsynth_lena-mpeg4-nsse
new file mode 100644
index 0000000000..31cddaa689
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-nsse
@@ -0,0 +1,4 @@
+f09593231b2137ae2064845c315b6a0b *tests/data/fate/vsynth_lena-mpeg4-nsse.avi
+198438 tests/data/fate/vsynth_lena-mpeg4-nsse.avi
+59864a1050e641eaed8b0ee077bc780b *tests/data/fate/vsynth_lena-mpeg4-nsse.out.rawvideo
+stddev: 4.32 PSNR: 35.40 MAXDIFF: 60 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-qpel b/tests/ref/vsynth/vsynth_lena-mpeg4-qpel
new file mode 100644
index 0000000000..e656130255
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-qpel
@@ -0,0 +1,4 @@
+04d020deb9956fb2b5970a16986d688c *tests/data/fate/vsynth_lena-mpeg4-qpel.avi
+163666 tests/data/fate/vsynth_lena-mpeg4-qpel.avi
+e2ce994dbb66da51c2e1ad26617d7c2f *tests/data/fate/vsynth_lena-mpeg4-qpel.out.rawvideo
+stddev: 3.97 PSNR: 36.14 MAXDIFF: 54 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-qprd b/tests/ref/vsynth/vsynth_lena-mpeg4-qprd
new file mode 100644
index 0000000000..831300b994
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-qprd
@@ -0,0 +1,4 @@
+5342abedb8fdc788e08c344d4122f2dc *tests/data/fate/vsynth_lena-mpeg4-qprd.avi
+231454 tests/data/fate/vsynth_lena-mpeg4-qprd.avi
+3071250e0864546c2455c9f9c9b8604e *tests/data/fate/vsynth_lena-mpeg4-qprd.out.rawvideo
+stddev: 3.71 PSNR: 36.72 MAXDIFF: 61 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-rc b/tests/ref/vsynth/vsynth_lena-mpeg4-rc
new file mode 100644
index 0000000000..fd6a998046
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-rc
@@ -0,0 +1,4 @@
+396a76466dee56e2714dfa42cebe3d2d *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
+stddev: 4.23 PSNR: 35.60 MAXDIFF: 85 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpeg4-thread b/tests/ref/vsynth/vsynth_lena-mpeg4-thread
new file mode 100644
index 0000000000..c0b7978b67
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpeg4-thread
@@ -0,0 +1,4 @@
+af5ea0bab124371051eb104552344b2e *tests/data/fate/vsynth_lena-mpeg4-thread.avi
+250096 tests/data/fate/vsynth_lena-mpeg4-thread.avi
+045fe9f226bbcc3d41644bffaed03b31 *tests/data/fate/vsynth_lena-mpeg4-thread.out.rawvideo
+stddev: 3.69 PSNR: 36.78 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-mpng b/tests/ref/vsynth/vsynth_lena-mpng
new file mode 100644
index 0000000000..20258433b0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-mpng
@@ -0,0 +1,4 @@
+319ca02f8465a9c53128442f4b0dd528 *tests/data/fate/vsynth_lena-mpng.avi
+12558334 tests/data/fate/vsynth_lena-mpng.avi
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth_lena-mpng.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-msmpeg4 b/tests/ref/vsynth/vsynth_lena-msmpeg4
new file mode 100644
index 0000000000..37bf7916e0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-msmpeg4
@@ -0,0 +1,4 @@
+9f48dd3b88a931ba25963a02d33261ca *tests/data/fate/vsynth_lena-msmpeg4.avi
+127664 tests/data/fate/vsynth_lena-msmpeg4.avi
+bb14902d5850d6b0ab70fdb017855775 *tests/data/fate/vsynth_lena-msmpeg4.out.rawvideo
+stddev: 5.33 PSNR: 33.58 MAXDIFF: 78 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-msmpeg4v2 b/tests/ref/vsynth/vsynth_lena-msmpeg4v2
new file mode 100644
index 0000000000..c355eacd14
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-msmpeg4v2
@@ -0,0 +1,4 @@
+7e3376dea39d44edd6ee3b0a59a87cbd *tests/data/fate/vsynth_lena-msmpeg4v2.avi
+129922 tests/data/fate/vsynth_lena-msmpeg4v2.avi
+537c114e1d47c54a4bccd31f4073e9bd *tests/data/fate/vsynth_lena-msmpeg4v2.out.rawvideo
+stddev: 5.33 PSNR: 33.59 MAXDIFF: 79 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-msvideo1 b/tests/ref/vsynth/vsynth_lena-msvideo1
new file mode 100644
index 0000000000..4f7de4010d
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-msvideo1
@@ -0,0 +1,4 @@
+f2d42ddffd6546b6ca71bbb6e3b62c00 *tests/data/fate/vsynth_lena-msvideo1.avi
+914564 tests/data/fate/vsynth_lena-msvideo1.avi
+9a6ac7c0171286f009d159b59fdc1154 *tests/data/fate/vsynth_lena-msvideo1.out.rawvideo
+stddev: 7.97 PSNR: 30.10 MAXDIFF: 123 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-prores b/tests/ref/vsynth/vsynth_lena-prores
new file mode 100644
index 0000000000..5b8c3fe1b4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-prores
@@ -0,0 +1,4 @@
+637f34b5fd81f072f76a967595fa6af7 *tests/data/fate/vsynth_lena-prores.mov
+2844076 tests/data/fate/vsynth_lena-prores.mov
+03fd29e3963716a09d232b6f817ecb57 *tests/data/fate/vsynth_lena-prores.out.rawvideo
+stddev: 1.31 PSNR: 45.77 MAXDIFF: 11 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-prores_ks b/tests/ref/vsynth/vsynth_lena-prores_ks
new file mode 100644
index 0000000000..0cdfa9bb2c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-prores_ks
@@ -0,0 +1,4 @@
+b03741c69037cbdcd2809278c00c0350 *tests/data/fate/vsynth_lena-prores_ks.mov
+3884596 tests/data/fate/vsynth_lena-prores_ks.mov
+6cfe987de99cf8ac9d43bdc5cd150838 *tests/data/fate/vsynth_lena-prores_ks.out.rawvideo
+stddev: 0.92 PSNR: 48.78 MAXDIFF: 10 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-qtrle b/tests/ref/vsynth/vsynth_lena-qtrle
new file mode 100644
index 0000000000..9ce6abe5ba
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-qtrle
@@ -0,0 +1,4 @@
+4863978263d966d704ffaaa6d23123bb *tests/data/fate/vsynth_lena-qtrle.mov
+14798345 tests/data/fate/vsynth_lena-qtrle.mov
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth_lena-qtrle.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-qtrlegray b/tests/ref/vsynth/vsynth_lena-qtrlegray
new file mode 100644
index 0000000000..951e7a7688
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-qtrlegray
@@ -0,0 +1,4 @@
+2c4e69b59d8e8e19903c843575806d5f *tests/data/fate/vsynth_lena-qtrlegray.mov
+5111283 tests/data/fate/vsynth_lena-qtrlegray.mov
+d7bfbe259af9ae323bb94b09c33570a5 *tests/data/fate/vsynth_lena-qtrlegray.out.rawvideo
+stddev: 18.65 PSNR: 22.72 MAXDIFF: 72 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-r210 b/tests/ref/vsynth/vsynth_lena-r210
new file mode 100644
index 0000000000..3ed30ff506
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-r210
@@ -0,0 +1,4 @@
+e5f96a1d0fe5c519f6cb954838e105bc *tests/data/fate/vsynth_lena-r210.avi
+22125252 tests/data/fate/vsynth_lena-r210.avi
+6ea4fcd93fc83defc8770e85b64b60bb *tests/data/fate/vsynth_lena-r210.out.rawvideo
+stddev: 0.70 PSNR: 51.12 MAXDIFF: 12 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-rgb b/tests/ref/vsynth/vsynth_lena-rgb
new file mode 100644
index 0000000000..9706ffba83
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-rgb
@@ -0,0 +1,4 @@
+f083e812216195c1e9454b5fac681c92 *tests/data/fate/vsynth_lena-rgb.avi
+15213252 tests/data/fate/vsynth_lena-rgb.avi
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth_lena-rgb.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-roqvideo b/tests/ref/vsynth/vsynth_lena-roqvideo
new file mode 100644
index 0000000000..10f2014089
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-roqvideo
@@ -0,0 +1,4 @@
+1a43cd71c91f2ef42d11a81419bff3bd *tests/data/fate/vsynth_lena-roqvideo.roq
+94810 tests/data/fate/vsynth_lena-roqvideo.roq
+97cda6096430c0ab7a43a0e120cd3e91 *tests/data/fate/vsynth_lena-roqvideo.out.rawvideo
+stddev: 3.81 PSNR: 36.50 MAXDIFF: 49 bytes: 7603200/ 760320
diff --git a/tests/ref/vsynth/vsynth_lena-rv10 b/tests/ref/vsynth/vsynth_lena-rv10
new file mode 100644
index 0000000000..651587b55e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-rv10
@@ -0,0 +1,4 @@
+33a2aae3351b0b2121f823057c0e226f *tests/data/fate/vsynth_lena-rv10.rm
+154321 tests/data/fate/vsynth_lena-rv10.rm
+b7d733ebedbaa04f49bf7493a907e223 *tests/data/fate/vsynth_lena-rv10.out.rawvideo
+stddev: 5.43 PSNR: 33.42 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-rv20 b/tests/ref/vsynth/vsynth_lena-rv20
new file mode 100644
index 0000000000..b8b6adfd04
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-rv20
@@ -0,0 +1,4 @@
+4d23a72fe7e29f98f38888804eacd111 *tests/data/fate/vsynth_lena-rv20.rm
+153304 tests/data/fate/vsynth_lena-rv20.rm
+6fa5dc1c2f00f858fc4895ad640891a2 *tests/data/fate/vsynth_lena-rv20.out.rawvideo
+stddev: 5.48 PSNR: 33.35 MAXDIFF: 81 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-snow b/tests/ref/vsynth/vsynth_lena-snow
new file mode 100644
index 0000000000..ec29a78483
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-snow
@@ -0,0 +1,4 @@
+8e96f337e8f4ccac7d72ef517e1d2208 *tests/data/fate/vsynth_lena-snow.avi
+57680 tests/data/fate/vsynth_lena-snow.avi
+90963cfd2359d460001c94d94256dc2b *tests/data/fate/vsynth_lena-snow.out.rawvideo
+stddev: 10.48 PSNR: 27.72 MAXDIFF: 119 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-snow-hpel b/tests/ref/vsynth/vsynth_lena-snow-hpel
new file mode 100644
index 0000000000..2d6edd8a79
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-snow-hpel
@@ -0,0 +1,4 @@
+56b14cb1cbb637536233982e87f7ac3e *tests/data/fate/vsynth_lena-snow-hpel.avi
+61764 tests/data/fate/vsynth_lena-snow-hpel.avi
+244b0266127fa354d8485234b2c388e4 *tests/data/fate/vsynth_lena-snow-hpel.out.rawvideo
+stddev: 10.45 PSNR: 27.74 MAXDIFF: 119 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-snow-ll b/tests/ref/vsynth/vsynth_lena-snow-ll
new file mode 100644
index 0000000000..aa8566f7e0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-snow-ll
@@ -0,0 +1,4 @@
+c0b349dadc1d1714960df23b7c92961c *tests/data/fate/vsynth_lena-snow-ll.avi
+2721750 tests/data/fate/vsynth_lena-snow-ll.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-snow-ll.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-svq1 b/tests/ref/vsynth/vsynth_lena-svq1
new file mode 100644
index 0000000000..1558c504fb
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-svq1
@@ -0,0 +1,4 @@
+6e9678439ab7460db1fcc8e41ca1a1e0 *tests/data/fate/vsynth_lena-svq1.mov
+766701 tests/data/fate/vsynth_lena-svq1.mov
+aa03471dac3f49455a33a2b19fda1098 *tests/data/fate/vsynth_lena-svq1.out.rawvideo
+stddev: 3.23 PSNR: 37.93 MAXDIFF: 61 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-v210 b/tests/ref/vsynth/vsynth_lena-v210
new file mode 100644
index 0000000000..ef5020b3f3
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-v210
@@ -0,0 +1,4 @@
+20af8b986704b9713cd75d3e6e41efa4 *tests/data/fate/vsynth_lena-v210.avi
+14752452 tests/data/fate/vsynth_lena-v210.avi
+7ba6e411e43c6b57c95c49d6848f41e6 *tests/data/fate/vsynth_lena-v210.out.rawvideo
+stddev: 0.34 PSNR: 57.41 MAXDIFF: 6 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-v308 b/tests/ref/vsynth/vsynth_lena-v308
new file mode 100644
index 0000000000..6de15b5aa4
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-v308
@@ -0,0 +1,4 @@
+5bff4d7763e624272835e056c9faf4c2 *tests/data/fate/vsynth_lena-v308.avi
+15213252 tests/data/fate/vsynth_lena-v308.avi
+d43cb310c130c69214332d74f6ee5f9a *tests/data/fate/vsynth_lena-v308.out.rawvideo
+stddev: 0.41 PSNR: 55.80 MAXDIFF: 7 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-v408 b/tests/ref/vsynth/vsynth_lena-v408
new file mode 100644
index 0000000000..ba19e28d2e
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-v408
@@ -0,0 +1,4 @@
+e2a1c097a78f1a5c8ad1bccc4077844b *tests/data/fate/vsynth_lena-v408.avi
+20282052 tests/data/fate/vsynth_lena-v408.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-v408.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-wmv1 b/tests/ref/vsynth/vsynth_lena-wmv1
new file mode 100644
index 0000000000..f407d17f7b
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-wmv1
@@ -0,0 +1,4 @@
+a9f43b25c3235a6cf922a2c5abd086e8 *tests/data/fate/vsynth_lena-wmv1.avi
+129514 tests/data/fate/vsynth_lena-wmv1.avi
+dec44e3c04db4fef49a7728f164d9159 *tests/data/fate/vsynth_lena-wmv1.out.rawvideo
+stddev: 5.33 PSNR: 33.60 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-wmv2 b/tests/ref/vsynth/vsynth_lena-wmv2
new file mode 100644
index 0000000000..fca01993c0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-wmv2
@@ -0,0 +1,4 @@
+62ef27d48181d8256ad476e02c536145 *tests/data/fate/vsynth_lena-wmv2.avi
+129856 tests/data/fate/vsynth_lena-wmv2.avi
+b4de16a0d302c52702f7a4362da989bc *tests/data/fate/vsynth_lena-wmv2.out.rawvideo
+stddev: 5.33 PSNR: 33.59 MAXDIFF: 77 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-xface b/tests/ref/vsynth/vsynth_lena-xface
new file mode 100644
index 0000000000..61031f98c9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-xface
@@ -0,0 +1,4 @@
+6a1a7b467eeab2795510e7dd1ca528ff *tests/data/fate/vsynth_lena-xface.nut
+17504 tests/data/fate/vsynth_lena-xface.nut
+6d87881d630439d02c7a97f468d67a1c *tests/data/fate/vsynth_lena-xface.out.rawvideo
+stddev: 99.01 PSNR: 8.22 MAXDIFF: 238 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-y41p b/tests/ref/vsynth/vsynth_lena-y41p
new file mode 100644
index 0000000000..9cc09573b0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-y41p
@@ -0,0 +1,4 @@
+3b958734c653d265cd42e31d6a22230f *tests/data/fate/vsynth_lena-y41p.avi
+7610052 tests/data/fate/vsynth_lena-y41p.avi
+d27a84ccdac09055724d122e03fea82a *tests/data/fate/vsynth_lena-y41p.out.rawvideo
+stddev: 1.07 PSNR: 47.54 MAXDIFF: 21 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-yuv b/tests/ref/vsynth/vsynth_lena-yuv
new file mode 100644
index 0000000000..bc27dcf6ae
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-yuv
@@ -0,0 +1,4 @@
+0d061b0b7bedcd59e5c90a99f58ceeae *tests/data/fate/vsynth_lena-yuv.avi
+7610052 tests/data/fate/vsynth_lena-yuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-yuv.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-yuv4 b/tests/ref/vsynth/vsynth_lena-yuv4
new file mode 100644
index 0000000000..97a1374a67
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-yuv4
@@ -0,0 +1,4 @@
+0686b8b4cbd3398f8b9f9d8c12922442 *tests/data/fate/vsynth_lena-yuv4.avi
+7610052 tests/data/fate/vsynth_lena-yuv4.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-yuv4.out.rawvideo
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-zlib b/tests/ref/vsynth/vsynth_lena-zlib
new file mode 100644
index 0000000000..009bcad853
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-zlib
@@ -0,0 +1,4 @@
+abbfccc551b173a357024d8392de21dd *tests/data/fate/vsynth_lena-zlib.avi
+12517180 tests/data/fate/vsynth_lena-zlib.avi
+98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth_lena-zlib.out.rawvideo
+stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth/vsynth_lena-zmbv b/tests/ref/vsynth/vsynth_lena-zmbv
new file mode 100644
index 0000000000..e6c994f844
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-zmbv
@@ -0,0 +1,4 @@
+e9cc761eb3fedc36ce5f97744196ed8b *tests/data/fate/vsynth_lena-zmbv.avi
+1808720 tests/data/fate/vsynth_lena-zmbv.avi
+ee68a5292fd0745834246b4ec0d85e9b *tests/data/fate/vsynth_lena-zmbv.out.rawvideo
+stddev: 8.12 PSNR: 29.94 MAXDIFF: 32 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth1/cljr b/tests/ref/vsynth1/cljr
new file mode 100644
index 0000000000..6002bbbbb6
--- /dev/null
+++ b/tests/ref/vsynth1/cljr
@@ -0,0 +1,4 @@
+041982e4fa83428c621a127647d47b3f *./tests/data/vsynth1/cljr.avi
+5075660 ./tests/data/vsynth1/cljr.avi
+e1c4c96c74de3435d0f9f6118c5ed9b5 *./tests/data/cljr.vsynth1.out.yuv
+stddev: 30.53 PSNR: 18.43 MAXDIFF: 225 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth1/yuv b/tests/ref/vsynth1/yuv
new file mode 100644
index 0000000000..6d8b1431db
--- /dev/null
+++ b/tests/ref/vsynth1/yuv
@@ -0,0 +1,4 @@
+eaa66c3b27a2602e882befe154a8b119 *./tests/data/vsynth1/yuv.avi
+7610060 ./tests/data/vsynth1/yuv.avi
+c5ccac874dbf808e9088bc3107860042 *./tests/data/yuv.vsynth1.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth_lena/cljr b/tests/ref/vsynth_lena/cljr
new file mode 100644
index 0000000000..e3bbc05f4b
--- /dev/null
+++ b/tests/ref/vsynth_lena/cljr
@@ -0,0 +1,4 @@
+fdc1926e0a599de94513f0a3472b598f *./tests/data/vsynth_lena/cljr.avi
+5075660 ./tests/data/vsynth_lena/cljr.avi
+7df03229ee6361ea11a0d83d4926cb10 *./tests/data/cljr.vsynth_lena.out.yuv
+stddev: 10.30 PSNR: 27.87 MAXDIFF: 65 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth_lena/huffyuv b/tests/ref/vsynth_lena/huffyuv
new file mode 100644
index 0000000000..c0e374d615
--- /dev/null
+++ b/tests/ref/vsynth_lena/huffyuv
@@ -0,0 +1,4 @@
+ed66182be0d515e8b6cb970ad63162da *./tests/data/vsynth_lena/huffyuv.avi
+6455232 ./tests/data/vsynth_lena/huffyuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *./tests/data/huffyuv.vsynth_lena.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/ref/vsynth_lena/yuv b/tests/ref/vsynth_lena/yuv
new file mode 100644
index 0000000000..eff44c3276
--- /dev/null
+++ b/tests/ref/vsynth_lena/yuv
@@ -0,0 +1,4 @@
+3d5ee6d2023bc15bba898819e4977e46 *./tests/data/vsynth_lena/yuv.avi
+7610060 ./tests/data/vsynth_lena/yuv.avi
+dde5895817ad9d219f79a52d0bdfb001 *./tests/data/yuv.vsynth_lena.out.yuv
+stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200
diff --git a/tests/regression-funcs.sh b/tests/regression-funcs.sh
index 3728d44980..c8e7c1b801 100755
--- a/tests/regression-funcs.sh
+++ b/tests/regression-funcs.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# common regression functions for avconv
+# common regression functions for ffmpeg
#
#
@@ -11,6 +11,7 @@ target_exec=$4
target_path=$5
threads=${6:-1}
cpuflags=${8:-all}
+target_samples=$9
datadir="./tests/data"
target_datadir="${target_path}/${datadir}"
@@ -19,10 +20,12 @@ this="$test.$test_ref"
outfile="$datadir/$test_ref/"
# various files
-avconv="$target_exec ${target_path}/avconv"
+ffmpeg="$target_exec ${target_path}/ffmpeg"
raw_src="${target_path}/$raw_src_dir/%02d.pgm"
raw_dst="$datadir/$this.out.yuv"
pcm_src="$target_datadir/asynth1.sw"
+pcm_src_1ch="$target_datadir/asynth-16000-1.wav"
+pcm_ref_1ch="$datadir/$test_ref-16000-1.ref.wav"
crcfile="$datadir/$this.crc"
target_crcfile="$target_datadir/$this.crc"
@@ -43,12 +46,12 @@ echov(){
AVCONV_OPTS="-nostats -y -cpuflags $cpuflags"
COMMON_OPTS="-flags +bitexact -idct simple -sws_flags +accurate_rnd+bitexact -fflags +bitexact"
DEC_OPTS="$COMMON_OPTS -threads $threads"
-ENC_OPTS="$COMMON_OPTS -threads 1 -dct fastint"
+ENC_OPTS="$COMMON_OPTS -threads $threads -dct fastint"
run_avconv()
{
- $echov $avconv $AVCONV_OPTS $*
- $avconv $AVCONV_OPTS $*
+ $echov $ffmpeg $AVCONV_OPTS $*
+ $ffmpeg $AVCONV_OPTS $*
}
do_avconv()
@@ -61,6 +64,21 @@ do_avconv()
echo $(wc -c $f)
}
+do_avconv_nomd5()
+{
+ f="$1"
+ shift
+ set -- $* ${target_path}/$f
+ run_avconv $*
+ if [ $f = $raw_dst ] ; then
+ $tiny_psnr $f $raw_ref
+ elif [ $f = $pcm_dst ] ; then
+ $tiny_psnr $f $pcm_ref 2
+ else
+ echo $(wc -c $f)
+ fi
+}
+
do_avconv_crc()
{
f="$1"
diff --git a/tests/rotozoom.c b/tests/rotozoom.c
index 69c88c2e95..cfa7f81369 100644
--- a/tests/rotozoom.c
+++ b/tests/rotozoom.c
@@ -3,20 +3,20 @@
*
* copyright (c) Sebastien Bechet <s.bechet@av7.net>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tests/test.ffmeta b/tests/test.ffmeta
new file mode 100644
index 0000000000..ad37b020e2
--- /dev/null
+++ b/tests/test.ffmeta
@@ -0,0 +1,9 @@
+;FFMETADATA1
+title=ffprobe test file
+comment='A comment with CSV, XML & JSON special chars': <tag value=\"x\">
+comment2=I ♥ ĂœĂ±Ă®Ă§Ă¸d€
+[STREAM]
+E=mc²
+[STREAM]
+title=foobar
+duration_ts=field-and-tags-conflict-attempt
diff --git a/tests/tiny_psnr.c b/tests/tiny_psnr.c
index 66eaf82895..5f791c168b 100644
--- a/tests/tiny_psnr.c
+++ b/tests/tiny_psnr.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -22,9 +22,9 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
-#include <assert.h>
#include <math.h>
#include <float.h>
+#include <limits.h>
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
@@ -57,6 +57,21 @@ uint64_t exp16_table[21] = {
582360139072LL,
};
+#if 0
+// 16.16 fixpoint exp()
+static unsigned int exp16(unsigned int a){
+ int i;
+ int out= 1<<16;
+
+ for(i=19;i>=0;i--){
+ if(a&(1<<i))
+ out= (out*exp16_table[i] + (1<<15))>>16;
+ }
+
+ return out;
+}
+#endif
+
// 16.16 fixpoint log()
static int64_t log16(uint64_t a)
{
@@ -115,79 +130,47 @@ static double get_f64l(uint8_t *p)
return av_int2double(AV_RL64(p));
}
-int main(int argc, char *argv[])
+static int run_psnr(FILE *f[2], int len, int shift, int skip_bytes)
{
int i, j;
uint64_t sse = 0;
double sse_d = 0.0;
- FILE *f[2];
uint8_t buf[2][SIZE];
- int len = 1;
- int64_t max;
- int shift = argc < 5 ? 0 : atoi(argv[4]);
- int skip_bytes = argc < 6 ? 0 : atoi(argv[5]);
+ int64_t max = (1LL << (8 * len)) - 1;
int size0 = 0;
int size1 = 0;
uint64_t maxdist = 0;
double maxdist_d = 0.0;
+ int noseek;
- if (argc < 3) {
- printf("tiny_psnr <file1> <file2> [<elem size> [<shift> [<skip bytes>]]]\n");
- printf("WAV headers are skipped automatically.\n");
- return 1;
- }
-
- if (argc > 3) {
- if (!strcmp(argv[3], "u8")) {
- len = 1;
- } else if (!strcmp(argv[3], "s16")) {
- len = 2;
- } else if (!strcmp(argv[3], "f32")) {
- len = 4;
- } else if (!strcmp(argv[3], "f64")) {
- len = 8;
- } else {
- char *end;
- len = strtol(argv[3], &end, 0);
- if (*end || len < 1 || len > 2) {
- fprintf(stderr, "Unsupported sample format: %s\n", argv[3]);
- return 1;
- }
- }
- }
-
- max = (1LL << (8 * len)) - 1;
+ noseek = fseek(f[0], 0, SEEK_SET) ||
+ fseek(f[1], 0, SEEK_SET);
- f[0] = fopen(argv[1], "rb");
- f[1] = fopen(argv[2], "rb");
- if (!f[0] || !f[1]) {
- fprintf(stderr, "Could not open input files.\n");
- return 1;
- }
-
- for (i = 0; i < 2; i++) {
- uint8_t *p = buf[i];
- if (fread(p, 1, 12, f[i]) != 12)
- return 1;
- if (!memcmp(p, "RIFF", 4) &&
- !memcmp(p + 8, "WAVE", 4)) {
- if (fread(p, 1, 8, f[i]) != 8)
- return 1;
- while (memcmp(p, "data", 4)) {
- int s = p[4] | p[5] << 8 | p[6] << 16 | p[7] << 24;
- fseek(f[i], s, SEEK_CUR);
+ if (!noseek) {
+ for (i = 0; i < 2; i++) {
+ uint8_t *p = buf[i];
+ if (fread(p, 1, 12, f[i]) != 12)
+ return -1;
+ if (!memcmp(p, "RIFF", 4) &&
+ !memcmp(p + 8, "WAVE", 4)) {
if (fread(p, 1, 8, f[i]) != 8)
- return 1;
+ return -1;
+ while (memcmp(p, "data", 4)) {
+ int s = p[4] | p[5] << 8 | p[6] << 16 | p[7] << 24;
+ fseek(f[i], s, SEEK_CUR);
+ if (fread(p, 1, 8, f[i]) != 8)
+ return -1;
+ }
+ } else {
+ fseek(f[i], -12, SEEK_CUR);
}
- } else {
- fseek(f[i], -12, SEEK_CUR);
}
- }
- fseek(f[shift < 0], abs(shift), SEEK_CUR);
+ fseek(f[shift < 0], abs(shift), SEEK_CUR);
- fseek(f[0], skip_bytes, SEEK_CUR);
- fseek(f[1], skip_bytes, SEEK_CUR);
+ fseek(f[0], skip_bytes, SEEK_CUR);
+ fseek(f[1], skip_bytes, SEEK_CUR);
+ }
for (;;) {
int s0 = fread(buf[0], 1, SIZE, f[0]);
@@ -197,8 +180,7 @@ int main(int argc, char *argv[])
switch (len) {
case 1:
case 2: {
- int64_t a = buf[0][j];
- int64_t b = buf[1][j];
+ int64_t a, b;
int dist;
if (len == 2) {
a = get_s16l(buf[0] + j);
@@ -255,16 +237,17 @@ int main(int argc, char *argv[])
(int)(dev / F), (int)(dev % F),
(int)(psnr / F), (int)(psnr % F),
maxdist, size0, size1);
- break;
+ return psnr;
}
case 4:
case 8: {
char psnr_str[64];
+ double psnr = INT_MAX;
double dev = sqrt(sse_d / i);
uint64_t scale = (len == 4) ? (1ULL << 24) : (1ULL << 32);
if (sse_d) {
- double psnr = 2 * log(DBL_MAX) - log(i / sse_d);
+ psnr = 2 * log(DBL_MAX) - log(i / sse_d);
snprintf(psnr_str, sizeof(psnr_str), "%5.02f", psnr);
} else
snprintf(psnr_str, sizeof(psnr_str), "inf");
@@ -273,8 +256,69 @@ int main(int argc, char *argv[])
printf("stddev:%10.2f PSNR:%s MAXDIFF:%10"PRIu64" bytes:%9d/%9d\n",
dev * scale, psnr_str, maxdist, size0, size1);
- break;
+ return psnr;
+ }
+ }
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *f[2];
+ int len = 1;
+ int shift_first= argc < 5 ? 0 : atoi(argv[4]);
+ int skip_bytes = argc < 6 ? 0 : atoi(argv[5]);
+ int shift_last = shift_first + (argc < 7 ? 0 : atoi(argv[6]));
+ int shift;
+ int max_psnr = -1;
+ int max_psnr_shift = 0;
+
+ if (shift_last > shift_first)
+ shift_first -= shift_last - shift_first;
+
+ if (argc > 3) {
+ if (!strcmp(argv[3], "u8")) {
+ len = 1;
+ } else if (!strcmp(argv[3], "s16")) {
+ len = 2;
+ } else if (!strcmp(argv[3], "f32")) {
+ len = 4;
+ } else if (!strcmp(argv[3], "f64")) {
+ len = 8;
+ } else {
+ char *end;
+ len = strtol(argv[3], &end, 0);
+ if (*end || len < 1 || len > 2) {
+ fprintf(stderr, "Unsupported sample format: %s\nSupported: u8, s16, f32, f64\n", argv[3]);
+ return 1;
+ }
+ }
+ }
+
+ if (argc < 3) {
+ printf("tiny_psnr <file1> <file2> [<elem size>|u8|s16|f32|f64 [<shift> [<skip bytes> [<shift search range>]]]]\n");
+ printf("WAV headers are skipped automatically.\n");
+ return 1;
}
+
+ f[0] = fopen(argv[1], "rb");
+ f[1] = fopen(argv[2], "rb");
+ if (!f[0] || !f[1]) {
+ fprintf(stderr, "Could not open input files.\n");
+ return 1;
}
+
+ for (shift = shift_first; shift <= shift_last; shift++) {
+ int psnr = run_psnr(f, len, shift, skip_bytes);
+ if (psnr > max_psnr || (shift < 0 && psnr == max_psnr)) {
+ max_psnr = psnr;
+ max_psnr_shift = shift;
+ }
+ }
+ if (max_psnr < 0)
+ return 2;
+
+ if (shift_last > shift_first)
+ printf("Best PSNR is %3d.%02d for shift %i\n", (int)(max_psnr / F), (int)(max_psnr % F), max_psnr_shift);
return 0;
}
diff --git a/tests/tiny_ssim.c b/tests/tiny_ssim.c
new file mode 100644
index 0000000000..9f355a3d82
--- /dev/null
+++ b/tests/tiny_ssim.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2003-2013 Loren Merritt
+ *
+ * This program 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.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 USA
+ */
+/*
+ * tiny_ssim.c
+ * Computes the Structural Similarity Metric between two rawYV12 video files.
+ * original algorithm:
+ * Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli,
+ * "Image quality assessment: From error visibility to structural similarity,"
+ * IEEE Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004.
+ *
+ * To improve speed, this implementation uses the standard approximation of
+ * overlapped 8x8 block sums, rather than the original gaussian weights.
+ */
+
+#include "config.h"
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)
+#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
+
+#define BIT_DEPTH 8
+#define PIXEL_MAX ((1 << BIT_DEPTH)-1)
+typedef uint8_t pixel;
+
+/****************************************************************************
+ * structural similarity metric
+ ****************************************************************************/
+static void ssim_4x4x2_core( const pixel *pix1, intptr_t stride1,
+ const pixel *pix2, intptr_t stride2,
+ int sums[2][4] )
+{
+ int x,y,z;
+
+ for( z = 0; z < 2; z++ )
+ {
+ uint32_t s1 = 0, s2 = 0, ss = 0, s12 = 0;
+ for( y = 0; y < 4; y++ )
+ for( x = 0; x < 4; x++ )
+ {
+ int a = pix1[x+y*stride1];
+ int b = pix2[x+y*stride2];
+ s1 += a;
+ s2 += b;
+ ss += a*a;
+ ss += b*b;
+ s12 += a*b;
+ }
+ sums[z][0] = s1;
+ sums[z][1] = s2;
+ sums[z][2] = ss;
+ sums[z][3] = s12;
+ pix1 += 4;
+ pix2 += 4;
+ }
+}
+
+static float ssim_end1( int s1, int s2, int ss, int s12 )
+{
+/* Maximum value for 10-bit is: ss*64 = (2^10-1)^2*16*4*64 = 4286582784, which will overflow in some cases.
+ * s1*s1, s2*s2, and s1*s2 also obtain this value for edge cases: ((2^10-1)*16*4)^2 = 4286582784.
+ * Maximum value for 9-bit is: ss*64 = (2^9-1)^2*16*4*64 = 1069551616, which will not overflow. */
+#if BIT_DEPTH > 9
+#define type float
+ static const float ssim_c1 = .01*.01*PIXEL_MAX*PIXEL_MAX*64;
+ static const float ssim_c2 = .03*.03*PIXEL_MAX*PIXEL_MAX*64*63;
+#else
+#define type int
+ static const int ssim_c1 = (int)(.01*.01*PIXEL_MAX*PIXEL_MAX*64 + .5);
+ static const int ssim_c2 = (int)(.03*.03*PIXEL_MAX*PIXEL_MAX*64*63 + .5);
+#endif
+ type fs1 = s1;
+ type fs2 = s2;
+ type fss = ss;
+ type fs12 = s12;
+ type vars = fss*64 - fs1*fs1 - fs2*fs2;
+ type covar = fs12*64 - fs1*fs2;
+ return (float)(2*fs1*fs2 + ssim_c1) * (float)(2*covar + ssim_c2)
+ / ((float)(fs1*fs1 + fs2*fs2 + ssim_c1) * (float)(vars + ssim_c2));
+#undef type
+}
+
+static float ssim_end4( int sum0[5][4], int sum1[5][4], int width )
+{
+ float ssim = 0.0;
+ int i;
+
+ for( 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],
+ sum0[i][3] + sum0[i+1][3] + sum1[i][3] + sum1[i+1][3] );
+ return ssim;
+}
+
+float ssim_plane(
+ pixel *pix1, intptr_t stride1,
+ pixel *pix2, intptr_t stride2,
+ int width, int height, void *buf, int *cnt )
+{
+ int z = 0;
+ int x, y;
+ float ssim = 0.0;
+ int (*sum0)[4] = buf;
+ int (*sum1)[4] = sum0 + (width >> 2) + 3;
+ width >>= 2;
+ height >>= 2;
+ for( y = 1; y < height; y++ )
+ {
+ for( ; z <= y; z++ )
+ {
+ FFSWAP( void*, sum0, sum1 );
+ for( x = 0; x < width; x+=2 )
+ ssim_4x4x2_core( &pix1[4*(x+z*stride1)], stride1, &pix2[4*(x+z*stride2)], stride2, &sum0[x] );
+ }
+ for( x = 0; x < width-1; x += 4 )
+ ssim += ssim_end4( sum0+x, sum1+x, FFMIN(4,width-x-1) );
+ }
+// *cnt = (height-1) * (width-1);
+ return ssim / ((height-1) * (width-1));
+}
+
+
+uint64_t ssd_plane( const uint8_t *pix1, const uint8_t *pix2, int size )
+{
+ uint64_t ssd = 0;
+ int i;
+ for( i=0; i<size; i++ )
+ {
+ int d = pix1[i] - pix2[i];
+ ssd += d*d;
+ }
+ return ssd;
+}
+
+static double ssd_to_psnr( uint64_t ssd, uint64_t denom )
+{
+ return -10*log((double)ssd/(denom*255*255))/log(10);
+}
+
+static double ssim_db( double ssim, double weight )
+{
+ return 10*(log(weight)/log(10)-log(weight-ssim)/log(10));
+}
+
+static void print_results(uint64_t ssd[3], double ssim[3], int frames, int w, int h)
+{
+ printf( "PSNR Y:%.3f U:%.3f V:%.3f All:%.3f | ",
+ ssd_to_psnr( ssd[0], (uint64_t)frames*w*h ),
+ ssd_to_psnr( ssd[1], (uint64_t)frames*w*h/4 ),
+ ssd_to_psnr( ssd[2], (uint64_t)frames*w*h/4 ),
+ ssd_to_psnr( ssd[0] + ssd[1] + ssd[2], (uint64_t)frames*w*h*3/2 ) );
+ printf( "SSIM Y:%.5f U:%.5f V:%.5f All:%.5f (%.5f)",
+ ssim[0] / frames,
+ ssim[1] / frames,
+ ssim[2] / frames,
+ (ssim[0]*4 + ssim[1] + ssim[2]) / (frames*6),
+ ssim_db(ssim[0] * 4 + ssim[1] + ssim[2], frames*6));
+}
+
+int main(int argc, char* argv[])
+{
+ FILE *f[2];
+ uint8_t *buf[2], *plane[2][3];
+ int *temp;
+ uint64_t ssd[3] = {0,0,0};
+ double ssim[3] = {0,0,0};
+ int frame_size, w, h;
+ int frames, seek;
+ int i;
+
+ if( argc<4 || 2 != sscanf(argv[3], "%dx%d", &w, &h) )
+ {
+ printf("tiny_ssim <file1.yuv> <file2.yuv> <width>x<height> [<seek>]\n");
+ return -1;
+ }
+
+ f[0] = fopen(argv[1], "rb");
+ f[1] = fopen(argv[2], "rb");
+ sscanf(argv[3], "%dx%d", &w, &h);
+
+ if (w<=0 || h<=0 || w*(int64_t)h >= INT_MAX/3 || 2LL*w+12 >= INT_MAX / sizeof(*temp)) {
+ fprintf(stderr, "Dimensions are too large, or invalid\n");
+ return -2;
+ }
+
+ frame_size = w*h*3LL/2;
+ for( i=0; i<2; i++ )
+ {
+ buf[i] = malloc(frame_size);
+ plane[i][0] = buf[i];
+ plane[i][1] = plane[i][0] + w*h;
+ plane[i][2] = plane[i][1] + w*h/4;
+ }
+ temp = malloc((2*w+12)*sizeof(*temp));
+ seek = argc<5 ? 0 : atoi(argv[4]);
+ fseek(f[seek<0], seek < 0 ? -seek : seek, SEEK_SET);
+
+ for( frames=0;; frames++ )
+ {
+ uint64_t ssd_one[3];
+ double ssim_one[3];
+ if( fread(buf[0], frame_size, 1, f[0]) != 1) break;
+ if( fread(buf[1], frame_size, 1, f[1]) != 1) break;
+ for( i=0; i<3; i++ )
+ {
+ ssd_one[i] = ssd_plane ( plane[0][i], plane[1][i], w*h>>2*!!i );
+ ssim_one[i] = ssim_plane( plane[0][i], w>>!!i,
+ plane[1][i], w>>!!i,
+ w>>!!i, h>>!!i, temp, NULL );
+ ssd[i] += ssd_one[i];
+ ssim[i] += ssim_one[i];
+ }
+
+ printf("Frame %d | ", frames);
+ print_results(ssd_one, ssim_one, 1, w, h);
+ printf(" \r");
+ fflush(stdout);
+ }
+
+ if( !frames ) return 0;
+
+ printf("Total %d frames | ", frames);
+ print_results(ssd, ssim, frames, w, h);
+ printf("\n");
+
+ return 0;
+}
diff --git a/tests/utils.c b/tests/utils.c
index 2fdc491f49..f2441046c3 100644
--- a/tests/utils.c
+++ b/tests/utils.c
@@ -1,18 +1,20 @@
/*
- * This file is part of Libav.
+ * copyright (c) Sebastien Bechet <s.bechet@av7.net>
*
- * Libav is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,7 +25,7 @@
#define SCALEBITS 8
#define ONE_HALF (1 << (SCALEBITS - 1))
-#define FIX(x) ((int) ((x) * (1L << SCALEBITS) + 0.5))
+#define FIX(x) ((int) ((x) * (1 << SCALEBITS) + 0.5))
#define err_if(expr) do { \
if (expr) { \
@@ -33,12 +35,12 @@
} while (0)
static void rgb24_to_yuv420p(unsigned char *lum, unsigned char *cb,
- unsigned char *cr, unsigned char *src,
+ unsigned char *cr, const unsigned char *src,
int width, int height)
{
int wrap, wrap3, x, y;
int r, g, b, r1, g1, b1;
- unsigned char *p;
+ const unsigned char *p;
wrap = width;
wrap3 = width * 3;
@@ -102,7 +104,7 @@ static void rgb24_to_yuv420p(unsigned char *lum, unsigned char *cb,
#define DEFAULT_NB_PICT 50
static void pgmyuv_save(const char *filename, int w, int h,
- unsigned char *rgb_tab)
+ const unsigned char *rgb_tab)
{
FILE *f;
int i, h2, w2;
diff --git a/tests/videogen.c b/tests/videogen.c
index 0b7f67eb18..91da8b540c 100644
--- a/tests/videogen.c
+++ b/tests/videogen.c
@@ -4,20 +4,20 @@
*
* Copyright (c) 2002 Fabrice Bellard
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -141,23 +141,37 @@ static void gen_image(int num, int w, int h)
}
}
+void print_help(const char* name)
+{
+ printf("usage: %s file|dir [w=%i] [h=%i]\n"
+ "generate a test video stream\n",
+ name, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ exit(1);
+}
+
int main(int argc, char **argv)
{
int w, h, i;
char buf[1024];
int isdir = 0;
- if (argc != 2) {
- printf("usage: %s file|dir\n"
- "generate a test video stream\n", argv[0]);
- exit(1);
+ if (argc < 2 || argc > 4) {
+ print_help(argv[0]);
}
if (!freopen(argv[1], "wb", stdout))
isdir = 1;
w = DEFAULT_WIDTH;
+ if(argc > 2) {
+ w = atoi(argv[2]);
+ if (w < 1) print_help(argv[0]);
+ }
h = DEFAULT_HEIGHT;
+ if(argc > 3) {
+ h = atoi(argv[3]);
+ if (h < 1) print_help(argv[0]);
+ }
rgb_tab = malloc(w * h * 3);
wrap = w * 3;
diff --git a/tools/aviocat.c b/tools/aviocat.c
index 59244a8e4f..3bd62b7b48 100644
--- a/tools/aviocat.c
+++ b/tools/aviocat.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tools/bisect-create b/tools/bisect-create
new file mode 100755
index 0000000000..fc60e86669
--- /dev/null
+++ b/tools/bisect-create
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+set -e
+
+if test "bisect-create" = "`basename $0`" ; then
+ echo tools/ffbisect created
+ git show master:tools/bisect-create > tools/ffbisect
+ chmod u+x tools/ffbisect
+ exit 1
+fi
+
+if ! git show master:tools/bisect-create | diff - tools/ffbisect > /dev/null ; then
+ echo updating tools/ffbisect script to HEAD.
+ git show master:tools/bisect-create > tools/ffbisect
+ chmod u+x tools/ffbisect
+ tools/ffbisect $*
+ exit 0
+fi
+
+case "$1" in
+ need)
+ case $2 in
+ ffmpeg|ffplay|ffprobe|ffserver)
+ echo $2.c >> tools/bisect.need
+ ;;
+ esac
+ ;;
+ start|reset)
+ echo . > tools/bisect.need
+ git bisect $*
+ ;;
+ skip)
+ git bisect $*
+ ;;
+ good|bad)
+ git bisect $*
+
+ until ls `cat tools/bisect.need` > /dev/null 2> /dev/null; do
+ git bisect skip || break
+ done
+ ;;
+ run)
+ shift # remove "run" from arguments
+ git bisect run sh -c "ls \`cat tools/bisect.need\` > /dev/null 2> /dev/null || exit 125; \"\$@\"" sh "$@"
+ ;;
+esac
diff --git a/tools/bookmarklets.html b/tools/bookmarklets.html
new file mode 100644
index 0000000000..9800ab5aef
--- /dev/null
+++ b/tools/bookmarklets.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!--
+ This file is part of FFmpeg.
+
+ All scripts contained in this file can be considered public domain.
+ -->
+<title>FFmpeg bookmarklets</title>
+<meta charset="UTF-8">
+<script type="text/javascript">
+function convert(js) {
+ js = js.replace(/\/\*.*?\*\//g, ""); /* comments */
+ js = js.replace(/\s+/g, " ");
+ js = js.replace(/\s+\z/, "");
+ js = "(function(){" + js + "})();void 0";
+ return "javascript:" + escape(js);
+}
+function init() {
+ var pre = document.getElementsByTagName("pre");
+ for (var i = 0; pre.length > i; i++) {
+ document.getElementById(pre[i].id + "-link").href = convert(pre[i].textContent);
+ }
+}
+</script>
+<style type="text/css">
+pre { border: solid black 1px; padding: 0.2ex; font-size: 80% }
+</style>
+</head>
+<body onload="init()">
+
+<h1>Introduction</h1>
+
+The scripts in this page are
+<a href="http://en.wikipedia.org/wiki/Bookmarklet">bookmarklets</a>: store
+their link version in a bookmark, and later activate the bookmark on a page
+to run the script.
+
+<h1>TED Talks captions</h1>
+
+<p><a id="ted_talks_captions-link" href="#">Get links to the captions</a></p>
+
+<pre id="ted_talks_captions">
+d = window.open("", "sub", "width=256,height=512,resizable=yes,scrollbars=yes").document;
+l = document.getElementById("languageCode").getElementsByTagName("option");
+for (i = 1; i &lt; l.length ; i++) {
+ d.body.appendChild(p = d.createElement("p"));
+ p.appendChild(a = d.createElement("a"));
+ a.appendChild(d.createTextNode(l[i].textContent));
+ a.href="http://www.ted.com/talks/subtitles/id/" + talkID+"/lang/" + l[i].value;
+}
+</pre>
+
+</body>
+</html>
diff --git a/tools/build_libstagefright b/tools/build_libstagefright
new file mode 100644
index 0000000000..22bb71225c
--- /dev/null
+++ b/tools/build_libstagefright
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+if [ "$NDK" = "" ]; then
+ echo NDK variable not set, assuming ${HOME}/android-ndk
+ export NDK=${HOME}/android-ndk
+fi
+
+echo "Fetching Android system headers"
+git clone --depth=1 --branch gingerbread-release https://github.com/CyanogenMod/android_frameworks_base.git ../android-source/frameworks/base
+git clone --depth=1 --branch gingerbread-release https://github.com/CyanogenMod/android_system_core.git ../android-source/system/core
+
+echo "Fetching Android libraries for linking"
+# Libraries from any froyo/gingerbread device/emulator should work
+# fine, since the symbols used should be available on most of them.
+if [ ! -d "../android-libs" ]; then
+ if [ ! -f "../update-cm-7.0.3-N1-signed.zip" ]; then
+ wget http://download.cyanogenmod.com/get/update-cm-7.0.3-N1-signed.zip -P../
+ fi
+ unzip ../update-cm-7.0.3-N1-signed.zip system/lib/* -d../
+ mv ../system/lib ../android-libs
+ rmdir ../system
+fi
+
+
+SYSROOT=$NDK/platforms/android-9/arch-arm
+# Expand the prebuilt/* path into the correct one
+TOOLCHAIN=`echo $NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/*-x86`
+export PATH=$TOOLCHAIN/bin:$PATH
+ANDROID_SOURCE=../android-source
+ANDROID_LIBS=../android-libs
+ABI="armeabi-v7a"
+
+rm -rf ../build/stagefright
+mkdir -p ../build/stagefright
+
+DEST=../build/stagefright
+FLAGS="--target-os=linux --cross-prefix=arm-linux-androideabi- --arch=arm --cpu=armv7-a"
+FLAGS="$FLAGS --sysroot=$SYSROOT"
+FLAGS="$FLAGS --disable-avdevice --disable-decoder=h264 --disable-decoder=h264_vdpau --enable-libstagefright-h264"
+
+EXTRA_CFLAGS="-I$ANDROID_SOURCE/frameworks/base/include -I$ANDROID_SOURCE/system/core/include"
+EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/media/libstagefright"
+EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/include/media/stagefright/openmax"
+EXTRA_CFLAGS="$EXTRA_CFLAGS -I$NDK/sources/cxx-stl/gnu-libstdc++/include -I$NDK/sources/cxx-stl/gnu-libstdc++/libs/$ABI/include"
+
+EXTRA_CFLAGS="$EXTRA_CFLAGS -march=armv7-a -mfloat-abi=softfp -mfpu=neon"
+EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -L$ANDROID_LIBS -Wl,-rpath-link,$ANDROID_LIBS -L$NDK/sources/cxx-stl/gnu-libstdc++/libs/$ABI"
+EXTRA_CXXFLAGS="-Wno-multichar -fno-exceptions -fno-rtti"
+DEST="$DEST/$ABI"
+FLAGS="$FLAGS --prefix=$DEST"
+
+mkdir -p $DEST
+
+echo $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" > $DEST/info.txt
+./configure $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" | tee $DEST/configuration.txt
+[ $PIPESTATUS == 0 ] || exit 1
+make clean
+make -j4 || exit 1
diff --git a/tools/clean-diff b/tools/clean-diff
new file mode 100755
index 0000000000..4600702b10
--- /dev/null
+++ b/tools/clean-diff
@@ -0,0 +1,11 @@
+#!/bin/sh
+sed '/^+[^+]/!s/ /TaBBaT/g' |\
+ expand -t $(seq -s , 9 8 200) |\
+ sed 's/TaBBaT/ /g' |\
+ sed '/^+[^+]/s/ * $//' |\
+ tr -d '\015' |\
+ tr '\n' '°' |\
+ sed 's/\(@@[^@]*@@°[^@]*\)/\n\1/g' |\
+ egrep -v '@@[^@]*@@°(( [^°]*°)|([+-][[:space:]]*°)|(-[[:space:]]*([^°]*)°\+[[:space:]]*\5°))*$' |\
+ tr -d '\n' |\
+ tr '°' '\n'
diff --git a/tools/coverity.c b/tools/coverity.c
new file mode 100644
index 0000000000..80fc1c2ad5
--- /dev/null
+++ b/tools/coverity.c
@@ -0,0 +1,42 @@
+/* Coverity Scan model
+*
+* Copyright (C) 2014 Red Hat, Inc.
+*
+* Authors:
+* Markus Armbruster <armbru@redhat.com>
+* Paolo Bonzini <pbonzini@redhat.com>
+*
+* This work is licensed under the terms of the GNU GPL, version 2 or, at your
+* option, any later version. See the COPYING file in the top-level directory.
+*/
+/*
+* This is the source code for our Coverity user model file. The
+* purpose of user models is to increase scanning accuracy by explaining
+* code Coverity can't see (out of tree libraries) or doesn't
+* sufficiently understand. Better accuracy means both fewer false
+* positives and more true defects. Memory leaks in particular.
+*
+* - A model file can't import any header files. Some built-in primitives are
+* available but not wchar_t, NULL etc.
+* - Modeling doesn't need full structs and typedefs. Rudimentary structs
+* and similar types are sufficient.
+* - An uninitialized local variable signifies that the variable could be
+* any value.
+*
+* The model file must be uploaded by an admin in the analysis settings of
+* https://scan.coverity.com/projects/54
+*
+* above text is based on https://github.com/qemu/qemu/blob/master/scripts/coverity-model.c
+*/
+
+#define NULL (void *)0
+
+// Based on https://scan.coverity.com/models
+void *av_malloc(size_t size) {
+ int has_memory;
+ __coverity_negative_sink__(size);
+ if(has_memory)
+ return __coverity_alloc__(size);
+ else
+ return 0;
+}
diff --git a/tools/crypto_bench.c b/tools/crypto_bench.c
new file mode 100644
index 0000000000..79629bcaf8
--- /dev/null
+++ b/tools/crypto_bench.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2013 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Optional external libraries; can be enabled using:
+ * make VERSUS=crypto+gcrypt+tomcrypt tools/crypto_bench */
+#define USE_crypto 0x01 /* OpenSSL's libcrypto */
+#define USE_gcrypt 0x02 /* GnuTLS's libgcrypt */
+#define USE_tomcrypt 0x04 /* LibTomCrypt */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "libavutil/avutil.h"
+#include "libavutil/avstring.h"
+#include "libavutil/crc.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/timer.h"
+
+#ifndef AV_READ_TIME
+#define AV_READ_TIME(x) 0
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h> /* for getopt */
+#endif
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+#define MAX_INPUT_SIZE 1048576
+#define MAX_OUTPUT_SIZE 128
+
+static const char *enabled_libs;
+static const char *enabled_algos;
+static unsigned specified_runs;
+
+static const uint8_t *hardcoded_key = "FFmpeg is the best program ever.";
+
+static void fatal_error(const char *tag)
+{
+ av_log(NULL, AV_LOG_ERROR, "Fatal error: %s\n", tag);
+ exit(1);
+}
+
+struct hash_impl {
+ const char *lib;
+ const char *name;
+ void (*run)(uint8_t *output, const uint8_t *input, unsigned size);
+ const char *output;
+};
+
+/***************************************************************************
+ * lavu: libavutil
+ ***************************************************************************/
+
+#include "libavutil/md5.h"
+#include "libavutil/sha.h"
+#include "libavutil/sha512.h"
+#include "libavutil/ripemd.h"
+#include "libavutil/aes.h"
+#include "libavutil/camellia.h"
+#include "libavutil/cast5.h"
+#include "libavutil/twofish.h"
+
+#define IMPL_USE_lavu IMPL_USE
+
+static void run_lavu_md5(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ av_md5_sum(output, input, size);
+}
+
+#define DEFINE_LAVU_MD(suffix, type, namespace, hsize) \
+static void run_lavu_ ## suffix(uint8_t *output, \
+ const uint8_t *input, unsigned size) \
+{ \
+ static struct type *h; \
+ if (!h && !(h = av_ ## namespace ## _alloc())) \
+ fatal_error("out of memory"); \
+ av_ ## namespace ## _init(h, hsize); \
+ av_ ## namespace ## _update(h, input, size); \
+ av_ ## namespace ## _final(h, output); \
+}
+
+DEFINE_LAVU_MD(sha1, AVSHA, sha, 160);
+DEFINE_LAVU_MD(sha256, AVSHA, sha, 256);
+DEFINE_LAVU_MD(sha512, AVSHA512, sha512, 512);
+DEFINE_LAVU_MD(ripemd160, AVRIPEMD, ripemd, 160);
+
+static void run_lavu_aes128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static struct AVAES *aes;
+ if (!aes && !(aes = av_aes_alloc()))
+ fatal_error("out of memory");
+ av_aes_init(aes, hardcoded_key, 128, 0);
+ av_aes_crypt(aes, output, input, size >> 4, NULL, 0);
+}
+
+static void run_lavu_camellia(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static struct AVCAMELLIA *camellia;
+ if (!camellia && !(camellia = av_camellia_alloc()))
+ fatal_error("out of memory");
+ av_camellia_init(camellia, hardcoded_key, 128);
+ av_camellia_crypt(camellia, output, input, size >> 4, NULL, 0);
+}
+
+static void run_lavu_cast128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static struct AVCAST5 *cast;
+ if (!cast && !(cast = av_cast5_alloc()))
+ fatal_error("out of memory");
+ av_cast5_init(cast, hardcoded_key, 128);
+ av_cast5_crypt(cast, output, input, size >> 3, 0);
+}
+
+static void run_lavu_twofish(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static struct AVTWOFISH *twofish;
+ if (!twofish && !(twofish = av_twofish_alloc()))
+ fatal_error("out of memory");
+ av_twofish_init(twofish, hardcoded_key, 128);
+ av_twofish_crypt(twofish, output, input, size >> 4, NULL, 0);
+}
+/***************************************************************************
+ * crypto: OpenSSL's libcrypto
+ ***************************************************************************/
+
+#if (USE_EXT_LIBS) & USE_crypto
+
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/ripemd.h>
+#include <openssl/aes.h>
+#include <openssl/camellia.h>
+#include <openssl/cast.h>
+
+#define DEFINE_CRYPTO_WRAPPER(suffix, function) \
+static void run_crypto_ ## suffix(uint8_t *output, \
+ const uint8_t *input, unsigned size) \
+{ \
+ function(input, size, output); \
+}
+
+DEFINE_CRYPTO_WRAPPER(md5, MD5)
+DEFINE_CRYPTO_WRAPPER(sha1, SHA1)
+DEFINE_CRYPTO_WRAPPER(sha256, SHA256)
+DEFINE_CRYPTO_WRAPPER(sha512, SHA512)
+DEFINE_CRYPTO_WRAPPER(ripemd160, RIPEMD160)
+
+static void run_crypto_aes128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ AES_KEY aes;
+ unsigned i;
+
+ AES_set_encrypt_key(hardcoded_key, 128, &aes);
+ size -= 15;
+ for (i = 0; i < size; i += 16)
+ AES_encrypt(input + i, output + i, &aes);
+}
+
+static void run_crypto_camellia(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ CAMELLIA_KEY camellia;
+ unsigned i;
+
+ Camellia_set_key(hardcoded_key, 128, &camellia);
+ size -= 15;
+ for (i = 0; i < size; i += 16)
+ Camellia_ecb_encrypt(input + i, output + i, &camellia, 1);
+}
+
+static void run_crypto_cast128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ CAST_KEY cast;
+ unsigned i;
+
+ CAST_set_key(&cast, 16, hardcoded_key);
+ for (i = 0; i < size; i += 8)
+ CAST_ecb_encrypt(input + i, output + i, &cast, 1);
+}
+
+#define IMPL_USE_crypto(...) IMPL_USE(__VA_ARGS__)
+#else
+#define IMPL_USE_crypto(...) /* ignore */
+#endif
+
+/***************************************************************************
+ * gcrypt: GnuTLS's libgcrypt
+ ***************************************************************************/
+
+#if (USE_EXT_LIBS) & USE_gcrypt
+
+#include <gcrypt.h>
+
+#define DEFINE_GCRYPT_WRAPPER(suffix, algo) \
+static void run_gcrypt_ ## suffix(uint8_t *output, \
+ const uint8_t *input, unsigned size) \
+{ \
+ gcry_md_hash_buffer(GCRY_MD_ ## algo, output, input, size); \
+}
+
+DEFINE_GCRYPT_WRAPPER(md5, MD5)
+DEFINE_GCRYPT_WRAPPER(sha1, SHA1)
+DEFINE_GCRYPT_WRAPPER(sha256, SHA256)
+DEFINE_GCRYPT_WRAPPER(sha512, SHA512)
+DEFINE_GCRYPT_WRAPPER(ripemd160, RMD160)
+
+static void run_gcrypt_aes128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static gcry_cipher_hd_t aes;
+ if (!aes)
+ gcry_cipher_open(&aes, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
+ gcry_cipher_setkey(aes, hardcoded_key, 16);
+ gcry_cipher_encrypt(aes, output, size, input, size);
+}
+
+static void run_gcrypt_camellia(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static gcry_cipher_hd_t camellia;
+ if (!camellia)
+ gcry_cipher_open(&camellia, GCRY_CIPHER_CAMELLIA128, GCRY_CIPHER_MODE_ECB, 0);
+ gcry_cipher_setkey(camellia, hardcoded_key, 16);
+ gcry_cipher_encrypt(camellia, output, size, input, size);
+}
+
+static void run_gcrypt_cast128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static gcry_cipher_hd_t cast;
+ if (!cast)
+ gcry_cipher_open(&cast, GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_ECB, 0);
+ gcry_cipher_setkey(cast, hardcoded_key, 16);
+ gcry_cipher_encrypt(cast, output, size, input, size);
+}
+
+static void run_gcrypt_twofish(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ static gcry_cipher_hd_t twofish;
+ if (!twofish)
+ gcry_cipher_open(&twofish, GCRY_CIPHER_TWOFISH128, GCRY_CIPHER_MODE_ECB, 0);
+ gcry_cipher_setkey(twofish, hardcoded_key, 16);
+ gcry_cipher_encrypt(twofish, output, size, input, size);
+}
+
+#define IMPL_USE_gcrypt(...) IMPL_USE(__VA_ARGS__)
+#else
+#define IMPL_USE_gcrypt(...) /* ignore */
+#endif
+
+/***************************************************************************
+ * tomcrypt: LibTomCrypt
+ ***************************************************************************/
+
+#if (USE_EXT_LIBS) & USE_tomcrypt
+
+#include <tomcrypt.h>
+
+#define DEFINE_TOMCRYPT_WRAPPER(suffix, namespace, algo) \
+static void run_tomcrypt_ ## suffix(uint8_t *output, \
+ const uint8_t *input, unsigned size) \
+{ \
+ hash_state md; \
+ namespace ## _init(&md); \
+ namespace ## _process(&md, input, size); \
+ namespace ## _done(&md, output); \
+}
+
+DEFINE_TOMCRYPT_WRAPPER(md5, md5, MD5)
+DEFINE_TOMCRYPT_WRAPPER(sha1, sha1, SHA1)
+DEFINE_TOMCRYPT_WRAPPER(sha256, sha256, SHA256)
+DEFINE_TOMCRYPT_WRAPPER(sha512, sha512, SHA512)
+DEFINE_TOMCRYPT_WRAPPER(ripemd160, rmd160, RIPEMD160)
+
+static void run_tomcrypt_aes128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ symmetric_key aes;
+ unsigned i;
+
+ aes_setup(hardcoded_key, 16, 0, &aes);
+ size -= 15;
+ for (i = 0; i < size; i += 16)
+ aes_ecb_encrypt(input + i, output + i, &aes);
+}
+
+static void run_tomcrypt_camellia(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ symmetric_key camellia;
+ unsigned i;
+
+ camellia_setup(hardcoded_key, 16, 0, &camellia);
+ size -= 15;
+ for (i = 0; i < size; i += 16)
+ camellia_ecb_encrypt(input + i, output + i, &camellia);
+}
+
+static void run_tomcrypt_cast128(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ symmetric_key cast;
+ unsigned i;
+
+ cast5_setup(hardcoded_key, 16, 0, &cast);
+ for (i = 0; i < size; i += 8)
+ cast5_ecb_encrypt(input + i, output + i, &cast);
+}
+
+static void run_tomcrypt_twofish(uint8_t *output,
+ const uint8_t *input, unsigned size)
+{
+ symmetric_key twofish;
+ unsigned i;
+
+ twofish_setup(hardcoded_key, 16, 0, &twofish);
+ size -= 15;
+ for (i = 0; i < size; i += 16)
+ twofish_ecb_encrypt(input + i, output + i, &twofish);
+}
+
+
+#define IMPL_USE_tomcrypt(...) IMPL_USE(__VA_ARGS__)
+#else
+#define IMPL_USE_tomcrypt(...) /* ignore */
+#endif
+
+/***************************************************************************
+ * Driver code
+ ***************************************************************************/
+
+static unsigned crc32(const uint8_t *data, unsigned size)
+{
+ return av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, data, size);
+}
+
+static void run_implementation(const uint8_t *input, uint8_t *output,
+ struct hash_impl *impl, unsigned size)
+{
+ uint64_t t0, t1;
+ unsigned nruns = specified_runs ? specified_runs : (1 << 30) / size;
+ unsigned outlen = 0, outcrc = 0;
+ unsigned i, j, val;
+ double mtime, ttime = 0, ttime2 = 0, stime;
+ uint8_t outref[MAX_OUTPUT_SIZE];
+
+ if (enabled_libs && !av_stristr(enabled_libs, impl->lib) ||
+ enabled_algos && !av_stristr(enabled_algos, impl->name))
+ return;
+ if (!sscanf(impl->output, "crc:%x", &outcrc)) {
+ outlen = strlen(impl->output) / 2;
+ for (i = 0; i < outlen; i++) {
+ sscanf(impl->output + i * 2, "%02x", &val);
+ outref[i] = val;
+ }
+ }
+ for (i = 0; i < 8; i++) /* heat caches */
+ impl->run(output, input, size);
+ for (i = 0; i < nruns; i++) {
+ memset(output, 0, size); /* avoid leftovers from previous runs */
+ t0 = AV_READ_TIME();
+ impl->run(output, input, size);
+ t1 = AV_READ_TIME();
+ if (outlen ? memcmp(output, outref, outlen) :
+ crc32(output, size) != outcrc) {
+ fprintf(stderr, "Expected: ");
+ if (outlen)
+ for (j = 0; j < outlen; j++)
+ fprintf(stderr, "%02x", output[j]);
+ else
+ fprintf(stderr, "%08x", crc32(output, size));
+ fprintf(stderr, "\n");
+ fatal_error("output mismatch");
+ }
+ mtime = (double)(t1 - t0) / size;
+ ttime += mtime;
+ ttime2 += mtime * mtime;
+ }
+
+ ttime /= nruns;
+ ttime2 /= nruns;
+ stime = sqrt(ttime2 - ttime * ttime);
+ printf("%-10s %-12s size: %7d runs: %6d time: %8.3f +- %.3f\n",
+ impl->lib, impl->name, size, nruns, ttime, stime);
+ fflush(stdout);
+}
+
+#define IMPL_USE(lib, name, symbol, output) \
+ { #lib, name, run_ ## lib ## _ ## symbol, output },
+#define IMPL(lib, ...) IMPL_USE_ ## lib(lib, __VA_ARGS__)
+#define IMPL_ALL(...) \
+ IMPL(lavu, __VA_ARGS__) \
+ IMPL(crypto, __VA_ARGS__) \
+ IMPL(gcrypt, __VA_ARGS__) \
+ IMPL(tomcrypt, __VA_ARGS__)
+
+struct hash_impl implementations[] = {
+ IMPL_ALL("MD5", md5, "aa26ff5b895356bcffd9292ba9f89e66")
+ IMPL_ALL("SHA-1", sha1, "1fd8bd1fa02f5b0fe916b0d71750726b096c5744")
+ IMPL_ALL("SHA-256", sha256, "14028ac673b3087e51a1d407fbf0df4deeec8f217119e13b07bf2138f93db8c5")
+ IMPL_ALL("SHA-512", sha512, "3afdd44a80d99af15c87bd724cb717243193767835ce866dd5d58c02d674bb57"
+ "7c25b9e118c200a189fcd5a01ef106a4e200061f3e97dbf50ba065745fd46bef")
+ IMPL_ALL("RIPEMD-160", ripemd160, "62a5321e4fc8784903bb43ab7752c75f8b25af00")
+ IMPL_ALL("AES-128", aes128, "crc:ff6bc888")
+ IMPL_ALL("CAMELLIA", camellia, "crc:7abb59a7")
+ IMPL_ALL("CAST-128", cast128, "crc:456aa584")
+ IMPL(lavu, "TWOFISH", twofish, "crc:9edbd5c1")
+ IMPL(gcrypt, "TWOFISH", twofish, "crc:9edbd5c1")
+ IMPL(tomcrypt, "TWOFISH", twofish, "crc:9edbd5c1")
+};
+
+int main(int argc, char **argv)
+{
+ uint8_t *input = av_malloc(MAX_INPUT_SIZE * 2);
+ uint8_t *output = input + MAX_INPUT_SIZE;
+ unsigned i, impl, size;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "hl:a:r:")) != -1) {
+ switch (opt) {
+ case 'l':
+ enabled_libs = optarg;
+ break;
+ case 'a':
+ enabled_algos = optarg;
+ break;
+ case 'r':
+ specified_runs = strtol(optarg, NULL, 0);
+ break;
+ case 'h':
+ default:
+ fprintf(stderr, "Usage: %s [-l libs] [-a algos] [-r runs]\n",
+ argv[0]);
+ if ((USE_EXT_LIBS)) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s%s%s",
+ ((USE_EXT_LIBS) & USE_crypto) ? "+crypto" : "",
+ ((USE_EXT_LIBS) & USE_gcrypt) ? "+gcrypt" : "",
+ ((USE_EXT_LIBS) & USE_tomcrypt) ? "+tomcrypt" : "");
+ fprintf(stderr, "Built with the following external libraries:\n"
+ "make VERSUS=%s\n", buf + 1);
+ } else {
+ fprintf(stderr, "Built without external libraries; use\n"
+ "make VERSUS=crypto+gcrypt+tomcrypt tools/crypto_bench\n"
+ "to enable them.\n");
+ }
+ exit(opt != 'h');
+ }
+ }
+
+ if (!input)
+ fatal_error("out of memory");
+ for (i = 0; i < MAX_INPUT_SIZE; i += 4)
+ AV_WB32(input + i, i);
+
+ size = MAX_INPUT_SIZE;
+ for (impl = 0; impl < FF_ARRAY_ELEMS(implementations); impl++)
+ run_implementation(input, output, &implementations[impl], size);
+
+ av_free(input);
+
+ return 0;
+}
diff --git a/tools/cws2fws.c b/tools/cws2fws.c
index 74588c10a6..d6cd2edd78 100644
--- a/tools/cws2fws.c
+++ b/tools/cws2fws.c
@@ -22,7 +22,7 @@
#ifdef DEBUG
#define dbgprintf printf
#else
-#define dbgprintf(...)
+#define dbgprintf(...) do { if (0) printf(__VA_ARGS__); } while (0)
#endif
int main(int argc, char *argv[])
@@ -62,7 +62,10 @@ int main(int argc, char *argv[])
return 1;
}
- fstat(fd_in, &statbuf);
+ if (fstat(fd_in, &statbuf) < 0) {
+ perror("fstat failed");
+ return 1;
+ }
comp_len = statbuf.st_size;
uncomp_len = buf_in[4] | (buf_in[5] << 8) | (buf_in[6] << 16) | (buf_in[7] << 24);
@@ -79,7 +82,10 @@ int main(int argc, char *argv[])
zstream.zalloc = NULL;
zstream.zfree = NULL;
zstream.opaque = NULL;
- inflateInit(&zstream);
+ if (inflateInit(&zstream) != Z_OK) {
+ fprintf(stderr, "inflateInit failed\n");
+ return 1;
+ }
for (i = 0; i < comp_len - 8;) {
int ret, len = read(fd_in, &buf_in, 1024);
@@ -125,8 +131,8 @@ int main(int argc, char *argv[])
buf_in[2] = ((zstream.total_out + 8) >> 16) & 0xff;
buf_in[3] = ((zstream.total_out + 8) >> 24) & 0xff;
- lseek(fd_out, 4, SEEK_SET);
- if (write(fd_out, &buf_in, 4) < 4) {
+ if ( lseek(fd_out, 4, SEEK_SET) < 0
+ || write(fd_out, &buf_in, 4) < 4) {
perror("Error writing output file");
return 1;
}
diff --git a/tools/dvd2concat b/tools/dvd2concat
new file mode 100755
index 0000000000..02371e0997
--- /dev/null
+++ b/tools/dvd2concat
@@ -0,0 +1,127 @@
+#!/usr/bin/env perl
+
+# Copyright (c) 2014 Nicolas George
+#
+# This file is part of FFmpeg.
+#
+# FFmpeg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+=head1 NAME
+
+dvd2concat - create a concat script for a DVD title
+
+=head1 SYNOPSIS
+
+tools/dvd2concat I<path/to/dvd/structure> > I<file.concat>
+
+=head1 DESCRIPTION
+
+This script uses B<lsdvd> to produce concat script for a DVD title.
+The resulting script can be used to play the DVD using B<ffplay>, to
+transcode it using B<ffmpeg> or any other similar use.
+
+I<path/to/dvd/structure> is the path to the DVD structure hierarchy; it
+normally contains a directory named B<VIDEO_TS>. It must not be encrypted
+with CSS.
+
+I<file.concat> is the output file. It can be used a input to ffmpeg.
+It will require the B<-safe 0> option.
+
+=cut
+
+use strict;
+use warnings;
+use Getopt::Long ":config" => "require_order";
+use Pod::Usage;
+
+my $title;
+
+GetOptions (
+ "help|usage|?|h" => sub { pod2usage({ -verbose => 1, -exitval => 0 }) },
+ "manpage|m" => sub { pod2usage({ -verbose => 2, -exitval => 0 }) },
+ "title|t=i" => \$title,
+) and @ARGV == 1 or pod2usage({ -verbose => 1, -exitval => 1 });
+my ($path) = @ARGV;
+
+my $lsdvd_message =
+"Make sure your lsdvd version has the two following patches applied:\n" .
+"http://sourceforge.net/p/lsdvd/feature-requests/1/\n" .
+"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=603826\n";
+
+my $lsdvd = do {
+ open my $l, "-|", "lsdvd", "-Op", "-x", $path
+ or die "You need to install lsdvd for this script to work.\n$lsdvd_message";
+ local $/;
+ <$l>;
+};
+my %lsdvd = eval $lsdvd;
+die $@ if $@;
+
+if (!defined $title) {
+ $title = $lsdvd{longest_track};
+ warn "Using longest title $title\n";
+}
+my $track = $lsdvd{track}[$title - 1]
+ or die "Title $title does not exist (1-", scalar(@{$lsdvd{track}}), ")\n";
+my $vts_base = sprintf "%s/VIDEO_TS/VTS_%02d_", $path, $track->{vts};
+my @frag;
+for my $i (1 .. 9) {
+ my $file = sprintf "%s%d.VOB", $vts_base, $i;
+ my $size = -s $file or last;
+ push @frag, { file => $file, size => $size >> 11 };
+}
+
+my $concat = "ffconcat version 1.0\n";
+$concat .= "\nstream\nexact_stream_id 0x1E0\n";
+for my $audio (@{$track->{audio}}) {
+ $concat .= "\nstream\nexact_stream_id " . $audio->{streamid} . "\n";
+}
+for my $subp (@{$track->{subp}}) {
+ $concat .= "\nstream\nexact_stream_id " . $subp->{streamid} . "\n";
+}
+for my $cell (@{$track->{cell}}) {
+ my $off = $cell->{first_sector};
+ die "Your lsdvd version does not print cell sectors.\n$lsdvd_message"
+ unless defined $off;
+ my $size = $cell->{last_sector} + 1 - $cell->{first_sector};
+
+ my $frag = 0;
+ while ($frag < @frag) {
+ last if $off < $frag[$frag]->{size};
+ $off -= $frag[$frag++]->{size};
+ }
+ die "Cell beyond VOB data\n" unless $frag < @frag;
+ my $cur_off = $off;
+ my $cur_size = $size;
+ my @files;
+ while ($cur_size > $frag[$frag]->{size} - $cur_off) {
+ push @files, $frag[$frag]->{file};
+ $cur_size -= $frag[$frag]->{size} - $cur_off;
+ $cur_off = 0;
+ die "Cell end beyond VOB data\n" unless ++$frag < @frag;
+ }
+ push @files, $frag[$frag]->{file};
+ my $file = @files == 1 ? $files[0] : "concat:" . join("|", @files);
+ my $start = $off << 11;
+ my $end = ($off + $size) << 11;
+ $file = "subfile,,start,${start},end,${end},,:$file";
+
+ my $dur = int(1000 * $cell->{length});
+ $concat .= sprintf "\nfile '%s'\nduration %02d:%02d:%02d.%03d\n", $file,
+ int($dur / 3600000), int($dur / 60000) % 60, int($dur / 1000) % 60,
+ $dur % 1000;
+}
+
+print $concat;
diff --git a/tools/enum_options.c b/tools/enum_options.c
new file mode 100644
index 0000000000..c2a295cad6
--- /dev/null
+++ b/tools/enum_options.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2011 Anton Khirnov
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * enumerate avoptions and format them in texinfo format
+ */
+
+#include <string.h>
+
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+
+static void print_usage(void)
+{
+ fprintf(stderr, "Usage: enum_options type\n"
+ "type: format codec\n");
+ exit(1);
+}
+
+static void print_option(const AVClass *class, const AVOption *o)
+{
+ printf("@item -%s @var{", o->name);
+ switch (o->type) {
+ case FF_OPT_TYPE_BINARY: printf("hexadecimal string"); break;
+ case FF_OPT_TYPE_STRING: printf("string"); break;
+ case FF_OPT_TYPE_INT:
+ case FF_OPT_TYPE_INT64: printf("integer"); break;
+ case FF_OPT_TYPE_FLOAT:
+ case FF_OPT_TYPE_DOUBLE: printf("float"); break;
+ case FF_OPT_TYPE_RATIONAL: printf("rational number"); break;
+ case FF_OPT_TYPE_FLAGS: printf("flags"); break;
+ default: printf("value"); break;
+ }
+ printf("} (@emph{");
+
+ if (o->flags & AV_OPT_FLAG_ENCODING_PARAM) {
+ printf("input");
+ if (o->flags & AV_OPT_FLAG_ENCODING_PARAM)
+ printf("/");
+ }
+ if (o->flags & AV_OPT_FLAG_ENCODING_PARAM)
+ printf("output");
+
+ printf("})\n");
+ if (o->help)
+ printf("%s\n", o->help);
+
+ if (o->unit) {
+ const AVOption *u = NULL;
+ printf("\nPossible values:\n@table @samp\n");
+
+ while ((u = av_next_option(&class, u)))
+ if (u->type == FF_OPT_TYPE_CONST && u->unit && !strcmp(u->unit, o->unit))
+ printf("@item %s\n%s\n", u->name, u->help ? u->help : "");
+ printf("@end table\n");
+ }
+}
+
+static void show_opts(const AVClass *class)
+{
+ const AVOption *o = NULL;
+
+ printf("@table @option\n");
+ while ((o = av_next_option(&class, o)))
+ if (o->type != FF_OPT_TYPE_CONST)
+ print_option(class, o);
+ printf("@end table\n");
+}
+
+static void show_format_opts(void)
+{
+ AVInputFormat *iformat = NULL;
+ AVOutputFormat *oformat = NULL;
+
+ printf("@section Generic format AVOptions\n");
+ show_opts(avformat_get_class());
+
+ printf("@section Format-specific AVOptions\n");
+ while ((iformat = av_iformat_next(iformat))) {
+ if (!iformat->priv_class)
+ continue;
+ printf("@subsection %s AVOptions\n", iformat->priv_class->class_name);
+ show_opts(iformat->priv_class);
+ }
+ while ((oformat = av_oformat_next(oformat))) {
+ if (!oformat->priv_class)
+ continue;
+ printf("@subsection %s AVOptions\n", oformat->priv_class->class_name);
+ show_opts(oformat->priv_class);
+ }
+}
+
+static void show_codec_opts(void)
+{
+ AVCodec *c = NULL;
+
+ printf("@section Generic codec AVOptions\n");
+ show_opts(avcodec_get_class());
+
+ printf("@section Codec-specific AVOptions\n");
+ while ((c = av_codec_next(c))) {
+ if (!c->priv_class)
+ continue;
+ printf("@subsection %s AVOptions\n", c->priv_class->class_name);
+ show_opts(c->priv_class);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 2)
+ print_usage();
+
+ av_register_all();
+
+ if (!strcmp(argv[1], "format"))
+ show_format_opts();
+ else if (!strcmp(argv[1], "codec"))
+ show_codec_opts();
+ else
+ print_usage();
+
+ return 0;
+}
diff --git a/tools/ffescape.c b/tools/ffescape.c
new file mode 100644
index 0000000000..0530d28c6d
--- /dev/null
+++ b/tools/ffescape.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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"
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#include "libavutil/log.h"
+#include "libavutil/bprint.h"
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+/**
+ * @file
+ * escaping utility
+ */
+
+static void usage(void)
+{
+ printf("Escape an input string, adopting the av_get_token() escaping logic\n");
+ printf("usage: ffescape [OPTIONS]\n");
+ printf("\n"
+ "Options:\n"
+ "-e echo each input line on output\n"
+ "-f flag select an escape flag, can assume the values 'whitespace' and 'strict'\n"
+ "-h print this help\n"
+ "-i INFILE set INFILE as input file, stdin if omitted\n"
+ "-l LEVEL set the number of escaping levels, 1 if omitted\n"
+ "-m ESCAPE_MODE select escape mode between 'auto', 'backslash', 'quote'\n"
+ "-o OUTFILE set OUTFILE as output file, stdout if omitted\n"
+ "-p PROMPT set output prompt, is '=> ' by default\n"
+ "-s SPECIAL_CHARS set the list of special characters\n");
+}
+
+int main(int argc, char **argv)
+{
+ AVBPrint src;
+ char *src_buf, *dst_buf;
+ const char *outfilename = NULL, *infilename = NULL;
+ FILE *outfile = NULL, *infile = NULL;
+ const char *prompt = "=> ";
+ enum AVEscapeMode escape_mode = AV_ESCAPE_MODE_AUTO;
+ int escape_flags = 0;
+ int level = 1;
+ int echo = 0;
+ char *special_chars = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "ef:hi:l:o:m:p:s:")) != -1) {
+ switch (c) {
+ case 'e':
+ echo = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ infilename = optarg;
+ break;
+ case 'f':
+ if (!strcmp(optarg, "whitespace")) escape_flags |= AV_ESCAPE_FLAG_WHITESPACE;
+ else if (!strcmp(optarg, "strict")) escape_flags |= AV_ESCAPE_FLAG_STRICT;
+ else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -f, "
+ "valid arguments are 'whitespace', and 'strict'\n", optarg);
+ return 1;
+ }
+ break;
+ case 'l':
+ {
+ char *tail;
+ long int li = strtol(optarg, &tail, 10);
+ if (*tail || li > INT_MAX || li < 0) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -l, argument must be a non negative integer\n",
+ optarg);
+ return 1;
+ }
+ level = li;
+ break;
+ }
+ case 'm':
+ if (!strcmp(optarg, "auto")) escape_mode = AV_ESCAPE_MODE_AUTO;
+ else if (!strcmp(optarg, "backslash")) escape_mode = AV_ESCAPE_MODE_BACKSLASH;
+ else if (!strcmp(optarg, "quote")) escape_mode = AV_ESCAPE_MODE_QUOTE;
+ else {
+ av_log(NULL, AV_LOG_ERROR,
+ "Invalid value '%s' for option -m, "
+ "valid arguments are 'backslash', and 'quote'\n", optarg);
+ return 1;
+ }
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'p':
+ prompt = optarg;
+ break;
+ case 's':
+ special_chars = optarg;
+ break;
+ case '?':
+ return 1;
+ }
+ }
+
+ if (!infilename || !strcmp(infilename, "-")) {
+ infilename = "stdin";
+ infile = stdin;
+ } else {
+ infile = fopen(infilename, "r");
+ }
+ if (!infile) {
+ av_log(NULL, AV_LOG_ERROR, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
+ return 1;
+ }
+
+ if (!outfilename || !strcmp(outfilename, "-")) {
+ outfilename = "stdout";
+ outfile = stdout;
+ } else {
+ outfile = fopen(outfilename, "w");
+ }
+ if (!outfile) {
+ av_log(NULL, AV_LOG_ERROR, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
+ return 1;
+ }
+
+ /* grab the input and store it in src */
+ av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
+ while ((c = fgetc(infile)) != EOF)
+ av_bprint_chars(&src, c, 1);
+ av_bprint_chars(&src, 0, 1);
+
+ if (!av_bprint_is_complete(&src)) {
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
+ av_bprint_finalize(&src, NULL);
+ return 1;
+ }
+ av_bprint_finalize(&src, &src_buf);
+
+ if (echo)
+ fprintf(outfile, "%s", src_buf);
+
+ /* escape */
+ dst_buf = src_buf;
+ while (level--) {
+ if (av_escape(&dst_buf, src_buf, special_chars, escape_mode, escape_flags) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Could not escape string\n");
+ return 1;
+ }
+ av_free(src_buf);
+ src_buf = dst_buf;
+ }
+
+ fprintf(outfile, "%s%s", prompt, dst_buf);
+ av_free(dst_buf);
+ return 0;
+}
diff --git a/tools/ffeval.c b/tools/ffeval.c
new file mode 100644
index 0000000000..944f374727
--- /dev/null
+++ b/tools/ffeval.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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"
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#include "libavutil/eval.h"
+#include "libavutil/mem.h"
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+/**
+ * @file
+ * simple arithmetic expression evaluator
+ */
+
+static void usage(void)
+{
+ printf("Simple expression evalutor, please *don't* turn me to a feature-complete language interpreter\n");
+ printf("usage: ffeval [OPTIONS]\n");
+ printf("\n"
+ "Options:\n"
+ "-e echo each input line on output\n"
+ "-h print this help\n"
+ "-i INFILE set INFILE as input file, stdin if omitted\n"
+ "-o OUTFILE set OUTFILE as output file, stdout if omitted\n"
+ "-p PROMPT set output prompt\n");
+}
+
+int main(int argc, char **argv)
+{
+ int buf_size = 0;
+ char *buf = NULL;
+ const char *outfilename = NULL, *infilename = NULL;
+ FILE *outfile = NULL, *infile = NULL;
+ const char *prompt = "=> ";
+ int count = 0, echo = 0;
+ int c;
+
+#define GROW_ARRAY() \
+ do { \
+ if (!av_dynarray2_add((void **)&buf, &buf_size, 1, NULL)) { \
+ av_log(NULL, AV_LOG_ERROR, \
+ "Memory allocation problem occurred\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+ GROW_ARRAY();
+ while ((c = getopt(argc, argv, "ehi:o:p:")) != -1) {
+ switch (c) {
+ case 'e':
+ echo = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ infilename = optarg;
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'p':
+ prompt = optarg;
+ break;
+ case '?':
+ return 1;
+ }
+ }
+
+ if (!infilename || !strcmp(infilename, "-")) {
+ infilename = "stdin";
+ infile = stdin;
+ } else {
+ infile = fopen(infilename, "r");
+ }
+ if (!infile) {
+ fprintf(stderr, "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
+ return 1;
+ }
+
+ if (!outfilename || !strcmp(outfilename, "-")) {
+ outfilename = "stdout";
+ outfile = stdout;
+ } else {
+ outfile = fopen(outfilename, "w");
+ }
+ if (!outfile) {
+ fprintf(stderr, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno));
+ return 1;
+ }
+
+ while ((c = fgetc(infile)) != EOF) {
+ if (c == '\n') {
+ double d;
+
+ buf[count] = 0;
+ if (buf[0] != '#') {
+ int ret = av_expr_parse_and_eval(&d, buf,
+ NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, 0, NULL);
+ if (echo)
+ fprintf(outfile, "%s ", buf);
+ if (ret >= 0) fprintf(outfile, "%s%f\n", prompt, d);
+ else fprintf(outfile, "%s%f (%s)\n", prompt, d, av_err2str(ret));
+ }
+ count = 0;
+ } else {
+ if (count >= buf_size-1)
+ GROW_ARRAY();
+ buf[count++] = c;
+ }
+ }
+
+ av_free(buf);
+ return 0;
+}
diff --git a/tools/ffhash.c b/tools/ffhash.c
new file mode 100644
index 0000000000..6942527732
--- /dev/null
+++ b/tools/ffhash.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2002 Fabrice Bellard
+ * Copyright (c) 2013 Michael Niedermayer
+ * Copyright (c) 2013 James Almer
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "libavutil/avstring.h"
+#include "libavutil/error.h"
+#include "libavutil/hash.h"
+#include "libavutil/mem.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#if HAVE_IO_H
+#include <io.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#define SIZE 65536
+
+static struct AVHashContext *hash;
+static int out_b64;
+
+static void usage(void)
+{
+ int i = 0;
+ const char *name;
+
+ printf("usage: ffhash [b64:]algorithm [input]...\n");
+ printf("Supported hash algorithms:");
+ do {
+ name = av_hash_names(i);
+ if (name)
+ printf(" %s", name);
+ i++;
+ } while(name);
+ printf("\n");
+}
+
+static void finish(void)
+{
+ char res[2 * AV_HASH_MAX_SIZE + 4];
+
+ printf("%s=", av_hash_get_name(hash));
+ if (out_b64) {
+ av_hash_final_b64(hash, res, sizeof(res));
+ printf("b64:%s", res);
+ } else {
+ av_hash_final_hex(hash, res, sizeof(res));
+ printf("0x%s", res);
+ }
+}
+
+static int check(char *file)
+{
+ uint8_t buffer[SIZE];
+ int fd, flags = O_RDONLY;
+ int ret = 0;
+
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+ if (file) fd = open(file, flags);
+ else fd = 0;
+ if (fd == -1) {
+ printf("%s=OPEN-FAILED: %s:", av_hash_get_name(hash), strerror(errno));
+ ret = 1;
+ goto end;
+ }
+
+ av_hash_init(hash);
+ for (;;) {
+ int size = read(fd, buffer, SIZE);
+ if (size < 0) {
+ int err = errno;
+ close(fd);
+ finish();
+ printf("+READ-FAILED: %s", strerror(err));
+ ret = 2;
+ goto end;
+ } else if(!size)
+ break;
+ av_hash_update(hash, buffer, size);
+ }
+ close(fd);
+
+ finish();
+end:
+ if (file)
+ printf(" *%s", file);
+ printf("\n");
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ int ret = 0;
+ const char *hash_name;
+
+ if (argc == 1) {
+ usage();
+ return 0;
+ }
+
+ hash_name = argv[1];
+ out_b64 = av_strstart(hash_name, "b64:", &hash_name);
+ if ((ret = av_hash_alloc(&hash, hash_name)) < 0) {
+ switch(ret) {
+ case AVERROR(EINVAL):
+ printf("Invalid hash type: %s\n", hash_name);
+ break;
+ case AVERROR(ENOMEM):
+ printf("%s\n", strerror(errno));
+ break;
+ }
+ return 1;
+ }
+
+ for (i = 2; i < argc; i++)
+ ret |= check(argv[i]);
+
+ if (argc < 3)
+ ret |= check(NULL);
+
+ av_hash_freep(&hash);
+
+ return ret;
+}
diff --git a/tools/fourcc2pixfmt.c b/tools/fourcc2pixfmt.c
new file mode 100644
index 0000000000..625f531f5c
--- /dev/null
+++ b/tools/fourcc2pixfmt.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2012 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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"
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#include "libavutil/pixdesc.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/common.h"
+#include "libavcodec/raw.h"
+
+#undef printf
+#undef fprintf
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+static void usage(void)
+{
+ printf("Show the relationships between rawvideo pixel formats and FourCC tags.\n");
+ printf("usage: fourcc2pixfmt [OPTIONS]\n");
+ printf("\n"
+ "Options:\n"
+ "-l list the pixel format for each fourcc\n"
+ "-L list the fourccs for each pixel format\n"
+ "-p PIX_FMT given a pixel format, print the list of associated fourccs (one per line)\n"
+ "-h print this help\n");
+}
+
+static void print_pix_fmt_fourccs(enum AVPixelFormat pix_fmt, const PixelFormatTag *pix_fmt_tags, char sep)
+{
+ int i;
+
+ for (i = 0; pix_fmt_tags[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
+ if (pix_fmt_tags[i].pix_fmt == pix_fmt) {
+ char buf[32];
+ av_get_codec_tag_string(buf, sizeof(buf), pix_fmt_tags[i].fourcc);
+ printf("%s%c", buf, sep);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int i, list_fourcc_pix_fmt = 0, list_pix_fmt_fourccs = 0;
+ const PixelFormatTag *pix_fmt_tags = avpriv_get_raw_pix_fmt_tags();
+ const char *pix_fmt_name = NULL;
+ char c;
+
+ if (argc == 1) {
+ usage();
+ return 0;
+ }
+
+ while ((c = getopt(argc, argv, "hp:lL")) != -1) {
+ switch (c) {
+ case 'h':
+ usage();
+ return 0;
+ case 'l':
+ list_fourcc_pix_fmt = 1;
+ break;
+ case 'L':
+ list_pix_fmt_fourccs = 1;
+ break;
+ case 'p':
+ pix_fmt_name = optarg;
+ break;
+ case '?':
+ usage();
+ return 1;
+ }
+ }
+
+ if (list_fourcc_pix_fmt) {
+ for (i = 0; pix_fmt_tags[i].pix_fmt != AV_PIX_FMT_NONE; i++) {
+ char buf[32];
+ av_get_codec_tag_string(buf, sizeof(buf), pix_fmt_tags[i].fourcc);
+ printf("%s: %s\n", buf, av_get_pix_fmt_name(pix_fmt_tags[i].pix_fmt));
+ }
+ }
+
+ if (list_pix_fmt_fourccs) {
+ for (i = 0; av_pix_fmt_desc_get(i); i++) {
+ const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(i);
+ if (!pix_desc->name || pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
+ continue;
+ printf("%s: ", pix_desc->name);
+ print_pix_fmt_fourccs(i, pix_fmt_tags, ' ');
+ printf("\n");
+ }
+ }
+
+ if (pix_fmt_name) {
+ enum AVPixelFormat pix_fmt = av_get_pix_fmt(pix_fmt_name);
+ if (pix_fmt == AV_PIX_FMT_NONE) {
+ fprintf(stderr, "Invalid pixel format selected '%s'\n", pix_fmt_name);
+ return 1;
+ }
+ print_pix_fmt_fourccs(pix_fmt, pix_fmt_tags, '\n');
+ }
+
+ return 0;
+}
diff --git a/tools/gen-rc b/tools/gen-rc
new file mode 100755
index 0000000000..d9ca37e9ff
--- /dev/null
+++ b/tools/gen-rc
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 James Almer
+# Copyright (c) 2013 Tiancheng "Timothy" Gu
+#
+# This file is part of FFmpeg.
+#
+# FFmpeg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+## Help
+die() {
+ cat <<EOF >&2
+This script is used to generate Windows resources file for the FFmpeg libraries.
+The output .rc file is to be compiled by windres(1). It is mainly useful for
+FFmpeg developers to tweak and regenerate all resources files at once.
+
+Usage: $0 <libname> <comment>
+
+The script will output the file to '<libname>/<libname-without-lib>res.rc'.
+
+Example: $0 libavcodec 'FFmpeg codecs library'
+EOF
+ exit 1
+}
+
+# Script to generate all:
+# (to remove prefix '# ' and add 'tools/' as prefix: sed -r 's/^.{2}/tools\//')
+# gen-rc libavutil "FFmpeg utility library"
+# gen-rc libavcodec "FFmpeg codec library"
+# gen-rc libavformat "FFmpeg container format library"
+# gen-rc libavdevice "FFmpeg device handling library"
+# gen-rc libavfilter "FFmpeg audio/video filtering library"
+# gen-rc libpostproc "FFmpeg postprocessing library"
+# gen-rc libavresample "Libav audio resampling library"
+# gen-rc libswscale "FFmpeg image rescaling library"
+# gen-rc libswresample "FFmpeg audio resampling library"
+
+## Sanity checks and argument parsing
+if test $# -lt 2 || test $# -gt 3; then
+ die
+fi
+
+name=$1
+shortname=${name#lib}
+comment=$2
+capname=`echo $name | awk '{print toupper($0)}'`
+version=${capname}_VERSION
+
+mkdir -p "$name"
+output="$name/${shortname}res.rc"
+
+## REAL magic
+cat <<EOF > $output
+/*
+ * Windows resource file for $name
+ *
+ * Copyright (C) 2012 James Almer
+ * Copyright (C) 2013 Tiancheng "Timothy" Gu
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <windows.h>
+#include "$name/version.h"
+#include "libavutil/ffversion.h"
+#include "config.h"
+
+1 VERSIONINFO
+FILEVERSION ${version}_MAJOR, ${version}_MINOR, ${version}_MICRO, 0
+PRODUCTVERSION ${version}_MAJOR, ${version}_MINOR, ${version}_MICRO, 0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "FFmpeg Project"
+ VALUE "FileDescription", "$comment"
+ VALUE "FileVersion", AV_STRINGIFY($version)
+ VALUE "InternalName", "$name"
+ VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project"
+ VALUE "OriginalFilename", "$shortname" BUILDSUF "-" AV_STRINGIFY(${version}_MAJOR) SLIBSUF
+ VALUE "ProductName", "FFmpeg"
+ VALUE "ProductVersion", FFMPEG_VERSION
+ }
+ }
+
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x0409, 0x04B0
+ }
+}
+EOF
diff --git a/tools/graph2dot.c b/tools/graph2dot.c
index 12f1066c87..23c7331dc3 100644
--- a/tools/graph2dot.c
+++ b/tools/graph2dot.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2008-2010 Stefano Sabatini
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -28,7 +28,6 @@
#include "libavutil/channel_layout.h"
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
-#include "libavutil/audioconvert.h"
#include "libavfilter/avfilter.h"
#if !HAVE_GETOPT
@@ -63,7 +62,7 @@ static void print_digraph(FILE *outfile, AVFilterGraph *graph)
char filter_ctx_label[128];
const AVFilterContext *filter_ctx = graph->filters[i];
- snprintf(filter_ctx_label, sizeof(filter_ctx_label), "%s (%s)",
+ snprintf(filter_ctx_label, sizeof(filter_ctx_label), "%s\\n(%s)",
filter_ctx->name,
filter_ctx->filter->name);
@@ -74,28 +73,32 @@ static void print_digraph(FILE *outfile, AVFilterGraph *graph)
const AVFilterContext *dst_filter_ctx = link->dst;
snprintf(dst_filter_ctx_label, sizeof(dst_filter_ctx_label),
- "%s (%s)",
+ "%s\\n(%s)",
dst_filter_ctx->name,
dst_filter_ctx->filter->name);
- fprintf(outfile, "\"%s\" -> \"%s\"",
- filter_ctx_label, dst_filter_ctx_label);
+ fprintf(outfile, "\"%s\" -> \"%s\" [ label= \"inpad:%s -> outpad:%s\\n",
+ filter_ctx_label, dst_filter_ctx_label,
+ link->srcpad->name, link->dstpad->name);
+
if (link->type == AVMEDIA_TYPE_VIDEO) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
fprintf(outfile,
- " [ label= \"fmt:%s w:%d h:%d tb:%d/%d\" ]",
- desc->name, link->w, link->h, link->time_base.num,
- link->time_base.den);
+ "fmt:%s w:%d h:%d tb:%d/%d",
+ desc->name,
+ link->w, link->h,
+ link->time_base.num, link->time_base.den);
} else if (link->type == AVMEDIA_TYPE_AUDIO) {
char buf[255];
av_get_channel_layout_string(buf, sizeof(buf), -1,
link->channel_layout);
fprintf(outfile,
- " [ label= \"fmt:%s sr:%d cl:%s\" ]",
+ "fmt:%s sr:%d cl:%s tb:%d/%d",
av_get_sample_fmt_name(link->format),
- link->sample_rate, buf);
+ link->sample_rate, buf,
+ link->time_base.num, link->time_base.den);
}
- fprintf(outfile, ";\n");
+ fprintf(outfile, "\" ];\n");
}
}
}
@@ -150,13 +153,21 @@ int main(int argc, char **argv)
/* read from infile and put it in a buffer */
{
- unsigned int count = 0;
+ int64_t count = 0;
struct line *line, *last_line, *first_line;
char *p;
last_line = first_line = av_malloc(sizeof(struct line));
+ if (!last_line) {
+ fprintf(stderr, "Memory allocation failure\n");
+ return 1;
+ }
while (fgets(last_line->data, sizeof(last_line->data), infile)) {
struct line *new_line = av_malloc(sizeof(struct line));
+ if (!new_line) {
+ fprintf(stderr, "Memory allocation failure\n");
+ return 1;
+ }
count += strlen(last_line->data);
last_line->next = new_line;
last_line = new_line;
@@ -164,9 +175,13 @@ int main(int argc, char **argv)
last_line->next = NULL;
graph_string = av_malloc(count + 1);
+ if (!graph_string) {
+ fprintf(stderr, "Memory allocation failure\n");
+ return 1;
+ }
p = graph_string;
for (line = first_line; line->next; line = line->next) {
- unsigned int l = strlen(line->data);
+ size_t l = strlen(line->data);
memcpy(p, line->data, l);
p += l;
}
diff --git a/tools/ismindex.c b/tools/ismindex.c
index f3bfec0a96..8636c966e8 100644
--- a/tools/ismindex.c
+++ b/tools/ismindex.c
@@ -1,26 +1,26 @@
/*
* Copyright (c) 2012 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* To create a simple file for smooth streaming:
- * avconv <normal input/transcoding options> -movflags frag_keyframe foo.ismv
+ * ffmpeg <normal input/transcoding options> -movflags frag_keyframe foo.ismv
* ismindex -n foo foo.ismv
* This step creates foo.ism and foo.ismc that is required by IIS for
* serving it.
@@ -47,6 +47,8 @@
#include <stdio.h>
#include <string.h>
+#include "cmdutils.h"
+
#include "libavformat/avformat.h"
#include "libavformat/isom.h"
#include "libavformat/os_support.h"
@@ -342,8 +344,9 @@ static int read_tfra(struct Tracks *tracks, int start_index, AVIOContext *f)
}
fieldlength = avio_rb32(f);
track->chunks = avio_rb32(f);
- track->offsets = av_mallocz(sizeof(*track->offsets) * track->chunks);
+ track->offsets = av_mallocz_array(track->chunks, sizeof(*track->offsets));
if (!track->offsets) {
+ track->chunks = 0;
ret = AVERROR(ENOMEM);
goto fail;
}
@@ -452,10 +455,11 @@ fail:
static int get_private_data(struct Track *track, AVCodecContext *codec)
{
- track->codec_private_size = codec->extradata_size;
+ track->codec_private_size = 0;
track->codec_private = av_mallocz(codec->extradata_size);
if (!track->codec_private)
return AVERROR(ENOMEM);
+ track->codec_private_size = codec->extradata_size;
memcpy(track->codec_private, codec->extradata, codec->extradata_size);
return 0;
}
@@ -534,8 +538,9 @@ static int handle_file(struct Tracks *tracks, const char *file, int split,
err = AVERROR(ENOMEM);
goto fail;
}
- temp = av_realloc(tracks->tracks,
- sizeof(*tracks->tracks) * (tracks->nb_tracks + 1));
+ temp = av_realloc_array(tracks->tracks,
+ tracks->nb_tracks + 1,
+ sizeof(*tracks->tracks));
if (!temp) {
av_free(track);
err = AVERROR(ENOMEM);
diff --git a/tools/make_chlayout_test b/tools/make_chlayout_test
new file mode 100755
index 0000000000..fcdbda3b73
--- /dev/null
+++ b/tools/make_chlayout_test
@@ -0,0 +1,114 @@
+#!/usr/bin/env perl
+
+# Copyright (c) 2012 Nicolas George
+#
+# This file is part of FFmpeg.
+#
+# FFmpeg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+=head1 NAME
+
+make_chlayout_test - produce a multichannel test file with the channels
+clearly identified
+
+=head1 SYNOPSIS
+
+tools/make_chlayout_test I<channels> I<out_options>
+
+=head1 DESCRIPTION
+
+This script uses B<ffmpeg> and B<libflite> to produce a file with audio
+channels clearly identified by their name. The resulting file can be used to
+check that the layout and order of channels is correctly handled by a piece
+of software, either a part of B<FFmpeg> or not.
+
+I<channels> is a list of channels or channel layouts, separated by '+'.
+
+I<out_options> is a list of valid ffmpeg outout options, including the
+output file.
+
+Note that some output codecs or formats can not handle arbitrary channel
+layout.
+
+This script requires a B<ffmpeg> binary, either in the source tree or in the
+search path; it must have the flite audio source enabled.
+
+=head1 EXAMPLES
+
+Check that the speakers are correctly plugged:
+
+ tools/make_chlayout_test FL+FR -f alsa default
+
+Produce a 5.1 FLAC file:
+
+ tools/make_chlayout_test 5.1 surround.flac
+
+=cut
+
+use strict;
+use warnings;
+use Getopt::Long ":config" => "require_order";
+use Pod::Usage;
+
+GetOptions (
+ "help|usage|?|h" => sub { pod2usage({ -verbose => 1, -exitval => 0 }) },
+ "manpage|m" => sub { pod2usage({ -verbose => 2, -exitval => 0 }) },
+) and @ARGV >= 2 or pod2usage({ -verbose => 1, -exitval => 1 });
+
+my $channels = shift @ARGV;
+my @out_options = @ARGV;
+
+my $ffmpeg = exists $ENV{FFMPEG} ? $ENV{FFMPEG} :
+ $0 =~ /(.*)\// && -e "$1/../ffmpeg" ? "$1/../ffmpeg" :
+ "ffmpeg";
+
+my %channel_label_to_descr;
+my %layout_to_channels;
+
+{
+ open my $stderr, ">&STDERR";
+ open STDERR, ">", "/dev/null";
+ open my $f, "-|", $ffmpeg, "-layouts" or die "$ffmpeg: $!\n";
+ open STDERR, ">&", $stderr;
+ while (<$f>) {
+ chomp;
+ next if /^NAME/ or /:$/ or /^$/; # skip headings
+ my ($name, $descr) = split " ", $_, 2;
+ next unless $descr;
+ if ($descr =~ /^[[:upper:]]+(?:\+[[:upper:]]+)*$/) {
+ $layout_to_channels{$name} = [ split /\+/, $descr ];
+ } else {
+ $channel_label_to_descr{$name} = $descr;
+ }
+ }
+}
+
+my @channels = map { @{$layout_to_channels{$_} // [$_]} } split /\+/, $channels;
+
+my $layout = join "+", @channels;
+my $graph = "";
+my $concat_in = "";
+for my $i (0 .. $#channels) {
+ my $label = $channels[$i];
+ my $descr = $channel_label_to_descr{$label}
+ or die "Channel $label not found\n";
+ $graph .= "flite=text='${descr}', aformat=channel_layouts=mono, " .
+ "pan=${layout}:${label}=c0 [ch$i] ;\n";
+ $concat_in .= "[ch$i] ";
+}
+$graph .= "${concat_in}concat=v=0:a=1:n=" . scalar(@channels);
+
+exec $ffmpeg, "-f", "lavfi", "-i", $graph, @out_options
+ or die "$ffmpeg: $!\n";
diff --git a/tools/missing_codec_desc b/tools/missing_codec_desc
new file mode 100755
index 0000000000..e1d3d60b4f
--- /dev/null
+++ b/tools/missing_codec_desc
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+srcdir=${0%/*}/..
+
+while read -r field equal value; do
+ case "$field $equal" in
+ ".id =")
+ eval "known_${value%,}=1"
+ ;;
+ esac
+done < $srcdir/libavcodec/codec_desc.c
+
+known_AV_CODEC_ID_NONE=1
+known_AV_CODEC_ID_FIRST_AUDIO=1
+known_AV_CODEC_ID_FIRST_SUBTITLE=1
+known_AV_CODEC_ID_FIRST_UNKNOWN=1
+known_AV_CODEC_ID_PROBE=1
+known_AV_CODEC_ID_MPEG2TS=1
+known_AV_CODEC_ID_MPEG4SYSTEMS=1
+known_AV_CODEC_ID_FFMETADATA=1
+
+in=0
+while read -r line; do
+ case "$in-$line" in
+ 0-"enum AVCodecID"*) in=1;;
+ 1-*"};"*) in=0;;
+ 1-*AV_CODEC_ID_*,*)
+ cid="${line%%[, =]*}"
+ eval "known=\$known_$cid"
+ case "$known" in
+ 1) ;;
+ *) echo "$cid missing";;
+ esac
+ ;;
+ esac
+done < $srcdir/libavcodec/avcodec.h
diff --git a/tools/normalize.py b/tools/normalize.py
new file mode 100755
index 0000000000..7d87c5e154
--- /dev/null
+++ b/tools/normalize.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python2
+
+import sys, subprocess
+
+if len(sys.argv) > 2:
+ ifile = sys.argv[1]
+ encopt = sys.argv[2:-1]
+ ofile = sys.argv[-1]
+else:
+ print 'usage: %s <input> [encode_options] <output>' % sys.argv[0]
+ sys.exit(1)
+
+analysis_cmd = 'ffprobe -v error -of compact=p=0:nk=1 '
+analysis_cmd += '-show_entries frame_tags=lavfi.r128.I -f lavfi '
+analysis_cmd += "amovie='%s',ebur128=metadata=1" % ifile
+try:
+ probe_out = subprocess.check_output(analysis_cmd, shell=True)
+except subprocess.CalledProcessError, e:
+ sys.exit(e.returncode)
+loudness = ref = -23
+for line in probe_out.splitlines():
+ sline = line.rstrip()
+ if sline:
+ loudness = sline
+adjust = ref - float(loudness)
+if abs(adjust) < 0.0001:
+ print 'No normalization needed for ' + ifile
+else:
+ print "Adjust %s by %.1fdB" % (ifile, adjust)
+ norm_cmd = ['ffmpeg', '-i', ifile, '-af', 'volume=%fdB' % adjust]
+ norm_cmd += encopt + [ofile]
+ print ' => %s' % ' '.join(norm_cmd)
+ subprocess.call(norm_cmd)
diff --git a/tools/patcheck b/tools/patcheck
index e681d6d29e..cbdbf8d34a 100755
--- a/tools/patcheck
+++ b/tools/patcheck
@@ -15,11 +15,11 @@ OPT="-nH"
#FILES=$($GREP '^+++' $* | sed 's/+++ //g')
echo patCHeck 1e10.0
-echo This tool is intended to help a human check/review patches it is very far from
-echo being free of false positives and negatives, its output are just hints of what
+echo This tool is intended to help a human check/review patches. It is very far from
+echo being free of false positives and negatives, and its output are just hints of what
echo may or may not be bad. When you use it and it misses something or detects
-echo something wrong, fix it and send a patch to the libav-devel mailing list.
-echo License:GPL Author: Michael Niedermayer
+echo something wrong, fix it and send a patch to the ffmpeg-devel mailing list.
+echo License: GPL, Author: Michael Niedermayer
ERE_PRITYP='(unsigned *|)(char|short|long|int|long *int|short *int|void|float|double|(u|)int(8|16|32|64)_t)'
ERE_TYPES='(const|static|av_cold|inline| *)*('$ERE_PRITYP'|[a-zA-Z][a-zA-Z0-9_]*)[* ]{1,}[a-zA-Z][a-zA-Z0-9_]*'
@@ -42,6 +42,7 @@ hiegrep2(){
cat $TMP
}
+hiegrep 'static[^(]*\*[a-zA-Z_]*\[' 'pointer array is not const' $*
hiegrep '[[:space:]]$' 'trailing whitespace' $*
hiegrep "$(echo x | tr 'x' '\t')" 'tabs' $*
#hiegrep ':\+$' 'Empty lines' $*
@@ -50,7 +51,7 @@ hiegrep2 '\b_[a-zA-Z0-9_]{1,}' '__(asm|attribute)([^a-zA-Z0-9]|$)' 'reserved ide
hiegrep '//[-/<\* ]*$' 'empty comment' $*
hiegrep '/\*[-<\* ]*\*/' 'empty comment' $*
hiegrep 'for *\( *'"$ERE_PRITYP"' ' 'not gcc 2.95 compatible' $*
-hiegrep '(static|inline|const) *\1' 'duplicate word' $*
+hiegrep '(static|inline|const) *\1[^_a-zA-Z]' 'duplicate word' $*
hiegrep 'INIT_VLC_USE_STATIC' 'forbidden ancient vlc type' $*
hiegrep '=[-+\*\&] ' 'looks like compound assignment' $*
hiegrep2 '/\*\* *[a-zA-Z0-9].*' '\*/' 'Inconsistently formatted doxygen comment' $*
@@ -67,7 +68,7 @@ $EGREP $OPT '^\+ *(const *|)static' $*| $EGREP --color=always '[^=]= *(0|NULL)[^
cat $TMP
hiegrep '# *ifdef * (HAVE|CONFIG)_' 'ifdefs that should be #if' $*
-hiegrep '\b(awnser|cant|dont|wont|doesnt|usefull|successfull|occured|teh|alot|wether|skiped|heigth|informations|colums|loosy|loosing|seperate|preceed|upto|paket|posible|unkown|inpossible|dimention|acheive)\b' 'common typos' $*
+hiegrep '\b(awnser|cant|dont|wont|doesnt|usefull|successfull|occured|teh|alot|wether|skiped|skiping|heigth|informations|colums|loosy|loosing|ouput|seperate|preceed|upto|paket|posible|unkown|inpossible|dimention|acheive|funtions|overriden|outputing|seperation|initalize|compatibilty|bistream|knwon|unknwon|choosen|additonal|gurantee|availble|wich)\b' 'common typos' $*
hiegrep 'av_log\( *NULL' 'Missing context in av_log' $*
hiegrep '[^sn]printf' 'Please use av_log' $*
diff --git a/tools/pktdumper.c b/tools/pktdumper.c
index c6398fe517..61cb5cc8ee 100644
--- a/tools/pktdumper.c
+++ b/tools/pktdumper.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2005 Francois Revol
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
diff --git a/tools/plotframes b/tools/plotframes
new file mode 100755
index 0000000000..f379723a9b
--- /dev/null
+++ b/tools/plotframes
@@ -0,0 +1,164 @@
+#!/usr/bin/env perl
+
+# Copyright (c) 2007-2013 Stefano Sabatini
+#
+# This file is part of FFmpeg.
+#
+# FFmpeg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+=head1 NAME
+
+plotframes - Plot video frame sizes using ffprobe and gnuplot
+
+=head1 SYNOPSIS
+
+plotframes [I<options>] [I<input>]
+
+=head1 DESCRIPTION
+
+plotframes reads a multimedia files with ffprobe, and plots the
+collected video sizes with gnuplot.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--input|-i> I<infile>
+
+Specify multimedia file to read. This is the file passed to the
+ffprobe command. If not specified it is the first argument passed to
+the script.
+
+=item B<--help|--usage|-h|-?>
+
+Print a brief help message and exit.
+
+=item B<--manpage|-m>
+
+Print the man page.
+
+=item B<--output|-o> I<outfile>
+
+Set the name of the output used by gnuplot. If not specified no output
+is created. Must be used in conjunction with the B<terminal> option.
+
+=item B<--stream|--s> I<stream_specifier>
+
+Specify stream. The value must be a string containing a stream
+specifier. Default value is "v".
+
+=item B<--terminal|-t> I<terminal>
+
+Set the name of the terminal used by gnuplot. By default it is
+"x11". Must be used in conjunction with the B<output> option. Check
+the gnuplot manual for the valid values.
+
+=back
+
+=cut
+
+=head1 SEE ALSO
+
+ffprobe(1), gnuplot(1)
+
+=cut
+
+use warnings;
+use strict;
+
+use File::Temp;
+use JSON -support_by_pp;
+use Getopt::Long;
+use Pod::Usage;
+
+my $input = $ARGV[0];
+my $stream_specifier = "v";
+my $gnuplot_terminal = "x11";
+my $gnuplot_output;
+
+GetOptions (
+ 'input|i=s' => \$input,
+ 'help|usage|?|h' => sub { pod2usage ( { -verbose => 1, -exitval => 0 }) },
+ 'manpage|m' => sub { pod2usage ( { -verbose => 2, -exitval => 0 }) },
+ 'stream|s=s' => \$stream_specifier,
+ 'terminal|t=s' => \$gnuplot_terminal,
+ 'output|o=s' => \$gnuplot_output,
+ ) or pod2usage( { -message=> "Parsing error", -verbose => 1, -exitval => 1 });
+
+die "You must specify an input file\n" unless $input;
+
+# fetch data
+my @cmd = (qw{ffprobe -show_entries frame -select_streams}, $stream_specifier, "-of", "json", $input);
+print STDERR "Executing command: @cmd\n";
+my $json_struct;
+{
+ open(FH, "-|", @cmd) or die "ffprobe command failed: $!\n";
+ local $/;
+ my $json_text = <FH>;
+ close FH;
+ die "ffprobe command failed" if $?;
+ eval { $json_struct = decode_json($json_text); };
+ die "JSON parsing error: $@\n" if $@;
+}
+
+# collect and print frame statistics per pict_type
+my %stats;
+my $frames = $json_struct->{frames};
+my $frame_count = 0;
+foreach my $frame (@{$frames}) {
+ my $type = $frame->{pict_type};
+ $frame->{count} = $frame_count++;
+ if (not $stats{$type}) {
+ $stats{$type}->{tmpfile} = File::Temp->new(SUFFIX => '.dat');
+ my $fn = $stats{$type}->{tmpfile}->filename;
+ open($stats{$type}->{fh}, ">", $fn) or die "Can't open $fn";
+ }
+
+ print { $stats{$type}->{fh} }
+ "$frame->{count} ", $frame->{pkt_size} * 8 / 1000, "\n";
+}
+foreach (keys %stats) { close $stats{$_}->{fh}; }
+
+# write gnuplot script
+my %type_color_map = (
+ "I" => "red",
+ "P" => "green",
+ "B" => "blue"
+ );
+
+my $gnuplot_script_tmpfile = File::Temp->new(SUFFIX => '.gnuplot');
+my $fn = $gnuplot_script_tmpfile->filename;
+open(FH, ">", $fn) or die "Couldn't open $fn: $!";
+print FH << "EOF";
+set title "video frame sizes"
+set xlabel "frame time"
+set ylabel "frame size (Kbits)"
+set grid
+set terminal "$gnuplot_terminal"
+EOF
+
+print FH "set output \"$gnuplot_output\"\n" if $gnuplot_output;
+print FH "plot";
+my $sep = "";
+foreach my $type (keys %stats) {
+ my $fn = $stats{$type}->{tmpfile}->filename;
+ print FH "$sep\"$fn\" title \"$type frames\" with impulses";
+ print FH " linecolor rgb \"$type_color_map{$type}\"" if $type_color_map{$type};
+ $sep = ", ";
+}
+close FH;
+
+# launch gnuplot with the generated script
+system ("gnuplot", "--persist", $gnuplot_script_tmpfile->filename);
diff --git a/tools/probetest.c b/tools/probetest.c
index 678f4dd3a7..74045eb498 100644
--- a/tools/probetest.c
+++ b/tools/probetest.c
@@ -1,20 +1,20 @@
/*
* copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -23,9 +23,17 @@
#include "libavformat/avformat.h"
#include "libavcodec/put_bits.h"
#include "libavutil/lfg.h"
+#include "libavutil/timer.h"
-static int score_array[1000]; //this must be larger than the number of formats
+#define MAX_FORMATS 1000 //this must be larger than the number of formats
+static int score_array[MAX_FORMATS];
+static int64_t time_array[MAX_FORMATS];
static int failures = 0;
+static const char *single_format;
+
+#ifndef AV_READ_TIME
+#define AV_READ_TIME(x) 0
+#endif
static void probe(AVProbeData *pd, int type, int p, int size)
{
@@ -35,8 +43,13 @@ static void probe(AVProbeData *pd, int type, int p, int size)
while ((fmt = av_iformat_next(fmt))) {
if (fmt->flags & AVFMT_NOFILE)
continue;
- if (fmt->read_probe) {
- int score = fmt->read_probe(pd);
+ if (fmt->read_probe &&
+ (!single_format || !strcmp(single_format, fmt->name))
+ ) {
+ int score;
+ int64_t start = AV_READ_TIME();
+ score = fmt->read_probe(pd);
+ time_array[i] += AV_READ_TIME() - start;
if (score > score_array[i] && score > AVPROBE_SCORE_MAX / 4) {
score_array[i] = score;
fprintf(stderr,
@@ -49,12 +62,67 @@ static void probe(AVProbeData *pd, int type, int p, int size)
}
}
-int main(void)
+static void print_times(void)
+{
+ int i = 0;
+ AVInputFormat *fmt = NULL;
+
+ while ((fmt = av_iformat_next(fmt))) {
+ if (fmt->flags & AVFMT_NOFILE)
+ continue;
+ if (time_array[i] > 1000000) {
+ fprintf(stderr, "%12"PRIu64" cycles, %12s\n",
+ time_array[i], fmt->name);
+ }
+ i++;
+ }
+}
+
+static int read_int(char *arg) {
+ int ret;
+
+ if (!arg || !*arg)
+ return -1;
+ ret = strtol(arg, &arg, 0);
+ if (*arg)
+ return -1;
+ return ret;
+}
+
+int main(int argc, char **argv)
{
unsigned int p, i, type, size, retry;
- AVProbeData pd;
+ AVProbeData pd = { 0 };
AVLFG state;
PutBitContext pb;
+ int retry_count= 4097;
+ int max_size = 65537;
+ int j;
+
+ for (j = i = 1; i<argc; i++) {
+ if (!strcmp(argv[i], "-f") && i+1<argc && !single_format) {
+ single_format = argv[++i];
+ } else if (read_int(argv[i])>0 && j == 1) {
+ retry_count = read_int(argv[i]);
+ j++;
+ } else if (read_int(argv[i])>0 && j == 2) {
+ max_size = read_int(argv[i]);
+ j++;
+ } else {
+ fprintf(stderr, "probetest [-f <input format>] [<retry_count> [<max_size>]]\n");
+ return 1;
+ }
+ }
+
+ if (max_size > 1000000000U/8) {
+ fprintf(stderr, "max_size out of bounds\n");
+ return 1;
+ }
+
+ if (retry_count > 1000000000U) {
+ fprintf(stderr, "retry_count out of bounds\n");
+ return 1;
+ }
avcodec_register_all();
av_register_all();
@@ -62,14 +130,21 @@ int main(void)
av_lfg_init(&state, 0xdeadbeef);
pd.buf = NULL;
- for (size = 1; size < 65537; size *= 2) {
+ for (size = 1; size < max_size; size *= 2) {
pd.buf_size = size;
pd.buf = av_realloc(pd.buf, size + AVPROBE_PADDING_SIZE);
pd.filename = "";
+ if (!pd.buf) {
+ fprintf(stderr, "out of memory\n");
+ return 1;
+ }
+
+ memset(pd.buf, 0, size + AVPROBE_PADDING_SIZE);
+
fprintf(stderr, "testing size=%d\n", size);
- for (retry = 0; retry < 4097; retry += FFMAX(size, 32)) {
+ for (retry = 0; retry < retry_count; retry += FFMAX(size, 32)) {
for (type = 0; type < 4; type++) {
for (p = 0; p < 4096; p++) {
unsigned hist = 0;
@@ -122,5 +197,7 @@ int main(void)
}
}
}
+ if(AV_READ_TIME())
+ print_times();
return failures;
}
diff --git a/tools/qt-faststart.c b/tools/qt-faststart.c
index 0db5ca2138..97be019c58 100644
--- a/tools/qt-faststart.c
+++ b/tools/qt-faststart.c
@@ -8,7 +8,7 @@
* is in front of the data, thus facilitating network streaming.
*
* To compile this program, start from the base directory from which you
- * are building Libav and type:
+ * are building FFmpeg and type:
* make tools/qt-faststart
* The qt-faststart program will be built in the tools/ directory. If you
* do not build the program in this manner, correct results are not
@@ -83,7 +83,7 @@
#define CO64_ATOM QT_ATOM('c', 'o', '6', '4')
#define ATOM_PREAMBLE_SIZE 8
-#define COPY_BUFFER_SIZE 65536
+#define COPY_BUFFER_SIZE 33554432
int main(int argc, char *argv[])
{
@@ -102,12 +102,12 @@ int main(int argc, char *argv[])
uint32_t offset_count;
uint64_t current_offset;
int64_t start_offset = 0;
- unsigned char copy_buffer[COPY_BUFFER_SIZE];
+ unsigned char *copy_buffer = NULL;
int bytes_to_copy;
if (argc != 3) {
printf("Usage: qt-faststart <infile.mov> <outfile.mov>\n"
- "Note: alternatively you can use -movflags +faststart in avconv\n");
+ "Note: alternatively you can use -movflags +faststart in ffmpeg\n");
return 0;
}
@@ -324,9 +324,15 @@ int main(int argc, char *argv[])
}
/* copy the remainder of the infile, from offset 0 -> last_offset - 1 */
+ bytes_to_copy = MIN(COPY_BUFFER_SIZE, last_offset);
+ copy_buffer = malloc(bytes_to_copy);
+ if (!copy_buffer) {
+ printf("could not allocate %d bytes for copy_buffer\n", bytes_to_copy);
+ goto error_out;
+ }
printf(" copying rest of file...\n");
while (last_offset) {
- bytes_to_copy = MIN(COPY_BUFFER_SIZE, last_offset);
+ bytes_to_copy = MIN(bytes_to_copy, last_offset);
if (fread(copy_buffer, bytes_to_copy, 1, infile) != 1) {
perror(argv[1]);
@@ -343,6 +349,7 @@ int main(int argc, char *argv[])
fclose(outfile);
free(moov_atom);
free(ftyp_atom);
+ free(copy_buffer);
return 0;
@@ -353,5 +360,6 @@ error_out:
fclose(outfile);
free(moov_atom);
free(ftyp_atom);
+ free(copy_buffer);
return 1;
}
diff --git a/tools/seek_print.c b/tools/seek_print.c
new file mode 100644
index 0000000000..c42b28dd44
--- /dev/null
+++ b/tools/seek_print.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#include "libavformat/avformat.h"
+#include "libavutil/timestamp.h"
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+static void usage(int ret)
+{
+ fprintf(ret ? stderr : stdout,
+ "Usage: seek_print file [command ...]\n"
+ "Commands:\n"
+ " read\n"
+ " seek:stream:min_ts:ts:max_ts:flags\n"
+ );
+ exit(ret);
+}
+
+int main(int argc, char **argv)
+{
+ int opt, ret, stream, flags;
+ const char *filename;
+ AVFormatContext *avf = NULL;
+ int64_t min_ts, max_ts, ts;
+ AVPacket packet;
+
+ while ((opt = getopt(argc, argv, "h")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage(0);
+ default:
+ usage(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (!argc)
+ usage(1);
+ filename = *argv;
+ argv++;
+ argc--;
+
+ av_register_all();
+ if ((ret = avformat_open_input(&avf, filename, NULL, NULL)) < 0) {
+ fprintf(stderr, "%s: %s\n", filename, av_err2str(ret));
+ return 1;
+ }
+ if ((ret = avformat_find_stream_info(avf, NULL)) < 0) {
+ fprintf(stderr, "%s: could not find codec parameters: %s\n", filename,
+ av_err2str(ret));
+ return 1;
+ }
+
+ for (; argc; argc--, argv++) {
+ if (!strcmp(*argv, "read")) {
+ ret = av_read_frame(avf, &packet);
+ if (ret < 0) {
+ printf("read: %d (%s)\n", ret, av_err2str(ret));
+ } else {
+ AVRational *tb = &avf->streams[packet.stream_index]->time_base;
+ printf("read: %d size=%d stream=%d dts=%s (%s) pts=%s (%s)\n",
+ ret, packet.size, packet.stream_index,
+ av_ts2str(packet.dts), av_ts2timestr(packet.dts, tb),
+ av_ts2str(packet.pts), av_ts2timestr(packet.pts, tb));
+ av_free_packet(&packet);
+ }
+ } else if (sscanf(*argv, "seek:%i:%"SCNi64":%"SCNi64":%"SCNi64":%i",
+ &stream, &min_ts, &ts, &max_ts, &flags) == 5) {
+ ret = avformat_seek_file(avf, stream, min_ts, ts, max_ts, flags);
+ printf("seek: %d (%s)\n", ret, av_err2str(ret));
+ } else {
+ fprintf(stderr, "'%s': unknown command\n", *argv);
+ return 1;
+ }
+ }
+
+ avformat_close_input(&avf);
+
+ return 0;
+}
diff --git a/tools/sidxindex.c b/tools/sidxindex.c
index 3adbc6f1f9..504c59588c 100644
--- a/tools/sidxindex.c
+++ b/tools/sidxindex.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2014 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -156,8 +156,8 @@ static int handle_file(struct Tracks *tracks, const char *file)
err = AVERROR(ENOMEM);
goto fail;
}
- temp = av_realloc(tracks->tracks,
- sizeof(*tracks->tracks) * (tracks->nb_tracks + 1));
+ temp = av_realloc_array(tracks->tracks, tracks->nb_tracks + 1,
+ sizeof(*tracks->tracks));
if (!temp) {
av_free(track);
err = AVERROR(ENOMEM);
@@ -244,7 +244,7 @@ static int output_mpd(struct Tracks *tracks, const char *filename)
nb_tracks = nb_tracks_buf;
nb_sets = 2;
for (i = 0; i < 2; i++) {
- adaptation_sets[i] = av_malloc(sizeof(*adaptation_sets[i]) * tracks->nb_tracks);
+ adaptation_sets[i] = av_malloc_array(tracks->nb_tracks, sizeof(*adaptation_sets[i]));
if (!adaptation_sets[i]) {
ret = AVERROR(ENOMEM);
goto err;
diff --git a/tools/trasher.c b/tools/trasher.c
index 35625e9a62..0b89cfed87 100644
--- a/tools/trasher.c
+++ b/tools/trasher.c
@@ -1,20 +1,20 @@
/*
* Copyright (c) 2007 Michael Niedermayer
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,15 @@ static uint32_t ran(void)
return state = state * 1664525 + 1013904223;
}
+static void checked_seek(FILE *stream, int64_t offset, int whence)
+{
+ offset = fseek(stream, offset, whence);
+ if (offset < 0) {
+ fprintf(stderr, "seek failed\n");
+ exit(1);
+ }
+}
+
int main(int argc, char **argv)
{
FILE *f;
@@ -49,14 +58,14 @@ int main(int argc, char **argv)
maxburst = atoi(argv[3]);
state = atoi(argv[4]);
- fseek(f, 0, SEEK_END);
+ checked_seek(f, 0, SEEK_END);
length = ftell(f);
- fseek(f, 0, SEEK_SET);
+ checked_seek(f, 0, SEEK_SET);
while (count--) {
int burst = 1 + ran() * (uint64_t) (abs(maxburst) - 1) / UINT32_MAX;
int pos = ran() * (uint64_t) length / UINT32_MAX;
- fseek(f, pos, SEEK_SET);
+ checked_seek(f, pos, SEEK_SET);
if (maxburst < 0)
burst = -maxburst;
diff --git a/tools/uncoded_frame.c b/tools/uncoded_frame.c
new file mode 100644
index 0000000000..3ca2ba4bbe
--- /dev/null
+++ b/tools/uncoded_frame.c
@@ -0,0 +1,279 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libavutil/avassert.h"
+#include "libavdevice/avdevice.h"
+#include "libavfilter/avfilter.h"
+#include "libavfilter/buffersink.h"
+#include "libavformat/avformat.h"
+
+typedef struct {
+ AVFormatContext *mux;
+ AVStream *stream;
+ AVFilterContext *sink;
+ AVFilterLink *link;
+} Stream;
+
+static int create_sink(Stream *st, AVFilterGraph *graph,
+ AVFilterContext *f, int idx)
+{
+ enum AVMediaType type = avfilter_pad_get_type(f->output_pads, idx);
+ const char *sink_name;
+ int ret;
+
+ switch (type) {
+ case AVMEDIA_TYPE_VIDEO: sink_name = "buffersink"; break;
+ case AVMEDIA_TYPE_AUDIO: sink_name = "abuffersink"; break;
+ default:
+ av_log(NULL, AV_LOG_ERROR, "Stream type not supported\n");
+ return AVERROR(EINVAL);
+ }
+ ret = avfilter_graph_create_filter(&st->sink,
+ avfilter_get_by_name(sink_name),
+ NULL, NULL, NULL, graph);
+ if (ret < 0)
+ return ret;
+ ret = avfilter_link(f, idx, st->sink, 0);
+ if (ret < 0)
+ return ret;
+ st->link = st->sink->inputs[0];
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *in_graph_desc, **out_dev_name;
+ int nb_out_dev = 0, nb_streams = 0;
+ AVFilterGraph *in_graph = NULL;
+ Stream *streams = NULL, *st;
+ AVFrame *frame = NULL;
+ int i, j, run = 1, ret;
+
+ //av_log_set_level(AV_LOG_DEBUG);
+
+ if (argc < 3) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Usage: %s filter_graph dev:out [dev2:out2...]\n\n"
+ "Examples:\n"
+ "%s movie=file.nut:s=v+a xv:- alsa:default\n"
+ "%s movie=file.nut:s=v+a uncodedframecrc:pipe:0\n",
+ argv[0], argv[0], argv[0]);
+ exit(1);
+ }
+ in_graph_desc = argv[1];
+ out_dev_name = argv + 2;
+ nb_out_dev = argc - 2;
+
+ av_register_all();
+ avdevice_register_all();
+ avfilter_register_all();
+
+ /* Create input graph */
+ if (!(in_graph = avfilter_graph_alloc())) {
+ ret = AVERROR(ENOMEM);
+ av_log(NULL, AV_LOG_ERROR, "Unable to alloc graph graph: %s\n",
+ av_err2str(ret));
+ goto fail;
+ }
+ ret = avfilter_graph_parse_ptr(in_graph, in_graph_desc, NULL, NULL, NULL);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Unable to parse graph: %s\n",
+ av_err2str(ret));
+ goto fail;
+ }
+ nb_streams = 0;
+ for (i = 0; i < in_graph->nb_filters; i++) {
+ AVFilterContext *f = in_graph->filters[i];
+ for (j = 0; j < f->nb_inputs; j++) {
+ if (!f->inputs[j]) {
+ av_log(NULL, AV_LOG_ERROR, "Graph has unconnected inputs\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ }
+ for (j = 0; j < f->nb_outputs; j++)
+ if (!f->outputs[j])
+ nb_streams++;
+ }
+ if (!nb_streams) {
+ av_log(NULL, AV_LOG_ERROR, "Graph has no output stream\n");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ if (nb_out_dev != 1 && nb_out_dev != nb_streams) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Graph has %d output streams, %d devices given\n",
+ nb_streams, nb_out_dev);
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+
+ if (!(streams = av_calloc(nb_streams, sizeof(*streams)))) {
+ ret = AVERROR(ENOMEM);
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate streams\n");
+ }
+ st = streams;
+ for (i = 0; i < in_graph->nb_filters; i++) {
+ AVFilterContext *f = in_graph->filters[i];
+ for (j = 0; j < f->nb_outputs; j++) {
+ if (!f->outputs[j]) {
+ if ((ret = create_sink(st++, in_graph, f, j)) < 0)
+ goto fail;
+ }
+ }
+ }
+ av_assert0(st - streams == nb_streams);
+ if ((ret = avfilter_graph_config(in_graph, NULL)) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to configure graph\n");
+ goto fail;
+ }
+
+ /* Create output devices */
+ for (i = 0; i < nb_out_dev; i++) {
+ char *fmt = NULL, *dev = out_dev_name[i];
+ st = &streams[i];
+ if ((dev = strchr(dev, ':'))) {
+ *(dev++) = 0;
+ fmt = out_dev_name[i];
+ }
+ ret = avformat_alloc_output_context2(&st->mux, NULL, fmt, dev);
+ if (ret < 0) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to allocate output: %s\n",
+ av_err2str(ret));
+ goto fail;
+ }
+ if (!(st->mux->oformat->flags & AVFMT_NOFILE)) {
+ ret = avio_open2(&st->mux->pb, st->mux->filename, AVIO_FLAG_WRITE,
+ NULL, NULL);
+ if (ret < 0) {
+ av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n",
+ av_err2str(ret));
+ goto fail;
+ }
+ }
+ }
+ for (; i < nb_streams; i++)
+ streams[i].mux = streams[0].mux;
+
+ /* Create output device streams */
+ for (i = 0; i < nb_streams; i++) {
+ st = &streams[i];
+ if (!(st->stream = avformat_new_stream(st->mux, NULL))) {
+ ret = AVERROR(ENOMEM);
+ av_log(NULL, AV_LOG_ERROR, "Failed to create output stream\n");
+ goto fail;
+ }
+ st->stream->codec->codec_type = st->link->type;
+ st->stream->time_base = st->stream->codec->time_base =
+ st->link->time_base;
+ switch (st->link->type) {
+ case AVMEDIA_TYPE_VIDEO:
+ st->stream->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
+ st->stream->avg_frame_rate =
+ st->stream-> r_frame_rate = av_buffersink_get_frame_rate(st->sink);
+ st->stream->codec->width = st->link->w;
+ st->stream->codec->height = st->link->h;
+ st->stream->codec->sample_aspect_ratio = st->link->sample_aspect_ratio;
+ st->stream->codec->pix_fmt = st->link->format;
+ break;
+ case AVMEDIA_TYPE_AUDIO:
+ st->stream->codec->channel_layout = st->link->channel_layout;
+ st->stream->codec->channels = avfilter_link_get_channels(st->link);
+ st->stream->codec->sample_rate = st->link->sample_rate;
+ st->stream->codec->sample_fmt = st->link->format;
+ st->stream->codec->codec_id =
+ av_get_pcm_codec(st->stream->codec->sample_fmt, -1);
+ break;
+ default:
+ av_assert0(!"reached");
+ }
+ }
+
+ /* Init output devices */
+ for (i = 0; i < nb_out_dev; i++) {
+ st = &streams[i];
+ if ((ret = avformat_write_header(st->mux, NULL)) < 0) {
+ av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n",
+ av_err2str(ret));
+ goto fail;
+ }
+ }
+
+ /* Check output devices */
+ for (i = 0; i < nb_streams; i++) {
+ st = &streams[i];
+ ret = av_write_uncoded_frame_query(st->mux, st->stream->index);
+ if (ret < 0) {
+ av_log(st->mux, AV_LOG_ERROR,
+ "Uncoded frames not supported on stream #%d: %s\n",
+ i, av_err2str(ret));
+ goto fail;
+ }
+ }
+
+ while (run) {
+ ret = avfilter_graph_request_oldest(in_graph);
+ if (ret < 0) {
+ if (ret == AVERROR_EOF) {
+ run = 0;
+ } else {
+ av_log(NULL, AV_LOG_ERROR, "Error filtering: %s\n",
+ av_err2str(ret));
+ break;
+ }
+ }
+ for (i = 0; i < nb_streams; i++) {
+ st = &streams[i];
+ while (1) {
+ if (!frame && !(frame = av_frame_alloc())) {
+ ret = AVERROR(ENOMEM);
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate frame\n");
+ goto fail;
+ }
+ ret = av_buffersink_get_frame_flags(st->sink, frame,
+ AV_BUFFERSINK_FLAG_NO_REQUEST);
+ if (ret < 0) {
+ if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
+ av_log(NULL, AV_LOG_WARNING, "Error in sink: %s\n",
+ av_err2str(ret));
+ break;
+ }
+ if (frame->pts != AV_NOPTS_VALUE)
+ frame->pts = av_rescale_q(frame->pts,
+ st->link ->time_base,
+ st->stream->time_base);
+ ret = av_interleaved_write_uncoded_frame(st->mux,
+ st->stream->index,
+ frame);
+ frame = NULL;
+ if (ret < 0) {
+ av_log(st->stream->codec, AV_LOG_ERROR,
+ "Error writing frame: %s\n", av_err2str(ret));
+ goto fail;
+ }
+ }
+ }
+ }
+ ret = 0;
+
+ for (i = 0; i < nb_out_dev; i++) {
+ st = &streams[i];
+ av_write_trailer(st->mux);
+ }
+
+fail:
+ av_frame_free(&frame);
+ avfilter_graph_free(&in_graph);
+ if (streams) {
+ for (i = 0; i < nb_out_dev; i++) {
+ st = &streams[i];
+ if (st->mux) {
+ if (st->mux->pb)
+ avio_closep(&st->mux->pb);
+ avformat_free_context(st->mux);
+ }
+ }
+ }
+ av_freep(&streams);
+ return ret < 0;
+}
diff --git a/tools/unwrap-diff b/tools/unwrap-diff
new file mode 100755
index 0000000000..ccea99b7b4
--- /dev/null
+++ b/tools/unwrap-diff
@@ -0,0 +1,2 @@
+#!/bin/sh
+tr '\n' '\001' | sed 's/\x01\x01/\x01 \x01/g' | sed 's/\x01\([^-+ @]\)/ \1/g' | tr '\001' '\n'
diff --git a/tools/yuvcmp.c b/tools/yuvcmp.c
new file mode 100644
index 0000000000..65b1794d07
--- /dev/null
+++ b/tools/yuvcmp.c
@@ -0,0 +1,184 @@
+/*
+ * originally by Andreas Ă–man (andoma)
+ * some changes by Alexander Strange
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int
+main(int argc, char **argv)
+{
+ int fd[2];
+ int print_pixels = 0;
+ int dump_blocks = 0;
+
+ int width;
+ int height;
+ int to_skip = 0;
+
+ if (argc < 6) {
+ fprintf(stderr, "%s [YUV file 1] [YUV file 2] width height pixelcmp|blockdump (# to skip)\n", argv[0]);
+ return 1;
+ }
+
+ width = atoi(argv[3]);
+ height = atoi(argv[4]);
+ if (argc > 6)
+ to_skip = atoi(argv[6]);
+
+ uint8_t *Y[2], *C[2][2];
+ int i, v, c, p;
+ int lsiz = width * height;
+ int csiz = width * height / 4;
+ int x, y;
+ int cwidth = width / 2;
+ int fr = to_skip;
+ int mb;
+ char *mberrors;
+ int mb_x, mb_y;
+ uint8_t *a;
+ uint8_t *b;
+ int die = 0;
+
+ print_pixels = strstr(argv[5], "pixelcmp") ? 1 : 0;
+ dump_blocks = strstr(argv[5], "blockdump") ? 1 : 0;
+
+ for(i = 0; i < 2; i++) {
+ Y[i] = malloc(lsiz);
+ C[0][i] = malloc(csiz);
+ C[1][i] = malloc(csiz);
+
+ fd[i] = open(argv[1 + i], O_RDONLY);
+ if(fd[i] == -1) {
+ perror("open");
+ exit(1);
+ }
+ fcntl(fd[i], F_NOCACHE, 1);
+
+ if (to_skip)
+ lseek(fd[i], to_skip * (lsiz + 2*csiz), SEEK_SET);
+ }
+
+ mb_x = width / 16;
+ mb_y = height / 16;
+
+ mberrors = malloc(mb_x * mb_y);
+
+ while(!die) {
+ memset(mberrors, 0, mb_x * mb_y);
+
+ printf("Loading frame %d\n", ++fr);
+
+ for(i = 0; i < 2; i++) {
+ v = read(fd[i], Y[i], lsiz);
+ if(v != lsiz) {
+ fprintf(stderr, "Unable to read Y from file %d, exiting\n", i + 1);
+ return 1;
+ }
+ }
+
+
+ for(c = 0; c < lsiz; c++) {
+ if(Y[0][c] != Y[1][c]) {
+ x = c % width;
+ y = c / width;
+
+ mb = x / 16 + (y / 16) * mb_x;
+
+ if(print_pixels)
+ printf("Luma diff 0x%02x != 0x%02x at pixel (%4d,%-4d) mb(%d,%d) #%d\n",
+ Y[0][c],
+ Y[1][c],
+ x, y,
+ x / 16,
+ y / 16,
+ mb);
+
+ mberrors[mb] |= 1;
+ }
+ }
+
+ /* Chroma planes */
+
+ for(p = 0; p < 2; p++) {
+
+ for(i = 0; i < 2; i++) {
+ v = read(fd[i], C[p][i], csiz);
+ if(v != csiz) {
+ fprintf(stderr, "Unable to read %c from file %d, exiting\n",
+ "UV"[p], i + 1);
+ return 1;
+ }
+ }
+
+ for(c = 0; c < csiz; c++) {
+ if(C[p][0][c] != C[p][1][c]) {
+ x = c % cwidth;
+ y = c / cwidth;
+
+ mb = x / 8 + (y / 8) * mb_x;
+
+ mberrors[mb] |= 2 << p;
+
+ if(print_pixels)
+
+ printf("c%c diff 0x%02x != 0x%02x at pixel (%4d,%-4d) "
+ "mb(%3d,%-3d) #%d\n",
+ p ? 'r' : 'b',
+ C[p][0][c],
+ C[p][1][c],
+
+ x, y,
+ x / 8,
+ y / 8,
+ x / 8 + y / 8 * cwidth / 8);
+ }
+ }
+ }
+
+ for(i = 0; i < mb_x * mb_y; i++) {
+ x = i % mb_x;
+ y = i / mb_x;
+
+ if(mberrors[i]) {
+ die = 1;
+
+ printf("MB (%3d,%-3d) %4d %d %c%c%c damaged\n",
+ x, y, i, mberrors[i],
+ mberrors[i] & 1 ? 'Y' : ' ',
+ mberrors[i] & 2 ? 'U' : ' ',
+ mberrors[i] & 4 ? 'V' : ' ');
+
+ if(dump_blocks) {
+ a = Y[0] + x * 16 + y * 16 * width;
+ b = Y[1] + x * 16 + y * 16 * width;
+
+ for(y = 0; y < 16; y++) {
+ printf("%c ", "TB"[y&1]);
+ for(x = 0; x < 16; x++)
+ printf("%02x%c", a[x + y * width],
+ a[x + y * width] != b[x + y * width] ? '<' : ' ');
+
+ printf("| ");
+ for(x = 0; x < 16; x++)
+ printf("%02x%c", b[x + y * width],
+ a[x + y * width] != b[x + y * width] ? '<' : ' ');
+
+ printf("\n");
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/zmqsend.c b/tools/zmqsend.c
new file mode 100644
index 0000000000..d47bf216b4
--- /dev/null
+++ b/tools/zmqsend.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013 Stefano Sabatini
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 <zmq.h>
+
+#include "libavutil/mem.h"
+#include "libavutil/bprint.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#if !HAVE_GETOPT
+#include "compat/getopt.c"
+#endif
+
+/**
+ * @file
+ * zmq message sender example, meant to be used with the zmq filters
+ */
+
+static void usage(void)
+{
+ printf("send message to ZMQ recipient, to use with the zmq filters\n");
+ printf("usage: zmqsend [OPTIONS]\n");
+ printf("\n"
+ "Options:\n"
+ "-b ADDRESS set bind address\n"
+ "-h print this help\n"
+ "-i INFILE set INFILE as input file, stdin if omitted\n");
+}
+
+int main(int argc, char **argv)
+{
+ AVBPrint src;
+ char c, *src_buf, *recv_buf;
+ int recv_buf_size, ret;
+ void *zmq_ctx, *socket;
+ const char *bind_address = "tcp://localhost:5555";
+ const char *infilename = NULL;
+ FILE *infile = NULL;
+ zmq_msg_t msg;
+
+ while ((c = getopt(argc, argv, "b:hi:")) != -1) {
+ switch (c) {
+ case 'b':
+ bind_address = optarg;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ infilename = optarg;
+ break;
+ case '?':
+ return 1;
+ }
+ }
+
+ if (!infilename || !strcmp(infilename, "-")) {
+ infilename = "stdin";
+ infile = stdin;
+ } else {
+ infile = fopen(infilename, "r");
+ }
+ if (!infile) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Impossible to open input file '%s': %s\n", infilename, strerror(errno));
+ return 1;
+ }
+
+ zmq_ctx = zmq_ctx_new();
+ if (!zmq_ctx) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not create ZMQ context: %s\n", zmq_strerror(errno));
+ return 1;
+ }
+
+ socket = zmq_socket(zmq_ctx, ZMQ_REQ);
+ if (!socket) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not create ZMQ socket: %s\n", zmq_strerror(errno));
+ ret = 1;
+ goto end;
+ }
+
+ if (zmq_connect(socket, bind_address) == -1) {
+ av_log(NULL, AV_LOG_ERROR, "Could not bind ZMQ responder to address '%s': %s\n",
+ bind_address, zmq_strerror(errno));
+ ret = 1;
+ goto end;
+ }
+
+ /* grab the input and store it in src */
+ av_bprint_init(&src, 1, AV_BPRINT_SIZE_UNLIMITED);
+ while ((c = fgetc(infile)) != EOF)
+ av_bprint_chars(&src, c, 1);
+ av_bprint_chars(&src, 0, 1);
+
+ if (!av_bprint_is_complete(&src)) {
+ av_log(NULL, AV_LOG_ERROR, "Could not allocate a buffer for the source string\n");
+ av_bprint_finalize(&src, NULL);
+ ret = 1;
+ goto end;
+ }
+ av_bprint_finalize(&src, &src_buf);
+
+ if (zmq_send(socket, src_buf, strlen(src_buf), 0) == -1) {
+ av_log(NULL, AV_LOG_ERROR, "Could not send message: %s\n", zmq_strerror(errno));
+ ret = 1;
+ goto end;
+ }
+
+ if (zmq_msg_init(&msg) == -1) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not initialize receiving message: %s\n", zmq_strerror(errno));
+ ret = 1;
+ goto end;
+ }
+
+ if (zmq_msg_recv(&msg, socket, 0) == -1) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not receive message: %s\n", zmq_strerror(errno));
+ zmq_msg_close(&msg);
+ ret = 1;
+ goto end;
+ }
+
+ recv_buf_size = zmq_msg_size(&msg) + 1;
+ recv_buf = av_malloc(recv_buf_size);
+ if (!recv_buf) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Could not allocate receiving message buffer\n");
+ zmq_msg_close(&msg);
+ ret = 1;
+ goto end;
+ }
+ memcpy(recv_buf, zmq_msg_data(&msg), recv_buf_size);
+ recv_buf[recv_buf_size-1] = 0;
+ printf("%s\n", recv_buf);
+ zmq_msg_close(&msg);
+ av_free(recv_buf);
+
+end:
+ zmq_close(socket);
+ zmq_ctx_destroy(zmq_ctx);
+ return ret;
+}
diff --git a/tools/zmqshell.py b/tools/zmqshell.py
new file mode 100755
index 0000000000..a7d1126006
--- /dev/null
+++ b/tools/zmqshell.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python2
+
+import sys, zmq, cmd
+
+class LavfiCmd(cmd.Cmd):
+ prompt = 'lavfi> '
+
+ def __init__(self, bind_address):
+ context = zmq.Context()
+ self.requester = context.socket(zmq.REQ)
+ self.requester.connect(bind_address)
+ cmd.Cmd.__init__(self)
+
+ def onecmd(self, cmd):
+ if cmd == 'EOF':
+ sys.exit(0)
+ print 'Sending command:[%s]' % cmd
+ self.requester.send(cmd)
+ message = self.requester.recv()
+ print 'Received reply:[%s]' % message
+
+try:
+ bind_address = sys.argv[1] if len(sys.argv) > 1 else "tcp://localhost:5555"
+ LavfiCmd(bind_address).cmdloop('FFmpeg libavfilter interactive shell')
+except KeyboardInterrupt:
+ pass
diff --git a/version.sh b/version.sh
index 6f72b2c2e6..f9754eb3cf 100755
--- a/version.sh
+++ b/version.sh
@@ -1,11 +1,39 @@
#!/bin/sh
+# Usage: version.sh <ffmpeg-root-dir> <output-version.h> <extra-version>
+
# check for git short hash
-revision=$(cd "$1" && git describe --always 2> /dev/null)
+if ! test "$revision"; then
+ if (cd "$1" && grep git RELEASE 2> /dev/null >/dev/null) ; then
+ revision=$(cd "$1" && git describe --tags --match N 2> /dev/null)
+ else
+ revision=$(cd "$1" && git describe --tags --always 2> /dev/null)
+ fi
+fi
+
+# Shallow Git clones (--depth) do not have the N tag:
+# use 'git-YYYY-MM-DD-hhhhhhh'.
+test "$revision" || revision=$(cd "$1" &&
+ git log -1 --pretty=format:"git-%cd-%h" --date=short 2> /dev/null)
+
+# Snapshots from gitweb are in a directory called ffmpeg-hhhhhhh or
+# ffmpeg-HEAD-hhhhhhh.
+if [ -z "$revision" ]; then
+ srcdir=$(cd "$1" && pwd)
+ case "$srcdir" in
+ */ffmpeg-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
+ git_hash="${srcdir##*-}";;
+ */ffmpeg-HEAD-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
+ git_hash="${srcdir##*-}";;
+ esac
+fi
# no revision number found
test "$revision" || revision=$(cd "$1" && cat RELEASE 2> /dev/null)
+# Append the Git hash if we have one
+test "$revision" && test "$git_hash" && revision="$revision-$git_hash"
+
# releases extract the version number from the VERSION file
version=$(cd "$1" && cat VERSION 2> /dev/null)
test "$version" || version=$revision
@@ -17,10 +45,18 @@ if [ -z "$2" ]; then
exit
fi
-NEW_REVISION="#define LIBAV_VERSION \"$version\""
-OLD_REVISION=$(cat version.h 2> /dev/null)
+NEW_REVISION="#define FFMPEG_VERSION \"$version\""
+OLD_REVISION=$(cat "$2" 2> /dev/null | head -3 | tail -1)
+
+# String used for preprocessor guard
+GUARD=$(echo "$2" | sed 's/\//_/' | sed 's/\./_/' | tr '[:lower:]' '[:upper:]' | sed 's/LIB//')
-# Update version.h only on revision changes to avoid spurious rebuilds
+# Update version header only on revision changes to avoid spurious rebuilds
if test "$NEW_REVISION" != "$OLD_REVISION"; then
- echo "$NEW_REVISION" > "$2"
+ cat << EOF > "$2"
+#ifndef $GUARD
+#define $GUARD
+$NEW_REVISION
+#endif /* $GUARD */
+EOF
fi